diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig index 5d3b86a3385704d798ec207b381091f60c2fd759..b179aaacb87cb214d1264f2d58b9841b41151fa4 100644 --- a/drivers/staging/Kconfig +++ b/drivers/staging/Kconfig @@ -110,4 +110,6 @@ source "drivers/staging/wilc1000/Kconfig" source "drivers/staging/most/Kconfig" +source "drivers/staging/qcacld-3.0/Kconfig" + endif # STAGING diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile index 654ee8d540967b5f847c3f6b0d42ec527a71fdd3..13f48c8056457737cd0723579a08be2116e482b3 100644 --- a/drivers/staging/Makefile +++ b/drivers/staging/Makefile @@ -46,3 +46,4 @@ obj-$(CONFIG_FB_TFT) += fbtft/ obj-$(CONFIG_FSL_MC_BUS) += fsl-mc/ obj-$(CONFIG_WILC1000) += wilc1000/ obj-$(CONFIG_MOST) += most/ +obj-$(CONFIG_QCA_CLD_WLAN) += qcacld-3.0/ diff --git a/drivers/staging/fw-api/fw/a_osapi.h b/drivers/staging/fw-api/fw/a_osapi.h new file mode 100644 index 0000000000000000000000000000000000000000..0eabec0a624486b02fce2f0639a897e54660aeff --- /dev/null +++ b/drivers/staging/fw-api/fw/a_osapi.h @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2013-2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* ============================================================================== */ +/* This file contains the definitions of the basic atheros data types. */ +/* It is used to map the data types in atheros files to a platform specific */ +/* type. */ +/* */ +/* Author(s): ="Atheros" */ +/* ============================================================================== */ +#ifndef _A_OSAPI_H_ +#define _A_OSAPI_H_ + +#if defined(__linux__) && !defined(LINUX_EMULATION) +#include "osapi_linux.h" +#endif + +/*=== the following primitives have the same definition for all platforms ===*/ + +#define A_COMPILE_TIME_ASSERT(assertion_name, predicate) \ + typedef char assertion_name[(predicate) ? 1 : -1] + +/* + * If N is a power of 2, then N and N-1 are orthogonal + * (N-1 has all the least-significant bits set which are zero in N) + * so N ^ (N-1) = (N << 1) - 1 + */ +#define A_COMPILE_TIME_ASSERT_IS_PWR2(assertion_name, value) \ + A_COMPILE_TIME_ASSERT (assertion_name, \ + (((value) ^ ((value)-1)) == ((value) << 1) - 1)) + +#ifndef __ubicom32__ +#define HIF_MALLOC_DIAGMEM(osdev, size, pa, context, retry) \ + os_malloc_CONSISTENT(osdev, size, pa, context, retry) +#define HIF_FREE_DIAGMEM(osdev, size, vaddr, pa, context) \ + OS_FREE_CONSISTENT(osdev, size, vaddr, pa, context) +#define HIF_DIAGMEM_SYNC(osdev, pa, size, dir, context) +#else +#define HIF_MALLOC_DIAGMEM(osdev, size, pa, context, retry) \ + os_malloc_NONCONSISTENT(osdev, size, pa, context, retry) +#define HIF_FREE_DIAGMEM(osdev, size, vaddr, pa, context) \ + OS_FREE_NONCONSISTENT(osdev, size, vaddr, pa, context) +#define HIF_DIAGMEM_SYNC(osdev, pa, size, dir, context) \ + OS_SYNC_SINGLE(osdev, pa, size, dir, context) +#endif /* ubicom32 */ + +#endif /* _OSAPI_H_ */ diff --git a/drivers/staging/fw-api/fw/a_usb_defs.h b/drivers/staging/fw-api/fw/a_usb_defs.h new file mode 100644 index 0000000000000000000000000000000000000000..1664a0a15859736b39d70387b9868c4186842e19 --- /dev/null +++ b/drivers/staging/fw-api/fw/a_usb_defs.h @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2013-2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ +/* + * Shared USB definitions + * + * + * + * + */ + +#ifndef __A_USB_DEFS_H__ +#define __A_USB_DEFS_H__ + +#ifndef ATH_TARGET +#include "athstartpack.h" +#endif + +/* USB endpoint definitions */ + +#define USB_EP_ADDR_APP_CTRL_IN 0x81 +#define USB_EP_ADDR_APP_DATA_IN 0x82 +#define USB_EP_ADDR_APP_DATA2_IN 0x83 +#define USB_EP_ADDR_APP_INT_IN 0x84 + +#define USB_EP_ADDR_APP_CTRL_OUT 0x01 +#define USB_EP_ADDR_APP_DATA_LP_OUT 0x02 +#define USB_EP_ADDR_APP_DATA_MP_OUT 0x03 +#define USB_EP_ADDR_APP_DATA_HP_OUT 0x04 + +#define USB_CONTROL_REQ_SEND_BMI_CMD 1 +#define USB_CONTROL_REQ_RECV_BMI_RESP 2 +#define USB_CONTROL_REQ_DIAG_CMD 3 +#define USB_CONTROL_REQ_DIAG_RESP 4 + +/* #define USB_CONTROL_MAX_BMI_TRANSFER_SIZE 64 */ +#define USB_CONTROL_MAX_BMI_TRANSFER_SIZE 252 + +#define HIF_BMI_MAX_TRANSFER_SIZE USB_CONTROL_MAX_BMI_TRANSFER_SIZE + +/* 512 Bytes Maxp for High Speed for BULK EP */ +#define USB_HS_BULK_MAXP_SIZE 0x200 +/* 64 Bytes Maxp for Full Speed for BULK EP */ +#define USB_FS_BULK_MAXP_SIZE 0x40 + +/* diagnostic command defnitions */ +#define USB_CTRL_DIAG_CC_READ 0 +#define USB_CTRL_DIAG_CC_WRITE 1 +#define USB_CTRL_DIAG_CC_WARM_RESET 2 + +typedef PREPACK struct { + A_UINT32 Cmd; + A_UINT32 Address; + A_UINT32 Value; + A_UINT32 _pad[1]; +} POSTPACK USB_CTRL_DIAG_CMD_WRITE; + +typedef PREPACK struct { + A_UINT32 Cmd; + A_UINT32 Address; +} POSTPACK USB_CTRL_DIAG_CMD_READ; + +typedef PREPACK struct { + A_UINT32 ReadValue; +} POSTPACK USB_CTRL_DIAG_RESP_READ; + +#define USB_CTRL_MAX_DIAG_CMD_SIZE (sizeof(USB_CTRL_DIAG_CMD_WRITE)) +#define USB_CTRL_MAX_DIAG_RESP_SIZE (sizeof(USB_CTRL_DIAG_RESP_READ)) + +#ifndef ATH_TARGET +#include "athendpack.h" +#endif + +#endif diff --git a/drivers/staging/fw-api/fw/apb_athr_wlan_map.h b/drivers/staging/fw-api/fw/apb_athr_wlan_map.h new file mode 100644 index 0000000000000000000000000000000000000000..3e48543f0de2d4122a7cf549fb85d60d1c82c6ce --- /dev/null +++ b/drivers/staging/fw-api/fw/apb_athr_wlan_map.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2013-2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef _APB_ATHR_WLAN_MAP_H_ +#define _APB_ATHR_WLAN_MAP_H_ + +#define RTC_SOC_BASE_ADDRESS 0x00004000 +#define RTC_WMAC_BASE_ADDRESS 0x00005000 +#define MAC_COEX_BASE_ADDRESS 0x00006000 +#define BT_COEX_BASE_ADDRESS 0x00007000 +#define SOC_PCIE_BASE_ADDRESS 0x00008000 +#define SOC_CORE_BASE_ADDRESS 0x00009000 +#define WLAN_UART_BASE_ADDRESS 0x0000c000 +#define WLAN_SI_BASE_ADDRESS 0x00010000 +#define WLAN_GPIO_BASE_ADDRESS 0x00014000 +#define WLAN_ANALOG_INTF_BASE_ADDRESS 0x0001c000 +#define WLAN_MAC_BASE_ADDRESS 0x00020000 +#define EFUSE_BASE_ADDRESS 0x00030000 +#define FPGA_REG_BASE_ADDRESS 0x00039000 +#define WLAN_UART2_BASE_ADDRESS 0x00054c00 +#define CE_WRAPPER_BASE_ADDRESS 0x00057000 +#define CE0_BASE_ADDRESS 0x00057400 +#define CE1_BASE_ADDRESS 0x00057800 +#define CE2_BASE_ADDRESS 0x00057c00 +#define CE3_BASE_ADDRESS 0x00058000 +#define CE4_BASE_ADDRESS 0x00058400 +#define CE5_BASE_ADDRESS 0x00058800 +#define CE6_BASE_ADDRESS 0x00058c00 +#define CE7_BASE_ADDRESS 0x00059000 +#define DBI_BASE_ADDRESS 0x00060000 +#define WLAN_MBOX_BASE_ADDRESS 0x00068000 +#define WLAN_DBG_UART_BASE_ADDRESS 0x00069000 +#define USB_DMA_BASE_ADDRESS 0x0006a000 + +#endif /* _APB_ATHR_WLAN_MAP_REG_H_ */ diff --git a/drivers/staging/fw-api/fw/athdefs.h b/drivers/staging/fw-api/fw/athdefs.h new file mode 100644 index 0000000000000000000000000000000000000000..d1ee6cb6ab0b7c06a1f5d7a71bda0c7f00286b79 --- /dev/null +++ b/drivers/staging/fw-api/fw/athdefs.h @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2012, 2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef __ATHDEFS_H__ +#define __ATHDEFS_H__ + +/* + * This file contains definitions that may be used across both + * Host and Target software. Nothing here is module-dependent + * or platform-dependent. + */ + +/* + * Generic error codes that can be used by hw, sta, ap, sim, dk + * and any other environments. Since these are enums, feel free to + * add any more codes that you need. + */ + +typedef enum { + A_ERROR = -1, /* Generic error return */ + A_OK = 0, /* success */ + /* Following values start at 1 */ + A_DEVICE_NOT_FOUND, /* not able to find PCI device */ + A_NO_MEMORY, /* not able to allocate memory, not available */ + A_MEMORY_NOT_AVAIL, /* memory region is not free for mapping */ + A_NO_FREE_DESC, /* no free descriptors available */ + A_BAD_ADDRESS, /* address does not match descriptor */ + A_WIN_DRIVER_ERROR, /* used in NT_HW version, if problem at init */ + A_REGS_NOT_MAPPED, /* registers not correctly mapped */ + A_EPERM, /* Not superuser */ + A_EACCES, /* Access denied */ + A_ENOENT, /* No such entry, search failed, etc. */ + A_EEXIST, /* The object already exists (can't create) */ + A_EFAULT, /* Bad address fault */ + A_EBUSY, /* Object is busy */ + A_EINVAL, /* Invalid parameter */ + A_EMSGSIZE, /* Inappropriate message buffer length */ + A_ECANCELED, /* Operation canceled */ + A_ENOTSUP, /* Operation not supported */ + A_ECOMM, /* Communication error on send */ + A_EPROTO, /* Protocol error */ + A_ENODEV, /* No such device */ + A_EDEVNOTUP, /* device is not UP */ + A_NO_RESOURCE, /* No resources for requested operation */ + A_HARDWARE, /* Hardware failure */ + A_PENDING, /* Asynchronous routine; will send up results la + ter (typically in callback) */ + A_EBADCHANNEL, /* The channel cannot be used */ + A_DECRYPT_ERROR, /* Decryption error */ + A_PHY_ERROR, /* RX PHY error */ + A_CONSUMED, /* Object was consumed */ + A_CLONE, /* The buffer is cloned */ + A_USB_ERROR, /* Rome USB Target error */ +} A_STATUS; + +#define A_SUCCESS(x) (x == A_OK) +#define A_FAILED(x) (!A_SUCCESS(x)) + +#endif /* __ATHDEFS_H__ */ diff --git a/drivers/staging/fw-api/fw/athendpack.h b/drivers/staging/fw-api/fw/athendpack.h new file mode 100644 index 0000000000000000000000000000000000000000..977909eb6e9f5a1cc8497f482de16ef2e1daa2ee --- /dev/null +++ b/drivers/staging/fw-api/fw/athendpack.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2013-2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifdef VXWORKS +#endif /* VXWORKS */ + +#if defined(LINUX) || defined(__linux__) +#endif /* LINUX */ + +#ifdef QNX +#endif /* QNX */ diff --git a/drivers/staging/fw-api/fw/bin_sig.h b/drivers/staging/fw-api/fw/bin_sig.h new file mode 100644 index 0000000000000000000000000000000000000000..d4f3516323256dd778ee878ebad3e7c1204cbd7c --- /dev/null +++ b/drivers/staging/fw-api/fw/bin_sig.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2012,2014, 2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef BIN_SIGN_H_ +#define BIN_SIGN_H_ + + +/* Signed binary MetaData */ +typedef struct { + unsigned int magic_num; + unsigned int total_len; + unsigned int rampatch_len; + unsigned int product_id; + unsigned int patch_ver; + unsigned short sign_format_ver; + unsigned short sign_algorithm; + unsigned char reserved[8]; +} SIGN_HEADER_T; + +#endif /* BIN_SIGN_H_ */ diff --git a/drivers/staging/fw-api/fw/bmi_msg.h b/drivers/staging/fw-api/fw/bmi_msg.h new file mode 100644 index 0000000000000000000000000000000000000000..feafa89a3ac8edbbb8a0e6cb8a7203466d8045d5 --- /dev/null +++ b/drivers/staging/fw-api/fw/bmi_msg.h @@ -0,0 +1,383 @@ +/* + * Copyright (c) 2012-2014, 2016-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef __BMI_MSG_H__ +#define __BMI_MSG_H__ + +#ifndef ATH_TARGET +#include "athstartpack.h" +#endif + +/* + * Bootloader Messaging Interface (BMI) + * + * BMI is a very simple messaging interface used during initialization + * to read memory, write memory, execute code, and to define an + * application entry PC. + * + * It is used to download an application to AR6K, to provide + * patches to code that is already resident on AR6K, and generally + * to examine and modify state. The Host has an opportunity to use + * BMI only once during bootup. Once the Host issues a BMI_DONE + * command, this opportunity ends. + * + * The Host writes BMI requests to mailbox0, and reads BMI responses + * from mailbox0. BMI requests all begin with a command + * (see below for specific commands), and are followed by + * command-specific data. + * + * Flow control: + * The Host can only issue a command once the Target gives it a + * "BMI Command Credit", using AR6K Counter #4. As soon as the + * Target has completed a command, it issues another BMI Command + * Credit (so the Host can issue the next command). + * + * BMI handles all required Target-side cache flushing. + */ + +/* Maximum data size used for BMI transfers */ +#define BMI_DATASZ_MAX 256 + +/* BMI Commands */ + +#define BMI_NO_COMMAND 0 + +#define BMI_DONE 1 +/* + * Semantics: Host is done using BMI + * Request format: + * A_UINT32 command (BMI_DONE) + * Response format: none + */ + +#define BMI_READ_MEMORY 2 +/* + * Semantics: Host reads AR6K memory + * Request format: + * A_UINT32 command (BMI_READ_MEMORY) + * A_UINT32 address + * A_UINT32 length, at most BMI_DATASZ_MAX + * Response format: + * A_UINT8 data[length] + */ + +#define BMI_WRITE_MEMORY 3 +/* + * Semantics: Host writes AR6K memory + * Request format: + * A_UINT32 command (BMI_WRITE_MEMORY) + * A_UINT32 address + * A_UINT32 length, at most BMI_DATASZ_MAX + * A_UINT8 data[length] + * Response format: none + */ +/* + * Capbility to write "segmented files" is provided for two reasons + * 1) backwards compatibility for certain situations where Hosts + * have limited flexibility + * 2) because it's darn convenient. + * + * A segmented file consists of a file header followed by an arbitrary number + * of segments. Each segment contains segment metadata -- a Target address and + * a length -- followed by "length" bytes of data. A segmented file ends with + * a segment that specifies length=BMI_SGMTFILE_DONE. When a segmented file + * is sent to the Target, firmware writes each segment to the specified address. + * + * Special cases: + * 1) If a segment's metadata indicates length=BMI_SGMTFILE_EXEC, then the + * specified address is used as a function entry point for a brief function + * with prototype "(void *)(void)". That function is called immediately. + * After execution of the function completes, firmware continues with the + * next segment. No data is expected when length=BMI_SGMTFILE_EXEC. + * + * 2) If a segment's metadata indicates length=BMI_SGMTFILE_BEGINADDR, then + * the specified address is established as the application start address + * so that a subsequent BMI_DONE jumps there. + * + * 3) If a segment's metadata indicates length=BMI_SGMTFILE_BDDATA, then + * the specified address is used as the (possibly compressed) length of board + * data, which is loaded into the proper Target address as specified by + * hi_board_data. In addition, the hi_board_data_initialized flag is set. + * + * A segmented file is sent to the Target using a sequence of 1 or more + * BMI_WRITE_MEMORY commands. The first such command must have + * address=BMI_SEGMENTED_WRITE_ADDR. Subsequent BMI_WRITE_MEMORY commands + * can use an arbitrary address. In each BMI_WRITE_MEMORY command, the + * length specifies the number of data bytes transmitted (except for the + * special cases listed above). + * + * Alternatively, a segmented file may be sent to the Target using a + * BMI_LZ_STREAM_START command with address=BMI_SEGMENTED_WRITE_ADDR + * followed by a series of BMI_LZ_DATA commands that each send the next portion + * of the segmented file. + * + * The data segments may be lz77 compressed. In this case, the segmented file + * header flag, BMI_SGMTFILE_FLAG_COMPRESS, must be set. Note that segmented + * file METAdata is never compressed; only the data segments themselves are + * compressed. There is no way to mix compressed and uncompressed data segments + * in a single segmented file. Compressed (or uncompressed) segments are handled + * by both BMI_WRITE_MEMORY and by BMI_LZ_DATA commands. (Compression is an + * attribute of the segmented file rather than of the command used to transmit + * it.) + */ +#define BMI_SEGMENTED_WRITE_ADDR 0x1234 + +/* File header for a segmented file */ +struct bmi_segmented_file_header { + A_UINT32 magic_num; + A_UINT32 file_flags; +}; +#define BMI_SGMTFILE_MAGIC_NUM 0x544d4753 /* "SGMT" */ +#define BMI_SGMTFILE_FLAG_COMPRESS 1 + +/* Metadata for a segmented file segment */ +struct bmi_segmented_metadata { + A_UINT32 addr; + A_UINT32 length; +}; +/* Special values for bmi_segmented_metadata.length (all have high bit set) */ +#define BMI_SGMTFILE_DONE 0xffffffff /* end of segmented data */ +#define BMI_SGMTFILE_BDDATA 0xfffffffe /* Board Data segment */ +#define BMI_SGMTFILE_BEGINADDR 0xfffffffd /* set beginning address */ +#define BMI_SGMTFILE_EXEC 0xfffffffc /* immediate function execution */ + +#define BMI_EXECUTE 4 +/* + * Semantics: Causes AR6K to execute code + * Request format: + * A_UINT32 command (BMI_EXECUTE) + * A_UINT32 address + * A_UINT32 parameter + * Response format: + * A_UINT32 return value + */ +/* + * Note: In order to support the segmented file feature + * (see BMI_WRITE_MEMORY), when the address specified in a + * BMI_EXECUTE command matches (same physical address) + * BMI_SEGMENTED_WRITE_ADDR, it is ignored. Instead, execution + * begins at the address specified by hi_app_start. + */ + +#define BMI_SET_APP_START 5 +/* + * Semantics: Set Target application starting address + * Request format: + * A_UINT32 command (BMI_SET_APP_START) + * A_UINT32 address + * Response format: none + */ + +#define BMI_READ_SOC_REGISTER 6 +#define BMI_READ_SOC_WORD 6 +/* + * Semantics: Read a 32-bit Target SOC word. + * Request format: + * A_UINT32 command (BMI_READ_REGISTER) + * A_UINT32 address + * Response format: + * A_UINT32 value + */ + +#define BMI_WRITE_SOC_REGISTER 7 +#define BMI_WRITE_SOC_WORD 7 +/* + * Semantics: Write a 32-bit Target SOC word. + * Request format: + * A_UINT32 command (BMI_WRITE_REGISTER) + * A_UINT32 address + * A_UINT32 value + * + * Response format: none + */ + +#define BMI_GET_TARGET_ID 8 +#define BMI_GET_TARGET_INFO 8 +/* + * Semantics: Fetch the 4-byte Target information + * Request format: + * A_UINT32 command (BMI_GET_TARGET_ID/INFO) + * + * Response format1 (old firmware): + * A_UINT32 TargetVersionID + * + * Response format2 (intermediate firmware, during transition): + * A_UINT32 TARGET_VERSION_SENTINAL + * struct bmi_target_info; + * + * Response format3 (newest firmware) + * struct bmi_target_info; + */ +PREPACK struct bmi_target_info { + /* size of this structure */ + A_UINT32 target_info_byte_count; + A_UINT32 target_ver; + A_UINT32 target_type; +} POSTPACK; + +#define TARGET_VERSION_SENTINAL 0xffffffff +#define TARGET_TYPE_UNKNOWN 0 +#define TARGET_TYPE_AR6001 1 +#define TARGET_TYPE_AR6002 2 +#define TARGET_TYPE_AR6003 3 +#define TARGET_TYPE_AR6004 5 +#define TARGET_TYPE_AR6006 6 +#define TARGET_TYPE_AR9888 7 +#define TARGET_TYPE_AR6320 8 +#define TARGET_TYPE_AR900B 9 +/* For attach Peregrine 2.0 board target_reg_tbl only */ +#define TARGET_TYPE_AR9888V2 10 +/* For attach Rome1.0 target_reg_tbl only*/ +#define TARGET_TYPE_AR6320V1 11 +/* For Rome2.0/2.1 target_reg_tbl ID*/ +#define TARGET_TYPE_AR6320V2 12 +/* For Rome3.0 target_reg_tbl ID*/ +#define TARGET_TYPE_AR6320V3 13 +/* For Tufello1.0 target_reg_tbl ID*/ +#define TARGET_TYPE_QCA9377V1 14 +/* cascade */ +#define TARGET_TYPE_QCA9984 15 +/* dakota */ +#define TARGET_TYPE_IPQ4019 16 +/* besra */ +#define TARGET_TYPE_QCA9888 17 +/* For Adrastea target */ +#define TARGET_TYPE_ADRASTEA 19 + +#define BMI_ROMPATCH_INSTALL 9 +/* + * Semantics: Install a ROM Patch. + * Request format: + * A_UINT32 command (BMI_ROMPATCH_INSTALL) + * A_UINT32 Target ROM Address + * A_UINT32 Target RAM Address or Value (depending on Target Type) + * A_UINT32 Size, in bytes + * A_UINT32 Activate? 1-->activate; + * 0-->install but do not activate + * Response format: + * A_UINT32 PatchID + */ + +#define BMI_ROMPATCH_UNINSTALL 10 +/* + * Semantics: Uninstall a previously-installed ROM Patch, + * automatically deactivating, if necessary. + * Request format: + * A_UINT32 command (BMI_ROMPATCH_UNINSTALL) + * A_UINT32 PatchID + * + * Response format: none + */ + +#define BMI_ROMPATCH_ACTIVATE 11 +/* + * Semantics: Activate a list of previously-installed ROM Patches. + * Request format: + * A_UINT32 command (BMI_ROMPATCH_ACTIVATE) + * A_UINT32 rompatch_count + * A_UINT32 PatchID[rompatch_count] + * + * Response format: none + */ + +#define BMI_ROMPATCH_DEACTIVATE 12 +/* + * Semantics: Deactivate a list of active ROM Patches. + * Request format: + * A_UINT32 command (BMI_ROMPATCH_DEACTIVATE) + * A_UINT32 rompatch_count + * A_UINT32 PatchID[rompatch_count] + * + * Response format: none + */ + +#define BMI_LZ_STREAM_START 13 +/* + * Semantics: Begin an LZ-compressed stream of input + * which is to be uncompressed by the Target to an + * output buffer at address. The output buffer must + * be sufficiently large to hold the uncompressed + * output from the compressed input stream. This BMI + * command should be followed by a series of 1 or more + * BMI_LZ_DATA commands. + * A_UINT32 command (BMI_LZ_STREAM_START) + * A_UINT32 address + * Note: Not supported on all versions of ROM firmware. + */ + +#define BMI_LZ_DATA 14 +/* + * Semantics: Host writes AR6K memory with LZ-compressed + * data which is uncompressed by the Target. This command + * must be preceded by a BMI_LZ_STREAM_START command. A series + * of BMI_LZ_DATA commands are considered part of a single + * input stream until another BMI_LZ_STREAM_START is issued. + * Request format: + * A_UINT32 command (BMI_LZ_DATA) + * A_UINT32 length (of compressed data), + * at most BMI_DATASZ_MAX + * A_UINT8 CompressedData[length] + * Response format: none + * Note: Not supported on all versions of ROM firmware. + */ + +#define BMI_NVRAM_PROCESS 15 +#define BMI_NVRAM_SEG_NAME_SZ 16 +/* + * Semantics: Cause Target to search NVRAM (if any) for a + * segment with the specified name and process it according + * to NVRAM metadata. + * Request format: + * A_UINT32 command (BMI_NVRAM_PROCESS) + * A_UCHAR name[BMI_NVRAM_SEG_NAME_SZ] name (LE format) + * Response format: + * A_UINT32 0, if nothing was executed; + * otherwise the value returned from the + * last NVRAM segment that was executed + */ + +#define BMI_SIGN_STREAM_START 17 +/* + * Semantics: Trigger target start/end binary signature verification + * flow. + * Request format: + * A_UINT32 command (BMI_SIGN_STREAM_START) + * A_UINT32 address + * A_UINT32 length, at most BMI_DATASZ_MAX + * A_UINT8 data[length] + * Response format: none + */ + +#ifndef ATH_TARGET +#include "athendpack.h" +#endif + +/* TBDXXX: Need a better place for these */ +#define BMI_CE_NUM_TO_TARG 0 +#define BMI_CE_NUM_TO_HOST 1 + +#endif /* __BMI_MSG_H__ */ diff --git a/drivers/staging/fw-api/fw/cepci.h b/drivers/staging/fw-api/fw/cepci.h new file mode 100755 index 0000000000000000000000000000000000000000..5c2247eafd568cafb0c8f7b9af076a8771ca0e6d --- /dev/null +++ b/drivers/staging/fw-api/fw/cepci.h @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2013-2014, 2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef __CEPCI_H__ +#define __CEPCI_H__ + +/* + * Support for Copy Engine over PCI. + * Structures shared between Host software and Target firmware. + */ + +/* + * Total number of PCIe MSI interrupts requested for all interrupt sources. + * PCIe standard forces this to be a power of 2. + * Some Host OS's limit MSI requests that can be granted to 8 + * so for now we abide by this limit and avoid requesting more + * than that. + */ +#define MSI_NUM_REQUEST_LOG2 3 +#define MSI_NUM_REQUEST (1<hi_interconnect_state points + * here (and all members are 32-bit quantities in order to + * facilitate Host access). In particular, Host software is + * required to initialize pipe_cfg_addr and svc_to_pipe_map. + */ +struct pcie_state_s { + uint32_t pipe_cfg_addr; /* Pipe configuration Target address */ + /* NB: CE_pipe_config[CE_COUNT] */ + + uint32_t svc_to_pipe_map; /* Service to pipe map Target address */ + /* NB: service_to_pipe[PIPE_TO_CE_MAP_CN] */ + + uint32_t MSI_requested; /* number of MSI interrupts requested */ + uint32_t MSI_granted; /* number of MSI interrupts granted */ + uint32_t MSI_addr; /* Message Signalled Interrupt address */ + uint32_t MSI_data; /* Base data */ + uint32_t MSI_fw_intr_data; /* Data for firmware interrupt; + MSI data for other interrupts are + in various SoC registers */ + + uint32_t power_mgmt_method; /* PCIE_PWR_METHOD_* */ + uint32_t config_flags; /* PCIE_CONFIG_FLAG_* */ +}; + +/* + * PCIE_CONFIG_FLAG definitions + */ +#if defined(AR900B) +#define CE_PKTLOG_PIPE 8 /* used by both host and target side */ +#endif + +#define PCIE_CONFIG_FLAG_ENABLE_L1 0x0000001 +#define PCIE_CONFIG_FLAG_CLK_GATING_L1 0x0000001 +#define PCIE_CONFIG_FLAG_CLK_SWITCH_WAIT 0x0000002 +#define PCIE_CONFIG_FLAG_AXI_CLK_GATE 0x0000004 +#define PCIE_CONFIG_FLAG_CLK_REQ_L1 0x0000008 + +#define PIPE_TO_CE_MAP_CNT 32 /* simple implementation constant */ + +/* + * Configuration information for a Copy Engine pipe. + * Passed from Host to Target during startup (one per CE). + */ +struct CE_pipe_config { + uint32_t pipenum; + uint32_t pipedir; + uint32_t nentries; + uint32_t nbytes_max; + uint32_t flags; + uint32_t reserved; +}; + +#endif /* __CEPCI_H__ */ diff --git a/drivers/staging/fw-api/fw/dbglog.h b/drivers/staging/fw-api/fw/dbglog.h new file mode 100755 index 0000000000000000000000000000000000000000..d3179a7ae92e44df4b02412d35ce0d53256f843c --- /dev/null +++ b/drivers/staging/fw-api/fw/dbglog.h @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2012, 2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef _DBGLOG_H_ +#define _DBGLOG_H_ + +#ifndef ATH_TARGET +#include "athstartpack.h" +#endif + +#include "wlan_module_ids.h" + +#ifdef __cplusplus +extern "C" { +#endif +#define DBGLOG_TIMESTAMP_OFFSET 0 + +/* Bit 0-15. Contains bit 8-23 of the LF0 timer */ +#define DBGLOG_TIMESTAMP_MASK 0xFFFFFFFF +#define DBGLOG_DBGID_OFFSET 0 + +#define DBGLOG_DBGID_MASK 0x000003FF /* Bit 0-9 */ +/* Upper limit is width of mask */ +#define DBGLOG_DBGID_NUM_MAX 256 + +#define DBGLOG_MODULEID_OFFSET 10 +#define DBGLOG_MODULEID_MASK 0x0003FC00 /* Bit 10-17 */ +/* Upper limit is width of mask */ +#define DBGLOG_MODULEID_NUM_MAX 32 + +#define DBGLOG_VDEVID_OFFSET 18 +#define DBGLOG_VDEVID_MASK 0x03FC0000 /* Bit 20-25 */ +#define DBGLOG_VDEVID_NUM_MAX 16 + +#define DBGLOG_NUM_ARGS_OFFSET 26 +#define DBGLOG_NUM_ARGS_MASK 0xFC000000 /* Bit 26-31 */ + +/* it is limited bcoz of limitations of corebsp MSG*() to accept max 9 arg */ +#define DBGLOG_NUM_ARGS_MAX 9 + +#define DBGLOG_LOG_BUFFER_SIZE 1500 +#define DBGLOG_DBGID_DEFINITION_LEN_MAX 90 + +#define DBGLOG_HOST_LOG_BUFFER_SIZE DBGLOG_LOG_BUFFER_SIZE + +#define DBGLOG_GET_DBGID(arg) \ + ((arg & DBGLOG_DBGID_MASK) >> DBGLOG_DBGID_OFFSET) + +#define DBGLOG_GET_MODULEID(arg) \ + ((arg & DBGLOG_MODULEID_MASK) >> DBGLOG_MODULEID_OFFSET) + +#define DBGLOG_GET_VDEVID(arg) \ + ((arg & DBGLOG_VDEVID_MASK) >> DBGLOG_VDEVID_OFFSET) + +#define DBGLOG_GET_NUMARGS(arg) \ + ((arg & DBGLOG_NUM_ARGS_MASK) >> DBGLOG_NUM_ARGS_OFFSET) + +#define DBGLOG_GET_TIME_STAMP(arg) \ + ((arg & DBGLOG_TIMESTAMP_MASK) >> DBGLOG_TIMESTAMP_OFFSET) + + +/* Debug Log levels*/ + +enum DBGLOG_LOG_LVL { + DBGLOG_VERBOSE = 0, + DBGLOG_INFO, + DBGLOG_INFO_LVL_1, + DBGLOG_INFO_LVL_2, + DBGLOG_WARN, + DBGLOG_ERR, + DBGLOG_LVL_MAX +}; + +PREPACK struct dbglog_buf_s { + struct dbglog_buf_s *next; + A_UINT8 *buffer; + A_UINT32 bufsize; + A_UINT32 length; + A_UINT32 count; + A_UINT32 free; +} POSTPACK; + +PREPACK struct dbglog_hdr_s { + struct dbglog_buf_s *dbuf; + A_UINT32 dropped; +} POSTPACK; + + +#define DBGLOG_MAX_VDEVID 15 /* 0-15 */ + +#ifdef __cplusplus +} +#endif +#endif /* _DBGLOG_H_ */ diff --git a/drivers/staging/fw-api/fw/dbglog_id.h b/drivers/staging/fw-api/fw/dbglog_id.h new file mode 100755 index 0000000000000000000000000000000000000000..892f1fe96e63e0319f6082fc11f7114cb691dc1d --- /dev/null +++ b/drivers/staging/fw-api/fw/dbglog_id.h @@ -0,0 +1,1748 @@ +/* + * Copyright (c) 2013-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef _DBGLOG_ID_H_ +#define _DBGLOG_ID_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * The nomenclature for the debug identifiers is MODULE_DESCRIPTION. + * Please ensure that the definition of any new debugid introduced is captured + * between the _DBGID_DEFINITION_START and + * _DBGID_DEFINITION_END defines. The structure is required for the + * parser to correctly pick up the values for different debug identifiers. + */ + +/* + * The target state machine framework will send dbglog messages on behalf on + * other modules. We do this do avoid each module adding identical dbglog code + * for state transitions and event processing. We also don't want to force each + * module to define the the same XXX_DBGID_SM_MSG with the same value below. + * Instead we use a special ID that the host dbglog code recognizes as a + * message sent by the SM on behalf on another module. + */ +#define DBGLOG_DBGID_SM_FRAMEWORK_PROXY_DBGLOG_MSG 1000 + +/* INF debug identifier definitions */ +#define INF_DBGID_DEFINITION_START 0 +#define INF_ASSERTION_FAILED 1 +#define INF_TARGET_ID 2 +#define INF_TARGET_MEM_REMAING 3 +#define INF_TARGET_MEM_EXT_REMAING 4 +#define INF_TARGET_MEM_ALLOC_TRACK 5 +#define INF_TARGET_MEM_ALLOC_RAM 6 +#define INF_DBGID_DEFINITION_END 7 + +/* WMI debug identifier definitions */ +#define WMI_DBGID_DEFINITION_START 0 +#define WMI_CMD_RX_XTND_PKT_TOO_SHORT 1 +#define WMI_EXTENDED_CMD_NOT_HANDLED 2 +#define WMI_CMD_RX_PKT_TOO_SHORT 3 +#define WMI_CALLING_WMI_EXTENSION_FN 4 +#define WMI_CMD_NOT_HANDLED 5 +#define WMI_IN_SYNC 6 +#define WMI_TARGET_WMI_SYNC_CMD 7 +#define WMI_SET_SNR_THRESHOLD_PARAMS 8 +#define WMI_SET_RSSI_THRESHOLD_PARAMS 9 +#define WMI_SET_LQ_TRESHOLD_PARAMS 10 +#define WMI_TARGET_CREATE_PSTREAM_CMD 11 +#define WMI_WI_DTM_INUSE 12 +#define WMI_TARGET_DELETE_PSTREAM_CMD 13 +#define WMI_TARGET_IMPLICIT_DELETE_PSTREAM_CMD 14 +#define WMI_TARGET_GET_BIT_RATE_CMD 15 +#define WMI_GET_RATE_MASK_CMD_FIX_RATE_MASK_IS 16 +#define WMI_TARGET_GET_AVAILABLE_CHANNELS_CMD 17 +#define WMI_TARGET_GET_TX_PWR_CMD 18 +#define WMI_FREE_EVBUF_WMIBUF 19 +#define WMI_FREE_EVBUF_DATABUF 20 +#define WMI_FREE_EVBUF_BADFLAG 21 +#define WMI_HTC_RX_ERROR_DATA_PACKET 22 +#define WMI_HTC_RX_SYNC_PAUSING_FOR_MBOX 23 +#define WMI_INCORRECT_WMI_DATA_HDR_DROPPING_PKT 24 +#define WMI_SENDING_READY_EVENT 25 +#define WMI_SETPOWER_MDOE_TO_MAXPERF 26 +#define WMI_SETPOWER_MDOE_TO_REC 27 +#define WMI_BSSINFO_EVENT_FROM 28 +#define WMI_TARGET_GET_STATS_CMD 29 +#define WMI_SENDING_SCAN_COMPLETE_EVENT 30 +#define WMI_SENDING_RSSI_INDB_THRESHOLD_EVENT 31 +#define WMI_SENDING_RSSI_INDBM_THRESHOLD_EVENT 32 +#define WMI_SENDING_LINK_QUALITY_THRESHOLD_EVENT 33 +#define WMI_SENDING_ERROR_REPORT_EVENT 34 +#define WMI_SENDING_CAC_EVENT 35 +#define WMI_TARGET_GET_ROAM_TABLE_CMD 36 +#define WMI_TARGET_GET_ROAM_DATA_CMD 37 +#define WMI_SENDING_GPIO_INTR_EVENT 38 +#define WMI_SENDING_GPIO_ACK_EVENT 39 +#define WMI_SENDING_GPIO_DATA_EVENT 40 +#define WMI_CMD_RX 41 +#define WMI_CMD_RX_XTND 42 +#define WMI_EVENT_SEND 43 +#define WMI_EVENT_SEND_XTND 44 +#define WMI_CMD_PARAMS_DUMP_START 45 +#define WMI_CMD_PARAMS_DUMP_END 46 +#define WMI_CMD_PARAMS 47 +#define WMI_EVENT_ALLOC_FAILURE 48 +#define WMI_DBGID_DCS_PARAM_CMD 49 +#define WMI_SEND_EVENT_WRONG_TLV 50 +#define WMI_SEND_EVENT_NO_TLV_DEF 51 +#define WMI_RECV_CMD_WRONG_TLV 52 +#define WMI_CHECK_TLV_PARAM_GET_NUM_TLVS_ERROR 53 +#define WMI_CHECK_TLV_PARAM_TLV_LEN_EXCEEDED_BUF_LEN 54 +#define WMI_CHECK_TLV_PARAM_NONEXISTING_TAG_ORDER 55 +#define WMI_CHECK_TLV_PARAM_WRONG_TAG_ORDER 56 +#define WMI_CHECK_TLV_PARAM_INVALID_TLV_DEF_ARRAY_SIZE 57 +#define WMI_CHECK_TLV_PARAM_INVALID_TLV_DEF_VARIED_SIZE 58 +#define WMI_CHECK_TLV_PARAM_WRONG_TLV_LENGTH 59 +#define WMI_CHECK_TLV_PARAM_UNALIGNED_TLV_LEN 60 +#define WMI_CHECK_TLV_PARAM_WRONG_INNER_TLV_LEN 61 +#define WMI_CHECK_TLV_PARAM_UNSUPPORTED_ARRAY_TAG 62 +#define WMI_CHECK_TLV_PARAM_EXCEEDED_MAX_TLVs 63 +#define WMI_CHECK_TLV_PARAM_CMD_BUF_ALLOC_FAILED 64 +#define WMI_CHECK_TLV_PARAM_TLV_INFO 65 +#define WMI_DBGID_DEFINITION_END 66 + +/* PM Message definition*/ +#define PS_STA_DEFINITION_START 0 +#define PS_STA_PM_ARB_REQUEST 1 +#define PS_STA_DELIVER_EVENT 2 +#define PS_STA_PSPOLL_SEQ_DONE 3 +#define PS_STA_COEX_MODE 4 +#define PS_STA_PSPOLL_ALLOW 5 +#define PS_STA_SET_PARAM 6 +#define PS_STA_SPECPOLL_TIMER_STARTED 7 +#define PS_STA_SPECPOLL_TIMER_STOPPED 8 +#define PS_STA_AVG_CHANNEL_CONGESTION 9 +#define PS_STA_DEFINITION_END 10 + +/** RESMGR dbg ids */ +/* TODO: 1. Segregate IDs as per sub-module. (Give 100 per sub-module?) + * 2. Add chmgr IDs over here. + * 3. Update prints in dbglog_host.c + * 4. Deprecate WLAN_MODULE_RESMGR_CHAN_MANAGER */ +#define RESMGR_DEFINITION_START 0 +#define RESMGR_OCS_ALLOCRAM_SIZE 1 +#define RESMGR_OCS_RESOURCES 2 +#define RESMGR_LINK_CREATE 3 +#define RESMGR_LINK_DELETE 4 +#define RESMGR_OCS_CHREQ_CREATE 5 +#define RESMGR_OCS_CHREQ_DELETE 6 +#define RESMGR_OCS_CHREQ_START 7 +#define RESMGR_OCS_CHREQ_STOP 8 +#define RESMGR_OCS_SCHEDULER_INVOKED 9 +#define RESMGR_OCS_CHREQ_GRANT 10 +#define RESMGR_OCS_CHREQ_COMPLETE 11 +#define RESMGR_OCS_NEXT_TSFTIME 12 +#define RESMGR_OCS_TSF_TIMEOUT_US 13 +#define RESMGR_OCS_CURR_CAT_WINDOW 14 +#define RESMGR_OCS_CURR_CAT_WINDOW_REQ 15 +#define RESMGR_OCS_CURR_CAT_WINDOW_TIMESLOT 16 +#define RESMGR_OCS_CHREQ_RESTART 17 +#define RESMGR_OCS_CLEANUP_CH_ALLOCATORS 18 +#define RESMGR_OCS_PURGE_CHREQ 19 +#define RESMGR_OCS_CH_ALLOCATOR_FREE 20 +#define RESMGR_OCS_RECOMPUTE_SCHEDULE 21 +#define RESMGR_OCS_NEW_CAT_WINDOW_REQ 22 +#define RESMGR_OCS_NEW_CAT_WINDOW_TIMESLOT 23 +#define RESMGR_OCS_CUR_CH_ALLOC 24 +#define RESMGR_OCS_WIN_CH_ALLOC 25 +#define RESMGR_OCS_SCHED_CH_CHANGE 26 +#define RESMGR_OCS_CONSTRUCT_CAT_WIN 27 +#define RESMGR_OCS_CHREQ_PREEMPTED 28 +#define RESMGR_OCS_CH_SWITCH_REQ 29 +#define RESMGR_OCS_CHANNEL_SWITCHED 30 +#define RESMGR_OCS_CLEANUP_STALE_REQS 31 +#define RESMGR_OCS_CHREQ_UPDATE 32 +#define RESMGR_OCS_REG_NOA_NOTIF 33 +#define RESMGR_OCS_DEREG_NOA_NOTIF 34 +#define RESMGR_OCS_GEN_PERIODIC_NOA 35 +#define RESMGR_OCS_RECAL_QUOTAS 36 +#define RESMGR_OCS_GRANTED_QUOTA_STATS 37 +#define RESMGR_OCS_ALLOCATED_QUOTA_STATS 38 +#define RESMGR_OCS_REQ_QUOTA_STATS 39 +#define RESMGR_OCS_TRACKING_TIME_FIRED 40 +#define RESMGR_VC_ARBITRATE_ATTRIBUTES 41 +#define RESMGR_OCS_LATENCY_STRICT_TIME_SLOT 42 +#define RESMGR_OCS_CURR_TSF 43 +#define RESMGR_OCS_QUOTA_REM 44 +#define RESMGR_OCS_LATENCY_CASE_NO 45 +#define RESMGR_OCS_WIN_CAT_DUR 46 +#define RESMGR_VC_UPDATE_CUR_VC 47 +#define RESMGR_VC_REG_UNREG_LINK 48 +#define RESMGR_VC_PRINT_LINK 49 +#define RESMGR_OCS_MISS_TOLERANCE 50 +#define RESMGR_DYN_SCH_ALLOCRAM_SIZE 51 +#define RESMGR_DYN_SCH_ENABLE 52 +#define RESMGR_DYN_SCH_ACTIVE 53 +#define RESMGR_DYN_SCH_CH_STATS_START 54 +#define RESMGR_DYN_SCH_CH_SX_STATS 55 +#define RESMGR_DYN_SCH_TOT_UTIL_PER 56 +#define RESMGR_DYN_SCH_HOME_CH_QUOTA 57 +#define RESMGR_OCS_REG_RECAL_QUOTA_NOTIF 58 +#define RESMGR_OCS_DEREG_RECAL_QUOTA_NOTIF 59 +#define RESMGR_DYN_SCH_CH_STATS_END 60 +#define RESMGR_DEFINITION_END 61 + +/* RESMGR CHNMGR debug ids */ +#define RESMGR_CHMGR_DEFINITION_START 0 +#define RESMGR_CHMGR_PAUSE_COMPLETE 1 +#define RESMGR_CHMGR_CHANNEL_CHANGE 2 +#define RESMGR_CHMGR_RESUME_COMPLETE 3 +#define RESMGR_CHMGR_VDEV_PAUSE 4 +#define RESMGR_CHMGR_VDEV_UNPAUSE 5 +#define RESMGR_CHMGR_CTS2S_TX_COMP 6 +#define RESMGR_CHMGR_CFEND_TX_COMP 7 +#define RESMGR_CHMGR_DEFINITION_END 8 + +/* VDEV manager debug ids */ +#define VDEV_MGR_DEFINITION_START 0 +#define VDEV_MGR_FIRST_BMISS_DETECTED 1 +#define VDEV_MGR_FINAL_BMISS_DETECTED 2 +#define VDEV_MGR_BCN_IN_SYNC 3 +#define VDEV_MGR_AP_KEEPALIVE_IDLE 4 +#define VDEV_MGR_AP_KEEPALIVE_INACTIVE 5 +#define VDEV_MGR_AP_KEEPALIVE_UNRESPONSIVE 6 +#define VDEV_MGR_AP_TBTT_CONFIG 7 +#define VDEV_MGR_FIRST_BCN_RECEIVED 8 +#define VDEV_MGR_VDEV_START 9 +#define VDEV_MGR_VDEV_UP 10 +#define VDEV_MGR_PEER_AUTHORIZED 11 +#define VDEV_MGR_OCS_HP_LP_REQ_POSTED 12 +#define VDEV_MGR_VDEV_START_OCS_HP_REQ_COMPLETE 13 +#define VDEV_MGR_VDEV_START_OCS_HP_REQ_STOP 14 +#define VDEV_MGR_HP_START_TIME 15 +#define VDEV_MGR_VDEV_PAUSE_DELAY_UPDATE 16 +#define VDEV_MGR_VDEV_PAUSE_FAIL 17 +#define VDEV_MGR_GEN_PERIODIC_NOA 18 +#define VDEV_MGR_OFF_CHAN_GO_CH_REQ_SETUP 19 +#define VDEV_MGR_DEFINITION_END 20 + +/* WHAL debug identifier definitions */ +#define WHAL_DBGID_DEFINITION_START 0 +#define WHAL_ERROR_ANI_CONTROL 1 +#define WHAL_ERROR_CHIP_TEST1 2 +#define WHAL_ERROR_CHIP_TEST2 3 +#define WHAL_ERROR_EEPROM_CHECKSUM 4 +#define WHAL_ERROR_EEPROM_MACADDR 5 +#define WHAL_ERROR_INTERRUPT_HIU 6 +#define WHAL_ERROR_KEYCACHE_RESET 7 +#define WHAL_ERROR_KEYCACHE_SET 8 +#define WHAL_ERROR_KEYCACHE_TYPE 9 +#define WHAL_ERROR_KEYCACHE_TKIPENTRY 10 +#define WHAL_ERROR_KEYCACHE_WEPLENGTH 11 +#define WHAL_ERROR_PHY_INVALID_CHANNEL 12 +#define WHAL_ERROR_POWER_AWAKE 13 +#define WHAL_ERROR_POWER_SET 14 +#define WHAL_ERROR_RECV_STOPDMA 15 +#define WHAL_ERROR_RECV_STOPPCU 16 +#define WHAL_ERROR_RESET_CHANNF1 17 +#define WHAL_ERROR_RESET_CHANNF2 18 +#define WHAL_ERROR_RESET_PM 19 +#define WHAL_ERROR_RESET_OFFSETCAL 20 +#define WHAL_ERROR_RESET_RFGRANT 21 +#define WHAL_ERROR_RESET_RXFRAME 22 +#define WHAL_ERROR_RESET_STOPDMA 23 +#define WHAL_ERROR_RESET_ERRID 24 +#define WHAL_ERROR_RESET_ADCDCCAL1 25 +#define WHAL_ERROR_RESET_ADCDCCAL2 26 +#define WHAL_ERROR_RESET_TXIQCAL 27 +#define WHAL_ERROR_RESET_RXIQCAL 28 +#define WHAL_ERROR_RESET_CARRIERLEAK 29 +#define WHAL_ERROR_XMIT_COMPUTE 30 +#define WHAL_ERROR_XMIT_NOQUEUE 31 +#define WHAL_ERROR_XMIT_ACTIVEQUEUE 32 +#define WHAL_ERROR_XMIT_BADTYPE 33 +#define WHAL_ERROR_XMIT_STOPDMA 34 +#define WHAL_ERROR_INTERRUPT_BB_PANIC 35 +#define WHAL_ERROR_PAPRD_MAXGAIN_ABOVE_WINDOW 36 +#define WHAL_ERROR_QCU_HW_PAUSE_MISMATCH 37 +#define WHAL_ERROR_POWER_RFLP_CONFIG 38 +#define WHAL_ERROR_POWER_RFLP_SYNTHBYPASS_CONFIG 39 +#define WHAL_ERROR_POWER_RFLP_BIAS2X_CONFIG 40 +#define WHAL_ERROR_POWER_RFLP_PLLBYPASS_CONFIG 41 +#define WHAL_ERROR_POWER_RFLP_OFF1CHAN_CONFIG 42 +#define WHAL_ERROR_POWER_ANTENNA_LMIT 43 +#define WHAL_ERROR_POWER_REGDMN_TX_LMIT 44 +#define WHAL_ERROR_POWER_MODE_SCALED_PWR 45 +#define WHAL_ERROR_POWER_EDGE_PWR_TPSCALE 46 +#define WHAL_ERROR_POWER_CHAN_REGALLOW 47 +#define WHAL_ERROR_WAIT_REG_TIMEOUT 48 +#define WHAL_ERROR_XTAL_SET 49 +#define WHAL_DBGID_DEFINITION_END 50 + +#define COEX_DEBUGID_START 0 +#define BTCOEX_DBG_MCI_1 1 +#define BTCOEX_DBG_MCI_2 2 +#define BTCOEX_DBG_MCI_3 3 +#define BTCOEX_DBG_MCI_4 4 +#define BTCOEX_DBG_MCI_5 5 +#define BTCOEX_DBG_MCI_6 6 +#define BTCOEX_DBG_MCI_7 7 +#define BTCOEX_DBG_MCI_8 8 +#define BTCOEX_DBG_MCI_9 9 +#define BTCOEX_DBG_MCI_10 10 +#define COEX_WAL_BTCOEX_INIT 11 +#define COEX_WAL_PAUSE 12 +#define COEX_WAL_RESUME 13 +#define COEX_UPDATE_AFH 14 +#define COEX_HWQ_EMPTY_CB 15 +#define COEX_MCI_TIMER_HANDLER 16 +#define COEX_MCI_RECOVER 17 +#define ERROR_COEX_MCI_ISR 18 +#define ERROR_COEX_MCI_GPM 19 +#define COEX_ProfileType 20 +#define COEX_LinkID 21 +#define COEX_LinkState 22 +#define COEX_LinkRole 23 +#define COEX_LinkRate 24 +#define COEX_VoiceType 25 +#define COEX_TInterval 26 +#define COEX_WRetrx 27 +#define COEX_Attempts 28 +#define COEX_PerformanceState 29 +#define COEX_LinkType 30 +#define COEX_RX_MCI_GPM_VERSION_QUERY 31 +#define COEX_RX_MCI_GPM_VERSION_RESPONSE 32 +#define COEX_RX_MCI_GPM_STATUS_QUERY 33 +#define COEX_STATE_WLAN_VDEV_DOWN 34 +#define COEX_STATE_WLAN_VDEV_START 35 +#define COEX_STATE_WLAN_VDEV_CONNECTED 36 +#define COEX_STATE_WLAN_VDEV_SCAN_STARTED 37 +#define COEX_STATE_WLAN_VDEV_SCAN_END 38 +#define COEX_STATE_WLAN_DEFAULT 39 +#define COEX_CHANNEL_CHANGE 40 +#define COEX_POWER_CHANGE 41 +#define COEX_CONFIG_MGR 42 +#define COEX_TX_MCI_GPM_BT_CAL_REQ 43 +#define COEX_TX_MCI_GPM_BT_CAL_GRANT 44 +#define COEX_TX_MCI_GPM_BT_CAL_DONE 45 +#define COEX_TX_MCI_GPM_WLAN_CAL_REQ 46 +#define COEX_TX_MCI_GPM_WLAN_CAL_GRANT 47 +#define COEX_TX_MCI_GPM_WLAN_CAL_DONE 48 +#define COEX_TX_MCI_GPM_BT_DEBUG 49 +#define COEX_TX_MCI_GPM_VERSION_QUERY 50 +#define COEX_TX_MCI_GPM_VERSION_RESPONSE 51 +#define COEX_TX_MCI_GPM_STATUS_QUERY 52 +#define COEX_TX_MCI_GPM_HALT_BT_GPM 53 +#define COEX_TX_MCI_GPM_WLAN_CHANNELS 54 +#define COEX_TX_MCI_GPM_BT_PROFILE_INFO 55 +#define COEX_TX_MCI_GPM_BT_STATUS_UPDATE 56 +#define COEX_TX_MCI_GPM_BT_UPDATE_FLAGS 57 +#define COEX_TX_MCI_GPM_UNKNOWN 58 +#define COEX_TX_MCI_SYS_WAKING 59 +#define COEX_TX_MCI_LNA_TAKE 60 +#define COEX_TX_MCI_LNA_TRANS 61 +#define COEX_TX_MCI_SYS_SLEEPING 62 +#define COEX_TX_MCI_REQ_WAKE 63 +#define COEX_TX_MCI_REMOTE_RESET 64 +#define COEX_TX_MCI_TYPE_UNKNOWN 65 +#define COEX_WHAL_MCI_RESET 66 +#define COEX_POLL_BT_CAL_DONE_TIMEOUT 67 +#define COEX_WHAL_PAUSE 68 +#define COEX_RX_MCI_GPM_BT_CAL_REQ 69 +#define COEX_RX_MCI_GPM_BT_CAL_DONE 70 +#define COEX_RX_MCI_GPM_BT_CAL_GRANT 71 +#define COEX_WLAN_CAL_START 72 +#define COEX_WLAN_CAL_RESULT 73 +#define COEX_BtMciState 74 +#define COEX_BtCalState 75 +#define COEX_WlanCalState 76 +#define COEX_RxReqWakeCount 77 +#define COEX_RxRemoteResetCount 78 +#define COEX_RESTART_CAL 79 +#define COEX_SENDMSG_QUEUE 80 +#define COEX_RESETSEQ_LNAINFO_TIMEOUT 81 +#define COEX_MCI_ISR_IntRaw 82 +#define COEX_MCI_ISR_Int1Raw 83 +#define COEX_MCI_ISR_RxMsgRaw 84 +#define COEX_WHAL_COEX_RESET 85 +#define COEX_WAL_COEX_INIT 86 +#define COEX_TXRX_CNT_LIMIT_ISR 87 +#define COEX_CH_BUSY 88 +#define COEX_REASSESS_WLAN_STATE 89 +#define COEX_BTCOEX_WLAN_STATE_UPDATE 90 +#define COEX_BT_NUM_OF_PROFILES 91 +#define COEX_BT_NUM_OF_HID_PROFILES 92 +#define COEX_BT_NUM_OF_ACL_PROFILES 93 +#define COEX_BT_NUM_OF_HI_ACL_PROFILES 94 +#define COEX_BT_NUM_OF_VOICE_PROFILES 95 +#define COEX_WLAN_AGGR_LIMIT 96 +#define COEX_BT_LOW_PRIO_BUDGET 97 +#define COEX_BT_HI_PRIO_BUDGET 98 +#define COEX_BT_IDLE_TIME 99 +#define COEX_SET_COEX_WEIGHT 100 +#define COEX_WLAN_WEIGHT_GROUP 101 +#define COEX_BT_WEIGHT_GROUP 102 +#define COEX_BT_INTERVAL_ALLOC 103 +#define COEX_BT_SCHEME 104 +#define COEX_BT_MGR 105 +#define COEX_BT_SM_ERROR 106 +#define COEX_SYSTEM_UPDATE 107 +#define COEX_LOW_PRIO_LIMIT 108 +#define COEX_HI_PRIO_LIMIT 109 +#define COEX_BT_INTERVAL_START 110 +#define COEX_WLAN_INTERVAL_START 111 +#define COEX_NON_LINK_BUDGET 112 +#define COEX_CONTENTION_MSG 113 +#define COEX_SET_NSS 114 +#define COEX_SELF_GEN_MASK 115 +#define COEX_PROFILE_ERROR 116 +#define COEX_WLAN_INIT 117 +#define COEX_BEACON_MISS 118 +#define COEX_BEACON_OK 119 +#define COEX_BTCOEX_SCAN_ACTIVITY 120 +#define COEX_SCAN_ACTIVITY 121 +#define COEX_FORCE_QUIETTIME 122 +#define COEX_BT_MGR_QUIETTIME 123 +#define COEX_BT_INACTIVITY_TRIGGER 124 +#define COEX_BT_INACTIVITY_REPORTED 125 +#define COEX_TX_MCI_GPM_WLAN_PRIO 126 +#define COEX_TX_MCI_GPM_BT_PAUSE_PROFILE 127 +#define COEX_TX_MCI_GPM_WLAN_SET_ACL_INACTIVITY 128 +#define COEX_RX_MCI_GPM_BT_ACL_INACTIVITY_REPORT 129 +#define COEX_GENERIC_ERROR 130 +#define COEX_RX_RATE_THRESHOLD 131 +#define COEX_RSSI 132 + +#define COEX_WLAN_VDEV_NOTIF_START 133 +#define COEX_WLAN_VDEV_NOTIF_UP 134 +#define COEX_WLAN_VDEV_NOTIF_DOWN 135 +#define COEX_WLAN_VDEV_NOTIF_STOP 136 +#define COEX_WLAN_VDEV_NOTIF_ADD_PEER 137 +#define COEX_WLAN_VDEV_NOTIF_DELETE_PEER 138 +#define COEX_WLAN_VDEV_NOTIF_CONNECTED_PEER 139 +#define COEX_WLAN_VDEV_NOTIF_PAUSE 140 +#define COEX_WLAN_VDEV_NOTIF_UNPAUSED 141 +#define COEX_STATE_WLAN_VDEV_PEER_ADD 142 +#define COEX_STATE_WLAN_VDEV_CONNECTED_PEER 143 +#define COEX_STATE_WLAN_VDEV_DELETE_PEER 144 +#define COEX_STATE_WLAN_VDEV_PAUSE 145 +#define COEX_STATE_WLAN_VDEV_UNPAUSED 146 +#define COEX_SCAN_CALLBACK 147 +#define COEX_RC_SET_CHAINMASK 148 +#define COEX_TX_MCI_GPM_WLAN_SET_BT_RXSS_THRES 149 +#define COEX_TX_MCI_GPM_BT_RXSS_THRES_QUERY 150 +#define COEX_BT_RXSS_THRES 151 +#define COEX_BT_PROFILE_ADD_RMV 152 +#define COEX_BT_SCHED_INFO 153 +#define COEX_TRF_MGMT 154 +#define COEX_SCHED_START 155 +#define COEX_SCHED_RESULT 156 +#define COEX_SCHED_ERROR 157 +#define COEX_SCHED_PRE_OP 158 +#define COEX_SCHED_POST_OP 159 +#define COEX_RX_RATE 160 +#define COEX_ACK_PRIORITY 161 +#define COEX_STATE_WLAN_VDEV_UP 162 +#define COEX_STATE_WLAN_VDEV_PEER_UPDATE 163 +#define COEX_STATE_WLAN_VDEV_STOP 164 +#define COEX_WLAN_PAUSE_PEER 165 +#define COEX_WLAN_UNPAUSE_PEER 166 +#define COEX_WLAN_PAUSE_INTERVAL_START 167 +#define COEX_WLAN_POSTPAUSE_INTERVAL_START 168 +#define COEX_TRF_FREERUN 169 +#define COEX_TRF_SHAPE_PM 170 +#define COEX_TRF_SHAPE_PSP 171 +#define COEX_TRF_SHAPE_S_CTS 172 +#define COEX_CHAIN_CONFIG 173 +#define COEX_SYSTEM_MONITOR 174 +#define COEX_SINGLECHAIN_INIT 175 +#define COEX_MULTICHAIN_INIT 176 +#define COEX_SINGLECHAIN_DBG_1 177 +#define COEX_SINGLECHAIN_DBG_2 178 +#define COEX_SINGLECHAIN_DBG_3 179 +#define COEX_MULTICHAIN_DBG_1 180 +#define COEX_MULTICHAIN_DBG_2 181 +#define COEX_MULTICHAIN_DBG_3 182 +#define COEX_PSP_TX_CB 183 +#define COEX_PSP_RX_CB 184 +#define COEX_PSP_STAT_1 185 +#define COEX_PSP_SPEC_POLL 186 +#define COEX_PSP_READY_STATE 187 +#define COEX_PSP_TX_STATUS_STATE 188 +#define COEX_PSP_RX_STATUS_STATE_1 189 +#define COEX_PSP_NOT_READY_STATE 190 +#define COEX_PSP_DISABLED_STATE 191 +#define COEX_PSP_ENABLED_STATE 192 +#define COEX_PSP_SEND_PSPOLL 193 +#define COEX_PSP_MGR_ENTER 194 +#define COEX_PSP_MGR_RESULT 195 +#define COEX_PSP_NONWLAN_INTERVAL 196 +#define COEX_PSP_STAT_2 197 +#define COEX_PSP_RX_STATUS_STATE_2 198 +#define COEX_PSP_ERROR 199 +#define COEX_T2BT 200 +#define COEX_BT_DURATION 201 +#define COEX_TX_MCI_GPM_WLAN_SCHED_INFO_TRIG 202 +#define COEX_TX_MCI_GPM_WLAN_SCHED_INFO_TRIG_RSP 203 +#define COEX_TX_MCI_GPM_SCAN_OP 204 +#define COEX_TX_MCI_GPM_BT_PAUSE_GPM_TX 205 +#define COEX_CTS2S_SEND 206 +#define COEX_CTS2S_RESULT 207 +#define COEX_ENTER_OCS 208 +#define COEX_EXIT_OCS 209 +#define COEX_UPDATE_OCS 210 +#define COEX_STATUS_OCS 211 +#define COEX_STATS_BT 212 + +#define COEX_MWS_WLAN_INIT 213 +#define COEX_MWS_WBTMR_SYNC 214 +#define COEX_MWS_TYPE2_RX 215 +#define COEX_MWS_TYPE2_TX 216 +#define COEX_MWS_WLAN_CHAVD 217 +#define COEX_MWS_WLAN_CHAVD_INSERT 218 +#define COEX_MWS_WLAN_CHAVD_MERGE 219 +#define COEX_MWS_WLAN_CHAVD_RPT 220 +#define COEX_MWS_CP_MSG_SEND 221 +#define COEX_MWS_CP_ESCAPE 222 +#define COEX_MWS_CP_UNFRAME 223 +#define COEX_MWS_CP_SYNC_UPDATE 224 +#define COEX_MWS_CP_SYNC 225 +#define COEX_MWS_CP_WLAN_STATE_IND 226 +#define COEX_MWS_CP_SYNCRESP_TIMEOUT 227 +#define COEX_MWS_SCHEME_UPDATE 228 +#define COEX_MWS_WLAN_EVENT 229 +#define COEX_MWS_UART_UNESCAPE 230 +#define COEX_MWS_UART_ENCODE_SEND 231 +#define COEX_MWS_UART_RECV_DECODE 232 +#define COEX_MWS_UL_HDL 233 +#define COEX_MWS_REMOTE_EVENT 234 +#define COEX_MWS_OTHER 235 +#define COEX_MWS_ERROR 236 +#define COEX_MWS_ANT_DIVERSITY 237 + +#define COEX_P2P_GO 238 +#define COEX_P2P_CLIENT 239 +#define COEX_SCC_1 240 +#define COEX_SCC_2 241 +#define COEX_MCC_1 242 +#define COEX_MCC_2 243 +#define COEX_TRF_SHAPE_NOA 244 +#define COEX_NOA_ONESHOT 245 +#define COEX_NOA_PERIODIC 246 +#define COEX_LE_1 247 +#define COEX_LE_2 248 +#define COEX_ANT_1 249 +#define COEX_ANT_2 250 +#define COEX_ENTER_NOA 251 +#define COEX_EXIT_NOA 252 +#define COEX_BT_SCAN_PROTECT 253 + +#define COEX_DEBUG_ID_END 254 + +#define SCAN_START_COMMAND_FAILED 0 +#define SCAN_STOP_COMMAND_FAILED 1 +#define SCAN_EVENT_SEND_FAILED 2 +#define SCAN_ENGINE_START 3 +#define SCAN_ENGINE_CANCEL_COMMAND 4 +#define SCAN_ENGINE_STOP_DUE_TO_TIMEOUT 5 +#define SCAN_EVENT_SEND_TO_HOST 6 +#define SCAN_EVENT_ADD 7 +#define SCAN_EVENT_REM 8 +#define SCAN_EVENT_PREEMPTED 9 +#define SCAN_EVENT_RESTARTED 10 +#define SCAN_EVENT_COMPLETED 11 +#define SCAN_SM_REQ_NEXT_CH 12 +#define SCAN_ENG_START 13 +#define SCAN_ENG_CANCEL 14 +#define SCAN_ENG_SPOOFED_MAC_ADDR 15 +#define SCAN_ENG_PARAM_1 16 +#define SCAN_ENG_PARAM_2 17 +#define SCAN_ENG_MAX_SCAN_TIMEOUT 18 +#define SCAN_ENG_START_IN_PROGRESS 19 +#define SCAN_SM_START_COMMAND_FAILED 20 +#define SCAN_SCH_START 21 +#define SCAN_SCH_START_INFO 22 +#define SCAN_SCH_START_NEW_REQ_FAILED 23 +#define SCAN_SCH_START_ALLOC_FAIL 24 +#define SCAN_SCH_ENGINE_STOP_DUE_TO_TIMEOUT 25 +#define SCAN_SCH_POLICY_EVENT 26 +#define SCAN_SCH_CANCEL 27 +#define SCAN_SCH_STOP_COMMAND_FAILED 28 +#define SCAN_SCH_NEXT_SCAN_FAILED 29 +#define SCAN_WMI_SET_CHAN_LIST 30 +#define SCAN_EVENT_STARTED 31 +#define SCAN_EVENT_BSS_CHANNEL 32 +#define SCAN_EVENT_FOREIGN_CHANNEL 33 +#define SCAN_EVENT_DEQUEUED 34 +#define SCAN_EVENT_START_FAILED 35 +#define SCAN_EVENT_FOREIGN_CHANNEL_EXIT 36 +#define SCAN_SM_DISPATCH 37 +#define SCAN_SM_TRANSITIONS 38 +#define SCAN_SM_REQ_NEXT_CHAN 39 +#define SCAN_SEND_PROBE_REQ_RET_VDEV 40 +#define SCAN_SEND_PROBE_REQ_RET_PLM 41 +#define SCAN_SEND_PROBE_REQ_RET_PASSIVE 42 +#define SCAN_SEND_PROBE_REQ_RET_RADAR 43 +#define SCAN_SEND_PROBE_REQ_RET_DFS 44 +#define SCAN_SEND_PROBE_REQ_INFO 45 +#define SCAN_SM_CANCEL 46 +#define SCAN_SM_PROBE_REQ_FRAME_SEND_FAILED 47 +#define SCAN_SCH_BANNED_MODULE 48 +#define SCAN_SM_STATS_INFO 49 +#define SCAN_DBGID_DEFINITION_END 50 + +#define BEACON_EVENT_SWBA_SEND_FAILED 0 +#define BEACON_EVENT_EARLY_RX_BMISS_STATUS 1 +#define BEACON_EVENT_EARLY_RX_SLEEP_SLOP 2 +#define BEACON_EVENT_EARLY_RX_CONT_BMISS_TIMEOUT 3 +#define BEACON_EVENT_EARLY_RX_PAUSE_SKIP_BCN_NUM 4 +#define BEACON_EVENT_EARLY_RX_CLK_DRIFT 5 +#define BEACON_EVENT_EARLY_RX_AP_DRIFT 6 +#define BEACON_EVENT_EARLY_RX_BCN_TYPE 7 + +#define RATECTRL_DBGID_DEFINITION_START 0 +#define RATECTRL_DBGID_ASSOC 1 +#define RATECTRL_DBGID_NSS_CHANGE 2 +#define RATECTRL_DBGID_CHAINMASK_ERR 3 +#define RATECTRL_DBGID_UNEXPECTED_FRAME 4 +#define RATECTRL_DBGID_WAL_RCQUERY 5 +#define RATECTRL_DBGID_WAL_RCUPDATE 6 +#define RATECTRL_DBGID_GTX_UPDATE 7 +#define RATECTRL_DBGID_DEFINITION_END 8 + +#define AP_PS_DBGID_DEFINITION_START 0 +#define AP_PS_DBGID_UPDATE_TIM 1 +#define AP_PS_DBGID_PEER_STATE_CHANGE 2 +#define AP_PS_DBGID_PSPOLL 3 +#define AP_PS_DBGID_PEER_CREATE 4 +#define AP_PS_DBGID_PEER_DELETE 5 +#define AP_PS_DBGID_VDEV_CREATE 6 +#define AP_PS_DBGID_VDEV_DELETE 7 +#define AP_PS_DBGID_SYNC_TIM 8 +#define AP_PS_DBGID_NEXT_RESPONSE 9 +#define AP_PS_DBGID_START_SP 10 +#define AP_PS_DBGID_COMPLETED_EOSP 11 +#define AP_PS_DBGID_TRIGGER 12 +#define AP_PS_DBGID_DUPLICATE_TRIGGER 13 +#define AP_PS_DBGID_UAPSD_RESPONSE 14 +#define AP_PS_DBGID_SEND_COMPLETE 15 +#define AP_PS_DBGID_SEND_N_COMPLETE 16 +#define AP_PS_DBGID_DETECT_OUT_OF_SYNC_STA 17 +#define AP_PS_DBGID_DELIVER_CAB 18 +#define AP_PS_DBGID_NO_CLIENT 27 +#define AP_PS_DBGID_CLIENT_IN_PS_ACTIVE 28 +#define AP_PS_DBGID_CLIENT_IN_PS_NON_ACTIVE 29 +#define AP_PS_DBGID_CLIENT_IN_AWAKE 30 +/* Enhanced Green AP DBGIDs */ +#define AP_PS_DBGID_EGAP_SET_PARAM 31 +#define AP_PS_DBGID_EGAP_VDEV_START 32 +#define AP_PS_DBGID_EGAP_VDEV_STOP 33 +#define AP_PS_DBGID_EGAP_CONN_PEER 34 +#define AP_PS_DBGID_EGAP_DELETE_PEER 35 +#define AP_PS_DBGID_EGAP_WAL_PEER_EVENT 36 +#define AP_PS_DBGID_EGAP_WAL_PDEV_EVENT 37 +#define AP_PS_DBGID_EGAP_NOTIF_STA_SLEEPING 38 +#define AP_PS_DBGID_EGAP_PROC_STA_SLEEPING 39 +#define AP_PS_DBGID_EGAP_PROC_STA_INACTIVITY 40 +#define AP_PS_DBGID_EGAP_CHANGE_CHAINMASK 41 +#define AP_PS_DBGID_EGAP_CHANGE_SM_STATE 42 + +/* WLAN_MODULE_MGMT_TXRX Debugids*/ +#define MGMT_TXRX_DBGID_DEFINITION_START 0 +#define MGMT_TXRX_FORWARD_TO_HOST 1 +#define MGMT_TXRX_MGMT_FRAME_BUFFER_FULL 2 +#define MGMT_TXRX_VDEV_USED_TO_SEND_FRAME_IS_FREE 3 +#define MGMT_TXRX_LOCAL_FRAME_SEND_FAILED 4 +#define MGMT_TXRX_DBGID_DEFINITION_END 5 + +#define WAL_DBGID_DEFINITION_START 0 +#define WAL_DBGID_FAST_WAKE_REQUEST 1 +#define WAL_DBGID_FAST_WAKE_RELEASE 2 +#define WAL_DBGID_SET_POWER_STATE 3 +#define WAL_DBGID_CHANNEL_CHANGE_FORCE_RESET 5 +#define WAL_DBGID_CHANNEL_CHANGE 6 +#define WAL_DBGID_VDEV_START 7 +#define WAL_DBGID_VDEV_STOP 8 +#define WAL_DBGID_VDEV_UP 9 +#define WAL_DBGID_VDEV_DOWN 10 +#define WAL_DBGID_SW_WDOG_RESET 11 +#define WAL_DBGID_TX_SCH_REGISTER_TIDQ 12 +#define WAL_DBGID_TX_SCH_UNREGISTER_TIDQ 13 +#define WAL_DBGID_TX_SCH_TICKLE_TIDQ 14 + +#define WAL_DBGID_XCESS_FAILURES 15 +#define WAL_DBGID_AST_ADD_WDS_ENTRY 16 +#define WAL_DBGID_AST_DEL_WDS_ENTRY 17 +#define WAL_DBGID_AST_WDS_ENTRY_PEER_CHG 18 +#define WAL_DBGID_AST_WDS_SRC_LEARN_FAIL 19 +#define WAL_DBGID_STA_KICKOUT 20 +#define WAL_DBGID_BAR_TX_FAIL 21 +#define WAL_DBGID_BAR_ALLOC_FAIL 22 +#define WAL_DBGID_LOCAL_DATA_TX_FAIL 23 +#define WAL_DBGID_SECURITY_PM4_QUEUED 24 +#define WAL_DBGID_SECURITY_GM1_QUEUED 25 +#define WAL_DBGID_SECURITY_PM4_SENT 26 +#define WAL_DBGID_SECURITY_ALLOW_DATA 27 +#define WAL_DBGID_SECURITY_UCAST_KEY_SET 28 +#define WAL_DBGID_SECURITY_MCAST_KEY_SET 29 +#define WAL_DBGID_SECURITY_ENCR_EN 30 +#define WAL_DBGID_BB_WDOG_TRIGGERED 31 +#define WAL_DBGID_RX_LOCAL_BUFS_LWM 32 +#define WAL_DBGID_RX_LOCAL_DROP_LARGE_MGMT 33 +#define WAL_DBGID_VHT_ILLEGAL_RATE_PHY_ERR_DETECTED 34 +#define WAL_DBGID_DEV_RESET 35 +#define WAL_DBGID_TX_BA_SETUP 36 +#define WAL_DBGID_RX_BA_SETUP 37 +#define WAL_DBGID_DEV_TX_TIMEOUT 38 +#define WAL_DBGID_DEV_RX_TIMEOUT 39 +#define WAL_DBGID_STA_VDEV_XRETRY 40 +#define WAL_DBGID_DCS 41 +#define WAL_DBGID_MGMT_TX_FAIL 42 +#define WAL_DBGID_SET_M4_SENT_MANUALLY 43 +#define WAL_DBGID_PROCESS_4_WAY_HANDSHAKE 44 +#define WAL_DBGID_WAL_CHANNEL_CHANGE_START 45 +#define WAL_DBGID_WAL_CHANNEL_CHANGE_COMPLETE 46 +#define WAL_DBGID_WHAL_CHANNEL_CHANGE_START 47 +#define WAL_DBGID_WHAL_CHANNEL_CHANGE_COMPLETE 48 +#define WAL_DBGID_TX_MGMT_DESCID_SEQ_TYPE_LEN 49 +#define WAL_DBGID_TX_DATA_MSDUID_SEQ_TYPE_LEN 50 +#define WAL_DBGID_TX_DISCARD 51 +#define WAL_DBGID_TX_MGMT_COMP_DESCID_STATUS 52 +#define WAL_DBGID_TX_DATA_COMP_MSDUID_STATUS 53 +#define WAL_DBGID_RESET_PCU_CYCLE_CNT 54 +#define WAL_DBGID_SETUP_RSSI_INTERRUPTS 55 +#define WAL_DBGID_BRSSI_CONFIG 56 +#define WAL_DBGID_CURRENT_BRSSI_AVE 57 +#define WAL_DBGID_BCN_TX_COMP 58 +#define WAL_DBGID_RX_REENTRY 59 +#define WAL_DBGID_SET_HW_CHAINMASK 60 +#define WAL_DBGID_SET_HW_CHAINMASK_TXRX_STOP_FAIL 61 +#define WAL_DBGID_GET_HW_CHAINMASK 62 +#define WAL_DBGID_SMPS_DISABLE 63 +#define WAL_DBGID_SMPS_ENABLE_HW_CNTRL 64 +#define WAL_DBGID_SMPS_SWSEL_CHAINMASK 65 +#define WAL_DBGID_SUSPEND 66 +#define WAL_DBGID_RESUME 67 +#define WAL_DBGID_PEER_TX_FAIL_CNT_THRES_EXCEEDED 68 +#define WAL_DBGID_RX_FULL_REORDER_SUPPORT 69 +#define WAL_DBGID_HCM_BIN 70 +#define WAL_DBGID_HCM_BIN_PENALIZE 71 +#define WAL_DBGID_HCM_BIN_DEPENALIZE 72 +#define WAL_DBGID_AST_UPDATE_WDS_ENTRY 73 +#define WAL_DBGID_PEER_EXT_STATS 74 +#define WAL_DBGID_TX_AC_BUFFER_SET 75 +#define WAL_DBGID_AST_ENTRY_EXIST 76 +#define WAL_DBGID_AST_ENTRY_FULL 77 +#define WAL_DBGID_WMMAC_TXQ_STATUS 78 +#define WAL_DBGID_PROLONGED_TX_PPDU_TOTAL_US 79 +#define WAL_DBGID_UPDATE_USED_TIME 80 +#define WAL_DBGID_PAST_WB_ACK_TIMESTAMP 81 +#define WAL_DBGID_WMMAC_ADD_DEL_TSPEC 82 +#define WAL_DBGID_WMMAC_TIMER_EXPIRY 83 +#define WAL_DBGID_WMMAC_PARAMS 84 +#define WAL_DBGID_TX_MGMT_WAL_PEER_DOES_NOT_EXIST 85 +#define WAL_DBGID_TX_MGMT_WAL_PEER_DELETE_IN_PROGRESS 86 +#define WAL_DBGID_TX_MGMT_FRAME_DESC_ALLOC_FAILED 87 +#define WAL_DBGID_TX_MGMT_TID_STRUCT_NOT_FOUND 88 +#define WAL_DBGID_TX_MGMT_ENQUEUE_FAILED 89 +#define WAL_DBGID_TX_ARP 90 +#define WAL_DBGID_TX_DHCP 91 +#define WAL_DBGID_DEFINITION_END 92 + +#define ANI_DBGID_POLL 0 +#define ANI_DBGID_CONTROL 1 +#define ANI_DBGID_OFDM_PARAMS 2 +#define ANI_DBGID_CCK_PARAMS 3 +#define ANI_DBGID_RESET 4 +#define ANI_DBGID_RESTART 5 +#define ANI_DBGID_OFDM_LEVEL 6 +#define ANI_DBGID_CCK_LEVEL 7 +#define ANI_DBGID_FIRSTEP 8 +#define ANI_DBGID_CYCPWR 9 +#define ANI_DBGID_MRC_CCK 10 +#define ANI_DBGID_SELF_CORR_LOW 11 +#define ANI_DBGID_ENABLE 12 + +#define ANI_DBGID_CURRENT_LEVEL 13 +#define ANI_DBGID_POLL_PERIOD 14 +#define ANI_DBGID_LISTEN_PERIOD 15 +#define ANI_DBGID_OFDM_LEVEL_CFG 16 +#define ANI_DBGID_CCK_LEVEL_CFG 17 + +/* OFFLOAD Manager Debugids*/ +#define OFFLOAD_MGR_DBGID_DEFINITION_START 0 +#define OFFLOADMGR_REGISTER_OFFLOAD 1 +#define OFFLOADMGR_DEREGISTER_OFFLOAD 2 +#define OFFLOADMGR_NO_REG_DATA_HANDLERS 3 +#define OFFLOADMGR_NO_REG_EVENT_HANDLERS 4 +#define OFFLOADMGR_REG_OFFLOAD_FAILED 5 +#define OFFLOADMGR_DEREG_OFFLOAD_FAILED 6 +#define OFFLOADMGR_ENTER_FAILED 7 +#define OFFLOADMGR_EXIT_FAILED 8 +#define OFFLOADMGR_GTK_FAILED 9 +#define OFFLOADMGR_GTK_REKEY_FAILED 10 +#define OFFLOADMGR_DBGID_DEFINITION_END 11 + +/*Resource Debug IDs*/ +#define RESOURCE_DBGID_DEFINITION_START 0 +#define RESOURCE_PEER_ALLOC 1 +#define RESOURCE_PEER_FREE 2 +#define RESOURCE_PEER_ALLOC_WAL_PEER 3 +#define RESOURCE_PEER_NBRHOOD_MGMT_ALLOC 4 +#define RESOURCE_PEER_NBRHOOD_MGMT_INFO 5 +#define RESOURCE_SMALL_MGMT_BUF_FULL 6 +#define RESOURCE_MGMT_AVAIL_BUF_CNT_NOT_ENOUGH 7 +#define RESOURCE_MGMT_BUF_FULL 8 +#define RESOURCE_MGMT_BUF_INC 9 +#define RESOURCE_MGMT_BUF_DEC 10 +#define RESOURCE_DBGID_DEFINITION_END 11 + +/* DCS debug IDs*/ +#define WLAN_DCS_DBGID_INIT 0 +#define WLAN_DCS_DBGID_WMI_CWINT 1 +#define WLAN_DCS_DBGID_TIMER 2 +#define WLAN_DCS_DBGID_CMDG 3 +#define WLAN_DCS_DBGID_CMDS 4 +#define WLAN_DCS_DBGID_DINIT 5 + +/*P2P Module ids*/ +#define P2P_DBGID_DEFINITION_START 0 +#define P2P_DEV_REGISTER 1 +#define P2P_HANDLE_NOA 2 +#define P2P_UPDATE_SCHEDULE_OPPS 3 +#define P2P_UPDATE_SCHEDULE 4 +#define P2P_UPDATE_START_TIME 5 +#define P2P_UPDATE_START_TIME_DIFF_TSF32 6 +#define P2P_UPDATE_START_TIME_FINAL 7 +#define P2P_SETUP_SCHEDULE_TIMER 8 +#define P2P_PROCESS_SCHEDULE_AFTER_CALC 9 +#define P2P_PROCESS_SCHEDULE_STARTED_TIMER 10 +#define P2P_CALC_SCHEDULES_FIRST_CALL_ALL_NEXT_EVENT 11 +#define P2P_CALC_SCHEDULES_FIRST_VALUE 12 +#define P2P_CALC_SCHEDULES_EARLIEST_NEXT_EVENT 13 +#define P2P_CALC_SCHEDULES_SANITY_COUNT 14 +#define P2P_CALC_SCHEDULES_CALL_ALL_NEXT_EVENT_FROM_WHILE_LOOP 15 +#define P2P_CALC_SCHEDULES_TIMEOUT_1 16 +#define P2P_CALC_SCHEDULES_TIMEOUT_2 17 +#define P2P_FIND_ALL_NEXT_EVENTS_REQ_EXPIRED 18 +#define P2P_FIND_ALL_NEXT_EVENTS_REQ_ACTIVE 19 +#define P2P_FIND_NEXT_EVENT_REQ_NOT_STARTED 20 +#define P2P_FIND_NEXT_EVENT_REQ_COMPLETE_NON_PERIODIC 21 +#define P2P_FIND_NEXT_EVENT_IN_MID_OF_NOA 22 +#define P2P_FIND_NEXT_EVENT_REQ_COMPLETE 23 +#define P2P_SCHEDULE_TIMEOUT 24 +#define P2P_CALC_SCHEDULES_ENTER 25 +#define P2P_PROCESS_SCHEDULE_ENTER 26 +#define P2P_FIND_ALL_NEXT_EVENTS_INDIVIDUAL_REQ_AFTER_CHANGE 27 +#define P2P_FIND_ALL_NEXT_EVENTS_INDIVIDUAL_REQ_BEFORE_CHANGE 28 +#define P2P_FIND_ALL_NEXT_EVENTS_ENTER 29 +#define P2P_FIND_NEXT_EVENT_ENTER 30 +#define P2P_NOA_GO_PRESENT 31 +#define P2P_NOA_GO_ABSENT 32 +#define P2P_GO_NOA_NOTIF 33 +#define P2P_GO_TBTT_OFFSET 34 +#define P2P_GO_GET_NOA_INFO 35 +#define P2P_GO_ADD_ONE_SHOT_NOA 36 +#define P2P_GO_GET_NOA_IE 37 +#define P2P_GO_BCN_TX_COMP 38 +#define P2P_DBGID_DEFINITION_END 39 + +/* CSA modules DBGIDs */ +#define CSA_DBGID_DEFINITION_START 0 +#define CSA_OFFLOAD_POOL_INIT 1 +#define CSA_OFFLOAD_REGISTER_VDEV 2 +#define CSA_OFFLOAD_DEREGISTER_VDEV 3 +#define CSA_DEREGISTER_VDEV_ERROR 4 +#define CSA_OFFLOAD_BEACON_RECEIVED 5 +#define CSA_OFFLOAD_BEACON_CSA_RECV 6 +#define CSA_OFFLOAD_CSA_RECV_ERROR_IE 7 +#define CSA_OFFLOAD_CSA_TIMER_ERROR 8 +#define CSA_OFFLOAD_CSA_TIMER_EXP 9 +#define CSA_OFFLOAD_WMI_EVENT_ERROR 10 +#define CSA_OFFLOAD_WMI_EVENT_SENT 11 +#define CSA_OFFLOAD_WMI_CHANSWITCH_RECV 12 +#define CSA_DBGID_DEFINITION_END 13 + +/* Chatter module DBGIDs */ +#define WLAN_CHATTER_DBGID_DEFINITION_START 0 +#define WLAN_CHATTER_ENTER 1 +#define WLAN_CHATTER_EXIT 2 +#define WLAN_CHATTER_FILTER_HIT 3 +#define WLAN_CHATTER_FILTER_MISS 4 +#define WLAN_CHATTER_FILTER_FULL 5 +#define WLAN_CHATTER_FILTER_TM_ADJ 6 +#define WLAN_CHATTER_BUFFER_FULL 7 +#define WLAN_CHATTER_TIMEOUT 8 +#define WLAN_CHATTER_MC_FILTER_ADD 9 +#define WLAN_CHATTER_MC_FILTER_DEL 10 +#define WLAN_CHATTER_MC_FILTER_ALLOW 11 +#define WLAN_CHATTER_MC_FILTER_DROP 12 +#define WLAN_CHATTER_COALESCING_FILTER_ADD 13 +#define WLAN_CHATTER_COALESCING_FILTER_DEL 14 +#define WLAN_CHATTER_DBGID_DEFINITION_END 15 + +#define WOW_DBGID_DEFINITION_START 0 +#define WOW_ENABLE_CMDID 1 +#define WOW_RECV_DATA_PKT 2 +#define WOW_WAKE_HOST_DATA 3 +#define WOW_RECV_MGMT 4 +#define WOW_WAKE_HOST_MGMT 5 +#define WOW_RECV_EVENT 6 +#define WOW_WAKE_HOST_EVENT 7 +#define WOW_INIT 8 +#define WOW_RECV_MAGIC_PKT 9 +#define WOW_RECV_BITMAP_PATTERN 10 +#define WOW_AP_VDEV_DISALLOW 11 +#define WOW_STA_VDEV_DISALLOW 12 +#define WOW_P2PGO_VDEV_DISALLOW 13 +#define WOW_NS_OFLD_ENABLE 14 +#define WOW_ARP_OFLD_ENABLE 15 +#define WOW_NS_ARP_OFLD_DISABLE 16 +#define WOW_NS_RECEIVED 17 +#define WOW_NS_REPLIED 18 +#define WOW_ARP_RECEIVED 19 +#define WOW_ARP_REPLIED 20 +#define WOW_BEACON_OFFLOAD_TX 21 +#define WOW_BEACON_OFFLOAD_CFG 22 +#define WOW_IBSS_VDEV_ALLOW 23 +#define WOW_DBGID_DEFINITION_END 24 + +/* SWBMISS module DBGIDs */ +#define SWBMISS_DBGID_DEFINITION_START 0 +#define SWBMISS_ENABLED 1 +#define SWBMISS_DISABLED 2 +#define SWBMISS_UPDATE_BEACON_RSSI 3 +#define SWBMISS_CHECK_RSSI_OUTLIER 4 +#define SWBMISS_TIMER_SET 5 +#define SWBMISS_DBGID_DEFINITION_END 6 + +/* WLAN module DBGIDS */ +#define ROAM_DBGID_DEFINITION_START 0 +#define ROAM_MODULE_INIT 1 +#define ROAM_DEV_START 2 +#define ROAM_CONFIG_RSSI_THRESH 3 +#define ROAM_CONFIG_SCAN_PERIOD 4 +#define ROAM_CONFIG_AP_PROFILE 5 +#define ROAM_CONFIG_CHAN_LIST 6 +#define ROAM_CONFIG_SCAN_PARAMS 7 +#define ROAM_CONFIG_RSSI_CHANGE 8 +#define ROAM_SCAN_TIMER_START 9 +#define ROAM_SCAN_TIMER_EXPIRE 10 +#define ROAM_SCAN_TIMER_STOP 11 +#define ROAM_SCAN_STARTED 12 +#define ROAM_SCAN_COMPLETE 13 +#define ROAM_SCAN_CANCELLED 14 +#define ROAM_CANDIDATE_FOUND 15 +#define ROAM_RSSI_ACTIVE_SCAN 16 +#define ROAM_RSSI_ACTIVE_ROAM 17 +#define ROAM_RSSI_GOOD 18 +#define ROAM_BMISS_FIRST_RECV 19 +#define ROAM_DEV_STOP 20 +#define ROAM_FW_OFFLOAD_ENABLE 21 +#define ROAM_CANDIDATE_SSID_MATCH 22 +#define ROAM_CANDIDATE_SECURITY_MATCH 23 +#define ROAM_LOW_RSSI_INTERRUPT 24 +#define ROAM_HIGH_RSSI_INTERRUPT 25 +#define ROAM_SCAN_REQUESTED 26 +#define ROAM_BETTER_CANDIDATE_FOUND 27 +#define ROAM_BETTER_AP_EVENT 28 +#define ROAM_CANCEL_LOW_PRIO_SCAN 29 +#define ROAM_FINAL_BMISS_RECVD 30 +#define ROAM_CONFIG_SCAN_MODE 31 +#define ROAM_BMISS_FINAL_SCAN_ENABLE 32 +#define ROAM_SUITABLE_AP_EVENT 33 +#define ROAM_RSN_IE_PARSE_ERROR 34 +#define ROAM_WPA_IE_PARSE_ERROR 35 +#define ROAM_SCAN_CMD_FROM_HOST 36 +#define ROAM_HO_SORT_CANDIDATE 37 +#define ROAM_HO_SAVE_CANDIDATE 38 +#define ROAM_HO_GET_CANDIDATE 39 +#define ROAM_HO_OFFLOAD_SET_PARAM 40 +#define ROAM_HO_SM 41 +#define ROAM_HO_HTT_SAVED 42 +#define ROAM_HO_SYNC_START 43 +#define ROAM_HO_START 44 +#define ROAM_HO_SYNC_COMPLETE 45 +#define ROAM_HO_STOP 46 +#define ROAM_HO_HTT_FORWARD 47 +#define ROAM_CONFIG_SCAN_PARAMS_1 48 +#define ROAM_SCAN_COMPLETE_1 49 +#define ROAM_SWBMISS_BCN_RECV_VAL 50 +#define ROAM_SWBMISS_BCN_RECV_THRE2 51 +#define ROAM_SCAN_REQUESTED_1 52 +#define ROAM_HO_SORT_CANDIDATE_CUR 53 +#define ROAM_HO_SAVE_CANDIDATE_DUP 54 +#define ROAM_HO_SM_EVENT 55 +#define ROAM_HO_ENTER_CH 56 +#define ROAM_HO_MGMT_RX 57 +#define ROAM_HO_CANDIDATE_INFO 58 +#define ROAM_HO_OFFLD_DATA_STORE 59 +#define ROAM_HO_HTT_DATA_STORE 60 +#define ROAM_HO_UPDATE_STATUS 61 +#define ROAM_HO_OCS_CH_CB 62 +#define ROAM_RSSI_INTERRUPT_STATE 63 +#define ROAM_INVOKE_PARAM_CHECK 64 +#define ROAM_INVOKE_PARAM_CHAN 65 +#define ROAM_INVOKE_PARAM_BSSID 66 +#define ROAM_INVOKE_STATE_CHECK 67 +#define ROAM_INVOKE_START_SUCCESS 68 +#define ROAM_INVOKE_START_FAILURE 69 +#define ROAM_INVOKE_BSSID_CHECK 70 +#define ROAM_CANDIDATE_INFO 71 +#define ROAM_CANDIDATE_FILTER_MATCH 72 +#define ROAM_CANDIDATE_RSSI_ADJUST 73 +#define ROAM_CONFIG_ROAM_FILTER 74 +#define ROAM_EXTENDED_RSSI_TRESHOLD_1 75 +#define ROAM_EXTENDED_RSSI_TRESHOLD_2 76 +#define ROAM_BLACKLIST_BSSID 77 +#define ROAM_WHITELIST_SSID 78 +#define ROAM_WHITELIST_SSID_2 79 +#define ROAM_PREFERRED_BSSID 80 +#define ROAM_PREFERRED_FACTOR 81 +#define ROAM_SCAN_HIRSSI_THRESHOLD 82 +#define ROAM_SCAN_HIRSSI_CHECK 83 +#define ROAM_SCAN_HIRSSI_TIMER_EXPIRED 84 +#define ROAM_SCAN_EXTSCAN_CHECK 85 +#define ROAM_STA_KICKOUT_RECV 86 +#define ROAM_DBGID_DEFINITION_END 87 + +/* DATA_TXRX module DBGIDs*/ +#define DATA_TXRX_DBGID_DEFINITION_START 0 +#define DATA_TXRX_DBGID_RX_DATA_SEQ_LEN_INFO 1 +#define DATA_TXRX_DBGID_REPLAY_CHECK 2 +#define DATA_TXRX_DBGID_DUP_CHECK 3 +#define DATA_TXRX_INVALID_PEER_AST_STA 4 +#define DATA_TXRX_INVALID_PEER_AST_P2P 5 +#define DATA_TXRX_INVALID_ADDR1_STA 6 +#define DATA_TXRX_INVALID_ADDR1_P2P 7 +#define DATA_TXRX_MULTICAST_BROADCAST_FRAME 8 +#define DATA_TXRX_INVALID_FRAME_CTRL_OR_ADDR 9 +#define DATA_TXRX_DBGID_DEFINITION_END 10 + +/* HTT module DBGIDs */ +#define HTT_DBGID_DEFINITION_START 0 +#define HTT_DBGID_INVALID_VDEVID_OR_GROUP 1 +#define HTT_DBGID_DISCARD_INTERNAL_PKTS 2 +#define HTT_DBGID_DISCARD_TX_PKTS 3 +#define HTT_DBGID_GROUP_CHANGE 4 +#define HTT_DBGID_GROUP_CREDIT_STATS 5 +#define HTT_DBGID_DISCARD_INTERNAL_PKTS_NUM 6 +#define HTT_DBGID_DEFINITION_END 7 + +/* TDLS module DBGIDs*/ +#define TDLS_DBGID_DEFINITION_START 0 +#define TDLS_DBGID_VDEV_CREATE 1 +#define TDLS_DBGID_VDEV_DELETE 2 +#define TDLS_DBGID_ENABLED_PASSIVE 3 +#define TDLS_DBGID_ENABLED_ACTIVE 4 +#define TDLS_DBGID_DISABLED 5 +#define TDLS_DBGID_CONNTRACK_TIMER 6 +#define TDLS_DBGID_WAL_SET 7 +#define TDLS_DBGID_WAL_GET 8 +#define TDLS_DBGID_WAL_PEER_UPDATE_SET 9 +#define TDLS_DBGID_WAL_PEER_UPDATE_EVT 10 +#define TDLS_DBGID_WAL_VDEV_CREATE 11 +#define TDLS_DBGID_WAL_VDEV_DELETE 12 +#define TDLS_DBGID_WLAN_EVENT 13 +#define TDLS_DBGID_WLAN_PEER_UPDATE_SET 14 +#define TDLS_DBGID_PEER_EVT_DRP_THRESH 15 +#define TDLS_DBGID_PEER_EVT_DRP_RATE 16 +#define TDLS_DBGID_PEER_EVT_DRP_RSSI 17 +#define TDLS_DBGID_PEER_EVT_DISCOVER 18 +#define TDLS_DBGID_PEER_EVT_DELETE 19 +#define TDLS_DBGID_PEER_CAP_UPDATE 20 +#define TDLS_DBGID_UAPSD_SEND_PTI_FRAME 21 +#define TDLS_DBGID_UAPSD_SEND_PTI_FRAME2PEER 22 +#define TDLS_DBGID_UAPSD_START_PTR_TIMER 23 +#define TDLS_DBGID_UAPSD_CANCEL_PTR_TIMER 24 +#define TDLS_DBGID_UAPSD_PTR_TIMER_TIMEOUT 25 +#define TDLS_DBGID_UAPSD_STA_PS_EVENT_HANDLER 26 +#define TDLS_DBGID_UAPSD_PEER_EVENT_HANDLER 27 +#define TDLS_DBGID_UAPSD_PS_DEFAULT_SETTINGS 28 +#define TDLS_DBGID_UAPSD_GENERIC 29 + +/* TXBF Module IDs */ +#define TXBFEE_DBGID_START 0 +#define TXBFEE_DBGID_NDPA_RECEIVED 1 +#define TXBFEE_DBGID_HOST_CONFIG_TXBFEE_TYPE 2 +#define TXBFER_DBGID_SEND_NDPA 3 +#define TXBFER_DBGID_GET_NDPA_BUF_FAIL 4 +#define TXBFER_DBGID_SEND_NDPA_FAIL 5 +#define TXBFER_DBGID_GET_NDP_BUF_FAIL 6 +#define TXBFER_DBGID_SEND_NDP_FAIL 7 +#define TXBFER_DBGID_GET_BRPOLL_BUF_FAIL 8 +#define TXBFER_DBGID_SEND_BRPOLL_FAIL 9 +#define TXBFER_DBGID_HOST_CONFIG_CMDID 10 +#define TXBFEE_DBGID_HOST_CONFIG_CMDID 11 +#define TXBFEE_DBGID_ENABLE_UPLOAD_H 12 +#define TXBFEE_DBGID_UPLOADH_CV_TAG 13 +#define TXBFEE_DBGID_UPLOADH_H_TAG 14 +#define TXBFEE_DBGID_CAPTUREH_RECEIVED 15 +#define TXBFEE_DBGID_PACKET_IS_STEERED 16 +#define TXBFEE_UPLOADH_EVENT_ALLOC_MEM_FAIL 17 +#define TXBFEE_DBGID_SW_WAR_AID_ZERO 18 +#define TXBFEE_DBGID_BRPOLL_RECEIVED 19 +#define TXBFEE_DBGID_GID_RECEIVED 20 +#define TXBFEE_DBGID_END 21 + +/* SMPS module DBGIDs */ +#define STA_SMPS_DBGID_DEFINITION_START 0 +#define STA_SMPS_DBGID_CREATE_PDEV_INSTANCE 1 +#define STA_SMPS_DBGID_CREATE_VIRTUAL_CHAN_INSTANCE 2 +#define STA_SMPS_DBGID_DELETE_VIRTUAL_CHAN_INSTANCE 3 +#define STA_SMPS_DBGID_CREATE_STA_INSTANCE 4 +#define STA_SMPS_DBGID_DELETE_STA_INSTANCE 5 +#define STA_SMPS_DBGID_VIRTUAL_CHAN_SMPS_START 6 +#define STA_SMPS_DBGID_VIRTUAL_CHAN_SMPS_STOP 7 +#define STA_SMPS_DBGID_SEND_SMPS_ACTION_FRAME 8 +#define STA_SMPS_DBGID_HOST_FORCED_MODE 9 +#define STA_SMPS_DBGID_FW_FORCED_MODE 10 +#define STA_SMPS_DBGID_RSSI_THRESHOLD_CROSSED 11 +#define STA_SMPS_DBGID_SMPS_ACTION_FRAME_COMPLETION 12 +#define STA_SMPS_DBGID_DTIM_EBT_EVENT_CHMASK_UPDATE 13 +#define STA_SMPS_DBGID_DTIM_CHMASK_UPDATE 14 +#define STA_SMPS_DBGID_DTIM_BEACON_EVENT_CHMASK_UPDATE 15 +#define STA_SMPS_DBGID_DTIM_POWER_STATE_CHANGE 16 +#define STA_SMPS_DBGID_DTIM_CHMASK_UPDATE_SLEEP 17 +#define STA_SMPS_DBGID_DTIM_CHMASK_UPDATE_AWAKE 18 + +#define STA_SMPS_DBGID_DEFINITION_END 18 + +/* RTT module DBGIDs*/ +#define RTT_CALL_FLOW 0 +#define RTT_REQ_SUB_TYPE 1 +#define RTT_MEAS_REQ_HEAD 2 +#define RTT_MEAS_REQ_BODY 3 +#define RTT_INIT_GLOBAL_STATE 6 +#define RTT_REPORT 8 +#define RTT_ERROR_REPORT 10 +#define RTT_TIMER_STOP 11 +#define RTT_SEND_TM_FRAME 12 +#define RTT_V3_RESP_CNT 13 +#define RTT_V3_RESP_FINISH 14 +#define RTT_CHANNEL_SWITCH_REQ 15 +#define RTT_CHANNEL_SWITCH_GRANT 16 +#define RTT_CHANNEL_SWITCH_COMPLETE 17 +#define RTT_CHANNEL_SWITCH_PREEMPT 18 +#define RTT_CHANNEL_SWITCH_STOP 19 +#define RTT_TIMER_START 20 + +#define RTT_FTM_PARAM_INFO 21 +#define RTT_RX_TM_FRAME 22 +#define RTT_INITR_TSTAMP 23 +#define RTT_RSPDR_TSTAMP 24 +#define RTT_TX_COMP_STATUS 25 +#define RTT_ERROR_WMI_EVENT 26 +#define RTT_MEASUREMENT_VALUES 27 + +/* WLAN HB module DBGIDs */ +#define WLAN_HB_DBGID_DEFINITION_START 0 +#define WLAN_HB_DBGID_INIT 1 +#define WLAN_HB_DBGID_TCP_GET_TXBUF_FAIL 2 +#define WLAN_HB_DBGID_TCP_SEND_FAIL 3 +#define WLAN_HB_DBGID_BSS_PEER_NULL 4 +#define WLAN_HB_DBGID_UDP_GET_TXBUF_FAIL 5 +#define WLAN_HB_DBGID_UDP_SEND_FAIL 6 +#define WLAN_HB_DBGID_WMI_CMD_INVALID_PARAM 7 +#define WLAN_HB_DBGID_WMI_CMD_INVALID_OP 8 +#define WLAN_HB_DBGID_WOW_NOT_ENTERED 9 +#define WLAN_HB_DBGID_ALLOC_SESS_FAIL 10 +#define WLAN_HB_DBGID_CTX_NULL 11 +#define WLAN_HB_DBGID_CHKSUM_ERR 12 +#define WLAN_HB_DBGID_UDP_TX 13 +#define WLAN_HB_DBGID_TCP_TX 14 +#define WLAN_HB_DBGID_DEFINITION_END 15 + +/* Thermal Manager DBGIDs*/ +#define THERMAL_MGR_DBGID_DEFINITION_START 0 +#define THERMAL_MGR_NEW_THRESH 1 +#define THERMAL_MGR_THRESH_CROSSED 2 +#define THERMAL_MGR_DBGID_DEFINITION_END 3 + +/* WLAN PHYERR DFS(parse/filter) DBGIDs */ +#define WLAN_PHYERR_DFS_DBGID_DEFINITION_START 0 +#define WLAN_PHYERR_DFS_PHYERR_INFO_CHAN_BUFLEN 1 +#define WLAN_PHYERR_DFS_PHYERR_INFO_PPDU 2 +#define WLAN_PHYERR_DFS_DBDID_RADAR_SUMMARY 3 +#define WLAN_PHYERR_DFS_DBDID_SEARCH_FFT 4 +#define WLAN_PHTERR_DFS_DBDID_FILTER_STATUS 5 +#define WLAN_PHYERR_DFS_DBGID_DEFINITION_END 6 + +/* RMC DBGIDs */ +#define RMC_DBGID_DEFINITION_START 0 +#define RMC_CREATE_INSTANCE 1 +#define RMC_DELETE_INSTANCE 2 +#define RMC_LDR_SEL 3 +#define RMC_NO_LDR 4 +#define RMC_LDR_NOT_SEL 5 +#define RMC_LDR_INF_SENT 6 +#define RMC_PEER_ADD 7 +#define RMC_PEER_DELETE 8 +#define RMC_PEER_UNKNOWN 9 +#define RMC_SET_MODE 10 +#define RMC_SET_ACTION_PERIOD 11 +#define RMC_ACTION_FRAME_RX 12 +#define RMC_WAL_EVENT_HANDLER 13 +#define RMC_BLACKLIST_PEER 14 +#define RMC_WHITELIST_PEER 15 +#define RMC_PEER_BCN_INFO 16 +#define RMC_DBGID_DEFINITION_END 17 + +/* UNIT_TEST module DBGIDs */ +#define UNIT_TEST_GEN 0 + +/* MLME module DBGIDs */ +#define MLME_DEBUG_CMN 0 +#define MLME_DEBUG_IF 1 +#define MLME_DEBUG_AUTH 2 +#define MLME_DEBUG_REASSOC 3 +#define MLME_DEBUG_DEAUTH 4 +#define MLME_DEBUG_DISASSOC 5 +#define MLME_DEBUG_ROAM 6 +#define MLME_DEBUG_RETRY 7 +#define MLME_DEBUG_TIMER 8 +#define MLME_DEBUG_FRAMEPARSE 9 + +/* SUPPL module DBGIDs */ +#define SUPPL_DBGID_INIT 0 +#define SUPPL_DBGID_RECV_EAPOL 1 +#define SUPPL_DBGID_RECV_EAPOL_TIMEOUT 2 +#define SUPPL_DBGID_SEND_EAPOL 3 +#define SUPPL_DBGID_MIC_MISMATCH 4 +#define SUPPL_DBGID_FINISH 5 +#define SUPPL_DBGID_GET_FRM_INFO 6 +#define SUPPL_DBGID_DUMP_TYPE 7 +#define SUPPL_DBGID_DUMP_HEX 8 +#define SUPPL_DBGID_NODE_NOT_FOUND 9 +#define SUPPL_DBGID_GET_EAPOL_BUF 10 +#define SUPPL_DBGID_GET_BUF_FAIL 11 +#define SUPPL_DBGID_RECV_EAPOL_ERROR 12 + +/* Stats Module DBGIDs */ +#define WLAN_STATS_DBGID_DEFINITION_START 0 +#define WLAN_STATS_DBGID_EST_LINKSPEED_VDEV_EN_DIS 1 +#define WLAN_STATS_DBGID_EST_LINKSPEED_CHAN_TIME_START 2 +#define WLAN_STATS_DBGID_EST_LINKSPEED_CHAN_TIME_END 3 +#define WLAN_STATS_DBGID_EST_LINKSPEED_CALC 4 +#define WLAN_STATS_DBGID_EST_LINKSPEED_UPDATE_HOME_CHAN 5 +#define WLAN_STATS_DBGID_RSSI 6 +#define WLAN_STATS_DBGID_CNE_RSSI 7 +#define WLAN_STATS_DBGID_DEFINITION_END 8 +/* NAN DBGIDs */ +#define NAN_DBGID_START 0 + +/* Debug IDs for debug logs. 3 args max, not fixed. */ +#define NAN_DBGID_DBG_LOG_FIRST 1 +#define NAN_DBGID_FUNC_BEGIN NAN_DBGID_DBG_LOG_FIRST +#define NAN_DBGID_FUNC_END 2 +#define NAN_DBGID_MAIN_DEBUG 3 +#define NAN_DBGID_MAC_DEBUG 4 +#define NAN_DBGID_BLOOM_FILTER_DEBUG 5 +#define NAN_DBGID_MAC_ADDR 6 +#define NAN_DBGID_PARAM_UPDATED 7 +#define NAN_DBGID_NULL_PTR 8 +#define NAN_DBGID_INVALID_FUNC_ARG 9 +#define NAN_DBGID_INVALID_MSG_PARAM 10 +#define NAN_DBGID_MISSING_MSG_PARAM 11 +#define NAN_DBGID_DEPRECATED_MSG_PARAM 12 +#define NAN_DBGID_UNSUPPORTED_MSG_PARAM 13 +#define NAN_DBGID_INVALID_PKT_DATA 14 +#define NAN_DBGID_LOG_PKT_DATA 15 +#define NAN_DBGID_INVALID_VALUE 16 +#define NAN_DBGID_INVALID_OPERATION 17 +#define NAN_DBGID_INVALID_STATE 18 +#define NAN_DBGID_FUNCTION_ENABLED 19 +#define NAN_DBGID_FUNCTION_DISABLED 20 +#define NAN_DBGID_INVALID_FUNCTION_STATE 21 +#define NAN_DBGID_READ_ERROR 22 +#define NAN_DBGID_WRITE_ERROR 23 +#define NAN_DBGID_RECEIVE_ERROR 24 +#define NAN_DBGID_TRANSMIT_ERROR 25 +#define NAN_DBGID_PARSE_ERROR 26 +#define NAN_DBGID_RES_ALLOC_ERROR 27 +/* PLEASE KEEP THIS ONE AT THE END */ +#define NAN_DBGID_DBG_LOG_LAST 28 + +/* Debug IDs for event logs. */ + +#define NAN_DBGID_EVT_BASE NAN_DBGID_DBG_LOG_LAST +/* args: */ +#define NAN_DBGID_NAN_ENABLED (NAN_DBGID_EVT_BASE + 0) +/* args: */ +#define NAN_DBGID_NAN_DISABLED (NAN_DBGID_EVT_BASE + 1) +/* args: */ +#define NAN_DBGID_CONFIG_RESTORED (NAN_DBGID_EVT_BASE + 2) +/* args: framesQueued */ +#define NAN_DBGID_SDF_QUEUED (NAN_DBGID_EVT_BASE + 3) +/* args: old, new */ +#define NAN_DBGID_TW_CHANGED (NAN_DBGID_EVT_BASE + 4) +/* args: */ +#define NAN_DBGID_DW_START (NAN_DBGID_EVT_BASE + 5) +/* args: busyDiff */ +#define NAN_DBGID_DW_END (NAN_DBGID_EVT_BASE + 6) +/* args: oldClusterId, newClusterId */ +#define NAN_DBGID_CLUSTER_ID_CHANGED (NAN_DBGID_EVT_BASE + 7) +/* args: cmd, buffer, length */ +#define NAN_DBGID_WMI_CMD_RECEIVED (NAN_DBGID_EVT_BASE + 8) +/* args: pEventPkt, pEventBuf, eventSize, dataSize */ +#define NAN_DBGID_WMI_EVT_SENT (NAN_DBGID_EVT_BASE + 9) +/* args: type length, readLen */ +#define NAN_DBGID_TLV_READ (NAN_DBGID_EVT_BASE + 10) +/* args: type length, writeLen */ +#define NAN_DBGID_TLV_WRITE (NAN_DBGID_EVT_BASE + 11) +/* args: handle */ +#define NAN_DBGID_PUBSUB_UPDATED (NAN_DBGID_EVT_BASE + 12) +/* args: handle */ +#define NAN_DBGID_PUBSUB_REMOVE_DEFERED (NAN_DBGID_EVT_BASE + 13) +/* args: handle */ +#define NAN_DBGID_PUBSUB_REMOVE_PENDING (NAN_DBGID_EVT_BASE + 14) +/* args: handle */ +#define NAN_DBGID_PUBSUB_REMOVED (NAN_DBGID_EVT_BASE + 15) +/* args: handle */ +#define NAN_DBGID_PUBSUB_PROCESSED (NAN_DBGID_EVT_BASE + 16) +/* args: handle, sid1, sid2, svcCtrl, length */ +#define NAN_DBGID_PUBSUB_MATCHED (NAN_DBGID_EVT_BASE + 17) +/* args: handle, flags */ +#define NAN_DBGID_PUBSUB_PREPARED (NAN_DBGID_EVT_BASE + 18) +/* args: handle, mac1, mac2 */ +#define NAN_DBGID_PUBSUB_FOLLOWUP_TRANSMIT (NAN_DBGID_EVT_BASE + 19) +/* args: handle, mac1, mac2 */ +#define NAN_DBGID_PUBSUB_FOLLOWUP_RECEIVED (NAN_DBGID_EVT_BASE + 20) +/* args: subscribeHandle, matchHandle, oldTimeout, newTimeout */ +#define NAN_DBGID_SUBSCRIBE_UNMATCH_TIMEOUT_UPDATE (NAN_DBGID_EVT_BASE + 21) +/* args: subscribeHandle, matchHandle, timestamp*/ +#define NAN_DBGID_SUBSCRIBE_MATCH_NEW (NAN_DBGID_EVT_BASE + 22) +/* args: subscribeHandle, matchHandle, timestamp*/ +#define NAN_DBGID_SUBSCRIBE_MATCH_REPEAT (NAN_DBGID_EVT_BASE + 23) +/* args: subscribeHandle, matchHandle, matchTimestamp, timestamp*/ +#define NAN_DBGID_SUBSCRIBE_MATCH_EXPIRED (NAN_DBGID_EVT_BASE + 24) +/* args: subscribeHandle, matchHandle, matchTimestamp, timestamp */ +#define NAN_DBGID_SUBSCRIBE_MATCH_LOG (NAN_DBGID_EVT_BASE + 25) +/* args: sid1, sid2 */ +#define NAN_DBGID_SERVICE_ID_CREATED (NAN_DBGID_EVT_BASE + 26) +/* args: size */ +#define NAN_DBGID_SD_ATTR_BUILT (NAN_DBGID_EVT_BASE + 27) +/* args: offset */ +#define NAN_DBGID_SERVICE_RSP_OFFSET (NAN_DBGID_EVT_BASE + 28) +/* args: offset */ +#define NAN_DBGID_SERVICE_INFO_OFFSET (NAN_DBGID_EVT_BASE + 29) +/* args: chan, interval, start_time */ +#define NAN_DBGID_CHREQ_CREATE (NAN_DBGID_EVT_BASE + 30) +/* args: start_time, status */ +#define NAN_DBGID_CHREQ_UPDATE (NAN_DBGID_EVT_BASE + 31) +/* args: chan, interval, status */ +#define NAN_DBGID_CHREQ_REMOVE (NAN_DBGID_EVT_BASE + 32) +/* args: type, timestamp */ +#define NAN_DBGID_CHREQ_GRANT (NAN_DBGID_EVT_BASE + 33) +/* args: type, timestamp */ +#define NAN_DBGID_CHREQ_END (NAN_DBGID_EVT_BASE + 34) +/* args: type, timestamp */ +#define NAN_DBGID_CHREQ_ERROR (NAN_DBGID_EVT_BASE + 35) +/* args: type, length, timestamp, rssi */ +#define NAN_DBGID_RX_CALLBACK (NAN_DBGID_EVT_BASE + 36) +/* args: type, handle, bufp, status, timestamp */ +#define NAN_DBGID_TX_COMPLETE (NAN_DBGID_EVT_BASE + 37) +/* args: tsf, tsf */ +#define NAN_DBGID_TSF_TIMEOUT (NAN_DBGID_EVT_BASE + 38) +/* args: clusterId, clusterStart */ +#define NAN_DBGID_SYNC_START (NAN_DBGID_EVT_BASE + 39) +/* args: clusterId */ +#define NAN_DBGID_SYNC_STOP (NAN_DBGID_EVT_BASE + 40) +/* args: enable, scanType, rval */ +#define NAN_DBGID_NAN_SCAN (NAN_DBGID_EVT_BASE + 41) +/* args: scanType */ +#define NAN_DBGID_NAN_SCAN_COMPLETE (NAN_DBGID_EVT_BASE + 42) +/* args: masterPref */ +#define NAN_DBGID_MPREF_CHANGE (NAN_DBGID_EVT_BASE + 43) +/* args: masterPref, randFactor */ +#define NAN_DBGID_WARMUP_EXPIRE (NAN_DBGID_EVT_BASE + 44) +/* args: randFactor */ +#define NAN_DBGID_RANDOM_FACTOR_EXPIRE (NAN_DBGID_EVT_BASE + 45) +/* args: tsf, tsf */ +#define NAN_DBGID_DW_SKIP (NAN_DBGID_EVT_BASE + 46) +/* args: type, tsfDiff */ +#define NAN_DBGID_DB_SKIP (NAN_DBGID_EVT_BASE + 47) +/* args: TBD */ +#define NAN_DBGID_BEACON_RX (NAN_DBGID_EVT_BASE + 48) +/* args: TBD */ +#define NAN_DBGID_BEACON_TX (NAN_DBGID_EVT_BASE + 49) +/* args: clusterId */ +#define NAN_DBGID_CLUSTER_MERGE (NAN_DBGID_EVT_BASE + 50) +/* args: cmd, status, value */ +#define NAN_DBGID_TEST_CMD_EXEC (NAN_DBGID_EVT_BASE + 51) +/* args: tsfHi, tsfLo, age */ +#define NAN_DBGID_APPLY_BEACON_TSF (NAN_DBGID_EVT_BASE + 52) +/* args: behindFlag, diff */ +#define NAN_DBGID_TSF_UPDATE (NAN_DBGID_EVT_BASE + 53) +/* args: argc==4 (rawTsfHi, rawTsfLo, nanTsfHi, nanTsfLo), argc==2(offsetHi, offsetLo) */ +#define NAN_DBGID_SET_TSF (NAN_DBGID_EVT_BASE + 54) +/* args: rankHi, rankLo, mp, rf */ +#define NAN_DBGID_NEW_MASTERRANK (NAN_DBGID_EVT_BASE + 55) +/* args: amRankHi, amRankLo, mp, rf */ +#define NAN_DBGID_NEW_ANCHORMASTER (NAN_DBGID_EVT_BASE + 56) +/* args: amRankHi, amRankLo, HC, BTT */ +#define NAN_DBGID_ANCHORMASTER_RECORD_UPDATE (NAN_DBGID_EVT_BASE + 57) +/* args: amRankHi, amRankLo, HC, BTT */ +#define NAN_DBGID_ANCHORMASTER_RECORD_EXPIRED (NAN_DBGID_EVT_BASE + 58) +/* args: reason, transitionsToAM */ +#define NAN_DBGID_BECOMING_ANCHORMASTER (NAN_DBGID_EVT_BASE + 59) +/* args: oldRole, newRole */ +#define NAN_DBGID_ROLE_CHANGE (NAN_DBGID_EVT_BASE + 60) +/* args: TBD */ +#define NAN_DBGID_SYNC_BEACON_DW_STATS (NAN_DBGID_EVT_BASE + 61) +/* args: attrId */ +#define NAN_DBGID_RX_UNSUPPORTED_SDF_ATTR_ID (NAN_DBGID_EVT_BASE + 62) +/* args: handle, sid1, sid2, svcCtrl, length */ +#define NAN_DBGID_PUBSUB_MATCHED_SKIPPED_SSI (NAN_DBGID_EVT_BASE + 63) +/* args: offset */ +#define NAN_DBGID_MATCH_FILTER_OFFSET (NAN_DBGID_EVT_BASE + 64) +/* args: twSize, n, twIndex */ +#define NAN_DBGID_TW_PARAMS (NAN_DBGID_EVT_BASE + 65) +/* args: */ +#define NAN_DBGID_BEACON_SENDER (NAN_DBGID_EVT_BASE + 66) +/* args: currTsf, nextDwTsf */ +#define NAN_DBGID_TSF_DUMP (NAN_DBGID_EVT_BASE + 67) +/* args: chan, startSlot, numSlots, repeat */ +#define NAN_DBGID_FAW_CONFIG (NAN_DBGID_EVT_BASE + 68) +/* args: */ +#define NAN_DBGID_FAW_START (NAN_DBGID_EVT_BASE + 69) +/* args: */ +#define NAN_DBGID_FAW_END (NAN_DBGID_EVT_BASE + 70) +/* args: offset, oldval, newval */ +#define NAN_DBGID_CONFIG_PARAM_CHANGED (NAN_DBGID_EVT_BASE + 71) +/* args: */ +#define NAN_DBGID_CONN_CAP_ATTR_CLEARED (NAN_DBGID_EVT_BASE + 72) +/* args: connType */ +#define NAN_DBGID_POST_DISC_ATTR_CLEARED (NAN_DBGID_EVT_BASE + 73) +/* args: */ +#define NAN_DBGID_VENDOR_SPECIFIC_ATTR_CLEARED (NAN_DBGID_EVT_BASE + 74) +/* args: offset */ +#define NAN_DBGID_WLAN_INFRA_MAP_CTRL_OFFSET (NAN_DBGID_EVT_BASE + 75) +/* args: offset */ +#define NAN_DBGID_WLAN_INFRA_AI_BITMAP_OFFSET (NAN_DBGID_EVT_BASE + 76) +/* args: offset */ +#define NAN_DBGID_WLAN_INFRA_DEVICE_ROLE_OFFSET (NAN_DBGID_EVT_BASE + 77) +/* args: offset */ +#define NAN_DBGID_MESH_ID_OFFSET (NAN_DBGID_EVT_BASE + 78) +/* args: */ +#define NAN_DBGID_SPARE_79 (NAN_DBGID_EVT_BASE + 79) +/* args: */ +#define NAN_DBGID_SPARE_80 (NAN_DBGID_EVT_BASE + 80) +/* args: */ +#define NAN_DBGID_SPARE_81 (NAN_DBGID_EVT_BASE + 81) +/* args: */ +#define NAN_DBGID_SPARE_82 (NAN_DBGID_EVT_BASE + 82) +/* args: */ +#define NAN_DBGID_SPARE_83 (NAN_DBGID_EVT_BASE + 83) +/* PLEASE KEEP THIS ONE AT THE END */ +#define NAN_DBGID_EVT_LOG_LAST (NAN_DBGID_EVT_BASE + 84) + +/* Debug IDs for message logs. */ +#define NAN_DBGID_API_MSG_BASE NAN_DBGID_EVT_LOG_LAST +#define NAN_DBGID_API_MSG_HEADER (NAN_DBGID_API_MSG_BASE + 0) +#define NAN_DBGID_API_MSG_DATA (NAN_DBGID_API_MSG_BASE + 1) +#define NAN_DBGID_API_MSG_LAST (NAN_DBGID_API_MSG_BASE + 2) + +/* Debug IDs for packet logs. */ +#define NAN_DBGID_OTA_PKT_BASE NAN_DBGID_API_MSG_LAST +#define NAN_DBGID_OTA_PKT_HEADER (NAN_DBGID_OTA_PKT_BASE + 0) +#define NAN_DBGID_OTA_PKT_DATA (NAN_DBGID_OTA_PKT_BASE + 1) +#define NAN_DBGID_OTA_PKT_LAST (NAN_DBGID_OTA_PKT_BASE + 2) /* not really the last! */ + +#define NAN_DBGID_BEACON_RX_TIMES (NAN_DBGID_OTA_PKT_LAST + 0) +#define NAN_DBGID_BEACON_RX_MANDATORY_ATTRS (NAN_DBGID_OTA_PKT_LAST + 1) +#define NAN_DBGID_BEACON_RX_SID_ATTR (NAN_DBGID_OTA_PKT_LAST + 2) +#define NAN_DBGID_BEACON_RX_VSA_ATTR (NAN_DBGID_OTA_PKT_LAST + 3) +#define NAN_DBGID_BEACON_RX_AVG_RSSI (NAN_DBGID_OTA_PKT_LAST + 4) +#define NAN_DBGID_CANDIDATE_BEACONS (NAN_DBGID_OTA_PKT_LAST + 5) +#define NAN_DBGID_TSF_OFFSET (NAN_DBGID_OTA_PKT_LAST + 6) +#define NAN_DBGID_ANCHORMASTER_RECORD_UPDATE_LAST (NAN_DBGID_OTA_PKT_LAST + 7) +#define NAN_DBGID_ANCHORMASTER_RECORD_EXPIRED2 (NAN_DBGID_OTA_PKT_LAST + 8) +#define NAN_DBGID_BEACON_TX_SEND (NAN_DBGID_OTA_PKT_LAST + 9) +#define NAN_DBGID_BEACON_TX_CANCEL (NAN_DBGID_OTA_PKT_LAST + 10) +#define NAN_DBGID_NAN_SCAN_EVENT (NAN_DBGID_OTA_PKT_LAST + 11) +#define NAN_DBGID_NAN_SDF_QUEUED (NAN_DBGID_OTA_PKT_LAST + 12) +#define NAN_DBGID_NAN_BEACON_QUEUED (NAN_DBGID_OTA_PKT_LAST + 13) +#define NAN_DBGID_NAN_NOT_ALLOWED (NAN_DBGID_OTA_PKT_LAST + 14) +#define NAN_DBGID_NAN_TX_FOLLOWUP_REQ_TR_ID (NAN_DBGID_OTA_PKT_LAST + 15) +#define NAN_DBGID_NAN_TX_FOLLOWUP_RESP_TR_ID (NAN_DBGID_OTA_PKT_LAST + 16) +#define NAN_DBGID_PUBSUB_TERM_IND_DISABLE_FLAG (NAN_DBGID_OTA_PKT_LAST + 17) +#define NAN_DBGID_UNMATCH_IND_DISABLE_FLAG (NAN_DBGID_OTA_PKT_LAST + 18) +#define NAN_DBGID_FOLLOWUP_RX_IND_DISABLE_FLAG (NAN_DBGID_OTA_PKT_LAST + 19) +#define NAN_DBGID_BEACON_RX_LAST (NAN_DBGID_OTA_PKT_LAST + 20) + +/* NaN Datapath Timekeeper debug IDs */ +/* 116 + 20 = 136 */ +#define NAN_DBGID_TMKR_BASE NAN_DBGID_BEACON_RX_LAST +/* 136 */ +#define NAN_DBGID_TMKR_INIT (NAN_DBGID_TMKR_BASE + 0) +#define NAN_DBGID_TMKR_OPEN (NAN_DBGID_TMKR_BASE + 1) +#define NAN_DBGID_TMKR_CLOSE (NAN_DBGID_TMKR_BASE + 2) +#define NAN_DBGID_TMKR_NEGOTIATE (NAN_DBGID_TMKR_BASE + 3) +#define NAN_DBGID_TMKR_TMR_HNDLR (NAN_DBGID_TMKR_BASE + 4) +#define NAN_DBGID_TMKR_UNITTEST (NAN_DBGID_TMKR_BASE + 5) +#define NAN_DBGID_TMKR_LF_TMR_HNDLR (NAN_DBGID_TMKR_BASE + 6) +#define NAN_DBGID_TMKR_DEINIT (NAN_DBGID_TMKR_BASE + 7) +#define NAN_DBGID_TMKR_SLOTBITMAP (NAN_DBGID_TMKR_BASE + 8) +#define NAN_DBGID_TMKR_CANCEL_SLOTBITMAP (NAN_DBGID_TMKR_BASE + 9) +#define NAN_DBGID_TMKR_CONFIRM_SLOTBITMAP (NAN_DBGID_TMKR_BASE + 10) +#define NAN_DBGID_TMKR_RESOLVE_SLOTBITMAP (NAN_DBGID_TMKR_BASE + 11) +#define NAN_DBGID_TMKR_ADD_CHAN_ELEMENT (NAN_DBGID_TMKR_BASE + 12) +#define NAN_DBGID_TMKR_REMOVE_CHAN_ELEMENT (NAN_DBGID_TMKR_BASE + 13) +/* 150 */ +#define NAN_DBGID_TMKR_FIND_CHAN_ELEMENT (NAN_DBGID_TMKR_BASE + 14) +#define NAN_DBGID_TMKR_QUERY_COMMITTED_SLOTBITMAP (NAN_DBGID_TMKR_BASE + 15) +#define NAN_DBGID_TMKR_ENCODE_SLOTBITMAP (NAN_DBGID_TMKR_BASE + 16) +#define NAN_DBGID_TMKR_SLOT_ARRAY_DBG (NAN_DBGID_TMKR_BASE + 17) +#define NAN_DBGID_TMKR_POPULATE_MASTER (NAN_DBGID_TMKR_BASE + 18) +#define NAN_DBGID_TMKR_ALLOCATE_SLOTS (NAN_DBGID_TMKR_BASE + 19) +#define NAN_DBGID_TMKR_RELEASE_SLOTS (NAN_DBGID_TMKR_BASE + 20) +#define NAN_DBGID_TMKR_ENABLE (NAN_DBGID_TMKR_BASE + 21) +#define NAN_DBGID_TMKR_DISABLE (NAN_DBGID_TMKR_BASE + 22) +#define NAN_DBGID_TMKR_GET_NEXT_SLOTWINDOW (NAN_DBGID_TMKR_BASE + 23) +#define NAN_DBGID_TMKR_RESUME_TIMEKEEPING (NAN_DBGID_TMKR_BASE + 24) +#define NAN_DBGID_TMKR_RESYNC_TO_DISCOVERY_WINDOW (NAN_DBGID_TMKR_BASE + 25) +/* 162 */ +#define NAN_DBGID_TMKR_SUSPEND_TIMEKEEPING (NAN_DBGID_TMKR_BASE + 26) +#define NAN_DBGID_TMKR_SYNC_TO_DISCOVERY_WINDOW (NAN_DBGID_TMKR_BASE + 27) +#define NAN_DBGID_TMKR_GET_NEXT_TSFTIME (NAN_DBGID_TMKR_BASE + 28) +#define NAN_DBGID_TMKR_SETUP_NEXT_INTERVAL (NAN_DBGID_TMKR_BASE + 29) +#define NAN_DBGID_TMKR_SCHEDULE_EVENT (NAN_DBGID_TMKR_BASE + 30) +#define NAN_DBGID_TMKR_ENABLE_TIMEKEEPING_EVENT (NAN_DBGID_TMKR_BASE + 31) +#define NAN_DBGID_TMKR_DISABLE_TIMEKEEPING_EVENT (NAN_DBGID_TMKR_BASE + 32) +#define NAN_DBGID_TMKR_SYNC_WITH_DW_EVENT (NAN_DBGID_TMKR_BASE + 33) +#define NAN_DBGID_TMKR_INTERVAL_EXPIRED_EVENT (NAN_DBGID_TMKR_BASE + 34) +#define NAN_DBGID_TMKR_PAUSE_TIMEKEEPING_EVENT (NAN_DBGID_TMKR_BASE + 35) +/* 172 */ +#define NAN_DBGID_TMKR_RESUME_TIMEKEEPING_EVENT (NAN_DBGID_TMKR_BASE + 36) +#define NAN_DBGID_TMKR_RESYNC_TO_DW_EVENT (NAN_DBGID_TMKR_BASE + 37) +#define NAN_DBGID_TMKR_LAST (NAN_DBGID_TMKR_BASE + 38) + +#define NAN_DBGID_END (NAN_DBGID_TMKR_LAST) + +/* IBSS PS module DBGIDs*/ +#define IBSS_PS_DBGID_DEFINITION_START 0 +#define IBSS_PS_DBGID_PEER_CREATE 1 +#define IBSS_PS_DBGID_PEER_DELETE 2 +#define IBSS_PS_DBGID_VDEV_CREATE 3 +#define IBSS_PS_DBGID_VDEV_DELETE 4 +#define IBSS_PS_DBGID_VDEV_EVENT 5 +#define IBSS_PS_DBGID_PEER_EVENT 6 +#define IBSS_PS_DBGID_DELIVER_CAB 7 +#define IBSS_PS_DBGID_DELIVER_UC_DATA 8 +#define IBSS_PS_DBGID_DELIVER_UC_DATA_ERROR 9 +#define IBSS_PS_DBGID_UC_INACTIVITY_TMR_RESTART 10 +#define IBSS_PS_DBGID_MC_INACTIVITY_TMR_RESTART 11 +#define IBSS_PS_DBGID_NULL_TX_COMPLETION 12 +#define IBSS_PS_DBGID_ATIM_TIMER_START 13 +#define IBSS_PS_DBGID_UC_ATIM_SEND 14 +#define IBSS_PS_DBGID_BC_ATIM_SEND 15 +#define IBSS_PS_DBGID_UC_TIMEOUT 16 +#define IBSS_PS_DBGID_PWR_COLLAPSE_ALLOWED 17 +#define IBSS_PS_DBGID_PWR_COLLAPSE_NOT_ALLOWED 18 +#define IBSS_PS_DBGID_SET_PARAM 19 +#define IBSS_PS_DBGID_HOST_TX_PAUSE 20 +#define IBSS_PS_DBGID_HOST_TX_UNPAUSE 21 +#define IBSS_PS_DBGID_PS_DESC_BIN_HWM 22 +#define IBSS_PS_DBGID_PS_DESC_BIN_LWM 23 +#define IBSS_PS_DBGID_PS_KICKOUT_PEER 24 +#define IBSS_PS_DBGID_SET_PEER_PARAM 25 +#define IBSS_PS_DBGID_BCN_ATIM_WIN_MISMATCH 26 +#define IBSS_PS_DBGID_RX_CHAINMASK_CHANGE 27 + +/* HIF UART Interface DBGIDs */ +#define HIF_UART_DBGID_START 0 +#define HIF_UART_DBGID_POWER_STATE 1 +#define HIF_UART_DBGID_TXRX_FLOW 2 +#define HIF_UART_DBGID_TXRX_CTRL_CHAR 3 +#define HIF_UART_DBGID_TXRX_BUF_DUMP 4 + +/* EXTSCAN DBGIDs */ +#define EXTSCAN_START 0 +#define EXTSCAN_STOP 1 +#define EXTSCAN_CLEAR_ENTRY_CONTENT 2 +#define EXTSCAN_GET_FREE_ENTRY_SUCCESS 3 +#define EXTSCAN_GET_FREE_ENTRY_INCONSISTENT 4 +#define EXTSCAN_GET_FREE_ENTRY_NO_MORE_ENTRIES 5 +#define EXTSCAN_CREATE_ENTRY_SUCCESS 6 +#define EXTSCAN_CREATE_ENTRY_ERROR 7 +#define EXTSCAN_SEARCH_SCAN_ENTRY_QUEUE 8 +#define EXTSCAN_SEARCH_SCAN_ENTRY_KEY_FOUND 9 +#define EXTSCAN_SEARCH_SCAN_ENTRY_KEY_NOT_FOUND 10 +#define EXTSCAN_ADD_ENTRY 11 +#define EXTSCAN_BUCKET_SEND_OPERATION_EVENT 12 +#define EXTSCAN_BUCKET_SEND_OPERATION_EVENT_FAILED 13 +#define EXTSCAN_BUCKET_START_SCAN_CYCLE 14 +#define EXTSCAN_BUCKET_PERIODIC_TIMER 15 +#define EXTSCAN_SEND_START_STOP_EVENT 16 +#define EXTSCAN_NOTIFY_WLAN_CHANGE 17 +#define EXTSCAN_NOTIFY_WLAN_HOTLIST_MATCH 18 +#define EXTSCAN_MAIN_RECEIVED_FRAME 19 +#define EXTSCAN_MAIN_NO_SSID_IE 20 +#define EXTSCAN_MAIN_MALFORMED_FRAME 21 +#define EXTSCAN_FIND_BSSID_BY_REFERENCE 22 +#define EXTSCAN_FIND_BSSID_BY_REFERENCE_ERROR 23 +#define EXTSCAN_NOTIFY_TABLE_USAGE 24 +#define EXTSCAN_FOUND_RSSI_ENTRY 25 +#define EXTSCAN_BSSID_FOUND_RSSI_SAMPLE 26 +#define EXTSCAN_BSSID_ADDED_RSSI_SAMPLE 27 +#define EXTSCAN_BSSID_REPLACED_RSSI_SAMPLE 28 +#define EXTSCAN_BSSID_TRANSFER_CURRENT_SAMPLES 29 +#define EXTSCAN_BUCKET_PROCESS_SCAN_EVENT 30 +#define EXTSCAN_BUCKET_CANNOT_FIND_BUCKET 31 +#define EXTSCAN_START_SCAN_REQUEST_FAILED 32 +#define EXTSCAN_BUCKET_STOP_CURRENT_SCANS 33 +#define EXTSCAN_BUCKET_SCAN_STOP_REQUEST 34 +#define EXTSCAN_BUCKET_PERIODIC_TIMER_ERROR 35 +#define EXTSCAN_BUCKET_START_OPERATION 36 +#define EXTSCAN_START_INTERNAL_ERROR 37 +#define EXTSCAN_NOTIFY_HOTLIST_MATCH 38 +#define EXTSCAN_CONFIG_HOTLIST_TABLE 39 +#define EXTSCAN_CONFIG_WLAN_CHANGE_TABLE 40 +#define EXTSCAN_EVENT_SEND_FAILED 41 + +/* ERE DBGIDs */ +#define ERE_DBGID_DEFINITION_START 0 +#define ERE_DBGID_VDEV_ATTACH 1 +#define ERE_DBGID_VDEV_DETACH 2 +#define ERE_DBGID_ENABLE_CMD 3 +#define ERE_DBGID_STATUS_ENABLED 4 +#define ERE_DBGID_STATUS_DISABLED 5 +#define ERE_DBGID_ISROUTE_TABLE_EMPTY 6 +#define ERE_DBGID_HASH_VALUE 7 +#define ERE_DBGID_MATCH_REQ 8 +#define ERE_DBGID_ADD_ROUTE_DBG 9 +#define ERE_DBGID_ADD_ROUTE_ENTRY 10 +#define ERE_DBGID_STATS_TX 11 +#define ERE_DBGID_STATS_RX 12 +#define ERE_DBGID_DEFINITION_END 13 +/* IDs 14 - 251 reserved for ERE */ + +/* Timekeeper debug IDs */ +#define TIMEKEEPER_INIT 252 +#define TIMEKEEPER_OPEN 253 +#define TIMEKEEPER_CLOSE 254 +#define TIMEKEEPER_NEGOTIATE 255 +#define TIMEKEEPER_TMR_HNDLR 256 +#define TIMEKEEPER_UNITTEST 257 +#define TIMEKEEPER_LF_TMR_HNDLR 258 +#define TIMEKEEPER_DEINIT 259 +#define TIMEKEEPER_SLOTBITMAP 260 +#define TIMEKEEPER_CANCEL_SLOTBITMAP 261 +#define TIMEKEEPER_CONFIRM_SLOTBITMAP 262 +#define TIMEKEEPER_RESOLVE_SLOTBITMAP 263 +#define TIMEKEEPER_ADD_CHAN_ELEMENT 264 +#define TIMEKEEPER_REMOVE_CHAN_ELEMENT 265 +#define TIMEKEEPER_FIND_CHAN_ELEMENT 266 +#define TIMEKEEPER_QUERY_COMMITTED_SLOTBITMAP 267 +#define TIMEKEEPER_ENCODE_SLOTBITMAP 268 +#define TIMEKEEPER_SLOT_ARRAY_DBG 269 +#define TIMEKEEPER_POPULATE_MASTER 270 + +/* NLO DBGIDs */ +#define NLO_DBGID_SSID_TO_BE_SCANNED_LIST 0 +#define NLO_DBGID_SSID_TO_BE_SKIPPED_LIST 1 + +/* Channel prediction/reduction DBGIDs */ +#define SCAN_CH_PREDICT_DBGID_DEFINITION_START 0 +#define SCAN_CH_PREDICT_CALCULATE 1 +#define SCAN_CH_PREDICT_CALCULATE_SAMPLE 2 +#define SCAN_CH_PREDICT_CALCULATE_RESULT 3 +#define SCAN_CH_PREDICT_FOUND_BSS 4 +#define SCAN_CH_PREDICT_SCAN_START 5 +#define SCAN_CH_PREDICT_START 6 +#define SCAN_CH_PREDICT_STOP 7 +#define SCAN_CH_PREDICT_DBGID_DEFINITION_END 8 + +/* DSRC DBGIDs */ +#define OCB_DBGID_VDEV_CREATE 0 +#define OCB_DBGID_VDEV_DELETE 1 +#define OCB_DBGID_CHAN_PAUSE 2 +#define OCB_DBGID_CHAN_UNPAUSE 3 +#define OCB_DBGID_PEER_CREATE 4 +#define OCB_DBGID_PEER_DELETE 5 +#define OCB_DBGID_DCC_START 6 +#define OCB_DBGID_DCC_STOP 7 +#define OCB_DBGID_SET_CONFIG_CMD 8 +#define OCB_DBGID_SET_UTC_TIME_CMD 9 +#define OCB_DBGID_START_TIMING_ADVERT_CMD 10 +#define OCB_DBGID_STOP_TIMING_ADVERT_CMD 11 +#define OCB_DBGID_GET_TSF_TIMER_CMD 12 +#define OCB_DBGID_GET_DCC_STATS_CMD 13 +#define OCB_DBGID_UPDATE_DCC_NDL_CMD 14 +#define OCB_DBGID_SET_CONFIG_RESP_EVENT 15 +#define OCB_DBGID_GET_TSF_TIMER_RESP_EVENT 16 +#define OCB_DBGID_GET_DCC_STATS_RESP_EVENT 17 +#define OCB_DBGID_DCC_STATS_EVENT 18 +#define OCB_UPDATE_DCC_NDL_RESP_EVENT 19 +#define OCB_DBGID_GENERIC 20 +#define OCB_DBGID_VDEV_START 21 +#define OCB_DBGID_CHANNEL_SCHED_EVENT 22 +#define OCB_DBGID_GPS_EVENT_START 23 +#define OCB_DBGID_GPS_EVENT_END 24 +#define OCB_DBGID_TX_TA_FRAME 25 +#define OCB_DBGID_RX_TA_FRAME 26 + +/* Up to 255 reserved for OCB debug IDs */ + +#define DCC_DBGID_START 256 +#define DCC_DBGID_STOP 257 +#define DCC_DBGID_DCC_STATS_EVENT 258 +#define DCC_DBGID_SM_INIT 259 +#define DCC_DBGID_SM_EVENT 260 +#define DCC_DBGID_SM_CHANGE 261 +#define DCC_DBGID_GET_TX_ALLOWED 262 +#define DCC_DBGID_NOTIFY_TX_COMPLETION 263 +#define DCC_DBGID_NOTIFY_RX 264 +#define DCC_DBGID_GET_TX_POWER 265 +#define DCC_DBGID_GET_TX_RATE 266 +#define DCC_DBGID_TICKLE_SCHED 267 +#define DCC_DBGID_GENERIC 268 +#define DCC_DBGID_RX_PATH 269 +#define DCC_DBGID_TX_PATH 270 + +/* RSSI Threshold Monitor DBGIDs */ +#define RSSI_MONITOR_DBGID_DEFINITION_START 0 +#define RSSI_MONITOR_VDEV_INIT 1 +#define RSSI_MONITOR_VDEV_FREE 2 +#define RSSI_MONITOR_VDEV_EVENT 3 +#define RSSI_MONITOR_HW_EVENT 4 +#define RSSI_MONITOR_ENABLE_THRESHOLDS_CLIENT_REQ 5 +#define RSSI_MONITOR_ENABLE_THRESHOLDS_CLIENT_REQ_ERR 6 +#define RSSI_MONITOR_DISABLE_THRESHOLDS_CLIENT_REQ 7 +#define RSSI_MONITOR_DISABLE_THRESHOLDS_CLIENT_REQ_ERR 8 +#define RSSI_MONITOR_ARBITER 9 +#define RSSI_MONITOR_ARBITER_CONFIG_HW 10 +#define RSSI_MONITOR_CHECK_AND_DELIVER_EVENT 11 +#define RSSI_MONITOR_DELIVER_EVENT 12 +#define RSSI_MONITOR_UPDATE_BEACON_RSSI 13 +#define RSSI_MONITOR_DBGID_DEFINITION_END 14 + +/* QBOOST DBGIDs */ +#define WLAN_MODULE_QBOOST_DEFINITION_START 0 +#define WLAN_MODULE_QBOOST_DBGID_WLAN_PEER_NOT_FOUND 1 +#define WLAN_MODULE_QBOOST_DEFINITION_END 2 + + +#ifdef __cplusplus +} +#endif +#endif /* _DBGLOG_ID_H_ */ diff --git a/drivers/staging/fw-api/fw/efuse_reg.h b/drivers/staging/fw-api/fw/efuse_reg.h new file mode 100644 index 0000000000000000000000000000000000000000..2bff9f8a28a54aad93e85c88761484242e63d6f7 --- /dev/null +++ b/drivers/staging/fw-api/fw/efuse_reg.h @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2013-2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef _EFUSE_REG_REG_H_ +#define _EFUSE_REG_REG_H_ + +#define EFUSE_WR_ENABLE_REG_ADDRESS 0x00000000 +#define EFUSE_WR_ENABLE_REG_OFFSET 0x00000000 +#define EFUSE_WR_ENABLE_REG_V_MSB 0 +#define EFUSE_WR_ENABLE_REG_V_LSB 0 +#define EFUSE_WR_ENABLE_REG_V_MASK 0x00000001 +#define EFUSE_WR_ENABLE_REG_V_GET(x) (((x) & EFUSE_WR_ENABLE_REG_V_MASK) >> EFUSE_WR_ENABLE_REG_V_LSB) +#define EFUSE_WR_ENABLE_REG_V_SET(x) (((x) << EFUSE_WR_ENABLE_REG_V_LSB) & EFUSE_WR_ENABLE_REG_V_MASK) + +#define EFUSE_INT_ENABLE_REG_ADDRESS 0x00000004 +#define EFUSE_INT_ENABLE_REG_OFFSET 0x00000004 +#define EFUSE_INT_ENABLE_REG_V_MSB 0 +#define EFUSE_INT_ENABLE_REG_V_LSB 0 +#define EFUSE_INT_ENABLE_REG_V_MASK 0x00000001 +#define EFUSE_INT_ENABLE_REG_V_GET(x) (((x) & EFUSE_INT_ENABLE_REG_V_MASK) >> EFUSE_INT_ENABLE_REG_V_LSB) +#define EFUSE_INT_ENABLE_REG_V_SET(x) (((x) << EFUSE_INT_ENABLE_REG_V_LSB) & EFUSE_INT_ENABLE_REG_V_MASK) + +#define EFUSE_INT_STATUS_REG_ADDRESS 0x00000008 +#define EFUSE_INT_STATUS_REG_OFFSET 0x00000008 +#define EFUSE_INT_STATUS_REG_V_MSB 0 +#define EFUSE_INT_STATUS_REG_V_LSB 0 +#define EFUSE_INT_STATUS_REG_V_MASK 0x00000001 +#define EFUSE_INT_STATUS_REG_V_GET(x) (((x) & EFUSE_INT_STATUS_REG_V_MASK) >> EFUSE_INT_STATUS_REG_V_LSB) +#define EFUSE_INT_STATUS_REG_V_SET(x) (((x) << EFUSE_INT_STATUS_REG_V_LSB) & EFUSE_INT_STATUS_REG_V_MASK) + +#define BITMASK_WR_REG_ADDRESS 0x0000000c +#define BITMASK_WR_REG_OFFSET 0x0000000c +#define BITMASK_WR_REG_V_MSB 31 +#define BITMASK_WR_REG_V_LSB 0 +#define BITMASK_WR_REG_V_MASK 0xffffffff +#define BITMASK_WR_REG_V_GET(x) (((x) & BITMASK_WR_REG_V_MASK) >> BITMASK_WR_REG_V_LSB) +#define BITMASK_WR_REG_V_SET(x) (((x) << BITMASK_WR_REG_V_LSB) & BITMASK_WR_REG_V_MASK) + +#define VDDQ_SETTLE_TIME_REG_ADDRESS 0x00000010 +#define VDDQ_SETTLE_TIME_REG_OFFSET 0x00000010 +#define VDDQ_SETTLE_TIME_REG_V_MSB 31 +#define VDDQ_SETTLE_TIME_REG_V_LSB 0 +#define VDDQ_SETTLE_TIME_REG_V_MASK 0xffffffff +#define VDDQ_SETTLE_TIME_REG_V_GET(x) (((x) & VDDQ_SETTLE_TIME_REG_V_MASK) >> VDDQ_SETTLE_TIME_REG_V_LSB) +#define VDDQ_SETTLE_TIME_REG_V_SET(x) (((x) << VDDQ_SETTLE_TIME_REG_V_LSB) & VDDQ_SETTLE_TIME_REG_V_MASK) + +#define VDDQ_HOLD_TIME_REG_ADDRESS 0x00000014 +#define VDDQ_HOLD_TIME_REG_OFFSET 0x00000014 +#define VDDQ_HOLD_TIME_REG_V_MSB 31 +#define VDDQ_HOLD_TIME_REG_V_LSB 0 +#define VDDQ_HOLD_TIME_REG_V_MASK 0xffffffff +#define VDDQ_HOLD_TIME_REG_V_GET(x) (((x) & VDDQ_HOLD_TIME_REG_V_MASK) >> VDDQ_HOLD_TIME_REG_V_LSB) +#define VDDQ_HOLD_TIME_REG_V_SET(x) (((x) << VDDQ_HOLD_TIME_REG_V_LSB) & VDDQ_HOLD_TIME_REG_V_MASK) + +#define RD_STROBE_PW_REG_ADDRESS 0x00000018 +#define RD_STROBE_PW_REG_OFFSET 0x00000018 +#define RD_STROBE_PW_REG_V_MSB 31 +#define RD_STROBE_PW_REG_V_LSB 0 +#define RD_STROBE_PW_REG_V_MASK 0xffffffff +#define RD_STROBE_PW_REG_V_GET(x) (((x) & RD_STROBE_PW_REG_V_MASK) >> RD_STROBE_PW_REG_V_LSB) +#define RD_STROBE_PW_REG_V_SET(x) (((x) << RD_STROBE_PW_REG_V_LSB) & RD_STROBE_PW_REG_V_MASK) + +#define PG_STROBE_PW_REG_ADDRESS 0x0000001c +#define PG_STROBE_PW_REG_OFFSET 0x0000001c +#define PG_STROBE_PW_REG_V_MSB 31 +#define PG_STROBE_PW_REG_V_LSB 0 +#define PG_STROBE_PW_REG_V_MASK 0xffffffff +#define PG_STROBE_PW_REG_V_GET(x) (((x) & PG_STROBE_PW_REG_V_MASK) >> PG_STROBE_PW_REG_V_LSB) +#define PG_STROBE_PW_REG_V_SET(x) (((x) << PG_STROBE_PW_REG_V_LSB) & PG_STROBE_PW_REG_V_MASK) + +#define PGENB_SETUP_HOLD_TIME_REG_ADDRESS 0x00000020 +#define PGENB_SETUP_HOLD_TIME_REG_OFFSET 0x00000020 +#define PGENB_SETUP_HOLD_TIME_REG_V_MSB 31 +#define PGENB_SETUP_HOLD_TIME_REG_V_LSB 0 +#define PGENB_SETUP_HOLD_TIME_REG_V_MASK 0xffffffff +#define PGENB_SETUP_HOLD_TIME_REG_V_GET(x) (((x) & PGENB_SETUP_HOLD_TIME_REG_V_MASK) >> PGENB_SETUP_HOLD_TIME_REG_V_LSB) +#define PGENB_SETUP_HOLD_TIME_REG_V_SET(x) (((x) << PGENB_SETUP_HOLD_TIME_REG_V_LSB) & PGENB_SETUP_HOLD_TIME_REG_V_MASK) + +#define STROBE_PULSE_INTERVAL_REG_ADDRESS 0x00000024 +#define STROBE_PULSE_INTERVAL_REG_OFFSET 0x00000024 +#define STROBE_PULSE_INTERVAL_REG_V_MSB 31 +#define STROBE_PULSE_INTERVAL_REG_V_LSB 0 +#define STROBE_PULSE_INTERVAL_REG_V_MASK 0xffffffff +#define STROBE_PULSE_INTERVAL_REG_V_GET(x) (((x) & STROBE_PULSE_INTERVAL_REG_V_MASK) >> STROBE_PULSE_INTERVAL_REG_V_LSB) +#define STROBE_PULSE_INTERVAL_REG_V_SET(x) (((x) << STROBE_PULSE_INTERVAL_REG_V_LSB) & STROBE_PULSE_INTERVAL_REG_V_MASK) + +#define CSB_ADDR_LOAD_SETUP_HOLD_REG_ADDRESS 0x00000028 +#define CSB_ADDR_LOAD_SETUP_HOLD_REG_OFFSET 0x00000028 +#define CSB_ADDR_LOAD_SETUP_HOLD_REG_V_MSB 31 +#define CSB_ADDR_LOAD_SETUP_HOLD_REG_V_LSB 0 +#define CSB_ADDR_LOAD_SETUP_HOLD_REG_V_MASK 0xffffffff +#define CSB_ADDR_LOAD_SETUP_HOLD_REG_V_GET(x) (((x) & CSB_ADDR_LOAD_SETUP_HOLD_REG_V_MASK) >> CSB_ADDR_LOAD_SETUP_HOLD_REG_V_LSB) +#define CSB_ADDR_LOAD_SETUP_HOLD_REG_V_SET(x) (((x) << CSB_ADDR_LOAD_SETUP_HOLD_REG_V_LSB) & CSB_ADDR_LOAD_SETUP_HOLD_REG_V_MASK) + +#define EFUSE_INTF0_ADDRESS 0x00000800 +#define EFUSE_INTF0_OFFSET 0x00000800 +#define EFUSE_INTF0_R_MSB 31 +#define EFUSE_INTF0_R_LSB 0 +#define EFUSE_INTF0_R_MASK 0xffffffff +#define EFUSE_INTF0_R_GET(x) (((x) & EFUSE_INTF0_R_MASK) >> EFUSE_INTF0_R_LSB) +#define EFUSE_INTF0_R_SET(x) (((x) << EFUSE_INTF0_R_LSB) & EFUSE_INTF0_R_MASK) + +#define EFUSE_INTF1_ADDRESS 0x00001000 +#define EFUSE_INTF1_OFFSET 0x00001000 +#define EFUSE_INTF1_R_MSB 31 +#define EFUSE_INTF1_R_LSB 0 +#define EFUSE_INTF1_R_MASK 0xffffffff +#define EFUSE_INTF1_R_GET(x) (((x) & EFUSE_INTF1_R_MASK) >> EFUSE_INTF1_R_LSB) +#define EFUSE_INTF1_R_SET(x) (((x) << EFUSE_INTF1_R_LSB) & EFUSE_INTF1_R_MASK) + +#ifndef __ASSEMBLER__ +typedef struct efuse_reg_reg_s { + volatile unsigned int efuse_wr_enable_reg; + volatile unsigned int efuse_int_enable_reg; + volatile unsigned int efuse_int_status_reg; + volatile unsigned int bitmask_wr_reg; + volatile unsigned int vddq_settle_time_reg; + volatile unsigned int vddq_hold_time_reg; + volatile unsigned int rd_strobe_pw_reg; + volatile unsigned int pg_strobe_pw_reg; + volatile unsigned int pgenb_setup_hold_time_reg; + volatile unsigned int strobe_pulse_interval_reg; + volatile unsigned int csb_addr_load_setup_hold_reg; + unsigned char pad0[2004]; /* pad to 0x800 */ + volatile unsigned int efuse_intf0[512]; + volatile unsigned int efuse_intf1[512]; +} efuse_reg_reg_t; +#endif /* __ASSEMBLER__ */ + +#endif /* _EFUSE_REG_H_ */ diff --git a/drivers/staging/fw-api/fw/enet.h b/drivers/staging/fw-api/fw/enet.h new file mode 100644 index 0000000000000000000000000000000000000000..3e66c676afa1e0a7c0f0c060ba523775346d042f --- /dev/null +++ b/drivers/staging/fw-api/fw/enet.h @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2012, 2014, 2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef _ENET__H_ +#define _ENET__H_ + +#if defined(ATH_TARGET) +#include /* A_UINT8 */ +#else +#include /* A_UINT8 */ +#endif + +#define ETHERNET_ADDR_LEN 6 /* bytes */ +#define ETHERNET_TYPE_LEN 2 /* bytes - length of the Ethernet type field */ + +struct ethernet_hdr_t { + A_UINT8 dest_addr[ETHERNET_ADDR_LEN]; + A_UINT8 src_addr[ETHERNET_ADDR_LEN]; + A_UINT8 ethertype[ETHERNET_TYPE_LEN]; +}; + +#define ETHERNET_HDR_LEN (sizeof(struct ethernet_hdr_t)) + +#define ETHERNET_CRC_LEN 4 /* bytes - length of the Ethernet CRC */ +#define ETHERNET_MAX_LEN 1518 /* bytes */ + +#define ETHERNET_MTU (ETHERNET_MAX_LEN - (ETHERNET_HDR_LEN + ETHERNET_CRC_LEN)) + + +struct llc_snap_hdr_t { + A_UINT8 dsap; + A_UINT8 ssap; + A_UINT8 cntl; + A_UINT8 org_code[3]; + A_UINT8 ethertype[2]; +}; + +#define LLC_SNAP_HDR_LEN (sizeof(struct llc_snap_hdr_t)) +#define LLC_SNAP_HDR_OFFSET_ETHERTYPE \ + (offsetof(struct llc_snap_hdr_t, ethertype[0])) + +#define ETHERTYPE_VLAN_LEN 4 + +struct ethernet_vlan_hdr_t { + A_UINT8 dest_addr[ETHERNET_ADDR_LEN]; + A_UINT8 src_addr[ETHERNET_ADDR_LEN]; + A_UINT8 vlan_tpid[2]; + A_UINT8 vlan_tci[2]; + A_UINT8 ethertype[2]; +}; + +#define ETHERTYPE_IS_EAPOL_WAPI(typeorlen) \ + ((typeorlen) == ETHERTYPE_PAE || \ + (typeorlen) == ETHERTYPE_WAI) + +#define IS_ETHERTYPE(_typeOrLen) ((_typeOrLen) >= 0x0600) + +#ifndef ETHERTYPE_IPV4 +#define ETHERTYPE_IPV4 0x0800 /* Internet Protocol, Version 4 (IPv4) */ +#endif + +#ifndef ETHERTYPE_AARP +#define ETHERTYPE_AARP 0x80f3 /* Internal QCA AARP protocol */ +#endif + +#ifndef ETHERTYPE_IPX +#define ETHERTYPE_IPX 0x8137 /* IPX over DIX protocol */ +#endif + +#ifndef ETHERTYPE_ARP +#define ETHERTYPE_ARP 0x0806 /* Address Resolution Protocol (ARP) */ +#endif + +#ifndef ETHERTYPE_RARP +#define ETHERTYPE_RARP 0x8035 /* Reverse Address Resolution Protocol (RARP) */ +#endif + +#ifndef ETHERTYPE_VLAN +#define ETHERTYPE_VLAN 0x8100 /* VLAN TAG protocol */ +#endif + +#ifndef ETHERTYPE_SNMP +#define ETHERTYPE_SNMP 0x814C /* Simple Network Management Protocol (SNMP) */ +#endif + +#ifndef ETHERTYPE_IPV6 +#define ETHERTYPE_IPV6 0x86DD /* Internet Protocol, Version 6 (IPv6) */ +#endif + +#ifndef ETHERTYPE_PAE +#define ETHERTYPE_PAE 0x888E /* EAP over LAN (EAPOL) */ +#endif + +#ifndef ETHERTYPE_WAI +#define ETHERTYPE_WAI 0x88B4 /* WAPI */ +#endif + +#ifndef ETHERTYPE_TDLS +#define ETHERTYPE_TDLS 0x890D /* TDLS */ +#endif + +#define LLC_SNAP_LSAP 0xaa +#define LLC_UI 0x3 + +#define RFC1042_SNAP_ORGCODE_0 0x00 +#define RFC1042_SNAP_ORGCODE_1 0x00 +#define RFC1042_SNAP_ORGCODE_2 0x00 + +#define BTEP_SNAP_ORGCODE_0 0x00 +#define BTEP_SNAP_ORGCODE_1 0x00 +#define BTEP_SNAP_ORGCODE_2 0xf8 + +#define IS_SNAP(_llc) ((_llc)->dsap == LLC_SNAP_LSAP && \ + (_llc)->ssap == LLC_SNAP_LSAP && \ + (_llc)->cntl == LLC_UI) + +#define IS_RFC1042(_llc) ((_llc)->org_code[0] == RFC1042_SNAP_ORGCODE_0 && \ + (_llc)->org_code[1] == RFC1042_SNAP_ORGCODE_1 && \ + (_llc)->org_code[2] == RFC1042_SNAP_ORGCODE_2) + +#define IS_BTEP(_llc) ((_llc)->org_code[0] == BTEP_SNAP_ORGCODE_0 && \ + (_llc)->org_code[1] == BTEP_SNAP_ORGCODE_1 && \ + (_llc)->org_code[2] == BTEP_SNAP_ORGCODE_2) + +#endif /* _ENET__H_ */ diff --git a/drivers/staging/fw-api/fw/epping_test.h b/drivers/staging/fw-api/fw/epping_test.h new file mode 100644 index 0000000000000000000000000000000000000000..b8e6d01785c69c593aa644d86031abdb32f8de90 --- /dev/null +++ b/drivers/staging/fw-api/fw/epping_test.h @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* This file contains shared definitions for the host/target endpoint ping test */ + +#ifndef EPPING_TEST_H +#define EPPING_TEST_H + +#ifndef ATH_TARGET +#include "athstartpack.h" +#endif + +/* alignment to 4-bytes */ +#define EPPING_ALIGNMENT_PAD (((sizeof(HTC_FRAME_HDR) + 3) & (~0x3)) - sizeof(HTC_FRAME_HDR)) + +#ifndef A_OFFSETOF +#define A_OFFSETOF(type,field) (int)(&(((type *)NULL)->field)) +#endif + +#define EPPING_RSVD_FILL 0xCC + +#define HCI_RSVD_EXPECTED_PKT_TYPE_RECV_OFFSET 7 + +typedef PREPACK struct { + A_UINT8 _HCIRsvd[8]; /* reserved for HCI packet header (GMBOX) testing */ + A_UINT8 StreamEcho_h; /* stream no. to echo this packet on (filled by host) */ + A_UINT8 StreamEchoSent_t; /* stream no. packet was echoed to (filled by target) + When echoed: StreamEchoSent_t == StreamEcho_h */ + A_UINT8 StreamRecv_t; /* stream no. that target received this packet on (filled by target) */ + A_UINT8 StreamNo_h; /* stream number to send on (filled by host) */ + A_UINT8 Magic_h[4]; /* magic number to filter for this packet on the host */ + A_UINT8 _rsvd[6]; /* reserved fields that must be set to a "reserved" value + since this packet maps to a 14-byte ethernet frame we want + to make sure ethertype field is set to something unknown */ + + A_UINT8 _pad[2]; /* padding for alignment */ + A_UINT8 TimeStamp[8]; /* timestamp of packet (host or target) */ + A_UINT32 HostContext_h; /* 4 byte host context, target echos this back */ + A_UINT32 SeqNo; /* sequence number (set by host or target) */ + A_UINT16 Cmd_h; /* ping command (filled by host) */ + A_UINT16 CmdFlags_h; /* optional flags */ + A_UINT8 CmdBuffer_h[8]; /* buffer for command (host -> target) */ + A_UINT8 CmdBuffer_t[8]; /* buffer for command (target -> host) */ + A_UINT16 DataLength; /* length of data */ + A_UINT16 DataCRC; /* 16 bit CRC of data */ + A_UINT16 HeaderCRC; /* header CRC (fields : StreamNo_h to end, minus HeaderCRC) */ +} POSTPACK EPPING_HEADER; + +#define EPPING_PING_MAGIC_0 0xAA +#define EPPING_PING_MAGIC_1 0x55 +#define EPPING_PING_MAGIC_2 0xCE +#define EPPING_PING_MAGIC_3 0xEC + +#define IS_EPPING_PACKET(pPkt) (((pPkt)->Magic_h[0] == EPPING_PING_MAGIC_0) && \ + ((pPkt)->Magic_h[1] == EPPING_PING_MAGIC_1) && \ + ((pPkt)->Magic_h[2] == EPPING_PING_MAGIC_2) && \ + ((pPkt)->Magic_h[3] == EPPING_PING_MAGIC_3)) + +#define SET_EPPING_PACKET_MAGIC(pPkt) { (pPkt)->Magic_h[0] = EPPING_PING_MAGIC_0; \ + (pPkt)->Magic_h[1] = EPPING_PING_MAGIC_1; \ + (pPkt)->Magic_h[2] = EPPING_PING_MAGIC_2; \ + (pPkt)->Magic_h[3] = EPPING_PING_MAGIC_3; } + +#define CMD_FLAGS_DATA_CRC (1 << 0) /* DataCRC field is valid */ +#define CMD_FLAGS_DELAY_ECHO (1 << 1) /* delay the echo of the packet */ +#define CMD_FLAGS_NO_DROP (1 << 2) /* do not drop at HTC layer no matter what the stream is */ + +#define IS_EPING_PACKET_NO_DROP(pPkt) ((pPkt)->CmdFlags_h & CMD_FLAGS_NO_DROP) + +#define EPPING_CMD_ECHO_PACKET 1 /* echo packet test */ +#define EPPING_CMD_RESET_RECV_CNT 2 /* reset recv count */ +#define EPPING_CMD_CAPTURE_RECV_CNT 3 /* fetch recv count, 4-byte count returned in CmdBuffer_t */ +#define EPPING_CMD_NO_ECHO 4 /* non-echo packet test (tx-only) */ +#define EPPING_CMD_CONT_RX_START 5 /* continous RX packets, parameters are in CmdBuffer_h */ +#define EPPING_CMD_CONT_RX_STOP 6 /* stop continuous RX packet transmission */ + +/* test command parameters may be no more than 8 bytes */ +typedef PREPACK struct { + A_UINT16 BurstCnt; /* number of packets to burst together (for HTC 2.1 testing) */ + A_UINT16 PacketLength; /* length of packet to generate including header */ + A_UINT16 Flags; /* flags */ + +#define EPPING_CONT_RX_DATA_CRC (1 << 0) /* Add CRC to all data */ +#define EPPING_CONT_RX_RANDOM_DATA (1 << 1) /* randomize the data pattern */ +#define EPPING_CONT_RX_RANDOM_LEN (1 << 2) /* randomize the packet lengths */ +#define EPPING_CONT_RX_NO_DATA_FILL (1 << 3) /* target will not fill buffers */ + A_UINT16 Context; /* flags */ + +} POSTPACK EPPING_CONT_RX_PARAMS; + +#define EPPING_HDR_CRC_OFFSET A_OFFSETOF(EPPING_HEADER,StreamNo_h) +#define EPPING_HDR_BYTES_CRC (sizeof(EPPING_HEADER) - EPPING_HDR_CRC_OFFSET - (sizeof(A_UINT16))) + +#define HCI_TRANSPORT_STREAM_NUM 16 /* this number is higher than the define WMM AC classes so we + can use this to distinguish packets */ + +#ifndef ATH_TARGET +#include "athendpack.h" +#endif + +#endif /* EPPING_TEST_H */ diff --git a/drivers/staging/fw-api/fw/htc.h b/drivers/staging/fw-api/fw/htc.h new file mode 100644 index 0000000000000000000000000000000000000000..9d9f014352fbaa234fe015d122582ee09122613f --- /dev/null +++ b/drivers/staging/fw-api/fw/htc.h @@ -0,0 +1,422 @@ +/* + * Copyright (c) 2012-2014, 2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef __HTC_H__ +#define __HTC_H__ + +#ifndef ATH_TARGET +#include "athstartpack.h" +#endif +#ifdef ATHR_WIN_NWF +#pragma warning(disable:4214) +#endif +#undef MS +#define MS(_v, _f) (((_v) & _f ## _MASK) >> _f ## _LSB) +#undef SM +#define SM(_v, _f) (((_v) << _f ## _LSB) & _f ## _MASK) +#undef WO +#define WO(_f) ((_f ## _OFFSET) >> 2) + +#undef GET_FIELD +#define GET_FIELD(_addr, _f) MS(*((A_UINT32 *)(_addr) + WO(_f)), _f) +#undef SET_FIELD +#define SET_FIELD(_addr, _f, _val) \ + (*((A_UINT32 *)(_addr) + WO(_f)) = \ + (*((A_UINT32 *)(_addr) + WO(_f)) & ~_f ## _MASK) | SM(_val, _f)) + +#define HTC_GET_FIELD(_msg_buf, _msg_type, _f) \ + GET_FIELD(_msg_buf, _msg_type ## _ ## _f) + +#define HTC_SET_FIELD(_msg_buf, _msg_type, _f, _val) \ + SET_FIELD(_msg_buf, _msg_type ## _ ## _f, _val) + +#define HTC_WRITE32(_addr, _val) \ + (*(A_UINT32 *)(_addr) = (_val)) + +#ifndef A_OFFSETOF +#define A_OFFSETOF(type,field) (unsigned long)(&(((type *)NULL)->field)) +#endif + +#define ASSEMBLE_UNALIGNED_UINT16(p,highbyte,lowbyte) \ + (((A_UINT16)(((A_UINT8 *)(p))[(highbyte)])) << 8 | (A_UINT16)(((A_UINT8 *)(p))[(lowbyte)])) + +/****** DANGER DANGER *************** + * + * The frame header length and message formats defined herein were + * selected to accommodate optimal alignment for target processing. This reduces code + * size and improves performance. + * + * Any changes to the header length may alter the alignment and cause exceptions + * on the target. When adding to the message structures insure that fields are + * properly aligned. + * + */ + +/* HTC frame header */ +typedef PREPACK struct _HTC_FRAME_HDR { + /* do not remove or re-arrange these fields, these are minimally required + * to take advantage of 4-byte lookaheads in some hardware implementations */ + A_UINT32 EndpointID : 8, Flags : 8, PayloadLen : 16; /* length of data (including trailer) that follows the header */ + + /***** end of 4-byte lookahead ****/ + + A_UINT32 ControlBytes0 : 8,/*used for CRC check if CRC_CHECK flag set*/ + ControlBytes1 : 8, /*used for seq check if SEQ_CHECK flag set*/ + reserved : 16; /*used by bundle processing in SDIO systems*/ + + /* message payload starts after the header */ + +} POSTPACK HTC_FRAME_HDR; + +#define HTC_FRAME_HDR_ENDPOINTID_LSB 0 +#define HTC_FRAME_HDR_ENDPOINTID_MASK 0x000000ff +#define HTC_FRAME_HDR_ENDPOINTID_OFFSET 0x00000000 +#define HTC_FRAME_HDR_FLAGS_LSB 8 +#define HTC_FRAME_HDR_FLAGS_MASK 0x0000ff00 +#define HTC_FRAME_HDR_FLAGS_OFFSET 0x00000000 +#define HTC_FRAME_HDR_PAYLOADLEN_LSB 16 +#define HTC_FRAME_HDR_PAYLOADLEN_MASK 0xffff0000 +#define HTC_FRAME_HDR_PAYLOADLEN_OFFSET 0x00000000 +#define HTC_FRAME_HDR_CONTROLBYTES0_LSB 0 +#define HTC_FRAME_HDR_CONTROLBYTES0_MASK 0x000000ff +#define HTC_FRAME_HDR_CONTROLBYTES0_OFFSET 0x00000004 +#define HTC_FRAME_HDR_CONTROLBYTES1_LSB 8 +#define HTC_FRAME_HDR_CONTROLBYTES1_MASK 0x0000ff00 +#define HTC_FRAME_HDR_CONTROLBYTES1_OFFSET 0x00000004 +#define HTC_FRAME_HDR_RESERVED_LSB 16 +#define HTC_FRAME_HDR_RESERVED_MASK 0xffff0000 +#define HTC_FRAME_HDR_RESERVED_OFFSET 0x00000004 + +/* frame header flags */ + +/* send direction */ +#define HTC_FLAGS_NEED_CREDIT_UPDATE (1 << 0) +#define HTC_FLAGS_SEND_BUNDLE (1 << 1) /* start or part of bundle */ +#define HTC_FLAGS_SEQ_CHECK (1 << 2) /* seq check on rx side */ +#define HTC_FLAGS_CRC_CHECK (1 << 3) /* CRC check on rx side */ +/* receive direction */ +#define HTC_FLAGS_RECV_1MORE_BLOCK (1 << 0) /* bit 0 bundle trailer present */ +#define HTC_FLAGS_RECV_TRAILER (1 << 1) /* bit 1 trailer data present */ +#define HTC_FLAGS_RECV_BUNDLE_CNT_MASK (0xFC) /* bits 7..2 */ +#define HTC_FLAGS_RECV_BUNDLE_CNT_SHIFT 2 +/* + * To be compatible with an older definition of a smaller (4-bit) + * bundle count field, the bundle count is stored in a segmented + * format - the 4 LSbs of the bundle count value are stored in bits 5:2 + * of the BUNDLE_CNT field, which is bits 7:4 of the HTC_FLAGS word; + * the next 2 bits of the bundle count value are stored in bits 1:0 of + * the BUNDLE_CNT field, which is bits 3:2 of the HTC_FLAGS word. + */ +#define HTC_FLAGS_RECV_BUNDLE_CNT_SET(x) \ + ((((x) << 2) | ((x) >> 4)) << HTC_FLAGS_RECV_BUNDLE_CNT_SHIFT) +#define HTC_FLAGS_RECV_BUNDLE_CNT_GET(x) \ + ((((x) & HTC_FLAGS_RECV_BUNDLE_CNT_MASK) >> \ + (HTC_FLAGS_RECV_BUNDLE_CNT_SHIFT + 2)) | \ + ((((x) >> HTC_FLAGS_RECV_BUNDLE_CNT_SHIFT) & 0x3) << 4)) + +#define HTC_HDR_LENGTH (sizeof(HTC_FRAME_HDR)) +#define HTC_HDR_ALIGNMENT_PADDING \ + (((sizeof(HTC_FRAME_HDR) + 3) & (~0x3)) - sizeof(HTC_FRAME_HDR)) +#define HTC_MAX_TRAILER_LENGTH 255 +#define HTC_MAX_PAYLOAD_LENGTH (4096 - sizeof(HTC_FRAME_HDR)) + +/* HTC control message IDs */ + +#define HTC_MSG_READY_ID 1 +#define HTC_MSG_CONNECT_SERVICE_ID 2 +#define HTC_MSG_CONNECT_SERVICE_RESPONSE_ID 3 +#define HTC_MSG_SETUP_COMPLETE_ID 4 +#define HTC_MSG_SETUP_COMPLETE_EX_ID 5 +#define HTC_MSG_SEND_SUSPEND_COMPLETE 6 +#define HTC_MSG_NACK_SUSPEND 7 +#define HTC_MSG_WAKEUP_FROM_SUSPEND_ID 8 + +#define HTC_MAX_CONTROL_MESSAGE_LENGTH 256 + +/* base message ID header */ +typedef PREPACK struct { + A_UINT32 MessageID : 16, reserved : 16; +} POSTPACK HTC_UNKNOWN_MSG; + +#define HTC_UNKNOWN_MSG_MESSAGEID_LSB 0 +#define HTC_UNKNOWN_MSG_MESSAGEID_MASK 0x0000ffff +#define HTC_UNKNOWN_MSG_MESSAGEID_OFFSET 0x00000000 + +/* HTC ready message + * direction : target-to-host */ +typedef PREPACK struct { + A_UINT32 MessageID : 16, /* ID */ + CreditCount : 16; /* number of credits the target can offer */ + A_UINT32 CreditSize : 16, /* size of each credit */ + MaxEndpoints : 8, /* maximum number of endpoints the target has resources for */ + _Pad1 : 8; +} POSTPACK HTC_READY_MSG; + +#define HTC_READY_MSG_MESSAGEID_LSB 0 +#define HTC_READY_MSG_MESSAGEID_MASK 0x0000ffff +#define HTC_READY_MSG_MESSAGEID_OFFSET 0x00000000 +#define HTC_READY_MSG_CREDITCOUNT_LSB 16 +#define HTC_READY_MSG_CREDITCOUNT_MASK 0xffff0000 +#define HTC_READY_MSG_CREDITCOUNT_OFFSET 0x00000000 +#define HTC_READY_MSG_CREDITSIZE_LSB 0 +#define HTC_READY_MSG_CREDITSIZE_MASK 0x0000ffff +#define HTC_READY_MSG_CREDITSIZE_OFFSET 0x00000004 +#define HTC_READY_MSG_MAXENDPOINTS_LSB 16 +#define HTC_READY_MSG_MAXENDPOINTS_MASK 0x00ff0000 +#define HTC_READY_MSG_MAXENDPOINTS_OFFSET 0x00000004 + +/* extended HTC ready message */ +typedef PREPACK struct { + HTC_READY_MSG Version2_0_Info; /* legacy version 2.0 information at the front... */ + /* extended information */ + A_UINT32 HTCVersion : 8, MaxMsgsPerHTCBundle : 8, reserved : 16; +} POSTPACK HTC_READY_EX_MSG; + +#define HTC_READY_EX_MSG_HTCVERSION_LSB 0 +#define HTC_READY_EX_MSG_HTCVERSION_MASK 0x000000ff +#define HTC_READY_EX_MSG_HTCVERSION_OFFSET sizeof(HTC_READY_MSG) +#define HTC_READY_EX_MSG_MAXMSGSPERHTCBUNDLE_LSB 8 +#define HTC_READY_EX_MSG_MAXMSGSPERHTCBUNDLE_MASK 0x0000ff00 +#define HTC_READY_EX_MSG_MAXMSGSPERHTCBUNDLE_OFFSET sizeof(HTC_READY_MSG) + +#define HTC_VERSION_2P0 0x00 +#define HTC_VERSION_2P1 0x01 /* HTC 2.1 */ + +#define HTC_SERVICE_META_DATA_MAX_LENGTH 128 + +/* connect service + * direction : host-to-target */ +typedef PREPACK struct { + /* service ID of the service to connect to */ + A_UINT32 MessageID:16, service_id:16; + A_UINT32 ConnectionFlags : 16, /* connection flags */ +#define HTC_CONNECT_FLAGS_REDUCE_CREDIT_DRIBBLE (1 << 2) + /* reduce credit dribbling when + the host needs credits */ +#define HTC_CONNECT_FLAGS_THRESHOLD_LEVEL_MASK (0x3) +#define HTC_CONNECT_FLAGS_THRESHOLD_LEVEL_ONE_FOURTH 0x0 +#define HTC_CONNECT_FLAGS_THRESHOLD_LEVEL_ONE_HALF 0x1 +#define HTC_CONNECT_FLAGS_THRESHOLD_LEVEL_THREE_FOURTHS 0x2 +#define HTC_CONNECT_FLAGS_THRESHOLD_LEVEL_UNITY 0x3 + /* disable credit flow control on a specific service */ +#define HTC_CONNECT_FLAGS_DISABLE_CREDIT_FLOW_CTRL (1 << 3) + /* enable htc schedule on a specific service */ +#define HTC_CONNECT_FLAGS_ENABLE_HTC_SCHEDULE (1 << 4) + ServiceMetaLength : 8, /* length of meta data that follows */ + _Pad1 : 8; + + /* service-specific meta data starts after the header */ + +} POSTPACK HTC_CONNECT_SERVICE_MSG; + +#define HTC_CONNECT_SERVICE_MSG_MESSAGEID_LSB 0 +#define HTC_CONNECT_SERVICE_MSG_MESSAGEID_MASK 0x0000ffff +#define HTC_CONNECT_SERVICE_MSG_MESSAGEID_OFFSET 0x00000000 +#define HTC_CONNECT_SERVICE_MSG_SERVICE_ID_LSB 16 +#define HTC_CONNECT_SERVICE_MSG_SERVICE_ID_MASK 0xffff0000 +#define HTC_CONNECT_SERVICE_MSG_SERVICE_ID_OFFSET 0x00000000 +#define HTC_CONNECT_SERVICE_MSG_CONNECTIONFLAGS_LSB 0 +#define HTC_CONNECT_SERVICE_MSG_CONNECTIONFLAGS_MASK 0x0000ffff +#define HTC_CONNECT_SERVICE_MSG_CONNECTIONFLAGS_OFFSET 0x00000004 +#define HTC_CONNECT_SERVICE_MSG_SERVICEMETALENGTH_LSB 16 +#define HTC_CONNECT_SERVICE_MSG_SERVICEMETALENGTH_MASK 0x00ff0000 +#define HTC_CONNECT_SERVICE_MSG_SERVICEMETALENGTH_OFFSET 0x00000004 + +#define HTC_SET_RECV_ALLOC_SHIFT 8 +#define HTC_SET_RECV_ALLOC_MASK 0xFF00 +#define HTC_CONNECT_FLAGS_SET_RECV_ALLOCATION(value) (((A_UINT8)value) << HTC_SET_RECV_ALLOC_SHIFT) +#define HTC_CONNECT_FLAGS_GET_RECV_ALLOCATION(value) (A_UINT8)(((value) & HTC_SET_RECV_ALLOC_MASK) >> HTC_SET_RECV_ALLOC_SHIFT) + +/* connect response + * direction : target-to-host */ +typedef PREPACK struct { + /* service ID that the connection request was made */ + A_UINT32 MessageID:16, service_id:16; + A_UINT32 Status : 8, /* service connection status */ + EndpointID : 8, /* assigned endpoint ID */ + MaxMsgSize : 16; /* maximum expected message size on this endpoint */ + A_UINT32 ServiceMetaLength : 8, /* length of meta data that follows */ + _Pad1 : 8, reserved : 16; + + /* service-specific meta data starts after the header */ + +} POSTPACK HTC_CONNECT_SERVICE_RESPONSE_MSG; + +#define HTC_CONNECT_SERVICE_RESPONSE_MSG_MESSAGEID_LSB 0 +#define HTC_CONNECT_SERVICE_RESPONSE_MSG_MESSAGEID_MASK 0x0000ffff +#define HTC_CONNECT_SERVICE_RESPONSE_MSG_MESSAGEID_OFFSET 0x00000000 +#define HTC_CONNECT_SERVICE_RESPONSE_MSG_SERVICEID_LSB 16 +#define HTC_CONNECT_SERVICE_RESPONSE_MSG_SERVICEID_MASK 0xffff0000 +#define HTC_CONNECT_SERVICE_RESPONSE_MSG_SERVICEID_OFFSET 0x00000000 +#define HTC_CONNECT_SERVICE_RESPONSE_MSG_STATUS_LSB 0 +#define HTC_CONNECT_SERVICE_RESPONSE_MSG_STATUS_MASK 0x000000ff +#define HTC_CONNECT_SERVICE_RESPONSE_MSG_STATUS_OFFSET 0x00000004 +#define HTC_CONNECT_SERVICE_RESPONSE_MSG_ENDPOINTID_LSB 8 +#define HTC_CONNECT_SERVICE_RESPONSE_MSG_ENDPOINTID_MASK 0x0000ff00 +#define HTC_CONNECT_SERVICE_RESPONSE_MSG_ENDPOINTID_OFFSET 0x00000004 +#define HTC_CONNECT_SERVICE_RESPONSE_MSG_MAXMSGSIZE_LSB 16 +#define HTC_CONNECT_SERVICE_RESPONSE_MSG_MAXMSGSIZE_MASK 0xffff0000 +#define HTC_CONNECT_SERVICE_RESPONSE_MSG_MAXMSGSIZE_OFFSET 0x00000004 +#define HTC_CONNECT_SERVICE_RESPONSE_MSG_SERVICEMETALENGTH_LSB 0 +#define HTC_CONNECT_SERVICE_RESPONSE_MSG_SERVICEMETALENGTH_MASK 0x000000ff +#define HTC_CONNECT_SERVICE_RESPONSE_MSG_SERVICEMETALENGTH_OFFSET 0x00000008 + +typedef PREPACK struct { + A_UINT32 MessageID : 16, reserved : 16; + /* currently, no other fields */ +} POSTPACK HTC_SETUP_COMPLETE_MSG; + +#define HTC_SETUP_COMPLETE_MSG_MESSAGEID_LSB 0 +#define HTC_SETUP_COMPLETE_MSG_MESSAGEID_MASK 0x0000ffff +#define HTC_SETUP_COMPLETE_MSG_MESSAGEID_OFFSET 0x00000000 + +/* extended setup completion message */ +typedef PREPACK struct { + A_UINT32 MessageID : 16, reserved : 16; + A_UINT32 SetupFlags : 32; + A_UINT32 MaxMsgsPerBundledRecv : 8, Rsvd0 : 8, Rsvd1 : 8, Rsvd2 : 8; +} POSTPACK HTC_SETUP_COMPLETE_EX_MSG; + +#define HTC_SETUP_COMPLETE_EX_MSG_MESSAGEID_LSB 0 +#define HTC_SETUP_COMPLETE_EX_MSG_MESSAGEID_MASK 0x0000ffff +#define HTC_SETUP_COMPLETE_EX_MSG_MESSAGEID_OFFSET 0x00000000 +#define HTC_SETUP_COMPLETE_EX_MSG_SETUPFLAGS_LSB 0 +#define HTC_SETUP_COMPLETE_EX_MSG_SETUPFLAGS_MASK 0xffffffff +#define HTC_SETUP_COMPLETE_EX_MSG_SETUPFLAGS_OFFSET 0x00000004 +#define HTC_SETUP_COMPLETE_EX_MSG_MAXMSGSPERBUNDLEDRECV_LSB 0 +#define HTC_SETUP_COMPLETE_EX_MSG_MAXMSGSPERBUNDLEDRECV_MASK 0x000000ff +#define HTC_SETUP_COMPLETE_EX_MSG_MAXMSGSPERBUNDLEDRECV_OFFSET 0x00000008 +#define HTC_SETUP_COMPLETE_EX_MSG_RSVD0_LSB 8 +#define HTC_SETUP_COMPLETE_EX_MSG_RSVD0_MASK 0x0000ff00 +#define HTC_SETUP_COMPLETE_EX_MSG_RSVD0_OFFSET 0x00000008 +#define HTC_SETUP_COMPLETE_EX_MSG_RSVD1_LSB 16 +#define HTC_SETUP_COMPLETE_EX_MSG_RSVD1_MASK 0x00ff0000 +#define HTC_SETUP_COMPLETE_EX_MSG_RSVD1_OFFSET 0x00000008 +#define HTC_SETUP_COMPLETE_EX_MSG_RSVD2_LSB 24 +#define HTC_SETUP_COMPLETE_EX_MSG_RSVD2_MASK 0xff000000 +#define HTC_SETUP_COMPLETE_EX_MSG_RSVD2_OFFSET 0x00000008 + +#define HTC_SETUP_COMPLETE_FLAGS_ENABLE_BUNDLE_RECV (1 << 0) /* enable recv bundling from target */ +#define HTC_SETUP_COMPLETE_FLAGS_DISABLE_TX_CREDIT_FLOW (1 << 1) /* disable credit based flow control, + only supported on some interconnects */ + +/* connect response status codes */ +#define HTC_SERVICE_SUCCESS 0 /* success */ +#define HTC_SERVICE_NOT_FOUND 1 /* service could not be found */ +#define HTC_SERVICE_FAILED 2 /* specific service failed the connect */ +#define HTC_SERVICE_NO_RESOURCES 3 /* no resources (i.e. no more endpoints) */ +#define HTC_SERVICE_NO_MORE_EP 4 /* specific service is not allowing any more + endpoints */ + +/* report record IDs */ + +#define HTC_RECORD_NULL 0 +#define HTC_RECORD_CREDITS 1 +#define HTC_RECORD_LOOKAHEAD 2 +#define HTC_RECORD_LOOKAHEAD_BUNDLE 3 + +typedef PREPACK struct { + A_UINT32 RecordID : 8, /* Record ID */ + Length : 8, /* Length of record */ + reserved : 16; +} POSTPACK HTC_RECORD_HDR; + +#define HTC_RECORD_HDR_RECORDID_LSB 0 +#define HTC_RECORD_HDR_RECORDID_MASK 0x000000ff +#define HTC_RECORD_HDR_RECORDID_OFFSET 0x00000000 +#define HTC_RECORD_HDR_LENGTH_LSB 8 +#define HTC_RECORD_HDR_LENGTH_MASK 0x0000ff00 +#define HTC_RECORD_HDR_LENGTH_OFFSET 0x00000000 + +typedef PREPACK struct { + A_UINT32 EndpointID : 8, /* Endpoint that owns these credits */ + Credits : 8, /* credits to report since last report */ + reserved : 16; +} POSTPACK HTC_CREDIT_REPORT; + +#define HTC_CREDIT_REPORT_ENDPOINTID_LSB 0 +#define HTC_CREDIT_REPORT_ENDPOINTID_MASK 0x000000ff +#define HTC_CREDIT_REPORT_ENDPOINTID_OFFSET 0x00000000 +#define HTC_CREDIT_REPORT_CREDITS_LSB 8 +#define HTC_CREDIT_REPORT_CREDITS_MASK 0x0000ff00 +#define HTC_CREDIT_REPORT_CREDITS_OFFSET 0x00000000 + +typedef PREPACK struct { + A_UINT32 PreValid : 8, /* pre valid guard */ + reserved0 : 24; + A_UINT32 LookAhead0 : 8, /* 4 byte lookahead */ + LookAhead1 : 8, LookAhead2 : 8, LookAhead3 : 8; + A_UINT32 PostValid : 8, /* post valid guard */ + reserved1 : 24; + + /* NOTE: the LookAhead array is guarded by a PreValid and Post Valid guard bytes. + * The PreValid bytes must equal the inverse of the PostValid byte */ + +} POSTPACK HTC_LOOKAHEAD_REPORT; + +#define HTC_LOOKAHEAD_REPORT_PREVALID_LSB 0 +#define HTC_LOOKAHEAD_REPORT_PREVALID_MASK 0x000000ff +#define HTC_LOOKAHEAD_REPORT_PREVALID_OFFSET 0x00000000 +#define HTC_LOOKAHEAD_REPORT_LOOKAHEAD0_LSB 0 +#define HTC_LOOKAHEAD_REPORT_LOOKAHEAD0_MASK 0x000000ff +#define HTC_LOOKAHEAD_REPORT_LOOKAHEAD0_OFFSET 0x00000004 +#define HTC_LOOKAHEAD_REPORT_LOOKAHEAD1_LSB 8 +#define HTC_LOOKAHEAD_REPORT_LOOKAHEAD1_MASK 0x0000ff00 +#define HTC_LOOKAHEAD_REPORT_LOOKAHEAD1_OFFSET 0x00000004 +#define HTC_LOOKAHEAD_REPORT_LOOKAHEAD2_LSB 16 +#define HTC_LOOKAHEAD_REPORT_LOOKAHEAD2_MASK 0x00ff0000 +#define HTC_LOOKAHEAD_REPORT_LOOKAHEAD2_OFFSET 0x00000004 +#define HTC_LOOKAHEAD_REPORT_LOOKAHEAD3_LSB 24 +#define HTC_LOOKAHEAD_REPORT_LOOKAHEAD3_MASK 0xff000000 +#define HTC_LOOKAHEAD_REPORT_LOOKAHEAD3_OFFSET 0x00000004 +#define HTC_LOOKAHEAD_REPORT_POSTVALID_LSB 0 +#define HTC_LOOKAHEAD_REPORT_POSTVALID_MASK 0x000000ff +#define HTC_LOOKAHEAD_REPORT_POSTVALID_OFFSET 0x00000008 + +typedef PREPACK struct { + A_UINT32 LookAhead0 : 8, /* 4 byte lookahead */ + LookAhead1 : 8, LookAhead2 : 8, LookAhead3 : 8; +} POSTPACK HTC_BUNDLED_LOOKAHEAD_REPORT; + +#define HTC_BUNDLED_LOOKAHEAD_REPORT_LOOKAHEAD0_LSB 0 +#define HTC_BUNDLED_LOOKAHEAD_REPORT_LOOKAHEAD0_MASK 0x000000ff +#define HTC_BUNDLED_LOOKAHEAD_REPORT_LOOKAHEAD0_OFFSET 0x00000000 +#define HTC_BUNDLED_LOOKAHEAD_REPORT_LOOKAHEAD1_LSB 8 +#define HTC_BUNDLED_LOOKAHEAD_REPORT_LOOKAHEAD1_MASK 0x0000ff00 +#define HTC_BUNDLED_LOOKAHEAD_REPORT_LOOKAHEAD1_OFFSET 0x00000000 +#define HTC_BUNDLED_LOOKAHEAD_REPORT_LOOKAHEAD2_LSB 16 +#define HTC_BUNDLED_LOOKAHEAD_REPORT_LOOKAHEAD2_MASK 0x00ff0000 +#define HTC_BUNDLED_LOOKAHEAD_REPORT_LOOKAHEAD2_OFFSET 0x00000000 +#define HTC_BUNDLED_LOOKAHEAD_REPORT_LOOKAHEAD3_LSB 24 +#define HTC_BUNDLED_LOOKAHEAD_REPORT_LOOKAHEAD3_MASK 0xff000000 +#define HTC_BUNDLED_LOOKAHEAD_REPORT_LOOKAHEAD3_OFFSET 0x00000000 + +#ifndef ATH_TARGET +#include "athendpack.h" +#endif + +#endif /* __HTC_H__ */ diff --git a/drivers/staging/fw-api/fw/htc_services.h b/drivers/staging/fw-api/fw/htc_services.h new file mode 100644 index 0000000000000000000000000000000000000000..c9c9537a20e1fec192440d25e92a1cfee01f7ab9 --- /dev/null +++ b/drivers/staging/fw-api/fw/htc_services.h @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2012, 2014, 2016, 2017 The Linux Foundation. + * All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef __HTC_SERVICES_H__ +#define __HTC_SERVICES_H__ + +/* Current service IDs */ + +typedef enum { + RSVD_SERVICE_GROUP = 0, + WMI_SERVICE_GROUP = 1, + NMI_SERVICE_GROUP = 2, + HTT_SERVICE_GROUP = 3, + CFG_NV_SERVICE_GROUP = 4, + WDI_IPA_SERVICE_GROUP = 5, + PACKET_LOG_SERVICE_GROUP = 6, + HTC_TEST_GROUP = 254, + HTC_SERVICE_GROUP_LAST = 255 +} HTC_SERVICE_GROUP_IDS; + +#define MAKE_SERVICE_ID(group,index) \ + (int)(((int)group << 8) | (int)(index)) + +/* NOTE: service ID of 0x0000 is reserved and should never be used */ +#define HTC_CTRL_RSVD_SVC MAKE_SERVICE_ID(RSVD_SERVICE_GROUP,1) +/* WMI_CONTROL_SVC: WMI service for MAC 0 */ +#define WMI_CONTROL_SVC MAKE_SERVICE_ID(WMI_SERVICE_GROUP,0) +#define WMI_DATA_BE_SVC MAKE_SERVICE_ID(WMI_SERVICE_GROUP,1) +#define WMI_DATA_BK_SVC MAKE_SERVICE_ID(WMI_SERVICE_GROUP,2) +#define WMI_DATA_VI_SVC MAKE_SERVICE_ID(WMI_SERVICE_GROUP,3) +#define WMI_DATA_VO_SVC MAKE_SERVICE_ID(WMI_SERVICE_GROUP,4) +/* WMI_CONTROL_SVC_WMAC1,2: WMI service for MACs 1 and 2 (where applicable) */ +#define WMI_CONTROL_SVC_WMAC1 MAKE_SERVICE_ID(WMI_SERVICE_GROUP,5) +#define WMI_CONTROL_SVC_WMAC2 MAKE_SERVICE_ID(WMI_SERVICE_GROUP,6) +#define WMI_MAX_SERVICES 7 + +#define NMI_CONTROL_SVC MAKE_SERVICE_ID(NMI_SERVICE_GROUP,0) +#define NMI_DATA_SVC MAKE_SERVICE_ID(NMI_SERVICE_GROUP,1) + +#define HTT_DATA_MSG_SVC MAKE_SERVICE_ID(HTT_SERVICE_GROUP,0) +#define HTT_DATA2_MSG_SVC MAKE_SERVICE_ID(HTT_SERVICE_GROUP,1) +#define HTT_DATA3_MSG_SVC MAKE_SERVICE_ID(HTT_SERVICE_GROUP, 2) + +/* raw stream service (i.e. flash, tcmd, calibration apps) */ +#define HTC_RAW_STREAMS_SVC MAKE_SERVICE_ID(HTC_TEST_GROUP,0) + +#define CFG_NV_SVC MAKE_SERVICE_ID(CFG_NV_SERVICE_GROUP,0) +#define WDI_IPA_TX_SVC MAKE_SERVICE_ID(WDI_IPA_SERVICE_GROUP,0) + +#define PACKET_LOG_SVC MAKE_SERVICE_ID(PACKET_LOG_SERVICE_GROUP, 0) + +/* + * Directions for interconnect pipe configuration. + * These definitions may be used during configuration and are shared + * between Host and Target. + * + * Pipe Directions are relative to the Host, so PIPEDIR_IN means + * "coming IN over air through Target to Host" as with a WiFi Rx operation. + * Conversely, PIPEDIR_OUT means "going OUT from Host through Target over air" + * as with a WiFi Tx operation. This is somewhat awkward for the "middle-man" + * Target since things that are "PIPEDIR_OUT" are coming IN to the Target + * over the interconnect. + */ +typedef A_UINT32 PIPEDIR; +#define PIPEDIR_NONE 0 +#define PIPEDIR_IN 1 /* Target-->Host, WiFi Rx direction */ +#define PIPEDIR_OUT 2 /* Host->Target, WiFi Tx direction */ +#define PIPEDIR_INOUT 3 /* bidirectional, target to target */ +#define PIPEDIR_INOUT_T2T PIPEDIR_INOUT +#define PIPEDIR_INOUT_H2H 4 /* bidirectional, host to host */ +#define PIPEDIR_MATCH(d1, d2) (((PIPEDIR)(d1) & (PIPEDIR)(d2)) != 0) + +/* Establish a mapping between a service/direction and a pipe. */ +struct service_to_pipe { + A_UINT32 service_id; + A_UINT32 pipedir; + A_UINT32 pipenum; +}; + +#endif /*HTC_SERVICES_H_ */ diff --git a/drivers/staging/fw-api/fw/htt.h b/drivers/staging/fw-api/fw/htt.h new file mode 100644 index 0000000000000000000000000000000000000000..b264e096a05efdc75aaea66af32934faef44186e --- /dev/null +++ b/drivers/staging/fw-api/fw/htt.h @@ -0,0 +1,9628 @@ +/* + * Copyright (c) 2011-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * @file htt.h + * + * @details the public header file of HTT layer + */ + +#ifndef _HTT_H_ +#define _HTT_H_ + +#include /* A_UINT32 */ +#include /* PREPACK, POSTPACK */ +#ifdef ATHR_WIN_NWF +#pragma warning(disable:4214) /*bit field types other than int */ +#endif +#include "wlan_defs.h" +#include + +/* + * Unless explicitly specified to use 64 bits to represent physical addresses + * (or more precisely, bus addresses), default to 32 bits. + */ +#ifndef HTT_PADDR64 +#define HTT_PADDR64 0 +#endif + +#ifndef offsetof +#define offsetof(type, field) ((unsigned int)(&((type *)0)->field)) +#endif + +/* + * HTT version history: + * 1.0 initial numbered version + * 1.1 modifications to STATS messages. + * These modifications are not backwards compatible, but since the + * STATS messages themselves are non-essential (they are for debugging), + * the 1.1 version of the HTT message library as a whole is compatible + * with the 1.0 version. + * 1.2 reset mask IE added to STATS_REQ message + * 1.3 stat config IE added to STATS_REQ message + *---- + * 2.0 FW rx PPDU desc added to RX_IND message + * 2.1 Enable msdu_ext/frag_desc banking change for WIFI2.0 + *---- + * 3.0 Remove HTT_H2T_MSG_TYPE_MGMT_TX message + * 3.1 Added HTT_T2H_MSG_TYPE_RX_IN_ORD_PADDR_IND message + * 3.2 Added HTT_H2T_MSG_TYPE_WDI_IPA_CFG, + * HTT_H2T_MSG_TYPE_WDI_IPA_OP_REQUEST messages + * 3.3 Added HTT_H2T_MSG_TYPE_AGGR_CFG_EX message + * 3.4 Added tx_compl_req flag in HTT tx descriptor + * 3.5 Added flush and fail stats in rx_reorder stats structure + * 3.6 Added frag flag in HTT RX INORDER PADDR IND header + * 3.7 Made changes to support EOS Mac_core 3.0 + * 3.8 Added txq_group information element definition; + * added optional txq_group suffix to TX_CREDIT_UPDATE_IND message + * 3.9 Added HTT_T2H CHAN_CHANGE message; + * Allow buffer addresses in bus-address format to be stored as + * either 32 bits or 64 bits. + * 3.10 Add optional TLV extensions to the VERSION_REQ and VERSION_CONF + * messages to specify which HTT options to use. + * Initial TLV options cover: + * - whether to use 32 or 64 bits to represent LL bus addresses + * - whether to use TX_COMPL_IND or TX_CREDIT_UPDATE_IND in HL systems + * - how many tx queue groups to use + * 3.11 Expand rx debug stats: + * - Expand the rx_reorder_stats struct with stats about successful and + * failed rx buffer allcoations. + * - Add a new rx_remote_buffer_mgmt_stats struct with stats about + * the supply, allocation, use, and recycling of rx buffers for the + * "remote ring" of rx buffers in host member in LL systems. + * Add RX_REMOTE_RING_BUFFER_INFO stats type for uploading these stats. + * 3.12 Add "rx offload packet error" message with initial "MIC error" subtype + * 3.13 Add constants + macros to support 64-bit address format for the + * tx fragments descriptor, the rx ring buffer, and the rx ring + * index shadow register. + * 3.14 Add a method for the host to provide detailed per-frame tx specs: + * - Add htt_tx_msdu_desc_ext_t struct def. + * - Add TLV to specify whether the target supports the HTT tx MSDU + * extension descriptor. + * - Change a reserved bit in the HTT tx MSDU descriptor to an + * "extension" bit, to specify whether a HTT tx MSDU extension + * descriptor is present. + * 3.15 Add HW rx desc info to per-MSDU info elems in RX_IN_ORD_PADDR_IND msg. + * (This allows the host to obtain key information about the MSDU + * from a memory location already in the cache, rather than taking a + * cache miss for each MSDU by reading the HW rx descs.) + * 3.16 Add htt_pkt_type_eth2 and define pkt_subtype flags to indicate + * whether a copy-engine classification result is appended to TX_FRM. + * 3.17 Add a version of the WDI_IPA_CFG message; add RX_RING2 to WDI_IPA_CFG + * 3.18 Add a PEER_DEL tx completion indication status, for HL cleanup of + * tx frames in the target after the peer has already been deleted. + * 3.19 Add HTT_DBG_STATS_RX_RATE_INFO_V2 and HTT_DBG_STATS_TX_RATE_INFO_V2 + * 3.20 Expand rx_reorder_stats. + * 3.21 Add optional rx channel spec to HL RX_IND. + * 3.22 Expand rx_reorder_stats + * (distinguish duplicates within vs. outside block ack window) + * 3.23 Add HTT_T2H_MSG_TYPE_RATE_REPORT to report peer justified rate. + * The justified rate is calculated by two steps. The first is to multiply + * user-rate by (1 - PER) and the other is to smooth the step 1's result + * by a low pass filter. + * This change allows HL download scheduling to consider the WLAN rate + * that will be used for transmitting the downloaded frames. + * 3.24 Expand rx_reorder_stats + * (add counter for decrypt / MIC errors) + * 3.25 Expand rx_reorder_stats + * (add counter of frames received into both local + remote rings) + * 3.26 Add stats struct for counting rx of tx BF, MU, SU, and NDPA frames + * (HTT_DBG_STATS_TXBF_MUSU_NDPA_PKT, rx_txbf_musu_ndpa_pkts_stats) + * 3.27 Add a new interface for flow-control. The following t2h messages have + * been included: HTT_T2H_MSG_TYPE_FLOW_POOL_MAP and + * HTT_T2H_MSG_TYPE_FLOW_POOL_UNMAP + * 3.28 Add a new interface for ring interface change. The following two h2t + * and one t2h messages have been included: + * HTT_H2T_MSG_TYPE_SRING_SETUP, HTT_H2T_MSG_TYPE_RX_RING_SELECTION_CFG, + * and HTT_T2H_MSG_TYPE_SRING_SETUP_DONE + * 3.29 Add definitions of htt_tx_msdu_desc_ext2_t descriptor and other + * information elements passed from the host to a Lithium target, + * Add definitions of the HTT_H2T ADD_WDS_ENTRY and DELETE_WDS_ENTRY + * messages and the HTT_T2H MAP_FLOW_INFO message (for use with Lithium + * targets). + * 3.30 Add pktlog flag inside HTT_T2H RX_IN_ORD_PADDR_IND message + * 3.31 Add HTT_H2T_MSG_TYPE_RFS_CONFIG + */ +#define HTT_CURRENT_VERSION_MAJOR 3 +#define HTT_CURRENT_VERSION_MINOR 31 + +#define HTT_NUM_TX_FRAG_DESC 1024 + +#define HTT_WIFI_IP_VERSION(x, y) ((x) == (y)) + +#define HTT_CHECK_SET_VAL(field, val) \ + A_ASSERT(!((val) & ~((field ## _M) >> (field ## _S)))) + +/* macros to assist in sign-extending fields from HTT messages */ +#define HTT_SIGN_BIT_MASK(field) \ + ((field ## _M + (1 << field ## _S)) >> 1) + #define HTT_SIGN_BIT(_val, field) \ + (_val & HTT_SIGN_BIT_MASK(field)) + #define HTT_SIGN_BIT_UNSHIFTED(_val, field) \ + (HTT_SIGN_BIT(_val, field) >> field ## _S) + #define HTT_SIGN_BIT_UNSHIFTED_MINUS_ONE(_val, field) \ + (HTT_SIGN_BIT_UNSHIFTED(_val, field) - 1) + #define HTT_SIGN_BIT_EXTENSION(_val, field) \ + (~(HTT_SIGN_BIT_UNSHIFTED(_val, field) | \ + HTT_SIGN_BIT_UNSHIFTED_MINUS_ONE(_val, field))) + #define HTT_SIGN_BIT_EXTENSION_MASK(_val, field) \ + (HTT_SIGN_BIT_EXTENSION(_val, field) & ~(field ## _M >> field ## _S)) + + +/* + * TEMPORARY: + * Provide HTT_H2T_MSG_TYPE_MGMT_TX as an alias for + * DEPRECATED_HTT_H2T_MSG_TYPE_MGMT_TX until all code + * that refers to HTT_H2T_MSG_TYPE_MGMT_TX has been + * updated. + */ +#define HTT_H2T_MSG_TYPE_MGMT_TX DEPRECATED_HTT_H2T_MSG_TYPE_MGMT_TX + +/* + * TEMPORARY: + * Provide HTT_T2H_MSG_TYPE_RC_UPDATE_IND as an alias for + * DEPRECATED_HTT_T2H_MSG_TYPE_RC_UPDATE_IND until all code + * that refers to HTT_T2H_MSG_TYPE_RC_UPDATE_IND has been + * updated. + */ +#define HTT_T2H_MSG_TYPE_RC_UPDATE_IND DEPRECATED_HTT_T2H_MSG_TYPE_RC_UPDATE_IND + +/* HTT Access Category values */ +enum HTT_AC_WMM { + /* WMM Access Categories */ + HTT_AC_WMM_BE = 0x0, + HTT_AC_WMM_BK = 0x1, + HTT_AC_WMM_VI = 0x2, + HTT_AC_WMM_VO = 0x3, + /* extension Access Categories */ + HTT_AC_EXT_NON_QOS = 0x4, + HTT_AC_EXT_UCAST_MGMT = 0x5, + HTT_AC_EXT_MCAST_DATA = 0x6, + HTT_AC_EXT_MCAST_MGMT = 0x7, +}; +enum HTT_AC_WMM_MASK { + /* WMM Access Categories */ + HTT_AC_WMM_BE_MASK = (1 << HTT_AC_WMM_BE), + HTT_AC_WMM_BK_MASK = (1 << HTT_AC_WMM_BK), + HTT_AC_WMM_VI_MASK = (1 << HTT_AC_WMM_VI), + HTT_AC_WMM_VO_MASK = (1 << HTT_AC_WMM_VO), + /* extension Access Categories */ + HTT_AC_EXT_NON_QOS_MASK = (1 << HTT_AC_EXT_NON_QOS), + HTT_AC_EXT_UCAST_MGMT_MASK = (1 << HTT_AC_EXT_UCAST_MGMT), + HTT_AC_EXT_MCAST_DATA_MASK = (1 << HTT_AC_EXT_MCAST_DATA), + HTT_AC_EXT_MCAST_MGMT_MASK = (1 << HTT_AC_EXT_MCAST_MGMT), +}; +#define HTT_AC_MASK_WMM \ + (HTT_AC_WMM_BE_MASK | HTT_AC_WMM_BK_MASK | \ + HTT_AC_WMM_VI_MASK | HTT_AC_WMM_VO_MASK) +#define HTT_AC_MASK_EXT \ + (HTT_AC_EXT_NON_QOS_MASK | HTT_AC_EXT_UCAST_MGMT_MASK | \ + HTT_AC_EXT_MCAST_DATA_MASK | HTT_AC_EXT_MCAST_MGMT_MASK) +#define HTT_AC_MASK_ALL (HTT_AC_MASK_WMM | HTT_AC_MASK_EXT) + +/* + * htt_dbg_stats_type - + * bit positions for each stats type within a stats type bitmask + * The bitmask contains 24 bits. + */ +enum htt_dbg_stats_type { + HTT_DBG_STATS_WAL_PDEV_TXRX = 0, /* bit 0 -> 0x1 */ + HTT_DBG_STATS_RX_REORDER = 1, /* bit 1 -> 0x2 */ + HTT_DBG_STATS_RX_RATE_INFO = 2, /* bit 2 -> 0x4 */ + HTT_DBG_STATS_TX_PPDU_LOG = 3, /* bit 3 -> 0x8 */ + HTT_DBG_STATS_TX_RATE_INFO = 4, /* bit 4 -> 0x10 */ + HTT_DBG_STATS_TIDQ = 5, /* bit 5 -> 0x20 */ + HTT_DBG_STATS_TXBF_INFO = 6, /* bit 6 -> 0x40 */ + HTT_DBG_STATS_SND_INFO = 7, /* bit 7 -> 0x80 */ + HTT_DBG_STATS_ERROR_INFO = 8, /* bit 8 -> 0x100 */ + HTT_DBG_STATS_TX_SELFGEN_INFO = 9, /* bit 9 -> 0x200 */ + HTT_DBG_STATS_TX_MU_INFO = 10, /* bit 10 -> 0x400 */ + HTT_DBG_STATS_SIFS_RESP_INFO = 11, /* bit 11 -> 0x800 */ + HTT_DBG_STATS_RX_REMOTE_RING_BUFFER_INFO = 12, /* bit 12 -> 0x1000 */ + HTT_DBG_STATS_RX_RATE_INFO_V2 = 13, /* bit 13 -> 0x2000 */ + HTT_DBG_STATS_TX_RATE_INFO_V2 = 14, /* bit 14 -> 0x4000 */ + HTT_DBG_STATS_TXBF_MUSU_NDPA_PKT = 15, /* bit 15 -> 0x8000 */ + /* bits 16-23 currently reserved */ + + /* keep this last */ + HTT_DBG_NUM_STATS +}; + +/*=== HTT option selection TLVs === + * Certain HTT messages have alternatives or options. + * For such cases, the host and target need to agree on which option to use. + * Option specification TLVs can be appended to the VERSION_REQ and + * VERSION_CONF messages to select options other than the default. + * These TLVs are entirely optional - if they are not provided, there is a + * well-defined default for each option. If they are provided, they can be + * provided in any order. Each TLV can be present or absent independent of + * the presence / absence of other TLVs. + * + * The HTT option selection TLVs use the following format: + * |31 16|15 8|7 0| + * |---------------------------------+----------------+----------------| + * | value (payload) | length | tag | + * |-------------------------------------------------------------------| + * The value portion need not be only 2 bytes; it can be extended by any + * integer number of 4-byte units. The total length of the TLV, including + * the tag and length fields, must be a multiple of 4 bytes. The length + * field specifies the total TLV size in 4-byte units. Thus, the typical + * TLV, with a 1-byte tag field, a 1-byte length field, and a 2-byte value + * field, would store 0x1 in its length field, to show that the TLV occupies + * a single 4-byte unit. + */ + +/*--- TLV header format - applies to all HTT option TLVs ---*/ + +enum HTT_OPTION_TLV_TAGS { + HTT_OPTION_TLV_TAG_RESERVED0 = 0x0, + HTT_OPTION_TLV_TAG_LL_BUS_ADDR_SIZE = 0x1, + HTT_OPTION_TLV_TAG_HL_SUPPRESS_TX_COMPL_IND = 0x2, + HTT_OPTION_TLV_TAG_MAX_TX_QUEUE_GROUPS = 0x3, + HTT_OPTION_TLV_TAG_SUPPORT_TX_MSDU_DESC_EXT = 0x4, +}; + +PREPACK struct htt_option_tlv_header_t { + A_UINT8 tag; + A_UINT8 length; +} POSTPACK; + +#define HTT_OPTION_TLV_TAG_M 0x000000ff +#define HTT_OPTION_TLV_TAG_S 0 +#define HTT_OPTION_TLV_LENGTH_M 0x0000ff00 +#define HTT_OPTION_TLV_LENGTH_S 8 +/* + * value0 - 16 bit value field stored in word0 + * The TLV's value field may be longer than 2 bytes, in which case + * the remainder of the value is stored in word1, word2, etc. + */ +#define HTT_OPTION_TLV_VALUE0_M 0xffff0000 +#define HTT_OPTION_TLV_VALUE0_S 16 + +#define HTT_OPTION_TLV_TAG_SET(word, tag) \ + do { \ + HTT_CHECK_SET_VAL(HTT_OPTION_TLV_TAG, tag); \ + (word) |= ((tag) << HTT_OPTION_TLV_TAG_S); \ + } while (0) +#define HTT_OPTION_TLV_TAG_GET(word) \ + (((word) & HTT_OPTION_TLV_TAG_M) >> HTT_OPTION_TLV_TAG_S) + +#define HTT_OPTION_TLV_LENGTH_SET(word, tag) \ + do { \ + HTT_CHECK_SET_VAL(HTT_OPTION_TLV_LENGTH, tag); \ + (word) |= ((tag) << HTT_OPTION_TLV_LENGTH_S); \ + } while (0) +#define HTT_OPTION_TLV_LENGTH_GET(word) \ + (((word) & HTT_OPTION_TLV_LENGTH_M) >> HTT_OPTION_TLV_LENGTH_S) + +#define HTT_OPTION_TLV_VALUE0_SET(word, tag) \ + do { \ + HTT_CHECK_SET_VAL(HTT_OPTION_TLV_VALUE0, tag); \ + (word) |= ((tag) << HTT_OPTION_TLV_VALUE0_S); \ + } while (0) +#define HTT_OPTION_TLV_VALUE0_GET(word) \ + (((word) & HTT_OPTION_TLV_VALUE0_M) >> HTT_OPTION_TLV_VALUE0_S) + +/*--- format of specific HTT option TLVs ---*/ + +/* + * HTT option TLV for specifying LL bus address size + * Some chips require bus addresses used by the target to access buffers + * within the host's memory to be 32 bits; others require bus addresses + * used by the target to access buffers within the host's memory to be + * 64 bits. + * The LL_BUS_ADDR_SIZE TLV can be sent from the target to the host as + * a suffix to the VERSION_CONF message to specify which bus address format + * the target requires. + * If this LL_BUS_ADDR_SIZE TLV is not sent by the target, the host should + * default to providing bus addresses to the target in 32-bit format. + */ +enum HTT_OPTION_TLV_LL_BUS_ADDR_SIZE_VALUES { + HTT_OPTION_TLV_LL_BUS_ADDR_SIZE32 = 0x0, + HTT_OPTION_TLV_LL_BUS_ADDR_SIZE64 = 0x1, +}; +PREPACK struct htt_option_tlv_ll_bus_addr_size_t { + struct htt_option_tlv_header_t hdr; + A_UINT16 ll_bus_addr_size; /* LL_BUS_ADDR_SIZE_VALUES enum */ +} POSTPACK; + +/* + * HTT option TLV for specifying whether HL systems should indicate + * over-the-air tx completion for individual frames, or should instead + * send a bulk TX_CREDIT_UPDATE_IND except when the host explicitly + * requests an OTA tx completion for a particular tx frame. + * This option does not apply to LL systems, where the TX_COMPL_IND + * is mandatory. + * This option is primarily intended for HL systems in which the tx frame + * downloads over the host --> target bus are as slow as or slower than + * the transmissions over the WLAN PHY. For cases where the bus is faster + * than the WLAN PHY, the target will transmit relatively large A-MPDUs, + * and consquently will send one TX_COMPL_IND message that covers several + * tx frames. For cases where the WLAN PHY is faster than the bus, + * the target will end up transmitting very short A-MPDUs, and consequently + * sending many TX_COMPL_IND messages, which each cover a very small number + * of tx frames. + * The HL_SUPPRESS_TX_COMPL_IND TLV can be sent by the host to the target as + * a suffix to the VERSION_REQ message to request whether the host desires to + * use TX_CREDIT_UPDATE_IND rather than TX_COMPL_IND. The target can then + * send a HTT_SUPPRESS_TX_COMPL_IND TLV to the host as a suffix to the + * VERSION_CONF message to confirm whether TX_CREDIT_UPDATE_IND will be used + * rather than TX_COMPL_IND. TX_CREDIT_UPDATE_IND shall only be used if the + * host sends a HL_SUPPRESS_TX_COMPL_IND TLV requesting use of + * TX_CREDIT_UPDATE_IND, and the target sends a HL_SUPPRESS_TX_COMPLE_IND TLV + * back to the host confirming use of TX_CREDIT_UPDATE_IND. + * Lack of a HL_SUPPRESS_TX_COMPL_IND TLV from either host --> target or + * target --> host is equivalent to a HL_SUPPRESS_TX_COMPL_IND that + * explicitly specifies HL_ALLOW_TX_COMPL_IND in the value payload of the + * TLV. + */ +enum HTT_OPTION_TLV_HL_SUPPRESS_TX_COMPL_IND_VALUES { + HTT_OPTION_TLV_HL_ALLOW_TX_COMPL_IND = 0x0, + HTT_OPTION_TLV_HL_SUPPRESS_TX_COMPL_IND = 0x1, +}; +PREPACK struct htt_option_tlv_hl_suppress_tx_compl_ind_t { + struct htt_option_tlv_header_t hdr; + A_UINT16 hl_suppress_tx_compl_ind;/*HL_SUPPRESS_TX_COMPL_IND enum*/ +} POSTPACK; + +/* + * HTT option TLV for specifying how many tx queue groups the target + * may establish. + * This TLV specifies the maximum value the target may send in the + * txq_group_id field of any TXQ_GROUP information elements sent by + * the target to the host. This allows the host to pre-allocate an + * appropriate number of tx queue group structs. + * + * The MAX_TX_QUEUE_GROUPS_TLV can be sent from the host to the target as + * a suffix to the VERSION_REQ message to specify whether the host supports + * tx queue groups at all, and if so if there is any limit on the number of + * tx queue groups that the host supports. + * The MAX_TX_QUEUE_GROUPS TLV can be sent from the target to the host as + * a suffix to the VERSION_CONF message. If the host has specified in the + * VER_REQ message a limit on the number of tx queue groups the host can + * supprt, the target shall limit its specification of the maximum tx groups + * to be no larger than this host-specified limit. + * + * If the target does not provide a MAX_TX_QUEUE_GROUPS TLV, then the host + * shall preallocate 4 tx queue group structs, and the target shall not + * specify a txq_group_id larger than 3. + */ +enum HTT_OPTION_TLV_MAX_TX_QUEUE_GROUPS_VALUES { + HTT_OPTION_TLV_TX_QUEUE_GROUPS_UNSUPPORTED = 0, + /* + * values 1 through N specify the max number of tx queue groups + * the sender supports + */ + HTT_OPTION_TLV_TX_QUEUE_GROUPS_UNLIMITED = 0xffff, +}; +/* TEMPORARY backwards-compatibility alias for a typo fix - + * The htt_option_tlv_mac_tx_queue_groups_t typo has been corrected + * to htt_option_tlv_max_tx_queue_groups_t, but an alias is provided + * to support the old name (with the typo) until all references to the + * old name are replaced with the new name. + */ +#define htt_option_tlv_mac_tx_queue_groups_t \ + htt_option_tlv_max_tx_queue_groups_t +PREPACK struct htt_option_tlv_max_tx_queue_groups_t { + struct htt_option_tlv_header_t hdr; + A_UINT16 max_tx_queue_groups; /* max txq_group_id + 1 */ +} POSTPACK; + +/* + * HTT option TLV for specifying whether the target supports an extended + * version of the HTT tx descriptor. If the target provides this TLV + * and specifies in the TLV that the target supports an extended version + * of the HTT tx descriptor, the target must check the "extension" bit in + * the HTT tx descriptor, and if the extension bit is set, to expect a + * HTT tx MSDU extension descriptor immediately following the HTT tx MSDU + * descriptor. Furthermore, the target must provide room for the HTT + * tx MSDU extension descriptor in the target's TX_FRM buffer. + * This option is intended for systems where the host needs to explicitly + * control the transmission parameters such as tx power for individual + * tx frames. + * The SUPPORT_TX_MSDU_DESC_EXT TLB can be sent by the target to the host + * as a suffix to the VERSION_CONF message to explicitly specify whether + * the target supports the HTT tx MSDU extension descriptor. + * Lack of a SUPPORT_TX_MSDU_DESC_EXT from the target shall be interpreted + * by the host as lack of target support for the HTT tx MSDU extension + * descriptor; the host shall provide HTT tx MSDU extension descriptors in + * the HTT_H2T TX_FRM messages only if the target indicates it supports + * the HTT tx MSDU extension descriptor. + * The host is not required to provide the HTT tx MSDU extension descriptor + * just because the target supports it; the target must check the + * "extension" bit in the HTT tx MSDU descriptor to determine whether an + * extension descriptor is present. + */ +enum HTT_OPTION_TLV_SUPPORT_TX_MSDU_DESC_EXT_VALUES { + HTT_OPTION_TLV_TX_MSDU_DESC_EXT_NO_SUPPORT = 0x0, + HTT_OPTION_TLV_TX_MSDU_DESC_EXT_SUPPORT = 0x1, +}; +PREPACK struct htt_option_tlv_support_tx_msdu_desc_ext_t { + struct htt_option_tlv_header_t hdr; + A_UINT16 tx_msdu_desc_ext_support;/*SUPPORT_TX_MSDU_DESC_EXT enum*/ +} POSTPACK; + + +/*=== host -> target messages ===============================================*/ + +enum htt_h2t_msg_type { + HTT_H2T_MSG_TYPE_VERSION_REQ = 0x0, + HTT_H2T_MSG_TYPE_TX_FRM = 0x1, + HTT_H2T_MSG_TYPE_RX_RING_CFG = 0x2, + HTT_H2T_MSG_TYPE_STATS_REQ = 0x3, + HTT_H2T_MSG_TYPE_SYNC = 0x4, + HTT_H2T_MSG_TYPE_AGGR_CFG = 0x5, + HTT_H2T_MSG_TYPE_FRAG_DESC_BANK_CFG = 0x6, + DEPRECATED_HTT_H2T_MSG_TYPE_MGMT_TX = 0x7, /* no longer used */ + HTT_H2T_MSG_TYPE_WDI_IPA_CFG = 0x8, + HTT_H2T_MSG_TYPE_WDI_IPA_OP_REQ = 0x9, + HTT_H2T_MSG_TYPE_AGGR_CFG_EX = 0xa, /*per vdev amsdu subfrm limit*/ + HTT_H2T_MSG_TYPE_SRING_SETUP = 0xb, + HTT_H2T_MSG_TYPE_RX_RING_SELECTION_CFG = 0xc, + HTT_H2T_MSG_TYPE_ADD_WDS_ENTRY = 0xd, + HTT_H2T_MSG_TYPE_DELETE_WDS_ENTRY = 0xe, + HTT_H2T_MSG_TYPE_RFS_CONFIG = 0xf, + + /* keep this last */ + HTT_H2T_NUM_MSGS +}; + +/* + * HTT host to target message type - + * stored in bits 7:0 of the first word of the message + */ +#define HTT_H2T_MSG_TYPE_M 0xff +#define HTT_H2T_MSG_TYPE_S 0 + +#define HTT_H2T_MSG_TYPE_SET(word, msg_type) \ + do { \ + HTT_CHECK_SET_VAL(HTT_H2T_MSG_TYPE, msg_type); \ + (word) |= ((msg_type) << HTT_H2T_MSG_TYPE_S); \ + } while (0) +#define HTT_H2T_MSG_TYPE_GET(word) \ + (((word) & HTT_H2T_MSG_TYPE_M) >> HTT_H2T_MSG_TYPE_S) + +/** + * @brief target -> host version number request message definition + * + * |31 24|23 16|15 8|7 0| + * |----------------+----------------+----------------+----------------| + * | reserved | msg type | + * |-------------------------------------------------------------------| + * : option request TLV (optional) | + * :...................................................................: + * + * The VER_REQ message may consist of a single 4-byte word, or may be + * extended with TLVs that specify which HTT options the host is requesting + * from the target. + * The following option TLVs may be appended to the VER_REQ message: + * - HL_SUPPRESS_TX_COMPL_IND + * - HL_MAX_TX_QUEUE_GROUPS + * These TLVs may appear in an arbitrary order. Any number of these TLVs + * may be appended to the VER_REQ message (but only one TLV of each type). + * + * Header fields: + * - MSG_TYPE + * Bits 7:0 + * Purpose: identifies this as a version number request message + * Value: 0x0 + */ + +#define HTT_VER_REQ_BYTES 4 + +/* TBDXXX: figure out a reasonable number */ +#define HTT_HL_DATA_SVC_PIPE_DEPTH 24 +#define HTT_LL_DATA_SVC_PIPE_DEPTH 64 + +/** + * @brief HTT tx MSDU descriptor + * + * @details + * The HTT tx MSDU descriptor is created by the host HTT SW for each + * tx MSDU. The HTT tx MSDU descriptor contains the information that + * the target firmware needs for the FW's tx processing, particularly + * for creating the HW msdu descriptor. + * The same HTT tx descriptor is used for HL and LL systems, though + * a few fields within the tx descriptor are used only by LL or + * only by HL. + * The HTT tx descriptor is defined in two manners: by a struct with + * bitfields, and by a series of [dword offset, bit mask, bit shift] + * definitions. + * The target should use the struct def, for simplicitly and clarity, + * but the host shall use the bit-mast + bit-shift defs, to be endian- + * neutral. Specifically, the host shall use the get/set macros built + * around the mask + shift defs. + */ +#define HTT_TX_MSDU_DESC_RAW_SUBTYPE_80211_HDR_S 0 +#define HTT_TX_MSDU_DESC_RAW_SUBTYPE_80211_HDR_M 0x1 +#define HTT_TX_MSDU_DESC_RAW_SUBTYPE_NO_AGGR_S 1 +#define HTT_TX_MSDU_DESC_RAW_SUBTYPE_NO_AGGR_M 0x2 +#define HTT_TX_MSDU_DESC_RAW_SUBTYPE_NO_ENCRYPT_S 2 +#define HTT_TX_MSDU_DESC_RAW_SUBTYPE_NO_ENCRYPT_M 0x4 +#define HTT_TX_MSDU_DESC_RAW_SUBTYPE_NO_CLASSIFY_S 3 +#define HTT_TX_MSDU_DESC_RAW_SUBTYPE_NO_CLASSIFY_M 0x8 + +#define HTT_TX_VDEV_ID_WORD 0 +#define HTT_TX_VDEV_ID_MASK 0x3f +#define HTT_TX_VDEV_ID_SHIFT 16 + +#define HTT_TX_L3_CKSUM_OFFLOAD 1 +#define HTT_TX_L4_CKSUM_OFFLOAD 2 + +#define HTT_TX_MSDU_LEN_DWORD 1 +#define HTT_TX_MSDU_LEN_MASK 0xffff; + +/* + * HTT_VAR_PADDR macros + * Allow physical / bus addresses to be either a single 32-bit value, + * or a 64-bit value, stored as a little-endian lo,hi pair of 32-bit parts + */ + +/* + * Note that in this macro A_UINT32 has been converted to + * uint32_t only to address checkpath errors caused by declaring + * var_name as A_UINT32. + */ +#define HTT_VAR_PADDR32(var_name) uint32_t (var_name) + +#define HTT_VAR_PADDR64_LE(var_name) \ + struct { \ + /* little-endian: lo precedes hi */ \ + A_UINT32 lo; \ + A_UINT32 hi; \ + } var_name + +/* + * TEMPLATE_HTT_TX_MSDU_DESC_T: + * This macro defines a htt_tx_msdu_descXXX_t in which any physical + * addresses are stored in a XXX-bit field. + * This macro is used to define both htt_tx_msdu_desc32_t and + * htt_tx_msdu_desc64_t structs. + */ +#define TEMPLATE_HTT_TX_MSDU_DESC_T(_paddr_bits_, _paddr__frags_desc_ptr_) \ +PREPACK struct htt_tx_msdu_desc ## _paddr_bits_ ## _t \ +{ \ + /* DWORD 0: flags and meta-data */ \ + A_UINT32 \ + msg_type:8, /* HTT_H2T_MSG_TYPE_TX_FRM */ \ + \ + /* pkt_subtype - \ + * Detailed specification of the tx frame contents, extending the \ + * general specification provided by pkt_type. \ + * FIX THIS: ADD COMPLETE SPECS FOR THIS FIELDS VALUE, e.g. \ + *pkt_type | pkt_subtype \ + *============================================================== \ + *802.3 | bit 0:3 - Reserved \ + * | bit 4: 0x0 - Copy-Engine Classification Results \ + * | not appended to the HTT message \ + * | 0x1 - Copy-Engine Classification Results \ + * | appended to the HTT message in the \ + * | format: \ + * | [HTT tx desc, frame header, \ + * | CE classification results] \ + * | The CE classification results begin \ + * | at the next 4-byte boundary after \ + * | the frame header. \ + *------------+------------------------------------------------- \ + *Eth2 | bit 0:3 - Reserved \ + * | bit 4: 0x0 - Copy-Engine Classification Results \ + * | not appended to the HTT message \ + * | 0x1 - Copy-Engine Classification Results \ + * | appended to the HTT message. \ + * | See the above specification of the \ + * | CE classification results location. \ + *------------+------------------------------------------------- \ + *native WiFi | bit 0:3 - Reserved \ + * | bit 4: 0x0 - Copy-Engine Classification Results \ + * | not appended to the HTT message \ + * | 0x1 - Copy-Engine Classification Results \ + * | appended to the HTT message. \ + * | See the above specification of the \ + * | CE classification results location. \ + *------------+------------------------------------------------- \ + *mgmt | 0x0 - 802.11 MAC header absent \ + * | 0x1 - 802.11 MAC header present \ + *------------+------------------------------------------------- \ + *raw | bit 0: 0x0 - 802.11 MAC header absent \ + * | 0x1 - 802.11 MAC header present \ + * | bit 1: 0x0 - allow aggregation \ + * | 0x1 - don't allow aggregation \ + * | bit 2: 0x0 - perform encryption \ + * | 0x1 - don't perform encryption \ + * | bit 3: 0x0 - perform tx classification / queuing \ + * | 0x1 - don't perform tx classification; \ + * | insert the frame into the "misc" \ + * | tx queue \ + * | bit 4: 0x0 - Copy-Engine Classification Results \ + * | not appended to the HTT message \ + * | 0x1 - Copy-Engine Classification Results \ + * | appended to the HTT message. \ + * | See the above specification of the \ + * | CE classification results location. \ + */ \ + pkt_subtype:5, \ + \ + /* pkt_type - \ + * General specification of the tx frame contents. \ + * The htt_pkt_type enum should be used to specify \ + * and check the value of this field. \ + */ \ + pkt_type:3, \ + \ + /* vdev_id - \ + * ID for the vdev that is sending this tx frame. \ + * For certain non-standard packet types, e.g. pkt_type == raw \ + * and (pkt_subtype >> 3) == 1, this field is not relevant/valid. \ + * This field is used primarily for determining where to queue \ + * broadcast and multicast frames. \ + */ \ + vdev_id:6, \ + /* ext_tid - \ + * The extended traffic ID. \ + * If the TID is unknown, the extended TID is set to \ + * HTT_TX_EXT_TID_INVALID. \ + * If the tx frame is QoS data, then the extended TID has the 0-15 \ + * value of the QoS TID. \ + * If the tx frame is non-QoS data, then the extended TID is set to \ + * HTT_TX_EXT_TID_NON_QOS. \ + * If the tx frame is multicast or broadcast, then the extended TID \ + * is set to HTT_TX_EXT_TID_MCAST_BCAST. \ + */ \ + ext_tid:5, \ + \ + /* postponed - \ + * This flag indicates whether the tx frame has been downloaded to \ + * the target before but discarded by the target, and now is being \ + * downloaded again; or if this is a new frame that is being \ + * downloaded for the first time. \ + * This flag allows the target to determine the correct order for \ + * transmitting new vs. old frames. \ + * value: 0 -> new frame, 1 -> re-send of a previously + * sent frame \ + * This flag only applies to HL systems, since in LL systems, \ + * the tx flow control is handled entirely within the target. \ + */ \ + postponed:1, \ + \ + /* extension - \ + * This flag indicates whether a HTT tx MSDU extension descriptor\ + * (htt_tx_msdu_desc_ext_t) follows this HTT tx MSDU descriptor.\ + * \ + * 0x0 - no extension MSDU descriptor is present \ + * 0x1 - an extension MSDU descriptor immediately follows the \ + * regular MSDU descriptor \ + */ \ + extension:1, \ + \ + /* cksum_offload - \ + * This flag indicates whether checksum offload is enabled or not \ + * for this frame. Target FW use this flag to turn on HW checksumming \ + * 0x0 - No checksum offload \ + * 0x1 - L3 header checksum only \ + * 0x2 - L4 checksum only \ + * 0x3 - L3 header checksum + L4 checksum \ + */ \ + cksum_offload:2, \ + \ + /* tx_comp_req - \ + * This flag indicates whether Tx Completion \ + * from fw is required or not. \ + * This flag is only relevant if tx completion is not \ + * universally enabled. \ + * For all LL systems, tx completion is mandatory, \ + * so this flag will be irrelevant. \ + * For HL systems tx completion is optional, but HL systems in which \ + * the bus throughput exceeds the WLAN throughput will \ + * probably want to always use tx completion, and thus \ + * would not check this flag. \ + * This flag is required when tx completions are not used universally, \ + * but are still required for certain tx frames for which \ + * an OTA delivery acknowledgment is needed by the host. \ + * In practice, this would be for HL systems in which the \ + * bus throughput is less than the WLAN throughput. \ + * \ + * 0x0 - Tx Completion Indication from Fw not required \ + * 0x1 - Tx Completion Indication from Fw is required \ + */ \ + tx_compl_req:1; \ + \ + \ + /* DWORD 1: MSDU length and ID */ \ + A_UINT32 \ + len:16, /* MSDU length, in bytes */ \ + id:16; /* MSDU ID used to identify the MSDU to the host, \ + * and this id is used to calculate fragmentation \ + * descriptor pointer inside the target based on \ + * the base address, configured inside the target. \ + */ \ + \ + /* DWORD 2 (or 2-3): fragmentation descriptor bus address */ \ + /* frags_desc_ptr - \ + * The fragmentation descriptor pointer tells the HW's MAC DMA \ + * where the tx frame's fragments reside in memory. \ + * This field only applies to LL systems, since in HL systems the \ + * (degenerate single-fragment) fragmentation descriptor is created \ + * within the target. \ + */ \ + _paddr__frags_desc_ptr_; \ + \ + /* DWORD 3 (or 4): peerid, chanfreq */ \ + /* \ + * Peer ID : Target can use this value to know which peer-id packet \ + * destined to. \ + * It's intended to be specified by host in case of NAWDS. \ + */ \ + A_UINT16 peerid; \ + \ + /* \ + * Channel frequency: This identifies the desired channel \ + * frequency (in mhz) for tx frames. This is used by FW to help \ + * determine when it is safe to transmit or drop frames for \ + * off-channel operation. \ + * The default value of zero indicates to FW that the \ + * corresponding VDEV's home channel (if there is one) is \ + * the desired channel frequency. \ + */ \ + A_UINT16 chanfreq; \ + \ + /* Reason reserved is commented is increasing the htt + * structure size leads to some wierd issues. + * A_UINT32 reserved_dword3_bits0_31; \ + */ \ +} POSTPACK +/* define a htt_tx_msdu_desc32_t type */ +TEMPLATE_HTT_TX_MSDU_DESC_T(32, HTT_VAR_PADDR32(frags_desc_ptr)); +/* define a htt_tx_msdu_desc64_t type */ +TEMPLATE_HTT_TX_MSDU_DESC_T(64, HTT_VAR_PADDR64_LE(frags_desc_ptr)); +/* + * Make htt_tx_msdu_desc_t be an alias for either + * htt_tx_msdu_desc32_t or htt_tx_msdu_desc64_t + */ +#if HTT_PADDR64 +#define htt_tx_msdu_desc_t htt_tx_msdu_desc64_t +#else +#define htt_tx_msdu_desc_t htt_tx_msdu_desc32_t +#endif + +/* decriptor information for Management frame*/ +/* + * THIS htt_mgmt_tx_desc_t STRUCT IS DEPRECATED - DON'T USE IT. + * BOTH MANAGEMENT AND DATA FRAMES SHOULD USE htt_tx_msdu_desc_t. + */ +#define HTT_MGMT_FRM_HDR_DOWNLOAD_LEN 32 +extern A_UINT32 mgmt_hdr_len; +PREPACK struct htt_mgmt_tx_desc_t { + A_UINT32 msg_type; +#if HTT_PADDR64 + A_UINT64 frag_paddr; /* DMAble address of the data */ +#else + A_UINT32 frag_paddr; /* DMAble address of the data */ +#endif + A_UINT32 desc_id; /* returned to host during completion + * to free the meory*/ + A_UINT32 len; /* Fragment length */ + A_UINT32 vdev_id; /* virtual device ID */ + A_UINT8 hdr[HTT_MGMT_FRM_HDR_DOWNLOAD_LEN]; /* frm header */ +} POSTPACK; + +PREPACK struct htt_mgmt_tx_compl_ind { + A_UINT32 desc_id; + A_UINT32 status; +} POSTPACK; + +/* + * This SDU header size comes from the summation of the following: + * 1. Max of: + * a. Native WiFi header, for native WiFi frames: 24 bytes + * (frame control, duration / ID, addr1, addr2, addr3, seq ctrl, addr4) + * b. 802.11 header, for raw frames: 36 bytes + * (frame control, duration / ID, addr1, addr2, addr3, seq ctrl, addr4, + * QoS header, HT header) + * c. 802.3 header, for ethernet frames: 14 bytes + * (destination address, source address, ethertype / length) + * 2. Max of: + * a. IPv4 header, up through the DiffServ Code Point: 2 bytes + * b. IPv6 header, up through the Traffic Class: 2 bytes + * 3. 802.1Q VLAN header: 4 bytes + * 4. LLC/SNAP header: 8 bytes + */ +#define HTT_TX_HDR_SIZE_NATIVE_WIFI 30 +#define HTT_TX_HDR_SIZE_802_11_RAW 36 +#define HTT_TX_HDR_SIZE_ETHERNET 14 + +#define HTT_TX_HDR_SIZE_OUTER_HDR_MAX HTT_TX_HDR_SIZE_802_11_RAW +A_COMPILE_TIME_ASSERT(htt_encap_hdr_size_max_check_nwifi, + HTT_TX_HDR_SIZE_OUTER_HDR_MAX >= + HTT_TX_HDR_SIZE_NATIVE_WIFI); +A_COMPILE_TIME_ASSERT(htt_encap_hdr_size_max_check_enet, + HTT_TX_HDR_SIZE_OUTER_HDR_MAX >= + HTT_TX_HDR_SIZE_ETHERNET); + +#define HTT_HL_TX_HDR_SIZE_IP 1600 /* also include payload */ +#define HTT_LL_TX_HDR_SIZE_IP 16 /* up to the end of UDP header for IPv4 case */ + +#define HTT_TX_HDR_SIZE_802_1Q 4 +#define HTT_TX_HDR_SIZE_LLC_SNAP 8 + + +#define HTT_COMMON_TX_FRM_HDR_LEN \ + (HTT_TX_HDR_SIZE_OUTER_HDR_MAX + \ + HTT_TX_HDR_SIZE_802_1Q + \ + HTT_TX_HDR_SIZE_LLC_SNAP) + +#define HTT_HL_TX_FRM_HDR_LEN \ + (HTT_COMMON_TX_FRM_HDR_LEN + HTT_HL_TX_HDR_SIZE_IP) + +#define HTT_LL_TX_FRM_HDR_LEN \ + (HTT_COMMON_TX_FRM_HDR_LEN + HTT_LL_TX_HDR_SIZE_IP) + +#define HTT_TX_DESC_LEN sizeof(struct htt_tx_msdu_desc_t) + +/* dword 0 */ +#define HTT_TX_DESC_PKT_SUBTYPE_OFFSET_BYTES 0 +#define HTT_TX_DESC_PKT_SUBTYPE_OFFSET_DWORD 0 +#define HTT_TX_DESC_PKT_SUBTYPE_M 0x00001f00 +#define HTT_TX_DESC_PKT_SUBTYPE_S 8 + +#define HTT_TX_DESC_NO_ENCRYPT_OFFSET_BYTES 0 +#define HTT_TX_DESC_NO_ENCRYPT_OFFSET_DWORD 0 +#define HTT_TX_DESC_NO_ENCRYPT_M 0x00000400 +#define HTT_TX_DESC_NO_ENCRYPT_S 10 + +#define HTT_TX_DESC_PKT_TYPE_OFFSET_BYTES 0 +#define HTT_TX_DESC_PKT_TYPE_OFFSET_DWORD 0 +#define HTT_TX_DESC_PKT_TYPE_M 0x0000e000 +#define HTT_TX_DESC_PKT_TYPE_S 13 + +#define HTT_TX_DESC_VDEV_ID_OFFSET_BYTES 0 +#define HTT_TX_DESC_VDEV_ID_OFFSET_DWORD 0 +#define HTT_TX_DESC_VDEV_ID_M 0x003f0000 +#define HTT_TX_DESC_VDEV_ID_S 16 + +#define HTT_TX_DESC_EXT_TID_OFFSET_BYTES 0 +#define HTT_TX_DESC_EXT_TID_OFFSET_DWORD 0 +#define HTT_TX_DESC_EXT_TID_M 0x07c00000 +#define HTT_TX_DESC_EXT_TID_S 22 + +#define HTT_TX_DESC_POSTPONED_OFFSET_BYTES 0 +#define HTT_TX_DESC_POSTPONED_OFFSET_DWORD 0 +#define HTT_TX_DESC_POSTPONED_M 0x08000000 +#define HTT_TX_DESC_POSTPONED_S 27 + +#define HTT_TX_DESC_EXTENSION_OFFSET_BYTE 0 +#define HTT_TX_DESC_EXTENSION_OFFSET_DWORD 0 +#define HTT_TX_DESC_EXTENSION_M 0x10000000 +#define HTT_TX_DESC_EXTENSION_S 28 + +#define HTT_TX_DESC_CKSUM_OFFLOAD_OFFSET_BYTES 0 +#define HTT_TX_DESC_CKSUM_OFFLOAD_OFFSET_DWORD 0 +#define HTT_TX_DESC_CKSUM_OFFLOAD_M 0x60000000 +#define HTT_TX_DESC_CKSUM_OFFLOAD_S 29 + +#define HTT_TX_DESC_TX_COMP_OFFSET_BYTES 0 +#define HTT_TX_DESC_TX_COMP_OFFSET_DWORD 0 +#define HTT_TX_DESC_TX_COMP_M 0x80000000 +#define HTT_TX_DESC_TX_COMP_S 31 + +/* dword 1 */ +#define HTT_TX_DESC_FRM_LEN_OFFSET_BYTES 4 +#define HTT_TX_DESC_FRM_LEN_OFFSET_DWORD 1 +#define HTT_TX_DESC_FRM_LEN_M 0x0000ffff +#define HTT_TX_DESC_FRM_LEN_S 0 + +#define HTT_TX_DESC_FRM_ID_OFFSET_BYTES 4 +#define HTT_TX_DESC_FRM_ID_OFFSET_DWORD 1 +#define HTT_TX_DESC_FRM_ID_M 0xffff0000 +#define HTT_TX_DESC_FRM_ID_S 16 + +/* dword 2 */ +#define HTT_TX_DESC_FRAGS_DESC_PADDR_OFFSET_BYTES 8 +#define HTT_TX_DESC_FRAGS_DESC_PADDR_OFFSET_DWORD 2 +/* for systems using 64-bit format for bus addresses */ +#define HTT_TX_DESC_FRAGS_DESC_PADDR_HI_M 0xffffffff +#define HTT_TX_DESC_FRAGS_DESC_PADDR_HI_S 0 +#define HTT_TX_DESC_FRAGS_DESC_PADDR_LO_M 0xffffffff +#define HTT_TX_DESC_FRAGS_DESC_PADDR_LO_S 0 +/* for systems using 32-bit format for bus addresses */ +#define HTT_TX_DESC_FRAGS_DESC_PADDR_M 0xffffffff +#define HTT_TX_DESC_FRAGS_DESC_PADDR_S 0 + +/* dword 3 */ +#define HTT_TX_DESC_PEER_ID_OFFSET_BYTES_64 16 +#define HTT_TX_DESC_PEER_ID_OFFSET_BYTES_32 12 +#define HTT_TX_DESC_PEER_ID_OFFSET_DWORD_64 \ + (HTT_TX_DESC_PEER_ID_OFFSET_BYTES_64 >> 2) +#define HTT_TX_DESC_PEER_ID_OFFSET_DWORD_32 \ + (HTT_TX_DESC_PEER_ID_OFFSET_BYTES_32 >> 2) + +#if HTT_PADDR64 +#define HTT_TX_DESC_PEER_ID_OFFSET_BYTES HTT_TX_DESC_PEER_ID_OFFSET_BYTES_64 +#define HTT_TX_DESC_PEER_ID_OFFSET_DWORD HTT_TX_DESC_PEER_ID_OFFSET_DWORD_64 +#else +#define HTT_TX_DESC_PEER_ID_OFFSET_BYTES HTT_TX_DESC_PEER_ID_OFFSET_BYTES_32 +#define HTT_TX_DESC_PEER_ID_OFFSET_DWORD HTT_TX_DESC_PEER_ID_OFFSET_DWORD_32 +#endif + +#define HTT_TX_DESC_PEER_ID_M 0x0000ffff +#define HTT_TX_DESC_PEER_ID_S 0 +/* + * TEMPORARY: + * The original definitions for the PEER_ID fields contained typos + * (with _DESC_PADDR appended to this PEER_ID field name). + * Retain deprecated original names for PEER_ID fields until all code that + * refers to them has been updated. + */ +#define HTT_TX_DESC_PEERID_DESC_PADDR_OFFSET_BYTES \ + HTT_TX_DESC_PEER_ID_OFFSET_BYTES +#define HTT_TX_DESC_PEERID_DESC_PADDR_OFFSET_DWORD \ + HTT_TX_DESC_PEER_ID_OFFSET_DWORD +#define HTT_TX_DESC_PEERID_DESC_PADDR_M \ + HTT_TX_DESC_PEER_ID_M +#define HTT_TX_DESC_PEERID_DESC_PADDR_S \ + HTT_TX_DESC_PEER_ID_S + +#define HTT_TX_DESC_CHAN_FREQ_OFFSET_BYTES_64 16 /* to dword with chan freq */ +#define HTT_TX_DESC_CHAN_FREQ_OFFSET_BYTES_32 12 /* to dword with chan freq */ +#define HTT_TX_DESC_CHAN_FREQ_OFFSET_DWORD_64 \ + (HTT_TX_DESC_CHAN_FREQ_OFFSET_BYTES_64 >> 2) +#define HTT_TX_DESC_CHAN_FREQ_OFFSET_DWORD_32 \ + (HTT_TX_DESC_CHAN_FREQ_OFFSET_BYTES_32 >> 2) + +#if HTT_PADDR64 +#define HTT_TX_DESC_CHAN_FREQ_OFFSET_BYTES HTT_TX_DESC_CHAN_FREQ_OFFSET_BYTES_64 +#define HTT_TX_DESC_CHAN_FREQ_OFFSET_DWORD HTT_TX_DESC_CHAN_FREQ_OFFSET_DWORD_64 +#else +#define HTT_TX_DESC_CHAN_FREQ_OFFSET_BYTES HTT_TX_DESC_CHAN_FREQ_OFFSET_BYTES_32 +#define HTT_TX_DESC_CHAN_FREQ_OFFSET_DWORD HTT_TX_DESC_CHAN_FREQ_OFFSET_DWORD_32 +#endif + +#define HTT_TX_DESC_CHAN_FREQ_M 0xffff0000 +#define HTT_TX_DESC_CHAN_FREQ_S 16 + +#define HTT_TX_DESC_PKT_SUBTYPE_GET(_var) \ + (((_var) & HTT_TX_DESC_PKT_SUBTYPE_M) >> HTT_TX_DESC_PKT_SUBTYPE_S) +#define HTT_TX_DESC_PKT_SUBTYPE_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_TX_DESC_PKT_SUBTYPE, _val); \ + ((_var) |= ((_val) << HTT_TX_DESC_PKT_SUBTYPE_S)); \ + } while (0) + +#define HTT_TX_DESC_NO_ENCRYPT_GET(_var) \ + (((_var) & HTT_TX_DESC_NO_ENCRYPT_M) >> HTT_TX_DESC_NO_ENCRYPT_S) +#define HTT_TX_DESC_NO_ENCRYPT_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_TX_DESC_NO_ENCRYPT, _val); \ + ((_var) |= ((_val) << HTT_TX_DESC_NO_ENCRYPT_S)); \ + } while (0) + +#define HTT_TX_DESC_PKT_TYPE_GET(_var) \ + (((_var) & HTT_TX_DESC_PKT_TYPE_M) >> HTT_TX_DESC_PKT_TYPE_S) +#define HTT_TX_DESC_PKT_TYPE_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_TX_DESC_PKT_TYPE, _val); \ + ((_var) |= ((_val) << HTT_TX_DESC_PKT_TYPE_S)); \ + } while (0) + +#define HTT_TX_DESC_VDEV_ID_GET(_var) \ + (((_var) & HTT_TX_DESC_VDEV_ID_M) >> HTT_TX_DESC_VDEV_ID_S) +#define HTT_TX_DESC_VDEV_ID_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_TX_DESC_VDEV_ID, _val); \ + ((_var) |= ((_val) << HTT_TX_DESC_VDEV_ID_S)); \ + } while (0) + +#define HTT_TX_DESC_EXT_TID_GET(_var) \ + (((_var) & HTT_TX_DESC_EXT_TID_M) >> HTT_TX_DESC_EXT_TID_S) +#define HTT_TX_DESC_EXT_TID_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_TX_DESC_EXT_TID, _val); \ + ((_var) |= ((_val) << HTT_TX_DESC_EXT_TID_S)); \ + } while (0) + +#define HTT_TX_DESC_POSTPONED_GET(_var) \ + (((_var) & HTT_TX_DESC_POSTPONED_M) >> HTT_TX_DESC_POSTPONED_S) +#define HTT_TX_DESC_POSTPONED_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_TX_DESC_POSTPONED, _val); \ + ((_var) |= ((_val) << HTT_TX_DESC_POSTPONED_S)); \ + } while (0) + +#define HTT_TX_DESC_EXTENSION_GET(_var) \ + (((_var) & HTT_TX_DESC_EXTENSION_M) >> HTT_TX_DESC_EXTENSION_S) +#define HTT_TX_DESC_EXTENSION_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_TX_DESC_EXTENSION, _val); \ + ((_var) |= ((_val) << HTT_TX_DESC_EXTENSION_S)); \ + } while (0) + +#define HTT_TX_DESC_FRM_LEN_GET(_var) \ + (((_var) & HTT_TX_DESC_FRM_LEN_M) >> HTT_TX_DESC_FRM_LEN_S) +#define HTT_TX_DESC_FRM_LEN_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_TX_DESC_FRM_LEN, _val); \ + ((_var) |= ((_val) << HTT_TX_DESC_FRM_LEN_S)); \ + } while (0) + +#define HTT_TX_DESC_FRM_ID_GET(_var) \ + (((_var) & HTT_TX_DESC_FRM_ID_M) >> HTT_TX_DESC_FRM_ID_S) +#define HTT_TX_DESC_FRM_ID_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_TX_DESC_FRM_ID, _val); \ + ((_var) |= ((_val) << HTT_TX_DESC_FRM_ID_S)); \ + } while (0) + +#define HTT_TX_DESC_CKSUM_OFFLOAD_GET(_var) \ + (((_var) & HTT_TX_DESC_CKSUM_OFFLOAD_M) >> HTT_TX_DESC_CKSUM_OFFLOAD_S) +#define HTT_TX_DESC_CKSUM_OFFLOAD_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_TX_DESC_CKSUM_OFFLOAD, _val); \ + ((_var) |= ((_val) << HTT_TX_DESC_CKSUM_OFFLOAD_S)); \ + } while (0) + +#define HTT_TX_DESC_TX_COMP_GET(_var) \ + (((_var) & HTT_TX_DESC_TX_COMP_M) >> HTT_TX_DESC_TX_COMP_S) +#define HTT_TX_DESC_TX_COMP_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_TX_DESC_TX_COMP, _val); \ + ((_var) |= ((_val) << HTT_TX_DESC_TX_COMP_S)); \ + } while (0) + +#define HTT_TX_DESC_PEER_ID_GET(_var) \ + (((_var) & HTT_TX_DESC_PEER_ID_M) >> HTT_TX_DESC_PEER_ID_S) +#define HTT_TX_DESC_PEER_ID_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_TX_DESC_PEER_ID, _val); \ + ((_var) |= ((_val) << HTT_TX_DESC_PEER_ID_S)); \ + } while (0) + +#define HTT_TX_DESC_CHAN_FREQ_GET(_var) \ + (((_var) & HTT_TX_DESC_CHAN_FREQ_M) >> HTT_TX_DESC_CHAN_FREQ_S) +#define HTT_TX_DESC_CHAN_FREQ_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_TX_DESC_CHAN_FREQ, _val); \ + ((_var) |= ((_val) << HTT_TX_DESC_CHAN_FREQ_S)); \ + } while (0) + + +/* enums used in the HTT tx MSDU extension descriptor */ +enum { + htt_tx_guard_interval_regular = 0, + htt_tx_guard_interval_short = 1, +}; + +enum { + htt_tx_preamble_type_ofdm = 0, + htt_tx_preamble_type_cck = 1, + htt_tx_preamble_type_ht = 2, + htt_tx_preamble_type_vht = 3, +}; + +enum { + htt_tx_bandwidth_5MHz = 0, + htt_tx_bandwidth_10MHz = 1, + htt_tx_bandwidth_20MHz = 2, + htt_tx_bandwidth_40MHz = 3, + htt_tx_bandwidth_80MHz = 4, + htt_tx_bandwidth_160MHz = 5, /* includes 80+80 */ +}; + +/** + * @brief HTT tx MSDU extension descriptor + * @details + * If the target supports HTT tx MSDU extension descriptors, the host has + * the option of appending the following struct following the regular + * HTT tx MSDU descriptor (and setting the "extension" flag in the regular + * HTT tx MSDU descriptor, to show that the extension descriptor is present). + * The HTT tx MSDU extension descriptors allows the host to provide detailed + * tx specs for each frame. + */ +PREPACK struct htt_tx_msdu_desc_ext_t { + /* DWORD 0: flags */ + A_UINT32 valid_pwr:1,/* bit 0:if set, tx pwr spec is valid */ + valid_mcs_mask:1,/* bit 1:if set, tx MCS mask spec is valid */ + valid_nss_mask:1,/* bit 2:if set, tx Nss mask spec is valid */ + valid_guard_interval:1,/* bit 3:if set, tx guard intv spec is valid */ + valid_preamble_type_mask:1,/* 4:if set, tx preamble mask is valid */ + valid_chainmask:1,/* bit 5:if set, tx chainmask spec is valid */ + valid_retries:1,/* bit 6:if set, tx retries spec is valid */ + valid_bandwidth:1,/* bit 7:if set, tx bandwidth spec is valid */ + valid_expire_tsf:1,/* bit 8:if set, tx expire TSF spec is valid */ + is_dsrc:1, /* bit 9:if set, MSDU is a DSRC frame */ + reserved0_31_7:22; /* bits 31:10 - unused, set to 0x0 */ + + /* DWORD 1:tx power, tx rate, tx BW */ + A_UINT32 + /* pwr - + * Specify what power the tx frame needs to be transmitted at. + * The power a signed (two's complement) value is in units of 0.5 dBm. + * The value needs to be appropriately sign-extended when extracting + * the value from the message and storing it in a variable that is + * larger than A_INT8. (The HTT_TX_MSDU_EXT_DESC_FLAG_PWR_GET macro + * automatically handles this sign-extension.) + * If the transmission uses multiple tx chains, this power spec is + * the total transmit power, assuming incoherent combination of + * per-chain power to produce the total power. + */ + pwr:8, + /* mcs_mask - + * Specify the allowable values for MCS index (modulation and coding) + * to use for transmitting the frame. + * + * For HT / VHT preamble types, this mask directly corresponds to + * the HT or VHT MCS indices that are allowed. For each bit N set + * within the mask, MCS index N is allowed for transmitting the frame. + * For legacy CCK and OFDM rates, separate bits are provided for CCK + * rates versus OFDM rates, so the host has the option of specifying + * that the target must transmit the frame with CCK or OFDM rates + * (not HT or VHT), but leaving the decision to the target whether + * to use CCK or OFDM. + * + * For CCK and OFDM, the bits within this mask are interpreted as + * follows: + * bit 0 -> CCK 1 Mbps rate is allowed + * bit 1 -> CCK 2 Mbps rate is allowed + * bit 2 -> CCK 5.5 Mbps rate is allowed + * bit 3 -> CCK 11 Mbps rate is allowed + * bit 4 -> OFDM BPSK modulation, 1/2 coding rate is allowed + * bit 5 -> OFDM BPSK modulation, 3/4 coding rate is allowed + * bit 6 -> OFDM QPSK modulation, 1/2 coding rate is allowed + * bit 7 -> OFDM QPSK modulation, 3/4 coding rate is allowed + * bit 8 -> OFDM 16-QAM modulation, 1/2 coding rate is allowed + * bit 9 -> OFDM 16-QAM modulation, 3/4 coding rate is allowed + * bit 10 -> OFDM 64-QAM modulation, 2/3 coding rate is allowed + * bit 11 -> OFDM 64-QAM modulation, 3/4 coding rate is allowed + * + * The MCS index specification needs to be compatible with the + * bandwidth mask specification. For example, a MCS index == 9 + * specification is inconsistent with a preamble type == VHT, + * Nss == 1, and channel bandwidth == 20 MHz. + * + * Furthermore, the host has only a limited ability to specify to + * the target to select from HT + legacy rates, or VHT + legacy rates, + * since this mcs_mask can specify either HT/VHT rates or legacy rates. + */ + mcs_mask:12, + /* nss_mask - + * Specify which numbers of spatial streams (MIMO factor) are permitted. + * Each bit in this mask corresponds to a Nss value: + * bit 0: if set, Nss = 1 (non-MIMO) is permitted + * bit 1: if set, Nss = 2 (2x2 MIMO) is permitted + * bit 2: if set, Nss = 3 (3x3 MIMO) is permitted + * bit 3: if set, Nss = 4 (4x4 MIMO) is permitted + * The values in the Nss mask must be suitable for the recipient, e.g. + * a value of 0x4 (Nss = 3) cannot be specified for a tx frame to a + * recipient which only supports 2x2 MIMO. + */ + nss_mask:4, + /* guard_interval - + * Specify a htt_tx_guard_interval enum value to indicate whether + * the transmission should use a regular guard interval or a + * short guard interval. + */ + guard_interval:1, + /* preamble_type_mask - + * Specify which preamble types (CCK, OFDM, HT, VHT) the target + * may choose from for transmitting this frame. + * The bits in this mask correspond to the values in the + * htt_tx_preamble_type enum. For example, to allow the target + * to transmit the frame as either CCK or OFDM, this field would + * be set to + * (1 << htt_tx_preamble_type_ofdm) | + * (1 << htt_tx_preamble_type_cck) + */ + preamble_type_mask:4, + + reserved1_31_29:3; /* unused, set to 0x0 */ + + /* DWORD 2: tx chain mask, tx retries */ + A_UINT32 + /* chain_mask - specify which chains to transmit from */ + chain_mask:4, + /* retry_limit - + * Specify the maximum number of transmissions, including the + * initial transmission, to attempt before giving up if no ack + * is received. + * If the tx rate is specified, then all retries shall use the + * same rate as the initial transmission. + * If no tx rate is specified, the target can choose whether to + * retain the original rate during the retransmissions, or to + * fall back to a more robust rate. + */ + retry_limit:4, + + /* bandwidth_mask - + * Specify what channel widths may be used for the transmission. + * A value of zero indicates "don't care" - the target may choose + * the transmission bandwidth. + * The bits within this mask correspond to the htt_tx_bandwidth + * enum values - bit 0 is for 5 MHz, bit 1 is for 10 MHz, etc. + * The bandwidth_mask must be consistent with the + * preamble_type_mask * and mcs_mask specs, if they are + * provided. For example, + * 80 MHz and 160 MHz can only be enabled in the mask + * if preamble_type == VHT. + */ + bandwidth_mask:6, + + reserved2_31_14:18; /* unused, set to 0x0 */ + + /* DWORD 3: tx expiry time (TSF) LSBs */ + A_UINT32 expire_tsf_lo; + + /* DWORD 4: tx expiry time (TSF) MSBs */ + A_UINT32 expire_tsf_hi; + + A_UINT32 reserved_for_future_expansion_set_to_zero[3]; +} POSTPACK; + +/* DWORD 0 */ +#define HTT_TX_MSDU_EXT_DESC_FLAG_VALID_PWR_M 0x00000001 +#define HTT_TX_MSDU_EXT_DESC_FLAG_VALID_PWR_S 0 +#define HTT_TX_MSDU_EXT_DESC_FLAG_VALID_MCS_MASK_M 0x00000002 +#define HTT_TX_MSDU_EXT_DESC_FLAG_VALID_MCS_MASK_S 1 +#define HTT_TX_MSDU_EXT_DESC_FLAG_VALID_NSS_MASK_M 0x00000004 +#define HTT_TX_MSDU_EXT_DESC_FLAG_VALID_NSS_MASK_S 2 +#define HTT_TX_MSDU_EXT_DESC_FLAG_VALID_GUARD_INTERVAL_M 0x00000008 +#define HTT_TX_MSDU_EXT_DESC_FLAG_VALID_GUARD_INTERVAL_S 3 +#define HTT_TX_MSDU_EXT_DESC_FLAG_VALID_PREAMBLE_TYPE_MASK_M 0x00000010 +#define HTT_TX_MSDU_EXT_DESC_FLAG_VALID_PREAMBLE_TYPE_MASK_S 4 +#define HTT_TX_MSDU_EXT_DESC_FLAG_VALID_CHAIN_MASK_M 0x00000020 +#define HTT_TX_MSDU_EXT_DESC_FLAG_VALID_CHAIN_MASK_S 5 +#define HTT_TX_MSDU_EXT_DESC_FLAG_VALID_RETRIES_M 0x00000040 +#define HTT_TX_MSDU_EXT_DESC_FLAG_VALID_RETRIES_S 6 +#define HTT_TX_MSDU_EXT_DESC_FLAG_VALID_BANDWIDTH_M 0x00000080 +#define HTT_TX_MSDU_EXT_DESC_FLAG_VALID_BANDWIDTH_S 7 +#define HTT_TX_MSDU_EXT_DESC_FLAG_VALID_EXPIRE_TIME_M 0x00000100 +#define HTT_TX_MSDU_EXT_DESC_FLAG_VALID_EXPIRE_TIME_S 8 +#define HTT_TX_MSDU_EXT_DESC_FLAG_IS_DSRC_M 0x00000200 +#define HTT_TX_MSDU_EXT_DESC_FLAG_IS_DSRC_S 9 + +/* DWORD 1 */ +#define HTT_TX_MSDU_EXT_DESC_PWR_M 0x000000ff +#define HTT_TX_MSDU_EXT_DESC_PWR_S 0 +#define HTT_TX_MSDU_EXT_DESC_MCS_MASK_M 0x000fff00 +#define HTT_TX_MSDU_EXT_DESC_MCS_MASK_S 8 +#define HTT_TX_MSDU_EXT_DESC_NSS_MASK_M 0x00f00000 +#define HTT_TX_MSDU_EXT_DESC_NSS_MASK_S 20 +#define HTT_TX_MSDU_EXT_DESC_GUARD_INTERVAL_M 0x01000000 +#define HTT_TX_MSDU_EXT_DESC_GUARD_INTERVAL_S 24 +#define HTT_TX_MSDU_EXT_DESC_PREAMBLE_TYPE_MASK_M 0x1c000000 +#define HTT_TX_MSDU_EXT_DESC_PREAMBLE_TYPE_MASK_S 25 + +/* DWORD 2 */ +#define HTT_TX_MSDU_EXT_DESC_CHAIN_MASK_M 0x0000000f +#define HTT_TX_MSDU_EXT_DESC_CHAIN_MASK_S 0 +#define HTT_TX_MSDU_EXT_DESC_RETRY_LIMIT_M 0x000000f0 +#define HTT_TX_MSDU_EXT_DESC_RETRY_LIMIT_S 4 +#define HTT_TX_MSDU_EXT_DESC_BANDWIDTH_MASK_M 0x00003f00 +#define HTT_TX_MSDU_EXT_DESC_BANDWIDTH_MASK_S 8 + + +/* DWORD 0 */ +#define HTT_TX_MSDU_EXT_DESC_FLAG_VALID_PWR_GET(_var) \ + (((_var) & HTT_TX_MSDU_EXT_DESC_FLAG_VALID_PWR_M) >> \ + HTT_TX_MSDU_EXT_DESC_FLAG_VALID_PWR_S) +#define HTT_TX_MSDU_EXT_DESC_FLAG_VALID_PWR_SET(_var, _val) \ +do { \ + HTT_CHECK_SET_VAL(HTT_TX_MSDU_EXT_DESC_FLAG_VALID_PWR, _val); \ + ((_var) |= ((_val) << HTT_TX_MSDU_EXT_DESC_FLAG_VALID_PWR_S)); \ +} while (0) + +#define HTT_TX_MSDU_EXT_DESC_FLAG_VALID_MCS_MASK_GET(_var) \ + (((_var) & HTT_TX_MSDU_EXT_DESC_FLAG_VALID_MCS_MASK_M) >> \ + HTT_TX_MSDU_EXT_DESC_FLAG_VALID_MCS_MASK_S) +#define HTT_TX_MSDU_EXT_DESC_FLAG_VALID_MCS_MASK_SET(_var, _val) \ +do { \ + HTT_CHECK_SET_VAL(HTT_TX_MSDU_EXT_DESC_FLAG_VALID_MCS_MASK, _val); \ + ((_var) |= ((_val) << HTT_TX_MSDU_EXT_DESC_FLAG_VALID_MCS_MASK_S)); \ +} while (0) + +#define HTT_TX_MSDU_EXT_DESC_FLAG_VALID_GUARD_INTERVAL_GET(_var) \ + (((_var) & HTT_TX_MSDU_EXT_DESC_FLAG_VALID_GUARD_INTERVAL_M) >> \ + HTT_TX_MSDU_EXT_DESC_FLAG_VALID_GUARD_INTERVAL_S) +#define HTT_TX_MSDU_EXT_DESC_FLAG_VALID_GUARD_INTERVAL_SET(_var, _val) \ +do { \ + HTT_CHECK_SET_VAL( \ + HTT_TX_MSDU_EXT_DESC_FLAG_VALID_GUARD_INTERVAL, _val); \ + ((_var) |= ((_val) \ + << HTT_TX_MSDU_EXT_DESC_FLAG_VALID_GUARD_INTERVAL_S)); \ +} while (0) + +#define HTT_TX_MSDU_EXT_DESC_FLAG_VALID_PREAMBLE_TYPE_MASK_GET(_var) \ + (((_var) & HTT_TX_MSDU_EXT_DESC_FLAG_VALID_PREAMBLE_TYPE_MASK_M) >>\ + HTT_TX_MSDU_EXT_DESC_FLAG_VALID_PREAMBLE_TYPE_MASK_S) +#define HTT_TX_MSDU_EXT_DESC_FLAG_VALID_PREAMBLE_TYPE_MASK_SET(_var, _val) \ +do { \ + HTT_CHECK_SET_VAL( \ + HTT_TX_MSDU_EXT_DESC_FLAG_VALID_PREAMBLE_TYPE_MASK, _val); \ + ((_var) |= ((_val) \ + << HTT_TX_MSDU_EXT_DESC_FLAG_VALID_PREAMBLE_TYPE_MASK_S)); \ +} while (0) + +#define HTT_TX_MSDU_EXT_DESC_FLAG_VALID_CHAIN_MASK_GET(_var) \ + (((_var) & HTT_TX_MSDU_EXT_DESC_FLAG_VALID_CHAIN_MASK_M) >> \ + HTT_TX_MSDU_EXT_DESC_FLAG_VALID_CHAIN_MASK_S) +#define HTT_TX_MSDU_EXT_DESC_FLAG_VALID_CHAIN_MASK_SET(_var, _val) \ +do { \ + HTT_CHECK_SET_VAL(HTT_TX_MSDU_EXT_DESC_FLAG_VALID_CHAIN_MASK, _val); \ + ((_var) |= ((_val) << \ + HTT_TX_MSDU_EXT_DESC_FLAG_VALID_CHAIN_MASK_S)); \ +} while (0) + +#define HTT_TX_MSDU_EXT_DESC_FLAG_VALID_RETRIES_GET(_var) \ + (((_var) & HTT_TX_MSDU_EXT_DESC_FLAG_VALID_RETRIES_M) >> \ + HTT_TX_MSDU_EXT_DESC_FLAG_VALID_RETRIES_S) +#define HTT_TX_MSDU_EXT_DESC_FLAG_VALID_RETRIES_SET(_var, _val) \ +do { \ + HTT_CHECK_SET_VAL(HTT_TX_MSDU_EXT_DESC_FLAG_VALID_RETRIES, _val); \ + ((_var) |= ((_val) << HTT_TX_MSDU_EXT_DESC_FLAG_VALID_RETRIES_S)); \ +} while (0) + +#define HTT_TX_MSDU_EXT_DESC_FLAG_VALID_BANDWIDTH_GET(_var) \ + (((_var) & HTT_TX_MSDU_EXT_DESC_FLAG_VALID_BANDWIDTH_M) >> \ + HTT_TX_MSDU_EXT_DESC_FLAG_VALID_BANDWIDTH_S) +#define HTT_TX_MSDU_EXT_DESC_FLAG_VALID_BANDWIDTH_SET(_var, _val) \ +do { \ + HTT_CHECK_SET_VAL(HTT_TX_MSDU_EXT_DESC_FLAG_VALID_BANDWIDTH, _val); \ + ((_var) |= ((_val) << HTT_TX_MSDU_EXT_DESC_FLAG_VALID_BANDWIDTH_S)); \ +} while (0) + +#define HTT_TX_MSDU_EXT_DESC_FLAG_VALID_EXPIRE_TIME_GET(_var) \ + (((_var) & HTT_TX_MSDU_EXT_DESC_FLAG_VALID_EXPIRE_TIME_M) >> \ + HTT_TX_MSDU_EXT_DESC_FLAG_VALID_EXPIRE_TIME_S) +#define HTT_TX_MSDU_EXT_DESC_FLAG_VALID_EXPIRE_TIME_SET(_var, _val) \ +do { \ + HTT_CHECK_SET_VAL(HTT_TX_MSDU_EXT_DESC_FLAG_VALID_EXPIRE_TIME, _val); \ + ((_var) |= ((_val) << HTT_TX_MSDU_EXT_DESC_FLAG_VALID_EXPIRE_TIME_S));\ +} while (0) + +#define HTT_TX_MSDU_EXT_DESC_FLAG_IS_DSRC_GET(_var) \ + (((_var) & HTT_TX_MSDU_EXT_DESC_FLAG_IS_DSRC_M) >> \ + HTT_TX_MSDU_EXT_DESC_FLAG_IS_DSRC_S) +#define HTT_TX_MSDU_EXT_DESC_FLAG_IS_DSRC_SET(_var, _val) \ +do { \ + HTT_CHECK_SET_VAL(HTT_TX_MSDU_EXT_DESC_FLAG_IS_DSRC, _val); \ + ((_var) |= ((_val) << HTT_TX_MSDU_EXT_DESC_FLAG_IS_DSRC_S)); \ +} while (0) + + +/* DWORD 1 */ +#define HTT_TX_MSDU_EXT_DESC_PWR_GET_BASE(_var) \ + (((_var) & HTT_TX_MSDU_EXT_DESC_PWR_M) >> \ + HTT_TX_MSDU_EXT_DESC_PWR_S) +#define HTT_TX_MSDU_EXT_DESC_PWR_GET(_var) \ + (HTT_TX_MSDU_EXT_DESC_PWR_GET_BASE(_var) | \ + HTT_SIGN_BIT_EXTENSION_MASK(_var, HTT_TX_MSDU_EXT_DESC_PWR)) +#define HTT_TX_MSDU_EXT_DESC_PWR_SET(_var, _val) \ + ((_var) |= (((_val) << HTT_TX_MSDU_EXT_DESC_PWR_S)) & \ + HTT_TX_MSDU_EXT_DESC_PWR_M) + +#define HTT_TX_MSDU_EXT_DESC_MCS_MASK_GET(_var) \ + (((_var) & HTT_TX_MSDU_EXT_DESC_MCS_MASK_M) >> \ + HTT_TX_MSDU_EXT_DESC_MCS_MASK_S) +#define HTT_TX_MSDU_EXT_DESC_MCS_MASK_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_TX_MSDU_EXT_DESC_MCS_MASK, _val); \ + ((_var) |= ((_val) << HTT_TX_MSDU_EXT_DESC_MCS_MASK_S)); \ + } while (0) + +#define HTT_TX_MSDU_EXT_DESC_NSS_MASK_GET(_var) \ + (((_var) & HTT_TX_MSDU_EXT_DESC_NSS_MASK_M) >> \ + HTT_TX_MSDU_EXT_DESC_NSS_MASK_S) +#define HTT_TX_MSDU_EXT_DESC_NSS_MASK_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_TX_MSDU_EXT_DESC_NSS_MASK, _val); \ + ((_var) |= ((_val) << HTT_TX_MSDU_EXT_DESC_NSS_MASK_S)); \ + } while (0) + +#define HTT_TX_MSDU_EXT_DESC_GUARD_INTERVAL_GET(_var) \ + (((_var) & HTT_TX_MSDU_EXT_DESC_GUARD_INTERVAL_M) >> \ + HTT_TX_MSDU_EXT_DESC_GUARD_INTERVAL_S) +#define HTT_TX_MSDU_EXT_DESC_GUARD_INTERVAL_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_TX_MSDU_EXT_DESC_GUARD_INTERVAL, _val); \ + ((_var) |= ((_val) << HTT_TX_MSDU_EXT_DESC_GUARD_INTERVAL_S)); \ + } while (0) + +#define HTT_TX_MSDU_EXT_DESC_PREAMBLE_TYPE_MASK_GET(_var) \ + (((_var) & HTT_TX_MSDU_EXT_DESC_PREAMBLE_TYPE_MASK_M) >> \ + HTT_TX_MSDU_EXT_DESC_PREAMBLE_TYPE_MASK_S) +#define HTT_TX_MSDU_EXT_DESC_PREAMBLE_TYPE_MASK_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_TX_MSDU_EXT_DESC_PREAMBLE_TYPE_MASK,\ + _val); \ + ((_var) |= ((_val) << \ + HTT_TX_MSDU_EXT_DESC_PREAMBLE_TYPE_MASK_S)); \ + } while (0) + + +/* DWORD 2 */ +#define HTT_TX_MSDU_EXT_DESC_CHAIN_MASK_GET(_var) \ + (((_var) & HTT_TX_MSDU_EXT_DESC_CHAIN_MASK_M) >> \ + HTT_TX_MSDU_EXT_DESC_CHAIN_MASK_S) +#define HTT_TX_MSDU_EXT_DESC_CHAIN_MASK_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_TX_MSDU_EXT_DESC_CHAIN_MASK, _val); \ + ((_var) |= ((_val) << HTT_TX_MSDU_EXT_DESC_CHAIN_MASK_S)); \ + } while (0) + +#define HTT_TX_MSDU_EXT_DESC_RETRY_LIMIT_GET(_var) \ + (((_var) & HTT_TX_MSDU_EXT_DESC_RETRY_LIMIT_M) >> \ + HTT_TX_MSDU_EXT_DESC_RETRY_LIMIT_S) +#define HTT_TX_MSDU_EXT_DESC_RETRY_LIMIT_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_TX_MSDU_EXT_DESC_RETRY_LIMIT, _val); \ + ((_var) |= ((_val) << HTT_TX_MSDU_EXT_DESC_RETRY_LIMIT_S)); \ + } while (0) + +#define HTT_TX_MSDU_EXT_DESC_BANDWIDTH_MASK_GET(_var) \ + (((_var) & HTT_TX_MSDU_EXT_DESC_BANDWIDTH_MASK_M) >> \ + HTT_TX_MSDU_EXT_DESC_BANDWIDTH_MASK_S) +#define HTT_TX_MSDU_EXT_DESC_BANDWIDTH_MASK_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_TX_MSDU_EXT_DESC_BANDWIDTH_MASK, _val); \ + ((_var) |= ((_val) << HTT_TX_MSDU_EXT_DESC_BANDWIDTH_MASK_S)); \ + } while (0) + + +typedef enum { + HTT_11AX_HE_LTF_SUBTYPE_1X, + HTT_11AX_HE_LTF_SUBTYPE_2X, + HTT_11AX_HE_LTF_SUBTYPE_4X, +} htt_11ax_ltf_subtype_t; + +typedef enum { + HTT_TX_MSDU_EXT2_DESC_PREAM_OFDM, + HTT_TX_MSDU_EXT2_DESC_PREAM_CCK, + HTT_TX_MSDU_EXT2_DESC_PREAM_HT, + HTT_TX_MSDU_EXT2_DESC_PREAM_VHT, + HTT_TX_MSDU_EXT2_DESC_PREAM_HE_SU, + HTT_TX_MSDU_EXT2_DESC_PREAM_HE_EXT_SU, +} htt_tx_ext2_preamble_type_t; + +#define HTT_TX_MSDU_EXT2_DESC_BW_5MHZ_M 0x00000001 +#define HTT_TX_MSDU_EXT2_DESC_BW_5MHZ_S 0 +#define HTT_TX_MSDU_EXT2_DESC_BW_10MHZ_M 0x00000002 +#define HTT_TX_MSDU_EXT2_DESC_BW_10MHZ_S 1 +#define HTT_TX_MSDU_EXT2_DESC_BW_20MHZ_M 0x00000004 +#define HTT_TX_MSDU_EXT2_DESC_BW_20MHZ_S 2 +#define HTT_TX_MSDU_EXT2_DESC_BW_40MHZ_M 0x00000008 +#define HTT_TX_MSDU_EXT2_DESC_BW_40MHZ_S 3 +#define HTT_TX_MSDU_EXT2_DESC_BW_80MHZ_M 0x00000010 +#define HTT_TX_MSDU_EXT2_DESC_BW_80MHZ_S 4 +#define HTT_TX_MSDU_EXT2_DESC_BW_160MHZ_M 0x00000020 +#define HTT_TX_MSDU_EXT2_DESC_BW_160MHZ_S 5 + +/** + * @brief HTT tx MSDU extension descriptor v2 + * @details + * In Lithium, if htt_tx_tcl_metadata->valid_htt_ext is set, this structure + * is received as tcl_exit_base->host_meta_info in firmware. + * Also there is no htt_tx_msdu_desc_t in Lithium since most of those fields + * are already part of tcl_exit_base. + */ +PREPACK struct htt_tx_msdu_desc_ext2_t { + /* DWORD 0: flags */ + A_UINT32 + valid_pwr : 1, /* if set, tx pwr spec is valid */ + valid_mcs_mask : 1, /* if set, tx MCS mask is valid */ + valid_nss_mask : 1, /* if set, tx Nss mask is valid */ + valid_preamble_type : 1, /* if set, tx preamble spec is valid */ + valid_retries : 1, /* if set, tx retries spec is valid */ + valid_guard_interval : 1, /* if set, tx guard intv spec is valid */ + /* if set, tx dyn_bw and bw_mask are valid */ + valid_bw_info : 1, + valid_chainmask : 1, /* if set, tx chainmask is valid */ + valid_encrypt_type : 1, /* if set, encrypt type is valid */ + valid_key_flags : 1, /* if set, key flags is valid */ + valid_expire_tsf : 1, /* if set, tx expire TSF spec is valid */ + valid_chanfreq : 1, /* if set, chanfreq is valid */ + is_dsrc : 1, /* if set, MSDU is a DSRC frame */ + guard_interval : 2, /* 0.4us, 0.8us, 1.6us, 3.2us */ + encrypt_type : 2, /* 0 = NO_ENCRYPT, + * 1 = ENCRYPT, + * 2 ~ 3 - Reserved + */ + /* retry_limit - + * Specify the maximum number of transmissions, including the + * initial transmission, to attempt before giving up if no ack + * is received. + * If the tx rate is specified, then all retries shall use the + * same rate as the initial transmission. + * If no tx rate is specified, the target can choose whether to + * retain the original rate during the retransmissions, or to + * fall back to a more robust rate. + */ + retry_limit : 4, + use_dcm_11ax : 1, /* If set, Use Dual subcarrier modulation. + * Valid only for 11ax preamble types HE_SU + * and HE_EXT_SU + */ + /* Takes enum values of htt_11ax_ltf_subtype_t + * Valid only for 11ax preamble types HE_SU + * and HE_EXT_SU + */ + ltf_subtype_11ax : 2, + dyn_bw : 1, /* 0 = static bw, 1 = dynamic bw */ + bw_mask : 6, /* Valid only if dyn_bw == 0 (static bw). + * (Bit mask of 5, 10, 20, 40, 80, 160Mhz. + * Refer to HTT_TX_MSDU_EXT2_DESC_BW defs.) + */ + reserved0_31 : 1; + + /* DWORD 1: tx power, tx rate */ + A_UINT32 + /* unit of the power field is 0.5 dbm + * similar to pwr field in htt_tx_msdu_desc_ext_t + * signed value ranging from -64dbm to 63.5 dbm + */ + power : 8, + /* mcs bit mask of 0 ~ 11 + * Setting more than one MCS isn't currently + * supported by the target (but is supported + * in the interface in case in the future + * the target supports specifications of + * a limited set of MCS values. + */ + mcs_mask : 12, + /* Nss bit mask 0 ~ 7 + * Setting more than one Nss isn't currently + * supported by the target (but is supported + * in the interface in case in the future + * the target supports specifications of + * a limited set of Nss values. + */ + nss_mask : 8, + /* Takes enum values of htt_tx_ext2_preamble_type_t */ + pream_type : 3, + reserved1_31 : 1; + + /* DWORD 2: tx chain mask, tx retries */ + A_UINT32 + /* chain_mask - specify which chains to transmit from */ + chain_mask : 8, + + /* Key Index and related flags - used in mesh mode + * TODO: Update Enum values for key_flags + */ + key_flags : 8, + /* + * Channel frequency: This identifies the desired channel + * frequency (in MHz) for tx frames. This is used by FW to help + * determine when it is safe to transmit or drop frames for + * off-channel operation. + * The default value of zero indicates to FW that the corresponding + * VDEV's home channel (if there is one) is the desired channel + * frequency. + */ + chanfreq : 16; + + /* DWORD 3: tx expiry time (TSF) LSBs */ + A_UINT32 expire_tsf_lo; + + /* DWORD 4: tx expiry time (TSF) MSBs */ + A_UINT32 expire_tsf_hi; +} POSTPACK; + +/* DWORD 0 */ +#define HTT_TX_MSDU_EXT2_DESC_FLAG_VALID_PWR_M 0x00000001 +#define HTT_TX_MSDU_EXT2_DESC_FLAG_VALID_PWR_S 0 +#define HTT_TX_MSDU_EXT2_DESC_FLAG_VALID_MCS_MASK_M 0x00000002 +#define HTT_TX_MSDU_EXT2_DESC_FLAG_VALID_MCS_MASK_S 1 +#define HTT_TX_MSDU_EXT2_DESC_FLAG_VALID_NSS_MASK_M 0x00000004 +#define HTT_TX_MSDU_EXT2_DESC_FLAG_VALID_NSS_MASK_S 2 +#define HTT_TX_MSDU_EXT2_DESC_FLAG_VALID_PREAMBLE_TYPE_M 0x00000008 +#define HTT_TX_MSDU_EXT2_DESC_FLAG_VALID_PREAMBLE_TYPE_S 3 +#define HTT_TX_MSDU_EXT2_DESC_FLAG_VALID_RETRIES_M 0x00000010 +#define HTT_TX_MSDU_EXT2_DESC_FLAG_VALID_RETRIES_S 4 +#define HTT_TX_MSDU_EXT2_DESC_FLAG_VALID_BW_INFO_M 0x00000020 +#define HTT_TX_MSDU_EXT2_DESC_FLAG_VALID_BW_INFO_S 5 +#define HTT_TX_MSDU_EXT2_DESC_FLAG_VALID_GUARD_INTERVAL_M 0x00000040 +#define HTT_TX_MSDU_EXT2_DESC_FLAG_VALID_GUARD_INTERVAL_S 6 +#define HTT_TX_MSDU_EXT2_DESC_FLAG_VALID_CHAIN_MASK_M 0x00000080 +#define HTT_TX_MSDU_EXT2_DESC_FLAG_VALID_CHAIN_MASK_S 7 +#define HTT_TX_MSDU_EXT2_DESC_FLAG_VALID_ENCRYPT_TYPE_M 0x00000100 +#define HTT_TX_MSDU_EXT2_DESC_FLAG_VALID_ENCRYPT_TYPE_S 8 +#define HTT_TX_MSDU_EXT2_DESC_FLAG_VALID_KEY_FLAGS_M 0x00000200 +#define HTT_TX_MSDU_EXT2_DESC_FLAG_VALID_KEY_FLAGS_S 9 +#define HTT_TX_MSDU_EXT2_DESC_FLAG_VALID_EXPIRE_TIME_M 0x00000400 +#define HTT_TX_MSDU_EXT2_DESC_FLAG_VALID_EXPIRE_TIME_S 10 +#define HTT_TX_MSDU_EXT2_DESC_FLAG_VALID_CHANFREQ_M 0x00000800 +#define HTT_TX_MSDU_EXT2_DESC_FLAG_VALID_CHANFREQ_S 11 +#define HTT_TX_MSDU_EXT2_DESC_FLAG_IS_DSRC_M 0x00001000 +#define HTT_TX_MSDU_EXT2_DESC_FLAG_IS_DSRC_S 12 +#define HTT_TX_MSDU_EXT2_DESC_GUARD_INTERVAL_M 0x00006000 +#define HTT_TX_MSDU_EXT2_DESC_GUARD_INTERVAL_S 13 +#define HTT_TX_MSDU_EXT2_DESC_ENCRYPT_TYPE_M 0x00018000 +#define HTT_TX_MSDU_EXT2_DESC_ENCRYPT_TYPE_S 15 +#define HTT_TX_MSDU_EXT2_DESC_RETRY_LIMIT_M 0x001e0000 +#define HTT_TX_MSDU_EXT2_DESC_RETRY_LIMIT_S 17 +#define HTT_TX_MSDU_EXT2_DESC_USE_DCM_11AX_M 0x00200000 +#define HTT_TX_MSDU_EXT2_DESC_USE_DCM_11AX_S 21 +#define HTT_TX_MSDU_EXT2_DESC_LTF_SUBTYPE_11AX_M 0x00c00000 +#define HTT_TX_MSDU_EXT2_DESC_LTF_SUBTYPE_11AX_S 22 +#define HTT_TX_MSDU_EXT2_DESC_DYN_BW_M 0x01000000 +#define HTT_TX_MSDU_EXT2_DESC_DYN_BW_S 24 +#define HTT_TX_MSDU_EXT2_DESC_BW_MASK_M 0x7e000000 +#define HTT_TX_MSDU_EXT2_DESC_BW_MASK_S 25 + +/* DWORD 1 */ +#define HTT_TX_MSDU_EXT2_DESC_PWR_M 0x000000ff +#define HTT_TX_MSDU_EXT2_DESC_PWR_S 0 +#define HTT_TX_MSDU_EXT2_DESC_MCS_MASK_M 0x000fff00 +#define HTT_TX_MSDU_EXT2_DESC_MCS_MASK_S 8 +#define HTT_TX_MSDU_EXT2_DESC_NSS_MASK_M 0x0ff00000 +#define HTT_TX_MSDU_EXT2_DESC_NSS_MASK_S 20 +#define HTT_TX_MSDU_EXT2_DESC_PREAM_TYPE_M 0x70000000 +#define HTT_TX_MSDU_EXT2_DESC_PREAM_TYPE_S 28 + +/* DWORD 2 */ +#define HTT_TX_MSDU_EXT2_DESC_CHAIN_MASK_M 0x000000ff +#define HTT_TX_MSDU_EXT2_DESC_CHAIN_MASK_S 0 +#define HTT_TX_MSDU_EXT2_DESC_KEY_FLAGS_M 0x0000ff00 +#define HTT_TX_MSDU_EXT2_DESC_KEY_FLAGS_S 8 +#define HTT_TX_MSDU_EXT_DESC_CHANFREQ_M 0xffff0000 +#define HTT_TX_MSDU_EXT_DESC_CHANFREQ_S 16 + +/* DWORD 0 */ +#define HTT_TX_MSDU_EXT2_DESC_FLAG_VALID_PWR_GET(_var) \ + (((_var) & HTT_TX_MSDU_EXT_DESC_FLAG_VALID_PWR_M) >> \ + HTT_TX_MSDU_EXT2_DESC_FLAG_VALID_PWR_S) +#define HTT_TX_MSDU_EXT2_DESC_FLAG_VALID_PWR_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_TX_MSDU_EXT2_DESC_FLAG_VALID_PWR, _val); \ + ((_var) |= ((_val) << HTT_TX_MSDU_EXT2_DESC_FLAG_VALID_PWR_S));\ + } while (0) + +#define HTT_TX_MSDU_EXT2_DESC_FLAG_VALID_MCS_MASK_GET(_var) \ + (((_var) & HTT_TX_MSDU_EXT2_DESC_FLAG_VALID_MCS_MASK_M) >> \ + HTT_TX_MSDU_EXT2_DESC_FLAG_VALID_MCS_MASK_S) +#define HTT_TX_MSDU_EXT2_DESC_FLAG_VALID_MCS_MASK_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_TX_MSDU_EXT2_DESC_FLAG_VALID_MCS_MASK,\ + _val); \ + ((_var) |= \ + ((_val) << HTT_TX_MSDU_EXT2_DESC_FLAG_VALID_MCS_MASK_S)); \ + } while (0) + +#define HTT_TX_MSDU_EXT2_DESC_FLAG_VALID_NSS_MASK_GET(_var) \ + (((_var) & HTT_TX_MSDU_EXT2_DESC_FLAG_VALID_NSS_MASK_M) >> \ + HTT_TX_MSDU_EXT2_DESC_FLAG_VALID_NSS_MASK_S) +#define HTT_TX_MSDU_EXT2_DESC_FLAG_VALID_NSS_MASK_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_TX_MSDU_EXT2_DESC_FLAG_VALID_NSS_MASK,\ + _val); \ + ((_var) |= \ + ((_val) << HTT_TX_MSDU_EXT2_DESC_FLAG_VALID_NSS_MASK_S)); \ + } while (0) + +#define HTT_TX_MSDU_EXT2_DESC_FLAG_VALID_PREAMBLE_TYPE_GET(_var) \ + (((_var) & HTT_TX_MSDU_EXT2_DESC_FLAG_VALID_PREAMBLE_TYPE_M) >> \ + HTT_TX_MSDU_EXT2_DESC_FLAG_VALID_PREAMBLE_TYPE_S) +#define HTT_TX_MSDU_EXT2_DESC_FLAG_VALID_PREAMBLE_TYPE_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL( \ + HTT_TX_MSDU_EXT2_DESC_FLAG_VALID_PREAMBLE_TYPE, _val); \ + ((_var) |= ((_val) \ + << HTT_TX_MSDU_EXT2_DESC_FLAG_VALID_PREAMBLE_TYPE_S)); \ + } while (0) + +#define HTT_TX_MSDU_EXT2_DESC_FLAG_VALID_RETRIES_GET(_var) \ + (((_var) & HTT_TX_MSDU_EXT2_DESC_FLAG_VALID_RETRIES_M) >> \ + HTT_TX_MSDU_EXT2_DESC_FLAG_VALID_RETRIES_S) +#define HTT_TX_MSDU_EXT2_DESC_FLAG_VALID_RETRIES_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_TX_MSDU_EXT2_DESC_FLAG_VALID_RETRIES,\ + _val); \ + ((_var) |= ((_val) << \ + HTT_TX_MSDU_EXT2_DESC_FLAG_VALID_RETRIES_S)); \ + } while (0) + +#define HTT_TX_MSDU_EXT2_DESC_FLAG_VALID_BW_INFO_GET(_var) \ + (((_var) & HTT_TX_MSDU_EXT2_DESC_FLAG_VALID_BW_INFO_M) >> \ + HTT_TX_MSDU_EXT2_DESC_FLAG_VALID_BW_INFO_S) +#define HTT_TX_MSDU_EXT2_DESC_FLAG_VALID_BW_INFO_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_TX_MSDU_EXT2_DESC_FLAG_VALID_BW_INFO,\ + _val); \ + ((_var) |= \ + ((_val) << HTT_TX_MSDU_EXT2_DESC_FLAG_VALID_BW_INFO_S)); \ + } while (0) + +#define HTT_TX_MSDU_EXT2_DESC_FLAG_VALID_GUARD_INTERVAL_GET(_var) \ + (((_var) & HTT_TX_MSDU_EXT2_DESC_FLAG_VALID_GUARD_INTERVAL_M) >>\ + HTT_TX_MSDU_EXT2_DESC_FLAG_VALID_GUARD_INTERVAL_S) +#define HTT_TX_MSDU_EXT2_DESC_FLAG_VALID_GUARD_INTERVAL_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL( \ + HTT_TX_MSDU_EXT2_DESC_FLAG_VALID_GUARD_INTERVAL, _val); \ + ((_var) |= ((_val) \ + << HTT_TX_MSDU_EXT2_DESC_FLAG_VALID_GUARD_INTERVAL_S)); \ + } while (0) + +#define HTT_TX_MSDU_EXT2_DESC_FLAG_VALID_CHAIN_MASK_GET(_var) \ + (((_var) & HTT_TX_MSDU_EXT2_DESC_FLAG_VALID_CHAIN_MASK_M) >> \ + HTT_TX_MSDU_EXT2_DESC_FLAG_VALID_CHAIN_MASK_S) +#define HTT_TX_MSDU_EXT2_DESC_FLAG_VALID_CHAIN_MASK_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_TX_MSDU_EXT2_DESC_FLAG_VALID_CHAIN_MASK,\ + _val); \ + ((_var) |= \ + ((_val) << HTT_TX_MSDU_EXT2_DESC_FLAG_VALID_CHAIN_MASK_S)); \ + } while (0) + +#define HTT_TX_MSDU_EXT2_DESC_FLAG_VALID_ENCRYPT_TYPE_GET(_var) \ + (((_var) & HTT_TX_MSDU_EXT2_DESC_FLAG_VALID_ENCRYPT_TYPE_M) >> \ + HTT_TX_MSDU_EXT2_DESC_FLAG_VALID_ENCRYPT_TYPE_S) +#define HTT_TX_MSDU_EXT2_DESC_FLAG_VALID_ENCRYPT_TYPE_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL( \ + HTT_TX_MSDU_EXT2_DESC_FLAG_VALID_ENCRYPT_TYPE, _val); \ + ((_var) |= \ + ((_val) << HTT_TX_MSDU_EXT2_DESC_FLAG_VALID_ENCRYPT_TYPE_S));\ + } while (0) + +#define HTT_TX_MSDU_EXT2_DESC_FLAG_VALID_KEY_FLAGS_GET(_var) \ + (((_var) & HTT_TX_MSDU_EXT2_DESC_FLAG_VALID_KEY_FLAGS_M) >> \ + HTT_TX_MSDU_EXT2_DESC_FLAG_VALID_KEY_FLAGS_S) +#define HTT_TX_MSDU_EXT2_DESC_FLAG_VALID_KEY_FLAGS_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL( \ + HTT_TX_MSDU_EXT2_DESC_FLAG_VALID_KEY_FLAGS, _val); \ + ((_var) |= \ + ((_val) << HTT_TX_MSDU_EXT2_DESC_FLAG_VALID_KEY_FLAGS_S));\ + } while (0) + +#define HTT_TX_MSDU_EXT2_DESC_FLAG_VALID_EXPIRE_TIME_GET(_var) \ + (((_var) & HTT_TX_MSDU_EXT2_DESC_FLAG_VALID_EXPIRE_TIME_M) >> \ + HTT_TX_MSDU_EXT2_DESC_FLAG_VALID_EXPIRE_TIME_S) +#define HTT_TX_MSDU_EXT2_DESC_FLAG_VALID_EXPIRE_TIME_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_TX_MSDU_EXT2_DESC_FLAG_VALID_EXPIRE_TIME,\ + _val); \ + ((_var) |= ((_val) << \ + HTT_TX_MSDU_EXT2_DESC_FLAG_VALID_EXPIRE_TIME_S));\ + } while (0) + +#define HTT_TX_MSDU_EXT2_DESC_FLAG_VALID_CHANFREQ_GET(_var) \ + (((_var) & HTT_TX_MSDU_EXT2_DESC_FLAG_VALID_CHANFREQ_M) >> \ + HTT_TX_MSDU_EXT2_DESC_FLAG_VALID_CHANFREQ_S) +#define HTT_TX_MSDU_EXT2_DESC_FLAG_VALID_CHANFREQ_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_TX_MSDU_EXT2_DESC_FLAG_VALID_CHANFREQ,\ + _val); \ + ((_var) |= ((_val) << \ + HTT_TX_MSDU_EXT2_DESC_FLAG_VALID_CHANFREQ_S));\ + } while (0) + +#define HTT_TX_MSDU_EXT2_DESC_FLAG_IS_DSRC_GET(_var) \ + (((_var) & HTT_TX_MSDU_EXT2_DESC_FLAG_IS_DSRC_M) >> \ + HTT_TX_MSDU_EXT2_DESC_FLAG_IS_DSRC_S) +#define HTT_TX_MSDU_EXT2_DESC_FLAG_IS_DSRC_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_TX_MSDU_EXT2_DESC_FLAG_IS_DSRC, _val);\ + ((_var) |= ((_val) << HTT_TX_MSDU_EXT2_DESC_FLAG_IS_DSRC_S));\ + } while (0) + +#define HTT_TX_MSDU_EXT2_DESC_GUARD_INTERVAL_GET(_var) \ + (((_var) & HTT_TX_MSDU_EXT2_DESC_GUARD_INTERVAL_M) >> \ + HTT_TX_MSDU_EXT2_DESC_GUARD_INTERVAL_S) +#define HTT_TX_MSDU_EXT2_DESC_GUARD_INTERVAL_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_TX_MSDU_EXT2_DESC_GUARD_INTERVAL, _val);\ + ((_var) |= ((_val) << HTT_TX_MSDU_EXT2_DESC_GUARD_INTERVAL_S));\ + } while (0) + +#define HTT_TX_MSDU_EXT2_DESC_ENCRYPT_TYPE_GET(_var) \ + (((_var) & HTT_TX_MSDU_EXT2_DESC_ENCRYPT_TYPE_M) >> \ + HTT_TX_MSDU_EXT2_DESC_ENCRYPT_TYPE_S) +#define HTT_TX_MSDU_EXT2_DESC_ENCRYPT_TYPE_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_TX_MSDU_EXT2_DESC_ENCRYPT_TYPE, _val);\ + ((_var) |= ((_val) << HTT_TX_MSDU_EXT2_DESC_ENCRYPT_TYPE_S));\ + } while (0) + +#define HTT_TX_MSDU_EXT2_DESC_RETRY_LIMIT_GET(_var) \ + (((_var) & HTT_TX_MSDU_EXT2_DESC_RETRY_LIMIT_M) >> \ + HTT_TX_MSDU_EXT2_DESC_RETRY_LIMIT_S) +#define HTT_TX_MSDU_EXT2_DESC_RETRY_LIMIT_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_TX_MSDU_EXT2_DESC_RETRY_LIMIT, _val);\ + ((_var) |= ((_val) << HTT_TX_MSDU_EXT2_DESC_RETRY_LIMIT_S));\ + } while (0) + +#define HTT_TX_MSDU_EXT2_DESC_USE_DCM_11AX_GET(_var) \ + (((_var) & HTT_TX_MSDU_EXT2_DESC_USE_DCM_11AX_M) >> \ + HTT_TX_MSDU_EXT2_DESC_USE_DCM_11AX_S) +#define HTT_TX_MSDU_EXT2_DESC_USE_DCM_11AX_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_TX_MSDU_EXT2_DESC_USE_DCM_11AX, _val);\ + ((_var) |= ((_val) << HTT_TX_MSDU_EXT2_DESC_USE_DCM_11AX_S));\ + } while (0) + +#define HTT_TX_MSDU_EXT2_DESC_LTF_SUBTYPE_11AX_GET(_var) \ + (((_var) & HTT_TX_MSDU_EXT2_DESC_LTF_SUBTYPE_11AX_M) >> \ + HTT_TX_MSDU_EXT2_DESC_LTF_SUBTYPE_11AX_S) +#define HTT_TX_MSDU_EXT2_DESC_LTF_SUBTYPE_11AX_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_TX_MSDU_EXT2_DESC_LTF_SUBTYPE_11AX,\ + _val); \ + ((_var) |= ((_val) << \ + HTT_TX_MSDU_EXT2_DESC_LTF_SUBTYPE_11AX_S)); \ + } while (0) + +#define HTT_TX_MSDU_EXT2_DESC_BW_MASK_GET(_var) \ + (((_var) & HTT_TX_MSDU_EXT2_DESC_BW_MASK_M) >> \ + HTT_TX_MSDU_EXT2_DESC_BW_MASK_S) +#define HTT_TX_MSDU_EXT2_DESC_BW_MASK_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_TX_MSDU_EXT2_DESC_BW_MASK, _val); \ + ((_var) |= ((_val) << HTT_TX_MSDU_EXT2_DESC_BW_MASK_S));\ + } while (0) + +#define HTT_TX_MSDU_EXT2_DESC_PARTIAL_BW_MASK_GET(_var) \ + (((_var) & HTT_TX_MSDU_EXT2_DESC_PARTIAL_BW_MASK_M) >> \ + HTT_TX_MSDU_EXT2_DESC_PARTIAL_BW_MASK_S) +#define HTT_TX_MSDU_EXT2_DESC_PARTIAL_BW_MASK_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_TX_MSDU_EXT2_DESC_PARTIAL_BW_MASK, _val);\ + ((_var) |= ((_val) << \ + HTT_TX_MSDU_EXT2_DESC_PARTIAL_BW_MASK_S)); \ + } while (0) + + +/* DWORD 1 */ +#define HTT_TX_MSDU_EXT2_DESC_PWR_GET_BASE(_var) \ + (((_var) & HTT_TX_MSDU_EXT2_DESC_PWR_M) >> \ + HTT_TX_MSDU_EXT2_DESC_PWR_S) +#define HTT_TX_MSDU_EXT2_DESC_PWR_GET(_var) \ + (HTT_TX_MSDU_EXT2_DESC_PWR_GET_BASE(_var) | \ + HTT_SIGN_BIT_EXTENSION_MASK(_var, HTT_TX_MSDU_EXT2_DESC_PWR)) +#define HTT_TX_MSDU_EXT2_DESC_PWR_SET(_var, _val) \ + ((_var) |= (((_val) << HTT_TX_MSDU_EXT2_DESC_PWR_S)) & \ + HTT_TX_MSDU_EXT2_DESC_PWR_M) + +#define HTT_TX_MSDU_EXT2_DESC_MCS_MASK_GET(_var) \ + (((_var) & HTT_TX_MSDU_EXT2_DESC_MCS_MASK_M) >> \ + HTT_TX_MSDU_EXT2_DESC_MCS_MASK_S) +#define HTT_TX_MSDU_EXT2_DESC_MCS_MASK_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_TX_MSDU_EXT2_DESC_MCS_MASK, _val);\ + ((_var) |= ((_val) << HTT_TX_MSDU_EXT2_DESC_MCS_MASK_S));\ + } while (0) + +#define HTT_TX_MSDU_EXT2_DESC_NSS_MASK_GET(_var) \ + (((_var) & HTT_TX_MSDU_EXT2_DESC_NSS_MASK_M) >> \ + HTT_TX_MSDU_EXT2_DESC_NSS_MASK_S) +#define HTT_TX_MSDU_EXT2_DESC_NSS_MASK_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_TX_MSDU_EXT2_DESC_NSS_MASK, _val);\ + ((_var) |= ((_val) << HTT_TX_MSDU_EXT2_DESC_NSS_MASK_S));\ + } while (0) + +#define HTT_TX_MSDU_EXT2_DESC_PREAMBLE_TYPE_GET(_var) \ + (((_var) & HTT_TX_MSDU_EXT2_DESC_PREAMBLE_TYPE_M) >> \ + HTT_TX_MSDU_EXT2_DESC_PREAMBLE_TYPE_S) +#define HTT_TX_MSDU_EXT2_DESC_PREAMBLE_TYPE_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_TX_MSDU_EXT2_DESC_PREAMBLE_TYPE, _val);\ + ((_var) |= ((_val) << HTT_TX_MSDU_EXT2_DESC_PREAMBLE_TYPE_S));\ + } while (0) + +/* DWORD 2 */ +#define HTT_TX_MSDU_EXT2_DESC_CHAIN_MASK_GET(_var) \ + (((_var) & HTT_TX_MSDU_EXT2_DESC_CHAIN_MASK_M) >> \ + HTT_TX_MSDU_EXT2_DESC_CHAIN_MASK_S) +#define HTT_TX_MSDU_EXT2_DESC_CHAIN_MASK_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_TX_MSDU_EXT2_DESC_CHAIN_MASK, _val);\ + ((_var) |= ((_val) << HTT_TX_MSDU_EXT2_DESC_CHAIN_MASK_S));\ + } while (0) + +#define HTT_TX_MSDU_EXT2_DESC_KEY_FLAGS_GET(_var) \ + (((_var) & HTT_TX_MSDU_EXT2_DESC_KEY_FLAGS_MASK_M) >> \ + HTT_TX_MSDU_EXT2_DESC_KEY_FLAGS_S) +#define HTT_TX_MSDU_EXT2_DESC_KEY_FLAGS_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_TX_MSDU_EXT2_DESC_KEY_FLAGS, _val);\ + ((_var) |= ((_val) << HTT_TX_MSDU_EXT2_DESC_KEY_FLAGS_S));\ + } while (0) + +#define HTT_TX_MSDU_EXT2_DESC_CHANFREQ_GET(_var) \ + (((_var) & HTT_TX_MSDU_EXT2_DESC_CHANFREQ_MASK_M) >> \ + HTT_TX_MSDU_EXT2_DESC_CHANFREQ_S) +#define HTT_TX_MSDU_EXT2_DESC_CHANFREQ_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_TX_MSDU_EXT2_DESC_CHANFREQ, _val);\ + ((_var) |= ((_val) << HTT_TX_MSDU_EXT2_DESC_CHANFREQ_S));\ + } while (0) + +typedef enum { + HTT_TCL_METADATA_TYPE_PEER_BASED = 0, + HTT_TCL_METADATA_TYPE_VDEV_BASED = 1, +} htt_tcl_metadata_type; + +/** + * @brief HTT TCL command number format + * @details + * This structure is passed from host as tcl_data_cmd->tcl_cmd_number and + * available to firmware as tcl_exit_base->tcl_status_number. + * For regular / multicast packets host will send vdev and mac id and for + * NAWDS packets, host will send peer id. + * A_UINT32 is used to avoid endianness conversion problems. + * tcl_status_number size is 16 bits, hence only 16 bits can be used. + */ + +typedef struct { + A_UINT32 + type: 1, /* vdev_id based or peer_id based */ + rsvd: 31; +} htt_tx_tcl_vdev_or_peer_t; + +typedef struct { + A_UINT32 + type: 1, /* vdev_id based or peer_id based */ + valid_htt_ext: 1, /* If set, tcl_exit_base->host_meta_info is valid */ + vdev_id: 8, + pdev_id: 2, + rsvd: 20; +} htt_tx_tcl_vdev_metadata; + +typedef struct { + A_UINT32 + type: 1, /* vdev_id based or peer_id based */ + valid_htt_ext: 1, /* If set, tcl_exit_base->host_meta_info is valid */ + peer_id: 14, + rsvd: 16; +} htt_tx_tcl_peer_metadata; + +PREPACK struct htt_tx_tcl_metadata { + union { + htt_tx_tcl_vdev_or_peer_t vdev_or_peer; + htt_tx_tcl_vdev_metadata vdev_meta; + htt_tx_tcl_peer_metadata peer_meta; + }; +} POSTPACK; + +/* DWORD 0 */ +#define HTT_TX_TCL_METADATA_TYPE_M 0x00000001 +#define HTT_TX_TCL_METADATA_TYPE_S 0 +#define HTT_TX_TCL_METADATA_VALID_HTT_M 0x00000002 +#define HTT_TX_TCL_METADATA_VALID_HTT_S 1 +#define HTT_TX_TCL_METADATA_VDEV_ID_M 0x000003fc +#define HTT_TX_TCL_METADATA_VDEV_ID_S 2 +#define HTT_TX_TCL_METADATA_PDEV_ID_M 0x00000c00 +#define HTT_TX_TCL_METADATA_PDEV_ID_S 10 +#define HTT_TX_TCL_METADATA_PEER_ID_M 0x0000fffc +#define HTT_TX_TCL_METADATA_PEER_ID_S 2 + +#define HTT_TX_TCL_METADATA_TYPE_GET(_var) \ + (((_var) & HTT_TX_TCL_METADATA_TYPE_M) >> \ + HTT_TX_TCL_METADATA_TYPE_S) +#define HTT_TX_TCL_METADATA_TYPE_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_TX_TCL_METADATA_TYPE, _val);\ + ((_var) |= ((_val) << HTT_TX_TCL_METADATA_TYPE_S));\ + } while (0) + +#define HTT_TX_TCL_METADATA_VALID_HTT_GET(_var) \ + (((_var) & HTT_TX_TCL_METADATA_VALID_HTT_M) >> \ + HTT_TX_TCL_METADATA_VALID_HTT_S) +#define HTT_TX_TCL_METADATA_VALID_HTT_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_TX_TCL_METADATA_VALID_HTT, _val);\ + ((_var) |= ((_val) << HTT_TX_TCL_METADATA_VALID_HTT_S));\ + } while (0) + +#define HTT_TX_TCL_METADATA_VDEV_ID_GET(_var) \ + (((_var) & HTT_TX_TCL_METADATA_VDEV_ID_M) >> \ + HTT_TX_TCL_METADATA_VDEV_ID_S) +#define HTT_TX_TCL_METADATA_VDEV_ID_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_TX_TCL_METADATA_VDEV_ID, _val);\ + ((_var) |= ((_val) << HTT_TX_TCL_METADATA_VDEV_ID_S));\ + } while (0) + +#define HTT_TX_TCL_METADATA_PDEV_ID_GET(_var) \ + (((_var) & HTT_TX_TCL_METADATA_PDEV_ID_M) >> \ + HTT_TX_TCL_METADATA_PDEV_ID_S) +#define HTT_TX_TCL_METADATA_PDEV_ID_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_TX_TCL_METADATA_PDEV_ID, _val);\ + ((_var) |= ((_val) << HTT_TX_TCL_METADATA_PDEV_ID_S));\ + } while (0) + +#define HTT_TX_TCL_METADATA_PEER_ID_GET(_var) \ + (((_var) & HTT_TX_TCL_METADATA_PEER_ID_M) >> \ + HTT_TX_TCL_METADATA_PEER_ID_S) +#define HTT_TX_TCL_METADATA_PEER_ID_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_TX_TCL_METADATA_PEER_ID, _val);\ + ((_var) |= ((_val) << HTT_TX_TCL_METADATA_PEER_ID_S));\ + } while (0) + + +typedef enum { + HTT_TX_FW2WBM_TX_STATUS_OK, + HTT_TX_FW2WBM_TX_STATUS_DROP, + HTT_TX_FW2WBM_TX_STATUS_TTL, + HTT_TX_FW2WBM_TX_STATUS_REINJECT, + HTT_TX_FW2WBM_TX_STATUS_INSPECT, + + HTT_TX_FW2WBM_TX_STATUS_MAX +} htt_tx_fw2wbm_tx_status_t; + +typedef enum { + HTT_TX_FW2WBM_REINJECT_REASON_EAPOL_ENCAP_EXP, + HTT_TX_FW2WBM_REINJECT_REASON_INJECT_VIA_EXP, + HTT_TX_FW2WBM_REINJECT_REASON_MCAST, + HTT_TX_FW2WBM_REINJECT_REASON_ARP, + HTT_TX_FW2WBM_REINJECT_REASON_DHCP, + + HTT_TX_FW2WBM_REINJECT_REASON_MAX, +} htt_tx_fw2wbm_reinject_reason_t; + +/** + * @brief HTT TX WBM Completion from firmware to host + * @details + * This structure is passed from firmware to host overlayed on wbm_release_ring + * DWORD 3 and 4 for software based completions (Exception frames and + * TQM bypass frames) + * For software based completions, wbm_release_ring->release_source_module will + * be set to release_source_fw + */ +PREPACK struct htt_tx_wbm_completion { + A_UINT32 + sch_cmd_id: 24, + /* If set, this packet was queued via exception path */ + exception_frame: 1, + rsvd0_31_25: 7; + + A_UINT32 + ack_frame_rssi: 8, /* If this frame is removed as the result of the + * reception of an ACK or BA, this field indicates + * the RSSI of the received ACK or BA frame. + * When the frame is removed as result of a direct + * remove command from the SW, this field is set + * to 0x0 (which is never a valid value when real + * RSSI is available). + * Units: dB w.r.t noise floor + */ + /* Takes enum values of htt_tx_fw2wbm_tx_status_t */ + tx_status: 4, + /* Takes enum values of htt_tx_fw2wbm_reinject_reason_t */ + reinject_reason: 4, + rsvd1_31_16: 16; +} POSTPACK; + +/* DWORD 0 */ +#define HTT_TX_WBM_COMPLETION_SCH_CMD_ID_M 0x00ffffff +#define HTT_TX_WBM_COMPLETION_SCH_CMD_ID_S 0 +#define HTT_TX_WBM_COMPLETION_EXP_FRAME_M 0x01000000 +#define HTT_TX_WBM_COMPLETION_EXP_FRAME_S 24 + +/* DWORD 1 */ +#define HTT_TX_WBM_COMPLETION_ACK_RSSI_M 0x000000ff +#define HTT_TX_WBM_COMPLETION_ACK_RSSI_S 0 +#define HTT_TX_WBM_COMPLETION_TX_STATUS_M 0x00000f00 +#define HTT_TX_WBM_COMPLETION_TX_STATUS_S 8 +#define HTT_TX_WBM_COMPLETION_REINJECT_REASON_M 0x0000f000 +#define HTT_TX_WBM_COMPLETION_REINJECT_REASON_S 12 + +/* DWORD 0 */ +#define HTT_TX_WBM_COMPLETION_SCH_CMD_ID_GET(_var) \ + (((_var) & HTT_TX_WBM_COMPLETION_SCH_CMD_ID_M) >> \ + HTT_TX_WBM_COMPLETION_SCH_CMD_ID_S) +#define HTT_TX_WBM_COMPLETION_SCH_CMD_ID_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_TX_WBM_COMPLETION_SCH_CMD_ID, _val);\ + ((_var) |= ((_val) << HTT_TX_WBM_COMPLETION_SCH_CMD_ID_S));\ + } while (0) + +#define HTT_TX_WBM_COMPLETION_EXP_FRAME_GET(_var) \ + (((_var) & HTT_TX_WBM_COMPLETION_EXP_FRAME_M) >> \ + HTT_TX_WBM_COMPLETION_EXP_FRAME_S) +#define HTT_TX_WBM_COMPLETION_EXP_FRAME_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_TX_WBM_COMPLETION_EXP_FRAME, _val);\ + ((_var) |= ((_val) << HTT_TX_WBM_COMPLETION_EXP_FRAME_S));\ + } while (0) + +/* DWORD 1 */ +#define HTT_TX_WBM_COMPLETION_ACK_RSSI_GET(_var) \ + (((_var) & HTT_TX_WBM_COMPLETION_ACK_RSSI_M) >> \ + HTT_TX_WBM_COMPLETION_ACK_RSSI_S) +#define HTT_TX_WBM_COMPLETION_ACK_RSSI_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_TX_WBM_COMPLETION_ACK_RSSI, _val);\ + ((_var) |= ((_val) << HTT_TX_WBM_COMPLETION_ACK_RSSI_S));\ + } while (0) + +#define HTT_TX_WBM_COMPLETION_TX_STATUS_GET(_var) \ + (((_var) & HTT_TX_WBM_COMPLETION_TX_STATUS_M) >> \ + HTT_TX_WBM_COMPLETION_TX_STATUS_S) +#define HTT_TX_WBM_COMPLETION_TX_STATUS_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_TX_WBM_COMPLETION_TX_STATUS, _val);\ + ((_var) |= ((_val) << HTT_TX_WBM_COMPLETION_TX_STATUS_S));\ + } while (0) + +#define HTT_TX_WBM_COMPLETION_REINJECT_REASON_GET(_var) \ + (((_var) & HTT_TX_WBM_COMPLETION_REINJECT_REASON_M) >> \ + HTT_TX_WBM_COMPLETION_REINJECT_REASON_S) +#define HTT_TX_WBM_COMPLETION_REINJECT_REASON_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_TX_WBM_COMPLETION_REINJECT_REASON, _val);\ + ((_var) |= ((_val) << \ + HTT_TX_WBM_COMPLETION_REINJECT_REASON_S)); \ + } while (0) + +typedef enum { + TX_FLOW_PRIORITY_BE, + TX_FLOW_PRIORITY_HIGH, + TX_FLOW_PRIORITY_LOW, +} htt_tx_flow_priority_t; + +typedef enum { + TX_FLOW_LATENCY_SENSITIVE, + TX_FLOW_LATENCY_INSENSITIVE, +} htt_tx_flow_latency_t; + +typedef enum { + TX_FLOW_BEST_EFFORT_TRAFFIC, + TX_FLOW_INTERACTIVE_TRAFFIC, + TX_FLOW_PERIODIC_TRAFFIC, + TX_FLOW_BURSTY_TRAFFIC, + TX_FLOW_OVER_SUBSCRIBED_TRAFFIC, +} htt_tx_flow_traffic_pattern_t; + +/** + * @brief HTT TX Flow search metadata format + * @details + * Host will set this metadata in flow table's flow search entry along with + * to_tqm_if_m0_fw. It indicates to forward the first MSDU to both the + * firmware and TQM ring if the flow search entry wins. + * This metadata is available to firmware in that first MSDU's + * tcl_exit_base->meta_data_fse. Firmware uses this metadata to map a new flow + * to one of the available flows for specific tid and returns the tqm flow + * pointer as part of htt_tx_map_flow_info message. + */ +PREPACK struct htt_tx_flow_metadata { + A_UINT32 + rsvd0_1_0: 2, + tid: 4, + /* Takes enum values of htt_tx_flow_priority_t */ + priority: 3, + /* Takes enum values of htt_tx_flow_traffic_pattern_t */ + traffic_pattern: 3, + /* If set, tid field in this struct is the final tid. + * Else choose final tid based on latency, priority. + */ + tid_override: 1, + dedicated_flowq: 1, /* Dedicated flowq per 5 tuple flow. */ + /* Takes enum values of htt_tx_flow_latency_t */ + latency_sensitive: 2, + /* Used by host to map flow metadata with flow entry */ + host_flow_identifier: 16; +} POSTPACK; + +/* DWORD 0 */ +#define HTT_TX_FLOW_METADATA_TID_M 0x0000003c +#define HTT_TX_FLOW_METADATA_TID_S 2 +#define HTT_TX_FLOW_METADATA_PRIORITY_M 0x000001c0 +#define HTT_TX_FLOW_METADATA_PRIORITY_S 6 +#define HTT_TX_FLOW_METADATA_TRAFFIC_PATTERN_M 0x00000e00 +#define HTT_TX_FLOW_METADATA_TRAFFIC_PATTERN_S 9 +#define HTT_TX_FLOW_METADATA_TID_OVERRIDE_M 0x00001000 +#define HTT_TX_FLOW_METADATA_TID_OVERRIDE_S 12 +#define HTT_TX_FLOW_METADATA_DEDICATED_FLOWQ_M 0x00002000 +#define HTT_TX_FLOW_METADATA_DEDICATED_FLOWQ_S 13 +#define HTT_TX_FLOW_METADATA_LATENCY_SENSITIVE_M 0x0000c000 +#define HTT_TX_FLOW_METADATA_LATENCY_SENSITIVE_S 14 +#define HTT_TX_FLOW_METADATA_HOST_FLOW_ID_M 0xffff0000 +#define HTT_TX_FLOW_METADATA_HOST_FLOW_ID_S 16 + +/* DWORD 0 */ +#define HTT_TX_FLOW_METADATA_TID_GET(_var) \ + (((_var) & HTT_TX_FLOW_METADATA_TID_M) >> \ + HTT_TX_FLOW_METADATA_TID_S) +#define HTT_TX_FLOW_METADATA_TID_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_TX_FLOW_METADATA_TID, _val); \ + ((_var) |= ((_val) << HTT_TX_FLOW_METADATA_TID_S)); \ + } while (0) + +#define HTT_TX_FLOW_METADATA_PRIORITY_GET(_var) \ + (((_var) & HTT_TX_FLOW_PRIORITY_M) >> \ + HTT_TX_FLOW_METADATA_PRIORITY_S) +#define HTT_TX_FLOW_METADATA_PRIORITY_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_TX_FLOW_METADATA_PRIORITY, _val); \ + ((_var) |= ((_val) << HTT_TX_FLOW_METADATA_PRIORITY_S));\ + } while (0) + +#define HTT_TX_FLOW_METADATA_TRAFFIC_PATTERN_GET(_var) \ + (((_var) & HTT_TX_FLOW_METADATA_TRAFFIC_PATTERN_M) >> \ + HTT_TX_FLOW_METADATA_TRAFFIC_PATTERN_S) +#define HTT_TX_FLOW_METADATA_TRAFFIC_PATTERN_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_TX_FLOW_METADATA_TRAFFIC_PATTERN, _val);\ + ((_var) |= ((_val) << HTT_TX_FLOW_METADATA_TRAFFIC_PATTERN_S));\ + } while (0) + +#define HTT_TX_FLOW_METADATA_TID_OVERRIDE_GET(_var) \ + (((_var) & HTT_TX_FLOW_METADATA_TID_OVERRIDE_M) >> \ + HTT_TX_FLOW_METADATA_TID_OVERRIDE_S) +#define HTT_TX_FLOW_METADATA_TID_OVERRIDE_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_TX_FLOW_METADATA_TID_OVERRIDE, _val);\ + ((_var) |= ((_val) << HTT_TX_FLOW_METADATA_TID_OVERRIDE_S));\ + } while (0) + +#define HTT_TX_FLOW_METADATA_DEDICATED_FLOWQ_GET(_var) \ + (((_var) & HTT_TX_FLOW_METADATA_DEDICATED_FLOWQ_M) >> \ + HTT_TX_FLOW_METADATA_DEDICATED_FLOWQ_S) +#define HTT_TX_FLOW_METADATA_DEDICATED_FLOWQ_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_TX_FLOW_METADATA_DEDICATED_FLOWQ, _val);\ + ((_var) |= ((_val) << HTT_TX_FLOW_METADATA_DEDICATED_FLOWQ_S));\ + } while (0) + +#define HTT_TX_FLOW_METADATA_LATENCY_SENSITIVE_GET(_var) \ + (((_var) & HTT_TX_FLOW_METADATA_LATENCY_SENSITIVE_M) >> \ + HTT_TX_FLOW_METADATA_LATENCY_SENSITIVE_S) +#define HTT_TX_FLOW_METADATA_LATENCY_SENSITIVE_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_TX_FLOW_LATENCY_SENSITIVE, _val); \ + ((_var) |= ((_val) << HTT_TX_FLOW_LATENCY_SENSITIVE_S));\ + } while (0) + +#define HTT_TX_FLOW_METADATA_HOST_FLOW_ID_GET(_var) \ + (((_var) & HTT_TX_FLOW_METADATA_HOST_FLOW_ID_M) >> \ + HTT_TX_FLOW_METADATA_HOST_FLOW_ID_S) +#define HTT_TX_FLOW_METADATA_HOST_FLOW_ID_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_TX_FLOW_METADATA_HOST_FLOW_ID, _val);\ + ((_var) |= ((_val) << HTT_TX_FLOW_METADATA_HOST_FLOW_ID_S));\ + } while (0) + +/** + * @brief for HTT_H2T_MSG_TYPE_ADD_WDS_ENTRY and + * HTT_H2T_MSG_TYPE_DELETE_WDS_ENTRY messages + * + * @details + * HTT wds entry from source port learning + * Host will learn wds entries from rx and send this message to firmware + * to enable firmware to configure/delete AST entries for wds clients. + * Firmware creates Source address's AST entry with Transmit MAC's peer_id + * and when SA's entry is deleted, firmware removes this AST entry + * + * The message would appear as follows: + * + * |31 30|29 |17 16|15 8|7 0| + * |----------------+----------------+----------------+----------------| + * | rsvd0 |PDVID| vdev_id | msg_type | + * |-------------------------------------------------------------------| + * | sa_addr_31_0 | + * |-------------------------------------------------------------------| + * | | ta_peer_id | sa_addr_47_32 | + * |-------------------------------------------------------------------| + * Where PDVID = pdev_id + * + * The message is interpreted as follows: + * + * dword0 - b'0:7 - msg_type: This will be set to + * HTT_H2T_MSG_TYPE_ADD_WDS_ENTRY or + * HTT_H2T_MSG_TYPE_DELETE_WDS_ENTRY + * + * dword0 - b'8:15 - vdev_id + * + * dword0 - b'16:17 - pdev_id + * + * dword0 - b'18:31 - rsvd10: Reserved for future use + * + * dword1 - b'0:31 - sa_addr_31_0: Lower 32 bits of source mac address + * + * dword2 - b'0:15 - sa_addr_47_32: Upper 16 bits of source mac address + * + * dword2 - b'16:19 - ta_peer_id: peer id of Transmit MAC + */ + +PREPACK struct htt_wds_entry { + A_UINT32 + msg_type: 8, + vdev_id: 8, + pdev_id: 2, + rsvd0: 14; + A_UINT32 sa_addr_31_0; + + A_UINT32 + sa_addr_47_32: 16, + ta_peer_id: 14, + rsvd2: 2; +} POSTPACK; + +/* DWORD 0 */ +#define HTT_WDS_ENTRY_VDEV_ID_M 0x0000ff00 +#define HTT_WDS_ENTRY_VDEV_ID_S 8 +#define HTT_WDS_ENTRY_PDEV_ID_M 0x00030000 +#define HTT_WDS_ENTRY_PDEV_ID_S 16 + +/* DWORD 2 */ +#define HTT_WDS_ENTRY_SA_ADDR_47_32_M 0x0000ffff +#define HTT_WDS_ENTRY_SA_ADDR_47_32_S 0 +#define HTT_WDS_ENTRY_TA_PEER_ID_M 0x3fff0000 +#define HTT_WDS_ENTRY_TA_PEER_ID_S 16 + +/* DWORD 0 */ +#define HTT_WDS_ENTRY_VDEV_ID_GET(_var) \ + (((_var) & HTT_WDS_ENTRY_VDEV_ID_M) >> \ + HTT_WDS_ENTRY_VDEV_ID_S) +#define HTT_WDS_ENTRY_VDEV_ID_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_WDS_ENTRY_VDEV_ID, _val); \ + ((_var) |= ((_val) << HTT_WDS_ENTRY_VDEV_ID_S)); \ + } while (0) + +#define HTT_WDS_ENTRY_PDEV_ID_GET(_var) \ + (((_var) & HTT_WDS_ENTRY_PDEV_ID_M) >> \ + HTT_WDS_ENTRY_PDEV_ID_S) +#define HTT_WDS_ENTRY_PDEV_ID_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_WDS_ENTRY_PDEV_ID, _val); \ + ((_var) |= ((_val) << HTT_WDS_ENTRY_PDEV_ID_S)); \ + } while (0) + +/* DWORD 2 */ +#define HTT_WDS_ENTRY_SA_ADDR_47_32_GET(_var) \ + (((_var) & HTT_WDS_ENTRY_SA_ADDR_47_32_M) >> \ + HTT_WDS_ENTRY_SA_ADDR_47_32_S) +#define HTT_WDS_ENTRY_SA_ADDR_47_32_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_WDS_ENTRY_SA_ADDR_47_32, _val); \ + ((_var) |= ((_val) << HTT_WDS_ENTRY_SA_ADDR_47_32_S)); \ + } while (0) + +#define HTT_WDS_ENTRY_TA_PEER_ID_GET(_var) \ + (((_var) & HTT_WDS_ENTRY_TA_PEER_ID_M) >> \ + HTT_WDS_ENTRY_TA_PEER_ID_S) +#define HTT_WDS_ENTRY_TA_PEER_ID_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_WDS_ENTRY_TA_PEER_ID, _val); \ + ((_var) |= ((_val) << HTT_WDS_ENTRY_TA_PEER_ID_S)); \ + } while (0) + + +/** + * @brief MAC DMA rx ring setup specification + * @details + * To allow for dynamic rx ring reconfiguration and to avoid race + * conditions, the host SW never directly programs the MAC DMA rx ring(s) + * it uses. Instead, it sends this message to the target, indicating how + * the rx ring used by the host should be set up and maintained. + * The message consists of a 4-octet header followed by 1 or 2 rx ring setup + * specifications. + * + * |31 16|15 8|7 0| + * |---------------------------------------------------------------| + * header: | reserved | num rings | msg type | + * |---------------------------------------------------------------| + * payload 1: | FW_IDX shadow register physical address (bits 31:0) | + #if HTT_PADDR64 + * | FW_IDX shadow register physical address (bits 63:32) | + #endif + * |---------------------------------------------------------------| + * | rx ring base physical address (bits 31:0) | + #if HTT_PADDR64 + * | rx ring base physical address (bits 63:32) | + #endif + * |---------------------------------------------------------------| + * | rx ring buffer size | rx ring length | + * |---------------------------------------------------------------| + * | FW_IDX initial value | enabled flags | + * |---------------------------------------------------------------| + * | MSDU payload offset | 802.11 header offset | + * |---------------------------------------------------------------| + * | PPDU end offset | PPDU start offset | + * |---------------------------------------------------------------| + * | MPDU end offset | MPDU start offset | + * |---------------------------------------------------------------| + * | MSDU end offset | MSDU start offset | + * |---------------------------------------------------------------| + * | frag info offset | rx attention offset | + * |---------------------------------------------------------------| + * payload 2, if present, has the same format as payload 1 + * Header fields: + * - MSG_TYPE + * Bits 7:0 + * Purpose: identifies this as an rx ring configuration message + * Value: 0x2 + * - NUM_RINGS + * Bits 15:8 + * Purpose: indicates whether the host is setting up one rx ring or two + * Value: 1 or 2 + * Payload: + * for systems using 64-bit format for bus addresses: + * - IDX_SHADOW_REG_PADDR_LO + * Bits 31:0 + * Value: lower 4 bytes of physical address of the host's + * FW_IDX shadow register + * - IDX_SHADOW_REG_PADDR_HI + * Bits 31:0 + * Value: upper 4 bytes of physical address of the host's + * FW_IDX shadow register + * - RING_BASE_PADDR_LO + * Bits 31:0 + * Value: lower 4 bytes of physical address of the host's rx ring + * - RING_BASE_PADDR_HI + * Bits 31:0 + * Value: uppper 4 bytes of physical address of the host's rx ring + * for systems using 32-bit format for bus addresses: + * - IDX_SHADOW_REG_PADDR + * Bits 31:0 + * Value: physical address of the host's FW_IDX shadow register + * - RING_BASE_PADDR + * Bits 31:0 + * Value: physical address of the host's rx ring + * - RING_LEN + * Bits 15:0 + * Value: number of elements in the rx ring + * - RING_BUF_SZ + * Bits 31:16 + * Value: size of the buffers referenced by the rx ring, in byte units + * - ENABLED_FLAGS + * Bits 15:0 + * Value: 1-bit flags to show whether different rx fields are enabled + * bit 0: 802.11 header enabled (1) or disabled (0) + * bit 1: MSDU payload enabled (1) or disabled (0) + * bit 2: PPDU start enabled (1) or disabled (0) + * bit 3: PPDU end enabled (1) or disabled (0) + * bit 4: MPDU start enabled (1) or disabled (0) + * bit 5: MPDU end enabled (1) or disabled (0) + * bit 6: MSDU start enabled (1) or disabled (0) + * bit 7: MSDU end enabled (1) or disabled (0) + * bit 8: rx attention enabled (1) or disabled (0) + * bit 9: frag info enabled (1) or disabled (0) + * bit 10: unicast rx enabled (1) or disabled (0) + * bit 11: multicast rx enabled (1) or disabled (0) + * bit 12: ctrl rx enabled (1) or disabled (0) + * bit 13: mgmt rx enabled (1) or disabled (0) + * bit 14: null rx enabled (1) or disabled (0) + * bit 15: phy data rx enabled (1) or disabled (0) + * - IDX_INIT_VAL + * Bits 31:16 + * Purpose: Specify the initial value for the FW_IDX. + * Value: the number of buffers initially present in the host's rx ring + * - OFFSET_802_11_HDR + * Bits 15:0 + * Value: offset in QUAD-bytes of 802.11 header from the buffer start + * - OFFSET_MSDU_PAYLOAD + * Bits 31:16 + * Value: offset in QUAD-bytes of MSDU payload from the buffer start + * - OFFSET_PPDU_START + * Bits 15:0 + * Value: offset in QUAD-bytes of PPDU start rx desc from the buffer start + * - OFFSET_PPDU_END + * Bits 31:16 + * Value: offset in QUAD-bytes of PPDU end rx desc from the buffer start + * - OFFSET_MPDU_START + * Bits 15:0 + * Value: offset in QUAD-bytes of MPDU start rx desc from the buffer start + * - OFFSET_MPDU_END + * Bits 31:16 + * Value: offset in QUAD-bytes of MPDU end rx desc from the buffer start + * - OFFSET_MSDU_START + * Bits 15:0 + * Value: offset in QUAD-bytes of MSDU start rx desc from the buffer start + * - OFFSET_MSDU_END + * Bits 31:16 + * Value: offset in QUAD-bytes of MSDU end rx desc from the buffer start + * - OFFSET_RX_ATTN + * Bits 15:0 + * Value: offset in QUAD-bytes of rx attention word from the buffer start + * - OFFSET_FRAG_INFO + * Bits 31:16 + * Value: offset in QUAD-bytes of frag info table + */ +/* header fields */ +#define HTT_RX_RING_CFG_NUM_RINGS_M 0xff00 +#define HTT_RX_RING_CFG_NUM_RINGS_S 8 + +/* payload fields */ +/* for systems using a 64-bit format for bus addresses */ +#define HTT_RX_RING_CFG_IDX_SHADOW_REG_PADDR_HI_M 0xffffffff +#define HTT_RX_RING_CFG_IDX_SHADOW_REG_PADDR_HI_S 0 +#define HTT_RX_RING_CFG_IDX_SHADOW_REG_PADDR_LO_M 0xffffffff +#define HTT_RX_RING_CFG_IDX_SHADOW_REG_PADDR_LO_S 0 +#define HTT_RX_RING_CFG_BASE_PADDR_HI_M 0xffffffff +#define HTT_RX_RING_CFG_BASE_PADDR_HI_S 0 +#define HTT_RX_RING_CFG_BASE_PADDR_LO_M 0xffffffff +#define HTT_RX_RING_CFG_BASE_PADDR_LO_S 0 + +/* for systems using a 32-bit format for bus addresses */ +#define HTT_RX_RING_CFG_IDX_SHADOW_REG_PADDR_M 0xffffffff +#define HTT_RX_RING_CFG_IDX_SHADOW_REG_PADDR_S 0 +#define HTT_RX_RING_CFG_BASE_PADDR_M 0xffffffff +#define HTT_RX_RING_CFG_BASE_PADDR_S 0 + +#define HTT_RX_RING_CFG_LEN_M 0xffff +#define HTT_RX_RING_CFG_LEN_S 0 +#define HTT_RX_RING_CFG_BUF_SZ_M 0xffff0000 +#define HTT_RX_RING_CFG_BUF_SZ_S 16 +#define HTT_RX_RING_CFG_ENABLED_802_11_HDR_M 0x1 +#define HTT_RX_RING_CFG_ENABLED_802_11_HDR_S 0 +#define HTT_RX_RING_CFG_ENABLED_MSDU_PAYLD_M 0x2 +#define HTT_RX_RING_CFG_ENABLED_MSDU_PAYLD_S 1 +#define HTT_RX_RING_CFG_ENABLED_PPDU_START_M 0x4 +#define HTT_RX_RING_CFG_ENABLED_PPDU_START_S 2 +#define HTT_RX_RING_CFG_ENABLED_PPDU_END_M 0x8 +#define HTT_RX_RING_CFG_ENABLED_PPDU_END_S 3 +#define HTT_RX_RING_CFG_ENABLED_MPDU_START_M 0x10 +#define HTT_RX_RING_CFG_ENABLED_MPDU_START_S 4 +#define HTT_RX_RING_CFG_ENABLED_MPDU_END_M 0x20 +#define HTT_RX_RING_CFG_ENABLED_MPDU_END_S 5 +#define HTT_RX_RING_CFG_ENABLED_MSDU_START_M 0x40 +#define HTT_RX_RING_CFG_ENABLED_MSDU_START_S 6 +#define HTT_RX_RING_CFG_ENABLED_MSDU_END_M 0x80 +#define HTT_RX_RING_CFG_ENABLED_MSDU_END_S 7 +#define HTT_RX_RING_CFG_ENABLED_RX_ATTN_M 0x100 +#define HTT_RX_RING_CFG_ENABLED_RX_ATTN_S 8 +#define HTT_RX_RING_CFG_ENABLED_FRAG_INFO_M 0x200 +#define HTT_RX_RING_CFG_ENABLED_FRAG_INFO_S 9 +#define HTT_RX_RING_CFG_ENABLED_UCAST_M 0x400 +#define HTT_RX_RING_CFG_ENABLED_UCAST_S 10 +#define HTT_RX_RING_CFG_ENABLED_MCAST_M 0x800 +#define HTT_RX_RING_CFG_ENABLED_MCAST_S 11 +#define HTT_RX_RING_CFG_ENABLED_CTRL_M 0x1000 +#define HTT_RX_RING_CFG_ENABLED_CTRL_S 12 +#define HTT_RX_RING_CFG_ENABLED_MGMT_M 0x2000 +#define HTT_RX_RING_CFG_ENABLED_MGMT_S 13 +#define HTT_RX_RING_CFG_ENABLED_NULL_M 0x4000 +#define HTT_RX_RING_CFG_ENABLED_NULL_S 14 +#define HTT_RX_RING_CFG_ENABLED_PHY_M 0x8000 +#define HTT_RX_RING_CFG_ENABLED_PHY_S 15 +#define HTT_RX_RING_CFG_IDX_INIT_VAL_M 0xffff0000 +#define HTT_RX_RING_CFG_IDX_INIT_VAL_S 16 +#define HTT_RX_RING_CFG_OFFSET_802_11_HDR_M 0xffff +#define HTT_RX_RING_CFG_OFFSET_802_11_HDR_S 0 +#define HTT_RX_RING_CFG_OFFSET_MSDU_PAYLD_M 0xffff0000 +#define HTT_RX_RING_CFG_OFFSET_MSDU_PAYLD_S 16 +#define HTT_RX_RING_CFG_OFFSET_PPDU_START_M 0xffff +#define HTT_RX_RING_CFG_OFFSET_PPDU_START_S 0 +#define HTT_RX_RING_CFG_OFFSET_PPDU_END_M 0xffff0000 +#define HTT_RX_RING_CFG_OFFSET_PPDU_END_S 16 +#define HTT_RX_RING_CFG_OFFSET_MPDU_START_M 0xffff +#define HTT_RX_RING_CFG_OFFSET_MPDU_START_S 0 +#define HTT_RX_RING_CFG_OFFSET_MPDU_END_M 0xffff0000 +#define HTT_RX_RING_CFG_OFFSET_MPDU_END_S 16 +#define HTT_RX_RING_CFG_OFFSET_MSDU_START_M 0xffff +#define HTT_RX_RING_CFG_OFFSET_MSDU_START_S 0 +#define HTT_RX_RING_CFG_OFFSET_MSDU_END_M 0xffff0000 +#define HTT_RX_RING_CFG_OFFSET_MSDU_END_S 16 +#define HTT_RX_RING_CFG_OFFSET_RX_ATTN_M 0xffff +#define HTT_RX_RING_CFG_OFFSET_RX_ATTN_S 0 +#define HTT_RX_RING_CFG_OFFSET_FRAG_INFO_M 0xffff0000 +#define HTT_RX_RING_CFG_OFFSET_FRAG_INFO_S 16 + +#define HTT_RX_RING_CFG_HDR_BYTES 4 +#define HTT_RX_RING_CFG_PAYLD_BYTES_64 44 +#define HTT_RX_RING_CFG_PAYLD_BYTES_32 36 +#if HTT_PADDR64 +#define HTT_RX_RING_CFG_PAYLD_BYTES HTT_RX_RING_CFG_PAYLD_BYTES_64 +#else +#define HTT_RX_RING_CFG_PAYLD_BYTES HTT_RX_RING_CFG_PAYLD_BYTES_32 +#endif +#define HTT_RX_RING_CFG_BYTES(num_rings) \ + (HTT_RX_RING_CFG_HDR_BYTES + (num_rings) * HTT_RX_RING_CFG_PAYLD_BYTES) + + +#define HTT_RX_RING_CFG_NUM_RINGS_GET(_var) \ + (((_var) & HTT_RX_RING_CFG_NUM_RINGS_M) >> HTT_RX_RING_CFG_NUM_RINGS_S) +#define HTT_RX_RING_CFG_NUM_RINGS_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_RING_CFG_NUM_RINGS, _val); \ + ((_var) |= ((_val) << HTT_RX_RING_CFG_NUM_RINGS_S)); \ + } while (0) + +/* degenerate case for 32-bit fields */ +#define HTT_RX_RING_CFG_IDX_SHADOW_REG_PADDR_HI_GET(_var) (_var) +#define HTT_RX_RING_CFG_IDX_SHADOW_REG_PADDR_HI_SET(_var, _val) \ + ((_var) = (_val)) +#define HTT_RX_RING_CFG_IDX_SHADOW_REG_PADDR_LO_GET(_var) (_var) +#define HTT_RX_RING_CFG_IDX_SHADOW_REG_PADDR_LO_SET(_var, _val) \ + ((_var) = (_val)) +#define HTT_RX_RING_CFG_IDX_SHADOW_REG_PADDR_GET(_var) (_var) +#define HTT_RX_RING_CFG_IDX_SHADOW_REG_PADDR_SET(_var, _val) \ + ((_var) = (_val)) + +/* degenerate case for 32-bit fields */ +#define HTT_RX_RING_CFG_BASE_PADDR_HI_GET(_var) (_var) +#define HTT_RX_RING_CFG_BASE_PADDR_HI_SET(_var, _val) ((_var) = (_val)) +#define HTT_RX_RING_CFG_BASE_PADDR_LO_GET(_var) (_var) +#define HTT_RX_RING_CFG_BASE_PADDR_LO_SET(_var, _val) ((_var) = (_val)) +#define HTT_RX_RING_CFG_BASE_PADDR_GET(_var) (_var) +#define HTT_RX_RING_CFG_BASE_PADDR_SET(_var, _val) ((_var) = (_val)) + +#define HTT_RX_RING_CFG_LEN_GET(_var) \ + (((_var) & HTT_RX_RING_CFG_LEN_M) >> HTT_RX_RING_CFG_LEN_S) +#define HTT_RX_RING_CFG_LEN_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_RING_CFG_LEN, _val); \ + ((_var) |= ((_val) << HTT_RX_RING_CFG_LEN_S)); \ + } while (0) + +#define HTT_RX_RING_CFG_BUF_SZ_GET(_var) \ + (((_var) & HTT_RX_RING_CFG_BUF_SZ_M) >> HTT_RX_RING_CFG_BUF_SZ_S) +#define HTT_RX_RING_CFG_BUF_SZ_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_RING_CFG_BUF_SZ, _val); \ + ((_var) |= ((_val) << HTT_RX_RING_CFG_BUF_SZ_S)); \ + } while (0) + +#define HTT_RX_RING_CFG_IDX_INIT_VAL_GET(_var) \ + (((_var) & HTT_RX_RING_CFG_IDX_INIT_VAL_M) >> \ + HTT_RX_RING_CFG_IDX_INIT_VAL_S) +#define HTT_RX_RING_CFG_IDX_INIT_VAL_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_RING_CFG_IDX_INIT_VAL, _val); \ + ((_var) |= ((_val) << HTT_RX_RING_CFG_IDX_INIT_VAL_S)); \ + } while (0) + +#define HTT_RX_RING_CFG_ENABLED_802_11_HDR_GET(_var) \ + (((_var) & HTT_RX_RING_CFG_ENABLED_802_11_HDR_M) >> \ + HTT_RX_RING_CFG_ENABLED_802_11_HDR_S) +#define HTT_RX_RING_CFG_ENABLED_802_11_HDR_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_RING_CFG_ENABLED_802_11_HDR, _val); \ + ((_var) |= ((_val) << HTT_RX_RING_CFG_ENABLED_802_11_HDR_S)); \ + } while (0) + +#define HTT_RX_RING_CFG_ENABLED_MSDU_PAYLD_GET(_var) \ + (((_var) & HTT_RX_RING_CFG_ENABLED_MSDU_PAYLD_M) >> \ + HTT_RX_RING_CFG_ENABLED_MSDU_PAYLD_S) +#define HTT_RX_RING_CFG_ENABLED_MSDU_PAYLD_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_RING_CFG_ENABLED_MSDU_PAYLD, _val); \ + ((_var) |= ((_val) << HTT_RX_RING_CFG_ENABLED_MSDU_PAYLD_S)); \ + } while (0) + +#define HTT_RX_RING_CFG_ENABLED_PPDU_START_GET(_var) \ + (((_var) & HTT_RX_RING_CFG_ENABLED_PPDU_START_M) >> \ + HTT_RX_RING_CFG_ENABLED_PPDU_START_S) +#define HTT_RX_RING_CFG_ENABLED_PPDU_START_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_RING_CFG_ENABLED_PPDU_START, _val); \ + ((_var) |= ((_val) << HTT_RX_RING_CFG_ENABLED_PPDU_START_S)); \ + } while (0) + +#define HTT_RX_RING_CFG_ENABLED_PPDU_END_GET(_var) \ + (((_var) & HTT_RX_RING_CFG_ENABLED_PPDU_END_M) >> \ + HTT_RX_RING_CFG_ENABLED_PPDU_END_S) +#define HTT_RX_RING_CFG_ENABLED_PPDU_END_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_RING_CFG_ENABLED_PPDU_END, _val); \ + ((_var) |= ((_val) << HTT_RX_RING_CFG_ENABLED_PPDU_END_S)); \ + } while (0) + +#define HTT_RX_RING_CFG_ENABLED_MPDU_START_GET(_var) \ + (((_var) & HTT_RX_RING_CFG_ENABLED_MPDU_START_M) >> \ + HTT_RX_RING_CFG_ENABLED_MPDU_START_S) +#define HTT_RX_RING_CFG_ENABLED_MPDU_START_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_RING_CFG_ENABLED_MPDU_START, _val); \ + ((_var) |= ((_val) << HTT_RX_RING_CFG_ENABLED_MPDU_START_S)); \ + } while (0) + +#define HTT_RX_RING_CFG_ENABLED_MPDU_END_GET(_var) \ + (((_var) & HTT_RX_RING_CFG_ENABLED_MPDU_END_M) >> \ + HTT_RX_RING_CFG_ENABLED_MPDU_END_S) +#define HTT_RX_RING_CFG_ENABLED_MPDU_END_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_RING_CFG_ENABLED_MPDU_END, _val); \ + ((_var) |= ((_val) << HTT_RX_RING_CFG_ENABLED_MPDU_END_S)); \ + } while (0) + +#define HTT_RX_RING_CFG_ENABLED_MSDU_START_GET(_var) \ + (((_var) & HTT_RX_RING_CFG_ENABLED_MSDU_START_M) >> \ + HTT_RX_RING_CFG_ENABLED_MSDU_START_S) +#define HTT_RX_RING_CFG_ENABLED_MSDU_START_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_RING_CFG_ENABLED_MSDU_START, _val); \ + ((_var) |= ((_val) << HTT_RX_RING_CFG_ENABLED_MSDU_START_S)); \ + } while (0) + +#define HTT_RX_RING_CFG_ENABLED_MSDU_END_GET(_var) \ + (((_var) & HTT_RX_RING_CFG_ENABLED_MSDU_END_M) >> \ + HTT_RX_RING_CFG_ENABLED_MSDU_END_S) +#define HTT_RX_RING_CFG_ENABLED_MSDU_END_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_RING_CFG_ENABLED_MSDU_END, _val); \ + ((_var) |= ((_val) << HTT_RX_RING_CFG_ENABLED_MSDU_END_S)); \ + } while (0) + +#define HTT_RX_RING_CFG_ENABLED_RX_ATTN_GET(_var) \ + (((_var) & HTT_RX_RING_CFG_ENABLED_RX_ATTN_M) >> \ + HTT_RX_RING_CFG_ENABLED_RX_ATTN_S) +#define HTT_RX_RING_CFG_ENABLED_RX_ATTN_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_RING_CFG_ENABLED_RX_ATTN, _val); \ + ((_var) |= ((_val) << HTT_RX_RING_CFG_ENABLED_RX_ATTN_S)); \ + } while (0) + +#define HTT_RX_RING_CFG_ENABLED_FRAG_INFO_GET(_var) \ + (((_var) & HTT_RX_RING_CFG_ENABLED_FRAG_INFO_M) >> \ + HTT_RX_RING_CFG_ENABLED_FRAG_INFO_S) +#define HTT_RX_RING_CFG_ENABLED_FRAG_INFO_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_RING_CFG_ENABLED_FRAG_INFO, _val); \ + ((_var) |= ((_val) << HTT_RX_RING_CFG_ENABLED_FRAG_INFO_S)); \ + } while (0) + +#define HTT_RX_RING_CFG_ENABLED_UCAST_GET(_var) \ + (((_var) & HTT_RX_RING_CFG_ENABLED_UCAST_M) >> \ + HTT_RX_RING_CFG_ENABLED_UCAST_S) +#define HTT_RX_RING_CFG_ENABLED_UCAST_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_RING_CFG_ENABLED_UCAST, _val); \ + ((_var) |= ((_val) << HTT_RX_RING_CFG_ENABLED_UCAST_S)); \ + } while (0) + +#define HTT_RX_RING_CFG_ENABLED_MCAST_GET(_var) \ + (((_var) & HTT_RX_RING_CFG_ENABLED_MCAST_M) >> \ + HTT_RX_RING_CFG_ENABLED_MCAST_S) +#define HTT_RX_RING_CFG_ENABLED_MCAST_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_RING_CFG_ENABLED_MCAST, _val); \ + ((_var) |= ((_val) << HTT_RX_RING_CFG_ENABLED_MCAST_S)); \ + } while (0) +#define HTT_RX_RING_CFG_ENABLED_CTRL_GET(_var) \ + (((_var) & HTT_RX_RING_CFG_ENABLED_CTRL_M) >> \ + HTT_RX_RING_CFG_ENABLED_CTRL_S) +#define HTT_RX_RING_CFG_ENABLED_CTRL_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_RING_CFG_ENABLED_CTRL, _val); \ + ((_var) |= ((_val) << HTT_RX_RING_CFG_ENABLED_CTRL_S)); \ + } while (0) +#define HTT_RX_RING_CFG_ENABLED_MGMT_GET(_var) \ + (((_var) & HTT_RX_RING_CFG_ENABLED_MGMT_M) >> \ + HTT_RX_RING_CFG_ENABLED_MGMT_S) +#define HTT_RX_RING_CFG_ENABLED_MGMT_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_RING_CFG_ENABLED_MGMT, _val); \ + ((_var) |= ((_val) << HTT_RX_RING_CFG_ENABLED_MGMT_S)); \ + } while (0) +#define HTT_RX_RING_CFG_ENABLED_NULL_GET(_var) \ + (((_var) & HTT_RX_RING_CFG_ENABLED_NULL_M) >> \ + HTT_RX_RING_CFG_ENABLED_NULL_S) +#define HTT_RX_RING_CFG_ENABLED_NULL_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_RING_CFG_ENABLED_NULL, _val); \ + ((_var) |= ((_val) << HTT_RX_RING_CFG_ENABLED_NULL_S)); \ + } while (0) +#define HTT_RX_RING_CFG_ENABLED_PHY_GET(_var) \ + (((_var) & HTT_RX_RING_CFG_ENABLED_PHY_M) >> \ + HTT_RX_RING_CFG_ENABLED_PHY_S) +#define HTT_RX_RING_CFG_ENABLED_PHY_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_RING_CFG_ENABLED_PHY, _val); \ + ((_var) |= ((_val) << HTT_RX_RING_CFG_ENABLED_PHY_S)); \ + } while (0) + +#define HTT_RX_RING_CFG_OFFSET_802_11_HDR_GET(_var) \ + (((_var) & HTT_RX_RING_CFG_OFFSET_802_11_HDR_M) >> \ + HTT_RX_RING_CFG_OFFSET_802_11_HDR_S) +#define HTT_RX_RING_CFG_OFFSET_802_11_HDR_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_RING_CFG_OFFSET_802_11_HDR, _val); \ + ((_var) |= ((_val) << HTT_RX_RING_CFG_OFFSET_802_11_HDR_S)); \ + } while (0) + +#define HTT_RX_RING_CFG_OFFSET_MSDU_PAYLD_GET(_var) \ + (((_var) & HTT_RX_RING_CFG_OFFSET_MSDU_PAYLD_M) >> \ + HTT_RX_RING_CFG_OFFSET_MSDU_PAYLD_S) +#define HTT_RX_RING_CFG_OFFSET_MSDU_PAYLD_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_RING_CFG_OFFSET_MSDU_PAYLD, _val); \ + ((_var) |= ((_val) << HTT_RX_RING_CFG_OFFSET_MSDU_PAYLD_S)); \ + } while (0) + +#define HTT_RX_RING_CFG_OFFSET_PPDU_START_GET(_var) \ + (((_var) & HTT_RX_RING_CFG_OFFSET_PPDU_START_M) >> \ + HTT_RX_RING_CFG_OFFSET_PPDU_START_S) +#define HTT_RX_RING_CFG_OFFSET_PPDU_START_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_RING_CFG_OFFSET_PPDU_START, _val); \ + ((_var) |= ((_val) << HTT_RX_RING_CFG_OFFSET_PPDU_START_S)); \ + } while (0) + +#define HTT_RX_RING_CFG_OFFSET_PPDU_END_GET(_var) \ + (((_var) & HTT_RX_RING_CFG_OFFSET_PPDU_END_M) >> \ + HTT_RX_RING_CFG_OFFSET_PPDU_END_S) +#define HTT_RX_RING_CFG_OFFSET_PPDU_END_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_RING_CFG_OFFSET_PPDU_END, _val); \ + ((_var) |= ((_val) << HTT_RX_RING_CFG_OFFSET_PPDU_END_S)); \ + } while (0) + +#define HTT_RX_RING_CFG_OFFSET_MPDU_START_GET(_var) \ + (((_var) & HTT_RX_RING_CFG_OFFSET_MPDU_START_M) >> \ + HTT_RX_RING_CFG_OFFSET_MPDU_START_S) +#define HTT_RX_RING_CFG_OFFSET_MPDU_START_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_RING_CFG_OFFSET_MPDU_START, _val); \ + ((_var) |= ((_val) << HTT_RX_RING_CFG_OFFSET_MPDU_START_S)); \ + } while (0) + +#define HTT_RX_RING_CFG_OFFSET_MPDU_END_GET(_var) \ + (((_var) & HTT_RX_RING_CFG_OFFSET_MPDU_END_M) >> \ + HTT_RX_RING_CFG_OFFSET_MPDU_END_S) +#define HTT_RX_RING_CFG_OFFSET_MPDU_END_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_RING_CFG_OFFSET_MPDU_END, _val); \ + ((_var) |= ((_val) << HTT_RX_RING_CFG_OFFSET_MPDU_END_S)); \ + } while (0) + +#define HTT_RX_RING_CFG_OFFSET_MSDU_START_GET(_var) \ + (((_var) & HTT_RX_RING_CFG_OFFSET_MSDU_START_M) >> \ + HTT_RX_RING_CFG_OFFSET_MSDU_START_S) +#define HTT_RX_RING_CFG_OFFSET_MSDU_START_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_RING_CFG_OFFSET_MSDU_START, _val); \ + ((_var) |= ((_val) << HTT_RX_RING_CFG_OFFSET_MSDU_START_S)); \ + } while (0) + +#define HTT_RX_RING_CFG_OFFSET_MSDU_END_GET(_var) \ + (((_var) & HTT_RX_RING_CFG_OFFSET_MSDU_END_M) >> \ + HTT_RX_RING_CFG_OFFSET_MSDU_END_S) +#define HTT_RX_RING_CFG_OFFSET_MSDU_END_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_RING_CFG_OFFSET_MSDU_END, _val); \ + ((_var) |= ((_val) << HTT_RX_RING_CFG_OFFSET_MSDU_END_S)); \ + } while (0) + +#define HTT_RX_RING_CFG_OFFSET_RX_ATTN_GET(_var) \ + (((_var) & HTT_RX_RING_CFG_OFFSET_RX_ATTN_M) >> \ + HTT_RX_RING_CFG_OFFSET_RX_ATTN_S) +#define HTT_RX_RING_CFG_OFFSET_RX_ATTN_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_RING_CFG_OFFSET_RX_ATTN, _val); \ + ((_var) |= ((_val) << HTT_RX_RING_CFG_OFFSET_RX_ATTN_S)); \ + } while (0) + +#define HTT_RX_RING_CFG_OFFSET_FRAG_INFO_GET(_var) \ + (((_var) & HTT_RX_RING_CFG_OFFSET_FRAG_INFO_M) >> \ + HTT_RX_RING_CFG_OFFSET_FRAG_INFO_S) +#define HTT_RX_RING_CFG_OFFSET_FRAG_INFO_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_RING_CFG_OFFSET_FRAG_INFO, _val); \ + ((_var) |= ((_val) << HTT_RX_RING_CFG_OFFSET_FRAG_INFO_S)); \ + } while (0) + +/** + * @brief host -> target FW statistics retrieve + * + * @details + * The following field definitions describe the format of the HTT host + * to target FW stats retrieve message. The message specifies the type of + * stats host wants to retrieve. + * + * |31 24|23 16|15 8|7 0| + * |-----------------------------------------------------------| + * | stats types request bitmask | msg type | + * |-----------------------------------------------------------| + * | stats types reset bitmask | reserved | + * |-----------------------------------------------------------| + * | stats type | config value | + * |-----------------------------------------------------------| + * | cookie LSBs | + * |-----------------------------------------------------------| + * | cookie MSBs | + * |-----------------------------------------------------------| + * Header fields: + * - MSG_TYPE + * Bits 7:0 + * Purpose: identifies this is a stats upload request message + * Value: 0x3 + * - UPLOAD_TYPES + * Bits 31:8 + * Purpose: identifies which types of FW statistics to upload + * Value: mask with bits set in positions defined by htt_dbg_stats_type + * - RESET_TYPES + * Bits 31:8 + * Purpose: identifies which types of FW statistics to reset + * Value: mask with bits set in positions defined by htt_dbg_stats_type + * - CFG_VAL + * Bits 23:0 + * Purpose: give an opaque configuration value to the specified stats type + * Value: stats-type specific configuration value + * if stats type == tx PPDU log, then CONFIG_VAL has the format: + * bits 7:0 - how many per-MPDU byte counts to include in a record + * bits 15:8 - how many per-MPDU MSDU counts to include in a record + * bits 23:16 - how many per-MSDU byte counts to include in a record + * - CFG_STAT_TYPE + * Bits 31:24 + * Purpose: specify which stats type (if any) the config value applies to + * Value: htt_dbg_stats_type value, or 0xff if the message doesn't have + * a valid configuration specification + * - COOKIE_LSBS + * Bits 31:0 + * Purpose: Provide a mechanism to match a target->host stats confirmation + * message with its preceding host->target stats request message. + * Value: LSBs of the opaque cookie specified by the host-side requestor + * - COOKIE_MSBS + * Bits 31:0 + * Purpose: Provide a mechanism to match a target->host stats confirmation + * message with its preceding host->target stats request message. + * Value: MSBs of the opaque cookie specified by the host-side requestor + */ + +#define HTT_H2T_STATS_REQ_MSG_SZ 20 /* bytes */ + +#define HTT_H2T_STATS_REQ_CFG_STAT_TYPE_INVALID 0xff + +#define HTT_H2T_STATS_REQ_UPLOAD_TYPES_M 0xffffff00 +#define HTT_H2T_STATS_REQ_UPLOAD_TYPES_S 8 + +#define HTT_H2T_STATS_REQ_RESET_TYPES_M 0xffffff00 +#define HTT_H2T_STATS_REQ_RESET_TYPES_S 8 + +#define HTT_H2T_STATS_REQ_CFG_VAL_M 0x00ffffff +#define HTT_H2T_STATS_REQ_CFG_VAL_S 0 + +#define HTT_H2T_STATS_REQ_CFG_STAT_TYPE_M 0xff000000 +#define HTT_H2T_STATS_REQ_CFG_STAT_TYPE_S 24 + +#define HTT_H2T_STATS_REQ_UPLOAD_TYPES_GET(_var) \ + (((_var) & HTT_H2T_STATS_REQ_UPLOAD_TYPES_M) >> \ + HTT_H2T_STATS_REQ_UPLOAD_TYPES_S) +#define HTT_H2T_STATS_REQ_UPLOAD_TYPES_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_H2T_STATS_REQ_UPLOAD_TYPES, _val); \ + ((_var) |= ((_val) << HTT_H2T_STATS_REQ_UPLOAD_TYPES_S)); \ + } while (0) + +#define HTT_H2T_STATS_REQ_RESET_TYPES_GET(_var) \ + (((_var) & HTT_H2T_STATS_REQ_RESET_TYPES_M) >> \ + HTT_H2T_STATS_REQ_RESET_TYPES_S) +#define HTT_H2T_STATS_REQ_RESET_TYPES_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_H2T_STATS_REQ_RESET_TYPES, _val); \ + ((_var) |= ((_val) << HTT_H2T_STATS_REQ_RESET_TYPES_S)); \ + } while (0) + +#define HTT_H2T_STATS_REQ_CFG_VAL_GET(_var) \ + (((_var) & HTT_H2T_STATS_REQ_CFG_VAL_M) >> \ + HTT_H2T_STATS_REQ_CFG_VAL_S) +#define HTT_H2T_STATS_REQ_CFG_VAL_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_H2T_STATS_REQ_CFG_VAL, _val); \ + ((_var) |= ((_val) << HTT_H2T_STATS_REQ_CFG_VAL_S)); \ + } while (0) + +#define HTT_H2T_STATS_REQ_CFG_STAT_TYPE_GET(_var) \ + (((_var) & HTT_H2T_STATS_REQ_CFG_STAT_TYPE_M) >> \ + HTT_H2T_STATS_REQ_CFG_STAT_TYPE_S) +#define HTT_H2T_STATS_REQ_CFG_STAT_TYPE_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_H2T_STATS_REQ_CFG_STAT_TYPE, _val); \ + ((_var) |= ((_val) << HTT_H2T_STATS_REQ_CFG_STAT_TYPE_S)); \ + } while (0) + +/** + * @brief host -> target HTT out-of-band sync request + * + * @details + * The HTT SYNC tells the target to suspend processing of subsequent + * HTT host-to-target messages until some other target agent locally + * informs the target HTT FW that the current sync counter is equal to + * or greater than (in a modulo sense) the sync counter specified in + * the SYNC message. + * This allows other host-target components to synchronize their operation + * with HTT, e.g. to ensure that tx frames don't get transmitted until a + * security key has been downloaded to and activated by the target. + * In the absence of any explicit synchronization counter value + * specification, the target HTT FW will use zero as the default current + * sync value. + * + * |31 24|23 16|15 8|7 0| + * |-----------------------------------------------------------| + * | reserved | sync count | msg type | + * |-----------------------------------------------------------| + * Header fields: + * - MSG_TYPE + * Bits 7:0 + * Purpose: identifies this as a sync message + * Value: 0x4 + * - SYNC_COUNT + * Bits 15:8 + * Purpose: specifies what sync value the HTT FW will wait for from + * an out-of-band specification to resume its operation + * Value: in-band sync counter value to compare against the out-of-band + * counter spec. + * The HTT target FW will suspend its host->target message processing + * as long as + * 0 < (in-band sync counter - out-of-band sync counter) & 0xff < 128 + */ + +#define HTT_H2T_SYNC_MSG_SZ 4 + +#define HTT_H2T_SYNC_COUNT_M 0x0000ff00 +#define HTT_H2T_SYNC_COUNT_S 8 + +#define HTT_H2T_SYNC_COUNT_GET(_var) \ + (((_var) & HTT_H2T_SYNC_COUNT_M) >> \ + HTT_H2T_SYNC_COUNT_S) +#define HTT_H2T_SYNC_COUNT_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_H2T_SYNC_COUNT, _val); \ + ((_var) |= ((_val) << HTT_H2T_SYNC_COUNT_S)); \ + } while (0) + + +/** + * @brief HTT aggregation configuration + */ +#define HTT_AGGR_CFG_MSG_SZ 4 + +#define HTT_AGGR_CFG_MAX_NUM_AMPDU_SUBFRM_M 0xff00 +#define HTT_AGGR_CFG_MAX_NUM_AMPDU_SUBFRM_S 8 +#define HTT_AGGR_CFG_MAX_NUM_AMSDU_SUBFRM_M 0x1f0000 +#define HTT_AGGR_CFG_MAX_NUM_AMSDU_SUBFRM_S 16 + +#define HTT_AGGR_CFG_MAX_NUM_AMPDU_SUBFRM_GET(_var) \ + (((_var) & HTT_AGGR_CFG_MAX_NUM_AMPDU_SUBFRM_M) >> \ + HTT_AGGR_CFG_MAX_NUM_AMPDU_SUBFRM_S) +#define HTT_AGGR_CFG_MAX_NUM_AMPDU_SUBFRM_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_AGGR_CFG_MAX_NUM_AMPDU_SUBFRM, _val); \ + ((_var) |= ((_val) << HTT_AGGR_CFG_MAX_NUM_AMPDU_SUBFRM_S)); \ + } while (0) + +#define HTT_AGGR_CFG_MAX_NUM_AMSDU_SUBFRM_GET(_var) \ + (((_var) & HTT_AGGR_CFG_MAX_NUM_AMSDU_SUBFRM_M) >> \ + HTT_AGGR_CFG_MAX_NUM_AMSDU_SUBFRM_S) +#define HTT_AGGR_CFG_MAX_NUM_AMSDU_SUBFRM_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_AGGR_CFG_MAX_NUM_AMSDU_SUBFRM, _val); \ + ((_var) |= ((_val) << HTT_AGGR_CFG_MAX_NUM_AMSDU_SUBFRM_S)); \ + } while (0) + + +/** + * @brief host -> target HTT configure max amsdu info per vdev + * + * @details + * The HTT AGGR CFG EX tells the target to configure max_amsdu info per vdev + * + * |31 21|20 16|15 8|7 0| + * |-----------------------------------------------------------| + * | reserved | vdev id | max amsdu | msg type | + * |-----------------------------------------------------------| + * Header fields: + * - MSG_TYPE + * Bits 7:0 + * Purpose: identifies this as a aggr cfg ex message + * Value: 0xa + * - MAX_NUM_AMSDU_SUBFRM + * Bits 15:8 + * Purpose: max MSDUs per A-MSDU + * - VDEV_ID + * Bits 20:16 + * Purpose: ID of the vdev to which this limit is applied + */ +#define HTT_AGGR_CFG_EX_MSG_SZ 4 + +#define HTT_AGGR_CFG_EX_MAX_NUM_AMSDU_SUBFRM_M 0xff00 +#define HTT_AGGR_CFG_EX_MAX_NUM_AMSDU_SUBFRM_S 8 +#define HTT_AGGR_CFG_EX_VDEV_ID_M 0x1f0000 +#define HTT_AGGR_CFG_EX_VDEV_ID_S 16 + +#define HTT_AGGR_CFG_EX_MAX_NUM_AMSDU_SUBFRM_GET(_var) \ + (((_var) & HTT_AGGR_CFG_EX_MAX_NUM_AMSDU_SUBFRM_M) >> \ + HTT_AGGR_CFG_EX_MAX_NUM_AMSDU_SUBFRM_S) +#define HTT_AGGR_CFG_EX_MAX_NUM_AMSDU_SUBFRM_SET(_var, _val) \ +do { \ + HTT_CHECK_SET_VAL(HTT_AGGR_CFG_EX_MAX_NUM_AMSDU_SUBFRM, _val); \ + ((_var) |= ((_val) << HTT_AGGR_CFG_EX_MAX_NUM_AMSDU_SUBFRM_S)); \ +} while (0) + +#define HTT_AGGR_CFG_EX_VDEV_ID_GET(_var) \ + (((_var) & HTT_AGGR_CFG_EX_VDEV_ID_M) >> \ + HTT_AGGR_CFG_EX_VDEV_ID_S) +#define HTT_AGGR_CFG_EX_VDEV_ID_SET(_var, _val) \ +do { \ + HTT_CHECK_SET_VAL(HTT_AGGR_CFG_EX_VDEV_ID, _val); \ + ((_var) |= ((_val) << HTT_AGGR_CFG_EX_VDEV_ID_S)); \ +} while (0) + +/** + * @brief HTT WDI_IPA Config Message + * + * @details + * The HTT WDI_IPA config message is created/sent by host at driver + * init time. It contains information about data structures used on + * WDI_IPA TX and RX path. + * TX CE ring is used for pushing packet metadata from IPA uC + * to WLAN FW + * TX Completion ring is used for generating TX completions from + * WLAN FW to IPA uC + * RX Indication ring is used for indicating RX packets from FW + * to IPA uC + * RX Ring2 is used as either completion ring or as second + * indication ring. when Ring2 is used as completion ring, IPA uC + * puts completed RX packet meta data to Ring2. when Ring2 is used + * as second indication ring, RX packets for LTE-WLAN aggregation are + * indicated in Ring2, other RX packets (e.g. hotspot related) are + * indicated in RX Indication ring. Please see WDI_IPA specification + * for more details. + * |31 24|23 16|15 8|7 0| + * |----------------+----------------+----------------+----------------| + * | tx pkt pool size | Rsvd | msg_type | + * |-------------------------------------------------------------------| + * | tx comp ring base (bits 31:0) | +#if HTT_PADDR64 + * | tx comp ring base (bits 63:32) | +#endif + * |-------------------------------------------------------------------| + * | tx comp ring size | + * |-------------------------------------------------------------------| + * | tx comp WR_IDX physical address (bits 31:0) | +#if HTT_PADDR64 + * | tx comp WR_IDX physical address (bits 63:32) | +#endif + * |-------------------------------------------------------------------| + * | tx CE WR_IDX physical address (bits 31:0) | +#if HTT_PADDR64 + * | tx CE WR_IDX physical address (bits 63:32) | +#endif + * |-------------------------------------------------------------------| + * | rx indication ring base (bits 31:0) | +#if HTT_PADDR64 + * | rx indication ring base (bits 63:32) | +#endif + * |-------------------------------------------------------------------| + * | rx indication ring size | + * |-------------------------------------------------------------------| + * | rx ind RD_IDX physical address (bits 31:0) | +#if HTT_PADDR64 + * | rx ind RD_IDX physical address (bits 63:32) | +#endif + * |-------------------------------------------------------------------| + * | rx ind WR_IDX physical address (bits 31:0) | +#if HTT_PADDR64 + * | rx ind WR_IDX physical address (bits 63:32) | +#endif + * |-------------------------------------------------------------------| + * |-------------------------------------------------------------------| + * | rx ring2 base (bits 31:0) | +#if HTT_PADDR64 + * | rx ring2 base (bits 63:32) | +#endif + * |-------------------------------------------------------------------| + * | rx ring2 size | + * |-------------------------------------------------------------------| + * | rx ring2 RD_IDX physical address (bits 31:0) | +#if HTT_PADDR64 + * | rx ring2 RD_IDX physical address (bits 63:32) | +#endif + * |-------------------------------------------------------------------| + * | rx ring2 WR_IDX physical address (bits 31:0) | +#if HTT_PADDR64 + * | rx ring2 WR_IDX physical address (bits 63:32) | +#endif + * |-------------------------------------------------------------------| + * + * Header fields: + * Header fields: + * - MSG_TYPE + * Bits 7:0 + * Purpose: Identifies this as WDI_IPA config message + * value: = 0x8 + * - TX_PKT_POOL_SIZE + * Bits 15:0 + * Purpose: Total number of TX packet buffer pool allocated by Host for + * WDI_IPA TX path + * For systems using 32-bit format for bus addresses: + * - TX_COMP_RING_BASE_ADDR + * Bits 31:0 + * Purpose: TX Completion Ring base address in DDR + * - TX_COMP_RING_SIZE + * Bits 31:0 + * Purpose: TX Completion Ring size (must be power of 2) + * - TX_COMP_WR_IDX_ADDR + * Bits 31:0 + * Purpose: IPA doorbell register address OR DDR address where WIFI FW + * updates the Write Index for WDI_IPA TX completion ring + * - TX_CE_WR_IDX_ADDR + * Bits 31:0 + * Purpose: DDR address where IPA uC + * updates the WR Index for TX CE ring + * (needed for fusion platforms) + * - RX_IND_RING_BASE_ADDR + * Bits 31:0 + * Purpose: RX Indication Ring base address in DDR + * - RX_IND_RING_SIZE + * Bits 31:0 + * Purpose: RX Indication Ring size + * - RX_IND_RD_IDX_ADDR + * Bits 31:0 + * Purpose: DDR address where IPA uC updates the Read Index for WDI_IPA + * RX indication ring + * - RX_IND_WR_IDX_ADDR + * Bits 31:0 + * Purpose: IPA doorbell register address OR DDR address where WIFI FW + * updates the Write Index for WDI_IPA RX indication ring + * - RX_RING2_BASE_ADDR + * Bits 31:0 + * Purpose: Second RX Ring(Indication or completion)base address in DDR + * - RX_RING2_SIZE + * Bits 31:0 + * Purpose: Second RX Ring size (must be >= RX_IND_RING_SIZE) + * - RX_RING2_RD_IDX_ADDR + * Bits 31:0 + * Purpose: If Second RX ring is Indication ring, DDR address where + * IPA uC updates the Read Index for Ring2. + * If Second RX ring is completion ring, this is NOT used + * - RX_RING2_WR_IDX_ADDR + * Bits 31:0 + * Purpose: If Second RX ring is Indication ring, DDR address where + * WIFI FW updates the Write Index for WDI_IPA RX ring2 + * If second RX ring is completion ring, DDR address where + * IPA uC updates the Write Index for Ring 2. + * For systems using 64-bit format for bus addresses: + * - TX_COMP_RING_BASE_ADDR_LO + * Bits 31:0 + * Purpose: Lower 4 bytes of TX Completion Ring base physical + * address in DDR + * - TX_COMP_RING_BASE_ADDR_HI + * Bits 31:0 + * Purpose: Higher 4 bytes of TX Completion Ring base physical + * address in DDR + * - TX_COMP_RING_SIZE + * Bits 31:0 + * Purpose: TX Completion Ring size (must be power of 2) + * - TX_COMP_WR_IDX_ADDR_LO + * Bits 31:0 + * Purpose: Lower 4 bytes of IPA doorbell register address OR + * Lower 4 bytes of DDR address where WIFI FW + * updates the Write Index for WDI_IPA TX completion ring + * - TX_COMP_WR_IDX_ADDR_HI + * Bits 31:0 + * Purpose: Higher 4 bytes of IPA doorbell register address OR + * Higher 4 bytes of DDR address where WIFI FW + * updates the Write Index for WDI_IPA TX completion ring + * - TX_CE_WR_IDX_ADDR_LO + * Bits 31:0 + * Purpose: Lower 4 bytes of DDR address where IPA uC + * updates the WR Index for TX CE ring + * (needed for fusion platforms) + * - TX_CE_WR_IDX_ADDR_HI + * Bits 31:0 + * Purpose: Higher 4 bytes of DDR address where IPA uC + * updates the WR Index for TX CE ring + * (needed for fusion platforms) + * - RX_IND_RING_BASE_ADDR_LO + * Bits 31:0 + * Purpose: Lower 4 bytes of RX Indication Ring base address in DDR + * - RX_IND_RING_BASE_ADDR_HI + * Bits 31:0 + * Purpose: Higher 4 bytes of RX Indication Ring base address in DDR + * - RX_IND_RING_SIZE + * Bits 31:0 + * Purpose: RX Indication Ring size + * - RX_IND_RD_IDX_ADDR_LO + * Bits 31:0 + * Purpose: Lower 4 bytes of DDR address where IPA uC updates the + * Read Index for WDI_IPA RX indication ring + * - RX_IND_RD_IDX_ADDR_HI + * Bits 31:0 + * Purpose: Higher 4 bytes of DDR address where IPA uC updates the + * Read Index for WDI_IPA RX indication ring + * - RX_IND_WR_IDX_ADDR_LO + * Bits 31:0 + * Purpose: Lower 4 bytes of IPA doorbell register address OR + * Lower 4 bytes of DDR address where WIFI FW + * updates the Write Index for WDI_IPA RX indication ring + * - RX_IND_WR_IDX_ADDR_HI + * Bits 31:0 + * Purpose: Higher 4 bytes of IPA doorbell register address OR + * Higher 4 bytes of DDR address where WIFI FW + * updates the Write Index for WDI_IPA RX indication ring + * - RX_RING2_BASE_ADDR_LO + * Bits 31:0 + * Purpose: Lower 4 bytes of Second RX Ring(Indication OR completion) + * base address in DDR + * - RX_RING2_BASE_ADDR_HI + * Bits 31:0 + * Purpose: Higher 4 bytes of Second RX Ring(Indication OR completion) + * base address in DDR + * - RX_RING2_SIZE + * Bits 31:0 + * Purpose: Second RX Ring size (must be >= RX_IND_RING_SIZE) + * - RX_RING2_RD_IDX_ADDR_LO + * Bits 31:0 + * Purpose: If Second RX ring is Indication ring, lower 4 bytes of + * DDR address where IPA uC updates the Read Index for Ring2. + * If Second RX ring is completion ring, this is NOT used + * - RX_RING2_RD_IDX_ADDR_HI + * Bits 31:0 + * Purpose: If Second RX ring is Indication ring, higher 4 bytes of + * DDR address where IPA uC updates the Read Index for Ring2. + * If Second RX ring is completion ring, this is NOT used + * - RX_RING2_WR_IDX_ADDR_LO + * Bits 31:0 + * Purpose: If Second RX ring is Indication ring, lower 4 bytes of + * DDR address where WIFI FW updates the Write Index + * for WDI_IPA RX ring2 + * If second RX ring is completion ring, lower 4 bytes of + * DDR address where IPA uC updates the Write Index for Ring 2. + * - RX_RING2_WR_IDX_ADDR_HI + * Bits 31:0 + * Purpose: If Second RX ring is Indication ring, higher 4 bytes of + * DDR address where WIFI FW updates the Write Index + * for WDI_IPA RX ring2 + * If second RX ring is completion ring, higher 4 bytes of + * DDR address where IPA uC updates the Write Index for Ring 2. + */ + +#if HTT_PADDR64 +#define HTT_WDI_IPA_CFG_SZ 88 /* bytes */ +#else +#define HTT_WDI_IPA_CFG_SZ 52 /* bytes */ +#endif + +#define HTT_WDI_IPA_CFG_TX_PKT_POOL_SIZE_M 0xffff0000 +#define HTT_WDI_IPA_CFG_TX_PKT_POOL_SIZE_S 16 + +#define HTT_WDI_IPA_CFG_TX_COMP_RING_BASE_ADDR_M 0xffffffff +#define HTT_WDI_IPA_CFG_TX_COMP_RING_BASE_ADDR_S 0 + +#define HTT_WDI_IPA_CFG_TX_COMP_RING_BASE_ADDR_LO_M 0xffffffff +#define HTT_WDI_IPA_CFG_TX_COMP_RING_BASE_ADDR_LO_S 0 + +#define HTT_WDI_IPA_CFG_TX_COMP_RING_BASE_ADDR_HI_M 0xffffffff +#define HTT_WDI_IPA_CFG_TX_COMP_RING_BASE_ADDR_HI_S 0 + +#define HTT_WDI_IPA_CFG_TX_COMP_RING_SIZE_M 0xffffffff +#define HTT_WDI_IPA_CFG_TX_COMP_RING_SIZE_S 0 + +#define HTT_WDI_IPA_CFG_TX_COMP_WR_IDX_ADDR_M 0xffffffff +#define HTT_WDI_IPA_CFG_TX_COMP_WR_IDX_ADDR_S 0 + +#define HTT_WDI_IPA_CFG_TX_COMP_WR_IDX_ADDR_LO_M 0xffffffff +#define HTT_WDI_IPA_CFG_TX_COMP_WR_IDX_ADDR_LO_S 0 + +#define HTT_WDI_IPA_CFG_TX_COMP_WR_IDX_ADDR_HI_M 0xffffffff +#define HTT_WDI_IPA_CFG_TX_COMP_WR_IDX_ADDR_HI_S 0 + +#define HTT_WDI_IPA_CFG_TX_CE_WR_IDX_ADDR_M 0xffffffff +#define HTT_WDI_IPA_CFG_TX_CE_WR_IDX_ADDR_S 0 + +#define HTT_WDI_IPA_CFG_TX_CE_WR_IDX_ADDR_LO_M 0xffffffff +#define HTT_WDI_IPA_CFG_TX_CE_WR_IDX_ADDR_LO_S 0 + +#define HTT_WDI_IPA_CFG_TX_CE_WR_IDX_ADDR_HI_M 0xffffffff +#define HTT_WDI_IPA_CFG_TX_CE_WR_IDX_ADDR_HI_S 0 + +#define HTT_WDI_IPA_CFG_RX_IND_RING_BASE_ADDR_M 0xffffffff +#define HTT_WDI_IPA_CFG_RX_IND_RING_BASE_ADDR_S 0 + +#define HTT_WDI_IPA_CFG_RX_IND_RING_BASE_ADDR_LO_M 0xffffffff +#define HTT_WDI_IPA_CFG_RX_IND_RING_BASE_ADDR_LO_S 0 + +#define HTT_WDI_IPA_CFG_RX_IND_RING_BASE_ADDR_HI_M 0xffffffff +#define HTT_WDI_IPA_CFG_RX_IND_RING_BASE_ADDR_HI_S 0 + +#define HTT_WDI_IPA_CFG_RX_IND_RING_SIZE_M 0xffffffff +#define HTT_WDI_IPA_CFG_RX_IND_RING_SIZE_S 0 + +#define HTT_WDI_IPA_CFG_RX_IND_RD_IDX_ADDR_M 0xffffffff +#define HTT_WDI_IPA_CFG_RX_IND_RD_IDX_ADDR_S 0 + +#define HTT_WDI_IPA_CFG_RX_IND_RD_IDX_ADDR_LO_M 0xffffffff +#define HTT_WDI_IPA_CFG_RX_IND_RD_IDX_ADDR_LO_S 0 + +#define HTT_WDI_IPA_CFG_RX_IND_RD_IDX_ADDR_HI_M 0xffffffff +#define HTT_WDI_IPA_CFG_RX_IND_RD_IDX_ADDR_HI_S 0 + +#define HTT_WDI_IPA_CFG_RX_IND_WR_IDX_ADDR_M 0xffffffff +#define HTT_WDI_IPA_CFG_RX_IND_WR_IDX_ADDR_S 0 + +#define HTT_WDI_IPA_CFG_RX_IND_WR_IDX_ADDR_LO_M 0xffffffff +#define HTT_WDI_IPA_CFG_RX_IND_WR_IDX_ADDR_LO_S 0 + +#define HTT_WDI_IPA_CFG_RX_IND_WR_IDX_ADDR_HI_M 0xffffffff +#define HTT_WDI_IPA_CFG_RX_IND_WR_IDX_ADDR_HI_S 0 + +#define HTT_WDI_IPA_CFG_RX_RING2_BASE_ADDR_M 0xffffffff +#define HTT_WDI_IPA_CFG_RX_RING2_BASE_ADDR_S 0 + +#define HTT_WDI_IPA_CFG_RX_RING2_BASE_ADDR_LO_M 0xffffffff +#define HTT_WDI_IPA_CFG_RX_RING2_BASE_ADDR_LO_S 0 + +#define HTT_WDI_IPA_CFG_RX_RING2_BASE_ADDR_HI_M 0xffffffff +#define HTT_WDI_IPA_CFG_RX_RING2_BASE_ADDR_HI_S 0 + +#define HTT_WDI_IPA_CFG_RX_RING2_SIZE_M 0xffffffff +#define HTT_WDI_IPA_CFG_RX_RING2_SIZE_S 0 + +#define HTT_WDI_IPA_CFG_RX_RING2_RD_IDX_ADDR_M 0xffffffff +#define HTT_WDI_IPA_CFG_RX_RING2_RD_IDX_ADDR_S 0 + +#define HTT_WDI_IPA_CFG_RX_RING2_RD_IDX_ADDR_LO_M 0xffffffff +#define HTT_WDI_IPA_CFG_RX_RING2_RD_IDX_ADDR_LO_S 0 + +#define HTT_WDI_IPA_CFG_RX_RING2_RD_IDX_ADDR_HI_M 0xffffffff +#define HTT_WDI_IPA_CFG_RX_RING2_RD_IDX_ADDR_HI_S 0 + +#define HTT_WDI_IPA_CFG_RX_RING2_WR_IDX_ADDR_M 0xffffffff +#define HTT_WDI_IPA_CFG_RX_RING2_WR_IDX_ADDR_S 0 + +#define HTT_WDI_IPA_CFG_RX_RING2_WR_IDX_ADDR_LO_M 0xffffffff +#define HTT_WDI_IPA_CFG_RX_RING2_WR_IDX_ADDR_LO_S 0 + +#define HTT_WDI_IPA_CFG_RX_RING2_WR_IDX_ADDR_HI_M 0xffffffff +#define HTT_WDI_IPA_CFG_RX_RING2_WR_IDX_ADDR_HI_S 0 + +#define HTT_WDI_IPA_CFG_TX_PKT_POOL_SIZE_GET(_var) \ + (((_var) & HTT_WDI_IPA_CFG_TX_PKT_POOL_SIZE_M) >> \ + HTT_WDI_IPA_CFG_TX_PKT_POOL_SIZE_S) +#define HTT_WDI_IPA_CFG_TX_PKT_POOL_SIZE_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_WDI_IPA_CFG_TX_PKT_POOL_SIZE, _val); \ + ((_var) |= ((_val) << HTT_WDI_IPA_CFG_TX_PKT_POOL_SIZE_S)); \ + } while (0) + +/* for systems using 32-bit format for bus addr */ +#define HTT_WDI_IPA_CFG_TX_COMP_RING_BASE_ADDR_GET(_var) \ + (((_var) & HTT_WDI_IPA_CFG_TX_COMP_RING_BASE_ADDR_M) >> \ + HTT_WDI_IPA_CFG_TX_COMP_RING_BASE_ADDR_S) +#define HTT_WDI_IPA_CFG_TX_COMP_RING_BASE_ADDR_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL( \ + HTT_WDI_IPA_CFG_TX_COMP_RING_BASE_ADDR, _val);\ + ((_var) |= \ + ((_val) << HTT_WDI_IPA_CFG_TX_COMP_RING_BASE_ADDR_S)); \ + } while (0) + +/* for systems using 64-bit format for bus addr */ +#define HTT_WDI_IPA_CFG_TX_COMP_RING_BASE_ADDR_HI_GET(_var) \ + (((_var) & HTT_WDI_IPA_CFG_TX_COMP_RING_BASE_ADDR_HI_M) >> \ + HTT_WDI_IPA_CFG_TX_COMP_RING_BASE_ADDR_HI_S) +#define HTT_WDI_IPA_CFG_TX_COMP_RING_BASE_ADDR_HI_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL( \ + HTT_WDI_IPA_CFG_TX_COMP_RING_BASE_ADDR_HI, _val);\ + ((_var) |= \ + ((_val) << \ + HTT_WDI_IPA_CFG_TX_COMP_RING_BASE_ADDR_HI_S)); \ + } while (0) + +/* for systems using 64-bit format for bus addr */ +#define HTT_WDI_IPA_CFG_TX_COMP_RING_BASE_ADDR_LO_GET(_var) \ + (((_var) & HTT_WDI_IPA_CFG_TX_COMP_RING_BASE_ADDR_LO_M) >> \ + HTT_WDI_IPA_CFG_TX_COMP_RING_BASE_ADDR_LO_S) +#define HTT_WDI_IPA_CFG_TX_COMP_RING_BASE_ADDR_LO_SET(_var, _val) \ +do { \ + HTT_CHECK_SET_VAL(HTT_WDI_IPA_CFG_TX_COMP_RING_BASE_ADDR_LO, _val); \ + ((_var) |= ((_val) << HTT_WDI_IPA_CFG_TX_COMP_RING_BASE_ADDR_LO_S)); \ +} while (0) + +#define HTT_WDI_IPA_CFG_TX_COMP_RING_SIZE_GET(_var) \ + (((_var) & HTT_WDI_IPA_CFG_TX_COMP_RING_SIZE_M) >> \ + HTT_WDI_IPA_CFG_TX_COMP_RING_SIZE_S) +#define HTT_WDI_IPA_CFG_TX_COMP_RING_SIZE_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_WDI_IPA_CFG_TX_COMP_RING_SIZE, _val); \ + ((_var) |= ((_val) << HTT_WDI_IPA_CFG_TX_COMP_RING_SIZE_S)); \ + } while (0) + +/* for systems using 32-bit format for bus addr */ +#define HTT_WDI_IPA_CFG_TX_COMP_WR_IDX_ADDR_GET(_var) \ + (((_var) & HTT_WDI_IPA_CFG_TX_COMP_WR_IDX_ADDR_M) >> \ + HTT_WDI_IPA_CFG_TX_COMP_WR_IDX_ADDR_S) +#define HTT_WDI_IPA_CFG_TX_COMP_WR_IDX_ADDR_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_WDI_IPA_CFG_TX_COMP_WR_IDX_ADDR, _val); \ + ((_var) |= ((_val) << HTT_WDI_IPA_CFG_TX_COMP_WR_IDX_ADDR_S)); \ + } while (0) + +/* for systems using 64-bit format for bus addr */ +#define HTT_WDI_IPA_CFG_TX_COMP_WR_IDX_ADDR_HI_GET(_var) \ + (((_var) & HTT_WDI_IPA_CFG_TX_COMP_WR_IDX_ADDR_HI_M) >> \ + HTT_WDI_IPA_CFG_TX_COMP_WR_IDX_ADDR_HI_S) +#define HTT_WDI_IPA_CFG_TX_COMP_WR_IDX_ADDR_HI_SET(_var, _val) \ +do { \ + HTT_CHECK_SET_VAL(HTT_WDI_IPA_CFG_TX_COMP_WR_IDX_ADDR_HI, _val); \ + ((_var) |= ((_val) << HTT_WDI_IPA_CFG_TX_COMP_WR_IDX_ADDR_HI_S)); \ +} while (0) + +/* for systems using 64-bit format for bus addr */ +#define HTT_WDI_IPA_CFG_TX_COMP_WR_IDX_ADDR_LO_GET(_var) \ + (((_var) & HTT_WDI_IPA_CFG_TX_COMP_WR_IDX_ADDR_LO_M) >> \ + HTT_WDI_IPA_CFG_TX_COMP_WR_IDX_ADDR_LO_S) +#define HTT_WDI_IPA_CFG_TX_COMP_WR_IDX_ADDR_LO_SET(_var, _val) \ +do { \ + HTT_CHECK_SET_VAL(HTT_WDI_IPA_CFG_TX_COMP_WR_IDX_ADDR_LO, _val); \ + ((_var) |= ((_val) << HTT_WDI_IPA_CFG_TX_COMP_WR_IDX_ADDR_LO_S)); \ +} while (0) + + +/* for systems using 32-bit format for bus addr */ +#define HTT_WDI_IPA_CFG_TX_CE_WR_IDX_ADDR_GET(_var) \ + (((_var) & HTT_WDI_IPA_CFG_TX_CE_WR_IDX_ADDR_M) >> \ + HTT_WDI_IPA_CFG_TX_CE_WR_IDX_ADDR_S) +#define HTT_WDI_IPA_CFG_TX_CE_WR_IDX_ADDR_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_WDI_IPA_CFG_TX_CE_WR_IDX_ADDR, _val); \ + ((_var) |= ((_val) << HTT_WDI_IPA_CFG_TX_CE_WR_IDX_ADDR_S)); \ + } while (0) + +/* for systems using 64-bit format for bus addr */ +#define HTT_WDI_IPA_CFG_TX_CE_WR_IDX_ADDR_HI_GET(_var) \ + (((_var) & HTT_WDI_IPA_CFG_TX_CE_WR_IDX_ADDR_HI_M) >>\ + HTT_WDI_IPA_CFG_TX_CE_WR_IDX_ADDR_HI_S) +#define HTT_WDI_IPA_CFG_TX_CE_WR_IDX_ADDR_HI_SET(_var, _val) \ +do { \ + HTT_CHECK_SET_VAL(HTT_WDI_IPA_CFG_TX_CE_WR_IDX_ADDR_HI, _val); \ + ((_var) |= ((_val) << HTT_WDI_IPA_CFG_TX_CE_WR_IDX_ADDR_HI_S)); \ +} while (0) + +/* for systems using 64-bit format for bus addr */ +#define HTT_WDI_IPA_CFG_TX_CE_WR_IDX_ADDR_LO_GET(_var) \ + (((_var) & HTT_WDI_IPA_CFG_TX_CE_WR_IDX_ADDR_LO_M) >> \ + HTT_WDI_IPA_CFG_TX_CE_WR_IDX_ADDR_LO_S) +#define HTT_WDI_IPA_CFG_TX_CE_WR_IDX_ADDR_LO_SET(_var, _val) \ +do { \ + HTT_CHECK_SET_VAL(HTT_WDI_IPA_CFG_TX_CE_WR_IDX_ADDR_LO, _val); \ + ((_var) |= ((_val) << HTT_WDI_IPA_CFG_TX_CE_WR_IDX_ADDR_LO_S)); \ +} while (0) + +/* for systems using 32-bit format for bus addr */ +#define HTT_WDI_IPA_CFG_RX_IND_RING_BASE_ADDR_GET(_var) \ + (((_var) & HTT_WDI_IPA_CFG_RX_IND_RING_BASE_ADDR_M) >> \ + HTT_WDI_IPA_CFG_RX_IND_RING_BASE_ADDR_S) +#define HTT_WDI_IPA_CFG_RX_IND_RING_BASE_ADDR_SET(_var, _val) \ +do { \ + HTT_CHECK_SET_VAL(HTT_WDI_IPA_CFG_RX_IND_RING_BASE_ADDR, _val); \ + ((_var) |= ((_val) << HTT_WDI_IPA_CFG_RX_IND_RING_BASE_ADDR_S)); \ +} while (0) + +/* for systems using 64-bit format for bus addr */ +#define HTT_WDI_IPA_CFG_RX_IND_RING_BASE_ADDR_HI_GET(_var) \ + (((_var) & HTT_WDI_IPA_CFG_RX_IND_RING_BASE_ADDR_HI_M) >> \ + HTT_WDI_IPA_CFG_RX_IND_RING_BASE_ADDR_HI_S) +#define HTT_WDI_IPA_CFG_RX_IND_RING_BASE_ADDR_HI_SET(_var, _val) \ +do { \ + HTT_CHECK_SET_VAL(HTT_WDI_IPA_CFG_RX_IND_RING_BASE_ADDR_HI, _val); \ + ((_var) |= ((_val) << HTT_WDI_IPA_CFG_RX_IND_RING_BASE_ADDR_HI_S)); \ +} while (0) + +/* for systems using 64-bit format for bus addr */ +#define HTT_WDI_IPA_CFG_RX_IND_RING_BASE_ADDR_LO_GET(_var) \ + (((_var) & HTT_WDI_IPA_CFG_RX_IND_RING_BASE_ADDR_LO_M) >> \ + HTT_WDI_IPA_CFG_RX_IND_RING_BASE_ADDR_LO_S) +#define HTT_WDI_IPA_CFG_RX_IND_RING_BASE_ADDR_LO_SET(_var, _val) \ +do { \ + HTT_CHECK_SET_VAL(HTT_WDI_IPA_CFG_RX_IND_RING_BASE_ADDR_LO, _val); \ + ((_var) |= ((_val) << HTT_WDI_IPA_CFG_RX_IND_RING_BASE_ADDR_LO_S)); \ +} while (0) + +#define HTT_WDI_IPA_CFG_RX_IND_RING_SIZE_GET(_var) \ + (((_var) & HTT_WDI_IPA_CFG_RX_IND_RING_SIZE_M) >> \ + HTT_WDI_IPA_CFG_RX_IND_RING_SIZE_S) +#define HTT_WDI_IPA_CFG_RX_IND_RING_SIZE_SET(_var, _val) \ +do { \ + HTT_CHECK_SET_VAL(HTT_WDI_IPA_CFG_RX_IND_RING_SIZE, _val); \ + ((_var) |= ((_val) << HTT_WDI_IPA_CFG_RX_IND_RING_SIZE_S)); \ +} while (0) + +/* for systems using 32-bit format for bus addr */ +#define HTT_WDI_IPA_CFG_RX_IND_RD_IDX_ADDR_GET(_var) \ + (((_var) & HTT_WDI_IPA_CFG_RX_IND_RD_IDX_ADDR_M) >> \ + HTT_WDI_IPA_CFG_RX_IND_RD_IDX_ADDR_S) +#define HTT_WDI_IPA_CFG_RX_IND_RD_IDX_ADDR_SET(_var, _val) \ +do { \ + HTT_CHECK_SET_VAL(HTT_WDI_IPA_CFG_RX_IND_RD_IDX_ADDR, _val); \ + ((_var) |= ((_val) << HTT_WDI_IPA_CFG_RX_IND_RD_IDX_ADDR_S)); \ +} while (0) + +/* for systems using 64-bit format for bus addr */ +#define HTT_WDI_IPA_CFG_RX_IND_RD_IDX_ADDR_HI_GET(_var) \ + (((_var) & HTT_WDI_IPA_CFG_RX_IND_RD_IDX_ADDR_HI_M) >> \ + HTT_WDI_IPA_CFG_RX_IND_RD_IDX_ADDR_HI_S) +#define HTT_WDI_IPA_CFG_RX_IND_RD_IDX_ADDR_HI_SET(_var, _val) \ +do { \ + HTT_CHECK_SET_VAL(HTT_WDI_IPA_CFG_RX_IND_RD_IDX_ADDR_HI, _val); \ + ((_var) |= ((_val) << HTT_WDI_IPA_CFG_RX_IND_RD_IDX_ADDR_HI_S)); \ +} while (0) + +/* for systems using 64-bit format for bus addr */ +#define HTT_WDI_IPA_CFG_RX_IND_RD_IDX_ADDR_LO_GET(_var) \ + (((_var) & HTT_WDI_IPA_CFG_RX_IND_RD_IDX_ADDR_LO_M) >> \ + HTT_WDI_IPA_CFG_RX_IND_RD_IDX_ADDR_LO_S) +#define HTT_WDI_IPA_CFG_RX_IND_RD_IDX_ADDR_LO_SET(_var, _val) \ +do { \ + HTT_CHECK_SET_VAL(HTT_WDI_IPA_CFG_RX_IND_RD_IDX_ADDR_LO, _val); \ + ((_var) |= ((_val) << HTT_WDI_IPA_CFG_RX_IND_RD_IDX_ADDR_LO_S)); \ +} while (0) + +/* for systems using 32-bit format for bus addr */ +#define HTT_WDI_IPA_CFG_RX_IND_WR_IDX_ADDR_GET(_var) \ + (((_var) & HTT_WDI_IPA_CFG_RX_IND_WR_IDX_ADDR_M) >> \ + HTT_WDI_IPA_CFG_RX_IND_WR_IDX_ADDR_S) +#define HTT_WDI_IPA_CFG_RX_IND_WR_IDX_ADDR_SET(_var, _val) \ +do { \ + HTT_CHECK_SET_VAL(HTT_WDI_IPA_CFG_RX_IND_WR_IDX_ADDR, _val); \ + ((_var) |= ((_val) << HTT_WDI_IPA_CFG_RX_IND_WR_IDX_ADDR_S)); \ +} while (0) + +/* for systems using 64-bit format for bus addr */ +#define HTT_WDI_IPA_CFG_RX_IND_WR_IDX_ADDR_HI_GET(_var) \ + (((_var) & HTT_WDI_IPA_CFG_RX_IND_WR_IDX_ADDR_HI_M) >> \ + HTT_WDI_IPA_CFG_RX_IND_WR_IDX_ADDR_HI_S) +#define HTT_WDI_IPA_CFG_RX_IND_WR_IDX_ADDR_HI_SET(_var, _val) \ +do { \ + HTT_CHECK_SET_VAL(HTT_WDI_IPA_CFG_RX_IND_WR_IDX_ADDR_HI, _val); \ + ((_var) |= ((_val) << HTT_WDI_IPA_CFG_RX_IND_WR_IDX_ADDR_HI_S)); \ +} while (0) + +/* for systems using 64-bit format for bus addr */ +#define HTT_WDI_IPA_CFG_RX_IND_WR_IDX_ADDR_LO_GET(_var) \ + (((_var) & HTT_WDI_IPA_CFG_RX_IND_WR_IDX_ADDR_LO_M) >> \ + HTT_WDI_IPA_CFG_RX_IND_WR_IDX_ADDR_LO_S) +#define HTT_WDI_IPA_CFG_RX_IND_WR_IDX_ADDR_LO_SET(_var, _val) \ +do { \ + HTT_CHECK_SET_VAL(HTT_WDI_IPA_CFG_RX_IND_WR_IDX_ADDR_LO, _val); \ + ((_var) |= ((_val) << HTT_WDI_IPA_CFG_RX_IND_WR_IDX_ADDR_LO_S)); \ + } while (0) + +/* for systems using 32-bit format for bus addr */ +#define HTT_WDI_IPA_CFG_RX_RING2_BASE_ADDR_GET(_var) \ + (((_var) & HTT_WDI_IPA_CFG_RX_RING2_BASE_ADDR_M) >> \ + HTT_WDI_IPA_CFG_RX_RING2_BASE_ADDR_S) +#define HTT_WDI_IPA_CFG_RX_RING2_BASE_ADDR_SET(_var, _val) \ +do { \ + HTT_CHECK_SET_VAL(HTT_WDI_IPA_CFG_RX_RING2_BASE_ADDR, _val); \ + ((_var) |= ((_val) << HTT_WDI_IPA_CFG_RX_RING2_BASE_ADDR_S)); \ +} while (0) + +/* for systems using 64-bit format for bus addr */ +#define HTT_WDI_IPA_CFG_RX_RING2_BASE_ADDR_HI_GET(_var) \ + (((_var) & HTT_WDI_IPA_CFG_RX_RING2_BASE_ADDR_HI_M) >> \ + HTT_WDI_IPA_CFG_RX_RING2_BASE_ADDR_HI_S) +#define HTT_WDI_IPA_CFG_RX_RING2_BASE_ADDR_HI_SET(_var, _val) \ +do { \ + HTT_CHECK_SET_VAL(HTT_WDI_IPA_CFG_RX_RING2_BASE_ADDR_HI, _val); \ + ((_var) |= ((_val) << HTT_WDI_IPA_CFG_RX_RING2_BASE_ADDR_HI_S)); \ +} while (0) + +/* for systems using 64-bit format for bus addr */ +#define HTT_WDI_IPA_CFG_RX_RING2_BASE_ADDR_LO_GET(_var) \ + (((_var) & HTT_WDI_IPA_CFG_RX_RING2_BASE_ADDR_LO_M) >> \ + HTT_WDI_IPA_CFG_RX_RING2_BASE_ADDR_LO_S) +#define HTT_WDI_IPA_CFG_RX_RING2_BASE_ADDR_LO_SET(_var, _val) \ +do { \ + HTT_CHECK_SET_VAL(HTT_WDI_IPA_CFG_RX_RING2_BASE_ADDR_LO, _val); \ + ((_var) |= ((_val) << HTT_WDI_IPA_CFG_RX_RING2_BASE_ADDR_LO_S)); \ +} while (0) + +#define HTT_WDI_IPA_CFG_RX_RING2_SIZE_GET(_var) \ + (((_var) & HTT_WDI_IPA_CFG_RX_RING2_SIZE_M) >> \ + HTT_WDI_IPA_CFG_RX_RING2_SIZE_S) +#define HTT_WDI_IPA_CFG_RX_RING2_SIZE_SET(_var, _val) \ +do { \ + HTT_CHECK_SET_VAL(HTT_WDI_IPA_CFG_RX_RING2_SIZE, _val); \ + ((_var) |= ((_val) << HTT_WDI_IPA_CFG_RX_RING2_SIZE_S)); \ +} while (0) + +/* for systems using 32-bit format for bus addr */ +#define HTT_WDI_IPA_CFG_RX_RING2_RD_IDX_ADDR_GET(_var) \ + (((_var) & HTT_WDI_IPA_CFG_RX_RING2_RD_IDX_ADDR_M) >> \ + HTT_WDI_IPA_CFG_RX_RING2_RD_IDX_ADDR_S) +#define HTT_WDI_IPA_CFG_RX_RING2_RD_IDX_ADDR_SET(_var, _val) \ +do { \ + HTT_CHECK_SET_VAL(HTT_WDI_IPA_CFG_RX_RING2_RD_IDX_ADDR, _val); \ + ((_var) |= ((_val) << HTT_WDI_IPA_CFG_RX_RING2_RD_IDX_ADDR_S)); \ +} while (0) + +/* for systems using 64-bit format for bus addr */ +#define HTT_WDI_IPA_CFG_RX_RING2_RD_IDX_ADDR_HI_GET(_var) \ + (((_var) & HTT_WDI_IPA_CFG_RX_RING2_RD_IDX_ADDR_HI_M) >> \ + HTT_WDI_IPA_CFG_RX_RING2_RD_IDX_ADDR_HI_S) +#define HTT_WDI_IPA_CFG_RX_RING2_RD_IDX_ADDR_HI_SET(_var, _val) \ +do { \ + HTT_CHECK_SET_VAL(HTT_WDI_IPA_CFG_RX_RING2_RD_IDX_ADDR_HI, _val); \ + ((_var) |= ((_val) << HTT_WDI_IPA_CFG_RX_RING2_RD_IDX_ADDR_HI_S)); \ +} while (0) + +/* for systems using 64-bit format for bus addr */ +#define HTT_WDI_IPA_CFG_RX_RING2_RD_IDX_ADDR_LO_GET(_var) \ + (((_var) & HTT_WDI_IPA_CFG_RX_RING2_RD_IDX_ADDR_LO_M) >> \ + HTT_WDI_IPA_CFG_RX_RING2_RD_IDX_ADDR_LO_S) +#define HTT_WDI_IPA_CFG_RX_RING2_RD_IDX_ADDR_LO_SET(_var, _val) \ +do { \ + HTT_CHECK_SET_VAL(HTT_WDI_IPA_CFG_RX_RING2_RD_IDX_ADDR_LO, _val); \ + ((_var) |= ((_val) << HTT_WDI_IPA_CFG_RX_RING2_RD_IDX_ADDR_LO_S)); \ +} while (0) + +/* for systems using 32-bit format for bus addr */ +#define HTT_WDI_IPA_CFG_RX_RING2_WR_IDX_ADDR_GET(_var) \ + (((_var) & HTT_WDI_IPA_CFG_RX_RING2_WR_IDX_ADDR_M) >> \ + HTT_WDI_IPA_CFG_RX_RING2_WR_IDX_ADDR_S) +#define HTT_WDI_IPA_CFG_RX_RING2_WR_IDX_ADDR_SET(_var, _val) \ +do { \ + HTT_CHECK_SET_VAL(HTT_WDI_IPA_CFG_RX_RING2_WR_IDX_ADDR, _val); \ + ((_var) |= ((_val) << HTT_WDI_IPA_CFG_RX_RING2_WR_IDX_ADDR_S)); \ +} while (0) + +/* for systems using 64-bit format for bus addr */ +#define HTT_WDI_IPA_CFG_RX_RING2_WR_IDX_ADDR_HI_GET(_var) \ + (((_var) & HTT_WDI_IPA_CFG_RX_RING2_WR_IDX_ADDR_HI_M) >> \ + HTT_WDI_IPA_CFG_RX_RING2_WR_IDX_ADDR_HI_S) +#define HTT_WDI_IPA_CFG_RX_RING2_WR_IDX_ADDR_HI_SET(_var, _val) \ +do { \ + HTT_CHECK_SET_VAL(HTT_WDI_IPA_CFG_RX_RING2_WR_IDX_ADDR_HI, _val); \ + ((_var) |= ((_val) << HTT_WDI_IPA_CFG_RX_RING2_WR_IDX_ADDR_HI_S)); \ +} while (0) + +/* for systems using 64-bit format for bus addr */ +#define HTT_WDI_IPA_CFG_RX_RING2_WR_IDX_ADDR_LO_GET(_var) \ + (((_var) & HTT_WDI_IPA_CFG_RX_RING2_WR_IDX_ADDR_LO_M) >> \ + HTT_WDI_IPA_CFG_RX_RING2_WR_IDX_ADDR_LO_S) +#define HTT_WDI_IPA_CFG_RX_RING2_WR_IDX_ADDR_LO_SET(_var, _val) \ +do { \ + HTT_CHECK_SET_VAL(HTT_WDI_IPA_CFG_RX_RING2_WR_IDX_ADDR_LO, _val); \ + ((_var) |= ((_val) << HTT_WDI_IPA_CFG_RX_RING2_WR_IDX_ADDR_LO_S)); \ +} while (0) + +/* + * TEMPLATE_HTT_WDI_IPA_CONFIG_T: + * This macro defines a htt_wdi_ipa_configXXX_t in which any physical + * addresses are stored in a XXX-bit field. + * This macro is used to define both htt_wdi_ipa_config32_t and + * htt_wdi_ipa_config64_t structs. + */ +#define TEMPLATE_HTT_WDI_IPA_CONFIG_T(_paddr_bits_, \ + _paddr__tx_comp_ring_base_addr_, \ + _paddr__tx_comp_wr_idx_addr_, \ + _paddr__tx_ce_wr_idx_addr_, \ + _paddr__rx_ind_ring_base_addr_, \ + _paddr__rx_ind_rd_idx_addr_, \ + _paddr__rx_ind_wr_idx_addr_, \ + _paddr__rx_ring2_base_addr_,\ + _paddr__rx_ring2_rd_idx_addr_,\ + _paddr__rx_ring2_wr_idx_addr_) \ +PREPACK struct htt_wdi_ipa_cfg ## _paddr_bits_ ## _t \ +{ \ + /* DWORD 0: flags and meta-data */ \ + A_UINT32 \ + msg_type:8, /* HTT_H2T_MSG_TYPE_WDI_IPA_CFG */ \ + reserved:8, \ + tx_pkt_pool_size:16;\ + /* DWORD 1 */\ + _paddr__tx_comp_ring_base_addr_;\ + /* DWORD 2 (or 3)*/\ + A_UINT32 tx_comp_ring_size;\ + /* DWORD 3 (or 4)*/\ + _paddr__tx_comp_wr_idx_addr_;\ + /* DWORD 4 (or 6)*/\ + _paddr__tx_ce_wr_idx_addr_;\ + /* DWORD 5 (or 8)*/\ + _paddr__rx_ind_ring_base_addr_;\ + /* DWORD 6 (or 10)*/\ + A_UINT32 rx_ind_ring_size;\ + /* DWORD 7 (or 11)*/\ + _paddr__rx_ind_rd_idx_addr_;\ + /* DWORD 8 (or 13)*/\ + _paddr__rx_ind_wr_idx_addr_;\ + /* DWORD 9 (or 15)*/\ + _paddr__rx_ring2_base_addr_;\ + /* DWORD 10 (or 17) */\ + A_UINT32 rx_ring2_size;\ + /* DWORD 11 (or 18) */\ + _paddr__rx_ring2_rd_idx_addr_;\ + /* DWORD 12 (or 20) */\ + _paddr__rx_ring2_wr_idx_addr_;\ +} POSTPACK + +/* define a htt_wdi_ipa_config32_t type */ +TEMPLATE_HTT_WDI_IPA_CONFIG_T(32, HTT_VAR_PADDR32(tx_comp_ring_base_addr), + HTT_VAR_PADDR32(tx_comp_wr_idx_addr), + HTT_VAR_PADDR32(tx_ce_wr_idx_addr), + HTT_VAR_PADDR32(rx_ind_ring_base_addr), + HTT_VAR_PADDR32(rx_ind_rd_idx_addr), + HTT_VAR_PADDR32(rx_ind_wr_idx_addr), + HTT_VAR_PADDR32(rx_ring2_base_addr), + HTT_VAR_PADDR32(rx_ring2_rd_idx_addr), + HTT_VAR_PADDR32(rx_ring2_wr_idx_addr)); + +/* define a htt_wdi_ipa_config64_t type */ +TEMPLATE_HTT_WDI_IPA_CONFIG_T(64, HTT_VAR_PADDR64_LE(tx_comp_ring_base_addr), + HTT_VAR_PADDR64_LE(tx_comp_wr_idx_addr), + HTT_VAR_PADDR64_LE(tx_ce_wr_idx_addr), + HTT_VAR_PADDR64_LE(rx_ind_ring_base_addr), + HTT_VAR_PADDR64_LE(rx_ind_rd_idx_addr), + HTT_VAR_PADDR64_LE(rx_ind_wr_idx_addr), + HTT_VAR_PADDR64_LE(rx_ring2_base_addr), + HTT_VAR_PADDR64_LE(rx_ring2_rd_idx_addr), + HTT_VAR_PADDR64_LE(rx_ring2_wr_idx_addr)); + +#if HTT_PADDR64 +#define htt_wdi_ipa_cfg_t htt_wdi_ipa_cfg64_t +#else +#define htt_wdi_ipa_cfg_t htt_wdi_ipa_cfg32_t +#endif + +enum htt_wdi_ipa_op_code { + HTT_WDI_IPA_OPCODE_TX_SUSPEND = 0, + HTT_WDI_IPA_OPCODE_TX_RESUME = 1, + HTT_WDI_IPA_OPCODE_RX_SUSPEND = 2, + HTT_WDI_IPA_OPCODE_RX_RESUME = 3, + HTT_WDI_IPA_OPCODE_DBG_STATS = 4, + HTT_WDI_IPA_OPCODE_GET_SHARING_STATS = 5, + HTT_WDI_IPA_OPCODE_SET_QUOTA = 6, + HTT_WDI_IPA_OPCODE_IND_QUOTA = 7, + /* keep this last */ + HTT_WDI_IPA_OPCODE_MAX +}; + +/** + * @brief HTT WDI_IPA Operation Request Message + * + * @details + * HTT WDI_IPA Operation Request message is sent by host + * to either suspend or resume WDI_IPA TX or RX path. + * |31 24|23 16|15 8|7 0| + * |----------------+----------------+----------------+----------------| + * | op_code | Rsvd | msg_type | + * |-------------------------------------------------------------------| + * + * Header fields: + * - MSG_TYPE + * Bits 7:0 + * Purpose: Identifies this as WDI_IPA Operation Request message + * value: = 0x9 + * - OP_CODE + * Bits 31:16 + * Purpose: Identifies operation host is requesting (e.g. TX suspend) + * value: = enum htt_wdi_ipa_op_code + */ + +PREPACK struct htt_wdi_ipa_op_request_t { + /* DWORD 0: flags and meta-data */ + A_UINT32 + msg_type:8, /* HTT_H2T_MSG_TYPE_WDI_IPA_OP_REQ */ + reserved:8, + op_code:16; +} POSTPACK; + +#define HTT_WDI_IPA_OP_REQUEST_SZ 4 + +#define HTT_WDI_IPA_OP_REQUEST_OP_CODE_M 0xffff0000 +#define HTT_WDI_IPA_OP_REQUEST_OP_CODE_S 16 + +#define HTT_WDI_IPA_OP_REQUEST_OP_CODE_GET(_var) \ + (((_var) & HTT_WDI_IPA_OP_REQUEST_OP_CODE_M) >> \ + HTT_WDI_IPA_OP_REQUEST_OP_CODE_S) +#define HTT_WDI_IPA_OP_REQUEST_OP_CODE_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_WDI_IPA_OP_REQUEST_OP_CODE, _val); \ + ((_var) |= ((_val) << HTT_WDI_IPA_OP_REQUEST_OP_CODE_S)); \ + } while (0) + +/** + * @brief WLAN_WDI_IPA_GET_SHARING_STATS_REQ + * |31 24|23 16|15 8|7 0| + * |----------------+----------------+----------------+----------------| + * | reserved | reset_stats | + * |-------------------------------------------------------------------| + * Header fields: + * - RESET_STATS + * Bits 7:0 + * Purpose: when 1, FW clears sharing stats + * - RESERVED + * Bits 31:8 + * Purpose: reserved bits + */ + +PREPACK struct htt_wdi_ipa_get_sharing_stats_t { + A_UINT32 + reset_stats:8, /* reset stat countis after response */ + reserved:24; +} POSTPACK; + +#define HTT_WDI_IPA_OP_REQ_GET_SHARING_STATS_SZ \ + (sizeof(struct htt_wdi_ipa_get_sharing_stats_t)) + +#define HTT_WDI_IPA_OP_REQ_GET_SHARING_STATS_RESET_STATS_M 0x000000ff +#define HTT_WDI_IPA_OP_REQ_GET_SHARING_STATS_RESET_STATS_S 0 +#define HTT_WDI_IPA_OP_REQ_GET_SHARING_STATS_RESET_STATS_GET(_var) \ + (((_var) & HTT_WDI_IPA_OP_REQ_GET_SHARING_STATS_RESET_STATS_M) >>\ + HTT_WDI_IPA_OP_REQ_GET_SHARING_STATS_RESET_STATS_S) +#define HTT_WDI_IPA_OP_REQ_GET_SHARING_STATS_RESET_STATS_SET(_var, _val)\ + do { \ + HTT_CHECK_SET_VAL( \ + HTT_WDI_IPA_OP_REQ_GET_SHARING_STATS_RESET_STATS,\ + _val); \ + ((_var) |= ((_val) << \ + HTT_WDI_IPA_OP_REQ_GET_SHARING_STATS_RESET_STATS_S)); \ + } while (0) + +/** + * @brief WLAN_WDI_IPA_SET_QUOTA_REQ + * + * |31 24|23 16|15 8|7 0| + * |----------------+----------------+----------------+----------------| + * | reserved | set_quota | + * |-------------------------------------------------------------------| + * | quota_lo | + * |-------------------------------------------------------------------| + * | quota_hi | + * |-------------------------------------------------------------------| + * Header fields: + * - set_quota + * Bits 7:0 + * Purpose: when 1, FW configures quota and starts quota monitoring. + * when 0, FW stops. + * - RESERVED + * Bits 31:8 + * Purpose: reserved bits + * - quota_lo + * Bits 31:0 + * Purpose: bytes of quota to be set, low 32-bit. + * It is accumulated number of bytes from when quota is configured. + * - quota_hi + * Bits 31:0 + * Purpose: bytes of quota to be set, high 32-bit + */ + +PREPACK struct htt_wdi_ipa_set_quota_t { + A_UINT32 + set_quota:8, /* enable quota monitoring */ + reserved:24; + A_UINT32 quota_lo; /* quota limit in bytes */ + A_UINT32 quota_hi; +} POSTPACK; + +#define HTT_WDI_IPA_OP_REQ_SET_QUOTA_SZ \ + (sizeof(struct htt_wdi_ipa_set_quota_t)) + +#define HTT_WDI_IPA_OP_REQ_SET_QUOTA_SET_QUOTA_M 0x000000ff +#define HTT_WDI_IPA_OP_REQ_SET_QUOTA_SET_QUOTA_S 0 +#define HTT_WDI_IPA_OP_REQ_SET_QUOTA_SET_QUOTA_GET(_var) \ + (((_var) & HTT_WDI_IPA_OP_REQ_SET_QUOTA_SET_QUOTA_M) >> \ + HTT_WDI_IPA_OP_REQ_SET_QUOTA_SET_QUOTA_S) +#define HTT_WDI_IPA_OP_REQ_SET_QUOTA_SET_QUOTA_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_WDI_IPA_OP_REQ_SET_QUOTA_SET_QUOTA,\ + _val); \ + ((_var) |= ((_val) << \ + HTT_WDI_IPA_OP_REQ_SET_QUOTA_SET_QUOTA_S)); \ + } while (0) + +#define HTT_WDI_IPA_OP_REQ_SET_QUOTA_QUOTA_LO_M 0xffffffff +#define HTT_WDI_IPA_OP_REQ_SET_QUOTA_QUOTA_LO_S 0 +#define HTT_WDI_IPA_OP_REQ_SET_QUOTA_QUOTA_LO_GET(_var) \ + (((_var) & HTT_WDI_IPA_OP_REQ_SET_QUOTA_QUOTA_LO_M) >> \ + HTT_WDI_IPA_OP_REQ_SET_QUOTA_QUOTA_LO_S) +#define HTT_WDI_IPA_OP_REQ_SET_QUOTA_QUOTA_LO_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_WDI_IPA_OP_REQ_SET_QUOTA_QUOTA_LO,\ + _val); \ + ((_var) |= ((_val) << \ + HTT_WDI_IPA_OP_REQ_SET_QUOTA_QUOTA_LO_S)); \ + } while (0) + +#define HTT_WDI_IPA_OP_REQ_SET_QUOTA_QUOTA_HI_M 0xffffffff +#define HTT_WDI_IPA_OP_REQ_SET_QUOTA_QUOTA_HI_S 0 +#define HTT_WDI_IPA_OP_REQ_SET_QUOTA_QUOTA_HI_GET(_var) \ + (((_var) & HTT_WDI_IPA_OP_REQ_SET_QUOTA_QUOTA_HI_M) >> \ + HTT_WDI_IPA_OP_REQ_SET_QUOTA_QUOTA_HI_S) +#define HTT_WDI_IPA_OP_REQ_SET_QUOTA_QUOTA_HI_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_WDI_IPA_OP_REQ_SET_QUOTA_QUOTA_HI,\ + _val); \ + ((_var) |= ((_val) << \ + HTT_WDI_IPA_OP_REQ_SET_QUOTA_QUOTA_HI_S)); \ + } while (0) + +/* + * @brief host -> target HTT_SRING_SETUP message + * + * @details + * After target is booted up, Host can send SRING setup message for + * each host facing LMAC SRING. Target setups up HW registers based + * on setup message and confirms back to Host if response_required is set. + * Host should wait for confirmation message before sending new SRING + * setup message + * + * The message would appear as follows: + * |31 24|23 20|19|18 16|15|14 8|7 0| + * |--------------- +-----------------+----------------+------------------| + * | ring_type | ring_id | pdev_id | msg_type | + * |----------------------------------------------------------------------| + * | ring_base_addr_lo | + * |----------------------------------------------------------------------| + * | ring_base_addr_hi | + * |----------------------------------------------------------------------| + * |ring_misc_cfg_flag|ring_entry_size| ring_size | + * |----------------------------------------------------------------------| + * | ring_head_offset32_remote_addr_lo | + * |----------------------------------------------------------------------| + * | ring_head_offset32_remote_addr_hi | + * |----------------------------------------------------------------------| + * | ring_tail_offset32_remote_addr_lo | + * |----------------------------------------------------------------------| + * | ring_tail_offset32_remote_addr_hi | + * |----------------------------------------------------------------------| + * | ring_msi_addr_lo | + * |----------------------------------------------------------------------| + * | ring_msi_addr_hi | + * |----------------------------------------------------------------------| + * | ring_msi_data | + * |----------------------------------------------------------------------| + * | intr_timer_th |IM| intr_batch_counter_th | + * |----------------------------------------------------------------------| + * | reserved |RR|PTCF| intr_low_threshold | + * |----------------------------------------------------------------------| + * Where + * IM = sw_intr_mode + * RR = response_required + * PTCF = prefetch_timer_cfg + * + * The message is interpreted as follows: + * dword0 - b'0:7 - msg_type: This will be set to + * HTT_H2T_MSG_TYPE_SRING_SETUP + * b'8:15 - pdev_id: + * 0 (for rings at SOC/UMAC level), + * 1/2/3 mac id (for rings at LMAC level) + * b'16:23 - ring_id: identify which ring is to setup, + * more details can be got from enum htt_srng_ring_id + * b'24:31 - ring_type: identify type of host rings, + * more details can be got from enum htt_srng_ring_type + * dword1 - b'0:31 - ring_base_addr_lo: Lower 32bits of ring base address + * dword2 - b'0:31 - ring_base_addr_hi: Upper 32bits of ring base address + * dword3 - b'0:15 - ring_size: size of the ring in unit of 4-bytes words + * b'16:23 - ring_entry_size: Size of each entry in 4-byte word units + * b'24:31 - ring_misc_cfg_flag: Valid only for HW_TO_SW_RING and + * SW_TO_HW_RING. + * Refer to HTT_SRING_SETUP_RING_MISC_CFG_RING defs. + * dword4 - b'0:31 - ring_head_offset32_remote_addr_lo: + * Lower 32 bits of memory address of the remote variable + * storing the 4-byte word offset that identifies the head + * element within the ring. + * (The head offset variable has type A_UINT32.) + * Valid for HW_TO_SW and SW_TO_SW rings. + * dword5 - b'0:31 - ring_head_offset32_remote_addr_hi: + * Upper 32 bits of memory address of the remote variable + * storing the 4-byte word offset that identifies the head + * element within the ring. + * (The head offset variable has type A_UINT32.) + * Valid for HW_TO_SW and SW_TO_SW rings. + * dword6 - b'0:31 - ring_tail_offset32_remote_addr_lo: + * Lower 32 bits of memory address of the remote variable + * storing the 4-byte word offset that identifies the tail + * element within the ring. + * (The tail offset variable has type A_UINT32.) + * Valid for HW_TO_SW and SW_TO_SW rings. + * dword7 - b'0:31 - ring_tail_offset32_remote_addr_hi: + * Upper 32 bits of memory address of the remote variable + * storing the 4-byte word offset that identifies the tail + * element within the ring. + * (The tail offset variable has type A_UINT32.) + * Valid for HW_TO_SW and SW_TO_SW rings. + * dword8 - b'0:31 - ring_msi_addr_lo: Lower 32bits of MSI cfg address + * valid only for HW_TO_SW_RING and SW_TO_HW_RING + * dword9 - b'0:31 - ring_msi_addr_hi: Upper 32bits of MSI cfg address + * valid only for HW_TO_SW_RING and SW_TO_HW_RING + * dword10 - b'0:31 - ring_msi_data: MSI data + * Refer to HTT_SRING_SETUP_RING_MSC_CFG_xxx defs + * valid only for HW_TO_SW_RING and SW_TO_HW_RING + * dword11 - b'0:14 - intr_batch_counter_th: + * batch counter threshold is in units of 4-byte words. + * HW internally maintains and increments batch count. + * (see SRING spec for detail description). + * When batch count reaches threshold value, an interrupt + * is generated by HW. + * b'15 - sw_intr_mode: + * This configuration shall be static. + * Only programmed at power up. + * 0: generate pulse style sw interrupts + * 1: generate level style sw interrupts + * b'16:31 - intr_timer_th: + * The timer init value when timer is idle or is + * initialized to start downcounting. + * In 8us units (to cover a range of 0 to 524 ms) + * dword12 - b'0:15 - intr_low_threshold: + * Used only by Consumer ring to generate ring_sw_int_p. + * Ring entries low threshold water mark, that is used + * in combination with the interrupt timer as well as + * the the clearing of the level interrupt. + * b'16:18 - prefetch_timer_cfg: + * Used only by Consumer ring to set timer mode to + * support Application prefetch handling. + * The external tail offset/pointer will be updated + * at following intervals: + * 3'b000: (Prefetch feature disabled; used only for debug) + * 3'b001: 1 usec + * 3'b010: 4 usec + * 3'b011: 8 usec (default) + * 3'b100: 16 usec + * Others: Reserverd + * b'19 - response_required: + * Host needs HTT_T2H_MSG_TYPE_SRING_SETUP_DONE as response + * b'20:31 - reserved: reserved for future use + */ +PREPACK struct htt_sring_setup_t { + A_UINT32 msg_type: 8, + pdev_id: 8, + ring_id: 8, + ring_type: 8; + A_UINT32 ring_base_addr_lo; + A_UINT32 ring_base_addr_hi; + A_UINT32 ring_size: 16, + ring_entry_size: 8, + ring_misc_cfg_flag: 8; + A_UINT32 ring_head_offset32_remote_addr_lo; + A_UINT32 ring_head_offset32_remote_addr_hi; + A_UINT32 ring_tail_offset32_remote_addr_lo; + A_UINT32 ring_tail_offset32_remote_addr_hi; + A_UINT32 ring_msi_addr_lo; + A_UINT32 ring_msi_addr_hi; + A_UINT32 ring_msi_data; + A_UINT32 intr_batch_counter_th: 15, + sw_intr_mode: 1, + intr_timer_th: 16; + A_UINT32 intr_low_threshold: 16, + prefetch_timer_cfg: 3, + response_required: 1, + reserved1: 12; +} POSTPACK; + +enum htt_srng_ring_type { + HTT_HW_TO_SW_RING = 0, + HTT_SW_TO_HW_RING, + HTT_SW_TO_SW_RING, + /* Insert new ring types above this line */ +}; + +enum htt_srng_ring_id { + /* Used by FW to feed remote buffers and update remote packets */ + HTT_RXDMA_HOST_BUF_RING = 0, + /* + * For getting all PPDU/MPDU/MSDU status deescriptors on host for + * monitor VAP or packet log purposes + */ + HTT_RXDMA_MONITOR_STATUS_RING, + /* For feeding free host buffers to RxDMA for monitor traffic upload */ + HTT_RXDMA_MONITOR_BUF_RING, + /* For providing free LINK_DESC to RXDMA for monitor traffic upload */ + HTT_RXDMA_MONITOR_DESC_RING, + /* Per MPDU indication to host for monitor traffic upload */ + HTT_RXDMA_MONITOR_DEST_RING, + /* (mobile only) used by host to provide remote RX buffers */ + HTT_HOST1_TO_FW_RXBUF_RING, + /* (mobile only) second ring used by host to provide remote RX buffers*/ + HTT_HOST2_TO_FW_RXBUF_RING, + /* + * Add Other SRING which can't be directly configured by host software + * above this line + */ +}; + +#define HTT_SRING_SETUP_SZ (sizeof(struct htt_sring_setup_t)) + +#define HTT_SRING_SETUP_PDEV_ID_M 0x0000ff00 +#define HTT_SRING_SETUP_PDEV_ID_S 8 +#define HTT_SRING_SETUP_PDEV_ID_GET(_var) \ + (((_var) & HTT_SRING_SETUP_PDEV_ID_M) >> \ + HTT_SRING_SETUP_PDEV_ID_S) +#define HTT_SRING_SETUP_PDEV_ID_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_SRING_SETUP_PDEV_ID, _val); \ + ((_var) |= ((_val) << HTT_SRING_SETUP_PDEV_ID_S)); \ + } while (0) + +#define HTT_SRING_SETUP_RING_ID_M 0x00ff0000 +#define HTT_SRING_SETUP_RING_ID_S 16 +#define HTT_SRING_SETUP_RING_ID_GET(_var) \ + (((_var) & HTT_SRING_SETUP_RING_ID_M) >> \ + HTT_SRING_SETUP_RING_ID_S) +#define HTT_SRING_SETUP_RING_ID_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_SRING_SETUP_RING_ID, _val); \ + ((_var) |= ((_val) << HTT_SRING_SETUP_RING_ID_S)); \ + } while (0) + +#define HTT_SRING_SETUP_RING_TYPE_M 0xff000000 +#define HTT_SRING_SETUP_RING_TYPE_S 24 +#define HTT_SRING_SETUP_RING_TYPE_GET(_var) \ + (((_var) & HTT_SRING_SETUP_RING_TYPE_M) >> \ + HTT_SRING_SETUP_RING_TYPE_S) +#define HTT_SRING_SETUP_RING_TYPE_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_SRING_SETUP_RING_TYPE, _val); \ + ((_var) |= ((_val) << HTT_SRING_SETUP_RING_TYPE_S)); \ + } while (0) + +#define HTT_SRING_SETUP_RING_BASE_ADDR_LO_M 0xffffffff +#define HTT_SRING_SETUP_RING_BASE_ADDR_LO_S 0 +#define HTT_SRING_SETUP_RING_BASE_ADDR_LO_GET(_var) \ + (((_var) & HTT_SRING_SETUP_RING_BASE_ADDR_LO_M) >> \ + HTT_SRING_SETUP_RING_BASE_ADDR_LO_S) +#define HTT_SRING_SETUP_RING_BASE_ADDR_LO_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_SRING_SETUP_RING_BASE_ADDR_LO, _val);\ + ((_var) |= ((_val) << HTT_SRING_SETUP_RING_BASE_ADDR_LO_S));\ + } while (0) + +#define HTT_SRING_SETUP_RING_BASE_ADDR_HI_M 0xffffffff +#define HTT_SRING_SETUP_RING_BASE_ADDR_HI_S 0 +#define HTT_SRING_SETUP_RING_BASE_ADDR_HI_GET(_var) \ + (((_var) & HTT_SRING_SETUP_RING_BASE_ADDR_HI_M) >> \ + HTT_SRING_SETUP_RING_BASE_ADDR_HI_S) +#define HTT_SRING_SETUP_RING_BASE_ADDR_HI_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_SRING_SETUP_RING_BASE_ADDR_HI, _val);\ + ((_var) |= ((_val) << HTT_SRING_SETUP_RING_BASE_ADDR_HI_S));\ + } while (0) + +#define HTT_SRING_SETUP_RING_SIZE_M 0x0000ffff +#define HTT_SRING_SETUP_RING_SIZE_S 0 +#define HTT_SRING_SETUP_RING_SIZE_GET(_var) \ + (((_var) & HTT_SRING_SETUP_RING_SIZE_M) >> \ + HTT_SRING_SETUP_RING_SIZE_S) +#define HTT_SRING_SETUP_RING_SIZE_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_SRING_SETUP_RING_SIZE, _val); \ + ((_var) |= ((_val) << HTT_SRING_SETUP_RING_SIZE_S)); \ + } while (0) + +#define HTT_SRING_SETUP_ENTRY_SIZE_M 0x00ff00000 +#define HTT_SRING_SETUP_ENTRY_SIZE_S 16 +#define HTT_SRING_SETUP_ENTRY_SIZE_GET(_var) \ + (((_var) & HTT_SRING_SETUP_ENTRY_SIZE_M) >> \ + HTT_SRING_SETUP_ENTRY_SIZE_S) +#define HTT_SRING_SETUP_ENTRY_SIZE_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_SRING_SETUP_ENTRY_SIZE, _val); \ + ((_var) |= ((_val) << HTT_SRING_SETUP_ENTRY_SIZE_S)); \ + } while (0) + +#define HTT_SRING_SETUP_MISC_CFG_FLAG_M 0xff0000000 +#define HTT_SRING_SETUP_MISC_CFG_FLAG_S 24 +#define HTT_SRING_SETUP_MISC_CFG_FLAG_GET(_var)\ + (((_var) & HTT_SRING_SETUP_MISC_CFG_FLAG_M) >> \ + HTT_SRING_SETUP_MISC_CFG_FLAG_S) +#define HTT_SRING_SETUP_MISC_CFG_FLAG_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_SRING_SETUP_MISC_CFG_FLAG, _val); \ + ((_var) |= ((_val) << HTT_SRING_SETUP_MISC_CFG_FLAG_S)); \ + } while (0) + +/* This control bit is applicable to only Producer, which updates Ring ID field + * of each descriptor before pushing into the ring. + * 0: updates ring_id(default) + * 1: ring_id updating disabled + */ +#define HTT_SRING_SETUP_RING_MISC_CFG_FLAG_RING_ID_DISABLE_M 0x01 +#define HTT_SRING_SETUP_RING_MISC_CFG_FLAG_RING_ID_DISABLE_S 0 +#define HTT_SRING_SETUP_RING_MISC_CFG_FLAG_RING_ID_DISABLE_GET(_var) \ + (((_var) & HTT_SRING_SETUP_RING_MISC_CFG_FLAG_RING_ID_DISABLE_M) >> \ + HTT_SRING_SETUP_RING_MISC_CFG_FLAG_RING_ID_DISABLE_S) +#define HTT_SRING_SETUP_RING_MISC_CFG_FLAG_RING_ID_DISABLE_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL( \ + HTT_SRING_SETUP_RING_MISC_CFG_FLAG_RING_ID_DISABLE, _val);\ + ((_var) |= ((_val) << \ + HTT_SRING_SETUP_RING_MISC_CFG_FLAG_RING_ID_DISABLE_S)); \ + } while (0) + +/* This control bit is applicable to only Producer, which updates Loopcnt field + * of each descriptor before pushing into the ring. + * 0: updates Loopcnt(default) + * 1: Loopcnt updating disabled + */ +#define HTT_SRING_SETUP_RING_MISC_CFG_FLAG_LOOPCOUNT_DISABLE_M 0x02 +#define HTT_SRING_SETUP_RING_MISC_CFG_FLAG_LOOPCOUNT_DISABLE_S 1 +#define HTT_SRING_SETUP_RING_MISC_CFG_FLAG_LOOPCOUNT_DISABLE_GET(_var) \ + (((_var) & HTT_SRING_SETUP_RING_MISC_CFG_FLAG_LOOPCOUNT_DISABLE_M) >> \ + HTT_SRING_SETUP_RING_MISC_CFG_FLAG_LOOPCOUNT_DISABLE_S) +#define HTT_SRING_SETUP_RING_MISC_CFG_FLAG_LOOPCOUNT_DISABLE_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL( \ + HTT_SRING_SETUP_RING_MISC_CFG_FLAG_LOOPCOUNT_DISABLE, _val); \ + ((_var) |= ((_val) << \ + HTT_SRING_SETUP_RING_MISC_CFG_FLAG_LOOPCOUNT_DISABLE_S)); \ + } while (0) + +/* Secured access enable/disable bit. SRNG drives value of this register bit + * into security_id port of GXI/AXI. + */ +#define HTT_SRING_SETUP_RING_MISC_CFG_FLAG_SECURITY_M 0x04 +#define HTT_SRING_SETUP_RING_MISC_CFG_FLAG_SECURITY_S 2 +#define HTT_SRING_SETUP_RING_MISC_CFG_FLAG_SECURITY_GET(_var) \ + (((_var) & HTT_SRING_SETUP_RING_MISC_CFG_FLAG_SECURITY_M) >> \ + HTT_SRING_SETUP_RING_MISC_CFG_FLAG_SECURITY_S) +#define HTT_SRING_SETUP_RING_MISC_CFG_FLAG_SECURITY_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_SRING_SETUP_RING_MISC_CFG_FLAG_SECURITY,\ + _val); \ + ((_var) |= ((_val) << \ + HTT_SRING_SETUP_RING_MISC_CFG_FLAG_SECURITY_S));\ + } while (0) + +/* During MSI write operation, SRNG drives value of this register bit into + * swap bit of GXI/AXI. + */ +#define HTT_SRING_SETUP_RING_MISC_CFG_FLAG_MSI_SWAP_M 0x08 +#define HTT_SRING_SETUP_RING_MISC_CFG_FLAG_MSI_SWAP_S 3 +#define HTT_SRING_SETUP_RING_MISC_CFG_FLAG_MSI_SWAP_GET(_var) \ + (((_var) & HTT_SRING_SETUP_RING_MISC_CFG_FLAG_MSI_SWAP_M) >> \ + HTT_SRING_SETUP_RING_MISC_CFG_FLAG_MSI_SWAP_S) +#define HTT_SRING_SETUP_RING_MISC_CFG_FLAG_MSI_SWAP_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_SRING_SETUP_RING_MISC_CFG_FLAG_MSI_SWAP,\ + _val); \ + ((_var) |= ((_val) << \ + HTT_SRING_SETUP_RING_MISC_CFG_FLAG_MSI_SWAP_S)); \ + } while (0) + +/* During Pointer write operation, SRNG drives value of this register bit into + * swap bit of GXI/AXI. + */ +#define HTT_SRING_SETUP_RING_MISC_CFG_FLAG_HOST_FW_SWAP_M 0x10 +#define HTT_SRING_SETUP_RING_MISC_CFG_FLAG_HOST_FW_SWAP_S 4 +#define HTT_SRING_SETUP_RING_MISC_CFG_FLAG_HOST_FW_SWAP_GET(_var) \ + (((_var) & HTT_SRING_SETUP_RING_MISC_CFG_FLAG_HOST_FW_SWAP_M) >> \ + HTT_SRING_SETUP_RING_MISC_CFG_FLAG_HOST_FW_SWAP_S) +#define HTT_SRING_SETUP_RING_MISC_CFG_FLAG_HOST_FW_SWAP_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL( \ + HTT_SRING_SETUP_RING_MISC_CFG_FLAG_HOST_FW_SWAP, _val); \ + ((_var) |= ((_val) << \ + HTT_SRING_SETUP_RING_MISC_CFG_FLAG_HOST_FW_SWAP_S)); \ + } while (0) + +/* During any data or TLV write operation, SRNG drives value of this register + * bit into swap bit of GXI/AXI. + */ +#define HTT_SRING_SETUP_RING_MISC_CFG_FLAG_TLV_SWAP_M 0x20 +#define HTT_SRING_SETUP_RING_MISC_CFG_FLAG_TLV_SWAP_S 5 +#define HTT_SRING_SETUP_RING_MISC_CFG_FLAG_TLV_SWAP_GET(_var) \ + (((_var) & HTT_SRING_SETUP_RING_MISC_CFG_FLAG_TLV_SWAP_M) >> \ + HTT_SRING_SETUP_RING_MISC_CFG_FLAG_TLV_SWAP_S) +#define HTT_SRING_SETUP_RING_MISC_CFG_FLAG_TLV_SWAP_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_SRING_SETUP_RING_MISC_CFG_FLAG_TLV_SWAP,\ + _val); \ + ((_var) |= ((_val) << \ + HTT_SRING_SETUP_RING_MISC_CFG_FLAG_TLV_SWAP_S));\ + } while (0) + +#define HTT_SRING_SETUP_RING_MISC_CFG_FLAG_RESERVED1 0x40 +#define HTT_SRING_SETUP_RING_MISC_CFG_FLAG_RESERVED2 0x80 + + +#define HTT_SRING_SETUP_HEAD_OFFSET32_REMOTE_BASE_ADDR_LO_M 0xffffffff +#define HTT_SRING_SETUP_HEAD_OFFSET32_REMOTE_BASE_ADDR_LO_S 0 +#define HTT_SRING_SETUP_HEAD_OFFSET32_REMOTE_BASE_ADDR_LO_GET(_var) \ + (((_var) & HTT_SRING_SETUP_HEAD_OFFSET32_REMOTE_BASE_ADDR_LO_M) >> \ + HTT_SRING_SETUP_HEAD_OFFSET32_REMOTE_BASE_ADDR_LO_S) +#define HTT_SRING_SETUP_HEAD_OFFSET32_REMOTE_BASE_ADDR_LO_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL( \ + HTT_SRING_SETUP_HEAD_OFFSET32_REMOTE_BASE_ADDR_LO, _val); \ + ((_var) |= ((_val) << \ + HTT_SRING_SETUP_HEAD_OFFSET32_REMOTE_BASE_ADDR_LO_S)); \ + } while (0) + +#define HTT_SRING_SETUP_HEAD_OFFSET32_REMOTE_BASE_ADDR_HI_M 0xffffffff +#define HTT_SRING_SETUP_HEAD_OFFSET32_REMOTE_BASE_ADDR_HI_S 0 +#define HTT_SRING_SETUP_HEAD_OFFSET32_REMOTE_BASE_ADDR_HI_GET(_var) \ + (((_var) & HTT_SRING_SETUP_HEAD_OFFSET32_REMOTE_BASE_ADDR_HI_M) >>\ + HTT_SRING_SETUP_HEAD_OFFSET32_REMOTE_BASE_ADDR_HI_S) +#define HTT_SRING_SETUP_HEAD_OFFSET32_REMOTE_BASE_ADDR_HI_SET(_var, _val)\ + do { \ + HTT_CHECK_SET_VAL( \ + HTT_SRING_SETUP_HEAD_OFFSET32_REMOTE_BASE_ADDR_HI, _val);\ + ((_var) |= ((_val) << \ + HTT_SRING_SETUP_HEAD_OFFSET32_REMOTE_BASE_ADDR_HI_S)); \ + } while (0) + +#define HTT_SRING_SETUP_TAIL_OFFSET32_REMOTE_BASE_ADDR_LO_M 0xffffffff +#define HTT_SRING_SETUP_TAIL_OFFSET32_REMOTE_BASE_ADDR_LO_S 0 +#define HTT_SRING_SETUP_TAIL_OFFSET32_REMOTE_BASE_ADDR_LO_GET(_var) \ + (((_var) & HTT_SRING_SETUP_TAIL_OFFSET32_REMOTE_BASE_ADDR_LO_M) >> \ + HTT_SRING_SETUP_TAIL_OFFSET32_REMOTE_BASE_ADDR_LO_S) +#define HTT_SRING_SETUP_TAIL_OFFSET32_REMOTE_BASE_ADDR_LO_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL( \ + HTT_SRING_SETUP_TAIL_OFFSET32_REMOTE_BASE_ADDR_LO, _val); \ + ((_var) |= ((_val) << \ + HTT_SRING_SETUP_TAIL_OFFSET32_REMOTE_BASE_ADDR_LO_S));\ + } while (0) + +#define HTT_SRING_SETUP_TAIL_OFFSET32_REMOTE_BASE_ADDR_HI_M 0xffffffff +#define HTT_SRING_SETUP_TAIL_OFFSET32_REMOTE_BASE_ADDR_HI_S 0 +#define HTT_SRING_SETUP_TAIL_OFFSET32_REMOTE_BASE_ADDR_HI_GET(_var) \ + (((_var) & HTT_SRING_SETUP_TAIL_OFFSET32_REMOTE_BASE_ADDR_HI_M) >> \ + HTT_SRING_SETUP_TAIL_OFFSET32_REMOTE_BASE_ADDR_HI_S) +#define HTT_SRING_SETUP_TAIL_OFFSET32_REMOTE_BASE_ADDR_HI_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL( \ + HTT_SRING_SETUP_TAIL_OFFSET32_REMOTE_BASE_ADDR_HI, _val); \ + ((_var) |= ((_val) << \ + HTT_SRING_SETUP_TAIL_OFFSET32_REMOTE_BASE_ADDR_HI_S)); \ + } while (0) + +#define HTT_SRING_SETUP_RING_MSI_ADDR_LO_M 0xffffffff +#define HTT_SRING_SETUP_RING_MSI_ADDR_LO_S 0 +#define HTT_SRING_SETUP_RING_MSI_ADDR_LO_GET(_var) \ + (((_var) & HTT_SRING_SETUP_RING_MSI_ADDR_LO_M) >> \ + HTT_SRING_SETUP_RING_MSI_ADDR_LO_S) +#define HTT_SRING_SETUP_RING_MSI_ADDR_LO_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_SRING_SETUP_RING_MSI_ADDR_LO, _val); \ + ((_var) |= ((_val) << HTT_SRING_SETUP_RING_MSI_ADDR_LO_S)); \ + } while (0) + +#define HTT_SRING_SETUP_RING_MSI_ADDR_HI_M 0xffffffff +#define HTT_SRING_SETUP_RING_MSI_ADDR_HI_S 0 +#define HTT_SRING_SETUP_RING_MSI_ADDR_HI_GET(_var) \ + (((_var) & HTT_SRING_SETUP_RING_MSI_ADDR_HI_M) >> \ + HTT_SRING_SETUP_RING_MSI_ADDR_HI_S) +#define HTT_SRING_SETUP_RING_MSI_ADDR_HI_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_SRING_SETUP_RING_MSI_ADDR_HI, _val); \ + ((_var) |= ((_val) << HTT_SRING_SETUP_RING_MSI_ADDR_HI_S)); \ + } while (0) + +#define HTT_SRING_SETUP_RING_MSI_DATA_M 0xffffffff +#define HTT_SRING_SETUP_RING_MSI_DATA_S 0 +#define HTT_SRING_SETUP_RING_MSI_DATA_GET(_var) \ + (((_var) & HTT_SRING_SETUP_RING_MSI_DATA_M) >> \ + HTT_SRING_SETUP_RING_MSI_DATA_S) +#define HTT_SRING_SETUP_RING_MSI_DATA_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_SRING_SETUP_RING_MSI_DATA, _val); \ + ((_var) |= ((_val) << HTT_SRING_SETUP_RING_MSI_DATA_S)); \ + } while (0) + +#define HTT_SRING_SETUP_INTR_BATCH_COUNTER_TH_M 0x00007fff +#define HTT_SRING_SETUP_INTR_BATCH_COUNTER_TH_S 0 +#define HTT_SRING_SETUP_INTR_BATCH_COUNTER_TH_GET(_var) \ + (((_var) & HTT_SRING_SETUP_INTR_BATCH_COUNTER_TH_M) >> \ + HTT_SRING_SETUP_INTR_BATCH_COUNTER_TH_S) +#define HTT_SRING_SETUP_INTR_BATCH_COUNTER_TH_SET(_var, _val) \ +do { \ + HTT_CHECK_SET_VAL(HTT_SRING_SETUP_INTR_BATCH_COUNTER_TH, _val); \ + ((_var) |= ((_val) << HTT_SRING_SETUP_INTR_BATCH_COUNTER_TH_S)); \ +} while (0) + +#define HTT_SRING_SETUP_SW_INTR_MODE_M 0x00008000 +#define HTT_SRING_SETUP_SW_INTR_MODE_S 15 +#define HTT_SRING_SETUP_SW_INTR_MODE_GET(_var) \ + (((_var) & HTT_SRING_SETUP_SW_INTR_MODE_M) >> \ + HTT_SRING_SETUP_SW_INTR_MODE_S) +#define HTT_SRING_SETUP_SW_INTR_MODE_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_SRING_SETUP_SW_INTR_MODE, _val); \ + ((_var) |= ((_val) << HTT_SRING_SETUP_SW_INTR_MODE_S)); \ + } while (0) + +#define HTT_SRING_SETUP_INTR_TIMER_TH_M 0xffff0000 +#define HTT_SRING_SETUP_INTR_TIMER_TH_S 16 +#define HTT_SRING_SETUP_INTR_TIMER_TH_GET(_var) \ + (((_var) & HTT_SRING_SETUP_INTR_TIMER_TH_M) >> \ + HTT_SRING_SETUP_INTR_TIMER_TH_S) +#define HTT_SRING_SETUP_INTR_TIMER_TH_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_SRING_SETUP_INTR_TIMER_TH, _val); \ + ((_var) |= ((_val) << HTT_SRING_SETUP_INTR_TIMER_TH_S)); \ + } while (0) + +#define HTT_SRING_SETUP_INTR_LOW_TH_M 0x0000ffff +#define HTT_SRING_SETUP_INTR_LOW_TH_S 0 +#define HTT_SRING_SETUP_INTR_LOW_TH_GET(_var) \ + (((_var) & HTT_SRING_SETUP_INTR_LOW_TH_M) >> \ + HTT_SRING_SETUP_INTR_LOW_TH_S) +#define HTT_SRING_SETUP_INTR_LOW_TH_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_SRING_SETUP_INTR_LOW_TH, _val); \ + ((_var) |= ((_val) << HTT_SRING_SETUP_INTR_LOW_TH_S)); \ + } while (0) + +#define HTT_SRING_SETUP_PREFETCH_TIMER_CFG_M 0x00070000 +#define HTT_SRING_SETUP_PREFETCH_TIMER_CFG_S 16 +#define HTT_SRING_SETUP_PREFETCH_TIMER_CFG_GET(_var) \ + (((_var) & HTT_SRING_SETUP_PREFETCH_TIMER_CFG_M) >> \ + HTT_SRING_SETUP_PREFETCH_TIMER_CFG_S) +#define HTT_SRING_SETUP_PREFETCH_TIMER_CFG_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_SRING_SETUP_PREFETCH_TIMER_CFG, _val); \ + ((_var) |= ((_val) << HTT_SRING_SETUP_PREFETCH_TIMER_CFG_S)); \ + } while (0) + +#define HTT_SRING_SETUP_RESPONSE_REQUIRED_M 0x00080000 +#define HTT_SRING_SETUP_RESPONSE_REQUIRED_S 19 +#define HTT_SRING_SETUP_RESPONSE_REQUIRED_GET(_var) \ + (((_var) & HTT_SRING_SETUP_RESPONSE_REQUIRED_M) >> \ + HTT_SRING_SETUP_RESPONSE_REQUIRED_S) +#define HTT_SRING_SETUP_RESPONSE_REQUIRED_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_SRING_SETUP_RESPONSE_REQUIRED, _val); \ + ((_var) |= ((_val) << HTT_SRING_SETUP_RESPONSE_REQUIRED_S)); \ + } while (0) + + +/** + * @brief HTT_H2T_MSG_TYPE_RX_RING_SELECTION_CFG Message + * + * @details + * HTT_H2T_MSG_TYPE_RX_RING_SELECTION_CFG message is sent by host to + * configure RXDMA rings. + * The configuration is per ring based and includes both packet subtypes + * and PPDU/MPDU TLVs. + * + * The message would appear as follows: + * + * |31 26|25|24|23 16|15 8|7 0| + * |-----------------+----------------+----------------+---------------| + * | rsvd1 |PS|SS| ring_id | pdev_id | msg_type | + * |-------------------------------------------------------------------| + * | rsvd2 | ring_buffer_size | + * |-------------------------------------------------------------------| + * | packet_type_enable_flags_0 | + * |-------------------------------------------------------------------| + * | packet_type_enable_flags_1 | + * |-------------------------------------------------------------------| + * | packet_type_enable_flags_2 | + * |-------------------------------------------------------------------| + * | packet_type_enable_flags_3 | + * |-------------------------------------------------------------------| + * | tlv_filter_in_flags | + * |-------------------------------------------------------------------| + * Where: + * PS = pkt_swap + * SS = status_swap + * The message is interpreted as follows: + * dword0 - b'0:7 - msg_type: This will be set to + * HTT_H2T_MSG_TYPE_RX_RING_SELECTION_CFG + * b'8:15 - pdev_id: + * 0 (for rings at SOC/UMAC level), + * 1/2/3 mac id (for rings at LMAC level) + * b'16:23 - ring_id : Identify the ring to configure. + * More details can be got from enum htt_srng_ring_id + * b'24 - status_swap: 1 is to swap status TLV + * b'25 - pkt_swap: 1 is to swap packet TLV + * b'26:31 - rsvd1: reserved for future use + * dword1 - b'0:16 - ring_buffer_size: size of bufferes referenced by rx ring, + * in byte units. + * Valid only for HW_TO_SW_RING and SW_TO_HW_RING + * - b'16:31 - rsvd2: Reserved for future use + * dword2 - b'0:31 - packet_type_enable_flags_0: + * Enable MGMT packet from 0b0000 to 0b1001 + * bits from low to high: FP, MD, MO - 3 bits + * FP: Filter_Pass + * MD: Monitor_Direct + * MO: Monitor_Other + * 10 mgmt subtypes * 3 bits -> 30 bits + * Refer to PKT_TYPE_ENABLE_FLAG0_xxx_MGMT_xxx defs + * dword3 - b'0:31 - packet_type_enable_flags_1: + * Enable MGMT packet from 0b1010 to 0b1111 + * bits from low to high: FP, MD, MO - 3 bits + * Refer to PKT_TYPE_ENABLE_FLAG1_xxx_MGMT_xxx defs + * dword4 - b'0:31 - packet_type_enable_flags_2: + * Enable CTRL packet from 0b0000 to 0b1001 + * bits from low to high: FP, MD, MO - 3 bits + * Refer to PKT_TYPE_ENABLE_FLAG2_xxx_CTRL_xxx defs + * dword5 - b'0:31 - packet_type_enable_flags_3: + * Enable CTRL packet from 0b1010 to 0b1111, + * MCAST_DATA, UCAST_DATA, NULL_DATA + * bits from low to high: FP, MD, MO - 3 bits + * Refer to PKT_TYPE_ENABLE_FLAG3_xxx_CTRL_xxx defs + * dword6 - b'0:31 - tlv_filter_in_flags: + * Filter in Attention/MPDU/PPDU/Header/User tlvs + * Refer to CFG_TLV_FILTER_IN_FLAG defs + */ +PREPACK struct htt_rx_ring_selection_cfg_t { + A_UINT32 msg_type: 8, + pdev_id: 8, + ring_id: 8, + status_swap: 1, + pkt_swap: 1, + rsvd1: 6; + A_UINT32 ring_buffer_size: 16, + rsvd2: 16; + A_UINT32 packet_type_enable_flags_0; + A_UINT32 packet_type_enable_flags_1; + A_UINT32 packet_type_enable_flags_2; + A_UINT32 packet_type_enable_flags_3; + A_UINT32 tlv_filter_in_flags; +} POSTPACK; + +#define HTT_RX_RING_SELECTION_CFG_SZ \ + (sizeof(struct htt_rx_ring_selection_cfg_t)) + +#define HTT_RX_RING_SELECTION_CFG_PDEV_ID_M 0x0000ff00 +#define HTT_RX_RING_SELECTION_CFG_PDEV_ID_S 8 +#define HTT_RX_RING_SELECTION_CFG_PDEV_ID_GET(_var) \ + (((_var) & HTT_RX_RING_SELECTION_CFG_PDEV_ID_M) >> \ + HTT_RX_RING_SELECTION_CFG_PDEV_ID_S) +#define HTT_RX_RING_SELECTION_CFG_PDEV_ID_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_RING_SELECTION_CFG_PDEV_ID, _val); \ + ((_var) |= ((_val) << HTT_RX_RING_SELECTION_CFG_PDEV_ID_S)); \ + } while (0) + +#define HTT_RX_RING_SELECTION_CFG_RING_ID_M 0x00ff0000 +#define HTT_RX_RING_SELECTION_CFG_RING_ID_S 16 +#define HTT_RX_RING_SELECTION_CFG_RING_ID_GET(_var) \ + (((_var) & HTT_RX_RING_SELECTION_CFG_RING_ID_M) >> \ + HTT_RX_RING_SELECTION_CFG_RING_ID_S) +#define HTT_RX_RING_SELECTION_CFG_RING_ID_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_RING_SELECTION_CFG_RING_ID, _val); \ + ((_var) |= ((_val) << HTT_RX_RING_SELECTION_CFG_RING_ID_S)); \ + } while (0) + +#define HTT_RX_RING_SELECTION_CFG_STATUS_TLV_SWAP_M 0x01000000 +#define HTT_RX_RING_SELECTION_CFG_STATUS_TLV_SWAP_S 24 +#define HTT_RX_RING_SELECTION_CFG_STATUS_TLV_GET(_var) \ + (((_var) & HTT_RX_RING_SELECTION_CFG_STATUS_TLV_SWAP_M) >> \ + HTT_RX_RING_SELECTION_CFG_STATUS_TLV_SWAP_S) +#define HTT_RX_RING_SELECTION_CFG_STATUS_TLV_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_RING_SELECTION_CFG_STATUS_TLV_SWAP,\ + _val); \ + ((_var) |= ((_val) << \ + HTT_RX_RING_SELECTION_CFG_STATUS_TLV_SWAP_S)); \ + } while (0) + +#define HTT_RX_RING_SELECTION_CFG_PKT_TLV_SWAP_M 0x02000000 +#define HTT_RX_RING_SELECTION_CFG_PKT_TLV_SWAP_S 25 +#define HTT_RX_RING_SELECTION_CFG_PKT_TLV_GET(_var) \ + (((_var) & HTT_RX_RING_SELECTION_CFG_PKT_TLV_SWAP_M) >> \ + HTT_RX_RING_SELECTION_CFG_PKT_TLV_SWAP_S) +#define HTT_RX_RING_SELECTION_CFG_PKT_TLV_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_RING_SELECTION_CFG_PKT_TLV_SWAP,\ + _val); \ + ((_var) |= ((_val) << \ + HTT_RX_RING_SELECTION_CFG_PKT_TLV_SWAP_S)); \ + } while (0) + +#define HTT_RX_RING_SELECTION_CFG_RING_BUFFER_SIZE_M 0x0000ffff +#define HTT_RX_RING_SELECTION_CFG_RING_BUFFER_SIZE_S 0 +#define HTT_RX_RING_SELECTION_CFG_RING_BUFFER_SIZE_GET(_var) \ + (((_var) & HTT_RX_RING_SELECTION_CFG_RING_BUFFER_SIZE_M) >> \ + HTT_RX_RING_SELECTION_CFG_RING_BUFFER_SIZE_S) +#define HTT_RX_RING_SELECTION_CFG_RING_BUFFER_SIZE_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_RING_SELECTION_CFG_RING_BUFFER_SIZE,\ + _val); \ + ((_var) |= ((_val) << \ + HTT_RX_RING_SELECTION_CFG_RING_BUFFER_SIZE_S)); \ + } while (0) + +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG_0_M 0xffffffff +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG_0_S 0 +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG_0_GET(_var) \ + (((_var) & HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG_0_M) >> \ + HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG_0_S) +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG_0_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL( \ + HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG_0, \ + _val); \ + ((_var) |= ((_val) << \ + HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG_0_S)); \ + } while (0) + +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG_1_M 0xffffffff +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG_1_S 0 +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG_1_GET(_var) \ + (((_var) & HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG_1_M) >> \ + HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG_1_S) +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG_1_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL( \ + HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG_1, _val);\ + ((_var) |= ((_val) << \ + HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG_1_S)); \ + } while (0) + +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG_2_M 0xffffffff +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG_2_S 0 +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG_2_GET(_var) \ + (((_var) & HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG_2_M) >> \ + HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG_2_S) +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG_2_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL( \ + HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG_2, _val);\ + ((_var) |= ((_val) << \ + HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG_2_S)); \ + } while (0) + +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG_3_M 0xffffffff +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG_3_S 0 +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG_3_GET(_var) \ + (((_var) & HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG_3_M) >> \ + HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG_3_S) +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG_3_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL( \ + HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG_3, _val);\ + ((_var) |= ((_val) << \ + HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG_3_S)); \ + } while (0) + +#define HTT_RX_RING_SELECTION_CFG_TLV_FILTER_IN_FLAG_M 0xffffffff +#define HTT_RX_RING_SELECTION_CFG_TLV_FILTER_IN_FLAG_S 0 +#define HTT_RX_RING_SELECTION_CFG_TLV_FILTER_IN_FLAG_GET(_var) \ + (((_var) & HTT_RX_RING_SELECTION_CFG_TLV_FILTER_IN_FLAG_M) >> \ + HTT_RX_RING_SELECTION_CFG_TLV_FILTER_IN_FLAG_S) +#define HTT_RX_RING_SELECTION_CFG_TLV_FILTER_IN_FLAG_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL( \ + HTT_RX_RING_SELECTION_CFG_TLV_FILTER_IN_FLAG, _val); \ + ((_var) |= ((_val) << \ + HTT_RX_RING_SELECTION_CFG_TLV_FILTER_IN_FLAG_S)); \ + } while (0) + +/* + * Subtype based MGMT frames enable bits. + * FP: Filter_Pass, MD: Monitor_Direct MO: Monitor_Other + */ +/* association request */ +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG0_FP_MGMT_0000_M \ + 0x00000001 +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG0_FP_MGMT_0000_S 0 + +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG0_MD_MGMT_0000_M \ + 0x00000002 +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG0_MD_MGMT_0000_S 1 + +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG0_MO_MGMT_0000_M \ + 0x00000004 +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG0_MO_MGMT_0000_S 2 + +/* association response */ +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG0_FP_MGMT_0001_M \ + 0x00000008 +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG0_FP_MGMT_0001_S 3 + +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG0_MD_MGMT_0001_M \ + 0x00000010 +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG0_MD_MGMT_0001_S 4 + +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG0_MO_MGMT_0001_M \ + 0x00000020 +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG0_MO_MGMT_0001_S 5 + +/* Reassociation request */ +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG0_FP_MGMT_0010_M \ + 0x00000040 +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG0_FP_MGMT_0010_S 6 + +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG0_MD_MGMT_0010_M \ + 0x00000080 +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG0_MD_MGMT_0010_S 7 + +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG0_MO_MGMT_0010_M \ + 0x00000100 +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG0_MO_MGMT_0010_S 8 + +/* Reassociation response */ +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG0_FP_MGMT_0011_M \ + 0x00000200 +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG0_FP_MGMT_0011_S 9 + +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG0_MD_MGMT_0011_M \ + 0x00000400 +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG0_MD_MGMT_0011_S 10 + +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG0_MO_MGMT_0011_M \ + 0x00000800 +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG0_MO_MGMT_0011_S 11 + +/* Probe request */ +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG0_FP_MGMT_0100_M \ + 0x00001000 +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG0_FP_MGMT_0100_S 12 + +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG0_MD_MGMT_0100_M \ + 0x00002000 +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG0_MD_MGMT_0100_S 13 + +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG0_MO_MGMT_0100_M \ + 0x00004000 +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG0_MO_MGMT_0100_S 14 + +/* Probe response */ +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG0_FP_MGMT_0101_M \ + 0x00008000 +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG0_FP_MGMT_0101_S 15 + +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG0_MD_MGMT_0101_M \ + 0x00010000 +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG0_MD_MGMT_0101_S 16 + +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG0_MO_MGMT_0101_M \ + 0x00020000 +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG0_MO_MGMT_0101_S 17 + +/* Timing Advertisement */ +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG0_FP_MGMT_0110_M \ + 0x00040000 +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG0_FP_MGMT_0110_S 18 + +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG0_MD_MGMT_0110_M \ + 0x00080000 +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG0_MD_MGMT_0110_S 19 + +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG0_MO_MGMT_0110_M \ + 0x00100000 +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG0_MO_MGMT_0110_S 20 + +/* Reserved */ +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG0_FP_MGMT_0111_M \ + 0x00200000 +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG0_FP_MGMT_0111_S 21 + +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG0_MD_MGMT_0111_M \ + 0x00400000 +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG0_MD_MGMT_0111_S 22 + +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG0_MO_MGMT_0111_M \ + 0x00800000 +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG0_MO_MGMT_0111_S 23 + +/* Beacon */ +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG0_FP_MGMT_1000_M \ + 0x01000001 +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG0_FP_MGMT_1000_S 24 + +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG0_MD_MGMT_1000_M \ + 0x02000001 +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG0_MD_MGMT_1000_S 25 + +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG0_MO_MGMT_1000_M \ + 0x00000001 +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG0_MO_MGMT_1000_S 26 + +/* ATIM */ +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG0_FP_MGMT_1001_M \ + 0x00000001 +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG0_FP_MGMT_1001_S 27 + +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG0_MD_MGMT_1001_M \ + 0x00000001 +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG0_MD_MGMT_1001_S 28 + +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG0_MO_MGMT_1001_M \ + 0x00000001 +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG0_MO_MGMT_1001_S 29 + +/* Disassociation */ +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG1_FP_MGMT_1010_M \ + 0x00000001 +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG1_FP_MGMT_1010_S 0 + +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG1_MD_MGMT_1010_M \ + 0x00000002 +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG1_MD_MGMT_1010_S 1 + +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG1_MO_MGMT_1010_M \ + 0x00000004 +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG1_MO_MGMT_1010_S 2 + +/* Authentication */ +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG1_FP_MGMT_1011_M \ + 0x00000008 +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG1_FP_MGMT_1011_S 3 + +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG1_MD_MGMT_1011_M \ + 0x00000010 +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG1_MD_MGMT_1011_S 4 + +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG1_MO_MGMT_1011_M \ + 0x00000020 +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG1_MO_MGMT_1011_S 5 + +/* Deauthentication */ +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG1_FP_MGMT_1100_M \ + 0x00000040 +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG1_FP_MGMT_1100_S 6 + +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG1_MD_MGMT_1100_M \ + 0x00000080 +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG1_MD_MGMT_1100_S 7 + +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG1_MO_MGMT_1100_M \ + 0x00000100 +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG1_MO_MGMT_1100_S 8 + +/* Action */ +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG1_FP_MGMT_1101_M \ + 0x00000200 +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG1_FP_MGMT_1101_S 9 + +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG1_MD_MGMT_1101_M \ + 0x00000400 +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG1_MD_MGMT_1101_S 10 + +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG1_MO_MGMT_1101_M \ + 0x00000800 +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG1_MO_MGMT_1101_S 11 + +/* Action No Ack */ +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG1_FP_MGMT_1110_M \ + 0x00001000 +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG1_FP_MGMT_1110_S 12 + +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG1_MD_MGMT_1110_M \ + 0x00002000 +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG1_MD_MGMT_1110_S 13 + +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG1_MO_MGMT_1110_M \ + 0x00004000 +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG1_MO_MGMT_1110_S 14 + +/* Reserved */ +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG1_FP_MGMT_1111_M \ + 0x00008000 +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG1_FP_MGMT_1111_S 15 + +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG1_MD_MGMT_1111_M \ + 0x00010000 +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG1_MD_MGMT_1111_S 16 + +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG1_MO_MGMT_1111_M \ + 0x00020000 +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG1_MO_MGMT_1111_S 17 + +/* + * Subtype based CTRL frames enable bits. + * FP: Filter_Pass, MD: Monitor_Direct, MO: Monitor_Other + */ +/* Reserved */ +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG2_FP_CTRL_0000_M \ + 0x00000001 +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG2_FP_CTRL_0000_S 0 + +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG2_MD_CTRL_0000_M \ + 0x00000002 +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG2_MD_CTRL_0000_S 1 + +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG2_MO_CTRL_0000_M \ + 0x00000004 +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG2_MO_CTRL_0000_S 2 + +/* Reserved */ +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG2_FP_CTRL_0001_M \ + 0x00000008 +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG2_FP_CTRL_0001_S 3 + +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG2_MD_CTRL_0001_M \ + 0x00000010 +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG2_MD_CTRL_0001_S 4 + +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG2_MO_CTRL_0001_M \ + 0x00000020 +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG2_MO_CTRL_0001_S 5 + +/* Reserved */ +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG2_FP_CTRL_0010_M \ + 0x00000040 +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG2_FP_CTRL_0010_S 6 + +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG2_MD_CTRL_0010_M \ + 0x00000080 +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG2_MD_CTRL_0010_S 7 + +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG2_MO_CTRL_0010_M \ + 0x00000100 +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG2_MO_CTRL_0010_S 8 + +/* Reserved */ +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG2_FP_CTRL_0011_M \ + 0x00000200 +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG2_FP_CTRL_0011_S 9 + +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG2_MD_CTRL_0011_M \ + 0x00000400 +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG2_MD_CTRL_0011_S 10 + +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG2_MO_CTRL_0011_M \ + 0x00000800 +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG2_MO_CTRL_0011_S 11 + +/* Reserved */ +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG2_FP_CTRL_0100_M \ + 0x00001000 +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG2_FP_CTRL_0100_S 12 + +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG2_MD_CTRL_0100_M \ + 0x00002000 +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG2_MD_CTRL_0100_S 13 + +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG2_MO_CTRL_0100_M \ + 0x00004000 +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG2_MO_CTRL_0100_S 14 + +/* Reserved */ +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG2_FP_CTRL_0101_M \ + 0x00008000 +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG2_FP_CTRL_0101_S 15 + +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG2_MD_CTRL_0101_M \ + 0x00010000 +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG2_MD_CTRL_0101_S 16 + +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG2_MO_CTRL_0101_M \ + 0x00020000 +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG2_MO_CTRL_0101_S 17 + +/* Reserved */ +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG2_FP_CTRL_0110_M \ + 0x00040000 +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG2_FP_CTRL_0110_S 18 + +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG2_MD_CTRL_0110_M \ + 0x00080000 +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG2_MD_CTRL_0110_S 19 + +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG2_MO_CTRL_0110_M \ + 0x00100000 +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG2_MO_CTRL_0110_S 20 + +/* Control Wrapper */ +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG2_FP_CTRL_0111_M \ + 0x00200000 +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG2_FP_CTRL_0111_S 21 + +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG2_MD_CTRL_0111_M \ + 0x00400000 +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG2_MD_CTRL_0111_S 22 + +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG2_MO_CTRL_0111_M \ + 0x00800000 +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG2_MO_CTRL_0111_S 23 + +/* Block Ack Request */ +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG2_FP_CTRL_1000_M \ + 0x01000001 +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG2_FP_CTRL_1000_S 24 + +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG2_MD_CTRL_1000_M \ + 0x02000001 +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG2_MD_CTRL_1000_S 25 + +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG2_MO_CTRL_1000_M \ + 0x00000001 +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG2_MO_CTRL_1000_S 26 + +/* Block Ack*/ +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG2_FP_CTRL_1001_M \ + 0x00000001 +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG2_FP_CTRL_1001_S 27 + +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG2_MD_CTRL_1001_M \ + 0x00000001 +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG2_MD_CTRL_1001_S 28 + +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG2_MO_CTRL_1001_M \ + 0x00000001 +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG2_MO_CTRL_1001_S 29 + +/* PS-POLL */ +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG3_FP_CTRL_1010_M \ + 0x00000001 +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG3_FP_CTRL_1010_S 0 + +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG3_MD_CTRL_1010_M \ + 0x00000002 +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG3_MD_CTRL_1010_S 1 + +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG3_MO_CTRL_1010_M \ + 0x00000004 +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG3_MO_CTRL_1010_S 2 + +/* RTS */ +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG3_FP_CTRL_1011_M \ + 0x00000008 +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG3_FP_CTRL_1011_S 3 + +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG3_MD_CTRL_1011_M \ + 0x00000010 +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG3_MD_CTRL_1011_S 4 + +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG3_MO_CTRL_1011_M \ + 0x00000020 +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG3_MO_CTRL_1011_S 5 + +/* CTS */ +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG3_FP_CTRL_1100_M \ + 0x00000040 +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG3_FP_CTRL_1100_S 6 + +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG3_MD_CTRL_1100_M \ + 0x00000080 +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG3_MD_CTRL_1100_S 7 + +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG3_MO_CTRL_1100_M \ + 0x00000100 +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG3_MO_CTRL_1100_S 8 + +/* ACK */ +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG3_FP_CTRL_1101_M \ + 0x00000200 +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG3_FP_CTRL_1101_S 9 + +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG3_MD_CTRL_1101_M \ + 0x00000400 +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG3_MD_CTRL_1101_S 10 + +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG3_MO_CTRL_1101_M \ + 0x00000800 +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG3_MO_CTRL_1101_S 11 + +/* CF-END */ +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG3_FP_CTRL_1110_M \ + 0x00001000 +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG3_FP_CTRL_1110_S 12 + +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG3_MD_CTRL_1110_M \ + 0x00002000 +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG3_MD_CTRL_1110_S 13 + +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG3_MO_CTRL_1110_M \ + 0x00004000 +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG3_MO_CTRL_1110_S 14 + +/* CF-END + CF-ACK */ +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG3_FP_CTRL_1111_M \ + 0x00008000 +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG3_FP_CTRL_1111_S 15 + +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG3_MD_CTRL_1111_M \ + 0x00010000 +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG3_MD_CTRL_1111_S 16 + +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG3_MO_CTRL_1111_M \ + 0x00020000 +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG3_MO_CTRL_1111_S 17 + +/* Multicast data */ +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG3_FP_DATA_MCAST_M \ + 0x00040000 +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG3_FP_DATA_MCAST_S 18 + +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG3_MD_DATA_MCAST_M \ + 0x00080000 +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG3_MD_DATA_MCAST_S 19 + +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG3_MO_DATA_MCAST_M \ + 0x00100000 +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG3_MO_DATA_MCAST_S 20 + +/* Unicast data */ +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG3_FP_DATA_UCAST_M \ + 0x00200000 +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG3_FP_DATA_UCAST_S 21 + +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG3_MD_DATA_UCAST_M \ + 0x00400000 +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG3_MD_DATA_UCAST_S 22 + +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG3_MO_DATA_UCAST_M \ + 0x00800000 +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG3_MO_DATA_UCAST_S 23 + +/* NULL data */ +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG3_FP_DATA_NULL_M \ + 0x01000000 +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG3_FP_DATA_NULL_S 24 + +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG3_MD_DATA_NULL_M \ + 0x02000000 +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG3_MD_DATA_NULL_S 25 + +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG3_MO_DATA_NULL_M \ + 0x04000000 +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_FLAG3_MO_DATA_NULL_S 26 + +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_SET(word, httsym, value) \ + do { \ + HTT_CHECK_SET_VAL(httsym, value); \ + (word) |= (value) << httsym##_S; \ + } while (0) +#define HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_GET(word, httsym) \ + (((word) & httsym##_M) >> httsym##_S) + +#define htt_rx_ring_pkt_enable_subtype_set( \ + word, flag, mode, type, subtype, val) \ + HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_SET(word, \ +HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_##flag##_##mode##_##type##_##subtype,\ + val) + +#define htt_rx_ring_pkt_enable_subtype_get( \ + word, flag, mode, type, subtype) \ + HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_GET(word,\ +HTT_RX_RING_SELECTION_CFG_PKT_TYPE_ENABLE_##flag##_##mode##_##type##_##subtype) + +/* Definition to filter in TLVs */ +#define HTT_RX_RING_SELECTION_CFG_TLV_FILTER_IN_FLAG_RX_MPDU_START_M 0x00000001 +#define HTT_RX_RING_SELECTION_CFG_TLV_FILTER_IN_FLAG_RX_MPDU_START_S 0 + +#define HTT_RX_RING_SELECTION_CFG_TLV_FILTER_IN_FLAG_RX_MSDU_START_M 0x00000002 +#define HTT_RX_RING_SELECTION_CFG_TLV_FILTER_IN_FLAG_RX_MSDU_START_S 1 + +#define HTT_RX_RING_SELECTION_CFG_TLV_FILTER_IN_FLAG_RX_PACKET_M 0x00000004 +#define HTT_RX_RING_SELECTION_CFG_TLV_FILTER_IN_FLAG_RX_PACKET_S 2 + +#define HTT_RX_RING_SELECTION_CFG_TLV_FILTER_IN_FLAG_RX_MSDU_END_M 0x00000008 +#define HTT_RX_RING_SELECTION_CFG_TLV_FILTER_IN_FLAG_RX_MSDU_END_S 3 + +#define HTT_RX_RING_SELECTION_CFG_TLV_FILTER_IN_FLAG_RX_MPDU_END_M 0x00000010 +#define HTT_RX_RING_SELECTION_CFG_TLV_FILTER_IN_FLAG_RX_MPDU_END_S 4 + +#define HTT_RX_RING_SELECTION_CFG_TLV_FILTER_IN_FLAG_RX_PACKET_HEADER_M \ + 0x00000020 +#define HTT_RX_RING_SELECTION_CFG_TLV_FILTER_IN_FLAG_RX_PACKET_HEADER_S 5 + +#define HTT_RX_RING_SELECTION_CFG_TLV_FILTER_IN_FLAG_RX_RESERVED_M 0x00000040 +#define HTT_RX_RING_SELECTION_CFG_TLV_FILTER_IN_FLAG_RX_RESERVED_S 6 + +#define HTT_RX_RING_SELECTION_CFG_TLV_FILTER_IN_FLAG_RX_ATTENTION_M 0x00000080 +#define HTT_RX_RING_SELECTION_CFG_TLV_FILTER_IN_FLAG_RX_ATTENTION_S 7 + +#define HTT_RX_RING_SELECTION_CFG_TLV_FILTER_IN_FLAG_RX_PPDU_START_M 0x00000100 +#define HTT_RX_RING_SELECTION_CFG_TLV_FILTER_IN_FLAG_RX_PPDU_START_S 8 + +#define HTT_RX_RING_SELECTION_CFG_TLV_FILTER_IN_FLAG_RX_PPDU_END_M 0x00000200 +#define HTT_RX_RING_SELECTION_CFG_TLV_FILTER_IN_FLAG_RX_PPDU_END_S 9 + +#define HTT_RX_RING_SELECTION_CFG_TLV_FILTER_IN_FLAG_RX_PPDU_END_USER_STATS_M \ + 0x00000400 +#define HTT_RX_RING_SELECTION_CFG_TLV_FILTER_IN_FLAG_RX_PPDU_END_USER_STATS_S 10 + +#define HTT_RX_RING_SELECTION_CFG_TLV_FILTER_IN_FLAG_RX_PPDU_END_USER_STATS_EXT_M 0x00000800 +#define HTT_RX_RING_SELECTION_CFG_TLV_FILTER_IN_FLAG_RX_PPDU_END_USER_STATS_EXT_S 11 + +#define HTT_RX_RING_SELECTION_CFG_TLV_FILTER_IN_FLAG_RX_PPDU_END_STATUS_DONE_M \ + 0x00001000 +#define HTT_RX_RING_SELECTION_CFG_TLV_FILTER_IN_FLAG_RX_PPDU_END_STATUS_DONE_S\ + 12 + +#define HTT_RX_RING_TLV_ENABLE_SET(word, httsym, enable) \ + do { \ + HTT_CHECK_SET_VAL(httsym, enable); \ + (word) |= (enable) << httsym##_S; \ + } while (0) +#define HTT_RX_RING_TLV_ENABLE_GET(word, httsym) \ + (((word) & httsym##_M) >> httsym##_S) + +#define htt_rx_ring_tlv_filter_in_enable_set(word, tlv, enable) \ + HTT_RX_RING_TLV_ENABLE_SET( \ + word, HTT_RX_RING_SELECTION_CFG_TLV_FILTER_IN_FLAG_RX_##tlv, enable) + +#define htt_rx_ring_tlv_filter_in_enable_get(word, tlv) \ + HTT_RX_RING_TLV_ENABLE_GET(word, \ + HTT_RX_RING_SELECTION_CFG_TLV_FILTER_IN_FLAG_RX_##tlv) + +/** + * @brief HTT_H2T_MSG_TYPE_RFS_CONFIG + * host --> target Receive Flow Steering configuration message definition. + * Host must send this message before sending HTT_H2T_MSG_TYPE_RX_RING_CFG. + * The reason for this is we want RFS to be configured and ready before MAC + * remote ring is enabled via HTT_H2T_MSG_TYPE_RX_RING_CFG. + * + * |31 24|23 16|15 9|8|7 0| + * |----------------+----------------+----------------+----------------| + * | reserved |E| msg type | + * |-------------------------------------------------------------------| + * Where E = RFS enable flag + * + * The RFS_CONFIG message consists of a single 4-byte word. + * + * Header fields: + * - MSG_TYPE + * Bits 7:0 + * Purpose: identifies this as a RFS config msg + * Value: 0xf (HTT_H2T_MSG_TYPE_RFS_CONFIG) + * - RFS_CONFIG + * Bit 8 + * Purpose: Tells target whether to enable (1) or disable (0) + * flow steering feature when sending rx indication messages to host + */ +#define HTT_RFS_CFG_REQ_BYTES 4 +#define HTT_H2T_RFS_CONFIG_M 0x100 +#define HTT_H2T_RFS_CONFIG_S 8 +#define HTT_RX_RFS_CONFIG_GET(_var) \ + (((_var) & HTT_H2T_RFS_CONFIG_M) >> \ + HTT_H2T_RFS_CONFIG_S) +#define HTT_RX_RFS_CONFIG_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_H2T_RFS_CONFIG, _val); \ + ((_var) |= ((_val) << HTT_H2T_RFS_CONFIG_S)); \ + } while (0) + +/*=== target -> host messages ===============================================*/ + + +enum htt_t2h_msg_type { + HTT_T2H_MSG_TYPE_VERSION_CONF = 0x0, + HTT_T2H_MSG_TYPE_RX_IND = 0x1, + HTT_T2H_MSG_TYPE_RX_FLUSH = 0x2, + HTT_T2H_MSG_TYPE_PEER_MAP = 0x3, + HTT_T2H_MSG_TYPE_PEER_UNMAP = 0x4, + HTT_T2H_MSG_TYPE_RX_ADDBA = 0x5, + HTT_T2H_MSG_TYPE_RX_DELBA = 0x6, + HTT_T2H_MSG_TYPE_TX_COMPL_IND = 0x7, + HTT_T2H_MSG_TYPE_PKTLOG = 0x8, + HTT_T2H_MSG_TYPE_STATS_CONF = 0x9, + HTT_T2H_MSG_TYPE_RX_FRAG_IND = 0xa, + HTT_T2H_MSG_TYPE_SEC_IND = 0xb, + DEPRECATED_HTT_T2H_MSG_TYPE_RC_UPDATE_IND = 0xc,/* no longer used */ + HTT_T2H_MSG_TYPE_TX_INSPECT_IND = 0xd, + HTT_T2H_MSG_TYPE_MGMT_TX_COMPL_IND = 0xe, + /* only used for HL, add HTT MSG for HTT CREDIT update */ + HTT_T2H_MSG_TYPE_TX_CREDIT_UPDATE_IND = 0xf, + HTT_T2H_MSG_TYPE_RX_PN_IND = 0x10, + HTT_T2H_MSG_TYPE_RX_OFFLOAD_DELIVER_IND = 0x11, + HTT_T2H_MSG_TYPE_RX_IN_ORD_PADDR_IND = 0x12, + /* 0x13 is reserved for RX_RING_LOW_IND (RX Full reordering related) */ + HTT_T2H_MSG_TYPE_WDI_IPA_OP_RESPONSE = 0x14, + HTT_T2H_MSG_TYPE_CHAN_CHANGE = 0x15, + HTT_T2H_MSG_TYPE_RX_OFLD_PKT_ERR = 0x16, + HTT_T2H_MSG_TYPE_RATE_REPORT = 0x17, + HTT_T2H_MSG_TYPE_FLOW_POOL_MAP = 0x18, + HTT_T2H_MSG_TYPE_FLOW_POOL_UNMAP = 0x19, + HTT_T2H_MSG_TYPE_SRING_SETUP_DONE = 0x1a, + HTT_T2H_MSG_TYPE_MAP_FLOW_INFO = 0x1b, + + HTT_T2H_MSG_TYPE_TEST, + /* keep this last */ + HTT_T2H_NUM_MSGS +}; + +/* + * HTT target to host message type - + * stored in bits 7:0 of the first word of the message + */ +#define HTT_T2H_MSG_TYPE_M 0xff +#define HTT_T2H_MSG_TYPE_S 0 + +#define HTT_T2H_MSG_TYPE_SET(word, msg_type) \ + do { \ + HTT_CHECK_SET_VAL(HTT_T2H_MSG_TYPE, msg_type); \ + (word) |= ((msg_type) << HTT_T2H_MSG_TYPE_S); \ + } while (0) +#define HTT_T2H_MSG_TYPE_GET(word) \ + (((word) & HTT_T2H_MSG_TYPE_M) >> HTT_T2H_MSG_TYPE_S) + +/** + * @brief target -> host version number confirmation message definition + * + * |31 24|23 16|15 8|7 0| + * |----------------+----------------+----------------+----------------| + * | reserved | major number | minor number | msg type | + * |-------------------------------------------------------------------| + * : option request TLV (optional) | + * :...................................................................: + * + * The VER_CONF message may consist of a single 4-byte word, or may be + * extended with TLVs that specify HTT options selected by the target. + * The following option TLVs may be appended to the VER_CONF message: + * - LL_BUS_ADDR_SIZE + * - HL_SUPPRESS_TX_COMPL_IND + * - MAX_TX_QUEUE_GROUPS + * These TLVs may appear in an arbitrary order. Any number of these TLVs + * may be appended to the VER_CONF message (but only one TLV of each type). + * + * Header fields: + * - MSG_TYPE + * Bits 7:0 + * Purpose: identifies this as a version number confirmation message + * Value: 0x0 + * - VER_MINOR + * Bits 15:8 + * Purpose: Specify the minor number of the HTT message library version + * in use by the target firmware. + * The minor number specifies the specific revision within a range + * of fundamentally compatible HTT message definition revisions. + * Compatible revisions involve adding new messages or perhaps + * adding new fields to existing messages, in a backwards-compatible + * manner. + * Incompatible revisions involve changing the message type values, + * or redefining existing messages. + * Value: minor number + * - VER_MAJOR + * Bits 15:8 + * Purpose: Specify the major number of the HTT message library version + * in use by the target firmware. + * The major number specifies the family of minor revisions that are + * fundamentally compatible with each other, but not with prior or + * later families. + * Value: major number + */ + +#define HTT_VER_CONF_MINOR_M 0x0000ff00 +#define HTT_VER_CONF_MINOR_S 8 +#define HTT_VER_CONF_MAJOR_M 0x00ff0000 +#define HTT_VER_CONF_MAJOR_S 16 + + +#define HTT_VER_CONF_MINOR_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_VER_CONF_MINOR, value); \ + (word) |= (value) << HTT_VER_CONF_MINOR_S; \ + } while (0) +#define HTT_VER_CONF_MINOR_GET(word) \ + (((word) & HTT_VER_CONF_MINOR_M) >> HTT_VER_CONF_MINOR_S) + +#define HTT_VER_CONF_MAJOR_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_VER_CONF_MAJOR, value); \ + (word) |= (value) << HTT_VER_CONF_MAJOR_S; \ + } while (0) +#define HTT_VER_CONF_MAJOR_GET(word) \ + (((word) & HTT_VER_CONF_MAJOR_M) >> HTT_VER_CONF_MAJOR_S) + + +#define HTT_VER_CONF_BYTES 4 + + +/** + * @brief - target -> host HTT Rx In order indication message + * + * @details + * + * |31 24|23 |15|14|13|12|11|10|9|8|7|6|5|4 0| + * |----------------+-------------------+---------------------+---------------| + * | peer ID | P| F| O| ext TID | msg type | + * |--------------------------------------------------------------------------| + * | MSDU count | Reserved | vdev id | + * |--------------------------------------------------------------------------| + * | MSDU 0 bus address (bits 31:0) | + #if HTT_PADDR64 + * | MSDU 0 bus address (bits 63:32) | + #endif + * |--------------------------------------------------------------------------| + * | MSDU info | MSDU 0 FW Desc | MSDU 0 Length | + * |--------------------------------------------------------------------------| + * | MSDU 1 bus address (bits 31:0) | + #if HTT_PADDR64 + * | MSDU 1 bus address (bits 63:32) | + #endif + * |--------------------------------------------------------------------------| + * | MSDU info | MSDU 1 FW Desc | MSDU 1 Length | + * |--------------------------------------------------------------------------| + */ + + +/** @brief - MSDU info byte for TCP_CHECKSUM_OFFLOAD use + * + * @details + * bits + * | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | + * |-----+----+-------+--------+--------+---------+---------+-----------| + * | reserved | is IP | is UDP | is TCP | is IPv6 |IP chksum| TCP/UDP | + * | | frag | | | | fail |chksum fail| + * |-----+----+-------+--------+--------+---------+---------+-----------| + * (see fw_rx_msdu_info def in wal_rx_desc.h) + */ + +struct htt_rx_in_ord_paddr_ind_hdr_t { + A_UINT32 /* word 0 */ + msg_type:8, + ext_tid:5, + offload:1, + frag:1, + /* + * Tell host whether to store MSDUs referenced in this message + * in pktlog + */ + pktlog:1, + peer_id:16; + + A_UINT32 /* word 1 */ + vap_id:8, + reserved_1:8, + msdu_cnt:16; +}; + +struct htt_rx_in_ord_paddr_ind_msdu32_t { + A_UINT32 dma_addr; + A_UINT32 + length:16, + fw_desc:8, + msdu_info:8; +}; +struct htt_rx_in_ord_paddr_ind_msdu64_t { + A_UINT32 dma_addr_lo; + A_UINT32 dma_addr_hi; + A_UINT32 + length:16, + fw_desc:8, + msdu_info:8; +}; +#if HTT_PADDR64 +#define htt_rx_in_ord_paddr_ind_msdu_t htt_rx_in_ord_paddr_ind_msdu64_t +#else +#define htt_rx_in_ord_paddr_ind_msdu_t htt_rx_in_ord_paddr_ind_msdu32_t +#endif + + +#define HTT_RX_IN_ORD_PADDR_IND_HDR_BYTES \ + (sizeof(struct htt_rx_in_ord_paddr_ind_hdr_t)) +#define HTT_RX_IN_ORD_PADDR_IND_HDR_DWORDS \ + (HTT_RX_IN_ORD_PADDR_IND_HDR_BYTES >> 2) +#define HTT_RX_IN_ORD_PADDR_IND_MSDU_BYTE_OFFSET \ + HTT_RX_IN_ORD_PADDR_IND_HDR_BYTES +#define HTT_RX_IN_ORD_PADDR_IND_MSDU_DWORD_OFFSET \ + HTT_RX_IN_ORD_PADDR_IND_HDR_DWORDS +#define HTT_RX_IN_ORD_PADDR_IND_MSDU_BYTES_64 \ + (sizeof(struct htt_rx_in_ord_paddr_ind_msdu64_t)) +#define HTT_RX_IN_ORD_PADDR_IND_MSDU_DWORDS_64 \ + (HTT_RX_IN_ORD_PADDR_IND_MSDU_BYTES_64 >> 2) +#define HTT_RX_IN_ORD_PADDR_IND_MSDU_BYTES_32 \ + (sizeof(struct htt_rx_in_ord_paddr_ind_msdu32_t)) +#define HTT_RX_IN_ORD_PADDR_IND_MSDU_DWORDS_32 \ + (HTT_RX_IN_ORD_PADDR_IND_MSDU_BYTES_32 >> 2) +#define HTT_RX_IN_ORD_PADDR_IND_MSDU_BYTES \ + (sizeof(struct htt_rx_in_ord_paddr_ind_msdu_t)) +#define HTT_RX_IN_ORD_PADDR_IND_MSDU_DWORDS \ + (HTT_RX_IN_ORD_PADDR_IND_MSDU_BYTES >> 2) + +#define HTT_RX_IN_ORD_PADDR_IND_EXT_TID_M 0x00001f00 +#define HTT_RX_IN_ORD_PADDR_IND_EXT_TID_S 8 +#define HTT_RX_IN_ORD_PADDR_IND_OFFLOAD_M 0x00002000 +#define HTT_RX_IN_ORD_PADDR_IND_OFFLOAD_S 13 +#define HTT_RX_IN_ORD_PADDR_IND_FRAG_M 0x00004000 +#define HTT_RX_IN_ORD_PADDR_IND_FRAG_S 14 +#define HTT_RX_IN_ORD_PADDR_IND_PKTLOG_M 0x00008000 +#define HTT_RX_IN_ORD_PADDR_IND_PKTLOG_S 15 +#define HTT_RX_IN_ORD_PADDR_IND_PEER_ID_M 0xffff0000 +#define HTT_RX_IN_ORD_PADDR_IND_PEER_ID_S 16 +#define HTT_RX_IN_ORD_PADDR_IND_VAP_ID_M 0x000000ff +#define HTT_RX_IN_ORD_PADDR_IND_VAP_ID_S 0 +#define HTT_RX_IN_ORD_PADDR_IND_MSDU_CNT_M 0xffff0000 +#define HTT_RX_IN_ORD_PADDR_IND_MSDU_CNT_S 16 +/* for systems using 64-bit format for bus addresses */ +#define HTT_RX_IN_ORD_PADDR_IND_PADDR_HI_M 0xffffffff +#define HTT_RX_IN_ORD_PADDR_IND_PADDR_HI_S 0 +#define HTT_RX_IN_ORD_PADDR_IND_PADDR_LO_M 0xffffffff +#define HTT_RX_IN_ORD_PADDR_IND_PADDR_LO_S 0 +/* for systems using 32-bit format for bus addresses */ +#define HTT_RX_IN_ORD_PADDR_IND_PADDR_M 0xffffffff +#define HTT_RX_IN_ORD_PADDR_IND_PADDR_S 0 +#define HTT_RX_IN_ORD_PADDR_IND_MSDU_LEN_M 0x0000ffff +#define HTT_RX_IN_ORD_PADDR_IND_MSDU_LEN_S 0 +#define HTT_RX_IN_ORD_PADDR_IND_FW_DESC_M 0x00ff0000 +#define HTT_RX_IN_ORD_PADDR_IND_FW_DESC_S 16 +#define HTT_RX_IN_ORD_PADDR_IND_MSDU_INFO_M 0xff000000 +#define HTT_RX_IN_ORD_PADDR_IND_MSDU_INFO_S 24 + + +#define HTT_RX_IN_ORD_PADDR_IND_EXT_TID_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_IN_ORD_PADDR_IND_EXT_TID, value); \ + (word) |= (value) << HTT_RX_IN_ORD_PADDR_IND_EXT_TID_S; \ + } while (0) +#define HTT_RX_IN_ORD_PADDR_IND_EXT_TID_GET(word) \ + (((word) & HTT_RX_IN_ORD_PADDR_IND_EXT_TID_M) >> \ + HTT_RX_IN_ORD_PADDR_IND_EXT_TID_S) + +#define HTT_RX_IN_ORD_PADDR_IND_PEER_ID_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_IN_ORD_PADDR_IND_PEER_ID, value); \ + (word) |= (value) << HTT_RX_IN_ORD_PADDR_IND_PEER_ID_S; \ + } while (0) +#define HTT_RX_IN_ORD_PADDR_IND_PEER_ID_GET(word) \ + (((word) & HTT_RX_IN_ORD_PADDR_IND_PEER_ID_M) >> \ + HTT_RX_IN_ORD_PADDR_IND_PEER_ID_S) + +#define HTT_RX_IN_ORD_PADDR_IND_VAP_ID_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_IN_ORD_PADDR_IND_VAP_ID, value); \ + (word) |= (value) << HTT_RX_IN_ORD_PADDR_IND_VAP_ID_S; \ + } while (0) +#define HTT_RX_IN_ORD_PADDR_IND_VAP_ID_GET(word) \ + (((word) & HTT_RX_IN_ORD_PADDR_IND_VAP_ID_M) >> \ + HTT_RX_IN_ORD_PADDR_IND_VAP_ID_S) + +#define HTT_RX_IN_ORD_PADDR_IND_MSDU_CNT_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_IN_ORD_PADDR_IND_MSDU_CNT, value); \ + (word) |= (value) << HTT_RX_IN_ORD_PADDR_IND_MSDU_CNT_S; \ + } while (0) +#define HTT_RX_IN_ORD_PADDR_IND_MSDU_CNT_GET(word) \ + (((word) & HTT_RX_IN_ORD_PADDR_IND_MSDU_CNT_M) >> \ + HTT_RX_IN_ORD_PADDR_IND_MSDU_CNT_S) + +/* for systems using 64-bit format for bus addresses */ +#define HTT_RX_IN_ORD_PADDR_IND_PADDR_HI_SET(word, value) \ +do { \ + HTT_CHECK_SET_VAL(HTT_RX_IN_ORD_PADDR_IND_PADDR_HI, value); \ + (word) |= (value) << HTT_RX_IN_ORD_PADDR_IND_PADDR_HI_S; \ +} while (0) +#define HTT_RX_IN_ORD_PADDR_IND_PADDR_HI_GET(word) \ + (((word) & HTT_RX_IN_ORD_PADDR_IND_PADDR_HI_M) >> \ + HTT_RX_IN_ORD_PADDR_IND_PADDR_HI_S) +#define HTT_RX_IN_ORD_PADDR_IND_PADDR_LO_SET(word, value) \ +do { \ + HTT_CHECK_SET_VAL(HTT_RX_IN_ORD_PADDR_IND_PADDR_LO, value); \ + (word) |= (value) << HTT_RX_IN_ORD_PADDR_IND_PADDR_LO_S; \ +} while (0) +#define HTT_RX_IN_ORD_PADDR_IND_PADDR_LO_GET(word) \ + (((word) & HTT_RX_IN_ORD_PADDR_IND_PADDR_LO_M) >> \ + HTT_RX_IN_ORD_PADDR_IND_PADDR_LO_S) + +/* for systems using 32-bit format for bus addresses */ +#define HTT_RX_IN_ORD_PADDR_IND_PADDR_SET(word, value) \ +do { \ + HTT_CHECK_SET_VAL(HTT_RX_IN_ORD_PADDR_IND_PADDR, value); \ + (word) |= (value) << HTT_RX_IN_ORD_PADDR_IND_PADDR_S; \ +} while (0) +#define HTT_RX_IN_ORD_PADDR_IND_PADDR_GET(word) \ + (((word) & HTT_RX_IN_ORD_PADDR_IND_PADDR_M) >> \ + HTT_RX_IN_ORD_PADDR_IND_PADDR_S) + +#define HTT_RX_IN_ORD_PADDR_IND_MSDU_LEN_SET(word, value) \ +do { \ + HTT_CHECK_SET_VAL(HTT_RX_IN_ORD_PADDR_IND_MSDU_LEN, value);\ + (word) |= (value) << HTT_RX_IN_ORD_PADDR_IND_MSDU_LEN_S; \ +} while (0) +#define HTT_RX_IN_ORD_PADDR_IND_MSDU_LEN_GET(word) \ + (((word) & HTT_RX_IN_ORD_PADDR_IND_MSDU_LEN_M) >> \ + HTT_RX_IN_ORD_PADDR_IND_MSDU_LEN_S) + +#define HTT_RX_IN_ORD_PADDR_IND_FW_DESC_SET(word, value) \ +do { \ + HTT_CHECK_SET_VAL(HTT_RX_IN_ORD_PADDR_IND_FW_DESC, value); \ + (word) |= (value) << HTT_RX_IN_ORD_PADDR_IND_FW_DESC_S; \ +} while (0) +#define HTT_RX_IN_ORD_PADDR_IND_FW_DESC_GET(word) \ + (((word) & HTT_RX_IN_ORD_PADDR_IND_FW_DESC_M) >> \ + HTT_RX_IN_ORD_PADDR_IND_FW_DESC_S) + +#define HTT_RX_IN_ORD_PADDR_IND_MSDU_INFO_SET(word, value) \ +do { \ + HTT_CHECK_SET_VAL(HTT_RX_IN_ORD_PADDR_IND_MSDU_INFO, value);\ + (word) |= (value) << HTT_RX_IN_ORD_PADDR_IND_MSDU_INFO_S;\ +} while (0) +#define HTT_RX_IN_ORD_PADDR_IND_MSDU_INFO_GET(word) \ + (((word) & HTT_RX_IN_ORD_PADDR_IND_MSDU_INFO_M) >> \ + HTT_RX_IN_ORD_PADDR_IND_MSDU_INFO_S) + +#define HTT_RX_IN_ORD_PADDR_IND_OFFLOAD_SET(word, value) \ +do { \ + HTT_CHECK_SET_VAL(HTT_RX_IN_ORD_IND_OFFLOAD, value);\ + (word) |= (value) << HTT_RX_IN_ORD_IND_OFFLOAD_S; \ +} while (0) +#define HTT_RX_IN_ORD_PADDR_IND_OFFLOAD_GET(word) \ + (((word) & HTT_RX_IN_ORD_PADDR_IND_OFFLOAD_M) >> \ + HTT_RX_IN_ORD_PADDR_IND_OFFLOAD_S) + +#define HTT_RX_IN_ORD_PADDR_IND_FRAG_SET(word, value) \ +do { \ + HTT_CHECK_SET_VAL(HTT_RX_IN_ORD_IND_FRAG, value); \ + (word) |= (value) << HTT_RX_IN_ORD_IND_FRAG_S; \ +} while (0) +#define HTT_RX_IN_ORD_PADDR_IND_FRAG_GET(word) \ + (((word) & HTT_RX_IN_ORD_PADDR_IND_FRAG_M) >> \ + HTT_RX_IN_ORD_PADDR_IND_FRAG_S) +#define HTT_RX_IN_ORD_PADDR_IND_PKTLOG_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_IN_ORD_PADDR_IND_PKTLOG, value); \ + (word) |= (value) << HTT_RX_IN_ORD_PADDR_IND_PKTLOG_S; \ + } while (0) +#define HTT_RX_IN_ORD_PADDR_IND_PKTLOG_GET(word) \ + (((word) & HTT_RX_IN_ORD_PADDR_IND_PKTLOG_M) >> \ + HTT_RX_IN_ORD_PADDR_IND_PKTLOG_S) + + +/* definitions used within target -> host rx indication message */ + +PREPACK struct htt_rx_ind_hdr_prefix_t { + A_UINT32 /* word 0 */ + msg_type:8, + ext_tid:5, + release_valid:1, + flush_valid:1, + reserved0:1, + peer_id:16; + + A_UINT32 /* word 1 */ + flush_start_seq_num:6, + flush_end_seq_num:6, + release_start_seq_num:6, + release_end_seq_num:6, + num_mpdu_ranges:8; +} POSTPACK; + +#define HTT_RX_IND_HDR_PREFIX_BYTES (sizeof(struct htt_rx_ind_hdr_prefix_t)) +#define HTT_RX_IND_HDR_PREFIX_SIZE32 (HTT_RX_IND_HDR_PREFIX_BYTES >> 2) + +#define HTT_TGT_RSSI_INVALID 0x80 + +PREPACK struct htt_rx_ppdu_desc_t { +#define HTT_RX_IND_PPDU_OFFSET_WORD_RSSI_CMB 0 +#define HTT_RX_IND_PPDU_OFFSET_WORD_TIMESTAMP_SUBMICROSEC 0 +#define HTT_RX_IND_PPDU_OFFSET_WORD_PHY_ERR_CODE 0 +#define HTT_RX_IND_PPDU_OFFSET_WORD_PHY_ERR 0 +#define HTT_RX_IND_PPDU_OFFSET_WORD_LEGACY_RATE 0 +#define HTT_RX_IND_PPDU_OFFSET_WORD_LEGACY_RATE_SEL 0 +#define HTT_RX_IND_PPDU_OFFSET_WORD_END_VALID 0 +#define HTT_RX_IND_PPDU_OFFSET_WORD_START_VALID 0 + A_UINT32 /* word 0 */ + rssi_cmb:8, + timestamp_submicrosec:8, + phy_err_code:8, + phy_err:1, + legacy_rate:4, + legacy_rate_sel:1, + end_valid:1, + start_valid:1; + +#define HTT_RX_IND_PPDU_OFFSET_WORD_RSSI0 1 + union { + A_UINT32 /* word 1 */ + rssi0_pri20:8, + rssi0_ext20:8, + rssi0_ext40:8, + rssi0_ext80:8; + A_UINT32 rssi0; /* access all 20/40/80 per-b/w RSSIs together */ + } u0; + +#define HTT_RX_IND_PPDU_OFFSET_WORD_RSSI1 2 + union { + A_UINT32 /* word 2 */ + rssi1_pri20:8, + rssi1_ext20:8, + rssi1_ext40:8, + rssi1_ext80:8; + A_UINT32 rssi1; /* access all 20/40/80 per-b/w RSSIs together */ + } u1; + +#define HTT_RX_IND_PPDU_OFFSET_WORD_RSSI2 3 + union { + A_UINT32 /* word 3 */ + rssi2_pri20:8, + rssi2_ext20:8, + rssi2_ext40:8, + rssi2_ext80:8; + A_UINT32 rssi2; /* access all 20/40/80 per-b/w RSSIs together */ + } u2; + +#define HTT_RX_IND_PPDU_OFFSET_WORD_RSSI3 4 + union { + A_UINT32 /* word 4 */ + rssi3_pri20:8, + rssi3_ext20:8, + rssi3_ext40:8, + rssi3_ext80:8; + A_UINT32 rssi3; /* access all 20/40/80 per-b/w RSSIs together */ + } u3; + +#define HTT_RX_IND_PPDU_OFFSET_WORD_TSF32 5 + A_UINT32 tsf32; /* word 5 */ + +#define HTT_RX_IND_PPDU_OFFSET_WORD_TIMESTAMP_MICROSEC 6 + A_UINT32 timestamp_microsec; /* word 6 */ + +#define HTT_RX_IND_PPDU_OFFSET_WORD_PREAMBLE_TYPE 7 +#define HTT_RX_IND_PPDU_OFFSET_WORD_VHT_SIG_A1 7 + A_UINT32 /* word 7 */ + vht_sig_a1:24, + preamble_type:8; + +#define HTT_RX_IND_PPDU_OFFSET_WORD_VHT_SIG_A2 8 + A_UINT32 /* word 8 */ + vht_sig_a2:24, + reserved0:8; +} POSTPACK; + +#define HTT_RX_PPDU_DESC_BYTES (sizeof(struct htt_rx_ppdu_desc_t)) +#define HTT_RX_PPDU_DESC_SIZE32 (HTT_RX_PPDU_DESC_BYTES >> 2) + +PREPACK struct htt_rx_ind_hdr_suffix_t { + A_UINT32 /* word 0 */ + fw_rx_desc_bytes:16, + reserved0:16; +} POSTPACK; + +#define HTT_RX_IND_HDR_SUFFIX_BYTES (sizeof(struct htt_rx_ind_hdr_suffix_t)) +#define HTT_RX_IND_HDR_SUFFIX_SIZE32 (HTT_RX_IND_HDR_SUFFIX_BYTES >> 2) + +PREPACK struct htt_rx_ind_hdr_t { + struct htt_rx_ind_hdr_prefix_t prefix; + struct htt_rx_ppdu_desc_t rx_ppdu_desc; + struct htt_rx_ind_hdr_suffix_t suffix; +} POSTPACK; + +#define HTT_RX_IND_HDR_BYTES (sizeof(struct htt_rx_ind_hdr_t)) +#define HTT_RX_IND_HDR_SIZE32 (HTT_RX_IND_HDR_BYTES >> 2) + +/* confirm that HTT_RX_IND_HDR_BYTES is a multiple of 4 */ +A_COMPILE_TIME_ASSERT(HTT_RX_IND_hdr_size_quantum, + (HTT_RX_IND_HDR_BYTES & 0x3) == 0); + +/* + * HTT_RX_IND_FW_RX_PPDU_DESC_BYTE_OFFSET: + * the offset into the HTT rx indication message at which the + * FW rx PPDU descriptor resides + */ +#define HTT_RX_IND_FW_RX_PPDU_DESC_BYTE_OFFSET HTT_RX_IND_HDR_PREFIX_BYTES + +/* + * HTT_RX_IND_HDR_SUFFIX_BYTE_OFFSET: + * the offset into the HTT rx indication message at which the + * header suffix (FW rx MSDU byte count) resides + */ +#define HTT_RX_IND_HDR_SUFFIX_BYTE_OFFSET \ + (HTT_RX_IND_FW_RX_PPDU_DESC_BYTE_OFFSET + HTT_RX_PPDU_DESC_BYTES) + +/* + * HTT_RX_IND_FW_RX_DESC_BYTE_OFFSET: + * the offset into the HTT rx indication message at which the per-MSDU + * information starts + * Bytes 0-7 are the message header; bytes 8-11 contain the length of the + * per-MSDU information portion of the message. The per-MSDU info itself + * starts at byte 12. + */ +#define HTT_RX_IND_FW_RX_DESC_BYTE_OFFSET HTT_RX_IND_HDR_BYTES + + +/** + * @brief target -> host rx indication message definition + * + * @details + * The following field definitions describe the format of the rx indication + * message sent from the target to the host. + * The message consists of three major sections: + * 1. a fixed-length header + * 2. a variable-length list of firmware rx MSDU descriptors + * 3. one or more 4-octet MPDU range information elements + * The fixed length header itself has two sub-sections + * 1. the message meta-information, including identification of the + * sender and type of the received data, and a 4-octet flush/release IE + * 2. the firmware rx PPDU descriptor + * + * The format of the message is depicted below. + * in this depiction, the following abbreviations are used for information + * elements within the message: + * - SV - start valid: this flag is set if the FW rx PPDU descriptor + * elements associated with the PPDU start are valid. + * Specifically, the following fields are valid only if SV is set: + * RSSI (all variants), L, legacy rate, preamble type, service, + * VHT-SIG-A + * - EV - end valid: this flag is set if the FW rx PPDU descriptor + * elements associated with the PPDU end are valid. + * Specifically, the following fields are valid only if EV is set: + * P, PHY err code, TSF, microsec / sub-microsec timestamp + * - L - Legacy rate selector - if legacy rates are used, this flag + * indicates whether the rate is from a CCK (L == 1) or OFDM + * (L == 0) PHY. + * - P - PHY error flag - boolean indication of whether the rx frame had + * a PHY error + * + * |31 24|23 18|17|16|15|14|13|12|11|10|9|8|7|6|5|4 0| + * |----------------+-------------------+---------------------+---------------| + * | peer ID | |RV|FV| ext TID | msg type | + * |--------------------------------------------------------------------------| + * | num | release | release | flush | flush | + * | MPDU | end | start | end | start | + * | ranges | seq num | seq num | seq num | seq num | + * |==========================================================================| + * |S|E|L| legacy |P| PHY err code | sub-microsec | combined | + * |V|V| | rate | | | timestamp | RSSI | + * |--------------------------------------------------------------------------| + * | RSSI rx0 ext80 | RSSI rx0 ext40 | RSSI rx0 ext20 | RSSI rx0 pri20| + * |--------------------------------------------------------------------------| + * | RSSI rx1 ext80 | RSSI rx1 ext40 | RSSI rx1 ext20 | RSSI rx1 pri20| + * |--------------------------------------------------------------------------| + * | RSSI rx2 ext80 | RSSI rx2 ext40 | RSSI rx2 ext20 | RSSI rx2 pri20| + * |--------------------------------------------------------------------------| + * | RSSI rx3 ext80 | RSSI rx3 ext40 | RSSI rx3 ext20 | RSSI rx3 pri20| + * |--------------------------------------------------------------------------| + * | TSF LSBs | + * |--------------------------------------------------------------------------| + * | microsec timestamp | + * |--------------------------------------------------------------------------| + * | preamble type | HT-SIG / VHT-SIG-A1 | + * |--------------------------------------------------------------------------| + * | service | HT-SIG / VHT-SIG-A2 | + * |==========================================================================| + * | reserved | FW rx desc bytes | + * |--------------------------------------------------------------------------| + * | MSDU Rx | MSDU Rx | MSDU Rx | MSDU Rx | + * | desc B3 | desc B2 | desc B1 | desc B0 | + * |--------------------------------------------------------------------------| + * : : : + * |--------------------------------------------------------------------------| + * | alignment | MSDU Rx | + * | padding | desc Bn | + * |--------------------------------------------------------------------------| + * | reserved | MPDU range status | MPDU count | + * |--------------------------------------------------------------------------| + * : reserved : MPDU range status : MPDU count : + * :- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - : + * + * Header fields: + * - MSG_TYPE + * Bits 7:0 + * Purpose: identifies this as an rx indication message + * Value: 0x1 + * - EXT_TID + * Bits 12:8 + * Purpose: identify the traffic ID of the rx data, including + * special "extended" TID values for multicast, broadcast, and + * non-QoS data frames + * Value: 0-15 for regular TIDs, or >= 16 for bcast/mcast/non-QoS + * - FLUSH_VALID (FV) + * Bit 13 + * Purpose: indicate whether the flush IE (start/end sequence numbers) + * is valid + * Value: + * 1 -> flush IE is valid and needs to be processed + * 0 -> flush IE is not valid and should be ignored + * - REL_VALID (RV) + * Bit 13 + * Purpose: indicate whether the release IE (start/end sequence numbers) + * is valid + * Value: + * 1 -> release IE is valid and needs to be processed + * 0 -> release IE is not valid and should be ignored + * - PEER_ID + * Bits 31:16 + * Purpose: Identify, by ID, which peer sent the rx data + * Value: ID of the peer who sent the rx data + * - FLUSH_SEQ_NUM_START + * Bits 5:0 + * Purpose: Indicate the start of a series of MPDUs to flush + * Not all MPDUs within this series are necessarily valid - the host + * must check each sequence number within this range to see if the + * corresponding MPDU is actually present. + * This field is only valid if the FV bit is set. + * Value: + * The sequence number for the first MPDUs to check to flush. + * The sequence number is masked by 0x3f. + * - FLUSH_SEQ_NUM_END + * Bits 11:6 + * Purpose: Indicate the end of a series of MPDUs to flush + * Value: + * The sequence number one larger than the sequence number of the + * last MPDU to check to flush. + * The sequence number is masked by 0x3f. + * Not all MPDUs within this series are necessarily valid - the host + * must check each sequence number within this range to see if the + * corresponding MPDU is actually present. + * This field is only valid if the FV bit is set. + * - REL_SEQ_NUM_START + * Bits 17:12 + * Purpose: Indicate the start of a series of MPDUs to release. + * All MPDUs within this series are present and valid - the host + * need not check each sequence number within this range to see if + * the corresponding MPDU is actually present. + * This field is only valid if the RV bit is set. + * Value: + * The sequence number for the first MPDUs to check to release. + * The sequence number is masked by 0x3f. + * - REL_SEQ_NUM_END + * Bits 23:18 + * Purpose: Indicate the end of a series of MPDUs to release. + * Value: + * The sequence number one larger than the sequence number of the + * last MPDU to check to release. + * The sequence number is masked by 0x3f. + * All MPDUs within this series are present and valid - the host + * need not check each sequence number within this range to see if + * the corresponding MPDU is actually present. + * This field is only valid if the RV bit is set. + * - NUM_MPDU_RANGES + * Bits 31:24 + * Purpose: Indicate how many ranges of MPDUs are present. + * Each MPDU range consists of a series of contiguous MPDUs within the + * rx frame sequence which all have the same MPDU status. + * Value: 1-63 (typically a small number, like 1-3) + * + * Rx PPDU descriptor fields: + * - RSSI_CMB + * Bits 7:0 + * Purpose: Combined RSSI from all active rx chains, across the active + * bandwidth. + * Value: RSSI dB units w.r.t. noise floor + * - TIMESTAMP_SUBMICROSEC + * Bits 15:8 + * Purpose: high-resolution timestamp + * Value: + * Sub-microsecond time of PPDU reception. + * This timestamp ranges from [0,MAC clock MHz). + * This timestamp can be used in conjunction with TIMESTAMP_MICROSEC + * to form a high-resolution, large range rx timestamp. + * - PHY_ERR_CODE + * Bits 23:16 + * Purpose: + * If the rx frame processing resulted in a PHY error, indicate what + * type of rx PHY error occurred. + * Value: + * This field is valid if the "P" (PHY_ERR) flag is set. + * TBD: document/specify the values for this field + * - PHY_ERR + * Bit 24 + * Purpose: indicate whether the rx PPDU had a PHY error + * Value: 0 -> no rx PHY error, 1 -> rx PHY error encountered + * - LEGACY_RATE + * Bits 28:25 + * Purpose: + * If the rx frame used a legacy rate rather than a HT or VHT rate, + * specify which rate was used. + * Value: + * The LEGACY_RATE field's value depends on the "L" (LEGACY_RATE_SEL) + * flag. + * If LEGACY_RATE_SEL is 0: + * 0x8: OFDM 48 Mbps + * 0x9: OFDM 24 Mbps + * 0xA: OFDM 12 Mbps + * 0xB: OFDM 6 Mbps + * 0xC: OFDM 54 Mbps + * 0xD: OFDM 36 Mbps + * 0xE: OFDM 18 Mbps + * 0xF: OFDM 9 Mbps + * If LEGACY_RATE_SEL is 1: + * 0x8: CCK 11 Mbps long preamble + * 0x9: CCK 5.5 Mbps long preamble + * 0xA: CCK 2 Mbps long preamble + * 0xB: CCK 1 Mbps long preamble + * 0xC: CCK 11 Mbps short preamble + * 0xD: CCK 5.5 Mbps short preamble + * 0xE: CCK 2 Mbps short preamble + * - LEGACY_RATE_SEL + * Bit 29 + * Purpose: if rx used a legacy rate, specify whether it was OFDM or CCK + * Value: + * This field is valid if the PREAMBLE_TYPE field indicates the rx + * used a legacy rate. + * 0 -> OFDM, 1 -> CCK + * - END_VALID + * Bit 30 + * Purpose: Indicate whether the FW rx PPDU desc fields associated with + * the start of the PPDU are valid. Specifically, the following + * fields are only valid if END_VALID is set: + * PHY_ERR, PHY_ERR_CODE, TSF32, TIMESTAMP_MICROSEC, + * TIMESTAMP_SUBMICROSEC + * Value: + * 0 -> rx PPDU desc end fields are not valid + * 1 -> rx PPDU desc end fields are valid + * - START_VALID + * Bit 31 + * Purpose: Indicate whether the FW rx PPDU desc fields associated with + * the end of the PPDU are valid. Specifically, the following + * fields are only valid if START_VALID is set: + * RSSI, LEGACY_RATE_SEL, LEGACY_RATE, PREAMBLE_TYPE, SERVICE, + * VHT-SIG-A + * Value: + * 0 -> rx PPDU desc start fields are not valid + * 1 -> rx PPDU desc start fields are valid + * - RSSI0_PRI20 + * Bits 7:0 + * Purpose: RSSI from chain 0 on the primary 20 MHz channel + * Value: RSSI dB units w.r.t. noise floor + * + * - RSSI0_EXT20 + * Bits 7:0 + * Purpose: RSSI from chain 0 on the bonded extension 20 MHz channel + * (if the rx bandwidth was >= 40 MHz) + * Value: RSSI dB units w.r.t. noise floor + * - RSSI0_EXT40 + * Bits 7:0 + * Purpose: RSSI from chain 0 on the bonded extension 40 MHz channel + * (if the rx bandwidth was >= 80 MHz) + * Value: RSSI dB units w.r.t. noise floor + * - RSSI0_EXT80 + * Bits 7:0 + * Purpose: RSSI from chain 0 on the bonded extension 80 MHz channel + * (if the rx bandwidth was >= 160 MHz) + * Value: RSSI dB units w.r.t. noise floor + * + * - RSSI1_PRI20 + * Bits 7:0 + * Purpose: RSSI from chain 1 on the primary 20 MHz channel + * Value: RSSI dB units w.r.t. noise floor + * - RSSI1_EXT20 + * Bits 7:0 + * Purpose: RSSI from chain 1 on the bonded extension 20 MHz channel + * (if the rx bandwidth was >= 40 MHz) + * Value: RSSI dB units w.r.t. noise floor + * - RSSI1_EXT40 + * Bits 7:0 + * Purpose: RSSI from chain 1 on the bonded extension 40 MHz channel + * (if the rx bandwidth was >= 80 MHz) + * Value: RSSI dB units w.r.t. noise floor + * - RSSI1_EXT80 + * Bits 7:0 + * Purpose: RSSI from chain 1 on the bonded extension 80 MHz channel + * (if the rx bandwidth was >= 160 MHz) + * Value: RSSI dB units w.r.t. noise floor + * + * - RSSI2_PRI20 + * Bits 7:0 + * Purpose: RSSI from chain 2 on the primary 20 MHz channel + * Value: RSSI dB units w.r.t. noise floor + * - RSSI2_EXT20 + * Bits 7:0 + * Purpose: RSSI from chain 2 on the bonded extension 20 MHz channel + * (if the rx bandwidth was >= 40 MHz) + * Value: RSSI dB units w.r.t. noise floor + * - RSSI2_EXT40 + * Bits 7:0 + * Purpose: RSSI from chain 2 on the bonded extension 40 MHz channel + * (if the rx bandwidth was >= 80 MHz) + * Value: RSSI dB units w.r.t. noise floor + * - RSSI2_EXT80 + * Bits 7:0 + * Purpose: RSSI from chain 2 on the bonded extension 80 MHz channel + * (if the rx bandwidth was >= 160 MHz) + * Value: RSSI dB units w.r.t. noise floor + * + * - RSSI3_PRI20 + * Bits 7:0 + * Purpose: RSSI from chain 3 on the primary 20 MHz channel + * Value: RSSI dB units w.r.t. noise floor + * - RSSI3_EXT20 + * Bits 7:0 + * Purpose: RSSI from chain 3 on the bonded extension 20 MHz channel + * (if the rx bandwidth was >= 40 MHz) + * Value: RSSI dB units w.r.t. noise floor + * - RSSI3_EXT40 + * Bits 7:0 + * Purpose: RSSI from chain 3 on the bonded extension 40 MHz channel + * (if the rx bandwidth was >= 80 MHz) + * Value: RSSI dB units w.r.t. noise floor + * - RSSI3_EXT80 + * Bits 7:0 + * Purpose: RSSI from chain 3 on the bonded extension 80 MHz channel + * (if the rx bandwidth was >= 160 MHz) + * Value: RSSI dB units w.r.t. noise floor + * + * - TSF32 + * Bits 31:0 + * Purpose: specify the time the rx PPDU was received, in TSF units + * Value: 32 LSBs of the TSF + * - TIMESTAMP_MICROSEC + * Bits 31:0 + * Purpose: specify the time the rx PPDU was received, in microsecond units + * Value: PPDU rx time, in microseconds + * - VHT_SIG_A1 + * Bits 23:0 + * Purpose: Provide the HT-SIG (initial 24 bits) or VHT-SIG-A1 field + * from the rx PPDU + * Value: + * If PREAMBLE_TYPE specifies VHT, then this field contains the + * VHT-SIG-A1 data. + * If PREAMBLE_TYPE specifies HT, then this field contains the + * first 24 bits of the HT-SIG data. + * Otherwise, this field is invalid. + * Refer to the the 802.11 protocol for the definition of the + * HT-SIG and VHT-SIG-A1 fields + * - VHT_SIG_A2 + * Bits 23:0 + * Purpose: Provide the HT-SIG (final 24 bits) or VHT-SIG-A2 field + * from the rx PPDU + * Value: + * If PREAMBLE_TYPE specifies VHT, then this field contains the + * VHT-SIG-A2 data. + * If PREAMBLE_TYPE specifies HT, then this field contains the + * last 24 bits of the HT-SIG data. + * Otherwise, this field is invalid. + * Refer to the the 802.11 protocol for the definition of the + * HT-SIG and VHT-SIG-A2 fields + * - PREAMBLE_TYPE + * Bits 31:24 + * Purpose: indicate the PHY format of the received burst + * Value: + * 0x4: Legacy (OFDM/CCK) + * 0x8: HT + * 0x9: HT with TxBF + * 0xC: VHT + * 0xD: VHT with TxBF + * - SERVICE + * Bits 31:24 + * Purpose: TBD + * Value: TBD + * + * Rx MSDU descriptor fields: + * - FW_RX_DESC_BYTES + * Bits 15:0 + * Purpose: Indicate how many bytes in the Rx indication are used for + * FW Rx descriptors + * + * Payload fields: + * - MPDU_COUNT + * Bits 7:0 + * Purpose: Indicate how many sequential MPDUs share the same status. + * All MPDUs within the indicated list are from the same RA-TA-TID. + * - MPDU_STATUS + * Bits 15:8 + * Purpose: Indicate whether the (group of sequential) MPDU(s) were + * received successfully. + * Value: + * 0x1: success + * 0x2: FCS error + * 0x3: duplicate error + * 0x4: replay error + * 0x5: invalid peer + */ +/* header fields */ +#define HTT_RX_IND_EXT_TID_M 0x1f00 +#define HTT_RX_IND_EXT_TID_S 8 +#define HTT_RX_IND_FLUSH_VALID_M 0x2000 +#define HTT_RX_IND_FLUSH_VALID_S 13 +#define HTT_RX_IND_REL_VALID_M 0x4000 +#define HTT_RX_IND_REL_VALID_S 14 +#define HTT_RX_IND_PEER_ID_M 0xffff0000 +#define HTT_RX_IND_PEER_ID_S 16 + +#define HTT_RX_IND_FLUSH_SEQ_NUM_START_M 0x3f +#define HTT_RX_IND_FLUSH_SEQ_NUM_START_S 0 +#define HTT_RX_IND_FLUSH_SEQ_NUM_END_M 0xfc0 +#define HTT_RX_IND_FLUSH_SEQ_NUM_END_S 6 +#define HTT_RX_IND_REL_SEQ_NUM_START_M 0x3f000 +#define HTT_RX_IND_REL_SEQ_NUM_START_S 12 +#define HTT_RX_IND_REL_SEQ_NUM_END_M 0xfc0000 +#define HTT_RX_IND_REL_SEQ_NUM_END_S 18 +#define HTT_RX_IND_NUM_MPDU_RANGES_M 0xff000000 +#define HTT_RX_IND_NUM_MPDU_RANGES_S 24 + +/* rx PPDU descriptor fields */ +#define HTT_RX_IND_RSSI_CMB_M 0x000000ff +#define HTT_RX_IND_RSSI_CMB_S 0 +#define HTT_RX_IND_TIMESTAMP_SUBMICROSEC_M 0x0000ff00 +#define HTT_RX_IND_TIMESTAMP_SUBMICROSEC_S 8 +#define HTT_RX_IND_PHY_ERR_CODE_M 0x00ff0000 +#define HTT_RX_IND_PHY_ERR_CODE_S 16 +#define HTT_RX_IND_PHY_ERR_M 0x01000000 +#define HTT_RX_IND_PHY_ERR_S 24 +#define HTT_RX_IND_LEGACY_RATE_M 0x1e000000 +#define HTT_RX_IND_LEGACY_RATE_S 25 +#define HTT_RX_IND_LEGACY_RATE_SEL_M 0x20000000 +#define HTT_RX_IND_LEGACY_RATE_SEL_S 29 +#define HTT_RX_IND_END_VALID_M 0x40000000 +#define HTT_RX_IND_END_VALID_S 30 +#define HTT_RX_IND_START_VALID_M 0x80000000 +#define HTT_RX_IND_START_VALID_S 31 + +#define HTT_RX_IND_RSSI_PRI20_M 0x000000ff +#define HTT_RX_IND_RSSI_PRI20_S 0 +#define HTT_RX_IND_RSSI_EXT20_M 0x0000ff00 +#define HTT_RX_IND_RSSI_EXT20_S 8 +#define HTT_RX_IND_RSSI_EXT40_M 0x00ff0000 +#define HTT_RX_IND_RSSI_EXT40_S 16 +#define HTT_RX_IND_RSSI_EXT80_M 0xff000000 +#define HTT_RX_IND_RSSI_EXT80_S 24 + +#define HTT_RX_IND_VHT_SIG_A1_M 0x00ffffff +#define HTT_RX_IND_VHT_SIG_A1_S 0 +#define HTT_RX_IND_VHT_SIG_A2_M 0x00ffffff +#define HTT_RX_IND_VHT_SIG_A2_S 0 +#define HTT_RX_IND_PREAMBLE_TYPE_M 0xff000000 +#define HTT_RX_IND_PREAMBLE_TYPE_S 24 +#define HTT_RX_IND_SERVICE_M 0xff000000 +#define HTT_RX_IND_SERVICE_S 24 + +/* rx MSDU descriptor fields */ +#define HTT_RX_IND_FW_RX_DESC_BYTES_M 0xffff +#define HTT_RX_IND_FW_RX_DESC_BYTES_S 0 + +/* payload fields */ +#define HTT_RX_IND_MPDU_COUNT_M 0xff +#define HTT_RX_IND_MPDU_COUNT_S 0 +#define HTT_RX_IND_MPDU_STATUS_M 0xff00 +#define HTT_RX_IND_MPDU_STATUS_S 8 + + +#define HTT_RX_IND_EXT_TID_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_IND_EXT_TID, value); \ + (word) |= (value) << HTT_RX_IND_EXT_TID_S; \ + } while (0) +#define HTT_RX_IND_EXT_TID_GET(word) \ + (((word) & HTT_RX_IND_EXT_TID_M) >> HTT_RX_IND_EXT_TID_S) + +#define HTT_RX_IND_FLUSH_VALID_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_IND_FLUSH_VALID, value); \ + (word) |= (value) << HTT_RX_IND_FLUSH_VALID_S; \ + } while (0) +#define HTT_RX_IND_FLUSH_VALID_GET(word) \ + (((word) & HTT_RX_IND_FLUSH_VALID_M) >> HTT_RX_IND_FLUSH_VALID_S) + +#define HTT_RX_IND_REL_VALID_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_IND_REL_VALID, value); \ + (word) |= (value) << HTT_RX_IND_REL_VALID_S; \ + } while (0) +#define HTT_RX_IND_REL_VALID_GET(word) \ + (((word) & HTT_RX_IND_REL_VALID_M) >> HTT_RX_IND_REL_VALID_S) + +#define HTT_RX_IND_PEER_ID_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_IND_PEER_ID, value); \ + (word) |= (value) << HTT_RX_IND_PEER_ID_S; \ + } while (0) +#define HTT_RX_IND_PEER_ID_GET(word) \ + (((word) & HTT_RX_IND_PEER_ID_M) >> HTT_RX_IND_PEER_ID_S) + + +#define HTT_RX_IND_FW_RX_DESC_BYTES_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_IND_FW_RX_DESC_BYTES, value); \ + (word) |= (value) << HTT_RX_IND_FW_RX_DESC_BYTES_S; \ + } while (0) +#define HTT_RX_IND_FW_RX_DESC_BYTES_GET(word) \ + (((word) & HTT_RX_IND_FW_RX_DESC_BYTES_M) >> \ + HTT_RX_IND_FW_RX_DESC_BYTES_S) + + +#define HTT_RX_IND_FLUSH_SEQ_NUM_START_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_IND_FLUSH_SEQ_NUM_START, value); \ + (word) |= (value) << HTT_RX_IND_FLUSH_SEQ_NUM_START_S; \ + } while (0) +#define HTT_RX_IND_FLUSH_SEQ_NUM_START_GET(word) \ + (((word) & HTT_RX_IND_FLUSH_SEQ_NUM_START_M) >> \ + HTT_RX_IND_FLUSH_SEQ_NUM_START_S) + +#define HTT_RX_IND_FLUSH_SEQ_NUM_END_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_IND_FLUSH_SEQ_NUM_END, value); \ + (word) |= (value) << HTT_RX_IND_FLUSH_SEQ_NUM_END_S; \ + } while (0) +#define HTT_RX_IND_FLUSH_SEQ_NUM_END_GET(word) \ + (((word) & HTT_RX_IND_FLUSH_SEQ_NUM_END_M) >> \ + HTT_RX_IND_FLUSH_SEQ_NUM_END_S) + +#define HTT_RX_IND_REL_SEQ_NUM_START_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_IND_REL_SEQ_NUM_START, value); \ + (word) |= (value) << HTT_RX_IND_REL_SEQ_NUM_START_S; \ + } while (0) +#define HTT_RX_IND_REL_SEQ_NUM_START_GET(word) \ + (((word) & HTT_RX_IND_REL_SEQ_NUM_START_M) >> \ + HTT_RX_IND_REL_SEQ_NUM_START_S) + +#define HTT_RX_IND_REL_SEQ_NUM_END_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_IND_REL_SEQ_NUM_END, value); \ + (word) |= (value) << HTT_RX_IND_REL_SEQ_NUM_END_S; \ + } while (0) +#define HTT_RX_IND_REL_SEQ_NUM_END_GET(word) \ + (((word) & HTT_RX_IND_REL_SEQ_NUM_END_M) >> \ + HTT_RX_IND_REL_SEQ_NUM_END_S) + +#define HTT_RX_IND_NUM_MPDU_RANGES_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_IND_NUM_MPDU_RANGES, value); \ + (word) |= (value) << HTT_RX_IND_NUM_MPDU_RANGES_S; \ + } while (0) +#define HTT_RX_IND_NUM_MPDU_RANGES_GET(word) \ + (((word) & HTT_RX_IND_NUM_MPDU_RANGES_M) >> \ + HTT_RX_IND_NUM_MPDU_RANGES_S) + +/* FW rx PPDU descriptor fields */ +#define HTT_RX_IND_RSSI_CMB_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_IND_RSSI_CMB, value); \ + (word) |= (value) << HTT_RX_IND_RSSI_CMB_S; \ + } while (0) +#define HTT_RX_IND_RSSI_CMB_GET(word) \ + (((word) & HTT_RX_IND_RSSI_CMB_M) >> \ + HTT_RX_IND_RSSI_CMB_S) + +#define HTT_RX_IND_TIMESTAMP_SUBMICROSEC_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_IND_TIMESTAMP_SUBMICROSEC, value); \ + (word) |= (value) << HTT_RX_IND_TIMESTAMP_SUBMICROSEC_S; \ + } while (0) +#define HTT_RX_IND_TIMESTAMP_SUBMICROSEC_GET(word) \ + (((word) & HTT_RX_IND_TIMESTAMP_SUBMICROSEC_M) >> \ + HTT_RX_IND_TIMESTAMP_SUBMICROSEC_S) + +#define HTT_RX_IND_PHY_ERR_CODE_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_IND_PHY_ERR_CODE, value); \ + (word) |= (value) << HTT_RX_IND_PHY_ERR_CODE_S; \ + } while (0) +#define HTT_RX_IND_PHY_ERR_CODE_GET(word) \ + (((word) & HTT_RX_IND_PHY_ERR_CODE_M) >> \ + HTT_RX_IND_PHY_ERR_CODE_S) + +#define HTT_RX_IND_PHY_ERR_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_IND_PHY_ERR, value); \ + (word) |= (value) << HTT_RX_IND_PHY_ERR_S; \ + } while (0) +#define HTT_RX_IND_PHY_ERR_GET(word) \ + (((word) & HTT_RX_IND_PHY_ERR_M) >> \ + HTT_RX_IND_PHY_ERR_S) + +#define HTT_RX_IND_LEGACY_RATE_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_IND_LEGACY_RATE, value); \ + (word) |= (value) << HTT_RX_IND_LEGACY_RATE_S; \ + } while (0) +#define HTT_RX_IND_LEGACY_RATE_GET(word) \ + (((word) & HTT_RX_IND_LEGACY_RATE_M) >> \ + HTT_RX_IND_LEGACY_RATE_S) + +#define HTT_RX_IND_LEGACY_RATE_SEL_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_IND_LEGACY_RATE_SEL, value); \ + (word) |= (value) << HTT_RX_IND_LEGACY_RATE_SEL_S; \ + } while (0) +#define HTT_RX_IND_LEGACY_RATE_SEL_GET(word) \ + (((word) & HTT_RX_IND_LEGACY_RATE_SEL_M) >> \ + HTT_RX_IND_LEGACY_RATE_SEL_S) + +#define HTT_RX_IND_END_VALID_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_IND_END_VALID, value); \ + (word) |= (value) << HTT_RX_IND_END_VALID_S; \ + } while (0) +#define HTT_RX_IND_END_VALID_GET(word) \ + (((word) & HTT_RX_IND_END_VALID_M) >> \ + HTT_RX_IND_END_VALID_S) + +#define HTT_RX_IND_START_VALID_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_IND_START_VALID, value); \ + (word) |= (value) << HTT_RX_IND_START_VALID_S; \ + } while (0) +#define HTT_RX_IND_START_VALID_GET(word) \ + (((word) & HTT_RX_IND_START_VALID_M) >> \ + HTT_RX_IND_START_VALID_S) + +#define HTT_RX_IND_RSSI_PRI20_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_IND_RSSI_PRI20, value); \ + (word) |= (value) << HTT_RX_IND_RSSI_PRI20_S; \ + } while (0) +#define HTT_RX_IND_RSSI_PRI20_GET(word) \ + (((word) & HTT_RX_IND_RSSI_PRI20_M) >> \ + HTT_RX_IND_RSSI_PRI20_S) + +#define HTT_RX_IND_RSSI_EXT20_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_IND_RSSI_EXT20, value); \ + (word) |= (value) << HTT_RX_IND_RSSI_EXT20_S; \ + } while (0) +#define HTT_RX_IND_RSSI_EXT20_GET(word) \ + (((word) & HTT_RX_IND_RSSI_EXT20_M) >> \ + HTT_RX_IND_RSSI_EXT20_S) + +#define HTT_RX_IND_RSSI_EXT40_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_IND_RSSI_EXT40, value); \ + (word) |= (value) << HTT_RX_IND_RSSI_EXT40_S; \ + } while (0) +#define HTT_RX_IND_RSSI_EXT40_GET(word) \ + (((word) & HTT_RX_IND_RSSI_EXT40_M) >> \ + HTT_RX_IND_RSSI_EXT40_S) + +#define HTT_RX_IND_RSSI_EXT80_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_IND_RSSI_EXT80, value); \ + (word) |= (value) << HTT_RX_IND_RSSI_EXT80_S; \ + } while (0) +#define HTT_RX_IND_RSSI_EXT80_GET(word) \ + (((word) & HTT_RX_IND_RSSI_EXT80_M) >> \ + HTT_RX_IND_RSSI_EXT80_S) + +#define HTT_RX_IND_VHT_SIG_A1_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_IND_VHT_SIG_A1, value); \ + (word) |= (value) << HTT_RX_IND_VHT_SIG_A1_S; \ + } while (0) +#define HTT_RX_IND_VHT_SIG_A1_GET(word) \ + (((word) & HTT_RX_IND_VHT_SIG_A1_M) >> \ + HTT_RX_IND_VHT_SIG_A1_S) + +#define HTT_RX_IND_VHT_SIG_A2_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_IND_VHT_SIG_A2, value); \ + (word) |= (value) << HTT_RX_IND_VHT_SIG_A2_S; \ + } while (0) +#define HTT_RX_IND_VHT_SIG_A2_GET(word) \ + (((word) & HTT_RX_IND_VHT_SIG_A2_M) >> \ + HTT_RX_IND_VHT_SIG_A2_S) + +#define HTT_RX_IND_PREAMBLE_TYPE_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_IND_PREAMBLE_TYPE, value); \ + (word) |= (value) << HTT_RX_IND_PREAMBLE_TYPE_S; \ + } while (0) +#define HTT_RX_IND_PREAMBLE_TYPE_GET(word) \ + (((word) & HTT_RX_IND_PREAMBLE_TYPE_M) >> \ + HTT_RX_IND_PREAMBLE_TYPE_S) + +#define HTT_RX_IND_SERVICE_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_IND_SERVICE, value); \ + (word) |= (value) << HTT_RX_IND_SERVICE_S; \ + } while (0) +#define HTT_RX_IND_SERVICE_GET(word) \ + (((word) & HTT_RX_IND_SERVICE_M) >> \ + HTT_RX_IND_SERVICE_S) + + +#define HTT_RX_IND_MPDU_COUNT_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_IND_MPDU_COUNT, value); \ + (word) |= (value) << HTT_RX_IND_MPDU_COUNT_S; \ + } while (0) +#define HTT_RX_IND_MPDU_COUNT_GET(word) \ + (((word) & HTT_RX_IND_MPDU_COUNT_M) >> HTT_RX_IND_MPDU_COUNT_S) + +#define HTT_RX_IND_MPDU_STATUS_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_IND_MPDU_STATUS, value); \ + (word) |= (value) << HTT_RX_IND_MPDU_STATUS_S; \ + } while (0) +#define HTT_RX_IND_MPDU_STATUS_GET(word) \ + (((word) & HTT_RX_IND_MPDU_STATUS_M) >> HTT_RX_IND_MPDU_STATUS_S) + + +#define HTT_RX_IND_HL_BYTES \ + (HTT_RX_IND_HDR_BYTES + \ + 4 /* single FW rx MSDU descriptor, plus padding */ + \ + 4 /* single MPDU range information element */) +#define HTT_RX_IND_HL_SIZE32 (HTT_RX_IND_HL_BYTES >> 2) + +/* Could we use one macro entry? */ +#define HTT_WORD_SET(word, field, value) \ + do { \ + HTT_CHECK_SET_VAL(field, value); \ + (word) |= ((value) << field ## _S); \ + } while (0) +#define HTT_WORD_GET(word, field) \ + (((word) & field ## _M) >> field ## _S) + +PREPACK struct hl_htt_rx_ind_base { + /* + * align with LL case rx indication message,but + * reduced to 5 words + */ + A_UINT32 rx_ind_msg[HTT_RX_IND_HL_SIZE32]; +} POSTPACK; + +/* + * HTT_RX_IND_HL_RX_DESC_BASE_OFFSET + * Currently, we use a resv field in hl_htt_rx_ind_base to store some + * HL host needed info. The field is just after the msdu fw rx desc. + */ +#define HTT_RX_IND_HL_RX_DESC_BASE_OFFSET \ + (HTT_RX_IND_FW_RX_DESC_BYTE_OFFSET + 1) +struct htt_rx_ind_hl_rx_desc_t { + A_UINT8 ver; + A_UINT8 len; + struct { + A_UINT8 + first_msdu:1, + last_msdu:1, + c3_failed:1, + c4_failed:1, + ipv6:1, + tcp:1, + udp:1, + reserved:1; + } flags; +}; + +#define HTT_RX_IND_HL_RX_DESC_VER_OFFSET \ + (HTT_RX_IND_HL_RX_DESC_BASE_OFFSET \ + + offsetof(struct htt_rx_ind_hl_rx_desc_t, ver)) +#define HTT_RX_IND_HL_RX_DESC_VER 0 + +#define HTT_RX_IND_HL_RX_DESC_LEN_OFFSET \ + (HTT_RX_IND_HL_RX_DESC_BASE_OFFSET \ + + offsetof(struct htt_rx_ind_hl_rx_desc_t, len)) + +#define HTT_RX_IND_HL_FLAG_OFFSET \ + (HTT_RX_IND_HL_RX_DESC_BASE_OFFSET \ + + offsetof(struct htt_rx_ind_hl_rx_desc_t, flags)) + +#define HTT_RX_IND_HL_FLAG_FIRST_MSDU (0x01 << 0) +#define HTT_RX_IND_HL_FLAG_LAST_MSDU (0x01 << 1) +#define HTT_RX_IND_HL_FLAG_C3_FAILED (0x01 << 2) /* L3 checksum failed */ +#define HTT_RX_IND_HL_FLAG_C4_FAILED (0x01 << 3) /* L4 checksum failed */ +#define HTT_RX_IND_HL_FLAG_IPV6 (0x01 << 4) /* is ipv6, or ipv4 */ +#define HTT_RX_IND_HL_FLAG_TCP (0x01 << 5) /* is tcp */ +#define HTT_RX_IND_HL_FLAG_UDP (0x01 << 6) /* is udp */ +/* This structure is used in HL, the basic descriptor information + * used by host. the structure is translated by FW from HW desc + * or generated by FW. But in HL monitor mode, the host would use + * the same structure with LL. + */ +PREPACK struct hl_htt_rx_desc_base { + A_UINT32 + seq_num:12, + encrypted:1, + chan_info_present:1, + resv0:2, + mcast_bcast:1, + fragment:1, + key_id_oct:8, + resv1:6; + A_UINT32 pn_31_0; + union { + struct { + A_UINT16 pn_47_32; + A_UINT16 pn_63_48; + } pn16; + A_UINT32 pn_63_32; + } u0; + A_UINT32 pn_95_64; + A_UINT32 pn_127_96; +} POSTPACK; + +/* + * Channel information can optionally be appended after hl_htt_rx_desc_base. + * If so, the len field in htt_rx_ind_hl_rx_desc_t will be updated accordingly, + * and the chan_info_present flag in hl_htt_rx_desc_base will be set. + * Please see htt_chan_change_t for description of the fields. + */ +PREPACK struct htt_chan_info_t +{ + A_UINT32 + primary_chan_center_freq_mhz:16, + contig_chan1_center_freq_mhz:16; + A_UINT32 + contig_chan2_center_freq_mhz:16, + phy_mode:8, + reserved:8; +} POSTPACK; + +#define HTT_CHAN_INFO_SIZE sizeof(struct htt_chan_info_t) + +#define HL_RX_DESC_SIZE (sizeof(struct hl_htt_rx_desc_base)) +#define HL_RX_DESC_SIZE_DWORD (HL_RX_STD_DESC_SIZE >> 2) + +#define HTT_HL_RX_DESC_MPDU_SEQ_NUM_M 0xfff +#define HTT_HL_RX_DESC_MPDU_SEQ_NUM_S 0 +#define HTT_HL_RX_DESC_MPDU_ENC_M 0x1000 +#define HTT_HL_RX_DESC_MPDU_ENC_S 12 +#define HTT_HL_RX_DESC_CHAN_INFO_PRESENT_M 0x2000 +#define HTT_HL_RX_DESC_CHAN_INFO_PRESENT_S 13 +#define HTT_HL_RX_DESC_MCAST_BCAST_M 0x10000 +#define HTT_HL_RX_DESC_MCAST_BCAST_S 16 +#define HTT_HL_RX_DESC_FRAGMENT_M 0x20000 +#define HTT_HL_RX_DESC_FRAGMENT_S 17 +#define HTT_HL_RX_DESC_KEY_ID_OCT_M 0x3fc0000 +#define HTT_HL_RX_DESC_KEY_ID_OCT_S 18 + +#define HTT_HL_RX_DESC_PN_OFFSET \ + offsetof(struct hl_htt_rx_desc_base, pn_31_0) +#define HTT_HL_RX_DESC_PN_WORD_OFFSET \ + (HTT_HL_RX_DESC_PN_OFFSET >> 2) + +/* Channel information */ +#define HTT_CHAN_INFO_PRIMARY_CHAN_CENTER_FREQ_M 0x0000ffff +#define HTT_CHAN_INFO_PRIMARY_CHAN_CENTER_FREQ_S 0 +#define HTT_CHAN_INFO_CONTIG_CHAN1_CENTER_FREQ_M 0xffff0000 +#define HTT_CHAN_INFO_CONTIG_CHAN1_CENTER_FREQ_S 16 +#define HTT_CHAN_INFO_CONTIG_CHAN2_CENTER_FREQ_M 0x0000ffff +#define HTT_CHAN_INFO_CONTIG_CHAN2_CENTER_FREQ_S 0 +#define HTT_CHAN_INFO_PHY_MODE_M 0x00ff0000 +#define HTT_CHAN_INFO_PHY_MODE_S 16 + + +#define HTT_CHAN_INFO_PRIMARY_CHAN_CENTER_FREQ_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_CHAN_INFO_PRIMARY_CHAN_CENTER_FREQ, value); \ + (word) |= (value) << HTT_CHAN_INFO_PRIMARY_CHAN_CENTER_FREQ_S; \ + } while (0) +#define HTT_CHAN_INFO_PRIMARY_CHAN_CENTER_FREQ_GET(word) \ + (((word) & HTT_CHAN_INFO_PRIMARY_CHAN_CENTER_FREQ_M) \ + >> HTT_CHAN_INFO_PRIMARY_CHAN_CENTER_FREQ_S) + + +#define HTT_CHAN_INFO_CONTIG_CHAN1_CENTER_FREQ_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_CHAN_INFO_CONTIG_CHAN1_CENTER_FREQ, value); \ + (word) |= (value) << HTT_CHAN_INFO_CONTIG_CHAN1_CENTER_FREQ_S; \ + } while (0) +#define HTT_CHAN_INFO_CONTIG_CHAN1_CENTER_FREQ_GET(word) \ + (((word) & HTT_CHAN_INFO_CONTIG_CHAN1_CENTER_FREQ_M) \ + >> HTT_CHAN_INFO_CONTIG_CHAN1_CENTER_FREQ_S) + + +#define HTT_CHAN_INFO_CONTIG_CHAN2_CENTER_FREQ_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_CHAN_INFO_CONTIG_CHAN2_CENTER_FREQ, value); \ + (word) |= (value) << HTT_CHAN_INFO_CONTIG_CHAN2_CENTER_FREQ_S; \ + } while (0) +#define HTT_CHAN_INFO_CONTIG_CHAN2_CENTER_FREQ_GET(word) \ + (((word) & HTT_CHAN_INFO_CONTIG_CHAN2_CENTER_FREQ_M) \ + >> HTT_CHAN_INFO_CONTIG_CHAN2_CENTER_FREQ_S) + + +#define HTT_CHAN_INFO_PHY_MODE_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_CHAN_INFO_PHY_MODE, value); \ + (word) |= (value) << HTT_CHAN_INFO_PHY_MODE_S; \ + } while (0) +#define HTT_CHAN_INFO_PHY_MODE_GET(word) \ + (((word) & HTT_CHAN_INFO_PHY_MODE_M) \ + >> HTT_CHAN_INFO_PHY_MODE_S) + +/* + * @brief target -> host rx reorder flush message definition + * + * @details + * The following field definitions describe the format of the rx flush + * message sent from the target to the host. + * The message consists of a 4-octet header, followed by one or more + * 4-octet payload information elements. + * + * |31 24|23 8|7 0| + * |--------------------------------------------------------------| + * | TID | peer ID | msg type | + * |--------------------------------------------------------------| + * | seq num end | seq num start | MPDU status | reserved | + * |--------------------------------------------------------------| + * First DWORD: + * - MSG_TYPE + * Bits 7:0 + * Purpose: identifies this as an rx flush message + * Value: 0x2 + * - PEER_ID + * Bits 23:8 (only bits 18:8 actually used) + * Purpose: identify which peer's rx data is being flushed + * Value: (rx) peer ID + * - TID + * Bits 31:24 (only bits 27:24 actually used) + * Purpose: Specifies which traffic identifier's rx data is being flushed + * Value: traffic identifier + * Second DWORD: + * - MPDU_STATUS + * Bits 15:8 + * Purpose: + * Indicate whether the flushed MPDUs should be discarded or processed. + * Value: + * 0x1: send the MPDUs from the rx reorder buffer to subsequent + * stages of rx processing + * other: discard the MPDUs + * It is anticipated that flush messages will always have + * MPDU status == 1, but the status flag is included for + * flexibility. + * - SEQ_NUM_START + * Bits 23:16 + * Purpose: + * Indicate the start of a series of consecutive MPDUs being flushed. + * Not all MPDUs within this range are necessarily valid - the host + * must check each sequence number within this range to see if the + * corresponding MPDU is actually present. + * Value: + * The sequence number for the first MPDU in the sequence. + * This sequence number is the 6 LSBs of the 802.11 sequence number. + * - SEQ_NUM_END + * Bits 30:24 + * Purpose: + * Indicate the end of a series of consecutive MPDUs being flushed. + * Value: + * The sequence number one larger than the sequence number of the + * last MPDU being flushed. + * This sequence number is the 6 LSBs of the 802.11 sequence number. + * The range of MPDUs from [SEQ_NUM_START,SEQ_NUM_END-1] inclusive + * are to be released for further rx processing. + * Not all MPDUs within this range are necessarily valid - the host + * must check each sequence number within this range to see if the + * corresponding MPDU is actually present. + */ +/* first DWORD */ +#define HTT_RX_FLUSH_PEER_ID_M 0xffff00 +#define HTT_RX_FLUSH_PEER_ID_S 8 +#define HTT_RX_FLUSH_TID_M 0xff000000 +#define HTT_RX_FLUSH_TID_S 24 +/* second DWORD */ +#define HTT_RX_FLUSH_MPDU_STATUS_M 0x0000ff00 +#define HTT_RX_FLUSH_MPDU_STATUS_S 8 +#define HTT_RX_FLUSH_SEQ_NUM_START_M 0x00ff0000 +#define HTT_RX_FLUSH_SEQ_NUM_START_S 16 +#define HTT_RX_FLUSH_SEQ_NUM_END_M 0xff000000 +#define HTT_RX_FLUSH_SEQ_NUM_END_S 24 + +#define HTT_RX_FLUSH_BYTES 8 + +#define HTT_RX_FLUSH_PEER_ID_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_FLUSH_PEER_ID, value); \ + (word) |= (value) << HTT_RX_FLUSH_PEER_ID_S; \ + } while (0) +#define HTT_RX_FLUSH_PEER_ID_GET(word) \ + (((word) & HTT_RX_FLUSH_PEER_ID_M) >> HTT_RX_FLUSH_PEER_ID_S) + +#define HTT_RX_FLUSH_TID_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_FLUSH_TID, value); \ + (word) |= (value) << HTT_RX_FLUSH_TID_S; \ + } while (0) +#define HTT_RX_FLUSH_TID_GET(word) \ + (((word) & HTT_RX_FLUSH_TID_M) >> HTT_RX_FLUSH_TID_S) + +#define HTT_RX_FLUSH_MPDU_STATUS_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_FLUSH_MPDU_STATUS, value); \ + (word) |= (value) << HTT_RX_FLUSH_MPDU_STATUS_S; \ + } while (0) +#define HTT_RX_FLUSH_MPDU_STATUS_GET(word) \ + (((word) & HTT_RX_FLUSH_MPDU_STATUS_M) >> HTT_RX_FLUSH_MPDU_STATUS_S) + +#define HTT_RX_FLUSH_SEQ_NUM_START_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_FLUSH_SEQ_NUM_START, value); \ + (word) |= (value) << HTT_RX_FLUSH_SEQ_NUM_START_S; \ + } while (0) +#define HTT_RX_FLUSH_SEQ_NUM_START_GET(word) \ + (((word) & HTT_RX_FLUSH_SEQ_NUM_START_M) >> \ + HTT_RX_FLUSH_SEQ_NUM_START_S) + +#define HTT_RX_FLUSH_SEQ_NUM_END_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_FLUSH_SEQ_NUM_END, value); \ + (word) |= (value) << HTT_RX_FLUSH_SEQ_NUM_END_S; \ + } while (0) +#define HTT_RX_FLUSH_SEQ_NUM_END_GET(word) \ + (((word) & HTT_RX_FLUSH_SEQ_NUM_END_M) >> HTT_RX_FLUSH_SEQ_NUM_END_S) + +/* + * @brief target -> host rx pn check indication message + * + * @details + * The following field definitions describe the format of the Rx PN check + * indication message sent from the target to the host. + * The message consists of a 4-octet header, followed by the start and + * end sequence numbers to be released, followed by the PN IEs. Each PN + * IE is one octet containing the sequence number that failed the PN + * check. + * + * |31 24|23 8|7 0| + * |--------------------------------------------------------------| + * | TID | peer ID | msg type | + * |--------------------------------------------------------------| + * | Reserved | PN IE count | seq num end | seq num start| + * |--------------------------------------------------------------| + * l : PN IE 2 | PN IE 1 | PN IE 0 | + * |--------------------------------------------------------------| + + * First DWORD: + * - MSG_TYPE + * Bits 7:0 + * Purpose: Identifies this as an rx pn check indication message + * Value: 0x2 + * - PEER_ID + * Bits 23:8 (only bits 18:8 actually used) + * Purpose: identify which peer + * Value: (rx) peer ID + * - TID + * Bits 31:24 (only bits 27:24 actually used) + * Purpose: identify traffic identifier + * Value: traffic identifier + * Second DWORD: + * - SEQ_NUM_START + * Bits 7:0 + * Purpose: + * Indicates the starting sequence number of the MPDU in this + * series of MPDUs that went though PN check. + * Value: + * The sequence number for the first MPDU in the sequence. + * This sequence number is the 6 LSBs of the 802.11 sequence number. + * - SEQ_NUM_END + * Bits 15:8 + * Purpose: + * Indicates the ending sequence number of the MPDU in this + * series of MPDUs that went though PN check. + * Value: + * The sequence number one larger then the sequence number of the last + * MPDU being flushed. + * This sequence number is the 6 LSBs of the 802.11 sequence number. + * The range of MPDUs from [SEQ_NUM_START,SEQ_NUM_END-1] + * have been checked for invalid PN numbers and are ready + * to be released for further processing. + * Not all MPDUs within this range are necessarily valid - the host + * must check each sequence number within this range to see if the + * corresponding MPDU is actually present. + * - PN_IE_COUNT + * Bits 23:16 + * Purpose: + * Used to determine the variable number of PN information + * elements in this message + * + * PN information elements: + * - PN_IE_x- + * Purpose: + * Each PN information element contains the sequence number + * of the MPDU that has failed the target PN check. + * Value: + * Contains the 6 LSBs of the 802.11 sequence number + * corresponding to the MPDU that failed the PN check. + */ +/* first DWORD */ +#define HTT_RX_PN_IND_PEER_ID_M 0xffff00 +#define HTT_RX_PN_IND_PEER_ID_S 8 +#define HTT_RX_PN_IND_TID_M 0xff000000 +#define HTT_RX_PN_IND_TID_S 24 +/* second DWORD */ +#define HTT_RX_PN_IND_SEQ_NUM_START_M 0x000000ff +#define HTT_RX_PN_IND_SEQ_NUM_START_S 0 +#define HTT_RX_PN_IND_SEQ_NUM_END_M 0x0000ff00 +#define HTT_RX_PN_IND_SEQ_NUM_END_S 8 +#define HTT_RX_PN_IND_PN_IE_CNT_M 0x00ff0000 +#define HTT_RX_PN_IND_PN_IE_CNT_S 16 + +#define HTT_RX_PN_IND_BYTES 8 + +#define HTT_RX_PN_IND_PEER_ID_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_PN_IND_PEER_ID, value); \ + (word) |= (value) << HTT_RX_PN_IND_PEER_ID_S; \ + } while (0) +#define HTT_RX_PN_IND_PEER_ID_GET(word) \ + (((word) & HTT_RX_PN_IND_PEER_ID_M) >> HTT_RX_PN_IND_PEER_ID_S) + +#define HTT_RX_PN_IND_EXT_TID_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_PN_IND_TID, value); \ + (word) |= (value) << HTT_RX_PN_IND_TID_S; \ + } while (0) +#define HTT_RX_PN_IND_EXT_TID_GET(word) \ + (((word) & HTT_RX_PN_IND_TID_M) >> HTT_RX_PN_IND_TID_S) + +#define HTT_RX_PN_IND_SEQ_NUM_START_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_PN_IND_SEQ_NUM_START, value); \ + (word) |= (value) << HTT_RX_PN_IND_SEQ_NUM_START_S; \ + } while (0) +#define HTT_RX_PN_IND_SEQ_NUM_START_GET(word) \ + (((word) & HTT_RX_PN_IND_SEQ_NUM_START_M) >> \ + HTT_RX_PN_IND_SEQ_NUM_START_S) + +#define HTT_RX_PN_IND_SEQ_NUM_END_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_PN_IND_SEQ_NUM_END, value); \ + (word) |= (value) << HTT_RX_PN_IND_SEQ_NUM_END_S; \ + } while (0) +#define HTT_RX_PN_IND_SEQ_NUM_END_GET(word) \ + (((word) & HTT_RX_PN_IND_SEQ_NUM_END_M) >> HTT_RX_PN_IND_SEQ_NUM_END_S) + +#define HTT_RX_PN_IND_PN_IE_CNT_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_PN_IND_PN_IE_CNT, value); \ + (word) |= (value) << HTT_RX_PN_IND_PN_IE_CNT_S; \ + } while (0) +#define HTT_RX_PN_IND_PN_IE_CNT_GET(word) \ + (((word) & HTT_RX_PN_IND_PN_IE_CNT_M) >> HTT_RX_PN_IND_PN_IE_CNT_S) + +/* + * @brief target -> host rx offload deliver message for LL system + * + * @details + * In a low latency system this message is sent whenever the offload + * manager flushes out the packets it has coalesced in its coalescing buffer. + * The DMA of the actual packets into host memory is done before sending out + * this message. This message indicates only how many MSDUs to reap. The + * peer ID, vdev ID, tid and MSDU length are copied inline into the header + * portion of the MSDU while DMA'ing into the host memory. Unlike the packets + * DMA'd by the MAC directly into host memory these packets do not contain + * the MAC descriptors in the header portion of the packet. Instead they contain + * the peer ID, vdev ID, tid and MSDU length. Also when the host receives this + * message, the packets are delivered directly to the NW stack without going + * through the regular reorder buffering and PN checking path since it has + * already been done in target. + * + * |31 24|23 16|15 8|7 0| + * |-----------------------------------------------------------------------| + * | Total MSDU count | reserved | msg type | + * |-----------------------------------------------------------------------| + * + * @brief target -> host rx offload deliver message for HL system + * + * @details + * In a high latency system this message is sent whenever the offload manager + * flushes out the packets it has coalesced in its coalescing buffer. The + * actual packets are also carried along with this message. When the host + * receives this message, it is expected to deliver these packets to the NW + * stack directly instead of routing them through the reorder buffering and + * PN checking path since it has already been done in target. + * + * |31 24|23 16|15 8|7 0| + * |-----------------------------------------------------------------------| + * | Total MSDU count | reserved | msg type | + * |-----------------------------------------------------------------------| + * | peer ID | MSDU length | + * |-----------------------------------------------------------------------| + * | MSDU payload | FW Desc | tid | vdev ID | + * |-----------------------------------------------------------------------| + * | MSDU payload contd. | + * |-----------------------------------------------------------------------| + * | peer ID | MSDU length | + * |-----------------------------------------------------------------------| + * | MSDU payload | FW Desc | tid | vdev ID | + * |-----------------------------------------------------------------------| + * | MSDU payload contd. | + * |-----------------------------------------------------------------------| + * + */ +/* first DWORD */ +#define HTT_RX_OFFLOAD_DELIVER_IND_HDR_BYTES 4 +#define HTT_RX_OFFLOAD_DELIVER_IND_MSDU_HDR_BYTES 7 + +#define HTT_RX_OFFLOAD_DELIVER_IND_MSDU_CNT_M 0xffff0000 +#define HTT_RX_OFFLOAD_DELIVER_IND_MSDU_CNT_S 16 +#define HTT_RX_OFFLOAD_DELIVER_IND_MSDU_LEN_M 0x0000ffff +#define HTT_RX_OFFLOAD_DELIVER_IND_MSDU_LEN_S 0 +#define HTT_RX_OFFLOAD_DELIVER_IND_MSDU_PEER_ID_M 0xffff0000 +#define HTT_RX_OFFLOAD_DELIVER_IND_MSDU_PEER_ID_S 16 +#define HTT_RX_OFFLOAD_DELIVER_IND_MSDU_VDEV_ID_M 0x000000ff +#define HTT_RX_OFFLOAD_DELIVER_IND_MSDU_VDEV_ID_S 0 +#define HTT_RX_OFFLOAD_DELIVER_IND_MSDU_TID_M 0x0000ff00 +#define HTT_RX_OFFLOAD_DELIVER_IND_MSDU_TID_S 8 +#define HTT_RX_OFFLOAD_DELIVER_IND_MSDU_DESC_M 0x00ff0000 +#define HTT_RX_OFFLOAD_DELIVER_IND_MSDU_DESC_S 16 + +#define HTT_RX_OFFLOAD_DELIVER_IND_MSDU_CNT_GET(word) \ + (((word) & HTT_RX_OFFLOAD_DELIVER_IND_MSDU_CNT_M) >> \ + HTT_RX_OFFLOAD_DELIVER_IND_MSDU_CNT_S) +#define HTT_RX_OFFLOAD_DELIVER_IND_MSDU_CNT_SET(word, value) \ +do { \ + HTT_CHECK_SET_VAL(HTT_RX_OFFLOAD_DELIVER_IND_MSDU_CNT, value); \ + (word) |= (value) << HTT_RX_OFFLOAD_DELIVER_IND_MSDU_CNT_S; \ +} while (0) \ + +#define HTT_RX_OFFLOAD_DELIVER_IND_MSDU_LEN_GET(word) \ + (((word) & HTT_RX_OFFLOAD_DELIVER_IND_MSDU_LEN_M) >> \ + HTT_RX_OFFLOAD_DELIVER_IND_MSDU_LEN_S) +#define HTT_RX_OFFLOAD_DELIVER_IND_MSDU_LEN_SET(word, value) \ +do { \ + HTT_CHECK_SET_VAL(HTT_RX_OFFLOAD_DELIVER_IND_MSDU_LEN, value); \ + (word) |= (value) << HTT_RX_OFFLOAD_DELIVER_IND_MSDU_LEN_S; \ +} while (0) \ + +#define HTT_RX_OFFLOAD_DELIVER_IND_MSDU_PEER_ID_GET(word) \ + (((word) & HTT_RX_OFFLOAD_DELIVER_IND_MSDU_PEER_ID_M) >> \ + HTT_RX_OFFLOAD_DELIVER_IND_MSDU_PEER_ID_S) +#define HTT_RX_OFFLOAD_DELIVER_IND_MSDU_PEER_ID_SET(word, value) \ +do { \ + HTT_CHECK_SET_VAL(HTT_RX_OFFLOAD_DELIVER_IND_MSDU_PEER_ID, value); \ + (word) |= (value) << HTT_RX_OFFLOAD_DELIVER_IND_MSDU_PEER_ID_S; \ +} while (0) \ + +#define HTT_RX_OFFLOAD_DELIVER_IND_MSDU_VDEV_ID_GET(word) \ + (((word) & HTT_RX_OFFLOAD_DELIVER_IND_MSDU_VDEV_ID_M) >> \ + HTT_RX_OFFLOAD_DELIVER_IND_MSDU_VDEV_ID_S) +#define HTT_RX_OFFLOAD_DELIVER_IND_MSDU_VDEV_ID_SET(word, value) \ +do { \ + HTT_CHECK_SET_VAL(HTT_RX_OFFLOAD_DELIVER_IND_MSDU_VDEV_ID, value); \ + (word) |= (value) << HTT_RX_OFFLOAD_DELIVER_IND_MSDU_VDEV_ID_S; \ +} while (0) \ + +#define HTT_RX_OFFLOAD_DELIVER_IND_MSDU_TID_GET(word) \ + (((word) & HTT_RX_OFFLOAD_DELIVER_IND_MSDU_TID_M) >> \ + HTT_RX_OFFLOAD_DELIVER_IND_MSDU_TID_S) +#define HTT_RX_OFFLOAD_DELIVER_IND_MSDU_TID_SET(word, value) \ +do { \ + HTT_CHECK_SET_VAL(HTT_RX_OFFLOAD_DELIVER_IND_MSDU_TID, value); \ + (word) |= (value) << HTT_RX_OFFLOAD_DELIVER_IND_MSDU_TID_S; \ +} while (0) \ + +#define HTT_RX_OFFLOAD_DELIVER_IND_MSDU_DESC_GET(word) \ + (((word) & HTT_RX_OFFLOAD_DELIVER_IND_MSDU_DESC_M) >> \ + HTT_RX_OFFLOAD_DELIVER_IND_MSDU_DESC_S) +#define HTT_RX_OFFLOAD_DELIVER_IND_MSDU_DESC_SET(word, value) \ +do { \ + HTT_CHECK_SET_VAL(HTT_RX_OFFLOAD_DELIVER_IND_MSDU_DESC, value); \ + (word) |= (value) << HTT_RX_OFFLOAD_DELIVER_IND_MSDU_DESC_S; \ +} while (0) \ + +/** + * @brief target -> host rx peer map/unmap message definition + * + * @details + * The following diagram shows the format of the rx peer map message sent + * from the target to the host. This layout assumes the target operates + * as little-endian. + * + * |31 24|23 16|15 8|7 0| + * |-----------------------------------------------------------------------| + * | peer ID | VDEV ID | msg type | + * |-----------------------------------------------------------------------| + * | MAC addr 3 | MAC addr 2 | MAC addr 1 | MAC addr 0 | + * |-----------------------------------------------------------------------| + * | reserved | MAC addr 5 | MAC addr 4 | + * |-----------------------------------------------------------------------| + * + * + * The following diagram shows the format of the rx peer unmap message sent + * from the target to the host. + * + * |31 24|23 16|15 8|7 0| + * |-----------------------------------------------------------------------| + * | peer ID | VDEV ID | msg type | + * |-----------------------------------------------------------------------| + * + * The following field definitions describe the format of the rx peer map + * and peer unmap messages sent from the target to the host. + * - MSG_TYPE + * Bits 7:0 + * Purpose: identifies this as an rx peer map or peer unmap message + * Value: peer map -> 0x3, peer unmap -> 0x4 + * - VDEV_ID + * Bits 15:8 + * Purpose: Indicates which virtual device the peer is associated + * with. + * Value: vdev ID (used in the host to look up the vdev object) + * - PEER_ID + * Bits 31:16 + * Purpose: The peer ID (index) that WAL is allocating (map) or + * freeing (unmap) + * Value: (rx) peer ID + * - MAC_ADDR_L32 (peer map only) + * Bits 31:0 + * Purpose: Identifies which peer node the peer ID is for. + * Value: lower 4 bytes of peer node's MAC address + * - MAC_ADDR_U16 (peer map only) + * Bits 15:0 + * Purpose: Identifies which peer node the peer ID is for. + * Value: upper 2 bytes of peer node's MAC address + */ +#define HTT_RX_PEER_MAP_VDEV_ID_M 0xff00 +#define HTT_RX_PEER_MAP_VDEV_ID_S 8 +#define HTT_RX_PEER_MAP_PEER_ID_M 0xffff0000 +#define HTT_RX_PEER_MAP_PEER_ID_S 16 +#define HTT_RX_PEER_MAP_MAC_ADDR_L32_M 0xffffffff +#define HTT_RX_PEER_MAP_MAC_ADDR_L32_S 0 +#define HTT_RX_PEER_MAP_MAC_ADDR_U16_M 0xffff +#define HTT_RX_PEER_MAP_MAC_ADDR_U16_S 0 + +#define HTT_RX_PEER_MAP_VAP_ID_SET HTT_RX_PEER_MAP_VDEV_ID_SET /* deprecated */ +#define HTT_RX_PEER_MAP_VDEV_ID_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_PEER_MAP_VDEV_ID, value); \ + (word) |= (value) << HTT_RX_PEER_MAP_VDEV_ID_S; \ + } while (0) +#define HTT_RX_PEER_MAP_VAP_ID_GET HTT_RX_PEER_MAP_VDEV_ID_GET /* deprecated */ +#define HTT_RX_PEER_MAP_VDEV_ID_GET(word) \ + (((word) & HTT_RX_PEER_MAP_VDEV_ID_M) >> HTT_RX_PEER_MAP_VDEV_ID_S) + +#define HTT_RX_PEER_MAP_PEER_ID_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_PEER_MAP_PEER_ID, value); \ + (word) |= (value) << HTT_RX_PEER_MAP_PEER_ID_S; \ + } while (0) +#define HTT_RX_PEER_MAP_PEER_ID_GET(word) \ + (((word) & HTT_RX_PEER_MAP_PEER_ID_M) >> HTT_RX_PEER_MAP_PEER_ID_S) + +#define HTT_RX_PEER_MAP_MAC_ADDR_OFFSET 4 /* bytes */ + +#define HTT_RX_PEER_MAP_BYTES 12 + + +#define HTT_RX_PEER_UNMAP_PEER_ID_M HTT_RX_PEER_MAP_PEER_ID_M +#define HTT_RX_PEER_UNMAP_PEER_ID_S HTT_RX_PEER_MAP_PEER_ID_S + +#define HTT_RX_PEER_UNMAP_PEER_ID_SET HTT_RX_PEER_MAP_PEER_ID_SET +#define HTT_RX_PEER_UNMAP_PEER_ID_GET HTT_RX_PEER_MAP_PEER_ID_GET + +#define HTT_RX_PEER_UNMAP_VDEV_ID_SET HTT_RX_PEER_MAP_VDEV_ID_SET +#define HTT_RX_PEER_UNMAP_VDEV_ID_GET HTT_RX_PEER_MAP_VDEV_ID_GET + +#define HTT_RX_PEER_UNMAP_BYTES 4 + + +/** + * @brief target -> host message specifying security parameters + * + * @details + * The following diagram shows the format of the security specification + * message sent from the target to the host. + * This security specification message tells the host whether a PN check is + * necessary on rx data frames, and if so, how large the PN counter is. + * This message also tells the host about the security processing to apply + * to defragmented rx frames - specifically, whether a Message Integrity + * Check is required, and the Michael key to use. + * + * |31 24|23 16|15|14 8|7 0| + * |-----------------------------------------------------------------------| + * | peer ID | U| security type | msg type | + * |-----------------------------------------------------------------------| + * | Michael Key K0 | + * |-----------------------------------------------------------------------| + * | Michael Key K1 | + * |-----------------------------------------------------------------------| + * | WAPI RSC Low0 | + * |-----------------------------------------------------------------------| + * | WAPI RSC Low1 | + * |-----------------------------------------------------------------------| + * | WAPI RSC Hi0 | + * |-----------------------------------------------------------------------| + * | WAPI RSC Hi1 | + * |-----------------------------------------------------------------------| + * + * The following field definitions describe the format of the security + * indication message sent from the target to the host. + * - MSG_TYPE + * Bits 7:0 + * Purpose: identifies this as a security specification message + * Value: 0xb + * - SEC_TYPE + * Bits 14:8 + * Purpose: specifies which type of security applies to the peer + * Value: htt_sec_type enum value + * - UNICAST + * Bit 15 + * Purpose: whether this security is applied to unicast or multicast data + * Value: 1 -> unicast, 0 -> multicast + * - PEER_ID + * Bits 31:16 + * Purpose: The ID number for the peer the security specification is for + * Value: peer ID + * - MICHAEL_KEY_K0 + * Bits 31:0 + * Purpose: 4-byte word that forms the 1st half of the TKIP Michael key + * Value: Michael Key K0 (if security type is TKIP) + * - MICHAEL_KEY_K1 + * Bits 31:0 + * Purpose: 4-byte word that forms the 2nd half of the TKIP Michael key + * Value: Michael Key K1 (if security type is TKIP) + * - WAPI_RSC_LOW0 + * Bits 31:0 + * Purpose: 4-byte word that forms the 1st quarter of the 16 byte WAPI RSC + * Value: WAPI RSC Low0 (if security type is WAPI) + * - WAPI_RSC_LOW1 + * Bits 31:0 + * Purpose: 4-byte word that forms the 2nd quarter of the 16 byte WAPI RSC + * Value: WAPI RSC Low1 (if security type is WAPI) + * - WAPI_RSC_HI0 + * Bits 31:0 + * Purpose: 4-byte word that forms the 3rd quarter of the 16 byte WAPI RSC + * Value: WAPI RSC Hi0 (if security type is WAPI) + * - WAPI_RSC_HI1 + * Bits 31:0 + * Purpose: 4-byte word that forms the 4th quarter of the 16 byte WAPI RSC + * Value: WAPI RSC Hi1 (if security type is WAPI) + */ + +#define HTT_SEC_IND_SEC_TYPE_M 0x00007f00 +#define HTT_SEC_IND_SEC_TYPE_S 8 +#define HTT_SEC_IND_UNICAST_M 0x00008000 +#define HTT_SEC_IND_UNICAST_S 15 +#define HTT_SEC_IND_PEER_ID_M 0xffff0000 +#define HTT_SEC_IND_PEER_ID_S 16 + +#define HTT_SEC_IND_SEC_TYPE_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_SEC_IND_SEC_TYPE, value); \ + (word) |= (value) << HTT_SEC_IND_SEC_TYPE_S; \ + } while (0) +#define HTT_SEC_IND_SEC_TYPE_GET(word) \ + (((word) & HTT_SEC_IND_SEC_TYPE_M) >> HTT_SEC_IND_SEC_TYPE_S) + +#define HTT_SEC_IND_UNICAST_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_SEC_IND_UNICAST, value); \ + (word) |= (value) << HTT_SEC_IND_UNICAST_S; \ + } while (0) +#define HTT_SEC_IND_UNICAST_GET(word) \ + (((word) & HTT_SEC_IND_UNICAST_M) >> HTT_SEC_IND_UNICAST_S) + +#define HTT_SEC_IND_PEER_ID_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_SEC_IND_PEER_ID, value); \ + (word) |= (value) << HTT_SEC_IND_PEER_ID_S; \ + } while (0) +#define HTT_SEC_IND_PEER_ID_GET(word) \ + (((word) & HTT_SEC_IND_PEER_ID_M) >> HTT_SEC_IND_PEER_ID_S) + + +#define HTT_SEC_IND_BYTES 28 + + +/** + * @brief target -> host rx ADDBA / DELBA message definitions + * + * @details + * The following diagram shows the format of the rx ADDBA message sent + * from the target to the host: + * + * |31 20|19 16|15 8|7 0| + * |---------------------------------------------------------------------| + * | peer ID | TID | window size | msg type | + * |---------------------------------------------------------------------| + * + * The following diagram shows the format of the rx DELBA message sent + * from the target to the host: + * + * |31 20|19 16|15 8|7 0| + * |---------------------------------------------------------------------| + * | peer ID | TID | reserved | msg type | + * |---------------------------------------------------------------------| + * + * The following field definitions describe the format of the rx ADDBA + * and DELBA messages sent from the target to the host. + * - MSG_TYPE + * Bits 7:0 + * Purpose: identifies this as an rx ADDBA or DELBA message + * Value: ADDBA -> 0x5, DELBA -> 0x6 + * - WIN_SIZE + * Bits 15:8 (ADDBA only) + * Purpose: Specifies the length of the block ack window (max = 64). + * Value: + * block ack window length specified by the received ADDBA + * management message. + * - TID + * Bits 19:16 + * Purpose: Specifies which traffic identifier the ADDBA / DELBA is for. + * Value: + * TID specified by the received ADDBA or DELBA management message. + * - PEER_ID + * Bits 31:20 + * Purpose: Identifies which peer sent the ADDBA / DELBA. + * Value: + * ID (hash value) used by the host for fast, direct lookup of + * host SW peer info, including rx reorder states. + */ +#define HTT_RX_ADDBA_WIN_SIZE_M 0xff00 +#define HTT_RX_ADDBA_WIN_SIZE_S 8 +#define HTT_RX_ADDBA_TID_M 0xf0000 +#define HTT_RX_ADDBA_TID_S 16 +#define HTT_RX_ADDBA_PEER_ID_M 0xfff00000 +#define HTT_RX_ADDBA_PEER_ID_S 20 + +#define HTT_RX_ADDBA_WIN_SIZE_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_ADDBA_WIN_SIZE, value); \ + (word) |= (value) << HTT_RX_ADDBA_WIN_SIZE_S; \ + } while (0) +#define HTT_RX_ADDBA_WIN_SIZE_GET(word) \ + (((word) & HTT_RX_ADDBA_WIN_SIZE_M) >> HTT_RX_ADDBA_WIN_SIZE_S) + +#define HTT_RX_ADDBA_TID_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_ADDBA_TID, value); \ + (word) |= (value) << HTT_RX_ADDBA_TID_S; \ + } while (0) +#define HTT_RX_ADDBA_TID_GET(word) \ + (((word) & HTT_RX_ADDBA_TID_M) >> HTT_RX_ADDBA_TID_S) + +#define HTT_RX_ADDBA_PEER_ID_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_ADDBA_PEER_ID, value); \ + (word) |= (value) << HTT_RX_ADDBA_PEER_ID_S; \ + } while (0) +#define HTT_RX_ADDBA_PEER_ID_GET(word) \ + (((word) & HTT_RX_ADDBA_PEER_ID_M) >> HTT_RX_ADDBA_PEER_ID_S) + +#define HTT_RX_ADDBA_BYTES 4 + + +#define HTT_RX_DELBA_TID_M HTT_RX_ADDBA_TID_M +#define HTT_RX_DELBA_TID_S HTT_RX_ADDBA_TID_S +#define HTT_RX_DELBA_PEER_ID_M HTT_RX_ADDBA_PEER_ID_M +#define HTT_RX_DELBA_PEER_ID_S HTT_RX_ADDBA_PEER_ID_S + +#define HTT_RX_DELBA_TID_SET HTT_RX_ADDBA_TID_SET +#define HTT_RX_DELBA_TID_GET HTT_RX_ADDBA_TID_GET +#define HTT_RX_DELBA_PEER_ID_SET HTT_RX_ADDBA_PEER_ID_SET +#define HTT_RX_DELBA_PEER_ID_GET HTT_RX_ADDBA_PEER_ID_GET + +#define HTT_RX_DELBA_BYTES 4 + +/** + * @brief tx queue group information element definition + * + * @details + * The following diagram shows the format of the tx queue group + * information element, which can be included in target --> host + * messages to specify the number of tx "credits" (tx descriptors + * for LL, or tx buffers for HL) available to a particular group + * of host-side tx queues, and which host-side tx queues belong to + * the group. + * + * |31|30 24|23 16|15|14|13 0| + * |------------------------------------------------------------------------| + * | X| reserved | tx queue grp ID | A| S| credit count | + * |------------------------------------------------------------------------| + * | vdev ID mask | AC mask | + * |------------------------------------------------------------------------| + * + * The following definitions describe the fields within the tx queue group + * information element: + * - credit_count + * Bits 13:1 + * Purpose: specify how many tx credits are available to the tx queue group + * Value: An absolute or relative, positive or negative credit value + * The 'A' bit specifies whether the value is absolute or relative. + * The 'S' bit specifies whether the value is positive or negative. + * A negative value can only be relative, not absolute. + * An absolute value replaces any prior credit value the host has for + * the tx queue group in question. + * A relative value is added to the prior credit value the host has for + * the tx queue group in question. + * - sign + * Bit 14 + * Purpose: specify whether the credit count is positive or negative + * Value: 0 -> positive, 1 -> negative + * - absolute + * Bit 15 + * Purpose: specify whether the credit count is absolute or relative + * Value: 0 -> relative, 1 -> absolute + * - txq_group_id + * Bits 23:16 + * Purpose: indicate which tx queue group's credit and/or membership are + * being specified + * Value: 0 to max_tx_queue_groups-1 + * - reserved + * Bits 30:16 + * Value: 0x0 + * - eXtension + * Bit 31 + * Purpose: specify whether another tx queue group info element follows + * Value: 0 -> no more tx queue group information elements + * 1 -> another tx queue group information element immediately follows + * - ac_mask + * Bits 15:0 + * Purpose: specify which Access Categories belong to the tx queue group + * Value: bit-OR of masks for the ACs (WMM and extension) that belong to + * the tx queue group. + * The AC bit-mask values are obtained by left-shifting by the + * corresponding HTT_AC_WMM enum values, e.g. (1 << HTT_AC_WMM_BE) == 0x1 + * - vdev_id_mask + * Bits 31:16 + * Purpose: specify which vdev's tx queues belong to the tx queue group + * Value: bit-OR of masks based on the IDs of the vdevs whose tx queues + * belong to the tx queue group. + * For example, if vdev IDs 1 and 4 belong to a tx queue group, the + * vdev_id_mask would be (1 << 1) | (1 << 4) = 0x12 + */ +PREPACK struct htt_txq_group { + A_UINT32 + credit_count:14, + sign:1, + absolute:1, + tx_queue_group_id:8, + reserved0:7, + extension:1; + A_UINT32 + ac_mask:16, + vdev_id_mask:16; +} POSTPACK; + +/* first word */ +#define HTT_TXQ_GROUP_CREDIT_COUNT_S 0 +#define HTT_TXQ_GROUP_CREDIT_COUNT_M 0x00003fff +#define HTT_TXQ_GROUP_SIGN_S 14 +#define HTT_TXQ_GROUP_SIGN_M 0x00004000 +#define HTT_TXQ_GROUP_ABS_S 15 +#define HTT_TXQ_GROUP_ABS_M 0x00008000 +#define HTT_TXQ_GROUP_ID_S 16 +#define HTT_TXQ_GROUP_ID_M 0x00ff0000 +#define HTT_TXQ_GROUP_EXT_S 31 +#define HTT_TXQ_GROUP_EXT_M 0x80000000 +/* second word */ +#define HTT_TXQ_GROUP_AC_MASK_S 0 +#define HTT_TXQ_GROUP_AC_MASK_M 0x0000ffff +#define HTT_TXQ_GROUP_VDEV_ID_MASK_S 16 +#define HTT_TXQ_GROUP_VDEV_ID_MASK_M 0xffff0000 + +#define HTT_TXQ_GROUP_CREDIT_COUNT_SET(_info, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_TXQ_GROUP_CREDIT_COUNT, _val); \ + ((_info) |= ((_val) << HTT_TXQ_GROUP_CREDIT_COUNT_S)); \ + } while (0) +#define HTT_TXQ_GROUP_CREDIT_COUNT_GET(_info) \ + (((_info) & HTT_TXQ_GROUP_CREDIT_COUNT_M) >> \ + HTT_TXQ_GROUP_CREDIT_COUNT_S) + +#define HTT_TXQ_GROUP_SIGN_SET(_info, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_TXQ_GROUP_SIGN, _val); \ + ((_info) |= ((_val) << HTT_TXQ_GROUP_SIGN_S)); \ + } while (0) +#define HTT_TXQ_GROUP_SIGN_GET(_info) \ + (((_info) & HTT_TXQ_GROUP_SIGN_M) >> HTT_TXQ_GROUP_SIGN_S) + +#define HTT_TXQ_GROUP_ABS_SET(_info, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_TXQ_GROUP_ABS, _val); \ + ((_info) |= ((_val) << HTT_TXQ_GROUP_ABS_S)); \ + } while (0) +#define HTT_TXQ_GROUP_ABS_GET(_info) \ + (((_info) & HTT_TXQ_GROUP_ABS_M) >> HTT_TXQ_GROUP_ABS_S) + +#define HTT_TXQ_GROUP_ID_SET(_info, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_TXQ_GROUP_ID, _val); \ + ((_info) |= ((_val) << HTT_TXQ_GROUP_ID_S)); \ + } while (0) +#define HTT_TXQ_GROUP_ID_GET(_info) \ + (((_info) & HTT_TXQ_GROUP_ID_M) >> HTT_TXQ_GROUP_ID_S) + +#define HTT_TXQ_GROUP_EXT_SET(_info, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_TXQ_GROUP_EXT, _val); \ + ((_info) |= ((_val) << HTT_TXQ_GROUP_EXT_S)); \ + } while (0) +#define HTT_TXQ_GROUP_EXT_GET(_info) \ + (((_info) & HTT_TXQ_GROUP_EXT_M) >> HTT_TXQ_GROUP_EXT_S) + +#define HTT_TXQ_GROUP_AC_MASK_SET(_info, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_TXQ_GROUP_AC_MASK, _val); \ + ((_info) |= ((_val) << HTT_TXQ_GROUP_AC_MASK_S)); \ + } while (0) +#define HTT_TXQ_GROUP_AC_MASK_GET(_info) \ + (((_info) & HTT_TXQ_GROUP_AC_MASK_M) >> HTT_TXQ_GROUP_AC_MASK_S) + +#define HTT_TXQ_GROUP_VDEV_ID_MASK_SET(_info, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_TXQ_GROUP_VDEV_ID_MASK, _val); \ + ((_info) |= ((_val) << HTT_TXQ_GROUP_VDEV_ID_MASK_S)); \ + } while (0) +#define HTT_TXQ_GROUP_VDEV_ID_MASK_GET(_info) \ + (((_info) & HTT_TXQ_GROUP_VDEV_ID_MASK_M) >> \ + HTT_TXQ_GROUP_VDEV_ID_MASK_S) + +/** + * @brief target -> host TX completion indication message definition + * + * @details + * The following diagram shows the format of the TX completion indication sent + * from the target to the host + * + * |31 25| 24|23 16| 15 |14 11|10 8|7 0| + * |-------------------------------------------------------------| + * header: | reserved |append| num | t_i| tid |status| msg_type | + * |-------------------------------------------------------------| + * payload: | MSDU1 ID | MSDU0 ID | + * |-------------------------------------------------------------| + * : MSDU3 ID : MSDU2 ID : + * |-------------------------------------------------------------| + * | struct htt_tx_compl_ind_append_retries | + * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * + * The following field definitions describe the format of the TX completion + * indication sent from the target to the host + * Header fields: + * - msg_type + * Bits 7:0 + * Purpose: identifies this as HTT TX completion indication + * Value: 0x7 + * - status + * Bits 10:8 + * Purpose: the TX completion status of payload fragmentations descriptors + * Value: could be HTT_TX_COMPL_IND_STAT_OK or HTT_TX_COMPL_IND_STAT_DISCARD + * - tid + * Bits 14:11 + * Purpose: the tid associated with those fragmentation descriptors. It is + * valid or not, depending on the tid_invalid bit. + * Value: 0 to 15 + * - tid_invalid + * Bits 15:15 + * Purpose: this bit indicates whether the tid field is valid or not + * Value: 0 indicates valid; 1 indicates invalid + * - num + * Bits 23:16 + * Purpose: the number of payload in this indication + * Value: 1 to 255 + * - append + * Bits 24:24 + * Purpose: append the struct htt_tx_compl_ind_append_retries which contains + * the number of tx retries for one MSDU at the end of this message + * Value: 0 indicates no appending; 1 indicates appending + * Payload fields: + * - hmsdu_id + * Bits 15:0 + * Purpose: this ID is used to track the Tx buffer in host + * Value: 0 to "size of host MSDU descriptor pool - 1" + */ + +#define HTT_TX_COMPL_IND_STATUS_S 8 +#define HTT_TX_COMPL_IND_STATUS_M 0x00000700 +#define HTT_TX_COMPL_IND_TID_S 11 +#define HTT_TX_COMPL_IND_TID_M 0x00007800 +#define HTT_TX_COMPL_IND_TID_INV_S 15 +#define HTT_TX_COMPL_IND_TID_INV_M 0x00008000 +#define HTT_TX_COMPL_IND_NUM_S 16 +#define HTT_TX_COMPL_IND_NUM_M 0x00ff0000 +#define HTT_TX_COMPL_IND_APPEND_S 24 +#define HTT_TX_COMPL_IND_APPEND_M 0x01000000 + +#define HTT_TX_COMPL_IND_STATUS_SET(_info, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_TX_COMPL_IND_STATUS, _val); \ + ((_info) |= ((_val) << HTT_TX_COMPL_IND_STATUS_S)); \ + } while (0) +#define HTT_TX_COMPL_IND_STATUS_GET(_info) \ + (((_info) & HTT_TX_COMPL_IND_STATUS_M) >> HTT_TX_COMPL_IND_STATUS_S) +#define HTT_TX_COMPL_IND_NUM_SET(_info, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_TX_COMPL_IND_NUM, _val); \ + ((_info) |= ((_val) << HTT_TX_COMPL_IND_NUM_S)); \ + } while (0) +#define HTT_TX_COMPL_IND_NUM_GET(_info) \ + (((_info) & HTT_TX_COMPL_IND_NUM_M) >> HTT_TX_COMPL_IND_NUM_S) +#define HTT_TX_COMPL_IND_TID_SET(_info, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_TX_COMPL_IND_TID, _val); \ + ((_info) |= ((_val) << HTT_TX_COMPL_IND_TID_S)); \ + } while (0) +#define HTT_TX_COMPL_IND_TID_GET(_info) \ + (((_info) & HTT_TX_COMPL_IND_TID_M) >> HTT_TX_COMPL_IND_TID_S) +#define HTT_TX_COMPL_IND_TID_INV_SET(_info, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_TX_COMPL_IND_TID_INV, _val); \ + ((_info) |= ((_val) << HTT_TX_COMPL_IND_TID_INV_S)); \ + } while (0) +#define HTT_TX_COMPL_IND_TID_INV_GET(_info) \ + (((_info) & HTT_TX_COMPL_IND_TID_INV_M) >> \ + HTT_TX_COMPL_IND_TID_INV_S) +#define HTT_TX_COMPL_IND_APPEND_SET(_info, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_TX_COMPL_IND_APPEND, _val); \ + ((_info) |= ((_val) << HTT_TX_COMPL_IND_APPEND_S)); \ + } while (0) +#define HTT_TX_COMPL_IND_APPEND_GET(_info) \ + (((_info) & HTT_TX_COMPL_IND_APPEND_M) >> HTT_TX_COMPL_IND_APPEND_S) + +#define HTT_TX_COMPL_CTXT_SZ sizeof(A_UINT16) +#define HTT_TX_COMPL_CTXT_NUM(_bytes) ((_bytes) >> 1) + +#define HTT_TX_COMPL_INV_MSDU_ID 0xffff + +#define HTT_TX_COMPL_IND_STAT_OK 0 +#define HTT_TX_COMPL_IND_STAT_DISCARD 1 +#define HTT_TX_COMPL_IND_STAT_NO_ACK 2 +#define HTT_TX_COMPL_IND_STAT_POSTPONE 3 +/* + * The PEER_DEL tx completion status is used for HL cases + * where the peer the frame is for has been deleted. + * The host has already discarded its copy of the frame, but + * it still needs the tx completion to restore its credit. + */ +#define HTT_TX_COMPL_IND_STAT_PEER_DEL 4 + + +#define HTT_TX_COMPL_IND_APPEND_SET_MORE_RETRY(f) ((f) |= 0x1) +#define HTT_TX_COMPL_IND_APPEND_CLR_MORE_RETRY(f) ((f) &= (~0x1)) + +PREPACK struct htt_tx_compl_ind_base { + A_UINT32 hdr; + A_UINT16 payload[1 /*or more */]; +} POSTPACK; + +PREPACK struct htt_tx_compl_ind_append_retries { + A_UINT16 msdu_id; + A_UINT8 tx_retries; + A_UINT8 flag;/* Bit 0, 1: another append_retries struct is appended + 0: this is the last append_retries struct */ +} POSTPACK; + +/** + * @brief target -> host rate-control update indication message + * + * @details + * The following diagram shows the format of the RC Update message + * sent from the target to the host, while processing the tx-completion + * of a transmitted PPDU. + * + * |31 24|23 16|15 8|7 0| + * |-------------------------------------------------------------| + * | peer ID | vdev ID | msg_type | + * |-------------------------------------------------------------| + * | MAC addr 3 | MAC addr 2 | MAC addr 1 | MAC addr 0 | + * |-------------------------------------------------------------| + * | reserved | num elems | MAC addr 5 | MAC addr 4 | + * |-------------------------------------------------------------| + * | : | + * : HTT_RC_TX_DONE_PARAMS (DWORD-aligned) : + * | : | + * |-------------------------------------------------------------| + * | : | + * : HTT_RC_TX_DONE_PARAMS (DWORD-aligned) : + * | : | + * |-------------------------------------------------------------| + * : : + * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * + */ + +typedef struct { + A_UINT32 rate_code; /* rate code, bw, chain mask sgi */ + A_UINT32 rate_code_flags; + A_UINT32 flags; /* Encodes information such as excessive + retransmission, aggregate, some info + from .11 frame control, + STBC, LDPC, (SGI and Tx Chain Mask + are encoded in ptx_rc->flags field), + AMPDU truncation (BT/time based etc.), + RTS/CTS attempt */ + + A_UINT32 num_enqued;/* # of MPDUs (for non-AMPDU 1) for this rate */ + A_UINT32 num_retries;/* Total # of transmission attempt for this rate */ + A_UINT32 num_failed;/* # of failed MPDUs in A-MPDU, 0 otherwise */ + A_UINT32 ack_rssi;/* ACK RSSI: b'7..b'0 avg RSSI across all chain */ + A_UINT32 time_stamp; /* ACK timestamp (helps determine age) */ + A_UINT32 is_probe; /* Valid if probing. Else, 0 */ +} HTT_RC_TX_DONE_PARAMS; + +#define HTT_RC_UPDATE_CTXT_SZ (sizeof(HTT_RC_TX_DONE_PARAMS))/* bytes */ +#define HTT_RC_UPDATE_HDR_SZ (12) /* bytes */ + +#define HTT_RC_UPDATE_MAC_ADDR_OFFSET (4) /* bytes */ +#define HTT_RC_UPDATE_MAC_ADDR_LENGTH IEEE80211_ADDR_LEN /* bytes */ + +#define HTT_RC_UPDATE_VDEVID_S 8 +#define HTT_RC_UPDATE_VDEVID_M 0xff00 +#define HTT_RC_UPDATE_PEERID_S 16 +#define HTT_RC_UPDATE_PEERID_M 0xffff0000 + +#define HTT_RC_UPDATE_NUM_ELEMS_S 16 +#define HTT_RC_UPDATE_NUM_ELEMS_M 0x00ff0000 + +#define HTT_RC_UPDATE_VDEVID_SET(_info, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RC_UPDATE_VDEVID, _val); \ + ((_info) |= ((_val) << HTT_RC_UPDATE_VDEVID_S)); \ + } while (0) + +#define HTT_RC_UPDATE_VDEVID_GET(_info) \ + (((_info) & HTT_RC_UPDATE_VDEVID_M) >> HTT_RC_UPDATE_VDEVID_S) + +#define HTT_RC_UPDATE_PEERID_SET(_info, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RC_UPDATE_PEERID, _val); \ + ((_info) |= ((_val) << HTT_RC_UPDATE_PEERID_S)); \ + } while (0) + +#define HTT_RC_UPDATE_PEERID_GET(_info) \ + (((_info) & HTT_RC_UPDATE_PEERID_M) >> HTT_RC_UPDATE_PEERID_S) + +#define HTT_RC_UPDATE_NUM_ELEMS_SET(_info, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RC_UPDATE_NUM_ELEMS, _val); \ + ((_info) |= ((_val) << HTT_RC_UPDATE_NUM_ELEMS_S)); \ + } while (0) + +#define HTT_RC_UPDATE_NUM_ELEMS_GET(_info) \ + (((_info) & HTT_RC_UPDATE_NUM_ELEMS_M) >> HTT_RC_UPDATE_NUM_ELEMS_S) + +/** + * @brief target -> host rx fragment indication message definition + * + * @details + * The following field definitions describe the format of the rx fragment + * indication message sent from the target to the host. + * The rx fragment indication message shares the format of the + * rx indication message, but not all fields from the rx indication message + * are relevant to the rx fragment indication message. + * + * + * |31 24|23 18|17|16|15|14|13|12|11|10|9|8|7|6|5|4 0| + * |-----------+-------------------+---------------------+-------------| + * | peer ID | |FV| ext TID | msg type | + * |-------------------------------------------------------------------| + * | | flush | flush | + * | | end | start | + * | | seq num | seq num | + * |-------------------------------------------------------------------| + * | reserved | FW rx desc bytes | + * |-------------------------------------------------------------------| + * | | FW MSDU Rx | + * | | desc B0 | + * |-------------------------------------------------------------------| + * Header fields: + * - MSG_TYPE + * Bits 7:0 + * Purpose: identifies this as an rx fragment indication message + * Value: 0xa + * - EXT_TID + * Bits 12:8 + * Purpose: identify the traffic ID of the rx data, including + * special "extended" TID values for multicast, broadcast, and + * non-QoS data frames + * Value: 0-15 for regular TIDs, or >= 16 for bcast/mcast/non-QoS + * - FLUSH_VALID (FV) + * Bit 13 + * Purpose: indicate whether the flush IE (start/end sequence numbers) + * is valid + * Value: + * 1 -> flush IE is valid and needs to be processed + * 0 -> flush IE is not valid and should be ignored + * - PEER_ID + * Bits 31:16 + * Purpose: Identify, by ID, which peer sent the rx data + * Value: ID of the peer who sent the rx data + * - FLUSH_SEQ_NUM_START + * Bits 5:0 + * Purpose: Indicate the start of a series of MPDUs to flush + * Not all MPDUs within this series are necessarily valid - the host + * must check each sequence number within this range to see if the + * corresponding MPDU is actually present. + * This field is only valid if the FV bit is set. + * Value: + * The sequence number for the first MPDUs to check to flush. + * The sequence number is masked by 0x3f. + * - FLUSH_SEQ_NUM_END + * Bits 11:6 + * Purpose: Indicate the end of a series of MPDUs to flush + * Value: + * The sequence number one larger than the sequence number of the + * last MPDU to check to flush. + * The sequence number is masked by 0x3f. + * Not all MPDUs within this series are necessarily valid - the host + * must check each sequence number within this range to see if the + * corresponding MPDU is actually present. + * This field is only valid if the FV bit is set. + * Rx descriptor fields: + * - FW_RX_DESC_BYTES + * Bits 15:0 + * Purpose: Indicate how many bytes in the Rx indication are used for + * FW Rx descriptors + * Value: 1 + */ +#define HTT_RX_FRAG_IND_HDR_PREFIX_SIZE32 2 + +#define HTT_RX_FRAG_IND_FW_DESC_BYTE_OFFSET 12 + +#define HTT_RX_FRAG_IND_EXT_TID_SET HTT_RX_IND_EXT_TID_SET +#define HTT_RX_FRAG_IND_EXT_TID_GET HTT_RX_IND_EXT_TID_GET + +#define HTT_RX_FRAG_IND_PEER_ID_SET HTT_RX_IND_PEER_ID_SET +#define HTT_RX_FRAG_IND_PEER_ID_GET HTT_RX_IND_PEER_ID_GET + +#define HTT_RX_FRAG_IND_FLUSH_VALID_SET HTT_RX_IND_FLUSH_VALID_SET +#define HTT_RX_FRAG_IND_FLUSH_VALID_GET HTT_RX_IND_FLUSH_VALID_GET + +#define HTT_RX_FRAG_IND_FLUSH_SEQ_NUM_START_SET \ + HTT_RX_IND_FLUSH_SEQ_NUM_START_SET +#define HTT_RX_FRAG_IND_FLUSH_SEQ_NUM_START_GET \ + HTT_RX_IND_FLUSH_SEQ_NUM_START_GET + +#define HTT_RX_FRAG_IND_FLUSH_SEQ_NUM_END_SET \ + HTT_RX_IND_FLUSH_SEQ_NUM_END_SET +#define HTT_RX_FRAG_IND_FLUSH_SEQ_NUM_END_GET \ + HTT_RX_IND_FLUSH_SEQ_NUM_END_GET + +#define HTT_RX_FRAG_IND_FW_RX_DESC_BYTES_GET HTT_RX_IND_FW_RX_DESC_BYTES_GET + +#define HTT_RX_FRAG_IND_BYTES \ + (4 /* msg hdr */ + \ + 4 /* flush spec */ + \ + 4 /* (unused) FW rx desc bytes spec */ + \ + 4 /* FW rx desc */) + +/** + * @brief target -> host test message definition + * + * @details + * The following field definitions describe the format of the test + * message sent from the target to the host. + * The message consists of a 4-octet header, followed by a variable + * number of 32-bit integer values, followed by a variable number + * of 8-bit character values. + * + * |31 16|15 8|7 0| + * |-----------------------------------------------------------| + * | num chars | num ints | msg type | + * |-----------------------------------------------------------| + * | int 0 | + * |-----------------------------------------------------------| + * | int 1 | + * |-----------------------------------------------------------| + * | ... | + * |-----------------------------------------------------------| + * | char 3 | char 2 | char 1 | char 0 | + * |-----------------------------------------------------------| + * | | | ... | char 4 | + * |-----------------------------------------------------------| + * - MSG_TYPE + * Bits 7:0 + * Purpose: identifies this as a test message + * Value: HTT_MSG_TYPE_TEST + * - NUM_INTS + * Bits 15:8 + * Purpose: indicate how many 32-bit integers follow the message header + * - NUM_CHARS + * Bits 31:16 + * Purpose: indicate how many 8-bit charaters follow the series of integers + */ +#define HTT_RX_TEST_NUM_INTS_M 0xff00 +#define HTT_RX_TEST_NUM_INTS_S 8 +#define HTT_RX_TEST_NUM_CHARS_M 0xffff0000 +#define HTT_RX_TEST_NUM_CHARS_S 16 + +#define HTT_RX_TEST_NUM_INTS_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_TEST_NUM_INTS, value); \ + (word) |= (value) << HTT_RX_TEST_NUM_INTS_S; \ + } while (0) +#define HTT_RX_TEST_NUM_INTS_GET(word) \ + (((word) & HTT_RX_TEST_NUM_INTS_M) >> HTT_RX_TEST_NUM_INTS_S) + +#define HTT_RX_TEST_NUM_CHARS_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_TEST_NUM_CHARS, value); \ + (word) |= (value) << HTT_RX_TEST_NUM_CHARS_S; \ + } while (0) +#define HTT_RX_TEST_NUM_CHARS_GET(word) \ + (((word) & HTT_RX_TEST_NUM_CHARS_M) >> HTT_RX_TEST_NUM_CHARS_S) + +/** + * @brief target -> host packet log message + * + * @details + * The following field definitions describe the format of the packet log + * message sent from the target to the host. + * The message consists of a 4-octet header,followed by a variable number + * of 32-bit character values. + * + * |31 24|23 16|15 8|7 0| + * |-----------------------------------------------------------| + * | | | | msg type | + * |-----------------------------------------------------------| + * | payload | + * |-----------------------------------------------------------| + * - MSG_TYPE + * Bits 7:0 + * Purpose: identifies this as a test message + * Value: HTT_MSG_TYPE_PACKETLOG + */ +PREPACK struct htt_pktlog_msg { + A_UINT32 header; + A_UINT32 payload[1 /* or more */]; +} POSTPACK; + + +/* + * Rx reorder statistics + * NB: all the fields must be defined in 4 octets size. + */ +struct rx_reorder_stats { + /* Non QoS MPDUs received */ + A_UINT32 deliver_non_qos; + /* MPDUs received in-order */ + A_UINT32 deliver_in_order; + /* Flush due to reorder timer expired */ + A_UINT32 deliver_flush_timeout; + /* Flush due to move out of window */ + A_UINT32 deliver_flush_oow; + /* Flush due to DELBA */ + A_UINT32 deliver_flush_delba; + /* MPDUs dropped due to FCS error */ + A_UINT32 fcs_error; + /* MPDUs dropped due to monitor mode non-data packet */ + A_UINT32 mgmt_ctrl; + /* Unicast-data MPDUs dropped due to invalid peer */ + A_UINT32 invalid_peer; + /* MPDUs dropped due to duplication (non aggregation) */ + A_UINT32 dup_non_aggr; + /* MPDUs dropped due to processed before */ + A_UINT32 dup_past; + /* MPDUs dropped due to duplicate in reorder queue */ + A_UINT32 dup_in_reorder; + /* Reorder timeout happened */ + A_UINT32 reorder_timeout; + /* invalid bar ssn */ + A_UINT32 invalid_bar_ssn; + /* reorder reset due to bar ssn */ + A_UINT32 ssn_reset; + /* Flush due to delete peer */ + A_UINT32 deliver_flush_delpeer; + /* Flush due to offload */ + A_UINT32 deliver_flush_offload; + /* Flush due to out of buffer */ + A_UINT32 deliver_flush_oob; + /* MPDUs dropped due to PN check fail */ + A_UINT32 pn_fail; + /* MPDUs dropped due to unable to allocate memory */ + A_UINT32 store_fail; + /* Number of times the tid pool alloc succeeded */ + A_UINT32 tid_pool_alloc_succ; + /* Number of times the MPDU pool alloc succeeded */ + A_UINT32 mpdu_pool_alloc_succ; + /* Number of times the MSDU pool alloc succeeded */ + A_UINT32 msdu_pool_alloc_succ; + /* Number of times the tid pool alloc failed */ + A_UINT32 tid_pool_alloc_fail; + /* Number of times the MPDU pool alloc failed */ + A_UINT32 mpdu_pool_alloc_fail; + /* Number of times the MSDU pool alloc failed */ + A_UINT32 msdu_pool_alloc_fail; + /* Number of times the tid pool freed */ + A_UINT32 tid_pool_free; + /* Number of times the MPDU pool freed */ + A_UINT32 mpdu_pool_free; + /* Number of times the MSDU pool freed */ + A_UINT32 msdu_pool_free; + /* number of MSDUs undelivered to HTT and queued + * to Data Rx MSDU free list */ + A_UINT32 msdu_queued; + /* Number of MSDUs released from Data Rx MSDU list to MAC ring */ + A_UINT32 msdu_recycled; + /* Number of MPDUs with invalid peer but A2 found in AST */ + A_UINT32 invalid_peer_a2_in_ast; + /* Number of MPDUs with invalid peer but A3 found in AST */ + A_UINT32 invalid_peer_a3_in_ast; + /* Number of MPDUs with invalid peer, Broadcast or Multicast frame */ + A_UINT32 invalid_peer_bmc_mpdus; + /* Number of MSDUs with err attention word */ + A_UINT32 rxdesc_err_att; + /* Number of MSDUs with flag of peer_idx_invalid */ + A_UINT32 rxdesc_err_peer_idx_inv; + /* Number of MSDUs with flag of peer_idx_timeout */ + A_UINT32 rxdesc_err_peer_idx_to; + /* Number of MSDUs with flag of overflow */ + A_UINT32 rxdesc_err_ov; + /* Number of MSDUs with flag of msdu_length_err */ + A_UINT32 rxdesc_err_msdu_len; + /* Number of MSDUs with flag of mpdu_length_err */ + A_UINT32 rxdesc_err_mpdu_len; + /* Number of MSDUs with flag of tkip_mic_err */ + A_UINT32 rxdesc_err_tkip_mic; + /* Number of MSDUs with flag of decrypt_err */ + A_UINT32 rxdesc_err_decrypt; + /* Number of MSDUs with flag of fcs_err */ + A_UINT32 rxdesc_err_fcs; + /* Number of Unicast (bc_mc bit is not set in attention word) + * frames with invalid peer handler + */ + A_UINT32 rxdesc_uc_msdus_inv_peer; + /* Number of unicast frame directly (direct bit is set in attention word) + * to DUT with invalid peer handler + */ + A_UINT32 rxdesc_direct_msdus_inv_peer; + /* Number of Broadcast/Multicast (bc_mc bit set in attention word) + * frames with invalid peer handler + */ + A_UINT32 rxdesc_bmc_msdus_inv_peer; + /* Number of MSDUs dropped due to no first MSDU flag */ + A_UINT32 rxdesc_no_1st_msdu; + /* Number of MSDUs droped due to ring overflow */ + A_UINT32 msdu_drop_ring_ov; + /* Number of MSDUs dropped due to FC mismatch */ + A_UINT32 msdu_drop_fc_mismatch; + /* Number of MSDUs dropped due to mgt frame in Remote ring */ + A_UINT32 msdu_drop_mgmt_remote_ring; + /* Number of MSDUs dropped due to errors not reported in attention word */ + A_UINT32 msdu_drop_misc; + /* Number of MSDUs go to offload before reorder */ + A_UINT32 offload_msdu_wal; + /* Number of data frame dropped by offload after reorder */ + A_UINT32 offload_msdu_reorder; + /* Number of MPDUs with sequence number in the past and within + the BA window */ + A_UINT32 dup_past_within_window; + /* Number of MPDUs with sequence number in the past and + * outside the BA window */ + A_UINT32 dup_past_outside_window; + /* Number of MSDUs with decrypt/MIC error */ + A_UINT32 rxdesc_err_decrypt_mic; + /* Number of data MSDUs received on both local and remote rings */ + A_UINT32 data_msdus_on_both_rings; +}; + + +/* + * Rx Remote buffer statistics + * NB: all the fields must be defined in 4 octets size. + */ +struct rx_remote_buffer_mgmt_stats { + /* Total number of MSDUs reaped for Rx processing */ + A_UINT32 remote_reaped; + /* MSDUs recycled within firmware */ + A_UINT32 remote_recycled; + /* MSDUs stored by Data Rx */ + A_UINT32 data_rx_msdus_stored; + /* Number of HTT indications from WAL Rx MSDU */ + A_UINT32 wal_rx_ind; + /* Number of unconsumed HTT indications from WAL Rx MSDU */ + A_UINT32 wal_rx_ind_unconsumed; + /* Number of HTT indications from Data Rx MSDU */ + A_UINT32 data_rx_ind; + /* Number of unconsumed HTT indications from Data Rx MSDU */ + A_UINT32 data_rx_ind_unconsumed; + /* Number of HTT indications from ATHBUF */ + A_UINT32 athbuf_rx_ind; + /* Number of remote buffers requested for refill */ + A_UINT32 refill_buf_req; + /* Number of remote buffers filled by the host */ + A_UINT32 refill_buf_rsp; + /* Number of times MAC hw_index = f/w write_index */ + A_INT32 mac_no_bufs; + /* Number of times f/w write_index = f/w read_index for MAC Rx ring */ + A_INT32 fw_indices_equal; + /* Number of times f/w finds no buffers to post */ + A_INT32 host_no_bufs; +}; + +/* + * TXBF MU/SU packets and NDPA statistics + * NB: all the fields must be defined in 4 octets size. + */ +struct rx_txbf_musu_ndpa_pkts_stats { + /* number of TXBF MU packets received */ + A_UINT32 number_mu_pkts; + /* number of TXBF SU packets received */ + A_UINT32 number_su_pkts; + /* number of TXBF directed NDPA */ + A_UINT32 txbf_directed_ndpa_count; + /* number of TXBF retried NDPA */ + A_UINT32 txbf_ndpa_retry_count; + /* total number of TXBF NDPA */ + A_UINT32 txbf_total_ndpa_count; + /* must be set to 0x0 */ + A_UINT32 reserved[3]; +}; + +/* + * htt_dbg_stats_status - + * present - The requested stats have been delivered in full. + * This indicates that either the stats information was contained + * in its entirety within this message, or else this message + * completes the delivery of the requested stats info that was + * partially delivered through earlier STATS_CONF messages. + * partial - The requested stats have been delivered in part. + * One or more subsequent STATS_CONF messages with the same + * cookie value will be sent to deliver the remainder of the + * information. + * error - The requested stats could not be delivered, for example due + * to a shortage of memory to construct a message holding the + * requested stats. + * invalid - The requested stat type is either not recognized, or the + * target is configured to not gather the stats type in question. + * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * series_done - This special value indicates that no further stats info + * elements are present within a series of stats info elems + * (within a stats upload confirmation message). + */ +enum htt_dbg_stats_status { + HTT_DBG_STATS_STATUS_PRESENT = 0, + HTT_DBG_STATS_STATUS_PARTIAL = 1, + HTT_DBG_STATS_STATUS_ERROR = 2, + HTT_DBG_STATS_STATUS_INVALID = 3, + + + HTT_DBG_STATS_STATUS_SERIES_DONE = 7 +}; + +/** + * @brief target -> host statistics upload + * + * @details + * The following field definitions describe the format of the HTT target + * to host stats upload confirmation message. + * The message contains a cookie echoed from the HTT host->target stats + * upload request, which identifies which request the confirmation is + * for, and a series of tag-length-value stats information elements. + * The tag-length header for each stats info element also includes a + * status field, to indicate whether the request for the stat type in + * question was fully met, partially met, unable to be met, or invalid + * (if the stat type in question is disabled in the target). + * A special value of all 1's in this status field is used to indicate + * the end of the series of stats info elements. + * + * + * |31 16|15 8|7 5|4 0| + * |------------------------------------------------------------| + * | reserved | msg type | + * |------------------------------------------------------------| + * | cookie LSBs | + * |------------------------------------------------------------| + * | cookie MSBs | + * |------------------------------------------------------------| + * | stats entry length | reserved | S |stat type| + * |------------------------------------------------------------| + * | | + * | type-specific stats info | + * | | + * |------------------------------------------------------------| + * | stats entry length | reserved | S |stat type| + * |------------------------------------------------------------| + * | | + * | type-specific stats info | + * | | + * |------------------------------------------------------------| + * | n/a | reserved | 111 | n/a | + * |------------------------------------------------------------| + * Header fields: + * - MSG_TYPE + * Bits 7:0 + * Purpose: identifies this is a statistics upload confirmation message + * Value: 0x9 + * - COOKIE_LSBS + * Bits 31:0 + * Purpose: Provide a mechanism to match a target->host stats confirmation + * message with its preceding host->target stats request message. + * Value: LSBs of the opaque cookie specified by the host-side requestor + * - COOKIE_MSBS + * Bits 31:0 + * Purpose: Provide a mechanism to match a target->host stats confirmation + * message with its preceding host->target stats request message. + * Value: MSBs of the opaque cookie specified by the host-side requestor + * + * Stats Information Element tag-length header fields: + * - STAT_TYPE + * Bits 4:0 + * Purpose: identifies the type of statistics info held in the + * following information element + * Value: htt_dbg_stats_type + * - STATUS + * Bits 7:5 + * Purpose: indicate whether the requested stats are present + * Value: htt_dbg_stats_status, including a special value (0x7) to mark + * the completion of the stats entry series + * - LENGTH + * Bits 31:16 + * Purpose: indicate the stats information size + * Value: This field specifies the number of bytes of stats information + * that follows the element tag-length header. + * It is expected but not required that this length is a multiple of + * 4 bytes. Even if the length is not an integer multiple of 4, the + * subsequent stats entry header will begin on a 4-byte aligned + * boundary. + */ +#define HTT_T2H_STATS_COOKIE_SIZE 8 + +#define HTT_T2H_STATS_CONF_TAIL_SIZE 4 + +#define HTT_T2H_STATS_CONF_HDR_SIZE 4 + +#define HTT_T2H_STATS_CONF_TLV_HDR_SIZE 4 + +#define HTT_T2H_STATS_CONF_TLV_TYPE_M 0x0000001f +#define HTT_T2H_STATS_CONF_TLV_TYPE_S 0 +#define HTT_T2H_STATS_CONF_TLV_STATUS_M 0x000000e0 +#define HTT_T2H_STATS_CONF_TLV_STATUS_S 5 +#define HTT_T2H_STATS_CONF_TLV_LENGTH_M 0xffff0000 +#define HTT_T2H_STATS_CONF_TLV_LENGTH_S 16 + +#define HTT_T2H_STATS_CONF_TLV_TYPE_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_T2H_STATS_CONF_TLV_TYPE, value); \ + (word) |= (value) << HTT_T2H_STATS_CONF_TLV_TYPE_S; \ + } while (0) +#define HTT_T2H_STATS_CONF_TLV_TYPE_GET(word) \ + (((word) & HTT_T2H_STATS_CONF_TLV_TYPE_M) >> \ + HTT_T2H_STATS_CONF_TLV_TYPE_S) + +#define HTT_T2H_STATS_CONF_TLV_STATUS_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_T2H_STATS_CONF_TLV_STATUS, value); \ + (word) |= (value) << HTT_T2H_STATS_CONF_TLV_STATUS_S; \ + } while (0) +#define HTT_T2H_STATS_CONF_TLV_STATUS_GET(word) \ + (((word) & HTT_T2H_STATS_CONF_TLV_STATUS_M) >> \ + HTT_T2H_STATS_CONF_TLV_STATUS_S) + +#define HTT_T2H_STATS_CONF_TLV_LENGTH_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_T2H_STATS_CONF_TLV_LENGTH, value); \ + (word) |= (value) << HTT_T2H_STATS_CONF_TLV_LENGTH_S; \ + } while (0) +#define HTT_T2H_STATS_CONF_TLV_LENGTH_GET(word) \ + (((word) & HTT_T2H_STATS_CONF_TLV_LENGTH_M) >> \ + HTT_T2H_STATS_CONF_TLV_LENGTH_S) + +#define HL_HTT_FW_RX_DESC_RSVD_SIZE 18 +#define HTT_MAX_AGGR 64 +#define HTT_HL_MAX_AGGR 18 + +/** + * @brief host -> target FRAG DESCRIPTOR/MSDU_EXT DESC bank + * + * @details + * The following field definitions describe the format of the HTT host + * to target frag_desc/msdu_ext bank configuration message. + * The message contains the based address and the min and max id of the + * MSDU_EXT/FRAG_DESC that will be used by the HTT to map MSDU DESC and + * MSDU_EXT/FRAG_DESC. + * HTT will use id in HTT descriptor instead sending the frag_desc_ptr. + * In peregrine the firmware will use fragment_desc_ptr but in WIFI2.0 + * the hardware does the mapping/translation. + * + * Total banks that can be configured is configured to 16. + * + * This should be called before any TX has be initiated by the HTT + * + * |31 16|15 8|7 5|4 0| + * |------------------------------------------------------------| + * | DESC_SIZE | NUM_BANKS | RES |SWP|pdev| msg type | + * |------------------------------------------------------------| + * | BANK0_BASE_ADDRESS (bits 31:0) | + #if HTT_PADDR64 + * | BANK0_BASE_ADDRESS (bits 63:32) | + #endif + * |------------------------------------------------------------| + * | ... | + * |------------------------------------------------------------| + * | BANK15_BASE_ADDRESS (bits 31:0) | + #if HTT_PADDR64 + * | BANK15_BASE_ADDRESS (bits 63:32) | + #endif + * |------------------------------------------------------------| + * | BANK0_MAX_ID | BANK0_MIN_ID | + * |------------------------------------------------------------| + * | ... | + * |------------------------------------------------------------| + * | BANK15_MAX_ID | BANK15_MIN_ID | + * |------------------------------------------------------------| + * Header fields: + * - MSG_TYPE + * Bits 7:0 + * Value: 0x6 + * for systems with 64-bit format for bus addresses: + * - BANKx_BASE_ADDRESS_LO + * Bits 31:0 + * Purpose: Provide a mechanism to specify the base address of the + * MSDU_EXT bank physical/bus address. + * Value: lower 4 bytes of MSDU_EXT bank physical / bus address + * - BANKx_BASE_ADDRESS_HI + * Bits 31:0 + * Purpose: Provide a mechanism to specify the base address of the + * MSDU_EXT bank physical/bus address. + * Value: higher 4 bytes of MSDU_EXT bank physical / bus address + * for systems with 32-bit format for bus addresses: + * - BANKx_BASE_ADDRESS + * Bits 31:0 + * Purpose: Provide a mechanism to specify the base address of the + * MSDU_EXT bank physical/bus address. + * Value: MSDU_EXT bank physical / bus address + * - BANKx_MIN_ID + * Bits 15:0 + * Purpose: Provide a mechanism to specify the min index that needs to + * mapped. + * - BANKx_MAX_ID + * Bits 31:16 + * Purpose: Provide a mechanism to specify the max index that needs to + * mapped. + * + */ + +/** @todo Compress the fields to fit MAX HTT Message size, until then + * configure to a safe value. + * @note MAX supported banks is 16. + */ +#define HTT_TX_MSDU_EXT_BANK_MAX 4 + +#define HTT_H2T_FRAG_DESC_BANK_PDEVID_M 0x300 +#define HTT_H2T_FRAG_DESC_BANK_PDEVID_S 8 + +#define HTT_H2T_FRAG_DESC_BANK_SWAP_M 0x400 +#define HTT_H2T_FRAG_DESC_BANK_SWAP_S 10 + +#define HTT_H2T_FRAG_DESC_BANK_NUM_BANKS_M 0xff0000 +#define HTT_H2T_FRAG_DESC_BANK_NUM_BANKS_S 16 + +#define HTT_H2T_FRAG_DESC_BANK_DESC_SIZE_M 0xff000000 +#define HTT_H2T_FRAG_DESC_BANK_DESC_SIZE_S 24 + +#define HTT_H2T_FRAG_DESC_BANK_MIN_IDX_M 0xffff +#define HTT_H2T_FRAG_DESC_BANK_MIN_IDX_S 0 + +#define HTT_H2T_FRAG_DESC_BANK_MAX_IDX_M 0xffff0000 +#define HTT_H2T_FRAG_DESC_BANK_MAX_IDX_S 16 + +#define HTT_H2T_FRAG_DESC_BANK_PDEVID_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_H2T_FRAG_DESC_BANK_PDEVID, value); \ + (word) |= ((value) << HTT_H2T_FRAG_DESC_BANK_PDEVID_S); \ + } while (0) +#define HTT_H2T_FRAG_DESC_BANK_PDEVID_GET(word) \ + (((word) & HTT_H2T_FRAG_DESC_BANK_PDEVID_M) >> \ + HTT_H2T_FRAG_DESC_BANK_PDEVID_S) + +#define HTT_H2T_FRAG_DESC_BANK_SWAP_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_H2T_FRAG_DESC_BANK_SWAP, value);\ + (word) |= ((value) << HTT_H2T_FRAG_DESC_BANK_SWAP_S);\ + } while (0) +#define HTT_H2T_FRAG_DESC_BANK_SWAP_GET(word) \ + (((word) & HTT_H2T_FRAG_DESC_BANK_SWAP_M) >> \ + HTT_H2T_FRAG_DESC_BANK_SWAP_S) + +#define HTT_H2T_FRAG_DESC_BANK_NUM_BANKS_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_H2T_FRAG_DESC_BANK_NUM_BANKS, value); \ + (word) |= ((value) << HTT_H2T_FRAG_DESC_BANK_NUM_BANKS_S); \ + } while (0) +#define HTT_H2T_FRAG_DESC_BANK_NUM_BANKS_GET(word) \ + (((word) & HTT_H2T_FRAG_DESC_BANK_NUM_BANKS_M) >> \ + HTT_H2T_FRAG_DESC_BANK_NUM_BANKS_S) + +#define HTT_H2T_FRAG_DESC_BANK_DESC_SIZE_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_H2T_FRAG_DESC_BANK_DESC_SIZE, value); \ + (word) |= ((value) << HTT_H2T_FRAG_DESC_BANK_DESC_SIZE_S); \ + } while (0) +#define HTT_H2T_FRAG_DESC_BANK_DESC_SIZE_GET(word) \ + (((word) & HTT_H2T_FRAG_DESC_BANK_DESC_SIZE_M) >> \ + HTT_H2T_FRAG_DESC_BANK_DESC_SIZE_S) + +#define HTT_H2T_FRAG_DESC_BANK_MIN_IDX_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_H2T_FRAG_DESC_BANK_MIN_IDX, value); \ + (word) |= ((value) << HTT_H2T_FRAG_DESC_BANK_MIN_IDX_S); \ + } while (0) +#define HTT_H2T_FRAG_DESC_BANK_MIN_IDX_GET(word) \ + (((word) & HTT_H2T_FRAG_DESC_BANK_MIN_IDX_M) >> \ + HTT_H2T_FRAG_DESC_BANK_MIN_IDX_S) + +#define HTT_H2T_FRAG_DESC_BANK_MAX_IDX_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_H2T_FRAG_DESC_BANK_MAX_IDX, value); \ + (word) |= ((value) << HTT_H2T_FRAG_DESC_BANK_MAX_IDX_S); \ + } while (0) +#define HTT_H2T_FRAG_DESC_BANK_MAX_IDX_GET(word) \ + (((word) & HTT_H2T_FRAG_DESC_BANK_MAX_IDX_M) >> \ + HTT_H2T_FRAG_DESC_BANK_MAX_IDX_S) + + +/* + * TEMPLATE_HTT_TX_FRAG_DESC_BANK_CFG_T: + * This macro defines a htt_tx_frag_descXXX_bank_cfg_t in which any physical + * addresses are stored in a XXX-bit field. + * This macro is used to define both htt_tx_frag_desc32_bank_cfg_t and + * htt_tx_frag_desc64_bank_cfg_t structs. + */ +#define TEMPLATE_HTT_TX_FRAG_DESC_BANK_CFG_T( \ + _paddr_bits_, \ + _paddr__bank_base_address_) \ + PREPACK struct htt_tx_frag_desc ## _paddr_bits_ ## _bank_cfg_t { \ + /** word 0 \ + * msg_type: 8, \ + * pdev_id: 2, \ + * swap: 1, \ + * reserved0: 5, \ + * num_banks: 8, \ + * desc_size: 8; \ + */ \ + A_UINT32 word0; \ + /* \ + * If bank_base_address is 64 bits, the upper / lower + * halves are stored \ + * in little-endian order (bytes 0-3 in the first A_UINT32, + * bytes 4-7 in the second A_UINT32). \ + */ \ + _paddr__bank_base_address_[HTT_TX_MSDU_EXT_BANK_MAX]; \ + A_UINT32 bank_info[HTT_TX_MSDU_EXT_BANK_MAX]; \ + } POSTPACK +/* define htt_tx_frag_desc32_bank_cfg_t */ +TEMPLATE_HTT_TX_FRAG_DESC_BANK_CFG_T(32, HTT_VAR_PADDR32(bank_base_address)); +/* define htt_tx_frag_desc64_bank_cfg_t */ +TEMPLATE_HTT_TX_FRAG_DESC_BANK_CFG_T(64, HTT_VAR_PADDR64_LE(bank_base_address)); +/* + * Make htt_tx_frag_desc_bank_cfg_t be an alias for either + * htt_tx_frag_desc32_bank_cfg_t or htt_tx_frag_desc64_bank_cfg_t + */ +#if HTT_PADDR64 +#define htt_tx_frag_desc_bank_cfg_t htt_tx_frag_desc64_bank_cfg_t +#else +#define htt_tx_frag_desc_bank_cfg_t htt_tx_frag_desc32_bank_cfg_t +#endif + + +/** + * @brief target -> host HTT TX Credit total count update message definition + * + *|31 16|15|14 9| 8 |7 0 | + *|---------------------+--+----------+-------+----------| + *|cur htt credit delta | Q| reserved | sign | msg type | + *|------------------------------------------------------| + * + * Header fields: + * - MSG_TYPE + * Bits 7:0 + * Purpose: identifies this as a htt tx credit delta update message + * Value: 0xe + * - SIGN + * Bits 8 + * identifies whether credit delta is positive or negative + * Value: + * - 0x0: credit delta is positive, rebalance in some buffers + * - 0x1: credit delta is negative, rebalance out some buffers + * - reserved + * Bits 14:9 + * Value: 0x0 + * - TXQ_GRP + * Bit 15 + * Purpose: indicates whether any tx queue group information elements + * are appended to the tx credit update message + * Value: 0 -> no tx queue group information element is present + * 1 -> a tx queue group information element immediately follows + * - DELTA_COUNT + * Bits 31:16 + * Purpose: Specify current htt credit delta absolute count + */ + +#define HTT_TX_CREDIT_SIGN_BIT_M 0x00000100 +#define HTT_TX_CREDIT_SIGN_BIT_S 8 +#define HTT_TX_CREDIT_TXQ_GRP_M 0x00008000 +#define HTT_TX_CREDIT_TXQ_GRP_S 15 +#define HTT_TX_CREDIT_DELTA_ABS_M 0xffff0000 +#define HTT_TX_CREDIT_DELTA_ABS_S 16 + + +#define HTT_TX_CREDIT_SIGN_BIT_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_TX_CREDIT_SIGN_BIT, value); \ + (word) |= (value) << HTT_TX_CREDIT_SIGN_BIT_S; \ + } while (0) + +#define HTT_TX_CREDIT_SIGN_BIT_GET(word) \ + (((word) & HTT_TX_CREDIT_SIGN_BIT_M) >> HTT_TX_CREDIT_SIGN_BIT_S) + +#define HTT_TX_CREDIT_TXQ_GRP_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_TX_CREDIT_TXQ_GRP, value); \ + (word) |= (value) << HTT_TX_CREDIT_TXQ_GRP_S; \ + } while (0) + +#define HTT_TX_CREDIT_TXQ_GRP_GET(word) \ + (((word) & HTT_TX_CREDIT_TXQ_GRP_M) >> HTT_TX_CREDIT_TXQ_GRP_S) + +#define HTT_TX_CREDIT_DELTA_ABS_SET(word, value) \ + do { \ + HTT_CHECK_SET_VAL(HTT_TX_CREDIT_DELTA_ABS, value); \ + (word) |= (value) << HTT_TX_CREDIT_DELTA_ABS_S; \ + } while (0) + +#define HTT_TX_CREDIT_DELTA_ABS_GET(word) \ + (((word) & HTT_TX_CREDIT_DELTA_ABS_M) >> HTT_TX_CREDIT_DELTA_ABS_S) + + +#define HTT_TX_CREDIT_MSG_BYTES 4 + +#define HTT_TX_CREDIT_SIGN_BIT_POSITIVE 0x0 +#define HTT_TX_CREDIT_SIGN_BIT_NEGATIVE 0x1 + + +/** + * @brief HTT WDI_IPA Operation Response Message + * + * @details + * HTT WDI_IPA Operation Response message is sent by target + * to host confirming suspend or resume operation. + * |31 24|23 16|15 8|7 0| + * |----------------+----------------+----------------+----------------| + * | op_code | Rsvd | msg_type | + * |-------------------------------------------------------------------| + * | Rsvd | Response len | + * |-------------------------------------------------------------------| + * | | + * | Response-type specific info | + * | | + * | | + * |-------------------------------------------------------------------| + * Header fields: + * - MSG_TYPE + * Bits 7:0 + * Purpose: Identifies this as WDI_IPA Operation Response message + * value: = 0x13 + * - OP_CODE + * Bits 31:16 + * Purpose: Identifies the operation target is responding to + * (e.g. TX suspend) + * value: = enum htt_wdi_ipa_op_code + * - RSP_LEN + * Bits 16:0 + * Purpose: length for the response-type specific info + * value: = length in bytes for response-type specific info + * For example, if OP_CODE == HTT_WDI_IPA_OPCODE_DBG_STATS, the + * length value will be sizeof(struct wlan_wdi_ipa_dbg_stats_t). + */ + +PREPACK struct htt_wdi_ipa_op_response_t { + /* DWORD 0: flags and meta-data */ + A_UINT32 + msg_type:8, /* HTT_T2H_MSG_TYPE_WDI_IPA_OP_RESPONSE */ + reserved1:8, + op_code:16; + A_UINT32 + rsp_len:16, + reserved2:16; +} POSTPACK; + +#define HTT_WDI_IPA_OP_RESPONSE_SZ 8 /* bytes */ + +#define HTT_WDI_IPA_OP_RESPONSE_OP_CODE_M 0xffff0000 +#define HTT_WDI_IPA_OP_RESPONSE_OP_CODE_S 16 + +#define HTT_WDI_IPA_OP_RESPONSE_RSP_LEN_M 0x0000ffff +#define HTT_WDI_IPA_OP_RESPONSE_RSP_LEN_S 0 + +#define HTT_WDI_IPA_OP_RESPONSE_OP_CODE_GET(_var) \ + (((_var) & HTT_WDI_IPA_OP_RESPONSE_OP_CODE_M) >> \ + HTT_WDI_IPA_OP_RESPONSE_OP_CODE_S) +#define HTT_WDI_IPA_OP_RESPONSE_OP_CODE_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_WDI_IPA_OP_RESPONSE_OP_CODE, _val); \ + ((_var) |= ((_val) << HTT_WDI_IPA_OP_RESPONSE_OP_CODE_S)); \ + } while (0) + +#define HTT_WDI_IPA_OP_RESPONSE_RSP_LEN_GET(_var) \ + (((_var) & HTT_WDI_IPA_OP_RESPONSE_RSP_LEN_M) >> \ + HTT_WDI_IPA_OP_RESPONSE_RSP_LEN_S) +#define HTT_WDI_IPA_OP_RESPONSE_RSP_LEN_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_WDI_IPA_OP_RESPONSE_RSP_LEN, _val); \ + ((_var) |= ((_val) << HTT_WDI_IPA_OP_RESPONSE_RSP_LEN_S)); \ + } while (0) + + +enum htt_phy_mode { + htt_phy_mode_11a = 0, + htt_phy_mode_11g = 1, + htt_phy_mode_11b = 2, + htt_phy_mode_11g_only = 3, + htt_phy_mode_11na_ht20 = 4, + htt_phy_mode_11ng_ht20 = 5, + htt_phy_mode_11na_ht40 = 6, + htt_phy_mode_11ng_ht40 = 7, + htt_phy_mode_11ac_vht20 = 8, + htt_phy_mode_11ac_vht40 = 9, + htt_phy_mode_11ac_vht80 = 10, + htt_phy_mode_11ac_vht20_2g = 11, + htt_phy_mode_11ac_vht40_2g = 12, + htt_phy_mode_11ac_vht80_2g = 13, + htt_phy_mode_11ac_vht80_80 = 14, /* 80+80 */ + htt_phy_mode_11ac_vht160 = 15, + + htt_phy_mode_max, +}; + +/** + * @brief target -> host HTT channel change indication + * @details + * Specify when a channel change occurs. + * This allows the host to precisely determine which rx frames arrived + * on the old channel and which rx frames arrived on the new channel. + * + *|31 |7 0 | + *|-------------------------------------------+----------| + *| reserved | msg type | + *|------------------------------------------------------| + *| primary_chan_center_freq_mhz | + *|------------------------------------------------------| + *| contiguous_chan1_center_freq_mhz | + *|------------------------------------------------------| + *| contiguous_chan2_center_freq_mhz | + *|------------------------------------------------------| + *| phy_mode | + *|------------------------------------------------------| + * + * Header fields: + * - MSG_TYPE + * Bits 7:0 + * Purpose: identifies this as a htt channel change indication message + * Value: 0x15 + * - PRIMARY_CHAN_CENTER_FREQ_MHZ + * Bits 31:0 + * Purpose: identify the (center of the) new 20 MHz primary channel + * Value: center frequency of the 20 MHz primary channel, in MHz units + * - CONTIG_CHAN1_CENTER_FREQ_MHZ + * Bits 31:0 + * Purpose: identify the (center of the) contiguous frequency range + * comprising the new channel. + * For example, if the new channel is a 80 MHz channel extending + * 60 MHz beyond the primary channel, this field would be 30 larger + * than the primary channel center frequency field. + * Value: center frequency of the contiguous frequency range comprising + * the full channel in MHz units + * (80+80 channels also use the CONTIG_CHAN2 field) + * - CONTIG_CHAN2_CENTER_FREQ_MHZ + * Bits 31:0 + * Purpose: Identify the (center of the) 80 MHz extension frequency range + * within a VHT 80+80 channel. + * This field is only relevant for VHT 80+80 channels. + * Value: center frequency of the 80 MHz extension channel in a VHT 80+80 + * channel (arbitrary value for cases besides VHT 80+80) + * - PHY_MODE + * Bits 31:0 + * Purpose: specify the PHY channel's type (legacy vs. HT vs. VHT), width, + * and band + * Value: htt_phy_mode enum value + */ + +PREPACK struct htt_chan_change_t { + /* DWORD 0: flags and meta-data */ + A_UINT32 msg_type:8, /* HTT_T2H_MSG_TYPE_CHAN_CHANGE */ + reserved1:24; + A_UINT32 primary_chan_center_freq_mhz; + A_UINT32 contig_chan1_center_freq_mhz; + A_UINT32 contig_chan2_center_freq_mhz; + A_UINT32 phy_mode; +} POSTPACK; + +#define HTT_CHAN_CHANGE_PRIMARY_CHAN_CENTER_FREQ_MHZ_M 0xffffffff +#define HTT_CHAN_CHANGE_PRIMARY_CHAN_CENTER_FREQ_MHZ_S 0 +#define HTT_CHAN_CHANGE_CONTIG_CHAN1_CENTER_FREQ_MHZ_M 0xffffffff +#define HTT_CHAN_CHANGE_CONTIG_CHAN1_CENTER_FREQ_MHZ_S 0 +#define HTT_CHAN_CHANGE_CONTIG_CHAN2_CENTER_FREQ_MHZ_M 0xffffffff +#define HTT_CHAN_CHANGE_CONTIG_CHAN2_CENTER_FREQ_MHZ_S 0 +#define HTT_CHAN_CHANGE_PHY_MODE_M 0xffffffff +#define HTT_CHAN_CHANGE_PHY_MODE_S 0 + + +#define HTT_CHAN_CHANGE_PRIMARY_CHAN_CENTER_FREQ_MHZ_SET(word, value) \ +do { \ + HTT_CHECK_SET_VAL( \ + HTT_CHAN_CHANGE_PRIMARY_CHAN_CENTER_FREQ_MHZ, value); \ + (word) |= (value) << \ + HTT_CHAN_CHANGE_PRIMARY_CHAN_CENTER_FREQ_MHZ_S; \ +} while (0) +#define HTT_CHAN_CHANGE_PRIMARY_CHAN_CENTER_FREQ_MHZ_GET(word) \ + (((word) & HTT_CHAN_CHANGE_PRIMARY_CHAN_CENTER_FREQ_MHZ_M) \ + >> HTT_CHAN_CHANGE_PRIMARY_CHAN_CENTER_FREQ_MHZ_S) + +#define HTT_CHAN_CHANGE_CONTIG_CHAN1_CENTER_FREQ_MHZ_SET(word, value) \ +do { \ + HTT_CHECK_SET_VAL( \ + HTT_CHAN_CHANGE_CONTIG_CHAN1_CENTER_FREQ_MHZ, value); \ + (word) |= (value) << \ + HTT_CHAN_CHANGE_CONTIG_CHAN1_CENTER_FREQ_MHZ_S; \ +} while (0) +#define HTT_CHAN_CHANGE_CONTIG_CHAN1_CENTER_FREQ_MHZ_GET(word) \ + (((word) & HTT_CHAN_CHANGE_CONTIG_CHAN1_CENTER_FREQ_MHZ_M) \ + >> HTT_CHAN_CHANGE_CONTIG_CHAN1_CENTER_FREQ_MHZ_S) + +#define HTT_CHAN_CHANGE_CONTIG_CHAN2_CENTER_FREQ_MHZ_SET(word, value) \ +do { \ + HTT_CHECK_SET_VAL( \ + HTT_CHAN_CHANGE_CONTIG_CHAN2_CENTER_FREQ_MHZ, value); \ + (word) |= (value) << \ + HTT_CHAN_CHANGE_CONTIG_CHAN2_CENTER_FREQ_MHZ_S; \ +} while (0) +#define HTT_CHAN_CHANGE_CONTIG_CHAN2_CENTER_FREQ_MHZ_GET(word) \ + (((word) & HTT_CHAN_CHANGE_CONTIG_CHAN2_CENTER_FREQ_MHZ_M) \ + >> HTT_CHAN_CHANGE_CONTIG_CHAN2_CENTER_FREQ_MHZ_S) + +#define HTT_CHAN_CHANGE_PHY_MODE_SET(word, value) \ +do { \ + HTT_CHECK_SET_VAL(HTT_CHAN_CHANGE_PHY_MODE, value); \ + (word) |= (value) << HTT_CHAN_CHANGE_PHY_MODE_S; \ +} while (0) +#define HTT_CHAN_CHANGE_PHY_MODE_GET(word) \ + (((word) & HTT_CHAN_CHANGE_PHY_MODE_M) \ + >> HTT_CHAN_CHANGE_PHY_MODE_S) + +#define HTT_CHAN_CHANGE_BYTES sizeof(struct htt_chan_change_t) + + +/** + * @brief rx offload packet error message + * + * @details + * HTT_RX_OFLD_PKT_ERR message is sent by target to host to indicate err + * of target payload like mic err. + * + * |31 24|23 16|15 8|7 0| + * |----------------+----------------+----------------+----------------| + * | tid | vdev_id | msg_sub_type | msg_type | + * |-------------------------------------------------------------------| + * : (sub-type dependent content) : + * :- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -: + * Header fields: + * - msg_type + * Bits 7:0 + * Purpose: Identifies this as HTT_RX_OFLD_PKT_ERR message + * value: 0x16 (HTT_T2H_MSG_TYPE_RX_OFLD_PKT_ERR) + * - msg_sub_type + * Bits 15:8 + * Purpose: Identifies which type of rx error is reported by this message + * value: htt_rx_ofld_pkt_err_type + * - vdev_id + * Bits 23:16 + * Purpose: Identifies which vdev received the erroneous rx frame + * value: + * - tid + * Bits 31:24 + * Purpose: Identifies the traffic type of the rx frame + * value: + * + * - The payload fields used if the sub-type == MIC error are shown below. + * Note - MIC err is per MSDU, while PN is per MPDU. + * The FW will discard the whole MPDU if any MSDU within the MPDU is marked + * with MIC err in A-MSDU case, so FW will send only one HTT message + * with the PN of this MPDU attached to indicate MIC err for one MPDU + * instead of sending separate HTT messages for each wrong MSDU within + * the MPDU. + * + * |31 24|23 16|15 8|7 0| + * |----------------+----------------+----------------+----------------| + * | Rsvd | key_id | peer_id | + * |-------------------------------------------------------------------| + * | receiver MAC addr 31:0 | + * |-------------------------------------------------------------------| + * | Rsvd | receiver MAC addr 47:32 | + * |-------------------------------------------------------------------| + * | transmitter MAC addr 31:0 | + * |-------------------------------------------------------------------| + * | Rsvd | transmitter MAC addr 47:32 | + * |-------------------------------------------------------------------| + * | PN 31:0 | + * |-------------------------------------------------------------------| + * | Rsvd | PN 47:32 | + * |-------------------------------------------------------------------| + * - peer_id + * Bits 15:0 + * Purpose: identifies which peer is frame is from + * value: + * - key_id + * Bits 23:16 + * Purpose: identifies key_id of rx frame + * value: + * - RA_31_0 (receiver MAC addr 31:0) + * Bits 31:0 + * Purpose: identifies by MAC address which vdev received the frame + * value: MAC address lower 4 bytes + * - RA_47_32 (receiver MAC addr 47:32) + * Bits 15:0 + * Purpose: identifies by MAC address which vdev received the frame + * value: MAC address upper 2 bytes + * - TA_31_0 (transmitter MAC addr 31:0) + * Bits 31:0 + * Purpose: identifies by MAC address which peer transmitted the frame + * value: MAC address lower 4 bytes + * - TA_47_32 (transmitter MAC addr 47:32) + * Bits 15:0 + * Purpose: identifies by MAC address which peer transmitted the frame + * value: MAC address upper 2 bytes + * - PN_31_0 + * Bits 31:0 + * Purpose: Identifies pn of rx frame + * value: PN lower 4 bytes + * - PN_47_32 + * Bits 15:0 + * Purpose: Identifies pn of rx frame + * value: + * TKIP or CCMP: PN upper 2 bytes + * WAPI: PN bytes 6:5 (bytes 15:7 not included in this message) + */ + +enum htt_rx_ofld_pkt_err_type { + HTT_RX_OFLD_PKT_ERR_TYPE_NONE = 0, + HTT_RX_OFLD_PKT_ERR_TYPE_MIC_ERR, +}; + +/* definition for HTT_RX_OFLD_PKT_ERR msg hdr */ +#define HTT_RX_OFLD_PKT_ERR_HDR_BYTES 4 + +#define HTT_RX_OFLD_PKT_ERR_MSG_SUB_TYPE_M 0x0000ff00 +#define HTT_RX_OFLD_PKT_ERR_MSG_SUB_TYPE_S 8 + +#define HTT_RX_OFLD_PKT_ERR_VDEV_ID_M 0x00ff0000 +#define HTT_RX_OFLD_PKT_ERR_VDEV_ID_S 16 + +#define HTT_RX_OFLD_PKT_ERR_TID_M 0xff000000 +#define HTT_RX_OFLD_PKT_ERR_TID_S 24 + +#define HTT_RX_OFLD_PKT_ERR_MSG_SUB_TYPE_GET(_var) \ + (((_var) & HTT_RX_OFLD_PKT_ERR_MSG_SUB_TYPE_M) \ + >> HTT_RX_OFLD_PKT_ERR_MSG_SUB_TYPE_S) +#define HTT_RX_OFLD_PKT_ERR_MSG_SUB_TYPE_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_OFLD_PKT_ERR_MSG_SUB_TYPE, _val); \ + ((_var) |= ((_val) << HTT_RX_OFLD_PKT_ERR_MSG_SUB_TYPE_S)); \ + } while (0) + +#define HTT_RX_OFLD_PKT_ERR_VDEV_ID_GET(_var) \ + (((_var) & HTT_RX_OFLD_PKT_ERR_VDEV_ID_M) >> \ + HTT_RX_OFLD_PKT_ERR_VDEV_ID_S) +#define HTT_RX_OFLD_PKT_ERR_VDEV_ID_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_OFLD_PKT_ERR_VDEV_ID, _val); \ + ((_var) |= ((_val) << HTT_RX_OFLD_PKT_ERR_VDEV_ID_S)); \ + } while (0) + +#define HTT_RX_OFLD_PKT_ERR_TID_GET(_var) \ + (((_var) & HTT_RX_OFLD_PKT_ERR_TID_M) >> HTT_RX_OFLD_PKT_ERR_TID_S) +#define HTT_RX_OFLD_PKT_ERR_TID_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_RX_OFLD_PKT_ERR_TID, _val); \ + ((_var) |= ((_val) << HTT_RX_OFLD_PKT_ERR_TID_S)); \ + } while (0) + +/* definition for HTT_RX_OFLD_PKT_ERR_MIC_ERR msg sub-type payload */ +#define HTT_RX_OFLD_PKT_ERR_MIC_ERR_BYTES 28 + +#define HTT_RX_OFLD_PKT_ERR_MIC_ERR_PEER_ID_M 0x0000ffff +#define HTT_RX_OFLD_PKT_ERR_MIC_ERR_PEER_ID_S 0 + +#define HTT_RX_OFLD_PKT_ERR_MIC_ERR_KEYID_M 0x00ff0000 +#define HTT_RX_OFLD_PKT_ERR_MIC_ERR_KEYID_S 16 + +#define HTT_RX_OFLD_PKT_ERR_MIC_ERR_RA_31_0_M 0xffffffff +#define HTT_RX_OFLD_PKT_ERR_MIC_ERR_RA_31_0_S 0 + +#define HTT_RX_OFLD_PKT_ERR_MIC_ERR_RA_47_32_M 0x0000ffff +#define HTT_RX_OFLD_PKT_ERR_MIC_ERR_RA_47_32_S 0 + +#define HTT_RX_OFLD_PKT_ERR_MIC_ERR_TA_31_0_M 0xffffffff +#define HTT_RX_OFLD_PKT_ERR_MIC_ERR_TA_31_0_S 0 + +#define HTT_RX_OFLD_PKT_ERR_MIC_ERR_TA_47_32_M 0x0000ffff +#define HTT_RX_OFLD_PKT_ERR_MIC_ERR_TA_47_32_S 0 + +#define HTT_RX_OFLD_PKT_ERR_MIC_ERR_PN_31_0_M 0xffffffff +#define HTT_RX_OFLD_PKT_ERR_MIC_ERR_PN_31_0_S 0 + +#define HTT_RX_OFLD_PKT_ERR_MIC_ERR_PN_47_32_M 0x0000ffff +#define HTT_RX_OFLD_PKT_ERR_MIC_ERR_PN_47_32_S 0 + +#define HTT_RX_OFLD_PKT_ERR_MIC_ERR_PEER_ID_GET(_var) \ + (((_var) & HTT_RX_OFLD_PKT_ERR_MIC_ERR_PEER_ID_M) >> \ + HTT_RX_OFLD_PKT_ERR_MIC_ERR_PEER_ID_S) +#define HTT_RX_OFLD_PKT_ERR_MIC_ERR_PEER_ID_SET(_var, _val) \ +do { \ + HTT_CHECK_SET_VAL(HTT_RX_OFLD_PKT_ERR_MIC_ERR_PEER_ID, _val); \ + ((_var) |= ((_val) << HTT_RX_OFLD_PKT_ERR_MIC_ERR_PEER_ID_S)); \ +} while (0) + +#define HTT_RX_OFLD_PKT_ERR_MIC_ERR_KEYID_GET(_var) \ + (((_var) & HTT_RX_OFLD_PKT_ERR_MIC_ERR_KEYID_M) >> \ + HTT_RX_OFLD_PKT_ERR_MIC_ERR_KEYID_S) +#define HTT_RX_OFLD_PKT_ERR_MIC_ERR_KEYID_SET(_var, _val) \ +do { \ + HTT_CHECK_SET_VAL(HTT_RX_OFLD_PKT_ERR_MIC_ERR_KEYID, _val); \ + ((_var) |= ((_val) << HTT_RX_OFLD_PKT_ERR_MIC_ERR_KEYID_S)); \ +} while (0) + +#define HTT_RX_OFLD_PKT_ERR_MIC_ERR_RA_31_0_GET(_var) \ + (((_var) & HTT_RX_OFLD_PKT_ERR_MIC_ERR_RA_31_0_M) >> \ + HTT_RX_OFLD_PKT_ERR_MIC_ERR_RA_31_0_S) +#define HTT_RX_OFLD_PKT_ERR_MIC_ERR_RA_31_0_SET(_var, _val) \ +do { \ + HTT_CHECK_SET_VAL(HTT_RX_OFLD_PKT_ERR_MIC_ERR_RA_31_0, _val); \ + ((_var) |= ((_val) << HTT_RX_OFLD_PKT_ERR_MIC_ERR_RA_31_0_S)); \ +} while (0) + +#define HTT_RX_OFLD_PKT_ERR_MIC_ERR_RA_47_32_GET(_var) \ + (((_var) & HTT_RX_OFLD_PKT_ERR_MIC_ERR_RA_47_32_M) >> \ + HTT_RX_OFLD_PKT_ERR_MIC_ERR_RA_47_32_S) +#define HTT_RX_OFLD_PKT_ERR_MIC_ERR_RA_47_32_SET(_var, _val) \ +do { \ + HTT_CHECK_SET_VAL(HTT_RX_OFLD_PKT_ERR_MIC_ERR_RA_47_32, _val); \ + ((_var) |= ((_val) << HTT_RX_OFLD_PKT_ERR_MIC_ERR_RA_47_32_S)); \ +} while (0) + +#define HTT_RX_OFLD_PKT_ERR_MIC_ERR_TA_31_0_GET(_var) \ + (((_var) & HTT_RX_OFLD_PKT_ERR_MIC_ERR_TA_31_0_M) >> \ + HTT_RX_OFLD_PKT_ERR_MIC_ERR_TA_31_0_S) +#define HTT_RX_OFLD_PKT_ERR_MIC_ERR_TA_31_0_SET(_var, _val) \ +do { \ + HTT_CHECK_SET_VAL(HTT_RX_OFLD_PKT_ERR_MIC_ERR_TA_31_0, _val); \ + ((_var) |= ((_val) << HTT_RX_OFLD_PKT_ERR_MIC_ERR_TA_31_0_S)); \ +} while (0) + +#define HTT_RX_OFLD_PKT_ERR_MIC_ERR_TA_47_32_GET(_var) \ + (((_var) & HTT_RX_OFLD_PKT_ERR_MIC_ERR_TA_47_32_M) >> \ + HTT_RX_OFLD_PKT_ERR_MIC_ERR_TA_47_32_S) +#define HTT_RX_OFLD_PKT_ERR_MIC_ERR_TA_47_32_SET(_var, _val) \ +do { \ + HTT_CHECK_SET_VAL(HTT_RX_OFLD_PKT_ERR_MIC_ERR_TA_47_32, _val); \ + ((_var) |= ((_val) << HTT_RX_OFLD_PKT_ERR_MIC_ERR_TA_47_32_S)); \ +} while (0) + +#define HTT_RX_OFLD_PKT_ERR_MIC_ERR_PN_31_0_GET(_var) \ + (((_var) & HTT_RX_OFLD_PKT_ERR_MIC_ERR_PN_31_0_M) >> \ + HTT_RX_OFLD_PKT_ERR_MIC_ERR_PN_31_0_S) +#define HTT_RX_OFLD_PKT_ERR_MIC_ERR_PN_31_0_SET(_var, _val) \ +do { \ + HTT_CHECK_SET_VAL(HTT_RX_OFLD_PKT_ERR_MIC_ERR_PN_31_0, _val); \ + ((_var) |= ((_val) << HTT_RX_OFLD_PKT_ERR_MIC_ERR_PN_31_0_S)); \ +} while (0) + +#define HTT_RX_OFLD_PKT_ERR_MIC_ERR_PN_47_32_GET(_var) \ + (((_var) & HTT_RX_OFLD_PKT_ERR_MIC_ERR_PN_47_32_M) >> \ + HTT_RX_OFLD_PKT_ERR_MIC_ERR_PN_47_32_S) +#define HTT_RX_OFLD_PKT_ERR_MIC_ERR_PN_47_32_SET(_var, _val) \ +do { \ + HTT_CHECK_SET_VAL(HTT_RX_OFLD_PKT_ERR_MIC_ERR_PN_47_32, _val); \ + ((_var) |= ((_val) << HTT_RX_OFLD_PKT_ERR_MIC_ERR_PN_47_32_S)); \ +} while (0) + +/** + * @brief peer rate report message + * + * @details + * HTT_T2H_MSG_TYPE_RATE_REPORT message is sent by target to host to indicate the + * justified rate of all the peers. + * + * |31 24|23 16|15 8|7 0| + * |----------------+----------------+----------------+----------------| + * | peer_count | | msg_type | + * |-------------------------------------------------------------------| + * : Payload (variant number of peer rate report) : + * :- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -: + * Header fields: + * - msg_type + * Bits 7:0 + * Purpose: Identifies this as HTT_T2H_MSG_TYPE_RATE_REPORT message. + * value: 0x17 (HTT_T2H_MSG_TYPE_RATE_REPORT) + * - reserved + * Bits 15:8 + * Purpose: + * value: + * - peer_count + * Bits 31:16 + * Purpose: Specify how many peer rate report elements are present in the payload. + * value: + * + * Payload: + * There are variant number of peer rate report follow the first 32 bits. + * The peer rate report is defined as follows. + * + * |31 20|19 16|15 0| + * |-----------------------+---------+---------------------------------|- + * | reserved | phy | peer_id | \ + * |-------------------------------------------------------------------| -> report #0 + * | rate | / + * |-----------------------+---------+---------------------------------|- + * | reserved | phy | peer_id | \ + * |-------------------------------------------------------------------| -> report #1 + * | rate | / + * |-----------------------+---------+---------------------------------|- + * | reserved | phy | peer_id | \ + * |-------------------------------------------------------------------| -> report #2 + * | rate | / + * |-------------------------------------------------------------------|- + * : : + * : : + * : : + * :-------------------------------------------------------------------: + * + * - peer_id + * Bits 15:0 + * Purpose: identify the peer + * value: + * - phy + * Bits 19:16 + * Purpose: identify which phy is in use + * value: 0=11b, 1=11a/g, 2=11n, 3=11ac. + * Please see enum htt_peer_report_phy_type for detail. + * - reserved + * Bits 31:20 + * Purpose: + * value: + * - rate + * Bits 31:0 + * Purpose: represent the justified rate of the peer specified by peer_id + * value: + */ + +enum htt_peer_rate_report_phy_type { + HTT_PEER_RATE_REPORT_11B = 0, + HTT_PEER_RATE_REPORT_11A_G, + HTT_PEER_RATE_REPORT_11N, + HTT_PEER_RATE_REPORT_11AC, +}; + +#define HTT_PEER_RATE_REPORT_SIZE 8 + +#define HTT_PEER_RATE_REPORT_MSG_PEER_COUNT_M 0xffff0000 +#define HTT_PEER_RATE_REPORT_MSG_PEER_COUNT_S 16 + +#define HTT_PEER_RATE_REPORT_MSG_PEER_ID_M 0x0000ffff +#define HTT_PEER_RATE_REPORT_MSG_PEER_ID_S 0 + +#define HTT_PEER_RATE_REPORT_MSG_PHY_M 0x000f0000 +#define HTT_PEER_RATE_REPORT_MSG_PHY_S 16 + +#define HTT_PEER_RATE_REPORT_MSG_PEER_COUNT_GET(_var) \ + (((_var) & HTT_PEER_RATE_REPORT_MSG_PEER_COUNT_M) \ + >> HTT_PEER_RATE_REPORT_MSG_PEER_COUNT_S) +#define HTT_PEER_RATE_REPORT_MSG_PEER_COUNT_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_PEER_RATE_REPORT_MSG_PEER_COUNT, _val); \ + ((_var) |= ((_val) << HTT_PEER_RATE_REPORT_MSG_PEER_COUNT_S)); \ + } while (0) + +#define HTT_PEER_RATE_REPORT_MSG_PEER_ID_GET(_var) \ + (((_var) & HTT_PEER_RATE_REPORT_MSG_PEER_ID_M) \ + >> HTT_PEER_RATE_REPORT_MSG_PEER_ID_S) +#define HTT_PEER_RATE_REPORT_MSG_PEER_ID_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_PEER_RATE_REPORT_MSG_PEER_ID, _val); \ + ((_var) |= ((_val) << HTT_PEER_RATE_REPORT_MSG_PEER_ID_S)); \ + } while (0) + +#define HTT_PEER_RATE_REPORT_MSG_PHY_GET(_var) \ + (((_var) & HTT_PEER_RATE_REPORT_MSG_PHY_M) \ + >> HTT_PEER_RATE_REPORT_MSG_PHY_S) +#define HTT_PEER_RATE_REPORT_MSG_PHY_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_PEER_RATE_REPORT_MSG_PHY, _val); \ + ((_var) |= ((_val) << HTT_PEER_RATE_REPORT_MSG_PHY_S)); \ + } while (0) + +/** + * @brief HTT_T2H_MSG_TYPE_FLOW_POOL_MAP Message + * + * @details + * HTT_T2H_MSG_TYPE_FLOW_POOL_MAP message is sent by the target when setting up + * a flow of descriptors. + * + * This message is in TLV format and indicates the parameters to be setup a + * flow in the host. Each entry indicates that a particular flow ID is ready to + * receive descriptors from a specified pool. + * + * The message would appear as follows: + * + * |31 24|23 16|15 8|7 0| + * |----------------+----------------+----------------+----------------| + * header | reserved | num_flows | msg_type | + * |-------------------------------------------------------------------| + * | | + * : payload : + * | | + * |-------------------------------------------------------------------| + * + * The header field is one DWORD long and is interpreted as follows: + * b'0:7 - msg_type: This will be set to HTT_T2H_MSG_TYPE_FLOW_POOL_MAP + * b'8-15 - num_flows: This will indicate the number of flows being setup in + * this message + * b'16-31 - reserved: These bits are reserved for future use + * + * Payload: + * The payload would contain multiple objects of the following structure. Each + * object represents a flow. + * + * |31 24|23 16|15 8|7 0| + * |----------------+----------------+----------------+----------------| + * header | reserved | num_flows | msg_type | + * |-------------------------------------------------------------------| + * payload0| flow_type | + * |-------------------------------------------------------------------| + * | flow_id | + * |-------------------------------------------------------------------| + * | reserved0 | flow_pool_id | + * |-------------------------------------------------------------------| + * | reserved1 | flow_pool_size | + * |-------------------------------------------------------------------| + * | reserved2 | + * |-------------------------------------------------------------------| + * payload1| flow_type | + * |-------------------------------------------------------------------| + * | flow_id | + * |-------------------------------------------------------------------| + * | reserved0 | flow_pool_id | + * |-------------------------------------------------------------------| + * | reserved1 | flow_pool_size | + * |-------------------------------------------------------------------| + * | reserved2 | + * |-------------------------------------------------------------------| + * | . | + * | . | + * | . | + * |-------------------------------------------------------------------| + * + * Each payload is 5 DWORDS long and is interpreted as follows: + * dword0 - b'0:31 - flow_type: This indicates the type of the entity to which + * this flow is associated. It can be VDEV, peer, + * or tid (AC). Based on enum htt_flow_type. + * + * dword1 - b'0:31 - flow_id: Identifier for the flow corresponding to this + * object. For flow_type vdev it is set to the + * vdevid, for peer it is peerid and for tid, it is + * tid_num. + * + * dword2 - b'0:15 - flow_pool_id: Identifier of the descriptor-pool being used + * in the host for this flow + * b'16:31 - reserved0: This field in reserved for the future. In case + * we have a hierarchical implementation (HCM) of + * pools, it can be used to indicate the ID of the + * parent-pool. + * + * dword3 - b'0:15 - flow_pool_size: Size of the pool in number of descriptors. + * Descriptors for this flow will be + * allocated from this pool in the host. + * b'16:31 - reserved1: This field in reserved for the future. In case + * we have a hierarchical implementation of pools, + * it can be used to indicate the max number of + * descriptors in the pool. The b'0:15 can be used + * to indicate min number of descriptors in the + * HCM scheme. + * + * dword4 - b'0:31 - reserved2: This field in reserved for the future. In case + * we have a hierarchical implementation of pools, + * b'0:15 can be used to indicate the + * priority-based borrowing (PBB) threshold of + * the flow's pool. The b'16:31 are still left + * reserved. + */ + +enum htt_flow_type { + FLOW_TYPE_VDEV = 0, + /* Insert new flow types above this line */ +}; + +PREPACK struct htt_flow_pool_map_payload_t { + A_UINT32 flow_type; + A_UINT32 flow_id; + A_UINT32 flow_pool_id:16, + reserved0:16; + A_UINT32 flow_pool_size:16, + reserved1:16; + A_UINT32 reserved2; +} POSTPACK; + +#define HTT_FLOW_POOL_MAP_HEADER_SZ (sizeof(A_UINT32)) + +#define HTT_FLOW_POOL_MAP_PAYLOAD_SZ \ + (sizeof(struct htt_flow_pool_map_payload_t)) + +#define HTT_FLOW_POOL_MAP_NUM_FLOWS_M 0x0000ff00 +#define HTT_FLOW_POOL_MAP_NUM_FLOWS_S 8 + +#define HTT_FLOW_POOL_MAP_FLOW_TYPE_M 0xffffffff +#define HTT_FLOW_POOL_MAP_FLOW_TYPE_S 0 + +#define HTT_FLOW_POOL_MAP_FLOW_ID_M 0xffffffff +#define HTT_FLOW_POOL_MAP_FLOW_ID_S 0 + +#define HTT_FLOW_POOL_MAP_FLOW_POOL_ID_M 0x0000ffff +#define HTT_FLOW_POOL_MAP_FLOW_POOL_ID_S 0 + +#define HTT_FLOW_POOL_MAP_FLOW_POOL_SIZE_M 0x0000ffff +#define HTT_FLOW_POOL_MAP_FLOW_POOL_SIZE_S 0 + +#define HTT_FLOW_POOL_MAP_NUM_FLOWS_GET(_var) \ + (((_var) & HTT_FLOW_POOL_MAP_NUM_FLOWS_M) >> HTT_FLOW_POOL_MAP_NUM_FLOWS_S) + +#define HTT_FLOW_POOL_MAP_FLOW_TYPE_GET(_var) \ + (((_var) & HTT_FLOW_POOL_MAP_FLOW_TYPE_M) >> HTT_FLOW_POOL_MAP_FLOW_TYPE_S) + +#define HTT_FLOW_POOL_MAP_FLOW_ID_GET(_var) \ + (((_var) & HTT_FLOW_POOL_MAP_FLOW_ID_M) >> HTT_FLOW_POOL_MAP_FLOW_ID_S) + +#define HTT_FLOW_POOL_MAP_FLOW_POOL_ID_GET(_var) \ + (((_var) & HTT_FLOW_POOL_MAP_FLOW_POOL_ID_M) >> \ + HTT_FLOW_POOL_MAP_FLOW_POOL_ID_S) + +#define HTT_FLOW_POOL_MAP_FLOW_POOL_SIZE_GET(_var) \ + (((_var) & HTT_FLOW_POOL_MAP_FLOW_POOL_SIZE_M) >> \ + HTT_FLOW_POOL_MAP_FLOW_POOL_SIZE_S) + +#define HTT_FLOW_POOL_MAP_NUM_FLOWS_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_FLOW_POOL_MAP_NUM_FLOWS, _val); \ + ((_var) |= ((_val) << HTT_FLOW_POOL_MAP_NUM_FLOWS_S)); \ + } while (0) + +#define HTT_FLOW_POOL_MAP_FLOW_TYPE_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_FLOW_POOL_MAP_FLOW_TYPE, _val); \ + ((_var) |= ((_val) << HTT_FLOW_POOL_MAP_FLOW_TYPE_S)); \ + } while (0) + +#define HTT_FLOW_POOL_MAP_FLOW_ID_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_FLOW_POOL_MAP_FLOW_ID, _val); \ + ((_var) |= ((_val) << HTT_FLOW_POOL_MAP_FLOW_ID_S)); \ + } while (0) + +#define HTT_FLOW_POOL_MAP_FLOW_POOL_ID_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_FLOW_POOL_MAP_FLOW_POOL_ID, _val); \ + ((_var) |= ((_val) << HTT_FLOW_POOL_MAP_FLOW_POOL_ID_S)); \ + } while (0) + +#define HTT_FLOW_POOL_MAP_FLOW_POOL_SIZE_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_FLOW_POOL_MAP_FLOW_POOL_SIZE, _val); \ + ((_var) |= ((_val) << HTT_FLOW_POOL_MAP_FLOW_POOL_SIZE_S)); \ + } while (0) + +/** + * @brief HTT_T2H_MSG_TYPE_FLOW_POOL_UNMAP Message + * + * @details + * HTT_T2H_MSG_TYPE_FLOW_POOL_UNMAP message is sent by the target when tearing + * down a flow of descriptors. + * This message indicates that for the flow (whose ID is provided) is wanting + * to stop receiving descriptors. This flow ID corresponds to the ID of the + * pool of descriptors from where descriptors are being allocated for this + * flow. When a flow (and its pool) are unmapped, all the child-pools will also + * be unmapped by the host. + * + * The message would appear as follows: + * + * |31 24|23 16|15 8|7 0| + * |----------------+----------------+----------------+----------------| + * | reserved0 | msg_type | + * |-------------------------------------------------------------------| + * | flow_type | + * |-------------------------------------------------------------------| + * | flow_id | + * |-------------------------------------------------------------------| + * | reserved1 | flow_pool_id | + * |-------------------------------------------------------------------| + * + * The message is interpreted as follows: + * dword0 - b'0:7 - msg_type: This will be set to + * HTT_T2H_MSG_TYPE_FLOW_POOL_UNMAP + * b'8:31 - reserved0: Reserved for future use + * + * dword1 - b'0:31 - flow_type: This indicates the type of the entity to which + * this flow is associated. It can be VDEV, peer, + * or tid (AC). Based on enum htt_flow_type. + * + * dword2 - b'0:31 - flow_id: Identifier for the flow corresponding to this + * object. For flow_type vdev it is set to the + * vdevid, for peer it is peerid and for tid, it is + * tid_num. + * + * dword3 - b'0:15 - flow_pool_id: Identifier of the descriptor-pool being + * used in the host for this flow + * b'16:31 - reserved0: This field in reserved for the future. + * + */ + +PREPACK struct htt_flow_pool_unmap_t { + A_UINT32 msg_type:8, + reserved0:24; + A_UINT32 flow_type; + A_UINT32 flow_id; + A_UINT32 flow_pool_id:16, + reserved1:16; +} POSTPACK; + +#define HTT_FLOW_POOL_UNMAP_SZ (sizeof(struct htt_flow_pool_unmap_t)) + +#define HTT_FLOW_POOL_UNMAP_FLOW_TYPE_M 0xffffffff +#define HTT_FLOW_POOL_UNMAP_FLOW_TYPE_S 0 + +#define HTT_FLOW_POOL_UNMAP_FLOW_ID_M 0xffffffff +#define HTT_FLOW_POOL_UNMAP_FLOW_ID_S 0 + +#define HTT_FLOW_POOL_UNMAP_FLOW_POOL_ID_M 0x0000ffff +#define HTT_FLOW_POOL_UNMAP_FLOW_POOL_ID_S 0 + +#define HTT_FLOW_POOL_UNMAP_FLOW_TYPE_GET(_var) \ + (((_var) & HTT_FLOW_POOL_UNMAP_FLOW_TYPE_M) >> \ + HTT_FLOW_POOL_UNMAP_FLOW_TYPE_S) + +#define HTT_FLOW_POOL_UNMAP_FLOW_ID_GET(_var) \ + (((_var) & HTT_FLOW_POOL_UNMAP_FLOW_ID_M) >> HTT_FLOW_POOL_UNMAP_FLOW_ID_S) + +#define HTT_FLOW_POOL_UNMAP_FLOW_POOL_ID_GET(_var) \ + (((_var) & HTT_FLOW_POOL_UNMAP_FLOW_POOL_ID_M) >> \ + HTT_FLOW_POOL_UNMAP_FLOW_POOL_ID_S) + +#define HTT_FLOW_POOL_UNMAP_FLOW_TYPE_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_FLOW_POOL_UNMAP_FLOW_TYPE, _val); \ + ((_var) |= ((_val) << HTT_FLOW_POOL_UNMAP_FLOW_TYPE_S)); \ + } while (0) + +#define HTT_FLOW_POOL_UNMAP_FLOW_ID_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_FLOW_POOL_UNMAP_FLOW_ID, _val); \ + ((_var) |= ((_val) << HTT_FLOW_POOL_UNMAP_FLOW_ID_S)); \ + } while (0) + +#define HTT_FLOW_POOL_UNMAP_FLOW_POOL_ID_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_FLOW_POOL_UNMAP_FLOW_POOL_ID, _val); \ + ((_var) |= ((_val) << HTT_FLOW_POOL_UNMAP_FLOW_POOL_ID_S)); \ + } while (0) + +/** + * @brief HTT_T2H_MSG_TYPE_SRING_SETUP_DONE Message + * + * @details + * HTT_T2H_MSG_TYPE_SRING_SETUP_DONE message is sent by the target when + * SRNG ring setup is done + * + * This message indicates whether the last setup operation is successful. + * It will be sent to host when host set respose_required bit in + * HTT_H2T_MSG_TYPE_SRING_SETUP. + * The message would appear as follows: + * + * |31 24|23 16|15 8|7 0| + * |--------------- +----------------+----------------+----------------| + * | setup_status | ring_id | pdev_id | msg_type | + * |-------------------------------------------------------------------| + * + * The message is interpreted as follows: + * dword0 - b'0:7 - msg_type: This will be set to + * HTT_T2H_MSG_TYPE_SRING_SETUP_DONE + * b'8:15 - pdev_id: + * 0 (for rings at SOC/UMAC level), + * 1/2/3 mac id (for rings at LMAC level) + * b'16:23 - ring_id: Identify the ring which is set up + * More details can be got from enum htt_srng_ring_id + * b'24:31 - setup_status: Indicate status of setup operation + * Refer to htt_ring_setup_status + */ + +PREPACK struct htt_sring_setup_done_t { + A_UINT32 msg_type: 8, + pdev_id: 8, + ring_id: 8, + setup_status: 8; +} POSTPACK; + +enum htt_ring_setup_status { + htt_ring_setup_status_ok = 0, + htt_ring_setup_status_error, +}; + +#define HTT_SRING_SETUP_DONE_SZ (sizeof(struct htt_sring_setup_done_t)) + +#define HTT_SRING_SETUP_DONE_PDEV_ID_M 0x0000ff00 +#define HTT_SRING_SETUP_DONE_PDEV_ID_S 8 +#define HTT_SRING_SETUP_DONE_PDEV_ID_GET(_var) \ + (((_var) & HTT_SRING_SETUP_DONE_PDEV_ID_M) >> \ + HTT_SRING_SETUP_DONE_PDEV_ID_S) +#define HTT_SRING_SETUP_DONE_PDEV_ID_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_SRING_SETUP_DONE_PDEV_ID, _val); \ + ((_var) |= ((_val) << HTT_SRING_SETUP_DONE_PDEV_ID_S)); \ + } while (0) + +#define HTT_SRING_SETUP_DONE_RING_ID_M 0x00ff0000 +#define HTT_SRING_SETUP_DONE_RING_ID_S 16 +#define HTT_SRING_SETUP_DONE_RING_ID_GET(_var) \ + (((_var) & HTT_SRING_SETUP_DONE_RING_ID_M) >> \ + HTT_SRING_SETUP_DONE_RING_ID_S) +#define HTT_SRING_SETUP_DONE_RING_ID_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_SRING_SETUP_DONE_RING_ID, _val); \ + ((_var) |= ((_val) << HTT_SRING_SETUP_DONE_RING_ID_S)); \ + } while (0) + +#define HTT_SRING_SETUP_DONE_STATUS_M 0xff000000 +#define HTT_SRING_SETUP_DONE_STATUS_S 24 +#define HTT_SRING_SETUP_DONE_STATUS_GET(_var) \ + (((_var) & HTT_SRING_SETUP_DONE_STATUS_M) >> \ + HTT_SRING_SETUP_DONE_STATUS_S) +#define HTT_SRING_SETUP_DONE_STATUS_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_SRING_SETUP_DONE_STATUS, _val); \ + ((_var) |= ((_val) << HTT_SRING_SETUP_DONE_STATUS_S)); \ + } while (0) + + +/** + * @brief HTT_T2H_MSG_TYPE_MAP_FLOW_INFO Message + * + * @details + * HTT TX map flow entry with tqm flow pointer + * Sent from firmware to host to add tqm flow pointer in corresponding + * flow search entry. Flow metadata is replayed back to host as part of this + * struct to enable host to find the specific flow search entry + * + * The message would appear as follows: + * + * |31 28|27 18|17 14|13 8|7 0| + * |-------+------------------------------------------+----------------| + * | rsvd0 | fse_hsh_idx | msg_type | + * |-------------------------------------------------------------------| + * | rsvd1 | tid | peer_id | + * |-------------------------------------------------------------------| + * | tqm_flow_pntr_lo | + * |-------------------------------------------------------------------| + * | tqm_flow_pntr_hi | + * |-------------------------------------------------------------------| + * | fse_meta_data | + * |-------------------------------------------------------------------| + * + * The message is interpreted as follows: + * + * dword0 - b'0:7 - msg_type: This will be set to + * HTT_T2H_MSG_TYPE_MAP_FLOW_INFO + * + * dword0 - b'8:27 - fse_hsh_idx: Flow search table index provided by host + * for this flow entry + * + * dword0 - b'28:31 - rsvd0: Reserved for future use + * + * dword1 - b'0:13 - peer_id: Software peer id given by host during association + * + * dword1 - b'14:17 - tid + * + * dword1 - b'18:31 - rsvd1: Reserved for future use + * + * dword2 - b'0:31 - tqm_flow_pntr_lo: Lower 32 bits of TQM flow pointer + * + * dword3 - b'0:31 - tqm_flow_pntr_hi: Higher 32 bits of TQM flow pointer + * + * dword4 - b'0:31 - fse_meta_data: Replay back TX flow search metadata + * given by host + */ +PREPACK struct htt_tx_map_flow_info { + A_UINT32 + msg_type: 8, + fse_hsh_idx: 20, + rsvd0: 4; + A_UINT32 + peer_id: 14, + tid: 4, + rsvd1: 14; + A_UINT32 tqm_flow_pntr_lo; + A_UINT32 tqm_flow_pntr_hi; + struct htt_tx_flow_metadata fse_meta_data; +} POSTPACK; + +/* DWORD 0 */ +#define HTT_TX_MAP_FLOW_INFO_FSE_HSH_IDX_M 0x0fffff00 +#define HTT_TX_MAP_FLOW_INFO_FSE_HSH_IDX_S 8 + +/* DWORD 1 */ +#define HTT_TX_MAP_FLOW_INFO_PEER_ID_M 0x00003fff +#define HTT_TX_MAP_FLOW_INFO_PEER_ID_S 0 +#define HTT_TX_MAP_FLOW_INFO_TID_M 0x0003c000 +#define HTT_TX_MAP_FLOW_INFO_TID_S 14 + +/* DWORD 0 */ +#define HTT_TX_MAP_FLOW_INFO_FSE_HSH_IDX_GET(_var) \ + (((_var) & HTT_TX_MAP_FLOW_INFO_FSE_HSH_IDX_M) >> \ + HTT_TX_MAP_FLOW_INFO_FSE_HSH_IDX_S) +#define HTT_TX_MAP_FLOW_INFO_FSE_HSH_IDX_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_TX_MAP_FLOW_INFO_FSE_HSH_IDX, _val); \ + ((_var) |= ((_val) << HTT_TX_MAP_FLOW_INFO_FSE_HSH_IDX_S)); \ + } while (0) + +/* DWORD 1 */ +#define HTT_TX_MAP_FLOW_INFO_PEER_ID_GET(_var) \ + (((_var) & HTT_TX_MAP_FLOW_INFO_PEER_ID_M) >> \ + HTT_TX_MAP_FLOW_INFO_PEER_ID_S) +#define HTT_TX_MAP_FLOW_INFO_PEER_ID_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_TX_MAP_FLOW_INFO_PEER_ID_IDX, _val); \ + ((_var) |= ((_val) << HTT_TX_MAP_FLOW_INFO_PEER_ID_S)); \ + } while (0) + +#define HTT_TX_MAP_FLOW_INFO_TID_GET(_var) \ + (((_var) & HTT_TX_MAP_FLOW_INFO_TID_M) >> \ + HTT_TX_MAP_FLOW_INFO_TID_S) +#define HTT_TX_MAP_FLOW_INFO_TID_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_TX_MAP_FLOW_INFO_TID_IDX, _val); \ + ((_var) |= ((_val) << HTT_TX_MAP_FLOW_INFO_TID_S)); \ + } while (0) + +#endif diff --git a/drivers/staging/fw-api/fw/htt_common.h b/drivers/staging/fw-api/fw/htt_common.h new file mode 100755 index 0000000000000000000000000000000000000000..8f4d82fe72e3e17be0cb4515d1faf8851f542b93 --- /dev/null +++ b/drivers/staging/fw-api/fw/htt_common.h @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * @file htt_common.h + * + * @details the public header file of HTT layer shared between host and firmware + */ + +#ifndef _HTT_COMMON_H_ +#define _HTT_COMMON_H_ + +enum htt_sec_type { + htt_sec_type_none, + htt_sec_type_wep128, + htt_sec_type_wep104, + htt_sec_type_wep40, + htt_sec_type_tkip, + htt_sec_type_tkip_nomic, + htt_sec_type_aes_ccmp, + htt_sec_type_wapi, + htt_sec_type_aes_ccmp_256, + htt_sec_type_aes_gcmp, + htt_sec_type_aes_gcmp_256, + + /* keep this last! */ + htt_num_sec_types +}; + +enum htt_rx_ind_mpdu_status { + HTT_RX_IND_MPDU_STATUS_UNKNOWN = 0x0, + HTT_RX_IND_MPDU_STATUS_OK, + HTT_RX_IND_MPDU_STATUS_ERR_FCS, + HTT_RX_IND_MPDU_STATUS_ERR_DUP, + HTT_RX_IND_MPDU_STATUS_ERR_REPLAY, + HTT_RX_IND_MPDU_STATUS_ERR_INV_PEER, + HTT_RX_IND_MPDU_STATUS_UNAUTH_PEER, /* only accept EAPOL frames */ + HTT_RX_IND_MPDU_STATUS_OUT_OF_SYNC, + HTT_RX_IND_MPDU_STATUS_MGMT_CTRL, /* Non-data in promiscous mode */ + HTT_RX_IND_MPDU_STATUS_TKIP_MIC_ERR, + HTT_RX_IND_MPDU_STATUS_DECRYPT_ERR, + HTT_RX_IND_MPDU_STATUS_MPDU_LENGTH_ERR, + HTT_RX_IND_MPDU_STATUS_ENCRYPT_REQUIRED_ERR, + HTT_RX_IND_MPDU_STATUS_PRIVACY_ERR, + + /* + * MISC: discard for unspecified reasons. + * Leave this enum value last. + */ + HTT_RX_IND_MPDU_STATUS_ERR_MISC = 0xFF +}; + +#define HTT_INVALID_PEER 0xffff +#define HTT_INVALID_VDEV 0xff + +#define HTT_NON_QOS_TID 16 +#define HTT_INVALID_TID 31 + +#define HTT_TX_EXT_TID_DEFAULT 0 +#define HTT_TX_EXT_TID_NON_QOS_MCAST_BCAST HTT_NON_QOS_TID +#define HTT_TX_EXT_TID_MGMT 17 +#define HTT_TX_EXT_TID_INVALID HTT_INVALID_TID +#define HTT_TX_EXT_TID_NONPAUSE 19 + + + +#define HTT_TX_L3_CKSUM_OFFLOAD 1 +#define HTT_TX_L4_CKSUM_OFFLOAD 2 + + +/** + * @brief General specification of the tx frame contents + * + * @details + * For efficiency, the HTT packet type values correspond + * to the bit positions of the WAL packet type values, so the + * translation is a simple shift operation. + * The exception is the "mgmt" type, which specifies frame payload + * type rather than L2 header type. + */ +enum htt_pkt_type { + htt_pkt_type_raw = 0, + htt_pkt_type_native_wifi = 1, + htt_pkt_type_ethernet = 2, + htt_pkt_type_mgmt = 3, + htt_pkt_type_eth2 = 4, + + /* keep this last */ + htt_pkt_num_types +}; + +/* + * TX MSDU ID partition - + * FW supports bigger MSDU ID partition which is defined as + * HTT_TX_IPA_NEW_MSDU_ID_SPACE_BEGIN + * When both host and FW support new partition, FW uses + * HTT_TX_IPA_NEW_MSDU_ID_SPACE_BEGIN + * If host doesn't support, FW falls back to HTT_TX_IPA_MSDU_ID_SPACE_BEGIN + * Handshaking is done through WMI_READY and WMI_INIT + */ +#define HTT_TX_HOST_MSDU_ID_SPACE_BEGIN 0 +#define HTT_TX_IPA_MSDU_ID_SPACE_BEGIN 3000 +#define TGT_RX2TX_MSDU_ID_SPACE_BEGIN 6000 +/* 8192 = 0xr2000 */ +#define HTT_TX_IPA_NEW_MSDU_ID_SPACE_BEGIN 8192 +/* 12288 = 0x3000 */ +#define TGT_RX2TX_NEW_MSDU_ID_SPACE_BEGIN 12288 + +#endif /* _HTT_COMMON_H_ */ diff --git a/drivers/staging/fw-api/fw/htt_isoc.h b/drivers/staging/fw-api/fw/htt_isoc.h new file mode 100644 index 0000000000000000000000000000000000000000..e0bca712e322143cbcd2a653e8692997e8e18231 --- /dev/null +++ b/drivers/staging/fw-api/fw/htt_isoc.h @@ -0,0 +1,1244 @@ +/* + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * @file htt_isoc.h + * + * @details + * This file defines the target --> host messages that configure the + * host data-path SW with the information required for data transfers + * to and from the target. + */ + +#ifndef _HTT_ISOC_H_ +#define _HTT_ISOC_H_ + +#include /* A_UINT32, A_UINT8 */ +#include /* A_COMPILE_TIME_ASSERT */ + +#ifdef ATHR_WIN_NWF +#pragma warning(disable:4214) /* bit field types other than int */ +#endif + +#include "htt_common.h" + +/*=== definitions that apply to all messages ================================*/ + +typedef enum htt_isoc_t2h_msg_type { + /* 0x0 reserved for VERSION message (probably not needed) */ + + /* PEER_INFO - specify ID and parameters of a new peer */ + HTT_ISOC_T2H_MSG_TYPE_PEER_INFO = 0x1, + + /* PEER_UNMAP - deallocate the ID that refers to a peer */ + HTT_ISOC_T2H_MSG_TYPE_PEER_UNMAP = 0x2, + + /* ADDBA - start rx aggregation for the specified peer-TID */ + HTT_ISOC_T2H_MSG_TYPE_RX_ADDBA = 0x3, + + /* DELBA - stop rx aggregation for the specified peer-TID */ + HTT_ISOC_T2H_MSG_TYPE_RX_DELBA = 0x4, + + /* TX_COMPL_IND - over-the-air tx completion notification for a tx frame */ + HTT_ISOC_T2H_MSG_TYPE_TX_COMPL_IND = 0x5, + + /* SEC_IND - notification of the type of security used for a new peer */ + HTT_ISOC_T2H_MSG_TYPE_SEC_IND = 0x6, + + /* PEER_TX_READY - the target is ready to transmit to a new peer */ + HTT_ISOC_T2H_MSG_TYPE_PEER_TX_READY = 0x7, + + /* RX_ERR - notification that an rx frame was discarded due to errors */ + HTT_ISOC_T2H_MSG_TYPE_RX_ERR = 0x8, + + /* NLO_MATCH - notification that target found NLO match */ + HTT_ISOC_T2H_MSG_TYPE_NLO_MATCH = 0x9, + + /* NLO_SCAN_END - notification that target NLO SCAN END 1:1 map with NLO_MATCH */ + HTT_ISOC_T2H_MSG_TYPE_NLO_SCAN_END = 0xA, + /* keep this last */ + HTT_ISOC_T2H_NUM_MSGS +} htt_isoc_t2h_msg_type; + +/* + * HTT ISOC target to host message type - + * stored in bits 7:0 of the first word of the message + */ +#define HTT_ISOC_T2H_MSG_TYPE_M 0xff +#define HTT_ISOC_T2H_MSG_TYPE_S 0 + +#define HTT_ISOC_T2H_MSG_TYPE_SET(msg_addr, msg_type) \ + (*((A_UINT8 *) msg_addr) = (msg_type)) +#define HTT_ISOC_T2H_MSG_TYPE_GET(msg_addr) \ + (*((A_UINT8 *) msg_addr)) + +#ifndef INLINE +#ifdef QCA_SUPPORT_INTEGRATED_SOC +/* host SW */ +#define INLINE inline +#else +/* target FW */ +#define INLINE __inline +#endif +#define HTT_ISOC_INLINE_DEF +#endif /* INLINE */ + +static INLINE void +htt_isoc_t2h_field_set( + A_UINT32 *msg_addr32, + unsigned offset32, + unsigned mask, + unsigned shift, + unsigned value) +{ + /* sanity check: make sure the value fits within the field */ + /* qdf_assert(value << shift == (value << shift) | mask); */ + + msg_addr32 += offset32; + /* clear the field */ + *msg_addr32 &= ~mask; + /* write the new value */ + *msg_addr32 |= (value << shift); +} + +#ifdef HTT_ISOC_INLINE_DEF +#undef HTT_ISOC_INLINE_DEF +#undef INLINE +#endif + +#define HTT_ISOC_T2H_FIELD_GET(msg_addr32, offset32, mask, shift) \ + (((*(msg_addr32 + offset32)) & mask) >> shift) + +typedef enum { + /* ASSOC - "real" peer from STA-AP association */ + HTT_ISOC_T2H_PEER_TYPE_ASSOC = 0x0, + + /* SELF - self-peer for unicast tx to unassociated peer */ + HTT_ISOC_T2H_PEER_TYPE_SELF = 0x1, + + /* BSSID - reserved for FW use for BT-AMP+IBSS */ + HTT_ISOC_T2H_PEER_TYPE_BSSID = 0x2, + + /* BCAST - self-peer for multicast / broadcast tx */ + HTT_ISOC_T2H_PEER_TYPE_BCAST = 0x3 +} HTT_ISOC_T2H_PEER_TYPE_ENUM; + +enum { + HTT_ISOC_NON_QOS = 0, + HTT_ISOC_QOS = 1 +}; + +enum { + HTT_ISOC_RMF_DISABLED = 0, + HTT_ISOC_RMF_ENABLED = 1 +}; + +enum { + HTT_ISOC_TID_MGMT = 7 +}; + +/*=== definitions for specific messages =====================================*/ + +/*=== PEER_INFO message ===*/ + +/** + * @brief target -> host peer info message definition + * + * @details + * The following diagram shows the format of the peer info message sent + * from the target to the host. This layout assumes the target operates + * as little-endian. + * + * |31 25|24|23 18|17|16|15 11|10|9|8|7|6| 0| + * |-----------------------------------------------------------------------| + * | mgmt DPU idx | bcast DPU idx | DPU idx | msg type | + * |-----------------------------------------------------------------------| + * | mgmt DPU sig |bcast DPU sig | DPU sig | peer ID | + * |-----------------------------------------------------------------------| + * | MAC addr 1 | MAC addr 0 | vdev ID | |R| peer type | + * |-----------------------------------------------------------------------| + * | MAC addr 5 | MAC addr 4 | MAC addr 3 | MAC addr 2 | + * |-----------------------------------------------------------------------| + * + * + * The following field definitions describe the format of the peer info + * message sent from the target to the host. + * + * WORD 0: + * - MSG_TYPE + * Bits 7:0 + * Purpose: identifies this as peer info message + * Value: 0x1 + * - DPU_IDX + * Bits 15:8 + * Purpose: specify the DPU index (a.k.a. security key ID) to use for + * unicast data frames sent to this peer + * Value: key ID + * - BCAST_DPU_IDX + * Bits 23:16 + * Purpose: specify the DPU index (a.k.a. security key ID) to use for + * broadcast data frames sent by this (self) peer + * Value: key ID + * - MGMT_DPU_IDX + * Bits 31:24 + * Purpose: specify the DPU index (a.k.a. security key ID) to use for + * unicast management frames sent by this (self) peer + * Value: key ID + * WORD 1: + * - PEER_ID + * Bits 10:0 + * Purpose: The ID that the target has allocated to refer to the peer + * - DPU_SIG + * Bits 17:11 + * Purpose: specify the DPU signature (a.k.a. security key validity + * magic number) to specify for unicast data frames sent to this peer + * - BCAST_DPU_SIG + * Bits 24:18 + * Purpose: specify the DPU signature (a.k.a. security key validity + * magic number) to specify for broadcast data frames sent by this + * (self) peer + * - MGMT_DPU_SIG + * Bits 31:25 + * Purpose: specify the DPU signature (a.k.a. security key validity + * magic number) to specify for unicast management frames sent by this + * (self) peer + * WORD 2: + * - PEER_TYPE + * Bits 5:0 + * Purpose: specify whether the peer in question is a real peer or + * one of the types of "self-peer" created for the vdev + * Value: HTT_ISOC_T2H_PEER_TYPE enum + * - RMF_ENABLED (R) + * Bit 6 + * Purpose: specify whether the peer in question has enable robust + * management frames, to encrypt certain managment frames + * Value: HTT_ISOC_RMF enum + * Value: HTT_ISOC_NON_QOS or HTT_ISOC_QOS + * - VDEV_ID + * Bits 15:8 + * Purpose: For a real peer, the vdev ID indicates which virtual device + * the peer is associated with. For a self-peer, the vdev ID shows + * which virtual device the self-peer represents. + * - MAC_ADDR_L16 + * Bits 31:16 + * Purpose: Identifies which peer the peer ID is for. + * Value: lower 2 bytes of the peer's MAC address + * For a self-peer, the peer's MAC address is the MAC address of the + * vdev the self-peer represents. + * WORD 3: + * - MAC_ADDR_U32 + * Bits 31:0 + * Purpose: Identifies which peer the peer ID is for. + * Value: upper 4 bytes of the peer's MAC address + * For a self-peer, the peer's MAC address is the MAC address of the + * vdev the self-peer represents. + */ +typedef struct htt_isoc_t2h_peer_info_s { + /* word 0 */ + A_UINT32 msg_type:8, /* HTT_ISOC_T2H_MSG_TYPE_PEER_INFO */ + dpu_idx:8, bcast_dpu_idx:8, mgmt_dpu_idx:8; + /* word 1 */ + A_UINT32 peer_id:11, dpu_sig:7, bcast_dpu_sig:7, mgmt_dpu_sig:7; + /* word 2 */ + A_UINT32 + peer_type:6, rmf_enabled:1, reserved0:1, vdev_id:8, mac_addr_l16:16; + /* word 3 */ + A_UINT32 mac_addr_u32; +} htt_isoc_t2h_peer_info_t; + +/* word 0 */ +#define HTT_ISOC_T2H_PEER_INFO_DPU_IDX_OFFSET32 0 +#define HTT_ISOC_T2H_PEER_INFO_DPU_IDX_M 0x0000ff00 +#define HTT_ISOC_T2H_PEER_INFO_DPU_IDX_S 8 + +#define HTT_ISOC_T2H_PEER_INFO_BCAST_DPU_IDX_OFFSET32 0 +#define HTT_ISOC_T2H_PEER_INFO_BCAST_DPU_IDX_M 0x00ff0000 +#define HTT_ISOC_T2H_PEER_INFO_BCAST_DPU_IDX_S 16 + +#define HTT_ISOC_T2H_PEER_INFO_MGMT_DPU_IDX_OFFSET32 0 +#define HTT_ISOC_T2H_PEER_INFO_MGMT_DPU_IDX_M 0xff000000 +#define HTT_ISOC_T2H_PEER_INFO_MGMT_DPU_IDX_S 24 + +/* word 1 */ +#define HTT_ISOC_T2H_PEER_INFO_PEER_ID_OFFSET32 1 +#define HTT_ISOC_T2H_PEER_INFO_PEER_ID_M 0x000007ff +#define HTT_ISOC_T2H_PEER_INFO_PEER_ID_S 0 + +#define HTT_ISOC_T2H_PEER_INFO_DPU_SIG_OFFSET32 1 +#define HTT_ISOC_T2H_PEER_INFO_DPU_SIG_M 0x0003f800 +#define HTT_ISOC_T2H_PEER_INFO_DPU_SIG_S 11 + +#define HTT_ISOC_T2H_PEER_INFO_BCAST_DPU_SIG_OFFSET32 1 +#define HTT_ISOC_T2H_PEER_INFO_BCAST_DPU_SIG_M 0x01fc0000 +#define HTT_ISOC_T2H_PEER_INFO_BCAST_DPU_SIG_S 18 + +#define HTT_ISOC_T2H_PEER_INFO_MGMT_DPU_SIG_OFFSET32 1 +#define HTT_ISOC_T2H_PEER_INFO_MGMT_DPU_SIG_M 0xfe000000 +#define HTT_ISOC_T2H_PEER_INFO_MGMT_DPU_SIG_S 25 + +/* word 2 */ +#define HTT_ISOC_T2H_PEER_INFO_PEER_TYPE_OFFSET32 2 +#define HTT_ISOC_T2H_PEER_INFO_PEER_TYPE_M 0x0000003f +#define HTT_ISOC_T2H_PEER_INFO_PEER_TYPE_S 0 + +#define HTT_ISOC_T2H_PEER_INFO_RMF_ENABLED_OFFSET32 2 +#define HTT_ISOC_T2H_PEER_INFO_RMF_ENABLED_M 0x00000040 +#define HTT_ISOC_T2H_PEER_INFO_RMF_ENABLED_S 6 + +#define HTT_ISOC_T2H_PEER_INFO_VDEV_ID_OFFSET32 2 +#define HTT_ISOC_T2H_PEER_INFO_VDEV_ID_M 0x0000ff00 +#define HTT_ISOC_T2H_PEER_INFO_VDEV_ID_S 8 + +#define HTT_ISOC_T2H_PEER_INFO_MAC_ADDR_L16_OFFSET32 2 +#define HTT_ISOC_T2H_PEER_INFO_MAC_ADDR_L16_M 0xffff0000 +#define HTT_ISOC_T2H_PEER_INFO_MAC_ADDR_L16_S 16 + +/* word 3 */ +#define HTT_ISOC_T2H_PEER_INFO_MAC_ADDR_U32_OFFSET32 3 +#define HTT_ISOC_T2H_PEER_INFO_MAC_ADDR_U32_M 0xffffffff +#define HTT_ISOC_T2H_PEER_INFO_MAC_ADDR_U32_S 0 + +/* general field access macros */ + +#define HTT_ISOC_T2H_PEER_INFO_FIELD_SET(field, msg_addr, value) \ + htt_isoc_t2h_field_set( \ + ((A_UINT32 *) msg_addr), \ + HTT_ISOC_T2H_PEER_INFO_ ## field ## _OFFSET32, \ + HTT_ISOC_T2H_PEER_INFO_ ## field ## _M, \ + HTT_ISOC_T2H_PEER_INFO_ ## field ## _S, \ + value) + +#define HTT_ISOC_T2H_PEER_INFO_FIELD_GET(field, msg_addr) \ + HTT_ISOC_T2H_FIELD_GET( \ + ((A_UINT32 *) msg_addr), \ + HTT_ISOC_T2H_PEER_INFO_ ## field ## _OFFSET32, \ + HTT_ISOC_T2H_PEER_INFO_ ## field ## _M, \ + HTT_ISOC_T2H_PEER_INFO_ ## field ## _S) + +/* access macros for specific fields */ + +#define HTT_ISOC_T2H_PEER_INFO_DPU_IDX_SET(msg_addr, value) \ + HTT_ISOC_T2H_PEER_INFO_FIELD_SET(DPU_IDX, msg_addr, value) +#define HTT_ISOC_T2H_PEER_INFO_DPU_IDX_GET(msg_addr) \ + HTT_ISOC_T2H_PEER_INFO_FIELD_GET(DPU_IDX, msg_addr) + +A_COMPILE_TIME_ASSERT(HTT_ISOC_T2H_PEER_INFO_BCAST_DPU_IDX_M_Size_Check, + (HTT_ISOC_T2H_PEER_INFO_BCAST_DPU_IDX_M >> HTT_ISOC_T2H_PEER_INFO_BCAST_DPU_IDX_S) \ + <= ((A_UINT8)~((A_UINT8)0))); +#define HTT_ISOC_T2H_PEER_INFO_BCAST_DPU_IDX_SET(msg_addr, value) \ + HTT_ISOC_T2H_PEER_INFO_FIELD_SET(BCAST_DPU_IDX, msg_addr, value) +#define HTT_ISOC_T2H_PEER_INFO_BCAST_DPU_IDX_GET(msg_addr) \ + (A_UINT8)(HTT_ISOC_T2H_PEER_INFO_FIELD_GET(BCAST_DPU_IDX, msg_addr)) + +A_COMPILE_TIME_ASSERT(HTT_ISOC_T2H_PEER_INFO_MGMT_DPU_IDX_M_Size_Check, + (HTT_ISOC_T2H_PEER_INFO_MGMT_DPU_IDX_M >> HTT_ISOC_T2H_PEER_INFO_MGMT_DPU_IDX_S) \ + <= ((A_UINT8)~((A_UINT8)0))); +#define HTT_ISOC_T2H_PEER_INFO_MGMT_DPU_IDX_SET(msg_addr, value) \ + HTT_ISOC_T2H_PEER_INFO_FIELD_SET(MGMT_DPU_IDX, msg_addr, value) +#define HTT_ISOC_T2H_PEER_INFO_MGMT_DPU_IDX_GET(msg_addr) \ + (A_UINT8)(HTT_ISOC_T2H_PEER_INFO_FIELD_GET(MGMT_DPU_IDX, msg_addr)) + +#define HTT_ISOC_T2H_PEER_INFO_PEER_ID_SET(msg_addr, value) \ + HTT_ISOC_T2H_PEER_INFO_FIELD_SET(PEER_ID, msg_addr, value) +#define HTT_ISOC_T2H_PEER_INFO_PEER_ID_GET(msg_addr) \ + HTT_ISOC_T2H_PEER_INFO_FIELD_GET(PEER_ID, msg_addr) + +A_COMPILE_TIME_ASSERT(HTT_ISOC_T2H_PEER_INFO_DPU_SIG_M_Size_Check, + (HTT_ISOC_T2H_PEER_INFO_DPU_SIG_M >> HTT_ISOC_T2H_PEER_INFO_DPU_SIG_S)\ + <= ((A_UINT8)~((A_UINT8)0))); +#define HTT_ISOC_T2H_PEER_INFO_DPU_SIG_SET(msg_addr, value) \ + HTT_ISOC_T2H_PEER_INFO_FIELD_SET(DPU_SIG, msg_addr, value) +#define HTT_ISOC_T2H_PEER_INFO_DPU_SIG_GET(msg_addr) \ + (A_UINT8)(HTT_ISOC_T2H_PEER_INFO_FIELD_GET(DPU_SIG, msg_addr)) + +A_COMPILE_TIME_ASSERT(HTT_ISOC_T2H_PEER_INFO_BCAST_DPU_SIG_M_Size_Check, + (HTT_ISOC_T2H_PEER_INFO_BCAST_DPU_SIG_M >> HTT_ISOC_T2H_PEER_INFO_BCAST_DPU_SIG_S)\ + <= ((A_UINT8)~((A_UINT8)0))); +#define HTT_ISOC_T2H_PEER_INFO_BCAST_DPU_SIG_SET(msg_addr, value) \ + HTT_ISOC_T2H_PEER_INFO_FIELD_SET(BCAST_DPU_SIG, msg_addr, value) +#define HTT_ISOC_T2H_PEER_INFO_BCAST_DPU_SIG_GET(msg_addr) \ + (A_UINT8)(HTT_ISOC_T2H_PEER_INFO_FIELD_GET(BCAST_DPU_SIG, msg_addr)) + +#define HTT_ISOC_T2H_PEER_INFO_MGMT_DPU_SIG_SET(msg_addr, value) \ + HTT_ISOC_T2H_PEER_INFO_FIELD_SET(MGMT_DPU_SIG, msg_addr, value) +#define HTT_ISOC_T2H_PEER_INFO_MGMT_DPU_SIG_GET(msg_addr) \ + HTT_ISOC_T2H_PEER_INFO_FIELD_GET(MGMT_DPU_SIG, msg_addr) + +#define HTT_ISOC_T2H_PEER_INFO_PEER_TYPE_SET(msg_addr, value) \ + HTT_ISOC_T2H_PEER_INFO_FIELD_SET(PEER_TYPE, msg_addr, value) +#define HTT_ISOC_T2H_PEER_INFO_PEER_TYPE_GET(msg_addr) \ + HTT_ISOC_T2H_PEER_INFO_FIELD_GET(PEER_TYPE, msg_addr) + +#define HTT_ISOC_T2H_PEER_INFO_QOS_CAPABLE_SET(msg_addr, value) \ + HTT_ISOC_T2H_PEER_INFO_FIELD_SET(QOS_CAPABLE, msg_addr, value) +#define HTT_ISOC_T2H_PEER_INFO_QOS_CAPABLE_GET(msg_addr) \ + HTT_ISOC_T2H_PEER_INFO_FIELD_GET(QOS_CAPABLE, msg_addr) + +#define HTT_ISOC_T2H_PEER_INFO_RMF_ENABLED_SET(msg_addr, value) \ + HTT_ISOC_T2H_PEER_INFO_FIELD_SET(RMF_ENABLED, msg_addr, value) +#define HTT_ISOC_T2H_PEER_INFO_RMF_ENABLED_GET(msg_addr) \ + HTT_ISOC_T2H_PEER_INFO_FIELD_GET(RMF_ENABLED, msg_addr) + +#define HTT_ISOC_T2H_PEER_INFO_VDEV_ID_SET(msg_addr, value) \ + HTT_ISOC_T2H_PEER_INFO_FIELD_SET(VDEV_ID, msg_addr, value) +#define HTT_ISOC_T2H_PEER_INFO_VDEV_ID_GET(msg_addr) \ + HTT_ISOC_T2H_PEER_INFO_FIELD_GET(VDEV_ID, msg_addr) + +#define HTT_ISOC_T2H_PEER_INFO_MAC_ADDR_L16_SET(msg_addr, value) \ + HTT_ISOC_T2H_PEER_INFO_FIELD_SET(MAC_ADDR_L16, msg_addr, value) +#define HTT_ISOC_T2H_PEER_INFO_MAC_ADDR_L16_GET(msg_addr) \ + HTT_ISOC_T2H_PEER_INFO_FIELD_GET(MAC_ADDR_L16, msg_addr) + +#define HTT_ISOC_T2H_PEER_INFO_MAC_ADDR_U32_SET(msg_addr, value) \ + HTT_ISOC_T2H_PEER_INFO_FIELD_SET(MAC_ADDR_U32, msg_addr, value) +#define HTT_ISOC_T2H_PEER_INFO_MAC_ADDR_U32_GET(msg_addr) \ + HTT_ISOC_T2H_PEER_INFO_FIELD_GET(MAC_ADDR_U32, msg_addr) + +/*=== PEER_UNMAP message ===*/ + +/** + * @brief target -> host peer unmap message definition + * + * @details + * The following diagram shows the format of the peer unmap message sent + * from the target to the host. This layout assumes the target operates + * as little-endian. + * + * |31 19|18 8|7 0| + * |-----------------------------------------------------------------------| + * | reserved | peer ID | msg type | + * |-----------------------------------------------------------------------| + * + * + * The following field definitions describe the format of the peer info + * message sent from the target to the host. + * + * WORD 0: + * - MSG_TYPE + * Bits 7:0 + * Purpose: identifies this as peer unmap message + * Value: 0x2 + * - PEER_ID + * Bits 18:8 + * Purpose: The ID that the target has allocated to refer to the peer + */ +typedef struct htt_isoc_t2h_peer_unmap_s { + /* word 0 */ + A_UINT32 msg_type:8, /* HTT_ISOC_T2H_MSG_TYPE_PEER_UNMAP */ + peer_id:11, reserved0:13; +} htt_isoc_t2h_peer_unmap_t; + +/* word 0 */ +#define HTT_ISOC_T2H_PEER_UNMAP_PEER_ID_OFFSET32 0 +#define HTT_ISOC_T2H_PEER_UNMAP_PEER_ID_M 0x0007ff00 +#define HTT_ISOC_T2H_PEER_UNMAP_PEER_ID_S 8 + +/* general field access macros */ + +#define HTT_ISOC_T2H_PEER_UNMAP_FIELD_SET(field, msg_addr, value) \ + htt_isoc_t2h_field_set( \ + ((A_UINT32 *) msg_addr), \ + HTT_ISOC_T2H_PEER_UNMAP_ ## field ## _OFFSET32, \ + HTT_ISOC_T2H_PEER_UNMAP_ ## field ## _M, \ + HTT_ISOC_T2H_PEER_UNMAP_ ## field ## _S, \ + value) + +#define HTT_ISOC_T2H_PEER_UNMAP_FIELD_GET(field, msg_addr) \ + HTT_ISOC_T2H_FIELD_GET( \ + ((A_UINT32 *) msg_addr), \ + HTT_ISOC_T2H_PEER_UNMAP_ ## field ## _OFFSET32, \ + HTT_ISOC_T2H_PEER_UNMAP_ ## field ## _M, \ + HTT_ISOC_T2H_PEER_UNMAP_ ## field ## _S) + +/* access macros for specific fields */ + +A_COMPILE_TIME_ASSERT(HTT_ISOC_T2H_PEER_UNMAP_PEER_ID_M_Size_Check, + (HTT_ISOC_T2H_PEER_UNMAP_PEER_ID_M >> HTT_ISOC_T2H_PEER_UNMAP_PEER_ID_S) \ + < ((A_UINT16)~((A_UINT16)0))); +#define HTT_ISOC_T2H_PEER_UNMAP_PEER_ID_SET(msg_addr, value) \ + HTT_ISOC_T2H_PEER_UNMAP_FIELD_SET(PEER_ID, msg_addr, value) +#define HTT_ISOC_T2H_PEER_UNMAP_PEER_ID_GET(msg_addr) \ + (A_UINT16)(HTT_ISOC_T2H_PEER_UNMAP_FIELD_GET(PEER_ID, msg_addr)) + +/*=== ADDBA message ===*/ +enum { + htt_isoc_addba_success = 0, + /* TBD: use different failure values to specify failure causes? */ + htt_isoc_addba_fail = 1, +}; + +/** + * @brief target -> host ADDBA message definition + * + * @details + * The following diagram shows the format of the rx ADDBA message sent + * from the target to the host: + * + * |31 20|19 16|15 12|11 8|7 0| + * |---------------------------------------------------------------------| + * | peer ID | TID | window size | msg type | + * |---------------------------------------------------------------------| + * | reserved |S| start seq num | + * |---------------------------------------------------------------------| + * + * The following field definitions describe the format of the ADDBA + * message sent from the target to the host. + * + * WORD 0: + * - MSG_TYPE + * Bits 7:0 + * Purpose: identifies this as an ADDBA message + * Value: 0x3 + * - WIN_SIZE + * Bits 15:8 + * Purpose: Specifies the length of the block ack window (max = 64). + * Value: + * block ack window length specified by the received ADDBA + * management message. + * - TID + * Bits 19:16 + * Purpose: Specifies which traffic identifier the ADDBA is for. + * Value: + * TID specified by the received ADDBA management message. + * - PEER_ID + * Bits 31:20 + * Purpose: Identifies which peer sent the ADDBA. + * Value: + * ID (hash value) used by the host for fast, direct lookup of + * host SW peer info, including rx reorder states. + * - START_SEQ_NUM + * Bits 11:0 + * Purpose: Specifies the initial location of the block ack window + * Value: start sequence value specified by the ADDBA-request message + * - STATUS + * Bit 12 + * Purpose: status of the WMI ADDBA request + * Value: 0 - SUCCESS, 1 - FAILURE + */ +typedef struct htt_isoc_t2h_addba_s { + /* word 0 */ + A_UINT32 msg_type:8, /* HTT_ISOC_T2H_MSG_TYPE_ADDBA */ + win_size:8, tid:4, peer_id:12; + /* word 1 */ + A_UINT32 start_seq_num:12, status:1, reserved0:19; +} htt_isoc_t2h_addba_t; + +/* word 0 */ +#define HTT_ISOC_T2H_ADDBA_WIN_SIZE_OFFSET32 0 +#define HTT_ISOC_T2H_ADDBA_WIN_SIZE_M 0x0000ff00 +#define HTT_ISOC_T2H_ADDBA_WIN_SIZE_S 8 + +#define HTT_ISOC_T2H_ADDBA_TID_OFFSET32 0 +#define HTT_ISOC_T2H_ADDBA_TID_M 0x000f0000 +#define HTT_ISOC_T2H_ADDBA_TID_S 16 + +#define HTT_ISOC_T2H_ADDBA_PEER_ID_OFFSET32 0 +#define HTT_ISOC_T2H_ADDBA_PEER_ID_M 0xfff00000 +#define HTT_ISOC_T2H_ADDBA_PEER_ID_S 20 + +/* word 1 */ +#define HTT_ISOC_T2H_ADDBA_START_SEQ_NUM_OFFSET32 1 +#define HTT_ISOC_T2H_ADDBA_START_SEQ_NUM_M 0x00000fff +#define HTT_ISOC_T2H_ADDBA_START_SEQ_NUM_S 0 + +#define HTT_ISOC_T2H_ADDBA_STATUS_OFFSET32 1 +#define HTT_ISOC_T2H_ADDBA_STATUS_M 0x00001000 +#define HTT_ISOC_T2H_ADDBA_STATUS_S 12 + +/* general field access macros */ +#define HTT_ISOC_T2H_ADDBA_FIELD_SET(field, msg_addr, value) \ + htt_isoc_t2h_field_set( \ + ((A_UINT32 *) msg_addr), \ + HTT_ISOC_T2H_ADDBA_ ## field ## _OFFSET32, \ + HTT_ISOC_T2H_ADDBA_ ## field ## _M, \ + HTT_ISOC_T2H_ADDBA_ ## field ## _S, \ + value) + +#define HTT_ISOC_T2H_ADDBA_FIELD_GET(field, msg_addr) \ + HTT_ISOC_T2H_FIELD_GET( \ + ((A_UINT32 *) msg_addr), \ + HTT_ISOC_T2H_ADDBA_ ## field ## _OFFSET32, \ + HTT_ISOC_T2H_ADDBA_ ## field ## _M, \ + HTT_ISOC_T2H_ADDBA_ ## field ## _S) + +/* access macros for specific fields */ + +#define HTT_ISOC_T2H_ADDBA_WIN_SIZE_SET(msg_addr, value) \ + HTT_ISOC_T2H_ADDBA_FIELD_SET(WIN_SIZE, msg_addr, value) +#define HTT_ISOC_T2H_ADDBA_WIN_SIZE_GET(msg_addr) \ + HTT_ISOC_T2H_ADDBA_FIELD_GET(WIN_SIZE, msg_addr) + +A_COMPILE_TIME_ASSERT(HTT_ISOC_T2H_ADDBA_TID_M_Size_Check, + (HTT_ISOC_T2H_ADDBA_TID_M >> HTT_ISOC_T2H_ADDBA_TID_S) \ + < ((A_UINT8)~((A_UINT8)0))); +#define HTT_ISOC_T2H_ADDBA_TID_SET(msg_addr, value) \ + HTT_ISOC_T2H_ADDBA_FIELD_SET(TID, msg_addr, value) +#define HTT_ISOC_T2H_ADDBA_TID_GET(msg_addr) \ + (A_UINT8)(HTT_ISOC_T2H_ADDBA_FIELD_GET(TID, msg_addr)) + +#define HTT_ISOC_T2H_ADDBA_PEER_ID_SET(msg_addr, value) \ + HTT_ISOC_T2H_ADDBA_FIELD_SET(PEER_ID, msg_addr, value) +#define HTT_ISOC_T2H_ADDBA_PEER_ID_GET(msg_addr) \ + HTT_ISOC_T2H_ADDBA_FIELD_GET(PEER_ID, msg_addr) + +#define HTT_ISOC_T2H_ADDBA_START_SEQ_NUM_SET(msg_addr, value) \ + HTT_ISOC_T2H_ADDBA_FIELD_SET(START_SEQ_NUM, msg_addr, value) +#define HTT_ISOC_T2H_ADDBA_START_SEQ_NUM_GET(msg_addr) \ + HTT_ISOC_T2H_ADDBA_FIELD_GET(START_SEQ_NUM, msg_addr) + +#define HTT_ISOC_T2H_ADDBA_STATUS_SET(msg_addr, value) \ + HTT_ISOC_T2H_ADDBA_FIELD_SET(STATUS, msg_addr, value) +#define HTT_ISOC_T2H_ADDBA_STATUS_GET(msg_addr) \ + HTT_ISOC_T2H_ADDBA_FIELD_GET(STATUS, msg_addr) + +/*=== DELBA message ===*/ + +/** + * @brief target -> host DELBA message definition + * + * @details + * The following diagram shows the format of the rx DELBA message sent + * from the target to the host: + * + * |31 20|19 16|15 12|11 8|7 0| + * |---------------------------------------------------------------------| + * | peer ID | TID | reserved |S| msg type | + * |---------------------------------------------------------------------| + * + * The following field definitions describe the format of the ADDBA + * message sent from the target to the host. + * + * WORD 0: + * - MSG_TYPE + * Bits 7:0 + * Purpose: identifies this as an DELBA message + * Value: 0x4 + * - TID + * Bits 19:16 + * Purpose: Specifies which traffic identifier the DELBA is for. + * Value: + * TID specified by the received DELBA management message. + * - PEER_ID + * Bits 31:20 + * Purpose: Identifies which peer sent the DELBA. + * Value: + * ID (hash value) used by the host for fast, direct lookup of + * host SW peer info, including rx reorder states. + * - STATUS + * Bit 8 + * Purpose: status of the WMI DELBA request + * Value: 0 - SUCCESS, 1 - FAILURE + */ +typedef struct htt_isoc_t2h_delba_s { + /* word 0 */ + A_UINT32 msg_type:8, /* HTT_ISOC_T2H_MSG_TYPE_DELBA */ + status:1, reserved0:7, tid:4, peer_id:12; +} htt_isoc_t2h_delba_t; + +/* word 0 */ +#define HTT_ISOC_T2H_DELBA_TID_OFFSET32 0 +#define HTT_ISOC_T2H_DELBA_TID_M 0x000f0000 +#define HTT_ISOC_T2H_DELBA_TID_S 16 + +#define HTT_ISOC_T2H_DELBA_PEER_ID_OFFSET32 0 +#define HTT_ISOC_T2H_DELBA_PEER_ID_M 0xfff00000 +#define HTT_ISOC_T2H_DELBA_PEER_ID_S 20 + +#define HTT_ISOC_T2H_DELBA_STATUS_OFFSET32 0 +#define HTT_ISOC_T2H_DELBA_STATUS_M 0x00000100 +#define HTT_ISOC_T2H_DELBA_STATUS_S 8 + +/* general field access macros */ + +#define HTT_ISOC_T2H_DELBA_FIELD_SET(field, msg_addr, value) \ + htt_isoc_t2h_field_set( \ + ((A_UINT32 *) msg_addr), \ + HTT_ISOC_T2H_DELBA_ ## field ## _OFFSET32, \ + HTT_ISOC_T2H_DELBA_ ## field ## _M, \ + HTT_ISOC_T2H_DELBA_ ## field ## _S, \ + value) + +#define HTT_ISOC_T2H_DELBA_FIELD_GET(field, msg_addr) \ + HTT_ISOC_T2H_FIELD_GET( \ + ((A_UINT32 *) msg_addr), \ + HTT_ISOC_T2H_DELBA_ ## field ## _OFFSET32, \ + HTT_ISOC_T2H_DELBA_ ## field ## _M, \ + HTT_ISOC_T2H_DELBA_ ## field ## _S) + +/* access macros for specific fields */ + +A_COMPILE_TIME_ASSERT(HTT_ISOC_T2H_DELBA_TID_M_Size_Check, + (HTT_ISOC_T2H_DELBA_TID_M >> HTT_ISOC_T2H_DELBA_TID_S) \ + < ((A_UINT8)~((A_UINT8)0))); +#define HTT_ISOC_T2H_DELBA_TID_SET(msg_addr, value) \ + HTT_ISOC_T2H_DELBA_FIELD_SET(TID, msg_addr, value) +#define HTT_ISOC_T2H_DELBA_TID_GET(msg_addr) \ + (A_UINT8)HTT_ISOC_T2H_DELBA_FIELD_GET(TID, msg_addr) + +#define HTT_ISOC_T2H_DELBA_PEER_ID_SET(msg_addr, value) \ + HTT_ISOC_T2H_DELBA_FIELD_SET(PEER_ID, msg_addr, value) +#define HTT_ISOC_T2H_DELBA_PEER_ID_GET(msg_addr) \ + HTT_ISOC_T2H_DELBA_FIELD_GET(PEER_ID, msg_addr) + +#define HTT_ISOC_T2H_DELBA_STATUS_SET(msg_addr, value) \ + HTT_ISOC_T2H_DELBA_FIELD_SET(STATUS, msg_addr, value) +#define HTT_ISOC_T2H_DELBA_STATUS_GET(msg_addr) \ + HTT_ISOC_T2H_DELBA_FIELD_GET(STATUS, msg_addr) + +/*=== SEC_IND message ===*/ + +/** + * @brief target -> host Security indication message definition + * + * @details + * The following diagram shows the format of the SEC_IND message sent + * from the target to the host. This layout assumes the target operates + * as little-endian. + * + * |31 25|24|23 18|17|16|15 11|10|9|8|7|6| 0| + * |-----------------------------------------------------------------------| + * | is unicast | sec type | Peer id | msg type | + * |-----------------------------------------------------------------------| + * | mic key1 | + * |-----------------------------------------------------------------------| + * | mic key2 | + * |-----------------------------------------------------------------------| + * + * + * The following field definitions describe the format of the peer info + * message sent from the target to the host. + * + * WORD 0: + * - MSG_TYPE + * Bits 7:0 + * Purpose: identifies this as SEC_IND message + * Value: 0x6 + * - PEER_ID + * Bits 15:8 + * Purpose: The ID that the target has allocated to refer to the peer + * Value: Peer ID + * - SEC_TYPE + * Bits 23:16 + * Purpose: specify the security encryption type + * Value: htt_sec_type + * - is unicast + * Bits 31:24 + * Purpose: specify unicast/bcast + * Value: 1-unicast/0-bcast + * WORD 1: + * - MIC1 + * Bits 31:0 + * Purpose: Mickey1 + * WORD 2: + * - MIC2 + * Bits 31:0 + * Purpose: Mickey2 + */ +typedef struct htt_isoc_t2h_sec_ind_s { + /* word 0 */ + A_UINT32 msg_type:8, /* HTT_ISOC_T2H_MSG_TYPE_SEC_IND */ + peer_id:8, sec_type:8, is_unicast:8; + /* word 1 */ + A_UINT32 mic_key1; + /* word 2 */ + A_UINT32 mic_key2; + /* word 3 */ + A_UINT32 status; +} htt_isoc_t2h_sec_ind_t; + +/* word 0 */ +#define HTT_ISOC_T2H_SEC_IND_PEER_ID_OFFSET32 0 +#define HTT_ISOC_T2H_SEC_IND_PEER_ID_M 0x0000ff00 +#define HTT_ISOC_T2H_SEC_IND_PEER_ID_S 8 + +#define HTT_ISOC_T2H_SEC_IND_SEC_TYPE_OFFSET32 0 +#define HTT_ISOC_T2H_SEC_IND_SEC_TYPE_M 0x00ff0000 +#define HTT_ISOC_T2H_SEC_IND_SEC_TYPE_S 16 + +#define HTT_ISOC_T2H_SEC_IND_IS_UNICAST_OFFSET32 0 +#define HTT_ISOC_T2H_SEC_IND_IS_UNICAST_M 0xff000000 +#define HTT_ISOC_T2H_SEC_IND_IS_UNICAST_S 24 + +/* word 1 */ +#define HTT_ISOC_T2H_SEC_IND_MIC1_OFFSET32 1 +#define HTT_ISOC_T2H_SEC_IND_MIC1_M 0xffffffff +#define HTT_ISOC_T2H_SEC_IND_MIC1_S 0 + +/* word 2 */ +#define HTT_ISOC_T2H_SEC_IND_MIC2_OFFSET32 2 +#define HTT_ISOC_T2H_SEC_IND_MIC2_M 0xffffffff +#define HTT_ISOC_T2H_SEC_IND_MIC2_S 0 + +/* general field access macros */ +#define HTT_ISOC_T2H_SEC_IND_FIELD_SET(field, msg_addr, value) \ + htt_isoc_t2h_field_set( \ + ((A_UINT32 *) msg_addr), \ + HTT_ISOC_T2H_SEC_IND_ ## field ## _OFFSET32, \ + HTT_ISOC_T2H_SEC_IND_ ## field ## _M, \ + HTT_ISOC_T2H_SEC_IND_ ## field ## _S, \ + value) + +#define HTT_ISOC_T2H_SEC_IND_FIELD_GET(field, msg_addr) \ + HTT_ISOC_T2H_FIELD_GET( \ + ((A_UINT32 *) msg_addr), \ + HTT_ISOC_T2H_SEC_IND_ ## field ## _OFFSET32, \ + HTT_ISOC_T2H_SEC_IND_ ## field ## _M, \ + HTT_ISOC_T2H_SEC_IND_ ## field ## _S) + +/* access macros for specific fields */ +#define HTT_ISOC_T2H_SEC_IND_PEER_ID_SET(msg_addr, value) \ + HTT_ISOC_T2H_SEC_IND_FIELD_SET(PEER_ID, msg_addr, value) +#define HTT_ISOC_T2H_SEC_IND_PEER_ID_GET(msg_addr) \ + HTT_ISOC_T2H_SEC_IND_FIELD_GET(PEER_ID, msg_addr) + +#define HTT_ISOC_T2H_SEC_IND_SEC_TYPE_SET(msg_addr, value) \ + HTT_ISOC_T2H_SEC_IND_FIELD_SET(SEC_TYPE, msg_addr, value) +#define HTT_ISOC_T2H_SEC_IND_SEC_TYPE_GET(msg_addr) \ + HTT_ISOC_T2H_SEC_IND_FIELD_GET(SEC_TYPE, msg_addr) + +#define HTT_ISOC_T2H_SEC_IND_IS_UNICAST_SET(msg_addr, value) \ + HTT_ISOC_T2H_SEC_IND_FIELD_SET(IS_UNICAST, msg_addr, value) +#define HTT_ISOC_T2H_SEC_IND_IS_UNICAST_GET(msg_addr) \ + HTT_ISOC_T2H_SEC_IND_FIELD_GET(IS_UNICAST, msg_addr) + +#define HTT_ISOC_T2H_SEC_IND_MIC1_SET(msg_addr, value) \ + HTT_ISOC_T2H_SEC_IND_FIELD_SET(MIC1, msg_addr, value) +#define HTT_ISOC_T2H_SEC_IND_MIC1_GET(msg_addr) \ + HTT_ISOC_T2H_SEC_IND_FIELD_GET(MIC1, msg_addr) + +#define HTT_ISOC_T2H_SEC_IND_MIC2_SET(msg_addr, value) \ + HTT_ISOC_T2H_SEC_IND_FIELD_SET(MIC2, msg_addr, value) +#define HTT_ISOC_T2H_SEC_IND_MIC2_GET(msg_addr) \ + HTT_ISOC_T2H_SEC_IND_FIELD_GET(MIC2, msg_addr) + +/*=== PEER_TX_READY message ===*/ + +/** + * @brief target -> host peer tx ready message definition + * + * @details + * The following diagram shows the format of the peer tx ready message sent + * from the target to the host. This layout assumes the target operates + * as little-endian. + * + * |31 19|18 8|7 0| + * |-----------------------------------------------------------------------| + * | reserved | peer ID | msg type | + * |-----------------------------------------------------------------------| + * + * + * The following field definitions describe the format of the peer info + * message sent from the target to the host. + * + * WORD 0: + * - MSG_TYPE + * Bits 7:0 + * Purpose: identifies this as peer tx ready message + * Value: 0x7 + * - PEER_ID + * Bits 18:8 + * Purpose: The ID assigned to the peer by the PEER_INFO message + */ +typedef struct htt_isoc_t2h_peer_tx_ready_s { + /* word 0 */ + A_UINT32 msg_type:8, /* HTT_ISOC_T2H_MSG_TYPE_PEER_TX_READY */ + peer_id:11, reserved0:13; +} htt_isoc_t2h_peer_tx_ready_t; + +/* word 0 */ +#define HTT_ISOC_T2H_PEER_TX_READY_PEER_ID_OFFSET32 0 +#define HTT_ISOC_T2H_PEER_TX_READY_PEER_ID_M 0x0007ff00 +#define HTT_ISOC_T2H_PEER_TX_READY_PEER_ID_S 8 + +/* general field access macros */ + +#define HTT_ISOC_T2H_PEER_TX_READY_FIELD_SET(field, msg_addr, value) \ + htt_isoc_t2h_field_set( \ + ((A_UINT32 *) msg_addr), \ + HTT_ISOC_T2H_PEER_TX_READY_ ## field ## _OFFSET32, \ + HTT_ISOC_T2H_PEER_TX_READY_ ## field ## _M, \ + HTT_ISOC_T2H_PEER_TX_READY_ ## field ## _S, \ + value) + +#define HTT_ISOC_T2H_PEER_TX_READY_FIELD_GET(field, msg_addr) \ + HTT_ISOC_T2H_FIELD_GET( \ + ((A_UINT32 *) msg_addr), \ + HTT_ISOC_T2H_PEER_TX_READY_ ## field ## _OFFSET32, \ + HTT_ISOC_T2H_PEER_TX_READY_ ## field ## _M, \ + HTT_ISOC_T2H_PEER_TX_READY_ ## field ## _S) + +/* access macros for specific fields */ + +A_COMPILE_TIME_ASSERT(HTT_ISOC_T2H_PEER_TX_READY_PEER_ID_M_Size_Check, + (HTT_ISOC_T2H_PEER_TX_READY_PEER_ID_M >> \ + HTT_ISOC_T2H_PEER_TX_READY_PEER_ID_S) < ((A_UINT16)~((A_UINT16)0))); + +#define HTT_ISOC_T2H_PEER_TX_READY_PEER_ID_SET(msg_addr, value) \ + HTT_ISOC_T2H_PEER_TX_READY_FIELD_SET(PEER_ID, msg_addr, value) +#define HTT_ISOC_T2H_PEER_TX_READY_PEER_ID_GET(msg_addr) \ + ((A_UINT16)(HTT_ISOC_T2H_PEER_TX_READY_FIELD_GET(PEER_ID, msg_addr))) + + +/*=== RX_ERR message ===*/ + +/** + * @brief target -> host rx error notification message definition + * + * @details + * The following diagram shows the format of the rx err message sent + * from the target to the host. This layout assumes the target operates + * as little-endian. + * + * |31 16|15 8|7|6|5|4 0| + * |---------------------------------------------------------------------| + * | peer ID | rx err type | msg type | + * |---------------------------------------------------------------------| + * | reserved | rx err count |M| r | ext TID | + * |---------------------------------------------------------------------| + * M = multicast + * r = reserved + * + * The following field definitions describe the format of the peer info + * message sent from the target to the host. + * + * WORD 0: + * - MSG_TYPE + * Bits 7:0 + * Purpose: identifies this as an rx err message + * Value: 0x8 + * - RX_ERR_TYPE + * Bits 15:8 + * Purpose: specifies which type of rx error is being reported + * Value: htt_rx_ind_mpdu_status enum + * - PEER_ID + * Bits 31:16 + * Purpose: specify which peer sent the frame that resulted in an error + * WORD 1: + * - EXT_TID + * Bits 4:0 + * Purpose: specifies which traffic type had the rx error + * Value: 0-15 for a real TID value, 16 for non-QoS data, 31 for unknown + * - MCAST + * Bit 6 + * Purpose: specify whether the rx error frame was unicast or multicast + * Value: 0 -> unicast, 1 -> multicast + * - L2_HDR_IS_80211 + * Bit 7 + * Purpose: specifies whether the included L2 header (if present) is in + * 802.3 or 802.11 format + * Value: 0 -> 802.3, 1 -> 802.11 + * - L2_HDR_BYTES + * Bits 15:8 + * Purpose: Specify the size of the L2 header in this rx error report. + * Value: + * If no L2 header is included, this field shall be 0. + * If a 802.3 + LLC/SNAP header is included, this field shall be + * 14 (ethernet header) + 8 (LLC/SNAP). + * If a 802.11 header is included, this field shall be 24 bytes for + * a basic header, or 26 bytes if a QoS control field is included, + * or 30 bytes if a 4th address is included, or 32 bytes if a 4th + * address and a QoS control field are included, etc. + * Though the L2 header included in the message needs to include + * padding up to a 4-byte boundary, this L2 header size field need + * not account for the padding following the L2 header. + * - SEC_HDR_BYTES + * Bits 23:16 + * Purpose: Specify the size of the security encapsulation header in + * this rx error report. + * Value: + * If no security header is included, this field shall be 0. + * If a security header is included, this field depends on the + * security type, which can be inferred from the rx error type. + * For TKIP MIC errors, the security header could be any of: + * 8 - if IV / KeyID and Extended IV are included + * 16 - if MIC is also included + * 20 - if ICV is also included + * - RX_ERR_CNT + * Bits 31:24 + * Purpose: specifies how many rx errors are reported in this message + * Value: + * Rx error reports that include a L2 header and/or security header + * will set this field to 1, to indicate that the error notification + * is for a single frame. + * Rx error reports that don't include a L2 header or security header + * can use this field to send a single message to report multiple + * erroneous rx frames. + */ +typedef struct htt_isoc_t2h_rx_err_s { + /* word 0 */ + A_UINT32 msg_type:8, /* HTT_ISOC_T2H_MSG_TYPE_RX_ERR */ + rx_err_type:8, peer_id:16; + /* word 1 */ + A_UINT32 + ext_tid:5, + reserved1:1, + mcast:1, + l2_hdr_is_80211:1, l2_hdr_bytes:8, sec_hdr_bytes:8, rx_err_cnt:8; + /* words 2 - M-1: L2 header */ + /* words M - N: security header */ +} htt_isoc_t2h_rx_err_t; + +/* This needs to be exact bytes for structure htt_isoc_t2h_rx_err_t + * * Since it is shared between host and FW, sizeof may not be used. + * * */ +#define HTT_ISOC_T2H_RX_ERR_BASE_BYTES 20 + +/* word 0 */ +#define HTT_ISOC_T2H_RX_ERR_TYPE_OFFSET32 0 +#define HTT_ISOC_T2H_RX_ERR_TYPE_M 0x0000ff00 +#define HTT_ISOC_T2H_RX_ERR_TYPE_ID_S 8 + +#define HTT_ISOC_T2H_RX_ERR_PEER_ID_OFFSET32 0 +#define HTT_ISOC_T2H_RX_ERR_PEER_ID_M 0xffff0000 +#define HTT_ISOC_T2H_RX_ERR_PEER_ID_S 16 + +/* word 1 */ +#define HTT_ISOC_T2H_RX_ERR_EXT_TID_OFFSET32 1 +#define HTT_ISOC_T2H_RX_ERR_EXT_TID_M 0x0000001f +#define HTT_ISOC_T2H_RX_ERR_EXT_TID_S 0 + +#define HTT_ISOC_T2H_RX_ERR_MCAST_OFFSET32 1 +#define HTT_ISOC_T2H_RX_ERR_MCAST_M 0x00000040 +#define HTT_ISOC_T2H_RX_ERR_MCAST_S 6 + +#define HTT_ISOC_T2H_RX_ERR_L2_HDR_IS_80211_OFFSET32 1 +#define HTT_ISOC_T2H_RX_ERR_L2_HDR_IS_80211_M 0x00000080 +#define HTT_ISOC_T2H_RX_ERR_L2_HDR_IS_80211_S 7 + +#define HTT_ISOC_T2H_RX_ERR_L2_HDR_BYTES_OFFSET32 1 +#define HTT_ISOC_T2H_RX_ERR_L2_HDR_BYTES_M 0x0000ff00 +#define HTT_ISOC_T2H_RX_ERR_L2_HDR_BYTES_S 8 + +#define HTT_ISOC_T2H_RX_ERR_SEC_HDR_BYTES_OFFSET32 1 +#define HTT_ISOC_T2H_RX_ERR_SEC_HDR_BYTES_M 0x00ff0000 +#define HTT_ISOC_T2H_RX_ERR_SEC_HDR_BYTES_S 16 + +#define HTT_ISOC_T2H_RX_ERR_CNT_OFFSET32 1 +#define HTT_ISOC_T2H_RX_ERR_CNT_M 0xff000000 +#define HTT_ISOC_T2H_RX_ERR_CNT_S 24 + + +/* general field access macros */ + +#define HTT_ISOC_T2H_RX_ERR_FIELD_SET(field, msg_addr, value) \ + htt_isoc_t2h_field_set( \ + ((A_UINT32 *) msg_addr), \ + HTT_ISOC_T2H_RX_ERR_ ## field ## _OFFSET32, \ + HTT_ISOC_T2H_RX_ERR_ ## field ## _M, \ + HTT_ISOC_T2H_RX_ERR_ ## field ## _S, \ + value) + +#define HTT_ISOC_T2H_RX_ERR_FIELD_GET(field, msg_addr) \ + HTT_ISOC_T2H_FIELD_GET( \ + ((A_UINT32 *) msg_addr), \ + HTT_ISOC_T2H_RX_ERR_ ## field ## _OFFSET32, \ + HTT_ISOC_T2H_RX_ERR_ ## field ## _M, \ + HTT_ISOC_T2H_RX_ERR_ ## field ## _S) + +/* access macros for specific fields */ + +#define HTT_ISOC_T2H_RX_ERR_TYPE_SET(msg_addr, value) \ + HTT_ISOC_T2H_RX_ERR_FIELD_SET(TYPE, msg_addr, value) +#define HTT_ISOC_T2H_RX_ERR_TYPE_GET(msg_addr) \ + HTT_ISOC_T2H_RX_ERR_FIELD_GET(TYPE, msg_addr) + +A_COMPILE_TIME_ASSERT(HTT_ISOC_T2H_RX_ERR_PEER_ID_M_Size_Check, + (HTT_ISOC_T2H_RX_ERR_PEER_ID_M >> HTT_ISOC_T2H_RX_ERR_PEER_ID_S) \ + <= ((A_UINT16)~((A_UINT16)0))); +#define HTT_ISOC_T2H_RX_ERR_PEER_ID_SET(msg_addr, value) \ + HTT_ISOC_T2H_RX_ERR_FIELD_SET(PEER_ID, msg_addr, value) +#define HTT_ISOC_T2H_RX_ERR_PEER_ID_GET(msg_addr) \ + ((A_UINT16)HTT_ISOC_T2H_RX_ERR_FIELD_GET(PEER_ID, msg_addr)) + +#define HTT_ISOC_T2H_RX_ERR_EXT_TID_SET(msg_addr, value) \ + HTT_ISOC_T2H_RX_ERR_FIELD_SET(EXT_TID, msg_addr, value) +#define HTT_ISOC_T2H_RX_ERR_EXT_TID_GET(msg_addr) \ + HTT_ISOC_T2H_RX_ERR_FIELD_GET(EXT_TID, msg_addr) + +#define HTT_ISOC_T2H_RX_ERR_MCAST_SET(msg_addr, value) \ + HTT_ISOC_T2H_RX_ERR_FIELD_SET(MCAST, msg_addr, value) +#define HTT_ISOC_T2H_RX_ERR_MCAST_GET(msg_addr) \ + HTT_ISOC_T2H_RX_ERR_FIELD_GET(MCAST, msg_addr) + +#define HTT_ISOC_T2H_RX_ERR_L2_HDR_IS_80211_SET(msg_addr, value) \ + HTT_ISOC_T2H_RX_ERR_FIELD_SET(L2_HDR_IS_80211, msg_addr, value) +#define HTT_ISOC_T2H_RX_ERR_L2_HDR_IS_80211_GET(msg_addr) \ + HTT_ISOC_T2H_RX_ERR_FIELD_GET(L2_HDR_IS_80211, msg_addr) + +#define HTT_ISOC_T2H_RX_ERR_L2_HDR_BYTES_SET(msg_addr, value) \ + HTT_ISOC_T2H_RX_ERR_FIELD_SET(L2_HDR_BYTES, msg_addr, value) +#define HTT_ISOC_T2H_RX_ERR_L2_HDR_BYTES_GET(msg_addr) \ + HTT_ISOC_T2H_RX_ERR_FIELD_GET(L2_HDR_BYTES, msg_addr) + +#define HTT_ISOC_T2H_RX_ERR_SEC_HDR_BYTES_SET(msg_addr, value) \ + HTT_ISOC_T2H_RX_ERR_FIELD_SET(SEC_HDR_BYTES, msg_addr, value) +#define HTT_ISOC_T2H_RX_ERR_SEC_HDR_BYTES_GET(msg_addr) \ + HTT_ISOC_T2H_RX_ERR_FIELD_GET(SEC_HDR_BYTES, msg_addr) + +#define HTT_ISOC_T2H_RX_ERR_CNT_SET(msg_addr, value) \ + HTT_ISOC_T2H_RX_ERR_FIELD_SET(CNT, msg_addr, value) +#define HTT_ISOC_T2H_RX_ERR_CNT_GET(msg_addr) \ + HTT_ISOC_T2H_RX_ERR_FIELD_GET(CNT, msg_addr) + +/*=== TX OTA complete indication message ===*/ + +/** + * @brief target -> tx complete indicate message + * + * @details + * The following diagram shows the format of the tx complete indication message sent + * from the target to the host. This layout assumes the target operates + * as little-endian. + * + * |31 19|18 8|7 0| + * |-----------------------------------------------------------------------| + * | reserved | status | msg type | + * |-----------------------------------------------------------------------| + * + * + * The following field definitions describe the format of the peer info + * message sent from the target to the host. + * + * WORD 0: + * - MSG_TYPE + * Bits 7:0 + * Purpose: identifies this as tx complete indication message + * Value: 0x7 + * - status + * Bits 18:8 + * Purpose: TX completion status + */ +typedef struct htt_isoc_t2h_tx_compl_s { + /* word 0 */ + A_UINT32 + /* HTT_ISOC_T2H_MSG_TYPE_TX_COMPL_IND */ + qmsg_type:8, + status:11, + reserved0:13; +} htt_isoc_t2h_tx_compl_t; + +/* word 0 */ +#define HTT_ISOC_T2H_TX_COMPL_IND_STATUS_OFFSET32 0 +#define HTT_ISOC_T2H_TX_COMPL_IND_STATUS_M 0x0007ff00 +#define HTT_ISOC_T2H_TX_COMPL_IND_STATUS_S 8 + + +/* general field access macros */ + +#define HTT_ISOC_T2H_TX_COMPL_IND_FIELD_SET(field, msg_addr, value) \ + htt_isoc_t2h_field_set( \ + ((A_UINT32 *) msg_addr), \ + HTT_ISOC_T2H_TX_COMPL_IND_ ## field ## _OFFSET32, \ + HTT_ISOC_T2H_TX_COMPL_IND_ ## field ## _M, \ + HTT_ISOC_T2H_TX_COMPL_IND_ ## field ## _S, \ + value) + +#define HTT_ISOC_T2H_TX_COMPL_IND_FIELD_GET(field, msg_addr) \ + HTT_ISOC_T2H_FIELD_GET( \ + ((A_UINT32 *) msg_addr), \ + HTT_ISOC_T2H_TX_COMPL_IND_ ## field ## _OFFSET32, \ + HTT_ISOC_T2H_TX_COMPL_IND_ ## field ## _M, \ + HTT_ISOC_T2H_TX_COMPL_IND_ ## field ## _S) + +/* access macros for specific fields */ + +#define HTT_ISOC_T2H_TX_COMPL_IND_STATUS_SET(msg_addr, value) \ + HTT_ISOC_T2H_TX_COMPL_IND_FIELD_SET(STATUS, msg_addr, value) +#define HTT_ISOC_T2H_TX_COMPL_IND_STATUS_GET(msg_addr) \ + HTT_ISOC_T2H_TX_COMPL_IND_FIELD_GET(STATUS, msg_addr) + +#define HTT_TX_COMPL_IND_STAT_OK 0 +#define HTT_TX_COMPL_IND_STAT_DISCARD 1 +#define HTT_TX_COMPL_IND_STAT_NO_ACK 2 +#define HTT_TX_COMPL_IND_STAT_POSTPONE 3 + +/*=== NLO indication message ===*/ + +/** +* @brief target -> NLO indicate message +* +* @details +* The following diagram shows the format of the NLO indication message sent +* from the target to the host. This layout assumes the target operates +* as little-endian. +* +* |31 8|7 0| +* |-----------------------------------------------------------------------| +* | reserved | msg type | +* |-----------------------------------------------------------------------| +* +* +* The following field definitions describe the format of NLO MATCH indication +* message sent from the target to the host. +* +* WORD 0: +* - MSG_TYPE +* Bits 7:0 +* Purpose: identifies this as NLO indication message +* Value: 0x9 - HTT_ISOC_T2H_MSG_TYPE_NLO_MATCH +* Value: 0xA - HTT_ISOC_T2H_MSG_TYPE_NLO_SCAN_END +*/ +typedef struct htt_isoc_t2h_nlo_ind_s { + /* word 0 */ + A_UINT32 + msg_type:8, + vdev_id:8, + reserved0:16; +} htt_isoc_t2h_nlo_ind_t; + +/* word 0 */ +#define HTT_ISOC_T2H_NLO_IND_VDEVID_OFFSET32 0 +#define HTT_ISOC_T2H_NLO_IND_VDEVID_M 0x0000ff00 +#define HTT_ISOC_T2H_NLO_IND_VDEVID_S 8 + + +/* general field access macros */ + +#define HTT_ISOC_T2H_NLO_IND_FIELD_SET(field, msg_addr, value) \ + htt_isoc_t2h_field_set( \ + ((A_UINT32 *) msg_addr), \ + HTT_ISOC_T2H_NLO_IND_ ## field ## _OFFSET32, \ + HTT_ISOC_T2H_NLO_IND_ ## field ## _M, \ + HTT_ISOC_T2H_NLO_IND_ ## field ## _S, \ + value) + +#define HTT_ISOC_T2H_NLO_IND_FIELD_GET(field, msg_addr) \ + HTT_ISOC_T2H_FIELD_GET( \ + ((A_UINT32 *) msg_addr), \ + HTT_ISOC_T2H_NLO_IND_ ## field ## _OFFSET32, \ + HTT_ISOC_T2H_NLO_IND_ ## field ## _M, \ + HTT_ISOC_T2H_NLO_IND_ ## field ## _S) + +/* access macros for specific fields */ + +#define HTT_ISOC_T2H_NLO_IND_VDEVID_SET(msg_addr, value) \ + HTT_ISOC_T2H_NLO_IND_FIELD_SET(VDEVID, msg_addr, value) +#define HTT_ISOC_T2H_NLO_IND_VDEVID_GET(msg_addr) \ + HTT_ISOC_T2H_NLO_IND_FIELD_GET(VDEVID, msg_addr) + + +#endif /* _HTT_ISOC_H_ */ diff --git a/drivers/staging/fw-api/fw/ip_prot.h b/drivers/staging/fw-api/fw/ip_prot.h new file mode 100644 index 0000000000000000000000000000000000000000..a1722fe3eb4fbc3ddf03cce1574296a27fb60b46 --- /dev/null +++ b/drivers/staging/fw-api/fw/ip_prot.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2012, 2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef _IP_PROT__H_ +#define _IP_PROT__H_ + +#define IP_PROTOCOL_ICMP 0x01 /* Internet Control Message Protocol */ +#define IP_PROTOCOL_IGMP 0x02 /* Internet Group Management Protocol */ +#define IP_PROTOCOL_IPV4 0x04 /* IPv4 (encapsulation) */ +#define IP_PROTOCOL_TCP 0x06 /* Transmission Control Protocol */ +#define IP_PROTOCOL_UDP 0x11 /* User Datagram Protocol */ +#define IP_PROTOCOL_RDP 0x1B /* Reliable Datagram Protocol */ +#define IP_PROTOCOL_IPV6 0x29 /* IPv6 (encapsulation) */ +#define IP_PROTOCOL_IPV6_ROUTE 0x2B /* Routing Header for IPv6 */ +#define IP_PROTOCOL_IPV6_FRAG 0x2C /* Fragment Header for IPv6 */ +#define IP_PROTOCOL_RSVP 0x2E /* Resource Reservation Protocol */ +#define IP_PROTOCOL_GRE 0x2F /* Generic Routing Encapsulation */ +#define IP_PROTOCOL_MHRP 0x30 /* Mobile Host Routing Protocol */ +#define IP_PROTOCOL_BNA 0x31 /* BNA */ +#define IP_PROTOCOL_ESP 0x32 /* Encapsulating Security Payload */ +#define IP_PROTOCOL_MOBILE 0x37 /* IP Mobility (Min Encap) */ +#define IP_PROTOCOL_IPV6_ICMP 0x3A /* ICMP for IPv6 */ +#define IP_PROTOCOL_IPV6_NONXT 0x3B /* No Next Header for IPv6 */ +#define IP_PROTOCOL_IPV6_OPTS 0x3C /* Destination Options for IPv6 */ +#define IP_PROTOCOL_IPCOMP 0x6C /* IP Payload Compression Protocol */ +#define IP_PROTOCOL_L2TP 0x73 /* Layer Two Tunneling Protocol Version 3 */ +#define IP_PROTOCOL_SMP 0x79 /* Simple Message Protocol */ +#define IP_PROTOCOL_SCTP 0x84 /* Stream Control Transmission Protocol */ +#define IP_PROTOCOL_SHIM6 0x8C /* Site Multihoming by IPv6 Intermediation */ + +/* IPv6 ICMP types */ +#define IPV6_ICMP_TYPE_MLD 0x8F + +#endif /* _IP_PROT__H_ */ diff --git a/drivers/staging/fw-api/fw/ipv4.h b/drivers/staging/fw-api/fw/ipv4.h new file mode 100644 index 0000000000000000000000000000000000000000..67eb3375507d4e10fdbe454a9b73330e43fe393a --- /dev/null +++ b/drivers/staging/fw-api/fw/ipv4.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2012, 2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef _IPV4__H_ +#define _IPV4__H_ + +#if defined(ATH_TARGET) +#include /* A_UINT8 */ +#else +#include /* A_UINT8 */ +#endif + +#define IPV4_ADDR_LEN 4 /* bytes */ +struct ipv4_hdr_t { + A_UINT8 ver_hdrlen; /* version and hdr length */ + A_UINT8 tos; /* type of service */ + A_UINT8 len[2]; /* total length */ + A_UINT8 id[2]; + A_UINT8 flags_fragoff[2]; /* flags and fragment offset field */ + A_UINT8 ttl; /* time to live */ + A_UINT8 protocol; + A_UINT8 hdr_checksum[2]; + A_UINT8 src_addr[IPV4_ADDR_LEN]; + A_UINT8 dst_addr[IPV4_ADDR_LEN]; +}; + +#define IPV4_HDR_LEN (sizeof(struct ipv4_hdr_t)) +#define IPV4_HDR_OFFSET_PROTOCOL (offsetof(struct ipv4_hdr_t, protocol)) +#define IPV4_HDR_OFFSET_DST_ADDR (offsetof(struct ipv4_hdr_t, dst_addr[0])) + +#endif /* _IPV4__H_ */ diff --git a/drivers/staging/fw-api/fw/ol_fw_tx_dbg.h b/drivers/staging/fw-api/fw/ol_fw_tx_dbg.h new file mode 100644 index 0000000000000000000000000000000000000000..254e94a6c1d5dd8b29dd7ac9f028447a07fb7239 --- /dev/null +++ b/drivers/staging/fw-api/fw/ol_fw_tx_dbg.h @@ -0,0 +1,184 @@ +/* + * Copyright (c) 2012, 2014-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * @file ol_fw_tx_dbg.h + * + * @details data structs used for uploading summary info about the FW's tx + */ + +#ifndef _OL_FW_TX_DBG__H_ +#define _OL_FW_TX_DBG__H_ + +/* + * Undef ATH_SUPPORT_FW_TX_DBG to remove the FW tx debug feature. + * Removing the FW tx debug feature saves a modest amount of program memory. + * The data memory allocation for the FW tx debug feature is controlled + * by the host --> target resource configuration parameters; even if + * ATH_SUPPORT_FW_TX_DBG is defined, no data memory will be allocated for + * the FW tx debug log unless the host --> target resource configuration + * specifies it. + */ +#define ATH_SUPPORT_FW_TX_DBG 1 /* enabled */ +/* #undef ATH_SUPPORT_FW_TX_DBG / * disabled * / */ + +#if defined(ATH_TARGET) +#include /* A_UINT32 */ +#else +#include /* A_UINT32 */ +#include /* PREPACK, POSTPACK */ +#endif + +enum ol_fw_tx_dbg_log_mode { + ol_fw_tx_dbg_log_mode_wraparound, /* overwrite old data with new */ + ol_fw_tx_dbg_log_mode_single, /* fill log once, then stop */ +}; + +/* + * tx PPDU stats upload message header + */ +struct ol_fw_tx_dbg_ppdu_msg_hdr { + /* word 0 */ +#define OL_FW_TX_DBG_PPDU_HDR_NUM_MPDU_BYTES_WORD 0 +#define OL_FW_TX_DBG_PPDU_HDR_NUM_MPDU_BYTES_S 0 +#define OL_FW_TX_DBG_PPDU_HDR_NUM_MPDU_BYTES_M 0x000000ff + A_UINT8 mpdu_bytes_array_len; /* length of array of per-MPDU byte counts */ + +#define OL_FW_TX_DBG_PPDU_HDR_NUM_MSDU_BYTES_WORD 0 +#define OL_FW_TX_DBG_PPDU_HDR_NUM_MSDU_BYTES_S 8 +#define OL_FW_TX_DBG_PPDU_HDR_NUM_MSDU_BYTES_M 0x0000ff00 + A_UINT8 msdu_bytes_array_len; /* length of array of per-MSDU byte counts */ + +#define OL_FW_TX_DBG_PPDU_HDR_NUM_MPDU_MSDUS_WORD 0 +#define OL_FW_TX_DBG_PPDU_HDR_NUM_MPDU_MSDUS_S 16 +#define OL_FW_TX_DBG_PPDU_HDR_NUM_MPDU_MSDUS_M 0x00ff0000 + A_UINT8 mpdu_msdus_array_len; /* length of array of per-MPDU MSDU counts */ + + A_UINT8 reserved; + + /* word 1 */ +#define OL_FW_TX_DBG_PPDU_HDR_MICROSEC_PER_TICK_WORD 1 +#define OL_FW_TX_DBG_PPDU_HDR_MICROSEC_PER_TICK_S 0 +#define OL_FW_TX_DBG_PPDU_HDR_MICROSEC_PER_TICK_M 0xffffffff + A_UINT32 microsec_per_tick; /* conversion for timestamp entries */ +}; + +/* + * tx PPDU log element / stats upload message element + */ +struct ol_fw_tx_dbg_ppdu_base { + /* word 0 - filled in during tx enqueue */ +#define OL_FW_TX_DBG_PPDU_START_SEQ_NUM_WORD 0 +#define OL_FW_TX_DBG_PPDU_START_SEQ_NUM_S 0 +#define OL_FW_TX_DBG_PPDU_START_SEQ_NUM_M 0x0000ffff + A_UINT16 start_seq_num; +#define OL_FW_TX_DBG_PPDU_START_PN_LSBS_WORD 0 +#define OL_FW_TX_DBG_PPDU_START_PN_LSBS_S 16 +#define OL_FW_TX_DBG_PPDU_START_PN_LSBS_M 0xffff0000 + A_UINT16 start_pn_lsbs; + + /* word 1 - filled in during tx enqueue */ +#define OL_FW_TX_DBG_PPDU_NUM_BYTES_WORD 1 +#define OL_FW_TX_DBG_PPDU_NUM_BYTES_S 0 +#define OL_FW_TX_DBG_PPDU_NUM_BYTES_M 0xffffffff + A_UINT32 num_bytes; + + /* word 2 - filled in during tx enqueue */ +#define OL_FW_TX_DBG_PPDU_NUM_MSDUS_WORD 2 +#define OL_FW_TX_DBG_PPDU_NUM_MSDUS_S 0 +#define OL_FW_TX_DBG_PPDU_NUM_MSDUS_M 0x000000ff + A_UINT8 num_msdus; +#define OL_FW_TX_DBG_PPDU_NUM_MPDUS_WORD 2 +#define OL_FW_TX_DBG_PPDU_NUM_MPDUS_S 8 +#define OL_FW_TX_DBG_PPDU_NUM_MPDUS_M 0x0000ff00 + A_UINT8 num_mpdus; + A_UINT16 +#define OL_FW_TX_DBG_PPDU_EXT_TID_WORD 2 +#define OL_FW_TX_DBG_PPDU_EXT_TID_S 16 +#define OL_FW_TX_DBG_PPDU_EXT_TID_M 0x001f0000 + ext_tid : 5, +#define OL_FW_TX_DBG_PPDU_PEER_ID_WORD 2 +#define OL_FW_TX_DBG_PPDU_PEER_ID_S 21 +#define OL_FW_TX_DBG_PPDU_PEER_ID_M 0xffe00000 + peer_id : 11; + + /* word 3 - filled in during tx enqueue */ +#define OL_FW_TX_DBG_PPDU_TIME_ENQUEUE_WORD 3 +#define OL_FW_TX_DBG_PPDU_TIME_ENQUEUE_S 0 +#define OL_FW_TX_DBG_PPDU_TIME_ENQUEUE_M 0xffffffff + A_UINT32 timestamp_enqueue; + + /* word 4 - filled in during tx completion */ +#define OL_FW_TX_DBG_PPDU_TIME_COMPL_WORD 4 +#define OL_FW_TX_DBG_PPDU_TIME_COMPL_S 0 +#define OL_FW_TX_DBG_PPDU_TIME_COMPL_M 0xffffffff + A_UINT32 timestamp_completion; + + /* word 5 - filled in during tx completion */ +#define OL_FW_TX_DBG_PPDU_BLOCK_ACK_LSBS_WORD 5 +#define OL_FW_TX_DBG_PPDU_BLOCK_ACK_LSBS_S 0 +#define OL_FW_TX_DBG_PPDU_BLOCK_ACK_LSBS_M 0xffffffff + A_UINT32 block_ack_bitmap_lsbs; + + /* word 6 - filled in during tx completion */ +#define OL_FW_TX_DBG_PPDU_BLOCK_ACK_MSBS_WORD 6 +#define OL_FW_TX_DBG_PPDU_BLOCK_ACK_MSBS_S 0 +#define OL_FW_TX_DBG_PPDU_BLOCK_ACK_MSBS_M 0xffffffff + A_UINT32 block_ack_bitmap_msbs; + + /* word 7 - filled in during tx completion (enqueue would work too) */ +#define OL_FW_TX_DBG_PPDU_ENQUEUED_LSBS_WORD 7 +#define OL_FW_TX_DBG_PPDU_ENQUEUED_LSBS_S 0 +#define OL_FW_TX_DBG_PPDU_ENQUEUED_LSBS_M 0xffffffff + A_UINT32 enqueued_bitmap_lsbs; + + /* word 8 - filled in during tx completion (enqueue would work too) */ +#define OL_FW_TX_DBG_PPDU_ENQUEUED_MSBS_WORD 8 +#define OL_FW_TX_DBG_PPDU_ENQUEUED_MSBS_S 0 +#define OL_FW_TX_DBG_PPDU_ENQUEUED_MSBS_M 0xffffffff + A_UINT32 enqueued_bitmap_msbs; + + /* word 9 - filled in during tx completion */ +#define OL_FW_TX_DBG_PPDU_RATE_CODE_WORD 9 +#define OL_FW_TX_DBG_PPDU_RATE_CODE_S 0 +#define OL_FW_TX_DBG_PPDU_RATE_CODE_M 0x000000ff + A_UINT8 rate_code; +#define OL_FW_TX_DBG_PPDU_RATE_FLAGS_WORD 9 +#define OL_FW_TX_DBG_PPDU_RATE_FLAGS_S 8 +#define OL_FW_TX_DBG_PPDU_RATE_FLAGS_M 0x0000ff00 + A_UINT8 rate_flags; /* includes dynamic bandwidth info */ +#define OL_FW_TX_DBG_PPDU_TRIES_WORD 9 +#define OL_FW_TX_DBG_PPDU_TRIES_S 16 +#define OL_FW_TX_DBG_PPDU_TRIES_M 0x00ff0000 + A_UINT8 tries; +#define OL_FW_TX_DBG_PPDU_COMPLETE_WORD 9 +#define OL_FW_TX_DBG_PPDU_COMPLETE_S 24 +#define OL_FW_TX_DBG_PPDU_COMPLETE_M 0xff000000 + A_UINT8 complete; +}; + +#endif /* _OL_FW_TX_DBG__H_ */ diff --git a/drivers/staging/fw-api/fw/rtc_soc_reg.h b/drivers/staging/fw-api/fw/rtc_soc_reg.h new file mode 100644 index 0000000000000000000000000000000000000000..11e80b1f1f925f891005eb275e4f655ae45ce273 --- /dev/null +++ b/drivers/staging/fw-api/fw/rtc_soc_reg.h @@ -0,0 +1,1966 @@ +/* + * Copyright (c) 2013-2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef _RTC_SOC_REG_REG_H_ +#define _RTC_SOC_REG_REG_H_ + +#define SOC_RESET_CONTROL_ADDRESS 0x00000000 +#define SOC_RESET_CONTROL_OFFSET 0x00000000 +#define SOC_RESET_CONTROL_SPI2_RST_MSB 30 +#define SOC_RESET_CONTROL_SPI2_RST_LSB 30 +#define SOC_RESET_CONTROL_SPI2_RST_MASK 0x40000000 +#define SOC_RESET_CONTROL_SPI2_RST_GET(x) (((x) & SOC_RESET_CONTROL_SPI2_RST_MASK) >> SOC_RESET_CONTROL_SPI2_RST_LSB) +#define SOC_RESET_CONTROL_SPI2_RST_SET(x) (((x) << SOC_RESET_CONTROL_SPI2_RST_LSB) & SOC_RESET_CONTROL_SPI2_RST_MASK) +#define SOC_RESET_CONTROL_I2S_1_RST_MSB 29 +#define SOC_RESET_CONTROL_I2S_1_RST_LSB 29 +#define SOC_RESET_CONTROL_I2S_1_RST_MASK 0x20000000 +#define SOC_RESET_CONTROL_I2S_1_RST_GET(x) (((x) & SOC_RESET_CONTROL_I2S_1_RST_MASK) >> SOC_RESET_CONTROL_I2S_1_RST_LSB) +#define SOC_RESET_CONTROL_I2S_1_RST_SET(x) (((x) << SOC_RESET_CONTROL_I2S_1_RST_LSB) & SOC_RESET_CONTROL_I2S_1_RST_MASK) +#define SOC_RESET_CONTROL_I2S_1_MBOX_RST_MSB 28 +#define SOC_RESET_CONTROL_I2S_1_MBOX_RST_LSB 28 +#define SOC_RESET_CONTROL_I2S_1_MBOX_RST_MASK 0x10000000 +#define SOC_RESET_CONTROL_I2S_1_MBOX_RST_GET(x) (((x) & SOC_RESET_CONTROL_I2S_1_MBOX_RST_MASK) >> SOC_RESET_CONTROL_I2S_1_MBOX_RST_LSB) +#define SOC_RESET_CONTROL_I2S_1_MBOX_RST_SET(x) (((x) << SOC_RESET_CONTROL_I2S_1_MBOX_RST_LSB) & SOC_RESET_CONTROL_I2S_1_MBOX_RST_MASK) +#define SOC_RESET_CONTROL_I2C_SLAVE_RST_MSB 27 +#define SOC_RESET_CONTROL_I2C_SLAVE_RST_LSB 27 +#define SOC_RESET_CONTROL_I2C_SLAVE_RST_MASK 0x08000000 +#define SOC_RESET_CONTROL_I2C_SLAVE_RST_GET(x) (((x) & SOC_RESET_CONTROL_I2C_SLAVE_RST_MASK) >> SOC_RESET_CONTROL_I2C_SLAVE_RST_LSB) +#define SOC_RESET_CONTROL_I2C_SLAVE_RST_SET(x) (((x) << SOC_RESET_CONTROL_I2C_SLAVE_RST_LSB) & SOC_RESET_CONTROL_I2C_SLAVE_RST_MASK) +#define SOC_RESET_CONTROL_USB_PHY_ARST_MSB 26 +#define SOC_RESET_CONTROL_USB_PHY_ARST_LSB 26 +#define SOC_RESET_CONTROL_USB_PHY_ARST_MASK 0x04000000 +#define SOC_RESET_CONTROL_USB_PHY_ARST_GET(x) (((x) & SOC_RESET_CONTROL_USB_PHY_ARST_MASK) >> SOC_RESET_CONTROL_USB_PHY_ARST_LSB) +#define SOC_RESET_CONTROL_USB_PHY_ARST_SET(x) (((x) << SOC_RESET_CONTROL_USB_PHY_ARST_LSB) & SOC_RESET_CONTROL_USB_PHY_ARST_MASK) +#define SOC_RESET_CONTROL_USB_PHY_RST_MSB 25 +#define SOC_RESET_CONTROL_USB_PHY_RST_LSB 25 +#define SOC_RESET_CONTROL_USB_PHY_RST_MASK 0x02000000 +#define SOC_RESET_CONTROL_USB_PHY_RST_GET(x) (((x) & SOC_RESET_CONTROL_USB_PHY_RST_MASK) >> SOC_RESET_CONTROL_USB_PHY_RST_LSB) +#define SOC_RESET_CONTROL_USB_PHY_RST_SET(x) (((x) << SOC_RESET_CONTROL_USB_PHY_RST_LSB) & SOC_RESET_CONTROL_USB_PHY_RST_MASK) +#define SOC_RESET_CONTROL_USB_RST_MSB 24 +#define SOC_RESET_CONTROL_USB_RST_LSB 24 +#define SOC_RESET_CONTROL_USB_RST_MASK 0x01000000 +#define SOC_RESET_CONTROL_USB_RST_GET(x) (((x) & SOC_RESET_CONTROL_USB_RST_MASK) >> SOC_RESET_CONTROL_USB_RST_LSB) +#define SOC_RESET_CONTROL_USB_RST_SET(x) (((x) << SOC_RESET_CONTROL_USB_RST_LSB) & SOC_RESET_CONTROL_USB_RST_MASK) +#define SOC_RESET_CONTROL_MMAC_RST_MSB 23 +#define SOC_RESET_CONTROL_MMAC_RST_LSB 23 +#define SOC_RESET_CONTROL_MMAC_RST_MASK 0x00800000 +#define SOC_RESET_CONTROL_MMAC_RST_GET(x) (((x) & SOC_RESET_CONTROL_MMAC_RST_MASK) >> SOC_RESET_CONTROL_MMAC_RST_LSB) +#define SOC_RESET_CONTROL_MMAC_RST_SET(x) (((x) << SOC_RESET_CONTROL_MMAC_RST_LSB) & SOC_RESET_CONTROL_MMAC_RST_MASK) +#define SOC_RESET_CONTROL_MDIO_RST_MSB 22 +#define SOC_RESET_CONTROL_MDIO_RST_LSB 22 +#define SOC_RESET_CONTROL_MDIO_RST_MASK 0x00400000 +#define SOC_RESET_CONTROL_MDIO_RST_GET(x) (((x) & SOC_RESET_CONTROL_MDIO_RST_MASK) >> SOC_RESET_CONTROL_MDIO_RST_LSB) +#define SOC_RESET_CONTROL_MDIO_RST_SET(x) (((x) << SOC_RESET_CONTROL_MDIO_RST_LSB) & SOC_RESET_CONTROL_MDIO_RST_MASK) +#define SOC_RESET_CONTROL_GE0_RST_MSB 21 +#define SOC_RESET_CONTROL_GE0_RST_LSB 21 +#define SOC_RESET_CONTROL_GE0_RST_MASK 0x00200000 +#define SOC_RESET_CONTROL_GE0_RST_GET(x) (((x) & SOC_RESET_CONTROL_GE0_RST_MASK) >> SOC_RESET_CONTROL_GE0_RST_LSB) +#define SOC_RESET_CONTROL_GE0_RST_SET(x) (((x) << SOC_RESET_CONTROL_GE0_RST_LSB) & SOC_RESET_CONTROL_GE0_RST_MASK) +#define SOC_RESET_CONTROL_I2S_RST_MSB 20 +#define SOC_RESET_CONTROL_I2S_RST_LSB 20 +#define SOC_RESET_CONTROL_I2S_RST_MASK 0x00100000 +#define SOC_RESET_CONTROL_I2S_RST_GET(x) (((x) & SOC_RESET_CONTROL_I2S_RST_MASK) >> SOC_RESET_CONTROL_I2S_RST_LSB) +#define SOC_RESET_CONTROL_I2S_RST_SET(x) (((x) << SOC_RESET_CONTROL_I2S_RST_LSB) & SOC_RESET_CONTROL_I2S_RST_MASK) +#define SOC_RESET_CONTROL_I2S_MBOX_RST_MSB 19 +#define SOC_RESET_CONTROL_I2S_MBOX_RST_LSB 19 +#define SOC_RESET_CONTROL_I2S_MBOX_RST_MASK 0x00080000 +#define SOC_RESET_CONTROL_I2S_MBOX_RST_GET(x) (((x) & SOC_RESET_CONTROL_I2S_MBOX_RST_MASK) >> SOC_RESET_CONTROL_I2S_MBOX_RST_LSB) +#define SOC_RESET_CONTROL_I2S_MBOX_RST_SET(x) (((x) << SOC_RESET_CONTROL_I2S_MBOX_RST_LSB) & SOC_RESET_CONTROL_I2S_MBOX_RST_MASK) +/* TODO: */ +#define SOC_RESET_CONTROL_CHECKSUM_ACC_RST_MSB 18 +#define SOC_RESET_CONTROL_CHECKSUM_ACC_RST_LSB 18 +#define SOC_RESET_CONTROL_CHECKSUM_ACC_RST_MASK 0x00040000 +#define SOC_RESET_CONTROL_CHECKSUM_ACC_RST_GET(x) (((x) & SOC_RESET_CONTROL_CHECKSUM_ACC_RST_MASK) >> SOC_RESET_CONTROL_CHECKSUM_ACC_RST_LSB) +#define SOC_RESET_CONTROL_CHECKSUM_ACC_RST_SET(x) (((x) << SOC_RESET_CONTROL_CHECKSUM_ACC_RST_LSB) & SOC_RESET_CONTROL_CHECKSUM_ACC_RST_MASK) +#define SOC_RESET_CONTROL_CE_RST_MSB 18 +#define SOC_RESET_CONTROL_CE_RST_LSB 18 +#define SOC_RESET_CONTROL_CE_RST_MASK 0x00040000 +#define SOC_RESET_CONTROL_CE_RST_GET(x) (((x) & SOC_RESET_CONTROL_CE_RST_MASK) >> SOC_RESET_CONTROL_CE_RST_LSB) +#define SOC_RESET_CONTROL_CE_RST_SET(x) (((x) << SOC_RESET_CONTROL_CE_RST_LSB) & SOC_RESET_CONTROL_CE_RST_MASK) +#define SOC_RESET_CONTROL_UART2_RST_MSB 17 +#define SOC_RESET_CONTROL_UART2_RST_LSB 17 +#define SOC_RESET_CONTROL_UART2_RST_MASK 0x00020000 +#define SOC_RESET_CONTROL_UART2_RST_GET(x) (((x) & SOC_RESET_CONTROL_UART2_RST_MASK) >> SOC_RESET_CONTROL_UART2_RST_LSB) +#define SOC_RESET_CONTROL_UART2_RST_SET(x) (((x) << SOC_RESET_CONTROL_UART2_RST_LSB) & SOC_RESET_CONTROL_UART2_RST_MASK) +#define SOC_RESET_CONTROL_DEBUG_UART_RST_MSB 16 +#define SOC_RESET_CONTROL_DEBUG_UART_RST_LSB 16 +#define SOC_RESET_CONTROL_DEBUG_UART_RST_MASK 0x00010000 +#define SOC_RESET_CONTROL_DEBUG_UART_RST_GET(x) (((x) & SOC_RESET_CONTROL_DEBUG_UART_RST_MASK) >> SOC_RESET_CONTROL_DEBUG_UART_RST_LSB) +#define SOC_RESET_CONTROL_DEBUG_UART_RST_SET(x) (((x) << SOC_RESET_CONTROL_DEBUG_UART_RST_LSB) & SOC_RESET_CONTROL_DEBUG_UART_RST_MASK) +#define SOC_RESET_CONTROL_CPU_INIT_RESET_MSB 11 +#define SOC_RESET_CONTROL_CPU_INIT_RESET_LSB 11 +#define SOC_RESET_CONTROL_CPU_INIT_RESET_MASK 0x00000800 +#define SOC_RESET_CONTROL_CPU_INIT_RESET_GET(x) (((x) & SOC_RESET_CONTROL_CPU_INIT_RESET_MASK) >> SOC_RESET_CONTROL_CPU_INIT_RESET_LSB) +#define SOC_RESET_CONTROL_CPU_INIT_RESET_SET(x) (((x) << SOC_RESET_CONTROL_CPU_INIT_RESET_LSB) & SOC_RESET_CONTROL_CPU_INIT_RESET_MASK) +#define SOC_RESET_CONTROL_RST_OUT_MSB 9 +#define SOC_RESET_CONTROL_RST_OUT_LSB 9 +#define SOC_RESET_CONTROL_RST_OUT_MASK 0x00000200 +#define SOC_RESET_CONTROL_RST_OUT_GET(x) (((x) & SOC_RESET_CONTROL_RST_OUT_MASK) >> SOC_RESET_CONTROL_RST_OUT_LSB) +#define SOC_RESET_CONTROL_RST_OUT_SET(x) (((x) << SOC_RESET_CONTROL_RST_OUT_LSB) & SOC_RESET_CONTROL_RST_OUT_MASK) +#define SOC_RESET_CONTROL_COLD_RST_MSB 8 +#define SOC_RESET_CONTROL_COLD_RST_LSB 8 +#define SOC_RESET_CONTROL_COLD_RST_MASK 0x00000100 +#define SOC_RESET_CONTROL_COLD_RST_GET(x) (((x) & SOC_RESET_CONTROL_COLD_RST_MASK) >> SOC_RESET_CONTROL_COLD_RST_LSB) +#define SOC_RESET_CONTROL_COLD_RST_SET(x) (((x) << SOC_RESET_CONTROL_COLD_RST_LSB) & SOC_RESET_CONTROL_COLD_RST_MASK) +#define SOC_RESET_CONTROL_CPU_WARM_RST_MSB 6 +#define SOC_RESET_CONTROL_CPU_WARM_RST_LSB 6 +#define SOC_RESET_CONTROL_CPU_WARM_RST_MASK 0x00000040 +#define SOC_RESET_CONTROL_CPU_WARM_RST_GET(x) (((x) & SOC_RESET_CONTROL_CPU_WARM_RST_MASK) >> SOC_RESET_CONTROL_CPU_WARM_RST_LSB) +#define SOC_RESET_CONTROL_CPU_WARM_RST_SET(x) (((x) << SOC_RESET_CONTROL_CPU_WARM_RST_LSB) & SOC_RESET_CONTROL_CPU_WARM_RST_MASK) +/* TODO: */ +#define SOC_RESET_CONTROL_PCIE_RST_SHORT_OVRD_MSB 2 +#define SOC_RESET_CONTROL_PCIE_RST_SHORT_OVRD_LSB 2 +#define SOC_RESET_CONTROL_PCIE_RST_SHORT_OVRD_MASK 0x00000004 +#define SOC_RESET_CONTROL_PCIE_RST_SHORT_OVRD_GET(x) (((x) & SOC_RESET_CONTROL_PCIE_RST_SHORT_OVRD_MASK) >> SOC_RESET_CONTROL_PCIE_RST_SHORT_OVRD_LSB) +#define SOC_RESET_CONTROL_PCIE_RST_SHORT_OVRD_SET(x) (((x) << SOC_RESET_CONTROL_PCIE_RST_SHORT_OVRD_LSB) & SOC_RESET_CONTROL_PCIE_RST_SHORT_OVRD_MASK) +#define SOC_RESET_CONTROL_MBOX_RST_MSB 2 +#define SOC_RESET_CONTROL_MBOX_RST_LSB 2 +#define SOC_RESET_CONTROL_MBOX_RST_MASK 0x00000004 +#define SOC_RESET_CONTROL_MBOX_RST_GET(x) (((x) & SOC_RESET_CONTROL_MBOX_RST_MASK) >> SOC_RESET_CONTROL_MBOX_RST_LSB) +#define SOC_RESET_CONTROL_MBOX_RST_SET(x) (((x) << SOC_RESET_CONTROL_MBOX_RST_LSB) & SOC_RESET_CONTROL_MBOX_RST_MASK) +#define SOC_RESET_CONTROL_UART_RST_MSB 1 +#define SOC_RESET_CONTROL_UART_RST_LSB 1 +#define SOC_RESET_CONTROL_UART_RST_MASK 0x00000002 +#define SOC_RESET_CONTROL_UART_RST_GET(x) (((x) & SOC_RESET_CONTROL_UART_RST_MASK) >> SOC_RESET_CONTROL_UART_RST_LSB) +#define SOC_RESET_CONTROL_UART_RST_SET(x) (((x) << SOC_RESET_CONTROL_UART_RST_LSB) & SOC_RESET_CONTROL_UART_RST_MASK) +#define SOC_RESET_CONTROL_SI0_RST_MSB 0 +#define SOC_RESET_CONTROL_SI0_RST_LSB 0 +#define SOC_RESET_CONTROL_SI0_RST_MASK 0x00000001 +#define SOC_RESET_CONTROL_SI0_RST_GET(x) (((x) & SOC_RESET_CONTROL_SI0_RST_MASK) >> SOC_RESET_CONTROL_SI0_RST_LSB) +#define SOC_RESET_CONTROL_SI0_RST_SET(x) (((x) << SOC_RESET_CONTROL_SI0_RST_LSB) & SOC_RESET_CONTROL_SI0_RST_MASK) + +#define SOC_TCXO_DETECT_ADDRESS 0x00000004 +#define SOC_TCXO_DETECT_OFFSET 0x00000004 +#define SOC_TCXO_DETECT_PRESENT_MSB 0 +#define SOC_TCXO_DETECT_PRESENT_LSB 0 +#define SOC_TCXO_DETECT_PRESENT_MASK 0x00000001 +#define SOC_TCXO_DETECT_PRESENT_GET(x) (((x) & SOC_TCXO_DETECT_PRESENT_MASK) >> SOC_TCXO_DETECT_PRESENT_LSB) +#define SOC_TCXO_DETECT_PRESENT_SET(x) (((x) << SOC_TCXO_DETECT_PRESENT_LSB) & SOC_TCXO_DETECT_PRESENT_MASK) + +#define SOC_XTAL_TEST_ADDRESS 0x00000008 +#define SOC_XTAL_TEST_OFFSET 0x00000008 +#define SOC_XTAL_TEST_NOTCXODET_MSB 0 +#define SOC_XTAL_TEST_NOTCXODET_LSB 0 +#define SOC_XTAL_TEST_NOTCXODET_MASK 0x00000001 +#define SOC_XTAL_TEST_NOTCXODET_GET(x) (((x) & SOC_XTAL_TEST_NOTCXODET_MASK) >> SOC_XTAL_TEST_NOTCXODET_LSB) +#define SOC_XTAL_TEST_NOTCXODET_SET(x) (((x) << SOC_XTAL_TEST_NOTCXODET_LSB) & SOC_XTAL_TEST_NOTCXODET_MASK) + +#define SOC_CPU_CLOCK_ADDRESS 0x00000020 +#define SOC_CPU_CLOCK_OFFSET 0x00000020 +#define SOC_CPU_CLOCK_STANDARD_MSB 1 +#define SOC_CPU_CLOCK_STANDARD_LSB 0 +#define SOC_CPU_CLOCK_STANDARD_MASK 0x00000003 +#define SOC_CPU_CLOCK_STANDARD_GET(x) (((x) & SOC_CPU_CLOCK_STANDARD_MASK) >> SOC_CPU_CLOCK_STANDARD_LSB) +#define SOC_CPU_CLOCK_STANDARD_SET(x) (((x) << SOC_CPU_CLOCK_STANDARD_LSB) & SOC_CPU_CLOCK_STANDARD_MASK) + +#define SOC_CLOCK_CONTROL_ADDRESS 0x00000028 +#define SOC_CLOCK_CONTROL_OFFSET 0x00000028 +#define SOC_CLOCK_CONTROL_USB_CLOCK_MSB 3 +#define SOC_CLOCK_CONTROL_USB_CLOCK_LSB 3 +#define SOC_CLOCK_CONTROL_USB_CLOCK_MASK 0x00000008 +#define SOC_CLOCK_CONTROL_USB_CLOCK_GET(x) (((x) & SOC_CLOCK_CONTROL_USB_CLOCK_MASK) >> SOC_CLOCK_CONTROL_USB_CLOCK_LSB) +#define SOC_CLOCK_CONTROL_USB_CLOCK_SET(x) (((x) << SOC_CLOCK_CONTROL_USB_CLOCK_LSB) & SOC_CLOCK_CONTROL_USB_CLOCK_MASK) +#define SOC_CLOCK_CONTROL_LF_CLK32_MSB 2 +#define SOC_CLOCK_CONTROL_LF_CLK32_LSB 2 +#define SOC_CLOCK_CONTROL_LF_CLK32_MASK 0x00000004 +#define SOC_CLOCK_CONTROL_LF_CLK32_GET(x) (((x) & SOC_CLOCK_CONTROL_LF_CLK32_MASK) >> SOC_CLOCK_CONTROL_LF_CLK32_LSB) +#define SOC_CLOCK_CONTROL_LF_CLK32_SET(x) (((x) << SOC_CLOCK_CONTROL_LF_CLK32_LSB) & SOC_CLOCK_CONTROL_LF_CLK32_MASK) +#define SOC_CLOCK_CONTROL_SI0_CLK_MSB 0 +#define SOC_CLOCK_CONTROL_SI0_CLK_LSB 0 +#define SOC_CLOCK_CONTROL_SI0_CLK_MASK 0x00000001 +#define SOC_CLOCK_CONTROL_SI0_CLK_GET(x) (((x) & SOC_CLOCK_CONTROL_SI0_CLK_MASK) >> SOC_CLOCK_CONTROL_SI0_CLK_LSB) +#define SOC_CLOCK_CONTROL_SI0_CLK_SET(x) (((x) << SOC_CLOCK_CONTROL_SI0_CLK_LSB) & SOC_CLOCK_CONTROL_SI0_CLK_MASK) + +#define SOC_WDT_CONTROL_ADDRESS 0x00000030 +#define SOC_WDT_CONTROL_OFFSET 0x00000030 +#define SOC_WDT_CONTROL_ACTION_MSB 2 +#define SOC_WDT_CONTROL_ACTION_LSB 0 +#define SOC_WDT_CONTROL_ACTION_MASK 0x00000007 +#define SOC_WDT_CONTROL_ACTION_GET(x) (((x) & SOC_WDT_CONTROL_ACTION_MASK) >> SOC_WDT_CONTROL_ACTION_LSB) +#define SOC_WDT_CONTROL_ACTION_SET(x) (((x) << SOC_WDT_CONTROL_ACTION_LSB) & SOC_WDT_CONTROL_ACTION_MASK) + +#define SOC_WDT_STATUS_ADDRESS 0x00000034 +#define SOC_WDT_STATUS_OFFSET 0x00000034 +#define SOC_WDT_STATUS_INTERRUPT_MSB 0 +#define SOC_WDT_STATUS_INTERRUPT_LSB 0 +#define SOC_WDT_STATUS_INTERRUPT_MASK 0x00000001 +#define SOC_WDT_STATUS_INTERRUPT_GET(x) (((x) & SOC_WDT_STATUS_INTERRUPT_MASK) >> SOC_WDT_STATUS_INTERRUPT_LSB) +#define SOC_WDT_STATUS_INTERRUPT_SET(x) (((x) << SOC_WDT_STATUS_INTERRUPT_LSB) & SOC_WDT_STATUS_INTERRUPT_MASK) + +#define SOC_WDT_ADDRESS 0x00000038 +#define SOC_WDT_OFFSET 0x00000038 +#define SOC_WDT_TARGET_MSB 21 +#define SOC_WDT_TARGET_LSB 0 +#define SOC_WDT_TARGET_MASK 0x003fffff +#define SOC_WDT_TARGET_GET(x) (((x) & SOC_WDT_TARGET_MASK) >> SOC_WDT_TARGET_LSB) +#define SOC_WDT_TARGET_SET(x) (((x) << SOC_WDT_TARGET_LSB) & SOC_WDT_TARGET_MASK) + +#define SOC_WDT_COUNT_ADDRESS 0x0000003c +#define SOC_WDT_COUNT_OFFSET 0x0000003c +#define SOC_WDT_COUNT_VALUE_MSB 21 +#define SOC_WDT_COUNT_VALUE_LSB 0 +#define SOC_WDT_COUNT_VALUE_MASK 0x003fffff +#define SOC_WDT_COUNT_VALUE_GET(x) (((x) & SOC_WDT_COUNT_VALUE_MASK) >> SOC_WDT_COUNT_VALUE_LSB) +#define SOC_WDT_COUNT_VALUE_SET(x) (((x) << SOC_WDT_COUNT_VALUE_LSB) & SOC_WDT_COUNT_VALUE_MASK) + +#define SOC_WDT_RESET_ADDRESS 0x00000040 +#define SOC_WDT_RESET_OFFSET 0x00000040 +#define SOC_WDT_RESET_VALUE_MSB 0 +#define SOC_WDT_RESET_VALUE_LSB 0 +#define SOC_WDT_RESET_VALUE_MASK 0x00000001 +#define SOC_WDT_RESET_VALUE_GET(x) (((x) & SOC_WDT_RESET_VALUE_MASK) >> SOC_WDT_RESET_VALUE_LSB) +#define SOC_WDT_RESET_VALUE_SET(x) (((x) << SOC_WDT_RESET_VALUE_LSB) & SOC_WDT_RESET_VALUE_MASK) + +#define SOC_INT_STATUS_ADDRESS 0x00000044 +#define SOC_INT_STATUS_OFFSET 0x00000044 +#define SOC_INT_STATUS_MAC_4_MSB 23 +#define SOC_INT_STATUS_MAC_4_LSB 23 +#define SOC_INT_STATUS_MAC_4_MASK 0x00800000 +#define SOC_INT_STATUS_MAC_4_GET(x) (((x) & SOC_INT_STATUS_MAC_4_MASK) >> SOC_INT_STATUS_MAC_4_LSB) +#define SOC_INT_STATUS_MAC_4_SET(x) (((x) << SOC_INT_STATUS_MAC_4_LSB) & SOC_INT_STATUS_MAC_4_MASK) +#define SOC_INT_STATUS_MAC_3_MSB 22 +#define SOC_INT_STATUS_MAC_3_LSB 22 +#define SOC_INT_STATUS_MAC_3_MASK 0x00400000 +#define SOC_INT_STATUS_MAC_3_GET(x) (((x) & SOC_INT_STATUS_MAC_3_MASK) >> SOC_INT_STATUS_MAC_3_LSB) +#define SOC_INT_STATUS_MAC_3_SET(x) (((x) << SOC_INT_STATUS_MAC_3_LSB) & SOC_INT_STATUS_MAC_3_MASK) +#define SOC_INT_STATUS_MAC_2_MSB 21 +#define SOC_INT_STATUS_MAC_2_LSB 21 +#define SOC_INT_STATUS_MAC_2_MASK 0x00200000 +#define SOC_INT_STATUS_MAC_2_GET(x) (((x) & SOC_INT_STATUS_MAC_2_MASK) >> SOC_INT_STATUS_MAC_2_LSB) +#define SOC_INT_STATUS_MAC_2_SET(x) (((x) << SOC_INT_STATUS_MAC_2_LSB) & SOC_INT_STATUS_MAC_2_MASK) +#define SOC_INT_STATUS_MAC_1_MSB 20 +#define SOC_INT_STATUS_MAC_1_LSB 20 +#define SOC_INT_STATUS_MAC_1_MASK 0x00100000 +#define SOC_INT_STATUS_MAC_1_GET(x) (((x) & SOC_INT_STATUS_MAC_1_MASK) >> SOC_INT_STATUS_MAC_1_LSB) +#define SOC_INT_STATUS_MAC_1_SET(x) (((x) << SOC_INT_STATUS_MAC_1_LSB) & SOC_INT_STATUS_MAC_1_MASK) +#define SOC_INT_STATUS_USBDMA_MSB 19 +#define SOC_INT_STATUS_USBDMA_LSB 19 +#define SOC_INT_STATUS_USBDMA_MASK 0x00080000 +#define SOC_INT_STATUS_USBDMA_GET(x) (((x) & SOC_INT_STATUS_USBDMA_MASK) >> SOC_INT_STATUS_USBDMA_LSB) +#define SOC_INT_STATUS_USBDMA_SET(x) (((x) << SOC_INT_STATUS_USBDMA_LSB) & SOC_INT_STATUS_USBDMA_MASK) +#define SOC_INT_STATUS_USBIP_MSB 18 +#define SOC_INT_STATUS_USBIP_LSB 18 +#define SOC_INT_STATUS_USBIP_MASK 0x00040000 +#define SOC_INT_STATUS_USBIP_GET(x) (((x) & SOC_INT_STATUS_USBIP_MASK) >> SOC_INT_STATUS_USBIP_LSB) +#define SOC_INT_STATUS_USBIP_SET(x) (((x) << SOC_INT_STATUS_USBIP_LSB) & SOC_INT_STATUS_USBIP_MASK) +#define SOC_INT_STATUS_THERM_MSB 17 +#define SOC_INT_STATUS_THERM_LSB 17 +#define SOC_INT_STATUS_THERM_MASK 0x00020000 +#define SOC_INT_STATUS_THERM_GET(x) (((x) & SOC_INT_STATUS_THERM_MASK) >> SOC_INT_STATUS_THERM_LSB) +#define SOC_INT_STATUS_THERM_SET(x) (((x) << SOC_INT_STATUS_THERM_LSB) & SOC_INT_STATUS_THERM_MASK) +#define SOC_INT_STATUS_EFUSE_OVERWRITE_MSB 16 +#define SOC_INT_STATUS_EFUSE_OVERWRITE_LSB 16 +#define SOC_INT_STATUS_EFUSE_OVERWRITE_MASK 0x00010000 +#define SOC_INT_STATUS_EFUSE_OVERWRITE_GET(x) (((x) & SOC_INT_STATUS_EFUSE_OVERWRITE_MASK) >> SOC_INT_STATUS_EFUSE_OVERWRITE_LSB) +#define SOC_INT_STATUS_EFUSE_OVERWRITE_SET(x) (((x) << SOC_INT_STATUS_EFUSE_OVERWRITE_LSB) & SOC_INT_STATUS_EFUSE_OVERWRITE_MASK) +#define SOC_INT_STATUS_RDMA_MSB 15 +#define SOC_INT_STATUS_RDMA_LSB 15 +#define SOC_INT_STATUS_RDMA_MASK 0x00008000 +#define SOC_INT_STATUS_RDMA_GET(x) (((x) & SOC_INT_STATUS_RDMA_MASK) >> SOC_INT_STATUS_RDMA_LSB) +#define SOC_INT_STATUS_RDMA_SET(x) (((x) << SOC_INT_STATUS_RDMA_LSB) & SOC_INT_STATUS_RDMA_MASK) +#define SOC_INT_STATUS_BTCOEX_MSB 14 +#define SOC_INT_STATUS_BTCOEX_LSB 14 +#define SOC_INT_STATUS_BTCOEX_MASK 0x00004000 +#define SOC_INT_STATUS_BTCOEX_GET(x) (((x) & SOC_INT_STATUS_BTCOEX_MASK) >> SOC_INT_STATUS_BTCOEX_LSB) +#define SOC_INT_STATUS_BTCOEX_SET(x) (((x) << SOC_INT_STATUS_BTCOEX_LSB) & SOC_INT_STATUS_BTCOEX_MASK) +#define SOC_INT_STATUS_RTC_POWER_MSB 13 +#define SOC_INT_STATUS_RTC_POWER_LSB 13 +#define SOC_INT_STATUS_RTC_POWER_MASK 0x00002000 +#define SOC_INT_STATUS_RTC_POWER_GET(x) (((x) & SOC_INT_STATUS_RTC_POWER_MASK) >> SOC_INT_STATUS_RTC_POWER_LSB) +#define SOC_INT_STATUS_RTC_POWER_SET(x) (((x) << SOC_INT_STATUS_RTC_POWER_LSB) & SOC_INT_STATUS_RTC_POWER_MASK) +#define SOC_INT_STATUS_MAC_MSB 12 +#define SOC_INT_STATUS_MAC_LSB 12 +#define SOC_INT_STATUS_MAC_MASK 0x00001000 +#define SOC_INT_STATUS_MAC_GET(x) (((x) & SOC_INT_STATUS_MAC_MASK) >> SOC_INT_STATUS_MAC_LSB) +#define SOC_INT_STATUS_MAC_SET(x) (((x) << SOC_INT_STATUS_MAC_LSB) & SOC_INT_STATUS_MAC_MASK) +#define SOC_INT_STATUS_MAILBOX_MSB 11 +#define SOC_INT_STATUS_MAILBOX_LSB 11 +#define SOC_INT_STATUS_MAILBOX_MASK 0x00000800 +#define SOC_INT_STATUS_MAILBOX_GET(x) (((x) & SOC_INT_STATUS_MAILBOX_MASK) >> SOC_INT_STATUS_MAILBOX_LSB) +#define SOC_INT_STATUS_MAILBOX_SET(x) (((x) << SOC_INT_STATUS_MAILBOX_LSB) & SOC_INT_STATUS_MAILBOX_MASK) +#define SOC_INT_STATUS_RTC_ALARM_MSB 10 +#define SOC_INT_STATUS_RTC_ALARM_LSB 10 +#define SOC_INT_STATUS_RTC_ALARM_MASK 0x00000400 +#define SOC_INT_STATUS_RTC_ALARM_GET(x) (((x) & SOC_INT_STATUS_RTC_ALARM_MASK) >> SOC_INT_STATUS_RTC_ALARM_LSB) +#define SOC_INT_STATUS_RTC_ALARM_SET(x) (((x) << SOC_INT_STATUS_RTC_ALARM_LSB) & SOC_INT_STATUS_RTC_ALARM_MASK) +#define SOC_INT_STATUS_HF_TIMER_MSB 9 +#define SOC_INT_STATUS_HF_TIMER_LSB 9 +#define SOC_INT_STATUS_HF_TIMER_MASK 0x00000200 +#define SOC_INT_STATUS_HF_TIMER_GET(x) (((x) & SOC_INT_STATUS_HF_TIMER_MASK) >> SOC_INT_STATUS_HF_TIMER_LSB) +#define SOC_INT_STATUS_HF_TIMER_SET(x) (((x) << SOC_INT_STATUS_HF_TIMER_LSB) & SOC_INT_STATUS_HF_TIMER_MASK) +#define SOC_INT_STATUS_LF_TIMER3_MSB 8 +#define SOC_INT_STATUS_LF_TIMER3_LSB 8 +#define SOC_INT_STATUS_LF_TIMER3_MASK 0x00000100 +#define SOC_INT_STATUS_LF_TIMER3_GET(x) (((x) & SOC_INT_STATUS_LF_TIMER3_MASK) >> SOC_INT_STATUS_LF_TIMER3_LSB) +#define SOC_INT_STATUS_LF_TIMER3_SET(x) (((x) << SOC_INT_STATUS_LF_TIMER3_LSB) & SOC_INT_STATUS_LF_TIMER3_MASK) +#define SOC_INT_STATUS_LF_TIMER2_MSB 7 +#define SOC_INT_STATUS_LF_TIMER2_LSB 7 +#define SOC_INT_STATUS_LF_TIMER2_MASK 0x00000080 +#define SOC_INT_STATUS_LF_TIMER2_GET(x) (((x) & SOC_INT_STATUS_LF_TIMER2_MASK) >> SOC_INT_STATUS_LF_TIMER2_LSB) +#define SOC_INT_STATUS_LF_TIMER2_SET(x) (((x) << SOC_INT_STATUS_LF_TIMER2_LSB) & SOC_INT_STATUS_LF_TIMER2_MASK) +#define SOC_INT_STATUS_LF_TIMER1_MSB 6 +#define SOC_INT_STATUS_LF_TIMER1_LSB 6 +#define SOC_INT_STATUS_LF_TIMER1_MASK 0x00000040 +#define SOC_INT_STATUS_LF_TIMER1_GET(x) (((x) & SOC_INT_STATUS_LF_TIMER1_MASK) >> SOC_INT_STATUS_LF_TIMER1_LSB) +#define SOC_INT_STATUS_LF_TIMER1_SET(x) (((x) << SOC_INT_STATUS_LF_TIMER1_LSB) & SOC_INT_STATUS_LF_TIMER1_MASK) +#define SOC_INT_STATUS_LF_TIMER0_MSB 5 +#define SOC_INT_STATUS_LF_TIMER0_LSB 5 +#define SOC_INT_STATUS_LF_TIMER0_MASK 0x00000020 +#define SOC_INT_STATUS_LF_TIMER0_GET(x) (((x) & SOC_INT_STATUS_LF_TIMER0_MASK) >> SOC_INT_STATUS_LF_TIMER0_LSB) +#define SOC_INT_STATUS_LF_TIMER0_SET(x) (((x) << SOC_INT_STATUS_LF_TIMER0_LSB) & SOC_INT_STATUS_LF_TIMER0_MASK) +#define SOC_INT_STATUS_SI_MSB 4 +#define SOC_INT_STATUS_SI_LSB 4 +#define SOC_INT_STATUS_SI_MASK 0x00000010 +#define SOC_INT_STATUS_SI_GET(x) (((x) & SOC_INT_STATUS_SI_MASK) >> SOC_INT_STATUS_SI_LSB) +#define SOC_INT_STATUS_SI_SET(x) (((x) << SOC_INT_STATUS_SI_LSB) & SOC_INT_STATUS_SI_MASK) +#define SOC_INT_STATUS_GPIO_MSB 3 +#define SOC_INT_STATUS_GPIO_LSB 3 +#define SOC_INT_STATUS_GPIO_MASK 0x00000008 +#define SOC_INT_STATUS_GPIO_GET(x) (((x) & SOC_INT_STATUS_GPIO_MASK) >> SOC_INT_STATUS_GPIO_LSB) +#define SOC_INT_STATUS_GPIO_SET(x) (((x) << SOC_INT_STATUS_GPIO_LSB) & SOC_INT_STATUS_GPIO_MASK) +#define SOC_INT_STATUS_DEBUG_UART_MSB 2 +#define SOC_INT_STATUS_DEBUG_UART_LSB 2 +#define SOC_INT_STATUS_DEBUG_UART_MASK 0x00000004 +#define SOC_INT_STATUS_DEBUG_UART_GET(x) (((x) & SOC_INT_STATUS_DEBUG_UART_MASK) >> SOC_INT_STATUS_DEBUG_UART_LSB) +#define SOC_INT_STATUS_DEBUG_UART_SET(x) (((x) << SOC_INT_STATUS_DEBUG_UART_LSB) & SOC_INT_STATUS_DEBUG_UART_MASK) +#define SOC_INT_STATUS_ERROR_MSB 1 +#define SOC_INT_STATUS_ERROR_LSB 1 +#define SOC_INT_STATUS_ERROR_MASK 0x00000002 +#define SOC_INT_STATUS_ERROR_GET(x) (((x) & SOC_INT_STATUS_ERROR_MASK) >> SOC_INT_STATUS_ERROR_LSB) +#define SOC_INT_STATUS_ERROR_SET(x) (((x) << SOC_INT_STATUS_ERROR_LSB) & SOC_INT_STATUS_ERROR_MASK) +#define SOC_INT_STATUS_WDT_INT_MSB 0 +#define SOC_INT_STATUS_WDT_INT_LSB 0 +#define SOC_INT_STATUS_WDT_INT_MASK 0x00000001 +#define SOC_INT_STATUS_WDT_INT_GET(x) (((x) & SOC_INT_STATUS_WDT_INT_MASK) >> SOC_INT_STATUS_WDT_INT_LSB) +#define SOC_INT_STATUS_WDT_INT_SET(x) (((x) << SOC_INT_STATUS_WDT_INT_LSB) & SOC_INT_STATUS_WDT_INT_MASK) + +#define SOC_LF_TIMER0_ADDRESS 0x00000048 +#define SOC_LF_TIMER0_OFFSET 0x00000048 +#define SOC_LF_TIMER0_TARGET_MSB 31 +#define SOC_LF_TIMER0_TARGET_LSB 0 +#define SOC_LF_TIMER0_TARGET_MASK 0xffffffff +#define SOC_LF_TIMER0_TARGET_GET(x) (((x) & SOC_LF_TIMER0_TARGET_MASK) >> SOC_LF_TIMER0_TARGET_LSB) +#define SOC_LF_TIMER0_TARGET_SET(x) (((x) << SOC_LF_TIMER0_TARGET_LSB) & SOC_LF_TIMER0_TARGET_MASK) + +#define SOC_LF_TIMER_COUNT0_ADDRESS 0x0000004c +#define SOC_LF_TIMER_COUNT0_OFFSET 0x0000004c +#define SOC_LF_TIMER_COUNT0_VALUE_MSB 31 +#define SOC_LF_TIMER_COUNT0_VALUE_LSB 0 +#define SOC_LF_TIMER_COUNT0_VALUE_MASK 0xffffffff +#define SOC_LF_TIMER_COUNT0_VALUE_GET(x) (((x) & SOC_LF_TIMER_COUNT0_VALUE_MASK) >> SOC_LF_TIMER_COUNT0_VALUE_LSB) +#define SOC_LF_TIMER_COUNT0_VALUE_SET(x) (((x) << SOC_LF_TIMER_COUNT0_VALUE_LSB) & SOC_LF_TIMER_COUNT0_VALUE_MASK) + +#define SOC_LF_TIMER_CONTROL0_ADDRESS 0x00000050 +#define SOC_LF_TIMER_CONTROL0_OFFSET 0x00000050 +#define SOC_LF_TIMER_CONTROL0_ENABLE_MSB 2 +#define SOC_LF_TIMER_CONTROL0_ENABLE_LSB 2 +#define SOC_LF_TIMER_CONTROL0_ENABLE_MASK 0x00000004 +#define SOC_LF_TIMER_CONTROL0_ENABLE_GET(x) (((x) & SOC_LF_TIMER_CONTROL0_ENABLE_MASK) >> SOC_LF_TIMER_CONTROL0_ENABLE_LSB) +#define SOC_LF_TIMER_CONTROL0_ENABLE_SET(x) (((x) << SOC_LF_TIMER_CONTROL0_ENABLE_LSB) & SOC_LF_TIMER_CONTROL0_ENABLE_MASK) +#define SOC_LF_TIMER_CONTROL0_AUTO_RESTART_MSB 1 +#define SOC_LF_TIMER_CONTROL0_AUTO_RESTART_LSB 1 +#define SOC_LF_TIMER_CONTROL0_AUTO_RESTART_MASK 0x00000002 +#define SOC_LF_TIMER_CONTROL0_AUTO_RESTART_GET(x) (((x) & SOC_LF_TIMER_CONTROL0_AUTO_RESTART_MASK) >> SOC_LF_TIMER_CONTROL0_AUTO_RESTART_LSB) +#define SOC_LF_TIMER_CONTROL0_AUTO_RESTART_SET(x) (((x) << SOC_LF_TIMER_CONTROL0_AUTO_RESTART_LSB) & SOC_LF_TIMER_CONTROL0_AUTO_RESTART_MASK) +#define SOC_LF_TIMER_CONTROL0_RESET_MSB 0 +#define SOC_LF_TIMER_CONTROL0_RESET_LSB 0 +#define SOC_LF_TIMER_CONTROL0_RESET_MASK 0x00000001 +#define SOC_LF_TIMER_CONTROL0_RESET_GET(x) (((x) & SOC_LF_TIMER_CONTROL0_RESET_MASK) >> SOC_LF_TIMER_CONTROL0_RESET_LSB) +#define SOC_LF_TIMER_CONTROL0_RESET_SET(x) (((x) << SOC_LF_TIMER_CONTROL0_RESET_LSB) & SOC_LF_TIMER_CONTROL0_RESET_MASK) + +#define SOC_LF_TIMER_STATUS0_ADDRESS 0x00000054 +#define SOC_LF_TIMER_STATUS0_OFFSET 0x00000054 +#define SOC_LF_TIMER_STATUS0_INTERRUPT_MSB 0 +#define SOC_LF_TIMER_STATUS0_INTERRUPT_LSB 0 +#define SOC_LF_TIMER_STATUS0_INTERRUPT_MASK 0x00000001 +#define SOC_LF_TIMER_STATUS0_INTERRUPT_GET(x) (((x) & SOC_LF_TIMER_STATUS0_INTERRUPT_MASK) >> SOC_LF_TIMER_STATUS0_INTERRUPT_LSB) +#define SOC_LF_TIMER_STATUS0_INTERRUPT_SET(x) (((x) << SOC_LF_TIMER_STATUS0_INTERRUPT_LSB) & SOC_LF_TIMER_STATUS0_INTERRUPT_MASK) + +#define SOC_LF_TIMER1_ADDRESS 0x00000058 +#define SOC_LF_TIMER1_OFFSET 0x00000058 +#define SOC_LF_TIMER1_TARGET_MSB 31 +#define SOC_LF_TIMER1_TARGET_LSB 0 +#define SOC_LF_TIMER1_TARGET_MASK 0xffffffff +#define SOC_LF_TIMER1_TARGET_GET(x) (((x) & SOC_LF_TIMER1_TARGET_MASK) >> SOC_LF_TIMER1_TARGET_LSB) +#define SOC_LF_TIMER1_TARGET_SET(x) (((x) << SOC_LF_TIMER1_TARGET_LSB) & SOC_LF_TIMER1_TARGET_MASK) + +#define SOC_LF_TIMER_COUNT1_ADDRESS 0x0000005c +#define SOC_LF_TIMER_COUNT1_OFFSET 0x0000005c +#define SOC_LF_TIMER_COUNT1_VALUE_MSB 31 +#define SOC_LF_TIMER_COUNT1_VALUE_LSB 0 +#define SOC_LF_TIMER_COUNT1_VALUE_MASK 0xffffffff +#define SOC_LF_TIMER_COUNT1_VALUE_GET(x) (((x) & SOC_LF_TIMER_COUNT1_VALUE_MASK) >> SOC_LF_TIMER_COUNT1_VALUE_LSB) +#define SOC_LF_TIMER_COUNT1_VALUE_SET(x) (((x) << SOC_LF_TIMER_COUNT1_VALUE_LSB) & SOC_LF_TIMER_COUNT1_VALUE_MASK) + +#define SOC_LF_TIMER_CONTROL1_ADDRESS 0x00000060 +#define SOC_LF_TIMER_CONTROL1_OFFSET 0x00000060 +#define SOC_LF_TIMER_CONTROL1_ENABLE_MSB 2 +#define SOC_LF_TIMER_CONTROL1_ENABLE_LSB 2 +#define SOC_LF_TIMER_CONTROL1_ENABLE_MASK 0x00000004 +#define SOC_LF_TIMER_CONTROL1_ENABLE_GET(x) (((x) & SOC_LF_TIMER_CONTROL1_ENABLE_MASK) >> SOC_LF_TIMER_CONTROL1_ENABLE_LSB) +#define SOC_LF_TIMER_CONTROL1_ENABLE_SET(x) (((x) << SOC_LF_TIMER_CONTROL1_ENABLE_LSB) & SOC_LF_TIMER_CONTROL1_ENABLE_MASK) +#define SOC_LF_TIMER_CONTROL1_AUTO_RESTART_MSB 1 +#define SOC_LF_TIMER_CONTROL1_AUTO_RESTART_LSB 1 +#define SOC_LF_TIMER_CONTROL1_AUTO_RESTART_MASK 0x00000002 +#define SOC_LF_TIMER_CONTROL1_AUTO_RESTART_GET(x) (((x) & SOC_LF_TIMER_CONTROL1_AUTO_RESTART_MASK) >> SOC_LF_TIMER_CONTROL1_AUTO_RESTART_LSB) +#define SOC_LF_TIMER_CONTROL1_AUTO_RESTART_SET(x) (((x) << SOC_LF_TIMER_CONTROL1_AUTO_RESTART_LSB) & SOC_LF_TIMER_CONTROL1_AUTO_RESTART_MASK) +#define SOC_LF_TIMER_CONTROL1_RESET_MSB 0 +#define SOC_LF_TIMER_CONTROL1_RESET_LSB 0 +#define SOC_LF_TIMER_CONTROL1_RESET_MASK 0x00000001 +#define SOC_LF_TIMER_CONTROL1_RESET_GET(x) (((x) & SOC_LF_TIMER_CONTROL1_RESET_MASK) >> SOC_LF_TIMER_CONTROL1_RESET_LSB) +#define SOC_LF_TIMER_CONTROL1_RESET_SET(x) (((x) << SOC_LF_TIMER_CONTROL1_RESET_LSB) & SOC_LF_TIMER_CONTROL1_RESET_MASK) + +#define SOC_LF_TIMER_STATUS1_ADDRESS 0x00000064 +#define SOC_LF_TIMER_STATUS1_OFFSET 0x00000064 +#define SOC_LF_TIMER_STATUS1_INTERRUPT_MSB 0 +#define SOC_LF_TIMER_STATUS1_INTERRUPT_LSB 0 +#define SOC_LF_TIMER_STATUS1_INTERRUPT_MASK 0x00000001 +#define SOC_LF_TIMER_STATUS1_INTERRUPT_GET(x) (((x) & SOC_LF_TIMER_STATUS1_INTERRUPT_MASK) >> SOC_LF_TIMER_STATUS1_INTERRUPT_LSB) +#define SOC_LF_TIMER_STATUS1_INTERRUPT_SET(x) (((x) << SOC_LF_TIMER_STATUS1_INTERRUPT_LSB) & SOC_LF_TIMER_STATUS1_INTERRUPT_MASK) + +#define SOC_LF_TIMER2_ADDRESS 0x00000068 +#define SOC_LF_TIMER2_OFFSET 0x00000068 +#define SOC_LF_TIMER2_TARGET_MSB 31 +#define SOC_LF_TIMER2_TARGET_LSB 0 +#define SOC_LF_TIMER2_TARGET_MASK 0xffffffff +#define SOC_LF_TIMER2_TARGET_GET(x) (((x) & SOC_LF_TIMER2_TARGET_MASK) >> SOC_LF_TIMER2_TARGET_LSB) +#define SOC_LF_TIMER2_TARGET_SET(x) (((x) << SOC_LF_TIMER2_TARGET_LSB) & SOC_LF_TIMER2_TARGET_MASK) + +#define SOC_LF_TIMER_COUNT2_ADDRESS 0x0000006c +#define SOC_LF_TIMER_COUNT2_OFFSET 0x0000006c +#define SOC_LF_TIMER_COUNT2_VALUE_MSB 31 +#define SOC_LF_TIMER_COUNT2_VALUE_LSB 0 +#define SOC_LF_TIMER_COUNT2_VALUE_MASK 0xffffffff +#define SOC_LF_TIMER_COUNT2_VALUE_GET(x) (((x) & SOC_LF_TIMER_COUNT2_VALUE_MASK) >> SOC_LF_TIMER_COUNT2_VALUE_LSB) +#define SOC_LF_TIMER_COUNT2_VALUE_SET(x) (((x) << SOC_LF_TIMER_COUNT2_VALUE_LSB) & SOC_LF_TIMER_COUNT2_VALUE_MASK) + +#define SOC_LF_TIMER_CONTROL2_ADDRESS 0x00000070 +#define SOC_LF_TIMER_CONTROL2_OFFSET 0x00000070 +#define SOC_LF_TIMER_CONTROL2_ENABLE_MSB 2 +#define SOC_LF_TIMER_CONTROL2_ENABLE_LSB 2 +#define SOC_LF_TIMER_CONTROL2_ENABLE_MASK 0x00000004 +#define SOC_LF_TIMER_CONTROL2_ENABLE_GET(x) (((x) & SOC_LF_TIMER_CONTROL2_ENABLE_MASK) >> SOC_LF_TIMER_CONTROL2_ENABLE_LSB) +#define SOC_LF_TIMER_CONTROL2_ENABLE_SET(x) (((x) << SOC_LF_TIMER_CONTROL2_ENABLE_LSB) & SOC_LF_TIMER_CONTROL2_ENABLE_MASK) +#define SOC_LF_TIMER_CONTROL2_AUTO_RESTART_MSB 1 +#define SOC_LF_TIMER_CONTROL2_AUTO_RESTART_LSB 1 +#define SOC_LF_TIMER_CONTROL2_AUTO_RESTART_MASK 0x00000002 +#define SOC_LF_TIMER_CONTROL2_AUTO_RESTART_GET(x) (((x) & SOC_LF_TIMER_CONTROL2_AUTO_RESTART_MASK) >> SOC_LF_TIMER_CONTROL2_AUTO_RESTART_LSB) +#define SOC_LF_TIMER_CONTROL2_AUTO_RESTART_SET(x) (((x) << SOC_LF_TIMER_CONTROL2_AUTO_RESTART_LSB) & SOC_LF_TIMER_CONTROL2_AUTO_RESTART_MASK) +#define SOC_LF_TIMER_CONTROL2_RESET_MSB 0 +#define SOC_LF_TIMER_CONTROL2_RESET_LSB 0 +#define SOC_LF_TIMER_CONTROL2_RESET_MASK 0x00000001 +#define SOC_LF_TIMER_CONTROL2_RESET_GET(x) (((x) & SOC_LF_TIMER_CONTROL2_RESET_MASK) >> SOC_LF_TIMER_CONTROL2_RESET_LSB) +#define SOC_LF_TIMER_CONTROL2_RESET_SET(x) (((x) << SOC_LF_TIMER_CONTROL2_RESET_LSB) & SOC_LF_TIMER_CONTROL2_RESET_MASK) + +#define SOC_LF_TIMER_STATUS2_ADDRESS 0x00000074 +#define SOC_LF_TIMER_STATUS2_OFFSET 0x00000074 +#define SOC_LF_TIMER_STATUS2_INTERRUPT_MSB 0 +#define SOC_LF_TIMER_STATUS2_INTERRUPT_LSB 0 +#define SOC_LF_TIMER_STATUS2_INTERRUPT_MASK 0x00000001 +#define SOC_LF_TIMER_STATUS2_INTERRUPT_GET(x) (((x) & SOC_LF_TIMER_STATUS2_INTERRUPT_MASK) >> SOC_LF_TIMER_STATUS2_INTERRUPT_LSB) +#define SOC_LF_TIMER_STATUS2_INTERRUPT_SET(x) (((x) << SOC_LF_TIMER_STATUS2_INTERRUPT_LSB) & SOC_LF_TIMER_STATUS2_INTERRUPT_MASK) + +#define SOC_LF_TIMER3_ADDRESS 0x00000078 +#define SOC_LF_TIMER3_OFFSET 0x00000078 +#define SOC_LF_TIMER3_TARGET_MSB 31 +#define SOC_LF_TIMER3_TARGET_LSB 0 +#define SOC_LF_TIMER3_TARGET_MASK 0xffffffff +#define SOC_LF_TIMER3_TARGET_GET(x) (((x) & SOC_LF_TIMER3_TARGET_MASK) >> SOC_LF_TIMER3_TARGET_LSB) +#define SOC_LF_TIMER3_TARGET_SET(x) (((x) << SOC_LF_TIMER3_TARGET_LSB) & SOC_LF_TIMER3_TARGET_MASK) + +#define SOC_LF_TIMER_COUNT3_ADDRESS 0x0000007c +#define SOC_LF_TIMER_COUNT3_OFFSET 0x0000007c +#define SOC_LF_TIMER_COUNT3_VALUE_MSB 31 +#define SOC_LF_TIMER_COUNT3_VALUE_LSB 0 +#define SOC_LF_TIMER_COUNT3_VALUE_MASK 0xffffffff +#define SOC_LF_TIMER_COUNT3_VALUE_GET(x) (((x) & SOC_LF_TIMER_COUNT3_VALUE_MASK) >> SOC_LF_TIMER_COUNT3_VALUE_LSB) +#define SOC_LF_TIMER_COUNT3_VALUE_SET(x) (((x) << SOC_LF_TIMER_COUNT3_VALUE_LSB) & SOC_LF_TIMER_COUNT3_VALUE_MASK) + +#define SOC_LF_TIMER_CONTROL3_ADDRESS 0x00000080 +#define SOC_LF_TIMER_CONTROL3_OFFSET 0x00000080 +#define SOC_LF_TIMER_CONTROL3_ENABLE_MSB 2 +#define SOC_LF_TIMER_CONTROL3_ENABLE_LSB 2 +#define SOC_LF_TIMER_CONTROL3_ENABLE_MASK 0x00000004 +#define SOC_LF_TIMER_CONTROL3_ENABLE_GET(x) (((x) & SOC_LF_TIMER_CONTROL3_ENABLE_MASK) >> SOC_LF_TIMER_CONTROL3_ENABLE_LSB) +#define SOC_LF_TIMER_CONTROL3_ENABLE_SET(x) (((x) << SOC_LF_TIMER_CONTROL3_ENABLE_LSB) & SOC_LF_TIMER_CONTROL3_ENABLE_MASK) +#define SOC_LF_TIMER_CONTROL3_AUTO_RESTART_MSB 1 +#define SOC_LF_TIMER_CONTROL3_AUTO_RESTART_LSB 1 +#define SOC_LF_TIMER_CONTROL3_AUTO_RESTART_MASK 0x00000002 +#define SOC_LF_TIMER_CONTROL3_AUTO_RESTART_GET(x) (((x) & SOC_LF_TIMER_CONTROL3_AUTO_RESTART_MASK) >> SOC_LF_TIMER_CONTROL3_AUTO_RESTART_LSB) +#define SOC_LF_TIMER_CONTROL3_AUTO_RESTART_SET(x) (((x) << SOC_LF_TIMER_CONTROL3_AUTO_RESTART_LSB) & SOC_LF_TIMER_CONTROL3_AUTO_RESTART_MASK) +#define SOC_LF_TIMER_CONTROL3_RESET_MSB 0 +#define SOC_LF_TIMER_CONTROL3_RESET_LSB 0 +#define SOC_LF_TIMER_CONTROL3_RESET_MASK 0x00000001 +#define SOC_LF_TIMER_CONTROL3_RESET_GET(x) (((x) & SOC_LF_TIMER_CONTROL3_RESET_MASK) >> SOC_LF_TIMER_CONTROL3_RESET_LSB) +#define SOC_LF_TIMER_CONTROL3_RESET_SET(x) (((x) << SOC_LF_TIMER_CONTROL3_RESET_LSB) & SOC_LF_TIMER_CONTROL3_RESET_MASK) + +#define SOC_LF_TIMER_STATUS3_ADDRESS 0x00000084 +#define SOC_LF_TIMER_STATUS3_OFFSET 0x00000084 +#define SOC_LF_TIMER_STATUS3_INTERRUPT_MSB 0 +#define SOC_LF_TIMER_STATUS3_INTERRUPT_LSB 0 +#define SOC_LF_TIMER_STATUS3_INTERRUPT_MASK 0x00000001 +#define SOC_LF_TIMER_STATUS3_INTERRUPT_GET(x) (((x) & SOC_LF_TIMER_STATUS3_INTERRUPT_MASK) >> SOC_LF_TIMER_STATUS3_INTERRUPT_LSB) +#define SOC_LF_TIMER_STATUS3_INTERRUPT_SET(x) (((x) << SOC_LF_TIMER_STATUS3_INTERRUPT_LSB) & SOC_LF_TIMER_STATUS3_INTERRUPT_MASK) + +#define SOC_HF_TIMER_ADDRESS 0x00000088 +#define SOC_HF_TIMER_OFFSET 0x00000088 +#define SOC_HF_TIMER_TARGET_MSB 31 +#define SOC_HF_TIMER_TARGET_LSB 12 +#define SOC_HF_TIMER_TARGET_MASK 0xfffff000 +#define SOC_HF_TIMER_TARGET_GET(x) (((x) & SOC_HF_TIMER_TARGET_MASK) >> SOC_HF_TIMER_TARGET_LSB) +#define SOC_HF_TIMER_TARGET_SET(x) (((x) << SOC_HF_TIMER_TARGET_LSB) & SOC_HF_TIMER_TARGET_MASK) + +#define SOC_HF_TIMER_COUNT_ADDRESS 0x0000008c +#define SOC_HF_TIMER_COUNT_OFFSET 0x0000008c +#define SOC_HF_TIMER_COUNT_VALUE_MSB 31 +#define SOC_HF_TIMER_COUNT_VALUE_LSB 12 +#define SOC_HF_TIMER_COUNT_VALUE_MASK 0xfffff000 +#define SOC_HF_TIMER_COUNT_VALUE_GET(x) (((x) & SOC_HF_TIMER_COUNT_VALUE_MASK) >> SOC_HF_TIMER_COUNT_VALUE_LSB) +#define SOC_HF_TIMER_COUNT_VALUE_SET(x) (((x) << SOC_HF_TIMER_COUNT_VALUE_LSB) & SOC_HF_TIMER_COUNT_VALUE_MASK) + +#define SOC_HF_LF_COUNT_ADDRESS 0x00000090 +#define SOC_HF_LF_COUNT_OFFSET 0x00000090 +#define SOC_HF_LF_COUNT_VALUE_MSB 31 +#define SOC_HF_LF_COUNT_VALUE_LSB 0 +#define SOC_HF_LF_COUNT_VALUE_MASK 0xffffffff +#define SOC_HF_LF_COUNT_VALUE_GET(x) (((x) & SOC_HF_LF_COUNT_VALUE_MASK) >> SOC_HF_LF_COUNT_VALUE_LSB) +#define SOC_HF_LF_COUNT_VALUE_SET(x) (((x) << SOC_HF_LF_COUNT_VALUE_LSB) & SOC_HF_LF_COUNT_VALUE_MASK) + +#define SOC_HF_TIMER_CONTROL_ADDRESS 0x00000094 +#define SOC_HF_TIMER_CONTROL_OFFSET 0x00000094 +#define SOC_HF_TIMER_CONTROL_ENABLE_MSB 3 +#define SOC_HF_TIMER_CONTROL_ENABLE_LSB 3 +#define SOC_HF_TIMER_CONTROL_ENABLE_MASK 0x00000008 +#define SOC_HF_TIMER_CONTROL_ENABLE_GET(x) (((x) & SOC_HF_TIMER_CONTROL_ENABLE_MASK) >> SOC_HF_TIMER_CONTROL_ENABLE_LSB) +#define SOC_HF_TIMER_CONTROL_ENABLE_SET(x) (((x) << SOC_HF_TIMER_CONTROL_ENABLE_LSB) & SOC_HF_TIMER_CONTROL_ENABLE_MASK) +#define SOC_HF_TIMER_CONTROL_ON_MSB 2 +#define SOC_HF_TIMER_CONTROL_ON_LSB 2 +#define SOC_HF_TIMER_CONTROL_ON_MASK 0x00000004 +#define SOC_HF_TIMER_CONTROL_ON_GET(x) (((x) & SOC_HF_TIMER_CONTROL_ON_MASK) >> SOC_HF_TIMER_CONTROL_ON_LSB) +#define SOC_HF_TIMER_CONTROL_ON_SET(x) (((x) << SOC_HF_TIMER_CONTROL_ON_LSB) & SOC_HF_TIMER_CONTROL_ON_MASK) +#define SOC_HF_TIMER_CONTROL_AUTO_RESTART_MSB 1 +#define SOC_HF_TIMER_CONTROL_AUTO_RESTART_LSB 1 +#define SOC_HF_TIMER_CONTROL_AUTO_RESTART_MASK 0x00000002 +#define SOC_HF_TIMER_CONTROL_AUTO_RESTART_GET(x) (((x) & SOC_HF_TIMER_CONTROL_AUTO_RESTART_MASK) >> SOC_HF_TIMER_CONTROL_AUTO_RESTART_LSB) +#define SOC_HF_TIMER_CONTROL_AUTO_RESTART_SET(x) (((x) << SOC_HF_TIMER_CONTROL_AUTO_RESTART_LSB) & SOC_HF_TIMER_CONTROL_AUTO_RESTART_MASK) +#define SOC_HF_TIMER_CONTROL_RESET_MSB 0 +#define SOC_HF_TIMER_CONTROL_RESET_LSB 0 +#define SOC_HF_TIMER_CONTROL_RESET_MASK 0x00000001 +#define SOC_HF_TIMER_CONTROL_RESET_GET(x) (((x) & SOC_HF_TIMER_CONTROL_RESET_MASK) >> SOC_HF_TIMER_CONTROL_RESET_LSB) +#define SOC_HF_TIMER_CONTROL_RESET_SET(x) (((x) << SOC_HF_TIMER_CONTROL_RESET_LSB) & SOC_HF_TIMER_CONTROL_RESET_MASK) + +#define SOC_HF_TIMER_STATUS_ADDRESS 0x00000098 +#define SOC_HF_TIMER_STATUS_OFFSET 0x00000098 +#define SOC_HF_TIMER_STATUS_INTERRUPT_MSB 0 +#define SOC_HF_TIMER_STATUS_INTERRUPT_LSB 0 +#define SOC_HF_TIMER_STATUS_INTERRUPT_MASK 0x00000001 +#define SOC_HF_TIMER_STATUS_INTERRUPT_GET(x) (((x) & SOC_HF_TIMER_STATUS_INTERRUPT_MASK) >> SOC_HF_TIMER_STATUS_INTERRUPT_LSB) +#define SOC_HF_TIMER_STATUS_INTERRUPT_SET(x) (((x) << SOC_HF_TIMER_STATUS_INTERRUPT_LSB) & SOC_HF_TIMER_STATUS_INTERRUPT_MASK) + +#define SOC_RTC_CONTROL_ADDRESS 0x0000009c +#define SOC_RTC_CONTROL_OFFSET 0x0000009c +#define SOC_RTC_CONTROL_ENABLE_MSB 2 +#define SOC_RTC_CONTROL_ENABLE_LSB 2 +#define SOC_RTC_CONTROL_ENABLE_MASK 0x00000004 +#define SOC_RTC_CONTROL_ENABLE_GET(x) (((x) & SOC_RTC_CONTROL_ENABLE_MASK) >> SOC_RTC_CONTROL_ENABLE_LSB) +#define SOC_RTC_CONTROL_ENABLE_SET(x) (((x) << SOC_RTC_CONTROL_ENABLE_LSB) & SOC_RTC_CONTROL_ENABLE_MASK) +#define SOC_RTC_CONTROL_LOAD_RTC_MSB 1 +#define SOC_RTC_CONTROL_LOAD_RTC_LSB 1 +#define SOC_RTC_CONTROL_LOAD_RTC_MASK 0x00000002 +#define SOC_RTC_CONTROL_LOAD_RTC_GET(x) (((x) & SOC_RTC_CONTROL_LOAD_RTC_MASK) >> SOC_RTC_CONTROL_LOAD_RTC_LSB) +#define SOC_RTC_CONTROL_LOAD_RTC_SET(x) (((x) << SOC_RTC_CONTROL_LOAD_RTC_LSB) & SOC_RTC_CONTROL_LOAD_RTC_MASK) +#define SOC_RTC_CONTROL_LOAD_ALARM_MSB 0 +#define SOC_RTC_CONTROL_LOAD_ALARM_LSB 0 +#define SOC_RTC_CONTROL_LOAD_ALARM_MASK 0x00000001 +#define SOC_RTC_CONTROL_LOAD_ALARM_GET(x) (((x) & SOC_RTC_CONTROL_LOAD_ALARM_MASK) >> SOC_RTC_CONTROL_LOAD_ALARM_LSB) +#define SOC_RTC_CONTROL_LOAD_ALARM_SET(x) (((x) << SOC_RTC_CONTROL_LOAD_ALARM_LSB) & SOC_RTC_CONTROL_LOAD_ALARM_MASK) + +#define SOC_RTC_TIME_ADDRESS 0x000000a0 +#define SOC_RTC_TIME_OFFSET 0x000000a0 +#define SOC_RTC_TIME_WEEK_DAY_MSB 26 +#define SOC_RTC_TIME_WEEK_DAY_LSB 24 +#define SOC_RTC_TIME_WEEK_DAY_MASK 0x07000000 +#define SOC_RTC_TIME_WEEK_DAY_GET(x) (((x) & SOC_RTC_TIME_WEEK_DAY_MASK) >> SOC_RTC_TIME_WEEK_DAY_LSB) +#define SOC_RTC_TIME_WEEK_DAY_SET(x) (((x) << SOC_RTC_TIME_WEEK_DAY_LSB) & SOC_RTC_TIME_WEEK_DAY_MASK) +#define SOC_RTC_TIME_HOUR_MSB 21 +#define SOC_RTC_TIME_HOUR_LSB 16 +#define SOC_RTC_TIME_HOUR_MASK 0x003f0000 +#define SOC_RTC_TIME_HOUR_GET(x) (((x) & SOC_RTC_TIME_HOUR_MASK) >> SOC_RTC_TIME_HOUR_LSB) +#define SOC_RTC_TIME_HOUR_SET(x) (((x) << SOC_RTC_TIME_HOUR_LSB) & SOC_RTC_TIME_HOUR_MASK) +#define SOC_RTC_TIME_MINUTE_MSB 14 +#define SOC_RTC_TIME_MINUTE_LSB 8 +#define SOC_RTC_TIME_MINUTE_MASK 0x00007f00 +#define SOC_RTC_TIME_MINUTE_GET(x) (((x) & SOC_RTC_TIME_MINUTE_MASK) >> SOC_RTC_TIME_MINUTE_LSB) +#define SOC_RTC_TIME_MINUTE_SET(x) (((x) << SOC_RTC_TIME_MINUTE_LSB) & SOC_RTC_TIME_MINUTE_MASK) +#define SOC_RTC_TIME_SECOND_MSB 6 +#define SOC_RTC_TIME_SECOND_LSB 0 +#define SOC_RTC_TIME_SECOND_MASK 0x0000007f +#define SOC_RTC_TIME_SECOND_GET(x) (((x) & SOC_RTC_TIME_SECOND_MASK) >> SOC_RTC_TIME_SECOND_LSB) +#define SOC_RTC_TIME_SECOND_SET(x) (((x) << SOC_RTC_TIME_SECOND_LSB) & SOC_RTC_TIME_SECOND_MASK) + +#define SOC_RTC_DATE_ADDRESS 0x000000a4 +#define SOC_RTC_DATE_OFFSET 0x000000a4 +#define SOC_RTC_DATE_YEAR_MSB 23 +#define SOC_RTC_DATE_YEAR_LSB 16 +#define SOC_RTC_DATE_YEAR_MASK 0x00ff0000 +#define SOC_RTC_DATE_YEAR_GET(x) (((x) & SOC_RTC_DATE_YEAR_MASK) >> SOC_RTC_DATE_YEAR_LSB) +#define SOC_RTC_DATE_YEAR_SET(x) (((x) << SOC_RTC_DATE_YEAR_LSB) & SOC_RTC_DATE_YEAR_MASK) +#define SOC_RTC_DATE_MONTH_MSB 12 +#define SOC_RTC_DATE_MONTH_LSB 8 +#define SOC_RTC_DATE_MONTH_MASK 0x00001f00 +#define SOC_RTC_DATE_MONTH_GET(x) (((x) & SOC_RTC_DATE_MONTH_MASK) >> SOC_RTC_DATE_MONTH_LSB) +#define SOC_RTC_DATE_MONTH_SET(x) (((x) << SOC_RTC_DATE_MONTH_LSB) & SOC_RTC_DATE_MONTH_MASK) +#define SOC_RTC_DATE_MONTH_DAY_MSB 5 +#define SOC_RTC_DATE_MONTH_DAY_LSB 0 +#define SOC_RTC_DATE_MONTH_DAY_MASK 0x0000003f +#define SOC_RTC_DATE_MONTH_DAY_GET(x) (((x) & SOC_RTC_DATE_MONTH_DAY_MASK) >> SOC_RTC_DATE_MONTH_DAY_LSB) +#define SOC_RTC_DATE_MONTH_DAY_SET(x) (((x) << SOC_RTC_DATE_MONTH_DAY_LSB) & SOC_RTC_DATE_MONTH_DAY_MASK) + +#define SOC_RTC_SET_TIME_ADDRESS 0x000000a8 +#define SOC_RTC_SET_TIME_OFFSET 0x000000a8 +#define SOC_RTC_SET_TIME_WEEK_DAY_MSB 26 +#define SOC_RTC_SET_TIME_WEEK_DAY_LSB 24 +#define SOC_RTC_SET_TIME_WEEK_DAY_MASK 0x07000000 +#define SOC_RTC_SET_TIME_WEEK_DAY_GET(x) (((x) & SOC_RTC_SET_TIME_WEEK_DAY_MASK) >> SOC_RTC_SET_TIME_WEEK_DAY_LSB) +#define SOC_RTC_SET_TIME_WEEK_DAY_SET(x) (((x) << SOC_RTC_SET_TIME_WEEK_DAY_LSB) & SOC_RTC_SET_TIME_WEEK_DAY_MASK) +#define SOC_RTC_SET_TIME_HOUR_MSB 21 +#define SOC_RTC_SET_TIME_HOUR_LSB 16 +#define SOC_RTC_SET_TIME_HOUR_MASK 0x003f0000 +#define SOC_RTC_SET_TIME_HOUR_GET(x) (((x) & SOC_RTC_SET_TIME_HOUR_MASK) >> SOC_RTC_SET_TIME_HOUR_LSB) +#define SOC_RTC_SET_TIME_HOUR_SET(x) (((x) << SOC_RTC_SET_TIME_HOUR_LSB) & SOC_RTC_SET_TIME_HOUR_MASK) +#define SOC_RTC_SET_TIME_MINUTE_MSB 14 +#define SOC_RTC_SET_TIME_MINUTE_LSB 8 +#define SOC_RTC_SET_TIME_MINUTE_MASK 0x00007f00 +#define SOC_RTC_SET_TIME_MINUTE_GET(x) (((x) & SOC_RTC_SET_TIME_MINUTE_MASK) >> SOC_RTC_SET_TIME_MINUTE_LSB) +#define SOC_RTC_SET_TIME_MINUTE_SET(x) (((x) << SOC_RTC_SET_TIME_MINUTE_LSB) & SOC_RTC_SET_TIME_MINUTE_MASK) +#define SOC_RTC_SET_TIME_SECOND_MSB 6 +#define SOC_RTC_SET_TIME_SECOND_LSB 0 +#define SOC_RTC_SET_TIME_SECOND_MASK 0x0000007f +#define SOC_RTC_SET_TIME_SECOND_GET(x) (((x) & SOC_RTC_SET_TIME_SECOND_MASK) >> SOC_RTC_SET_TIME_SECOND_LSB) +#define SOC_RTC_SET_TIME_SECOND_SET(x) (((x) << SOC_RTC_SET_TIME_SECOND_LSB) & SOC_RTC_SET_TIME_SECOND_MASK) + +#define SOC_RTC_SET_DATE_ADDRESS 0x000000ac +#define SOC_RTC_SET_DATE_OFFSET 0x000000ac +#define SOC_RTC_SET_DATE_YEAR_MSB 23 +#define SOC_RTC_SET_DATE_YEAR_LSB 16 +#define SOC_RTC_SET_DATE_YEAR_MASK 0x00ff0000 +#define SOC_RTC_SET_DATE_YEAR_GET(x) (((x) & SOC_RTC_SET_DATE_YEAR_MASK) >> SOC_RTC_SET_DATE_YEAR_LSB) +#define SOC_RTC_SET_DATE_YEAR_SET(x) (((x) << SOC_RTC_SET_DATE_YEAR_LSB) & SOC_RTC_SET_DATE_YEAR_MASK) +#define SOC_RTC_SET_DATE_MONTH_MSB 12 +#define SOC_RTC_SET_DATE_MONTH_LSB 8 +#define SOC_RTC_SET_DATE_MONTH_MASK 0x00001f00 +#define SOC_RTC_SET_DATE_MONTH_GET(x) (((x) & SOC_RTC_SET_DATE_MONTH_MASK) >> SOC_RTC_SET_DATE_MONTH_LSB) +#define SOC_RTC_SET_DATE_MONTH_SET(x) (((x) << SOC_RTC_SET_DATE_MONTH_LSB) & SOC_RTC_SET_DATE_MONTH_MASK) +#define SOC_RTC_SET_DATE_MONTH_DAY_MSB 5 +#define SOC_RTC_SET_DATE_MONTH_DAY_LSB 0 +#define SOC_RTC_SET_DATE_MONTH_DAY_MASK 0x0000003f +#define SOC_RTC_SET_DATE_MONTH_DAY_GET(x) (((x) & SOC_RTC_SET_DATE_MONTH_DAY_MASK) >> SOC_RTC_SET_DATE_MONTH_DAY_LSB) +#define SOC_RTC_SET_DATE_MONTH_DAY_SET(x) (((x) << SOC_RTC_SET_DATE_MONTH_DAY_LSB) & SOC_RTC_SET_DATE_MONTH_DAY_MASK) + +#define SOC_RTC_SET_ALARM_ADDRESS 0x000000b0 +#define SOC_RTC_SET_ALARM_OFFSET 0x000000b0 +#define SOC_RTC_SET_ALARM_HOUR_MSB 21 +#define SOC_RTC_SET_ALARM_HOUR_LSB 16 +#define SOC_RTC_SET_ALARM_HOUR_MASK 0x003f0000 +#define SOC_RTC_SET_ALARM_HOUR_GET(x) (((x) & SOC_RTC_SET_ALARM_HOUR_MASK) >> SOC_RTC_SET_ALARM_HOUR_LSB) +#define SOC_RTC_SET_ALARM_HOUR_SET(x) (((x) << SOC_RTC_SET_ALARM_HOUR_LSB) & SOC_RTC_SET_ALARM_HOUR_MASK) +#define SOC_RTC_SET_ALARM_MINUTE_MSB 14 +#define SOC_RTC_SET_ALARM_MINUTE_LSB 8 +#define SOC_RTC_SET_ALARM_MINUTE_MASK 0x00007f00 +#define SOC_RTC_SET_ALARM_MINUTE_GET(x) (((x) & SOC_RTC_SET_ALARM_MINUTE_MASK) >> SOC_RTC_SET_ALARM_MINUTE_LSB) +#define SOC_RTC_SET_ALARM_MINUTE_SET(x) (((x) << SOC_RTC_SET_ALARM_MINUTE_LSB) & SOC_RTC_SET_ALARM_MINUTE_MASK) +#define SOC_RTC_SET_ALARM_SECOND_MSB 6 +#define SOC_RTC_SET_ALARM_SECOND_LSB 0 +#define SOC_RTC_SET_ALARM_SECOND_MASK 0x0000007f +#define SOC_RTC_SET_ALARM_SECOND_GET(x) (((x) & SOC_RTC_SET_ALARM_SECOND_MASK) >> SOC_RTC_SET_ALARM_SECOND_LSB) +#define SOC_RTC_SET_ALARM_SECOND_SET(x) (((x) << SOC_RTC_SET_ALARM_SECOND_LSB) & SOC_RTC_SET_ALARM_SECOND_MASK) + +#define SOC_RTC_CONFIG_ADDRESS 0x000000b4 +#define SOC_RTC_CONFIG_OFFSET 0x000000b4 +#define SOC_RTC_CONFIG_BCD_MSB 2 +#define SOC_RTC_CONFIG_BCD_LSB 2 +#define SOC_RTC_CONFIG_BCD_MASK 0x00000004 +#define SOC_RTC_CONFIG_BCD_GET(x) (((x) & SOC_RTC_CONFIG_BCD_MASK) >> SOC_RTC_CONFIG_BCD_LSB) +#define SOC_RTC_CONFIG_BCD_SET(x) (((x) << SOC_RTC_CONFIG_BCD_LSB) & SOC_RTC_CONFIG_BCD_MASK) +#define SOC_RTC_CONFIG_TWELVE_HOUR_MSB 1 +#define SOC_RTC_CONFIG_TWELVE_HOUR_LSB 1 +#define SOC_RTC_CONFIG_TWELVE_HOUR_MASK 0x00000002 +#define SOC_RTC_CONFIG_TWELVE_HOUR_GET(x) (((x) & SOC_RTC_CONFIG_TWELVE_HOUR_MASK) >> SOC_RTC_CONFIG_TWELVE_HOUR_LSB) +#define SOC_RTC_CONFIG_TWELVE_HOUR_SET(x) (((x) << SOC_RTC_CONFIG_TWELVE_HOUR_LSB) & SOC_RTC_CONFIG_TWELVE_HOUR_MASK) +#define SOC_RTC_CONFIG_DSE_MSB 0 +#define SOC_RTC_CONFIG_DSE_LSB 0 +#define SOC_RTC_CONFIG_DSE_MASK 0x00000001 +#define SOC_RTC_CONFIG_DSE_GET(x) (((x) & SOC_RTC_CONFIG_DSE_MASK) >> SOC_RTC_CONFIG_DSE_LSB) +#define SOC_RTC_CONFIG_DSE_SET(x) (((x) << SOC_RTC_CONFIG_DSE_LSB) & SOC_RTC_CONFIG_DSE_MASK) + +#define SOC_RTC_ALARM_STATUS_ADDRESS 0x000000b8 +#define SOC_RTC_ALARM_STATUS_OFFSET 0x000000b8 +#define SOC_RTC_ALARM_STATUS_ENABLE_MSB 1 +#define SOC_RTC_ALARM_STATUS_ENABLE_LSB 1 +#define SOC_RTC_ALARM_STATUS_ENABLE_MASK 0x00000002 +#define SOC_RTC_ALARM_STATUS_ENABLE_GET(x) (((x) & SOC_RTC_ALARM_STATUS_ENABLE_MASK) >> SOC_RTC_ALARM_STATUS_ENABLE_LSB) +#define SOC_RTC_ALARM_STATUS_ENABLE_SET(x) (((x) << SOC_RTC_ALARM_STATUS_ENABLE_LSB) & SOC_RTC_ALARM_STATUS_ENABLE_MASK) +#define SOC_RTC_ALARM_STATUS_INTERRUPT_MSB 0 +#define SOC_RTC_ALARM_STATUS_INTERRUPT_LSB 0 +#define SOC_RTC_ALARM_STATUS_INTERRUPT_MASK 0x00000001 +#define SOC_RTC_ALARM_STATUS_INTERRUPT_GET(x) (((x) & SOC_RTC_ALARM_STATUS_INTERRUPT_MASK) >> SOC_RTC_ALARM_STATUS_INTERRUPT_LSB) +#define SOC_RTC_ALARM_STATUS_INTERRUPT_SET(x) (((x) << SOC_RTC_ALARM_STATUS_INTERRUPT_LSB) & SOC_RTC_ALARM_STATUS_INTERRUPT_MASK) + +#define SOC_UART_WAKEUP_ADDRESS 0x000000bc +#define SOC_UART_WAKEUP_OFFSET 0x000000bc +#define SOC_UART_WAKEUP_ENABLE_MSB 0 +#define SOC_UART_WAKEUP_ENABLE_LSB 0 +#define SOC_UART_WAKEUP_ENABLE_MASK 0x00000001 +#define SOC_UART_WAKEUP_ENABLE_GET(x) (((x) & SOC_UART_WAKEUP_ENABLE_MASK) >> SOC_UART_WAKEUP_ENABLE_LSB) +#define SOC_UART_WAKEUP_ENABLE_SET(x) (((x) << SOC_UART_WAKEUP_ENABLE_LSB) & SOC_UART_WAKEUP_ENABLE_MASK) + +#define SOC_RESET_CAUSE_ADDRESS 0x000000c0 +#define SOC_RESET_CAUSE_OFFSET 0x000000c0 +#define SOC_RESET_CAUSE_LAST_MSB 2 +#define SOC_RESET_CAUSE_LAST_LSB 0 +#define SOC_RESET_CAUSE_LAST_MASK 0x00000007 +#define SOC_RESET_CAUSE_LAST_GET(x) (((x) & SOC_RESET_CAUSE_LAST_MASK) >> SOC_RESET_CAUSE_LAST_LSB) +#define SOC_RESET_CAUSE_LAST_SET(x) (((x) << SOC_RESET_CAUSE_LAST_LSB) & SOC_RESET_CAUSE_LAST_MASK) + +#define SOC_SYSTEM_SLEEP_ADDRESS 0x000000c4 +#define SOC_SYSTEM_SLEEP_OFFSET 0x000000c4 +#define SOC_SYSTEM_SLEEP_MCI_MSB 5 +#define SOC_SYSTEM_SLEEP_MCI_LSB 5 +#define SOC_SYSTEM_SLEEP_MCI_MASK 0x00000020 +#define SOC_SYSTEM_SLEEP_MCI_GET(x) (((x) & SOC_SYSTEM_SLEEP_MCI_MASK) >> SOC_SYSTEM_SLEEP_MCI_LSB) +#define SOC_SYSTEM_SLEEP_MCI_SET(x) (((x) << SOC_SYSTEM_SLEEP_MCI_LSB) & SOC_SYSTEM_SLEEP_MCI_MASK) +#define SOC_SYSTEM_SLEEP_HOST_IF_MSB 4 +#define SOC_SYSTEM_SLEEP_HOST_IF_LSB 4 +#define SOC_SYSTEM_SLEEP_HOST_IF_MASK 0x00000010 +#define SOC_SYSTEM_SLEEP_HOST_IF_GET(x) (((x) & SOC_SYSTEM_SLEEP_HOST_IF_MASK) >> SOC_SYSTEM_SLEEP_HOST_IF_LSB) +#define SOC_SYSTEM_SLEEP_HOST_IF_SET(x) (((x) << SOC_SYSTEM_SLEEP_HOST_IF_LSB) & SOC_SYSTEM_SLEEP_HOST_IF_MASK) +#define SOC_SYSTEM_SLEEP_MBOX_MSB 3 +#define SOC_SYSTEM_SLEEP_MBOX_LSB 3 +#define SOC_SYSTEM_SLEEP_MBOX_MASK 0x00000008 +#define SOC_SYSTEM_SLEEP_MBOX_GET(x) (((x) & SOC_SYSTEM_SLEEP_MBOX_MASK) >> SOC_SYSTEM_SLEEP_MBOX_LSB) +#define SOC_SYSTEM_SLEEP_MBOX_SET(x) (((x) << SOC_SYSTEM_SLEEP_MBOX_LSB) & SOC_SYSTEM_SLEEP_MBOX_MASK) +#define SOC_SYSTEM_SLEEP_MAC_IF_MSB 2 +#define SOC_SYSTEM_SLEEP_MAC_IF_LSB 2 +#define SOC_SYSTEM_SLEEP_MAC_IF_MASK 0x00000004 +#define SOC_SYSTEM_SLEEP_MAC_IF_GET(x) (((x) & SOC_SYSTEM_SLEEP_MAC_IF_MASK) >> SOC_SYSTEM_SLEEP_MAC_IF_LSB) +#define SOC_SYSTEM_SLEEP_MAC_IF_SET(x) (((x) << SOC_SYSTEM_SLEEP_MAC_IF_LSB) & SOC_SYSTEM_SLEEP_MAC_IF_MASK) +#define SOC_SYSTEM_SLEEP_LIGHT_MSB 1 +#define SOC_SYSTEM_SLEEP_LIGHT_LSB 1 +#define SOC_SYSTEM_SLEEP_LIGHT_MASK 0x00000002 +#define SOC_SYSTEM_SLEEP_LIGHT_GET(x) (((x) & SOC_SYSTEM_SLEEP_LIGHT_MASK) >> SOC_SYSTEM_SLEEP_LIGHT_LSB) +#define SOC_SYSTEM_SLEEP_LIGHT_SET(x) (((x) << SOC_SYSTEM_SLEEP_LIGHT_LSB) & SOC_SYSTEM_SLEEP_LIGHT_MASK) +#define SOC_SYSTEM_SLEEP_DISABLE_MSB 0 +#define SOC_SYSTEM_SLEEP_DISABLE_LSB 0 +#define SOC_SYSTEM_SLEEP_DISABLE_MASK 0x00000001 +#define SOC_SYSTEM_SLEEP_DISABLE_GET(x) (((x) & SOC_SYSTEM_SLEEP_DISABLE_MASK) >> SOC_SYSTEM_SLEEP_DISABLE_LSB) +#define SOC_SYSTEM_SLEEP_DISABLE_SET(x) (((x) << SOC_SYSTEM_SLEEP_DISABLE_LSB) & SOC_SYSTEM_SLEEP_DISABLE_MASK) + +#define SOC_SDIO_WRAPPER_ADDRESS 0x000000c8 +#define SOC_SDIO_WRAPPER_OFFSET 0x000000c8 +#define SOC_SDIO_WRAPPER_SLEEP_MSB 3 +#define SOC_SDIO_WRAPPER_SLEEP_LSB 3 +#define SOC_SDIO_WRAPPER_SLEEP_MASK 0x00000008 +#define SOC_SDIO_WRAPPER_SLEEP_GET(x) (((x) & SOC_SDIO_WRAPPER_SLEEP_MASK) >> SOC_SDIO_WRAPPER_SLEEP_LSB) +#define SOC_SDIO_WRAPPER_SLEEP_SET(x) (((x) << SOC_SDIO_WRAPPER_SLEEP_LSB) & SOC_SDIO_WRAPPER_SLEEP_MASK) +#define SOC_SDIO_WRAPPER_WAKEUP_MSB 2 +#define SOC_SDIO_WRAPPER_WAKEUP_LSB 2 +#define SOC_SDIO_WRAPPER_WAKEUP_MASK 0x00000004 +#define SOC_SDIO_WRAPPER_WAKEUP_GET(x) (((x) & SOC_SDIO_WRAPPER_WAKEUP_MASK) >> SOC_SDIO_WRAPPER_WAKEUP_LSB) +#define SOC_SDIO_WRAPPER_WAKEUP_SET(x) (((x) << SOC_SDIO_WRAPPER_WAKEUP_LSB) & SOC_SDIO_WRAPPER_WAKEUP_MASK) +#define SOC_SDIO_WRAPPER_SOC_ON_MSB 1 +#define SOC_SDIO_WRAPPER_SOC_ON_LSB 1 +#define SOC_SDIO_WRAPPER_SOC_ON_MASK 0x00000002 +#define SOC_SDIO_WRAPPER_SOC_ON_GET(x) (((x) & SOC_SDIO_WRAPPER_SOC_ON_MASK) >> SOC_SDIO_WRAPPER_SOC_ON_LSB) +#define SOC_SDIO_WRAPPER_SOC_ON_SET(x) (((x) << SOC_SDIO_WRAPPER_SOC_ON_LSB) & SOC_SDIO_WRAPPER_SOC_ON_MASK) +#define SOC_SDIO_WRAPPER_ON_MSB 0 +#define SOC_SDIO_WRAPPER_ON_LSB 0 +#define SOC_SDIO_WRAPPER_ON_MASK 0x00000001 +#define SOC_SDIO_WRAPPER_ON_GET(x) (((x) & SOC_SDIO_WRAPPER_ON_MASK) >> SOC_SDIO_WRAPPER_ON_LSB) +#define SOC_SDIO_WRAPPER_ON_SET(x) (((x) << SOC_SDIO_WRAPPER_ON_LSB) & SOC_SDIO_WRAPPER_ON_MASK) + +#define SOC_INT_SLEEP_MASK_ADDRESS 0x000000cc +#define SOC_INT_SLEEP_MASK_OFFSET 0x000000cc +#define SOC_INT_SLEEP_MASK_BITMAP_MSB 31 +#define SOC_INT_SLEEP_MASK_BITMAP_LSB 0 +#define SOC_INT_SLEEP_MASK_BITMAP_MASK 0xffffffff +#define SOC_INT_SLEEP_MASK_BITMAP_GET(x) (((x) & SOC_INT_SLEEP_MASK_BITMAP_MASK) >> SOC_INT_SLEEP_MASK_BITMAP_LSB) +#define SOC_INT_SLEEP_MASK_BITMAP_SET(x) (((x) << SOC_INT_SLEEP_MASK_BITMAP_LSB) & SOC_INT_SLEEP_MASK_BITMAP_MASK) + +#define SOC_LPO_CAL_TIME_ADDRESS 0x000000d4 +#define SOC_LPO_CAL_TIME_OFFSET 0x000000d4 +#define SOC_LPO_CAL_TIME_LENGTH_MSB 13 +#define SOC_LPO_CAL_TIME_LENGTH_LSB 0 +#define SOC_LPO_CAL_TIME_LENGTH_MASK 0x00003fff +#define SOC_LPO_CAL_TIME_LENGTH_GET(x) (((x) & SOC_LPO_CAL_TIME_LENGTH_MASK) >> SOC_LPO_CAL_TIME_LENGTH_LSB) +#define SOC_LPO_CAL_TIME_LENGTH_SET(x) (((x) << SOC_LPO_CAL_TIME_LENGTH_LSB) & SOC_LPO_CAL_TIME_LENGTH_MASK) + +#define SOC_LPO_INIT_DIVIDEND_INT_ADDRESS 0x000000d8 +#define SOC_LPO_INIT_DIVIDEND_INT_OFFSET 0x000000d8 +#define SOC_LPO_INIT_DIVIDEND_INT_VALUE_MSB 23 +#define SOC_LPO_INIT_DIVIDEND_INT_VALUE_LSB 0 +#define SOC_LPO_INIT_DIVIDEND_INT_VALUE_MASK 0x00ffffff +#define SOC_LPO_INIT_DIVIDEND_INT_VALUE_GET(x) (((x) & SOC_LPO_INIT_DIVIDEND_INT_VALUE_MASK) >> SOC_LPO_INIT_DIVIDEND_INT_VALUE_LSB) +#define SOC_LPO_INIT_DIVIDEND_INT_VALUE_SET(x) (((x) << SOC_LPO_INIT_DIVIDEND_INT_VALUE_LSB) & SOC_LPO_INIT_DIVIDEND_INT_VALUE_MASK) + +#define SOC_LPO_INIT_DIVIDEND_FRACTION_ADDRESS 0x000000dc +#define SOC_LPO_INIT_DIVIDEND_FRACTION_OFFSET 0x000000dc +#define SOC_LPO_INIT_DIVIDEND_FRACTION_VALUE_MSB 10 +#define SOC_LPO_INIT_DIVIDEND_FRACTION_VALUE_LSB 0 +#define SOC_LPO_INIT_DIVIDEND_FRACTION_VALUE_MASK 0x000007ff +#define SOC_LPO_INIT_DIVIDEND_FRACTION_VALUE_GET(x) (((x) & SOC_LPO_INIT_DIVIDEND_FRACTION_VALUE_MASK) >> SOC_LPO_INIT_DIVIDEND_FRACTION_VALUE_LSB) +#define SOC_LPO_INIT_DIVIDEND_FRACTION_VALUE_SET(x) (((x) << SOC_LPO_INIT_DIVIDEND_FRACTION_VALUE_LSB) & SOC_LPO_INIT_DIVIDEND_FRACTION_VALUE_MASK) + +#define SOC_LPO_CAL_ADDRESS 0x000000e0 +#define SOC_LPO_CAL_OFFSET 0x000000e0 +#define SOC_LPO_CAL_ENABLE_MSB 20 +#define SOC_LPO_CAL_ENABLE_LSB 20 +#define SOC_LPO_CAL_ENABLE_MASK 0x00100000 +#define SOC_LPO_CAL_ENABLE_GET(x) (((x) & SOC_LPO_CAL_ENABLE_MASK) >> SOC_LPO_CAL_ENABLE_LSB) +#define SOC_LPO_CAL_ENABLE_SET(x) (((x) << SOC_LPO_CAL_ENABLE_LSB) & SOC_LPO_CAL_ENABLE_MASK) +#define SOC_LPO_CAL_COUNT_MSB 19 +#define SOC_LPO_CAL_COUNT_LSB 0 +#define SOC_LPO_CAL_COUNT_MASK 0x000fffff +#define SOC_LPO_CAL_COUNT_GET(x) (((x) & SOC_LPO_CAL_COUNT_MASK) >> SOC_LPO_CAL_COUNT_LSB) +#define SOC_LPO_CAL_COUNT_SET(x) (((x) << SOC_LPO_CAL_COUNT_LSB) & SOC_LPO_CAL_COUNT_MASK) + +#define SOC_LPO_CAL_TEST_CONTROL_ADDRESS 0x000000e4 +#define SOC_LPO_CAL_TEST_CONTROL_OFFSET 0x000000e4 +#define SOC_LPO_CAL_TEST_CONTROL_ENABLE_MSB 16 +#define SOC_LPO_CAL_TEST_CONTROL_ENABLE_LSB 16 +#define SOC_LPO_CAL_TEST_CONTROL_ENABLE_MASK 0x00010000 +#define SOC_LPO_CAL_TEST_CONTROL_ENABLE_GET(x) (((x) & SOC_LPO_CAL_TEST_CONTROL_ENABLE_MASK) >> SOC_LPO_CAL_TEST_CONTROL_ENABLE_LSB) +#define SOC_LPO_CAL_TEST_CONTROL_ENABLE_SET(x) (((x) << SOC_LPO_CAL_TEST_CONTROL_ENABLE_LSB) & SOC_LPO_CAL_TEST_CONTROL_ENABLE_MASK) +#define SOC_LPO_CAL_TEST_CONTROL_RTC_CYCLES_MSB 15 +#define SOC_LPO_CAL_TEST_CONTROL_RTC_CYCLES_LSB 0 +#define SOC_LPO_CAL_TEST_CONTROL_RTC_CYCLES_MASK 0x0000ffff +#define SOC_LPO_CAL_TEST_CONTROL_RTC_CYCLES_GET(x) (((x) & SOC_LPO_CAL_TEST_CONTROL_RTC_CYCLES_MASK) >> SOC_LPO_CAL_TEST_CONTROL_RTC_CYCLES_LSB) +#define SOC_LPO_CAL_TEST_CONTROL_RTC_CYCLES_SET(x) (((x) << SOC_LPO_CAL_TEST_CONTROL_RTC_CYCLES_LSB) & SOC_LPO_CAL_TEST_CONTROL_RTC_CYCLES_MASK) + +#define SOC_LPO_CAL_TEST_STATUS_ADDRESS 0x000000e8 +#define SOC_LPO_CAL_TEST_STATUS_OFFSET 0x000000e8 +#define SOC_LPO_CAL_TEST_STATUS_READY_MSB 16 +#define SOC_LPO_CAL_TEST_STATUS_READY_LSB 16 +#define SOC_LPO_CAL_TEST_STATUS_READY_MASK 0x00010000 +#define SOC_LPO_CAL_TEST_STATUS_READY_GET(x) (((x) & SOC_LPO_CAL_TEST_STATUS_READY_MASK) >> SOC_LPO_CAL_TEST_STATUS_READY_LSB) +#define SOC_LPO_CAL_TEST_STATUS_READY_SET(x) (((x) << SOC_LPO_CAL_TEST_STATUS_READY_LSB) & SOC_LPO_CAL_TEST_STATUS_READY_MASK) +#define SOC_LPO_CAL_TEST_STATUS_COUNT_MSB 15 +#define SOC_LPO_CAL_TEST_STATUS_COUNT_LSB 0 +#define SOC_LPO_CAL_TEST_STATUS_COUNT_MASK 0x0000ffff +#define SOC_LPO_CAL_TEST_STATUS_COUNT_GET(x) (((x) & SOC_LPO_CAL_TEST_STATUS_COUNT_MASK) >> SOC_LPO_CAL_TEST_STATUS_COUNT_LSB) +#define SOC_LPO_CAL_TEST_STATUS_COUNT_SET(x) (((x) << SOC_LPO_CAL_TEST_STATUS_COUNT_LSB) & SOC_LPO_CAL_TEST_STATUS_COUNT_MASK) + +#define LEGACY_SOC_CHIP_ID_ADDRESS 0x000000ec +#define LEGACY_SOC_CHIP_ID_OFFSET 0x000000ec +#define LEGACY_SOC_CHIP_ID_DEVICE_ID_MSB 31 +#define LEGACY_SOC_CHIP_ID_DEVICE_ID_LSB 16 +#define LEGACY_SOC_CHIP_ID_DEVICE_ID_MASK 0xffff0000 +#define LEGACY_SOC_CHIP_ID_DEVICE_ID_GET(x) (((x) & LEGACY_SOC_CHIP_ID_DEVICE_ID_MASK) >> LEGACY_SOC_CHIP_ID_DEVICE_ID_LSB) +#define LEGACY_SOC_CHIP_ID_DEVICE_ID_SET(x) (((x) << LEGACY_SOC_CHIP_ID_DEVICE_ID_LSB) & LEGACY_SOC_CHIP_ID_DEVICE_ID_MASK) +#define LEGACY_SOC_CHIP_ID_CONFIG_ID_MSB 15 +#define LEGACY_SOC_CHIP_ID_CONFIG_ID_LSB 4 +#define LEGACY_SOC_CHIP_ID_CONFIG_ID_MASK 0x0000fff0 +#define LEGACY_SOC_CHIP_ID_CONFIG_ID_GET(x) (((x) & LEGACY_SOC_CHIP_ID_CONFIG_ID_MASK) >> LEGACY_SOC_CHIP_ID_CONFIG_ID_LSB) +#define LEGACY_SOC_CHIP_ID_CONFIG_ID_SET(x) (((x) << LEGACY_SOC_CHIP_ID_CONFIG_ID_LSB) & LEGACY_SOC_CHIP_ID_CONFIG_ID_MASK) +#define LEGACY_SOC_CHIP_ID_VERSION_ID_MSB 3 +#define LEGACY_SOC_CHIP_ID_VERSION_ID_LSB 0 +#define LEGACY_SOC_CHIP_ID_VERSION_ID_MASK 0x0000000f +#define LEGACY_SOC_CHIP_ID_VERSION_ID_GET(x) (((x) & LEGACY_SOC_CHIP_ID_VERSION_ID_MASK) >> LEGACY_SOC_CHIP_ID_VERSION_ID_LSB) +#define LEGACY_SOC_CHIP_ID_VERSION_ID_SET(x) (((x) << LEGACY_SOC_CHIP_ID_VERSION_ID_LSB) & LEGACY_SOC_CHIP_ID_VERSION_ID_MASK) + +#define SOC_CHIP_ID_ADDRESS 0x000000f0 +#define SOC_CHIP_ID_OFFSET 0x000000f0 +#define SOC_CHIP_ID_DEVICE_ID_MSB 31 +#define SOC_CHIP_ID_DEVICE_ID_LSB 16 +#define SOC_CHIP_ID_DEVICE_ID_MASK 0xffff0000 +#define SOC_CHIP_ID_DEVICE_ID_GET(x) (((x) & SOC_CHIP_ID_DEVICE_ID_MASK) >> SOC_CHIP_ID_DEVICE_ID_LSB) +#define SOC_CHIP_ID_DEVICE_ID_SET(x) (((x) << SOC_CHIP_ID_DEVICE_ID_LSB) & SOC_CHIP_ID_DEVICE_ID_MASK) +#define SOC_CHIP_ID_CONFIG_ID_MSB 15 +#define SOC_CHIP_ID_CONFIG_ID_LSB 4 +#define SOC_CHIP_ID_CONFIG_ID_MASK 0x0000fff0 +#define SOC_CHIP_ID_CONFIG_ID_GET(x) (((x) & SOC_CHIP_ID_CONFIG_ID_MASK) >> SOC_CHIP_ID_CONFIG_ID_LSB) +#define SOC_CHIP_ID_CONFIG_ID_SET(x) (((x) << SOC_CHIP_ID_CONFIG_ID_LSB) & SOC_CHIP_ID_CONFIG_ID_MASK) +#define SOC_CHIP_ID_VERSION_ID_MSB 3 +#define SOC_CHIP_ID_VERSION_ID_LSB 0 +#define SOC_CHIP_ID_VERSION_ID_MASK 0x0000000f +#define SOC_CHIP_ID_VERSION_ID_GET(x) (((x) & SOC_CHIP_ID_VERSION_ID_MASK) >> SOC_CHIP_ID_VERSION_ID_LSB) +#define SOC_CHIP_ID_VERSION_ID_SET(x) (((x) << SOC_CHIP_ID_VERSION_ID_LSB) & SOC_CHIP_ID_VERSION_ID_MASK) + +#define SOC_POWER_REG_ADDRESS 0x0000010c +#define SOC_POWER_REG_OFFSET 0x0000010c +#define SOC_POWER_REG_DISCON_MODE_EN_MSB 16 +#define SOC_POWER_REG_DISCON_MODE_EN_LSB 16 +#define SOC_POWER_REG_DISCON_MODE_EN_MASK 0x00010000 +#define SOC_POWER_REG_DISCON_MODE_EN_GET(x) (((x) & SOC_POWER_REG_DISCON_MODE_EN_MASK) >> SOC_POWER_REG_DISCON_MODE_EN_LSB) +#define SOC_POWER_REG_DISCON_MODE_EN_SET(x) (((x) << SOC_POWER_REG_DISCON_MODE_EN_LSB) & SOC_POWER_REG_DISCON_MODE_EN_MASK) +#define SOC_POWER_REG_DEEP_SLEEP_EN_MSB 15 +#define SOC_POWER_REG_DEEP_SLEEP_EN_LSB 15 +#define SOC_POWER_REG_DEEP_SLEEP_EN_MASK 0x00008000 +#define SOC_POWER_REG_DEEP_SLEEP_EN_GET(x) (((x) & SOC_POWER_REG_DEEP_SLEEP_EN_MASK) >> SOC_POWER_REG_DEEP_SLEEP_EN_LSB) +#define SOC_POWER_REG_DEEP_SLEEP_EN_SET(x) (((x) << SOC_POWER_REG_DEEP_SLEEP_EN_LSB) & SOC_POWER_REG_DEEP_SLEEP_EN_MASK) +#define SOC_POWER_REG_DEBUG_EN_MSB 14 +#define SOC_POWER_REG_DEBUG_EN_LSB 14 +#define SOC_POWER_REG_DEBUG_EN_MASK 0x00004000 +#define SOC_POWER_REG_DEBUG_EN_GET(x) (((x) & SOC_POWER_REG_DEBUG_EN_MASK) >> SOC_POWER_REG_DEBUG_EN_LSB) +#define SOC_POWER_REG_DEBUG_EN_SET(x) (((x) << SOC_POWER_REG_DEBUG_EN_LSB) & SOC_POWER_REG_DEBUG_EN_MASK) +#define SOC_POWER_REG_WLAN_BB_PWD_EN_MSB 13 +#define SOC_POWER_REG_WLAN_BB_PWD_EN_LSB 13 +#define SOC_POWER_REG_WLAN_BB_PWD_EN_MASK 0x00002000 +#define SOC_POWER_REG_WLAN_BB_PWD_EN_GET(x) (((x) & SOC_POWER_REG_WLAN_BB_PWD_EN_MASK) >> SOC_POWER_REG_WLAN_BB_PWD_EN_LSB) +#define SOC_POWER_REG_WLAN_BB_PWD_EN_SET(x) (((x) << SOC_POWER_REG_WLAN_BB_PWD_EN_LSB) & SOC_POWER_REG_WLAN_BB_PWD_EN_MASK) +#define SOC_POWER_REG_WLAN_MAC_PWD_EN_MSB 12 +#define SOC_POWER_REG_WLAN_MAC_PWD_EN_LSB 12 +#define SOC_POWER_REG_WLAN_MAC_PWD_EN_MASK 0x00001000 +#define SOC_POWER_REG_WLAN_MAC_PWD_EN_GET(x) (((x) & SOC_POWER_REG_WLAN_MAC_PWD_EN_MASK) >> SOC_POWER_REG_WLAN_MAC_PWD_EN_LSB) +#define SOC_POWER_REG_WLAN_MAC_PWD_EN_SET(x) (((x) << SOC_POWER_REG_WLAN_MAC_PWD_EN_LSB) & SOC_POWER_REG_WLAN_MAC_PWD_EN_MASK) +#define SOC_POWER_REG_CPU_INT_ENABLE_MSB 7 +#define SOC_POWER_REG_CPU_INT_ENABLE_LSB 7 +#define SOC_POWER_REG_CPU_INT_ENABLE_MASK 0x00000080 +#define SOC_POWER_REG_CPU_INT_ENABLE_GET(x) (((x) & SOC_POWER_REG_CPU_INT_ENABLE_MASK) >> SOC_POWER_REG_CPU_INT_ENABLE_LSB) +#define SOC_POWER_REG_CPU_INT_ENABLE_SET(x) (((x) << SOC_POWER_REG_CPU_INT_ENABLE_LSB) & SOC_POWER_REG_CPU_INT_ENABLE_MASK) +#define SOC_POWER_REG_WLAN_ISO_DIS_MSB 6 +#define SOC_POWER_REG_WLAN_ISO_DIS_LSB 6 +#define SOC_POWER_REG_WLAN_ISO_DIS_MASK 0x00000040 +#define SOC_POWER_REG_WLAN_ISO_DIS_GET(x) (((x) & SOC_POWER_REG_WLAN_ISO_DIS_MASK) >> SOC_POWER_REG_WLAN_ISO_DIS_LSB) +#define SOC_POWER_REG_WLAN_ISO_DIS_SET(x) (((x) << SOC_POWER_REG_WLAN_ISO_DIS_LSB) & SOC_POWER_REG_WLAN_ISO_DIS_MASK) +#define SOC_POWER_REG_WLAN_ISO_CNTL_MSB 5 +#define SOC_POWER_REG_WLAN_ISO_CNTL_LSB 5 +#define SOC_POWER_REG_WLAN_ISO_CNTL_MASK 0x00000020 +#define SOC_POWER_REG_WLAN_ISO_CNTL_GET(x) (((x) & SOC_POWER_REG_WLAN_ISO_CNTL_MASK) >> SOC_POWER_REG_WLAN_ISO_CNTL_LSB) +#define SOC_POWER_REG_WLAN_ISO_CNTL_SET(x) (((x) << SOC_POWER_REG_WLAN_ISO_CNTL_LSB) & SOC_POWER_REG_WLAN_ISO_CNTL_MASK) +#define SOC_POWER_REG_RADIO_PWD_EN_MSB 4 +#define SOC_POWER_REG_RADIO_PWD_EN_LSB 4 +#define SOC_POWER_REG_RADIO_PWD_EN_MASK 0x00000010 +#define SOC_POWER_REG_RADIO_PWD_EN_GET(x) (((x) & SOC_POWER_REG_RADIO_PWD_EN_MASK) >> SOC_POWER_REG_RADIO_PWD_EN_LSB) +#define SOC_POWER_REG_RADIO_PWD_EN_SET(x) (((x) << SOC_POWER_REG_RADIO_PWD_EN_LSB) & SOC_POWER_REG_RADIO_PWD_EN_MASK) +#define SOC_POWER_REG_SOC_ISO_EN_MSB 3 +#define SOC_POWER_REG_SOC_ISO_EN_LSB 3 +#define SOC_POWER_REG_SOC_ISO_EN_MASK 0x00000008 +#define SOC_POWER_REG_SOC_ISO_EN_GET(x) (((x) & SOC_POWER_REG_SOC_ISO_EN_MASK) >> SOC_POWER_REG_SOC_ISO_EN_LSB) +#define SOC_POWER_REG_SOC_ISO_EN_SET(x) (((x) << SOC_POWER_REG_SOC_ISO_EN_LSB) & SOC_POWER_REG_SOC_ISO_EN_MASK) +#define SOC_POWER_REG_WLAN_ISO_EN_MSB 2 +#define SOC_POWER_REG_WLAN_ISO_EN_LSB 2 +#define SOC_POWER_REG_WLAN_ISO_EN_MASK 0x00000004 +#define SOC_POWER_REG_WLAN_ISO_EN_GET(x) (((x) & SOC_POWER_REG_WLAN_ISO_EN_MASK) >> SOC_POWER_REG_WLAN_ISO_EN_LSB) +#define SOC_POWER_REG_WLAN_ISO_EN_SET(x) (((x) << SOC_POWER_REG_WLAN_ISO_EN_LSB) & SOC_POWER_REG_WLAN_ISO_EN_MASK) +#define SOC_POWER_REG_WLAN_PWD_EN_MSB 1 +#define SOC_POWER_REG_WLAN_PWD_EN_LSB 1 +#define SOC_POWER_REG_WLAN_PWD_EN_MASK 0x00000002 +#define SOC_POWER_REG_WLAN_PWD_EN_GET(x) (((x) & SOC_POWER_REG_WLAN_PWD_EN_MASK) >> SOC_POWER_REG_WLAN_PWD_EN_LSB) +#define SOC_POWER_REG_WLAN_PWD_EN_SET(x) (((x) << SOC_POWER_REG_WLAN_PWD_EN_LSB) & SOC_POWER_REG_WLAN_PWD_EN_MASK) +#define SOC_POWER_REG_POWER_EN_MSB 0 +#define SOC_POWER_REG_POWER_EN_LSB 0 +#define SOC_POWER_REG_POWER_EN_MASK 0x00000001 +#define SOC_POWER_REG_POWER_EN_GET(x) (((x) & SOC_POWER_REG_POWER_EN_MASK) >> SOC_POWER_REG_POWER_EN_LSB) +#define SOC_POWER_REG_POWER_EN_SET(x) (((x) << SOC_POWER_REG_POWER_EN_LSB) & SOC_POWER_REG_POWER_EN_MASK) + +#define SOC_CORE_CLK_CTRL_ADDRESS 0x00000110 +#define SOC_CORE_CLK_CTRL_OFFSET 0x00000110 +#define SOC_CORE_CLK_CTRL_DIV_MSB 2 +#define SOC_CORE_CLK_CTRL_DIV_LSB 0 +#define SOC_CORE_CLK_CTRL_DIV_MASK 0x00000007 +#define SOC_CORE_CLK_CTRL_DIV_GET(x) (((x) & SOC_CORE_CLK_CTRL_DIV_MASK) >> SOC_CORE_CLK_CTRL_DIV_LSB) +#define SOC_CORE_CLK_CTRL_DIV_SET(x) (((x) << SOC_CORE_CLK_CTRL_DIV_LSB) & SOC_CORE_CLK_CTRL_DIV_MASK) + +#define SOC_GPIO_WAKEUP_CONTROL_ADDRESS 0x00000114 +#define SOC_GPIO_WAKEUP_CONTROL_OFFSET 0x00000114 +#define SOC_GPIO_WAKEUP_CONTROL_ENABLE_MSB 0 +#define SOC_GPIO_WAKEUP_CONTROL_ENABLE_LSB 0 +#define SOC_GPIO_WAKEUP_CONTROL_ENABLE_MASK 0x00000001 +#define SOC_GPIO_WAKEUP_CONTROL_ENABLE_GET(x) (((x) & SOC_GPIO_WAKEUP_CONTROL_ENABLE_MASK) >> SOC_GPIO_WAKEUP_CONTROL_ENABLE_LSB) +#define SOC_GPIO_WAKEUP_CONTROL_ENABLE_SET(x) (((x) << SOC_GPIO_WAKEUP_CONTROL_ENABLE_LSB) & SOC_GPIO_WAKEUP_CONTROL_ENABLE_MASK) + +#define SLEEP_RETENTION_ADDRESS 0x00000214 +#define SLEEP_RETENTION_OFFSET 0x00000214 +#define SLEEP_RETENTION_GREEN_SAVE_MSB 10 +#define SLEEP_RETENTION_GREEN_SAVE_LSB 10 +#define SLEEP_RETENTION_GREEN_SAVE_MASK 0x00000400 +#define SLEEP_RETENTION_GREEN_SAVE_GET(x) (((x) & SLEEP_RETENTION_GREEN_SAVE_MASK) >> SLEEP_RETENTION_GREEN_SAVE_LSB) +#define SLEEP_RETENTION_GREEN_SAVE_SET(x) (((x) << SLEEP_RETENTION_GREEN_SAVE_LSB) & SLEEP_RETENTION_GREEN_SAVE_MASK) +#define SLEEP_RETENTION_TIME_MSB 9 +#define SLEEP_RETENTION_TIME_LSB 2 +#define SLEEP_RETENTION_TIME_MASK 0x000003fc +#define SLEEP_RETENTION_TIME_GET(x) (((x) & SLEEP_RETENTION_TIME_MASK) >> SLEEP_RETENTION_TIME_LSB) +#define SLEEP_RETENTION_TIME_SET(x) (((x) << SLEEP_RETENTION_TIME_LSB) & SLEEP_RETENTION_TIME_MASK) +#define SLEEP_RETENTION_MODE_MSB 1 +#define SLEEP_RETENTION_MODE_LSB 1 +#define SLEEP_RETENTION_MODE_MASK 0x00000002 +#define SLEEP_RETENTION_MODE_GET(x) (((x) & SLEEP_RETENTION_MODE_MASK) >> SLEEP_RETENTION_MODE_LSB) +#define SLEEP_RETENTION_MODE_SET(x) (((x) << SLEEP_RETENTION_MODE_LSB) & SLEEP_RETENTION_MODE_MASK) +#define SLEEP_RETENTION_ENABLE_MSB 0 +#define SLEEP_RETENTION_ENABLE_LSB 0 +#define SLEEP_RETENTION_ENABLE_MASK 0x00000001 +#define SLEEP_RETENTION_ENABLE_GET(x) (((x) & SLEEP_RETENTION_ENABLE_MASK) >> SLEEP_RETENTION_ENABLE_LSB) +#define SLEEP_RETENTION_ENABLE_SET(x) (((x) << SLEEP_RETENTION_ENABLE_LSB) & SLEEP_RETENTION_ENABLE_MASK) + +#define LP_PERF_COUNTER_ADDRESS 0x00000284 +#define LP_PERF_COUNTER_OFFSET 0x00000284 +#define LP_PERF_COUNTER_EN_MSB 0 +#define LP_PERF_COUNTER_EN_LSB 0 +#define LP_PERF_COUNTER_EN_MASK 0x00000001 +#define LP_PERF_COUNTER_EN_GET(x) (((x) & LP_PERF_COUNTER_EN_MASK) >> LP_PERF_COUNTER_EN_LSB) +#define LP_PERF_COUNTER_EN_SET(x) (((x) << LP_PERF_COUNTER_EN_LSB) & LP_PERF_COUNTER_EN_MASK) + +#define LP_PERF_LIGHT_SLEEP_ADDRESS 0x00000288 +#define LP_PERF_LIGHT_SLEEP_OFFSET 0x00000288 +#define LP_PERF_LIGHT_SLEEP_CNT_MSB 31 +#define LP_PERF_LIGHT_SLEEP_CNT_LSB 0 +#define LP_PERF_LIGHT_SLEEP_CNT_MASK 0xffffffff +#define LP_PERF_LIGHT_SLEEP_CNT_GET(x) (((x) & LP_PERF_LIGHT_SLEEP_CNT_MASK) >> LP_PERF_LIGHT_SLEEP_CNT_LSB) +#define LP_PERF_LIGHT_SLEEP_CNT_SET(x) (((x) << LP_PERF_LIGHT_SLEEP_CNT_LSB) & LP_PERF_LIGHT_SLEEP_CNT_MASK) + +#define LP_PERF_DEEP_SLEEP_ADDRESS 0x0000028c +#define LP_PERF_DEEP_SLEEP_OFFSET 0x0000028c +#define LP_PERF_DEEP_SLEEP_CNT_MSB 31 +#define LP_PERF_DEEP_SLEEP_CNT_LSB 0 +#define LP_PERF_DEEP_SLEEP_CNT_MASK 0xffffffff +#define LP_PERF_DEEP_SLEEP_CNT_GET(x) (((x) & LP_PERF_DEEP_SLEEP_CNT_MASK) >> LP_PERF_DEEP_SLEEP_CNT_LSB) +#define LP_PERF_DEEP_SLEEP_CNT_SET(x) (((x) << LP_PERF_DEEP_SLEEP_CNT_LSB) & LP_PERF_DEEP_SLEEP_CNT_MASK) + +#define LP_PERF_ON_ADDRESS 0x00000290 +#define LP_PERF_ON_OFFSET 0x00000290 +#define LP_PERF_ON_CNT_MSB 31 +#define LP_PERF_ON_CNT_LSB 0 +#define LP_PERF_ON_CNT_MASK 0xffffffff +#define LP_PERF_ON_CNT_GET(x) (((x) & LP_PERF_ON_CNT_MASK) >> LP_PERF_ON_CNT_LSB) +#define LP_PERF_ON_CNT_SET(x) (((x) << LP_PERF_ON_CNT_LSB) & LP_PERF_ON_CNT_MASK) + +#define CHIP_MODE_ADDRESS 0x000002a8 +#define CHIP_MODE_OFFSET 0x000002a8 +#define CHIP_MODE_BIT_MSB 1 +#define CHIP_MODE_BIT_LSB 0 +#define CHIP_MODE_BIT_MASK 0x00000003 +#define CHIP_MODE_BIT_GET(x) (((x) & CHIP_MODE_BIT_MASK) >> CHIP_MODE_BIT_LSB) +#define CHIP_MODE_BIT_SET(x) (((x) << CHIP_MODE_BIT_LSB) & CHIP_MODE_BIT_MASK) + +#define CLK_REQ_FALL_EDGE_ADDRESS 0x000002ac +#define CLK_REQ_FALL_EDGE_OFFSET 0x000002ac +#define CLK_REQ_FALL_EDGE_EN_MSB 31 +#define CLK_REQ_FALL_EDGE_EN_LSB 31 +#define CLK_REQ_FALL_EDGE_EN_MASK 0x80000000 +#define CLK_REQ_FALL_EDGE_EN_GET(x) (((x) & CLK_REQ_FALL_EDGE_EN_MASK) >> CLK_REQ_FALL_EDGE_EN_LSB) +#define CLK_REQ_FALL_EDGE_EN_SET(x) (((x) << CLK_REQ_FALL_EDGE_EN_LSB) & CLK_REQ_FALL_EDGE_EN_MASK) +#define CLK_REQ_FALL_EDGE_DELAY_MSB 7 +#define CLK_REQ_FALL_EDGE_DELAY_LSB 0 +#define CLK_REQ_FALL_EDGE_DELAY_MASK 0x000000ff +#define CLK_REQ_FALL_EDGE_DELAY_GET(x) (((x) & CLK_REQ_FALL_EDGE_DELAY_MASK) >> CLK_REQ_FALL_EDGE_DELAY_LSB) +#define CLK_REQ_FALL_EDGE_DELAY_SET(x) (((x) << CLK_REQ_FALL_EDGE_DELAY_LSB) & CLK_REQ_FALL_EDGE_DELAY_MASK) + +#define OTP_ADDRESS 0x000002b0 +#define OTP_OFFSET 0x000002b0 +#define OTP_LDO25_EN_MSB 1 +#define OTP_LDO25_EN_LSB 1 +#define OTP_LDO25_EN_MASK 0x00000002 +#define OTP_LDO25_EN_GET(x) (((x) & OTP_LDO25_EN_MASK) >> OTP_LDO25_EN_LSB) +#define OTP_LDO25_EN_SET(x) (((x) << OTP_LDO25_EN_LSB) & OTP_LDO25_EN_MASK) +#define OTP_VDD12_EN_MSB 0 +#define OTP_VDD12_EN_LSB 0 +#define OTP_VDD12_EN_MASK 0x00000001 +#define OTP_VDD12_EN_GET(x) (((x) & OTP_VDD12_EN_MASK) >> OTP_VDD12_EN_LSB) +#define OTP_VDD12_EN_SET(x) (((x) << OTP_VDD12_EN_LSB) & OTP_VDD12_EN_MASK) + +#define OTP_STATUS_ADDRESS 0x000002b4 +#define OTP_STATUS_OFFSET 0x000002b4 +#define OTP_STATUS_LDO25_EN_READY_MSB 1 +#define OTP_STATUS_LDO25_EN_READY_LSB 1 +#define OTP_STATUS_LDO25_EN_READY_MASK 0x00000002 +#define OTP_STATUS_LDO25_EN_READY_GET(x) (((x) & OTP_STATUS_LDO25_EN_READY_MASK) >> OTP_STATUS_LDO25_EN_READY_LSB) +#define OTP_STATUS_LDO25_EN_READY_SET(x) (((x) << OTP_STATUS_LDO25_EN_READY_LSB) & OTP_STATUS_LDO25_EN_READY_MASK) +#define OTP_STATUS_VDD12_EN_READY_MSB 0 +#define OTP_STATUS_VDD12_EN_READY_LSB 0 +#define OTP_STATUS_VDD12_EN_READY_MASK 0x00000001 +#define OTP_STATUS_VDD12_EN_READY_GET(x) (((x) & OTP_STATUS_VDD12_EN_READY_MASK) >> OTP_STATUS_VDD12_EN_READY_LSB) +#define OTP_STATUS_VDD12_EN_READY_SET(x) (((x) << OTP_STATUS_VDD12_EN_READY_LSB) & OTP_STATUS_VDD12_EN_READY_MASK) + +#define PMU_ADDRESS 0x000002b8 +#define PMU_OFFSET 0x000002b8 +#define PMU_REG_WAKEUP_TIME_SEL_MSB 1 +#define PMU_REG_WAKEUP_TIME_SEL_LSB 0 +#define PMU_REG_WAKEUP_TIME_SEL_MASK 0x00000003 +#define PMU_REG_WAKEUP_TIME_SEL_GET(x) (((x) & PMU_REG_WAKEUP_TIME_SEL_MASK) >> PMU_REG_WAKEUP_TIME_SEL_LSB) +#define PMU_REG_WAKEUP_TIME_SEL_SET(x) (((x) << PMU_REG_WAKEUP_TIME_SEL_LSB) & PMU_REG_WAKEUP_TIME_SEL_MASK) + +#define PMU_CONFIG_ADDRESS 0x000002bc +#define PMU_CONFIG_OFFSET 0x000002bc +#define PMU_CONFIG_VALUE_MSB 4 +#define PMU_CONFIG_VALUE_LSB 0 +#define PMU_CONFIG_VALUE_MASK 0x0000001f +#define PMU_CONFIG_VALUE_GET(x) (((x) & PMU_CONFIG_VALUE_MASK) >> PMU_CONFIG_VALUE_LSB) +#define PMU_CONFIG_VALUE_SET(x) (((x) << PMU_CONFIG_VALUE_LSB) & PMU_CONFIG_VALUE_MASK) + +#define PMU_PAREG_ADDRESS 0x000002c0 +#define PMU_PAREG_OFFSET 0x000002c0 +#define PMU_PAREG_LVL_CTR_MSB 2 +#define PMU_PAREG_LVL_CTR_LSB 0 +#define PMU_PAREG_LVL_CTR_MASK 0x00000007 +#define PMU_PAREG_LVL_CTR_GET(x) (((x) & PMU_PAREG_LVL_CTR_MASK) >> PMU_PAREG_LVL_CTR_LSB) +#define PMU_PAREG_LVL_CTR_SET(x) (((x) << PMU_PAREG_LVL_CTR_LSB) & PMU_PAREG_LVL_CTR_MASK) + +#define PMU_BYPASS_ADDRESS 0x000002c4 +#define PMU_BYPASS_OFFSET 0x000002c4 +#define PMU_BYPASS_SWREG_MSB 2 +#define PMU_BYPASS_SWREG_LSB 2 +#define PMU_BYPASS_SWREG_MASK 0x00000004 +#define PMU_BYPASS_SWREG_GET(x) (((x) & PMU_BYPASS_SWREG_MASK) >> PMU_BYPASS_SWREG_LSB) +#define PMU_BYPASS_SWREG_SET(x) (((x) << PMU_BYPASS_SWREG_LSB) & PMU_BYPASS_SWREG_MASK) +#define PMU_BYPASS_DREG_MSB 1 +#define PMU_BYPASS_DREG_LSB 1 +#define PMU_BYPASS_DREG_MASK 0x00000002 +#define PMU_BYPASS_DREG_GET(x) (((x) & PMU_BYPASS_DREG_MASK) >> PMU_BYPASS_DREG_LSB) +#define PMU_BYPASS_DREG_SET(x) (((x) << PMU_BYPASS_DREG_LSB) & PMU_BYPASS_DREG_MASK) +#define PMU_BYPASS_PAREG_MSB 0 +#define PMU_BYPASS_PAREG_LSB 0 +#define PMU_BYPASS_PAREG_MASK 0x00000001 +#define PMU_BYPASS_PAREG_GET(x) (((x) & PMU_BYPASS_PAREG_MASK) >> PMU_BYPASS_PAREG_LSB) +#define PMU_BYPASS_PAREG_SET(x) (((x) << PMU_BYPASS_PAREG_LSB) & PMU_BYPASS_PAREG_MASK) + +#define THERM_CTRL1_ADDRESS 0x000002dc +#define THERM_CTRL1_OFFSET 0x000002dc +#define THERM_CTRL1_BYPASS_MSB 16 +#define THERM_CTRL1_BYPASS_LSB 16 +#define THERM_CTRL1_BYPASS_MASK 0x00010000 +#define THERM_CTRL1_BYPASS_GET(x) (((x) & THERM_CTRL1_BYPASS_MASK) >> THERM_CTRL1_BYPASS_LSB) +#define THERM_CTRL1_BYPASS_SET(x) (((x) << THERM_CTRL1_BYPASS_LSB) & THERM_CTRL1_BYPASS_MASK) +#define THERM_CTRL1_WIDTH_ARBITOR_MSB 15 +#define THERM_CTRL1_WIDTH_ARBITOR_LSB 12 +#define THERM_CTRL1_WIDTH_ARBITOR_MASK 0x0000f000 +#define THERM_CTRL1_WIDTH_ARBITOR_GET(x) (((x) & THERM_CTRL1_WIDTH_ARBITOR_MASK) >> THERM_CTRL1_WIDTH_ARBITOR_LSB) +#define THERM_CTRL1_WIDTH_ARBITOR_SET(x) (((x) << THERM_CTRL1_WIDTH_ARBITOR_LSB) & THERM_CTRL1_WIDTH_ARBITOR_MASK) +#define THERM_CTRL1_WIDTH_MSB 11 +#define THERM_CTRL1_WIDTH_LSB 5 +#define THERM_CTRL1_WIDTH_MASK 0x00000fe0 +#define THERM_CTRL1_WIDTH_GET(x) (((x) & THERM_CTRL1_WIDTH_MASK) >> THERM_CTRL1_WIDTH_LSB) +#define THERM_CTRL1_WIDTH_SET(x) (((x) << THERM_CTRL1_WIDTH_LSB) & THERM_CTRL1_WIDTH_MASK) +#define THERM_CTRL1_TYPE_MSB 4 +#define THERM_CTRL1_TYPE_LSB 3 +#define THERM_CTRL1_TYPE_MASK 0x00000018 +#define THERM_CTRL1_TYPE_GET(x) (((x) & THERM_CTRL1_TYPE_MASK) >> THERM_CTRL1_TYPE_LSB) +#define THERM_CTRL1_TYPE_SET(x) (((x) << THERM_CTRL1_TYPE_LSB) & THERM_CTRL1_TYPE_MASK) +#define THERM_CTRL1_MEASURE_MSB 2 +#define THERM_CTRL1_MEASURE_LSB 2 +#define THERM_CTRL1_MEASURE_MASK 0x00000004 +#define THERM_CTRL1_MEASURE_GET(x) (((x) & THERM_CTRL1_MEASURE_MASK) >> THERM_CTRL1_MEASURE_LSB) +#define THERM_CTRL1_MEASURE_SET(x) (((x) << THERM_CTRL1_MEASURE_LSB) & THERM_CTRL1_MEASURE_MASK) +#define THERM_CTRL1_INT_EN_MSB 1 +#define THERM_CTRL1_INT_EN_LSB 1 +#define THERM_CTRL1_INT_EN_MASK 0x00000002 +#define THERM_CTRL1_INT_EN_GET(x) (((x) & THERM_CTRL1_INT_EN_MASK) >> THERM_CTRL1_INT_EN_LSB) +#define THERM_CTRL1_INT_EN_SET(x) (((x) << THERM_CTRL1_INT_EN_LSB) & THERM_CTRL1_INT_EN_MASK) +#define THERM_CTRL1_INT_STATUS_MSB 0 +#define THERM_CTRL1_INT_STATUS_LSB 0 +#define THERM_CTRL1_INT_STATUS_MASK 0x00000001 +#define THERM_CTRL1_INT_STATUS_GET(x) (((x) & THERM_CTRL1_INT_STATUS_MASK) >> THERM_CTRL1_INT_STATUS_LSB) +#define THERM_CTRL1_INT_STATUS_SET(x) (((x) << THERM_CTRL1_INT_STATUS_LSB) & THERM_CTRL1_INT_STATUS_MASK) + +#define THERM_CTRL2_ADDRESS 0x000002e0 +#define THERM_CTRL2_OFFSET 0x000002e0 +#define THERM_CTRL2_ADC_OFF_MSB 25 +#define THERM_CTRL2_ADC_OFF_LSB 25 +#define THERM_CTRL2_ADC_OFF_MASK 0x02000000 +#define THERM_CTRL2_ADC_OFF_GET(x) (((x) & THERM_CTRL2_ADC_OFF_MASK) >> THERM_CTRL2_ADC_OFF_LSB) +#define THERM_CTRL2_ADC_OFF_SET(x) (((x) << THERM_CTRL2_ADC_OFF_LSB) & THERM_CTRL2_ADC_OFF_MASK) +#define THERM_CTRL2_ADC_ON_MSB 24 +#define THERM_CTRL2_ADC_ON_LSB 24 +#define THERM_CTRL2_ADC_ON_MASK 0x01000000 +#define THERM_CTRL2_ADC_ON_GET(x) (((x) & THERM_CTRL2_ADC_ON_MASK) >> THERM_CTRL2_ADC_ON_LSB) +#define THERM_CTRL2_ADC_ON_SET(x) (((x) << THERM_CTRL2_ADC_ON_LSB) & THERM_CTRL2_ADC_ON_MASK) +#define THERM_CTRL2_SAMPLE_MSB 23 +#define THERM_CTRL2_SAMPLE_LSB 16 +#define THERM_CTRL2_SAMPLE_MASK 0x00ff0000 +#define THERM_CTRL2_SAMPLE_GET(x) (((x) & THERM_CTRL2_SAMPLE_MASK) >> THERM_CTRL2_SAMPLE_LSB) +#define THERM_CTRL2_SAMPLE_SET(x) (((x) << THERM_CTRL2_SAMPLE_LSB) & THERM_CTRL2_SAMPLE_MASK) +#define THERM_CTRL2_HIGH_MSB 15 +#define THERM_CTRL2_HIGH_LSB 8 +#define THERM_CTRL2_HIGH_MASK 0x0000ff00 +#define THERM_CTRL2_HIGH_GET(x) (((x) & THERM_CTRL2_HIGH_MASK) >> THERM_CTRL2_HIGH_LSB) +#define THERM_CTRL2_HIGH_SET(x) (((x) << THERM_CTRL2_HIGH_LSB) & THERM_CTRL2_HIGH_MASK) +#define THERM_CTRL2_LOW_MSB 7 +#define THERM_CTRL2_LOW_LSB 0 +#define THERM_CTRL2_LOW_MASK 0x000000ff +#define THERM_CTRL2_LOW_GET(x) (((x) & THERM_CTRL2_LOW_MASK) >> THERM_CTRL2_LOW_LSB) +#define THERM_CTRL2_LOW_SET(x) (((x) << THERM_CTRL2_LOW_LSB) & THERM_CTRL2_LOW_MASK) + +#define THERM_CTRL3_ADDRESS 0x000002e4 +#define THERM_CTRL3_OFFSET 0x000002e4 +#define THERM_CTRL3_ADC_GAIN_MSB 16 +#define THERM_CTRL3_ADC_GAIN_LSB 8 +#define THERM_CTRL3_ADC_GAIN_MASK 0x0001ff00 +#define THERM_CTRL3_ADC_GAIN_GET(x) (((x) & THERM_CTRL3_ADC_GAIN_MASK) >> THERM_CTRL3_ADC_GAIN_LSB) +#define THERM_CTRL3_ADC_GAIN_SET(x) (((x) << THERM_CTRL3_ADC_GAIN_LSB) & THERM_CTRL3_ADC_GAIN_MASK) +#define THERM_CTRL3_ADC_OFFSET_MSB 7 +#define THERM_CTRL3_ADC_OFFSET_LSB 0 +#define THERM_CTRL3_ADC_OFFSET_MASK 0x000000ff +#define THERM_CTRL3_ADC_OFFSET_GET(x) (((x) & THERM_CTRL3_ADC_OFFSET_MASK) >> THERM_CTRL3_ADC_OFFSET_LSB) +#define THERM_CTRL3_ADC_OFFSET_SET(x) (((x) << THERM_CTRL3_ADC_OFFSET_LSB) & THERM_CTRL3_ADC_OFFSET_MASK) + +#define LISTEN_MODE1_ADDRESS 0x000002e8 +#define LISTEN_MODE1_OFFSET 0x000002e8 +#define LISTEN_MODE1_TIMER_CLEAR_MSB 19 +#define LISTEN_MODE1_TIMER_CLEAR_LSB 19 +#define LISTEN_MODE1_TIMER_CLEAR_MASK 0x00080000 +#define LISTEN_MODE1_TIMER_CLEAR_GET(x) (((x) & LISTEN_MODE1_TIMER_CLEAR_MASK) >> LISTEN_MODE1_TIMER_CLEAR_LSB) +#define LISTEN_MODE1_TIMER_CLEAR_SET(x) (((x) << LISTEN_MODE1_TIMER_CLEAR_LSB) & LISTEN_MODE1_TIMER_CLEAR_MASK) +#define LISTEN_MODE1_TIMER_THRESH_WAKE_MSB 18 +#define LISTEN_MODE1_TIMER_THRESH_WAKE_LSB 3 +#define LISTEN_MODE1_TIMER_THRESH_WAKE_MASK 0x0007fff8 +#define LISTEN_MODE1_TIMER_THRESH_WAKE_GET(x) (((x) & LISTEN_MODE1_TIMER_THRESH_WAKE_MASK) >> LISTEN_MODE1_TIMER_THRESH_WAKE_LSB) +#define LISTEN_MODE1_TIMER_THRESH_WAKE_SET(x) (((x) << LISTEN_MODE1_TIMER_THRESH_WAKE_LSB) & LISTEN_MODE1_TIMER_THRESH_WAKE_MASK) +#define LISTEN_MODE1_TIMER_OVERFLOW_WAKE_MSB 2 +#define LISTEN_MODE1_TIMER_OVERFLOW_WAKE_LSB 2 +#define LISTEN_MODE1_TIMER_OVERFLOW_WAKE_MASK 0x00000004 +#define LISTEN_MODE1_TIMER_OVERFLOW_WAKE_GET(x) (((x) & LISTEN_MODE1_TIMER_OVERFLOW_WAKE_MASK) >> LISTEN_MODE1_TIMER_OVERFLOW_WAKE_LSB) +#define LISTEN_MODE1_TIMER_OVERFLOW_WAKE_SET(x) (((x) << LISTEN_MODE1_TIMER_OVERFLOW_WAKE_LSB) & LISTEN_MODE1_TIMER_OVERFLOW_WAKE_MASK) +#define LISTEN_MODE1_CLOCK_GATE_MSB 1 +#define LISTEN_MODE1_CLOCK_GATE_LSB 1 +#define LISTEN_MODE1_CLOCK_GATE_MASK 0x00000002 +#define LISTEN_MODE1_CLOCK_GATE_GET(x) (((x) & LISTEN_MODE1_CLOCK_GATE_MASK) >> LISTEN_MODE1_CLOCK_GATE_LSB) +#define LISTEN_MODE1_CLOCK_GATE_SET(x) (((x) << LISTEN_MODE1_CLOCK_GATE_LSB) & LISTEN_MODE1_CLOCK_GATE_MASK) +#define LISTEN_MODE1_ENABLE_MSB 0 +#define LISTEN_MODE1_ENABLE_LSB 0 +#define LISTEN_MODE1_ENABLE_MASK 0x00000001 +#define LISTEN_MODE1_ENABLE_GET(x) (((x) & LISTEN_MODE1_ENABLE_MASK) >> LISTEN_MODE1_ENABLE_LSB) +#define LISTEN_MODE1_ENABLE_SET(x) (((x) << LISTEN_MODE1_ENABLE_LSB) & LISTEN_MODE1_ENABLE_MASK) + +#define LISTEN_MODE2_ADDRESS 0x000002ec +#define LISTEN_MODE2_OFFSET 0x000002ec +#define LISTEN_MODE2_TIMER_TRIGGER_WAKE_MSB 15 +#define LISTEN_MODE2_TIMER_TRIGGER_WAKE_LSB 0 +#define LISTEN_MODE2_TIMER_TRIGGER_WAKE_MASK 0x0000ffff +#define LISTEN_MODE2_TIMER_TRIGGER_WAKE_GET(x) (((x) & LISTEN_MODE2_TIMER_TRIGGER_WAKE_MASK) >> LISTEN_MODE2_TIMER_TRIGGER_WAKE_LSB) +#define LISTEN_MODE2_TIMER_TRIGGER_WAKE_SET(x) (((x) << LISTEN_MODE2_TIMER_TRIGGER_WAKE_LSB) & LISTEN_MODE2_TIMER_TRIGGER_WAKE_MASK) + +#define AUDIO_PLL_CONFIG_ADDRESS 0x000002f0 +#define AUDIO_PLL_CONFIG_OFFSET 0x000002f0 +#define AUDIO_PLL_CONFIG_UPDATING_MSB 31 +#define AUDIO_PLL_CONFIG_UPDATING_LSB 31 +#define AUDIO_PLL_CONFIG_UPDATING_MASK 0x80000000 +#define AUDIO_PLL_CONFIG_UPDATING_GET(x) (((x) & AUDIO_PLL_CONFIG_UPDATING_MASK) >> AUDIO_PLL_CONFIG_UPDATING_LSB) +#define AUDIO_PLL_CONFIG_UPDATING_SET(x) (((x) << AUDIO_PLL_CONFIG_UPDATING_LSB) & AUDIO_PLL_CONFIG_UPDATING_MASK) +#define AUDIO_PLL_CONFIG_EXT_DIV_MSB 14 +#define AUDIO_PLL_CONFIG_EXT_DIV_LSB 12 +#define AUDIO_PLL_CONFIG_EXT_DIV_MASK 0x00007000 +#define AUDIO_PLL_CONFIG_EXT_DIV_GET(x) (((x) & AUDIO_PLL_CONFIG_EXT_DIV_MASK) >> AUDIO_PLL_CONFIG_EXT_DIV_LSB) +#define AUDIO_PLL_CONFIG_EXT_DIV_SET(x) (((x) << AUDIO_PLL_CONFIG_EXT_DIV_LSB) & AUDIO_PLL_CONFIG_EXT_DIV_MASK) +#define AUDIO_PLL_CONFIG_POSTPLLDIV_MSB 9 +#define AUDIO_PLL_CONFIG_POSTPLLDIV_LSB 7 +#define AUDIO_PLL_CONFIG_POSTPLLDIV_MASK 0x00000380 +#define AUDIO_PLL_CONFIG_POSTPLLDIV_GET(x) (((x) & AUDIO_PLL_CONFIG_POSTPLLDIV_MASK) >> AUDIO_PLL_CONFIG_POSTPLLDIV_LSB) +#define AUDIO_PLL_CONFIG_POSTPLLDIV_SET(x) (((x) << AUDIO_PLL_CONFIG_POSTPLLDIV_LSB) & AUDIO_PLL_CONFIG_POSTPLLDIV_MASK) +#define AUDIO_PLL_CONFIG_PLLPWD_MSB 5 +#define AUDIO_PLL_CONFIG_PLLPWD_LSB 5 +#define AUDIO_PLL_CONFIG_PLLPWD_MASK 0x00000020 +#define AUDIO_PLL_CONFIG_PLLPWD_GET(x) (((x) & AUDIO_PLL_CONFIG_PLLPWD_MASK) >> AUDIO_PLL_CONFIG_PLLPWD_LSB) +#define AUDIO_PLL_CONFIG_PLLPWD_SET(x) (((x) << AUDIO_PLL_CONFIG_PLLPWD_LSB) & AUDIO_PLL_CONFIG_PLLPWD_MASK) +#define AUDIO_PLL_CONFIG_BYPASS_MSB 4 +#define AUDIO_PLL_CONFIG_BYPASS_LSB 4 +#define AUDIO_PLL_CONFIG_BYPASS_MASK 0x00000010 +#define AUDIO_PLL_CONFIG_BYPASS_GET(x) (((x) & AUDIO_PLL_CONFIG_BYPASS_MASK) >> AUDIO_PLL_CONFIG_BYPASS_LSB) +#define AUDIO_PLL_CONFIG_BYPASS_SET(x) (((x) << AUDIO_PLL_CONFIG_BYPASS_LSB) & AUDIO_PLL_CONFIG_BYPASS_MASK) +#define AUDIO_PLL_CONFIG_REFDIV_MSB 3 +#define AUDIO_PLL_CONFIG_REFDIV_LSB 0 +#define AUDIO_PLL_CONFIG_REFDIV_MASK 0x0000000f +#define AUDIO_PLL_CONFIG_REFDIV_GET(x) (((x) & AUDIO_PLL_CONFIG_REFDIV_MASK) >> AUDIO_PLL_CONFIG_REFDIV_LSB) +#define AUDIO_PLL_CONFIG_REFDIV_SET(x) (((x) << AUDIO_PLL_CONFIG_REFDIV_LSB) & AUDIO_PLL_CONFIG_REFDIV_MASK) + +#define AUDIO_PLL_MODULATION_ADDRESS 0x000002f4 +#define AUDIO_PLL_MODULATION_OFFSET 0x000002f4 +#define AUDIO_PLL_MODULATION_TGT_DIV_FRAC_MSB 28 +#define AUDIO_PLL_MODULATION_TGT_DIV_FRAC_LSB 11 +#define AUDIO_PLL_MODULATION_TGT_DIV_FRAC_MASK 0x1ffff800 +#define AUDIO_PLL_MODULATION_TGT_DIV_FRAC_GET(x) (((x) & AUDIO_PLL_MODULATION_TGT_DIV_FRAC_MASK) >> AUDIO_PLL_MODULATION_TGT_DIV_FRAC_LSB) +#define AUDIO_PLL_MODULATION_TGT_DIV_FRAC_SET(x) (((x) << AUDIO_PLL_MODULATION_TGT_DIV_FRAC_LSB) & AUDIO_PLL_MODULATION_TGT_DIV_FRAC_MASK) +#define AUDIO_PLL_MODULATION_TGT_DIV_INT_MSB 6 +#define AUDIO_PLL_MODULATION_TGT_DIV_INT_LSB 1 +#define AUDIO_PLL_MODULATION_TGT_DIV_INT_MASK 0x0000007e +#define AUDIO_PLL_MODULATION_TGT_DIV_INT_GET(x) (((x) & AUDIO_PLL_MODULATION_TGT_DIV_INT_MASK) >> AUDIO_PLL_MODULATION_TGT_DIV_INT_LSB) +#define AUDIO_PLL_MODULATION_TGT_DIV_INT_SET(x) (((x) << AUDIO_PLL_MODULATION_TGT_DIV_INT_LSB) & AUDIO_PLL_MODULATION_TGT_DIV_INT_MASK) +#define AUDIO_PLL_MODULATION_START_MSB 0 +#define AUDIO_PLL_MODULATION_START_LSB 0 +#define AUDIO_PLL_MODULATION_START_MASK 0x00000001 +#define AUDIO_PLL_MODULATION_START_GET(x) (((x) & AUDIO_PLL_MODULATION_START_MASK) >> AUDIO_PLL_MODULATION_START_LSB) +#define AUDIO_PLL_MODULATION_START_SET(x) (((x) << AUDIO_PLL_MODULATION_START_LSB) & AUDIO_PLL_MODULATION_START_MASK) + +#define AUDIO_PLL_MOD_STEP_ADDRESS 0x000002f8 +#define AUDIO_PLL_MOD_STEP_OFFSET 0x000002f8 +#define AUDIO_PLL_MOD_STEP_FRAC_MSB 31 +#define AUDIO_PLL_MOD_STEP_FRAC_LSB 14 +#define AUDIO_PLL_MOD_STEP_FRAC_MASK 0xffffc000 +#define AUDIO_PLL_MOD_STEP_FRAC_GET(x) (((x) & AUDIO_PLL_MOD_STEP_FRAC_MASK) >> AUDIO_PLL_MOD_STEP_FRAC_LSB) +#define AUDIO_PLL_MOD_STEP_FRAC_SET(x) (((x) << AUDIO_PLL_MOD_STEP_FRAC_LSB) & AUDIO_PLL_MOD_STEP_FRAC_MASK) +#define AUDIO_PLL_MOD_STEP_INT_MSB 13 +#define AUDIO_PLL_MOD_STEP_INT_LSB 4 +#define AUDIO_PLL_MOD_STEP_INT_MASK 0x00003ff0 +#define AUDIO_PLL_MOD_STEP_INT_GET(x) (((x) & AUDIO_PLL_MOD_STEP_INT_MASK) >> AUDIO_PLL_MOD_STEP_INT_LSB) +#define AUDIO_PLL_MOD_STEP_INT_SET(x) (((x) << AUDIO_PLL_MOD_STEP_INT_LSB) & AUDIO_PLL_MOD_STEP_INT_MASK) +#define AUDIO_PLL_MOD_STEP_UPDATE_CNT_MSB 3 +#define AUDIO_PLL_MOD_STEP_UPDATE_CNT_LSB 0 +#define AUDIO_PLL_MOD_STEP_UPDATE_CNT_MASK 0x0000000f +#define AUDIO_PLL_MOD_STEP_UPDATE_CNT_GET(x) (((x) & AUDIO_PLL_MOD_STEP_UPDATE_CNT_MASK) >> AUDIO_PLL_MOD_STEP_UPDATE_CNT_LSB) +#define AUDIO_PLL_MOD_STEP_UPDATE_CNT_SET(x) (((x) << AUDIO_PLL_MOD_STEP_UPDATE_CNT_LSB) & AUDIO_PLL_MOD_STEP_UPDATE_CNT_MASK) + +#define CURRENT_AUDIO_PLL_MODULATION_ADDRESS 0x000002fc +#define CURRENT_AUDIO_PLL_MODULATION_OFFSET 0x000002fc +#define CURRENT_AUDIO_PLL_MODULATION_FRAC_MSB 27 +#define CURRENT_AUDIO_PLL_MODULATION_FRAC_LSB 10 +#define CURRENT_AUDIO_PLL_MODULATION_FRAC_MASK 0x0ffffc00 +#define CURRENT_AUDIO_PLL_MODULATION_FRAC_GET(x) (((x) & CURRENT_AUDIO_PLL_MODULATION_FRAC_MASK) >> CURRENT_AUDIO_PLL_MODULATION_FRAC_LSB) +#define CURRENT_AUDIO_PLL_MODULATION_FRAC_SET(x) (((x) << CURRENT_AUDIO_PLL_MODULATION_FRAC_LSB) & CURRENT_AUDIO_PLL_MODULATION_FRAC_MASK) +#define CURRENT_AUDIO_PLL_MODULATION_INT_MSB 6 +#define CURRENT_AUDIO_PLL_MODULATION_INT_LSB 1 +#define CURRENT_AUDIO_PLL_MODULATION_INT_MASK 0x0000007e +#define CURRENT_AUDIO_PLL_MODULATION_INT_GET(x) (((x) & CURRENT_AUDIO_PLL_MODULATION_INT_MASK) >> CURRENT_AUDIO_PLL_MODULATION_INT_LSB) +#define CURRENT_AUDIO_PLL_MODULATION_INT_SET(x) (((x) << CURRENT_AUDIO_PLL_MODULATION_INT_LSB) & CURRENT_AUDIO_PLL_MODULATION_INT_MASK) + +#define ETH_PLL_CONFIG_ADDRESS 0x00000300 +#define ETH_PLL_CONFIG_OFFSET 0x00000300 +#define ETH_PLL_CONFIG_GE0_MASTER_MSB 30 +#define ETH_PLL_CONFIG_GE0_MASTER_LSB 30 +#define ETH_PLL_CONFIG_GE0_MASTER_MASK 0x40000000 +#define ETH_PLL_CONFIG_GE0_MASTER_GET(x) (((x) & ETH_PLL_CONFIG_GE0_MASTER_MASK) >> ETH_PLL_CONFIG_GE0_MASTER_LSB) +#define ETH_PLL_CONFIG_GE0_MASTER_SET(x) (((x) << ETH_PLL_CONFIG_GE0_MASTER_LSB) & ETH_PLL_CONFIG_GE0_MASTER_MASK) +#define ETH_PLL_CONFIG_GE0_MSB 29 +#define ETH_PLL_CONFIG_GE0_LSB 29 +#define ETH_PLL_CONFIG_GE0_MASK 0x20000000 +#define ETH_PLL_CONFIG_GE0_GET(x) (((x) & ETH_PLL_CONFIG_GE0_MASK) >> ETH_PLL_CONFIG_GE0_LSB) +#define ETH_PLL_CONFIG_GE0_SET(x) (((x) << ETH_PLL_CONFIG_GE0_LSB) & ETH_PLL_CONFIG_GE0_MASK) +#define ETH_PLL_CONFIG_RANGE_MSB 28 +#define ETH_PLL_CONFIG_RANGE_LSB 28 +#define ETH_PLL_CONFIG_RANGE_MASK 0x10000000 +#define ETH_PLL_CONFIG_RANGE_GET(x) (((x) & ETH_PLL_CONFIG_RANGE_MASK) >> ETH_PLL_CONFIG_RANGE_LSB) +#define ETH_PLL_CONFIG_RANGE_SET(x) (((x) << ETH_PLL_CONFIG_RANGE_LSB) & ETH_PLL_CONFIG_RANGE_MASK) +#define ETH_PLL_CONFIG_FRAC_MSB 27 +#define ETH_PLL_CONFIG_FRAC_LSB 18 +#define ETH_PLL_CONFIG_FRAC_MASK 0x0ffc0000 +#define ETH_PLL_CONFIG_FRAC_GET(x) (((x) & ETH_PLL_CONFIG_FRAC_MASK) >> ETH_PLL_CONFIG_FRAC_LSB) +#define ETH_PLL_CONFIG_FRAC_SET(x) (((x) << ETH_PLL_CONFIG_FRAC_LSB) & ETH_PLL_CONFIG_FRAC_MASK) +#define ETH_PLL_CONFIG_INT_MSB 17 +#define ETH_PLL_CONFIG_INT_LSB 12 +#define ETH_PLL_CONFIG_INT_MASK 0x0003f000 +#define ETH_PLL_CONFIG_INT_GET(x) (((x) & ETH_PLL_CONFIG_INT_MASK) >> ETH_PLL_CONFIG_INT_LSB) +#define ETH_PLL_CONFIG_INT_SET(x) (((x) << ETH_PLL_CONFIG_INT_LSB) & ETH_PLL_CONFIG_INT_MASK) +#define ETH_PLL_CONFIG_OUTDIV_MSB 9 +#define ETH_PLL_CONFIG_OUTDIV_LSB 7 +#define ETH_PLL_CONFIG_OUTDIV_MASK 0x00000380 +#define ETH_PLL_CONFIG_OUTDIV_GET(x) (((x) & ETH_PLL_CONFIG_OUTDIV_MASK) >> ETH_PLL_CONFIG_OUTDIV_LSB) +#define ETH_PLL_CONFIG_OUTDIV_SET(x) (((x) << ETH_PLL_CONFIG_OUTDIV_LSB) & ETH_PLL_CONFIG_OUTDIV_MASK) +#define ETH_PLL_CONFIG_PLLPWD_MSB 6 +#define ETH_PLL_CONFIG_PLLPWD_LSB 6 +#define ETH_PLL_CONFIG_PLLPWD_MASK 0x00000040 +#define ETH_PLL_CONFIG_PLLPWD_GET(x) (((x) & ETH_PLL_CONFIG_PLLPWD_MASK) >> ETH_PLL_CONFIG_PLLPWD_LSB) +#define ETH_PLL_CONFIG_PLLPWD_SET(x) (((x) << ETH_PLL_CONFIG_PLLPWD_LSB) & ETH_PLL_CONFIG_PLLPWD_MASK) +#define ETH_PLL_CONFIG_BYPASS_MSB 5 +#define ETH_PLL_CONFIG_BYPASS_LSB 5 +#define ETH_PLL_CONFIG_BYPASS_MASK 0x00000020 +#define ETH_PLL_CONFIG_BYPASS_GET(x) (((x) & ETH_PLL_CONFIG_BYPASS_MASK) >> ETH_PLL_CONFIG_BYPASS_LSB) +#define ETH_PLL_CONFIG_BYPASS_SET(x) (((x) << ETH_PLL_CONFIG_BYPASS_LSB) & ETH_PLL_CONFIG_BYPASS_MASK) +#define ETH_PLL_CONFIG_REFDIV_MSB 4 +#define ETH_PLL_CONFIG_REFDIV_LSB 0 +#define ETH_PLL_CONFIG_REFDIV_MASK 0x0000001f +#define ETH_PLL_CONFIG_REFDIV_GET(x) (((x) & ETH_PLL_CONFIG_REFDIV_MASK) >> ETH_PLL_CONFIG_REFDIV_LSB) +#define ETH_PLL_CONFIG_REFDIV_SET(x) (((x) << ETH_PLL_CONFIG_REFDIV_LSB) & ETH_PLL_CONFIG_REFDIV_MASK) + +#define CPU_PLL_CONFIG_ADDRESS 0x00000304 +#define CPU_PLL_CONFIG_OFFSET 0x00000304 +#define CPU_PLL_CONFIG_RANGE_MSB 28 +#define CPU_PLL_CONFIG_RANGE_LSB 28 +#define CPU_PLL_CONFIG_RANGE_MASK 0x10000000 +#define CPU_PLL_CONFIG_RANGE_GET(x) (((x) & CPU_PLL_CONFIG_RANGE_MASK) >> CPU_PLL_CONFIG_RANGE_LSB) +#define CPU_PLL_CONFIG_RANGE_SET(x) (((x) << CPU_PLL_CONFIG_RANGE_LSB) & CPU_PLL_CONFIG_RANGE_MASK) +#define CPU_PLL_CONFIG_FRAC_MSB 25 +#define CPU_PLL_CONFIG_FRAC_LSB 20 +#define CPU_PLL_CONFIG_FRAC_MASK 0x03f00000 +#define CPU_PLL_CONFIG_FRAC_GET(x) (((x) & CPU_PLL_CONFIG_FRAC_MASK) >> CPU_PLL_CONFIG_FRAC_LSB) +#define CPU_PLL_CONFIG_FRAC_SET(x) (((x) << CPU_PLL_CONFIG_FRAC_LSB) & CPU_PLL_CONFIG_FRAC_MASK) +#define CPU_PLL_CONFIG_INT_MSB 17 +#define CPU_PLL_CONFIG_INT_LSB 12 +#define CPU_PLL_CONFIG_INT_MASK 0x0003f000 +#define CPU_PLL_CONFIG_INT_GET(x) (((x) & CPU_PLL_CONFIG_INT_MASK) >> CPU_PLL_CONFIG_INT_LSB) +#define CPU_PLL_CONFIG_INT_SET(x) (((x) << CPU_PLL_CONFIG_INT_LSB) & CPU_PLL_CONFIG_INT_MASK) +#define CPU_PLL_CONFIG_OUTDIV_MSB 9 +#define CPU_PLL_CONFIG_OUTDIV_LSB 7 +#define CPU_PLL_CONFIG_OUTDIV_MASK 0x00000380 +#define CPU_PLL_CONFIG_OUTDIV_GET(x) (((x) & CPU_PLL_CONFIG_OUTDIV_MASK) >> CPU_PLL_CONFIG_OUTDIV_LSB) +#define CPU_PLL_CONFIG_OUTDIV_SET(x) (((x) << CPU_PLL_CONFIG_OUTDIV_LSB) & CPU_PLL_CONFIG_OUTDIV_MASK) +#define CPU_PLL_CONFIG_PLLPWD_MSB 6 +#define CPU_PLL_CONFIG_PLLPWD_LSB 6 +#define CPU_PLL_CONFIG_PLLPWD_MASK 0x00000040 +#define CPU_PLL_CONFIG_PLLPWD_GET(x) (((x) & CPU_PLL_CONFIG_PLLPWD_MASK) >> CPU_PLL_CONFIG_PLLPWD_LSB) +#define CPU_PLL_CONFIG_PLLPWD_SET(x) (((x) << CPU_PLL_CONFIG_PLLPWD_LSB) & CPU_PLL_CONFIG_PLLPWD_MASK) +#define CPU_PLL_CONFIG_REFDIV_MSB 4 +#define CPU_PLL_CONFIG_REFDIV_LSB 0 +#define CPU_PLL_CONFIG_REFDIV_MASK 0x0000001f +#define CPU_PLL_CONFIG_REFDIV_GET(x) (((x) & CPU_PLL_CONFIG_REFDIV_MASK) >> CPU_PLL_CONFIG_REFDIV_LSB) +#define CPU_PLL_CONFIG_REFDIV_SET(x) (((x) << CPU_PLL_CONFIG_REFDIV_LSB) & CPU_PLL_CONFIG_REFDIV_MASK) + +#define BB_PLL_CONFIG_ADDRESS 0x00000308 +#define BB_PLL_CONFIG_OFFSET 0x00000308 +#define BB_PLL_CONFIG_FRAC_MSB 17 +#define BB_PLL_CONFIG_FRAC_LSB 0 +#define BB_PLL_CONFIG_FRAC_MASK 0x0003ffff +#define BB_PLL_CONFIG_FRAC_GET(x) (((x) & BB_PLL_CONFIG_FRAC_MASK) >> BB_PLL_CONFIG_FRAC_LSB) +#define BB_PLL_CONFIG_FRAC_SET(x) (((x) << BB_PLL_CONFIG_FRAC_LSB) & BB_PLL_CONFIG_FRAC_MASK) + +#define ETH_XMII_ADDRESS 0x0000030c +#define ETH_XMII_OFFSET 0x0000030c +#define ETH_XMII_TX_INVERT_MSB 31 +#define ETH_XMII_TX_INVERT_LSB 31 +#define ETH_XMII_TX_INVERT_MASK 0x80000000 +#define ETH_XMII_TX_INVERT_GET(x) (((x) & ETH_XMII_TX_INVERT_MASK) >> ETH_XMII_TX_INVERT_LSB) +#define ETH_XMII_TX_INVERT_SET(x) (((x) << ETH_XMII_TX_INVERT_LSB) & ETH_XMII_TX_INVERT_MASK) +#define ETH_XMII_GIGE_QUAD_MSB 30 +#define ETH_XMII_GIGE_QUAD_LSB 30 +#define ETH_XMII_GIGE_QUAD_MASK 0x40000000 +#define ETH_XMII_GIGE_QUAD_GET(x) (((x) & ETH_XMII_GIGE_QUAD_MASK) >> ETH_XMII_GIGE_QUAD_LSB) +#define ETH_XMII_GIGE_QUAD_SET(x) (((x) << ETH_XMII_GIGE_QUAD_LSB) & ETH_XMII_GIGE_QUAD_MASK) +#define ETH_XMII_RX_DELAY_MSB 29 +#define ETH_XMII_RX_DELAY_LSB 28 +#define ETH_XMII_RX_DELAY_MASK 0x30000000 +#define ETH_XMII_RX_DELAY_GET(x) (((x) & ETH_XMII_RX_DELAY_MASK) >> ETH_XMII_RX_DELAY_LSB) +#define ETH_XMII_RX_DELAY_SET(x) (((x) << ETH_XMII_RX_DELAY_LSB) & ETH_XMII_RX_DELAY_MASK) +#define ETH_XMII_TX_DELAY_MSB 27 +#define ETH_XMII_TX_DELAY_LSB 26 +#define ETH_XMII_TX_DELAY_MASK 0x0c000000 +#define ETH_XMII_TX_DELAY_GET(x) (((x) & ETH_XMII_TX_DELAY_MASK) >> ETH_XMII_TX_DELAY_LSB) +#define ETH_XMII_TX_DELAY_SET(x) (((x) << ETH_XMII_TX_DELAY_LSB) & ETH_XMII_TX_DELAY_MASK) +#define ETH_XMII_GIGE_MSB 25 +#define ETH_XMII_GIGE_LSB 25 +#define ETH_XMII_GIGE_MASK 0x02000000 +#define ETH_XMII_GIGE_GET(x) (((x) & ETH_XMII_GIGE_MASK) >> ETH_XMII_GIGE_LSB) +#define ETH_XMII_GIGE_SET(x) (((x) << ETH_XMII_GIGE_LSB) & ETH_XMII_GIGE_MASK) +#define ETH_XMII_OFFSET_PHASE_MSB 24 +#define ETH_XMII_OFFSET_PHASE_LSB 24 +#define ETH_XMII_OFFSET_PHASE_MASK 0x01000000 +#define ETH_XMII_OFFSET_PHASE_GET(x) (((x) & ETH_XMII_OFFSET_PHASE_MASK) >> ETH_XMII_OFFSET_PHASE_LSB) +#define ETH_XMII_OFFSET_PHASE_SET(x) (((x) << ETH_XMII_OFFSET_PHASE_LSB) & ETH_XMII_OFFSET_PHASE_MASK) +#define ETH_XMII_OFFSET_COUNT_MSB 23 +#define ETH_XMII_OFFSET_COUNT_LSB 16 +#define ETH_XMII_OFFSET_COUNT_MASK 0x00ff0000 +#define ETH_XMII_OFFSET_COUNT_GET(x) (((x) & ETH_XMII_OFFSET_COUNT_MASK) >> ETH_XMII_OFFSET_COUNT_LSB) +#define ETH_XMII_OFFSET_COUNT_SET(x) (((x) << ETH_XMII_OFFSET_COUNT_LSB) & ETH_XMII_OFFSET_COUNT_MASK) +#define ETH_XMII_PHASE1_COUNT_MSB 15 +#define ETH_XMII_PHASE1_COUNT_LSB 8 +#define ETH_XMII_PHASE1_COUNT_MASK 0x0000ff00 +#define ETH_XMII_PHASE1_COUNT_GET(x) (((x) & ETH_XMII_PHASE1_COUNT_MASK) >> ETH_XMII_PHASE1_COUNT_LSB) +#define ETH_XMII_PHASE1_COUNT_SET(x) (((x) << ETH_XMII_PHASE1_COUNT_LSB) & ETH_XMII_PHASE1_COUNT_MASK) +#define ETH_XMII_PHASE0_COUNT_MSB 7 +#define ETH_XMII_PHASE0_COUNT_LSB 0 +#define ETH_XMII_PHASE0_COUNT_MASK 0x000000ff +#define ETH_XMII_PHASE0_COUNT_GET(x) (((x) & ETH_XMII_PHASE0_COUNT_MASK) >> ETH_XMII_PHASE0_COUNT_LSB) +#define ETH_XMII_PHASE0_COUNT_SET(x) (((x) << ETH_XMII_PHASE0_COUNT_LSB) & ETH_XMII_PHASE0_COUNT_MASK) + +#define USB_PHY_CONFIG_ADDRESS 0x00000310 +#define USB_PHY_CONFIG_OFFSET 0x00000310 +#define USB_PHY_CONFIG_REFCLK_SEL_MSB 7 +#define USB_PHY_CONFIG_REFCLK_SEL_LSB 4 +#define USB_PHY_CONFIG_REFCLK_SEL_MASK 0x000000f0 +#define USB_PHY_CONFIG_REFCLK_SEL_GET(x) (((x) & USB_PHY_CONFIG_REFCLK_SEL_MASK) >> USB_PHY_CONFIG_REFCLK_SEL_LSB) +#define USB_PHY_CONFIG_REFCLK_SEL_SET(x) (((x) << USB_PHY_CONFIG_REFCLK_SEL_LSB) & USB_PHY_CONFIG_REFCLK_SEL_MASK) +#define USB_PHY_CONFIG_REFDIV_MSB 3 +#define USB_PHY_CONFIG_REFDIV_LSB 3 +#define USB_PHY_CONFIG_REFDIV_MASK 0x00000008 +#define USB_PHY_CONFIG_REFDIV_GET(x) (((x) & USB_PHY_CONFIG_REFDIV_MASK) >> USB_PHY_CONFIG_REFDIV_LSB) +#define USB_PHY_CONFIG_REFDIV_SET(x) (((x) << USB_PHY_CONFIG_REFDIV_LSB) & USB_PHY_CONFIG_REFDIV_MASK) +#define USB_PHY_CONFIG_TESTMODE_MSB 2 +#define USB_PHY_CONFIG_TESTMODE_LSB 2 +#define USB_PHY_CONFIG_TESTMODE_MASK 0x00000004 +#define USB_PHY_CONFIG_TESTMODE_GET(x) (((x) & USB_PHY_CONFIG_TESTMODE_MASK) >> USB_PHY_CONFIG_TESTMODE_LSB) +#define USB_PHY_CONFIG_TESTMODE_SET(x) (((x) << USB_PHY_CONFIG_TESTMODE_LSB) & USB_PHY_CONFIG_TESTMODE_MASK) +#define USB_PHY_CONFIG_PLL_PWD_MSB 1 +#define USB_PHY_CONFIG_PLL_PWD_LSB 1 +#define USB_PHY_CONFIG_PLL_PWD_MASK 0x00000002 +#define USB_PHY_CONFIG_PLL_PWD_GET(x) (((x) & USB_PHY_CONFIG_PLL_PWD_MASK) >> USB_PHY_CONFIG_PLL_PWD_LSB) +#define USB_PHY_CONFIG_PLL_PWD_SET(x) (((x) << USB_PHY_CONFIG_PLL_PWD_LSB) & USB_PHY_CONFIG_PLL_PWD_MASK) +#define USB_PHY_CONFIG_HOSTMODE_MSB 0 +#define USB_PHY_CONFIG_HOSTMODE_LSB 0 +#define USB_PHY_CONFIG_HOSTMODE_MASK 0x00000001 +#define USB_PHY_CONFIG_HOSTMODE_GET(x) (((x) & USB_PHY_CONFIG_HOSTMODE_MASK) >> USB_PHY_CONFIG_HOSTMODE_LSB) +#define USB_PHY_CONFIG_HOSTMODE_SET(x) (((x) << USB_PHY_CONFIG_HOSTMODE_LSB) & USB_PHY_CONFIG_HOSTMODE_MASK) + +#define USBCORE_CLK60M_ADDRESS 0x00000314 +#define USBCORE_CLK60M_OFFSET 0x00000314 +#define USBCORE_CLK60M_SEL_MSB 0 +#define USBCORE_CLK60M_SEL_LSB 0 +#define USBCORE_CLK60M_SEL_MASK 0x00000001 +#define USBCORE_CLK60M_SEL_GET(x) (((x) & USBCORE_CLK60M_SEL_MASK) >> USBCORE_CLK60M_SEL_LSB) +#define USBCORE_CLK60M_SEL_SET(x) (((x) << USBCORE_CLK60M_SEL_LSB) & USBCORE_CLK60M_SEL_MASK) + +#define USBPHY_UTMI_CLK_ADDRESS 0x00000318 +#define USBPHY_UTMI_CLK_OFFSET 0x00000318 +#define USBPHY_UTMI_CLK_EN_MSB 0 +#define USBPHY_UTMI_CLK_EN_LSB 0 +#define USBPHY_UTMI_CLK_EN_MASK 0x00000001 +#define USBPHY_UTMI_CLK_EN_GET(x) (((x) & USBPHY_UTMI_CLK_EN_MASK) >> USBPHY_UTMI_CLK_EN_LSB) +#define USBPHY_UTMI_CLK_EN_SET(x) (((x) << USBPHY_UTMI_CLK_EN_LSB) & USBPHY_UTMI_CLK_EN_MASK) + +#define USB_TXVALID_DLY_CONFIG_ADDRESS 0x0000031c +#define USB_TXVALID_DLY_CONFIG_OFFSET 0x0000031c +#define USB_TXVALID_DLY_CONFIG_UTMI16_MSB 7 +#define USB_TXVALID_DLY_CONFIG_UTMI16_LSB 4 +#define USB_TXVALID_DLY_CONFIG_UTMI16_MASK 0x000000f0 +#define USB_TXVALID_DLY_CONFIG_UTMI16_GET(x) (((x) & USB_TXVALID_DLY_CONFIG_UTMI16_MASK) >> USB_TXVALID_DLY_CONFIG_UTMI16_LSB) +#define USB_TXVALID_DLY_CONFIG_UTMI16_SET(x) (((x) << USB_TXVALID_DLY_CONFIG_UTMI16_LSB) & USB_TXVALID_DLY_CONFIG_UTMI16_MASK) +#define USB_TXVALID_DLY_CONFIG_UTMI8_MSB 3 +#define USB_TXVALID_DLY_CONFIG_UTMI8_LSB 0 +#define USB_TXVALID_DLY_CONFIG_UTMI8_MASK 0x0000000f +#define USB_TXVALID_DLY_CONFIG_UTMI8_GET(x) (((x) & USB_TXVALID_DLY_CONFIG_UTMI8_MASK) >> USB_TXVALID_DLY_CONFIG_UTMI8_LSB) +#define USB_TXVALID_DLY_CONFIG_UTMI8_SET(x) (((x) << USB_TXVALID_DLY_CONFIG_UTMI8_LSB) & USB_TXVALID_DLY_CONFIG_UTMI8_MASK) + +#define SECOND_HOST_INFT_ADDRESS 0x00000320 +#define SECOND_HOST_INFT_OFFSET 0x00000320 +#define SECOND_HOST_INFT_SDIO_MODE_MSB 0 +#define SECOND_HOST_INFT_SDIO_MODE_LSB 0 +#define SECOND_HOST_INFT_SDIO_MODE_MASK 0x00000001 +#define SECOND_HOST_INFT_SDIO_MODE_GET(x) (((x) & SECOND_HOST_INFT_SDIO_MODE_MASK) >> SECOND_HOST_INFT_SDIO_MODE_LSB) +#define SECOND_HOST_INFT_SDIO_MODE_SET(x) (((x) << SECOND_HOST_INFT_SDIO_MODE_LSB) & SECOND_HOST_INFT_SDIO_MODE_MASK) + +#define SDIO_HOST_ADDRESS 0x00000324 +#define SDIO_HOST_OFFSET 0x00000324 +#define SDIO_HOST_RESET_MSB 0 +#define SDIO_HOST_RESET_LSB 0 +#define SDIO_HOST_RESET_MASK 0x00000001 +#define SDIO_HOST_RESET_GET(x) (((x) & SDIO_HOST_RESET_MASK) >> SDIO_HOST_RESET_LSB) +#define SDIO_HOST_RESET_SET(x) (((x) << SDIO_HOST_RESET_LSB) & SDIO_HOST_RESET_MASK) + +#define ENTERPRISE_CONFIG_ADDRESS 0x00000328 +#define ENTERPRISE_CONFIG_OFFSET 0x00000328 +#define ENTERPRISE_CONFIG_TPC_LOWER_PERFORMANCE_MSB 12 +#define ENTERPRISE_CONFIG_TPC_LOWER_PERFORMANCE_LSB 12 +#define ENTERPRISE_CONFIG_TPC_LOWER_PERFORMANCE_MASK 0x00001000 +#define ENTERPRISE_CONFIG_TPC_LOWER_PERFORMANCE_GET(x) (((x) & ENTERPRISE_CONFIG_TPC_LOWER_PERFORMANCE_MASK) >> ENTERPRISE_CONFIG_TPC_LOWER_PERFORMANCE_LSB) +#define ENTERPRISE_CONFIG_TPC_LOWER_PERFORMANCE_SET(x) (((x) << ENTERPRISE_CONFIG_TPC_LOWER_PERFORMANCE_LSB) & ENTERPRISE_CONFIG_TPC_LOWER_PERFORMANCE_MASK) +#define ENTERPRISE_CONFIG_SWCOM_IDLE_MODE_MSB 11 +#define ENTERPRISE_CONFIG_SWCOM_IDLE_MODE_LSB 11 +#define ENTERPRISE_CONFIG_SWCOM_IDLE_MODE_MASK 0x00000800 +#define ENTERPRISE_CONFIG_SWCOM_IDLE_MODE_GET(x) (((x) & ENTERPRISE_CONFIG_SWCOM_IDLE_MODE_MASK) >> ENTERPRISE_CONFIG_SWCOM_IDLE_MODE_LSB) +#define ENTERPRISE_CONFIG_SWCOM_IDLE_MODE_SET(x) (((x) << ENTERPRISE_CONFIG_SWCOM_IDLE_MODE_LSB) & ENTERPRISE_CONFIG_SWCOM_IDLE_MODE_MASK) +#define ENTERPRISE_CONFIG_STBC_DISABLE_MSB 10 +#define ENTERPRISE_CONFIG_STBC_DISABLE_LSB 10 +#define ENTERPRISE_CONFIG_STBC_DISABLE_MASK 0x00000400 +#define ENTERPRISE_CONFIG_STBC_DISABLE_GET(x) (((x) & ENTERPRISE_CONFIG_STBC_DISABLE_MASK) >> ENTERPRISE_CONFIG_STBC_DISABLE_LSB) +#define ENTERPRISE_CONFIG_STBC_DISABLE_SET(x) (((x) << ENTERPRISE_CONFIG_STBC_DISABLE_LSB) & ENTERPRISE_CONFIG_STBC_DISABLE_MASK) +#define ENTERPRISE_CONFIG_LDPC_DISABLE_MSB 9 +#define ENTERPRISE_CONFIG_LDPC_DISABLE_LSB 9 +#define ENTERPRISE_CONFIG_LDPC_DISABLE_MASK 0x00000200 +#define ENTERPRISE_CONFIG_LDPC_DISABLE_GET(x) (((x) & ENTERPRISE_CONFIG_LDPC_DISABLE_MASK) >> ENTERPRISE_CONFIG_LDPC_DISABLE_LSB) +#define ENTERPRISE_CONFIG_LDPC_DISABLE_SET(x) (((x) << ENTERPRISE_CONFIG_LDPC_DISABLE_LSB) & ENTERPRISE_CONFIG_LDPC_DISABLE_MASK) +#define ENTERPRISE_CONFIG_GREEN_TX_DISABLE_MSB 8 +#define ENTERPRISE_CONFIG_GREEN_TX_DISABLE_LSB 8 +#define ENTERPRISE_CONFIG_GREEN_TX_DISABLE_MASK 0x00000100 +#define ENTERPRISE_CONFIG_GREEN_TX_DISABLE_GET(x) (((x) & ENTERPRISE_CONFIG_GREEN_TX_DISABLE_MASK) >> ENTERPRISE_CONFIG_GREEN_TX_DISABLE_LSB) +#define ENTERPRISE_CONFIG_GREEN_TX_DISABLE_SET(x) (((x) << ENTERPRISE_CONFIG_GREEN_TX_DISABLE_LSB) & ENTERPRISE_CONFIG_GREEN_TX_DISABLE_MASK) +#define ENTERPRISE_CONFIG_DUAL_BAND_DISABLE_MSB 7 +#define ENTERPRISE_CONFIG_DUAL_BAND_DISABLE_LSB 7 +#define ENTERPRISE_CONFIG_DUAL_BAND_DISABLE_MASK 0x00000080 +#define ENTERPRISE_CONFIG_DUAL_BAND_DISABLE_GET(x) (((x) & ENTERPRISE_CONFIG_DUAL_BAND_DISABLE_MASK) >> ENTERPRISE_CONFIG_DUAL_BAND_DISABLE_LSB) +#define ENTERPRISE_CONFIG_DUAL_BAND_DISABLE_SET(x) (((x) << ENTERPRISE_CONFIG_DUAL_BAND_DISABLE_LSB) & ENTERPRISE_CONFIG_DUAL_BAND_DISABLE_MASK) +#define ENTERPRISE_CONFIG_CHAIN1_DISABLE_MSB 6 +#define ENTERPRISE_CONFIG_CHAIN1_DISABLE_LSB 6 +#define ENTERPRISE_CONFIG_CHAIN1_DISABLE_MASK 0x00000040 +#define ENTERPRISE_CONFIG_CHAIN1_DISABLE_GET(x) (((x) & ENTERPRISE_CONFIG_CHAIN1_DISABLE_MASK) >> ENTERPRISE_CONFIG_CHAIN1_DISABLE_LSB) +#define ENTERPRISE_CONFIG_CHAIN1_DISABLE_SET(x) (((x) << ENTERPRISE_CONFIG_CHAIN1_DISABLE_LSB) & ENTERPRISE_CONFIG_CHAIN1_DISABLE_MASK) +#define ENTERPRISE_CONFIG_CH_5MHZ_DISABLE_MSB 5 +#define ENTERPRISE_CONFIG_CH_5MHZ_DISABLE_LSB 5 +#define ENTERPRISE_CONFIG_CH_5MHZ_DISABLE_MASK 0x00000020 +#define ENTERPRISE_CONFIG_CH_5MHZ_DISABLE_GET(x) (((x) & ENTERPRISE_CONFIG_CH_5MHZ_DISABLE_MASK) >> ENTERPRISE_CONFIG_CH_5MHZ_DISABLE_LSB) +#define ENTERPRISE_CONFIG_CH_5MHZ_DISABLE_SET(x) (((x) << ENTERPRISE_CONFIG_CH_5MHZ_DISABLE_LSB) & ENTERPRISE_CONFIG_CH_5MHZ_DISABLE_MASK) +#define ENTERPRISE_CONFIG_CH_10MHZ_DISABLE_MSB 4 +#define ENTERPRISE_CONFIG_CH_10MHZ_DISABLE_LSB 4 +#define ENTERPRISE_CONFIG_CH_10MHZ_DISABLE_MASK 0x00000010 +#define ENTERPRISE_CONFIG_CH_10MHZ_DISABLE_GET(x) (((x) & ENTERPRISE_CONFIG_CH_10MHZ_DISABLE_MASK) >> ENTERPRISE_CONFIG_CH_10MHZ_DISABLE_LSB) +#define ENTERPRISE_CONFIG_CH_10MHZ_DISABLE_SET(x) (((x) << ENTERPRISE_CONFIG_CH_10MHZ_DISABLE_LSB) & ENTERPRISE_CONFIG_CH_10MHZ_DISABLE_MASK) +#define ENTERPRISE_CONFIG_TXBF_DISABLE_MSB 3 +#define ENTERPRISE_CONFIG_TXBF_DISABLE_LSB 3 +#define ENTERPRISE_CONFIG_TXBF_DISABLE_MASK 0x00000008 +#define ENTERPRISE_CONFIG_TXBF_DISABLE_GET(x) (((x) & ENTERPRISE_CONFIG_TXBF_DISABLE_MASK) >> ENTERPRISE_CONFIG_TXBF_DISABLE_LSB) +#define ENTERPRISE_CONFIG_TXBF_DISABLE_SET(x) (((x) << ENTERPRISE_CONFIG_TXBF_DISABLE_LSB) & ENTERPRISE_CONFIG_TXBF_DISABLE_MASK) +#define ENTERPRISE_CONFIG_MIN_PKT_SIZE_DISABLE_MSB 2 +#define ENTERPRISE_CONFIG_MIN_PKT_SIZE_DISABLE_LSB 2 +#define ENTERPRISE_CONFIG_MIN_PKT_SIZE_DISABLE_MASK 0x00000004 +#define ENTERPRISE_CONFIG_MIN_PKT_SIZE_DISABLE_GET(x) (((x) & ENTERPRISE_CONFIG_MIN_PKT_SIZE_DISABLE_MASK) >> ENTERPRISE_CONFIG_MIN_PKT_SIZE_DISABLE_LSB) +#define ENTERPRISE_CONFIG_MIN_PKT_SIZE_DISABLE_SET(x) (((x) << ENTERPRISE_CONFIG_MIN_PKT_SIZE_DISABLE_LSB) & ENTERPRISE_CONFIG_MIN_PKT_SIZE_DISABLE_MASK) +#define ENTERPRISE_CONFIG_LOOPBACK_DISABLE_MSB 1 +#define ENTERPRISE_CONFIG_LOOPBACK_DISABLE_LSB 1 +#define ENTERPRISE_CONFIG_LOOPBACK_DISABLE_MASK 0x00000002 +#define ENTERPRISE_CONFIG_LOOPBACK_DISABLE_GET(x) (((x) & ENTERPRISE_CONFIG_LOOPBACK_DISABLE_MASK) >> ENTERPRISE_CONFIG_LOOPBACK_DISABLE_LSB) +#define ENTERPRISE_CONFIG_LOOPBACK_DISABLE_SET(x) (((x) << ENTERPRISE_CONFIG_LOOPBACK_DISABLE_LSB) & ENTERPRISE_CONFIG_LOOPBACK_DISABLE_MASK) +#define ENTERPRISE_CONFIG_LOCATION_DISABLE_MSB 0 +#define ENTERPRISE_CONFIG_LOCATION_DISABLE_LSB 0 +#define ENTERPRISE_CONFIG_LOCATION_DISABLE_MASK 0x00000001 +#define ENTERPRISE_CONFIG_LOCATION_DISABLE_GET(x) (((x) & ENTERPRISE_CONFIG_LOCATION_DISABLE_MASK) >> ENTERPRISE_CONFIG_LOCATION_DISABLE_LSB) +#define ENTERPRISE_CONFIG_LOCATION_DISABLE_SET(x) (((x) << ENTERPRISE_CONFIG_LOCATION_DISABLE_LSB) & ENTERPRISE_CONFIG_LOCATION_DISABLE_MASK) + +#define RTC_DEBUG_BUS_ADDRESS 0x0000032c +#define RTC_DEBUG_BUS_OFFSET 0x0000032c +#define RTC_DEBUG_BUS_SEL_MSB 0 +#define RTC_DEBUG_BUS_SEL_LSB 0 +#define RTC_DEBUG_BUS_SEL_MASK 0x00000001 +#define RTC_DEBUG_BUS_SEL_GET(x) (((x) & RTC_DEBUG_BUS_SEL_MASK) >> RTC_DEBUG_BUS_SEL_LSB) +#define RTC_DEBUG_BUS_SEL_SET(x) (((x) << RTC_DEBUG_BUS_SEL_LSB) & RTC_DEBUG_BUS_SEL_MASK) + +#define RTC_EXT_CLK_BUF_ADDRESS 0x00000330 +#define RTC_EXT_CLK_BUF_OFFSET 0x00000330 +#define RTC_EXT_CLK_BUF_EN_MSB 0 +#define RTC_EXT_CLK_BUF_EN_LSB 0 +#define RTC_EXT_CLK_BUF_EN_MASK 0x00000001 +#define RTC_EXT_CLK_BUF_EN_GET(x) (((x) & RTC_EXT_CLK_BUF_EN_MASK) >> RTC_EXT_CLK_BUF_EN_LSB) +#define RTC_EXT_CLK_BUF_EN_SET(x) (((x) << RTC_EXT_CLK_BUF_EN_LSB) & RTC_EXT_CLK_BUF_EN_MASK) + +#define WLAN_AHB_BRIDGE_TIMEOUT_ADDRESS 0x00000334 +#define WLAN_AHB_BRIDGE_TIMEOUT_OFFSET 0x00000334 +#define WLAN_AHB_BRIDGE_TIMEOUT_CONFIG_MSB 13 +#define WLAN_AHB_BRIDGE_TIMEOUT_CONFIG_LSB 0 +#define WLAN_AHB_BRIDGE_TIMEOUT_CONFIG_MASK 0x00003fff +#define WLAN_AHB_BRIDGE_TIMEOUT_CONFIG_GET(x) (((x) & WLAN_AHB_BRIDGE_TIMEOUT_CONFIG_MASK) >> WLAN_AHB_BRIDGE_TIMEOUT_CONFIG_LSB) +#define WLAN_AHB_BRIDGE_TIMEOUT_CONFIG_SET(x) (((x) << WLAN_AHB_BRIDGE_TIMEOUT_CONFIG_LSB) & WLAN_AHB_BRIDGE_TIMEOUT_CONFIG_MASK) + +#define WLAN_AHB_CONFIG_ADDRESS 0x00000338 +#define WLAN_AHB_CONFIG_OFFSET 0x00000338 +#define WLAN_AHB_CONFIG_MAX_BURST_16_MSB 2 +#define WLAN_AHB_CONFIG_MAX_BURST_16_LSB 2 +#define WLAN_AHB_CONFIG_MAX_BURST_16_MASK 0x00000004 +#define WLAN_AHB_CONFIG_MAX_BURST_16_GET(x) (((x) & WLAN_AHB_CONFIG_MAX_BURST_16_MASK) >> WLAN_AHB_CONFIG_MAX_BURST_16_LSB) +#define WLAN_AHB_CONFIG_MAX_BURST_16_SET(x) (((x) << WLAN_AHB_CONFIG_MAX_BURST_16_LSB) & WLAN_AHB_CONFIG_MAX_BURST_16_MASK) +#define WLAN_AHB_CONFIG_MAX_BURST_8_MSB 1 +#define WLAN_AHB_CONFIG_MAX_BURST_8_LSB 1 +#define WLAN_AHB_CONFIG_MAX_BURST_8_MASK 0x00000002 +#define WLAN_AHB_CONFIG_MAX_BURST_8_GET(x) (((x) & WLAN_AHB_CONFIG_MAX_BURST_8_MASK) >> WLAN_AHB_CONFIG_MAX_BURST_8_LSB) +#define WLAN_AHB_CONFIG_MAX_BURST_8_SET(x) (((x) << WLAN_AHB_CONFIG_MAX_BURST_8_LSB) & WLAN_AHB_CONFIG_MAX_BURST_8_MASK) +#define WLAN_AHB_CONFIG_MAX_BURST_4_MSB 0 +#define WLAN_AHB_CONFIG_MAX_BURST_4_LSB 0 +#define WLAN_AHB_CONFIG_MAX_BURST_4_MASK 0x00000001 +#define WLAN_AHB_CONFIG_MAX_BURST_4_GET(x) (((x) & WLAN_AHB_CONFIG_MAX_BURST_4_MASK) >> WLAN_AHB_CONFIG_MAX_BURST_4_LSB) +#define WLAN_AHB_CONFIG_MAX_BURST_4_SET(x) (((x) << WLAN_AHB_CONFIG_MAX_BURST_4_LSB) & WLAN_AHB_CONFIG_MAX_BURST_4_MASK) + +#define RTC_AXI_AHB_BRIDGE_ADDRESS 0x0000033c +#define RTC_AXI_AHB_BRIDGE_OFFSET 0x0000033c +#define RTC_AXI_AHB_BRIDGE_BURST_WR_ALIGN_EN_MSB 3 +#define RTC_AXI_AHB_BRIDGE_BURST_WR_ALIGN_EN_LSB 3 +#define RTC_AXI_AHB_BRIDGE_BURST_WR_ALIGN_EN_MASK 0x00000008 +#define RTC_AXI_AHB_BRIDGE_BURST_WR_ALIGN_EN_GET(x) (((x) & RTC_AXI_AHB_BRIDGE_BURST_WR_ALIGN_EN_MASK) >> RTC_AXI_AHB_BRIDGE_BURST_WR_ALIGN_EN_LSB) +#define RTC_AXI_AHB_BRIDGE_BURST_WR_ALIGN_EN_SET(x) (((x) << RTC_AXI_AHB_BRIDGE_BURST_WR_ALIGN_EN_LSB) & RTC_AXI_AHB_BRIDGE_BURST_WR_ALIGN_EN_MASK) +#define RTC_AXI_AHB_BRIDGE_BURST_RD_ALIGN_EN_MSB 2 +#define RTC_AXI_AHB_BRIDGE_BURST_RD_ALIGN_EN_LSB 2 +#define RTC_AXI_AHB_BRIDGE_BURST_RD_ALIGN_EN_MASK 0x00000004 +#define RTC_AXI_AHB_BRIDGE_BURST_RD_ALIGN_EN_GET(x) (((x) & RTC_AXI_AHB_BRIDGE_BURST_RD_ALIGN_EN_MASK) >> RTC_AXI_AHB_BRIDGE_BURST_RD_ALIGN_EN_LSB) +#define RTC_AXI_AHB_BRIDGE_BURST_RD_ALIGN_EN_SET(x) (((x) << RTC_AXI_AHB_BRIDGE_BURST_RD_ALIGN_EN_LSB) & RTC_AXI_AHB_BRIDGE_BURST_RD_ALIGN_EN_MASK) +#define RTC_AXI_AHB_BRIDGE_MAX_BEATS_MSB 1 +#define RTC_AXI_AHB_BRIDGE_MAX_BEATS_LSB 0 +#define RTC_AXI_AHB_BRIDGE_MAX_BEATS_MASK 0x00000003 +#define RTC_AXI_AHB_BRIDGE_MAX_BEATS_GET(x) (((x) & RTC_AXI_AHB_BRIDGE_MAX_BEATS_MASK) >> RTC_AXI_AHB_BRIDGE_MAX_BEATS_LSB) +#define RTC_AXI_AHB_BRIDGE_MAX_BEATS_SET(x) (((x) << RTC_AXI_AHB_BRIDGE_MAX_BEATS_LSB) & RTC_AXI_AHB_BRIDGE_MAX_BEATS_MASK) + +#define WLAN2BT_CPUCOM_INT_STS_ADDRESS 0x00000400 +#define WLAN2BT_CPUCOM_INT_STS_OFFSET 0x00000400 +#define WLAN2BT_CPUCOM_INT_STS_REG_MSB 31 +#define WLAN2BT_CPUCOM_INT_STS_REG_LSB 0 +#define WLAN2BT_CPUCOM_INT_STS_REG_MASK 0xffffffff +#define WLAN2BT_CPUCOM_INT_STS_REG_GET(x) (((x) & WLAN2BT_CPUCOM_INT_STS_REG_MASK) >> WLAN2BT_CPUCOM_INT_STS_REG_LSB) +#define WLAN2BT_CPUCOM_INT_STS_REG_SET(x) (((x) << WLAN2BT_CPUCOM_INT_STS_REG_LSB) & WLAN2BT_CPUCOM_INT_STS_REG_MASK) + +#define WLAN2BT_CPUCOM_INT_MASK_N_ADDRESS 0x00000404 +#define WLAN2BT_CPUCOM_INT_MASK_N_OFFSET 0x00000404 +#define WLAN2BT_CPUCOM_INT_MASK_N_REG_MSB 31 +#define WLAN2BT_CPUCOM_INT_MASK_N_REG_LSB 0 +#define WLAN2BT_CPUCOM_INT_MASK_N_REG_MASK 0xffffffff +#define WLAN2BT_CPUCOM_INT_MASK_N_REG_GET(x) (((x) & WLAN2BT_CPUCOM_INT_MASK_N_REG_MASK) >> WLAN2BT_CPUCOM_INT_MASK_N_REG_LSB) +#define WLAN2BT_CPUCOM_INT_MASK_N_REG_SET(x) (((x) << WLAN2BT_CPUCOM_INT_MASK_N_REG_LSB) & WLAN2BT_CPUCOM_INT_MASK_N_REG_MASK) + +#define WLAN2BT_CPUCOM_INT_EOI_ADDRESS 0x00000408 +#define WLAN2BT_CPUCOM_INT_EOI_OFFSET 0x00000408 +#define WLAN2BT_CPUCOM_INT_EOI_REG_MSB 31 +#define WLAN2BT_CPUCOM_INT_EOI_REG_LSB 0 +#define WLAN2BT_CPUCOM_INT_EOI_REG_MASK 0xffffffff +#define WLAN2BT_CPUCOM_INT_EOI_REG_GET(x) (((x) & WLAN2BT_CPUCOM_INT_EOI_REG_MASK) >> WLAN2BT_CPUCOM_INT_EOI_REG_LSB) +#define WLAN2BT_CPUCOM_INT_EOI_REG_SET(x) (((x) << WLAN2BT_CPUCOM_INT_EOI_REG_LSB) & WLAN2BT_CPUCOM_INT_EOI_REG_MASK) + +#define WLAN2BT_CPUCOM_INT_ACK_STS_ADDRESS 0x0000040c +#define WLAN2BT_CPUCOM_INT_ACK_STS_OFFSET 0x0000040c +#define WLAN2BT_CPUCOM_INT_ACK_STS_REG_MSB 31 +#define WLAN2BT_CPUCOM_INT_ACK_STS_REG_LSB 0 +#define WLAN2BT_CPUCOM_INT_ACK_STS_REG_MASK 0xffffffff +#define WLAN2BT_CPUCOM_INT_ACK_STS_REG_GET(x) (((x) & WLAN2BT_CPUCOM_INT_ACK_STS_REG_MASK) >> WLAN2BT_CPUCOM_INT_ACK_STS_REG_LSB) +#define WLAN2BT_CPUCOM_INT_ACK_STS_REG_SET(x) (((x) << WLAN2BT_CPUCOM_INT_ACK_STS_REG_LSB) & WLAN2BT_CPUCOM_INT_ACK_STS_REG_MASK) + +#define WLAN2BT_CPUCOM_INT_ACK_MASK_N_ADDRESS 0x00000410 +#define WLAN2BT_CPUCOM_INT_ACK_MASK_N_OFFSET 0x00000410 +#define WLAN2BT_CPUCOM_INT_ACK_MASK_N_REG_MSB 31 +#define WLAN2BT_CPUCOM_INT_ACK_MASK_N_REG_LSB 0 +#define WLAN2BT_CPUCOM_INT_ACK_MASK_N_REG_MASK 0xffffffff +#define WLAN2BT_CPUCOM_INT_ACK_MASK_N_REG_GET(x) (((x) & WLAN2BT_CPUCOM_INT_ACK_MASK_N_REG_MASK) >> WLAN2BT_CPUCOM_INT_ACK_MASK_N_REG_LSB) +#define WLAN2BT_CPUCOM_INT_ACK_MASK_N_REG_SET(x) (((x) << WLAN2BT_CPUCOM_INT_ACK_MASK_N_REG_LSB) & WLAN2BT_CPUCOM_INT_ACK_MASK_N_REG_MASK) + +#define WLAN_CPUCOM_CRD_CNT0_ADDRESS 0x00000414 +#define WLAN_CPUCOM_CRD_CNT0_OFFSET 0x00000414 +#define WLAN_CPUCOM_CRD_CNT0_REG_MSB 15 +#define WLAN_CPUCOM_CRD_CNT0_REG_LSB 0 +#define WLAN_CPUCOM_CRD_CNT0_REG_MASK 0x0000ffff +#define WLAN_CPUCOM_CRD_CNT0_REG_GET(x) (((x) & WLAN_CPUCOM_CRD_CNT0_REG_MASK) >> WLAN_CPUCOM_CRD_CNT0_REG_LSB) +#define WLAN_CPUCOM_CRD_CNT0_REG_SET(x) (((x) << WLAN_CPUCOM_CRD_CNT0_REG_LSB) & WLAN_CPUCOM_CRD_CNT0_REG_MASK) + +#define WLAN_CPUCOM_CRD_INC0_ADDRESS 0x00000418 +#define WLAN_CPUCOM_CRD_INC0_OFFSET 0x00000418 +#define WLAN_CPUCOM_CRD_INC0_REG_MSB 15 +#define WLAN_CPUCOM_CRD_INC0_REG_LSB 0 +#define WLAN_CPUCOM_CRD_INC0_REG_MASK 0x0000ffff +#define WLAN_CPUCOM_CRD_INC0_REG_GET(x) (((x) & WLAN_CPUCOM_CRD_INC0_REG_MASK) >> WLAN_CPUCOM_CRD_INC0_REG_LSB) +#define WLAN_CPUCOM_CRD_INC0_REG_SET(x) (((x) << WLAN_CPUCOM_CRD_INC0_REG_LSB) & WLAN_CPUCOM_CRD_INC0_REG_MASK) + +#define WLAN_CPUCOM_CRD_DEC0_ADDRESS 0x0000041c +#define WLAN_CPUCOM_CRD_DEC0_OFFSET 0x0000041c +#define WLAN_CPUCOM_CRD_DEC0_REG_MSB 15 +#define WLAN_CPUCOM_CRD_DEC0_REG_LSB 0 +#define WLAN_CPUCOM_CRD_DEC0_REG_MASK 0x0000ffff +#define WLAN_CPUCOM_CRD_DEC0_REG_GET(x) (((x) & WLAN_CPUCOM_CRD_DEC0_REG_MASK) >> WLAN_CPUCOM_CRD_DEC0_REG_LSB) +#define WLAN_CPUCOM_CRD_DEC0_REG_SET(x) (((x) << WLAN_CPUCOM_CRD_DEC0_REG_LSB) & WLAN_CPUCOM_CRD_DEC0_REG_MASK) + +#define WLAN_CPUCOM_CRD_CNT1_ADDRESS 0x00000420 +#define WLAN_CPUCOM_CRD_CNT1_OFFSET 0x00000420 +#define WLAN_CPUCOM_CRD_CNT1_REG_MSB 15 +#define WLAN_CPUCOM_CRD_CNT1_REG_LSB 0 +#define WLAN_CPUCOM_CRD_CNT1_REG_MASK 0x0000ffff +#define WLAN_CPUCOM_CRD_CNT1_REG_GET(x) (((x) & WLAN_CPUCOM_CRD_CNT1_REG_MASK) >> WLAN_CPUCOM_CRD_CNT1_REG_LSB) +#define WLAN_CPUCOM_CRD_CNT1_REG_SET(x) (((x) << WLAN_CPUCOM_CRD_CNT1_REG_LSB) & WLAN_CPUCOM_CRD_CNT1_REG_MASK) + +#define WLAN_CPUCOM_CRD_INC1_ADDRESS 0x00000424 +#define WLAN_CPUCOM_CRD_INC1_OFFSET 0x00000424 +#define WLAN_CPUCOM_CRD_INC1_REG_MSB 15 +#define WLAN_CPUCOM_CRD_INC1_REG_LSB 0 +#define WLAN_CPUCOM_CRD_INC1_REG_MASK 0x0000ffff +#define WLAN_CPUCOM_CRD_INC1_REG_GET(x) (((x) & WLAN_CPUCOM_CRD_INC1_REG_MASK) >> WLAN_CPUCOM_CRD_INC1_REG_LSB) +#define WLAN_CPUCOM_CRD_INC1_REG_SET(x) (((x) << WLAN_CPUCOM_CRD_INC1_REG_LSB) & WLAN_CPUCOM_CRD_INC1_REG_MASK) + +#define WLAN_CPUCOM_CRD_DEC1_ADDRESS 0x00000428 +#define WLAN_CPUCOM_CRD_DEC1_OFFSET 0x00000428 +#define WLAN_CPUCOM_CRD_DEC1_REG_MSB 15 +#define WLAN_CPUCOM_CRD_DEC1_REG_LSB 0 +#define WLAN_CPUCOM_CRD_DEC1_REG_MASK 0x0000ffff +#define WLAN_CPUCOM_CRD_DEC1_REG_GET(x) (((x) & WLAN_CPUCOM_CRD_DEC1_REG_MASK) >> WLAN_CPUCOM_CRD_DEC1_REG_LSB) +#define WLAN_CPUCOM_CRD_DEC1_REG_SET(x) (((x) << WLAN_CPUCOM_CRD_DEC1_REG_LSB) & WLAN_CPUCOM_CRD_DEC1_REG_MASK) + +#define WLAN_CPUCOM_SCRATCH0_ADDRESS 0x0000042c +#define WLAN_CPUCOM_SCRATCH0_OFFSET 0x0000042c +#define WLAN_CPUCOM_SCRATCH0_REG_MSB 31 +#define WLAN_CPUCOM_SCRATCH0_REG_LSB 0 +#define WLAN_CPUCOM_SCRATCH0_REG_MASK 0xffffffff +#define WLAN_CPUCOM_SCRATCH0_REG_GET(x) (((x) & WLAN_CPUCOM_SCRATCH0_REG_MASK) >> WLAN_CPUCOM_SCRATCH0_REG_LSB) +#define WLAN_CPUCOM_SCRATCH0_REG_SET(x) (((x) << WLAN_CPUCOM_SCRATCH0_REG_LSB) & WLAN_CPUCOM_SCRATCH0_REG_MASK) + +#define WLAN_CPUCOM_SCRATCH1_ADDRESS 0x00000430 +#define WLAN_CPUCOM_SCRATCH1_OFFSET 0x00000430 +#define WLAN_CPUCOM_SCRATCH1_REG_MSB 31 +#define WLAN_CPUCOM_SCRATCH1_REG_LSB 0 +#define WLAN_CPUCOM_SCRATCH1_REG_MASK 0xffffffff +#define WLAN_CPUCOM_SCRATCH1_REG_GET(x) (((x) & WLAN_CPUCOM_SCRATCH1_REG_MASK) >> WLAN_CPUCOM_SCRATCH1_REG_LSB) +#define WLAN_CPUCOM_SCRATCH1_REG_SET(x) (((x) << WLAN_CPUCOM_SCRATCH1_REG_LSB) & WLAN_CPUCOM_SCRATCH1_REG_MASK) + +#define WLAN_CPUCOM_SCRATCH2_ADDRESS 0x00000434 +#define WLAN_CPUCOM_SCRATCH2_OFFSET 0x00000434 +#define WLAN_CPUCOM_SCRATCH2_REG_MSB 31 +#define WLAN_CPUCOM_SCRATCH2_REG_LSB 0 +#define WLAN_CPUCOM_SCRATCH2_REG_MASK 0xffffffff +#define WLAN_CPUCOM_SCRATCH2_REG_GET(x) (((x) & WLAN_CPUCOM_SCRATCH2_REG_MASK) >> WLAN_CPUCOM_SCRATCH2_REG_LSB) +#define WLAN_CPUCOM_SCRATCH2_REG_SET(x) (((x) << WLAN_CPUCOM_SCRATCH2_REG_LSB) & WLAN_CPUCOM_SCRATCH2_REG_MASK) + +#define WLAN_CPUCOM_SCRATCH3_ADDRESS 0x00000438 +#define WLAN_CPUCOM_SCRATCH3_OFFSET 0x00000438 +#define WLAN_CPUCOM_SCRATCH3_REG_MSB 31 +#define WLAN_CPUCOM_SCRATCH3_REG_LSB 0 +#define WLAN_CPUCOM_SCRATCH3_REG_MASK 0xffffffff +#define WLAN_CPUCOM_SCRATCH3_REG_GET(x) (((x) & WLAN_CPUCOM_SCRATCH3_REG_MASK) >> WLAN_CPUCOM_SCRATCH3_REG_LSB) +#define WLAN_CPUCOM_SCRATCH3_REG_SET(x) (((x) << WLAN_CPUCOM_SCRATCH3_REG_LSB) & WLAN_CPUCOM_SCRATCH3_REG_MASK) + +#define WLAN_CPUCOM_DBG_ADDRESS 0x0000043c +#define WLAN_CPUCOM_DBG_OFFSET 0x0000043c +#define WLAN_CPUCOM_DBG_RESERVE_MSB 7 +#define WLAN_CPUCOM_DBG_RESERVE_LSB 4 +#define WLAN_CPUCOM_DBG_RESERVE_MASK 0x000000f0 +#define WLAN_CPUCOM_DBG_RESERVE_GET(x) (((x) & WLAN_CPUCOM_DBG_RESERVE_MASK) >> WLAN_CPUCOM_DBG_RESERVE_LSB) +#define WLAN_CPUCOM_DBG_RESERVE_SET(x) (((x) << WLAN_CPUCOM_DBG_RESERVE_LSB) & WLAN_CPUCOM_DBG_RESERVE_MASK) +#define WLAN_CPUCOM_DBG_CRD1_DEC_ERR_MSB 3 +#define WLAN_CPUCOM_DBG_CRD1_DEC_ERR_LSB 3 +#define WLAN_CPUCOM_DBG_CRD1_DEC_ERR_MASK 0x00000008 +#define WLAN_CPUCOM_DBG_CRD1_DEC_ERR_GET(x) (((x) & WLAN_CPUCOM_DBG_CRD1_DEC_ERR_MASK) >> WLAN_CPUCOM_DBG_CRD1_DEC_ERR_LSB) +#define WLAN_CPUCOM_DBG_CRD1_DEC_ERR_SET(x) (((x) << WLAN_CPUCOM_DBG_CRD1_DEC_ERR_LSB) & WLAN_CPUCOM_DBG_CRD1_DEC_ERR_MASK) +#define WLAN_CPUCOM_DBG_CRD1_INC_ERR_MSB 2 +#define WLAN_CPUCOM_DBG_CRD1_INC_ERR_LSB 2 +#define WLAN_CPUCOM_DBG_CRD1_INC_ERR_MASK 0x00000004 +#define WLAN_CPUCOM_DBG_CRD1_INC_ERR_GET(x) (((x) & WLAN_CPUCOM_DBG_CRD1_INC_ERR_MASK) >> WLAN_CPUCOM_DBG_CRD1_INC_ERR_LSB) +#define WLAN_CPUCOM_DBG_CRD1_INC_ERR_SET(x) (((x) << WLAN_CPUCOM_DBG_CRD1_INC_ERR_LSB) & WLAN_CPUCOM_DBG_CRD1_INC_ERR_MASK) +#define WLAN_CPUCOM_DBG_CRD0_DEC_ERR_MSB 1 +#define WLAN_CPUCOM_DBG_CRD0_DEC_ERR_LSB 1 +#define WLAN_CPUCOM_DBG_CRD0_DEC_ERR_MASK 0x00000002 +#define WLAN_CPUCOM_DBG_CRD0_DEC_ERR_GET(x) (((x) & WLAN_CPUCOM_DBG_CRD0_DEC_ERR_MASK) >> WLAN_CPUCOM_DBG_CRD0_DEC_ERR_LSB) +#define WLAN_CPUCOM_DBG_CRD0_DEC_ERR_SET(x) (((x) << WLAN_CPUCOM_DBG_CRD0_DEC_ERR_LSB) & WLAN_CPUCOM_DBG_CRD0_DEC_ERR_MASK) +#define WLAN_CPUCOM_DBG_CRD0_INC_ERR_MSB 0 +#define WLAN_CPUCOM_DBG_CRD0_INC_ERR_LSB 0 +#define WLAN_CPUCOM_DBG_CRD0_INC_ERR_MASK 0x00000001 +#define WLAN_CPUCOM_DBG_CRD0_INC_ERR_GET(x) (((x) & WLAN_CPUCOM_DBG_CRD0_INC_ERR_MASK) >> WLAN_CPUCOM_DBG_CRD0_INC_ERR_LSB) +#define WLAN_CPUCOM_DBG_CRD0_INC_ERR_SET(x) (((x) << WLAN_CPUCOM_DBG_CRD0_INC_ERR_LSB) & WLAN_CPUCOM_DBG_CRD0_INC_ERR_MASK) + +#define WLAN2BT_CPUCOM_INT_ACK_EN_ADDRESS 0x00000440 +#define WLAN2BT_CPUCOM_INT_ACK_EN_OFFSET 0x00000440 +#define WLAN2BT_CPUCOM_INT_ACK_EN_REG_MSB 0 +#define WLAN2BT_CPUCOM_INT_ACK_EN_REG_LSB 0 +#define WLAN2BT_CPUCOM_INT_ACK_EN_REG_MASK 0x00000001 +#define WLAN2BT_CPUCOM_INT_ACK_EN_REG_GET(x) (((x) & WLAN2BT_CPUCOM_INT_ACK_EN_REG_MASK) >> WLAN2BT_CPUCOM_INT_ACK_EN_REG_LSB) +#define WLAN2BT_CPUCOM_INT_ACK_EN_REG_SET(x) (((x) << WLAN2BT_CPUCOM_INT_ACK_EN_REG_LSB) & WLAN2BT_CPUCOM_INT_ACK_EN_REG_MASK) + +#define BT2WLAN_CPUCOM_INT_EN_ADDRESS 0x00000444 +#define BT2WLAN_CPUCOM_INT_EN_OFFSET 0x00000444 +#define BT2WLAN_CPUCOM_INT_EN_REG_MSB 0 +#define BT2WLAN_CPUCOM_INT_EN_REG_LSB 0 +#define BT2WLAN_CPUCOM_INT_EN_REG_MASK 0x00000001 +#define BT2WLAN_CPUCOM_INT_EN_REG_GET(x) (((x) & BT2WLAN_CPUCOM_INT_EN_REG_MASK) >> BT2WLAN_CPUCOM_INT_EN_REG_LSB) +#define BT2WLAN_CPUCOM_INT_EN_REG_SET(x) (((x) << BT2WLAN_CPUCOM_INT_EN_REG_LSB) & BT2WLAN_CPUCOM_INT_EN_REG_MASK) + +#ifndef __ASSEMBLER__ +typedef struct rtc_soc_reg_reg_s { + volatile unsigned int soc_reset_control; + volatile unsigned int soc_tcxo_detect; + volatile unsigned int soc_xtal_test; + unsigned char pad0[20]; /* pad to 0x20 */ + volatile unsigned int soc_cpu_clock; + unsigned char pad1[4]; /* pad to 0x28 */ + volatile unsigned int soc_clock_control; + unsigned char pad2[4]; /* pad to 0x30 */ + volatile unsigned int soc_wdt_control; + volatile unsigned int soc_wdt_status; + volatile unsigned int soc_wdt; + volatile unsigned int soc_wdt_count; + volatile unsigned int soc_wdt_reset; + volatile unsigned int soc_int_status; + volatile unsigned int soc_lf_timer0; + volatile unsigned int soc_lf_timer_count0; + volatile unsigned int soc_lf_timer_control0; + volatile unsigned int soc_lf_timer_status0; + volatile unsigned int soc_lf_timer1; + volatile unsigned int soc_lf_timer_count1; + volatile unsigned int soc_lf_timer_control1; + volatile unsigned int soc_lf_timer_status1; + volatile unsigned int soc_lf_timer2; + volatile unsigned int soc_lf_timer_count2; + volatile unsigned int soc_lf_timer_control2; + volatile unsigned int soc_lf_timer_status2; + volatile unsigned int soc_lf_timer3; + volatile unsigned int soc_lf_timer_count3; + volatile unsigned int soc_lf_timer_control3; + volatile unsigned int soc_lf_timer_status3; + volatile unsigned int soc_hf_timer; + volatile unsigned int soc_hf_timer_count; + volatile unsigned int soc_hf_lf_count; + volatile unsigned int soc_hf_timer_control; + volatile unsigned int soc_hf_timer_status; + volatile unsigned int soc_rtc_control; + volatile unsigned int soc_rtc_time; + volatile unsigned int soc_rtc_date; + volatile unsigned int soc_rtc_set_time; + volatile unsigned int soc_rtc_set_date; + volatile unsigned int soc_rtc_set_alarm; + volatile unsigned int soc_rtc_config; + volatile unsigned int soc_rtc_alarm_status; + volatile unsigned int soc_uart_wakeup; + volatile unsigned int soc_reset_cause; + volatile unsigned int soc_system_sleep; + volatile unsigned int soc_sdio_wrapper; + volatile unsigned int soc_int_sleep_mask; + unsigned char pad3[4]; /* pad to 0xd4 */ + volatile unsigned int soc_lpo_cal_time; + volatile unsigned int soc_lpo_init_dividend_int; + volatile unsigned int soc_lpo_init_dividend_fraction; + volatile unsigned int soc_lpo_cal; + volatile unsigned int soc_lpo_cal_test_control; + volatile unsigned int soc_lpo_cal_test_status; + volatile unsigned int legacy_soc_chip_id; + volatile unsigned int soc_chip_id; + unsigned char pad4[24]; /* pad to 0x10c */ + volatile unsigned int soc_power_reg; + volatile unsigned int soc_core_clk_ctrl; + volatile unsigned int soc_gpio_wakeup_control; + unsigned char pad5[252]; /* pad to 0x214 */ + volatile unsigned int sleep_retention; + unsigned char pad6[108]; /* pad to 0x284 */ + volatile unsigned int lp_perf_counter; + volatile unsigned int lp_perf_light_sleep; + volatile unsigned int lp_perf_deep_sleep; + volatile unsigned int lp_perf_on; + unsigned char pad7[20]; /* pad to 0x2a8 */ + volatile unsigned int chip_mode; + volatile unsigned int clk_req_fall_edge; + volatile unsigned int otp; + volatile unsigned int otp_status; + volatile unsigned int pmu; + volatile unsigned int pmu_config; + volatile unsigned int pmu_pareg; + volatile unsigned int pmu_bypass; + unsigned char pad8[20]; /* pad to 0x2dc */ + volatile unsigned int therm_ctrl1; + volatile unsigned int therm_ctrl2; + volatile unsigned int therm_ctrl3; + volatile unsigned int listen_mode1; + volatile unsigned int listen_mode2; + volatile unsigned int audio_pll_config; + volatile unsigned int audio_pll_modulation; + volatile unsigned int audio_pll_mod_step; + volatile unsigned int current_audio_pll_modulation; + volatile unsigned int eth_pll_config; + volatile unsigned int cpu_pll_config; + volatile unsigned int bb_pll_config; + volatile unsigned int eth_xmii; + volatile unsigned int usb_phy_config; + volatile unsigned int usbcore_clk60m; + volatile unsigned int usbphy_utmi_clk; + volatile unsigned int usb_txvalid_dly_config; + volatile unsigned int second_host_inft; + volatile unsigned int sdio_host; + volatile unsigned int enterprise_config; + volatile unsigned int rtc_debug_bus; + volatile unsigned int rtc_ext_clk_buf; + volatile unsigned int wlan_ahb_bridge_timeout; + volatile unsigned int wlan_ahb_config; + volatile unsigned int rtc_axi_ahb_bridge; + unsigned char pad9[192]; /* pad to 0x400 */ + volatile unsigned int wlan2bt_cpucom_int_sts; + volatile unsigned int wlan2bt_cpucom_int_mask_n; + volatile unsigned int wlan2bt_cpucom_int_eoi; + volatile unsigned int wlan2bt_cpucom_int_ack_sts; + volatile unsigned int wlan2bt_cpucom_int_ack_mask_n; + volatile unsigned int wlan_cpucom_crd_cnt0; + volatile unsigned int wlan_cpucom_crd_inc0[1]; + volatile unsigned int wlan_cpucom_crd_dec0[1]; + volatile unsigned int wlan_cpucom_crd_cnt1; + volatile unsigned int wlan_cpucom_crd_inc1[1]; + volatile unsigned int wlan_cpucom_crd_dec1[1]; + volatile unsigned int wlan_cpucom_scratch0; + volatile unsigned int wlan_cpucom_scratch1; + volatile unsigned int wlan_cpucom_scratch2; + volatile unsigned int wlan_cpucom_scratch3; + volatile unsigned int wlan_cpucom_dbg; + volatile unsigned int wlan2bt_cpucom_int_ack_en; + volatile unsigned int bt2wlan_cpucom_int_en; +} rtc_soc_reg_reg_t; +#endif /* __ASSEMBLER__ */ + +#endif /* _RTC_SOC_REG_H_ */ diff --git a/drivers/staging/fw-api/fw/targaddrs.h b/drivers/staging/fw-api/fw/targaddrs.h new file mode 100755 index 0000000000000000000000000000000000000000..13e1a7136d71d917302d7d8b5877ecdbe7c61ee9 --- /dev/null +++ b/drivers/staging/fw-api/fw/targaddrs.h @@ -0,0 +1,707 @@ +/* + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef __TARGADDRS_H__ +#define __TARGADDRS_H__ + +#if defined(ATH_TARGET) +#include "soc_addrs.h" +#endif + +#if !defined(ATH_TARGET) +#include "athstartpack.h" +#endif + +/* + * SOC option bits, to enable/disable various features. + * By default, all option bits are 0. + * AR6004: These bits can be set in LOCAL_SCRATCH register 0. + * AR9888: These bits can be set in soc_core register SCRATCH_0. + */ +#define SOC_OPTION_BMI_DISABLE 0x01 /* Disable BMI comm with Host */ +#define SOC_OPTION_SERIAL_ENABLE 0x02 /* Enable serial port msgs */ +#define SOC_OPTION_WDT_DISABLE 0x04 /* WatchDog Timer override */ +#define SOC_OPTION_SLEEP_DISABLE 0x08 /* Disable system sleep */ +#define SOC_OPTION_STOP_BOOT 0x10 /* Stop boot processes (for ATE) */ +#define SOC_OPTION_ENABLE_NOANI 0x20 /* Operate without ANI */ +#define SOC_OPTION_DSET_DISABLE 0x40 /* Ignore DataSets */ +#define SOC_OPTION_IGNORE_FLASH 0x80 /* Ignore flash during bootup */ + +/* + * xxx_HOST_INTEREST_ADDRESS is the address in Target RAM of the + * host_interest structure. It must match the address of the _host_interest + * symbol (see linker script). + * + * Host Interest is shared between Host and Target in order to coordinate + * between the two, and is intended to remain constant (with additions only + * at the end) across software releases. + * + * All addresses are available here so that it's possible to + * write a single binary that works with all Target Types. + * May be used in assembler code as well as C. + */ +#define AR6002_HOST_INTEREST_ADDRESS 0x00500400 +#define AR6003_HOST_INTEREST_ADDRESS 0x00540600 +#define AR6004_HOST_INTEREST_ADDRESS 0x00400800 +#define AR9888_HOST_INTEREST_ADDRESS 0x00400800 +#define AR900B_HOST_INTEREST_ADDRESS 0x00400800 +#define AR6320_HOST_INTEREST_ADDRESS 0x00400800 +#define QCA9377_HOST_INTEREST_ADDRESS 0x00400800 +#define AR6004_SOC_RESET_ADDRESS 0X00004000 +#define AR6004_SOC_RESET_CPU_INIT_RESET_MASK 0X00000800 +#if defined(AR6006_MEMORY_NEW_ARCH) +#define AR6006_HOST_INTEREST_ADDRESS 0x00428800 +#else +#define AR6006_HOST_INTEREST_ADDRESS 0x00400800 +#endif +#define AR6006_SOC_RESET_ADDRESS 0X00004000 +#define AR6006_SOC_RESET_CPU_INIT_RESET_MASK 0X00000800 + +#define HOST_INTEREST_MAX_SIZE 0x200 + +#if !defined(__ASSEMBLER__) +struct register_dump_s; +struct dbglog_hdr_s; + +/* + * These are items that the Host may need to access + * via BMI or via the Diagnostic Window. The position + * of items in this structure must remain constant + * across firmware revisions! + * + * Types for each item must be fixed size across + * target and host platforms. + * + * More items may be added at the end. + */ +PREPACK64 struct host_interest_s { + /* + * Pointer to application-defined area, if any. + * Set by Target application during startup. + */ + A_UINT32 hi_app_host_interest; /* 0x00 */ + + /* Pointer to register dump area, valid after Target crash. */ + A_UINT32 hi_failure_state; /* 0x04 */ + + /* Pointer to debug logging header */ + A_UINT32 hi_dbglog_hdr; /* 0x08 */ + + /* Save SW ROM version */ + A_UINT32 hi_sw_rom_version; /* 0x0c */ + + /* + * General-purpose flag bits, similar to SOC_OPTION_* flags. + * Can be used by application rather than by OS. + */ + volatile A_UINT32 hi_option_flag; /* 0x10 */ + + /* + * Boolean that determines whether or not to + * display messages on the serial port. + */ + A_UINT32 hi_serial_enable; /* 0x14 */ + + /* Start address of DataSet index, if any */ + A_UINT32 hi_dset_list_head; /* 0x18 */ + + /* Override Target application start address */ + A_UINT32 hi_app_start; /* 0x1c */ + + /* Clock and voltage tuning */ + A_UINT32 hi_skip_clock_init; /* 0x20 */ + A_UINT32 hi_core_clock_setting; /* 0x24 */ + A_UINT32 hi_cpu_clock_setting; /* 0x28 */ + A_UINT32 hi_system_sleep_setting; /* 0x2c */ + A_UINT32 hi_xtal_control_setting; /* 0x30 */ + A_UINT32 hi_pll_ctrl_setting_24ghz; /* 0x34 */ + A_UINT32 hi_pll_ctrl_setting_5ghz; /* 0x38 */ + A_UINT32 hi_ref_voltage_trim_setting; /* 0x3c */ + A_UINT32 hi_clock_info; /* 0x40 */ + + /* Host uses BE CPU or not */ + A_UINT32 hi_be; /* 0x44 */ + + A_UINT32 hi_stack; /* normal stack *//* 0x48 */ + A_UINT32 hi_err_stack; /* error stack *//* 0x4c */ + A_UINT32 hi_desired_cpu_speed_hz; /* 0x50 */ + + /* Pointer to Board Data */ + A_UINT32 hi_board_data; /* 0x54 */ + + /* + * Indication of Board Data state: + * 0: board data is not yet initialized. + * 1: board data is initialized; unknown size + * >1: number of bytes of initialized board data (varies with board type) + */ + A_UINT32 hi_board_data_initialized; /* 0x58 */ + + A_UINT32 hi_dset_RAM_index_table; /* 0x5c */ + + A_UINT32 hi_desired_baud_rate; /* 0x60 */ + A_UINT32 hi_dbglog_config; /* 0x64 */ + A_UINT32 hi_end_RAM_reserve_sz; /* 0x68 */ + A_UINT32 hi_mbox_io_block_sz; /* 0x6c */ + + A_UINT32 hi_num_bpatch_streams; /* 0x70 -- unused */ + A_UINT32 hi_mbox_isr_yield_limit; /* 0x74 */ + + A_UINT32 hi_refclk_hz; /* 0x78 */ + A_UINT32 hi_ext_clk_detected; /* 0x7c */ + A_UINT32 hi_dbg_uart_txpin; /* 0x80 */ + A_UINT32 hi_dbg_uart_rxpin; /* 0x84 */ + A_UINT32 hi_hci_uart_baud; /* 0x88 */ + A_UINT32 hi_hci_uart_pin_assignments; /* 0x8C */ + /* NOTE: byte [0] = tx pin, [1] = rx pin, [2] = rts pin, [3] = cts pin */ + A_UINT32 hi_hci_uart_baud_scale_val; /* 0x90 */ + A_UINT32 hi_hci_uart_baud_step_val; /* 0x94 */ + + A_UINT32 hi_allocram_start; /* 0x98 */ + A_UINT32 hi_allocram_sz; /* 0x9c */ + A_UINT32 hi_hci_bridge_flags; /* 0xa0 */ + A_UINT32 hi_hci_uart_support_pins; /* 0xa4 */ + /* NOTE: byte [0] = RESET pin (bit 7 is polarity), bytes[1]..bytes[3] are for future use */ + A_UINT32 hi_hci_uart_pwr_mgmt_params; /* 0xa8 */ + /* 0xa8 - [1]: 0 = UART FC active low, 1 = UART FC active high + * [31:16]: wakeup timeout in ms + */ + /* Pointer to extended board Data */ + A_UINT32 hi_board_ext_data; /* 0xac */ + A_UINT32 hi_board_ext_data_config; /* 0xb0 */ + /* + * Bit [0] : valid + * Bit[31:16: size + */ + /* + * hi_reset_flag is used to do some stuff when target reset. + * such as restore app_start after warm reset or + * preserve host Interest area, or preserve ROM data, literals etc. + */ + A_UINT32 hi_reset_flag; /* 0xb4 */ + /* indicate hi_reset_flag is valid */ + A_UINT32 hi_reset_flag_valid; /* 0xb8 */ + A_UINT32 hi_hci_uart_pwr_mgmt_params_ext; /* 0xbc */ + /* 0xbc - [31:0]: idle timeout in ms + */ + /* ACS flags */ + A_UINT32 hi_acs_flags; /* 0xc0 */ + A_UINT32 hi_console_flags; /* 0xc4 */ + A_UINT32 hi_nvram_state; /* 0xc8 */ + volatile A_UINT32 hi_option_flag2; /* 0xcc */ + + /* If non-zero, override values sent to Host in WMI_READY event. */ + A_UINT32 hi_sw_version_override; /* 0xd0 */ + A_UINT32 hi_abi_version_override; /* 0xd4 */ + + /* Percentage of high priority RX traffic to total expected RX traffic - + * applicable only to ar6004 */ + A_UINT32 hi_hp_rx_traffic_ratio; /* 0xd8 */ + + /* test applications flags */ + A_UINT32 hi_test_apps_related; /* 0xdc */ + /* location of test script */ + A_UINT32 hi_ota_testscript; /* 0xe0 */ + /* location of CAL data */ + A_UINT32 hi_cal_data; /* 0xe4 */ + + /* Number of packet log buffers */ + volatile A_UINT32 hi_pktlog_num_buffers; /* 0xe8 */ + + /* wow extension configuration */ + A_UINT32 hi_wow_ext_config; /* 0xec */ + A_UINT32 hi_pwr_save_flags; /* 0xf0 */ + + /* Spatial Multiplexing Power Save (SMPS) options */ + A_UINT32 hi_smps_options; /* 0xf4 */ + + /* Interconnect-specific state */ + A_UINT32 hi_interconnect_state; /* 0xf8 */ + + /* Coex configuration flags */ + A_UINT32 hi_coex_config; /* 0xfc */ + + /* Early allocation support */ + A_UINT32 hi_early_alloc; /* 0x100 */ + + /* FW swap field */ + /* Bits of this 32bit word will be used to pass specific swap + instruction to FW */ + /* Bit 0 -- AP Nart descriptor no swap. When this bit is set + FW will not swap TX descriptor. Meaning packets are formed + on the target processor. */ + /* Bit 1 -- TBD */ + + A_UINT32 hi_fw_swap; /* 0x104 */ + + /* global arenas pointer address, used by host driver debug */ + A_UINT32 hi_dynamic_mem_arenas_addr; /* 0x108 */ + + /* allocated bytes of DRAM use by allocated */ + A_UINT32 hi_dynamic_mem_allocated; /* 0x10C */ + + /* remaining bytes of DRAM */ + A_UINT32 hi_dynamic_mem_remaining; /* 0x110 */ + + /* memory track count, configured by host */ + A_UINT32 hi_dynamic_mem_track_max; /* 0x114 */ + + /* minidump buffer */ + A_UINT32 hi_minidump; /* 0x118 */ + + /* bdata's sig and key addr */ + A_UINT32 hi_bd_sig_key; /* 0x11c */ + +} POSTPACK64; + +/* bitmap for hi_test_apps_related */ +#define HI_TEST_APPS_TESTSCRIPT_LOADED 0x00000001 +#define HI_TEST_APPS_CAL_DATA_AVAIL 0x00000002 + +/* Bits defined in hi_option_flag */ +#define HI_OPTION_TIMER_WAR 0x01 /* Enable timer workaround */ +#define HI_OPTION_BMI_CRED_LIMIT 0x02 /* Limit BMI command credits */ +#define HI_OPTION_RELAY_DOT11_HDR 0x04 /* Relay Dot11 hdr to/from host */ +#define HI_OPTION_MAC_ADDR_METHOD 0x08 /* MAC addr method 0-locally administred 1-globally unique addrs */ +#define HI_OPTION_FW_BRIDGE 0x10 /* Firmware Bridging */ +#define HI_OPTION_ENABLE_PROFILE 0x20 /* Enable CPU profiling */ +#define HI_OPTION_DISABLE_DBGLOG 0x40 /* Disable debug logging */ +#define HI_OPTION_SKIP_ERA_TRACKING 0x80 /* Skip Era Tracking */ +#define HI_OPTION_PAPRD_DISABLE 0x100 /* Disable PAPRD (debug) */ +#define HI_OPTION_NUM_DEV_LSB 0x200 +#define HI_OPTION_NUM_DEV_MSB 0x800 +#define HI_OPTION_DEV_MODE_LSB 0x1000 +#define HI_OPTION_DEV_MODE_MSB 0x8000000 +#define HI_OPTION_NO_LFT_STBL 0x10000000 /* Disable LowFreq Timer Stabilization */ +#define HI_OPTION_SKIP_REG_SCAN 0x20000000 /* Skip regulatory scan */ +#define HI_OPTION_INIT_REG_SCAN 0x40000000 /* Do regulatory scan during init before + * sending WMI ready event to host */ +#define HI_OPTION_SKIP_MEMMAP 0x80000000 /* REV6: Do not adjust memory map */ + +#define HI_OPTION_MAC_ADDR_METHOD_SHIFT 3 + +/* 2 bits of hi_option_flag are used to represent 3 modes */ +#define HI_OPTION_FW_MODE_IBSS 0x0 /* IBSS Mode */ +#define HI_OPTION_FW_MODE_BSS_STA 0x1 /* STA Mode */ +#define HI_OPTION_FW_MODE_AP 0x2 /* AP Mode */ +#define HI_OPTION_FW_MODE_BT30AMP 0x3 /* BT30 AMP Mode */ + +/* 2 bits of hi_option flag are usedto represent 4 submodes */ +#define HI_OPTION_FW_SUBMODE_NONE 0x0 /* Normal mode */ +#define HI_OPTION_FW_SUBMODE_P2PDEV 0x1 /* p2p device mode */ +#define HI_OPTION_FW_SUBMODE_P2PCLIENT 0x2 /* p2p client mode */ +#define HI_OPTION_FW_SUBMODE_P2PGO 0x3 /* p2p go mode */ + +/* Num dev Mask */ +#define HI_OPTION_NUM_DEV_MASK 0x7 +#define HI_OPTION_NUM_DEV_SHIFT 0x9 + +/* firmware bridging */ +#define HI_OPTION_FW_BRIDGE_SHIFT 0x04 + +/* Fw Mode/SubMode Mask + |-------------------------------------------------------------------------------| + | SUB | SUB | SUB | SUB | | | | | + | MODE[3] | MODE[2] | MODE[1] | MODE[0] | MODE[3] | MODE[2] | MODE[1] | MODE[0] | + | (2) | (2) | (2) | (2) | (2) | (2) | (2) | (2) | + |||-------------------------------------------------------------------------------| + */ +#define HI_OPTION_FW_MODE_BITS 0x2 +#define HI_OPTION_FW_MODE_MASK 0x3 +#define HI_OPTION_FW_MODE_SHIFT 0xC +#define HI_OPTION_ALL_FW_MODE_MASK 0xFF + +#define HI_OPTION_FW_SUBMODE_BITS 0x2 +#define HI_OPTION_FW_SUBMODE_MASK 0x3 +#define HI_OPTION_FW_SUBMODE_SHIFT 0x14 +#define HI_OPTION_ALL_FW_SUBMODE_MASK 0xFF00 +#define HI_OPTION_ALL_FW_SUBMODE_SHIFT 0x8 + +/* hi_option_flag2 options */ +#define HI_OPTION_OFFLOAD_AMSDU 0x01 +#define HI_OPTION_DFS_SUPPORT 0x02 /* Enable DFS support */ +#define HI_OPTION_ENABLE_RFKILL 0x04 /* RFKill Enable Feature */ +#define HI_OPTION_RADIO_RETENTION_DISABLE 0x08 /* Disable radio retention */ +#define HI_OPTION_EARLY_CFG_DONE 0x10 /* Early configuration is complete */ + +#define HI_OPTION_RF_KILL_SHIFT 0x2 +#define HI_OPTION_RF_KILL_MASK 0x1 + +#define HI_OPTION_HTT_TGT_DEBUG_TX_COMPL_IDX 0x20 + +#define HTT_TGT_DEBUG_TX_COMPL_IDX_VALUE() \ + ((HOST_INTEREST->hi_option_flag2 & HI_OPTION_HTT_TGT_DEBUG_TX_COMPL_IDX)) + +/* AR9888 1.0 only. Enable/disable CDC max perf support from host */ +#define HI_OPTION_DISABLE_CDC_MAX_PERF_WAR 0x20 +#define CDC_MAX_PERF_WAR_ENABLED() \ + (!(HOST_INTEREST->hi_option_flag2 & HI_OPTION_DISABLE_CDC_MAX_PERF_WAR)) +#define HI_OPTION_USE_EXT_LDO 0x40 /* use LDO27 for 1.1V instead of PMU. */ +#define HI_OPTION_DBUART_SUPPORT 0x80 /* Enable uart debug support */ +/* This bit is to enable BE low latency for some customers. + * The side effect is TCP DL will be 8Mbps decreased (673Mbps -> 665Mbps). + */ +#define HI_OPTION_BE_LATENCY_OPTIMIZE 0x100 +#define HT_OPTION_GPIO_WAKEUP_SUPPORT 0x200 /* GPIO wake up support */ +#define GPIO_WAKEUP_ENABLED() \ + (HOST_INTEREST->hi_option_flag2 & HT_OPTION_GPIO_WAKEUP_SUPPORT) + +/* hi_reset_flag */ +#define HI_RESET_FLAG_PRESERVE_APP_START 0x01 /* preserve App Start address */ +#define HI_RESET_FLAG_PRESERVE_HOST_INTEREST 0x02 /* preserve host interest */ +#define HI_RESET_FLAG_PRESERVE_ROMDATA 0x04 /* preserve ROM data */ +#define HI_RESET_FLAG_PRESERVE_NVRAM_STATE 0x08 +#define HI_RESET_FLAG_PRESERVE_BOOT_INFO 0x10 +#define HI_RESET_FLAG_WARM_RESET 0x20 + +/* define hi_fw_swap bits */ +#define HI_DESC_IN_FW_BIT 0x01 + +#define HI_RESET_FLAG_IS_VALID 0x12345678 /* indicate the reset flag is valid */ + +#define ON_RESET_FLAGS_VALID() \ + (HOST_INTEREST->hi_reset_flag_valid == HI_RESET_FLAG_IS_VALID) + +#define RESET_FLAGS_VALIDATE() \ + (HOST_INTEREST->hi_reset_flag_valid = HI_RESET_FLAG_IS_VALID) + +#define RESET_FLAGS_INVALIDATE() \ + (HOST_INTEREST->hi_reset_flag_valid = 0) + +#define ON_RESET_PRESERVE_APP_START() \ + (HOST_INTEREST->hi_reset_flag & HI_RESET_FLAG_PRESERVE_APP_START) + +#define ON_RESET_PRESERVE_NVRAM_STATE() \ + (HOST_INTEREST->hi_reset_flag & HI_RESET_FLAG_PRESERVE_NVRAM_STATE) + +#define ON_RESET_PRESERVE_HOST_INTEREST() \ + (HOST_INTEREST->hi_reset_flag & HI_RESET_FLAG_PRESERVE_HOST_INTEREST) + +#define ON_RESET_PRESERVE_ROMDATA() \ + (HOST_INTEREST->hi_reset_flag & HI_RESET_FLAG_PRESERVE_ROMDATA) + +#define ON_RESET_PRESERVE_BOOT_INFO() \ + (HOST_INTEREST->hi_reset_flag & HI_RESET_FLAG_PRESERVE_BOOT_INFO) + +#define ON_RESET_WARM_RESET() \ + (HOST_INTEREST->hi_reset_flag & HI_RESET_FLAG_WARM_RESET) + +/* host CPU endianness */ +#define HOST_ON_BE_CPU() \ + (HOST_INTEREST->hi_be) + +/* AP nart no swap descriptor flag. Decsriptors are created + * on the target processor. + */ +#define DESC_IN_FW() \ + (HOST_INTEREST->hi_fw_swap & HI_DESC_IN_FW_BIT) + + +/* redefine for hi_acs_flags since no product ever use it + * NOTE: + * This flag was only used in AR6004 for a customer project that has + * been canceled, we are reusing it to avoid extending the Host interest + * area. + * BIT Range Meaning + * --------- ---------------------------------- + * 0 HOST wants to swap MBOX usage + * 1 HOST supports HTT reduced tx completion + * 2 HOST supports HTT alternate credit size for data frames + * 15..3 reserved for HOST + * 16 FW set it before sending HTC_Ready to indicate MBOX swap is done + * 17 same as above but to indicate HTT reduced tx completion capability + * 31..18 reserved for FW + */ +/* HOST require to swap MBOX */ +#define HI_ACS_FLAGS_HOST_SWAP_MBOX (1 << 0) +/* HOST supports HTT reduced tx completion */ +#define HI_ACS_FLAGS_HOST_REDUCE_TX_COMPL (1 << 1) +/* HOST supports alternate credit size for data frames */ +#define HI_ACS_FLAGS_ALT_DATA_CREDIT_SIZE (1 << 2) +/* FW swapped MBOX */ +#define HI_ACS_FLAGS_FW_SWAPPED_MBOX (1 << 16) +/* FW support HTT reduced tx completion */ +#define HI_ACS_FLAGS_FW_REDUCE_TX_COMPL (1 << 17) + +/* CONSOLE FLAGS + * + * Bit Range Meaning + * --------- -------------------------------- + * 2..0 UART ID (0 = Default) + * 3 Baud Select (0 = 9600, 1 = 115200) + * 30..4 Reserved + * 31 Enable Console + * + * */ + +#define HI_CONSOLE_FLAGS_ENABLE (1 << 31) +#define HI_CONSOLE_FLAGS_UART_MASK (0x7) +#define HI_CONSOLE_FLAGS_UART_SHIFT 0 +#define HI_CONSOLE_FLAGS_BAUD_SELECT (1 << 3) + +/* SM power save options */ +#define HI_SMPS_ALLOW_MASK (0x00000001) +#define HI_SMPS_MODE_MASK (0x00000002) +#define HI_SMPS_MODE_STATIC (0x00000000) +#define HI_SMPS_MODE_DYNAMIC (0x00000002) +#define HI_SMPS_DISABLE_AUTO_MODE (0x00000004) +#define HI_SMPS_DATA_THRESH_MASK (0x000007f8) +#define HI_SMPS_DATA_THRESH_SHIFT (3) +#define HI_SMPS_RSSI_THRESH_MASK (0x0007f800) +#define HI_SMPS_RSSI_THRESH_SHIFT (11) +#define HI_SMPS_LOWPWR_CM_MASK (0x00380000) +#define HI_SMPS_LOWPWR_CM_SHIFT (15) +#define HI_SMPS_HIPWR_CM_MASK (0x03c00000) +#define HI_SMPS_HIPWR_CM_SHIFT (19) + +#define HOST_INTEREST_SMPS_GET_MODE() (HOST_INTEREST->hi_smps_options & HI_SMPS_MODE_MASK) +#define HOST_INTEREST_SMPS_GET_DATA_THRESH() ((HOST_INTEREST->hi_smps_options & HI_SMPS_DATA_THRESH_MASK) >> HI_SMPS_DATA_THRESH_SHIFT) +#define HOST_INTEREST_SMPS_SET_DATA_THRESH(x) (((x) << HI_SMPS_DATA_THRESH_SHIFT) & HI_SMPS_DATA_THRESH_MASK) +#define HOST_INTEREST_SMPS_GET_RSSI_THRESH() ((HOST_INTEREST->hi_smps_options & HI_SMPS_RSSI_THRESH_MASK) >> HI_SMPS_RSSI_THRESH_SHIFT) +#define HOST_INTEREST_SMPS_SET_RSSI_THRESH(x) (((x) << HI_SMPS_RSSI_THRESH_SHIFT) & HI_SMPS_RSSI_THRESH_MASK) +#define HOST_INTEREST_SMPS_SET_LOWPWR_CM() ((HOST_INTEREST->hi_smps_options & HI_SMPS_LOWPWR_CM_MASK) >> HI_SMPS_LOWPWR_CM_SHIFT) +#define HOST_INTEREST_SMPS_SET_HIPWR_CM() ((HOST_INTEREST->hi_smps_options << HI_SMPS_HIPWR_CM_MASK) & HI_SMPS_HIPWR_CM_SHIFT) +#define HOST_INTEREST_SMPS_IS_AUTO_MODE_DISABLED() (HOST_INTEREST->hi_smps_options & HI_SMPS_DISABLE_AUTO_MODE) + +/* WOW Extension configuration + * + * Bit Range Meaning + * --------- -------------------------------- + * 8..0 Size of each WOW pattern (max 511) + * 15..9 Number of patterns per list (max 127) + * 17..16 Number of lists (max 4) + * 30..18 Reserved + * 31 Enabled + * + * set values (except enable) to zeros for default settings + * + * */ + +#define HI_WOW_EXT_ENABLED_MASK (1 << 31) +#define HI_WOW_EXT_NUM_LIST_SHIFT 16 +#define HI_WOW_EXT_NUM_LIST_MASK (0x3 << HI_WOW_EXT_NUM_LIST_SHIFT) +#define HI_WOW_EXT_NUM_PATTERNS_SHIFT 9 +#define HI_WOW_EXT_NUM_PATTERNS_MASK (0x7F << HI_WOW_EXT_NUM_PATTERNS_SHIFT) +#define HI_WOW_EXT_PATTERN_SIZE_SHIFT 0 +#define HI_WOW_EXT_PATTERN_SIZE_MASK (0x1FF << HI_WOW_EXT_PATTERN_SIZE_SHIFT) + +#define HI_WOW_EXT_MAKE_CONFIG(num_lists,count,size) \ + ((((num_lists) << HI_WOW_EXT_NUM_LIST_SHIFT) & HI_WOW_EXT_NUM_LIST_MASK) | \ + (((count) << HI_WOW_EXT_NUM_PATTERNS_SHIFT) & HI_WOW_EXT_NUM_PATTERNS_MASK) | \ + (((size) << HI_WOW_EXT_PATTERN_SIZE_SHIFT) & HI_WOW_EXT_PATTERN_SIZE_MASK)) + +#define HI_WOW_EXT_GET_NUM_LISTS(config) \ + (((config) & HI_WOW_EXT_NUM_LIST_MASK) >> HI_WOW_EXT_NUM_LIST_SHIFT) +#define HI_WOW_EXT_GET_NUM_PATTERNS(config) \ + (((config) & HI_WOW_EXT_NUM_PATTERNS_MASK) >> HI_WOW_EXT_NUM_PATTERNS_SHIFT) +#define HI_WOW_EXT_GET_PATTERN_SIZE(config) \ + (((config) & HI_WOW_EXT_PATTERN_SIZE_MASK) >> HI_WOW_EXT_PATTERN_SIZE_SHIFT) + +/* + * Early allocation configuration + * Support RAM bank configuration before BMI done and this eases the memory + * allocation at very early stage + * Bit Range Meaning + * --------- ---------------------------------- + * [0:3] number of bank assigned to be IRAM + * [4:15] reserved + * [16:31] magic number + * + * Note: + * 1. target firmware would check magic number and if it's a match, firmware + * would consider the bits[0:15] are valid and base on that to calculate + * the end of DRAM. Early allocation would be located at that area and + * may be reclaimed when necesary + * 2. if no magic number is found, early allocation would happen at "_end" + * symbol of ROM which is located before the app-data and might NOT be + * re-claimable. If this is adopted, link script should keep this in + * mind to avoid data corruption. + */ +#define HI_EARLY_ALLOC_MAGIC 0x6d8a +#define HI_EARLY_ALLOC_MAGIC_MASK 0xffff0000 +#define HI_EARLY_ALLOC_MAGIC_SHIFT 16 +#define HI_EARLY_ALLOC_IRAM_BANKS_MASK 0x0000000f +#define HI_EARLY_ALLOC_IRAM_BANKS_SHIFT 0 + +#define HI_EARLY_ALLOC_VALID() \ + ((((HOST_INTEREST->hi_early_alloc) & HI_EARLY_ALLOC_MAGIC_MASK) >> HI_EARLY_ALLOC_MAGIC_SHIFT) \ + == (HI_EARLY_ALLOC_MAGIC)) +#define HI_EARLY_ALLOC_GET_IRAM_BANKS() \ + (((HOST_INTEREST->hi_early_alloc) & HI_EARLY_ALLOC_IRAM_BANKS_MASK) >> HI_EARLY_ALLOC_IRAM_BANKS_SHIFT) + +/* + * Intended for use by Host software, this macro returns the Target RAM + * address of any item in the host_interest structure. + * Example: target_addr = AR6002_HOST_INTEREST_ITEM_ADDRESS(hi_board_data); + */ +#define AR6002_HOST_INTEREST_ITEM_ADDRESS(item) \ + (A_UINT32)((size_t)&((((struct host_interest_s *)(AR6002_HOST_INTEREST_ADDRESS))->item))) + +#define AR6003_HOST_INTEREST_ITEM_ADDRESS(item) \ + (A_UINT32)((size_t)&((((struct host_interest_s *)(AR6003_HOST_INTEREST_ADDRESS))->item))) + +#define AR6004_HOST_INTEREST_ITEM_ADDRESS(item) \ + (A_UINT32)((size_t)&((((struct host_interest_s *)(AR6004_HOST_INTEREST_ADDRESS))->item))) + +#define AR6006_HOST_INTEREST_ITEM_ADDRESS(item) \ + (A_UINT32)((size_t)&((((struct host_interest_s *)(AR6006_HOST_INTEREST_ADDRESS))->item))) + +#define AR9888_HOST_INTEREST_ITEM_ADDRESS(item) \ + (A_UINT32)((size_t)&((((struct host_interest_s *)(AR9888_HOST_INTEREST_ADDRESS))->item))) + +#define AR6320_HOST_INTEREST_ITEM_ADDRESS(item) \ + (A_UINT32)((size_t)&((((struct host_interest_s *)(AR6320_HOST_INTEREST_ADDRESS))->item))) + +#define AR900B_HOST_INTEREST_ITEM_ADDRESS(item) \ + (A_UINT32)((size_t)&((((struct host_interest_s *)(AR900B_HOST_INTEREST_ADDRESS))->item))) + +#define HOST_INTEREST_DBGLOG_IS_ENABLED() \ + (!(HOST_INTEREST->hi_option_flag & HI_OPTION_DISABLE_DBGLOG)) + +#define HOST_INTEREST_PKTLOG_IS_ENABLED() \ + ((HOST_INTEREST->hi_pktlog_num_buffers)) + +#define HOST_INTEREST_PROFILE_IS_ENABLED() \ + (HOST_INTEREST->hi_option_flag & HI_OPTION_ENABLE_PROFILE) + +#define LF_TIMER_STABILIZATION_IS_ENABLED() \ + (!(HOST_INTEREST->hi_option_flag & HI_OPTION_NO_LFT_STBL)) + +#define IS_AMSDU_OFFLAOD_ENABLED() \ + ((HOST_INTEREST->hi_option_flag2 & HI_OPTION_OFFLOAD_AMSDU)) + +#define HOST_INTEREST_DFS_IS_ENABLED() \ + ((HOST_INTEREST->hi_option_flag2 & HI_OPTION_DFS_SUPPORT)) + +#define HOST_INTEREST_EARLY_CFG_DONE() \ + ((HOST_INTEREST->hi_option_flag2 & HI_OPTION_EARLY_CFG_DONE)) + +/*power save flag bit definitions*/ +#define HI_PWR_SAVE_LPL_ENABLED 0x1 +/*b1-b3 reserved*/ +/*b4-b5 : dev0 LPL type : 0 - none + 1- Reduce Pwr Search + 2- Reduce Pwr Listen*/ +/*b6-b7 : dev1 LPL type and so on for Max 8 devices*/ +#define HI_PWR_SAVE_LPL_DEV0_LSB 4 +#define HI_PWR_SAVE_LPL_DEV_MASK 0x3 +/*power save related utility macros*/ +#define HI_LPL_ENABLED() \ + ((HOST_INTEREST->hi_pwr_save_flags & HI_PWR_SAVE_LPL_ENABLED)) +#define HI_DEV_LPL_TYPE_GET(_devix) \ + (HOST_INTEREST->hi_pwr_save_flags & \ + ((HI_PWR_SAVE_LPL_DEV_MASK) << \ + (HI_PWR_SAVE_LPL_DEV0_LSB + \ + (_devix)*2))) + +#define HOST_INTEREST_SMPS_IS_ALLOWED() \ + ((HOST_INTEREST->hi_smps_options & HI_SMPS_ALLOW_MASK)) + +/* Convert a Target virtual address into a Target physical address */ +#define AR6002_VTOP(vaddr) ((vaddr) & 0x001fffff) +#define AR6003_VTOP(vaddr) ((vaddr) & 0x001fffff) +#define AR6004_VTOP(vaddr) (vaddr) +#define AR6006_VTOP(vaddr) (vaddr) +#define AR9888_VTOP(vaddr) (vaddr) +#define AR6320_VTOP(vaddr) (vaddr) +#define AR900B_VTOP(vaddr) (vaddr) +#define TARG_VTOP(TargetType, vaddr) \ + (((TargetType) == TARGET_TYPE_AR6002) ? AR6002_VTOP(vaddr) : \ + (((TargetType) == TARGET_TYPE_AR6003) ? AR6003_VTOP(vaddr) : \ + (((TargetType) == TARGET_TYPE_AR6004) ? AR6004_VTOP(vaddr) : \ + (((TargetType) == TARGET_TYPE_AR6006) ? AR6006_VTOP(vaddr) : \ + (((TargetType) == TARGET_TYPE_AR9888) ? AR9888_VTOP(vaddr) : \ + (((TargetType) == TARGET_TYPE_AR6320) ? AR6320_VTOP(vaddr) : \ + (((TargetType) == TARGET_TYPE_AR900B) ? AR900B_VTOP(vaddr) : \ + 0))))))) + +#define HOST_INTEREST_ITEM_ADDRESS(TargetType, item) \ + (((TargetType) == TARGET_TYPE_AR6002) ? AR6002_HOST_INTEREST_ITEM_ADDRESS(item) : \ + (((TargetType) == TARGET_TYPE_AR6003) ? AR6003_HOST_INTEREST_ITEM_ADDRESS(item) : \ + (((TargetType) == TARGET_TYPE_AR6004) ? AR6004_HOST_INTEREST_ITEM_ADDRESS(item) : \ + (((TargetType) == TARGET_TYPE_AR6006) ? AR6006_HOST_INTEREST_ITEM_ADDRESS(item) : \ + (((TargetType) == TARGET_TYPE_AR9888) ? AR9888_HOST_INTEREST_ITEM_ADDRESS(item) : \ + (((TargetType) == TARGET_TYPE_AR6320) ? AR6320_HOST_INTEREST_ITEM_ADDRESS(item) : \ + (((TargetType) == TARGET_TYPE_AR900B) ? AR900B_HOST_INTEREST_ITEM_ADDRESS(item) : \ + 0))))))) + +#define AR6002_BOARD_DATA_SZ 768 +#define AR6002_BOARD_EXT_DATA_SZ 0 +#define AR6003_BOARD_DATA_SZ 1024 +/* Reserve 1024 bytes for extended board data */ +#if defined(AR6002_REV43) +#define AR6003_BOARD_EXT_DATA_SZ 1024 +#else +#define AR6003_BOARD_EXT_DATA_SZ 768 +#endif +#define AR6004_BOARD_DATA_SZ 7168 +#define AR6004_BOARD_EXT_DATA_SZ 0 +#define AR9888_BOARD_DATA_SZ 7168 +#define AR9888_BOARD_EXT_DATA_SZ 0 +#define AR6320_BOARD_DATA_SZ 8192 +#define AR6320_BOARD_EXT_DATA_SZ 0 +#define QCA9377_BOARD_DATA_SZ 8192 +#define QCA9377_BOARD_EXT_DATA_SZ 0 +#define AR900B_BOARD_DATA_SZ 7168 +#define AR900B_BOARD_EXT_DATA_SZ 0 + +#define AR6003_REV3_APP_START_OVERRIDE 0x946100 +#define AR6003_REV3_APP_LOAD_ADDRESS 0x545000 +#define AR6003_REV3_BOARD_EXT_DATA_ADDRESS 0x542330 +#define AR6003_REV3_DATASET_PATCH_ADDRESS 0x57FF74 +#define AR6003_REV3_RAM_RESERVE_SIZE 4096 + +#define AR6004_REV1_BOARD_DATA_ADDRESS 0x423900 +#define AR6004_REV1_RAM_RESERVE_SIZE 19456 +#define AR6004_REV1_DATASET_PATCH_ADDRESS 0x425294 + +#define AR6004_REV2_BOARD_DATA_ADDRESS 0x426400 +#define AR6004_REV2_RAM_RESERVE_SIZE 7168 +#define AR6004_REV2_DATASET_PATCH_ADDRESS 0x435294 + +#define AR6004_REV5_BOARD_DATA_ADDRESS 0x436400 +#define AR6004_REV5_RAM_RESERVE_SIZE 7168 +#define AR6004_REV5_DATASET_PATCH_ADDRESS 0x437860 + +/* Reserve 4K for OTA test script */ +#define AR6004_REV1_RAM_RESERVE_SIZE_FOR_TEST_SCRIPT 4096 +#define AR6004_REV1_TEST_SCRIPT_ADDRESS 0x422900 + +/* # of A_UINT32 entries in targregs, used by DIAG_FETCH_TARG_REGS */ +#define AR6003_FETCH_TARG_REGS_COUNT 64 +#define AR6004_FETCH_TARG_REGS_COUNT 64 +#define AR9888_FETCH_TARG_REGS_COUNT 64 +#define AR6320_FETCH_TARG_REGS_COUNT 64 +#define AR900B_FETCH_TARG_REGS_COUNT 64 + +#endif /* !__ASSEMBLER__ */ + +#ifndef ATH_TARGET +#include "athendpack.h" +#endif + +#endif /* __TARGADDRS_H__ */ diff --git a/drivers/staging/fw-api/fw/targcfg.h b/drivers/staging/fw-api/fw/targcfg.h new file mode 100755 index 0000000000000000000000000000000000000000..52a8d41eaf62812ad9a463c08fd0b3717f427abe --- /dev/null +++ b/drivers/staging/fw-api/fw/targcfg.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2013-2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef __TARGCFG_H__ +#define __TARGCFG_H__ + +#if defined(ATH_TARGET) +#include /* A_UINT32 */ +#else +#include /* A_UINT32 */ +#endif + +typedef struct _targcfg_t { + A_UINT32 num_vdev; + A_UINT32 num_peers; + A_UINT32 num_peer_ast; + A_UINT32 num_peer_keys; + A_UINT32 num_peer_tid; + A_UINT32 num_mcast_keys; + A_UINT32 num_tx; + A_UINT32 num_rx; + A_UINT32 num_mgmt_tx; + A_UINT32 num_mgmt_rx; + A_UINT32 tx_chain_mask; + A_UINT32 rx_chain_mask; + A_UINT32 override; /* Override target with the values supplied above */ +} targcfg_t; + +#endif /* __TARGCFG_H__ */ diff --git a/drivers/staging/fw-api/fw/wal_rx_desc.h b/drivers/staging/fw-api/fw/wal_rx_desc.h new file mode 100755 index 0000000000000000000000000000000000000000..cb4be58b9d9932ede2e9504ba5e792ad51388e23 --- /dev/null +++ b/drivers/staging/fw-api/fw/wal_rx_desc.h @@ -0,0 +1,243 @@ +/* + * Copyright (c) 2011-2012, 2014, 2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef _WAL_RX_DESC__H_ +#define _WAL_RX_DESC__H_ + +#if defined(ATH_TARGET) +#include /* A_UINT8 */ +#else +#include /* A_UINT8 */ +#endif + +/* + * As this header is used by host also, + * and host will access target registers by target reg tbl, + * so disable direct-reference here for host. + * + */ +#if !defined(ATH_PERF_PWR_OFFLOAD) +#if defined(CONFIG_AR900B_SUPPORT) || defined(AR900B) +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#else +/* HW rx descriptor definitions */ +#include +#include +#include +#include +#include +#include +#include +#include +#endif +/* + * This struct defines the basic descriptor information, which is + * written by the 11ac HW MAC into the WAL's rx status descriptor + * ring. + */ +struct hw_rx_desc_base { + struct rx_attention attention; + struct rx_frag_info frag_info; + struct rx_mpdu_start mpdu_start; + struct rx_msdu_start msdu_start; + struct rx_msdu_end msdu_end; + struct rx_mpdu_end mpdu_end; + struct rx_ppdu_start ppdu_start; + struct rx_ppdu_end ppdu_end; +}; +#endif + +#define FW_MSDU_INFO_FIRST_WAKEUP_M 0x40 +#define FW_MSDU_INFO_FIRST_WAKEUP_S 6 + +/* + * This struct defines the basic MSDU rx descriptor created by FW. + */ +struct fw_rx_desc_base { + union { + struct { + A_UINT8 discard:1, + forward:1, + any_err:1, + dup_err:1, + ipa_ind:1, + inspect:1, + extension:2; + } bits; + A_UINT8 val; + } u; +}; + +#define FW_RX_DESC_DISCARD_M 0x1 +#define FW_RX_DESC_DISCARD_S 0 +#define FW_RX_DESC_FORWARD_M 0x2 +#define FW_RX_DESC_FORWARD_S 1 +#define FW_RX_DESC_ANY_ERR_M 0x4 +#define FW_RX_DESC_ANY_ERR_S 2 +#define FW_RX_DESC_DUP_ERR_M 0x8 +#define FW_RX_DESC_DUP_ERR_S 3 +#define FW_RX_DESC_INSPECT_M 0x20 +#define FW_RX_DESC_INSPECT_S 5 +#define FW_RX_DESC_EXT_M 0xc0 +#define FW_RX_DESC_EXT_S 6 + +#define FW_RX_DESC_CNT_2_BYTES(_fw_desc_cnt) (_fw_desc_cnt) + +enum { + FW_RX_DESC_EXT_NONE = 0, + FW_RX_DESC_EXT_LRO_ONLY, + FW_RX_DESC_EXT_LRO_AND_OTHER, + FW_RX_DESC_EXT_OTHER +}; + +#define FW_RX_DESC_DISCARD_GET(_var) \ + (((_var) & FW_RX_DESC_DISCARD_M) >> FW_RX_DESC_DISCARD_S) +#define FW_RX_DESC_DISCARD_SET(_var, _val) \ + ((_var) |= ((_val) << FW_RX_DESC_DISCARD_S)) + +#define FW_RX_DESC_FORWARD_GET(_var) \ + (((_var) & FW_RX_DESC_FORWARD_M) >> FW_RX_DESC_FORWARD_S) +#define FW_RX_DESC_FORWARD_SET(_var, _val) \ + ((_var) |= ((_val) << FW_RX_DESC_FORWARD_S)) + +#define FW_RX_DESC_INSPECT_GET(_var) \ + (((_var) & FW_RX_DESC_INSPECT_M) >> FW_RX_DESC_INSPECT_S) +#define FW_RX_DESC_INSPECT_SET(_var, _val) \ + ((_var) |= ((_val) << FW_RX_DESC_INSPECT_S)) + +#define FW_RX_DESC_EXT_GET(_var) \ + (((_var) & FW_RX_DESC_EXT_M) >> FW_RX_DESC_EXT_S) +#define FW_RX_DESC_EXT_SET(_var, _val) \ + ((_var) |= ((_val) << FW_RX_DESC_EXT_S)) + +/* + * This struct defines TCP_CHKSUM_OFFLOAD bit fields which are needed by host. + */ +struct fw_rx_msdu_info { + union { + /* + * The "bits" struct defines the flags in fw_rx_msdu_info used + * during regular operation. + */ + struct { + A_UINT8 tcp_udp_chksum_fail:1, /* for tcp checksum offload use */ + ip_chksum_fail:1, + ipv6_proto:1, + tcp_proto:1, + udp_proto:1, + ip_frag:1, + first_wakeup:1, + reserved:1; + } bits; + /* + * The "mon" struct defines the flags in fw_rx_msdu_info used + * during monitor mode. + */ + struct { + A_UINT8 last_frag:1, + reserved:7; + } mon; + A_UINT8 val; + } u; +}; + +/* regular operation flags */ + +#define FW_RX_MSDU_INFO_TCP_UDP_CHKSUM_FAIL_M 0x1 +#define FW_RX_MSDU_INFO_TCP_UDP_CHKSUM_FAIL_S 0 +#define FW_RX_MSDU_INFO_IP_CHKSUM_FAIL_M 0x2 +#define FW_RX_MSDU_INFO_IP_CHKSUM_FAIL_S 1 +#define FW_RX_MSDU_INFO_IPV6_PROTO_M 0x4 +#define FW_RX_MSDU_INFO_IPV6_PROTO_S 2 +#define FW_RX_MSDU_INFO_TCP_PROTO_M 0x8 +#define FW_RX_MSDU_INFO_TCP_PROTO_S 3 +#define FW_RX_MSDU_INFO_UDP_PROTO_M 0x10 +#define FW_RX_MSDU_INFO_UDP_PROTO_S 4 +#define FW_RX_MSDU_INFO_IP_FRAG_M 0x20 +#define FW_RX_MSDU_INFO_IP_FRAG_S 5 +#define FW_RX_MSDU_INFO_FIRST_WAKEUP_M 0x40 +#define FW_RX_MSDU_INFO_FIRST_WAKEUP_S 6 + +#define FW_RX_MSDU_INFO_TCP_UDP_CHKSUM_FAIL_GET(_var) \ + (((_var) & FW_RX_MSDU_INFO_TCP_UDP_CHKSUM_FAIL_M) >> FW_RX_MSDU_INFO_TCP_UDP_CHKSUM_FAIL_S) +#define FW_RX_MSDU_INFO_TCP_UDP_CHKSUM_FAIL_SET(_var, _val) \ + ((_var) |= ((_val) << FW_RX_MSDU_INFO_TCP_UDP_CHKSUM_FAIL_S)) + +#define FW_RX_MSDU_INFO_IP_CHKSUM_FAIL_GET(_var) \ + (((_var) & FW_RX_MSDU_INFO_IP_CHKSUM_FAIL_M) >> FW_RX_MSDU_INFO_IP_CHKSUM_FAIL_S) +#define FW_RX_MSDU_INFO_IP_CHKSUM_FAIL_SET(_var, _val) \ + ((_var) |= ((_val) << FW_RX_MSDU_INFO_IP_CHKSUM_FAIL_S)) + +#define FW_RX_MSDU_INFO_IPV6_PROTO_GET(_var) \ + (((_var) & FW_RX_MSDU_INFO_IPV6_PROTO_M) >> FW_RX_MSDU_INFO_IPV6_PROTO_S) +#define FW_RX_MSDU_INFO_IPV6_PROTO_SET(_var, _val) \ + ((_var) |= ((_val) << FW_RX_MSDU_INFO_IPV6_PROTO_S)) + +#define FW_RX_MSDU_INFO_TCP_PROTO_GET(_var) \ + (((_var) & FW_RX_MSDU_INFO_TCP_PROTO_M) >> FW_RX_MSDU_INFO_TCP_PROTO_S) +#define FW_RX_MSDU_INFO_TCP_PROTO_SET(_var, _val) \ + ((_var) |= ((_val) << FW_RX_MSDU_INFO_TCP_PROTO_S)) + +#define FW_RX_MSDU_INFO_UDP_PROTO_GET(_var) \ + (((_var) & FW_RX_MSDU_INFO_UDP_PROTO_M) >> FW_RX_MSDU_INFO_UDP_PROTO_S) +#define FW_RX_MSDU_INFO_UDP_PROTO_SET(_var, _val) \ + ((_var) |= ((_val) << FW_RX_MSDU_INFO_UDP_PROTO_S)) + +#define FW_RX_MSDU_INFO_IP_FRAG_GET(_var) \ + (((_var) & FW_RX_MSDU_INFO_IP_FRAG_M) >> FW_RX_MSDU_INFO_IP_FRAG_S) +#define FW_RX_MSDU_INFO_IP_FRAG_SET(_var, _val) \ + ((_var) |= ((_val) << FW_RX_MSDU_INFO_IP_FRAG_S)) + +#define FW_RX_MSDU_INFO_FIRST_WAKEUP_GET(_var) \ + (((_var) & FW_RX_MSDU_INFO_FIRST_WAKEUP_M) >> FW_RX_MSDU_INFO_FIRST_WAKEUP_S) +#define FW_RX_MSDU_INFO_FIRST_WAKEUP_SET(_var, _val) \ + ((_var) |= ((_val) << FW_RX_MSDU_INFO_FIRST_WAKEUP_S)) + + +/* monitor mode flags */ + +#define FW_RX_MSDU_INFO_MON_LAST_FRAG_M 0x1 +#define FW_RX_MSDU_INFO_MON_LAST_FRAG_S 0 + + +#define FW_RX_MSDU_INFO_MON_LAST_FRAG_GET(_var) \ + (((_var) & FW_RX_MSDU_INFO_MON_LAST_FRAG_M) >> FW_RX_MSDU_INFO_MON_LAST_FRAG_S) +#define FW_RX_MSDU_INFO_MON_LAST_FRAG_SET(_var, _val) \ + ((_var) |= ((_val) << FW_RX_MSDU_INFO_MON_LAST_FRAG_S)) +#endif /* _WAL_RX_DESC__H_ */ diff --git a/drivers/staging/fw-api/fw/wlan_defs.h b/drivers/staging/fw-api/fw/wlan_defs.h new file mode 100755 index 0000000000000000000000000000000000000000..d627c2a9d616591b23ab00c076ebbf606d68078e --- /dev/null +++ b/drivers/staging/fw-api/fw/wlan_defs.h @@ -0,0 +1,913 @@ +/* + * Copyright (c) 2013-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ +#ifndef __WLAN_DEFS_H__ +#define __WLAN_DEFS_H__ + +#include /* A_COMPILE_TIME_ASSERT */ + +/* + * This file contains WLAN definitions that may be used across both + * Host and Target software. + */ + + +/* + * MAX_SPATIAL_STREAM should be defined in a fwconfig_xxx.h file, + * but for now provide a default value here in case it's not defined + * in the fwconfig_xxx.h file. + */ +#ifndef MAX_SPATIAL_STREAM +#define MAX_SPATIAL_STREAM 3 +#endif + +#ifndef CONFIG_160MHZ_SUPPORT +#define CONFIG_160MHZ_SUPPORT 0 /* default: 160 MHz channels not supported */ +#endif + +#ifndef SUPPORT_11AX +#define SUPPORT_11AX 0 /* 11ax not supported by default */ +#endif + +/* + * MAX_SPATIAL_STREAM_ANY - + * what is the largest number of spatial streams that any target supports + */ +#define MAX_SPATIAL_STREAM_ANY_V2 4 /* pre-hawkeye */ +#define MAX_SPATIAL_STREAM_ANY_V3 8 /* includes hawkeye */ +/* + * (temporarily) leave the old MAX_SPATIAL_STREAM_ANY name in place as an alias, + * and in case some old code is using it + */ +#define MAX_SPATIAL_STREAM_ANY MAX_SPATIAL_STREAM_ANY_V2 /* DEPRECATED */ + +/* defines to set Packet extension values whic can be 0 us, 8 usec or 16 usec */ +/* NOTE: Below values cannot be changed without breaking WMI Compatibility */ +#define MAX_HE_NSS 8 +#define MAX_HE_MODULATION 8 +#define MAX_HE_RU 4 +#define HE_MODULATION_NONE 7 +#define HE_PET_0_USEC 0 +#define HE_PET_8_USEC 1 +#define HE_PET_16_USEC 2 + +typedef enum { + MODE_11A = 0, /* 11a Mode */ + MODE_11G = 1, /* 11b/g Mode */ + MODE_11B = 2, /* 11b Mode */ + MODE_11GONLY = 3, /* 11g only Mode */ + MODE_11NA_HT20 = 4, /* 11a HT20 mode */ + MODE_11NG_HT20 = 5, /* 11g HT20 mode */ + MODE_11NA_HT40 = 6, /* 11a HT40 mode */ + MODE_11NG_HT40 = 7, /* 11g HT40 mode */ + MODE_11AC_VHT20 = 8, + MODE_11AC_VHT40 = 9, + MODE_11AC_VHT80 = 10, + MODE_11AC_VHT20_2G = 11, + MODE_11AC_VHT40_2G = 12, + MODE_11AC_VHT80_2G = 13, +#if CONFIG_160MHZ_SUPPORT + MODE_11AC_VHT80_80 = 14, + MODE_11AC_VHT160 = 15, +#endif + +#if SUPPORT_11AX + MODE_11AX_HE20 = 16, + MODE_11AX_HE40 = 17, + MODE_11AX_HE80 = 18, + MODE_11AX_HE80_80 = 19, + MODE_11AX_HE160 = 20, + MODE_11AX_HE20_2G = 21, + MODE_11AX_HE40_2G = 22, + MODE_11AX_HE80_2G = 23, +#endif + + /* + * MODE_UNKNOWN should not be used within the host / target interface. + * Thus, it is permissible for ODE_UNKNOWN to be conditionally-defined, + * taking different values when compiling for different targets. + */ + MODE_UNKNOWN, + MODE_UNKNOWN_NO_160MHZ_SUPPORT = 14, /* not needed? */ +#if 0 + MODE_UNKNOWN_NO_11AX_SUPPORT = 16, /* not needed? */ + MODE_UNKNOWN_11AX_SUPPORT = 24, /* not needed? */ +#endif + MODE_UNKNOWN_160MHZ_SUPPORT = MODE_UNKNOWN, /* not needed? */ + +#ifdef ATHR_WIN_NWF + PHY_MODE_MAX = MODE_UNKNOWN, + PHY_MODE_MAX_NO_160_MHZ_SUPPORT = MODE_UNKNOWN_NO_160MHZ_SUPPORT, + PHY_MODE_MAX_160_MHZ_SUPPORT = MODE_UNKNOWN_160MHZ_SUPPORT, +#else + MODE_MAX = MODE_UNKNOWN, + MODE_MAX_NO_160_MHZ_SUPPORT = MODE_UNKNOWN_NO_160MHZ_SUPPORT, + MODE_MAX_160_MHZ_SUPPORT = MODE_UNKNOWN_160MHZ_SUPPORT, +#endif +} WLAN_PHY_MODE; + +#if CONFIG_160MHZ_SUPPORT == 0 +A_COMPILE_TIME_ASSERT( + mode_unknown_value_consistency_Check, + MODE_UNKNOWN == MODE_UNKNOWN_NO_160MHZ_SUPPORT); +#else +A_COMPILE_TIME_ASSERT( + mode_unknown_value_consistency_Check, + MODE_UNKNOWN == MODE_UNKNOWN_160MHZ_SUPPORT); +#endif + +typedef enum { + VHT_MODE_NONE = 0, /* NON VHT Mode, e.g., HT, DSSS, CCK */ + VHT_MODE_20M = 1, + VHT_MODE_40M = 2, + VHT_MODE_80M = 3, + VHT_MODE_160M = 4 +} VHT_OPER_MODE; + +typedef enum { + WLAN_11A_CAPABILITY = 1, + WLAN_11G_CAPABILITY = 2, + WLAN_11AG_CAPABILITY = 3, +} WLAN_CAPABILITY; + +#if CONFIG_160MHZ_SUPPORT +#define IS_MODE_VHT(mode) (((mode) == MODE_11AC_VHT20) || \ + ((mode) == MODE_11AC_VHT40) || \ + ((mode) == MODE_11AC_VHT80) || \ + ((mode) == MODE_11AC_VHT80_80) || \ + ((mode) == MODE_11AC_VHT160)) +#else +#define IS_MODE_VHT(mode) (((mode) == MODE_11AC_VHT20) || \ + ((mode) == MODE_11AC_VHT40) || \ + ((mode) == MODE_11AC_VHT80)) +#endif + +#define IS_MODE_HE(mode) (((mode) == MODE_11AX_HE20) || \ + ((mode) == MODE_11AX_HE40) || \ + ((mode) == MODE_11AX_HE80) || \ + ((mode) == MODE_11AX_HE80_80) || \ + ((mode) == MODE_11AX_HE160) || \ + ((mode) == MODE_11AX_HE20_2G) || \ + ((mode) == MODE_11AX_HE40_2G) || \ + ((mode) == MODE_11AX_HE80_2G)) + +#define IS_MODE_VHT_2G(mode) (((mode) == MODE_11AC_VHT20_2G) || \ + ((mode) == MODE_11AC_VHT40_2G) || \ + ((mode) == MODE_11AC_VHT80_2G)) + + +#define IS_MODE_11A(mode) (((mode) == MODE_11A) || \ + ((mode) == MODE_11NA_HT20) || \ + ((mode) == MODE_11NA_HT40) || \ + (IS_MODE_VHT(mode))) + +#define IS_MODE_11B(mode) ((mode) == MODE_11B) +#define IS_MODE_11G(mode) (((mode) == MODE_11G) || \ + ((mode) == MODE_11GONLY) || \ + ((mode) == MODE_11NG_HT20) || \ + ((mode) == MODE_11NG_HT40) || \ + (IS_MODE_VHT_2G(mode))) +#define IS_MODE_11GN(mode) (((mode) == MODE_11NG_HT20) || \ + ((mode) == MODE_11NG_HT40)) +#define IS_MODE_11GONLY(mode) ((mode) == MODE_11GONLY) + + +enum { + REGDMN_MODE_11A = 0x00000001, /* 11a channels */ + REGDMN_MODE_TURBO = 0x00000002, /* 11a turbo-only channels */ + REGDMN_MODE_11B = 0x00000004, /* 11b channels */ + REGDMN_MODE_PUREG = 0x00000008, /* 11g channels (OFDM only) */ + REGDMN_MODE_11G = 0x00000008, /* XXX historical */ + REGDMN_MODE_108G = 0x00000020, /* 11g+Turbo channels */ + REGDMN_MODE_108A = 0x00000040, /* 11a+Turbo channels */ + REGDMN_MODE_XR = 0x00000100, /* XR channels */ + REGDMN_MODE_11A_HALF_RATE = 0x00000200, /* 11A half rate channels */ + REGDMN_MODE_11A_QUARTER_RATE = 0x00000400, /* 11A quarter rate channels */ + REGDMN_MODE_11NG_HT20 = 0x00000800, /* 11N-G HT20 channels */ + REGDMN_MODE_11NA_HT20 = 0x00001000, /* 11N-A HT20 channels */ + REGDMN_MODE_11NG_HT40PLUS = 0x00002000, /* 11N-G HT40 + channels */ + REGDMN_MODE_11NG_HT40MINUS = 0x00004000, /* 11N-G HT40 - channels */ + REGDMN_MODE_11NA_HT40PLUS = 0x00008000, /* 11N-A HT40 + channels */ + REGDMN_MODE_11NA_HT40MINUS = 0x00010000, /* 11N-A HT40 - channels */ + REGDMN_MODE_11AC_VHT20 = 0x00020000, /* 5Ghz, VHT20 */ + REGDMN_MODE_11AC_VHT40PLUS = 0x00040000, /* 5Ghz, VHT40 + channels */ + REGDMN_MODE_11AC_VHT40MINUS = 0x00080000, /* 5Ghz VHT40 - channels */ + REGDMN_MODE_11AC_VHT80 = 0x000100000, /* 5Ghz, VHT80 channels */ + REGDMN_MODE_11AC_VHT20_2G = 0x000200000, /* 2Ghz, VHT20 */ + REGDMN_MODE_11AC_VHT40_2G = 0x000400000, /* 2Ghz, VHT40 */ + REGDMN_MODE_11AC_VHT80_2G = 0x000800000, /* 2Ghz, VHT80 */ + REGDMN_MODE_11AC_VHT160 = 0x001000000, /* 5Ghz, VHT160 */ + REGDMN_MODE_11AC_VHT40_2GPLUS = 0x002000000, /* 2Ghz, VHT40+ */ + REGDMN_MODE_11AC_VHT40_2GMINUS = 0x004000000, /* 2Ghz, VHT40- */ + REGDMN_MODE_11AC_VHT80_80 = 0x008000000, /* 5GHz, VHT80+80 */ +}; + +#define REGDMN_MODE_ALL (0xFFFFFFFF) /* REGDMN_MODE_ALL is defined out of the enum + * to prevent the ARM compile "warning #66: + * enumeration value is out of int range" + * Anyway, this is a BIT-OR of all possible values. + */ + +#define REGDMN_CAP1_CHAN_HALF_RATE 0x00000001 +#define REGDMN_CAP1_CHAN_QUARTER_RATE 0x00000002 +#define REGDMN_CAP1_CHAN_HAL49GHZ 0x00000004 + + +/* regulatory capabilities */ +#define REGDMN_EEPROM_EEREGCAP_EN_FCC_MIDBAND 0x0040 +#define REGDMN_EEPROM_EEREGCAP_EN_KK_U1_EVEN 0x0080 +#define REGDMN_EEPROM_EEREGCAP_EN_KK_U2 0x0100 +#define REGDMN_EEPROM_EEREGCAP_EN_KK_MIDBAND 0x0200 +#define REGDMN_EEPROM_EEREGCAP_EN_KK_U1_ODD 0x0400 +#define REGDMN_EEPROM_EEREGCAP_EN_KK_NEW_11A 0x0800 + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMI_TLVTAG_STRUC_HAL_REG_CAPABILITIES */ + A_UINT32 eeprom_rd; /* regdomain value specified in EEPROM */ + A_UINT32 eeprom_rd_ext; /* regdomain */ + A_UINT32 regcap1; /* CAP1 capabilities bit map. */ + A_UINT32 regcap2; /* REGDMN EEPROM CAP. */ + A_UINT32 wireless_modes; /* REGDMN MODE */ + A_UINT32 low_2ghz_chan; + A_UINT32 high_2ghz_chan; + A_UINT32 low_5ghz_chan; + A_UINT32 high_5ghz_chan; +} HAL_REG_CAPABILITIES; + +#ifdef NUM_SPATIAL_STREAM +/* + * The rate control definitions below are only used in the target. + * (Host-based rate control is no longer applicable.) + * Maintain the defs in wlanfw_cmn for the sake of existing Rome / Helium + * targets, but for Lithium targets remove them from wlanfw_cmn and define + * them in a target-only location instead. + * SUPPORT_11AX is essentially used as a condition to identify Lithium targets. + * Some host drivers would also have SUPPORT_11AX defined, and thus would lose + * the definition of RATE_CODE, RC_TX_DONE_PARAMS, and related macros, but + * that's okay because the host should have no references to these + * target-only data structures. + */ +#if !((NUM_SPATIAL_STREAM > 4) || SUPPORT_11AX) /* following N/A for Lithium */ + +/* + * Used to update rate-control logic with the status of the tx-completion. + * In host-based implementation of the rate-control feature, this struture is used to + * create the payload for HTT message/s from target to host. + */ + +#if (NUM_SPATIAL_STREAM > 3) + #define A_RATEMASK A_UINT64 +#else + #define A_RATEMASK A_UINT32 +#endif + +typedef A_UINT8 A_RATE; +typedef A_UINT8 A_RATECODE; + +#define A_RATEMASK_NUM_OCTET (sizeof (A_RATEMASK)) +#define A_RATEMASK_NUM_BITS ((sizeof (A_RATEMASK)) << 3) + +typedef struct { + A_RATECODE rateCode; + A_UINT8 flags; +} RATE_CODE; + +typedef struct { + RATE_CODE ptx_rc; /* rate code, bw, chain mask sgi */ + A_UINT8 reserved[2]; + A_UINT32 flags; /* Encodes information such as excessive + retransmission, aggregate, some info + from .11 frame control, + STBC, LDPC, (SGI and Tx Chain Mask + are encoded in ptx_rc->flags field), + AMPDU truncation (BT/time based etc.), + RTS/CTS attempt */ + A_UINT32 num_enqued; /* # of MPDUs (for non-AMPDU 1) for this rate */ + A_UINT32 num_retries; /* Total # of transmission attempt for this rate */ + A_UINT32 num_failed; /* # of failed MPDUs in A-MPDU, 0 otherwise */ + A_UINT32 ack_rssi; /* ACK RSSI: b'7..b'0 avg RSSI across all chain */ + A_UINT32 time_stamp ; /* ACK timestamp (helps determine age) */ + A_UINT32 is_probe; /* Valid if probing. Else, 0 */ + A_UINT32 ba_win_size; /* b'7..b0, block Ack Window size, b'31..b8 Resvd */ + A_UINT32 failed_ba_bmap_0_31; /* failed BA bitmap 0..31 */ + A_UINT32 failed_ba_bmap_32_63; /* failed BA bitmap 32..63 */ + A_UINT32 bmap_tried_0_31; /* enqued bitmap 0..31 */ + A_UINT32 bmap_tried_32_63; /* enqued bitmap 32..63 */ +} RC_TX_DONE_PARAMS; + + +#define RC_SET_TX_DONE_INFO(_dst, _rc, _f, _nq, _nr, _nf, _rssi, _ts) \ + do { \ + (_dst).ptx_rc.rateCode = (_rc).rateCode; \ + (_dst).ptx_rc.flags = (_rc).flags; \ + (_dst).flags = (_f); \ + (_dst).num_enqued = (_nq); \ + (_dst).num_retries = (_nr); \ + (_dst).num_failed = (_nf); \ + (_dst).ack_rssi = (_rssi); \ + (_dst).time_stamp = (_ts); \ + } while (0) + +#define RC_SET_TXBF_DONE_INFO(_dst, _f) \ + do { \ + (_dst).flags |= (_f); \ + } while (0) + +#endif /* !((NUM_SPATIAL_STREAM > 4) || SUPPORT_11AX) */ /* above N/A for Lithium */ +#endif /* NUM_SPATIAL_STREAM */ + +/* NOTE: NUM_DYN_BW and NUM_SCHED_ENTRIES cannot be changed without breaking WMI Compatibility */ +#define NUM_SCHED_ENTRIES 2 +#define NUM_DYN_BW_MAX 4 + +/* Some products only use 20/40/80; some use 20/40/80/160 */ +#ifndef NUM_DYN_BW +#define NUM_DYN_BW 3 /* default: support up through 80 MHz */ +#endif + +#define NUM_DYN_BW_MASK 0x3 + +#define PROD_SCHED_BW_ENTRIES (NUM_SCHED_ENTRIES * NUM_DYN_BW) + +#if NUM_DYN_BW > 4 +/* Extend rate table module first */ +#error "Extend rate table module first" +#endif + +#define MAX_IBSS_PEERS 32 + +#ifdef NUM_SPATIAL_STREAM +/* + * RC_TX_RATE_SCHEDULE and RC_TX_RATE_INFO defs are used only in the target. + * (Host-based rate control is no longer applicable.) + * Maintain the defs in wlanfw_cmn for the sake of existing Rome / Helium + * targets, but for Lithium targets remove them from wlanfw_cmn and define + * them in a target-only location instead. + * SUPPORT_11AX is essentially used as a condition to identify Lithium targets. + * Some host drivers would also have SUPPORT_11AX defined, and thus would lose + * the definition of RC_TX_RATE_SCHEDULE and RC_TX_RATE_INFO, but that's okay + * because the host should have no references to these target-only data + * structures. + */ +#if !((NUM_SPATIAL_STREAM > 4) || SUPPORT_11AX) + #if defined(CONFIG_AR900B_SUPPORT) || defined(AR900B) + typedef struct{ + A_UINT32 psdu_len[NUM_DYN_BW * NUM_SCHED_ENTRIES]; + A_UINT16 flags[NUM_SCHED_ENTRIES][NUM_DYN_BW]; + A_RATE rix[NUM_SCHED_ENTRIES][NUM_DYN_BW]; + A_UINT8 tpc[NUM_SCHED_ENTRIES][NUM_DYN_BW]; + A_UINT32 antmask[NUM_SCHED_ENTRIES]; + A_UINT8 num_mpdus[NUM_DYN_BW * NUM_SCHED_ENTRIES]; + A_UINT16 txbf_cv_len; + A_UINT32 txbf_cv_ptr; + A_UINT16 txbf_flags; + A_UINT16 txbf_cv_size; + A_UINT8 txbf_nc_idx; + A_UINT8 tries[NUM_SCHED_ENTRIES]; + A_UINT8 bw_mask[NUM_SCHED_ENTRIES]; + A_UINT8 max_bw[NUM_SCHED_ENTRIES]; + A_UINT8 num_sched_entries; + A_UINT8 paprd_mask; + A_RATE rts_rix; + A_UINT8 sh_pream; + A_UINT8 min_spacing_1_4_us; + A_UINT8 fixed_delims; + A_UINT8 bw_in_service; + A_RATE probe_rix; + A_UINT8 num_valid_rates; + A_UINT8 rtscts_tpc; + A_UINT8 dd_profile; + } RC_TX_RATE_SCHEDULE; + #else + typedef struct{ + A_UINT32 psdu_len[NUM_DYN_BW * NUM_SCHED_ENTRIES]; + A_UINT16 flags[NUM_DYN_BW * NUM_SCHED_ENTRIES]; + A_RATE rix[NUM_DYN_BW * NUM_SCHED_ENTRIES]; + A_UINT8 tpc[NUM_DYN_BW * NUM_SCHED_ENTRIES]; + A_UINT8 num_mpdus[NUM_DYN_BW * NUM_SCHED_ENTRIES]; + A_UINT32 antmask[NUM_SCHED_ENTRIES]; + A_UINT32 txbf_cv_ptr; + A_UINT16 txbf_cv_len; + A_UINT8 tries[NUM_SCHED_ENTRIES]; + A_UINT8 num_valid_rates; + A_UINT8 paprd_mask; + A_RATE rts_rix; + A_UINT8 sh_pream; + A_UINT8 min_spacing_1_4_us; + A_UINT8 fixed_delims; + A_UINT8 bw_in_service; + A_RATE probe_rix; + } RC_TX_RATE_SCHEDULE; + #endif + + typedef struct{ + A_UINT16 flags[NUM_DYN_BW * NUM_SCHED_ENTRIES]; + A_RATE rix[NUM_DYN_BW * NUM_SCHED_ENTRIES]; + #ifdef DYN_TPC_ENABLE + A_UINT8 tpc[NUM_DYN_BW * NUM_SCHED_ENTRIES]; + #endif + #ifdef SECTORED_ANTENNA + A_UINT32 antmask[NUM_SCHED_ENTRIES]; + #endif + A_UINT8 tries[NUM_SCHED_ENTRIES]; + A_UINT8 num_valid_rates; + A_RATE rts_rix; + A_UINT8 sh_pream; + A_UINT8 bw_in_service; + A_RATE probe_rix; + A_UINT8 dd_profile; + } RC_TX_RATE_INFO; +#endif /* !((NUM_SPATIAL_STREAM > 4) || SUPPORT_11AX) */ +#endif + +/* + * Temporarily continue to provide the WHAL_RC_INIT_RC_MASKS def in wlan_defs.h + * for older targets. + * The WHAL_RX_INIT_RC_MASKS macro def needs to be moved into ratectrl_11ac.h + * for all targets, but until this is complete, the WHAL_RC_INIT_RC_MASKS def + * will be maintained here in its old location. + */ +#if CONFIG_160MHZ_SUPPORT == 0 +#define WHAL_RC_INIT_RC_MASKS(_rm) do { \ + _rm[WHAL_RC_MASK_IDX_NON_HT] = A_RATEMASK_OFDM_CCK; \ + _rm[WHAL_RC_MASK_IDX_HT_20] = A_RATEMASK_HT_20; \ + _rm[WHAL_RC_MASK_IDX_HT_40] = A_RATEMASK_HT_40; \ + _rm[WHAL_RC_MASK_IDX_VHT_20] = A_RATEMASK_VHT_20; \ + _rm[WHAL_RC_MASK_IDX_VHT_40] = A_RATEMASK_VHT_40; \ + _rm[WHAL_RC_MASK_IDX_VHT_80] = A_RATEMASK_VHT_80; \ + } while (0) +#endif + +/** + * strucutre describing host memory chunk. + */ +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wlan_host_memory_chunk */ + /** id of the request that is passed up in service ready */ + A_UINT32 req_id; + /** the physical address the memory chunk */ + A_UINT32 ptr; + /** size of the chunk */ + A_UINT32 size; +} wlan_host_memory_chunk; + +#define NUM_UNITS_IS_NUM_VDEVS 0x1 +#define NUM_UNITS_IS_NUM_PEERS 0x2 +#define NUM_UNITS_IS_NUM_ACTIVE_PEERS 0x4 +/* request host to allocate memory contiguously */ +#define REQ_TO_HOST_FOR_CONT_MEMORY 0x8 + +/** + * structure used by FW for requesting host memory + */ +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMI_TLVTAG_STRUC_wlan_host_mem_req */ + + /** ID of the request */ + A_UINT32 req_id; + /** size of the of each unit */ + A_UINT32 unit_size; + /** + * flags to indicate that + * the number units is dependent + * on number of resources(num vdevs num peers .. etc) + */ + A_UINT32 num_unit_info; + /* + * actual number of units to allocate . if flags in the num_unit_info + * indicate that number of units is tied to number of a particular + * resource to allocate then num_units filed is set to 0 and host + * will derive the number units from number of the resources it is + * requesting. + */ + A_UINT32 num_units; +} wlan_host_mem_req; + +typedef enum { + IGNORE_DTIM = 0x01, + NORMAL_DTIM = 0x02, + STICK_DTIM = 0x03, + AUTO_DTIM = 0x04, +} BEACON_DTIM_POLICY; + +/* During test it is observed that 6 * 400 = 2400 can + * be alloced in addition to CFG_TGT_NUM_MSDU_DESC. + * If there is any change memory requirement, this number + * needs to be revisited. */ +#define TOTAL_VOW_ALLOCABLE 2400 +#define VOW_DESC_GRAB_MAX 800 + +#define VOW_GET_NUM_VI_STA(vow_config) (((vow_config) & 0xffff0000) >> 16) +#define VOW_GET_DESC_PER_VI_STA(vow_config) ((vow_config) & 0x0000ffff) + +/***TODO!!! Get these values dynamically in WMI_READY event and use it to calculate the mem req*/ +/* size in bytes required for msdu descriptor. If it changes, this should be updated. LARGE_AP + * case is not considered. LARGE_AP is disabled when VoW is enabled.*/ +#define MSDU_DESC_SIZE 20 + +/* size in bytes required to support a peer in target. + * This obtained by considering Two tids per peer. + * peer structure = 168 bytes + * tid = 96 bytes (per sta 2 means we need 192 bytes) + * peer_cb = 16 * 2 + * key = 52 * 2 + * AST = 12 * 2 + * rate, reorder.. = 384 + * smart antenna = 50 + */ +#define MEMORY_REQ_FOR_PEER 800 +/* + * NB: it is important to keep all the fields in the structure dword long + * so that it is easy to handle the statistics in BE host. + */ + +struct wlan_dbg_tx_stats { + /* Num HTT cookies queued to dispatch list */ + A_INT32 comp_queued; + /* Num HTT cookies dispatched */ + A_INT32 comp_delivered; + /* Num MSDU queued to WAL */ + A_INT32 msdu_enqued; + /* Num MPDU queue to WAL */ + A_INT32 mpdu_enqued; + /* Num MSDUs dropped by WMM limit */ + A_INT32 wmm_drop; + /* Num Local frames queued */ + A_INT32 local_enqued; + /* Num Local frames done */ + A_INT32 local_freed; + /* Num queued to HW */ + A_INT32 hw_queued; + /* Num PPDU reaped from HW */ + A_INT32 hw_reaped; + /* Num underruns */ + A_INT32 underrun; +#if defined(AR900B) + /* HW Paused. */ + A_UINT32 hw_paused; +#endif + /* Num PPDUs cleaned up in TX abort */ + A_INT32 tx_abort; + /* Num MPDUs requed by SW */ + A_INT32 mpdus_requed; + /* excessive retries */ + A_UINT32 tx_ko; +#if defined(AR900B) + A_UINT32 tx_xretry; +#endif + /* data hw rate code */ + A_UINT32 data_rc; + /* Scheduler self triggers */ + A_UINT32 self_triggers; + /* frames dropped due to excessive sw retries */ + A_UINT32 sw_retry_failure; + /* illegal rate phy errors */ + A_UINT32 illgl_rate_phy_err; + /* wal pdev continous xretry */ + A_UINT32 pdev_cont_xretry; + /* wal pdev continous xretry */ + A_UINT32 pdev_tx_timeout; + /* wal pdev resets */ + A_UINT32 pdev_resets; + /* frames dropped due to non-availability of stateless TIDs */ + A_UINT32 stateless_tid_alloc_failure; + /* PhY/BB underrun */ + A_UINT32 phy_underrun; + /* MPDU is more than txop limit */ + A_UINT32 txop_ovf; +#if defined(AR900B) + /* Number of Sequences posted */ + A_UINT32 seq_posted; + /* Number of Sequences failed queueing */ + A_UINT32 seq_failed_queueing; + /* Number of Sequences completed */ + A_UINT32 seq_completed; + /* Number of Sequences restarted */ + A_UINT32 seq_restarted; + /* Number of MU Sequences posted */ + A_UINT32 mu_seq_posted; + /* Num MPDUs flushed by SW, HWPAUSED, SW TXABORT (Reset,channel change) */ + A_INT32 mpdus_sw_flush; + /* Num MPDUs filtered by HW, all filter condition (TTL expired) */ + A_INT32 mpdus_hw_filter; + /* Num MPDUs truncated by PDG (TXOP, TBTT, PPDU_duration based on rate, dyn_bw) */ + A_INT32 mpdus_truncated; + /* Num MPDUs that was tried but didn't receive ACK or BA */ + A_INT32 mpdus_ack_failed; + /* Num MPDUs that was dropped du to expiry. */ + A_INT32 mpdus_expired; +#endif +}; + +struct wlan_dbg_rx_stats { + /* Cnts any change in ring routing mid-ppdu */ + A_INT32 mid_ppdu_route_change; + /* Total number of statuses processed */ + A_INT32 status_rcvd; + /* Extra frags on rings 0-3 */ + A_INT32 r0_frags; + A_INT32 r1_frags; + A_INT32 r2_frags; + A_INT32 r3_frags; + /* MSDUs / MPDUs delivered to HTT */ + A_INT32 htt_msdus; + A_INT32 htt_mpdus; + /* MSDUs / MPDUs delivered to local stack */ + A_INT32 loc_msdus; + A_INT32 loc_mpdus; + /* AMSDUs that have more MSDUs than the status ring size */ + A_INT32 oversize_amsdu; + /* Number of PHY errors */ + A_INT32 phy_errs; + /* Number of PHY errors drops */ + A_INT32 phy_err_drop; + /* Number of mpdu errors - FCS, MIC, ENC etc. */ + A_INT32 mpdu_errs; +#if defined(AR900B) + /* Number of rx overflow errors. */ + A_INT32 rx_ovfl_errs; +#endif +}; + + +struct wlan_dbg_mem_stats { + A_UINT32 iram_free_size; + A_UINT32 dram_free_size; +}; + +struct wlan_dbg_peer_stats { + + A_INT32 dummy; /* REMOVE THIS ONCE REAL PEER STAT COUNTERS ARE ADDED */ +}; + +typedef struct { + A_UINT32 mcs[10]; + A_UINT32 sgi[10]; + A_UINT32 nss[4]; + A_UINT32 nsts; + A_UINT32 stbc[10]; + A_UINT32 bw[3]; + A_UINT32 pream[6]; + A_UINT32 ldpc; + A_UINT32 txbf; + A_UINT32 mgmt_rssi; + A_UINT32 data_rssi; + A_UINT32 rssi_chain0; + A_UINT32 rssi_chain1; + A_UINT32 rssi_chain2; +/* + * TEMPORARY: leave rssi_chain3 in place for AR900B builds until code using + * rssi_chain3 has been converted to use wlan_dbg_rx_rate_info_v2_t. + * At that time, this rssi_chain3 field will be deleted. + */ +#if defined(AR900B) + A_UINT32 rssi_chain3; +#endif +} wlan_dbg_rx_rate_info_t ; + +typedef struct { + A_UINT32 mcs[10]; + A_UINT32 sgi[10]; +/* + * TEMPORARY: leave nss conditionally defined, until all code that + * requires nss[4] is converted to use wlan_dbg_tx_rate_info_v2_t. + * At that time, this nss array will be made length = 3 unconditionally. + */ +#if defined(CONFIG_AR900B_SUPPORT) || defined(AR900B) + A_UINT32 nss[4]; +#else + A_UINT32 nss[3]; +#endif + A_UINT32 stbc[10]; + A_UINT32 bw[3]; + A_UINT32 pream[4]; + A_UINT32 ldpc; + A_UINT32 rts_cnt; + A_UINT32 ack_rssi; +} wlan_dbg_tx_rate_info_t ; + +#define WLAN_MAX_MCS 10 + +typedef struct { + A_UINT32 mcs[WLAN_MAX_MCS]; + A_UINT32 sgi[WLAN_MAX_MCS]; + A_UINT32 nss[MAX_SPATIAL_STREAM_ANY_V2]; + A_UINT32 nsts; + A_UINT32 stbc[WLAN_MAX_MCS]; + A_UINT32 bw[NUM_DYN_BW_MAX]; + A_UINT32 pream[6]; + A_UINT32 ldpc; + A_UINT32 txbf; + A_UINT32 mgmt_rssi; + A_UINT32 data_rssi; + A_UINT32 rssi_chain0; + A_UINT32 rssi_chain1; + A_UINT32 rssi_chain2; + A_UINT32 rssi_chain3; + A_UINT32 reserved[8]; +} wlan_dbg_rx_rate_info_v2_t; + +typedef struct { + A_UINT32 mcs[WLAN_MAX_MCS]; + A_UINT32 sgi[WLAN_MAX_MCS]; + A_UINT32 nss[MAX_SPATIAL_STREAM_ANY_V2]; + A_UINT32 stbc[WLAN_MAX_MCS]; + A_UINT32 bw[NUM_DYN_BW_MAX]; + A_UINT32 pream[4]; + A_UINT32 ldpc; + A_UINT32 rts_cnt; + A_UINT32 ack_rssi; + A_UINT32 reserved[8]; +} wlan_dbg_tx_rate_info_v2_t; + +typedef struct { + A_UINT32 mcs[WLAN_MAX_MCS]; + A_UINT32 sgi[WLAN_MAX_MCS]; + A_UINT32 nss[MAX_SPATIAL_STREAM_ANY_V3]; + A_UINT32 nsts; + A_UINT32 stbc[WLAN_MAX_MCS]; + A_UINT32 bw[NUM_DYN_BW_MAX]; + A_UINT32 pream[6]; + A_UINT32 ldpc; + A_UINT32 txbf; + A_UINT32 mgmt_rssi; + A_UINT32 data_rssi; + A_UINT32 rssi_chain0; + A_UINT32 rssi_chain1; + A_UINT32 rssi_chain2; + A_UINT32 rssi_chain3; + A_UINT32 reserved[8]; +} wlan_dbg_rx_rate_info_v3_t; + +typedef struct { + A_UINT32 mcs[WLAN_MAX_MCS]; + A_UINT32 sgi[WLAN_MAX_MCS]; + A_UINT32 nss[MAX_SPATIAL_STREAM_ANY_V3]; + A_UINT32 stbc[WLAN_MAX_MCS]; + A_UINT32 bw[NUM_DYN_BW_MAX]; + A_UINT32 pream[4]; + A_UINT32 ldpc; + A_UINT32 rts_cnt; + A_UINT32 ack_rssi; + A_UINT32 reserved[8]; +} wlan_dbg_tx_rate_info_v3_t; + +#define WHAL_DBG_PHY_ERR_MAXCNT 18 +#define WHAL_DBG_SIFS_STATUS_MAXCNT 8 +#define WHAL_DBG_SIFS_ERR_MAXCNT 8 +#define WHAL_DBG_CMD_RESULT_MAXCNT 11 +#define WHAL_DBG_CMD_STALL_ERR_MAXCNT 4 +#define WHAL_DBG_FLUSH_REASON_MAXCNT 40 + +typedef enum { + WIFI_URRN_STATS_FIRST_PKT, + WIFI_URRN_STATS_BETWEEN_MPDU, + WIFI_URRN_STATS_WITHIN_MPDU, + WHAL_MAX_URRN_STATS +} wifi_urrn_type_t; + +typedef struct wlan_dbg_txbf_snd_stats { + A_UINT32 cbf_20[4]; + A_UINT32 cbf_40[4]; + A_UINT32 cbf_80[4]; + A_UINT32 sounding[9]; + A_UINT32 cbf_160[4]; +} wlan_dbg_txbf_snd_stats_t; + +typedef struct wlan_dbg_wifi2_error_stats { + A_UINT32 urrn_stats[WHAL_MAX_URRN_STATS]; + A_UINT32 flush_errs[WHAL_DBG_FLUSH_REASON_MAXCNT]; + A_UINT32 schd_stall_errs[WHAL_DBG_CMD_STALL_ERR_MAXCNT]; + A_UINT32 schd_cmd_result[WHAL_DBG_CMD_RESULT_MAXCNT]; + A_UINT32 sifs_status[WHAL_DBG_SIFS_STATUS_MAXCNT]; + A_UINT8 phy_errs[WHAL_DBG_PHY_ERR_MAXCNT]; + A_UINT32 rx_rate_inval; +} wlan_dbg_wifi2_error_stats_t; + +typedef struct wlan_dbg_wifi2_error2_stats { + A_UINT32 schd_errs[WHAL_DBG_CMD_STALL_ERR_MAXCNT]; + A_UINT32 sifs_errs[WHAL_DBG_SIFS_ERR_MAXCNT]; +} wlan_dbg_wifi2_error2_stats_t; + +#define WLAN_DBG_STATS_SIZE_TXBF_VHT 10 +#define WLAN_DBG_STATS_SIZE_TXBF_HT 8 +#define WLAN_DBG_STATS_SIZE_TXBF_OFDM 8 +#define WLAN_DBG_STATS_SIZE_TXBF_CCK 7 + +typedef struct wlan_dbg_txbf_data_stats { + A_UINT32 tx_txbf_vht[WLAN_DBG_STATS_SIZE_TXBF_VHT]; + A_UINT32 rx_txbf_vht[WLAN_DBG_STATS_SIZE_TXBF_VHT]; + A_UINT32 tx_txbf_ht[WLAN_DBG_STATS_SIZE_TXBF_HT]; + A_UINT32 tx_txbf_ofdm[WLAN_DBG_STATS_SIZE_TXBF_OFDM]; + A_UINT32 tx_txbf_cck[WLAN_DBG_STATS_SIZE_TXBF_CCK]; +} wlan_dbg_txbf_data_stats_t; + +struct wlan_dbg_tx_mu_stats { + A_UINT32 mu_sch_nusers_2; + A_UINT32 mu_sch_nusers_3; + A_UINT32 mu_mpdus_queued_usr[4]; + A_UINT32 mu_mpdus_tried_usr[4]; + A_UINT32 mu_mpdus_failed_usr[4]; + A_UINT32 mu_mpdus_requeued_usr[4]; + A_UINT32 mu_err_no_ba_usr[4]; + A_UINT32 mu_mpdu_underrun_usr[4]; + A_UINT32 mu_ampdu_underrun_usr[4]; +}; + +struct wlan_dbg_tx_selfgen_stats { + A_UINT32 su_ndpa; + A_UINT32 su_ndp; + A_UINT32 mu_ndpa; + A_UINT32 mu_ndp; + A_UINT32 mu_brpoll_1; + A_UINT32 mu_brpoll_2; + A_UINT32 mu_bar_1; + A_UINT32 mu_bar_2; + A_UINT32 cts_burst; + A_UINT32 su_ndp_err; + A_UINT32 su_ndpa_err; + A_UINT32 mu_ndp_err; + A_UINT32 mu_brp1_err; + A_UINT32 mu_brp2_err; +}; + +typedef struct wlan_dbg_sifs_resp_stats { + A_UINT32 ps_poll_trigger; /* num ps-poll trigger frames */ + A_UINT32 uapsd_trigger; /* num uapsd trigger frames */ + A_UINT32 qb_data_trigger[2]; /* num data trigger frames; idx 0: explicit and idx 1: implicit */ + A_UINT32 qb_bar_trigger[2]; /* num bar trigger frames; idx 0: explicit and idx 1: implicit */ + A_UINT32 sifs_resp_data; /* num ppdus transmitted at SIFS interval */ + A_UINT32 sifs_resp_err; /* num ppdus failed to meet SIFS resp timing */ +} wlan_dgb_sifs_resp_stats_t; + + + +/** wlan_dbg_wifi2_error_stats_t is not grouped with the + * following structure as it is allocated differently and only + * belongs to whal + */ +typedef struct wlan_dbg_stats_wifi2 { + wlan_dbg_txbf_snd_stats_t txbf_snd_info; + wlan_dbg_txbf_data_stats_t txbf_data_info; + struct wlan_dbg_tx_selfgen_stats tx_selfgen; + struct wlan_dbg_tx_mu_stats tx_mu; + wlan_dgb_sifs_resp_stats_t sifs_resp_info; +} wlan_dbg_wifi2_stats_t; + +typedef struct { + wlan_dbg_rx_rate_info_t rx_phy_info; + wlan_dbg_tx_rate_info_t tx_rate_info; +} wlan_dbg_rate_info_t; + +typedef struct { + wlan_dbg_rx_rate_info_v2_t rx_phy_info; + wlan_dbg_tx_rate_info_v2_t tx_rate_info; +} wlan_dbg_rate_info_v2_t; + +struct wlan_dbg_stats { + struct wlan_dbg_tx_stats tx; + struct wlan_dbg_rx_stats rx; +#if defined(AR900B) + struct wlan_dbg_mem_stats mem; +#endif + struct wlan_dbg_peer_stats peer; +}; + +#define DBG_STATS_MAX_HWQ_NUM 10 +#define DBG_STATS_MAX_TID_NUM 20 +#define DBG_STATS_MAX_CONG_NUM 16 +struct wlan_dbg_txq_stats { + A_UINT16 num_pkts_queued[DBG_STATS_MAX_HWQ_NUM]; + A_UINT16 tid_hw_qdepth[DBG_STATS_MAX_TID_NUM]; /* WAL_MAX_TID is 20 */ + A_UINT16 tid_sw_qdepth[DBG_STATS_MAX_TID_NUM]; /* WAL_MAX_TID is 20 */ +}; + +struct wlan_dbg_tidq_stats{ + A_UINT32 wlan_dbg_tid_txq_status; + struct wlan_dbg_txq_stats txq_st; +}; + +#endif /* __WLANDEFS_H__ */ diff --git a/drivers/staging/fw-api/fw/wlan_module_ids.h b/drivers/staging/fw-api/fw/wlan_module_ids.h new file mode 100755 index 0000000000000000000000000000000000000000..39b9d4db517f7590ec8ca4e2157ea78b80d720ab --- /dev/null +++ b/drivers/staging/fw-api/fw/wlan_module_ids.h @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2011, 2014-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef _WLAN_MODULE_IDS_H_ +#define _WLAN_MODULE_IDS_H_ + +/* Wlan module ids , global across all the modules */ +typedef enum { + WLAN_MODULE_ID_MIN = 0, + WLAN_MODULE_INF = WLAN_MODULE_ID_MIN, /* 0x0 */ + WLAN_MODULE_WMI, /* 0x1 */ + WLAN_MODULE_STA_PWRSAVE, /* 0x2 */ + WLAN_MODULE_WHAL, /* 0x3 */ + WLAN_MODULE_COEX, /* 0x4 */ + WLAN_MODULE_ROAM, /* 0x5 */ + WLAN_MODULE_RESMGR_CHAN_MANAGER, /* 0x6 */ + WLAN_MODULE_RESMGR, /* 0x7 */ + WLAN_MODULE_VDEV_MGR, /* 0x8 */ + WLAN_MODULE_SCAN, /* 0x9 */ + WLAN_MODULE_RATECTRL, /* 0xa */ + WLAN_MODULE_AP_PWRSAVE, /* 0xb */ + WLAN_MODULE_BLOCKACK, /* 0xc */ + WLAN_MODULE_MGMT_TXRX, /* 0xd */ + WLAN_MODULE_DATA_TXRX, /* 0xe */ + WLAN_MODULE_HTT, /* 0xf */ + WLAN_MODULE_HOST, /* 0x10 */ + WLAN_MODULE_BEACON, /* 0x11 */ + WLAN_MODULE_OFFLOAD, /* 0x12 */ + WLAN_MODULE_WAL, /* 0x13 */ + WAL_MODULE_DE, /* 0x14 */ + WLAN_MODULE_PCIELP, /* 0x15 */ + WLAN_MODULE_RTT, /* 0x16 */ + WLAN_MODULE_RESOURCE, /* 0x17 */ + WLAN_MODULE_DCS, /* 0x18 */ + WLAN_MODULE_CACHEMGR, /* 0x19 */ + WLAN_MODULE_ANI, /* 0x1a */ + WLAN_MODULE_P2P, /* 0x1b */ + WLAN_MODULE_CSA, /* 0x1c */ + WLAN_MODULE_NLO, /* 0x1d */ + WLAN_MODULE_CHATTER, /* 0x1e */ + WLAN_MODULE_WOW, /* 0x1f */ + WLAN_MODULE_WAL_VDEV, /* 0x20 */ + WLAN_MODULE_WAL_PDEV, /* 0x21 */ + WLAN_MODULE_TEST, /* 0x22 */ + WLAN_MODULE_STA_SMPS, /* 0x23 */ + WLAN_MODULE_SWBMISS, /* 0x24 */ + WLAN_MODULE_WMMAC, /* 0x25 */ + WLAN_MODULE_TDLS, /* 0x26 */ + WLAN_MODULE_HB, /* 0x27 */ + WLAN_MODULE_TXBF, /* 0x28 */ + WLAN_MODULE_BATCH_SCAN, /* 0x29 */ + WLAN_MODULE_THERMAL_MGR, /* 0x2a */ + WLAN_MODULE_PHYERR_DFS, /* 0x2b */ + WLAN_MODULE_RMC, /* 0x2c */ + WLAN_MODULE_STATS, /* 0x2d */ + WLAN_MODULE_NAN, /* 0x2e */ + WLAN_MODULE_IBSS_PWRSAVE, /* 0x2f */ + WLAN_MODULE_HIF_UART, /* 0x30 */ + WLAN_MODULE_LPI, /* 0x31 */ + WLAN_MODULE_EXTSCAN, /* 0x32 */ + WLAN_MODULE_UNIT_TEST, /* 0x33 */ + WLAN_MODULE_MLME, /* 0x34 */ + WLAN_MODULE_SUPPL, /* 0x35 */ + WLAN_MODULE_ERE, /* 0x36 */ + WLAN_MODULE_OCB, /* 0x37 */ + WLAN_MODULE_RSSI_MONITOR, /* 0x38 */ + WLAN_MODULE_WPM, /* 0x39 */ + WLAN_MODULE_CSS, /* 0x3a */ + WLAN_MODULE_PPS, /* 0x3b */ + WLAN_MODULE_SCAN_CH_PREDICT, /* 0x3c */ + WLAN_MODULE_MAWC, /* 0x3d */ + WLAN_MODULE_CMC_QMIC, /* 0x3e */ + WLAN_MODULE_EGAP, /* 0x3f */ + WLAN_MODULE_NAN20, /* 0x40 */ + WLAN_MODULE_QBOOST, /* 0x41 */ + WLAN_MODULE_P2P_LISTEN_OFFLOAD, /* 0x42 */ + WLAN_MODULE_HALPHY, /* 0x43 */ + WAL_MODULE_ENQ, /* 0x44 */ + + WLAN_MODULE_ID_MAX, + WLAN_MODULE_ID_INVALID = WLAN_MODULE_ID_MAX, +} WLAN_MODULE_ID; + + +#endif /* _WLAN_MODULE_IDS_H_ */ diff --git a/drivers/staging/fw-api/fw/wlan_tgt_def_config.h b/drivers/staging/fw-api/fw/wlan_tgt_def_config.h new file mode 100644 index 0000000000000000000000000000000000000000..b0f6ae67a639f5e7180c74153cc3e09a89f49086 --- /dev/null +++ b/drivers/staging/fw-api/fw/wlan_tgt_def_config.h @@ -0,0 +1,257 @@ +/* + * Copyright (c) 2011, 2014-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef __WLAN_TGT_DEF_CONFIG_H__ +#define __WLAN_TGT_DEF_CONFIG_H__ + +/* + * set of default target config , that can be over written by platform + */ + +/* + * default limit of 8 VAPs per device. + */ +/* Rome PRD support 4 vdevs */ +#define CFG_TGT_NUM_VDEV 4 + +/* + * We would need 1 AST entry per peer. Scale it by a factor of 2 to minimize hash collisions. + * TODO: This scaling factor would be taken care inside the WAL in the future. + */ +#define CFG_TGT_NUM_PEER_AST 2 + +/* # of WDS entries to support. + */ +#define CFG_TGT_WDS_ENTRIES 0 + +/* MAC DMA burst size. 0: 128B - default, 1: 256B, 2: 64B + */ +#define CFG_TGT_DEFAULT_DMA_BURST_SIZE 0 + +/* Fixed delimiters to be inserted after every MPDU + */ +#define CFG_TGT_DEFAULT_MAC_AGGR_DELIM 0 + +/* + * This value may need to be fine tuned, but a constant value will + * probably always be appropriate; it is probably not necessary to + * determine this value dynamically. + */ +#define CFG_TGT_AST_SKID_LIMIT 16 + +/* + * total number of peers per device. + */ +#define CFG_TGT_NUM_PEERS 14 + +/* + * In offload mode target supports features like WOW, chatter and other + * protocol offloads. In order to support them some functionalities like + * reorder buffering, PN checking need to be done in target. This determines + * maximum number of peers suported by target in offload mode + */ + +/* + * The current firmware implementation requires the number of offload peers + * should be (number of vdevs + 1). + + * The reason for this is the firmware clubbed the self peer and offload peer + * in the same pool. So if the firmware wanted to support n vdevs then the + * number of offload peer must be n+1 of which n buffers will be used for + * self peer and the remaining 1 is used for offload peer to support chatter + * mode for single STA. + + * Technically the macro should be 1 however the current firmware requires n+1. + + * TODO: This MACRO need to be modified in the future, if the firmware modified + * to allocate buffers for self peer and offload peer independently. + */ + +#define CFG_TGT_NUM_OFFLOAD_PEERS (CFG_TGT_NUM_VDEV+1) + +/* + * Number of reorder buffers used in offload mode + */ +#define CFG_TGT_NUM_OFFLOAD_REORDER_BUFFS 4 + +/* + * keys per peer node + */ +#define CFG_TGT_NUM_PEER_KEYS 2 +/* + * total number of data TX and RX TIDs + */ +#define CFG_TGT_NUM_TIDS (2 * (CFG_TGT_NUM_PEERS + CFG_TGT_NUM_VDEV + 2)) +/* + * set this to 0x7 (Peregrine = 3 chains). + * need to be set dynamically based on the HW capability. + */ +#define CFG_TGT_DEFAULT_TX_CHAIN_MASK 0x7 +/* + * set this to 0x7 (Peregrine = 3 chains). + * need to be set dynamically based on the HW capability. + */ +#define CFG_TGT_DEFAULT_RX_CHAIN_MASK 0x7 +/* 100 ms for video, best-effort, and background */ +#define CFG_TGT_RX_TIMEOUT_LO_PRI 100 +/* 40 ms for voice*/ +#define CFG_TGT_RX_TIMEOUT_HI_PRI 40 + +/* AR9888 unified is default in ethernet mode */ +#define CFG_TGT_RX_DECAP_MODE (0x2) +/* Decap to native Wifi header */ +#define CFG_TGT_RX_DECAP_MODE_NWIFI (0x1) +/* Decap to raw mode header */ +#define CFG_TGT_RX_DECAP_MODE_RAW (0x0) + +/* maximum number of pending scan requests */ +#define CFG_TGT_DEFAULT_SCAN_MAX_REQS 0x4 + +/* maximum number of VDEV that could use BMISS offload */ +#define CFG_TGT_DEFAULT_BMISS_OFFLOAD_MAX_VDEV 0x3 + +/* maximum number of VDEV offload Roaming to support */ +#define CFG_TGT_DEFAULT_ROAM_OFFLOAD_MAX_VDEV 0x3 + +/* maximum number of AP profiles pushed to offload Roaming */ +#define CFG_TGT_DEFAULT_ROAM_OFFLOAD_MAX_PROFILES 0x8 + +/* maximum number of VDEV offload GTK to support */ +#define CFG_TGT_DEFAULT_GTK_OFFLOAD_MAX_VDEV 0x3 + +/* default: mcast->ucast disabled if ATH_SUPPORT_MCAST2UCAST not defined */ +#ifndef ATH_SUPPORT_MCAST2UCAST +#define CFG_TGT_DEFAULT_NUM_MCAST_GROUPS 0 +#define CFG_TGT_DEFAULT_NUM_MCAST_TABLE_ELEMS 0 +#define CFG_TGT_DEFAULT_MCAST2UCAST_MODE 0 /* disabled */ +#else +/* (for testing) small multicast group membership table enabled */ +#define CFG_TGT_DEFAULT_NUM_MCAST_GROUPS 4 +#define CFG_TGT_DEFAULT_NUM_MCAST_TABLE_ELEMS 16 +#define CFG_TGT_DEFAULT_MCAST2UCAST_MODE 2 +#endif + +#define CFG_TGT_MAX_MULTICAST_FILTER_ENTRIES 32 +/* + * Specify how much memory the target should allocate for a debug log of + * tx PPDU meta-information (how large the PPDU was, when it was sent, + * whether it was successful, etc.) + * The size of the log records is configurable, from a minimum of 28 bytes + * to a maximum of about 300 bytes. A typical configuration would result + * in each log record being about 124 bytes. + * Thus, 1KB of log space can hold about 30 small records, 3 large records, + * or about 8 typical-sized records. + */ +#define CFG_TGT_DEFAULT_TX_DBG_LOG_SIZE 1024 /* bytes */ + +/* target based fragment timeout and MPDU duplicate detection */ +#define CFG_TGT_DEFAULT_RX_SKIP_DEFRAG_TIMEOUT_DUP_DETECTION_CHECK 0 + +/* Default VoW configuration + */ +#define CFG_TGT_DEFAULT_VOW_CONFIG 0 + +/* + * total number of descriptors to use in the target + */ +#define CFG_TGT_NUM_MSDU_DESC (1024 + 32) + +/* + * Maximum number of frag table entries + */ +#define CFG_TGT_MAX_FRAG_TABLE_ENTRIES 10 + +/* + * Maximum number of VDEV that beacon tx offload will support + */ +#define CFG_TGT_DEFAULT_BEACON_TX_OFFLOAD_MAX_VDEV 3 + +/* + * number of vdevs that can support tdls + */ +#define CFG_TGT_NUM_TDLS_VDEVS 1 + +/* + * number of peers that each Tdls vdev can track + */ +#define CFG_TGT_NUM_TDLS_CONN_TABLE_ENTRIES 8 + +/* + * number of TDLS concurrent sleep STAs + */ +#define CFG_TGT_NUM_TDLS_CONC_SLEEP_STAS 1 + +/* + * number of TDLS concurrent buffer STAs + */ +#define CFG_TGT_NUM_TDLS_CONC_BUFFER_STAS 1 + +/* + * ht enable highest MCS by default + */ +#define CFG_TGT_DEFAULT_GTX_HT_MASK 0x8080 +/* + * vht enable highest MCS by default + */ +#define CFG_TGT_DEFAULT_GTX_VHT_MASK 0x80200 +/* + * threshold to enable GTX + */ +#define CFG_TGT_DEFAULT_GTX_PER_THRESHOLD 3 +/* + * margin to move back when per > margin + threshold + */ +#define CFG_TGT_DEFAULT_GTX_PER_MARGIN 2 +/* + * step for every move + */ +#define CFG_TGT_DEFAULT_GTX_TPC_STEP 1 +/* + * lowest TPC + */ +#define CFG_TGT_DEFAULT_GTX_TPC_MIN 0 +/* + * enable all BW 20/40/80/160 + */ +#define CFG_TGT_DEFAULT_GTX_BW_MASK 0xf + +/* + * number of vdevs that can support OCB + */ +#define CFG_TGT_NUM_OCB_VDEVS 1 + +/* + * maximum number of channels that can do OCB + */ +#define CFG_TGT_NUM_OCB_CHANNELS 2 + +/* + * maximum number of channels in an OCB schedule + */ +#define CFG_TGT_NUM_OCB_SCHEDULES 2 + +#endif /*__WLAN_TGT_DEF_CONFIG_H__ */ diff --git a/drivers/staging/fw-api/fw/wlan_tgt_def_config_hl.h b/drivers/staging/fw-api/fw/wlan_tgt_def_config_hl.h new file mode 100644 index 0000000000000000000000000000000000000000..dbd6280825dffb76a78f86296e5da30d415b405a --- /dev/null +++ b/drivers/staging/fw-api/fw/wlan_tgt_def_config_hl.h @@ -0,0 +1,289 @@ +/* + * Copyright (c) 2013-2016 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_TGT_DEF_CONFIG_H__ +#define __WLAN_TGT_DEF_CONFIG_H__ + +/* + * TODO: please help to consider if we need a seperate config file from LL case. + */ + +/* + * set of default target config , that can be over written by platform + */ + +#ifdef QCA_SUPPORT_INTEGRATED_SOC +#define CFG_TGT_NUM_VDEV 3 /*STA, P2P device, P2P GO/Cli*/ +#else +/* + * default limit of VAPs per device. + */ +#define CFG_TGT_NUM_VDEV 3 +#endif +/* + * We would need 1 AST entry per peer. Scale it by a factor of 2 to minimize + * hash collisions. + * TODO: This scaling factor would be taken care inside the WAL in the future. + */ +#define CFG_TGT_NUM_PEER_AST 2 + +/* # of WDS entries to support. + */ +#define CFG_TGT_WDS_ENTRIES 2 + +/* MAC DMA burst size. 0: 128B - default, 1: 256B, 2: 64B + */ +#define CFG_TGT_DEFAULT_DMA_BURST_SIZE 0 + +/* Fixed delimiters to be inserted after every MPDU + */ +#define CFG_TGT_DEFAULT_MAC_AGGR_DELIM 0 + +/* + * This value may need to be fine tuned, but a constant value will + * probably always be appropriate; it is probably not necessary to + * determine this value dynamically. + */ +#define CFG_TGT_AST_SKID_LIMIT 6 +/* + * total number of peers per device. + * currently set to 8 to bring up IP3.9 for memory size problem + */ +#define CFG_TGT_NUM_PEERS 8 +/* + * max number of peers per device. + */ +#define CFG_TGT_NUM_PEERS_MAX 8 +/* + * In offload mode target supports features like WOW, chatter and other + * protocol offloads. In order to support them some functionalities like + * reorder buffering, PN checking need to be done in target. This determines + * maximum number of peers suported by target in offload mode + */ +#define CFG_TGT_NUM_OFFLOAD_PEERS 0 +/* + * Number of reorder buffers used in offload mode + */ +#define CFG_TGT_NUM_OFFLOAD_REORDER_BUFFS 0 +/* + * keys per peer node + */ +#define CFG_TGT_NUM_PEER_KEYS 2 +/* + * total number of TX/RX data TIDs + */ +#define CFG_TGT_NUM_TIDS (2 * (CFG_TGT_NUM_PEERS + \ + CFG_TGT_NUM_VDEV)) +/* + * max number of Tx TIDS + */ +#define CFG_TGT_NUM_TIDS_MAX (2 * (CFG_TGT_NUM_PEERS_MAX + \ + CFG_TGT_NUM_VDEV)) +/* + * number of multicast keys. + */ +#define CFG_TGT_NUM_MCAST_KEYS 8 +/* + * A value of 3 would probably suffice - one for the control stack, one for + * the data stack, and one for debugging. + * This value may need to be fine tuned, but a constant value will + * probably always be appropriate; it is probably not necessary to + * determine this value dynamically. + */ +#define CFG_TGT_NUM_PDEV_HANDLERS 8 +/* + * A value of 3 would probably suffice - one for the control stack, one for + * the data stack, and one for debugging. + * This value may need to be fine tuned, but a constant value will + * probably always be appropriate; it is probably not necessary to + * determine this value dynamically. + */ +#define CFG_TGT_NUM_VDEV_HANDLERS 4 +/* + * set this to 8: + * one for WAL interals (connection pause) + * one for the control stack, + * one for the data stack + * and one for debugging + * This value may need to be fine tuned, but a constant value will + * probably always be appropriate; it is probably not necessary to + * determine this value dynamically. + */ +#define CFG_TGT_NUM_HANDLERS 14 +/* + * set this to 3: one for the control stack, one for + * the data stack, and one for debugging. + * This value may need to be fine tuned, but a constant value will + * probably always be appropriate; it is probably not necessary to + * determine this value dynamically. + */ +#define CFG_TGT_NUM_PEER_HANDLERS 32 +/* + * set this to 0x7 (Peregrine = 3 chains). + * need to be set dynamically based on the HW capability. + * this is rome + */ +#define CFG_TGT_DEFAULT_TX_CHAIN_MASK 0x3 +/* + * set this to 0x7 (Peregrine = 3 chains). + * need to be set dynamically based on the HW capability. + * this is rome + */ +#define CFG_TGT_DEFAULT_RX_CHAIN_MASK 0x3 +/* 100 ms for video, best-effort, and background */ +#define CFG_TGT_RX_TIMEOUT_LO_PRI 100 +/* 40 ms for voice*/ +#define CFG_TGT_RX_TIMEOUT_HI_PRI 40 + +/* AR9888 unified is default in ethernet mode */ +#define CFG_TGT_RX_DECAP_MODE (0x2) +/* Decap to native Wifi header */ +#define CFG_TGT_RX_DECAP_MODE_NWIFI (0x1) + +/* Decap to raw mode header */ +#define CFG_TGT_RX_DECAP_MODE_RAW (0x0) + +/* maximum number of pending scan requests */ +#define CFG_TGT_DEFAULT_SCAN_MAX_REQS 0x4 + +/* maximum number of scan event handlers */ +#define CFG_TGT_DEFAULT_SCAN_MAX_HANDLERS 0x4 + +/* maximum number of VDEV that could use BMISS offload */ +#define CFG_TGT_DEFAULT_BMISS_OFFLOAD_MAX_VDEV 0x2 + +/* maximum number of VDEV offload Roaming to support */ +#define CFG_TGT_DEFAULT_ROAM_OFFLOAD_MAX_VDEV 0x2 + +/* maximum number of AP profiles pushed to offload Roaming */ +#define CFG_TGT_DEFAULT_ROAM_OFFLOAD_MAX_PROFILES 0x8 + +/* maximum number of VDEV offload GTK to support */ +#define CFG_TGT_DEFAULT_GTK_OFFLOAD_MAX_VDEV 0x2 +/* default: mcast->ucast disabled */ + +#define CFG_TGT_DEFAULT_NUM_MCAST_GROUPS 0 +#define CFG_TGT_DEFAULT_NUM_MCAST_TABLE_ELEMS 0 +#define CFG_TGT_DEFAULT_MCAST2UCAST_MODE 0 /* disabled */ + +/* + * Specify how much memory the target should allocate for a debug log of + * tx PPDU meta-information (how large the PPDU was, when it was sent, + * whether it was successful, etc.) + * The size of the log records is configurable, from a minimum of 28 bytes + * to a maximum of about 300 bytes. A typical configuration would result + * in each log record being about 124 bytes. + * Thus, 1KB of log space can hold about 30 small records, 3 large records, + * or about 8 typical-sized records. + */ +#define CFG_TGT_DEFAULT_TX_DBG_LOG_SIZE 1024 /* bytes */ + +/* target based fragment timeout and MPDU duplicate detection */ +#define CFG_TGT_DEFAULT_RX_SKIP_DEFRAG_TIMEOUT_DUP_DETECTION_CHECK 0 +/* Default VoW configuration + */ +#define CFG_TGT_DEFAULT_VOW_CONFIG 0 + +/* + * total number of descriptors to use in the target + */ +#ifndef HIF_SDIO +#define CFG_TGT_NUM_MSDU_DESC (32) +#else +#define CFG_TGT_NUM_MSDU_DESC (0) +#endif +/* + * Maximum number of frag table entries + */ +#define CFG_TGT_MAX_FRAG_TABLE_ENTRIES 2 + +/* + * number of vdevs that can support tdls + */ +#define CFG_TGT_NUM_TDLS_VDEVS 1 + +/* + * number of peers that each Tdls vdev can track + */ +#define CFG_TGT_NUM_TDLS_CONN_TABLE_ENTRIES 8 +/* + * number of TDLS concurrent sleep STAs + */ +#define CFG_TGT_NUM_TDLS_CONC_SLEEP_STAS 1 + +/* + * number of TDLS concurrent buffer STAs + */ +#define CFG_TGT_NUM_TDLS_CONC_BUFFER_STAS 1 + +#define CFG_TGT_MAX_MULTICAST_FILTER_ENTRIES 16 +/* + * Maximum number of VDEV that beacon tx offload will support + */ +#ifdef HIF_SDIO +#define CFG_TGT_DEFAULT_BEACON_TX_OFFLOAD_MAX_VDEV 2 +#else +#define CFG_TGT_DEFAULT_BEACON_TX_OFFLOAD_MAX_VDEV 1 +#endif + +/* + * ht enable highest MCS by default + */ +#define CFG_TGT_DEFAULT_GTX_HT_MASK 0x8080 +/* + * vht enable highest MCS by default + */ +#define CFG_TGT_DEFAULT_GTX_VHT_MASK 0x80200 +/* + * threshold to enable GTX + */ +#define CFG_TGT_DEFAULT_GTX_PER_THRESHOLD 3 +/* + * margin to move back when per > margin + threshold + */ +#define CFG_TGT_DEFAULT_GTX_PER_MARGIN 2 +/* + * step for every move + */ +#define CFG_TGT_DEFAULT_GTX_TPC_STEP 1 +/* + * lowest TPC + */ +#define CFG_TGT_DEFAULT_GTX_TPC_MIN 0 +/* + * enable all BW 20/40/80/160 + */ +#define CFG_TGT_DEFAULT_GTX_BW_MASK 0xf + +/* + * number of vdevs that can support OCB + */ +#define CFG_TGT_NUM_OCB_VDEVS 1 + +/* + * maximum number of channels that can do OCB + */ +#define CFG_TGT_NUM_OCB_CHANNELS 2 + +/* + * maximum number of channels in an OCB schedule + */ +#define CFG_TGT_NUM_OCB_SCHEDULES 2 + +#endif /*__WLAN_TGT_DEF_CONFIG_H__ */ diff --git a/drivers/staging/fw-api/fw/wmi.h b/drivers/staging/fw-api/fw/wmi.h new file mode 100755 index 0000000000000000000000000000000000000000..4b92765c3e7fe2e7b8c1fa33dcb8f371740c6fab --- /dev/null +++ b/drivers/staging/fw-api/fw/wmi.h @@ -0,0 +1,199 @@ +/* + * Copyright (c) 2010-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * This file contains the definitions of the WMI protocol specified in the + * Wireless Module Interface (WMI). It includes definitions of all the + * commands and events. Commands are messages from the host to the WM. + * Events and Replies are messages from the WM to the host. + * + * Ownership of correctness in regards to commands + * belongs to the host driver and the WMI is not required to validate + * parameters for value, proper range, or any other checking. + * + */ + +#ifndef _WMI_H_ +#define _WMI_H_ + +#include "wlan_defs.h" +#include "wmix.h" +#include "wmi_unified.h" +#include "wmi_tlv_helper.h" +#include "wmi_tlv_defs.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +#define HTC_PROTOCOL_VERSION 0x0002 + +#define WMI_PROTOCOL_VERSION 0x0002 + +#define WMI_MODE_MAX 8 +#define WMI_MAX_RATE_MASK 6 + + +PREPACK struct host_app_area_s { + A_UINT32 wmi_protocol_ver; +} POSTPACK; + + +#undef MS +#define MS(_v, _f) (((_v) & _f##_MASK) >> _f##_LSB) +#undef SM +#define SM(_v, _f) (((_v) << _f##_LSB) & _f##_MASK) +#undef WO +#define WO(_f) ((_f##_OFFSET) >> 2) + +#undef GET_FIELD +#define GET_FIELD(_addr, _f) MS(*((A_UINT32 *)(_addr) + WO(_f)), _f) +#undef SET_FIELD +#define SET_FIELD(_addr, _f, _val) \ + (*((A_UINT32 *)(_addr) + WO(_f)) = \ + (*((A_UINT32 *)(_addr) + WO(_f)) & ~_f##_MASK) | SM(_val, _f)) + +#define WMI_GET_FIELD(_msg_buf, _msg_type, _f) \ + GET_FIELD(_msg_buf, _msg_type ## _ ## _f) + +#define WMI_SET_FIELD(_msg_buf, _msg_type, _f, _val) \ + SET_FIELD(_msg_buf, _msg_type ## _ ## _f, _val) + +#define WMI_EP_APASS WMI_EP_APSS /* TYPO: leave incorrect name as an alias for the correct name */ +#define WMI_EP_APSS 0x0 /* WLAN driver running on apps processor sub-system */ +#define WMI_EP_LPASS 0x1 +#define WMI_EP_SENSOR 0x2 +#define WMI_EP_NANOHUB 0x3 /* WLAN driver running on NANO Hub */ +#define WMI_EP_MODEM 0x4 +#define WMI_EP_LOCATION 0x5 + +/* + * Control Path + */ +typedef PREPACK struct { + A_UINT32 commandId : 24, + reserved : 2, /* used for WMI endpoint ID */ + plt_priv : 6; /* platform private */ +} POSTPACK WMI_CMD_HDR; /* used for commands and events */ + +#define WMI_CMD_HDR_COMMANDID_LSB 0 +#define WMI_CMD_HDR_COMMANDID_MASK 0x00ffffff +#define WMI_CMD_HDR_COMMANDID_OFFSET 0x00000000 +#define WMI_CMD_HDR_WMI_ENDPOINTID_MASK 0x03000000 +#define WMI_CMD_HDR_WMI_ENDPOINTID_OFFSET 24 +#define WMI_CMD_HDR_PLT_PRIV_LSB 24 +#define WMI_CMD_HDR_PLT_PRIV_MASK 0xff000000 +#define WMI_CMD_HDR_PLT_PRIV_OFFSET 0x00000000 + +/* + * List of Commnands + */ +typedef enum { + WMI_EXTENSION_CMDID, //used in wmi_svc.c /* Non-wireless extensions */ + WMI_IGNORE_CMDID, //used in wlan_wmi.c +} WMI_COMMAND_ID; + + +typedef enum { + NONE_CRYPT = 0x01, + WEP_CRYPT = 0x02, + TKIP_CRYPT = 0x04, + AES_CRYPT = 0x08, +#ifdef WAPI_ENABLE + WAPI_CRYPT = 0x10, +#endif /*WAPI_ENABLE*/ +} CRYPTO_TYPE; + +#define WMI_MAX_SSID_LEN 32 + +/* + * WMI_SET_PMK_CMDID + */ +#define WMI_PMK_LEN 32 + + +/* + * WMI_ADD_CIPHER_KEY_CMDID + */ +typedef enum { + PAIRWISE_USAGE = 0x00, + GROUP_USAGE = 0x01, + TX_USAGE = 0x02, /* default Tx Key - Static WEP only */ + PMK_USAGE = 0x04, /* PMK cache */ +} KEY_USAGE; +/* + * List of Events (target to host) + */ +typedef enum { + WMI_EXTENSION_EVENTID //wmi_profhook.c and umac_wmi_events.c +} WMI_EVENT_ID; + +typedef enum { + WMI_11A_CAPABILITY = 1, + WMI_11G_CAPABILITY = 2, + WMI_11AG_CAPABILITY = 3, + WMI_11NA_CAPABILITY = 4, + WMI_11NG_CAPABILITY = 5, + WMI_11NAG_CAPABILITY = 6, + WMI_11AC_CAPABILITY = 7, + WMI_11AX_CAPABILITY = 8, + // END CAPABILITY + WMI_11N_CAPABILITY_OFFSET = (WMI_11NA_CAPABILITY - WMI_11A_CAPABILITY), +} WMI_PHY_CAPABILITY; + + +/* Deprectated, need clean up */ +#define WMI_MAX_RX_META_SZ (12) + +typedef PREPACK struct { + A_INT8 rssi; + A_UINT8 info; /* usage of 'info' field(8-bit): + * b1:b0 - WMI_MSG_TYPE + * b4:b3:b2 - UP(tid) + * b5 - Used in AP mode. More-data in tx dir, PS in rx. + * b7:b6 - Dot3 header(0), + * Dot11 Header(1), + * ACL data(2) + */ + + A_UINT16 info2; /* usage of 'info2' field(16-bit): + * b11:b0 - seq_no + * b12 - A-MSDU? + * b15:b13 - META_DATA_VERSION 0 - 7 + */ + A_UINT16 info3; /* b3:b2:b1:b0 - device id + * b4 - Used in AP mode. uAPSD trigger in rx, EOSP in tx + * b7:b5 - unused? + * b15:b8 - pad before data start(irrespective of meta version) + */ +} POSTPACK WMI_DATA_HDR; +#ifdef __cplusplus +} +#endif + +#endif /* _WMI_H_ */ diff --git a/drivers/staging/fw-api/fw/wmi_services.h b/drivers/staging/fw-api/fw/wmi_services.h new file mode 100755 index 0000000000000000000000000000000000000000..3a8251bb9ddcdab0d40380952306904f202f2356 --- /dev/null +++ b/drivers/staging/fw-api/fw/wmi_services.h @@ -0,0 +1,280 @@ +/* + * Copyright (c) 2011-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef _WMI_SERVICES_H_ +#define _WMI_SERVICES_H_ + + +#ifdef __cplusplus +extern "C" { +#endif + + + +typedef enum { + WMI_SERVICE_BEACON_OFFLOAD=0, /* beacon offload */ + WMI_SERVICE_SCAN_OFFLOAD=1, /* scan offload */ + WMI_SERVICE_ROAM_SCAN_OFFLOAD=2, /* roam scan offload */ + WMI_SERVICE_BCN_MISS_OFFLOAD=3, /* beacon miss offload */ + WMI_SERVICE_STA_PWRSAVE=4, /* fake sleep + basic power save */ + WMI_SERVICE_STA_ADVANCED_PWRSAVE=5, /* uapsd, pspoll, force sleep */ + WMI_SERVICE_AP_UAPSD=6, /* uapsd on AP */ + WMI_SERVICE_AP_DFS=7, /* DFS on AP */ + WMI_SERVICE_11AC=8, /* supports 11ac */ + WMI_SERVICE_BLOCKACK=9, /* Supports triggering ADDBA/DELBA from host*/ + WMI_SERVICE_PHYERR=10, /* PHY error */ + WMI_SERVICE_BCN_FILTER=11, /* Beacon filter support */ + WMI_SERVICE_RTT=12, /* RTT (round trip time) support */ + WMI_SERVICE_WOW=13, /* WOW Support */ + WMI_SERVICE_RATECTRL_CACHE=14, /* Rate-control caching */ + WMI_SERVICE_IRAM_TIDS=15, /* TIDs in IRAM */ + WMI_SERVICE_ARPNS_OFFLOAD=16, /* ARP NS Offload support for STA vdev */ + WMI_SERVICE_NLO=17, /* Network list offload service */ + WMI_SERVICE_GTK_OFFLOAD=18, /* GTK offload */ + WMI_SERVICE_SCAN_SCH=19, /* Scan Scheduler Service */ + WMI_SERVICE_CSA_OFFLOAD=20, /* CSA offload service */ + WMI_SERVICE_CHATTER=21, /* Chatter service */ + WMI_SERVICE_COEX_FREQAVOID=22, /* FW report freq range to avoid */ + WMI_SERVICE_PACKET_POWER_SAVE=23, /* packet power save service */ + WMI_SERVICE_FORCE_FW_HANG=24, /* Service to test the firmware recovery mechanism */ + WMI_SERVICE_GPIO=25, /* GPIO service */ + WMI_SERVICE_STA_DTIM_PS_MODULATED_DTIM=26, /* Modulated DTIM support */ + WMI_STA_UAPSD_BASIC_AUTO_TRIG=27, /* Basic version of station UAPSD AC Trigger Generation Method with + * variable tigger periods (service, delay, and suspend intervals) */ + WMI_STA_UAPSD_VAR_AUTO_TRIG=28, /* Station UAPSD AC Trigger Generation Method with variable + * trigger periods (service, delay, and suspend intervals) */ + WMI_SERVICE_STA_KEEP_ALIVE=29, /* Serivce to support the STA KEEP ALIVE mechanism */ + WMI_SERVICE_TX_ENCAP=30, /* Packet type for TX encapsulation */ + WMI_SERVICE_AP_PS_DETECT_OUT_OF_SYNC=31, /* detect out-of-sync sleeping stations */ + WMI_SERVICE_EARLY_RX=32, /* adaptive early-rx feature */ + WMI_SERVICE_STA_SMPS=33, /* STA MIMO-PS */ + WMI_SERVICE_FWTEST=34, /* Firmware test service */ + WMI_SERVICE_STA_WMMAC=35, /* STA WMMAC */ + WMI_SERVICE_TDLS=36, /* TDLS support */ + WMI_SERVICE_BURST=37, /* SIFS spaced burst support */ + WMI_SERVICE_MCC_BCN_INTERVAL_CHANGE=38, /* Dynamic beaocn interval change for SAP/P2p GO in MCC scenario */ + WMI_SERVICE_ADAPTIVE_OCS=39, /* Service to support adaptive off-channel scheduler */ + WMI_SERVICE_BA_SSN_SUPPORT=40, /* target will provide Sequence number for the peer/tid combo */ + WMI_SERVICE_FILTER_IPSEC_NATKEEPALIVE=41, + WMI_SERVICE_WLAN_HB=42, /* wlan HB service */ + WMI_SERVICE_LTE_ANT_SHARE_SUPPORT=43, /* support LTE/WLAN antenna sharing */ + WMI_SERVICE_BATCH_SCAN=44, /* Service to support batch scan */ + WMI_SERVICE_QPOWER=45, /* QPower service */ + WMI_SERVICE_PLMREQ=46, + WMI_SERVICE_THERMAL_MGMT=47, /* thermal throttling support */ + WMI_SERVICE_RMC=48, /* RMC support */ + WMI_SERVICE_MHF_OFFLOAD=49, /* multi-hop forwarding offload */ + WMI_SERVICE_COEX_SAR=50, /* target support SAR tx limit from WMI_PDEV_PARAM_TXPOWER_LIMITxG */ + WMI_SERVICE_BCN_TXRATE_OVERRIDE=51, /* Will support the bcn/prb rsp rate override */ + WMI_SERVICE_NAN=52, /* Neighbor Awareness Network */ + WMI_SERVICE_L1SS_STAT=53, /* L1SS statistics counter report */ + WMI_SERVICE_ESTIMATE_LINKSPEED=54, /* Linkspeed Estimation per peer */ + WMI_SERVICE_OBSS_SCAN=55, /* Service to support OBSS scan */ + WMI_SERVICE_TDLS_OFFCHAN=56, /* TDLS off channel support */ + WMI_SERVICE_TDLS_UAPSD_BUFFER_STA=57, /* TDLS UAPSD Buffer STA support */ + WMI_SERVICE_TDLS_UAPSD_SLEEP_STA=58, /* TDLS UAPSD Sleep STA support */ + WMI_SERVICE_IBSS_PWRSAVE=59, /* IBSS power save support */ + WMI_SERVICE_LPASS=60, /* Service to support LPASS */ + WMI_SERVICE_EXTSCAN=61, /* Extended Scans */ + WMI_SERVICE_D0WOW=62, /* D0-WOW Support */ + WMI_SERVICE_HSOFFLOAD=63, /* Hotspot offload feature Support */ + WMI_SERVICE_ROAM_HO_OFFLOAD=64, /* roam handover offload */ + WMI_SERVICE_RX_FULL_REORDER=65, /* target-based Rx full reorder */ + WMI_SERVICE_DHCP_OFFLOAD=66, /* DHCP offload support */ + WMI_SERVICE_STA_RX_IPA_OFFLOAD_SUPPORT=67, /* STA RX DATA offload to IPA support */ + WMI_SERVICE_MDNS_OFFLOAD=68, /* mDNS responder offload support */ + WMI_SERVICE_SAP_AUTH_OFFLOAD=69, /* softap auth offload */ + WMI_SERVICE_DUAL_BAND_SIMULTANEOUS_SUPPORT=70, /* Dual Band Simultaneous support */ + WMI_SERVICE_OCB=71, /* OCB mode support */ + WMI_SERVICE_AP_ARPNS_OFFLOAD=72, /* arp offload support for ap mode vdev */ + WMI_SERVICE_PER_BAND_CHAINMASK_SUPPORT=73, /* Per band chainmask support */ + WMI_SERVICE_PACKET_FILTER_OFFLOAD=74, /* Per vdev packet filters */ + WMI_SERVICE_MGMT_TX_HTT=75, /* Mgmt Tx via HTT interface */ + WMI_SERVICE_MGMT_TX_WMI=76, /* Mgmt Tx via WMI interface */ + WMI_SERVICE_EXT_MSG=77, /* WMI_SERVICE_READY_EXT msg follows */ + WMI_SERVICE_MAWC=78, /* Motion Aided WiFi Connectivity (MAWC)*/ + WMI_SERVICE_PEER_ASSOC_CONF=79, /* target will send ASSOC_CONF after ASSOC_CMD is processed */ + WMI_SERVICE_EGAP=80, /* enhanced green ap support */ + WMI_SERVICE_STA_PMF_OFFLOAD=81, /* FW supports 11W PMF Offload for STA */ + WMI_SERVICE_UNIFIED_WOW_CAPABILITY=82, /* FW supports unified D0 and D3 wow */ + WMI_SERVICE_ENHANCED_PROXY_STA=83, /* Enhanced ProxySTA mode support */ + WMI_SERVICE_ATF=84, /* Air Time Fairness support */ + WMI_SERVICE_COEX_GPIO=85, /* BTCOEX GPIO support */ + WMI_SERVICE_AUX_SPECTRAL_INTF=86, /* Aux Radio enhancement support for ignoring spectral scan intf from main radios */ + WMI_SERVICE_AUX_CHAN_LOAD_INTF=87, /* Aux Radio enhancement support for ignoring chan load intf from main radios*/ + WMI_SERVICE_BSS_CHANNEL_INFO_64=88, /* BSS channel info (freq, noise floor, 64-bit counters) event support */ + WMI_SERVICE_ENTERPRISE_MESH=89, /* Enterprise MESH Service Support */ + WMI_SERVICE_RESTRT_CHNL_SUPPORT=90, /* Restricted Channel Support */ + WMI_SERVICE_BPF_OFFLOAD=91, /* FW supports bpf offload */ + WMI_SERVICE_SYNC_DELETE_CMDS=92, /* FW sends response event for Peer, Vdev delete commands */ + WMI_SERVICE_SMART_ANTENNA_SW_SUPPORT=93, + WMI_SERVICE_SMART_ANTENNA_HW_SUPPORT=94, + WMI_SERVICE_RATECTRL_LIMIT_MAX_MIN_RATES=95, /* allow per-peer tx MCS min/max limits by host */ + WMI_SERVICE_NAN_DATA=96, /* FW supports NAN data */ + WMI_SERVICE_NAN_RTT=97, /* FW supports NAN RTT */ + WMI_SERVICE_11AX=98, /* FW supports 802.11ax */ + /* WMI_SERVICE_DEPRECATED_REPLACE + * FW supports these new WMI commands, to be used rather than + * deprecated matching commands: + * - WMI_PDEV_SET_PCL_CMDID (vs. WMI_SOC_SET_PCL_CMDID) + * - WMI_PDEV_SET_HW_MODE_CMDID (vs. WMI_SOC_SET_HW_MODE_CMDID) + * - WMI_PDEV_SET_MAC_CONFIG_CMDID (vs. WMI_SOC_SET_DUAL_MAC_CONFIG_CMDID) + * - WMI_PDEV_SET_ANTENNA_MODE_CMDID (vs. WMI_SOC_SET_ANTENNA_MODE_CMDID) + * - WMI_VDEV_SET_DSCP_TID_MAP_CMDID (vs. WMI_VDEV_SET_WMM_PARAMS_CMDID) + */ + WMI_SERVICE_DEPRECATED_REPLACE=99, + WMI_SERVICE_TDLS_CONN_TRACKER_IN_HOST_MODE=100, /* FW supports a new mode that allows to run connection tracker in host */ + WMI_SERVICE_ENHANCED_MCAST_FILTER=101, /* FW supports enhanced multicast filtering (of mcast IP inside ucast WLAN) */ + WMI_SERVICE_PERIODIC_CHAN_STAT_SUPPORT=102, /* periodic channel stats service */ + WMI_SERVICE_MESH_11S=103, /* 11s mesh service support */ + WMI_SERVICE_HALF_RATE_QUARTER_RATE_SUPPORT=104, /* FW+HW supports 10 MHz (half rate) and 5 MHz (quarter rate) channel bandwidth */ + WMI_SERVICE_VDEV_RX_FILTER=105, /* Support per-vdev specs of which rx frames to filter out */ + WMI_SERVICE_P2P_LISTEN_OFFLOAD_SUPPORT=106, + WMI_SERVICE_MARK_FIRST_WAKEUP_PACKET=107, /* FW supports marking the first data packet which wakes the host from suspend */ + WMI_SERVICE_MULTIPLE_MCAST_FILTER_SET=108, /* FW supports command that can add/delete multiple mcast filters */ + /* WMI_SERVICE_HOST_MANAGED_RX_REORDER - + * FW supports host-managed RX reorder. + * Host managed RX reorder involves RX BA state machine handling + * on peer/TID basis, REO configuration for HW based reordering/PN + * check and processing reorder exceptions generated by HW. + */ + WMI_SERVICE_HOST_MANAGED_RX_REORDER=109, + /* Specify whether the target supports the following WMI messages for + * reading / writing its flash memory: + * WMI_READ_DATA_FROM_FLASH_CMDID, + * WMI_READ_DATA_FROM_FLASH_EVENTID, + * WMI_TRANSFER_DATA_TO_FLASH_CMDID, + * WMI_TRANSFER_DATA_TO_FLASH_COMPLETE_EVENTID, + */ + WMI_SERVICE_FLASH_RDWR_SUPPORT=110, + WMI_SERVICE_WLAN_STATS_REPORT=111, /* support WLAN stats report */ + /* WMI_SERVICE_TX_MSDU_ID_NEW_PARTITION_SUPPORT - + * FW supports bigger MSDU ID partition which is defined as HTT_TX_IPA_NEW_MSDU_ID_SPACE_BEGIN + * When both host and FW support new partition, FW uses HTT_TX_IPA_NEW_MSDU_ID_SPACE_BEGIN + * If host doesn't support, FW falls back to HTT_TX_IPA_MSDU_ID_SPACE_BEGIN + * Handshaking is done through WMI_INIT and WMI service ready + */ + WMI_SERVICE_TX_MSDU_ID_NEW_PARTITION_SUPPORT=112, /* support bigger MSDU ID partition */ + WMI_SERVICE_DFS_PHYERR_OFFLOAD=113, + WMI_SERVICE_RCPI_SUPPORT=114, + WMI_SERVICE_FW_MEM_DUMP_SUPPORT=115, /* Support FW Memory dump */ + WMI_SERVICE_PEER_STATS_INFO=116, /* support per peer stats info */ + WMI_SERVICE_REGULATORY_DB=117, /* support regulatory database in FW */ + WMI_SERVICE_11D_OFFLOAD=118, /* support 11D scan offload in FW */ + WMI_SERVICE_HW_DATA_FILTERING=119, + WMI_SERVICE_MULTIPLE_VDEV_RESTART=120, /* Support for single command for multiple vdev restart */ + WMI_SERVICE_PKT_ROUTING=121, /* Support for routing specific data packets to selected destination rings */ + WMI_SERVICE_CHECK_CAL_VERSION=122, /* Support cal version check */ + WMI_SERVICE_OFFCHAN_TX_WMI=123, /* Support offchan data/mgmt tx over wmi */ + WMI_SERVICE_8SS_TX_BFEE = 124, /* support for 8Ant Bfee */ + WMI_SERVICE_EXTENDED_NSS_SUPPORT=125, /* Extend NSS support for 80Mhz and 160Mhz */ + WMI_SERVICE_ACK_TIMEOUT=126, /* Support TX ack timeout configurations */ + WMI_SERVICE_PDEV_BSS_CHANNEL_INFO_64 = 127, /* BSS channel info (freq, noise floor, rx clear, cycles 64-bit counters) event support */ + + WMI_MAX_SERVICE=128, /* max service */ + + /* NOTE: + * The above service flags are delivered in the wmi_service_bitmap field + * of the WMI_SERVICE_READY_EVENT message. + * The below service flags are delivered in a WMI_SERVICE_AVAILABLE_EVENT + * message rather than in the WMI_SERVICE_READY_EVENT message's + * wmi_service_bitmap field. + * The WMI_SERVICE_AVAILABLE_EVENT message immediately precedes the + * WMI_SERVICE_READY_EVENT message. + */ + + WMI_SERVICE_CHAN_LOAD_INFO=128, /* The values in WMI_CHAN_INFO_EVENTID is the difference in cycle counters */ + WMI_SERVICE_TX_PPDU_INFO_STATS_SUPPORT=129, /* support to report tx ppdu info stats via htt events */ + WMI_SERVICE_VDEV_LIMIT_OFFCHAN_SUPPORT=130, /* support to report the offchannel duration limiting capability on connected interface */ + WMI_SERVICE_FILS_SUPPORT=131, /* support for FILS */ + /******* ADD NEW SERVICES HERE *******/ + + WMI_MAX_EXT_SERVICE + +} WMI_SERVICE; + +#define WMI_SERVICE_BM_SIZE ((WMI_MAX_SERVICE + sizeof(A_UINT32)- 1)/sizeof(A_UINT32)) + +#define WMI_NUM_EXT_SERVICES (WMI_MAX_EXT_SERVICE - WMI_MAX_SERVICE) +#define WMI_SERVICE_EXT_BM_SIZE32 ((WMI_NUM_EXT_SERVICES + 31) / 32) + +#define WMI_SERVICE_ROAM_OFFLOAD WMI_SERVICE_ROAM_SCAN_OFFLOAD /* depreciated the name WMI_SERVICE_ROAM_OFFLOAD, but here to help compiling with old host driver */ + +/* + * turn on the WMI service bit corresponding to the WMI service. + */ +#define WMI_SERVICE_ENABLE(pwmi_svc_bmap,svc_id) \ + ( (pwmi_svc_bmap)[(svc_id)/(sizeof(A_UINT32))] |= \ + (1 << ((svc_id)%(sizeof(A_UINT32)))) ) + +#define WMI_SERVICE_DISABLE(pwmi_svc_bmap,svc_id) \ + ( (pwmi_svc_bmap)[(svc_id)/(sizeof(A_UINT32))] &= \ + ( ~(1 << ((svc_id)%(sizeof(A_UINT32)))) ) ) + +#define WMI_SERVICE_IS_ENABLED(pwmi_svc_bmap,svc_id) \ + ( ((pwmi_svc_bmap)[(svc_id)/(sizeof(A_UINT32))] & \ + (1 << ((svc_id)%(sizeof(A_UINT32)))) ) != 0) + + +#define WMI_SERVICE_EXT_ENABLE(pwmi_svc_bmap, pwmi_svc_ext_bmap, svc_id) \ + do { \ + if (svc_id < WMI_MAX_SERVICE) { \ + WMI_SERVICE_ENABLE(pwmi_svc_bmap, svc_id); \ + } else { \ + int word = ((svc_id) - WMI_MAX_SERVICE) / 32; \ + int bit = (svc_id) & 0x1f; /* svc_id mod 32 */ \ + (pwmi_svc_ext_bmap)[word] |= (1 << bit); \ + } \ + } while (0) + +#define WMI_SERVICE_EXT_DISABLE(pwmi_svc_bmap, pwmi_svc_ext_bmap, svc_id) \ + do { \ + if (svc_id < WMI_MAX_SERVICE) { \ + WMI_SERVICE_DISABLE(pwmi_svc_bmap, svc_id); \ + } else { \ + int word = ((svc_id) - WMI_MAX_SERVICE) / 32; \ + int bit = (svc_id) & 0x1f; /* svc_id mod 32 */ \ + (pwmi_svc_ext_bmap)[word] &= ~(1 << bit); \ + } \ + } while (0) + +#define WMI_SERVICE_EXT_IS_ENABLED(pwmi_svc_bmap, pwmi_svc_ext_bmap, svc_id) \ + /* If the service ID is beyond the known limit, treat it as disabled */ \ + ((svc_id) >= WMI_MAX_EXT_SERVICE ? 0 : \ + /* If service ID is in the non-extension range, use the old check */ \ + (svc_id) < WMI_MAX_SERVICE ? \ + WMI_SERVICE_IS_ENABLED(pwmi_svc_bmap, svc_id) : \ + /* If service ID is in the extended range, check ext_bmap */ \ + (pwmi_svc_ext_bmap)[((svc_id) - WMI_MAX_SERVICE) / 32] >> \ + ((svc_id) & 0x1f)) + + +#ifdef __cplusplus +} +#endif + +#endif /*_WMI_SERVICES_H_*/ diff --git a/drivers/staging/fw-api/fw/wmi_tlv_defs.h b/drivers/staging/fw-api/fw/wmi_tlv_defs.h new file mode 100755 index 0000000000000000000000000000000000000000..c4ef582b319067c59d79bc9e7a4f24ec9b3c73f3 --- /dev/null +++ b/drivers/staging/fw-api/fw/wmi_tlv_defs.h @@ -0,0 +1,4547 @@ +/* + * Copyright (c) 2010-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ +/* + * wmi_tlv_defs_expanded.h file can be generated using macro preprocessor output of gcc for ease of debugging and reference by developers + * Following command has to be run from "fw_common\fw_interface\include" directory to create wmi_tlv_defs_expanded.h file + * gcc -E wmi_tlv_defs.h > wmi_tlv_defs_expanded.h on Linux + * and + * gcc -E wmi_tlv_defs.h -o wmi_tlv_defs_expanded.h on Linux/Windows + * + */ +#ifndef _WMI_TLV_DEFS_H_ +#define _WMI_TLV_DEFS_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#define WMITLV_FIELD_BUF_IS_ALLOCATED(elem_name) \ + is_allocated_##elem_name + +#define WMITLV_FIELD_NUM_OF(elem_name) \ + num_##elem_name + +/* Define the structure typedef for the TLV parameters of each cmd/event */ +#define WMITLV_TYPEDEF_STRUCT_PARAMS_TLVS(wmi_cmd_event_id) \ + wmi_cmd_event_id##_param_tlvs + +/* + * The following macro WMITLV_OP_* are created by the macro WMITLV_ELEM(). + */ +/* macro to define the TLV name in the correct order. When (op==TAG_ORDER) */ +#define WMITLV_OP_TAG_ORDER_macro(param_ptr, param_len, wmi_cmd_event_id, elem_tlv_tag, elem_struc_type, elem_name, var_len, arr_size) \ + wmi_cmd_event_id##_tlv_order_##elem_name, + +/* macro to define the TLV name with the TLV Tag value. When (op==TAG_ID) */ +#define WMITLV_OP_TAG_ID_macro(param_ptr, param_len, wmi_cmd_event_id, elem_tlv_tag, elem_struc_type, elem_name, var_len, arr_size) \ + wmi_cmd_event_id##_tlv_tag_##elem_name = elem_tlv_tag, + +/* macro to define the TLV name with the TLV structure size. May not be accurate when variable length. When (op==TAG_SIZEOF) */ +#define WMITLV_OP_TAG_SIZEOF_macro(param_ptr, param_len, wmi_cmd_event_id, elem_tlv_tag, elem_struc_type, elem_name, var_len, arr_size) \ + wmi_cmd_event_id##_sizeof_##elem_name = sizeof(elem_struc_type), + +/* macro to define the TLV name with value indicating whether the TLV is variable length. When (op==TAG_VAR_SIZED) */ +#define WMITLV_OP_TAG_VAR_SIZED_macro(param_ptr, param_len, wmi_cmd_event_id, elem_tlv_tag, elem_struc_type, elem_name, var_len, arr_size) \ + wmi_cmd_event_id##_var_sized_##elem_name = var_len, + +/* macro to define the TLV name with value indicating the fixed array size. When (op==TAG_ARR_SIZE) */ +#define WMITLV_OP_TAG_ARR_SIZE_macro(param_ptr, param_len, wmi_cmd_event_id, elem_tlv_tag, elem_struc_type, elem_name, var_len, arr_size) \ + wmi_cmd_event_id##_arr_size_##elem_name = arr_size, + +/* + * macro to define afew fields associated to a TLV. For example, a structure pointer with the TLV name. + * This macro is expand from WMITLV_ELEM(op) when (op==STRUCT_FIELD). + * NOTE: If this macro is changed, then "mirror" structure wmitlv_cmd_param_info + * should be updated too. + */ +#define WMITLV_OP_STRUCT_FIELD_macro(param_ptr, param_len, wmi_cmd_event_id, elem_tlv_tag, elem_struc_type, elem_name, var_len, arr_size) \ + elem_struc_type *elem_name; \ + A_UINT32 WMITLV_FIELD_NUM_OF(elem_name); \ + A_UINT32 WMITLV_FIELD_BUF_IS_ALLOCATED(elem_name); + +/* + * A "mirror" structure that contains the fields that is created by the + * macro WMITLV_OP_STRUCT_FIELD_macro. + * NOTE: you should modify this structure and WMITLV_OP_STRUCT_FIELD_macro + * so that they both has the same kind of fields. + */ +typedef struct { + void *tlv_ptr; /* Pointer to the TLV Buffer. But the "real" one will have the right type instead of void. */ + A_UINT32 num_elements; /* Number of elements. For non-array, this is one. For array, this is the number of elements. */ + A_UINT32 buf_is_allocated;/* Boolean flag to indicate that a new buffer is allocated for this TLV. */ +} wmitlv_cmd_param_info; + +/* + * NOTE TRICKY MACRO: + * WMITLV_ELEM is re-defined to a "op" specific macro. + * Eg. WMITLV_OP_TAG_ORDER_macro is created for the op_type=TAG_ORDER. + */ +#define WMITLV_ELEM(wmi_cmd_event_id, op_type, param_ptr, param_len, elem_tlv_tag, elem_struc_type, elem_name, var_len) \ + WMITLV_OP_##op_type##_macro(param_ptr, param_len, wmi_cmd_event_id, elem_tlv_tag, elem_struc_type, elem_name, var_len, WMITLV_ARR_SIZE_INVALID) +/* + * WMITLV_FXAR (FiX ARray) is similar to WMITLV_ELEM except it has an extra parameter for the fixed number of elements. + * It is re-defined to a "op" specific macro. + * Eg. WMITLV_OP_TAG_ORDER_macro is created for the op_type=TAG_ORDER. + */ +#define WMITLV_FXAR(wmi_cmd_event_id, op_type, param_ptr, param_len, elem_tlv_tag, elem_struc_type, elem_name, var_len, arr_size) \ + WMITLV_OP_##op_type##_macro(param_ptr, param_len, wmi_cmd_event_id, elem_tlv_tag, elem_struc_type, elem_name, var_len, arr_size) + +#define WMITLV_TABLE(id,op,buf,len) WMITLV_TABLE_##id(id,op,buf,len) + +/* + * This macro will create various enumerations and structures to describe the TLVs for + * the given Command/Event ID. + * + * For example, the following is for WMI_SERVICE_READY_EVENTID: + * #define WMITLV_TABLE_WMI_SERVICE_READY_EVENTID(id,op,buf,len) \ + * WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_service_ready_event_fixed_param, wmi_service_ready_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + * WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_HAL_REG_CAPABILITIES, HAL_REG_CAPABILITIES, hal_reg_capabilities, WMITLV_SIZE_FIX) \ + * WMITLV_FXAR(id,op,buf,len, WMITLV_TAG_ARRAY_UINT32, A_UINT32, wmi_service_bitmap, WMITLV_SIZE_FIX, WMI_SERVICE_BM_SIZE) \ + * WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wlan_host_mem_req, mem_reqs, WMITLV_SIZE_VAR) + * WMITLV_CREATE_PARAM_STRUC(WMI_SERVICE_READY_EVENTID); + * This macro will create the following text: + * + * typedef enum { + * WMI_SERVICE_READY_EVENTID_tlv_order_wmi_service_ready_event_fixed_param, + * WMI_SERVICE_READY_EVENTID_tlv_order_hal_reg_capabilities, + * WMI_SERVICE_READY_EVENTID_tlv_order_wmi_service_bitmap, + * WMI_SERVICE_READY_EVENTID_tlv_order_mem_reqs, + * WMI_TLV_HLPR_NUM_TLVS_FOR_WMI_SERVICE_READY_EVENTID + * } WMI_SERVICE_READY_EVENTID_TAG_ID_enum_type; + * //NOTE: WMI_TLV_HLPR_NUM_TLVS_FOR_WMI_SERVICE_READY_EVENTID is the number of TLVs. + * + * typedef enum { + * WMI_SERVICE_READY_EVENTID_tlv_tag_wmi_service_ready_event_fixed_param = WMITLV_TAG_STRUC_wmi_service_ready_event_fixed_param, + * WMI_SERVICE_READY_EVENTID_tlv_tag_hal_reg_capabilities = WMITLV_TAG_STRUC_HAL_REG_CAPABILITIES, + * WMI_SERVICE_READY_EVENTID_tlv_tag_wmi_service_bitmap = WMITLV_TAG_ARRAY_UINT32, + * WMI_SERVICE_READY_EVENTID_tlv_tag_mem_reqs = WMITLV_TAG_ARRAY_STRUC, + * } WMI_SERVICE_READY_EVENTID_TAG_ORDER_enum_type; + * + * typedef enum { + * WMI_SERVICE_READY_EVENTID_sizeof_wmi_service_ready_event_fixed_param = sizeof(wmi_service_ready_event_fixed_param), + * WMI_SERVICE_READY_EVENTID_sizeof_hal_reg_capabilities = sizeof(HAL_REG_CAPABILITIES), + * WMI_SERVICE_READY_EVENTID_sizeof_wmi_service_bitmap = sizeof(A_UINT32), + * WMI_SERVICE_READY_EVENTID_sizeof_mem_reqs = sizeof(wlan_host_mem_req), + * } WMI_SERVICE_READY_EVENTID_TAG_SIZEOF_enum_type; + * + * typedef enum { + * WMI_SERVICE_READY_EVENTID_var_sized_wmi_service_ready_event_fixed_param = WMITLV_SIZE_FIX, + * WMI_SERVICE_READY_EVENTID_var_sized_hal_reg_capabilities = WMITLV_SIZE_FIX, + * WMI_SERVICE_READY_EVENTID_var_sized_wmi_service_bitmap = WMITLV_SIZE_VAR, + * WMI_SERVICE_READY_EVENTID_var_sized_mem_reqs = WMITLV_SIZE_VAR, + * } WMI_SERVICE_READY_EVENTID_TAG_VAR_SIZED_enum_type; + * + * typedef enum { + * WMI_SERVICE_READY_EVENTID_arr_size_wmi_service_ready_event_fixed_param = WMITLV_ARR_SIZE_INVALID, + * WMI_SERVICE_READY_EVENTID_arr_size_hal_reg_capabilities = WMITLV_ARR_SIZE_INVALID, + * WMI_SERVICE_READY_EVENTID_arr_size_wmi_service_bitmap = WMI_SERVICE_BM_SIZE, + * WMI_SERVICE_READY_EVENTID_arr_size_mem_reqs = WMITLV_ARR_SIZE_INVALID, + * } WMI_SERVICE_READY_EVENTID_TAG_ARR_SIZE_enum_type; + * + * typedef struct { + * wmi_service_ready_event_fixed_param *fixed_param; + * A_UINT32 num_fixed_param; + * A_UINT32 is_allocated_fixed_param; + * HAL_REG_CAPABILITIES *hal_reg_capabilities; + * A_UINT32 num_hal_reg_capabilities; + * A_UINT32 is_allocated_hal_reg_capabilities; + * A_UINT32 *wmi_service_bitmap; + * A_UINT32 num_wmi_service_bitmap; + * A_UINT32 is_allocated_wmi_service_bitmap; + * wlan_host_mem_req *mem_reqs; + * A_UINT32 num_mem_reqs; + * A_UINT32 is_allocated_mem_reqs; + * + * } WMI_SERVICE_READY_EVENTID_param_tlvs; + * + */ + +#define WMITLV_CREATE_PARAM_STRUC(wmi_cmd_event_id) \ + typedef enum { \ + WMITLV_TABLE(wmi_cmd_event_id, TAG_ORDER, NULL, 0) \ + WMI_TLV_HLPR_NUM_TLVS_FOR_##wmi_cmd_event_id \ + } wmi_cmd_event_id##_TAG_ORDER_enum_type; \ + \ + typedef struct { \ + WMITLV_TABLE(wmi_cmd_event_id, STRUCT_FIELD, NULL, 0) \ + } WMITLV_TYPEDEF_STRUCT_PARAMS_TLVS(wmi_cmd_event_id); \ + +/** Enum list of TLV Tags for each parameter structure type. */ +typedef enum { + /* 0 to 15 is reserved */ + WMITLV_TAG_LAST_RESERVED = 15, + WMITLV_TAG_FIRST_ARRAY_ENUM, /* First entry of ARRAY type tags */ + WMITLV_TAG_ARRAY_UINT32 = WMITLV_TAG_FIRST_ARRAY_ENUM, + WMITLV_TAG_ARRAY_BYTE, + WMITLV_TAG_ARRAY_STRUC, + WMITLV_TAG_ARRAY_FIXED_STRUC, + WMITLV_TAG_LAST_ARRAY_ENUM = 31, /* Last entry of ARRAY type tags */ + WMITLV_TAG_STRUC_wmi_service_ready_event_fixed_param, + WMITLV_TAG_STRUC_HAL_REG_CAPABILITIES, + WMITLV_TAG_STRUC_wlan_host_mem_req, + WMITLV_TAG_STRUC_wmi_ready_event_fixed_param, + WMITLV_TAG_STRUC_wmi_scan_event_fixed_param, + WMITLV_TAG_STRUC_wmi_pdev_tpc_config_event_fixed_param, + WMITLV_TAG_STRUC_wmi_chan_info_event_fixed_param, + WMITLV_TAG_STRUC_wmi_comb_phyerr_rx_hdr, + WMITLV_TAG_STRUC_wmi_vdev_start_response_event_fixed_param, + WMITLV_TAG_STRUC_wmi_vdev_stopped_event_fixed_param, + WMITLV_TAG_STRUC_wmi_vdev_install_key_complete_event_fixed_param, + WMITLV_TAG_STRUC_wmi_peer_sta_kickout_event_fixed_param, + WMITLV_TAG_STRUC_wmi_mgmt_rx_hdr, + WMITLV_TAG_STRUC_wmi_tbtt_offset_event_fixed_param, + WMITLV_TAG_STRUC_wmi_tx_delba_complete_event_fixed_param, + WMITLV_TAG_STRUC_wmi_tx_addba_complete_event_fixed_param, + WMITLV_TAG_STRUC_wmi_roam_event_fixed_param, + WMITLV_TAG_STRUC_WOW_EVENT_INFO_fixed_param, + WMITLV_TAG_STRUC_WOW_EVENT_INFO_SECTION_BITMAP, + WMITLV_TAG_STRUC_wmi_rtt_event_header, + WMITLV_TAG_STRUC_wmi_rtt_error_report_event_fixed_param, + WMITLV_TAG_STRUC_wmi_rtt_meas_event_fixed_param, + WMITLV_TAG_STRUC_wmi_echo_event_fixed_param, + WMITLV_TAG_STRUC_wmi_ftm_intg_event_fixed_param, + WMITLV_TAG_STRUC_wmi_vdev_get_keepalive_event_fixed_param, + WMITLV_TAG_STRUC_wmi_gpio_input_event_fixed_param, + WMITLV_TAG_STRUC_wmi_csa_event_fixed_param, + WMITLV_TAG_STRUC_WMI_GTK_OFFLOAD_STATUS_EVENT_fixed_param, + WMITLV_TAG_STRUC_wmi_igtk_info, + WMITLV_TAG_STRUC_wmi_dcs_interference_event_fixed_param, + WMITLV_TAG_STRUC_ath_dcs_cw_int, /* DEPRECATED */ + WMITLV_TAG_STRUC_wlan_dcs_cw_int = /* alias */ + WMITLV_TAG_STRUC_ath_dcs_cw_int, + WMITLV_TAG_STRUC_ath_dcs_wlan_int_stat, /* DEPRECATED */ + WMITLV_TAG_STRUC_wlan_dcs_im_tgt_stats_t = /* alias */ + WMITLV_TAG_STRUC_ath_dcs_wlan_int_stat, + WMITLV_TAG_STRUC_wmi_wlan_profile_ctx_t, + WMITLV_TAG_STRUC_wmi_wlan_profile_t, + WMITLV_TAG_STRUC_wmi_pdev_qvit_event_fixed_param, + WMITLV_TAG_STRUC_wmi_host_swba_event_fixed_param, + WMITLV_TAG_STRUC_wmi_tim_info, + WMITLV_TAG_STRUC_wmi_p2p_noa_info, + WMITLV_TAG_STRUC_wmi_stats_event_fixed_param, + WMITLV_TAG_STRUC_wmi_avoid_freq_ranges_event_fixed_param, + WMITLV_TAG_STRUC_wmi_avoid_freq_range_desc, + WMITLV_TAG_STRUC_wmi_gtk_rekey_fail_event_fixed_param, + WMITLV_TAG_STRUC_wmi_init_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_resource_config, + WMITLV_TAG_STRUC_wlan_host_memory_chunk, + WMITLV_TAG_STRUC_wmi_start_scan_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_stop_scan_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_scan_chan_list_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_channel, + WMITLV_TAG_STRUC_wmi_pdev_set_regdomain_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_pdev_set_param_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_pdev_set_wmm_params_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_wmm_params, + WMITLV_TAG_STRUC_wmi_pdev_set_quiet_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_vdev_create_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_vdev_delete_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_vdev_start_request_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_p2p_noa_descriptor, + WMITLV_TAG_STRUC_wmi_p2p_go_set_beacon_ie_fixed_param, + WMITLV_TAG_STRUC_WMI_GTK_OFFLOAD_CMD_fixed_param, + WMITLV_TAG_STRUC_wmi_vdev_up_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_vdev_stop_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_vdev_down_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_vdev_set_param_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_vdev_install_key_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_peer_create_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_peer_delete_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_peer_flush_tids_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_peer_set_param_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_peer_assoc_complete_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_vht_rate_set, + WMITLV_TAG_STRUC_wmi_bcn_tmpl_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_prb_tmpl_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_bcn_prb_info, + WMITLV_TAG_STRUC_wmi_peer_tid_addba_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_peer_tid_delba_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_sta_powersave_mode_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_sta_powersave_param_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_sta_dtim_ps_method_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_roam_scan_mode_fixed_param, + WMITLV_TAG_STRUC_wmi_roam_scan_rssi_threshold_fixed_param, + WMITLV_TAG_STRUC_wmi_roam_scan_period_fixed_param, + WMITLV_TAG_STRUC_wmi_roam_scan_rssi_change_threshold_fixed_param, + WMITLV_TAG_STRUC_wmi_pdev_suspend_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_pdev_resume_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_add_bcn_filter_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_rmv_bcn_filter_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_wow_enable_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_wow_hostwakeup_from_sleep_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_sta_uapsd_auto_trig_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_sta_uapsd_auto_trig_param, + WMITLV_TAG_STRUC_WMI_SET_ARP_NS_OFFLOAD_CMD_fixed_param, + WMITLV_TAG_STRUC_WMI_ARP_OFFLOAD_TUPLE, + WMITLV_TAG_STRUC_WMI_NS_OFFLOAD_TUPLE, + WMITLV_TAG_STRUC_wmi_ftm_intg_cmd_fixed_param, + WMITLV_TAG_STRUC_WMI_STA_KEEPALIVE_CMD_fixed_param, + WMITLV_TAG_STRUC_WMI_STA_KEEPALVE_ARP_RESPONSE, + WMITLV_TAG_STRUC_wmi_p2p_set_vendor_ie_data_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_ap_ps_peer_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_peer_rate_retry_sched_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_wlan_profile_trigger_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_wlan_profile_set_hist_intvl_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_wlan_profile_get_prof_data_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_wlan_profile_enable_profile_id_cmd_fixed_param, + WMITLV_TAG_STRUC_WMI_WOW_DEL_PATTERN_CMD_fixed_param, + WMITLV_TAG_STRUC_WMI_WOW_ADD_DEL_EVT_CMD_fixed_param, + WMITLV_TAG_STRUC_wmi_rtt_measreq_head, + WMITLV_TAG_STRUC_wmi_rtt_measreq_body, + WMITLV_TAG_STRUC_wmi_rtt_tsf_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_vdev_spectral_configure_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_vdev_spectral_enable_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_request_stats_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_nlo_config_cmd_fixed_param, + WMITLV_TAG_STRUC_nlo_configured_parameters, + WMITLV_TAG_STRUC_wmi_csa_offload_enable_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_csa_offload_chanswitch_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_chatter_set_mode_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_echo_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_vdev_set_keepalive_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_vdev_get_keepalive_cmd_fixed_param, + WMITLV_TAG_STRUC_WMI_FORCE_FW_HANG_CMD_fixed_param, + WMITLV_TAG_STRUC_wmi_gpio_config_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_gpio_output_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_peer_add_wds_entry_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_peer_remove_wds_entry_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_bcn_tx_hdr, + WMITLV_TAG_STRUC_wmi_bcn_send_from_host_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_mgmt_tx_hdr, + WMITLV_TAG_STRUC_wmi_addba_clear_resp_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_addba_send_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_delba_send_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_addba_setresponse_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_send_singleamsdu_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_pdev_pktlog_enable_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_pdev_pktlog_disable_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_pdev_set_ht_ie_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_pdev_set_vht_ie_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_pdev_set_dscp_tid_map_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_pdev_green_ap_ps_enable_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_pdev_get_tpc_config_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_pdev_set_base_macaddr_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_peer_mcast_group_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_roam_ap_profile_fixed_param, + WMITLV_TAG_STRUC_wmi_ap_profile, + WMITLV_TAG_STRUC_wmi_scan_sch_priority_table_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_pdev_dfs_enable_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_pdev_dfs_disable_cmd_fixed_param, + WMITLV_TAG_STRUC_WMI_WOW_ADD_PATTERN_CMD_fixed_param, + WMITLV_TAG_STRUC_WOW_BITMAP_PATTERN_T, + WMITLV_TAG_STRUC_WOW_IPV4_SYNC_PATTERN_T, + WMITLV_TAG_STRUC_WOW_IPV6_SYNC_PATTERN_T, + WMITLV_TAG_STRUC_WOW_MAGIC_PATTERN_CMD, + WMITLV_TAG_STRUC_WMI_scan_update_request_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_chatter_pkt_coalescing_filter, + WMITLV_TAG_STRUC_wmi_chatter_coalescing_add_filter_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_chatter_coalescing_delete_filter_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_chatter_coalescing_query_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_txbf_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_debug_log_config_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_nlo_event, + WMITLV_TAG_STRUC_wmi_chatter_query_reply_event_fixed_param, + WMITLV_TAG_STRUC_wmi_upload_h_hdr, + WMITLV_TAG_STRUC_wmi_capture_h_event_hdr, + WMITLV_TAG_STRUC_WMI_VDEV_WNM_SLEEPMODE_CMD_fixed_param, + WMITLV_TAG_STRUC_WMI_VDEV_IPSEC_NATKEEPALIVE_FILTER_CMD_fixed_param, + WMITLV_TAG_STRUC_wmi_vdev_wmm_addts_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_vdev_wmm_delts_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_vdev_set_wmm_params_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_tdls_set_state_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_tdls_peer_update_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_tdls_peer_event_fixed_param, + WMITLV_TAG_STRUC_wmi_tdls_peer_capabilities, + WMITLV_TAG_STRUC_wmi_vdev_mcc_set_tbtt_mode_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_roam_chan_list_fixed_param, + WMITLV_TAG_STRUC_wmi_vdev_mcc_bcn_intvl_change_event_fixed_param, + WMITLV_TAG_STRUC_wmi_resmgr_adaptive_ocs_enable_disable_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_resmgr_set_chan_time_quota_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_resmgr_set_chan_latency_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_ba_req_ssn_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_ba_rsp_ssn_event_fixed_param, + WMITLV_TAG_STRUC_wmi_sta_smps_force_mode_cmd_fixed_param, + WMITLV_TAG_STRUC_WMI_SET_MCASTBCAST_FILTER_CMD_fixed_param, + WMITLV_TAG_STRUC_wmi_p2p_set_oppps_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_p2p_set_noa_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_ba_req_ssn_cmd_sub_struct_param, + WMITLV_TAG_STRUC_wmi_ba_req_ssn_event_sub_struct_param, + WMITLV_TAG_STRUC_wmi_sta_smps_param_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_vdev_set_gtx_params_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_mcc_sched_traffic_stats_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_mcc_sched_sta_traffic_stats, + WMITLV_TAG_STRUC_wmi_offload_bcn_tx_status_event_fixed_param, + WMITLV_TAG_STRUC_wmi_p2p_noa_event_fixed_param, + WMITLV_TAG_STRUC_wmi_hb_set_enable_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_hb_set_tcp_params_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_hb_set_tcp_pkt_filter_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_hb_set_udp_params_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_hb_set_udp_pkt_filter_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_hb_ind_event_fixed_param, + WMITLV_TAG_STRUC_wmi_tx_pause_event_fixed_param, + WMITLV_TAG_STRUC_wmi_rfkill_event_fixed_param, + WMITLV_TAG_STRUC_wmi_dfs_radar_event_fixed_param, + WMITLV_TAG_STRUC_wmi_dfs_phyerr_filter_ena_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_dfs_phyerr_filter_dis_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_batch_scan_result_scan_list, + WMITLV_TAG_STRUC_wmi_batch_scan_result_network_info, + WMITLV_TAG_STRUC_wmi_batch_scan_enable_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_batch_scan_disable_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_batch_scan_trigger_result_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_batch_scan_enabled_event_fixed_param, + WMITLV_TAG_STRUC_wmi_batch_scan_result_event_fixed_param, + WMITLV_TAG_STRUC_wmi_vdev_plmreq_start_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_vdev_plmreq_stop_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_thermal_mgmt_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_thermal_mgmt_event_fixed_param, + WMITLV_TAG_STRUC_wmi_peer_info_req_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_peer_info_event_fixed_param, + WMITLV_TAG_STRUC_wmi_peer_info, + WMITLV_TAG_STRUC_wmi_peer_tx_fail_cnt_thr_event_fixed_param, + WMITLV_TAG_STRUC_wmi_rmc_set_mode_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_rmc_set_action_period_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_rmc_config_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_mhf_offload_set_mode_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_mhf_offload_plumb_routing_table_cmd_fixed_param, + WMITLV_TAG_STRUC_WMI_ADD_PROACTIVE_ARP_RSP_PATTERN_CMD_fixed_param, + WMITLV_TAG_STRUC_WMI_DEL_PROACTIVE_ARP_RSP_PATTERN_CMD_fixed_param, + WMITLV_TAG_STRUC_wmi_nan_cmd_param, + WMITLV_TAG_STRUC_wmi_nan_event_hdr, + WMITLV_TAG_STRUC_wmi_pdev_l1ss_track_event_fixed_param, + WMITLV_TAG_STRUC_wmi_diag_data_container_event_fixed_param, + WMITLV_TAG_STRUC_wmi_modem_power_state_cmd_param, + WMITLV_TAG_STRUC_wmi_peer_get_estimated_linkspeed_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_peer_estimated_linkspeed_event_fixed_param, + WMITLV_TAG_STRUC_wmi_aggr_state_trig_event_fixed_param, + WMITLV_TAG_STRUC_wmi_mhf_offload_routing_table_entry, + WMITLV_TAG_STRUC_wmi_roam_scan_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_req_stats_ext_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_stats_ext_event_fixed_param, + WMITLV_TAG_STRUC_wmi_obss_scan_enable_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_obss_scan_disable_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_offload_prb_rsp_tx_status_event_fixed_param, + WMITLV_TAG_STRUC_wmi_pdev_set_led_config_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_host_auto_shutdown_cfg_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_host_auto_shutdown_event_fixed_param, + WMITLV_TAG_STRUC_wmi_update_whal_mib_stats_event_fixed_param, + WMITLV_TAG_STRUC_wmi_chan_avoid_update_cmd_param, + WMITLV_TAG_STRUC_WOW_IOAC_PKT_PATTERN_T, + WMITLV_TAG_STRUC_WOW_IOAC_TMR_PATTERN_T, + WMITLV_TAG_STRUC_WMI_WOW_IOAC_ADD_KEEPALIVE_CMD_fixed_param, + WMITLV_TAG_STRUC_WMI_WOW_IOAC_DEL_KEEPALIVE_CMD_fixed_param, + WMITLV_TAG_STRUC_WMI_WOW_IOAC_KEEPALIVE_T, + WMITLV_TAG_STRUC_WMI_WOW_IOAC_ADD_PATTERN_CMD_fixed_param, + WMITLV_TAG_STRUC_WMI_WOW_IOAC_DEL_PATTERN_CMD_fixed_param, + WMITLV_TAG_STRUC_wmi_start_link_stats_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_clear_link_stats_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_request_link_stats_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_iface_link_stats_event_fixed_param, + WMITLV_TAG_STRUC_wmi_radio_link_stats_event_fixed_param, + WMITLV_TAG_STRUC_wmi_peer_stats_event_fixed_param, + WMITLV_TAG_STRUC_wmi_channel_stats, + WMITLV_TAG_STRUC_wmi_radio_link_stats, + WMITLV_TAG_STRUC_wmi_rate_stats, + WMITLV_TAG_STRUC_wmi_peer_link_stats, + WMITLV_TAG_STRUC_wmi_wmm_ac_stats, + WMITLV_TAG_STRUC_wmi_iface_link_stats, + WMITLV_TAG_STRUC_wmi_lpi_mgmt_snooping_config_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_lpi_start_scan_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_lpi_stop_scan_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_lpi_result_event_fixed_param, + WMITLV_TAG_STRUC_wmi_peer_state_event_fixed_param, + WMITLV_TAG_STRUC_wmi_extscan_bucket_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_extscan_bucket_channel_event_fixed_param, + WMITLV_TAG_STRUC_wmi_extscan_start_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_extscan_stop_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_extscan_configure_wlan_change_monitor_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_extscan_wlan_change_bssid_param_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_extscan_configure_hotlist_monitor_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_extscan_get_cached_results_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_extscan_get_wlan_change_results_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_extscan_set_capabilities_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_extscan_get_capabilities_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_extscan_operation_event_fixed_param, + WMITLV_TAG_STRUC_wmi_extscan_start_stop_event_fixed_param, + WMITLV_TAG_STRUC_wmi_extscan_table_usage_event_fixed_param, + WMITLV_TAG_STRUC_wmi_extscan_wlan_descriptor_event_fixed_param, + WMITLV_TAG_STRUC_wmi_extscan_rssi_info_event_fixed_param, + WMITLV_TAG_STRUC_wmi_extscan_cached_results_event_fixed_param, + WMITLV_TAG_STRUC_wmi_extscan_wlan_change_results_event_fixed_param, + WMITLV_TAG_STRUC_wmi_extscan_wlan_change_result_bssid_event_fixed_param, + WMITLV_TAG_STRUC_wmi_extscan_hotlist_match_event_fixed_param, + WMITLV_TAG_STRUC_wmi_extscan_capabilities_event_fixed_param, + WMITLV_TAG_STRUC_wmi_extscan_cache_capabilities_event_fixed_param, + WMITLV_TAG_STRUC_wmi_extscan_wlan_change_monitor_capabilities_event_fixed_param, + WMITLV_TAG_STRUC_wmi_extscan_hotlist_monitor_capabilities_event_fixed_param, + WMITLV_TAG_STRUC_wmi_d0_wow_enable_disable_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_d0_wow_disable_ack_event_fixed_param, + WMITLV_TAG_STRUC_wmi_unit_test_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_roam_offload_tlv_param, + WMITLV_TAG_STRUC_wmi_roam_11i_offload_tlv_param, + WMITLV_TAG_STRUC_wmi_roam_11r_offload_tlv_param, + WMITLV_TAG_STRUC_wmi_roam_ese_offload_tlv_param, + WMITLV_TAG_STRUC_wmi_roam_synch_event_fixed_param, + WMITLV_TAG_STRUC_wmi_roam_synch_complete_fixed_param, + WMITLV_TAG_STRUC_wmi_extwow_enable_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_extwow_set_app_type1_params_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_extwow_set_app_type2_params_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_lpi_status_event_fixed_param, + WMITLV_TAG_STRUC_wmi_lpi_handoff_event_fixed_param, + WMITLV_TAG_STRUC_wmi_vdev_rate_stats_event_fixed_param, + WMITLV_TAG_STRUC_wmi_vdev_rate_ht_info, + WMITLV_TAG_STRUC_wmi_ric_request_fixed_param, + WMITLV_TAG_STRUC_wmi_pdev_get_temperature_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_pdev_temperature_event_fixed_param, + WMITLV_TAG_STRUC_wmi_set_dhcp_server_offload_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_tpc_chainmask_config_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_ric_tspec, + WMITLV_TAG_STRUC_wmi_tpc_chainmask_config, + WMITLV_TAG_STRUCT_wmi_ipa_offload_enable_disable_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_scan_prob_req_oui_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_key_material, + WMITLV_TAG_STRUC_wmi_tdls_set_offchan_mode_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_set_led_flashing_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_mdns_offload_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_mdns_set_fqdn_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_mdns_set_resp_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_mdns_get_stats_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_mdns_stats_event_fixed_param, + WMITLV_TAG_STRUC_wmi_roam_invoke_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_pdev_resume_event_fixed_param, + WMITLV_TAG_STRUC_wmi_pdev_set_antenna_diversity_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_sap_ofl_enable_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_sap_ofl_add_sta_event_fixed_param, + WMITLV_TAG_STRUC_wmi_sap_ofl_del_sta_event_fixed_param, + WMITLV_TAG_STRUC_wmi_apfind_cmd_param, + WMITLV_TAG_STRUC_wmi_apfind_event_hdr, + WMITLV_TAG_STRUC_wmi_ocb_set_sched_cmd_fixed_param, // DEPRECATED + WMITLV_TAG_STRUC_wmi_ocb_set_sched_event_fixed_param, // DEPRECATED + WMITLV_TAG_STRUC_wmi_ocb_set_config_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_ocb_set_config_resp_event_fixed_param, + WMITLV_TAG_STRUC_wmi_ocb_set_utc_time_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_ocb_start_timing_advert_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_ocb_stop_timing_advert_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_ocb_get_tsf_timer_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_ocb_get_tsf_timer_resp_event_fixed_param, + WMITLV_TAG_STRUC_wmi_dcc_get_stats_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_dcc_channel_stats_request, + WMITLV_TAG_STRUC_wmi_dcc_get_stats_resp_event_fixed_param, + WMITLV_TAG_STRUC_wmi_dcc_clear_stats_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_dcc_update_ndl_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_dcc_update_ndl_resp_event_fixed_param, + WMITLV_TAG_STRUC_wmi_dcc_stats_event_fixed_param, + WMITLV_TAG_STRUC_wmi_ocb_channel, + WMITLV_TAG_STRUC_wmi_ocb_schedule_element, + WMITLV_TAG_STRUC_wmi_dcc_ndl_stats_per_channel, + WMITLV_TAG_STRUC_wmi_dcc_ndl_chan, + WMITLV_TAG_STRUC_wmi_qos_parameter, + WMITLV_TAG_STRUC_wmi_dcc_ndl_active_state_config, + WMITLV_TAG_STRUC_wmi_roam_scan_extended_threshold_param, + WMITLV_TAG_STRUC_wmi_roam_filter_fixed_param, + WMITLV_TAG_STRUC_wmi_passpoint_config_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_passpoint_event_hdr, + WMITLV_TAG_STRUC_wmi_extscan_configure_hotlist_ssid_monitor_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_extscan_hotlist_ssid_match_event_fixed_param, + WMITLV_TAG_STRUC_wmi_vdev_tsf_tstamp_action_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_vdev_tsf_report_event_fixed_param, + WMITLV_TAG_STRUC_wmi_get_fw_mem_dump_fixed_param, + WMITLV_TAG_STRUC_wmi_update_fw_mem_dump_fixed_param, + WMITLV_TAG_STRUC_wmi_fw_mem_dump_params, + WMITLV_TAG_STRUC_wmi_debug_mesg_flush_fixed_param, + WMITLV_TAG_STRUC_wmi_debug_mesg_flush_complete_fixed_param, + WMITLV_TAG_STRUC_wmi_peer_set_rate_report_condition_fixed_param, + WMITLV_TAG_STRUC_wmi_roam_subnet_change_config_fixed_param, + WMITLV_TAG_STRUC_wmi_vdev_set_ie_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_rssi_breach_monitor_config_fixed_param, + WMITLV_TAG_STRUC_wmi_rssi_breach_event_fixed_param, + WMITLV_TAG_STRUC_WOW_EVENT_INITIAL_WAKEUP_fixed_param, + WMITLV_TAG_STRUC_wmi_soc_set_pcl_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_soc_set_hw_mode_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_soc_set_hw_mode_response_event_fixed_param, + WMITLV_TAG_STRUC_wmi_soc_hw_mode_transition_event_fixed_param, + WMITLV_TAG_STRUC_wmi_vdev_txrx_streams, + WMITLV_TAG_STRUC_wmi_soc_set_hw_mode_response_vdev_mac_entry, + WMITLV_TAG_STRUC_wmi_soc_set_dual_mac_config_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_soc_set_dual_mac_config_response_event_fixed_param, + WMITLV_TAG_STRUC_WOW_IOAC_SOCK_PATTERN_T, + WMITLV_TAG_STRUC_wmi_wow_enable_icmpv6_na_flt_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_diag_event_log_config_fixed_param, + WMITLV_TAG_STRUC_wmi_diag_event_log_supported_event_fixed_params, + WMITLV_TAG_STRUC_wmi_packet_filter_config_fixed_param, + WMITLV_TAG_STRUC_wmi_packet_filter_enable_fixed_param, + WMITLV_TAG_STRUC_wmi_sap_set_blacklist_param_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_mgmt_tx_send_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_mgmt_tx_compl_event_fixed_param, + WMITLV_TAG_STRUC_wmi_soc_set_antenna_mode_cmd_fixed_param, + WMITLV_TAG_STRUC_WMI_WOW_UDP_SVC_OFLD_CMD_fixed_param, + WMITLV_TAG_STRUC_wmi_lro_info_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_roam_earlystop_rssi_thres_param, + WMITLV_TAG_STRUC_wmi_service_ready_ext_event_fixed_param, + WMITLV_TAG_STRUC_wmi_mawc_sensor_report_ind_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_mawc_enable_sensor_event_fixed_param, + WMITLV_TAG_STRUC_wmi_roam_configure_mawc_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_nlo_configure_mawc_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_extscan_configure_mawc_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_peer_assoc_conf_event_fixed_param, + WMITLV_TAG_STRUC_wmi_wow_hostwakeup_gpio_pin_pattern_config_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_ap_ps_egap_param_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_ap_ps_egap_info_event_fixed_param, + WMITLV_TAG_STRUC_WMI_PMF_OFFLOAD_SET_SA_QUERY_CMD_fixed_param, + WMITLV_TAG_STRUC_wmi_transfer_data_to_flash_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_transfer_data_to_flash_complete_event_fixed_param, + WMITLV_TAG_STRUC_wmi_scpc_event_fixed_param, + WMITLV_TAG_STRUC_wmi_ap_ps_egap_info_chainmask_list, + WMITLV_TAG_STRUC_wmi_sta_smps_force_mode_complete_event_fixed_param, + WMITLV_TAG_STRUC_wmi_bpf_get_capability_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_bpf_capability_info_evt_fixed_param, + WMITLV_TAG_STRUC_wmi_bpf_get_vdev_stats_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_bpf_vdev_stats_info_evt_fixed_param, + WMITLV_TAG_STRUC_wmi_bpf_set_vdev_instructions_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_bpf_del_vdev_instructions_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_vdev_delete_resp_event_fixed_param, + WMITLV_TAG_STRUC_wmi_peer_delete_resp_event_fixed_param, + WMITLV_TAG_STRUC_wmi_roam_dense_thres_param, + WMITLV_TAG_STRUC_enlo_candidate_score_param, + WMITLV_TAG_STRUC_wmi_peer_update_wds_entry_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_vdev_config_ratemask_fixed_param, + WMITLV_TAG_STRUC_wmi_pdev_fips_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_pdev_smart_ant_enable_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_pdev_smart_ant_set_rx_antenna_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_peer_smart_ant_set_tx_antenna_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_peer_smart_ant_set_train_antenna_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_peer_smart_ant_set_node_config_ops_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_pdev_set_ant_switch_tbl_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_pdev_set_ctl_table_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_pdev_set_mimogain_table_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_fwtest_set_param_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_peer_atf_request_fixed_param, + WMITLV_TAG_STRUC_wmi_vdev_atf_request_fixed_param, + WMITLV_TAG_STRUC_wmi_pdev_get_ani_cck_config_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_pdev_get_ani_ofdm_config_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_inst_rssi_stats_resp_fixed_param, + WMITLV_TAG_STRUC_wmi_med_util_report_event_fixed_param, + WMITLV_TAG_STRUC_wmi_peer_sta_ps_statechange_event_fixed_param, + WMITLV_TAG_STRUC_wmi_wds_addr_event_fixed_param, + WMITLV_TAG_STRUC_wmi_peer_ratecode_list_event_fixed_param, + WMITLV_TAG_STRUC_wmi_pdev_nfcal_power_all_channels_event_fixed_param, + WMITLV_TAG_STRUC_wmi_pdev_tpc_event_fixed_param, + WMITLV_TAG_STRUC_wmi_ani_ofdm_event_fixed_param, + WMITLV_TAG_STRUC_wmi_ani_cck_event_fixed_param, + WMITLV_TAG_STRUC_wmi_pdev_channel_hopping_event_fixed_param, + WMITLV_TAG_STRUC_wmi_pdev_fips_event_fixed_param, + WMITLV_TAG_STRUC_wmi_atf_peer_info, + WMITLV_TAG_STRUC_wmi_pdev_get_tpc_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_vdev_filter_nrp_config_cmd_fixed_param, + WMITLV_TAG_STRUC_WMI_QBOOST_CFG_CMD_fixed_param, + WMITLV_TAG_STRUC_wmi_pdev_smart_ant_gpio_handle, + WMITLV_TAG_STRUC_wmi_peer_smart_ant_set_tx_antenna_series, + WMITLV_TAG_STRUC_wmi_peer_smart_ant_set_train_antenna_param, + WMITLV_TAG_STRUC_wmi_pdev_set_ant_ctrl_chain, + WMITLV_TAG_STRUC_wmi_peer_cck_ofdm_rate_info, + WMITLV_TAG_STRUC_wmi_peer_mcs_rate_info, + WMITLV_TAG_STRUC_wmi_pdev_nfcal_power_all_channels_nfdBr, + WMITLV_TAG_STRUC_wmi_pdev_nfcal_power_all_channels_nfdBm, + WMITLV_TAG_STRUC_wmi_pdev_nfcal_power_all_channels_freqNum, + WMITLV_TAG_STRUC_wmi_mu_report_total_mu, + WMITLV_TAG_STRUC_wmi_vdev_set_dscp_tid_map_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_roam_set_mbo_fixed_param, + WMITLV_TAG_STRUC_wmi_mib_stats_enable_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_nan_disc_iface_created_event_fixed_param, + WMITLV_TAG_STRUC_wmi_nan_disc_iface_deleted_event_fixed_param, + WMITLV_TAG_STRUC_wmi_nan_started_cluster_event_fixed_param, + WMITLV_TAG_STRUC_wmi_nan_joined_cluster_event_fixed_param, + WMITLV_TAG_STRUC_wmi_ndi_get_cap_req_fixed_param, + WMITLV_TAG_STRUC_wmi_ndp_initiator_req_fixed_param, + WMITLV_TAG_STRUC_wmi_ndp_responder_req_fixed_param, + WMITLV_TAG_STRUC_wmi_ndp_end_req_fixed_param, + WMITLV_TAG_STRUC_wmi_ndi_cap_rsp_event_fixed_param, + WMITLV_TAG_STRUC_wmi_ndp_initiator_rsp_event_fixed_param, + WMITLV_TAG_STRUC_wmi_ndp_responder_rsp_event_fixed_param, + WMITLV_TAG_STRUC_wmi_ndp_end_rsp_event_fixed_param, + WMITLV_TAG_STRUC_wmi_ndp_indication_event_fixed_param, + WMITLV_TAG_STRUC_wmi_ndp_confirm_event_fixed_param, + WMITLV_TAG_STRUC_wmi_ndp_end_indication_event_fixed_param, + WMITLV_TAG_STRUC_wmi_vdev_set_quiet_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_pdev_set_pcl_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_pdev_set_hw_mode_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_pdev_set_mac_config_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_pdev_set_antenna_mode_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_pdev_set_hw_mode_response_event_fixed_param, + WMITLV_TAG_STRUC_wmi_pdev_hw_mode_transition_event_fixed_param, + WMITLV_TAG_STRUC_wmi_pdev_set_hw_mode_response_vdev_mac_entry, + WMITLV_TAG_STRUC_wmi_pdev_set_mac_config_response_event_fixed_param, + WMITLV_TAG_STRUC_WMI_COEX_CONFIG_CMD_fixed_param, + WMITLV_TAG_STRUC_wmi_config_enhanced_mcast_filter_fixed_param, + WMITLV_TAG_STRUC_WMI_CHAN_AVOID_RPT_ALLOW_CMD_fixed_param, + WMITLV_TAG_STRUC_wmi_set_periodic_channel_stats_config_fixed_param, + WMITLV_TAG_STRUC_wmi_vdev_set_custom_aggr_size_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_pdev_wal_power_debug_cmd_fixed_param, + WMITLV_TAG_STRUC_WMI_MAC_PHY_CAPABILITIES, + WMITLV_TAG_STRUC_WMI_HW_MODE_CAPABILITIES, + WMITLV_TAG_STRUC_WMI_SOC_MAC_PHY_HW_MODE_CAPS, + WMITLV_TAG_STRUC_WMI_HAL_REG_CAPABILITIES_EXT, + WMITLV_TAG_STRUC_WMI_SOC_HAL_REG_CAPABILITIES, + WMITLV_TAG_STRUC_wmi_vdev_wisa_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_tx_power_level_stats_evt_fixed_param, + WMITLV_TAG_STRUC_wmi_scan_adaptive_dwell_parameters_tlv, + WMITLV_TAG_STRUC_wmi_scan_adaptive_dwell_config_fixed_param, + WMITLV_TAG_STRUC_wmi_wow_set_action_wake_up_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_ndp_end_rsp_per_ndi, + WMITLV_TAG_STRUC_wmi_peer_bwf_request_fixed_param, + WMITLV_TAG_STRUC_wmi_bwf_peer_info, + WMITLV_TAG_STRUC_wmi_dbglog_time_stamp_sync_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_rmc_set_leader_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_rmc_manual_leader_event_fixed_param, + WMITLV_TAG_STRUC_wmi_per_chain_rssi_stats, + WMITLV_TAG_STRUC_wmi_rssi_stats, + WMITLV_TAG_STRUC_wmi_p2p_lo_start_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_p2p_lo_stop_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_p2p_lo_stopped_event_fixed_param, + WMITLV_TAG_STRUC_wmi_peer_reorder_queue_setup_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_peer_reorder_queue_remove_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_set_multiple_mcast_filter_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_mgmt_tx_compl_bundle_event_fixed_param, + WMITLV_TAG_STRUC_wmi_read_data_from_flash_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_read_data_from_flash_event_fixed_param, + WMITLV_TAG_STRUC_wmi_pdev_set_reorder_timeout_val_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_peer_set_rx_blocksize_cmd_fixed_param, + WMITLV_TAG_STRUC_WMI_PDEV_SET_WAKEUP_CONFIG_CMDID_fixed_param, + WMITLV_TAG_STRUC_wmi_tlv_buf_len_param, + WMITLV_TAG_STRUC_wmi_service_available_event_fixed_param, + WMITLV_TAG_STRUC_wmi_peer_antdiv_info_req_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_peer_antdiv_info_event_fixed_param, + WMITLV_TAG_STRUC_wmi_peer_antdiv_info, + WMITLV_TAG_STRUC_wmi_pdev_get_antdiv_status_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_pdev_antdiv_status_event_fixed_param, + WMITLV_TAG_STRUC_wmi_mnt_filter_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_get_chip_power_stats_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_pdev_chip_power_stats_event_fixed_param, + WMITLV_TAG_STRUC_wmi_coex_get_antenna_isolation_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_coex_report_isolation_event_fixed_param, + WMITLV_TAG_STRUC_wmi_chan_cca_stats, + WMITLV_TAG_STRUC_wmi_peer_signal_stats, + WMITLV_TAG_STRUC_wmi_tx_stats, + WMITLV_TAG_STRUC_wmi_peer_ac_tx_stats, + WMITLV_TAG_STRUC_wmi_rx_stats, + WMITLV_TAG_STRUC_wmi_peer_ac_rx_stats, + WMITLV_TAG_STRUC_wmi_report_stats_event_fixed_param, + WMITLV_TAG_STRUC_wmi_chan_cca_stats_thresh, + WMITLV_TAG_STRUC_wmi_peer_signal_stats_thresh, + WMITLV_TAG_STRUC_wmi_tx_stats_thresh, + WMITLV_TAG_STRUC_wmi_rx_stats_thresh, + WMITLV_TAG_STRUC_wmi_pdev_set_stats_threshold_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_request_wlan_stats_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_rx_aggr_failure_event_fixed_param, + WMITLV_TAG_STRUC_wmi_rx_aggr_failure_info, + WMITLV_TAG_STRUC_wmi_vdev_encrypt_decrypt_data_req_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_vdev_encrypt_decrypt_data_resp_event_fixed_param, + WMITLV_TAG_STRUC_wmi_pdev_band_to_mac, + WMITLV_TAG_STRUC_wmi_tbtt_offset_info, + WMITLV_TAG_STRUC_wmi_tbtt_offset_ext_event_fixed_param, + WMITLV_TAG_STRUC_wmi_sar_limits_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_sar_limit_cmd_row, + WMITLV_TAG_STRUC_wmi_pdev_dfs_phyerr_offload_enable_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_pdev_dfs_phyerr_offload_disable_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_vdev_adfs_ch_cfg_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_vdev_adfs_ocac_abort_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_pdev_dfs_radar_detection_event_fixed_param, + WMITLV_TAG_STRUC_wmi_vdev_adfs_ocac_complete_event_fixed_param, + WMITLV_TAG_STRUC_wmi_vdev_dfs_cac_complete_event_fixed_param, + WMITLV_TAG_STRUC_wmi_vendor_oui, + WMITLV_TAG_STRUC_wmi_request_rcpi_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_update_rcpi_event_fixed_param, + WMITLV_TAG_STRUC_wmi_request_peer_stats_info_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_peer_stats_info, + WMITLV_TAG_STRUC_wmi_peer_stats_info_event_fixed_param, + WMITLV_TAG_STRUC_wmi_pkgid_event_fixed_param, + WMITLV_TAG_STRUC_wmi_connected_nlo_rssi_params, + WMITLV_TAG_STRUC_wmi_set_current_country_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_regulatory_rule_struct, + WMITLV_TAG_STRUC_wmi_reg_chan_list_cc_event_fixed_param, + WMITLV_TAG_STRUC_wmi_11d_scan_start_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_11d_scan_stop_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_11d_new_country_event_fixed_param, + WMITLV_TAG_STRUC_wmi_request_radio_chan_stats_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_radio_chan_stats, + WMITLV_TAG_STRUC_wmi_radio_chan_stats_event_fixed_param, + WMITLV_TAG_STRUC_wmi_roam_per_config_fixed_param, + WMITLV_TAG_STRUC_wmi_vdev_add_mac_addr_to_rx_filter_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_vdev_add_mac_addr_to_rx_filter_status_event_fixed_param, + WMITLV_TAG_STRUC_wmi_bpf_set_vdev_active_mode_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_hw_data_filter_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_connected_nlo_bss_band_rssi_pref, + WMITLV_TAG_STRUC_wmi_peer_oper_mode_change_event_fixed_param, + WMITLV_TAG_STRUC_wmi_chip_power_save_failure_detected_fixed_param, + WMITLV_TAG_STRUC_wmi_pdev_multiple_vdev_restart_request_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_pdev_csa_switch_count_status_event_fixed_param, + WMITLV_TAG_STRUC_wmi_pdev_update_pkt_routing_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_pdev_check_cal_version_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_pdev_check_cal_version_event_fixed_param, + WMITLV_TAG_STRUC_wmi_pdev_set_diversity_gain_cmd_fixed_param, + WMITLV_TAG_STRUC_WMI_MAC_PHY_CHAINMASK_COMBO, + WMITLV_TAG_STRUC_WMI_MAC_PHY_CHAINMASK_CAPABILITY, + WMITLV_TAG_STRUC_wmi_vdev_set_arp_stats_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_vdev_get_arp_stats_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_vdev_get_arp_stats_event_fixed_param, + WMITLV_TAG_STRUC_wmi_iface_offload_stats, + WMITLV_TAG_STRUC_wmi_request_stats_cmd_sub_struc_param, + WMITLV_TAG_STRUC_rssi_ctl_ext, + WMITLV_TAG_STRUC_wmi_single_phyerr_ext_rx_hdr, + WMITLV_TAG_STRUC_wmi_coex_bt_activity_event_fixed_param, + WMITLV_TAG_STRUC_wmi_vdev_get_tx_power_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_vdev_tx_power_event_fixed_param, + WMITLV_TAG_STRUC_wmi_offchan_data_tx_compl_event_fixed_param, + WMITLV_TAG_STRUC_wmi_offchan_data_tx_send_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_tx_send_params, + WMITLV_TAG_STRUC_wmi_he_rate_set, + WMITLV_TAG_STRUC_wmi_congestion_stats, + WMITLV_TAG_STRUC_wmi_set_init_country_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_scan_dbs_duty_cycle_fixed_param, + WMITLV_TAG_STRUC_wmi_scan_dbs_duty_cycle_param_tlv, + WMITLV_TAG_STRUC_wmi_pdev_div_get_rssi_antid_fixed_param, + WMITLV_TAG_STRUC_wmi_therm_throt_config_request_fixed_param, + WMITLV_TAG_STRUC_wmi_therm_throt_level_config_info, + WMITLV_TAG_STRUC_wmi_therm_throt_stats_event_fixed_param, + WMITLV_TAG_STRUC_wmi_therm_throt_level_stats_info, + WMITLV_TAG_STRUC_wmi_pdev_div_rssi_antid_event_fixed_param, + WMITLV_TAG_STRUC_WMI_OEM_DMA_RING_CAPABILITIES, + WMITLV_TAG_STRUC_wmi_oem_dma_ring_cfg_req_fixed_param, + WMITLV_TAG_STRUC_wmi_oem_dma_ring_cfg_rsp_fixed_param, + WMITLV_TAG_STRUC_wmi_oem_indirect_data, + WMITLV_TAG_STRUC_wmi_oem_dma_buf_release_fixed_param, + WMITLV_TAG_STRUC_wmi_oem_dma_buf_release_entry, + WMITLV_TAG_STRUC_wmi_pdev_bss_chan_info_request_fixed_param, + WMITLV_TAG_STRUC_wmi_pdev_bss_chan_info_event_fixed_param, + WMITLV_TAG_STRUC_wmi_roam_lca_disallow_config_tlv_param, + WMITLV_TAG_STRUC_wmi_vdev_limit_offchan_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_roam_rssi_rejection_oce_config_param, + WMITLV_TAG_STRUC_wmi_unit_test_event_fixed_param, + WMITLV_TAG_STRUC_wmi_roam_fils_offload_tlv_param, + WMITLV_TAG_STRUC_wmi_pdev_update_pmk_cache_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_pmk_cache, + WMITLV_TAG_STRUC_wmi_pdev_update_fils_hlp_pkt_cmd_fixed_param, + WMITLV_TAG_STRUC_wmi_roam_fils_synch_tlv_param, + WMITLV_TAG_STRUC_wmi_gtk_offload_extended_tlv_param, + WMITLV_TAG_STRUC_wmi_roam_bg_scan_roaming_param, +} WMITLV_TAG_ID; + +/* + * IMPORTANT: Please add _ALL_ WMI Commands Here. + * Otherwise, these WMI TLV Functions will be process them. + */ +#define WMITLV_ALL_CMD_LIST(OP) \ + OP(WMI_INIT_CMDID) \ + OP(WMI_PEER_CREATE_CMDID) \ + OP(WMI_PEER_DELETE_CMDID) \ + OP(WMI_PEER_FLUSH_TIDS_CMDID) \ + OP(WMI_PEER_SET_PARAM_CMDID) \ + OP(WMI_STA_POWERSAVE_MODE_CMDID) \ + OP(WMI_STA_POWERSAVE_PARAM_CMDID) \ + OP(WMI_STA_DTIM_PS_METHOD_CMDID) \ + OP(WMI_PDEV_SET_REGDOMAIN_CMDID) \ + OP(WMI_PEER_TID_ADDBA_CMDID) \ + OP(WMI_PEER_TID_DELBA_CMDID) \ + OP(WMI_PDEV_FTM_INTG_CMDID) \ + OP(WMI_WOW_HOSTWAKEUP_FROM_SLEEP_CMDID) \ + OP(WMI_WOW_ENABLE_CMDID) \ + OP(WMI_RMV_BCN_FILTER_CMDID) \ + OP(WMI_ROAM_SCAN_MODE) \ + OP(WMI_ROAM_SCAN_RSSI_THRESHOLD) \ + OP(WMI_ROAM_SCAN_PERIOD) \ + OP(WMI_ROAM_SCAN_RSSI_CHANGE_THRESHOLD) \ + OP(WMI_START_SCAN_CMDID) \ + OP(WMI_VDEV_PLMREQ_START_CMDID) \ + OP(WMI_VDEV_PLMREQ_STOP_CMDID) \ + OP(WMI_PDEV_SET_CHANNEL_CMDID) \ + OP(WMI_PDEV_SET_WMM_PARAMS_CMDID) \ + OP(WMI_VDEV_START_REQUEST_CMDID) \ + OP(WMI_VDEV_RESTART_REQUEST_CMDID) \ + OP(WMI_P2P_GO_SET_BEACON_IE) \ + OP(WMI_GTK_OFFLOAD_CMDID) \ + OP(WMI_SCAN_CHAN_LIST_CMDID) \ + OP(WMI_STA_UAPSD_AUTO_TRIG_CMDID) \ + OP(WMI_PRB_TMPL_CMDID) \ + OP(WMI_BCN_TMPL_CMDID) \ + OP(WMI_VDEV_INSTALL_KEY_CMDID) \ + OP(WMI_PEER_ASSOC_CMDID) \ + OP(WMI_ADD_BCN_FILTER_CMDID) \ + OP(WMI_STA_KEEPALIVE_CMDID) \ + OP(WMI_SET_ARP_NS_OFFLOAD_CMDID) \ + OP(WMI_P2P_SET_VENDOR_IE_DATA_CMDID) \ + OP(WMI_AP_PS_PEER_PARAM_CMDID) \ + OP(WMI_WLAN_PROFILE_TRIGGER_CMDID) \ + OP(WMI_WLAN_PROFILE_SET_HIST_INTVL_CMDID) \ + OP(WMI_WLAN_PROFILE_GET_PROFILE_DATA_CMDID) \ + OP(WMI_WLAN_PROFILE_ENABLE_PROFILE_ID_CMDID) \ + OP(WMI_WOW_DEL_WAKE_PATTERN_CMDID) \ + OP(WMI_WOW_ENABLE_DISABLE_WAKE_EVENT_CMDID) \ + OP(WMI_RTT_MEASREQ_CMDID) \ + OP(WMI_RTT_TSF_CMDID) \ + OP(WMI_OEM_REQ_CMDID) \ + OP(WMI_VDEV_SPECTRAL_SCAN_CONFIGURE_CMDID) \ + OP(WMI_VDEV_SPECTRAL_SCAN_ENABLE_CMDID) \ + OP(WMI_REQUEST_STATS_CMDID) \ + OP(WMI_NETWORK_LIST_OFFLOAD_CONFIG_CMDID) \ + OP(WMI_CSA_OFFLOAD_ENABLE_CMDID) \ + OP(WMI_CSA_OFFLOAD_CHANSWITCH_CMDID) \ + OP(WMI_CHATTER_SET_MODE_CMDID) \ + OP(WMI_ECHO_CMDID) \ + OP(WMI_PDEV_UTF_CMDID) \ + OP(WMI_PDEV_QVIT_CMDID) \ + OP(WMI_VDEV_SET_KEEPALIVE_CMDID) \ + OP(WMI_VDEV_GET_KEEPALIVE_CMDID) \ + OP(WMI_FORCE_FW_HANG_CMDID) \ + OP(WMI_GPIO_CONFIG_CMDID) \ + OP(WMI_GPIO_OUTPUT_CMDID) \ + OP(WMI_PEER_ADD_WDS_ENTRY_CMDID) \ + OP(WMI_PEER_REMOVE_WDS_ENTRY_CMDID) \ + OP(WMI_BCN_TX_CMDID) \ + OP(WMI_PDEV_SEND_BCN_CMDID) \ + OP(WMI_MGMT_TX_CMDID) \ + OP(WMI_ADDBA_CLEAR_RESP_CMDID) \ + OP(WMI_ADDBA_SEND_CMDID) \ + OP(WMI_DELBA_SEND_CMDID) \ + OP(WMI_ADDBA_SET_RESP_CMDID) \ + OP(WMI_SEND_SINGLEAMSDU_CMDID) \ + OP(WMI_PDEV_PKTLOG_ENABLE_CMDID) \ + OP(WMI_PDEV_PKTLOG_DISABLE_CMDID) \ + OP(WMI_PDEV_SET_HT_CAP_IE_CMDID) \ + OP(WMI_PDEV_SET_VHT_CAP_IE_CMDID) \ + OP(WMI_PDEV_SET_DSCP_TID_MAP_CMDID) \ + OP(WMI_PDEV_GREEN_AP_PS_ENABLE_CMDID) \ + OP(WMI_PDEV_GET_TPC_CONFIG_CMDID) \ + OP(WMI_PDEV_SET_BASE_MACADDR_CMDID) \ + OP(WMI_PEER_MCAST_GROUP_CMDID) \ + OP(WMI_ROAM_AP_PROFILE) \ + OP(WMI_SCAN_SCH_PRIO_TBL_CMDID) \ + OP(WMI_PDEV_DFS_ENABLE_CMDID) \ + OP(WMI_PDEV_DFS_DISABLE_CMDID) \ + OP(WMI_WOW_ADD_WAKE_PATTERN_CMDID) \ + OP(WMI_PDEV_SUSPEND_CMDID) \ + OP(WMI_PDEV_RESUME_CMDID) \ + OP(WMI_STOP_SCAN_CMDID) \ + OP(WMI_PDEV_SET_PARAM_CMDID) \ + OP(WMI_PDEV_SET_QUIET_MODE_CMDID) \ + OP(WMI_VDEV_CREATE_CMDID) \ + OP(WMI_VDEV_DELETE_CMDID) \ + OP(WMI_VDEV_UP_CMDID) \ + OP(WMI_VDEV_STOP_CMDID) \ + OP(WMI_VDEV_DOWN_CMDID) \ + OP(WMI_VDEV_SET_PARAM_CMDID) \ + OP(WMI_SCAN_UPDATE_REQUEST_CMDID) \ + OP(WMI_CHATTER_ADD_COALESCING_FILTER_CMDID) \ + OP(WMI_CHATTER_DELETE_COALESCING_FILTER_CMDID) \ + OP(WMI_CHATTER_COALESCING_QUERY_CMDID) \ + OP(WMI_TXBF_CMDID) \ + OP(WMI_DBGLOG_CFG_CMDID) \ + OP(WMI_VDEV_WNM_SLEEPMODE_CMDID) \ + OP(WMI_VDEV_IPSEC_NATKEEPALIVE_FILTER_CMDID) \ + OP(WMI_VDEV_WMM_ADDTS_CMDID) \ + OP(WMI_VDEV_WMM_DELTS_CMDID) \ + OP(WMI_VDEV_SET_WMM_PARAMS_CMDID) \ + OP(WMI_VDEV_SET_GTX_PARAMS_CMDID) \ + OP(WMI_TDLS_SET_STATE_CMDID) \ + OP(WMI_TDLS_PEER_UPDATE_CMDID) \ + OP(WMI_FWTEST_VDEV_MCC_SET_TBTT_MODE_CMDID) \ + OP(WMI_ROAM_CHAN_LIST) \ + OP(WMI_RESMGR_ADAPTIVE_OCS_ENABLE_DISABLE_CMDID)\ + OP(WMI_RESMGR_SET_CHAN_TIME_QUOTA_CMDID) \ + OP(WMI_RESMGR_SET_CHAN_LATENCY_CMDID) \ + OP(WMI_BA_REQ_SSN_CMDID) \ + OP(WMI_STA_SMPS_FORCE_MODE_CMDID) \ + OP(WMI_SET_MCASTBCAST_FILTER_CMDID) \ + OP(WMI_P2P_SET_OPPPS_PARAM_CMDID) \ + OP(WMI_FWTEST_P2P_SET_NOA_PARAM_CMDID) \ + OP(WMI_STA_SMPS_PARAM_CMDID) \ + OP(WMI_MCC_SCHED_TRAFFIC_STATS_CMDID) \ + OP(WMI_HB_SET_ENABLE_CMDID) \ + OP(WMI_HB_SET_TCP_PARAMS_CMDID) \ + OP(WMI_HB_SET_TCP_PKT_FILTER_CMDID) \ + OP(WMI_HB_SET_UDP_PARAMS_CMDID) \ + OP(WMI_HB_SET_UDP_PKT_FILTER_CMDID) \ + OP(WMI_PEER_INFO_REQ_CMDID) \ + OP(WMI_RMC_SET_MODE_CMDID) \ + OP(WMI_RMC_SET_ACTION_PERIOD_CMDID) \ + OP(WMI_RMC_CONFIG_CMDID) \ + OP(WMI_MHF_OFFLOAD_SET_MODE_CMDID) \ + OP(WMI_MHF_OFFLOAD_PLUMB_ROUTING_TBL_CMDID) \ + OP(WMI_DFS_PHYERR_FILTER_ENA_CMDID) \ + OP(WMI_DFS_PHYERR_FILTER_DIS_CMDID) \ + OP(WMI_BATCH_SCAN_ENABLE_CMDID) \ + OP(WMI_BATCH_SCAN_DISABLE_CMDID) \ + OP(WMI_BATCH_SCAN_TRIGGER_RESULT_CMDID)\ + OP(WMI_THERMAL_MGMT_CMDID)\ + OP(WMI_ADD_PROACTIVE_ARP_RSP_PATTERN_CMDID)\ + OP(WMI_DEL_PROACTIVE_ARP_RSP_PATTERN_CMDID) \ + OP(WMI_NAN_CMDID) \ + OP(WMI_MODEM_POWER_STATE_CMDID) \ + OP(WMI_PEER_GET_ESTIMATED_LINKSPEED_CMDID) \ + OP(WMI_ROAM_SCAN_CMD) \ + OP(WMI_REQUEST_STATS_EXT_CMDID) \ + OP(WMI_OBSS_SCAN_ENABLE_CMDID) \ + OP(WMI_OBSS_SCAN_DISABLE_CMDID) \ + OP(WMI_PDEV_SET_LED_CONFIG_CMDID) \ + OP(WMI_HOST_AUTO_SHUTDOWN_CFG_CMDID) \ + OP(WMI_TPC_CHAINMASK_CONFIG_CMDID) \ + OP(WMI_CHAN_AVOID_UPDATE_CMDID) \ + OP(WMI_WOW_IOAC_ADD_KEEPALIVE_CMDID) \ + OP(WMI_WOW_IOAC_DEL_KEEPALIVE_CMDID) \ + OP(WMI_WOW_IOAC_ADD_WAKE_PATTERN_CMDID) \ + OP(WMI_WOW_IOAC_DEL_WAKE_PATTERN_CMDID) \ + OP(WMI_REQUEST_LINK_STATS_CMDID) \ + OP(WMI_START_LINK_STATS_CMDID) \ + OP(WMI_CLEAR_LINK_STATS_CMDID) \ + OP(WMI_LPI_MGMT_SNOOPING_CONFIG_CMDID) \ + OP(WMI_LPI_START_SCAN_CMDID) \ + OP(WMI_LPI_STOP_SCAN_CMDID) \ + OP(WMI_EXTSCAN_START_CMDID) \ + OP(WMI_EXTSCAN_STOP_CMDID) \ + OP(WMI_EXTSCAN_CONFIGURE_WLAN_CHANGE_MONITOR_CMDID) \ + OP(WMI_EXTSCAN_CONFIGURE_HOTLIST_MONITOR_CMDID) \ + OP(WMI_EXTSCAN_GET_CACHED_RESULTS_CMDID) \ + OP(WMI_EXTSCAN_GET_WLAN_CHANGE_RESULTS_CMDID) \ + OP(WMI_EXTSCAN_SET_CAPABILITIES_CMDID) \ + OP(WMI_EXTSCAN_GET_CAPABILITIES_CMDID) \ + OP(WMI_EXTSCAN_CONFIGURE_HOTLIST_SSID_MONITOR_CMDID) \ + OP(WMI_D0_WOW_ENABLE_DISABLE_CMDID) \ + OP(WMI_UNIT_TEST_CMDID) \ + OP(WMI_ROAM_SYNCH_COMPLETE) \ + OP(WMI_EXTWOW_ENABLE_CMDID) \ + OP(WMI_EXTWOW_SET_APP_TYPE1_PARAMS_CMDID) \ + OP(WMI_EXTWOW_SET_APP_TYPE2_PARAMS_CMDID) \ + OP(WMI_ROAM_SET_RIC_REQUEST_CMDID) \ + OP(WMI_PDEV_GET_TEMPERATURE_CMDID) \ + OP(WMI_SET_DHCP_SERVER_OFFLOAD_CMDID) \ + OP(WMI_IPA_OFFLOAD_ENABLE_DISABLE_CMDID)\ + OP(WMI_SCAN_PROB_REQ_OUI_CMDID) \ + OP(WMI_TDLS_SET_OFFCHAN_MODE_CMDID)\ + OP(WMI_PDEV_SET_LED_FLASHING_CMDID) \ + OP(WMI_ROAM_INVOKE_CMDID) \ + OP(WMI_MDNS_OFFLOAD_ENABLE_CMDID) \ + OP(WMI_MDNS_SET_FQDN_CMDID) \ + OP(WMI_MDNS_SET_RESPONSE_CMDID) \ + OP(WMI_MDNS_GET_STATS_CMDID) \ + OP(WMI_SET_ANTENNA_DIVERSITY_CMDID) \ + OP(WMI_SAP_OFL_ENABLE_CMDID) \ + OP(WMI_APFIND_CMDID) \ + OP(WMI_OCB_SET_SCHED_CMDID) \ + OP(WMI_OCB_SET_CONFIG_CMDID) \ + OP(WMI_OCB_SET_UTC_TIME_CMDID) \ + OP(WMI_OCB_START_TIMING_ADVERT_CMDID) \ + OP(WMI_OCB_STOP_TIMING_ADVERT_CMDID) \ + OP(WMI_OCB_GET_TSF_TIMER_CMDID) \ + OP(WMI_DCC_GET_STATS_CMDID) \ + OP(WMI_DCC_CLEAR_STATS_CMDID) \ + OP(WMI_DCC_UPDATE_NDL_CMDID) \ + OP(WMI_ROAM_FILTER_CMDID) \ + OP(WMI_PASSPOINT_LIST_CONFIG_CMDID) \ + OP(WMI_VDEV_TSF_TSTAMP_ACTION_CMDID) \ + OP(WMI_GET_FW_MEM_DUMP_CMDID) \ + OP(WMI_DEBUG_MESG_FLUSH_CMDID) \ + OP(WMI_PEER_SET_RATE_REPORT_CONDITION_CMDID) \ + OP(WMI_ROAM_SUBNET_CHANGE_CONFIG_CMDID) \ + OP(WMI_VDEV_SET_IE_CMDID) \ + OP(WMI_RSSI_BREACH_MONITOR_CONFIG_CMDID) \ + OP(WMI_SOC_SET_PCL_CMDID) \ + OP(WMI_SOC_SET_HW_MODE_CMDID) \ + OP(WMI_SOC_SET_DUAL_MAC_CONFIG_CMDID) \ + OP(WMI_WOW_ENABLE_ICMPV6_NA_FLT_CMDID) \ + OP(WMI_DIAG_EVENT_LOG_CONFIG_CMDID) \ + OP(WMI_PACKET_FILTER_CONFIG_CMDID) \ + OP(WMI_PACKET_FILTER_ENABLE_CMDID) \ + OP(WMI_SAP_SET_BLACKLIST_PARAM_CMDID) \ + OP(WMI_MGMT_TX_SEND_CMDID) \ + OP(WMI_SOC_SET_ANTENNA_MODE_CMDID) \ + OP(WMI_WOW_UDP_SVC_OFLD_CMDID) \ + OP(WMI_LRO_CONFIG_CMDID) \ + OP(WMI_MAWC_SENSOR_REPORT_IND_CMDID) \ + OP(WMI_ROAM_CONFIGURE_MAWC_CMDID) \ + OP(WMI_NLO_CONFIGURE_MAWC_CMDID) \ + OP(WMI_EXTSCAN_CONFIGURE_MAWC_CMDID) \ + OP(WMI_WOW_HOSTWAKEUP_GPIO_PIN_PATTERN_CONFIG_CMDID) \ + OP(WMI_AP_PS_EGAP_PARAM_CMDID) \ + OP(WMI_PMF_OFFLOAD_SET_SA_QUERY_CMDID) \ + OP(WMI_TRANSFER_DATA_TO_FLASH_CMDID) \ + OP(WMI_OEM_REQUEST_CMDID) \ + OP(WMI_BPF_GET_CAPABILITY_CMDID) \ + OP(WMI_BPF_GET_VDEV_STATS_CMDID) \ + OP(WMI_BPF_SET_VDEV_INSTRUCTIONS_CMDID) \ + OP(WMI_BPF_DEL_VDEV_INSTRUCTIONS_CMDID) \ + OP(WMI_PEER_UPDATE_WDS_ENTRY_CMDID) \ + OP(WMI_PEER_ADD_PROXY_STA_ENTRY_CMDID) \ + OP(WMI_PDEV_FIPS_CMDID) \ + OP(WMI_PDEV_SMART_ANT_ENABLE_CMDID) \ + OP(WMI_PDEV_SMART_ANT_SET_RX_ANTENNA_CMDID) \ + OP(WMI_PDEV_SET_ANTENNA_SWITCH_TABLE_CMDID) \ + OP(WMI_PDEV_SET_CTL_TABLE_CMDID) \ + OP(WMI_PDEV_SET_MIMOGAIN_TABLE_CMDID) \ + OP(WMI_PDEV_GET_TPC_CMDID) \ + OP(WMI_PDEV_GET_ANI_CCK_CONFIG_CMDID) \ + OP(WMI_PDEV_GET_ANI_OFDM_CONFIG_CMDID) \ + OP(WMI_VDEV_RATEMASK_CMDID) \ + OP(WMI_VDEV_ATF_REQUEST_CMDID) \ + OP(WMI_VDEV_SET_DSCP_TID_MAP_CMDID) \ + OP(WMI_VDEV_FILTER_NEIGHBOR_RX_PACKETS_CMDID) \ + OP(WMI_PEER_SMART_ANT_SET_TX_ANTENNA_CMDID) \ + OP(WMI_PEER_SMART_ANT_SET_TRAIN_INFO_CMDID) \ + OP(WMI_PEER_SMART_ANT_SET_NODE_CONFIG_OPS_CMDID) \ + OP(WMI_PEER_ATF_REQUEST_CMDID) \ + OP(WMI_FWTEST_CMDID) \ + OP(WMI_QBOOST_CFG_CMDID) \ + OP(WMI_ROAM_SET_MBO_PARAM_CMDID) \ + OP(WMI_MIB_STATS_ENABLE_CMDID) \ + OP(WMI_NDI_GET_CAP_REQ_CMDID) \ + OP(WMI_NDP_INITIATOR_REQ_CMDID) \ + OP(WMI_NDP_RESPONDER_REQ_CMDID) \ + OP(WMI_NDP_END_REQ_CMDID) \ + OP(WMI_PDEV_SET_PCL_CMDID) \ + OP(WMI_PDEV_SET_HW_MODE_CMDID) \ + OP(WMI_PDEV_SET_MAC_CONFIG_CMDID) \ + OP(WMI_PDEV_SET_ANTENNA_MODE_CMDID) \ + OP(WMI_VDEV_SET_QUIET_MODE_CMDID) \ + OP(WMI_COEX_CONFIG_CMDID) \ + OP(WMI_CONFIG_ENHANCED_MCAST_FILTER_CMDID) \ + OP(WMI_CHAN_AVOID_RPT_ALLOW_CMDID) \ + OP(WMI_SET_PERIODIC_CHANNEL_STATS_CONFIG_CMDID) \ + OP(WMI_VDEV_SET_CUSTOM_AGGR_SIZE_CMDID) \ + OP(WMI_PDEV_WAL_POWER_DEBUG_CMDID) \ + OP(WMI_VDEV_WISA_CMDID) \ + OP(WMI_SCAN_ADAPTIVE_DWELL_CONFIG_CMDID) \ + OP(WMI_WOW_SET_ACTION_WAKE_UP_CMDID) \ + OP(WMI_PEER_BWF_REQUEST_CMDID) \ + OP(WMI_DBGLOG_TIME_STAMP_SYNC_CMDID) \ + OP(WMI_RMC_SET_MANUAL_LEADER_CMDID) \ + OP(WMI_P2P_LISTEN_OFFLOAD_START_CMDID) \ + OP(WMI_P2P_LISTEN_OFFLOAD_STOP_CMDID) \ + OP(WMI_PEER_REORDER_QUEUE_SETUP_CMDID) \ + OP(WMI_PEER_REORDER_QUEUE_REMOVE_CMDID) \ + OP(WMI_SET_MULTIPLE_MCAST_FILTER_CMDID) \ + OP(WMI_READ_DATA_FROM_FLASH_CMDID) \ + OP(WMI_PDEV_SET_REORDER_TIMEOUT_VAL_CMDID) \ + OP(WMI_PEER_SET_RX_BLOCKSIZE_CMDID) \ + OP(WMI_PDEV_SET_WAKEUP_CONFIG_CMDID) \ + OP(WMI_PEER_ANTDIV_INFO_REQ_CMDID) \ + OP(WMI_PDEV_GET_ANTDIV_STATUS_CMDID) \ + OP(WMI_MNT_FILTER_CMDID) \ + OP(WMI_PDEV_GET_CHIP_POWER_STATS_CMDID) \ + OP(WMI_COEX_GET_ANTENNA_ISOLATION_CMDID) \ + OP(WMI_PDEV_SET_STATS_THRESHOLD_CMDID) \ + OP(WMI_REQUEST_WLAN_STATS_CMDID) \ + OP(WMI_VDEV_ENCRYPT_DECRYPT_DATA_REQ_CMDID) \ + OP(WMI_SAR_LIMITS_CMDID) \ + OP(WMI_PDEV_DFS_PHYERR_OFFLOAD_ENABLE_CMDID) \ + OP(WMI_PDEV_DFS_PHYERR_OFFLOAD_DISABLE_CMDID) \ + OP(WMI_VDEV_ADFS_CH_CFG_CMDID) \ + OP(WMI_VDEV_ADFS_OCAC_ABORT_CMDID) \ + OP(WMI_REQUEST_RCPI_CMDID) \ + OP(WMI_REQUEST_PEER_STATS_INFO_CMDID) \ + OP(WMI_SET_CURRENT_COUNTRY_CMDID) \ + OP(WMI_11D_SCAN_START_CMDID) \ + OP(WMI_11D_SCAN_STOP_CMDID) \ + OP(WMI_REQUEST_RADIO_CHAN_STATS_CMDID) \ + OP(WMI_ROAM_PER_CONFIG_CMDID) \ + OP(WMI_VDEV_ADD_MAC_ADDR_TO_RX_FILTER_CMDID) \ + OP(WMI_BPF_SET_VDEV_ACTIVE_MODE_CMDID) \ + OP(WMI_HW_DATA_FILTER_CMDID) \ + OP(WMI_PDEV_MULTIPLE_VDEV_RESTART_REQUEST_CMDID) \ + OP(WMI_LPI_OEM_REQ_CMDID) \ + OP(WMI_PDEV_UPDATE_PKT_ROUTING_CMDID) \ + OP(WMI_PDEV_CHECK_CAL_VERSION_CMDID) \ + OP(WMI_PDEV_SET_DIVERSITY_GAIN_CMDID) \ + OP(WMI_VDEV_SET_ARP_STAT_CMDID) \ + OP(WMI_VDEV_GET_ARP_STAT_CMDID) \ + OP(WMI_VDEV_GET_TX_POWER_CMDID) \ + OP(WMI_OFFCHAN_DATA_TX_SEND_CMDID) \ + OP(WMI_SET_INIT_COUNTRY_CMDID) \ + OP(WMI_SET_SCAN_DBS_DUTY_CYCLE_CMDID) \ + OP(WMI_PDEV_DIV_GET_RSSI_ANTID_CMDID) \ + OP(WMI_THERM_THROT_SET_CONF_CMDID) \ + OP(WMI_OEM_DMA_RING_CFG_REQ_CMDID) \ + OP(WMI_PDEV_BSS_CHAN_INFO_REQUEST_CMDID) \ + OP(WMI_VDEV_LIMIT_OFFCHAN_CMDID) \ + OP(WMI_PDEV_UPDATE_FILS_HLP_PKT_CMDID) \ + OP(WMI_PDEV_UPDATE_PMK_CACHE_CMDID) \ + /* add new CMD_LIST elements above this line */ + + +/* + * IMPORTANT: Please add _ALL_ WMI Events Here. + * Otherwise, these WMI TLV Functions will be process them. + */ +#define WMITLV_ALL_EVT_LIST(OP) \ + OP(WMI_SERVICE_READY_EVENTID) \ + OP(WMI_SERVICE_READY_EXT_EVENTID) \ + OP(WMI_READY_EVENTID) \ + OP(WMI_SCAN_EVENTID) \ + OP(WMI_PDEV_TPC_CONFIG_EVENTID) \ + OP(WMI_CHAN_INFO_EVENTID) \ + OP(WMI_PHYERR_EVENTID) \ + OP(WMI_VDEV_START_RESP_EVENTID) \ + OP(WMI_VDEV_STOPPED_EVENTID) \ + OP(WMI_VDEV_INSTALL_KEY_COMPLETE_EVENTID) \ + OP(WMI_PEER_STA_KICKOUT_EVENTID) \ + OP(WMI_MGMT_RX_EVENTID) \ + OP(WMI_TBTTOFFSET_UPDATE_EVENTID) \ + OP(WMI_TX_DELBA_COMPLETE_EVENTID) \ + OP(WMI_TX_ADDBA_COMPLETE_EVENTID) \ + OP(WMI_ROAM_EVENTID) \ + OP(WMI_WOW_WAKEUP_HOST_EVENTID) \ + OP(WMI_RTT_ERROR_REPORT_EVENTID) \ + OP(WMI_OEM_MEASUREMENT_REPORT_EVENTID) \ + OP(WMI_OEM_ERROR_REPORT_EVENTID) \ + OP(WMI_OEM_CAPABILITY_EVENTID) \ + OP(WMI_ECHO_EVENTID) \ + OP(WMI_PDEV_FTM_INTG_EVENTID) \ + OP(WMI_VDEV_GET_KEEPALIVE_EVENTID) \ + OP(WMI_GPIO_INPUT_EVENTID) \ + OP(WMI_CSA_HANDLING_EVENTID) \ + OP(WMI_DEBUG_MESG_EVENTID) \ + OP(WMI_GTK_OFFLOAD_STATUS_EVENTID) \ + OP(WMI_DCS_INTERFERENCE_EVENTID) \ + OP(WMI_WLAN_PROFILE_DATA_EVENTID) \ + OP(WMI_PDEV_UTF_EVENTID) \ + OP(WMI_DEBUG_PRINT_EVENTID) \ + OP(WMI_RTT_MEASUREMENT_REPORT_EVENTID) \ + OP(WMI_HOST_SWBA_EVENTID) \ + OP(WMI_UPDATE_STATS_EVENTID) \ + OP(WMI_PDEV_QVIT_EVENTID) \ + OP(WMI_WLAN_FREQ_AVOID_EVENTID) \ + OP(WMI_GTK_REKEY_FAIL_EVENTID) \ + OP(WMI_NLO_MATCH_EVENTID) \ + OP(WMI_NLO_SCAN_COMPLETE_EVENTID) \ + OP(WMI_APFIND_EVENTID) \ + OP(WMI_CHATTER_PC_QUERY_EVENTID) \ + OP(WMI_UPLOADH_EVENTID) \ + OP(WMI_CAPTUREH_EVENTID) \ + OP(WMI_TDLS_PEER_EVENTID) \ + OP(WMI_VDEV_MCC_BCN_INTERVAL_CHANGE_REQ_EVENTID) \ + OP(WMI_BA_RSP_SSN_EVENTID) \ + OP(WMI_OFFLOAD_BCN_TX_STATUS_EVENTID) \ + OP(WMI_P2P_NOA_EVENTID) \ + OP(WMI_TX_PAUSE_EVENTID) \ + OP(WMI_RFKILL_STATE_CHANGE_EVENTID) \ + OP(WMI_PEER_INFO_EVENTID) \ + OP(WMI_PEER_TX_FAIL_CNT_THR_EVENTID) \ + OP(WMI_DFS_RADAR_EVENTID) \ + OP(WMI_BATCH_SCAN_ENABLED_EVENTID) \ + OP(WMI_BATCH_SCAN_RESULT_EVENTID) \ + OP(WMI_THERMAL_MGMT_EVENTID) \ + OP(WMI_NAN_EVENTID) \ + OP(WMI_PDEV_L1SS_TRACK_EVENTID) \ + OP(WMI_DIAG_DATA_CONTAINER_EVENTID) \ + OP(WMI_PEER_ESTIMATED_LINKSPEED_EVENTID) \ + OP(WMI_AGGR_STATE_TRIG_EVENTID) \ + OP(WMI_STATS_EXT_EVENTID) \ + OP(WMI_OFFLOAD_PROB_RESP_TX_STATUS_EVENTID) \ + OP(WMI_HOST_AUTO_SHUTDOWN_EVENTID) \ + OP(WMI_UPDATE_WHAL_MIB_STATS_EVENTID) \ + OP(WMI_IFACE_LINK_STATS_EVENTID) \ + OP(WMI_PEER_LINK_STATS_EVENTID) \ + OP(WMI_RADIO_LINK_STATS_EVENTID) \ + OP(WMI_LPI_RESULT_EVENTID) \ + OP(WMI_PEER_STATE_EVENTID) \ + OP(WMI_EXTSCAN_START_STOP_EVENTID) \ + OP(WMI_EXTSCAN_OPERATION_EVENTID) \ + OP(WMI_EXTSCAN_TABLE_USAGE_EVENTID) \ + OP(WMI_EXTSCAN_CACHED_RESULTS_EVENTID) \ + OP(WMI_EXTSCAN_WLAN_CHANGE_RESULTS_EVENTID) \ + OP(WMI_EXTSCAN_HOTLIST_MATCH_EVENTID) \ + OP(WMI_EXTSCAN_CAPABILITIES_EVENTID) \ + OP(WMI_EXTSCAN_HOTLIST_SSID_MATCH_EVENTID) \ + OP(WMI_D0_WOW_DISABLE_ACK_EVENTID) \ + OP(WMI_ROAM_SYNCH_EVENTID) \ + OP(WMI_LPI_STATUS_EVENTID) \ + OP(WMI_LPI_HANDOFF_EVENTID) \ + OP(WMI_UPDATE_VDEV_RATE_STATS_EVENTID) \ + OP(WMI_PDEV_TEMPERATURE_EVENTID) \ + OP(WMI_DIAG_EVENTID) \ + OP(WMI_MDNS_STATS_EVENTID) \ + OP(WMI_PDEV_RESUME_EVENTID) \ + OP(WMI_SAP_OFL_ADD_STA_EVENTID) \ + OP(WMI_SAP_OFL_DEL_STA_EVENTID) \ + OP(WMI_OCB_SET_SCHED_EVENTID) \ + OP(WMI_OCB_SET_CONFIG_RESP_EVENTID) \ + OP(WMI_OCB_GET_TSF_TIMER_RESP_EVENTID) \ + OP(WMI_DCC_GET_STATS_RESP_EVENTID) \ + OP(WMI_DCC_UPDATE_NDL_RESP_EVENTID) \ + OP(WMI_DCC_STATS_EVENTID) \ + OP(WMI_PASSPOINT_MATCH_EVENTID) \ + OP(WMI_VDEV_TSF_REPORT_EVENTID) \ + OP(WMI_UPDATE_FW_MEM_DUMP_EVENTID) \ + OP(WMI_DEBUG_MESG_FLUSH_COMPLETE_EVENTID) \ + OP(WMI_RSSI_BREACH_EVENTID) \ + OP(WMI_WOW_INITIAL_WAKEUP_EVENTID) \ + OP(WMI_SOC_SET_HW_MODE_RESP_EVENTID) \ + OP(WMI_SOC_HW_MODE_TRANSITION_EVENTID) \ + OP(WMI_SOC_SET_DUAL_MAC_CONFIG_RESP_EVENTID) \ + OP(WMI_DIAG_EVENT_LOG_SUPPORTED_EVENTID) \ + OP(WMI_MGMT_TX_COMPLETION_EVENTID) \ + OP(WMI_MAWC_ENABLE_SENSOR_EVENTID) \ + OP(WMI_PEER_ASSOC_CONF_EVENTID) \ + OP(WMI_AP_PS_EGAP_INFO_EVENTID) \ + OP(WMI_TRANSFER_DATA_TO_FLASH_COMPLETE_EVENTID) \ + OP(WMI_OEM_RESPONSE_EVENTID) \ + OP(WMI_PDEV_UTF_SCPC_EVENTID) \ + OP(WMI_STA_SMPS_FORCE_MODE_COMPLETE_EVENTID) \ + OP(WMI_BPF_CAPABILIY_INFO_EVENTID) \ + OP(WMI_BPF_VDEV_STATS_INFO_EVENTID) \ + OP(WMI_VDEV_DELETE_RESP_EVENTID) \ + OP(WMI_PEER_DELETE_RESP_EVENTID) \ + OP(WMI_PDEV_FIPS_EVENTID) \ + OP(WMI_PDEV_CHANNEL_HOPPING_EVENTID) \ + OP(WMI_PDEV_ANI_CCK_LEVEL_EVENTID) \ + OP(WMI_PDEV_ANI_OFDM_LEVEL_EVENTID) \ + OP(WMI_PDEV_TPC_EVENTID) \ + OP(WMI_PDEV_NFCAL_POWER_ALL_CHANNELS_EVENTID) \ + OP(WMI_PEER_RATECODE_LIST_EVENTID) \ + OP(WMI_WDS_PEER_EVENTID) \ + OP(WMI_PEER_STA_PS_STATECHG_EVENTID) \ + OP(WMI_INST_RSSI_STATS_EVENTID) \ + OP(WMI_NAN_DISC_IFACE_CREATED_EVENTID) \ + OP(WMI_NAN_DISC_IFACE_DELETED_EVENTID) \ + OP(WMI_NAN_STARTED_CLUSTER_EVENTID) \ + OP(WMI_NAN_JOINED_CLUSTER_EVENTID) \ + OP(WMI_NDI_CAP_RSP_EVENTID) \ + OP(WMI_NDP_INITIATOR_RSP_EVENTID) \ + OP(WMI_NDP_RESPONDER_RSP_EVENTID) \ + OP(WMI_NDP_END_RSP_EVENTID) \ + OP(WMI_NDP_INDICATION_EVENTID) \ + OP(WMI_NDP_CONFIRM_EVENTID) \ + OP(WMI_NDP_END_INDICATION_EVENTID) \ + OP(WMI_PDEV_SET_HW_MODE_RESP_EVENTID) \ + OP(WMI_PDEV_HW_MODE_TRANSITION_EVENTID) \ + OP(WMI_PDEV_SET_MAC_CONFIG_RESP_EVENTID) \ + OP(WMI_RADIO_TX_POWER_LEVEL_STATS_EVENTID) \ + OP(WMI_RMC_NEW_LEADER_EVENTID) \ + OP(WMI_P2P_LISTEN_OFFLOAD_STOPPED_EVENTID) \ + OP(WMI_MGMT_TX_BUNDLE_COMPLETION_EVENTID) \ + OP(WMI_READ_DATA_FROM_FLASH_EVENTID) \ + OP(WMI_SERVICE_AVAILABLE_EVENTID) \ + OP(WMI_PEER_ANTDIV_INFO_EVENTID) \ + OP(WMI_PDEV_ANTDIV_STATUS_EVENTID) \ + OP(WMI_PDEV_CHIP_POWER_STATS_EVENTID) \ + OP(WMI_COEX_REPORT_ANTENNA_ISOLATION_EVENTID) \ + OP(WMI_REPORT_STATS_EVENTID) \ + OP(WMI_REPORT_RX_AGGR_FAILURE_EVENTID) \ + OP(WMI_VDEV_ENCRYPT_DECRYPT_DATA_RESP_EVENTID) \ + OP(WMI_TBTTOFFSET_EXT_UPDATE_EVENTID) \ + OP(WMI_PDEV_DFS_RADAR_DETECTION_EVENTID) \ + OP(WMI_VDEV_DFS_CAC_COMPLETE_EVENTID) \ + OP(WMI_VDEV_ADFS_OCAC_COMPLETE_EVENTID) \ + OP(WMI_UPDATE_RCPI_EVENTID) \ + OP(WMI_PEER_STATS_INFO_EVENTID) \ + OP(WMI_PKGID_EVENTID) \ + OP(WMI_REG_CHAN_LIST_CC_EVENTID) \ + OP(WMI_11D_NEW_COUNTRY_EVENTID) \ + OP(WMI_RADIO_CHAN_STATS_EVENTID) \ + OP(WMI_VDEV_ADD_MAC_ADDR_TO_RX_FILTER_STATUS_EVENTID) \ + OP(WMI_PEER_OPER_MODE_CHANGE_EVENTID) \ + OP(WMI_PDEV_CHIP_POWER_SAVE_FAILURE_DETECTED_EVENTID) \ + OP(WMI_PDEV_CSA_SWITCH_COUNT_STATUS_EVENTID) \ + OP(WMI_PDEV_CHECK_CAL_VERSION_EVENTID) \ + OP(WMI_VDEV_GET_ARP_STAT_EVENTID) \ + OP(WMI_WLAN_COEX_BT_ACTIVITY_EVENTID) \ + OP(WMI_VDEV_GET_TX_POWER_EVENTID) \ + OP(WMI_OFFCHAN_DATA_TX_COMPLETION_EVENTID) \ + OP(WMI_THERM_THROT_STATS_EVENTID) \ + OP(WMI_PDEV_DIV_RSSI_ANTID_EVENTID) \ + OP(WMI_OEM_DMA_RING_CFG_RSP_EVENTID) \ + OP(WMI_OEM_DMA_BUF_RELEASE_EVENTID) \ + OP(WMI_PDEV_BSS_CHAN_INFO_EVENTID) \ + OP(WMI_UNIT_TEST_EVENTID) \ + /* add new EVT_LIST elements above this line */ + + +/* TLV definitions of WMI commands */ + +/* Init Cmd */ +#define WMITLV_TABLE_WMI_INIT_CMDID(id,op,buf,len)\ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_init_cmd_fixed_param, wmi_init_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX)\ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_resource_config, wmi_resource_config, resource_config, WMITLV_SIZE_FIX)\ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wlan_host_memory_chunk, host_mem_chunks, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_pdev_set_hw_mode_cmd_fixed_param, wmi_pdev_set_hw_mode_cmd_fixed_param, hw_mode, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_pdev_band_to_mac, band_to_mac, WMITLV_SIZE_VAR) + +WMITLV_CREATE_PARAM_STRUC(WMI_INIT_CMDID); + +/* Peer create Cmd */ +#define WMITLV_TABLE_WMI_PEER_CREATE_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_peer_create_cmd_fixed_param, wmi_peer_create_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_PEER_CREATE_CMDID); + +/* Peer delete Cmd */ +#define WMITLV_TABLE_WMI_PEER_DELETE_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_peer_delete_cmd_fixed_param, wmi_peer_delete_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_PEER_DELETE_CMDID); + +/* Peer flush Cmd*/ +#define WMITLV_TABLE_WMI_PEER_FLUSH_TIDS_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_peer_flush_tids_cmd_fixed_param, wmi_peer_flush_tids_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_PEER_FLUSH_TIDS_CMDID); + +/* Peer Set Param Cmd */ +#define WMITLV_TABLE_WMI_PEER_SET_PARAM_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_peer_set_param_cmd_fixed_param, wmi_peer_set_param_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_PEER_SET_PARAM_CMDID); + +/* STA Powersave Mode Cmd */ +#define WMITLV_TABLE_WMI_STA_POWERSAVE_MODE_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_sta_powersave_mode_cmd_fixed_param, wmi_sta_powersave_mode_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_STA_POWERSAVE_MODE_CMDID); + +/* STA Powersave Param Cmd */ +#define WMITLV_TABLE_WMI_STA_POWERSAVE_PARAM_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_sta_powersave_param_cmd_fixed_param, wmi_sta_powersave_param_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_STA_POWERSAVE_PARAM_CMDID); + +/* STA DTIM PS METHOD Cmd */ +#define WMITLV_TABLE_WMI_STA_DTIM_PS_METHOD_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_sta_dtim_ps_method_cmd_fixed_param, wmi_sta_dtim_ps_method_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_STA_DTIM_PS_METHOD_CMDID); + +/* Pdev Set Reg Domain Cmd */ +#define WMITLV_TABLE_WMI_PDEV_SET_REGDOMAIN_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_pdev_set_regdomain_cmd_fixed_param, wmi_pdev_set_regdomain_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_PDEV_SET_REGDOMAIN_CMDID); + + +/* Peer TID ADD BA Cmd */ +#define WMITLV_TABLE_WMI_PEER_TID_ADDBA_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_peer_tid_addba_cmd_fixed_param, wmi_peer_tid_addba_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_PEER_TID_ADDBA_CMDID); + +/* Peer TID DEL BA Cmd */ +#define WMITLV_TABLE_WMI_PEER_TID_DELBA_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_peer_tid_delba_cmd_fixed_param, wmi_peer_tid_delba_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_PEER_TID_DELBA_CMDID); + +/* Peer Req Add BA Ssn for staId/tid pair Cmd */ +#define WMITLV_TABLE_WMI_BA_REQ_SSN_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_ba_req_ssn_cmd_fixed_param, wmi_ba_req_ssn_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len,WMITLV_TAG_ARRAY_STRUC, wmi_ba_req_ssn, ba_req_ssn_list, WMITLV_SIZE_VAR) + +WMITLV_CREATE_PARAM_STRUC(WMI_BA_REQ_SSN_CMDID); + + +/* PDEV FTM integration Cmd */ +#define WMITLV_TABLE_WMI_PDEV_FTM_INTG_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_ftm_intg_cmd_fixed_param, wmi_ftm_intg_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX)\ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, data, WMITLV_SIZE_VAR) + +WMITLV_CREATE_PARAM_STRUC(WMI_PDEV_FTM_INTG_CMDID); + +/* WOW Wakeup from sleep Cmd */ +#define WMITLV_TABLE_WMI_WOW_HOSTWAKEUP_FROM_SLEEP_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_wow_hostwakeup_from_sleep_cmd_fixed_param, wmi_wow_hostwakeup_from_sleep_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_WOW_HOSTWAKEUP_FROM_SLEEP_CMDID); + +/* WOW Enable Cmd */ +#define WMITLV_TABLE_WMI_WOW_ENABLE_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_wow_enable_cmd_fixed_param, wmi_wow_enable_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_WOW_ENABLE_CMDID); + +/* WOW ICMPv6 NA filtering command */ +#define WMITLV_TABLE_WMI_WOW_ENABLE_ICMPV6_NA_FLT_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_wow_enable_icmpv6_na_flt_cmd_fixed_param, wmi_wow_enable_icmpv6_na_flt_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_WOW_ENABLE_ICMPV6_NA_FLT_CMDID); + +/* Remove Bcn Filter Cmd */ +#define WMITLV_TABLE_WMI_RMV_BCN_FILTER_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_rmv_bcn_filter_cmd_fixed_param, wmi_rmv_bcn_filter_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_RMV_BCN_FILTER_CMDID); + +/** Service bit WMI_SERVICE_ROAM_OFFLOAD for Roaming feature */ +/* Roam scan mode Cmd */ +#define WMITLV_TABLE_WMI_ROAM_SCAN_MODE(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_roam_scan_mode_fixed_param, wmi_roam_scan_mode_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_start_scan_cmd_fixed_param, wmi_start_scan_cmd_fixed_param, scan_params, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_roam_offload_tlv_param, offload_param, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_roam_11i_offload_tlv_param, offload_11i_param, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_roam_11r_offload_tlv_param, offload_11r_param, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_roam_ese_offload_tlv_param, offload_ese_param, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_tlv_buf_len_param, assoc_ie_len_param, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, assoc_ie_buf, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_roam_fils_offload_tlv_param, offload_fils_info_param, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_ROAM_SCAN_MODE); + +/* Roam scan Rssi Threshold Cmd */ +#define WMITLV_TABLE_WMI_ROAM_SCAN_RSSI_THRESHOLD(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_roam_scan_rssi_threshold_fixed_param, wmi_roam_scan_rssi_threshold_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_roam_scan_extended_threshold_param, extended_param, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_roam_earlystop_rssi_thres_param, earlystop_param, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_roam_dense_thres_param, dense_param, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_roam_bg_scan_roaming_param, bg_scan_param, WMITLV_SIZE_VAR) + +WMITLV_CREATE_PARAM_STRUC(WMI_ROAM_SCAN_RSSI_THRESHOLD); + +/* Roam Scan Period Cmd */ +#define WMITLV_TABLE_WMI_ROAM_SCAN_PERIOD(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_roam_scan_period_fixed_param, wmi_roam_scan_period_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_ROAM_SCAN_PERIOD); + +/* Roam scan change Rssi Threshold Cmd */ +#define WMITLV_TABLE_WMI_ROAM_SCAN_RSSI_CHANGE_THRESHOLD(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_roam_scan_rssi_change_threshold_fixed_param, wmi_roam_scan_rssi_change_threshold_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_ROAM_SCAN_RSSI_CHANGE_THRESHOLD); + +/* Roam Scan Channel list Cmd */ +#define WMITLV_TABLE_WMI_ROAM_CHAN_LIST(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_roam_chan_list_fixed_param, wmi_roam_chan_list_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_UINT32, A_UINT32, channel_list, WMITLV_SIZE_VAR) + +WMITLV_CREATE_PARAM_STRUC(WMI_ROAM_CHAN_LIST); + +/* Roam scan mode Cmd */ +#define WMITLV_TABLE_WMI_ROAM_SCAN_CMD(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_roam_scan_cmd_fixed_param, wmi_roam_scan_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_ROAM_SCAN_CMD); + +/* Roam mbo configuration */ +#define WMITLV_TABLE_WMI_ROAM_SET_MBO_PARAM_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_roam_set_mbo_fixed_param, wmi_roam_set_mbo_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_UINT32, A_UINT32, cellular_cap, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_supported_operating_class_param, supp_op_class_param, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_UINT32, A_UINT32, supp_op_class_list, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_mbo_non_preferred_channel_report_param, non_prefer_ch_param, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, non_prefer_ch_attr, WMITLV_SIZE_VAR) + +WMITLV_CREATE_PARAM_STRUC(WMI_ROAM_SET_MBO_PARAM_CMDID); + +/* Roam PER configure cmd */ +#define WMITLV_TABLE_WMI_ROAM_PER_CONFIG_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_roam_per_config_fixed_param, wmi_roam_per_config_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_ROAM_PER_CONFIG_CMDID); + +#define WMITLV_TABLE_WMI_VDEV_PLMREQ_START_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_vdev_plmreq_start_cmd_fixed_param, wmi_vdev_plmreq_start_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_UINT32, A_UINT32, channel_list, WMITLV_SIZE_VAR) + +WMITLV_CREATE_PARAM_STRUC(WMI_VDEV_PLMREQ_START_CMDID); + +#define WMITLV_TABLE_WMI_VDEV_PLMREQ_STOP_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_vdev_plmreq_stop_cmd_fixed_param, wmi_vdev_plmreq_stop_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_VDEV_PLMREQ_STOP_CMDID); +/* Start scan Cmd */ +#define WMITLV_TABLE_WMI_START_SCAN_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_start_scan_cmd_fixed_param, wmi_start_scan_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_UINT32, A_UINT32, channel_list, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_FIXED_STRUC, wmi_ssid, ssid_list, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_FIXED_STRUC, wmi_mac_addr, bssid_list, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, ie_data, WMITLV_SIZE_VAR)\ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_vendor_oui, vendor_oui, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_START_SCAN_CMDID); + +/* Scan adaptive dwell mode configuration */ +#define WMITLV_TABLE_WMI_SCAN_ADAPTIVE_DWELL_CONFIG_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_scan_adaptive_dwell_config_fixed_param, wmi_scan_adaptive_dwell_config_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_scan_adaptive_dwell_parameters_tlv, param, WMITLV_SIZE_VAR) + +WMITLV_CREATE_PARAM_STRUC(WMI_SCAN_ADAPTIVE_DWELL_CONFIG_CMDID); + +/* Set scan selection duty cycle */ +#define WMITLV_TABLE_WMI_SET_SCAN_DBS_DUTY_CYCLE_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_scan_dbs_duty_cycle_fixed_param, wmi_scan_dbs_duty_cycle_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_scan_dbs_duty_cycle_tlv_param, param, WMITLV_SIZE_VAR) + +WMITLV_CREATE_PARAM_STRUC(WMI_SET_SCAN_DBS_DUTY_CYCLE_CMDID); + +/* Start ExtScan Cmd */ +#define WMITLV_TABLE_WMI_EXTSCAN_START_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_extscan_start_cmd_fixed_param, wmi_extscan_start_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_FIXED_STRUC, wmi_ssid, ssid_list, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_FIXED_STRUC, wmi_mac_addr, bssid_list, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, ie_data, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_extscan_bucket, bucket_list, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_extscan_bucket_channel, channel_list, WMITLV_SIZE_VAR) + +WMITLV_CREATE_PARAM_STRUC(WMI_EXTSCAN_START_CMDID); + +/* Stop ExtScan Cmd */ +#define WMITLV_TABLE_WMI_EXTSCAN_STOP_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_extscan_stop_cmd_fixed_param, wmi_extscan_stop_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_EXTSCAN_STOP_CMDID); + +/* Start ExtScan BSSID Monitoring Cmd */ +#define WMITLV_TABLE_WMI_EXTSCAN_CONFIGURE_WLAN_CHANGE_MONITOR_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_extscan_configure_wlan_change_monitor_cmd_fixed_param, wmi_extscan_configure_wlan_change_monitor_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_extscan_wlan_change_bssid_param, wlan_change_descriptor_list, WMITLV_SIZE_VAR) + +WMITLV_CREATE_PARAM_STRUC(WMI_EXTSCAN_CONFIGURE_WLAN_CHANGE_MONITOR_CMDID); + +/* Start Hot List Monitoring Cmd */ +#define WMITLV_TABLE_WMI_EXTSCAN_CONFIGURE_HOTLIST_MONITOR_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_extscan_configure_hotlist_monitor_cmd_fixed_param, wmi_extscan_configure_hotlist_monitor_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_extscan_hotlist_entry, hotlist, WMITLV_SIZE_VAR) + +WMITLV_CREATE_PARAM_STRUC(WMI_EXTSCAN_CONFIGURE_HOTLIST_MONITOR_CMDID); + +/* Get ExtScan BSSID/RSSI list Cmd */ +#define WMITLV_TABLE_WMI_EXTSCAN_GET_CACHED_RESULTS_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_extscan_get_cached_results_cmd_fixed_param, wmi_extscan_get_cached_results_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_EXTSCAN_GET_CACHED_RESULTS_CMDID); + +/* Get ExtScan BSSID monitor results Cmd */ +#define WMITLV_TABLE_WMI_EXTSCAN_GET_WLAN_CHANGE_RESULTS_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_extscan_get_wlan_change_results_cmd_fixed_param, wmi_extscan_get_wlan_change_results_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_EXTSCAN_GET_WLAN_CHANGE_RESULTS_CMDID); + +/* Set ExtScan Capabilities Cmd */ +#define WMITLV_TABLE_WMI_EXTSCAN_SET_CAPABILITIES_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_extscan_set_capabilities_cmd_fixed_param, wmi_extscan_set_capabilities_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_extscan_cache_capabilities, extscan_cache_capabilities, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_extscan_wlan_change_monitor_capabilities, wlan_change_capabilities, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_extscan_hotlist_monitor_capabilities, hotlist_capabilities, WMITLV_SIZE_VAR) + +WMITLV_CREATE_PARAM_STRUC(WMI_EXTSCAN_SET_CAPABILITIES_CMDID); + +/* Get ExtScan Capabilities Cmd */ +#define WMITLV_TABLE_WMI_EXTSCAN_GET_CAPABILITIES_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_extscan_get_capabilities_cmd_fixed_param, wmi_extscan_get_capabilities_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_EXTSCAN_GET_CAPABILITIES_CMDID); + +/* Start SSID Hot List Monitoring Cmd */ +#define WMITLV_TABLE_WMI_EXTSCAN_CONFIGURE_HOTLIST_SSID_MONITOR_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_extscan_configure_hotlist_ssid_monitor_cmd_fixed_param, wmi_extscan_configure_hotlist_ssid_monitor_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_extscan_hotlist_ssid_entry, hotlist_ssid, WMITLV_SIZE_VAR) + +WMITLV_CREATE_PARAM_STRUC(WMI_EXTSCAN_CONFIGURE_HOTLIST_SSID_MONITOR_CMDID); + +/* P2P set vendor ID data Cmd */ +#define WMITLV_TABLE_WMI_P2P_SET_VENDOR_IE_DATA_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_p2p_set_vendor_ie_data_cmd_fixed_param, wmi_p2p_set_vendor_ie_data_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_P2P_SET_VENDOR_IE_DATA_CMDID); + +/* P2P set OppPS parameters Cmd */ +#define WMITLV_TABLE_WMI_P2P_SET_OPPPS_PARAM_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_p2p_set_oppps_cmd_fixed_param, wmi_p2p_set_oppps_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_P2P_SET_OPPPS_PARAM_CMDID); + +/* P2P set listen offload start parameters Cmd */ +#define WMITLV_TABLE_WMI_P2P_LISTEN_OFFLOAD_START_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_p2p_lo_start_cmd_fixed_param, wmi_p2p_lo_start_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, device_types_data, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, prob_resp_data, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_P2P_LISTEN_OFFLOAD_START_CMDID); + +/* P2P set listen offload stop parameters Cmd */ +#define WMITLV_TABLE_WMI_P2P_LISTEN_OFFLOAD_STOP_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_p2p_lo_stop_cmd_fixed_param, wmi_p2p_lo_stop_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_P2P_LISTEN_OFFLOAD_STOP_CMDID); + +/* P2P set listen offload stopped parameters Event */ +#define WMITLV_TABLE_WMI_P2P_LISTEN_OFFLOAD_STOPPED_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_p2p_lo_stopped_event_fixed_param, wmi_p2p_lo_stopped_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_P2P_LISTEN_OFFLOAD_STOPPED_EVENTID); + +/* Pdev set channel Cmd */ +#define WMITLV_TABLE_WMI_PDEV_SET_CHANNEL_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_channel, wmi_channel, chan, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_PDEV_SET_CHANNEL_CMDID); + +#define WMITLV_TABLE_WMI_PDEV_UPDATE_PMK_CACHE_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_pdev_update_pmk_cache_cmd_fixed_param, wmi_pdev_update_pmk_cache_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_pmk_cache, pmk_cache, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_PDEV_UPDATE_PMK_CACHE_CMDID); + +#define WMITLV_TABLE_WMI_PDEV_UPDATE_FILS_HLP_PKT_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_pdev_update_fils_hlp_pkt_cmd_fixed_param, wmi_pdev_update_fils_hlp_pkt_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, fils_hlp_pkt, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_PDEV_UPDATE_FILS_HLP_PKT_CMDID); +/* Echo Cmd */ +#define WMITLV_TABLE_WMI_ECHO_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_echo_cmd_fixed_param, wmi_echo_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_ECHO_CMDID); + +/* Pdev set wmm params */ +#define WMITLV_TABLE_WMI_PDEV_SET_WMM_PARAMS_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_pdev_set_wmm_params_cmd_fixed_param, wmi_pdev_set_wmm_params_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX)\ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_wmm_params, wmi_wmm_params, wmm_params_ac_be, WMITLV_SIZE_FIX)\ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_wmm_params, wmi_wmm_params, wmm_params_ac_bk, WMITLV_SIZE_FIX)\ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_wmm_params, wmi_wmm_params, wmm_params_ac_vi, WMITLV_SIZE_FIX)\ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_wmm_params, wmi_wmm_params, wmm_params_ac_vo, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_PDEV_SET_WMM_PARAMS_CMDID); + +/* Vdev start request Cmd */ +#define WMITLV_TABLE_WMI_VDEV_START_REQUEST_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_vdev_start_request_cmd_fixed_param, wmi_vdev_start_request_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_channel, wmi_channel, chan, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_p2p_noa_descriptor, noa_descriptors, WMITLV_SIZE_VAR) + +WMITLV_CREATE_PARAM_STRUC(WMI_VDEV_START_REQUEST_CMDID); + +/* Vdev restart request cmd */ +#define WMITLV_TABLE_WMI_VDEV_RESTART_REQUEST_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_vdev_start_request_cmd_fixed_param, wmi_vdev_start_request_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_channel, wmi_channel, chan, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_p2p_noa_descriptor, noa_descriptors, WMITLV_SIZE_VAR) + +WMITLV_CREATE_PARAM_STRUC(WMI_VDEV_RESTART_REQUEST_CMDID); + +/* P2P Go set beacon IE cmd */ +#define WMITLV_TABLE_WMI_P2P_GO_SET_BEACON_IE(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_p2p_go_set_beacon_ie_fixed_param, wmi_p2p_go_set_beacon_ie_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, ie_data, WMITLV_SIZE_VAR) + +WMITLV_CREATE_PARAM_STRUC(WMI_P2P_GO_SET_BEACON_IE); + +/* GTK offload Cmd */ +#define WMITLV_TABLE_WMI_GTK_OFFLOAD_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_WMI_GTK_OFFLOAD_CMD_fixed_param, WMI_GTK_OFFLOAD_CMD_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_gtk_offload_fils_tlv_param, wmi_fils_gtk_info, WMITLV_SIZE_VAR) + +WMITLV_CREATE_PARAM_STRUC(WMI_GTK_OFFLOAD_CMDID); + +/* PMF 11w offload Set SA query cmd */ +#define WMITLV_TABLE_WMI_PMF_OFFLOAD_SET_SA_QUERY_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_WMI_PMF_OFFLOAD_SET_SA_QUERY_CMD_fixed_param, WMI_PMF_OFFLOAD_SET_SA_QUERY_CMD_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_PMF_OFFLOAD_SET_SA_QUERY_CMDID); + +/* Scan channel list Cmd */ +#define WMITLV_TABLE_WMI_SCAN_CHAN_LIST_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_scan_chan_list_cmd_fixed_param, wmi_scan_chan_list_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_channel, chan_info, WMITLV_SIZE_VAR) + +WMITLV_CREATE_PARAM_STRUC(WMI_SCAN_CHAN_LIST_CMDID); + +/* STA UAPSD Auto trigger Cmd */ +#define WMITLV_TABLE_WMI_STA_UAPSD_AUTO_TRIG_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_sta_uapsd_auto_trig_cmd_fixed_param, wmi_sta_uapsd_auto_trig_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_sta_uapsd_auto_trig_param, ac_param, WMITLV_SIZE_VAR) + +WMITLV_CREATE_PARAM_STRUC(WMI_STA_UAPSD_AUTO_TRIG_CMDID); + +/* Probe template Cmd */ +#define WMITLV_TABLE_WMI_PRB_TMPL_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_prb_tmpl_cmd_fixed_param, wmi_prb_tmpl_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_bcn_prb_info, wmi_bcn_prb_info, bcn_prb_info, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, bufp, WMITLV_SIZE_VAR) + +WMITLV_CREATE_PARAM_STRUC(WMI_PRB_TMPL_CMDID); + +/* Beacon template Cmd */ +#define WMITLV_TABLE_WMI_BCN_TMPL_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_bcn_tmpl_cmd_fixed_param, wmi_bcn_tmpl_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_bcn_prb_info, wmi_bcn_prb_info, bcn_prb_info, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, bufp, WMITLV_SIZE_VAR) + +WMITLV_CREATE_PARAM_STRUC(WMI_BCN_TMPL_CMDID); + +/* VDEV install key complete Cmd */ +#define WMITLV_TABLE_WMI_VDEV_INSTALL_KEY_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_vdev_install_key_cmd_fixed_param, wmi_vdev_install_key_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX)\ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, key_data, WMITLV_SIZE_VAR) + +WMITLV_CREATE_PARAM_STRUC(WMI_VDEV_INSTALL_KEY_CMDID); + +/* VDEV WNM SLEEP MODE Cmd */ +#define WMITLV_TABLE_WMI_VDEV_WNM_SLEEPMODE_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_WMI_VDEV_WNM_SLEEPMODE_CMD_fixed_param, WMI_VDEV_WNM_SLEEPMODE_CMD_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_VDEV_WNM_SLEEPMODE_CMDID); + +#define WMITLV_TABLE_WMI_VDEV_IPSEC_NATKEEPALIVE_FILTER_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_WMI_VDEV_IPSEC_NATKEEPALIVE_FILTER_CMD_fixed_param, WMI_VDEV_IPSEC_NATKEEPALIVE_FILTER_CMD_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_VDEV_IPSEC_NATKEEPALIVE_FILTER_CMDID); + +/* Peer Assoc Cmd */ +#define WMITLV_TABLE_WMI_PEER_ASSOC_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_peer_assoc_complete_cmd_fixed_param, wmi_peer_assoc_complete_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, peer_legacy_rates, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, peer_ht_rates, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_vht_rate_set, wmi_vht_rate_set, peer_vht_rates, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_he_rate_set, peer_he_rates, WMITLV_SIZE_VAR) + +WMITLV_CREATE_PARAM_STRUC(WMI_PEER_ASSOC_CMDID); + +/* Peer Set Rate Report Condition Cmd */ +#define WMITLV_TABLE_WMI_PEER_SET_RATE_REPORT_CONDITION_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_peer_set_rate_report_condition_fixed_param, wmi_peer_set_rate_report_condition_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_PEER_SET_RATE_REPORT_CONDITION_CMDID); + +/* Add Beacon filter Cmd */ +#define WMITLV_TABLE_WMI_ADD_BCN_FILTER_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_add_bcn_filter_cmd_fixed_param, wmi_add_bcn_filter_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_FXAR(id,op,buf,len, WMITLV_TAG_ARRAY_UINT32, A_UINT32, ie_map, WMITLV_SIZE_FIX, BCN_FLT_MAX_ELEMS_IE_LIST) + +WMITLV_CREATE_PARAM_STRUC(WMI_ADD_BCN_FILTER_CMDID); + +/* Sta keepalive cmd */ +#define WMITLV_TABLE_WMI_STA_KEEPALIVE_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_WMI_STA_KEEPALIVE_CMD_fixed_param, WMI_STA_KEEPALIVE_CMD_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_WMI_STA_KEEPALVE_ARP_RESPONSE, WMI_STA_KEEPALVE_ARP_RESPONSE, arp_resp, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_STA_KEEPALIVE_CMDID); + +/* ARP NS offload Cmd */ +#define WMITLV_TABLE_WMI_SET_ARP_NS_OFFLOAD_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_WMI_SET_ARP_NS_OFFLOAD_CMD_fixed_param, WMI_SET_ARP_NS_OFFLOAD_CMD_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_FXAR(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, WMI_NS_OFFLOAD_TUPLE, ns_tuples, WMITLV_SIZE_FIX, WMI_MAX_NS_OFFLOADS) \ + WMITLV_FXAR(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, WMI_ARP_OFFLOAD_TUPLE, arp_tuples, WMITLV_SIZE_FIX, WMI_MAX_ARP_OFFLOADS) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, WMI_NS_OFFLOAD_TUPLE, ns_ext_tuples, WMITLV_SIZE_VAR) + +WMITLV_CREATE_PARAM_STRUC(WMI_SET_ARP_NS_OFFLOAD_CMDID); + +/* AP PS peer param Cmd */ +#define WMITLV_TABLE_WMI_AP_PS_PEER_PARAM_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_ap_ps_peer_cmd_fixed_param, wmi_ap_ps_peer_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_AP_PS_PEER_PARAM_CMDID); + +/* AP PS enhanced green ap param Cmd */ +#define WMITLV_TABLE_WMI_AP_PS_EGAP_PARAM_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_ap_ps_egap_param_cmd_fixed_param, wmi_ap_ps_egap_param_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_AP_PS_EGAP_PARAM_CMDID); + +/* Profile Trigger Cmd */ +#define WMITLV_TABLE_WMI_WLAN_PROFILE_TRIGGER_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_wlan_profile_trigger_cmd_fixed_param, wmi_wlan_profile_trigger_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_WLAN_PROFILE_TRIGGER_CMDID); + +/* WLAN Profile set hist interval Cmd */ +#define WMITLV_TABLE_WMI_WLAN_PROFILE_SET_HIST_INTVL_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_wlan_profile_set_hist_intvl_cmd_fixed_param, wmi_wlan_profile_set_hist_intvl_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_WLAN_PROFILE_SET_HIST_INTVL_CMDID); + +/* WLAN Profile get profile data Cmd */ +#define WMITLV_TABLE_WMI_WLAN_PROFILE_GET_PROFILE_DATA_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_wlan_profile_get_prof_data_cmd_fixed_param, wmi_wlan_profile_get_prof_data_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_WLAN_PROFILE_GET_PROFILE_DATA_CMDID); + +/* WLAN Profile enable profile ID Cmd */ +#define WMITLV_TABLE_WMI_WLAN_PROFILE_ENABLE_PROFILE_ID_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_wlan_profile_enable_profile_id_cmd_fixed_param, wmi_wlan_profile_enable_profile_id_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_WLAN_PROFILE_ENABLE_PROFILE_ID_CMDID); + +/* WOW Delete Wake Pattern Cmd */ +#define WMITLV_TABLE_WMI_WOW_DEL_WAKE_PATTERN_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_WMI_WOW_DEL_PATTERN_CMD_fixed_param, WMI_WOW_DEL_PATTERN_CMD_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_WOW_DEL_WAKE_PATTERN_CMDID); + +#define WMITLV_TABLE_WMI_WOW_UDP_SVC_OFLD_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_WMI_WOW_UDP_SVC_OFLD_CMD_fixed_param, WMI_WOW_UDP_SVC_OFLD_CMD_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, pattern, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, response, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_WOW_UDP_SVC_OFLD_CMDID); + +#define WMITLV_TABLE_WMI_WOW_HOSTWAKEUP_GPIO_PIN_PATTERN_CONFIG_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_wow_hostwakeup_gpio_pin_pattern_config_cmd_fixed_param, WMI_WOW_HOSTWAKEUP_GPIO_PIN_PATTERN_CONFIG_CMD_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_WOW_HOSTWAKEUP_GPIO_PIN_PATTERN_CONFIG_CMDID); + +#define WMITLV_TABLE_WMI_WOW_SET_ACTION_WAKE_UP_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_wow_set_action_wake_up_cmd_fixed_param, WMI_WOW_SET_ACTION_WAKE_UP_CMD_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_UINT32, A_UINT32, action_bitmaps_per_category, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_WOW_SET_ACTION_WAKE_UP_CMDID); + +/* Wow enable/disable wake up Cmd */ +#define WMITLV_TABLE_WMI_WOW_ENABLE_DISABLE_WAKE_EVENT_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_WMI_WOW_ADD_DEL_EVT_CMD_fixed_param, WMI_WOW_ADD_DEL_EVT_CMD_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_WOW_ENABLE_DISABLE_WAKE_EVENT_CMDID); + +/* RTT measurement request Cmd */ +#define WMITLV_TABLE_WMI_RTT_MEASREQ_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, data, WMITLV_SIZE_VAR) + + +WMITLV_CREATE_PARAM_STRUC(WMI_RTT_MEASREQ_CMDID); + +/* RTT TSF Cmd */ +#define WMITLV_TABLE_WMI_RTT_TSF_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, data, WMITLV_SIZE_VAR) + +WMITLV_CREATE_PARAM_STRUC(WMI_RTT_TSF_CMDID); + +/* RTT OEM req Cmd */ +#define WMITLV_TABLE_WMI_OEM_REQ_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, data, WMITLV_SIZE_VAR) + +WMITLV_CREATE_PARAM_STRUC(WMI_OEM_REQ_CMDID); + +/* RTT OEM request Cmd - DEPRECATED */ +#define WMITLV_TABLE_WMI_OEM_REQUEST_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, data, WMITLV_SIZE_VAR) + +WMITLV_CREATE_PARAM_STRUC(WMI_OEM_REQUEST_CMDID); + +/* RTT OEM req Cmd through LPASS */ +#define WMITLV_TABLE_WMI_LPI_OEM_REQ_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, data, WMITLV_SIZE_VAR) + +WMITLV_CREATE_PARAM_STRUC(WMI_LPI_OEM_REQ_CMDID); + +#define WMITLV_TABLE_WMI_OEM_DMA_RING_CFG_REQ_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_oem_dma_ring_cfg_req_fixed_param, wmi_oem_dma_ring_cfg_req_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_OEM_DMA_RING_CFG_REQ_CMDID); + +/* Spectral scan configure Cmd */ +#define WMITLV_TABLE_WMI_VDEV_SPECTRAL_SCAN_CONFIGURE_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_vdev_spectral_configure_cmd_fixed_param, wmi_vdev_spectral_configure_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_VDEV_SPECTRAL_SCAN_CONFIGURE_CMDID); + +/* Spectral scan enable Cmd */ +#define WMITLV_TABLE_WMI_VDEV_SPECTRAL_SCAN_ENABLE_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_vdev_spectral_enable_cmd_fixed_param, wmi_vdev_spectral_enable_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_VDEV_SPECTRAL_SCAN_ENABLE_CMDID); + +/* Request stats Cmd */ +#define WMITLV_TABLE_WMI_REQUEST_STATS_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_request_stats_cmd_fixed_param, wmi_request_stats_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_inst_rssi_stats_params, inst_rssi_params, WMITLV_SIZE_VAR) + +WMITLV_CREATE_PARAM_STRUC(WMI_REQUEST_STATS_CMDID); + +/* Request for memory dump stats Cmd */ +#define WMITLV_TABLE_WMI_GET_FW_MEM_DUMP_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_get_fw_mem_dump_fixed_param, wmi_get_fw_mem_dump_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_fw_mem_dump, fw_mem_dump_params, WMITLV_SIZE_VAR) + +WMITLV_CREATE_PARAM_STRUC(WMI_GET_FW_MEM_DUMP_CMDID); + +/* flush debug messages */ +#define WMITLV_TABLE_WMI_DEBUG_MESG_FLUSH_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_debug_mesg_flush_fixed_param, wmi_debug_mesg_flush_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_DEBUG_MESG_FLUSH_CMDID); + +/* Request to config the DIAG Events and LOGs*/ +#define WMITLV_TABLE_WMI_DIAG_EVENT_LOG_CONFIG_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_diag_event_log_config_fixed_param, wmi_diag_event_log_config_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_UINT32, A_UINT32, diag_events_logs_list, WMITLV_SIZE_VAR) + +WMITLV_CREATE_PARAM_STRUC(WMI_DIAG_EVENT_LOG_CONFIG_CMDID); + +/* Set config params */ +#define WMITLV_TABLE_WMI_START_LINK_STATS_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_start_link_stats_cmd_fixed_param, wmi_start_link_stats_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_START_LINK_STATS_CMDID); + +/* Request to clear link stats */ +#define WMITLV_TABLE_WMI_CLEAR_LINK_STATS_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_clear_link_stats_cmd_fixed_param, wmi_clear_link_stats_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_CLEAR_LINK_STATS_CMDID); + +/* Request stats Cmd */ +#define WMITLV_TABLE_WMI_REQUEST_LINK_STATS_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_request_link_stats_cmd_fixed_param, wmi_request_link_stats_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_REQUEST_LINK_STATS_CMDID); + +/* Network list offload config Cmd */ +#define WMITLV_TABLE_WMI_NETWORK_LIST_OFFLOAD_CONFIG_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_nlo_config_cmd_fixed_param, wmi_nlo_config_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, nlo_configured_parameters, nlo_list, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_UINT32, A_UINT32, channel_list, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, nlo_channel_prediction_cfg, channel_prediction_param, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_enlo_candidate_score_param, enlo_candidate_score_params, candidate_score_params, WMITLV_SIZE_FIX)\ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_vendor_oui, vendor_oui, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_connected_nlo_rssi_params, connected_nlo_rssi_params, cnlo_rssi_params, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, connected_nlo_bss_band_rssi_pref, cnlo_bss_band_rssi_pref, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_NETWORK_LIST_OFFLOAD_CONFIG_CMDID); + +/* Passpoint list offload config Cmd */ +#define WMITLV_TABLE_WMI_PASSPOINT_LIST_CONFIG_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_passpoint_config_cmd_fixed_param, wmi_passpoint_config_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_PASSPOINT_LIST_CONFIG_CMDID); + +/* CSA offload enable Cmd */ +#define WMITLV_TABLE_WMI_CSA_OFFLOAD_ENABLE_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_csa_offload_enable_cmd_fixed_param, wmi_csa_offload_enable_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_CSA_OFFLOAD_ENABLE_CMDID); + +/* CSA offload channel switch Cmd */ +#define WMITLV_TABLE_WMI_CSA_OFFLOAD_CHANSWITCH_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_csa_offload_chanswitch_cmd_fixed_param, wmi_csa_offload_chanswitch_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_channel, wmi_channel, chan, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_CSA_OFFLOAD_CHANSWITCH_CMDID); + +/* Chatter set mode Cmd */ +#define WMITLV_TABLE_WMI_CHATTER_SET_MODE_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_chatter_set_mode_cmd_fixed_param, wmi_chatter_set_mode_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_CHATTER_SET_MODE_CMDID); + + +/* PDEV UTF Cmd */ +#define WMITLV_TABLE_WMI_PDEV_UTF_CMDID(id,op,buf,len)\ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, data, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_PDEV_UTF_CMDID); + +/* PDEV QVIT Cmd */ +#define WMITLV_TABLE_WMI_PDEV_QVIT_CMDID(id,op,buf,len)\ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, data, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_PDEV_QVIT_CMDID); + +#define WMITLV_TABLE_WMI_PDEV_SET_WAKEUP_CONFIG_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_WMI_PDEV_SET_WAKEUP_CONFIG_CMDID_fixed_param, WMI_PDEV_SET_WAKEUP_CONFIG_CMDID_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_PDEV_SET_WAKEUP_CONFIG_CMDID); + +/* Vdev Set keep alive Cmd */ +#define WMITLV_TABLE_WMI_VDEV_SET_KEEPALIVE_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_vdev_set_keepalive_cmd_fixed_param, wmi_vdev_set_keepalive_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_VDEV_SET_KEEPALIVE_CMDID); + +/* Vdev Get keep alive Cmd */ +#define WMITLV_TABLE_WMI_VDEV_GET_KEEPALIVE_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_vdev_get_keepalive_cmd_fixed_param, wmi_vdev_get_keepalive_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_VDEV_GET_KEEPALIVE_CMDID); + +/*FWTEST Set TBTT mode Cmd*/ +#define WMITLV_TABLE_WMI_FWTEST_VDEV_MCC_SET_TBTT_MODE_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_vdev_mcc_set_tbtt_mode_cmd_fixed_param, wmi_vdev_mcc_set_tbtt_mode_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_FWTEST_VDEV_MCC_SET_TBTT_MODE_CMDID); + +/* FWTEST set NoA parameters Cmd */ +#define WMITLV_TABLE_WMI_FWTEST_P2P_SET_NOA_PARAM_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_p2p_set_noa_cmd_fixed_param, wmi_p2p_set_noa_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_p2p_noa_descriptor, noa_descriptor, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_FWTEST_P2P_SET_NOA_PARAM_CMDID); + +/* Unit test FW */ +#define WMITLV_TABLE_WMI_UNIT_TEST_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_unit_test_cmd_fixed_param, wmi_unit_test_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_UINT32, A_UINT32, args, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_UNIT_TEST_CMDID); + +/* Force Fw Hang Cmd */ +#define WMITLV_TABLE_WMI_FORCE_FW_HANG_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_WMI_FORCE_FW_HANG_CMD_fixed_param, WMI_FORCE_FW_HANG_CMD_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_FORCE_FW_HANG_CMDID); + +/* Set Mcast address Cmd */ +#define WMITLV_TABLE_WMI_SET_MCASTBCAST_FILTER_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_WMI_SET_MCASTBCAST_FILTER_CMD_fixed_param, WMI_SET_MCASTBCAST_FILTER_CMD_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_SET_MCASTBCAST_FILTER_CMDID); + +/* Enhanced Mcast add/delete filter list cmd */ +#define WMITLV_TABLE_WMI_SET_MULTIPLE_MCAST_FILTER_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id, op, buf, len, WMITLV_TAG_STRUC_wmi_set_multiple_mcast_filter_cmd_fixed_param, WMI_SET_MULTIPLE_MCAST_FILTER_CMD_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id, op, buf, len, WMITLV_TAG_ARRAY_FIXED_STRUC, wmi_mac_addr, mcast_list, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_SET_MULTIPLE_MCAST_FILTER_CMDID); + +/* Set dbglog time stamp sync cmd */ +#define WMITLV_TABLE_WMI_DBGLOG_TIME_STAMP_SYNC_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_dbglog_time_stamp_sync_cmd_fixed_param, WMI_DBGLOG_TIME_STAMP_SYNC_CMD_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_DBGLOG_TIME_STAMP_SYNC_CMDID); + +/* GPIO config Cmd */ +#define WMITLV_TABLE_WMI_GPIO_CONFIG_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_gpio_config_cmd_fixed_param, wmi_gpio_config_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_GPIO_CONFIG_CMDID); + +/* GPIO output Cmd */ +#define WMITLV_TABLE_WMI_GPIO_OUTPUT_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_gpio_output_cmd_fixed_param, wmi_gpio_output_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_GPIO_OUTPUT_CMDID); + +/* Peer add WDA entry Cmd */ +#define WMITLV_TABLE_WMI_PEER_ADD_WDS_ENTRY_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_peer_add_wds_entry_cmd_fixed_param, wmi_peer_add_wds_entry_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_PEER_ADD_WDS_ENTRY_CMDID); + +/*Peer remove WDS entry Cmd */ +#define WMITLV_TABLE_WMI_PEER_REMOVE_WDS_ENTRY_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_peer_remove_wds_entry_cmd_fixed_param, wmi_peer_remove_wds_entry_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_PEER_REMOVE_WDS_ENTRY_CMDID); + +/* Beacon tx Cmd */ +#define WMITLV_TABLE_WMI_BCN_TX_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_bcn_tx_hdr, wmi_bcn_tx_hdr, hdr, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, bufp, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_BCN_TX_CMDID); + +/* PDEV send Beacon Cmd */ +#define WMITLV_TABLE_WMI_PDEV_SEND_BCN_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_bcn_send_from_host_cmd_fixed_param, wmi_bcn_send_from_host_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_PDEV_SEND_BCN_CMDID); + +/* Management tx Cmd */ +#define WMITLV_TABLE_WMI_MGMT_TX_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_mgmt_tx_hdr, wmi_mgmt_tx_hdr, hdr, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, bufp, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_MGMT_TX_CMDID); + +/* Management tx send cmd */ +#define WMITLV_TABLE_WMI_MGMT_TX_SEND_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_mgmt_tx_send_cmd_fixed_param, wmi_mgmt_tx_send_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, bufp, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_tx_send_params, wmi_tx_send_params, tx_send_params, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_MGMT_TX_SEND_CMDID); + +/* offchan data tx send cmd */ +#define WMITLV_TABLE_WMI_OFFCHAN_DATA_TX_SEND_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_offchan_data_tx_send_cmd_fixed_param, wmi_offchan_data_tx_send_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, bufp, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_tx_send_params, wmi_tx_send_params, tx_send_params, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_OFFCHAN_DATA_TX_SEND_CMDID); + +/* ADD clear response Cmd */ +#define WMITLV_TABLE_WMI_ADDBA_CLEAR_RESP_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_addba_clear_resp_cmd_fixed_param, wmi_addba_clear_resp_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_ADDBA_CLEAR_RESP_CMDID); + +/* ADD BA send Cmd */ +#define WMITLV_TABLE_WMI_ADDBA_SEND_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_addba_send_cmd_fixed_param, wmi_addba_send_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_ADDBA_SEND_CMDID); + +/* DEL BA send Cmd */ +#define WMITLV_TABLE_WMI_DELBA_SEND_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_delba_send_cmd_fixed_param, wmi_delba_send_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_DELBA_SEND_CMDID); + +/* ADD BA set response Cmd */ +#define WMITLV_TABLE_WMI_ADDBA_SET_RESP_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_addba_setresponse_cmd_fixed_param, wmi_addba_setresponse_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_ADDBA_SET_RESP_CMDID); + +/* Send single AMSDU Cmd */ +#define WMITLV_TABLE_WMI_SEND_SINGLEAMSDU_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_send_singleamsdu_cmd_fixed_param, wmi_send_singleamsdu_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_SEND_SINGLEAMSDU_CMDID); + +/* PDev Packet Log enable Cmd */ +#define WMITLV_TABLE_WMI_PDEV_PKTLOG_ENABLE_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_pdev_pktlog_enable_cmd_fixed_param, wmi_pdev_pktlog_enable_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_PDEV_PKTLOG_ENABLE_CMDID); + +/* PDev Packet Log disable Cmd */ +#define WMITLV_TABLE_WMI_PDEV_PKTLOG_DISABLE_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_pdev_pktlog_disable_cmd_fixed_param, wmi_pdev_pktlog_disable_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_PDEV_PKTLOG_DISABLE_CMDID); + +/* PDev set HT Cap IE Cmd */ +#define WMITLV_TABLE_WMI_PDEV_SET_HT_CAP_IE_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_pdev_set_ht_ie_cmd_fixed_param, wmi_pdev_set_ht_ie_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX)\ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, ie_data, WMITLV_SIZE_VAR) + +WMITLV_CREATE_PARAM_STRUC(WMI_PDEV_SET_HT_CAP_IE_CMDID); + +/* PDev set VHT Cap IE Cmd */ +#define WMITLV_TABLE_WMI_PDEV_SET_VHT_CAP_IE_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_pdev_set_vht_ie_cmd_fixed_param, wmi_pdev_set_vht_ie_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX)\ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, ie_data, WMITLV_SIZE_VAR) + +WMITLV_CREATE_PARAM_STRUC(WMI_PDEV_SET_VHT_CAP_IE_CMDID); + +/* PDev Set DSCP to TID map Cmd */ +#define WMITLV_TABLE_WMI_PDEV_SET_DSCP_TID_MAP_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_pdev_set_dscp_tid_map_cmd_fixed_param, wmi_pdev_set_dscp_tid_map_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_PDEV_SET_DSCP_TID_MAP_CMDID); + +/* PDev Green AP PS enable Cmd */ +#define WMITLV_TABLE_WMI_PDEV_GREEN_AP_PS_ENABLE_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_pdev_green_ap_ps_enable_cmd_fixed_param, wmi_pdev_green_ap_ps_enable_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_PDEV_GREEN_AP_PS_ENABLE_CMDID); + +/* PDEV Get TPC Config Cmd */ +#define WMITLV_TABLE_WMI_PDEV_GET_TPC_CONFIG_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_pdev_get_tpc_config_cmd_fixed_param, wmi_pdev_get_tpc_config_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_PDEV_GET_TPC_CONFIG_CMDID); + +/* PDEV Get Antenna diversity chains rssi and antenna index Cmd */ +#define WMITLV_TABLE_WMI_PDEV_DIV_GET_RSSI_ANTID_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_pdev_div_get_rssi_antid_fixed_param, wmi_pdev_div_get_rssi_antid_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_PDEV_DIV_GET_RSSI_ANTID_CMDID); + +#define WMITLV_TABLE_WMI_PDEV_BSS_CHAN_INFO_REQUEST_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_pdev_bss_chan_info_request_fixed_param, wmi_pdev_bss_chan_info_request_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_PDEV_BSS_CHAN_INFO_REQUEST_CMDID); + +/* VDEV Get Tx power Cmd */ +#define WMITLV_TABLE_WMI_VDEV_GET_TX_POWER_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_vdev_get_tx_power_cmd_fixed_param, wmi_vdev_get_tx_power_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_VDEV_GET_TX_POWER_CMDID); + +/* Limit Offchannel duration Cmd */ +#define WMITLV_TABLE_WMI_VDEV_LIMIT_OFFCHAN_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_vdev_limit_offchan_cmd_fixed_param, wmi_vdev_limit_offchan_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_VDEV_LIMIT_OFFCHAN_CMDID); + +/* PDEV Set Base Mac Address Cmd */ +#define WMITLV_TABLE_WMI_PDEV_SET_BASE_MACADDR_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_pdev_set_base_macaddr_cmd_fixed_param, wmi_pdev_set_base_macaddr_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_PDEV_SET_BASE_MACADDR_CMDID); + +/* MIB Stats*/ +#define WMITLV_TABLE_WMI_MIB_STATS_ENABLE_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_mib_stats_enable_cmd_fixed_param, wmi_mib_stats_enable_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_MIB_STATS_ENABLE_CMDID); + +/* Peer multicast group Cmd */ +#define WMITLV_TABLE_WMI_PEER_MCAST_GROUP_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_peer_mcast_group_cmd_fixed_param, wmi_peer_mcast_group_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_PEER_MCAST_GROUP_CMDID); + +/* Roam AP profile Cmd */ +#define WMITLV_TABLE_WMI_ROAM_AP_PROFILE(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_roam_ap_profile_fixed_param, wmi_roam_ap_profile_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_ap_profile, wmi_ap_profile, ap_profile, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_ROAM_AP_PROFILE); + +/* Roam sync complete Cmd */ +#define WMITLV_TABLE_WMI_ROAM_SYNCH_COMPLETE(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_roam_synch_complete_fixed_param, wmi_roam_synch_complete_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_ROAM_SYNCH_COMPLETE); + +#define WMITLV_TABLE_WMI_ROAM_SET_RIC_REQUEST_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_ric_request_fixed_param, wmi_ric_request_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_ric_tspec, ric_tspec_list, WMITLV_SIZE_VAR) + +WMITLV_CREATE_PARAM_STRUC(WMI_ROAM_SET_RIC_REQUEST_CMDID); + +/* Scan scheduler priority Table Cmd */ +#define WMITLV_TABLE_WMI_SCAN_SCH_PRIO_TBL_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_scan_sch_priority_table_cmd_fixed_param, wmi_scan_sch_priority_table_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_UINT32, A_UINT32, mapping_table, WMITLV_SIZE_VAR) + +WMITLV_CREATE_PARAM_STRUC(WMI_SCAN_SCH_PRIO_TBL_CMDID); + +/* PDEV DFS enable Cmd */ +#define WMITLV_TABLE_WMI_PDEV_DFS_ENABLE_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_pdev_dfs_enable_cmd_fixed_param, wmi_pdev_dfs_enable_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_PDEV_DFS_ENABLE_CMDID); + +/* PDEV DFS disable Cmd */ +#define WMITLV_TABLE_WMI_PDEV_DFS_DISABLE_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_pdev_dfs_disable_cmd_fixed_param, wmi_pdev_dfs_disable_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_PDEV_DFS_DISABLE_CMDID); + +/* DFS phyerr parse/filter offload enable Cmd */ +#define WMITLV_TABLE_WMI_DFS_PHYERR_FILTER_ENA_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_dfs_phyerr_filter_ena_cmd_fixed_param, wmi_dfs_phyerr_filter_ena_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_DFS_PHYERR_FILTER_ENA_CMDID); + +/* DFS phyerr parse/filter offload disable Cmd */ +#define WMITLV_TABLE_WMI_DFS_PHYERR_FILTER_DIS_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_dfs_phyerr_filter_dis_cmd_fixed_param, wmi_dfs_phyerr_filter_dis_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_DFS_PHYERR_FILTER_DIS_CMDID); + +/* DFS phyerr processing offload enable cmd */ +#define WMITLV_TABLE_WMI_PDEV_DFS_PHYERR_OFFLOAD_ENABLE_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_pdev_dfs_phyerr_offload_enable_cmd_fixed_param, wmi_pdev_dfs_phyerr_offload_enable_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_PDEV_DFS_PHYERR_OFFLOAD_ENABLE_CMDID); + +/* DFS phyerr processing offload disble cmd */ +#define WMITLV_TABLE_WMI_PDEV_DFS_PHYERR_OFFLOAD_DISABLE_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_pdev_dfs_phyerr_offload_disable_cmd_fixed_param, wmi_pdev_dfs_phyerr_offload_disable_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_PDEV_DFS_PHYERR_OFFLOAD_DISABLE_CMDID); + +/* set ADFS channel config cmd */ +#define WMITLV_TABLE_WMI_VDEV_ADFS_CH_CFG_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_vdev_adfs_ch_cfg_cmd_fixed_param, wmi_vdev_adfs_ch_cfg_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_VDEV_ADFS_CH_CFG_CMDID); + +/* DFS abort ADFS ocac currently in progress */ +#define WMITLV_TABLE_WMI_VDEV_ADFS_OCAC_ABORT_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_vdev_adfs_ocac_abort_cmd_fixed_param, wmi_vdev_adfs_ocac_abort_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_VDEV_ADFS_OCAC_ABORT_CMDID); + +/* WOW Add Wake Pattern Cmd */ +#define WMITLV_TABLE_WMI_WOW_ADD_WAKE_PATTERN_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_WMI_WOW_ADD_PATTERN_CMD_fixed_param, WMI_WOW_ADD_PATTERN_CMD_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, WOW_BITMAP_PATTERN_T, pattern_info_bitmap, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, WOW_IPV4_SYNC_PATTERN_T, pattern_info_ipv4, WMITLV_SIZE_VAR)\ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, WOW_IPV6_SYNC_PATTERN_T, pattern_info_ipv6, WMITLV_SIZE_VAR)\ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, WOW_MAGIC_PATTERN_CMD, pattern_info_magic_pattern, WMITLV_SIZE_VAR)\ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_UINT32, A_UINT32, pattern_info_timeout, WMITLV_SIZE_VAR) \ + WMITLV_FXAR(id,op,buf,len, WMITLV_TAG_ARRAY_UINT32, A_UINT32, ra_ratelimit_interval, WMITLV_SIZE_FIX, 1) + +WMITLV_CREATE_PARAM_STRUC(WMI_WOW_ADD_WAKE_PATTERN_CMDID); + +/* IOAC add keep alive cmd. */ +#define WMITLV_TABLE_WMI_WOW_IOAC_ADD_KEEPALIVE_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_WMI_WOW_IOAC_ADD_KEEPALIVE_CMD_fixed_param, WMI_WOW_IOAC_ADD_KEEPALIVE_CMD_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, WMI_WOW_IOAC_KEEPALIVE_T, keepalive_set, WMITLV_SIZE_VAR) + +WMITLV_CREATE_PARAM_STRUC(WMI_WOW_IOAC_ADD_KEEPALIVE_CMDID); + +/* IOAC del keep alive cmd. */ +#define WMITLV_TABLE_WMI_WOW_IOAC_DEL_KEEPALIVE_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_WMI_WOW_IOAC_DEL_KEEPALIVE_CMD_fixed_param, WMI_WOW_IOAC_DEL_KEEPALIVE_CMD_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_WOW_IOAC_DEL_KEEPALIVE_CMDID); + +/* WOW IOAC Add Wake Pattern Cmd */ +#define WMITLV_TABLE_WMI_WOW_IOAC_ADD_WAKE_PATTERN_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_WMI_WOW_IOAC_ADD_PATTERN_CMD_fixed_param, WMI_WOW_IOAC_ADD_PATTERN_CMD_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, WOW_IOAC_PKT_PATTERN_T, pattern_info_pkt, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, WOW_IOAC_TMR_PATTERN_T, pattern_info_tmr, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, WOW_IOAC_SOCK_PATTERN_T, pattern_info_sock, WMITLV_SIZE_VAR) + +WMITLV_CREATE_PARAM_STRUC(WMI_WOW_IOAC_ADD_WAKE_PATTERN_CMDID); + +/* WOW IOAC Delete Wake Pattern Cmd */ +#define WMITLV_TABLE_WMI_WOW_IOAC_DEL_WAKE_PATTERN_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_WMI_WOW_IOAC_DEL_PATTERN_CMD_fixed_param, WMI_WOW_IOAC_DEL_PATTERN_CMD_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_WOW_IOAC_DEL_WAKE_PATTERN_CMDID); + +/* extwow enable Cmd */ +#define WMITLV_TABLE_WMI_EXTWOW_ENABLE_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_extwow_enable_cmd_fixed_param, wmi_extwow_enable_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_EXTWOW_ENABLE_CMDID); + +/* extwow set wakeup params cmd for app type1 */ +#define WMITLV_TABLE_WMI_EXTWOW_SET_APP_TYPE1_PARAMS_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_extwow_set_app_type1_params_cmd_fixed_param, wmi_extwow_set_app_type1_params_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_EXTWOW_SET_APP_TYPE1_PARAMS_CMDID); + +/* extwow set wakeup params cmd for app type2 */ +#define WMITLV_TABLE_WMI_EXTWOW_SET_APP_TYPE2_PARAMS_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_extwow_set_app_type2_params_cmd_fixed_param, wmi_extwow_set_app_type2_params_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_EXTWOW_SET_APP_TYPE2_PARAMS_CMDID); + +/* Stop scan Cmd */ +#define WMITLV_TABLE_WMI_STOP_SCAN_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_stop_scan_cmd_fixed_param, wmi_stop_scan_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_STOP_SCAN_CMDID); + +#define WMITLV_TABLE_WMI_PDEV_SET_PARAM_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_pdev_set_param_cmd_fixed_param, wmi_pdev_set_param_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_PDEV_SET_PARAM_CMDID); + +/* PDev set quiet Cmd */ +#define WMITLV_TABLE_WMI_PDEV_SET_QUIET_MODE_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_pdev_set_quiet_cmd_fixed_param, wmi_pdev_set_quiet_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_PDEV_SET_QUIET_MODE_CMDID); + +/* VDev set quiet Cmd */ +#define WMITLV_TABLE_WMI_VDEV_SET_QUIET_MODE_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_vdev_set_quiet_cmd_fixed_param, wmi_vdev_set_quiet_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_VDEV_SET_QUIET_MODE_CMDID); + +/* Setting custom aggregation size using command */ +#define WMITLV_TABLE_WMI_VDEV_SET_CUSTOM_AGGR_SIZE_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_vdev_set_custom_aggr_size_cmd_fixed_param, wmi_vdev_set_custom_aggr_size_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_VDEV_SET_CUSTOM_AGGR_SIZE_CMDID); + +/* Vdev create Cmd */ +#define WMITLV_TABLE_WMI_VDEV_CREATE_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_vdev_create_cmd_fixed_param, wmi_vdev_create_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_vdev_txrx_streams, cfg_txrx_streams, WMITLV_SIZE_VAR) + +WMITLV_CREATE_PARAM_STRUC(WMI_VDEV_CREATE_CMDID); + +/* Vdev delete Cmd */ +#define WMITLV_TABLE_WMI_VDEV_DELETE_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_vdev_delete_cmd_fixed_param, wmi_vdev_delete_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_VDEV_DELETE_CMDID); + +/* Vdev up Cmd */ +#define WMITLV_TABLE_WMI_VDEV_UP_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_vdev_up_cmd_fixed_param, wmi_vdev_up_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_VDEV_UP_CMDID); + +/* Vdev stop cmd */ +#define WMITLV_TABLE_WMI_VDEV_STOP_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_vdev_stop_cmd_fixed_param, wmi_vdev_stop_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_VDEV_STOP_CMDID); + +/* Vdev down Cmd */ +#define WMITLV_TABLE_WMI_VDEV_DOWN_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_vdev_down_cmd_fixed_param, wmi_vdev_down_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_VDEV_DOWN_CMDID); + +/* Vdev set param Cmd */ +#define WMITLV_TABLE_WMI_VDEV_SET_PARAM_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_vdev_set_param_cmd_fixed_param, wmi_vdev_set_param_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_VDEV_SET_PARAM_CMDID); + +/* Pdev suspend Cmd */ +#define WMITLV_TABLE_WMI_PDEV_SUSPEND_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_pdev_suspend_cmd_fixed_param, wmi_pdev_suspend_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_PDEV_SUSPEND_CMDID); + +/* Pdev Resume Cmd */ +#define WMITLV_TABLE_WMI_PDEV_RESUME_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_pdev_resume_cmd_fixed_param, wmi_pdev_resume_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_PDEV_RESUME_CMDID); + +#define WMITLV_TABLE_WMI_SCAN_UPDATE_REQUEST_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_WMI_scan_update_request_cmd_fixed_param, wmi_scan_update_request_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_SCAN_UPDATE_REQUEST_CMDID); + +#define WMITLV_TABLE_WMI_SCAN_PROB_REQ_OUI_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_scan_prob_req_oui_cmd_fixed_param, wmi_scan_prob_req_oui_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_vendor_oui, vendor_oui, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_SCAN_PROB_REQ_OUI_CMDID); + +#define WMITLV_TABLE_WMI_CHATTER_ADD_COALESCING_FILTER_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len,WMITLV_TAG_STRUC_wmi_chatter_coalescing_add_filter_cmd_fixed_param, wmi_chatter_coalescing_add_filter_cmd_fixed_param, fixed_param,WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, chatter_pkt_coalescing_filter, coalescing_filter, WMITLV_SIZE_VAR) + +WMITLV_CREATE_PARAM_STRUC(WMI_CHATTER_ADD_COALESCING_FILTER_CMDID); + +#define WMITLV_TABLE_WMI_CHATTER_DELETE_COALESCING_FILTER_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_chatter_coalescing_delete_filter_cmd_fixed_param,wmi_chatter_coalescing_delete_filter_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + +WMITLV_CREATE_PARAM_STRUC(WMI_CHATTER_DELETE_COALESCING_FILTER_CMDID); + +#define WMITLV_TABLE_WMI_CHATTER_COALESCING_QUERY_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_chatter_coalescing_query_cmd_fixed_param, wmi_chatter_coalescing_query_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + +WMITLV_CREATE_PARAM_STRUC(WMI_CHATTER_COALESCING_QUERY_CMDID); + +#define WMITLV_TABLE_WMI_TXBF_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len,WMITLV_TAG_STRUC_wmi_txbf_cmd_fixed_param, wmi_txbf_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + +WMITLV_CREATE_PARAM_STRUC(WMI_TXBF_CMDID); + +#define WMITLV_TABLE_WMI_DBGLOG_CFG_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_debug_log_config_cmd_fixed_param, wmi_debug_log_config_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_FXAR(id,op,buf,len,WMITLV_TAG_ARRAY_UINT32, A_UINT32, module_id_bitmap, WMITLV_SIZE_FIX, MAX_MODULE_ID_BITMAP_WORDS) \ + +WMITLV_CREATE_PARAM_STRUC(WMI_DBGLOG_CFG_CMDID); + +#define WMITLV_TABLE_WMI_VDEV_WMM_ADDTS_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_vdev_wmm_addts_cmd_fixed_param, wmi_vdev_wmm_addts_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_VDEV_WMM_ADDTS_CMDID); + +#define WMITLV_TABLE_WMI_VDEV_WMM_DELTS_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_vdev_wmm_delts_cmd_fixed_param, wmi_vdev_wmm_delts_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_VDEV_WMM_DELTS_CMDID); + +#define WMITLV_TABLE_WMI_VDEV_SET_WMM_PARAMS_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_vdev_set_wmm_params_cmd_fixed_param, wmi_vdev_set_wmm_params_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_VDEV_SET_WMM_PARAMS_CMDID); + +#define WMITLV_TABLE_WMI_VDEV_SET_GTX_PARAMS_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_vdev_set_gtx_params_cmd_fixed_param, wmi_vdev_set_gtx_params_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_VDEV_SET_GTX_PARAMS_CMDID); + +/* TDLS Enable/Disable Cmd */ +#define WMITLV_TABLE_WMI_TDLS_SET_STATE_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_tdls_set_state_cmd_fixed_param, \ + wmi_tdls_set_state_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_TDLS_SET_STATE_CMDID); + +/* TDLS Peer Update Cmd */ +#define WMITLV_TABLE_WMI_TDLS_PEER_UPDATE_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_tdls_peer_update_cmd_fixed_param, wmi_tdls_peer_update_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_tdls_peer_capabilities, wmi_tdls_peer_capabilities, peer_caps, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_channel, peer_chan_list, WMITLV_SIZE_VAR) + +WMITLV_CREATE_PARAM_STRUC(WMI_TDLS_PEER_UPDATE_CMDID); + +/* Enable/Disable TDLS Offchannel Cmd */ +#define WMITLV_TABLE_WMI_TDLS_SET_OFFCHAN_MODE_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_tdls_set_offchan_mode_cmd_fixed_param, \ + wmi_tdls_set_offchan_mode_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_TDLS_SET_OFFCHAN_MODE_CMDID); + + +/* Resmgr Enable/Disable Adaptive OCS CMD */ +#define WMITLV_TABLE_WMI_RESMGR_ADAPTIVE_OCS_ENABLE_DISABLE_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_resmgr_adaptive_ocs_enable_disable_cmd_fixed_param, \ + wmi_resmgr_adaptive_ocs_enable_disable_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_RESMGR_ADAPTIVE_OCS_ENABLE_DISABLE_CMDID); + +/* Resmgr Set Channel Time Quota CMD */ +#define WMITLV_TABLE_WMI_RESMGR_SET_CHAN_TIME_QUOTA_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_resmgr_set_chan_time_quota_cmd_fixed_param, \ + wmi_resmgr_set_chan_time_quota_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, data, WMITLV_SIZE_VAR) + +WMITLV_CREATE_PARAM_STRUC(WMI_RESMGR_SET_CHAN_TIME_QUOTA_CMDID); + +/* Resmgr Set Channel Latency CMD */ +#define WMITLV_TABLE_WMI_RESMGR_SET_CHAN_LATENCY_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_resmgr_set_chan_latency_cmd_fixed_param, \ + wmi_resmgr_set_chan_latency_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, data, WMITLV_SIZE_VAR) + +WMITLV_CREATE_PARAM_STRUC(WMI_RESMGR_SET_CHAN_LATENCY_CMDID); + +/* STA SMPS Force Mode CMD */ +#define WMITLV_TABLE_WMI_STA_SMPS_FORCE_MODE_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_sta_smps_force_mode_cmd_fixed_param, \ + wmi_sta_smps_force_mode_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_STA_SMPS_FORCE_MODE_CMDID); + +/* wlan hb enable/disable CMD */ +#define WMITLV_TABLE_WMI_HB_SET_ENABLE_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_hb_set_enable_cmd_fixed_param, \ + wmi_hb_set_enable_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_HB_SET_ENABLE_CMDID); + +/* wlan hb set tcp params CMD */ +#define WMITLV_TABLE_WMI_HB_SET_TCP_PARAMS_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_hb_set_tcp_params_cmd_fixed_param, \ + wmi_hb_set_tcp_params_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_HB_SET_TCP_PARAMS_CMDID); + +/* wlan hb set tcp pkt filter CMD */ +#define WMITLV_TABLE_WMI_HB_SET_TCP_PKT_FILTER_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_hb_set_tcp_pkt_filter_cmd_fixed_param, \ + wmi_hb_set_tcp_pkt_filter_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_HB_SET_TCP_PKT_FILTER_CMDID); + +/* wlan set udp params CMD */ +#define WMITLV_TABLE_WMI_HB_SET_UDP_PARAMS_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_hb_set_udp_params_cmd_fixed_param, \ + wmi_hb_set_udp_params_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_HB_SET_UDP_PARAMS_CMDID); + +/* wlan hb set udp pkt filter CMD */ +#define WMITLV_TABLE_WMI_HB_SET_UDP_PKT_FILTER_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_hb_set_udp_pkt_filter_cmd_fixed_param, \ + wmi_hb_set_udp_pkt_filter_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_HB_SET_UDP_PKT_FILTER_CMDID); + +/* STA SMPS Param CMD */ +#define WMITLV_TABLE_WMI_STA_SMPS_PARAM_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_sta_smps_param_cmd_fixed_param, \ + wmi_sta_smps_param_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_STA_SMPS_PARAM_CMDID); + +/* MCC Adaptive Scheduler Traffic Stats */ +#define WMITLV_TABLE_WMI_MCC_SCHED_TRAFFIC_STATS_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_mcc_sched_traffic_stats_cmd_fixed_param, wmi_mcc_sched_traffic_stats_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id, op, buf, len, WMITLV_TAG_ARRAY_STRUC, wmi_mcc_sched_sta_traffic_stats, mcc_sched_sta_traffic_stats_list, WMITLV_SIZE_VAR) + +WMITLV_CREATE_PARAM_STRUC(WMI_MCC_SCHED_TRAFFIC_STATS_CMDID); + +#define WMITLV_TABLE_WMI_BATCH_SCAN_ENABLE_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_batch_scan_enable_cmd_fixed_param, wmi_batch_scan_enable_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + + +WMITLV_CREATE_PARAM_STRUC(WMI_BATCH_SCAN_ENABLE_CMDID); + +#define WMITLV_TABLE_WMI_PEER_INFO_REQ_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_peer_info_req_cmd_fixed_param, \ + wmi_peer_info_req_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_PEER_INFO_REQ_CMDID); + +#define WMITLV_TABLE_WMI_PEER_ANTDIV_INFO_REQ_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_peer_antdiv_info_req_cmd_fixed_param, \ + wmi_peer_antdiv_info_req_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_PEER_ANTDIV_INFO_REQ_CMDID); + +#define WMITLV_TABLE_WMI_RMC_SET_MODE_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_rmc_set_mode_cmd_fixed_param, \ + wmi_rmc_set_mode_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_RMC_SET_MODE_CMDID); + +#define WMITLV_TABLE_WMI_RMC_SET_ACTION_PERIOD_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_rmc_set_action_period_cmd_fixed_param, \ + wmi_rmc_set_action_period_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_RMC_SET_ACTION_PERIOD_CMDID); + +#define WMITLV_TABLE_WMI_RMC_CONFIG_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_rmc_config_cmd_fixed_param, \ + wmi_rmc_config_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_RMC_CONFIG_CMDID); + +#define WMITLV_TABLE_WMI_MHF_OFFLOAD_SET_MODE_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_mhf_offload_set_mode_cmd_fixed_param, \ + wmi_mhf_offload_set_mode_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_MHF_OFFLOAD_SET_MODE_CMDID); + +#define WMITLV_TABLE_WMI_MHF_OFFLOAD_PLUMB_ROUTING_TBL_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_mhf_offload_plumb_routing_table_cmd_fixed_param, \ + wmi_mhf_offload_plumb_routing_table_cmd, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_mhf_offload_routing_table_entry, \ + routing_tbl_entries, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_MHF_OFFLOAD_PLUMB_ROUTING_TBL_CMDID); + +#define WMITLV_TABLE_WMI_BATCH_SCAN_DISABLE_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_batch_scan_disable_cmd_fixed_param, wmi_batch_scan_disable_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_BATCH_SCAN_DISABLE_CMDID); + +#define WMITLV_TABLE_WMI_BATCH_SCAN_TRIGGER_RESULT_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_batch_scan_trigger_result_cmd_fixed_param, wmi_batch_scan_trigger_result_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_BATCH_SCAN_TRIGGER_RESULT_CMDID); + +/* LPI mgmt snooping config Cmd */ +#define WMITLV_TABLE_WMI_LPI_MGMT_SNOOPING_CONFIG_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_lpi_mgmt_snooping_config_cmd_fixed_param, wmi_lpi_mgmt_snooping_config_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_LPI_MGMT_SNOOPING_CONFIG_CMDID); + +/* LPI start scan Cmd */ +#define WMITLV_TABLE_WMI_LPI_START_SCAN_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_lpi_start_scan_cmd_fixed_param, wmi_lpi_start_scan_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_UINT32, A_UINT32, channel_list, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_FIXED_STRUC, wmi_ssid, ssid_list, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_FIXED_STRUC, wmi_mac_addr, bssid_list, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, ie_data, WMITLV_SIZE_VAR) + +WMITLV_CREATE_PARAM_STRUC(WMI_LPI_START_SCAN_CMDID); + +/* LPI stop scan Cmd */ +#define WMITLV_TABLE_WMI_LPI_STOP_SCAN_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_lpi_stop_scan_cmd_fixed_param, wmi_lpi_stop_scan_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_LPI_STOP_SCAN_CMDID); + +#define WMITLV_TABLE_WMI_LPI_RESULT_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_lpi_result_event_fixed_param, wmi_lpi_result_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, data, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_LPI_RESULT_EVENTID); + +/* LPI Status Event */ +#define WMITLV_TABLE_WMI_LPI_STATUS_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_lpi_status_event_fixed_param, wmi_lpi_status_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_LPI_STATUS_EVENTID); + +/* LPI Handoff Event */ +#define WMITLV_TABLE_WMI_LPI_HANDOFF_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_lpi_handoff_event_fixed_param, wmi_lpi_handoff_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_LPI_HANDOFF_EVENTID); + +/* Thermal Manager Params*/ +#define WMITLV_TABLE_WMI_THERMAL_MGMT_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_thermal_mgmt_cmd_fixed_param, wmi_thermal_mgmt_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_THERMAL_MGMT_CMDID); + + +#define WMITLV_TABLE_WMI_ADD_PROACTIVE_ARP_RSP_PATTERN_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_WMI_ADD_PROACTIVE_ARP_RSP_PATTERN_CMD_fixed_param, WMI_ADD_PROACTIVE_ARP_RSP_PATTERN_CMD_fixed_param, fixed_param, WMITLV_SIZE_FIX)\ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, pattern, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_ADD_PROACTIVE_ARP_RSP_PATTERN_CMDID); + +#define WMITLV_TABLE_WMI_DEL_PROACTIVE_ARP_RSP_PATTERN_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_WMI_DEL_PROACTIVE_ARP_RSP_PATTERN_CMD_fixed_param, WMI_DEL_PROACTIVE_ARP_RSP_PATTERN_CMD_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_DEL_PROACTIVE_ARP_RSP_PATTERN_CMDID); + +/* NaN Request */ +#define WMITLV_TABLE_WMI_NAN_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_nan_cmd_param, wmi_nan_cmd_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, data, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_NAN_CMDID); + +/* NAN Data Get Capabilities Cmd */ +#define WMITLV_TABLE_WMI_NDI_GET_CAP_REQ_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_ndi_get_cap_req_fixed_param, wmi_ndi_get_cap_req_fixed_param_PROTOTYPE, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_NDI_GET_CAP_REQ_CMDID); + +/** NAN Data Initiator Request Cmd + * + * TLV (tag length value ) parameters follow the ndp_initiator_req + * structure. The TLV's are: + * wmi_channel channel; + * A_UINT8 ndp_cfg[]; + * A_UINT8 ndp_app_info[]; + * A_UINT8 ndp_pmk[]; + * A_INT8 ndp_passphrase[]; + * A_INT8 nan_servicename[]; + */ +#define WMITLV_TABLE_WMI_NDP_INITIATOR_REQ_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_ndp_initiator_req_fixed_param, wmi_ndp_initiator_req_fixed_param_PROTOTYPE, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_channel, wmi_channel, channel, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, ndp_cfg, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, ndp_app_info, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, ndp_pmk, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_INT8, ndp_passphrase, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_INT8, nan_servicename, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_NDP_INITIATOR_REQ_CMDID); + +/** NAN Data Responder Request Cmd + * TLV (tag length value ) parameters follow the ndp_responder_req + * structure. The TLV's are: + * A_UINT8 ndp_cfg[]; + * A_UINT8 ndp_app_info[]; + * A_UINT8 ndp_pmk[]; + * A_INT8 ndp_passphrase[]; + * A_INT8 nan_servicename[]; + */ +#define WMITLV_TABLE_WMI_NDP_RESPONDER_REQ_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_ndp_responder_req_fixed_param, wmi_ndp_responder_req_fixed_param_PROTOTYPE, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, ndp_cfg, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, ndp_app_info, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, ndp_pmk, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_INT8, ndp_passphrase, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_INT8, nan_servicename, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_NDP_RESPONDER_REQ_CMDID); + +/** NAN Data End Request Cmd + * + * TLV (tag length value ) parameters follow the ndp_end_req + * structure. The TLV's are: + * wmi_ndp_end_req wmi_ndp_end_req_list[]; + */ +#define WMITLV_TABLE_WMI_NDP_END_REQ_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_ndp_end_req_fixed_param, wmi_ndp_end_req_fixed_param_PROTOTYPE, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_ndp_end_req_PROTOTYPE, ndp_end_req_list, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_NDP_END_REQ_CMDID); + +/* RCPI Info Request Cmd */ +#define WMITLV_TABLE_WMI_REQUEST_RCPI_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_request_rcpi_cmd_fixed_param, wmi_request_rcpi_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_REQUEST_RCPI_CMDID); + +/* Modem power state cmd */ +#define WMITLV_TABLE_WMI_MODEM_POWER_STATE_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_modem_power_state_cmd_param, wmi_modem_power_state_cmd_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_MODEM_POWER_STATE_CMDID); + +/* SAR limit update cmd */ +#define WMITLV_TABLE_WMI_SAR_LIMITS_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_sar_limits_cmd_fixed_param, wmi_sar_limits_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_sar_limit_cmd_row, sar_limits, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_SAR_LIMITS_CMDID); + +/* get estimated link speed cmd */ +#define WMITLV_TABLE_WMI_PEER_GET_ESTIMATED_LINKSPEED_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_peer_get_estimated_linkspeed_cmd_fixed_param, wmi_peer_get_estimated_linkspeed_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_PEER_GET_ESTIMATED_LINKSPEED_CMDID); + +/* ext stats Request */ +#define WMITLV_TABLE_WMI_REQUEST_STATS_EXT_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_req_stats_ext_cmd_fixed_param, wmi_req_stats_ext_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, data, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_REQUEST_STATS_EXT_CMDID); + +/* 2.4Ghz HT40 OBSS scan enable */ +#define WMITLV_TABLE_WMI_OBSS_SCAN_ENABLE_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id, op, buf, len, WMITLV_TAG_STRUC_wmi_obss_scan_enable_cmd_fixed_param, wmi_obss_scan_enable_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id, op, buf, len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, channels, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id, op, buf, len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, ie_field, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_OBSS_SCAN_ENABLE_CMDID); + +/* 2.4Ghz HT40 OBSS scan disable */ +#define WMITLV_TABLE_WMI_OBSS_SCAN_DISABLE_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id, op, buf, len, WMITLV_TAG_STRUC_wmi_obss_scan_disable_cmd_fixed_param, wmi_obss_scan_disable_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_OBSS_SCAN_DISABLE_CMDID); + +/* Pdev Set LED Config Cmd */ +#define WMITLV_TABLE_WMI_PDEV_SET_LED_CONFIG_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_pdev_set_led_config_cmd_fixed_param, wmi_pdev_set_led_config_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_PDEV_SET_LED_CONFIG_CMDID); + +/* host auto shut down config cmd */ +#define WMITLV_TABLE_WMI_HOST_AUTO_SHUTDOWN_CFG_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_host_auto_shutdown_cfg_cmd_fixed_param, wmi_host_auto_shutdown_cfg_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_HOST_AUTO_SHUTDOWN_CFG_CMDID); + +/* tpc chainmask config cmd */ +#define WMITLV_TABLE_WMI_TPC_CHAINMASK_CONFIG_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_tpc_chainmask_config_cmd_fixed_param, wmi_tpc_chainmask_config_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_tpc_chainmask_config, config_list, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_TPC_CHAINMASK_CONFIG_CMDID); + + +/* Ch avoidance update cmd */ +#define WMITLV_TABLE_WMI_CHAN_AVOID_UPDATE_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_chan_avoid_update_cmd_param, wmi_chan_avoid_update_cmd_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_CHAN_AVOID_UPDATE_CMDID); + +/* Ch avoidance report allow/disallow cmd*/ +#define WMITLV_TABLE_WMI_CHAN_AVOID_RPT_ALLOW_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_WMI_CHAN_AVOID_RPT_ALLOW_CMD_fixed_param, WMI_CHAN_AVOID_RPT_ALLOW_CMD_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_CHAN_AVOID_RPT_ALLOW_CMDID); + +/* D0-WOW Enable Disable Cmd */ +#define WMITLV_TABLE_WMI_D0_WOW_ENABLE_DISABLE_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_d0_wow_enable_disable_cmd_fixed_param, wmi_d0_wow_enable_disable_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_D0_WOW_ENABLE_DISABLE_CMDID); + +/* Pdev get chip temperature Cmd */ +#define WMITLV_TABLE_WMI_PDEV_GET_TEMPERATURE_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_pdev_get_temperature_cmd_fixed_param, wmi_pdev_get_temperature_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_PDEV_GET_TEMPERATURE_CMDID); + +/* Pdev get ANT DIV feature status Cmd */ +#define WMITLV_TABLE_WMI_PDEV_GET_ANTDIV_STATUS_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_pdev_get_antdiv_status_cmd_fixed_param, wmi_pdev_get_antdiv_status_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_PDEV_GET_ANTDIV_STATUS_CMDID); + +/* DISA feature : vdev encrypt decrypt request */ +#define WMITLV_TABLE_WMI_VDEV_ENCRYPT_DECRYPT_DATA_REQ_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_vdev_encrypt_decrypt_data_req_cmd_fixed_param, wmi_vdev_encrypt_decrypt_data_req_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, data, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_VDEV_ENCRYPT_DECRYPT_DATA_REQ_CMDID); + +/* Set antenna diversity Cmd */ +#define WMITLV_TABLE_WMI_SET_ANTENNA_DIVERSITY_CMDID(id,op,buf,len) \ +WMITLV_ELEM(id, op, buf, len, WMITLV_TAG_STRUC_wmi_pdev_set_antenna_diversity_cmd_fixed_param, wmi_pdev_set_antenna_diversity_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_SET_ANTENNA_DIVERSITY_CMDID); + +/* Set rssi monitoring config Cmd */ +#define WMITLV_TABLE_WMI_RSSI_BREACH_MONITOR_CONFIG_CMDID(id,op,buf,len) \ +WMITLV_ELEM(id, op, buf, len, WMITLV_TAG_STRUC_wmi_rssi_breach_monitor_config_fixed_param, wmi_rssi_breach_monitor_config_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_RSSI_BREACH_MONITOR_CONFIG_CMDID); + +/* DHCP server offload param Cmd */ +#define WMITLV_TABLE_WMI_SET_DHCP_SERVER_OFFLOAD_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_set_dhcp_server_offload_cmd_fixed_param, wmi_set_dhcp_server_offload_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_SET_DHCP_SERVER_OFFLOAD_CMDID); + +/* IPA Offload Enable Disable Cmd */ +#define WMITLV_TABLE_WMI_IPA_OFFLOAD_ENABLE_DISABLE_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUCT_wmi_ipa_offload_enable_disable_cmd_fixed_param, wmi_ipa_offload_enable_disable_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_IPA_OFFLOAD_ENABLE_DISABLE_CMDID); + +/* Set LED flashing parameter Cmd */ +#define WMITLV_TABLE_WMI_PDEV_SET_LED_FLASHING_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_set_led_flashing_cmd_fixed_param, wmi_set_led_flashing_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_PDEV_SET_LED_FLASHING_CMDID); + +/* mDNS responder offload param Cmd */ +#define WMITLV_TABLE_WMI_MDNS_OFFLOAD_ENABLE_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_mdns_offload_cmd_fixed_param, wmi_mdns_offload_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_MDNS_OFFLOAD_ENABLE_CMDID); + +#define WMITLV_TABLE_WMI_MDNS_SET_FQDN_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_mdns_set_fqdn_cmd_fixed_param, wmi_mdns_set_fqdn_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, fqdn_data, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_MDNS_SET_FQDN_CMDID); + +#define WMITLV_TABLE_WMI_MDNS_SET_RESPONSE_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_mdns_set_resp_cmd_fixed_param, wmi_mdns_set_resp_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, resp_data, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_MDNS_SET_RESPONSE_CMDID); + +#define WMITLV_TABLE_WMI_MDNS_GET_STATS_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_mdns_get_stats_cmd_fixed_param, wmi_mdns_get_stats_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_MDNS_GET_STATS_CMDID); + +/* roam invoke Cmd */ +#define WMITLV_TABLE_WMI_ROAM_INVOKE_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_roam_invoke_cmd_fixed_param, wmi_roam_invoke_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_UINT32, A_UINT32, channel_list, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_FIXED_STRUC, wmi_mac_addr, bssid_list, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_FIXED_STRUC, wmi_tlv_buf_len_param, bcn_prb_buf_list, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, bcn_prb_frm, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_ROAM_INVOKE_CMDID); + +/* SAP Authentication offload param Cmd */ +#define WMITLV_TABLE_WMI_SAP_OFL_ENABLE_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_sap_ofl_enable_cmd_fixed_param, wmi_sap_ofl_enable_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, psk, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_SAP_OFL_ENABLE_CMDID); + +/* SAP set blacklist param cmd */ +#define WMITLV_TABLE_WMI_SAP_SET_BLACKLIST_PARAM_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_sap_set_blacklist_param_cmd_fixed_param, wmi_sap_set_blacklist_param_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_SAP_SET_BLACKLIST_PARAM_CMDID); + +/* APFIND Request */ +#define WMITLV_TABLE_WMI_APFIND_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_apfind_cmd_param, wmi_apfind_cmd_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, data, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_APFIND_CMDID); + +/* Set OCB schedule cmd, DEPRECATED */ +#define WMITLV_TABLE_WMI_OCB_SET_SCHED_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id, op, buf, len, WMITLV_TAG_STRUC_wmi_ocb_set_sched_cmd_fixed_param, wmi_ocb_set_sched_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_OCB_SET_SCHED_CMDID); + +/* Set OCB configuration cmd */ +#define WMITLV_TABLE_WMI_OCB_SET_CONFIG_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_ocb_set_config_cmd_fixed_param, wmi_ocb_set_config_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_channel, chan_list, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_ocb_channel, ocb_chan_list, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_qos_parameter, qos_parameter_list, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_dcc_ndl_chan, chan_cfg, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_dcc_ndl_active_state_config, ndl_active_state_config_list, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_ocb_schedule_element, schedule_list, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_OCB_SET_CONFIG_CMDID); + +/* Set UTC time cmd */ +#define WMITLV_TABLE_WMI_OCB_SET_UTC_TIME_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_ocb_set_utc_time_cmd_fixed_param, wmi_ocb_set_utc_time_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_OCB_SET_UTC_TIME_CMDID); + +/* Start timing advertisement cmd */ +#define WMITLV_TABLE_WMI_OCB_START_TIMING_ADVERT_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_ocb_start_timing_advert_cmd_fixed_param, wmi_ocb_start_timing_advert_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, bufp, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_OCB_START_TIMING_ADVERT_CMDID); + +/* Stop timing advertisement cmd */ +#define WMITLV_TABLE_WMI_OCB_STOP_TIMING_ADVERT_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_ocb_stop_timing_advert_cmd_fixed_param, wmi_ocb_stop_timing_advert_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_OCB_STOP_TIMING_ADVERT_CMDID); + +/* Get TSF timer cmd */ +#define WMITLV_TABLE_WMI_OCB_GET_TSF_TIMER_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_ocb_get_tsf_timer_cmd_fixed_param, wmi_ocb_get_tsf_timer_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_OCB_GET_TSF_TIMER_CMDID); + +/* Get DCC stats cmd */ +#define WMITLV_TABLE_WMI_DCC_GET_STATS_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_dcc_get_stats_cmd_fixed_param, wmi_dcc_get_stats_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_dcc_channel_stats_request, channel_stats_request, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_DCC_GET_STATS_CMDID); + +/* Clear DCC stats cmd */ +#define WMITLV_TABLE_WMI_DCC_CLEAR_STATS_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_dcc_clear_stats_cmd_fixed_param, wmi_dcc_clear_stats_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_DCC_CLEAR_STATS_CMDID); + +/* Update DCC NDL cmd */ +#define WMITLV_TABLE_WMI_DCC_UPDATE_NDL_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_dcc_update_ndl_cmd_fixed_param, wmi_dcc_update_ndl_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_dcc_ndl_chan, chan_ndl_list, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_dcc_ndl_active_state_config, ndl_active_state_config_list, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_DCC_UPDATE_NDL_CMDID); + +/* Roam filter cmd */ +#define WMITLV_TABLE_WMI_ROAM_FILTER_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_roam_filter_fixed_param, wmi_roam_filter_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_FIXED_STRUC, wmi_mac_addr, bssid_black_list, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_FIXED_STRUC, wmi_ssid, ssid_white_list, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_FIXED_STRUC, wmi_mac_addr, bssid_preferred_list, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_UINT32, A_UINT32, bssid_preferred_factor, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_roam_lca_disallow_config_tlv_param, lca_disallow_param, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_roam_rssi_rejection_oce_config_param, rssi_rejection_list, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_ROAM_FILTER_CMDID); + +/* TSF timestamp action cmd */ +#define WMITLV_TABLE_WMI_VDEV_TSF_TSTAMP_ACTION_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_vdev_tsf_tstamp_action_cmd_fixed_param, wmi_vdev_tsf_tstamp_action_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_VDEV_TSF_TSTAMP_ACTION_CMDID); + +/* LFR subnet change config Cmd */ +#define WMITLV_TABLE_WMI_ROAM_SUBNET_CHANGE_CONFIG_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_roam_subnet_change_config_fixed_param, wmi_roam_subnet_change_config_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_FIXED_STRUC, wmi_mac_addr, skip_subnet_change_detection_bssid_list, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_ROAM_SUBNET_CHANGE_CONFIG_CMDID); + +/* Set the SOC Preferred Channel List (PCL) Cmd - DEPRECATED */ +#define WMITLV_TABLE_WMI_SOC_SET_PCL_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_soc_set_pcl_cmd_fixed_param, wmi_soc_set_pcl_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_UINT32, A_UINT32, channel_list, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_SOC_SET_PCL_CMDID); + +/* Set the PDEV Preferred Channel List (PCL) Cmd */ +#define WMITLV_TABLE_WMI_PDEV_SET_PCL_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_pdev_set_pcl_cmd_fixed_param, wmi_pdev_set_pcl_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_UINT32, A_UINT32, channel_weight, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_PDEV_SET_PCL_CMDID); + +/* Set the SOC Hardware Mode Cmd - DEPRECATED */ +#define WMITLV_TABLE_WMI_SOC_SET_HW_MODE_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_soc_set_hw_mode_cmd_fixed_param, wmi_soc_set_hw_mode_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_SOC_SET_HW_MODE_CMDID); + +/* Set the PDEV Hardware Mode Cmd */ +#define WMITLV_TABLE_WMI_PDEV_SET_HW_MODE_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_pdev_set_hw_mode_cmd_fixed_param, wmi_pdev_set_hw_mode_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_PDEV_SET_HW_MODE_CMDID); + +/* Set the SOC Dual MAC Config Cmd - DEPRECATED */ +#define WMITLV_TABLE_WMI_SOC_SET_DUAL_MAC_CONFIG_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_soc_set_dual_mac_config_cmd_fixed_param, wmi_soc_set_dual_mac_config_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_SOC_SET_DUAL_MAC_CONFIG_CMDID); + +/* Set the PDEV MAC Config Cmd */ +#define WMITLV_TABLE_WMI_PDEV_SET_MAC_CONFIG_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_pdev_set_mac_config_cmd_fixed_param, wmi_pdev_set_mac_config_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_PDEV_SET_MAC_CONFIG_CMDID); + +/* Set the SOC Antenna Mode Cmd - DEPRECATED */ +#define WMITLV_TABLE_WMI_SOC_SET_ANTENNA_MODE_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_soc_set_antenna_mode_cmd_fixed_param, wmi_soc_set_antenna_mode_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_SOC_SET_ANTENNA_MODE_CMDID); + +/* Set the PDEV Antenna Mode Cmd */ +#define WMITLV_TABLE_WMI_PDEV_SET_ANTENNA_MODE_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_pdev_set_antenna_mode_cmd_fixed_param, wmi_pdev_set_antenna_mode_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_PDEV_SET_ANTENNA_MODE_CMDID); + +#define WMITLV_TABLE_WMI_LRO_CONFIG_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_lro_info_cmd_fixed_param, wmi_lro_info_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_LRO_CONFIG_CMDID); + +#define WMITLV_TABLE_WMI_TRANSFER_DATA_TO_FLASH_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_transfer_data_to_flash_cmd_fixed_param, wmi_transfer_data_to_flash_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, data, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_TRANSFER_DATA_TO_FLASH_CMDID); + +#define WMITLV_TABLE_WMI_READ_DATA_FROM_FLASH_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_read_data_from_flash_cmd_fixed_param, wmi_read_data_from_flash_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_READ_DATA_FROM_FLASH_CMDID); + +#define WMITLV_TABLE_WMI_CONFIG_ENHANCED_MCAST_FILTER_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_config_enhanced_mcast_filter_fixed_param, wmi_config_enhanced_mcast_filter_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_CONFIG_ENHANCED_MCAST_FILTER_CMDID); + +#define WMITLV_TABLE_WMI_VDEV_WISA_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_vdev_wisa_cmd_fixed_param, wmi_vdev_wisa_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_VDEV_WISA_CMDID); + +/* MAWC sensor report indication cmd */ +#define WMITLV_TABLE_WMI_MAWC_SENSOR_REPORT_IND_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_mawc_sensor_report_ind_cmd_fixed_param, wmi_mawc_sensor_report_ind_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_MAWC_SENSOR_REPORT_IND_CMDID); + +/* Roam configure MAWC cmd */ +#define WMITLV_TABLE_WMI_ROAM_CONFIGURE_MAWC_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_roam_configure_mawc_cmd_fixed_param, wmi_roam_configure_mawc_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_ROAM_CONFIGURE_MAWC_CMDID); + +/* NLO configure MAWC cmd */ +#define WMITLV_TABLE_WMI_NLO_CONFIGURE_MAWC_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_nlo_configure_mawc_cmd_fixed_param, wmi_nlo_configure_mawc_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_NLO_CONFIGURE_MAWC_CMDID); + +/* Extscan configure MAWC cmd */ +#define WMITLV_TABLE_WMI_EXTSCAN_CONFIGURE_MAWC_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_extscan_configure_mawc_cmd_fixed_param, wmi_extscan_configure_mawc_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_EXTSCAN_CONFIGURE_MAWC_CMDID); + +/* COEX config cmd */ +#define WMITLV_TABLE_WMI_COEX_CONFIG_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_WMI_COEX_CONFIG_CMD_fixed_param, WMI_COEX_CONFIG_CMD_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_COEX_CONFIG_CMDID); + +/* Coex get antenna isolation cmd */ +#define WMITLV_TABLE_WMI_COEX_GET_ANTENNA_ISOLATION_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_coex_get_antenna_isolation_cmd_fixed_param, wmi_coex_get_antenna_isolation_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_COEX_GET_ANTENNA_ISOLATION_CMDID); + +/* bpf offload capability get cmd */ +#define WMITLV_TABLE_WMI_BPF_GET_CAPABILITY_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_bpf_get_capability_cmd_fixed_param, wmi_bpf_get_capability_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_BPF_GET_CAPABILITY_CMDID); + +/* bpf offload get vdev status cmd */ +#define WMITLV_TABLE_WMI_BPF_GET_VDEV_STATS_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_bpf_get_vdev_stats_cmd_fixed_param, wmi_bpf_get_vdev_stats_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_BPF_GET_VDEV_STATS_CMDID); + +/* bpf offload set vdev instructions cmd */ +#define WMITLV_TABLE_WMI_BPF_SET_VDEV_INSTRUCTIONS_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_bpf_set_vdev_instructions_cmd_fixed_param, wmi_bpf_set_vdev_instructions_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, buf_inst, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_BPF_SET_VDEV_INSTRUCTIONS_CMDID); + +/* bpf offload delete vdev instructions cmd */ +#define WMITLV_TABLE_WMI_BPF_DEL_VDEV_INSTRUCTIONS_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_bpf_del_vdev_instructions_cmd_fixed_param, wmi_bpf_del_vdev_instructions_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_BPF_DEL_VDEV_INSTRUCTIONS_CMDID); + +#define WMITLV_TABLE_WMI_BPF_SET_VDEV_ACTIVE_MODE_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_bpf_set_vdev_active_mode_cmd_fixed_param, wmi_bpf_set_vdev_active_mode_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_BPF_SET_VDEV_ACTIVE_MODE_CMDID); + +/* Enable/Disable Smart Antenna */ +#define WMITLV_TABLE_WMI_PDEV_SMART_ANT_ENABLE_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_pdev_smart_ant_enable_cmd_fixed_param, wmi_pdev_smart_ant_enable_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_pdev_smart_ant_gpio_handle, gpio_handle, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_PDEV_SMART_ANT_ENABLE_CMDID); + +/* Set Smart Antenna RX antenna */ +#define WMITLV_TABLE_WMI_PDEV_SMART_ANT_SET_RX_ANTENNA_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_pdev_smart_ant_set_rx_antenna_cmd_fixed_param, wmi_pdev_smart_ant_set_rx_antenna_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_PDEV_SMART_ANT_SET_RX_ANTENNA_CMDID); + +/* Override the antenna switch table */ +#define WMITLV_TABLE_WMI_PDEV_SET_ANTENNA_SWITCH_TABLE_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_pdev_set_ant_switch_tbl_cmd_fixed_param, wmi_pdev_set_ant_switch_tbl_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_pdev_set_ant_ctrl_chain, ant_ctrl_chain, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_PDEV_SET_ANTENNA_SWITCH_TABLE_CMDID); + +/* Override the CTL table */ +#define WMITLV_TABLE_WMI_PDEV_SET_CTL_TABLE_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_pdev_set_ctl_table_cmd_fixed_param, wmi_pdev_set_ctl_table_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_UINT32, A_UINT32, ctl_info, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_PDEV_SET_CTL_TABLE_CMDID); + +/* Override the array gain table */ +#define WMITLV_TABLE_WMI_PDEV_SET_MIMOGAIN_TABLE_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_pdev_set_mimogain_table_cmd_fixed_param, wmi_pdev_set_mimogain_table_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_UINT32, A_UINT32, arraygain_tbl, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_PDEV_SET_MIMOGAIN_TABLE_CMDID); + +/* FIPS cmd */ +#define WMITLV_TABLE_WMI_PDEV_FIPS_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_pdev_fips_cmd_fixed_param, wmi_pdev_fips_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, data, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_PDEV_FIPS_CMDID); + +/* get CCK ANI level */ +#define WMITLV_TABLE_WMI_PDEV_GET_ANI_CCK_CONFIG_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_pdev_get_ani_cck_config_cmd_fixed_param, wmi_pdev_get_ani_cck_config_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_PDEV_GET_ANI_CCK_CONFIG_CMDID); + +/* get OFDM ANI level */ +#define WMITLV_TABLE_WMI_PDEV_GET_ANI_OFDM_CONFIG_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_pdev_get_ani_ofdm_config_cmd_fixed_param, wmi_pdev_get_ani_ofdm_config_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_PDEV_GET_ANI_OFDM_CONFIG_CMDID); + +/* TxPPDU TPC cmd */ +#define WMITLV_TABLE_WMI_PDEV_GET_TPC_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_pdev_get_tpc_cmd_fixed_param, wmi_pdev_get_tpc_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_PDEV_GET_TPC_CMDID); + +#define WMITLV_TABLE_WMI_VDEV_RATEMASK_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_vdev_config_ratemask_fixed_param, wmi_vdev_config_ratemask_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_VDEV_RATEMASK_CMDID); + +/* ATF VDEV REQUEST commands */ +#define WMITLV_TABLE_WMI_VDEV_ATF_REQUEST_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_vdev_atf_request_fixed_param, wmi_vdev_atf_request_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_VDEV_ATF_REQUEST_CMDID); + +/* Command to send the DSCP-to-TID map to the target for VAP */ +#define WMITLV_TABLE_WMI_VDEV_SET_DSCP_TID_MAP_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_vdev_set_dscp_tid_map_cmd_fixed_param, wmi_vdev_set_dscp_tid_map_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_VDEV_SET_DSCP_TID_MAP_CMDID); + +/* Configure filter for Neighbor Rx Pkt (smart mesh selective listening) */ +#define WMITLV_TABLE_WMI_VDEV_FILTER_NEIGHBOR_RX_PACKETS_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_vdev_filter_nrp_config_cmd_fixed_param, wmi_vdev_filter_nrp_config_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_VDEV_FILTER_NEIGHBOR_RX_PACKETS_CMDID); + +/* update a wds (4 address) entry */ +#define WMITLV_TABLE_WMI_PEER_UPDATE_WDS_ENTRY_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_peer_update_wds_entry_cmd_fixed_param, wmi_peer_update_wds_entry_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_PEER_UPDATE_WDS_ENTRY_CMDID); + +/* add a proxy sta entry */ +#define WMITLV_TABLE_WMI_PEER_ADD_PROXY_STA_ENTRY_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_peer_create_cmd_fixed_param, wmi_peer_create_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_PEER_ADD_PROXY_STA_ENTRY_CMDID); + +/* Set Smart Antenna TX antenna */ +#define WMITLV_TABLE_WMI_PEER_SMART_ANT_SET_TX_ANTENNA_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len,WMITLV_TAG_STRUC_wmi_peer_smart_ant_set_tx_antenna_cmd_fixed_param, wmi_peer_smart_ant_set_tx_antenna_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_peer_smart_ant_set_tx_antenna_series, antenna_series, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_PEER_SMART_ANT_SET_TX_ANTENNA_CMDID); + +/* Set Smart Antenna TX train info */ +#define WMITLV_TABLE_WMI_PEER_SMART_ANT_SET_TRAIN_INFO_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_peer_smart_ant_set_train_antenna_cmd_fixed_param, wmi_peer_smart_ant_set_train_antenna_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_peer_smart_ant_set_train_antenna_param, antenna_param, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_PEER_SMART_ANT_SET_TRAIN_INFO_CMDID); + +/* Set SA node config options */ +#define WMITLV_TABLE_WMI_PEER_SMART_ANT_SET_NODE_CONFIG_OPS_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_peer_smart_ant_set_node_config_ops_cmd_fixed_param, wmi_peer_smart_ant_set_node_config_ops_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_UINT32, A_UINT32, args, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_PEER_SMART_ANT_SET_NODE_CONFIG_OPS_CMDID); + +/* Q-Boost configuration test commands */ +#define WMITLV_TABLE_WMI_QBOOST_CFG_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_WMI_QBOOST_CFG_CMD_fixed_param, WMI_QBOOST_CFG_CMD_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_QBOOST_CFG_CMDID); + +/* set debug and tuning parameters */ +#define WMITLV_TABLE_WMI_FWTEST_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_fwtest_set_param_cmd_fixed_param, wmi_fwtest_set_param_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_FWTEST_CMDID); + +/* ATF PEER REQUEST commands. */ +#define WMITLV_TABLE_WMI_PEER_ATF_REQUEST_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_peer_atf_request_fixed_param, wmi_peer_atf_request_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ +WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_atf_peer_info, peer_info, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_PEER_ATF_REQUEST_CMDID); + +/* enable/disable and set the periodicity of periodic channel stats */ +#define WMITLV_TABLE_WMI_SET_PERIODIC_CHANNEL_STATS_CONFIG_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_set_periodic_channel_stats_config_fixed_param, wmi_set_periodic_channel_stats_config_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_SET_PERIODIC_CHANNEL_STATS_CONFIG_CMDID); + +/* wal power debug command per pdev */ +#define WMITLV_TABLE_WMI_PDEV_WAL_POWER_DEBUG_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_pdev_wal_power_debug_cmd_fixed_param, wmi_pdev_wal_power_debug_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_UINT32, A_UINT32, args, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_PDEV_WAL_POWER_DEBUG_CMDID); + +/* pdev set reorder timeout val */ +#define WMITLV_TABLE_WMI_PDEV_SET_REORDER_TIMEOUT_VAL_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_pdev_set_reorder_timeout_val_cmd_fixed_param, wmi_pdev_set_reorder_timeout_val_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_PDEV_SET_REORDER_TIMEOUT_VAL_CMDID); + +/* peer set rx blocksize cmd */ +#define WMITLV_TABLE_WMI_PEER_SET_RX_BLOCKSIZE_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_peer_set_rx_blocksize_cmd_fixed_param, wmi_peer_set_rx_blocksize_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_PEER_SET_RX_BLOCKSIZE_CMDID); + +/* Bandwidth Fairness (BWF) peer configure commands */ +#define WMITLV_TABLE_WMI_PEER_BWF_REQUEST_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_peer_bwf_request_fixed_param, wmi_peer_bwf_request_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_bwf_peer_info, peer_info, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_PEER_BWF_REQUEST_CMDID); + +#define WMITLV_TABLE_WMI_RMC_SET_MANUAL_LEADER_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id, op, buf, len, WMITLV_TAG_STRUC_wmi_rmc_set_leader_cmd_fixed_param, wmi_rmc_set_leader_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_RMC_SET_MANUAL_LEADER_CMDID); + +/* peer reorder queue setup cmd */ +#define WMITLV_TABLE_WMI_PEER_REORDER_QUEUE_SETUP_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_peer_reorder_queue_setup_cmd_fixed_param, wmi_peer_reorder_queue_setup_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_PEER_REORDER_QUEUE_SETUP_CMDID); + +/* peer reorder queue remove cmd */ +#define WMITLV_TABLE_WMI_PEER_REORDER_QUEUE_REMOVE_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_peer_reorder_queue_remove_cmd_fixed_param, wmi_peer_reorder_queue_remove_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_PEER_REORDER_QUEUE_REMOVE_CMDID); + +/* Filter in monitor mode paramters Cmd */ +#define WMITLV_TABLE_WMI_MNT_FILTER_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_mnt_filter_cmd_fixed_param, wmi_mnt_filter_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_MNT_FILTER_CMDID); + +/* WLAN GET Chip power Stats*/ +#define WMITLV_TABLE_WMI_PDEV_GET_CHIP_POWER_STATS_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_get_chip_power_stats_cmd_fixed_param, wmi_pdev_get_chip_power_stats_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_PDEV_GET_CHIP_POWER_STATS_CMDID); + +/* pdev set stats threshold cmd*/ +#define WMITLV_TABLE_WMI_PDEV_SET_STATS_THRESHOLD_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_pdev_set_stats_threshold_cmd_fixed_param, wmi_pdev_set_stats_threshold_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_chan_cca_stats_thresh, wmi_chan_cca_stats_thresh, cca_thresh, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_peer_signal_stats_thresh, wmi_peer_signal_stats_thresh, signal_thresh, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_tx_stats_thresh, wmi_tx_stats_thresh, tx_thresh, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_rx_stats_thresh, wmi_rx_stats_thresh, rx_thresh, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_PDEV_SET_STATS_THRESHOLD_CMDID); + +/* Request wlan stats cmd */ +#define WMITLV_TABLE_WMI_REQUEST_WLAN_STATS_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_request_wlan_stats_cmd_fixed_param, wmi_request_wlan_stats_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_REQUEST_WLAN_STATS_CMDID); + +/* Request peer stats info cmd */ +#define WMITLV_TABLE_WMI_REQUEST_PEER_STATS_INFO_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_request_peer_stats_info_cmd_fixed_param, wmi_request_peer_stats_info_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_REQUEST_PEER_STATS_INFO_CMDID); + +/* Host sets the current country code */ +#define WMITLV_TABLE_WMI_SET_CURRENT_COUNTRY_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_set_current_country_cmd_fixed_param, wmi_set_current_country_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_SET_CURRENT_COUNTRY_CMDID); + +/* Host sets the init country code */ +#define WMITLV_TABLE_WMI_SET_INIT_COUNTRY_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_set_init_country_cmd_fixed_param, wmi_set_init_country_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_SET_INIT_COUNTRY_CMDID); + +/* Start 11d scan in FW */ +#define WMITLV_TABLE_WMI_11D_SCAN_START_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_11d_scan_start_cmd_fixed_param, wmi_11d_scan_start_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_11D_SCAN_START_CMDID); + +/* Stop 11d scan in FW */ +#define WMITLV_TABLE_WMI_11D_SCAN_STOP_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_11d_scan_stop_cmd_fixed_param, wmi_11d_scan_stop_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_11D_SCAN_STOP_CMDID); + +/* Request radio channel stats cmd */ +#define WMITLV_TABLE_WMI_REQUEST_RADIO_CHAN_STATS_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_request_radio_chan_stats_cmd_fixed_param, wmi_request_radio_chan_stats_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_REQUEST_RADIO_CHAN_STATS_CMDID); + +/* mac randomization cmd */ +#define WMITLV_TABLE_WMI_VDEV_ADD_MAC_ADDR_TO_RX_FILTER_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_vdev_add_mac_addr_to_rx_filter_cmd_fixed_param, wmi_vdev_add_mac_addr_to_rx_filter_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_VDEV_ADD_MAC_ADDR_TO_RX_FILTER_CMDID); + +#define WMITLV_TABLE_WMI_HW_DATA_FILTER_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_hw_data_filter_cmd_fixed_param, wmi_hw_data_filter_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_HW_DATA_FILTER_CMDID); + +/* Multiple vdev restart request cmd */ +#define WMITLV_TABLE_WMI_PDEV_MULTIPLE_VDEV_RESTART_REQUEST_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_pdev_multiple_vdev_restart_request_cmd_fixed_param, wmi_pdev_multiple_vdev_restart_request_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_UINT32, A_UINT32, vdev_ids, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_channel, wmi_channel, chan, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_PDEV_MULTIPLE_VDEV_RESTART_REQUEST_CMDID); + +#define WMITLV_TABLE_WMI_PDEV_UPDATE_PKT_ROUTING_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_pdev_update_pkt_routing_cmd_fixed_param, wmi_pdev_update_pkt_routing_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_PDEV_UPDATE_PKT_ROUTING_CMDID); + +/* Get cal version cmd */ +#define WMITLV_TABLE_WMI_PDEV_CHECK_CAL_VERSION_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_pdev_check_cal_version_cmd_fixed_param, wmi_pdev_check_cal_version_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_PDEV_CHECK_CAL_VERSION_CMDID); + +#define WMITLV_TABLE_WMI_PDEV_SET_DIVERSITY_GAIN_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_pdev_set_diversity_gain_cmd_fixed_param, wmi_pdev_set_diversity_gain_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, diversity_gains, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_PDEV_SET_DIVERSITY_GAIN_CMDID); + +/* set arp stats cmd */ +#define WMITLV_TABLE_WMI_VDEV_SET_ARP_STAT_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_vdev_set_arp_stats_cmd_fixed_param, wmi_vdev_set_arp_stats_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_VDEV_SET_ARP_STAT_CMDID); + +/* get arp stats cmd */ +#define WMITLV_TABLE_WMI_VDEV_GET_ARP_STAT_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_vdev_get_arp_stats_cmd_fixed_param, wmi_vdev_get_arp_stats_cmd_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_VDEV_GET_ARP_STAT_CMDID); + +/* Thermal Throttling SET CONFIG commands. */ +#define WMITLV_TABLE_WMI_THERM_THROT_SET_CONF_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_therm_throt_config_request_fixed_param, wmi_therm_throt_config_request_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_therm_throt_level_config_info, therm_throt_level_config_info, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_THERM_THROT_SET_CONF_CMDID); + + +/************************** TLV definitions of WMI events *******************************/ + +/* Service Ready event */ +#define WMITLV_TABLE_WMI_SERVICE_READY_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_service_ready_event_fixed_param, wmi_service_ready_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_HAL_REG_CAPABILITIES, HAL_REG_CAPABILITIES, hal_reg_capabilities, WMITLV_SIZE_FIX) \ + WMITLV_FXAR(id,op,buf,len, WMITLV_TAG_ARRAY_UINT32, A_UINT32, wmi_service_bitmap, WMITLV_SIZE_FIX, WMI_SERVICE_BM_SIZE) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wlan_host_mem_req, mem_reqs, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_UINT32, A_UINT32, wlan_dbs_hw_mode_list, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_SERVICE_READY_EVENTID); + +/* service available event */ +#define WMITLV_TABLE_WMI_SERVICE_AVAILABLE_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_service_available_event_fixed_param, wmi_service_available_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_SERVICE_AVAILABLE_EVENTID); + +/* Service Ready Extension event */ +#define WMITLV_TABLE_WMI_SERVICE_READY_EXT_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_service_ready_ext_event_fixed_param, wmi_service_ready_ext_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_WMI_SOC_MAC_PHY_HW_MODE_CAPS, WMI_SOC_MAC_PHY_HW_MODE_CAPS, soc_hw_mode_caps, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, WMI_HW_MODE_CAPABILITIES, hw_mode_caps, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, WMI_MAC_PHY_CAPABILITIES, mac_phy_caps, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_WMI_SOC_HAL_REG_CAPABILITIES, WMI_SOC_HAL_REG_CAPABILITIES, soc_hal_reg_caps, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, WMI_HAL_REG_CAPABILITIES_EXT, hal_reg_caps, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, WMI_MAC_PHY_CHAINMASK_COMBO, mac_phy_chainmask_combo, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, WMI_MAC_PHY_CHAINMASK_CAPABILITY, mac_phy_chainmask_caps, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, WMI_OEM_DMA_RING_CAPABILITIES, oem_dma_ring_caps, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_SERVICE_READY_EXT_EVENTID); + +/* Ready event */ +#define WMITLV_TABLE_WMI_READY_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_ready_event_fixed_param, wmi_ready_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_FIXED_STRUC, wmi_mac_addr, mac_addr_list, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_READY_EVENTID); + +/* Scan Event */ +#define WMITLV_TABLE_WMI_SCAN_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_scan_event_fixed_param, wmi_scan_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_SCAN_EVENTID); + +/* ExtScan Start/Stop Event */ +#define WMITLV_TABLE_WMI_EXTSCAN_START_STOP_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_extscan_start_stop_event_fixed_param, wmi_extscan_start_stop_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_EXTSCAN_START_STOP_EVENTID); + +/* ExtScan Event */ +#define WMITLV_TABLE_WMI_EXTSCAN_OPERATION_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_extscan_operation_event_fixed_param, wmi_extscan_operation_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_UINT32, A_UINT32, bucket_id, WMITLV_SIZE_VAR) + +WMITLV_CREATE_PARAM_STRUC(WMI_EXTSCAN_OPERATION_EVENTID); + +/* ExtScan Table Usage Event */ +#define WMITLV_TABLE_WMI_EXTSCAN_TABLE_USAGE_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_extscan_table_usage_event_fixed_param, wmi_extscan_table_usage_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_EXTSCAN_TABLE_USAGE_EVENTID); + +/* ExtScan Result Event */ +#define WMITLV_TABLE_WMI_EXTSCAN_CACHED_RESULTS_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_extscan_cached_results_event_fixed_param, wmi_extscan_cached_results_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_extscan_wlan_descriptor, bssid_list, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_extscan_rssi_info, rssi_list, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, ie_list, WMITLV_SIZE_VAR) + +WMITLV_CREATE_PARAM_STRUC(WMI_EXTSCAN_CACHED_RESULTS_EVENTID); + +/* ExtScan Monitor RSSI List Event */ +#define WMITLV_TABLE_WMI_EXTSCAN_WLAN_CHANGE_RESULTS_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_extscan_wlan_change_results_event_fixed_param, wmi_extscan_wlan_change_results_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_extscan_wlan_change_result_bssid, bssid_signal_descriptor_list, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, rssi_list, WMITLV_SIZE_VAR) + +WMITLV_CREATE_PARAM_STRUC(WMI_EXTSCAN_WLAN_CHANGE_RESULTS_EVENTID); + +/* ExtScan Hot List Match Event */ +#define WMITLV_TABLE_WMI_EXTSCAN_HOTLIST_MATCH_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_extscan_hotlist_match_event_fixed_param, wmi_extscan_hotlist_match_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_extscan_wlan_descriptor, hotlist_match, WMITLV_SIZE_VAR) + +WMITLV_CREATE_PARAM_STRUC(WMI_EXTSCAN_HOTLIST_MATCH_EVENTID); + +/* ExtScan Hot List Match Event */ +#define WMITLV_TABLE_WMI_EXTSCAN_CAPABILITIES_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_extscan_capabilities_event_fixed_param, wmi_extscan_capabilities_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_extscan_cache_capabilities, extscan_cache_capabilities, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_extscan_wlan_change_monitor_capabilities, wlan_change_capabilities, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_extscan_hotlist_monitor_capabilities, hotlist_capabilities, WMITLV_SIZE_VAR) + +WMITLV_CREATE_PARAM_STRUC(WMI_EXTSCAN_CAPABILITIES_EVENTID); + +/* ExtScan Hot List Match Event */ +#define WMITLV_TABLE_WMI_EXTSCAN_HOTLIST_SSID_MATCH_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_extscan_hotlist_ssid_match_event_fixed_param, wmi_extscan_hotlist_ssid_match_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_extscan_wlan_descriptor, hotlist_ssid_match, WMITLV_SIZE_VAR) + +WMITLV_CREATE_PARAM_STRUC(WMI_EXTSCAN_HOTLIST_SSID_MATCH_EVENTID); + +/* Update_whal_mib_stats Event */ +#define WMITLV_TABLE_WMI_UPDATE_WHAL_MIB_STATS_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id, op, buf, len, WMITLV_TAG_STRUC_wmi_update_whal_mib_stats_event_fixed_param, wmi_update_whal_mib_stats_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_UPDATE_WHAL_MIB_STATS_EVENTID); + +/* PDEV TPC Config Event */ +#define WMITLV_TABLE_WMI_PDEV_TPC_CONFIG_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_pdev_tpc_config_event_fixed_param, wmi_pdev_tpc_config_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, ratesArray, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_PDEV_TPC_CONFIG_EVENTID); + +/* PDEV DIV RSSI Antenna index Event */ +#define WMITLV_TABLE_WMI_PDEV_DIV_RSSI_ANTID_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_pdev_div_rssi_antid_event_fixed_param, wmi_pdev_div_rssi_antid_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_PDEV_DIV_RSSI_ANTID_EVENTID); + +/* PDEV BSS CHAN info Event */ +#define WMITLV_TABLE_WMI_PDEV_BSS_CHAN_INFO_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_pdev_bss_chan_info_event_fixed_param, wmi_pdev_bss_chan_info_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_PDEV_BSS_CHAN_INFO_EVENTID); + +/* VDEV Tx Power Event */ +#define WMITLV_TABLE_WMI_VDEV_GET_TX_POWER_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_vdev_tx_power_event_fixed_param, wmi_vdev_get_tx_power_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_VDEV_GET_TX_POWER_EVENTID); + +/* Channel Info Event */ +#define WMITLV_TABLE_WMI_CHAN_INFO_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_chan_info_event_fixed_param, wmi_chan_info_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_CHAN_INFO_EVENTID); + +/* Phy Error Event */ +#define WMITLV_TABLE_WMI_PHYERR_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_comb_phyerr_rx_hdr, wmi_comb_phyerr_rx_hdr, hdr, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, bufp, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_single_phyerr_ext_rx_hdr, single_phyerr_ext, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_PHYERR_EVENTID); + +/* TX Pause/Unpause event */ +#define WMITLV_TABLE_WMI_TX_PAUSE_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_tx_pause_event_fixed_param, wmi_tx_pause_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_TX_PAUSE_EVENTID); + +/* Mgmt TX completion event */ +#define WMITLV_TABLE_WMI_MGMT_TX_COMPLETION_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_mgmt_tx_compl_event_fixed_param, wmi_mgmt_tx_compl_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_MGMT_TX_COMPLETION_EVENTID); + +/* offchan data TX completion event */ +#define WMITLV_TABLE_WMI_OFFCHAN_DATA_TX_COMPLETION_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_offchan_data_tx_compl_event_fixed_param, wmi_offchan_data_tx_compl_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_OFFCHAN_DATA_TX_COMPLETION_EVENTID); + +/* Bundled Mgmt TX completion event */ +#define WMITLV_TABLE_WMI_MGMT_TX_BUNDLE_COMPLETION_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_mgmt_tx_compl_bundle_event_fixed_param, wmi_mgmt_tx_compl_bundle_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_UINT32, A_UINT32, desc_ids, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_UINT32, A_UINT32, status, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_MGMT_TX_BUNDLE_COMPLETION_EVENTID); + +/* VDEV Start response Event */ +#define WMITLV_TABLE_WMI_VDEV_START_RESP_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_vdev_start_response_event_fixed_param, wmi_vdev_start_response_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_VDEV_START_RESP_EVENTID); + +/* VDEV Stopped Event */ +#define WMITLV_TABLE_WMI_VDEV_STOPPED_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_vdev_stopped_event_fixed_param, wmi_vdev_stopped_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_VDEV_STOPPED_EVENTID); + +/* VDEV delete response Event */ +#define WMITLV_TABLE_WMI_VDEV_DELETE_RESP_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_vdev_delete_resp_event_fixed_param, wmi_vdev_delete_resp_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_VDEV_DELETE_RESP_EVENTID); + +/* VDEV Install Key Complete Event */ +#define WMITLV_TABLE_WMI_VDEV_INSTALL_KEY_COMPLETE_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_vdev_install_key_complete_event_fixed_param, wmi_vdev_install_key_complete_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_VDEV_INSTALL_KEY_COMPLETE_EVENTID); + +/* Peer STA Kickout Event */ +#define WMITLV_TABLE_WMI_PEER_STA_KICKOUT_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_peer_sta_kickout_event_fixed_param, wmi_peer_sta_kickout_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_PEER_STA_KICKOUT_EVENTID); + +/* Management Rx Event */ +#define WMITLV_TABLE_WMI_MGMT_RX_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_mgmt_rx_hdr, wmi_mgmt_rx_hdr, hdr, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, bufp, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_rssi_ctl_ext, rssi_ctl_ext, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_MGMT_RX_EVENTID); + +/* TBTT offset Event */ +#define WMITLV_TABLE_WMI_TBTTOFFSET_UPDATE_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_tbtt_offset_event_fixed_param, wmi_tbtt_offset_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_FXAR(id,op,buf,len, WMITLV_TAG_ARRAY_UINT32, A_UINT32, tbttoffset_list, WMITLV_SIZE_FIX, WMI_MAX_AP_VDEV) +WMITLV_CREATE_PARAM_STRUC(WMI_TBTTOFFSET_UPDATE_EVENTID); + +/* TBTT EXT offset Event */ +#define WMITLV_TABLE_WMI_TBTTOFFSET_EXT_UPDATE_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_tbtt_offset_ext_event_fixed_param, wmi_tbtt_offset_ext_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_tbtt_offset_info, tbtt_offset_info, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_TBTTOFFSET_EXT_UPDATE_EVENTID); + +/* TX DELBA Complete Event */ +#define WMITLV_TABLE_WMI_TX_DELBA_COMPLETE_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_tx_delba_complete_event_fixed_param, wmi_tx_delba_complete_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_TX_DELBA_COMPLETE_EVENTID); + +/* Tx ADDBA Complete Event */ +#define WMITLV_TABLE_WMI_TX_ADDBA_COMPLETE_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_tx_addba_complete_event_fixed_param, wmi_tx_addba_complete_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_TX_ADDBA_COMPLETE_EVENTID); + +/* ADD BA Req ssn Event */ +#define WMITLV_TABLE_WMI_BA_RSP_SSN_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_ba_rsp_ssn_event_fixed_param, wmi_ba_rsp_ssn_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id, op, buf, len, WMITLV_TAG_ARRAY_STRUC, wmi_ba_event_ssn, ba_event_ssn_list, WMITLV_SIZE_VAR) + +WMITLV_CREATE_PARAM_STRUC(WMI_BA_RSP_SSN_EVENTID); + +/* Aggregation Request event */ +#define WMITLV_TABLE_WMI_AGGR_STATE_TRIG_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_aggr_state_trig_event_fixed_param, wmi_aggr_state_trig_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_AGGR_STATE_TRIG_EVENTID); + +/* Roam Event */ +#define WMITLV_TABLE_WMI_ROAM_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_roam_event_fixed_param, wmi_roam_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_ROAM_EVENTID); + +/* Roam Synch Event */ +#define WMITLV_TABLE_WMI_ROAM_SYNCH_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_roam_synch_event_fixed_param, wmi_roam_synch_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, bcn_probe_rsp_frame, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, reassoc_rsp_frame, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_channel, wmi_channel, chan, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_key_material, key, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_UINT32, A_UINT32, status, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, reassoc_req_frame, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_pdev_hw_mode_transition_event_fixed_param, hw_mode_transition_fixed_param, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_pdev_set_hw_mode_response_vdev_mac_entry, wmi_pdev_set_hw_mode_response_vdev_mac_mapping, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_roam_fils_synch_tlv_param, roam_fils_synch_info, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_ROAM_SYNCH_EVENTID); + +/* WOW Wakeup Host Event */ +/* NOTE: Make sure wow_bitmap_info can be zero or one elements only */ +#define WMITLV_TABLE_WMI_WOW_WAKEUP_HOST_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_WOW_EVENT_INFO_fixed_param, WOW_EVENT_INFO_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, WOW_EVENT_INFO_SECTION_BITMAP, wow_bitmap_info, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, wow_packet_buffer, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_hb_ind_event_fixed_param, hb_indevt, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, WMI_GTK_OFFLOAD_STATUS_EVENT_fixed_param, wow_gtkigtk, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_WOW_WAKEUP_HOST_EVENTID); + +#define WMITLV_TABLE_WMI_WOW_INITIAL_WAKEUP_EVENTID(id,op,buf,len) \ +WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_WOW_EVENT_INITIAL_WAKEUP_fixed_param, WOW_INITIAL_WAKEUP_EVENT_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_WOW_INITIAL_WAKEUP_EVENTID); + +/* RTT error report Event */ +#define WMITLV_TABLE_WMI_RTT_ERROR_REPORT_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, data, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_RTT_ERROR_REPORT_EVENTID); + +/* Echo Event */ +#define WMITLV_TABLE_WMI_ECHO_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_echo_event_fixed_param, wmi_echo_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_ECHO_EVENTID); + +/* FTM Integration Event */ +#define WMITLV_TABLE_WMI_PDEV_FTM_INTG_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_ftm_intg_event_fixed_param, wmi_ftm_intg_event_fixed_param, fixed_param, WMITLV_SIZE_FIX)\ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, data, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_PDEV_FTM_INTG_EVENTID); + +/* VDEV get Keepalive Event */ +#define WMITLV_TABLE_WMI_VDEV_GET_KEEPALIVE_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_vdev_get_keepalive_event_fixed_param, wmi_vdev_get_keepalive_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_VDEV_GET_KEEPALIVE_EVENTID); + +/* GPIO Input Event */ +#define WMITLV_TABLE_WMI_GPIO_INPUT_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_gpio_input_event_fixed_param, wmi_gpio_input_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_GPIO_INPUT_EVENTID); + +/* CSA Handling Event */ +#define WMITLV_TABLE_WMI_CSA_HANDLING_EVENTID(id,op,buf,len)\ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_csa_event_fixed_param, wmi_csa_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_CSA_HANDLING_EVENTID); + +/* Rfkill state change Event */ +#define WMITLV_TABLE_WMI_RFKILL_STATE_CHANGE_EVENTID(id,op,buf,len)\ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_rfkill_event_fixed_param, wmi_rfkill_mode_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_RFKILL_STATE_CHANGE_EVENTID); + + +/* Debug Message Event */ +#define WMITLV_TABLE_WMI_DEBUG_MESG_EVENTID(id,op,buf,len)\ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, bufp, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_DEBUG_MESG_EVENTID); + +#define WMITLV_TABLE_WMI_DEBUG_MESG_FLUSH_COMPLETE_EVENTID(id,op,buf,len)\ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_debug_mesg_flush_complete_fixed_param, wmi_debug_mesg_flush_complete_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_DEBUG_MESG_FLUSH_COMPLETE_EVENTID); + +#define WMITLV_TABLE_WMI_RSSI_BREACH_EVENTID(id,op,buf,len)\ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_rssi_breach_event_fixed_param, wmi_rssi_breach_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_RSSI_BREACH_EVENTID); + +#define WMITLV_TABLE_WMI_TRANSFER_DATA_TO_FLASH_COMPLETE_EVENTID(id,op,buf,len)\ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_transfer_data_to_flash_complete_event_fixed_param, wmi_transfer_data_to_flash_complete_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_TRANSFER_DATA_TO_FLASH_COMPLETE_EVENTID); + +#define WMITLV_TABLE_WMI_READ_DATA_FROM_FLASH_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_read_data_from_flash_event_fixed_param, wmi_read_data_from_flash_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, data, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_READ_DATA_FROM_FLASH_EVENTID); + +/* Diagnostics Event */ +#define WMITLV_TABLE_WMI_DIAG_EVENTID(id,op,buf,len)\ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, bufp, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_DIAG_EVENTID); + +/* IGTK Offload Event */ +#define WMITLV_TABLE_WMI_GTK_OFFLOAD_STATUS_EVENTID(id,op,buf,len)\ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_WMI_GTK_OFFLOAD_STATUS_EVENT_fixed_param, WMI_GTK_OFFLOAD_STATUS_EVENT_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_GTK_OFFLOAD_STATUS_EVENTID); + +/* DCA interferance Event */ +#define WMITLV_TABLE_WMI_DCS_INTERFERENCE_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_dcs_interference_event_fixed_param, wmi_dcs_interference_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wlan_dcs_cw_int, cw_int, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wlan_dcs_im_tgt_stats_t, wlan_stat, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_DCS_INTERFERENCE_EVENTID); + +/* Profile data Event */ +#define WMITLV_TABLE_WMI_WLAN_PROFILE_DATA_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_wlan_profile_ctx_t, wmi_wlan_profile_ctx_t, profile_ctx, WMITLV_SIZE_FIX)\ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_wlan_profile_t, profile_data, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_WLAN_PROFILE_DATA_EVENTID); + +/* PDEV UTF Event */ +#define WMITLV_TABLE_WMI_PDEV_UTF_EVENTID(id,op,buf,len)\ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, data, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_PDEV_UTF_EVENTID); + +/* Update SCPC calibrated data Event */ +#define WMITLV_TABLE_WMI_PDEV_UTF_SCPC_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_scpc_event_fixed_param, wmi_scpc_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, data, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_PDEV_UTF_SCPC_EVENTID); + +/* Debug print Event */ +#define WMITLV_TABLE_WMI_DEBUG_PRINT_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, data, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_DEBUG_PRINT_EVENTID); + +/* RTT measurement report Event - DEPRECATED */ +#define WMITLV_TABLE_WMI_RTT_MEASUREMENT_REPORT_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, data, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_RTT_MEASUREMENT_REPORT_EVENTID); + +/*oem measurement report Event - DEPRECATED */ +#define WMITLV_TABLE_WMI_OEM_MEASUREMENT_REPORT_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, data, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_OEM_MEASUREMENT_REPORT_EVENTID); + +/*oem error report event - DEPRECATED */ +#define WMITLV_TABLE_WMI_OEM_ERROR_REPORT_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, data, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_OEM_ERROR_REPORT_EVENTID); + +/*oem capability report event - DEPRECATED */ +#define WMITLV_TABLE_WMI_OEM_CAPABILITY_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, data, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_OEM_CAPABILITY_EVENTID); + +/*oem response event*/ +#define WMITLV_TABLE_WMI_OEM_RESPONSE_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, data, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_oem_indirect_data, wmi_oem_indirect_data, indirect_data, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, data2, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_OEM_RESPONSE_EVENTID); + +/* oem dma buffer release event */ +#define WMITLV_TABLE_WMI_OEM_DMA_BUF_RELEASE_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_oem_dma_buf_release_fixed_param, wmi_oem_dma_buf_release_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_oem_dma_buf_release_entry, entries, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_OEM_DMA_BUF_RELEASE_EVENTID); + +/* HOST SWBA Event */ +#define WMITLV_TABLE_WMI_HOST_SWBA_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_host_swba_event_fixed_param, wmi_host_swba_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_tim_info, tim_info, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_p2p_noa_info, p2p_noa_info, WMITLV_SIZE_VAR) + +WMITLV_CREATE_PARAM_STRUC(WMI_HOST_SWBA_EVENTID); + + +/* Update stats Event */ +#define WMITLV_TABLE_WMI_UPDATE_STATS_EVENTID(id,op,buf,len)\ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_stats_event_fixed_param, wmi_stats_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, data, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_per_chain_rssi_stats, wmi_per_chain_rssi_stats, chain_stats, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_rssi_stats, rssi_stats, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_congestion_stats, congestion_stats, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_UPDATE_STATS_EVENTID); + +/* For vdev based ht/vht info upload*/ +#define WMITLV_TABLE_WMI_UPDATE_VDEV_RATE_STATS_EVENTID(id,op,buf,len)\ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_vdev_rate_stats_event_fixed_param, wmi_vdev_rate_stats_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_vdev_rate_ht_info, ht_info, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_UPDATE_VDEV_RATE_STATS_EVENTID); + +/* report rx aggregation failure information */ +#define WMITLV_TABLE_WMI_REPORT_RX_AGGR_FAILURE_EVENTID(id,op,buf,len)\ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_rx_aggr_failure_event_fixed_param, wmi_rx_aggr_failure_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_rx_aggr_failure_info, failure_info, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_REPORT_RX_AGGR_FAILURE_EVENTID); + +/* Update memory dump complete Event */ +#define WMITLV_TABLE_WMI_UPDATE_FW_MEM_DUMP_EVENTID(id,op,buf,len)\ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_update_fw_mem_dump_fixed_param, wmi_update_fw_mem_dump_fixed_param, fixed_param, WMITLV_SIZE_FIX) + +WMITLV_CREATE_PARAM_STRUC(WMI_UPDATE_FW_MEM_DUMP_EVENTID); + +/* Event indicating the DIAG LOGs/Events supported by FW */ +#define WMITLV_TABLE_WMI_DIAG_EVENT_LOG_SUPPORTED_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_diag_event_log_supported_event_fixed_params, wmi_diag_event_log_supported_event_fixed_params, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_UINT32, A_UINT32, diag_events_logs_list, WMITLV_SIZE_VAR) + +WMITLV_CREATE_PARAM_STRUC(WMI_DIAG_EVENT_LOG_SUPPORTED_EVENTID); + +/* Update iface link stats Event */ +#define WMITLV_TABLE_WMI_IFACE_LINK_STATS_EVENTID(id,op,buf,len)\ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_iface_link_stats_event_fixed_param, wmi_iface_link_stats_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_iface_link_stats, iface_link_stats, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_wmm_ac_stats, ac, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_iface_offload_stats, iface_offload_stats, WMITLV_SIZE_VAR) + +WMITLV_CREATE_PARAM_STRUC(WMI_IFACE_LINK_STATS_EVENTID); + +/* Update Peer link stats Event */ +#define WMITLV_TABLE_WMI_PEER_LINK_STATS_EVENTID(id,op,buf,len)\ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_peer_stats_event_fixed_param, wmi_peer_stats_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_peer_link_stats, peer_stats, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_rate_stats, peer_rate_stats, WMITLV_SIZE_VAR) + +WMITLV_CREATE_PARAM_STRUC(WMI_PEER_LINK_STATS_EVENTID); + +/* Update radio stats Event */ +#define WMITLV_TABLE_WMI_RADIO_LINK_STATS_EVENTID(id,op,buf,len)\ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_radio_link_stats_event_fixed_param, wmi_radio_link_stats_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_radio_link_stats, radio_stats, WMITLV_SIZE_VAR)\ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_channel_stats, channel_stats, WMITLV_SIZE_VAR) + +WMITLV_CREATE_PARAM_STRUC(WMI_RADIO_LINK_STATS_EVENTID); + +/* PDEV QVIT Event */ +#define WMITLV_TABLE_WMI_PDEV_QVIT_EVENTID(id,op,buf,len)\ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, data, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_PDEV_QVIT_EVENTID); + +/* WLAN Frequency avoid Event */ +#define WMITLV_TABLE_WMI_WLAN_FREQ_AVOID_EVENTID(id,op,buf,len)\ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_avoid_freq_ranges_event_fixed_param, wmi_avoid_freq_ranges_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_avoid_freq_range_desc, avd_freq_range, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_WLAN_FREQ_AVOID_EVENTID); + +/* GTK rekey fail Event */ +#define WMITLV_TABLE_WMI_GTK_REKEY_FAIL_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_gtk_rekey_fail_event_fixed_param, wmi_gtk_rekey_fail_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_GTK_REKEY_FAIL_EVENTID); + +/* NLO match event */ +#define WMITLV_TABLE_WMI_NLO_MATCH_EVENTID(id,op,buf,len) \ +WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_nlo_event, wmi_nlo_event, fixed_param, WMITLV_SIZE_FIX) + WMITLV_CREATE_PARAM_STRUC(WMI_NLO_MATCH_EVENTID); + +/* NLO scan complete event */ +#define WMITLV_TABLE_WMI_NLO_SCAN_COMPLETE_EVENTID(id,op,buf,len) \ +WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_nlo_event, wmi_nlo_event, fixed_param, WMITLV_SIZE_FIX) + WMITLV_CREATE_PARAM_STRUC(WMI_NLO_SCAN_COMPLETE_EVENTID); + +/* APFIND event */ +#define WMITLV_TABLE_WMI_APFIND_EVENTID(id,op,buf,len) \ +WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_apfind_event_hdr, wmi_apfind_event_hdr, hdr, WMITLV_SIZE_FIX) \ +WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, data, WMITLV_SIZE_VAR) + WMITLV_CREATE_PARAM_STRUC(WMI_APFIND_EVENTID); + +/* WMI_PASSPOINT_MATCH_EVENTID */ +#define WMITLV_TABLE_WMI_PASSPOINT_MATCH_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_passpoint_event_hdr, wmi_passpoint_event_hdr, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, bufp, WMITLV_SIZE_VAR) + WMITLV_CREATE_PARAM_STRUC(WMI_PASSPOINT_MATCH_EVENTID); + +/* Chatter query reply event */ +#define WMITLV_TABLE_WMI_CHATTER_PC_QUERY_EVENTID(id,op,buf,len) \ +WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_chatter_query_reply_event_fixed_param, wmi_chatter_query_reply_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) + WMITLV_CREATE_PARAM_STRUC(WMI_CHATTER_PC_QUERY_EVENTID); + +/* Upload H_CV info event */ +#define WMITLV_TABLE_WMI_UPLOADH_EVENTID(id,op,buf,len) \ +WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_upload_h_hdr, wmi_upload_h_hdr, hdr, WMITLV_SIZE_FIX) \ +WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, bufp, WMITLV_SIZE_VAR) + WMITLV_CREATE_PARAM_STRUC(WMI_UPLOADH_EVENTID); + +/* Capture H info event */ +#define WMITLV_TABLE_WMI_CAPTUREH_EVENTID(id,op,buf,len) \ +WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_capture_h_event_hdr, wmi_capture_h_event_hdr, fixed_param, WMITLV_SIZE_FIX) + WMITLV_CREATE_PARAM_STRUC(WMI_CAPTUREH_EVENTID); + +/* TDLS Peer Update event */ +#define WMITLV_TABLE_WMI_TDLS_PEER_EVENTID(id,op,buf,len) \ +WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_tdls_peer_event_fixed_param, wmi_tdls_peer_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) + WMITLV_CREATE_PARAM_STRUC(WMI_TDLS_PEER_EVENTID); + +/* VDEV MCC Beacon Interval Change Request Event */ +#define WMITLV_TABLE_WMI_VDEV_MCC_BCN_INTERVAL_CHANGE_REQ_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_vdev_mcc_bcn_intvl_change_event_fixed_param, wmi_vdev_mcc_bcn_intvl_change_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_VDEV_MCC_BCN_INTERVAL_CHANGE_REQ_EVENTID); + +#define WMITLV_TABLE_WMI_BATCH_SCAN_ENABLED_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_batch_scan_enabled_event_fixed_param, wmi_batch_scan_enabled_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_BATCH_SCAN_ENABLED_EVENTID); + +#define WMITLV_TABLE_WMI_BATCH_SCAN_RESULT_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_batch_scan_result_event_fixed_param, wmi_batch_scan_result_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len,WMITLV_TAG_ARRAY_STRUC, wmi_batch_scan_result_scan_list, scan_list, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len,WMITLV_TAG_ARRAY_STRUC, wmi_batch_scan_result_network_info, network_list, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_BATCH_SCAN_RESULT_EVENTID); + +#define WMITLV_TABLE_WMI_OFFLOAD_BCN_TX_STATUS_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_offload_bcn_tx_status_event_fixed_param, wmi_offload_bcn_tx_status_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_OFFLOAD_BCN_TX_STATUS_EVENTID); + +/* NOA Event */ +#define WMITLV_TABLE_WMI_P2P_NOA_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_p2p_noa_event_fixed_param, wmi_p2p_noa_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_p2p_noa_info, wmi_p2p_noa_info, p2p_noa_info, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_P2P_NOA_EVENTID); + +/* AP PS enhanced green ap Event */ +#define WMITLV_TABLE_WMI_AP_PS_EGAP_INFO_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_ap_ps_egap_info_event_fixed_param, wmi_ap_ps_egap_info_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_ap_ps_egap_info_chainmask_list, chainmask_list, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_AP_PS_EGAP_INFO_EVENTID); + +#define WMITLV_TABLE_WMI_PEER_INFO_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_peer_info_event_fixed_param, wmi_peer_info_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_peer_info, peer_info, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_PEER_INFO_EVENTID); + +#define WMITLV_TABLE_WMI_PEER_ANTDIV_INFO_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_peer_antdiv_info_event_fixed_param, wmi_peer_antdiv_info_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_peer_antdiv_info, peer_info, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_PEER_ANTDIV_INFO_EVENTID); + +#define WMITLV_TABLE_WMI_PEER_TX_FAIL_CNT_THR_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_peer_tx_fail_cnt_thr_event_fixed_param, wmi_peer_tx_fail_cnt_thr_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_PEER_TX_FAIL_CNT_THR_EVENTID); + +#define WMITLV_TABLE_WMI_PEER_OPER_MODE_CHANGE_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_peer_oper_mode_change_event_fixed_param, wmi_peer_oper_mode_change_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_PEER_OPER_MODE_CHANGE_EVENTID); + +/* DFS radar Event */ +#define WMITLV_TABLE_WMI_DFS_RADAR_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_dfs_radar_event_fixed_param, wmi_dfs_radar_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_DFS_RADAR_EVENTID); + +#define WMITLV_TABLE_WMI_PDEV_DFS_RADAR_DETECTION_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_pdev_dfs_radar_detection_event_fixed_param, wmi_pdev_dfs_radar_detection_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_PDEV_DFS_RADAR_DETECTION_EVENTID); + +#define WMITLV_TABLE_WMI_VDEV_ADFS_OCAC_COMPLETE_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_vdev_adfs_ocac_complete_event_fixed_param, wmi_vdev_adfs_ocac_complete_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_VDEV_ADFS_OCAC_COMPLETE_EVENTID); + +#define WMITLV_TABLE_WMI_VDEV_DFS_CAC_COMPLETE_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_vdev_dfs_cac_complete_event_fixed_param, wmi_vdev_dfs_cac_complete_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_VDEV_DFS_CAC_COMPLETE_EVENTID); + +/* Thermal Event */ +#define WMITLV_TABLE_WMI_THERMAL_MGMT_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_thermal_mgmt_event_fixed_param, wmi_thermal_mgmt_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_THERMAL_MGMT_EVENTID); + +#define WMITLV_TABLE_WMI_OEM_DMA_RING_CFG_RSP_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_oem_dma_ring_cfg_rsp_fixed_param, wmi_oem_dma_ring_cfg_rsp_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_OEM_DMA_RING_CFG_RSP_EVENTID) + +/* NAN Response/Indication Event */ +#define WMITLV_TABLE_WMI_NAN_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_nan_event_hdr, wmi_nan_event_hdr, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, data, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_NAN_EVENTID); + +/* NAN discovery interface created event */ +#define WMITLV_TABLE_WMI_NAN_DISC_IFACE_CREATED_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_nan_disc_iface_created_event_fixed_param, wmi_nan_disc_iface_created_event_fixed_param_PROTOTYPE, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_NAN_DISC_IFACE_CREATED_EVENTID); + +/* NAN discovery interface deleted event */ +#define WMITLV_TABLE_WMI_NAN_DISC_IFACE_DELETED_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_nan_disc_iface_deleted_event_fixed_param, wmi_nan_disc_iface_deleted_event_fixed_param_PROTOTYPE, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_NAN_DISC_IFACE_DELETED_EVENTID); + +/* NAN device started new cluster event */ +#define WMITLV_TABLE_WMI_NAN_STARTED_CLUSTER_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_nan_started_cluster_event_fixed_param, wmi_nan_started_cluster_event_fixed_param_PROTOTYPE, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_NAN_STARTED_CLUSTER_EVENTID); + +/* NAN device joined to cluster event */ +#define WMITLV_TABLE_WMI_NAN_JOINED_CLUSTER_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_nan_joined_cluster_event_fixed_param, wmi_nan_joined_cluster_event_fixed_param_PROTOTYPE, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_NAN_JOINED_CLUSTER_EVENTID); + +/* Coex report antenna isolation event */ +#define WMITLV_TABLE_WMI_COEX_REPORT_ANTENNA_ISOLATION_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_coex_report_isolation_event_fixed_param, wmi_coex_report_isolation_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_COEX_REPORT_ANTENNA_ISOLATION_EVENTID); + +/* NDP capabilities response event */ +#define WMITLV_TABLE_WMI_NDI_CAP_RSP_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_ndi_cap_rsp_event_fixed_param, wmi_ndi_cap_rsp_event_fixed_param_PROTOTYPE, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_NDI_CAP_RSP_EVENTID); + +/* NDP initiator response event */ +#define WMITLV_TABLE_WMI_NDP_INITIATOR_RSP_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_ndp_initiator_rsp_event_fixed_param, wmi_ndp_initiator_rsp_event_fixed_param_PROTOTYPE, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_NDP_INITIATOR_RSP_EVENTID); + +/* NDP responder response event */ +#define WMITLV_TABLE_WMI_NDP_RESPONDER_RSP_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_ndp_responder_rsp_event_fixed_param, wmi_ndp_responder_rsp_event_fixed_param_PROTOTYPE, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_NDP_RESPONDER_RSP_EVENTID); + +/** NDP end response event + * + * TLV (tag length value ) parameters follow the ndp_end_rsp + * structure. The TLV's are: + * wmi_ndp_end_rsp_per_ndi ndp_end_rsp_per_ndi_list[]; + * wmi_active_ndp_instance_id active_ndp_instances_id[]; + */ +#define WMITLV_TABLE_WMI_NDP_END_RSP_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_ndp_end_rsp_event_fixed_param, wmi_ndp_end_rsp_event_fixed_param_PROTOTYPE, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_ndp_end_rsp_per_ndi_PROTOTYPE, ndp_end_rsp_per_ndi_list, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_active_ndp_instance_id_PROTOTYPE, active_ndp_instances_id, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_NDP_END_RSP_EVENTID); + +/** NDP indication event + * + * TLV (tag length value ) parameters follow the ndp_indication + * structure. The TLV's are: + * A_UINT8 ndp_cfg[]; + * A_UINT8 ndp_app_info[]; + */ +#define WMITLV_TABLE_WMI_NDP_INDICATION_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_ndp_indication_event_fixed_param, wmi_ndp_indication_event_fixed_param_PROTOTYPE, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, ndp_cfg, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, ndp_app_info, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, ndp_scid, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_NDP_INDICATION_EVENTID); + +/** NDP confirm event + * TLV (tag length value ) parameters follow the ndp_confirm + * structure. The TLV's are: + * A_UINT8 ndp_cfg[]; + * A_UINT8 ndp_app_info[]; + */ +#define WMITLV_TABLE_WMI_NDP_CONFIRM_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_ndp_confirm_event_fixed_param, wmi_ndp_confirm_event_fixed_param_PROTOTYPE, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, ndp_cfg, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, ndp_app_info, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_NDP_CONFIRM_EVENTID); + +/** NDP end indication event + * + * TLV (tag length value ) parameters follow the ndp_end_indication + * structure. The TLV's are: + * wmi_ndp_end_indication ndp_end_indication_list[]; + */ +#define WMITLV_TABLE_WMI_NDP_END_INDICATION_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_ndp_end_indication_PROTOTYPE, ndp_end_indication_list, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_NDP_END_INDICATION_EVENTID); + +/* Update RCPI Info Event */ +#define WMITLV_TABLE_WMI_UPDATE_RCPI_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_update_rcpi_event_fixed_param, wmi_update_rcpi_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_UPDATE_RCPI_EVENTID); + +/* L1SS track Event */ +#define WMITLV_TABLE_WMI_PDEV_L1SS_TRACK_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_pdev_l1ss_track_event_fixed_param, wmi_pdev_l1ss_track_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_PDEV_L1SS_TRACK_EVENTID); + +#define WMITLV_TABLE_WMI_DIAG_DATA_CONTAINER_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_diag_data_container_event_fixed_param, wmi_diag_data_container_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, bufp, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_DIAG_DATA_CONTAINER_EVENTID); + +/* Estimated Link Speed Indication*/ +#define WMITLV_TABLE_WMI_PEER_ESTIMATED_LINKSPEED_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_peer_estimated_linkspeed_event_fixed_param, wmi_peer_estimated_linkspeed_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_PEER_ESTIMATED_LINKSPEED_EVENTID); + +/* NAN Response/Indication Event */ +#define WMITLV_TABLE_WMI_STATS_EXT_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_stats_ext_event_fixed_param, wmi_stats_ext_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, data, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_STATS_EXT_EVENTID); + +#define WMITLV_TABLE_WMI_OFFLOAD_PROB_RESP_TX_STATUS_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_offload_prb_rsp_tx_status_event_fixed_param, wmi_offload_prb_rsp_tx_status_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_OFFLOAD_PROB_RESP_TX_STATUS_EVENTID); + +/* host auto shut down event */ +#define WMITLV_TABLE_WMI_HOST_AUTO_SHUTDOWN_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_host_auto_shutdown_event_fixed_param, wmi_host_auto_shutdown_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_HOST_AUTO_SHUTDOWN_EVENTID); + +/* peer state Event */ +#define WMITLV_TABLE_WMI_PEER_STATE_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_peer_state_event_fixed_param, wmi_peer_state_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_PEER_STATE_EVENTID); + +/* peer delete response Event */ +#define WMITLV_TABLE_WMI_PEER_DELETE_RESP_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_peer_delete_resp_event_fixed_param, wmi_peer_delete_resp_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_PEER_DELETE_RESP_EVENTID); + +/* peer assoc conf Event */ +#define WMITLV_TABLE_WMI_PEER_ASSOC_CONF_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_peer_assoc_conf_event_fixed_param, wmi_peer_assoc_conf_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_PEER_ASSOC_CONF_EVENTID); + +/* D0-WOW Disable Ack event */ +#define WMITLV_TABLE_WMI_D0_WOW_DISABLE_ACK_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_d0_wow_disable_ack_event_fixed_param, wmi_d0_wow_disable_ack_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_D0_WOW_DISABLE_ACK_EVENTID); + +/* Pdev get chip temperature event */ +#define WMITLV_TABLE_WMI_PDEV_TEMPERATURE_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_pdev_temperature_event_fixed_param, wmi_pdev_temperature_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_PDEV_TEMPERATURE_EVENTID); + +/* Pdev get ANT DIV feature status event */ +#define WMITLV_TABLE_WMI_PDEV_ANTDIV_STATUS_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_pdev_antdiv_status_event_fixed_param, wmi_pdev_antdiv_status_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_PDEV_ANTDIV_STATUS_EVENTID); + +/* mDNS offload stats event */ +#define WMITLV_TABLE_WMI_MDNS_STATS_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_mdns_stats_event_fixed_param, wmi_mdns_stats_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_MDNS_STATS_EVENTID); + +/* pdev resume event */ +#define WMITLV_TABLE_WMI_PDEV_RESUME_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_pdev_resume_event_fixed_param, wmi_pdev_resume_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_PDEV_RESUME_EVENTID); + +/* SAP Authentication offload event */ +#define WMITLV_TABLE_WMI_SAP_OFL_ADD_STA_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_sap_ofl_add_sta_event_fixed_param, wmi_sap_ofl_add_sta_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, bufp, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_SAP_OFL_ADD_STA_EVENTID); + +#define WMITLV_TABLE_WMI_SAP_OFL_DEL_STA_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_sap_ofl_del_sta_event_fixed_param, wmi_sap_ofl_del_sta_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_SAP_OFL_DEL_STA_EVENTID); + +/* Set OCB schedule event, DEPRECATED */ +#define WMITLV_TABLE_WMI_OCB_SET_SCHED_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id, op, buf, len, WMITLV_TAG_STRUC_wmi_ocb_set_sched_event_fixed_param, wmi_ocb_set_sched_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_OCB_SET_SCHED_EVENTID); + +/* Set OCB configuration response event */ +#define WMITLV_TABLE_WMI_OCB_SET_CONFIG_RESP_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_ocb_set_config_resp_event_fixed_param, wmi_ocb_set_config_resp_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_OCB_SET_CONFIG_RESP_EVENTID); + +/* Get TSF timer response event */ +#define WMITLV_TABLE_WMI_OCB_GET_TSF_TIMER_RESP_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_ocb_get_tsf_timer_resp_event_fixed_param, wmi_ocb_get_tsf_timer_resp_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_OCB_GET_TSF_TIMER_RESP_EVENTID); + +/* Get DCC stats response event */ +#define WMITLV_TABLE_WMI_DCC_GET_STATS_RESP_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_dcc_get_stats_resp_event_fixed_param, wmi_dcc_get_stats_resp_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_dcc_ndl_stats_per_channel, stats_per_channel_list, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_DCC_GET_STATS_RESP_EVENTID); + +/* Update DCC NDL response event */ +#define WMITLV_TABLE_WMI_DCC_UPDATE_NDL_RESP_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_dcc_update_ndl_resp_event_fixed_param, wmi_dcc_update_ndl_resp_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_DCC_UPDATE_NDL_RESP_EVENTID); + +/* DCC stats event */ +#define WMITLV_TABLE_WMI_DCC_STATS_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_dcc_stats_event_fixed_param, wmi_dcc_stats_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_dcc_ndl_stats_per_channel, stats_per_channel_list, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_DCC_STATS_EVENTID); + +/* Read TSF timer response event */ +#define WMITLV_TABLE_WMI_VDEV_TSF_REPORT_EVENTID(id,op,buf,len) \ +WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_vdev_tsf_report_event_fixed_param, wmi_vdev_tsf_report_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_VDEV_TSF_REPORT_EVENTID); + +/* Vdev capabilities IE to be transmitted in mgmt frames */ +#define WMITLV_TABLE_WMI_VDEV_SET_IE_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_vdev_set_ie_cmd_fixed_param, wmi_vdev_set_ie_cmd_fixed_param, vdev_ie, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, bufp, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_VDEV_SET_IE_CMDID); + +/* SOC Set Hardware Mode Response event - DEPRECATED */ +#define WMITLV_TABLE_WMI_SOC_SET_HW_MODE_RESP_EVENTID(id,op,buf,len) \ +WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_soc_set_hw_mode_response_event_fixed_param, wmi_soc_set_hw_mode_response_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ +WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_soc_set_hw_mode_response_vdev_mac_entry, wmi_soc_set_hw_mode_response_vdev_mac_mapping, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_SOC_SET_HW_MODE_RESP_EVENTID); + +/* PDEV Set Hardware Mode Response event */ +#define WMITLV_TABLE_WMI_PDEV_SET_HW_MODE_RESP_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_pdev_set_hw_mode_response_event_fixed_param, wmi_pdev_set_hw_mode_response_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_pdev_set_hw_mode_response_vdev_mac_entry, wmi_pdev_set_hw_mode_response_vdev_mac_mapping, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_PDEV_SET_HW_MODE_RESP_EVENTID); + +/* SOC Hardware Mode Transition event - DEPRECATED */ +#define WMITLV_TABLE_WMI_SOC_HW_MODE_TRANSITION_EVENTID(id,op,buf,len) \ +WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_soc_hw_mode_transition_event_fixed_param, wmi_soc_hw_mode_transition_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ +WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_soc_set_hw_mode_response_vdev_mac_entry, wmi_soc_set_hw_mode_response_vdev_mac_mapping, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_SOC_HW_MODE_TRANSITION_EVENTID); + +/* PDEV Hardware Mode Transition event */ +#define WMITLV_TABLE_WMI_PDEV_HW_MODE_TRANSITION_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_pdev_hw_mode_transition_event_fixed_param, wmi_pdev_hw_mode_transition_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_pdev_set_hw_mode_response_vdev_mac_entry, wmi_pdev_set_hw_mode_response_vdev_mac_mapping, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_PDEV_HW_MODE_TRANSITION_EVENTID); + +/* SOC Set Dual MAC Config Response event - DEPRECATED */ +#define WMITLV_TABLE_WMI_SOC_SET_DUAL_MAC_CONFIG_RESP_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_soc_set_dual_mac_config_response_event_fixed_param, wmi_soc_set_dual_mac_config_response_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_SOC_SET_DUAL_MAC_CONFIG_RESP_EVENTID); + +/* PDEV Set Dual MAC Config Response event */ +#define WMITLV_TABLE_WMI_PDEV_SET_MAC_CONFIG_RESP_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_pdev_set_mac_config_response_event_fixed_param, wmi_pdev_set_mac_config_response_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_PDEV_SET_MAC_CONFIG_RESP_EVENTID); + +/* Packet Filter configure command*/ +#define WMITLV_TABLE_WMI_PACKET_FILTER_CONFIG_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_packet_filter_config_fixed_param, WMI_PACKET_FILTER_CONFIG_CMD_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_PACKET_FILTER_CONFIG_CMDID); + +/* Packet Filter enable command*/ +#define WMITLV_TABLE_WMI_PACKET_FILTER_ENABLE_CMDID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_packet_filter_enable_fixed_param, WMI_PACKET_FILTER_ENABLE_CMD_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_PACKET_FILTER_ENABLE_CMDID); + +/* MAWC enable/disable sensor event */ +#define WMITLV_TABLE_WMI_MAWC_ENABLE_SENSOR_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_mawc_enable_sensor_event_fixed_param, wmi_mawc_enable_sensor_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_MAWC_ENABLE_SENSOR_EVENTID); + +/* SMPS force mode complete Event */ +#define WMITLV_TABLE_WMI_STA_SMPS_FORCE_MODE_COMPLETE_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_sta_smps_force_mode_complete_event_fixed_param, wmi_sta_smps_force_mode_complete_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_STA_SMPS_FORCE_MODE_COMPLETE_EVENTID); + +/* bpf offload capability info event */ +#define WMITLV_TABLE_WMI_BPF_CAPABILIY_INFO_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_bpf_capability_info_evt_fixed_param, wmi_bpf_capability_info_evt_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_BPF_CAPABILIY_INFO_EVENTID); + +/* bpf offload vdev status info event */ +#define WMITLV_TABLE_WMI_BPF_VDEV_STATS_INFO_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_bpf_vdev_stats_info_evt_fixed_param, wmi_bpf_vdev_stats_info_evt_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_BPF_VDEV_STATS_INFO_EVENTID); + +/* Indicate new country code to host from 11d scan */ +#define WMITLV_TABLE_WMI_11D_NEW_COUNTRY_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_11d_new_country_event_fixed_param, wmi_11d_new_country_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_11D_NEW_COUNTRY_EVENTID); + +/* Regulatory channel list of current country code */ +#define WMITLV_TABLE_WMI_REG_CHAN_LIST_CC_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_reg_chan_list_cc_event_fixed_param, wmi_reg_chan_list_cc_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_regulatory_rule_struct, reg_rule_array, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_REG_CHAN_LIST_CC_EVENTID); + +/* FIPS event */ +#define WMITLV_TABLE_WMI_PDEV_FIPS_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_pdev_fips_event_fixed_param, wmi_pdev_fips_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, data, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_PDEV_FIPS_EVENTID); + +#define WMITLV_TABLE_WMI_PDEV_CHANNEL_HOPPING_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_pdev_channel_hopping_event_fixed_param, wmi_pdev_channel_hopping_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_PDEV_CHANNEL_HOPPING_EVENTID); + +#define WMITLV_TABLE_WMI_PDEV_ANI_CCK_LEVEL_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_ani_cck_event_fixed_param, wmi_ani_cck_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_PDEV_ANI_CCK_LEVEL_EVENTID); + +#define WMITLV_TABLE_WMI_PDEV_CHIP_POWER_SAVE_FAILURE_DETECTED_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_chip_power_save_failure_detected_fixed_param, wmi_chip_power_save_failure_detected_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_PDEV_CHIP_POWER_SAVE_FAILURE_DETECTED_EVENTID); + +#define WMITLV_TABLE_WMI_PDEV_CHIP_POWER_STATS_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_pdev_chip_power_stats_event_fixed_param, wmi_pdev_chip_power_stats_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_UINT32, A_UINT32, debug_registers, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_PDEV_CHIP_POWER_STATS_EVENTID); + +#define WMITLV_TABLE_WMI_PDEV_ANI_OFDM_LEVEL_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_ani_ofdm_event_fixed_param, wmi_ani_ofdm_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_PDEV_ANI_OFDM_LEVEL_EVENTID); + +#define WMITLV_TABLE_WMI_PDEV_TPC_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_pdev_tpc_event_fixed_param, wmi_pdev_tpc_event_fixed_param, fixed_param, WMITLV_SIZE_FIX)\ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_UINT32, A_UINT32, tpc, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_PDEV_TPC_EVENTID); + +#define WMITLV_TABLE_WMI_PDEV_NFCAL_POWER_ALL_CHANNELS_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_pdev_nfcal_power_all_channels_event_fixed_param, wmi_pdev_nfcal_power_all_channels_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_pdev_nfcal_power_all_channels_nfdBr, nfdbr, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_pdev_nfcal_power_all_channels_nfdBm, nfdbm, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_pdev_nfcal_power_all_channels_freqNum, freqnum, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_PDEV_NFCAL_POWER_ALL_CHANNELS_EVENTID); + +#define WMITLV_TABLE_WMI_PEER_RATECODE_LIST_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_peer_ratecode_list_event_fixed_param, wmi_peer_ratecode_list_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_peer_cck_ofdm_rate_info, ratecode_legacy, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_peer_mcs_rate_info, ratecode_mcs, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_PEER_RATECODE_LIST_EVENTID); + +#define WMITLV_TABLE_WMI_WDS_PEER_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_wds_addr_event_fixed_param, wmi_wds_addr_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_WDS_PEER_EVENTID); + +#define WMITLV_TABLE_WMI_PEER_STA_PS_STATECHG_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_peer_sta_ps_statechange_event_fixed_param, wmi_peer_sta_ps_statechange_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_PEER_STA_PS_STATECHG_EVENTID); + +#define WMITLV_TABLE_WMI_INST_RSSI_STATS_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_inst_rssi_stats_resp_fixed_param, wmi_inst_rssi_stats_resp_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_INST_RSSI_STATS_EVENTID); + +#define WMITLV_TABLE_WMI_RADIO_TX_POWER_LEVEL_STATS_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_tx_power_level_stats_evt_fixed_param, wmi_tx_power_level_stats_evt_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_UINT32, A_UINT32, tx_time_per_power_level, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_RADIO_TX_POWER_LEVEL_STATS_EVENTID); + +#define WMITLV_TABLE_WMI_RMC_NEW_LEADER_EVENTID(id, op, buf, len) \ + WMITLV_ELEM(id, op, buf, len, WMITLV_TAG_STRUC_wmi_rmc_manual_leader_event_fixed_param, wmi_rmc_manual_leader_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_RMC_NEW_LEADER_EVENTID); + +/* Layout of WMI_REPORT_STATS_EVENTID message: + * fixed_param; + * wmi_chan_cca_stats chan_cca_stats[]; Array length is specified by num_chan_cca_stats + * wmi_peer_signal_stats peer_signal_stats[]; Array length is specified by num_peer_signal_stats + * wmi_peer_ac_tx_stats peer_ac_tx_stats[]; Array length is specified by num_peer_ac_tx_stats + * wmi_tx_stats tx_stats[][]; Array length is num_peer_ac_tx_stats * WLAN_MAX_AC, array index is (peer_index * WLAN_MAX_AC + ac_index) + * A_UINT32 tx_mpdu_aggr[][][]; Array length is num_peer_ac_tx_stats * WLAN_MAX_AC * tx_mpdu_aggr_array_len, + * array index is (peer_index * WLAN_MAX_AC + ac_index) * tx_mpdu_aggr_array_len + A-MPDU size index + * Contains a histogram of how many A-MPDUs of a given size (i.e. number of MPDUs) have been transmitted. + * Element 0 contains the number of PPDUs with a single-MPDU A-MPDU. + * Element 1 contains the number of PPDUs with 2 MPDUs. + * Element 2 contains the number of PPDUs with 3 MPDUs. + * Element tx_mpdu_aggr_array_len-1 contains the number of PPDUs with >= tx_mpdu_aggr_array_len MPDUs. + * A_UINT32 tx_succ_mcs[][][]; Array length is num_peer_ac_tx_stats * WLAN_MAX_AC * tx_succ_mcs_array_len, + * array index is (peer_index * WLAN_MAX_AC + ac_index) * tx_succ_mcs_array_len + MCS index + * Contains a count of how many tx PPDUs have been acked for each MCS of each AC of each peer. + * A_UINT32 tx_fail_mcs[][][]; Array length is num_peer_ac_tx_stats * WLAN_MAX_AC * tx_fail_mcs_array_len, + * array index is (peer_index * WLAN_MAX_AC + ac_index) * tx_fail_mcs_array_len + MCS index + * Contains a count of how many PPDUs failed tx due to no ack for each MCS of each AC of each peer. + * A_UINT32 tx_ppdu_delay[][][]; Array length is num_peer_ac_tx_stats * WLAN_MAX_AC * tx_ppdu_delay_array_len, + * array index is (peer_index * WLAN_MAX_AC + ac_index) * tx_ppdu_delay_array_len + delay index + * Contains a histogram of how many PPDUs encountered each level of delay due to retries or air interface contention. + * The time represented by each array element (i.e. histogram bin) is specified by tx_ppdu_delay_bin_size_ms. + * Element 0 contains the count of PPDUs delayed by less than tx_ppdu_delay_bin_size_ms. + * Element 1 contains the count of PPDUs delayed by more than 1x tx_ppdu_delay_bin_size_ms but less than 2x. + * Element tx_ppdu_delay_array_len-1 contains the count of PPDUs delayed by + * >= tx_ppdu_delay_bin_size_ms * (tx_ppdu_delay_array_len-1) + * wmi_peer_ac_rx_stats peer_ac_rx_stats[]; Array length is specified by num_peer_ac_rx_stats + * wmi_rx_stats rx_stats[][]; Array length is num_peer_ac_rx_stats * WLAN_MAX_AC, array index is (peer_index * WLAN_MAX_AC + ac_index) + * A_UINT32 rx_mpdu_aggr[][][]; Array length is num_peer_ac_rx_stats * WLAN_MAX_AC * rx_mpdu_aggr_array_len, + * array index is (peer_index * WLAN_MAX_AC + ac_index) * rx_mpdu_aggr_array_len + A-MPDU size index + * Contains a histogram of how many A-MPDUs of a given size (i.e. number of MPDUs) have been received. + * Element 0 contains the number of PPDUs with a single MPDU. + * Element 1 contains the number of PPDUs with 2 MPDUs. + * Element 2 contains the number of PPDUs with 3 MPDUs. + * Element rx_mpdu_aggr_array_len-1 contains the number of PPDUs with >= rx_mpdu_aggr_array_len MPDUs. + * A_UINT32 rx_mcs[][][]; Array length is (num_peer_ac_rx_stats * WLAN_MAX_AC) * rx_mcs_array_len, + * array index is (peer_index * WLAN_MAX_AC + ac_index) * rx_mcs_array_len + MCS index + * Contains a count of rx PPDUs for each MCS of each AC of each peer. + * For example, if there were 2 peers (X and Y) whose stats were being reported, + * the message and its TLV arrays would look like this: + * 1. fixed_param + * 2. chan_cca_stats[0] + * 3. peer_signal_stats[0] for peer X + * 4. peer_signal_stats[1] for peer Y + * 5. peer_ac_tx_stats[0] for X + * 6. peer_ac_tx_stats[1] for Y + * 7. tx_stats[0][0] for peer X, AC 0 + * 8. tx_stats[0][1] for peer X, AC 1 + * 9. tx_stats[0][2] for peer X, AC 2 + * 10. tx_stats[0][3] for peer X, AC 3 + * 11. tx_stats[1][0] for peer Y, AC 0 + * 12 tx_stats[1][1] for peer Y, AC 1 + * 13. tx_stats[1][2] for peer Y, AC 2 + * 14. tx_stats[1][3] for peer Y, AC 3 + * 15. tx_mpdu_aggr[0][0][] for peer X, AC 0 + * 16. tx_mpdu_aggr[0][1][] for peer X, AC 1 + * 17. tx_mpdu_aggr[0][2][] for peer X, AC 2 + * 18. tx_mpdu_aggr[0][3][] for peer X, AC 3 + * 19. tx_mpdu_aggr[1][0][] for peer Y, AC 0 + * 20. tx_mpdu_aggr[1][1][] for peer Y, AC 1 + * 21. tx_mpdu_aggr[1][2][] for peer Y, AC 2 + * 22. tx_mpdu_aggr[1][3][] for peer Y, AC 3 + * 23. tx_succ_mcs[0][0][] for peer X, AC 0 + * 24. tx_succ_mcs[0][1][] for peer X, AC 1 + * 25. tx_succ_mcs[0][2][] for peer X, AC 2 + * 26. tx_succ_mcs[0][3][] for peer X, AC 3 + * 27. tx_succ_mcs[1][0][] for peer Y, AC 0 + * 28. tx_succ_mcs[1][1][] for peer Y, AC 1 + * 29. tx_succ_mcs[1][2][] for peer Y, AC 2 + * 30. tx_succ_mcs[1][3][] for peer Y, AC 3 + * 31. tx_fail_mcs[0][0][] for peer X, AC 0 + * 32. tx_fail_mcs[0][1][] for peer X, AC 1 + * 33. tx_fail_mcs[0][2][] for peer X, AC 2 + * 34. tx_fail_mcs[0][3][] for peer X, AC 3 + * 35. tx_fail_mcs[1][0][] for peer Y, AC 0 + * 36. tx_fail_mcs[1][1][] for peer Y, AC 1 + * 37. tx_fail_mcs[1][2][] for peer Y, AC 2 + * 38. tx_fail_mcs[1][3][] for peer Y, AC 3 + * 39. tx_ppdu_delay[0][0][] for peer X, AC 0 + * 40. tx_ppdu_delay[0][1][] for peer X, AC 1 + * 41. tx_ppdu_delay[0][2][] for peer X, AC 2 + * 42. tx_ppdu_delay[0][3][] for peer X, AC 3 + * 43. tx_ppdu_delay[1][0][] for peer Y, AC 0 + * 44. tx_ppdu_delay[1][1][] for peer Y, AC 1 + * 45. tx_ppdu_delay[1][2][] for peer Y, AC 2 + * 46. tx_ppdu_delay[1][3][] for peer Y, AC 3 + * 47. peer_ac_rx_stats[0] for X + * 48. peer_ac_rx_stats[1] for Y + * 49. rx_stats[0][0] for peer X, AC 0 + * 50. rx_stats[0][1] for peer X, AC 1 + * 51. rx_stats[0][2] for peer X, AC 2 + * 52. rx_stats[0][3] for peer X, AC 3 + * 53. rx_stats[1][0] for peer Y, AC 0 + * 54. rx_stats[1][1] for peer Y, AC 1 + * 55. rx_stats[1][2] for peer Y, AC 2 + * 56. rx_stats[1][3] for peer Y, AC 3 + * 57. rx_mpdu_aggr[0][0][] for peer X, AC 0 + * 58. rx_mpdu_aggr[0][1][] for peer X, AC 1 + * 59. rx_mpdu_aggr[0][2][] for peer X, AC 2 + * 60. rx_mpdu_aggr[0][3][] for peer X, AC 3 + * 61. rx_mpdu_aggr[1][0][] for peer Y, AC 0 + * 62. rx_mpdu_aggr[1][1][] for peer Y, AC 1 + * 63. rx_mpdu_aggr[1][2][] for peer Y, AC 2 + * 64. rx_mpdu_aggr[1][3][] for peer Y, AC 3 + * 65. rx_mcs[0][0][] for peer X, AC 0 + * 66. rx_mcs[0][1][] for peer X, AC 1 + * 67. rx_mcs[0][2][] for peer X, AC 2 + * 68. rx_mcs[0][3][] for peer X, AC 3 + * 69. rx_mcs[1][0][] for peer Y, AC 0 + * 70. rx_mcs[1][1][] for peer Y, AC 1 + * 71. rx_mcs[1][2][] for peer Y, AC 2 + * 72. rx_mcs[1][3][] for peer Y, AC 3 + **/ +#define WMITLV_TABLE_WMI_REPORT_STATS_EVENTID(id, op, buf, len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_report_stats_event_fixed_param, wmi_report_stats_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_chan_cca_stats, chan_cca_stats, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_peer_signal_stats, peer_signal_stats, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_peer_ac_tx_stats, peer_ac_tx_stats, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_tx_stats, tx_stats, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_UINT32, A_UINT32, tx_mpdu_aggr, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_UINT32, A_UINT32, tx_succ_mcs, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_UINT32, A_UINT32, tx_fail_mcs, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_UINT32, A_UINT32, tx_ppdu_delay, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_peer_ac_rx_stats, peer_ac_rx_stats, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_rx_stats, rx_stats, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_UINT32, A_UINT32, rx_mpdu_aggr, WMITLV_SIZE_VAR) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_UINT32, A_UINT32, rx_mcs, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_REPORT_STATS_EVENTID); + +#define WMITLV_TABLE_WMI_VDEV_ENCRYPT_DECRYPT_DATA_RESP_EVENTID(id, op, buf, len) \ + WMITLV_ELEM(id, op, buf, len, WMITLV_TAG_STRUC_wmi_vdev_encrypt_decrypt_data_resp_event_fixed_param, wmi_vdev_encrypt_decrypt_data_resp_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, enc80211_frame, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_VDEV_ENCRYPT_DECRYPT_DATA_RESP_EVENTID); + +#define WMITLV_TABLE_WMI_PEER_STATS_INFO_EVENTID(id, op, buf, len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_peer_stats_info_event_fixed_param, wmi_peer_stats_info_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_peer_stats_info, peer_stats_info, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_PEER_STATS_INFO_EVENTID); + +#define WMITLV_TABLE_WMI_RADIO_CHAN_STATS_EVENTID(id, op, buf, len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_radio_chan_stats_event_fixed_param, wmi_radio_chan_stats_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_radio_chan_stats, radio_chan_stats, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_RADIO_CHAN_STATS_EVENTID); + +#define WMITLV_TABLE_WMI_PKGID_EVENTID(id, op, buf, len) \ + WMITLV_ELEM(id, op, buf, len, WMITLV_TAG_STRUC_wmi_pkgid_event_fixed_param, wmi_pkgid_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_PKGID_EVENTID); + +/* mac randomization event */ +#define WMITLV_TABLE_WMI_VDEV_ADD_MAC_ADDR_TO_RX_FILTER_STATUS_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_vdev_add_mac_addr_to_rx_filter_status_event_fixed_param, wmi_vdev_add_mac_addr_to_rx_filter_status_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_VDEV_ADD_MAC_ADDR_TO_RX_FILTER_STATUS_EVENTID); + +#define WMITLV_TABLE_WMI_PDEV_CSA_SWITCH_COUNT_STATUS_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_pdev_csa_switch_count_status_event_fixed_param, wmi_pdev_csa_switch_count_status_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_UINT32, A_UINT32, vdev_ids, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_PDEV_CSA_SWITCH_COUNT_STATUS_EVENTID); + +/* cal version response event */ +#define WMITLV_TABLE_WMI_PDEV_CHECK_CAL_VERSION_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_pdev_check_cal_version_event_fixed_param, wmi_pdev_check_cal_version_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_PDEV_CHECK_CAL_VERSION_EVENTID); + +/* ARP stats response event */ +#define WMITLV_TABLE_WMI_VDEV_GET_ARP_STAT_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_vdev_get_arp_stats_event_fixed_param, wmi_vdev_get_arp_stats_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_VDEV_GET_ARP_STAT_EVENTID); + +/* Coex BT activity response event */ +#define WMITLV_TABLE_WMI_WLAN_COEX_BT_ACTIVITY_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_coex_bt_activity_event_fixed_param, wmi_coex_bt_activity_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) +WMITLV_CREATE_PARAM_STRUC(WMI_WLAN_COEX_BT_ACTIVITY_EVENTID); + +/* Thermal Throttling stats event */ +#define WMITLV_TABLE_WMI_THERM_THROT_STATS_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_therm_throt_stats_event_fixed_param, wmi_therm_throt_stats_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_STRUC, wmi_therm_throt_level_stats_info, therm_throt_level_stats_info, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_THERM_THROT_STATS_EVENTID); + + +/* UNIT-TEST Event */ +#define WMITLV_TABLE_WMI_UNIT_TEST_EVENTID(id,op,buf,len) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_STRUC_wmi_unit_test_event_fixed_param, wmi_unit_test_event_fixed_param, fixed_param, WMITLV_SIZE_FIX) \ + WMITLV_ELEM(id,op,buf,len, WMITLV_TAG_ARRAY_BYTE, A_UINT8, bufp, WMITLV_SIZE_VAR) +WMITLV_CREATE_PARAM_STRUC(WMI_UNIT_TEST_EVENTID); + +#ifdef __cplusplus +} +#endif + +#endif /*_WMI_TLV_DEFS_H_*/ diff --git a/drivers/staging/fw-api/fw/wmi_tlv_helper.h b/drivers/staging/fw-api/fw/wmi_tlv_helper.h new file mode 100755 index 0000000000000000000000000000000000000000..6634c8f186c63416e977821799ccd1435120558a --- /dev/null +++ b/drivers/staging/fw-api/fw/wmi_tlv_helper.h @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ +#ifndef _WMI_TLV_HELPER_H_ +#define _WMI_TLV_HELPER_H_ + +/* + * Every command or event parameter structure will need a TLV definition. + * The macro WMITLV_TABLE is used to help build this TLV definition. Inside this macro define, the + * individual TLV's are specified. The parameters for WMITLV_ELEM are: + * (1) the list of parameters that are passed unchanged from the WMITLV_TABLE. Currently, they are id,op,buf,len + * (2) The TLV Tag. You should create a new tag for each cmd/event in WMITLV_TAG_ID. The name of the + * tag is . There are special tags, + * e.g. WMI_TLVTAG_ARRAY_UINT32 and WMI_TLVTAG_ARRAY_STRUC. WMI_TLVTAG_ARRAY_UINT32 is for a + * variable size array of UINT32 elements. WMI_TLVTAG_ARRAY_STRUC is for a varialbe size array + * of structures. + * (3) type of the TLV. For WMI_TLVTAG_ARRAY_* tag, then it is the type of each element. + * (4) Name of this TLV. It must be unique in this TLV TABLE. + * (5) Either WMITLV_SIZE_FIX or WMITLV_SIZE_VAR to indicate if this TLV is variable size. + * + * Note: It is important that the last TLV_ELEM does not have the "\" character. +*/ + +/* Size of the TLV Header which is the Tag and Length fields */ +#define WMI_TLV_HDR_SIZE (1 * sizeof(A_UINT32)) + +/** TLV Helper macro to get the TLV Header given the pointer + * to the TLV buffer. */ +#define WMITLV_GET_HDR(tlv_buf) (((A_UINT32 *)(tlv_buf))[0]) + +/** TLV Helper macro to set the TLV Header given the pointer + * to the TLV buffer. */ +#define WMITLV_SET_HDR(tlv_buf, tag, len) (((A_UINT32 *)(tlv_buf))[0]) = ((tag << 16) | (len & 0x0000FFFF)) + +/** TLV Helper macro to get the TLV Tag given the TLV header. */ +#define WMITLV_GET_TLVTAG(tlv_header) ((A_UINT32)((tlv_header)>>16)) + +/** TLV Helper macro to get the TLV Buffer Length (minus TLV + * header size) given the TLV header. */ +#define WMITLV_GET_TLVLEN(tlv_header) ((A_UINT32)((tlv_header) & 0x0000FFFF)) + +/** TLV Helper macro to get the TLV length from TLV structure size by removing TLV header size */ +#define WMITLV_GET_STRUCT_TLVLEN(tlv_struct) ((A_UINT32)(sizeof(tlv_struct)-WMI_TLV_HDR_SIZE)) + +/* Indicates whether the TLV is fixed size or variable length */ +#define WMITLV_SIZE_FIX 0 +#define WMITLV_SIZE_VAR 1 + +typedef struct { + A_UINT32 tag_order; + A_UINT32 tag_id; + A_UINT32 tag_struct_size; + A_UINT32 tag_varied_size; + A_UINT32 tag_array_size; + A_UINT32 cmd_num_tlv; +} wmitlv_attributes_struc; + + +/* Template structure definition for a variable size array of UINT32 */ +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMI_TLVTAG_ARRAY_UINT32 */ + A_UINT32 uint32_array[1]; /* variable length Array of UINT32 */ +} wmitlv_array_uint32; + +/* Template structure definition for a variable size array of unknown structure */ +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMI_TLVTAG_ARRAY_STRUC */ + A_UINT32 struc_array[1]; /* variable length Array of structures */ +} wmitlv_array_struc; + +/* + * Used to fill in the "arr_size" parameter when it is not specified and hence, invalid. Can be used to + * indicate if the original TLV definition specify this fixed array size. + */ +#define WMITLV_ARR_SIZE_INVALID 0x1FE + +#define WMITLV_GET_TAG_NUM_TLV_ATTRIB(wmi_cmd_event_id) \ + WMI_TLV_HLPR_NUM_TLVS_FOR_##wmi_cmd_event_id + + +void +wmitlv_set_static_param_tlv_buf(void *param_tlv_buf, A_UINT32 max_tlvs_accomodated); + +void +wmitlv_set_static_param_tlv_buf_ext(void *param_tlv_buf, A_UINT32 max_tlvs_accomodated, A_UINT32 indx); + +void +wmitlv_free_allocated_command_tlvs( + A_UINT32 cmd_id, + void **wmi_cmd_struct_ptr); + +void +wmitlv_free_allocated_event_tlvs( + A_UINT32 event_id, + void **wmi_cmd_struct_ptr); + +int +wmitlv_check_command_tlv_params( + void *os_ctx, void *param_struc_ptr, A_UINT32 param_buf_len, A_UINT32 wmi_cmd_event_id); + +int +wmitlv_check_event_tlv_params( + void *os_ctx, void *param_struc_ptr, A_UINT32 param_buf_len, A_UINT32 wmi_cmd_event_id); + +int +wmitlv_check_and_pad_command_tlvs( + void *os_ctx, void *param_struc_ptr, A_UINT32 param_buf_len, A_UINT32 wmi_cmd_event_id, void **wmi_cmd_struct_ptr); + +int +wmitlv_check_and_pad_event_tlvs( + void *os_ctx, void *param_struc_ptr, A_UINT32 param_buf_len, A_UINT32 wmi_cmd_event_id, void **wmi_cmd_struct_ptr); + +/** This structure is the element for the Version WhiteList + * table. */ +typedef struct { + A_UINT32 major; + A_UINT32 minor; + A_UINT32 namespace_0; + A_UINT32 namespace_1; + A_UINT32 namespace_2; + A_UINT32 namespace_3; +} wmi_whitelist_version_info; + +struct _wmi_abi_version; /* Forward declaration to make the ARM compiler happy */ + +int +wmi_cmp_and_set_abi_version(int num_whitelist, wmi_whitelist_version_info *version_whitelist_table, + struct _wmi_abi_version *my_vers, + struct _wmi_abi_version *opp_vers, + struct _wmi_abi_version *out_vers); + +int +wmi_versions_are_compatible(struct _wmi_abi_version *vers1, struct _wmi_abi_version *vers2); + +#endif /*_WMI_TLV_HELPER_H_*/ diff --git a/drivers/staging/fw-api/fw/wmi_unified.h b/drivers/staging/fw-api/fw/wmi_unified.h new file mode 100755 index 0000000000000000000000000000000000000000..f22b399eaee73473ff8e923ee799c825adbd7a37 --- /dev/null +++ b/drivers/staging/fw-api/fw/wmi_unified.h @@ -0,0 +1,20159 @@ +/* + * Copyright (c) 2010-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * @addtogroup WMIAPI + *@{ + */ + +/** @file + * This file specifies the WMI interface for the Software Architecture. + * + * It includes definitions of all the commands and events. Commands are messages + * from the host to the target. Events and Replies are messages from the target + * to the host. + * + * Ownership of correctness in regards to WMI commands + * belongs to the host driver and the target is not required to validate + * parameters for value, proper range, or any other checking. + * + * Guidelines for extending this interface are below. + * + * 1. Add new WMI commands ONLY within the specified range - 0x9000 - 0x9fff + * 2. Use ONLY A_UINT32 type for defining member variables within WMI command/event + * structures. Do not use A_UINT8, A_UINT16, A_BOOL or enum types within these structures. + * 3. DO NOT define bit fields within structures. Implement bit fields using masks + * if necessary. Do not use the programming language's bit field definition. + * 4. Define macros for encode/decode of A_UINT8, A_UINT16 fields within the A_UINT32 + * variables. Use these macros for set/get of these fields. Try to use this to + * optimize the structure without bloating it with A_UINT32 variables for every lower + * sized field. + * 5. Do not use PACK/UNPACK attributes for the structures as each member variable is + * already 4-byte aligned by virtue of being a A_UINT32 type. + * 6. Comment each parameter part of the WMI command/event structure by using the + * 2 stars at the begining of C comment instead of one star to enable HTML document + * generation using Doxygen. + * + */ + +#ifndef _WMI_UNIFIED_H_ +#define _WMI_UNIFIED_H_ + + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +#define ATH_MAC_LEN 6 /**< length of MAC in bytes */ +#define WMI_EVENT_STATUS_SUCCESS 0 /* Success return status to host */ +#define WMI_EVENT_STATUS_FAILURE 1 /* Failure return status to host */ + +#define MAX_TX_RATE_VALUES 10 /*Max Tx Rates*/ +#define MAX_RSSI_VALUES 10 /*Max Rssi values*/ +#define WMI_MAX_CHAINS 8 + +/* The WLAN_MAX_AC macro cannot be changed without breaking + WMI compatibility. */ +/* The maximum value of access category */ +#define WLAN_MAX_AC 4 + +/* + * These don't necessarily belong here; but as the MS/SM macros require + * ar6000_internal.h to be included, it may not be defined as yet. + */ +#define WMI_F_MS(_v, _f) \ + (((_v) & (_f)) >> (_f##_S)) + +/* + * This breaks the "good macro practice" of only referencing each + * macro field once (to avoid things like field++ from causing issues.) + */ +#define WMI_F_RMW(_var, _v, _f) \ + do { \ + (_var) &= ~(_f); \ + (_var) |= (((_v) << (_f##_S)) & (_f)); \ + } while (0) + +#define WMI_GET_BITS(_val,_index,_num_bits) \ + (((_val) >> (_index)) & ((1 << (_num_bits)) - 1)) + +#define WMI_SET_BITS(_var,_index,_num_bits,_val) do { \ + (_var) &= ~(((1 << (_num_bits)) - 1) << (_index)); \ + (_var) |= (((_val) & ((1 << (_num_bits)) - 1)) << (_index)); \ + } while (0) + +/** + * A packed array is an array where each entry in the array is less than + * or equal to 16 bits, and the entries are stuffed into an A_UINT32 array. + * For example, if each entry in the array is 11 bits, then you can stuff + * an array of 4 11-bit values into an array of 2 A_UINT32 values. + * The first 2 11-bit values will be stored in the first A_UINT32, + * and the last 2 11-bit values will be stored in the second A_UINT32. + */ +#define WMI_PACKED_ARR_SIZE(num_entries,bits_per_entry) \ + (((num_entries) / (32 / (bits_per_entry))) + \ + (((num_entries) % (32 / (bits_per_entry))) ? 1 : 0)) + +#define WMI_RETURN_STRING(str) case ((str)): return (uint8_t *)(# str); + +static INLINE A_UINT32 wmi_packed_arr_get_bits(A_UINT32 *arr, + A_UINT32 entry_index, A_UINT32 bits_per_entry) +{ + A_UINT32 entries_per_uint = (32 / bits_per_entry); + A_UINT32 uint_index = (entry_index / entries_per_uint); + A_UINT32 num_entries_in_prev_uints = (uint_index * entries_per_uint); + A_UINT32 index_in_uint = (entry_index - num_entries_in_prev_uints); + A_UINT32 start_bit_in_uint = (index_in_uint * bits_per_entry); + return (arr[uint_index] >> start_bit_in_uint) & + ((1 << bits_per_entry) - 1); +} + +static INLINE void wmi_packed_arr_set_bits(A_UINT32 *arr, A_UINT32 entry_index, + A_UINT32 bits_per_entry, A_UINT32 val) +{ + A_UINT32 entries_per_uint = (32 / bits_per_entry); + A_UINT32 uint_index = (entry_index / entries_per_uint); + A_UINT32 num_entries_in_prev_uints = (uint_index * entries_per_uint); + A_UINT32 index_in_uint = (entry_index - num_entries_in_prev_uints); + A_UINT32 start_bit_in_uint = (index_in_uint * bits_per_entry); + + arr[uint_index] &= ~(((1 << bits_per_entry) - 1) << start_bit_in_uint); + arr[uint_index] |= + ((val & ((1 << bits_per_entry) - 1)) << start_bit_in_uint); +} + +/** 2 word representation of MAC addr */ +typedef struct { + /** upper 4 bytes of MAC address */ + A_UINT32 mac_addr31to0; + /** lower 2 bytes of MAC address */ + A_UINT32 mac_addr47to32; +} wmi_mac_addr; + +/** macro to convert MAC address from WMI word format to char array */ +#define WMI_MAC_ADDR_TO_CHAR_ARRAY(pwmi_mac_addr,c_macaddr) do { \ + (c_macaddr)[0] = (((pwmi_mac_addr)->mac_addr31to0) >> 0) & 0xff; \ + (c_macaddr)[1] = (((pwmi_mac_addr)->mac_addr31to0) >> 8) & 0xff; \ + (c_macaddr)[2] = (((pwmi_mac_addr)->mac_addr31to0) >> 16) & 0xff; \ + (c_macaddr)[3] = (((pwmi_mac_addr)->mac_addr31to0) >> 24) & 0xff; \ + (c_macaddr)[4] = (((pwmi_mac_addr)->mac_addr47to32) >> 0) & 0xff; \ + (c_macaddr)[5] = (((pwmi_mac_addr)->mac_addr47to32) >> 8) & 0xff; \ + } while (0) + +/** macro to convert MAC address from char array to WMI word format */ +#define WMI_CHAR_ARRAY_TO_MAC_ADDR(c_macaddr,pwmi_mac_addr) do { \ + (pwmi_mac_addr)->mac_addr31to0 = \ + (((c_macaddr)[0] << 0) | \ + ((c_macaddr)[1] << 8) | \ + ((c_macaddr)[2] << 16) | \ + ((c_macaddr)[3] << 24)); \ + (pwmi_mac_addr)->mac_addr47to32 = ((c_macaddr)[4] | ((c_macaddr)[5] << 8));\ + } while (0) + +/* + * wmi command groups. + */ +typedef enum { + /* 0 to 2 are reserved */ + WMI_GRP_START = 0x3, + WMI_GRP_SCAN = WMI_GRP_START, /* 0x3 */ + WMI_GRP_PDEV, /* 0x4 */ + WMI_GRP_VDEV, /* 0x5 */ + WMI_GRP_PEER, /* 0x6 */ + WMI_GRP_MGMT, /* 0x7 */ + WMI_GRP_BA_NEG, /* 0x8 */ + WMI_GRP_STA_PS, /* 0x9 */ + WMI_GRP_DFS, /* 0xa */ + WMI_GRP_ROAM, /* 0xb */ + WMI_GRP_OFL_SCAN, /* 0xc */ + WMI_GRP_P2P, /* 0xd */ + WMI_GRP_AP_PS, /* 0xe */ + WMI_GRP_RATE_CTRL, /* 0xf */ + WMI_GRP_PROFILE, /* 0x10 */ + WMI_GRP_SUSPEND, /* 0x11 */ + WMI_GRP_BCN_FILTER, /* 0x12 */ + WMI_GRP_WOW, /* 0x13 */ + WMI_GRP_RTT, /* 0x14 */ + WMI_GRP_SPECTRAL, /* 0x15 */ + WMI_GRP_STATS, /* 0x16 */ + WMI_GRP_ARP_NS_OFL, /* 0x17 */ + WMI_GRP_NLO_OFL, /* 0x18 */ + WMI_GRP_GTK_OFL, /* 0x19 */ + WMI_GRP_CSA_OFL, /* 0x1a */ + WMI_GRP_CHATTER, /* 0x1b */ + WMI_GRP_TID_ADDBA, /* 0x1c */ + WMI_GRP_MISC, /* 0x1d */ + WMI_GRP_GPIO, /* 0x1e */ + WMI_GRP_FWTEST, /* 0x1f */ + WMI_GRP_TDLS, /* 0x20 */ + WMI_GRP_RESMGR, /* 0x21 */ + WMI_GRP_STA_SMPS, /* 0x22 */ + WMI_GRP_WLAN_HB, /* 0x23 */ + WMI_GRP_RMC, /* 0x24 */ + WMI_GRP_MHF_OFL, /* 0x25 */ + WMI_GRP_LOCATION_SCAN, /* 0x26 */ + WMI_GRP_OEM, /* 0x27 */ + WMI_GRP_NAN, /* 0x28 */ + WMI_GRP_COEX, /* 0x29 */ + WMI_GRP_OBSS_OFL, /* 0x2a */ + WMI_GRP_LPI, /* 0x2b */ + WMI_GRP_EXTSCAN, /* 0x2c */ + WMI_GRP_DHCP_OFL, /* 0x2d */ + WMI_GRP_IPA, /* 0x2e */ + WMI_GRP_MDNS_OFL, /* 0x2f */ + WMI_GRP_SAP_OFL, /* 0x30 */ + WMI_GRP_OCB, /* 0x31 */ + WMI_GRP_SOC, /* 0x32 */ + WMI_GRP_PKT_FILTER, /* 0x33 */ + WMI_GRP_MAWC, /* 0x34 */ + WMI_GRP_PMF_OFFLOAD, /* 0x35 */ + WMI_GRP_BPF_OFFLOAD, /* 0x36 Berkeley Packet Filter */ + WMI_GRP_NAN_DATA, /* 0x37 */ + WMI_GRP_PROTOTYPE, /* 0x38 */ + WMI_GRP_MONITOR, /* 0x39 */ + WMI_GRP_REGULATORY, /* 0x3a */ + WMI_GRP_HW_DATA_FILTER, /* 0x3b */ +} WMI_GRP_ID; + +#define WMI_CMD_GRP_START_ID(grp_id) (((grp_id) << 12) | 0x1) +#define WMI_EVT_GRP_START_ID(grp_id) (((grp_id) << 12) | 0x1) + +/** + * Command IDs and commange events + */ +typedef enum { + /** initialize the wlan sub system */ + WMI_INIT_CMDID = 0x1, + + /* Scan specific commands */ + + /** start scan request to FW */ + WMI_START_SCAN_CMDID = WMI_CMD_GRP_START_ID(WMI_GRP_SCAN), + /** stop scan request to FW */ + WMI_STOP_SCAN_CMDID, + /** full list of channels as defined by the regulatory that will be used by scanner */ + WMI_SCAN_CHAN_LIST_CMDID, + /** overwrite default priority table in scan scheduler */ + WMI_SCAN_SCH_PRIO_TBL_CMDID, + /** This command to adjust the priority and min.max_rest_time + * of an on ongoing scan request. + */ + WMI_SCAN_UPDATE_REQUEST_CMDID, + + /** set OUI to be used in probe request if enabled */ + WMI_SCAN_PROB_REQ_OUI_CMDID, + /** config adaptive dwell scan */ + WMI_SCAN_ADAPTIVE_DWELL_CONFIG_CMDID, + /** Only applicable to DBS capable product */ + WMI_SET_SCAN_DBS_DUTY_CYCLE_CMDID, + + /* PDEV(physical device) specific commands */ + /** set regulatorty ctl id used by FW to determine the exact ctl power limits */ + WMI_PDEV_SET_REGDOMAIN_CMDID = WMI_CMD_GRP_START_ID(WMI_GRP_PDEV), + /** set channel. mainly used for supporting monitor mode */ + WMI_PDEV_SET_CHANNEL_CMDID, + /** set pdev specific parameters */ + WMI_PDEV_SET_PARAM_CMDID, + /** enable packet log */ + WMI_PDEV_PKTLOG_ENABLE_CMDID, + /** disable packet log*/ + WMI_PDEV_PKTLOG_DISABLE_CMDID, + /** set wmm parameters */ + WMI_PDEV_SET_WMM_PARAMS_CMDID, + /** set HT cap ie that needs to be carried probe requests HT/VHT channels */ + WMI_PDEV_SET_HT_CAP_IE_CMDID, + /** set VHT cap ie that needs to be carried on probe requests on VHT channels */ + WMI_PDEV_SET_VHT_CAP_IE_CMDID, + + /** Command to send the DSCP-to-TID map to the target */ + WMI_PDEV_SET_DSCP_TID_MAP_CMDID, + /** set quiet ie parameters. primarily used in AP mode */ + WMI_PDEV_SET_QUIET_MODE_CMDID, + /** Enable/Disable Green AP Power Save */ + WMI_PDEV_GREEN_AP_PS_ENABLE_CMDID, + /** get TPC config for the current operating channel */ + WMI_PDEV_GET_TPC_CONFIG_CMDID, + + /** set the base MAC address for the physical device before a VDEV is created. + * For firmware that doesn't support this feature and this command, the pdev + * MAC address will not be changed. */ + WMI_PDEV_SET_BASE_MACADDR_CMDID, + + /* eeprom content dump , the same to bdboard data */ + WMI_PDEV_DUMP_CMDID, + /* set LED configuration */ + WMI_PDEV_SET_LED_CONFIG_CMDID, + /* Get Current temprature of chip in Celcius degree*/ + WMI_PDEV_GET_TEMPERATURE_CMDID, + /* Set LED flashing behavior */ + WMI_PDEV_SET_LED_FLASHING_CMDID, + /** Enable/Disable Smart Antenna */ + WMI_PDEV_SMART_ANT_ENABLE_CMDID, + /** Set Smart Antenna RX antenna*/ + WMI_PDEV_SMART_ANT_SET_RX_ANTENNA_CMDID, + /** Override the antenna switch table */ + WMI_PDEV_SET_ANTENNA_SWITCH_TABLE_CMDID, + /** Override the CTL table */ + WMI_PDEV_SET_CTL_TABLE_CMDID, + /** Override the array gain table */ + WMI_PDEV_SET_MIMOGAIN_TABLE_CMDID, + /** FIPS test mode command */ + WMI_PDEV_FIPS_CMDID, + /** get CCK ANI level */ + WMI_PDEV_GET_ANI_CCK_CONFIG_CMDID, + /** get OFDM ANI level */ + WMI_PDEV_GET_ANI_OFDM_CONFIG_CMDID, + /** NF Cal Power dBr/dBm */ + WMI_PDEV_GET_NFCAL_POWER_CMDID, + /** TxPPDU TPC */ + WMI_PDEV_GET_TPC_CMDID, + /** Set to enable MIB stats collection */ + WMI_MIB_STATS_ENABLE_CMDID, + /** Set preferred channel list for DBS Mgr */ + WMI_PDEV_SET_PCL_CMDID, + /** Set HW mode. Eg: single MAC, DBS & SBS, see soc_hw_mode_t for values */ + WMI_PDEV_SET_HW_MODE_CMDID, + /** Set DFS, SCAN modes and other FW configurations */ + WMI_PDEV_SET_MAC_CONFIG_CMDID, + /** Set per band and per pdev antenna chains */ + WMI_PDEV_SET_ANTENNA_MODE_CMDID, + /** Periodic channel stats request command */ + WMI_SET_PERIODIC_CHANNEL_STATS_CONFIG_CMDID, + /** WMI command for power debug framework */ + WMI_PDEV_WAL_POWER_DEBUG_CMDID, + /** set per-AC rx reorder timeouts */ + WMI_PDEV_SET_REORDER_TIMEOUT_VAL_CMDID, + /** WMI command for WOW gpio and type */ + WMI_PDEV_SET_WAKEUP_CONFIG_CMDID, + /* Get current ANT's per chain's RSSI info */ + WMI_PDEV_GET_ANTDIV_STATUS_CMDID, + /** WMI command for getting Chip Power Stats */ + WMI_PDEV_GET_CHIP_POWER_STATS_CMDID, + /** set stats reporting thresholds - see WMI_REPORT_STATS_EVENTID */ + WMI_PDEV_SET_STATS_THRESHOLD_CMDID, + /** vdev restart request for multiple vdevs */ + WMI_PDEV_MULTIPLE_VDEV_RESTART_REQUEST_CMDID, + /** Pdev update packet routing command */ + WMI_PDEV_UPDATE_PKT_ROUTING_CMDID, + /** Get Calibration data version details */ + WMI_PDEV_CHECK_CAL_VERSION_CMDID, + /** Set Diversity Gain */ + WMI_PDEV_SET_DIVERSITY_GAIN_CMDID, + /** Get chain RSSI and antena index command */ + WMI_PDEV_DIV_GET_RSSI_ANTID_CMDID, + /* get bss chan info */ + WMI_PDEV_BSS_CHAN_INFO_REQUEST_CMDID, + /* update pmk cache info */ + WMI_PDEV_UPDATE_PMK_CACHE_CMDID, + /* update fils HLP */ + WMI_PDEV_UPDATE_FILS_HLP_PKT_CMDID, + + /* VDEV (virtual device) specific commands */ + /** vdev create */ + WMI_VDEV_CREATE_CMDID = WMI_CMD_GRP_START_ID(WMI_GRP_VDEV), + /** vdev delete */ + WMI_VDEV_DELETE_CMDID, + /** vdev start request */ + WMI_VDEV_START_REQUEST_CMDID, + /** vdev restart request (RX only, NO TX, used for CAC period)*/ + WMI_VDEV_RESTART_REQUEST_CMDID, + /** vdev up request */ + WMI_VDEV_UP_CMDID, + /** vdev stop request */ + WMI_VDEV_STOP_CMDID, + /** vdev down request */ + WMI_VDEV_DOWN_CMDID, + /* set a vdev param */ + WMI_VDEV_SET_PARAM_CMDID, + /* set a key (used for setting per peer unicast and per vdev multicast) */ + WMI_VDEV_INSTALL_KEY_CMDID, + + /* wnm sleep mode command */ + WMI_VDEV_WNM_SLEEPMODE_CMDID, + WMI_VDEV_WMM_ADDTS_CMDID, + WMI_VDEV_WMM_DELTS_CMDID, + WMI_VDEV_SET_WMM_PARAMS_CMDID, + WMI_VDEV_SET_GTX_PARAMS_CMDID, + WMI_VDEV_IPSEC_NATKEEPALIVE_FILTER_CMDID, + + WMI_VDEV_PLMREQ_START_CMDID, + WMI_VDEV_PLMREQ_STOP_CMDID, + /* TSF timestamp action for specified vdev */ + WMI_VDEV_TSF_TSTAMP_ACTION_CMDID, + /** set the additional IEs in probe requests for scan or + * assoc req etc for frames FW locally generates */ + WMI_VDEV_SET_IE_CMDID, + + WMI_VDEV_RATEMASK_CMDID, + /** ATF VDEV REQUEST commands. */ + WMI_VDEV_ATF_REQUEST_CMDID, + /** Command to send the DSCP-to-TID map to the target for VAP */ + WMI_VDEV_SET_DSCP_TID_MAP_CMDID, + /* Configure filter for Neighbor Rx Pkt (smart mesh selective listening) */ + WMI_VDEV_FILTER_NEIGHBOR_RX_PACKETS_CMDID, + /** set quiet ie parameters. primarily used in AP mode */ + WMI_VDEV_SET_QUIET_MODE_CMDID, + /** To set custom aggregation size for per vdev */ + WMI_VDEV_SET_CUSTOM_AGGR_SIZE_CMDID, + + /* DISA feature: Encrypt-decrypt data request */ + WMI_VDEV_ENCRYPT_DECRYPT_DATA_REQ_CMDID, + + /** Command to enable mac randomizaton **/ + WMI_VDEV_ADD_MAC_ADDR_TO_RX_FILTER_CMDID, + + /** WMI commands related to dbg arp stats */ + WMI_VDEV_SET_ARP_STAT_CMDID, + WMI_VDEV_GET_ARP_STAT_CMDID, + + /** get tx power for the current vdev */ + WMI_VDEV_GET_TX_POWER_CMDID, + /* limit STA offchannel activity */ + WMI_VDEV_LIMIT_OFFCHAN_CMDID, + + /* peer specific commands */ + + /** create a peer */ + WMI_PEER_CREATE_CMDID = WMI_CMD_GRP_START_ID(WMI_GRP_PEER), + /** delete a peer */ + WMI_PEER_DELETE_CMDID, + /** flush specific tid queues of a peer */ + WMI_PEER_FLUSH_TIDS_CMDID, + /** set a parameter of a peer */ + WMI_PEER_SET_PARAM_CMDID, + /** set peer to associated state. will cary all parameters determined during assocication time */ + WMI_PEER_ASSOC_CMDID, + /**add a wds (4 address) entry. used only for testing WDS feature on AP products */ + WMI_PEER_ADD_WDS_ENTRY_CMDID, + /**remove wds (4 address) entry. used only for testing WDS feature on AP products */ + WMI_PEER_REMOVE_WDS_ENTRY_CMDID, + /** set up mcast group infor for multicast to unicast conversion */ + WMI_PEER_MCAST_GROUP_CMDID, + /** request peer info from FW. FW shall respond with PEER_INFO_EVENTID */ + WMI_PEER_INFO_REQ_CMDID, + /** request the estimated link speed for the peer. FW shall respond with + * WMI_PEER_ESTIMATED_LINKSPEED_EVENTID. + */ + WMI_PEER_GET_ESTIMATED_LINKSPEED_CMDID, + /** Set the conditions to report peer justified rate to driver + * The justified rate means the the user-rate is justified by PER. + */ + WMI_PEER_SET_RATE_REPORT_CONDITION_CMDID, + + /** update a wds (4 address) entry */ + WMI_PEER_UPDATE_WDS_ENTRY_CMDID, + /** add a proxy sta entry */ + WMI_PEER_ADD_PROXY_STA_ENTRY_CMDID, + /** Set Smart Antenna TX antenna */ + WMI_PEER_SMART_ANT_SET_TX_ANTENNA_CMDID, + /** Set Smart Antenna TX train info */ + WMI_PEER_SMART_ANT_SET_TRAIN_INFO_CMDID, + /** Set SA node config options */ + WMI_PEER_SMART_ANT_SET_NODE_CONFIG_OPS_CMDID, + /** ATF PEER REQUEST commands */ + WMI_PEER_ATF_REQUEST_CMDID, + /** bandwidth fairness (BWF) peer configuration request command */ + WMI_PEER_BWF_REQUEST_CMDID, + /** rx reorder queue setup for peer/tid */ + WMI_PEER_REORDER_QUEUE_SETUP_CMDID, + /** rx reorder queue remove for peer/tid */ + WMI_PEER_REORDER_QUEUE_REMOVE_CMDID, + /** specify a limit for rx A-MPDU block size */ + WMI_PEER_SET_RX_BLOCKSIZE_CMDID, + /** request peer antdiv info from FW. FW shall respond with PEER_ANTDIV_INFO_EVENTID */ + WMI_PEER_ANTDIV_INFO_REQ_CMDID, + /** Peer operating mode change indication sent to host to update stats */ + WMI_PEER_OPER_MODE_CHANGE_EVENTID, + + /* beacon/management specific commands */ + + /** transmit beacon by reference . used for transmitting beacon on low latency interface like pcie */ + WMI_BCN_TX_CMDID = WMI_CMD_GRP_START_ID(WMI_GRP_MGMT), + /** transmit beacon by value */ + WMI_PDEV_SEND_BCN_CMDID, + /** set the beacon template. used in beacon offload mode to setup the + * the common beacon template with the FW to be used by FW to generate beacons */ + WMI_BCN_TMPL_CMDID, + /** set beacon filter with FW */ + WMI_BCN_FILTER_RX_CMDID, + /* enable/disable filtering of probe requests in the firmware */ + WMI_PRB_REQ_FILTER_RX_CMDID, + /** transmit management frame by value. will be deprecated */ + WMI_MGMT_TX_CMDID, + /** set the probe response template. used in beacon offload mode to setup the + * the common probe response template with the FW to be used by FW to generate + * probe responses */ + WMI_PRB_TMPL_CMDID, + /** Transmit Mgmt frame by reference */ + WMI_MGMT_TX_SEND_CMDID, + /** Transmit data frame by reference */ + WMI_OFFCHAN_DATA_TX_SEND_CMDID, + + /** commands to directly control ba negotiation directly from host. only used in test mode */ + + /** turn off FW Auto addba mode and let host control addba */ + WMI_ADDBA_CLEAR_RESP_CMDID = WMI_CMD_GRP_START_ID(WMI_GRP_BA_NEG), + /** send add ba request */ + WMI_ADDBA_SEND_CMDID, + WMI_ADDBA_STATUS_CMDID, + /** send del ba */ + WMI_DELBA_SEND_CMDID, + /** set add ba response will be used by FW to generate addba response*/ + WMI_ADDBA_SET_RESP_CMDID, + /** send single VHT MPDU with AMSDU */ + WMI_SEND_SINGLEAMSDU_CMDID, + + /** Station power save specific config */ + /** enable/disable station powersave */ + WMI_STA_POWERSAVE_MODE_CMDID = WMI_CMD_GRP_START_ID(WMI_GRP_STA_PS), + /** set station power save specific parameter */ + WMI_STA_POWERSAVE_PARAM_CMDID, + /** set station mimo powersave mode */ + WMI_STA_MIMO_PS_MODE_CMDID, + + + /** DFS-specific commands */ + /** enable DFS (radar detection)*/ + WMI_PDEV_DFS_ENABLE_CMDID = WMI_CMD_GRP_START_ID(WMI_GRP_DFS), + /** disable DFS (radar detection)*/ + WMI_PDEV_DFS_DISABLE_CMDID, + /** enable DFS phyerr/parse filter offload */ + WMI_DFS_PHYERR_FILTER_ENA_CMDID, + /** enable DFS phyerr/parse filter offload */ + WMI_DFS_PHYERR_FILTER_DIS_CMDID, + /** enable DFS phyerr processing offload */ + WMI_PDEV_DFS_PHYERR_OFFLOAD_ENABLE_CMDID, + /** disable DFS phyerr processing offload */ + WMI_PDEV_DFS_PHYERR_OFFLOAD_DISABLE_CMDID, + /** set ADFS channel config */ + WMI_VDEV_ADFS_CH_CFG_CMDID, + /** abort ADFS off-channel-availability-check currently in progress */ + WMI_VDEV_ADFS_OCAC_ABORT_CMDID, + + /* Roaming specific commands */ + /** set roam scan mode */ + WMI_ROAM_SCAN_MODE = WMI_CMD_GRP_START_ID(WMI_GRP_ROAM), + /** set roam scan rssi threshold below which roam scan is enabled */ + WMI_ROAM_SCAN_RSSI_THRESHOLD, + /** set roam scan period for periodic roam scan mode */ + WMI_ROAM_SCAN_PERIOD, + /** set roam scan trigger rssi change threshold */ + WMI_ROAM_SCAN_RSSI_CHANGE_THRESHOLD, + /** set roam AP profile */ + WMI_ROAM_AP_PROFILE, + /** set channel list for roam scans */ + WMI_ROAM_CHAN_LIST, + /** Stop scan command */ + WMI_ROAM_SCAN_CMD, + /** roaming sme offload sync complete */ + WMI_ROAM_SYNCH_COMPLETE, + /** set ric request element for 11r roaming */ + WMI_ROAM_SET_RIC_REQUEST_CMDID, + /** Invoke roaming forcefully */ + WMI_ROAM_INVOKE_CMDID, + /** roaming filter cmd to allow further filtering of roaming candidate */ + WMI_ROAM_FILTER_CMDID, + /** set gateway ip, mac and retries for subnet change detection */ + WMI_ROAM_SUBNET_CHANGE_CONFIG_CMDID, + /** configure thresholds for MAWC */ + WMI_ROAM_CONFIGURE_MAWC_CMDID, + /** configure MultiBand Operation(refer WFA MBO spec) parameter */ + WMI_ROAM_SET_MBO_PARAM_CMDID, /* DEPRECATED */ + /** configure packet error rate threshold for triggering roaming */ + WMI_ROAM_PER_CONFIG_CMDID, + + /** offload scan specific commands */ + /** set offload scan AP profile */ + WMI_OFL_SCAN_ADD_AP_PROFILE = WMI_CMD_GRP_START_ID(WMI_GRP_OFL_SCAN), + /** remove offload scan AP profile */ + WMI_OFL_SCAN_REMOVE_AP_PROFILE, + /** set offload scan period */ + WMI_OFL_SCAN_PERIOD, + + /* P2P specific commands */ + /**set P2P device info. FW will used by FW to create P2P IE to be carried in probe response + * generated during p2p listen and for p2p discoverability */ + WMI_P2P_DEV_SET_DEVICE_INFO = WMI_CMD_GRP_START_ID(WMI_GRP_P2P), + /** enable/disable p2p discoverability on STA/AP VDEVs */ + WMI_P2P_DEV_SET_DISCOVERABILITY, + /** set p2p ie to be carried in beacons generated by FW for GO */ + WMI_P2P_GO_SET_BEACON_IE, + /** set p2p ie to be carried in probe response frames generated by FW for GO */ + WMI_P2P_GO_SET_PROBE_RESP_IE, + /** set the vendor specific p2p ie data. FW will use this to parse the P2P NoA + * attribute in the beacons/probe responses received. + * Note: This command is currently used only for Apple P2P implementation. + */ + WMI_P2P_SET_VENDOR_IE_DATA_CMDID, + /** set the configure of p2p find offload */ + WMI_P2P_DISC_OFFLOAD_CONFIG_CMDID, + /** set the vendor specific p2p ie data for p2p find offload using */ + WMI_P2P_DISC_OFFLOAD_APPIE_CMDID, + /** set the BSSID/device name pattern of p2p find offload */ + WMI_P2P_DISC_OFFLOAD_PATTERN_CMDID, + /** set OppPS related parameters **/ + WMI_P2P_SET_OPPPS_PARAM_CMDID, + /** set listen offload start related parameters */ + WMI_P2P_LISTEN_OFFLOAD_START_CMDID, + /** set listen offload stop related parameters */ + WMI_P2P_LISTEN_OFFLOAD_STOP_CMDID, + + /** AP power save specific config */ + /** set AP power save specific param */ + WMI_AP_PS_PEER_PARAM_CMDID = WMI_CMD_GRP_START_ID(WMI_GRP_AP_PS), + /** set AP UAPSD coex pecific param */ + WMI_AP_PS_PEER_UAPSD_COEX_CMDID, + /** set Enhanced Green AP param */ + WMI_AP_PS_EGAP_PARAM_CMDID, + + /** Rate-control specific commands */ + WMI_PEER_RATE_RETRY_SCHED_CMDID = WMI_CMD_GRP_START_ID(WMI_GRP_RATE_CTRL), + + /** WLAN Profiling commands. */ + WMI_WLAN_PROFILE_TRIGGER_CMDID = WMI_CMD_GRP_START_ID(WMI_GRP_PROFILE), + WMI_WLAN_PROFILE_SET_HIST_INTVL_CMDID, + WMI_WLAN_PROFILE_GET_PROFILE_DATA_CMDID, + WMI_WLAN_PROFILE_ENABLE_PROFILE_ID_CMDID, + WMI_WLAN_PROFILE_LIST_PROFILE_ID_CMDID, + + /** Suspend resume command Ids */ + WMI_PDEV_SUSPEND_CMDID = WMI_CMD_GRP_START_ID(WMI_GRP_SUSPEND), + WMI_PDEV_RESUME_CMDID, + + /* Beacon filter commands */ + /** add a beacon filter */ + WMI_ADD_BCN_FILTER_CMDID = WMI_CMD_GRP_START_ID(WMI_GRP_BCN_FILTER), + /** remove a beacon filter */ + WMI_RMV_BCN_FILTER_CMDID, + + /* WOW Specific WMI commands*/ + /** add pattern for awake */ + WMI_WOW_ADD_WAKE_PATTERN_CMDID = WMI_CMD_GRP_START_ID(WMI_GRP_WOW), + /** deleta a wake pattern */ + WMI_WOW_DEL_WAKE_PATTERN_CMDID, + /** enable/deisable wake event */ + WMI_WOW_ENABLE_DISABLE_WAKE_EVENT_CMDID, + /** enable WOW */ + WMI_WOW_ENABLE_CMDID, + /** host woke up from sleep event to FW. Generated in response to WOW Hardware event */ + WMI_WOW_HOSTWAKEUP_FROM_SLEEP_CMDID, + /* IOAC add keep alive cmd. */ + WMI_WOW_IOAC_ADD_KEEPALIVE_CMDID, + /* IOAC del keep alive cmd. */ + WMI_WOW_IOAC_DEL_KEEPALIVE_CMDID, + /* IOAC add pattern for awake */ + WMI_WOW_IOAC_ADD_WAKE_PATTERN_CMDID, + /* IOAC deleta a wake pattern */ + WMI_WOW_IOAC_DEL_WAKE_PATTERN_CMDID, + /* D0-WOW enable or disable cmd */ + WMI_D0_WOW_ENABLE_DISABLE_CMDID, + /* enable extend WoW */ + WMI_EXTWOW_ENABLE_CMDID, + /* Extend WoW command to configure app type1 parameter */ + WMI_EXTWOW_SET_APP_TYPE1_PARAMS_CMDID, + /* Extend WoW command to configure app type2 parameter */ + WMI_EXTWOW_SET_APP_TYPE2_PARAMS_CMDID, + /* enable ICMPv6 Network advertisement filtering */ + WMI_WOW_ENABLE_ICMPV6_NA_FLT_CMDID, + /* + * Set a pattern to match UDP packet in WOW mode. + * If match, construct a tx frame in a local buffer + * to send through the peer AP to the entity in the + * IP network that sent the UDP packet to this STA. + */ + WMI_WOW_UDP_SVC_OFLD_CMDID, + /* configure WOW host wakeup PIN pattern */ + WMI_WOW_HOSTWAKEUP_GPIO_PIN_PATTERN_CONFIG_CMDID, + + /* Set which action category should wake the host from suspend */ + WMI_WOW_SET_ACTION_WAKE_UP_CMDID, + + /* RTT measurement related cmd */ + /** request to make an RTT measurement */ + WMI_RTT_MEASREQ_CMDID = WMI_CMD_GRP_START_ID(WMI_GRP_RTT), + /** request to report a tsf measurement */ + WMI_RTT_TSF_CMDID, + + /** spectral scan command */ + /** configure spectral scan */ + WMI_VDEV_SPECTRAL_SCAN_CONFIGURE_CMDID = WMI_CMD_GRP_START_ID(WMI_GRP_SPECTRAL), + /** enable/disable spectral scan and trigger */ + WMI_VDEV_SPECTRAL_SCAN_ENABLE_CMDID, + + /* F/W stats */ + /** one time request for stats */ + WMI_REQUEST_STATS_CMDID = WMI_CMD_GRP_START_ID(WMI_GRP_STATS), + /** Push MCC Adaptive Scheduler Stats to Firmware */ + WMI_MCC_SCHED_TRAFFIC_STATS_CMDID, + /** one time request for txrx stats */ + WMI_REQUEST_STATS_EXT_CMDID, + /* Link Layer stats */ + /** Request for link layer stats */ + WMI_REQUEST_LINK_STATS_CMDID, + /** Request for setting params to link layer stats */ + WMI_START_LINK_STATS_CMDID, + /** Request to clear stats*/ + WMI_CLEAR_LINK_STATS_CMDID, + + /** Request for getting the Firmware Memory Dump */ + WMI_GET_FW_MEM_DUMP_CMDID, + + /** Request to flush of the buffered debug messages */ + WMI_DEBUG_MESG_FLUSH_CMDID, + + /** Cmd to configure the verbose level */ + WMI_DIAG_EVENT_LOG_CONFIG_CMDID, + + /** One time request for wlan stats */ + WMI_REQUEST_WLAN_STATS_CMDID, + + /** Request for getting RCPI of peer */ + WMI_REQUEST_RCPI_CMDID, + + /** One time request for peer stats info */ + WMI_REQUEST_PEER_STATS_INFO_CMDID, + + /** One time request for radio channel stats */ + WMI_REQUEST_RADIO_CHAN_STATS_CMDID, + + /** ARP OFFLOAD REQUEST*/ + WMI_SET_ARP_NS_OFFLOAD_CMDID = WMI_CMD_GRP_START_ID(WMI_GRP_ARP_NS_OFL), + + /** Proactive ARP Response Add Pattern Command*/ + WMI_ADD_PROACTIVE_ARP_RSP_PATTERN_CMDID, + + /** Proactive ARP Response Del Pattern Command*/ + WMI_DEL_PROACTIVE_ARP_RSP_PATTERN_CMDID, + + /** NS offload confid*/ + WMI_NETWORK_LIST_OFFLOAD_CONFIG_CMDID = WMI_CMD_GRP_START_ID(WMI_GRP_NLO_OFL), + + /** APFIND Config */ + WMI_APFIND_CMDID, + + /** Passpoint list config */ + WMI_PASSPOINT_LIST_CONFIG_CMDID, + + /** configure supprssing parameters for MAWC */ + WMI_NLO_CONFIGURE_MAWC_CMDID, + + /* GTK offload Specific WMI commands*/ + WMI_GTK_OFFLOAD_CMDID = WMI_CMD_GRP_START_ID(WMI_GRP_GTK_OFL), + + /* CSA offload Specific WMI commands*/ + /** csa offload enable */ + WMI_CSA_OFFLOAD_ENABLE_CMDID = WMI_CMD_GRP_START_ID(WMI_GRP_CSA_OFL), + /** chan switch command */ + WMI_CSA_OFFLOAD_CHANSWITCH_CMDID, + + /* Chatter commands*/ + /* Change chatter mode of operation */ + WMI_CHATTER_SET_MODE_CMDID = WMI_CMD_GRP_START_ID(WMI_GRP_CHATTER), + /** chatter add coalescing filter command */ + WMI_CHATTER_ADD_COALESCING_FILTER_CMDID, + /** chatter delete coalescing filter command */ + WMI_CHATTER_DELETE_COALESCING_FILTER_CMDID, + /** chatter coalecing query command */ + WMI_CHATTER_COALESCING_QUERY_CMDID, + + /**addba specific commands */ + /** start the aggregation on this TID */ + WMI_PEER_TID_ADDBA_CMDID = WMI_CMD_GRP_START_ID(WMI_GRP_TID_ADDBA), + /** stop the aggregation on this TID */ + WMI_PEER_TID_DELBA_CMDID, + + /** set station mimo powersave method */ + WMI_STA_DTIM_PS_METHOD_CMDID, + /** Configure the Station UAPSD AC Auto Trigger Parameters */ + WMI_STA_UAPSD_AUTO_TRIG_CMDID, + /** Configure the Keep Alive Parameters */ + WMI_STA_KEEPALIVE_CMDID, + + /* Request ssn from target for a sta/tid pair */ + WMI_BA_REQ_SSN_CMDID, + + + /* misc command group */ + /** echo command mainly used for testing */ + WMI_ECHO_CMDID = WMI_CMD_GRP_START_ID(WMI_GRP_MISC), + + /* !!IMPORTANT!! + * If you need to add a new WMI command to the WMI_GRP_MISC sub-group, + * please make sure you add it BEHIND WMI_PDEV_UTF_CMDID, + * as we MUST have a fixed value here to maintain compatibility between + * UTF and the ART2 driver + */ + /** UTF WMI commands */ + WMI_PDEV_UTF_CMDID, + + /** set debug log config */ + WMI_DBGLOG_CFG_CMDID, + /* QVIT specific command id */ + WMI_PDEV_QVIT_CMDID, + /* Factory Testing Mode request command + * used for integrated chipsets */ + WMI_PDEV_FTM_INTG_CMDID, + /* set and get keepalive parameters command */ + WMI_VDEV_SET_KEEPALIVE_CMDID, + WMI_VDEV_GET_KEEPALIVE_CMDID, + /* For fw recovery test command */ + WMI_FORCE_FW_HANG_CMDID, + /* Set Mcast/Bdcast filter */ + WMI_SET_MCASTBCAST_FILTER_CMDID, + /** set thermal management params **/ + WMI_THERMAL_MGMT_CMDID, + /** set host auto shutdown params **/ + WMI_HOST_AUTO_SHUTDOWN_CFG_CMDID, + /** set tpc chainmask config command */ + WMI_TPC_CHAINMASK_CONFIG_CMDID, + /** set Antenna diversity command */ + WMI_SET_ANTENNA_DIVERSITY_CMDID, + /** Set OCB Sched Request, deprecated */ + WMI_OCB_SET_SCHED_CMDID, + /** Set rssi monitoring config command */ + WMI_RSSI_BREACH_MONITOR_CONFIG_CMDID, + /** Enable/disable Large Receive Offload processing; provide cfg params */ + WMI_LRO_CONFIG_CMDID, + /** transfer data from host to firmware to write flash */ + WMI_TRANSFER_DATA_TO_FLASH_CMDID, + /** Command to enable/disable filtering of multicast IP with unicast mac */ + WMI_CONFIG_ENHANCED_MCAST_FILTER_CMDID, + /** Command to control WISA mode */ + WMI_VDEV_WISA_CMDID, + /** set debug log time stamp sync up with host */ + WMI_DBGLOG_TIME_STAMP_SYNC_CMDID, + /** Command for host to set/delete multiple mcast filters */ + WMI_SET_MULTIPLE_MCAST_FILTER_CMDID, + /** upload a requested section of data from firmware flash to host */ + WMI_READ_DATA_FROM_FLASH_CMDID, + /* Thermal Throttling SET CONF commands */ + WMI_THERM_THROT_SET_CONF_CMDID, + + /* GPIO Configuration */ + WMI_GPIO_CONFIG_CMDID = WMI_CMD_GRP_START_ID(WMI_GRP_GPIO), + WMI_GPIO_OUTPUT_CMDID, + + /* Txbf configuration command */ + WMI_TXBF_CMDID, + + /* FWTEST Commands */ + WMI_FWTEST_VDEV_MCC_SET_TBTT_MODE_CMDID = WMI_CMD_GRP_START_ID(WMI_GRP_FWTEST), + /** set NoA descs **/ + WMI_FWTEST_P2P_SET_NOA_PARAM_CMDID, + /* UNIT Tests */ + WMI_UNIT_TEST_CMDID, + /* set debug and tuning parameters */ + WMI_FWTEST_CMDID, + /* Q-Boost configuration test commands */ + WMI_QBOOST_CFG_CMDID, + + /** TDLS Configuration */ + /** enable/disable TDLS */ + WMI_TDLS_SET_STATE_CMDID = WMI_CMD_GRP_START_ID(WMI_GRP_TDLS), + /** set tdls peer state */ + WMI_TDLS_PEER_UPDATE_CMDID, + /** TDLS Offchannel control */ + WMI_TDLS_SET_OFFCHAN_MODE_CMDID, + + /** Resmgr Configuration */ + /** Adaptive OCS is enabled by default in the FW. This command is used to + * disable FW based adaptive OCS. + */ + WMI_RESMGR_ADAPTIVE_OCS_ENABLE_DISABLE_CMDID = WMI_CMD_GRP_START_ID(WMI_GRP_RESMGR), + /** set the requested channel time quota for the home channels */ + WMI_RESMGR_SET_CHAN_TIME_QUOTA_CMDID, + /** set the requested latency for the home channels */ + WMI_RESMGR_SET_CHAN_LATENCY_CMDID, + + /** STA SMPS Configuration */ + /** force SMPS mode */ + WMI_STA_SMPS_FORCE_MODE_CMDID = WMI_CMD_GRP_START_ID(WMI_GRP_STA_SMPS), + /** set SMPS parameters */ + WMI_STA_SMPS_PARAM_CMDID, + + /* Wlan HB commands*/ + /* enalbe/disable wlan HB */ + WMI_HB_SET_ENABLE_CMDID = WMI_CMD_GRP_START_ID(WMI_GRP_WLAN_HB), + /* set tcp parameters for wlan HB */ + WMI_HB_SET_TCP_PARAMS_CMDID, + /* set tcp pkt filter for wlan HB */ + WMI_HB_SET_TCP_PKT_FILTER_CMDID, + /* set udp parameters for wlan HB */ + WMI_HB_SET_UDP_PARAMS_CMDID, + /* set udp pkt filter for wlan HB */ + WMI_HB_SET_UDP_PKT_FILTER_CMDID, + + /** Wlan RMC commands*/ + /** enable/disable RMC */ + WMI_RMC_SET_MODE_CMDID = WMI_CMD_GRP_START_ID(WMI_GRP_RMC), + /** configure action frame period */ + WMI_RMC_SET_ACTION_PERIOD_CMDID, + /** For debug/future enhancement purposes only, + * configures/finetunes RMC algorithms */ + WMI_RMC_CONFIG_CMDID, + /** select manual leader */ + WMI_RMC_SET_MANUAL_LEADER_CMDID, + + /** WLAN MHF offload commands */ + /** enable/disable MHF offload */ + WMI_MHF_OFFLOAD_SET_MODE_CMDID = WMI_CMD_GRP_START_ID(WMI_GRP_MHF_OFL), + /** Plumb routing table for MHF offload */ + WMI_MHF_OFFLOAD_PLUMB_ROUTING_TBL_CMDID, + + /*location scan commands*/ + /*start batch scan*/ + WMI_BATCH_SCAN_ENABLE_CMDID = WMI_CMD_GRP_START_ID(WMI_GRP_LOCATION_SCAN), + /*stop batch scan*/ + WMI_BATCH_SCAN_DISABLE_CMDID, + /*get batch scan result*/ + WMI_BATCH_SCAN_TRIGGER_RESULT_CMDID, + /* OEM related cmd */ + WMI_OEM_REQ_CMDID = WMI_CMD_GRP_START_ID(WMI_GRP_OEM), + WMI_OEM_REQUEST_CMDID, /* UNUSED */ + /* OEM related cmd used for Low Power ranging */ + WMI_LPI_OEM_REQ_CMDID, + WMI_OEM_DMA_RING_CFG_REQ_CMDID, + + /** Nan Request */ + WMI_NAN_CMDID = WMI_CMD_GRP_START_ID(WMI_GRP_NAN), + + /** Modem power state command */ + WMI_MODEM_POWER_STATE_CMDID = WMI_CMD_GRP_START_ID(WMI_GRP_COEX), + WMI_CHAN_AVOID_UPDATE_CMDID, + WMI_COEX_CONFIG_CMDID, + WMI_CHAN_AVOID_RPT_ALLOW_CMDID, + WMI_COEX_GET_ANTENNA_ISOLATION_CMDID, + WMI_SAR_LIMITS_CMDID, + + /** + * OBSS scan offload enable/disable commands + * OBSS scan enable CMD will send to FW after VDEV UP, if these conditions are true: + * 1. WMI_SERVICE_OBSS_SCAN is reported by FW in service ready, + * 2. STA connect to a 2.4Ghz ht20/ht40 AP, + * 3. AP enable 20/40 coexistence (OBSS_IE-74 can be found in beacon or association response) + * If OBSS parameters from beacon changed, also use enable CMD to update parameters. + * OBSS scan disable CMD will send to FW if have enabled when tearing down connection. + */ + WMI_OBSS_SCAN_ENABLE_CMDID = WMI_CMD_GRP_START_ID(WMI_GRP_OBSS_OFL), + WMI_OBSS_SCAN_DISABLE_CMDID, + + /**LPI commands*/ + /**LPI mgmt snooping config command*/ + WMI_LPI_MGMT_SNOOPING_CONFIG_CMDID = WMI_CMD_GRP_START_ID(WMI_GRP_LPI), + /**LPI scan start command*/ + WMI_LPI_START_SCAN_CMDID, + /**LPI scan stop command*/ + WMI_LPI_STOP_SCAN_CMDID, + + /** ExtScan commands */ + WMI_EXTSCAN_START_CMDID = WMI_CMD_GRP_START_ID(WMI_GRP_EXTSCAN), + WMI_EXTSCAN_STOP_CMDID, + WMI_EXTSCAN_CONFIGURE_WLAN_CHANGE_MONITOR_CMDID, + WMI_EXTSCAN_CONFIGURE_HOTLIST_MONITOR_CMDID, + WMI_EXTSCAN_GET_CACHED_RESULTS_CMDID, + WMI_EXTSCAN_GET_WLAN_CHANGE_RESULTS_CMDID, + WMI_EXTSCAN_SET_CAPABILITIES_CMDID, + WMI_EXTSCAN_GET_CAPABILITIES_CMDID, + WMI_EXTSCAN_CONFIGURE_HOTLIST_SSID_MONITOR_CMDID, + WMI_EXTSCAN_CONFIGURE_MAWC_CMDID, + + /** DHCP server offload commands */ + WMI_SET_DHCP_SERVER_OFFLOAD_CMDID = WMI_CMD_GRP_START_ID(WMI_GRP_DHCP_OFL), + + /** IPA Offload features related commands */ + WMI_IPA_OFFLOAD_ENABLE_DISABLE_CMDID = WMI_CMD_GRP_START_ID(WMI_GRP_IPA), + + /** mDNS responder offload commands */ + WMI_MDNS_OFFLOAD_ENABLE_CMDID = WMI_CMD_GRP_START_ID(WMI_GRP_MDNS_OFL), + WMI_MDNS_SET_FQDN_CMDID, + WMI_MDNS_SET_RESPONSE_CMDID, + WMI_MDNS_GET_STATS_CMDID, + + /* enable/disable AP Authentication offload */ + WMI_SAP_OFL_ENABLE_CMDID = WMI_CMD_GRP_START_ID(WMI_GRP_SAP_OFL), + WMI_SAP_SET_BLACKLIST_PARAM_CMDID, + + /** Out-of-context-of-BSS (OCB) commands */ + WMI_OCB_SET_CONFIG_CMDID = WMI_CMD_GRP_START_ID(WMI_GRP_OCB), + WMI_OCB_SET_UTC_TIME_CMDID, + WMI_OCB_START_TIMING_ADVERT_CMDID, + WMI_OCB_STOP_TIMING_ADVERT_CMDID, + WMI_OCB_GET_TSF_TIMER_CMDID, + WMI_DCC_GET_STATS_CMDID, + WMI_DCC_CLEAR_STATS_CMDID, + WMI_DCC_UPDATE_NDL_CMDID, + + /* System-On-Chip commands */ + WMI_SOC_SET_PCL_CMDID = WMI_CMD_GRP_START_ID(WMI_GRP_SOC), + WMI_SOC_SET_HW_MODE_CMDID, + WMI_SOC_SET_DUAL_MAC_CONFIG_CMDID, + WMI_SOC_SET_ANTENNA_MODE_CMDID, + + /* packet filter commands */ + WMI_PACKET_FILTER_CONFIG_CMDID = WMI_CMD_GRP_START_ID(WMI_GRP_PKT_FILTER), + WMI_PACKET_FILTER_ENABLE_CMDID, + + /** Motion Aided WiFi Connectivity (MAWC) commands */ + WMI_MAWC_SENSOR_REPORT_IND_CMDID = WMI_CMD_GRP_START_ID(WMI_GRP_MAWC), + + /** WMI commands related to PMF 11w Offload */ + WMI_PMF_OFFLOAD_SET_SA_QUERY_CMDID = WMI_CMD_GRP_START_ID(WMI_GRP_PMF_OFFLOAD), + + /** WMI commands related to pkt filter (BPF) offload */ + WMI_BPF_GET_CAPABILITY_CMDID = WMI_CMD_GRP_START_ID(WMI_GRP_BPF_OFFLOAD), + WMI_BPF_GET_VDEV_STATS_CMDID, + WMI_BPF_SET_VDEV_INSTRUCTIONS_CMDID, + WMI_BPF_DEL_VDEV_INSTRUCTIONS_CMDID, + WMI_BPF_SET_VDEV_ACTIVE_MODE_CMDID, + + /** WMI commands related to monitor mode. */ + WMI_MNT_FILTER_CMDID = WMI_CMD_GRP_START_ID(WMI_GRP_MONITOR), + + /** WMI commands related to regulatory offload */ + WMI_SET_CURRENT_COUNTRY_CMDID = WMI_CMD_GRP_START_ID(WMI_GRP_REGULATORY), + WMI_11D_SCAN_START_CMDID, + WMI_11D_SCAN_STOP_CMDID, + WMI_SET_INIT_COUNTRY_CMDID, + + /** + * Nan Data commands + * NDI - NAN Data Interface + * NDP - NAN Data Path + */ + /* Commands in prototyping phase */ + WMI_NDI_GET_CAP_REQ_CMDID = WMI_CMD_GRP_START_ID(WMI_GRP_PROTOTYPE), + WMI_NDP_INITIATOR_REQ_CMDID, + WMI_NDP_RESPONDER_REQ_CMDID, + WMI_NDP_END_REQ_CMDID, + + /** WMI commands related to HW data filtering **/ + WMI_HW_DATA_FILTER_CMDID = WMI_CMD_GRP_START_ID(WMI_GRP_HW_DATA_FILTER), + +} WMI_CMD_ID; + +typedef enum { + /** WMI service is ready; after this event WMI messages can be sent/received */ + WMI_SERVICE_READY_EVENTID = 0x1, + /** WMI is ready; after this event the wlan subsystem is initialized and can process commands. */ + WMI_READY_EVENTID, + + /** Specify what WMI services the target supports (for services beyond + * what fits in the WMI_SERVICE_READY_EVENT message's wmi_service_bitmap) + */ + WMI_SERVICE_AVAILABLE_EVENTID, + + /** Scan specific events */ + WMI_SCAN_EVENTID = WMI_EVT_GRP_START_ID(WMI_GRP_SCAN), + + /* PDEV specific events */ + /** TPC config for the current operating channel */ + WMI_PDEV_TPC_CONFIG_EVENTID = WMI_EVT_GRP_START_ID(WMI_GRP_PDEV), + /** Channel stats event */ + WMI_CHAN_INFO_EVENTID, + + /** PHY Error specific WMI event */ + WMI_PHYERR_EVENTID, + + /** eeprom dump event */ + WMI_PDEV_DUMP_EVENTID, + + /** traffic pause event */ + WMI_TX_PAUSE_EVENTID, + + /** DFS radar event */ + WMI_DFS_RADAR_EVENTID, + + /** track L1SS entry and residency event */ + WMI_PDEV_L1SS_TRACK_EVENTID, + + /** Report current temprature of the chip in Celcius degree */ + WMI_PDEV_TEMPERATURE_EVENTID, + + /** Extension of WMI_SERVICE_READY msg with extra target capability info */ + WMI_SERVICE_READY_EXT_EVENTID, + + /** FIPS test mode event */ + WMI_PDEV_FIPS_EVENTID, + + /** Channel hopping avoidance */ + WMI_PDEV_CHANNEL_HOPPING_EVENTID, + + /** CCK ANI level event */ + WMI_PDEV_ANI_CCK_LEVEL_EVENTID, + + /** OFDM ANI level event */ + WMI_PDEV_ANI_OFDM_LEVEL_EVENTID, + + /** Tx PPDU params */ + WMI_PDEV_TPC_EVENTID, + + /** NF Cal Power in DBR/DBM for all channels */ + WMI_PDEV_NFCAL_POWER_ALL_CHANNELS_EVENTID, + + /** SOC/PDEV events */ + WMI_PDEV_SET_HW_MODE_RESP_EVENTID, + WMI_PDEV_HW_MODE_TRANSITION_EVENTID, + WMI_PDEV_SET_MAC_CONFIG_RESP_EVENTID, + /** Report ANT DIV feature's status */ + WMI_PDEV_ANTDIV_STATUS_EVENTID, + /** Chip level Power stats */ + WMI_PDEV_CHIP_POWER_STATS_EVENTID, + /** Power Save Failure Detected */ + WMI_PDEV_CHIP_POWER_SAVE_FAILURE_DETECTED_EVENTID, + + /* Event to report the switch count in csa of one or more VDEVs */ + WMI_PDEV_CSA_SWITCH_COUNT_STATUS_EVENTID, + + /** Report the caldata version to host */ + WMI_PDEV_CHECK_CAL_VERSION_EVENTID, + + /** Report chain RSSI and antenna index to host */ + WMI_PDEV_DIV_RSSI_ANTID_EVENTID, + + /** provide noise floor and cycle counts for a channel */ + WMI_PDEV_BSS_CHAN_INFO_EVENTID, + + /* VDEV specific events */ + /** VDEV started event in response to VDEV_START request */ + WMI_VDEV_START_RESP_EVENTID = WMI_EVT_GRP_START_ID(WMI_GRP_VDEV), + /** vdev stopped event , generated in response to VDEV_STOP request */ + WMI_VDEV_STOPPED_EVENTID, + /* Indicate the set key (used for setting per + * peer unicast and per vdev multicast) + * operation has completed */ + WMI_VDEV_INSTALL_KEY_COMPLETE_EVENTID, + /* NOTE: WMI_VDEV_MCC_BCN_INTERVAL_CHANGE_REQ_EVENTID would be deprecated. Please + don't use this for any new implementations */ + /* Firmware requests dynamic change to a specific beacon interval for a specific vdev ID in MCC scenario. + This request is valid only for vdevs operating in soft AP or P2P GO mode */ + WMI_VDEV_MCC_BCN_INTERVAL_CHANGE_REQ_EVENTID, + + /* Return the TSF timestamp of specified vdev */ + WMI_VDEV_TSF_REPORT_EVENTID, + + /* FW response to Host for vdev delete cmdid */ + WMI_VDEV_DELETE_RESP_EVENTID, + + /* DISA feature: FW response to Host with encrypted/decrypted 802.11 DISA frame */ + WMI_VDEV_ENCRYPT_DECRYPT_DATA_RESP_EVENTID, + + /** event to report mac randomization success **/ + WMI_VDEV_ADD_MAC_ADDR_TO_RX_FILTER_STATUS_EVENTID, + + /* event for ARP stats collection */ + WMI_VDEV_GET_ARP_STAT_EVENTID, + + /** get tx power event in response to VDEV_GET_TX_POWER request */ + WMI_VDEV_GET_TX_POWER_EVENTID, + + /* peer specific events */ + /** FW reauet to kick out the station for reasons like inactivity,lack of response ..etc */ + WMI_PEER_STA_KICKOUT_EVENTID = WMI_EVT_GRP_START_ID(WMI_GRP_PEER), + + /** Peer Info Event with data_rate, rssi, tx_fail_cnt etc */ + WMI_PEER_INFO_EVENTID, + + /** Event indicating that TX fail count reaching threshold */ + WMI_PEER_TX_FAIL_CNT_THR_EVENTID, + + /* Return the estimate link speed for the Peer specified in the + * WMI_PEER_GET_ESTIMATED_LINKSPEED_CMDID command. + */ + WMI_PEER_ESTIMATED_LINKSPEED_EVENTID, + /* Return the peer state + * WMI_PEER_SET_PARAM_CMDID, WMI_PEER_AUTHORIZE + */ + WMI_PEER_STATE_EVENTID, + + /* Peer Assoc Conf event to confirm fw had received PEER_ASSOC_CMD. + * After that, host will send Mx message. + * Otherwise, host will pause any Mx(STA:M2/M4) message + */ + WMI_PEER_ASSOC_CONF_EVENTID, + + /* FW response to Host for peer delete cmdid */ + WMI_PEER_DELETE_RESP_EVENTID, + + /** Valid rate code list for peer */ + WMI_PEER_RATECODE_LIST_EVENTID, + WMI_WDS_PEER_EVENTID, + WMI_PEER_STA_PS_STATECHG_EVENTID, + /** Peer Ant Div Info Event with rssi per chain, etc */ + WMI_PEER_ANTDIV_INFO_EVENTID, + + /* beacon/mgmt specific events */ + /** RX management frame. the entire frame is carried along with the event. */ + WMI_MGMT_RX_EVENTID = WMI_EVT_GRP_START_ID(WMI_GRP_MGMT), + /** software beacon alert event to Host requesting host to Queue a beacon for transmission + use only in host beacon mode */ + WMI_HOST_SWBA_EVENTID, + /** beacon tbtt offset event indicating the tsf offset of the tbtt from the theritical value. + tbtt offset is normally 0 and will be non zero if there are multiple VDEVs operating in + staggered beacon transmission mode */ + WMI_TBTTOFFSET_UPDATE_EVENTID, + + /** event after the first beacon is transmitted following + a change in the template.*/ + WMI_OFFLOAD_BCN_TX_STATUS_EVENTID, + /** event after the first probe response is transmitted following + a change in the template.*/ + WMI_OFFLOAD_PROB_RESP_TX_STATUS_EVENTID, + /** Event for Mgmt TX completion event */ + WMI_MGMT_TX_COMPLETION_EVENTID, + /** Event for Mgmt TX bundle completion event */ + WMI_MGMT_TX_BUNDLE_COMPLETION_EVENTID, + /** vdev_map used in WMI_TBTTOFFSET_UPDATE_EVENTID supports max 32 vdevs. + * Use this event if number of vdevs > 32. + */ + WMI_TBTTOFFSET_EXT_UPDATE_EVENTID, + /** Event for offchan data TX completion event */ + WMI_OFFCHAN_DATA_TX_COMPLETION_EVENTID, + + /* ADDBA Related WMI Events*/ + /** Indication the completion of the prior + WMI_PEER_TID_DELBA_CMDID(initiator) */ + WMI_TX_DELBA_COMPLETE_EVENTID = WMI_EVT_GRP_START_ID(WMI_GRP_BA_NEG), + /** Indication the completion of the prior + *WMI_PEER_TID_ADDBA_CMDID(initiator) */ + WMI_TX_ADDBA_COMPLETE_EVENTID, + + /* Seq num returned from hw for a sta/tid pair */ + WMI_BA_RSP_SSN_EVENTID, + + /* Aggregation state requested by BTC */ + WMI_AGGR_STATE_TRIG_EVENTID, + + /** Roam event to trigger roaming on host */ + WMI_ROAM_EVENTID = WMI_EVT_GRP_START_ID(WMI_GRP_ROAM), + + /** matching AP found from list of profiles */ + WMI_PROFILE_MATCH, + /** roam synch event */ + WMI_ROAM_SYNCH_EVENTID, + + /** P2P disc found */ + WMI_P2P_DISC_EVENTID = WMI_EVT_GRP_START_ID(WMI_GRP_P2P), + /** send noa info to host when noa is changed for beacon tx offload enable */ + WMI_P2P_NOA_EVENTID, + /** send p2p listen offload stopped event with different reason */ + WMI_P2P_LISTEN_OFFLOAD_STOPPED_EVENTID, + + /** Send EGAP Info to host */ + WMI_AP_PS_EGAP_INFO_EVENTID = WMI_EVT_GRP_START_ID(WMI_GRP_AP_PS), + + /* send pdev resume event to host after pdev resume. */ + WMI_PDEV_RESUME_EVENTID = WMI_EVT_GRP_START_ID(WMI_GRP_SUSPEND), + + /** WOW wake up host event.generated in response to WMI_WOW_HOSTWAKEUP_FROM_SLEEP_CMDID. + will cary wake reason */ + WMI_WOW_WAKEUP_HOST_EVENTID = WMI_EVT_GRP_START_ID(WMI_GRP_WOW), + WMI_D0_WOW_DISABLE_ACK_EVENTID, + WMI_WOW_INITIAL_WAKEUP_EVENTID, + + /*RTT related event ID*/ + /** RTT measurement report */ + WMI_RTT_MEASUREMENT_REPORT_EVENTID = WMI_EVT_GRP_START_ID(WMI_GRP_RTT), + /** TSF measurement report */ + WMI_TSF_MEASUREMENT_REPORT_EVENTID, + /** RTT error report */ + WMI_RTT_ERROR_REPORT_EVENTID, + + /*STATS specific events*/ + /** txrx stats event requested by host */ + WMI_STATS_EXT_EVENTID = WMI_EVT_GRP_START_ID(WMI_GRP_STATS), + /** FW iface link stats Event */ + WMI_IFACE_LINK_STATS_EVENTID, + /** FW iface peer link stats Event */ + WMI_PEER_LINK_STATS_EVENTID, + /** FW Update radio stats Event */ + WMI_RADIO_LINK_STATS_EVENTID, + + /** Firmware memory dump Complete event*/ + WMI_UPDATE_FW_MEM_DUMP_EVENTID, + + /** Event indicating the DIAG logs/events supported by FW */ + WMI_DIAG_EVENT_LOG_SUPPORTED_EVENTID, + + /** Instantaneous RSSI event */ + WMI_INST_RSSI_STATS_EVENTID, + + /** FW update tx power levels event */ + WMI_RADIO_TX_POWER_LEVEL_STATS_EVENTID, + + /** This event is used to report wlan stats to host. + * It is triggered under 3 conditions: + * (a) Periodic timer timed out, based on the period specified + * by WMI_PDEV_PARAM_STATS_OBSERVATION_PERIOD + * (b) Whenever any of the (enabled) stats thresholds specified + * in the WMI_PDEV_SET_STATS_THRESHOLD_CMD message is exceeded + * within the current stats period. + * (c) In response to the one-time wlan stats request of + * WMI_REQUEST_WLAN_STATS_CMDID from host. + * + * If this event is triggered by condition a or b, + * the stats counters are cleared at the start of each period. + * But if it is triggered by condition c, stats counters won't be cleared. + */ + WMI_REPORT_STATS_EVENTID, + + /** Event indicating RCPI of the peer requested by host in the WMI_REQUEST_RCPI_CMDID */ + WMI_UPDATE_RCPI_EVENTID, + + /** This event is used to respond to WMI_REQUEST_PEER_STATS_INFO_CMDID + * and report peer stats info to host */ + WMI_PEER_STATS_INFO_EVENTID, + + /** This event is used to respond to WMI_REQUEST_RADIO_CHAN_STATS_CMDID + * and report radio channel stats to host */ + WMI_RADIO_CHAN_STATS_EVENTID, + + /* NLO specific events */ + /** NLO match event after the first match */ + WMI_NLO_MATCH_EVENTID = WMI_EVT_GRP_START_ID(WMI_GRP_NLO_OFL), + + /** NLO scan complete event */ + WMI_NLO_SCAN_COMPLETE_EVENTID, + + /** APFIND specific events */ + WMI_APFIND_EVENTID, + + /** passpoint network match event */ + WMI_PASSPOINT_MATCH_EVENTID, + + /** GTK offload stautus event requested by host */ + WMI_GTK_OFFLOAD_STATUS_EVENTID = WMI_EVT_GRP_START_ID(WMI_GRP_GTK_OFL), + + /** GTK offload failed to rekey event */ + WMI_GTK_REKEY_FAIL_EVENTID, + /* CSA IE received event */ + WMI_CSA_HANDLING_EVENTID = WMI_EVT_GRP_START_ID(WMI_GRP_CSA_OFL), + + /*chatter query reply event*/ + WMI_CHATTER_PC_QUERY_EVENTID = WMI_EVT_GRP_START_ID(WMI_GRP_CHATTER), + + /** DFS related events */ + WMI_PDEV_DFS_RADAR_DETECTION_EVENTID = WMI_EVT_GRP_START_ID(WMI_GRP_DFS), + /** Indicate channel-availability-check completion event to host */ + WMI_VDEV_DFS_CAC_COMPLETE_EVENTID, + /** Indicate off-channel-availability-check completion event to host */ + WMI_VDEV_ADFS_OCAC_COMPLETE_EVENTID, + + /** echo event in response to echo command */ + WMI_ECHO_EVENTID = WMI_EVT_GRP_START_ID(WMI_GRP_MISC), + + /* !!IMPORTANT!! + * If you need to add a new WMI event ID to the WMI_GRP_MISC sub-group, + * please make sure you add it BEHIND WMI_PDEV_UTF_EVENTID, + * as we MUST have a fixed value here to maintain compatibility between + * UTF and the ART2 driver + */ + /** UTF specific WMI event */ + WMI_PDEV_UTF_EVENTID, + + /** event carries buffered debug messages */ + WMI_DEBUG_MESG_EVENTID, + /** FW stats(periodic or on shot) */ + WMI_UPDATE_STATS_EVENTID, + /** debug print message used for tracing FW code while debugging */ + WMI_DEBUG_PRINT_EVENTID, + /** DCS wlan or non-wlan interference event + */ + WMI_DCS_INTERFERENCE_EVENTID, + /** VI spoecific event */ + WMI_PDEV_QVIT_EVENTID, + /** FW code profile data in response to profile request */ + WMI_WLAN_PROFILE_DATA_EVENTID, + /* Factory Testing Mode request event + * used for integrated chipsets */ + WMI_PDEV_FTM_INTG_EVENTID, + /* avoid list of frequencies . + */ + WMI_WLAN_FREQ_AVOID_EVENTID, + /* Indicate the keepalive parameters */ + WMI_VDEV_GET_KEEPALIVE_EVENTID, + /*Thermal Management event*/ + WMI_THERMAL_MGMT_EVENTID, + + /* Container for DIAG event and log data */ + WMI_DIAG_DATA_CONTAINER_EVENTID, + + /* host auto shutdown event */ + WMI_HOST_AUTO_SHUTDOWN_EVENTID, + + /*update mib counters together with WMI_UPDATE_STATS_EVENTID*/ + WMI_UPDATE_WHAL_MIB_STATS_EVENTID, + + /*update ht/vht info based on vdev (rx and tx NSS and preamble)*/ + WMI_UPDATE_VDEV_RATE_STATS_EVENTID, + + WMI_DIAG_EVENTID, + + /** Set OCB Sched Response, deprecated */ + WMI_OCB_SET_SCHED_EVENTID, + + /** event to indicate the flush of the buffered debug messages is complete*/ + WMI_DEBUG_MESG_FLUSH_COMPLETE_EVENTID, + + /** event to report mix/max RSSI breach events */ + WMI_RSSI_BREACH_EVENTID, + + /** event to report completion of data storage into flash memory */ + WMI_TRANSFER_DATA_TO_FLASH_COMPLETE_EVENTID, + + /** event to report SCPC calibrated data to host */ + WMI_PDEV_UTF_SCPC_EVENTID, + + /** event to provide requested data from the target's flash memory */ + WMI_READ_DATA_FROM_FLASH_EVENTID, + + /** event to report rx aggregation failure frame information */ + WMI_REPORT_RX_AGGR_FAILURE_EVENTID, + + /** event to upload a PKGID to host to identify chip for various products */ + WMI_PKGID_EVENTID, + + /* Thermal Throttling stats event id for every pdev and zones, etc */ + WMI_THERM_THROT_STATS_EVENTID, + + /* WMI UNIT TEST event */ + WMI_UNIT_TEST_EVENTID, + + /* GPIO Event */ + WMI_GPIO_INPUT_EVENTID = WMI_EVT_GRP_START_ID(WMI_GRP_GPIO), + /** upload H_CV info WMI event + * to indicate uploaded H_CV info to host + */ + WMI_UPLOADH_EVENTID, + + /** capture H info WMI event + * to indicate captured H info to host + */ + WMI_CAPTUREH_EVENTID, + /* hw RFkill */ + WMI_RFKILL_STATE_CHANGE_EVENTID, + + /* TDLS Event */ + WMI_TDLS_PEER_EVENTID = WMI_EVT_GRP_START_ID(WMI_GRP_TDLS), + + /** STA SMPS Event */ + /** force SMPS mode */ + WMI_STA_SMPS_FORCE_MODE_COMPLETE_EVENTID = WMI_EVT_GRP_START_ID(WMI_GRP_STA_SMPS), + + /*location scan event*/ + /*report the firmware's capability of batch scan*/ + WMI_BATCH_SCAN_ENABLED_EVENTID = WMI_EVT_GRP_START_ID(WMI_GRP_LOCATION_SCAN), + /*batch scan result*/ + WMI_BATCH_SCAN_RESULT_EVENTID, + /* OEM Event */ + WMI_OEM_CAPABILITY_EVENTID = WMI_EVT_GRP_START_ID(WMI_GRP_OEM), /*DEPRECATED*/ + WMI_OEM_MEASUREMENT_REPORT_EVENTID, /* DEPRECATED */ + WMI_OEM_ERROR_REPORT_EVENTID, /* DEPRECATED */ + WMI_OEM_RESPONSE_EVENTID, + WMI_OEM_DMA_RING_CFG_RSP_EVENTID, + WMI_OEM_DMA_BUF_RELEASE_EVENTID, + + /* NAN Event */ + WMI_NAN_EVENTID = WMI_EVT_GRP_START_ID(WMI_GRP_NAN), + WMI_NAN_DISC_IFACE_CREATED_EVENTID, + WMI_NAN_DISC_IFACE_DELETED_EVENTID, + WMI_NAN_STARTED_CLUSTER_EVENTID, + WMI_NAN_JOINED_CLUSTER_EVENTID, + + /* Coex Event */ + WMI_COEX_REPORT_ANTENNA_ISOLATION_EVENTID = WMI_EVT_GRP_START_ID(WMI_GRP_COEX), + + /* LPI Event */ + WMI_LPI_RESULT_EVENTID = WMI_EVT_GRP_START_ID(WMI_GRP_LPI), + WMI_LPI_STATUS_EVENTID, + WMI_LPI_HANDOFF_EVENTID, + + /* ExtScan events */ + WMI_EXTSCAN_START_STOP_EVENTID = WMI_EVT_GRP_START_ID(WMI_GRP_EXTSCAN), + WMI_EXTSCAN_OPERATION_EVENTID, + WMI_EXTSCAN_TABLE_USAGE_EVENTID, + WMI_EXTSCAN_CACHED_RESULTS_EVENTID, + WMI_EXTSCAN_WLAN_CHANGE_RESULTS_EVENTID, + WMI_EXTSCAN_HOTLIST_MATCH_EVENTID, + WMI_EXTSCAN_CAPABILITIES_EVENTID, + WMI_EXTSCAN_HOTLIST_SSID_MATCH_EVENTID, + + /* mDNS offload events */ + WMI_MDNS_STATS_EVENTID = WMI_EVT_GRP_START_ID(WMI_GRP_MDNS_OFL), + + /* SAP Authentication offload events */ + WMI_SAP_OFL_ADD_STA_EVENTID = WMI_EVT_GRP_START_ID(WMI_GRP_SAP_OFL), + WMI_SAP_OFL_DEL_STA_EVENTID, + + /** Out-of-context-of-bss (OCB) events */ + WMI_OCB_SET_CONFIG_RESP_EVENTID = WMI_EVT_GRP_START_ID(WMI_GRP_OCB), + WMI_OCB_GET_TSF_TIMER_RESP_EVENTID, + WMI_DCC_GET_STATS_RESP_EVENTID, + WMI_DCC_UPDATE_NDL_RESP_EVENTID, + WMI_DCC_STATS_EVENTID, + + /* System-On-Chip events */ + WMI_SOC_SET_HW_MODE_RESP_EVENTID = WMI_EVT_GRP_START_ID(WMI_GRP_SOC), + WMI_SOC_HW_MODE_TRANSITION_EVENTID, + WMI_SOC_SET_DUAL_MAC_CONFIG_RESP_EVENTID, + + /** Motion Aided WiFi Connectivity (MAWC) events */ + WMI_MAWC_ENABLE_SENSOR_EVENTID = WMI_EVT_GRP_START_ID(WMI_GRP_MAWC), + + /** pkt filter (BPF) offload relevant events */ + WMI_BPF_CAPABILIY_INFO_EVENTID = WMI_EVT_GRP_START_ID(WMI_GRP_BPF_OFFLOAD), + WMI_BPF_VDEV_STATS_INFO_EVENTID, + + + /* RMC specific event */ + /* RMC manual leader selected event */ + WMI_RMC_NEW_LEADER_EVENTID = WMI_EVT_GRP_START_ID(WMI_GRP_RMC), + + /** WMI events related to regulatory offload */ + WMI_REG_CHAN_LIST_CC_EVENTID = WMI_EVT_GRP_START_ID(WMI_GRP_REGULATORY), + WMI_11D_NEW_COUNTRY_EVENTID, + + /** Events in Prototyping phase */ + WMI_NDI_CAP_RSP_EVENTID = WMI_EVT_GRP_START_ID(WMI_GRP_PROTOTYPE), + WMI_NDP_INITIATOR_RSP_EVENTID, + WMI_NDP_RESPONDER_RSP_EVENTID, + WMI_NDP_END_RSP_EVENTID, + WMI_NDP_INDICATION_EVENTID, + WMI_NDP_CONFIRM_EVENTID, + WMI_NDP_END_INDICATION_EVENTID, + WMI_WLAN_COEX_BT_ACTIVITY_EVENTID, +} WMI_EVT_ID; + +/* defines for OEM message sub-types */ +#define WMI_OEM_CAPABILITY_REQ 0x01 +#define WMI_OEM_CAPABILITY_RSP 0x02 +#define WMI_OEM_MEASUREMENT_REQ 0x03 +#define WMI_OEM_MEASUREMENT_RSP 0x04 +#define WMI_OEM_ERROR_REPORT_RSP 0x05 +#define WMI_OEM_NAN_MEAS_REQ 0x06 +#define WMI_OEM_NAN_MEAS_RSP 0x07 +#define WMI_OEM_NAN_PEER_INFO 0x08 +#define WMI_OEM_CONFIGURE_LCR 0x09 +#define WMI_OEM_CONFIGURE_LCI 0x0A + + +#define WMI_CHAN_LIST_TAG 0x1 +#define WMI_SSID_LIST_TAG 0x2 +#define WMI_BSSID_LIST_TAG 0x3 +#define WMI_IE_TAG 0x4 + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_channel */ + /** primary 20 MHz channel frequency in mhz */ + A_UINT32 mhz; + /** Center frequency 1 in MHz*/ + A_UINT32 band_center_freq1; + /** Center frequency 2 in MHz - valid only for 11acvht 80plus80 mode*/ + A_UINT32 band_center_freq2; + /** channel info described below */ + A_UINT32 info; + /** contains min power, max power, reg power and reg class id. */ + A_UINT32 reg_info_1; + /** contains antennamax */ + A_UINT32 reg_info_2; +} wmi_channel; + +typedef enum { + WMI_CHANNEL_CHANGE_CAUSE_NONE = 0, + WMI_CHANNEL_CHANGE_CAUSE_CSA, +} wmi_channel_change_cause; + +/** channel info consists of 6 bits of channel mode */ + +#define WMI_SET_CHANNEL_MODE(pwmi_channel,val) do { \ + (pwmi_channel)->info &= 0xffffffc0; \ + (pwmi_channel)->info |= (val); \ + } while (0) + +#define WMI_GET_CHANNEL_MODE(pwmi_channel) ((pwmi_channel)->info & 0x0000003f) + +#define WMI_CHAN_FLAG_HT40_PLUS 6 +#define WMI_CHAN_FLAG_PASSIVE 7 +#define WMI_CHAN_ADHOC_ALLOWED 8 +#define WMI_CHAN_AP_DISABLED 9 +#define WMI_CHAN_FLAG_DFS 10 +#define WMI_CHAN_FLAG_ALLOW_HT 11 /* HT is allowed on this channel */ +#define WMI_CHAN_FLAG_ALLOW_VHT 12 /* VHT is allowed on this channel */ +#define WMI_CHANNEL_CHANGE_CAUSE_CSA 13 /*Indicate reason for channel switch */ +#define WMI_CHAN_FLAG_HALF_RATE 14 /* Indicates half rate channel */ +#define WMI_CHAN_FLAG_QUARTER_RATE 15 /* Indicates quarter rate channel */ +#define WMI_CHAN_FLAG_DFS_CFREQ2 16 /* Enable radar event reporting for sec80 in VHT80p80 */ +#define WMI_CHAN_FLAG_ALLOW_HE 17 /* HE (11ax) is allowed on this channel */ + +#define WMI_SET_CHANNEL_FLAG(pwmi_channel,flag) do { \ + (pwmi_channel)->info |= (1 << flag); \ + } while (0) + +#define WMI_GET_CHANNEL_FLAG(pwmi_channel,flag) \ + (((pwmi_channel)->info & (1 << flag)) >> flag) + +#define WMI_SET_CHANNEL_MIN_POWER(pwmi_channel,val) do { \ + (pwmi_channel)->reg_info_1 &= 0xffffff00; \ + (pwmi_channel)->reg_info_1 |= (val & 0xff); \ + } while (0) +#define WMI_GET_CHANNEL_MIN_POWER(pwmi_channel) ((pwmi_channel)->reg_info_1 & 0xff) + +#define WMI_SET_CHANNEL_MAX_POWER(pwmi_channel,val) do { \ + (pwmi_channel)->reg_info_1 &= 0xffff00ff; \ + (pwmi_channel)->reg_info_1 |= ((val & 0xff) << 8); \ + } while (0) +#define WMI_GET_CHANNEL_MAX_POWER(pwmi_channel) ((((pwmi_channel)->reg_info_1) >> 8) & 0xff) + +#define WMI_SET_CHANNEL_REG_POWER(pwmi_channel,val) do { \ + (pwmi_channel)->reg_info_1 &= 0xff00ffff; \ + (pwmi_channel)->reg_info_1 |= ((val & 0xff) << 16); \ + } while (0) +#define WMI_GET_CHANNEL_REG_POWER(pwmi_channel) ((((pwmi_channel)->reg_info_1) >> 16) & 0xff) +#define WMI_SET_CHANNEL_REG_CLASSID(pwmi_channel,val) do { \ + (pwmi_channel)->reg_info_1 &= 0x00ffffff; \ + (pwmi_channel)->reg_info_1 |= ((val & 0xff) << 24); \ + } while (0) +#define WMI_GET_CHANNEL_REG_CLASSID(pwmi_channel) ((((pwmi_channel)->reg_info_1) >> 24) & 0xff) + +#define WMI_SET_CHANNEL_ANTENNA_MAX(pwmi_channel,val) do { \ + (pwmi_channel)->reg_info_2 &= 0xffffff00; \ + (pwmi_channel)->reg_info_2 |= (val & 0xff); \ + } while (0) +#define WMI_GET_CHANNEL_ANTENNA_MAX(pwmi_channel) ((pwmi_channel)->reg_info_2 & 0xff) + +/* max tx power is in 1 dBm units */ +#define WMI_SET_CHANNEL_MAX_TX_POWER(pwmi_channel,val) do { \ + (pwmi_channel)->reg_info_2 &= 0xffff00ff; \ + (pwmi_channel)->reg_info_2 |= ((val & 0xff) << 8); \ + } while (0) +#define WMI_GET_CHANNEL_MAX_TX_POWER(pwmi_channel) ((((pwmi_channel)->reg_info_2)>>8) & 0xff) + + +/** HT Capabilities*/ +#define WMI_HT_CAP_ENABLED 0x0001 /* HT Enabled/ disabled */ +#define WMI_HT_CAP_HT20_SGI 0x0002 /* Short Guard Interval with HT20 */ +#define WMI_HT_CAP_DYNAMIC_SMPS 0x0004 /* Dynamic MIMO powersave */ +#define WMI_HT_CAP_TX_STBC 0x0008 /* B3 TX STBC */ +#define WMI_HT_CAP_TX_STBC_MASK_SHIFT 3 +#define WMI_HT_CAP_RX_STBC 0x0030 /* B4-B5 RX STBC */ +#define WMI_HT_CAP_RX_STBC_MASK_SHIFT 4 +#define WMI_HT_CAP_LDPC 0x0040 /* LDPC supported */ +#define WMI_HT_CAP_L_SIG_TXOP_PROT 0x0080 /* L-SIG TXOP Protection */ +#define WMI_HT_CAP_MPDU_DENSITY 0x0700 /* MPDU Density */ +#define WMI_HT_CAP_MPDU_DENSITY_MASK_SHIFT 8 +#define WMI_HT_CAP_HT40_SGI 0x0800 +#define WMI_HT_CAP_RX_LDPC 0x1000 /* LDPC RX support */ +#define WMI_HT_CAP_TX_LDPC 0x2000 /* LDPC TX support */ + + +/* These macros should be used when we wish to advertise STBC support for + * only 1SS or 2SS or 3SS. */ +#define WMI_HT_CAP_RX_STBC_1SS 0x0010 /* B4-B5 RX STBC */ +#define WMI_HT_CAP_RX_STBC_2SS 0x0020 /* B4-B5 RX STBC */ +#define WMI_HT_CAP_RX_STBC_3SS 0x0030 /* B4-B5 RX STBC */ + + +#define WMI_HT_CAP_DEFAULT_ALL (WMI_HT_CAP_ENABLED | \ + WMI_HT_CAP_HT20_SGI | \ + WMI_HT_CAP_HT40_SGI | \ + WMI_HT_CAP_TX_STBC | \ + WMI_HT_CAP_RX_STBC | \ + WMI_HT_CAP_LDPC | \ + WMI_HT_CAP_TX_LDPC | \ + WMI_HT_CAP_RX_LDPC) + +/* WMI_VHT_CAP_* these maps to ieee 802.11ac vht capability information + field. The fields not defined here are not supported, or reserved. + Do not change these masks and if you have to add new one follow the + bitmask as specified by 802.11ac draft. + */ + + +#define WMI_VHT_CAP_MAX_MPDU_LEN_7935 0x00000001 +#define WMI_VHT_CAP_MAX_MPDU_LEN_11454 0x00000002 +#define WMI_VHT_CAP_MAX_MPDU_LEN_MASK 0x00000003 +#define WMI_VHT_CAP_CH_WIDTH_160MHZ 0x00000004 +#define WMI_VHT_CAP_CH_WIDTH_80P80_160MHZ 0x00000008 +#define WMI_VHT_CAP_RX_LDPC 0x00000010 +#define WMI_VHT_CAP_SGI_80MHZ 0x00000020 +#define WMI_VHT_CAP_SGI_160MHZ 0x00000040 +#define WMI_VHT_CAP_TX_STBC 0x00000080 +#define WMI_VHT_CAP_RX_STBC_MASK 0x00000300 +#define WMI_VHT_CAP_RX_STBC_MASK_SHIFT 8 +#define WMI_VHT_CAP_SU_BFORMER 0x00000800 +#define WMI_VHT_CAP_SU_BFORMEE 0x00001000 +#define WMI_VHT_CAP_MAX_CS_ANT_MASK 0x0000E000 +#define WMI_VHT_CAP_MAX_CS_ANT_MASK_SHIFT 13 +#define WMI_VHT_CAP_MAX_SND_DIM_MASK 0x00070000 +#define WMI_VHT_CAP_MAX_SND_DIM_MASK_SHIFT 16 +#define WMI_VHT_CAP_MU_BFORMER 0x00080000 +#define WMI_VHT_CAP_MU_BFORMEE 0x00100000 +#define WMI_VHT_CAP_TXOP_PS 0x00200000 +#define WMI_VHT_CAP_MAX_AMPDU_LEN_EXP 0x03800000 +#define WMI_VHT_CAP_MAX_AMPDU_LEN_EXP_SHIFT 23 +#define WMI_VHT_CAP_RX_FIXED_ANT 0x10000000 +#define WMI_VHT_CAP_TX_FIXED_ANT 0x20000000 +#define WMI_VHT_CAP_TX_LDPC 0x40000000 + + +/* TEMPORARY: + * Preserve the incorrect old name as an alias for the correct new name + * until all references to the old name have been removed from all hosts + * and targets. + */ +#define WMI_VHT_CAP_MAX_AMPDU_LEN_EXP_SHIT WMI_VHT_CAP_MAX_AMPDU_LEN_EXP_SHIFT + + +/* These macros should be used when we wish to advertise STBC support for + * only 1SS or 2SS or 3SS. */ +#define WMI_VHT_CAP_RX_STBC_1SS 0x00000100 +#define WMI_VHT_CAP_RX_STBC_2SS 0x00000200 +#define WMI_VHT_CAP_RX_STBC_3SS 0x00000300 + +/* TEMPORARY: + * Preserve the incorrect old name as an alias for the correct new name + * until all references to the old name have been removed from all hosts + * and targets. + */ +#define WMI_vHT_CAP_RX_STBC_3SS WMI_VHT_CAP_RX_STBC_3SS + +#define WMI_VHT_CAP_DEFAULT_ALL (WMI_VHT_CAP_MAX_MPDU_LEN_11454 | \ + WMI_VHT_CAP_SGI_80MHZ | \ + WMI_VHT_CAP_TX_STBC | \ + WMI_VHT_CAP_RX_STBC_MASK | \ + WMI_VHT_CAP_RX_LDPC | \ + WMI_VHT_CAP_TX_LDPC | \ + WMI_VHT_CAP_MAX_AMPDU_LEN_EXP | \ + WMI_VHT_CAP_RX_FIXED_ANT | \ + WMI_VHT_CAP_TX_FIXED_ANT) + +/* Interested readers refer to Rx/Tx MCS Map definition as defined in + 802.11ac + */ +#define WMI_VHT_MAX_MCS_4_SS_MASK(r,ss) ((3 & (r)) << (((ss) - 1) << 1)) +#define WMI_VHT_MAX_SUPP_RATE_MASK 0x1fff0000 +#define WMI_VHT_MAX_SUPP_RATE_MASK_SHIFT 16 + +/** 11ax capabilities */ +#define WMI_HE_CAP_PPE_PRESENT 0x00000001 +#define WMI_HE_CAP_TWT_RESPONDER_SUPPORT 0x00000002 +#define WMI_HE_CAP_TWT_REQUESTER_SUPPORT 0x00000004 +#define WMI_HE_FRAG_SUPPORT_MASK 0x00000018 +#define WMI_HE_FRAG_SUPPORT_SHIFT 3 + +/* Interested readers refer to Rx/Tx MCS Map definition as defined in 802.11ax + */ +#define WMI_HE_MAX_MCS_4_SS_MASK(r,ss) ((7 & (r)) << ((((ss) - 1) << 1)+((ss) - 1))) +#define WMI_HE_MAX_SUPP_RATE_MASK 0x1f000000 +#define WMI_HE_MAX_SUPP_RATE_MASK_SHIFT 24 + +/* fragmentation support field value */ +enum { + WMI_HE_FRAG_SUPPORT_LEVEL0, /* No Fragmentation support */ + WMI_HE_FRAG_SUPPORT_LEVEL1, /* support for fragments within a VHT single MPDU, no support for fragments within AMPDU */ + WMI_HE_FRAG_SUPPORT_LEVEL2, /* support for up to 1 fragment per MSDU within a single A-MPDU */ + WMI_HE_FRAG_SUPPORT_LEVEL3, /* support for multiple fragments per MSDU within an A-MPDU */ +}; + +/** NOTE: This defs cannot be changed in the future without breaking WMI compatibility */ +#define WMI_MAX_NUM_SS MAX_HE_NSS +#define WMI_MAX_NUM_RU MAX_HE_RU + +/* + * Figure 8 554ae: -PPE Threshold Info field format + * we pack PPET16 and PPT8 for four RU's in one element of array. + * + * ppet16_ppet8_ru3_ru0 array element 0 holds: + * | PPET8 | PPET16 | PPET8 | PPET16 | PPET8 | PPET16 | PPET8 | PPET16 | + *rsvd |NSS1,RU4|NSS1,RU4|NSS1,RU3|NSS1,RU3|NSS1,RU2|NSS1,RU2|NSS1,RU1|NSS1,RU1| + *31:23| 22:20 | 19:17 | 17:15 | 14:12 | 11:9 | 8:6 | 5:3 | 2:0 | + * + * ppet16_ppet8_ru3_ru0 array element 1 holds: + * | PPET8 | PPET16 | PPET8 | PPET16 | PPET8 | PPET16 | PPET8 | PPET16 | + *rsvd |NSS2,RU4|NSS2,RU4|NSS2,RU3|NSS2,RU3|NSS2,RU2|NSS2,RU2|NSS2,RU1|NSS2,RU1| + *31:23| 22:20 | 19:17 | 17:15 | 14:12 | 11:9 | 8:6 | 5:3 | 2:0 | + * + * etc. + */ + +/* + * Note that in these macros, "ru" is one-based, not zero-based, while + * nssm1 is zero-based. + */ +#define WMI_SET_PPET16(ppet16_ppet8_ru3_ru0, ru, nssm1, ppet) \ + do { \ + ppet16_ppet8_ru3_ru0[nssm1] &= ~(7 << (((ru-1) & 3) * 6)); \ + ppet16_ppet8_ru3_ru0[nssm1] |= ((ppet & 7) << (((ru-1) & 3) * 6)); \ + } while (0) + +#define WMI_GET_PPET16(ppet16_ppet8_ru3_ru0, ru, nssm1) \ + ((ppet16_ppet8_ru3_ru0[nssm1] >> (((ru-1) & 3) * 6)) & 7) + +#define WMI_SET_PPET8(ppet16_ppet8_ru3_ru0, ru, nssm1, ppet) \ + do { \ + ppet16_ppet8_ru3_ru0[nssm1] &= ~(7 << (((ru-1) & 3) * 6 + 3)); \ + ppet16_ppet8_ru3_ru0[nssm1] |= ((ppet&7) << (((ru-1) & 3) * 6 + 3)); \ + } while (0) + +#define WMI_GET_PPET8(ppet16_ppet8_ru3_ru0, ru, nssm1) \ + ((ppet16_ppet8_ru3_ru0[nssm1] >> (((ru-1) & 3) * 6 + 3)) & 7) + +typedef struct _wmi_ppe_threshold { + A_UINT32 numss_m1; /** NSS - 1*/ + union { + A_UINT32 ru_count; /** RU COUNT OBSOLETE to be removed after few versions */ + A_UINT32 ru_mask; /** RU index mask */ + }; + A_UINT32 ppet16_ppet8_ru3_ru0[WMI_MAX_NUM_SS]; /** ppet8 and ppet16 for max num ss */ +} wmi_ppe_threshold; + +/* WMI_SYS_CAPS_* refer to the capabilities that system support + */ +#define WMI_SYS_CAP_ENABLE 0x00000001 +#define WMI_SYS_CAP_TXPOWER 0x00000002 + +/* + * WMI Dual Band Simultaneous (DBS) hardware mode list bit-mask definitions. + * Bits 5:0 are reserved + */ +#define WMI_DBS_HW_MODE_MAC0_TX_STREAMS_BITPOS (28) +#define WMI_DBS_HW_MODE_MAC0_RX_STREAMS_BITPOS (24) +#define WMI_DBS_HW_MODE_MAC1_TX_STREAMS_BITPOS (20) +#define WMI_DBS_HW_MODE_MAC1_RX_STREAMS_BITPOS (16) +#define WMI_DBS_HW_MODE_MAC0_BANDWIDTH_BITPOS (12) +#define WMI_DBS_HW_MODE_MAC1_BANDWIDTH_BITPOS (8) +#define WMI_DBS_HW_MODE_DBS_MODE_BITPOS (7) +#define WMI_DBS_HW_MODE_AGILE_DFS_MODE_BITPOS (6) + +#define WMI_DBS_HW_MODE_MAC0_TX_STREAMS_MASK (0xf << WMI_DBS_HW_MODE_MAC0_TX_STREAMS_BITPOS) +#define WMI_DBS_HW_MODE_MAC0_RX_STREAMS_MASK (0xf << WMI_DBS_HW_MODE_MAC0_RX_STREAMS_BITPOS) +#define WMI_DBS_HW_MODE_MAC1_TX_STREAMS_MASK (0xf << WMI_DBS_HW_MODE_MAC1_TX_STREAMS_BITPOS) +#define WMI_DBS_HW_MODE_MAC1_RX_STREAMS_MASK (0xf << WMI_DBS_HW_MODE_MAC1_RX_STREAMS_BITPOS) +#define WMI_DBS_HW_MODE_MAC0_BANDWIDTH_MASK (0xf << WMI_DBS_HW_MODE_MAC0_BANDWIDTH_BITPOS) +#define WMI_DBS_HW_MODE_MAC1_BANDWIDTH_MASK (0xf << WMI_DBS_HW_MODE_MAC1_BANDWIDTH_BITPOS) +#define WMI_DBS_HW_MODE_DBS_MODE_MASK (0x1 << WMI_DBS_HW_MODE_DBS_MODE_BITPOS) +#define WMI_DBS_HW_MODE_AGILE_DFS_MODE_MASK (0x1 << WMI_DBS_HW_MODE_AGILE_DFS_MODE_BITPOS) + +#define WMI_DBS_HW_MODE_MAC0_TX_STREAMS_SET(hw_mode, value) \ + WMI_SET_BITS(hw_mode, WMI_DBS_HW_MODE_MAC0_TX_STREAMS_BITPOS, 4, value) +#define WMI_DBS_HW_MODE_MAC0_RX_STREAMS_SET(hw_mode, value) \ + WMI_SET_BITS(hw_mode, WMI_DBS_HW_MODE_MAC0_RX_STREAMS_BITPOS, 4, value) +#define WMI_DBS_HW_MODE_MAC1_TX_STREAMS_SET(hw_mode, value) \ + WMI_SET_BITS(hw_mode, WMI_DBS_HW_MODE_MAC1_TX_STREAMS_BITPOS, 4, value) +#define WMI_DBS_HW_MODE_MAC1_RX_STREAMS_SET(hw_mode, value) \ + WMI_SET_BITS(hw_mode, WMI_DBS_HW_MODE_MAC1_RX_STREAMS_BITPOS, 4, value) +#define WMI_DBS_HW_MODE_MAC0_BANDWIDTH_SET(hw_mode, value) \ + WMI_SET_BITS(hw_mode, WMI_DBS_HW_MODE_MAC0_BANDWIDTH_BITPOS, 4, value) +#define WMI_DBS_HW_MODE_MAC1_BANDWIDTH_SET(hw_mode, value) \ + WMI_SET_BITS(hw_mode, WMI_DBS_HW_MODE_MAC1_BANDWIDTH_BITPOS, 4, value) +#define WMI_DBS_HW_MODE_DBS_MODE_SET(hw_mode, value) \ + WMI_SET_BITS(hw_mode, WMI_DBS_HW_MODE_DBS_MODE_BITPOS, 1, value) +#define WMI_DBS_HW_MODE_AGILE_DFS_SET(hw_mode, value) \ + WMI_SET_BITS(hw_mode, WMI_DBS_HW_MODE_AGILE_DFS_MODE_BITPOS, 1, value) + +#define WMI_DBS_HW_MODE_MAC0_TX_STREAMS_GET(hw_mode) \ + ((hw_mode & WMI_DBS_HW_MODE_MAC0_TX_STREAMS_MASK) >> WMI_DBS_HW_MODE_MAC0_TX_STREAMS_BITPOS) +#define WMI_DBS_HW_MODE_MAC0_RX_STREAMS_GET(hw_mode) \ + ((hw_mode & WMI_DBS_HW_MODE_MAC0_RX_STREAMS_MASK) >> WMI_DBS_HW_MODE_MAC0_RX_STREAMS_BITPOS) +#define WMI_DBS_HW_MODE_MAC1_TX_STREAMS_GET(hw_mode) \ + ((hw_mode & WMI_DBS_HW_MODE_MAC1_TX_STREAMS_MASK) >> WMI_DBS_HW_MODE_MAC1_TX_STREAMS_BITPOS) +#define WMI_DBS_HW_MODE_MAC1_RX_STREAMS_GET(hw_mode) \ + ((hw_mode & WMI_DBS_HW_MODE_MAC1_RX_STREAMS_MASK) >> WMI_DBS_HW_MODE_MAC1_RX_STREAMS_BITPOS) +#define WMI_DBS_HW_MODE_MAC0_BANDWIDTH_GET(hw_mode) \ + ((hw_mode & WMI_DBS_HW_MODE_MAC0_BANDWIDTH_MASK) >> WMI_DBS_HW_MODE_MAC0_BANDWIDTH_BITPOS) +#define WMI_DBS_HW_MODE_MAC1_BANDWIDTH_GET(hw_mode) \ + ((hw_mode & WMI_DBS_HW_MODE_MAC1_BANDWIDTH_MASK) >> WMI_DBS_HW_MODE_MAC1_BANDWIDTH_BITPOS) +#define WMI_DBS_HW_MODE_DBS_MODE_GET(hw_mode) \ + ((hw_mode & WMI_DBS_HW_MODE_DBS_MODE_MASK) >> WMI_DBS_HW_MODE_DBS_MODE_BITPOS) +#define WMI_DBS_HW_MODE_AGILE_DFS_GET(hw_mode) \ + ((hw_mode & WMI_DBS_HW_MODE_AGILE_DFS_MODE_MASK) >> WMI_DBS_HW_MODE_AGILE_DFS_MODE_BITPOS) + +#define WMI_DBS_CONC_SCAN_CFG_DBS_SCAN_BITPOS (31) +#define WMI_DBS_CONC_SCAN_CFG_AGILE_SCAN_BITPOS (30) +#define WMI_DBS_CONC_SCAN_CFG_AGILE_DFS_SCAN_BITPOS (29) +#define WMI_DBS_CONC_SCAN_CFG_ASYNC_DBS_SCAN_BITPOS (28) +#define WMI_DBS_CONC_SCAN_CFG_SYNC_DBS_SCAN_BITPOS (27) + +#define WMI_DBS_CONC_SCAN_CFG_DBS_SCAN_MASK (0x1 << WMI_DBS_CONC_SCAN_CFG_DBS_SCAN_BITPOS) +#define WMI_DBS_CONC_SCAN_CFG_AGILE_SCAN_MASK (0x1 << WMI_DBS_CONC_SCAN_CFG_AGILE_SCAN_BITPOS) +#define WMI_DBS_CONC_SCAN_CFG_AGILE_DFS_SCAN_MASK (0x1 << WMI_DBS_CONC_SCAN_CFG_AGILE_DFS_SCAN_BITPOS) +#define WMI_DBS_CONC_SCAN_CFG_ASYC_DBS_SCAN_MASK (0x1 << WMI_DBS_CONC_SCAN_CFG_ASYNC_DBS_SCAN_BITPOS) +#define WMI_DBS_CONC_SCAN_CFG_SYNC_DBS_SCAN_MASK (0x1 << WMI_DBS_CONC_SCAN_CFG_SYNC_DBS_SCAN_BITPOS) + +#define WMI_DBS_CONC_SCAN_CFG_DBS_SCAN_SET(scan_cfg, value) \ + WMI_SET_BITS(scan_cfg, WMI_DBS_CONC_SCAN_CFG_DBS_SCAN_BITPOS, 1, value) +#define WMI_DBS_CONC_SCAN_CFG_AGILE_SCAN_SET(scan_cfg, value) \ + WMI_SET_BITS(scan_cfg, WMI_DBS_CONC_SCAN_CFG_AGILE_SCAN_BITPOS, 1, value) +#define WMI_DBS_CONC_SCAN_CFG_AGILE_DFS_SCAN_SET(scan_cfg, value) \ + WMI_SET_BITS(scan_cfg, WMI_DBS_CONC_SCAN_CFG_AGILE_DFS_SCAN_BITPOS, 1, value) +#define WMI_DBS_CONC_SCAN_CFG_ASYNC_DBS_SCAN_SET(scan_cfg, value) \ + WMI_SET_BITS(scan_cfg, WMI_DBS_CONC_SCAN_CFG_ASYNC_DBS_SCAN_BITPOS, 1, value) +#define WMI_DBS_CONC_SCAN_CFG_SYNC_DBS_SCAN_SET(scan_cfg, value) \ + WMI_SET_BITS(scan_cfg, WMI_DBS_CONC_SCAN_CFG_SYNC_DBS_SCAN_BITPOS, 1, value) + +#define WMI_DBS_CONC_SCAN_CFG_DBS_SCAN_GET(scan_cfg) \ + ((scan_cfg & WMI_DBS_CONC_SCAN_CFG_DBS_SCAN_MASK) >> WMI_DBS_CONC_SCAN_CFG_DBS_SCAN_BITPOS) +#define WMI_DBS_CONC_SCAN_CFG_AGILE_SCAN_GET(scan_cfg) \ + ((scan_cfg & WMI_DBS_CONC_SCAN_CFG_AGILE_SCAN_MASK) >> WMI_DBS_CONC_SCAN_CFG_AGILE_SCAN_BITPOS) +#define WMI_DBS_CONC_SCAN_CFG_AGILE_DFS_SCAN_GET(scan_cfg) \ + ((scan_cfg & WMI_DBS_CONC_SCAN_CFG_AGILE_DFS_SCAN_MASK) >> WMI_DBS_CONC_SCAN_CFG_AGILE_DFS_SCAN_BITPOS) +#define WMI_DBS_CONC_SCAN_CFG_ASYNC_DBS_SCAN_GET(scan_cfg) \ + ((scan_cfg & WMI_DBS_CONC_SCAN_CFG_ASYC_DBS_SCAN_MASK) >> WMI_DBS_CONC_SCAN_CFG_ASYNC_DBS_SCAN_BITPOS) +#define WMI_DBS_CONC_SCAN_CFG_SYNC_DBS_SCAN_GET(scan_cfg) \ + ((scan_cfg & WMI_DBS_CONC_SCAN_CFG_SYNC_DBS_SCAN_MASK) >> WMI_DBS_CONC_SCAN_CFG_SYNC_DBS_SCAN_BITPOS) + +#define WMI_DBS_FW_MODE_CFG_DBS_BITPOS (31) +#define WMI_DBS_FW_MODE_CFG_AGILE_DFS_BITPOS (30) +#define WMI_DBS_FW_MODE_CFG_DBS_FOR_CXN_BITPOS (29) + +#define WMI_DBS_FW_MODE_CFG_DBS_MASK (0x1 << WMI_DBS_FW_MODE_CFG_DBS_BITPOS) +#define WMI_DBS_FW_MODE_CFG_AGILE_DFS_MASK (0x1 << WMI_DBS_FW_MODE_CFG_AGILE_DFS_BITPOS) +#define WMI_DBS_FW_MODE_CFG_DBS_FOR_CXN_DFS_MASK (0x1 << WMI_DBS_FW_MODE_CFG_DBS_FOR_CXN_BITPOS) + +#define WMI_DBS_FW_MODE_CFG_DBS_SET(fw_mode, value) \ + WMI_SET_BITS(fw_mode, WMI_DBS_FW_MODE_CFG_DBS_BITPOS, 1, value) +#define WMI_DBS_FW_MODE_CFG_AGILE_DFS_SET(fw_mode, value) \ + WMI_SET_BITS(fw_mode, WMI_DBS_FW_MODE_CFG_AGILE_DFS_BITPOS, 1, value) +#define WMI_DBS_FW_MODE_CFG_DBS_FOR_CXN_SET(fw_mode, value) \ + WMI_SET_BITS(fw_mode, WMI_DBS_FW_MODE_CFG_DBS_FOR_CXN_BITPOS, 1, value) + +#define WMI_DBS_FW_MODE_CFG_DBS_GET(fw_mode) \ + ((fw_mode & WMI_DBS_FW_MODE_CFG_DBS_MASK) >> WMI_DBS_FW_MODE_CFG_DBS_BITPOS) +#define WMI_DBS_FW_MODE_CFG_AGILE_DFS_GET(fw_mode) \ + ((fw_mode & WMI_DBS_FW_MODE_CFG_AGILE_DFS_MASK) >> WMI_DBS_FW_MODE_CFG_AGILE_DFS_BITPOS) +#define WMI_DBS_FW_MODE_CFG_DBS_FOR_CXN_GET(fw_mode) \ + ((fw_mode & WMI_DBS_FW_MODE_CFG_DBS_FOR_CXN_DFS_MASK) >> WMI_DBS_FW_MODE_CFG_DBS_FOR_CXN_BITPOS) + + +/** NOTE: This structure cannot be extended in the future without breaking WMI compatibility */ +typedef struct _wmi_abi_version { + A_UINT32 abi_version_0; /** WMI Major and Minor versions */ + A_UINT32 abi_version_1; /** WMI change revision */ + A_UINT32 abi_version_ns_0; /** ABI version namespace first four dwords */ + A_UINT32 abi_version_ns_1; /** ABI version namespace second four dwords */ + A_UINT32 abi_version_ns_2; /** ABI version namespace third four dwords */ + A_UINT32 abi_version_ns_3; /** ABI version namespace fourth four dwords */ +} wmi_abi_version; + +/* + * maximum number of memroy requests allowed from FW. + */ +#define WMI_MAX_MEM_REQS 16 + +/* !!NOTE!!: + * This HW_BD_INFO_SIZE cannot be changed without breaking compatibility. + * Please don't change it. + */ +#define HW_BD_INFO_SIZE 5 + +/** + * PDEV ID to identify the physical device, + * value 0 reserved for SOC level commands/event + */ +#define WMI_PDEV_ID_SOC 0 /* SOC level, applicable to all PDEVs */ +#define WMI_PDEV_ID_1ST 1 /* first pdev (pdev 0) */ +#define WMI_PDEV_ID_2ND 2 /* second pdev (pdev 1) */ +#define WMI_PDEV_ID_3RD 3 /* third pdev (pdev 2) */ + +/** + * The following struct holds optional payload for + * wmi_service_ready_event_fixed_param,e.g., 11ac pass some of the + * device capability to the host. + */ +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_WMI_SERVICE_READY_EVENT */ + A_UINT32 fw_build_vers; /* firmware build number */ + wmi_abi_version fw_abi_vers; + A_UINT32 phy_capability; /* WMI_PHY_CAPABILITY */ + A_UINT32 max_frag_entry; /* Maximum number of frag table entries that SW will populate less 1 */ + A_UINT32 num_rf_chains; + /* The following field is only valid for service type WMI_SERVICE_11AC */ + A_UINT32 ht_cap_info; /* WMI HT Capability */ + A_UINT32 vht_cap_info; /* VHT capability info field of 802.11ac */ + A_UINT32 vht_supp_mcs; /* VHT Supported MCS Set field Rx/Tx same */ + A_UINT32 hw_min_tx_power; + A_UINT32 hw_max_tx_power; + A_UINT32 sys_cap_info; + A_UINT32 min_pkt_size_enable; /* Enterprise mode short pkt enable */ + /** Max beacon and Probe Response IE offload size (includes + * optional P2P IEs) */ + A_UINT32 max_bcn_ie_size; + /* + * request to host to allocate a chuck of memory and pss it down to FW via WM_INIT. + * FW uses this as FW extesnsion memory for saving its data structures. Only valid + * for low latency interfaces like PCIE where FW can access this memory directly (or) + * by DMA. + */ + A_UINT32 num_mem_reqs; + /* Max No. scan channels target can support + * If FW is too old and doesn't indicate this number, host side value will default to + * 0, and host will take the original compatible value (62) for future scan channel + * setup. + */ + A_UINT32 max_num_scan_channels; + + /* Hardware board specific ID. Values defined in enum WMI_HWBOARD_ID. + * Default 0 means tha hw_bd_info[] is invalid(legacy board). + */ + A_UINT32 hw_bd_id; + A_UINT32 hw_bd_info[HW_BD_INFO_SIZE]; /* Board specific information. Invalid if hw_hd_id is zero. */ + + /* + * Number of MACs supported, i.e. a DBS-capable device will return 2 + */ + A_UINT32 max_supported_macs; + + /* + * FW sub-feature capabilities to be used in concurrence with wmi_service_bitmap + */ + A_UINT32 wmi_fw_sub_feat_caps; /* values from enum WMI_FW_SUB_FEAT_CAPS */ + + /* + * Number of Dual Band Simultaneous (DBS) hardware modes + */ + A_UINT32 num_dbs_hw_modes; + + /* + * txrx_chainmask + * [7:0] - 2G band tx chain mask + * [15:8] - 2G band rx chain mask + * [23:16] - 5G band tx chain mask + * [31:24] - 5G band rx chain mask + * + */ + A_UINT32 txrx_chainmask; + + /* + * default Dual Band Simultaneous (DBS) hardware mode + */ + A_UINT32 default_dbs_hw_mode_index; + + /* + * Number of msdu descriptors target would use + */ + A_UINT32 num_msdu_desc; + +/* The TLVs for hal_reg_capabilities, wmi_service_bitmap and mem_reqs[] will follow this TLV. + * HAL_REG_CAPABILITIES hal_reg_capabilities; + * A_UINT32 wmi_service_bitmap[WMI_SERVICE_BM_SIZE]; + * wlan_host_mem_req mem_reqs[]; + * wlan_dbs_hw_mode_list[]; + */ +} wmi_service_ready_event_fixed_param; + +#define WMI_SERVICE_SEGMENT_BM_SIZE32 4 /* 4x A_UINT32 = 128 bits */ +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_service_available_event_fixed_param */ + /* + * The wmi_service_segment offset field specifies the position within the + * logical bitmap of WMI service flags at which the WMI service flags + * specified within this message begin. + * Since the first 128 WMI service flags are specified within the + * wmi_service_bitmap field of the WMI_SERVICE_READY_EVENT message, + * the wmi_service_segment_offset value is expected to be 128 or more. + */ + A_UINT32 wmi_service_segment_offset; + A_UINT32 wmi_service_segment_bitmap[WMI_SERVICE_SEGMENT_BM_SIZE32]; +} wmi_service_available_event_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_WMI_SERVICE_EXT_READY_EVENT */ + /* which WMI_DBS_CONC_SCAN_CFG setting the FW is initialized with */ + A_UINT32 default_conc_scan_config_bits; + /* which WMI_DBS_FW_MODE_CFG setting the FW is initialized with */ + A_UINT32 default_fw_config_bits; + wmi_ppe_threshold ppet; + A_UINT32 he_cap_info; /* see section 8.4.2.213 from draft r8 of 802.11ax; see WMI_HE_FRAG_SUPPORT enum */ + /* + * An HT STA shall not allow transmission of more than one MPDU start + * within the time limit described in the MPDU maximum density field. + */ + A_UINT32 mpdu_density; /* units are microseconds */ + /* + * Maximum no of BSSID based RX filters host can program + * Value 0 means FW hasn't given any limit to host. + */ + A_UINT32 max_bssid_rx_filters; + /* + * Extended FW build version information: + * bits 27:0 -> reserved + * bits 31:28 -> CRM sub ID + */ + A_UINT32 fw_build_vers_ext; +} wmi_service_ready_ext_event_fixed_param; + +typedef enum { + WMI_FW_STA_RTT_INITR = 0x00000001, + WMI_FW_STA_RTT_RESPR = 0x00000002, + WMI_FW_P2P_CLI_RTT_INITR = 0x00000004, + WMI_FW_P2P_CLI_RTT_RESPR = 0x00000008, + WMI_FW_P2P_GO_RTT_INITR = 0x00000010, + WMI_FW_P2P_GO_RTT_RESPR = 0x00000020, + WMI_FW_AP_RTT_INITR = 0x00000040, + WMI_FW_AP_RTT_RESPR = 0x00000080, + WMI_FW_NAN_RTT_INITR = 0x00000100, + WMI_FW_NAN_RTT_RESPR = 0x00000200, + WMI_FW_SCAN_DBS_POLICY = 0x00000400, + /* + * New fw sub feature capabilites before + * WMI_FW_MAX_SUB_FEAT_CAP + */ + WMI_FW_MAX_SUB_FEAT_CAP = 0x80000000, +} WMI_FW_SUB_FEAT_CAPS; + +typedef enum { + WMI_HWBD_NONE = 0, /* No hw board information is given */ + WMI_HWBD_QCA6174 = 1, /* Rome(AR6320) */ + WMI_HWBD_QCA2582 = 2, /* Killer 1525*/ +} WMI_HWBD_ID; + +#define ATH_BD_DATA_REV_MASK 0x000000FF +#define ATH_BD_DATA_REV_SHIFT 0 + +#define ATH_BD_DATA_PROJ_ID_MASK 0x0000FF00 +#define ATH_BD_DATA_PROJ_ID_SHIFT 8 + +#define ATH_BD_DATA_CUST_ID_MASK 0x00FF0000 +#define ATH_BD_DATA_CUST_ID_SHIFT 16 + +#define ATH_BD_DATA_REF_DESIGN_ID_MASK 0xFF000000 +#define ATH_BD_DATA_REF_DESIGN_ID_SHIFT 24 + +#define SET_BD_DATA_REV(bd_data_ver, value) \ + ((bd_data_ver) &= ~ATH_BD_DATA_REV_MASK, (bd_data_ver) |= ((value) << ATH_BD_DATA_REV_SHIFT)) + +#define GET_BD_DATA_REV(bd_data_ver) \ + (((bd_data_ver) & ATH_BD_DATA_REV_MASK) >> ATH_BD_DATA_REV_SHIFT) + +#define SET_BD_DATA_PROJ_ID(bd_data_ver, value) \ + ((bd_data_ver) &= ~ATH_BD_DATA_PROJ_ID_MASK, (bd_data_ver) |= ((value) << ATH_BD_DATA_PROJ_ID_SHIFT)) + +#define GET_BD_DATA_PROJ_ID(bd_data_ver) \ + (((bd_data_ver) & ATH_BD_DATA_PROJ_ID_MASK) >> ATH_BD_DATA_PROJ_ID_SHIFT) + +#define SET_BD_DATA_CUST_ID(bd_data_ver, value) \ + ((bd_data_ver) &= ~ATH_BD_DATA_CUST_ID_MASK, (bd_data_ver) |= ((value) << ATH_BD_DATA_CUST_ID_SHIFT)) + +#define GET_BD_DATA_CUST_ID(bd_data_ver) \ + (((bd_data_ver) & ATH_BD_DATA_CUST_ID_MASK) >> ATH_BD_DATA_CUST_ID_SHIFT) + +#define SET_BD_DATA_REF_DESIGN_ID(bd_data_ver, value) \ + ((bd_data_ver) &= ~ATH_BD_DATA_REF_DESIGN_ID_MASK, (bd_data_ver) |= ((value) << ATH_BD_DATA_REF_DESIGN_ID_SHIFT)) + +#define GET_BD_DATA_REF_DESIGN_ID(bd_data_ver) \ + (((bd_data_ver) & ATH_BD_DATA_REF_DESIGN_ID_MASK) >> ATH_BD_DATA_REF_DESIGN_ID_SHIFT) + + +#ifdef ROME_LTE_COEX_FREQ_AVOID +typedef struct { + A_UINT32 start_freq; /* start frequency, not channel center freq */ + A_UINT32 end_freq; /* end frequency */ +} avoid_freq_range_desc; + +typedef struct { + /* bad channel range count, multi range is allowed, 0 means all channel clear */ + A_UINT32 num_freq_ranges; + /* multi range with num_freq_ranges, LTE advance multi carrier, CDMA,etc */ + avoid_freq_range_desc avd_freq_range[0]; +} wmi_wlan_avoid_freq_ranges_event; +#endif + +/** status consists of upper 16 bits fo A_STATUS status and lower 16 bits of module ID that retuned status */ +#define WLAN_INIT_STATUS_SUCCESS 0x0 +#define WLAN_INIT_STATUS_GEN_FAILED 0x1 +#define WLAN_GET_INIT_STATUS_REASON(status) ((status) & 0xffff) +#define WLAN_GET_INIT_STATUS_MODULE_ID(status) (((status) >> 16) & 0xffff) + +typedef A_UINT32 WLAN_INIT_STATUS; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_ready_event_fixed_param */ + wmi_abi_version fw_abi_vers; + /* + * mac_addr is always filled; in addition, there can be a mac_addr_list + * TLV following this fixed_param TLV to specify additional MAC addresses, + * for cases where the target specifies one MAC address per pdev + * (so the host can treat the pdevs within the target as separately + * as possible) rather than one MAC address for the whole SOC. + */ + wmi_mac_addr mac_addr; + A_UINT32 status; + A_UINT32 num_dscp_table; + /* num_extra_mac_addr - + * how many additional MAC addresses besides the above mac_addr + * are provided in the subsequent mac_addr_list TLV + */ + A_UINT32 num_extra_mac_addr; +/* + * This fixed_param TLV is followed by these additional TLVs: + * mac_addr_list[num_extra_mac_addr]; + */ +} wmi_ready_event_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_resource_config */ + /** + * @brief num_vdev - number of virtual devices (VAPs) to support + */ + A_UINT32 num_vdevs; + /** + * @brief num_peers - number of peer nodes to support + */ + A_UINT32 num_peers; + /* + * @brief In offload mode target supports features like WOW, chatter and other + * protocol offloads. In order to support them some functionalities like + * reorder buffering, PN checking need to be done in target. This determines + * maximum number of peers suported by target in offload mode + */ + A_UINT32 num_offload_peers; + /* @brief Number of reorder buffers available for doing target based reorder + * Rx reorder buffering + */ + A_UINT32 num_offload_reorder_buffs; + /** + * @brief num_peer_keys - number of keys per peer + */ + A_UINT32 num_peer_keys; + /** + * @brief num_peer_tids - number of TIDs to provide storage for per peer. + */ + A_UINT32 num_tids; + /** + * @brief ast_skid_limit - max skid for resolving hash collisions + * @details + * The address search table is sparse, so that if two MAC addresses + * result in the same hash value, the second of these conflicting + * entries can slide to the next index in the address search table, + * and use it, if it is unoccupied. This ast_skid_limit parameter + * specifies the upper bound on how many subsequent indices to search + * over to find an unoccupied space. + */ + A_UINT32 ast_skid_limit; + /** + * @brief tx_chain_mask - the nominal chain mask for transmit + * @details + * The chain mask may be modified dynamically, e.g. to operate AP tx with + * a reduced number of chains if no clients are associated. + * This configuration parameter specifies the nominal chain-mask that + * should be used when not operating with a reduced set of tx chains. + */ + A_UINT32 tx_chain_mask; + /** + * @brief rx_chain_mask - the nominal chain mask for receive + * @details + * The chain mask may be modified dynamically, e.g. for a client to use + * a reduced number of chains for receive if the traffic to the client + * is low enough that it doesn't require downlink MIMO or antenna + * diversity. + * This configuration parameter specifies the nominal chain-mask that + * should be used when not operating with a reduced set of rx chains. + */ + A_UINT32 rx_chain_mask; + /** + * @brief rx_timeout_pri - what rx reorder timeout (ms) to use for the AC + * @details + * Each WMM access class (voice, video, best-effort, background) will + * have its own timeout value to dictate how long to wait for missing + * rx MPDUs to arrive before flushing subsequent MPDUs that have already + * been received. + * This parameter specifies the timeout in milliseconds for each class . + * NOTE: the number of class (defined as 4) cannot be + * changed in the future without breaking WMI compatibility. + */ + A_UINT32 rx_timeout_pri[4]; + /** + * @brief rx_decap mode - what mode the rx should decap packets to + * @details + * MAC can decap to RAW (no decap), native wifi or Ethernet types + * THis setting also determines the default TX behavior, however TX + * behavior can be modified on a per VAP basis during VAP init + */ + A_UINT32 rx_decap_mode; + /** + * @brief scan_max_pending_req - what is the maximum scan requests than can be queued + */ + A_UINT32 scan_max_pending_req; + + /** + * @brief maximum VDEV that could use BMISS offload + */ + A_UINT32 bmiss_offload_max_vdev; + + /** + * @brief maximum VDEV that could use offload roaming + */ + A_UINT32 roam_offload_max_vdev; + + /** + * @brief maximum AP profiles that would push to offload roaming + */ + A_UINT32 roam_offload_max_ap_profiles; + + /** + * @brief num_mcast_groups - how many groups to use for mcast->ucast conversion + * @details + * The target's WAL maintains a table to hold information regarding which + * peers belong to a given multicast group, so that if multicast->unicast + * conversion is enabled, the target can convert multicast tx frames to a + * series of unicast tx frames, to each peer within the multicast group. + * This num_mcast_groups configuration parameter tells the target how + * many multicast groups to provide storage for within its multicast + * group membership table. + */ + A_UINT32 num_mcast_groups; + + /** + * @brief num_mcast_table_elems - size to alloc for the mcast membership table + * @details + * This num_mcast_table_elems configuration parameter tells the target + * how many peer elements it needs to provide storage for in its + * multicast group membership table. + * These multicast group membership table elements are shared by the + * multicast groups stored within the table. + */ + A_UINT32 num_mcast_table_elems; + + /** + * @brief mcast2ucast_mode - whether/how to do multicast->unicast conversion + * @details + * This configuration parameter specifies whether the target should + * perform multicast --> unicast conversion on transmit, and if so, + * what to do if it finds no entries in its multicast group membership + * table for the multicast IP address in the tx frame. + * Configuration value: + * 0 -> Do not perform multicast to unicast conversion. + * 1 -> Convert multicast frames to unicast, if the IP multicast address + * from the tx frame is found in the multicast group membership + * table. If the IP multicast address is not found, drop the frame. + * 2 -> Convert multicast frames to unicast, if the IP multicast address + * from the tx frame is found in the multicast group membership + * table. If the IP multicast address is not found, transmit the + * frame as multicast. + */ + A_UINT32 mcast2ucast_mode; + + + /** + * @brief tx_dbg_log_size - how much memory to allocate for a tx PPDU dbg log + * @details + * This parameter controls how much memory the target will allocate to + * store a log of tx PPDU meta-information (how large the PPDU was, + * when it was sent, whether it was successful, etc.) + */ + A_UINT32 tx_dbg_log_size; + + /** + * @brief num_wds_entries - how many AST entries to be allocated for WDS + */ + A_UINT32 num_wds_entries; + + /** + * @brief dma_burst_size - MAC DMA burst size, e.g., on Peregrine on PCI + * this limit can be 0 -default, 1 256B + */ + A_UINT32 dma_burst_size; + + /** + * @brief mac_aggr_delim - Fixed delimiters to be inserted after every MPDU + * to account for interface latency to avoid underrun. + */ + A_UINT32 mac_aggr_delim; + /** + * @brief rx_skip_defrag_timeout_dup_detection_check + * @details + * determine whether target is responsible for detecting duplicate + * non-aggregate MPDU and timing out stale fragments. + * + * A-MPDU reordering is always performed on the target. + * + * 0: target responsible for frag timeout and dup checking + * 1: host responsible for frag timeout and dup checking + */ + A_UINT32 rx_skip_defrag_timeout_dup_detection_check; + + /** + * @brief vow_config - Configuration for VoW : No of Video Nodes to be supported + * and Max no of descriptors for each Video link (node). + */ + A_UINT32 vow_config; + + /** + * @brief maximum VDEV that could use GTK offload + */ + A_UINT32 gtk_offload_max_vdev; + + /** + * @brief num_msdu_desc - Number of msdu descriptors target should use + */ + A_UINT32 num_msdu_desc; /* Number of msdu desc */ + /** + * @brief max_frag_entry - Max. number of Tx fragments per MSDU + * @details + * This parameter controls the max number of Tx fragments per MSDU. + * This is sent by the target as part of the WMI_SERVICE_READY event + * and is overriden by the OS shim as required. + */ + A_UINT32 max_frag_entries; + + /** + * @brief num_tdls_vdevs - Max. number of vdevs that can support TDLS + * @brief num_msdu_desc - Number of vdev that can support beacon offload + */ + + A_UINT32 num_tdls_vdevs; /* number of vdevs allowed to do tdls */ + + /** + * @brief num_tdls_conn_table_entries - Number of peers tracked by tdls vdev + * @details + * Each TDLS enabled vdev can track outgoing transmits/rssi/rates to/of + * peers in a connection tracking table for possible TDLS link creation + * or deletion. This controls the number of tracked peers per vdev. + */ + A_UINT32 num_tdls_conn_table_entries; /* number of peers to track per TDLS vdev */ + A_UINT32 beacon_tx_offload_max_vdev; + A_UINT32 num_multicast_filter_entries; + A_UINT32 num_wow_filters; /*host can configure the number of wow filters*/ + + /** + * @brief num_keep_alive_pattern - Num of keep alive patterns configured + * from host. + */ + A_UINT32 num_keep_alive_pattern; + /** + * @brief keep_alive_pattern_size - keep alive pattern size. + */ + A_UINT32 keep_alive_pattern_size; + /** + * @brief max_tdls_concurrent_sleep_sta - Number of tdls sleep sta supported + * @details + * Each TDLS STA can become a sleep STA independently. This parameter + * mentions how many such sleep STAs can be supported concurrently. + */ + A_UINT32 max_tdls_concurrent_sleep_sta; + + /** + * @brief max_tdls_concurrent_buffer_sta - Number of tdls buffer sta supported + * @details + * Each TDLS STA can become a buffer STA independently. This parameter + * mentions how many such buffer STAs can be supported concurrently. + */ + A_UINT32 max_tdls_concurrent_buffer_sta; + + /** + * @brief wmi_send_separate - host configures fw to send the wmi separately + */ + A_UINT32 wmi_send_separate; + + /** + * @brief num_ocb_vdevs - Number of vdevs used for OCB support + */ + A_UINT32 num_ocb_vdevs; + + /** + * @brief num_ocb_channels - The supported number of simultaneous OCB channels + */ + A_UINT32 num_ocb_channels; + + /** + * @brief num_ocb_schedules - The supported number of OCB schedule segments + */ + A_UINT32 num_ocb_schedules; + + /** + * @brief specific configuration from host, such as per platform configuration + */ + #define WMI_RSRC_CFG_FLAG_WOW_IGN_PCIE_RST_S 0 + #define WMI_RSRC_CFG_FLAG_WOW_IGN_PCIE_RST_M 0x1 + + #define WMI_RSRC_CFG_FLAG_LTEU_SUPPORT_S 1 + #define WMI_RSRC_CFG_FLAG_LTEU_SUPPORT_M 0x2 + + #define WMI_RSRC_CFG_FLAG_COEX_GPIO_SUPPORT_S 2 + #define WMI_RSRC_CFG_FLAG_COEX_GPIO_SUPPORT_M 0x4 + + #define WMI_RSRC_CFG_FLAG_AUX_RADIO_SPECTRAL_INTF_S 3 + #define WMI_RSRC_CFG_FLAG_AUX_RADIO_SPECTRAL_INTF_M 0x8 + + #define WMI_RSRC_CFG_FLAG_AUX_RADIO_CHAN_LOAD_INTF_S 4 + #define WMI_RSRC_CFG_FLAG_AUX_RADIO_CHAN_LOAD_INTF_M 0x10 + + #define WMI_RSRC_CFG_FLAG_BSS_CHANNEL_INFO_64_S 5 + #define WMI_RSRC_CFG_FLAG_BSS_CHANNEL_INFO_64_M 0x20 + + #define WMI_RSRC_CFG_FLAG_ATF_CONFIG_ENABLE_S 6 + #define WMI_RSRC_CFG_FLAG_ATF_CONFIG_ENABLE_M 0x40 + + #define WMI_RSRC_CFG_FLAG_IPHR_PAD_CONFIG_ENABLE_S 7 + #define WMI_RSRC_CFG_FLAG_IPHR_PAD_CONFIG_ENABLE_M 0x80 + + #define WMI_RSRC_CFG_FLAG_QWRAP_MODE_ENABLE_S 8 + #define WMI_RSRC_CFG_FLAG_QWRAP_MODE_ENABLE_M 0x100 + + #define WMI_RSRC_CFG_FLAG_MGMT_COMP_EVT_BUNDLE_SUPPORT_S 9 + #define WMI_RSRC_CFG_FLAG_MGMT_COMP_EVT_BUNDLE_SUPPORT_M 0x200 + + #define WMI_RSRC_CFG_FLAG_TX_MSDU_ID_NEW_PARTITION_SUPPORT_S 10 + #define WMI_RSRC_CFG_FLAG_TX_MSDU_ID_NEW_PARTITION_SUPPORT_M 0x400 + + #define WMI_RSRC_CFG_FLAG_TX_PPDU_STATS_ENABLE_S 11 + #define WMI_RSRC_CFG_FLAG_TX_PPDU_STATS_ENABLE_M 0x800 + + A_UINT32 flag1; + + /** @brief smart_ant_cap - Smart Antenna capabilities information + * @details + * 1 - Smart antenna is enabled. + * 0 - Smart antenna is disabled. + * In future this can contain smart antenna specifc capabilities. + */ + A_UINT32 smart_ant_cap; + + /** + * User can configure the buffers allocated for each AC (BE, BK, VI, VO) + * during init + */ + A_UINT32 BK_Minfree; + A_UINT32 BE_Minfree; + A_UINT32 VI_Minfree; + A_UINT32 VO_Minfree; + + /** + * @brief alloc_frag_desc_for_data_pkt . Controls data packet fragment + * descriptor memory allocation. + * 1 - Allocate fragment descriptor memory for data packet in firmware. + * If host wants to transmit data packet at its desired rate, + * this field must be set. + * 0 - Don't allocate fragment descriptor for data packet. + */ + A_UINT32 alloc_frag_desc_for_data_pkt; + + /** how much space to allocate for NDP NS (neighbor solicitation) specs */ + A_UINT32 num_ns_ext_tuples_cfg; + + /** + * size (in bytes) of the buffer the FW shall allocate to store + * packet filtering instructions + */ + A_UINT32 bpf_instruction_size; + + /** + * Maximum no of BSSID based RX filters host would program + * Value 0 means host doesn't given any limit to FW. + */ + A_UINT32 max_bssid_rx_filters; + /** + * Use PDEV ID instead of MAC ID, added for backward compatibility with older host + * which is using MAC ID. 1 means PDEV ID, 0 means MAC ID. + */ + A_UINT32 use_pdev_id; + + /** Maximum number of scan clients whose DBS scan duty cycle can be configured */ + A_UINT32 max_num_dbs_scan_duty_cycle; +} wmi_resource_config; + +#define WMI_RSRC_CFG_FLAG_SET(word32, flag, value) \ + do { \ + (word32) &= ~WMI_RSRC_CFG_FLAG_ ## flag ## _M; \ + (word32) |= ((value) << WMI_RSRC_CFG_FLAG_ ## flag ## _S) & \ + WMI_RSRC_CFG_FLAG_ ## flag ## _M; \ + } while (0) +#define WMI_RSRC_CFG_FLAG_GET(word32, flag) \ + (((word32) & WMI_RSRC_CFG_FLAG_ ## flag ## _M) >> \ + WMI_RSRC_CFG_FLAG_ ## flag ## _S) + +#define WMI_RSRC_CFG_FLAG_WOW_IGN_PCIE_RST_SET(word32, value) \ + WMI_RSRC_CFG_FLAG_SET((word32), WOW_IGN_PCIE_RST, (value)) +#define WMI_RSRC_CFG_FLAG_WOW_IGN_PCIE_RST_GET(word32) \ + WMI_RSRC_CFG_FLAG_GET((word32), WOW_IGN_PCIE_RST) + +#define WMI_RSRC_CFG_FLAG_LTEU_SUPPORT_SET(word32, value) \ + WMI_RSRC_CFG_FLAG_SET((word32), LTEU_SUPPORT, (value)) +#define WMI_RSRC_CFG_FLAG_LTEU_SUPPORT_GET(word32) \ + WMI_RSRC_CFG_FLAG_GET((word32), LTEU_SUPPORT) + +#define WMI_RSRC_CFG_FLAG_COEX_GPIO_SUPPORT_SET(word32, value) \ + WMI_RSRC_CFG_FLAG_SET((word32), COEX_GPIO_SUPPORT, (value)) +#define WMI_RSRC_CFG_FLAG_COEX_GPIO_SUPPORT_GET(word32) \ + WMI_RSRC_CFG_FLAG_GET((word32), COEX_GPIO_SUPPORT) + +#define WMI_RSRC_CFG_FLAG_AUX_RADIO_SPECTRAL_INTF_SET(word32, value) \ + WMI_RSRC_CFG_FLAG_SET((word32), AUX_RADIO_SPECTRAL_INTF, (value)) +#define WMI_RSRC_CFG_FLAG_AUX_RADIO_SPECTRAL_INTF_GET(word32) \ + WMI_RSRC_CFG_FLAG_GET((word32), AUX_RADIO_SPECTRAL_INTF) + +#define WMI_RSRC_CFG_FLAG_AUX_RADIO_CHAN_LOAD_INTF_SET(word32, value) \ + WMI_RSRC_CFG_FLAG_SET((word32), AUX_RADIO_CHAN_LOAD_INTF, (value)) +#define WMI_RSRC_CFG_FLAG_AUX_RADIO_CHAN_LOAD_INTF_GET(word32) \ + WMI_RSRC_CFG_FLAG_GET((word32), AUX_RADIO_CHAN_LOAD_INTF) + +#define WMI_RSRC_CFG_FLAG_BSS_CHANNEL_INFO_64_SET(word32, value) \ + WMI_RSRC_CFG_FLAG_SET((word32), BSS_CHANNEL_INFO_64, (value)) +#define WMI_RSRC_CFG_FLAG_BSS_CHANNEL_INFO_64_GET(word32) \ + WMI_RSRC_CFG_FLAG_GET((word32), BSS_CHANNEL_INFO_64) + +#define WMI_RSRC_CFG_FLAG_ATF_CONFIG_ENABLE_SET(word32, value) \ + WMI_RSRC_CFG_FLAG_SET((word32), ATF_CONFIG_ENABLE, (value)) +#define WMI_RSRC_CFG_FLAG_ATF_CONFIG_ENABLE_GET(word32) \ + WMI_RSRC_CFG_FLAG_GET((word32), ATF_CONFIG_ENABLE) + +#define WMI_RSRC_CFG_FLAG_IPHR_PAD_CONFIG_ENABLE_SET(word32, value) \ + WMI_RSRC_CFG_FLAG_SET((word32), IPHR_PAD_CONFIG_ENABLE, (value)) +#define WMI_RSRC_CFG_FLAG_IPHR_PAD_CONFIG_ENABLE_GET(word32) \ + WMI_RSRC_CFG_FLAG_GET((word32), IPHR_PAD_CONFIG_ENABLE) + +#define WMI_RSRC_CFG_FLAG_QWRAP_MODE_ENABLE_SET(word32, value) \ + WMI_RSRC_CFG_FLAG_SET((word32), QWRAP_MODE_ENABLE, (value)) +#define WMI_RSRC_CFG_FLAG_QWRAP_MODE_ENABLE_GET(word32) \ + WMI_RSRC_CFG_FLAG_GET((word32), QWRAP_MODE_ENABLE) + +#define WMI_RSRC_CFG_FLAG_MGMT_COMP_EVT_BUNDLE_SUPPORT_SET(word32, value) \ + WMI_RSRC_CFG_FLAG_SET((word32), MGMT_COMP_EVT_BUNDLE_SUPPORT, (value)) +#define WMI_RSRC_CFG_FLAG_MGMT_COMP_EVT_BUNDLE_SUPPORT_GET(word32) \ + WMI_RSRC_CFG_FLAG_GET((word32), MGMT_COMP_EVT_BUNDLE_SUPPORT) + +#define WMI_RSRC_CFG_FLAG_TX_MSDU_ID_NEW_PARTITION_SUPPORT_SET(word32, value) \ + WMI_RSRC_CFG_FLAG_SET((word32), TX_MSDU_ID_NEW_PARTITION_SUPPORT, (value)) +#define WMI_RSRC_CFG_FLAG_TX_MSDU_ID_NEW_PARTITION_SUPPORT_GET(word32) \ + WMI_RSRC_CFG_FLAG_GET((word32), TX_MSDU_ID_NEW_PARTITION_SUPPORT) + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_init_cmd_fixed_param */ + + /** The following indicate the WMI versions to be supported by + * the host driver. Note that the host driver decide to + * "downgrade" its WMI version support and this may not be the + * native version of the host driver. */ + wmi_abi_version host_abi_vers; + + A_UINT32 num_host_mem_chunks; /** size of array host_mem_chunks[] */ +/* The TLVs for resource_config, host_mem_chunks[], and hw_mode_config will follow. + * wmi_resource_config resource_config; + * wlan_host_memory_chunk host_mem_chunks[]; + * wmi_pdev_set_hw_mode_cmd_fixed_param hw_mode_config; + * Note that the hw_mode_config, in spite of its "pdev" name, + * applies to the entire target rather than for a single pdev + * within the target. + * To avoid specifying a HW mode for the target, the host should + * fill hw_mode_config's fields with 0x0. + */ + +} wmi_init_cmd_fixed_param; + +/** + * TLV for channel list + */ +typedef struct { + /** WMI_CHAN_LIST_TAG */ + A_UINT32 tag; + /** # of channels to scan */ + A_UINT32 num_chan; + /** channels in Mhz */ + A_UINT32 channel_list[1]; +} wmi_chan_list; + +/** + * TLV for bssid list + */ +typedef struct { + /** WMI_BSSID_LIST_TAG */ + A_UINT32 tag; + /** number of bssids */ + A_UINT32 num_bssid; + /** bssid list */ + wmi_mac_addr bssid_list[1]; +} wmi_bssid_list; + +/** + * TLV for ie data. + */ +typedef struct { + /** WMI_IE_TAG */ + A_UINT32 tag; + /** number of bytes in ie data */ + A_UINT32 ie_len; + /** ie data array (ie_len adjusted to number of words (ie_len + 4)/4) */ + A_UINT32 ie_data[1]; +} wmi_ie_data; + +/** + * TLV used for length/buffer + */ +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_tlv_buf_len_param */ + A_UINT32 buf_len; /** Length of buf */ + /** + * Following this structure is the TLV byte stream of buf of length buf_len: + * A_UINT8 buf[]; + * + */ +} wmi_tlv_buf_len_param; + +typedef struct { + /** Len of the SSID */ + A_UINT32 ssid_len; + /** SSID */ + A_UINT32 ssid[8]; +} wmi_ssid; + +typedef struct { + /** WMI_SSID_LIST_TAG */ + A_UINT32 tag; + A_UINT32 num_ssids; + wmi_ssid ssids[1]; +} wmi_ssid_list; + +/* prefix used by scan requestor ids on the host */ +#define WMI_HOST_SCAN_REQUESTOR_ID_PREFIX 0xA000 +/* prefix used by scan request ids generated on the host */ +/* host cycles through the lower 12 bits to generate ids */ +#define WMI_HOST_SCAN_REQ_ID_PREFIX 0xA000 + +#define WLAN_SCAN_PARAMS_MAX_SSID 16 +#define WLAN_SCAN_PARAMS_MAX_BSSID 4 +#define WLAN_SCAN_PARAMS_MAX_IE_LEN 512 + +/* NOTE: This constant cannot be changed without breaking WMI compatibility */ +#define WMI_IE_BITMAP_SIZE 8 + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_start_scan_cmd_fixed_param */ + /** Scan ID (lower 16 bits) MSB 4 bits is used to identify scan client based on enum WMI_SCAN_CLIENT_ID */ + A_UINT32 scan_id; + /** Scan requestor ID (lower 16 bits) is used by scan client to classify the scan source, reason, ...etc */ + A_UINT32 scan_req_id; + /** VDEV id(interface) that is requesting scan */ + A_UINT32 vdev_id; + /** Scan Priority, input to scan scheduler */ + A_UINT32 scan_priority; + /** Scan events subscription */ + A_UINT32 notify_scan_events; + /** dwell time in msec on active channels */ + A_UINT32 dwell_time_active; + /** dwell time in msec on passive channels */ + A_UINT32 dwell_time_passive; + /** min time in msec on the BSS channel,only valid if atleast one VDEV is active*/ + A_UINT32 min_rest_time; + /** max rest time in msec on the BSS channel,only valid if at least one VDEV is active*/ + /** the scanner will rest on the bss channel at least min_rest_time. after min_rest_time the scanner + * will start checking for tx/rx activity on all VDEVs. if there is no activity the scanner will + * switch to off channel. if there is activity the scanner will let the radio on the bss channel + * until max_rest_time expires.at max_rest_time scanner will switch to off channel + * irrespective of activity. activity is determined by the idle_time parameter. + */ + A_UINT32 max_rest_time; + /** time before sending next set of probe requests. + * The scanner keeps repeating probe requests transmission with period specified by repeat_probe_time. + * The number of probe requests specified depends on the ssid_list and bssid_list + */ + A_UINT32 repeat_probe_time; + /** time in msec between 2 consequetive probe requests with in a set. */ + A_UINT32 probe_spacing_time; + /** data inactivity time in msec on bss channel that will be used by scanner for measuring the inactivity */ + A_UINT32 idle_time; + /** maximum time in msec allowed for scan */ + A_UINT32 max_scan_time; + /** delay in msec before sending first probe request after switching to a channel */ + A_UINT32 probe_delay; + /** Scan control flags */ + A_UINT32 scan_ctrl_flags; + /** Burst duration time in msec*/ + A_UINT32 burst_duration; + + /** # if channels to scan. In the TLV channel_list[] */ + A_UINT32 num_chan; + /** number of bssids. In the TLV bssid_list[] */ + A_UINT32 num_bssid; + /** number of ssid. In the TLV ssid_list[] */ + A_UINT32 num_ssids; + /** number of bytes in ie data. In the TLV ie_data[]. Max len is defined by WLAN_SCAN_PARAMS_MAX_IE_LEN */ + A_UINT32 ie_len; + /** Max number of probes to be sent */ + A_UINT32 n_probes; + /** MAC Address to use in Probe Req as SA **/ + wmi_mac_addr mac_addr; + /** Mask on which MAC has to be randomized **/ + wmi_mac_addr mac_mask; + /** ie bitmap to use in probe req **/ + A_UINT32 ie_bitmap[WMI_IE_BITMAP_SIZE]; + /** Number of vendor OUIs. In the TLV vendor_oui[] **/ + A_UINT32 num_vendor_oui; + /** Scan control flags extended **/ + A_UINT32 scan_ctrl_flags_ext; + +/** + * TLV (tag length value) parameters follow the scan_cmd + * structure. The TLV's are: + * A_UINT32 channel_list[]; + * wmi_ssid ssid_list[]; + * wmi_mac_addr bssid_list[]; + * A_UINT8 ie_data[]; + * wmi_vendor_oui vendor_oui[]; + */ +} wmi_start_scan_cmd_fixed_param; + +/** + * scan control flags. + */ + +/** passively scan all channels including active channels */ +#define WMI_SCAN_FLAG_PASSIVE 0x1 +/** add wild card ssid probe request even though ssid_list is specified. */ +#define WMI_SCAN_ADD_BCAST_PROBE_REQ 0x2 +/** add cck rates to rates/xrate ie for the generated probe request */ +#define WMI_SCAN_ADD_CCK_RATES 0x4 +/** add ofdm rates to rates/xrate ie for the generated probe request */ +#define WMI_SCAN_ADD_OFDM_RATES 0x8 +/** To enable indication of Chan load and Noise floor to host */ +#define WMI_SCAN_CHAN_STAT_EVENT 0x10 +/** Filter Probe request frames */ +#define WMI_SCAN_FILTER_PROBE_REQ 0x20 +/**When set, not to scan DFS channels*/ +#define WMI_SCAN_BYPASS_DFS_CHN 0x40 +/**When set, certain errors are ignored and scan continues. + * Different FW scan engine may use its own logic to decide what errors to ignore*/ +#define WMI_SCAN_CONTINUE_ON_ERROR 0x80 +/** Enable promiscous mode for CCXv4 */ +#define WMI_SCAN_FILTER_PROMISCOUS 0x100 +/** allow to send probe req on DFS channel */ +#define WMI_SCAN_FLAG_FORCE_ACTIVE_ON_DFS 0x200 +/** add TPC content in probe req frame */ +#define WMI_SCAN_ADD_TPC_IE_IN_PROBE_REQ 0x400 +/** add DS content in probe req frame */ +#define WMI_SCAN_ADD_DS_IE_IN_PROBE_REQ 0x800 +/** use random mac address for TA for probe request frame and add + * oui specified by WMI_SCAN_PROB_REQ_OUI_CMDID to the probe req frame. + * if oui is not set by WMI_SCAN_PROB_REQ_OUI_CMDID then the flag is ignored*/ +#define WMI_SCAN_ADD_SPOOFED_MAC_IN_PROBE_REQ 0x1000 +/** allow mgmt transmission during off channel scan */ +#define WMI_SCAN_OFFCHAN_MGMT_TX 0x2000 +/** allow data transmission during off channel scan */ +#define WMI_SCAN_OFFCHAN_DATA_TX 0x4000 +/** allow capture ppdu with phy errrors */ +#define WMI_SCAN_CAPTURE_PHY_ERROR 0x8000 +/** always do passive scan on passive channels */ +#define WMI_SCAN_FLAG_STRICT_PASSIVE_ON_PCHN 0x10000 +/** set HALF (10MHz) rate support */ +#define WMI_SCAN_FLAG_HALF_RATE_SUPPORT 0x20000 +/** set Quarter (5MHz) rate support */ +#define WMI_SCAN_FLAG_QUARTER_RATE_SUPPORT 0x40000 +#define WMI_SCAN_RANDOM_SEQ_NO_IN_PROBE_REQ 0x80000 +#define WMI_SCAN_ENABLE_IE_WHTELIST_IN_PROBE_REQ 0x100000 + +/** for adaptive scan mode using 3 bits (21 - 23 bits) */ +#define WMI_SCAN_DWELL_MODE_MASK 0x00E00000 +#define WMI_SCAN_DWELL_MODE_SHIFT 21 + +typedef enum { + WMI_SCAN_DWELL_MODE_DEFAULT = 0, + WMI_SCAN_DWELL_MODE_CONSERVATIVE = 1, + WMI_SCAN_DWELL_MODE_MODERATE = 2, + WMI_SCAN_DWELL_MODE_AGGRESSIVE = 3, + WMI_SCAN_DWELL_MODE_STATIC = 4, +} WMI_SCAN_DWELL_MODE; + +#define WMI_SCAN_SET_DWELL_MODE(flag, mode) \ + do { \ + (flag) |= (((mode) << WMI_SCAN_DWELL_MODE_SHIFT) & \ + WMI_SCAN_DWELL_MODE_MASK); \ + } while (0) + +#define WMI_SCAN_GET_DWELL_MODE(flag) \ + (((flag) & WMI_SCAN_DWELL_MODE_MASK) >> WMI_SCAN_DWELL_MODE_SHIFT) + +/** WMI_SCAN_CLASS_MASK must be the same value as IEEE80211_SCAN_CLASS_MASK */ +#define WMI_SCAN_CLASS_MASK 0xFF000000 + +/* + * Masks identifying types/ID of scans + * Scan_Stop macros should be the same value as below defined in UMAC + * #define IEEE80211_SPECIFIC_SCAN 0x00000000 + * #define IEEE80211_VAP_SCAN 0x01000000 + * #define IEEE80211_ALL_SCANS 0x04000000 + */ +#define WMI_SCAN_STOP_ONE 0x00000000 +#define WMI_SCN_STOP_VAP_ALL 0x01000000 +#define WMI_SCAN_STOP_ALL 0x04000000 + +/** extended Scan ctrl flags **/ +#define WMI_SCAN_FLAG_EXT_DBS_SCAN_POLICY_MASK 0x00000003 /* Bit 0-1 reserved for DBS scan selection policy.*/ + +#define WMI_SCAN_DBS_POLICY_DEFAULT 0x0 /** Select duty cycle if configured, else fall back to whatever + policy scan manager computes */ +#define WMI_SCAN_DBS_POLICY_FORCE_NONDBS 0x1 /** Force to select Non-DBS scan */ +#define WMI_SCAN_DBS_POLICY_IGNORE_DUTY 0x2 /** Ignore duty cycle even if configured and fall back to whatever + policy scan manager computes*/ +#define WMI_SCAN_DBS_POLICY_RESERVED 0x3 +#define WMI_SCAN_DBS_POLICY_MAX 0x3 + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_stop_scan_cmd_fixed_param */ + /** requestor requesting cancel */ + A_UINT32 requestor; + /** Scan ID */ + A_UINT32 scan_id; + /** + * Req Type + * req_type should be WMI_SCAN_STOP_ONE, WMI_SCN_STOP_VAP_ALL or WMI_SCAN_STOP_ALL + * WMI_SCAN_STOP_ONE indicates to stop a specific scan with scan_id (on a specific pdev in DBDC) + * WMI_SCN_STOP_VAP_ALL indicates to stop all scan requests on a specific vDev with vdev_id + * WMI_SCAN_STOP_ALL indicates to stop all scan requests in both Scheduler's queue and Scan Engine (on a specific pdev in DBDC) + */ + A_UINT32 req_type; + /** + * vDev ID + * used when req_type equals to WMI_SCN_STOP_VAP_ALL, it indexed the vDev on which to stop the scan + */ + A_UINT32 vdev_id; + /** pdev_id for identifying the MAC + * See macros starting with WMI_PDEV_ID_ for values. + * In non-DBDC case host should set it to 0 + */ + A_UINT32 pdev_id; +} wmi_stop_scan_cmd_fixed_param; + + +#define MAX_NUM_CHAN_PER_WMI_CMD 58 /* each WMI cmd can hold 58 channel entries at most */ +#define APPEND_TO_EXISTING_CHAN_LIST 1 + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_scan_chan_list_cmd_fixed_param */ + A_UINT32 num_scan_chans; /** no of elements in chan_info[] */ + A_UINT32 flags; /* Flags used to control the behavior of channel list update on target side */ + A_UINT32 pdev_id; /** pdev_id for identifying the MAC. See macros starting with WMI_PDEV_ID_ for values. In non-DBDC case host should set it to 0. */ +/** Followed by the variable length TLV chan_info: + * wmi_channel chan_info[] */ +} wmi_scan_chan_list_cmd_fixed_param; + +/* + * Priority numbers must be sequential, starting with 0. + */ +/* NOTE: WLAN SCAN_PRIORITY_COUNT can't be changed without breaking the compatibility */ +typedef enum { + WMI_SCAN_PRIORITY_VERY_LOW = 0, + WMI_SCAN_PRIORITY_LOW, + WMI_SCAN_PRIORITY_MEDIUM, + WMI_SCAN_PRIORITY_HIGH, + WMI_SCAN_PRIORITY_VERY_HIGH, + + WMI_SCAN_PRIORITY_COUNT /* number of priorities supported */ +} wmi_scan_priority; + +/* Five Levels for Requested Priority */ +/* VERY_LOW LOW MEDIUM HIGH VERY_HIGH */ +typedef A_UINT32 WLAN_PRIORITY_MAPPING[WMI_SCAN_PRIORITY_COUNT]; + +/** + * to keep align with UMAC implementation, we pass only vdev_type but not vdev_subtype when we overwrite an entry for a specific vdev_subtype + * ex. if we need overwrite P2P Client prority entry, we will overwrite the whole table for WLAN_M_STA + * we will generate the new WLAN_M_STA table with modified P2P Client Entry but keep STA entry intact + */ +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_scan_sch_priority_table_cmd_fixed_param */ + /** + * used as an index to find the proper table for a specific vdev type in default_scan_priority_mapping_table + * vdev_type should be one of enum in WLAN_OPMODE which inculdes WLAN_M_IBSS, WLAN_M_STA, WLAN_M_AP and WLAN_M_MONITOR currently + */ + A_UINT32 vdev_type; + /** + * number of rows in mapping_table for a specific vdev + * for WLAN_M_STA type, there are 3 entries in the table (refer to default_scan_priority_mapping_table definition) + */ + A_UINT32 number_rows; + /** + * pdev_id for identifying the MAC. See macros starting with WMI_PDEV_ID_ for values. + * In non-DBDC case host should set it to 0 + */ + A_UINT32 pdev_id; +/** mapping_table for a specific vdev follows this TLV + * WLAN_PRIORITY_MAPPING mapping_table[]; */ +} wmi_scan_sch_priority_table_cmd_fixed_param; + +/** update flags */ +#define WMI_SCAN_UPDATE_SCAN_PRIORITY 0x1 +#define WMI_SCAN_UPDATE_SCAN_MIN_REST_TIME 0x2 +#define WMI_SCAN_UPDATE_SCAN_MAX_REST_TIME 0x4 + +typedef struct { + A_UINT32 tlv_header; + /** requestor requesting update scan request */ + A_UINT32 requestor; + /** Scan ID of the scan request that need to be update */ + A_UINT32 scan_id; + /** update flags, indicating which of the following fields are valid and need to be updated*/ + A_UINT32 scan_update_flags; + /** scan priority. Only valid if WMI_SCAN_UPDATE_SCAN_PRIORITY flag is set in scan_update_flag */ + A_UINT32 scan_priority; + /** min rest time. Only valid if WMI_SCAN_UPDATE_MIN_REST_TIME flag is set in scan_update_flag */ + A_UINT32 min_rest_time; + /** min rest time. Only valid if WMI_SCAN_UPDATE_MAX_REST_TIME flag is set in scan_update_flag */ + A_UINT32 max_rest_time; + /** pdev_id for identifying the MAC. See macros starting with WMI_PDEV_ID_ for values. In non-DBDC case host should set it to 0 */ + A_UINT32 pdev_id; +} wmi_scan_update_request_cmd_fixed_param; + +#define WMI_SCAN_PROBE_OUI_SPOOFED_MAC_IN_PROBE_REQ 0x1 +#define WMI_SCAN_PROBE_OUI_RANDOM_SEQ_NO_IN_PROBE_REQ 0x2 +#define WMI_SCAN_PROBE_OUI_ENABLE_IE_WHITELIST_IN_PROBE_REQ 0x4 + +typedef struct _wmi_vendor_oui { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_vendor_oui */ + A_UINT32 oui_type_subtype; /** Vendor OUI type and subtype, lower 3 bytes is type and highest byte is subtype**/ +}wmi_vendor_oui; + +typedef struct { + A_UINT32 tlv_header; + /** oui to be used in probe request frame when random mac addresss is + * requested part of scan parameters. this is applied to both FW internal scans and + * host initated scans. host can request for random mac address with + * WMI_SCAN_ADD_SPOOFED_MAC_IN_PROBE_REQ flag. */ + A_UINT32 prob_req_oui; + A_UINT32 vdev_id; + /** Control Flags **/ + A_UINT32 flags; + /** ie bitmap to use in probe req **/ + A_UINT32 ie_bitmap[WMI_IE_BITMAP_SIZE]; + /** Number of vendor OUIs. In the TLV vendor_oui[] **/ + A_UINT32 num_vendor_oui; + /** pdev_id for identifying the MAC. See macros starting with WMI_PDEV_ID_ for values. In non-DBDC case host should set it to 0 */ + A_UINT32 pdev_id; + /* Following this tlv, there comes an array of structure of type wmi_vendor_oui + wmi_vendor_oui vendor_oui[];*/ +} wmi_scan_prob_req_oui_cmd_fixed_param; + + +enum wmi_scan_event_type { + WMI_SCAN_EVENT_STARTED = 0x1, + WMI_SCAN_EVENT_COMPLETED = 0x2, + WMI_SCAN_EVENT_BSS_CHANNEL = 0x4, + WMI_SCAN_EVENT_FOREIGN_CHANNEL = 0x8, + WMI_SCAN_EVENT_DEQUEUED = 0x10, /* scan request got dequeued */ + WMI_SCAN_EVENT_PREEMPTED = 0x20, /* preempted by other high priority scan */ + WMI_SCAN_EVENT_START_FAILED = 0x40, /* scan start failed */ + WMI_SCAN_EVENT_RESTARTED = 0x80, /* scan restarted */ + WMI_SCAN_EVENT_FOREIGN_CHANNEL_EXIT = 0x100, + WMI_SCAN_EVENT_SUSPENDED = 0x200, /* scan request is suspended */ + WMI_SCAN_EVENT_RESUMED = 0x400, /* scan request is resumed */ + WMI_SCAN_EVENT_MAX = 0x8000 +}; + +enum wmi_scan_completion_reason { + /** scan related events */ + WMI_SCAN_REASON_NONE = 0xFF, + WMI_SCAN_REASON_COMPLETED = 0, + WMI_SCAN_REASON_CANCELLED = 1, + WMI_SCAN_REASON_PREEMPTED = 2, + WMI_SCAN_REASON_TIMEDOUT = 3, + WMI_SCAN_REASON_INTERNAL_FAILURE = 4, /* This reason indication failures when performaing scan */ + WMI_SCAN_REASON_SUSPENDED = 5, + WMI_SCAN_REASON_MAX, +}; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_scan_event_fixed_param */ + /** scan event (wmi_scan_event_type) */ + A_UINT32 event; + /** status of the scan completion event */ + A_UINT32 reason; + /** channel freq , only valid for FOREIGN channel event*/ + A_UINT32 channel_freq; + /**id of the requestor whose scan is in progress */ + A_UINT32 requestor; + /**id of the scan that is in progress */ + A_UINT32 scan_id; + /**id of VDEV that requested the scan */ + A_UINT32 vdev_id; +} wmi_scan_event_fixed_param; + +/* WMI Diag event */ +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag is WMITLV_TAG_STRUC_wmi_diag_event_fixed_param */ + A_UINT32 time_stamp; /* Reference timestamp. diag frame contains diff value */ + A_UINT32 count; /* Number of diag frames added to current event */ + A_UINT32 dropped; + /* followed by WMITLV_TAG_ARRAY_BYTE */ +} wmi_diag_event_fixed_param; + + +#define WMI_MAX_PMKID_LEN 16 +#define WMI_MAX_PMK_LEN 64 + +#define WMI_PMK_CACHE_CAT_FLAG_BSSID 0x1 +#define WMI_PMK_CACHE_CAT_FLAG_SSID_CACHE_ID 0x2 + +#define WMI_PMK_CACHE_ACTION_FLAG_ADD_ENTRY 0x1 +#define WMI_PMK_CACHE_ACTION_FLAG_DEL_ENTRY 0x2 + +typedef struct { + A_UINT32 tlv_header; + A_UINT32 pmk_len; + A_UINT8 pmk[WMI_MAX_PMK_LEN];/* for big-endian hosts, manual endian conversion will be needed to keep the array values in their original order, + in spite of the automatic byte-swap applied to WMI messages during download*/ + A_UINT32 pmkid_len; + A_UINT8 pmkid[WMI_MAX_PMKID_LEN]; + wmi_mac_addr bssid; + wmi_ssid ssid; + A_UINT32 cache_id; + A_UINT32 cat_flag; // whether (bssid) or (ssid,cache_id) is valid + A_UINT32 action_flag; // add/delete the entry +} wmi_pmk_cache; + +#define WMI_PMK_CACHE_OP_FLAG_FLUSH_ALL 0x1 + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_pdev_update_pmk_cache_cmd_fixed_param */ + A_UINT32 op_flag; //option to flush all the cache at once + A_UINT32 vdev_id; + A_UINT32 num_cache; + /** + * TLV (tag length value) parameters follow the update_pmk_cache cmd + * structure. The TLV's are: + * wmi_pmk_cache cache_list[]; + */ +} wmi_pdev_update_pmk_cache_cmd_fixed_param; + +#define WMI_FILS_MAX_USERNAME_LEN 16 +#define WMI_FILS_MAX_REALM_LEN 256 +#define WMI_FILS_MAX_RRK_LEN 64 +#define WMI_FILS_MAX_RIK_LEN 64 + +/* for big-endian hosts, manual endian conversion will be needed to keep the array values in their original order, +in spite of the automatic byte-swap applied to WMI messages during download*/ + +typedef struct { + A_UINT8 username[WMI_FILS_MAX_USERNAME_LEN]; + A_UINT32 username_length; + A_UINT32 next_erp_seq_num; + A_UINT8 rRk[WMI_FILS_MAX_RRK_LEN]; + A_UINT32 rRk_length; + A_UINT8 rIk[WMI_FILS_MAX_RIK_LEN]; + A_UINT32 rIk_length; + A_UINT8 realm[WMI_FILS_MAX_REALM_LEN]; + A_UINT32 realm_len; +} wmi_erp_info; + +enum wmi_fils_hlp_pkt_type { + WMI_FILS_HLP_PKT_TYPE_DHCP_DISCOVER = 1, +}; + +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_roam_fils_offload_tlv_param */ + A_UINT32 flags; + wmi_erp_info vdev_erp_info; +} wmi_roam_fils_offload_tlv_param; + +typedef struct { + A_UINT32 tlv_header; /** tag WMITLV_TAG_STRUC_wmi_pdev_update_fils_hlp_pkt_cmd_fixed_param**/ + A_UINT32 flags; + A_UINT32 vdev_id; + A_UINT32 size; + A_UINT32 pkt_type; // filled using enum wmi_fils_hlp_pkt_type + // A_UINT8 fils_hlp_pkt[]; +} wmi_pdev_update_fils_hlp_pkt_cmd_fixed_param; + +#define WMI_MAX_KEK_LEN 64 +#define GTK_OFFLOAD_KEK_EXTENDED_BYTES WMI_MAX_KEK_LEN /*KEK len has been increased to 64 to support FILS security. + To not break backward compatibility, new GTK_OFFLOAD_KEK_EXTENDED_BYTES has been defined without modifying old GTK_OFFLOAD_KEK_BYTES */ + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_roam_fils_synch_tlv_param */ + A_UINT32 update_erp_next_seq_num;// Boolean denoting whether next erp_seq_num changed or not. + A_UINT32 next_erp_seq_num; + A_UINT32 kek_len; + A_UINT8 kek[WMI_MAX_KEK_LEN]; + A_UINT32 pmk_len; + A_UINT8 pmk[WMI_MAX_PMK_LEN]; + A_UINT8 pmkid[WMI_MAX_PMKID_LEN]; + A_UINT8 realm[WMI_FILS_MAX_REALM_LEN]; + A_UINT32 realm_len; +} wmi_roam_fils_synch_tlv_param; + +/* +* If FW has multiple active channels due to MCC(multi channel concurrency), +* then these stats are combined stats for all the active channels. +*/ +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_update_whal_mib_stats_event_fixed_param */ + /** ack count, it is an incremental number, not accumulated number */ + A_UINT32 ackRcvBad; + /** bad rts count, it is an incremental number, not accumulated number */ + A_UINT32 rtsBad; + /** good rts, it is an incremental number, not accumulated number */ + A_UINT32 rtsGood; + /** fcs count, it is an incremental number, not accumulated number */ + A_UINT32 fcsBad; + /** beacon count, it is an incremental number, not accumulated number */ + A_UINT32 noBeacons; +} wmi_update_whal_mib_stats_event_fixed_param; + +/* + * This defines how much headroom is kept in the + * receive frame between the descriptor and the + * payload, in order for the WMI PHY error and + * management handler to insert header contents. + * + * This is in bytes. + */ +#define WMI_MGMT_RX_HDR_HEADROOM (sizeof(wmi_comb_phyerr_rx_hdr) + WMI_TLV_HDR_SIZE + sizeof(wmi_single_phyerr_rx_hdr)) + +/** This event will be used for sending scan results + * as well as rx mgmt frames to the host. The rx buffer + * will be sent as part of this WMI event. It would be a + * good idea to pass all the fields in the RX status + * descriptor up to the host. + */ +/* ATH_MAX_ANTENNA value (4) can't be changed without breaking the compatibility */ +#define ATH_MAX_ANTENNA 4 /* To support beelinear, which is up to 4 chains */ + +/** flag indicating that the the mgmt frame (probe req/beacon) is received in the context of extscan performed by FW */ +#define WMI_MGMT_RX_HDR_EXTSCAN 0x01 +/** flag indicating that the the mgmt frame (probe req/beacon) is received in the context of matched network by FW ENLO */ +#define WMI_MGMT_RX_HDR_ENLO 0x02 + +#define MAX_ANTENNA_EIGHT 8 + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_mgmt_rx_hdr */ + /** channel on which this frame is received. */ + A_UINT32 channel; + /** snr information used to cal rssi */ + A_UINT32 snr; + /** Rate kbps */ + A_UINT32 rate; + /** rx phy mode WLAN_PHY_MODE */ + A_UINT32 phy_mode; + /** length of the frame */ + A_UINT32 buf_len; + /** rx status */ + A_UINT32 status; + /** RSSI of PRI 20MHz for each chain. */ + A_UINT32 rssi_ctl[ATH_MAX_ANTENNA]; + /** information about the management frame e.g. can give a scan source for a scan result mgmt frame */ + A_UINT32 flags; + /** combined RSSI, i.e. the sum of the snr + noise floor (dBm units) */ + A_INT32 rssi; + /** delta between local TSF(TSF timestamp when frame was RXd) + * and remote TSF(TSF timestamp in the IE for mgmt frame - + * beacon,proberesp for e.g). If remote TSF is not available, + * delta set to 0. + * Although tsf_delta is stored as A_UINT32, it can be negative, + * and thus would need to be sign-extended if added to a value + * larger than 32 bits. + */ + A_UINT32 tsf_delta; + + /* The lower 32 bits of the TSF (rx_tsf_l32) is copied by FW from + * TSF timestamp in the RX MAC descriptor provided by HW. + */ + A_UINT32 rx_tsf_l32; + + /* The Upper 32 bits (rx_tsf_u32) is filled by reading the TSF register + * after the packet is received. + */ + A_UINT32 rx_tsf_u32; + + /** pdev_id for identifying the MAC the rx mgmt frame was received by + * See macros starting with WMI_PDEV_ID_ for values. + */ + A_UINT32 pdev_id; + +/* This TLV is followed by array of bytes: + * A_UINT8 bufp[]; <-- management frame buffer + */ +/* This TLV is optionally followed by array of struct: + * wmi_rssi_ctl_ext rssi_ctl_ext; + */ +} wmi_mgmt_rx_hdr; + +/* + * Instead of universally increasing the RX_HDR_HEADROOM size which may cause problems for older targets, + * this new ext_hdr can be used for extending the header and will be only applicable for new targets. + */ +typedef struct +{ + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_rssi_ctl_ext */ + /** RSSI of PRI 20MHz for each chain, in dB w.r.t. noise floor */ + A_UINT32 rssi_ctl_ext[MAX_ANTENNA_EIGHT - ATH_MAX_ANTENNA]; +} wmi_rssi_ctl_ext; + +typedef struct { + /** TSF timestamp */ + A_UINT32 tsf_timestamp; + + /** + * Current freq1, freq2 + * + * [7:0]: freq1[lo] + * [15:8] : freq1[hi] + * [23:16]: freq2[lo] + * [31:24]: freq2[hi] + */ + A_UINT32 freq_info_1; + + /** + * Combined RSSI over all chains and channel width for this PHY error + * + * [7:0]: RSSI combined + * [15:8]: Channel width (MHz) + * [23:16]: PHY error code + * [24:16]: reserved (future use) + */ + A_UINT32 freq_info_2; + + /** + * RSSI on chain 0 through 3 + * + * This is formatted the same as the PPDU_START RX descriptor + * field: + * + * [7:0]: pri20 + * [15:8]: sec20 + * [23:16]: sec40 + * [31:24]: sec80 + */ + A_UINT32 rssi_chain0; + A_UINT32 rssi_chain1; + A_UINT32 rssi_chain2; + A_UINT32 rssi_chain3; + + /** + * Last calibrated NF value for chain 0 through 3 + * + * nf_list_1: + * + * + [15:0] - chain 0 + * + [31:16] - chain 1 + * + * nf_list_2: + * + * + [15:0] - chain 2 + * + [31:16] - chain 3 + */ + A_UINT32 nf_list_1; + A_UINT32 nf_list_2; + + /** Length of the frame */ + A_UINT32 buf_len; +} wmi_single_phyerr_rx_hdr; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_single_phyerr_ext_rx_hdr */ + /** + * RSSI on chain 4 through 7 in dB w.r.t noise floor. + * + * This is formatted the same as the PPDU_START RX descriptor + * field: + * + * [7:0]: pri20 + * [15:8]: sec20 + * [23:16]: sec40 + * [31:24]: sec80 + */ + A_UINT32 rssi_chain4; + A_UINT32 rssi_chain5; + A_UINT32 rssi_chain6; + A_UINT32 rssi_chain7; + /** + * Last calibrated NF value for chain 4 through 7 in dbm + * + * nf_list_3: + * + [15:0] - chain 4 + * + [31:16] - chain 5 + * + * nf_list_4: + * + [15:0] - chain 6 + * + [31:16] - chain 7 + * + * Each chain's noise floor is stored as a sign-extended (negative) + * value in dBm units. + */ + A_UINT32 nf_list_3; + A_UINT32 nf_list_4; +} wmi_single_phyerr_ext_rx_hdr; + +#define WMI_UNIFIED_FREQINFO_1_LO 0x000000ff +#define WMI_UNIFIED_FREQINFO_1_LO_S 0 +#define WMI_UNIFIED_FREQINFO_1_HI 0x0000ff00 +#define WMI_UNIFIED_FREQINFO_1_HI_S 8 +#define WMI_UNIFIED_FREQINFO_2_LO 0x00ff0000 +#define WMI_UNIFIED_FREQINFO_2_LO_S 16 +#define WMI_UNIFIED_FREQINFO_2_HI 0xff000000 +#define WMI_UNIFIED_FREQINFO_2_HI_S 24 + +/* + * Please keep in mind that these _SET macros break macro side effect + * assumptions; don't be clever with them. + */ +#define WMI_UNIFIED_FREQ_INFO_GET(hdr, f) \ + (WMI_F_MS((hdr)->freq_info_1, \ + WMI_UNIFIED_FREQINFO_##f##_LO) \ + | (WMI_F_MS((hdr)->freq_info_1, \ + WMI_UNIFIED_FREQINFO_##f##_HI) << 8)) + +#define WMI_UNIFIED_FREQ_INFO_SET(hdr, f, v) \ + do { \ + WMI_F_RMW((hdr)->freq_info_1, (v) & 0xff, \ + WMI_UNIFIED_FREQINFO_##f##_LO); \ + WMI_F_RMW((hdr)->freq_info_1, ((v) >> 8) & 0xff, \ + WMI_UNIFIED_FREQINFO_##f##_HI); \ + } while (0) + +#define WMI_UNIFIED_FREQINFO_2_RSSI_COMB 0x000000ff +#define WMI_UNIFIED_FREQINFO_2_RSSI_COMB_S 0 +#define WMI_UNIFIED_FREQINFO_2_CHWIDTH 0x0000ff00 +#define WMI_UNIFIED_FREQINFO_2_CHWIDTH_S 8 +#define WMI_UNIFIED_FREQINFO_2_PHYERRCODE 0x00ff0000 +#define WMI_UNIFIED_FREQINFO_2_PHYERRCODE_S 16 + +#define WMI_UNIFIED_RSSI_COMB_GET(hdr) \ + ((int8_t) (WMI_F_MS((hdr)->freq_info_2, \ + WMI_UNIFIED_FREQINFO_2_RSSI_COMB))) + +#define WMI_UNIFIED_RSSI_COMB_SET(hdr, v) \ + WMI_F_RMW((hdr)->freq_info_2, (v) & 0xff, \ + WMI_UNIFIED_FREQINFO_2_RSSI_COMB); + +#define WMI_UNIFIED_CHWIDTH_GET(hdr) \ + WMI_F_MS((hdr)->freq_info_2, WMI_UNIFIED_FREQINFO_2_CHWIDTH) + +#define WMI_UNIFIED_CHWIDTH_SET(hdr, v) \ + WMI_F_RMW((hdr)->freq_info_2, (v) & 0xff, \ + WMI_UNIFIED_FREQINFO_2_CHWIDTH); + +#define WMI_UNIFIED_PHYERRCODE_GET(hdr) \ + WMI_F_MS((hdr)->freq_info_2, WMI_UNIFIED_FREQINFO_2_PHYERRCODE) + +#define WMI_UNIFIED_PHYERRCODE_SET(hdr, v) \ + WMI_F_RMW((hdr)->freq_info_2, (v) & 0xff, \ + WMI_UNIFIED_FREQINFO_2_PHYERRCODE); + +#define WMI_UNIFIED_CHAIN_0 0x0000ffff +#define WMI_UNIFIED_CHAIN_0_S 0 +#define WMI_UNIFIED_CHAIN_1 0xffff0000 +#define WMI_UNIFIED_CHAIN_1_S 16 +#define WMI_UNIFIED_CHAIN_2 0x0000ffff +#define WMI_UNIFIED_CHAIN_2_S 0 +#define WMI_UNIFIED_CHAIN_3 0xffff0000 +#define WMI_UNIFIED_CHAIN_3_S 16 + +#define WMI_UNIFIED_CHAIN_4 0x0000ffff +#define WMI_UNIFIED_CHAIN_4_S 0 +#define WMI_UNIFIED_CHAIN_5 0xffff0000 +#define WMI_UNIFIED_CHAIN_5_S 16 +#define WMI_UNIFIED_CHAIN_6 0x0000ffff +#define WMI_UNIFIED_CHAIN_6_S 0 +#define WMI_UNIFIED_CHAIN_7 0xffff0000 +#define WMI_UNIFIED_CHAIN_7_S 16 + +#define WMI_UNIFIED_CHAIN_0_FIELD nf_list_1 +#define WMI_UNIFIED_CHAIN_1_FIELD nf_list_1 +#define WMI_UNIFIED_CHAIN_2_FIELD nf_list_2 +#define WMI_UNIFIED_CHAIN_3_FIELD nf_list_2 +#define WMI_UNIFIED_CHAIN_4_FIELD nf_list_3 +#define WMI_UNIFIED_CHAIN_5_FIELD nf_list_3 +#define WMI_UNIFIED_CHAIN_6_FIELD nf_list_4 +#define WMI_UNIFIED_CHAIN_7_FIELD nf_list_4 + +#define WMI_UNIFIED_NF_CHAIN_GET(hdr, c) \ + ((int16_t) (WMI_F_MS((hdr)->WMI_UNIFIED_CHAIN_##c##_FIELD, \ + WMI_UNIFIED_CHAIN_##c))) + +#define WMI_UNIFIED_NF_CHAIN_SET(hdr, c, nf) \ + WMI_F_RMW((hdr)->WMI_UNIFIED_CHAIN_##c##_FIELD, (nf) & 0xffff, \ + WMI_UNIFIED_CHAIN_##c); + +/* + * For now, this matches what the underlying hardware is doing. + * Update ar6000ProcRxDesc() to use these macros when populating + * the rx descriptor and then we can just copy the field over + * to the WMI PHY notification without worrying about breaking + * things. + */ +#define WMI_UNIFIED_RSSI_CHAN_PRI20 0x000000ff +#define WMI_UNIFIED_RSSI_CHAN_PRI20_S 0 +#define WMI_UNIFIED_RSSI_CHAN_SEC20 0x0000ff00 +#define WMI_UNIFIED_RSSI_CHAN_SEC20_S 8 +#define WMI_UNIFIED_RSSI_CHAN_SEC40 0x00ff0000 +#define WMI_UNIFIED_RSSI_CHAN_SEC40_S 16 +#define WMI_UNIFIED_RSSI_CHAN_SEC80 0xff000000 +#define WMI_UNIFIED_RSSI_CHAN_SEC80_S 24 + +#define WMI_UNIFIED_RSSI_CHAN_SET(hdr, c, ch, rssi) \ + WMI_F_RMW((hdr)->rssi_chain##c, (rssi) & 0xff, \ + WMI_UNIFIED_RSSI_CHAN_##ch); + +#define WMI_UNIFIED_RSSI_CHAN_GET(hdr, c, ch) \ + ((int8_t) (WMI_F_MS((hdr)->rssi_chain##c, \ + WMI_UNIFIED_RSSI_CHAN_##ch))) + +typedef struct { + /** Phy error event header */ + wmi_single_phyerr_rx_hdr hdr; + /** frame buffer */ + A_UINT8 bufp[1]; +} wmi_single_phyerr_rx_event; + +/* PHY ERROR MASK 0 */ +/* bits 1:0 defined but not published */ +#define WMI_PHY_ERROR_MASK0_RADAR (1 << 2) +/* bits 23:3 defined but not published */ +#define WMI_PHY_ERROR_MASK0_FALSE_RADAR_EXT (1 << 24) +/* bits 25:24 defined but not published */ +#define WMI_PHY_ERROR_MASK0_SPECTRAL_SCAN (1 << 26) +/* bits 31:27 defined but not published */ + +/* PHY ERROR MASK 1 */ +/* bits 13:0 defined but not published */ +/* bits 31:14 reserved */ + +/* PHY ERROR MASK 2 */ +/* bits 31:0 reserved */ + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_comb_phyerr_rx_hdr */ + /** Phy error phy error count */ + A_UINT32 num_phyerr_events; + A_UINT32 tsf_l32; + A_UINT32 tsf_u32; + A_UINT32 buf_len; + union { + A_UINT32 pmac_id; /* OBSOLETE - will be removed once all refs are gone */ + /** pdev_id for identifying the MAC + * See macros starting with WMI_PDEV_ID_ for values. + */ + A_UINT32 pdev_id; + }; + A_UINT32 rsPhyErrMask0; /* see WMI_PHY_ERROR_MASK0 */ + A_UINT32 rsPhyErrMask1; /* see WMI_PHY_ERROR_MASK1 */ + A_UINT32 rsPhyErrMask2; /* see WMI_PHY_ERROR_MASK2 */ +/* This TLV is followed by array of bytes: + * frame buffer - contains multiple payloads in the order: + * header - payload, header - payload... + * (The header is of type: wmi_single_phyerr_rx_hdr) + * A_UINT8 bufp[]; + * The extension hdr will repeat num_phyerr_events of times + * and will have 1:1 mapping with above header. i.e the 1st + * ext_rx_hdr will belong to 1st phyerr_rx_hdr and so on. + * wmi_single_phyerr_ext_rx_hdr single_phyerr_ext; + */ +} wmi_comb_phyerr_rx_hdr; + +/* WMI MGMT TX */ +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_mgmt_tx_hdr */ + /** unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; + /** peer MAC address */ + wmi_mac_addr peer_macaddr; + /** xmit rate */ + A_UINT32 tx_rate; + /** xmit power */ + A_UINT32 tx_power; + /** Buffer length in bytes */ + A_UINT32 buf_len; +/* This TLV is followed by array of bytes: + * A_UINT8 bufp[]; <-- management frame buffer + */ +} wmi_mgmt_tx_hdr; + +#define WMI_TX_SEND_PARAM_PWR_GET(tx_param_dword0) WMI_GET_BITS(tx_param_dword0, 0, 8) +#define WMI_TX_SEND_PARAM_PWR_SET(tx_param_dword0, value) WMI_SET_BITS(tx_param_dword0, 0, 8, value) + +#define WMI_TX_SEND_PARAM_MCS_MASK_GET(tx_param_dword0) WMI_GET_BITS(tx_param_dword0, 8, 12) +#define WMI_TX_SEND_PARAM_MCS_MASK_SET(tx_param_dword0, value) WMI_SET_BITS(tx_param_dword0, 8, 12, value) + +#define WMI_TX_SEND_PARAM_NSS_MASK_GET(tx_param_dword0) WMI_GET_BITS(tx_param_dword0, 20, 8) +#define WMI_TX_SEND_PARAM_NSS_MASK_SET(tx_param_dword0, value) WMI_SET_BITS(tx_param_dword0, 20, 8, value) + +#define WMI_TX_SEND_PARAM_RETRY_LIMIT_GET(tx_param_dword0) WMI_GET_BITS(tx_param_dword0, 28, 4) +#define WMI_TX_SEND_PARAM_RETRY_LIMIT_SET(tx_param_dword0, value) WMI_SET_BITS(tx_param_dword0, 28, 4, value) + +#define WMI_TX_SEND_PARAM_CHAIN_MASK_GET(tx_param_dword1) WMI_GET_BITS(tx_param_dword1, 0, 8) +#define WMI_TX_SEND_PARAM_CHAIN_MASK_SET(tx_param_dword1, value) WMI_SET_BITS(tx_param_dword1, 0, 8, value) + +#define WMI_TX_SEND_PARAM_BW_MASK_GET(tx_param_dword1) WMI_GET_BITS(tx_param_dword1, 8, 7) +#define WMI_TX_SEND_PARAM_BW_MASK_SET(tx_param_dword1, value) WMI_SET_BITS(tx_param_dword1, 8, 7, value) + +#define WMI_TX_SEND_PARAM_PREAMBLE_GET(tx_param_dword1) WMI_GET_BITS(tx_param_dword1, 15, 5) +#define WMI_TX_SEND_PARAM_PREAMBLE_SET(tx_param_dword1, value) WMI_SET_BITS(tx_param_dword1, 15, 5, value) + +#define WMI_TX_SEND_PARAM_FRAME_TYPE_GET(tx_param_dword1) WMI_GET_BITS(tx_param_dword1, 20, 1) +#define WMI_TX_SEND_PARAM_FRAME_TYPE_SET(tx_param_dword1, value) WMI_SET_BITS(tx_param_dword1, 20, 1, value) + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_tx_send_params */ + + union { + struct { + /* DWORD 0: tx power, tx rate, retry_limit */ + A_UINT32 + /* pwr - + * Specify what power the tx frame needs to be transmitted at. + * The power a signed (two's complement) value is in units of 0.5 dBm. + * The value needs to be appropriately sign-extended when extracting + * the value from the message and storing it in a variable that is + * larger than A_INT8. (fw automatically handles this sign-extension.) + * If the transmission uses multiple tx chains, this power spec is + * the total transmit power, assuming incoherent combination of + * per-chain power to produce the total power. + */ + pwr: 8, + + /* mcs_mask - + * Specify the allowable values for MCS index (modulation and coding) + * to use for transmitting the frame. + * + * For HT / VHT preamble types, this mask directly corresponds to + * the HT or VHT MCS indices that are allowed. For each bit N set + * within the mask, MCS index N is allowed for transmitting the frame. + * For legacy CCK and OFDM rates, separate bits are provided for CCK + * rates versus OFDM rates, so the host has the option of specifying + * that the target must transmit the frame with CCK or OFDM rates + * (not HT or VHT), but leaving the decision to the target whether + * to use CCK or OFDM. + * + * For CCK and OFDM, the bits within this mask are interpreted as + * follows: + * bit 0 -> CCK 1 Mbps rate is allowed + * bit 1 -> CCK 2 Mbps rate is allowed + * bit 2 -> CCK 5.5 Mbps rate is allowed + * bit 3 -> CCK 11 Mbps rate is allowed + * bit 4 -> OFDM BPSK modulation, 1/2 coding rate is allowed + * bit 5 -> OFDM BPSK modulation, 3/4 coding rate is allowed + * bit 6 -> OFDM QPSK modulation, 1/2 coding rate is allowed + * bit 7 -> OFDM QPSK modulation, 3/4 coding rate is allowed + * bit 8 -> OFDM 16-QAM modulation, 1/2 coding rate is allowed + * bit 9 -> OFDM 16-QAM modulation, 3/4 coding rate is allowed + * bit 10 -> OFDM 64-QAM modulation, 2/3 coding rate is allowed + * bit 11 -> OFDM 64-QAM modulation, 3/4 coding rate is allowed + * + * The MCS index specification needs to be compatible with the + * bandwidth mask specification. For example, a MCS index == 9 + * specification is inconsistent with a preamble type == VHT, + * Nss == 1, and channel bandwidth == 20 MHz. + * + * Furthermore, the host has only a limited ability to specify to + * the target to select from HT + legacy rates, or VHT + legacy rates, + * since this mcs_mask can specify either HT/VHT rates or legacy rates. + * If no bits are set, target can choose what MCS type to use. + */ + mcs_mask: 12, + + /* nss_mask - + * Specify which numbers of spatial streams (MIMO factor) are permitted. + * Each bit in this mask corresponds to a Nss value: + * bit 0: if set, Nss = 1 (non-MIMO) is permitted + * bit 1: if set, Nss = 2 (2x2 MIMO) is permitted + * bit 2: if set, Nss = 3 (3x3 MIMO) is permitted + * bit 3: if set, Nss = 4 (4x4 MIMO) is permitted + * bit 4: if set, Nss = 5 (5x5 MIMO) is permitted + * bit 5: if set, Nss = 6 (6x6 MIMO) is permitted + * bit 6: if set, Nss = 7 (7x7 MIMO) is permitted + * bit 7: if set, Nss = 8 (8x8 MIMO) is permitted + * The values in the Nss mask must be suitable for the recipient, e.g. + * a value of 0x4 (Nss = 3) cannot be specified for a tx frame to a + * recipient which only supports 2x2 MIMO. + * If no bits are set, target can choose what NSS type to use. + */ + nss_mask: 8, + + /* retry_limit - + * Specify the maximum number of transmissions, including the + * initial transmission, to attempt before giving up if no ack + * is received. + * If the tx rate is specified, then all retries shall use the + * same rate as the initial transmission. + * If no tx rate is specified, the target can choose whether to + * retain the original rate during the retransmissions, or to + * fall back to a more robust rate. + */ + retry_limit: 4; + + }; + A_UINT32 tx_param_dword0; + }; + + union { + struct { + /* DWORD 1: tx chain mask, preamble_type, tx BW */ + A_UINT32 + /* chain_mask - specify which chains to transmit from + * If not set, target will choose what chain_mask to use. + */ + chain_mask: 8, + + /* The bits in this mask correspond to the values as below + * bit 0 -> 5MHz + * bit 1 -> 10MHz + * bit 2 -> 20MHz + * bit 3 -> 40MHz + * bit 4 -> 80MHz + * bit 5 -> 160MHz + * bit 6 -> 80_80MHz + * If no bits are set, target can choose what BW to use. + */ + bw_mask: 7, + + /* preamble_type_mask - + * Specify which preamble types (CCK, OFDM, HT, VHT) the target + * may choose from for transmitting this frame. + * Each bit in this mask corresponds to a preamble_type value: + * bit 0: if set, OFDM + * bit 1: if set, CCK + * bit 2: if set, HT + * bit 3: if set, VHT + * bit 4: if set, HE + * If no bits are set, target can choose what preamble type to use. + */ + preamble_type: 5, + + /* Data:1 Mgmt:0 + */ + frame_type: 1, + + reserved1_31_21: 11; + }; + A_UINT32 tx_param_dword1; + }; +} wmi_tx_send_params; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_mgmt_tx_send_cmd_fixed_param */ + A_UINT32 vdev_id; + A_UINT32 desc_id; /* echoed in tx_compl_event */ + A_UINT32 chanfreq; /* MHz units */ + A_UINT32 paddr_lo; + A_UINT32 paddr_hi; + A_UINT32 frame_len; + A_UINT32 buf_len; /** Buffer length in bytes */ + /* + * The frame which will have tx_params_valid set will be always be RAW + * frame, as it will be tx'ed on non-pause tid + */ + A_UINT32 tx_params_valid; +/* This TLV is followed by array of bytes: First 64 bytes of management frame + * A_UINT8 bufp[]; + */ +/* This TLV is followed by wmi_tx_send_params + * wmi_tx_send_params tx_send_params; + */ +} wmi_mgmt_tx_send_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_offchan_data_tx_send_cmd_fixed_param */ + A_UINT32 vdev_id; + A_UINT32 desc_id; /* echoed in tx_compl_event */ + A_UINT32 chanfreq; /* MHz units */ + A_UINT32 paddr_lo; + A_UINT32 paddr_hi; + A_UINT32 frame_len; + A_UINT32 buf_len; /** Buffer length in bytes */ + /* The frame which will have tx_params_valid set will be always be RAW + * frame, as it will be tx'ed on non-pause tid + */ + A_UINT32 tx_params_valid; + +/* This TLV is followed by array of bytes: First 64 bytes of frame + * A_UINT8 bufp[]; + */ +/* This TLV is followed by wmi_tx_send_params + * wmi_tx_send_params tx_send_params; + */ +} wmi_offchan_data_tx_send_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_echo_event_fixed_param */ + A_UINT32 value; +} wmi_echo_event_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_echo_cmd_fixed_param */ + A_UINT32 value; +} wmi_echo_cmd_fixed_param; + + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_pdev_set_regdomain_cmd_fixed_param */ + + /** pdev_id for identifying the MAC + * See macros starting with WMI_PDEV_ID_ for values. + */ + A_UINT32 pdev_id; + /** reg domain code */ + A_UINT32 reg_domain; + A_UINT32 reg_domain_2G; + A_UINT32 reg_domain_5G; + A_UINT32 conformance_test_limit_2G; + A_UINT32 conformance_test_limit_5G; + A_UINT32 dfs_domain; +} wmi_pdev_set_regdomain_cmd_fixed_param; + +typedef struct { + /** TRUE for scan start and flase for scan end */ + A_UINT32 scan_start; +} wmi_pdev_scan_cmd; + +/* WMI support for setting ratemask in target */ + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_vdev_config_ratemask_fixed_param */ + A_UINT32 vdev_id; + /* 0 - cck/ofdm + * 1 - HT + * 2 - VHT */ + A_UINT32 type; + + A_UINT32 mask_lower32; + A_UINT32 mask_higher32; +} wmi_vdev_config_ratemask_cmd_fixed_param; + +/* nrp action - Filter Neighbor Rx Packets - add/remove filter */ +enum { + WMI_FILTER_NRP_ACTION_ADD = 0x1, + WMI_FILTER_NRP_ACTION_REMOVE = 0x2, + WMI_FILTER_NRP_ACTION_GET_LIST = 0x3, +}; /* nrp - Neighbor Rx Packets */ + +/* nrp type - Filter Neighbor Rx Packets - ap/client addr */ +enum { + WMI_FILTER_NRP_TYPE_AP_BSSID = 0x1, + WMI_FILTER_NRP_TYPE_STA_MACADDR = 0x2, +}; + +/* nrp flag - Filter Neighbor Rx Packets + * (capture flag, 2 & 3 not initially supported) + */ +enum { + WMI_FILTER_NRP_CAPTURE_ONLY_RX_PACKETS = 0x1, + WMI_FILTER_NRP_CAPTURE_ONLY_TX_PACKETS = 0x2, + WMI_FILTER_NRP_CAPTURE_BOTH_TXRX_PACKETS = 0x3, +}; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_vdev_filter_nrp_config_cmd_fixed_param */ + A_UINT32 vdev_id; + /* AP Bssid or Client Mac-addr */ + wmi_mac_addr addr; + /* Add/Remove NRF Filter */ + A_UINT32 action; /* WMI_FILTER_NRP_ACTION enum */ + /* client/ap filter */ + A_UINT32 type; /* WMI_FILTER_NRP_TYPE enum */ + /* optional - tx/rx capture */ + A_UINT32 flag; /* WMI_FILTER_NRP_CAPTURE enum */ + /* BSSID index - index of the BSSID register */ + A_UINT32 bssid_idx; +} wmi_vdev_filter_nrp_config_cmd_fixed_param; /* Filter for Neighbor Rx Packets */ + + +/*Command to set/unset chip in quiet mode*/ +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_pdev_set_quiet_cmd_fixed_param */ + A_UINT32 pdev_id; /** pdev_id for identifying the MAC, See macros starting with WMI_PDEV_ID_ for values. */ + A_UINT32 period; /*period in TUs*/ + A_UINT32 duration; /*duration in TUs*/ + A_UINT32 next_start; /*offset in TUs*/ + A_UINT32 enabled; /*enable/disable*/ +} wmi_pdev_set_quiet_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_vdev_set_quiet_cmd_fixed_param */ + A_UINT32 vdev_id; /* Virtual interface ID */ + A_UINT32 period; /* period in TUs */ + A_UINT32 duration; /* duration in TUs */ + A_UINT32 next_start; /* offset in TUs */ + A_UINT32 enabled; /* enable/disable */ +} wmi_vdev_set_quiet_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_vdev_set_custom_aggr_size_cmd_fixed_param */ + A_UINT32 vdev_id; /* vdev id indicating to which the vdev custom aggregation size will be applied. */ + A_UINT32 tx_aggr_size; /* Size for tx aggregation (max MPDUs per A-MPDU) for the vdev mentioned in vdev id */ + A_UINT32 rx_aggr_size; /* Size for rx aggregation (block ack window size limit) for the vdev mentioned in vdev id*/ +} wmi_vdev_set_custom_aggr_size_cmd_fixed_param; + +/* + * Command to enable/disable Green AP Power Save. + * This helps conserve power during AP operation. When the AP has no + * stations associated with it, the host can enable Green AP Power Save + * to request the firmware to shut down all but one transmit and receive + * chains. + */ +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_pdev_green_ap_ps_enable_cmd_fixed_param */ + /** pdev_id for identifying the MAC + * See macros starting with WMI_PDEV_ID_ for values. + */ + A_UINT32 pdev_id; + A_UINT32 enable; /*1:enable, 0:disable*/ +} wmi_pdev_green_ap_ps_enable_cmd_fixed_param; + + +#define MAX_HT_IE_LEN 32 +/* DEPRECATED */ +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_pdev_set_ht_ie_cmd_fixed_param */ + A_UINT32 reserved0; /** placeholder for pdev_id of future multiple MAC products. Init. to 0. */ + A_UINT32 ie_len; /*length of the ht ie in the TLV ie_data[] */ + A_UINT32 tx_streams; /* Tx streams supported for this HT IE */ + A_UINT32 rx_streams; /* Rx streams supported for this HT IE */ +/** The TLV for the HT IE follows: + * A_UINT32 ie_data[]; + */ +} wmi_pdev_set_ht_ie_cmd_fixed_param; + +#define MAX_VHT_IE_LEN 32 +/* DEPRECATED */ +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_pdev_set_vht_ie_cmd_fixed_param */ + A_UINT32 reserved0; /** placeholder for pdev_id of future multiple MAC products. Init. to 0. */ + A_UINT32 ie_len; /*length of the vht ie in the TLV ie_data[] */ + A_UINT32 tx_streams; /* Tx streams supported for this HT IE */ + A_UINT32 rx_streams; /* Rx streams supported for this HT IE */ +/** The TLV for the VHT IE follows: + * A_UINT32 ie_data[]; + */ +} wmi_pdev_set_vht_ie_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_pdev_set_base_macaddr_cmd_fixed_param */ + /** pdev_id for identifying the MAC + * See macros starting with WMI_PDEV_ID_ for values. + */ + A_UINT32 pdev_id; + wmi_mac_addr base_macaddr; +} wmi_pdev_set_base_macaddr_cmd_fixed_param; + +/* + * For now, the spectral configuration is global rather than + * per-vdev. The vdev is a placeholder and will be ignored + * by the firmware. + */ +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_vdev_spectral_configure_cmd_fixed_param */ + A_UINT32 vdev_id; + A_UINT32 spectral_scan_count; + A_UINT32 spectral_scan_period; + A_UINT32 spectral_scan_priority; + A_UINT32 spectral_scan_fft_size; + A_UINT32 spectral_scan_gc_ena; + A_UINT32 spectral_scan_restart_ena; + A_UINT32 spectral_scan_noise_floor_ref; + A_UINT32 spectral_scan_init_delay; + A_UINT32 spectral_scan_nb_tone_thr; + A_UINT32 spectral_scan_str_bin_thr; + A_UINT32 spectral_scan_wb_rpt_mode; + A_UINT32 spectral_scan_rssi_rpt_mode; + A_UINT32 spectral_scan_rssi_thr; + A_UINT32 spectral_scan_pwr_format; + A_UINT32 spectral_scan_rpt_mode; + A_UINT32 spectral_scan_bin_scale; + A_UINT32 spectral_scan_dBm_adj; + A_UINT32 spectral_scan_chn_mask; +} wmi_vdev_spectral_configure_cmd_fixed_param; + +/* + * Enabling, disabling and triggering the spectral scan + * is a per-vdev operation. That is, it will set channel + * flags per vdev rather than globally; so concurrent scan/run + * and multiple STA (eg p2p, tdls, multi-band STA) is possible. + */ +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_vdev_spectral_enable_cmd_fixed_param */ + A_UINT32 vdev_id; + /* 0 - ignore; 1 - trigger, 2 - clear trigger */ + A_UINT32 trigger_cmd; + /* 0 - ignore; 1 - enable, 2 - disable */ + A_UINT32 enable_cmd; +} wmi_vdev_spectral_enable_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_vdev_get_tx_power_cmd_fixed_param */ + A_UINT32 vdev_id; +} wmi_vdev_get_tx_power_cmd_fixed_param; + +/** common structure used for wmi_vedv_get_tx_power_event */ +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_vdev_tx_power_event_fixed_param */ + A_UINT32 tx_power; /** units: 0.5 dBm, per-chain tx power */ + A_UINT32 vdev_id; /** unique id identifying the VDEV, generated by the caller */ +} wmi_vdev_get_tx_power_event_fixed_param; + +typedef enum { + /** Limit the offchannel duration */ + WMI_VDEV_LIMIT_OFFCHAN_ENABLE = 0x1, + /** Skip DFS channels from Scan channel list. + * valid for both host scans and FW scans */ + WMI_VDEV_LIMIT_OFFCHAN_SKIP_DFS = 0x2, +} wmi_vdev_limit_offchan_flags; + +typedef struct { + A_UINT32 tlv_header; /* WMITLV_TAG_STRUC_wmi_vdev_limit_offchan_cmd_fixed_param */ + /** Limit the duration of offchannel events requested by the vdev corresponding to the specified vdev_id */ + A_UINT32 vdev_id; + /** see enum wmi_vdev_limit_offchan_flags */ + A_UINT32 flags; + /** max offchannel time allowed in msec when WMI_VDEV_LIMIT_OFFCHAN_ENABLE flag is set */ + A_UINT32 max_offchan_time; + /** rest time in msec on the BSS channel */ + A_UINT32 rest_time; +} wmi_vdev_limit_offchan_cmd_fixed_param; + +#define WMI_CSA_EVENT_QSBW_ISE_ID_MASK 0x000000FF /* information sub element id for QSBW, expected value is 0x02 */ +#define WMI_CSA_EVENT_QSBW_ISE_LEN_MASK 0x0000FF00 /* length of QSBW ISE data, expected value is 0x02 */ +#define WMI_CSA_EVENT_QSBW_ISE_CAP_MASK 0x00FF0000 /* capabilities, 0x01 for 5MHz, 0x02 for 10MHz, 0x01|0x2 for both (see WMI_CSA_EVENT_QSBW_ISE bitmask defs) */ +#define WMI_CSA_EVENT_QSBW_ISE_NOTIF_MASK 0xFF000000 /* notification from AP, 0x01 for 5MHz, 0x02 for 10MHz (see WMI_CSA_EVENT_QSBW_ISE bitmask defs) */ + +#define WMI_CSA_EVENT_QSBW_ISE_ID 0x02 +#define WMI_CSA_EVENT_QSBW_ISE_LEN 0x02 + +#define WMI_CSA_EVENT_QSBW_ISE_5M_BITMASK 0x01 +#define WMI_CSA_EVENT_QSBW_ISE_10M_BITMASK 0x02 + +#define WMI_CSA_EVENT_QSBW_ISE_CAP_5M(qsbw_ise) \ + (((qsbw_ise) >> 16) & WMI_CSA_EVENT_QSBW_ISE_5M_BITMASK) +#define WMI_CSA_EVENT_QSBW_ISE_CAP_10M(qsbw_ise) \ + (((qsbw_ise) >> 16) & WMI_CSA_EVENT_QSBW_ISE_10M_BITMASK) +#define WMI_CSA_EVENT_QSBW_ISE_NOTIF_5M(qsbw_ise) \ + (((qsbw_ise) >> 24) & WMI_CSA_EVENT_QSBW_ISE_5M_BITMASK) +#define WMI_CSA_EVENT_QSBW_ISE_NOTIF_10M(qsbw_ise) \ + (((qsbw_ise) >> 24) & WMI_CSA_EVENT_QSBW_ISE_10M_BITMASK) + +typedef enum { + WMI_CSA_IE_PRESENT = 0x00000001, + WMI_XCSA_IE_PRESENT = 0x00000002, + WMI_WBW_IE_PRESENT = 0x00000004, + WMI_CSWARP_IE_PRESENT = 0x00000008, + WMI_QSBW_ISE_PRESENT = 0x00000010, +} WMI_CSA_EVENT_IES_PRESENT_FLAG; + +/* wmi CSA receive event from beacon frame */ +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_csa_event_fixed_param */ + A_UINT32 i_fc_dur; /* Bit 0-15: FC, Bit 16-31: DUR */ + wmi_mac_addr i_addr1; + wmi_mac_addr i_addr2; + /* NOTE: size of array of csa_ie[], xcsa_ie[], and wb_ie[] cannot be + * changed in the future without breaking WMI compatibility */ + A_UINT32 csa_ie[2]; + A_UINT32 xcsa_ie[2]; + A_UINT32 wb_ie[2]; + A_UINT32 cswarp_ie; + A_UINT32 ies_present_flag; /* WMI_CSA_EVENT_IES_PRESENT_FLAG */ + A_UINT32 qsbw_ise; +} wmi_csa_event_fixed_param; + +typedef enum { + WAL_PEER_MCAST2UCAST_DISABLED = 0, + WAL_PEER_MCAST2UCAST_DROP_EMPTY = 1, /* Drop the frames if match is not found */ + WAL_PEER_MCAST2UCAST_MCAST_EMPTY = 2, /* Send as mcast if match is not found */ +} WMI_PEER_MCAST2UCAST_MODE; + +typedef enum { + PKT_PWR_SAVE_NAP_ENABLE = 0x00000001, + PKT_PWR_SAVE_LS_ENABLE = 0x00000002, + PKT_PWR_SAVE_DS_ENABLE = 0x00000004, + + PKT_PWR_SAVE_BTCOEX_ENABLE = 0x00000008, + + PKT_PWR_SAVE_FSM_ENABLE = 0x80000000, +} WMI_PDEV_PKT_PWR_SAVE_LEVEL; + +typedef enum { + /** TX chain mask */ + WMI_PDEV_PARAM_TX_CHAIN_MASK = 0x1, + /** RX chain mask */ + WMI_PDEV_PARAM_RX_CHAIN_MASK, + /** TX power limit for 2G Radio */ + WMI_PDEV_PARAM_TXPOWER_LIMIT2G, + /** TX power limit for 5G Radio */ + WMI_PDEV_PARAM_TXPOWER_LIMIT5G, + /** TX power scale */ + WMI_PDEV_PARAM_TXPOWER_SCALE, + /** Beacon generation mode . 0: host, 1: target */ + WMI_PDEV_PARAM_BEACON_GEN_MODE, + /** Beacon generation mode . 0: staggered 1: bursted */ + WMI_PDEV_PARAM_BEACON_TX_MODE, + /** Resource manager off chan mode . + * 0: turn off off chan mode. 1: turn on offchan mode + */ + WMI_PDEV_PARAM_RESMGR_OFFCHAN_MODE, + /** Protection mode 0: no protection 1:use CTS-to-self 2: use RTS/CTS */ + WMI_PDEV_PARAM_PROTECTION_MODE, + /** Dynamic bandwidth 0: disable 1: enable */ + WMI_PDEV_PARAM_DYNAMIC_BW, + /** Non aggregrate/ 11g sw retry threshold.0-disable */ + WMI_PDEV_PARAM_NON_AGG_SW_RETRY_TH, + /** aggregrate sw retry threshold. 0-disable*/ + WMI_PDEV_PARAM_AGG_SW_RETRY_TH, + /** Station kickout threshold (non of consecutive failures).0-disable */ + WMI_PDEV_PARAM_STA_KICKOUT_TH, + /** Aggerate size scaling configuration per AC */ + WMI_PDEV_PARAM_AC_AGGRSIZE_SCALING, + /** LTR enable */ + WMI_PDEV_PARAM_LTR_ENABLE, + /** LTR latency for BE, in us */ + WMI_PDEV_PARAM_LTR_AC_LATENCY_BE, + /** LTR latency for BK, in us */ + WMI_PDEV_PARAM_LTR_AC_LATENCY_BK, + /** LTR latency for VI, in us */ + WMI_PDEV_PARAM_LTR_AC_LATENCY_VI, + /** LTR latency for VO, in us */ + WMI_PDEV_PARAM_LTR_AC_LATENCY_VO, + /** LTR AC latency timeout, in ms */ + WMI_PDEV_PARAM_LTR_AC_LATENCY_TIMEOUT, + /** LTR platform latency override, in us */ + WMI_PDEV_PARAM_LTR_SLEEP_OVERRIDE, + /** LTR-M override, in us */ + WMI_PDEV_PARAM_LTR_RX_OVERRIDE, + /** Tx activity timeout for LTR, in us */ + WMI_PDEV_PARAM_LTR_TX_ACTIVITY_TIMEOUT, + /** L1SS state machine enable */ + WMI_PDEV_PARAM_L1SS_ENABLE, + /** Deep sleep state machine enable */ + WMI_PDEV_PARAM_DSLEEP_ENABLE, + /** RX buffering flush enable */ + WMI_PDEV_PARAM_PCIELP_TXBUF_FLUSH, + /** RX buffering matermark */ + WMI_PDEV_PARAM_PCIELP_TXBUF_WATERMARK, + /** RX buffering timeout enable */ + WMI_PDEV_PARAM_PCIELP_TXBUF_TMO_EN, + /** RX buffering timeout value */ + WMI_PDEV_PARAM_PCIELP_TXBUF_TMO_VALUE, + /** pdev level stats update period in ms */ + WMI_PDEV_PARAM_PDEV_STATS_UPDATE_PERIOD, + /** vdev level stats update period in ms */ + WMI_PDEV_PARAM_VDEV_STATS_UPDATE_PERIOD, + /** peer level stats update period in ms */ + WMI_PDEV_PARAM_PEER_STATS_UPDATE_PERIOD, + /** beacon filter status update period */ + WMI_PDEV_PARAM_BCNFLT_STATS_UPDATE_PERIOD, + /** QOS Mgmt frame protection MFP/PMF 0: disable, 1: enable */ + WMI_PDEV_PARAM_PMF_QOS, + /** Access category on which ARP frames are sent */ + WMI_PDEV_PARAM_ARP_AC_OVERRIDE, + /** DCS configuration */ + WMI_PDEV_PARAM_DCS, + /** Enable/Disable ANI on target */ + WMI_PDEV_PARAM_ANI_ENABLE, + /** configure the ANI polling period */ + WMI_PDEV_PARAM_ANI_POLL_PERIOD, + /** configure the ANI listening period */ + WMI_PDEV_PARAM_ANI_LISTEN_PERIOD, + /** configure OFDM immunity level */ + WMI_PDEV_PARAM_ANI_OFDM_LEVEL, + /** configure CCK immunity level */ + WMI_PDEV_PARAM_ANI_CCK_LEVEL, + /** Enable/Disable CDD for 1x1 STAs in rate control module */ + WMI_PDEV_PARAM_DYNTXCHAIN, + /** Enable/Disable proxy STA */ + WMI_PDEV_PARAM_PROXY_STA, + /** Enable/Disable low power state when all VDEVs are inactive/idle. */ + WMI_PDEV_PARAM_IDLE_PS_CONFIG, + /** Enable/Disable power gating sleep */ + WMI_PDEV_PARAM_POWER_GATING_SLEEP, + /** Enable/Disable Rfkill */ + WMI_PDEV_PARAM_RFKILL_ENABLE, + /** Set Bursting DUR */ + WMI_PDEV_PARAM_BURST_DUR, + /** Set Bursting ENABLE */ + WMI_PDEV_PARAM_BURST_ENABLE, + /** HW rfkill config */ + WMI_PDEV_PARAM_HW_RFKILL_CONFIG, + /** Enable radio low power features */ + WMI_PDEV_PARAM_LOW_POWER_RF_ENABLE, + /** L1SS entry and residency time track */ + WMI_PDEV_PARAM_L1SS_TRACK, + /** set hyst at runtime, requirement from SS */ + WMI_PDEV_PARAM_HYST_EN, + /** Enable/ Disable POWER COLLAPSE */ + WMI_PDEV_PARAM_POWER_COLLAPSE_ENABLE, + /** configure LED system state */ + WMI_PDEV_PARAM_LED_SYS_STATE, + /** Enable/Disable LED */ + WMI_PDEV_PARAM_LED_ENABLE, + /** set DIRECT AUDIO time latency */ + WMI_PDEV_PARAM_AUDIO_OVER_WLAN_LATENCY, /* DEPRECATED */ + /** set DIRECT AUDIO Feature ENABLE */ + WMI_PDEV_PARAM_AUDIO_OVER_WLAN_ENABLE, /* DEPRECATED */ + /** pdev level whal mib stats update enable */ + WMI_PDEV_PARAM_WHAL_MIB_STATS_UPDATE_ENABLE, + /** ht/vht info based on vdev */ + WMI_PDEV_PARAM_VDEV_RATE_STATS_UPDATE_PERIOD, + /** Set CTS channel BW for dynamic BW adjustment feature */ + WMI_PDEV_PARAM_CTS_CBW, + /** Set GPIO pin info used by WNTS */ + WMI_PDEV_PARAM_WNTS_CONFIG, + /** Enable/Disable hardware adaptive early rx feature */ + WMI_PDEV_PARAM_ADAPTIVE_EARLY_RX_ENABLE, + /** The minimum early rx duration, to ensure early rx duration is non-zero */ + WMI_PDEV_PARAM_ADAPTIVE_EARLY_RX_MIN_SLEEP_SLOP, + /** Increasing/decreasing step used by hardware */ + WMI_PDEV_PARAM_ADAPTIVE_EARLY_RX_INC_DEC_STEP, + /** The fixed early rx duration when adaptive early rx is disabled */ + WMI_PDEV_PARAM_EARLY_RX_FIX_SLEEP_SLOP, + /** Enable/Disable bmiss based adaptive beacon timeout feature */ + WMI_PDEV_PARAM_BMISS_BASED_ADAPTIVE_BTO_ENABLE, + /** The minimum beacon timeout duration, to ensure beacon timeout duration is non-zero */ + WMI_PDEV_PARAM_BMISS_BTO_MIN_BCN_TIMEOUT, + /** Increasing/decreasing step used by hardware */ + WMI_PDEV_PARAM_BMISS_BTO_INC_DEC_STEP, + /** The fixed beacon timeout duration when bmiss based adaptive beacon timeout is disabled */ + WMI_PDEV_PARAM_BTO_FIX_BCN_TIMEOUT, + /** Enable/Disable Congestion Estimator based adaptive beacon timeout feature */ + WMI_PDEV_PARAM_CE_BASED_ADAPTIVE_BTO_ENABLE, + /** combo value of ce_id, ce_threshold, ce_time, refer to WMI_CE_BTO_CE_ID_MASK */ + WMI_PDEV_PARAM_CE_BTO_COMBO_CE_VALUE, + /** 2G TX chain mask */ + WMI_PDEV_PARAM_TX_CHAIN_MASK_2G, + /** 2G RX chain mask */ + WMI_PDEV_PARAM_RX_CHAIN_MASK_2G, + /** 5G TX chain mask */ + WMI_PDEV_PARAM_TX_CHAIN_MASK_5G, + /** 5G RX chain mask */ + WMI_PDEV_PARAM_RX_CHAIN_MASK_5G, + /* Set tx chain mask for CCK rates */ + WMI_PDEV_PARAM_TX_CHAIN_MASK_CCK, + /* Set tx chain mask for 1SS stream */ + WMI_PDEV_PARAM_TX_CHAIN_MASK_1SS, + /* Enable/Disable CTS2Self for P2P GO when Non-P2P Client is connected */ + WMI_PDEV_PARAM_CTS2SELF_FOR_P2P_GO_CONFIG, + /** TX power backoff in dB: tx power -= param value + * Host passes values(DB) to Halphy, Halphy reduces the power table by + * the values. Safety check will happen in Halphy + */ + WMI_PDEV_PARAM_TXPOWER_DECR_DB, + /** enable and disable aggregate burst along with duration */ + WMI_PDEV_PARAM_AGGR_BURST, + /** Set the global RX decap mode */ + WMI_PDEV_PARAM_RX_DECAP_MODE, + /** Enable/Disable Fast channel reset */ + WMI_PDEV_PARAM_FAST_CHANNEL_RESET, + /** Default antenna for Smart antenna */ + WMI_PDEV_PARAM_SMART_ANTENNA_DEFAULT_ANTENNA, + /** Set the user-specified antenna gain */ + WMI_PDEV_PARAM_ANTENNA_GAIN, + /** Set the user-specified RX filter */ + WMI_PDEV_PARAM_RX_FILTER, + /** configure the user-specified MCAST tid for managed mcast feature + * 0-15 is the valid range. 0xff will clear the tid setting */ + WMI_PDEV_SET_MCAST_TO_UCAST_TID, + /** Enable/Disable Proxy sta mode */ + WMI_PDEV_PARAM_PROXY_STA_MODE, + /** configure the mcast2ucast mode for the pdev->peer_mcast. + * See WMI_PEER_MCAST2UCAST_MODE for possible values */ + WMI_PDEV_PARAM_SET_MCAST2UCAST_MODE, + /** Sets the Mcast buffers for cloning, to support Mcast enhancement */ + WMI_PDEV_PARAM_SET_MCAST2UCAST_BUFFER, + /** Remove the Mcast buffers added by host */ + WMI_PDEV_PARAM_REMOVE_MCAST2UCAST_BUFFER, + /** En/disable station power save state indication */ + WMI_PDEV_PEER_STA_PS_STATECHG_ENABLE, + /** Access category on which ARP frames are sent */ + WMI_PDEV_PARAM_IGMPMLD_AC_OVERRIDE, + /** allow or disallow interbss frame forwarding */ + WMI_PDEV_PARAM_BLOCK_INTERBSS, + /** Enable/Disable reset */ + WMI_PDEV_PARAM_SET_DISABLE_RESET_CMDID, + /** Enable/Disable/Set MSDU_TTL in milliseconds. */ + WMI_PDEV_PARAM_SET_MSDU_TTL_CMDID, + /** Set global PPDU duration limit (usec). */ + WMI_PDEV_PARAM_SET_PPDU_DURATION_CMDID, + /** set txbf sounding period of vap in milliseconds */ + WMI_PDEV_PARAM_TXBF_SOUND_PERIOD_CMDID, + /** Set promiscuous mode */ + WMI_PDEV_PARAM_SET_PROMISC_MODE_CMDID, + /** Set burst mode */ + WMI_PDEV_PARAM_SET_BURST_MODE_CMDID, + /** enable enhanced stats */ + WMI_PDEV_PARAM_EN_STATS, + /** Set mu-grouping policy */ + WMI_PDEV_PARAM_MU_GROUP_POLICY, + /** Channel Hopping Enable */ + WMI_PDEV_PARAM_NOISE_DETECTION, + /** Set Channel Hopping NF threshold in dBm */ + WMI_PDEV_PARAM_NOISE_THRESHOLD, + /** Set PAPRD policy */ + WMI_PDEV_PARAM_DPD_ENABLE, + /** Enable/disable mcast/bcast echo, used by ProxySTA */ + WMI_PDEV_PARAM_SET_MCAST_BCAST_ECHO, + /** ATF enable/disable strict schedule */ + WMI_PDEV_PARAM_ATF_STRICT_SCH, + /** ATF set access category duration, B0-B29 duration, B30-B31: AC */ + WMI_PDEV_PARAM_ATF_SCHED_DURATION, + /** Default antenna polarization */ + WMI_PDEV_PARAM_ANT_PLZN, + /** Set mgmt retry limit */ + WMI_PDEV_PARAM_MGMT_RETRY_LIMIT, + /** Set CCA sensitivity level in dBm */ + WMI_PDEV_PARAM_SENSITIVITY_LEVEL, + /** Set 2G positive and negative Tx power in 0.5dBm units */ + WMI_PDEV_PARAM_SIGNED_TXPOWER_2G, + /** Set 5G positive and negative Tx power in 0.5dBm + * units */ + WMI_PDEV_PARAM_SIGNED_TXPOWER_5G, + /** Enable/disble AMSDU for tids */ + WMI_PDEV_PARAM_ENABLE_PER_TID_AMSDU, + /** Enable/disable AMPDU for tids */ + WMI_PDEV_PARAM_ENABLE_PER_TID_AMPDU, + /** Set CCA threshold in dBm */ + WMI_PDEV_PARAM_CCA_THRESHOLD, + /** RTS Fixed rate setting */ + WMI_PDEV_PARAM_RTS_FIXED_RATE, + /** Pdev reset */ + WMI_PDEV_PARAM_PDEV_RESET, + /** wapi mbssid offset **/ + WMI_PDEV_PARAM_WAPI_MBSSID_OFFSET, + /** ARP DEBUG source address*/ + WMI_PDEV_PARAM_ARP_DBG_SRCADDR, + /** ARP DEBUG destination address*/ + WMI_PDEV_PARAM_ARP_DBG_DSTADDR, + /** ATF enable/disable obss noise scheduling */ + WMI_PDEV_PARAM_ATF_OBSS_NOISE_SCH, + /** ATF obss noise scaling factor */ + WMI_PDEV_PARAM_ATF_OBSS_NOISE_SCALING_FACTOR, + /** + * TX power reduction scaling exponent - final tx power is the + * nominal tx power (A_MIN(reg_pow,ctl,etc..)) divided by + * 2^(scale exponent). For example: + * If this scale exponent is 0, the power is unchanged (divided by 2^0) + * If this factor is 1, the power is scaled down by 2^1, i.e. 3 dB + * If this factor is 2, the power is scaled down by 2^2, i.e. 6 dB + * If this factor is 3, the power is scaled down by 2^3, i.e. 9 dB + */ + WMI_PDEV_PARAM_CUST_TXPOWER_SCALE, + /** ATF enabe/disabe dynamically */ + WMI_PDEV_PARAM_ATF_DYNAMIC_ENABLE, + /** Set tx retry limit for control frames. 0 = disable, 31 = max */ + WMI_PDEV_PARAM_CTRL_RETRY_LIMIT, + /** Set propagation delay for 2G / 5G band. + * The propagation delay is fundamentally a per-peer property, but + * the target may not support per-peer settings for ack timeouts. + * This pdev parameter allows the MAC-level ack timeout to be set to + * a value suitable for the worst-case propagation delay of any peer + * within that pdev. + * Units are microseconds. + */ + WMI_PDEV_PARAM_PROPAGATION_DELAY, + /** + * Host can enable/disable ANT DIV feature + * if it's been enabled in BDF + */ + WMI_PDEV_PARAM_ENA_ANT_DIV, + /** Host can force one chain to select a specific ANT */ + WMI_PDEV_PARAM_FORCE_CHAIN_ANT, + /** + * Start a cycle ANT self test periodically. + * In the test, the FW would select each ANT pair + * one by one, the cycle time could be configured + * via WMI_PDEV_PARAM_ANT_DIV_SELFTEST_INTVL + */ + WMI_PDEV_PARAM_ANT_DIV_SELFTEST, + /** + * Configure the cycle time of ANT self test, + * the unit is micro second. Per the timer + * limitation, too small value could be not so + * accurate. + */ + WMI_PDEV_PARAM_ANT_DIV_SELFTEST_INTVL, + /** + * wlan stats observation period, the unit is millisecond. + * The value of 0 is used to turn off periodic stats report. + */ + WMI_PDEV_PARAM_STATS_OBSERVATION_PERIOD, + /** + * Set tx_ppdu_delay[] bin size to specify how many + * milliseconds each bin of the wmi_tx_stats.tx_ppdu_delay[] + * histogram represents. + */ + WMI_PDEV_PARAM_TX_PPDU_DELAY_BIN_SIZE_MS, + /** set wmi_tx_stats.tx_ppdu_delay[] array length */ + WMI_PDEV_PARAM_TX_PPDU_DELAY_ARRAY_LEN, + /** set wmi_tx_stats.tx_mpdu_aggr[] array length */ + WMI_PDEV_PARAM_TX_MPDU_AGGR_ARRAY_LEN, + /** set wmi_rx_stats.rx_mpdu_aggr[] array length */ + WMI_PDEV_PARAM_RX_MPDU_AGGR_ARRAY_LEN, + /** Set TX delay value in TX sch module, unit is microseconds */ + WMI_PDEV_PARAM_TX_SCH_DELAY, + /** Set RTS enable for SIFS bursting */ + WMI_PDEV_PARAM_ENABLE_RTS_SIFS_BURSTING, + /** Set Maximum number of MPDUs in an AMPDU*/ + WMI_PDEV_PARAM_MAX_MPDUS_IN_AMPDU, + + /** Enable/disable peer stats info mechanism + * A zero value disables; a non-zero value enables. + */ + WMI_PDEV_PARAM_PEER_STATS_INFO_ENABLE, + + /** Configure Fast PWR Transition mode + * 0x0 -> inidcates Fast PWR transition disabled + * 0x1 -> indicates Static mode enabled + * 0x2 -> indicates Dynamic mode enabled + */ + WMI_PDEV_PARAM_FAST_PWR_TRANSITION, + + /** Enable/disable radio channel stats mechanism + * A zero value disables; a non-zero value enables. + */ + WMI_PDEV_PARAM_RADIO_CHAN_STATS_ENABLE, + /** Enable/disable radio diagnosis feature + * which allows retrieving the status of radio. + * A zero value disables; a non-zero value enables. + */ + WMI_PDEV_PARAM_RADIO_DIAGNOSIS_ENABLE, + /** Enable/Disable mesh mcast traffic + * 1 - Allow mesh mcast traffic + * 0 - Disallow mesh mcast traffic + */ + WMI_PDEV_PARAM_MESH_MCAST_ENABLE, + /** Enable/Disable smart chainmask scheme + * 1 - Enable smart chainmask scheme + * 0 - Disable smart chainmask scheme + */ + WMI_PDEV_PARAM_SMART_CHAINMASK_SCHEME, + /** Enable/Disable alternate chainmask scheme + * 1 - Enable alternate chainmask scheme + * 0 - Disable alternate chainmask scheme + */ + WMI_PDEV_PARAM_ALTERNATIVE_CHAINMASK_SCHEME, + /** User configured parameters for antenna diversity algorithm + * BIT[25..13]: Probe period (milliseconds units) + * BIT[12..0]: Stay period (milliseconds units) + */ + WMI_PDEV_PARAM_ANT_DIV_USRCFG, + /** pdev packet power save levels, + * refer to WMI_PDEV_PKT_PWR_SAVE_LEVEL + */ + WMI_PDEV_PARAM_PACKET_POWER_SAVE_LEVEL, + /** Define IOT pattern to be enabled/disabled + * bit values: 0 - disable, 1 - enable + * BIT[0..31]: each bit represents an IOT pattern + * ----- + * Bit 0 - avoid SMPS with certain APs + * Bits 31:1 - reserved + */ + WMI_PDEV_PARAM_SET_IOT_PATTERN, + /** ACK timeout - change wireless packet ack timeout configuration, + * units are microseconds + */ + WMI_PDEV_PARAM_ACK_TIMEOUT, + /** Number of TX chains to use for a/b/g rates. + * bit 0~15 : 11b mode TX chain number. + * bit 16~31 : 11ag mode TX chain number. + */ + WMI_PDEV_PARAM_ABG_MODE_TX_CHAIN_NUM, + /** Enable/Disable cck txfir override + * bit 0 - enable (1) or disable (0) CCK tx FIR + * bits 31:1 - unused / reserved (set to 0) + */ + WMI_PDEV_PARAM_ENABLE_CCK_TXFIR_OVERRIDE, + /** Enable/Disable DTIM Synth + * 1- Enable DTIM Synth + * 0- Disable DTIM Synth + */ + WMI_PDEV_PARAM_DTIM_SYNTH, +} WMI_PDEV_PARAM; + +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_pdev_set_param_cmd_fixed_param */ + /** pdev_id for identifying the MAC + * See macros starting with WMI_PDEV_ID_ for values. + */ + A_UINT32 pdev_id; + /** parameter id */ + A_UINT32 param_id; /* WMI_PDEV_PARAM */ + /** parameter value */ + A_UINT32 param_value; +} wmi_pdev_set_param_cmd_fixed_param; + +/** MACRO define to set / get 11b and 11ag mode TX chain number: + * bit 0~15 : 11b mode TX chain number. + * bit 16~31: 11ag mode TX chain number. + */ +#define WMI_PDEV_PARAM_11B_TX_CHAIN_NUM_S 0 +#define WMI_PDEV_PARAM_11B_TX_CHAIN_NUM 0x0000FFFF +#define WMI_PDEV_PARAM_11AG_TX_CHAIN_NUM_S 16 +#define WMI_PDEV_PARAM_11AG_TX_CHAIN_NUM 0xFFFF0000 + +#define WMI_PDEV_PARAM_GET_11B_TX_CHAIN_NUM(word32) WMI_F_MS(word32, WMI_PDEV_PARAM_11B_TX_CHAIN_NUM) +#define WMI_PDEV_PARAM_SET_11B_TX_CHAIN_NUM(word32, value) WMI_F_RMW(word32,value,WMI_PDEV_PARAM_11B_TX_CHAIN_NUM) + +#define WMI_PDEV_PARAM_GET_11AG_TX_CHAIN_NUM(word32) WMI_F_MS(word32, WMI_PDEV_PARAM_11AG_TX_CHAIN_NUM) +#define WMI_PDEV_PARAM_SET_11AG_TX_CHAIN_NUM(word32, value) WMI_F_RMW(word32,value,WMI_PDEV_PARAM_11AG_TX_CHAIN_NUM) + +/* param_value for param_id WMI_PDEV_PARAM_CTS_CBW */ +typedef enum { + WMI_CTS_CBW_INVALID = 0, + WMI_CTS_CBW_20, + WMI_CTS_CBW_40, + WMI_CTS_CBW_80, + WMI_CTS_CBW_80_80, + WMI_CTS_CBW_160, +} WMI_CTS_CBW; + +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_pdev_get_tpc_config_cmd_fixed_param */ + /** pdev_id for identifying the MAC + * See macros starting with WMI_PDEV_ID_ for values. + */ + A_UINT32 pdev_id; + /** parameter */ + A_UINT32 param; +} wmi_pdev_get_tpc_config_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* WMITLV_TAG_STRUC_wmi_pdev_div_get_rssi_antid_fixed_param */ + /** pdev_id for identifying the MAC */ + A_UINT32 pdev_id; + /** RSSI (rssi_chain_x_pri20) on each chain (units: dB above noise floor) */ + A_UINT32 chain_rssi[WMI_MAX_CHAINS]; + /** index of the last-used antenna for each chain */ + A_UINT32 ant_id[WMI_MAX_CHAINS]; + /** mac address of diversity peer */ + wmi_mac_addr macaddr; +} wmi_pdev_div_get_rssi_antid_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* WMITLV_TAG_STRUC_wmi_pdev_bss_chan_info_request_fixed_param */ + A_UINT32 param; /* 1 = read only, 2= read and clear */ +} wmi_pdev_bss_chan_info_request_fixed_param; + +#define WMI_FAST_DIVERSITY_BIT_OFFSET 0 +#define WMI_SLOW_DIVERSITY_BIT_OFFSET 1 + +#define WMI_SLOW_DIVERSITY_CH0_WEIGHT_SHIFT 2 +#define WMI_SLOW_DIVERSITY_CH0_WEIGHT_MASK (0xf << WMI_SLOW_DIVERSITY_CH0_WEIGHT_SHIFT) +#define WMI_SLOW_DIVERSITY_CH0_WEIGHT_GET_BITS(word32) \ + (((word32) & WMI_SLOW_DIVERSITY_CH0_WEIGHT_MASK) >> WMI_SLOW_DIVERSITY_CH0_WEIGHT_SHIFT) +#define WMI_SLOW_DIVERSITY_CH0_WEIGHT_SET_BITS(word32, value) \ + do { \ + (word32) &= ~WMI_SLOW_DIVERSITY_CH0_WEIGHT_MASK; \ + (word32) |= ((value) << WMI_SLOW_DIVERSITY_CH0_WEIGHT_SHIFT) & \ + WMI_SLOW_DIVERSITY_CH0_WEIGHT_MASK; \ + } while (0) + +#define WMI_SLOW_DIVERSITY_CH1_WEIGHT_SHIFT 6 +#define WMI_SLOW_DIVERSITY_CH1_WEIGHT_MASK (0xf << WMI_SLOW_DIVERSITY_CH1_WEIGHT_SHIFT) +#define WMI_SLOW_DIVERSITY_CH1_WEIGHT_GET_BITS(word32) \ + (((word32) & WMI_SLOW_DIVERSITY_CH1_WEIGHT_MASK) >> WMI_SLOW_DIVERSITY_CH1_WEIGHT_SHIFT) +#define WMI_SLOW_DIVERSITY_CH1_WEIGHT_SET_BITS(word32, value) \ + do { \ + (word32) &= ~WMI_SLOW_DIVERSITY_CH1_WEIGHT_MASK; \ + (word32) |= ((value) << WMI_SLOW_DIVERSITY_CH1_WEIGHT_SHIFT) & \ + WMI_SLOW_DIVERSITY_CH1_WEIGHT_MASK; \ + } while (0) + +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_pdev_set_antenna_diversity_cmd_fixed_param */ + union { + A_UINT32 mac_id; /* OBSOLETE - will be removed once all refs are gone */ + /** pdev_id for identifying the MAC + * See macros starting with WMI_PDEV_ID_ for values. + */ + A_UINT32 pdev_id; + }; + /** + * The following "value" field is divided into bit fields as follows: + * bits | purpose + * -----+--------------------------------------- + * 0 | enable/disable FAST diversity + * 1 | enable/disable SLOW diversity + * 5:2 | chain0 slow-diversity weighting factor + * 9:6 | chain1 slow-diversity weighting factor + * 31:10| currenty unused (set to 0x0) + * Refer to the above WMI_[FAST/SLOW]_DIVERSITY constants. + */ + A_UINT32 value; +} wmi_pdev_set_antenna_diversity_cmd_fixed_param; + +#define WMI_MAX_RSSI_THRESHOLD_SUPPORTED 3 + +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_rssi_breach_monitor_config_cmd_fixed_param */ + A_UINT32 vdev_id; /* vdev_id, where RSSI monitoring will take place */ + A_UINT32 request_id; /* host will configure request_id and firmware echo this id in RSSI_BREACH_EVENT */ + A_UINT32 enabled_bitmap; /* bit [0-2] = low_rssi_breach_enabled[0-2] enabled, bit [3-5] = hi_rssi_breach_enabled[0-2] */ + A_UINT32 low_rssi_breach_threshold[WMI_MAX_RSSI_THRESHOLD_SUPPORTED]; /* unit dBm. host driver to make sure [0] > [1] > [2] */ + A_UINT32 hi_rssi_breach_threshold[WMI_MAX_RSSI_THRESHOLD_SUPPORTED]; /* unit dBm. host driver to make sure [0] < [1] < [2] */ + A_UINT32 lo_rssi_reenable_hysteresis; /* unit dBm. once low rssi[] breached, same event bitmap will be generated only after signal gets better than this level. This value is adopted for all low_rssi_breach_threshold[3] */ + A_UINT32 hi_rssi_reenable_histeresis;/* unit dBm. once hi rssi[] breached, same event bitmap will be generated only after signal gets worse than this level. This value is adopted for all hi_rssi_breach_threshold[3] */ + A_UINT32 min_report_interval; /* After last event is generated, we wait until this interval to generate next event */ + A_UINT32 max_num_report; /* this is to suppress number of event to be generated */ +} wmi_rssi_breach_monitor_config_fixed_param; + +typedef struct { + /** parameter */ + A_UINT32 param; +} wmi_pdev_dump_cmd; + +typedef enum { + PAUSE_TYPE_CHOP = 0x1, /** for MCC (switch channel), only vdev_map is valid */ + PAUSE_TYPE_PS = 0x2, /** for peer station sleep in sap mode, only peer_id is valid */ + PAUSE_TYPE_UAPSD = 0x3, /** for uapsd, only peer_id and tid_map are valid. */ + PAUSE_TYPE_P2P_CLIENT_NOA = 0x4, /** only vdev_map is valid, actually only one vdev id is set at one time */ + PAUSE_TYPE_P2P_GO_PS = 0x5, /** only vdev_map is valid, actually only one vdev id is set at one time */ + PAUSE_TYPE_STA_ADD_BA = 0x6, /** only peer_id and tid_map are valid, actually only one tid is set at one time */ + PAUSE_TYPE_AP_PS = 0x7, /** for pausing AP vdev when all the connected clients are in PS. only vdev_map is valid */ + PAUSE_TYPE_IBSS_PS = 0x8, /** for pausing IBSS vdev when all the peers are in PS. only vdev_map is valid */ + PAUSE_TYPE_CHOP_TDLS_OFFCHAN = 0x9, /** for TDLS offchannel MCC (switch channel), only vdev_map is valid, TDLS connection tracker needs to be notified */ + + PAUSE_TYPE_HOST = 0x15, /* host is requesting vdev pause */ +} wmi_tx_pause_type; + +typedef enum { + ACTION_PAUSE = 0x0, + ACTION_UNPAUSE = 0x1, +} wmi_tx_pause_action; + +typedef struct { + A_UINT32 tlv_header; + A_UINT32 pause_type; + A_UINT32 action; + A_UINT32 vdev_map; + A_UINT32 peer_id; + A_UINT32 tid_map; +} wmi_tx_pause_event_fixed_param; + +typedef enum { + WMI_MGMT_TX_COMP_TYPE_COMPLETE_OK = 0, + WMI_MGMT_TX_COMP_TYPE_DISCARD, + WMI_MGMT_TX_COMP_TYPE_INSPECT, + WMI_MGMT_TX_COMP_TYPE_COMPLETE_NO_ACK, + WMI_MGMT_TX_COMP_TYPE_MAX, +} WMI_MGMT_TX_COMP_STATUS_TYPE; + +typedef struct { + A_UINT32 tlv_header; + A_UINT32 desc_id; /* from tx_send_cmd */ + A_UINT32 status; /* WMI_MGMT_TX_COMP_STATUS_TYPE */ + /** pdev_id for identifying the MAC that transmitted the mgmt frame + * See macros starting with WMI_PDEV_ID_ for values. + */ + A_UINT32 pdev_id; +} wmi_mgmt_tx_compl_event_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_offchan_data_tx_compl_event_fixed_param */ + A_UINT32 desc_id; /* from tx_send_cmd */ + A_UINT32 status; /* same status as WMI_MGMT_TX_COMP_STATUS_TYPE */ + /** pdev_id for identifying the MAC that transmitted the mgmt frame + * See macros starting with WMI_PDEV_ID_ for values. + */ + A_UINT32 pdev_id; +} wmi_offchan_data_tx_compl_event_fixed_param; + +typedef struct { + A_UINT32 tlv_header; + A_UINT32 num_reports; + /* tlv for completion + * A_UINT32 desc_ids[num_reports]; <- from tx_send_cmd + * A_UINT32 status[num_reports]; <- WMI_MGMT_TX_COMP_STATUS_TYPE + */ +} wmi_mgmt_tx_compl_bundle_event_fixed_param; + +#define WMI_TPC_RATE_MAX 160 +/* WMI_TPC_TX_NUM_CHAIN macro can't be changed without breaking the WMI compatibility */ +#define WMI_TPC_TX_NUM_CHAIN 4 + +typedef enum { + WMI_TPC_CONFIG_EVENT_FLAG_TABLE_CDD = 0x1, + WMI_TPC_CONFIG_EVENT_FLAG_TABLE_STBC = 0x2, + WMI_TPC_CONFIG_EVENT_FLAG_TABLE_TXBF = 0x4, +} WMI_TPC_CONFIG_EVENT_FLAG; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_pdev_tpc_config_event_fixed_param */ + A_UINT32 regDomain; + A_UINT32 chanFreq; + A_UINT32 phyMode; + A_UINT32 twiceAntennaReduction; + A_UINT32 twiceMaxRDPower; + A_INT32 twiceAntennaGain; + A_UINT32 powerLimit; + A_UINT32 rateMax; + A_UINT32 numTxChain; + A_UINT32 ctl; + A_UINT32 flags; + /* WMI_TPC_TX_NUM_CHAIN macro can't be changed without breaking the WMI compatibility */ + A_INT8 maxRegAllowedPower[WMI_TPC_TX_NUM_CHAIN]; + A_INT8 maxRegAllowedPowerAGCDD[WMI_TPC_TX_NUM_CHAIN][WMI_TPC_TX_NUM_CHAIN]; + A_INT8 maxRegAllowedPowerAGSTBC[WMI_TPC_TX_NUM_CHAIN][WMI_TPC_TX_NUM_CHAIN]; + A_INT8 maxRegAllowedPowerAGTXBF[WMI_TPC_TX_NUM_CHAIN][WMI_TPC_TX_NUM_CHAIN]; + /** pdev_id for identifying the MAC + * See macros starting with WMI_PDEV_ID_ for values. + */ + A_UINT32 pdev_id; +/* This TLV is followed by a byte array: + * A_UINT8 ratesArray[]; + */ +} wmi_pdev_tpc_config_event_fixed_param; + +typedef struct { + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_pdev_div_rssi_antid_event_fixed_param */ + A_UINT32 tlv_header; + /** how many elements in the MAX_CHAINS arrays below contain valid info */ + A_UINT32 num_chains_valid; + /** RSSI (rssi_chain_x_pri20) on each chain (units: dB above noise floor) */ + A_UINT32 chain_rssi[WMI_MAX_CHAINS]; + /** index of the last-used antenna for each chain */ + A_UINT32 ant_id[WMI_MAX_CHAINS]; + /** mac address of diversity peer */ + wmi_mac_addr macaddr; +} wmi_pdev_div_rssi_antid_event_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* WMITLV_TAG_STRUC_wmi_pdev_bss_chan_info_event_fixed_param */ + A_UINT32 freq; /* Units in MHz */ + A_INT32 noise_floor; /* units are dBm */ + + /* rx clear - how often the channel was unused */ + A_UINT32 rx_clear_count_low; /* low 31 bits of rx_clear cnt in 64bits format */ + A_UINT32 rx_clear_count_high; /* high 31 bits of rx_clear cnt in 64bits format */ + + /* cycle count - elapsed time during the measured period, in clock ticks */ + A_UINT32 cycle_count_low; /* low 31 bits of cycle cnt in 64bits format */ + A_UINT32 cycle_count_high; /* high 31 bits of cycle cnt in 64bits format */ + + /* tx cycle count - elapsed time spent in tx, in clock ticks */ + A_UINT32 tx_cycle_count_low; /* low 31 bits of tx_cycle cnt in 64bits format */ + A_UINT32 tx_cycle_count_high; /* high 31 bits of tx_cycle cnt in 64bits format */ + + /* rx cycle count - elapsed time spent in rx, in clock ticks */ + A_UINT32 rx_cycle_count_low; /* low 31 bits of rx_cycle cnt in 64bits format */ + A_UINT32 rx_cycle_count_high; /* high 31 bits of rx_cycle cnt in 64bits format */ + + A_UINT32 rx_bss_cycle_count_low; /* low 31 bits of rx cycle cnt for my bss in 64bits format */ + A_UINT32 rx_bss_cycle_count_high; /* high 31 bits of rx_cycle cnt for my bss in 64bits format */ +} wmi_pdev_bss_chan_info_event_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_pdev_l1ss_track_event_fixed_param */ + A_UINT32 periodCnt; + A_UINT32 L1Cnt; + A_UINT32 L11Cnt; + A_UINT32 L12Cnt; + A_UINT32 L1Entry; + A_UINT32 L11Entry; + A_UINT32 L12Entry; + /** pdev_id for identifying the MAC + * See macros starting with WMI_PDEV_ID_ for values. + */ + A_UINT32 pdev_id; +} wmi_pdev_l1ss_track_event_fixed_param; + +typedef struct { + A_UINT32 len; + A_UINT32 msgref; + A_UINT32 segmentInfo; +} wmi_pdev_seg_hdr_info; + + +/* + * Transmit power scale factor. + * + */ +typedef enum { + WMI_TP_SCALE_MAX = 0, /* no scaling (default) */ + WMI_TP_SCALE_50 = 1, /* 50% of max (-3 dBm) */ + WMI_TP_SCALE_25 = 2, /* 25% of max (-6 dBm) */ + WMI_TP_SCALE_12 = 3, /* 12% of max (-9 dBm) */ + WMI_TP_SCALE_MIN = 4, /* min, but still on */ + WMI_TP_SCALE_SIZE = 5, /* max num of enum */ +} WMI_TP_SCALE; + +#define WMI_MAX_DEBUG_MESG (sizeof(A_UINT32) * 32) + +typedef struct { + /** message buffer, NULL terminated */ + char bufp[WMI_MAX_DEBUG_MESG]; +} wmi_debug_mesg_event; + +enum { + /** P2P device */ + VDEV_SUBTYPE_P2PDEV = 0, + /** P2P client */ + VDEV_SUBTYPE_P2PCLI, + /** P2P GO */ + VDEV_SUBTYPE_P2PGO, + /** BT3.0 HS */ + VDEV_SUBTYPE_BT, +}; + +typedef struct { + /** idnore power , only use flags , mode and freq */ + wmi_channel chan; +} wmi_pdev_set_channel_cmd; + +typedef enum { + WMI_PKTLOG_EVENT_RX = 0x1, + WMI_PKTLOG_EVENT_TX = 0x2, + WMI_PKTLOG_EVENT_RCF = 0x4, /* Rate Control Find */ + WMI_PKTLOG_EVENT_RCU = 0x8, /* Rate Control Update */ + /* 0x10 used by deprecated DBG_PRINT */ + WMI_PKTLOG_EVENT_SMART_ANTENNA = 0x20, /* To support Smart Antenna */ + WMI_PKTLOG_EVENT_SW = 0x40, /* To support SW defined events */ +} WMI_PKTLOG_EVENT; + +typedef enum { + WMI_PKTLOG_ENABLE_AUTO = 0, /* (default) FW will decide under what conditions to enable pktlog */ + WMI_PKTLOG_ENABLE_FORCE = 1, /* pktlog unconditionally enabled */ +} WMI_PKTLOG_ENABLE; + +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_pdev_pktlog_enable_cmd_fixed_param */ + /** pdev_id for identifying the MAC + * See macros starting with WMI_PDEV_ID_ for values. + */ + A_UINT32 pdev_id; + A_UINT32 evlist; /* WMI_PKTLOG_EVENT */ + A_UINT32 enable; /* WMI_PKTLOG_ENABLE */ +} wmi_pdev_pktlog_enable_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_pdev_pktlog_disable_cmd_fixed_param */ + /** pdev_id for identifying the MAC + * See macros starting with WMI_PDEV_ID_ for values. + */ + A_UINT32 pdev_id; +} wmi_pdev_pktlog_disable_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_mib_stats_enable_cmd_fixed_param */ + /** pdev_id for identifying the MAC + * See macros starting with WMI_PDEV_ID_ for values. + */ + A_UINT32 pdev_id; + A_UINT32 enable_Mib; /** enable for mib stats collection. Stats are delivered to host in wmi_mib_stats structure. + * If enable_Mib=1, stats collection is enabled. If enable_Mib=0, stats collection does not happen */ +} wmi_mib_stats_enable_cmd_fixed_param; + +/** Customize the DSCP (bit) to TID (0-7) mapping for QOS. + * NOTE: This constant cannot be changed without breaking + * WMI Compatibility. */ + +#define WMI_DSCP_MAP_MAX (64) +/* + * @brief dscp_tid_map_cmdid - command to send the dscp to tid map to the target + * @details + * Create an API for sending the custom DSCP-to-TID map to the target + * If this is a request from the user space or from above the UMAC + * then the best place to implement this is in the umac_if_offload of the OL path. + * Provide a place holder for this API in the ieee80211com (ic). + * + * This API will be a function pointer in the ieee80211com (ic). Any user space calls for manually setting the DSCP-to-TID mapping + * in the target should be directed to the function pointer in the ic. + * + * Implementation details of the API to send the map to the target are as described- + * + * 1. The function will have 2 arguments- struct ieee80211com, DSCP-to-TID map. + * DSCP-to-TID map is a one dimensional u_int32_t array of length 64 to accomodate + * 64 TID values for 2^6 (64) DSCP ids. + * Example: + * A_UINT32 dscp_tid_map[WMI_DSCP_MAP_MAX] = { + * 0, 0, 0, 0, 0, 0, 0, 0, + * 1, 1, 1, 1, 1, 1, 1, 1, + * 2, 2, 2, 2, 2, 2, 2, 2, + * 3, 3, 3, 3, 3, 3, 3, 3, + * 4, 4, 4, 4, 4, 4, 4, 4, + * 5, 5, 5, 5, 5, 5, 5, 5, + * 6, 6, 6, 6, 6, 6, 6, 6, + * 7, 7, 7, 7, 7, 7, 7, 7, + * }; + * + * 2. Request for the WMI buffer of size equal to the size of the DSCP-to-TID map. + * + * 3. Copy the DSCP-to-TID map into the WMI buffer. + * + * 4. Invoke the wmi_unified_cmd_send to send the cmd buffer to the target with the + * WMI_PDEV_SET_DSCP_TID_MAP_CMDID. Arguments to the wmi send cmd API + * (wmi_unified_send_cmd) are wmi handle, cmd buffer, length of the cmd buffer and + * the WMI_PDEV_SET_DSCP_TID_MAP_CMDID id. + * + */ +/* DEPRECATED - use VDEV level command instead + * (wmi_vdev_set_dscp_tid_map_cmd_fixed_param) + */ +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_pdev_set_dscp_tid_map_cmd_fixed_param */ + A_UINT32 reserved0; /** placeholder for pdev_id of future multiple MAC products. Init. to 0. */ + /* map indicating DSCP to TID conversion */ + A_UINT32 dscp_to_tid_map[WMI_DSCP_MAP_MAX]; +} wmi_pdev_set_dscp_tid_map_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_vdev_set_dscp_tid_map_cmd_fixed_param */ + A_UINT32 vdev_id; + /** map indicating DSCP to TID conversion */ + A_UINT32 dscp_to_tid_map[WMI_DSCP_MAP_MAX]; + A_UINT32 enable_override; +} wmi_vdev_set_dscp_tid_map_cmd_fixed_param; + +enum WMI_WAKE_GPIO_TYPE { + WMI_WAKE_GPIO_LOW = 1, + WMI_WAKE_GPIO_HIGH = 2, + WMI_WAKE_GPIO_RISING_EDGE = 3, + WMI_WAKE_GPIO_FALLING_EDGE = 4, +}; + +/** + * Set GPIO numbers used to wakeup host and wakeup target. + */ +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_WMI_PDEV_SET_WAKEUP_CONFIG_CMDID_fixed_param */ + A_UINT32 host_wakeup_gpio; /* gpio num used to wakeup host, 0xff disable wakeup gpio */ + A_UINT32 host_wakeup_type; /* refer to WMI_WAKE_GPIO_TYPE */ + A_UINT32 target_wakeup_gpio; /* gpio num used to wakeup target, 0xff disable wakeup gpio */ + A_UINT32 target_wakeup_type; /* refer to WMI_WAKE_GPIO_TYPE */ +} WMI_PDEV_SET_WAKEUP_CONFIG_CMDID_fixed_param; + +/** Fixed rate (rate-code) for broadcast/ multicast data frames */ +/* @brief bcast_mcast_data_rate - set the rates for the bcast/ mcast frames + * @details + * Create an API for setting the custom rate for the MCAST and BCAST frames + * in the target. If this is a request from the user space or from above the UMAC + * then the best place to implement this is in the umac_if_offload of the OL path. + * Provide a place holder for this API in the ieee80211com (ic). + * + * Implementation details of the API to set custom rates for MCAST and BCAST in + * the target are as described- + * + * 1. The function will have 3 arguments- + * vap structure, + * MCAST/ BCAST identifier code, + * 8 bit rate code + * + * The rate-code is a 1-byte field in which:for given rate, nss and preamble + * b'7-b-6 indicate the preamble (0 OFDM, 1 CCK, 2, HT, 3 VHT) + * b'5-b'4 indicate the NSS (0 - 1x1, 1 - 2x2, 2 - 3x3) + * b'3-b'0 indicate the rate, which is indicated as follows: + * OFDM : 0: OFDM 48 Mbps + * 1: OFDM 24 Mbps + * 2: OFDM 12 Mbps + * 3: OFDM 6 Mbps + * 4: OFDM 54 Mbps + * 5: OFDM 36 Mbps + * 6: OFDM 18 Mbps + * 7: OFDM 9 Mbps + * CCK (pream == 1) + * 0: CCK 11 Mbps Long + * 1: CCK 5.5 Mbps Long + * 2: CCK 2 Mbps Long + * 3: CCK 1 Mbps Long + * 4: CCK 11 Mbps Short + * 5: CCK 5.5 Mbps Short + * 6: CCK 2 Mbps Short + * HT/VHT (pream == 2/3) + * 0..7: MCS0..MCS7 (HT) + * 0..9: MCS0..MCS9 (VHT) + * + * 2. Invoke the wmi_unified_vdev_set_param_send to send the rate value + * to the target. + * Arguments to the API are- + * wmi handle, + * VAP interface id (av_if_id) defined in ol_ath_vap_net80211, + * WMI_VDEV_PARAM_BCAST_DATA_RATE/ WMI_VDEV_PARAM_MCAST_DATA_RATE, + * rate value. + */ +typedef enum { + WMI_SET_MCAST_RATE, + WMI_SET_BCAST_RATE +} MCAST_BCAST_RATE_ID; + +typedef struct { + MCAST_BCAST_RATE_ID rate_id; + A_UINT32 rate; +} mcast_bcast_rate; + +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_wmm_params */ + A_UINT32 cwmin; + A_UINT32 cwmax; + A_UINT32 aifs; + A_UINT32 txoplimit; + A_UINT32 acm; + A_UINT32 no_ack; +} wmi_wmm_params; + +/* DEPRECATED - use VDEV level command instead + * (wmi_vdev_set_wmm_params_cmd_fixed_param) + */ +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_pdev_set_wmm_params_cmd_fixed_param */ + A_UINT32 reserved0; /** placeholder for pdev_id of future multiple MAC products. Init. to 0. */ + A_UINT32 dg_type; + +/* The TLVs for the 4 AC follows: + * wmi_wmm_params wmm_params_ac_be; + * wmi_wmm_params wmm_params_ac_bk; + * wmi_wmm_params wmm_params_ac_vi; + * wmi_wmm_params wmm_params_ac_vo; + */ +} wmi_pdev_set_wmm_params_cmd_fixed_param; + +typedef enum { + WMI_REQUEST_PEER_STAT = 0x01, + WMI_REQUEST_AP_STAT = 0x02, + WMI_REQUEST_PDEV_STAT = 0x04, + WMI_REQUEST_VDEV_STAT = 0x08, + WMI_REQUEST_BCNFLT_STAT = 0x10, + WMI_REQUEST_VDEV_RATE_STAT = 0x20, + WMI_REQUEST_INST_STAT = 0x40, + WMI_REQUEST_MIB_STAT = 0x80, + WMI_REQUEST_RSSI_PER_CHAIN_STAT = 0x100, + WMI_REQUEST_CONGESTION_STAT = 0x200, + WMI_REQUEST_PEER_EXTD_STAT = 0x400, +} wmi_stats_id; + +/* + * cfg_retry_count is set to max number of times the AP should try sending + * QoS Null frames to the STA for measuring the instantaneous RSSI + * + * retry_count is used to maintain the number of times the AP has tried sending + * QoS Null frames to the STA for measuring the instantaneous RSSI + */ +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_request_stats_cmd_sub_struc_param */ + A_UINT32 cfg_retry_count; + A_UINT32 retry_count; +} wmi_inst_rssi_stats_params; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_request_stats_cmd_fixed_param */ + wmi_stats_id stats_id; + /** unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; + /** peer MAC address */ + wmi_mac_addr peer_macaddr; +/* + * This TLV is (optionally) followed by other TLVs: + * wmi_inst_rssi_stats_params inst_rssi_params; + */ +} wmi_request_stats_cmd_fixed_param; + +/* stats type bitmap */ +#define WMI_LINK_STATS_RADIO 0x00000001 +#define WMI_LINK_STATS_IFACE 0x00000002 +#define WMI_LINK_STATS_ALL_PEER 0x00000004 +#define WMI_LINK_STATS_PER_PEER 0x00000008 + + +/* wifi clear statistics bitmap */ +#define WIFI_STATS_RADIO 0x00000001 /** all radio statistics */ +#define WIFI_STATS_RADIO_CCA 0x00000002 /** cca_busy_time (within radio statistics) */ +#define WIFI_STATS_RADIO_CHANNELS 0x00000004 /** all channel statistics (within radio statistics) */ +#define WIFI_STATS_RADIO_SCAN 0x00000008 /** all scan statistics (within radio statistics) */ +#define WIFI_STATS_IFACE 0x00000010 /** all interface statistics */ +#define WIFI_STATS_IFACE_TXRATE 0x00000020 /** all tx rate statistics (within interface statistics) */ +#define WIFI_STATS_IFACE_AC 0x00000040 /** all ac statistics (within interface statistics) */ +#define WIFI_STATS_IFACE_CONTENTION 0x00000080 /** all contention (min, max, avg) statistics (within ac statisctics) */ +#define WMI_STATS_IFACE_ALL_PEER 0x00000100 /** All peer stats on this interface */ +#define WMI_STATS_IFACE_PER_PEER 0x00000200 /** Clear particular peer stats depending on the peer_mac */ + +/** Default value for stats if the stats collection has not started */ +#define WMI_STATS_VALUE_INVALID 0xffffffff + +#define WMI_DIAG_ID_GET(diag_events_logs) WMI_GET_BITS(diag_events_logs, 0, 16) +#define WMI_DIAG_ID_SET(diag_events_logs, value) WMI_SET_BITS(diag_events_logs, 0, 16, value) +#define WMI_DIAG_TYPE_GET(diag_events_logs) WMI_GET_BITS(diag_events_logs, 16, 1) +#define WMI_DIAG_TYPE_SET(diag_events_logs, value) WMI_SET_BITS(diag_events_logs, 16, 1, value) +#define WMI_DIAG_ID_ENABLED_DISABLED_GET(diag_events_logs) WMI_GET_BITS(diag_events_logs, 17, 1) +#define WMI_DIAG_ID_ENABLED_DISABLED_SET(diag_events_logs, value) WMI_SET_BITS(diag_events_logs, 17, 1, value) + +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_diag_event_log_config_fixed_param */ + A_UINT32 num_of_diag_events_logs; +/* The TLVs will follow. + * A_UINT32 diag_events_logs_list[]; 0-15 Bits Diag EVENT/LOG ID, + * Bit 16 - DIAG type EVENT/LOG, 0 - Event, 1 - LOG + * Bit 17 Indicate if the DIAG type is Enabled/Disabled. + */ +} wmi_diag_event_log_config_fixed_param; + +#define WMI_DIAG_FREQUENCY_GET(diag_events_logs) WMI_GET_BITS(diag_events_logs, 17, 1) +#define WMI_DIAG_FREQUENCY_SET(diag_events_logs, value) WMI_SET_BITS(diag_events_logs, 17, 1, value) +#define WMI_DIAG_EXT_FEATURE_GET(diag_events_logs) WMI_GET_BITS(diag_events_logs, 18, 1) +#define WMI_DIAG_EXT_FEATURE_SET(diag_events_logs, value) WMI_SET_BITS(diag_events_logs, 18, 1, value) + +typedef struct { + A_UINT32 tlv_header; + A_UINT32 num_of_diag_events_logs; +/* The TLVs will follow. + * A_UINT32 diag_events_logs_list[]; 0-15 Bits Diag EVENT/LOG ID, + * Bit 16 - DIAG type EVENT/LOG, 0 - Event, 1 - LOG + * Bit 17 - Frequncy of the DIAG EVENT/LOG High Frequency -1, Low Frequency - 0 + * Bit 18 - Set if the EVENTS/LOGs are used for EXT DEBUG Framework + */ +} wmi_diag_event_log_supported_event_fixed_params; + +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_debug_mesg_flush_fixed_param*/ + A_UINT32 reserved0; /** placeholder for future */ +} wmi_debug_mesg_flush_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_debug_mesg_flush_complete_fixed_param*/ + A_UINT32 reserved0; /** placeholder for future */ +} wmi_debug_mesg_flush_complete_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_rssi_breach_fixed_param */ + /* vdev_id, where RSSI breach event occurred */ + A_UINT32 vdev_id; + /* request id */ + A_UINT32 request_id; + /* bitmap[0-2] is corresponding to low_rssi[0-2]. bitmap[3-5] is corresponding to hi_rssi[0-2]*/ + A_UINT32 event_bitmap; + /* rssi at the time of RSSI breach. Unit dBm */ + A_UINT32 rssi; + /* bssid of the monitored AP's */ + wmi_mac_addr bssid; +} wmi_rssi_breach_event_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_fw_mem_dump */ + /** unique id identifying the segment */ + A_UINT32 seg_id; + /** Start address of the segment to be read */ + A_UINT32 seg_start_addr_lo; + A_UINT32 seg_start_addr_hi; + /** Length of the segment to be read */ + A_UINT32 seg_length; + /** Host bufeer address to which the segment will be read and dumped */ + A_UINT32 dest_addr_lo; + A_UINT32 dest_addr_hi; +} wmi_fw_mem_dump; + +/* Command to get firmware memory dump*/ +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_get_fw_mem_dump_fixed_param */ + /** unique id identifying the request */ + A_UINT32 request_id; + /** number of memory dump segments */ + A_UINT32 num_fw_mem_dump_segs; +/** + * This TLV is followed by another TLV + * wmi_fw_mem_dump fw_mem_dump[]; + */ +} wmi_get_fw_mem_dump_fixed_param; + +/** Event to indicate the completion of fw mem dump */ +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_update_fw_mem_dump_fixed_param */ + /** unique id identifying the request, given in the request stats command */ + A_UINT32 request_id; + /*In case of Firmware memory dump */ + A_UINT32 fw_mem_dump_complete; +} wmi_update_fw_mem_dump_fixed_param; + + +typedef enum { + WMI_ROAMING_IDLE = 0, + WMI_ROAMING_ACTIVE = 1, +} wmi_roam_state; + +/* access categories */ +typedef enum { + WMI_AC_VO = 0, + WMI_AC_VI = 1, + WMI_AC_BE = 2, + WMI_AC_BK = 3, + WMI_AC_MAX = 4, +} wmi_traffic_ac; + +typedef enum { + WMI_STA_STATS = 0, + WMI_SOFTAP_STATS = 1, + WMI_IBSS_STATS = 2, + WMI_P2P_CLIENT_STATS = 3, + WMI_P2P_GO_STATS = 4, + WMI_NAN_STATS = 5, + WMI_MESH_STATS = 6, + } wmi_link_iface_type; + +/* channel operating width */ +typedef enum { + WMI_CHAN_WIDTH_20 = 0, + WMI_CHAN_WIDTH_40 = 1, + WMI_CHAN_WIDTH_80 = 2, + WMI_CHAN_WIDTH_160 = 3, + WMI_CHAN_WIDTH_80P80 = 4, + WMI_CHAN_WIDTH_5 = 5, + WMI_CHAN_WIDTH_10 = 6, +} wmi_channel_width; + +/*Clear stats*/ +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_clear_link_stats_cmd_fixed_param */ + /** unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; + /** stop_stats_collection_req = 1 will imply stop the statistics collection */ + A_UINT32 stop_stats_collection_req; + /** identifies what stats to be cleared */ + A_UINT32 stats_clear_req_mask; + /** identifies which peer stats to be cleared. Valid only while clearing PER_REER */ + wmi_mac_addr peer_macaddr; +} wmi_clear_link_stats_cmd_fixed_param; + +/* Link Stats configuration params. Trigger the link layer statistics collection*/ +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_start_link_stats_cmd_fixed_param */ + /** threshold to classify the pkts as short or long */ + A_UINT32 mpdu_size_threshold; + /** set for field debug mode. Driver should collect all statistics regardless of performance impact.*/ + A_UINT32 aggressive_statistics_gathering; +} wmi_start_link_stats_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_request_link_stats_cmd_fixed_param */ + /** Type of stats required. This is a bitmask WMI_LINK_STATS_RADIO, WMI_LINK_STATS_IFACE */ + A_UINT32 stats_type; + /** unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; + /** unique id identifying the request, generated by the caller */ + A_UINT32 request_id; + /** peer MAC address */ + wmi_mac_addr peer_macaddr; +} wmi_request_link_stats_cmd_fixed_param; + +/* channel statistics */ +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_channel_stats */ + /** Channel width (20, 40, 80, 80+80, 160) enum wmi_channel_width*/ + A_UINT32 channel_width; + /** Primary 20 MHz channel */ + A_UINT32 center_freq; + /** center frequency (MHz) first segment */ + A_UINT32 center_freq0; + /** center frequency (MHz) second segment */ + A_UINT32 center_freq1; + /** msecs the radio is awake (32 bits number accruing over time) */ + A_UINT32 radio_awake_time; + /** msecs the CCA register is busy (32 bits number accruing over time) */ + A_UINT32 cca_busy_time; +} wmi_channel_stats; + +/* + * Each step represents 0.5 dB. The starting value is 0 dBm. + * Thus the TPC levels cover 0 dBm to 31.5 dBm inclusive in 0.5 dB steps. + */ +#define MAX_TPC_LEVELS 64 + +/* radio statistics */ +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_radio_link_stats */ + /** Wifi radio (if multiple radio supported) */ + A_UINT32 radio_id; + /** msecs the radio is awake (32 bits number accruing over time) */ + A_UINT32 on_time; + /** msecs the radio is transmitting (32 bits number accruing over time) */ + A_UINT32 tx_time; + /** msecs the radio is in active receive (32 bits number accruing over time) */ + A_UINT32 rx_time; + /** msecs the radio is awake due to all scan (32 bits number accruing over time) */ + A_UINT32 on_time_scan; + /** msecs the radio is awake due to NAN (32 bits number accruing over time) */ + A_UINT32 on_time_nbd; + /** msecs the radio is awake due to G?scan (32 bits number accruing over time) */ + A_UINT32 on_time_gscan; + /** msecs the radio is awake due to roam?scan (32 bits number accruing over time) */ + A_UINT32 on_time_roam_scan; + /** msecs the radio is awake due to PNO scan (32 bits number accruing over time) */ + A_UINT32 on_time_pno_scan; + /** msecs the radio is awake due to HS2.0 scans and GAS exchange (32 bits number accruing over time) */ + A_UINT32 on_time_hs20; + /** number of channels */ + A_UINT32 num_channels; + /** tx time per TPC level - DEPRECATED + * This field is deprecated. + * It is superseded by the WMI_RADIO_TX_POWER_LEVEL_STATS_EVENTID message. + */ + A_UINT32 tx_time_per_tpc[MAX_TPC_LEVELS]; + /** msecs the radio is awake due to Host initiated scan (accruing over time) */ + A_UINT32 on_time_host_scan; + /** msecs the radio is awake due to LPI scan (accruing over time) */ + A_UINT32 on_time_lpi_scan; +} wmi_radio_link_stats; + +/** tx time per power level statistics */ +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_tx_power_level_stats_evt_fixed_param */ + /** total number of tx power levels */ + A_UINT32 total_num_tx_power_levels; + /** number of tx power levels that are carried in this event */ + A_UINT32 num_tx_power_levels; + /** offset of current stats + * If ((num_tx_power_levels + power_level_offset)) == + * total_num_tx_power_levels) + * this message completes the report of tx time per power levels. + * Otherwise, additional WMI_RADIO_TX_POWER_LEVEL_STATS_EVENTID messages + * will be sent by the target to deliver the remainder of the tx time + * per power level stats. + */ + A_UINT32 power_level_offset; + /* radio id for this tx time per power level statistics (if multiple radio supported) */ + A_UINT32 radio_id; +/* + * This TLV will be followed by a TLV containing a variable-length array of + * A_UINT32 with tx time per power level data + * A_UINT32 tx_time_per_power_level[num_tx_power_levels] + * The tx time is in units of milliseconds. + * The power levels are board-specific values; a board-specific translation + * has to be applied to determine what actual power corresponds to each + * power level. + * Just as the host has a BDF file available, the host should also have + * a data file available that provides the power level to power translations. + */ +} wmi_tx_power_level_stats_evt_fixed_param; + + +/** Radio statistics (once started) do not stop or get reset unless wifi_clear_link_stats is invoked */ +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_stats_event_fixed_param */ + /** unique id identifying the request, given in the request stats command */ + A_UINT32 request_id; + /** Number of radios*/ + A_UINT32 num_radio; + /** more_data will be set depending on the number of radios */ + A_UINT32 more_radio_events; +/* + * This TLV is followed by another TLV of array of bytes + * size of(struct wmi_radio_link_stats); + * + * This TLV is followed by another TLV of array of bytes + * num_channels * size of(struct wmi_channel_stats) + */ + +} wmi_radio_link_stats_event_fixed_param; + +/* per rate statistics */ +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_rate_stats */ + /** rate information + * The rate-code is a 1-byte field in which:for given rate, nss and preamble + * b'7-b-6 indicate the preamble (0 OFDM, 1 CCK, 2, HT, 3 VHT) + * b'5-b'4 indicate the NSS (0 - 1x1, 1 - 2x2, 2 - 3x3) + * b'3-b'0 indicate the rate, which is indicated as follows: + * OFDM : 0: OFDM 48 Mbps + * 1: OFDM 24 Mbps + * 2: OFDM 12 Mbps + * 3: OFDM 6 Mbps + * 4: OFDM 54 Mbps + * 5: OFDM 36 Mbps + * 6: OFDM 18 Mbps + * 7: OFDM 9 Mbps + * CCK (pream == 1) + * 0: CCK 11 Mbps Long + * 1: CCK 5.5 Mbps Long + * 2: CCK 2 Mbps Long + * 3: CCK 1 Mbps Long + * 4: CCK 11 Mbps Short + * 5: CCK 5.5 Mbps Short + * 6: CCK 2 Mbps Short + * HT/VHT (pream == 2/3) + * 0..7: MCS0..MCS7 (HT) + * 0..9: MCS0..MCS9 (VHT) + */ + A_UINT32 rate; + /** units of 100 Kbps */ + A_UINT32 bitrate; + /** number of successfully transmitted data pkts (ACK rcvd) */ + A_UINT32 tx_mpdu; + /** number of received data pkts */ + A_UINT32 rx_mpdu; + /** number of data packet losses (no ACK) */ + A_UINT32 mpdu_lost; + /** total number of data pkt retries */ + A_UINT32 retries; + /** number of short data pkt retries */ + A_UINT32 retries_short; + /** number of long data pkt retries */ + A_UINT32 retries_long; +} wmi_rate_stats; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_peer_link_stats */ + /** peer type (AP, TDLS, GO etc.) enum wmi_peer_type*/ + A_UINT32 peer_type; + /** mac address */ + wmi_mac_addr peer_mac_address; + /** peer wmi_CAPABILITY_XXX */ + A_UINT32 capabilities; + /** number of rates */ + A_UINT32 num_rates; +} wmi_peer_link_stats; + +/** PEER statistics (once started) reset and start afresh after each connection */ +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_peer_stats_event_fixed_param */ + /** unique id identifying the request, given in the request stats command */ + A_UINT32 request_id; + /** number of peers accomidated in this particular event */ + A_UINT32 num_peers; + /** Indicates the fragment number */ + A_UINT32 peer_event_number; + /** Indicates if there are more peers which will be sent as seperate peer_stats event */ + A_UINT32 more_data; + +/** + * This TLV is followed by another TLV + * num_peers * size of(struct wmi_peer_stats) + * num_rates * size of(struct wmi_rate_stats). num_rates is the sum of the rates of all the peers. + */ +} wmi_peer_stats_event_fixed_param; + +/* per access category statistics */ +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_wmm_ac_stats */ + /** access category (VI, VO, BE, BK) enum wmi_traffic_ac*/ + A_UINT32 ac_type; + /** number of successfully transmitted unicast data pkts (ACK rcvd) */ + A_UINT32 tx_mpdu; + /** number of received unicast mpdus */ + A_UINT32 rx_mpdu; + /** number of succesfully transmitted multicast data packets */ + /** STA case: implies ACK received from AP for the unicast packet in which mcast pkt was sent */ + A_UINT32 tx_mcast; + /** number of received multicast data packets */ + A_UINT32 rx_mcast; + /** number of received unicast a-mpdus */ + A_UINT32 rx_ampdu; + /** number of transmitted unicast a-mpdus */ + A_UINT32 tx_ampdu; + /** number of data pkt losses (no ACK) */ + A_UINT32 mpdu_lost; + /** total number of data pkt retries */ + A_UINT32 retries; + /** number of short data pkt retries */ + A_UINT32 retries_short; + /** number of long data pkt retries */ + A_UINT32 retries_long; + /** data pkt min contention time (usecs) */ + A_UINT32 contention_time_min; + /** data pkt max contention time (usecs) */ + A_UINT32 contention_time_max; + /** data pkt avg contention time (usecs) */ + A_UINT32 contention_time_avg; + /** num of data pkts used for contention statistics */ + A_UINT32 contention_num_samples; +} wmi_wmm_ac_stats; + +/* interface statistics */ +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_iface_link_stats */ + /** access point beacon received count from connected AP */ + A_UINT32 beacon_rx; + /** access point mgmt frames received count from connected AP (including Beacon) */ + A_UINT32 mgmt_rx; + /** action frames received count */ + A_UINT32 mgmt_action_rx; + /** action frames transmit count */ + A_UINT32 mgmt_action_tx; + /** access Point Beacon and Management frames RSSI (averaged) */ + A_UINT32 rssi_mgmt; + /** access Point Data Frames RSSI (averaged) from connected AP */ + A_UINT32 rssi_data; + /** access Point ACK RSSI (averaged) from connected AP */ + A_UINT32 rssi_ack; + /** number of peers */ + A_UINT32 num_peers; + /** Indicates how many peer_stats events will be sent depending on the num_peers. */ + A_UINT32 num_peer_events; + /** number of ac */ + A_UINT32 num_ac; + /** Roaming Stat */ + A_UINT32 roam_state; + /** Average Beacon spread offset is the averaged time delay between TBTT and beacon TSF */ + /** Upper 32 bits of averaged 64 bit beacon spread offset */ + A_UINT32 avg_bcn_spread_offset_high; + /** Lower 32 bits of averaged 64 bit beacon spread offset */ + A_UINT32 avg_bcn_spread_offset_low; + /** Takes value of 1 if AP leaks packets after sending an ACK for PM=1 otherwise 0 */ + A_UINT32 is_leaky_ap; + /** Average number of frames received from AP after receiving the ACK for a frame with PM=1 */ + A_UINT32 avg_rx_frms_leaked; + /** Rx leak watch window currently in force to minimize data loss because of leaky AP. Rx leak window is the + time driver waits before shutting down the radio or switching the channel and after receiving an ACK for + a data frame with PM bit set) */ + A_UINT32 rx_leak_window; + A_UINT32 tx_rts_succ_cnt; + A_UINT32 tx_rts_fail_cnt; + A_UINT32 tx_ppdu_succ_cnt; + A_UINT32 tx_ppdu_fail_cnt; + /** msecs the interface is in Connected state (accruing over time) */ + A_UINT32 connected_duration; + /** msecs the interface is in DisConnected state (accruing over time) */ + A_UINT32 disconnected_duration; + /** msecs the interface is doing RTT ranging (accruing over time) */ + A_UINT32 rtt_ranging_duration; + /** msecs the interface is in RTT responder mode (accruing over time) */ + A_UINT32 rtt_responder_duration; + /** Number of Probes (Tx) sent on the interface (accruing over time) */ + A_UINT32 num_probes_tx; + /** Number of Beacon misses on this interface (accruing over time) */ + A_UINT32 num_beacon_miss; +} wmi_iface_link_stats; + +typedef enum { + WMI_OFFLOAD_STATS_TYPE_SOC_BCAST = 0, + WMI_OFFLOAD_STATS_TYPE_SOC_MCAST = 1, + WMI_OFFLOAD_STATS_TYPE_SOC_UCAST = 2, + WMI_OFFLOAD_STATS_TYPE_ARP = 3, + WMI_OFFLOAD_STATS_TYPE_NS = 4, + WMI_OFFLOAD_STATS_TYPE_APF_BCAST = 5, + WMI_OFFLOAD_STATS_TYPE_APF_MCAST = 6, + WMI_OFFLOAD_STATS_TYPE_APF_UCAST = 7, + /* Add New offload stat type here */ + WMI_OFFLOAD_STATS_TYPE_MAX, +} wmi_offload_stats_type; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_iface_offload_stats */ + /** Type of offload stat. enum wmi_offload_stats_type **/ + A_UINT32 type; + /** Number of (MSDUs) frames Received **/ + A_UINT32 rx_count; + /** Number of frames Dropped **/ + A_UINT32 drp_count; + /** Number of frames for which FW Responded (Valid for ARP and NS only). (or) + * Number of frames forwarded to Host (Valid for stats type except ARP and NS). **/ + A_UINT32 fwd_count; +} wmi_iface_offload_stats; + +/** Interface statistics (once started) reset and start afresh after each connection */ +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_iface_link_stats_event_fixed_param */ + /** unique id identifying the request, given in the request stats command */ + A_UINT32 request_id; + /** unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; + /** Number of offload stats **/ + A_UINT32 num_offload_stats; +/* + * This TLV is followed by other TLVs: + * wmi_iface_link_stats iface_link_stats; + * num_ac * size of(struct wmi_wmm_ac_stats) + * wmi_iface_offload_stats iface_offload_stats[num_offload_stats] + */ +} wmi_iface_link_stats_event_fixed_param; + +/** Suspend option */ +enum { + WMI_PDEV_SUSPEND, /* suspend */ + WMI_PDEV_SUSPEND_AND_DISABLE_INTR, /* suspend and disable all interrupts */ +}; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_pdev_suspend_cmd_fixed_param */ + /* suspend option sent to target */ + A_UINT32 pdev_id; /** pdev_id for identifying the MAC, See macros starting with WMI_PDEV_ID_ for values. */ + A_UINT32 suspend_opt; +} wmi_pdev_suspend_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_pdev_resume_cmd_fixed_param */ + A_UINT32 pdev_id; /** pdev_id for identifying the MAC, See macros starting with WMI_PDEV_ID_ for values. */ +} wmi_pdev_resume_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_vdev_rate_stats_event_fixed_param, */ + A_UINT32 num_vdev_stats; /* number of vdevs */ +} wmi_vdev_rate_stats_event_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len, tag equals WMITLV_TAG_STRUC_wmi_vdev_rate_ht_info*/ + A_UINT32 vdevid; /* Id of the wlan vdev*/ + A_UINT32 tx_nss; /* Bit 28 of tx_rate_kbps has this info - based on last data packet transmitted*/ + A_UINT32 rx_nss; /* Bit 24 of rx_rate_kbps - same as above*/ + A_UINT32 tx_preamble; /* Bits 30-29 from tx_rate_kbps */ + A_UINT32 rx_preamble; /* Bits 26-25 from rx_rate_kbps */ +} wmi_vdev_rate_ht_info; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len, tag equals WMITLV_TAG_STRUC_wmi_rx_aggr_failure_event_fixed_param */ + A_UINT32 num_failure_info; /* How many holes on rx aggregation */ +} wmi_rx_aggr_failure_event_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len, tag equals WMITLV_wmi_rx_aggr_failure_info */ + A_UINT32 start_seq; /* start sequence number of the hole */ + A_UINT32 end_seq; /* end sequence number of the hole */ +} wmi_rx_aggr_failure_info; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_stats_event_fixed_param */ + wmi_stats_id stats_id; + /** number of pdev stats event structures (wmi_pdev_stats) 0 or 1 */ + A_UINT32 num_pdev_stats; + /** number of vdev stats event structures (wmi_vdev_stats) 0 or max vdevs */ + A_UINT32 num_vdev_stats; + /** number of peer stats event structures (wmi_peer_stats) 0 or max peers */ + A_UINT32 num_peer_stats; + A_UINT32 num_bcnflt_stats; + /** number of chan stats event structures (wmi_chan_stats) 0 to MAX MCC CHANS */ + A_UINT32 num_chan_stats; + /** number of MIB stats event structures (wmi_mib_stats) */ + A_UINT32 num_mib_stats; +/* This TLV is followed by another TLV of array of bytes + * A_UINT8 data[]; + * This data array contains + * num_pdev_stats * size of(struct wmi_pdev_stats) + * num_vdev_stats * size of(struct wmi_vdev_stats) + * num_peer_stats * size of(struct wmi_peer_stats) + * num_bcnflt_stats * size_of() + * num_chan_stats * size of(struct wmi_chan_stats) + * num_mib_stats * size of(struct wmi_mib_stats) + */ +/* If WMI_REQUEST_PEER_EXTD_STAT is set in stats_id, + * the data[] array also contains num_peer_stats * size of wmi_peer_extd_stats + * following the information elements listed above. + */ +} wmi_stats_event_fixed_param; + +/* WLAN channel CCA stats bitmap */ +#define WLAN_STATS_IDLE_TIME_SHIFT 0 +#define WLAN_STATS_IDLE_TIME_TIME 0x00000001 + +#define WLAN_STATS_TX_TIME_SHIFT 1 +#define WLAN_STATS_TX_TIME_MASK 0x00000002 + +#define WLAN_STATS_RX_IN_BSS_TIME_SHIFT 2 +#define WLAN_STATS_RX_IN_BSS_TIME_MASK 0x00000004 + +#define WLAN_STATS_RX_OUT_BSS_TIME_SHIFT 3 +#define WLAN_STATS_RX_OUT_BSS_TIME_MASK 0x00000008 + +#define WLAN_STATS_RX_BUSY_TIME_SHIFT 4 +#define WLAN_STATS_RX_BUSY_TIME_MASK 0x00000010 + +#define WLAN_STATS_RX_IN_BAD_COND_TIME_SHIFT 5 +#define WLAN_STATS_RX_IN_BAD_COND_TIME_MASK 0x00000020 + +#define WLAN_STATS_TX_IN_BAD_COND_TIME_SHIFT 6 +#define WLAN_STATS_TX_IN_BAD_COND_TIME_MASK 0x00000040 + +#define WLAN_STATS_WLAN_NOT_AVAIL_TIME_SHIFT 7 +#define WLAN_STATS_WLAN_NOT_AVAIL_TIME_MASK 0x00000080 + +/* WLAN peer signal stats bitmap */ +#define WLAN_STATS_PER_CHAIN_SNR_SHIFT 0 +#define WLAN_STATS_PER_CHAIN_SNR_MASK 0x00000001 + +#define WLAN_STATS_PER_CHAIN_NF_SHIFT 1 +#define WLAN_STATS_PER_CHAIN_NF_MASK 0x00000002 + +/* WLAN TX stats bitmap */ +#define WLAN_STATS_TX_MSDU_CNT_SHIFT 0 +#define WLAN_STATS_TX_MSDU_CNT_MASK 0x00000001 + +#define WLAN_STATS_TX_MPDU_CNT_SHIFT 1 +#define WLAN_STATS_TX_MPDU_CNT_MASK 0x00000002 + +#define WLAN_STATS_TX_PPDU_CNT_SHIFT 2 +#define WLAN_STATS_TX_PPDU_CNT_MASK 0x00000004 + +#define WLAN_STATS_TX_BYTES_SHIFT 3 +#define WLAN_STATS_TX_BYTES_MASK 0x00000008 + +#define WLAN_STATS_TX_MSDU_DROP_CNT_SHIFT 4 +#define WLAN_STATS_TX_MSDU_DROP_CNT_MASK 0x00000010 + +#define WLAN_STATS_TX_DROP_BYTES_SHIFT 5 +#define WLAN_STATS_TX_DROP_BYTES_MASK 0x00000020 + +#define WLAN_STATS_TX_MPDU_RETRY_CNT_SHIFT 6 +#define WLAN_STATS_TX_MPDU_RETRY_CNT_MASK 0x00000040 + +#define WLAN_STATS_TX_MPDU_FAIL_CNT_SHIFT 7 +#define WLAN_STATS_TX_MPDU_FAIL_CNT_MASK 0x00000080 + +#define WLAN_STATS_TX_PPDU_FAIL_CNT_SHIFT 8 +#define WLAN_STATS_TX_PPDU_FAIL_CNT_MASK 0x00000100 + +#define WLAN_STATS_TX_MPDU_AGGR_SHIFT 9 +#define WLAN_STATS_TX_MPDU_AGGR_MASK 0x00000200 + +#define WLAN_STATS_TX_SUCC_MCS_SHIFT 10 +#define WLAN_STATS_TX_SUCC_MCS_MASK 0x00000400 + +#define WLAN_STATS_TX_FAIL_MCS_SHIFT 11 +#define WLAN_STATS_TX_FAIL_MCS_MASK 0x00000800 + +#define WLAN_STATS_TX_PPDU_DELAY_SHIFT 12 +#define WLAN_STATS_TX_PPDU_DELAY_MASK 0x00001000 + +/* WLAN RX stats bitmap */ +#define WLAN_STATS_MAC_RX_MPDU_CNT_SHIFT 0 +#define WLAN_STATS_MAC_RX_MPDU_CNT_MASK 0x00000001 + +#define WLAN_STATS_MAC_RX_BYTES_SHIFT 1 +#define WLAN_STATS_MAC_RX_BYTES_MASK 0x00000002 + +#define WLAN_STATS_PHY_RX_PPDU_CNT_SHIFT 2 +#define WLAN_STATS_PHY_RX_PPDU_CNT_MASK 0x00000004 + +#define WLAN_STATS_PHY_RX_BYTES_SHIFT 3 +#define WLAN_STATS_PHY_RX_BYTES_MASK 0x00000008 + +#define WLAN_STATS_RX_DISORDER_CNT_SHIFT 4 +#define WLAN_STATS_RX_DISORDER_CNT_MASK 0x00000010 + +#define WLAN_STATS_RX_MPDU_RETRY_CNT_SHIFT 5 +#define WLAN_STATS_RX_MPDU_RETRY_CNT_MASK 0x00000020 + +#define WLAN_STATS_RX_MPDU_DUP_CNT_SHIFT 6 +#define WLAN_STATS_RX_MPDU_DUP_CNT_MASK 0x00000040 + +#define WLAN_STATS_RX_MPDU_DISCARD_CNT_SHIFT 7 +#define WLAN_STATS_RX_MPDU_DISCARD_CNT_MASK 0x00000080 + +#define WLAN_STATS_RX_MPDU_AGGR_SHIFT 8 +#define WLAN_STATS_RX_MPDU_AGGR_MASK 0x00000100 + +#define WLAN_STATS_RX_MCS_SHIFT 9 +#define WLAN_STATS_RX_MCS_MASK 0x00000200 + +#define WLAN_STATS_STA_PS_INDS_SHIFT 10 +#define WLAN_STATS_STA_PS_INDS_MASK 0x00000400 + +#define WLAN_STATS_STA_PS_DURS_SHIFT 11 +#define WLAN_STATS_STA_PS_DURS_MASK 0x00000800 + +#define WLAN_STATS_RX_PROBE_REQS_SHIFT 12 +#define WLAN_STATS_RX_PROBE_REQS_MASK 0x00001000 + +#define WLAN_STATS_RX_OTH_MGMTS_SHIFT 13 +#define WLAN_STATS_RX_OTH_MGMTS_MASK 0x00002000 + +typedef struct +{ + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_chan_cca_stats */ + A_UINT32 vdev_id; + /** Percentage of idle time, no TX, no RX, no interference */ + A_UINT32 idle_time; + /** Percentage of time transmitting packets */ + A_UINT32 tx_time; + /** Percentage of time receiving packets in current BSSs */ + A_UINT32 rx_in_bss_time; + /** Percentage of time receiving packets not in current BSSs */ + A_UINT32 rx_out_bss_time; + /** Percentage of time interference detected. */ + A_UINT32 rx_busy_time; + /** Percentage of time receiving packets with errors + * or packets flagged as retransmission or seqnum discontinued. */ + A_UINT32 rx_in_bad_cond_time; + /** Percentage of time the device transmitted packets that haven't been ACKed. */ + A_UINT32 tx_in_bad_cond_time; + /** Percentage of time the chip is unable to work in normal conditions. */ + A_UINT32 wlan_not_avail_time; +} wmi_chan_cca_stats; + +/** Thresholds of cca stats, stands for percentages of stats variation. + * Check wmi_chan_cca_stats for each stats's meaning. + */ +typedef struct +{ + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_chan_cca_stats_thresh */ + A_UINT32 idle_time; /* units = percent */ + A_UINT32 tx_time; /* units = percent */ + A_UINT32 rx_in_bss_time; /* units = percent */ + A_UINT32 rx_out_bss_time; /* units = percent */ + A_UINT32 rx_busy_time; /* units = percent */ + A_UINT32 rx_in_bad_cond_time; /* units = percent */ + A_UINT32 tx_in_bad_cond_time; /* units = percent */ + A_UINT32 wlan_not_avail_time; /* units = percent */ +} wmi_chan_cca_stats_thresh; + +typedef struct +{ + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_peer_signal_stats */ + A_UINT32 vdev_id; + A_UINT32 peer_id; + /** per chain SNR in current bss, units are dB */ + A_INT32 per_chain_snr[WMI_MAX_CHAINS]; + /** per chain background noise, units are dBm */ + A_INT32 per_chain_nf[WMI_MAX_CHAINS]; + /** per antenna rx MPDUs */ + A_UINT32 per_antenna_rx_mpdus[WMI_MAX_CHAINS]; + /** per antenna tx MPDUs */ + A_UINT32 per_antenna_tx_mpdus[WMI_MAX_CHAINS]; + /** num of valid chains for per antenna rx/tx MPDU cnts*/ + A_UINT32 num_chains_valid; +} wmi_peer_signal_stats; + +/** Thresholds of signal stats, stand for percentage of stats variation. + * Check wmi_peer_signal_stats for each stats's meaning. + */ +typedef struct +{ + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_peer_signal_stats_thresh */ + A_UINT32 per_chain_snr; /* units = dB */ + A_UINT32 per_chain_nf; /* units = dBm */ +} wmi_peer_signal_stats_thresh; + +typedef struct +{ + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_tx_stats */ + /** Number of total TX MSDUs on MAC layer in the period */ + A_UINT32 tx_msdu_cnt; + /** Number of total TX MPDUs on MAC layer in the period */ + A_UINT32 tx_mpdu_cnt; + /** Number of total TX PPDUs on MAC layer in the period */ + A_UINT32 tx_ppdu_cnt; + /** Bytes of tx data on MAC layer in the period */ + A_UINT32 tx_bytes; + /** Number of TX MSDUs cancelled due to any reason in the period, + * such as WMM limitation/bandwidth limitation/radio congestion */ + A_UINT32 tx_msdu_drop_cnt; + /** Bytes of dropped TX packets in the period */ + A_UINT32 tx_drop_bytes; + /** Number of unacked transmissions of MPDUs */ + A_UINT32 tx_mpdu_retry_cnt; + /** Number of MPDUs have not been ACKed despite retried */ + A_UINT32 tx_mpdu_fail_cnt; + /** Number of PPDUs which received no block ack */ + A_UINT32 tx_ppdu_fail_cnt; + /* This TLV is followed by TLVs below: : + * A_UINT32 tx_mpdu_aggr[tx_mpdu_aggr_array_len]; + * A_UINT32 tx_succ_mcs[tx_succ_mcs_array_len]; + * A_UINT32 tx_fail_mcs[tx_fail_mcs_array_len]; + * A_UINT32 tx_ppdu_delay[tx_ppdu_delay_array_len]; + */ +} wmi_tx_stats; + +/** Thresholds of tx stats, stand for percentage of stats variation. + * Check wmi_tx_stats for each stats's meaning. + */ +typedef struct +{ + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_tx_stats_thresh */ + A_UINT32 tx_msdu_cnt; + A_UINT32 tx_mpdu_cnt; + A_UINT32 tx_ppdu_cnt; + A_UINT32 tx_bytes; + A_UINT32 tx_msdu_drop_cnt; + A_UINT32 tx_drop_bytes; + A_UINT32 tx_mpdu_retry_cnt; + A_UINT32 tx_mpdu_fail_cnt; + A_UINT32 tx_ppdu_fail_cnt; + A_UINT32 tx_mpdu_aggr; + A_UINT32 tx_succ_mcs; + A_UINT32 tx_fail_mcs; + A_UINT32 tx_ppdu_delay; +} wmi_tx_stats_thresh; + +typedef struct +{ + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_peer_ac_tx_stats */ + A_UINT32 vdev_id; + A_UINT32 peer_id; + /* The TLVs for the 4 AC follows: + * wmi_tx_stats tx_stats[]; wmi_tx_stats for BE/BK/VI/VO + */ +} wmi_peer_ac_tx_stats; + +typedef struct +{ + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_rx_stats */ + /** Number of RX MPDUs on MAC layer */ + A_UINT32 mac_rx_mpdu_cnt; + /** Bytes of RX packets on MAC layer */ + A_UINT32 mac_rx_bytes; + /** Number of RX PPDU on PHY layer */ + A_UINT32 phy_rx_ppdu_cnt; + /** Bytes of RX packets on PHY layer */ + A_UINT32 phy_rx_bytes; + /** Number of discontinuity in seqnum */ + A_UINT32 rx_disorder_cnt; + /** Number of RX MPDUs flagged as retransmissions */ + A_UINT32 rx_mpdu_retry_cnt; + /** Number of RX MPDUs identified as duplicates */ + A_UINT32 rx_mpdu_dup_cnt; + /** Number of RX MPDUs discarded */ + A_UINT32 rx_mpdu_discard_cnt; + /* This TLV is followed by TLVs below: + * A_UINT32 rx_mpdu_aggr[rx_mpdu_aggr_array_len]; + * A_UINT32 rx_mcs[rx_mcs_array_len]; + */ +} wmi_rx_stats; + +/** Thresholds of rx stats, stands for percentage of stats variation. + * Check wmi_rx_stats for each stats's meaning. + */ +typedef struct +{ + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_rx_stats_thresh */ + A_UINT32 mac_rx_mpdu_cnt; + A_UINT32 mac_rx_bytes; + A_UINT32 phy_rx_ppdu_cnt; + A_UINT32 phy_rx_bytes; + A_UINT32 rx_disorder_cnt; + A_UINT32 rx_mpdu_retry_cnt; + A_UINT32 rx_mpdu_dup_cnt; + A_UINT32 rx_mpdu_discard_cnt; + A_UINT32 rx_mpdu_aggr; + A_UINT32 rx_mcs; + A_UINT32 sta_ps_inds; + A_UINT32 sta_ps_durs; + A_UINT32 rx_probe_reqs; + A_UINT32 rx_oth_mgmts; +} wmi_rx_stats_thresh; + +typedef struct +{ + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_peer_ac_rx_stats */ + A_UINT32 vdev_id; + A_UINT32 peer_id; + /** How many times STAs go to sleep */ + A_UINT32 sta_ps_inds; + /** Total sleep time of STAs, milliseconds units */ + A_UINT32 sta_ps_durs; + /** Number of probe requests received */ + A_UINT32 rx_probe_reqs; + /** Number of other management frames received, not including probe requests */ + A_UINT32 rx_oth_mgmts; + /* The TLVs for the 4 AC follows: + * wmi_rx_stats rx_stats[]; wmi_rx_stats for BE/BK/VI/VO + */ +} wmi_peer_ac_rx_stats; + +typedef enum { + /** Periodic timer timed out, based on the period specified + * by WMI_PDEV_PARAM_STATS_OBSERVATION_PERIOD + */ + TRIGGER_COND_ID_TIMER_TIMED_OUT = 0x1, + /** Any of the (enabled) stats thresholds specified + * in the WMI_PDEV_SET_STATS_THRESHOLD_CMD message is exceeded + * within the current stats period. + */ + TRIGGER_COND_ID_THRESH_EXCEEDED = 0x2, + /** In Response to the one-time wlan stats request of + * WMI_REQUEST_WLAN_STATS_CMDID from host. + */ + TRIGGER_COND_ID_ONE_TIME_REQUEST = 0x3, +} wmi_report_stats_event_trigger_cond_id; + +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_report_stats_event_fixed_param */ + /** Indicate what triggered this event, check wmi_report_stats_event_trigger_cond_id for details */ + A_UINT32 trigger_cond_id; + /** Bitmap to indicate changed channel CCA stats which exceeded the thresholds */ + A_UINT32 cca_chgd_bitmap; + /** Bitmap to indicate changed peer signal stats which exceeded the thresholds */ + A_UINT32 sig_chgd_bitmap; + /** Bitmap to indicate changed TX counters which exceeded the thresholds */ + A_UINT32 tx_chgd_bitmap; + /** Bitmap to indicate changed RX counters which exceeded the thresholds */ + A_UINT32 rx_chgd_bitmap; + /** number of per channel CCA stats structures (wmi_chan_cca_stats), 0 to max vdevs*/ + A_UINT32 num_chan_cca_stats; + /** number of per peer signal stats structures (wmi_peer_signal_stats), 0 to max peers*/ + A_UINT32 num_peer_signal_stats; + /** number of per peer ac TX stats structures (wmi_peer_ac_tx_stats), 0 to max peers*/ + A_UINT32 num_peer_ac_tx_stats; + /** Array length of tx_mpdu_aggr[] which is histogram of MPDU aggregation size(1 to 7 and 8+). + * The array indicates number of MPDUs sent on specified aggregation size + * (per number of MPDUs per AMPDUs / 1 to 7 and 8+). + * Array length can be set per WMI_PDEV_PARAM_TX_MPDU_AGGR_ARRAY_LEN */ + A_UINT32 tx_mpdu_aggr_array_len; + /** Array length of tx_succ_mcs[] which is histogram of encoding rate. + * The array indicates number of acked PPDUs sent at a specific rate */ + A_UINT32 tx_succ_mcs_array_len; + /** Array length of tx_fail_mcs[] which is histogram of encoding rate. + * The array indicates number of unacked PPDUs sent at a specific rate */ + A_UINT32 tx_fail_mcs_array_len; + /** tx_ppdu_delay[]is a histogram of delays on MAC layer. + * The array counts numbers of PPDUs encountering different TX time delays. + * TX delay here means time interval between the time a PPDU is queued + * to the MAC HW for transmission and the time the lower layers of + * tx FW return a tx status. + * + * The bin size tx_ppdu_delay_bin_size_ms specifies how many milliseconds + * each bin of the tx_ppdu_delay histogram represents. + * By default the bin size is 10ms. + * tx_ppdu_delay[0] -> delays between 0-9 ms + * tx_ppdu_delay[1] -> delays between 10-19 ms + * ... + * tx_ppdu_delay[9] -> delays between 90-99 ms + * tx_ppdu_delay[10] -> delays >= 100 ms + * Bin size can be set per WMI_PDEV_PARAM_TX_PPDU_DELAY_BIN_SIZE_MS. + */ + A_UINT32 tx_ppdu_delay_bin_size_ms; + /** Array length of tx_ppdu_delay[]. It can be set per WMI_PDEV_PARAM_TX_PPDU_DELAY_ARRAY_LEN */ + A_UINT32 tx_ppdu_delay_array_len; + /** number of per peer ac RX stats structures (wmi_peer_ac_rx_stats), 0 to max peers*/ + A_UINT32 num_peer_ac_rx_stats; + /** Array length of rx_mpdu_aggr[] which is histogram of MPDU aggregation size(1 to 7 and 8+). + * It can be set per WMI_PDEV_PARAM_RX_MPDU_AGGR_ARRAY_LEN */ + A_UINT32 rx_mpdu_aggr_array_len; + /** Array size of rx_mcs[] which is histogram of encoding rate. + * The array indicates number of PPDUs received at a specific rate */ + A_UINT32 rx_mcs_array_len; + + /** + * This TLV is followed by TLVs below: + * wmi_chan_cca_stats chan_cca_stats[]; Array length is specified by num_chan_cca_stats + * wmi_peer_signal_stats peer_signal_stats[]; Array length is specified by num_peer_signal_stats + * wmi_peer_ac_tx_stats peer_ac_tx_stats[]; Array length is specified by num_peer_ac_tx_stats + * wmi_tx_stats tx_stats[][]; Array length is num_peer_ac_tx_stats * WLAN_MAX_AC, array index is (peer_index * WLAN_MAX_AC + ac_index) + * A_UINT32 tx_mpdu_aggr[][][]; Array length is num_peer_ac_tx_stats * WLAN_MAX_AC * tx_mpdu_aggr_array_len, + * array index is (peer_index * WLAN_MAX_AC + ac_index) * tx_mpdu_aggr_array_len + A-MPDU aggregation index + * A_UINT32 tx_succ_mcs[][][]; Array length is num_peer_ac_tx_stats * WLAN_MAX_AC * tx_succ_mcs_array_len, + * array index is (peer_index * WLAN_MAX_AC + ac_index) * tx_succ_mcs_array_len + MCS index + * A_UINT32 tx_fail_mcs[][][]; Array length is num_peer_ac_tx_stats * WLAN_MAX_AC * tx_fail_mcs_array_len, + * array index is (peer_index * WLAN_MAX_AC + ac_index) * tx_fail_mcs_array_len + MCS index + * A_UINT32 tx_ppdu_delay[][][]; Array length is num_peer_ac_tx_stats * WLAN_MAX_AC * tx_ppdu_delay_array_len, + * array index is (peer_index * WLAN_MAX_AC + ac_index) * tx_ppdu_delay_array_len + tx delay index + * wmi_peer_ac_rx_stats peer_ac_rx_stats[]; Array length is specified by num_peer_ac_rx_stats + * wmi_rx_stats rx_stats[][]; Array length is num_peer_ac_rx_stats * WLAN_MAX_AC, array index is (peer_index * WLAN_MAX_AC + ac_index) + * A_UINT32 rx_mpdu_aggr[][][]; Array length is num_peer_ac_rx_stats * WLAN_MAX_AC * rx_mpdu_aggr_array_len, + * array index is (peer_index * WLAN_MAX_AC + ac_index) * rx_mpdu_aggr_array_len + A-MPDU aggregation index + * A_UINT32 rx_mcs[][][]; Array length is (num_peer_ac_rx_stats * WLAN_MAX_AC) * rx_mcs_array_len, + * array index is (peer_index * WLAN_MAX_AC + ac_index) * rx_mcs_array_len + MCS index + **/ +} wmi_report_stats_event_fixed_param; + +typedef struct { + /** TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_peer_stats_info */ + A_UINT32 tlv_header; + /** peer MAC address */ + wmi_mac_addr peer_macaddr; + /** bytes (size of MPDUs) transmitted to this peer */ + struct { + /* lower 32 bits of the tx_bytes value */ + A_UINT32 low_32; + /* upper 32 bits of the tx_bytes value */ + A_UINT32 high_32; + } tx_bytes; + /** packets (MSDUs) transmitted to this peer */ + struct { + /* lower 32 bits of the tx_packets value */ + A_UINT32 low_32; + /* upper 32 bits of the tx_packets value */ + A_UINT32 high_32; + } tx_packets; + /** bytes (size of MPDUs) received from this peer */ + struct { + /* lower 32 bits of the rx_bytes value */ + A_UINT32 low_32; + /* upper 32 bits of the rx_bytes value */ + A_UINT32 high_32; + } rx_bytes; + /** packets (MSDUs) received from this peer */ + struct { + /* lower 32 bits of the rx_packets value */ + A_UINT32 low_32; + /* upper 32 bits of the rx_packets value */ + A_UINT32 high_32; + } rx_packets; + /** cumulative retry counts (MPDUs) */ + A_UINT32 tx_retries; + /** number of failed transmissions (MPDUs) (retries exceeded, no ACK) */ + A_UINT32 tx_failed; + /** rate information, it is output of WMI_ASSEMBLE_RATECODE_V1 + * (in format of 0x1000RRRR) + * The rate-code is a 4-bytes field in which, + * for given rate, nss and preamble + * + * b'31-b'29 unused / reserved + * b'28 indicate the version of rate-code (1 = RATECODE_V1) + * b'27-b'11 unused / reserved + * b'10-b'8 indicate the preamble (0 OFDM, 1 CCK, 2 HT, 3 VHT) + * b'7-b'5 indicate the NSS (0 - 1x1, 1 - 2x2, 2 - 3x3, 3 - 4x4) + * b'4-b'0 indicate the rate, which is indicated as follows: + * OFDM : 0: OFDM 48 Mbps + * 1: OFDM 24 Mbps + * 2: OFDM 12 Mbps + * 3: OFDM 6 Mbps + * 4: OFDM 54 Mbps + * 5: OFDM 36 Mbps + * 6: OFDM 18 Mbps + * 7: OFDM 9 Mbps + * CCK (pream == 1) + * 0: CCK 11 Mbps Long + * 1: CCK 5.5 Mbps Long + * 2: CCK 2 Mbps Long + * 3: CCK 1 Mbps Long + * 4: CCK 11 Mbps Short + * 5: CCK 5.5 Mbps Short + * 6: CCK 2 Mbps Short + * HT/VHT (pream == 2/3) + * 0..7: MCS0..MCS7 (HT) + * 0..9: MCS0..MCS9 (11AC VHT) + * 0..11: MCS0..MCS11 (11AX VHT) + */ + /** rate-code of the last transmission */ + A_UINT32 last_tx_rate_code; + /** rate-code of the last received PPDU */ + A_UINT32 last_rx_rate_code; + /** bitrate of the last transmission, in units of kbps */ + A_UINT32 last_tx_bitrate_kbps; + /** bitrate of the last received PPDU, in units of kbps */ + A_UINT32 last_rx_bitrate_kbps; + /** combined RSSI of the last received PPDU, in unit of dBm */ + A_INT32 peer_rssi; +} wmi_peer_stats_info; + +typedef struct { + /** TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_peer_stats_info_event_fixed_param */ + A_UINT32 tlv_header; + /** VDEV to which the peers belong to */ + A_UINT32 vdev_id; + /** number of peers in peer_stats_info[] */ + A_UINT32 num_peers; + /** flag to indicate if there are more peers which will + * be sent a following seperate peer_stats_info event */ + A_UINT32 more_data; + /* This TLV is followed by another TLV of array of structs + * wmi_peer_stats_info peer_stats_info[]; + */ +} wmi_peer_stats_info_event_fixed_param; + +typedef struct { + /** TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_radio_chan_stats */ + A_UINT32 tlv_header; + /** primary channel freq of the channel whose stats is sent */ + A_UINT32 chan_mhz; + /** accumulation of time the radio is tuned to this channel, + * in units of microseconds */ + A_UINT32 on_chan_us; + /** accumulation of the TX PPDU duration over the measurement period, + * in units of microseconds */ + A_UINT32 tx_duration_us; + /** accumulation of the RX PPDU duration over the measurement period, + * in units of microseconds */ + A_UINT32 rx_duration_us; + /** ratio of channel busy time to on_chan_us, in units of percent */ + A_UINT32 chan_busy_ratio; + /** ratio of on_chan_us to the measurement period, in units of percent */ + A_UINT32 on_chan_ratio; + /** measurement period, in units of microseconds */ + A_UINT32 measurement_period_us; + /** MPDUs transmitted on this channel */ + A_UINT32 tx_mpdus; + /** MSDUs transmitted on this channel */ + A_UINT32 tx_msdus; + /** MPDUS successfully received on this channel */ + A_UINT32 rx_succ_mpdus; + /** Failed MPDUs (CRC failures) received on this channel */ + A_UINT32 rx_fail_mpdus; +} wmi_radio_chan_stats; + +typedef struct { + /** TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_radio_chan_stats_event_fixed_param */ + A_UINT32 tlv_header; + /** number of channel stats in radio_chan_stats[] */ + A_UINT32 num_chans; + /* This TLV is followed by another TLV of array of structs + * wmi_radio_chan_stats radio_chan_stats[]; + */ +} wmi_radio_chan_stats_event_fixed_param; + +/** + * PDEV statistics + * @todo + * add all PDEV stats here + */ +typedef struct { + /** Channel noise floor */ + A_INT32 chan_nf; + /** TX frame count */ + A_UINT32 tx_frame_count; + /** RX frame count */ + A_UINT32 rx_frame_count; + /** rx clear count */ + A_UINT32 rx_clear_count; + /** cycle count */ + A_UINT32 cycle_count; + /** Phy error count */ + A_UINT32 phy_err_count; + /** Channel Tx Power */ + A_UINT32 chan_tx_pwr; + /** WAL dbg stats */ + struct wlan_dbg_stats pdev_stats; + +} wmi_pdev_stats; + +/** + * VDEV statistics + * @todo + * add all VDEV stats here + */ + +typedef struct { + A_INT32 bcn_snr; + A_INT32 dat_snr; +} wmi_snr_info; + +typedef struct { + /** unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; + wmi_snr_info vdev_snr; + A_UINT32 tx_frm_cnt[WLAN_MAX_AC];/* Total number of packets(per AC) that were successfully transmitted(with and without retries, including multi-cast, broadcast) */ + A_UINT32 rx_frm_cnt;/* Total number of packets that were successfully received (after appropriate filter rules including multi-cast, broadcast)*/ + A_UINT32 multiple_retry_cnt[WLAN_MAX_AC];/*The number of MSDU packets and MMPDU frames per AC + that the 802.11 station successfully transmitted after more than one retransmission attempt*/ + A_UINT32 fail_cnt[WLAN_MAX_AC]; /*Total number packets(per AC) failed to transmit */ + A_UINT32 rts_fail_cnt;/*Total number of RTS/CTS sequence failures for transmission of a packet*/ + A_UINT32 rts_succ_cnt;/*Total number of RTS/CTS sequence success for transmission of a packet*/ + A_UINT32 rx_err_cnt;/*The receive error count. HAL will provide the RxP FCS error global */ + A_UINT32 rx_discard_cnt;/* The sum of the receive error count and dropped-receive-buffer error count. (FCS error)*/ + A_UINT32 ack_fail_cnt;/*Total number packets failed transmit because of no ACK from the remote entity*/ + A_UINT32 tx_rate_history[MAX_TX_RATE_VALUES];/*History of last ten transmit rate, in units of 500 kbit/sec*/ + A_UINT32 bcn_rssi_history[MAX_RSSI_VALUES];/*History of last ten Beacon rssi of the connected Bss*/ +} wmi_vdev_stats; + +/** + * peer statistics. + */ +typedef struct { + /** peer MAC address */ + wmi_mac_addr peer_macaddr; + /** rssi */ + A_UINT32 peer_rssi; + /** last tx data rate used for peer */ + A_UINT32 peer_tx_rate; + /** last rx data rate used for peer */ + A_UINT32 peer_rx_rate; +} wmi_peer_stats; + +/** + * Peer extension statistics + */ +typedef struct { + /** peer MAC address */ + wmi_mac_addr peer_macaddr; + /* rx duration in microseconds*/ + A_UINT32 rx_duration; + /** Total TX bytes (including dot11 header) sent to peer */ + A_UINT32 peer_tx_bytes; + /** Total RX bytes (including dot11 header) received from peer */ + A_UINT32 peer_rx_bytes; + /** last TX ratecode */ + A_UINT32 last_tx_rate_code; + /** TX power used by peer - units are 0.5 dBm */ + A_INT32 last_tx_power; + A_UINT32 reserved[4]; /** for future use - add new peer stats here */ +} wmi_peer_extd_stats; + +typedef struct { + /** Primary channel freq of the channel for which stats are sent */ + A_UINT32 chan_mhz; + /** Time spent on the channel */ + A_UINT32 sampling_period_us; + /** Aggregate duration over a sampling period for which channel activity was observed */ + A_UINT32 rx_clear_count; + /** Accumalation of the TX PPDU duration over a sampling period */ + A_UINT32 tx_duration_us; + /** Accumalation of the RX PPDU duration over a sampling period */ + A_UINT32 rx_duration_us; +} wmi_chan_stats; + +typedef struct { + A_UINT32 tx_mpdu_grp_frag_cnt; /*dot11TransmittedFragmentCount */ + A_UINT32 tx_msdu_grp_frm_cnt; /*dot11GroupTransmittedFrameCount */ + A_UINT32 tx_msdu_fail_cnt; /*dot11FailedCount*/ + A_UINT32 rx_mpdu_frag_cnt; /*dot11ReceivedFragmentCount*/ + A_UINT32 rx_msdu_grp_frm_cnt; /*dot11GroupReceivedFrameCount*/ + A_UINT32 rx_mpdu_fcs_err; /*dot11FCSErrorCount*/ + A_UINT32 tx_msdu_frm_cnt; /*dot11TransmittedFrameCount*/ + A_UINT32 tx_msdu_retry_cnt; /*dot11RetryCount*/ + A_UINT32 rx_frm_dup_cnt; /*dot11FrameDuplicateCount */ + A_UINT32 tx_rts_success_cnt; /*dot11RTSSuccessCount*/ + A_UINT32 tx_rts_fail_cnt; /*dot11RTSFailureCount*/ + A_UINT32 tx_Qos_mpdu_grp_frag_cnt; /*dot11QosTransmittedFragmentCount */ + A_UINT32 tx_Qos_msdu_fail_UP; /*dot11QosFailedCount */ + A_UINT32 tx_Qos_msdu_retry_UP; /*dot11QosRetryCount */ + A_UINT32 rx_Qos_frm_dup_cnt_UP; /*dot11QosFrameDuplicateCount*/ + A_UINT32 tx_Qos_rts_success_cnt_UP; /*dot11QosRTSSuccessCount*/ + A_UINT32 tx_Qos_rts_fail_cnt_UP; /*dot11QosRTSFailureCount*/ + A_UINT32 rx_Qos_mpdu_frag_cnt_UP; /*dot11QosReceivedFragmentCount*/ + A_UINT32 tx_Qos_msdu_frm_cnt_UP; /*dot11QosTransmittedFrameCount*/ + A_UINT32 rx_Qos_msdu_discard_cnt_UP; /*dot11QosDiscardedFrameCount*/ + A_UINT32 rx_Qos_mpdu_cnt; /*dot11QosMPDUsReceivedCount*/ + A_UINT32 rx_Qos_mpdu_retryBit_cnt; /*dot11QosRetriesReceivedCount*/ + A_UINT32 rsna_Mgmt_discard_CCMP_replay_err_cnt; /*dot11RSNAStatsRobustMgmtCCMPReplays*/ + A_UINT32 rsna_TKIP_icv_err_cnt; /*dot11RSNAStatsTKIPICVErrors*/ + A_UINT32 rsna_TKIP_replay_err_cnt; /*dot11RSNAStatsTKIPReplays*/ + A_UINT32 rsna_CCMP_decrypt_err_cnt; /*dot11RSNAStatsCCMPDecryptErrors*/ + A_UINT32 rsna_CCMP_replay_err_cnt; /*dot11RSNAStatsCCMPReplays*/ + A_UINT32 tx_ampdu_cnt; /*dot11TransmittedAMPDUCount*/ + A_UINT32 tx_mpdu_cnt_in_ampdu; /*dot11TransmittedMPDUsInAMPDUCount*/ + union { + A_UINT64 counter; /* for use by target only */ + struct { + A_UINT32 low; + A_UINT32 high; + } upload; /* for use by host */ + } tx_octets_in_ampdu; /*dot11TransmittedOctetsInAMPDUCount*/ + A_UINT32 rx_ampdu_cnt; /*dot11AMPDUReceivedCount*/ + A_UINT32 rx_mpdu_cnt_in_ampdu; /*dot11MPDUInReceivedAMPDUCount*/ + union { + A_UINT64 counter; /* for use by target only */ + struct { + A_UINT32 rx_octets_in_ampdu_low; + A_UINT32 rx_octets_in_ampdu_high; + } upload; /* for use by host */ + } rx_octets_in_ampdu; /*dot11ReceivedOctetsInAMPDUCount*/ + A_UINT32 reserved_1; + A_UINT32 reserved_2; + A_UINT32 reserved_3; + A_UINT32 reserved_4; +} wmi_mib_stats; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_rssi_stats */ + A_UINT32 vdev_id; + A_INT32 rssi_avg_beacon[WMI_MAX_CHAINS]; + A_INT32 rssi_avg_data[WMI_MAX_CHAINS]; + wmi_mac_addr peer_macaddr; +} wmi_rssi_stats; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_congestion_stats */ + A_UINT32 vdev_id; + /* congestion - + * This field holds the congestion percentage = (busy_time/total_time)*100 + * for the interval from when the vdev was started to the current time + * (or the time at which the vdev was stopped). + */ + A_UINT32 congestion; +} wmi_congestion_stats; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_per_chain_rssi_stats */ + A_UINT32 num_per_chain_rssi_stats; +/* This TLV is followed by another TLV of array of structs: + * wmi_rssi_stats rssi_stats[num_per_chain_rssi_stats]; + */ +} wmi_per_chain_rssi_stats; + +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_vdev_create_cmd_fixed_param */ + /** unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; + /** VDEV type (AP,STA,IBSS,MONITOR) */ + A_UINT32 vdev_type; + /** VDEV subtype (P2PDEV, P2PCLI, P2PGO, BT3.0)*/ + A_UINT32 vdev_subtype; + /** VDEV MAC address */ + wmi_mac_addr vdev_macaddr; + /** Number of configured txrx streams */ + A_UINT32 num_cfg_txrx_streams; + /** + * pdev_id for identifying the MAC, + * See macros starting with WMI_PDEV_ID_ for values. + */ + A_UINT32 pdev_id; +/* This TLV is followed by another TLV of array of structures + * wmi_vdev_txrx_streams cfg_txrx_streams[]; + */ +} wmi_vdev_create_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_vdev_txrx_streams */ + /* band - Should take values from wmi_channel_band_mask */ + A_UINT32 band; + /* max supported tx streams per given band for this vdev */ + A_UINT32 supported_tx_streams; + /* max supported rx streams per given band for this vdev */ + A_UINT32 supported_rx_streams; +} wmi_vdev_txrx_streams; + +/* wmi_p2p_noa_descriptor structure can't be modified without breaking the compatibility for WMI_HOST_SWBA_EVENTID */ +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_p2p_noa_descriptor */ + A_UINT32 type_count; /** 255: continuous schedule, 0: reserved */ + A_UINT32 duration; /** Absent period duration in micro seconds */ + A_UINT32 interval; /** Absent period interval in micro seconds */ + A_UINT32 start_time; /** 32 bit tsf time when in starts */ +} wmi_p2p_noa_descriptor; + +/** values for vdev_type */ +#define WMI_VDEV_TYPE_AP 0x1 +#define WMI_VDEV_TYPE_STA 0x2 +#define WMI_VDEV_TYPE_IBSS 0x3 +#define WMI_VDEV_TYPE_MONITOR 0x4 + +/** VDEV type is for social wifi interface.This VDEV is Currently mainly needed +* by FW to execute the NAN specific WMI commands and also implement NAN specific +* operations like Network discovery, service provisioning and service +* subscription ..etc. If FW needs NAN VDEV then Host should issue VDEV create +* WMI command to create this VDEV once during initialization and host is not +* expected to use any VDEV specific WMI commands on this VDEV. +**/ +#define WMI_VDEV_TYPE_NAN 0x5 + +#define WMI_VDEV_TYPE_OCB 0x6 + +/* NAN Data Interface */ +#define WMI_VDEV_TYPE_NDI 0x7 + +/* + * Param values to be sent for WMI_VDEV_PARAM_SGI command + * which are used in 11ax systems + */ +#define WMI_SGI_LEGACY 0x1 /* for HT and VHT */ +#define WMI_SGI_HE_400_NS 0x2 /* for HE 400 nsec */ +#define WMI_SGI_HE_800_NS 0x4 /* for HE 800 nsec */ +#define WMI_SGI_HE_1600_NS 0x8 /* for HE 1600 nsec */ +#define WMI_SGI_HE_3200_NS 0x10 /* for HE 3200 nsec */ + +/** values for vdev_subtype */ +#define WMI_UNIFIED_VDEV_SUBTYPE_P2P_DEVICE 0x1 +#define WMI_UNIFIED_VDEV_SUBTYPE_P2P_CLIENT 0x2 +#define WMI_UNIFIED_VDEV_SUBTYPE_P2P_GO 0x3 +#define WMI_UNIFIED_VDEV_SUBTYPE_PROXY_STA 0x4 +#define WMI_UNIFIED_VDEV_SUBTYPE_MESH 0x5 +/* new subtype for 11S mesh is required as 11S functionality differs + * in many ways from proprietary mesh + * 11S uses 6-addr frame format and supports peering between mesh + * stations and dynamic best path selection between mesh stations. + * While in proprietary mesh, neighboring mesh station MAC is manually + * added to AST table for traffic flow between mesh stations + */ +#define WMI_UNIFIED_VDEV_SUBTYPE_MESH_11S 0x6 + +/** values for vdev_start_request flags */ +/** Indicates that AP VDEV uses hidden ssid. only valid for + * AP/GO */ +#define WMI_UNIFIED_VDEV_START_HIDDEN_SSID (1<<0) +/** Indicates if robust management frame/management frame + * protection is enabled. For GO/AP vdevs, it indicates that + * it may support station/client associations with RMF enabled. + * For STA/client vdevs, it indicates that sta will + * associate with AP with RMF enabled. */ +#define WMI_UNIFIED_VDEV_START_PMF_ENABLED (1<<1) +/* + * Host is sending bcn_tx_rate to override the beacon tx rates. + */ +#define WMI_UNIFIED_VDEV_START_BCN_TX_RATE_PRESENT (1<<2) +/** Indicates if LDPC RX will be advertized inside HT/VHT Capabilities IE + * of assoc request/response + */ +#define WMI_UNIFIED_VDEV_START_LDPC_RX_ENABLED (1<<3) + +/* BSS color 0-6 */ +#define WMI_HEOPS_COLOR_GET(he_ops) WMI_GET_BITS(he_ops, 0, 6) +#define WMI_HEOPS_COLOR_SET(he_ops, value) WMI_SET_BITS(he_ops, 0, 6, value) + +/* Default PE Duration subfield indicates the PE duration in units of 4 us */ +#define WMI_HEOPS_DEFPE_GET(he_ops) WMI_GET_BITS(he_ops, 6, 3) +#define WMI_HEOPS_DEFPE_SET(he_ops, value) WMI_SET_BITS(he_ops, 6, 3, value) + +/* TWT required */ +#define WMI_HEOPS_TWT_GET(he_ops) WMI_GET_BITS(he_ops, 9, 1) +#define WMI_HEOPS_TWT_SET(he_ops, value) WMI_SET_BITS(he_ops, 9, 1, value) + +/* RTS threshold in units of 32 us,0 - always use RTS 1023 - this is disabled */ +#define WMI_HEOPS_RTSTHLD_GET(he_ops) WMI_GET_BITS(he_ops, 10, 10) +#define WMI_HEOPS_RTSTHLD_SET(he_ops, value) WMI_SET_BITS(he_ops, 10, 10, value) + +/* Partial BSS Color field indicates whether BSS applies an AID assignment rule using partial BSS color bits */ +#define WMI_HEOPS_PARTBSSCOLOR_GET(he_ops) WMI_GET_BITS(he_ops, 20, 1) +#define WMI_HEOPS_PARTBSSCOLOR_SET(he_ops, value) WMI_SET_BITS(he_ops, 20, 1, value) + +/* MAX BSS supported by MultiBSS element */ +#define WMI_HEOPS_MAXBSSID_GET(he_ops) WMI_GET_BITS(he_ops, 21, 8) +#define WMI_HEOPS_MAXBSSID_SET(he_ops, value) WMI_SET_BITS(he_ops, 21, 8, value) + +/* Tx BSSID Indicator indicates whether HE AP corresponds to transmitted BSSID */ +#define WMI_HEOPS_TXBSSID_GET(he_ops) WMI_GET_BITS(he_ops, 29, 1) +#define WMI_HEOPS_TXBSSID_SET(he_ops, value) WMI_SET_BITS(he_ops, 29, 1, value) + +/* when set to 1 disables use of BSS color */ +#define WMI_HEOPS_BSSCOLORDISABLE_GET(he_ops) WMI_GET_BITS(he_ops, 30, 1) +#define WMI_HEOPS_BSSCOLORDISABLE_SET(he_ops, value) WMI_SET_BITS(he_ops, 30, 1, value) + +/* When set to 1 HE AP transmits beacons using two PHY formats, + * one in non-HE format and other in an HE_EXT_SU PHY format + */ +#define WMI_HEOPS_DUALBEACON_GET(he_ops) WMI_GET_BITS(he_ops, 30, 1) +#define WMI_HEOPS_DUALBEACON_SET(he_ops, value) WMI_SET_BITS(he_ops, 30, 1, value) + +#define WMI_MAX_HECAP_PHY_SIZE (3) + + + + + + + +/* Dual Band both 2.4 GHz and 5 GHz Supported */ +#define WMI_HECAP_PHY_DB_GET(he_cap_phy) WMI_GET_BITS(he_cap_phy[0], 0, 1) +#define WMI_HECAP_PHY_DB_SET(he_cap_phy, value) WMI_SET_BITS(he_cap_phy[0], 0, 1, value) + +/* + * B0: Indicates STA support 40 MHz channel width in 2.4 GHz + * B1: Indicates STA support 40 MHz and 80 MHz channel width in 5 GHz + * B2: Indicates STA supports 160 MHz channel width in 5 GHz + * B3: Indicates STA supports 160/80+80 MHz channel width in 5 GHz + * B4: If B1 is set to 0, then B5 indicates support of 242/106/52/26-tone + * RU mapping in 40 MHz channel width in 2.4 GHz. Otherwise Reserved. + * B5: If B2, B3, and B4 are set to 0, then B6 indicates support of + * 242-tone RU mapping in 40 MHz and 80 + * MHz channel width in 5 GHz. Otherwise Reserved. + * B6: Reserved + */ +#define WMI_HECAP_PHY_CBW_GET(he_cap_phy) WMI_GET_BITS(he_cap_phy[0], 1, 7) +#define WMI_HECAP_PHY_CBW_SET(he_cap_phy, value) WMI_SET_BITS(he_cap_phy[0], 1, 7, value) + +/* + * B0: Indicates STA supports reception of preamble puncturing in 80 MHz, + * where in the preamble only the secondary 20 MHz is punctured + * B1: Indicates STA supports reception of preamble puncturing in 80 MHz, + * where in the preamble only one of the two 20 MHz sub-channels in the + * secondary 40 MHz is punctured + * B2: Indicates STA supports reception of preamble puncturing in 160 MHz + * or 80+80 MHz, where in the primary 80 MHz of the preamble only the + * secondary 20 MHz is punctured + * B3: Indicates STA supports reception of preamble puncturing in 160 MHz + * or 80+80 MHz, where in the primary 80 MHz of the preamble, the + * primary 40 MHz is present + */ +#define WMI_HECAP_PHY_PREAMBLEPUNCRX_GET(he_cap_phy) WMI_GET_BITS(he_cap_phy[0], 8, 4) +#define WMI_HECAP_PHY_PREAMBLEPUNCRX_SET(he_cap_phy, value) WMI_SET_BITS(he_cap_phy[0], 8, 4, value) + +/* Indicates transmitting STA is a Class A (1) or a Class B (0) device */ +#define WMI_HECAP_PHY_COD_GET(he_cap_phy) WMI_GET_BITS(he_cap_phy[0], 12, 1) +#define WMI_HECAP_PHY_COD_SET(he_cap_phy, value) WMI_SET_BITS(he_cap_phy[0], 12, 1, value) + +/* Indicates support of transmission and reception of LDPC encoded packets */ +#define WMI_HECAP_PHY_LDPC_GET(he_cap_phy) WMI_GET_BITS(he_cap_phy[0], 13, 1) +#define WMI_HECAP_PHY_LDPC_SET(he_cap_phy, value) WMI_SET_BITS(he_cap_phy[0], 13, 1, value) + +/* Below 2 macros are for maintaining backward compatability - Deprecated use WMI_HECAP_PHY_LDPC instead */ +#define WMI_HECAP_PHY_TXLDPC_GET(he_cap_phy) WMI_HECAP_PHY_LDPC_GET(he_cap_phy) +#define WMI_HECAP_PHY_TXLDPC_SET(he_cap_phy, value) WMI_HECAP_PHY_LDPC_SET(he_cap_phy, value) +/* Below 2 macros are for maintaining backward compatability - Deprecated use WMI_HECAP_PHY_LDPC instead */ +#define WMI_HECAP_PHY_RXLDPC_GET(he_cap_phy) WMI_HECAP_PHY_LDPC_GET(he_cap_phy) +#define WMI_HECAP_PHY_RXLDPC_SET(he_cap_phy, value) WMI_HECAP_PHY_LDPC_SET(he_cap_phy, value) + +/* + * B0: Indicates support of reception of 1x LTF and 0.8us guard interval duration for HE SU PPDUs. + */ +#define WMI_HECAP_PHY_LTFGIFORHE_GET(he_cap_phy) WMI_GET_BITS(he_cap_phy[0], 14, 1) +#define WMI_HECAP_PHY_LTFGIFORHE_SET(he_cap_phy, value) WMI_SET_BITS(he_cap_phy[0], 14, 1, value) + +/* + * bit 15: reserved + * bit 16: reserved + */ + +/* + * B0: For a transmitting STA acting as beamformee, it indicates support of + * NDP reception using 4x LTF and 3.2 us guard interval duration + */ +#define WMI_HECAP_PHY_LTFGIFORNDP_GET(he_cap_phy) WMI_GET_BITS(he_cap_phy[0], 17, 1) +#define WMI_HECAP_PHY_LTFGIFORNDP_SET(he_cap_phy, value) WMI_SET_BITS(he_cap_phy[0], 17, 1, value) + +/* indicates support for the transmission of HE PPDUs using STBC with one spatial stream for <= 80MHz Tx*/ +#define WMI_HECAP_PHY_TXSTBC_GET(he_cap_phy) WMI_GET_BITS(he_cap_phy[0], 18, 1) +#define WMI_HECAP_PHY_TXSTBC_SET(he_cap_phy, value) WMI_SET_BITS(he_cap_phy[0], 18, 1, value) + +/* indicates support for the reception of HE PPDUs using STBC with one spatial stream for <= 80MHz Tx*/ +#define WMI_HECAP_PHY_RXSTBC_GET(he_cap_phy) WMI_GET_BITS(he_cap_phy[0], 19, 1) +#define WMI_HECAP_PHY_RXSTBC_SET(he_cap_phy, value) WMI_SET_BITS(he_cap_phy[0], 19, 1, value) + +/* indicates transmitting STA supports transmitting HE PPDUs with Doppler procedure */ +#define WMI_HECAP_PHY_TXDOPPLER_GET(he_cap_phy) WMI_GET_BITS(he_cap_phy[0], 20, 1) +#define WMI_HECAP_PHY_TXDOPPLER_SET(he_cap_phy, value) WMI_SET_BITS(he_cap_phy[0], 20, 1, value) + +/* indicates transmitting STA supports receiving HE PPDUs with Doppler procedure */ +#define WMI_HECAP_PHY_RXDOPPLER_GET(he_cap_phy) WMI_GET_BITS(he_cap_phy[0], 21, 1) +#define WMI_HECAP_PHY_RXDOPPLER_SET(he_cap_phy, value) WMI_SET_BITS(he_cap_phy[0], 21, 1, value) + +/* + * If the transmitting STA is an AP: + * indicates STA supports of reception of full bandwidth UL MU-MIMO + * transmission. + * If the transmitting STA is a non-AP STA: + * indicates STA supports of transmission of full bandwidth UL MU-MIMO + * transmission. + */ +#define WMI_HECAP_PHY_UL_MU_MIMO_GET(he_cap_phy) WMI_GET_BITS(he_cap_phy[0], 22, 1) +#define WMI_HECAP_PHY_UL_MU_MIMO_SET(he_cap_phy, value) WMI_SET_BITS(he_cap_phy[0], 22, 1, value) + +/* + * If the transmitting STA is an AP: + * indicates STA supports of reception of UL MUMIMO transmission on an + * RU in an HE MU PPDU where the RU does not span the entire PPDU bandwidth. + * If the transmitting STA is a non-AP STA: + * indicates STA supports of transmission of UL MU-MIMO transmission on an + * RU in an HE MU PPDU where the RU does not span the entire PPDU bandwidth. + */ +#define WMI_HECAP_PHY_ULMUMIMOOFDMA_GET(he_cap_phy) WMI_GET_BITS(he_cap_phy[0], 23, 1) +#define WMI_HECAP_PHY_ULMUMIMOOFDMA_SET(he_cap_phy, value) WMI_SET_BITS(he_cap_phy[0], 23, 1, value) + +/* Tx DCM + * B0:B1 + * 00: Does not support DCM + * 01: BPSK + * 10: QPSK + * 11: 16-QAM + * B2 signals maximum number of spatial streams with DCM + * 0: 1 spatial stream + * 1: 2 spatial streams + */ +#define WMI_HECAP_PHY_DCMTX_GET(he_cap_phy) WMI_GET_BITS(he_cap_phy[0], 24, 3) +#define WMI_HECAP_PHY_DCMTX_SET(he_cap_phy, value) WMI_SET_BITS(he_cap_phy[0], 24, 3, value) + +/* Rx DCM + * B0:B1 + * 00: Does not support DCM + * 01: BPSK + * 10: QPSK + * 11: 16-QAM + * B2 signals maximum number of spatial streams with DCM + * 0: 1 spatial stream + * 1: 2 spatial streams + */ +#define WMI_HECAP_PHY_DCMRX_GET(he_cap_phy) WMI_GET_BITS(he_cap_phy[0], 27, 3) +#define WMI_HECAP_PHY_DCMRX_SET(he_cap_phy, value) WMI_SET_BITS(he_cap_phy[0], 27, 3, value) + + +/* + * Indicates that the STA supports the reception of an HE MU PPDU payload + * over full bandwidth and partial bandwidth (106-tone RU within 20 MHz). + */ +#define WMI_HECAP_PHY_ULHEMU_GET(he_cap_phy) WMI_GET_BITS(he_cap_phy[0], 30, 1) +#define WMI_HECAP_PHY_ULHEMU_SET(he_cap_phy, value) WMI_SET_BITS(he_cap_phy[0], 30, 1, value) + +/* Indicates support for operation as an SU beamformer */ +#define WMI_HECAP_PHY_SUBFMR_GET(he_cap_phy) WMI_GET_BITS(he_cap_phy[0], 31, 1) +#define WMI_HECAP_PHY_SUBFMR_SET(he_cap_phy, value) WMI_SET_BITS(he_cap_phy[0], 31, 1, value) + +/* Indicates support for operation as an SU beamformee */ +#define WMI_HECAP_PHY_SUBFME_GET(he_cap_phy) WMI_GET_BITS(he_cap_phy[1], 0, 1) +#define WMI_HECAP_PHY_SUBFME_SET(he_cap_phy, value) WMI_SET_BITS(he_cap_phy[1], 0, 1, value) + +/* Indicates support for operation as an MU Beamformer */ +#define WMI_HECAP_PHY_MUBFMR_GET(he_cap_phy) WMI_GET_BITS(he_cap_phy[1], 1, 1) +#define WMI_HECAP_PHY_MUBFMR_SET(he_cap_phy, value) WMI_SET_BITS(he_cap_phy[1], 1, 1, value) + +/* + * Num STS -1 for <= 80MHz (min val 3) + * The maximum number of space-time streams minus 1 that the STA can + * receive in an HE NDP + */ +#define WMI_HECAP_PHY_BFMESTSLT80MHZ_GET(he_cap_phy) WMI_GET_BITS(he_cap_phy[1], 2, 3) +#define WMI_HECAP_PHY_BFMESTSLT80MHZ_SET(he_cap_phy, value) WMI_SET_BITS(he_cap_phy[1], 2, 3, value) + + +/* + * Num STS -1 for > 80MHz (min val 3) + * The maximum number of space-time streams minus 1 that the STA can + * receive in an HE NDP + */ +#define WMI_HECAP_PHY_BFMESTSGT80MHZ_GET(he_cap_phy) WMI_GET_BITS(he_cap_phy[1], 5, 3) +#define WMI_HECAP_PHY_BFMESTSGT80MHZ_SET(he_cap_phy, value) WMI_SET_BITS(he_cap_phy[1], 5, 3, value) + +/* + * Number Of Sounding Dimensions For <= 80 MHz + * If SU beamformer capable, set to the maximum supported value of the + * TXVECTOR parameter NUM_STS minus 1. + * Otherwise, reserved. + */ +#define WMI_HECAP_PHY_NUMSOUNDLT80MHZ_GET(he_cap_phy) WMI_GET_BITS(he_cap_phy[1], 8, 3) +#define WMI_HECAP_PHY_NUMSOUNDLT80MHZ_SET(he_cap_phy, value) WMI_SET_BITS(he_cap_phy[1], 8, 3, value) + +/* + * Number Of Sounding Dimensions For > 80 MHz + * If SU beamformer capable, set to the maximum supported value of the + * TXVECTOR parameter NUM_STS minus 1. + * Otherwise, reserved. + */ +#define WMI_HECAP_PHY_NUMSOUNDGT80MHZ_GET(he_cap_phy) WMI_GET_BITS(he_cap_phy[1], 11, 3) +#define WMI_HECAP_PHY_NUMSOUNDGT80MHZ_SET(he_cap_phy, value) WMI_SET_BITS(he_cap_phy[1], 11, 3, value) + +/* + * Indicates if the HE beamformee is capable of feedback with tone + * grouping of 16 in the HE Compressed Beamforming Report field for + * a SU-type feedback. + */ +#define WMI_HECAP_PHY_NG16SUFEEDBACKLT80_GET(he_cap_phy) WMI_GET_BITS(he_cap_phy[1], 14, 1) +#define WMI_HECAP_PHY_NG16SUFEEDBACKLT80_SET(he_cap_phy, value) WMI_SET_BITS(he_cap_phy[1], 14, 1, value) + +/* + * Indicates if the HE beamformee is capable of feedback with tone + * grouping of 16 in the HE Compressed Beamforming Report field for + * a MU-type feedback. + */ +#define WMI_HECAP_PHY_NG16MUFEEDBACKGT80_GET(he_cap_phy) WMI_GET_BITS(he_cap_phy[1], 15, 1) +#define WMI_HECAP_PHY_NG16MUFEEDBACKGT80_SET(he_cap_phy, value) WMI_SET_BITS(he_cap_phy[1], 15, 1, value) + +/* + * Indicates if HE beamformee is capable of feedback with codebook + * size {4, 2} in the HECompressed Beamforming Report field for + * a SU-type feedback. + */ +#define WMI_HECAP_PHY_CODBK42SU_GET(he_cap_phy) WMI_GET_BITS(he_cap_phy[1], 16, 1) +#define WMI_HECAP_PHY_CODBK42SU_SET(he_cap_phy, value) WMI_SET_BITS(he_cap_phy[1], 16, 1, value) + +/* + * Indicates if HE beamformee is capable of feedback with codebook + * size {7, 5} in the HE Compressed Beamforming Report field for + * a MU-type feedback. + */ +#define WMI_HECAP_PHY_CODBK75MU_GET(he_cap_phy) WMI_GET_BITS(he_cap_phy[1], 17, 1) +#define WMI_HECAP_PHY_CODBK75MU_SET(he_cap_phy, value) WMI_SET_BITS(he_cap_phy[1], 17, 1, value) + +/* + * Beamforming Feedback With Trigger Frame + * If the transmitting STA is an AP STA: + * B0: indicates support of reception of SU-Type partial(1) and full bandwidth feedback(0) + * B1: indicates support of reception of MU-Type partial(1) bandwidth feedback + * B2: indicates support of reception of CQI-Only partial and full bandwidth feedback + * If the transmitting STA is a non-AP STA: + * B0: indicates support of transmission of SU-Type partial(1) and full bandwidth(0) feedback + * B1: indicates support of transmission of MU-Type partial(1) bandwidth feedback + * B2: indicates support of transmission of CQI-Onlypartial (1)and full bandwidth feedback + */ +#define WMI_HECAP_PHY_BFFEEDBACKTRIG_GET(he_cap_phy) WMI_GET_BITS(he_cap_phy[1], 18, 3) +#define WMI_HECAP_PHY_BFFEEDBACKTRIG_SET(he_cap_phy, value) WMI_SET_BITS(he_cap_phy[1], 18, 3, value) + +/* Indicates the support of transmission and reception of an HE extended range SU PPDU payload transmitted + * over the right 106-tone RU or partial BW ER + */ +#define WMI_HECAP_PHY_HEERSU_GET(he_cap_phy) WMI_GET_BITS(he_cap_phy[1], 21, 1) +#define WMI_HECAP_PHY_HEERSU_SET(he_cap_phy, value) WMI_SET_BITS(he_cap_phy[1], 21, 1, value) + +/* Indicates that the non-AP STA supports reception of a DL MU-MIMO transmission on an RU in an HE MU PPDU + * where the RU does not span the entire PPDU bandwidth. + */ +#define WMI_HECAP_PHY_DLMUMIMOPARTIALBW_GET(he_cap_phy) WMI_GET_BITS(he_cap_phy[1], 22, 1) +#define WMI_HECAP_PHY_DLMUMIMOPARTIALBW_SET(he_cap_phy, value) WMI_SET_BITS(he_cap_phy[1], 22, 1, value) + +/* Indicates whether or not the PPE Threshold field is present */ +#define WMI_HECAP_PHY_PETHRESPRESENT_GET(he_cap_phy) WMI_GET_BITS(he_cap_phy[1], 23, 1) +#define WMI_HECAP_PHY_PETHRESPRESENT_SET(he_cap_phy, value) WMI_SET_BITS(he_cap_phy[1], 23, 1, value) + +/* Indicates that the STA supports SRP-based SR operation */ +#define WMI_HECAP_PHY_SRPSPRESENT_GET(he_cap_phy) WMI_GET_BITS(he_cap_phy[1], 24, 1) +#define WMI_HECAP_PHY_SRPPRESENT_SET(he_cap_phy, value) WMI_SET_BITS(he_cap_phy[1], 24, 1, value) + +/* Indicates that the STA supports a power boost factor ar for the r-th RU in the range [0.5, 2] */ +#define WMI_HECAP_PHY_PWRBOOSTAR_GET(he_cap_phy) WMI_GET_BITS(he_cap_phy[1], 25, 1) +#define WMI_HECAP_PHY_PWRBOOSTAR_SET(he_cap_phy, value) WMI_SET_BITS(he_cap_phy[1], 25, 1, value) + +/* Indicates support for the reception of 4x LTF and 0.8us guard interval duration for HE SU PPDUs. */ +#define WMI_HECAP_PHY_4XLTFAND800NSECSGI_GET(he_cap_phy) WMI_GET_BITS(he_cap_phy[1], 26, 1) +#define WMI_HECAP_PHY_4XLTFAND800NSECSGI_SET(he_cap_phy, value) WMI_SET_BITS(he_cap_phy[1], 26, 1, value) + +/* For a transmitting STA acting as a beamformee, it indicates the maximum Nc for beamforming sounding + * feedback supported If SU beamformee capable, then set to the maximum Nc for beamforming sounding feedback + * minus 1. Otherwise, reserved. + */ +#define WMI_HECAP_PHY_MAXNC_GET(he_cap_phy) WMI_GET_BITS(he_cap_phy[1], 27, 3) +#define WMI_HECAP_PHY_MAXNC_SET(he_cap_phy, value) WMI_SET_BITS(he_cap_phy[1], 27, 3, value) + +/* Indicates support for the transmission of an HE PPDU that has a bandwidth greater than 80 MHz and is using + * STBC with one spatial stream + */ +#define WMI_HECAP_PHY_STBCTXGT80_GET(he_cap_phy) WMI_GET_BITS(he_cap_phy[1], 30, 1) +#define WMI_HECAP_PHY_STBCTXGT80_SET(he_cap_phy, value) WMI_SET_BITS(he_cap_phy[1], 30, 1, value) + +/* Indicates support for the reception of an HE PPDU that has a bandwidth greater than 80 MHz and is using + * STBC with one spatial stream + */ +#define WMI_HECAP_PHY_STBCRXGT80_GET(he_cap_phy) WMI_GET_BITS(he_cap_phy[1], 31, 1) +#define WMI_HECAP_PHY_STBCRXGT80_SET(he_cap_phy, value) WMI_SET_BITS(he_cap_phy[1], 31, 1, value) + +/* Indicates support for the reception of an HE ER SU PPDU with 4x LTF and 0.8 us guard interval duration */ +#define WMI_HECAP_PHY_ERSU4X800NSECGI_GET(he_cap_phy) WMI_GET_BITS(he_cap_phy[2], 0, 1) +#define WMI_HECAP_PHY_ERSU4X800NSECGI_SET(he_cap_phy, value) WMI_SET_BITS(he_cap_phy[2], 0, 1, value) + + + +/*HTC + HE Support Set to 1 if STA supports reception of HE Variant HT control Field*/ +#define WMI_HECAP_MAC_HECTRL_GET(he_cap) WMI_GET_BITS(he_cap, 0, 1) +#define WMI_HECAP_MAC_HECTRL_SET(he_cap, value) WMI_SET_BITS(he_cap, 0, 1, value) + +/* set to 1 to for TWT Requestor support*/ +#define WMI_HECAP_MAC_TWTREQ_GET(he_cap) WMI_GET_BITS(he_cap, 1, 1) +#define WMI_HECAP_MAC_TWTREQ_SET(he_cap, value) WMI_SET_BITS(he_cap, 1, 1, value) + +/* set to 1 to for TWT Responder support*/ +#define WMI_HECAP_MAC_TWTRSP_GET(he_cap) WMI_GET_BITS(he_cap, 2, 1) +#define WMI_HECAP_MAC_TWTRSP_SET(he_cap, value) WMI_SET_BITS(he_cap, 2, 1, value) + +/* Level of frag support + Set to 0 for no support for dynamic fragmentation. + Set to 1 for support for dynamic fragments that are contained within a S-MPDU + Set to 2 for support for dynamic fragments that are contained within a Single MPDU and support for up to + one dynamic fragment for each MSDU and each MMPDU within an A-MPDU or multi-TID A-MPDU. + Set to 3 for support for dynamic fragments that are contained within a Single MPDU and support for multiple + dynamic fragments for each MSDU within an AMPDU or multi-TID AMPDU and up to one dynamic fragment + for each MMPDU in a multi-TID A-MPDU that is not a Single MPDU +*/ +#define WMI_HECAP_MAC_HEFRAG_GET(he_cap) WMI_GET_BITS(he_cap, 3, 2) +#define WMI_HECAP_MAC_HEFRAG_SET(he_cap, value) WMI_SET_BITS(he_cap, 3, 2, value) + +/* The maximum number of fragmented MSDUs, Nmax,defined by this field is Nmax = 2 Maximum Number Of FMPDUs*/ +#define WMI_HECAP_MAC_MAXFRAGMSDU_GET(he_cap) WMI_GET_BITS(he_cap, 5, 3) +#define WMI_HECAP_MAC_MAXFRAGMSDU_SET(he_cap, value) WMI_SET_BITS(he_cap, 5, 3, value) + +/* 0 = no restriction on the minimum payload , 1 = 128 octets min, 2 = 256 octets min, 3 = 512 octets min */ +#define WMI_HECAP_MAC_MINFRAGSZ_GET(he_cap) WMI_GET_BITS(he_cap, 8, 2) +#define WMI_HECAP_MAC_MINFRAGSZ_SET(he_cap, value) WMI_SET_BITS(he_cap, 8, 2, value) + +/*0 = no additional processing time, 1 = 8us,2 = 16us */ +#define WMI_HECAP_MAC_TRIGPADDUR_GET(he_cap) WMI_GET_BITS(he_cap, 10, 2) +#define WMI_HECAP_MAC_TRIGPADDUR_SET(he_cap, value) WMI_SET_BITS(he_cap, 10, 2, value) + +/*number of TIDs minus 1 of QoS Data frames that HE STA can aggregate in multi-TID AMPDU*/ +#define WMI_HECAP_MAC_MTID_GET(he_cap) WMI_GET_BITS(he_cap, 12, 3) +#define WMI_HECAP_MAC_MTID_SET(he_cap, value) WMI_SET_BITS(he_cap, 12, 3, value) + +/*0=No Feedback,2=Unsolicited,3=Both*/ +#define WMI_HECAP_MAC_HELKAD_GET(he_cap) WMI_GET_BITS(he_cap, 15, 2) +#define WMI_HECAP_MAC_HELKAD_SET(he_cap, value) WMI_SET_BITS(he_cap, 15, 2, value) + +/*Set to 1 for reception of AllAck support*/ +#define WMI_HECAP_MAC_AACK_GET(he_cap) WMI_GET_BITS(he_cap, 17, 1) +#define WMI_HECAP_MAC_AACK_SET(he_cap, value) WMI_SET_BITS(he_cap, 17, 1, value) + +/*Set to 1 if the STA supports reception of the UL MU Response Scheduling A-Control field*/ +#define WMI_HECAP_MAC_ULMURSP_GET(he_cap) WMI_GET_BITS(he_cap, 18, 1) +#define WMI_HECAP_MAC_ULMURSP_SET(he_cap, value) WMI_SET_BITS(he_cap, 18, 1, value) + +/*Set to 1 if the STA supports the BSR A-Control field functionality.*/ +#define WMI_HECAP_MAC_BSR_GET(he_cap) WMI_GET_BITS(he_cap, 19, 1) +#define WMI_HECAP_MAC_BSR_SET(he_cap, value) WMI_SET_BITS(he_cap, 19, 1, value) + +/*Set to 1 when the STA supports broadcast TWT functionality.*/ +#define WMI_HECAP_MAC_BCSTTWT_GET(he_cap) WMI_GET_BITS(he_cap, 20, 1) +#define WMI_HECAP_MAC_BCSTTWT_SET(he_cap, value) WMI_SET_BITS(he_cap, 20, 1, value) + +/*Set to 1 if STA supports rx of Multi-STA BA that has 32-bit Block Ack Bitmap*/ +#define WMI_HECAP_MAC_32BITBA_GET(he_cap) WMI_GET_BITS(he_cap, 21, 1) +#define WMI_HECAP_MAC_32BITBA_SET(he_cap, value) WMI_SET_BITS(he_cap, 21, 1, value) + +/*Set to 1 if the STA supports MU cascading operation*/ +#define WMI_HECAP_MAC_MUCASCADE_GET(he_cap) WMI_GET_BITS(he_cap, 22, 1) +#define WMI_HECAP_MAC_MUCASCADE_SET(he_cap, value) WMI_SET_BITS(he_cap, 22, 1, value) + +/*Set to 1 when the STA supports reception of this multi-TID A-MPDU format*/ +#define WMI_HECAP_MAC_ACKMTIDAMPDU_GET(he_cap) WMI_GET_BITS(he_cap, 23, 1) +#define WMI_HECAP_MAC_ACKMTIDAMPDU_SET(he_cap, value) WMI_SET_BITS(he_cap, 23, 1, value) + +/*Set to 1 when the STA supports its reception*/ +#define WMI_HECAP_MAC_GROUPMSTABA_GET(he_cap) WMI_GET_BITS(he_cap, 24, 1) +#define WMI_HECAP_MAC_GROUPMSTABA_SET(he_cap, value) WMI_SET_BITS(he_cap, 24, 1, value) + +/*Set to 1 if the STA supports reception of the OMI A-Control field*/ +#define WMI_HECAP_MAC_OMI_GET(he_cap) WMI_GET_BITS(he_cap, 25, 1) +#define WMI_HECAP_MAC_OMI_SET(he_cap, value) WMI_SET_BITS(he_cap, 25, 1, value) + +/*1 if OFDMA Random Access Supported*/ +#define WMI_HECAP_MAC_OFDMARA_GET(he_cap) WMI_GET_BITS(he_cap, 26, 1) +#define WMI_HECAP_MAC_OFDMARA_SET(he_cap, value) WMI_SET_BITS(he_cap, 26, 1, value) + +/* Maximum AMPDU Length Exponent. + * If the HE STA includes a VHT Capabilities element, the Maximum A-MPDU Length Exponent subfield in + * HE Capabilities element combined with the Maximum A-MPDU Length Exponent subfield in VHT + * Capabilities element indicate the maximum length of A-MPDU that the STA can Receive where EOF + * padding is not included in this limit. +*/ +#define WMI_HECAP_MAC_MAXAMPDULEN_EXP_GET(he_cap) WMI_GET_BITS(he_cap, 27, 2) +#define WMI_HECAP_MAC_MAXAMPDULEN_EXP_SET(he_cap, value) WMI_SET_BITS(he_cap, 27, 2, value) + +/*A-MSDU Fragmentation Support*/ +#define WMI_HECAP_MAC_AMSDUFRAG_GET(he_cap) WMI_GET_BITS(he_cap, 29, 1) +#define WMI_HECAP_MAC_AMSDUFRAG_SET(he_cap, value) WMI_SET_BITS(he_cap, 29, 1, value) + +/*Flexible TWT Schedule Support*/ +#define WMI_HECAP_MAC_FLEXTWT_GET(he_cap) WMI_GET_BITS(he_cap, 30, 1) +#define WMI_HECAP_MAC_FLEXTWT_SET(he_cap, value) WMI_SET_BITS(he_cap, 30, 1, value) + +/*Rx Control Frame to MultiBSS*/ +#define WMI_HECAP_MAC_MBSS_GET(he_cap) WMI_GET_BITS(he_cap, 31, 1) +#define WMI_HECAP_MAC_MBSS_SET(he_cap, value) WMI_SET_BITS(he_cap, 31, 1, value) + +/* BSRP A-MPDU Aggregation + * maintaining compatability since we dont support this now so not wasting memory + */ +#define WMI_HECAP_MAC_BSRPAMPDU_GET(he_cap) (0) +#define WMI_HECAP_MAC_BSRPAMPDU_SET(he_cap, value) {;} + +/* Quiet Time Period (QTP) operation + * maintaining compatability since we dont support this now so not wasting memory + */ +#define WMI_HECAP_MAC_QTP_GET(he_cap) (0) +#define WMI_HECAP_MAC_QTP_SET(he_cap, value) {;} + +/* support by an AP for receiving an (A-)MPDU that contains a BQR in the + * A-Control subfield and support by a non-AP STA for generating an (A-)MPDU + * that contains a BQR in the A-Control subfield + * maintaining compatability since we dont support this now so not wasting memory + */ +#define WMI_HECAP_MAC_ABQR_GET(he_cap) (0) +#define WMI_HECAP_MAC_ABQR_SET(he_cap, value) {;} + +/*Indicates support by the STA for the role of SR Responder.*/ +#define WMI_HECAP_MAC_SRRESP_GET(he_cap) (0) +#define WMI_HECAP_MAC_SRRESP_SET(he_cap, value) {;} + +/* Indicates support for an AP to encode OPS information to TIM element of the FILS Discovery + * frames or TIM frames as described in AP operation for opportunistic power save. + * Indicates support for a non-AP STA to receive the opportunistic power save encoded TIM elements + */ +#define WMI_HECAP_MAC_OPS_GET(he_cap) (0) +#define WMI_HECAP_MAC_OPS_SET(he_cap, value) {;} + + +/* Indicates support for a non-AP STA to follow the NDP feedback report procedure and respond to + * the NDP Feedback Report Poll Trigger frame. + */ +#define WMI_HECAP_MAC_NDPFDBKRPT_GET(he_cap) (0) +#define WMI_HECAP_MAC_NDPFDBKRPT_SET(he_cap, value) {;} + +/* BELOW MACROS ARE DEPRECATED Also we are not defining bits for capabilities + * beyond bit 31 we donot support as it adds additional dword to our struct which may be later + * removed by standard + */ +#define WMI_HECAP_MAC_MBAHECTRL_GET(he_cap) (0) /* DO NOT USE - DEPRECATED*/ +#define WMI_HECAP_MAC_MBAHECTRL_SET(he_cap, value) {;} /* DO NOT USE - DEPRECATED*/ + +#define WMI_HECAP_MAC_MURTS_GET(he_cap) (0) /* DO NOT USE - DEPRECATED*/ +#define WMI_HECAP_MAC_MURTS_SET(he_cap, value) {;} /* DO NOT USE - DEPRECATED*/ + +/*Deprecate use WMI_HECAP_PHY_PREAMBLEPUNCRX instead*/ +#define WMI_HECAP_PHY_CBMODE_GET(he_cap_phy) WMI_HECAP_PHY_CBMODE_GET(he_cap_phy) +#define WMI_HECAP_PHY_CBMODE_SET(he_cap_phy, value) WMI_HECAP_PHY_CBMODE_SET(he_cap_phy, value) + + +/* Below 2 macros are for maintaining backward compatability - Deprecated use WMI_HECAP_PHY_LTFGIFORHE_GET instead */ +#define WMI_HECAP_PHY_OLTF_GET(he_cap_phy) WMI_HECAP_PHY_LTFGIFORHE_GET(he_cap_phy) +#define WMI_HECAP_PHY_OLTF_SET(he_cap_phy, value) WMI_HECAP_PHY_LTFGIFORHE_SET(he_cap_phy, value) + + +/*DEPRECATED - USE WMI_HECAP_PHY_BFMENLTSGT80MHZ*/ +#define WMI_HECAP_PHY_SUBFMESTS_GET(he_cap_phy) WMI_HECAP_PHY_BFMESTSLT80MHZ_GET(he_cap_phy) +#define WMI_HECAP_PHY_SUBFMESTS_SET(he_cap_phy, value) WMI_HECAP_PHY_BFMESTSLT80MHZ_SET(he_cap_phy, value) + +/*DEPRECATED - use WMI_HECAP_PHY_PETHRESPRESENT**/ +#define WMI_HECAP_PHY_PADDING_GET(he_cap_phy) WMI_HECAP_PHY_PETHRESPRESENT_GET(he_cap_phy) +#define WMI_HECAP_PHY_PADDING_SET(he_cap_phy, value) WMI_HECAP_PHY_PETHRESPRESENT_SET(he_cap_phy, value) + + +/**DO NOT USE - DEPRECATED*/ +#define WMI_HECAP_PHY_DLOFMAMUMIMO_GET(he_cap_phy) (0) +#define WMI_HECAP_PHY_DLOFDMAMUMIO_SET(he_cap_phy, value) {;} + +/*DO NOT USE - DEPRECATED**/ +#define WMI_HECAP_PHY_32GI_GET(he_cap_phy) (0) +#define WMI_HECAP_PHY_32GI_SET(he_cap_phy, value) {;} + +/*DO NOT USE - DEPRECATED**/ +#define WMI_HECAP_PHY_NOSUNDIMENS_GET(he_cap_phy) (0) +#define WMI_HECAP_PHY_NOSUNDIMENS_SET(he_cap_phy, value) {;} + +/*DO NOT USE - DEPRECATED**/ +#define WMI_HECAP_PHY_40MHZNSS_GET(he_cap_phy)(0) +#define WMI_HECAP_PHY_40MHZNSS_SET(he_cap_phy, value) {;} + + +/* START TEMPORARY WORKAROUND - + * Leave legacy names as aliases for new names, until all references to the + * legacy names have been removed. + */ +#define WMI_HECAP_PHY_ULOFDMA_GET WMI_HECAP_PHY_ULMUMIMOOFDMA_GET +#define WMI_HECAP_PHY_ULOFDMA_SET WMI_HECAP_PHY_ULMUMIMOOFDMA_SET +/* END TEMPORARY WORKAROUND */ + +/* DEPRECATED - use WMI_HECAP_PHY_DCMRX or WMI_HECAP_PHY_DCMTX */ +#define WMI_HECAP_PHY_DCM_GET(he_cap_phy) WMI_HECAP_PHY_DCMRX_GET(he_cap_phy) +#define WMI_HECAP_PHY_DCM_SET(he_cap_phy, value) WMI_HECAP_PHY_DCMRX_SET(he_cap_phy, value) + +/* + * The maximum value for NSTS-1<=80MHz,(min val 3)total that can be sent + * to the STA in a DL MU-MIMO transmission on full or partial bandwidth + */ +#define WMI_HECAP_PHY_NSTSLT80MHZ_GET(he_cap_phy) WMI_GET_BITS(he_cap_phy[1], 5, 3) +#define WMI_HECAP_PHY_NSTSLT80MHZ_SET(he_cap_phy, value) WMI_SET_BITS(he_cap_phy[1], 5, 3, value) + + +/* + * The maximum value for NSTS-1 > 80MHz (min val 3) total that can be sent + * to the STA in a DL MU-MIMO transmission on full or partial bandwidth + */ +#define WMI_HECAP_PHY_NSTSGT80MHZ_GET(he_cap_phy) WMI_GET_BITS(he_cap_phy[1], 8, 3) +#define WMI_HECAP_PHY_NSTSGT80MHZ_SET(he_cap_phy, value) WMI_SET_BITS(he_cap_phy[1], 8, 3, value) + + +#define WMI_GET_HW_RATECODE_PREAM_V1(_rcode) (((_rcode) >> 8) & 0x7) +#define WMI_GET_HW_RATECODE_NSS_V1(_rcode) (((_rcode) >> 5) & 0x7) +#define WMI_GET_HW_RATECODE_RATE_V1(_rcode) (((_rcode) >> 0) & 0x1F) +#define WMI_ASSEMBLE_RATECODE_V1(_rate, _nss, _pream) \ + (((1) << 28) | ((_pream) << 8) | ((_nss) << 5) | (_rate)) + +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_vdev_start_request_cmd_fixed_param */ + /** unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; + /** requestor id identifying the caller module */ + A_UINT32 requestor_id; + /** beacon interval from received beacon */ + A_UINT32 beacon_interval; + /** DTIM Period from the received beacon */ + A_UINT32 dtim_period; + /** Flags */ + A_UINT32 flags; + /** ssid field. Only valid for AP/GO/IBSS/BTAmp VDEV type. */ + wmi_ssid ssid; + /** beacon/probe reponse xmit rate. Applicable for SoftAP. */ + /** This field will be invalid and ignored unless the */ + /** flags field has the WMI_UNIFIED_VDEV_START_BCN_TX_RATE_PRESENT bit. */ + /** When valid, this field contains the fixed tx rate for the beacon */ + /** and probe response frames send by the GO or SoftAP */ + A_UINT32 bcn_tx_rate; + /** beacon/probe reponse xmit power. Applicable for SoftAP. */ + A_UINT32 bcn_txPower; + /** number of p2p NOA descriptor(s) from scan entry */ + A_UINT32 num_noa_descriptors; + /** Disable H/W ack. This used by WMI_VDEV_RESTART_REQUEST_CMDID. + During CAC, Our HW shouldn't ack ditected frames */ + A_UINT32 disable_hw_ack; + /** This field will be invalid unless the Dual Band Simultaneous (DBS) feature is enabled. */ + /** The DBS policy manager indicates the preferred number of transmit streams. */ + A_UINT32 preferred_tx_streams; + /** This field will be invalid unless the Dual Band Simultaneous (DBS) feature is enabled. */ + /** the DBS policy manager indicates the preferred number of receive streams. */ + A_UINT32 preferred_rx_streams; + A_UINT32 he_ops; /* refer to WMI_HEOPS_xxx macros */ + A_UINT32 cac_duration_ms; /* in milliseconds */ + A_UINT32 regdomain; +/* The TLVs follows this structure: + * wmi_channel chan; <-- WMI channel + * wmi_p2p_noa_descriptor noa_descriptors[]; <-- actual p2p NOA descriptor from scan entry + */ +} wmi_vdev_start_request_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_vdev_delete_cmd_fixed_param */ + /** unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; +} wmi_vdev_delete_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_vdev_up_cmdid_fixed_param */ + /** unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; + /** aid (assoc id) received in association response for STA VDEV */ + A_UINT32 vdev_assoc_id; + /** bssid of the BSS the VDEV is joining */ + wmi_mac_addr vdev_bssid; + /** bssid of transmitted AP (mbssid case) */ + wmi_mac_addr trans_bssid; + /** the profile index of the connected non-trans ap (mbssid case). 0 means invalid */ + A_UINT32 profile_idx; + /** the total profile numbers of non-trans aps (mbssid case). 0 means legacy AP */ + A_UINT32 profile_num; +} wmi_vdev_up_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_vdev_stop_cmd_fixed_param */ + /** unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; +} wmi_vdev_stop_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_vdev_down_cmd_fixed_param */ + /** unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; +} wmi_vdev_down_cmd_fixed_param; + +typedef struct { + /** unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; +} wmi_vdev_standby_response_cmd; + +typedef struct { + /** unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; +} wmi_vdev_resume_response_cmd; + +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_vdev_set_param_cmd_fixed_param */ + /** unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; + /** parameter id */ + A_UINT32 param_id; + /** parameter value */ + A_UINT32 param_value; +} wmi_vdev_set_param_cmd_fixed_param; + +typedef struct { + A_UINT32 key_seq_counter_l; + A_UINT32 key_seq_counter_h; +} wmi_key_seq_counter; + +#define WMI_CIPHER_NONE 0x0 /* clear key */ +#define WMI_CIPHER_WEP 0x1 +#define WMI_CIPHER_TKIP 0x2 +#define WMI_CIPHER_AES_OCB 0x3 +#define WMI_CIPHER_AES_CCM 0x4 +#define WMI_CIPHER_WAPI 0x5 +#define WMI_CIPHER_CKIP 0x6 +#define WMI_CIPHER_AES_CMAC 0x7 +#define WMI_CIPHER_ANY 0x8 +#define WMI_CIPHER_AES_GCM 0x9 +#define WMI_CIPHER_AES_GMAC 0xa +#define WMI_CIPHER_WAPI_GCM_SM4 0xb + +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_vdev_install_key_cmd_fixed_param */ + /** unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; + /** MAC address used for installing */ + wmi_mac_addr peer_macaddr; + /** key index */ + A_UINT32 key_ix; + /** key flags */ + A_UINT32 key_flags; + /** key cipher, defined above */ + A_UINT32 key_cipher; + /** key rsc counter */ + wmi_key_seq_counter key_rsc_counter; + /** global key rsc counter */ + wmi_key_seq_counter key_global_rsc_counter; + /** global key tsc counter */ + wmi_key_seq_counter key_tsc_counter; + /** WAPI key rsc counter */ + A_UINT8 wpi_key_rsc_counter[16]; + /** WAPI key tsc counter */ + A_UINT8 wpi_key_tsc_counter[16]; + /** key length */ + A_UINT32 key_len; + /** key tx mic length */ + A_UINT32 key_txmic_len; + /** key rx mic length */ + A_UINT32 key_rxmic_len; +/* + * Following this struct are this TLV. + * A_UINT8 key_data[]; <-- actual key data; contains key followed by tx mic followed by rx mic + */ +} wmi_vdev_install_key_cmd_fixed_param; + +/** Preamble types to be used with VDEV fixed rate configuration */ +typedef enum { + WMI_RATE_PREAMBLE_OFDM, + WMI_RATE_PREAMBLE_CCK, + WMI_RATE_PREAMBLE_HT, + WMI_RATE_PREAMBLE_VHT, + WMI_RATE_PREAMBLE_HE, +} WMI_RATE_PREAMBLE; + +/** Value to disable fixed rate setting */ +#define WMI_FIXED_RATE_NONE (0xff) + +#define WMI_GI_400_NS 1 +#define WMI_GI_800_NS 0 +#define WMI_GI_1600_NS 2 +#define WMI_GI_3200_NS 3 + +/** the definition of different VDEV parameters */ +typedef enum { + /** RTS Threshold */ + WMI_VDEV_PARAM_RTS_THRESHOLD = 0x1, + /** Fragmentation threshold */ + WMI_VDEV_PARAM_FRAGMENTATION_THRESHOLD, + /** beacon interval in TUs */ + WMI_VDEV_PARAM_BEACON_INTERVAL, + /** Listen interval in TUs */ + WMI_VDEV_PARAM_LISTEN_INTERVAL, + /** muticast rate in Mbps */ + WMI_VDEV_PARAM_MULTICAST_RATE, + /** management frame rate in Mbps */ + WMI_VDEV_PARAM_MGMT_TX_RATE, + /** slot time (long vs short) */ + WMI_VDEV_PARAM_SLOT_TIME, + /** preamble (long vs short) */ + WMI_VDEV_PARAM_PREAMBLE, + /** SWBA time (time before tbtt in msec) */ + WMI_VDEV_PARAM_SWBA_TIME, + /** time period for updating VDEV stats */ + WMI_VDEV_STATS_UPDATE_PERIOD, + /** age out time in msec for frames queued for station in power save*/ + WMI_VDEV_PWRSAVE_AGEOUT_TIME, + /** Host SWBA interval (time in msec before tbtt for SWBA event generation) */ + WMI_VDEV_HOST_SWBA_INTERVAL, + /** DTIM period (specified in units of num beacon intervals) */ + WMI_VDEV_PARAM_DTIM_PERIOD, + /** scheduler air time limit for this VDEV. used by off chan scheduler */ + WMI_VDEV_OC_SCHEDULER_AIR_TIME_LIMIT, + /** enable/dsiable WDS for this VDEV */ + WMI_VDEV_PARAM_WDS, + /** ATIM Window */ + WMI_VDEV_PARAM_ATIM_WINDOW, + /** BMISS max */ + WMI_VDEV_PARAM_BMISS_COUNT_MAX, + /** BMISS first time */ + WMI_VDEV_PARAM_BMISS_FIRST_BCNT, + /** BMISS final time */ + WMI_VDEV_PARAM_BMISS_FINAL_BCNT, + /** WMM enables/disabled */ + WMI_VDEV_PARAM_FEATURE_WMM, + /** Channel width */ + WMI_VDEV_PARAM_CHWIDTH, + /** Channel Offset */ + WMI_VDEV_PARAM_CHEXTOFFSET, + /** Disable HT Protection */ + WMI_VDEV_PARAM_DISABLE_HTPROTECTION, + /** Quick STA Kickout */ + WMI_VDEV_PARAM_STA_QUICKKICKOUT, + /** Rate to be used with Management frames */ + WMI_VDEV_PARAM_MGMT_RATE, + /** Protection Mode */ + WMI_VDEV_PARAM_PROTECTION_MODE, + /** Fixed rate setting + * The top nibble is used to select which format to use for encoding + * the rate specification: 0xVXXXXXXX + * If V == 0b0000: format is same as before: 0x000000RR + * If V == 0b0001: format is: 0x1000RRRR. + * This will be output of WMI_ASSEMBLE_RATECODE_V1 + * The host shall use the new V1 format (and set V = 0x1) if the target + * indicates 802.11ax support via the WMI_SERVICE_11AX flag, or if the + * system is configured with Nss > 4 (either at compile time within the + * host driver, or through WMI_SERVICE_READY PHY capabilities provided + * by the target). + */ + WMI_VDEV_PARAM_FIXED_RATE, + /** + * 11AX: GI = + * WMI_GI_400_NS, WMI_GI_800_NS, WMI_GI_1600_NS, or WMI_GI_3200_NS + * 11N: SGI=WMI_GI_400_NS + */ + WMI_VDEV_PARAM_SGI, + /** Enable LDPC */ + WMI_VDEV_PARAM_LDPC, + /** Enable Tx STBC */ + WMI_VDEV_PARAM_TX_STBC, + /** Enable Rx STBC */ + WMI_VDEV_PARAM_RX_STBC, + /** Intra BSS forwarding */ + WMI_VDEV_PARAM_INTRA_BSS_FWD, + /** Setting Default xmit key for Vdev */ + WMI_VDEV_PARAM_DEF_KEYID, + /** NSS width */ + WMI_VDEV_PARAM_NSS, + /** Set the custom rate for the broadcast data frames */ + WMI_VDEV_PARAM_BCAST_DATA_RATE, + /** Set the custom rate (rate-code) for multicast data frames */ + WMI_VDEV_PARAM_MCAST_DATA_RATE, + /** Tx multicast packet indicate Enable/Disable */ + WMI_VDEV_PARAM_MCAST_INDICATE, + /** Tx DHCP packet indicate Enable/Disable */ + WMI_VDEV_PARAM_DHCP_INDICATE, + /** Enable host inspection of Tx unicast packet to unknown destination */ + WMI_VDEV_PARAM_UNKNOWN_DEST_INDICATE, + + /* The minimum amount of time AP begins to consider STA inactive */ + WMI_VDEV_PARAM_AP_KEEPALIVE_MIN_IDLE_INACTIVE_TIME_SECS, + + /* An associated STA is considered inactive when there is no recent TX/RX + * activity and no downlink frames are buffered for it. Once a STA exceeds + * the maximum idle inactive time, the AP will send an 802.11 data-null as + * a keep alive to verify the STA is still associated. If the STA does ACK + * the data-null, or if the data-null is buffered and the STA does not + * retrieve it, the STA will be considered unresponsive (see + * WMI_VDEV_AP_KEEPALIVE_MAX_UNRESPONSIVE_TIME_SECS). */ + WMI_VDEV_PARAM_AP_KEEPALIVE_MAX_IDLE_INACTIVE_TIME_SECS, + + /* An associated STA is considered unresponsive if there is no recent + * TX/RX activity and downlink frames are buffered for it. Once a STA + * exceeds the maximum unresponsive time, the AP will send a + * WMI_STA_KICKOUT event to the host so the STA can be deleted. */ + WMI_VDEV_PARAM_AP_KEEPALIVE_MAX_UNRESPONSIVE_TIME_SECS, + + /* Enable NAWDS : MCAST INSPECT Enable, NAWDS Flag set */ + WMI_VDEV_PARAM_AP_ENABLE_NAWDS, + /** Enable/Disable RTS-CTS */ + WMI_VDEV_PARAM_ENABLE_RTSCTS, + /* Enable TXBFee/er */ + WMI_VDEV_PARAM_TXBF, + + /**Set packet power save */ + WMI_VDEV_PARAM_PACKET_POWERSAVE, + + /**Drops un-encrypted packets if any received in an encryted connection + * otherwise forwards to host + */ + WMI_VDEV_PARAM_DROP_UNENCRY, + + /* + * Set TX encap type. + * + * enum wmi_pkt_type is to be used as the parameter + * specifying the encap type. + */ + WMI_VDEV_PARAM_TX_ENCAP_TYPE, + + /* + * Try to detect stations that woke-up and exited power save but did not + * successfully transmit data-null with PM=0 to AP. When this happens, + * STA and AP power save state are out-of-sync. Use buffered but + * undelivered MSDU to the STA as a hint that the STA is really awake + * and expecting normal ASAP delivery, rather than retrieving BU with + * PS-Poll, U-APSD trigger, etc. + * + * 0 disables out-of-sync detection. Maximum time is 255 seconds. + */ + WMI_VDEV_PARAM_AP_DETECT_OUT_OF_SYNC_SLEEPING_STA_TIME_SECS, + + /* Enable/Disable early rx dynamic adjust feature. + * Early-rx dynamic adjust is a advance power save feature. + * Early-rx is a wakeup duration before exact TBTT,which is deemed necessary to provide a cushion for various + * timing discrepancies in the system. + * In current code branch, the duration is set to a very conservative fix value to make sure the drift impact is minimum. + * The fix early-tx will result in the unnessary power consume, so a dynamic early-rx adjust algorithm can be designed + * properly to minimum the power consume.*/ + WMI_VDEV_PARAM_EARLY_RX_ADJUST_ENABLE, + + /* set target bmiss number per sample cycle if bmiss adjust was chosen. + * In this adjust policy,early-rx is adjusted by comparing the current bmiss rate to target bmiss rate + * which can be set by user through WMI command. + */ + WMI_VDEV_PARAM_EARLY_RX_TGT_BMISS_NUM, + + /* set sample cycle(in the unit of beacon interval) if bmiss adjust was chosen */ + WMI_VDEV_PARAM_EARLY_RX_BMISS_SAMPLE_CYCLE, + + /* set slop_step */ + WMI_VDEV_PARAM_EARLY_RX_SLOP_STEP, + + /* set init slop */ + WMI_VDEV_PARAM_EARLY_RX_INIT_SLOP, + + /* pause adjust enable/disable */ + WMI_VDEV_PARAM_EARLY_RX_ADJUST_PAUSE, + + + /* Set channel pwr limit value of the vdev the minimal value of all + * vdevs operating on this channel will be set as channel tx power + * limit, which is used to configure ratearray + */ + WMI_VDEV_PARAM_TX_PWRLIMIT, + + /* set the count of snr value for calculation in snr monitor */ + WMI_VDEV_PARAM_SNR_NUM_FOR_CAL, + + /** Roaming offload */ + WMI_VDEV_PARAM_ROAM_FW_OFFLOAD, + + /** Enable Leader request RX functionality for RMC */ + WMI_VDEV_PARAM_ENABLE_RMC, + + /* IBSS does not have deauth/disassoc, vdev has to detect peer gone event + * by himself. If the beacon lost time exceed this threshold, the peer is + * thought to be gone. */ + WMI_VDEV_PARAM_IBSS_MAX_BCN_LOST_MS, + + /** max rate in kpbs, transmit rate can't go beyond it */ + WMI_VDEV_PARAM_MAX_RATE, + + /* enable/disable drift sample. 0: disable; 1: clk_drift; 2: ap_drift; 3 both clk and ap drift*/ + WMI_VDEV_PARAM_EARLY_RX_DRIFT_SAMPLE, + + /* set Tx failure count threshold for the vdev */ + WMI_VDEV_PARAM_SET_IBSS_TX_FAIL_CNT_THR, + + /* set ebt resync timeout value, in the unit of TU */ + WMI_VDEV_PARAM_EBT_RESYNC_TIMEOUT, + + /* Enable Aggregation State Trigger Event */ + WMI_VDEV_PARAM_AGGR_TRIG_EVENT_ENABLE, + + /* This parameter indicates whether IBSS station can enter into power save + * mode by sending Null frame (with PM=1). When not allowed, IBSS station has to stay + * awake all the time and should never set PM=1 in its transmitted frames. + * This parameter is meaningful/valid only when WMI_VDEV_PARAM_ATIM_WINDOW_LENGTH + * is non-zero. */ + WMI_VDEV_PARAM_IS_IBSS_POWER_SAVE_ALLOWED, + + /* This parameter indicates if this station can enter into power collapse + * for the remaining beacon interval after the ATIM window. + * This parameter is meaningful/valid only when WMI_VDEV_PARAM_IS_IBSS_POWER_SAVE_ALLOWED + * is set to TRUE. */ + WMI_VDEV_PARAM_IS_POWER_COLLAPSE_ALLOWED, + + /* This parameter indicates whether IBSS station exit power save mode and + * enter power active state (by sending Null frame with PM=0 in the immediate ATIM Window) + * whenever there is a TX/RX activity. */ + WMI_VDEV_PARAM_IS_AWAKE_ON_TXRX_ENABLED, + + /* If Awake on TX/RX activity is enabled, this parameter indicates + * the data inactivity time in number of beacon intervals after which + * IBSS station reenters power save by sending Null frame with PM=1. */ + WMI_VDEV_PARAM_INACTIVITY_CNT, + + /* Inactivity time in msec after which TX Service Period (SP) is + * terminated by sending a Qos Null frame with EOSP. + * If value is 0, TX SP is terminated with the last buffered packet itself + * instead of waiting for the inactivity timeout. */ + WMI_VDEV_PARAM_TXSP_END_INACTIVITY_TIME_MS, + + /** DTIM policy */ + WMI_VDEV_PARAM_DTIM_POLICY, + + /* When IBSS network is initialized, PS-supporting device + * does not enter protocol sleep state during first + * WMI_VDEV_PARAM_IBSS_PS_WARMUP_TIME_SECS seconds. */ + WMI_VDEV_PARAM_IBSS_PS_WARMUP_TIME_SECS, + + /* Enable/Disable 1 RX chain usage during the ATIM window */ + WMI_VDEV_PARAM_IBSS_PS_1RX_CHAIN_IN_ATIM_WINDOW_ENABLE, + + /* RX Leak window is the time driver waits before shutting down + * the radio or switching the channel and after receiving an ACK + * for a data frame with PM bit set) */ + WMI_VDEV_PARAM_RX_LEAK_WINDOW, + + /** Averaging factor(16 bit value) is used in the calculations to + * perform averaging of different link level statistics like average + * beacon spread or average number of frames leaked */ + WMI_VDEV_PARAM_STATS_AVG_FACTOR, + + /** disconnect threshold, once the consecutive error for specific peer + * exceed this threhold, FW will send kickout event to host */ + WMI_VDEV_PARAM_DISCONNECT_TH, + + /** The rate_code of RTS_CTS changed by host. Now FW can support + * more non-HT rates rather than 1Mbps or 6Mbps */ + WMI_VDEV_PARAM_RTSCTS_RATE, + + /** This parameter indicates whether using a long duration RTS-CTS + * protection when a SAP goes off channel in MCC mode */ + WMI_VDEV_PARAM_MCC_RTSCTS_PROTECTION_ENABLE, + + /** This parameter indicates whether using a broadcast probe response + * to increase the detectability of SAP in MCC mode */ + WMI_VDEV_PARAM_MCC_BROADCAST_PROBE_ENABLE, + + /** This parameter indicates the power backoff in percentage + * currently supports 100%, 50%, 25%, 12.5%, and minimum + * Host passes 0, 1, 2, 3, 4 to Firmware + * 0 --> 100% --> no changes, 1 --> 50% --> -3dB, + * 2 --> 25% --> -6dB, 3 --> 12.5% --> -9dB, 4 --> minimum --> -32dB + */ + WMI_VDEV_PARAM_TXPOWER_SCALE, + + /** TX power backoff in dB: tx power -= param value + * Host passes values(DB) to Halphy, Halphy reduces the power table + * by the values. Safety check will happen in Halphy. + */ + WMI_VDEV_PARAM_TXPOWER_SCALE_DECR_DB, + + /** Multicast to Unicast conversion setting */ + WMI_VDEV_PARAM_MCAST2UCAST_SET, + + /** Total number of HW retries */ + WMI_VDEV_PARAM_RC_NUM_RETRIES, + + /** Max tx percentage for cabq */ + WMI_VDEV_PARAM_CABQ_MAXDUR, + + /** MFPTEST settings */ + WMI_VDEV_PARAM_MFPTEST_SET, + + /** RTS Fixed rate setting */ + WMI_VDEV_PARAM_RTS_FIXED_RATE, + + /** VHT SGI MASK */ + WMI_VDEV_PARAM_VHT_SGIMASK, + + /** VHT80 Auto Rate MASK */ + WMI_VDEV_PARAM_VHT80_RATEMASK, + + /** set Proxy STA features for this vap */ + WMI_VDEV_PARAM_PROXY_STA, + + /** set virtual cell mode - enable/disable */ + WMI_VDEV_PARAM_VIRTUAL_CELL_MODE, + + /** Set receive packet type */ + WMI_VDEV_PARAM_RX_DECAP_TYPE, + + /** Set ratemask with specific Bandwidth and NSS */ + WMI_VDEV_PARAM_BW_NSS_RATEMASK, + + /** Set SENSOR Support */ + WMI_VDEV_PARAM_SENSOR_AP, + + /** Set beacon rate */ + WMI_VDEV_PARAM_BEACON_RATE, + + /** Enable CTS to self for DTIM beacon */ + WMI_VDEV_PARAM_DTIM_ENABLE_CTS, + + /** Disable station kickout at Vap level */ + WMI_VDEV_PARAM_STA_KICKOUT, + + /* VDEV capabilities */ + WMI_VDEV_PARAM_CAPABILITIES, /* see capabilities defs below */ + + /** + * Increment TSF in micro seconds to avoid beacon collision on mesh VAP. + * The host must ensure that either no other vdevs share the TSF with + * this vdev, or else that it is acceptable to apply this TSF adjustment + * to all vdevs sharing the TSF. + */ + WMI_VDEV_PARAM_TSF_INCREMENT, + + /** Disable/Enable AMPDU of vdev per AC: + * bit | AC + * -------- + * 0 | VO + * 1 | VI + * 2 | BE + * 3 | BK + * A value of 0 in a given bit disables A-MPDU aggregation for + * that AC; a value of 1 enables A-MPDU aggregation + */ + WMI_VDEV_PARAM_AMPDU_PER_AC, + + /** + * Vdev level rx filter of from-ds / to-ds / no-ds / ta / ra frames. + * Used mainly for mesh-vap. + * The parameter value delivered with the RX_FILTER vdev param contains + * a bit-or mask of wmi_vdev_param_filter enum values. + */ + WMI_VDEV_PARAM_RX_FILTER, + + /** vdev-specific mgmt tx power in dBm units (signed integer value) */ + WMI_VDEV_PARAM_MGMT_TX_POWER, + + /** Vdev level non aggregration/11g sw retry threshold. 0-disable, min:0, max:31, default:15 */ + WMI_VDEV_PARAM_NON_AGG_SW_RETRY_TH, + /** Vdev level aggregration sw retry threshold. 0-disable, min:0, max:31, default:15 */ + WMI_VDEV_PARAM_AGG_SW_RETRY_TH, + + /** disable dynamic bw RTS **/ + WMI_VDEV_PARAM_DISABLE_DYN_BW_RTS, + + /** per ssid (vdev) based ATF strict/fair scheduling policy + * param values are WMI_ATF_SSID_FAIR_SCHED or WMI_ATF_SSID_STRICT_SCHED + */ + WMI_VDEV_PARAM_ATF_SSID_SCHED_POLICY, + + /** Enable or disable Dual carrier modulation + * valid values: 0-Disable DCM, 1-Enable DCM. + */ + WMI_VDEV_PARAM_HE_DCM, + + /** Enable or disable Extended range + * valid values: 0-Disable ER, 1-Enable ER. + */ + WMI_VDEV_PARAM_HE_RANGE_EXT, + + /* enable or disable BCAST probe response feature */ + WMI_VDEV_PARAM_ENABLE_BCAST_PROBE_RESPONSE, + + /* param to specify probe request Tx delay during Fast Initial Link Setup */ + WMI_VDEV_PARAM_FILS_MAX_CHANNEL_GUARD_TIME, /* units = milliseconds */ + + /* enable or disable NOA for P2P GO */ + WMI_VDEV_PARAM_DISABLE_NOA_P2P_GO, + + /** Per band user management frame fix rate setting + * BIT 31: enable (1) or disable (0) mgmt fix rate for 5G + * BIT 30: enable (1) or disable (0) mgmt fix rate for 2G + * + * BIT 23: 11ax (1) or legacy (0) rate code + * BITS [22..12]: rate code for 5G + * + * BIT 11: 11ax (1) or legacy (0) rate code + * BITS [10..0]: rate code for 2G + */ + WMI_VDEV_PARAM_PER_BAND_MGMT_TX_RATE, + /* This should be called before WMI_VDEV_PARAM_TXBF */ + WMI_VDEV_PARAM_11AX_TXBF, + + /** This parameter indicates whether VDEV is SMPS intolerant. + * I.e. - SMPS action frame cannot be transmitted by the VDEV to + * dynamically change the RX NSS. + * + * valid values: 1 - VDEV is SMPS intolerant, 0 - VDEV is SMPS tolerant + */ + WMI_VDEV_PARAM_SMPS_INTOLERANT, + + /** specify probe request Tx delay for scans triggered on this VDEV */ + WMI_VDEV_PARAM_PROBE_DELAY, /* units = milliseconds */ + + /** specify the time gap between each set of probe request transmissions. + * The number of probe requests in each set depends on the ssid_list and + * bssid_list in the scan request. + * This parameter will be applied only for scans triggered on this VDEV. + */ + WMI_VDEV_PARAM_REPEAT_PROBE_TIME, /* units = milliseconds */ + + + /*=== ADD NEW VDEV PARAM TYPES ABOVE THIS LINE === + * The below vdev param types are used for prototyping, and are + * prone to change. + */ + WMI_VDEV_PARAM_PROTOTYPE = 0x8000, + /* 11AX SPECIFIC defines */ + /* USE this for BSS color change */ + WMI_VDEV_PARAM_BSS_COLOR, + /* + * Enable / disable trigger access for a AP vdev's peers. + * For a STA mode vdev this will enable/disable triggered access + * and enable/disable Multi User mode of operation. + * 0 Disable MU OFDMA and MU MIMO + * 1 Disable DL OFDMA + * 2 Disable DL MUMIMO + * 3 Disable UL OFDMA + * 4 Disable UL MUMIMO + * 5 Enable MU OFDMA and MU MIMO + * 6 Enable DL OFDMA + * 7 Enable DL MUMIMO + * 8 Enable UL OFDMA + * 9 Enable UL MUMIMO + */ + WMI_VDEV_PARAM_SET_HEMU_MODE, + WMI_VDEV_PARAM_HEOPS_0_31, + WMI_VDEV_PARAM_OBSSPD, + /*=== END VDEV_PARAM_PROTOTYPE SECTION ===*/ +} WMI_VDEV_PARAM; + +/* vdev capabilities bit mask */ +#define WMI_VDEV_BEACON_SUPPORT 0x1 +#define WMI_VDEV_WDS_LRN_ENABLED 0x2 +#define WMI_VDEV_VOW_ENABLED 0x4 + +#define WMI_VDEV_IS_BEACON_SUPPORTED(param) ((param) & WMI_VDEV_BEACON_SUPPORT) +#define WMI_VDEV_IS_WDS_LRN_ENABLED(param) ((param) & WMI_VDEV_WDS_LRN_ENABLED) +#define WMI_VDEV_IS_VOW_ENABLED(param) ((param) & WMI_VDEV_VOW_ENABLED) + +/* TXBF capabilities masks */ +#define WMI_TXBF_CONF_SU_TX_BFEE_S 0 +#define WMI_TXBF_CONF_SU_TX_BFEE_M 0x1 +#define WMI_TXBF_CONF_SU_TX_BFEE (WMI_TXBF_CONF_SU_TX_BFEE_M << WMI_TXBF_CONF_SU_TX_BFEE_S) +#define WMI_TXBF_CONF_SU_TX_BFEE_GET(x) WMI_F_MS(x,WMI_TXBF_CONF_SU_TX_BFEE) +#define WMI_TXBF_CONF_SU_TX_BFEE_SET(x,z) WMI_F_RMW(x,z,WMI_TXBF_CONF_SU_TX_BFEE) + +#define WMI_TXBF_CONF_MU_TX_BFEE_S 1 +#define WMI_TXBF_CONF_MU_TX_BFEE_M 0x1 +#define WMI_TXBF_CONF_MU_TX_BFEE (WMI_TXBF_CONF_MU_TX_BFEE_M << WMI_TXBF_CONF_MU_TX_BFEE_S) +#define WMI_TXBF_CONF_MU_TX_BFEE_GET(x) WMI_F_MS(x,WMI_TXBF_CONF_MU_TX_BFEE) +#define WMI_TXBF_CONF_MU_TX_BFEE_SET(x,z) WMI_F_RMW(x,z,WMI_TXBF_CONF_MU_TX_BFEE) + +#define WMI_TXBF_CONF_SU_TX_BFER_S 2 +#define WMI_TXBF_CONF_SU_TX_BFER_M 0x1 +#define WMI_TXBF_CONF_SU_TX_BFER (WMI_TXBF_CONF_SU_TX_BFER_M << WMI_TXBF_CONF_SU_TX_BFER_S) +#define WMI_TXBF_CONF_SU_TX_BFER_GET(x) WMI_F_MS(x,WMI_TXBF_CONF_SU_TX_BFER) +#define WMI_TXBF_CONF_SU_TX_BFER_SET(x,z) WMI_F_RMW(x,z,WMI_TXBF_CONF_SU_TX_BFER) + +#define WMI_TXBF_CONF_MU_TX_BFER_S 3 +#define WMI_TXBF_CONF_MU_TX_BFER_M 0x1 +#define WMI_TXBF_CONF_MU_TX_BFER (WMI_TXBF_CONF_MU_TX_BFER_M << WMI_TXBF_CONF_MU_TX_BFER_S) +#define WMI_TXBF_CONF_MU_TX_BFER_GET(x) WMI_F_MS(x,WMI_TXBF_CONF_MU_TX_BFER) +#define WMI_TXBF_CONF_MU_TX_BFER_SET(x,z) WMI_F_RMW(x,z,WMI_TXBF_CONF_MU_TX_BFER) + +#define WMI_TXBF_CONF_STS_CAP_S 4 +#define WMI_TXBF_CONF_STS_CAP_M 0x7 +#define WMI_TXBF_CONF_STS_CAP (WMI_TXBF_CONF_STS_CAP_M << WMI_TXBF_CONF_STS_CAP_S) +#define WMI_TXBF_CONF_STS_CAP_GET(x) WMI_F_MS(x,WMI_TXBF_CONF_STS_CAP); +#define WMI_TXBF_CONF_STS_CAP_SET(x,z) WMI_F_RMW(x,z,WMI_TXBF_CONF_STS_CAP) + +#define WMI_TXBF_CONF_IMPLICIT_BF_S 7 +#define WMI_TXBF_CONF_IMPLICIT_BF_M 0x1 +#define WMI_TXBF_CONF_IMPLICIT_BF (WMI_TXBF_CONF_IMPLICIT_BF_M << WMI_TXBF_CONF_IMPLICIT_BF_S) +#define WMI_TXBF_CONF_IMPLICIT_BF_GET(x) WMI_F_MS(x,WMI_TXBF_CONF_IMPLICIT_BF) +#define WMI_TXBF_CONF_IMPLICIT_BF_SET(x,z) WMI_F_RMW(x,z,WMI_TXBF_CONF_IMPLICIT_BF) + +#define WMI_TXBF_CONF_BF_SND_DIM_S 8 +#define WMI_TXBF_CONF_BF_SND_DIM_M 0x7 +#define WMI_TXBF_CONF_BF_SND_DIM (WMI_TXBF_CONF_BF_SND_DIM_M << WMI_TXBF_CONF_BF_SND_DIM_S) +#define WMI_TXBF_CONF_BF_SND_DIM_GET(x) WMI_F_MS(x,WMI_TXBF_CONF_BF_SND_DIM) +#define WMI_TXBF_CONF_BF_SND_DIM_SET(x,z) WMI_F_RMW(x,z,WMI_TXBF_CONF_BF_SND_DIM) + +/* commands for 11ax TXBF capabilities */ + +#define WMI_TXBF_CONF_11AX_SU_TX_BFER_GET(x) WMI_GET_BITS((x,0,1) +#define WMI_TXBF_CONF_11AX_SU_TX_BFER_SET(x,z) WMI_SET_BITS(x,0,1,z) + +#define WMI_TXBF_CONF_11AX_SU_TX_BFEE_GET(x) WMI_GET_BITS((x,1,1) +#define WMI_TXBF_CONF_11AX_SU_TX_BFEE_SET(x,z) WMI_SET_BITS(x,1,1,z) + +#define WMI_TXBF_CONF_11AX_MU_TX_BFER_GET(x) WMI_GET_BITS((x,2,1) +#define WMI_TXBF_CONF_11AX_MU_TX_BFER_SET(x,z) WMI_SET_BITS(x,2,1,z) + +#define WMI_TXBF_CONF_11AX_BFEE_NDP_STS_LT_EQ_80_GET(x) WMI_GET_BITS((x,3,3) +#define WMI_TXBF_CONF_11AX_BFEE_NDP_STS_LT_EQ_80_SET(x,z) WMI_SET_BITS(x,3,3,z) + +#define WMI_TXBF_CONF_11AX_NSTS_LT_EQ_80_GET(x) WMI_GET_BITS((x,6,3) +#define WMI_TXBF_CONF_11AX_NSTS_LT_EQ_80_SET(x,z) WMI_SET_BITS(x,6,3,z) + +#define WMI_TXBF_CONF_11AX_TX_BFEE_NDP_STS_GT_80_GET(x) WMI_GET_BITS((x,9,3) +#define WMI_TXBF_CONF_11AX_TX_BFEE_NDP_STS_GT_80_SET(x,z) WMI_SET_BITS(x,9,3,z) + +#define WMI_TXBF_CONF_11AX_NSTS_GT_80_GET(x) WMI_GET_BITS((x,12,3) +#define WMI_TXBF_CONF_11AX_NSTS_GT_80_SET(x,z) WMI_SET_BITS(x,12,3,z) + +#define WMI_TXBF_CONF_AX_BFER_SND_DIM_LT_EQ_80_SND_DIM_GET(x) WMI_GET_BITS((x,15,3) +#define WMI_TXBF_CONF_AX_BFER_SND_DIM_LT_EQ_80_SND_DIM_SET(x,z) WMI_SET_BITS(x,15,3,z) + +#define WMI_TXBF_CONF_AX_BFER_SND_DIM_GT_80_SND_DIM_GET(x) WMI_GET_BITS((x,18,3) +#define WMI_TXBF_CONF_AX_BFER_SND_DIM_GT_80_SND_DIM_SET(x,z) WMI_SET_BITS(x,18,3,z) + +#define WMI_TXBF_CONF_AX_SU_BFEE_NG16_FDBK_GET(x) WMI_GET_BITS((x,21,1) +#define WMI_TXBF_CONF_AX_SU_BFEE_NG16_FDBK_SET(x,z) WMI_SET_BITS(x,21,1,z) + +#define WMI_TXBF_CONF_AX_MU_BFEE_NG16_FDBK_GET(x) WMI_GET_BITS((x,22,1) +#define WMI_TXBF_CONF_AX_MU_BFEE_NG16_FDBK_SET(x,z) WMI_SET_BITS(x,22,1,z) + +#define WMI_TXBF_CONF_AX_SU_BFEE_CDBK_4_2_GET(x) WMI_GET_BITS((x,23,1) +#define WMI_TXBF_CONF_AX_SU_BFEE_CDBK_4_2_SET(x,z) WMI_SET_BITS(x,23,1,z) + +#define WMI_TXBF_CONF_AX_MU_BFEE_CDBK_7_5_GET(x) WMI_GET_BITS((x,24,1) +#define WMI_TXBF_CONF_AX_MU_BFEE_CDBK_7_5_SET(x,z) WMI_SET_BITS(x,24,1,z) + +#define WMI_TXBF_CONF_AX_FDBK_TRIG_GET(x) WMI_GET_BITS((x,25,1) +#define WMI_TXBF_CONF_AX_FDBK_TRIG_SET(x,z) WMI_SET_BITS(x,25,1,z) + + +/* TXBF capabilities */ +typedef struct { + A_UINT32 txbf_cap; +} wmi_vdev_txbf_cap; + +/* vdev rx filters (for mesh) */ +typedef enum { + WMI_VDEV_RX_ALLOW_ALL_FRAMES = 0x0, /* Don't drop any frames - Default */ + WMI_VDEV_RX_FILTER_OUT_FROMDS = 0x1, /* Drop FromDS frames */ + WMI_VDEV_RX_FILTER_OUT_TODS = 0x2, /* Drop ToDS frames */ + WMI_VDEV_RX_FILTER_OUT_NODS = 0x4, /* Drop NODS frames */ + WMI_VDEV_RX_FILTER_OUT_RA = 0x8, /* Drop RA frames */ + WMI_VDEV_RX_FILTER_OUT_TA = 0x10, /* Drop TA frames */ +} wmi_vdev_param_filter; + +/* Length of ATIM Window in TU */ +#define WMI_VDEV_PARAM_ATIM_WINDOW_LENGTH WMI_VDEV_PARAM_ATIM_WINDOW + +enum wmi_pkt_type { + WMI_PKT_TYPE_RAW = 0, + WMI_PKT_TYPE_NATIVE_WIFI = 1, + WMI_PKT_TYPE_ETHERNET = 2, +}; + +/******************************************************************* + * wmi_vdev_txbf_en is DEPRECATED in favor of wmi_vdev_txbf_cap + * Do not use it! + *******************************************************************/ +typedef struct { + A_UINT8 sutxbfee : 1, + mutxbfee : 1, + sutxbfer : 1, + mutxbfer : 1, + txb_sts_cap : 3, + implicit_bf : 1; +} wmi_vdev_txbf_en; + +/** Upto 8 bits are available for Roaming module to be sent along with +WMI_VDEV_PARAM_ROAM_FW_OFFLOAD WMI_VDEV_PARAM **/ +/* Enable Roaming FW offload LFR1.5/LFR2.0 implementation */ +#define WMI_ROAM_FW_OFFLOAD_ENABLE_FLAG 0x1 +/* Enable Roaming module in FW to do scan based on Final BMISS */ +#define WMI_ROAM_BMISS_FINAL_SCAN_ENABLE_FLAG 0x2 + +/** slot time long */ +#define WMI_VDEV_SLOT_TIME_LONG 0x1 +/** slot time short */ +#define WMI_VDEV_SLOT_TIME_SHORT 0x2 +/** preablbe long */ +#define WMI_VDEV_PREAMBLE_LONG 0x1 +/** preablbe short */ +#define WMI_VDEV_PREAMBLE_SHORT 0x2 + +/** the definition of different START/RESTART Event response */ +typedef enum { + /* Event respose of START CMD */ + WMI_VDEV_START_RESP_EVENT = 0, + /* Event respose of RESTART CMD */ + WMI_VDEV_RESTART_RESP_EVENT, +} WMI_START_EVENT_PARAM; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_vdev_start_response_event_fixed_param */ + /** unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; + /** requestor id that requested the VDEV start request */ + A_UINT32 requestor_id; + /* Respose of Event type START/RESTART */ + WMI_START_EVENT_PARAM resp_type; + /** status of the response */ + A_UINT32 status; + /** Vdev chain mask */ + A_UINT32 chain_mask; + /** Vdev mimo power save mode */ + A_UINT32 smps_mode; + union { + A_UINT32 mac_id; /* OBSOLETE - will be removed once all refs are gone */ + /** pdev_id for identifying the MAC + * See macros starting with WMI_PDEV_ID_ for values. + */ + A_UINT32 pdev_id; + }; + /** Configured Transmit Streams **/ + A_UINT32 cfgd_tx_streams; + /** Configured Receive Streams **/ + A_UINT32 cfgd_rx_streams; +} wmi_vdev_start_response_event_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_vdev_stopped_event_fixed_param */ + /** unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; +} wmi_vdev_stopped_event_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_vdev_delete_resp_event_fixed_param */ + /** unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; +} wmi_vdev_delete_resp_event_fixed_param; + +/** common structure used for simple events (stopped, resume_req, standby response) */ +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag would be equivalent to actual event */ + /** unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; +} wmi_vdev_simple_event_fixed_param; + + +/** VDEV start response status codes */ +#define WMI_VDEV_START_RESPONSE_STATUS_SUCCESS 0x0 /** VDEV succesfully started */ +#define WMI_VDEV_START_RESPONSE_INVALID_VDEVID 0x1 /** requested VDEV not found */ +#define WMI_VDEV_START_RESPONSE_NOT_SUPPORTED 0x2 /** unsupported VDEV combination */ + +/** Beacon processing related command and event structures */ +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_bcn_tx_hdr */ + /** unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; + /** xmit rate */ + A_UINT32 tx_rate; + /** xmit power */ + A_UINT32 txPower; + /** beacon buffer length in bytes */ + A_UINT32 buf_len; +/* This TLV is followed by array of bytes: + * A_UINT8 bufp[]; <-- beacon frame buffer + */ +} wmi_bcn_tx_hdr; + +/* Beacon filter */ +#define WMI_BCN_FILTER_ALL 0 /* Filter all beacons */ +#define WMI_BCN_FILTER_NONE 1 /* Pass all beacons */ +#define WMI_BCN_FILTER_RSSI 2 /* Pass Beacons RSSI >= RSSI threshold */ +#define WMI_BCN_FILTER_BSSID 3 /* Pass Beacons with matching BSSID */ +#define WMI_BCN_FILTER_SSID 4 /* Pass Beacons with matching SSID */ + +typedef struct { + /** Filter ID */ + A_UINT32 bcn_filter_id; + /** Filter type - wmi_bcn_filter */ + A_UINT32 bcn_filter; + /** Buffer len */ + A_UINT32 bcn_filter_len; + /** Filter info (threshold, BSSID, RSSI) */ + A_UINT8 *bcn_filter_buf; +} wmi_bcn_filter_rx_cmd; + +/** Capabilities and IEs to be passed to firmware */ +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_bcn_prb_info */ + /** Capabilities */ + A_UINT32 caps; + /** ERP info */ + A_UINT32 erp; +/** Advanced capabilities */ +/** HT capabilities */ +/** HT Info */ +/** ibss_dfs */ +/** wpa Info */ +/** rsn Info */ +/** rrm info */ +/** ath_ext */ +/** app IE */ +} wmi_bcn_prb_info; + +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_bcn_tmpl_cmd_fixed_param */ + /** unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; + /** TIM IE offset from the beginning of the template. */ + A_UINT32 tim_ie_offset; + /** beacon buffer length. data is in TLV data[] */ + A_UINT32 buf_len; + /** CSA IE switch count offset from the beginning of data[] + * Value 0 indicates CSA IE is not present in beacon template. + */ + A_UINT32 csa_switch_count_offset; /* units = bytes */ + /** Extended CSA IE switch count offset from the beginning of data[] + * Value 0 indicates CSA IE is not present in beacon template. + */ + A_UINT32 ext_csa_switch_count_offset; /* units = bytes */ + +/* + * The TLVs follows: + * wmi_bcn_prb_info bcn_prb_info; <-- beacon probe capabilities and IEs + * A_UINT8 data[]; <-- Variable length data + */ +} wmi_bcn_tmpl_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_prb_tmpl_cmd_fixed_param */ + /** unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; + /** beacon buffer length. data is in TLV data[] */ + A_UINT32 buf_len; +/* + * The TLVs follows: + * wmi_bcn_prb_info bcn_prb_info; <-- beacon probe capabilities and IEs + * A_UINT8 data[]; <-- Variable length data + */ +} wmi_prb_tmpl_cmd_fixed_param; + +typedef struct { + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_offload_bcn_tx_status_event_fixed_param */ + A_UINT32 tlv_header; + /** unique id identifying the VDEV */ + A_UINT32 vdev_id; + /** bcn tx status, values defined in enum WMI_FRAME_TX_STATUS */ + A_UINT32 tx_status; +} wmi_offload_bcn_tx_status_event_fixed_param; + +enum wmi_sta_ps_mode { + /** enable power save for the given STA VDEV */ + WMI_STA_PS_MODE_DISABLED = 0, + /** disable power save for a given STA VDEV */ + WMI_STA_PS_MODE_ENABLED = 1, +}; + +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_sta_powersave_mode_cmd_fixed_param */ + /** unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; + + /** Power save mode + * + * (see enum wmi_sta_ps_mode) + */ + A_UINT32 sta_ps_mode; +} wmi_sta_powersave_mode_cmd_fixed_param; + +enum wmi_csa_offload_en { + WMI_CSA_OFFLOAD_DISABLE = 0, + WMI_CSA_OFFLOAD_ENABLE = 1, +}; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_csa_offload_enable_cmd_fixed_param */ + A_UINT32 vdev_id; + A_UINT32 csa_offload_enable; +} wmi_csa_offload_enable_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_csa_offload_chanswitch_cmd_fixed_param */ + A_UINT32 vdev_id; +/* + * The TLVs follows: + * wmi_channel chan; + */ +} wmi_csa_offload_chanswitch_cmd_fixed_param; +/** + * This parameter controls the policy for retrieving frames from AP while the + * STA is in sleep state. + * + * Only takes affect if the sta_ps_mode is enabled + */ +enum wmi_sta_ps_param_rx_wake_policy { + /* Wake up when ever there is an RX activity on the VDEV. In this mode + * the Power save SM(state machine) will come out of sleep by either + * sending null frame (or) a data frame (with PS==0) in response to TIM + * bit set in the received beacon frame from AP. + */ + WMI_STA_PS_RX_WAKE_POLICY_WAKE = 0, + + /* Here the power save state machine will not wakeup in response to TIM + * bit, instead it will send a PSPOLL (or) UASPD trigger based on UAPSD + * configuration setup by WMISET_PS_SET_UAPSD WMI command. When all + * access categories are delivery-enabled, the station will send a UAPSD + * trigger frame, otherwise it will send a PS-Poll. + */ + WMI_STA_PS_RX_WAKE_POLICY_POLL_UAPSD = 1, +}; + +/** Number of tx frames/beacon that cause the power save SM to wake up. + * + * Value 1 causes the SM to wake up for every TX. Value 0 has a special + * meaning, It will cause the SM to never wake up. This is useful if you want + * to keep the system to sleep all the time for some kind of test mode . host + * can change this parameter any time. It will affect at the next tx frame. + */ +enum wmi_sta_ps_param_tx_wake_threshold { + WMI_STA_PS_TX_WAKE_THRESHOLD_NEVER = 0, + WMI_STA_PS_TX_WAKE_THRESHOLD_ALWAYS = 1, + +/* Values greater than one indicate that many TX attempts per beacon + * interval before the STA will wake up + */ +}; + +/** + * The maximum number of PS-Poll frames the FW will send in response to + * traffic advertised in TIM before waking up (by sending a null frame with PS + * = 0). Value 0 has a special meaning: there is no maximum count and the FW + * will send as many PS-Poll as are necessary to retrieve buffered BU. This + * parameter is used when the RX wake policy is + * WMI_STA_PS_RX_WAKE_POLICY_POLL_UAPSD and ignored when the RX wake + * policy is WMI_STA_PS_RX_WAKE_POLICY_WAKE. + */ +enum wmi_sta_ps_param_pspoll_count { + WMI_STA_PS_PSPOLL_COUNT_NO_MAX = 0, +/* Values greater than 0 indicate the maximum numer of PS-Poll frames FW + * will send before waking up. + */ +}; + +/* + * This will include the delivery and trigger enabled state for every AC. + * This is the negotiated state with AP. The host MLME needs to set this based + * on AP capability and the state Set in the association request by the + * station MLME.Lower 8 bits of the value specify the UAPSD configuration. + */ +#define WMI_UAPSD_AC_TYPE_DELI 0 +#define WMI_UAPSD_AC_TYPE_TRIG 1 + +#define WMI_UAPSD_AC_BIT_MASK(ac,type) \ + ((type == WMI_UAPSD_AC_TYPE_DELI) ? \ + (1 << (ac<<1)) : \ + (1 << ((ac<<1)+1))) + +enum wmi_sta_ps_param_uapsd { + WMI_STA_PS_UAPSD_AC0_DELIVERY_EN = (1 << 0), + WMI_STA_PS_UAPSD_AC0_TRIGGER_EN = (1 << 1), + WMI_STA_PS_UAPSD_AC1_DELIVERY_EN = (1 << 2), + WMI_STA_PS_UAPSD_AC1_TRIGGER_EN = (1 << 3), + WMI_STA_PS_UAPSD_AC2_DELIVERY_EN = (1 << 4), + WMI_STA_PS_UAPSD_AC2_TRIGGER_EN = (1 << 5), + WMI_STA_PS_UAPSD_AC3_DELIVERY_EN = (1 << 6), + WMI_STA_PS_UAPSD_AC3_TRIGGER_EN = (1 << 7), +}; + +enum wmi_sta_powersave_param { +/** + * Controls how frames are retrievd from AP while STA is sleeping + * + * (see enum wmi_sta_ps_param_rx_wake_policy) + */ +WMI_STA_PS_PARAM_RX_WAKE_POLICY = 0, + +/** + * The STA will go active after this many TX + * + * (see enum wmi_sta_ps_param_tx_wake_threshold) + */ +WMI_STA_PS_PARAM_TX_WAKE_THRESHOLD = 1, + +/** + * Number of PS-Poll to send before STA wakes up + * + * (see enum wmi_sta_ps_param_pspoll_count) + * + */ +WMI_STA_PS_PARAM_PSPOLL_COUNT = 2, + +/** + * TX/RX inactivity time in msec before going to sleep. + * + * The power save SM will monitor tx/rx activity on the VDEV, if no + * activity for the specified msec of the parameter the Power save SM will + * go to sleep. + */ +WMI_STA_PS_PARAM_INACTIVITY_TIME = 3, + +/** + * Set uapsd configuration. + * + * (see enum wmi_sta_ps_param_uapsd) + */ +WMI_STA_PS_PARAM_UAPSD = 4, + +/** + * Number of PS-Poll to send before STA wakes up in QPower Mode + */ +WMI_STA_PS_PARAM_QPOWER_PSPOLL_COUNT = 5, + +/** + * Enable QPower + */ +WMI_STA_PS_ENABLE_QPOWER = 6, + +/** + * Number of TX frames before the entering the Active state + */ +WMI_STA_PS_PARAM_QPOWER_MAX_TX_BEFORE_WAKE = 7, + +/** + * QPower SPEC PSPOLL interval + */ +WMI_STA_PS_PARAM_QPOWER_SPEC_PSPOLL_WAKE_INTERVAL = 8, + +/** + * Max SPEC PSPOLL to be sent when the PSPOLL response has + * no-data bit set + */ +WMI_STA_PS_PARAM_QPOWER_SPEC_MAX_SPEC_NODATA_PSPOLL = 9, + +/** + * Max value of ITO reset when there is no tx-rx + * after AP has set the TIM bit + */ +WMI_STA_PS_PARAM_MAX_RESET_ITO_COUNT_ON_TIM_NO_TXRX = 10, +}; + +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_sta_powersave_param_cmd_fixed_param */ + /** unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; + /** station power save parameter (see enum wmi_sta_powersave_param) */ + A_UINT32 param; + A_UINT32 value; +} wmi_sta_powersave_param_cmd_fixed_param; + +/** No MIMO power save */ +#define WMI_STA_MIMO_PS_MODE_DISABLE +/** mimo powersave mode static*/ +#define WMI_STA_MIMO_PS_MODE_STATIC +/** mimo powersave mode dynamic */ +#define WMI_STA_MIMO_PS_MODE_DYNAMI + +typedef struct { + /** unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; + /** mimo powersave mode as defined above */ + A_UINT32 mimo_pwrsave_mode; +} wmi_sta_mimo_ps_mode_cmd; + + +/** U-APSD configuration of peer station from (re)assoc request and TSPECs */ +enum wmi_ap_ps_param_uapsd { + WMI_AP_PS_UAPSD_AC0_DELIVERY_EN = (1 << 0), + WMI_AP_PS_UAPSD_AC0_TRIGGER_EN = (1 << 1), + WMI_AP_PS_UAPSD_AC1_DELIVERY_EN = (1 << 2), + WMI_AP_PS_UAPSD_AC1_TRIGGER_EN = (1 << 3), + WMI_AP_PS_UAPSD_AC2_DELIVERY_EN = (1 << 4), + WMI_AP_PS_UAPSD_AC2_TRIGGER_EN = (1 << 5), + WMI_AP_PS_UAPSD_AC3_DELIVERY_EN = (1 << 6), + WMI_AP_PS_UAPSD_AC3_TRIGGER_EN = (1 << 7), +}; + +/** U-APSD maximum service period of peer station */ +enum wmi_ap_ps_peer_param_max_sp { + WMI_AP_PS_PEER_PARAM_MAX_SP_UNLIMITED = 0, + WMI_AP_PS_PEER_PARAM_MAX_SP_2 = 1, + WMI_AP_PS_PEER_PARAM_MAX_SP_4 = 2, + WMI_AP_PS_PEER_PARAM_MAX_SP_6 = 3, + + /* keep last! */ + MAX_WMI_AP_PS_PEER_PARAM_MAX_SP, +}; + +/** param values for WMI_AP_PS_PEER_PARAM_SIFS_RESP_FRMTYPE */ +enum wmi_ap_ps_param_sifs_resp_frmtype { + WMI_SIFS_RESP_PSPOLL = (1 << 0), + WMI_SIFS_RESP_UAPSD = (1 << 1), + WMI_SIFS_RESP_QBST_EXP = (1 << 2), + WMI_SIFS_RESP_QBST_DATA = (1 << 3), + WMI_SIFS_RESP_QBST_BAR = (1 << 4), +}; + +/** + * AP power save parameter + * Set a power save specific parameter for a peer station + */ +enum wmi_ap_ps_peer_param { + /** Set uapsd configuration for a given peer. + * + * This will include the delivery and trigger enabled state for every AC. + * The host MLME needs to set this based on AP capability and stations + * request Set in the association request received from the station. + * + * Lower 8 bits of the value specify the UAPSD configuration. + * + * (see enum wmi_ap_ps_param_uapsd) + * The default value is 0. + */ + WMI_AP_PS_PEER_PARAM_UAPSD = 0, + + /** + * Set the service period for a UAPSD capable station + * + * The service period from wme ie in the (re)assoc request frame. + * + * (see enum wmi_ap_ps_peer_param_max_sp) + */ + WMI_AP_PS_PEER_PARAM_MAX_SP = 1, + + /** Time in seconds for aging out buffered frames for STA in power save */ + WMI_AP_PS_PEER_PARAM_AGEOUT_TIME = 2, + + /** + * Specify frame types that are considered SIFS RESP trigger frame + * (see enum wmi_ap_ps_param_sifs_resp_frmtype) + */ + WMI_AP_PS_PEER_PARAM_SIFS_RESP_FRMTYPE = 3, + + /** Specifies the trigger state of TID. Valid only for UAPSD frame type */ + WMI_AP_PS_PEER_PARAM_SIFS_RESP_UAPSD = 4, + + /** Specifies the WNM sleep state of a STA */ + WMI_AP_PS_PEER_PARAM_WNM_SLEEP = 5, +}; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_ap_ps_peer_cmd_fixed_param */ + /** unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; + /** peer MAC address */ + wmi_mac_addr peer_macaddr; + /** AP powersave param (see enum wmi_ap_ps_peer_param) */ + A_UINT32 param; + /** AP powersave param value (see defines) */ + A_UINT32 value; +} wmi_ap_ps_peer_cmd_fixed_param; + +/** Configure peer station 11v U-APSD coexistance + * + * Two parameters from uaspd coexistence ie info (as specified in 11v) are + * sent down to FW along with this command. + * + * The semantics of these fields are described in the following text extracted + * from 802.11v. + * + * --- If the non-AP STA specified a non-zero TSF 0 Offset value in the + * U-APSD Coexistence element, the AP should not transmit frames to the + * non-AP STA outside of the U-APSD Coexistence Service Period, which + * begins when the AP receives the U-APSD trigger frame and ends after + * the transmission period specified by the result of the following + * calculation: + * + * End of transmission period = T + (Interval . ((T . TSF 0 Offset) mod Interval)) + * + * Where T is the time the U-APSD trigger frame was received at the AP + * Interval is the UAPSD Coexistence element Duration/Interval field + * value (see 7.3.2.91) or upon the successful transmission of a frame + * with EOSP bit set to 1, whichever is earlier. + * + * + * --- If the non-AP STA specified a zero TSF 0 Offset value in the U-APSD + * Coexistence element, the AP should not transmit frames to the non-AP + * STA outside of the U-APSD Coexistence Service Period, which begins + * when the AP receives a U-APSD trigger frame and ends after the + * transmission period specified by the result of the following + * calculation: End of transmission period = T + Duration + */ +typedef struct { + /** unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; + /** peer MAC address */ + wmi_mac_addr peer_macaddr; + /** Enable U-APSD coexistence support for this peer + * + * 0 -> disabled (default) + * 1 -> enabled + */ + A_UINT32 enabled; + /** Duration/Interval as defined by 11v U-ASPD coexistance */ + A_UINT32 duration_interval; + /** Upper 32 bits of 64-bit TSF offset */ + A_UINT32 tsf_offset_high; + /** Lower 32 bits of 64-bit TSF offset */ + A_UINT32 tsf_offset_low; +} wmi_ap_powersave_peer_uapsd_coex_cmd; + +typedef enum { + WMI_AP_PS_EGAP_F_ENABLE_PHYERR_DETECTION = 0x0001, + WMI_AP_PS_EGAP_F_ENABLE_PWRSAVE_BY_PS_STATE = 0x0002, + WMI_AP_PS_EGAP_F_ENABLE_PWRSAVE_BY_INACTIVITY = 0x0004, + + WMI_AP_PS_EGAP_FLAG_MAX = 0x8000 +} wmi_ap_ps_egap_flag_type; + +/** + * configure ehanced green ap parameters + */ +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals wmi_ap_powersave_egap_param_cmd_fixed_param */ + /** Enable enhanced green ap + * 0 -> disabled + * 1 -> enabled + */ + A_UINT32 enable; + /** The param indicates a duration that all STAs connected + * to S-AP have no traffic. + */ + A_UINT32 inactivity_time; /* in unit of milliseconds */ + /** The param indicates a duration that all STAs connected + * to S-AP have no traffic, after all STAs have entered powersave. + */ + A_UINT32 wait_time; /* in unit of milliseconds */ + /** The param is used to turn on/off some functions within E-GAP. + */ + A_UINT32 flags; /* wmi_ap_ps_egap_flag_type bitmap */ +} wmi_ap_ps_egap_param_cmd_fixed_param; + +typedef enum { + WMI_AP_PS_EGAP_STATUS_IDLE = 1, + WMI_AP_PS_EGAP_STATUS_PWRSAVE_OFF = 2, + WMI_AP_PS_EGAP_STATUS_PWRSAVE_ON = 3, + + WMI_AP_PS_EGAP_STATUS_MAX = 15 +} wmi_ap_ps_egap_status_type; + +/** + * send ehanced green ap status to host + */ +typedef struct +{ + /** TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_ap_ps_egap_info_chainmask_list */ + A_UINT32 tlv_header; + union { + A_UINT32 mac_id; /* OBSOLETE - will be removed once all refs are gone */ + /** pdev_id for identifying the MAC + * See macros starting with WMI_PDEV_ID_ for values. + */ + A_UINT32 pdev_id; + }; + /** The param indicates the current tx chainmask with the mac id. */ + A_UINT32 tx_chainmask; + /** The param indicates the current rx chainmask with the mac id. */ + A_UINT32 rx_chainmask; +} wmi_ap_ps_egap_info_chainmask_list; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals wmi_ap_powersave_egap_param_cmd_fixed_param */ + /** Enhanced green ap status (WMI_AP_PS_EGAP_STATUS). */ + A_UINT32 status; +/* This TLV is followed by + * wmi_ap_ps_egap_info_chainmask_list chainmask_list[]; + */ +} wmi_ap_ps_egap_info_event_fixed_param; + +/* 128 clients = 4 words */ +/* WMI_TIM_BITMAP_ARRAY_SIZE can't be modified without breaking the compatibility */ +#define WMI_TIM_BITMAP_ARRAY_SIZE 4 + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_tim_info */ + /** TIM bitmap len (in bytes) */ + A_UINT32 tim_len; + /** TIM Partial Virtual Bitmap */ + A_UINT32 tim_mcast; + A_UINT32 tim_bitmap[WMI_TIM_BITMAP_ARRAY_SIZE]; + A_UINT32 tim_changed; + A_UINT32 tim_num_ps_pending; + /** Use the vdev_id only if vdev_id_valid is set */ + A_UINT32 vdev_id_valid; + /** unique id identifying the VDEV */ + A_UINT32 vdev_id; +} wmi_tim_info; + +typedef struct { + /** Flag to enable quiet period IE support */ + A_UINT32 is_enabled; + /** Quiet start */ + A_UINT32 tbttcount; + /** Beacon intervals between quiets*/ + A_UINT32 period; + /** TUs of each quiet*/ + A_UINT32 duration; + /** TUs of from TBTT of quiet start*/ + A_UINT32 offset; +} wmi_quiet_info; + +/* WMI_P2P_MAX_NOA_DESCRIPTORS can't be modified without breaking the compatibility */ +#define WMI_P2P_MAX_NOA_DESCRIPTORS 4 /* Maximum number of NOA Descriptors supported */ + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_p2p_noa_info */ + /** Bit 0: Flag to indicate an update in NOA schedule + * Bits 7-1: Reserved + * Bits 15-8: Index (identifies the instance of NOA sub element) + * Bit 16: Opp PS state of the AP + * Bits 23-17: Ctwindow in TUs + * Bits 31-24: Number of NOA descriptors + */ + A_UINT32 noa_attributes; + wmi_p2p_noa_descriptor noa_descriptors[WMI_P2P_MAX_NOA_DESCRIPTORS]; + /** Use the vdev_id only if vdev_id_valid is set */ + A_UINT32 vdev_id_valid; + /** unique id identifying the VDEV */ + A_UINT32 vdev_id; +} wmi_p2p_noa_info; + +#define WMI_UNIFIED_NOA_ATTR_MODIFIED 0x1 +#define WMI_UNIFIED_NOA_ATTR_MODIFIED_S 0 + +#define WMI_UNIFIED_NOA_ATTR_IS_MODIFIED(hdr) \ + WMI_F_MS((hdr)->noa_attributes, WMI_UNIFIED_NOA_ATTR_MODIFIED) + +#define WMI_UNIFIED_NOA_ATTR_MODIFIED_SET(hdr) \ + WMI_F_RMW((hdr)->noa_attributes, 0x1, \ + WMI_UNIFIED_NOA_ATTR_MODIFIED); + +#define WMI_UNIFIED_NOA_ATTR_INDEX 0xff00 +#define WMI_UNIFIED_NOA_ATTR_INDEX_S 8 + +#define WMI_UNIFIED_NOA_ATTR_INDEX_GET(hdr) \ + WMI_F_MS((hdr)->noa_attributes, WMI_UNIFIED_NOA_ATTR_INDEX) + +#define WMI_UNIFIED_NOA_ATTR_INDEX_SET(hdr, v) \ + WMI_F_RMW((hdr)->noa_attributes, (v) & 0xff, \ + WMI_UNIFIED_NOA_ATTR_INDEX); + +#define WMI_UNIFIED_NOA_ATTR_OPP_PS 0x10000 +#define WMI_UNIFIED_NOA_ATTR_OPP_PS_S 16 + +#define WMI_UNIFIED_NOA_ATTR_OPP_PS_GET(hdr) \ + WMI_F_MS((hdr)->noa_attributes, WMI_UNIFIED_NOA_ATTR_OPP_PS) + +#define WMI_UNIFIED_NOA_ATTR_OPP_PS_SET(hdr) \ + WMI_F_RMW((hdr)->noa_attributes, 0x1, \ + WMI_UNIFIED_NOA_ATTR_OPP_PS); + +#define WMI_UNIFIED_NOA_ATTR_CTWIN 0xfe0000 +#define WMI_UNIFIED_NOA_ATTR_CTWIN_S 17 + +#define WMI_UNIFIED_NOA_ATTR_CTWIN_GET(hdr) \ + WMI_F_MS((hdr)->noa_attributes, WMI_UNIFIED_NOA_ATTR_CTWIN) + +#define WMI_UNIFIED_NOA_ATTR_CTWIN_SET(hdr, v) \ + WMI_F_RMW((hdr)->noa_attributes, (v) & 0x7f, \ + WMI_UNIFIED_NOA_ATTR_CTWIN); + +#define WMI_UNIFIED_NOA_ATTR_NUM_DESC 0xff000000 +#define WMI_UNIFIED_NOA_ATTR_NUM_DESC_S 24 + +#define WMI_UNIFIED_NOA_ATTR_NUM_DESC_GET(hdr) \ + WMI_F_MS((hdr)->noa_attributes, WMI_UNIFIED_NOA_ATTR_NUM_DESC) + +#define WMI_UNIFIED_NOA_ATTR_NUM_DESC_SET(hdr, v) \ + WMI_F_RMW((hdr)->noa_attributes, (v) & 0xff, \ + WMI_UNIFIED_NOA_ATTR_NUM_DESC); + +typedef struct { + /** TIM info */ + wmi_tim_info tim_info; + /** P2P NOA info */ + wmi_p2p_noa_info p2p_noa_info; +/* TBD: More info elements to be added later */ +} wmi_bcn_info; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_host_swba_event_fixed_param */ + /** bitmap identifying the VDEVs, generated by the caller */ + A_UINT32 vdev_map; + /** how many vdev's info is included in this message + * If this field is zero, then the number of vdevs is specified by + * the number of bits set in the vdev_map bitmap. + */ + A_UINT32 num_vdevs; +/* This TLV is followed by tim_info and p2p_noa_info for each vdev: + * wmi_tim_info tim_info[]; + * wmi_p2p_noa_info p2p_noa_info[]; + * + */ +} wmi_host_swba_event_fixed_param; + +#define WMI_MAX_AP_VDEV 16 + + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_tbtt_offset_event_fixed_param */ + /** bimtap of VDEVs that has tbtt offset updated */ + A_UINT32 vdev_map; +/* The TLVs for tbttoffset_list will follow this TLV. + * tbtt offset list in the order of the LSB to MSB in the vdev_map bitmap + * A_UINT32 tbttoffset_list[WMI_MAX_AP_VDEV]; + */ +} wmi_tbtt_offset_event_fixed_param; + +typedef struct { + A_UINT32 tlv_header;/* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_tbtt_offset_info */ + /** unique id identifying the VDEV */ + A_UINT32 vdev_id; + /** tbttoffset in TUs */ + A_UINT32 tbttoffset; +} wmi_tbtt_offset_info; + +/** Use this event if number of vdevs > 32 */ +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_tbtt_offset_ext_event_fixed_param */ + A_UINT32 num_vdevs; +/* + * The TLVs for tbttoffset will follow this TLV. + * Of size num_vdevs * wmi_tbtt_offset_info + */ +} wmi_tbtt_offset_ext_event_fixed_param; + + +/* Peer Specific commands and events */ + +typedef struct { + A_UINT32 percentage; /* in unit of 12.5% */ + A_UINT32 min_delta; /* in unit of Mbps */ +} rate_delta_t; + +#define PEER_RATE_REPORT_COND_FLAG_DELTA 0x01 +#define PEER_RATE_REPORT_COND_FLAG_THRESHOLD 0x02 +#define MAX_NUM_OF_RATE_THRESH 4 + +typedef struct { + A_UINT32 val_cond_flags; /* PEER_RATE_REPORT_COND_FLAG_DELTA, PEER_RATE_REPORT_COND_FLAG_THRESHOLD + Any of these two conditions or both of them can be set. */ + rate_delta_t rate_delta; + A_UINT32 rate_threshold[MAX_NUM_OF_RATE_THRESH]; /* In unit of Mbps. There are at most 4 thresholds. + If the threshold count is less than 4, set zero to + the one following the last threshold */ +} report_cond_per_phy_t; + + +enum peer_rate_report_cond_phy_type { + PEER_RATE_REPORT_COND_11B = 0, + PEER_RATE_REPORT_COND_11A_G, + PEER_RATE_REPORT_COND_11N, + PEER_RATE_REPORT_COND_11AC, + PEER_RATE_REPORT_COND_MAX_NUM +}; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_peer_rate_report_condtion_fixed_param */ + A_UINT32 enable_rate_report; /* 1= enable, 0=disable */ + A_UINT32 report_backoff_time; /* in unit of msecond */ + A_UINT32 report_timer_period; /* in unit of msecond */ + /* In the following field, the array index means the phy type, + * please see enum peer_rate_report_cond_phy_type for detail */ + report_cond_per_phy_t cond_per_phy[PEER_RATE_REPORT_COND_MAX_NUM]; +} wmi_peer_set_rate_report_condition_fixed_param; + +/* Peer Type: + * NB: This can be left DEFAULT for the normal case, and f/w will determine BSS type based + * on address and vdev opmode. This is largely here to allow host to indicate that + * peer is explicitly a TDLS peer + */ +enum wmi_peer_type { + WMI_PEER_TYPE_DEFAULT = 0, /* Generic/Non-BSS/Self Peer */ + WMI_PEER_TYPE_BSS = 1, /* Peer is BSS Peer entry */ + WMI_PEER_TYPE_TDLS = 2, /* Peer is a TDLS Peer */ + WMI_PEER_TYPE_OCB = 3, /* Peer is a OCB Peer */ + WMI_PEER_TYPE_NAN_DATA = 4, /* Peer is NAN DATA */ + WMI_PEER_TYPE_HOST_MAX = 127, /* Host <-> Target Peer type is assigned up to 127 */ + /* Reserved from 128 - 255 for target internal use.*/ + WMI_PEER_TYPE_ROAMOFFLOAD_TEMP = 128, /* Temporarily created during offload roam */ +}; + +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_peer_create_cmd_fixed_param */ + /** unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; + /** peer MAC address */ + wmi_mac_addr peer_macaddr; + /** peer type: see enum values above */ + A_UINT32 peer_type; +} wmi_peer_create_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_peer_delete_cmd_fixed_param */ + /** unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; + /** peer MAC address */ + wmi_mac_addr peer_macaddr; +} wmi_peer_delete_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_peer_set_rx_blocksize_cmd_fixed_param */ + /** unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; + /** peer MAC address */ + wmi_mac_addr peer_macaddr; + /** + * maximum block ack window size to use during a rx block ack negotiation, + * i.e. the maximum number of MPDUs per A-MPDU that will be received + */ + A_UINT32 rx_block_ack_win_limit; +} wmi_peer_set_rx_blocksize_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_peer_flush_tids_cmd_fixed_param */ + /** unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; + /** peer MAC address */ + wmi_mac_addr peer_macaddr; + /** tid bitmap identifying the tids to flush */ + A_UINT32 peer_tid_bitmap; +} wmi_peer_flush_tids_cmd_fixed_param; + +typedef struct { + /** rate mode . 0: disable fixed rate (auto rate) + * 1: legacy (non 11n) rate specified as ieee rate 2*Mbps + * 2: ht20 11n rate specified as mcs index + * 3: ht40 11n rate specified as mcs index + */ + A_UINT32 rate_mode; + /** 4 rate values for 4 rate series. series 0 is stored in byte 0 (LSB) + * and series 3 is stored at byte 3 (MSB) */ + A_UINT32 rate_series; + /** 4 retry counts for 4 rate series. retry count for rate 0 is stored in byte 0 (LSB) + * and retry count for rate 3 is stored at byte 3 (MSB) */ + A_UINT32 rate_retries; +} wmi_fixed_rate; + +typedef struct { + /** unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; + /** peer MAC address */ + wmi_mac_addr peer_macaddr; + /** fixed rate */ + wmi_fixed_rate peer_fixed_rate; +} wmi_peer_fixed_rate_cmd; + +#define WMI_MGMT_TID 17 + +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_addba_clear_resp_cmd_fixed_param */ + /** unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; + /** peer MAC address */ + wmi_mac_addr peer_macaddr; +} wmi_addba_clear_resp_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_addba_send_cmd_fixed_param */ + /** unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; + /** peer MAC address */ + wmi_mac_addr peer_macaddr; + /** Tid number */ + A_UINT32 tid; + /** Buffer/Window size*/ + A_UINT32 buffersize; +} wmi_addba_send_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_delba_send_cmd_fixed_param */ + /** unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; + /** peer MAC address */ + wmi_mac_addr peer_macaddr; + /** Tid number */ + A_UINT32 tid; + /** Is Initiator */ + A_UINT32 initiator; + /** Reason code */ + A_UINT32 reasoncode; +} wmi_delba_send_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_addba_setresponse_cmd_fixed_param */ + /** unique id identifying the vdev, generated by the caller */ + A_UINT32 vdev_id; + /** peer mac address */ + wmi_mac_addr peer_macaddr; + /** Tid number */ + A_UINT32 tid; + /** status code */ + A_UINT32 statuscode; +} wmi_addba_setresponse_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_send_singleamsdu_cmd_fixed_param */ + /** unique id identifying the vdev, generated by the caller */ + A_UINT32 vdev_id; + /** peer mac address */ + wmi_mac_addr peer_macaddr; + /** Tid number */ + A_UINT32 tid; +} wmi_send_singleamsdu_cmd_fixed_param; + +/* Type of Station DTIM Power Save method */ +enum { + /* For NORMAL DTIM, the parameter is the number of beacon intervals and + * also the same value as the listen interval. For this method, the + * station will wake up based on the listen interval. If this + * listen interval is not equal to DTIM, then the station may + * miss certain DTIM beacons. If this value is 1, then the + * station will wake up for every beacon. + */ + WMI_STA_DTIM_PS_NORMAL_DTIM = 0x01, + /* For MODULATED_DTIM, parameter is a multiple of DTIM beacons to skip. + * When this value is 1, then the station will wake at every DTIM beacon. + * If this value is >1, then the station will skip certain DTIM beacons. + * This value is the multiple of DTIM intervals that the station will + * wake up to receive the DTIM beacons. + */ + WMI_STA_DTIM_PS_MODULATED_DTIM = 0x02, +}; + +/* Parameter structure for the WMI_STA_DTIM_PS_METHOD_CMDID */ +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_sta_dtim_ps_method_cmd_fixed_param */ + /** unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; + /** Station DTIM Power Save method as defined above */ + A_UINT32 dtim_pwrsave_method; + /** DTIM PS value. Contents depends on the method */ + A_UINT32 value; + /** Modulated DTIM value */ + A_UINT32 MaxLIModulatedDTIM; +} wmi_sta_dtim_ps_method_cmd_fixed_param; + +/* + * For Station UAPSD Auto Trigger feature, the Firmware monitors the + * uAPSD uplink and downlink traffic for each uAPSD enabled WMM ACs. + * If there is no uplink/download for the specified service interval (field service_interval), + * firmware will auto generate a QOS-NULL trigger for that WMM-AP with the TID value + * specified in the UP (field user_priority). + * Firmware also monitors the responses for these QOS-NULL triggers. + * If the peer does not have any delivery frames, it will respond with + * QOS-NULL (EOSP=1). This feature of only using service interval is assumed to be mandatory for all + * firmware implementation. For this basic implementation, the suspend_interval and delay_interval + * are unused and should be set to 0. + * When service_interval is 0, then the firmware will not send any trigger frames. This is for + * certain host-based implementations that don't want this firmware offload. + * Note that the per-AC intervals are required for some usage scenarios. This is why the intervals + * are given in the array of ac_param[]. For example, Voice service interval may defaults to 20 ms + * and rest of the AC default to 300 ms. + * + * The service bit, WMI_STA_UAPSD_VAR_AUTO_TRIG, will indicate that the more advanced feature + * of variable auto trigger is supported. The suspend_interval and delay_interval is used in + * the more advanced monitoring method. + * If the PEER does not have any delivery enabled data frames (non QOS-NULL) for the + * suspend interval (field suspend_interval), firmware will change its auto trigger interval + * to delay interval (field delay_interval). This way, when there is no traffic, the station + * will save more power by waking up less and sending less trigger frames. + * The (service_interval < suspend_interval) and (service_interval < delay_interval). + * If this variable auto trigger is not required, then the suspend_interval and delay_interval + * should be 0. + */ +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_sta_uapsd_auto_trig_param */ + /** WMM Access category from 0 to 3 */ + A_UINT32 wmm_ac; + /** User priority to use in trigger frames. It is the TID + * value. This field needs to be specified and may not be + * equivalent to AC since some implementation may use the TSPEC + * to enable UAPSD and negotiate a particular user priority. */ + A_UINT32 user_priority; + /** service interval in ms */ + A_UINT32 service_interval; + /** Suspend interval in ms */ + A_UINT32 suspend_interval; + /** delay interval in ms */ + A_UINT32 delay_interval; +} wmi_sta_uapsd_auto_trig_param; + +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_sta_uapsd_auto_trig_cmd_fixed_param */ + /** unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; + /** peer mac address */ + wmi_mac_addr peer_macaddr; + /** Number of AC to specify */ + A_UINT32 num_ac; +/* + * Following this struc is the TLV: + * wmi_sta_uapsd_auto_trig_param ac_param[]; <-- Variable number of AC parameters (defined by field num_ac) + */ + +} wmi_sta_uapsd_auto_trig_cmd_fixed_param; + +/** mimo powersave state */ +#define WMI_PEER_MIMO_PS_STATE 0x1 +/** enable/disable AMPDU . initial value (enabled) */ +#define WMI_PEER_AMPDU 0x2 +/** authorize/unauthorize peer. initial value is unauthorized (0) */ +#define WMI_PEER_AUTHORIZE 0x3 +/** peer channel bandwidth */ +#define WMI_PEER_CHWIDTH 0x4 +/** peer NSS */ +#define WMI_PEER_NSS 0x5 +/** USE 4 ADDR */ +#define WMI_PEER_USE_4ADDR 0x6 +/* set group membership status */ +#define WMI_PEER_MEMBERSHIP 0x7 +#define WMI_PEER_USERPOS 0x8 +/* + * A critical high-level protocol is being used with this peer. Target + * should take appropriate measures (if possible) to ensure more + * reliable link with minimal latency. This *may* include modifying the + * station power save policy, enabling more RX chains, increased + * priority of channel scheduling, etc. + * + * NOTE: This parameter should only be considered a hint as specific + * behavior will depend on many factors including current network load + * and vdev/peer configuration. + * + * For STA VDEV this peer corresponds to the AP's BSS peer. + * For AP VDEV this peer corresponds to the remote peer STA. + */ +#define WMI_PEER_CRIT_PROTO_HINT_ENABLED 0x9 +/* set Tx failure count threshold for the peer - Currently unused */ +#define WMI_PEER_TX_FAIL_CNT_THR 0xA +/* Enable H/W retry and Enable H/W Send CTS2S before Data */ +#define WMI_PEER_SET_HW_RETRY_CTS2S 0xB + +/* Set peer advertised IBSS atim window length */ +#define WMI_PEER_IBSS_ATIM_WINDOW_LENGTH 0xC + +/** peer phy mode */ +#define WMI_PEER_PHYMODE 0xD +/** Use FIXED Pwr */ +#define WMI_PEER_USE_FIXED_PWR 0xE +/** Set peer fixed rate + * The top nibble is used to select which format to use for encoding + * the rate specification: 0xVXXXXXXX + * If V == 0b0000: format is same as before: 0x000000RR + * If V == 0b0001: format is: 0x1000RRRR. + * This will be output of WMI_ASSEMBLE_RATECODE_V1 + * The host shall use the new V1 format (and set V = 0x1) if the target + * indicates 802.11ax support via the WMI_SERVICE_11AX flag, or if the + * system is configured with Nss > 4 (either at compile time within the + * host driver, or through WMI_SERVICE_READY PHY capabilities provided + * by the target). + */ +#define WMI_PEER_PARAM_FIXED_RATE 0xF +/** Whitelist peer TIDs */ +#define WMI_PEER_SET_MU_WHITELIST 0x10 +/** Set peer max tx rate (MCS) in adaptive rate ctrl */ +#define WMI_PEER_SET_MAX_TX_RATE 0x11 +/** Set peer minimal tx rate (MCS) in adaptive rate ctrl */ +#define WMI_PEER_SET_MIN_TX_RATE 0x12 +/** + * default ring routing for peer data packets, + * param_value = bit 0 for hash based routing enabled or not + * (value 1 is enabled, value 0 is disabled) + * bits 1:5 are for ring 32 (i.e. ring id value + * selected from 0 to 31 values) + */ +#define WMI_PEER_SET_DEFAULT_ROUTING 0x13 + +/** mimo ps values for the parameter WMI_PEER_MIMO_PS_STATE */ +#define WMI_PEER_MIMO_PS_NONE 0x0 +#define WMI_PEER_MIMO_PS_STATIC 0x1 +#define WMI_PEER_MIMO_PS_DYNAMIC 0x2 + +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_peer_set_param_cmd_fixed_param */ + /** unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; + /** peer MAC address */ + wmi_mac_addr peer_macaddr; + /** parameter id */ + A_UINT32 param_id; + /** parametr value */ + A_UINT32 param_value; +} wmi_peer_set_param_cmd_fixed_param; + +typedef union { + /* + * The A_UINT16 "mode" and "tx_rate" fields can only be directly used + * by the target or a little-endian host. + * A big-endian host needs to use the WMI_PEER_MAX_MIN_TX_xxx_GET/SET + * macros on the A_UINT32 "value" field. + */ + struct { + A_UINT16 mode; /* 0:CCK, 1:OFDM, 2:HT, 3:VHT (see WMI_RATE_PREAMBLE) */ + A_UINT16 tx_rate; /* see per-mode specs below */ + }; + A_UINT32 value; /* for use by big-endian host */ +} wmi_peer_max_min_tx_rate; + +/* + * Any access to the mode/tx_rate in an big endian system should use + * the below Macros on the wmi_peer_max_min_tx_rate.value field. + */ +#define WMI_PEER_MAX_MIN_TX_MODE_GET(value32) WMI_GET_BITS(value32, 0, 16) +#define WMI_PEER_MAX_MIN_TX_MODE_SET(value32, tx_mode) WMI_SET_BITS(value32, 0, 16, tx_mode) + +#define WMI_PEER_MAX_MIN_TX_RATE_GET(value32) WMI_GET_BITS(value32, 16, 16) +#define WMI_PEER_MAX_MIN_TX_RATE_SET(value32, tx_mode) WMI_SET_BITS(value32, 16, 16, tx_mode) + +/* CCK max/min tx Rate description + * tx_rate = 0: 1 Mbps + * tx_rate = 1: 2 Mbps + * tx_rate = 2: 5.5 Mbps + * tx_rate = 3: 11 Mbps + * tx_rate = else: invalid + */ +enum { + WMI_MAX_CCK_TX_RATE_1M, /* up to 1M CCK Rate avaliable */ + WMI_MAX_CCK_TX_RATE_2M, /* up to 2M CCK Rate avaliable */ + WMI_MAX_CCK_TX_RATE_5_5M, /* up to 5.5M CCK Rate avaliable */ + WMI_MAX_CCK_TX_RATE_11M, /* up to 11M CCK Rate avaliable */ + WMI_MAX_CCK_TX_RATE = WMI_MAX_CCK_TX_RATE_11M, +}; + +/* OFDM max/min tx Rate description + * tx_rate = 0: 6 Mbps + * tx_rate = 1: 9 Mbps + * tx_rate = 2: 12 Mbps + * tx_rate = 3: 18 Mbps + * tx_rate = 4: 24 Mbps + * tx_rate = 5: 32 Mbps + * tx_rate = 6: 48 Mbps + * tx_rate = 7: 54 Mbps + * tx_rate = else: invalid + */ +enum { + WMI_MAX_OFDM_TX_RATE_6M, /* up to 6M OFDM Rate avaliable */ + WMI_MAX_OFDM_TX_RATE_9M, /* up to 9M OFDM Rate avaliable */ + WMI_MAX_OFDM_TX_RATE_12M, /* up to 12M OFDM Rate avaliable */ + WMI_MAX_OFDM_TX_RATE_18M, /* up to 18M OFDM Rate avaliable */ + WMI_MAX_OFDM_TX_RATE_24M, /* up to 24M OFDM Rate avaliable */ + WMI_MAX_OFDM_TX_RATE_36M, /* up to 36M OFDM Rate avaliable */ + WMI_MAX_OFDM_TX_RATE_48M, /* up to 48M OFDM Rate avaliable */ + WMI_MAX_OFDM_TX_RATE_54M, /* up to 54M OFDM Rate avaliable */ + WMI_MAX_OFDM_TX_RATE = WMI_MAX_OFDM_TX_RATE_54M, +}; + +/* HT max/min tx rate description + * tx_rate = 0~7 : MCS Rate 0~7 + * tx_rate=else : invalid. + */ +#define WMI_MAX_HT_TX_MCS 0x07 + +/* VHT max/min tx rate description + * tx_rate = 0~9 : MCS Rate 0~9 + * tx_rate=else : invalid. + */ +#define WMI_MAX_VHT_TX_MCS 0x09 + + +#define MAX_SUPPORTED_RATES 128 + +typedef struct { + /** total number of rates */ + A_UINT32 num_rates; + /** + * rates (each 8bit value) packed into a 32 bit word. + * the rates are filled from least significant byte to most + * significant byte. + */ + A_UINT32 rates[(MAX_SUPPORTED_RATES / 4) + 1]; +} wmi_rate_set; + +/* NOTE: It would bea good idea to represent the Tx MCS + * info in one word and Rx in another word. This is split + * into multiple words for convenience + */ +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_vht_rate_set */ + A_UINT32 rx_max_rate; /* Max Rx data rate */ + A_UINT32 rx_mcs_set; /* Negotiated RX VHT rates */ + A_UINT32 tx_max_rate; /* Max Tx data rate */ + A_UINT32 tx_mcs_set; /* Negotiated TX VHT rates */ + A_UINT32 tx_max_mcs_nss; /* b0-b3: max mcs idx; b4-b7: max nss */ +} wmi_vht_rate_set; + + +/* NOTE: It would bea good idea to represent the Tx MCS + * info in one word and Rx in another word. This is split + * into multiple words for convenience + * currently this is being defined in IEEE802.11ax so this is same as wmi_vht_rate_set and is sub change in future and may include BW as well + */ +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_he_rate_set */ + /* HE Supported MCS Set field Rx + * - 3 bits are used for each NSS chain.Max of 8 NSS can be encoded with + * bit 2-0 indicating max HE MCS of NSS1 + * bit 5-3 indicating max HE MCS of NSS2 and so on + * - The max HE-MCS for n SS subfield (where n = 1,...,8) is encoded as follows + * - 0 indicates support for VHT-MCS 0-7 for n spatial streams + * - 1 indicates support for VHT-MCS 0-8 for n spatial streams + * - 2 indicates support for VHT-MCS 0-9 for n spatial streams + * - 3 indicates support for VHT-MCS 0-10 for n spatial streams + * - 4 indicates support for VHT-MCS 0-11 for n spatial streams + * - 5-6 reserved + * - 7 indicates that n spatial streams is not supported + * - WMI_HE_MAX_MCS_4_SS_MASK macro can be used for encoding this info + */ + A_UINT32 rx_mcs_set; /* Negotiated RX VHT rates (i.e. rate this node can RX from peer)*/ + /* HE Supported MCS Set field Tx + * - 3 bits are used for each NSS chain.Max of 8 NSS can be encoded with + * bit 2-0 indicating max HE MCS of NSS1 + * bit 5-3 indicating max HE MCS of NSS2 and so on + * - The max HE-MCS for n SS subfield (where n = 1,...,8) is encoded as follows + * - 0 indicates support for VHT-MCS 0-7 for n spatial streams + * - 1 indicates support for VHT-MCS 0-8 for n spatial streams + * - 2 indicates support for VHT-MCS 0-9 for n spatial streams + * - 3 indicates support for VHT-MCS 0-10 for n spatial streams + * - 4 indicates support for VHT-MCS 0-11 for n spatial streams + * - 5-6 reserved + * - 7 indicates that n spatial streams is not supported + * - WMI_HE_MAX_MCS_4_SS_MASK macro can be used for encoding this info + */ + A_UINT32 tx_mcs_set; /* Negotiated TX VHT rates(i.e. rate this node can TX to peer) */ +} wmi_he_rate_set; + + + + + + +/* + * IMPORTANT: Make sure the bit definitions here are consistent + * with the ni_flags definitions in wlan_peer.h + */ +#define WMI_PEER_AUTH 0x00000001 /* Authorized for data */ +#define WMI_PEER_QOS 0x00000002 /* QoS enabled */ +#define WMI_PEER_NEED_PTK_4_WAY 0x00000004 /* Needs PTK 4 way handshake for authorization */ +#define WMI_PEER_NEED_GTK_2_WAY 0x00000010 /* Needs GTK 2 way handshake after 4-way handshake */ +#define WMI_PEER_HE 0x00000400 /* HE Enabled */ +#define WMI_PEER_APSD 0x00000800 /* U-APSD power save enabled */ +#define WMI_PEER_HT 0x00001000 /* HT enabled */ +#define WMI_PEER_40MHZ 0x00002000 /* 40MHz enabld */ +#define WMI_PEER_STBC 0x00008000 /* STBC Enabled */ +#define WMI_PEER_LDPC 0x00010000 /* LDPC ENabled */ +#define WMI_PEER_DYN_MIMOPS 0x00020000 /* Dynamic MIMO PS Enabled */ +#define WMI_PEER_STATIC_MIMOPS 0x00040000 /* Static MIMO PS enabled */ +#define WMI_PEER_SPATIAL_MUX 0x00200000 /* SM Enabled */ +#define WMI_PEER_VHT 0x02000000 /* VHT Enabled */ +#define WMI_PEER_80MHZ 0x04000000 /* 80MHz enabld */ +#define WMI_PEER_PMF 0x08000000 /* Robust Management Frame Protection enabled */ +/** CAUTION TODO: Place holder for WLAN_PEER_F_PS_PRESEND_REQUIRED = 0x10000000. Need to be clean up */ +#define WMI_PEER_IS_P2P_CAPABLE 0x20000000 /* P2P capable peer */ +#define WMI_PEER_160MHZ 0x40000000 /* 160 MHz enabled */ +#define WMI_PEER_SAFEMODE_EN 0x80000000 /* Fips Mode Enabled */ + +/** + * Peer rate capabilities. + * + * This is of interest to the ratecontrol + * module which resides in the firmware. The bit definitions are + * consistent with that defined in if_athrate.c. + * + * @todo + * Move this to a common header file later so there is no need to + * duplicate the definitions or maintain consistency. + */ +#define WMI_RC_DS_FLAG 0x01 /* Dual stream flag */ +#define WMI_RC_CW40_FLAG 0x02 /* CW 40 */ +#define WMI_RC_SGI_FLAG 0x04 /* Short Guard Interval */ +#define WMI_RC_HT_FLAG 0x08 /* HT */ +#define WMI_RC_RTSCTS_FLAG 0x10 /* RTS-CTS */ +#define WMI_RC_TX_STBC_FLAG 0x20 /* TX STBC */ +#define WMI_RC_TX_STBC_FLAG_S 5 /* TX STBC */ +#define WMI_RC_RX_STBC_FLAG 0xC0 /* RX STBC ,2 bits */ +#define WMI_RC_RX_STBC_FLAG_S 6 /* RX STBC ,2 bits */ +#define WMI_RC_WEP_TKIP_FLAG 0x100 /* WEP/TKIP encryption */ +#define WMI_RC_TS_FLAG 0x200 /* Three stream flag */ +#define WMI_RC_UAPSD_FLAG 0x400 /* UAPSD Rate Control */ + +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_peer_assoc_complete_cmd_fixed_param */ + /** peer MAC address */ + wmi_mac_addr peer_macaddr; + /** VDEV id */ + A_UINT32 vdev_id; + /** assoc = 1 reassoc = 0 */ + A_UINT32 peer_new_assoc; + /** peer associd (16 bits) */ + A_UINT32 peer_associd; + /** peer station flags: see definition above */ + A_UINT32 peer_flags; + /** negotiated capabilities (lower 16 bits)*/ + A_UINT32 peer_caps; + /** Listen interval */ + A_UINT32 peer_listen_intval; + /** HT capabilties of the peer */ + A_UINT32 peer_ht_caps; + /** maximum rx A-MPDU length */ + A_UINT32 peer_max_mpdu; + /** mpdu density of the peer in usec(0 to 16) */ + A_UINT32 peer_mpdu_density; + /** peer rate capabilties see flags above */ + A_UINT32 peer_rate_caps; + /** num spatial streams */ + A_UINT32 peer_nss; + /** VHT capabilties of the peer */ + A_UINT32 peer_vht_caps; + /** phy mode */ + A_UINT32 peer_phymode; + /** HT Operation Element of the peer. Five bytes packed in 2 + * INT32 array and filled from lsb to msb. + * Note that the size of array peer_ht_info[] cannotbe changed + * without breaking WMI Compatibility. */ + A_UINT32 peer_ht_info[2]; + /** total number of negotiated legacy rate set. Also the sizeof + * peer_legacy_rates[] */ + A_UINT32 num_peer_legacy_rates; + /** total number of negotiated ht rate set. Also the sizeof + * peer_ht_rates[] */ + A_UINT32 num_peer_ht_rates; + /** + * Bitmap providing customized mapping of bandwidths to max Rx NSS + * for this peer. + * This is required since 802.11 standard currently facilitates peer to be + * able to advertise only a single max Rx NSS value across all bandwidths. + * Some QCA chipsets might need to be able to advertise a different max + * Rx NSS value for 160 MHz, than that for 80 MHz and lower. + * + * bit[2:0] : Represents value of Rx NSS for VHT 160 MHz + * bit[30:3]: Reserved + * bit[31] : MSB(0/1): 1 in case of valid data else all bits will be set + * to 0 by host + */ + A_UINT32 peer_bw_rxnss_override; + + /* 802.11ax capabilities */ + wmi_ppe_threshold peer_ppet; + A_UINT32 peer_he_cap_info; /* protocol-defined HE / 11ax capability flags */ + A_UINT32 peer_he_ops; /* HE operation contains BSS color */ + A_UINT32 peer_he_cap_phy[WMI_MAX_HECAP_PHY_SIZE]; + A_UINT32 peer_he_mcs; /* Indicates number of HE MCS TLV present */ + +/* Following this struct are the TLV's: + * A_UINT8 peer_legacy_rates[]; + * A_UINT8 peer_ht_rates[]; + * wmi_vht_rate_set peer_vht_rates; <-- VHT capabilties of the peer + * WMI_he_rate_set_peer_he_rates; <-- HE capabilities of the peer + */ +} wmi_peer_assoc_complete_cmd_fixed_param; + +/* WDS Entry Flags */ +#define WMI_WDS_FLAG_STATIC 0x1 /* Disable aging & learning */ + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_peer_add_wds_entry_cmd_fixed_param */ + /** peer MAC address */ + wmi_mac_addr peer_macaddr; + /** wds MAC addr */ + wmi_mac_addr wds_macaddr; + /* Flags associated with WDS entry - see WMI_WDS_FLAG defs */ + A_UINT32 flags; + A_UINT32 vdev_id; +} wmi_peer_add_wds_entry_cmd_fixed_param; + +#define WMI_CHAN_InFO_START_RESP 0 +#define WMI_CHAN_InFO_END_RESP 1 + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_peer_remove_wds_entry_cmd_fixed_param */ + /** wds MAC addr */ + wmi_mac_addr wds_macaddr; + A_UINT32 vdev_id; +} wmi_peer_remove_wds_entry_cmd_fixed_param; + + +typedef struct { + /** peer MAC address */ + wmi_mac_addr peer_macaddr; +} wmi_peer_q_empty_callback_event; + +/* + * Command to update an already existing WDS entry. Different address setting + * combinations are possible. + * + * Valid wds and peer -> Associated WDS entry peer ptr & flags will be updated. + * Valid wds and null peer -> Associated WDS entry flags will be updated. + * Null wds and Valid peer -> Flags will be updated for all WDS entries behind the peer. + * Null wds and peer -> Flags will be updated for all WDS entries. + */ +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_peer_update_wds_entry_cmd_fixed_param */ + /** peer MAC address */ + wmi_mac_addr peer_macaddr; + /** wds MAC addr */ + wmi_mac_addr wds_macaddr; + /* Flags associated with WDS entry */ + A_UINT32 flags; + A_UINT32 vdev_id; +} wmi_peer_update_wds_entry_cmd_fixed_param; + +/** + * Channel info WMI event + */ +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_chan_info_event_fixed_param */ + /** Error code */ + A_UINT32 err_code; + /** Channel freq */ + A_UINT32 freq; + /** Read flags */ + A_UINT32 cmd_flags; + /** Noise Floor value */ + A_UINT32 noise_floor; + /** rx clear count */ + A_UINT32 rx_clear_count; + /** cycle count */ + A_UINT32 cycle_count; + /** channel tx power per range in 0.5dBm steps */ + A_UINT32 chan_tx_pwr_range; + /** channel tx power per throughput */ + A_UINT32 chan_tx_pwr_tp; + /** rx frame count (cumulative) */ + A_UINT32 rx_frame_count; + /** BSS rx cycle count */ + A_UINT32 my_bss_rx_cycle_count; + /** b-mode data rx time (units are microseconds) */ + A_UINT32 rx_11b_mode_data_duration; + /** tx frame count */ + A_UINT32 tx_frame_cnt; + /** mac clock */ + A_UINT32 mac_clk_mhz; + /** unique id identifying the VDEV */ + A_UINT32 vdev_id; +} wmi_chan_info_event_fixed_param; + +/** + * Non wlan interference event + */ +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wlan_dcs_cw_int */ + A_UINT32 channel; /* either number or freq in mhz*/ +} wlan_dcs_cw_int; +#define ath_dcs_cw_int /* DEPRECATED */ wlan_dcs_cw_int /* alias */ + +/** + * wlan_dcs_im_tgt_stats + * + */ +typedef struct _wlan_dcs_im_tgt_stats { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wlan_dcs_im_tgt_stats_t */ + + /** current running TSF from the TSF-1 */ + A_UINT32 reg_tsf32; + + /** Known last frame rssi, in case of multiple stations, if + * and at different ranges, this would not gaurantee that + * this is the least rssi. + */ + A_UINT32 last_ack_rssi; + + /** Sum of all the failed durations in the last one second interval. + */ + A_UINT32 tx_waste_time; + /** count how many times the hal_rxerr_phy is marked, in this + * time period + */ + A_UINT32 rx_time; + A_UINT32 phyerr_cnt; + + /** + * WLAN IM stats from target to host + * + * Below statistics are sent from target to host periodically. + * These are collected at target as long as target is running + * and target chip is not in sleep. + * + */ + + /** listen time from ANI */ + A_INT32 listen_time; + + /** tx frame count, MAC_PCU_TX_FRAME_CNT_ADDRESS */ + A_UINT32 reg_tx_frame_cnt; + + /** rx frame count, MAC_PCU_RX_FRAME_CNT_ADDRESS */ + A_UINT32 reg_rx_frame_cnt; + + /** rx clear count, MAC_PCU_RX_CLEAR_CNT_ADDRESS */ + A_UINT32 reg_rxclr_cnt; + + /** total cycle counts MAC_PCU_CYCLE_CNT_ADDRESS */ + A_UINT32 reg_cycle_cnt; /* delta cycle count */ + + /** extenstion channel rx clear count */ + A_UINT32 reg_rxclr_ext_cnt; + + /** OFDM phy error counts, MAC_PCU_PHY_ERR_CNT_1_ADDRESS */ + A_UINT32 reg_ofdm_phyerr_cnt; + + /** CCK phy error count, MAC_PCU_PHY_ERR_CNT_2_ADDRESS */ + A_UINT32 reg_cck_phyerr_cnt; /* CCK err count since last reset, read from register */ + + /** Channel noise floor (units are dBm) */ + A_INT32 chan_nf; + + /** BSS rx cycle count */ + A_UINT32 my_bss_rx_cycle_count; +} wlan_dcs_im_tgt_stats_t; + +/** + * wmi_dcs_interference_event_t + * + * Right now this is event and stats together. Partly this is + * because cw interference is handled in target now. This + * can be done at host itself, if we can carry the NF alone + * as a stats event. In future this would be done and this + * event would carry only stats. + */ +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_dcs_interference_event_fixed_param */ + /** + * Type of the event present, either the cw interference event, or the wlan_im stats + */ + A_UINT32 interference_type; /* type of interference, wlan or cw */ + /** pdev_id for identifying the MAC + * See macros starting with WMI_PDEV_ID_ for values. + */ + A_UINT32 pdev_id; +/* + * Following this struct are these TLVs. Note that they are both array of structures + * but can have at most one element. Which TLV is empty or has one element depends + * on the field interference_type. This is to emulate an union with cw_int and wlan_stat + * elements (not arrays). union { wlan_dcs_cw_int cw_int; wlan_dcs_im_tgt_stats_t wlan_stat; } int_event; + * + * wlan_dcs_cw_int cw_int[]; <-- cw_interference event + * wlan_dcs_im_tgt_stats_t wlan_stat[]; <-- wlan im interfernce stats + */ +} wmi_dcs_interference_event_fixed_param; + +enum wmi_peer_mcast_group_action { + wmi_peer_mcast_group_action_add = 0, + wmi_peer_mcast_group_action_del = 1 +}; +#define WMI_PEER_MCAST_GROUP_FLAG_ACTION_M 0x1 +#define WMI_PEER_MCAST_GROUP_FLAG_ACTION_S 0 +#define WMI_PEER_MCAST_GROUP_FLAG_WILDCARD_M 0x2 +#define WMI_PEER_MCAST_GROUP_FLAG_WILDCARD_S 1 +#define WMI_PEER_MCAST_GROUP_FLAG_SRC_FILTER_EXCLUDE_M 0x4 /* flag to exclude an ip while filtering. set to exclude */ +#define WMI_PEER_MCAST_GROUP_FLAG_SRC_FILTER_EXCLUDE_S 2 +#define WMI_PEER_MCAST_GROUP_FLAG_IPV6_M 0x8 /* flag to say ipv4/ipv6. Will be set for ipv6 */ +#define WMI_PEER_MCAST_GROUP_FLAG_IPV6_S 3 +#define WMI_PEER_MCAST_GROUP_FLAG_DELETEALL_M 0x10 /* delete all mcast table entries. */ +#define WMI_PEER_MCAST_GROUP_FLAG_DELETEALL_S 4 + +/* multicast group membership commands */ +/* TODO: Converting this will be tricky since it uses an union. + Also, the mac_addr is not aligned. We will convert to the wmi_mac_addr */ +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_peer_mcast_group_cmd_fixed_param */ + A_UINT32 flags; + wmi_mac_addr ucast_mac_addr; + /* in network byte order */ + /* for ipv4, bytes (12-15) should contain ip address and other lower bytes 0. ipv6 should have all bytes valid */ + A_UINT8 mcast_ip_addr[16]; + /* for ipv6, all 16 bytes has to be valid; for ipv4 last 4 bytes(12-15) has to be valid, rest all 0s */ + A_UINT8 mcast_ip_mask[16];/* zero out lower bytes if ipv4*/ + /* number of address filters - irrespective of ipv4/ipv6 addresses */ + A_UINT32 num_filter_addr; + /* this array should contain the src IPs that are to be filtered during find + The array should be packed. + If there are 2 ipv4 addresses, there should be 8 bytes and rest all 0s */ + A_UINT8 filter_addr[64]; /* 16 ipv4 addresses or 4 ipv6 addresses */ + A_UINT8 vdev_id; /* vdev of this mcast group */ +} wmi_peer_mcast_group_cmd_fixed_param; + + +/** Offload Scan and Roaming related commands */ +/** The FW performs 2 different kinds of offload scans independent + * of host. One is Roam scan which is primarily performed on a + * station VDEV after association to look for a better AP that + * the station VDEV can roam to. The second scan is connect scan + * which is mainly performed when the station is not associated + * and to look for a matching AP profile from a list of + * configured profiles. */ + +/* flags for roam_scan_mode_cmd + * indicate the status (success/fail) of wmi_roam_scan_mode cmd through WMI_ROAM_EVENTID */ +#define WMI_ROAM_SCAN_MODE_FLAG_REPORT_STATUS 0x1 + +/** + * WMI_ROAM_SCAN_MODE: Set Roam Scan mode + * the roam scan mode is one of the periodic, rssi change, both, none. + * None : Disable Roam scan. No Roam scan at all. + * Periodic : Scan periodically with a configurable period. + * Rssi change : Scan when ever rssi to current AP changes by the threshold value + * set by WMI_ROAM_SCAN_RSSI_CHANGE_THRESHOLD command. + * Both : Both of the above (scan when either period expires or rss to current AP changes by X amount) + * + */ +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_roam_scan_mode_fixed_param */ + A_UINT32 roam_scan_mode; + A_UINT32 vdev_id; + A_UINT32 flags; /* see WMI_ROAM_SCAN_MODE_FLAG defs */ +} wmi_roam_scan_mode_fixed_param; + +#define WMI_ROAM_SCAN_MODE_NONE 0x0 +#define WMI_ROAM_SCAN_MODE_PERIODIC 0x1 +#define WMI_ROAM_SCAN_MODE_RSSI_CHANGE 0x2 +#define WMI_ROAM_SCAN_MODE_BOTH 0x3 +/* Note: WMI_ROAM_SCAN_MODE_ROAMOFFLOAD is one bit not conflict with LFR2.0 SCAN_MODE. */ +#define WMI_ROAM_SCAN_MODE_ROAMOFFLOAD 0x4 + + +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_roam_scan_cmd_fixed_param */ + A_UINT32 vdev_id; + A_UINT32 command_arg; +} wmi_roam_scan_cmd_fixed_param; + +#define WMI_ROAM_SCAN_STOP_CMD 0x1 + +/** + * WMI_ROAM_SCAN_RSSI_THRESHOLD : set scan rssi thresold + * scan rssi threshold is the rssi threshold below which the FW will start running Roam scans. + * Applicable when WMI_ROAM_SCAN_MODE is not set to none. + */ +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_roam_scan_rssi_threshold_fixed_param */ + /** unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; + /** roam scan rssi threshold */ + A_UINT32 roam_scan_rssi_thresh; + /** When using Hw generated beacon RSSI interrupts */ + A_UINT32 roam_rssi_thresh_diff; + /** 5G scan max count */ + A_UINT32 hirssi_scan_max_count; + /** 5G scan rssi change threshold value */ + A_UINT32 hirssi_scan_delta; + /** 5G scan upper bound */ + A_UINT32 hirssi_upper_bound; + /** roam scan rssi threshold for 5G band. + * offset from roam_scan_rssi_thres, in dB units + */ + A_INT32 rssi_thresh_offset_5g; + /* The TLVs will follow. + * wmi_roam_scan_extended_threshold_param extended_param; + * wmi_roam_earlystop_rssi_thres_param earlystop_param; + * wmi_roam_dense_thres_param dense_param; + * wmi_roam_bg_scan_roaming_param bg_scan_param; + */ +} wmi_roam_scan_rssi_threshold_fixed_param; + +#define WMI_ROAM_5G_BOOST_PENALIZE_ALGO_FIXED 0x0 +#define WMI_ROAM_5G_BOOST_PENALIZE_ALGO_LINEAR 0x1 +#define WMI_ROAM_5G_BOOST_PENALIZE_ALGO_LOG 0x2 +#define WMI_ROAM_5G_BOOST_PENALIZE_ALGO_EXP 0x3 + +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_roam_scan_extended_threshold_param */ + A_UINT32 boost_threshold_5g; /** RSSI threshold above which 5GHz RSSI is favored */ + A_UINT32 penalty_threshold_5g; /** RSSI threshold below which 5GHz RSSI is penalized */ + A_UINT32 boost_algorithm_5g; /** 0 == fixed, 1 == linear, 2 == logarithm ..etc */ + A_UINT32 boost_factor_5g; /** factor by which 5GHz RSSI is boosted */ + A_UINT32 penalty_algorithm_5g; /** 0 == fixed, 1 == linear, 2 == logarithm ..etc */ + A_UINT32 penalty_factor_5g; /** factor by which 5GHz RSSI is penalized */ + A_UINT32 max_boost_5g; /** maximum boost that can be applied to a 5GHz RSSI */ + A_UINT32 max_penalty_5g; /** maximum penality that can be applied to a 5GHz RSSI */ + A_UINT32 good_rssi_threshold; /** RSSI below which roam is kicked in by background scan, although rssi is still good */ +} wmi_roam_scan_extended_threshold_param; + +/** + * WMI_ROAM_SCAN_PERIOD: period for roam scan. + * Applicable when the scan mode is Periodic or both. + */ +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_roam_scan_period_fixed_param */ + /** unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; + /** roam scan period value */ + A_UINT32 roam_scan_period; + /** Aging for Roam scans */ + A_UINT32 roam_scan_age; +} wmi_roam_scan_period_fixed_param; + +/** + * WMI_ROAM_SCAN_RSSI_CHANGE_THRESHOLD : rssi delta to trigger the roam scan. + * Rssi change threshold used when mode is Rssi change (or) Both. + * The FW will run the roam scan when ever the rssi changes (up or down) by the value set by this parameter. + * Note scan is triggered based on the rssi threshold condition set by WMI_ROAM_SCAN_RSSI_THRESHOLD + */ +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_roam_scan_rssi_change_threshold_fixed_param */ + /** unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; + /** roam scan rssi change threshold value */ + A_UINT32 roam_scan_rssi_change_thresh; + /** When using Hw generated beacon RSSI interrupts */ + A_UINT32 bcn_rssi_weight; + /** Minimum delay between two 5G scans */ + A_UINT32 hirssi_delay_btw_scans; +} wmi_roam_scan_rssi_change_threshold_fixed_param; + +#define WMI_ROAM_SCAN_CHAN_LIST_TYPE_NONE 0x1 +#define WMI_ROAM_SCAN_CHAN_LIST_TYPE_STATIC 0x2 +#define WMI_ROAM_SCAN_CHAN_LIST_TYPE_DYNAMIC 0x3 +/** + * TLV for roaming channel list + */ +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_roam_chan_list_fixed_param */ + /** unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; + /** WMI_CHAN_LIST_TAG */ + A_UINT32 chan_list_type; + /** # if channels to scan */ + A_UINT32 num_chan; +/** + * TLV (tag length value) parameters follow the wmi_roam_chan_list + * structure. The TLV's are: + * A_UINT32 channel_list[]; + **/ +} wmi_roam_chan_list_fixed_param; + +/** Authentication modes */ +enum { + WMI_AUTH_NONE, /* no upper level auth */ + WMI_AUTH_OPEN, /* open */ + WMI_AUTH_SHARED, /* shared-key */ + WMI_AUTH_8021X, /* 802.1x */ + WMI_AUTH_AUTO, /* Auto */ + WMI_AUTH_WPA, /* WPA */ + WMI_AUTH_RSNA, /* WPA2/RSNA */ + WMI_AUTH_CCKM, /* CCKM */ + WMI_AUTH_WAPI, /* WAPI */ + WMI_AUTH_AUTO_PSK, + WMI_AUTH_WPA_PSK, + WMI_AUTH_RSNA_PSK, + WMI_AUTH_WAPI_PSK, + WMI_AUTH_FT_RSNA, /* 11r FT */ + WMI_AUTH_FT_RSNA_PSK, + WMI_AUTH_RSNA_PSK_SHA256, + WMI_AUTH_RSNA_8021X_SHA256, + WMI_AUTH_CCKM_WPA, + WMI_AUTH_CCKM_RSNA, + WMI_AUTH_RSNA_FILS_SHA256, + WMI_AUTH_RSNA_FILS_SHA384, +}; + +typedef enum { + WMI_SCAN_CLIENT_NLO = 0x1, /* 1 */ + WMI_SCAN_CLIENT_EXTSCAN, /* 2 */ + WMI_SCAN_CLIENT_ROAM, /* 3 */ + WMI_SCAN_CLIENT_P2P, /* 4 */ + WMI_SCAN_CLIENT_LPI, /* 5 */ + WMI_SCAN_CLIENT_NAN, /* 6 */ + WMI_SCAN_CLIENT_ANQP, /* 7 */ + WMI_SCAN_CLIENT_OBSS, /* 8 */ + WMI_SCAN_CLIENT_PLM, /* 9 */ + WMI_SCAN_CLIENT_HOST, /* 10 */ +} WMI_SCAN_CLIENT_ID; + +typedef struct { + /** authentication mode (defined above) */ + A_UINT32 rsn_authmode; + /** unicast cipher set */ + A_UINT32 rsn_ucastcipherset; + /** mcast/group cipher set */ + A_UINT32 rsn_mcastcipherset; + /** mcast/group management frames cipher set */ + A_UINT32 rsn_mcastmgmtcipherset; +} wmi_rsn_params; + +/** looking for a wps enabled AP */ +#define WMI_AP_PROFILE_FLAG_WPS 0x1 +/** looking for a secure AP */ +#define WMI_AP_PROFILE_FLAG_CRYPTO 0x2 +/** looking for a PMF enabled AP */ +#define WMI_AP_PROFILE_FLAG_PMF 0x4 + + +/** To match an open AP, the rs_authmode should be set to WMI_AUTH_NONE + * and WMI_AP_PROFILE_FLAG_CRYPTO should be clear. + * To match a WEP enabled AP, the rs_authmode should be set to WMI_AUTH_NONE + * and WMI_AP_PROFILE_FLAG_CRYPTO should be set . + */ + +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_ap_profile */ + /** flags as defined above */ + A_UINT32 flags; + /** + * rssi thresold value: the value of the the candidate AP should + * higher by this threshold than the rssi of the currrently associated AP. + */ + A_UINT32 rssi_threshold; + /** + * ssid vlaue to be matched. + */ + wmi_ssid ssid; + + /** + * security params to be matched. + */ + /** authentication mode (defined above) */ + A_UINT32 rsn_authmode; + /** unicast cipher set */ + A_UINT32 rsn_ucastcipherset; + /** mcast/group cipher set */ + A_UINT32 rsn_mcastcipherset; + /** mcast/group management frames cipher set */ + A_UINT32 rsn_mcastmgmtcipherset; + /** + * rssi_abs_thresold value: the value of the candidate AP should + * higher than this absolute RSSI threshold. + * Zero means no absolute minimum RSSI is required. + * units are the offset from the noise floor in dB. + */ + A_UINT32 rssi_abs_thresh; +} wmi_ap_profile; + +/** Support early stop roaming scanning when finding a strong candidate AP + * A 'strong' candidate is + * 1) Is eligible candidate + * (all conditions are met in existing candidate selection). + * 2) Its rssi is better than earlystop threshold. + * Earlystop threshold will be relaxed as each channel is scanned. + */ +typedef struct { + A_UINT32 tlv_header; + /* Minimum RSSI threshold value for early stop, unit is dB above NF. */ + A_UINT32 roam_earlystop_thres_min; + /* Maminum RSSI threshold value for early stop, unit is dB above NF. */ + A_UINT32 roam_earlystop_thres_max; +} wmi_roam_earlystop_rssi_thres_param; + +typedef struct { + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_roam_dense_thres_param */ + A_UINT32 tlv_header; + /** rssi threshold offset under trffic and dense env */ + A_UINT32 roam_dense_rssi_thres_offset; + /** minimum number of APs to determine dense env */ + A_UINT32 roam_dense_min_aps; + /** initial dense status detected by host at the time of initial connection */ + A_UINT32 roam_dense_status; + /* traffic threshold to enable aggressive roaming in dense env; units are percent of medium occupancy, 0 - 100 */ + A_UINT32 roam_dense_traffic_thres; +} wmi_roam_dense_thres_param; + +typedef struct { + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_roam_bg_scan_roaming_param */ + A_UINT32 tlv_header; + /** rssi threshold in dBm below which roaming will be triggered during background scan(non-roam scan). 0 will disable this threshold */ + A_UINT32 roam_bg_scan_bad_rssi_thresh; + /** bitmap for which scan client will enable/disable background roaming. bit position is mapped to the enum WMI_SCAN_CLIENT_ID. 1 = enable, 0 = disable */ + A_UINT32 roam_bg_scan_client_bitmap; +} wmi_roam_bg_scan_roaming_param; + +/** Beacon filter wmi command info */ + +#define BCN_FLT_MAX_SUPPORTED_IES 256 +#define BCN_FLT_MAX_ELEMS_IE_LIST (BCN_FLT_MAX_SUPPORTED_IES/32) + +typedef struct bss_bcn_stats { + A_UINT32 vdev_id; + A_UINT32 bss_bcnsdropped; + A_UINT32 bss_bcnsdelivered; +} wmi_bss_bcn_stats_t; + +typedef struct bcn_filter_stats { + A_UINT32 bcns_dropped; + A_UINT32 bcns_delivered; + A_UINT32 activefilters; + wmi_bss_bcn_stats_t bss_stats; +} wmi_bcnfilter_stats_t; + +typedef struct wmi_add_bcn_filter_cmd { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_add_bcn_filter_cmd_fixed_param */ + A_UINT32 vdev_id; +/* + * Following this structure is the TLV: + * A_UINT32 ie_map[BCN_FLT_MAX_ELEMS_IE_LIST]; + */ +} wmi_add_bcn_filter_cmd_fixed_param; + +typedef struct wmi_rmv_bcn_filter_cmd { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_rmv_bcn_filter_cmd_fixed_param */ + A_UINT32 vdev_id; +} wmi_rmv_bcn_filter_cmd_fixed_param; + +#define WMI_BCN_SEND_DTIM_ZERO 1 +#define WMI_BCN_SEND_DTIM_BITCTL_SET 2 +typedef struct wmi_bcn_send_from_host { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_bcn_send_from_host_cmd_fixed_param */ + A_UINT32 vdev_id; + A_UINT32 data_len; + union { + A_UINT32 frag_ptr; /* Physical address of the frame */ + A_UINT32 frag_ptr_lo; /* LSBs of physical address of the frame */ + }; + A_UINT32 frame_ctrl; /* farme ctrl to setup PPDU desc */ + A_UINT32 dtim_flag; /* to control CABQ traffic */ + A_UINT32 bcn_antenna; /* Antenna for beacon transmission */ + A_UINT32 frag_ptr_hi; /* MSBs of physical address of the frame */ +} wmi_bcn_send_from_host_cmd_fixed_param; + +/* cmd to support bcn snd for all vaps at once */ +typedef struct wmi_pdev_send_bcn { + A_UINT32 num_vdevs; + wmi_bcn_send_from_host_cmd_fixed_param bcn_cmd[1]; +} wmi_pdev_send_bcn_cmd_t; + +/* + * WMI_ROAM_AP_PROFILE: AP profile of connected AP for roaming. + */ +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_roam_ap_profile_fixed_param */ + /** id of AP criteria */ + A_UINT32 id; + + /** unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; + +/* + * Following this structure is the TLV: + * wmi_ap_profile ap_profile; <-- AP profile info + */ +} wmi_roam_ap_profile_fixed_param; + +/** + * WMI_OFL_SCAN_ADD_AP_PROFILE: add an AP profile. + */ +typedef struct { + /** id of AP criteria */ + A_UINT32 id; + + /** unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; + + /** AP profile info */ + wmi_ap_profile ap_profile; + +} wmi_ofl_scan_add_ap_profile; + +/** + * WMI_OFL_SCAN_REMOVE_AP_CRITERIA: remove an ap profile. + */ +typedef struct { + /** id of AP criteria */ + A_UINT32 id; + /** unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; +} wmi_ofl_scan_remove_ap_profile; + +/** + * WMI_OFL_SCAN_PERIOD: period in msec for offload scan. + * 0 will disable ofload scan and a very low value will perform a continous + * scan. + */ +typedef struct { + /** offload scan period value, used for scans used when not connected */ + A_UINT32 ofl_scan_period; +} wmi_ofl_scan_period; + +/* Do not modify XXX_BYTES or XXX_LEN below as it is fixed by standard */ +#define ROAM_OFFLOAD_PMK_BYTES (32) +#define ROAM_OFFLOAD_PSK_MSK_BYTES (32) +#define ROAM_OFFLOAD_KRK_BYTES (16) +#define ROAM_OFFLOAD_BTK_BYTES (32) +#define ROAM_OFFLOAD_R0KH_ID_MAX_LEN (48) +#define ROAM_OFFLOAD_NUM_MCS_SET (16) + +/* This TLV will be filled only in case roam offload for wpa2-psk/okc/ese/11r is enabled */ +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_roam_offload_fixed_param */ + A_UINT32 rssi_cat_gap; /* gap for every category bucket */ + A_UINT32 prefer_5g; /* prefer select 5G candidate */ + A_UINT32 select_5g_margin; + A_UINT32 reassoc_failure_timeout; /* reassoc failure timeout */ + A_UINT32 capability; + A_UINT32 ht_caps_info; + A_UINT32 ampdu_param; + A_UINT32 ht_ext_cap; + A_UINT32 ht_txbf; + A_UINT32 asel_cap; + A_UINT32 qos_enabled; + A_UINT32 qos_caps; + A_UINT32 wmm_caps; + A_UINT32 mcsset[ROAM_OFFLOAD_NUM_MCS_SET>>2]; /* since this 4 byte aligned, we don't declare it as tlv array */ +} wmi_roam_offload_tlv_param; + + +/* flags for 11i offload */ +#define WMI_ROAM_OFFLOAD_FLAG_OKC_ENABLED 0 /* okc is enabled */ +#define WMI_ROAM_OFFLOAD_FLAG_PMK_CACHE_DISABLED 1 /* pmk caching is disabled */ +/* from bit 2 to bit 31 are reserved */ + +#define WMI_SET_ROAM_OFFLOAD_OKC_ENABLED(flag) do { \ + (flag) |= (1 << WMI_ROAM_OFFLOAD_FLAG_OKC_ENABLED); \ + } while (0) + +#define WMI_SET_ROAM_OFFLOAD_OKC_DISABLED(flag) do { \ + (flag) &= ~(1 << WMI_ROAM_OFFLOAD_FLAG_OKC_ENABLED); \ + } while (0) + +#define WMI_GET_ROAM_OFFLOAD_OKC_ENABLED(flag) \ + ((flag) & (1 << WMI_ROAM_OFFLOAD_FLAG_OKC_ENABLED)) + + +#define WMI_SET_ROAM_OFFLOAD_PMK_CACHE_ENABLED(flag) \ + do { \ + (flag) &= ~(1 << WMI_ROAM_OFFLOAD_FLAG_PMK_CACHE_DISABLED); \ + } while (0) + +#define WMI_SET_ROAM_OFFLOAD_PMK_CACHE_DISABLED(flag) \ + do { \ + (flag) |= (1 << WMI_ROAM_OFFLOAD_FLAG_PMK_CACHE_DISABLED); \ + } while (0) + +#define WMI_GET_ROAM_OFFLOAD_PMK_CACHE_DISABLED(flag) \ + ((flag) & (1 << WMI_ROAM_OFFLOAD_FLAG_PMK_CACHE_DISABLED)) + + +/* This TLV will be filled only in case of wpa-psk/wpa2-psk */ +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_roam_11i_offload_fixed_param */ + A_UINT32 flags; /** flags. see WMI_ROAM_OFFLOAD_FLAG_ above */ + A_UINT32 pmk[ROAM_OFFLOAD_PMK_BYTES>>2]; /* pmk offload. As this 4 byte aligned, we don't declare it as tlv array */ + A_UINT32 pmk_len; /**the length of pmk. in normal case it should be 32, but for LEAP, is should be 16*/ +} wmi_roam_11i_offload_tlv_param; + +/* This TLV will be filled only in case of 11R*/ +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_roam_11r_offload_fixed_param */ + A_UINT32 mdie_present; + A_UINT32 mdid; + A_UINT32 r0kh_id[ROAM_OFFLOAD_R0KH_ID_MAX_LEN>>2]; + A_UINT32 r0kh_id_len; + A_UINT32 psk_msk[ROAM_OFFLOAD_PSK_MSK_BYTES>>2]; /* psk/msk offload. As this 4 byte aligned, we don't declare it as tlv array */ + A_UINT32 psk_msk_len; /**length of psk_msk*/ +} wmi_roam_11r_offload_tlv_param; + +/* This TLV will be filled only in case of ESE */ +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_roam_ese_offload_fixed_param */ + A_UINT32 krk[ROAM_OFFLOAD_KRK_BYTES>>2]; /* KRK offload. As this 4 byte aligned, we don't declare it as tlv array */ + A_UINT32 btk[ROAM_OFFLOAD_BTK_BYTES>>2]; /* BTK offload. As this 4 byte aligned, we don't declare it as tlv array */ +} wmi_roam_ese_offload_tlv_param; + +/** WMI_ROAM_EVENT: roam event triggering the host roam logic. + * generated when ever a better AP is found in the recent roam scan (or) + * when beacon miss is detected (or) when a DEAUTH/DISASSOC is received + * from the current AP. + */ +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_roam_event_fixed_param */ + /** unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; + /** reason for roam event */ + A_UINT32 reason; + /** associated AP's rssi calculated by FW when reason code is WMI_ROAM_REASON_LOW_RSSI*/ + A_UINT32 rssi; + /** roam notification */ + A_UINT32 notif; +} wmi_roam_event_fixed_param; + + +/* roam_reason: bits 0-3 */ +#define WMI_ROAM_REASON_INVALID 0x0 /** invalid reason. Do not interpret reason field */ +#define WMI_ROAM_REASON_BETTER_AP 0x1 /** found a better AP */ +#define WMI_ROAM_REASON_BMISS 0x2 /** beacon miss detected */ +#define WMI_ROAM_REASON_DEAUTH 0x2 /** deauth/disassoc received */ +#define WMI_ROAM_REASON_LOW_RSSI 0x3 /** connected AP's low rssi condition detected */ +#define WMI_ROAM_REASON_SUITABLE_AP 0x4 /** found another AP that matches + SSID and Security profile in + WMI_ROAM_AP_PROFILE, found during scan + triggered upon FINAL_BMISS **/ +#define WMI_ROAM_REASON_HO_FAILED 0x5 /** LFR3.0 roaming failed, indicate the disconnection to host */ +/** WMI_ROAM_REASON_INVOKE_ROAM_FAIL: + * Result code of WMI_ROAM_INVOKE_CMDID. + * Any roaming failure before reassociation will be indicated to host + * with this reason. + * Any roaming failure after reassociation will be indicated to host with + * WMI_ROAM_REASON_HO_FAILED no matter WMI_ROAM_INVOKE_CMDID is called or not. + */ +#define WMI_ROAM_REASON_INVOKE_ROAM_FAIL 0x6 +#define WMI_ROAM_REASON_RSO_STATUS 0x7 +/* reserved up through 0xF */ + +/* subnet status: bits 4-5 */ +typedef enum +{ + WMI_ROAM_SUBNET_CHANGE_STATUS_UNKNOWN = 0, + WMI_ROAM_SUBNET_CHANGE_STATUS_UNCHANGED, + WMI_ROAM_SUBNET_CHANGE_STATUS_CHANGED, +} wmi_roam_subnet_change_status; + +#define WMI_ROAM_SUBNET_CHANGE_STATUS_MASK 0x30 +#define WMI_ROAM_SUBNET_CHANGE_STATUS_SHIFT 4 + +#define WMI_SET_ROAM_SUBNET_CHANGE_STATUS(roam_reason, status) \ + do { \ + (roam_reason) |= \ + (((status) << WMI_ROAM_SUBNET_CHANGE_STATUS_SHIFT) & \ + WMI_ROAM_SUBNET_CHANGE_STATUS_MASK); \ + } while (0) + +#define WMI_GET_ROAM_SUBNET_CHANGE_STATUS(roam_reason) \ + (((roam_reason) & WMI_ROAM_SUBNET_CHANGE_STATUS_MASK) >> \ + WMI_ROAM_SUBNET_CHANGE_STATUS_SHIFT) + +#define WMI_ROAM_REQUEST_HOST_HW_MODE_CHANGE_MASK 0x40 +#define WMI_ROAM_REQUEST_HOST_HW_MODE_CHANGE_SHIFT 6 + +#define WMI_SET_ROAM_REQUEST_HOST_HW_MODE_CHANGE(roam_reason, status) \ + do { \ + (roam_reason) |= \ + (((status) << WMI_ROAM_REQUEST_HOST_HW_MODE_CHANGE_SHIFT) & \ + WMI_ROAM_REQUEST_HOST_HW_MODE_CHANGE_MASK); \ + } while (0) + +#define WMI_GET_ROAM_REQUEST_HOST_HW_MODE_CHANGE(roam_reason) \ + (((roam_reason) & WMI_ROAM_REQUEST_HOST_HW_MODE_CHANGE_MASK) >> \ + WMI_ROAM_REQUEST_HOST_HW_MODE_CHANGE_SHIFT) + +/* roaming notification */ +#define WMI_ROAM_NOTIF_INVALID 0x0 /** invalid notification. Do not interpret notif field */ +#define WMI_ROAM_NOTIF_ROAM_START 0x1 /** indicate that roaming is started. sent only in non WOW state */ +#define WMI_ROAM_NOTIF_ROAM_ABORT 0x2 /** indicate that roaming is aborted. sent only in non WOW state */ +#define WMI_ROAM_NOTIF_ROAM_REASSOC 0x3 /** indicate that reassociation is done. sent only in non WOW state */ +#define WMI_ROAM_NOTIF_SCAN_MODE_SUCCESS 0x4 /** indicate that roaming scan mode is successful */ +#define WMI_ROAM_NOTIF_SCAN_MODE_FAIL 0x5 /** indicate that roaming scan mode is failed due to internal roaming state */ + +/**whenever RIC request information change, host driver should pass all ric related information to firmware (now only support tsepc) +* Once, 11r roaming happens, firmware can generate RIC request in reassoc request based on these informations +*/ +typedef struct +{ + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_ric_request_fixed_param */ + A_UINT32 vdev_id; /**unique id identifying the VDEV, generated by the caller*/ + A_UINT32 num_ric_request; /**number of ric request ie send to firmware.(max value is 2 now)*/ + A_UINT32 is_add_ric; /**support add ric or delete ric*/ +} wmi_ric_request_fixed_param; + +/**tspec element: refer to 8.4.2.32 of 802.11 2012 spec +* these elements are used to construct tspec field in RIC request, which allow station to require specific TS when 11r roaming +*/ +typedef struct{ + A_UINT32 tlv_header; + A_UINT32 ts_info; /** bits value of TS Info field.*/ + A_UINT32 nominal_msdu_size; /**Nominal MSDU Size field*/ + A_UINT32 maximum_msdu_size; /**The Maximum MSDU Size field*/ + A_UINT32 min_service_interval; /**The Minimum Service Interval field*/ + A_UINT32 max_service_interval; /**The Maximum Service Interval field*/ + A_UINT32 inactivity_interval; /**The Inactivity Interval field*/ + A_UINT32 suspension_interval; /**The Suspension Interval field*/ + A_UINT32 svc_start_time; /**The Service Start Time field*/ + A_UINT32 min_data_rate; /**The Minimum Data Rate field*/ + A_UINT32 mean_data_rate; /**The Mean Data Rate field*/ + A_UINT32 peak_data_rate; /**The Peak Data Rate field*/ + A_UINT32 max_burst_size; /**The Burst Size field*/ + A_UINT32 delay_bound; /**The Delay Bound field*/ + A_UINT32 min_phy_rate; /**The Minimum PHY Rate field*/ + A_UINT32 surplus_bw_allowance; /**The Surplus Bandwidth Allowance field*/ + A_UINT32 medium_time; /**The Medium Time field,in units of 32 us/s.*/ +} wmi_ric_tspec; + +/* flags for roam_invoke_cmd */ +/* add this channel into roam cache channel list after this command is finished */ +#define WMI_ROAM_INVOKE_FLAG_ADD_CH_TO_CACHE 0 +/* indicate to host of failure if WMI_ROAM_INVOKE_CMDID. */ +#define WMI_ROAM_INVOKE_FLAG_REPORT_FAILURE 1 +/* during host-invoked roaming, don't send null data frame to AP */ +#define WMI_ROAM_INVOKE_FLAG_NO_NULL_FRAME_TO_AP 2 +/* from bit 3 to bit 31 are reserved */ + +#define WMI_SET_ROAM_INVOKE_ADD_CH_TO_CACHE(flag) do { \ + (flag) |= (1 << WMI_SET_ROAM_INVOKE_ADD_CH_TO_CACHE); \ + } while (0) + +#define WMI_CLEAR_ROAM_INVOKE_ADD_CH_TO_CACHE(flag) do { \ + (flag) &= ~(1 << WMI_SET_ROAM_INVOKE_ADD_CH_TO_CACHE); \ + } while (0) + +#define WMI_GET_ROAM_INVOKE_ADD_CH_TO_CACHE(flag) \ + ((flag) & (1 << WMI_SET_ROAM_INVOKE_ADD_CH_TO_CACHE)) + + +#define WMI_ROAM_INVOKE_SCAN_MODE_FIXED_CH 0 /* scan given channel only */ +#define WMI_ROAM_INVOKE_SCAN_MODE_CACHE_LIST 1 /* scan cached channel list */ +#define WMI_ROAM_INVOKE_SCAN_MODE_FULL_CH 2 /* scan full channel */ +#define WMI_ROAM_INVOKE_SCAN_MODE_SKIP 3 /* no scan is performed. use beacon/probe resp given by the host */ + +#define WMI_ROAM_INVOKE_AP_SEL_FIXED_BSSID 0 /* roam to given BSSID only */ +#define WMI_ROAM_INVOKE_AP_SEL_ANY_BSSID 1 /* roam to any BSSID */ + +/** WMI_ROAM_INVOKE_CMD: command to invoke roaming forcefully +* +if is zero and is not given, roaming is not executed. +if is zero and = 0 + = 0 + = 0 + |= WMI_ROAM_INVOKE_FLAG_ADD_CH_TO_CACHE + = do not fill (there will be no actual roaming because of ap_sel_mode is zero, but no BSSID is given) + = channel list to be added +*/ +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_roam_invoke_fixed_param */ + A_UINT32 vdev_id; /** Unique id identifying the VDEV on which roaming is invoked */ + A_UINT32 flags; /** flags. see WMI_ROAM_INVOKE_FLAG_ above */ + A_UINT32 roam_scan_mode; /** see WMI_ROAM_INVOKE_SCAN_ above */ + A_UINT32 roam_ap_sel_mode; /** see WMI_ROAM_INVOKE_AP_SEL_ above */ + A_UINT32 roam_delay; /** 0 = immediate roam, 1-2^32 = roam after this delay (msec) */ + A_UINT32 num_chan; /** # if channels to scan. In the TLV channel_list[] */ + A_UINT32 num_bssid; /** number of bssids. In the TLV bssid_list[] */ + A_UINT32 num_buf; /** number of buffers In the TLV bcn_prb_buf_list[] */ + /** + * TLV (tag length value) parameters follows roam_invoke_req + * The TLV's are: + * A_UINT32 channel_list[]; + * wmi_mac_addr bssid_list[]; + * wmi_tlv_buf_len_param bcn_prb_buf_list[]; + * A_UINT8 bcn_prb_frm[]; + */ +} wmi_roam_invoke_cmd_fixed_param; + +/* Definition for op_bitmap */ +enum { + ROAM_FILTER_OP_BITMAP_BLACK_LIST = 0x1, + ROAM_FILTER_OP_BITMAP_WHITE_LIST = 0x2, + ROAM_FILTER_OP_BITMAP_PREFER_BSSID = 0x4, + ROAM_FILTER_OP_BITMAP_LCA_DISALLOW = 0x8, + ROAM_FILTER_OP_BITMAP_RSSI_REJECTION_OCE = 0x10, +}; + +/** lca_enable_source_bitmap */ +#define WMI_ROAM_LCA_DISALLOW_SOURCE_PER 0x1 +#define WMI_ROAM_LCA_DISALLOW_SOURCE_BMISS 0x2 +#define WMI_ROAM_LCA_DISALLOW_SOURCE_LOW_RSSI 0x4 +#define WMI_ROAM_LCA_DISALLOW_SOURCE_HIGH_RSSI 0x8 +#define WMI_ROAM_LCA_DISALLOW_SOURCE_PERIODIC 0x10 +#define WMI_ROAM_LCA_DISALLOW_SOURCE_MAWC 0x20 /* MAWC = Motion Aided Wifi connectivity */ +#define WMI_ROAM_LCA_DISALLOW_SOURCE_DENSE 0x40 +#define WMI_ROAM_LCA_DISALLOW_SOURCE_BACKGROUND 0x80 +#define WMI_ROAM_LCA_DISALLOW_SOURCE_FORCED 0x100 + +typedef struct { + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_roam_rssi_rejection_oce_config_param */ + A_UINT32 tlv_header; + /** BSSID of AP, who reject (re-)assoc due to low RSSI */ + wmi_mac_addr bssid; + /** Disallowed AP for certain duration, in units of milliseconds */ + A_UINT32 remaining_disallow_duration; + /** AP will be allowed for candidate, when AP RSSI better than expected RSSI units in dBm */ + A_INT32 requested_rssi; +} wmi_roam_rssi_rejection_oce_config_param; + +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_roam_filter_list_fixed_param */ + A_UINT32 vdev_id; /** Unique id identifying the VDEV on which roaming filter is adopted */ + A_UINT32 flags; /** flags for filter */ + A_UINT32 op_bitmap; /** 32 bit bitmap to be set on. bit0 = first param, bit 1 = second param...etc. Can be or'ed */ + A_UINT32 num_bssid_black_list; /* number of blacklist in the TLV variable bssid_black_list */ + A_UINT32 num_ssid_white_list; /* number of whitelist in the TLV variable ssid_white_list */ + A_UINT32 num_bssid_preferred_list; /* only for lfr 3.0. number of preferred list & factor in the TLV */ + A_UINT32 num_rssi_rejection_ap; /** number of list of AP who rejected STA due to low RSSI */ + /** + * TLV (tag length value) parameters follows roam_filter_list_cmd + * The TLV's are: + * wmi_mac_addr bssid_black_list[]; + * wmi_ssid ssid_white_list[]; + * wmi_mac_addr bssid_preferred_list[]; + * A_UINT32 bssid_preferred_factor[]; + * wmi_roam_lca_disallow_config_tlv_param lca_disallow_param[0/1] (opt) + * wmi_roam_rssi_rejection_oce_config_param rssi_rejection_list[] + */ +} wmi_roam_filter_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_roam_lca_disallow_config_tlv_param */ + A_UINT32 disallow_duration; /** How long LCA AP will be disallowed before it can be a roaming candidate again, in units of seconds */ + A_UINT32 rssi_channel_penalization; /** How much RSSI will be penalized if candidate(s) are found in the same channel as disallowed AP's, in units of db */ + A_UINT32 num_disallowed_aps; /** How many APs the target should maintain in its LCA (Last Connected AP) list */ + A_UINT32 disallow_lca_enable_source_bitmap; /** disallow LCA logic is enabled only when trigger sources are matched with corresponding bit (see WMI_ROAM_LCA_DISALLOW_SOURCE constants) */ +} wmi_roam_lca_disallow_config_tlv_param; + +typedef struct { + A_UINT8 address[4]; /* IPV4 address in Network Byte Order */ +} WMI_IPV4_ADDR; + +typedef struct _WMI_IPV6_ADDR { + A_UINT8 address[16]; /* IPV6 in Network Byte Order */ +} WMI_IPV6_ADDR; + +/* flags for subnet change detection */ +#define WMI_ROAM_SUBNET_CHANGE_FLAG_IP4_ENABLED 0 +#define WMI_ROAM_SUBNET_CHANGE_FLAG_IP6_ENABLED 1 +/* bit 2 to bit 31 are reserved */ + +/* set IPv4 enabled/disabled flag and get the flag */ +#define WMI_SET_ROAM_SUBNET_CHANGE_FLAG_IP4_ENABLED(flag) do { \ + (flag) |= (1 << WMI_ROAM_SUBNET_CHANGE_FLAG_IP4_ENABLED); \ +} while (0) + +#define WMI_SET_ROAM_SUBNET_CHANGE_FLAG_IP4_DISABLED(flag) do { \ + (flag) &= ~(1 << WMI_ROAM_SUBNET_CHANGE_FLAG_IP4_ENABLED); \ +} while (0) + +#define WMI_GET_ROAM_SUBNET_CHANGE_FLAG_IP4_ENABLED(flag) \ + ((flag) & (1 << WMI_ROAM_SUBNET_CHANGE_FLAG_IP4_ENABLED)) + +/* set IPv6 enabled flag, disabled and get the flag */ +#define WMI_SET_ROAM_SUBNET_CHANGE_FLAG_IP6_ENABLED(flag) do { \ + (flag) |= (1 << WMI_ROAM_SUBNET_CHANGE_FLAG_IP6_ENABLED); \ +} while (0) + +#define WMI_SET_ROAM_SUBNET_CHANGE_FLAG_IP6_DISABLED(flag) do { \ + (flag) &= ~(1 << WMI_ROAM_SUBNET_CHANGE_FLAG_IP6_ENABLED); \ +} while (0) + +#define WMI_GET_ROAM_SUBNET_CHANGE_FLAG_IP6_ENABLED(flag) \ + ((flag) & (1 << WMI_ROAM_SUBNET_CHANGE_FLAG_IP6_ENABLED)) + +/** + * WMI_ROAM_SUBNET_CHANGE_CONFIG : Pass the gateway IP and MAC addresses + * to FW. FW uses these parameters for subnet change detection. + */ +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_roam_subnet_change_config_fixed_param */ + /** unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; + /** IPv4/IPv6 enabled/disabled */ + /** This flag sets the WMI_SET_ROAM_SUBNET_CHANGE_FLAG_xxx_ENABLED/DISABLED */ + A_UINT32 flag; + /** Gateway MAC address */ + wmi_mac_addr inet_gw_mac_addr; + /** IP addresses */ + WMI_IPV4_ADDR inet_gw_ip_v4_addr; + WMI_IPV6_ADDR inet_gw_ip_v6_addr; + /** Number of software retries for ARP/Neighbor solicitation request */ + A_UINT32 max_retries; + /** timeout in milliseconds for each ARP request*/ + A_UINT32 timeout; + /** number of skipped aps **/ + A_UINT32 num_skip_subnet_change_detection_bssid_list; +/** + * TLV (tag length value) parameters follows roam_subnet_change_config_cmd + * structure. The TLV's are: + * wmi_mac_addr skip_subnet_change_detection_bssid_list []; + **/ +} wmi_roam_subnet_change_config_fixed_param; + +/** WMI_PROFILE_MATCH_EVENT: offload scan + * generated when ever atleast one of the matching profiles is found + * in recent NLO scan. no data is carried with the event. + */ + +/** P2P specific commands */ + +/** + * WMI_P2P_DEV_SET_DEVICE_INFO : p2p device info, which will be used by + * FW to generate P2P IE tobe carried in probe response frames. + * FW will respond to probe requests while in listen state. + */ +typedef struct { + /* number of secondary device types,supported */ + A_UINT32 num_secondary_dev_types; +/** + * followed by 8 bytes of primary device id and + * num_secondary_dev_types * 8 bytes of secondary device + * id. + */ +} wmi_p2p_dev_set_device_info; + +/** WMI_P2P_DEV_SET_DISCOVERABILITY: enable/disable discoverability + * state. if enabled, an active STA/AP will respond to P2P probe requests on + * the operating channel of the VDEV. + */ + +typedef struct { + /* 1:enable disoverability, 0:disable discoverability */ + A_UINT32 enable_discoverability; +} wmi_p2p_set_discoverability; + +/** WMI_P2P_GO_SET_BEACON_IE: P2P IE to be added to + * beacons generated by FW. used in FW beacon mode. + * the FW will add this IE to beacon in addition to the beacon + * template set by WMI_BCN_TMPL_CMDID command. + */ +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_p2p_go_set_beacon_ie_fixed_param */ + /** unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; + /* ie length */ + A_UINT32 ie_buf_len; +/* Following this structure is the TLV byte stream of ie data of length ie_buf_len: + * A_UINT8 ie_data[]; <-- length in byte given by field num_data. + */ + +} wmi_p2p_go_set_beacon_ie_fixed_param; + +/** WMI_P2P_GO_PROBE_RESP_IE: P2P IE to be added to + * probe response generated by FW. used in FW beacon mode. + * the FW will add this IE to probe response in addition to the probe response + * template set by WMI_PRB_TMPL_CMDID command. + */ +typedef struct { + /** unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; + /* ie length */ + A_UINT32 ie_buf_len; +/*followed by byte stream of ie data of length ie_buf_len */ +} wmi_p2p_go_set_probe_resp_ie; + +/** WMI_P2P_SET_VENDOR_IE_DATA_CMDID: Vendor specific P2P IE data, which will + * be used by the FW to parse the P2P NoA attribute in beacons, probe resposes + * and action frames received by the P2P Client. + * Note: This command is currently used only for Apple P2P implementation. + */ +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_p2p_set_vendor_ie_data_cmd_fixed_param */ + /** OS specific P2P IE OUI (3 bytes) + OUI type (1 byte) */ + A_UINT32 p2p_ie_oui_type; + /** OS specific NoA Attribute ID */ + A_UINT32 p2p_noa_attribute; +} wmi_p2p_set_vendor_ie_data_cmd_fixed_param; + +/*----P2P disc offload definition ----*/ + +typedef struct { + A_UINT32 pattern_type; +/** + * TLV (tag length value) paramerters follow the pattern structure. + * TLV can contain bssid list, ssid list and + * ie. the TLV tags are defined above; + */ +} wmi_p2p_disc_offload_pattern_cmd; + +typedef struct { + /* unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; + /* mgmt type of the ie*/ + A_UINT32 mgmt_type; + /* ie length */ + A_UINT32 ie_buf_len; +/*followed by byte stream of ie data of length ie_buf_len */ +} wmi_p2p_disc_offload_appie_cmd; + +typedef struct { + /* enable/disable p2p find offload*/ + A_UINT32 enable; + /* unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; + /* p2p find type */ + A_UINT32 disc_type; + /* p2p find perodic */ + A_UINT32 perodic; + /* p2p find listen channel */ + A_UINT32 listen_channel; + /* p2p find full channel number */ + A_UINT32 num_scan_chans; +/** + * TLV (tag length value) paramerters follow the pattern structure. + * TLV contain channel list + */ +} wmi_p2p_disc_offload_config_cmd; + +/*----P2P OppPS definition ----*/ +typedef struct { + /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_p2p_set_oppps_cmd_fixed_param */ + A_UINT32 tlv_header; + /* unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; + /* OppPS attributes */ + /** Bit 0: Indicate enable/disable of OppPS + * Bits 7-1: Ctwindow in TUs + * Bits 31-8: Reserved + */ + A_UINT32 oppps_attr; +} wmi_p2p_set_oppps_cmd_fixed_param; + +#define WMI_UNIFIED_OPPPS_ATTR_ENALBED 0x1 +#define WMI_UNIFIED_OPPPS_ATTR_ENALBED_S 0 + +#define WMI_UNIFIED_OPPPS_ATTR_IS_ENABLED(hdr) \ + WMI_F_MS((hdr)->oppps_attr, WMI_UNIFIED_OPPPS_ATTR_ENALBED) + +#define WMI_UNIFIED_OPPPS_ATTR_ENABLED_SET(hdr) \ + WMI_F_RMW((hdr)->oppps_attr, 0x1, \ + WMI_UNIFIED_OPPPS_ATTR_ENALBED); + +#define WMI_UNIFIED_OPPPS_ATTR_CTWIN 0xfe +#define WMI_UNIFIED_OPPPS_ATTR_CTWIN_S 1 + +#define WMI_UNIFIED_OPPPS_ATTR_CTWIN_GET(hdr) \ + WMI_F_MS((hdr)->oppps_attr, WMI_UNIFIED_OPPPS_ATTR_CTWIN) + +#define WMI_UNIFIED_OPPPS_ATTR_CTWIN_SET(hdr, v) \ + WMI_F_RMW((hdr)->oppps_attr, (v) & 0x7f, \ + WMI_UNIFIED_OPPPS_ATTR_CTWIN); + +typedef enum p2p_lo_start_ctrl_flags_e { + P2P_LO_START_CTRL_FLAG_FLUSH_LISTEN_RESULT = 1 << 0, /* flush prob. req when host is awake */ +} p2p_lo_start_ctrl_flags; + +#define P2P_LO_PER_DEV_TYPE_LEN 8 +#define P2P_LO_DEV_TYPES_COUNT_MAX 10 +#define P2P_LO_DEV_TYPES_LEN_MAX (P2P_LO_PER_DEV_TYPE_LEN * P2P_LO_DEV_TYPES_COUNT_MAX) +#define P2P_LO_PROB_RESP_MAX_LEN 512 + +typedef struct { + A_UINT32 tlv_header; + A_UINT32 vdev_id; + A_UINT32 ctl_flags; /* refer to enum_p2p_lo_start_ctrl_flags_e */ + A_UINT32 channel; /* MHz */ + A_UINT32 period; /* ms */ + A_UINT32 interval; /* ms, interval should be larger than period */ + A_UINT32 count; /* 0 means forever */ + /* + * device_types_len specifies the number of bytes in the + * device_types_data[] byte-array TLV that follows this TLV. + * The data in device_types_data[] is in 8-byte elements, so + * device_types_len will be a multiple of 8. + * Refer to P2P_LO_DEV_TYPES_LEN_MAX + */ + A_UINT32 device_types_len; + /* + * prob_resp_len specifies the number of bytes in the + * prob_resp_data[] byte-array TLV that follows this TLV. + * Refer to P2P_LO_PROB_RESP_MAX_LEN + */ + A_UINT32 prob_resp_len; + /* + * Two other TLVs follow this TLV: + * A_UINT8 device_types_data[device_types_len]; + * A_UINT8 prob_resp_data[prob_resp_len]; + * The information in device_types_data[] and prob_resp_data[] + * needs to be provided to the target in over-the-air byte order. + * On a big-endian host, if device_types_data and prob_resp_data + * are initially in the correct over-the-air byte order, + * the automatic byteswap for endianness-correction during WMI + * message download will mess up the byte order. + * Thus, a big-endian host needs to explicitly byte-swap the bytes + * within each quad-byte segment of device_types_data[] and + * prob_resp_data[], so that the automatic byte-swap applied during + * WMI download from a big-endian host to the little-endian target + * will restore device_types_data and prob_resp_data into the + * correct byte ordering. + */ +} wmi_p2p_lo_start_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; + A_UINT32 vdev_id; +} wmi_p2p_lo_stop_cmd_fixed_param; + +typedef enum p2p_lo_stopped_reason_e { + P2P_LO_STOPPED_REASON_COMPLETE = 0, /* finished as scheduled */ + P2P_LO_STOPPED_REASON_RECV_STOP_CMD, /* host stops it */ + P2P_LO_STOPPED_REASON_INVALID_LO_PAR, /* invalid listen offload par */ + P2P_LO_STOPPED_REASON_FW_NOT_SUPPORT, /* vdev cannot support it right now */ +} p2p_lo_stopped_reason; + +typedef struct { + A_UINT32 tlv_header; + A_UINT32 vdev_id; + A_UINT32 reason;/* refer to p2p_lo_stopped_reason_e */ +} wmi_p2p_lo_stopped_event_fixed_param; + +typedef enum { + WMI_MNT_FILTER_CONFIG_MANAGER, + WMI_MNT_FILTER_CONFIG_CONTROL, + WMI_MNT_FILTER_CONFIG_DATA, + WMI_MNT_FILTER_CONFIG_ALL, + WMI_MNT_FILTER_CONFIG_UNKNOWN, +} WMI_MNT_FILTER_CONFIG_TYPE; + +typedef struct { + A_UINT32 tlv_header; + A_UINT32 vdev_id; + A_UINT32 clear_or_set; + A_UINT32 configure_type; /* see WMI_MNT_FILTER_CONFIG_TYPE */ +} wmi_mnt_filter_cmd_fixed_param; + +typedef struct { + A_UINT32 time32; /* upper 32 bits of time stamp */ + A_UINT32 time0; /* lower 32 bits of time stamp */ +} A_TIME64; + +typedef enum wmi_peer_sta_kickout_reason { + WMI_PEER_STA_KICKOUT_REASON_UNSPECIFIED = 0, /* default value to preserve legacy behavior */ + WMI_PEER_STA_KICKOUT_REASON_XRETRY = 1, + WMI_PEER_STA_KICKOUT_REASON_INACTIVITY = 2, + WMI_PEER_STA_KICKOUT_REASON_IBSS_DISCONNECT = 3, + WMI_PEER_STA_KICKOUT_REASON_TDLS_DISCONNECT = 4, /* TDLS peer has disappeared. All tx is failing */ + WMI_PEER_STA_KICKOUT_REASON_SA_QUERY_TIMEOUT = 5, +} PEER_KICKOUT_REASON; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_peer_sta_kickout_event_fixed_param */ + /** peer mac address */ + wmi_mac_addr peer_macaddr; + /** Reason code, defined as above */ + A_UINT32 reason; + /** RSSI of the last bcn (averaged) in dB. 0 means Noise Floor value */ + A_UINT32 rssi; +} wmi_peer_sta_kickout_event_fixed_param; + +#define WMI_WLAN_PROFILE_MAX_HIST 3 +#define WMI_WLAN_PROFILE_MAX_BIN_CNT 32 + +typedef struct _wmi_wlan_profile_t { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_wlan_profile_t */ + A_UINT32 id; + A_UINT32 cnt; + A_UINT32 tot; + A_UINT32 min; + A_UINT32 max; + A_UINT32 hist_intvl; + A_UINT32 hist[WMI_WLAN_PROFILE_MAX_HIST]; +} wmi_wlan_profile_t; + +typedef struct _wmi_wlan_profile_ctx_t { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_wlan_profile_ctx_t */ + A_UINT32 tot; /* time in us */ + A_UINT32 tx_msdu_cnt; + A_UINT32 tx_mpdu_cnt; + A_UINT32 tx_ppdu_cnt; + A_UINT32 rx_msdu_cnt; + A_UINT32 rx_mpdu_cnt; + A_UINT32 bin_count; +} wmi_wlan_profile_ctx_t; + + +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_wlan_profile_trigger_cmd_fixed_param */ + A_UINT32 enable; +} wmi_wlan_profile_trigger_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_wlan_profile_get_prof_data_cmd_fixed_param */ + A_UINT32 value; +} wmi_wlan_profile_get_prof_data_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_wlan_profile_set_hist_intvl_cmd_fixed_param */ + A_UINT32 profile_id; + A_UINT32 value; +} wmi_wlan_profile_set_hist_intvl_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_wlan_profile_enable_profile_id_cmd_fixed_param */ + A_UINT32 profile_id; + A_UINT32 enable; +} wmi_wlan_profile_enable_profile_id_cmd_fixed_param; + +/*Wifi header is upto 26, LLC is 8, with 14 byte duplicate in 802.3 header, that's 26+8-14=20. + 146-128=18. So this means it is converted to non-QoS header. Riva FW take care of the QOS/non-QOS + when comparing wifi header.*/ +/* NOTE: WOW_DEFAULT_BITMAP_PATTERN_SIZE(_DWORD) and WOW_DEFAULT_BITMASK_SIZE(_DWORD) can't be changed without breaking the compatibility */ +#define WOW_DEFAULT_BITMAP_PATTERN_SIZE 146 +#define WOW_DEFAULT_BITMAP_PATTERN_SIZE_DWORD 37 /* Convert WOW_DEFAULT_EVT_BUF_SIZE into Int32 size */ +#define WOW_DEFAULT_BITMASK_SIZE 146 +#define WOW_DEFAULT_BITMASK_SIZE_DWORD 37 +#define WOW_MAX_BITMAP_FILTERS 32 +#define WOW_DEFAULT_MAGIG_PATTERN_MATCH_CNT 16 +#define WOW_EXTEND_PATTERN_MATCH_CNT 16 +#define WOW_SHORT_PATTERN_MATCH_CNT 8 +#define WOW_DEFAULT_EVT_BUF_SIZE 148 /* Maximum 148 bytes of the data is copied starting from header incase if the match is found. + The 148 comes from (128 - 14) payload size + 8bytes LLC + 26bytes MAC header*/ +#define WOW_DEFAULT_IOAC_PATTERN_SIZE 6 +#define WOW_DEFAULT_IOAC_PATTERN_SIZE_DWORD 2 +#define WOW_DEFAULT_IOAC_RANDOM_SIZE 6 +#define WOW_DEFAULT_IOAC_RANDOM_SIZE_DWORD 2 +#define WOW_DEFAULT_IOAC_KEEP_ALIVE_PKT_SIZE 120 +#define WOW_DEFAULT_IOAC_KEEP_ALIVE_PKT_SIZE_DWORD 30 +#define WOW_DEFAULT_IOAC_SOCKET_PATTERN_SIZE 32 +#define WOW_DEFAULT_IOAC_SOCKET_PATTERN_SIZE_DWORD 8 +#define WOW_DEFAULT_IOAC_KEEP_ALIVE_PKT_REV_SIZE 32 +#define WOW_DEFAULT_IOAC_KEEP_ALIVE_PKT_REV_SIZE_DWORD 8 +#define WOW_DEFAULT_IOAC_SOCKET_PATTERN_ACKNAK_SIZE 128 +#define WOW_DEFAULT_IOAC_SOCKET_PATTERN_ACKNAK_SIZE_DWORD 32 + +typedef enum pattern_type_e { + WOW_PATTERN_MIN = 0, + WOW_BITMAP_PATTERN = WOW_PATTERN_MIN, + WOW_IPV4_SYNC_PATTERN, + WOW_IPV6_SYNC_PATTERN, + WOW_WILD_CARD_PATTERN, + WOW_TIMER_PATTERN, + WOW_MAGIC_PATTERN, + WOW_IPV6_RA_PATTERN, + WOW_IOAC_PKT_PATTERN, + WOW_IOAC_TMR_PATTERN, + WOW_IOAC_SOCK_PATTERN, + WOW_PATTERN_MAX +} WOW_PATTERN_TYPE; + +typedef enum event_type_e { + WOW_BMISS_EVENT = 0, + WOW_BETTER_AP_EVENT, + WOW_DEAUTH_RECVD_EVENT, + WOW_MAGIC_PKT_RECVD_EVENT, + WOW_GTK_ERR_EVENT, + WOW_FOURWAY_HSHAKE_EVENT, + WOW_EAPOL_RECVD_EVENT, + WOW_NLO_DETECTED_EVENT, + WOW_DISASSOC_RECVD_EVENT, + WOW_PATTERN_MATCH_EVENT, + WOW_CSA_IE_EVENT, + WOW_PROBE_REQ_WPS_IE_EVENT, + WOW_AUTH_REQ_EVENT, + WOW_ASSOC_REQ_EVENT, + WOW_HTT_EVENT, + WOW_RA_MATCH_EVENT, + WOW_HOST_AUTO_SHUTDOWN_EVENT, + WOW_IOAC_MAGIC_EVENT, + WOW_IOAC_SHORT_EVENT, + WOW_IOAC_EXTEND_EVENT, + WOW_IOAC_TIMER_EVENT, + WOW_DFS_PHYERR_RADAR_EVENT, + WOW_BEACON_EVENT, + WOW_CLIENT_KICKOUT_EVENT, + WOW_NAN_EVENT, + WOW_EXTSCAN_EVENT, + WOW_IOAC_REV_KA_FAIL_EVENT, + WOW_IOAC_SOCK_EVENT, + WOW_NLO_SCAN_COMPLETE_EVENT, + WOW_NAN_DATA_EVENT, + WOW_NAN_RTT_EVENT, /* DEPRECATED, UNUSED */ + WOW_OEM_RESPONSE_EVENT = WOW_NAN_RTT_EVENT, /* reuse deprecated event value */ + WOW_TDLS_CONN_TRACKER_EVENT, + WOW_CRITICAL_LOG_EVENT, + WOW_CHIP_POWER_FAILURE_DETECT_EVENT, + WOW_11D_SCAN_EVENT, +} WOW_WAKE_EVENT_TYPE; + +typedef enum wake_reason_e { + WOW_REASON_UNSPECIFIED = -1, + WOW_REASON_NLOD = 0, + WOW_REASON_AP_ASSOC_LOST, + WOW_REASON_LOW_RSSI, + WOW_REASON_DEAUTH_RECVD, + WOW_REASON_DISASSOC_RECVD, + WOW_REASON_GTK_HS_ERR, + WOW_REASON_EAP_REQ, + WOW_REASON_FOURWAY_HS_RECV, + WOW_REASON_TIMER_INTR_RECV, + WOW_REASON_PATTERN_MATCH_FOUND, + WOW_REASON_RECV_MAGIC_PATTERN, + WOW_REASON_P2P_DISC, + WOW_REASON_WLAN_HB, + WOW_REASON_CSA_EVENT, + WOW_REASON_PROBE_REQ_WPS_IE_RECV, + WOW_REASON_AUTH_REQ_RECV, + WOW_REASON_ASSOC_REQ_RECV, + WOW_REASON_HTT_EVENT, + WOW_REASON_RA_MATCH, + WOW_REASON_HOST_AUTO_SHUTDOWN, + WOW_REASON_IOAC_MAGIC_EVENT, + WOW_REASON_IOAC_SHORT_EVENT, + WOW_REASON_IOAC_EXTEND_EVENT, + WOW_REASON_IOAC_TIMER_EVENT, + WOW_REASON_ROAM_HO, + WOW_REASON_DFS_PHYERR_RADADR_EVENT, + WOW_REASON_BEACON_RECV, + WOW_REASON_CLIENT_KICKOUT_EVENT, + WOW_REASON_NAN_EVENT, + WOW_REASON_EXTSCAN, + WOW_REASON_RSSI_BREACH_EVENT, + WOW_REASON_IOAC_REV_KA_FAIL_EVENT, + WOW_REASON_IOAC_SOCK_EVENT, + WOW_REASON_NLO_SCAN_COMPLETE, + WOW_REASON_PACKET_FILTER_MATCH, + WOW_REASON_ASSOC_RES_RECV, + WOW_REASON_REASSOC_REQ_RECV, + WOW_REASON_REASSOC_RES_RECV, + WOW_REASON_ACTION_FRAME_RECV, + WOW_REASON_BPF_ALLOW, + WOW_REASON_NAN_DATA, + WOW_REASON_NAN_RTT, /* DEPRECATED, UNUSED */ + WOW_REASON_OEM_RESPONSE_EVENT = WOW_REASON_NAN_RTT, /* reuse deprecated reason value */ + WOW_REASON_TDLS_CONN_TRACKER_EVENT, + WOW_REASON_CRITICAL_LOG, + WOW_REASON_P2P_LISTEN_OFFLOAD, + WOW_REASON_NAN_EVENT_WAKE_HOST, + WOW_REASON_CHIP_POWER_FAILURE_DETECT, + WOW_REASON_11D_SCAN, + WOW_REASON_THERMAL_CHANGE, + WOW_REASON_DEBUG_TEST = 0xFF, +} WOW_WAKE_REASON_TYPE; + + +typedef enum { + WOW_IFACE_PAUSE_ENABLED, + WOW_IFACE_PAUSE_DISABLED +} WOW_IFACE_STATUS; + +enum { + WMI_WOW_FLAG_IGNORE_PCIE_RESET = 0x00000001, /* some win10 platfrom will not assert pcie_reset for wow.*/ + /* WMI_WOW_FLAG_SEND_PM_PME + * Some platforms have issues if the PM_PME message is sent after WoW, + * so don't send PM_PME after WoW unless the host uses this flag + * to request it. + */ + WMI_WOW_FLAG_SEND_PM_PME = 0x00000002, + /* Flag to indicate unit test */ + WMI_WOW_FLAG_UNIT_TEST_ENABLE = 0x00000004, + /* Force HTC wakeup */ + WMI_WOW_FLAG_DO_HTC_WAKEUP = 0x00000008, + /* Enable L1SS sleep for PCIE DRV case */ + WMI_WOW_FLAG_ENABLE_DRV_PCIE_L1SS_SLEEP = 0x00000010, +}; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_wow_enable_cmd_fixed_param */ + A_UINT32 enable; + A_UINT32 pause_iface_config; + A_UINT32 flags; /* WMI_WOW_FLAG enums */ +} wmi_wow_enable_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_wow_hostwakeup_from_sleep_cmd_fixed_param */ + /** Reserved for future use */ + A_UINT32 reserved0; +} wmi_wow_hostwakeup_from_sleep_cmd_fixed_param; + +#define WOW_ICMPV6_NA_FILTER_DISABLE 0 +#define WOW_ICMPV6_NA_FILTER_ENABLE 1 + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_wow_enable_icmpv6_na_flt_cmd_fixed_param */ + A_UINT32 vdev_id; + A_UINT32 enable; /* WOW_ICMPV6_NA_FILTER_ENABLE/DISABLE */ +} wmi_wow_enable_icmpv6_na_flt_cmd_fixed_param; + +typedef struct bitmap_pattern_s { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_WOW_BITMAP_PATTERN_T */ + A_UINT32 patternbuf[WOW_DEFAULT_BITMAP_PATTERN_SIZE_DWORD]; + A_UINT32 bitmaskbuf[WOW_DEFAULT_BITMASK_SIZE_DWORD]; + A_UINT32 pattern_offset; + A_UINT32 pattern_len; + A_UINT32 bitmask_len; + A_UINT32 pattern_id; /* must be less than max_bitmap_filters */ +} WOW_BITMAP_PATTERN_T; + +typedef struct ipv4_sync_s { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_WOW_IPV4_SYNC_PATTERN_T */ + A_UINT32 ipv4_src_addr; + A_UINT32 ipv4_dst_addr; + A_UINT32 tcp_src_prt; + A_UINT32 tcp_dst_prt; +} WOW_IPV4_SYNC_PATTERN_T; + +typedef struct ipv6_sync_s { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_WOW_IPV6_SYNC_PATTERN_T */ + A_UINT32 ipv6_src_addr[4]; + A_UINT32 ipv6_dst_addr[4]; + A_UINT32 tcp_src_prt; + A_UINT32 tcp_dst_prt; +} WOW_IPV6_SYNC_PATTERN_T; + +typedef struct WOW_MAGIC_PATTERN_CMD +{ + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_WOW_MAGIC_PATTERN_CMD */ + wmi_mac_addr macaddr; +} WOW_MAGIC_PATTERN_CMD; + +typedef enum wow_ioac_pattern_type { + WOW_IOAC_MAGIC_PATTERN = 1, + WOW_IOAC_SHORT_PATTERN, + WOW_IOAC_EXTEND_PATTERN, +} WOW_IOAC_PATTERN_TYPE; + +typedef struct ioac_sock_pattern_s { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_WOW_IOAC_SOCK_PATTERN_T */ + A_UINT32 id; + A_UINT32 local_ipv4; + A_UINT32 remote_ipv4; + A_UINT32 local_port; + A_UINT32 remote_port; + A_UINT32 pattern_len; /* units = bytes */ + A_UINT32 pattern[WOW_DEFAULT_IOAC_SOCKET_PATTERN_SIZE_DWORD]; + WMI_IPV6_ADDR local_ipv6; + WMI_IPV6_ADDR remote_ipv6; + A_UINT32 ack_nak_len; + A_UINT32 ackpkt[WOW_DEFAULT_IOAC_SOCKET_PATTERN_ACKNAK_SIZE_DWORD]; + A_UINT32 nakpkt[WOW_DEFAULT_IOAC_SOCKET_PATTERN_ACKNAK_SIZE_DWORD]; +} WOW_IOAC_SOCK_PATTERN_T; + +typedef struct ioac_pkt_pattern_s { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_WOW_IOAC_PKT_PATTERN_T */ + A_UINT32 pattern_type; + A_UINT32 pattern[WOW_DEFAULT_IOAC_PATTERN_SIZE_DWORD]; + A_UINT32 random[WOW_DEFAULT_IOAC_RANDOM_SIZE_DWORD]; + A_UINT32 pattern_len; + A_UINT32 random_len; +} WOW_IOAC_PKT_PATTERN_T; + +typedef struct ioac_tmr_pattern_s { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_WOW_IOAC_TMR_PATTERN_T */ + A_UINT32 wake_in_s; + A_UINT32 vdev_id; +} WOW_IOAC_TMR_PATTERN_T; + +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_WMI_WOW_IOAC_ADD_KEEPALIVE_CMD_fixed_param */ + A_UINT32 nID; +} WMI_WOW_IOAC_ADD_KEEPALIVE_CMD_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_WMI_WOW_IOAC_DEL_KEEPALIVE_CMD_fixed_param */ + A_UINT32 nID; +} WMI_WOW_IOAC_DEL_KEEPALIVE_CMD_fixed_param; + +typedef struct ioac_keepalive_s { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_WMI_WOW_IOAC_KEEPALIVE_T */ + A_UINT32 keepalive_pkt_buf[WOW_DEFAULT_IOAC_KEEP_ALIVE_PKT_SIZE_DWORD]; + A_UINT32 keepalive_pkt_len; + A_UINT32 period_in_ms; + A_UINT32 vdev_id; + A_UINT32 max_loss_cnt; + A_UINT32 local_ipv4; + A_UINT32 remote_ipv4; + A_UINT32 local_port; + A_UINT32 remote_port; + A_UINT32 recv_period_in_ms; + A_UINT32 rev_ka_size; + A_UINT32 rev_ka_data[WOW_DEFAULT_IOAC_KEEP_ALIVE_PKT_REV_SIZE_DWORD]; + WMI_IPV6_ADDR local_ipv6; + WMI_IPV6_ADDR remote_ipv6; +} WMI_WOW_IOAC_KEEPALIVE_T; + +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_WMI_WOW_IOAC_ADD_PATTERN_CMD_fixed_param */ + A_UINT32 vdev_id; + A_UINT32 pattern_type; +/* + * Following this struct are these TLVs. Note that they are all array of structures + * but can have at most one element. Which TLV is empty or has one element depends + * on the field pattern_type. This is to emulate an union. + * WOW_IOAC_PKT_PATTERN_T pattern_info_pkt[]; + * WOW_IOAC_TMR_PATTERN_T pattern_info_tmr[]; + */ +} WMI_WOW_IOAC_ADD_PATTERN_CMD_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_WMI_WOW_IOAC_DEL_PATTERN_CMD_fixed_param */ + A_UINT32 vdev_id; + A_UINT32 pattern_type; + A_UINT32 pattern_id; +} WMI_WOW_IOAC_DEL_PATTERN_CMD_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_WMI_WOW_ADD_PATTERN_CMD_fixed_param */ + A_UINT32 vdev_id; + A_UINT32 pattern_id; + A_UINT32 pattern_type; +/* + * Following this struct are these TLVs. Note that they are all array of structures + * but can have at most one element. Which TLV is empty or has one element depends + * on the field pattern_type. This is to emulate an union. + * WOW_BITMAP_PATTERN_T pattern_info_bitmap[]; + * WOW_IPV4_SYNC_PATTERN_T pattern_info_ipv4[]; + * WOW_IPV6_SYNC_PATTERN_T pattern_info_ipv6[]; + * WOW_MAGIC_PATTERN_CMD pattern_info_magic_pattern[]; + * A_UINT32 pattern_info_timeout[]; + * A_UINT32 ra_ratelimit_interval; + */ +} WMI_WOW_ADD_PATTERN_CMD_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_WMI_WOW_DEL_PATTERN_CMD_fixed_param */ + A_UINT32 vdev_id; + A_UINT32 pattern_id; + A_UINT32 pattern_type; +} WMI_WOW_DEL_PATTERN_CMD_fixed_param; + +#define WMI_WOW_MAX_EVENT_BM_LEN 4 + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_WMI_WOW_ADD_DEL_EVT_CMD_fixed_param */ + A_UINT32 vdev_id; + A_UINT32 is_add; + union { + A_UINT32 event_bitmap; + A_UINT32 event_bitmaps[WMI_WOW_MAX_EVENT_BM_LEN]; + }; +} WMI_WOW_ADD_DEL_EVT_CMD_fixed_param; + +/* + * This structure is used to set the pattern to check UDP packet in WOW mode. + * If match, construct a tx frame in a local buffer to send through the peer + * AP to the entity in the IP network that sent the UDP packet to this STA. + */ +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_WMI_WOW_UDP_SVC_OFLD_CMD_fixed_param */ + A_UINT32 vdev_id; + A_UINT32 enable; /* 1: enable, 0: disable*/ + /* dest_port - + * bits 7:0 contain the LSB of the UDP dest port, + * bits 15:8 contain the MSB of the UDP dest port + */ + A_UINT32 dest_port; + A_UINT32 pattern_len; /* length in byte of pattern[] */ + A_UINT32 response_len; /* length in byte of response[] */ +/* Following this struct are the TLV's: + * A_UINT8 pattern[]; <-- payload of UDP packet to be checked, network byte order + * A_UINT8 response[]; <-- payload of UDP packet to be response, network byte order + */ +} WMI_WOW_UDP_SVC_OFLD_CMD_fixed_param; + +/* + * This structure is used to set the pattern for WOW host wakeup pin pulse pattern confirguration. + */ +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_WMI_WOW_HOSTWAKEUP_PIN_PATTERN_CONFIG_CMD_fixed_param */ + A_UINT32 enable; /* 1: enable, 0: disable */ + A_UINT32 pin; /* pin for host wakeup */ + A_UINT32 interval_low; /* interval for keeping low voltage, unit: ms */ + A_UINT32 interval_high; /* interval for keeping high voltage, unit: ms */ + A_UINT32 repeat_cnt; /* repeat times for pulse (0xffffffff means forever) */ +} WMI_WOW_HOSTWAKEUP_GPIO_PIN_PATTERN_CONFIG_CMD_fixed_param; + +#define MAX_SUPPORTED_ACTION_CATEGORY 256 +#define MAX_SUPPORTED_ACTION_SUBCATEGORY 32 +#define MAX_SUPPORTED_ACTION_CATEGORY_ELE_LIST (MAX_SUPPORTED_ACTION_CATEGORY/32) + +typedef enum { + WOW_ACTION_WAKEUP_OPERATION_RESET = 0, + WOW_ACTION_WAKEUP_OPERATION_SET, + WOW_ACTION_WAKEUP_OPERATION_ADD_SET, + WOW_ACTION_WAKEUP_OPERATION_DELETE_SET, +} WOW_ACTION_WAKEUP_OPERATION; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_WMI_WOW_SET_ACTION_WAKE_UP_CMD_fixed_param */ + A_UINT32 vdev_id; + A_UINT32 operation; /* 0 reset to fw default, 1 set the bits, 2 add the setting bits, 3 delete the setting bits */ + A_UINT32 action_category_map[MAX_SUPPORTED_ACTION_CATEGORY_ELE_LIST]; + /* This fixed_param TLV is followed by these additional TLV's + * action_bitmaps_per_category - + * Each element is a 32-bit bitmap indicating which subcategories + * for that particular action category are considered for WoW wakeup + * (if the subcategory's bit is 0) or ignored for WoW wakeup (if the + * subcategory's bit is 1). + * + * A_UINT32 action_bitmaps_per_category[]; <-- variable length array + */ +} WMI_WOW_SET_ACTION_WAKE_UP_CMD_fixed_param; + +typedef struct wow_event_info_s { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_WOW_EVENT_INFO_fixed_param */ + A_UINT32 vdev_id; + A_UINT32 flag; /*This is current reserved.*/ + A_INT32 wake_reason; + A_UINT32 data_len; +} WOW_EVENT_INFO_fixed_param; + +typedef struct wow_initial_wakeup_event_s { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WOW_INITIAL_WAKEUP_EVENT_fixed_param */ + A_UINT32 vdev_id; +} WOW_INITIAL_WAKEUP_EVENT_fixed_param; + +typedef enum { + WOW_EVENT_INFO_TYPE_PACKET = 0x0001, + WOW_EVENT_INFO_TYPE_BITMAP, + WOW_EVENT_INFO_TYPE_GTKIGTK, +} WOW_EVENT_INFO_TYPE; + +typedef struct wow_event_info_section_s { + A_UINT32 data_type; + A_UINT32 data_len; +} WOW_EVENT_INFO_SECTION; + +typedef struct wow_event_info_section_packet_s { + A_UINT8 packet[WOW_DEFAULT_EVT_BUF_SIZE]; +} WOW_EVENT_INFO_SECTION_PACKET; + +typedef struct wow_event_info_section_bitmap_s { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_WOW_EVENT_INFO_SECTION_BITMAP */ + A_UINT32 flag; /*This is current reserved.*/ + A_UINT32 value; /*This could be the pattern id for bitmap pattern.*/ + A_UINT32 org_len; /*The length of the orginal packet.*/ +} WOW_EVENT_INFO_SECTION_BITMAP; + +/** + * This command is sent from WLAN host driver to firmware to + * enable or disable D0-WOW. D0-WOW means APSS suspend with + * PCIe link and DDR being active. + * + * + * Entering D0-WOW Mode (based on kernel suspend request): + * host->target: WMI_DO_WOW_ENABLE_DISABLE_CMDID (enable = 1) + * target: Take action (e.g. dbglog suspend) + * target->host: HTC_ACK (HTC_MSG_SEND_SUSPEND_COMPLETE message) + * + * Exiting D0-WOW mode (based on kernel resume OR target->host message received) + * host->target: WMI_DO_WOW_ENABLE_DISABLE_CMDID (enable = 0) + * target: Take action (e.g. dbglog resume) + * target->host: WMI_D0_WOW_DISABLE_ACK_EVENTID + * + * This command is applicable only on the PCIE LL systems + * Host can enter either D0-WOW or WOW mode, but NOT both at same time + * Decision to enter D0-WOW or WOW is based on active interfaces + * + */ +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_d0_wow_enable_disable_cmd_fixed_param */ + A_UINT32 enable; /* 1 = enable, 0 = disable */ +} wmi_d0_wow_enable_disable_cmd_fixed_param; + + +typedef enum extend_wow_type_e { + EXTWOW_TYPE_APP_TYPE1, /* extend wow type: only enable wakeup for app type1 */ + EXTWOW_TYPE_APP_TYPE2, /* extend wow type: only enable wakeup for app type2 */ + EXTWOW_TYPE_APP_TYPE1_2, /* extend wow type: enable wakeup for app type1&2 */ + EXTWOW_TYPE_APP_PULSETEST, + EXTWOW_DISABLED = 255, +} EXTWOW_TYPE; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals wmi_extwow_enable_cmd_fixed_param */ + A_UINT32 vdev_id; + A_UINT32 type; + A_UINT32 wakeup_pin_num; + A_UINT32 swol_pulsetest_type; + A_UINT32 swol_pulsetest_application; +} wmi_extwow_enable_cmd_fixed_param; + +#define SWOL_INDOOR_MAC_ADDRESS_INDEX_MAX 8 +#define SWOL_INDOOR_KEY_LEN 16 + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals wmi_extwow_set_app_type1_params_cmd_fixed_param */ + A_UINT32 vdev_id; + wmi_mac_addr wakee_mac; + A_UINT8 ident[8]; + A_UINT8 passwd[16]; + A_UINT32 ident_len; + A_UINT32 passwd_len; + + /* indoor check parameters */ + /* key for mac addresses specified in swol_indoor_key_mac + * Big-endian hosts need to byte-swap the bytes within each 4-byte + * segment of this array, so the bytes will return to their original + * order when the entire WMI message contents are byte-swapped to + * convert from big-endian to little-endian format. + */ + A_UINT8 swol_indoor_key[SWOL_INDOOR_MAC_ADDRESS_INDEX_MAX][SWOL_INDOOR_KEY_LEN]; + /* key length for specified mac address index + * Big-endian hosts need to byte-swap the bytes within each 4-byte + * segment of this array, so the bytes will return to their original + * order when the entire WMI message contents are byte-swapped to + * convert from big-endian to little-endian format. + */ + A_UINT8 swol_indoor_key_len[SWOL_INDOOR_MAC_ADDRESS_INDEX_MAX]; + /* mac address array allowed to wakeup host*/ + wmi_mac_addr swol_indoor_key_mac[SWOL_INDOOR_MAC_ADDRESS_INDEX_MAX]; + /* app mask for the mac addresses specified in swol_indoor_key_mac */ + A_UINT32 swol_indoor_app_mask[SWOL_INDOOR_MAC_ADDRESS_INDEX_MAX]; + A_UINT32 swol_indoor_waker_check; /* whether to do indoor waker check */ + A_UINT32 swol_indoor_pw_check; /* whether to check password */ + A_UINT32 swol_indoor_pattern; /* wakeup pattern */ + A_UINT32 swol_indoor_exception; /* wakeup when exception happens */ + A_UINT32 swol_indoor_exception_app; + A_UINT32 swol_assist_enable; /* whether to enable IoT mode */ +} wmi_extwow_set_app_type1_params_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals wmi_extwow_set_app_type2_params_cmd_fixed_param */ + A_UINT32 vdev_id; + + A_UINT8 rc4_key[16]; + A_UINT32 rc4_key_len; + + /** ip header parameter */ + A_UINT32 ip_id; /* NC id */ + A_UINT32 ip_device_ip; /* NC IP address */ + A_UINT32 ip_server_ip; /* Push server IP address */ + + /** tcp header parameter */ + A_UINT16 tcp_src_port; /* NC TCP port */ + A_UINT16 tcp_dst_port; /* Push server TCP port */ + A_UINT32 tcp_seq; + A_UINT32 tcp_ack_seq; + + A_UINT32 keepalive_init; /* Initial ping interval */ + A_UINT32 keepalive_min; /* Minimum ping interval */ + A_UINT32 keepalive_max; /* Maximum ping interval */ + A_UINT32 keepalive_inc; /* Increment of ping interval */ + + wmi_mac_addr gateway_mac; + A_UINT32 tcp_tx_timeout_val; + A_UINT32 tcp_rx_timeout_val; + + /** add extra parameter for backward-compatible */ + /* + * For all byte arrays, natural order is used. E.g. + * rc4_write_sandbox[0] holds the 1st RC4 S-box byte, + * rc4_write_sandbox[1] holds the 2nd RC4 S-box byte, etc. + */ + + /* used to encrypt transmit packet such as keep-alive */ + A_UINT8 rc4_write_sandbox[256]; + A_UINT32 rc4_write_x; + A_UINT32 rc4_write_y; + + /* used to decrypt received packet such as wow data */ + A_UINT8 rc4_read_sandbox[256]; + A_UINT32 rc4_read_x; + A_UINT32 rc4_read_y; + + /* used to caculate HMAC hash for transmit packet such as keep-alive */ + A_UINT8 ssl_write_seq[8]; + A_UINT8 ssl_sha1_write_key[64]; + A_UINT32 ssl_sha1_write_key_len; + + /* used to calculate HAMC hash for receive packet such as wow data */ + A_UINT8 ssl_read_seq[8]; + A_UINT8 ssl_sha1_read_key[64]; + A_UINT32 ssl_sha1_read_key_len; + + /* optional element for specifying TCP options data to include in + * transmit packets such as keep-alive + */ + A_UINT32 tcp_options_len; + A_UINT8 tcp_options[40]; + + A_UINT32 async_id; /* keep-alive request id */ +} wmi_extwow_set_app_type2_params_cmd_fixed_param; + + +#define WMI_RXERR_CRC 0x01 /* CRC error on frame */ +#define WMI_RXERR_DECRYPT 0x08 /* non-Michael decrypt error */ +#define WMI_RXERR_MIC 0x10 /* Michael MIC decrypt error */ +#define WMI_RXERR_KEY_CACHE_MISS 0x20 /* No/incorrect key matter in h/w */ + +typedef enum { + PKT_PWR_SAVE_PAID_MATCH = 0x00000001, + PKT_PWR_SAVE_GID_MATCH = 0x00000002, + PKT_PWR_SAVE_EARLY_TIM_CLEAR = 0x00000004, + PKT_PWR_SAVE_EARLY_DTIM_CLEAR = 0x00000008, + PKT_PWR_SAVE_EOF_PAD_DELIM = 0x00000010, + PKT_PWR_SAVE_MACADDR_MISMATCH = 0x00000020, + PKT_PWR_SAVE_DELIM_CRC_FAIL = 0x00000040, + PKT_PWR_SAVE_GID_NSTS_ZERO = 0x00000080, + PKT_PWR_SAVE_RSSI_CHECK = 0x00000100, + PKT_PWR_SAVE_5G_EBT = 0x00000200, + PKT_PWR_SAVE_2G_EBT = 0x00000400, + PKT_PWR_SAVE_BSS_COLOR_MISMATCH = 0x00000800, + PKT_PWR_SAVE_UL_FLAG = 0x00001000, + PKT_PWR_SAVE_STA_ID_MISMATCH = 0x00002000, + PKT_PWR_SAVE_MACADDR_MISMATCH_FCS = 0x00004000, + + PKT_PWR_SAVE_ENABLE = 0x80000000, +} WMI_PKT_PWR_SAVE_TYPE; + +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_ftm_intg_cmd_fixed_param */ + A_UINT32 num_data; /** length in byte of data[]. */ + /** pdev_id for identifying the MAC + * See macros starting with WMI_PDEV_ID_ for values. + */ + A_UINT32 pdev_id; +/* This structure is used to send Factory Test Mode [FTM] command + * from host to firmware for integrated chips which are binary blobs. + * Following this structure is the TLV: + * A_UINT8 data[]; <-- length in byte given by field num_data. + */ +} wmi_ftm_intg_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_ftm_intg_event_fixed_param */ + A_UINT32 num_data; /** length in byte of data[]. */ +/* This structure is used to receive Factory Test Mode [FTM] event + * from firmware to host for integrated chips which are binary blobs. + * Following this structure is the TLV: + * A_UINT8 data[]; <-- length in byte given by field num_data. + */ +} wmi_ftm_intg_event_fixed_param; + +#define WMI_MAX_NS_OFFLOADS 2 +#define WMI_MAX_ARP_OFFLOADS 2 + +#define WMI_ARPOFF_FLAGS_VALID (1 << 0) /* the tuple entry is valid */ +#define WMI_ARPOFF_FLAGS_MAC_VALID (1 << 1) /* the target mac address is valid */ +#define WMI_ARPOFF_FLAGS_REMOTE_IP_VALID (1 << 2) /* remote IP field is valid */ + +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_WMI_ARP_OFFLOAD_TUPLE */ + A_UINT32 flags; /* flags */ + A_UINT8 target_ipaddr[4]; /* IPV4 addresses of the local node*/ + A_UINT8 remote_ipaddr[4]; /* source address of the remote node requesting the ARP (qualifier) */ + wmi_mac_addr target_mac; /* mac address for this tuple, if not valid, the local MAC is used */ +} WMI_ARP_OFFLOAD_TUPLE; + +#define WMI_NSOFF_FLAGS_VALID (1 << 0) /* the tuple entry is valid */ +#define WMI_NSOFF_FLAGS_MAC_VALID (1 << 1) /* the target mac address is valid */ +#define WMI_NSOFF_FLAGS_REMOTE_IP_VALID (1 << 2) /* remote IP field is valid */ +#define WMI_NSOFF_FLAGS_IS_IPV6_ANYCAST (1 << 3) /* whether the configured IPv6 address is anycast */ + +#define WMI_NSOFF_MAX_TARGET_IPS 2 + +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_WMI_NS_OFFLOAD_TUPLE */ + A_UINT32 flags; /* flags */ + /* NOTE: This size of array target_ipaddr[] cannot be changed without breaking WMI compatibility. */ + WMI_IPV6_ADDR target_ipaddr[WMI_NSOFF_MAX_TARGET_IPS]; /* IPV6 target addresses of the local node */ + WMI_IPV6_ADDR solicitation_ipaddr; /* multi-cast source IP addresses for receiving solicitations */ + WMI_IPV6_ADDR remote_ipaddr; /* address of remote node requesting the solicitation (qualifier) */ + wmi_mac_addr target_mac; /* mac address for this tuple, if not valid, the local MAC is used */ +} WMI_NS_OFFLOAD_TUPLE; + +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_WMI_SET_ARP_NS_OFFLOAD_CMD_fixed_param */ + A_UINT32 flags; + A_UINT32 vdev_id; + A_UINT32 num_ns_ext_tuples; +/* Following this structure are the TLVs: + * WMI_NS_OFFLOAD_TUPLE ns_tuples[WMI_MAX_NS_OFFLOADS]; + * WMI_ARP_OFFLOAD_TUPLE arp_tuples[WMI_MAX_ARP_OFFLOADS]; + * WMI_NS_OFFLOAD_TUPLE ns_ext_tuples[]; <-- size based on num_ns_ext_tuples + */ +} WMI_SET_ARP_NS_OFFLOAD_CMD_fixed_param; + + +typedef struct { + A_UINT32 tlv_header; + A_UINT32 vdev_id; + A_UINT32 pattern_id; + A_UINT32 timeout; + A_UINT32 length; + /*Following this would be the pattern + A_UINT8 pattern[] of length specifed by length + field in the structure.*/ +} WMI_ADD_PROACTIVE_ARP_RSP_PATTERN_CMD_fixed_param; + + +typedef struct { + A_UINT32 tlv_header; + A_UINT32 vdev_id; + A_UINT32 pattern_id; +} WMI_DEL_PROACTIVE_ARP_RSP_PATTERN_CMD_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_peer_tid_addba_cmd_fixed_param */ + /** unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; + /** peer MAC address */ + wmi_mac_addr peer_macaddr; + /** Tid number */ + A_UINT32 tid; + /** Initiator (1) or Responder (0) for this aggregation */ + A_UINT32 initiator; + /** size of the negotiated window */ + A_UINT32 window_size; + /** starting sequence number (only valid for initiator) */ + A_UINT32 ssn; + /** timeout field represents the time to wait for Block Ack in + * initiator case and the time to wait for BAR in responder + * case. 0 represents no timeout. */ + A_UINT32 timeout; + /* BA policy: immediate ACK (0) or delayed ACK (1) */ + A_UINT32 policy; +} wmi_peer_tid_addba_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_peer_tid_delba_cmd */ + /** unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; + /** peer MAC address */ + wmi_mac_addr peer_macaddr; + /** Tid number */ + A_UINT32 tid; + /** Initiator (1) or Responder (0) for this aggregation */ + A_UINT32 initiator; +} wmi_peer_tid_delba_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_tx_addba_complete_event_fixed_param */ + /** unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; + /** peer MAC address */ + wmi_mac_addr peer_macaddr; + /** Tid number */ + A_UINT32 tid; + /** Event status */ + A_UINT32 status; +} wmi_tx_addba_complete_event_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_tx_delba_complete_event_fixed_param */ + /** unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; + /** peer MAC address */ + wmi_mac_addr peer_macaddr; + /** Tid number */ + A_UINT32 tid; + /** Event status */ + A_UINT32 status; +} wmi_tx_delba_complete_event_fixed_param; + + + +/* + * Structure to request sequence numbers for a given + * peer station on different TIDs. The TIDs are + * indicated in the tidBitMap, tid 0 would + * be represented by LSB bit 0. tid 1 would be + * represented by LSB bit 1 etc. + * The target will retrieve the current sequence + * numbers for the peer on all the TIDs requested + * and send back a response in a WMI event. + */ +typedef struct +{ + A_UINT32 tlv_header; /* TLV tag and len; tag equals + WMITLV_TAG_STRUC_wmi_ba_req_ssn_cmd_sub_struct_param */ + wmi_mac_addr peer_macaddr; + A_UINT32 tidBitmap; +} wmi_ba_req_ssn; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals + WMITLV_TAG_STRUC_wmi_ba_req_ssn_cmd_fixed_param */ + /** unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; + /** Number of requested SSN In the TLV wmi_ba_req_ssn[] */ + A_UINT32 num_ba_req_ssn; +/* Following this struc are the TLV's: + * wmi_ba_req_ssn ba_req_ssn_list; All peer and tidBitMap for which the ssn is requested + */ +} wmi_ba_req_ssn_cmd_fixed_param; + +/* + * Max transmit categories + * + * Note: In future if we need to increase WMI_MAX_TC definition + * It would break the compatibility for WMI_BA_RSP_SSN_EVENTID. + */ +#define WMI_MAX_TC 8 + +/* + * Structure to send response sequence numbers + * for a give peer and tidmap. + */ +typedef struct +{ + A_UINT32 tlv_header; /* TLV tag and len; tag equals + WMITLV_TAG_STRUC_wmi_ba_req_ssn_event_sub_struct_param */ + wmi_mac_addr peer_macaddr; + /* A boolean to indicate if ssn is present */ + A_UINT32 ssn_present_for_tid[WMI_MAX_TC]; + /* The ssn from target, valid only if + * ssn_present_for_tid[tidn] equals 1 + */ + A_UINT32 ssn_for_tid[WMI_MAX_TC]; +} wmi_ba_event_ssn; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals + WMITLV_TAG_STRUC_wmi_ba_rsp_ssn_event_fixed_param */ + /** unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; + /** Event status, success or failure of the overall operation */ + A_UINT32 status; + /** Number of requested SSN In the TLV wmi_ba_req_ssn[] */ + A_UINT32 num_ba_event_ssn; +/* Following this struc are the TLV's: + * wmi_ba_event_ssn ba_event_ssn_list; All peer and tidBitMap for which the ssn is requested + */ +} wmi_ba_rsp_ssn_event_fixed_param; + + +enum wmi_aggr_state_req_type { + + WMI_DISABLE_AGGREGATION, + WMI_ENABLE_AGGREGATION +}; + +/* + * This event is generated by the COEX module + * when esco call is begins the coex module in fw genrated this event to host to + * disable the RX aggregation and after completion of the esco call fw will indicate to + * enable back the Rx aggregation . +*/ + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_aggr_state_trig_event_fixed_param */ + /** unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; + /** req_type contains values from enum + * wmi_aggr_state_req_type; 0 (disable) 1(enable) */ + A_UINT32 req_type; +} wmi_aggr_state_trig_event_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_vdev_install_key_complete_event_fixed_param */ + /** unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; + /** MAC address used for installing */ + wmi_mac_addr peer_macaddr; + /** key index */ + A_UINT32 key_ix; + /** key flags */ + A_UINT32 key_flags; + /** Event status */ + A_UINT32 status; +} wmi_vdev_install_key_complete_event_fixed_param; + +typedef enum _WMI_NLO_AUTH_ALGORITHM { + WMI_NLO_AUTH_ALGO_80211_OPEN = 1, + WMI_NLO_AUTH_ALGO_80211_SHARED_KEY = 2, + WMI_NLO_AUTH_ALGO_WPA = 3, + WMI_NLO_AUTH_ALGO_WPA_PSK = 4, + WMI_NLO_AUTH_ALGO_WPA_NONE = 5, + WMI_NLO_AUTH_ALGO_RSNA = 6, + WMI_NLO_AUTH_ALGO_RSNA_PSK = 7, +} WMI_NLO_AUTH_ALGORITHM; + +typedef enum _WMI_NLO_CIPHER_ALGORITHM { + WMI_NLO_CIPHER_ALGO_NONE = 0x00, + WMI_NLO_CIPHER_ALGO_WEP40 = 0x01, + WMI_NLO_CIPHER_ALGO_TKIP = 0x02, + WMI_NLO_CIPHER_ALGO_CCMP = 0x04, + WMI_NLO_CIPHER_ALGO_WEP104 = 0x05, + WMI_NLO_CIPHER_ALGO_BIP = 0x06, + WMI_NLO_CIPHER_ALGO_WPA_USE_GROUP = 0x100, + WMI_NLO_CIPHER_ALGO_RSN_USE_GROUP = 0x100, + WMI_NLO_CIPHER_ALGO_WEP = 0x101, +} WMI_NLO_CIPHER_ALGORITHM; + +/* SSID broadcast type passed in NLO params */ +typedef enum _WMI_NLO_SSID_BcastNwType +{ + WMI_NLO_BCAST_UNKNOWN = 0, + WMI_NLO_BCAST_NORMAL = 1, + WMI_NLO_BCAST_HIDDEN = 2, +} WMI_NLO_SSID_BcastNwType; + +#define WMI_NLO_MAX_SSIDS 16 +#define WMI_NLO_MAX_CHAN 48 + +#define WMI_NLO_CONFIG_STOP (0x1 << 0) +#define WMI_NLO_CONFIG_START (0x1 << 1) +#define WMI_NLO_CONFIG_RESET (0x1 << 2) +#define WMI_NLO_CONFIG_SLOW_SCAN (0x1 << 4) +#define WMI_NLO_CONFIG_FAST_SCAN (0x1 << 5) +#define WMI_NLO_CONFIG_SSID_HIDE_EN (0x1 << 6) + +/* This bit is used to indicate if EPNO Profile is enabled */ +#define WMI_NLO_CONFIG_ENLO (0x1 << 7) +#define WMI_NLO_CONFIG_SCAN_PASSIVE (0x1 << 8) +#define WMI_NLO_CONFIG_ENLO_RESET (0x1 << 9) +#define WMI_NLO_CONFIG_SPOOFED_MAC_IN_PROBE_REQ (0x1 << 10) +#define WMI_NLO_CONFIG_RANDOM_SEQ_NO_IN_PROBE_REQ (0x1 << 11) +#define WMI_NLO_CONFIG_ENABLE_IE_WHITELIST_IN_PROBE_REQ (0x1 << 12) +#define WMI_NLO_CONFIG_ENABLE_CNLO_RSSI_CONFIG (0x1 << 13) + +/* Whether directed scan needs to be performed (for hidden SSIDs) */ +#define WMI_ENLO_FLAG_DIRECTED_SCAN 1 +/* Whether PNO event shall be triggered if the network is found on A band */ +#define WMI_ENLO_FLAG_A_BAND 2 +/* Whether PNO event shall be triggered if the network is found on G band */ +#define WMI_ENLO_FLAG_G_BAND 4 +/* Whether strict matching is required (i.e. firmware shall not match on the entire SSID) */ +#define WMI_ENLO_FLAG_STRICT_MATCH 8 + +/* Code for matching the beacon AUTH IE - additional codes TBD */ +/* open */ +#define WMI_ENLO_AUTH_CODE_OPEN 1 +/* WPA_PSK or WPA2PSK */ +#define WMI_ENLO_AUTH_CODE_PSK 2 +/* any EAPOL */ +#define WMI_ENLO_AUTH_CODE_EAPOL 4 + +/* NOTE: wmi_nlo_ssid_param structure can't be changed without breaking the compatibility */ +typedef struct wmi_nlo_ssid_param +{ + A_UINT32 valid; + wmi_ssid ssid; +} wmi_nlo_ssid_param; + +/* NOTE: wmi_nlo_enc_param structure can't be changed without breaking the compatibility */ +typedef struct wmi_nlo_enc_param +{ + A_UINT32 valid; + A_UINT32 enc_type; +} wmi_nlo_enc_param; + +/* NOTE: wmi_nlo_auth_param structure can't be changed without breaking the compatibility */ +typedef struct wmi_nlo_auth_param +{ + A_UINT32 valid; + A_UINT32 auth_type; +} wmi_nlo_auth_param; + +/* NOTE: wmi_nlo_bcast_nw_param structure can't be changed without breaking the compatibility */ +typedef struct wmi_nlo_bcast_nw_param +{ + A_UINT32 valid; +/* If WMI_NLO_CONFIG_EPNO is not set. Supplicant PNO is enabled. The value should be true/false +Otherwise EPNO is enabled. bcast_nw_type would be used as a bit flag contains WMI_ENLO_FLAG_XXX */ + A_UINT32 bcast_nw_type; +} wmi_nlo_bcast_nw_param; + +/* NOTE: wmi_nlo_rssi_param structure can't be changed without breaking the compatibility */ +typedef struct wmi_nlo_rssi_param +{ + A_UINT32 valid; + A_INT32 rssi; +} wmi_nlo_rssi_param; + +typedef struct nlo_configured_parameters { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_nlo_configured_parameters */ + wmi_nlo_ssid_param ssid; + wmi_nlo_enc_param enc_type; + wmi_nlo_auth_param auth_type; + wmi_nlo_rssi_param rssi_cond; + wmi_nlo_bcast_nw_param bcast_nw_type; /* indicates if the SSID is hidden or not */ +} nlo_configured_parameters; + + +/* Support channel prediction for PNO scan after scanning top_k_num channels + * if stationary_threshold is met. + */ +typedef struct nlo_channel_prediction_cfg { + A_UINT32 tlv_header; + /* Enable or disable this feature. */ + A_UINT32 enable; + /* Top K channels will be scanned before deciding whether to further scan + * or stop. Minimum value is 3 and maximum is 5. */ + A_UINT32 top_k_num; + /* Preconfigured stationary threshold. + * Lesser value means more conservative. Bigger value means more aggressive. + * Maximum is 100 and mininum is 0. */ + A_UINT32 stationary_threshold; + /* Periodic full channel scan in milliseconds unit. + * After full_scan_period_ms since last full scan, channel prediction + * scan is suppressed and will do full scan. + * This is to help detecting sudden AP power-on or -off. Value 0 means no + * full scan at all (not recommended). + */ + A_UINT32 full_scan_period_ms; +} nlo_channel_prediction_cfg; + +typedef struct enlo_candidate_score_params_t { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_enlo_candidate_score_param */ + A_INT32 min5GHz_rssi; /* minimum 5GHz RSSI for a BSSID to be considered (units = dBm) */ + A_INT32 min24GHz_rssi; /* minimum 2.4GHz RSSI for a BSSID to be considered (units = dBm) */ + A_UINT32 initial_score_max; /* the maximum score that a network can have before bonuses */ + /* current_connection_bonus: + * only report when there is a network's score this much higher + * than the current connection + */ + A_UINT32 current_connection_bonus; + A_UINT32 same_network_bonus; /* score bonus for all networks with the same network flag */ + A_UINT32 secure_bonus; /* score bonus for networks that are not open */ + A_UINT32 band5GHz_bonus; /* 5GHz RSSI score bonus (applied to all 5GHz networks) */ +} enlo_candidate_score_params; + +typedef struct connected_nlo_bss_band_rssi_pref_t { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_connected_nlo_bss_band_rssi_pref */ + /** band which needs to get preference over other band - see wmi_set_vdev_ie_band enum */ + A_UINT32 band; + /* Amount of RSSI preference (in dB) that can be given to band (mentioned above) over other band */ + A_INT32 rssi_pref; +} connected_nlo_bss_band_rssi_pref; + +typedef struct connected_nlo_rssi_params_t { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_connected_nlo_rssi_params */ + /* Relative rssi threshold (in dB) by which new BSS should have better rssi than + * the current connected BSS. + */ + A_INT32 relative_rssi; + /* The amount of rssi preference (in dB) that can be given to a 5G BSS over 2.4G BSS. */ + A_INT32 relative_rssi_5g_pref; +} connected_nlo_rssi_params; + +typedef struct wmi_nlo_config { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_nlo_config_cmd_fixed_param */ + A_UINT32 flags; + A_UINT32 vdev_id; + A_UINT32 fast_scan_max_cycles; + A_UINT32 active_dwell_time; + A_UINT32 passive_dwell_time; /* PDT in msecs */ + A_UINT32 probe_bundle_size; + A_UINT32 rest_time; /* ART = IRT */ + A_UINT32 max_rest_time; /* Max value that can be reached after SBM */ + A_UINT32 scan_backoff_multiplier; /* SBM */ + A_UINT32 fast_scan_period; /* SCBM */ + A_UINT32 slow_scan_period; /* specific to windows */ + A_UINT32 no_of_ssids; + A_UINT32 num_of_channels; + A_UINT32 delay_start_time; /* NLO scan start delay time in milliseconds */ + /** MAC Address to use in Probe Req as SA **/ + wmi_mac_addr mac_addr; + /** Mask on which MAC has to be randomized **/ + wmi_mac_addr mac_mask; + /** IE bitmap to use in Probe Req **/ + A_UINT32 ie_bitmap[WMI_IE_BITMAP_SIZE]; + /** Number of vendor OUIs. In the TLV vendor_oui[] **/ + A_UINT32 num_vendor_oui; + /** Number of connected NLO band preferences **/ + A_UINT32 num_cnlo_band_pref; +/* The TLVs will follow. + * nlo_configured_parameters nlo_list[]; + * A_UINT32 channel_list[num_of_channels]; + * nlo_channel_prediction_cfg ch_prediction_cfg; + * enlo_candidate_score_params candidate_score_params; + * wmi_vendor_oui vendor_oui[num_vendor_oui]; + * connected_nlo_rssi_params cnlo_rssi_params; + * connected_nlo_bss_band_rssi_pref cnlo_bss_band_rssi_pref[num_cnlo_band_pref]; + */ +} wmi_nlo_config_cmd_fixed_param; + +typedef struct wmi_nlo_event +{ + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_nlo_event */ + A_UINT32 vdev_id; +} wmi_nlo_event; + + +/* WMI_PASSPOINT_CONFIG_SET + * Sets a list for passpoint networks for PNO purposes; + * it should be matched against any passpoint networks found + * during regular PNO scan. + */ +#define WMI_PASSPOINT_CONFIG_SET (0x1 << 0) +/* WMI_PASSPOINT_CONFIG_RESET + * Reset passpoint network list - + * no Passpoint networks should be matched after this. + */ +#define WMI_PASSPOINT_CONFIG_RESET (0x1 << 1) + +#define PASSPOINT_REALM_LEN 256 +#define PASSPOINT_ROAMING_CONSORTIUM_ID_LEN 5 +#define PASSPOINT_ROAMING_CONSORTIUM_ID_NUM 16 +#define PASSPOINT_PLMN_ID_LEN 3 +#define PASSPOINT_PLMN_ID_ALLOC_LEN /* round up to A_UINT32 boundary */ \ + (((PASSPOINT_PLMN_ID_LEN + 3) >> 2) << 2) + +/* + * Confirm PASSPOINT_REALM_LEN is a multiple of 4, so the + * A_UINT8 realm[PASSPOINT_REALM_LEN] + * array will end on a 4-byte boundary. + * (This 4-byte alignment simplifies endianness-correction byte swapping.) + */ +A_COMPILE_TIME_ASSERT( + check_passpoint_realm_size, + (PASSPOINT_REALM_LEN % sizeof(A_UINT32)) == 0); + +/* + * Confirm the product of PASSPOINT_ROAMING_CONSORTIUM_ID_NUM and + * PASSPOINT_ROAMING_CONSORTIUM_ID_LEN is a multiple of 4, so the + * roaming_consortium_ids array below will end on a 4-byte boundary. + * (This 4-byte alignment simplifies endianness-correction byte swapping.) + */ +A_COMPILE_TIME_ASSERT( + check_passpoint_roaming_consortium_ids_size, + ((PASSPOINT_ROAMING_CONSORTIUM_ID_NUM*PASSPOINT_ROAMING_CONSORTIUM_ID_LEN) % sizeof(A_UINT32)) == 0); + +/* wildcard ID to allow an action (reset) to apply to all networks */ +#define WMI_PASSPOINT_NETWORK_ID_WILDCARD 0xFFFFFFFF +typedef struct wmi_passpoint_config { + A_UINT32 tlv_header; /* TLV tag and len; tag equals wmi_passpoint_config_cmd_fixed_param */ + /* (network) id + * identifier of the matched network, report this in event + * This id can be a wildcard (WMI_PASSPOINT_NETWORK_ID_WILDCARD) + * that indicates the action should be applied to all networks. + * Currently, the only action that is applied to all networks is "reset". + * If a non-wildcard ID is specified, that particular network is configured. + * If a wildcard ID is specified, all networks are reset. + */ + A_UINT32 id; + A_UINT32 req_id; + A_UINT8 realm[PASSPOINT_REALM_LEN]; /*null terminated UTF8 encoded realm, 0 if unspecified*/ + A_UINT8 roaming_consortium_ids[PASSPOINT_ROAMING_CONSORTIUM_ID_NUM][PASSPOINT_ROAMING_CONSORTIUM_ID_LEN]; /*roaming consortium ids to match, 0s if unspecified*/ + /*This would be bytes-stream as same as defition of realm id in 802.11 standard*/ + A_UINT8 plmn[PASSPOINT_PLMN_ID_ALLOC_LEN]; /*PLMN id mcc/mnc combination as per rules, 0s if unspecified */ +} wmi_passpoint_config_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals wmi_passpoint_event_hdr */ + A_UINT32 id; /* identifier of the matched network */ + A_UINT32 vdev_id; + A_UINT32 timestamp; /* time since boot (in microsecond) when the result was retrieved*/ + wmi_ssid ssid; + wmi_mac_addr bssid; /* bssid of the network */ + A_UINT32 channel_mhz; /* channel frequency in MHz */ + A_UINT32 rssi; /* rssi value */ + A_UINT32 rtt; /* timestamp in nanoseconds*/ + A_UINT32 rtt_sd; /* standard deviation in rtt */ + A_UINT32 beacon_period; /* beacon advertised in the beacon */ + A_UINT32 capability; /* capabilities advertised in the beacon */ + A_UINT32 ie_length; /* size of the ie_data blob */ + A_UINT32 anqp_length; /* length of ANQP blob */ +/* Following this structure is the byte stream of ie data of length ie_buf_len: + * A_UINT8 ie_data[]; <-- length in byte given by field ie_length, blob of ie data in beacon + * A_UINT8 anqp_ie[]; <-- length in byte given by field anqp_len, blob of anqp data of IE + * Implicitly, combing ie_data and anqp_ie into a single bufp, and the bytes stream of each ie should be same as BEACON/Action-frm by 802.11 spec. + */ +} wmi_passpoint_event_hdr; + + +#define GTK_OFFLOAD_OPCODE_MASK 0xFF000000 +/** Enable GTK offload, and provided parameters KEK,KCK and replay counter values */ +#define GTK_OFFLOAD_ENABLE_OPCODE 0x01000000 +/** Disable GTK offload */ +#define GTK_OFFLOAD_DISABLE_OPCODE 0x02000000 +/** Read GTK offload parameters, generates WMI_GTK_OFFLOAD_STATUS_EVENT */ +#define GTK_OFFLOAD_REQUEST_STATUS_OPCODE 0x04000000 +enum wmi_chatter_mode { + /* Chatter enter/exit happens + * automatically based on preset + * params + */ + WMI_CHATTER_MODE_AUTO, + /* Chatter enter is triggered + * manually by the user + */ + WMI_CHATTER_MODE_MANUAL_ENTER, + /* Chatter exit is triggered + * manually by the user + */ + WMI_CHATTER_MODE_MANUAL_EXIT, + /* Placeholder max value, always last*/ + WMI_CHATTER_MODE_MAX +}; + +enum wmi_chatter_query_type { + /*query coalescing filter match counter*/ + WMI_CHATTER_QUERY_FILTER_MATCH_CNT, + WMI_CHATTER_QUERY_MAX +}; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_chatter_set_mode_cmd_fixed_param */ + A_UINT32 chatter_mode; +} wmi_chatter_set_mode_cmd_fixed_param; + +/** maximum number of filter supported*/ +#define CHATTER_MAX_COALESCING_RULES 11 +/** maximum number of field tests per filter*/ +#define CHATTER_MAX_FIELD_TEST 5 +/** maximum field length in number of DWORDS*/ +#define CHATTER_MAX_TEST_FIELD_LEN32 2 + +/** field test kinds*/ +#define CHATTER_COALESCING_TEST_EQUAL 1 +#define CHATTER_COALESCING_TEST_MASKED_EQUAL 2 +#define CHATTER_COALESCING_TEST_NOT_EQUAL 3 + +/** packet type*/ +#define CHATTER_COALESCING_PKT_TYPE_UNICAST (1 << 0) +#define CHATTER_COALESCING_PKT_TYPE_MULTICAST (1 << 1) +#define CHATTER_COALESCING_PKT_TYPE_BROADCAST (1 << 2) + +/** coalescing field test*/ +typedef struct _chatter_pkt_coalescing_hdr_test { + /** offset from start of mac header, for windows native wifi host driver + * should assume standard 802.11 frame format without QoS info and address4 + * FW would account for any non-stand fields for final offset value. + */ + A_UINT32 offset; + A_UINT32 length; /* length of test field*/ + A_UINT32 test; /*equal, not equal or masked equal*/ + A_UINT32 mask[CHATTER_MAX_TEST_FIELD_LEN32]; /*mask byte stream*/ + A_UINT32 value[CHATTER_MAX_TEST_FIELD_LEN32]; /*value byte stream*/ +} chatter_pkt_coalescing_hdr_test; + +/** packet coalescing filter*/ +typedef struct _chatter_pkt_coalescing_filter { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_chatter_pkt_coalescing_filter */ + A_UINT32 filter_id; /*unique id assigned by OS*/ + A_UINT32 max_coalescing_delay; /*max miliseconds 1st pkt can be hold*/ + A_UINT32 pkt_type; /*unicast/multicast/broadcast*/ + A_UINT32 num_of_test_field; /*number of field test in table*/ + chatter_pkt_coalescing_hdr_test test_fields[CHATTER_MAX_FIELD_TEST]; /*field test tbl*/ +} chatter_pkt_coalescing_filter; + +/** packet coalescing filter add command*/ +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_chatter_coalescing_add_filter_cmd_fixed_param */ + A_UINT32 num_of_filters; +/* Following this tlv, there comes an array of structure of type chatter_pkt_coalescing_filter + chatter_pkt_coalescing_filter rx_filter[1];*/ +} wmi_chatter_coalescing_add_filter_cmd_fixed_param; +/** packet coalescing filter delete command*/ +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_chatter_coalescing_delete_filter_cmd_fixed_param */ + A_UINT32 filter_id; /*filter id which will be deleted*/ +} wmi_chatter_coalescing_delete_filter_cmd_fixed_param; +/** packet coalescing query command*/ +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_chatter_coalescing_query_cmd_fixed_param */ + A_UINT32 type; /*type of query*/ +} wmi_chatter_coalescing_query_cmd_fixed_param; +/** chatter query reply event*/ +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_chatter_query_reply_event_fixed_param */ + A_UINT32 type; /*query type*/ + A_UINT32 filter_match_cnt; /*coalescing filter match counter*/ +} wmi_chatter_query_reply_event_fixed_param; + +/* NOTE: This constants GTK_OFFLOAD_KEK_BYTES, GTK_OFFLOAD_KCK_BYTES, and GTK_REPLAY_COUNTER_BYTES + * cannot be changed without breaking WMI compatibility. */ +#define GTK_OFFLOAD_KEK_BYTES 16 +#define GTK_OFFLOAD_KCK_BYTES 16 +/* NOTE: GTK_REPLAY_COUNTER_BYTES, WMI_MAX_KEY_LEN, IGTK_PN_SIZE cannot be changed in the future without breaking WMI compatibility */ +#define GTK_REPLAY_COUNTER_BYTES 8 +#define WMI_MAX_KEY_LEN 32 +#define IGTK_PN_SIZE 6 + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_WMI_GTK_OFFLOAD_STATUS_EVENT_fixed_param */ + A_UINT32 vdev_id; /** unique id identifying the VDEV */ + A_UINT32 flags; /* status flags */ + A_UINT32 refresh_cnt; /* number of successful GTK refresh exchanges since last SET operation */ + A_UINT8 replay_counter[GTK_REPLAY_COUNTER_BYTES]; /* current replay counter */ + A_UINT8 igtk_keyIndex; /* Use if IGTK_OFFLOAD is defined */ + A_UINT8 igtk_keyLength; /* Use if IGTK_OFFLOAD is defined */ + A_UINT8 igtk_keyRSC[IGTK_PN_SIZE]; /* key replay sequence counter *//* Use if IGTK_OFFLOAD is defined */ + A_UINT8 igtk_key[WMI_MAX_KEY_LEN]; /* Use if IGTK_OFFLOAD is defined */ +} WMI_GTK_OFFLOAD_STATUS_EVENT_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_WMI_GTK_OFFLOAD_CMD_fixed_param */ + A_UINT32 vdev_id; /** unique id identifying the VDEV */ + A_UINT32 flags; /* control flags, GTK offload command use high byte */ + /* The size of following 3 arrays cannot be changed without breaking WMI compatibility. */ + A_UINT8 KEK[GTK_OFFLOAD_KEK_BYTES]; /* key encryption key */ + A_UINT8 KCK[GTK_OFFLOAD_KCK_BYTES]; /* key confirmation key */ + A_UINT8 replay_counter[GTK_REPLAY_COUNTER_BYTES]; /* replay counter for re-key */ +} WMI_GTK_OFFLOAD_CMD_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_gtk_offload_extended_tlv_param */ + A_UINT32 vdev_id; /** unique id identifying the VDEV */ + A_UINT32 flags; /* control flags, GTK offload command use high byte */ + A_UINT32 kek_len; + A_UINT8 KEK[GTK_OFFLOAD_KEK_EXTENDED_BYTES]; /* key encryption key */ + A_UINT8 KCK[GTK_OFFLOAD_KCK_BYTES]; /* key confirmation key */ + A_UINT8 replay_counter[GTK_REPLAY_COUNTER_BYTES]; /* replay counter for re-key */ +} wmi_gtk_offload_fils_tlv_param; + +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_WMI_PMF_OFFLOAD_SET_SA_QUERY_CMD_fixed_param */ + A_UINT32 vdev_id; + A_UINT32 sa_query_retry_interval; /* in msec */ + A_UINT32 sa_query_max_retry_count; +} WMI_PMF_OFFLOAD_SET_SA_QUERY_CMD_fixed_param; + +typedef enum { + WMI_STA_KEEPALIVE_METHOD_NULL_FRAME = 1, /* 802.11 NULL frame */ + WMI_STA_KEEPALIVE_METHOD_UNSOLICITED_ARP_RESPONSE = 2, /* ARP response */ + WMI_STA_KEEPALIVE_METHOD_ETHERNET_LOOPBACK = 3, /*ETHERNET LOOPBACK*/ + WMI_STA_KEEPALIVE_METHOD_GRATUITOUS_ARP_REQUEST = 4, /* gratuitous ARP req*/ +} WMI_STA_KEEPALIVE_METHOD; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_WMI_STA_KEEPALVE_ARP_RESPONSE */ + WMI_IPV4_ADDR sender_prot_addr; /* Sender protocol address */ + WMI_IPV4_ADDR target_prot_addr; /* Target protocol address */ + wmi_mac_addr dest_mac_addr; /* destination MAC address */ +} WMI_STA_KEEPALVE_ARP_RESPONSE; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_WMI_STA_KEEPALIVE_CMD_fixed_param */ + A_UINT32 vdev_id; + A_UINT32 enable; /* 1 - Enable, 0 - disable */ + A_UINT32 method; /* keep alive method */ + A_UINT32 interval; /* time interval in seconds */ +/* + * NOTE: following this structure is the TLV for ARP Resonse: + * WMI_STA_KEEPALVE_ARP_RESPONSE arp_resp; <-- ARP response + */ +} WMI_STA_KEEPALIVE_CMD_fixed_param; + +typedef struct { + A_UINT32 tlv_header; + A_UINT32 vdev_id; + A_UINT32 action; +} WMI_VDEV_WNM_SLEEPMODE_CMD_fixed_param; +typedef WMI_VDEV_WNM_SLEEPMODE_CMD_fixed_param WMI_STA_WNMSLEEP_CMD; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_vdev_set_keepalive_cmd_fixed_param */ + A_UINT32 vdev_id; + A_UINT32 keepaliveInterval; /* seconds */ + A_UINT32 keepaliveMethod; +} wmi_vdev_set_keepalive_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_vdev_get_keepalive_cmd_fixed_param */ + A_UINT32 vdev_id; +} wmi_vdev_get_keepalive_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_vdev_get_keepalive_event_fixed_param */ + A_UINT32 vdev_id; + A_UINT32 keepaliveInterval; /* seconds */ + A_UINT32 keepaliveMethod; /* seconds */ +} wmi_vdev_get_keepalive_event_fixed_param; + +typedef enum { + WMI_CLEAR_ARP_STATS_COLLECTED = 0x0, + WMI_START_ARP_STATS_COLLECTION, +} WMI_ARP_STATS_ACTION; + +typedef enum { + WMI_ARP_STATS_RX_PKT_TYPE_ARP = 0x1, +} WMI_ARP_STATS_RX_PKT_TYPE; + +typedef enum { + WMI_BA_SESSION_ESTABLISHMENT_STATUS_SUCCESS = 0x0, + WMI_BA_SESSION_ESTABLISHMENT_STATUS_FAILURE, +} WMI_ARP_STATS_BA_SESSION_ESTABLISH_STATUS; + +typedef enum { + WMI_CONNECTION_STATUS_FAILURE = 0x0, + WMI_CONNECTION_STATUS_SUCCESS, +} WMI_ARP_STATS_CONNECTION_STATUS; + +/* ARP stats set (configure) req */ +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_vdev_set_arp_stats_cmd_fixed_param */ + A_UINT32 vdev_id; + A_UINT32 set_clr; /* WMI_ARP_STATS_ACTION */ + A_UINT32 pkt_type; /* WMI_ARP_STATS_RX_PKT_TYPE */ + A_UINT32 ipv4; /* target will maintain ARP stats (only) for frames containing this IP address */ +} wmi_vdev_set_arp_stats_cmd_fixed_param; + +/* ARP stats get req */ +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_vdev_get_arp_stats_cmd_fixed_param */ + A_UINT32 vdev_id; +} wmi_vdev_get_arp_stats_cmd_fixed_param; + +/* per vdev based ARP stats */ +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_vdev_get_arp_stats_event_fixed_param */ + A_UINT32 vdev_id; + A_UINT32 arp_req_enqueue; + A_UINT32 arp_req_tx_success; + A_UINT32 arp_req_tx_failure; /* number of times a tx MPDU containing a unicast ARP request went unacked */ + A_UINT32 arp_rsp_recvd; + A_UINT32 out_of_order_arp_rsp_drop_cnt; + A_UINT32 dad_detected; /* duplicate address detection */ + A_UINT32 connect_status; /* WMI_ARP_STATS_CONNECTION_STATUS */ + A_UINT32 ba_session_establishment_status; /* WMI_ARP_STATS_BA_SESSION_ESTABLISH_STATUS */ +} wmi_vdev_get_arp_stats_event_fixed_param; + +typedef struct { + A_UINT32 tlv_header; + A_UINT32 vdev_id; +#define IPSEC_NATKEEPALIVE_FILTER_DISABLE 0 +#define IPSEC_NATKEEPALIVE_FILTER_ENABLE 1 + A_UINT32 action; +} WMI_VDEV_IPSEC_NATKEEPALIVE_FILTER_CMD_fixed_param; +typedef WMI_VDEV_IPSEC_NATKEEPALIVE_FILTER_CMD_fixed_param WMI_VDEV_IPSEC_NATKEEPALIVE_FILTER_CMD; + +typedef struct { + A_UINT32 tlv_header; + A_UINT32 vdev_id; + A_UINT32 mcc_tbttmode; + wmi_mac_addr mcc_bssid; +} wmi_vdev_mcc_set_tbtt_mode_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; + A_UINT32 vdev_id; /* home vdev id */ + A_UINT32 meas_token; /* from measure request frame */ + A_UINT32 dialog_token; + A_UINT32 number_bursts; /* zero keep sending until cancel, bigger than 0 means times e.g. 1,2 */ + A_UINT32 burst_interval; /* unit in mill seconds, interval between consecutive burst*/ + A_UINT32 burst_cycle; /* times cycle through within one burst */ + A_UINT32 tx_power; /* for path frame */ + A_UINT32 off_duration; /* uint in mill seconds, channel off duraiton for path loss frame sending */ + wmi_mac_addr dest_mac; /* multicast DA, for path loss frame */ + A_UINT32 num_chans; +} wmi_vdev_plmreq_start_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; + A_UINT32 vdev_id; + A_UINT32 meas_token; /* same value from req*/ +} wmi_vdev_plmreq_stop_cmd_fixed_param; + +typedef struct { + /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_p2p_set_noa_cmd_fixed_param */ + A_UINT32 tlv_header; + /* unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; + /* enable/disable NoA */ + A_UINT32 enable; + /** number of NoA desc. In the TLV noa_descriptor[] */ + A_UINT32 num_noa; + /** + * TLV (tag length value) paramerters follow the pattern structure. + * TLV contain NoA desc with num of num_noa + */ +} wmi_p2p_set_noa_cmd_fixed_param; + +typedef struct { + /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_unit_test_cmd_fixed_param */ + A_UINT32 tlv_header; + /* unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; + /* Identify the wlan module */ + A_UINT32 module_id; + /* Num of test arguments passed */ + A_UINT32 num_args; + /* unique id identifying the unit test cmd, generated by the caller */ + A_UINT32 diag_token; +/** + * TLV (tag length value) parameters follow the wmi_roam_chan_list + * structure. The TLV's are: + * A_UINT32 args[]; + **/ +} wmi_unit_test_cmd_fixed_param; + +/** Roaming offload SYNCH_COMPLETE from host when host finished sync logic + * after it received WMI_ROAM_SYNCH_EVENTID. + */ +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_roam_synch_complete_fixed_param */ + /** unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; +} wmi_roam_synch_complete_fixed_param; + + +typedef enum { + RECOVERY_SIM_ASSERT = 0x01, + RECOVERY_SIM_NO_DETECT = 0x02, + RECOVERY_SIM_CTR_EP_FULL = 0x03, + RECOVERY_SIM_EMPTY_POINT = 0x04, + RECOVERY_SIM_STACK_OV = 0x05, + RECOVERY_SIM_INFINITE_LOOP = 0x06, + RECOVERY_SIM_PCIE_LINKDOWN = 0x07, + RECOVERY_SIM_SELF_RECOVERY = 0x08, +} RECOVERY_SIM_TYPE; + +/* WMI_FORCE_FW_HANG_CMDID */ +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_WMI_FORCE_FW_HANG_CMD_fixed_param */ + A_UINT32 type; /*0:unused 1: ASSERT, 2: not respond detect command,3: simulate ep-full(),4:...*/ + A_UINT32 delay_time_ms; /*0xffffffff means the simulate will delay for random time (0 ~0xffffffff ms)*/ +} WMI_FORCE_FW_HANG_CMD_fixed_param; + +typedef enum { + WMI_MCAST_FILTER_SET = 1, + WMI_MCAST_FILTER_DELETE +} WMI_SET_SINGLE_MCAST_FILTER_OP; + +typedef struct { + A_UINT32 tlv_header; + A_UINT32 vdev_id; + A_UINT32 index; + A_UINT32 action; + wmi_mac_addr mcastbdcastaddr; +} WMI_SET_MCASTBCAST_FILTER_CMD_fixed_param; + +typedef enum { + WMI_MULTIPLE_MCAST_FILTER_CLEAR = 1, /* clear all previous mc list */ + WMI_MULTIPLE_MCAST_FILTER_SET, /* clear all previous mc list, and set new list */ + WMI_MULTIPLE_MCAST_FILTER_DELETE, /* delete one/multiple mc list */ + WMI_MULTIPLE_MCAST_FILTER_ADD /* add one/multiple mc list */ +} WMI_MULTIPLE_MCAST_FILTER_OP; + +typedef struct { + A_UINT32 tlv_header; + A_UINT32 vdev_id; + A_UINT32 operation; /* refer WMI_MULTIPLE_MCAST_FILTER_OP */ + A_UINT32 num_mcastaddrs; /* number of elements in the subsequent mcast addr list */ +/** + * TLV (tag length value) parameters follow the + * structure. The TLV's are: + * wmi_mac_addr mcastaddr_list[num_mcastaddrs]; + */ +} WMI_SET_MULTIPLE_MCAST_FILTER_CMD_fixed_param; + + +/* WMI_DBGLOG_TIME_STAMP_SYNC_CMDID */ +typedef enum { + WMI_TIME_STAMP_SYNC_MODE_MS, /* millisecond units */ + WMI_TIME_STAMP_SYNC_MODE_US, /* microsecond units */ +} WMI_TIME_STAMP_SYNC_MODE; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_dbglog_time_stamp_sync_cmd_fixed_param */ + A_UINT32 mode; /* 0: millisec, 1: microsec (see WMI_TIME_STAMP_SYNC_MODE) */ + A_UINT32 time_stamp_low; /* lower 32 bits of remote time stamp */ + A_UINT32 time_stamp_high; /* higher 32 bits of remote time stamp */ +} WMI_DBGLOG_TIME_STAMP_SYNC_CMD_fixed_param; + +/* GPIO Command and Event data structures */ + +/* WMI_GPIO_CONFIG_CMDID */ +enum { + WMI_GPIO_PULL_NONE, + WMI_GPIO_PULL_UP, + WMI_GPIO_PULL_DOWN, +}; + +enum { + WMI_GPIO_INTTYPE_DISABLE, + WMI_GPIO_INTTYPE_RISING_EDGE, + WMI_GPIO_INTTYPE_FALLING_EDGE, + WMI_GPIO_INTTYPE_BOTH_EDGE, + WMI_GPIO_INTTYPE_LEVEL_LOW, + WMI_GPIO_INTTYPE_LEVEL_HIGH +}; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_gpio_config_cmd_fixed_param */ + A_UINT32 gpio_num; /* GPIO number to be setup */ + A_UINT32 input; /* 0 - Output/ 1 - Input */ + A_UINT32 pull_type; /* Pull type defined above */ + A_UINT32 intr_mode; /* Interrupt mode defined above (Input) */ +} wmi_gpio_config_cmd_fixed_param; + +/* WMI_GPIO_OUTPUT_CMDID */ +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_gpio_output_cmd_fixed_param */ + A_UINT32 gpio_num; /* GPIO number to be setup */ + A_UINT32 set; /* Set the GPIO pin*/ +} wmi_gpio_output_cmd_fixed_param; + +/* WMI_GPIO_INPUT_EVENTID */ +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_gpio_input_event_fixed_param */ + A_UINT32 gpio_num; /* GPIO number which changed state */ +} wmi_gpio_input_event_fixed_param; + +/* WMI_P2P_DISC_EVENTID */ +enum { + P2P_DISC_SEARCH_PROB_REQ_HIT = 0, /* prob req hit the p2p find pattern */ + P2P_DISC_SEARCH_PROB_RESP_HIT, /* prob resp hit the p2p find pattern */ +}; + +enum { + P2P_DISC_MODE_SEARCH = 0, /* do search when p2p find offload*/ + P2P_DISC_MODE_LISTEN, /* do listen when p2p find offload*/ + P2P_DISC_MODE_AUTO, /* do listen and search when p2p find offload*/ +}; + +enum { + P2P_DISC_PATTERN_TYPE_BSSID = 0, /* BSSID pattern */ + P2P_DISC_PATTERN_TYPE_DEV_NAME, /* device name pattern */ +}; + +typedef struct { + A_UINT32 vdev_id; + A_UINT32 reason; /* P2P DISC wake up reason*/ +} wmi_p2p_disc_event; + +typedef WMI_GTK_OFFLOAD_STATUS_EVENT_fixed_param WOW_EVENT_INFO_SECTION_GTKIGTK; + +typedef enum { + WMI_FAKE_TXBFER_SEND_NDPA, + WMI_FAKE_TXBFER_SEND_MU, + WMI_FAKE_TXBFER_NDPA_FBTYPE, + WMI_FAKE_TXBFER_NDPA_NCIDX, + WMI_FAKE_TXBFER_NDPA_POLL, + WMI_FAKE_TXBFER_NDPA_BW, + WMI_FAKE_TXBFER_NDPA_PREAMBLE, + WMI_FAKE_TXBFER_NDPA_RATE, + WMI_FAKE_TXBFER_NDP_BW, + WMI_FAKE_TXBFER_NDP_NSS, + WMI_TXBFEE_ENABLE_UPLOAD_H, + WMI_TXBFEE_ENABLE_CAPTURE_H, + WMI_TXBFEE_SET_CBF_TBL, + WMI_TXBFEE_CBF_TBL_LSIG, + WMI_TXBFEE_CBF_TBL_SIGA1, + WMI_TXBFEE_CBF_TBL_SIGA2, + WMI_TXBFEE_CBF_TBL_SIGB, + WMI_TXBFEE_CBF_TBL_PAD, + WMI_TXBFEE_CBF_TBL_DUR, + WMI_TXBFEE_SU_NCIDX, + WMI_TXBFEE_CBIDX, + WMI_TXBFEE_NGIDX, +} WMI_TXBF_PARAM_ID; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_txbf_cmd_fixed_param */ + /** parameter id */ + A_UINT32 param_id; + /** parameter value */ + A_UINT32 param_value; +} wmi_txbf_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_upload_h_hdr */ + A_UINT32 h_length; + A_UINT32 cv_length; +/* This TLV is followed by array of bytes: + * A_UINT8 bufp[]; <-- h_cv info buffer + */ +} wmi_upload_h_hdr; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_capture_h_event_hdr */ + A_UINT32 svd_num; + A_UINT32 tone_num; + A_UINT32 reserved; +} wmi_capture_h_event_hdr; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_avoid_freq_range_desc */ + A_UINT32 start_freq; /* start frequency, not channel center freq */ + A_UINT32 end_freq; /* end frequency */ +} wmi_avoid_freq_range_desc; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_avoid_freq_ranges_event_fixed_param */ + /* bad channel range count, multi range is allowed, 0 means all channel clear */ + A_UINT32 num_freq_ranges; + +/* The TLVs will follow. + * multi range with num_freq_ranges, LTE advance multi carrier, CDMA,etc + * wmi_avoid_freq_range_desc avd_freq_range[]; <-- message buffer, NULL terminated + */ +} wmi_avoid_freq_ranges_event_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_gtk_rekey_fail_event_fixed_param */ + /** Reserved for future use */ + A_UINT32 reserved0; + A_UINT32 vdev_id; +} wmi_gtk_rekey_fail_event_fixed_param; + + +typedef enum WLAN_COEX_EVENT { + WLAN_COEX_EVENT_BT_NONE = 0, + WLAN_COEX_EVENT_BT_A2DP_PROFILE_ADD = 1, + WLAN_COEX_EVENT_BT_A2DP_PROFILE_REMOVE = 2, + WLAN_COEX_EVENT_BT_VOICE_PROFILE_ADD = 3, + WLAN_COEX_EVENT_BT_VOICE_PROFILE_REMOVE = 4, + WLAN_COEX_EVENT_BT_SCAN_START = 5, + WLAN_COEX_EVENT_BT_SCAN_STOP = 6, +}WLAN_COEX_EVENT; + +typedef struct { + A_UINT32 tlv_header; + A_UINT32 coex_profile_evt; //uses the enum values form WLAN_COEX_EVENT +} wmi_coex_bt_activity_event_fixed_param; + +enum wmm_ac_downgrade_policy { + WMM_AC_DOWNGRADE_DEPRIO, + WMM_AC_DOWNGRADE_DROP, + WMM_AC_DOWNGRADE_INVALID, +}; + +/* WMM EDCA Params type */ +#define WMM_PARAM_TYPE_LEGACY 0 +/* Relaxed EDCA parameters for 11ax to be used in case of triggered access */ +#define WMM_PARAM_TYPE_11AX_EDCA 1 + +typedef struct { + A_UINT32 tlv_header; + A_UINT32 cwmin; + A_UINT32 cwmax; + A_UINT32 aifs; + union { + A_UINT32 txoplimit; + A_UINT32 mu_edca_timer; + }; + A_UINT32 acm; + A_UINT32 no_ack; +} wmi_wmm_vparams; + +typedef struct { + A_UINT32 tlv_header; + A_UINT32 vdev_id; + wmi_wmm_vparams wmm_params[4]; /* 0 be, 1 bk, 2 vi, 3 vo */ + A_UINT32 wmm_param_type; /* see WMM_PARAM_TYPE_xxx defs */ +} wmi_vdev_set_wmm_params_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; + A_UINT32 vdev_id; + A_UINT32 gtxRTMask[2]; /* for HT and VHT rate masks */ + A_UINT32 userGtxMask; /* host request for GTX mask */ + A_UINT32 gtxPERThreshold; /* default: 10% */ + A_UINT32 gtxPERMargin; /* default: 2% */ + A_UINT32 gtxTPCstep; /* default: 1 */ + A_UINT32 gtxTPCMin; /* default: 5 */ + A_UINT32 gtxBWMask; /* 20/40/80/160 Mhz */ +} wmi_vdev_set_gtx_params_cmd_fixed_param; + +typedef struct +{ + A_UINT32 tlv_header; + A_UINT32 vdev_id; + A_UINT32 ac; + A_UINT32 medium_time_us; /* per second unit, the Admitted time granted, unit in micro seconds */ + A_UINT32 downgrade_type; +} wmi_vdev_wmm_addts_cmd_fixed_param; + +typedef struct +{ + A_UINT32 tlv_header; + A_UINT32 vdev_id; + A_UINT32 ac; +} wmi_vdev_wmm_delts_cmd_fixed_param; + +/* DEPRECATED */ +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_pdev_dfs_enable_cmd_fixed_param */ + /** Reserved for future use */ + A_UINT32 reserved0; +} wmi_pdev_dfs_enable_cmd_fixed_param; + +/* DEPRECATED */ +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_pdev_dfs_disable_cmd_fixed_param */ + /** pdev_id for identifying the MAC + * See macros starting with WMI_PDEV_ID_ for values. + */ + A_UINT32 pdev_id; +} wmi_pdev_dfs_disable_cmd_fixed_param; + +typedef struct { + /** TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_dfs_phyerr_filter_ena_cmd_fixed_param + */ + A_UINT32 tlv_header; + + /** pdev_id for identifying the MAC + * See macros starting with WMI_PDEV_ID_ for values. + */ + A_UINT32 pdev_id; +} wmi_dfs_phyerr_filter_ena_cmd_fixed_param; + +typedef struct { + /** TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_dfs_phyerr_filter_dis_cmd_fixed_param + */ + A_UINT32 tlv_header; + /** pdev_id for identifying the MAC + * See macros starting with WMI_PDEV_ID_ for values. + */ + A_UINT32 pdev_id; +} wmi_dfs_phyerr_filter_dis_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; + A_UINT32 pdev_id; +} wmi_pdev_dfs_phyerr_offload_enable_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; + A_UINT32 pdev_id; +} wmi_pdev_dfs_phyerr_offload_disable_cmd_fixed_param; + +typedef enum { + QUICK_OCAC = 0, + EXTENSIVE_OCAC, +} WMI_ADFS_OCAC_MODE; + +typedef struct { + A_UINT32 tlv_header; + A_UINT32 vdev_id; + A_UINT32 ocac_mode; /* WMI_ADFS_OCAC_MODE */ + A_UINT32 min_duration_ms; /* in milliseconds */ + A_UINT32 max_duration_ms; /* in milliseconds */ + A_UINT32 chan_freq; /* in MHz */ + A_UINT32 chan_width; /* in MHz */ + A_UINT32 center_freq; /* in MHz */ +} wmi_vdev_adfs_ch_cfg_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; + A_UINT32 vdev_id; +} wmi_vdev_adfs_ocac_abort_cmd_fixed_param; + +typedef enum { + IN_SERVICE_MODE = 0, + OCAC_MODE, +} WMI_DFS_RADAR_DETECTION_MODE; + +typedef struct { + A_UINT32 tlv_header; + A_UINT32 pdev_id; + /* In-service mode or O-CAC mode */ + A_UINT32 detection_mode; /* WMI_DFS_RADAR_DETECTION_MODE */ + A_UINT32 chan_freq; /* in MHz */ + A_UINT32 chan_width; /* in MHz */ + A_UINT32 detector_id; + A_UINT32 segment_id; + A_UINT32 timestamp; + A_UINT32 is_chirp; + A_INT32 freq_offset; /* in MHz */ + A_INT32 sidx; /* segment index (where was the radar within the channel) */ +} wmi_pdev_dfs_radar_detection_event_fixed_param; + +typedef enum { + OCAC_COMPLETE = 0, + OCAC_ABORT, +} WMI_VDEV_OCAC_COMPLETE_STATUS; + +typedef struct { + A_UINT32 tlv_header; + A_UINT32 vdev_id; + A_UINT32 chan_freq; /* in MHz */ + A_UINT32 chan_width; /* in MHz */ + A_UINT32 center_freq; /* in MHz */ + A_UINT32 status; /* WMI_VDEV_OCAC_COMPLETE_STATUS */ +} wmi_vdev_adfs_ocac_complete_event_fixed_param; + +typedef struct { + A_UINT32 tlv_header; + A_UINT32 vdev_id; +} wmi_vdev_dfs_cac_complete_event_fixed_param; + + +/** TDLS COMMANDS */ + +/* WMI_TDLS_SET_STATE_CMDID */ +/* TDLS State */ +enum wmi_tdls_state { + /** TDLS disable */ + WMI_TDLS_DISABLE, + /** TDLS enabled - no firmware connection tracking/notifications */ + WMI_TDLS_ENABLE_PASSIVE, + /** TDLS enabled - with firmware connection tracking/notifications */ + WMI_TDLS_ENABLE_ACTIVE, + /** TDLS enabled - firmware waits for peer mac for connection tracking */ + WMI_TDLS_ENABLE_ACTIVE_EXTERNAL_CONTROL, + /** TDLS enabled - TDLS connection tracking is done in host */ + WMI_TDLS_ENABLE_CONNECTION_TRACKER_IN_HOST, +}; + +/* TDLS Options */ +#define WMI_TDLS_OFFCHAN_EN (1 << 0) /** TDLS Off Channel support */ +#define WMI_TDLS_BUFFER_STA_EN (1 << 1) /** TDLS Buffer STA support */ +#define WMI_TDLS_SLEEP_STA_EN (1 << 2) /** TDLS Sleep STA support (not currently supported) */ + +typedef struct { + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_tdls_set_state_cmd_fixed_param */ + A_UINT32 tlv_header; + /** unique id identifying the VDEV */ + A_UINT32 vdev_id; + /** Enable/Disable TDLS (wmi_tdls_state) */ + A_UINT32 state; + /** Duration (in ms) over which to calculate tx/rx threshold to trigger TDLS Discovery */ + A_UINT32 notification_interval_ms; + /** number of packets OVER which notify/suggest TDLS Discovery: + * if current tx pps counter / notification interval >= threshold + * then a notification will be sent to host to advise TDLS Discovery */ + A_UINT32 tx_discovery_threshold; + /** number of packets UNDER which notify/suggest TDLS Teardown: + * if current tx pps counter / notification interval < threshold + * then a notification will be sent to host to advise TDLS Tear down */ + A_UINT32 tx_teardown_threshold; + /** Absolute RSSI value under which notify/suggest TDLS Teardown */ + A_INT32 rssi_teardown_threshold; + /** Peer RSSI < (AP RSSI + delta) will trigger a teardown */ + A_INT32 rssi_delta; + /** TDLS Option Control + * Off-Channel, Buffer STA, (later)Sleep STA support */ + A_UINT32 tdls_options; + /* Buffering time in number of beacon intervals */ + A_UINT32 tdls_peer_traffic_ind_window; + /* Wait time for PTR frame */ + A_UINT32 tdls_peer_traffic_response_timeout_ms; + /* Self PUAPSD mask */ + A_UINT32 tdls_puapsd_mask; + /* Inactivity timeout */ + A_UINT32 tdls_puapsd_inactivity_time_ms; + /* Max of rx frame during SP */ + A_UINT32 tdls_puapsd_rx_frame_threshold; + /**Duration (in ms) over which to check whether TDLS link needs to be torn down */ + A_UINT32 teardown_notification_ms; + /**STA kickout threshold for TDLS peer */ + A_UINT32 tdls_peer_kickout_threshold; +} wmi_tdls_set_state_cmd_fixed_param; + +/* WMI_TDLS_PEER_UPDATE_CMDID */ + +enum wmi_tdls_peer_state { + /** tx peer TDLS link setup now starting, traffic to DA should be + * paused (except TDLS frames) until state is moved to CONNECTED (or + * TEARDOWN on setup failure) */ + WMI_TDLS_PEER_STATE_PEERING, + /** tx peer TDLS link established, running (all traffic to DA unpaused) */ + WMI_TDLS_PEER_STATE_CONNECTED, + /** tx peer TDLS link tear down started (link paused, any frames + * queued for DA will be requeued back through the AP)*/ + WMI_TDLS_PEER_STATE_TEARDOWN, + /** Add peer mac into connection table */ + WMI_TDLS_PEER_ADD_MAC_ADDR, + /** Remove peer mac from connection table */ + WMI_TDLS_PEER_REMOVE_MAC_ADDR, +}; + +/* NB: These defines are fixed, and cannot be changed without breaking WMI compatibility */ +#define WMI_TDLS_MAX_SUPP_CHANNELS 128 +#define WMI_TDLS_MAX_SUPP_OPER_CLASSES 32 +typedef struct { + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_tdls_peer_capabilities */ + A_UINT32 tlv_header; + /* Peer's QoS Info - for U-APSD */ + /* AC FLAGS - accessed through macros below */ + /* Ack, SP, More Data Ack - accessed through macros below */ + A_UINT32 peer_qos; + /*TDLS Peer's U-APSD Buffer STA Support*/ + A_UINT32 buff_sta_support; + /*TDLS off channel related params */ + A_UINT32 off_chan_support; + A_UINT32 peer_curr_operclass; + A_UINT32 self_curr_operclass; + /* Number of channels available for off channel operation */ + A_UINT32 peer_chan_len; + A_UINT32 peer_operclass_len; + A_UINT8 peer_operclass[WMI_TDLS_MAX_SUPP_OPER_CLASSES]; + /* Is peer initiator or responder of TDLS setup request */ + A_UINT32 is_peer_responder; + /* Preferred off channel number as configured by user */ + A_UINT32 pref_offchan_num; + /* Preferred off channel bandwidth as configured by user */ + A_UINT32 pref_offchan_bw; + + /** Followed by the variable length TLV peer_chan_list: + * wmi_channel peer_chan_list[]. + * Array size would be peer_chan_len. + * This array is intersected channels which is supported by both peer + * and DUT. freq1 in chan_info shall be same as mhz, freq2 shall be 0. + * FW shall compute BW for an offchan based on peer's ht/vht cap + * received in peer_assoc cmd during change STA operation + */ + } wmi_tdls_peer_capabilities; + +#define WMI_TDLS_QOS_VO_FLAG 0 +#define WMI_TDLS_QOS_VI_FLAG 1 +#define WMI_TDLS_QOS_BK_FLAG 2 +#define WMI_TDLS_QOS_BE_FLAG 3 +#define WMI_TDLS_QOS_ACK_FLAG 4 +#define WMI_TDLS_QOS_SP_FLAG 5 +#define WMI_TDLS_QOS_MOREDATA_FLAG 7 + +#define WMI_TDLS_PEER_SET_QOS_FLAG(ppeer_caps,flag) do { \ + (ppeer_caps)->peer_qos |= (1 << flag); \ + } while (0) +#define WMI_TDLS_PEER_GET_QOS_FLAG(ppeer_caps,flag) \ + (((ppeer_caps)->peer_qos & (1 << flag)) >> flag) + +#define WMI_SET_TDLS_PEER_VO_UAPSD(ppeer_caps) \ + WMI_TDLS_PEER_SET_QOS_FLAG(ppeer_caps, WMI_TDLS_QOS_VO_FLAG) +#define WMI_GET_TDLS_PEER_VO_UAPSD(ppeer_caps) \ + WMI_TDLS_PEER_GET_QOS_FLAG(ppeer_caps, WMI_TDLS_QOS_VO_FLAG) +#define WMI_SET_TDLS_PEER_VI_UAPSD(ppeer_caps) \ + WMI_TDLS_PEER_SET_QOS_FLAG(ppeer_caps, WMI_TDLS_QOS_VI_FLAG) +#define WMI_GET_TDLS_PEER_VI_UAPSD(ppeer_caps) \ + WMI_TDLS_PEER_GET_QOS_FLAG(ppeer_caps, WMI_TDLS_QOS_VI_FLAG) +#define WMI_SET_TDLS_PEER_BK_UAPSD(ppeer_caps) \ + WMI_TDLS_PEER_SET_QOS_FLAG(ppeer_caps, WMI_TDLS_QOS_BK_FLAG) +#define WMI_GET_TDLS_PEER_BK_UAPSD(ppeer_caps) \ + WMI_TDLS_PEER_GET_QOS_FLAG(ppeer_caps, WMI_TDLS_QOS_BK_FLAG) +#define WMI_SET_TDLS_PEER_BE_UAPSD(ppeer_caps) \ + WMI_TDLS_PEER_SET_QOS_FLAG(ppeer_caps, WMI_TDLS_QOS_BE_FLAG) +#define WMI_GET_TDLS_PEER_BE_UAPSD(ppeer_caps) \ + WMI_TDLS_PEER_GET_QOS_FLAG(ppeer_caps, WMI_TDLS_QOS_BE_FLAG) +#define WMI_SET_TDLS_PEER_ACK_UAPSD(ppeer_caps) \ + WMI_TDLS_PEER_SET_QOS_FLAG(ppeer_caps, WMI_TDLS_QOS_ACK_FLAG) +#define WMI_GET_TDLS_PEER_ACK_UAPSD(ppeer_caps) \ + WMI_TDLS_PEER_GET_QOS_FLAG(ppeer_caps, WMI_TDLS_QOS_ACK_FLAG) +/* SP has 2 bits */ +#define WMI_SET_TDLS_PEER_SP_UAPSD(ppeer_caps,val) do { \ + (ppeer_caps)->peer_qos |= (((val) & 0x3) << WMI_TDLS_QOS_SP_FLAG); \ + } while (0) +#define WMI_GET_TDLS_PEER_SP_UAPSD(ppeer_caps) \ + (((ppeer_caps)->peer_qos & (0x3 << WMI_TDLS_QOS_SP_FLAG)) >> WMI_TDLS_QOS_SP_FLAG) + +#define WMI_SET_TDLS_PEER_MORE_DATA_ACK_UAPSD(ppeer_caps) \ + WMI_TDLS_PEER_SET_QOS_FLAG(ppeer_caps, WMI_TDLS_QOS_MOREDATA_FLAG) +#define WMI_GET_TDLS_PEER_MORE_DATA_ACK_UAPSD(ppeer_caps) \ + WMI_TDLS_PEER_GET_QOS_FLAG(ppeer_caps, WMI_TDLS_QOS_MOREDATA_FLAG) + + +#define WMI_TDLS_SELF_SET_QOS_FLAG(pset_cmd,flag) do { \ + (pset_cmd)->tdls_puapsd_mask |= (1 << flag); \ + } while (0) +#define WMI_TDLS_SELF_GET_QOS_FLAG(pset_cmd,flag) \ + (((pset_cmd)->tdls_puapsd_mask & (1 << flag)) >> flag) + +#define WMI_SET_TDLS_SELF_VO_UAPSD(pset_cmd) \ + WMI_TDLS_SELF_SET_QOS_FLAG(pset_cmd, WMI_TDLS_QOS_VO_FLAG) +#define WMI_GET_TDLS_SELF_VO_UAPSD(pset_cmd) \ + WMI_TDLS_SELF_GET_QOS_FLAG(pset_cmd, WMI_TDLS_QOS_VO_FLAG) +#define WMI_SET_TDLS_SELF_VI_UAPSD(pset_cmd) \ + WMI_TDLS_SELF_SET_QOS_FLAG(pset_cmd, WMI_TDLS_QOS_VI_FLAG) +#define WMI_GET_TDLS_SELF_VI_UAPSD(pset_cmd) \ + WMI_TDLS_SELF_GET_QOS_FLAG(pset_cmd, WMI_TDLS_QOS_VI_FLAG) +#define WMI_SET_TDLS_SELF_BK_UAPSD(pset_cmd) \ + WMI_TDLS_SELF_SET_QOS_FLAG(pset_cmd, WMI_TDLS_QOS_BK_FLAG) +#define WMI_GET_TDLS_SELF__BK_UAPSD(pset_cmd) \ + WMI_TDLS_SELF_GET_QOS_FLAG(pset_cmd, WMI_TDLS_QOS_BK_FLAG) +#define WMI_SET_TDLS_SELF_BE_UAPSD(pset_cmd) \ + WMI_TDLS_SELF_SET_QOS_FLAG(pset_cmd, WMI_TDLS_QOS_BE_FLAG) +#define WMI_GET_TDLS_SELF_BE_UAPSD(pset_cmd) \ + WMI_TDLS_SELF_GET_QOS_FLAG(pset_cmd, WMI_TDLS_QOS_BE_FLAG) +#define WMI_SET_TDLS_SELF_ACK_UAPSD(pset_cmd) \ + WMI_TDLS_SELF_SET_QOS_FLAG(pset_cmd, WMI_TDLS_QOS_ACK_FLAG) +#define WMI_GET_TDLS_SELF_ACK_UAPSD(pset_cmd) \ + WMI_TDLS_SELF_GET_QOS_FLAG(pset_cmd, WMI_TDLS_QOS_ACK_FLAG) +/* SP has 2 bits */ +#define WMI_SET_TDLS_SELF_SP_UAPSD(pset_cmd,val) do { \ + (pset_cmd)->tdls_puapsd_mask |= (((val) & 0x3) << WMI_TDLS_QOS_SP_FLAG); \ + } while (0) +#define WMI_GET_TDLS_SELF_SP_UAPSD(pset_cmd) \ + (((pset_cmd)->tdls_puapsd_mask & (0x3 << WMI_TDLS_QOS_SP_FLAG)) >> WMI_TDLS_QOS_SP_FLAG) + +#define WMI_SET_TDLS_SELF_MORE_DATA_ACK_UAPSD(pset_cmd) \ + WMI_TDLS_SELF_SET_QOS_FLAG(pset_cmd, WMI_TDLS_QOS_MOREDATA_FLAG) +#define WMI_GET_TDLS_SELF_MORE_DATA_ACK_UAPSD(pset_cmd) \ + WMI_TDLS_SELF_GET_QOS_FLAG(pset_cmd, WMI_TDLS_QOS_MOREDATA_FLAG) + + +typedef struct { + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_tdls_peer_update_cmd_fixed_param */ + A_UINT32 tlv_header; + /** unique id identifying the VDEV */ + A_UINT32 vdev_id; + /** peer MAC address */ + wmi_mac_addr peer_macaddr; + /** new TDLS state for peer (wmi_tdls_peer_state) */ + A_UINT32 peer_state; + /* The TLV for wmi_tdls_peer_capabilities will follow. + * wmi_tdls_peer_capabilities peer_caps; + */ + /** Followed by the variable length TLV chan_info: + * wmi_channel chan_info[] */ +} wmi_tdls_peer_update_cmd_fixed_param; + +/* WMI_TDLS_SET_OFFCHAN_MODE_CMDID */ + + +/* bitmap 20, 40, 80 or 160 MHz wide channel */ +#define WMI_TDLS_OFFCHAN_20MHZ 0x1 /* 20 MHz wide channel */ +#define WMI_TDLS_OFFCHAN_40MHZ 0x2 /* 40 MHz wide channel */ +#define WMI_TDLS_OFFCHAN_80MHZ 0x4 /* 80 MHz wide channel */ +#define WMI_TDLS_OFFCHAN_160MHZ 0x8 /* 160 MHz wide channel */ + + +enum wmi_tdls_offchan_mode { + WMI_TDLS_ENABLE_OFFCHANNEL, + WMI_TDLS_DISABLE_OFFCHANNEL +}; + +typedef struct { + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_tdls_set_offchan_mode_cmd_fixed_param */ + A_UINT32 tlv_header; + /** unique id identifying the VDEV */ + A_UINT32 vdev_id; + /** Enable/Disable TDLS offchannel */ + A_UINT32 offchan_mode; + /** peer MAC address */ + wmi_mac_addr peer_macaddr; + /* Is peer initiator or responder of TDLS setup request */ + A_UINT32 is_peer_responder; + /* off channel number*/ + A_UINT32 offchan_num; + /* off channel bandwidth bitmap, e.g. WMI_OFFCHAN_20MHZ */ + A_UINT32 offchan_bw_bitmap; + /* operating class for offchan */ + A_UINT32 offchan_oper_class; +} wmi_tdls_set_offchan_mode_cmd_fixed_param; + + +/** TDLS EVENTS */ +enum wmi_tdls_peer_notification { + /** tdls discovery recommended for peer (based + * on tx bytes per second > tx_discover threshold) */ + WMI_TDLS_SHOULD_DISCOVER, + /** tdls link tear down recommended for peer + * due to tx bytes per second below tx_teardown_threshold + * NB: this notification sent once */ + WMI_TDLS_SHOULD_TEARDOWN, + /** tx peer TDLS link tear down complete */ + WMI_TDLS_PEER_DISCONNECTED, + /** TDLS/BT role change notification for connection tracker */ + WMI_TDLS_CONNECTION_TRACKER_NOTIFICATION, +}; + +enum wmi_tdls_peer_reason { + /** tdls teardown recommended due to low transmits */ + WMI_TDLS_TEARDOWN_REASON_TX, + /** tdls link tear down recommended due to poor RSSI */ + WMI_TDLS_TEARDOWN_REASON_RSSI, + /** tdls link tear down recommended due to offchannel scan */ + WMI_TDLS_TEARDOWN_REASON_SCAN, + /** tdls peer disconnected due to peer deletion */ + WMI_TDLS_DISCONNECTED_REASON_PEER_DELETE, + /** tdls peer disconnected due to PTR timeout */ + WMI_TDLS_TEARDOWN_REASON_PTR_TIMEOUT, + /** tdls peer disconnected due wrong PTR format */ + WMI_TDLS_TEARDOWN_REASON_BAD_PTR, + /** tdls peer not responding */ + WMI_TDLS_TEARDOWN_REASON_NO_RESPONSE, + /** tdls entered buffer STA role, TDLS connection tracker needs to handle this */ + WMI_TDLS_ENTER_BUF_STA, + /** tdls exited buffer STA role, TDLS connection tracker needs to handle this */ + WMI_TDLS_EXIT_BUF_STA, + /** BT entered busy mode, TDLS connection tracker needs to handle this */ + WMI_TDLS_ENTER_BT_BUSY_MODE, + /** BT exited busy mode, TDLS connection tracker needs to handle this */ + WMI_TDLS_EXIT_BT_BUSY_MODE, + /** TDLS module received a scan start event, TDLS connection tracker needs to handle this */ + WMI_TDLS_SCAN_STARTED_EVENT, + /** TDLS module received a scan complete event, TDLS connection tracker needs to handle this */ + WMI_TDLS_SCAN_COMPLETED_EVENT, +}; + +/* WMI_TDLS_PEER_EVENTID */ +typedef struct { + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_tdls_peer_event_fixed_param */ + A_UINT32 tlv_header; + /** peer MAC address */ + wmi_mac_addr peer_macaddr; + /** TDLS peer status (wmi_tdls_peer_notification)*/ + A_UINT32 peer_status; + /** TDLS peer reason (wmi_tdls_peer_reason) */ + A_UINT32 peer_reason; + /** unique id identifying the VDEV */ + A_UINT32 vdev_id; +} wmi_tdls_peer_event_fixed_param; + +/* NOTE: wmi_vdev_mcc_bcn_intvl_change_event_fixed_param would be deprecated. Please + don't use this for any new implementations */ +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_vdev_mcc_bcn_intvl_change_event_fixed_param */ + /** unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; + /* New beacon interval to be used for the specified VDEV suggested by firmware */ + A_UINT32 new_bcn_intvl; +} wmi_vdev_mcc_bcn_intvl_change_event_fixed_param; + +/* WMI_RESMGR_ADAPTIVE_OCS_ENABLE_DISABLE_CMDID */ +typedef struct { + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_resmgr_adaptive_ocs_enable_disable_cmd_fixed_param */ + A_UINT32 tlv_header; + /** 1: enable fw based adaptive ocs, + * 0: disable fw based adaptive ocs + */ + A_UINT32 enable; + /** This field contains the MAC identifier in order to lookup the appropriate OCS instance. */ + union { + A_UINT32 mac_id; /* OBSOLETE - will be removed once all refs are gone */ + /** pdev_id for identifying the MAC + * See macros starting with WMI_PDEV_ID_ for values. + */ + A_UINT32 pdev_id; + }; +} wmi_resmgr_adaptive_ocs_enable_disable_cmd_fixed_param; + +/* WMI_RESMGR_SET_CHAN_TIME_QUOTA_CMDID */ +typedef struct { + /* Frequency of the channel for which the quota is set */ + A_UINT32 chan_mhz; + /* Requested channel time quota expressed as percentage */ + A_UINT32 channel_time_quota; +} wmi_resmgr_chan_time_quota; + +typedef struct { + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_resmgr_set_chan_time_quota_cmd_fixed_param */ + A_UINT32 tlv_header; + /** number of channel time quota command structures + * (wmi_resmgr_chan_time_quota) 1 or 2 + */ + A_UINT32 num_chans; +/* This TLV is followed by another TLV of array of bytes + * A_UINT8 data[]; + * This data array contains + * num_chans * size of(struct wmi_resmgr_chan_time_quota) + */ +} wmi_resmgr_set_chan_time_quota_cmd_fixed_param; + +/* WMI_RESMGR_SET_CHAN_LATENCY_CMDID */ +typedef struct { + /* Frequency of the channel for which the latency is set */ + A_UINT32 chan_mhz; + /* Requested channel latency in milliseconds */ + A_UINT32 latency; +} wmi_resmgr_chan_latency; + +typedef struct { + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_resmgr_set_chan_latency_cmd_fixed_param */ + A_UINT32 tlv_header; + /** number of channel latency command structures + * (wmi_resmgr_chan_latency) 1 or 2 + */ + A_UINT32 num_chans; +/* This TLV is followed by another TLV of array of bytes + * A_UINT8 data[]; + * This data array contains + * num_chans * size of(struct wmi_resmgr_chan_latency) + */ +} wmi_resmgr_set_chan_latency_cmd_fixed_param; + +/* WMI_STA_SMPS_FORCE_MODE_CMDID */ + +/** STA SMPS Forced Mode */ +typedef enum { + WMI_SMPS_FORCED_MODE_NONE = 0, + WMI_SMPS_FORCED_MODE_DISABLED, + WMI_SMPS_FORCED_MODE_STATIC, + WMI_SMPS_FORCED_MODE_DYNAMIC +} wmi_sta_smps_forced_mode; + +typedef struct { + /** TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_sta_smps_force_mode_cmd_fixed_param */ + A_UINT32 tlv_header; + /** Unique id identifying the VDEV */ + A_UINT32 vdev_id; + /** The mode of SMPS that is to be forced in the FW. */ + A_UINT32 forced_mode; +} wmi_sta_smps_force_mode_cmd_fixed_param; + +/** wlan HB commands */ +#define WMI_WLAN_HB_ITEM_UDP 0x1 +#define WMI_WLAN_HB_ITEM_TCP 0x2 +#define WMI_WLAN_HB_MAX_FILTER_SIZE 32 /* should be equal to WLAN_HB_MAX_FILTER_SIZE, + must be a multiple of 4 bytes */ + +typedef struct { + /** TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_hb_set_enable_cmd_fixed_param */ + A_UINT32 tlv_header; + A_UINT32 vdev_id; + A_UINT32 enable; + A_UINT32 item; + A_UINT32 session; +} wmi_hb_set_enable_cmd_fixed_param; + +typedef struct { + /** TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_hb_set_tcp_params_cmd_fixed_param */ + A_UINT32 tlv_header; + A_UINT32 vdev_id; + A_UINT32 srv_ip; + A_UINT32 dev_ip; + A_UINT32 seq; + A_UINT32 src_port; + A_UINT32 dst_port; + A_UINT32 interval; + A_UINT32 timeout; + A_UINT32 session; + wmi_mac_addr gateway_mac; +} wmi_hb_set_tcp_params_cmd_fixed_param; + +typedef struct { + /** TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_hb_set_tcp_pkt_filter_cmd_fixed_param */ + A_UINT32 tlv_header; + A_UINT32 vdev_id; + A_UINT32 length; + A_UINT32 offset; + A_UINT32 session; + A_UINT8 filter[WMI_WLAN_HB_MAX_FILTER_SIZE]; +} wmi_hb_set_tcp_pkt_filter_cmd_fixed_param; + +typedef struct { + /** TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_hb_set_udp_params_cmd_fixed_param */ + A_UINT32 tlv_header; + A_UINT32 vdev_id; + A_UINT32 srv_ip; + A_UINT32 dev_ip; + A_UINT32 src_port; + A_UINT32 dst_port; + A_UINT32 interval; + A_UINT32 timeout; + A_UINT32 session; + wmi_mac_addr gateway_mac; +} wmi_hb_set_udp_params_cmd_fixed_param; + +typedef struct { + /** TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_hb_set_udp_pkt_filter_cmd_fixed_param */ + A_UINT32 tlv_header; + A_UINT32 vdev_id; + A_UINT32 length; + A_UINT32 offset; + A_UINT32 session; + A_UINT8 filter[WMI_WLAN_HB_MAX_FILTER_SIZE]; +} wmi_hb_set_udp_pkt_filter_cmd_fixed_param; + +/** wlan HB events */ +typedef enum { + WMI_WLAN_HB_REASON_UNKNOWN = 0, + WMI_WLAN_HB_REASON_TCP_TIMEOUT = 1, + WMI_WLAN_HB_REASON_UDP_TIMEOUT = 2, +} WMI_HB_WAKEUP_REASON; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_hb_ind_event_fixed_param */ + A_UINT32 vdev_id; /* unique id identifying the VDEV */ + A_UINT32 session; /* Session ID from driver */ + A_UINT32 reason; /* wakeup reason */ +} wmi_hb_ind_event_fixed_param; + +/** WMI_STA_SMPS_PARAM_CMDID */ +typedef enum { + /** RSSI threshold to enter Dynamic SMPS mode from inactive mode */ + WMI_STA_SMPS_PARAM_UPPER_RSSI_THRESH = 0, + /** RSSI threshold to enter Stalled-D-SMPS mode from D-SMPS mode or + * to enter D-SMPS mode from Stalled-D-SMPS mode */ + WMI_STA_SMPS_PARAM_STALL_RSSI_THRESH = 1, + /** RSSI threshold to disable SMPS modes */ + WMI_STA_SMPS_PARAM_LOWER_RSSI_THRESH = 2, + /** Upper threshold for beacon-RSSI. Used to reduce RX chainmask. */ + WMI_STA_SMPS_PARAM_UPPER_BRSSI_THRESH = 3, + /** Lower threshold for beacon-RSSI. Used to increase RX chainmask. */ + WMI_STA_SMPS_PARAM_LOWER_BRSSI_THRESH = 4, + /** Enable/Disable DTIM 1chRx feature */ + WMI_STA_SMPS_PARAM_DTIM_1CHRX_ENABLE = 5 +} wmi_sta_smps_param; + +typedef struct { + /** TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_sta_smps_param_cmd_fixed_param */ + A_UINT32 tlv_header; + /** Unique id identifying the VDEV */ + A_UINT32 vdev_id; + /** SMPS parameter (see wmi_sta_smps_param) */ + A_UINT32 param; + /** Value of SMPS parameter */ + A_UINT32 value; +} wmi_sta_smps_param_cmd_fixed_param; + +typedef struct { + /** TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_mcc_sched_sta_traffic_stats */ + A_UINT32 tlv_header; + /* TX stats */ + A_UINT32 txBytesPushed; + A_UINT32 txPacketsPushed; + /* RX stats */ + A_UINT32 rxBytesRcvd; + A_UINT32 rxPacketsRcvd; + A_UINT32 rxTimeTotal; + /** peer MAC address */ + wmi_mac_addr peer_macaddr; +} wmi_mcc_sched_sta_traffic_stats; + +typedef struct { + /** TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_mcc_sched_traffic_stats_cmd_fixed_param */ + A_UINT32 tlv_header; + /** Duration over which the host stats were collected */ + A_UINT32 duration; + /** Number of stations filled in following stats array */ + A_UINT32 num_sta; + /* Following this struct are the TLVs: + * wmi_mcc_sched_sta_traffic_stats mcc_sched_sta_traffic_stats_list; + */ +} wmi_mcc_sched_traffic_stats_cmd_fixed_param; + +typedef struct +{ + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_batch_scan_enable_cmd_fixed_param */ + /* unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; + /*Batch scan enable command parameters*/ + A_UINT32 scanInterval; + A_UINT32 numScan2Batch; + A_UINT32 bestNetworks; + A_UINT32 rfBand; + A_UINT32 rtt; +} wmi_batch_scan_enable_cmd_fixed_param; + +typedef struct +{ + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_batch_scan_enabled_event_fixed_param */ + A_UINT32 supportedMscan; +} wmi_batch_scan_enabled_event_fixed_param; + +typedef struct +{ + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_batch_scan_disable_cmd_fixed_param */ + /* unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; + A_UINT32 param; +} wmi_batch_scan_disable_cmd_fixed_param; + +typedef struct +{ + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_batch_scan_trigger_result_cmd_fixed_param */ + /** unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; + A_UINT32 param; +} wmi_batch_scan_trigger_result_cmd_fixed_param; + +typedef struct +{ + A_UINT32 tlv_header; + wmi_mac_addr bssid; /* BSSID */ + wmi_ssid ssid; /* SSID */ + A_UINT32 ch; /* Channel */ + A_UINT32 rssi; /* RSSI or Level */ + /* Timestamp when Network was found. Used to calculate age based on timestamp in GET_RSP msg header */ + A_UINT32 timestamp; +} wmi_batch_scan_result_network_info; + +typedef struct +{ + A_UINT32 tlv_header; + A_UINT32 scanId; /* Scan List ID. */ + /* No of AP in a Scan Result. Should be same as bestNetwork in SET_REQ msg */ + A_UINT32 numNetworksInScanList; + A_UINT32 netWorkStartIndex; /* indicate the start index of network info*/ +} wmi_batch_scan_result_scan_list; + +#define LPI_IE_BITMAP_BSSID 0x00000001 /* if this bit is set, bssid of the scan response frame is sent as the first IE in the data buffer sent to LOWI LP. */ +#define LPI_IE_BITMAP_IS_PROBE 0x00000002 /* send true or false based on scan response frame being a Probe Rsp or not */ +#define LPI_IE_BITMAP_SSID 0x00000004 /* send ssid from received scan response frame */ +#define LPI_IE_BITMAP_RSSI 0x00000008 /* send RSSI value reported by HW for the received scan response after adjusting with noise floor */ +#define LPI_IE_BITMAP_CHAN 0x00000010 /* send channel number from the received scan response */ +#define LPI_IE_BITMAP_AP_TX_PWR 0x00000020 /* send Tx power from TPC IE of scan rsp */ +#define LPI_IE_BITMAP_TX_RATE 0x00000040 /* send rate of the received frame as reported by HW. */ +#define LPI_IE_BITMAP_80211_MC_SUPPORT 0x00000080 /* send true or false based on the received scan rsp was from a 11mc supported AP or not. */ +#define LPI_IE_BITMAP_TSF_TIMER_VALUE 0x00000100 /* send timestamp reported in the received scan rsp frame. */ +#define LPI_IE_BITMAP_AGE_OF_MEASUREMENT 0x00000200 /* (current system time - received time) = duration of time scan rsp frame data is kept in the buffer before sending to LOWI LP. */ +/* + * TEMPORARY alias of incorrect old name the correct name. + * This alias will be removed once all references to the old name have been fixed. + */ +#define LPI_IE_BITMAP_AGE_OF_MESAUREMENT LPI_IE_BITMAP_AGE_OF_MEASUREMENT +#define LPI_IE_BITMAP_CONN_STATUS 0x00000400 /* If an infra STA is active and connected to an AP, true value is sent else false. */ +#define LPI_IE_BITMAP_MSAP_IE 0x00000800 /* info on the vendor specific proprietary IE MSAP */ +#define LPI_IE_BITMAP_SEC_STATUS 0x00001000 /* we indicate true or false based on if the AP has WPA or RSN security enabled */ +#define LPI_IE_BITMAP_DEVICE_TYPE 0x00002000 /* info about the beacons coming from an AP or P2P or NAN device. */ +#define LPI_IE_BITMAP_CHAN_IS_PASSIVE 0x00004000 /* info on whether the scan rsp was received from a passive channel */ +#define LPI_IE_BITMAP_DWELL_TIME 0x00008000 /* send the scan dwell time of the channel on which the current scan rsp frame was received. */ +#define LPI_IE_BITMAP_BAND_CENTER_FREQ1 0x00010000 /* the center frequencies in case AP is supporting wider channels than 20 MHz */ +#define LPI_IE_BITMAP_BAND_CENTER_FREQ2 0x00020000 /* same as above */ +#define LPI_IE_BITMAP_PHY_MODE 0x00040000 /* PHY mode indicates a, b, ,g, ac and other combinations */ +#define LPI_IE_BITMAP_SCAN_MODULE_ID 0x00080000 /* scan module id indicates the scan client who originated the scan */ +#define LPI_IE_BITMAP_SCAN_ID 0x00100000 /* extscan inserts the scan cycle count for this value; other scan clients can insert the scan id of the scan, if needed. */ +#define LPI_IE_BITMAP_FLAGS 0x00200000 /* reserved as a bitmap to indicate more scan information; one such use being to indicate if the on-going scan is interrupted or not */ +#define LPI_IE_BITMAP_CACHING_REQD 0x00400000 /* extscan will use this field to indicate if this frame info needs to be cached in LOWI LP or not */ +#define LPI_IE_BITMAP_REPORT_CONTEXT_HUB 0x00800000 /* extscan will use this field to indicate to LOWI LP whether to report result to context hub or not. */ +#define LPI_IE_BITMAP_CHRE_ESS 0x010000000 /* ESS capability info for CHRE */ +#define LPI_IE_BITMAP_CHRE_SEC_MODE 0x020000000 /* Security capability info for CHRE */ +#define LPI_IE_BITMAP_CHRE_SUPPORTED_RATE 0x040000000 /* Hightest MCS corresponding NCC for TX and RX */ +#define LPI_IE_BITMAP_COUNTRY_STRING 0x080000000 /* send country string inside Country IE to LOWI LP */ +#define LPI_IE_BITMAP_ALL 0xFFFFFFFF + +typedef struct { + A_UINT32 tlv_header; + /**A_BOOL indicates LPI mgmt snooping enable/disable*/ + A_UINT32 enable; + /**LPI snooping mode*/ + A_UINT32 snooping_mode; + /** LPI interested IEs in snooping context */ + A_UINT32 ie_bitmap; +} wmi_lpi_mgmt_snooping_config_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_start_scan_cmd_fixed_param */ + /** Scan ID */ + A_UINT32 scan_id; + /** Scan requestor ID */ + A_UINT32 scan_req_id; + /** VDEV id(interface) that is requesting scan */ + A_UINT32 vdev_id; + /** LPI interested IEs in scan context */ + A_UINT32 ie_bitmap; + /** Scan Priority, input to scan scheduler */ + A_UINT32 scan_priority; + /** dwell time in msec on active channels */ + A_UINT32 dwell_time_active; + /** dwell time in msec on passive channels */ + A_UINT32 dwell_time_passive; + /** min time in msec on the BSS channel,only valid if atleast one VDEV is active*/ + A_UINT32 min_rest_time; + /** max rest time in msec on the BSS channel,only valid if at least one VDEV is active*/ + /** the scanner will rest on the bss channel at least min_rest_time. after min_rest_time the scanner + * will start checking for tx/rx activity on all VDEVs. if there is no activity the scanner will + * switch to off channel. if there is activity the scanner will let the radio on the bss channel + * until max_rest_time expires.at max_rest_time scanner will switch to off channel + * irrespective of activity. activity is determined by the idle_time parameter. + */ + A_UINT32 max_rest_time; + /** time before sending next set of probe requests. + * The scanner keeps repeating probe requests transmission with period specified by repeat_probe_time. + * The number of probe requests specified depends on the ssid_list and bssid_list + */ + A_UINT32 repeat_probe_time; + /** time in msec between 2 consequetive probe requests with in a set. */ + A_UINT32 probe_spacing_time; + /** data inactivity time in msec on bss channel that will be used by scanner for measuring the inactivity */ + A_UINT32 idle_time; + /** maximum time in msec allowed for scan */ + A_UINT32 max_scan_time; + /** delay in msec before sending first probe request after switching to a channel */ + A_UINT32 probe_delay; + /** Scan control flags */ + A_UINT32 scan_ctrl_flags; + /** Burst duration time in msec*/ + A_UINT32 burst_duration; + + /** # if channels to scan. In the TLV channel_list[] */ + A_UINT32 num_chan; + /** number of bssids. In the TLV bssid_list[] */ + A_UINT32 num_bssid; + /** number of ssid. In the TLV ssid_list[] */ + A_UINT32 num_ssids; + /** number of bytes in ie data. In the TLV ie_data[] */ + A_UINT32 ie_len; + +/** + * TLV (tag length value) parameters follow the scan_cmd + * structure. The TLV's are: + * A_UINT32 channel_list[]; + * wmi_ssid ssid_list[]; + * wmi_mac_addr bssid_list[]; + * A_UINT8 ie_data[]; + */ +} wmi_lpi_start_scan_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_stop_scan_cmd_fixed_param */ + /** Scan requestor ID */ + A_UINT32 scan_req_id; + /** Scan ID */ + A_UINT32 scan_id; + /** + * Req Type + * req_type should be WMI_SCAN_STOP_ONE, WMI_SCN_STOP_VAP_ALL or WMI_SCAN_STOP_ALL + * WMI_SCAN_STOP_ONE indicates to stop a specific scan with scan_id + * WMI_SCN_STOP_VAP_ALL indicates to stop all scan requests on a specific vDev with vdev_id + * WMI_SCAN_STOP_ALL indicates to stop all scan requests in both Scheduler's queue and Scan Engine + */ + A_UINT32 req_type; + /** + * vDev ID + * used when req_type equals to WMI_SCN_STOP_VAP_ALL, it indexed the vDev on which to stop the scan + */ + A_UINT32 vdev_id; +} wmi_lpi_stop_scan_cmd_fixed_param; + +typedef enum { + WMI_LPI_DEVICE_TYPE_AP = 1, + WMI_LPI_DEVICE_TYPE_P2P = 2, + WMI_LPI_DEVICE_TYPE_NAN = 3, +} wmi_lpi_device_type; + +typedef struct +{ + A_UINT32 tlv_header; + /** Scan requestor ID */ + A_UINT32 scan_req_id; + A_UINT32 ie_bitmap; + A_UINT32 data_len; +} wmi_lpi_result_event_fixed_param; + +typedef enum { + /** User scan Request completed */ + WMI_LPI_STATUS_SCAN_REQ_COMPLED = 0, + /** User Request was never serviced */ + WMI_LPI_STATUS_DROPPED_REQ = 1, + /** Illegal channel Req */ + WMI_LPI_STATUS_ILLEGAL_CHAN_REQ = 2, + /** Illegal Operation Req */ + WMI_LPI_STATUS_ILLEGAL_OPER_REQ = 3, + /** Request Aborted */ + WMI_LPI_STATUS_REQ_ABORTED = 4, + /** Request Timed Out */ + WMI_LPI_STATUS_REQ_TIME_OUT = 5, + /** Medium Busy, already there + * is a scan is going on */ + WMI_LPI_STATUS_MEDIUM_BUSY = 6, + /** Extscan is the scan client whose scan complete event is triggered */ + WMI_LPI_STATUS_EXTSCAN_CYCLE_AND_SCAN_REQ_COMPLETED = 7, +} wmi_lpi_staus; + +typedef struct +{ + A_UINT32 tlv_header; + wmi_lpi_staus status; + /** Scan requestor ID */ + A_UINT32 scan_req_id; +} wmi_lpi_status_event_fixed_param; + + +typedef struct +{ + A_UINT32 tlv_header; + wmi_mac_addr bssid; + wmi_ssid ssid; + A_UINT32 freq; + A_UINT32 rssi; + A_UINT32 vdev_id; +} wmi_lpi_handoff_event_fixed_param; +typedef struct +{ + A_UINT32 tlv_header; + A_UINT32 timestamp; /*timestamp of batch scan event*/ + A_UINT32 numScanLists; /*number of scan in this event*/ + A_UINT32 isLastResult; /*is this event a last event of the whole batch scan*/ +} wmi_batch_scan_result_event_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_p2p_noa_event_fixed_param */ + A_UINT32 vdev_id; +/* This TLV is followed by p2p_noa_info for vdev : + * wmi_p2p_noa_info p2p_noa_info; + */ +} wmi_p2p_noa_event_fixed_param; + +#define WMI_RFKILL_CFG_RADIO_LEVEL_OFFSET 6 +#define WMI_RFKILL_CFG_RADIO_LEVEL_MASK 0x1 + +#define WMI_RFKILL_CFG_GPIO_PIN_NUM_OFFSET 0 +#define WMI_RFKILL_CFG_GPIO_PIN_NUM_MASK 0x3f + +#define WMI_RFKILL_CFG_PIN_AS_GPIO_OFFSET 7 +#define WMI_RFKILL_CFG_PIN_AS_GPIO_MASK 0xf + +typedef struct { + /** TLV tag and len; tag equals + * */ + A_UINT32 tlv_header; + /** gpip pin number */ + A_UINT32 gpio_pin_num; + /** gpio interupt type */ + A_UINT32 int_type; + /** RF radio status */ + A_UINT32 radio_state; +} wmi_rfkill_mode_param; + +typedef enum { + WMI_SET_LED_SYS_POWEROFF, + WMI_SET_LED_SYS_S3_SUSPEND, + WMI_SET_LED_SYS_S4_S5, + WMI_SET_LED_SYS_DRIVER_DISABLE, + WMI_SET_LED_SYS_WAKEUP, + WMI_SET_LED_SYS_ALWAYS_ON, /* just for test! */ + WMI_SET_LED_SYS_POWERON, +} wmi_led_sys_state_param; + +typedef enum { + WMI_CONFIG_LED_TO_VDD = 0, + WMI_CONFIG_LED_TO_GND = 1, +} wmi_config_led_connect_type; + +typedef enum { + WMI_CONFIG_LED_NOT_WITH_BT = 0, + WMI_CONFIG_LED_WITH_BT = 1, +} wmi_config_led_with_bt_flag; + +typedef enum { + WMI_CONFIG_LED_DISABLE = 0, + WMI_CONFIG_LED_ENABLE = 1, +} wmi_config_led_enable_flag; + +typedef enum { + WMI_CONFIG_LED_HIGH_UNSPECIFIED = 0, + WMI_CONFIG_LED_HIGH_OFF = 1, + WMI_CONFIG_LED_HIGH_ON = 2, +} wmi_config_led_on_flag; + +typedef enum { + WMI_CONFIG_LED_UNSPECIFIED = 0, + WMI_CONFIG_LED_ON = 1, + WMI_CONFIG_LED_OFF = 2, + WMI_CONFIG_LED_DIM = 3, + WMI_CONFIG_LED_BLINK = 4, + WMI_CONFIG_LED_TXRX = 5, +} wmi_config_led_operation_type; + +typedef struct { + /** TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_pdev_set_led_config_cmd_fixed_param */ + A_UINT32 tlv_header; + /* Set GPIO pin */ + A_UINT32 led_gpio_pin; + /* Set connect type defined in wmi_config_led_connect_type */ + A_UINT32 connect_type; + /* Set flag defined in wmi_config_led_with_bt_flag*/ + A_UINT32 with_bt; + /* Set LED enablement defined in wmi_config_led_enable_flag */ + A_UINT32 led_enable; + /** pdev_id for identifying the MAC + * See macros starting with WMI_PDEV_ID_ for values. + */ + A_UINT32 pdev_id; + /* see wmi_config_led_operation_type enum */ + A_UINT32 led_operation_type; + /* see wmi_config_led_on_flag enum */ + A_UINT32 led_on_flag; /* configure high/low on/off sense */ + A_UINT32 led_on_interval; /* for blink function; unit: ms */ + A_UINT32 led_off_interval; /* for blink function; unit: ms */ + A_UINT32 led_repeat_cnt; /* for blink function: how many blinks */ +} wmi_pdev_set_led_config_cmd_fixed_param; + +#define WMI_WNTS_CFG_GPIO_PIN_NUM_OFFSET 0 +#define WMI_WNTS_CFG_GPIO_PIN_NUM_MASK 0xff + +/** WMI_PEER_INFO_REQ_CMDID + * Request FW to provide peer info */ +typedef struct { + /** TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_peer_info_req_cmd_fixed_param */ + A_UINT32 tlv_header; + /** In order to get the peer info for a single peer, host shall + * issue the peer_mac_address of that peer. For getting the + * info all peers, the host shall issue 0xFFFFFFFF as the mac + * address. The firmware will return the peer info for all the + * peers on the specified vdev_id */ + wmi_mac_addr peer_mac_address; + /** vdev id */ + A_UINT32 vdev_id; +} wmi_peer_info_req_cmd_fixed_param; + +typedef struct { + /** TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_peer_info */ + A_UINT32 tlv_header; + /** mac addr of the peer */ + wmi_mac_addr peer_mac_address; + /** data_rate of the peer */ + A_UINT32 data_rate; + /** rssi of the peer */ + A_UINT32 rssi; + /** tx fail count */ + A_UINT32 tx_fail_cnt; +} wmi_peer_info; + +/** FW response with the peer info */ +typedef struct { + /** TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_peer_info_event_fixed_param */ + A_UINT32 tlv_header; + /** number of peers in peer_info */ + A_UINT32 num_peers; + /* Set to 1 only if vdev_id field is valid */ + A_UINT32 valid_vdev_id; + /* VDEV to which the peer belongs to */ + A_UINT32 vdev_id; + /* This TLV is followed by another TLV of array of structs + * wmi_peer_info peer_info[]; + */ +} wmi_peer_info_event_fixed_param; + +/** WMI_PEER_ANTDIV_INFO_REQ_CMDID + * Request FW to provide peer info */ +typedef struct { + /** TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_peer_antdiv_info_req_cmd_fixed_param */ + A_UINT32 tlv_header; + /** In order to get the peer antdiv info for a single peer, host shall + * issue the peer_mac_address of that peer. For getting the + * info all peers, the host shall issue 0xFFFFFFFF as the mac + * address. The firmware will return the peer info for all the + * peers on the specified vdev_id */ + wmi_mac_addr peer_mac_address; + /** vdev id */ + A_UINT32 vdev_id; +} wmi_peer_antdiv_info_req_cmd_fixed_param; + +/** FW response with the peer antdiv info */ +typedef struct { + /** TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_peer_antdiv_info_event_fixed_param */ + A_UINT32 tlv_header; + /** number of peers in peer_info */ + A_UINT32 num_peers; + /* VDEV to which the peer belongs to */ + A_UINT32 vdev_id; + /* This TLV is followed by another TLV of array of structs + * wmi_peer_antdiv_info peer_antdiv_info[]; + */ +} wmi_peer_antdiv_info_event_fixed_param; + +typedef struct { + /** TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_peer_antdiv_info */ + A_UINT32 tlv_header; + /** mac addr of the peer */ + wmi_mac_addr peer_mac_address; + /** per chain rssi of the peer, for up to 8 chains. + * Each chain's entry reports the RSSI for different bandwidths: + * bits 7:0 -> primary 20 MHz + * bits 15:8 -> secondary 20 MHz of 40 MHz channel (if applicable) + * bits 23:16 -> secondary 40 MHz of 80 MHz channel (if applicable) + * bits 31:24 -> secondary 80 MHz of 160 MHz channel (if applicable) + * Each of these 8-bit RSSI reports is in dB units, with respect to + * the noise floor. + * 0x80 means invalid. + * All unused bytes within used chain_rssi indices shall be set to 0x80. + * All unused chain_rssi indices shall be set to 0x80808080. + */ + A_INT32 chain_rssi[8]; +} wmi_peer_antdiv_info; + +typedef enum { + WMI_PEER_IND_SMPS = 0x0, /* spatial multiplexing power save */ + WMI_PEER_IND_OMN, /* operating mode notification */ + WMI_PEER_IND_OMI, /* operating mode indication */ +} WMI_PEER_OPER_MODE_IND; + +typedef struct { + /** TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_peer_oper_mode_change */ + A_UINT32 tlv_header; + /** mac addr of the peer */ + wmi_mac_addr peer_mac_address; + /** Peer type indication WMI_PEER_OPER_MODE_IND. */ + A_UINT32 ind_type; + /** new_rxnss valid for all peer_operating mode ind. */ + A_UINT32 new_rxnss; + /** new_bw valid for peer_operating mode ind. OMN/OMI + * value of this bw is as per 11ax/ac standard: + * 0 = 20MHz,1 = 40MHz, 2= 80MHz, 3 = 160MHz + */ + A_UINT32 new_bw; + /** new_txnss valid for peer_operating mode ind. OMI */ + A_UINT32 new_txnss; + /** new_disablemu: disable mu mode + * valid for peer_operating mode ind. OMI + */ + A_UINT32 new_disablemu; +} wmi_peer_oper_mode_change_event_fixed_param; + +/** FW response when tx failure count has reached threshold + * for a peer */ +typedef struct { + /** TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_peer_tx_fail_cnt_thr_event_fixed_param */ + A_UINT32 tlv_header; + /** vdev id*/ + A_UINT32 vdev_id; + /** mac address */ + wmi_mac_addr peer_mac_address; + /** tx failure count - will eventually be removed and not used */ + A_UINT32 tx_fail_cnt; + /** seq number of the nth tx_fail_event */ + A_UINT32 seq_no; +} wmi_peer_tx_fail_cnt_thr_event_fixed_param; + +enum wmi_rmc_mode { + /** Disable RMC */ + WMI_RMC_MODE_DISABLED = 0, + /** Enable RMC */ + WMI_RMC_MODE_ENABLED = 1, +}; + +/** Enable RMC transmitter functionality. Upon + * receiving this, the FW shall mutlicast frames with + * reliablity. This is a vendor + * proprietary feature. */ +typedef struct { + /** TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_rmc_set_mode_cmd_fixed_param */ + A_UINT32 tlv_header; + /** vdev id*/ + A_UINT32 vdev_id; + /** enable_rmc contains values from enum wmi_rmc_mode; + * Default value: 0 (disabled) */ + A_UINT32 enable_rmc; +} wmi_rmc_set_mode_cmd_fixed_param; + +/** Configure transmission periodicity of action frames in a + * RMC network for the multicast transmitter */ +typedef struct { + /** TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_rmc_set_action_period_cmd_fixed_param */ + A_UINT32 tlv_header; + /** vdev id */ + A_UINT32 vdev_id; + /** time period in milliseconds. Default: 300 ms. + An action frame indicating the current leader is transmitted by the + RMC transmitter once every 'periodity_msec' */ + A_UINT32 periodicity_msec; +} wmi_rmc_set_action_period_cmd_fixed_param; + +/** Optimise Leader selection process in RMC functionality. For + * Enhancement/Debug purposes only */ +typedef struct { + /** TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_rmc_config_cmd_fixed_param */ + A_UINT32 tlv_header; + /** vdev id */ + A_UINT32 vdev_id; + /** flags :: + * 0x0001 - Enable beacon averaging + * 0x0002 - Force leader selection + * 0x0004 - Enable Timer based leader switch + * 0x0008 - Use qos/NULL based for multicast reliability */ + A_UINT32 flags; + /** control leader change timeperiod (in seconds) */ + A_UINT32 peridocity_leader_switch; + /** control activity timeout value for data rx (in seconds) */ + A_UINT32 data_activity_timeout; + /** mac address of leader */ + wmi_mac_addr forced_leader_mac_addr; +} wmi_rmc_config_cmd_fixed_param; + +/** MHF is generally implemented in + * the kernel. To decrease system power consumption, the + * driver can enable offloading this to the chipset. In + * order for the offload, the firmware needs the routing table. + * The host shall plumb the routing table into FW. The firmware + * shall perform an IP address lookup and forward the packet to + * the next hop using next hop's mac address. This is a vendor + * proprietary feature. */ +enum wmi_mhf_ofl_mode { + /** Disable MHF offload */ + WMI_MHF_OFL_MODE_DISABLED = 0, + /** Enable MHF offload */ + WMI_MHF_OFL_MODE_ENABLED = 1, +}; + +typedef struct { + /** TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_mhf_offload_set_mode_cmd_fixed_param */ + A_UINT32 tlv_header; + /** vdev id*/ + A_UINT32 vdev_id; + /** enable_mhf_ofl contains values from enum + * wmi_mhf_ofl_mode; Default value: 0 (disabled) */ + A_UINT32 enable_mhf_ofl; +} wmi_mhf_offload_set_mode_cmd_fixed_param; + +enum wmi_mhf_ofl_table_action { + /** Create MHF offload table in FW */ + WMI_MHF_OFL_TBL_CREATE = 0, + /** Append to existing MHF offload table */ + WMI_MHF_OFL_TBL_APPEND = 1, + /** Flush entire MHF offload table in FW */ + WMI_MHF_OFL_TBL_FLUSH = 2, +}; + +typedef struct { + /** TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_mhf_offload_plumb_routing_table_cmd_fixed_param */ + A_UINT32 tlv_header; + /** vdev id*/ + A_UINT32 vdev_id; + /** action corresponds to values from enum + * wmi_mhf_ofl_table_action */ + A_UINT32 action; + /** number of entries in the table */ + A_UINT32 num_entries; +/** Followed by the variable length TLV + * wmi_mhf_offload_routing_table_entry entries[] */ +} wmi_mhf_offload_plumb_routing_table_cmd; + +typedef struct { + /** TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_mhf_offload_routing_table_entry */ + A_UINT32 tlv_header; + /** Destination node's IP address */ + WMI_IPV4_ADDR dest_ipv4_addr; + /** Next hop node's MAC address */ + wmi_mac_addr next_hop_mac_addr; +} wmi_mhf_offload_routing_table_entry; + +typedef struct { + /** tlv tag and len, tag equals + * WMITLV_TAG_STRUC_wmi_dfs_radar_event */ + A_UINT32 tlv_header; + + /** full 64 tsf timestamp get from MAC tsf timer indicates + * the time that the radar event uploading to host, split + * it to high 32 bit and lower 32 bit in fulltsf_high and + * full_tsf_low + */ + A_UINT32 upload_fullts_low; + A_UINT32 upload_fullts_high; + + /** timestamp indicates the time when DFS pulse is detected + * equal to ppdu_end_ts - radar_pusle_summary_ts_offset + */ + A_UINT32 pulse_detect_ts; + + /** the duaration of the pulse in us */ + A_UINT32 pulse_duration; + + /** the center frequency of the radar pulse detected, KHz */ + A_UINT32 pulse_center_freq; + + /** bandwidth of current DFS channel, MHz */ + A_UINT32 ch_bandwidth; + + /** center channel frequency1 of current DFS channel, MHz */ + A_UINT16 ch_center_freq1; + + /** center channel frequency2 of current DFS channel, MHz, + * reserved for 160 BW mode + */ + A_UINT16 ch_center_freq2; + + /** flag to indicate if this pulse is chirp */ + A_UINT8 pulse_is_chirp; + + /** RSSI recorded in the ppdu */ + A_UINT8 rssi; + + /** extened RSSI info */ + A_UINT8 rssi_ext; + + union { + A_UINT8 pmac_id; /* OBSOLETE - will be removed once all refs are gone */ + /** pdev_id for identifying the MAC + * See macros starting with WMI_PDEV_ID_ for values. + */ + A_UINT8 pdev_id; + }; + + /** index of peak magnitude bin (signed) */ + A_INT32 peak_sidx; + +} wmi_dfs_radar_event_fixed_param; + +enum { + /* DEFAULT - target chooses what action to take, based on its thermal + * management policy + * Targets which throttle tx (and potentially rx) based on thermal + * management thresholds specified by the host will shut down tx + * if the temperature exceeds upper_thresh_degreeC. + * Targets which simply inform the host about threshold breaches will + * send a notification message to the host if the temperature exceeds + * upper_thresh_degreeC. + * Conversely, if the temperature was above upper_thresh_degreeC but + * then drops to below lower_threshold_degreeC, the target will either + * resume tx, or notify the host. + */ + WMI_THERMAL_MGMT_ACTION_DEFAULT = 0, + /* HALT_TRAFFIC - + * If the temperature rises above upper_thresh_degreeC, the target will + * halt tx. + * If the temperature falls back below lower_thresh_degreeC, the target + * will resume tx. + */ + WMI_THERMAL_MGMT_ACTION_HALT_TRAFFIC = 1, + /* NOTIFY_HOST - the target will notify the host if the temperature + * either rises above upper_thresh_degreeC or falls below + * lower_thresh_degreeC. + */ + WMI_THERMAL_MGMT_ACTION_NOTIFY_HOST = 2, +}; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_thermal_mgmt_cmd_fixed_param */ + + /*Thermal thresholds*/ + A_UINT32 lower_thresh_degreeC; /* in degree C*/ + A_UINT32 upper_thresh_degreeC; /* in degree C*/ + + /*Enable/Disable Thermal Monitoring for Mitigation*/ + A_UINT32 enable; + + /* action: what the target should do when a thermal upper/lower threshold + * is crossed. + * Refer to the WMI_THERMAL_MGMT_ACTION enum. + */ + A_UINT32 action; + A_UINT32 threshold_warning_degreeC; + A_UINT32 sample_rate_ms; +} wmi_thermal_mgmt_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_thermal_mgmt_event_fixed_param */ + + A_UINT32 temperature_degreeC;/* temperature in degree C*/ +} wmi_thermal_mgmt_event_fixed_param; + +/** +* This command is sent from WLAN host driver to firmware to + * request firmware to configure auto shutdown timer in fw + * 0 - Disable <1-19600>-Enabled and timer value is seconds (86400 seconds = 1 day maximum> + */ +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_host_auto_shutdown_cfg_cmd_param */ + A_UINT32 timer_value; /** timer value; 0=disable */ +} wmi_host_auto_shutdown_cfg_cmd_fixed_param; + +enum wmi_host_auto_shutdown_reason { + WMI_HOST_AUTO_SHUTDOWN_REASON_UNKNOWN = 0, + WMI_HOST_AUTO_SHUTDOWN_REASON_TIMER_EXPIRY = 1, + WMI_HOST_AUTO_SHUTDOWN_REASON_MAX, +}; + +/* WMI_HOST_AUTO_SHUTDOWN_EVENTID */ +typedef struct{ + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_host_auto_shutdown_event_fixed_param */ + A_UINT32 shutdown_reason; /* value: wmi_host_auto_shutdown_reason */ +} wmi_host_auto_shutdown_event_fixed_param; + + + +/** New WMI command to support TPC CHAINMASK ADJUSTMENT ACCORDING TO a set of conditions specified in the command. + * fw will save c tpc offset/chainmask along with conditions and adjust tpc/chainmask when condition meet. + * This command is only used by some customer for verification test. It is not for end-user. + * + * array of wmi_tpc_chainmask_config structures are passed with the command to specify multiple conditions. + * + * The set of conditions include bt status, stbc status, band, phy_mode, 1stream/2streams, channel, rate. when all these conditions meet, + * the output(tpc_offset,chainmask) will be applied on per packet basis. ack_offset is applied based on channel condtion only. When multiple + * conditions has the same channel ,then the first ack_offset will be applied. It is better for host driver to make sure the + * pair is unique. + * + * the conditions (bt status, stbc status, band, phy_mode, 1steam/2streams, tpc_offset, ack_offset, chainmask) are combinedi into a single word + * called basic_config_info by bitmap + * to save memory. And channel & rate info will be tracked by 'channel' field and 'rate0', 'rate1' field because of its large combination. + * + * 'rate bit' or 'channel bit' field of basic_config_info indicate validity of the channel and rate fields.if rate bit is 0 then the rate field + * is ignored. + * disable will remove preious conditions from FW. + * conditions from the later command will over write conditions stored from a previous command. + * + */ + +#define WMI_TPC_CHAINMASK_CONFIG_BT_ON_OFF 0 /** dont' care the bt status */ +#define WMI_TPC_CHAINMASK_CONFIG_BT_ON 1 /** apply only when bt on */ +#define WMI_TPC_CHAINMASK_CONFIG_BT_OFF 2 /** apply only when bt off */ +#define WMI_TPC_CHAINMASK_CONFIG_BT_RESV1 3 /** reserved */ + +#define WMI_TPC_CHAINMASK_CONFIG_CHAINMASK_DONT_CARE 0 /** don't care the chainmask */ +#define WMI_TPC_CHAINMASK_CONFIG_CHAINMASK_CHAIN0 1 /** force to use Chain0 to send */ +#define WMI_TPC_CHAINMASK_CONFIG_CHAINMASK_CHAIN1 2 /** force to use Chain1 to send */ +#define WMI_TPC_CHAINMASK_CONFIG_CHAINMASK_CHAIN0_CHAIN1 3 /** force to use Chain0 & Chain1 to send */ + +#define WMI_TPC_CHAINMASK_CONFIG_STBC_ON_OFF 0 /** don't care about stbc */ +#define WMI_TPC_CHAINMASK_CONFIG_STBC_ON 1 /** apply only when stbc on */ +#define WMI_TPC_CHAINMASK_CONFIG_STBC_OFF 2 /** apply only when stbc off */ +#define WMI_TPC_CHAINMASK_CONFIG_STBC_RESV1 3 /** reserved */ + +#define WMI_TPC_CHAINMASK_CONFIG_BAND_2G 0 /** 2G */ +#define WMI_TPC_CHAINMASK_CONFIG_BAND_5G 1 /** 5G */ + +#define WMI_TPC_CHAINMASK_CONFIG_PHY_MODE_11B_2G 0 /** 11b 2G */ +#define WMI_TPC_CHAINMASK_CONFIG_PHY_MODE_11G_2G 1 /** 11g 2G */ +#define WMI_TPC_CHAINMASK_CONFIG_PHY_MODE_11N_2G 2 /** 11n 2G */ +#define WMI_TPC_CHAINMASK_CONFIG_PHY_MODE_11N_11AC_2G 3 /** 11n + 11ac 2G */ +#define WMI_TPC_CHAINMASK_CONFIG_PHY_MODE_11A_5G 4 /** 11a 5G */ +#define WMI_TPC_CHAINMASK_CONFIG_PHY_MODE_11N_5G 5 /** 11n 5G */ +#define WMI_TPC_CHAINMASK_CONFIG_PHY_MODE_11AC_5G 6 /** 11ac 5G */ +#define WMI_TPC_CHAINMASK_CONFIG_PHY_MODE_11N_11AC_5G 7 /** 11n + 11ac 5G */ + +#define WMI_TPC_CHAINMASK_CONFIG_STREAM_1 0 /** 1 stream */ +#define WMI_TPC_CHAINMASK_CONFIG_STREAM_2 1 /** 2 streams */ + +#define WMI_TPC_CHAINMASK_CONFIG_CHANNEL_OFF 0 /** channel field is ignored */ +#define WMI_TPC_CHAINMASK_CONFIG_CHANNEL_ON 1 /** channel field needs to be checked */ + +#define WMI_TPC_CHAINMASK_CONFIG_RATE_OFF 0 /** rate field is ignored */ +#define WMI_TPC_CHAINMASK_CONFIG_RATE_ON 1 /** rate field needs to be checked */ + +/** Bit map definition for basic_config_info starts */ +#define WMI_TPC_CHAINMASK_CONFIG_TPC_OFFSET_S 0 +#define WMI_TPC_CHAINMASK_CONFIG_TPC_OFFSET (0x1f << WMI_TPC_CHAINMASK_CONFIG_TPC_OFFSET_S) +#define WMI_TPC_CHAINMASK_CONFIG_TPC_OFFSET_GET(x) WMI_F_MS(x,WMI_TPC_CHAINMASK_CONFIG_TPC_OFFSET) +#define WMI_TPC_CHAINMASK_CONFIG_TPC_OFFSET_SET(x,z) WMI_F_RMW(x,(z) & 0x1f,WMI_TPC_CHAINMASK_CONFIG_TPC_OFFSET) + +#define WMI_TPC_CHAINMASK_CONFIG_ACK_OFFSET_S 5 +#define WMI_TPC_CHAINMASK_CONFIG_ACK_OFFSET (0x1f << WMI_TPC_CHAINMASK_CONFIG_ACK_OFFSET_S) +#define WMI_TPC_CHAINMASK_CONFIG_ACK_OFFSET_GET(x) WMI_F_MS(x,WMI_TPC_CHAINMASK_CONFIG_ACK_OFFSET) +#define WMI_TPC_CHAINMASK_CONFIG_ACK_OFFSET_SET(x,z) WMI_F_RMW(x, (z) & 0x1f, WMI_TPC_CHAINMASK_CONFIG_ACK_OFFSET) + +#define WMI_TPC_CHAINMASK_CONFIG_CHAINMASK_S 10 +#define WMI_TPC_CHAINMASK_CONFIG_CHAINMASK (0x3 << WMI_TPC_CHAINMASK_CONFIG_CHAINMASK_S) +#define WMI_TPC_CHAINMASK_CONFIG_CHAINMASK_GET(x) WMI_F_MS(x,WMI_TPC_CHAINMASK_CONFIG_CHAINMASK) +#define WMI_TPC_CHAINMASK_CONFIG_CHAINMASK_SET(x,z) WMI_F_RMW(x, (z) & 0x3, WMI_TPC_CHAINMASK_CONFIG_CHAINMASK) + +#define WMI_TPC_CHAINMASK_CONFIG_BT_S 12 +#define WMI_TPC_CHAINMASK_CONFIG_BT (0x3 << WMI_TPC_CHAINMASK_CONFIG_BT_S) +#define WMI_TPC_CHAINMASK_CONFIG_BT_GET(x) WMI_F_MS(x,WMI_TPC_CHAINMASK_CONFIG_BT) +#define WMI_TPC_CHAINMASK_CONFIG_BT_SET(x,z) WMI_F_RMW(x, (z) & 0x3, WMI_TPC_CHAINMASK_CONFIG_BT) + +#define WMI_TPC_CHAINMASK_CONFIG_STBC_S 14 +#define WMI_TPC_CHAINMASK_CONFIG_STBC (0x3 << WMI_TPC_CHAINMASK_CONFIG_STBC_S) +#define WMI_TPC_CHAINMASK_CONFIG_STBC_GET(x) WMI_F_MS(x,WMI_TPC_CHAINMASK_CONFIG_STBC) +#define WMI_TPC_CHAINMASK_CONFIG_STBC_SET(x,z) WMI_F_RMW(x, (z) & 0x3, WMI_TPC_CHAINMASK_CONFIG_STBC) + +#define WMI_TPC_CHAINMASK_CONFIG_BAND_S 16 +#define WMI_TPC_CHAINMASK_CONFIG_BAND (0x1 << WMI_TPC_CHAINMASK_CONFIG_BAND_S) +#define WMI_TPC_CHAINMASK_CONFIG_BAND_GET(x) WMI_F_MS(x,WMI_TPC_CHAINMASK_CONFIG_BAND) +#define WMI_TPC_CHAINMASK_CONFIG_BAND_SET(x,z) WMI_F_RMW(x, (z) & 0x1, WMI_TPC_CHAINMASK_CONFIG_BAND) + +#define WMI_TPC_CHAINMASK_CONFIG_STREAM_S 17 +#define WMI_TPC_CHAINMASK_CONFIG_STREAM (0x1 << WMI_TPC_CHAINMASK_CONFIG_STREAM_S) +#define WMI_TPC_CHAINMASK_CONFIG_STREAM_GET(x) WMI_F_MS(x,WMI_TPC_CHAINMASK_CONFIG_STREAM) +#define WMI_TPC_CHAINMASK_CONFIG_STREAM_SET(x,z) WMI_F_RMW(x, (z) & 0x1, WMI_TPC_CHAINMASK_CONFIG_STREAM) + +#define WMI_TPC_CHAINMASK_CONFIG_PHY_MODE_S 18 +#define WMI_TPC_CHAINMASK_CONFIG_PHY_MODE (0x7 << WMI_TPC_CHAINMASK_CONFIG_PHY_MODE_S) +#define WMI_TPC_CHAINMASK_CONFIG_PHY_MODE_GET(x) WMI_F_MS(x,WMI_TPC_CHAINMASK_CONFIG_PHY_MODE) +#define WMI_TPC_CHAINAMSK_CONFIG_PHY_MODE_SET(x,z) WMI_F_RMW(x, (z) & 0x7, WMI_TPC_CHAINMASK_CONFIG_PHY_MODE) + +#define WMI_TPC_CHAINMASK_CONFIG_CHANNEL_S 21 +/* + * The deprecated old name (WMI_TPC_CHAINMASK_CONFIG_CHANNEL_EXIST) + * is temporarily maintained as an alias for the correct name + * (WMI_TPC_CHAINMASK_CONFIG_CHANNEL) + */ +#define WMI_TPC_CHAINMASK_CONFIG_CHANNEL_EXIST WMI_TPC_CHAINMASK_CONFIG_CHANNEL +#define WMI_TPC_CHAINMASK_CONFIG_CHANNEL (0x1 << WMI_TPC_CHAINMASK_CONFIG_CHANNEL_S) +#define WMI_TPC_CHAINMASK_CONFIG_CHANNEL_GET(x) WMI_F_MS(x,WMI_TPC_CHAINMASK_CONFIG_CHANNEL) +#define WMI_TPC_CHAINMASK_CONFIG_CHANNEL_SET(x,z) WMI_F_RMW(x, (z) & 0x1, WMI_TPC_CHAINMASK_CONFIG_CHANNEL) + +#define WMI_TPC_CHAINMASK_CONFIG_RATE_S 22 +/* + * The deprecated old name (WMI_TPC_CHAINMASK_CONFIG_RATE_EXIST) + * is temporarily maintained as an alias for the correct name + * (WMI_TPC_CHAINMASK_CONFIG_RATE) + */ +#define WMI_TPC_CHAINMASK_CONFIG_RATE_EXIST WMI_TPC_CHAINMASK_CONFIG_RATE +#define WMI_TPC_CHAINMASK_CONFIG_RATE (0x1 << WMI_TPC_CHAINMASK_CONFIG_RATE_S) +#define WMI_TPC_CHAINMASK_CONFIG_RATE_GET(x) WMI_F_MS(x, WMI_TPC_CHAINMASK_CONFIG_RATE) +#define WMI_TPC_CHAINMASK_CONFIG_RATE_SET(x,z) WMI_F_RMW(x, (z) & 0x1, WMI_TPC_CHAINMASK_CONFIG_RATE) + +/** Bit map definition for basic_config_info ends */ + +typedef struct{ + A_UINT32 tlv_header; + /** Basic condition defined as bit map above, bitmap is chosen to save memory. + * Bit0 ~ Bit4: tpc offset which will be adjusted if condtion matches, the unit is 0.5dB. bit4 indicates signed + * Bit5 ~ Bit9: ack offset which will be adjusted if condtion matches, the unit is 0.5dB. bit9 indicates signed + * Bit10 ~ Bit11: chainmask b'00: don't care, b'01: force to use chain0, b'10: force to use chain1, b'11: force to use chain0&chain1 + * Bit12 ~ Bit13: bt condition b'00: don't care, b'01: apply only when bt on, b'10: apply only when bt off, b'11: reserved + * Bit14 ~ Bit15: stbc condition b'00: don't care, b'01: apply only when stbc on, b'10: apply only when stbc off, b'11: reserved + * Bit16 : band condition b'0: 2G, b'1: 5G + * Bit17 : stream condition: b'0: 1 stream, b'1: 2 streams + * Bit18 ~ Bit20: phy mode condition: b'000: 11b 2g, b'001: 11g 2g, b'010: 11n 2g, b'011: 11n+11ac 2g, b'100: 11a, b'101: 11n 5g, b'110: 11ac 5g, b'111: 11n+11ac 5g + * Bit21 : channel bit, if this bit is 0, then the following channel field is ignored + * Bit22 : rate bit, if this bit is 0, then the following rate0&rate1 is ignored. + * Bit23 ~ Bit31: reserved + */ + A_UINT32 basic_config_info; + + /** channel mapping bit rule: The lower bit corresponds with smaller channel. + * it depends on Bit14 of basic_config_info + * Total 24 channels for 5G + * 36 40 44 48 52 56 60 64 100 104 108 112 116 120 124 128 132 136 140 149 153 157 161 165 + * Total 14 channels for 2G + * 1 ~ 14 + */ + A_UINT32 channel; + + /** rate mapping bit rule: The lower bit corresponds with lower rate. + * it depends on Bit16 ~ Bit18 of basic_config_info, "phy mode condition" + * Legacy rates , 11b, 11g, 11A + * 11n one stream (ht20, ht40) 8+8 + * 11n two streams (ht20, ht40) 8+8 + * 11ac one stream (vht20, vht40, vht80) 10+10+10 + * 11ac two streams (vht20, vht40, vht80) 10+10+10 + */ + A_UINT32 rate0; + /** For example, for 11b, when rate0 equals 0x3, it means if actual_rate in [ "1Mbps", "2Mbps"] connection, the rate condition is true. + * For example, for 11g/11a, when rate0 equals 0xf0,it means "54Mbps", "48Mbps", "36Mbps", "24Mb's" is selected, while "18Mbps", "12Mbps", "9Mbps", "6Mbps" is not selected + */ + + /** only used for "11n+11ac" combined phy_mode, (WMI_TPC_CHAINMASK_CONFIG_PHY_MODE_11N_11AC_2G , WMI_TPC_CHAINMASK_CONFIG_PHY_MODE_11N_11AC_5G) in this case, 11n rates begins on rate0, while 11ac rates begins on rate1 + */ + A_UINT32 rate1; +} wmi_tpc_chainmask_config; + +#define WMI_TPC_CHAINMASK_CONFIG_DISABLE 0 /** control the off for the tpc & chainmask*/ +#define WMI_TPC_CHAINMASK_CONFIG_ENABLE 1 /** control the on for the tpc & chainmask*/ + +typedef struct{ + A_UINT32 tlv_header; + A_UINT32 enable; /** enable to set tpc & chainmask when condtions meet, 0: disabled, 1: enabled. */ + A_UINT32 num_tpc_chainmask_configs; + /** following this structure is num_tpc_chainmask_configs number of wmi_tpc_chainmask_config */ +} wmi_tpc_chainmask_config_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_oem_dma_ring_cfg_req_fixed_param */ + A_UINT32 pdev_id; + /** + * Bits 31:0: base address of ring [31:0] + */ + A_UINT32 base_addr_lo; + /** + * Bits 3:0: base address of ring [35:32] + * Bits 31:4: reserved + */ + A_UINT32 base_addr_hi; + /** + * Bits 31:0: address of head index [31:0] + */ + A_UINT32 head_idx_addr_lo; + /** + * Bits 3:0: address of head index [35:32] + * Bits 31:4: reserved + */ + A_UINT32 head_idx_addr_hi; + /** + * Bits 31:0: address of tail index [31:0] + */ + A_UINT32 tail_idx_addr_lo; + /** + * Bits 3:0: address of tail index [35:32] + * Bits 31:4: reserved + */ + A_UINT32 tail_idx_addr_hi; + A_UINT32 num_ptr; /** Number of pointers in the ring */ +} wmi_oem_dma_ring_cfg_req_fixed_param; + +#define WMI_OEM_DMA_RING_ADDR_LO_S 0 +#define WMI_OEM_DMA_RING_ADDR_LO 0xffffffff + +#define WMI_OEM_DMA_RING_ADDR_LO_GET(dword) WMI_F_MS(dword, WMI_OEM_DMA_RING_ADDR_LO) +#define WMI_OEM_DMA_RING_ADDR_LO_SET(dword, val) WMI_F_RMW(dword, val, WMI_OEM_DMA_RING_ADDR_LO) + +#define WMI_OEM_DMA_RING_ADDR_HI_S 0 +#define WMI_OEM_DMA_RING_ADDR_HI 0xf + +#define WMI_OEM_DMA_RING_ADDR_HI_GET(dword) WMI_F_MS(dword, WMI_OEM_DMA_RING_ADDR_HI) +#define WMI_OEM_DMA_RING_ADDR_HI_SET(dword, val) WMI_F_RMW(dword, val, WMI_OEM_DMA_RING_ADDR_HI) + +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_oem_dma_ring_cfg_rsp_fixed_param */ + A_UINT32 pdev_id; + A_UINT32 cfg_status; /** Configuration status; see A_STATUS */ +} wmi_oem_dma_ring_cfg_rsp_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_oem_indirect_data */ + A_UINT32 pdev_id; /** ID of pdev whose OEM DMA ring produced the data */ + /** + * Bits 31:0: address of data [31:0] + */ + A_UINT32 addr_lo; + /** + * Bits 3:0: address of data [35:32] + * Bits 11:4: reserved + * Bits 31:12: opaque host context data [19:0] + */ + A_UINT32 addr_hi; + A_UINT32 len; /** Length of data in bytes */ +} wmi_oem_indirect_data; + +#define WMI_OEM_DMA_DATA_ADDR_LO_S 0 +#define WMI_OEM_DMA_DATA_ADDR_LO 0xffffffff + +#define WMI_OEM_DMA_DATA_ADDR_LO_GET(dword) WMI_F_MS(dword, WMI_OEM_DMA_DATA_ADDR_LO) +#define WMI_OEM_DMA_DATA_ADDR_LO_SET(dword, val) WMI_F_RMW(dword, val, WMI_OEM_DMA_DATA_ADDR_LO) + +#define WMI_OEM_DMA_DATA_ADDR_HI_S 0 +#define WMI_OEM_DMA_DATA_ADDR_HI 0xf + +#define WMI_OEM_DMA_DATA_ADDR_HI_GET(dword) WMI_F_MS(dword, WMI_OEM_DMA_DATA_ADDR_HI) +#define WMI_OEM_DMA_DATA_ADDR_HI_SET(dword, val) WMI_F_RMW(dword, val, WMI_OEM_DMA_DATA_ADDR_HI) + +#define WMI_OEM_DMA_DATA_ADDR_HI_HOST_DATA_S 12 +#define WMI_OEM_DMA_DATA_ADDR_HI_HOST_DATA 0xfffff + +#define WMI_OEM_DMA_DATA_ADDR_HI_HOST_DATA_GET(dword) WMI_F_MS(dword, WMI_OEM_DMA_DATA_ADDR_HI_HOST_DATA) +#define WMI_OEM_DMA_DATA_ADDR_HI_HOST_DATA_SET(dword, val) WMI_F_RMW(dword, val, WMI_OEM_DMA_DATA_ADDR_HI_HOST_DATA) + +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_oem_dma_buf_release_hdr */ + A_UINT32 pdev_id; /** ID of pdev whose OEM DMA ring produced the data */ +} wmi_oem_dma_buf_release_fixed_param; + +typedef struct { + /** + * Bits 31:0: address of data [31:0] + */ + A_UINT32 addr_lo; + /** + * Bits 3:0: address of data [35:32] + * Bits 11:4: reserved + * Bits 31:12: host context data [19:0] + */ + A_UINT32 addr_hi; +} wmi_oem_dma_buf_release_entry; + +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_nan_cmd_param */ + A_UINT32 data_len; /** length in byte of data[]. */ +/* This structure is used to send REQ binary blobs +* from application/service to firmware where Host drv is pass through . +* Following this structure is the TLV: +* A_UINT8 data[]; <-- length in byte given by field data_len. +*/ +} wmi_nan_cmd_param; + +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_nan_event_hdr */ + A_UINT32 data_len; /** length in byte of data[]. */ +/* This structure is used to send REQ binary blobs +* from firmware to application/service where Host drv is pass through . +* Following this structure is the TLV: +* A_UINT8 data[]; <-- length in byte given by field data_len. +*/ +} wmi_nan_event_hdr; + +/** + * Event to indicate NAN discovery interface created + */ +typedef struct { + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_nan_disc_iface_created_event_fixed_param */ + A_UINT32 tlv_header; + /** Unique id identifying the VDEV */ + A_UINT32 vdev_id; + /** NAN interface MAC address */ + wmi_mac_addr nan_interface_macaddr; +} wmi_nan_disc_iface_created_event_fixed_param_PROTOTYPE; + +#define wmi_nan_disc_iface_created_event_fixed_param wmi_nan_disc_iface_created_event_fixed_param_PROTOTYPE + +/** + * Event to indicate NAN discovery interface deleted + */ +typedef struct { + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_nan_disc_iface_deleted_event_fixed_param */ + A_UINT32 tlv_header; + /** Unique id identifying the VDEV */ + A_UINT32 vdev_id; +} wmi_nan_disc_iface_deleted_event_fixed_param_PROTOTYPE; + +#define wmi_nan_disc_iface_deleted_event_fixed_param wmi_nan_disc_iface_deleted_event_fixed_param_PROTOTYPE + +/** + * Event to indicate NAN device started new cluster + */ +typedef struct { + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_nan_started_cluster_event_fixed_param */ + A_UINT32 tlv_header; + /** Unique id identifying the VDEV */ + A_UINT32 vdev_id; + /** NAN Cluster ID */ + A_UINT32 nan_cluster_id; +} wmi_nan_started_cluster_event_fixed_param_PROTOTYPE; + +#define wmi_nan_started_cluster_event_fixed_param wmi_nan_started_cluster_event_fixed_param_PROTOTYPE + +/** + * Event to indicate NAN device joined to cluster + */ +typedef struct { + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_nan_joined_cluster_event_fixed_param */ + A_UINT32 tlv_header; + /** Unique id identifying the VDEV */ + A_UINT32 vdev_id; + /** NAN Cluster ID */ + A_UINT32 nan_cluster_id; +} wmi_nan_joined_cluster_event_fixed_param_PROTOTYPE; + +#define wmi_nan_joined_cluster_event_fixed_param wmi_nan_joined_cluster_event_fixed_param_PROTOTYPE + +/** NAN DATA CMD's */ + +/** + * NAN Data get capabilities req + */ +typedef struct { + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_ndi_get_cap_req_fixed_param */ + A_UINT32 tlv_header; + /** unique id generated in upper layer for the transaction */ + A_UINT32 transaction_id; +} wmi_ndi_get_cap_req_fixed_param_PROTOTYPE; + +#define wmi_ndi_get_cap_req_fixed_param wmi_ndi_get_cap_req_fixed_param_PROTOTYPE + +/** + * NDP Response code + */ +typedef enum { + NDP_RSP_CODE_REQUEST_ACCEPT = 0x00, + NDP_RSP_CODE_REQUEST_REJECT = 0x01, + NDP_RSP_CODE_REQUEST_DEFER = 0x02, +} wmi_ndp_rsp_code_PROTOTYPE; + +#define wmi_ndp_rsp_code wmi_ndp_rsp_code_PROTOTYPE + +/** + * NDP Channel configuration type + */ +typedef enum { + WMI_NDP_CHANNEL_NOT_REQUESTED = 0, /* Channel will not configured */ + WMI_NDP_REQUEST_CHANNEL_SETUP = 1, /* Channel will be provided and is optional/hint */ + WMI_NDP_FORCE_CHANNEL_SETUP = 2/* NDP must start on the provided channel */ +} wmi_ndp_channel_cfg_PROTOTYPE; + +#define wmi_ndp_channel_cfg wmi_ndp_channel_cfg_PROTOTYPE + +/** + * NDP Initiator requesting a data session + */ +typedef struct { + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_ndp_initiator_req_fixed_param */ + A_UINT32 tlv_header; + /** Unique id identifying the VDEV */ + A_UINT32 vdev_id; + /** unique id generated in upper layer for the transaction */ + A_UINT32 transaction_id; + /** Unique Instance Id identifying the Responder's service */ + A_UINT32 service_instance_id; + /** Discovery MAC addr of the publisher/peer */ + wmi_mac_addr peer_discovery_mac_addr; + /** Actual number of bytes in TLV ndp_cfg */ + A_UINT32 ndp_cfg_len; + /** Actual number of bytes in TLV ndp_app_info */ + A_UINT32 ndp_app_info_len; + /** NDP channel configuration type defined in wmi_ndp_channel_cfg */ + A_UINT32 ndp_channel_cfg; + /** NAN Cipher Suite Shared Key */ + A_UINT32 nan_csid; + /** Actual number of bytes in TLV ndp_pmk */ + A_UINT32 nan_pmk_len; + /** Actual number of bytes in TLV ndp_passphrase */ + A_UINT32 nan_passphrase_len; + /** Actual number of bytes in TLV nan_servicename */ + A_UINT32 nan_servicename_len; + /** + * TLV (tag length value) parameters follow the ndp_initiator_req + * structure. The TLV's are: + * wmi_channel channel; + * A_UINT8 ndp_cfg[]; + * A_UINT8 ndp_app_info[]; + * A_UINT8 ndp_pmk[]; + * A_INT8 ndp_passphrase[]; + * A_INT8 nan_servicename[]; + */ +} wmi_ndp_initiator_req_fixed_param_PROTOTYPE; + +#define wmi_ndp_initiator_req_fixed_param wmi_ndp_initiator_req_fixed_param_PROTOTYPE + +/** + * Initiate a data response on the responder side + * for data request indication from the peer + */ +typedef struct { + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_ndp_responder_req_fixed_param */ + A_UINT32 tlv_header; + /** Unique id identifying the VDEV */ + A_UINT32 vdev_id; + /** unique id generated in upper layer for the transaction */ + A_UINT32 transaction_id; + /** + * Unique token Id generated on the initiator/responder + * side used for a NDP session between two NAN devices + */ + A_UINT32 ndp_instance_id; + /** Response Code defined in wmi_ndp_rsp_code */ + A_UINT32 rsp_code; + /** Number of bytes in TLV ndp_cfg */ + A_UINT32 ndp_cfg_len; + /** Number of bytes in TLV ndp_app_info */ + A_UINT32 ndp_app_info_len; + /** NAN Cipher Suite Shared Key */ + A_UINT32 nan_csid; + /** Actual number of bytes in TLV ndp_pmk */ + A_UINT32 nan_pmk_len; + /** Actual number of bytes in TLV ndp_passphrase */ + A_UINT32 nan_passphrase_len; + /** Actual number of bytes in TLV nan_servicename */ + A_UINT32 nan_servicename_len; + /** + * TLV (tag length value) parameters follow the ndp_responder_req + * structure. The TLV's are: + * A_UINT8 ndp_cfg[]; + * A_UINT8 ndp_app_info[]; + * A_UINT8 ndp_pmk[]; + * A_INT8 ndp_passphrase[]; + * A_INT8 nan_servicename[]; + */ +} wmi_ndp_responder_req_fixed_param_PROTOTYPE; + +#define wmi_ndp_responder_req_fixed_param wmi_ndp_responder_req_fixed_param_PROTOTYPE + +/** + * NDP end type + */ +typedef enum { + WMI_NDP_END_TYPE_UNSPECIFIED = 0x00, + WMI_NDP_END_TYPE_PEER_UNAVAILABLE = 0x01, + WMI_NDP_END_TYPE_OTA_FRAME = 0x02, +} wmi_ndp_end_type_PROTOTYPE; + +#define wmi_ndp_end_type wmi_ndp_end_type_PROTOTYPE + +/** + * NDP end reason code + */ +typedef enum { + WMI_NDP_END_REASON_UNSPECIFIED = 0x00, + WMI_NDP_END_REASON_INACTIVITY = 0x01, + WMI_NDP_END_REASON_PEER_DATA_END = 0x02, +} wmi_ndp_end_reason_code_PROTOTYPE; + +#define wmi_ndp_end_reason_code wmi_ndp_end_reason_code_PROTOTYPE + +/** + * NDP end request + */ +typedef struct { + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_ndp_end_req */ + A_UINT32 tlv_header; + /** NDP instance id */ + A_UINT32 ndp_instance_id; +} wmi_ndp_end_req_PROTOTYPE; + +#define wmi_ndp_end_req wmi_ndp_end_req_PROTOTYPE + +/** + * NDP End request + */ +typedef struct { + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_ndp_end_req_fixed_param */ + A_UINT32 tlv_header; + /** unique id generated in upper layer for the transaction */ + A_UINT32 transaction_id; + /** + * TLV (tag length value) parameters follow the ndp_end_req + * structure. The TLV's are: + * wmi_ndp_end_req ndp_end_req_list[]; + */ +} wmi_ndp_end_req_fixed_param_PROTOTYPE; + +#define wmi_ndp_end_req_fixed_param wmi_ndp_end_req_fixed_param_PROTOTYPE + +/* NAN DATA RSP EVENTS */ + +/** + * Event to indicate NAN Data Interface capabilities cmd + */ +typedef struct { + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_ndi_cap_rsp_event_fixed_param */ + A_UINT32 tlv_header; + /** Copy of transaction_id received in wmi_ndi_get_cap_req */ + A_UINT32 transaction_id; + /** Max ndi interface support */ + A_UINT32 max_ndi_interfaces; + /** Max ndp sessions can support */ + A_UINT32 max_ndp_sessions; + /** Max number of peer's per ndi */ + A_UINT32 max_peers_per_ndi; + /** which combination of bands is supported - see NAN_DATA_SUPPORTED_BAND enums */ + A_UINT32 nan_data_supported_bands; +} wmi_ndi_cap_rsp_event_fixed_param_PROTOTYPE; + +#define wmi_ndi_cap_rsp_event_fixed_param wmi_ndi_cap_rsp_event_fixed_param_PROTOTYPE + +/** + * NDP command response code + */ +typedef enum { + NDP_CMD_RSP_STATUS_SUCCESS = 0x00, + NDP_CMD_RSP_STATUS_ERROR = 0x01, +} wmi_ndp_cmd_rsp_status_PROTOTYPE; + +#define wmi_ndp_cmd_rsp_status wmi_ndp_cmd_rsp_status_PROTOTYPE + +/** + * Event response for wmi_ndp_initiator_req + */ +typedef struct { + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_ndp_initiator_rsp_event_fixed_param */ + A_UINT32 tlv_header; + /** Unique id identifying the VDEV */ + A_UINT32 vdev_id; + /** Copy of transaction_id received in wmi_ndp_initiator_req */ + A_UINT32 transaction_id; + /** Response status defined in wmi_ndp_cmd_rsp_status*/ + A_UINT32 rsp_status; + A_UINT32 reason_code; + /** + * Unique token Id generated on the initiator/responder + * side used for a NDP session between two NAN devices + */ + A_UINT32 ndp_instance_id; +} wmi_ndp_initiator_rsp_event_fixed_param_PROTOTYPE; + +#define wmi_ndp_initiator_rsp_event_fixed_param wmi_ndp_initiator_rsp_event_fixed_param_PROTOTYPE + +/** + * Event response for wmi_ndp_responder_req cmd + */ +typedef struct { + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_ndp_responder_rsp_event_fixed_param */ + A_UINT32 tlv_header; + /** Unique id identifying the VDEV */ + A_UINT32 vdev_id; + /** Copy of transaction_id received in wmi_ndp_responder_req */ + A_UINT32 transaction_id; + /** Response status defined in wmi_ndp_cmd_rsp_status*/ + A_UINT32 rsp_status; + A_UINT32 reason_code; + /** + * Unique token Id generated on the initiator/responder + * side used for a NDP session between two NAN devices + */ + A_UINT32 ndp_instance_id; + /** NDI mac address of the peer */ + wmi_mac_addr peer_ndi_mac_addr; + /** Host can create peer if this entry is TRUE */ + A_UINT32 create_peer; +} wmi_ndp_responder_rsp_event_fixed_param_PROTOTYPE; + +#define wmi_ndp_responder_rsp_event_fixed_param wmi_ndp_responder_rsp_event_fixed_param_PROTOTYPE +/** + * Active ndp instance id + */ +typedef struct { + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_active_ndp_instance_id */ + A_UINT32 tlv_header; + /** NDP instance id */ + A_UINT32 ndp_instance_id; +} wmi_active_ndp_instance_id_PROTOTYPE; + +#define wmi_active_ndp_instance_id wmi_active_ndp_instance_id_PROTOTYPE + +/** + * NDP end response per ndi + */ +typedef struct { + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_ndp_end_rsp_per_ndi */ + A_UINT32 tlv_header; + /** Unique id identifying the VDEV */ + A_UINT32 vdev_id; + /** Peer MAC addr */ + wmi_mac_addr peer_mac_addr; + /** Number of active ndps on this ndi */ + A_UINT32 num_active_ndps_on_ndi; +} wmi_ndp_end_rsp_per_ndi_PROTOTYPE; + +#define wmi_ndp_end_rsp_per_ndi wmi_ndp_end_rsp_per_ndi_PROTOTYPE + +/** + * Event response for wmi_ndp_end_req cmd + */ +typedef struct { + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_ndp_end_rsp_event_fixed_param */ + A_UINT32 tlv_header; + /** Copy of transaction_id received in wmi_ndp_end_req */ + A_UINT32 transaction_id; + /** Response status defined in wmi_ndp_cmd_rsp_status*/ + A_UINT32 rsp_status; + A_UINT32 reason_code; + /** + * TLV (tag length value) parameters follow the ndp_end_rsp + * structure. The TLV's are: + * wmi_ndp_end_rsp_per_ndi ndp_end_rsp_per_ndis[]; + * wmi_active_ndp_instance_id active_ndp_instances_id[]; + */ +} wmi_ndp_end_rsp_event_fixed_param_PROTOTYPE; + +#define wmi_ndp_end_rsp_event_fixed_param wmi_ndp_end_rsp_event_fixed_param_PROTOTYPE + +/** NAN DATA EVENTS */ + +/** + * NDP self role + */ +typedef enum { + WMI_NDP_INITIATOR_ROLE, + WMI_NDP_RESPONDER_ROLE, +} wmi_ndp_self_role_PROTOTYPE; + +#define wmi_ndp_self_role wmi_ndp_self_role_PROTOTYPE + +/** + * NDP accept policy + */ +typedef enum { + WMI_NDP_ACCEPT_POLICY_NONE, + WMI_NDP_ACCEPT_POLICY_ALL, +} wmi_ndp_accept_policy_PROTOTYPE; + +#define wmi_ndp_accept_policy wmi_ndp_accept_policy_PROTOTYPE + +/** + * Event indication received on the responder side when a NDP Initiator request/ + * NDP session is initiated on the Initiator side (self role will be NDP_RESPONDER_ROLE) + * + * Event indication received on the initiator side when a + * NDP responder request on the Initiator side (self role will be NDP_INITIATOR_ROLE) + */ +typedef struct { + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_ndp_indication_event_fixed_param */ + A_UINT32 tlv_header; + /** Unique id identifying the VDEV */ + A_UINT32 vdev_id; + /** Self NDP Role defined in wmi_ndp_self_role */ + A_UINT32 self_ndp_role; + /** Accept policy defined in wmi_ndp_accept_policy */ + A_UINT32 accept_policy; + /** Unique Instance Id corresponding to a service/session. */ + A_UINT32 service_instance_id; + /** Discovery MAC addr of the peer/initiator */ + wmi_mac_addr peer_discovery_mac_addr; + /** NDI mac address of the peer */ + wmi_mac_addr peer_ndi_mac_addr; + /** + * Unique token Id generated on the initiator/responder + * side used for a NDP session between two NAN devices + */ + A_UINT32 ndp_instance_id; + /** Number of bytes in TLV wmi_ndp_cfg */ + A_UINT32 ndp_cfg_len; + /** Number of bytes in TLV wmi_ndp_app_info */ + A_UINT32 ndp_app_info_len; + /** Peer NAN Cipher Suite Shared Key */ + A_UINT32 nan_csid; + /** Actual number of bytes in TLV nan_scid */ + A_UINT32 nan_scid_len; + /** Self NDI mac address */ + wmi_mac_addr self_ndi_mac_addr; + /** + * TLV (tag length value) parameters follow the ndp_indication + * structure. The TLV's are: + * A_UINT8 ndp_cfg[]; + * A_UINT8 ndp_app_info[]; + * A_UINT8 nan_scid[]; + */ +} wmi_ndp_indication_event_fixed_param_PROTOTYPE; + +#define wmi_ndp_indication_event_fixed_param wmi_ndp_indication_event_fixed_param_PROTOTYPE + +/** + * Event indication of data confirm is received on both + * initiator and responder side confirming a NDP session + */ +typedef struct { + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_ndp_confirm_event_fixed_param */ + A_UINT32 tlv_header; + /** Unique id identifying the VDEV */ + A_UINT32 vdev_id; + /** + * Unique token Id generated on the initiator/responder + * side used for a NDP session between two NAN devices + */ + A_UINT32 ndp_instance_id; + /** NDI mac address of the peer (required to derive target ipv6 address) */ + wmi_mac_addr peer_ndi_mac_addr; + /** Response Code defined in wmi_ndp_rsp_code */ + A_UINT32 rsp_code; + /** Number of bytes in TLV wmi_ndp_cfg */ + A_UINT32 ndp_cfg_len; + /** Number of bytes in TLV wmi_ndp_app_info */ + A_UINT32 ndp_app_info_len; + /** Reason Code */ + A_UINT32 reason_code; + /** Number of active ndps on this peer */ + A_UINT32 num_active_ndps_on_peer; + /** + * TLV (tag length value) parameters follow the ndp_confirm + * structure. The TLV's are: + * A_UINT8 ndp_cfg[]; + * A_UINT8 ndp_app_info[]; + */ +} wmi_ndp_confirm_event_fixed_param_PROTOTYPE; + +#define wmi_ndp_confirm_event_fixed_param wmi_ndp_confirm_event_fixed_param_PROTOTYPE + +/** + * Event indication received on the initiator/responder side terminating a NDP session + */ +typedef struct { + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_ndp_end_indication */ + A_UINT32 tlv_header; + /** type defined in wmi_ndp_end_type */ + A_UINT32 type; + /** Unique id identifying the VDEV */ + A_UINT32 vdev_id; + /** reason_code defined in wmi_ndp_end_reason_code */ + A_UINT32 reason_code; + /** NDP instance id */ + A_UINT32 ndp_instance_id; + /** NDI MAC addr of the peer */ + wmi_mac_addr peer_ndi_mac_addr; + /** Number of active ndps on this peer */ + A_UINT32 num_active_ndps_on_peer; +} wmi_ndp_end_indication_PROTOTYPE; + +#define wmi_ndp_end_indication wmi_ndp_end_indication_PROTOTYPE + +typedef struct { + A_UINT32 tlv_header; + A_UINT32 num_data; + /* followed by WMITLV_TAG_ARRAY_BYTE */ +} wmi_diag_data_container_event_fixed_param; + +enum { + WMI_PDEV_PARAM_TXPOWER_REASON_NONE = 0, + WMI_PDEV_PARAM_TXPOWER_REASON_SAR, + WMI_PDEV_PARAM_TXPOWER_REASON_MAX +}; + +#define PDEV_PARAM_TXPOWER_VALUE_MASK 0x000000FF +#define PDEV_PARAM_TXPOWER_VALUE_SHIFT 0 + +#define PDEV_PARAM_TXPOWER_REASON_MASK 0x0000FF00 +#define PDEV_PARAM_TXPOWER_REASON_SHIFT 8 + +#define SET_PDEV_PARAM_TXPOWER_VALUE(txpower_param, value) \ + ((txpower_param) &= ~PDEV_PARAM_TXPOWER_VALUE_MASK, (txpower_param) |= ((value) << PDEV_PARAM_TXPOWER_VALUE_SHIFT)) + +#define SET_PDEV_PARAM_TXPOWER_REASON(txpower_param, value) \ + ((txpower_param) &= ~PDEV_PARAM_TXPOWER_REASON_MASK, (txpower_param) |= ((value) << PDEV_PARAM_TXPOWER_REASON_SHIFT)) + +#define GET_PDEV_PARAM_TXPOWER_VALUE(txpower_param) \ + (((txpower_param) & PDEV_PARAM_TXPOWER_VALUE_MASK) >> PDEV_PARAM_TXPOWER_VALUE_SHIFT) + +#define GET_PDEV_PARAM_TXPOWER_REASON(txpower_param) \ + (((txpower_param) & PDEV_PARAM_TXPOWER_REASON_MASK) >> PDEV_PARAM_TXPOWER_REASON_SHIFT) + +#define PDEV_PARAM_SMART_CHAINMASK_SCHEME_DECISION_MASK 0x00000001 +#define PDEV_PARAM_SMART_CHAINMASK_SCHEME_DECISION_SHIFT 0 + +#define SET_PDEV_SMART_CHAINMASK_SCHEME_DECISION(param, value) \ + do { \ + (param) &= ~PDEV_PARAM_SMART_CHAINMASK_SCHEME_DECISION_MASK; \ + (param) |= (value) << PDEV_PARAM_SMART_CHAINMASK_SCHEME_DECISION_SHIFT; \ + while (0) + +#define GET_PDEV_SMART_CHAINMASK_SCHEME_DECISION(param) \ + (((param) & PDEV_PARAM_SMART_CHAINMASK_SCHEME_DECISION_MASK) >> PDEV_PARAM_SMART_CHAINMASK_SCHEME_DECISION_SHIFT) + +/** + * This command is sent from WLAN host driver to firmware to + * notify the current modem power state. Host would receive a + * message from modem when modem is powered on. Host driver + * would then send this command to firmware. Firmware would then + * power on WCI-2 (UART) interface for LTE/MWS Coex. + * + * This command is only applicable for APQ platform which has + * modem on the platform. If firmware doesn't support MWS Coex, + * this command can be dropped by firmware. + * + * This is a requirement from modem team that WCN can't toggle + * UART before modem is powered on. + */ +typedef struct { + /** TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_modem_power_state_cmd_param */ + A_UINT32 tlv_header; + + /** Modem power state parameter */ + A_UINT32 modem_power_state; +} wmi_modem_power_state_cmd_param; + +enum { + WMI_MODEM_STATE_OFF = 0, + WMI_MODEM_STATE_ON +}; + +/** + * This command is sent from WLAN host driver to firmware to + * notify the updated Specific Absorption Rate (SAR) limits. + * A critical regulation for FCC compliance, OEMs require methods to set + * limits on TX power of WLAN/WWAN. + * Host would receive instructions on what to set the limits per + * band/chain/modulation to, it would then interpret and send the limits + * to FW using this WMI message. + * Since it is possible to have too many commands to fit into one message, + * FW will keep receiving the messages, until it finds one with + * commit_limits = 1, at which point it will apply all the received + * specifications. + */ +typedef struct { + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_sar_limits_cmd_param */ + A_UINT32 tlv_header; + + /** when set to WMI_SAR_FEATURE_ON_*, enable SAR feature + * with BDF (SET_0 to 4) or WMI + * if set to WMI_SAR_FEATURE_OFF, disable feature; + * if set to WMI_SAR_FEATURE_NO_CHANGE, do not alter state of feature; + */ + A_UINT32 sar_enable; + + /** number of items in sar_limits[] */ + A_UINT32 num_limit_rows; + + /** once received and is set to 1, FW will calculate the power limits + * and send set_power command to apply them. + * Otherwise just update local values stored in FW until a future msg + * with commit_limits=1 arrives. + */ + A_UINT32 commit_limits; + + /** + * TLV (tag length value) parameters follow the sar_limit_cmd_row + * structure. The TLV's are: + * wmi_sar_limit_cmd_row sar_limits[]; + */ +} wmi_sar_limits_cmd_fixed_param; + +enum wmi_sar_feature_state_flags { + WMI_SAR_FEATURE_OFF = 0, + WMI_SAR_FEATURE_ON_SET_0, + WMI_SAR_FEATURE_ON_SET_1, + WMI_SAR_FEATURE_ON_SET_2, + WMI_SAR_FEATURE_ON_SET_3, + WMI_SAR_FEATURE_ON_SET_4, + WMI_SAR_FEATURE_NO_CHANGE, + WMI_SAR_FEATURE_ON_USER_DEFINED, +}; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_sar_limit_cmd_row */ + + /** Current values: WMI_SAR_2G_ID, WMI_SAR_5G_ID. Can be extended by adding + * new band_id values . + */ + A_UINT32 band_id; + + A_UINT32 chain_id; + + /** Current values: WMI_SAR_MOD_CCK, WMI_SAR_MOD_OFDM */ + A_UINT32 mod_id; + + /** actual power limit value, in steps of 0.5 dBm */ + A_UINT32 limit_value; + + /** in case the OEM doesn't care about one of the qualifiers from above, + * the bit for that qualifier within the validity_bitmap can be set to 0 + * so that limit is applied to all possible cases of this qualifier + * (i.e. if a qualifier's validity_bitmap flag is 0, the qualifier is + * treated as a wildcard). + * Current masks: + * WMI_SAR_BAND_ID_VALID_MASK + * WMI_SAR_CHAIN_ID_VALID_MASK + * WMI_SAR_MOD_ID_VALID_MASK + * Example: if !WMI_IS_SAR_MOD_ID_VALID(bitmap), + * it means apply same limit_value to both WMI_SAR_MOD_CCK and + * WMI_SAR_MOD_OFDM cases. + */ + A_UINT32 validity_bitmap; +} wmi_sar_limit_cmd_row; + +enum wmi_sar_band_id_flags { + WMI_SAR_2G_ID = 0, + WMI_SAR_5G_ID +}; + +enum wmi_sar_mod_id_flags { + WMI_SAR_MOD_CCK = 0, + WMI_SAR_MOD_OFDM +}; + +#define WMI_SAR_BAND_ID_VALID_MASK (0x1) +#define WMI_SAR_CHAIN_ID_VALID_MASK (0x2) +#define WMI_SAR_MOD_ID_VALID_MASK (0x4) + +#define WMI_SET_SAR_BAND_ID_VALID(bitmap) ((bitmap) |= WMI_SAR_BAND_ID_VALID_MASK) +#define WMI_SET_SAR_CHAIN_ID_VALID(bitmap) ((bitmap) |= WMI_SAR_CHAIN_ID_VALID_MASK) +#define WMI_SET_SAR_MOD_ID_VALID(bitmap) ((bitmap) |= WMI_SAR_MOD_ID_VALID_MASK) + +#define WMI_IS_SAR_BAND_ID_VALID(bitmap) ((bitmap) & WMI_SAR_BAND_ID_VALID_MASK) +#define WMI_IS_SAR_CHAIN_ID_VALID(bitmap) ((bitmap) & WMI_SAR_CHAIN_ID_VALID_MASK) +#define WMI_IS_SAR_MOD_ID_VALID(bitmap) ((bitmap) & WMI_SAR_MOD_ID_VALID_MASK) + +#define WMI_ROAM_AUTH_STATUS_CONNECTED 0x1 /** connected, but not authenticated */ +#define WMI_ROAM_AUTH_STATUS_AUTHENTICATED 0x2 /** connected and authenticated */ + +/** WMI_ROAM_SYNCH_EVENT: roam synch event triggering the host propagation logic + generated whenever firmware roamed to new AP silently and + (a) If the host is awake, FW sends the event to the host immediately . + (b) If host is in sleep then either + (1) FW waits until host sends WMI_PDEV_RESUME_CMDID or WMI_WOW_HOSTWAKEUP_FROM_SLEEP_CMDID + command to FW (part of host wake up sequence from low power mode) before sending the event host. + (2) data/mgmt frame is received from roamed AP, which needs to return to host +*/ + +typedef struct { + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_key_material */ + A_UINT32 tlv_header; + + A_UINT8 kck[GTK_OFFLOAD_KCK_BYTES]; /* EAPOL-Key Key Confirmation Key (KCK) */ + A_UINT8 kek[GTK_OFFLOAD_KEK_BYTES]; /* EAPOL-Key Key Encryption Key (KEK) */ + A_UINT8 replay_counter[GTK_REPLAY_COUNTER_BYTES]; +} wmi_key_material; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_roam_synch_event_fixed_param */ + /** Unique id identifying the VDEV on which roaming is done by firmware */ + A_UINT32 vdev_id; + /** auth_status: connected or authorized */ + A_UINT32 auth_status; + /** roam_reason: + * bits 0-3 for roam reason see WMI_ROAM_REASON_XXX + * bits 4-5 for subnet status see WMI_ROAM_SUBNET_CHANGE_STATUS_XXX. + * bit 6 for HW mode status, set 1 to indicate host to schedule + * HW mode change, see WMI_ROAM_REQUEST_HOST_HW_MODE_CHANGE. + */ + A_UINT32 roam_reason; + /** associated AP's rssi calculated by FW when reason code is WMI_ROAM_REASON_LOW_RSSI. not valid if roam_reason is BMISS */ + A_UINT32 rssi; + /** MAC address of roamed AP */ + wmi_mac_addr bssid; /* BSSID */ + /** whether the frame is beacon or probe rsp */ + A_UINT32 is_beacon; + /** the length of beacon/probe rsp */ + A_UINT32 bcn_probe_rsp_len; + /** the length of reassoc rsp */ + A_UINT32 reassoc_rsp_len; + /** the length of reassoc req */ + A_UINT32 reassoc_req_len; + /** + * TLV (tag length value) parameters follows roam_synch_event + * The TLV's are: + * A_UINT8 bcn_probe_rsp_frame[]; length identified by bcn_probe_rsp_len + * A_UINT8 reassoc_rsp_frame[]; length identified by reassoc_rsp_len + * wmi_channel chan; + * wmi_key_material key; + * A_UINT32 status; subnet changed status not being used currently. + * will pass the information using roam_status. + * A_UINT8 reassoc_req_frame[]; length identified by reassoc_req_len + * + **/ +} wmi_roam_synch_event_fixed_param; + +#define WMI_PEER_ESTIMATED_LINKSPEED_INVALID 0xFFFFFFFF + +typedef struct { + /* TLV tag and len; tag equals WMITLV_TAG_STRUC_ wmi_peer_get_estimated_linkspeed_cmd_fixed_param */ + A_UINT32 tlv_header; + /** MAC address of the peer for which the estimated link speed is required. */ + wmi_mac_addr peer_macaddr; + /* Set to 1 only if vdev_id field is valid */ + A_UINT32 valid_vdev_id; + /* VDEV to which the peer belongs to */ + A_UINT32 vdev_id; +} wmi_peer_get_estimated_linkspeed_cmd_fixed_param; + +typedef struct { + /* TLV tag and len; tag equals WMITLV_TAG_STRUC_ wmi_peer_estimated_linkspeed_event_fixed_param */ + A_UINT32 tlv_header; + /** MAC address of the peer for which the estimated link speed is required. + */ + wmi_mac_addr peer_macaddr; + /* Estimated link speed in kbps. + * When est_linkspeed_kbps is not valid, the value is set to WMI_PEER_ESTIMATED_LINKSPEED_INVALID. + */ + A_UINT32 est_linkspeed_kbps; + /* Set to 1 only if vdev_id field is valid */ + A_UINT32 valid_vdev_id; + /* VDEV to which the peer belongs to */ + A_UINT32 vdev_id; +} wmi_peer_estimated_linkspeed_event_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals */ + /* vdev ID */ + A_UINT32 vdev_id; + A_UINT32 data_len; /** length in byte of data[]. */ + /* This structure is used to send REQ binary blobs +* from application/service to firmware where Host drv is pass through . +* Following this structure is the TLV: +* A_UINT8 data[]; <-- length in byte given by field data_len. +*/ +} wmi_req_stats_ext_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_stats1_event_fix_param */ + A_UINT32 vdev_id; /** vdev ID */ + A_UINT32 data_len; /** length in byte of data[]. */ + /* This structure is used to send REQ binary blobs + * from firmware to application/service where Host drv is pass through . + * Following this structure is the TLV: + * A_UINT8 data[]; <-- length in byte given by field data_len. + */ +} wmi_stats_ext_event_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_peer_delete_resp_event_fixed_param */ + /** unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; + /** peer MAC address */ + wmi_mac_addr peer_macaddr; +} wmi_peer_delete_resp_event_fixed_param; + +typedef struct { + /* TLV tag and len; tag equals WMITLV_TAG_STRUC_ wmi_peer_state_event_fixed_param */ + A_UINT32 tlv_header; + A_UINT32 vdev_id; /* vdev ID */ + /* MAC address of the peer for which the estimated link speed is required.*/ + wmi_mac_addr peer_macaddr; + A_UINT32 state; /* peer state */ +} wmi_peer_state_event_fixed_param; + +typedef struct { + /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_peer_assoc_conf_event_fixed_param */ + A_UINT32 tlv_header; + /* unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; + /* peer MAC address */ + wmi_mac_addr peer_macaddr; +} wmi_peer_assoc_conf_event_fixed_param; + +enum { + WMI_2G4_HT40_OBSS_SCAN_PASSIVE = 0, /** scan_type: passive */ + WMI_2G4_HT40_OBSS_SCAN_ACTIVE, /** scan_type: active */ +}; + +typedef struct { + /** + * TLV tag and len; + * tag equals WMITLV_TAG_STRUC_wmi_obss_scan_enalbe_cmd_fixed_param + */ + A_UINT32 tlv_header; + A_UINT32 vdev_id; + /** + * active or passive. if active all the channels are actively scanned. + * if passive then all the channels are passively scanned + */ + A_UINT32 scan_type; + /** + * FW can perform multiple scans with in a OBSS scan interval. + * For each scan, + * if the scan is passive then obss_scan_passive_dwell is minimum dwell to be used for each channel , + * if the scan is active then obss_scan_active_dwell is minimum dwell to be used for each channel . + * The unit for these 2 parameters is TUs. + */ + A_UINT32 obss_scan_passive_dwell; + A_UINT32 obss_scan_active_dwell; + /** + * OBSS scan interval . FW needs to perform one or more OBSS scans within this interval and fulfill the + * both min and total per channel dwell time requirement + */ + A_UINT32 bss_channel_width_trigger_scan_interval; + /** + * FW can perform multiple scans with in a OBSS scan interval. + * For each scan, + * the total per channel dwell time across all scans with in OBSS scan interval should be + * atleast obss_scan_passive_total_per channel for passive scas and obss_scan_active_total_per channel + * for active scans and , + * The unit for these 2 parameters is TUs. + */ + A_UINT32 obss_scan_passive_total_per_channel; + A_UINT32 obss_scan_active_total_per_channel; + A_UINT32 bss_width_channel_transition_delay_factor; /** parameter to check exemption from scan */ + A_UINT32 obss_scan_activity_threshold; /** parameter to check exemption from scan */ + /** following two parameters used by FW to fill IEs when sending 20/40 coexistence action frame to AP */ + A_UINT32 forty_mhz_intolerant; /** STA 40M bandwidth intolerant capability */ + A_UINT32 current_operating_class; /** STA current operating class */ + /** length of 2.4GHz channel list to scan at, channel list in tlv->channels[] */ + A_UINT32 channel_len; + /** length of optional ie data to append to probe reqest when active scan, ie data in tlv->ie_field[] */ + A_UINT32 ie_len; +} wmi_obss_scan_enable_cmd_fixed_param; + +typedef struct { + /** + * TLV tag and len; + * tag equals WMITLV_TAG_STRUC_wmi_obss_scan_disalbe_cmd_fixed_param + */ + A_UINT32 tlv_header; + A_UINT32 vdev_id; +} wmi_obss_scan_disable_cmd_fixed_param; + +typedef struct { + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_offload_prb_rsp_tx_status_event_fixed_param */ + A_UINT32 tlv_header; + /** unique id identifying the VDEV */ + A_UINT32 vdev_id; + /** prb rsp tx status, values defined in enum WMI_FRAME_TX_STATUS */ + A_UINT32 tx_status; +} wmi_offload_prb_rsp_tx_status_event_fixed_param; + +typedef enum { + WMI_FRAME_TX_OK, /* frame tx ok */ + WMI_FRAME_TX_XRETRY, /* excessivley retried */ + WMI_FRAME_TX_DROP, /* frame dropped by FW due to resources */ + WMI_FRAME_TX_FILTERED, /* frame filtered by hardware */ +} WMI_FRAME_TX_STATUS; + +/** + * This command is sent from WLAN host driver to firmware to + * request firmware to send the latest channel avoidance range + * to host. + * + * This command is only applicable for APQ platform which has + * modem on the platform. If firmware doesn't support MWS Coex, + * this command can be dropped by firmware. + * + * Host would send this command to firmware to request a channel + * avoidance information update. + */ +typedef struct { + /** TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_chan_avoid_update_cmd_param */ + A_UINT32 tlv_header; +} wmi_chan_avoid_update_cmd_param; + +/* ExtScan operation mode */ +typedef enum { + WMI_EXTSCAN_MODE_NONE = 0x0000, + WMI_EXTSCAN_MODE_START = 0x0001, /* ExtScan/TableMonitoring operation started */ + WMI_EXTSCAN_MODE_STOP = 0x0002, /* ExtScan/TableMonitoring operation stopped */ + WMI_EXTSCAN_MODE_IGNORED = 0x0003, /* ExtScan command ignored due to error */ +} wmi_extscan_operation_mode; + +/* Channel Mask */ +typedef enum { + WMI_CHANNEL_BAND_UNSPECIFIED = 0x0000, + WMI_CHANNEL_BAND_24 = 0x0001, /* 2.4 channel */ + WMI_CHANNEL_BAND_5_NON_DFS = 0x0002, /* 5G Channels (No DFS channels) */ + WMI_CHANNEL_BAND_DFS = 0x0004, /* DFS channels */ +} wmi_channel_band_mask; + +typedef enum { + WMI_EXTSCAN_CYCLE_STARTED_EVENT = 0x0001, + WMI_EXTSCAN_CYCLE_COMPLETED_EVENT = 0x0002, + WMI_EXTSCAN_BUCKET_STARTED_EVENT = 0x0004, + WMI_EXTSCAN_BUCKET_COMPLETED_EVENT = 0x0008, + WMI_EXTSCAN_BUCKET_FAILED_EVENT = 0x0010, + WMI_EXTSCAN_BUCKET_OVERRUN_EVENT = 0x0020, + WMI_EXTSCAN_THRESHOLD_NUM_SCANS = 0x0040, + WMI_EXTSCAN_THRESHOLD_PERCENT = 0x0080, + + WMI_EXTSCAN_EVENT_MAX = 0x8000 +} wmi_extscan_event_type; + +#define WMI_EXTSCAN_CYCLE_EVENTS_MASK (WMI_EXTSCAN_CYCLE_STARTED_EVENT | \ + WMI_EXTSCAN_CYCLE_COMPLETED_EVENT) + +#define WMI_EXTSCAN_BUCKET_EVENTS_MASK (WMI_EXTSCAN_BUCKET_STARTED_EVENT | \ + WMI_EXTSCAN_BUCKET_COMPLETED_EVENT | \ + WMI_EXTSCAN_BUCKET_FAILED_EVENT | \ + WMI_EXTSCAN_BUCKET_OVERRUN_EVENT) + +typedef enum { + WMI_EXTSCAN_NO_FORWARDING = 0x0000, + WMI_EXTSCAN_FORWARD_FRAME_TO_HOST = 0x0001 +} wmi_extscan_forwarding_flags; + +typedef enum { + WMI_EXTSCAN_USE_MSD = 0x0001, /* Use Motion Sensor Detection */ + WMI_EXTSCAN_EXTENDED_BATCHING_EN = 0x0002, /* Extscan LPASS extended batching feature is supported and enabled */ +} wmi_extscan_configuration_flags; + +typedef enum { + WMI_EXTSCAN_BUCKET_CACHE_RESULTS = 0x0001, /* Cache the results of bucket whose configuration flags has this bit set */ + WMI_EXTSCAN_REPORT_EVENT_CONTEXT_HUB = 0x0002, /* Report ext scan results to context hub or not. */ +} wmi_extscan_bucket_configuration_flags; + +typedef enum { + WMI_EXTSCAN_STATUS_OK = 0, + WMI_EXTSCAN_STATUS_ERROR = 0x80000000, + WMI_EXTSCAN_STATUS_INVALID_PARAMETERS, + WMI_EXTSCAN_STATUS_INTERNAL_ERROR +} wmi_extscan_start_stop_status; + +typedef struct { + /** Request ID - to identify command. Cannot be 0 */ + A_UINT32 request_id; + /** Requestor ID - client requesting ExtScan */ + A_UINT32 requestor_id; + /** VDEV id(interface) that is requesting scan */ + A_UINT32 vdev_id; +} wmi_extscan_command_id; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_ARRAY_STRUC */ + /** channel number */ + A_UINT32 channel; + + /** dwell time in msec - use defaults if 0 */ + A_UINT32 min_dwell_time; + A_UINT32 max_dwell_time; + + /** passive/active channel and other flags */ + A_UINT32 control_flags; /* 0 => active, 1 => passive scan; ignored for DFS */ +} wmi_extscan_bucket_channel; + +/* Scan Bucket specification */ +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_ARRAY_STRUC */ + /** Bucket ID - 0-based */ + A_UINT32 bucket_id; + /** ExtScan events subscription - events to be reported to client (see wmi_extscan_event_type) */ + A_UINT32 notify_extscan_events; + /** Options to forward scan results - see wmi_extscan_forwarding_flags */ + A_UINT32 forwarding_flags; + /** ExtScan configuration flags - wmi_extscan_bucket_configuration_flags */ + A_UINT32 configuration_flags; + /** DEPRECATED member: multiplier to be applied to the periodic scan's base period */ + A_UINT32 base_period_multiplier; + /** dwell time in msec on active channels - use defaults if 0 */ + A_UINT32 min_dwell_time_active; + A_UINT32 max_dwell_time_active; + /** dwell time in msec on passive channels - use defaults if 0 */ + A_UINT32 min_dwell_time_passive; + A_UINT32 max_dwell_time_passive; + /** see wmi_channel_band_mask; when equal to WMI_CHANNEL_UNSPECIFIED, use channel list */ + A_UINT32 channel_band; + /** number of channels (if channel_band is WMI_CHANNEL_UNSPECIFIED) */ + A_UINT32 num_channels; + /** scan period upon start or restart of the bucket - periodicity of the bucket to begin with */ + A_UINT32 min_period; + /** period above which exponent is not applied anymore */ + A_UINT32 max_period; + /** back off value to be applied to bucket's periodicity after exp_max_step_count scan cycles + * new_bucket_period = last_bucket_period + last_exponent_period * exp_backoff + */ + A_UINT32 exp_backoff; + /** number of scans performed at a given periodicity after which exponential back off value is + * applied to current periodicity to obtain a newer one + */ + A_UINT32 exp_max_step_count; +/** Followed by the variable length TLV chan_list: + * wmi_extscan_bucket_channel chan_list[] */ +} wmi_extscan_bucket; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_extscan_start_cmd_fixed_param */ + /** Request ID - to identify command. Cannot be 0 */ + A_UINT32 request_id; + /** Requestor ID - client requesting ExtScan */ + A_UINT32 requestor_id; + /** VDEV id(interface) that is requesting scan */ + A_UINT32 vdev_id; + /** table ID - to allow support for multiple simultaneous requests */ + A_UINT32 table_id; + /** Base period (milliseconds) used by scan buckets to define periodicity of the scans */ + A_UINT32 base_period; + /** Maximum number of iterations to run - one iteration is the scanning of the least frequent bucket */ + A_UINT32 max_iterations; + /** Options to forward scan results - see wmi_extscan_forwarding_flags */ + A_UINT32 forwarding_flags; + /** ExtScan configuration flags - wmi_extscan_configuration_flags */ + A_UINT32 configuration_flags; + /** ExtScan events subscription - bitmask indicating which events should be send to client (see wmi_extscan_event_type) */ + A_UINT32 notify_extscan_events; + /** Scan Priority, input to scan scheduler */ + A_UINT32 scan_priority; + /** Maximum number of BSSIDs to cache on each scan cycle */ + A_UINT32 max_bssids_per_scan_cycle; + /** Minimum RSSI value to report */ + A_UINT32 min_rssi; + /** Maximum table usage in percentage */ + A_UINT32 max_table_usage; + /** default dwell time in msec on active channels */ + A_UINT32 min_dwell_time_active; + A_UINT32 max_dwell_time_active; + /** default dwell time in msec on passive channels */ + A_UINT32 min_dwell_time_passive; + A_UINT32 max_dwell_time_passive; + /** min time in msec on the BSS channel,only valid if atleast one VDEV is active*/ + A_UINT32 min_rest_time; + /** max rest time in msec on the BSS channel,only valid if at least one VDEV is active*/ + /** the scanner will rest on the bss channel at least min_rest_time. after min_rest_time the scanner + * will start checking for tx/rx activity on all VDEVs. if there is no activity the scanner will + * switch to off channel. if there is activity the scanner will let the radio on the bss channel + * until max_rest_time expires.at max_rest_time scanner will switch to off channel + * irrespective of activity. activity is determined by the idle_time parameter. + */ + A_UINT32 max_rest_time; + /** time before sending next set of probe requests. + * The scanner keeps repeating probe requests transmission with period specified by repeat_probe_time. + * The number of probe requests specified depends on the ssid_list and bssid_list + */ + /** Max number of probes to be sent */ + A_UINT32 n_probes; + /** time in msec between 2 sets of probe requests. */ + A_UINT32 repeat_probe_time; + /** time in msec between 2 consequetive probe requests with in a set. */ + A_UINT32 probe_spacing_time; + /** data inactivity time in msec on bss channel that will be used by scanner for measuring the inactivity */ + A_UINT32 idle_time; + /** maximum time in msec allowed for scan */ + A_UINT32 max_scan_time; + /** delay in msec before sending first probe request after switching to a channel */ + A_UINT32 probe_delay; + /** Scan control flags */ + A_UINT32 scan_ctrl_flags; + /** Burst duration time in msec*/ + A_UINT32 burst_duration; + + /** number of bssids in the TLV bssid_list[] */ + A_UINT32 num_bssid; + /** number of ssid in the TLV ssid_list[] */ + A_UINT32 num_ssids; + /** number of bytes in TLV ie_data[] */ + A_UINT32 ie_len; + /** number of buckets in the TLV bucket_list[] */ + A_UINT32 num_buckets; + /** in number of scans, send notifications to host after these many scans */ + A_UINT32 report_threshold_num_scans; + /** number of channels in channel_list[] determined by the + sum of wmi_extscan_bucket.num_channels in array */ + +/** + * TLV (tag length value) parameters follow the extscan_cmd + * structure. The TLV's are: + * wmi_ssid ssid_list[]; + * wmi_mac_addr bssid_list[]; + * A_UINT8 ie_data[]; + * wmi_extscan_bucket bucket_list[]; + * wmi_extscan_bucket_channel channel_list[]; + */ +} wmi_extscan_start_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_extscan_stop_cmd_fixed_param */ + /** Request ID - to match running command. 0 matches any request */ + A_UINT32 request_id; + /** Requestor ID - client requesting stop */ + A_UINT32 requestor_id; + /** VDEV id(interface) that is requesting scan */ + A_UINT32 vdev_id; + /** table ID - to allow support for multiple simultaneous requests */ + A_UINT32 table_id; +} wmi_extscan_stop_cmd_fixed_param; + +enum wmi_extscan_get_cached_results_flags { + WMI_EXTSCAN_GET_CACHED_RESULTS_FLAG_NONE = 0x0000, + WMI_EXTSCAN_GET_CACHED_RESULTS_FLAG_FLUSH_TABLE = 0x0001 +}; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_extscan_get_cached_results_cmd_fixed_param */ + /** request ID - used to correlate command with events */ + A_UINT32 request_id; + /** Requestor ID - client that requested results */ + A_UINT32 requestor_id; + /** VDEV id(interface) that is requesting scan */ + A_UINT32 vdev_id; + /** table ID - to allow support for multiple simultaneous requests */ + A_UINT32 table_id; + /** maximum number of results to be returned */ + A_UINT32 max_results; + /** flush BSSID list - wmi_extscan_get_cached_results_flags */ + A_UINT32 control_flags; /* enum wmi_extscan_get_cached_results_flags */ +} wmi_extscan_get_cached_results_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_extscan_get_wlan_change_results_cmd_fixed_param */ + /** request ID - used to correlate command with events */ + A_UINT32 request_id; + /** Requestor ID - client that requested results */ + A_UINT32 requestor_id; + /** VDEV id(interface) that is requesting scan */ + A_UINT32 vdev_id; + /** table ID - to allow support for multiple simultaneous requests */ + A_UINT32 table_id; +} wmi_extscan_get_wlan_change_results_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_ARRAY_STRUC */ + /**bssid */ + wmi_mac_addr bssid; + /**channel number */ + A_UINT32 channel; + /**upper RSSI limit */ + A_UINT32 upper_rssi_limit; + /**lower RSSI limit */ + A_UINT32 lower_rssi_limit; +} wmi_extscan_wlan_change_bssid_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_extscan_configure_wlan_change_monitor_cmd_fixed_param */ + /** Request ID - to identify command. Cannot be 0 */ + A_UINT32 request_id; + /** Requestor ID - client requesting wlan change monitoring */ + A_UINT32 requestor_id; + /** VDEV id(interface) that is requesting scan */ + A_UINT32 vdev_id; + /** table ID - to allow support for multiple simultaneous tables */ + A_UINT32 table_id; + /** operation mode: start/stop */ + A_UINT32 mode; /* wmi_extscan_operation_mode */ + /** number of rssi samples to store */ + A_UINT32 max_rssi_samples; + /** number of samples to use to calculate RSSI average */ + A_UINT32 rssi_averaging_samples; + /** number of scans to confirm loss of contact with RSSI */ + A_UINT32 lost_ap_scan_count; + /** number of out-of-range BSSIDs necessary to send event */ + A_UINT32 max_out_of_range_count; + + /** total number of bssid signal descriptors (in all pages) */ + A_UINT32 total_entries; + /** index of the first bssid entry found in the TLV wlan_change_descriptor_list*/ + A_UINT32 first_entry_index; + /** number of bssid signal descriptors in this page */ + A_UINT32 num_entries_in_page; +/* Following this structure is the TLV: + * wmi_extscan_wlan_change_bssid_param wlan_change_descriptor_list[]; + * (number of elements given by field num_page_entries) + */ +} wmi_extscan_configure_wlan_change_monitor_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_ARRAY_STRUC */ + /**bssid */ + wmi_mac_addr bssid; + /**RSSI min threshold for reporting */ + A_UINT32 min_rssi; + /**Deprecated entry - channel number */ + A_UINT32 channel; + /** RSSI max threshold for reporting */ + A_UINT32 max_rssi; +} wmi_extscan_hotlist_entry; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_extscan_configure_hotlist_monitor_cmd_fixed_param */ + /** Request ID - to identify command. Cannot be 0 */ + A_UINT32 request_id; + /** Requestor ID - client requesting hotlist monitoring */ + A_UINT32 requestor_id; + /** VDEV id(interface) that is requesting scan */ + A_UINT32 vdev_id; + /** table ID - to allow support for multiple simultaneous tables */ + A_UINT32 table_id; + /** operation mode: start/stop */ + A_UINT32 mode; /* wmi_extscan_operation_mode */ + /** total number of bssids (in all pages) */ + A_UINT32 total_entries; + /** index of the first bssid entry found in the TLV wmi_extscan_hotlist_entry */ + A_UINT32 first_entry_index; + /** number of bssids in this page */ + A_UINT32 num_entries_in_page; + /** number of consecutive scans to confirm loss of contact with AP */ + A_UINT32 lost_ap_scan_count; +/* Following this structure is the TLV: + * wmi_extscan_hotlist_entry hotlist[]; <-- number of elements given by field num_page_entries. + */ +} wmi_extscan_configure_hotlist_monitor_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_ARRAY_STRUC */ + /**ssid */ + wmi_ssid ssid; + /**band */ + A_UINT32 band; + /**RSSI threshold for reporting */ + A_UINT32 min_rssi; + A_UINT32 max_rssi; +} wmi_extscan_hotlist_ssid_entry; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_extscan_configure_hotlist_ssid_monitor_cmd_fixed_param */ + /** Request ID - to identify command. Cannot be 0 */ + A_UINT32 request_id; + /** Requestor ID - client requesting hotlist ssid monitoring */ + A_UINT32 requestor_id; + /** VDEV id(interface) that is requesting scan */ + A_UINT32 vdev_id; + /** table ID - to allow support for multiple simultaneous tables */ + A_UINT32 table_id; + /** operation mode: start/stop */ + A_UINT32 mode; /* wmi_extscan_operation_mode */ + /**total number of ssids (in all pages) */ + A_UINT32 total_entries; + /**index of the first ssid entry found in the TLV wmi_extscan_hotlist_ssid_entry*/ + A_UINT32 first_entry_index; + /**number of ssids in this page */ + A_UINT32 num_entries_in_page; + /** number of consecutive scans to confirm loss of an ssid **/ + A_UINT32 lost_ap_scan_count; + /* Following this structure is the TLV: + * wmi_extscan_hotlist_ssid_entry hotlist_ssid[]; <-- number of elements given by field num_page_entries. + */ +} wmi_extscan_configure_hotlist_ssid_monitor_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_ARRAY_STRUC */ + /** table ID - to allow support for multiple simultaneous tables */ + A_UINT32 table_id; + /** size in bytes of scan cache entry */ + A_UINT32 scan_cache_entry_size; + /** maximum number of scan cache entries */ + A_UINT32 max_scan_cache_entries; + /** maximum number of buckets per extscan request */ + A_UINT32 max_buckets; + /** maximum number of BSSIDs that will be stored in each scan (best n/w as per RSSI) */ + A_UINT32 max_bssid_per_scan; + /** table usage level at which indication must be sent to host */ + A_UINT32 max_table_usage_threshold; +} wmi_extscan_cache_capabilities; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_ARRAY_STRUC */ + /** table ID - to allow support for multiple simultaneous tables */ + A_UINT32 table_id; + /** size in bytes of wlan change entry */ + A_UINT32 wlan_change_entry_size; + /** maximum number of entries in wlan change table */ + A_UINT32 max_wlan_change_entries; + /** number of RSSI samples used for averaging RSSI */ + A_UINT32 max_rssi_averaging_samples; + /** number of BSSID/RSSI entries (BSSID pointer, RSSI, timestamp) that device can hold */ + A_UINT32 max_rssi_history_entries; +} wmi_extscan_wlan_change_monitor_capabilities; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_ARRAY_STRUC */ + /** table ID - to allow support for multiple simultaneous tables */ + A_UINT32 table_id; + /** size in bytes of hotlist entry */ + A_UINT32 wlan_hotlist_entry_size; + /** maximum number of entries in wlan change table */ + A_UINT32 max_hotlist_entries; +} wmi_extscan_hotlist_monitor_capabilities; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_extscan_set_capabilities_cmd_fixed_param */ + /** Request ID - matches request ID used to start hot list monitoring */ + A_UINT32 request_id; + /** Requestor ID - client requesting stop */ + A_UINT32 requestor_id; + /** number of extscan caches */ + A_UINT32 num_extscan_cache_tables; + /** number of wlan change lists */ + A_UINT32 num_wlan_change_monitor_tables; + /** number of hotlists */ + A_UINT32 num_hotlist_monitor_tables; + /** if one sided rtt data collection is supported */ + A_UINT32 rtt_one_sided_supported; + /** if 11v data collection is supported */ + A_UINT32 rtt_11v_supported; + /** if 11mc data collection is supported */ + A_UINT32 rtt_ftm_supported; + /** number of extscan cache capabilities (one per table) */ + A_UINT32 num_extscan_cache_capabilities; + /** number of wlan change capabilities (one per table) */ + A_UINT32 num_extscan_wlan_change_capabilities; + /** number of extscan hotlist capabilities (one per table) */ + A_UINT32 num_extscan_hotlist_capabilities; +/* Following this structure is the TLV: + * wmi_extscan_cache_capabilities extscan_cache_capabilities; <-- number of capabilities given by num_extscan_caches + * wmi_extscan_wlan_change_monitor_capabilities wlan_change_capabilities; <-- number of capabilities given by num_wlan_change_monitor_tables + * wmi_extscan_hotlist_monitor_capabilities hotlist_capabilities; <-- number of capabilities given by num_hotlist_monitor_tables + */ +} wmi_extscan_set_capabilities_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_extscan_get_capabilities_cmd_fixed_param */ + /** Request ID - matches request ID used to start hot list monitoring */ + A_UINT32 request_id; + /** Requestor ID - client requesting capabilities */ + A_UINT32 requestor_id; +} wmi_extscan_get_capabilities_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_extscan_start_stop_event_fixed_param */ + /** Request ID of the operation that was started/stopped */ + A_UINT32 request_id; + /** Requestor ID of the operation that was started/stopped */ + A_UINT32 requestor_id; + /** VDEV id(interface) of the operation that was started/stopped */ + A_UINT32 vdev_id; + /** extscan WMI command */ + A_UINT32 command; + /** operation mode: start/stop */ + A_UINT32 mode; /* wmi_extscan_operation_mode */ + /**success/failure */ + A_UINT32 status; /* enum wmi_extscan_start_stop_status */ + /** table ID - to allow support for multiple simultaneous requests */ + A_UINT32 table_id; +} wmi_extscan_start_stop_event_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_extscan_operation_event_fixed_param */ + /** Request ID of the extscan operation that is currently running */ + A_UINT32 request_id; + /** Requestor ID of the extscan operation that is currently running */ + A_UINT32 requestor_id; + /** VDEV id(interface) of the extscan operation that is currently running */ + A_UINT32 vdev_id; + /** scan event (wmi_scan_event_type) */ + A_UINT32 event; /* wmi_extscan_event_type */ + /** table ID - to allow support for multiple simultaneous requests */ + A_UINT32 table_id; + /**number of buckets */ + A_UINT32 num_buckets; + /* Following this structure is the TLV: + * A_UINT32 bucket_id[]; <-- number of elements given by field num_buckets. + */ +} wmi_extscan_operation_event_fixed_param; + +/* Types of extscan tables */ +typedef enum { + EXTSCAN_TABLE_NONE = 0, + EXTSCAN_TABLE_BSSID = 1, + EXTSCAN_TABLE_RSSI = 2, +} wmi_extscan_table_type; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_extscan_table_usage_event_fixed_param */ + /** Request ID of the extscan operation that is currently running */ + A_UINT32 request_id; + /** Requestor ID of the extscan operation that is currently running */ + A_UINT32 requestor_id; + /** VDEV id(interface) of the extscan operation that is currently running */ + A_UINT32 vdev_id; + /** table ID - to allow support for multiple simultaneous tables */ + A_UINT32 table_id; + /**see wmi_extscan_table_type for table reporting usage */ + A_UINT32 table_type; + /**number of entries in use */ + A_UINT32 entries_in_use; + /**maximum number of entries in table */ + A_UINT32 maximum_entries; +} wmi_extscan_table_usage_event_fixed_param; + +typedef enum { + WMI_SCAN_STATUS_INTERRUPTED = 1 /* Indicates scan got interrupted i.e. aborted or pre-empted for a long time (> 1sec) + this can be used to discard scan results */ +} wmi_scan_status_flags; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_ARRAY_STRUC */ + /** RSSI */ + A_UINT32 rssi; + /** time stamp in milliseconds */ + A_UINT32 tstamp; + /** Extscan cycle during which this entry was scanned */ + A_UINT32 scan_cycle_id; + /** flag to indicate if the given result was obtained as part of interrupted (aborted/large time gap preempted) scan */ + A_UINT32 flags; + /** Bitmask of buckets (i.e. sets of channels) scanned */ + A_UINT32 buckets_scanned; +} wmi_extscan_rssi_info; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_ARRAY_STRUC */ + /**bssid */ + wmi_mac_addr bssid; + /**ssid */ + wmi_ssid ssid; + /**channel number */ + A_UINT32 channel; + /* capabilities */ + A_UINT32 capabilities; + /* beacon interval in TUs */ + A_UINT32 beacon_interval; + /**time stamp in milliseconds - time last seen */ + A_UINT32 tstamp; + /**flags - _tExtScanEntryFlags */ + A_UINT32 flags; + /**RTT in ns */ + A_UINT32 rtt; + /**rtt standard deviation */ + A_UINT32 rtt_sd; + /* rssi information */ + A_UINT32 number_rssi_samples; + /** IE length */ + A_UINT32 ie_length; /* length of IE data */ +} wmi_extscan_wlan_descriptor; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_extscan_cached_results_event_fixed_param */ + /** Request ID of the WMI_EXTSCAN_GET_CACHED_RESULTS_CMDID */ + A_UINT32 request_id; + /** Requestor ID of the WMI_EXTSCAN_GET_CACHED_RESULTS_CMDID */ + A_UINT32 requestor_id; + /** VDEV id(interface) of the WMI_EXTSCAN_GET_CACHED_RESULTS_CMDID */ + A_UINT32 vdev_id; + /** Request ID of the extscan operation that is currently running */ + A_UINT32 extscan_request_id; + /** Requestor ID of the extscan operation that is currently running */ + A_UINT32 extscan_requestor_id; + /** VDEV id(interface) of the extscan operation that is currently running */ + A_UINT32 extscan_vdev_id; + /** table ID - to allow support for multiple simultaneous tables */ + A_UINT32 table_id; + /**current time stamp in seconds. Used to provide a baseline for the relative timestamps returned for each block and entry */ + A_UINT32 current_tstamp; + /**total number of bssids (in all pages) */ + A_UINT32 total_entries; + /**index of the first bssid entry found in the TLV wmi_extscan_wlan_descriptor*/ + A_UINT32 first_entry_index; + /**number of bssids in this page */ + A_UINT32 num_entries_in_page; + /** number of buckets scanned**/ + A_UINT32 buckets_scanned; + /* Followed by the variable length TLVs + * wmi_extscan_wlan_descriptor bssid_list[] + * wmi_extscan_rssi_info rssi_list[] + * A_UINT8 ie_list[] + */ +} wmi_extscan_cached_results_event_fixed_param; + +typedef enum { + EXTSCAN_WLAN_CHANGE_FLAG_NONE = 0x00, + EXTSCAN_WLAN_CHANGE_FLAG_OUT_OF_RANGE = 0x01, + EXTSCAN_WLAN_CHANGE_FLAG_AP_LOST = 0x02, +} wmi_extscan_wlan_change_flags; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_ARRAY_STRUC */ + /**bssid */ + wmi_mac_addr bssid; + /**time stamp in milliseconds */ + A_UINT32 tstamp; + /**upper RSSI limit */ + A_UINT32 upper_rssi_limit; + /**lower RSSI limit */ + A_UINT32 lower_rssi_limit; + /** channel */ + A_UINT32 channel; /* in MHz */ + /**current RSSI average */ + A_UINT32 rssi_average; + /**flags - wmi_extscan_wlan_change_flags */ + A_UINT32 flags; + /**legnth of RSSI history to follow (number of values) */ + A_UINT32 num_rssi_samples; +} wmi_extscan_wlan_change_result_bssid; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_extscan_wlan_change_results_event_fixed_param */ + /** Request ID of the WMI_EXTSCAN_GET_WLAN_CHANGE_RESULTS_CMDID command that requested the results */ + A_UINT32 request_id; + /** Requestor ID of the WMI_EXTSCAN_GET_WLAN_CHANGE_RESULTS_CMDID command that requested the results */ + A_UINT32 requestor_id; + /** VDEV id(interface) of the WMI_EXTSCAN_GET_WLAN_CHANGE_RESULTS_CMDID command that requested the results */ + A_UINT32 vdev_id; + /** Request ID of the WMI_EXTSCAN_CONFIGURE_WLAN_CHANGE_MONITOR_CMDID command that configured the table */ + A_UINT32 config_request_id; + /** Requestor ID of the WMI_EXTSCAN_CONFIGURE_WLAN_CHANGE_MONITOR_CMDID command that configured the table */ + A_UINT32 config_requestor_id; + /** VDEV id(interface) of the WMI_EXTSCAN_CONFIGURE_WLAN_CHANGE_MONITOR_CMDID command that configured the table */ + A_UINT32 config_vdev_id; + /** table ID - to allow support for multiple simultaneous tables */ + A_UINT32 table_id; + /**number of entries with RSSI out of range or BSSID not detected */ + A_UINT32 change_count; + /**total number of bssid signal descriptors (in all pages) */ + A_UINT32 total_entries; + /**index of the first bssid signal descriptor entry found in the TLV wmi_extscan_wlan_descriptor*/ + A_UINT32 first_entry_index; + /**number of bssids signal descriptors in this page */ + A_UINT32 num_entries_in_page; +/* Following this structure is the TLV: + * wmi_extscan_wlan_change_result_bssid bssid_signal_descriptor_list[]; + * (number of descriptors given by field num_entries_in_page) + * Following this structure is the list of RSSI values (each is an A_UINT8): + * A_UINT8 rssi_list[]; <-- last N RSSI values. + */ +} wmi_extscan_wlan_change_results_event_fixed_param; + +enum _tExtScanEntryFlags +{ + WMI_HOTLIST_FLAG_NONE = 0x00, + WMI_HOTLIST_FLAG_PRESENCE = 0x01, + WMI_HOTLIST_FLAG_DUPLICATE_SSID = 0x80, +}; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_extscan_hotlist_match_event_fixed_param */ + /** Request ID of the WMI_EXTSCAN_CONFIGURE_HOTLIST_MONITOR_CMDID that configured the table */ + A_UINT32 config_request_id; + /** Requestor ID of the WMI_EXTSCAN_CONFIGURE_HOTLIST_MONITOR_CMDID that configured the table */ + A_UINT32 config_requestor_id; + /** VDEV id(interface) of the WMI_EXTSCAN_CONFIGURE_HOTLIST_MONITOR_CMDID that configured the table */ + A_UINT32 config_vdev_id; + /** table ID - to allow support for multiple simultaneous tables */ + A_UINT32 table_id; + /**total number of bssids (in all pages) */ + A_UINT32 total_entries; + /**index of the first bssid entry found in the TLV wmi_extscan_wlan_descriptor*/ + A_UINT32 first_entry_index; + /**number of bssids in this page */ + A_UINT32 num_entries_in_page; +/* Following this structure is the TLV: + * wmi_extscan_wlan_descriptor hotlist_match[]; <-- number of descriptors given by field num_entries_in_page. + */ +} wmi_extscan_hotlist_match_event_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_extscan_hotlist_match_event_fixed_param */ + /** Request ID of the WMI_EXTSCAN_CONFIGURE_HOTLIST_SSID_MONITOR_CMDID that configured the table */ + A_UINT32 config_request_id; + /** Requestor ID of the WMI_EXTSCAN_CONFIGURE_HOTLIST_SSID_MONITOR_CMDID that configured the table */ + A_UINT32 config_requestor_id; + /** VDEV id(interface) of the WMI_EXTSCAN_CONFIGURE_HOTLIST_SSID_MONITOR_CMDID that configured the table */ + A_UINT32 config_vdev_id; + /** table ID - to allow support for multiple simultaneous tables */ + A_UINT32 table_id; + /**total number of ssids (in all pages) */ + A_UINT32 total_entries; + /**index of the first ssid entry found in the TLV wmi_extscan_wlan_descriptor*/ + A_UINT32 first_entry_index; + /**number of ssids in this page */ + A_UINT32 num_entries_in_page; +/* Following this structure is the TLV: + * wmi_extscan_wlan_descriptor hotlist_match[]; <-- number of descriptors given by field num_entries_in_page. + */ +} wmi_extscan_hotlist_ssid_match_event_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_extscan_capabilities_event_fixed_param */ + /** Request ID of the WMI_EXTSCAN_GET_CAPABILITIES_CMDID */ + A_UINT32 request_id; + /** Requestor ID of the WMI_EXTSCAN_GET_CAPABILITIES_CMDID */ + A_UINT32 requestor_id; + /** VDEV id(interface) of the WMI_EXTSCAN_GET_CAPABILITIES_CMDID */ + A_UINT32 vdev_id; + /** number of extscan caches */ + A_UINT32 num_extscan_cache_tables; + /** number of wlan change lists */ + A_UINT32 num_wlan_change_monitor_tables; + /** number of hotlists */ + A_UINT32 num_hotlist_monitor_tables; + /** if one sided rtt data collection is supported */ + A_UINT32 rtt_one_sided_supported; + /** if 11v data collection is supported */ + A_UINT32 rtt_11v_supported; + /** if 11mc data collection is supported */ + A_UINT32 rtt_ftm_supported; + /** number of extscan cache capabilities (one per table) */ + A_UINT32 num_extscan_cache_capabilities; + /** number of wlan change capabilities (one per table) */ + A_UINT32 num_extscan_wlan_change_capabilities; + /** number of extscan hotlist capabilities (one per table) */ + A_UINT32 num_extscan_hotlist_capabilities; + /* max number of roaming ssid whitelist firmware can support */ + A_UINT32 num_roam_ssid_whitelist; + /* max number of blacklist bssid firmware can support */ + A_UINT32 num_roam_bssid_blacklist; + /* max number of preferred list firmware can support */ + A_UINT32 num_roam_bssid_preferred_list; + /* max number of hotlist ssids firmware can support */ + A_UINT32 num_extscan_hotlist_ssid; + /* max number of epno networks firmware can support */ + A_UINT32 num_epno_networks; + +/* Following this structure are the TLVs describing the capabilities of of the various types of lists. The FW theoretically + * supports multiple lists of each type. + * + * wmi_extscan_cache_capabilities extscan_cache_capabilities[] <-- capabilities of extscan cache (BSSID/RSSI lists) + * wmi_extscan_wlan_change_monitor_capabilities wlan_change_capabilities[] <-- capabilities of wlan_change_monitor_tables + * wmi_extscan_hotlist_monitor_capabilities hotlist_capabilities[] <-- capabilities of hotlist_monitor_tables + */ +} wmi_extscan_capabilities_event_fixed_param; + +/* WMI_D0_WOW_DISABLE_ACK_EVENTID */ +typedef struct{ + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_d0_wow_disable_ack_event_fixed_param */ + A_UINT32 reserved0; /* for future need */ +} wmi_d0_wow_disable_ack_event_fixed_param; + +/** WMI_PDEV_RESUME_EVENTID : generated in response to WMI_PDEV_RESUME_CMDID */ +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_pdev_resume_event_fixed_param */ + /** pdev_id for identifying the MAC + * See macros starting with WMI_PDEV_ID_ for values. + */ + A_UINT32 pdev_id; +} wmi_pdev_resume_event_fixed_param; + + + +/** value representing all modules */ +#define WMI_DEBUG_LOG_MODULE_ALL 0xffff + +/* param definitions */ + +/** + * Log level for a given module. Value contains both module id and log level. + * here is the bitmap definition for value. + * module Id : 16 + * Flags : reserved + * Level : 8 + * if odule Id is WMI_DEBUG_LOG_MODULE_ALL then log level is applied to all modules (global). + * WMI_DEBUG_LOG_MIDULE_ALL will overwrites per module level setting. + */ +#define WMI_DEBUG_LOG_PARAM_LOG_LEVEL 0x1 + +#define WMI_DBGLOG_SET_LOG_LEVEL(val,lvl) do { \ + (val) |= (lvl & 0xff); \ + } while (0) + +#define WMI_DBGLOG_GET_LOG_LEVEL(val) ((val) & 0xff) + +#define WMI_DBGLOG_SET_MODULE_ID(val,mid) do { \ + (val) |= ((mid & 0xffff) << 16); \ + } while (0) + +#define WMI_DBGLOG_GET_MODULE_ID(val) (((val) >> 16) & 0xffff) + +/** + * Enable the debug log for a given vdev. Value is vdev id + */ +#define WMI_DEBUG_LOG_PARAM_VDEV_ENABLE 0x2 + + +/** + * Disable the debug log for a given vdev. Value is vdev id + * All the log level for a given VDEV is disabled except the ERROR log messages + */ + +#define WMI_DEBUG_LOG_PARAM_VDEV_DISABLE 0x3 + +/** + * set vdev enable bitmap. value is the vden enable bitmap + */ +#define WMI_DEBUG_LOG_PARAM_VDEV_ENABLE_BITMAP 0x4 + +/** + * set a given log level to all the modules specified in the module bitmap. + * and set the log levle for all other modules to DBGLOG_ERR. + * value: log levelt to be set. + * module_id_bitmap : identifies the modules for which the log level should be set and + * modules for which the log level should be reset to DBGLOG_ERR. + */ +#define WMI_DEBUG_LOG_PARAM_MOD_ENABLE_BITMAP 0x5 + +#define NUM_MODULES_PER_ENTRY ((sizeof(A_UINT32)) << 3) + +#define WMI_MODULE_ENABLE(pmid_bitmap,mod_id) \ + ((pmid_bitmap)[(mod_id)/NUM_MODULES_PER_ENTRY] |= \ + (1 << ((mod_id)%NUM_MODULES_PER_ENTRY))) + +#define WMI_MODULE_DISABLE(pmid_bitmap,mod_id) \ + ((pmid_bitmap)[(mod_id)/NUM_MODULES_PER_ENTRY] &= \ + (~(1 << ((mod_id)%NUM_MODULES_PER_ENTRY)))) + +#define WMI_MODULE_IS_ENABLED(pmid_bitmap,mod_id) \ + (((pmid_bitmap)[(mod_id)/NUM_MODULES_PER_ENTRY] & \ + (1 << ((mod_id)%NUM_MODULES_PER_ENTRY))) != 0) + +#define MAX_MODULE_ID_BITMAP_WORDS 16 /* 16*32=512 module ids. should be more than sufficient */ +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_debug_log_config_cmd_fixed_param */ + A_UINT32 dbg_log_param; /** param types are defined above */ + A_UINT32 value; + /* The below array will follow this tlv ->fixed length module_id_bitmap[] + A_UINT32 module_id_bitmap[MAX_MODULE_ID_BITMAP_WORDS]; + */ +} wmi_debug_log_config_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_pdev_get_temperature_cmd_fixed_param */ + A_UINT32 param; /* Reserved for future use */ + /** pdev_id for identifying the MAC + * See macros starting with WMI_PDEV_ID_ for values. + */ + A_UINT32 pdev_id; +} wmi_pdev_get_temperature_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_pdev_temperature_event_fixed_param */ + A_INT32 value; /* temprature value in Celcius degree */ + /** pdev_id for identifying the MAC + * See macros starting with WMI_PDEV_ID_ for values. + */ + A_UINT32 pdev_id; +} wmi_pdev_temperature_event_fixed_param; + +typedef enum { + ANTDIV_HW_CFG_STATUS, + ANTDIV_SW_CFG_STATUS, + ANTDIV_MAX_STATUS_TYPE_NUM +} ANTDIV_STATUS_TYPE; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_pdev_get_antdiv_status_cmd_fixed_param */ + A_UINT32 status_event_id; /* Status event ID - see ANTDIV_STATUS_TYPE */ + /** pdev_id for identifying the MAC + * See macros starting with WMI_PDEV_ID_ for values. + */ + A_UINT32 pdev_id; +} wmi_pdev_get_antdiv_status_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_pdev_antdiv_status_event_fixed_param */ + A_UINT32 support; /* ANT DIV feature enabled or not */ + A_UINT32 chain_num; /* how many chain supported */ + A_UINT32 ant_num; /* how many ANT supported, 32 max */ + /* + * Each entry is for a tx/rx chain, and contains a bitmap identifying + * the antennas attached to that tx/rx chain. + */ + A_UINT32 selectable_ant_mask[8]; + /** pdev_id for identifying the MAC + * See macros starting with WMI_PDEV_ID_ for values. + */ + A_UINT32 pdev_id; +} wmi_pdev_antdiv_status_event_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_set_dhcp_server_offload_cmd_fixed_param */ + A_UINT32 vdev_id; + A_UINT32 enable; + A_UINT32 srv_ipv4; /* server IP */ + A_UINT32 start_lsb; /* starting address assigned to client */ + A_UINT32 num_client; /* number of clients we support */ +} wmi_set_dhcp_server_offload_cmd_fixed_param; + +typedef enum { + AP_RX_DATA_OFFLOAD = 0x00, + STA_RX_DATA_OFFLOAD = 0x01, +} wmi_ipa_offload_types; + +/** + * This command is sent from WLAN host driver to firmware for + * enabling/disabling IPA data-path offload features. + * + * + * Enabling data path offload to IPA(based on host INI configuration), example: + * when STA interface comes up, + * host->target: WMI_IPA_OFFLOAD_ENABLE_DISABLE_CMD, + * (enable = 1, vdev_id = STA vdev id, offload_type = STA_RX_DATA_OFFLOAD) + * + * Disabling data path offload to IPA, example: + * host->target: WMI_IPA_OFFLOAD_ENABLE_DISABLE_CMD, + * (enable = 0, vdev_id = STA vdev id, offload_type = STA_RX_DATA_OFFLOAD) + * + * + * This command is applicable only on the PCIE LL systems + * + */ +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_ipa_offload_enable_disable_cmd_fixed_param */ + A_UINT32 offload_type; /* wmi_ipa_offload_types enum values */ + A_UINT32 vdev_id; + A_UINT32 enable; /* 1 == enable, 0 == disable */ +} wmi_ipa_offload_enable_disable_cmd_fixed_param; + +typedef enum { + WMI_LED_FLASHING_PATTERN_NOT_CONNECTED = 0, + WMI_LED_FLASHING_PATTERN_CONNECTED = 1, + WMI_LED_FLASHING_PATTERN_RESERVED = 2, +} wmi_set_led_flashing_type; + +/** +The state of the LED GPIO control is determined by two 32 bit values(X_0 and X_1) to produce a 64 bit value. +Each 32 bit value consists of 4 bytes, where each byte defines the number of 50ms intervals that the GPIO will +remain at a predetermined state. The 64 bit value provides 8 unique GPIO timing intervals. The pattern starts +with the MSB of X_0 and continues to the LSB of X_1. After executing the timer interval of the LSB of X_1, the +pattern returns to the MSB of X_0 and repeats. The GPIO state for each timing interval alternates from Low to +High and the first interval of the pattern represents the time when the GPIO is Low. When a timing interval of +Zero is reached, it is skipped and moves on to the next interval. +*/ +typedef struct{ + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_set_led_flashing_cmd_fixed_param */ + A_UINT32 pattern_id; /* pattern identifier */ + A_UINT32 led_x0; /* led flashing parameter0 */ + A_UINT32 led_x1; /* led flashing parameter1 */ + A_UINT32 gpio_num; /* GPIO number */ +} wmi_set_led_flashing_cmd_fixed_param; + +/** + * The purpose of the multicast Domain Name System (mDNS) is to resolve host names to IP addresses + * within small networks that do not include a local name server. + * It utilizes essentially the same programming interfaces, packet formats and operating semantics + * as the unicast DNS, and the advantage is zero configuration service while no need for central or + * global server. + * Based on mDNS, the DNS-SD (Service Discovery) allows clients to discover a named list of services + * by type in a specified domain using standard DNS queries. + * Here, we provide the ability to advertise the available services by responding to mDNS queries. + */ +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_mdns_offload_cmd_fixed_param */ + A_UINT32 vdev_id; + A_UINT32 enable; +} wmi_mdns_offload_cmd_fixed_param; + +#define WMI_MAX_MDNS_FQDN_LEN 64 +#define WMI_MAX_MDNS_RESP_LEN 512 +#define WMI_MDNS_FQDN_TYPE_GENERAL 0 +#define WMI_MDNS_FQDN_TYPE_UNIQUE 1 + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_mdns_set_fqdn_cmd_fixed_param */ + A_UINT32 vdev_id; + /** type of fqdn, general or unique */ + A_UINT32 type; + /** length of fqdn */ + A_UINT32 fqdn_len; + /* Following this structure is the TLV byte stream of fqdn data of length fqdn_len + * A_UINT8 fqdn_data[]; <-- fully-qualified domain name to check if match with the received queries + */ +} wmi_mdns_set_fqdn_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_mdns_set_resp_cmd_fixed_param */ + A_UINT32 vdev_id; + /** Answer Resource Record count */ + A_UINT32 AR_count; + /** length of response */ + A_UINT32 resp_len; + /* Following this structure is the TLV byte stream of resp data of length resp_len + * A_UINT8 resp_data[]; <-- responses consisits of Resource Records + */ +} wmi_mdns_set_resp_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_mdns_get_stats_cmd_fixed_param */ + A_UINT32 vdev_id; +} wmi_mdns_get_stats_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_mdns_stats_event_fixed_param */ + A_UINT32 vdev_id; + /** curTimestamp in milliseconds */ + A_UINT32 curTimestamp; + /** last received Query in milliseconds */ + A_UINT32 lastQueryTimestamp; + /** last sent Response in milliseconds */ + A_UINT32 lastResponseTimestamp; + /** stats of received queries */ + A_UINT32 totalQueries; + /** stats of macth queries */ + A_UINT32 totalMatches; + /** stats of responses */ + A_UINT32 totalResponses; + /** indicate the current status of mDNS offload */ + A_UINT32 status; +} wmi_mdns_stats_event_fixed_param; + +/** + * The purpose of the SoftAP authenticator offload is to offload the association and 4-way handshake process + * down to the firmware. When this feature is enabled, firmware can process the association/disassociation + * request and create/remove connection even host is suspended. + * 3 major components are offloaded: + * 1. ap-mlme. Firmware will process auth/deauth, association/disassociation request and send out response. + * 2. 4-way handshake. Firmware will send out m1/m3 and receive m2/m4. + * 3. key installation. Firmware will generate PMK from the psk info which is sent from the host and install PMK/GTK. + * Current implementation only supports WPA2 CCMP. + */ + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_sap_ofl_enable_cmd_fixed_param */ + /** VDEV id(interface) of the WMI_SAP_OFL_ENABLE_CMDID */ + A_UINT32 vdev_id; + /** enable/disable sap auth offload */ + A_UINT32 enable; + /** sap ssid */ + wmi_ssid ap_ssid; + /** authentication mode (defined above) */ + A_UINT32 rsn_authmode; + /** unicast cipher set */ + A_UINT32 rsn_ucastcipherset; + /** mcast/group cipher set */ + A_UINT32 rsn_mcastcipherset; + /** mcast/group management frames cipher set */ + A_UINT32 rsn_mcastmgmtcipherset; + /** sap channel */ + A_UINT32 channel; + /** length of psk */ + A_UINT32 psk_len; + /* Following this structure is the TLV byte stream of wpa passphrase data of length psk_len + * A_UINT8 psk[]; + */ +} wmi_sap_ofl_enable_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_sap_ofl_add_sta_event_fixed_param */ + /** VDEV id(interface) of the WMI_SAP_OFL_ADD_STA_EVENTID */ + A_UINT32 vdev_id; + /** aid (association id) of this station */ + A_UINT32 assoc_id; + /** peer station's mac addr */ + wmi_mac_addr peer_macaddr; + /** length of association request frame */ + A_UINT32 data_len; + /* Following this structure is the TLV byte stream of a whole association request frame of length data_len + * A_UINT8 bufp[]; + */ +} wmi_sap_ofl_add_sta_event_fixed_param; + +typedef enum { + SAP_OFL_DEL_STA_FLAG_NONE = 0x00, + SAP_OFL_DEL_STA_FLAG_RECONNECT = 0x01, +} wmi_sap_ofl_del_sta_flags; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_sap_ofl_del_sta_event_fixed_param */ + /** VDEV id(interface) of the WMI_SAP_OFL_DEL_STA_EVENTID */ + A_UINT32 vdev_id; + /** aid (association id) of this station */ + A_UINT32 assoc_id; + /** peer station's mac addr */ + wmi_mac_addr peer_macaddr; + /** disassociation reason */ + A_UINT32 reason; + /** flags - wmi_sap_ofl_del_sta_flags */ + A_UINT32 flags; +} wmi_sap_ofl_del_sta_event_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_sap_set_blacklist_param_cmd_fixed_param */ + A_UINT32 vdev_id; + /* Number of client failure connection attempt */ + A_UINT32 num_retry; + /* Time in milliseconds to record the client's failure connection attempts */ + A_UINT32 retry_allow_time_ms; + /* Time in milliseconds to drop the connection request if client is blacklisted */ + A_UINT32 blackout_time_ms; +} wmi_sap_set_blacklist_param_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_apfind_cmd_param */ + A_UINT32 data_len; /** length in byte of data[]. */ + /** This structure is used to send REQ binary blobs + * from application/service to firmware where Host drv is pass through . + * Following this structure is the TLV: + * A_UINT8 data[]; <-- length in byte given by field data_len. + */ +} wmi_apfind_cmd_param; + +typedef enum apfind_event_type_e { + APFIND_MATCH_EVENT = 0, + APFIND_WAKEUP_EVENT, +} APFIND_EVENT_TYPE; + +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_apfind_event_hdr */ + A_UINT32 event_type; /** APFIND_EVENT_TYPE */ + A_UINT32 data_len; /** length in byte of data[]. */ + /** This structure is used to send event binary blobs + * from firmware to application/service and Host drv. + * Following this structure is the TLV: + * A_UINT8 data[]; <-- length in byte given by field data_len. + */ +} wmi_apfind_event_hdr; + + +/** + * OCB DCC types and structures. + */ + +/** + * DCC types as described in ETSI TS 102 687 + * Type Format stepSize referenceValue numBits + * ------------------------------------------------------------------------- + * ndlType_acPrio INTEGER (0...7) 1 number 3 + * ndlType_controlLoop INTEGER (0...7) 1 0 3 + * ndlType_arrivalRate INTEGER (0..8191) 0.01 /s 0 13 + * ndlType_channelLoad INTEGER (0..1000) 0.1 % 0 % 10 + * ndlType_channelUse INTEGER (0..8000) 0.0125 % 0 % 13 + * ndlType_datarate INTEGER (0..7) Table 8 3 + * ndlType_distance INTEGER (0..4095) 1 m 0 12 + * ndlType_numberElements INTEGER (0..63) number 6 + * ndlType_packetDuration INTEGER (0..2047) TSYM 0 11 + * ndlType_packetInterval INTEGER (0..1023) 10 ms 0 10 + * ndlType_pathloss INTEGER (0..31) 0.1 1.0 5 + * ndlType_rxPower INTEGER (0..127) -0.5 dB -40 dBm 7 + * ndlType_snr INTEGER (0..127) 0.5 dB -10 dB 7 + * ndlType_timing INTEGER (0..4095) 10 ms 0 12 + * ndlType_txPower INTEGER (0..127) 0.5 dB -20 dBm 7 + * ndlType_ratio INTEGER (0..100) 1 % 0 % 7 + * ndlType_exponent INTEGER (0..100) 0.1 0 7 + * ndlType_queueStatus Enumeration Table A.2 1 + * ndlType_dccMechanism Bitset Table A.2 6 + * + * NOTE: All of following size macros (SIZE_NDLTYPE_ACPRIO through SIZE_BYTE) + * cannot be changed without breaking WMI compatibility. + * + * NOTE: For each of the types, one additional bit is allocated. This + * leftmost bit is used to indicate that the value is invalid. */ +#define SIZE_NDLTYPE_ACPRIO (1 + 3) +#define SIZE_NDLTYPE_CONTROLLOOP (1 + 3) +#define SIZE_NDLTYPE_ARRIVALRATE (1 + 13) +#define SIZE_NDLTYPE_CHANNELLOAD (1 + 10) +#define SIZE_NDLTYPE_CHANNELUSE (1 + 13) +#define SIZE_NDLTYPE_DATARATE (1 + 3) +#define SIZE_NDLTYPE_DISTANCE (1 + 12) +#define SIZE_NDLTYPE_NUMBERELEMENTS (1 + 6) +#define SIZE_NDLTYPE_PACKETDURATION (1 + 11) +#define SIZE_NDLTYPE_PACKETINTERVAL (1 + 10) +#define SIZE_NDLTYPE_PATHLOSS (1 + 5) +#define SIZE_NDLTYPE_RXPOWER (1 + 7) +#define SIZE_NDLTYPE_SNR (1 + 7) +#define SIZE_NDLTYPE_TIMING (1 + 12) +#define SIZE_NDLTYPE_TXPOWER (1 + 7) +#define SIZE_NDLTYPE_RATIO (1 + 7) +#define SIZE_NDLTYPE_EXPONENT (1 + 7) +#define SIZE_NDLTYPE_QUEUESTATUS (1 + 1) +#define SIZE_NDLTYPE_DCCMECHANISM (1 + 6) +#define SIZE_BYTE (8) + +#define INVALID_ACPRIO ((1 << SIZE_NDLTYPE_ACPRIO) - 1) +#define INVALID_CONTROLLOOP ((1 << SIZE_NDLTYPE_CONTROLLOOP) - 1) +#define INVALID_ARRIVALRATE ((1 << SIZE_NDLTYPE_ARRIVALRATE) - 1) +#define INVALID_CHANNELLOAD ((1 << SIZE_NDLTYPE_CHANNELLOAD) - 1) +#define INVALID_CHANNELUSE ((1 << SIZE_NDLTYPE_CHANNELUSE) - 1) +#define INVALID_DATARATE ((1 << SIZE_NDLTYPE_DATARATE) - 1) +#define INVALID_DISTANCE ((1 << SIZE_NDLTYPE_DISTANCE) - 1) +#define INVALID_NUMBERELEMENTS ((1 << SIZE_NDLTYPE_NUMBERELEMENTS) - 1) +#define INVALID_PACKETDURATION ((1 << SIZE_NDLTYPE_PACKETDURATION) - 1) +#define INVALID_PACKETINTERVAL ((1 << SIZE_NDLTYPE_PACKETINTERVAL) - 1) +#define INVALID_PATHLOSS ((1 << SIZE_NDLTYPE_PATHLOSS) - 1) +#define INVALID_RXPOWER ((1 << SIZE_NDLTYPE_RXPOWER) - 1) +#define INVALID_SNR ((1 << SIZE_NDLTYPE_SNR) - 1) +#define INVALID_TIMING ((1 << SIZE_NDLTYPE_TIMING) - 1) +#define INVALID_TXPOWER ((1 << SIZE_NDLTYPE_TXPOWER) - 1) +#define INVALID_RATIO ((1 << SIZE_NDLTYPE_RATIO) - 1) +#define INVALID_EXPONENT ((1 << SIZE_NDLTYPE_EXPONENT) - 1) +#define INVALID_QUEUESTATS ((1 << SIZE_NDLTYPE_QUEUESTATUS) - 1) +#define INVALID_DCCMECHANISM ((1 << SIZE_NDLTYPE_DCCMECHANISM) - 1) + +/** The MCS_COUNT macro cannot be modified without breaking + * WMI compatibility. */ +#define MCS_COUNT (8) + +/** Flags for ndlType_dccMechanism. */ +typedef enum { + DCC_MECHANISM_TPC = 1, + DCC_MECHANISM_TRC = 2, + DCC_MECHANISM_TDC = 4, + DCC_MECHANISM_DSC = 8, + DCC_MECHANISM_TAC = 16, + DCC_MECHANISM_RESERVED = 32, + DCC_MECHANISM_ALL = 0x3f, +} wmi_dcc_ndl_type_dcc_mechanism; + +/** Values for ndlType_queueStatus. */ +typedef enum { + DCC_QUEUE_CLOSED = 0, + DCC_QUEUE_OPEN = 1, +} wmi_dcc_ndl_type_queue_status; + +/** For ndlType_acPrio, use the values in wmi_traffic_ac. */ + +/** Values for ndlType_datarate */ +typedef enum { + DCC_DATARATE_3_MBPS = 0, + DCC_DATARATE_4_5_MBPS = 1, + DCC_DATARATE_6_MBPS = 2, + DCC_DATARATE_9_MBPS = 3, + DCC_DATARATE_12_MBPS = 4, + DCC_DATARATE_18_MBPS = 5, + DCC_DATARATE_24_MBPS = 6, + DCC_DATARATE_27_MBPS = 7, +} wmi_dcc_ndl_type_datarate; + +/** Data structure for active state configuration. */ +typedef struct { + /** TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_dcc_ndl_active_state_config */ + A_UINT32 tlv_header; + /** + * NDL_asStateId, ndlType_numberElements, 1+6 bits. + * NDL_asChanLoad, ndlType_channelLoad, 1+10 bits. + */ + A_UINT32 state_info; + /** + * NDL_asDcc(AC_BK), ndlType_dccMechanism, 1+6 bits. + * NDL_asDcc(AC_BE), ndlType_dccMechanism, 1+6 bits. + * NDL_asDcc(AC_VI), ndlType_dccMechanism, 1+6 bits. + * NDL_asDcc(AC_VO), ndlType_dccMechanism, 1+6 bits. + */ + A_UINT32 as_dcc[WMI_PACKED_ARR_SIZE(WLAN_MAX_AC, SIZE_NDLTYPE_DCCMECHANISM)]; + + /** + * NDL_asTxPower(AC_BK), ndlType_txPower, 1+7 bits. + * NDL_asTxPower(AC_BE), ndlType_txPower, 1+7 bits. + * NDL_asTxPower(AC_VI), ndlType_txPower, 1+7 bits. + * NDL_asTxPower(AC_VO), ndlType_txPower, 1+7 bits. + */ + A_UINT32 as_tx_power_ac[WMI_PACKED_ARR_SIZE(WLAN_MAX_AC, SIZE_NDLTYPE_TXPOWER)]; + /** + * NDL_asPacketInterval(AC_BK), ndlType_packetInterval, 1+10 bits. + * NDL_asPacketInterval(AC_BE), ndlType_packetInterval, 1+10 bits. + * NDL_asPacketInterval(AC_VI), ndlType_packetInterval, 1+10 bits. + * NDL_asPacketInterval(AC_VO), ndlType_packetInterval, 1+10 bits. + */ + A_UINT32 as_packet_interval_ac[WMI_PACKED_ARR_SIZE(WLAN_MAX_AC, SIZE_NDLTYPE_PACKETINTERVAL)]; + /** + * NDL_asDatarate(AC_BK), ndlType_datarate, 1+3 bits. + * NDL_asDatarate(AC_BE), ndlType_datarate, 1+3 bits. + * NDL_asDatarate(AC_VI), ndlType_datarate, 1+3 bits. + * NDL_asDatarate(AC_VO), ndlType_datarate, 1+3 bits. + */ + A_UINT32 as_datarate_ac[WMI_PACKED_ARR_SIZE(WLAN_MAX_AC, SIZE_NDLTYPE_DATARATE)]; + /** + * NDL_asCarrierSense(AC_BK), ndlType_rxPower, 1+7 bits. + * NDL_asCarrierSense(AC_BE), ndlType_rxPower, 1+7 bits. + * NDL_asCarrierSense(AC_VI), ndlType_rxPower, 1+7 bits. + * NDL_asCarrierSense(AC_VO), ndlType_rxPower, 1+7 bits. + */ + A_UINT32 as_carrier_sense_ac[WMI_PACKED_ARR_SIZE(WLAN_MAX_AC, SIZE_NDLTYPE_RXPOWER)]; +} wmi_dcc_ndl_active_state_config; + +#define WMI_NDL_AS_STATE_ID_GET(ptr) WMI_GET_BITS((ptr)->state_info, 0, 7) +#define WMI_NDL_AS_STATE_ID_SET(ptr,val) WMI_SET_BITS((ptr)->state_info, 0, 7, val) +#define WMI_NDL_AS_CHAN_LOAD_GET(ptr) WMI_GET_BITS((ptr)->state_info, 7, 11) +#define WMI_NDL_AS_CHAN_LOAD_SET(ptr,val) WMI_SET_BITS((ptr)->state_info, 7, 11, val) +#define WMI_NDL_AS_DCC_GET(ptr,acprio) wmi_packed_arr_get_bits((ptr)->as_dcc, acprio, SIZE_NDLTYPE_DCCMECHANISM) +#define WMI_NDL_AS_DCC_SET(ptr,acprio,val) wmi_packed_arr_set_bits((ptr)->as_dcc, acprio, SIZE_NDLTYPE_DCCMECHANISM, val) +#define WMI_NDL_AS_TX_POWER_GET(ptr,acprio) wmi_packed_arr_get_bits((ptr)->as_tx_power_ac, acprio, SIZE_NDLTYPE_TXPOWER) +#define WMI_NDL_AS_TX_POWER_SET(ptr,acprio,val) wmi_packed_arr_set_bits((ptr)->as_tx_power_ac, acprio, SIZE_NDLTYPE_TXPOWER, val) +#define WMI_NDL_AS_PACKET_INTERVAL_GET(ptr,acprio) wmi_packed_arr_get_bits((ptr)->as_packet_interval_ac, acprio, SIZE_NDLTYPE_PACKETINTERVAL) +#define WMI_NDL_AS_PACKET_INTERVAL_SET(ptr,acprio,val) wmi_packed_arr_set_bits((ptr)->as_packet_interval_ac, acprio, SIZE_NDLTYPE_PACKETINTERVAL, val) +#define WMI_NDL_AS_DATARATE_GET(ptr,acprio) wmi_packed_arr_get_bits((ptr)->as_datarate_ac, acprio, SIZE_NDLTYPE_DATARATE) +#define WMI_NDL_AS_DATARATE_SET(ptr,acprio,val) wmi_packed_arr_set_bits((ptr)->as_datarate_ac, acprio, SIZE_NDLTYPE_DATARATE, val) +#define WMI_NDL_AS_CARRIER_SENSE_GET(ptr,acprio) wmi_packed_arr_get_bits((ptr)->as_carrier_sense_ac, acprio, SIZE_NDLTYPE_RXPOWER) +#define WMI_NDL_AS_CARRIER_SENSE_SET(ptr,acprio,val) wmi_packed_arr_set_bits((ptr)->as_carrier_sense_ac, acprio, SIZE_NDLTYPE_RXPOWER, val) + +/** Data structure for EDCA/QOS parameters. */ +typedef struct +{ + /** TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_qos_parameter */ + A_UINT32 tlv_header; + /** Arbitration Inter-Frame Spacing. Range: 2-15 */ + A_UINT32 aifsn; + /** Contention Window minimum. Range: 1 - 10 */ + A_UINT32 cwmin; + /** Contention Window maximum. Range: 1 - 10 */ + A_UINT32 cwmax; +} wmi_qos_parameter; + +/** Data structure for information specific to a channel. */ +typedef struct { + /** TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_ocb_channel */ + A_UINT32 tlv_header; + A_UINT32 bandwidth; /* MHz units */ + wmi_mac_addr mac_address; +} wmi_ocb_channel; + +/** Data structure for an element of the schedule array. */ +typedef struct { + /** TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_ocb_schedule_element */ + A_UINT32 tlv_header; + A_UINT32 channel_freq; /* MHz units */ + A_UINT32 total_duration; /* ms units */ + A_UINT32 guard_interval; /* ms units */ +} wmi_ocb_schedule_element; + +/** Data structure for OCB configuration. */ +typedef struct { + /** TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_ocb_set_config_cmd_fixed_param */ + A_UINT32 tlv_header; + /** VDEV id(interface) that is being configured */ + A_UINT32 vdev_id; + A_UINT32 channel_count; + A_UINT32 schedule_size; + A_UINT32 flags; + A_UINT32 ta_max_duration; /* Max duration of continuing multichannel operation without receiving a TA frame (units = seconds) */ + + /** This is followed by a TLV array of wmi_channel. */ + /** This is followed by a TLV array of wmi_ocb_channel. */ + /** This is followed by a TLV array of wmi_qos_parameter. */ + /** This is followed by a TLV array of wmi_dcc_ndl_chan. */ + /** This is followed by a TLV array of wmi_dcc_ndl_active_state_config. */ + /** This is followed by a TLV array of wmi_ocb_schedule_element. */ +} wmi_ocb_set_config_cmd_fixed_param; + +#define EXPIRY_TIME_IN_TSF_TIMESTAMP_OFFSET 0 +#define EXPIRY_TIME_IN_TSF_TIMESTAMP_MASK 1 + +#define WMI_OCB_EXPIRY_TIME_IN_TSF(ptr) (((ptr)->flags & EXPIRY_TIME_IN_TSF_TIMESTAMP_MASK) >> EXPIRY_TIME_IN_TSF_TIMESTAMP_OFFSET) + + +/** Data structure for the response to the WMI_OCB_SET_CONFIG_CMDID command. */ +typedef struct { + /** TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_ocb_set_config_resp_event_fixed_param */ + A_UINT32 tlv_header; + /* VDEV identifier */ + A_UINT32 vdev_id; + A_UINT32 status; +} wmi_ocb_set_config_resp_event_fixed_param; + +/* SIZE_UTC_TIME and SIZE_UTC_TIME_ERROR cannot be modified without breaking + WMI compatibility. */ +#define SIZE_UTC_TIME (10) /* The size of the utc time in bytes. */ +#define SIZE_UTC_TIME_ERROR (5) /* The size of the utc time error in bytes. */ + +/** Data structure to set the UTC time. */ +typedef struct { + /** TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_ocb_set_utc_time_cmd_fixed_param */ + A_UINT32 tlv_header; + /* VDEV identifier */ + A_UINT32 vdev_id; + /** 10 bytes of the utc time. */ + A_UINT32 utc_time[WMI_PACKED_ARR_SIZE(SIZE_UTC_TIME,SIZE_BYTE)]; + /** 5 bytes of the time error. */ + A_UINT32 time_error[WMI_PACKED_ARR_SIZE(SIZE_UTC_TIME_ERROR,SIZE_BYTE)]; +} wmi_ocb_set_utc_time_cmd_fixed_param; + +#define WMI_UTC_TIME_GET(ptr,byte_index) wmi_packed_arr_get_bits((ptr)->utc_time, byte_index, SIZE_BYTE) +#define WMI_UTC_TIME_SET(ptr,byte_index,val) wmi_packed_arr_set_bits((ptr)->utc_time, byte_index, SIZE_BYTE, val) +#define WMI_TIME_ERROR_GET(ptr,byte_index) wmi_packed_arr_get_bits((ptr)->time_error, byte_index, SIZE_BYTE) +#define WMI_TIME_ERROR_SET(ptr,byte_index,val) wmi_packed_arr_set_bits((ptr)->time_error, byte_index, SIZE_BYTE, val) + +/** Data structure start the timing advertisement. The template for the + * timing advertisement frame follows this structure in the WMI command. + */ +typedef struct { + /** TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_ocb_start_timing_advert_cmd_fixed_param */ + A_UINT32 tlv_header; + /* VDEV identifier */ + A_UINT32 vdev_id; + /** Number of times the TA is sent every 5 seconds. */ + A_UINT32 repeat_rate; + /** The frequency on which to transmit. */ + A_UINT32 channel_freq; /* MHz units */ + /** The offset into the template of the timestamp. */ + A_UINT32 timestamp_offset; + /** The offset into the template of the time value. */ + A_UINT32 time_value_offset; + /** The length of the timing advertisement template. The + * template is in the TLV data. */ + A_UINT32 timing_advert_template_length; + + /** This is followed by a binary array containing the TA template. */ +} wmi_ocb_start_timing_advert_cmd_fixed_param; + +/** Data structure to stop the timing advertisement. */ +typedef struct { + /** TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_ocb_stop_timing_advert_cmd_fixed_param */ + A_UINT32 tlv_header; + /* VDEV identifier */ + A_UINT32 vdev_id; + A_UINT32 channel_freq; /* MHz units */ +} wmi_ocb_stop_timing_advert_cmd_fixed_param; + +/** Data structure for the request for WMI_OCB_GET_TSF_TIMER_CMDID. */ +typedef struct { + /** TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_ocb_get_tsf_timer_cmd_fixed_param */ + A_UINT32 tlv_header; + /* VDEV identifier */ + A_UINT32 vdev_id; + A_UINT32 reserved; +} wmi_ocb_get_tsf_timer_cmd_fixed_param; + +/** Data structure for the response to WMI_OCB_GET_TSF_TIMER_CMDID. */ +typedef struct { + /** TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_ocb_get_tsf_timer_resp_event_fixed_param */ + A_UINT32 tlv_header; + /* VDEV identifier */ + A_UINT32 vdev_id; + A_UINT32 tsf_timer_high; + A_UINT32 tsf_timer_low; +} wmi_ocb_get_tsf_timer_resp_event_fixed_param; + +/** Data structure for DCC stats configuration per channel. */ +typedef struct { + /** TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_dcc_ndl_stats_per_channel */ + A_UINT32 tlv_header; + + /** The channel for which this applies, 16 bits. */ + /** The dcc_stats_bitmap, 8 bits. */ + A_UINT32 chan_info; + + /** Demodulation model parameters. */ + /** + * NDL_snrBackoff(MCS0), ndlType_snr, 1+7 bits. + * NDL_snrBackoff(MCS1), ndlType_snr, 1+7 bits. + * NDL_snrBackoff(MCS2), ndlType_snr, 1+7 bits. + * NDL_snrBackoff(MCS3), ndlType_snr, 1+7 bits. + * NDL_snrBackoff(MCS4), ndlType_snr, 1+7 bits. + * NDL_snrBackoff(MCS5), ndlType_snr, 1+7 bits. + * NDL_snrBackoff(MCS6), ndlType_snr, 1+7 bits. + * NDL_snrBackoff(MCS7), ndlType_snr, 1+7 bits. + */ + A_UINT32 snr_backoff_mcs[WMI_PACKED_ARR_SIZE(MCS_COUNT,SIZE_NDLTYPE_SNR)]; + + /** Communication ranges. */ + /** + * tx_power, ndlType_txPower, 1+7 bits. + * datarate, ndlType_datarate, 1+3 bits. + */ + A_UINT32 tx_power_datarate; + /** + * NDL_carrierSenseRange, ndlType_distance, 1+12 bits. + * NDL_estCommRange, ndlType_distance, 1+12 bits. + */ + A_UINT32 carrier_sense_est_comm_range; + + /** Channel load measures. */ + /** + * dccSensitivity, ndlType_rxPower, 1+7 bits. + * carrierSense, ndlType_rxPower, 1+7 bits. + * NDL_channelLoad, ndlType_channelLoad, 1+10 bits. + */ + A_UINT32 dcc_stats; + /** + * NDL_packetArrivalRate, ndlType_arrivalRate, 1+13 bits. + * NDL_packetAvgDuration, ndlType_packetDuration, 1+11 bits. + */ + A_UINT32 packet_stats; + /** + * NDL_channelBusyTime, ndlType_channelLoad, 1+10 bits. + */ + A_UINT32 channel_busy_time; + + /** Transmit packet statistics. */ + /** + * NDL_txPacketArrivalRate(AC_BK), ndlType_arrivalRate, 1+13 bits. + * NDL_txPacketArrivalRate(AC_BE), ndlType_arrivalRate, 1+13 bits. + * NDL_txPacketArrivalRate(AC_VI), ndlType_arrivalRate, 1+13 bits. + * NDL_txPacketArrivalRate(AC_VO), ndlType_arrivalRate, 1+13 bits. + */ + A_UINT32 tx_packet_arrival_rate_ac[WMI_PACKED_ARR_SIZE(WLAN_MAX_AC,SIZE_NDLTYPE_ARRIVALRATE)]; + /** + * NDL_txPacketAvgDuration(AC_BK), ndlType_packetDuration, 1+11 bits. + * NDL_txPacketAvgDuration(AC_BE), ndlType_packetDuration, 1+11 bits. + * NDL_txPacketAvgDuration(AC_VI), ndlType_packetDuration, 1+11 bits. + * NDL_txPacketAvgDuration(AC_VO), ndlType_packetDuration, 1+11 bits. + */ + A_UINT32 tx_packet_avg_duration_ac[WMI_PACKED_ARR_SIZE(WLAN_MAX_AC,SIZE_NDLTYPE_PACKETDURATION)]; + /** + * NDL_txChannelUse(AC_BK), ndlType_channelUse, 1+13 bits. + * NDL_txChannelUse(AC_BE), ndlType_channelUse, 1+13 bits. + * NDL_txChannelUse(AC_VI), ndlType_channelUse, 1+13 bits. + * NDL_txChannelUse(AC_VO), ndlType_channelUse, 1+13 bits. + */ + A_UINT32 tx_channel_use_ac[WMI_PACKED_ARR_SIZE(WLAN_MAX_AC,SIZE_NDLTYPE_CHANNELUSE)]; + /** + * NDL_txSignalAvgPower(AC_BK), ndlType_txPower, 1+7 bits. + * NDL_txSignalAvgPower(AC_BE), ndlType_txPower, 1+7 bits. + * NDL_txSignalAvgPower(AC_VI), ndlType_txPower, 1+7 bits. + * NDL_txSignalAvgPower(AC_VO), ndlType_txPower, 1+7 bits. + */ + A_UINT32 tx_signal_avg_power_ac[WMI_PACKED_ARR_SIZE(WLAN_MAX_AC,SIZE_NDLTYPE_TXPOWER)]; +} wmi_dcc_ndl_stats_per_channel; + +#define WMI_NDL_STATS_SNR_BACKOFF_GET(ptr,mcs) wmi_packed_arr_get_bits((ptr)->snr_backoff_mcs, mcs, SIZE_NDLTYPE_SNR) +#define WMI_NDL_STATS_SNR_BACKOFF_SET(ptr,mcs,val) wmi_packed_arr_set_bits((ptr)->snr_backoff_mcs, mcs, SIZE_NDLTYPE_SNR, val) + +#define WMI_NDL_STATS_CHAN_FREQ_GET(ptr) WMI_GET_BITS((ptr)->chan_info, 0, 16) +#define WMI_NDL_STATS_CHAN_FREQ_SET(ptr,val) WMI_SET_BITS((ptr)->chan_info, 0, 16, val) +#define WMI_NDL_STATS_DCC_STATS_BITMAP_GET(ptr) WMI_GET_BITS((ptr)->chan_info, 16, 8) +#define WMI_NDL_STATS_DCC_STATS_BITMAP_SET(ptr,val) WMI_SET_BITS((ptr)->chan_info, 16, 8, val) + +#define WMI_NDL_STATS_SNR_BACKOFF_GET(ptr,mcs) wmi_packed_arr_get_bits((ptr)->snr_backoff_mcs, mcs, SIZE_NDLTYPE_SNR) +#define WMI_NDL_STATS_SNR_BACKOFF_SET(ptr,mcs,val) wmi_packed_arr_set_bits((ptr)->snr_backoff_mcs, mcs, SIZE_NDLTYPE_SNR, val) + +#define WMI_TX_POWER_GET(ptr) WMI_GET_BITS((ptr)->tx_power_datarate, 0, 8) +#define WMI_TX_POWER_SET(ptr,val) WMI_SET_BITS((ptr)->tx_power_datarate, 0, 8, val) +#define WMI_TX_DATARATE_GET(ptr) WMI_GET_BITS((ptr)->tx_power_datarate, 0, 4) +#define WMI_TX_DATARATE_SET(ptr,val) WMI_SET_BITS((ptr)->tx_power_datarate, 0, 4, val) +#define WMI_NDL_CARRIER_SENSE_RANGE_GET(ptr) WMI_GET_BITS((ptr)->carrier_sense_est_comm_range, 0, 13) +#define WMI_NDL_CARRIER_SENSE_RANGE_SET(ptr,val) WMI_SET_BITS((ptr)->carrier_sense_est_comm_range, 0, 13, val) +#define WMI_NDL_EST_COMM_RANGE_GET(ptr) WMI_GET_BITS((ptr)->carrier_sense_est_comm_range, 13, 13) +#define WMI_NDL_EST_COMM_RANGE_SET(ptr,val) WMI_SET_BITS((ptr)->carrier_sense_est_comm_range, 13, 13, val) + +#define WMI_DCC_SENSITIVITY_GET(ptr) WMI_GET_BITS((ptr)->dcc_stats, 0, 8) +#define WMI_DCC_SENSITIVITY_SET(ptr,val) WMI_SET_BITS((ptr)->dcc_stats, 0, 8, val) +#define WMI_CARRIER_SENSE_GET(ptr) WMI_GET_BITS((ptr)->dcc_stats, 8, 8) +#define WMI_CARRIER_SENSE_SET(ptr,val) WMI_SET_BITS((ptr)->dcc_stats, 8, 8, val) +#define WMI_NDL_CHANNEL_LOAD_GET(ptr) WMI_GET_BITS((ptr)->dcc_stats, 16, 11) +#define WMI_NDL_CHANNEL_LOAD_SET(ptr,val) WMI_SET_BITS((ptr)->dcc_stats, 16, 11, val) +#define WMI_NDL_PACKET_ARRIVAL_RATE_GET(ptr) WMI_GET_BITS((ptr)->packet_stats, 0, 14) +#define WMI_NDL_PACKET_ARRIVAL_RATE_SET(ptr,val) WMI_SET_BITS((ptr)->packet_stats, 0, 14, val) +#define WMI_NDL_PACKET_AVG_DURATION_GET(ptr) WMI_GET_BITS((ptr)->packet_stats, 14, 12) +#define WMI_NDL_PACKET_AVG_DURATION_SET(ptr,val) WMI_SET_BITS((ptr)->packet_stats, 14, 12, val) +#define WMI_NDL_CHANNEL_BUSY_TIME_GET(ptr) WMI_GET_BITS((ptr)->channel_busy_time, 0, 11) +#define WMI_NDL_CHANNEL_BUSY_TIME_SET(ptr,val) WMI_SET_BITS((ptr)->channel_busy_time, 0, 11, val) + +#define WMI_NDL_TX_PACKET_ARRIVAL_RATE_GET(ptr,acprio) wmi_packed_arr_get_bits((ptr)->tx_packet_arrival_rate_ac, acprio, SIZE_NDLTYPE_ARRIVALRATE) +#define WMI_NDL_TX_PACKET_ARRIVAL_RATE_SET(ptr,acprio,val) wmi_packed_arr_set_bits((ptr)->tx_packet_arrival_rate_ac, acprio, SIZE_NDLTYPE_ARRIVALRATE, val) +#define WMI_NDL_TX_PACKET_AVG_DURATION_GET(ptr,acprio) wmi_packed_arr_get_bits((ptr)->tx_packet_avg_duration_ac, acprio, SIZE_NDLTYPE_PACKETDURATION) +#define WMI_NDL_TX_PACKET_AVG_DURATION_SET(ptr,acprio,val) wmi_packed_arr_set_bits((ptr)->tx_packet_avg_duration_ac, acprio, SIZE_NDLTYPE_PACKETDURATION, val) +#define WMI_NDL_TX_CHANNEL_USE_GET(ptr,acprio) wmi_packed_arr_get_bits((ptr)->tx_channel_use_ac, acprio, SIZE_NDLTYPE_CHANNELUSE) +#define WMI_NDL_TX_CHANNEL_USE_SET(ptr,acprio,val) wmi_packed_arr_set_bits((ptr)->tx_channel_use_ac, acprio, SIZE_NDLTYPE_CHANNELUSE, val) +#define WMI_NDL_TX_SIGNAL_AVG_POWER_GET(ptr,acprio) wmi_packed_arr_get_bits((ptr)->tx_signal_avg_power_ac, acprio, SIZE_NDLTYPE_TXPOWER) +#define WMI_NDL_TX_SIGNAL_AVG_POWER_SET(ptr,acprio,val) wmi_packed_arr_set_bits((ptr)->tx_signal_avg_power_ac, acprio, SIZE_NDLTYPE_TXPOWER, val) + +/** Bitmap for DCC stats. */ +typedef enum { + DCC_STATS_DEMODULATION_MODEL = 1, + DCC_STATS_COMMUNICATION_RANGES = 2, + DCC_STATS_CHANNEL_LOAD_MEASURES = 4, + DCC_STATS_TRANSMIT_PACKET_STATS = 8, + DCC_STATS_TRANSMIT_MODEL_PARAMETER = 16, + DCC_STATS_ALL = 0xff, +} wmi_dcc_stats_bitmap; + +/** Data structure for getting the DCC stats. */ +typedef struct { + /** TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_dcc_get_stats_cmd_fixed_param */ + A_UINT32 tlv_header; + + /* VDEV identifier */ + A_UINT32 vdev_id; + + /** The number of channels for which stats are being requested. */ + A_UINT32 num_channels; + + /** This is followed by a TLV array of wmi_dcc_channel_stats_request. */ +} wmi_dcc_get_stats_cmd_fixed_param; + +typedef struct { + /** TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_dcc_channel_stats_request */ + A_UINT32 tlv_header; + + /** The channel for which this applies. */ + A_UINT32 chan_freq; /* MHz units */ + + /** The DCC stats being requested. */ + A_UINT32 dcc_stats_bitmap; +} wmi_dcc_channel_stats_request; + +/** Data structure for the response with the DCC stats. */ +typedef struct { + /** TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_dcc_get_stats_resp_event_fixed_param */ + A_UINT32 tlv_header; + /* VDEV identifier */ + A_UINT32 vdev_id; + /** Number of channels in the response. */ + A_UINT32 num_channels; + /** This is followed by a TLV array of wmi_dcc_ndl_stats_per_channel. */ +} wmi_dcc_get_stats_resp_event_fixed_param; + +/** Data structure for clearing the DCC stats. */ +typedef struct { + /** TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_dcc_clear_stats_cmd_fixed_param */ + A_UINT32 tlv_header; + /* VDEV identifier */ + A_UINT32 vdev_id; + A_UINT32 dcc_stats_bitmap; +} wmi_dcc_clear_stats_cmd_fixed_param; + +/** Data structure for the pushed DCC stats */ +typedef struct { + /** TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_dcc_stats_event_fixed_param */ + A_UINT32 tlv_header; + /* VDEV identifier */ + A_UINT32 vdev_id; + /** The number of channels in the response. */ + A_UINT32 num_channels; + + /** This is followed by a TLV array of wmi_dcc_ndl_stats_per_channel. */ +} wmi_dcc_stats_event_fixed_param; + +/** Data structure for updating NDL per channel. */ +typedef struct { + /** TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_dcc_ndl_chan */ + A_UINT32 tlv_header; + + /** + * Channel frequency, 16 bits + * NDL_numActiveState, ndlType_numberElements, 1+6 bits + */ + A_UINT32 chan_info; + + /** + * NDL_minDccSampling, 10 bits. + * Maximum time interval between subsequent checks of the DCC rules. + */ + A_UINT32 ndl_min_dcc_sampling; + + /** + * dcc_enable, 1 bit. + * dcc_stats_enable, 1 bit. + * dcc_stats_interval, 16 bits. + */ + A_UINT32 dcc_flags; + + /** General DCC configuration. */ + /** + * NDL_timeUp, ndlType_timing, 1+12 bits. + * NDL_timeDown, ndlType_timing, 1+12 bits. + */ + A_UINT32 general_config; + + /** Transmit power thresholds. */ + /** + * NDL_minTxPower, ndlType_txPower, 1+7 bits. + * NDL_maxTxPower, ndlType_txPower, 1+7 bits. + */ + A_UINT32 min_max_tx_power; /* see "ETSI TS 102 687" table above for units */ + /** + * NDL_defTxPower(AC_BK), ndlType_txPower, 1+7 bits. + * NDL_defTxPower(AC_BE), ndlType_txPower, 1+7 bits. + * NDL_defTxPower(AC_VI), ndlType_txPower, 1+7 bits. + * NDL_defTxPower(AC_VO), ndlType_txPower, 1+7 bits. + */ + /* see "ETSI TS 102 687" table above for units */ + A_UINT32 def_tx_power_ac[WMI_PACKED_ARR_SIZE(WLAN_MAX_AC,SIZE_NDLTYPE_TXPOWER)]; + + /** Packet timing thresholds. */ + /** + * NDL_maxPacketDuration(AC_BK), ndlType_packetDuration, 1+11 bits. + * NDL_maxPacketDuration(AC_BE), ndlType_packetDuration, 1+11 bits. + * NDL_maxPacketDuration(AC_VI), ndlType_packetDuration, 1+11 bits. + * NDL_maxPacketDuration(AC_VO), ndlType_packetDuration, 1+11 bits. + */ + A_UINT32 max_packet_duration_ac[WMI_PACKED_ARR_SIZE(WLAN_MAX_AC,SIZE_NDLTYPE_PACKETDURATION)]; + /** + * NDL_minPacketInterval, ndlType_packetInterval, 1+10 bits. + * NDL_maxPacketInterval, ndlType_packetInterval, 1+10 bits. + */ + A_UINT32 min_max_packet_interval; + /** + * NDL_defPacketInterval(AC_BK), ndlType_packetInterval, 1+10 bits. + * NDL_defPacketInterval(AC_BE), ndlType_packetInterval, 1+10 bits. + * NDL_defPacketInterval(AC_VI), ndlType_packetInterval, 1+10 bits. + * NDL_defPacketInterval(AC_VO), ndlType_packetInterval, 1+10 bits. + */ + A_UINT32 def_packet_interval_ac[WMI_PACKED_ARR_SIZE(WLAN_MAX_AC,SIZE_NDLTYPE_PACKETINTERVAL)]; + + /** Packet datarate thresholds. */ + /** + * NDL_minDatarate, ndlType_datarate, 1+3 bits. + * NDL_maxDatarate, ndlType_datarate, 1+3 bits. + */ + A_UINT32 min_max_datarate; + /** + * NDL_defDatarate(AC_BK), ndlType_datarate, 1+3 bits. + * NDL_defDatarate(AC_BE), ndlType_datarate, 1+3 bits. + * NDL_defDatarate(AC_VI), ndlType_datarate, 1+3 bits. + * NDL_defDatarate(AC_VO), ndlType_datarate, 1+3 bits. + */ + A_UINT32 def_datarate_ac[WMI_PACKED_ARR_SIZE(WLAN_MAX_AC,SIZE_NDLTYPE_DATARATE)]; + + /** Receive signal thresholds. */ + /** + * NDL_minCarrierSense, ndlType_rxPower, 1+7 bits. + * NDL_maxCarrierSense, ndlType_rxPower, 1+7 bits. + * NDL_defCarrierSense, ndlType_rxPower, 1+7 bits. + */ + A_UINT32 min_max_def_carrier_sense; + + /** Receive model parameter. */ + /** + * NDL_defDccSensitivity, ndlType_rxPower, 1+7 bits. + * NDL_maxCsRange, ndlType_distance, 1+12 bits. + * NDL_refPathLoss, ndlType_pathloss, 1+5 bits. + */ + A_UINT32 receive_model_parameter; + + /** + * NDL_minSNR, ndlType_snr, 1+7 bits. + */ + A_UINT32 receive_model_parameter_2; + + /** Demodulation model parameters. */ + /** + * NDL_snrBackoff(MCS0), ndlType_snr, 1+7 bits. + * NDL_snrBackoff(MCS1), ndlType_snr, 1+7 bits. + * NDL_snrBackoff(MCS2), ndlType_snr, 1+7 bits. + * NDL_snrBackoff(MCS3), ndlType_snr, 1+7 bits. + * NDL_snrBackoff(MCS4), ndlType_snr, 1+7 bits. + * NDL_snrBackoff(MCS5), ndlType_snr, 1+7 bits. + * NDL_snrBackoff(MCS6), ndlType_snr, 1+7 bits. + * NDL_snrBackoff(MCS7), ndlType_snr, 1+7 bits. + */ + A_UINT32 snr_backoff_mcs[WMI_PACKED_ARR_SIZE(MCS_COUNT,SIZE_NDLTYPE_SNR)]; + + /** Transmit model parameters. */ + /** + * NDL_tmPacketArrivalRate(AC_BK), ndlType_arrivalRate, 1+13 bits. + * NDL_tmPacketArrivalRate(AC_BE), ndlType_arrivalRate, 1+13 bits. + * NDL_tmPacketArrivalRate(AC_VI), ndlType_arrivalRate, 1+13 bits. + * NDL_tmPacketArrivalRate(AC_VO), ndlType_arrivalRate, 1+13 bits. + */ + A_UINT32 tm_packet_arrival_rate_ac[WMI_PACKED_ARR_SIZE(WLAN_MAX_AC, SIZE_NDLTYPE_ARRIVALRATE)]; + /** + * NDL_tmPacketAvgDuration(AC_BK), ndlType_packetDuration, 1+11 bits. + * NDL_tmPacketAvgDuration(AC_BE), ndlType_packetDuration, 1+11 bits. + * NDL_tmPacketAvgDuration(AC_VI), ndlType_packetDuration, 1+11 bits. + * NDL_tmPacketAvgDuration(AC_VO), ndlType_packetDuration, 1+11 bits. + */ + A_UINT32 tm_packet_avg_duration_ac[WMI_PACKED_ARR_SIZE(WLAN_MAX_AC, SIZE_NDLTYPE_PACKETDURATION)]; + /** + * NDL_tmSignalAvgPower(AC_BK), ndlType_txPower, 1+7 bits. + * NDL_tmSignalAvgPower(AC_BE), ndlType_txPower, 1+7 bits. + * NDL_tmSignalAvgPower(AC_VI), ndlType_txPower, 1+7 bits. + * NDL_tmSignalAvgPower(AC_VO), ndlType_txPower, 1+7 bits. + */ + A_UINT32 tm_signal_avg_power_ac[WMI_PACKED_ARR_SIZE(WLAN_MAX_AC, SIZE_NDLTYPE_TXPOWER)]; + /** + * NDL_tmMaxChannelUse, ndlType_channelUse, 1+13 bits. + */ + A_UINT32 tm_max_channel_use; + /** + * NDL_tmChannelUse(AC_BK), ndlType_channelUse, 1+13 bits. + * NDL_tmChannelUse(AC_BE), ndlType_channelUse, 1+13 bits. + * NDL_tmChannelUse(AC_VI), ndlType_channelUse, 1+13 bits. + * NDL_tmChannelUse(AC_VO), ndlType_channelUse, 1+13 bits. + */ + A_UINT32 tm_channel_use_ac[WMI_PACKED_ARR_SIZE(WLAN_MAX_AC, SIZE_NDLTYPE_CHANNELUSE)]; + + /** Channel load thresholds. */ + /** + * NDL_minChannelLoad, ndlType_channelLoad, 1+10 bits. + * NDL_maxChannelLoad, ndlType_channelLoad, 1+10 bits. + */ + A_UINT32 min_max_channel_load; + + /** Transmit queue parameters. */ + /** + * NDL_numQueue, ndlType_acPrio, 1+3 bits. + * NDL_refQueueStatus(AC_BK), ndlType_queueStatus, 1+1 bit. + * NDL_refQueueStatus(AC_BE), ndlType_queueStatus, 1+1 bit. + * NDL_refQueueStatus(AC_VI), ndlType_queueStatus, 1+1 bit. + * NDL_refQueueStatus(AC_VO), ndlType_queueStatus, 1+1 bit. + */ + A_UINT32 transmit_queue_parameters; + + /** + * NDL_refQueueLen(AC_BK), ndlType_numberElements, 1+6 bits. + * NDL_refQueueLen(AC_BE), ndlType_numberElements, 1+6 bits. + * NDL_refQueueLen(AC_VI), ndlType_numberElements, 1+6 bits. + * NDL_refQueueLen(AC_VO), ndlType_numberElements, 1+6 bits. + */ + A_UINT32 numberElements[WMI_PACKED_ARR_SIZE(WLAN_MAX_AC, SIZE_NDLTYPE_NUMBERELEMENTS)]; + +} wmi_dcc_ndl_chan; + +#define WMI_CHAN_FREQ_GET(ptr) WMI_GET_BITS((ptr)->chan_info, 0, 16) +#define WMI_CHAN_FREQ_SET(ptr,val) WMI_SET_BITS((ptr)->chan_info, 0, 16, val) +#define WMI_NDL_NUM_ACTIVE_STATE_GET(ptr) WMI_GET_BITS((ptr)->chan_info, 16, 7) +#define WMI_NDL_NUM_ACTIVE_STATE_SET(ptr,val) WMI_SET_BITS((ptr)->chan_info, 16, 7, val) + +#define WMI_NDL_MIN_DCC_SAMPLING_GET(ptr) WMI_GET_BITS((ptr)->ndl_min_dcc_sampling, 0, 10) +#define WMI_NDL_MIN_DCC_SAMPLING_SET(ptr,val) WMI_SET_BITS((ptr)->ndl_min_dcc_sampling, 0, 10, val) +#define WMI_NDL_MEASURE_INTERVAL_GET(ptr) WMI_GET_BITS((ptr)->ndl_min_dcc_sampling, 10, 16) +#define WMI_NDL_MEASURE_INTERVAL_SET(ptr,val) WMI_SET_BITS((ptr)->ndl_min_dcc_sampling, 10, 16, val) + +#define WMI_NDL_DCC_ENABLE_GET(ptr) WMI_GET_BITS((ptr)->dcc_flags, 0, 1) +#define WMI_NDL_DCC_ENABLE_SET(ptr,val) WMI_SET_BITS((ptr)->dcc_flags, 0, 1, val) +#define WMI_NDL_DCC_STATS_ENABLE_GET(ptr) WMI_GET_BITS((ptr)->dcc_flags, 1, 1) +#define WMI_NDL_DCC_STATS_ENABLE_SET(ptr,val) WMI_SET_BITS((ptr)->dcc_flags, 1, 1, val) +#define WMI_NDL_DCC_STATS_INTERVAL_GET(ptr) WMI_GET_BITS((ptr)->dcc_flags, 2, 16) +#define WMI_NDL_DCC_STATS_INTERVAL_SET(ptr,val) WMI_SET_BITS((ptr)->dcc_flags, 2, 16, val) + +#define WMI_NDL_TIME_UP_GET(ptr) WMI_GET_BITS((ptr)->general_config, 0, 13) +#define WMI_NDL_TIME_UP_SET(ptr,val) WMI_SET_BITS((ptr)->general_config, 0, 13, val) +#define WMI_NDL_TIME_DOWN_GET(ptr) WMI_GET_BITS((ptr)->general_config, 13, 13) +#define WMI_NDL_TIME_DOWN_SET(ptr,val) WMI_SET_BITS((ptr)->general_config, 13, 13, val) + +#define WMI_NDL_MIN_TX_POWER_GET(ptr) WMI_GET_BITS((ptr)->min_max_tx_power, 0, 8) +#define WMI_NDL_MIN_TX_POWER_SET(ptr,val) WMI_SET_BITS((ptr)->min_max_tx_power, 0, 8, val) +#define WMI_NDL_MAX_TX_POWER_GET(ptr) WMI_GET_BITS((ptr)->min_max_tx_power, 8, 8) +#define WMI_NDL_MAX_TX_POWER_SET(ptr,val) WMI_SET_BITS((ptr)->min_max_tx_power, 8, 8, val) + +#define WMI_NDL_DEF_TX_POWER_GET(ptr,acprio) wmi_packed_arr_get_bits((ptr)->def_tx_power_ac, acprio, SIZE_NDLTYPE_TXPOWER) +#define WMI_NDL_DEF_TX_POWER_SET(ptr,acprio,val) wmi_packed_arr_set_bits((ptr)->def_tx_power_ac, acprio, SIZE_NDLTYPE_TXPOWER, val) + +#define WMI_NDL_MAX_PACKET_DURATION_GET(ptr,acprio) wmi_packed_arr_get_bits((ptr)->max_packet_duration_ac, acprio, SIZE_NDLTYPE_PACKETDURATION) +#define WMI_NDL_MAX_PACKET_DURATION_SET(ptr,acprio,val) wmi_packed_arr_set_bits((ptr)->max_packet_duration_ac, acprio, SIZE_NDLTYPE_PACKETDURATION, val) +#define WMI_NDL_MIN_PACKET_INTERVAL_GET(ptr) WMI_GET_BITS((ptr)->min_max_packet_interval, 0, 11) +#define WMI_NDL_MIN_PACKET_INTERVAL_SET(ptr,val) WMI_SET_BITS((ptr)->min_max_packet_interval, 0, 11, val) +#define WMI_NDL_MAX_PACKET_INTERVAL_GET(ptr) WMI_GET_BITS((ptr)->min_max_packet_interval, 11, 11) +#define WMI_NDL_MAX_PACKET_INTERVAL_SET(ptr,val) WMI_SET_BITS((ptr)->min_max_packet_interval, 11, 11, val) +#define WMI_NDL_DEF_PACKET_INTERVAL_GET(ptr,acprio) wmi_packed_arr_get_bits((ptr)->def_packet_interval_ac, acprio, SIZE_NDLTYPE_PACKETINTERVAL) +#define WMI_NDL_DEF_PACKET_INTERVAL_SET(ptr,acprio,val) wmi_packed_arr_set_bits((ptr)->def_packet_interval_ac, acprio, SIZE_NDLTYPE_PACKETINTERVAL, val) + +#define WMI_NDL_MIN_DATARATE_GET(ptr) WMI_GET_BITS((ptr)->min_max_datarate, 0, 4) +#define WMI_NDL_MIN_DATARATE_SET(ptr,val) WMI_SET_BITS((ptr)->min_max_datarate, 0, 4, val) +#define WMI_NDL_MAX_DATARATE_GET(ptr) WMI_GET_BITS((ptr)->min_max_datarate, 4, 4) +#define WMI_NDL_MAX_DATARATE_SET(ptr,val) WMI_SET_BITS((ptr)->min_max_datarate, 4, 4, val) +#define WMI_NDL_DEF_DATARATE_GET(ptr,acprio) wmi_packed_arr_get_bits((ptr)->def_datarate_ac, acprio, SIZE_NDLTYPE_DATARATE) +#define WMI_NDL_DEF_DATARATE_SET(ptr,acprio,val) wmi_packed_arr_set_bits((ptr)->def_datarate_ac, acprio, SIZE_NDLTYPE_DATARATE, val) + +#define WMI_NDL_MIN_CARRIER_SENSE_GET(ptr) WMI_GET_BITS((ptr)->min_max_def_carrier_sense, 0, 8) +#define WMI_NDL_MIN_CARRIER_SENSE_SET(ptr,val) WMI_SET_BITS((ptr)->min_max_def_carrier_sense, 0, 8, val) +#define WMI_NDL_MAX_CARRIER_SENSE_GET(ptr) WMI_GET_BITS((ptr)->min_max_def_carrier_sense, 8, 8) +#define WMI_NDL_MAX_CARRIER_SENSE_SET(ptr,val) WMI_SET_BITS((ptr)->min_max_def_carrier_sense, 8, 8, val) +#define WMI_NDL_DEF_CARRIER_SENSE_GET(ptr) WMI_GET_BITS((ptr)->min_max_def_carrier_sense, 16, 8) +#define WMI_NDL_DEF_CARRIER_SENSE_SET(ptr,val) WMI_SET_BITS((ptr)->min_max_def_carrier_sense, 16, 8, val) + +#define WMI_NDL_DEF_DCC_SENSITIVITY_GET(ptr) WMI_GET_BITS((ptr)->receive_model_parameter, 0, 8) +#define WMI_NDL_DEF_DCC_SENSITIVITY_SET(ptr,val) WMI_SET_BITS((ptr)->receive_model_parameter, 0, 8, val) +#define WMI_NDL_MAX_CS_RANGE_GET(ptr) WMI_GET_BITS((ptr)->receive_model_parameter, 8, 13) +#define WMI_NDL_MAX_CS_RANGE_SET(ptr,val) WMI_SET_BITS((ptr)->receive_model_parameter, 8, 13, val) +#define WMI_NDL_REF_PATH_LOSS_GET(ptr) WMI_GET_BITS((ptr)->receive_model_parameter, 21, 6) +#define WMI_NDL_REF_PATH_LOSS_SET(ptr,val) WMI_SET_BITS((ptr)->receive_model_parameter, 21, 6, val) + +#define WMI_NDL_MIN_SNR_GET(ptr) WMI_GET_BITS((ptr)->receive_model_parameter_2, 0, 8) +#define WMI_NDL_MIN_SNR_SET(ptr,val) WMI_SET_BITS((ptr)->receive_model_parameter_2, 0, 8, val) + +#define WMI_NDL_SNR_BACKOFF_GET(ptr,mcs) wmi_packed_arr_get_bits((ptr)->snr_backoff_mcs, mcs, SIZE_NDLTYPE_SNR) +#define WMI_NDL_SNR_BACKOFF_SET(ptr,mcs,val) wmi_packed_arr_set_bits((ptr)->snr_backoff_mcs, mcs, SIZE_NDLTYPE_SNR, val) + +#define WMI_NDL_TM_PACKET_ARRIVAL_RATE_GET(ptr,acprio) wmi_packed_arr_get_bits((ptr)->tm_packet_arrival_rate_ac, acprio, SIZE_NDLTYPE_ARRIVALRATE) +#define WMI_NDL_TM_PACKET_ARRIVAL_RATE_SET(ptr,acprio,val) wmi_packed_arr_set_bits((ptr)->tm_packet_arrival_rate_ac, acprio, SIZE_NDLTYPE_ARRIVALRATE, val) +#define WMI_NDL_TM_PACKET_AVG_DURATION_GET(ptr,acprio) wmi_packed_arr_get_bits((ptr)->tm_packet_avg_duration_ac, acprio, SIZE_NDLTYPE_PACKETDURATION) +#define WMI_NDL_TM_PACKET_AVG_DURATION_SET(ptr,acprio,val) wmi_packed_arr_set_bits((ptr)->tm_packet_avg_duration_ac, acprio, SIZE_NDLTYPE_PACKETDURATION, val) +#define WMI_NDL_TM_SIGNAL_AVG_POWER_GET(ptr,acprio) wmi_packed_arr_get_bits((ptr)->tm_signal_avg_power_ac, acprio, SIZE_NDLTYPE_TXPOWER) +#define WMI_NDL_TM_SIGNAL_AVG_POWER_SET(ptr,acprio,val) wmi_packed_arr_set_bits((ptr)->tm_signal_avg_power_ac, acprio, SIZE_NDLTYPE_TXPOWER, val) +#define WMI_NDL_TM_MAX_CHANNEL_USE_GET(ptr) WMI_GET_BITS((ptr)->tm_max_channel_use, 0, 14) +#define WMI_NDL_TM_MAX_CHANNEL_USE_SET(ptr,val) WMI_SET_BITS((ptr)->tm_max_channel_use, 0, 14, val) +#define WMI_NDL_TM_CHANNEL_USE_GET(ptr,acprio) wmi_packed_arr_get_bits((ptr)->tm_channel_use_ac, acprio, SIZE_NDLTYPE_CHANNELUSE) +#define WMI_NDL_TM_CHANNEL_USE_SET(ptr,acprio,val) wmi_packed_arr_set_bits((ptr)->tm_channel_use_ac, acprio, SIZE_NDLTYPE_CHANNELUSE, val) + +#define WMI_NDL_MIN_CHANNEL_LOAD_GET(ptr) WMI_GET_BITS((ptr)->min_max_channel_load, 0, 11) +#define WMI_NDL_MIN_CHANNEL_LOAD_SET(ptr,val) WMI_SET_BITS((ptr)->min_max_channel_load, 0, 11, val) +#define WMI_NDL_MAX_CHANNEL_LOAD_GET(ptr) WMI_GET_BITS((ptr)->min_max_channel_load, 11, 11) +#define WMI_NDL_MAX_CHANNEL_LOAD_SET(ptr,val) WMI_SET_BITS((ptr)->min_max_channel_load, 11, 11, val) + +#define WMI_NDL_NUM_QUEUE_GET(ptr) WMI_GET_BITS((ptr)->transmit_queue_parameters, 0, 4) +#define WMI_NDL_NUM_QUEUE_SET(ptr,val) WMI_SET_BITS((ptr)->transmit_queue_parameters, 0, 4, val) +#define WMI_NDL_REF_QUEUE_STATUS_GET(ptr,acprio) WMI_GET_BITS((ptr)->transmit_queue_parameters, (4 + (acprio * 2)), 2) +#define WMI_NDL_REF_QUEUE_STATUS_SET(ptr,acprio,val) WMI_SET_BITS((ptr)->transmit_queue_parameters, (4 + (acprio * 2)), 2, val) +#define WMI_NDL_REF_QUEUE_LEN_GET(ptr,acprio) wmi_packed_arr_get_bits((ptr)->numberElements, acprio, SIZE_NDLTYPE_NUMBERELEMENTS) +#define WMI_NDL_REF_QUEUE_LEN_SET(ptr,acprio,val) wmi_packed_arr_set_bits((ptr)->numberElements, acprio, SIZE_NDLTYPE_NUMBERELEMENTS, val) + +/** Data structure for updating the NDL. */ +typedef struct { + /** TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_dcc_update_ndl_cmd_fixed_param */ + A_UINT32 tlv_header; + + /* VDEV identifier */ + A_UINT32 vdev_id; + + /** The number of channels in the request. */ + A_UINT32 num_channel; + + /** This is followed by a TLV array of wmi_dcc_ndl_chan. */ + /** This is followed by a TLV array of wmi_dcc_ndl_active_state_config. */ +} wmi_dcc_update_ndl_cmd_fixed_param; + +typedef struct { + /** TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_dcc_update_ndl_resp_event_fixed_param */ + A_UINT32 tlv_header; + /* VDEV identifier */ + A_UINT32 vdev_id; + A_UINT32 status; +} wmi_dcc_update_ndl_resp_event_fixed_param; + +/* Actions for TSF timestamp */ +typedef enum { + TSF_TSTAMP_CAPTURE_REQ = 1, + TSF_TSTAMP_CAPTURE_RESET = 2, + TSF_TSTAMP_READ_VALUE = 3, + TSF_TSTAMP_QTIMER_CAPTURE_REQ = 4, +} wmi_tsf_tstamp_action; + +typedef struct { + /** TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_vdev_tsf_tstamp_action_cmd_fixed_param */ + A_UINT32 tlv_header; + /** unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; + /* action type, refer to wmi_tsf_tstamp_action */ + A_UINT32 tsf_action; +} wmi_vdev_tsf_tstamp_action_cmd_fixed_param; + +typedef struct { + /* TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_vdev_tsf_report_event_fixed_param */ + A_UINT32 tlv_header; + /* VDEV identifier */ + A_UINT32 vdev_id; + /* low 32bit of tsf */ + A_UINT32 tsf_low; + /* high 32 bit of tsf */ + A_UINT32 tsf_high; + /* low 32 bits of qtimer */ + A_UINT32 qtimer_low; + /* high 32 bits of qtimer */ + A_UINT32 qtimer_high; +} wmi_vdev_tsf_report_event_fixed_param; + +/* ie_id values: + * 0 to 255 are used for individual IEEE802.11 Information Element types + */ +#define WMI_SET_VDEV_IE_ID_SCAN_SET_DEFAULT_IE 256 + +/* source values: */ +#define WMI_SET_VDEV_IE_SOURCE_HOST 0x0 + +/* band values: */ +typedef enum { + WMI_SET_VDEV_IE_BAND_ALL = 0, + WMI_SET_VDEV_IE_BAND_2_4GHZ, + WMI_SET_VDEV_IE_BAND_5GHZ, +} wmi_set_vdev_ie_band; + +typedef struct { + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_vdev_set_ie_cmd_fixed_param */ + A_UINT32 tlv_header; + /** unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; + /** unique id to identify the ie_data as defined by ieee 802.11 spec */ + A_UINT32 ie_id; + /** ie_len corresponds to num of bytes in ie_data[] */ + A_UINT32 ie_len; + /** source of this command */ + A_UINT32 ie_source; /* see WMI_SET_VDEV_IE_SOURCE_ defs */ + /** band for this IE - se wmi_set_vdev_ie_band enum */ + A_UINT32 band; + /** + * Following this structure is the TLV byte stream of ie data of length ie_buf_len: + * A_UINT8 ie_data[]; + * + */ +} wmi_vdev_set_ie_cmd_fixed_param; + +/* DISA feature related data structures */ +#define MAX_MAC_HEADER_LEN 32 +typedef enum { + WMI_ENCRYPT_DECRYPT_FLAG_INVALID, + WMI_ENCRYPT = 1, + WMI_DECRYPT = 2, +} WMI_ENCRYPT_DECRYPT_FLAG; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_vdev_encrypt_decrypt_data_req_cmd_fixed_param */ + /** unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; + A_UINT32 key_flag; /* WMI_ENCRYPT_DECRYPT_FLAG */ + A_UINT32 key_idx; + A_UINT32 key_cipher; + A_UINT32 key_len; /* units = bytes */ + A_UINT32 key_txmic_len; /* units = bytes */ + A_UINT32 key_rxmic_len; /* units = bytes */ + /** Key: This array needs to be provided in little-endian order */ + A_UINT8 key_data[WMI_MAX_KEY_LEN]; + /** Packet number: This array needs to be provided in little-endian order. + * If the PN is less than 8 bytes, the PN data shall be placed into this + * pn[] array starting at byte 0, leaving the MSBs empty. + */ + A_UINT8 pn[8]; + /** 802.11 MAC header to be typecast to struct ieee80211_qosframe_addr4 + * This array needs to be provided in little-endian order. + */ + A_UINT8 mac_hdr[MAX_MAC_HEADER_LEN]; + A_UINT32 data_len; /** Payload length, units = bytes */ + /* + * Following this struct are this TLV: + * A_UINT8 data[]; <-- actual data to be encrypted, + * needs to be provided in little-endian order + */ +} wmi_vdev_encrypt_decrypt_data_req_cmd_fixed_param; + +/* This event is generated in response to WMI_VDEV_ENCRYPT_DECRYPT_DATA_REQ_CMDID from HOST. + * On receiving WMI command WMI_VDEV_ENCRYPT_DECRYPT_DATA_REQ_CMDID from + * HOST with DISA test vectors, DISA frame will prepared and submitted to HW, + * then on receiving the tx completion for the DISA frame this WMI event + * will be delivered to HOST with the encrypted frame. + */ +typedef struct { + /** TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_vdev_encrypt_decrypt_data_resp_event_fixed_param */ + A_UINT32 tlv_header; + /* VDEV identifier */ + A_UINT32 vdev_id; + A_INT32 status; /* 0: success, -1: Failure, */ + /* 802.11 header length + encrypted payload length (units = bytes) */ + A_UINT32 data_length; + /* + * Following this struct is this TLV: + * A_UINT8 enc80211_frame[]; <-- Encrypted 802.11 frame; + * 802.11 header + encrypted payload, + * provided in little-endian order + */ +} wmi_vdev_encrypt_decrypt_data_resp_event_fixed_param; + +/* DEPRECATED - use wmi_pdev_set_pcl_cmd_fixed_param instead */ +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_soc_set_pcl_cmd_fixed_param */ + /** Set Preferred Channel List **/ + + /** # of channels to scan */ + A_UINT32 num_chan; +/** + * TLV (tag length value) parameters follow the wmi_soc_set_pcl_cmd + * structure. The TLV's are: + * A_UINT32 channel_list[]; + **/ +} wmi_soc_set_pcl_cmd_fixed_param; + +/* Values for channel_weight */ +typedef enum { + WMI_PCL_WEIGHT_DISALLOW = 0, + WMI_PCL_WEIGHT_LOW = 1, + WMI_PCL_WEIGHT_MEDIUM = 2, + WMI_PCL_WEIGHT_HIGH = 3, + WMI_PCL_WEIGHT_VERY_HIGH = 4, +} wmi_pcl_chan_weight; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_pdev_set_pcl_cmd_fixed_param */ + /** Set Preferred Channel List **/ + + /** pdev_id for identifying the MAC + * See macros starting with WMI_PDEV_ID_ for values. + */ + A_UINT32 pdev_id; + + /** # of channels to scan */ + A_UINT32 num_chan; +/** + * TLV (tag length value) parameters follow the wmi_soc_set_pcl_cmd + 12930 * structure. The TLV's are: + * A_UINT32 channel_weight[]; channel order & size will be as per the list provided in WMI_SCAN_CHAN_LIST_CMDID + **/ +} wmi_pdev_set_pcl_cmd_fixed_param; + +/* DEPRECATED - use wmi_pdev_set_hw_mode_cmd_fixed_param instead */ +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_soc_set_hw_mode_cmd_fixed_param */ + /** Set Hardware Mode **/ + + /* Hardware Mode Index */ + A_UINT32 hw_mode_index; +} wmi_soc_set_hw_mode_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len tag equals WMITLV_TAG_STRUC_wmi_pdev_band_to_mac */ + /** pdev_id for identifying the MAC + * See macros starting with WMI_PDEV_ID_ for values. + */ + A_UINT32 pdev_id; + /* start frequency in MHz */ + A_UINT32 start_freq; + /* end frequency in MHz */ + A_UINT32 end_freq; +} wmi_pdev_band_to_mac; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_pdev_set_hw_mode_cmd_fixed_param */ + /** Set Hardware Mode **/ + + /** pdev_id for identifying the MAC + * See macros starting with WMI_PDEV_ID_ for values. + */ + A_UINT32 pdev_id; + + /* Hardware Mode Index */ + A_UINT32 hw_mode_index; + + /* Number of band to mac TLVs */ + A_UINT32 num_band_to_mac; + + /* Followed by TLVs of type + * num_band_to_mac * wmi_pdev_band_to_mac. + */ +} wmi_pdev_set_hw_mode_cmd_fixed_param; + +/* DEPRECATED - use wmi_pdev_set_dual_mac_config_cmd_fixed_param instead */ +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_soc_set_dual_mac_config_cmd_fixed_param */ + /** Set Dual MAC Firmware Configuration **/ + + /* Concurrent scan configuration bits */ + A_UINT32 concurrent_scan_config_bits; + /* Firmware mode configuration bits */ + A_UINT32 fw_mode_config_bits; +} wmi_soc_set_dual_mac_config_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_pdev_set_mac_config_cmd_fixed_param */ + /** Set Dual MAC Firmware Configuration **/ + + /** pdev_id for identifying the MAC + * See macros starting with WMI_PDEV_ID_ for values. + */ + A_UINT32 pdev_id; + + /* Concurrent scan configuration bits */ + A_UINT32 concurrent_scan_config_bits; + /* Firmware mode configuration bits */ + A_UINT32 fw_mode_config_bits; +} wmi_pdev_set_mac_config_cmd_fixed_param; + +typedef struct { /* DEPRECATED */ + A_UINT32 num_tx_chains; + A_UINT32 num_rx_chains; + A_UINT32 reserved[2]; +} soc_num_tx_rx_chains; + +typedef struct { + A_UINT32 num_tx_chains_2g; + A_UINT32 num_rx_chains_2g; + A_UINT32 num_tx_chains_5g; + A_UINT32 num_rx_chains_5g; +} band_num_tx_rx_chains; + +typedef union { /* DEPRECATED */ + soc_num_tx_rx_chains soc_txrx_chain_setting; + band_num_tx_rx_chains band_txrx_chain_setting; +} antenna_num_tx_rx_chains; + +typedef enum { + ANTENNA_MODE_DISABLED = 0x0, + ANTENNA_MODE_LOW_POWER_LOCATION_SCAN = 0x01, + /* reserved */ +} antenna_mode_reason; + +/* DEPRECATED - use wmi_pdev_set_antenna_mode_cmd_fixed_param instead */ +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_soc_set_antenna_mode_cmd_fixed_param */ + + /* the reason for setting antenna mode, refer antenna_mode_reason */ + A_UINT32 reason; + + /* + * The above reason parameter will select whether the following union + * is soc_num_tx_rx_chains or band_num_tx_rx_chains. + */ + antenna_num_tx_rx_chains num_txrx_chains_setting; +} wmi_soc_set_antenna_mode_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_pdev_set_antenna_mode_cmd_fixed_param */ + + /** pdev_id for identifying the MAC + * See macros starting with WMI_PDEV_ID_ for values. + */ + A_UINT32 pdev_id; + + /* Bits 0-15 is the number of RX chains and 16-31 is the number of TX chains */ + A_UINT32 num_txrx_chains; +} wmi_pdev_set_antenna_mode_cmd_fixed_param; + +/** Data structure for information specific to a VDEV to MAC mapping. */ +/* DEPRECATED - use wmi_pdev_set_hw_mode_response_vdev_mac_entry instead */ +typedef struct { + /** TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_soc_set_hw_mode_response_vdev_mac_entry */ + A_UINT32 tlv_header; + A_UINT32 vdev_id; /* VDEV ID */ + A_UINT32 mac_id; /* MAC ID */ +} wmi_soc_set_hw_mode_response_vdev_mac_entry; + +/** Data structure for information specific to a VDEV to MAC mapping. */ +typedef struct { + /** TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_pdev_set_hw_mode_response_vdev_mac_entry */ + A_UINT32 tlv_header; + + /** pdev_id for identifying the MAC + * See macros starting with WMI_PDEV_ID_ for values. + */ + A_UINT32 pdev_id; + + A_UINT32 vdev_id; +} wmi_pdev_set_hw_mode_response_vdev_mac_entry; + +/* DEPRECATED - use wmi_pdev_set_hw_mode_response_event_fixed_param instead */ +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_soc_set_hw_mode_response_event_fixed_param */ + /** Set Hardware Mode Response Event **/ + + /* Status of set_hw_mode command */ + /* + * Values for Status: + * 0 - OK; command successful + * 1 - EINVAL; Requested invalid hw_mode + * 2 - ECANCELED; HW mode change canceled + * 3 - ENOTSUP; HW mode not supported + * 4 - EHARDWARE; HW mode change prevented by hardware + * 5 - EPENDING; HW mode change is pending + * 6 - ECOEX; HW mode change conflict with Coex + */ + A_UINT32 status; + /* Configured Hardware Mode */ + A_UINT32 cfgd_hw_mode_index; + /* Number of Vdev to Mac entries */ + A_UINT32 num_vdev_mac_entries; + +/** + * TLV (tag length value) parameters follow the soc_set_hw_mode_response_event + * structure. The TLV's are: + * A_UINT32 wmi_soc_set_hw_mode_response_vdev_mac_entry[]; + */ +} wmi_soc_set_hw_mode_response_event_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_pdev_set_hw_mode_response_event_fixed_param */ + /** Set Hardware Mode Response Event **/ + + /** pdev_id for identifying the MAC + * See macros starting with WMI_PDEV_ID_ for values. + */ + A_UINT32 pdev_id; + + /* Status of set_hw_mode command */ + /* + * Values for Status: + * 0 - OK; command successful + * 1 - EINVAL; Requested invalid hw_mode + * 2 - ECANCELED; HW mode change canceled + * 3 - ENOTSUP; HW mode not supported + * 4 - EHARDWARE; HW mode change prevented by hardware + * 5 - EPENDING; HW mode change is pending + * 6 - ECOEX; HW mode change conflict with Coex + */ + A_UINT32 status; + /* Configured Hardware Mode */ + A_UINT32 cfgd_hw_mode_index; + /* Number of Vdev to Mac entries */ + A_UINT32 num_vdev_mac_entries; +/** + * TLV (tag length value) parameters follow the soc_set_hw_mode_response_event + * structure. The TLV's are: + * A_UINT32 wmi_soc_set_hw_mode_response_vdev_mac_entry[]; + */ +} wmi_pdev_set_hw_mode_response_event_fixed_param; + +/* DEPRECATED - use wmi_pdev_hw_mode_transition_event_fixed_param instead */ +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_soc_hw_mode_transition_event_fixed_param */ + /** Hardware Mode Transition Event **/ + + /* Original or old Hardware mode */ + A_UINT32 old_hw_mode_index; + /* New Hardware Mode */ + A_UINT32 new_hw_mode_index; + /* Number of Vdev to Mac entries */ + A_UINT32 num_vdev_mac_entries; + +/** + * TLV (tag length value) parameters follow the soc_set_hw_mode_response_event + * structure. The TLV's are: + * A_UINT32 wmi_soc_set_hw_mode_response_vdev_mac_entry[]; + */ +} wmi_soc_hw_mode_transition_event_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_pdev_hw_mode_transition_event_fixed_param */ + /** Hardware Mode Transition Event **/ + + /** pdev_id for identifying the MAC + * See macros starting with WMI_PDEV_ID_ for values. + */ + A_UINT32 pdev_id; + + /* Original or old Hardware mode */ + A_UINT32 old_hw_mode_index; + /* New Hardware Mode */ + A_UINT32 new_hw_mode_index; + /* Number of Vdev to Mac entries */ + A_UINT32 num_vdev_mac_entries; + +/** + * TLV (tag length value) parameters follow the soc_set_hw_mode_response_event + * structure. The TLV's are: + * A_UINT32 wmi_soc_set_hw_mode_response_vdev_mac_entry[]; + */ +} wmi_pdev_hw_mode_transition_event_fixed_param; + +/** + * This command is sent from WLAN host driver to firmware for + * plugging in reorder queue desc to lithium hw. + * + * Example: plug-in queue desc for TID 5 + * host->target: WMI_PEER_REORDER_QUEUE_SETUP_CMDID, + * (vdev_id = PEER vdev id, + * peer_macaddr = PEER mac addr, + * tid = 5, + * queue_ptr_lo = queue desc addr lower 32 bits, + * queue_ptr_hi = queue desc addr higher 32 bits, + * queue_no = 16-bit number assigned by host for queue, + * stored in bits 15:0 of queue_no field) + */ +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_peer_reorder_queue_setup_cmd_fixed_param */ + A_UINT32 vdev_id; + wmi_mac_addr peer_macaddr; /* peer mac address */ + A_UINT32 tid; /* 0 to 15 = QoS TIDs, 16 = non-qos TID */ + A_UINT32 queue_ptr_lo; /* lower 32 bits of queue desc adddress */ + A_UINT32 queue_ptr_hi; /* upper 32 bits of queue desc adddress */ + A_UINT32 queue_no; /* 16-bit number assigned by host for queue, + stored in bits 15:0 of queue_no field */ +} wmi_peer_reorder_queue_setup_cmd_fixed_param; + +/** + * This command is sent from WLAN host driver to firmware for + * removing one or more reorder queue desc to lithium hw. + * + * Example: remove queue desc for all TIDs + * host->target: WMI_PEER_REORDER_REMOVE_CMDID, + * (vdev_id = PEER vdev id, + * peer_macaddr = PEER mac addr, + * tid = 0x1FFFF, + */ +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_peer_reorder_queue_remove_cmd_fixed_param */ + A_UINT32 vdev_id; + wmi_mac_addr peer_macaddr; /* peer mac address */ + A_UINT32 tid_mask; /* bits 0 to 15 = QoS TIDs, bit 16 = non-qos TID */ +} wmi_peer_reorder_queue_remove_cmd_fixed_param; + + +/* DEPRECATED - use wmi_pdev_set_mac_config_response_event_fixed_param instead */ +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_soc_set_dual_mac_config_response_event_fixed_param */ + /** Set Dual MAC Config Response Event **/ + + /* Status for set_dual_mac_config command */ + /* + * Values for Status: + * 0 - OK; command successful + * 1 - EINVAL; Requested invalid hw_mode + * 3 - ENOTSUP; HW mode not supported + * 4 - EHARDWARE; HW mode change prevented by hardware + * 6 - ECOEX; HW mode change conflict with Coex + */ + A_UINT32 status; + +} wmi_soc_set_dual_mac_config_response_event_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_pdev_set_mac_config_response_event_fixed_param */ + /** Set Dual MAC Config Response Event **/ + + /** pdev_id for identifying the MAC + * See macros starting with WMI_PDEV_ID_ for values. + */ + A_UINT32 pdev_id; + + /* Status for set_dual_mac_config command */ + /* + * Values for Status: + * 0 - OK; command successful + * 1 - EINVAL; Requested invalid hw_mode + * 3 - ENOTSUP; HW mode not supported + * 4 - EHARDWARE; HW mode change prevented by hardware + * 6 - ECOEX; HW mode change conflict with Coex + */ + A_UINT32 status; +} wmi_pdev_set_mac_config_response_event_fixed_param; + +typedef enum { + MAWC_MOTION_STATE_UNKNOWN, + MAWC_MOTION_STATE_STATIONARY, + MAWC_MOTION_STATE_WALK, + MAWC_MOTION_STATE_TRANSIT, +} MAWC_MOTION_STATE; + +typedef enum { + MAWC_SENSOR_STATUS_OK, + MAWC_SENSOR_STATUS_FAILED_TO_ENABLE, + MAWC_SENSOR_STATUS_SHUTDOWN, +} MAWC_SENSOR_STATUS; + +typedef struct { + /* TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_mawc_sensor_report_ind_cmd_fixed_param */ + A_UINT32 tlv_header; + /** new motion state, MAWC_MOTION_STATE */ + A_UINT32 motion_state; + /** status code of sensor, MAWC_SENSOR_STATUS */ + A_UINT32 sensor_status; +} wmi_mawc_sensor_report_ind_cmd_fixed_param; + +/* MBO flag field definition */ +/* Bit 0: 0 - Allow to connect to both MBO and non-MBO AP + * 1 - Allow to connect to MBO AP only + * Bit 1-31 : reserved. + */ +#define WMI_ROAM_MBO_FLAG_MBO_ONLY_MODE (1<<0) /* DEPRECATED */ + +typedef struct { + /* TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_roam_set_mbo_fixed_param */ + A_UINT32 tlv_header; + /** vdev id */ + A_UINT32 vdev_id; + /** enable or disable MBO */ + A_UINT32 enable; + /** MBO flags, refer to definition of MBO flags*/ + A_UINT32 flags; +} wmi_roam_set_mbo_fixed_param; /* DEPRECATED */ + +typedef struct { + /* TLV tag and len; tag equals + * WMITLV_TAG_ARRAY_STRUC */ + A_UINT32 tlv_header; + /** Current operating class number */ + A_UINT32 cur_op_class; + /** Country string of current reg domain, + * the expected value should be same as country str defined + * in country IE. + * 3 octets (COUNTRY_STR) + 1 octet (always 0) + * The ordering of this array must be maintained, + * even when a big-endian host's WMI messages undergo + * automatic byte reordering for conversion to the + * little-endian ordering required by the target. + * On big-endian hosts, this array may need to be byte-swapped + * by the host, so the subsequent automatic byte-swap + * will result in the correct final byte order. + * global operating class: set country_str[0]=0 + */ + A_UINT8 country_str[4]; + /** Supported operating class number in current regdomain */ + A_UINT32 supp_op_class_num; + /* The TLVs will follow. */ + /* A_UINT32 supp_op_class_list[] */ +} wmi_supported_operating_class_param; + +typedef struct { + /* TLV tag and len; tag equals + * WMITLV_TAG_ARRAY_STRUC */ + A_UINT32 tlv_header; + /** non preferred channel attribute length */ + A_UINT32 non_prefer_ch_attr_len; + /* The TLVs will follow. */ + /** A_UINT8 non_prefer_ch_attr[];*/ +} wmi_mbo_non_preferred_channel_report_param; + +typedef struct { + /* TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_mawc_enable_sensor_event_fixed_param */ + A_UINT32 tlv_header; + /* enable(1) or disable(0) */ + A_UINT32 enable; +} wmi_mawc_enable_sensor_event_fixed_param; + +typedef struct { + /* TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_extscan_configure_mawc_cmd_fixed_param */ + A_UINT32 tlv_header; + /* Unique id identifying the VDEV */ + A_UINT32 vdev_id; + /* enable(1) or disable(0) MAWC */ + A_UINT32 enable; + /* ratio of skipping suppressing scan, skip one out of x */ + A_UINT32 suppress_ratio; +} wmi_extscan_configure_mawc_cmd_fixed_param; + +typedef struct { + /* TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_roam_per_config_fixed_param */ + A_UINT32 tlv_header; + /* Unique id identifying the VDEV */ + A_UINT32 vdev_id; + /* enable(1) or disable(0) packet error rate trigger for roaming */ + A_UINT32 enable; + /* high_rate_thresh, low_rate_thresh, pkt_err_rate_thresh_pct: + * If PER monitoring as a trigger for roaming is enabled, + * it is controlled by high_rate_thresh, low_rate_thresh, and + * pkt_err_rate_thresh_pct. + * PER monitoring is performed only when the time-averaged throughput + * is less than high_rate_thresh. + * During PER monitoring, the target keeps track of the PHY rate for + * each of the first N PPDUs within a time window. + * If the number of PPDUs with PHY rate < low_rate_thresh exceeds + * N * pkt_err_rate_thresh_pct / 100, roaming will be triggered. + * + * This PER monitoring as a trigger for roaming is performed + * concurrently but independently for rx and tx. + */ + A_UINT32 high_rate_thresh; /* units = Kbps */ + A_UINT32 low_rate_thresh; /* units = Kbps */ + A_UINT32 pkt_err_rate_thresh_pct; + /* + * rest time after associating to a new AP before + * starting to monitor PER as a roaming trigger, + * (units are seconds) + */ + A_UINT32 per_rest_time; + /* This is the total time for which PER monitoring will be run. + * After completion of time windows, the average PER over the window + * will be computed. + * The parameter value stores specifications for both TX and RX + * monitor times. + * The two least-significant bytes (0 & 1) hold the RX monitor time; + * the two most-significant bytes (2 & 3) hold the TX monitor time. + */ + A_UINT32 pkt_err_rate_mon_time; /* units = seconds */ + /* Minimum roamable AP RSSI for candidate selection for PER based roam */ + A_INT32 min_candidate_rssi; /* units = dBm */ +} wmi_roam_per_config_fixed_param; + +typedef struct { + /* TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_nlo_configure_mawc_cmd_fixed_param */ + A_UINT32 tlv_header; + /* Unique id identifying the VDEV */ + A_UINT32 vdev_id; + /* enable(1) or disable(0) MAWC */ + A_UINT32 enable; + /* ratio of exponential backoff, next = current + current*ratio/100 */ + A_UINT32 exp_backoff_ratio; + /* initial scan interval(msec) */ + A_UINT32 init_scan_interval; + /* max scan interval(msec) */ + A_UINT32 max_scan_interval; +} wmi_nlo_configure_mawc_cmd_fixed_param; + +typedef struct { + /* TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_roam_configure_mawc_cmd_fixed_param */ + A_UINT32 tlv_header; + /* Unique id identifying the VDEV */ + A_UINT32 vdev_id; + /* enable(1) or disable(0) MAWC */ + A_UINT32 enable; + /* data traffic load (kBps) to register CMC */ + A_UINT32 traffic_load_threshold; + /* RSSI threshold (dBm) to scan for Best AP */ + A_UINT32 best_ap_rssi_threshold; + /* high RSSI threshold adjustment in Stationary to suppress scan */ + A_UINT32 rssi_stationary_high_adjust; + /* low RSSI threshold adjustment in Stationary to suppress scan */ + A_UINT32 rssi_stationary_low_adjust; +} wmi_roam_configure_mawc_cmd_fixed_param; + +#define WMI_PACKET_FILTER_COMPARE_DATA_LEN_DWORD 2 +#define WMI_PACKET_FILTER_MAX_CMP_PER_PACKET_FILTER 5 + +typedef enum { + PACKET_FILTER_TYPE_INVALID = 0, + PACKET_FILTER_TYPE_FILTER_PKT, + PACKET_FILTER_TYPE_RESERVE_PKT, /* not used */ + PACKET_FILTER_TYPE_MAX_ENUM_SIZE +} WMI_PACKET_FILTER_FILTER_TYPE; + +typedef enum { + PACKET_FILTER_PROTO_TYPE_INVALID = 0, + + /* L2 header */ + PACKET_FILTER_PROTO_TYPE_MAC, + PACKET_FILTER_PROTO_TYPE_SNAP, + + /* L3 header (EtherType) */ + PACKET_FILTER_PROTO_TYPE_IPV4, + PACKET_FILTER_PROTO_TYPE_IPV6, + + /* L4 header (IP protocol) */ + PACKET_FILTER_PROTO_TYPE_UDP, + PACKET_FILTER_PROTO_TYPE_TCP, + PACKET_FILTER_PROTO_TYPE_ICMPV6, + + PACKET_FILTER_PROTO_TYPE_MAX +} WMI_PACKET_FILTER_PROTO_TYPE; + +typedef enum { + PACKET_FILTER_CMP_TYPE_INVALID = 0, + PACKET_FILTER_CMP_TYPE_EQUAL, + PACKET_FILTER_CMP_TYPE_MASK_EQUAL, + PACKET_FILTER_CMP_TYPE_NOT_EQUAL, + PACKET_FILTER_CMP_TYPE_MASK_NOT_EQUAL, + PACKET_FILTER_CMP_TYPE_ADDRTYPE, + PACKET_FILTER_CMP_TYPE_MAX +} WMI_PACKET_FILTER_CMP_TYPE; + +typedef enum { + PACKET_FILTER_SET_INACTIVE = 0, + PACKET_FILTER_SET_ACTIVE +} WMI_PACKET_FILTER_ACTION; + +typedef enum { + PACKET_FILTER_SET_DISABLE = 0, + PACKET_FILTER_SET_ENABLE +} WMI_PACKET_FILTER_RUNTIME_ENABLE; + +typedef struct { + A_UINT32 proto_type; + A_UINT32 cmp_type; + A_UINT32 data_length; /* Length of the data to compare (units = bytes) */ + A_UINT32 data_offset; /* from start of the respective frame header (units = bytes) */ + A_UINT32 compareData[WMI_PACKET_FILTER_COMPARE_DATA_LEN_DWORD]; /* Data to compare, little-endian order */ + A_UINT32 dataMask[WMI_PACKET_FILTER_COMPARE_DATA_LEN_DWORD]; /* Mask to be applied on rcvd packet data before compare, little-endian order */ +} WMI_PACKET_FILTER_PARAMS_TYPE; + +typedef struct { + A_UINT32 tlv_header; + A_UINT32 vdev_id; + A_UINT32 filter_id; + A_UINT32 filter_action; /* WMI_PACKET_FILTER_ACTION */ + A_UINT32 filter_type; + A_UINT32 num_params; /* how many entries in paramsData are valid */ + A_UINT32 coalesce_time; /* not currently used - fill with 0x0 */ + WMI_PACKET_FILTER_PARAMS_TYPE paramsData[WMI_PACKET_FILTER_MAX_CMP_PER_PACKET_FILTER]; + /* deprecated0: + * This field simply provides filler space to retain the original message + * format while reducing WMI_PACKET_FILTER_MAX_CMP_PER_PACKET_FILTER + * from 10 to 5. + */ + WMI_PACKET_FILTER_PARAMS_TYPE deprecated0[5]; +} WMI_PACKET_FILTER_CONFIG_CMD_fixed_param; + +/* enable / disable all filters within the specified vdev */ +typedef struct { + A_UINT32 tlv_header; + A_UINT32 vdev_id; + A_UINT32 enable; /* WMI_PACKET_FILTER_RUNTIME_ENABLE */ +} WMI_PACKET_FILTER_ENABLE_CMD_fixed_param; + +#define WMI_LRO_INFO_TCP_FLAG_VALS_BITPOS 0 +#define WMI_LRO_INFO_TCP_FLAG_VALS_NUMBITS 9 + +#define WMI_LRO_INFO_TCP_FLAG_VALS_SET(tcp_flag_u32, tcp_flag_values) \ + WMI_SET_BITS(tcp_flag_u32, \ + WMI_LRO_INFO_TCP_FLAG_VALS_BITPOS, \ + WMI_LRO_INFO_TCP_FLAG_VALS_NUMBITS, \ + tcp_flag_values) +#define WMI_LRO_INFO_TCP_FLAG_VALS_GET(tcp_flag_u32) \ + WMI_GET_BITS(tcp_flag_u32, \ + WMI_LRO_INFO_TCP_FLAG_VALS_BITPOS, \ + WMI_LRO_INFO_TCP_FLAG_VALS_NUMBITS) + +#define WMI_LRO_INFO_TCP_FLAGS_MASK_BITPOS 9 +#define WMI_LRO_INFO_TCP_FLAGS_MASK_NUMBITS 9 + +#define WMI_LRO_INFO_TCP_FLAGS_MASK_SET(tcp_flag_u32, tcp_flags_mask) \ + WMI_SET_BITS(tcp_flag_u32, \ + WMI_LRO_INFO_TCP_FLAGS_MASK_BITPOS, \ + WMI_LRO_INFO_TCP_FLAGS_MASK_NUMBITS, \ + tcp_flags_mask) +#define WMI_LRO_INFO_TCP_FLAGS_MASK_GET(tcp_flag_u32) \ + WMI_GET_BITS(tcp_flag_u32, \ + WMI_LRO_INFO_TCP_FLAGS_MASK_BITPOS, \ + WMI_LRO_INFO_TCP_FLAGS_MASK_NUMBITS) + +typedef struct { + A_UINT32 tlv_header; + /** + * @brief lro_enable - indicates whether lro is enabled + * [0] LRO Enable + */ + A_UINT32 lro_enable; + /** + * @brief tcp_flag_u32 - mask of which TCP flags to check and + * values to check for + * [8:0] TCP flag values - If the TCP flags from the packet do not match + * the values in this field after masking with TCP flags mask below, + * LRO eligible will not be set + * [17:9] TCP flags mask - Mask field for comparing the TCP values + * provided above with the TCP flags field in the received packet + * Use WMI_LRO_INFO_TCP_FLAG_VALS and WMI_LRO_INFO_TCP_FLAGS_MASK + * macros to isolate the mask field and values field that are packed + * into this u32 "word". + */ + A_UINT32 tcp_flag_u32; + /** + * @brief toeplitz_hash_ipv4 - contains seed needed to compute + * the flow id 5-tuple toeplitz hash for IPv4 packets. Contains + * bytes 0 to 3 + * + * In this and all the below toeplitz_hash fields, the bytes are + * specified in little-endian order. For example: + * toeplitz_hash_ipv4_0_3 bits 7:0 holds seed byte 0 + * toeplitz_hash_ipv4_0_3 bits 15:8 holds seed byte 1 + * toeplitz_hash_ipv4_0_3 bits 23:16 holds seed byte 2 + * toeplitz_hash_ipv4_0_3 bits 31:24 holds seed byte 3 + */ + A_UINT32 toeplitz_hash_ipv4_0_3; + + /** + * @brief toeplitz_hash_ipv4 - contains seed needed to compute + * the flow id 5-tuple toeplitz hash for IPv4 packets. Contains + * bytes 4 to 7 + */ + A_UINT32 toeplitz_hash_ipv4_4_7; + + /** + * @brief toeplitz_hash_ipv4 - contains seed needed to compute + * the flow id 5-tuple toeplitz hash for IPv4 packets. Contains + * bytes 8 to 11 + */ + A_UINT32 toeplitz_hash_ipv4_8_11; + + /** + * @brief toeplitz_hash_ipv4 - contains seed needed to compute + * the flow id 5-tuple toeplitz hash for IPv4 packets. Contains + * bytes 12 to 15 + */ + A_UINT32 toeplitz_hash_ipv4_12_15; + + /** + * @brief toeplitz_hash_ipv4 - contains seed needed to compute + * the flow id 5-tuple toeplitz hash for IPv4 packets. Contains + * byte 16 + */ + A_UINT32 toeplitz_hash_ipv4_16; + + /** + * @brief toeplitz_hash_ipv6 - contains seed needed to compute + * the flow id 5-tuple toeplitz hash for IPv6 packets. Contains + * bytes 0 to 3 + */ + A_UINT32 toeplitz_hash_ipv6_0_3; + + /** + * @brief toeplitz_hash_ipv6 - contains seed needed to compute + * the flow id 5-tuple toeplitz hash for IPv6 packets. Contains + * bytes 4 to 7 + */ + A_UINT32 toeplitz_hash_ipv6_4_7; + + /** + * @brief toeplitz_hash_ipv6 - contains seed needed to compute + * the flow id 5-tuple toeplitz hash for IPv6 packets. Contains + * bytes 8 to 11 + */ + A_UINT32 toeplitz_hash_ipv6_8_11; + + /** + * @brief toeplitz_hash_ipv6 - contains seed needed to compute + * the flow id 5-tuple toeplitz hash for IPv6 packets. Contains + * bytes 12 to 15 + */ + A_UINT32 toeplitz_hash_ipv6_12_15; + + /** + * @brief toeplitz_hash_ipv6 - contains seed needed to compute + * the flow id 5-tuple toeplitz hash for IPv6 packets. Contains + * bytes 16 to 19 + */ + A_UINT32 toeplitz_hash_ipv6_16_19; + + /** + * @brief toeplitz_hash_ipv6 - contains seed needed to compute + * the flow id 5-tuple toeplitz hash for IPv6 packets. Contains + * bytes 20 to 22 + */ + A_UINT32 toeplitz_hash_ipv6_20_23; + + /** + * @brief toeplitz_hash_ipv6 - contains seed needed to compute + * the flow id 5-tuple toeplitz hash for IPv6 packets. Contains + * bytes 24 to 27 + */ + A_UINT32 toeplitz_hash_ipv6_24_27; + + /** + * @brief toeplitz_hash_ipv6 - contains seed needed to compute + * the flow id 5-tuple toeplitz hash for IPv6 packets. Contains + * bytes 28 to 31 + */ + A_UINT32 toeplitz_hash_ipv6_28_31; + + /** + * @brief toeplitz_hash_ipv6 - contains seed needed to compute + * the flow id 5-tuple toeplitz hash for IPv6 packets. Contains + * bytes 32 to 35 + */ + A_UINT32 toeplitz_hash_ipv6_32_35; + + /** + * @brief toeplitz_hash_ipv6 - contains seed needed to compute + * the flow id 5-tuple toeplitz hash for IPv6 packets. Contains + * bytes 36 to 39 + */ + A_UINT32 toeplitz_hash_ipv6_36_39; + + /** + * @brief toeplitz_hash_ipv6 - contains seed needed to compute + * the flow id 5-tuple toeplitz hash for IPv6 packets. Contains + * byte 40 + */ + A_UINT32 toeplitz_hash_ipv6_40; +} wmi_lro_info_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_transfer_data_to_flash_cmd_fixed_param */ + A_UINT32 offset; /* flash offset to write, starting from 0 */ + A_UINT32 length; /* vaild data length in buffer, unit: byte */ +} wmi_transfer_data_to_flash_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_transfer_data_to_flash_complete_event_fixed_param */ + /** Return status. 0 for success, non-zero otherwise */ + A_UINT32 status; +} wmi_transfer_data_to_flash_complete_event_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_read_data_from_flash_cmd_fixed_param */ + A_UINT32 offset; /* flash offset to read, starting from 0 */ + A_UINT32 length; /* data length to read, unit: byte */ +} wmi_read_data_from_flash_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_read_data_from_flash_event_fixed_param */ + A_UINT32 status; /* Return status. 0 for success, non-zero otherwise */ + A_UINT32 offset; /* flash offset reading from, starting from 0 */ + A_UINT32 length; /* length of data being reported, unit: byte */ +} wmi_read_data_from_flash_event_fixed_param; + +typedef enum { + ENHANCED_MCAST_FILTER_DISABLED, + ENHANCED_MCAST_FILTER_ENABLED +} ENHANCED_MCAST_FILTER_CONFIG; + +/* + * Command to enable/disable filtering of multicast IP with unicast mac + */ +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_config_enhanced_mcast_filter_fixed_param */ + /* Unique id identifying the VDEV */ + A_UINT32 vdev_id; + /* 1 = enable 0 = disable (see ENHANCED_MCAST_FILTER_CONFIG) */ + A_UINT32 enable; +} wmi_config_enhanced_mcast_filter_cmd_fixed_param; + +typedef struct { + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_vdev_wisa_cmd_fixed_param */ + A_UINT32 tlv_header; + /** unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; + /** WISA enable / disable mode */ + A_UINT32 wisa_mode; +} wmi_vdev_wisa_cmd_fixed_param; + +/* + * This structure is used to report SMPS force mode set complete to host. + */ +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_sta_smps_force_mode_complete_event_fixed_param */ + /* Unique id identifying the VDEV */ + A_UINT32 vdev_id; + /* Return status. 0 for success, non-zero otherwise */ + A_UINT32 status; +} wmi_sta_smps_force_mode_complete_event_fixed_param; + +/* + * This structure is used to report SCPC calibrated data to host. + */ +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_scpc_event_fixed_param */ + /** number of BDF patches. Each patch contains offset, length and data */ + A_UINT32 num_patch; +/* This TLV is followed by another TLV of array of bytes + * A_UINT8 data[]; + * This data array contains, for example + * patch1 offset(byte3~0), patch1 data length(byte7~4), patch1 data(byte11~8) + * patch2 offset(byte15~12), patch2 data length(byte19~16), patch2 data(byte47~20) + * + */ +} wmi_scpc_event_fixed_param; + +typedef enum { + FW_ACTIVE_BPF_MODE_DISABLE = (1 << 1), + FW_ACTIVE_BPF_MODE_FORCE_ENABLE = (1 << 2), + FW_ACTIVE_BPF_MODE_ADAPTIVE_ENABLE = (1 << 3), +} FW_ACTIVE_BPF_MODE; + +/* bpf interface structure */ +typedef struct wmi_bpf_get_capability_cmd_s { + A_UINT32 tlv_header; + A_UINT32 reserved; /* reserved for future use - must be filled with 0x0 */ +} wmi_bpf_get_capability_cmd_fixed_param; + +typedef struct wmi_bpf_capability_info_evt_s { + A_UINT32 tlv_header; + A_UINT32 bpf_version; /* fw's implement version */ + A_UINT32 max_bpf_filters; /* max filters that fw supports */ + A_UINT32 max_bytes_for_bpf_inst; /* the maximum bytes that can be used as bpf instructions */ + A_UINT32 fw_active_bpf_support_mcbc_modes; /* multicast/broadcast - refer to FW_ACTIVE_BPF_MODE, it can be 'or' of them */ + A_UINT32 fw_active_bpf_support_uc_modes; /* unicast - refer to FW_ACTIVE_BPF_MODE, it can be 'or' of them */ +} wmi_bpf_capability_info_evt_fixed_param; + +/* bit 0 of flags: report counters */ +#define WMI_BPF_GET_VDEV_STATS_FLAG_CTR_S 0 +#define WMI_BPF_GET_VDEV_STATS_FLAG_CTR_M 0x1 +typedef struct wmi_bpf_get_vdev_stats_cmd_s { + A_UINT32 tlv_header; + A_UINT32 flags; + A_UINT32 vdev_id; +} wmi_bpf_get_vdev_stats_cmd_fixed_param; + +typedef struct wmi_bpf_vdev_stats_info_evt_s { + A_UINT32 tlv_header; + A_UINT32 vdev_id; + A_UINT32 num_filters; + A_UINT32 num_checked_pkts; + A_UINT32 num_dropped_pkts; +} wmi_bpf_vdev_stats_info_evt_fixed_param; + +typedef struct wmi_bpf_set_vdev_instructions_cmd_s { + A_UINT32 tlv_header; + A_UINT32 vdev_id; + A_UINT32 filter_id; + A_UINT32 bpf_version; /* host bpf version */ + A_UINT32 total_length; + A_UINT32 current_offset; + A_UINT32 current_length; +/* + * The TLV follows: + * A_UINT8 buf_inst[]; <-- Variable length buffer for the instuctions + */ +} wmi_bpf_set_vdev_instructions_cmd_fixed_param; + +#define BPF_FILTER_ID_ALL 0xFFFFFFFF +typedef struct wmi_bpf_del_vdev_instructions_cmd_s { + A_UINT32 tlv_header; + A_UINT32 vdev_id; + A_UINT32 filter_id; /* BPF_FILTER_ID_ALL means delete all */ +} wmi_bpf_del_vdev_instructions_cmd_fixed_param; + +typedef struct wmi_bpf_set_vdev_active_mode_cmd_s { + A_UINT32 tlv_header; + A_UINT32 vdev_id; + A_UINT32 mcbc_mode; /* refer to FW_ACTIVE_BPF_MODE */ + A_UINT32 uc_mode; /* refer to FW_ACTIVE_BPF_MODE */ +} wmi_bpf_set_vdev_active_mode_cmd_fixed_param; + +#define AES_BLOCK_LEN 16 /* in bytes */ +#define FIPS_KEY_LENGTH_128 16 /* in bytes */ +#define FIPS_KEY_LENGTH_256 32 /* in bytes */ +#define FIPS_ENCRYPT_CMD 0 +#define FIPS_DECRYPT_CMD 1 +#define FIPS_ENGINE_AES_CTR 0 +#define FIPS_ENGINE_AES_MIC 1 +#define FIPS_ERROR_OPER_TIMEOUT 1 + +/* WMI_PDEV_FIPS_CMDID */ +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_pdev_fips_cmd_fixed_param */ + + union { + A_UINT32 mac_id; /* OBSOLETE - will be removed once all refs are gone */ + /** pdev_id for identifying the MAC + * See macros starting with WMI_PDEV_ID_ for values. + */ + A_UINT32 pdev_id; + }; + + A_UINT32 fips_cmd; /* FIPS_ENCRYPT or FIPS_DECRYPT */ + A_UINT32 mode; /* FIPS_ENGINE_AES_CTR or FIPS_ENGINE_AES_MIC */ + A_UINT32 key_len; /* FIPS_KEY_LENGTH_128 or FIPS_KEY_LENGTH_256 (units = bytes) */ + A_UINT8 key[WMI_MAX_KEY_LEN]; /* Key */ + A_UINT32 data_len; /* data length */ +/* + * Following this structure is the TLV: + * A_UINT32 data[1]; <-- In Data (keep this in the end) + */ +} wmi_pdev_fips_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_pdev_smart_ant_enable_cmd_fixed_param */ + union { + A_UINT32 mac_id; /* OBSOLETE - will be removed once all refs are gone */ + /** pdev_id for identifying the MAC + * See macros starting with WMI_PDEV_ID_ for values. + */ + A_UINT32 pdev_id; + }; + A_UINT32 enable; /* 1:enable, 0:disable */ + A_UINT32 mode; /* 1:GPIO parallel mode, 0:GPIO serial mode */ + A_UINT32 rx_antenna; /* rx antenna */ + A_UINT32 tx_default_antenna; /* tx default antenna */ + /* + * Following this structure is the TLV: + * wmi_pdev_smart_ant_gpio_handle + */ +} wmi_pdev_smart_ant_enable_cmd_fixed_param; + +/** GPIO pins/function values to control antennas */ +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_pdev_smart_ant_gpio_handle */ + A_UINT32 gpio_pin; /* For serial: index 0-strobe index 1-data, For Parallel: per stream */ + A_UINT32 gpio_func; /* GPIO function values for Smart Antenna */ + /** pdev_id for identifying the MAC + * See macros starting with WMI_PDEV_ID_ for values. + */ + A_UINT32 pdev_id; +} wmi_pdev_smart_ant_gpio_handle; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_pdev_smart_ant_set_rx_antenna_cmd_fixed_param */ + union { + A_UINT32 mac_id; /* OBSOLETE - will be removed once all refs are gone */ + /** pdev_id for identifying the MAC + * See macros starting with WMI_PDEV_ID_ for values. + */ + A_UINT32 pdev_id; + }; + A_UINT32 rx_antenna; +} wmi_pdev_smart_ant_set_rx_antenna_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_peer_smart_ant_set_tx_antenna_cmd_fixed_param */ + /** unique id identifying the vdev, generated by the caller */ + A_UINT32 vdev_id; /* ID of the vdev this peer belongs to */ + /** peer MAC address */ + wmi_mac_addr peer_macaddr; + /* + * Following this structure is the TLV: + * wmi_peer_smart_ant_set_tx_antenna_series + */ +} wmi_peer_smart_ant_set_tx_antenna_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_peer_smart_ant_set_tx_antenna_series */ + /* antenna array */ + A_UINT32 antenna_series; +} wmi_peer_smart_ant_set_tx_antenna_series; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_peer_smart_ant_set_train_antenna_param */ + /* rate array */ + A_UINT32 train_rate_series; + /* antenna array */ + A_UINT32 train_antenna_series; + /* Rate flags */ + /* TODO: For future use? */ + A_UINT32 rc_flags; +} wmi_peer_smart_ant_set_train_antenna_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_peer_smart_ant_set_train_antenna_cmd_fixed_param */ + /** unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; /* ID of the vdev this peer belongs to */ + /** peer MAC address */ + wmi_mac_addr peer_macaddr; + /* num packets; 0-stop training */ + A_UINT32 num_pkts; + /* + * Following this structure is the TLV: + * wmi_peer_smart_ant_set_train_antenna_param + */ +} wmi_peer_smart_ant_set_train_antenna_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_peer_smart_ant_set_node_config_ops_cmd_fixed_param */ + /** unique id identifying the vdev, generated by the caller */ + A_UINT32 vdev_id; /* ID of the vdev this peer belongs to */ + /** peer MAC address */ + wmi_mac_addr peer_macaddr; + /* command id*/ + A_UINT32 cmd_id; + /* number of arguments passed */ + A_UINT32 args_count; +/* + * Following this structure is the TLV: + * A_UINT32 args[]; <-- argument list + */ +} wmi_peer_smart_ant_set_node_config_ops_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_pdev_set_ant_ctrl_chain */ + A_UINT32 antCtrlChain; + /** pdev_id for identifying the MAC + * See macros starting with WMI_PDEV_ID_ for values. + */ + A_UINT32 pdev_id; +} wmi_pdev_set_ant_ctrl_chain; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_pdev_set_ant_switch_tbl_cmd_fixed_param */ + A_UINT32 mac_id; /* MAC ID */ + A_UINT32 antCtrlCommon1; + A_UINT32 antCtrlCommon2; + /* + * Following this structure is the TLV: + * wmi_pdev_set_ant_ctrl_chain + */ +} wmi_pdev_set_ant_switch_tbl_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_pdev_set_ctl_table_cmd_fixed_param */ + union { + A_UINT32 mac_id; /* OBSOLETE - will be removed once all refs are gone */ + /** pdev_id for identifying the MAC + * See macros starting with WMI_PDEV_ID_ for values. + */ + A_UINT32 pdev_id; + }; + /** len of CTL info */ + A_UINT32 ctl_len; + /* ctl array (len adjusted to number of words). + * Following this structure is the TLV: + * A_UINT32 ctl_info[1]; + */ +} wmi_pdev_set_ctl_table_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_pdev_set_mimogain_table_cmd_fixed_param */ + union { + A_UINT32 mac_id; /* OBSOLETE - will be removed once all refs are gone */ + /** pdev_id for identifying the MAC + * See macros starting with WMI_PDEV_ID_ for values. + */ + A_UINT32 pdev_id; + }; + A_UINT32 mimogain_info; /* see WMI_MIMOGAIN macros */ + /* + * Bit 7:0 len of array gain table + * Bit 8 bypass multi chain gain or not + */ + /* array gain table(s) (len adjusted to number of words). + * Following this structure is the TLV: + * A_UINT32 arraygain_tbl[1]; + */ +} wmi_pdev_set_mimogain_table_cmd_fixed_param; + +#define WMI_MIMOGAIN_ARRAY_GAIN_LEN_S 0 +#define WMI_MIMOGAIN_ARRAY_GAIN_LEN (0xff << WMI_MIMOGAIN_ARRAY_GAIN_LEN_S) +#define WMI_MIMOGAIN_ARRAY_GAIN_LEN_GET(x) WMI_F_MS(x,WMI_MIMOGAIN_ARRAY_GAIN_LEN) +#define WMI_MIMOGAIN_ARRAY_GAIN_LEN_SET(x,z) WMI_F_RMW(x,z,WMI_MIMOGAIN_ARRAY_GAIN_LEN) + +#define WMI_MIMOGAIN_MULTI_CHAIN_BYPASS_S 8 +#define WMI_MIMOGAIN_MULTI_CHAIN_BYPASS (0x1 << WMI_MIMOGAIN_MULTI_CHAIN_BYPASS_S) +#define WMI_MIMOGAIN_MULTI_CHAIN_BYPASS_GET(x) WMI_F_MS(x,WMI_MIMOGAIN_MULTI_CHAIN_BYPASS) +#define WMI_MIMOGAIN_MULTI_CHAIN_BYPASS_SET(x,z) WMI_F_RMW(x,z,WMI_MIMOGAIN_MULTI_CHAIN_BYPASS) + + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_fwtest_set_param_cmd_fixed_param */ + /** parameter id */ + A_UINT32 param_id; + /** parameter value */ + A_UINT32 param_value; +} wmi_fwtest_set_param_cmd_fixed_param; + +#define WMI_ATF_DENOMINATION 1000 /* Expressed in 1 part in 1000 (permille) */ + +#define WMI_ATF_SSID_FAIR_SCHED 0 /** fair ATF scheduling for vdev */ +#define WMI_ATF_SSID_STRICT_SCHED 1 /** strict ATF scheduling for vdev */ + +typedef struct { + /** TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_atf_peer_info */ + A_UINT32 tlv_header; + wmi_mac_addr peer_macaddr; + A_UINT32 atf_units; /* Based on 1 part in 1000 (per mille) */ + A_UINT32 atf_groupid; /* Group Id of the peers for ATF SSID grouping */ + A_UINT32 atf_units_reserved; /* Peer congestion threshold for future use */ + A_UINT32 vdev_id; + A_UINT32 pdev_id; +} wmi_atf_peer_info; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_peer_atf_request_fixed_param */ + A_UINT32 num_peers; + /* + * Following this structure is the TLV: + * struct wmi_atf_peer_info peer_info[num_peers]; + */ +} wmi_peer_atf_request_fixed_param; + +/* Structure for Bandwidth Fairness peer information */ +typedef struct { + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_bwf_peer_info */ + A_UINT32 tlv_header; + wmi_mac_addr peer_macaddr; + A_UINT32 bwf_guaranteed_bandwidth; /* BWF guaranteed_bandwidth for the peers in mbps */ + A_UINT32 bwf_max_airtime; /* BWF Maximum airtime percentage that can be allocated to the peer to meet the guaranteed_bandwidth */ + A_UINT32 bwf_peer_priority; /* BWF priority of the peer to allocate the tokens dynamically */ + A_UINT32 vdev_id; + A_UINT32 pdev_id; +} wmi_bwf_peer_info; + +/* Structure for Bandwidth Fairness peer request */ +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_peer_bwf_request_fixed_param */ + A_UINT32 num_peers; + /* + * Following this structure is the TLV: + * struct wmi_bwf_peer_info peer_info[num_peers]; + */ +} wmi_peer_bwf_request_fixed_param; + +/* Equal distribution of ATF air time within an VDEV. */ +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_vdev_atf_request_fixed_param */ + A_UINT32 vdev_id; + A_UINT32 peer_atf_units; /* Per peer ATF units (per mille). */ + A_UINT32 pdev_id; +} wmi_vdev_atf_request_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_pdev_get_ani_cck_config_cmd_fixed_param */ + /** pdev_id for identifying the MAC + * See macros starting with WMI_PDEV_ID_ for values. + */ + A_UINT32 pdev_id; + /** parameter */ + A_UINT32 param; +} wmi_pdev_get_ani_cck_config_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_pdev_get_ani_ofdm_config_cmd_fixed_param */ + /** pdev_id for identifying the MAC + * See macros starting with WMI_PDEV_ID_ for values. + */ + A_UINT32 pdev_id; + /** parameter */ + A_UINT32 param; +} wmi_pdev_get_ani_ofdm_config_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_WMI_QBOOST_CFG_CMD_fixed_param */ + A_UINT32 vdev_id; /* ID of the vdev this peer belongs to */ + A_UINT32 qb_enable; + wmi_mac_addr peer_macaddr; +} WMI_QBOOST_CFG_CMD_fixed_param; + +#define WMI_INST_STATS_INVALID_RSSI 0 + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_inst_rssi_stats_resp_fixed_param */ + A_UINT32 iRSSI; /* dB above the noise floor */ + /* peer MAC address */ + wmi_mac_addr peer_macaddr; + A_UINT32 vdev_id; /* ID of the vdev this peer belongs to */ +} wmi_inst_rssi_stats_resp_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_peer_cck_ofdm_rate_info */ + A_UINT32 ratecode_legacy; /* Rate code for CCK OFDM */ +} wmi_peer_cck_ofdm_rate_info; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_peer_mcs_rate_info */ + A_UINT32 ratecode_20; /* Rate code for 20MHz BW */ + A_UINT32 ratecode_40; /* Rate code for 40MHz BW */ + A_UINT32 ratecode_80; /* Rate code for 80MHz BW */ +} wmi_peer_mcs_rate_info; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_peer_ratecode_list_event_fixed_param */ + wmi_mac_addr peer_macaddr; + A_UINT32 ratecount; /* Max Rate count for each mode */ + A_UINT32 vdev_id; /* ID of the vdev this peer belongs to */ + /* + * Following this structure are the TLV: + * struct wmi_peer_cck_ofdm_rate_info; + * struct wmi_peer_mcs_rate_info; + */ +} wmi_peer_ratecode_list_event_fixed_param; + +typedef struct wmi_wds_addr_event { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_wds_addr_event_fixed_param */ + A_UINT32 event_type[4]; + wmi_mac_addr peer_mac; + wmi_mac_addr dest_mac; + A_UINT32 vdev_id; /* ID of the vdev this peer belongs to */ +} wmi_wds_addr_event_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_peer_sta_ps_statechange_event_fixed_param */ + wmi_mac_addr peer_macaddr; + A_UINT32 peer_ps_state; +} wmi_peer_sta_ps_statechange_event_fixed_param; + +/* WMI_PDEV_FIPS_EVENTID */ +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_pdev_fips_event_fixed_param */ + union { + A_UINT32 mac_id; /* OBSOLETE - will be removed once all refs are gone */ + /** pdev_id for identifying the MAC + * See macros starting with WMI_PDEV_ID_ for values. + */ + A_UINT32 pdev_id; + }; + A_UINT32 error_status; /* Error status: 0 (no err), 1, or OPER_TIMEOUT */ + A_UINT32 data_len; /* Data length */ +/* + * Following this structure is the TLV: + * A_UINT32 data[1]; <-- Out Data (keep this in the end) + */ +} wmi_pdev_fips_event_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_pdev_channel_hopping_event_fixed_param */ + union { + A_UINT32 mac_id; /* OBSOLETE - will be removed once all refs are gone */ + /** pdev_id for identifying the MAC + * See macros starting with WMI_PDEV_ID_ for values. + */ + A_UINT32 pdev_id; + }; + /* Noise threshold iterations with high values */ + A_UINT32 noise_floor_report_iter; + /* Total noise threshold iterations */ + A_UINT32 noise_floor_total_iter; +} wmi_pdev_channel_hopping_event_fixed_param; + +enum { + WMI_PDEV_RESERVE_AST_ENTRY_OK, + WMI_PDEV_RESERVE_AST_ENTRY_HASH_COLLISION, + WMI_PDEV_RESERVE_AST_ENTRY_CROSSING_AXI_BOUNDARY, +}; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_pdev_get_tpc_cmd_fixed_param */ + union { + A_UINT32 mac_id; /* OBSOLETE - will be removed once all refs are gone */ + /** pdev_id for identifying the MAC + * See macros starting with WMI_PDEV_ID_ for values. + */ + A_UINT32 pdev_id; + }; + A_UINT32 rate_flags; + /** + * FLAG_ONE_CHAIN 0x00000001 - one chain mask + * FLAG_TWO_CHAIN 0x00000003 - two chain mask + * FLAG_THREE_CHAIN 0x00000007 - three chain mask + * FLAG_FOUR_CHAIN 0x0000000F - four chain mask + * FLAG_FIVE_CHAIN 0x0000001F - five chain mask + * FLAG_SIX_CHAIN 0x0000003F - six chain mask + * FLAG_SEVEN_CHAIN 0x0000007F - seven chain mask + * FLAG_EIGHT_CHAIN 0x000000FF - eight chain mask + * FLAG_STBC 0x00000100 - STBC is set + * FLAG_40MHZ 0x00000200 + * FLAG_80MHZ 0x00000300 + * FLAG_160MHZ 0x00000400 + * FLAG_TXBF 0x00000800 - Tx Bf enabled + * FLAG_RTSENA 0x00001000 - RTS enabled + * FLAG_CTSENA 0x00002000 - CTS enabled + * FLAG_LDPC 0x00004000 - LDPC set + * FLAG_SGI 0x00008000 - Short gaurd interval + * (0x00010000-0x00080000 unused) + *------------------ + * 0x00100000-0x00700000 used for SU/MU/OFDMA tx mode + * FLAG_SU 0x00100000 - SU Data + * FLAG_DL_MU_MIMO_AC 0x00200000 - DL AC MU data + * FLAG_DL_MU_MIMO_AX 0x00300000 - DL AX MU data + * FLAG_DL_OFDMA 0x00400000 - DL OFDMA data + * FLAG_UL_OFDMA 0x00500000 - UL OFDMA data + * FLAG_UL_MU_MIMO 0x00600000 - UL MU data + *------------------ + * */ + A_UINT32 nss; + /** + * NSS 0x0 - 0x7 + * */ + A_UINT32 preamble; + /** + * PREAM_OFDM - 0x0 + * PREAM_CCK - 0x1 + * PREAM_HT - 0x2 + * PREAM_VHT - 0x3 + * PREAM_HE - 0x4 + * */ + A_UINT32 hw_rate; + /** + * *** HW_OFDM_RATE *** + * OFDM_48_MBPS - 0x0 + * OFDM_24_MBPS - 0x1 + * OFDM_12_MBPS - 0x2 + * OFDM_6_MBPS - 0x3 + * OFDM_54_MBPS - 0x4 + * OFDM_36_MBPS - 0x5 + * OFDM_18_MBPS - 0x6 + * OFDM_9_MBPS - 0x7 + * + * *** HW_CCK_RATE *** + * CCK_11_LONG_MBPS - 0x0 + * CCK_5_5_LONG_MBPS - 0x1 + * CCK_2_LONG_MBPS - 0x2 + * CCK_1_LONG_MBPS - 0x3 + * CCK_11_SHORT_MBPS - 0x4 + * CCK_5_5_SHORT_MBPS - 0x5 + * CCK_2_SHORT_MBPS - 0x6 + * + * *** HW_HT / VHT_RATE *** + * MCS 0x0 - 0xb + * */ +} wmi_pdev_get_tpc_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_pdev_get_chip_power_stats_cmd_fixed_param */ + /** pdev_id for identifying the MAC + * See macros starting with WMI_PDEV_ID_ for values. + */ + A_UINT32 pdev_id; +} wmi_pdev_get_chip_power_stats_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_pdev_tpc_event_fixed_param */ + /** pdev_id for identifying the MAC + * See macros starting with WMI_PDEV_ID_ for values. + */ + A_UINT32 pdev_id; + /* + * Following this structure is the TLV: + * A_UINT32 tpc[1]; + */ +} wmi_pdev_tpc_event_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_pdev_nfcal_power_all_channels_event_fixed_param */ + union { + A_UINT32 mac_id; /* OBSOLETE - will be removed once all refs are gone */ + /** pdev_id for identifying the MAC + * See macros starting with WMI_PDEV_ID_ for values. + */ + A_UINT32 pdev_id; + }; + A_UINT32 nfdBr_len; + A_UINT32 nfdBm_len; + A_UINT32 freqNum_len; + /* + * Following this structure is the TLV: + * WMITLV_TAG_STRUC_wmi_pdev_nfcal_power_all_channels_nfdBr; + * WMITLV_TAG_STRUC_wmi_pdev_nfcal_power_all_channels_nfdBm; + * WMITLV_TAG_STRUC_wmi_pdev_nfcal_power_all_channels_freqNum; + */ +} wmi_pdev_nfcal_power_all_channels_event_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_pdev_nfcal_power_all_channels_nfdBr */ + A_UINT32 nfdBr; +} wmi_pdev_nfcal_power_all_channels_nfdBr; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_pdev_nfcal_power_all_channels_nfdBm */ + A_UINT32 nfdBm; +} wmi_pdev_nfcal_power_all_channels_nfdBm; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_pdev_nfcal_power_all_channels_freqNum */ + A_UINT32 freqNum; +} wmi_pdev_nfcal_power_all_channels_freqNum; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_ani_cck_event_fixed_param */ + A_UINT32 cck_level; +} wmi_ani_cck_event_fixed_param; + +typedef enum wmi_power_debug_reg_fmt_type { + /* WMI_POWER_DEBUG_REG_FMT_TYPE_ROME -> Dumps following 12 Registers + * SOC_SYSTEM_SLEEP + * WLAN_SYSTEM_SLEEP + * RTC_SYNC_FORCE_WAKE + * MAC_DMA_ISR + * MAC_DMA_TXRX_ISR + * MAC_DMA_ISR_S1 + * MAC_DMA_ISR_S2 + * MAC_DMA_ISR_S3 + * MAC_DMA_ISR_S4 + * MAC_DMA_ISR_S5 + * MAC_DMA_ISR_S6 + * MAC_DMA_ISR_S7 + */ + WMI_POWER_DEBUG_REG_FMT_TYPE_ROME, + + WMI_POWER_DEBUG_REG_FMT_TYPE_MAX = 0xf, +} WMI_POWER_DEBUG_REG_FMT_TYPE; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_chip_power_stats_event_fixed_param */ + A_UINT32 cumulative_sleep_time_ms; /* maximum range is 35 hours, due to conversion from internal 0.03215 ms units to ms */ + A_UINT32 cumulative_total_on_time_ms; /* maximum range is 35 hours, due to conversion from internal 0.03215 ms units to ms */ + A_UINT32 deep_sleep_enter_counter; /* count of number of times chip enterred deep sleep */ + A_UINT32 last_deep_sleep_enter_tstamp_ms; /* Last Timestamp when Chip went to deep sleep */ + A_UINT32 debug_register_fmt; /* WMI_POWER_DEBUG_REG_FMT_TYPE enum, describes debug registers being dumped as part of the event */ + A_UINT32 num_debug_register; /* number of debug registers being sent to host */ + /* + * Following this structure is the TLV: + * A_UINT32 debug_registers[num_debug_registers]; + */ +} wmi_pdev_chip_power_stats_event_fixed_param; + +typedef enum wmi_chip_power_save_failure_reason_code_type { + WMI_PROTOCOL_POWER_SAVE_FAILURE_REASON, + WMI_HW_POWER_SAVE_FAILURE_REASON, + WMI_CSS_LOCKED_POWER_FAILURE_REASON, + WMI_MAC0_LOCKED_POWER_FAILURE_REASON, + WMI_MAC1_LOCKED_POWER_FAILURE_REASON, + WMI_POWER_SAVE_FAILURE_REASON_MAX = 0xf, +} WMI_POWER_SAVE_FAILURE_REASON_TYPE; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_chip_power_save_failure_detected_fixed_param */ + A_UINT32 power_save_failure_reason_code; /* Chip power save failuire reason as defined in WMI_POWER_SAVE_FAILURE_REASON_TYPE */ + A_UINT32 protocol_wake_lock_bitmap[4]; /* bitmap with bits set for modules (from WLAN_MODULE_ID enum) voting against sleep for prolonged duration */ +} wmi_chip_power_save_failure_detected_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_ani_ofdm_event_fixed_param */ + A_UINT32 ofdm_level; +} wmi_ani_ofdm_event_fixed_param; + +/* When a bit is set it specifies the particular WLAN traffic type is high priority. + * BT low priority traffic has higher priority than WLAN low priority traffic and has + * lower priority when compared to WLAN high priority traffic. + * BT high priority traffic has higher priority than WLAN low/high priority traffic. + */ +#define WMI_PDEV_BE_PRIORITY_BIT (1<<0) +#define WMI_PDEV_BK_PRIORITY_BIT (1<<1) +#define WMI_PDEV_VI_PRIORITY_BIT (1<<2) +#define WMI_PDEV_VO_PRIORITY_BIT (1<<3) +#define WMI_PDEV_BEACON_PRIORITY_BIT (1<<4) +#define WMI_PDEV_MGMT_PRIORITY_BIT (1<<5) +#define WMI_PDEV_IS_BE_PRIORITY_SET(val) ((val) & WMI_PDEV_BE_PRIORITY_BIT) +#define WMI_PDEV_IS_BK_PRIORITY_SET(val) ((val) & WMI_PDEV_BK_PRIORITY_BIT) +#define WMI_PDEV_IS_VI_PRIORITY_SET(val) ((val) & WMI_PDEV_VI_PRIORITY_BIT) +#define WMI_PDEV_IS_VO_PRIORITY_SET(val) ((val) & WMI_PDEV_VO_PRIORITY_BIT) +#define WMI_PDEV_IS_BEACON_PRIORITY_SET(val) ((val) & WMI_PDEV_BEACON_PRIORITY_BIT) +#define WMI_PDEV_IS_MGMT_PRIORITY_SET(val) ((val) & WMI_PDEV_MGMT_PRIORITY_BIT) + +typedef enum wmi_coex_algo_type { + WMI_COEX_ALGO_UNCONS_FREERUN = 0, + WMI_COEX_ALGO_FREERUN = 1, + WMI_COEX_ALGO_OCS = 2, +} WMI_COEX_ALGO_TYPE; + +typedef enum wmi_coex_config_type { + WMI_COEX_CONFIG_PAGE_P2P_TDM = 1, /* config interval (arg1 BT, arg2 WLAN) for P2P + PAGE */ + WMI_COEX_CONFIG_PAGE_STA_TDM = 2, /* config interval (arg1 BT, arg2 WLAN) for STA + PAGE */ + WMI_COEX_CONFIG_PAGE_SAP_TDM = 3, /* config interval (arg1 BT, arg2 WLAN) for SAP + PAGE */ + WMI_COEX_CONFIG_DURING_WLAN_CONN = 4, /* config during WLAN connection */ + WMI_COEX_CONFIG_BTC_ENABLE = 5, /* config to enable/disable BTC */ + WMI_COEX_CONFIG_COEX_DBG = 6, /* config of COEX debug setting */ + WMI_COEX_CONFIG_PAGE_P2P_STA_TDM = 7, /* config interval (ms units) (arg1 BT, arg2 WLAN) for P2P + STA + PAGE */ + WMI_COEX_CONFIG_INQUIRY_P2P_TDM = 8, /* config interval (ms units) (arg1 BT, arg2 WLAN) for P2P + INQUIRY */ + WMI_COEX_CONFIG_INQUIRY_STA_TDM = 9, /* config interval (ms units) (arg1 BT, arg2 WLAN) for STA + INQUIRY */ + WMI_COEX_CONFIG_INQUIRY_SAP_TDM = 10, /* config interval (ms units) (arg1 BT, arg2 WLAN) for SAP + INQUIRY */ + WMI_COEX_CONFIG_INQUIRY_P2P_STA_TDM = 11, /* config interval (ms units) (arg1 BT, arg2 WLAN) for P2P + STA + INQUIRY */ + WMI_COEX_CONFIG_TX_POWER = 12, /* config wlan total tx power when bt coex (arg1 is wlan_tx_power_limit, in 0.5dbm units) */ + WMI_COEX_CONFIG_PTA_CONFIG = 13, /* config whether enable PTA and GPIO number (arg1 is pta_enable, arg2 is GPIO number used as /BT_ACTIVE/BT_PRIORITY/WLAN_DENY,8 bit for each) */ + WMI_COEX_CONFIG_AP_TDM = 14, /* config interval (arg1 duty cycle in ms, arg2 WLAN duration in ms) for AP */ + WMI_COEX_CONFIG_WLAN_SCAN_PRIORITY = 15, /* config to set WLAN priority during Off Channel Scan */ + WMI_COEX_CONFIG_WLAN_PKT_PRIORITY = 16, /* config to set WLAN priority for BE/BK/VO/VI/Beacon/Management frame */ + WMI_COEX_CONFIG_PTA_INTERFACE = 17, /* config PTA interface, + arg1 PTA num, + arg2 mode (2-wire/3-wire/PTA), + arg3 first slot time in microsec, + arg4 BT priority time in microsec, + arg5 PTA algorithm (WMI_COEX_ALGO_TYPE), + arg6 PTA priority */ + WMI_COEX_CONFIG_BTC_DUTYCYCLE = 18, /* config interval (ms units) (arg1 WLAN pause duration, arg2 WLAN unpause duration) for WLAN UL + BT Rx */ + WMI_COEX_CONFIG_HANDOVER_RSSI = 19, /* config to set WLAN RSSI (dBm units) at which device switches from Hybrid to TDD coex mode */ + WMI_COEX_CONFIG_PTA_BT_INFO = 20, /* get BT information, + arg1 BT info type: WMI_COEX_PTA_BT_INFO_TYPE_T, scan/advertise/connection info, + arg2-arg5: BT information parameters */ + WMI_COEX_CONFIG_SINK_WLAN_TDM = 21, /* config interval (ms units) (arg1 BT, arg2 WLAN) for A2DP SINK + WLAN */ + WMI_COEX_CONFIG_COEX_ENABLE_MCC_TDM = 22, /* config disable/enable COEX TDM for MCC */ +} WMI_COEX_CONFIG_TYPE; + +typedef struct { + A_UINT32 tlv_header; + A_UINT32 vdev_id; + A_UINT32 config_type; /* wmi_coex_config_type enum */ + A_UINT32 config_arg1; + A_UINT32 config_arg2; + A_UINT32 config_arg3; + A_UINT32 config_arg4; + A_UINT32 config_arg5; + A_UINT32 config_arg6; +} WMI_COEX_CONFIG_CMD_fixed_param; + +/** + * This command is sent from WLAN host driver to firmware to + * request firmware to enable/disable channel avoidance report + * to host. + * + */ +enum { + WMI_MWSCOEX_CHAN_AVD_RPT_DISALLOW = 0, + WMI_MWSCOEX_CHAN_AVD_RPT_ALLOW = 1 +}; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_WMI_CHAN_AVOID_RPT_ALLOW_CMD_fixed_param */ + /** Allow/disallow flag - see WMI_MWSCOEX_CHAN_AVD_RPT enum */ + A_UINT32 rpt_allow; +} WMI_CHAN_AVOID_RPT_ALLOW_CMD_fixed_param; + +/* + * Periodic channel stats WMI command structure + * WMI_SET_PERIODIC_CHANNEL_STATS_CONFIG_CMDID + */ +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_set_periodic_channel_stats_config_fixed_param */ + /** 1 = enable, 0 = disable */ + A_UINT32 enable; + /** periodic stats duration (units are milliseconds) */ + A_UINT32 stats_period; + /** pdev_id for identifying the MAC + * See macros starting with WMI_PDEV_ID_ for values. + */ + A_UINT32 pdev_id; +} wmi_set_periodic_channel_stats_config_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_pdev_wal_power_debug_cmd_fixed_param */ + /** pdev_id for identifying the MAC + * See macros starting with WMI_PDEV_ID_ for values. + */ + A_UINT32 pdev_id; + /* Identify the wlan module */ + A_UINT32 module_id; + /* Num of elements in the following args[] array */ + A_UINT32 num_args; +/** + * Following this structure are the TLVs: + * A_UINT32 args[]; + **/ +} wmi_pdev_wal_power_debug_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_pdev_set_reorder_timeout_val_cmd_fixed_param */ + /** + * @brief rx_timeout_pri - what rx reorder timeout (ms) to use for the AC + * @details + * Each WMM access category (voice, video, best-effort, background) + * will have its own timeout value to dictate how long to wait for + * missing rx MPDUs to arrive before releasing subsequent MPDUs that + * have already been received. + * This parameter specifies the timeout in milliseconds for each + * access category. + * The array elements are indexed by the WMI_AC enum to identify + * which array element corresponds to which AC / traffic type. + */ + A_UINT32 rx_timeout_pri[WMI_AC_MAX]; +} wmi_pdev_set_reorder_timeout_val_cmd_fixed_param; + +/** + * wlan stats shall be understood as per period. + * Generally, it is reported periodically based on the period specified by host. + * But if the variation of one stats of compared to the + * pervious notification exceeds a threshold, + * FW will report the wlan stats immediately. + * The values of the stats becomes the new reference to compute variations. + * This threshold can be a global setting or per category. + * Host can enable/disable the mechanism for any stats per bitmap. + * TX/RX thresholds (percentage value) are shared across ACs, + * and TX/RX stats comprisons are processed per AC of each peer. + * For example, if bit 0 (stand for tx_mpdus) of tx_thresh_bitmap is set to 1, + * and the detailed tx_mpdus threshold value is set to 10%, + * suppose tx_mpdus value of BE of peer 0 is 100 in first period, + * and it reaches 110 during the second period, + * FW will generate and send out a wlan stats event immediately. + */ +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_pdev_set_stats_threshold_cmd_fixed_param */ + /** Indicate if threshold mechnism is enabled or disabled. + * It is disabled by default. + * Host can enable and disable it dynamically. + */ + A_UINT32 enable_thresh; + /** use_thresh_bitmap equals 0 means gbl_thresh is used. + * when use_thresh_bitmap equals 1, ignore gbl_thresh and use stats bitmap indicated thresholds. + */ + A_UINT32 use_thresh_bitmap; + /** global threshold, valid when use_thresh_bitmap equals 0. + * It takes effect for all counters. + * If use_thresh_bitmap ==0 && gbl_thresh == 0, disable threshold mechanism. + */ + A_UINT32 gbl_thresh; + /** Enable/disable bitmap for threshold mechanism of CCA stats */ + A_UINT32 cca_thresh_enable_bitmap; + /** Enable/disable bitmap for threshold mechanism of signal stats */ + A_UINT32 signal_thresh_enable_bitmap; + /** Enable/disable bitmap for threshold mechanism of TX stats */ + A_UINT32 tx_thresh_enable_bitmap; + /** Enable/disable bitmap for threshold mechanism of RX stats */ + A_UINT32 rx_thresh_enable_bitmap; + /* This TLV is followed by TLVs below: + * wmi_chan_cca_stats_thresh cca_thresh; + * wmi_peer_signal_stats_thresh signal_thresh; + * wmi_tx_stats_thresh tx_thresh; + * wmi_rx_stats_thresh rx_thresh; + */ +} wmi_pdev_set_stats_threshold_cmd_fixed_param; + +typedef enum { + WMI_REQUEST_WLAN_TX_STAT = 0x01, + WMI_REQUEST_WLAN_RX_STAT = 0x02, + WMI_REQUEST_WLAN_CCA_STAT = 0x04, + WMI_REQUEST_WLAN_SIGNAL_STAT = 0x08, +} wmi_wlan_stats_id; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_request_wlan_stats_cmd_fixed_param */ + wmi_wlan_stats_id stats_id; +} wmi_request_wlan_stats_cmd_fixed_param; + +typedef enum { + WMI_REQUEST_ONE_PEER_STATS_INFO = 0x01, /* request stats of one specified peer */ + WMI_REQUEST_VDEV_ALL_PEER_STATS_INFO = 0x02, /* request stats of all peers belong to specified VDEV */ +} wmi_peer_stats_info_request_type; + +/** It is required to issue WMI_PDEV_PARAM_PEER_STATS_INFO_ENABLE + * (with a non-zero value) before issuing the first REQUEST_PEER_STATS_INFO. + */ +typedef struct { + /** TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_request_peer_stats_info_cmd_fixed_param */ + A_UINT32 tlv_header; + /** request_type to indicate if only stats of + * one peer or all peers of the VDEV are requested, + * see wmi_peer_stats_info_request_type. + */ + A_UINT32 request_type; + /** VDEV identifier */ + A_UINT32 vdev_id; + /** this peer_macaddr is only used if request_type == ONE_PEER_STATS_INFO */ + wmi_mac_addr peer_macaddr; + /** flag to indicate if FW needs to reset requested peers stats */ + A_UINT32 reset_after_request; +} wmi_request_peer_stats_info_cmd_fixed_param; + +typedef enum { + WMI_REQUEST_ONE_RADIO_CHAN_STATS = 0x01, /* request stats of one specified channel */ + WMI_REQUEST_ALL_RADIO_CHAN_STATS = 0x02, /* request stats of all channels */ +} wmi_radio_chan_stats_request_type; + +/** It is required to issue WMI_PDEV_PARAM_RADIO_CHAN_STATS_ENABLE + * (with a non-zero value) before issuing the first REQUEST_RADIO_CHAN_STATS. + */ +typedef struct { + /** TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_request_radio_chan_stats_cmd_fixed_param */ + A_UINT32 tlv_header; + /** request_type to indicate if only stats of + * one channel or all channels are requested, + * see wmi_radio_chan_stats_request_type. + */ + A_UINT32 request_type; + /** Frequency of channel whose stats is requested, + * only used when request_type == WMI_REQUEST_ONE_RADIO_CHAN_STATS + */ + A_UINT32 chan_mhz; + /** flag to indicate if FW needs to reset requested stats of specified channel/channels */ + A_UINT32 reset_after_request; +} wmi_request_radio_chan_stats_cmd_fixed_param; + +typedef struct { + /** TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_rmc_set_leader_cmd_fixed_param */ + A_UINT32 tlv_header; + /* VDEV identifier */ + A_UINT32 vdev_id; + /* Leader's mac address */ + wmi_mac_addr leader_mac_addr; +} wmi_rmc_set_leader_cmd_fixed_param; + +typedef struct { + /** TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_rmc_manual_leader_event_fixed_param */ + A_UINT32 tlv_header; + /* VDEV identifier */ + A_UINT32 vdev_id; + /* 0: success + * 1: selected leader not found in network, able to find using auto selection + * -1: error + * non zero value should be return to userspace in case of failure */ + A_INT32 status; + /* bssid of new leader */ + wmi_mac_addr leader_mac_addr; +} wmi_rmc_manual_leader_event_fixed_param; + +typedef enum { + WLAN_2G_CAPABILITY = 0x1, + WLAN_5G_CAPABILITY = 0x2, +} WLAN_BAND_CAPABILITY; + +typedef enum wmi_hw_mode_config_type { + WMI_HW_MODE_SINGLE = 0, /* Only one PHY is active. */ + WMI_HW_MODE_DBS = 1, /* Both PHYs are active in different bands, one in 2G and another in 5G. */ + WMI_HW_MODE_SBS_PASSIVE = 2, /* Both PHYs are in passive mode (only rx) in same band; no tx allowed. */ + WMI_HW_MODE_SBS = 3, /* Both PHYs are active in the same band. + * Support for both PHYs within one band is planned for 5G only + * (as indicated in WMI_MAC_PHY_CAPABILITIES), + * but could be extended to other bands in the future. + * The separation of the band between the two PHYs needs to be communicated separately. + */ + WMI_HW_MODE_DBS_SBS = 4, /* 3 PHYs, with 2 on the same band doing SBS + * as in WMI_HW_MODE_SBS, and 3rd on the other band + */ +} WMI_HW_MODE_CONFIG_TYPE; + +#define WMI_SUPPORT_11B_GET(flags) WMI_GET_BITS(flags, 0, 1) +#define WMI_SUPPORT_11B_SET(flags, value) WMI_SET_BITS(flags, 0, 1, value) + +#define WMI_SUPPORT_11G_GET(flags) WMI_GET_BITS(flags, 1, 1) +#define WMI_SUPPORT_11G_SET(flags, value) WMI_SET_BITS(flags, 1, 1, value) + +#define WMI_SUPPORT_11A_GET(flags) WMI_GET_BITS(flags, 2, 1) +#define WMI_SUPPORT_11A_SET(flags, value) WMI_SET_BITS(flags, 2, 1, value) + +#define WMI_SUPPORT_11N_GET(flags) WMI_GET_BITS(flags, 3, 1) +#define WMI_SUPPORT_11N_SET(flags, value) WMI_SET_BITS(flags, 3, 1, value) + +#define WMI_SUPPORT_11AC_GET(flags) WMI_GET_BITS(flags, 4, 1) +#define WMI_SUPPORT_11AC_SET(flags, value) WMI_SET_BITS(flags, 4, 1, value) + +#define WMI_SUPPORT_11AX_GET(flags) WMI_GET_BITS(flags, 5, 1) +#define WMI_SUPPORT_11AX_SET(flags, value) WMI_SET_BITS(flags, 5, 1, value) + +#define WMI_MAX_MUBFEE_GET(flags) WMI_GET_BITS(flags, 28, 4) +#define WMI_MAX_MUBFEE_SET(flags, value) WMI_SET_BITS(flags, 28, 4, value) + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_WMI_MAC_PHY_CAPABILITIES */ + /* hw_mode_id - identify a particular set of HW characteristics, as specified + * by the subsequent fields. WMI_MAC_PHY_CAPABILITIES element must be mapped + * to its parent WMI_HW_MODE_CAPABILITIES element using hw_mode_id. + * No particular ordering of WMI_MAC_PHY_CAPABILITIES elements should be assumed, + * though in practice the elements may always be ordered by hw_mode_id */ + A_UINT32 hw_mode_id; + /* pdev_id starts with 1. pdev_id 1 => phy_id 0, pdev_id 2 => phy_id 1 */ + A_UINT32 pdev_id; + /* phy id. Starts with 0 */ + A_UINT32 phy_id; + /* supported modulations and number of MU beamformees */ + union { + struct { + A_UINT32 supports_11b:1, + supports_11g:1, + supports_11a:1, + supports_11n:1, + supports_11ac:1, + supports_11ax:1, + + unused: 22, + + max_mubfee: 4; /* max MU beamformees supported per MAC */ + }; + A_UINT32 supported_flags; + }; + /* supported bands, enum WLAN_BAND_CAPABILITY */ + A_UINT32 supported_bands; + /* ampdu density 0 for no restriction, 1 for 1/4 us, 2 for 1/2 us, + * 3 for 1 us,4 for 2 us, 5 for 4 us, 6 for 8 us,7 for 16 us */ + A_UINT32 ampdu_density; + /* max bw supported 2G, enum wmi_channel_width */ + A_UINT32 max_bw_supported_2G; + /* WMI HT Capability, WMI_HT_CAP defines */ + A_UINT32 ht_cap_info_2G; + /* VHT capability info field of 802.11ac, WMI_VHT_CAP defines */ + A_UINT32 vht_cap_info_2G; + /* VHT Supported MCS Set field Rx/Tx same + * The max VHT-MCS for n SS subfield (where n = 1,...,8) is encoded as follows + * - 0 indicates support for VHT-MCS 0-7 for n spatial streams + * - 1 indicates support for VHT-MCS 0-8 for n spatial streams + * - 2 indicates support for VHT-MCS 0-9 for n spatial streams + * - 3 indicates that n spatial streams is not supported */ + A_UINT32 vht_supp_mcs_2G; + /*HE capability info field of 802.11ax, WMI_HE_CAP defines */ + A_UINT32 he_cap_info_2G; + /* HE Supported MCS Set field Rx/Tx same + * - 3 bits are used for each NSS chain.Max of 8 NSS can be encoded with + * bit 2-0 indicating max HE MCS of NSS1 + * bit 5-3 indicating max HE MCS of NSS2 and so on + * - The max HE-MCS for n SS subfield (where n = 1,...,8) is encoded as follows + * - 0 indicates support for VHT-MCS 0-7 for n spatial streams + * - 1 indicates support for VHT-MCS 0-8 for n spatial streams + * - 2 indicates support for VHT-MCS 0-9 for n spatial streams + * - 3 indicates support for VHT-MCS 0-10 for n spatial streams + * - 4 indicates support for VHT-MCS 0-11 for n spatial streams + * - 5-6 reserved + * - 7 indicates that n spatial streams is not supported + * - WMI_HE_MAX_MCS_4_SS_MASK macro can be used for encoding this info + */ + A_UINT32 he_supp_mcs_2G; + /* Valid Transmit chain mask */ + A_UINT32 tx_chain_mask_2G; + /* Valid Receive chain mask */ + A_UINT32 rx_chain_mask_2G; + /* max bw supported 5G, enum wmi_channel_width */ + A_UINT32 max_bw_supported_5G; + /* WMI HT Capability, WMI_HT_CAP defines */ + A_UINT32 ht_cap_info_5G; + /* VHT capability info field of 802.11ac, WMI_VHT_CAP defines */ + A_UINT32 vht_cap_info_5G; + /* VHT Supported MCS Set field Rx/Tx same + * The max VHT-MCS for n SS subfield (where n = 1,...,8) is encoded as follows + * - 0 indicates support for VHT-MCS 0-7 for n spatial streams + * - 1 indicates support for VHT-MCS 0-8 for n spatial streams + * - 2 indicates support for VHT-MCS 0-9 for n spatial streams + * - 3 indicates that n spatial streams is not supported */ + A_UINT32 vht_supp_mcs_5G; + /*HE capability info field of 802.11ax, WMI_HE_CAP defines */ + A_UINT32 he_cap_info_5G; + /* HE Supported MCS Set field Rx/Tx same + * - 3 bits are used for each NSS chain.Max of 8 NSS can be encoded with + * bit 2-0 indicating max HE MCS of NSS1 + * bit 5-3 indicating max HE MCS of NSS2 and so on + * - The max HE-MCS for n SS subfield (where n = 1,...,8) is encoded as follows + * - 0 indicates support for VHT-MCS 0-7 for n spatial streams + * - 1 indicates support for VHT-MCS 0-8 for n spatial streams + * - 2 indicates support for VHT-MCS 0-9 for n spatial streams + * - 3 indicates support for VHT-MCS 0-10 for n spatial streams + * - 4 indicates support for VHT-MCS 0-11 for n spatial streams + * - 5-6 reserved + * - 7 indicates that n spatial streams is not supported + * - WMI_HE_MAX_MCS_4_SS_MASK macro can be used for encoding this info + */ + A_UINT32 he_supp_mcs_5G; + /* Valid Transmit chain mask */ + A_UINT32 tx_chain_mask_5G; + /* Valid Receive chain mask */ + A_UINT32 rx_chain_mask_5G; + /* HE capability phy field of 802.11ax, WMI_HE_CAP defines */ + A_UINT32 he_cap_phy_info_2G[WMI_MAX_HECAP_PHY_SIZE]; + A_UINT32 he_cap_phy_info_5G[WMI_MAX_HECAP_PHY_SIZE]; + wmi_ppe_threshold he_ppet2G; + wmi_ppe_threshold he_ppet5G; + /* chainmask table to be used for the MAC */ + A_UINT32 chainmask_table_id; +} WMI_MAC_PHY_CAPABILITIES; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_WMI_HW_MODE_CAPABILITIES */ + /* hw_mode_id - identify a particular set of HW characteristics, + * as specified by the subsequent fields */ + A_UINT32 hw_mode_id; + /* BIT0 represents phy_id 0, BIT1 represent phy_id 1 and so on + * number of bits set in phy_id_map represents number of WMI_MAC_PHY_CAPABILITIES TLV's + * one for each active PHY for current HW mode identified by hw_mode_id. For example for + * DBS/SBS mode there will be 2 WMI_MAC_PHY_CAPABILITIES TLVs and for single MAC modes it + * will be 1 WMI_MAC_PHY_CAPABILITIES TLVs */ + A_UINT32 phy_id_map; + /* hw_mode_config_type + * Identify a particular type of HW mode such as SBS, DBS etc. + * Refer to WMI_HW_MODE_CONFIG_TYPE values. + */ + A_UINT32 hw_mode_config_type; +} WMI_HW_MODE_CAPABILITIES; + +/* + * The following macros are for the bitfields witihin the supported flags field + * of WMI_MAC_PHY_CHAINMASK_CAPABILITY: + * Capabilities for the chainmask + */ + +#define WMI_SUPPORT_CHAN_WIDTH_20_GET(flags) WMI_GET_BITS(flags, 0, 1) +#define WMI_SUPPORT_CHAN_WIDTH_20_SET(flags, value) WMI_SET_BITS(flags, 0, 1, value) + +#define WMI_SUPPORT_CHAN_WIDTH_40_GET(flags) WMI_GET_BITS(flags, 1, 1) +#define WMI_SUPPORT_CHAN_WIDTH_40_SET(flags, value) WMI_SET_BITS(flags, 1, 1, value) + +#define WMI_SUPPORT_CHAN_WIDTH_80_GET(flags) WMI_GET_BITS(flags, 2, 1) +#define WMI_SUPPORT_CHAN_WIDTH_80_SET(flags, value) WMI_SET_BITS(flags, 2, 1, value) + +#define WMI_SUPPORT_CHAN_WIDTH_160_GET(flags) WMI_GET_BITS(flags, 3, 1) +#define WMI_SUPPORT_CHAN_WIDTH_160_SET(flags, value) WMI_SET_BITS(flags, 3, 1, value) + +#define WMI_SUPPORT_CHAN_WIDTH_80P80_GET(flags) WMI_GET_BITS(flags, 4, 1) +#define WMI_SUPPORT_CHAN_WIDTH_80P80_SET(flags, value) WMI_SET_BITS(flags, 4, 1, value) + +#define WMI_SUPPORT_CHAIN_MASK_2G_GET(flags) WMI_GET_BITS(flags, 27, 1) +#define WMI_SUPPORT_CHAIN_MASK_2G_SET(flags, value) WMI_SET_BITS(flags, 27, 1, value) + +#define WMI_SUPPORT_CHAIN_MASK_5G_GET(flags) WMI_GET_BITS(flags, 28, 1) +#define WMI_SUPPORT_CHAIN_MASK_5G_SET(flags, value) WMI_SET_BITS(flags, 28, 1, value) + +#define WMI_SUPPORT_CHAIN_MASK_TX_GET(flags) WMI_GET_BITS(flags, 29, 1) +#define WMI_SUPPORT_CHAIN_MASK_TX_SET(flags, value) WMI_SET_BITS(flags, 29, 1, value) + +#define WMI_SUPPORT_CHAIN_MASK_RX_GET(flags) WMI_GET_BITS(flags, 30, 1) +#define WMI_SUPPORT_CHAIN_MASK_RX_SET(flags, value) WMI_SET_BITS(flags, 30, 1, value) + +#define WMI_SUPPORT_CHAIN_MASK_ADFS_GET(flags) WMI_GET_BITS(flags, 31, 1) +#define WMI_SUPPORT_CHAIN_MASK_ADFS_SET(flags, value) WMI_SET_BITS(flags, 31, 1, value) + +/** Definition of valid chainmask and associated capabilities */ +typedef struct { + A_UINT32 tlv_header;/* TLV tag and len; tag equals WMITLV_TAG_STRUC_WMI_MAC_PHY_CHAINMASK_CAPABILITY */ + /* supported flags: Capabilities for this chianmask*/ + union { + struct { + A_UINT32 supports_chan_width_20:1, + supports_chan_width_40:1, + supports_chan_width_80:1, + supports_chan_width_160:1, + supports_chan_width_80P80:1, + reserved:22, /* bits 26:5 */ + chain_mask_2G:1, + chain_mask_5G:1, + chain_mask_tx:1, + chain_mask_rx:1, + supports_aDFS:1; /* agile DFS */ + }; + A_UINT32 supported_flags; + }; + A_UINT32 chainmask; +} WMI_MAC_PHY_CHAINMASK_CAPABILITY; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_WMI_MAC_PHY_CHAINMASK_COMBO */ + A_UINT32 chainmask_table_id; + /* Number of vaild Chainmask in the table */ + A_UINT32 num_valid_chainmask; +/* + * This TLV is followed by the below TLVs: + * WMI_MAC_PHY_CHAINMASK_CAPABILITY mac_phy_chainmask_caps[num_valid_chainmask] + */ +} WMI_MAC_PHY_CHAINMASK_COMBO; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_WMI_SOC_MAC_PHY_HW_MODE_CAPS */ + /* num HW modes */ + A_UINT32 num_hw_modes; + /* number of unique chainmask combo tables */ + A_UINT32 num_chainmask_tables; +/* + * This TLV is followed by the below TLVs: + * + * WMI_HW_MODE_CAPABILITIES soc_hw_mode_caps[num_hw_modes] + * + * (intervening TLVs, e.g. HW_MODE_CAPS, MAC_PHY_CAPS, HAL_REG_CAPS) + * + * WMI_MAC_PHY_CHAINMASK_COMBO mac_phy_chainmask_combo[num_chainmask_tables] + * // number of chainmasks specified in mac_phy_chainmask_combo[0] + * WMI_MAC_PHY_CHAINMASK_CAPABILITY mac_phy_chainmask_caps[num_valid_chainmask0] + * // number of chainmasks specified in mac_phy_chainmask_combo[1] + * WMI_MAC_PHY_CHAINMASK_CAPABILITY mac_phy_chainmask_caps[num_valid_chainmask1] + * // number of chainmasks specified in mac_phy_chainmask_combo[2] + * WMI_MAC_PHY_CHAINMASK_CAPABILITY mac_phy_chainmask_caps[num_valid_chainmask2] + * etc. + */ +} WMI_SOC_MAC_PHY_HW_MODE_CAPS; + +/*Below are Reg caps per PHY. Please note PHY ID starts with 0.*/ +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_WMI_HAL_REG_CAPABILITIES_EXT */ + /* phy id */ + A_UINT32 phy_id; + /* regdomain value specified in EEPROM */ + A_UINT32 eeprom_reg_domain; + /* regdomain */ + A_UINT32 eeprom_reg_domain_ext; + /* CAP1 capabilities bit map, see REGDMN_CAP1_ defines */ + A_UINT32 regcap1; + /* REGDMN EEPROM CAP, see REGDMN_EEPROM_EEREGCAP_ defines */ + A_UINT32 regcap2; + /* REGDMN MODE, see REGDMN_MODE_ enum */ + A_UINT32 wireless_modes; + A_UINT32 low_2ghz_chan; + A_UINT32 high_2ghz_chan; + A_UINT32 low_5ghz_chan; + A_UINT32 high_5ghz_chan; +} WMI_HAL_REG_CAPABILITIES_EXT; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_WMI_SOC_HAL_REG_CAPABILITIES */ + A_UINT32 num_phy; + /* num_phy WMI_HAL_REG_CAPABILITIES_EXT TLV's */ +} WMI_SOC_HAL_REG_CAPABILITIES; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_WMI_OEM_DMA_RING_CAPABILITIES */ + A_UINT32 pdev_id; + A_UINT32 min_num_ptr; + /* Minimum number of pointers in the OEM DMA ring for this pdev */ + A_UINT32 min_buf_size; + /* Minimum size in bytes of each buffer in the OEM DMA ring */ + A_UINT32 min_buf_align; + /* Minimum alignment in bytes of each buffer in the OEM DMA ring */ +} WMI_OEM_DMA_RING_CAPABILITIES; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_scan_adaptive_dwell_parameters_tlv */ + /** global default adaptive dwell mode, used when WMI_SCAN_DWELL_MODE_DEFAULT */ + A_UINT32 default_adaptive_dwell_mode; + /** the weight to calculate the average low pass filter for channel congestion. 0-100 */ + A_UINT32 adapative_lpf_weight; + /** interval to monitor passive scan in msec */ + A_UINT32 passive_monitor_interval_ms; + /** % of wifi activity to switch from passive to active 0-100 */ + A_UINT32 wifi_activity_threshold_pct; +} wmi_scan_adaptive_dwell_parameters_tlv; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_scan_adaptive_dwell_config_fixed_param */ + /* globally enable/disable adaptive dwell */ + A_UINT32 enable; + /** pdev_id for identifying the MAC + * See macros starting with WMI_PDEV_ID_ for values. + * In non-DBDC case host should set it to 0 + */ + A_UINT32 pdev_id; +/** + * followed by TLV (tag length value) parameters array + * The TLV's are: + * wmi_scan_adaptive_dwell_parameters_tlv param[]; (0 or 1 elements) + */ +} wmi_scan_adaptive_dwell_config_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_scan_dbs_duty_cycle_param_tlv */ + /** module_id **/ + A_UINT32 module_id; + /** number of dbs scans */ + A_UINT32 num_dbs_scans; + /** number of non-dbs scans */ + A_UINT32 num_non_dbs_scans; +} wmi_scan_dbs_duty_cycle_tlv_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_scan_dbs_duty_cycle_fixed_param */ + /* number of scan client dutycycle param elements */ + A_UINT32 num_clients; + /** pdev_id for identifying the MAC + * See macros starting with WMI_PDEV_ID_ for values. + * In non-DBDC case host should set it to 0 + */ + A_UINT32 pdev_id; +/** + * followed by TLV (tag length value) parameters array + * The TLV's are: + * wmi_scan_selection_duty_cycle_tlv_param[num_clients]; + */ +} wmi_scan_dbs_duty_cycle_fixed_param; + +typedef struct { + /** TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_therm_throt_level_config_info */ + A_UINT32 tlv_header; + /** + * temperature sensor value in celsius when to exit to lower zone, + * this value can be lower than HWM of lower zone as zone overlapping + * is permitted by design to provide hysteresis + */ + A_UINT32 temp_lwm; + /** + * temperature sensor value in celsius when to exit to higher zone, + * this value can be higher than LWM of higher zone as zone overlapping + * is permitted by design to provide hysteresis + */ + A_UINT32 temp_hwm; + A_UINT32 dc_off_percent; /* duty cycle off percent 0-100. 0 means no off, 100 means no on (shutdown the phy) */ + /** Disable only the transmit queues in firmware that have lower priority than value defined by prio + * Prioritization: + * 0 = disable all data tx queues, No Prioritization defined + * 1 = disable BK tx queue + * 2 = disable BK+BE tx queues + * 3 = disable BK+BE+VI tx queues + */ + A_UINT32 prio; +} wmi_therm_throt_level_config_info; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_therm_throt_config_request_fixed_param */ + A_UINT32 pdev_id; /* config for each pdev */ + A_UINT32 enable; /* 0:disable, 1:enable */ + A_UINT32 dc; /* duty cycle in ms */ + A_UINT32 dc_per_event; /* how often (after how many duty cycles) the FW sends stats to host */ + A_UINT32 therm_throt_levels; /* Indicates the number of thermal zone configuration */ + /* + * Following this structure is the TLV: + * struct wmi_therm_throt_level_config_info therm_throt_level_config_info[therm_throt_levels]; + */ +} wmi_therm_throt_config_request_fixed_param; + +/** FW response with the stats event id for every pdev and zones */ +typedef struct { + /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_therm_throt_stats_event_fixed_param */ + A_UINT32 tlv_header; + A_UINT32 pdev_id; /* stats for corresponding pdev*/ + A_UINT32 temp; /* Temperature reading in celsius */ + A_UINT32 level; /* current thermal throttling level */ + A_UINT32 therm_throt_levels; /* number of levels in therm_throt_level_stats_info */ + /* This TLV is followed by another TLV of array of structs + * wmi_therm_throt_level_stats_info therm_throt_level_stats_info[therm_throt_levels]; + */ +} wmi_therm_throt_stats_event_fixed_param; + + + +typedef struct { + /** TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_therm_throt_level_stats_info */ + A_UINT32 tlv_header; + A_UINT32 level_count; /* count of each time thermal throttling entered this state */ + A_UINT32 dc_count; /* total number of duty cycles spent in this state. */ + /* this number increments by one each time we are in this state and we finish one full duty cycle. */ +} wmi_therm_throt_level_stats_info; + + + + +typedef enum { + WMI_REG_EXT_FCC_MIDBAND = 0, + WMI_REG_EXT_JAPAN_MIDBAND = 1, + WMI_REG_EXT_FCC_DFS_HT40 = 2, + WMI_REG_EXT_JAPAN_NONDFS_HT40 = 3, + WMI_REG_EXT_JAPAN_DFS_HT40 = 4, + WMI_REG_EXT_FCC_CH_144 = 5, +} WMI_REG_EXT_BITMAP; + +#ifdef WMI_CMD_STRINGS +static INLINE A_UINT8 *wmi_id_to_name(A_UINT32 wmi_command) +{ + switch (wmi_command) { + /* initialize the wlan sub system */ + WMI_RETURN_STRING(WMI_INIT_CMDID); + + /* Scan specific commands */ + + /* start scan request to FW */ + WMI_RETURN_STRING(WMI_START_SCAN_CMDID); + /* stop scan request to FW */ + WMI_RETURN_STRING(WMI_STOP_SCAN_CMDID); + /* full list of channels as defined by the regulatory + * that will be used by scanner */ + WMI_RETURN_STRING(WMI_SCAN_CHAN_LIST_CMDID); + /* overwrite default priority table in scan scheduler */ + WMI_RETURN_STRING(WMI_SCAN_SCH_PRIO_TBL_CMDID); + /* This command to adjust the priority and min.max_rest_time + * of an on ongoing scan request. + */ + WMI_RETURN_STRING(WMI_SCAN_UPDATE_REQUEST_CMDID); + + /* PDEV(physical device) specific commands */ + /* set regulatorty ctl id used by FW to determine the exact + * ctl power limits */ + WMI_RETURN_STRING(WMI_PDEV_SET_REGDOMAIN_CMDID); + /* set channel. mainly used for supporting monitor mode */ + WMI_RETURN_STRING(WMI_PDEV_SET_CHANNEL_CMDID); + /* set pdev specific parameters */ + WMI_RETURN_STRING(WMI_PDEV_SET_PARAM_CMDID); + /* enable packet log */ + WMI_RETURN_STRING(WMI_PDEV_PKTLOG_ENABLE_CMDID); + /* disable packet log*/ + WMI_RETURN_STRING(WMI_PDEV_PKTLOG_DISABLE_CMDID); + /* set wmm parameters */ + WMI_RETURN_STRING(WMI_PDEV_SET_WMM_PARAMS_CMDID); + /* set HT cap ie that needs to be carried probe requests + * HT/VHT channels */ + WMI_RETURN_STRING(WMI_PDEV_SET_HT_CAP_IE_CMDID); + /* set VHT cap ie that needs to be carried on probe + * requests on VHT channels */ + WMI_RETURN_STRING(WMI_PDEV_SET_VHT_CAP_IE_CMDID); + + /* Command to send the DSCP-to-TID map to the target */ + WMI_RETURN_STRING(WMI_PDEV_SET_DSCP_TID_MAP_CMDID); + /* set quiet ie parameters. primarily used in AP mode */ + WMI_RETURN_STRING(WMI_PDEV_SET_QUIET_MODE_CMDID); + /* Enable/Disable Green AP Power Save */ + WMI_RETURN_STRING(WMI_PDEV_GREEN_AP_PS_ENABLE_CMDID); + /* get TPC config for the current operating channel */ + WMI_RETURN_STRING(WMI_PDEV_GET_TPC_CONFIG_CMDID); + + /* set the base MAC address for the physical device before + * a VDEV is created. For firmware that does not support + * this feature and this command, the pdev MAC address will + * not be changed. */ + WMI_RETURN_STRING(WMI_PDEV_SET_BASE_MACADDR_CMDID); + + /* eeprom content dump , the same to bdboard data */ + WMI_RETURN_STRING(WMI_PDEV_DUMP_CMDID); + + /* VDEV(virtual device) specific commands */ + /* vdev create */ + WMI_RETURN_STRING(WMI_VDEV_CREATE_CMDID); + /* vdev delete */ + WMI_RETURN_STRING(WMI_VDEV_DELETE_CMDID); + /* vdev start request */ + WMI_RETURN_STRING(WMI_VDEV_START_REQUEST_CMDID); + /* vdev restart request (RX only, NO TX, used for CAC period)*/ + WMI_RETURN_STRING(WMI_VDEV_RESTART_REQUEST_CMDID); + /* vdev up request */ + WMI_RETURN_STRING(WMI_VDEV_UP_CMDID); + /* vdev stop request */ + WMI_RETURN_STRING(WMI_VDEV_STOP_CMDID); + /* vdev down request */ + WMI_RETURN_STRING(WMI_VDEV_DOWN_CMDID); + /* set a vdev param */ + WMI_RETURN_STRING(WMI_VDEV_SET_PARAM_CMDID); + /* set a key (used for setting per peer unicast + * and per vdev multicast) */ + WMI_RETURN_STRING(WMI_VDEV_INSTALL_KEY_CMDID); + + /* wnm sleep mode command */ + WMI_RETURN_STRING(WMI_VDEV_WNM_SLEEPMODE_CMDID); + WMI_RETURN_STRING(WMI_VDEV_WMM_ADDTS_CMDID); + WMI_RETURN_STRING(WMI_VDEV_WMM_DELTS_CMDID); + WMI_RETURN_STRING(WMI_VDEV_SET_WMM_PARAMS_CMDID); + WMI_RETURN_STRING(WMI_VDEV_SET_GTX_PARAMS_CMDID); + WMI_RETURN_STRING(WMI_VDEV_IPSEC_NATKEEPALIVE_FILTER_CMDID); + + WMI_RETURN_STRING(WMI_VDEV_PLMREQ_START_CMDID); + WMI_RETURN_STRING(WMI_VDEV_PLMREQ_STOP_CMDID); + WMI_RETURN_STRING(WMI_VDEV_TSF_TSTAMP_ACTION_CMDID); + WMI_RETURN_STRING(WMI_VDEV_SET_IE_CMDID); + + /* peer specific commands */ + + /** create a peer */ + WMI_RETURN_STRING(WMI_PEER_CREATE_CMDID); + /** delete a peer */ + WMI_RETURN_STRING(WMI_PEER_DELETE_CMDID); + /** flush specific tid queues of a peer */ + WMI_RETURN_STRING(WMI_PEER_FLUSH_TIDS_CMDID); + /** set a parameter of a peer */ + WMI_RETURN_STRING(WMI_PEER_SET_PARAM_CMDID); + /* set peer to associated state. will cary all parameters + * determined during assocication time */ + WMI_RETURN_STRING(WMI_PEER_ASSOC_CMDID); + /* add a wds (4 address ) entry. used only for testing + * WDS feature on AP products */ + WMI_RETURN_STRING(WMI_PEER_ADD_WDS_ENTRY_CMDID); + /* remove wds (4 address ) entry. used only for testing WDS + * feature on AP products */ + WMI_RETURN_STRING(WMI_PEER_REMOVE_WDS_ENTRY_CMDID); + /* set up mcast info for multicast to unicast conversion */ + WMI_RETURN_STRING(WMI_PEER_MCAST_GROUP_CMDID); + /* request peer info from FW to get PEER_INFO_EVENTID */ + WMI_RETURN_STRING(WMI_PEER_INFO_REQ_CMDID); + + /* beacon/management specific commands */ + + /* transmit beacon by reference. used for transmitting beacon + * on low latency interface like pcie */ + WMI_RETURN_STRING(WMI_BCN_TX_CMDID); + /* transmit beacon by value */ + WMI_RETURN_STRING(WMI_PDEV_SEND_BCN_CMDID); + /* set the beacon template. used in beacon offload mode to setup + * the common beacon template with the FW to be used by FW to + * generate beacons */ + WMI_RETURN_STRING(WMI_BCN_TMPL_CMDID); + /* set beacon filter with FW */ + WMI_RETURN_STRING(WMI_BCN_FILTER_RX_CMDID); + /* enable/disable filtering of probe requests in the firmware */ + WMI_RETURN_STRING(WMI_PRB_REQ_FILTER_RX_CMDID); + /* transmit management frame by value. will be deprecated */ + WMI_RETURN_STRING(WMI_MGMT_TX_CMDID); + /* set the probe response template. used in beacon offload mode + * to setup the common probe response template with the FW to + * be used by FW to generate probe responses */ + WMI_RETURN_STRING(WMI_PRB_TMPL_CMDID); + + /* commands to directly control ba negotiation directly from + * host. only used in test mode */ + + /* turn off FW Auto addba mode and let host control addba */ + WMI_RETURN_STRING(WMI_ADDBA_CLEAR_RESP_CMDID); + /* send add ba request */ + WMI_RETURN_STRING(WMI_ADDBA_SEND_CMDID); + WMI_RETURN_STRING(WMI_ADDBA_STATUS_CMDID); + /* send del ba */ + WMI_RETURN_STRING(WMI_DELBA_SEND_CMDID); + /* set add ba response will be used by FW to generate + * addba response*/ + WMI_RETURN_STRING(WMI_ADDBA_SET_RESP_CMDID); + /* send single VHT MPDU with AMSDU */ + WMI_RETURN_STRING(WMI_SEND_SINGLEAMSDU_CMDID); + + /* Station power save specific config */ + /* enable/disable station powersave */ + WMI_RETURN_STRING(WMI_STA_POWERSAVE_MODE_CMDID); + /* set station power save specific parameter */ + WMI_RETURN_STRING(WMI_STA_POWERSAVE_PARAM_CMDID); + /* set station mimo powersave mode */ + WMI_RETURN_STRING(WMI_STA_MIMO_PS_MODE_CMDID); + + /* DFS-specific commands */ + /* enable DFS (radar detection)*/ + WMI_RETURN_STRING(WMI_PDEV_DFS_ENABLE_CMDID); + /* disable DFS (radar detection)*/ + WMI_RETURN_STRING(WMI_PDEV_DFS_DISABLE_CMDID); + /* enable DFS phyerr/parse filter offload */ + WMI_RETURN_STRING(WMI_DFS_PHYERR_FILTER_ENA_CMDID); + /* enable DFS phyerr/parse filter offload */ + WMI_RETURN_STRING(WMI_DFS_PHYERR_FILTER_DIS_CMDID); + + /* Roaming specific commands */ + /* set roam scan mode */ + WMI_RETURN_STRING(WMI_ROAM_SCAN_MODE); + /* set roam scan rssi threshold below which roam + * scan is enabled */ + WMI_RETURN_STRING(WMI_ROAM_SCAN_RSSI_THRESHOLD); + /* set roam scan period for periodic roam scan mode */ + WMI_RETURN_STRING(WMI_ROAM_SCAN_PERIOD); + /* set roam scan trigger rssi change threshold */ + WMI_RETURN_STRING(WMI_ROAM_SCAN_RSSI_CHANGE_THRESHOLD); + /* set roam AP profile */ + WMI_RETURN_STRING(WMI_ROAM_AP_PROFILE); + /* set channel list for roam scans */ + WMI_RETURN_STRING(WMI_ROAM_CHAN_LIST); + /* offload scan specific commands */ + /* set offload scan AP profile */ + WMI_RETURN_STRING(WMI_OFL_SCAN_ADD_AP_PROFILE); + /* remove offload scan AP profile */ + WMI_RETURN_STRING(WMI_OFL_SCAN_REMOVE_AP_PROFILE); + /* set offload scan period */ + WMI_RETURN_STRING(WMI_OFL_SCAN_PERIOD); + + /* P2P specific commands */ + /* set P2P device info. FW will used by FW to create P2P IE + * to be carried in probe response generated during p2p listen + * and for p2p discoverability */ + WMI_RETURN_STRING(WMI_P2P_DEV_SET_DEVICE_INFO); + /* enable/disable p2p discoverability on STA/AP VDEVs */ + WMI_RETURN_STRING(WMI_P2P_DEV_SET_DISCOVERABILITY); + /* set p2p ie to be carried in beacons generated by FW for GO */ + WMI_RETURN_STRING(WMI_P2P_GO_SET_BEACON_IE); + /* set p2p ie to be carried in probe response frames generated + * by FW for GO */ + WMI_RETURN_STRING(WMI_P2P_GO_SET_PROBE_RESP_IE); + /* set the vendor specific p2p ie data. + * FW will use this to parse the P2P NoA + * attribute in the beacons/probe responses received. + */ + WMI_RETURN_STRING(WMI_P2P_SET_VENDOR_IE_DATA_CMDID); + /* set the configure of p2p find offload */ + WMI_RETURN_STRING(WMI_P2P_DISC_OFFLOAD_CONFIG_CMDID); + /* set the vendor specific p2p ie data for p2p find offload */ + WMI_RETURN_STRING(WMI_P2P_DISC_OFFLOAD_APPIE_CMDID); + /* set the BSSID/device name pattern of p2p find offload */ + WMI_RETURN_STRING(WMI_P2P_DISC_OFFLOAD_PATTERN_CMDID); + /* set OppPS related parameters **/ + WMI_RETURN_STRING(WMI_P2P_SET_OPPPS_PARAM_CMDID); + + /* AP power save specific config + * set AP power save specific param */ + WMI_RETURN_STRING(WMI_AP_PS_PEER_PARAM_CMDID); + /* set AP UAPSD coex pecific param */ + WMI_RETURN_STRING(WMI_AP_PS_PEER_UAPSD_COEX_CMDID); + + /* Rate-control specific commands */ + WMI_RETURN_STRING(WMI_PEER_RATE_RETRY_SCHED_CMDID); + + /* WLAN Profiling commands. */ + WMI_RETURN_STRING(WMI_WLAN_PROFILE_TRIGGER_CMDID); + WMI_RETURN_STRING(WMI_WLAN_PROFILE_SET_HIST_INTVL_CMDID); + WMI_RETURN_STRING(WMI_WLAN_PROFILE_GET_PROFILE_DATA_CMDID); + WMI_RETURN_STRING(WMI_WLAN_PROFILE_ENABLE_PROFILE_ID_CMDID); + WMI_RETURN_STRING(WMI_WLAN_PROFILE_LIST_PROFILE_ID_CMDID); + + /* Suspend resume command Ids */ + WMI_RETURN_STRING(WMI_PDEV_SUSPEND_CMDID); + WMI_RETURN_STRING(WMI_PDEV_RESUME_CMDID); + + /* Beacon filter commands */ + /* add a beacon filter */ + WMI_RETURN_STRING(WMI_ADD_BCN_FILTER_CMDID); + /* remove a beacon filter */ + WMI_RETURN_STRING(WMI_RMV_BCN_FILTER_CMDID); + + /* WOW Specific WMI commands */ + /* add pattern for awake */ + WMI_RETURN_STRING(WMI_WOW_ADD_WAKE_PATTERN_CMDID); + /* deleta a wake pattern */ + WMI_RETURN_STRING(WMI_WOW_DEL_WAKE_PATTERN_CMDID); + /* enable/deisable wake event */ + WMI_RETURN_STRING(WMI_WOW_ENABLE_DISABLE_WAKE_EVENT_CMDID); + /* enable WOW */ + WMI_RETURN_STRING(WMI_WOW_ENABLE_CMDID); + /* host woke up from sleep event to FW. Generated in response + * to WOW Hardware event */ + WMI_RETURN_STRING(WMI_WOW_HOSTWAKEUP_FROM_SLEEP_CMDID); + + /* RTT measurement related cmd */ + /* reques to make an RTT measurement */ + WMI_RETURN_STRING(WMI_RTT_MEASREQ_CMDID); + /* reques to report a tsf measurement */ + WMI_RETURN_STRING(WMI_RTT_TSF_CMDID); + + /* spectral scan command */ + /* configure spectral scan */ + WMI_RETURN_STRING(WMI_VDEV_SPECTRAL_SCAN_CONFIGURE_CMDID); + /* enable/disable spectral scan and trigger */ + WMI_RETURN_STRING(WMI_VDEV_SPECTRAL_SCAN_ENABLE_CMDID); + + /* F/W stats */ + /* one time request for stats */ + WMI_RETURN_STRING(WMI_REQUEST_STATS_CMDID); + /* Push MCC Adaptive Scheduler Stats to Firmware */ + WMI_RETURN_STRING(WMI_MCC_SCHED_TRAFFIC_STATS_CMDID); + + /* ARP OFFLOAD REQUEST*/ + WMI_RETURN_STRING(WMI_SET_ARP_NS_OFFLOAD_CMDID); + + /* Proactive ARP Response Add Pattern Command*/ + WMI_RETURN_STRING(WMI_ADD_PROACTIVE_ARP_RSP_PATTERN_CMDID); + + /* Proactive ARP Response Del Pattern Command*/ + WMI_RETURN_STRING(WMI_DEL_PROACTIVE_ARP_RSP_PATTERN_CMDID); + + /* NS offload confid*/ + WMI_RETURN_STRING(WMI_NETWORK_LIST_OFFLOAD_CONFIG_CMDID); + + /* GTK offload Specific WMI commands */ + WMI_RETURN_STRING(WMI_GTK_OFFLOAD_CMDID); + + /* CSA offload Specific WMI commands */ + /* csa offload enable */ + WMI_RETURN_STRING(WMI_CSA_OFFLOAD_ENABLE_CMDID); + /* chan switch command */ + WMI_RETURN_STRING(WMI_CSA_OFFLOAD_CHANSWITCH_CMDID); + + /* Chatter commands */ + /* Change chatter mode of operation */ + WMI_RETURN_STRING(WMI_CHATTER_SET_MODE_CMDID); + /* chatter add coalescing filter command */ + WMI_RETURN_STRING(WMI_CHATTER_ADD_COALESCING_FILTER_CMDID); + /* chatter delete coalescing filter command */ + WMI_RETURN_STRING(WMI_CHATTER_DELETE_COALESCING_FILTER_CMDID); + /* chatter coalecing query command */ + WMI_RETURN_STRING(WMI_CHATTER_COALESCING_QUERY_CMDID); + + /* addba specific commands */ + /* start the aggregation on this TID */ + WMI_RETURN_STRING(WMI_PEER_TID_ADDBA_CMDID); + /* stop the aggregation on this TID */ + WMI_RETURN_STRING(WMI_PEER_TID_DELBA_CMDID); + + /* set station mimo powersave method */ + WMI_RETURN_STRING(WMI_STA_DTIM_PS_METHOD_CMDID); + /* Configure the Station UAPSD AC Auto Trigger Parameters */ + WMI_RETURN_STRING(WMI_STA_UAPSD_AUTO_TRIG_CMDID); + /* Configure the Keep Alive Parameters */ + WMI_RETURN_STRING(WMI_STA_KEEPALIVE_CMDID); + + /* Request ssn from target for a sta/tid pair */ + WMI_RETURN_STRING(WMI_BA_REQ_SSN_CMDID); + /* misc command group */ + /* echo command mainly used for testing */ + WMI_RETURN_STRING(WMI_ECHO_CMDID); + + /* !!IMPORTANT!! + * If you need to add a new WMI command to the + * WMI_RETURN_STRING(WMI_GRP_MISC) sub-group, + * please make sure you add it BEHIND + * WMI_RETURN_STRING(WMI_PDEV_UTF_CMDID); + * as we MUST have a fixed value here to maintain compatibility between + * UTF and the ART2 driver + */ + /* UTF WMI commands */ + WMI_RETURN_STRING(WMI_PDEV_UTF_CMDID); + + /* set debug log config */ + WMI_RETURN_STRING(WMI_DBGLOG_CFG_CMDID); + /* QVIT specific command id */ + WMI_RETURN_STRING(WMI_PDEV_QVIT_CMDID); + /* Factory Testing Mode request command + * used for integrated chipsets */ + WMI_RETURN_STRING(WMI_PDEV_FTM_INTG_CMDID); + /* set and get keepalive parameters command */ + WMI_RETURN_STRING(WMI_VDEV_SET_KEEPALIVE_CMDID); + WMI_RETURN_STRING(WMI_VDEV_GET_KEEPALIVE_CMDID); + /* For fw recovery test command */ + WMI_RETURN_STRING(WMI_FORCE_FW_HANG_CMDID); + /* Set Mcast/Bdcast filter */ + WMI_RETURN_STRING(WMI_SET_MCASTBCAST_FILTER_CMDID); + /* set thermal management params */ + WMI_RETURN_STRING(WMI_THERMAL_MGMT_CMDID); + WMI_RETURN_STRING(WMI_RSSI_BREACH_MONITOR_CONFIG_CMDID); + WMI_RETURN_STRING(WMI_LRO_CONFIG_CMDID); + WMI_RETURN_STRING(WMI_TRANSFER_DATA_TO_FLASH_CMDID); + WMI_RETURN_STRING(WMI_CONFIG_ENHANCED_MCAST_FILTER_CMDID); + WMI_RETURN_STRING(WMI_VDEV_WISA_CMDID); + WMI_RETURN_STRING(WMI_SCAN_ADAPTIVE_DWELL_CONFIG_CMDID); + WMI_RETURN_STRING(WMI_WOW_SET_ACTION_WAKE_UP_CMDID); + WMI_RETURN_STRING(WMI_MAWC_SENSOR_REPORT_IND_CMDID); + WMI_RETURN_STRING(WMI_ROAM_CONFIGURE_MAWC_CMDID); + WMI_RETURN_STRING(WMI_NLO_CONFIGURE_MAWC_CMDID); + WMI_RETURN_STRING(WMI_EXTSCAN_CONFIGURE_MAWC_CMDID); + /* GPIO Configuration */ + WMI_RETURN_STRING(WMI_GPIO_CONFIG_CMDID); + WMI_RETURN_STRING(WMI_GPIO_OUTPUT_CMDID); + + /* Txbf configuration command */ + WMI_RETURN_STRING(WMI_TXBF_CMDID); + + /* FWTEST Commands */ + WMI_RETURN_STRING(WMI_FWTEST_VDEV_MCC_SET_TBTT_MODE_CMDID); + /* set NoA descs */ + WMI_RETURN_STRING(WMI_FWTEST_P2P_SET_NOA_PARAM_CMDID); + + /* TDLS Configuration */ + /* enable/disable TDLS */ + WMI_RETURN_STRING(WMI_TDLS_SET_STATE_CMDID); + /* set tdls peer state */ + WMI_RETURN_STRING(WMI_TDLS_PEER_UPDATE_CMDID); + + /* Resmgr Configuration */ + /* Adaptive OCS is enabled by default in the FW. + * This command is used to disable FW based adaptive OCS. + */ + WMI_RETURN_STRING + (WMI_RESMGR_ADAPTIVE_OCS_ENABLE_DISABLE_CMDID); + /* set the requested channel time quota for the home channels */ + WMI_RETURN_STRING(WMI_RESMGR_SET_CHAN_TIME_QUOTA_CMDID); + /* set the requested latency for the home channels */ + WMI_RETURN_STRING(WMI_RESMGR_SET_CHAN_LATENCY_CMDID); + + /* STA SMPS Configuration */ + /* force SMPS mode */ + WMI_RETURN_STRING(WMI_STA_SMPS_FORCE_MODE_CMDID); + /* set SMPS parameters */ + WMI_RETURN_STRING(WMI_STA_SMPS_PARAM_CMDID); + + /* Wlan HB commands */ + /* enalbe/disable wlan HB */ + WMI_RETURN_STRING(WMI_HB_SET_ENABLE_CMDID); + /* set tcp parameters for wlan HB */ + WMI_RETURN_STRING(WMI_HB_SET_TCP_PARAMS_CMDID); + /* set tcp pkt filter for wlan HB */ + WMI_RETURN_STRING(WMI_HB_SET_TCP_PKT_FILTER_CMDID); + /* set udp parameters for wlan HB */ + WMI_RETURN_STRING(WMI_HB_SET_UDP_PARAMS_CMDID); + /* set udp pkt filter for wlan HB */ + WMI_RETURN_STRING(WMI_HB_SET_UDP_PKT_FILTER_CMDID); + + /* Wlan RMC commands*/ + /* enable/disable RMC */ + WMI_RETURN_STRING(WMI_RMC_SET_MODE_CMDID); + /* configure action frame period */ + WMI_RETURN_STRING(WMI_RMC_SET_ACTION_PERIOD_CMDID); + /* For debug/future enhancement purposes only, + * configures/finetunes RMC algorithms */ + WMI_RETURN_STRING(WMI_RMC_CONFIG_CMDID); + + /* WLAN MHF offload commands */ + /* enable/disable MHF offload */ + WMI_RETURN_STRING(WMI_MHF_OFFLOAD_SET_MODE_CMDID); + /* Plumb routing table for MHF offload */ + WMI_RETURN_STRING(WMI_MHF_OFFLOAD_PLUMB_ROUTING_TBL_CMDID); + + /* location scan commands */ + /* start batch scan */ + WMI_RETURN_STRING(WMI_BATCH_SCAN_ENABLE_CMDID); + /* stop batch scan */ + WMI_RETURN_STRING(WMI_BATCH_SCAN_DISABLE_CMDID); + /* get batch scan result */ + WMI_RETURN_STRING(WMI_BATCH_SCAN_TRIGGER_RESULT_CMDID); + /* OEM related cmd */ + WMI_RETURN_STRING(WMI_OEM_REQ_CMDID); + WMI_RETURN_STRING(WMI_OEM_REQUEST_CMDID); + /* NAN request cmd */ + WMI_RETURN_STRING(WMI_NAN_CMDID); + /* Modem power state cmd */ + WMI_RETURN_STRING(WMI_MODEM_POWER_STATE_CMDID); + WMI_RETURN_STRING(WMI_REQUEST_STATS_EXT_CMDID); + WMI_RETURN_STRING(WMI_OBSS_SCAN_ENABLE_CMDID); + WMI_RETURN_STRING(WMI_OBSS_SCAN_DISABLE_CMDID); + WMI_RETURN_STRING(WMI_PEER_GET_ESTIMATED_LINKSPEED_CMDID); + WMI_RETURN_STRING(WMI_ROAM_SCAN_CMD); + WMI_RETURN_STRING(WMI_PDEV_SET_LED_CONFIG_CMDID); + WMI_RETURN_STRING(WMI_HOST_AUTO_SHUTDOWN_CFG_CMDID); + WMI_RETURN_STRING(WMI_CHAN_AVOID_UPDATE_CMDID); + WMI_RETURN_STRING(WMI_COEX_CONFIG_CMDID); + WMI_RETURN_STRING(WMI_WOW_IOAC_ADD_KEEPALIVE_CMDID); + WMI_RETURN_STRING(WMI_WOW_IOAC_DEL_KEEPALIVE_CMDID); + WMI_RETURN_STRING(WMI_WOW_IOAC_ADD_WAKE_PATTERN_CMDID); + WMI_RETURN_STRING(WMI_WOW_IOAC_DEL_WAKE_PATTERN_CMDID); + WMI_RETURN_STRING(WMI_REQUEST_LINK_STATS_CMDID); + WMI_RETURN_STRING(WMI_START_LINK_STATS_CMDID); + WMI_RETURN_STRING(WMI_CLEAR_LINK_STATS_CMDID); + WMI_RETURN_STRING(WMI_GET_FW_MEM_DUMP_CMDID); + WMI_RETURN_STRING(WMI_LPI_MGMT_SNOOPING_CONFIG_CMDID); + WMI_RETURN_STRING(WMI_LPI_START_SCAN_CMDID); + WMI_RETURN_STRING(WMI_LPI_STOP_SCAN_CMDID); + WMI_RETURN_STRING(WMI_EXTSCAN_START_CMDID); + WMI_RETURN_STRING(WMI_EXTSCAN_STOP_CMDID); + WMI_RETURN_STRING(WMI_EXTSCAN_CONFIGURE_WLAN_CHANGE_MONITOR_CMDID); + WMI_RETURN_STRING(WMI_EXTSCAN_CONFIGURE_HOTLIST_MONITOR_CMDID); + WMI_RETURN_STRING(WMI_EXTSCAN_GET_CACHED_RESULTS_CMDID); + WMI_RETURN_STRING(WMI_EXTSCAN_GET_WLAN_CHANGE_RESULTS_CMDID); + WMI_RETURN_STRING(WMI_EXTSCAN_SET_CAPABILITIES_CMDID); + WMI_RETURN_STRING(WMI_EXTSCAN_GET_CAPABILITIES_CMDID); + WMI_RETURN_STRING(WMI_EXTSCAN_CONFIGURE_HOTLIST_SSID_MONITOR_CMDID); + WMI_RETURN_STRING(WMI_ROAM_SYNCH_COMPLETE); + WMI_RETURN_STRING(WMI_D0_WOW_ENABLE_DISABLE_CMDID); + WMI_RETURN_STRING(WMI_EXTWOW_ENABLE_CMDID); + WMI_RETURN_STRING(WMI_EXTWOW_SET_APP_TYPE1_PARAMS_CMDID); + WMI_RETURN_STRING(WMI_EXTWOW_SET_APP_TYPE2_PARAMS_CMDID); + WMI_RETURN_STRING(WMI_UNIT_TEST_CMDID); + WMI_RETURN_STRING(WMI_ROAM_SET_RIC_REQUEST_CMDID); + WMI_RETURN_STRING(WMI_PDEV_GET_TEMPERATURE_CMDID); + WMI_RETURN_STRING(WMI_SET_DHCP_SERVER_OFFLOAD_CMDID); + WMI_RETURN_STRING(WMI_TPC_CHAINMASK_CONFIG_CMDID); + WMI_RETURN_STRING(WMI_IPA_OFFLOAD_ENABLE_DISABLE_CMDID); + WMI_RETURN_STRING(WMI_SCAN_PROB_REQ_OUI_CMDID); + WMI_RETURN_STRING(WMI_TDLS_SET_OFFCHAN_MODE_CMDID); + WMI_RETURN_STRING(WMI_PDEV_SET_LED_FLASHING_CMDID); + WMI_RETURN_STRING(WMI_MDNS_OFFLOAD_ENABLE_CMDID); + WMI_RETURN_STRING(WMI_MDNS_SET_FQDN_CMDID); + WMI_RETURN_STRING(WMI_MDNS_SET_RESPONSE_CMDID); + WMI_RETURN_STRING(WMI_MDNS_GET_STATS_CMDID); + WMI_RETURN_STRING(WMI_ROAM_INVOKE_CMDID); + WMI_RETURN_STRING(WMI_SET_ANTENNA_DIVERSITY_CMDID); + WMI_RETURN_STRING(WMI_SAP_OFL_ENABLE_CMDID); + WMI_RETURN_STRING(WMI_APFIND_CMDID); + WMI_RETURN_STRING(WMI_PASSPOINT_LIST_CONFIG_CMDID); + WMI_RETURN_STRING(WMI_OCB_SET_SCHED_CMDID); + WMI_RETURN_STRING(WMI_OCB_SET_CONFIG_CMDID); + WMI_RETURN_STRING(WMI_OCB_SET_UTC_TIME_CMDID); + WMI_RETURN_STRING(WMI_OCB_START_TIMING_ADVERT_CMDID); + WMI_RETURN_STRING(WMI_OCB_STOP_TIMING_ADVERT_CMDID); + WMI_RETURN_STRING(WMI_OCB_GET_TSF_TIMER_CMDID); + WMI_RETURN_STRING(WMI_DCC_GET_STATS_CMDID); + WMI_RETURN_STRING(WMI_DCC_CLEAR_STATS_CMDID); + WMI_RETURN_STRING(WMI_DCC_UPDATE_NDL_CMDID); + WMI_RETURN_STRING(WMI_ROAM_FILTER_CMDID); + WMI_RETURN_STRING(WMI_ROAM_SUBNET_CHANGE_CONFIG_CMDID); + WMI_RETURN_STRING(WMI_DEBUG_MESG_FLUSH_CMDID); + WMI_RETURN_STRING(WMI_PEER_SET_RATE_REPORT_CONDITION_CMDID); + WMI_RETURN_STRING(WMI_SOC_SET_PCL_CMDID); + WMI_RETURN_STRING(WMI_SOC_SET_HW_MODE_CMDID); + WMI_RETURN_STRING(WMI_SOC_SET_DUAL_MAC_CONFIG_CMDID); + WMI_RETURN_STRING(WMI_WOW_ENABLE_ICMPV6_NA_FLT_CMDID); + WMI_RETURN_STRING(WMI_DIAG_EVENT_LOG_CONFIG_CMDID); + WMI_RETURN_STRING(WMI_PACKET_FILTER_CONFIG_CMDID); + WMI_RETURN_STRING(WMI_PACKET_FILTER_ENABLE_CMDID); + WMI_RETURN_STRING(WMI_SAP_SET_BLACKLIST_PARAM_CMDID); + WMI_RETURN_STRING(WMI_WOW_UDP_SVC_OFLD_CMDID); + WMI_RETURN_STRING(WMI_MGMT_TX_SEND_CMDID); + WMI_RETURN_STRING(WMI_SOC_SET_ANTENNA_MODE_CMDID); + WMI_RETURN_STRING(WMI_WOW_HOSTWAKEUP_GPIO_PIN_PATTERN_CONFIG_CMDID); + WMI_RETURN_STRING(WMI_AP_PS_EGAP_PARAM_CMDID); + WMI_RETURN_STRING(WMI_PMF_OFFLOAD_SET_SA_QUERY_CMDID); + WMI_RETURN_STRING(WMI_BPF_GET_CAPABILITY_CMDID); + WMI_RETURN_STRING(WMI_BPF_GET_VDEV_STATS_CMDID); + WMI_RETURN_STRING(WMI_BPF_SET_VDEV_INSTRUCTIONS_CMDID); + WMI_RETURN_STRING(WMI_BPF_DEL_VDEV_INSTRUCTIONS_CMDID); + WMI_RETURN_STRING(WMI_NDI_GET_CAP_REQ_CMDID); + WMI_RETURN_STRING(WMI_NDP_INITIATOR_REQ_CMDID); + WMI_RETURN_STRING(WMI_NDP_RESPONDER_REQ_CMDID); + WMI_RETURN_STRING(WMI_NDP_END_REQ_CMDID); + WMI_RETURN_STRING(WMI_PEER_UPDATE_WDS_ENTRY_CMDID); + WMI_RETURN_STRING(WMI_PEER_ADD_PROXY_STA_ENTRY_CMDID); + WMI_RETURN_STRING(WMI_PDEV_FIPS_CMDID); + WMI_RETURN_STRING(WMI_PDEV_SMART_ANT_ENABLE_CMDID); + WMI_RETURN_STRING(WMI_PDEV_SMART_ANT_SET_RX_ANTENNA_CMDID); + WMI_RETURN_STRING(WMI_PDEV_SET_ANTENNA_SWITCH_TABLE_CMDID); + WMI_RETURN_STRING(WMI_PDEV_SET_CTL_TABLE_CMDID); + WMI_RETURN_STRING(WMI_PDEV_SET_MIMOGAIN_TABLE_CMDID); + WMI_RETURN_STRING(WMI_PDEV_GET_TPC_CMDID); + WMI_RETURN_STRING(WMI_MIB_STATS_ENABLE_CMDID); + WMI_RETURN_STRING(WMI_PDEV_GET_ANI_CCK_CONFIG_CMDID); + WMI_RETURN_STRING(WMI_PDEV_GET_ANI_OFDM_CONFIG_CMDID); + WMI_RETURN_STRING(WMI_VDEV_RATEMASK_CMDID); + WMI_RETURN_STRING(WMI_VDEV_ATF_REQUEST_CMDID); + WMI_RETURN_STRING(WMI_VDEV_SET_DSCP_TID_MAP_CMDID); + WMI_RETURN_STRING(WMI_VDEV_FILTER_NEIGHBOR_RX_PACKETS_CMDID); + WMI_RETURN_STRING(WMI_VDEV_SET_QUIET_MODE_CMDID); + WMI_RETURN_STRING(WMI_PEER_SMART_ANT_SET_TX_ANTENNA_CMDID); + WMI_RETURN_STRING(WMI_PEER_SMART_ANT_SET_TRAIN_INFO_CMDID); + WMI_RETURN_STRING(WMI_PEER_SMART_ANT_SET_NODE_CONFIG_OPS_CMDID); + WMI_RETURN_STRING(WMI_PEER_ATF_REQUEST_CMDID); + WMI_RETURN_STRING(WMI_FWTEST_CMDID); + WMI_RETURN_STRING(WMI_QBOOST_CFG_CMDID); + WMI_RETURN_STRING(WMI_PDEV_GET_NFCAL_POWER_CMDID); + WMI_RETURN_STRING(WMI_PDEV_SET_PCL_CMDID); + WMI_RETURN_STRING(WMI_PDEV_SET_HW_MODE_CMDID); + WMI_RETURN_STRING(WMI_PDEV_SET_MAC_CONFIG_CMDID); + WMI_RETURN_STRING(WMI_PDEV_SET_ANTENNA_MODE_CMDID); + WMI_RETURN_STRING(WMI_ROAM_SET_MBO_PARAM_CMDID); + WMI_RETURN_STRING(WMI_CHAN_AVOID_RPT_ALLOW_CMDID); + WMI_RETURN_STRING(WMI_SET_PERIODIC_CHANNEL_STATS_CONFIG_CMDID); + WMI_RETURN_STRING(WMI_VDEV_SET_CUSTOM_AGGR_SIZE_CMDID); + WMI_RETURN_STRING(WMI_PDEV_WAL_POWER_DEBUG_CMDID); + WMI_RETURN_STRING(WMI_PEER_BWF_REQUEST_CMDID); + WMI_RETURN_STRING(WMI_DBGLOG_TIME_STAMP_SYNC_CMDID); + WMI_RETURN_STRING(WMI_P2P_LISTEN_OFFLOAD_START_CMDID); + WMI_RETURN_STRING(WMI_P2P_LISTEN_OFFLOAD_STOP_CMDID); + WMI_RETURN_STRING(WMI_PEER_REORDER_QUEUE_SETUP_CMDID); + WMI_RETURN_STRING(WMI_PEER_REORDER_QUEUE_REMOVE_CMDID); + WMI_RETURN_STRING(WMI_SET_MULTIPLE_MCAST_FILTER_CMDID); + WMI_RETURN_STRING(WMI_READ_DATA_FROM_FLASH_CMDID); + WMI_RETURN_STRING(WMI_PDEV_SET_REORDER_TIMEOUT_VAL_CMDID); + WMI_RETURN_STRING(WMI_PEER_SET_RX_BLOCKSIZE_CMDID); + WMI_RETURN_STRING(WMI_PDEV_SET_WAKEUP_CONFIG_CMDID); + WMI_RETURN_STRING(WMI_PDEV_GET_ANTDIV_STATUS_CMDID); + WMI_RETURN_STRING(WMI_PEER_ANTDIV_INFO_REQ_CMDID); + WMI_RETURN_STRING(WMI_MNT_FILTER_CMDID); + WMI_RETURN_STRING(WMI_PDEV_GET_CHIP_POWER_STATS_CMDID); + WMI_RETURN_STRING(WMI_COEX_GET_ANTENNA_ISOLATION_CMDID); + WMI_RETURN_STRING(WMI_PDEV_SET_STATS_THRESHOLD_CMDID); + WMI_RETURN_STRING(WMI_REQUEST_WLAN_STATS_CMDID); + WMI_RETURN_STRING(WMI_VDEV_ENCRYPT_DECRYPT_DATA_REQ_CMDID); + WMI_RETURN_STRING(WMI_REQUEST_PEER_STATS_INFO_CMDID); + WMI_RETURN_STRING(WMI_REQUEST_RADIO_CHAN_STATS_CMDID); + WMI_RETURN_STRING(WMI_ROAM_PER_CONFIG_CMDID); + WMI_RETURN_STRING(WMI_VDEV_ADD_MAC_ADDR_TO_RX_FILTER_CMDID); + WMI_RETURN_STRING(WMI_BPF_SET_VDEV_ACTIVE_MODE_CMDID); + WMI_RETURN_STRING(WMI_HW_DATA_FILTER_CMDID); + WMI_RETURN_STRING(WMI_PDEV_MULTIPLE_VDEV_RESTART_REQUEST_CMDID); + WMI_RETURN_STRING(WMI_LPI_OEM_REQ_CMDID); + WMI_RETURN_STRING(WMI_PDEV_UPDATE_PKT_ROUTING_CMDID); + WMI_RETURN_STRING(WMI_PDEV_CHECK_CAL_VERSION_CMDID); + WMI_RETURN_STRING(WMI_PDEV_SET_DIVERSITY_GAIN_CMDID); + WMI_RETURN_STRING(WMI_VDEV_SET_ARP_STAT_CMDID); + WMI_RETURN_STRING(WMI_VDEV_GET_ARP_STAT_CMDID); + WMI_RETURN_STRING(WMI_VDEV_GET_TX_POWER_CMDID); + WMI_RETURN_STRING(WMI_OFFCHAN_DATA_TX_SEND_CMDID); + WMI_RETURN_STRING(WMI_SET_INIT_COUNTRY_CMDID); + WMI_RETURN_STRING(WMI_SET_SCAN_DBS_DUTY_CYCLE_CMDID); + WMI_RETURN_STRING(WMI_THERM_THROT_SET_CONF_CMDID); + WMI_RETURN_STRING(WMI_OEM_DMA_RING_CFG_REQ_CMDID); + WMI_RETURN_STRING(WMI_PDEV_BSS_CHAN_INFO_REQUEST_CMDID); + WMI_RETURN_STRING(WMI_VDEV_LIMIT_OFFCHAN_CMDID); + } + + return "Invalid WMI cmd"; +} +#endif /* WMI_CMD_STRINGS */ + +/** WMI commands/events for the regulatory offload */ + +/** Host indicating current country code to FW */ +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_set_current_country_cmd_fixed_param */ + A_UINT32 pdev_id; + A_UINT32 new_alpha2; /** alpha2 characters representing the country code */ +} wmi_set_current_country_cmd_fixed_param; + +typedef enum { + WMI_COUNTRYCODE_ALPHA2, + WMI_COUNTRYCODE_COUNTRY_ID, + WMI_COUNTRYCODE_DOMAIN_CODE, +} WMI_COUNTRYCODE_TYPE; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_set_init_country_cmd_fixed_param */ + A_UINT32 pdev_id; + A_UINT32 countrycode_type; /* WMI_COUNTRYCODE_TYPE */ + union { + struct { + /* Three character for alpha2. The first two is ISO name for country the last one + present if it is indoor and out door. First char in bits 7:0 and second char in bits 15:8 ... */ + A_UINT32 alpha2:24, + unused:8; + }; + A_UINT32 country_id; /* Country ID */ + A_UINT32 domain_code; /* Domain code */ + } country_code; +} wmi_set_init_country_cmd_fixed_param; + +/* Freq units in MHz */ +#define WMI_REG_RULE_START_FREQ_GET(freq_info) WMI_GET_BITS(freq_info, 0, 16) +#define WMI_REG_RULE_START_FREQ_SET(freq_info, value) WMI_SET_BITS(freq_info, 0, 16, value) +#define WMI_REG_RULE_END_FREQ_GET(freq_info) WMI_GET_BITS(freq_info, 16, 16) +#define WMI_REG_RULE_END_FREQ_SET(freq_info, value) WMI_SET_BITS(freq_info, 16, 16, value) + +/* BW in MHz */ +#define WMI_REG_RULE_MAX_BW_GET(bw_pwr_info) WMI_GET_BITS(bw_pwr_info, 0, 16) +#define WMI_REG_RULE_MAX_BW_SET(bw_pwr_info, value) WMI_SET_BITS(bw_pwr_info, 0, 16, value) +/* regpower in dBm */ +#define WMI_REG_RULE_REG_POWER_GET(bw_pwr_info) WMI_GET_BITS(bw_pwr_info, 16, 8) +#define WMI_REG_RULE_REG_POWER_SET(bw_pwr_info, value) WMI_SET_BITS(bw_pwr_info, 16, 8, value) +/* antenna gain */ +#define WMI_REG_RULE_ANTENNA_GAIN_GET(bw_pwr_info) WMI_GET_BITS(bw_pwr_info, 24, 8) +#define WMI_REG_RULE_ANTENNA_GAIN_SET(bw_pwr_info, value) WMI_SET_BITS(bw_pwr_info, 24, 8, value) + +typedef enum { + WMI_REG_FLAG_CHAN_NO_IR = 0x0001, /* passive channel */ + WMI_REG_FLAG_CHAN_RADAR = 0x0002, /* dfs channel */ + WMI_REG_FLAG_CHAN_NO_OFDM = 0x0004, /* no ofdm channel */ + WMI_REG_FLAG_CHAN_INDOOR_ONLY = 0x0008, /* indoor only channel */ +} WMI_REGULATORY_FLAGS; + +#define WMI_REG_RULE_FLAGS_GET(flag_info) WMI_GET_BITS(flag_info, 0, 16) +#define WMI_REG_RULE_FLAGS_SET(flag_info, value) WMI_SET_BITS(flag_info, 0, 16, value) + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_regulatory_rule_struct */ + A_UINT32 freq_info; /* bits 15:0 = u16 start_freq, + * bits 31:16 = u16 end_freq + * (both in MHz units) */ + A_UINT32 bw_pwr_info; /* bits 15:0 = u16 max_bw (MHz units), + bits 23:16 = u8 reg_power (dBm units), + bits 31:24 = u8 ant_gain (dB units) */ + A_UINT32 flag_info; /* bits 15:0 = u16 flags, + bits 31:16 reserved */ +} wmi_regulatory_rule_struct; + +typedef enum { + WMI_REG_DFS_UNINIT_REGION = 0, + WMI_REG_DFS_FCC_REGION = 1, + WMI_REG_DFS_ETSI_REGION = 2, + WMI_REG_DFS_MKK_REGION = 3, + WMI_REG_DFS_CN_REGION = 4, + WMI_REG_DFS_KR_REGION = 5, + + /* Add new items above */ + WMI_REG_DFS_UNDEF_REGION = 0xFFFF, +} WMI_REG_DFS_REGION; + +typedef enum { + WMI_REGULATORY_PHYMODE_NO11A = 0x0001, /* NO 11A */ + WMI_REGULATORY_PHYMODE_NO11B = 0x0002, /* NO 11B */ + WMI_REGULATORY_PHYMODE_NO11G = 0x0004, /* NO 11G */ + WMI_REGULATORY_PHYMODE_NO11N = 0x0008, /* NO 11N */ + WMI_REGULATORY_PHYMODE_NO11AC = 0x0010, /* NO 11AC */ + WMI_REGULATORY_PHYMODE_NO11AX = 0x0020, /* NO 11AX */ +} WMI_REGULATORY_PHYBITMAP; + +typedef enum { + WMI_REG_SET_CC_STATUS_PASS = 0, + WMI_REG_CURRENT_ALPHA2_NOT_FOUND = 1, + WMI_REG_INIT_ALPHA2_NOT_FOUND = 2, + WMI_REG_SET_CC_CHANGE_NOT_ALLOWED = 3, + WMI_REG_SET_CC_STATUS_NO_MEMORY = 4, + WMI_REG_SET_CC_STATUS_FAIL = 5, +} WMI_REG_SET_CC_STATUS_CODE; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_reg_chan_list_cc_event_fixed_param */ + A_UINT32 status_code; /* WMI_REG_SET_CC_STATUS_CODE */ + A_UINT32 phy_id; + A_UINT32 alpha2; + A_UINT32 num_phy; + A_UINT32 country_id; + A_UINT32 domain_code; + A_UINT32 dfs_region; /* WMI_REG_DFS_REGION */ + A_UINT32 phybitmap; /* WMI_REGULATORY_PHYBITMAP */ + A_UINT32 min_bw_2g; /* BW in MHz */ + A_UINT32 max_bw_2g; /* BW in MHz */ + A_UINT32 min_bw_5g; /* BW in MHz */ + A_UINT32 max_bw_5g; /* BW in MHz */ + A_UINT32 num_2g_reg_rules; + A_UINT32 num_5g_reg_rules; +/* followed by wmi_regulatory_rule_struct TLV array. First 2G and then 5G */ +} wmi_reg_chan_list_cc_event_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_11d_scan_start_cmd_fixed_param */ + A_UINT32 vdev_id; + A_UINT32 scan_period_msec; /** scan duration in milli-seconds */ + A_UINT32 start_interval_msec; /** offset duration to start the scan in milli-seconds */ +} wmi_11d_scan_start_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_11d_scan_stop_cmd_fixed_param */ + A_UINT32 vdev_id; +} wmi_11d_scan_stop_cmd_fixed_param; + +/** FW indicating new current country code to Host */ +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_11d_new_country_event_fixed_param */ + A_UINT32 new_alpha2; /** alpha2 characters representing the country code */ +} wmi_11d_new_country_event_fixed_param; + +typedef struct { + /** TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_coex_get_antenna_isolation_cmd_fixed_param */ + A_UINT32 tlv_header; + /* Currently there are no parameters for this message. */ +} wmi_coex_get_antenna_isolation_cmd_fixed_param; + +typedef struct { + /** TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_coex_report_isolation_event_fixed_param */ + A_UINT32 tlv_header; + /** Antenna isolation value in dB units, none zero value is valid while 0 means failed to do isolation measurement or corresponding chain is not active. + * Currently the HW descriptor only supports 4 chains at most. + * Further isolation_chainX elements can be added in the future + * for additional chains, if needed. + */ + A_UINT32 isolation_chain0:8, /* [7:0], isolation value for chain 0 */ + isolation_chain1:8, /* [15:8], isolation value for chain 1 */ + isolation_chain2:8, /* [23:16], isolation value for chain 2 */ + isolation_chain3:8; /* [31:24], isolation value for chain 3 */ +} wmi_coex_report_isolation_event_fixed_param; + +typedef enum { + WMI_RCPI_MEASUREMENT_TYPE_AVG_MGMT = 1, + WMI_RCPI_MEASUREMENT_TYPE_AVG_DATA = 2, + WMI_RCPI_MEASUREMENT_TYPE_LAST_MGMT = 3, + WMI_RCPI_MEASUREMENT_TYPE_LAST_DATA = 4, +} wmi_rcpi_measurement_type; + +typedef struct { + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_request_rcpi_cmd_fixed_param */ + A_UINT32 tlv_header; + /* VDEV identifier */ + A_UINT32 vdev_id; + /* peer MAC address */ + wmi_mac_addr peer_macaddr; + /* measurement type - defined in enum wmi_rcpi_measurement_type */ + A_UINT32 measurement_type; +} wmi_request_rcpi_cmd_fixed_param; + +typedef struct { + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_update_rcpi_event_fixed_param */ + A_UINT32 tlv_header; + /* VDEV identifier */ + A_UINT32 vdev_id; + /* peer MAC address */ + wmi_mac_addr peer_macaddr; + /* measurement type - defined in enum wmi_rcpi_measurement_type */ + A_UINT32 measurement_type; + /* Measured RCPI in dBm of the peer requested by host */ + A_INT32 rcpi; + /** status + * 0 - Requested peer RCPI available + * 1 - Requested peer RCPI not available + */ + A_UINT32 status; +} wmi_update_rcpi_event_fixed_param; + +/* Definition of mask for various package id */ +#define WMI_PKGID_MASK_AUTO 0x00000080 + +typedef struct { + /** TLV tag and len; tag equals*/ + A_UINT32 tlv_header; + /** + * The value field is filled with WMI_PKGID_MASK values. + * Currently, the only flag used within values is + * WMI_PKGID_MASK_AUTO, where bit7=1 for automotive systems. + */ + A_UINT32 value; +} wmi_pkgid_event_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_vdev_add_mac_addr_to_rx_filter_cmd_fixed_params */ + A_UINT32 vdev_id; /* vdev id whose mac to be randomized */ + /* enable is set to 1 if mac randomization to be enabled */ + A_UINT32 enable; + /* randomization mac address if randomization is enabled */ + wmi_mac_addr mac_addr; + /* To get the PMAC from freq param */ + A_UINT32 freq; /* units in MHz */ +} wmi_vdev_add_mac_addr_to_rx_filter_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_vdev_add_mac_addr_to_rx_filter_event_fixed_params */ + A_UINT32 vdev_id; /* vdev of id whose mac address was randomized */ + A_UINT32 status; /* status is 1 if success and 0 if failed */ +} wmi_vdev_add_mac_addr_to_rx_filter_status_event_fixed_param; + +/* Definition of HW data filtering */ +typedef enum { + WMI_HW_DATA_FILTER_DROP_NON_ARP_BC = 0x01, + WMI_HW_DATA_FILTER_DROP_NON_ICMPV6_MC = 0x02, +} WMI_HW_DATA_FILTER_BITMAP_TYPE; + +typedef struct { + A_UINT32 tlv_header; + A_UINT32 vdev_id; + A_UINT32 enable; /* 1 . enable, 0- disable */ + A_UINT32 hw_filter_bitmap; /* see WMI_HW_DATA_FILTER_BITMAP_TYPE */ +} wmi_hw_data_filter_cmd_fixed_param; + +/* This command is used whenever host wants to restart multiple + * VDEVs using single command and the VDEV that are restarted will + * need to have same properties they had before restart except for the + * operating channel + */ +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_pdev_multiple_vdev_restart_request_cmd_fixed_param */ + /** pdev_id for identifying the MAC + * See macros starting with WMI_PDEV_ID_ for values. + * In non-DBDC case host should set it to 0 + */ + A_UINT32 pdev_id; + /** unique id identifying the module, generated by the caller */ + A_UINT32 requestor_id; + /** Disable H/W ack. + * During CAC, Our HW shouldn't ack directed frames + */ + A_UINT32 disable_hw_ack; + /* Determine the duration of CAC on the given channel 'chan' */ + A_UINT32 cac_duration_ms; + A_UINT32 num_vdevs; + + /* The TLVs follows this structure: + * A_UINT32 vdev_ids[]; <--- Array of VDEV ids. + * wmi_channel chan; <------ WMI channel + */ +} wmi_pdev_multiple_vdev_restart_request_cmd_fixed_param; + +typedef struct { + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_pdev_csa_switch_count_status_event_fixed_param */ + A_UINT32 tlv_header; + /** pdev_id for identifying the MAC + * See macros starting with WMI_PDEV_ID_ for values. + * In non-DBDC case host should set it to 0 + */ + A_UINT32 pdev_id; + /** CSA switch count value in the last transmitted beacon */ + A_UINT32 current_switch_count; + A_UINT32 num_vdevs; + + /* The TLVs follows this structure: + * A_UINT32 vdev_ids[]; <--- Array of VDEV ids. + */ +} wmi_pdev_csa_switch_count_status_event_fixed_param; + +/* Operation types for packet routing command */ +typedef enum { + WMI_PDEV_ADD_PKT_ROUTING, + WMI_PDEV_DEL_PKT_ROUTING, +} wmi_pdev_pkt_routing_op_code; + +/* Packet routing types based on specific data types */ +typedef enum { + WMI_PDEV_ROUTING_TYPE_ARP_IPV4, + WMI_PDEV_ROUTING_TYPE_NS_IPV6, + WMI_PDEV_ROUTING_TYPE_IGMP_IPV4, + WMI_PDEV_ROUTING_TYPE_MLD_IPV6, + WMI_PDEV_ROUTING_TYPE_DHCP_IPV4, + WMI_PDEV_ROUTING_TYPE_DHCP_IPV6, +} wmi_pdev_pkt_routing_type; + +/* This command shall be sent only when no VDEV is up. If the command is sent after any VDEV is up, target will ignore the command */ +typedef struct { + /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_pdev_update_pkt_routing_cmd_fixed_param */ + A_UINT32 tlv_header; + /** Identifies pdev on which routing needs to be applied */ + A_UINT32 pdev_id; + /** Indicates the routing operation type: add/delete */ + A_UINT32 op_code; /* wmi_pdev_pkt_routing_op_code */ + /** Bitmap of multiple pkt routing types for a given destination ring and meta data */ + A_UINT32 routing_type_bitmap; /* see wmi_pdev_pkt_routing_type */ + /** 5 bits [4:0] are used to specify the destination ring where the CCE matched + * packet needs to be routed. + */ + A_UINT32 dest_ring; + /** 16 bits [15:0] meta data can be passed to CCE. When the superrule matches, + * CCE copies this back in RX_MSDU_END_TLV. + */ + A_UINT32 meta_data; +} wmi_pdev_update_pkt_routing_cmd_fixed_param; + +typedef enum { + WMI_CALIBRATION_NO_FEATURE = 0, /* The board was calibrated with a meta which did not have this feature */ + WMI_CALIBRATION_OK, /* The calibration status is OK */ + WMI_CALIBRATION_NOT_OK, /* The calibration status is NOT OK */ +} WMI_CALIBRATION_STATUS; + +typedef struct { + A_UINT32 tlv_header; /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_pdev_check_cal_version_event_fixed_param */ + A_UINT32 software_cal_version; /* Current software level calibration data version */ + A_UINT32 board_cal_version; /* Calibration data version programmed on chip */ + A_UINT32 cal_status; /* filled with WMI_CALIBRATION_STATUS enum value */ + /** pdev_id for identifying the MAC + * See macros starting with WMI_PDEV_ID_ for values. + */ + A_UINT32 pdev_id; +} wmi_pdev_check_cal_version_event_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_pdev_check_cal_version_cmd_fixed_param */ + /** pdev_id for identifying the MAC + * See macros starting with WMI_PDEV_ID_ for values. + */ + A_UINT32 pdev_id; +} wmi_pdev_check_cal_version_cmd_fixed_param; + +typedef struct { + A_UINT32 tlv_header; /** TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_pdev_set_diversity_gain_cmd_fixed_param */ + /** Identifies pdev on which diversity gain to be applied */ + A_UINT32 pdev_id; + /** The number of spatial stream */ + A_UINT32 nss; + /** The number of gains */ + A_UINT32 num_gains; + /* + * This fixed_param TLV is followed by other TLVs: + * A_UINT8 diversity_gains[num_gains]; (gain is in dB units) + */ +} wmi_pdev_set_diversity_gain_cmd_fixed_param; + +/* flags for unit_test_event */ +#define WMI_UNIT_TEST_EVENT_FLAG_STATUS 0 /* 0 = success, 1 = fail */ +#define WMI_UNIT_TEST_EVENT_FLAG_DONE 1 /* 0 = not done, 1 = done */ + +/* from bit 2 to bit 31 are reserved */ + +#define WMI_SET_UNIT_TEST_EVENT_FLAG_STATUS_SUCCESS(flag) do { \ + (flag) |= (1 << WMI_UNIT_TEST_EVENT_FLAG_STATUS); \ + } while (0) + +#define WMI_SET_UNIT_TEST_EVENT_FLAG_STATUS_FAIL(flag) do { \ + (flag) &= ~(1 << WMI_UNIT_TEST_EVENT_FLAG_STATUS); \ + } while (0) + +#define WMI_GET_UNIT_TEST_EVENT_FLAG_STSTUS(flag) \ + ((flag) & (1 << WMI_UNIT_TEST_EVENT_FLAG_STATUS)) + +#define WMI_SET_UNIT_TEST_EVENT_FLAG_DONE(flag) do { \ + (flag) |= (1 << WMI_UNIT_TEST_EVENT_FLAG_DONE); \ + } while (0) + +#define WMI_CLR_UNIT_TEST_EVENT_FLAG_DONE(flag) do { \ + (flag) &= ~(1 << WMI_UNIT_TEST_EVENT_FLAG_DONE); \ + } while (0) + +#define WMI_GET_UNIT_TEST_EVENT_FLAG_DONE(flag) \ + ((flag) & (1 << WMI_UNIT_TEST_EVENT_FLAG_DONE)) + +typedef struct { + /* TLV tag and len; tag equals WMI_UNIT_TEST_EVENTID */ + A_UINT32 tlv_header; + /* unique id identifying the VDEV, generated by the caller */ + A_UINT32 vdev_id; + /* Identify the wlan module */ + A_UINT32 module_id; + /* unique id identifying the unit test cmd, generated by the caller */ + A_UINT32 diag_token; + /* flag for the status of the unit_test_cmd */ + A_UINT32 flag; + /* data length number of bytes for current dump */ + A_UINT32 payload_len; + /* TLV/Payload after this structure is sent in little endian + * format for the length mentioned in this structure. + * A_UINT8 payload[1]; + */ +} wmi_unit_test_event_fixed_param; + +/* ADD NEW DEFS HERE */ + + +/***************************************************************************** + * The following structures are deprecated. DO NOT USE THEM! + */ +/** Max number of channels in the schedule. */ +#define OCB_CHANNEL_MAX (5) + +/* NOTE: Make sure these data structures are identical to those +* defined in sirApi.h */ + +typedef struct +{ + /** Arbitration Inter-Frame Spacing. Range: 2-15 */ + A_UINT32 aifsn; + /** Contention Window minimum. Range: 1 - 10 */ + A_UINT32 cwmin; + /** Contention Window maximum. Range: 1 - 10 */ + A_UINT32 cwmax; +} wmi_qos_params_t; + +typedef struct +{ + /** Channel frequency in MHz */ + A_UINT32 chan_freq; + /** Channel duration in ms */ + A_UINT32 duration; + /** Start guard interval in ms */ + A_UINT32 start_guard_interval; + /** End guard interval in ms */ + A_UINT32 end_guard_interval; + /** Transmit power in dBm, range 0 - 23 */ + A_UINT32 tx_power; + /** Transmit datarate in Mbps */ + A_UINT32 tx_rate; + /** QoS parameters for each AC */ + wmi_qos_params_t qos_params[WLAN_MAX_AC]; + /** 1 to enable RX stats for this channel, 0 otherwise */ + A_UINT32 rx_stats; +} wmi_ocb_channel_t; + +typedef struct { + /** TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_ocb_set_sched_cmd_fixed_param */ + A_UINT32 tlv_header; + /* VDEV identifier */ + A_UINT32 vdev_id; + /** Number of valid channels in the channels array */ + A_UINT32 num_channels; + /** The array of channels */ + wmi_ocb_channel_t channels[OCB_CHANNEL_MAX]; + /** 1 to allow off-channel tx, 0 otherwise */ + A_UINT32 off_channel_tx; /* Not supported */ +} wmi_ocb_set_sched_cmd_fixed_param; + +typedef struct { + /** Return status. 0 for success, non-zero otherwise */ + A_UINT32 status; +} wmi_ocb_set_sched_event_fixed_param; + +/***************************************************************************** + * END DEPRECATED + */ + +/* ADD NEW DEFS ABOVE THIS DEPRECATED SECTION */ + + +#ifdef __cplusplus +} +#endif + +#endif /*_WMI_UNIFIED_H_*/ + +/**@}*/ diff --git a/drivers/staging/fw-api/fw/wmi_version.h b/drivers/staging/fw-api/fw/wmi_version.h new file mode 100755 index 0000000000000000000000000000000000000000..c66848b0e56152155985fe434b49bb40f579ed78 --- /dev/null +++ b/drivers/staging/fw-api/fw/wmi_version.h @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * IMPORTANT NOTE: For all change to WMI Interface, the ABI version number _must_ be updated. + */ +/** Major version number is incremented when there are significant changes to WMI Interface that break compatibility. */ +#define __WMI_VER_MAJOR_ 1 +/** Minor version number is incremented when there are changes + * (however minor) to WMI Interface that break + * compatibility. */ +#define __WMI_VER_MINOR_ 0 +/** WMI revision number has to be incremented when there is a + * change that may or may not break compatibility. */ +#define __WMI_REVISION_ 421 + +/** The Version Namespace should not be normally changed. Only + * host and firmware of the same WMI namespace will work + * together. + * For example, "QCA_ML" converts to 0x4C, 0x4D5F414351. + * where 'Q'=0x51, 'C'=0x43, 'A'=0x41, '_'=0x5F. 'M'=4D, 'L'=4C + */ +#define __NAMESPACE_0_ 0x5F414351 +#define __NAMESPACE_1_ 0x00004C4D +#define __NAMESPACE_2_ 0x00000000 +#define __NAMESPACE_3_ 0x00000000 + +/* Format of the version number. */ +#define WMI_VER_MAJOR_BIT_OFFSET 24 +#define WMI_VER_MINOR_BIT_OFFSET 0 + +#define WMI_VER_MAJOR_BIT_MASK 0xFF000000 +#define WMI_VER_MINOR_BIT_MASK 0x00FFFFFF + +/* Macros to extract the sw_version components. + */ +#define WMI_VER_GET_MAJOR(x) (((x) & WMI_VER_MAJOR_BIT_MASK)>>WMI_VER_MAJOR_BIT_OFFSET) +#define WMI_VER_GET_MINOR(x) (((x) & WMI_VER_MINOR_BIT_MASK)>>WMI_VER_MINOR_BIT_OFFSET) + +#define WMI_VER_GET_VERSION_0(major, minor) ( (( major << WMI_VER_MAJOR_BIT_OFFSET ) & WMI_VER_MAJOR_BIT_MASK) + (( minor << WMI_VER_MINOR_BIT_OFFSET ) & WMI_VER_MINOR_BIT_MASK) ) +/* + * The version has the following format: + * Bits 24-31: Major version + * Bits 0-23: Minor version + * Bits 0-31: Build number + * E.g. Build 1.1.7 would be represented as 0x01000001 for Major/Minor & 0x00000007 for buildnum. + * + * DO NOT split the following macro into multiple lines as this may confuse the build scripts. + */ +/* ABI Version. Reflects the version of binary interface exposed by Target firmware. */ +#define WMI_ABI_VERSION_0 WMI_VER_GET_VERSION_0(__WMI_VER_MAJOR_, __WMI_VER_MINOR_) +#define WMI_ABI_VERSION_1 __WMI_REVISION_ +#define WMI_ABI_VERSION_NS_0 __NAMESPACE_0_ +#define WMI_ABI_VERSION_NS_1 __NAMESPACE_1_ +#define WMI_ABI_VERSION_NS_2 __NAMESPACE_2_ +#define WMI_ABI_VERSION_NS_3 __NAMESPACE_3_ diff --git a/drivers/staging/fw-api/fw/wmix.h b/drivers/staging/fw-api/fw/wmix.h new file mode 100755 index 0000000000000000000000000000000000000000..243478299ef3d755c5290364b5a9cc2f8a584eca --- /dev/null +++ b/drivers/staging/fw-api/fw/wmix.h @@ -0,0 +1,185 @@ +/* + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * This file contains extensions of the WMI protocol specified in the + * Wireless Module Interface (WMI). It includes definitions of all + * extended commands and events. Extensions include useful commands + * that are not directly related to wireless activities. They may + * be hardware-specific, and they might not be supported on all + * implementations. + * + * Extended WMIX commands are encapsulated in a WMI message with + * cmd=WMI_EXTENSION_CMD. + */ + +#ifndef _WMIX_H_ +#define _WMIX_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Extended WMI commands are those that are needed during wireless + * operation, but which are not really wireless commands. This allows, + * for instance, platform-specific commands. Extended WMI commands are + * embedded in a WMI command message with WMI_COMMAND_ID=WMI_EXTENSION_CMDID. + * Extended WMI events are similarly embedded in a WMI event message with + * WMI_EVENT_ID=WMI_EXTENSION_EVENTID. + */ +typedef struct { + A_UINT32 commandId; +} POSTPACK WMIX_CMD_HDR; + +typedef enum { + WMIX_DSETOPEN_REPLY_CMDID = 0x2001, + WMIX_DSETDATA_REPLY_CMDID, + WMIX_HB_CHALLENGE_RESP_CMDID, + WMIX_DBGLOG_CFG_MODULE_CMDID, + WMIX_PROF_CFG_CMDID, /* 0x200a */ + WMIX_PROF_ADDR_SET_CMDID, + WMIX_PROF_START_CMDID, + WMIX_PROF_STOP_CMDID, + WMIX_PROF_COUNT_GET_CMDID, +} WMIX_COMMAND_ID; + +typedef enum { + WMIX_DSETOPENREQ_EVENTID = 0x3001, + WMIX_DSETCLOSE_EVENTID, + WMIX_DSETDATAREQ_EVENTID, + WMIX_HB_CHALLENGE_RESP_EVENTID, + WMIX_DBGLOG_EVENTID, + WMIX_PROF_COUNT_EVENTID, + WMIX_PKTLOG_EVENTID, +} WMIX_EVENT_ID; + +/* + * =============DataSet support================= + */ + +/* + * WMIX_DSETOPENREQ_EVENTID + * DataSet Open Request Event + */ +typedef struct { + A_UINT32 dset_id; + A_UINT32 targ_dset_handle; /* echo'ed, not used by Host, */ + A_UINT32 targ_reply_fn; /* echo'ed, not used by Host, */ + A_UINT32 targ_reply_arg; /* echo'ed, not used by Host, */ +} POSTPACK WMIX_DSETOPENREQ_EVENT; + +/* + * WMIX_DSETCLOSE_EVENTID + * DataSet Close Event + */ +typedef struct { + A_UINT32 access_cookie; +} POSTPACK WMIX_DSETCLOSE_EVENT; + +/* + * WMIX_DSETDATAREQ_EVENTID + * DataSet Data Request Event + */ +typedef struct { + A_UINT32 access_cookie; + A_UINT32 offset; + A_UINT32 length; + A_UINT32 targ_buf; /* echo'ed, not used by Host, */ + A_UINT32 targ_reply_fn; /* echo'ed, not used by Host, */ + A_UINT32 targ_reply_arg; /* echo'ed, not used by Host, */ +} WMIX_DSETDATAREQ_EVENT; + +typedef struct { + A_UINT32 status; + A_UINT32 targ_dset_handle; + A_UINT32 targ_reply_fn; + A_UINT32 targ_reply_arg; + A_UINT32 access_cookie; + A_UINT32 size; + A_UINT32 version; +} WMIX_DSETOPEN_REPLY_CMD; + +typedef struct { + A_UINT32 status; + A_UINT32 targ_buf; + A_UINT32 targ_reply_fn; + A_UINT32 targ_reply_arg; + A_UINT32 length; + A_UINT8 buf[1]; +} WMIX_DSETDATA_REPLY_CMD; + + +/* + * =============Error Detection support================= + */ + +/* + * WMIX_HB_CHALLENGE_RESP_CMDID + * Heartbeat Challenge Response command + */ +typedef struct { + A_UINT32 cookie; + A_UINT32 source; +} WMIX_HB_CHALLENGE_RESP_CMD; + +/* + * WMIX_HB_CHALLENGE_RESP_EVENTID + * Heartbeat Challenge Response Event + */ +#define WMIX_HB_CHALLENGE_RESP_EVENT WMIX_HB_CHALLENGE_RESP_CMD + +/* + * =============Target Profiling support================= + */ + +typedef struct { + A_UINT32 period; /* Time (in 30.5us ticks) between samples */ + A_UINT32 nbins; +} WMIX_PROF_CFG_CMD; + +typedef struct { + A_UINT32 addr; +} WMIX_PROF_ADDR_SET_CMD; + +/* + * Target responds to Hosts's earlier WMIX_PROF_COUNT_GET_CMDID request + * using a WMIX_PROF_COUNT_EVENT with + * addr set to the next address + * count set to the corresponding count + */ +typedef struct { + A_UINT32 addr; + A_UINT32 count; +} WMIX_PROF_COUNT_EVENT; + + +#ifdef __cplusplus +} +#endif + +#endif /* _WMIX_H_ */ diff --git a/drivers/staging/qca-wifi-host-cmn/README.txt b/drivers/staging/qca-wifi-host-cmn/README.txt new file mode 100644 index 0000000000000000000000000000000000000000..bdf3e7a7adc4eaf2883ac235c8ad755f3552a88f --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/README.txt @@ -0,0 +1 @@ +This is CNSS WLAN Host Driver for products starting from iHelium diff --git a/drivers/staging/qca-wifi-host-cmn/VERSION.txt b/drivers/staging/qca-wifi-host-cmn/VERSION.txt new file mode 100644 index 0000000000000000000000000000000000000000..9c12bb77d66419e1c1700d08c422d96002ec412f --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/VERSION.txt @@ -0,0 +1,2 @@ +Current Component wlan-cmn.driver.lnx.1.0 version 5.1.0.28N +Matches Component wlan-cld3.driver.lnx.1.1 version 5.1.0.22D diff --git a/drivers/staging/qca-wifi-host-cmn/dp/inc/cdp_txrx_bus.h b/drivers/staging/qca-wifi-host-cmn/dp/inc/cdp_txrx_bus.h new file mode 100644 index 0000000000000000000000000000000000000000..575d6c4147cce56667d956afe58b137c47fab795 --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/dp/inc/cdp_txrx_bus.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + /** + * @file cdp_txrx_bus.h + * @brief Define the host data path bus related functions + */ +#ifndef _CDP_TXRX_BUS_H_ +#define _CDP_TXRX_BUS_H_ + +QDF_STATUS ol_txrx_bus_suspend(void); +QDF_STATUS ol_txrx_bus_resume(void); + +#endif /* _CDP_TXRX_BUS_H_ */ diff --git a/drivers/staging/qca-wifi-host-cmn/dp/inc/cdp_txrx_cfg.h b/drivers/staging/qca-wifi-host-cmn/dp/inc/cdp_txrx_cfg.h new file mode 100644 index 0000000000000000000000000000000000000000..cd1c188cbbcbcda8fb0225188316bd31881f6473 --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/dp/inc/cdp_txrx_cfg.h @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + /** + * @file cdp_txrx_cfg.h + * @brief Define the host data path configuration API functions + */ +#ifndef _CDP_TXRX_CFG_H_ +#define _CDP_TXRX_CFG_H_ + +#define TX_WMM_AC_NUM 4 + +/** + * struct ol_tx_sched_wrr_ac_specs_t - the wrr ac specs params structure + * @wrr_skip_weight: map to ol_tx_sched_wrr_adv_category_info_t.specs. + * wrr_skip_weight + * @credit_threshold: map to ol_tx_sched_wrr_adv_category_info_t.specs. + * credit_threshold + * @send_limit: map to ol_tx_sched_wrr_adv_category_info_t.specs. + * send_limit + * @credit_reserve: map to ol_tx_sched_wrr_adv_category_info_t.specs. + * credit_reserve + * @discard_weight: map to ol_tx_sched_wrr_adv_category_info_t.specs. + * discard_weight + * + * This structure is for wrr ac specs params set from user, it will update + * its content corresponding to the ol_tx_sched_wrr_adv_category_info_t.specs. + */ +struct ol_tx_sched_wrr_ac_specs_t { + int wrr_skip_weight; + uint32_t credit_threshold; + uint16_t send_limit; + int credit_reserve; + int discard_weight; +}; + +/** + * struct txrx_pdev_cfg_param_t - configuration information + * passed to the data path + */ +struct txrx_pdev_cfg_param_t { + uint8_t is_full_reorder_offload; + /* IPA Micro controller data path offload enable flag */ + uint8_t is_uc_offload_enabled; + /* IPA Micro controller data path offload TX buffer count */ + uint32_t uc_tx_buffer_count; + /* IPA Micro controller data path offload TX buffer size */ + uint32_t uc_tx_buffer_size; + /* IPA Micro controller data path offload RX indication ring count */ + uint32_t uc_rx_indication_ring_count; + /* IPA Micro controller data path offload TX partition base */ + uint32_t uc_tx_partition_base; + /* IP, TCP and UDP checksum offload */ + bool ip_tcp_udp_checksum_offload; + /* Rx processing in thread from TXRX */ + bool enable_rxthread; + /* CE classification enabled through INI */ + bool ce_classify_enabled; +#ifdef QCA_LL_TX_FLOW_CONTROL_V2 + /* Threshold to stop queue in percentage */ + uint32_t tx_flow_stop_queue_th; + /* Start queue offset in percentage */ + uint32_t tx_flow_start_queue_offset; +#endif + + struct ol_tx_sched_wrr_ac_specs_t ac_specs[TX_WMM_AC_NUM]; +}; + +void ol_set_cfg_rx_fwd_disabled(ol_pdev_handle pdev, uint8_t disable_rx_fwd); + +void ol_set_cfg_packet_log_enabled(ol_pdev_handle pdev, uint8_t val); + +ol_pdev_handle ol_pdev_cfg_attach(qdf_device_t osdev, + struct txrx_pdev_cfg_param_t cfg_param); + +void ol_vdev_rx_set_intrabss_fwd(ol_txrx_vdev_handle vdev, bool val); + +/** + * ol_txrx_get_opmode() - Return operation mode of vdev + * @vdev: vdev handle + * + * Return: operation mode. + */ +int ol_txrx_get_opmode(ol_txrx_vdev_handle vdev); + +/** + * ol_txrx_is_rx_fwd_disabled() - returns the rx_fwd_disabled status on vdev + * @vdev: vdev handle + * + * Return: Rx Fwd disabled status + */ +uint8_t +ol_txrx_is_rx_fwd_disabled(ol_txrx_vdev_handle vdev); +#endif /* _CDP_TXRX_CFG_H_ */ diff --git a/drivers/staging/qca-wifi-host-cmn/dp/inc/cdp_txrx_cmn.h b/drivers/staging/qca-wifi-host-cmn/dp/inc/cdp_txrx_cmn.h new file mode 100644 index 0000000000000000000000000000000000000000..460fcfbd58014660319fa2da0d9cb7aed923d4c9 --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/dp/inc/cdp_txrx_cmn.h @@ -0,0 +1,461 @@ +/* + * Copyright (c) 2011-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + /** + * @file cdp_txrx_api_common.h + * @brief Define the host data path converged API functions + * called by the host control SW and the OS interface module + */ +#ifndef _CDP_TXRX_CMN_H_ +#define _CDP_TXRX_CMN_H_ + +#include "htc_api.h" +#include "htt.h" +#include "qdf_types.h" +#include "qdf_nbuf.h" + +/****************************************************************************** + * + * Common Data Path Header File + * + *****************************************************************************/ + +/****************************************************************************** + * + * Structure definitions + * + *****************************************************************************/ + + /** + * ol_txrx_pdev_handle - opaque handle for txrx physical device + * object + */ +struct ol_txrx_pdev_t; +typedef struct ol_txrx_pdev_t *ol_txrx_pdev_handle; + +/** + * ol_txrx_vdev_handle - opaque handle for txrx virtual device + * object + */ +struct ol_txrx_vdev_t; +typedef struct ol_txrx_vdev_t *ol_txrx_vdev_handle; + +/** + * ol_pdev_handle - opaque handle for the configuration + * associated with the physical device + */ +struct ol_pdev_t; +typedef struct ol_pdev_t *ol_pdev_handle; + +/** + * ol_txrx_peer_handle - opaque handle for txrx peer object + */ +struct ol_txrx_peer_t; +typedef struct ol_txrx_peer_t *ol_txrx_peer_handle; + +/** + * ol_txrx_vdev_delete_cb - callback registered during vdev + * detach + */ +typedef void (*ol_txrx_vdev_delete_cb)(void *context); + +/** + * ol_osif_vdev_handle - paque handle for OS shim virtual device + * object + */ +struct ol_osif_vdev_t; +typedef struct ol_osif_vdev_t *ol_osif_vdev_handle; + +/** + * External Device physical address types + * + * Currently, both MAC and IPA uController use the same size addresses + * and descriptors are exchanged between these two depending on the mode. + * + * Rationale: qdf_dma_addr_t is the type used internally on the host for DMA + * operations. However, external device physical address sizes + * may be different from host-specific physical address sizes. + * This calls for the following definitions for target devices + * (MAC, IPA uc). + */ +#if HTT_PADDR64 +typedef uint64_t target_paddr_t; +#else +typedef uint32_t target_paddr_t; +#endif /*HTT_PADDR64 */ + +/** + * wlan_op_mode - Virtual device operation mode + * @wlan_op_mode_unknown: Unknown mode + * @wlan_op_mode_ap: AP mode + * @wlan_op_mode_ibss: IBSS mode + * @wlan_op_mode_sta: STA (client) mode + * @wlan_op_mode_monitor: Monitor mode + * @wlan_op_mode_ocb: OCB mode + * @wlan_op_mode_ndi: NAN datapath mode + */ +enum wlan_op_mode { + wlan_op_mode_unknown, + wlan_op_mode_ap, + wlan_op_mode_ibss, + wlan_op_mode_sta, + wlan_op_mode_monitor, + wlan_op_mode_ocb, + wlan_op_mode_ndi, +}; + +/** + * ol_txrx_tx_fp - top-level transmit function + * @data_vdev - handle to the virtual device object + * @msdu_list - list of network buffers + */ +typedef qdf_nbuf_t (*ol_txrx_tx_fp)(ol_txrx_vdev_handle data_vdev, + qdf_nbuf_t msdu_list); +/** + * ol_txrx_tx_flow_control_fp - tx flow control notification + * function from txrx to OS shim + * @osif_dev - the virtual device's OS shim object + * @tx_resume - tx os q should be resumed or not + */ +typedef void (*ol_txrx_tx_flow_control_fp)(void *osif_dev, + bool tx_resume); + +/** + * ol_txrx_rx_fp - receive function to hand batches of data + * frames from txrx to OS shim + * @data_vdev - handle to the OSIF virtual device object + * @msdu_list - list of network buffers + */ +typedef QDF_STATUS (*ol_txrx_rx_fp)(void *osif_dev, qdf_nbuf_t msdu_list); + +/** + * ol_txrx_rx_check_wai_fp - OSIF WAPI receive function +*/ +typedef bool (*ol_txrx_rx_check_wai_fp)(ol_osif_vdev_handle vdev, + qdf_nbuf_t mpdu_head, + qdf_nbuf_t mpdu_tail); +/** + * ol_txrx_rx_mon_fp - OSIF monitor mode receive function for single + * MPDU (802.11 format) + */ +typedef void (*ol_txrx_rx_mon_fp)(ol_osif_vdev_handle vdev, + qdf_nbuf_t mpdu, + void *rx_status); + +/** + * ol_txrx_proxy_arp_fp - proxy arp function pointer +*/ +typedef int (*ol_txrx_proxy_arp_fp)(ol_osif_vdev_handle vdev, + qdf_nbuf_t netbuf); + +/** + * ol_txrx_stats_callback - statistics notify callback + */ +typedef void (*ol_txrx_stats_callback)(void *ctxt, + enum htt_dbg_stats_type type, + uint8_t *buf, int bytes); + +/** + * ol_txrx_ops - (pointers to) the functions used for tx and rx + * data xfer + * + * There are two portions of these txrx operations. + * The rx portion is filled in by OSIF SW before calling + * ol_txrx_osif_vdev_register; inside the ol_txrx_osif_vdev_register + * the txrx SW stores a copy of these rx function pointers, to use + * as it delivers rx data frames to the OSIF SW. + * The tx portion is filled in by the txrx SW inside + * ol_txrx_osif_vdev_register; when the function call returns, + * the OSIF SW stores a copy of these tx functions to use as it + * delivers tx data frames to the txrx SW. + * + * @tx.std - the tx function pointer for standard data + * frames This function pointer is set by the txrx SW + * perform host-side transmit operations based on + * whether a HL or LL host/target interface is in use. + * @tx.flow_control_cb - the transmit flow control + * function that is registered by the + * OSIF which is called from txrx to + * indicate whether the transmit OS + * queues should be paused/resumed + * @rx.std - the OS shim rx function to deliver rx data + * frames to. This can have different values for + * different virtual devices, e.g. so one virtual + * device's OS shim directly hands rx frames to the OS, + * but another virtual device's OS shim filters out P2P + * messages before sending the rx frames to the OS. The + * netbufs delivered to the osif_rx function are in the + * format specified by the OS to use for tx and rx + * frames (either 802.3 or native WiFi) + * @rx.wai_check - the tx function pointer for WAPI frames + * @rx.mon - the OS shim rx monitor function to deliver + * monitor data to Though in practice, it is probable + * that the same function will be used for delivering + * rx monitor data for all virtual devices, in theory + * each different virtual device can have a different + * OS shim function for accepting rx monitor data. The + * netbufs delivered to the osif_rx_mon function are in + * 802.11 format. Each netbuf holds a 802.11 MPDU, not + * an 802.11 MSDU. Depending on compile-time + * configuration, each netbuf may also have a + * monitor-mode encapsulation header such as a radiotap + * header added before the MPDU contents. + * @proxy_arp - proxy arp function pointer - specified by + * OS shim, stored by txrx + */ +struct ol_txrx_ops { + /* tx function pointers - specified by txrx, stored by OS shim */ + struct { + ol_txrx_tx_fp tx; + } tx; + + /* rx function pointers - specified by OS shim, stored by txrx */ + struct { + ol_txrx_rx_fp rx; + ol_txrx_rx_check_wai_fp wai_check; + ol_txrx_rx_mon_fp mon; + } rx; + + /* proxy arp function pointer - specified by OS shim, stored by txrx */ + ol_txrx_proxy_arp_fp proxy_arp; +}; + +/** + * ol_txrx_stats_req - specifications of the requested + * statistics + */ +struct ol_txrx_stats_req { + uint32_t stats_type_upload_mask; /* which stats to upload */ + uint32_t stats_type_reset_mask; /* which stats to reset */ + + /* stats will be printed if either print element is set */ + struct { + int verbose; /* verbose stats printout */ + int concise; /* concise stats printout (takes precedence) */ + } print; /* print uploaded stats */ + + /* stats notify callback will be invoked if fp is non-NULL */ + struct { + ol_txrx_stats_callback fp; + void *ctxt; + } callback; + + /* stats will be copied into the specified buffer if buf is non-NULL */ + struct { + uint8_t *buf; + int byte_limit; /* don't copy more than this */ + } copy; + + /* + * If blocking is true, the caller will take the specified semaphore + * to wait for the stats to be uploaded, and the driver will release + * the semaphore when the stats are done being uploaded. + */ + struct { + int blocking; + /*Note: this needs to change to some qdf_* type */ + qdf_semaphore_t *sem_ptr; + } wait; +}; + +/****************************************************************************** + * + * Control Interface (A Interface) + * + *****************************************************************************/ + +int +ol_txrx_pdev_attach_target(ol_txrx_pdev_handle pdev); + +ol_txrx_vdev_handle +ol_txrx_vdev_attach(ol_txrx_pdev_handle pdev, uint8_t *vdev_mac_addr, + uint8_t vdev_id, enum wlan_op_mode op_mode); + +void +ol_txrx_vdev_detach(ol_txrx_vdev_handle vdev, + ol_txrx_vdev_delete_cb callback, void *cb_context); + +ol_txrx_pdev_handle +ol_txrx_pdev_attach( + ol_pdev_handle ctrl_pdev, + HTC_HANDLE htc_pdev, + qdf_device_t osdev); + +void ol_txrx_pdev_pre_detach(ol_txrx_pdev_handle pdev, int force); +void ol_txrx_pdev_detach(ol_txrx_pdev_handle pdev); + +ol_txrx_peer_handle +ol_txrx_peer_attach(ol_txrx_vdev_handle vdev, uint8_t *peer_mac_addr); + +void +ol_txrx_peer_detach(ol_txrx_peer_handle peer); + +int +ol_txrx_set_monitor_mode(ol_txrx_vdev_handle vdev); + +void +ol_txrx_set_curchan( + ol_txrx_pdev_handle pdev, + uint32_t chan_mhz); + +void +ol_txrx_set_privacy_filters(ol_txrx_vdev_handle vdev, + void *filter, uint32_t num); + +/****************************************************************************** + * Data Interface (B Interface) + *****************************************************************************/ +void +ol_txrx_vdev_register(ol_txrx_vdev_handle vdev, + void *osif_vdev, struct ol_txrx_ops *txrx_ops); + +int +ol_txrx_mgmt_send( + ol_txrx_vdev_handle vdev, + qdf_nbuf_t tx_mgmt_frm, + uint8_t type); + +int +ol_txrx_mgmt_send_ext(ol_txrx_vdev_handle vdev, + qdf_nbuf_t tx_mgmt_frm, + uint8_t type, uint8_t use_6mbps, uint16_t chanfreq); + +/** + * ol_txrx_mgmt_tx_cb - tx management delivery notification + * callback function + */ +typedef void +(*ol_txrx_mgmt_tx_cb)(void *ctxt, qdf_nbuf_t tx_mgmt_frm, int had_error); + +void +ol_txrx_mgmt_tx_cb_set(ol_txrx_pdev_handle pdev, + uint8_t type, + ol_txrx_mgmt_tx_cb download_cb, + ol_txrx_mgmt_tx_cb ota_ack_cb, void *ctxt); + +int ol_txrx_get_tx_pending(ol_txrx_pdev_handle pdev); + +/** + * ol_txrx_data_tx_cb - Function registered with the data path + * that is called when tx frames marked as "no free" are + * done being transmitted + */ +typedef void +(*ol_txrx_data_tx_cb)(void *ctxt, qdf_nbuf_t tx_frm, int had_error); + +void +ol_txrx_data_tx_cb_set(ol_txrx_vdev_handle data_vdev, + ol_txrx_data_tx_cb callback, void *ctxt); + +/****************************************************************************** + * Statistics and Debugging Interface (C Inteface) + *****************************************************************************/ + +int +ol_txrx_aggr_cfg(ol_txrx_vdev_handle vdev, + int max_subfrms_ampdu, + int max_subfrms_amsdu); + +int +ol_txrx_fw_stats_get( + ol_txrx_vdev_handle vdev, + struct ol_txrx_stats_req *req, + bool per_vdev, + bool response_expected); + +int +ol_txrx_debug(ol_txrx_vdev_handle vdev, int debug_specs); + +void ol_txrx_fw_stats_cfg( + ol_txrx_vdev_handle vdev, + uint8_t cfg_stats_type, + uint32_t cfg_val); + +void ol_txrx_print_level_set(unsigned level); + +#define TXRX_FW_STATS_TXSTATS 1 +#define TXRX_FW_STATS_RXSTATS 2 +#define TXRX_FW_STATS_RX_RATE_INFO 3 +#define TXRX_FW_STATS_PHYSTATS 4 +#define TXRX_FW_STATS_PHYSTATS_CONCISE 5 +#define TXRX_FW_STATS_TX_RATE_INFO 6 +#define TXRX_FW_STATS_TID_STATE 7 +#define TXRX_FW_STATS_HOST_STATS 8 +#define TXRX_FW_STATS_CLEAR_HOST_STATS 9 +#define TXRX_FW_STATS_CE_STATS 10 +#define TXRX_FW_STATS_VOW_UMAC_COUNTER 11 +#define TXRX_FW_STATS_ME_STATS 12 +#define TXRX_FW_STATS_TXBF_INFO 13 +#define TXRX_FW_STATS_SND_INFO 14 +#define TXRX_FW_STATS_ERROR_INFO 15 +#define TXRX_FW_STATS_TX_SELFGEN_INFO 16 +#define TXRX_FW_STATS_TX_MU_INFO 17 +#define TXRX_FW_SIFS_RESP_INFO 18 +#define TXRX_FW_RESET_STATS 19 +#define TXRX_FW_MAC_WDOG_STATS 20 +#define TXRX_FW_MAC_DESC_STATS 21 +#define TXRX_FW_MAC_FETCH_MGR_STATS 22 +#define TXRX_FW_MAC_PREFETCH_MGR_STATS 23 + +#define PER_RADIO_FW_STATS_REQUEST 0 +#define PER_VDEV_FW_STATS_REQUEST 1 +/** + * ol_txrx_get_vdev_mac_addr() - Return mac addr of vdev + * @vdev: vdev handle + * + * Return: vdev mac address + */ +uint8_t * +ol_txrx_get_vdev_mac_addr(ol_txrx_vdev_handle vdev); + +/** + * ol_txrx_get_vdev_struct_mac_addr() - Return handle to struct qdf_mac_addr of + * vdev + * @vdev: vdev handle + * + * Return: Handle to struct qdf_mac_addr + */ +struct qdf_mac_addr * +ol_txrx_get_vdev_struct_mac_addr(ol_txrx_vdev_handle vdev); + +/** + * ol_txrx_get_pdev_from_vdev() - Return handle to pdev of vdev + * @vdev: vdev handle + * + * Return: Handle to pdev + */ +ol_txrx_pdev_handle ol_txrx_get_pdev_from_vdev(ol_txrx_vdev_handle vdev); + +/** + * ol_txrx_get_ctrl_pdev_from_vdev() - Return control pdev of vdev + * @vdev: vdev handle + * + * Return: Handle to control pdev + */ +ol_pdev_handle +ol_txrx_get_ctrl_pdev_from_vdev(ol_txrx_vdev_handle vdev); + +#endif /* _CDP_TXRX_CMN_H_ */ diff --git a/drivers/staging/qca-wifi-host-cmn/dp/inc/cdp_txrx_ctrl.h b/drivers/staging/qca-wifi-host-cmn/dp/inc/cdp_txrx_ctrl.h new file mode 100644 index 0000000000000000000000000000000000000000..daaea25ff9912b692d5127db3dd701e6763a3b94 --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/dp/inc/cdp_txrx_ctrl.h @@ -0,0 +1,251 @@ +/* + * Copyright (c) 2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + /** + * @file cdp_txrx_ctrl.h + * @brief Define the host data path control API functions + * called by the host control SW and the OS interface module + */ + +#ifndef _CDP_TXRX_CTRL_H_ +#define _CDP_TXRX_CTRL_H_ +/* TODO: adf need to be replaced with qdf */ +/* + * Cleanups -- Might need cleanup + */ +#if !QCA_OL_TX_PDEV_LOCK && QCA_NSS_PLATFORM || \ + (defined QCA_PARTNER_PLATFORM && QCA_PARTNER_SUPPORT_FAST_TX) +#define VAP_TX_SPIN_LOCK(_x) spin_lock(_x) +#define VAP_TX_SPIN_UNLOCK(_x) spin_unlock(_x) +#else /* QCA_OL_TX_PDEV_LOCK */ +#define VAP_TX_SPIN_LOCK(_x) +#define VAP_TX_SPIN_UNLOCK(_x) +#endif /* QCA_OL_TX_PDEV_LOCK */ + +#if QCA_OL_TX_PDEV_LOCK +void ol_ll_pdev_tx_lock(void *); +void ol_ll_pdev_tx_unlock(void *); +#define OL_TX_LOCK(_x) ol_ll_pdev_tx_lock(_x) +#define OL_TX_UNLOCK(_x) ol_ll_pdev_tx_unlock(_x) + +#define OL_TX_PDEV_LOCK(_x) qdf_spin_lock_bh(_x) +#define OL_TX_PDEV_UNLOCK(_x) qdf_spin_unlock_bh(_x) +#else +#define OL_TX_PDEV_LOCK(_x) +#define OL_TX_PDEV_UNLOCK(_x) + +#define OL_TX_LOCK(_x) +#define OL_TX_UNLOCK(_x) +#endif /* QCA_OL_TX_PDEV_LOCK */ + +#if !QCA_OL_TX_PDEV_LOCK +#define OL_TX_FLOW_CTRL_LOCK(_x) qdf_spin_lock_bh(_x) +#define OL_TX_FLOW_CTRL_UNLOCK(_x) qdf_spin_unlock_bh(_x) + +#define OL_TX_DESC_LOCK(_x) qdf_spin_lock_bh(_x) +#define OL_TX_DESC_UNLOCK(_x) qdf_spin_unlock_bh(_x) + +#define OSIF_VAP_TX_LOCK(_x) spin_lock(&((_x)->tx_lock)) +#define OSIF_VAP_TX_UNLOCK(_x) spin_unlock(&((_x)->tx_lock)) + +#define OL_TX_PEER_LOCK(_x, _id) qdf_spin_lock_bh(&((_x)->peer_lock[_id])) +#define OL_TX_PEER_UNLOCK(_x, _id) qdf_spin_unlock_bh(&((_x)->peer_lock[_id])) + +#define OL_TX_PEER_UPDATE_LOCK(_x, _id) \ + qdf_spin_lock_bh(&((_x)->peer_lock[_id])) +#define OL_TX_PEER_UPDATE_UNLOCK(_x, _id) \ + qdf_spin_unlock_bh(&((_x)->peer_lock[_id])) + +#else +#define OSIF_VAP_TX_LOCK(_x) ol_ll_pdev_tx_lock((_x)->iv_txrx_handle) +#define OSIF_VAP_TX_UNLOCK(_x) ol_ll_pdev_tx_unlock((_x)->iv_txrx_handle) + +#define OL_TX_FLOW_CTRL_LOCK(_x) +#define OL_TX_FLOW_CTRL_UNLOCK(_x) + +#define OL_TX_DESC_LOCK(_x) +#define OL_TX_DESC_UNLOCK(_x) + +#define OL_TX_PEER_LOCK(_x, _id) +#define OL_TX_PEER_UNLOCK(_x, _id) + +#define OL_TX_PEER_UPDATE_LOCK(_x, _id) qdf_spin_lock_bh(&((_x)->tx_lock)) +#define OL_TX_PEER_UPDATE_UNLOCK(_x, _id) qdf_spin_unlock_bh(&((_x)->tx_lock)) + +#endif /* !QCA_OL_TX_PDEV_LOCK */ + + +extern int ol_txrx_is_target_ar900b(ol_txrx_vdev_handle vdev); +#define OL_TXRX_IS_TARGET_AR900B(vdev) ol_txrx_is_target_ar900b(vdev) + + +/* WIN */ +int +ol_txrx_mempools_attach(ol_pdev_handle ctrl_pdev); +int +ol_txrx_set_filter_neighbour_peers( + ol_txrx_pdev_handle pdev, + u_int32_t val); +/** + * @brief set the safemode of the device + * @details + * This flag is used to bypass the encrypt and decrypt processes when send and + * receive packets. It works like open AUTH mode, HW will treate all packets + * as non-encrypt frames because no key installed. For rx fragmented frames, + * it bypasses all the rx defragmentaion. + * + * @param vdev - the data virtual device object + * @param val - the safemode state + * @return - void + */ + +void +ol_txrx_set_safemode( + ol_txrx_vdev_handle vdev, + u_int32_t val); +/** + * @brief configure the drop unencrypted frame flag + * @details + * Rx related. When set this flag, all the unencrypted frames + * received over a secure connection will be discarded + * + * @param vdev - the data virtual device object + * @param val - flag + * @return - void + */ +void +ol_txrx_set_drop_unenc( + ol_txrx_vdev_handle vdev, + u_int32_t val); + + +/** + * @brief set the Tx encapsulation type of the VDEV + * @details + * This will be used to populate the HTT desc packet type field during Tx + * + * @param vdev - the data virtual device object + * @param val - the Tx encap type + * @return - void + */ +void +ol_txrx_set_tx_encap_type( + ol_txrx_vdev_handle vdev, + enum htt_pkt_type val); + +/** + * @brief set the Rx decapsulation type of the VDEV + * @details + * This will be used to configure into firmware and hardware which format to + * decap all Rx packets into, for all peers under the VDEV. + * + * @param vdev - the data virtual device object + * @param val - the Rx decap mode + * @return - void + */ +void +ol_txrx_set_vdev_rx_decap_type( + ol_txrx_vdev_handle vdev, + enum htt_pkt_type val); + +/** + * @brief get the Rx decapsulation type of the VDEV + * + * @param vdev - the data virtual device object + * @return - the Rx decap type + */ +enum htt_pkt_type +ol_txrx_get_vdev_rx_decap_type(ol_txrx_vdev_handle vdev); + +/* Is this similar to ol_txrx_peer_state_update() in MCL */ +/** + * @brief Update the authorize peer object at association time + * @details + * For the host-based implementation of rate-control, it + * updates the peer/node-related parameters within rate-control + * context of the peer at association. + * + * @param peer - pointer to the node's object + * @authorize - either to authorize or unauthorize peer + * + * @return none + */ +void +ol_txrx_peer_authorize(struct ol_txrx_peer_t *peer, u_int32_t authorize); + +bool +ol_txrx_set_inact_params(ol_txrx_pdev_handle pdev, + u_int16_t inact_check_interval, + u_int16_t inact_normal, + u_int16_t inact_overload); +bool +ol_txrx_start_inact_timer( + ol_txrx_pdev_handle pdev, + bool enable); + +/** + * @brief Set the overload status of the radio + * @details + * Set the overload status of the radio, updating the inactivity + * threshold and inactivity count for each node. + * + * @param pdev - the data physical device object + * @param overload - whether the radio is overloaded or not + */ +void +ol_txrx_set_overload( + ol_txrx_pdev_handle pdev, + bool overload); +/** + * @brief Check the inactivity status of the peer/node + * + * @param peer - pointer to the node's object + * @return true if the node is inactive; otherwise return false + */ +bool +ol_txrx_peer_is_inact(ol_txrx_peer_handle peer); + +/** + * @brief Mark inactivity status of the peer/node + * @details + * If it becomes active, reset inactivity count to reload value; + * if the inactivity status changed, notify umac band steering. + * + * @param peer - pointer to the node's object + * @param inactive - whether the node is inactive or not + */ +void +ol_txrx_mark_peer_inact( + ol_txrx_peer_handle peer, + bool inactive); + + +/* Should be ol_txrx_ctrl_api.h */ +void ol_txrx_set_mesh_mode(ol_txrx_vdev_handle vdev, u_int32_t val); + +void ol_tx_flush_buffers(struct ol_txrx_vdev_t *vdev); + +#endif diff --git a/drivers/staging/qca-wifi-host-cmn/dp/inc/cdp_txrx_flow_ctrl_legacy.h b/drivers/staging/qca-wifi-host-cmn/dp/inc/cdp_txrx_flow_ctrl_legacy.h new file mode 100644 index 0000000000000000000000000000000000000000..b53a397ff9a54275c66b2d2414219510e8881e44 --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/dp/inc/cdp_txrx_flow_ctrl_legacy.h @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + /** + * @file cdp_txrx_flow_ctrl_legacy.h + * @brief Define the host data path legacy flow control API + * functions + */ +#ifndef _CDP_TXRX_FC_LEG_H_ +#define _CDP_TXRX_FC_LEG_H_ + +/** + * enum netif_action_type - Type of actions on netif queues + * @WLAN_STOP_ALL_NETIF_QUEUE: stop all netif queues + * @WLAN_START_ALL_NETIF_QUEUE: start all netif queues + * @WLAN_WAKE_ALL_NETIF_QUEUE: wake all netif queues + * @WLAN_STOP_ALL_NETIF_QUEUE_N_CARRIER: stop all queues and off carrier + * @WLAN_START_ALL_NETIF_QUEUE_N_CARRIER: start all queues and on carrier + * @WLAN_NETIF_TX_DISABLE: disable tx + * @WLAN_NETIF_TX_DISABLE_N_CARRIER: disable tx and off carrier + * @WLAN_NETIF_CARRIER_ON: on carrier + * @WLAN_NETIF_CARRIER_OFF: off carrier + */ +enum netif_action_type { + WLAN_STOP_ALL_NETIF_QUEUE = 1, + WLAN_START_ALL_NETIF_QUEUE, + WLAN_WAKE_ALL_NETIF_QUEUE, + WLAN_STOP_ALL_NETIF_QUEUE_N_CARRIER, + WLAN_START_ALL_NETIF_QUEUE_N_CARRIER, + WLAN_NETIF_TX_DISABLE, + WLAN_NETIF_TX_DISABLE_N_CARRIER, + WLAN_NETIF_CARRIER_ON, + WLAN_NETIF_CARRIER_OFF, + WLAN_NETIF_ACTION_TYPE_MAX, +}; + +/** + * enum netif_reason_type - reason for netif queue action + * @WLAN_CONTROL_PATH: action from control path + * @WLAN_DATA_FLOW_CONTROL: because of flow control + * @WLAN_FW_PAUSE: because of firmware pause + * @WLAN_TX_ABORT: because of tx abort + * @WLAN_VDEV_STOP: because of vdev stop + * @WLAN_PEER_UNAUTHORISED: because of peer is unauthorised + * @WLAN_THERMAL_MITIGATION: because of thermal mitigation + */ +enum netif_reason_type { + WLAN_CONTROL_PATH = 1, + WLAN_DATA_FLOW_CONTROL, + WLAN_FW_PAUSE, + WLAN_TX_ABORT, + WLAN_VDEV_STOP, + WLAN_PEER_UNAUTHORISED, + WLAN_THERMAL_MITIGATION, + WLAN_REASON_TYPE_MAX, +}; + +#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL +/** + * ol_txrx_tx_flow_control_fp - tx flow control notification + * function from txrx to OS shim + * @osif_dev - the virtual device's OS shim object + * @tx_resume - tx os q should be resumed or not + */ +typedef void (*ol_txrx_tx_flow_control_fp)(void *osif_dev, + bool tx_resume); + +int ol_txrx_register_tx_flow_control(uint8_t vdev_id, + ol_txrx_tx_flow_control_fp flowControl, + void *osif_fc_ctx); + +int ol_txrx_deregister_tx_flow_control_cb(uint8_t vdev_id); + +void ol_txrx_flow_control_cb(ol_txrx_vdev_handle vdev, + bool tx_resume); +bool +ol_txrx_get_tx_resource(uint8_t sta_id, + unsigned int low_watermark, + unsigned int high_watermark_offset); + +int +ol_txrx_ll_set_tx_pause_q_depth(uint8_t vdev_id, int pause_q_depth); + +#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */ + +void ol_txrx_vdev_flush(ol_txrx_vdev_handle data_vdev); + +#ifdef CONFIG_ICNSS +static inline void ol_txrx_vdev_pause(ol_txrx_vdev_handle vdev, uint32_t reason) +{ + return; +} +#else +void ol_txrx_vdev_pause(ol_txrx_vdev_handle vdev, uint32_t reason); +#endif + +#ifdef CONFIG_ICNSS +static inline void ol_txrx_vdev_unpause(ol_txrx_vdev_handle data_vdev, + uint32_t reason) +{ + return; +} +#else +void ol_txrx_vdev_unpause(ol_txrx_vdev_handle data_vdev, uint32_t reason); +#endif + +#endif /* _CDP_TXRX_FC_LEG_H_ */ diff --git a/drivers/staging/qca-wifi-host-cmn/dp/inc/cdp_txrx_flow_ctrl_v2.h b/drivers/staging/qca-wifi-host-cmn/dp/inc/cdp_txrx_flow_ctrl_v2.h new file mode 100644 index 0000000000000000000000000000000000000000..53948c39c5245ec7cd84175ba08a0d5f04cefd74 --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/dp/inc/cdp_txrx_flow_ctrl_v2.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + /** + * @file cdp_txrx_flow_ctrl_v2.h + * @brief Define the host data path flow control version 2 API + * functions + */ +#ifndef _CDP_TXRX_FC_V2_H_ +#define _CDP_TXRX_FC_V2_H_ + +#include "cdp_txrx_flow_ctrl_legacy.h" + +/** + * @typedef ol_tx_pause_callback_fp + * @brief OSIF function registered with the data path + */ +typedef void (*ol_tx_pause_callback_fp)(uint8_t vdev_id, + enum netif_action_type action, + enum netif_reason_type reason); + +#ifdef QCA_LL_TX_FLOW_CONTROL_V2 +QDF_STATUS ol_txrx_register_pause_cb(ol_tx_pause_callback_fp pause_cb); + +void ol_tx_set_desc_global_pool_size(uint32_t num_msdu_desc); +#else +static inline +QDF_STATUS ol_txrx_register_pause_cb(ol_tx_pause_callback_fp pause_cb) +{ + return QDF_STATUS_SUCCESS; + +} + +static inline void ol_tx_set_desc_global_pool_size(uint32_t num_msdu_desc) +{ + return; +} +#endif + +#endif /* _CDP_TXRX_FC_V2_H_ */ diff --git a/drivers/staging/qca-wifi-host-cmn/dp/inc/cdp_txrx_host_stats.h b/drivers/staging/qca-wifi-host-cmn/dp/inc/cdp_txrx_host_stats.h new file mode 100644 index 0000000000000000000000000000000000000000..e87ca3b1e074fc905164afef8db0c7952d5322a4 --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/dp/inc/cdp_txrx_host_stats.h @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + /** + * @file cdp_txrx_host_stats.h + * @brief Define the host data path stats API functions + * called by the host control SW and the OS interface module + */ +#ifndef _CDP_TXRX_HOST_STATS_H_ +#define _CDP_TXRX_HOST_STATS_H_ + +#include +/* WIN */ +/* Need to remove the "req" parameter */ +/* Need to rename the function to reflect the functionality "show" / "display" + * WIN -- to figure out whether to change OSIF to converge (not an immediate AI) + * */ +#if WLAN_FEATURE_FASTPATH +int ol_txrx_host_stats_get( + ol_txrx_vdev_handle vdev, + struct ol_txrx_stats_req *req); + + +void +ol_txrx_host_stats_clr(ol_txrx_vdev_handle vdev); + +void +ol_txrx_host_ce_stats(ol_txrx_vdev_handle vdev); + +int +ol_txrx_stats_publish(ol_txrx_pdev_handle pdev, struct ol_txrx_stats *buf); +/** + * @brief Enable enhanced stats functionality. + * + * @param pdev - the physical device object + * @return - void + */ +void +ol_txrx_enable_enhanced_stats(ol_txrx_pdev_handle pdev); + +/** + * @brief Disable enhanced stats functionality. + * + * @param pdev - the physical device object + * @return - void + */ +void +ol_txrx_disable_enhanced_stats(ol_txrx_pdev_handle pdev); + +#if ENHANCED_STATS +/** + * @brief Get the desired stats from the message. + * + * @param pdev - the physical device object + * @param stats_base - stats buffer recieved from FW + * @param type - stats type. + * @return - pointer to requested stat identified by type + */ +uint32_t *ol_txrx_get_stats_base(ol_txrx_pdev_handle pdev, + uint32_t *stats_base, uint32_t msg_len, uint8_t type); +#endif +#endif /* WLAN_FEATURE_FASTPATH*/ +#if (HOST_SW_TSO_ENABLE || HOST_SW_TSO_SG_ENABLE) +void +ol_tx_print_tso_stats( + ol_txrx_vdev_handle vdev); + +void +ol_tx_rst_tso_stats(ol_txrx_vdev_handle vdev); +#endif /* HOST_SW_TSO_ENABLE || HOST_SW_TSO_SG_ENABLE */ + +#if HOST_SW_SG_ENABLE +void +ol_tx_print_sg_stats( + ol_txrx_vdev_handle vdev); + +void +ol_tx_rst_sg_stats(ol_txrx_vdev_handle vdev); +#endif /* HOST_SW_SG_ENABLE */ + +#if RX_CHECKSUM_OFFLOAD +void +ol_print_rx_cksum_stats( + ol_txrx_vdev_handle vdev); + +void +ol_rst_rx_cksum_stats(ol_txrx_vdev_handle vdev); +#endif /* RX_CHECKSUM_OFFLOAD */ + +#if (ATH_SUPPORT_IQUE && WLAN_FEATURE_FASTPATH) +A_STATUS +ol_txrx_host_me_stats(ol_txrx_vdev_handle vdev); +#endif /* WLAN_FEATURE_FASTPATH */ +#if PEER_FLOW_CONTROL +extern void +ol_txrx_per_peer_stats(struct ol_txrx_pdev_t *pdev, char *addr); +#endif +#if WLAN_FEATURE_FASTPATH && PEER_FLOW_CONTROL +int ol_txrx_host_msdu_ttl_stats( + ol_txrx_vdev_handle vdev, + struct ol_txrx_stats_req *req); +#endif + +#define BSS_CHAN_INFO_READ 1 +#define BSS_CHAN_INFO_READ_AND_CLEAR 2 + +#define TX_FRAME_TYPE_DATA 0 +#define TX_FRAME_TYPE_MGMT 1 +#define TX_FRAME_TYPE_BEACON 2 + +#if HOST_SW_LRO_ENABLE +void +ol_print_lro_stats(ol_txrx_vdev_handle vdev); + +void +ol_reset_lro_stats(ol_txrx_vdev_handle vdev); +#endif /* HOST_SW_LRO_ENABLE */ + +#endif diff --git a/drivers/staging/qca-wifi-host-cmn/dp/inc/cdp_txrx_ipa.h b/drivers/staging/qca-wifi-host-cmn/dp/inc/cdp_txrx_ipa.h new file mode 100644 index 0000000000000000000000000000000000000000..bbaf1f1f49a0490b50c8a549597393d484d4688c --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/dp/inc/cdp_txrx_ipa.h @@ -0,0 +1,145 @@ +/* + * Copyright (c) 2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + /** + * @file cdp_txrx_ipa.h + * @brief Define the host data path IP Acceleraor API functions + */ +#ifndef _CDP_TXRX_IPA_H_ +#define _CDP_TXRX_IPA_H_ + + +/** + * ol_txrx_ipa_resources - Resources needed for IPA + */ +struct ol_txrx_ipa_resources { + qdf_dma_addr_t ce_sr_base_paddr; + uint32_t ce_sr_ring_size; + qdf_dma_addr_t ce_reg_paddr; + + qdf_dma_addr_t tx_comp_ring_base_paddr; + uint32_t tx_comp_ring_size; + uint32_t tx_num_alloc_buffer; + + qdf_dma_addr_t rx_rdy_ring_base_paddr; + uint32_t rx_rdy_ring_size; + qdf_dma_addr_t rx_proc_done_idx_paddr; + void *rx_proc_done_idx_vaddr; + + qdf_dma_addr_t rx2_rdy_ring_base_paddr; + uint32_t rx2_rdy_ring_size; + qdf_dma_addr_t rx2_proc_done_idx_paddr; + void *rx2_proc_done_idx_vaddr; +}; + +#ifdef IPA_OFFLOAD + +void +ol_txrx_ipa_uc_get_resource(ol_txrx_pdev_handle pdev, + struct ol_txrx_ipa_resources *ipa_res); + +void +ol_txrx_ipa_uc_set_doorbell_paddr(ol_txrx_pdev_handle pdev, + qdf_dma_addr_t ipa_tx_uc_doorbell_paddr, + qdf_dma_addr_t ipa_rx_uc_doorbell_paddr); + +void +ol_txrx_ipa_uc_set_active(ol_txrx_pdev_handle pdev, + bool uc_active, bool is_tx); + +void ol_txrx_ipa_uc_op_response(ol_txrx_pdev_handle pdev, uint8_t *op_msg); + +void ol_txrx_ipa_uc_register_op_cb(ol_txrx_pdev_handle pdev, + void (*ipa_uc_op_cb_type)(uint8_t *op_msg, + void *osif_ctxt), + void *osif_dev); + +void ol_txrx_ipa_uc_get_stat(ol_txrx_pdev_handle pdev); + +void ol_txrx_ipa_uc_get_share_stats(ol_txrx_pdev_handle pdev, + uint8_t reset_stats); + +void ol_txrx_ipa_uc_set_quota(ol_txrx_pdev_handle pdev, uint64_t quota_bytes); + +qdf_nbuf_t ol_tx_send_ipa_data_frame(void *vdev, qdf_nbuf_t skb); +#else + +static inline void +ol_txrx_ipa_uc_get_resource(ol_txrx_pdev_handle pdev, + struct ol_txrx_ipa_resources *ipa_res) +{ + return; +} + +static inline void +ol_txrx_ipa_uc_set_doorbell_paddr(ol_txrx_pdev_handle pdev, + qdf_dma_addr_t ipa_tx_uc_doorbell_paddr, + qdf_dma_addr_t ipa_rx_uc_doorbell_paddr) +{ + return; +} + +static inline void +ol_txrx_ipa_uc_set_active(ol_txrx_pdev_handle pdev, + bool uc_active, bool is_tx) +{ + return; +} + +static inline void +ol_txrx_ipa_uc_op_response(ol_txrx_pdev_handle pdev, uint8_t *op_msg) +{ + return; +} + +static inline void +ol_txrx_ipa_uc_register_op_cb(ol_txrx_pdev_handle pdev, + void (*ipa_uc_op_cb_type)(uint8_t *op_msg, + void *osif_ctxt), + void *osif_dev) +{ + return; +} + +static inline void ol_txrx_ipa_uc_get_share_stats(ol_txrx_pdev_handle pdev, + uint8_t reset_stats) +{ + return; +} + +static inline void ol_txrx_ipa_uc_set_quota(ol_txrx_pdev_handle pdev, + uint64_t quota_bytes) +{ + return; +} + +static inline void ol_txrx_ipa_uc_get_stat(ol_txrx_pdev_handle pdev) +{ + return; +} +#endif /* IPA_OFFLOAD */ + +#endif /* _CDP_TXRX_IPA_H_ */ diff --git a/drivers/staging/qca-wifi-host-cmn/dp/inc/cdp_txrx_lro.h b/drivers/staging/qca-wifi-host-cmn/dp/inc/cdp_txrx_lro.h new file mode 100644 index 0000000000000000000000000000000000000000..46ca71961f27529d3c0d197b5f67b9194eeece2b --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/dp/inc/cdp_txrx_lro.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + /** + * @file cdp_txrx_lro.h + * @brief Define the host data path Large Receive Offload API + * functions + */ +#ifndef _CDP_TXRX_LRO_H_ +#define _CDP_TXRX_LRO_H_ + +void ol_register_lro_flush_cb(void (lro_flush_cb)(void *), + void *(lro_init_cb)(void)); +void ol_deregister_lro_flush_cb(void (lro_deinit_cb)(void *)); + +#endif /* _CDP_TXRX_LRO_H_ */ diff --git a/drivers/staging/qca-wifi-host-cmn/dp/inc/cdp_txrx_me.h b/drivers/staging/qca-wifi-host-cmn/dp/inc/cdp_txrx_me.h new file mode 100644 index 0000000000000000000000000000000000000000..74e69cebafa820cc3dfa112a4da2ac57b07906f2 --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/dp/inc/cdp_txrx_me.h @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + /** + * @file cdp_txrx_me.h + * @brief Define the host data path mcast enhance API functions + * called by the host control SW and the OS interface module + */ +#ifndef _CDP_TXRX_ME_H_ +#define _CDP_TXRX_ME_H_ + +/* TODO: adf need to be replaced with qdf */ + +#if ATH_SUPPORT_ME_FW_BASED + +extern u_int16_t +ol_tx_desc_alloc_and_mark_for_mcast_clone(struct ol_txrx_pdev_t *pdev, u_int16_t +buf_count) + +extern u_int16_t +ol_tx_desc_free_and_unmark_for_mcast_clone(struct ol_txrx_pdev_t *pdev, + u_int16_t buf_count); + +extern u_int16_t +ol_tx_get_mcast_buf_allocated_marked(struct ol_txrx_pdev_t *pdev); +#else +extern void +ol_tx_me_alloc_descriptor(struct ol_txrx_pdev_t *pdev); + +extern void +ol_tx_me_free_descriptor(struct ol_txrx_pdev_t *pdev); + +extern uint16_t +ol_tx_me_convert_ucast(ol_txrx_vdev_handle vdev, qdf_nbuf_t wbuf, + u_int8_t newmac[][6], uint8_t newmaccnt); +#endif +/* Should be a function pointer in ol_txrx_osif_ops{} */ +#if ATH_MCAST_HOST_INSPECT +/** + * @brief notify mcast frame indication from FW. + * @details + * This notification will be used to convert + * multicast frame to unicast. + * + * @param pdev - handle to the ctrl SW's physical device object + * @param vdev_id - ID of the virtual device received the special data + * @param msdu - the multicast msdu returned by FW for host inspect + */ + +int ol_mcast_notify(ol_pdev_handle pdev, + u_int8_t vdev_id, qdf_nbuf_t msdu); +#endif + +#endif diff --git a/drivers/staging/qca-wifi-host-cmn/dp/inc/cdp_txrx_misc.h b/drivers/staging/qca-wifi-host-cmn/dp/inc/cdp_txrx_misc.h new file mode 100644 index 0000000000000000000000000000000000000000..92ea29e0f237d8a1320b79cfcdf30b2e37d5afdf --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/dp/inc/cdp_txrx_misc.h @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + /** + * @file cdp_txrx_misc.h + * @brief Define the host data path miscelleneous API functions + * called by the host control SW and the OS interface module + */ +#ifndef _CDP_TXRX_MISC_H_ +#define _CDP_TXRX_MISC_H_ + +/** + * @enum ol_tx_spec + * @brief indicate what non-standard transmission actions to apply + * @details + * Indicate one or more of the following: + * - The tx frame already has a complete 802.11 header. + * Thus, skip 802.3/native-WiFi to 802.11 header encapsulation and + * A-MSDU aggregation. + * - The tx frame should not be aggregated (A-MPDU or A-MSDU) + * - The tx frame is already encrypted - don't attempt encryption. + * - The tx frame is a segment of a TCP jumbo frame. + * - This tx frame should not be unmapped and freed by the txrx layer + * after transmission, but instead given to a registered tx completion + * callback. + * More than one of these specification can apply, though typically + * only a single specification is applied to a tx frame. + * A compound specification can be created, as a bit-OR of these + * specifications. + */ +enum ol_tx_spec { + OL_TX_SPEC_STD = 0x0, /* do regular processing */ + OL_TX_SPEC_RAW = 0x1, /* skip encap + A-MSDU aggr */ + OL_TX_SPEC_NO_AGGR = 0x2, /* skip encap + all aggr */ + OL_TX_SPEC_NO_ENCRYPT = 0x4, /* skip encap + encrypt */ + OL_TX_SPEC_TSO = 0x8, /* TCP segmented */ + OL_TX_SPEC_NWIFI_NO_ENCRYPT = 0x10, /* skip encrypt for nwifi */ + OL_TX_SPEC_NO_FREE = 0x20, /* give to cb rather than free */ +}; + +/** + * ol_tx_non_std() - Allow the control-path SW to send data frames + * + * @data_vdev - which vdev should transmit the tx data frames + * @tx_spec - what non-standard handling to apply to the tx data frames + * @msdu_list - NULL-terminated list of tx MSDUs + * + * Generally, all tx data frames come from the OS shim into the txrx layer. + * However, there are rare cases such as TDLS messaging where the UMAC + * control-path SW creates tx data frames. + * This UMAC SW can call this function to provide the tx data frames to + * the txrx layer. + * The UMAC SW can request a callback for these data frames after their + * transmission completes, by using the ol_txrx_data_tx_cb_set function + * to register a tx completion callback, and by specifying + * ol_tx_spec_no_free as the tx_spec arg when giving the frames to + * ol_tx_non_std. + * The MSDUs need to have the appropriate L2 header type (802.3 vs. 802.11), + * as specified by ol_cfg_frame_type(). + * + * Return: null - success, skb - failure + */ +qdf_nbuf_t ol_tx_non_std(ol_txrx_vdev_handle vdev, + enum ol_tx_spec tx_spec, qdf_nbuf_t msdu_list); + +/** + * ol_txrx_update_ibss_vdev_heart_beat_timer_of_vdev() - Update ibss vdev heart + * beat timer + * @vdev: vdev handle + * @timer_value_sec: new heart beat timer value + * + * Return: Old timer value set in vdev. + */ +uint16_t ol_txrx_set_ibss_vdev_heart_beat_timer(ol_txrx_vdev_handle vdev, + uint16_t timer_value_sec); +#endif /* _CDP_TXRX_MISC_H_ */ diff --git a/drivers/staging/qca-wifi-host-cmn/dp/inc/cdp_txrx_mon.h b/drivers/staging/qca-wifi-host-cmn/dp/inc/cdp_txrx_mon.h new file mode 100644 index 0000000000000000000000000000000000000000..5597bcc9a4fcd9c4b098ae2ca793380f12f9905c --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/dp/inc/cdp_txrx_mon.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + /** + * @file cdp_txrx_mon.h + * @brief Define the monitor mode API functions + * called by the host control SW and the OS interface module + */ + +#ifndef _CDP_TXRX_MON_H_ +#define _CDP_TXRX_MON_H_ +void ol_txrx_monitor_set_filter_ucast_data(ol_txrx_pdev_handle, u_int8_t val); +void ol_txrx_monitor_set_filter_mcast_data(ol_txrx_pdev_handle, u_int8_t val); +void ol_txrx_monitor_set_filter_non_data(ol_txrx_pdev_handle, u_int8_t val); + +u_int8_t ol_txrx_monitor_get_filter_ucast_data( + ol_txrx_vdev_handle vdev_txrx_handle); +u_int8_t ol_txrx_monitor_get_filter_mcast_data( + ol_txrx_vdev_handle vdev_txrx_handle); +u_int8_t ol_txrx_monitor_get_filter_non_data( + ol_txrx_vdev_handle vdev_txrx_handle); + + +int ol_txrx_reset_monitor_mode(ol_txrx_pdev_handle pdev); + +#endif diff --git a/drivers/staging/qca-wifi-host-cmn/dp/inc/cdp_txrx_ocb.h b/drivers/staging/qca-wifi-host-cmn/dp/inc/cdp_txrx_ocb.h new file mode 100644 index 0000000000000000000000000000000000000000..074637a263d5bc2bca6e434100c5e6b48d9f62cb --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/dp/inc/cdp_txrx_ocb.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef _CDP_TXRX_OCB_H_ +#define _CDP_TXRX_OCB_H_ + +/** + * struct ol_txrx_ocb_set_chan - txrx OCB channel info + * @ocb_channel_count: Channel count + * @ocb_channel_info: OCB channel info + */ +struct ol_txrx_ocb_set_chan { + uint32_t ocb_channel_count; + struct ol_txrx_ocb_chan_info *ocb_channel_info; +}; + +/** + * ol_txrx_set_ocb_chan_info() - set OCB channel info to vdev. + * @vdev: vdev handle + * @ocb_set_chan: OCB channel information to be set in vdev. + * + * Return: NONE + */ +void ol_txrx_set_ocb_chan_info(ol_txrx_vdev_handle vdev, + struct ol_txrx_ocb_set_chan ocb_set_chan); +/** + * ol_txrx_get_ocb_chan_info() - return handle to vdev ocb_channel_info + * @vdev: vdev handle + * + * Return: handle to struct ol_txrx_ocb_chan_info + */ +struct ol_txrx_ocb_chan_info * +ol_txrx_get_ocb_chan_info(ol_txrx_vdev_handle vdev); +#endif /* _CDP_TXRX_OCB_H_ */ diff --git a/drivers/staging/qca-wifi-host-cmn/dp/inc/cdp_txrx_peer_ops.h b/drivers/staging/qca-wifi-host-cmn/dp/inc/cdp_txrx_peer_ops.h new file mode 100644 index 0000000000000000000000000000000000000000..c349f31bc4a1edd97a5468d59ee0f9efa0132f63 --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/dp/inc/cdp_txrx_peer_ops.h @@ -0,0 +1,176 @@ +/* + * Copyright (c) 2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + /** + * @file cdp_txrx_peer.h + * @brief Define the host data path peer API functions + * called by the host control SW and the OS interface module + */ +#ifndef _CDP_TXRX_PEER_H_ +#define _CDP_TXRX_PEER_H_ + +typedef QDF_STATUS (*ol_rx_callback_fp)(void *p_cds_gctx, + qdf_nbuf_t pDataBuff, + uint8_t ucSTAId); + +/** + * struct ol_txrx_peer_state - Peer state information + */ +enum ol_txrx_peer_state { + OL_TXRX_PEER_STATE_INVALID, + OL_TXRX_PEER_STATE_DISC, /* initial state */ + OL_TXRX_PEER_STATE_CONN, /* authentication in progress */ + OL_TXRX_PEER_STATE_AUTH, /* authentication successful */ +}; + +/** + * struct ol_txrx_desc_type - txrx descriptor type + * @sta_id: sta id + * @is_qos_enabled: is station qos enabled + * @is_wapi_supported: is station wapi supported + */ +struct ol_txrx_desc_type { + uint8_t sta_id; + uint8_t is_qos_enabled; + uint8_t is_wapi_supported; +}; + +QDF_STATUS ol_txrx_register_peer(struct ol_txrx_desc_type *sta_desc); + +/** + * ol_txrx_vdev_peer_remove_cb - wma_remove_peer callback + */ +typedef void (*ol_txrx_vdev_peer_remove_cb)(void *handle, uint8_t *bssid, + uint8_t vdev_id, + ol_txrx_peer_handle peer, + bool roam_synch_in_progress); + +QDF_STATUS ol_txrx_clear_peer(uint8_t sta_id); + +QDF_STATUS ol_txrx_change_peer_state(uint8_t sta_id, + enum ol_txrx_peer_state sta_state, + bool roam_synch_in_progress); + +ol_txrx_peer_handle ol_txrx_find_peer_by_addr(ol_txrx_pdev_handle pdev, + uint8_t *peer_addr, + uint8_t *peer_id); + +ol_txrx_peer_handle +ol_txrx_find_peer_by_addr_and_vdev(ol_txrx_pdev_handle pdev, + ol_txrx_vdev_handle vdev, + uint8_t *peer_addr, uint8_t *peer_id); + +#ifdef QCA_SUPPORT_TXRX_LOCAL_PEER_ID +uint16_t ol_txrx_local_peer_id(ol_txrx_peer_handle peer); +ol_txrx_peer_handle ol_txrx_find_peer_by_addr(ol_txrx_pdev_handle pdev, + uint8_t *peer_addr, + uint8_t *peer_id); +ol_txrx_peer_handle +ol_txrx_find_peer_by_addr_and_vdev(ol_txrx_pdev_handle pdev, + ol_txrx_vdev_handle vdev, + uint8_t *peer_addr, uint8_t *peer_id); +ol_txrx_peer_handle +ol_txrx_peer_find_by_local_id(ol_txrx_pdev_handle pdev, uint8_t local_peer_id); +#else +#define ol_txrx_local_peer_id(peer) OL_TXRX_INVALID_LOCAL_PEER_ID +#define ol_txrx_find_peer_by_addr(pdev, peer_addr, peer_id) NULL +#define ol_txrx_find_peer_by_addr_and_vdev(pdev, vdev, peer_addr, peer_id) NULL +#define ol_txrx_peer_find_by_local_id(pdev, local_peer_id) NULL +#endif /* QCA_SUPPORT_TXRX_LOCAL_PEER_ID */ + +QDF_STATUS +ol_txrx_peer_state_update(ol_txrx_pdev_handle pdev, uint8_t *peer_addr, + enum ol_txrx_peer_state state); + +QDF_STATUS ol_txrx_get_vdevid(struct ol_txrx_peer_t *peer, uint8_t *vdev_id); +void *ol_txrx_get_vdev_by_sta_id(uint8_t sta_id); + +QDF_STATUS ol_txrx_register_ocb_peer(void *cds_ctx, uint8_t *mac_addr, + uint8_t *peer_id); + +/** + * ol_txrx_peer_get_peer_mac_addr() - return mac_addr from peer handle. + * @peer: handle to peer + * + * returns mac addrs for module which do not know peer type + * + * Return: the mac_addr from peer + */ +uint8_t *ol_txrx_peer_get_peer_mac_addr(ol_txrx_peer_handle peer); + +/** + * ol_txrx_get_peer_state() - Return peer state of peer + * @peer: peer handle + * + * Return: return peer state + */ +int ol_txrx_get_peer_state(ol_txrx_peer_handle peer); + +/** + * ol_txrx_get_vdev_for_peer() - Return vdev from peer handle + * @peer: peer handle + * + * Return: vdev handle from peer + */ +ol_txrx_vdev_handle +ol_txrx_get_vdev_for_peer(ol_txrx_peer_handle peer); + +/** + * ol_txrx_update_ibss_add_peer_num_of_vdev() - update and return peer num + * @vdev: vdev handle + * @peer_num_delta: peer nums to be adjusted + * + * Return: -1 for failure or total peer nums after adjustment. + */ +int16_t +ol_txrx_update_ibss_add_peer_num_of_vdev(ol_txrx_vdev_handle vdev, + int16_t peer_num_delta); +/** + * ol_txrx_remove_peers_for_vdev() - remove all vdev peers with lock held + * @vdev: vdev handle + * @callback: callback function to remove the peer. + * @callback_context: handle for callback function + * @remove_last_peer: Does it required to last peer. + * + * Return: NONE + */ +void +ol_txrx_remove_peers_for_vdev(ol_txrx_vdev_handle vdev, + ol_txrx_vdev_peer_remove_cb callback, + void *callback_context, bool remove_last_peer); +/** + * ol_txrx_remove_peers_for_vdev_no_lock() - remove vdev peers with no lock. + * @vdev: vdev handle + * @callback: callback function to remove the peer. + * @callback_context: handle for callback function + * + * Return: NONE + */ +void +ol_txrx_remove_peers_for_vdev_no_lock(ol_txrx_vdev_handle vdev, + ol_txrx_vdev_peer_remove_cb callback, + void *callback_context); +#endif /* _CDP_TXRX_PEER_H_ */ diff --git a/drivers/staging/qca-wifi-host-cmn/dp/inc/cdp_txrx_pflow.h b/drivers/staging/qca-wifi-host-cmn/dp/inc/cdp_txrx_pflow.h new file mode 100644 index 0000000000000000000000000000000000000000..43e39ad0cfa1f8958085a40325cfb9942a2105ff --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/dp/inc/cdp_txrx_pflow.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + /** + * @file cdp_txrx_pflow.h + * @brief Define the host data path peer flow API functions + * called by the host control SW and the OS interface module + */ +#ifndef _CDP_TXRX_PFLOW_H_ +#define _CDP_TXRX_PFLOW_H_ + +#include +#if PEER_FLOW_CONTROL +extern uint32_t ol_pflow_update_pdev_params(struct ol_txrx_pdev_t *, + ol_ath_param_t, uint32_t, void *); +#endif +#endif diff --git a/drivers/staging/qca-wifi-host-cmn/dp/inc/cdp_txrx_pmf.h b/drivers/staging/qca-wifi-host-cmn/dp/inc/cdp_txrx_pmf.h new file mode 100644 index 0000000000000000000000000000000000000000..42218c77cf90b306596ee5497ab038a5a1c08334 --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/dp/inc/cdp_txrx_pmf.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ +#ifndef _CDP_TXRX_PMF_H_ +#define _CDP_TXRX_PMF_H_ + +/** + * ol_txrx_get_pn_info() - Returns pn info from peer + * @peer: handle to peer + * @last_pn_valid: return last_rmf_pn_valid value from peer. + * @last_pn: return last_rmf_pn value from peer. + * @rmf_pn_replays: return rmf_pn_replays value from peer. + * + * Return: NONE + */ +void +ol_txrx_get_pn_info(ol_txrx_peer_handle peer, uint8_t **last_pn_valid, + uint64_t **last_pn, uint32_t **rmf_pn_replays); +#endif /* _CDP_TXRX_PMF_H_ */ diff --git a/drivers/staging/qca-wifi-host-cmn/dp/inc/cdp_txrx_raw.h b/drivers/staging/qca-wifi-host-cmn/dp/inc/cdp_txrx_raw.h new file mode 100644 index 0000000000000000000000000000000000000000..0891480242db48488c3e0ed7bae633ab4910a162 --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/dp/inc/cdp_txrx_raw.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + /** + * @file cdp_txrx_raw.h + * @brief Define the host data path raw mode API functions + * called by the host control SW and the OS interface module + */ +#ifndef _CDP_TXRX_RAW_H_ +#define _CDP_TXRX_RAW_H_ + + +/* TODO: adf need to be replaced with qdf */ +extern int ol_txrx_get_nwifi_mode(ol_txrx_vdev_handle vdev); +#define OL_TXRX_GET_NWIFI_MODE(vdev) ol_txrx_get_nwifi_mode(vdev) +/* Questionable -- should this be in OL AND/OR is this used? */ +/* Called by ol_tx_ll_umac_raw_process() */ +/** + * @brief encap nbuf(s) from Ethernet II format to 802.11 Raw format + * @details + * Note that in the case of IP fragments, the function takes two fragments at a + * time and creates an A-MSDU. If it has seen the first of such fragments, it + * returns 0 to indicate that it needs to consume one more. In this case, the + * caller shouldn't pass the nbuf to lower layers. + * The function is simple and doesn't dynamically take decisions on A-MSDU + * formation. It can be extended to pack more fragments into an A-MSDU if + * required, but in this case there can be greater losses due to the + * environment. The objective of the function is only to simulate regular + * scatter/gather. + * + * @param vdev - the data virtual device object + * @param pnbuf - pointer to nbuf + * + * @return - 0 on success, -1 on error, 1 if more nbufs need to be consumed. + */ + +int +ol_rsim_tx_encap(ol_txrx_vdev_handle vdev, qdf_nbuf_t *pnbuf); +#endif diff --git a/drivers/staging/qca-wifi-host-cmn/dp/inc/cdp_txrx_stats.h b/drivers/staging/qca-wifi-host-cmn/dp/inc/cdp_txrx_stats.h new file mode 100644 index 0000000000000000000000000000000000000000..68bdad74ad1bbd61a94c5fd510a2d53d6c27d055 --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/dp/inc/cdp_txrx_stats.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + /** + * @file cdp_txrx_stats.h + * @brief Define the host data path statistics API functions + * called by the host control SW and the OS interface module + */ +#ifndef _CDP_TXRX_STATS_H_ +#define _CDP_TXRX_STATS_H_ +#include + +QDF_STATUS ol_txrx_display_stats(uint16_t bitmap); +QDF_STATUS ol_txrx_clear_stats(uint16_t bitmap); +int ol_txrx_stats(uint8_t vdev_id, char *buffer, unsigned buf_len); + +#endif /* _CDP_TXRX_STATS_H_ */ diff --git a/drivers/staging/qca-wifi-host-cmn/dp/inc/cdp_txrx_stats_struct.h b/drivers/staging/qca-wifi-host-cmn/dp/inc/cdp_txrx_stats_struct.h new file mode 100644 index 0000000000000000000000000000000000000000..32091e1e76801d96969644f414c51d2e3a1fcba4 --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/dp/inc/cdp_txrx_stats_struct.h @@ -0,0 +1,472 @@ +/* + * Copyright (c) 2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + /** + * @file cdp_txrx_stats_struct.h + * @brief Define the host data path stats API functions + * called by the host control SW and the OS interface module + */ +#ifndef _CDP_TXRX_STATS_STRUCT_H_ +#define _CDP_TXRX_STATS_STRUCT_H_ +#include + +#define TXRX_STATS_LEVEL_OFF 0 +#define TXRX_STATS_LEVEL_BASIC 1 +#define TXRX_STATS_LEVEL_FULL 2 + +#ifndef TXRX_STATS_LEVEL +#define TXRX_STATS_LEVEL TXRX_STATS_LEVEL_BASIC +#endif + +#ifndef BIG_ENDIAN_HOST +typedef struct { + u_int32_t pkts; + u_int32_t bytes; +} ol_txrx_stats_elem; +#else +struct ol_txrx_elem_t { + u_int32_t pkts; + u_int32_t bytes; +}; +typedef struct ol_txrx_elem_t ol_txrx_stats_elem; +#endif + +/** + * @brief data stats published by the host txrx layer + */ +struct ol_txrx_stats { + struct { + /* MSDUs received from the stack */ + ol_txrx_stats_elem from_stack; + /* MSDUs successfully sent across the WLAN */ + ol_txrx_stats_elem delivered; + struct { + /* MSDUs that the host did not accept */ + ol_txrx_stats_elem host_reject; + /* MSDUs which could not be downloaded to the + target */ + ol_txrx_stats_elem download_fail; + /* MSDUs which the target discarded + (lack of mem or old age) */ + ol_txrx_stats_elem target_discard; + /* MSDUs which the target sent but couldn't get + an ack for */ + ol_txrx_stats_elem no_ack; + /* MSDUs dropped in NSS-FW */ + ol_txrx_stats_elem nss_ol_dropped; + } dropped; + u_int32_t desc_in_use; + u_int32_t desc_alloc_fails; + u_int32_t ce_ring_full; + u_int32_t dma_map_error; + /* MSDUs given to the txrx layer by the management stack */ + ol_txrx_stats_elem mgmt; +#if (HOST_SW_TSO_ENABLE || HOST_SW_TSO_SG_ENABLE) + struct { + /* TSO applied jumbo packets received from NW Stack */ + ol_txrx_stats_elem tso_pkts; + /* Non - TSO packets */ + ol_txrx_stats_elem non_tso_pkts; + /* TSO packets : Dropped during TCP segmentation*/ + ol_txrx_stats_elem tso_dropped; + /* TSO Descriptors */ + u_int32_t tso_desc_cnt; + } tso; +#endif /* HOST_SW_TSO_ENABLE || HOST_SW_TSO_SG_ENABLE */ + +#if HOST_SW_SG_ENABLE + struct { + /* TSO applied jumbo packets received from NW Stack */ + ol_txrx_stats_elem sg_pkts; + /* Non - TSO packets */ + ol_txrx_stats_elem non_sg_pkts; + /* TSO packets : Dropped during TCP segmentation*/ + ol_txrx_stats_elem sg_dropped; + /* TSO Descriptors */ + u_int32_t sg_desc_cnt; + } sg; +#endif /* HOST_SW_SG_ENABLE */ + struct { + /* packets enqueued for flow control */ + u_int32_t fl_ctrl_enqueue; + /* packets discarded for flow control is full */ + u_int32_t fl_ctrl_discard; + /* packets sent to CE without flow control */ + u_int32_t fl_ctrl_avoid; + } fl_ctrl; + } tx; + struct { + /* MSDUs given to the OS shim */ + ol_txrx_stats_elem delivered; + /* MSDUs forwarded from the rx path to the tx path */ + ol_txrx_stats_elem forwarded; +#if RX_CHECKSUM_OFFLOAD + /* MSDUs in which ipv4 chksum error detected by HW */ + ol_txrx_stats_elem ipv4_cksum_err; + /* MSDUs in which tcp chksum error detected by HW */ + ol_txrx_stats_elem tcp_ipv4_cksum_err; + /* MSDUs in which udp chksum error detected by HW */ + ol_txrx_stats_elem udp_ipv4_cksum_err; + /* MSDUs in which tcp V6 chksum error detected by HW */ + ol_txrx_stats_elem tcp_ipv6_cksum_err; + /* MSDUs in which UDP V6 chksum error detected by HW */ + ol_txrx_stats_elem udp_ipv6_cksum_err; +#endif /* RX_CHECKSUM_OFFLOAD */ + } rx; + struct { + /* Number of mcast recieved for conversion */ + u_int32_t num_me_rcvd; + /* Number of unicast sent as part of mcast conversion */ + u_int32_t num_me_ucast; + /* Number of multicast frames dropped due to dma_map failure */ + u_int32_t num_me_dropped_m; + /* Number of multicast frames dropped due to allocation + failure */ + u_int32_t num_me_dropped_a; + /* Number of multicast frames dropped due to internal failure */ + u_int32_t num_me_dropped_i; + /* Number of me buf currently in use */ + u_int32_t num_me_buf; + /* Number of me buf frames to self mac address */ + u_int32_t num_me_dropped_s; + /* Number of me buf in use in non pool based allocation*/ + u_int32_t num_me_nonpool; + /* Number of me buf allocated using non pool based allocation*/ + u_int32_t num_me_nonpool_count; + } mcast_enhance; +}; + +struct ol_ath_dbg_rx_rssi { + A_UINT8 rx_rssi_pri20; + A_UINT8 rx_rssi_sec20; + A_UINT8 rx_rssi_sec40; + A_UINT8 rx_rssi_sec80; +}; + +struct ol_ath_radiostats { + A_UINT64 tx_beacon; + A_UINT32 be_nobuf; + A_UINT32 tx_buf_count; + A_UINT32 tx_packets; + A_UINT32 rx_packets; + A_INT32 tx_mgmt; + A_UINT32 tx_num_data; + A_UINT32 rx_num_data; + A_INT32 rx_mgmt; + A_UINT32 rx_num_mgmt; + A_UINT32 rx_num_ctl; + A_UINT32 tx_rssi; + A_UINT32 tx_mcs[10]; + A_UINT32 rx_mcs[10]; + A_UINT32 rx_rssi_comb; + struct ol_ath_dbg_rx_rssi rx_rssi_chain0; + struct ol_ath_dbg_rx_rssi rx_rssi_chain1; + struct ol_ath_dbg_rx_rssi rx_rssi_chain2; + struct ol_ath_dbg_rx_rssi rx_rssi_chain3; + A_UINT64 rx_bytes; + A_UINT64 tx_bytes; + A_UINT32 tx_compaggr; + A_UINT32 rx_aggr; + A_UINT32 tx_bawadv; + A_UINT32 tx_compunaggr; + A_UINT32 rx_overrun; + A_UINT32 rx_badcrypt; + A_UINT32 rx_badmic; + A_UINT32 rx_crcerr; + A_UINT32 rx_phyerr; + A_UINT32 ackRcvBad; + A_UINT32 rtsBad; + A_UINT32 rtsGood; + A_UINT32 fcsBad; + A_UINT32 noBeacons; + A_UINT32 mib_int_count; + A_UINT32 rx_looplimit_start; + A_UINT32 rx_looplimit_end; + A_UINT8 ap_stats_tx_cal_enable; + A_UINT32 tgt_asserts; + A_INT16 chan_nf; + A_UINT32 rx_last_msdu_unset_cnt; + A_INT16 chan_nf_sec80; +}; + +/* +** structure to hold all stats information +** for offload device interface +*/ +struct ol_stats { + int txrx_stats_level; + struct ol_txrx_stats txrx_stats; + struct wlan_dbg_stats stats; + struct ol_ath_radiostats interface_stats; + struct wlan_dbg_tidq_stats tidq_stats; +}; + +/* +** Enumeration of PDEV Configuration parameter +*/ +typedef enum _ol_ath_param_t { + OL_ATH_PARAM_TXCHAINMASK = 1, + OL_ATH_PARAM_RXCHAINMASK = 2, + OL_ATH_PARAM_AMPDU = 6, + OL_ATH_PARAM_AMPDU_LIMIT = 7, + OL_ATH_PARAM_AMPDU_SUBFRAMES = 8, + OL_ATH_PARAM_TXPOWER_LIMIT2G = 12, + OL_ATH_PARAM_TXPOWER_LIMIT5G = 13, + OL_ATH_PARAM_LDPC = 32, + OL_ATH_PARAM_VOW_EXT_STATS = 45, + OL_ATH_PARAM_DYN_TX_CHAINMASK = 73, + OL_ATH_PARAM_BURST_ENABLE = 77, + OL_ATH_PARAM_BURST_DUR = 78, + OL_ATH_PARAM_BCN_BURST = 80, + OL_ATH_PARAM_DCS = 82, +#if UMAC_SUPPORT_PERIODIC_PERFSTATS + OL_ATH_PARAM_PRDPERFSTAT_THRPUT_ENAB = 83, + OL_ATH_PARAM_PRDPERFSTAT_THRPUT_WIN = 84, + OL_ATH_PARAM_PRDPERFSTAT_THRPUT = 85, + OL_ATH_PARAM_PRDPERFSTAT_PER_ENAB = 86, + OL_ATH_PARAM_PRDPERFSTAT_PER_WIN = 87, + OL_ATH_PARAM_PRDPERFSTAT_PER = 88, +#endif + /* UMAC_SUPPORT_PERIODIC_PERFSTATS */ + OL_ATH_PARAM_TOTAL_PER = 89, + /*set manual rate for rts frame */ + OL_ATH_PARAM_RTS_CTS_RATE = 92, + /** co channel interference threshold level */ + OL_ATH_PARAM_DCS_COCH_THR = 93, + /** transmit error threshold */ + OL_ATH_PARAM_DCS_TXERR_THR = 94, + /** phy error threshold */ + OL_ATH_PARAM_DCS_PHYERR_THR = 95, + /* The IOCTL number is 114, it is made 114, inorder to make the IOCTL + number same as Direct-attach IOCTL. + Please, don't change number. This IOCTL gets the Interface code path + it should be either DIRECT-ATTACH or OFF-LOAD. + */ + OL_ATH_PARAM_GET_IF_ID = 114, + /*Enable Acs back Ground Channel selection Scan timer in AP mode*/ + OL_ATH_PARAM_ACS_ENABLE_BK_SCANTIMEREN = 118, + /* ACS scan timer value in Seconds */ + OL_ATH_PARAM_ACS_SCANTIME = 119, + /*Negligence Delta RSSI between two channel */ + OL_ATH_PARAM_ACS_RSSIVAR = 120, + /*Negligence Delta Channel load between two channel*/ + OL_ATH_PARAM_ACS_CHLOADVAR = 121, + /* Enable Limited OBSS check */ + OL_ATH_PARAM_ACS_LIMITEDOBSS = 122, + /* Acs control flag for Scan timer */ + OL_ATH_PARAM_ACS_CTRLFLAG = 123, + /* Acs Run time Debug level*/ + OL_ATH_PARAM_ACS_DEBUGTRACE = 124, + OL_ATH_PARAM_SET_FW_HANG_ID = 137, + /* Radio type 1:11ac 0:11abgn */ + OL_ATH_PARAM_RADIO_TYPE = 138, + OL_ATH_PARAM_IGMPMLD_OVERRIDE, /* IGMP/MLD packet override */ + OL_ATH_PARAM_IGMPMLD_TID, /* IGMP/MLD packet TID no */ + OL_ATH_PARAM_ARPDHCP_AC_OVERRIDE, + OL_ATH_PARAM_NON_AGG_SW_RETRY_TH, + OL_ATH_PARAM_AGG_SW_RETRY_TH, + /* Dont change this number it as per sync with DA + Blocking certian channel from ic channel list */ + OL_ATH_PARAM_DISABLE_DFS = 144, + OL_ATH_PARAM_ENABLE_AMSDU = 145, + OL_ATH_PARAM_ENABLE_AMPDU = 146, + OL_ATH_PARAM_STA_KICKOUT_TH, + OL_ATH_PARAM_WLAN_PROF_ENABLE, + OL_ATH_PARAM_LTR_ENABLE, + OL_ATH_PARAM_LTR_AC_LATENCY_BE = 150, + OL_ATH_PARAM_LTR_AC_LATENCY_BK, + OL_ATH_PARAM_LTR_AC_LATENCY_VI, + OL_ATH_PARAM_LTR_AC_LATENCY_VO, + OL_ATH_PARAM_LTR_AC_LATENCY_TIMEOUT, + OL_ATH_PARAM_LTR_TX_ACTIVITY_TIMEOUT = 155, + OL_ATH_PARAM_LTR_SLEEP_OVERRIDE, + OL_ATH_PARAM_LTR_RX_OVERRIDE, + OL_ATH_PARAM_L1SS_ENABLE, + OL_ATH_PARAM_DSLEEP_ENABLE, + /** radar error threshold */ + OL_ATH_PARAM_DCS_RADAR_ERR_THR = 160, + /** Tx channel utilization due to AP's tx and rx */ + OL_ATH_PARAM_DCS_USERMAX_CU_THR, + /** interference detection threshold */ + OL_ATH_PARAM_DCS_INTR_DETECT_THR, + /** sampling window, default 10secs */ + OL_ATH_PARAM_DCS_SAMPLE_WINDOW, + /** debug logs enable/disable */ + OL_ATH_PARAM_DCS_DEBUG, + OL_ATH_PARAM_ANI_ENABLE = 165, + OL_ATH_PARAM_ANI_POLL_PERIOD, + OL_ATH_PARAM_ANI_LISTEN_PERIOD, + OL_ATH_PARAM_ANI_OFDM_LEVEL, + OL_ATH_PARAM_ANI_CCK_LEVEL, + OL_ATH_PARAM_DSCP_TID_MAP = 170, + OL_ATH_PARAM_TXPOWER_SCALE, + /** Phy error penalty */ + OL_ATH_PARAM_DCS_PHYERR_PENALTY, +#if ATH_SUPPORT_DSCP_OVERRIDE + /** set/get TID for sending HMMC packets */ + OL_ATH_PARAM_HMMC_DSCP_TID_MAP, + /** set/get DSCP mapping override */ + OL_ATH_PARAM_DSCP_OVERRIDE, + /** set/get HMMC-DSCP mapping override */ + OL_ATH_PARAM_HMMC_DSCP_OVERRIDE = 175, +#endif +#if ATH_RX_LOOPLIMIT_TIMER + OL_ATH_PARAM_LOOPLIMIT_NUM, +#endif + OL_ATH_PARAM_ANTENNA_GAIN_2G, + OL_ATH_PARAM_ANTENNA_GAIN_5G, + OL_ATH_PARAM_RX_FILTER, +#if ATH_SUPPORT_HYFI_ENHANCEMENTS + OL_ATH_PARAM_BUFF_THRESH = 180, + OL_ATH_PARAM_BLK_REPORT_FLOOD, + OL_ATH_PARAM_DROP_STA_QUERY, +#endif + OL_ATH_PARAM_QBOOST, + OL_ATH_PARAM_SIFS_FRMTYPE, + OL_ATH_PARAM_SIFS_UAPSD = 185, + OL_ATH_PARAM_FW_RECOVERY_ID, + OL_ATH_PARAM_RESET_OL_STATS, + OL_ATH_PARAM_AGGR_BURST, + /* Number of deauth sent in consecutive rx_peer_invalid */ + OL_ATH_PARAM_DEAUTH_COUNT, + OL_ATH_PARAM_BLOCK_INTERBSS = 190, + /* Firmware reset control for Bmiss / timeout / reset */ + OL_ATH_PARAM_FW_DISABLE_RESET, + OL_ATH_PARAM_MSDU_TTL, + OL_ATH_PARAM_PPDU_DURATION, + OL_ATH_PARAM_SET_TXBF_SND_PERIOD, + OL_ATH_PARAM_ALLOW_PROMISC = 195, + OL_ATH_PARAM_BURST_MODE, + OL_ATH_PARAM_DYN_GROUPING, + OL_ATH_PARAM_DPD_ENABLE, + OL_ATH_PARAM_DBGLOG_RATELIM, + /* firmware should intimate us about ps state change for node */ + OL_ATH_PARAM_PS_STATE_CHANGE = 200, + OL_ATH_PARAM_MCAST_BCAST_ECHO, + /* OBSS RSSI threshold for 20/40 coexistance */ + OL_ATH_PARAM_OBSS_RSSI_THRESHOLD, + /* Link/node RX RSSI threshold for 20/40 coexistance */ + OL_ATH_PARAM_OBSS_RX_RSSI_THRESHOLD, +#if ATH_CHANNEL_BLOCKING + OL_ATH_PARAM_ACS_BLOCK_MODE = 205, +#endif + OL_ATH_PARAM_ACS_TX_POWER_OPTION, + /* Default Antenna Polarization MSB 8 bits (24:31) specifying + enable/disable ; LSB 24 bits (0:23) antenna mask value */ + OL_ATH_PARAM_ANT_POLARIZATION, + /* rate limit mute type error prints */ + OL_ATH_PARAM_PRINT_RATE_LIMIT, + OL_ATH_PARAM_PDEV_RESET, /* Reset FW PDEV*/ + /*Do not crash host when target assert happened*/ + OL_ATH_PARAM_FW_DUMP_NO_HOST_CRASH = 210, + /*Consider OBSS non-erp to change to long slot*/ + OL_ATH_PARAM_CONSIDER_OBSS_NON_ERP_LONG_SLOT = 211, +#if PEER_FLOW_CONTROL + OL_ATH_PARAM_STATS_FC, + OL_ATH_PARAM_QFLUSHINTERVAL, + OL_ATH_PARAM_TOTAL_Q_SIZE, + OL_ATH_PARAM_TOTAL_Q_SIZE_RANGE0, + OL_ATH_PARAM_TOTAL_Q_SIZE_RANGE1, + OL_ATH_PARAM_TOTAL_Q_SIZE_RANGE2, + OL_ATH_PARAM_TOTAL_Q_SIZE_RANGE3, + OL_ATH_PARAM_MIN_THRESHOLD, + OL_ATH_PARAM_MAX_Q_LIMIT, + OL_ATH_PARAM_MIN_Q_LIMIT, + OL_ATH_PARAM_CONG_CTRL_TIMER_INTV, + OL_ATH_PARAM_STATS_TIMER_INTV, + OL_ATH_PARAM_ROTTING_TIMER_INTV, + OL_ATH_PARAM_LATENCY_PROFILE, + OL_ATH_PARAM_HOSTQ_DUMP, + OL_ATH_PARAM_TIDQ_MAP, +#endif + OL_ATH_PARAM_DBG_ARP_SRC_ADDR, /* ARP DEBUG source address*/ + OL_ATH_PARAM_DBG_ARP_DST_ADDR, /* ARP DEBUG destination address*/ + OL_ATH_PARAM_ARP_DBG_CONF, /* ARP debug configuration */ + OL_ATH_PARAM_DISABLE_STA_VAP_AMSDU, /* Disable AMSDU for station vap */ +#if ATH_SUPPORT_DFS && ATH_SUPPORT_STA_DFS + OL_ATH_PARAM_STADFS_ENABLE = 300, /* STA DFS is enabled or not */ +#endif +#if QCA_AIRTIME_FAIRNESS + OL_ATH_PARAM_ATF_STRICT_SCHED = 301, + OL_ATH_PARAM_ATF_GROUP_POLICY = 302, +#endif +#if DBDC_REPEATER_SUPPORT + OL_ATH_PARAM_PRIMARY_RADIO, + OL_ATH_PARAM_DBDC_ENABLE, +#endif + OL_ATH_PARAM_TXPOWER_DBSCALE, + OL_ATH_PARAM_CTL_POWER_SCALE, +#if QCA_AIRTIME_FAIRNESS + OL_ATH_PARAM_ATF_OBSS_SCHED = 307, + OL_ATH_PARAM_ATF_OBSS_SCALE = 308, +#endif + OL_ATH_PARAM_PHY_OFDM_ERR = 309, + OL_ATH_PARAM_PHY_CCK_ERR = 310, + OL_ATH_PARAM_FCS_ERR = 311, + OL_ATH_PARAM_CHAN_UTIL = 312, +#if DBDC_REPEATER_SUPPORT + OL_ATH_PARAM_CLIENT_MCAST, +#endif + OL_ATH_PARAM_EMIWAR_80P80 = 314, + OL_ATH_PARAM_BATCHMODE = 315, + OL_ATH_PARAM_PACK_AGGR_DELAY = 316, +#if UMAC_SUPPORT_ACFG + OL_ATH_PARAM_DIAG_ENABLE = 317, +#endif +#if ATH_SUPPORT_VAP_QOS + OL_ATH_PARAM_VAP_QOS = 318, +#endif + OL_ATH_PARAM_CHAN_STATS_TH = 319, + /* Passive scan is enabled or disabled */ + OL_ATH_PARAM_PASSIVE_SCAN_ENABLE = 320, + OL_ATH_MIN_RSSI_ENABLE = 321, + OL_ATH_MIN_RSSI = 322, + OL_ATH_PARAM_ACS_2G_ALLCHAN = 323, +#if DBDC_REPEATER_SUPPORT + OL_ATH_PARAM_DELAY_STAVAP_UP = 324, +#endif + OL_ATH_PARAM_TXPOW_MGMT = 326, /* Can be used to configure transmit power for management frames */ + OL_ATH_PARAM_CHANSWITCH_OPTIONS = 327, /* It is used to set the channel switch options */ + OL_ATH_BTCOEX_ENABLE = 328, + OL_ATH_BTCOEX_WL_PRIORITY = 329, + OL_ATH_PARAM_TID_OVERRIDE_QUEUE_MAPPING = 330, + OL_ATH_PARAM_CAL_VER_CHECK = 331, + OL_ATH_PARAM_NO_VLAN = 332, + OL_ATH_PARAM_CCA_THRESHOLD = 333, +} ol_ath_param_t; + +/* +** Enumeration of PDEV Configuration parameter +*/ + +typedef enum _ol_hal_param_t { + OL_HAL_CONFIG_DMA_BEACON_RESPONSE_TIME = 0 +} ol_hal_param_t; + + +/* Bitmasks for stats that can block */ +#define EXT_TXRX_FW_STATS 0x0001 +#endif diff --git a/drivers/staging/qca-wifi-host-cmn/dp/inc/cdp_txrx_tx_delay.h b/drivers/staging/qca-wifi-host-cmn/dp/inc/cdp_txrx_tx_delay.h new file mode 100644 index 0000000000000000000000000000000000000000..16c749c0cd43a5982d436d7a698095a8cc3ee21f --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/dp/inc/cdp_txrx_tx_delay.h @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + /** + * @file cdp_txrx_tx_delay.h + * @brief Define the host data path histogram API functions + * called by the host control SW and the OS interface module + */ +#ifndef _CDP_TXRX_COMPUTE_TX_DELAY_H_ +#define _CDP_TXRX_COMPUTE_TX_DELAY_H_ + +#ifdef QCA_COMPUTE_TX_DELAY +void +ol_tx_delay(ol_txrx_pdev_handle pdev, + uint32_t *queue_delay_microsec, + uint32_t *tx_delay_microsec, int category); +void +ol_tx_delay_hist(ol_txrx_pdev_handle pdev, + uint16_t *bin_values, int category); +void +ol_tx_packet_count(ol_txrx_pdev_handle pdev, + uint16_t *out_packet_count, + uint16_t *out_packet_loss_count, int category); +void ol_tx_set_compute_interval(ol_txrx_pdev_handle pdev, + uint32_t interval); +#else +static inline void +ol_tx_delay(ol_txrx_pdev_handle pdev, + uint32_t *queue_delay_microsec, + uint32_t *tx_delay_microsec, int category) +{ + return; +} + +static inline void +ol_tx_delay_hist(ol_txrx_pdev_handle pdev, + uint16_t *bin_values, int category) +{ + return; +} + +static inline void +ol_tx_packet_count(ol_txrx_pdev_handle pdev, + uint16_t *out_packet_count, + uint16_t *out_packet_loss_count, int category) +{ + return; +} + +static inline void +ol_tx_set_compute_interval(ol_txrx_pdev_handle pdev, + uint32_t interval) +{ + return; +} +#endif + +#endif /* _CDP_TXRX_COMPUTE_TX_DELAY_H_ */ diff --git a/drivers/staging/qca-wifi-host-cmn/dp/inc/cdp_txrx_tx_throttle.h b/drivers/staging/qca-wifi-host-cmn/dp/inc/cdp_txrx_tx_throttle.h new file mode 100644 index 0000000000000000000000000000000000000000..7f64a8a6a8f62c4ba75fbdcd868a46456b05cdb4 --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/dp/inc/cdp_txrx_tx_throttle.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + /** + * @file cdp_txrx_tx_throttle.h + * @brief Define the host data path transmit throttle API + * functions called by the host control SW and the OS interface + * module + */ +#ifndef _CDP_TXRX_TX_THROTTLE_H_ +#define _CDP_TXRX_TX_THROTTLE_H_ + +#if defined(QCA_SUPPORT_TX_THROTTLE) +void ol_tx_throttle_init_period(struct ol_txrx_pdev_t *pdev, int period, + uint8_t *dutycycle_level); + +void ol_tx_throttle_set_level(struct ol_txrx_pdev_t *pdev, int level); +#else +static inline void ol_tx_throttle_set_level(struct ol_txrx_pdev_t *pdev, + int level) +{ + /* no-op */ +} + +static inline void ol_tx_throttle_init_period(struct ol_txrx_pdev_t *pdev, + int period, + uint8_t *dutycycle_level) +{ + /* no-op */ +} +#endif +#endif /* _CDP_TXRX_TX_THROTTLE_H_ */ diff --git a/drivers/staging/qca-wifi-host-cmn/dp/inc/cdp_txrx_wds.h b/drivers/staging/qca-wifi-host-cmn/dp/inc/cdp_txrx_wds.h new file mode 100644 index 0000000000000000000000000000000000000000..f5249502625a2fbf9d164427b2a8e4eaae155f16 --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/dp/inc/cdp_txrx_wds.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + /** + * @file cdp_txrx_wds.h + * @brief Define the host data path WDS API functions + * called by the host control SW and the OS interface module + */ +#ifndef _CDP_TXRX_WDS_H_ +#define _CDP_TXRX_WDS_H_ + +/** + * @brief set the wds rx filter policy of the device + * @details + * This flag sets the wds rx policy on the vdev. Rx frames not compliant + * with the policy will be dropped. + * + * @param vdev - the data virtual device object + * @param val - the wds rx policy bitmask + * @return - void + */ +#if WDS_VENDOR_EXTENSION +void +ol_txrx_set_wds_rx_policy( + ol_txrx_vdev_handle vdev, + u_int32_t val); +#endif +#endif diff --git a/drivers/staging/qca-wifi-host-cmn/hif/inc/hif.h b/drivers/staging/qca-wifi-host-cmn/hif/inc/hif.h new file mode 100644 index 0000000000000000000000000000000000000000..39a0a81259a8196cdbde400863cb7d0c3c7b4a5e --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/hif/inc/hif.h @@ -0,0 +1,727 @@ +/* + * Copyright (c) 2013-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef _HIF_H_ +#define _HIF_H_ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* Header files */ +#include +#include "qdf_nbuf.h" +#include "ol_if_athvar.h" +#include +#ifdef HIF_PCI +#include +#endif /* HIF_PCI */ +#ifdef HIF_USB +#include +#endif /* HIF_USB */ +#ifdef IPA_OFFLOAD +#include +#endif +#define ENABLE_MBOX_DUMMY_SPACE_FEATURE 1 + +typedef struct htc_callbacks HTC_CALLBACKS; +typedef void __iomem *A_target_id_t; +typedef void *hif_handle_t; + +#define HIF_TYPE_AR6002 2 +#define HIF_TYPE_AR6003 3 +#define HIF_TYPE_AR6004 5 +#define HIF_TYPE_AR9888 6 +#define HIF_TYPE_AR6320 7 +#define HIF_TYPE_AR6320V2 8 +/* For attaching Peregrine 2.0 board host_reg_tbl only */ +#define HIF_TYPE_AR9888V2 9 +#define HIF_TYPE_ADRASTEA 10 +#define HIF_TYPE_AR900B 11 +#define HIF_TYPE_QCA9984 12 +#define HIF_TYPE_IPQ4019 13 +#define HIF_TYPE_QCA9888 14 + +/* TARGET definition needs to be abstracted in fw common + * header files, below is the placeholder till WIN codebase + * moved to latest copy of fw common header files. + */ +#ifdef CONFIG_WIN +#define TARGET_TYPE_UNKNOWN 0 +#define TARGET_TYPE_AR6001 1 +#define TARGET_TYPE_AR6002 2 +#define TARGET_TYPE_AR6003 3 +#define TARGET_TYPE_AR6004 5 +#define TARGET_TYPE_AR6006 6 +#define TARGET_TYPE_AR9888 7 +#define TARGET_TYPE_AR6320 8 +#define TARGET_TYPE_AR900B 9 +#define TARGET_TYPE_QCA9984 10 +#define TARGET_TYPE_IPQ4019 11 +#define TARGET_TYPE_QCA9888 12 +/* For attach Peregrine 2.0 board target_reg_tbl only */ +#define TARGET_TYPE_AR9888V2 13 +/* For attach Rome1.0 target_reg_tbl only*/ +#define TARGET_TYPE_AR6320V1 14 +/* For Rome2.0/2.1 target_reg_tbl ID*/ +#define TARGET_TYPE_AR6320V2 15 +/* For Rome3.0 target_reg_tbl ID*/ +#define TARGET_TYPE_AR6320V3 16 +/* For Tufello1.0 target_reg_tbl ID*/ +#define TARGET_TYPE_QCA9377V1 17 +/* For Adrastea target */ +#define TARGET_TYPE_ADRASTEA 19 +#endif + +#ifdef IPA_OFFLOAD +#define DMA_COHERENT_MASK_IPA_VER_3_AND_ABOVE 37 +#define DMA_COHERENT_MASK_BELOW_IPA_VER_3 32 +#endif + +struct CE_state; +#define CE_COUNT_MAX 12 + +#ifdef CONFIG_SLUB_DEBUG_ON +#define QCA_NAPI_BUDGET 64 +#define QCA_NAPI_DEF_SCALE 2 +#else /* PERF build */ +#define QCA_NAPI_BUDGET 64 +#define QCA_NAPI_DEF_SCALE 16 +#endif /* SLUB_DEBUG_ON */ +#define HIF_NAPI_MAX_RECEIVES (QCA_NAPI_BUDGET * QCA_NAPI_DEF_SCALE) + +/* NOTE: "napi->scale" can be changed, + but this does not change the number of buckets */ +#define QCA_NAPI_NUM_BUCKETS 4 +struct qca_napi_stat { + uint32_t napi_schedules; + uint32_t napi_polls; + uint32_t napi_completes; + uint32_t napi_workdone; + uint32_t cpu_corrected; + uint32_t napi_budget_uses[QCA_NAPI_NUM_BUCKETS]; + uint32_t time_limit_reached; + uint32_t rxpkt_thresh_reached; +}; + +/** + * per NAPI instance data structure + * This data structure holds stuff per NAPI instance. + * Note that, in the current implementation, though scale is + * an instance variable, it is set to the same value for all + * instances. + */ +struct qca_napi_info { + struct net_device netdev; /* dummy net_dev */ + void *hif_ctx; + struct napi_struct napi; + uint8_t scale; /* currently same on all instances */ + uint8_t id; + uint8_t cpu; + int irq; + struct qca_napi_stat stats[NR_CPUS]; + /* will only be present for data rx CE's */ + void (*lro_flush_cb)(void *); + void *lro_ctx; +}; + +/** + * struct qca_napi_cpu - an entry of the napi cpu table + * @core_id: physical core id of the core + * @cluster_id: cluster this core belongs to + * @core_mask: mask to match all core of this cluster + * @thread_mask: mask for this core within the cluster + * @max_freq: maximum clock this core can be clocked at + * same for all cpus of the same core. + * @napis: bitmap of napi instances on this core + * cluster_nxt: chain to link cores within the same cluster + * + * This structure represents a single entry in the napi cpu + * table. The table is part of struct qca_napi_data. + * This table is initialized by the init function, called while + * the first napi instance is being created, updated by hotplug + * notifier and when cpu affinity decisions are made (by throughput + * detection), and deleted when the last napi instance is removed. + */ +enum qca_napi_tput_state { + QCA_NAPI_TPUT_UNINITIALIZED, + QCA_NAPI_TPUT_LO, + QCA_NAPI_TPUT_HI +}; +enum qca_napi_cpu_state { + QCA_NAPI_CPU_UNINITIALIZED, + QCA_NAPI_CPU_DOWN, + QCA_NAPI_CPU_UP }; +struct qca_napi_cpu { + enum qca_napi_cpu_state state; + int core_id; + int cluster_id; + cpumask_t core_mask; + cpumask_t thread_mask; + unsigned int max_freq; + uint32_t napis; + int cluster_nxt; /* index, not pointer */ +}; + +/** + * NAPI data-structure common to all NAPI instances. + * + * A variable of this type will be stored in hif module context. + */ +struct qca_napi_data { + qdf_spinlock_t lock; + uint32_t state; + uint32_t ce_map; /* bitmap of created/registered NAPI + instances, indexed by pipe_id, + not used by clients (clients use an + id returned by create) */ + struct qca_napi_info *napis[CE_COUNT_MAX]; + struct qca_napi_cpu napi_cpu[NR_CPUS]; + int lilcl_head, bigcl_head; + enum qca_napi_tput_state napi_mode; + struct notifier_block hnc_cpu_notifier; + uint8_t flags; +}; + +/** + * struct hif_config_info - Place Holder for hif confiruation + * @enable_self_recovery: Self Recovery + * + * Structure for holding hif ini parameters. + */ +struct hif_config_info { + bool enable_self_recovery; +#ifdef FEATURE_RUNTIME_PM + bool enable_runtime_pm; + u_int32_t runtime_pm_delay; +#endif +}; + +/** + * struct hif_target_info - Target Information + * @target_version: Target Version + * @target_type: Target Type + * @target_revision: Target Revision + * @soc_version: SOC Version + * + * Structure to hold target information. + */ +struct hif_target_info { + uint32_t target_version; + uint32_t target_type; + uint32_t target_revision; + uint32_t soc_version; + char *hw_name; +}; + +struct hif_opaque_softc { +}; + +typedef enum { + HIF_DEVICE_POWER_UP, /* HIF layer should power up interface + * and/or module */ + HIF_DEVICE_POWER_DOWN, /* HIF layer should initiate bus-specific + * measures to minimize power */ + HIF_DEVICE_POWER_CUT /* HIF layer should initiate bus-specific + * AND/OR platform-specific measures + * to completely power-off the module and + * associated hardware (i.e. cut power + * supplies) */ +} HIF_DEVICE_POWER_CHANGE_TYPE; + +/** + * enum hif_enable_type: what triggered the enabling of hif + * + * @HIF_ENABLE_TYPE_PROBE: probe triggered enable + * @HIF_ENABLE_TYPE_REINIT: reinit triggered enable + */ +enum hif_enable_type { + HIF_ENABLE_TYPE_PROBE, + HIF_ENABLE_TYPE_REINIT, + HIF_ENABLE_TYPE_MAX +}; + +/** + * enum hif_disable_type: what triggered the disabling of hif + * + * @HIF_DISABLE_TYPE_PROBE_ERROR: probe error triggered disable + * @HIF_DISABLE_TYPE_REINIT_ERROR: reinit error triggered + * disable + * @HIF_DISABLE_TYPE_REMOVE: remove triggered disable + * @HIF_DISABLE_TYPE_SHUTDOWN: shutdown triggered disable + */ +enum hif_disable_type { + HIF_DISABLE_TYPE_PROBE_ERROR, + HIF_DISABLE_TYPE_REINIT_ERROR, + HIF_DISABLE_TYPE_REMOVE, + HIF_DISABLE_TYPE_SHUTDOWN, + HIF_DISABLE_TYPE_MAX +}; +/** + * enum hif_device_config_opcode: configure mode + * + * @HIF_DEVICE_POWER_STATE: device power state + * @HIF_DEVICE_GET_MBOX_BLOCK_SIZE: get mbox block size + * @HIF_DEVICE_GET_MBOX_ADDR: get mbox block address + * @HIF_DEVICE_GET_PENDING_EVENTS_FUNC: get pending events functions + * @HIF_DEVICE_GET_IRQ_PROC_MODE: get irq proc mode + * @HIF_DEVICE_GET_RECV_EVENT_MASK_UNMASK_FUNC: receive event function + * @HIF_DEVICE_POWER_STATE_CHANGE: change power state + * @HIF_DEVICE_GET_IRQ_YIELD_PARAMS: get yield params + * @HIF_CONFIGURE_QUERY_SCATTER_REQUEST_SUPPORT: configure scatter request + * @HIF_DEVICE_GET_OS_DEVICE: get OS device + * @HIF_DEVICE_DEBUG_BUS_STATE: debug bus state + * @HIF_BMI_DONE: bmi done + * @HIF_DEVICE_SET_TARGET_TYPE: set target type + * @HIF_DEVICE_SET_HTC_CONTEXT: set htc context + * @HIF_DEVICE_GET_HTC_CONTEXT: get htc context + */ +enum hif_device_config_opcode { + HIF_DEVICE_POWER_STATE = 0, + HIF_DEVICE_GET_MBOX_BLOCK_SIZE, + HIF_DEVICE_GET_MBOX_ADDR, + HIF_DEVICE_GET_PENDING_EVENTS_FUNC, + HIF_DEVICE_GET_IRQ_PROC_MODE, + HIF_DEVICE_GET_RECV_EVENT_MASK_UNMASK_FUNC, + HIF_DEVICE_POWER_STATE_CHANGE, + HIF_DEVICE_GET_IRQ_YIELD_PARAMS, + HIF_CONFIGURE_QUERY_SCATTER_REQUEST_SUPPORT, + HIF_DEVICE_GET_OS_DEVICE, + HIF_DEVICE_DEBUG_BUS_STATE, + HIF_BMI_DONE, + HIF_DEVICE_SET_TARGET_TYPE, + HIF_DEVICE_SET_HTC_CONTEXT, + HIF_DEVICE_GET_HTC_CONTEXT, +}; + +#ifdef CONFIG_ATH_PCIE_ACCESS_DEBUG +typedef struct _HID_ACCESS_LOG { + uint32_t seqnum; + bool is_write; + void *addr; + uint32_t value; +} HIF_ACCESS_LOG; +#endif + +void hif_reg_write(struct hif_opaque_softc *hif_ctx, uint32_t offset, + uint32_t value); +uint32_t hif_reg_read(struct hif_opaque_softc *hif_ctx, uint32_t offset); + +#define HIF_MAX_DEVICES 1 + +struct htc_callbacks { + void *context; /* context to pass to the dsrhandler + * note : rwCompletionHandler is provided + * the context passed to hif_read_write */ + QDF_STATUS(*rwCompletionHandler)(void *rwContext, QDF_STATUS status); + QDF_STATUS(*dsrHandler)(void *context); +}; + +/** + * struct hif_driver_state_callbacks - Callbacks for HIF to query Driver state + * @context: Private data context + * @set_recovery_in_progress: To Set Driver state for recovery in progress + * @is_recovery_in_progress: Query if driver state is recovery in progress + * @is_load_unload_in_progress: Query if driver state Load/Unload in Progress + * @is_driver_unloading: Query if driver is unloading. + * + * This Structure provides callback pointer for HIF to query hdd for driver + * states. + */ +struct hif_driver_state_callbacks { + void *context; + void (*set_recovery_in_progress)(void *context, uint8_t val); + bool (*is_recovery_in_progress)(void *context); + bool (*is_load_unload_in_progress)(void *context); + bool (*is_driver_unloading)(void *context); +}; + +/* This API detaches the HTC layer from the HIF device */ +void hif_detach_htc(struct hif_opaque_softc *scn); + +/****************************************************************/ +/* BMI and Diag window abstraction */ +/****************************************************************/ + +#define HIF_BMI_EXCHANGE_NO_TIMEOUT ((uint32_t)(0)) + +#define DIAG_TRANSFER_LIMIT 2048U /* maximum number of bytes that can be + * handled atomically by + * DiagRead/DiagWrite */ + +/* + * API to handle HIF-specific BMI message exchanges, this API is synchronous + * and only allowed to be called from a context that can block (sleep) */ +QDF_STATUS hif_exchange_bmi_msg(struct hif_opaque_softc *scn, + qdf_dma_addr_t cmd, qdf_dma_addr_t rsp, + uint8_t *pSendMessage, uint32_t Length, + uint8_t *pResponseMessage, + uint32_t *pResponseLength, uint32_t TimeoutMS); + +/* + * APIs to handle HIF specific diagnostic read accesses. These APIs are + * synchronous and only allowed to be called from a context that + * can block (sleep). They are not high performance APIs. + * + * hif_diag_read_access reads a 4 Byte aligned/length value from a + * Target register or memory word. + * + * hif_diag_read_mem reads an arbitrary length of arbitrarily aligned memory. + */ +QDF_STATUS hif_diag_read_access(struct hif_opaque_softc *scn, uint32_t address, + uint32_t *data); +QDF_STATUS hif_diag_read_mem(struct hif_opaque_softc *scn, uint32_t address, + uint8_t *data, int nbytes); +void hif_dump_target_memory(struct hif_opaque_softc *scn, void *ramdump_base, + uint32_t address, uint32_t size); +/* + * APIs to handle HIF specific diagnostic write accesses. These APIs are + * synchronous and only allowed to be called from a context that + * can block (sleep). + * They are not high performance APIs. + * + * hif_diag_write_access writes a 4 Byte aligned/length value to a + * Target register or memory word. + * + * hif_diag_write_mem writes an arbitrary length of arbitrarily aligned memory. + */ +QDF_STATUS hif_diag_write_access(struct hif_opaque_softc *scn, uint32_t address, + uint32_t data); +QDF_STATUS hif_diag_write_mem(struct hif_opaque_softc *scn, uint32_t address, + uint8_t *data, int nbytes); + +typedef void (*fastpath_msg_handler)(void *, qdf_nbuf_t *, uint32_t); + +/* + * Set the FASTPATH_mode_on flag in sc, for use by data path + */ +#ifdef WLAN_FEATURE_FASTPATH +void hif_enable_fastpath(struct hif_opaque_softc *hif_ctx); +bool hif_is_fastpath_mode_enabled(struct hif_opaque_softc *hif_ctx); +void *hif_get_ce_handle(struct hif_opaque_softc *hif_ctx, int ret); +int hif_ce_fastpath_cb_register(struct hif_opaque_softc *hif_ctx, + fastpath_msg_handler handler, void *context); +#else +static inline int hif_ce_fastpath_cb_register(struct hif_opaque_softc *hif_ctx, + fastpath_msg_handler handler, + void *context) +{ + return QDF_STATUS_E_FAILURE; +} +static inline void *hif_get_ce_handle(struct hif_opaque_softc *hif_ctx, int ret) +{ + return NULL; +} + +#endif + +/* + * Enable/disable CDC max performance workaround + * For max-performace set this to 0 + * To allow SoC to enter sleep set this to 1 + */ +#define CONFIG_DISABLE_CDC_MAX_PERF_WAR 0 + +void hif_ipa_get_ce_resource(struct hif_opaque_softc *scn, + qdf_dma_addr_t *ce_sr_base_paddr, + uint32_t *ce_sr_ring_size, + qdf_dma_addr_t *ce_reg_paddr); + +/** + * @brief List of callbacks - filled in by HTC. + */ +struct hif_msg_callbacks { + void *Context; + /**< context meaningful to HTC */ + QDF_STATUS (*txCompletionHandler)(void *Context, qdf_nbuf_t wbuf, + uint32_t transferID, + uint32_t toeplitz_hash_result); + QDF_STATUS (*rxCompletionHandler)(void *Context, qdf_nbuf_t wbuf, + uint8_t pipeID); + void (*txResourceAvailHandler)(void *context, uint8_t pipe); + void (*fwEventHandler)(void *context, QDF_STATUS status); +}; + +enum hif_target_status { + TARGET_STATUS_CONNECTED = 0, /* target connected */ + TARGET_STATUS_RESET, /* target got reset */ + TARGET_STATUS_EJECT, /* target got ejected */ + TARGET_STATUS_SUSPEND /*target got suspend */ +}; + +#define HIF_DATA_ATTR_SET_TX_CLASSIFY(attr, v) \ + (attr |= (v & 0x01) << 5) +#define HIF_DATA_ATTR_SET_ENCAPSULATION_TYPE(attr, v) \ + (attr |= (v & 0x03) << 6) +#define HIF_DATA_ATTR_SET_ADDR_X_SEARCH_DISABLE(attr, v) \ + (attr |= (v & 0x01) << 13) +#define HIF_DATA_ATTR_SET_ADDR_Y_SEARCH_DISABLE(attr, v) \ + (attr |= (v & 0x01) << 14) +#define HIF_DATA_ATTR_SET_TOEPLITZ_HASH_ENABLE(attr, v) \ + (attr |= (v & 0x01) << 15) +#define HIF_DATA_ATTR_SET_PACKET_OR_RESULT_OFFSET(attr, v) \ + (attr |= (v & 0x0FFF) << 16) +#define HIF_DATA_ATTR_SET_ENABLE_11H(attr, v) \ + (attr |= (v & 0x01) << 30) + +struct hif_ul_pipe_info { + unsigned int nentries; + unsigned int nentries_mask; + unsigned int sw_index; + unsigned int write_index; /* cached copy */ + unsigned int hw_index; /* cached copy */ + void *base_addr_owner_space; /* Host address space */ + qdf_dma_addr_t base_addr_CE_space; /* CE address space */ +}; + +struct hif_dl_pipe_info { + unsigned int nentries; + unsigned int nentries_mask; + unsigned int sw_index; + unsigned int write_index; /* cached copy */ + unsigned int hw_index; /* cached copy */ + void *base_addr_owner_space; /* Host address space */ + qdf_dma_addr_t base_addr_CE_space; /* CE address space */ +}; + +struct hif_pipe_addl_info { + uint32_t pci_mem; + uint32_t ctrl_addr; + struct hif_ul_pipe_info ul_pipe; + struct hif_dl_pipe_info dl_pipe; +}; + +struct hif_bus_id; +typedef struct hif_bus_id hif_bus_id; + +void hif_claim_device(struct hif_opaque_softc *hif_ctx); +QDF_STATUS hif_get_config_item(struct hif_opaque_softc *hif_ctx, + int opcode, void *config, uint32_t config_len); +void hif_set_mailbox_swap(struct hif_opaque_softc *hif_ctx); +void hif_mask_interrupt_call(struct hif_opaque_softc *scn); +void hif_post_init(struct hif_opaque_softc *scn, void *hHTC, + struct hif_msg_callbacks *callbacks); +QDF_STATUS hif_start(struct hif_opaque_softc *scn); +void hif_stop(struct hif_opaque_softc *scn); +void hif_flush_surprise_remove(struct hif_opaque_softc *scn); +void hif_dump(struct hif_opaque_softc *scn, uint8_t CmdId, bool start); +void hif_trigger_dump(struct hif_opaque_softc *hif_ctx, + uint8_t cmd_id, bool start); + +QDF_STATUS hif_send_head(struct hif_opaque_softc *scn, uint8_t PipeID, + uint32_t transferID, uint32_t nbytes, + qdf_nbuf_t wbuf, uint32_t data_attr); +void hif_send_complete_check(struct hif_opaque_softc *scn, uint8_t PipeID, + int force); +void hif_shut_down_device(struct hif_opaque_softc *scn); +void hif_get_default_pipe(struct hif_opaque_softc *scn, uint8_t *ULPipe, + uint8_t *DLPipe); +int hif_map_service_to_pipe(struct hif_opaque_softc *scn, uint16_t svc_id, + uint8_t *ul_pipe, uint8_t *dl_pipe, int *ul_is_polled, + int *dl_is_polled); +uint16_t +hif_get_free_queue_number(struct hif_opaque_softc *scn, uint8_t PipeID); +void *hif_get_targetdef(struct hif_opaque_softc *scn); +uint32_t hif_hia_item_address(uint32_t target_type, uint32_t item_offset); +void hif_set_target_sleep(struct hif_opaque_softc *scn, bool sleep_ok, + bool wait_for_it); +int hif_check_fw_reg(struct hif_opaque_softc *scn); +#ifndef HIF_PCI +static inline int hif_check_soc_status(struct hif_opaque_softc *scn) +{ + return 0; +} +#else +int hif_check_soc_status(struct hif_opaque_softc *scn); +#endif +void hif_get_hw_info(struct hif_opaque_softc *scn, u32 *version, u32 *revision, + const char **target_name); +void hif_disable_isr(struct hif_opaque_softc *scn); +void hif_reset_soc(struct hif_opaque_softc *scn); +void hif_save_htc_htt_config_endpoint(struct hif_opaque_softc *hif_ctx, + int htc_htt_tx_endpoint); +struct hif_opaque_softc *hif_open(qdf_device_t qdf_ctx, uint32_t mode, + enum qdf_bus_type bus_type, + struct hif_driver_state_callbacks *cbk); +void hif_close(struct hif_opaque_softc *hif_ctx); +QDF_STATUS hif_enable(struct hif_opaque_softc *hif_ctx, struct device *dev, + void *bdev, const hif_bus_id *bid, + enum qdf_bus_type bus_type, + enum hif_enable_type type); +void hif_disable(struct hif_opaque_softc *hif_ctx, enum hif_disable_type type); +void hif_display_stats(struct hif_opaque_softc *hif_ctx); +void hif_clear_stats(struct hif_opaque_softc *hif_ctx); +#ifdef FEATURE_RUNTIME_PM +struct hif_pm_runtime_lock; +int hif_pm_runtime_get(struct hif_opaque_softc *hif_ctx); +void hif_pm_runtime_get_noresume(struct hif_opaque_softc *hif_ctx); +int hif_pm_runtime_put(struct hif_opaque_softc *hif_ctx); +int hif_runtime_lock_init(qdf_runtime_lock_t *lock, const char *name); +void hif_runtime_lock_deinit(struct hif_opaque_softc *hif_ctx, + struct hif_pm_runtime_lock *lock); +int hif_pm_runtime_prevent_suspend(struct hif_opaque_softc *ol_sc, + struct hif_pm_runtime_lock *lock); +int hif_pm_runtime_allow_suspend(struct hif_opaque_softc *ol_sc, + struct hif_pm_runtime_lock *lock); +int hif_pm_runtime_prevent_suspend_timeout(struct hif_opaque_softc *ol_sc, + struct hif_pm_runtime_lock *lock, unsigned int delay); +#else +struct hif_pm_runtime_lock { + const char *name; +}; + +static inline void hif_pm_runtime_get_noresume(struct hif_opaque_softc *hif_ctx) +{} + +static inline int hif_pm_runtime_get(struct hif_opaque_softc *hif_ctx) +{ return 0; } +static inline int hif_pm_runtime_put(struct hif_opaque_softc *hif_ctx) +{ return 0; } +static inline int hif_runtime_lock_init(qdf_runtime_lock_t *lock, + const char *name) +{ return 0; } +static inline void +hif_runtime_lock_deinit(struct hif_opaque_softc *hif_ctx, + struct hif_pm_runtime_lock *lock) {} + +static inline int hif_pm_runtime_prevent_suspend(struct hif_opaque_softc *ol_sc, + struct hif_pm_runtime_lock *lock) +{ return 0; } +static inline int hif_pm_runtime_allow_suspend(struct hif_opaque_softc *ol_sc, + struct hif_pm_runtime_lock *lock) +{ return 0; } +static inline int +hif_pm_runtime_prevent_suspend_timeout(struct hif_opaque_softc *ol_sc, + struct hif_pm_runtime_lock *lock, unsigned int delay) +{ return 0; } +#endif + +void hif_enable_power_management(struct hif_opaque_softc *hif_ctx, + bool is_packet_log_enabled); +void hif_disable_power_management(struct hif_opaque_softc *hif_ctx); + +void hif_vote_link_down(struct hif_opaque_softc *); +void hif_vote_link_up(struct hif_opaque_softc *); +bool hif_can_suspend_link(struct hif_opaque_softc *); + +#ifdef IPA_OFFLOAD +/** + * hif_get_ipa_hw_type() - get IPA hw type + * + * This API return the IPA hw type. + * + * Return: IPA hw type + */ +static inline +enum ipa_hw_type hif_get_ipa_hw_type(void) +{ + return ipa_get_hw_type(); +} +#endif +int hif_bus_resume(struct hif_opaque_softc *); +/** + * hif_bus_ealry_suspend() - stop non wmi tx traffic + * @context: hif context + */ +int hif_bus_early_suspend(struct hif_opaque_softc *hif_ctx); + +/** + * hif_bus_late_resume() - resume non wmi traffic + * @context: hif context + */ +int hif_bus_late_resume(struct hif_opaque_softc *hif_ctx); +int hif_bus_suspend(struct hif_opaque_softc *); +int hif_bus_resume_noirq(struct hif_opaque_softc *); +int hif_bus_suspend_noirq(struct hif_opaque_softc *); + +#ifdef FEATURE_RUNTIME_PM +int hif_pre_runtime_suspend(struct hif_opaque_softc *hif_ctx); +void hif_pre_runtime_resume(struct hif_opaque_softc *hif_ctx); +int hif_runtime_suspend(struct hif_opaque_softc *hif_ctx); +int hif_runtime_resume(struct hif_opaque_softc *hif_ctx); +void hif_process_runtime_suspend_success(struct hif_opaque_softc *); +void hif_process_runtime_suspend_failure(struct hif_opaque_softc *); +void hif_process_runtime_resume_success(struct hif_opaque_softc *); +#endif + +int hif_dump_registers(struct hif_opaque_softc *scn); +int ol_copy_ramdump(struct hif_opaque_softc *scn); +void hif_crash_shutdown(struct hif_opaque_softc *hif_ctx); +void hif_get_hw_info(struct hif_opaque_softc *scn, u32 *version, u32 *revision, + const char **target_name); +void hif_lro_flush_cb_register(struct hif_opaque_softc *scn, + void (lro_flush_handler)(void *), + void *(lro_init_handler)(void)); +void hif_lro_flush_cb_deregister(struct hif_opaque_softc *scn, + void (lro_deinit_cb)(void *)); +bool hif_needs_bmi(struct hif_opaque_softc *scn); +enum qdf_bus_type hif_get_bus_type(struct hif_opaque_softc *hif_hdl); +struct hif_target_info *hif_get_target_info_handle(struct hif_opaque_softc * + scn); +struct hif_config_info *hif_get_ini_handle(struct hif_opaque_softc *scn); +struct ramdump_info *hif_get_ramdump_ctx(struct hif_opaque_softc *hif_ctx); +enum hif_target_status hif_get_target_status(struct hif_opaque_softc *hif_ctx); +void hif_set_target_status(struct hif_opaque_softc *hif_ctx, enum + hif_target_status); +void hif_init_ini_config(struct hif_opaque_softc *hif_ctx, + struct hif_config_info *cfg); +void hif_update_tx_ring(struct hif_opaque_softc *osc, u_int32_t num_htt_cmpls); +qdf_nbuf_t hif_batch_send(struct hif_opaque_softc *osc, qdf_nbuf_t msdu, + uint32_t transfer_id, u_int32_t len, uint32_t sendhead); +int hif_send_single(struct hif_opaque_softc *osc, qdf_nbuf_t msdu, uint32_t + transfer_id, u_int32_t len); +int hif_send_fast(struct hif_opaque_softc *osc, qdf_nbuf_t nbuf, + uint32_t transfer_id, uint32_t download_len); +void hif_pkt_dl_len_set(void *hif_sc, unsigned int pkt_download_len); +void hif_ce_war_disable(void); +void hif_ce_war_enable(void); +void hif_disable_interrupt(struct hif_opaque_softc *osc, uint32_t pipe_num); +#ifdef QCA_NSS_WIFI_OFFLOAD_SUPPORT +struct hif_pipe_addl_info *hif_get_addl_pipe_info(struct hif_opaque_softc *osc, + struct hif_pipe_addl_info *hif_info, uint32_t pipe_number); +uint32_t hif_set_nss_wifiol_mode(struct hif_opaque_softc *osc, + uint32_t pipe_num); +int32_t hif_get_nss_wifiol_bypass_nw_process(struct hif_opaque_softc *osc); +#endif /* QCA_NSS_WIFI_OFFLOAD_SUPPORT */ + +void hif_set_bundle_mode(struct hif_opaque_softc *scn, bool enabled, + int rx_bundle_cnt); +int hif_bus_reset_resume(struct hif_opaque_softc *scn); + +void *hif_get_lro_info(int ctx_id, struct hif_opaque_softc *hif_hdl); +#ifdef WLAN_SUSPEND_RESUME_TEST +typedef void (*hif_fake_resume_callback)(uint32_t val); +void hif_fake_apps_suspend(struct hif_opaque_softc *hif_ctx, + hif_fake_resume_callback callback); +void hif_fake_apps_resume(struct hif_opaque_softc *hif_ctx); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* _HIF_H_ */ diff --git a/drivers/staging/qca-wifi-host-cmn/hif/inc/hif_napi.h b/drivers/staging/qca-wifi-host-cmn/hif/inc/hif_napi.h new file mode 100644 index 0000000000000000000000000000000000000000..3ff8a3c2e02f26a2f66bd3566c1ee5ba15b6224d --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/hif/inc/hif_napi.h @@ -0,0 +1,264 @@ +/* + * Copyright (c) 2015-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef __HIF_NAPI_H__ +#define __HIF_NAPI_H__ + +/** + * DOC: hif_napi.h + * + * Interface to HIF implemented functions of NAPI. + * These are used by hdd_napi. + */ + + +/* CLD headers */ +#include /* struct hif_opaque_softc; */ + +/** + * common stuff + * The declarations until #ifdef FEATURE_NAPI below + * are valid whether or not FEATURE_NAPI has been + * defined. + */ + +/** + * NAPI manages the following states: + * NAPI state: per NAPI instance, ENABLED/DISABLED + * CPU state: per CPU, DOWN/UP + * TPUT state: global, LOW/HI + * + * "Dynamic" changes to state of various NAPI structures are + * managed by NAPI events. The events may be produced by + * various detection points. With each event, some data is + * sent. The main event handler in hif_napi handles and makes + * the state changes. + * + * event : data : generated + * ---------------:------------------:------------------ + * EVT_INI_FILE : cfg->napi_enable : after ini file processed + * EVT_CMD_STATE : cmd arg : by the vendor cmd + * EVT_INT_STATE : 0 : internal - shut off/disable + * EVT_CPU_STATE : (cpu << 16)|state: CPU hotplug events + * EVT_TPUT_STATE : (high/low) : tput trigger + * EVT_USR_SERIAL : num-serial_calls : WMA/ROAMING-START/IND + * EVT_USR_NORMAL : N/A : WMA/ROAMING-END + */ +enum qca_napi_event { + NAPI_EVT_INVALID, + NAPI_EVT_INI_FILE, + NAPI_EVT_CMD_STATE, + NAPI_EVT_INT_STATE, + NAPI_EVT_CPU_STATE, + NAPI_EVT_TPUT_STATE, + NAPI_EVT_USR_SERIAL, + NAPI_EVT_USR_NORMAL +}; +/** + * Following are some of NAPI related features controlled using feature flag + * These flags need to be enabled in the qca_napi_data->flags variable for the + * feature to kick in. +.* QCA_NAPI_FEATURE_CPU_CORRECTION - controls CPU correction logic +.* QCA_NAPI_FEATURE_IRQ_BLACKLISTING - controls call to irq_blacklist_on API +.* QCA_NAPI_FEATURE_CORE_CTL_BOOST - controls call to core_ctl_set_boost API + */ +#define QCA_NAPI_FEATURE_CPU_CORRECTION BIT(1) +#define QCA_NAPI_FEATURE_IRQ_BLACKLISTING BIT(2) +#define QCA_NAPI_FEATURE_CORE_CTL_BOOST BIT(3) + +/** + * Macros to map ids -returned by ...create()- to pipes and vice versa + */ +#define NAPI_ID2PIPE(i) ((i)-1) +#define NAPI_PIPE2ID(p) ((p)+1) + +int hif_napi_lro_flush_cb_register(struct hif_opaque_softc *hif_hdl, + void (lro_flush_handler)(void *), + void *(lro_init_handler)(void)); + +void hif_napi_lro_flush_cb_deregister(struct hif_opaque_softc *hif_hdl, + void (lro_deinit_cb)(void *)); + +void *hif_napi_get_lro_info(struct hif_opaque_softc *hif_hdl, int napi_id); +#ifdef FEATURE_NAPI + +/** + * NAPI HIF API + * + * the declarations below only apply to the case + * where FEATURE_NAPI is defined + */ + +int hif_napi_create(struct hif_opaque_softc *hif, + int (*poll)(struct napi_struct *, int), + int budget, + int scale, + uint8_t flags); +int hif_napi_destroy(struct hif_opaque_softc *hif, + uint8_t id, + int force); + +struct qca_napi_data *hif_napi_get_all(struct hif_opaque_softc *hif); + +int hif_napi_event(struct hif_opaque_softc *hif, + enum qca_napi_event event, + void *data); + +/* called from the ISR within hif, so, ce is known */ +int hif_napi_enabled(struct hif_opaque_softc *hif, int ce); + +/* called from hdd (napi_poll), using napi id as a selector */ +void hif_napi_enable_irq(struct hif_opaque_softc *hif, int id); + +/* called by ce_tasklet.c::ce_dispatch_interrupt*/ +int hif_napi_schedule(struct hif_opaque_softc *scn, int ce_id); + +/* called by hdd_napi, which is called by kernel */ +int hif_napi_poll(struct hif_opaque_softc *hif_ctx, + struct napi_struct *napi, int budget); +#ifdef HELIUMPLUS +/* called to retrieve NAPI CPU statistics */ +void hif_napi_stats(struct qca_napi_data *napid); +void hif_napi_update_yield_stats(struct CE_state *ce_state, + bool time_limit_reached, + bool rxpkt_thresh_reached); +#else +static inline void hif_napi_stats(struct qca_napi_data *napid) { } + +static inline void hif_napi_update_yield_stats(struct CE_state *ce_state, + bool time_limit_reached, + bool rxpkt_thresh_reached) { } + +#endif + +#ifdef FEATURE_NAPI_DEBUG +#define NAPI_DEBUG(fmt, ...) \ + qdf_print("wlan: NAPI: %s:%d "fmt, __func__, __LINE__, ##__VA_ARGS__); +#else +#define NAPI_DEBUG(fmt, ...) /* NO-OP */ +#endif /* FEATURE NAPI_DEBUG */ + +#define HNC_ANY_CPU (-1) +#define HNC_ACT_RELOCATE (0) +#define HNC_ACT_COLLAPSE (1) +#define HNC_ACT_DISPERSE (-1) + +enum qca_blacklist_op { + BLACKLIST_QUERY, + BLACKLIST_OFF, + BLACKLIST_ON +}; + +int hif_napi_cpu_blacklist(struct qca_napi_data *napid, enum qca_blacklist_op op); +/** + * Local interface to HIF implemented functions of NAPI CPU affinity management. + * Note: + * 1- The symbols in this file are NOT supposed to be used by any + * entity other than hif_napi.c + * 2- The symbols are valid only if HELIUMPLUS is defined. They are otherwise + * mere wrappers. + * + */ +#ifndef HELIUMPLUS +/** + * stub functions + */ +/* fw-declare to make compiler happy */ +struct qca_napi_data; +static inline int hif_napi_cpu_init(struct hif_opaque_softc *hif) +{ return 0; } + +static inline int hif_napi_cpu_deinit(struct hif_opaque_softc *hif) +{ return 0; } + +static inline int hif_napi_serialize(struct hif_opaque_softc *hif, int is_on) +{ return -EPERM; } +#else /* HELIUMPLUS - NAPI CPU symbols are valid */ + +/* + * prototype signatures + */ +int hif_napi_cpu_init(struct hif_opaque_softc *hif); +int hif_napi_cpu_deinit(struct hif_opaque_softc *hif); + +int hif_napi_cpu_migrate(struct qca_napi_data *napid, int cpu, int action); +int hif_napi_serialize(struct hif_opaque_softc *hif, int is_on); + +#endif /* HELIUMPLUS */ + +#else /* ! defined(FEATURE_NAPI) */ + +/** + * Stub API + * + * The declarations in this section are valid only + * when FEATURE_NAPI has *not* been defined. + */ + +#define NAPI_DEBUG(fmt, ...) /* NO-OP */ + +static inline int hif_napi_create(struct hif_opaque_softc *hif, + uint8_t pipe_id, + int (*poll)(struct napi_struct *, int), + int budget, + int scale, + uint8_t flags) +{ return -EPERM; } + +static inline int hif_napi_destroy(struct hif_opaque_softc *hif, + uint8_t id, + int force) +{ return -EPERM; } + +static inline struct qca_napi_data *hif_napi_get_all( + struct hif_opaque_softc *hif) +{ return NULL; } + +static inline int hif_napi_event(struct hif_opaque_softc *hif, + enum qca_napi_event event, + void *data) +{ return -EPERM; } + +/* called from the ISR within hif, so, ce is known */ +static inline int hif_napi_enabled(struct hif_opaque_softc *hif, int ce) +{ return 0; } + +/* called from hdd (napi_poll), using napi id as a selector */ +static inline void hif_napi_enable_irq(struct hif_opaque_softc *hif, int id) +{ return; } + +static inline int hif_napi_schedule(struct hif_opaque_softc *hif, int ce_id) +{ return 0; } + +static inline int hif_napi_poll(struct napi_struct *napi, int budget) +{ return -EPERM; } + +static inline void hif_napi_stats(struct qca_napi_data *napid) { } + +#endif /* FEATURE_NAPI */ + +#endif /* __HIF_NAPI_H__ */ diff --git a/drivers/staging/qca-wifi-host-cmn/hif/inc/host_reg_init.h b/drivers/staging/qca-wifi-host-cmn/hif/inc/host_reg_init.h new file mode 100644 index 0000000000000000000000000000000000000000..f154192c9f9f958844c029997559a6713af4d3d4 --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/hif/inc/host_reg_init.h @@ -0,0 +1,181 @@ +/* + * Copyright (c) 2016 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 HOST_REG_INIT_H +#define HOST_REG_INIT_H + +#include "reg_struct.h" +#include "targaddrs.h" + +#if defined(MY_HOST_DEF) + +#if !defined(FW_IND_HOST_READY) +#define FW_IND_HOST_READY 0 +#endif + +#if !defined(PCIE_LOCAL_BASE_ADDRESS) +#define PCIE_LOCAL_BASE_ADDRESS 0 +#define PCIE_SOC_WAKE_RESET 0 +#define PCIE_SOC_WAKE_ADDRESS 0 +#define PCIE_SOC_WAKE_V_MASK 0 +#define RTC_STATE_ADDRESS 0 +#define RTC_STATE_COLD_RESET_MASK 0 +#define RTC_STATE_V_MASK 0 +#define RTC_STATE_V_LSB 0 +#define RTC_STATE_V_ON 0 +#define SOC_GLOBAL_RESET_ADDRESS 0 +#endif + +#if !defined(CE_COUNT) +#define CE_COUNT 0 +#endif + +#if !defined(TRANSACTION_ID_MASK) +#define TRANSACTION_ID_MASK 0xfff +#endif + +static struct hostdef_s my_host_def = { + .d_INT_STATUS_ENABLE_ERROR_LSB = INT_STATUS_ENABLE_ERROR_LSB, + .d_INT_STATUS_ENABLE_ERROR_MASK = INT_STATUS_ENABLE_ERROR_MASK, + .d_INT_STATUS_ENABLE_CPU_LSB = INT_STATUS_ENABLE_CPU_LSB, + .d_INT_STATUS_ENABLE_CPU_MASK = INT_STATUS_ENABLE_CPU_MASK, + .d_INT_STATUS_ENABLE_COUNTER_LSB = INT_STATUS_ENABLE_COUNTER_LSB, + .d_INT_STATUS_ENABLE_COUNTER_MASK = INT_STATUS_ENABLE_COUNTER_MASK, + .d_INT_STATUS_ENABLE_MBOX_DATA_LSB = INT_STATUS_ENABLE_MBOX_DATA_LSB, + .d_INT_STATUS_ENABLE_MBOX_DATA_MASK = INT_STATUS_ENABLE_MBOX_DATA_MASK, + .d_ERROR_STATUS_ENABLE_RX_UNDERFLOW_LSB + = ERROR_STATUS_ENABLE_RX_UNDERFLOW_LSB, + .d_ERROR_STATUS_ENABLE_RX_UNDERFLOW_MASK + = ERROR_STATUS_ENABLE_RX_UNDERFLOW_MASK, + .d_ERROR_STATUS_ENABLE_TX_OVERFLOW_LSB + = ERROR_STATUS_ENABLE_TX_OVERFLOW_LSB, + .d_ERROR_STATUS_ENABLE_TX_OVERFLOW_MASK + = ERROR_STATUS_ENABLE_TX_OVERFLOW_MASK, + .d_COUNTER_INT_STATUS_ENABLE_BIT_LSB + = COUNTER_INT_STATUS_ENABLE_BIT_LSB, + .d_COUNTER_INT_STATUS_ENABLE_BIT_MASK + = COUNTER_INT_STATUS_ENABLE_BIT_MASK, + .d_INT_STATUS_ENABLE_ADDRESS = INT_STATUS_ENABLE_ADDRESS, + .d_CPU_INT_STATUS_ENABLE_BIT_LSB = CPU_INT_STATUS_ENABLE_BIT_LSB, + .d_CPU_INT_STATUS_ENABLE_BIT_MASK = CPU_INT_STATUS_ENABLE_BIT_MASK, + .d_HOST_INT_STATUS_ADDRESS = HOST_INT_STATUS_ADDRESS, + .d_CPU_INT_STATUS_ADDRESS = CPU_INT_STATUS_ADDRESS, + .d_ERROR_INT_STATUS_ADDRESS = ERROR_INT_STATUS_ADDRESS, + .d_ERROR_INT_STATUS_WAKEUP_MASK = ERROR_INT_STATUS_WAKEUP_MASK, + .d_ERROR_INT_STATUS_WAKEUP_LSB = ERROR_INT_STATUS_WAKEUP_LSB, + .d_ERROR_INT_STATUS_RX_UNDERFLOW_MASK + = ERROR_INT_STATUS_RX_UNDERFLOW_MASK, + .d_ERROR_INT_STATUS_RX_UNDERFLOW_LSB + = ERROR_INT_STATUS_RX_UNDERFLOW_LSB, + .d_ERROR_INT_STATUS_TX_OVERFLOW_MASK + = ERROR_INT_STATUS_TX_OVERFLOW_MASK, + .d_ERROR_INT_STATUS_TX_OVERFLOW_LSB = ERROR_INT_STATUS_TX_OVERFLOW_LSB, + .d_COUNT_DEC_ADDRESS = COUNT_DEC_ADDRESS, + .d_HOST_INT_STATUS_CPU_MASK = HOST_INT_STATUS_CPU_MASK, + .d_HOST_INT_STATUS_CPU_LSB = HOST_INT_STATUS_CPU_LSB, + .d_HOST_INT_STATUS_ERROR_MASK = HOST_INT_STATUS_ERROR_MASK, + .d_HOST_INT_STATUS_ERROR_LSB = HOST_INT_STATUS_ERROR_LSB, + .d_HOST_INT_STATUS_COUNTER_MASK = HOST_INT_STATUS_COUNTER_MASK, + .d_HOST_INT_STATUS_COUNTER_LSB = HOST_INT_STATUS_COUNTER_LSB, + .d_RX_LOOKAHEAD_VALID_ADDRESS = RX_LOOKAHEAD_VALID_ADDRESS, + .d_WINDOW_DATA_ADDRESS = WINDOW_DATA_ADDRESS, + .d_WINDOW_READ_ADDR_ADDRESS = WINDOW_READ_ADDR_ADDRESS, + .d_WINDOW_WRITE_ADDR_ADDRESS = WINDOW_WRITE_ADDR_ADDRESS, + .d_SOC_GLOBAL_RESET_ADDRESS = SOC_GLOBAL_RESET_ADDRESS, + .d_RTC_STATE_ADDRESS = RTC_STATE_ADDRESS, + .d_RTC_STATE_COLD_RESET_MASK = RTC_STATE_COLD_RESET_MASK, + .d_PCIE_LOCAL_BASE_ADDRESS = PCIE_LOCAL_BASE_ADDRESS, + .d_PCIE_SOC_WAKE_RESET = PCIE_SOC_WAKE_RESET, + .d_PCIE_SOC_WAKE_ADDRESS = PCIE_SOC_WAKE_ADDRESS, + .d_PCIE_SOC_WAKE_V_MASK = PCIE_SOC_WAKE_V_MASK, + .d_RTC_STATE_V_MASK = RTC_STATE_V_MASK, + .d_RTC_STATE_V_LSB = RTC_STATE_V_LSB, + .d_FW_IND_EVENT_PENDING = FW_IND_EVENT_PENDING, + .d_FW_IND_INITIALIZED = FW_IND_INITIALIZED, + .d_RTC_STATE_V_ON = RTC_STATE_V_ON, +#if defined(SDIO_3_0) + .d_HOST_INT_STATUS_MBOX_DATA_MASK = HOST_INT_STATUS_MBOX_DATA_MASK, + .d_HOST_INT_STATUS_MBOX_DATA_LSB = HOST_INT_STATUS_MBOX_DATA_LSB, +#endif + .d_FW_IND_HOST_READY = FW_IND_HOST_READY, + .d_HOST_CE_COUNT = CE_COUNT, + .d_TRANSACTION_ID_MASK = TRANSACTION_ID_MASK, +}; + +struct hostdef_s *MY_HOST_DEF = &my_host_def; +#else /* MY_HOST_DEF */ +#endif /* MY_HOST_DEF */ + + + +#if defined(MY_HOST_SHADOW_REGS) +struct host_shadow_regs_s my_host_shadow_regs = { + .d_A_LOCAL_SHADOW_REG_VALUE_0 = A_LOCAL_SHADOW_REG_VALUE_0; + .d_A_LOCAL_SHADOW_REG_VALUE_1 = A_LOCAL_SHADOW_REG_VALUE_1; + .d_A_LOCAL_SHADOW_REG_VALUE_2 = A_LOCAL_SHADOW_REG_VALUE_2; + .d_A_LOCAL_SHADOW_REG_VALUE_3 = A_LOCAL_SHADOW_REG_VALUE_3; + .d_A_LOCAL_SHADOW_REG_VALUE_4 = A_LOCAL_SHADOW_REG_VALUE_4; + .d_A_LOCAL_SHADOW_REG_VALUE_5 = A_LOCAL_SHADOW_REG_VALUE_5; + .d_A_LOCAL_SHADOW_REG_VALUE_6 = A_LOCAL_SHADOW_REG_VALUE_6; + .d_A_LOCAL_SHADOW_REG_VALUE_7 = A_LOCAL_SHADOW_REG_VALUE_7; + .d_A_LOCAL_SHADOW_REG_VALUE_8 = A_LOCAL_SHADOW_REG_VALUE_8; + .d_A_LOCAL_SHADOW_REG_VALUE_9 = A_LOCAL_SHADOW_REG_VALUE_9; + .d_A_LOCAL_SHADOW_REG_VALUE_10 = A_LOCAL_SHADOW_REG_VALUE_10; + .d_A_LOCAL_SHADOW_REG_VALUE_11 = A_LOCAL_SHADOW_REG_VALUE_11; + .d_A_LOCAL_SHADOW_REG_VALUE_12 = A_LOCAL_SHADOW_REG_VALUE_12; + .d_A_LOCAL_SHADOW_REG_VALUE_13 = A_LOCAL_SHADOW_REG_VALUE_13; + .d_A_LOCAL_SHADOW_REG_VALUE_14 = A_LOCAL_SHADOW_REG_VALUE_14; + .d_A_LOCAL_SHADOW_REG_VALUE_15 = A_LOCAL_SHADOW_REG_VALUE_15; + .d_A_LOCAL_SHADOW_REG_VALUE_16 = A_LOCAL_SHADOW_REG_VALUE_16; + .d_A_LOCAL_SHADOW_REG_VALUE_17 = A_LOCAL_SHADOW_REG_VALUE_17; + .d_A_LOCAL_SHADOW_REG_VALUE_18 = A_LOCAL_SHADOW_REG_VALUE_18; + .d_A_LOCAL_SHADOW_REG_VALUE_19 = A_LOCAL_SHADOW_REG_VALUE_19; + .d_A_LOCAL_SHADOW_REG_VALUE_20 = A_LOCAL_SHADOW_REG_VALUE_20; + .d_A_LOCAL_SHADOW_REG_VALUE_21 = A_LOCAL_SHADOW_REG_VALUE_21; + .d_A_LOCAL_SHADOW_REG_VALUE_22 = A_LOCAL_SHADOW_REG_VALUE_22; + .d_A_LOCAL_SHADOW_REG_VALUE_23 = A_LOCAL_SHADOW_REG_VALUE_23; + .d_A_LOCAL_SHADOW_REG_ADDRESS_0 = A_LOCAL_SHADOW_REG_ADDRESS_0; + .d_A_LOCAL_SHADOW_REG_ADDRESS_1 = A_LOCAL_SHADOW_REG_ADDRESS_1; + .d_A_LOCAL_SHADOW_REG_ADDRESS_2 = A_LOCAL_SHADOW_REG_ADDRESS_2; + .d_A_LOCAL_SHADOW_REG_ADDRESS_3 = A_LOCAL_SHADOW_REG_ADDRESS_3; + .d_A_LOCAL_SHADOW_REG_ADDRESS_4 = A_LOCAL_SHADOW_REG_ADDRESS_4; + .d_A_LOCAL_SHADOW_REG_ADDRESS_5 = A_LOCAL_SHADOW_REG_ADDRESS_5; + .d_A_LOCAL_SHADOW_REG_ADDRESS_6 = A_LOCAL_SHADOW_REG_ADDRESS_6; + .d_A_LOCAL_SHADOW_REG_ADDRESS_7 = A_LOCAL_SHADOW_REG_ADDRESS_7; + .d_A_LOCAL_SHADOW_REG_ADDRESS_8 = A_LOCAL_SHADOW_REG_ADDRESS_8; + .d_A_LOCAL_SHADOW_REG_ADDRESS_9 = A_LOCAL_SHADOW_REG_ADDRESS_9; + .d_A_LOCAL_SHADOW_REG_ADDRESS_10 = A_LOCAL_SHADOW_REG_ADDRESS_10; + .d_A_LOCAL_SHADOW_REG_ADDRESS_11 = A_LOCAL_SHADOW_REG_ADDRESS_11; + .d_A_LOCAL_SHADOW_REG_ADDRESS_12 = A_LOCAL_SHADOW_REG_ADDRESS_12; + .d_A_LOCAL_SHADOW_REG_ADDRESS_13 = A_LOCAL_SHADOW_REG_ADDRESS_13; + .d_A_LOCAL_SHADOW_REG_ADDRESS_14 = A_LOCAL_SHADOW_REG_ADDRESS_14; + .d_A_LOCAL_SHADOW_REG_ADDRESS_15 = A_LOCAL_SHADOW_REG_ADDRESS_15; + .d_A_LOCAL_SHADOW_REG_ADDRESS_16 = A_LOCAL_SHADOW_REG_ADDRESS_16; + .d_A_LOCAL_SHADOW_REG_ADDRESS_17 = A_LOCAL_SHADOW_REG_ADDRESS_17; + .d_A_LOCAL_SHADOW_REG_ADDRESS_18 = A_LOCAL_SHADOW_REG_ADDRESS_18; + .d_A_LOCAL_SHADOW_REG_ADDRESS_19 = A_LOCAL_SHADOW_REG_ADDRESS_19; + .d_A_LOCAL_SHADOW_REG_ADDRESS_20 = A_LOCAL_SHADOW_REG_ADDRESS_20; + .d_A_LOCAL_SHADOW_REG_ADDRESS_21 = A_LOCAL_SHADOW_REG_ADDRESS_21; + .d_A_LOCAL_SHADOW_REG_ADDRESS_22 = A_LOCAL_SHADOW_REG_ADDRESS_22; + .d_A_LOCAL_SHADOW_REG_ADDRESS_23 = A_LOCAL_SHADOW_REG_ADDRESS_23; +}; + +struct hostdef_s *MY_HOST_SHADOW_REGS = &my_host_shadow_regs; +#else /* MY_HOST_SHADOW_REGS */ +#endif /* MY_HOST_SHADOW_REGS */ +#endif /* HOST_REG_INIT_H */ diff --git a/drivers/staging/qca-wifi-host-cmn/hif/inc/hostdef.h b/drivers/staging/qca-wifi-host-cmn/hif/inc/hostdef.h new file mode 100644 index 0000000000000000000000000000000000000000..b291bbfb1431ca8fc25fb1065b7a29c92a893282 --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/hif/inc/hostdef.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2013-2016 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 HOSTDEFS_H_ +#define HOSTDEFS_H_ + +#include +#include +#include +#include "host_reg_init.h" + +extern struct hostdef_s *AR6002_HOSTdef; +extern struct hostdef_s *AR6003_HOSTdef; +extern struct hostdef_s *AR6004_HOSTdef; +extern struct hostdef_s *AR9888_HOSTdef; +extern struct hostdef_s *AR9888V2_HOSTdef; +extern struct hostdef_s *AR6320_HOSTdef; +extern struct hostdef_s *AR900B_HOSTdef; +extern struct hostdef_s *QCA9984_HOSTdef; +extern struct hostdef_s *QCA9888_HOSTdef; +#ifdef ATH_AHB +extern struct hostdef_s *IPQ4019_HOSTdef; +#endif + +#endif diff --git a/drivers/staging/qca-wifi-host-cmn/hif/inc/reg_struct.h b/drivers/staging/qca-wifi-host-cmn/hif/inc/reg_struct.h new file mode 100644 index 0000000000000000000000000000000000000000..7e05857c9bfc75512a12f25722ed8804d593d0f0 --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/hif/inc/reg_struct.h @@ -0,0 +1,709 @@ +/* + * Copyright (c) 2015-2016 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 REG_STRUCT_H +#define REG_STRUCT_H + +#define MISSING_REGISTER 0 +#define UNSUPPORTED_REGISTER_OFFSET 0xffffffff + +/** + * is_register_supported() - return true if the register offset is valid + * @reg: register address being checked + * + * Return: true if the register offset is valid + */ +static inline bool is_register_supported(uint32_t reg) +{ + return (reg != MISSING_REGISTER) && + (reg != UNSUPPORTED_REGISTER_OFFSET); +} + +struct targetdef_s { + uint32_t d_RTC_SOC_BASE_ADDRESS; + uint32_t d_RTC_WMAC_BASE_ADDRESS; + uint32_t d_SYSTEM_SLEEP_OFFSET; + uint32_t d_WLAN_SYSTEM_SLEEP_OFFSET; + uint32_t d_WLAN_SYSTEM_SLEEP_DISABLE_LSB; + uint32_t d_WLAN_SYSTEM_SLEEP_DISABLE_MASK; + uint32_t d_CLOCK_CONTROL_OFFSET; + uint32_t d_CLOCK_CONTROL_SI0_CLK_MASK; + uint32_t d_RESET_CONTROL_OFFSET; + uint32_t d_RESET_CONTROL_MBOX_RST_MASK; + uint32_t d_RESET_CONTROL_SI0_RST_MASK; + uint32_t d_WLAN_RESET_CONTROL_OFFSET; + uint32_t d_WLAN_RESET_CONTROL_COLD_RST_MASK; + uint32_t d_WLAN_RESET_CONTROL_WARM_RST_MASK; + uint32_t d_GPIO_BASE_ADDRESS; + uint32_t d_GPIO_PIN0_OFFSET; + uint32_t d_GPIO_PIN1_OFFSET; + uint32_t d_GPIO_PIN0_CONFIG_MASK; + uint32_t d_GPIO_PIN1_CONFIG_MASK; + uint32_t d_SI_CONFIG_BIDIR_OD_DATA_LSB; + uint32_t d_SI_CONFIG_BIDIR_OD_DATA_MASK; + uint32_t d_SI_CONFIG_I2C_LSB; + uint32_t d_SI_CONFIG_I2C_MASK; + uint32_t d_SI_CONFIG_POS_SAMPLE_LSB; + uint32_t d_SI_CONFIG_POS_SAMPLE_MASK; + uint32_t d_SI_CONFIG_INACTIVE_CLK_LSB; + uint32_t d_SI_CONFIG_INACTIVE_CLK_MASK; + uint32_t d_SI_CONFIG_INACTIVE_DATA_LSB; + uint32_t d_SI_CONFIG_INACTIVE_DATA_MASK; + uint32_t d_SI_CONFIG_DIVIDER_LSB; + uint32_t d_SI_CONFIG_DIVIDER_MASK; + uint32_t d_SI_BASE_ADDRESS; + uint32_t d_SI_CONFIG_OFFSET; + uint32_t d_SI_TX_DATA0_OFFSET; + uint32_t d_SI_TX_DATA1_OFFSET; + uint32_t d_SI_RX_DATA0_OFFSET; + uint32_t d_SI_RX_DATA1_OFFSET; + uint32_t d_SI_CS_OFFSET; + uint32_t d_SI_CS_DONE_ERR_MASK; + uint32_t d_SI_CS_DONE_INT_MASK; + uint32_t d_SI_CS_START_LSB; + uint32_t d_SI_CS_START_MASK; + uint32_t d_SI_CS_RX_CNT_LSB; + uint32_t d_SI_CS_RX_CNT_MASK; + uint32_t d_SI_CS_TX_CNT_LSB; + uint32_t d_SI_CS_TX_CNT_MASK; + uint32_t d_BOARD_DATA_SZ; + uint32_t d_BOARD_EXT_DATA_SZ; + uint32_t d_MBOX_BASE_ADDRESS; + uint32_t d_LOCAL_SCRATCH_OFFSET; + uint32_t d_CPU_CLOCK_OFFSET; + uint32_t d_LPO_CAL_OFFSET; + uint32_t d_GPIO_PIN10_OFFSET; + uint32_t d_GPIO_PIN11_OFFSET; + uint32_t d_GPIO_PIN12_OFFSET; + uint32_t d_GPIO_PIN13_OFFSET; + uint32_t d_CLOCK_GPIO_OFFSET; + uint32_t d_CPU_CLOCK_STANDARD_LSB; + uint32_t d_CPU_CLOCK_STANDARD_MASK; + uint32_t d_LPO_CAL_ENABLE_LSB; + uint32_t d_LPO_CAL_ENABLE_MASK; + uint32_t d_CLOCK_GPIO_BT_CLK_OUT_EN_LSB; + uint32_t d_CLOCK_GPIO_BT_CLK_OUT_EN_MASK; + uint32_t d_ANALOG_INTF_BASE_ADDRESS; + uint32_t d_WLAN_MAC_BASE_ADDRESS; + uint32_t d_CE0_BASE_ADDRESS; + uint32_t d_CE1_BASE_ADDRESS; + uint32_t d_FW_INDICATOR_ADDRESS; + uint32_t d_FW_CPU_PLL_CONFIG; + uint32_t d_DRAM_BASE_ADDRESS; + uint32_t d_SOC_CORE_BASE_ADDRESS; + uint32_t d_CORE_CTRL_ADDRESS; + uint32_t d_CE_COUNT; + uint32_t d_MSI_NUM_REQUEST; + uint32_t d_MSI_ASSIGN_FW; + uint32_t d_MSI_ASSIGN_CE_INITIAL; + uint32_t d_PCIE_INTR_ENABLE_ADDRESS; + uint32_t d_PCIE_INTR_CLR_ADDRESS; + uint32_t d_PCIE_INTR_FIRMWARE_MASK; + uint32_t d_PCIE_INTR_CE_MASK_ALL; + uint32_t d_CORE_CTRL_CPU_INTR_MASK; + uint32_t d_WIFICMN_PCIE_BAR_REG_ADDRESS; + /* htt_rx.c */ + /* htt tx */ + uint32_t d_MSDU_LINK_EXT_3_TCP_OVER_IPV4_CHECKSUM_EN_MASK; + uint32_t d_MSDU_LINK_EXT_3_TCP_OVER_IPV6_CHECKSUM_EN_MASK; + uint32_t d_MSDU_LINK_EXT_3_UDP_OVER_IPV4_CHECKSUM_EN_MASK; + uint32_t d_MSDU_LINK_EXT_3_UDP_OVER_IPV6_CHECKSUM_EN_MASK; + uint32_t d_MSDU_LINK_EXT_3_TCP_OVER_IPV4_CHECKSUM_EN_LSB; + uint32_t d_MSDU_LINK_EXT_3_TCP_OVER_IPV6_CHECKSUM_EN_LSB; + uint32_t d_MSDU_LINK_EXT_3_UDP_OVER_IPV4_CHECKSUM_EN_LSB; + uint32_t d_MSDU_LINK_EXT_3_UDP_OVER_IPV6_CHECKSUM_EN_LSB; + /* copy_engine.c */ + uint32_t d_DST_WR_INDEX_ADDRESS; + uint32_t d_SRC_WATERMARK_ADDRESS; + uint32_t d_SRC_WATERMARK_LOW_MASK; + uint32_t d_SRC_WATERMARK_HIGH_MASK; + uint32_t d_DST_WATERMARK_LOW_MASK; + uint32_t d_DST_WATERMARK_HIGH_MASK; + uint32_t d_CURRENT_SRRI_ADDRESS; + uint32_t d_CURRENT_DRRI_ADDRESS; + uint32_t d_HOST_IS_SRC_RING_HIGH_WATERMARK_MASK; + uint32_t d_HOST_IS_SRC_RING_LOW_WATERMARK_MASK; + uint32_t d_HOST_IS_DST_RING_HIGH_WATERMARK_MASK; + uint32_t d_HOST_IS_DST_RING_LOW_WATERMARK_MASK; + uint32_t d_HOST_IS_ADDRESS; + uint32_t d_HOST_IS_COPY_COMPLETE_MASK; + uint32_t d_CE_CMD_ADDRESS; + uint32_t d_CE_CMD_HALT_MASK; + uint32_t d_CE_WRAPPER_BASE_ADDRESS; + uint32_t d_CE_WRAPPER_INTERRUPT_SUMMARY_ADDRESS; + uint32_t d_HOST_IE_ADDRESS; + uint32_t d_HOST_IE_COPY_COMPLETE_MASK; + uint32_t d_SR_BA_ADDRESS; + uint32_t d_SR_SIZE_ADDRESS; + uint32_t d_CE_CTRL1_ADDRESS; + uint32_t d_CE_CTRL1_DMAX_LENGTH_MASK; + uint32_t d_DR_BA_ADDRESS; + uint32_t d_DR_SIZE_ADDRESS; + uint32_t d_MISC_IE_ADDRESS; + uint32_t d_MISC_IS_AXI_ERR_MASK; + uint32_t d_MISC_IS_DST_ADDR_ERR_MASK; + uint32_t d_MISC_IS_SRC_LEN_ERR_MASK; + uint32_t d_MISC_IS_DST_MAX_LEN_VIO_MASK; + uint32_t d_MISC_IS_DST_RING_OVERFLOW_MASK; + uint32_t d_MISC_IS_SRC_RING_OVERFLOW_MASK; + uint32_t d_SRC_WATERMARK_LOW_LSB; + uint32_t d_SRC_WATERMARK_HIGH_LSB; + uint32_t d_DST_WATERMARK_LOW_LSB; + uint32_t d_DST_WATERMARK_HIGH_LSB; + uint32_t d_CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_MASK; + uint32_t d_CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_LSB; + uint32_t d_CE_CTRL1_DMAX_LENGTH_LSB; + uint32_t d_CE_CTRL1_SRC_RING_BYTE_SWAP_EN_MASK; + uint32_t d_CE_CTRL1_DST_RING_BYTE_SWAP_EN_MASK; + uint32_t d_CE_CTRL1_SRC_RING_BYTE_SWAP_EN_LSB; + uint32_t d_CE_CTRL1_DST_RING_BYTE_SWAP_EN_LSB; + uint32_t d_CE_CMD_HALT_STATUS_MASK; + uint32_t d_CE_CMD_HALT_STATUS_LSB; + uint32_t d_SR_WR_INDEX_ADDRESS; + uint32_t d_DST_WATERMARK_ADDRESS; + + /* htt_rx.c */ + uint32_t d_RX_MSDU_END_4_FIRST_MSDU_MASK; + uint32_t d_RX_MSDU_END_4_FIRST_MSDU_LSB; + uint32_t d_RX_MPDU_START_0_RETRY_LSB; + uint32_t d_RX_MPDU_START_0_RETRY_MASK; + uint32_t d_RX_MPDU_START_0_SEQ_NUM_MASK; + uint32_t d_RX_MPDU_START_0_SEQ_NUM_LSB; + uint32_t d_RX_MPDU_START_2_PN_47_32_LSB; + uint32_t d_RX_MPDU_START_2_PN_47_32_MASK; + uint32_t d_RX_MPDU_START_2_TID_LSB; + uint32_t d_RX_MPDU_START_2_TID_MASK; + uint32_t d_RX_MSDU_END_1_EXT_WAPI_PN_63_48_MASK; + uint32_t d_RX_MSDU_END_1_EXT_WAPI_PN_63_48_LSB; + uint32_t d_RX_MSDU_END_1_KEY_ID_OCT_MASK; + uint32_t d_RX_MSDU_END_1_KEY_ID_OCT_LSB; + uint32_t d_RX_MSDU_END_4_LAST_MSDU_MASK; + uint32_t d_RX_MSDU_END_4_LAST_MSDU_LSB; + uint32_t d_RX_ATTENTION_0_MCAST_BCAST_MASK; + uint32_t d_RX_ATTENTION_0_MCAST_BCAST_LSB; + uint32_t d_RX_ATTENTION_0_FRAGMENT_MASK; + uint32_t d_RX_ATTENTION_0_FRAGMENT_LSB; + uint32_t d_RX_ATTENTION_0_MPDU_LENGTH_ERR_MASK; + uint32_t d_RX_FRAG_INFO_0_RING2_MORE_COUNT_MASK; + uint32_t d_RX_FRAG_INFO_0_RING2_MORE_COUNT_LSB; + uint32_t d_RX_MSDU_START_0_MSDU_LENGTH_MASK; + uint32_t d_RX_MSDU_START_0_MSDU_LENGTH_LSB; + uint32_t d_RX_MSDU_START_2_DECAP_FORMAT_OFFSET; + uint32_t d_RX_MSDU_START_2_DECAP_FORMAT_MASK; + uint32_t d_RX_MSDU_START_2_DECAP_FORMAT_LSB; + uint32_t d_RX_MPDU_START_0_ENCRYPTED_MASK; + uint32_t d_RX_MPDU_START_0_ENCRYPTED_LSB; + uint32_t d_RX_ATTENTION_0_MORE_DATA_MASK; + uint32_t d_RX_ATTENTION_0_MSDU_DONE_MASK; + uint32_t d_RX_ATTENTION_0_TCP_UDP_CHKSUM_FAIL_MASK; + /* end */ + + /* PLL start */ + uint32_t d_EFUSE_OFFSET; + uint32_t d_EFUSE_XTAL_SEL_MSB; + uint32_t d_EFUSE_XTAL_SEL_LSB; + uint32_t d_EFUSE_XTAL_SEL_MASK; + uint32_t d_BB_PLL_CONFIG_OFFSET; + uint32_t d_BB_PLL_CONFIG_OUTDIV_MSB; + uint32_t d_BB_PLL_CONFIG_OUTDIV_LSB; + uint32_t d_BB_PLL_CONFIG_OUTDIV_MASK; + uint32_t d_BB_PLL_CONFIG_FRAC_MSB; + uint32_t d_BB_PLL_CONFIG_FRAC_LSB; + uint32_t d_BB_PLL_CONFIG_FRAC_MASK; + uint32_t d_WLAN_PLL_SETTLE_TIME_MSB; + uint32_t d_WLAN_PLL_SETTLE_TIME_LSB; + uint32_t d_WLAN_PLL_SETTLE_TIME_MASK; + uint32_t d_WLAN_PLL_SETTLE_OFFSET; + uint32_t d_WLAN_PLL_SETTLE_SW_MASK; + uint32_t d_WLAN_PLL_SETTLE_RSTMASK; + uint32_t d_WLAN_PLL_SETTLE_RESET; + uint32_t d_WLAN_PLL_CONTROL_NOPWD_MSB; + uint32_t d_WLAN_PLL_CONTROL_NOPWD_LSB; + uint32_t d_WLAN_PLL_CONTROL_NOPWD_MASK; + uint32_t d_WLAN_PLL_CONTROL_BYPASS_MSB; + uint32_t d_WLAN_PLL_CONTROL_BYPASS_LSB; + uint32_t d_WLAN_PLL_CONTROL_BYPASS_MASK; + uint32_t d_WLAN_PLL_CONTROL_BYPASS_RESET; + uint32_t d_WLAN_PLL_CONTROL_CLK_SEL_MSB; + uint32_t d_WLAN_PLL_CONTROL_CLK_SEL_LSB; + uint32_t d_WLAN_PLL_CONTROL_CLK_SEL_MASK; + uint32_t d_WLAN_PLL_CONTROL_CLK_SEL_RESET; + uint32_t d_WLAN_PLL_CONTROL_REFDIV_MSB; + uint32_t d_WLAN_PLL_CONTROL_REFDIV_LSB; + uint32_t d_WLAN_PLL_CONTROL_REFDIV_MASK; + uint32_t d_WLAN_PLL_CONTROL_REFDIV_RESET; + uint32_t d_WLAN_PLL_CONTROL_DIV_MSB; + uint32_t d_WLAN_PLL_CONTROL_DIV_LSB; + uint32_t d_WLAN_PLL_CONTROL_DIV_MASK; + uint32_t d_WLAN_PLL_CONTROL_DIV_RESET; + uint32_t d_WLAN_PLL_CONTROL_OFFSET; + uint32_t d_WLAN_PLL_CONTROL_SW_MASK; + uint32_t d_WLAN_PLL_CONTROL_RSTMASK; + uint32_t d_WLAN_PLL_CONTROL_RESET; + uint32_t d_SOC_CORE_CLK_CTRL_OFFSET; + uint32_t d_SOC_CORE_CLK_CTRL_DIV_MSB; + uint32_t d_SOC_CORE_CLK_CTRL_DIV_LSB; + uint32_t d_SOC_CORE_CLK_CTRL_DIV_MASK; + uint32_t d_RTC_SYNC_STATUS_PLL_CHANGING_MSB; + uint32_t d_RTC_SYNC_STATUS_PLL_CHANGING_LSB; + uint32_t d_RTC_SYNC_STATUS_PLL_CHANGING_MASK; + uint32_t d_RTC_SYNC_STATUS_PLL_CHANGING_RESET; + uint32_t d_RTC_SYNC_STATUS_OFFSET; + uint32_t d_SOC_CPU_CLOCK_OFFSET; + uint32_t d_SOC_CPU_CLOCK_STANDARD_MSB; + uint32_t d_SOC_CPU_CLOCK_STANDARD_LSB; + uint32_t d_SOC_CPU_CLOCK_STANDARD_MASK; + /* PLL end */ + + uint32_t d_SOC_POWER_REG_OFFSET; + uint32_t d_PCIE_INTR_CAUSE_ADDRESS; + uint32_t d_SOC_RESET_CONTROL_ADDRESS; + uint32_t d_SOC_RESET_CONTROL_PCIE_RST_SHORT_OVRD_MASK; + uint32_t d_SOC_RESET_CONTROL_PCIE_RST_SHORT_OVRD_LSB; + uint32_t d_SOC_RESET_CONTROL_CE_RST_MASK; + uint32_t d_SOC_RESET_CONTROL_CPU_WARM_RST_MASK; + uint32_t d_CPU_INTR_ADDRESS; + uint32_t d_SOC_LF_TIMER_CONTROL0_ADDRESS; + uint32_t d_SOC_LF_TIMER_CONTROL0_ENABLE_MASK; + + /* chip id start */ + uint32_t d_SI_CONFIG_ERR_INT_MASK; + uint32_t d_SI_CONFIG_ERR_INT_LSB; + uint32_t d_GPIO_ENABLE_W1TS_LOW_ADDRESS; + uint32_t d_GPIO_PIN0_CONFIG_LSB; + uint32_t d_GPIO_PIN0_PAD_PULL_LSB; + uint32_t d_GPIO_PIN0_PAD_PULL_MASK; + + uint32_t d_SOC_CHIP_ID_ADDRESS; + uint32_t d_SOC_CHIP_ID_VERSION_MASK; + uint32_t d_SOC_CHIP_ID_VERSION_LSB; + uint32_t d_SOC_CHIP_ID_REVISION_MASK; + uint32_t d_SOC_CHIP_ID_REVISION_LSB; + uint32_t d_SOC_CHIP_ID_REVISION_MSB; + uint32_t d_FW_AXI_MSI_ADDR; + uint32_t d_FW_AXI_MSI_DATA; + uint32_t d_WLAN_SUBSYSTEM_CORE_ID_ADDRESS; + uint32_t d_FPGA_VERSION_ADDRESS; + + /* chip id end */ + + uint32_t d_A_SOC_CORE_SCRATCH_0_ADDRESS; + uint32_t d_A_SOC_CORE_SCRATCH_1_ADDRESS; + uint32_t d_A_SOC_CORE_SCRATCH_2_ADDRESS; + uint32_t d_A_SOC_CORE_SCRATCH_3_ADDRESS; + uint32_t d_A_SOC_CORE_SCRATCH_4_ADDRESS; + uint32_t d_A_SOC_CORE_SCRATCH_5_ADDRESS; + uint32_t d_A_SOC_CORE_SCRATCH_6_ADDRESS; + uint32_t d_A_SOC_CORE_SCRATCH_7_ADDRESS; + uint32_t d_A_SOC_CORE_SPARE_0_REGISTER; + uint32_t d_PCIE_INTR_FIRMWARE_ROUTE_MASK; + uint32_t d_A_SOC_CORE_PCIE_INTR_CAUSE_GRP1; + uint32_t d_A_SOC_CORE_SPARE_1_REGISTER; + uint32_t d_A_SOC_CORE_PCIE_INTR_CLR_GRP1; + uint32_t d_A_SOC_CORE_PCIE_INTR_ENABLE_GRP1; + uint32_t d_A_SOC_PCIE_PCIE_SCRATCH_0; + uint32_t d_A_SOC_PCIE_PCIE_SCRATCH_1; + uint32_t d_A_WIFI_APB_1_A_WFSS_CE_TARGET_HOST_DELTA; + uint32_t d_A_SOC_PCIE_PCIE_SCRATCH_2; + uint32_t d_A_SOC_CORE_PCIE_INTR_ENABLE_GRP0_Q6_MASK; + + uint32_t d_WLAN_DEBUG_INPUT_SEL_OFFSET; + uint32_t d_WLAN_DEBUG_INPUT_SEL_SRC_MSB; + uint32_t d_WLAN_DEBUG_INPUT_SEL_SRC_LSB; + uint32_t d_WLAN_DEBUG_INPUT_SEL_SRC_MASK; + uint32_t d_WLAN_DEBUG_CONTROL_OFFSET; + uint32_t d_WLAN_DEBUG_CONTROL_ENABLE_MSB; + uint32_t d_WLAN_DEBUG_CONTROL_ENABLE_LSB; + uint32_t d_WLAN_DEBUG_CONTROL_ENABLE_MASK; + uint32_t d_WLAN_DEBUG_OUT_OFFSET; + uint32_t d_WLAN_DEBUG_OUT_DATA_MSB; + uint32_t d_WLAN_DEBUG_OUT_DATA_LSB; + uint32_t d_WLAN_DEBUG_OUT_DATA_MASK; + uint32_t d_AMBA_DEBUG_BUS_OFFSET; + uint32_t d_AMBA_DEBUG_BUS_PCIE_DEBUG_SEL_MSB; + uint32_t d_AMBA_DEBUG_BUS_PCIE_DEBUG_SEL_LSB; + uint32_t d_AMBA_DEBUG_BUS_PCIE_DEBUG_SEL_MASK; + uint32_t d_AMBA_DEBUG_BUS_SEL_MSB; + uint32_t d_AMBA_DEBUG_BUS_SEL_LSB; + uint32_t d_AMBA_DEBUG_BUS_SEL_MASK; + +#ifdef QCA_WIFI_3_0_ADRASTEA + uint32_t d_Q6_ENABLE_REGISTER_0; + uint32_t d_Q6_ENABLE_REGISTER_1; + uint32_t d_Q6_CAUSE_REGISTER_0; + uint32_t d_Q6_CAUSE_REGISTER_1; + uint32_t d_Q6_CLEAR_REGISTER_0; + uint32_t d_Q6_CLEAR_REGISTER_1; +#endif +#ifdef CONFIG_BYPASS_QMI + uint32_t d_BYPASS_QMI_TEMP_REGISTER; +#endif + uint32_t d_WIFICMN_INT_STATUS_ADDRESS; +}; + +struct hostdef_s { + uint32_t d_INT_STATUS_ENABLE_ERROR_LSB; + uint32_t d_INT_STATUS_ENABLE_ERROR_MASK; + uint32_t d_INT_STATUS_ENABLE_CPU_LSB; + uint32_t d_INT_STATUS_ENABLE_CPU_MASK; + uint32_t d_INT_STATUS_ENABLE_COUNTER_LSB; + uint32_t d_INT_STATUS_ENABLE_COUNTER_MASK; + uint32_t d_INT_STATUS_ENABLE_MBOX_DATA_LSB; + uint32_t d_INT_STATUS_ENABLE_MBOX_DATA_MASK; + uint32_t d_ERROR_STATUS_ENABLE_RX_UNDERFLOW_LSB; + uint32_t d_ERROR_STATUS_ENABLE_RX_UNDERFLOW_MASK; + uint32_t d_ERROR_STATUS_ENABLE_TX_OVERFLOW_LSB; + uint32_t d_ERROR_STATUS_ENABLE_TX_OVERFLOW_MASK; + uint32_t d_COUNTER_INT_STATUS_ENABLE_BIT_LSB; + uint32_t d_COUNTER_INT_STATUS_ENABLE_BIT_MASK; + uint32_t d_INT_STATUS_ENABLE_ADDRESS; + uint32_t d_CPU_INT_STATUS_ENABLE_BIT_LSB; + uint32_t d_CPU_INT_STATUS_ENABLE_BIT_MASK; + uint32_t d_HOST_INT_STATUS_ADDRESS; + uint32_t d_CPU_INT_STATUS_ADDRESS; + uint32_t d_ERROR_INT_STATUS_ADDRESS; + uint32_t d_ERROR_INT_STATUS_WAKEUP_MASK; + uint32_t d_ERROR_INT_STATUS_WAKEUP_LSB; + uint32_t d_ERROR_INT_STATUS_RX_UNDERFLOW_MASK; + uint32_t d_ERROR_INT_STATUS_RX_UNDERFLOW_LSB; + uint32_t d_ERROR_INT_STATUS_TX_OVERFLOW_MASK; + uint32_t d_ERROR_INT_STATUS_TX_OVERFLOW_LSB; + uint32_t d_COUNT_DEC_ADDRESS; + uint32_t d_HOST_INT_STATUS_CPU_MASK; + uint32_t d_HOST_INT_STATUS_CPU_LSB; + uint32_t d_HOST_INT_STATUS_ERROR_MASK; + uint32_t d_HOST_INT_STATUS_ERROR_LSB; + uint32_t d_HOST_INT_STATUS_COUNTER_MASK; + uint32_t d_HOST_INT_STATUS_COUNTER_LSB; + uint32_t d_RX_LOOKAHEAD_VALID_ADDRESS; + uint32_t d_WINDOW_DATA_ADDRESS; + uint32_t d_WINDOW_READ_ADDR_ADDRESS; + uint32_t d_WINDOW_WRITE_ADDR_ADDRESS; + uint32_t d_SOC_GLOBAL_RESET_ADDRESS; + uint32_t d_RTC_STATE_ADDRESS; + uint32_t d_RTC_STATE_COLD_RESET_MASK; + uint32_t d_PCIE_LOCAL_BASE_ADDRESS; + uint32_t d_PCIE_SOC_WAKE_RESET; + uint32_t d_PCIE_SOC_WAKE_ADDRESS; + uint32_t d_PCIE_SOC_WAKE_V_MASK; + uint32_t d_RTC_STATE_V_MASK; + uint32_t d_RTC_STATE_V_LSB; + uint32_t d_FW_IND_EVENT_PENDING; + uint32_t d_FW_IND_INITIALIZED; + uint32_t d_FW_IND_HELPER; + uint32_t d_RTC_STATE_V_ON; +#if defined(SDIO_3_0) + uint32_t d_HOST_INT_STATUS_MBOX_DATA_MASK; + uint32_t d_HOST_INT_STATUS_MBOX_DATA_LSB; +#endif + uint32_t d_PCIE_SOC_RDY_STATUS_ADDRESS; + uint32_t d_PCIE_SOC_RDY_STATUS_BAR_MASK; + uint32_t d_SOC_PCIE_BASE_ADDRESS; + uint32_t d_MSI_MAGIC_ADR_ADDRESS; + uint32_t d_MSI_MAGIC_ADDRESS; + uint32_t d_HOST_CE_COUNT; + uint32_t d_ENABLE_MSI; + uint32_t d_MUX_ID_MASK; + uint32_t d_TRANSACTION_ID_MASK; + uint32_t d_DESC_DATA_FLAG_MASK; + uint32_t d_A_SOC_PCIE_PCIE_BAR0_START; + uint32_t d_FW_IND_HOST_READY; +}; + +struct host_shadow_regs_s { + uint32_t d_A_LOCAL_SHADOW_REG_VALUE_0; + uint32_t d_A_LOCAL_SHADOW_REG_VALUE_1; + uint32_t d_A_LOCAL_SHADOW_REG_VALUE_2; + uint32_t d_A_LOCAL_SHADOW_REG_VALUE_3; + uint32_t d_A_LOCAL_SHADOW_REG_VALUE_4; + uint32_t d_A_LOCAL_SHADOW_REG_VALUE_5; + uint32_t d_A_LOCAL_SHADOW_REG_VALUE_6; + uint32_t d_A_LOCAL_SHADOW_REG_VALUE_7; + uint32_t d_A_LOCAL_SHADOW_REG_VALUE_8; + uint32_t d_A_LOCAL_SHADOW_REG_VALUE_9; + uint32_t d_A_LOCAL_SHADOW_REG_VALUE_10; + uint32_t d_A_LOCAL_SHADOW_REG_VALUE_11; + uint32_t d_A_LOCAL_SHADOW_REG_VALUE_12; + uint32_t d_A_LOCAL_SHADOW_REG_VALUE_13; + uint32_t d_A_LOCAL_SHADOW_REG_VALUE_14; + uint32_t d_A_LOCAL_SHADOW_REG_VALUE_15; + uint32_t d_A_LOCAL_SHADOW_REG_VALUE_16; + uint32_t d_A_LOCAL_SHADOW_REG_VALUE_17; + uint32_t d_A_LOCAL_SHADOW_REG_VALUE_18; + uint32_t d_A_LOCAL_SHADOW_REG_VALUE_19; + uint32_t d_A_LOCAL_SHADOW_REG_VALUE_20; + uint32_t d_A_LOCAL_SHADOW_REG_VALUE_21; + uint32_t d_A_LOCAL_SHADOW_REG_VALUE_22; + uint32_t d_A_LOCAL_SHADOW_REG_VALUE_23; + uint32_t d_A_LOCAL_SHADOW_REG_ADDRESS_0; + uint32_t d_A_LOCAL_SHADOW_REG_ADDRESS_1; + uint32_t d_A_LOCAL_SHADOW_REG_ADDRESS_2; + uint32_t d_A_LOCAL_SHADOW_REG_ADDRESS_3; + uint32_t d_A_LOCAL_SHADOW_REG_ADDRESS_4; + uint32_t d_A_LOCAL_SHADOW_REG_ADDRESS_5; + uint32_t d_A_LOCAL_SHADOW_REG_ADDRESS_6; + uint32_t d_A_LOCAL_SHADOW_REG_ADDRESS_7; + uint32_t d_A_LOCAL_SHADOW_REG_ADDRESS_8; + uint32_t d_A_LOCAL_SHADOW_REG_ADDRESS_9; + uint32_t d_A_LOCAL_SHADOW_REG_ADDRESS_10; + uint32_t d_A_LOCAL_SHADOW_REG_ADDRESS_11; + uint32_t d_A_LOCAL_SHADOW_REG_ADDRESS_12; + uint32_t d_A_LOCAL_SHADOW_REG_ADDRESS_13; + uint32_t d_A_LOCAL_SHADOW_REG_ADDRESS_14; + uint32_t d_A_LOCAL_SHADOW_REG_ADDRESS_15; + uint32_t d_A_LOCAL_SHADOW_REG_ADDRESS_16; + uint32_t d_A_LOCAL_SHADOW_REG_ADDRESS_17; + uint32_t d_A_LOCAL_SHADOW_REG_ADDRESS_18; + uint32_t d_A_LOCAL_SHADOW_REG_ADDRESS_19; + uint32_t d_A_LOCAL_SHADOW_REG_ADDRESS_20; + uint32_t d_A_LOCAL_SHADOW_REG_ADDRESS_21; + uint32_t d_A_LOCAL_SHADOW_REG_ADDRESS_22; + uint32_t d_A_LOCAL_SHADOW_REG_ADDRESS_23; +}; + + +/* + * @d_DST_WR_INDEX_ADDRESS: Destination ring write index + * + * @d_SRC_WATERMARK_ADDRESS: Source ring watermark + * + * @d_SRC_WATERMARK_LOW_MASK: Bits indicating low watermark from Source ring + * watermark + * + * @d_SRC_WATERMARK_HIGH_MASK: Bits indicating high watermark from Source ring + * watermark + * + * @d_DST_WATERMARK_LOW_MASK: Bits indicating low watermark from Destination + * ring watermark + * + * @d_DST_WATERMARK_HIGH_MASK: Bits indicating high watermark from Destination + * ring watermark + * + * @d_CURRENT_SRRI_ADDRESS: Current source ring read index.The Start Offset + * will be reflected after a CE transfer is completed. + * + * @d_CURRENT_DRRI_ADDRESS: Current Destination ring read index. The Start + * Offset will be reflected after a CE transfer + * is completed. + * + * @d_HOST_IS_SRC_RING_HIGH_WATERMARK_MASK: Source ring high watermark + * Interrupt Status + * + * @d_HOST_IS_SRC_RING_LOW_WATERMARK_MASK: Source ring low watermark + * Interrupt Status + * + * @d_HOST_IS_DST_RING_HIGH_WATERMARK_MASK: Destination ring high watermark + * Interrupt Status + * + * @d_HOST_IS_DST_RING_LOW_WATERMARK_MASK: Source ring low watermark + * Interrupt Status + * + * @d_HOST_IS_ADDRESS: Host Interrupt Status Register + * + * @d_MISC_IS_ADDRESS: Miscellaneous Interrupt Status Register + * + * @d_HOST_IS_COPY_COMPLETE_MASK: Bits indicating Copy complete interrupt + * status from the Host Interrupt Status + * register + * + * @d_CE_WRAPPER_BASE_ADDRESS: Copy Engine Wrapper Base Address + * + * @d_CE_WRAPPER_INTERRUPT_SUMMARY_ADDRESS: CE Wrapper summary for interrupts + * to host + * + * @d_CE_WRAPPER_INDEX_BASE_LOW: The LSB Base address to which source and + * destination read indices are written + * + * @d_CE_WRAPPER_INDEX_BASE_HIGH: The MSB Base address to which source and + * destination read indices are written + * + * @d_HOST_IE_ADDRESS: Host Line Interrupt Enable Register + * + * @d_HOST_IE_COPY_COMPLETE_MASK: Bits indicating Copy complete interrupt + * enable from the IE register + * + * @d_SR_BA_ADDRESS: LSB of Source Ring Base Address + * + * @d_SR_BA_ADDRESS_HIGH: MSB of Source Ring Base Address + * + * @d_SR_SIZE_ADDRESS: Source Ring size - number of entries and Start Offset + * + * @d_CE_CTRL1_ADDRESS: CE Control register + * + * @d_CE_CTRL1_DMAX_LENGTH_MASK: Destination buffer Max Length used for error + * check + * + * @d_DR_BA_ADDRESS: Destination Ring Base Address Low + * + * @d_DR_BA_ADDRESS_HIGH: Destination Ring Base Address High + * + * @d_DR_SIZE_ADDRESS: Destination Ring size - number of entries Start Offset + * + * @d_CE_CMD_REGISTER: Implements commands to all CE Halt Flush + * + * @d_CE_MSI_ADDRESS: CE MSI LOW Address register + * + * @d_CE_MSI_ADDRESS_HIGH: CE MSI High Address register + * + * @d_CE_MSI_DATA: CE MSI Data Register + * + * @d_CE_MSI_ENABLE_BIT: Bit in CTRL1 register indication the MSI enable + * + * @d_MISC_IE_ADDRESS: Miscellaneous Interrupt Enable Register + * + * @d_MISC_IS_AXI_ERR_MASK: + * Bit in Misc IS indicating AXI Timeout Interrupt status + * + * @d_MISC_IS_DST_ADDR_ERR_MASK: + * Bit in Misc IS indicating Destination Address Error + * + * @d_MISC_IS_SRC_LEN_ERR_MASK: Bit in Misc IS indicating Source Zero Length + * Error Interrupt status + * + * @d_MISC_IS_DST_MAX_LEN_VIO_MASK: Bit in Misc IS indicating Destination Max + * Length Violated Interrupt status + * + * @d_MISC_IS_DST_RING_OVERFLOW_MASK: Bit in Misc IS indicating Destination + * Ring Overflow Interrupt status + * + * @d_MISC_IS_SRC_RING_OVERFLOW_MASK: Bit in Misc IS indicating Source Ring + * Overflow Interrupt status + * + * @d_SRC_WATERMARK_LOW_LSB: Source Ring Low Watermark LSB + * + * @d_SRC_WATERMARK_HIGH_LSB: Source Ring Low Watermark MSB + * + * @d_DST_WATERMARK_LOW_LSB: Destination Ring Low Watermark LSB + * + * @d_DST_WATERMARK_HIGH_LSB: Destination Ring High Watermark LSB + * + * @d_CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_MASK: + * Bits in d_CE_WRAPPER_INTERRUPT_SUMMARY_ADDR + * indicating Copy engine miscellaneous interrupt summary + * + * @d_CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_LSB: + * Bits in d_CE_WRAPPER_INTERRUPT_SUMMARY_ADDR + * indicating Host interrupts summary + * + * @d_CE_CTRL1_DMAX_LENGTH_LSB: + * LSB of Destination buffer Max Length used for error check + * + * @d_CE_CTRL1_SRC_RING_BYTE_SWAP_EN_MASK: + * Bits indicating Source ring Byte Swap enable. + * Treats source ring memory organisation as big-endian. + * + * @d_CE_CTRL1_DST_RING_BYTE_SWAP_EN_MASK: + * Bits indicating Destination ring byte swap enable. + * Treats destination ring memory organisation as big-endian + * + * @d_CE_CTRL1_SRC_RING_BYTE_SWAP_EN_LSB: + * LSB of Source ring Byte Swap enable + * + * @d_CE_CTRL1_DST_RING_BYTE_SWAP_EN_LSB: + * LSB of Destination ring Byte Swap enable + * + * @d_CE_WRAPPER_DEBUG_OFFSET: Offset of CE OBS BUS Select register + * + * @d_CE_WRAPPER_DEBUG_SEL_MSB: + * MSB of Control register selecting inputs for trace/debug + * + * @d_CE_WRAPPER_DEBUG_SEL_LSB: + * LSB of Control register selecting inputs for trace/debug + * + * @d_CE_WRAPPER_DEBUG_SEL_MASK: + * Bit mask for trace/debug Control register + * + * @d_CE_DEBUG_OFFSET: Offset of Copy Engine FSM Debug Status + * + * @d_CE_DEBUG_SEL_MSB: MSB of Copy Engine FSM Debug Status + * + * @d_CE_DEBUG_SEL_LSB: LSB of Copy Engine FSM Debug Status + * + * @d_CE_DEBUG_SEL_MASK: Bits indicating Copy Engine FSM Debug Status + * + */ +struct ce_reg_def { + /* copy_engine.c */ + uint32_t d_DST_WR_INDEX_ADDRESS; + uint32_t d_SRC_WATERMARK_ADDRESS; + uint32_t d_SRC_WATERMARK_LOW_MASK; + uint32_t d_SRC_WATERMARK_HIGH_MASK; + uint32_t d_DST_WATERMARK_LOW_MASK; + uint32_t d_DST_WATERMARK_HIGH_MASK; + uint32_t d_CURRENT_SRRI_ADDRESS; + uint32_t d_CURRENT_DRRI_ADDRESS; + uint32_t d_HOST_IS_SRC_RING_HIGH_WATERMARK_MASK; + uint32_t d_HOST_IS_SRC_RING_LOW_WATERMARK_MASK; + uint32_t d_HOST_IS_DST_RING_HIGH_WATERMARK_MASK; + uint32_t d_HOST_IS_DST_RING_LOW_WATERMARK_MASK; + uint32_t d_HOST_IS_ADDRESS; + uint32_t d_MISC_IS_ADDRESS; + uint32_t d_HOST_IS_COPY_COMPLETE_MASK; + uint32_t d_CE_WRAPPER_BASE_ADDRESS; + uint32_t d_CE_WRAPPER_INTERRUPT_SUMMARY_ADDRESS; + uint32_t d_CE_DDR_ADDRESS_FOR_RRI_LOW; + uint32_t d_CE_DDR_ADDRESS_FOR_RRI_HIGH; + uint32_t d_HOST_IE_ADDRESS; + uint32_t d_HOST_IE_COPY_COMPLETE_MASK; + uint32_t d_SR_BA_ADDRESS; + uint32_t d_SR_BA_ADDRESS_HIGH; + uint32_t d_SR_SIZE_ADDRESS; + uint32_t d_CE_CTRL1_ADDRESS; + uint32_t d_CE_CTRL1_DMAX_LENGTH_MASK; + uint32_t d_DR_BA_ADDRESS; + uint32_t d_DR_BA_ADDRESS_HIGH; + uint32_t d_DR_SIZE_ADDRESS; + uint32_t d_CE_CMD_REGISTER; + uint32_t d_CE_MSI_ADDRESS; + uint32_t d_CE_MSI_ADDRESS_HIGH; + uint32_t d_CE_MSI_DATA; + uint32_t d_CE_MSI_ENABLE_BIT; + uint32_t d_MISC_IE_ADDRESS; + uint32_t d_MISC_IS_AXI_ERR_MASK; + uint32_t d_MISC_IS_DST_ADDR_ERR_MASK; + uint32_t d_MISC_IS_SRC_LEN_ERR_MASK; + uint32_t d_MISC_IS_DST_MAX_LEN_VIO_MASK; + uint32_t d_MISC_IS_DST_RING_OVERFLOW_MASK; + uint32_t d_MISC_IS_SRC_RING_OVERFLOW_MASK; + uint32_t d_SRC_WATERMARK_LOW_LSB; + uint32_t d_SRC_WATERMARK_HIGH_LSB; + uint32_t d_DST_WATERMARK_LOW_LSB; + uint32_t d_DST_WATERMARK_HIGH_LSB; + uint32_t d_CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_MASK; + uint32_t d_CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_LSB; + uint32_t d_CE_CTRL1_DMAX_LENGTH_LSB; + uint32_t d_CE_CTRL1_SRC_RING_BYTE_SWAP_EN_MASK; + uint32_t d_CE_CTRL1_DST_RING_BYTE_SWAP_EN_MASK; + uint32_t d_CE_CTRL1_SRC_RING_BYTE_SWAP_EN_LSB; + uint32_t d_CE_CTRL1_DST_RING_BYTE_SWAP_EN_LSB; + uint32_t d_CE_CTRL1_IDX_UPD_EN_MASK; + uint32_t d_CE_WRAPPER_DEBUG_OFFSET; + uint32_t d_CE_WRAPPER_DEBUG_SEL_MSB; + uint32_t d_CE_WRAPPER_DEBUG_SEL_LSB; + uint32_t d_CE_WRAPPER_DEBUG_SEL_MASK; + uint32_t d_CE_DEBUG_OFFSET; + uint32_t d_CE_DEBUG_SEL_MSB; + uint32_t d_CE_DEBUG_SEL_LSB; + uint32_t d_CE_DEBUG_SEL_MASK; + uint32_t d_CE0_BASE_ADDRESS; + uint32_t d_CE1_BASE_ADDRESS; + uint32_t d_A_WIFI_APB_3_A_WCMN_APPS_CE_INTR_ENABLES; + uint32_t d_A_WIFI_APB_3_A_WCMN_APPS_CE_INTR_STATUS; +}; + +#endif diff --git a/drivers/staging/qca-wifi-host-cmn/hif/inc/regtable.h b/drivers/staging/qca-wifi-host-cmn/hif/inc/regtable.h new file mode 100644 index 0000000000000000000000000000000000000000..fe460499022f1a96ad2e678c1177c0cc08cebec0 --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/hif/inc/regtable.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2015-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef _REGTABLE_H_ +#define _REGTABLE_H_ + +#ifdef HIF_SDIO +#include "regtable_sdio.h" +#endif + +#if defined(HIF_PCI) || defined(HIF_SNOC) || defined(HIF_AHB) +#include "reg_struct.h" +#include "regtable_pcie.h" +#endif + +#if defined(HIF_USB) +#include "regtable_usb.h" +#endif + +#endif diff --git a/drivers/staging/qca-wifi-host-cmn/hif/inc/regtable_pcie.h b/drivers/staging/qca-wifi-host-cmn/hif/inc/regtable_pcie.h new file mode 100644 index 0000000000000000000000000000000000000000..25df023c203343ae65b7e823c1aef68126a5910c --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/hif/inc/regtable_pcie.h @@ -0,0 +1,743 @@ +/* + * Copyright (c) 2011-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef _REGTABLE_PCIE_H_ +#define _REGTABLE_PCIE_H_ + +#define MISSING 0 + +#define A_SOC_CORE_PCIE_INTR_ENABLE_GRP0_Q6_MASK \ + (scn->targetdef->d_A_SOC_CORE_PCIE_INTR_ENABLE_GRP0_Q6_MASK) +#define A_SOC_CORE_PCIE_INTR_CAUSE_GRP1 \ + (scn->targetdef->d_A_SOC_CORE_PCIE_INTR_CAUSE_GRP1) +#define A_SOC_CORE_SPARE_1_REGISTER \ + (scn->targetdef->d_A_SOC_CORE_SPARE_1_REGISTER) +#define A_SOC_CORE_PCIE_INTR_CLR_GRP1 \ + (scn->targetdef->d_A_SOC_CORE_PCIE_INTR_CLR_GRP1) +#define A_SOC_CORE_PCIE_INTR_ENABLE_GRP1 \ + (scn->targetdef->d_A_SOC_CORE_PCIE_INTR_ENABLE_GRP1) +#define A_SOC_PCIE_PCIE_SCRATCH_0 \ + (scn->targetdef->d_A_SOC_PCIE_PCIE_SCRATCH_0) +#define A_SOC_PCIE_PCIE_SCRATCH_1 \ + (scn->targetdef->d_A_SOC_PCIE_PCIE_SCRATCH_1) +#define A_WIFI_APB_1_A_WFSS_CE_TARGET_HOST_DELTA \ + (scn->targetdef->d_A_WIFI_APB_1_A_WFSS_CE_TARGET_HOST_DELTA) +#define A_SOC_PCIE_PCIE_SCRATCH_2 \ + (scn->targetdef->d_A_SOC_PCIE_PCIE_SCRATCH_2) +/* end Q6 iHelium emu registers */ + +#define PCIE_INTR_FIRMWARE_ROUTE_MASK \ + (scn->targetdef->d_PCIE_INTR_FIRMWARE_ROUTE_MASK) +#define A_SOC_CORE_SPARE_0_REGISTER \ + (scn->targetdef->d_A_SOC_CORE_SPARE_0_REGISTER) +#define A_SOC_CORE_SCRATCH_0_ADDRESS \ + (scn->targetdef->d_A_SOC_CORE_SCRATCH_0_ADDRESS) +#define A_SOC_CORE_SCRATCH_1_ADDRESS \ + (scn->targetdef->d_A_SOC_CORE_SCRATCH_1_ADDRESS) +#define A_SOC_CORE_SCRATCH_2_ADDRESS \ + (scn->targetdef->d_A_SOC_CORE_SCRATCH_2_ADDRESS) +#define A_SOC_CORE_SCRATCH_3_ADDRESS \ + (scn->targetdef->d_A_SOC_CORE_SCRATCH_3_ADDRESS) +#define A_SOC_CORE_SCRATCH_4_ADDRESS \ + (scn->targetdef->d_A_SOC_CORE_SCRATCH_4_ADDRESS) +#define A_SOC_CORE_SCRATCH_5_ADDRESS \ + (scn->targetdef->d_A_SOC_CORE_SCRATCH_5_ADDRESS) +#define A_SOC_CORE_SCRATCH_6_ADDRESS \ + (scn->targetdef->d_A_SOC_CORE_SCRATCH_6_ADDRESS) +#define A_SOC_CORE_SCRATCH_7_ADDRESS \ + (scn->targetdef->d_A_SOC_CORE_SCRATCH_7_ADDRESS) +#define RTC_SOC_BASE_ADDRESS (scn->targetdef->d_RTC_SOC_BASE_ADDRESS) +#define RTC_WMAC_BASE_ADDRESS (scn->targetdef->d_RTC_WMAC_BASE_ADDRESS) +#define SYSTEM_SLEEP_OFFSET (scn->targetdef->d_SYSTEM_SLEEP_OFFSET) +#define WLAN_SYSTEM_SLEEP_OFFSET \ + (scn->targetdef->d_WLAN_SYSTEM_SLEEP_OFFSET) +#define WLAN_SYSTEM_SLEEP_DISABLE_LSB \ + (scn->targetdef->d_WLAN_SYSTEM_SLEEP_DISABLE_LSB) +#define WLAN_SYSTEM_SLEEP_DISABLE_MASK \ + (scn->targetdef->d_WLAN_SYSTEM_SLEEP_DISABLE_MASK) +#define CLOCK_CONTROL_OFFSET (scn->targetdef->d_CLOCK_CONTROL_OFFSET) +#define CLOCK_CONTROL_SI0_CLK_MASK \ + (scn->targetdef->d_CLOCK_CONTROL_SI0_CLK_MASK) +#define RESET_CONTROL_OFFSET (scn->targetdef->d_RESET_CONTROL_OFFSET) +#define RESET_CONTROL_MBOX_RST_MASK \ + (scn->targetdef->d_RESET_CONTROL_MBOX_RST_MASK) +#define RESET_CONTROL_SI0_RST_MASK \ + (scn->targetdef->d_RESET_CONTROL_SI0_RST_MASK) +#define WLAN_RESET_CONTROL_OFFSET \ + (scn->targetdef->d_WLAN_RESET_CONTROL_OFFSET) +#define WLAN_RESET_CONTROL_COLD_RST_MASK \ + (scn->targetdef->d_WLAN_RESET_CONTROL_COLD_RST_MASK) +#define WLAN_RESET_CONTROL_WARM_RST_MASK \ + (scn->targetdef->d_WLAN_RESET_CONTROL_WARM_RST_MASK) +#define GPIO_BASE_ADDRESS (scn->targetdef->d_GPIO_BASE_ADDRESS) +#define GPIO_PIN0_OFFSET (scn->targetdef->d_GPIO_PIN0_OFFSET) +#define GPIO_PIN1_OFFSET (scn->targetdef->d_GPIO_PIN1_OFFSET) +#define GPIO_PIN0_CONFIG_MASK (scn->targetdef->d_GPIO_PIN0_CONFIG_MASK) +#define GPIO_PIN1_CONFIG_MASK (scn->targetdef->d_GPIO_PIN1_CONFIG_MASK) +#define A_SOC_CORE_SCRATCH_0 (scn->targetdef->d_A_SOC_CORE_SCRATCH_0) +#define SI_CONFIG_BIDIR_OD_DATA_LSB \ + (scn->targetdef->d_SI_CONFIG_BIDIR_OD_DATA_LSB) +#define SI_CONFIG_BIDIR_OD_DATA_MASK \ + (scn->targetdef->d_SI_CONFIG_BIDIR_OD_DATA_MASK) +#define SI_CONFIG_I2C_LSB (scn->targetdef->d_SI_CONFIG_I2C_LSB) +#define SI_CONFIG_I2C_MASK \ + (scn->targetdef->d_SI_CONFIG_I2C_MASK) +#define SI_CONFIG_POS_SAMPLE_LSB \ + (scn->targetdef->d_SI_CONFIG_POS_SAMPLE_LSB) +#define SI_CONFIG_POS_SAMPLE_MASK \ + (scn->targetdef->d_SI_CONFIG_POS_SAMPLE_MASK) +#define SI_CONFIG_INACTIVE_CLK_LSB \ + (scn->targetdef->d_SI_CONFIG_INACTIVE_CLK_LSB) +#define SI_CONFIG_INACTIVE_CLK_MASK \ + (scn->targetdef->d_SI_CONFIG_INACTIVE_CLK_MASK) +#define SI_CONFIG_INACTIVE_DATA_LSB \ + (scn->targetdef->d_SI_CONFIG_INACTIVE_DATA_LSB) +#define SI_CONFIG_INACTIVE_DATA_MASK \ + (scn->targetdef->d_SI_CONFIG_INACTIVE_DATA_MASK) +#define SI_CONFIG_DIVIDER_LSB (scn->targetdef->d_SI_CONFIG_DIVIDER_LSB) +#define SI_CONFIG_DIVIDER_MASK (scn->targetdef->d_SI_CONFIG_DIVIDER_MASK) +#define SI_BASE_ADDRESS (scn->targetdef->d_SI_BASE_ADDRESS) +#define SI_CONFIG_OFFSET (scn->targetdef->d_SI_CONFIG_OFFSET) +#define SI_TX_DATA0_OFFSET (scn->targetdef->d_SI_TX_DATA0_OFFSET) +#define SI_TX_DATA1_OFFSET (scn->targetdef->d_SI_TX_DATA1_OFFSET) +#define SI_RX_DATA0_OFFSET (scn->targetdef->d_SI_RX_DATA0_OFFSET) +#define SI_RX_DATA1_OFFSET (scn->targetdef->d_SI_RX_DATA1_OFFSET) +#define SI_CS_OFFSET (scn->targetdef->d_SI_CS_OFFSET) +#define SI_CS_DONE_ERR_MASK (scn->targetdef->d_SI_CS_DONE_ERR_MASK) +#define SI_CS_DONE_INT_MASK (scn->targetdef->d_SI_CS_DONE_INT_MASK) +#define SI_CS_START_LSB (scn->targetdef->d_SI_CS_START_LSB) +#define SI_CS_START_MASK (scn->targetdef->d_SI_CS_START_MASK) +#define SI_CS_RX_CNT_LSB (scn->targetdef->d_SI_CS_RX_CNT_LSB) +#define SI_CS_RX_CNT_MASK (scn->targetdef->d_SI_CS_RX_CNT_MASK) +#define SI_CS_TX_CNT_LSB (scn->targetdef->d_SI_CS_TX_CNT_LSB) +#define SI_CS_TX_CNT_MASK (scn->targetdef->d_SI_CS_TX_CNT_MASK) +#define EEPROM_SZ (scn->targetdef->d_BOARD_DATA_SZ) +#define EEPROM_EXT_SZ (scn->targetdef->d_BOARD_EXT_DATA_SZ) +#define MBOX_BASE_ADDRESS (scn->targetdef->d_MBOX_BASE_ADDRESS) +#define LOCAL_SCRATCH_OFFSET (scn->targetdef->d_LOCAL_SCRATCH_OFFSET) +#define CPU_CLOCK_OFFSET (scn->targetdef->d_CPU_CLOCK_OFFSET) +#define LPO_CAL_OFFSET (scn->targetdef->d_LPO_CAL_OFFSET) +#define GPIO_PIN10_OFFSET (scn->targetdef->d_GPIO_PIN10_OFFSET) +#define GPIO_PIN11_OFFSET (scn->targetdef->d_GPIO_PIN11_OFFSET) +#define GPIO_PIN12_OFFSET (scn->targetdef->d_GPIO_PIN12_OFFSET) +#define GPIO_PIN13_OFFSET (scn->targetdef->d_GPIO_PIN13_OFFSET) +#define CLOCK_GPIO_OFFSET (scn->targetdef->d_CLOCK_GPIO_OFFSET) +#define CPU_CLOCK_STANDARD_LSB (scn->targetdef->d_CPU_CLOCK_STANDARD_LSB) +#define CPU_CLOCK_STANDARD_MASK (scn->targetdef->d_CPU_CLOCK_STANDARD_MASK) +#define LPO_CAL_ENABLE_LSB (scn->targetdef->d_LPO_CAL_ENABLE_LSB) +#define LPO_CAL_ENABLE_MASK (scn->targetdef->d_LPO_CAL_ENABLE_MASK) +#define CLOCK_GPIO_BT_CLK_OUT_EN_LSB \ + (scn->targetdef->d_CLOCK_GPIO_BT_CLK_OUT_EN_LSB) +#define CLOCK_GPIO_BT_CLK_OUT_EN_MASK \ + (scn->targetdef->d_CLOCK_GPIO_BT_CLK_OUT_EN_MASK) +#define ANALOG_INTF_BASE_ADDRESS (scn->targetdef->d_ANALOG_INTF_BASE_ADDRESS) +#define WLAN_MAC_BASE_ADDRESS (scn->targetdef->d_WLAN_MAC_BASE_ADDRESS) +#define FW_INDICATOR_ADDRESS (scn->targetdef->d_FW_INDICATOR_ADDRESS) +#define DRAM_BASE_ADDRESS (scn->targetdef->d_DRAM_BASE_ADDRESS) +#define SOC_CORE_BASE_ADDRESS (scn->targetdef->d_SOC_CORE_BASE_ADDRESS) +#define CORE_CTRL_ADDRESS (scn->targetdef->d_CORE_CTRL_ADDRESS) +#define CE_COUNT (scn->targetdef->d_CE_COUNT) +#define PCIE_INTR_ENABLE_ADDRESS (scn->targetdef->d_PCIE_INTR_ENABLE_ADDRESS) +#define PCIE_INTR_CLR_ADDRESS (scn->targetdef->d_PCIE_INTR_CLR_ADDRESS) +#define PCIE_INTR_FIRMWARE_MASK (scn->targetdef->d_PCIE_INTR_FIRMWARE_MASK) +#define PCIE_INTR_CE_MASK_ALL (scn->targetdef->d_PCIE_INTR_CE_MASK_ALL) +#define CORE_CTRL_CPU_INTR_MASK (scn->targetdef->d_CORE_CTRL_CPU_INTR_MASK) +#define PCIE_INTR_CAUSE_ADDRESS (scn->targetdef->d_PCIE_INTR_CAUSE_ADDRESS) +#define SOC_RESET_CONTROL_ADDRESS (scn->targetdef->d_SOC_RESET_CONTROL_ADDRESS) +#define HOST_GROUP0_MASK (PCIE_INTR_FIRMWARE_MASK | PCIE_INTR_CE_MASK_ALL | \ + A_SOC_CORE_PCIE_INTR_ENABLE_GRP0_Q6_MASK) +#define SOC_RESET_CONTROL_CE_RST_MASK \ + (scn->targetdef->d_SOC_RESET_CONTROL_CE_RST_MASK) +#define SOC_RESET_CONTROL_CPU_WARM_RST_MASK \ + (scn->targetdef->d_SOC_RESET_CONTROL_CPU_WARM_RST_MASK) +#define CPU_INTR_ADDRESS (scn->targetdef->d_CPU_INTR_ADDRESS) +#define SOC_LF_TIMER_CONTROL0_ADDRESS \ + (scn->targetdef->d_SOC_LF_TIMER_CONTROL0_ADDRESS) +#define SOC_LF_TIMER_CONTROL0_ENABLE_MASK \ + (scn->targetdef->d_SOC_LF_TIMER_CONTROL0_ENABLE_MASK) +#define SOC_RESET_CONTROL_PCIE_RST_SHORT_OVRD_LSB \ + (scn->targetdef->d_SOC_RESET_CONTROL_PCIE_RST_SHORT_OVRD_LSB) +#define SOC_RESET_CONTROL_PCIE_RST_SHORT_OVRD_MASK \ + (scn->targetdef->d_SOC_RESET_CONTROL_PCIE_RST_SHORT_OVRD_MASK) + +#define SOC_RESET_CONTROL_PCIE_RST_SHORT_OVRD_GET(x) \ + (((x) & SOC_RESET_CONTROL_PCIE_RST_SHORT_OVRD_MASK) >> \ + SOC_RESET_CONTROL_PCIE_RST_SHORT_OVRD_LSB) +#define SOC_RESET_CONTROL_PCIE_RST_SHORT_OVRD_SET(x) \ + (((x) << SOC_RESET_CONTROL_PCIE_RST_SHORT_OVRD_LSB) & \ + SOC_RESET_CONTROL_PCIE_RST_SHORT_OVRD_MASK) + +/* hif_pci.c */ +#define CHIP_ID_ADDRESS (scn->targetdef->d_SOC_CHIP_ID_ADDRESS) +#define SOC_CHIP_ID_REVISION_MASK (scn->targetdef->d_SOC_CHIP_ID_REVISION_MASK) +#define SOC_CHIP_ID_REVISION_LSB (scn->targetdef->d_SOC_CHIP_ID_REVISION_LSB) +#define SOC_CHIP_ID_VERSION_MASK (scn->targetdef->d_SOC_CHIP_ID_VERSION_MASK) +#define SOC_CHIP_ID_VERSION_LSB (scn->targetdef->d_SOC_CHIP_ID_VERSION_LSB) +#define CHIP_ID_REVISION_GET(x) \ + (((x) & SOC_CHIP_ID_REVISION_MASK) >> SOC_CHIP_ID_REVISION_LSB) +#define CHIP_ID_VERSION_GET(x) \ + (((x) & SOC_CHIP_ID_VERSION_MASK) >> SOC_CHIP_ID_VERSION_LSB) +/* hif_pci.c end */ + +/* misc */ +#define SR_WR_INDEX_ADDRESS (scn->targetdef->d_SR_WR_INDEX_ADDRESS) +#define DST_WATERMARK_ADDRESS (scn->targetdef->d_DST_WATERMARK_ADDRESS) +#define SOC_POWER_REG_OFFSET (scn->targetdef->d_SOC_POWER_REG_OFFSET) +/* end */ + +#ifndef CONFIG_WIN +/* htt_rx.c */ +#define RX_MSDU_END_4_FIRST_MSDU_MASK \ + (pdev->targetdef->d_RX_MSDU_END_4_FIRST_MSDU_MASK) +#define RX_MSDU_END_4_FIRST_MSDU_LSB \ + (pdev->targetdef->d_RX_MSDU_END_4_FIRST_MSDU_LSB) +#define RX_MPDU_START_0_RETRY_LSB \ + (pdev->targetdef->d_RX_MPDU_START_0_RETRY_LSB) +#define RX_MPDU_START_0_RETRY_MASK \ + (pdev->targetdef->d_RX_MPDU_START_0_RETRY_MASK) +#define RX_MPDU_START_0_SEQ_NUM_MASK \ + (pdev->targetdef->d_RX_MPDU_START_0_SEQ_NUM_MASK) +#define RX_MPDU_START_0_SEQ_NUM_LSB \ + (pdev->targetdef->d_RX_MPDU_START_0_SEQ_NUM_LSB) +#define RX_MPDU_START_2_PN_47_32_LSB \ + (pdev->targetdef->d_RX_MPDU_START_2_PN_47_32_LSB) +#define RX_MPDU_START_2_PN_47_32_MASK \ + (pdev->targetdef->d_RX_MPDU_START_2_PN_47_32_MASK) +#define RX_MPDU_START_2_TID_LSB \ + (pdev->targetdef->d_RX_MPDU_START_2_TID_LSB) +#define RX_MPDU_START_2_TID_MASK \ + (pdev->targetdef->d_RX_MPDU_START_2_TID_MASK) +#define RX_MSDU_END_1_KEY_ID_OCT_MASK \ + (pdev->targetdef->d_RX_MSDU_END_1_KEY_ID_OCT_MASK) +#define RX_MSDU_END_1_KEY_ID_OCT_LSB \ + (pdev->targetdef->d_RX_MSDU_END_1_KEY_ID_OCT_LSB) +#define RX_MSDU_END_1_EXT_WAPI_PN_63_48_MASK \ + (pdev->targetdef->d_RX_MSDU_END_1_EXT_WAPI_PN_63_48_MASK) +#define RX_MSDU_END_1_EXT_WAPI_PN_63_48_LSB \ + (pdev->targetdef->d_RX_MSDU_END_1_EXT_WAPI_PN_63_48_LSB) +#define RX_MSDU_END_4_LAST_MSDU_MASK \ + (pdev->targetdef->d_RX_MSDU_END_4_LAST_MSDU_MASK) +#define RX_MSDU_END_4_LAST_MSDU_LSB \ + (pdev->targetdef->d_RX_MSDU_END_4_LAST_MSDU_LSB) +#define RX_ATTENTION_0_MCAST_BCAST_MASK \ + (pdev->targetdef->d_RX_ATTENTION_0_MCAST_BCAST_MASK) +#define RX_ATTENTION_0_MCAST_BCAST_LSB \ + (pdev->targetdef->d_RX_ATTENTION_0_MCAST_BCAST_LSB) +#define RX_ATTENTION_0_FRAGMENT_MASK \ + (pdev->targetdef->d_RX_ATTENTION_0_FRAGMENT_MASK) +#define RX_ATTENTION_0_FRAGMENT_LSB \ + (pdev->targetdef->d_RX_ATTENTION_0_FRAGMENT_LSB) +#define RX_ATTENTION_0_MPDU_LENGTH_ERR_MASK \ + (pdev->targetdef->d_RX_ATTENTION_0_MPDU_LENGTH_ERR_MASK) +#define RX_FRAG_INFO_0_RING2_MORE_COUNT_MASK \ + (pdev->targetdef->d_RX_FRAG_INFO_0_RING2_MORE_COUNT_MASK) +#define RX_FRAG_INFO_0_RING2_MORE_COUNT_LSB \ + (pdev->targetdef->d_RX_FRAG_INFO_0_RING2_MORE_COUNT_LSB) +#define RX_MSDU_START_0_MSDU_LENGTH_MASK \ + (pdev->targetdef->d_RX_MSDU_START_0_MSDU_LENGTH_MASK) +#define RX_MSDU_START_0_MSDU_LENGTH_LSB \ + (pdev->targetdef->d_RX_MSDU_START_0_MSDU_LENGTH_LSB) +#define RX_MSDU_START_2_DECAP_FORMAT_OFFSET \ + (pdev->targetdef->d_RX_MSDU_START_2_DECAP_FORMAT_OFFSET) +#define RX_MSDU_START_2_DECAP_FORMAT_MASK \ + (pdev->targetdef->d_RX_MSDU_START_2_DECAP_FORMAT_MASK) +#define RX_MSDU_START_2_DECAP_FORMAT_LSB \ + (pdev->targetdef->d_RX_MSDU_START_2_DECAP_FORMAT_LSB) +#define RX_MPDU_START_0_ENCRYPTED_MASK \ + (pdev->targetdef->d_RX_MPDU_START_0_ENCRYPTED_MASK) +#define RX_MPDU_START_0_ENCRYPTED_LSB \ + (pdev->targetdef->d_RX_MPDU_START_0_ENCRYPTED_LSB) +#define RX_ATTENTION_0_MORE_DATA_MASK \ + (pdev->targetdef->d_RX_ATTENTION_0_MORE_DATA_MASK) +#define RX_ATTENTION_0_MSDU_DONE_MASK \ + (pdev->targetdef->d_RX_ATTENTION_0_MSDU_DONE_MASK) +#define RX_ATTENTION_0_TCP_UDP_CHKSUM_FAIL_MASK \ + (pdev->targetdef->d_RX_ATTENTION_0_TCP_UDP_CHKSUM_FAIL_MASK) +/* end */ +#endif + +/* copy_engine.c */ +/* end */ +/* PLL start */ +#define EFUSE_OFFSET (scn->targetdef->d_EFUSE_OFFSET) +#define EFUSE_XTAL_SEL_MSB (scn->targetdef->d_EFUSE_XTAL_SEL_MSB) +#define EFUSE_XTAL_SEL_LSB (scn->targetdef->d_EFUSE_XTAL_SEL_LSB) +#define EFUSE_XTAL_SEL_MASK (scn->targetdef->d_EFUSE_XTAL_SEL_MASK) +#define BB_PLL_CONFIG_OFFSET (scn->targetdef->d_BB_PLL_CONFIG_OFFSET) +#define BB_PLL_CONFIG_OUTDIV_MSB (scn->targetdef->d_BB_PLL_CONFIG_OUTDIV_MSB) +#define BB_PLL_CONFIG_OUTDIV_LSB (scn->targetdef->d_BB_PLL_CONFIG_OUTDIV_LSB) +#define BB_PLL_CONFIG_OUTDIV_MASK (scn->targetdef->d_BB_PLL_CONFIG_OUTDIV_MASK) +#define BB_PLL_CONFIG_FRAC_MSB (scn->targetdef->d_BB_PLL_CONFIG_FRAC_MSB) +#define BB_PLL_CONFIG_FRAC_LSB (scn->targetdef->d_BB_PLL_CONFIG_FRAC_LSB) +#define BB_PLL_CONFIG_FRAC_MASK (scn->targetdef->d_BB_PLL_CONFIG_FRAC_MASK) +#define WLAN_PLL_SETTLE_TIME_MSB (scn->targetdef->d_WLAN_PLL_SETTLE_TIME_MSB) +#define WLAN_PLL_SETTLE_TIME_LSB (scn->targetdef->d_WLAN_PLL_SETTLE_TIME_LSB) +#define WLAN_PLL_SETTLE_TIME_MASK (scn->targetdef->d_WLAN_PLL_SETTLE_TIME_MASK) +#define WLAN_PLL_SETTLE_OFFSET (scn->targetdef->d_WLAN_PLL_SETTLE_OFFSET) +#define WLAN_PLL_SETTLE_SW_MASK (scn->targetdef->d_WLAN_PLL_SETTLE_SW_MASK) +#define WLAN_PLL_SETTLE_RSTMASK (scn->targetdef->d_WLAN_PLL_SETTLE_RSTMASK) +#define WLAN_PLL_SETTLE_RESET (scn->targetdef->d_WLAN_PLL_SETTLE_RESET) +#define WLAN_PLL_CONTROL_NOPWD_MSB \ + (scn->targetdef->d_WLAN_PLL_CONTROL_NOPWD_MSB) +#define WLAN_PLL_CONTROL_NOPWD_LSB \ + (scn->targetdef->d_WLAN_PLL_CONTROL_NOPWD_LSB) +#define WLAN_PLL_CONTROL_NOPWD_MASK \ + (scn->targetdef->d_WLAN_PLL_CONTROL_NOPWD_MASK) +#define WLAN_PLL_CONTROL_BYPASS_MSB \ + (scn->targetdef->d_WLAN_PLL_CONTROL_BYPASS_MSB) +#define WLAN_PLL_CONTROL_BYPASS_LSB \ + (scn->targetdef->d_WLAN_PLL_CONTROL_BYPASS_LSB) +#define WLAN_PLL_CONTROL_BYPASS_MASK \ + (scn->targetdef->d_WLAN_PLL_CONTROL_BYPASS_MASK) +#define WLAN_PLL_CONTROL_BYPASS_RESET \ + (scn->targetdef->d_WLAN_PLL_CONTROL_BYPASS_RESET) +#define WLAN_PLL_CONTROL_CLK_SEL_MSB \ + (scn->targetdef->d_WLAN_PLL_CONTROL_CLK_SEL_MSB) +#define WLAN_PLL_CONTROL_CLK_SEL_LSB \ + (scn->targetdef->d_WLAN_PLL_CONTROL_CLK_SEL_LSB) +#define WLAN_PLL_CONTROL_CLK_SEL_MASK \ + (scn->targetdef->d_WLAN_PLL_CONTROL_CLK_SEL_MASK) +#define WLAN_PLL_CONTROL_CLK_SEL_RESET \ + (scn->targetdef->d_WLAN_PLL_CONTROL_CLK_SEL_RESET) +#define WLAN_PLL_CONTROL_REFDIV_MSB \ + (scn->targetdef->d_WLAN_PLL_CONTROL_REFDIV_MSB) +#define WLAN_PLL_CONTROL_REFDIV_LSB \ + (scn->targetdef->d_WLAN_PLL_CONTROL_REFDIV_LSB) +#define WLAN_PLL_CONTROL_REFDIV_MASK \ + (scn->targetdef->d_WLAN_PLL_CONTROL_REFDIV_MASK) +#define WLAN_PLL_CONTROL_REFDIV_RESET \ + (scn->targetdef->d_WLAN_PLL_CONTROL_REFDIV_RESET) +#define WLAN_PLL_CONTROL_DIV_MSB (scn->targetdef->d_WLAN_PLL_CONTROL_DIV_MSB) +#define WLAN_PLL_CONTROL_DIV_LSB (scn->targetdef->d_WLAN_PLL_CONTROL_DIV_LSB) +#define WLAN_PLL_CONTROL_DIV_MASK (scn->targetdef->d_WLAN_PLL_CONTROL_DIV_MASK) +#define WLAN_PLL_CONTROL_DIV_RESET \ + (scn->targetdef->d_WLAN_PLL_CONTROL_DIV_RESET) +#define WLAN_PLL_CONTROL_OFFSET (scn->targetdef->d_WLAN_PLL_CONTROL_OFFSET) +#define WLAN_PLL_CONTROL_SW_MASK (scn->targetdef->d_WLAN_PLL_CONTROL_SW_MASK) +#define WLAN_PLL_CONTROL_RSTMASK (scn->targetdef->d_WLAN_PLL_CONTROL_RSTMASK) +#define WLAN_PLL_CONTROL_RESET (scn->targetdef->d_WLAN_PLL_CONTROL_RESET) +#define SOC_CORE_CLK_CTRL_OFFSET (scn->targetdef->d_SOC_CORE_CLK_CTRL_OFFSET) +#define SOC_CORE_CLK_CTRL_DIV_MSB (scn->targetdef->d_SOC_CORE_CLK_CTRL_DIV_MSB) +#define SOC_CORE_CLK_CTRL_DIV_LSB (scn->targetdef->d_SOC_CORE_CLK_CTRL_DIV_LSB) +#define SOC_CORE_CLK_CTRL_DIV_MASK \ + (scn->targetdef->d_SOC_CORE_CLK_CTRL_DIV_MASK) +#define RTC_SYNC_STATUS_PLL_CHANGING_MSB \ + (scn->targetdef->d_RTC_SYNC_STATUS_PLL_CHANGING_MSB) +#define RTC_SYNC_STATUS_PLL_CHANGING_LSB \ + (scn->targetdef->d_RTC_SYNC_STATUS_PLL_CHANGING_LSB) +#define RTC_SYNC_STATUS_PLL_CHANGING_MASK \ + (scn->targetdef->d_RTC_SYNC_STATUS_PLL_CHANGING_MASK) +#define RTC_SYNC_STATUS_PLL_CHANGING_RESET \ + (scn->targetdef->d_RTC_SYNC_STATUS_PLL_CHANGING_RESET) +#define RTC_SYNC_STATUS_OFFSET (scn->targetdef->d_RTC_SYNC_STATUS_OFFSET) +#define SOC_CPU_CLOCK_OFFSET (scn->targetdef->d_SOC_CPU_CLOCK_OFFSET) +#define SOC_CPU_CLOCK_STANDARD_MSB \ + (scn->targetdef->d_SOC_CPU_CLOCK_STANDARD_MSB) +#define SOC_CPU_CLOCK_STANDARD_LSB \ + (scn->targetdef->d_SOC_CPU_CLOCK_STANDARD_LSB) +#define SOC_CPU_CLOCK_STANDARD_MASK \ + (scn->targetdef->d_SOC_CPU_CLOCK_STANDARD_MASK) +/* PLL end */ + +#define FW_CPU_PLL_CONFIG \ + (scn->targetdef->d_FW_CPU_PLL_CONFIG) + +#define WIFICMN_PCIE_BAR_REG_ADDRESS \ + (sc->targetdef->d_WIFICMN_PCIE_BAR_REG_ADDRESS) + + /* htt tx */ +#define MSDU_LINK_EXT_3_TCP_OVER_IPV4_CHECKSUM_EN_MASK \ + (pdev->targetdef->d_MSDU_LINK_EXT_3_TCP_OVER_IPV4_CHECKSUM_EN_MASK) +#define MSDU_LINK_EXT_3_TCP_OVER_IPV6_CHECKSUM_EN_MASK \ + (pdev->targetdef->d_MSDU_LINK_EXT_3_TCP_OVER_IPV6_CHECKSUM_EN_MASK) +#define MSDU_LINK_EXT_3_UDP_OVER_IPV4_CHECKSUM_EN_MASK \ + (pdev->targetdef->d_MSDU_LINK_EXT_3_UDP_OVER_IPV4_CHECKSUM_EN_MASK) +#define MSDU_LINK_EXT_3_UDP_OVER_IPV6_CHECKSUM_EN_MASK \ + (pdev->targetdef->d_MSDU_LINK_EXT_3_UDP_OVER_IPV6_CHECKSUM_EN_MASK) +#define MSDU_LINK_EXT_3_TCP_OVER_IPV4_CHECKSUM_EN_LSB \ + (pdev->targetdef->d_MSDU_LINK_EXT_3_TCP_OVER_IPV4_CHECKSUM_EN_LSB) +#define MSDU_LINK_EXT_3_TCP_OVER_IPV6_CHECKSUM_EN_LSB \ + (pdev->targetdef->d_MSDU_LINK_EXT_3_TCP_OVER_IPV6_CHECKSUM_EN_LSB) +#define MSDU_LINK_EXT_3_UDP_OVER_IPV4_CHECKSUM_EN_LSB \ + (pdev->targetdef->d_MSDU_LINK_EXT_3_UDP_OVER_IPV4_CHECKSUM_EN_LSB) +#define MSDU_LINK_EXT_3_UDP_OVER_IPV6_CHECKSUM_EN_LSB \ + (pdev->targetdef->d_MSDU_LINK_EXT_3_UDP_OVER_IPV6_CHECKSUM_EN_LSB) + +#define CE_CMD_ADDRESS \ + (scn->targetdef->d_CE_CMD_ADDRESS) +#define CE_CMD_HALT_MASK \ + (scn->targetdef->d_CE_CMD_HALT_MASK) +#define CE_CMD_HALT_STATUS_MASK \ + (scn->targetdef->d_CE_CMD_HALT_STATUS_MASK) +#define CE_CMD_HALT_STATUS_LSB \ + (scn->targetdef->d_CE_CMD_HALT_STATUS_LSB) + +#define SI_CONFIG_ERR_INT_MASK \ + (scn->targetdef->d_SI_CONFIG_ERR_INT_MASK) +#define SI_CONFIG_ERR_INT_LSB \ + (scn->targetdef->d_SI_CONFIG_ERR_INT_LSB) +#define GPIO_ENABLE_W1TS_LOW_ADDRESS \ + (scn->targetdef->d_GPIO_ENABLE_W1TS_LOW_ADDRESS) +#define GPIO_PIN0_CONFIG_LSB \ + (scn->targetdef->d_GPIO_PIN0_CONFIG_LSB) +#define GPIO_PIN0_PAD_PULL_LSB \ + (scn->targetdef->d_GPIO_PIN0_PAD_PULL_LSB) +#define GPIO_PIN0_PAD_PULL_MASK \ + (scn->targetdef->d_GPIO_PIN0_PAD_PULL_MASK) + +#define SOC_CHIP_ID_REVISION_MSB \ + (scn->targetdef->d_SOC_CHIP_ID_REVISION_MSB) + +#define FW_AXI_MSI_ADDR \ + (scn->targetdef->d_FW_AXI_MSI_ADDR) +#define FW_AXI_MSI_DATA \ + (scn->targetdef->d_FW_AXI_MSI_DATA) +#define WLAN_SUBSYSTEM_CORE_ID_ADDRESS \ + (scn->targetdef->d_WLAN_SUBSYSTEM_CORE_ID_ADDRESS) +#define FPGA_VERSION_ADDRESS \ + (scn->targetdef->d_FPGA_VERSION_ADDRESS) + +/* SET macros */ +#define WLAN_SYSTEM_SLEEP_DISABLE_SET(x) \ + (((x) << WLAN_SYSTEM_SLEEP_DISABLE_LSB) & \ + WLAN_SYSTEM_SLEEP_DISABLE_MASK) +#define SI_CONFIG_BIDIR_OD_DATA_SET(x) \ + (((x) << SI_CONFIG_BIDIR_OD_DATA_LSB) & SI_CONFIG_BIDIR_OD_DATA_MASK) +#define SI_CONFIG_I2C_SET(x) (((x) << SI_CONFIG_I2C_LSB) & SI_CONFIG_I2C_MASK) +#define SI_CONFIG_POS_SAMPLE_SET(x) \ + (((x) << SI_CONFIG_POS_SAMPLE_LSB) & SI_CONFIG_POS_SAMPLE_MASK) +#define SI_CONFIG_INACTIVE_CLK_SET(x) \ + (((x) << SI_CONFIG_INACTIVE_CLK_LSB) & SI_CONFIG_INACTIVE_CLK_MASK) +#define SI_CONFIG_INACTIVE_DATA_SET(x) \ + (((x) << SI_CONFIG_INACTIVE_DATA_LSB) & SI_CONFIG_INACTIVE_DATA_MASK) +#define SI_CONFIG_DIVIDER_SET(x) \ + (((x) << SI_CONFIG_DIVIDER_LSB) & SI_CONFIG_DIVIDER_MASK) +#define SI_CS_START_SET(x) (((x) << SI_CS_START_LSB) & SI_CS_START_MASK) +#define SI_CS_RX_CNT_SET(x) (((x) << SI_CS_RX_CNT_LSB) & SI_CS_RX_CNT_MASK) +#define SI_CS_TX_CNT_SET(x) (((x) << SI_CS_TX_CNT_LSB) & SI_CS_TX_CNT_MASK) +#define LPO_CAL_ENABLE_SET(x) \ + (((x) << LPO_CAL_ENABLE_LSB) & LPO_CAL_ENABLE_MASK) +#define CPU_CLOCK_STANDARD_SET(x) \ + (((x) << CPU_CLOCK_STANDARD_LSB) & CPU_CLOCK_STANDARD_MASK) +#define CLOCK_GPIO_BT_CLK_OUT_EN_SET(x) \ + (((x) << CLOCK_GPIO_BT_CLK_OUT_EN_LSB) & CLOCK_GPIO_BT_CLK_OUT_EN_MASK) +/* copy_engine.c */ +/* end */ +/* PLL start */ +#define EFUSE_XTAL_SEL_GET(x) \ + (((x) & EFUSE_XTAL_SEL_MASK) >> EFUSE_XTAL_SEL_LSB) +#define EFUSE_XTAL_SEL_SET(x) \ + (((x) << EFUSE_XTAL_SEL_LSB) & EFUSE_XTAL_SEL_MASK) +#define BB_PLL_CONFIG_OUTDIV_GET(x) \ + (((x) & BB_PLL_CONFIG_OUTDIV_MASK) >> BB_PLL_CONFIG_OUTDIV_LSB) +#define BB_PLL_CONFIG_OUTDIV_SET(x) \ + (((x) << BB_PLL_CONFIG_OUTDIV_LSB) & BB_PLL_CONFIG_OUTDIV_MASK) +#define BB_PLL_CONFIG_FRAC_GET(x) \ + (((x) & BB_PLL_CONFIG_FRAC_MASK) >> BB_PLL_CONFIG_FRAC_LSB) +#define BB_PLL_CONFIG_FRAC_SET(x) \ + (((x) << BB_PLL_CONFIG_FRAC_LSB) & BB_PLL_CONFIG_FRAC_MASK) +#define WLAN_PLL_SETTLE_TIME_GET(x) \ + (((x) & WLAN_PLL_SETTLE_TIME_MASK) >> WLAN_PLL_SETTLE_TIME_LSB) +#define WLAN_PLL_SETTLE_TIME_SET(x) \ + (((x) << WLAN_PLL_SETTLE_TIME_LSB) & WLAN_PLL_SETTLE_TIME_MASK) +#define WLAN_PLL_CONTROL_NOPWD_GET(x) \ + (((x) & WLAN_PLL_CONTROL_NOPWD_MASK) >> WLAN_PLL_CONTROL_NOPWD_LSB) +#define WLAN_PLL_CONTROL_NOPWD_SET(x) \ + (((x) << WLAN_PLL_CONTROL_NOPWD_LSB) & WLAN_PLL_CONTROL_NOPWD_MASK) +#define WLAN_PLL_CONTROL_BYPASS_GET(x) \ + (((x) & WLAN_PLL_CONTROL_BYPASS_MASK) >> WLAN_PLL_CONTROL_BYPASS_LSB) +#define WLAN_PLL_CONTROL_BYPASS_SET(x) \ + (((x) << WLAN_PLL_CONTROL_BYPASS_LSB) & WLAN_PLL_CONTROL_BYPASS_MASK) +#define WLAN_PLL_CONTROL_CLK_SEL_GET(x) \ + (((x) & WLAN_PLL_CONTROL_CLK_SEL_MASK) >> WLAN_PLL_CONTROL_CLK_SEL_LSB) +#define WLAN_PLL_CONTROL_CLK_SEL_SET(x) \ + (((x) << WLAN_PLL_CONTROL_CLK_SEL_LSB) & WLAN_PLL_CONTROL_CLK_SEL_MASK) +#define WLAN_PLL_CONTROL_REFDIV_GET(x) \ + (((x) & WLAN_PLL_CONTROL_REFDIV_MASK) >> WLAN_PLL_CONTROL_REFDIV_LSB) +#define WLAN_PLL_CONTROL_REFDIV_SET(x) \ + (((x) << WLAN_PLL_CONTROL_REFDIV_LSB) & WLAN_PLL_CONTROL_REFDIV_MASK) +#define WLAN_PLL_CONTROL_DIV_GET(x) \ + (((x) & WLAN_PLL_CONTROL_DIV_MASK) >> WLAN_PLL_CONTROL_DIV_LSB) +#define WLAN_PLL_CONTROL_DIV_SET(x) \ + (((x) << WLAN_PLL_CONTROL_DIV_LSB) & WLAN_PLL_CONTROL_DIV_MASK) +#define SOC_CORE_CLK_CTRL_DIV_GET(x) \ + (((x) & SOC_CORE_CLK_CTRL_DIV_MASK) >> SOC_CORE_CLK_CTRL_DIV_LSB) +#define SOC_CORE_CLK_CTRL_DIV_SET(x) \ + (((x) << SOC_CORE_CLK_CTRL_DIV_LSB) & SOC_CORE_CLK_CTRL_DIV_MASK) +#define RTC_SYNC_STATUS_PLL_CHANGING_GET(x) \ + (((x) & RTC_SYNC_STATUS_PLL_CHANGING_MASK) >> \ + RTC_SYNC_STATUS_PLL_CHANGING_LSB) +#define RTC_SYNC_STATUS_PLL_CHANGING_SET(x) \ + (((x) << RTC_SYNC_STATUS_PLL_CHANGING_LSB) & \ + RTC_SYNC_STATUS_PLL_CHANGING_MASK) +#define SOC_CPU_CLOCK_STANDARD_GET(x) \ + (((x) & SOC_CPU_CLOCK_STANDARD_MASK) >> SOC_CPU_CLOCK_STANDARD_LSB) +#define SOC_CPU_CLOCK_STANDARD_SET(x) \ + (((x) << SOC_CPU_CLOCK_STANDARD_LSB) & SOC_CPU_CLOCK_STANDARD_MASK) +/* PLL end */ +#define WLAN_GPIO_PIN0_CONFIG_SET(x) \ + (((x) << GPIO_PIN0_CONFIG_LSB) & GPIO_PIN0_CONFIG_MASK) +#define WLAN_GPIO_PIN0_PAD_PULL_SET(x) \ + (((x) << GPIO_PIN0_PAD_PULL_LSB) & GPIO_PIN0_PAD_PULL_MASK) +#define SI_CONFIG_ERR_INT_SET(x) \ + (((x) << SI_CONFIG_ERR_INT_LSB) & SI_CONFIG_ERR_INT_MASK) + + +#ifdef QCA_WIFI_3_0_ADRASTEA +#define Q6_ENABLE_REGISTER_0 \ + (scn->targetdef->d_Q6_ENABLE_REGISTER_0) +#define Q6_ENABLE_REGISTER_1 \ + (scn->targetdef->d_Q6_ENABLE_REGISTER_1) +#define Q6_CAUSE_REGISTER_0 \ + (scn->targetdef->d_Q6_CAUSE_REGISTER_0) +#define Q6_CAUSE_REGISTER_1 \ + (scn->targetdef->d_Q6_CAUSE_REGISTER_1) +#define Q6_CLEAR_REGISTER_0 \ + (scn->targetdef->d_Q6_CLEAR_REGISTER_0) +#define Q6_CLEAR_REGISTER_1 \ + (scn->targetdef->d_Q6_CLEAR_REGISTER_1) +#endif + +#ifdef CONFIG_BYPASS_QMI +#define BYPASS_QMI_TEMP_REGISTER \ + (scn->targetdef->d_BYPASS_QMI_TEMP_REGISTER) +#endif + +#define A_SOC_PCIE_PCIE_BAR0_START (scn->hostdef->d_A_SOC_PCIE_PCIE_BAR0_START) +#define DESC_DATA_FLAG_MASK (scn->hostdef->d_DESC_DATA_FLAG_MASK) +#define MUX_ID_MASK (scn->hostdef->d_MUX_ID_MASK) +#define TRANSACTION_ID_MASK (scn->hostdef->d_TRANSACTION_ID_MASK) +#define HOST_CE_COUNT (scn->hostdef->d_HOST_CE_COUNT) +#define ENABLE_MSI (scn->hostdef->d_ENABLE_MSI) +#define INT_STATUS_ENABLE_ERROR_LSB \ + (scn->hostdef->d_INT_STATUS_ENABLE_ERROR_LSB) +#define INT_STATUS_ENABLE_ERROR_MASK \ + (scn->hostdef->d_INT_STATUS_ENABLE_ERROR_MASK) +#define INT_STATUS_ENABLE_CPU_LSB (scn->hostdef->d_INT_STATUS_ENABLE_CPU_LSB) +#define INT_STATUS_ENABLE_CPU_MASK (scn->hostdef->d_INT_STATUS_ENABLE_CPU_MASK) +#define INT_STATUS_ENABLE_COUNTER_LSB \ + (scn->hostdef->d_INT_STATUS_ENABLE_COUNTER_LSB) +#define INT_STATUS_ENABLE_COUNTER_MASK \ + (scn->hostdef->d_INT_STATUS_ENABLE_COUNTER_MASK) +#define INT_STATUS_ENABLE_MBOX_DATA_LSB \ + (scn->hostdef->d_INT_STATUS_ENABLE_MBOX_DATA_LSB) +#define INT_STATUS_ENABLE_MBOX_DATA_MASK \ + (scn->hostdef->d_INT_STATUS_ENABLE_MBOX_DATA_MASK) +#define ERROR_STATUS_ENABLE_RX_UNDERFLOW_LSB \ + (scn->hostdef->d_ERROR_STATUS_ENABLE_RX_UNDERFLOW_LSB) +#define ERROR_STATUS_ENABLE_RX_UNDERFLOW_MASK \ + (scn->hostdef->d_ERROR_STATUS_ENABLE_RX_UNDERFLOW_MASK) +#define ERROR_STATUS_ENABLE_TX_OVERFLOW_LSB \ + (scn->hostdef->d_ERROR_STATUS_ENABLE_TX_OVERFLOW_LSB) +#define ERROR_STATUS_ENABLE_TX_OVERFLOW_MASK \ + (scn->hostdef->d_ERROR_STATUS_ENABLE_TX_OVERFLOW_MASK) +#define COUNTER_INT_STATUS_ENABLE_BIT_LSB \ + (scn->hostdef->d_COUNTER_INT_STATUS_ENABLE_BIT_LSB) +#define COUNTER_INT_STATUS_ENABLE_BIT_MASK \ + (scn->hostdef->d_COUNTER_INT_STATUS_ENABLE_BIT_MASK) +#define INT_STATUS_ENABLE_ADDRESS \ + (scn->hostdef->d_INT_STATUS_ENABLE_ADDRESS) +#define CPU_INT_STATUS_ENABLE_BIT_LSB \ + (scn->hostdef->d_CPU_INT_STATUS_ENABLE_BIT_LSB) +#define CPU_INT_STATUS_ENABLE_BIT_MASK \ + (scn->hostdef->d_CPU_INT_STATUS_ENABLE_BIT_MASK) +#define HOST_INT_STATUS_ADDRESS (scn->hostdef->d_HOST_INT_STATUS_ADDRESS) +#define CPU_INT_STATUS_ADDRESS (scn->hostdef->d_CPU_INT_STATUS_ADDRESS) +#define ERROR_INT_STATUS_ADDRESS (scn->hostdef->d_ERROR_INT_STATUS_ADDRESS) +#define ERROR_INT_STATUS_WAKEUP_MASK \ + (scn->hostdef->d_ERROR_INT_STATUS_WAKEUP_MASK) +#define ERROR_INT_STATUS_WAKEUP_LSB \ + (scn->hostdef->d_ERROR_INT_STATUS_WAKEUP_LSB) +#define ERROR_INT_STATUS_RX_UNDERFLOW_MASK \ + (scn->hostdef->d_ERROR_INT_STATUS_RX_UNDERFLOW_MASK) +#define ERROR_INT_STATUS_RX_UNDERFLOW_LSB \ + (scn->hostdef->d_ERROR_INT_STATUS_RX_UNDERFLOW_LSB) +#define ERROR_INT_STATUS_TX_OVERFLOW_MASK \ + (scn->hostdef->d_ERROR_INT_STATUS_TX_OVERFLOW_MASK) +#define ERROR_INT_STATUS_TX_OVERFLOW_LSB \ + (scn->hostdef->d_ERROR_INT_STATUS_TX_OVERFLOW_LSB) +#define COUNT_DEC_ADDRESS (scn->hostdef->d_COUNT_DEC_ADDRESS) +#define HOST_INT_STATUS_CPU_MASK (scn->hostdef->d_HOST_INT_STATUS_CPU_MASK) +#define HOST_INT_STATUS_CPU_LSB (scn->hostdef->d_HOST_INT_STATUS_CPU_LSB) +#define HOST_INT_STATUS_ERROR_MASK (scn->hostdef->d_HOST_INT_STATUS_ERROR_MASK) +#define HOST_INT_STATUS_ERROR_LSB (scn->hostdef->d_HOST_INT_STATUS_ERROR_LSB) +#define HOST_INT_STATUS_COUNTER_MASK \ + (scn->hostdef->d_HOST_INT_STATUS_COUNTER_MASK) +#define HOST_INT_STATUS_COUNTER_LSB \ + (scn->hostdef->d_HOST_INT_STATUS_COUNTER_LSB) +#define RX_LOOKAHEAD_VALID_ADDRESS (scn->hostdef->d_RX_LOOKAHEAD_VALID_ADDRESS) +#define WINDOW_DATA_ADDRESS (scn->hostdef->d_WINDOW_DATA_ADDRESS) +#define WINDOW_READ_ADDR_ADDRESS (scn->hostdef->d_WINDOW_READ_ADDR_ADDRESS) +#define WINDOW_WRITE_ADDR_ADDRESS (scn->hostdef->d_WINDOW_WRITE_ADDR_ADDRESS) +#define SOC_GLOBAL_RESET_ADDRESS (scn->hostdef->d_SOC_GLOBAL_RESET_ADDRESS) +#define RTC_STATE_ADDRESS (scn->hostdef->d_RTC_STATE_ADDRESS) +#define RTC_STATE_COLD_RESET_MASK (scn->hostdef->d_RTC_STATE_COLD_RESET_MASK) +#define PCIE_LOCAL_BASE_ADDRESS (scn->hostdef->d_PCIE_LOCAL_BASE_ADDRESS) +#define PCIE_SOC_WAKE_RESET (scn->hostdef->d_PCIE_SOC_WAKE_RESET) +#define PCIE_SOC_WAKE_ADDRESS (scn->hostdef->d_PCIE_SOC_WAKE_ADDRESS) +#define PCIE_SOC_WAKE_V_MASK (scn->hostdef->d_PCIE_SOC_WAKE_V_MASK) +#define RTC_STATE_V_MASK (scn->hostdef->d_RTC_STATE_V_MASK) +#define RTC_STATE_V_LSB (scn->hostdef->d_RTC_STATE_V_LSB) +#define FW_IND_EVENT_PENDING (scn->hostdef->d_FW_IND_EVENT_PENDING) +#define FW_IND_INITIALIZED (scn->hostdef->d_FW_IND_INITIALIZED) +#define FW_IND_HELPER (scn->hostdef->d_FW_IND_HELPER) +#define RTC_STATE_V_ON (scn->hostdef->d_RTC_STATE_V_ON) + +#define FW_IND_HOST_READY (scn->hostdef->d_FW_IND_HOST_READY) + +#if defined(SDIO_3_0) +#define HOST_INT_STATUS_MBOX_DATA_MASK \ + (scn->hostdef->d_HOST_INT_STATUS_MBOX_DATA_MASK) +#define HOST_INT_STATUS_MBOX_DATA_LSB \ + (scn->hostdef->d_HOST_INT_STATUS_MBOX_DATA_LSB) +#endif + +#if !defined(SOC_PCIE_BASE_ADDRESS) +#define SOC_PCIE_BASE_ADDRESS 0 +#endif + +#if !defined(PCIE_SOC_RDY_STATUS_ADDRESS) +#define PCIE_SOC_RDY_STATUS_ADDRESS 0 +#define PCIE_SOC_RDY_STATUS_BAR_MASK 0 +#endif + +#if !defined(MSI_MAGIC_ADR_ADDRESS) +#define MSI_MAGIC_ADR_ADDRESS 0 +#define MSI_MAGIC_ADDRESS 0 +#endif + +/* SET/GET macros */ +#define INT_STATUS_ENABLE_ERROR_SET(x) \ + (((x) << INT_STATUS_ENABLE_ERROR_LSB) & INT_STATUS_ENABLE_ERROR_MASK) +#define INT_STATUS_ENABLE_CPU_SET(x) \ + (((x) << INT_STATUS_ENABLE_CPU_LSB) & INT_STATUS_ENABLE_CPU_MASK) +#define INT_STATUS_ENABLE_COUNTER_SET(x) \ + (((x) << INT_STATUS_ENABLE_COUNTER_LSB) & \ + INT_STATUS_ENABLE_COUNTER_MASK) +#define INT_STATUS_ENABLE_MBOX_DATA_SET(x) \ + (((x) << INT_STATUS_ENABLE_MBOX_DATA_LSB) & \ + INT_STATUS_ENABLE_MBOX_DATA_MASK) +#define CPU_INT_STATUS_ENABLE_BIT_SET(x) \ + (((x) << CPU_INT_STATUS_ENABLE_BIT_LSB) & \ + CPU_INT_STATUS_ENABLE_BIT_MASK) +#define ERROR_STATUS_ENABLE_RX_UNDERFLOW_SET(x) \ + (((x) << ERROR_STATUS_ENABLE_RX_UNDERFLOW_LSB) & \ + ERROR_STATUS_ENABLE_RX_UNDERFLOW_MASK) +#define ERROR_STATUS_ENABLE_TX_OVERFLOW_SET(x) \ + (((x) << ERROR_STATUS_ENABLE_TX_OVERFLOW_LSB) & \ + ERROR_STATUS_ENABLE_TX_OVERFLOW_MASK) +#define COUNTER_INT_STATUS_ENABLE_BIT_SET(x) \ + (((x) << COUNTER_INT_STATUS_ENABLE_BIT_LSB) & \ + COUNTER_INT_STATUS_ENABLE_BIT_MASK) +#define ERROR_INT_STATUS_WAKEUP_GET(x) \ + (((x) & ERROR_INT_STATUS_WAKEUP_MASK) >> \ + ERROR_INT_STATUS_WAKEUP_LSB) +#define ERROR_INT_STATUS_RX_UNDERFLOW_GET(x) \ + (((x) & ERROR_INT_STATUS_RX_UNDERFLOW_MASK) >> \ + ERROR_INT_STATUS_RX_UNDERFLOW_LSB) +#define ERROR_INT_STATUS_TX_OVERFLOW_GET(x) \ + (((x) & ERROR_INT_STATUS_TX_OVERFLOW_MASK) >> \ + ERROR_INT_STATUS_TX_OVERFLOW_LSB) +#define HOST_INT_STATUS_CPU_GET(x) \ + (((x) & HOST_INT_STATUS_CPU_MASK) >> HOST_INT_STATUS_CPU_LSB) +#define HOST_INT_STATUS_ERROR_GET(x) \ + (((x) & HOST_INT_STATUS_ERROR_MASK) >> HOST_INT_STATUS_ERROR_LSB) +#define HOST_INT_STATUS_COUNTER_GET(x) \ + (((x) & HOST_INT_STATUS_COUNTER_MASK) >> HOST_INT_STATUS_COUNTER_LSB) +#define RTC_STATE_V_GET(x) \ + (((x) & RTC_STATE_V_MASK) >> RTC_STATE_V_LSB) +#if defined(SDIO_3_0) +#define HOST_INT_STATUS_MBOX_DATA_GET(x) \ + (((x) & HOST_INT_STATUS_MBOX_DATA_MASK) >> \ + HOST_INT_STATUS_MBOX_DATA_LSB) +#endif + +#define INVALID_REG_LOC_DUMMY_DATA 0xAA + +#define AR6320_CORE_CLK_DIV_ADDR 0x403fa8 +#define AR6320_CPU_PLL_INIT_DONE_ADDR 0x403fd0 +#define AR6320_CPU_SPEED_ADDR 0x403fa4 +#define AR6320V2_CORE_CLK_DIV_ADDR 0x403fd8 +#define AR6320V2_CPU_PLL_INIT_DONE_ADDR 0x403fd0 +#define AR6320V2_CPU_SPEED_ADDR 0x403fd4 +#define AR6320V3_CORE_CLK_DIV_ADDR 0x404028 +#define AR6320V3_CPU_PLL_INIT_DONE_ADDR 0x404020 +#define AR6320V3_CPU_SPEED_ADDR 0x404024 + +typedef enum { + SOC_REFCLK_UNKNOWN = -1, /* Unsupported ref clock -- use PLL Bypass */ + SOC_REFCLK_48_MHZ = 0, + SOC_REFCLK_19_2_MHZ = 1, + SOC_REFCLK_24_MHZ = 2, + SOC_REFCLK_26_MHZ = 3, + SOC_REFCLK_37_4_MHZ = 4, + SOC_REFCLK_38_4_MHZ = 5, + SOC_REFCLK_40_MHZ = 6, + SOC_REFCLK_52_MHZ = 7, +} A_refclk_speed_t; + +#define A_REFCLK_UNKNOWN SOC_REFCLK_UNKNOWN +#define A_REFCLK_48_MHZ SOC_REFCLK_48_MHZ +#define A_REFCLK_19_2_MHZ SOC_REFCLK_19_2_MHZ +#define A_REFCLK_24_MHZ SOC_REFCLK_24_MHZ +#define A_REFCLK_26_MHZ SOC_REFCLK_26_MHZ +#define A_REFCLK_37_4_MHZ SOC_REFCLK_37_4_MHZ +#define A_REFCLK_38_4_MHZ SOC_REFCLK_38_4_MHZ +#define A_REFCLK_40_MHZ SOC_REFCLK_40_MHZ +#define A_REFCLK_52_MHZ SOC_REFCLK_52_MHZ + +#define TARGET_CPU_FREQ 176000000 + +struct wlan_pll_s { + uint32_t refdiv; + uint32_t div; + uint32_t rnfrac; + uint32_t outdiv; +}; + +struct cmnos_clock_s { + A_refclk_speed_t refclk_speed; + uint32_t refclk_hz; + uint32_t pll_settling_time; /* 50us */ + struct wlan_pll_s wlan_pll; +}; + +typedef struct TGT_REG_SECTION { + uint32_t start_addr; + uint32_t end_addr; +} tgt_reg_section; + +typedef struct TGT_REG_TABLE { + tgt_reg_section *section; + uint32_t section_size; +} tgt_reg_table; + +struct hif_softc; +void hif_target_register_tbl_attach(struct hif_softc *scn, u32 target_type); +void hif_register_tbl_attach(struct hif_softc *scn, u32 hif_type); + +#endif /* _REGTABLE_PCIE_H_ */ diff --git a/drivers/staging/qca-wifi-host-cmn/hif/inc/target_reg_init.h b/drivers/staging/qca-wifi-host-cmn/hif/inc/target_reg_init.h new file mode 100644 index 0000000000000000000000000000000000000000..a776678d9038f6a65c01621f84d001c99fbcbc6b --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/hif/inc/target_reg_init.h @@ -0,0 +1,504 @@ +/* + * Copyright (c) 2016 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 TARGET_REG_INIT_H +#define TARGET_REG_INIT_H +#include "reg_struct.h" +#include "targaddrs.h" +/*** WARNING : Add to the end of the TABLE! do not change the order ****/ +typedef struct targetdef_s TARGET_REGISTER_TABLE; + + + +#define ATH_UNSUPPORTED_REG_OFFSET UNSUPPORTED_REGISTER_OFFSET +#define ATH_SUPPORTED_BY_TARGET(reg_offset) \ + ((reg_offset) != ATH_UNSUPPORTED_REG_OFFSET) + +#if defined(MY_TARGET_DEF) + +/* Cross-platform compatibility */ +#if !defined(SOC_RESET_CONTROL_OFFSET) && defined(RESET_CONTROL_OFFSET) +#define SOC_RESET_CONTROL_OFFSET RESET_CONTROL_OFFSET +#endif + +#if !defined(CLOCK_GPIO_OFFSET) +#define CLOCK_GPIO_OFFSET ATH_UNSUPPORTED_REG_OFFSET +#define CLOCK_GPIO_BT_CLK_OUT_EN_LSB 0 +#define CLOCK_GPIO_BT_CLK_OUT_EN_MASK 0 +#endif + +#if !defined(WLAN_MAC_BASE_ADDRESS) +#define WLAN_MAC_BASE_ADDRESS ATH_UNSUPPORTED_REG_OFFSET +#endif + +#if !defined(CE0_BASE_ADDRESS) +#define CE0_BASE_ADDRESS ATH_UNSUPPORTED_REG_OFFSET +#define CE1_BASE_ADDRESS ATH_UNSUPPORTED_REG_OFFSET +#define CE_COUNT 0 +#endif + +#if !defined(MSI_NUM_REQUEST) +#define MSI_NUM_REQUEST 0 +#define MSI_ASSIGN_FW 0 +#define MSI_ASSIGN_CE_INITIAL 0 +#endif + +#if !defined(FW_INDICATOR_ADDRESS) +#define FW_INDICATOR_ADDRESS ATH_UNSUPPORTED_REG_OFFSET +#endif + +#if !defined(FW_CPU_PLL_CONFIG) +#define FW_CPU_PLL_CONFIG ATH_UNSUPPORTED_REG_OFFSET +#endif + +#if !defined(DRAM_BASE_ADDRESS) +#define DRAM_BASE_ADDRESS ATH_UNSUPPORTED_REG_OFFSET +#endif + +#if !defined(SOC_CORE_BASE_ADDRESS) +#define SOC_CORE_BASE_ADDRESS ATH_UNSUPPORTED_REG_OFFSET +#endif + +#if !defined(CPU_INTR_ADDRESS) +#define CPU_INTR_ADDRESS ATH_UNSUPPORTED_REG_OFFSET +#endif + +#if !defined(SOC_LF_TIMER_CONTROL0_ADDRESS) +#define SOC_LF_TIMER_CONTROL0_ADDRESS ATH_UNSUPPORTED_REG_OFFSET +#define SOC_LF_TIMER_CONTROL0_ENABLE_MASK ATH_UNSUPPORTED_REG_OFFSET +#endif + +#if !defined(SOC_RESET_CONTROL_ADDRESS) +#define SOC_RESET_CONTROL_ADDRESS ATH_UNSUPPORTED_REG_OFFSET +#define SOC_RESET_CONTROL_CE_RST_MASK ATH_UNSUPPORTED_REG_OFFSET +#define SOC_RESET_CONTROL_CPU_WARM_RST_MASK ATH_UNSUPPORTED_REG_OFFSET +#endif + +#if !defined(CORE_CTRL_ADDRESS) +#define CORE_CTRL_ADDRESS ATH_UNSUPPORTED_REG_OFFSET +#define CORE_CTRL_CPU_INTR_MASK 0 +#endif + +#if !defined(PCIE_INTR_ENABLE_ADDRESS) +#define PCIE_INTR_ENABLE_ADDRESS ATH_UNSUPPORTED_REG_OFFSET +#define PCIE_INTR_CLR_ADDRESS ATH_UNSUPPORTED_REG_OFFSET +#define PCIE_INTR_FIRMWARE_MASK ATH_UNSUPPORTED_REG_OFFSET +#define PCIE_INTR_CE_MASK_ALL ATH_UNSUPPORTED_REG_OFFSET +#define PCIE_INTR_CAUSE_ADDRESS ATH_UNSUPPORTED_REG_OFFSET +#endif + +#if !defined(WIFICMN_PCIE_BAR_REG_ADDRESS) +#define WIFICMN_PCIE_BAR_REG_ADDRESS ATH_UNSUPPORTED_REG_OFFSET +#endif + +#if !defined(WIFICMN_INT_STATUS_ADDRESS) +#define WIFICMN_INT_STATUS_ADDRESS ATH_UNSUPPORTED_REG_OFFSET +#endif + +#if !defined(FW_AXI_MSI_ADDR) +#define FW_AXI_MSI_ADDR ATH_UNSUPPORTED_REG_OFFSET +#endif + +#if !defined(FW_AXI_MSI_DATA) +#define FW_AXI_MSI_DATA ATH_UNSUPPORTED_REG_OFFSET +#endif + +#if !defined(WLAN_SUBSYSTEM_CORE_ID_ADDRESS) +#define WLAN_SUBSYSTEM_CORE_ID_ADDRESS ATH_UNSUPPORTED_REG_OFFSET +#endif + +#if !defined(FPGA_VERSION_ADDRESS) +#define FPGA_VERSION_ADDRESS ATH_UNSUPPORTED_REG_OFFSET +#endif + +#if !defined(SI_CONFIG_ADDRESS) +#define SI_CONFIG_ADDRESS ATH_UNSUPPORTED_REG_OFFSET +#define SI_CONFIG_BIDIR_OD_DATA_LSB 0 +#define SI_CONFIG_BIDIR_OD_DATA_MASK 0 +#define SI_CONFIG_I2C_LSB 0 +#define SI_CONFIG_I2C_MASK 0 +#define SI_CONFIG_POS_SAMPLE_LSB 0 +#define SI_CONFIG_POS_SAMPLE_MASK 0 +#define SI_CONFIG_INACTIVE_CLK_LSB 0 +#define SI_CONFIG_INACTIVE_CLK_MASK 0 +#define SI_CONFIG_INACTIVE_DATA_LSB 0 +#define SI_CONFIG_INACTIVE_DATA_MASK 0 +#define SI_CONFIG_DIVIDER_LSB 0 +#define SI_CONFIG_DIVIDER_MASK 0 +#define SI_CONFIG_OFFSET 0 +#define SI_TX_DATA0_OFFSET ATH_UNSUPPORTED_REG_OFFSET +#define SI_TX_DATA1_OFFSET ATH_UNSUPPORTED_REG_OFFSET +#define SI_RX_DATA0_OFFSET ATH_UNSUPPORTED_REG_OFFSET +#define SI_RX_DATA1_OFFSET ATH_UNSUPPORTED_REG_OFFSET +#define SI_CS_OFFSET ATH_UNSUPPORTED_REG_OFFSET +#define SI_CS_DONE_ERR_MASK 0 +#define SI_CS_DONE_INT_MASK 0 +#define SI_CS_START_LSB 0 +#define SI_CS_START_MASK 0 +#define SI_CS_RX_CNT_LSB 0 +#define SI_CS_RX_CNT_MASK 0 +#define SI_CS_TX_CNT_LSB 0 +#define SI_CS_TX_CNT_MASK 0 +#endif + +#ifndef SI_BASE_ADDRESS +#define SI_BASE_ADDRESS ATH_UNSUPPORTED_REG_OFFSET +#endif + +#ifndef WLAN_GPIO_PIN10_ADDRESS +#define WLAN_GPIO_PIN10_ADDRESS ATH_UNSUPPORTED_REG_OFFSET +#endif + +#ifndef WLAN_GPIO_PIN11_ADDRESS +#define WLAN_GPIO_PIN11_ADDRESS ATH_UNSUPPORTED_REG_OFFSET +#endif + +#ifndef WLAN_GPIO_PIN12_ADDRESS +#define WLAN_GPIO_PIN12_ADDRESS ATH_UNSUPPORTED_REG_OFFSET +#endif + +#ifndef WLAN_GPIO_PIN13_ADDRESS +#define WLAN_GPIO_PIN13_ADDRESS ATH_UNSUPPORTED_REG_OFFSET +#endif + +#ifndef WIFICMN_INT_STATUS_ADDRESS +#define WIFICMN_INT_STATUS_ADDRESS ATH_UNSUPPORTED_REG_OFFSET +#endif + +static struct targetdef_s my_target_def = { + .d_RTC_SOC_BASE_ADDRESS = RTC_SOC_BASE_ADDRESS, + .d_RTC_WMAC_BASE_ADDRESS = RTC_WMAC_BASE_ADDRESS, + .d_SYSTEM_SLEEP_OFFSET = WLAN_SYSTEM_SLEEP_OFFSET, + .d_WLAN_SYSTEM_SLEEP_OFFSET = WLAN_SYSTEM_SLEEP_OFFSET, + .d_WLAN_SYSTEM_SLEEP_DISABLE_LSB = WLAN_SYSTEM_SLEEP_DISABLE_LSB, + .d_WLAN_SYSTEM_SLEEP_DISABLE_MASK = WLAN_SYSTEM_SLEEP_DISABLE_MASK, + .d_CLOCK_CONTROL_OFFSET = CLOCK_CONTROL_OFFSET, + .d_CLOCK_CONTROL_SI0_CLK_MASK = CLOCK_CONTROL_SI0_CLK_MASK, + .d_RESET_CONTROL_OFFSET = SOC_RESET_CONTROL_OFFSET, + .d_RESET_CONTROL_SI0_RST_MASK = RESET_CONTROL_SI0_RST_MASK, + .d_WLAN_RESET_CONTROL_OFFSET = WLAN_RESET_CONTROL_OFFSET, + .d_WLAN_RESET_CONTROL_COLD_RST_MASK = WLAN_RESET_CONTROL_COLD_RST_MASK, + .d_WLAN_RESET_CONTROL_WARM_RST_MASK = WLAN_RESET_CONTROL_WARM_RST_MASK, + .d_GPIO_BASE_ADDRESS = GPIO_BASE_ADDRESS, + .d_GPIO_PIN0_OFFSET = GPIO_PIN0_OFFSET, + .d_GPIO_PIN1_OFFSET = GPIO_PIN1_OFFSET, + .d_GPIO_PIN0_CONFIG_MASK = GPIO_PIN0_CONFIG_MASK, + .d_GPIO_PIN1_CONFIG_MASK = GPIO_PIN1_CONFIG_MASK, + .d_SI_CONFIG_BIDIR_OD_DATA_LSB = SI_CONFIG_BIDIR_OD_DATA_LSB, + .d_SI_CONFIG_BIDIR_OD_DATA_MASK = SI_CONFIG_BIDIR_OD_DATA_MASK, + .d_SI_CONFIG_I2C_LSB = SI_CONFIG_I2C_LSB, + .d_SI_CONFIG_I2C_MASK = SI_CONFIG_I2C_MASK, + .d_SI_CONFIG_POS_SAMPLE_LSB = SI_CONFIG_POS_SAMPLE_LSB, + .d_SI_CONFIG_POS_SAMPLE_MASK = SI_CONFIG_POS_SAMPLE_MASK, + .d_SI_CONFIG_INACTIVE_CLK_LSB = SI_CONFIG_INACTIVE_CLK_LSB, + .d_SI_CONFIG_INACTIVE_CLK_MASK = SI_CONFIG_INACTIVE_CLK_MASK, + .d_SI_CONFIG_INACTIVE_DATA_LSB = SI_CONFIG_INACTIVE_DATA_LSB, + .d_SI_CONFIG_INACTIVE_DATA_MASK = SI_CONFIG_INACTIVE_DATA_MASK, + .d_SI_CONFIG_DIVIDER_LSB = SI_CONFIG_DIVIDER_LSB, + .d_SI_CONFIG_DIVIDER_MASK = SI_CONFIG_DIVIDER_MASK, + .d_SI_BASE_ADDRESS = SI_BASE_ADDRESS, + .d_SI_CONFIG_OFFSET = SI_CONFIG_OFFSET, + .d_SI_TX_DATA0_OFFSET = SI_TX_DATA0_OFFSET, + .d_SI_TX_DATA1_OFFSET = SI_TX_DATA1_OFFSET, + .d_SI_RX_DATA0_OFFSET = SI_RX_DATA0_OFFSET, + .d_SI_RX_DATA1_OFFSET = SI_RX_DATA1_OFFSET, + .d_SI_CS_OFFSET = SI_CS_OFFSET, + .d_SI_CS_DONE_ERR_MASK = SI_CS_DONE_ERR_MASK, + .d_SI_CS_DONE_INT_MASK = SI_CS_DONE_INT_MASK, + .d_SI_CS_START_LSB = SI_CS_START_LSB, + .d_SI_CS_START_MASK = SI_CS_START_MASK, + .d_SI_CS_RX_CNT_LSB = SI_CS_RX_CNT_LSB, + .d_SI_CS_RX_CNT_MASK = SI_CS_RX_CNT_MASK, + .d_SI_CS_TX_CNT_LSB = SI_CS_TX_CNT_LSB, + .d_SI_CS_TX_CNT_MASK = SI_CS_TX_CNT_MASK, + .d_BOARD_DATA_SZ = MY_TARGET_BOARD_DATA_SZ, + .d_BOARD_EXT_DATA_SZ = MY_TARGET_BOARD_EXT_DATA_SZ, + .d_MBOX_BASE_ADDRESS = MBOX_BASE_ADDRESS, + .d_LOCAL_SCRATCH_OFFSET = LOCAL_SCRATCH_OFFSET, + .d_CPU_CLOCK_OFFSET = CPU_CLOCK_OFFSET, + .d_GPIO_PIN10_OFFSET = GPIO_PIN10_OFFSET, + .d_GPIO_PIN11_OFFSET = GPIO_PIN11_OFFSET, + .d_GPIO_PIN12_OFFSET = GPIO_PIN12_OFFSET, + .d_GPIO_PIN13_OFFSET = GPIO_PIN13_OFFSET, + .d_CLOCK_GPIO_OFFSET = CLOCK_GPIO_OFFSET, + .d_CPU_CLOCK_STANDARD_LSB = CPU_CLOCK_STANDARD_LSB, + .d_CPU_CLOCK_STANDARD_MASK = CPU_CLOCK_STANDARD_MASK, + .d_LPO_CAL_ENABLE_LSB = LPO_CAL_ENABLE_LSB, + .d_LPO_CAL_ENABLE_MASK = LPO_CAL_ENABLE_MASK, + .d_CLOCK_GPIO_BT_CLK_OUT_EN_LSB = CLOCK_GPIO_BT_CLK_OUT_EN_LSB, + .d_CLOCK_GPIO_BT_CLK_OUT_EN_MASK = CLOCK_GPIO_BT_CLK_OUT_EN_MASK, + .d_ANALOG_INTF_BASE_ADDRESS = ANALOG_INTF_BASE_ADDRESS, + .d_WLAN_MAC_BASE_ADDRESS = WLAN_MAC_BASE_ADDRESS, + .d_CE0_BASE_ADDRESS = CE0_BASE_ADDRESS, + .d_CE1_BASE_ADDRESS = CE1_BASE_ADDRESS, + .d_FW_INDICATOR_ADDRESS = FW_INDICATOR_ADDRESS, + .d_FW_CPU_PLL_CONFIG = FW_CPU_PLL_CONFIG, + .d_DRAM_BASE_ADDRESS = DRAM_BASE_ADDRESS, + .d_SOC_CORE_BASE_ADDRESS = SOC_CORE_BASE_ADDRESS, + .d_CORE_CTRL_ADDRESS = CORE_CTRL_ADDRESS, + .d_CE_COUNT = CE_COUNT, + .d_MSI_NUM_REQUEST = MSI_NUM_REQUEST, + .d_MSI_ASSIGN_FW = MSI_ASSIGN_FW, + .d_MSI_ASSIGN_CE_INITIAL = MSI_ASSIGN_CE_INITIAL, + .d_PCIE_INTR_ENABLE_ADDRESS = PCIE_INTR_ENABLE_ADDRESS, + .d_PCIE_INTR_CLR_ADDRESS = PCIE_INTR_CLR_ADDRESS, + .d_PCIE_INTR_FIRMWARE_MASK = PCIE_INTR_FIRMWARE_MASK, + .d_PCIE_INTR_CE_MASK_ALL = PCIE_INTR_CE_MASK_ALL, + .d_CORE_CTRL_CPU_INTR_MASK = CORE_CTRL_CPU_INTR_MASK, + .d_WIFICMN_PCIE_BAR_REG_ADDRESS = WIFICMN_PCIE_BAR_REG_ADDRESS, + /* htt_rx.c */ + /* htt tx */ + .d_MSDU_LINK_EXT_3_TCP_OVER_IPV4_CHECKSUM_EN_MASK + = MSDU_LINK_EXT_3_TCP_OVER_IPV4_CHECKSUM_EN_MASK, + .d_MSDU_LINK_EXT_3_TCP_OVER_IPV6_CHECKSUM_EN_MASK + = MSDU_LINK_EXT_3_TCP_OVER_IPV6_CHECKSUM_EN_MASK, + .d_MSDU_LINK_EXT_3_UDP_OVER_IPV4_CHECKSUM_EN_MASK + = MSDU_LINK_EXT_3_UDP_OVER_IPV4_CHECKSUM_EN_MASK, + .d_MSDU_LINK_EXT_3_UDP_OVER_IPV6_CHECKSUM_EN_MASK + = MSDU_LINK_EXT_3_UDP_OVER_IPV6_CHECKSUM_EN_MASK, + .d_MSDU_LINK_EXT_3_TCP_OVER_IPV4_CHECKSUM_EN_LSB + = MSDU_LINK_EXT_3_TCP_OVER_IPV4_CHECKSUM_EN_LSB, + .d_MSDU_LINK_EXT_3_TCP_OVER_IPV6_CHECKSUM_EN_LSB + = MSDU_LINK_EXT_3_TCP_OVER_IPV6_CHECKSUM_EN_LSB, + .d_MSDU_LINK_EXT_3_UDP_OVER_IPV4_CHECKSUM_EN_LSB + = MSDU_LINK_EXT_3_UDP_OVER_IPV4_CHECKSUM_EN_LSB, + .d_MSDU_LINK_EXT_3_UDP_OVER_IPV6_CHECKSUM_EN_LSB + = MSDU_LINK_EXT_3_UDP_OVER_IPV6_CHECKSUM_EN_LSB, + /* copy_engine.c */ + .d_DST_WR_INDEX_ADDRESS = DST_WR_INDEX_ADDRESS, + .d_SRC_WATERMARK_ADDRESS = SRC_WATERMARK_ADDRESS, + .d_SRC_WATERMARK_LOW_MASK = SRC_WATERMARK_LOW_MASK, + .d_SRC_WATERMARK_HIGH_MASK = SRC_WATERMARK_HIGH_MASK, + .d_DST_WATERMARK_LOW_MASK = DST_WATERMARK_LOW_MASK, + .d_DST_WATERMARK_HIGH_MASK = DST_WATERMARK_HIGH_MASK, + .d_CURRENT_SRRI_ADDRESS = CURRENT_SRRI_ADDRESS, + .d_CURRENT_DRRI_ADDRESS = CURRENT_DRRI_ADDRESS, + .d_HOST_IS_SRC_RING_HIGH_WATERMARK_MASK + = HOST_IS_SRC_RING_HIGH_WATERMARK_MASK, + .d_HOST_IS_SRC_RING_LOW_WATERMARK_MASK + = HOST_IS_SRC_RING_LOW_WATERMARK_MASK, + .d_HOST_IS_DST_RING_HIGH_WATERMARK_MASK + = HOST_IS_DST_RING_HIGH_WATERMARK_MASK, + .d_HOST_IS_DST_RING_LOW_WATERMARK_MASK + = HOST_IS_DST_RING_LOW_WATERMARK_MASK, + .d_HOST_IS_ADDRESS = HOST_IS_ADDRESS, + .d_HOST_IS_COPY_COMPLETE_MASK = HOST_IS_COPY_COMPLETE_MASK, + .d_CE_CMD_ADDRESS = CE_CMD_ADDRESS, + .d_CE_CMD_HALT_MASK = CE_CMD_HALT_MASK, + .d_CE_WRAPPER_BASE_ADDRESS = CE_WRAPPER_BASE_ADDRESS, + .d_CE_WRAPPER_INTERRUPT_SUMMARY_ADDRESS + = CE_WRAPPER_INTERRUPT_SUMMARY_ADDRESS, + .d_HOST_IE_ADDRESS = HOST_IE_ADDRESS, + .d_HOST_IE_COPY_COMPLETE_MASK = HOST_IE_COPY_COMPLETE_MASK, + .d_SR_BA_ADDRESS = SR_BA_ADDRESS, + .d_SR_SIZE_ADDRESS = SR_SIZE_ADDRESS, + .d_CE_CTRL1_ADDRESS = CE_CTRL1_ADDRESS, + .d_CE_CTRL1_DMAX_LENGTH_MASK = CE_CTRL1_DMAX_LENGTH_MASK, + .d_DR_BA_ADDRESS = DR_BA_ADDRESS, + .d_DR_SIZE_ADDRESS = DR_SIZE_ADDRESS, + .d_MISC_IE_ADDRESS = MISC_IE_ADDRESS, + .d_MISC_IS_AXI_ERR_MASK = MISC_IS_AXI_ERR_MASK, + .d_MISC_IS_DST_ADDR_ERR_MASK = MISC_IS_DST_ADDR_ERR_MASK, + .d_MISC_IS_SRC_LEN_ERR_MASK = MISC_IS_SRC_LEN_ERR_MASK, + .d_MISC_IS_DST_MAX_LEN_VIO_MASK = MISC_IS_DST_MAX_LEN_VIO_MASK, + .d_MISC_IS_DST_RING_OVERFLOW_MASK = MISC_IS_DST_RING_OVERFLOW_MASK, + .d_MISC_IS_SRC_RING_OVERFLOW_MASK = MISC_IS_SRC_RING_OVERFLOW_MASK, + .d_SRC_WATERMARK_LOW_LSB = SRC_WATERMARK_LOW_LSB, + .d_SRC_WATERMARK_HIGH_LSB = SRC_WATERMARK_HIGH_LSB, + .d_DST_WATERMARK_LOW_LSB = DST_WATERMARK_LOW_LSB, + .d_DST_WATERMARK_HIGH_LSB = DST_WATERMARK_HIGH_LSB, + .d_CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_MASK + = CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_MASK, + .d_CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_LSB + = CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_LSB, + .d_CE_CTRL1_DMAX_LENGTH_LSB = CE_CTRL1_DMAX_LENGTH_LSB, + .d_CE_CTRL1_SRC_RING_BYTE_SWAP_EN_MASK + = CE_CTRL1_SRC_RING_BYTE_SWAP_EN_MASK, + .d_CE_CTRL1_DST_RING_BYTE_SWAP_EN_MASK + = CE_CTRL1_DST_RING_BYTE_SWAP_EN_MASK, + .d_CE_CTRL1_SRC_RING_BYTE_SWAP_EN_LSB + = CE_CTRL1_SRC_RING_BYTE_SWAP_EN_LSB, + .d_CE_CTRL1_DST_RING_BYTE_SWAP_EN_LSB + = CE_CTRL1_DST_RING_BYTE_SWAP_EN_LSB, + .d_CE_CMD_HALT_STATUS_MASK = CE_CMD_HALT_STATUS_MASK, + .d_CE_CMD_HALT_STATUS_LSB = CE_CMD_HALT_STATUS_LSB, + .d_SR_WR_INDEX_ADDRESS = SR_WR_INDEX_ADDRESS, + .d_DST_WATERMARK_ADDRESS = DST_WATERMARK_ADDRESS, + .d_PCIE_INTR_CAUSE_ADDRESS = PCIE_INTR_CAUSE_ADDRESS, + .d_SOC_RESET_CONTROL_ADDRESS = SOC_RESET_CONTROL_ADDRESS, + .d_SOC_RESET_CONTROL_CE_RST_MASK = SOC_RESET_CONTROL_CE_RST_MASK, + .d_SOC_RESET_CONTROL_CPU_WARM_RST_MASK + = SOC_RESET_CONTROL_CPU_WARM_RST_MASK, + .d_CPU_INTR_ADDRESS = CPU_INTR_ADDRESS, + .d_SOC_LF_TIMER_CONTROL0_ADDRESS = SOC_LF_TIMER_CONTROL0_ADDRESS, + .d_SOC_LF_TIMER_CONTROL0_ENABLE_MASK + = SOC_LF_TIMER_CONTROL0_ENABLE_MASK, + .d_SI_CONFIG_ERR_INT_MASK = SI_CONFIG_ERR_INT_MASK, + .d_SI_CONFIG_ERR_INT_LSB = SI_CONFIG_ERR_INT_LSB, + .d_GPIO_ENABLE_W1TS_LOW_ADDRESS = GPIO_ENABLE_W1TS_LOW_ADDRESS, + .d_GPIO_PIN0_CONFIG_LSB = GPIO_PIN0_CONFIG_LSB, + .d_GPIO_PIN0_PAD_PULL_LSB = GPIO_PIN0_PAD_PULL_LSB, + .d_GPIO_PIN0_PAD_PULL_MASK = GPIO_PIN0_PAD_PULL_MASK, + .d_SOC_CHIP_ID_ADDRESS = SOC_CHIP_ID_ADDRESS, + .d_SOC_CHIP_ID_REVISION_MASK = SOC_CHIP_ID_REVISION_MASK, + .d_SOC_CHIP_ID_REVISION_LSB = SOC_CHIP_ID_REVISION_LSB, + .d_SOC_CHIP_ID_REVISION_MSB = SOC_CHIP_ID_REVISION_MSB, + .d_WIFICMN_PCIE_BAR_REG_ADDRESS = WIFICMN_PCIE_BAR_REG_ADDRESS, + .d_FW_AXI_MSI_ADDR = FW_AXI_MSI_ADDR, + .d_FW_AXI_MSI_DATA = FW_AXI_MSI_DATA, + .d_WLAN_SUBSYSTEM_CORE_ID_ADDRESS = WLAN_SUBSYSTEM_CORE_ID_ADDRESS, + .d_FPGA_VERSION_ADDRESS = FPGA_VERSION_ADDRESS, + .d_WIFICMN_INT_STATUS_ADDRESS = WIFICMN_INT_STATUS_ADDRESS, +}; + +struct targetdef_s *MY_TARGET_DEF = &my_target_def; +#else +#endif + +#if defined(MY_CEREG_DEF) + +#if !defined(CE_DDR_ADDRESS_FOR_RRI_LOW) +#define CE_DDR_ADDRESS_FOR_RRI_LOW ATH_UNSUPPORTED_REG_OFFSET +#endif +#if !defined(CE_DDR_ADDRESS_FOR_RRI_HIGH) +#define CE_DDR_ADDRESS_FOR_RRI_HIGH ATH_UNSUPPORTED_REG_OFFSET +#endif +#if !defined(SR_BA_ADDRESS_HIGH) +#define SR_BA_ADDRESS_HIGH ATH_UNSUPPORTED_REG_OFFSET +#endif +#if !defined(DR_BA_ADDRESS_HIGH) +#define DR_BA_ADDRESS_HIGH ATH_UNSUPPORTED_REG_OFFSET +#endif +#if !defined(CE_CMD_REGISTER) +#define CE_CMD_REGISTER ATH_UNSUPPORTED_REG_OFFSET +#endif +#if !defined(CE_MSI_ADDRESS) +#define CE_MSI_ADDRESS ATH_UNSUPPORTED_REG_OFFSET +#endif +#if !defined(CE_MSI_ADDRESS_HIGH) +#define CE_MSI_ADDRESS_HIGH ATH_UNSUPPORTED_REG_OFFSET +#endif +#if !defined(CE_MSI_DATA) +#define CE_MSI_DATA ATH_UNSUPPORTED_REG_OFFSET +#endif +#if !defined(CE_MSI_ENABLE_BIT) +#define CE_MSI_ENABLE_BIT ATH_UNSUPPORTED_REG_OFFSET +#endif +#if !defined(CE_CTRL1_IDX_UPD_EN_MASK) +#define CE_CTRL1_IDX_UPD_EN_MASK ATH_UNSUPPORTED_REG_OFFSET +#endif +#if !defined(CE_WRAPPER_DEBUG_OFFSET) +#define CE_WRAPPER_DEBUG_OFFSET ATH_UNSUPPORTED_REG_OFFSET +#endif +#if !defined(CE_DEBUG_OFFSET) +#define CE_DEBUG_OFFSET ATH_UNSUPPORTED_REG_OFFSET +#endif +#if !defined(A_WIFI_APB_3_A_WCMN_APPS_CE_INTR_ENABLES) +#define A_WIFI_APB_3_A_WCMN_APPS_CE_INTR_ENABLES ATH_UNSUPPORTED_REG_OFFSET +#endif +#if !defined(A_WIFI_APB_3_A_WCMN_APPS_CE_INTR_STATUS) +#define A_WIFI_APB_3_A_WCMN_APPS_CE_INTR_STATUS ATH_UNSUPPORTED_REG_OFFSET +#endif + +static struct ce_reg_def my_ce_reg_def = { + /* copy_engine.c */ + .d_DST_WR_INDEX_ADDRESS = DST_WR_INDEX_ADDRESS, + .d_SRC_WATERMARK_ADDRESS = SRC_WATERMARK_ADDRESS, + .d_SRC_WATERMARK_LOW_MASK = SRC_WATERMARK_LOW_MASK, + .d_SRC_WATERMARK_HIGH_MASK = SRC_WATERMARK_HIGH_MASK, + .d_DST_WATERMARK_LOW_MASK = DST_WATERMARK_LOW_MASK, + .d_DST_WATERMARK_HIGH_MASK = DST_WATERMARK_HIGH_MASK, + .d_CURRENT_SRRI_ADDRESS = CURRENT_SRRI_ADDRESS, + .d_CURRENT_DRRI_ADDRESS = CURRENT_DRRI_ADDRESS, + .d_HOST_IS_SRC_RING_HIGH_WATERMARK_MASK + = HOST_IS_SRC_RING_HIGH_WATERMARK_MASK, + .d_HOST_IS_SRC_RING_LOW_WATERMARK_MASK + = HOST_IS_SRC_RING_LOW_WATERMARK_MASK, + .d_HOST_IS_DST_RING_HIGH_WATERMARK_MASK + = HOST_IS_DST_RING_HIGH_WATERMARK_MASK, + .d_HOST_IS_DST_RING_LOW_WATERMARK_MASK + = HOST_IS_DST_RING_LOW_WATERMARK_MASK, + .d_HOST_IS_ADDRESS = HOST_IS_ADDRESS, + .d_MISC_IS_ADDRESS = MISC_IS_ADDRESS, + .d_HOST_IS_COPY_COMPLETE_MASK = HOST_IS_COPY_COMPLETE_MASK, + .d_CE_WRAPPER_BASE_ADDRESS = CE_WRAPPER_BASE_ADDRESS, + .d_CE_WRAPPER_INTERRUPT_SUMMARY_ADDRESS + = CE_WRAPPER_INTERRUPT_SUMMARY_ADDRESS, + .d_CE_DDR_ADDRESS_FOR_RRI_LOW = CE_DDR_ADDRESS_FOR_RRI_LOW, + .d_CE_DDR_ADDRESS_FOR_RRI_HIGH = CE_DDR_ADDRESS_FOR_RRI_HIGH, + .d_HOST_IE_ADDRESS = HOST_IE_ADDRESS, + .d_HOST_IE_COPY_COMPLETE_MASK = HOST_IE_COPY_COMPLETE_MASK, + .d_SR_BA_ADDRESS = SR_BA_ADDRESS, + .d_SR_BA_ADDRESS_HIGH = SR_BA_ADDRESS_HIGH, + .d_SR_SIZE_ADDRESS = SR_SIZE_ADDRESS, + .d_CE_CTRL1_ADDRESS = CE_CTRL1_ADDRESS, + .d_CE_CTRL1_DMAX_LENGTH_MASK = CE_CTRL1_DMAX_LENGTH_MASK, + .d_DR_BA_ADDRESS = DR_BA_ADDRESS, + .d_DR_BA_ADDRESS_HIGH = DR_BA_ADDRESS_HIGH, + .d_DR_SIZE_ADDRESS = DR_SIZE_ADDRESS, + .d_CE_CMD_REGISTER = CE_CMD_REGISTER, + .d_CE_MSI_ADDRESS = CE_MSI_ADDRESS, + .d_CE_MSI_ADDRESS_HIGH = CE_MSI_ADDRESS_HIGH, + .d_CE_MSI_DATA = CE_MSI_DATA, + .d_CE_MSI_ENABLE_BIT = CE_MSI_ENABLE_BIT, + .d_MISC_IE_ADDRESS = MISC_IE_ADDRESS, + .d_MISC_IS_AXI_ERR_MASK = MISC_IS_AXI_ERR_MASK, + .d_MISC_IS_DST_ADDR_ERR_MASK = MISC_IS_DST_ADDR_ERR_MASK, + .d_MISC_IS_SRC_LEN_ERR_MASK = MISC_IS_SRC_LEN_ERR_MASK, + .d_MISC_IS_DST_MAX_LEN_VIO_MASK = MISC_IS_DST_MAX_LEN_VIO_MASK, + .d_MISC_IS_DST_RING_OVERFLOW_MASK = MISC_IS_DST_RING_OVERFLOW_MASK, + .d_MISC_IS_SRC_RING_OVERFLOW_MASK = MISC_IS_SRC_RING_OVERFLOW_MASK, + .d_SRC_WATERMARK_LOW_LSB = SRC_WATERMARK_LOW_LSB, + .d_SRC_WATERMARK_HIGH_LSB = SRC_WATERMARK_HIGH_LSB, + .d_DST_WATERMARK_LOW_LSB = DST_WATERMARK_LOW_LSB, + .d_DST_WATERMARK_HIGH_LSB = DST_WATERMARK_HIGH_LSB, + .d_CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_MASK + = CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_MASK, + .d_CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_LSB + = CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_LSB, + .d_CE_CTRL1_DMAX_LENGTH_LSB = CE_CTRL1_DMAX_LENGTH_LSB, + .d_CE_CTRL1_SRC_RING_BYTE_SWAP_EN_MASK + = CE_CTRL1_SRC_RING_BYTE_SWAP_EN_MASK, + .d_CE_CTRL1_DST_RING_BYTE_SWAP_EN_MASK + = CE_CTRL1_DST_RING_BYTE_SWAP_EN_MASK, + .d_CE_CTRL1_SRC_RING_BYTE_SWAP_EN_LSB + = CE_CTRL1_SRC_RING_BYTE_SWAP_EN_LSB, + .d_CE_CTRL1_DST_RING_BYTE_SWAP_EN_LSB + = CE_CTRL1_DST_RING_BYTE_SWAP_EN_LSB, + .d_CE_CTRL1_IDX_UPD_EN_MASK = CE_CTRL1_IDX_UPD_EN_MASK, + .d_CE_WRAPPER_DEBUG_OFFSET = CE_WRAPPER_DEBUG_OFFSET, + .d_CE_WRAPPER_DEBUG_SEL_MSB = CE_WRAPPER_DEBUG_SEL_MSB, + .d_CE_WRAPPER_DEBUG_SEL_LSB = CE_WRAPPER_DEBUG_SEL_LSB, + .d_CE_WRAPPER_DEBUG_SEL_MASK = CE_WRAPPER_DEBUG_SEL_MASK, + .d_CE_DEBUG_OFFSET = CE_DEBUG_OFFSET, + .d_CE_DEBUG_SEL_MSB = CE_DEBUG_SEL_MSB, + .d_CE_DEBUG_SEL_LSB = CE_DEBUG_SEL_LSB, + .d_CE_DEBUG_SEL_MASK = CE_DEBUG_SEL_MASK, + .d_CE0_BASE_ADDRESS = CE0_BASE_ADDRESS, + .d_CE1_BASE_ADDRESS = CE1_BASE_ADDRESS, + .d_A_WIFI_APB_3_A_WCMN_APPS_CE_INTR_ENABLES + = A_WIFI_APB_3_A_WCMN_APPS_CE_INTR_ENABLES, + .d_A_WIFI_APB_3_A_WCMN_APPS_CE_INTR_STATUS + = A_WIFI_APB_3_A_WCMN_APPS_CE_INTR_STATUS +}; + +struct ce_reg_def *MY_CEREG_DEF = &my_ce_reg_def; + +#else +#endif +#endif diff --git a/drivers/staging/qca-wifi-host-cmn/hif/inc/targetdef.h b/drivers/staging/qca-wifi-host-cmn/hif/inc/targetdef.h new file mode 100644 index 0000000000000000000000000000000000000000..0c99e0fe6fa2a761d0c46e1cd75d2ce6397992ed --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/hif/inc/targetdef.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2013-2016 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 TARGETDEFS_H_ +#define TARGETDEFS_H_ + +#include +#include +#include +#include "target_reg_init.h" + +extern struct targetdef_s *AR6002_TARGETdef; +extern struct targetdef_s *AR6003_TARGETdef; +extern struct targetdef_s *AR6004_TARGETdef; +extern struct targetdef_s *AR9888_TARGETdef; +extern struct targetdef_s *AR9888V2_TARGETdef; +extern struct targetdef_s *AR6320_TARGETdef; +extern struct targetdef_s *AR900B_TARGETdef; +extern struct targetdef_s *QCA9984_TARGETdef; +extern struct targetdef_s *QCA9888_TARGETdef; +#ifdef ATH_AHB +extern struct targetdef_s *IPQ4019_TARGETdef; +#endif + +extern struct ce_reg_def *AR6002_CE_TARGETdef; +extern struct ce_reg_def *AR6003_CE_TARGETdef; +extern struct ce_reg_def *AR6004_CE_TARGETdef; +extern struct ce_reg_def *AR9888_CE_TARGETdef; +extern struct ce_reg_def *AR9888V2_CE_TARGETdef; +extern struct ce_reg_def *AR6320_CE_TARGETdef; +extern struct ce_reg_def *AR900B_CE_TARGETdef; +extern struct ce_reg_def *QCA9984_CE_TARGETdef; +extern struct ce_reg_def *QCA9888_CE_TARGETdef; +#ifdef ATH_AHB +extern struct ce_reg_def *IPQ4019_CE_TARGETdef; +#endif + + +#endif diff --git a/drivers/staging/qca-wifi-host-cmn/hif/src/adrastea_reg_def.h b/drivers/staging/qca-wifi-host-cmn/hif/src/adrastea_reg_def.h new file mode 100644 index 0000000000000000000000000000000000000000..a9cd309a3c21dd3b9cd826d3a69bf97fe45ae8f7 --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/hif/src/adrastea_reg_def.h @@ -0,0 +1,2376 @@ +/* + * Copyright (c) 2015-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef ADRASTEA_REG_DEF_H +#define ADRASTEA_REG_DEF_H + +/* + * Start auto-generated headers from register parser + * + * DO NOT CHANGE MANUALLY +*/ + + +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CE_CMD__SRC_FLUSH___S 1 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE10_MISC_IS__AXI_TIMEOUT_ERR___S 10 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE1_SR_BA_LOW (0x00241000) +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE11_MISC_IS__AXI_TIMEOUT_ERR___M 0x00000400 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CE_CTRL1__SRC_RING_BYTE_SWAP_EN___POR 0x0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE9_MISC_IS__AXI_TIMEOUT_ERR___M 0x00000400 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS2__ADDRESS_REGISTER___M 0x003FFFFF +#define ADRASTEA_A_WCSS_SR_APSS_FORCE_WAKE___M 0x00000001 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_QDSP_ERROR_INTR_ENABLES_SET__CE_INTR_MISC_P___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE6___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS2 (0x00030028) +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS13___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_CLEAR__FORCE_WAKE_CLEAR___POR 0x0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_QDSP_ERROR_INTR_ENABLES_SET__EXTERNAL_INTR___POR 0x000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE4_SR_BA_LOW (0x00244000) +#define ADRASTEA_A_WCSS_SR_APSS_SR_CONTROL__SOFT_RESET___M 0x00000001 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_CLEAR___M 0x000003FF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_APPS_CE_INTR_ENABLES_CLEAR___RWC QCSR_REG_RW +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE17___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_DIRTY___RWC QCSR_REG_RO +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CE_CMD__HALT_STATUS___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_FORCE_WAKE (0x00032060) +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE5_SR_BA_LOW__BASE_ADDR_LOW___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS15___POR 0x00000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CE_CTRL1___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS6 (0x00030038) +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_QDSP_ERROR_INTR_ENABLES_SET__CE_INTR_TIMEOUT_P___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_SW_SCRATCH (0x00032064) +#define ADRASTEA_A_WCSS_SR_APSS_ADDRESS_VALID__BITS___POR 0x000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_DR_BA_LOW___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS4___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE8_MISC_IS__AXI_BUS_ERR___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_DIRTY___M 0x00FFFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE6_MISC_IS__AXI_BUS_ERR___M 0x00000200 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_CLEAR__ERR_RESP_CLEAR___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_CLEAR__FORCE_WAKE_CLEAR___S 1 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE1_SR_BA_LOW__BASE_ADDR_LOW___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS15__ADDRESS_REGISTER___M 0x003FFFFF +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE4___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE4_SR_BA_LOW__BASE_ADDR_LOW___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS13___M 0x003FFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE2_MISC_IS__AXI_TIMEOUT_ERR___S 10 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE22___RWC QCSR_REG_RW +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_STATUS__ECAHB_TIMEOUT___POR 0x0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_QDSP_ERROR_INTR_ENABLES_SET__MCIM_INT___M 0x00000010 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_ENABLE__WLAN2_HW2SW_GRANT___M 0x00000080 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_DR_SIZE__SIZE___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_CLEAR__ECAHB_TIMEOUT___M 0x00000010 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_DR_SIZE___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE3_SR_BA_LOW__BASE_ADDR_LOW___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS0___M 0x003FFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CE_CTRL1__SRC_RING_BYTE_SWAP_EN___S 17 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE2__VALUE_REGISTER___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_INVALID_ADDR_ACCESS___M 0x0003FFFF +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE19___RWC QCSR_REG_RW +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS10___RWC QCSR_REG_RO +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IE__SRC_RING_HIGH_WATERMARK___M 0x00000002 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_SRC_WR_INDEX__SRC_WR_INDEX___M 0x0000FFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE_COMMON_WRAPPER_CE_WRAPPER_HOST_INTERRUPT_SUMMARY___M 0x00FFF000 +#define ADRASTEA_A_WCSS_SR_APSS_ADDRESS_VALID___M 0x00FFFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_SR_BA_HIGH__BASE_ADDR_HIGH___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE10_MISC_IS__AXI_BUS_ERR___M 0x00000200 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE18___RWC QCSR_REG_RW +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS4 (0x00030030) +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE8___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE14___RWC QCSR_REG_RW +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE5_SR_BA_LOW___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE3_MISC_IS__AXI_BUS_ERR___M 0x00000200 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IS__SRC_LEN_ERR___POR 0x0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_QDSP_ERROR_INTR_ENABLES_SET__CE_INTR_TIMEOUT_P___M 0x00000100 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_QDSP_ERROR_INTR_ENABLES_SET___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_CLEAR__ECAHB_TIMEOUT___S 4 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE22__VALUE_REGISTER___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IS__SRC_RING_LOW_WATERMARK___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_SR_CONTROL___RWC QCSR_REG_RO +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_STATUS__DIRTY_BIT_SET___M 0x00000001 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_DST_WR_INDEX (0x00240040) +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IS (0x00240038) +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE5__VALUE_REGISTER___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_QDSP_ERROR_INTR_ENABLES_SET__INVALID_BB_1_INTR___S 10 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE5___RWC QCSR_REG_RW +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE0__VALUE_REGISTER___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS16___M 0x003FFFFF +#define ADRASTEA_A_WCSS_SR_APSS_SR_CONTROL__SR_PLL_REF_MUX_SEL___POR 0x0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_APPS_CE_INTR_ENABLES_CLEAR (0x002F1008) +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS20___RWC QCSR_REG_RO +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE23___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE9___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS7___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE4__VALUE_REGISTER___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IE__DST_MAX_LEN_VIO___M 0x00000080 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE15__VALUE_REGISTER___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_SR_BA_LOW___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS14___POR 0x00000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_HOST_IS__DST_RING_LOW_WATERMARK___M 0x00000010 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS17___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_PMM_SR_MSB__STATUS___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE16___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE5_MISC_IS__AXI_TIMEOUT_ERR___S 10 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IE__DST_RING_HIGH_WATERMARK___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_WCSSAON_SR_LSB___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE11_MISC_IS__AXI_TIMEOUT_ERR___S 10 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE9__VALUE_REGISTER___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_APPS_CE_INTR_ENABLES_CLEAR___M 0x00000FFF +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS11___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CE_CMD__SRC_FLUSH___M 0x00000002 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS5___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS20 (0x00030070) +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_SRC_WATERMARK___POR 0x00000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_DST_WR_INDEX___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE12 (0x00032030) +#define ADRASTEA_A_WCSS_SR_APSS_SR_CONTROL__CLOCK_GATE_DISABLE___M 0x00000002 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_APPS_CE_INTR_ENABLES_SET__CE_INTR_LINE_HOST_P___POR 0x000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_QDSP_ERROR_INTR_ENABLES_SET__EXTERNAL_INTR___S 18 +#define ADRASTEA_A_WCSS_SR_APSS_SR_TESTBUS__SELECT___POR 0x0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IS___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE9__VALUE_REGISTER___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_DST_WR_INDEX__DST_WR_INDEX___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE7_MISC_IS__AXI_TIMEOUT_ERR___M 0x00000400 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_APPS_CE_INTR_ENABLES___M 0x00000FFF +#define ADRASTEA_A_WCSS_SR_APSS_WCSSAON_SR_LSB (0x00032070) +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_CLEAR__WLAN2_HW2SW_GRANT___M 0x00000080 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE12__VALUE_REGISTER___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IE__AXI_TIMEOUT_ERR___S 10 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE21__VALUE_REGISTER___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS22__ADDRESS_REGISTER___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE9_SR_BA_LOW___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE1___POR 0x00000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_SR_BA_LOW__BASE_ADDR_LOW___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE10_SR_BA_LOW___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE2_MISC_IS__AXI_BUS_ERR___M 0x00000200 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS6__ADDRESS_REGISTER___M 0x003FFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IS__DST_RING_OVERFLOW___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_CLEAR__WLAN2_HW2SW_GRANT___POR 0x0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_APPS_CE_INTR_ENABLES_CLEAR__CE_INTR_LINE_HOST_P___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE8_SR_BA_LOW___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_STATUS__PMM_SR_XO_SETTLE_TIMEOUT___S 9 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_HOST_IE__COPY_COMPLETE___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE6_MISC_IS__AXI_BUS_ERR___S 9 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS21___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE10___RWC QCSR_REG_RW +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_DR_BA_HIGH__BASE_ADDR_HIGH___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE9___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE4__VALUE_REGISTER___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_SR_SIZE__SIZE___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_SRC_WR_INDEX___M 0x0000FFFF +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE2__VALUE_REGISTER___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS6___M 0x003FFFFF +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS14__ADDRESS_REGISTER___POR 0x000000 +#define ADRASTEA_A_WCSS_SR_APSS_INVALID_ADDR_ACCESS___RWC QCSR_REG_RO +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE1_SR_BA_LOW__BASE_ADDR_LOW___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE6__VALUE_REGISTER___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_SR_BA_HIGH___POR 0x00000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE11_SR_BA_LOW___POR 0x00000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_HOST_IE__DST_RING_HIGH_WATERMARK___M 0x00000008 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE15__VALUE_REGISTER___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS16___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE3__VALUE_REGISTER___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE18__VALUE_REGISTER___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_FORCE_WAKE___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE17___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_DR_BA_HIGH___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS5__ADDRESS_REGISTER___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_HOST_IS___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CURRENT_SRRI___RWC QCSR_REG_RO +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE13 (0x00032034) +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE3___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS3 (0x0003002C) +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS3__ADDRESS_REGISTER___M 0x003FFFFF +#define ADRASTEA_A_WCSS_SR_APSS_INVALID_ADDR_ACCESS___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_ADDRESS_VALID (0x000300E0) +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE22 (0x00032058) +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS4___RWC QCSR_REG_RO +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE0___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE11___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IE__SRC_RING_OVERFLOW___M 0x00000020 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS22__ADDRESS_REGISTER___M 0x003FFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CE_CTRL1__MSI_EN___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_PMM_SR_MSB___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE19___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE15___POR 0x00000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE8_SR_BA_LOW___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_CLEAR__VALUE_REG_UPDATED_WITH_INVALID_ADDR___M 0x00000020 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS23___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_APPS_CE_INTR_ENABLES_CLEAR___POR 0x00000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_SR_SIZE__SIZE___M 0x0000FFFF +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_STATUS__VALUE_REG_UPDATED_WITH_INVALID_ADDR___POR 0x0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CE_CTRL2___RWC QCSR_REG_RW +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE3_MISC_IS__AXI_BUS_ERR___S 9 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE2_SR_BA_LOW__BASE_ADDR_LOW___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS19___M 0x003FFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_HOST_IE__SRC_RING_LOW_WATERMARK___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS14 (0x00030058) +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS2___RWC QCSR_REG_RO +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_DR_BA_HIGH___M 0x0000007F +#define ADRASTEA_A_WCSS_SR_APSS_SR_CONTROL__CLOCK_GATE_DISABLE___POR 0x0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CE_CTRL1__IDX_UPD_EN___S 19 +#define ADRASTEA_A_WCSS_SR_APSS_PMM_SR_MSB__STATUS___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE0__VALUE_REGISTER___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_SR_BA_LOW___POR 0x00000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE2_SR_BA_LOW___RWC QCSR_REG_RW +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE1 (0x00032004) +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS8___M 0x003FFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE9_SR_BA_LOW___RWC QCSR_REG_RW +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IS__SRC_RING_OVERFLOW___S 5 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_SRC_WATERMARK__SR_HIGH_WATER_MARK_THRESHOLD___M 0x0000FFFF +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE23___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_QDSP_ERROR_INTR_ENABLES_SET__BMH_INT___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS18___M 0x003FFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE3_SR_BA_LOW___RWC QCSR_REG_RW +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS8__ADDRESS_REGISTER___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOWREG_STATUS__WCSS_CORE_WAKE_SLEEP_STATE___M 0x00000008 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS1___M 0x003FFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IE__SRC_RING_LOW_WATERMARK___M 0x00000004 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_ENABLE__DIRTY_BIT_SET_ENABLE___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE6_SR_BA_LOW__BASE_ADDR_LOW___POR 0x00000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_APPS_CE_INTR_ENABLES_SET__CE_INTR_LINE_HOST_P___M 0x00000FFF +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE14 (0x00032038) +#define ADRASTEA_A_WCSS_SR_APSS_SR_CONTROL__SR_RF_XO_MUX_SEL___M 0x00000010 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE8_MISC_IS__AXI_BUS_ERR___M 0x00000200 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IE___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS3___M 0x003FFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IE__COPY_COMPLETE___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS12___M 0x003FFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE_SECURE_WRAPPER_CE_WRAPPER_INTERRUPT_SUMMARY__MISC___M 0x00000FFF +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE21__VALUE_REGISTER___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE9_SR_BA_LOW__BASE_ADDR_LOW___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE17__VALUE_REGISTER___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_ENABLE__PMM_SR_XO_SETTLE_TIMEOUT___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS11___RWC QCSR_REG_RO +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_HOST_IE___RWC QCSR_REG_RW +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE1_MISC_IS__AXI_TIMEOUT_ERR___S 10 +#define ADRASTEA_A_WCSS_SR_APSS_COMMIT_REPLAY__ENABLE___M 0x00000001 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE7___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_SR_APSS_ADDRESS_VALID___RWC QCSR_REG_RO +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_QDSP_ERROR_INTR_ENABLES_SET__LCMH_STROBE_INTERRUPT___S 1 +#define ADRASTEA_A_WCSS_SR_APSS_WCSSAON_SR_MSB___POR 0x00000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE9_MISC_IS__AXI_TIMEOUT_ERR___S 10 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS12___RWC QCSR_REG_RO +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE10___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS9___POR 0x00000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_HOST_IE__DST_RING_LOW_WATERMARK___M 0x00000010 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS11___M 0x003FFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_HOST_IE___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE3_MISC_IS__AXI_TIMEOUT_ERR___M 0x00000400 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_HOST_IS__DST_RING_LOW_WATERMARK___S 4 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_HOST_IS___M 0x0000001F +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE23 (0x0003205C) +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IE (0x00240034) +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS12__ADDRESS_REGISTER___POR 0x000000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS1__ADDRESS_REGISTER___M 0x003FFFFF +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS16__ADDRESS_REGISTER___M 0x003FFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE_SECURE_WRAPPER_CE_WRAPPER_INTERRUPT_SUMMARY___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS17___RWC QCSR_REG_RO +#define ADRASTEA_A_WCSS_SR_APSS_PMM_SR_MSB___POR 0x00000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE_SECURE_WRAPPER_CE_WRAPPER_INTERRUPT_SUMMARY (0x0024D000) +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE5_SR_BA_LOW__BASE_ADDR_LOW___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS18___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS15 (0x0003005C) +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS10___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_QDSP_ERROR_INTR_ENABLES_SET__WLAN1_SLP_TMR_INTR___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_COMMIT_REPLAY___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_ENABLE___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE22___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS19___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CURRENT_SRRI__CURRENT_SRRI___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_HOST_IE (0x0024002C) +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE6_SR_BA_LOW__BASE_ADDR_LOW___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IE__DST_RING_LOW_WATERMARK___S 4 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE4_MISC_IS__AXI_BUS_ERR___M 0x00000200 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS1___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_CLEAR__PMM_SR_XO_SETTLE_TIMEOUT___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS2___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_CLEAR__WLAN2_HW2SW_GRANT___S 7 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE11__VALUE_REGISTER___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_SR_BA_HIGH___M 0x0000001F +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IS__DST_RING_HIGH_WATERMARK___POR 0x0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE1_MISC_IS__AXI_BUS_ERR___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_INVALID_ADDR_ACCESS__ADDRESS_BITS_17_TO_2___M 0x0000FFFF +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_STATUS__ECAHB_TIMEOUT___M 0x00000010 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IE__AXI_TIMEOUT_ERR___POR 0x0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE_SECURE_WRAPPER_CE_WRAPPER_INTERRUPT_SUMMARY___M 0x01FFFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_DR_BA_LOW___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IE__PARSER_INT___POR 0x000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IS__COPY_COMPLETE___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_INVALID_ADDR_ACCESS__ADDRESS_BITS_17_TO_2___POR 0x0000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE_SECURE_WRAPPER_CE_WRAPPER_INTERRUPT_SUMMARY__ILL_REG___S 24 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS6___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CURRENT_SRRI___POR 0x00000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE1_SR_BA_LOW___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IE__DST_RING_OVERFLOW___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS19___RWC QCSR_REG_RO +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE1_SR_BA_LOW__BASE_ADDR_LOW___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_APPS_CE_INTR_ENABLES_CLEAR___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE6_SR_BA_LOW___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_SR_APSS_SHADOWREG_STATUS__STATE___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE0 (0x00032000) +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS23__ADDRESS_REGISTER___M 0x003FFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_SRC_WATERMARK__SR_LOW_WATER_MARK_THRESOLD___M 0xFFFF0000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE2_SR_BA_LOW__BASE_ADDR_LOW___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE10__VALUE_REGISTER___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_CLEAR (0x00030014) +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS10__ADDRESS_REGISTER___M 0x003FFFFF +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE12___POR 0x00000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_QDSP_ERROR_INTR_ENABLES_SET__CE_INTR_MISC_P___M 0x00000080 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE11__VALUE_REGISTER___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE20 (0x00032050) +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_QDSP_ERROR_INTR_ENABLES_SET__LMH_INT___S 3 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CURRENT_DRRI__CURRENT_DRRI___M 0x0000FFFF +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_ENABLE__ERR_RESP_ENABLE___S 2 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE10_SR_BA_LOW__BASE_ADDR_LOW___POR 0x00000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_QDSP_ERROR_INTR_ENABLES_SET__WLAN2_SLP_TMR_INTR___M 0x00008000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS18___RWC QCSR_REG_RO +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE14__VALUE_REGISTER___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_SRC_WR_INDEX__SRC_WR_INDEX___POR 0x0000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE5_MISC_IS__AXI_BUS_ERR___M 0x00000200 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE7___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE7___RWC QCSR_REG_RW +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS23___POR 0x00000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE4_SR_BA_LOW___RWC QCSR_REG_RW +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CE_CTRL1__SRC_RING_BYTE_SWAP_EN___M 0x00020000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE11_SR_BA_LOW (0x0024B000) +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_APPS_CE_INTR_ENABLES_SET (0x002F1004) +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE2 (0x00032008) +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE7_SR_BA_LOW___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_DR_BA_HIGH__DESC_SKIP_DWORD___S 5 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_HOST_IE__SRC_RING_HIGH_WATERMARK___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_SR_TESTBUS___POR 0x00000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_DST_WATERMARK__DR_LOW_WATER_MARK_THRESHOLD___M 0xFFFF0000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE2___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_FORCE_WAKE__FORCE_WAKE_ENABLE___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_DR_BA_HIGH__BASE_ADDR_HIGH___POR 0x00 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE4_SR_BA_LOW___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_ENABLE__FORCE_WAKE_ENABLE___M 0x00000002 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS12___POR 0x00000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_APPS_CE_INTR_ENABLES___POR 0x00000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_QDSP_ERROR_INTR_ENABLES_SET__BMH_INT___M 0x00000001 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CE_CTRL2__DST_AXI_MAX_LEN___S 2 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_DR_BA_HIGH__DESC_SKIP_DWORD___M 0x00000060 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_SR_BA_LOW__BASE_ADDR_LOW___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_QDSP_ERROR_INTR_ENABLES_SET__SMH_INT___S 6 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE5_SR_BA_LOW___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_QDSP_ERROR_INTR_ENABLES_SET__EXTERNAL_INTR___M 0x0FFC0000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE7__VALUE_REGISTER___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE1__VALUE_REGISTER___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CURRENT_DRRI__CURRENT_DRRI___POR 0x0000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS3___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS17__ADDRESS_REGISTER___POR 0x000000 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_STATUS__INVALID_ADDR___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS17___M 0x003FFFFF +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_STATUS__WLAN1_HW2SW_GRANT___S 6 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_ENABLE__PMM_WCSS_WAKEUP_IRQ_ACK___S 8 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_SR_SIZE___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE5_SR_BA_LOW (0x00245000) +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_SRC_WR_INDEX___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_HOST_IS__SRC_RING_LOW_WATERMARK___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS22 (0x00030078) +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_QDSP_ERROR_INTR_ENABLES_SET__SMH_INT___M 0x00000040 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CE_CTRL2___POR 0x00000005 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS4__ADDRESS_REGISTER___POR 0x000000 +#define ADRASTEA_A_WCSS_SR_APSS_COMMIT_REPLAY___RWC QCSR_REG_RO +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CURRENT_DRRI___POR 0x00000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CE_CMD__HALT_STATUS___S 3 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_STATUS__DIRTY_BIT_SET___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE_SECURE_WRAPPER_CE_WRAPPER_INTERRUPT_SUMMARY__MISC___POR 0x000 +#define ADRASTEA_A_WCSS_SR_APSS_WCSSAON_SR_LSB___RWC QCSR_REG_RO +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_ENABLE__FORCE_WAKE_ENABLE___S 1 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IE__SRC_RING_OVERFLOW___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_INVALID_ADDR_ACCESS__ADDRESS_BITS_17_TO_2___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IE___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_CLEAR___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE6___RWC QCSR_REG_RW +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE11_SR_BA_LOW___RWC QCSR_REG_RW +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CURRENT_DRRI___RWC QCSR_REG_RO +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE8_SR_BA_LOW__BASE_ADDR_LOW___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS2___M 0x003FFFFF +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE11___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE7_SR_BA_LOW___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS6__ADDRESS_REGISTER___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE16__VALUE_REGISTER___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CE_CTRL2__DST_AXI_MAX_LEN___POR 0x1 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_SRC_WATERMARK (0x0024004C) +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_STATUS__ERR_RESP___M 0x00000004 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IE___RWC QCSR_REG_RW +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_STATUS__PMM_WCSS_WAKEUP_IRQ_ACK___M 0x00000100 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_QDSP_ERROR_INTR_ENABLES_SET__INVALID_BB_2_INTR___S 11 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE4___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IE__SRC_RING_LOW_WATERMARK___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS17 (0x00030064) +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE16___RWC QCSR_REG_RW +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE8__VALUE_REGISTER___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS19___POR 0x00000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_DR_BA_LOW (0x0024000C) +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_QDSP_ERROR_INTR_ENABLES_SET__INVALID_BB_1_INTR___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_ADDRESS_VALID__BITS___M 0x00FFFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_DR_BA_HIGH__DESC_SKIP_DWORD___POR 0x0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE10_SR_BA_LOW (0x0024A000) +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_ENABLE__WLAN1_HW2SW_GRANT___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS15___M 0x003FFFFF +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_CLEAR__INVALID_ADDR___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE12___RWC QCSR_REG_RW +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_SRC_WATERMARK___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_QDSP_ERROR_INTR_ENABLES_SET__MCIM_INT___S 4 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE13__VALUE_REGISTER___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_DST_WATERMARK___RWC QCSR_REG_RW +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE4_SR_BA_LOW__BASE_ADDR_LOW___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE7_SR_BA_LOW__BASE_ADDR_LOW___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE19__VALUE_REGISTER___POR 0x00000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CE_CTRL2__SRC_AXI_MAX_LEN___M 0x00000003 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS8__ADDRESS_REGISTER___M 0x003FFFFF +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE10__VALUE_REGISTER___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE8__VALUE_REGISTER___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS5___POR 0x00000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IE__DST_RING_OVERFLOW___M 0x00000040 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_CLEAR__PMM_WCSS_WAKEUP_IRQ_ACK___M 0x00000100 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE12___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_DST_WATERMARK___POR 0x00000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IS__AXI_TIMEOUT_ERR___POR 0x0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE10_SR_BA_LOW___RWC QCSR_REG_RW +#define ADRASTEA_A_WCSS_SR_APSS_SHADOWREG_STATUS (0x00030008) +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE9_SR_BA_LOW___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_SR_CONTROL__SR_PLL_REF_MUX_SEL___S 3 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS8__ADDRESS_REGISTER___POR 0x000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CE_CTRL1__MSI_EN___M 0x00010000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS22___M 0x003FFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IE__PARSER_INT___M 0x000FF800 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IE__SRC_LEN_ERR___S 8 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_ENABLE__ECAHB_TIMEOUT___M 0x00000010 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS16___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS1___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE19 (0x0003204C) +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_HOST_IE__DST_RING_HIGH_WATERMARK___S 3 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IS__AXI_TIMEOUT_ERR___S 10 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE3_MISC_IS__AXI_TIMEOUT_ERR___S 10 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS5 (0x00030034) +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IS__SRC_RING_OVERFLOW___M 0x00000020 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_APPS_CE_INTR_ENABLES_CLEAR__CE_INTR_LINE_HOST_P___M 0x00000FFF +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS22___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SW_SCRATCH___RWC QCSR_REG_RW +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE_SECURE_WRAPPER_CE_WRAPPER_INTERRUPT_SUMMARY__HOST___M 0x00FFF000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE3_MISC_IS__AXI_TIMEOUT_ERR___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE8___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_SR_APSS_SR_CONTROL__SR_RF_XO_MUX_SEL___S 4 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CE_CTRL1__MSI_EN___S 16 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE13___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_ENABLE__VALUE_REG_UPDATED_WITH_INVALID_ADDR___POR 0x0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IE___M 0x000FFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IS__PARSER_INT___M 0x000FF800 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE18__VALUE_REGISTER___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_SRC_WATERMARK__SR_HIGH_WATER_MARK_THRESHOLD___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_DR_BA_LOW__BASE_ADDR_LOW___POR 0x00000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IS___RWC QCSR_REG_RW +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE23___RWC QCSR_REG_RW +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_QDSP_ERROR_INTR_ENABLES_SET__WFSS_DBG_INTR___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE0__VALUE_REGISTER___POR 0x00000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE6_SR_BA_LOW___RWC QCSR_REG_RW +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_DR_SIZE__SIZE___M 0x0000FFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CURRENT_DRRI___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_QDSP_ERROR_INTR_ENABLES_SET__SW_SLP_TMR_INTR___M 0x00010000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_DST_WATERMARK__DR_HIGH_WATER_MARK_THRESHOLD___POR 0x0000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_APPS_CE_INTR_ENABLES___RWC QCSR_REG_RO +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS13___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_SR_SIZE___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE3___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_CLEAR__PMM_WCSS_WAKEUP_IRQ_ACK___S 8 +#define ADRASTEA_A_WCSS_SR_APSS_WCSSAON_SR_LSB__STATUS___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IS__DST_MAX_LEN_VIO___M 0x00000080 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE_COMMON_WRAPPER_CE_WRAPPER_HOST_INTERRUPT_SUMMARY___RWC QCSR_REG_RO +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS13__ADDRESS_REGISTER___M 0x003FFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_DR_SIZE__SIZE___POR 0x0000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS10___M 0x003FFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_HOST_IS___RWC QCSR_REG_RW +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE5 (0x00032014) +#define ADRASTEA_A_WCSS_SR_APSS_SR_TESTBUS___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE12__VALUE_REGISTER___POR 0x00000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE4_MISC_IS__AXI_TIMEOUT_ERR___S 10 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CE_CTRL1___RWC QCSR_REG_RW +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_STATUS (0x0003000C) +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE11_MISC_IS__AXI_BUS_ERR___POR 0x0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE9_MISC_IS__AXI_BUS_ERR___M 0x00000200 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_QDSP_ERROR_INTR_ENABLES_SET___RWC QCSR_REG_RW +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_CLEAR__DIRTY_BIT_SET_CLEAR___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS7___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_CLEAR___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_DR_BA_HIGH__BASE_ADDR_HIGH___M 0x0000001F +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS0___POR 0x00000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE4_SR_BA_LOW___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CE_CMD__SRC_FLUSH___POR 0x0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_DST_WATERMARK__DR_LOW_WATER_MARK_THRESHOLD___S 16 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE5_MISC_IS__AXI_TIMEOUT_ERR___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE9 (0x00032024) +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IS__COPY_COMPLETE___M 0x00000001 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CE_CMD___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_INVALID_ADDR_ACCESS__WRITE_ACCESS___POR 0x0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_HOST_IE___M 0x0000001F +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS23___RWC QCSR_REG_RO +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_HOST_IE__COPY_COMPLETE___M 0x00000001 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE21__VALUE_REGISTER___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IE__PARSER_INT___S 11 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS21__ADDRESS_REGISTER___M 0x003FFFFF +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS20__ADDRESS_REGISTER___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_DST_WR_INDEX___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE_SECURE_WRAPPER_CE_WRAPPER_INTERRUPT_SUMMARY__HOST___POR 0x000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IE__DST_RING_OVERFLOW___S 6 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE13___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE7_SR_BA_LOW__BASE_ADDR_LOW___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_QDSP_ERROR_INTR_ENABLES_SET__WLAN1_SLP_TMR_INTR___M 0x00004000 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_CLEAR__ERR_RESP_CLEAR___M 0x00000004 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE15___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE3_SR_BA_LOW___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_QDSP_ERROR_INTR_ENABLES_SET___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOWREG_STATUS___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_INVALID_ADDR_ACCESS__WRITE_ACCESS___M 0x00020000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE1_SR_BA_LOW___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_SR_BA_HIGH___RWC QCSR_REG_RW +#define ADRASTEA_A_WCSS_SR_APSS_ADDRESS_VALID___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_CLEAR__VALUE_REG_UPDATED_WITH_INVALID_ADDR___S 5 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CE_CTRL1__DEST_MAX_LENGTH___M 0x0000FFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE4_MISC_IS__AXI_TIMEOUT_ERR___M 0x00000400 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CE_CMD__HALT_STATUS___M 0x00000008 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_QDSP_ERROR_INTR_ENABLES_SET__LCMH_WCI2_INTERRUPT___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS2__ADDRESS_REGISTER___POR 0x000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_HOST_IS__DST_RING_HIGH_WATERMARK___M 0x00000008 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE1_SR_BA_LOW___RWC QCSR_REG_RW +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CE_CTRL1___POR 0x00000080 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE19__VALUE_REGISTER___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS7__ADDRESS_REGISTER___M 0x003FFFFF +#define ADRASTEA_A_WCSS_SR_APSS_DIRTY___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_CLEAR__DIRTY_BIT_SET_CLEAR___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_CLEAR__PMM_SR_XO_SETTLE_TIMEOUT___S 9 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE18 (0x00032048) +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_QDSP_ERROR_INTR_ENABLES_SET__NOC_WCMN_INTR___M 0x00001000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS21___RWC QCSR_REG_RO +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS10__ADDRESS_REGISTER___POR 0x000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_DST_WATERMARK (0x00240050) +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE4_MISC_IS__AXI_BUS_ERR___S 9 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE4_SR_BA_LOW___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_STATUS__DIRTY_BIT_SET___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_WCSSAON_SR_LSB__STATUS___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_ENABLE__DIRTY_BIT_SET_ENABLE___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS14___RWC QCSR_REG_RO +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CE_CTRL1__IDX_UPD_EN___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_CLEAR__WLAN1_HW2SW_GRANT___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS12__ADDRESS_REGISTER___M 0x003FFFFF +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS20___M 0x003FFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE3_SR_BA_LOW (0x00243000) +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_SR_SIZE__START_OFFSET___S 16 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS5___M 0x003FFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_SR_SIZE___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS9__ADDRESS_REGISTER___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE16__VALUE_REGISTER___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE9__VALUE_REGISTER___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_DIRTY (0x00030080) +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IE__AXI_TIMEOUT_ERR___M 0x00000400 +#define ADRASTEA_A_WCSS_SR_APSS_PMM_SR_LSB___POR 0x00000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE8_SR_BA_LOW (0x00248000) +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS6___RWC QCSR_REG_RO +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS21___M 0x003FFFFF +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE21___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS15__ADDRESS_REGISTER___POR 0x000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_APPS_CE_INTR_ENABLES_SET___RWC QCSR_REG_RW +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_HOST_IS__SRC_RING_LOW_WATERMARK___S 2 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS3___RWC QCSR_REG_RO +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE16 (0x00032040) +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_HOST_IE__DST_RING_HIGH_WATERMARK___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS18__ADDRESS_REGISTER___POR 0x000000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOWREG_STATUS___M 0x0000000F +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_HOST_IS__DST_RING_HIGH_WATERMARK___POR 0x0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_DR_BA_LOW__BASE_ADDR_LOW___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE8_MISC_IS__AXI_TIMEOUT_ERR___M 0x00000400 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE2___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_DR_SIZE__START_OFFSET___S 16 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS14___M 0x003FFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE_COMMON_WRAPPER_CE_WRAPPER_HOST_INTERRUPT_SUMMARY (0x0024C000) +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS6___POR 0x00000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE10_SR_BA_LOW___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE2_SR_BA_LOW___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_ENABLE__WLAN2_HW2SW_GRANT___POR 0x0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_HOST_IS__COPY_COMPLETE___POR 0x0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_QDSP_ERROR_INTR_ENABLES_SET__INVALID_BB_2_INTR___M 0x00000800 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CE_CTRL1__DST_RING_BYTE_SWAP_EN___S 18 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE0___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_SR_APSS_INVALID_ADDR_ACCESS (0x00032078) +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE13__VALUE_REGISTER___POR 0x00000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE6_SR_BA_LOW___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_DR_BA_LOW___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_WCSSAON_SR_MSB__STATUS___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SW_SCRATCH__SPARE_REGISTER___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS15___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS21___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_ADDRESS_VALID__BITS___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS7___RWC QCSR_REG_RO +#define ADRASTEA_A_WCSS_SR_APSS_SR_TESTBUS__SELECT___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS23__ADDRESS_REGISTER___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IS__SRC_RING_LOW_WATERMARK___S 2 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS21__ADDRESS_REGISTER___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_QDSP_ERROR_INTR_ENABLES_SET__LMH_INT___M 0x00000008 +#define ADRASTEA_A_WCSS_SR_APSS_ADDRESS_VALID___POR 0x00000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE2_SR_BA_LOW___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_PMM_SR_LSB__STATUS___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE18___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_DR_BA_LOW__BASE_ADDR_LOW___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS8___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS12 (0x00030050) +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE9_MISC_IS__AXI_BUS_ERR___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_SR_TESTBUS__SELECT___M 0x00000007 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS23___M 0x003FFFFF +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS20___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_QDSP_ERROR_INTR_ENABLES_SET__PMH_INT___M 0x00000020 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE11_SR_BA_LOW___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE20__VALUE_REGISTER___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_WCSSAON_SR_MSB___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SR_CONTROL__ENABLE_APSS_FULL_ACCESS___M 0x00000004 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_QDSP_ERROR_INTR_ENABLES_SET__WLAN1_SLP_TMR_INTR___S 14 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_HOST_IS__SRC_RING_LOW_WATERMARK___M 0x00000004 +#define ADRASTEA_A_WCSS_SR_APSS_WCSSAON_SR_MSB___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CE_CTRL1__DST_RING_BYTE_SWAP_EN___M 0x00040000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS10___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS13__ADDRESS_REGISTER___POR 0x000000 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_STATUS__PMM_WCSS_WAKEUP_IRQ_ACK___S 8 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE9_SR_BA_LOW__BASE_ADDR_LOW___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IE__SRC_LEN_ERR___M 0x00000100 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE13___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_COMMIT_REPLAY__ENABLE___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS7 (0x0003003C) +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CURRENT_DRRI__CURRENT_DRRI___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_DST_WATERMARK___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SW_SCRATCH__SPARE_REGISTER___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE8__VALUE_REGISTER___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_FORCE_WAKE___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IE__DST_MAX_LEN_VIO___POR 0x0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_QDSP_ERROR_INTR_ENABLES_SET (0x002F0084) +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_APPS_CE_INTR_ENABLES_SET__CE_INTR_LINE_HOST_P___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_DST_WATERMARK__DR_HIGH_WATER_MARK_THRESHOLD___M 0x0000FFFF +#define ADRASTEA_A_WCSS_SR_APSS_INVALID_ADDR_ACCESS__READ_ACCESS___POR 0x0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_SR_SIZE__SIZE___POR 0x0000 +#define ADRASTEA_A_WCSS_SR_APSS_SR_CONTROL__ENABLE_APSS_FULL_ACCESS___S 2 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_APPS_CE_INTR_ENABLES__CE_INTR_LINE_HOST_P___POR 0x000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE9_MISC_IS__AXI_TIMEOUT_ERR___POR 0x0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE6_MISC_IS__AXI_TIMEOUT_ERR___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_COMMIT_REPLAY__ENABLE___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_STATUS___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS8 (0x00030040) +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS0___RWC QCSR_REG_RO +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_HOST_IS (0x00240030) +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IE__DST_RING_LOW_WATERMARK___M 0x00000010 +#define ADRASTEA_A_WCSS_SR_APSS_SR_CONTROL__SOFT_RESET___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS22___RWC QCSR_REG_RO +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS15__ADDRESS_REGISTER___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS22__ADDRESS_REGISTER___POR 0x000000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE23___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE15 (0x0003203C) +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS2___POR 0x00000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IS__SRC_RING_HIGH_WATERMARK___M 0x00000002 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IE__COPY_COMPLETE___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_SR_BA_HIGH (0x00240004) +#define ADRASTEA_A_WCSS_SR_APSS_SHADOWREG_STATUS__STATE___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE8___RWC QCSR_REG_RW +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS11__ADDRESS_REGISTER___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_INVALID_ADDR_ACCESS__WRITE_ACCESS___S 17 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE0___POR 0x00000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_APPS_CE_INTR_ENABLES_SET___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_COMMIT_REPLAY___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE5_SR_BA_LOW___RWC QCSR_REG_RW +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IS__DST_RING_OVERFLOW___S 6 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS8___RWC QCSR_REG_RO +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_ENABLE__PMM_SR_XO_SETTLE_TIMEOUT___M 0x00000200 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_STATUS__ECAHB_TIMEOUT___S 4 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE15__VALUE_REGISTER___POR 0x00000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CE_CTRL1__DEST_MAX_LENGTH___POR 0x0080 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_DST_WATERMARK__DR_LOW_WATER_MARK_THRESHOLD___POR 0x0000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE10___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE9___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_STATUS__PMM_SR_XO_SETTLE_TIMEOUT___M 0x00000200 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_STATUS__WLAN1_HW2SW_GRANT___POR 0x0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IS__DST_RING_HIGH_WATERMARK___S 3 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE10_SR_BA_LOW__BASE_ADDR_LOW___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE22___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE7___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE5_MISC_IS__AXI_TIMEOUT_ERR___M 0x00000400 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_HOST_IS__DST_RING_HIGH_WATERMARK___S 3 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE8_MISC_IS__AXI_TIMEOUT_ERR___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE13___RWC QCSR_REG_RW +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_CLEAR__PMM_WCSS_WAKEUP_IRQ_ACK___POR 0x0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_SR_BA_LOW (0x00240000) +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS5__ADDRESS_REGISTER___POR 0x000000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS16__ADDRESS_REGISTER___POR 0x000000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE16___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS13 (0x00030054) +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_QDSP_ERROR_INTR_ENABLES_SET__WLAN2_SLP_TMR_INTR___S 15 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_DR_BA_HIGH (0x00240010) +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE4__VALUE_REGISTER___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS12___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE11___POR 0x00000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IS__PARSER_INT___S 11 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_CLEAR__ERR_RESP_CLEAR___S 2 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE20___RWC QCSR_REG_RW +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE4 (0x00032010) +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS14__ADDRESS_REGISTER___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_HOST_IS___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS10__ADDRESS_REGISTER___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_COMMIT_REPLAY___M 0x00000001 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS4___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS1__ADDRESS_REGISTER___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS5___RWC QCSR_REG_RO +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_ENABLE__PMM_WCSS_WAKEUP_IRQ_ACK___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_PMM_SR_LSB___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE8_MISC_IS__AXI_TIMEOUT_ERR___S 10 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE11___RWC QCSR_REG_RW +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_ENABLE___RWC QCSR_REG_RO +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_QDSP_ERROR_INTR_ENABLES_SET__SW_SLP_TMR_INTR___POR 0x0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IE__AXI_ERR___POR 0x0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE7_MISC_IS__AXI_TIMEOUT_ERR___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS23__ADDRESS_REGISTER___POR 0x000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IS__DST_MAX_LEN_VIO___S 7 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_HOST_IE__DST_RING_LOW_WATERMARK___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS3__ADDRESS_REGISTER___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IE__DST_MAX_LEN_VIO___S 7 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS0__ADDRESS_REGISTER___M 0x003FFFFF +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE1___RWC QCSR_REG_RW +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_HOST_IE___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS7__ADDRESS_REGISTER___POR 0x000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE6_SR_BA_LOW (0x00246000) +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_APPS_CE_INTR_ENABLES___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CE_CTRL1__DST_RING_BYTE_SWAP_EN___POR 0x0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_QDSP_ERROR_INTR_ENABLES_SET__INVALID_BB_2_INTR___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE7__VALUE_REGISTER___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE13__VALUE_REGISTER___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_STATUS__PMM_WCSS_WAKEUP_IRQ_ACK___POR 0x0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE_COMMON_WRAPPER_CE_WRAPPER_HOST_INTERRUPT_SUMMARY__HOST___POR 0x000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_QDSP_ERROR_INTR_ENABLES_SET__NOC_WCMN_INTR___S 12 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IS__PARSER_INT___POR 0x000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE1___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CE_CMD__DST_FLUSH___M 0x00000004 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE18___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE10_MISC_IS__AXI_TIMEOUT_ERR___POR 0x0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE8_SR_BA_LOW__BASE_ADDR_LOW___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_SR_APSS_SW_SCRATCH___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS23 (0x0003007C) +#define ADRASTEA_A_WCSS_SR_APSS_SR_CONTROL___M 0x0000001F +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE3_SR_BA_LOW__BASE_ADDR_LOW___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_SRC_WATERMARK___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IS__DST_RING_OVERFLOW___M 0x00000040 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE6__VALUE_REGISTER___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS1__ADDRESS_REGISTER___POR 0x000000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS9___M 0x003FFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_QDSP_ERROR_INTR_ENABLES_SET__SMH_INT___POR 0x0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE10_MISC_IS__AXI_BUS_ERR___S 9 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_QDSP_ERROR_INTR_ENABLES_SET__SW_SLP_TMR_INTR___S 16 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE14__VALUE_REGISTER___POR 0x00000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE_COMMON_WRAPPER_CE_WRAPPER_HOST_INTERRUPT_SUMMARY__HOST___S 12 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE2_MISC_IS__AXI_TIMEOUT_ERR___M 0x00000400 +#define ADRASTEA_A_WCSS_SR_APSS_PMM_SR_LSB___RWC QCSR_REG_RO +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_SR_BA_HIGH__BASE_ADDR_HIGH___POR 0x00 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IS__SRC_LEN_ERR___M 0x00000100 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_CLEAR__VALUE_REG_UPDATED_WITH_INVALID_ADDR___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_FORCE_WAKE___RWC QCSR_REG_RW +#define ADRASTEA_A_WCSS_SR_APSS_SW_SCRATCH__SPARE_REGISTER___POR 0x00000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_HOST_IS__SRC_RING_HIGH_WATERMARK___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS4__ADDRESS_REGISTER___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_FORCE_WAKE__FORCE_WAKE_ENABLE___POR 0x0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_SRC_WR_INDEX__SRC_WR_INDEX___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE5_MISC_IS__AXI_BUS_ERR___S 9 +#define ADRASTEA_A_WCSS_SR_APSS_WCSSAON_SR_MSB__STATUS___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_ENABLE__ERR_RESP_ENABLE___POR 0x0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CURRENT_DRRI___M 0x0000FFFF +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE8___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE20___POR 0x00000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_DR_BA_HIGH___RWC QCSR_REG_RW +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE_SECURE_WRAPPER_CE_WRAPPER_INTERRUPT_SUMMARY__ILL_REG___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE12___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CE_CTRL2__SRC_AXI_MAX_LEN___POR 0x1 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CE_CTRL1 (0x00240018) +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE7_SR_BA_LOW__BASE_ADDR_LOW___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE0___RWC QCSR_REG_RW +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS19 (0x0003006C) +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_SRC_WR_INDEX (0x0024003C) +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE20___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS20__ADDRESS_REGISTER___M 0x003FFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CE_CMD___M 0x0000000F +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS18__ADDRESS_REGISTER___M 0x003FFFFF +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_ENABLE__VALUE_REG_UPDATED_WITH_INVALID_ADDR___S 5 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE1__VALUE_REGISTER___POR 0x00000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE10_MISC_IS__AXI_TIMEOUT_ERR___M 0x00000400 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CURRENT_SRRI__CURRENT_SRRI___POR 0x0000 +#define ADRASTEA_A_WCSS_SR_APSS_SR_CONTROL__SR_RF_XO_MUX_SEL___POR 0x0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CE_CTRL2___M 0x0000000F +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE2__VALUE_REGISTER___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_ENABLE__INVALID_ADDR___M 0x00000008 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE22__VALUE_REGISTER___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS16__ADDRESS_REGISTER___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE3__VALUE_REGISTER___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_QDSP_ERROR_INTR_ENABLES_SET___M 0x0FFFDDFF +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE7 (0x0003201C) +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_HOST_IE__SRC_RING_LOW_WATERMARK___M 0x00000004 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_ENABLE__INVALID_ADDR___S 3 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CE_CTRL2__DST_AXI_MAX_LEN___M 0x0000000C +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE5_MISC_IS__AXI_BUS_ERR___POR 0x0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE11_MISC_IS__AXI_TIMEOUT_ERR___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS0__ADDRESS_REGISTER___POR 0x000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE11_MISC_IS__AXI_BUS_ERR___M 0x00000200 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_SRC_WR_INDEX___POR 0x00000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE_SECURE_WRAPPER_CE_WRAPPER_INTERRUPT_SUMMARY__MISC___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE15___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IS__COPY_COMPLETE___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_SRC_WATERMARK__SR_HIGH_WATER_MARK_THRESHOLD___POR 0x0000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS2__ADDRESS_REGISTER___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS17__ADDRESS_REGISTER___M 0x003FFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IS__AXI_TIMEOUT_ERR___M 0x00000400 +#define ADRASTEA_A_WCSS_SR_APSS_SR_CONTROL__CLOCK_GATE_DISABLE___S 1 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE_SECURE_WRAPPER_CE_WRAPPER_INTERRUPT_SUMMARY___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_CLEAR__DIRTY_BIT_SET_CLEAR___M 0x00000001 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_ENABLE__ECAHB_TIMEOUT___POR 0x0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE6_MISC_IS__AXI_BUS_ERR___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE6__VALUE_REGISTER___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_STATUS___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_STATUS__FORCE_WAKE___S 1 +#define ADRASTEA_A_WCSS_SR_APSS_PMM_SR_MSB__STATUS___POR 0x00000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_SRC_WATERMARK___RWC QCSR_REG_RW +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IS__AXI_BUS_ERR___M 0x00000200 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS0___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_ENABLE__PMM_SR_XO_SETTLE_TIMEOUT___S 9 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_STATUS__VALUE_REG_UPDATED_WITH_INVALID_ADDR___S 5 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE3___RWC QCSR_REG_RW +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS18___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_WCSSAON_SR_MSB__STATUS___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_ENABLE__VALUE_REG_UPDATED_WITH_INVALID_ADDR___M 0x00000020 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE11_SR_BA_LOW__BASE_ADDR_LOW___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_QDSP_ERROR_INTR_ENABLES_SET__CE_INTR_MISC_P___S 7 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IS__SRC_RING_OVERFLOW___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_CLEAR__INVALID_ADDR___S 3 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE1_MISC_IS__AXI_TIMEOUT_ERR___POR 0x0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_DST_WR_INDEX__DST_WR_INDEX___M 0x0000FFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_QDSP_ERROR_INTR_ENABLES_SET__LCMH_STROBE_INTERRUPT___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_CLEAR___RWC QCSR_REG_WO +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_STATUS__PMM_SR_XO_SETTLE_TIMEOUT___POR 0x0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_APPS_CE_INTR_ENABLES__CE_INTR_LINE_HOST_P___M 0x00000FFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_SRC_WATERMARK__SR_LOW_WATER_MARK_THRESOLD___S 16 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS20___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_STATUS__FORCE_WAKE___M 0x00000002 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS16 (0x00030060) +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE4___RWC QCSR_REG_RW +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE2___RWC QCSR_REG_RW +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE3_SR_BA_LOW__BASE_ADDR_LOW___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_SR_TESTBUS (0x00030144) +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE1_SR_BA_LOW___POR 0x00000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_DST_WATERMARK___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_SR_SIZE__START_OFFSET___POR 0x0000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS5__ADDRESS_REGISTER___M 0x003FFFFF +#define ADRASTEA_A_WCSS_SR_APSS_SR_CONTROL__SR_PLL_REF_MUX_SEL___M 0x00000008 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS13___RWC QCSR_REG_RO +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_SR_BA_HIGH___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE17 (0x00032044) +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_SRC_WR_INDEX___RWC QCSR_REG_RW +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_STATUS___M 0x000003FF +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE3__VALUE_REGISTER___POR 0x00000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_QDSP_ERROR_INTR_ENABLES_SET__WFSS_DBG_INTR___M 0x00020000 +#define ADRASTEA_A_WCSS_SR_APSS_WCSSAON_SR_LSB__STATUS___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_SR_CONTROL__ENABLE_APSS_FULL_ACCESS___POR 0x0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_HOST_IS__SRC_RING_HIGH_WATERMARK___M 0x00000002 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE5___POR 0x00000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_SR_SIZE__START_OFFSET___M 0xFFFF0000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE17___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CE_CMD__HALT___POR 0x0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_HOST_IE__SRC_RING_HIGH_WATERMARK___S 1 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE1_MISC_IS__AXI_BUS_ERR___M 0x00000200 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_QDSP_ERROR_INTR_ENABLES_SET__CE_INTR_TIMEOUT_P___S 8 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_HOST_IS__COPY_COMPLETE___M 0x00000001 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_DR_SIZE__START_OFFSET___POR 0x0000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IS___POR 0x00000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE6_MISC_IS__AXI_TIMEOUT_ERR___M 0x00000400 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IS___M 0x000FFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE10_SR_BA_LOW___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE1___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IS__SRC_RING_HIGH_WATERMARK___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_ENABLE__ECAHB_TIMEOUT___S 4 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CE_CTRL1___M 0x000FFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE2_MISC_IS__AXI_TIMEOUT_ERR___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS17__ADDRESS_REGISTER___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS14__ADDRESS_REGISTER___M 0x003FFFFF +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_ENABLE__FORCE_WAKE_ENABLE___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_PMM_SR_LSB__STATUS___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE_SECURE_WRAPPER_CE_WRAPPER_INTERRUPT_SUMMARY___RWC QCSR_REG_RO +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE9_SR_BA_LOW__BASE_ADDR_LOW___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_CLEAR__INVALID_ADDR___M 0x00000008 +#define ADRASTEA_A_WCSS_SR_APSS_PMM_SR_MSB___RWC QCSR_REG_RO +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS18__ADDRESS_REGISTER___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SR_TESTBUS___M 0x00000007 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS17___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_ENABLE__WLAN1_HW2SW_GRANT___S 6 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IS__AXI_BUS_ERR___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS19__ADDRESS_REGISTER___POR 0x000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IS__SRC_RING_HIGH_WATERMARK___S 1 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE2_SR_BA_LOW (0x00242000) +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CE_CTRL2___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS7___M 0x003FFFFF +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_ENABLE__WLAN2_HW2SW_GRANT___S 7 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS9___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IS__DST_RING_LOW_WATERMARK___S 4 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS9__ADDRESS_REGISTER___M 0x003FFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CE_CTRL1__DEST_MAX_LENGTH___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_ENABLE (0x00030010) +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_CLEAR__FORCE_WAKE_CLEAR___M 0x00000002 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE16___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE19___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE8 (0x00032020) +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE8_SR_BA_LOW___RWC QCSR_REG_RW +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE8_SR_BA_LOW___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE4___POR 0x00000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_APPS_CE_INTR_ENABLES_SET___M 0x00000FFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE6_SR_BA_LOW___POR 0x00000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_SR_SIZE___RWC QCSR_REG_RW +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE10_MISC_IS__AXI_BUS_ERR___POR 0x0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CE_CMD___RWC QCSR_REG_RW +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS11__ADDRESS_REGISTER___M 0x003FFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CE_CTRL1__IDX_UPD_EN___M 0x00080000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS19__ADDRESS_REGISTER___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE7_MISC_IS__AXI_BUS_ERR___S 9 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE11__VALUE_REGISTER___POR 0x00000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_QDSP_ERROR_INTR_ENABLES_SET__BMH_INT___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE7__VALUE_REGISTER___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_SR_CONTROL__SOFT_RESET___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS9__ADDRESS_REGISTER___POR 0x000000 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_CLEAR__WLAN1_HW2SW_GRANT___S 6 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS0 (0x00030020) +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_QDSP_ERROR_INTR_ENABLES_SET__PMH_INT___S 5 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_DST_WR_INDEX___RWC QCSR_REG_RW +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE9___RWC QCSR_REG_RW +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE_COMMON_WRAPPER_CE_WRAPPER_HOST_INTERRUPT_SUMMARY__HOST___M 0x00FFF000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE3_SR_BA_LOW___POR 0x00000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_DR_BA_LOW___RWC QCSR_REG_RW +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_DST_WR_INDEX__DST_WR_INDEX___POR 0x0000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_DST_WATERMARK__DR_HIGH_WATER_MARK_THRESHOLD___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE5_SR_BA_LOW___POR 0x00000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE_SECURE_WRAPPER_CE_WRAPPER_INTERRUPT_SUMMARY__ILL_REG___M 0x01000000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE5___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE21___RWC QCSR_REG_RW +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_HOST_IS__DST_RING_LOW_WATERMARK___POR 0x0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_QDSP_ERROR_INTR_ENABLES_SET__WLAN2_SLP_TMR_INTR___POR 0x0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CE_CMD___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE1__VALUE_REGISTER___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS11 (0x0003004C) +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_QDSP_ERROR_INTR_ENABLES_SET__PMH_INT___POR 0x0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE4_SR_BA_LOW__BASE_ADDR_LOW___POR 0x00000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE8_SR_BA_LOW__BASE_ADDR_LOW___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_QDSP_ERROR_INTR_ENABLES_SET__INVALID_BB_1_INTR___M 0x00000400 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE9_MISC_IS__AXI_BUS_ERR___S 9 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_SRC_WATERMARK__SR_LOW_WATER_MARK_THRESOLD___POR 0x0000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_DR_SIZE___RWC QCSR_REG_RW +#define ADRASTEA_A_WCSS_SR_APSS_PMM_SR_MSB (0x0003206C) +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_ENABLE__PMM_WCSS_WAKEUP_IRQ_ACK___M 0x00000100 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_DR_SIZE___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_INVALID_ADDR_ACCESS___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS11__ADDRESS_REGISTER___POR 0x000000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE10___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IS__DST_RING_LOW_WATERMARK___POR 0x0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CURRENT_SRRI___M 0x0000FFFF +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE2___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_ENABLE__DIRTY_BIT_SET_ENABLE___M 0x00000001 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_DST_WR_INDEX___M 0x0000FFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_DR_SIZE (0x00240014) +#define ADRASTEA_A_WCSS_SR_APSS_SHADOWREG_STATUS__STATE___M 0x00000007 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE6_MISC_IS__AXI_TIMEOUT_ERR___S 10 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE11 (0x0003202C) +#define ADRASTEA_A_WCSS_SR_APSS_SR_CONTROL___POR 0x00000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CURRENT_DRRI (0x00240048) +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE6_SR_BA_LOW__BASE_ADDR_LOW___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOWREG_STATUS__WCSS_CORE_WAKE_SLEEP_STATE___S 3 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE4_MISC_IS__AXI_BUS_ERR___POR 0x0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE9_SR_BA_LOW (0x00249000) +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_HOST_IE__DST_RING_LOW_WATERMARK___S 4 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IS__SRC_LEN_ERR___S 8 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE20__VALUE_REGISTER___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE4_MISC_IS__AXI_TIMEOUT_ERR___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_ENABLE__ERR_RESP_ENABLE___M 0x00000004 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE18__VALUE_REGISTER___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_QDSP_ERROR_INTR_ENABLES_SET__LCMH_WCI2_INTERRUPT___S 2 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CE_CMD__HALT___M 0x00000001 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOWREG_STATUS___RWC QCSR_REG_RO +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE6___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_HOST_IS__SRC_RING_HIGH_WATERMARK___S 1 +#define ADRASTEA_A_WCSS_SR_APSS_DIRTY___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE14__VALUE_REGISTER___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_SR_APSS_SHADOWREG_STATUS__WCSS_CORE_WAKE_SLEEP_STATE___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_INVALID_ADDR_ACCESS__READ_ACCESS___S 16 +#define ADRASTEA_A_WCSS_SR_APSS_SR_TESTBUS___RWC QCSR_REG_RW +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_SR_BA_LOW___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS8___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_INVALID_ADDR_ACCESS__READ_ACCESS___M 0x00010000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IS__DST_RING_HIGH_WATERMARK___M 0x00000008 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE22___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_APPS_CE_INTR_ENABLES_CLEAR__CE_INTR_LINE_HOST_P___POR 0x000 +#define ADRASTEA_A_WCSS_SR_APSS_SR_CONTROL (0x00030000) +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS21__ADDRESS_REGISTER___POR 0x000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CURRENT_SRRI (0x00240044) +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS19__ADDRESS_REGISTER___M 0x003FFFFF +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE14___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS22___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS11___POR 0x00000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE8_MISC_IS__AXI_BUS_ERR___S 9 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IS__DST_MAX_LEN_VIO___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_WCSSAON_SR_LSB___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE14___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_DIRTY__BITS___M 0x00FFFFFF +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE5___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_ENABLE___M 0x000003FF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CE_CMD (0x00240020) +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE19__VALUE_REGISTER___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE3_SR_BA_LOW___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS20__ADDRESS_REGISTER___POR 0x000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_DR_SIZE___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IS__SRC_RING_LOW_WATERMARK___M 0x00000004 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE2_MISC_IS__AXI_BUS_ERR___S 9 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_QDSP_ERROR_INTR_ENABLES_SET__NOC_WCMN_INTR___POR 0x0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE_SECURE_WRAPPER_CE_WRAPPER_INTERRUPT_SUMMARY__HOST___S 12 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE14___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_WCSSAON_SR_LSB___POR 0x00000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_HOST_IE__COPY_COMPLETE___POR 0x0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE1_MISC_IS__AXI_BUS_ERR___S 9 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOWREG_STATUS___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_PMM_SR_LSB__STATUS___POR 0x00000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE11_SR_BA_LOW__BASE_ADDR_LOW___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_APPS_CE_INTR_ENABLES (0x002F1000) +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE1_MISC_IS__AXI_TIMEOUT_ERR___M 0x00000400 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS15___RWC QCSR_REG_RO +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE19___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE18___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS6__ADDRESS_REGISTER___POR 0x000000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS9 (0x00030044) +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_SR_BA_LOW__BASE_ADDR_LOW___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE15___RWC QCSR_REG_RW +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE6 (0x00032018) +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE21 (0x00032054) +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_SR_BA_HIGH__BASE_ADDR_HIGH___M 0x0000001F +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE_COMMON_WRAPPER_CE_WRAPPER_HOST_INTERRUPT_SUMMARY___S 12 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CE_CMD__HALT___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE7_SR_BA_LOW (0x00247000) +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS18 (0x00030068) +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS7__ADDRESS_REGISTER___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE3___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IE__AXI_ERR___S 9 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_STATUS__WLAN1_HW2SW_GRANT___M 0x00000040 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IS__DST_RING_LOW_WATERMARK___M 0x00000010 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_ENABLE__INVALID_ADDR___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE23__VALUE_REGISTER___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_PMM_SR_LSB___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS3___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IE__DST_RING_HIGH_WATERMARK___M 0x00000008 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS16___RWC QCSR_REG_RO +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_STATUS__ERR_RESP___S 2 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE22__VALUE_REGISTER___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_SR_SIZE (0x00240008) +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE23__VALUE_REGISTER___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_STATUS___RWC QCSR_REG_RO +#define ADRASTEA_A_WCSS_SR_APSS_SR_CONTROL___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS13__ADDRESS_REGISTER___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_DIRTY__BITS___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IE__DST_RING_HIGH_WATERMARK___S 3 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE17__VALUE_REGISTER___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_CLEAR__WLAN1_HW2SW_GRANT___M 0x00000040 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_QDSP_ERROR_INTR_ENABLES_SET__LMH_INT___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_STATUS__WLAN2_HW2SW_GRANT___M 0x00000080 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE11_SR_BA_LOW__BASE_ADDR_LOW___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS1 (0x00030024) +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CE_CTRL2 (0x0024001C) +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_APPS_CE_INTR_ENABLES__CE_INTR_LINE_HOST_P___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS0__ADDRESS_REGISTER___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE11_MISC_IS__AXI_BUS_ERR___S 9 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE23__VALUE_REGISTER___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_STATUS__WLAN2_HW2SW_GRANT___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_SW_SCRATCH___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE3_MISC_IS__AXI_BUS_ERR___POR 0x0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_APPS_CE_INTR_ENABLES_SET___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_QDSP_ERROR_INTR_ENABLES_SET__LCMH_STROBE_INTERRUPT___M 0x00000002 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_STATUS__VALUE_REG_UPDATED_WITH_INVALID_ADDR___M 0x00000020 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_QDSP_ERROR_INTR_ENABLES_SET__MCIM_INT___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_STATUS__FORCE_WAKE___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE6___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_PMM_SR_MSB___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS21 (0x00030074) +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS14___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE7_SR_BA_LOW___RWC QCSR_REG_RW +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE2_SR_BA_LOW___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_SR_APSS_DIRTY__BITS___POR 0x000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE2_SR_BA_LOW__BASE_ADDR_LOW___POR 0x00000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CE_CMD__DST_FLUSH___POR 0x0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IE__AXI_ERR___M 0x00000200 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_STATUS__WLAN2_HW2SW_GRANT___S 7 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_ENABLE___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE12__VALUE_REGISTER___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE20___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CURRENT_SRRI___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE5__VALUE_REGISTER___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE17__VALUE_REGISTER___POR 0x00000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IE__SRC_LEN_ERR___POR 0x0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE7_SR_BA_LOW___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE_COMMON_WRAPPER_CE_WRAPPER_HOST_INTERRUPT_SUMMARY___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE17___RWC QCSR_REG_RW +#define ADRASTEA_A_WCSS_SR_APSS_WCSSAON_SR_MSB___RWC QCSR_REG_RO +#define ADRASTEA_A_WCSS_SR_APSS_WCSSAON_SR_MSB (0x00032074) +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS9___RWC QCSR_REG_RO +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IE__SRC_RING_HIGH_WATERMARK___POR 0x0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE2_MISC_IS__AXI_BUS_ERR___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_FORCE_WAKE__FORCE_WAKE_ENABLE___M 0x00000001 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CE_CMD__DST_FLUSH___S 2 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_HOST_IE__SRC_RING_LOW_WATERMARK___S 2 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_DR_SIZE__START_OFFSET___M 0xFFFF0000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS10 (0x00030048) +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS4___M 0x003FFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IE__SRC_RING_OVERFLOW___S 5 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CURRENT_SRRI__CURRENT_SRRI___M 0x0000FFFF +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE21___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS4__ADDRESS_REGISTER___M 0x003FFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_HOST_IE__SRC_RING_HIGH_WATERMARK___M 0x00000002 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_HOST_IS__COPY_COMPLETE___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_STATUS__ERR_RESP___POR 0x0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IE__COPY_COMPLETE___M 0x00000001 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE20__VALUE_REGISTER___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE5_SR_BA_LOW__BASE_ADDR_LOW___POR 0x00000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE7_MISC_IS__AXI_TIMEOUT_ERR___S 10 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE10_SR_BA_LOW__BASE_ADDR_LOW___M 0xFFFFFFFF +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE9_SR_BA_LOW___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_STATUS__INVALID_ADDR___S 3 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS1___RWC QCSR_REG_RO +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_CLEAR__ECAHB_TIMEOUT___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_SW_SCRATCH___POR 0x00000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IS__AXI_BUS_ERR___S 9 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE5__VALUE_REGISTER___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS3__ADDRESS_REGISTER___POR 0x000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IE__SRC_RING_LOW_WATERMARK___S 2 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CE_CTRL2__SRC_AXI_MAX_LEN___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_PMM_SR_LSB (0x00032068) +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_QDSP_ERROR_INTR_ENABLES_SET__WFSS_DBG_INTR___S 17 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_CLEAR__PMM_SR_XO_SETTLE_TIMEOUT___M 0x00000200 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_DR_BA_HIGH___S 0 +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_ENABLE__WLAN1_HW2SW_GRANT___M 0x00000040 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE11_SR_BA_LOW___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE7_MISC_IS__AXI_BUS_ERR___M 0x00000200 +#define ADRASTEA_A_WCSS_SR_APSS_COMMIT_REPLAY (0x00030004) +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_SR_BA_LOW___RWC QCSR_REG_RW +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE21___S 0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE7_MISC_IS__AXI_BUS_ERR___POR 0x0 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_3_A_WCMN_QDSP_ERROR_INTR_ENABLES_SET__LCMH_WCI2_INTERRUPT___M 0x00000004 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IE__DST_RING_LOW_WATERMARK___POR 0x0 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE10__VALUE_REGISTER___POR 0x00000000 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE10 (0x00032028) +#define ADRASTEA_A_WCSS_SR_APSS_SR_INTERRUPT_STATUS__INVALID_ADDR___M 0x00000008 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE3 (0x0003200C) +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE16__VALUE_REGISTER___POR 0x00000000 +#define ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IE__SRC_RING_HIGH_WATERMARK___S 1 +#define ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS12__ADDRESS_REGISTER___S 0 + + +/* End auto-generated headers from register parser */ + +#define A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE_COMMON_WRAPPER_CE_WRAPPER_INDEX_BASE_LOW 0x0024C004 +#define A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE_COMMON_WRAPPER_CE_WRAPPER_INDEX_BASE_HIGH 0x0024C008 + +#define MISSING 0 +#define MISSING_FOR_ADRASTEA MISSING +#define ADRASTEA_PCIE_LOCAL_REG_BASE_ADDRESS 0 +#define ADRASTEA_WIFI_RTC_REG_BASE_ADDRESS 0x45000 +#define ADRASTEA_RTC_SOC_REG_BASE_ADDRESS 0x113000 +#define ADRASTEA_GPIO_ATHR_WLAN_REG_BASE_ADDRESS 0x85000 +#define ADRASTEA_SI_REG_BASE_ADDRESS 0x84000 +#define ADRASTEA_SOC_CORE_REG_BASE_ADDRESS 0x113000 +#define ADRASTEA_CE_WRAPPER_REG_CSR_BASE_ADDRESS 0xC000 +#define ADRASTEA_MAC_WIFICMN_REG_BASE_ADDRESS MISSING + +/* Base Addresses */ +#define ADRASTEA_RTC_SOC_BASE_ADDRESS 0x00000000 +#define ADRASTEA_RTC_WMAC_BASE_ADDRESS 0x00000000 +#define ADRASTEA_MAC_COEX_BASE_ADDRESS 0x0000f000 +#define ADRASTEA_BT_COEX_BASE_ADDRESS 0x00002000 +#define ADRASTEA_SOC_PCIE_BASE_ADDRESS 0x00130000 +#define ADRASTEA_SOC_CORE_BASE_ADDRESS 0x00000000 +#define ADRASTEA_WLAN_UART_BASE_ADDRESS 0x00111000 +#define ADRASTEA_WLAN_SI_BASE_ADDRESS 0x00010000 +#define ADRASTEA_WLAN_GPIO_BASE_ADDRESS 0x00000000 +#define ADRASTEA_WLAN_ANALOG_INTF_BASE_ADDRESS 0x00000000 +#define ADRASTEA_WLAN_MAC_BASE_ADDRESS 0x00000000 +#define ADRASTEA_EFUSE_BASE_ADDRESS 0x00024000 +#define ADRASTEA_FPGA_REG_BASE_ADDRESS 0x00039000 +#define ADRASTEA_WLAN_UART2_BASE_ADDRESS 0x00054c00 + +#define ADRASTEA_CE_WRAPPER_BASE_ADDRESS \ + ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE_COMMON_WRAPPER_CE_WRAPPER_HOST_INTERRUPT_SUMMARY +#define ADRASTEA_CE0_BASE_ADDRESS \ + ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_SR_BA_LOW +#define ADRASTEA_CE1_BASE_ADDRESS \ + ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE1_SR_BA_LOW +#define ADRASTEA_CE2_BASE_ADDRESS \ + ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE2_SR_BA_LOW +#define ADRASTEA_CE3_BASE_ADDRESS \ + ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE3_SR_BA_LOW +#define ADRASTEA_CE4_BASE_ADDRESS \ + ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE4_SR_BA_LOW +#define ADRASTEA_CE5_BASE_ADDRESS \ + ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE5_SR_BA_LOW +#define ADRASTEA_CE6_BASE_ADDRESS \ + ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE6_SR_BA_LOW +#define ADRASTEA_CE7_BASE_ADDRESS \ + ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE7_SR_BA_LOW +#define ADRASTEA_CE8_BASE_ADDRESS \ + ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE8_SR_BA_LOW +#define ADRASTEA_CE9_BASE_ADDRESS \ + ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE9_SR_BA_LOW +#define ADRASTEA_CE10_BASE_ADDRESS \ + ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE10_SR_BA_LOW +#define ADRASTEA_CE11_BASE_ADDRESS \ + ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE11_SR_BA_LOW + +#define ADRASTEA_A_SOC_PCIE_SOC_PCIE_REG MISSING +#define ADRASTEA_DBI_BASE_ADDRESS MISSING +#define ADRASTEA_WLAN_ANALOG_INTF_PCIE_BASE_ADDRESS MISSING +#define ADRASTEA_WIFICMN_BASE_ADDRESS MISSING +#define ADRASTEA_BOARD_DATA_SZ MISSING +#define ADRASTEA_BOARD_EXT_DATA_SZ MISSING +#define ADRASTEA_A_SOC_PCIE_PCIE_BAR0_START MISSING +#define ADRASTEA_A_SOC_CORE_SCRATCH_0_ADDRESS MISSING +#define ADRASTEA_A_SOC_CORE_SPARE_0_REGISTER MISSING +#define ADRASTEA_PCIE_INTR_FIRMWARE_ROUTE_MASK MISSING +#define ADRASTEA_SCRATCH_3_ADDRESS MISSING +#define ADRASTEA_TARG_DRAM_START 0x00400000 +#define ADRASTEA_SOC_SYSTEM_SLEEP_OFFSET 0x000000c0 +#define ADRASTEA_SOC_RESET_CONTROL_OFFSET \ + (0x00000000 + ADRASTEA_RTC_SOC_REG_BASE_ADDRESS) +#define ADRASTEA_SOC_CLOCK_CONTROL_OFFSET \ + (0x00000028 + ADRASTEA_RTC_SOC_REG_BASE_ADDRESS) +#define ADRASTEA_SOC_CLOCK_CONTROL_SI0_CLK_MASK 0x00000001 +#define ADRASTEA_SOC_RESET_CONTROL_SI0_RST_MASK 0x00000001 +#define ADRASTEA_WLAN_GPIO_PIN0_ADDRESS \ + (0x50 + ADRASTEA_GPIO_ATHR_WLAN_REG_BASE_ADDRESS) +#define ADRASTEA_WLAN_GPIO_PIN1_ADDRESS \ + (0x54 + ADRASTEA_GPIO_ATHR_WLAN_REG_BASE_ADDRESS) +#define ADRASTEA_WLAN_GPIO_PIN0_CONFIG_MASK 0x00007800 +#define ADRASTEA_WLAN_GPIO_PIN1_CONFIG_MASK 0x00007800 +#define ADRASTEA_SOC_CPU_CLOCK_OFFSET 0x00000020 +#define ADRASTEA_SOC_LPO_CAL_OFFSET \ + (0xe0 + ADRASTEA_RTC_SOC_REG_BASE_ADDRESS) +#define ADRASTEA_WLAN_GPIO_PIN10_ADDRESS \ + (0x78 + ADRASTEA_GPIO_ATHR_WLAN_REG_BASE_ADDRESS) +#define ADRASTEA_WLAN_GPIO_PIN11_ADDRESS \ + (0x7c + ADRASTEA_GPIO_ATHR_WLAN_REG_BASE_ADDRESS) +#define ADRASTEA_WLAN_GPIO_PIN12_ADDRESS \ + (0x80 + ADRASTEA_GPIO_ATHR_WLAN_REG_BASE_ADDRESS) +#define ADRASTEA_WLAN_GPIO_PIN13_ADDRESS \ + (0x84 + ADRASTEA_GPIO_ATHR_WLAN_REG_BASE_ADDRESS) +#define ADRASTEA_SOC_CPU_CLOCK_STANDARD_LSB 0 +#define ADRASTEA_SOC_CPU_CLOCK_STANDARD_MASK 0x00000003 +#define ADRASTEA_SOC_LPO_CAL_ENABLE_LSB 20 +#define ADRASTEA_SOC_LPO_CAL_ENABLE_MASK 0x00100000 + +#define ADRASTEA_WLAN_SYSTEM_SLEEP_DISABLE_LSB 0 +#define ADRASTEA_WLAN_SYSTEM_SLEEP_DISABLE_MASK 0x00000001 +#define ADRASTEA_WLAN_RESET_CONTROL_COLD_RST_MASK 0x00000002 +#define ADRASTEA_WLAN_RESET_CONTROL_WARM_RST_MASK 0x00000001 +#define ADRASTEA_SI_CONFIG_BIDIR_OD_DATA_LSB 18 +#define ADRASTEA_SI_CONFIG_BIDIR_OD_DATA_MASK 0x00040000 +#define ADRASTEA_SI_CONFIG_I2C_LSB 16 +#define ADRASTEA_SI_CONFIG_I2C_MASK 0x00010000 +#define ADRASTEA_SI_CONFIG_POS_SAMPLE_LSB 7 +#define ADRASTEA_SI_CONFIG_POS_SAMPLE_MASK 0x00000080 +#define ADRASTEA_SI_CONFIG_INACTIVE_CLK_LSB 4 +#define ADRASTEA_SI_CONFIG_INACTIVE_CLK_MASK 0x00000010 +#define ADRASTEA_SI_CONFIG_INACTIVE_DATA_LSB 5 +#define ADRASTEA_SI_CONFIG_INACTIVE_DATA_MASK 0x00000020 +#define ADRASTEA_SI_CONFIG_DIVIDER_LSB 0 +#define ADRASTEA_SI_CONFIG_DIVIDER_MASK 0x0000000f +#define ADRASTEA_SI_CONFIG_OFFSET (0x00000000 + ADRASTEA_SI_REG_BASE_ADDRESS) +#define ADRASTEA_SI_TX_DATA0_OFFSET (0x00000008 + ADRASTEA_SI_REG_BASE_ADDRESS) +#define ADRASTEA_SI_TX_DATA1_OFFSET (0x0000000c + ADRASTEA_SI_REG_BASE_ADDRESS) +#define ADRASTEA_SI_RX_DATA0_OFFSET (0x00000010 + ADRASTEA_SI_REG_BASE_ADDRESS) +#define ADRASTEA_SI_RX_DATA1_OFFSET (0x00000014 + ADRASTEA_SI_REG_BASE_ADDRESS) +#define ADRASTEA_SI_CS_OFFSET (0x00000004 + ADRASTEA_SI_REG_BASE_ADDRESS) +#define ADRASTEA_SI_CS_DONE_ERR_MASK 0x00000400 +#define ADRASTEA_SI_CS_DONE_INT_MASK 0x00000200 +#define ADRASTEA_SI_CS_START_LSB 8 +#define ADRASTEA_SI_CS_START_MASK 0x00000100 +#define ADRASTEA_SI_CS_RX_CNT_LSB 4 +#define ADRASTEA_SI_CS_RX_CNT_MASK 0x000000f0 +#define ADRASTEA_SI_CS_TX_CNT_LSB 0 +#define ADRASTEA_SI_CS_TX_CNT_MASK 0x0000000f +#define ADRASTEA_CE_COUNT 12 +#define ADRASTEA_SR_WR_INDEX_OFFSET (ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_SRC_WR_INDEX \ + - ADRASTEA_CE0_BASE_ADDRESS) +#define ADRASTEA_DST_WATERMARK_OFFSET (ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_DST_WATERMARK \ + - ADRASTEA_CE0_BASE_ADDRESS) +#define ADRASTEA_RX_MSDU_END_4_FIRST_MSDU_LSB 14 +#define ADRASTEA_RX_MSDU_END_4_FIRST_MSDU_MASK 0x00004000 +#define ADRASTEA_RX_MPDU_START_0_SEQ_NUM_LSB 16 +#define ADRASTEA_RX_MPDU_START_0_SEQ_NUM_MASK 0x0fff0000 +#define ADRASTEA_RX_MPDU_START_2_PN_47_32_LSB 0 +#define ADRASTEA_RX_MPDU_START_2_PN_47_32_MASK 0x0000ffff +#define ADRASTEA_RX_MSDU_END_1_EXT_WAPI_PN_63_48_LSB 16 +#define ADRASTEA_RX_MSDU_END_1_EXT_WAPI_PN_63_48_MASK 0xffff0000 +#define ADRASTEA_RX_MSDU_END_4_LAST_MSDU_LSB 15 +#define ADRASTEA_RX_MSDU_END_4_LAST_MSDU_MASK 0x00008000 +#define ADRASTEA_RX_ATTENTION_0_MCAST_BCAST_LSB 2 +#define ADRASTEA_RX_ATTENTION_0_MCAST_BCAST_MASK 0x00000004 +#define ADRASTEA_RX_ATTENTION_0_FRAGMENT_LSB 13 +#define ADRASTEA_RX_ATTENTION_0_FRAGMENT_MASK 0x00002000 +#define ADRASTEA_RX_ATTENTION_0_MPDU_LENGTH_ERR_MASK 0x08000000 +#define ADRASTEA_RX_FRAG_INFO_0_RING2_MORE_COUNT_LSB 16 +#define ADRASTEA_RX_FRAG_INFO_0_RING2_MORE_COUNT_MASK 0x00ff0000 +#define ADRASTEA_RX_MSDU_START_0_MSDU_LENGTH_LSB 0 +#define ADRASTEA_RX_MSDU_START_0_MSDU_LENGTH_MASK 0x00003fff + +#define ADRASTEA_RX_MSDU_START_2_DECAP_FORMAT_OFFSET 0x00000008 +#define ADRASTEA_RX_MSDU_START_2_DECAP_FORMAT_LSB 8 +#define ADRASTEA_RX_MSDU_START_2_DECAP_FORMAT_MASK 0x00000300 +#define ADRASTEA_RX_MPDU_START_0_ENCRYPTED_LSB 13 +#define ADRASTEA_RX_MPDU_START_0_ENCRYPTED_MASK 0x00002000 +#define ADRASTEA_RX_ATTENTION_0_MORE_DATA_MASK 0x00000400 +#define ADRASTEA_RX_ATTENTION_0_MSDU_DONE_MASK 0x80000000 +#define ADRASTEA_RX_ATTENTION_0_TCP_UDP_CHKSUM_FAIL_MASK 0x00040000 + +#define ADRASTEA_DST_WR_INDEX_OFFSET (ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_DST_WR_INDEX\ + - ADRASTEA_CE0_BASE_ADDRESS) + +#define ADRASTEA_SRC_WATERMARK_OFFSET (ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_SRC_WATERMARK\ + - ADRASTEA_CE0_BASE_ADDRESS) + +#define ADRASTEA_SRC_WATERMARK_LOW_MASK 0xffff0000 +#define ADRASTEA_SRC_WATERMARK_HIGH_MASK 0x0000ffff +#define ADRASTEA_DST_WATERMARK_LOW_MASK 0xffff0000 +#define ADRASTEA_DST_WATERMARK_HIGH_MASK 0x0000ffff + +#define ADRASTEA_CURRENT_SRRI_OFFSET (ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CURRENT_SRRI\ + - ADRASTEA_CE0_BASE_ADDRESS) + +#define ADRASTEA_CURRENT_DRRI_OFFSET (ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CURRENT_DRRI\ + - ADRASTEA_CE0_BASE_ADDRESS) + +#define ADRASTEA_HOST_IS_SRC_RING_HIGH_WATERMARK_MASK 0x00000002 +#define ADRASTEA_HOST_IS_SRC_RING_LOW_WATERMARK_MASK \ + ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_HOST_IS__SRC_RING_LOW_WATERMARK___M + +#define ADRASTEA_HOST_IS_DST_RING_HIGH_WATERMARK_MASK \ + ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_HOST_IS__DST_RING_HIGH_WATERMARK___M + +#define ADRASTEA_HOST_IS_DST_RING_LOW_WATERMARK_MASK \ + ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_HOST_IS__DST_RING_LOW_WATERMARK___M + +#define ADRASTEA_HOST_IS_OFFSET (ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_HOST_IS \ + - ADRASTEA_CE0_BASE_ADDRESS) + +#define ADRASTEA_MISC_IS_OFFSET (ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IS \ + - ADRASTEA_CE0_BASE_ADDRESS) + +#define ADRASTEA_HOST_IS_COPY_COMPLETE_MASK \ + ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_HOST_IS__COPY_COMPLETE___M + +#define ADRASTEA_CE_WRAPPER_INTERRUPT_SUMMARY_ADDRESS_OFFSET \ + (ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE_COMMON_WRAPPER_CE_WRAPPER_HOST_INTERRUPT_SUMMARY\ + - ADRASTEA_CE_WRAPPER_BASE_ADDRESS) + +/* + * Base address where the CE source and destination ring read + * indices are written to be viewed by host. + */ + +#define ADRASTEA_CE_DDR_ADDRESS_FOR_RRI_LOW \ + (A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE_COMMON_WRAPPER_CE_WRAPPER_INDEX_BASE_LOW\ + - ADRASTEA_CE_WRAPPER_BASE_ADDRESS) + +#define ADRASTEA_CE_DDR_ADDRESS_FOR_RRI_HIGH \ + (A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE_COMMON_WRAPPER_CE_WRAPPER_INDEX_BASE_HIGH - ADRASTEA_CE_WRAPPER_BASE_ADDRESS) + +#define ADRASTEA_HOST_IE_OFFSET (ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_HOST_IE\ + - ADRASTEA_CE0_BASE_ADDRESS) + +#define ADRASTEA_HOST_IE_COPY_COMPLETE_MASK \ + ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_HOST_IE__COPY_COMPLETE___M + +#define ADRASTEA_SR_BA_OFFSET (ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_SR_BA_LOW\ + - ADRASTEA_CE0_BASE_ADDRESS) + +#define ADRASTEA_SR_BA_HIGH_OFFSET \ + (ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_SR_BA_HIGH \ + - ADRASTEA_CE0_BASE_ADDRESS) + +#define ADRASTEA_SR_SIZE_OFFSET (ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_SR_SIZE \ + - ADRASTEA_CE0_BASE_ADDRESS) + +#define ADRASTEA_CE_CTRL1_OFFSET (ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CE_CTRL1 \ + - ADRASTEA_CE0_BASE_ADDRESS) + +#define ADRASTEA_CE_CTRL1_DMAX_LENGTH_MASK \ + ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CE_CTRL1__DEST_MAX_LENGTH___M + +#define ADRASTEA_DR_BA_OFFSET (ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_DR_BA_LOW\ + - ADRASTEA_CE0_BASE_ADDRESS) + +#define ADRASTEA_DR_BA_HIGH_OFFSET \ + (ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_DR_BA_HIGH\ + - ADRASTEA_CE0_BASE_ADDRESS) + +#define ADRASTEA_DR_SIZE_OFFSET (ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_DR_SIZE\ + - ADRASTEA_CE0_BASE_ADDRESS) + +#define ADRASTEA_CE_CMD_REGISTER_OFFSET (ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CE_CMD\ + - ADRASTEA_CE0_BASE_ADDRESS) + +#define ADRASTEA_MISC_IE_OFFSET \ + (ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IE - ADRASTEA_CE0_BASE_ADDRESS) + +#define ADRASTEA_MISC_IS_AXI_ERR_MASK 0x00000100 + +#define ADRASTEA_MISC_IS_DST_ADDR_ERR_MASK 0x00000200 + +#define ADRASTEA_MISC_IS_AXI_TIMEOUT_ERR \ + ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IS__AXI_TIMEOUT_ERR___M + +#define ADRASTEA_MISC_IS_SRC_LEN_ERR_MASK \ + ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IS__SRC_LEN_ERR___M + +#define ADRASTEA_MISC_IS_DST_MAX_LEN_VIO_MASK\ + ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IS__DST_MAX_LEN_VIO___M + +#define ADRASTEA_MISC_IS_DST_RING_OVERFLOW_MASK \ + ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IS__DST_RING_OVERFLOW___M + +#define ADRASTEA_MISC_IS_SRC_RING_OVERFLOW_MASK \ + ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_MISC_IS__SRC_RING_OVERFLOW___M + +#define ADRASTEA_SRC_WATERMARK_LOW_LSB \ + ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_SRC_WATERMARK__SR_LOW_WATER_MARK_THRESOLD___S + +#define ADRASTEA_SRC_WATERMARK_HIGH_LSB \ + ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_SRC_WATERMARK__SR_HIGH_WATER_MARK_THRESHOLD___S + +#define ADRASTEA_DST_WATERMARK_LOW_LSB \ + ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_DST_WATERMARK__DR_LOW_WATER_MARK_THRESHOLD___S + +#define ADRASTEA_DST_WATERMARK_HIGH_LSB \ + ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_DST_WATERMARK__DR_HIGH_WATER_MARK_THRESHOLD___S + +#define ADRASTEA_CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_MASK \ + ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE_COMMON_WRAPPER_CE_WRAPPER_HOST_INTERRUPT_SUMMARY__HOST___M + +#define ADRASTEA_CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_LSB \ + ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE_COMMON_WRAPPER_CE_WRAPPER_HOST_INTERRUPT_SUMMARY__HOST___S + +#define ADRASTEA_CE_CTRL1_DMAX_LENGTH_LSB \ + ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CE_CTRL1__DEST_MAX_LENGTH___S + +#define ADRASTEA_CE_CTRL1_SRC_RING_BYTE_SWAP_EN_MASK \ + ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CE_CTRL1__SRC_RING_BYTE_SWAP_EN___M + +#define ADRASTEA_CE_CTRL1_DST_RING_BYTE_SWAP_EN_MASK \ + ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CE_CTRL1__DST_RING_BYTE_SWAP_EN___M + +#define ADRASTEA_CE_CTRL1_SRC_RING_BYTE_SWAP_EN_LSB \ + ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CE_CTRL1__SRC_RING_BYTE_SWAP_EN___S + +#define ADRASTEA_CE_CTRL1_DST_RING_BYTE_SWAP_EN_LSB \ + ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CE_CTRL1__DST_RING_BYTE_SWAP_EN___S + +#define ADRASTEA_SOC_RESET_CONTROL_PCIE_RST_SHORT_OVRD_MASK 0x0000004 +#define ADRASTEA_SOC_RESET_CONTROL_PCIE_RST_SHORT_OVRD_LSB 2 +#define ADRASTEA_SOC_GLOBAL_RESET_ADDRESS \ + (0x0008 + ADRASTEA_PCIE_LOCAL_REG_BASE_ADDRESS) +#define ADRASTEA_RTC_STATE_ADDRESS \ + (0x0000 + ADRASTEA_PCIE_LOCAL_REG_BASE_ADDRESS) +#define ADRASTEA_RTC_STATE_COLD_RESET_MASK 0x400 + +#define ADRASTEA_PCIE_SOC_WAKE_RESET 0x00000000 +#define ADRASTEA_PCIE_SOC_WAKE_ADDRESS (ADRASTEA_A_WCSS_SR_APSS_FORCE_WAKE) +#define ADRASTEA_PCIE_SOC_WAKE_V_MASK 0x00000001 + +#define ADRASTEA_RTC_STATE_V_MASK 0x00000007 +#define ADRASTEA_RTC_STATE_V_LSB 0 +#define ADRASTEA_RTC_STATE_V_ON 5 +#define ADRASTEA_PCIE_LOCAL_BASE_ADDRESS 0x0 +#define ADRASTEA_FW_IND_EVENT_PENDING 1 +#define ADRASTEA_FW_IND_INITIALIZED 2 +#define ADRASTEA_FW_IND_HELPER 4 + +#define ADRASTEA_PCIE_INTR_FIRMWARE_MASK 0x00000000 +#define ADRASTEA_PCIE_INTR_CE0_MASK 0x00000100 +#define ADRASTEA_PCIE_INTR_CE_MASK_ALL 0x00001ffe + +#define ADRASTEA_CPU_INTR_ADDRESS 0xffffffff +#define ADRASTEA_SOC_LF_TIMER_CONTROL0_ADDRESS 0xffffffff +#define ADRASTEA_SOC_LF_TIMER_CONTROL0_ENABLE_MASK 0xffffffff +#define ADRASTEA_SOC_RESET_CONTROL_ADDRESS \ + (0x00000000 + ADRASTEA_RTC_SOC_REG_BASE_ADDRESS) +#define ADRASTEA_SOC_RESET_CONTROL_CE_RST_MASK 0x0100 +#define ADRASTEA_SOC_RESET_CONTROL_CPU_WARM_RST_MASK 0x00000040 +#define ADRASTEA_CORE_CTRL_ADDRESS (0x0000 + ADRASTEA_SOC_CORE_REG_BASE_ADDRESS) +#define ADRASTEA_CORE_CTRL_CPU_INTR_MASK 0x00002000 +#define ADRASTEA_LOCAL_SCRATCH_OFFSET 0x00000018 +#define ADRASTEA_CLOCK_GPIO_OFFSET 0xffffffff +#define ADRASTEA_CLOCK_GPIO_BT_CLK_OUT_EN_LSB 0 +#define ADRASTEA_CLOCK_GPIO_BT_CLK_OUT_EN_MASK 0 +#define ADRASTEA_SOC_CHIP_ID_ADDRESS 0x000000f0 +#define ADRASTEA_SOC_CHIP_ID_VERSION_MASK 0xfffc0000 +#define ADRASTEA_SOC_CHIP_ID_VERSION_LSB 18 +#define ADRASTEA_SOC_CHIP_ID_REVISION_MASK 0x00000f00 +#define ADRASTEA_SOC_CHIP_ID_REVISION_LSB 8 +#define ADRASTEA_SOC_POWER_REG_OFFSET 0x0000010c + +/* Copy Engine Debug */ +#define ADRASTEA_WLAN_DEBUG_INPUT_SEL_OFFSET 0x0000010c +#define ADRASTEA_WLAN_DEBUG_INPUT_SEL_SRC_MSB 3 +#define ADRASTEA_WLAN_DEBUG_INPUT_SEL_SRC_LSB 0 +#define ADRASTEA_WLAN_DEBUG_INPUT_SEL_SRC_MASK 0x0000000f +#define ADRASTEA_WLAN_DEBUG_CONTROL_OFFSET 0x00000108 +#define ADRASTEA_WLAN_DEBUG_CONTROL_ENABLE_MSB 0 +#define ADRASTEA_WLAN_DEBUG_CONTROL_ENABLE_LSB 0 +#define ADRASTEA_WLAN_DEBUG_CONTROL_ENABLE_MASK 0x00000001 +#define ADRASTEA_WLAN_DEBUG_OUT_OFFSET 0x00000110 +#define ADRASTEA_WLAN_DEBUG_OUT_DATA_MSB 19 +#define ADRASTEA_WLAN_DEBUG_OUT_DATA_LSB 0 +#define ADRASTEA_WLAN_DEBUG_OUT_DATA_MASK 0x000fffff +#define ADRASTEA_AMBA_DEBUG_BUS_OFFSET 0x0000011c +#define ADRASTEA_AMBA_DEBUG_BUS_PCIE_DEBUG_SEL_MSB 13 +#define ADRASTEA_AMBA_DEBUG_BUS_PCIE_DEBUG_SEL_LSB 8 +#define ADRASTEA_AMBA_DEBUG_BUS_PCIE_DEBUG_SEL_MASK 0x00003f00 +#define ADRASTEA_AMBA_DEBUG_BUS_SEL_MSB 4 +#define ADRASTEA_AMBA_DEBUG_BUS_SEL_LSB 0 +#define ADRASTEA_AMBA_DEBUG_BUS_SEL_MASK 0x0000001f +#define ADRASTEA_CE_WRAPPER_DEBUG_OFFSET 0x0008 +#define ADRASTEA_CE_WRAPPER_DEBUG_SEL_MSB 4 +#define ADRASTEA_CE_WRAPPER_DEBUG_SEL_LSB 0 +#define ADRASTEA_CE_WRAPPER_DEBUG_SEL_MASK 0x0000001f +#define ADRASTEA_CE_DEBUG_OFFSET 0x0054 +#define ADRASTEA_CE_DEBUG_SEL_MSB 5 +#define ADRASTEA_CE_DEBUG_SEL_LSB 0 +#define ADRASTEA_CE_DEBUG_SEL_MASK 0x0000003f +/* End */ + +/* PLL start */ +#define ADRASTEA_EFUSE_OFFSET 0x0000032c +#define ADRASTEA_EFUSE_XTAL_SEL_MSB 10 +#define ADRASTEA_EFUSE_XTAL_SEL_LSB 8 +#define ADRASTEA_EFUSE_XTAL_SEL_MASK 0x00000700 +#define ADRASTEA_BB_PLL_CONFIG_OFFSET 0x000002f4 +#define ADRASTEA_BB_PLL_CONFIG_OUTDIV_MSB 20 +#define ADRASTEA_BB_PLL_CONFIG_OUTDIV_LSB 18 +#define ADRASTEA_BB_PLL_CONFIG_OUTDIV_MASK 0x001c0000 +#define ADRASTEA_BB_PLL_CONFIG_FRAC_MSB 17 +#define ADRASTEA_BB_PLL_CONFIG_FRAC_LSB 0 +#define ADRASTEA_BB_PLL_CONFIG_FRAC_MASK 0x0003ffff +#define ADRASTEA_WLAN_PLL_SETTLE_TIME_MSB 10 +#define ADRASTEA_WLAN_PLL_SETTLE_TIME_LSB 0 +#define ADRASTEA_WLAN_PLL_SETTLE_TIME_MASK 0x000007ff +#define ADRASTEA_WLAN_PLL_SETTLE_OFFSET 0x0018 +#define ADRASTEA_WLAN_PLL_SETTLE_SW_MASK 0x000007ff +#define ADRASTEA_WLAN_PLL_SETTLE_RSTMASK 0xffffffff +#define ADRASTEA_WLAN_PLL_SETTLE_RESET 0x00000400 +#define ADRASTEA_WLAN_PLL_CONTROL_NOPWD_MSB 18 +#define ADRASTEA_WLAN_PLL_CONTROL_NOPWD_LSB 18 +#define ADRASTEA_WLAN_PLL_CONTROL_NOPWD_MASK 0x00040000 +#define ADRASTEA_WLAN_PLL_CONTROL_BYPASS_MSB 16 +#define ADRASTEA_WLAN_PLL_CONTROL_BYPASS_LSB 16 +#define ADRASTEA_WLAN_PLL_CONTROL_BYPASS_MASK 0x00010000 +#define ADRASTEA_WLAN_PLL_CONTROL_BYPASS_RESET 0x1 +#define ADRASTEA_WLAN_PLL_CONTROL_CLK_SEL_MSB 15 +#define ADRASTEA_WLAN_PLL_CONTROL_CLK_SEL_LSB 14 +#define ADRASTEA_WLAN_PLL_CONTROL_CLK_SEL_MASK 0x0000c000 +#define ADRASTEA_WLAN_PLL_CONTROL_CLK_SEL_RESET 0x0 +#define ADRASTEA_WLAN_PLL_CONTROL_REFDIV_MSB 13 +#define ADRASTEA_WLAN_PLL_CONTROL_REFDIV_LSB 10 +#define ADRASTEA_WLAN_PLL_CONTROL_REFDIV_MASK 0x00003c00 +#define ADRASTEA_WLAN_PLL_CONTROL_REFDIV_RESET 0x0 +#define ADRASTEA_WLAN_PLL_CONTROL_DIV_MSB 9 +#define ADRASTEA_WLAN_PLL_CONTROL_DIV_LSB 0 +#define ADRASTEA_WLAN_PLL_CONTROL_DIV_MASK 0x000003ff +#define ADRASTEA_WLAN_PLL_CONTROL_DIV_RESET 0x11 +#define ADRASTEA_WLAN_PLL_CONTROL_OFFSET 0x0014 +#define ADRASTEA_WLAN_PLL_CONTROL_SW_MASK 0x001fffff +#define ADRASTEA_WLAN_PLL_CONTROL_RSTMASK 0xffffffff +#define ADRASTEA_WLAN_PLL_CONTROL_RESET 0x00010011 +#define ADRASTEA_SOC_CORE_CLK_CTRL_OFFSET 0x00000114 +#define ADRASTEA_SOC_CORE_CLK_CTRL_DIV_MSB 2 +#define ADRASTEA_SOC_CORE_CLK_CTRL_DIV_LSB 0 +#define ADRASTEA_SOC_CORE_CLK_CTRL_DIV_MASK 0x00000007 +#define ADRASTEA_RTC_SYNC_STATUS_PLL_CHANGING_MSB 5 +#define ADRASTEA_RTC_SYNC_STATUS_PLL_CHANGING_LSB 5 +#define ADRASTEA_RTC_SYNC_STATUS_PLL_CHANGING_MASK 0x00000020 +#define ADRASTEA_RTC_SYNC_STATUS_PLL_CHANGING_RESET 0x0 +#define ADRASTEA_RTC_SYNC_STATUS_OFFSET 0x0244 +#define ADRASTEA_SOC_CPU_CLOCK_OFFSET 0x00000020 +#define ADRASTEA_SOC_CPU_CLOCK_STANDARD_MSB 1 +#define ADRASTEA_SOC_CPU_CLOCK_STANDARD_LSB 0 +#define ADRASTEA_SOC_CPU_CLOCK_STANDARD_MASK 0x00000003 +/* PLL end */ + +#define ADRASTEA_PCIE_INTR_CE_MASK(n) (ADRASTEA_PCIE_INTR_CE0_MASK << (n)) +#define ADRASTEA_DRAM_BASE_ADDRESS ADRASTEA_TARG_DRAM_START +#define ADRASTEA_FW_INDICATOR_ADDRESS \ + (ADRASTEA_WIFICMN_BASE_ADDRESS + ADRASTEA_SCRATCH_3_ADDRESS) +#define ADRASTEA_SYSTEM_SLEEP_OFFSET ADRASTEA_SOC_SYSTEM_SLEEP_OFFSET +#define ADRASTEA_WLAN_SYSTEM_SLEEP_OFFSET (0x002c + ADRASTEA_WIFI_RTC_REG_BASE_ADDRESS) +#define ADRASTEA_WLAN_RESET_CONTROL_OFFSET (0x0000 + ADRASTEA_WIFI_RTC_REG_BASE_ADDRESS) +#define ADRASTEA_CLOCK_CONTROL_OFFSET ADRASTEA_SOC_CLOCK_CONTROL_OFFSET +#define ADRASTEA_CLOCK_CONTROL_SI0_CLK_MASK \ + ADRASTEA_SOC_CLOCK_CONTROL_SI0_CLK_MASK +#define ADRASTEA_RESET_CONTROL_MBOX_RST_MASK 0x00000004 +#define ADRASTEA_RESET_CONTROL_SI0_RST_MASK \ + ADRASTEA_SOC_RESET_CONTROL_SI0_RST_MASK +#define ADRASTEA_GPIO_BASE_ADDRESS ADRASTEA_WLAN_GPIO_BASE_ADDRESS +#define ADRASTEA_GPIO_PIN0_OFFSET ADRASTEA_WLAN_GPIO_PIN0_ADDRESS +#define ADRASTEA_GPIO_PIN1_OFFSET ADRASTEA_WLAN_GPIO_PIN1_ADDRESS +#define ADRASTEA_GPIO_PIN0_CONFIG_MASK ADRASTEA_WLAN_GPIO_PIN0_CONFIG_MASK +#define ADRASTEA_GPIO_PIN1_CONFIG_MASK ADRASTEA_WLAN_GPIO_PIN1_CONFIG_MASK +#define ADRASTEA_SI_BASE_ADDRESS 0x00000000 +#define ADRASTEA_CPU_CLOCK_OFFSET (0x20 + ADRASTEA_RTC_SOC_REG_BASE_ADDRESS) +#define ADRASTEA_LPO_CAL_OFFSET ADRASTEA_SOC_LPO_CAL_OFFSET +#define ADRASTEA_GPIO_PIN10_OFFSET ADRASTEA_WLAN_GPIO_PIN10_ADDRESS +#define ADRASTEA_GPIO_PIN11_OFFSET ADRASTEA_WLAN_GPIO_PIN11_ADDRESS +#define ADRASTEA_GPIO_PIN12_OFFSET ADRASTEA_WLAN_GPIO_PIN12_ADDRESS +#define ADRASTEA_GPIO_PIN13_OFFSET ADRASTEA_WLAN_GPIO_PIN13_ADDRESS +#define ADRASTEA_CPU_CLOCK_STANDARD_LSB 0 +#define ADRASTEA_CPU_CLOCK_STANDARD_MASK 0x1 +#define ADRASTEA_LPO_CAL_ENABLE_LSB ADRASTEA_SOC_LPO_CAL_ENABLE_LSB +#define ADRASTEA_LPO_CAL_ENABLE_MASK ADRASTEA_SOC_LPO_CAL_ENABLE_MASK +#define ADRASTEA_ANALOG_INTF_BASE_ADDRESS ADRASTEA_WLAN_ANALOG_INTF_BASE_ADDRESS +#define ADRASTEA_MBOX_BASE_ADDRESS 0x00008000 +#define ADRASTEA_INT_STATUS_ENABLE_ERROR_LSB MISSING +#define ADRASTEA_INT_STATUS_ENABLE_ERROR_MASK MISSING +#define ADRASTEA_INT_STATUS_ENABLE_CPU_LSB MISSING +#define ADRASTEA_INT_STATUS_ENABLE_CPU_MASK MISSING +#define ADRASTEA_INT_STATUS_ENABLE_COUNTER_LSB MISSING +#define ADRASTEA_INT_STATUS_ENABLE_COUNTER_MASK MISSING +#define ADRASTEA_INT_STATUS_ENABLE_MBOX_DATA_LSB MISSING +#define ADRASTEA_INT_STATUS_ENABLE_MBOX_DATA_MASK MISSING +#define ADRASTEA_ERROR_STATUS_ENABLE_RX_UNDERFLOW_LSB MISSING +#define ADRASTEA_ERROR_STATUS_ENABLE_RX_UNDERFLOW_MASK MISSING +#define ADRASTEA_ERROR_STATUS_ENABLE_TX_OVERFLOW_LSB MISSING +#define ADRASTEA_ERROR_STATUS_ENABLE_TX_OVERFLOW_MASK MISSING +#define ADRASTEA_COUNTER_INT_STATUS_ENABLE_BIT_LSB MISSING +#define ADRASTEA_COUNTER_INT_STATUS_ENABLE_BIT_MASK MISSING +#define ADRASTEA_INT_STATUS_ENABLE_ADDRESS MISSING +#define ADRASTEA_CPU_INT_STATUS_ENABLE_BIT_LSB MISSING +#define ADRASTEA_CPU_INT_STATUS_ENABLE_BIT_MASK MISSING +#define ADRASTEA_HOST_INT_STATUS_ADDRESS MISSING +#define ADRASTEA_CPU_INT_STATUS_ADDRESS MISSING +#define ADRASTEA_ERROR_INT_STATUS_ADDRESS MISSING +#define ADRASTEA_ERROR_INT_STATUS_WAKEUP_MASK MISSING +#define ADRASTEA_ERROR_INT_STATUS_WAKEUP_LSB MISSING +#define ADRASTEA_ERROR_INT_STATUS_RX_UNDERFLOW_MASK MISSING +#define ADRASTEA_ERROR_INT_STATUS_RX_UNDERFLOW_LSB MISSING +#define ADRASTEA_ERROR_INT_STATUS_TX_OVERFLOW_MASK MISSING +#define ADRASTEA_ERROR_INT_STATUS_TX_OVERFLOW_LSB MISSING +#define ADRASTEA_COUNT_DEC_ADDRESS MISSING +#define ADRASTEA_HOST_INT_STATUS_CPU_MASK MISSING +#define ADRASTEA_HOST_INT_STATUS_CPU_LSB MISSING +#define ADRASTEA_HOST_INT_STATUS_ERROR_MASK MISSING +#define ADRASTEA_HOST_INT_STATUS_ERROR_LSB MISSING +#define ADRASTEA_HOST_INT_STATUS_COUNTER_MASK MISSING +#define ADRASTEA_HOST_INT_STATUS_COUNTER_LSB MISSING +#define ADRASTEA_RX_LOOKAHEAD_VALID_ADDRESS MISSING +#define ADRASTEA_WINDOW_DATA_ADDRESS MISSING +#define ADRASTEA_WINDOW_READ_ADDR_ADDRESS MISSING +#define ADRASTEA_WINDOW_WRITE_ADDR_ADDRESS MISSING + +/* Shadow Registers - Start */ +#define ADRASTEA_A_LOCAL_SHADOW_REG_VALUE_0 \ + ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE0 +#define ADRASTEA_A_LOCAL_SHADOW_REG_VALUE_1 \ + ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE1 +#define ADRASTEA_A_LOCAL_SHADOW_REG_VALUE_2 \ + ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE2 +#define ADRASTEA_A_LOCAL_SHADOW_REG_VALUE_3 \ + ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE3 +#define ADRASTEA_A_LOCAL_SHADOW_REG_VALUE_4 \ + ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE4 +#define ADRASTEA_A_LOCAL_SHADOW_REG_VALUE_5 \ + ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE5 +#define ADRASTEA_A_LOCAL_SHADOW_REG_VALUE_6 \ + ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE6 +#define ADRASTEA_A_LOCAL_SHADOW_REG_VALUE_7 \ + ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE7 +#define ADRASTEA_A_LOCAL_SHADOW_REG_VALUE_8 \ + ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE8 +#define ADRASTEA_A_LOCAL_SHADOW_REG_VALUE_9 \ + ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE9 +#define ADRASTEA_A_LOCAL_SHADOW_REG_VALUE_10 \ + ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE10 +#define ADRASTEA_A_LOCAL_SHADOW_REG_VALUE_11 \ + ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE11 +#define ADRASTEA_A_LOCAL_SHADOW_REG_VALUE_12 \ + ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE12 +#define ADRASTEA_A_LOCAL_SHADOW_REG_VALUE_13 \ + ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE13 +#define ADRASTEA_A_LOCAL_SHADOW_REG_VALUE_14 \ + ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE14 +#define ADRASTEA_A_LOCAL_SHADOW_REG_VALUE_15 \ + ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE15 +#define ADRASTEA_A_LOCAL_SHADOW_REG_VALUE_16 \ + ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE16 +#define ADRASTEA_A_LOCAL_SHADOW_REG_VALUE_17 \ + ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE17 +#define ADRASTEA_A_LOCAL_SHADOW_REG_VALUE_18 \ + ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE18 +#define ADRASTEA_A_LOCAL_SHADOW_REG_VALUE_19 \ + ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE19 +#define ADRASTEA_A_LOCAL_SHADOW_REG_VALUE_20 \ + ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE20 +#define ADRASTEA_A_LOCAL_SHADOW_REG_VALUE_21 \ + ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE21 +#define ADRASTEA_A_LOCAL_SHADOW_REG_VALUE_22 \ + ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE22 +#define ADRASTEA_A_LOCAL_SHADOW_REG_VALUE_23 \ + ADRASTEA_A_WCSS_SR_APSS_SHADOW_VALUE23 + +#define ADRASTEA_A_LOCAL_SHADOW_REG_ADDRESS_0 \ + ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS0 +#define ADRASTEA_A_LOCAL_SHADOW_REG_ADDRESS_1 \ + ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS1 +#define ADRASTEA_A_LOCAL_SHADOW_REG_ADDRESS_2 \ + ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS2 +#define ADRASTEA_A_LOCAL_SHADOW_REG_ADDRESS_3 \ + ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS3 +#define ADRASTEA_A_LOCAL_SHADOW_REG_ADDRESS_4 \ + ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS4 +#define ADRASTEA_A_LOCAL_SHADOW_REG_ADDRESS_5 \ + ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS5 +#define ADRASTEA_A_LOCAL_SHADOW_REG_ADDRESS_6 \ + ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS6 +#define ADRASTEA_A_LOCAL_SHADOW_REG_ADDRESS_7 \ + ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS7 +#define ADRASTEA_A_LOCAL_SHADOW_REG_ADDRESS_8 \ + ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS8 +#define ADRASTEA_A_LOCAL_SHADOW_REG_ADDRESS_9 \ + ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS9 +#define ADRASTEA_A_LOCAL_SHADOW_REG_ADDRESS_10 \ + ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS10 +#define ADRASTEA_A_LOCAL_SHADOW_REG_ADDRESS_11 \ + ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS11 +#define ADRASTEA_A_LOCAL_SHADOW_REG_ADDRESS_12 \ + ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS12 +#define ADRASTEA_A_LOCAL_SHADOW_REG_ADDRESS_13 \ + ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS13 +#define ADRASTEA_A_LOCAL_SHADOW_REG_ADDRESS_14 \ + ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS14 +#define ADRASTEA_A_LOCAL_SHADOW_REG_ADDRESS_15 \ + ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS15 +#define ADRASTEA_A_LOCAL_SHADOW_REG_ADDRESS_16 \ + ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS16 +#define ADRASTEA_A_LOCAL_SHADOW_REG_ADDRESS_17 \ + ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS17 +#define ADRASTEA_A_LOCAL_SHADOW_REG_ADDRESS_18 \ + ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS18 +#define ADRASTEA_A_LOCAL_SHADOW_REG_ADDRESS_19 \ + ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS19 +#define ADRASTEA_A_LOCAL_SHADOW_REG_ADDRESS_20 \ + ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS20 +#define ADRASTEA_A_LOCAL_SHADOW_REG_ADDRESS_21 \ + ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS21 +#define ADRASTEA_A_LOCAL_SHADOW_REG_ADDRESS_22 \ + ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS22 +#define ADRASTEA_A_LOCAL_SHADOW_REG_ADDRESS_23 \ + ADRASTEA_A_WCSS_SR_APSS_SHADOW_ADDRESS23 + +/* Q6 iHelium emulation registers */ +#define ADRASTEA_A_SOC_CORE_PCIE_INTR_CAUSE_GRP1 0x00113018 +#define ADRASTEA_A_SOC_CORE_SPARE_1_REGISTER 0x00113184 +#define ADRASTEA_A_SOC_CORE_PCIE_INTR_CLR_GRP1 0x00113020 +#define ADRASTEA_A_SOC_CORE_PCIE_INTR_ENABLE_GRP1 0x00113010 +#define ADRASTEA_A_SOC_PCIE_PCIE_SCRATCH_0 0x00130040 +#define ADRASTEA_A_SOC_PCIE_PCIE_SCRATCH_1 0x00130044 + +#define ADRASTEA_HOST_ENABLE_REGISTER 0x00188000 +#define ADRASTEA_Q6_ENABLE_REGISTER_0 0x00188004 +#define ADRASTEA_Q6_ENABLE_REGISTER_1 0x00188008 +#define ADRASTEA_HOST_CAUSE_REGISTER 0x0018800c +#define ADRASTEA_Q6_CAUSE_REGISTER_0 0x00188010 +#define ADRASTEA_Q6_CAUSE_REGISTER_1 0x00188014 +#define ADRASTEA_HOST_CLEAR_REGISTER 0x00188018 +#define ADRASTEA_Q6_CLEAR_REGISTER_0 0x0018801c +#define ADRASTEA_Q6_CLEAR_REGISTER_1 0x00188020 + +#define ADRASTEA_A_WIFI_APB_1_A_WFSS_CE_TARGET_HOST_DELTA 0x08 +#define ADRASTEA_A_SOC_PCIE_PCIE_SCRATCH_2 0x0013005C +#define ADRASTEA_A_SOC_CORE_PCIE_INTR_ENABLE_GRP0_Q6_MASK 0x0 +/* end: Q6 iHelium emulation registers */ + +#define ADRASTEA_BYPASS_QMI_TEMP_REGISTER 0x00032064 + +struct targetdef_s adrastea_targetdef = { + .d_RTC_SOC_BASE_ADDRESS = ADRASTEA_RTC_SOC_BASE_ADDRESS, + .d_RTC_WMAC_BASE_ADDRESS = ADRASTEA_RTC_WMAC_BASE_ADDRESS, + .d_SYSTEM_SLEEP_OFFSET = ADRASTEA_WLAN_SYSTEM_SLEEP_OFFSET, + .d_WLAN_SYSTEM_SLEEP_OFFSET = ADRASTEA_WLAN_SYSTEM_SLEEP_OFFSET, + .d_WLAN_SYSTEM_SLEEP_DISABLE_LSB = + ADRASTEA_WLAN_SYSTEM_SLEEP_DISABLE_LSB, + .d_WLAN_SYSTEM_SLEEP_DISABLE_MASK = + ADRASTEA_WLAN_SYSTEM_SLEEP_DISABLE_MASK, + .d_CLOCK_CONTROL_OFFSET = ADRASTEA_CLOCK_CONTROL_OFFSET, + .d_CLOCK_CONTROL_SI0_CLK_MASK = ADRASTEA_CLOCK_CONTROL_SI0_CLK_MASK, + .d_RESET_CONTROL_OFFSET = ADRASTEA_SOC_RESET_CONTROL_OFFSET, + .d_RESET_CONTROL_MBOX_RST_MASK = ADRASTEA_RESET_CONTROL_MBOX_RST_MASK, + .d_RESET_CONTROL_SI0_RST_MASK = ADRASTEA_RESET_CONTROL_SI0_RST_MASK, + .d_WLAN_RESET_CONTROL_OFFSET = ADRASTEA_WLAN_RESET_CONTROL_OFFSET, + .d_WLAN_RESET_CONTROL_COLD_RST_MASK = + ADRASTEA_WLAN_RESET_CONTROL_COLD_RST_MASK, + .d_WLAN_RESET_CONTROL_WARM_RST_MASK = + ADRASTEA_WLAN_RESET_CONTROL_WARM_RST_MASK, + .d_GPIO_BASE_ADDRESS = ADRASTEA_GPIO_BASE_ADDRESS, + .d_GPIO_PIN0_OFFSET = ADRASTEA_GPIO_PIN0_OFFSET, + .d_GPIO_PIN1_OFFSET = ADRASTEA_GPIO_PIN1_OFFSET, + .d_GPIO_PIN0_CONFIG_MASK = ADRASTEA_GPIO_PIN0_CONFIG_MASK, + .d_GPIO_PIN1_CONFIG_MASK = ADRASTEA_GPIO_PIN1_CONFIG_MASK, + .d_SI_CONFIG_BIDIR_OD_DATA_LSB = ADRASTEA_SI_CONFIG_BIDIR_OD_DATA_LSB, + .d_SI_CONFIG_BIDIR_OD_DATA_MASK = ADRASTEA_SI_CONFIG_BIDIR_OD_DATA_MASK, + .d_SI_CONFIG_I2C_LSB = ADRASTEA_SI_CONFIG_I2C_LSB, + .d_SI_CONFIG_I2C_MASK = ADRASTEA_SI_CONFIG_I2C_MASK, + .d_SI_CONFIG_POS_SAMPLE_LSB = ADRASTEA_SI_CONFIG_POS_SAMPLE_LSB, + .d_SI_CONFIG_POS_SAMPLE_MASK = ADRASTEA_SI_CONFIG_POS_SAMPLE_MASK, + .d_SI_CONFIG_INACTIVE_CLK_LSB = ADRASTEA_SI_CONFIG_INACTIVE_CLK_LSB, + .d_SI_CONFIG_INACTIVE_CLK_MASK = ADRASTEA_SI_CONFIG_INACTIVE_CLK_MASK, + .d_SI_CONFIG_INACTIVE_DATA_LSB = ADRASTEA_SI_CONFIG_INACTIVE_DATA_LSB, + .d_SI_CONFIG_INACTIVE_DATA_MASK = ADRASTEA_SI_CONFIG_INACTIVE_DATA_MASK, + .d_SI_CONFIG_DIVIDER_LSB = ADRASTEA_SI_CONFIG_DIVIDER_LSB, + .d_SI_CONFIG_DIVIDER_MASK = ADRASTEA_SI_CONFIG_DIVIDER_MASK, + .d_SI_BASE_ADDRESS = ADRASTEA_SI_BASE_ADDRESS, + .d_SI_CONFIG_OFFSET = ADRASTEA_SI_CONFIG_OFFSET, + .d_SI_TX_DATA0_OFFSET = ADRASTEA_SI_TX_DATA0_OFFSET, + .d_SI_TX_DATA1_OFFSET = ADRASTEA_SI_TX_DATA1_OFFSET, + .d_SI_RX_DATA0_OFFSET = ADRASTEA_SI_RX_DATA0_OFFSET, + .d_SI_RX_DATA1_OFFSET = ADRASTEA_SI_RX_DATA1_OFFSET, + .d_SI_CS_OFFSET = ADRASTEA_SI_CS_OFFSET, + .d_SI_CS_DONE_ERR_MASK = ADRASTEA_SI_CS_DONE_ERR_MASK, + .d_SI_CS_DONE_INT_MASK = ADRASTEA_SI_CS_DONE_INT_MASK, + .d_SI_CS_START_LSB = ADRASTEA_SI_CS_START_LSB, + .d_SI_CS_START_MASK = ADRASTEA_SI_CS_START_MASK, + .d_SI_CS_RX_CNT_LSB = ADRASTEA_SI_CS_RX_CNT_LSB, + .d_SI_CS_RX_CNT_MASK = ADRASTEA_SI_CS_RX_CNT_MASK, + .d_SI_CS_TX_CNT_LSB = ADRASTEA_SI_CS_TX_CNT_LSB, + .d_SI_CS_TX_CNT_MASK = ADRASTEA_SI_CS_TX_CNT_MASK, + .d_BOARD_DATA_SZ = ADRASTEA_BOARD_DATA_SZ, + .d_BOARD_EXT_DATA_SZ = ADRASTEA_BOARD_EXT_DATA_SZ, + .d_MBOX_BASE_ADDRESS = ADRASTEA_MBOX_BASE_ADDRESS, + .d_LOCAL_SCRATCH_OFFSET = ADRASTEA_LOCAL_SCRATCH_OFFSET, + .d_CPU_CLOCK_OFFSET = ADRASTEA_CPU_CLOCK_OFFSET, + .d_LPO_CAL_OFFSET = ADRASTEA_LPO_CAL_OFFSET, + .d_GPIO_PIN10_OFFSET = ADRASTEA_GPIO_PIN10_OFFSET, + .d_GPIO_PIN11_OFFSET = ADRASTEA_GPIO_PIN11_OFFSET, + .d_GPIO_PIN12_OFFSET = ADRASTEA_GPIO_PIN12_OFFSET, + .d_GPIO_PIN13_OFFSET = ADRASTEA_GPIO_PIN13_OFFSET, + .d_CLOCK_GPIO_OFFSET = ADRASTEA_CLOCK_GPIO_OFFSET, + .d_CPU_CLOCK_STANDARD_LSB = ADRASTEA_CPU_CLOCK_STANDARD_LSB, + .d_CPU_CLOCK_STANDARD_MASK = ADRASTEA_CPU_CLOCK_STANDARD_MASK, + .d_LPO_CAL_ENABLE_LSB = ADRASTEA_LPO_CAL_ENABLE_LSB, + .d_LPO_CAL_ENABLE_MASK = ADRASTEA_LPO_CAL_ENABLE_MASK, + .d_CLOCK_GPIO_BT_CLK_OUT_EN_LSB = ADRASTEA_CLOCK_GPIO_BT_CLK_OUT_EN_LSB, + .d_CLOCK_GPIO_BT_CLK_OUT_EN_MASK = + ADRASTEA_CLOCK_GPIO_BT_CLK_OUT_EN_MASK, + .d_ANALOG_INTF_BASE_ADDRESS = ADRASTEA_ANALOG_INTF_BASE_ADDRESS, + .d_WLAN_MAC_BASE_ADDRESS = ADRASTEA_WLAN_MAC_BASE_ADDRESS, + .d_FW_INDICATOR_ADDRESS = ADRASTEA_FW_INDICATOR_ADDRESS, + .d_DRAM_BASE_ADDRESS = ADRASTEA_DRAM_BASE_ADDRESS, + .d_SOC_CORE_BASE_ADDRESS = ADRASTEA_SOC_CORE_BASE_ADDRESS, + .d_CORE_CTRL_ADDRESS = ADRASTEA_CORE_CTRL_ADDRESS, + .d_CE_COUNT = ADRASTEA_CE_COUNT, + .d_MSI_NUM_REQUEST = MSI_NUM_REQUEST, + .d_MSI_ASSIGN_FW = MSI_ASSIGN_FW, + .d_MSI_ASSIGN_CE_INITIAL = MSI_ASSIGN_CE_INITIAL, + .d_PCIE_INTR_ENABLE_ADDRESS = ADRASTEA_HOST_ENABLE_REGISTER, + .d_PCIE_INTR_CLR_ADDRESS = ADRASTEA_HOST_CLEAR_REGISTER, + .d_PCIE_INTR_FIRMWARE_MASK = ADRASTEA_PCIE_INTR_FIRMWARE_MASK, + .d_PCIE_INTR_CE_MASK_ALL = ADRASTEA_PCIE_INTR_CE_MASK_ALL, + .d_CORE_CTRL_CPU_INTR_MASK = ADRASTEA_CORE_CTRL_CPU_INTR_MASK, + .d_SR_WR_INDEX_ADDRESS = ADRASTEA_SR_WR_INDEX_OFFSET, + .d_DST_WATERMARK_ADDRESS = ADRASTEA_DST_WATERMARK_OFFSET, + /* htt_rx.c */ + .d_RX_MSDU_END_4_FIRST_MSDU_MASK = + ADRASTEA_RX_MSDU_END_4_FIRST_MSDU_MASK, + .d_RX_MSDU_END_4_FIRST_MSDU_LSB = ADRASTEA_RX_MSDU_END_4_FIRST_MSDU_LSB, + .d_RX_MPDU_START_0_SEQ_NUM_MASK = ADRASTEA_RX_MPDU_START_0_SEQ_NUM_MASK, + .d_RX_MPDU_START_0_SEQ_NUM_LSB = ADRASTEA_RX_MPDU_START_0_SEQ_NUM_LSB, + .d_RX_MPDU_START_2_PN_47_32_LSB = ADRASTEA_RX_MPDU_START_2_PN_47_32_LSB, + .d_RX_MPDU_START_2_PN_47_32_MASK = + ADRASTEA_RX_MPDU_START_2_PN_47_32_MASK, + .d_RX_MSDU_END_1_EXT_WAPI_PN_63_48_MASK = + ADRASTEA_RX_MSDU_END_1_EXT_WAPI_PN_63_48_MASK, + .d_RX_MSDU_END_1_EXT_WAPI_PN_63_48_LSB = + ADRASTEA_RX_MSDU_END_1_EXT_WAPI_PN_63_48_LSB, + .d_RX_MSDU_END_4_LAST_MSDU_MASK = ADRASTEA_RX_MSDU_END_4_LAST_MSDU_MASK, + .d_RX_MSDU_END_4_LAST_MSDU_LSB = ADRASTEA_RX_MSDU_END_4_LAST_MSDU_LSB, + .d_RX_ATTENTION_0_MCAST_BCAST_MASK = + ADRASTEA_RX_ATTENTION_0_MCAST_BCAST_MASK, + .d_RX_ATTENTION_0_MCAST_BCAST_LSB = + ADRASTEA_RX_ATTENTION_0_MCAST_BCAST_LSB, + .d_RX_ATTENTION_0_FRAGMENT_MASK = ADRASTEA_RX_ATTENTION_0_FRAGMENT_MASK, + .d_RX_ATTENTION_0_FRAGMENT_LSB = ADRASTEA_RX_ATTENTION_0_FRAGMENT_LSB, + .d_RX_ATTENTION_0_MPDU_LENGTH_ERR_MASK = + ADRASTEA_RX_ATTENTION_0_MPDU_LENGTH_ERR_MASK, + .d_RX_FRAG_INFO_0_RING2_MORE_COUNT_MASK = + ADRASTEA_RX_FRAG_INFO_0_RING2_MORE_COUNT_MASK, + .d_RX_FRAG_INFO_0_RING2_MORE_COUNT_LSB = + ADRASTEA_RX_FRAG_INFO_0_RING2_MORE_COUNT_LSB, + .d_RX_MSDU_START_0_MSDU_LENGTH_MASK = + ADRASTEA_RX_MSDU_START_0_MSDU_LENGTH_MASK, + .d_RX_MSDU_START_0_MSDU_LENGTH_LSB = + ADRASTEA_RX_MSDU_START_0_MSDU_LENGTH_LSB, + .d_RX_MSDU_START_2_DECAP_FORMAT_OFFSET = + ADRASTEA_RX_MSDU_START_2_DECAP_FORMAT_OFFSET, + .d_RX_MSDU_START_2_DECAP_FORMAT_MASK = + ADRASTEA_RX_MSDU_START_2_DECAP_FORMAT_MASK, + .d_RX_MSDU_START_2_DECAP_FORMAT_LSB = + ADRASTEA_RX_MSDU_START_2_DECAP_FORMAT_LSB, + .d_RX_MPDU_START_0_ENCRYPTED_MASK = + ADRASTEA_RX_MPDU_START_0_ENCRYPTED_MASK, + .d_RX_MPDU_START_0_ENCRYPTED_LSB = + ADRASTEA_RX_MPDU_START_0_ENCRYPTED_LSB, + .d_RX_ATTENTION_0_MORE_DATA_MASK = + ADRASTEA_RX_ATTENTION_0_MORE_DATA_MASK, + .d_RX_ATTENTION_0_MSDU_DONE_MASK = + ADRASTEA_RX_ATTENTION_0_MSDU_DONE_MASK, + .d_RX_ATTENTION_0_TCP_UDP_CHKSUM_FAIL_MASK = + ADRASTEA_RX_ATTENTION_0_TCP_UDP_CHKSUM_FAIL_MASK, + + /* PLL start */ + .d_EFUSE_OFFSET = ADRASTEA_EFUSE_OFFSET, + .d_EFUSE_XTAL_SEL_MSB = ADRASTEA_EFUSE_XTAL_SEL_MSB, + .d_EFUSE_XTAL_SEL_LSB = ADRASTEA_EFUSE_XTAL_SEL_LSB, + .d_EFUSE_XTAL_SEL_MASK = ADRASTEA_EFUSE_XTAL_SEL_MASK, + .d_BB_PLL_CONFIG_OFFSET = ADRASTEA_BB_PLL_CONFIG_OFFSET, + .d_BB_PLL_CONFIG_OUTDIV_MSB = ADRASTEA_BB_PLL_CONFIG_OUTDIV_MSB, + .d_BB_PLL_CONFIG_OUTDIV_LSB = ADRASTEA_BB_PLL_CONFIG_OUTDIV_LSB, + .d_BB_PLL_CONFIG_OUTDIV_MASK = ADRASTEA_BB_PLL_CONFIG_OUTDIV_MASK, + .d_BB_PLL_CONFIG_FRAC_MSB = ADRASTEA_BB_PLL_CONFIG_FRAC_MSB, + .d_BB_PLL_CONFIG_FRAC_LSB = ADRASTEA_BB_PLL_CONFIG_FRAC_LSB, + .d_BB_PLL_CONFIG_FRAC_MASK = ADRASTEA_BB_PLL_CONFIG_FRAC_MASK, + .d_WLAN_PLL_SETTLE_TIME_MSB = ADRASTEA_WLAN_PLL_SETTLE_TIME_MSB, + .d_WLAN_PLL_SETTLE_TIME_LSB = ADRASTEA_WLAN_PLL_SETTLE_TIME_LSB, + .d_WLAN_PLL_SETTLE_TIME_MASK = ADRASTEA_WLAN_PLL_SETTLE_TIME_MASK, + .d_WLAN_PLL_SETTLE_OFFSET = ADRASTEA_WLAN_PLL_SETTLE_OFFSET, + .d_WLAN_PLL_SETTLE_SW_MASK = ADRASTEA_WLAN_PLL_SETTLE_SW_MASK, + .d_WLAN_PLL_SETTLE_RSTMASK = ADRASTEA_WLAN_PLL_SETTLE_RSTMASK, + .d_WLAN_PLL_SETTLE_RESET = ADRASTEA_WLAN_PLL_SETTLE_RESET, + .d_WLAN_PLL_CONTROL_NOPWD_MSB = ADRASTEA_WLAN_PLL_CONTROL_NOPWD_MSB, + .d_WLAN_PLL_CONTROL_NOPWD_LSB = ADRASTEA_WLAN_PLL_CONTROL_NOPWD_LSB, + .d_WLAN_PLL_CONTROL_NOPWD_MASK = ADRASTEA_WLAN_PLL_CONTROL_NOPWD_MASK, + .d_WLAN_PLL_CONTROL_BYPASS_MSB = ADRASTEA_WLAN_PLL_CONTROL_BYPASS_MSB, + .d_WLAN_PLL_CONTROL_BYPASS_LSB = ADRASTEA_WLAN_PLL_CONTROL_BYPASS_LSB, + .d_WLAN_PLL_CONTROL_BYPASS_MASK = ADRASTEA_WLAN_PLL_CONTROL_BYPASS_MASK, + .d_WLAN_PLL_CONTROL_BYPASS_RESET = + ADRASTEA_WLAN_PLL_CONTROL_BYPASS_RESET, + .d_WLAN_PLL_CONTROL_CLK_SEL_MSB = ADRASTEA_WLAN_PLL_CONTROL_CLK_SEL_MSB, + .d_WLAN_PLL_CONTROL_CLK_SEL_LSB = ADRASTEA_WLAN_PLL_CONTROL_CLK_SEL_LSB, + .d_WLAN_PLL_CONTROL_CLK_SEL_MASK = + ADRASTEA_WLAN_PLL_CONTROL_CLK_SEL_MASK, + .d_WLAN_PLL_CONTROL_CLK_SEL_RESET = + ADRASTEA_WLAN_PLL_CONTROL_CLK_SEL_RESET, + .d_WLAN_PLL_CONTROL_REFDIV_MSB = ADRASTEA_WLAN_PLL_CONTROL_REFDIV_MSB, + .d_WLAN_PLL_CONTROL_REFDIV_LSB = ADRASTEA_WLAN_PLL_CONTROL_REFDIV_LSB, + .d_WLAN_PLL_CONTROL_REFDIV_MASK = ADRASTEA_WLAN_PLL_CONTROL_REFDIV_MASK, + .d_WLAN_PLL_CONTROL_REFDIV_RESET = + ADRASTEA_WLAN_PLL_CONTROL_REFDIV_RESET, + .d_WLAN_PLL_CONTROL_DIV_MSB = ADRASTEA_WLAN_PLL_CONTROL_DIV_MSB, + .d_WLAN_PLL_CONTROL_DIV_LSB = ADRASTEA_WLAN_PLL_CONTROL_DIV_LSB, + .d_WLAN_PLL_CONTROL_DIV_MASK = ADRASTEA_WLAN_PLL_CONTROL_DIV_MASK, + .d_WLAN_PLL_CONTROL_DIV_RESET = ADRASTEA_WLAN_PLL_CONTROL_DIV_RESET, + .d_WLAN_PLL_CONTROL_OFFSET = ADRASTEA_WLAN_PLL_CONTROL_OFFSET, + .d_WLAN_PLL_CONTROL_SW_MASK = ADRASTEA_WLAN_PLL_CONTROL_SW_MASK, + .d_WLAN_PLL_CONTROL_RSTMASK = ADRASTEA_WLAN_PLL_CONTROL_RSTMASK, + .d_WLAN_PLL_CONTROL_RESET = ADRASTEA_WLAN_PLL_CONTROL_RESET, + .d_SOC_CORE_CLK_CTRL_OFFSET = ADRASTEA_SOC_CORE_CLK_CTRL_OFFSET, + .d_SOC_CORE_CLK_CTRL_DIV_MSB = ADRASTEA_SOC_CORE_CLK_CTRL_DIV_MSB, + .d_SOC_CORE_CLK_CTRL_DIV_LSB = ADRASTEA_SOC_CORE_CLK_CTRL_DIV_LSB, + .d_SOC_CORE_CLK_CTRL_DIV_MASK = ADRASTEA_SOC_CORE_CLK_CTRL_DIV_MASK, + .d_RTC_SYNC_STATUS_PLL_CHANGING_MSB = + ADRASTEA_RTC_SYNC_STATUS_PLL_CHANGING_MSB, + .d_RTC_SYNC_STATUS_PLL_CHANGING_LSB = + ADRASTEA_RTC_SYNC_STATUS_PLL_CHANGING_LSB, + .d_RTC_SYNC_STATUS_PLL_CHANGING_MASK = + ADRASTEA_RTC_SYNC_STATUS_PLL_CHANGING_MASK, + .d_RTC_SYNC_STATUS_PLL_CHANGING_RESET = + ADRASTEA_RTC_SYNC_STATUS_PLL_CHANGING_RESET, + .d_RTC_SYNC_STATUS_OFFSET = ADRASTEA_RTC_SYNC_STATUS_OFFSET, + .d_SOC_CPU_CLOCK_OFFSET = ADRASTEA_SOC_CPU_CLOCK_OFFSET, + .d_SOC_CPU_CLOCK_STANDARD_MSB = ADRASTEA_SOC_CPU_CLOCK_STANDARD_MSB, + .d_SOC_CPU_CLOCK_STANDARD_LSB = ADRASTEA_SOC_CPU_CLOCK_STANDARD_LSB, + .d_SOC_CPU_CLOCK_STANDARD_MASK = ADRASTEA_SOC_CPU_CLOCK_STANDARD_MASK, + /* PLL end */ + .d_SOC_POWER_REG_OFFSET = ADRASTEA_SOC_POWER_REG_OFFSET, + .d_PCIE_INTR_CAUSE_ADDRESS = ADRASTEA_HOST_CAUSE_REGISTER, + .d_SOC_RESET_CONTROL_ADDRESS = ADRASTEA_SOC_RESET_CONTROL_ADDRESS, + .d_SOC_RESET_CONTROL_PCIE_RST_SHORT_OVRD_MASK = + ADRASTEA_SOC_RESET_CONTROL_PCIE_RST_SHORT_OVRD_MASK, + .d_SOC_RESET_CONTROL_PCIE_RST_SHORT_OVRD_LSB = + ADRASTEA_SOC_RESET_CONTROL_PCIE_RST_SHORT_OVRD_LSB, + .d_SOC_RESET_CONTROL_CE_RST_MASK = + ADRASTEA_SOC_RESET_CONTROL_CE_RST_MASK, + .d_SOC_RESET_CONTROL_CPU_WARM_RST_MASK = + ADRASTEA_SOC_RESET_CONTROL_CPU_WARM_RST_MASK, + .d_CPU_INTR_ADDRESS = ADRASTEA_CPU_INTR_ADDRESS, + .d_SOC_LF_TIMER_CONTROL0_ADDRESS = + ADRASTEA_SOC_LF_TIMER_CONTROL0_ADDRESS, + .d_SOC_LF_TIMER_CONTROL0_ENABLE_MASK = + ADRASTEA_SOC_LF_TIMER_CONTROL0_ENABLE_MASK, + /* chip id start */ + .d_SOC_CHIP_ID_ADDRESS = ADRASTEA_SOC_CHIP_ID_ADDRESS, + .d_SOC_CHIP_ID_VERSION_MASK = ADRASTEA_SOC_CHIP_ID_VERSION_MASK, + .d_SOC_CHIP_ID_VERSION_LSB = ADRASTEA_SOC_CHIP_ID_VERSION_LSB, + .d_SOC_CHIP_ID_REVISION_MASK = ADRASTEA_SOC_CHIP_ID_REVISION_MASK, + .d_SOC_CHIP_ID_REVISION_LSB = ADRASTEA_SOC_CHIP_ID_REVISION_LSB, + /* chip id end */ + .d_A_SOC_CORE_SCRATCH_0_ADDRESS = ADRASTEA_A_SOC_CORE_SCRATCH_0_ADDRESS, + .d_A_SOC_CORE_SPARE_0_REGISTER = ADRASTEA_A_SOC_CORE_SPARE_0_REGISTER, + .d_PCIE_INTR_FIRMWARE_ROUTE_MASK = + ADRASTEA_PCIE_INTR_FIRMWARE_ROUTE_MASK, + .d_A_SOC_CORE_PCIE_INTR_CAUSE_GRP1 = + ADRASTEA_A_SOC_CORE_PCIE_INTR_CAUSE_GRP1, + .d_A_SOC_CORE_SPARE_1_REGISTER = + ADRASTEA_A_SOC_CORE_SPARE_1_REGISTER, + .d_A_SOC_CORE_PCIE_INTR_CLR_GRP1 = + ADRASTEA_A_SOC_CORE_PCIE_INTR_CLR_GRP1, + .d_A_SOC_CORE_PCIE_INTR_ENABLE_GRP1 = + ADRASTEA_A_SOC_CORE_PCIE_INTR_ENABLE_GRP1, + .d_A_SOC_PCIE_PCIE_SCRATCH_0 = ADRASTEA_A_SOC_PCIE_PCIE_SCRATCH_0, + .d_A_SOC_PCIE_PCIE_SCRATCH_1 = ADRASTEA_A_SOC_PCIE_PCIE_SCRATCH_1, + .d_A_WIFI_APB_1_A_WFSS_CE_TARGET_HOST_DELTA = + ADRASTEA_A_WIFI_APB_1_A_WFSS_CE_TARGET_HOST_DELTA, + .d_A_SOC_PCIE_PCIE_SCRATCH_2 = ADRASTEA_A_SOC_PCIE_PCIE_SCRATCH_2, + .d_A_SOC_CORE_PCIE_INTR_ENABLE_GRP0_Q6_MASK = + ADRASTEA_A_SOC_CORE_PCIE_INTR_ENABLE_GRP0_Q6_MASK, + .d_WLAN_DEBUG_INPUT_SEL_OFFSET = ADRASTEA_WLAN_DEBUG_INPUT_SEL_OFFSET, + .d_WLAN_DEBUG_INPUT_SEL_SRC_MSB = ADRASTEA_WLAN_DEBUG_INPUT_SEL_SRC_MSB, + .d_WLAN_DEBUG_INPUT_SEL_SRC_LSB = ADRASTEA_WLAN_DEBUG_INPUT_SEL_SRC_LSB, + .d_WLAN_DEBUG_INPUT_SEL_SRC_MASK = + ADRASTEA_WLAN_DEBUG_INPUT_SEL_SRC_MASK, + .d_WLAN_DEBUG_CONTROL_OFFSET = ADRASTEA_WLAN_DEBUG_CONTROL_OFFSET, + .d_WLAN_DEBUG_CONTROL_ENABLE_MSB = + ADRASTEA_WLAN_DEBUG_CONTROL_ENABLE_MSB, + .d_WLAN_DEBUG_CONTROL_ENABLE_LSB = + ADRASTEA_WLAN_DEBUG_CONTROL_ENABLE_LSB, + .d_WLAN_DEBUG_CONTROL_ENABLE_MASK = + ADRASTEA_WLAN_DEBUG_CONTROL_ENABLE_MASK, + .d_WLAN_DEBUG_OUT_OFFSET = ADRASTEA_WLAN_DEBUG_OUT_OFFSET, + .d_WLAN_DEBUG_OUT_DATA_MSB = ADRASTEA_WLAN_DEBUG_OUT_DATA_MSB, + .d_WLAN_DEBUG_OUT_DATA_LSB = ADRASTEA_WLAN_DEBUG_OUT_DATA_LSB, + .d_WLAN_DEBUG_OUT_DATA_MASK = ADRASTEA_WLAN_DEBUG_OUT_DATA_MASK, + .d_AMBA_DEBUG_BUS_OFFSET = ADRASTEA_AMBA_DEBUG_BUS_OFFSET, + .d_AMBA_DEBUG_BUS_PCIE_DEBUG_SEL_MSB = + ADRASTEA_AMBA_DEBUG_BUS_PCIE_DEBUG_SEL_MSB, + .d_AMBA_DEBUG_BUS_PCIE_DEBUG_SEL_LSB = + ADRASTEA_AMBA_DEBUG_BUS_PCIE_DEBUG_SEL_LSB, + .d_AMBA_DEBUG_BUS_PCIE_DEBUG_SEL_MASK = + ADRASTEA_AMBA_DEBUG_BUS_PCIE_DEBUG_SEL_MASK, + .d_AMBA_DEBUG_BUS_SEL_MSB = ADRASTEA_AMBA_DEBUG_BUS_SEL_MSB, + .d_AMBA_DEBUG_BUS_SEL_LSB = ADRASTEA_AMBA_DEBUG_BUS_SEL_LSB, + .d_AMBA_DEBUG_BUS_SEL_MASK = ADRASTEA_AMBA_DEBUG_BUS_SEL_MASK, + +#ifdef QCA_WIFI_3_0_ADRASTEA + .d_Q6_ENABLE_REGISTER_0 = ADRASTEA_Q6_ENABLE_REGISTER_0, + .d_Q6_ENABLE_REGISTER_1 = ADRASTEA_Q6_ENABLE_REGISTER_1, + .d_Q6_CAUSE_REGISTER_0 = ADRASTEA_Q6_CAUSE_REGISTER_0, + .d_Q6_CAUSE_REGISTER_1 = ADRASTEA_Q6_CAUSE_REGISTER_1, + .d_Q6_CLEAR_REGISTER_0 = ADRASTEA_Q6_CLEAR_REGISTER_0, + .d_Q6_CLEAR_REGISTER_1 = ADRASTEA_Q6_CLEAR_REGISTER_1, +#endif + +#ifdef CONFIG_BYPASS_QMI + .d_BYPASS_QMI_TEMP_REGISTER = ADRASTEA_BYPASS_QMI_TEMP_REGISTER, +#endif +}; + +struct hostdef_s adrastea_hostdef = { + .d_INT_STATUS_ENABLE_ERROR_LSB = ADRASTEA_INT_STATUS_ENABLE_ERROR_LSB, + .d_INT_STATUS_ENABLE_ERROR_MASK = ADRASTEA_INT_STATUS_ENABLE_ERROR_MASK, + .d_INT_STATUS_ENABLE_CPU_LSB = ADRASTEA_INT_STATUS_ENABLE_CPU_LSB, + .d_INT_STATUS_ENABLE_CPU_MASK = ADRASTEA_INT_STATUS_ENABLE_CPU_MASK, + .d_INT_STATUS_ENABLE_COUNTER_LSB = + ADRASTEA_INT_STATUS_ENABLE_COUNTER_LSB, + .d_INT_STATUS_ENABLE_COUNTER_MASK = + ADRASTEA_INT_STATUS_ENABLE_COUNTER_MASK, + .d_INT_STATUS_ENABLE_MBOX_DATA_LSB = + ADRASTEA_INT_STATUS_ENABLE_MBOX_DATA_LSB, + .d_INT_STATUS_ENABLE_MBOX_DATA_MASK = + ADRASTEA_INT_STATUS_ENABLE_MBOX_DATA_MASK, + .d_ERROR_STATUS_ENABLE_RX_UNDERFLOW_LSB = + ADRASTEA_ERROR_STATUS_ENABLE_RX_UNDERFLOW_LSB, + .d_ERROR_STATUS_ENABLE_RX_UNDERFLOW_MASK = + ADRASTEA_ERROR_STATUS_ENABLE_RX_UNDERFLOW_MASK, + .d_ERROR_STATUS_ENABLE_TX_OVERFLOW_LSB = + ADRASTEA_ERROR_STATUS_ENABLE_TX_OVERFLOW_LSB, + .d_ERROR_STATUS_ENABLE_TX_OVERFLOW_MASK = + ADRASTEA_ERROR_STATUS_ENABLE_TX_OVERFLOW_MASK, + .d_COUNTER_INT_STATUS_ENABLE_BIT_LSB = + ADRASTEA_COUNTER_INT_STATUS_ENABLE_BIT_LSB, + .d_COUNTER_INT_STATUS_ENABLE_BIT_MASK = + ADRASTEA_COUNTER_INT_STATUS_ENABLE_BIT_MASK, + .d_INT_STATUS_ENABLE_ADDRESS = ADRASTEA_INT_STATUS_ENABLE_ADDRESS, + .d_CPU_INT_STATUS_ENABLE_BIT_LSB = + ADRASTEA_CPU_INT_STATUS_ENABLE_BIT_LSB, + .d_CPU_INT_STATUS_ENABLE_BIT_MASK = + ADRASTEA_CPU_INT_STATUS_ENABLE_BIT_MASK, + .d_HOST_INT_STATUS_ADDRESS = ADRASTEA_HOST_INT_STATUS_ADDRESS, + .d_CPU_INT_STATUS_ADDRESS = ADRASTEA_CPU_INT_STATUS_ADDRESS, + .d_ERROR_INT_STATUS_ADDRESS = ADRASTEA_ERROR_INT_STATUS_ADDRESS, + .d_ERROR_INT_STATUS_WAKEUP_MASK = ADRASTEA_ERROR_INT_STATUS_WAKEUP_MASK, + .d_ERROR_INT_STATUS_WAKEUP_LSB = ADRASTEA_ERROR_INT_STATUS_WAKEUP_LSB, + .d_ERROR_INT_STATUS_RX_UNDERFLOW_MASK = + ADRASTEA_ERROR_INT_STATUS_RX_UNDERFLOW_MASK, + .d_ERROR_INT_STATUS_RX_UNDERFLOW_LSB = + ADRASTEA_ERROR_INT_STATUS_RX_UNDERFLOW_LSB, + .d_ERROR_INT_STATUS_TX_OVERFLOW_MASK = + ADRASTEA_ERROR_INT_STATUS_TX_OVERFLOW_MASK, + .d_ERROR_INT_STATUS_TX_OVERFLOW_LSB = + ADRASTEA_ERROR_INT_STATUS_TX_OVERFLOW_LSB, + .d_COUNT_DEC_ADDRESS = ADRASTEA_COUNT_DEC_ADDRESS, + .d_HOST_INT_STATUS_CPU_MASK = ADRASTEA_HOST_INT_STATUS_CPU_MASK, + .d_HOST_INT_STATUS_CPU_LSB = ADRASTEA_HOST_INT_STATUS_CPU_LSB, + .d_HOST_INT_STATUS_ERROR_MASK = ADRASTEA_HOST_INT_STATUS_ERROR_MASK, + .d_HOST_INT_STATUS_ERROR_LSB = ADRASTEA_HOST_INT_STATUS_ERROR_LSB, + .d_HOST_INT_STATUS_COUNTER_MASK = ADRASTEA_HOST_INT_STATUS_COUNTER_MASK, + .d_HOST_INT_STATUS_COUNTER_LSB = ADRASTEA_HOST_INT_STATUS_COUNTER_LSB, + .d_RX_LOOKAHEAD_VALID_ADDRESS = ADRASTEA_RX_LOOKAHEAD_VALID_ADDRESS, + .d_WINDOW_DATA_ADDRESS = ADRASTEA_WINDOW_DATA_ADDRESS, + .d_WINDOW_READ_ADDR_ADDRESS = ADRASTEA_WINDOW_READ_ADDR_ADDRESS, + .d_WINDOW_WRITE_ADDR_ADDRESS = ADRASTEA_WINDOW_WRITE_ADDR_ADDRESS, + .d_SOC_GLOBAL_RESET_ADDRESS = ADRASTEA_SOC_GLOBAL_RESET_ADDRESS, + .d_RTC_STATE_ADDRESS = ADRASTEA_RTC_STATE_ADDRESS, + .d_RTC_STATE_COLD_RESET_MASK = ADRASTEA_RTC_STATE_COLD_RESET_MASK, + .d_PCIE_LOCAL_BASE_ADDRESS = ADRASTEA_PCIE_LOCAL_BASE_ADDRESS, + .d_PCIE_SOC_WAKE_RESET = ADRASTEA_PCIE_SOC_WAKE_RESET, + .d_PCIE_SOC_WAKE_ADDRESS = ADRASTEA_PCIE_SOC_WAKE_ADDRESS, + .d_PCIE_SOC_WAKE_V_MASK = ADRASTEA_PCIE_SOC_WAKE_V_MASK, + .d_RTC_STATE_V_MASK = ADRASTEA_RTC_STATE_V_MASK, + .d_RTC_STATE_V_LSB = ADRASTEA_RTC_STATE_V_LSB, + .d_FW_IND_EVENT_PENDING = ADRASTEA_FW_IND_EVENT_PENDING, + .d_FW_IND_INITIALIZED = ADRASTEA_FW_IND_INITIALIZED, + .d_FW_IND_HELPER = ADRASTEA_FW_IND_HELPER, + .d_RTC_STATE_V_ON = ADRASTEA_RTC_STATE_V_ON, +#if defined(SDIO_3_0) + .d_HOST_INT_STATUS_MBOX_DATA_MASK = + ADRASTEA_HOST_INT_STATUS_MBOX_DATA_MASK, + .d_HOST_INT_STATUS_MBOX_DATA_LSB = + ADRASTEA_HOST_INT_STATUS_MBOX_DATA_LSB, +#endif + .d_PCIE_SOC_RDY_STATUS_ADDRESS = PCIE_SOC_RDY_STATUS_ADDRESS, + .d_PCIE_SOC_RDY_STATUS_BAR_MASK = PCIE_SOC_RDY_STATUS_BAR_MASK, + .d_SOC_PCIE_BASE_ADDRESS = SOC_PCIE_BASE_ADDRESS, + .d_MSI_MAGIC_ADR_ADDRESS = MSI_MAGIC_ADR_ADDRESS, + .d_MSI_MAGIC_ADDRESS = MSI_MAGIC_ADDRESS, + .d_HOST_CE_COUNT = ADRASTEA_CE_COUNT, + .d_ENABLE_MSI = 0, + .d_MUX_ID_MASK = 0xf000, + .d_TRANSACTION_ID_MASK = 0x0fff, + .d_DESC_DATA_FLAG_MASK = 0x1FFFE3E0, + .d_A_SOC_PCIE_PCIE_BAR0_START = ADRASTEA_A_SOC_PCIE_PCIE_BAR0_START, +}; + + +struct ce_reg_def adrastea_ce_targetdef = { + /* copy_engine.c */ + .d_DST_WR_INDEX_ADDRESS = ADRASTEA_DST_WR_INDEX_OFFSET, + .d_SRC_WATERMARK_ADDRESS = ADRASTEA_SRC_WATERMARK_OFFSET, + .d_SRC_WATERMARK_LOW_MASK = ADRASTEA_SRC_WATERMARK_LOW_MASK, + .d_SRC_WATERMARK_HIGH_MASK = ADRASTEA_SRC_WATERMARK_HIGH_MASK, + .d_DST_WATERMARK_LOW_MASK = ADRASTEA_DST_WATERMARK_LOW_MASK, + .d_DST_WATERMARK_HIGH_MASK = ADRASTEA_DST_WATERMARK_HIGH_MASK, + .d_CURRENT_SRRI_ADDRESS = ADRASTEA_CURRENT_SRRI_OFFSET, + .d_CURRENT_DRRI_ADDRESS = ADRASTEA_CURRENT_DRRI_OFFSET, + .d_HOST_IS_SRC_RING_HIGH_WATERMARK_MASK = + ADRASTEA_HOST_IS_SRC_RING_HIGH_WATERMARK_MASK, + .d_HOST_IS_SRC_RING_LOW_WATERMARK_MASK = + ADRASTEA_HOST_IS_SRC_RING_LOW_WATERMARK_MASK, + .d_HOST_IS_DST_RING_HIGH_WATERMARK_MASK = + ADRASTEA_HOST_IS_DST_RING_HIGH_WATERMARK_MASK, + .d_HOST_IS_DST_RING_LOW_WATERMARK_MASK = + ADRASTEA_HOST_IS_DST_RING_LOW_WATERMARK_MASK, + .d_HOST_IS_ADDRESS = ADRASTEA_HOST_IS_OFFSET, + .d_MISC_IS_ADDRESS = ADRASTEA_MISC_IS_OFFSET, + .d_HOST_IS_COPY_COMPLETE_MASK = ADRASTEA_HOST_IS_COPY_COMPLETE_MASK, + .d_CE_WRAPPER_BASE_ADDRESS = ADRASTEA_CE_WRAPPER_BASE_ADDRESS, + .d_CE_WRAPPER_INTERRUPT_SUMMARY_ADDRESS = + ADRASTEA_CE_WRAPPER_INTERRUPT_SUMMARY_ADDRESS_OFFSET, + .d_CE_DDR_ADDRESS_FOR_RRI_LOW = + ADRASTEA_CE_DDR_ADDRESS_FOR_RRI_LOW, + .d_CE_DDR_ADDRESS_FOR_RRI_HIGH = + ADRASTEA_CE_DDR_ADDRESS_FOR_RRI_HIGH, + .d_HOST_IE_ADDRESS = ADRASTEA_HOST_IE_OFFSET, + .d_HOST_IE_COPY_COMPLETE_MASK = ADRASTEA_HOST_IE_COPY_COMPLETE_MASK, + .d_SR_BA_ADDRESS = ADRASTEA_SR_BA_OFFSET, + .d_SR_BA_ADDRESS_HIGH = ADRASTEA_SR_BA_HIGH_OFFSET, + .d_SR_SIZE_ADDRESS = ADRASTEA_SR_SIZE_OFFSET, + .d_CE_CTRL1_ADDRESS = ADRASTEA_CE_CTRL1_OFFSET, + .d_CE_CTRL1_DMAX_LENGTH_MASK = ADRASTEA_CE_CTRL1_DMAX_LENGTH_MASK, + .d_DR_BA_ADDRESS = ADRASTEA_DR_BA_OFFSET, + .d_DR_BA_ADDRESS_HIGH = ADRASTEA_DR_BA_HIGH_OFFSET, + .d_DR_SIZE_ADDRESS = ADRASTEA_DR_SIZE_OFFSET, + .d_CE_CMD_REGISTER = ADRASTEA_CE_CMD_REGISTER_OFFSET, + .d_CE_MSI_ADDRESS = MISSING_FOR_ADRASTEA, + .d_CE_MSI_ADDRESS_HIGH = MISSING_FOR_ADRASTEA, + .d_CE_MSI_DATA = MISSING_FOR_ADRASTEA, + .d_CE_MSI_ENABLE_BIT = MISSING_FOR_ADRASTEA, + .d_MISC_IE_ADDRESS = ADRASTEA_MISC_IE_OFFSET, + .d_MISC_IS_AXI_ERR_MASK = ADRASTEA_MISC_IS_AXI_ERR_MASK, + .d_MISC_IS_DST_ADDR_ERR_MASK = ADRASTEA_MISC_IS_DST_ADDR_ERR_MASK, + .d_MISC_IS_SRC_LEN_ERR_MASK = ADRASTEA_MISC_IS_SRC_LEN_ERR_MASK, + .d_MISC_IS_DST_MAX_LEN_VIO_MASK = ADRASTEA_MISC_IS_DST_MAX_LEN_VIO_MASK, + .d_MISC_IS_DST_RING_OVERFLOW_MASK = + ADRASTEA_MISC_IS_DST_RING_OVERFLOW_MASK, + .d_MISC_IS_SRC_RING_OVERFLOW_MASK = + ADRASTEA_MISC_IS_SRC_RING_OVERFLOW_MASK, + .d_SRC_WATERMARK_LOW_LSB = ADRASTEA_SRC_WATERMARK_LOW_LSB, + .d_SRC_WATERMARK_HIGH_LSB = ADRASTEA_SRC_WATERMARK_HIGH_LSB, + .d_DST_WATERMARK_LOW_LSB = ADRASTEA_DST_WATERMARK_LOW_LSB, + .d_DST_WATERMARK_HIGH_LSB = ADRASTEA_DST_WATERMARK_HIGH_LSB, + .d_CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_MASK = + ADRASTEA_CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_MASK, + .d_CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_LSB = + ADRASTEA_CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_LSB, + .d_CE_CTRL1_DMAX_LENGTH_LSB = ADRASTEA_CE_CTRL1_DMAX_LENGTH_LSB, + .d_CE_CTRL1_SRC_RING_BYTE_SWAP_EN_MASK = + ADRASTEA_CE_CTRL1_SRC_RING_BYTE_SWAP_EN_MASK, + .d_CE_CTRL1_DST_RING_BYTE_SWAP_EN_MASK = + ADRASTEA_CE_CTRL1_DST_RING_BYTE_SWAP_EN_MASK, + .d_CE_CTRL1_SRC_RING_BYTE_SWAP_EN_LSB = + ADRASTEA_CE_CTRL1_SRC_RING_BYTE_SWAP_EN_LSB, + .d_CE_CTRL1_DST_RING_BYTE_SWAP_EN_LSB = + ADRASTEA_CE_CTRL1_DST_RING_BYTE_SWAP_EN_LSB, + .d_CE_CTRL1_IDX_UPD_EN_MASK = + ADRASTEA_A_WCSS_HM_A_WIFI_APB_1_A_WFSS_CE0_CE_CTRL1__IDX_UPD_EN___M, + .d_CE_WRAPPER_DEBUG_OFFSET = ADRASTEA_CE_WRAPPER_DEBUG_OFFSET, + .d_CE_WRAPPER_DEBUG_SEL_MSB = ADRASTEA_CE_WRAPPER_DEBUG_SEL_MSB, + .d_CE_WRAPPER_DEBUG_SEL_LSB = ADRASTEA_CE_WRAPPER_DEBUG_SEL_LSB, + .d_CE_WRAPPER_DEBUG_SEL_MASK = ADRASTEA_CE_WRAPPER_DEBUG_SEL_MASK, + .d_CE_DEBUG_OFFSET = ADRASTEA_CE_DEBUG_OFFSET, + .d_CE_DEBUG_SEL_MSB = ADRASTEA_CE_DEBUG_SEL_MSB, + .d_CE_DEBUG_SEL_LSB = ADRASTEA_CE_DEBUG_SEL_LSB, + .d_CE_DEBUG_SEL_MASK = ADRASTEA_CE_DEBUG_SEL_MASK, + .d_CE0_BASE_ADDRESS = ADRASTEA_CE0_BASE_ADDRESS, + .d_CE1_BASE_ADDRESS = ADRASTEA_CE1_BASE_ADDRESS, + .d_A_WIFI_APB_3_A_WCMN_APPS_CE_INTR_ENABLES = + MISSING_FOR_ADRASTEA, + .d_A_WIFI_APB_3_A_WCMN_APPS_CE_INTR_STATUS = + MISSING_FOR_ADRASTEA, +}; + + +struct host_shadow_regs_s adrastea_host_shadow_regs = { + .d_A_LOCAL_SHADOW_REG_VALUE_0 = + ADRASTEA_A_LOCAL_SHADOW_REG_VALUE_0, + .d_A_LOCAL_SHADOW_REG_VALUE_1 = + ADRASTEA_A_LOCAL_SHADOW_REG_VALUE_1, + .d_A_LOCAL_SHADOW_REG_VALUE_2 = + ADRASTEA_A_LOCAL_SHADOW_REG_VALUE_2, + .d_A_LOCAL_SHADOW_REG_VALUE_3 = + ADRASTEA_A_LOCAL_SHADOW_REG_VALUE_3, + .d_A_LOCAL_SHADOW_REG_VALUE_4 = + ADRASTEA_A_LOCAL_SHADOW_REG_VALUE_4, + .d_A_LOCAL_SHADOW_REG_VALUE_5 = + ADRASTEA_A_LOCAL_SHADOW_REG_VALUE_5, + .d_A_LOCAL_SHADOW_REG_VALUE_6 = + ADRASTEA_A_LOCAL_SHADOW_REG_VALUE_6, + .d_A_LOCAL_SHADOW_REG_VALUE_7 = + ADRASTEA_A_LOCAL_SHADOW_REG_VALUE_7, + .d_A_LOCAL_SHADOW_REG_VALUE_8 = + ADRASTEA_A_LOCAL_SHADOW_REG_VALUE_8, + .d_A_LOCAL_SHADOW_REG_VALUE_9 = + ADRASTEA_A_LOCAL_SHADOW_REG_VALUE_9, + .d_A_LOCAL_SHADOW_REG_VALUE_10 = + ADRASTEA_A_LOCAL_SHADOW_REG_VALUE_10, + .d_A_LOCAL_SHADOW_REG_VALUE_11 = + ADRASTEA_A_LOCAL_SHADOW_REG_VALUE_11, + .d_A_LOCAL_SHADOW_REG_VALUE_12 = + ADRASTEA_A_LOCAL_SHADOW_REG_VALUE_12, + .d_A_LOCAL_SHADOW_REG_VALUE_13 = + ADRASTEA_A_LOCAL_SHADOW_REG_VALUE_13, + .d_A_LOCAL_SHADOW_REG_VALUE_14 = + ADRASTEA_A_LOCAL_SHADOW_REG_VALUE_14, + .d_A_LOCAL_SHADOW_REG_VALUE_15 = + ADRASTEA_A_LOCAL_SHADOW_REG_VALUE_15, + .d_A_LOCAL_SHADOW_REG_VALUE_16 = + ADRASTEA_A_LOCAL_SHADOW_REG_VALUE_16, + .d_A_LOCAL_SHADOW_REG_VALUE_17 = + ADRASTEA_A_LOCAL_SHADOW_REG_VALUE_17, + .d_A_LOCAL_SHADOW_REG_VALUE_18 = + ADRASTEA_A_LOCAL_SHADOW_REG_VALUE_18, + .d_A_LOCAL_SHADOW_REG_VALUE_19 = + ADRASTEA_A_LOCAL_SHADOW_REG_VALUE_19, + .d_A_LOCAL_SHADOW_REG_VALUE_20 = + ADRASTEA_A_LOCAL_SHADOW_REG_VALUE_20, + .d_A_LOCAL_SHADOW_REG_VALUE_21 = + ADRASTEA_A_LOCAL_SHADOW_REG_VALUE_21, + .d_A_LOCAL_SHADOW_REG_VALUE_22 = + ADRASTEA_A_LOCAL_SHADOW_REG_VALUE_22, + .d_A_LOCAL_SHADOW_REG_VALUE_23 = + ADRASTEA_A_LOCAL_SHADOW_REG_VALUE_23, + .d_A_LOCAL_SHADOW_REG_ADDRESS_0 = + ADRASTEA_A_LOCAL_SHADOW_REG_ADDRESS_0, + .d_A_LOCAL_SHADOW_REG_ADDRESS_1 = + ADRASTEA_A_LOCAL_SHADOW_REG_ADDRESS_1, + .d_A_LOCAL_SHADOW_REG_ADDRESS_2 = + ADRASTEA_A_LOCAL_SHADOW_REG_ADDRESS_2, + .d_A_LOCAL_SHADOW_REG_ADDRESS_3 = + ADRASTEA_A_LOCAL_SHADOW_REG_ADDRESS_3, + .d_A_LOCAL_SHADOW_REG_ADDRESS_4 = + ADRASTEA_A_LOCAL_SHADOW_REG_ADDRESS_4, + .d_A_LOCAL_SHADOW_REG_ADDRESS_5 = + ADRASTEA_A_LOCAL_SHADOW_REG_ADDRESS_5, + .d_A_LOCAL_SHADOW_REG_ADDRESS_6 = + ADRASTEA_A_LOCAL_SHADOW_REG_ADDRESS_6, + .d_A_LOCAL_SHADOW_REG_ADDRESS_7 = + ADRASTEA_A_LOCAL_SHADOW_REG_ADDRESS_7, + .d_A_LOCAL_SHADOW_REG_ADDRESS_8 = + ADRASTEA_A_LOCAL_SHADOW_REG_ADDRESS_8, + .d_A_LOCAL_SHADOW_REG_ADDRESS_9 = + ADRASTEA_A_LOCAL_SHADOW_REG_ADDRESS_9, + .d_A_LOCAL_SHADOW_REG_ADDRESS_10 = + ADRASTEA_A_LOCAL_SHADOW_REG_ADDRESS_10, + .d_A_LOCAL_SHADOW_REG_ADDRESS_11 = + ADRASTEA_A_LOCAL_SHADOW_REG_ADDRESS_11, + .d_A_LOCAL_SHADOW_REG_ADDRESS_12 = + ADRASTEA_A_LOCAL_SHADOW_REG_ADDRESS_12, + .d_A_LOCAL_SHADOW_REG_ADDRESS_13 = + ADRASTEA_A_LOCAL_SHADOW_REG_ADDRESS_13, + .d_A_LOCAL_SHADOW_REG_ADDRESS_14 = + ADRASTEA_A_LOCAL_SHADOW_REG_ADDRESS_14, + .d_A_LOCAL_SHADOW_REG_ADDRESS_15 = + ADRASTEA_A_LOCAL_SHADOW_REG_ADDRESS_15, + .d_A_LOCAL_SHADOW_REG_ADDRESS_16 = + ADRASTEA_A_LOCAL_SHADOW_REG_ADDRESS_16, + .d_A_LOCAL_SHADOW_REG_ADDRESS_17 = + ADRASTEA_A_LOCAL_SHADOW_REG_ADDRESS_17, + .d_A_LOCAL_SHADOW_REG_ADDRESS_18 = + ADRASTEA_A_LOCAL_SHADOW_REG_ADDRESS_18, + .d_A_LOCAL_SHADOW_REG_ADDRESS_19 = + ADRASTEA_A_LOCAL_SHADOW_REG_ADDRESS_19, + .d_A_LOCAL_SHADOW_REG_ADDRESS_20 = + ADRASTEA_A_LOCAL_SHADOW_REG_ADDRESS_20, + .d_A_LOCAL_SHADOW_REG_ADDRESS_21 = + ADRASTEA_A_LOCAL_SHADOW_REG_ADDRESS_21, + .d_A_LOCAL_SHADOW_REG_ADDRESS_22 = + ADRASTEA_A_LOCAL_SHADOW_REG_ADDRESS_22, + .d_A_LOCAL_SHADOW_REG_ADDRESS_23 = + ADRASTEA_A_LOCAL_SHADOW_REG_ADDRESS_23 +}; + +#endif /* ADRASTEA_REG_DEF_H */ diff --git a/drivers/staging/qca-wifi-host-cmn/hif/src/ar6004def.c b/drivers/staging/qca-wifi-host-cmn/hif/src/ar6004def.c new file mode 100644 index 0000000000000000000000000000000000000000..88bdcc5df2320dfbbe3a0574e4b27a1d4a5eb646 --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/hif/src/ar6004def.c @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2013,2016 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. + */ + +#if defined(AR6004_HEADERS_DEF) +#define AR6004 1 + +#define WLAN_HEADERS 1 +#include "common_drv.h" +#include "AR6004/hw/apb_map.h" +#include "AR6004/hw/gpio_reg.h" +#include "AR6004/hw/rtc_reg.h" +#include "AR6004/hw/si_reg.h" +#include "AR6004/hw/mbox_reg.h" +#include "AR6004/hw/mbox_wlan_host_reg.h" + +#define SYSTEM_SLEEP_OFFSET SOC_SYSTEM_SLEEP_OFFSET +#define SCRATCH_BASE_ADDRESS MBOX_BASE_ADDRESS + +#define MY_TARGET_DEF AR6004_TARGETdef +#define MY_HOST_DEF AR6004_HOSTdef +#define MY_CEREG_DEF AR6004_CE_TARGETdef +#define MY_TARGET_BOARD_DATA_SZ AR6004_BOARD_DATA_SZ +#define MY_TARGET_BOARD_EXT_DATA_SZ AR6004_BOARD_EXT_DATA_SZ +#include "targetdef.h" +#include "hostdef.h" +#else +#include "common_drv.h" +#include "targetdef.h" +#include "hostdef.h" +struct targetdef_s *AR6004_TARGETdef; +struct hostdef_s *AR6004_HOSTdef; +#endif /*AR6004_HEADERS_DEF */ diff --git a/drivers/staging/qca-wifi-host-cmn/hif/src/ar6320def.c b/drivers/staging/qca-wifi-host-cmn/hif/src/ar6320def.c new file mode 100644 index 0000000000000000000000000000000000000000..5440ecdecd9a1462abfcfaa892d23e3ef1e919b3 --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/hif/src/ar6320def.c @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2013,2016 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. + */ + +#if defined(AR6320_HEADERS_DEF) +#define AR6320 1 + +#define WLAN_HEADERS 1 +#include "common_drv.h" +#include "AR6320/hw/apb_map.h" +#include "AR6320/hw/gpio_reg.h" +#include "AR6320/hw/rtc_reg.h" +#include "AR6320/extra/hw/si_reg.h" +#include "AR6320/hw/mbox_reg.h" +#include "AR6320/extra/hw/ce_reg_csr.h" +#include "AR6320/hw/mbox_wlan_host_reg.h" +#include "soc_addrs.h" +#include "AR6320/extra/hw/soc_core_reg.h" +#include "AR6320/hw/pcie_local_reg.h" +#include "AR6320/hw/soc_pcie_reg.h" + +#ifndef SYSTEM_SLEEP_OFFSET +#define SYSTEM_SLEEP_OFFSET SOC_SYSTEM_SLEEP_OFFSET +#endif +#ifndef WLAN_SYSTEM_SLEEP_OFFSET +#define WLAN_SYSTEM_SLEEP_OFFSET SOC_SYSTEM_SLEEP_OFFSET +#endif +#ifndef WLAN_RESET_CONTROL_OFFSET +#define WLAN_RESET_CONTROL_OFFSET SOC_RESET_CONTROL_OFFSET +#endif +#ifndef RESET_CONTROL_SI0_RST_MASK +#define RESET_CONTROL_SI0_RST_MASK SOC_RESET_CONTROL_SI0_RST_MASK +#endif +#ifndef SI_BASE_ADDRESS +#define SI_BASE_ADDRESS WLAN_SI_BASE_ADDRESS +#endif +#ifndef PCIE_LOCAL_BASE_ADDRESS +/* TBDXXX: Eventually, this Base Address will be defined in HW header files */ +#define PCIE_LOCAL_BASE_ADDRESS 0x80000 +#endif +#ifndef RTC_STATE_V_ON +#define RTC_STATE_V_ON 3 +#endif + +#define MY_TARGET_DEF AR6320_TARGETdef +#define MY_HOST_DEF AR6320_HOSTdef +#define MY_CEREG_DEF AR6320_CE_TARGETdef +#define MY_TARGET_BOARD_DATA_SZ AR6320_BOARD_DATA_SZ +#define MY_TARGET_BOARD_EXT_DATA_SZ AR6320_BOARD_EXT_DATA_SZ +#define DRAM_BASE_ADDRESS TARG_DRAM_START +#include "targetdef.h" +#include "hostdef.h" +#else +#include "common_drv.h" +#include "targetdef.h" +#include "hostdef.h" +struct targetdef_s *AR6320_TARGETdef; +struct hostdef_s *AR6320_HOSTdef; +#endif /* AR6320_HEADERS_DEF */ diff --git a/drivers/staging/qca-wifi-host-cmn/hif/src/ar6320def.h b/drivers/staging/qca-wifi-host-cmn/hif/src/ar6320def.h new file mode 100644 index 0000000000000000000000000000000000000000..f03a07caa0976ce0dc80a0d9d41da74b58028113 --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/hif/src/ar6320def.h @@ -0,0 +1,805 @@ +/* + * Copyright (c) 2011-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef _AR6320DEF_H_ +#define _AR6320DEF_H_ + +/* Base Addresses */ +#define AR6320_RTC_SOC_BASE_ADDRESS 0x00000000 +#define AR6320_RTC_WMAC_BASE_ADDRESS 0x00001000 +#define AR6320_MAC_COEX_BASE_ADDRESS 0x0000f000 +#define AR6320_BT_COEX_BASE_ADDRESS 0x00002000 +#define AR6320_SOC_CORE_BASE_ADDRESS 0x0003a000 +#define AR6320_WLAN_UART_BASE_ADDRESS 0x0000c000 +#define AR6320_WLAN_SI_BASE_ADDRESS 0x00010000 +#define AR6320_WLAN_GPIO_BASE_ADDRESS 0x00005000 +#define AR6320_WLAN_ANALOG_INTF_BASE_ADDRESS 0x00006000 +#define AR6320_WLAN_MAC_BASE_ADDRESS 0x00010000 +#define AR6320_EFUSE_BASE_ADDRESS 0x00024000 +#define AR6320_FPGA_REG_BASE_ADDRESS 0x00039000 +#define AR6320_WLAN_UART2_BASE_ADDRESS 0x00054c00 +#define AR6320_DBI_BASE_ADDRESS 0x0003c000 + +#define AR6320_SCRATCH_3_ADDRESS 0x0028 +#define AR6320_TARG_DRAM_START 0x00400000 +#define AR6320_SOC_SYSTEM_SLEEP_OFFSET 0x000000c0 +#define AR6320_SOC_RESET_CONTROL_OFFSET 0x00000000 +#define AR6320_SOC_CLOCK_CONTROL_OFFSET 0x00000028 +#define AR6320_SOC_CLOCK_CONTROL_SI0_CLK_MASK 0x00000001 +#define AR6320_SOC_RESET_CONTROL_SI0_RST_MASK 0x00000000 +#define AR6320_WLAN_GPIO_PIN0_ADDRESS 0x00000068 +#define AR6320_WLAN_GPIO_PIN1_ADDRESS 0x0000006c +#define AR6320_WLAN_GPIO_PIN0_CONFIG_MASK 0x00007800 +#define AR6320_WLAN_GPIO_PIN1_CONFIG_MASK 0x00007800 +#define AR6320_SOC_CPU_CLOCK_OFFSET 0x00000020 +#define AR6320_SOC_LPO_CAL_OFFSET 0x000000e0 +#define AR6320_WLAN_GPIO_PIN10_ADDRESS 0x00000090 +#define AR6320_WLAN_GPIO_PIN11_ADDRESS 0x00000094 +#define AR6320_WLAN_GPIO_PIN12_ADDRESS 0x00000098 +#define AR6320_WLAN_GPIO_PIN13_ADDRESS 0x0000009c +#define AR6320_SOC_CPU_CLOCK_STANDARD_LSB 0 +#define AR6320_SOC_CPU_CLOCK_STANDARD_MASK 0x00000003 +#define AR6320_SOC_LPO_CAL_ENABLE_LSB 20 +#define AR6320_SOC_LPO_CAL_ENABLE_MASK 0x00100000 + +#define AR6320_WLAN_SYSTEM_SLEEP_DISABLE_LSB 0 +#define AR6320_WLAN_SYSTEM_SLEEP_DISABLE_MASK 0x00000001 +#define AR6320_WLAN_RESET_CONTROL_COLD_RST_MASK 0x00000008 +#define AR6320_WLAN_RESET_CONTROL_WARM_RST_MASK 0x00000004 +#define AR6320_SI_CONFIG_BIDIR_OD_DATA_LSB 18 +#define AR6320_SI_CONFIG_BIDIR_OD_DATA_MASK 0x00040000 +#define AR6320_SI_CONFIG_I2C_LSB 16 +#define AR6320_SI_CONFIG_I2C_MASK 0x00010000 +#define AR6320_SI_CONFIG_POS_SAMPLE_LSB 7 +#define AR6320_SI_CONFIG_POS_SAMPLE_MASK 0x00000080 +#define AR6320_SI_CONFIG_INACTIVE_CLK_LSB 4 +#define AR6320_SI_CONFIG_INACTIVE_CLK_MASK 0x00000010 +#define AR6320_SI_CONFIG_INACTIVE_DATA_LSB 5 +#define AR6320_SI_CONFIG_INACTIVE_DATA_MASK 0x00000020 +#define AR6320_SI_CONFIG_DIVIDER_LSB 0 +#define AR6320_SI_CONFIG_DIVIDER_MASK 0x0000000f +#define AR6320_SI_CONFIG_OFFSET 0x00000000 +#define AR6320_SI_TX_DATA0_OFFSET 0x00000008 +#define AR6320_SI_TX_DATA1_OFFSET 0x0000000c +#define AR6320_SI_RX_DATA0_OFFSET 0x00000010 +#define AR6320_SI_RX_DATA1_OFFSET 0x00000014 +#define AR6320_SI_CS_OFFSET 0x00000004 +#define AR6320_SI_CS_DONE_ERR_MASK 0x00000400 +#define AR6320_SI_CS_DONE_INT_MASK 0x00000200 +#define AR6320_SI_CS_START_LSB 8 +#define AR6320_SI_CS_START_MASK 0x00000100 +#define AR6320_SI_CS_RX_CNT_LSB 4 +#define AR6320_SI_CS_RX_CNT_MASK 0x000000f0 +#define AR6320_SI_CS_TX_CNT_LSB 0 +#define AR6320_SI_CS_TX_CNT_MASK 0x0000000f +#define AR6320_SR_WR_INDEX_ADDRESS 0x003c +#define AR6320_DST_WATERMARK_ADDRESS 0x0050 +#define AR6320_RX_MSDU_END_4_FIRST_MSDU_LSB 14 +#define AR6320_RX_MSDU_END_4_FIRST_MSDU_MASK 0x00004000 +#define AR6320_RX_MPDU_START_0_RETRY_LSB 14 +#define AR6320_RX_MPDU_START_0_RETRY_MASK 0x00004000 +#define AR6320_RX_MPDU_START_0_SEQ_NUM_LSB 16 +#define AR6320_RX_MPDU_START_0_SEQ_NUM_MASK 0x0fff0000 +#define AR6320_RX_MPDU_START_2_TID_LSB 28 +#define AR6320_RX_MPDU_START_2_TID_MASK 0xf0000000 +#if defined(HIF_PCI) || defined(HIF_SNOC) || defined(HIF_AHB) +#define AR6320_SOC_PCIE_BASE_ADDRESS 0x00038000 +#define AR6320_CE_WRAPPER_BASE_ADDRESS 0x00034000 +#define AR6320_CE0_BASE_ADDRESS 0x00034400 +#define AR6320_CE1_BASE_ADDRESS 0x00034800 +#define AR6320_CE2_BASE_ADDRESS 0x00034c00 +#define AR6320_CE3_BASE_ADDRESS 0x00035000 +#define AR6320_CE4_BASE_ADDRESS 0x00035400 +#define AR6320_CE5_BASE_ADDRESS 0x00035800 +#define AR6320_CE6_BASE_ADDRESS 0x00035c00 +#define AR6320_CE7_BASE_ADDRESS 0x00036000 +#define AR6320_WLAN_ANALOG_INTF_PCIE_BASE_ADDRESS 0x00007800 +#define AR6320_CE_COUNT 8 +#define AR6320_CE_CTRL1_ADDRESS 0x0010 +#define AR6320_CE_CTRL1_DMAX_LENGTH_MASK 0x0000ffff +#define AR6320_CE_WRAPPER_INTERRUPT_SUMMARY_ADDRESS 0x0000 +#define AR6320_CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_MASK 0x0000ff00 +#define AR6320_CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_LSB 8 +#define AR6320_CE_CTRL1_DMAX_LENGTH_LSB 0 +#define AR6320_CE_CTRL1_SRC_RING_BYTE_SWAP_EN_MASK 0x00010000 +#define AR6320_CE_CTRL1_DST_RING_BYTE_SWAP_EN_MASK 0x00020000 +#define AR6320_CE_CTRL1_SRC_RING_BYTE_SWAP_EN_LSB 16 +#define AR6320_CE_CTRL1_DST_RING_BYTE_SWAP_EN_LSB 17 +#define AR6320_SOC_RESET_CONTROL_PCIE_RST_SHORT_OVRD_MASK 0x00000020 +#define AR6320_SOC_RESET_CONTROL_PCIE_RST_SHORT_OVRD_LSB 5 +#define AR6320_PCIE_SOC_WAKE_RESET 0x00000000 +#define AR6320_PCIE_SOC_WAKE_ADDRESS 0x0004 +#define AR6320_PCIE_SOC_WAKE_V_MASK 0x00000001 +#define AR6320_MUX_ID_MASK 0x0000 +#define AR6320_TRANSACTION_ID_MASK 0x3fff +#define AR6320_PCIE_LOCAL_BASE_ADDRESS 0x80000 +#define AR6320_FW_IND_HELPER 4 +#define AR6320_PCIE_INTR_ENABLE_ADDRESS 0x0008 +#define AR6320_PCIE_INTR_CLR_ADDRESS 0x0014 +#define AR6320_PCIE_INTR_FIRMWARE_MASK 0x00000400 +#define AR6320_PCIE_INTR_CE0_MASK 0x00000800 +#define AR6320_PCIE_INTR_CE_MASK_ALL 0x0007f800 +#define AR6320_PCIE_INTR_CAUSE_ADDRESS 0x000c +#define AR6320_SOC_RESET_CONTROL_CE_RST_MASK 0x00000001 +#endif +#define AR6320_RX_MPDU_START_2_PN_47_32_LSB 0 +#define AR6320_RX_MPDU_START_2_PN_47_32_MASK 0x0000ffff +#define AR6320_RX_MSDU_END_1_KEY_ID_OCT_MASK 0x000000ff +#define AR6320_RX_MSDU_END_1_KEY_ID_OCT_LSB 0 +#define AR6320_RX_MSDU_END_1_EXT_WAPI_PN_63_48_LSB 16 +#define AR6320_RX_MSDU_END_1_EXT_WAPI_PN_63_48_MASK 0xffff0000 +#define AR6320_RX_MSDU_END_4_LAST_MSDU_LSB 15 +#define AR6320_RX_MSDU_END_4_LAST_MSDU_MASK 0x00008000 +#define AR6320_RX_ATTENTION_0_MCAST_BCAST_LSB 2 +#define AR6320_RX_ATTENTION_0_MCAST_BCAST_MASK 0x00000004 +#define AR6320_RX_ATTENTION_0_FRAGMENT_LSB 13 +#define AR6320_RX_ATTENTION_0_FRAGMENT_MASK 0x00002000 +#define AR6320_RX_ATTENTION_0_MPDU_LENGTH_ERR_MASK 0x08000000 +#define AR6320_RX_FRAG_INFO_0_RING2_MORE_COUNT_LSB 16 +#define AR6320_RX_FRAG_INFO_0_RING2_MORE_COUNT_MASK 0x00ff0000 +#define AR6320_RX_MSDU_START_0_MSDU_LENGTH_LSB 0 +#define AR6320_RX_MSDU_START_0_MSDU_LENGTH_MASK 0x00003fff +#define AR6320_RX_MSDU_START_2_DECAP_FORMAT_OFFSET 0x00000008 +#define AR6320_RX_MSDU_START_2_DECAP_FORMAT_LSB 8 +#define AR6320_RX_MSDU_START_2_DECAP_FORMAT_MASK 0x00000300 +#define AR6320_RX_MPDU_START_0_ENCRYPTED_LSB 13 +#define AR6320_RX_MPDU_START_0_ENCRYPTED_MASK 0x00002000 +#define AR6320_RX_ATTENTION_0_MORE_DATA_MASK 0x00000400 +#define AR6320_RX_ATTENTION_0_MSDU_DONE_MASK 0x80000000 +#define AR6320_RX_ATTENTION_0_TCP_UDP_CHKSUM_FAIL_MASK 0x00040000 +#define AR6320_DST_WR_INDEX_ADDRESS 0x0040 +#define AR6320_SRC_WATERMARK_ADDRESS 0x004c +#define AR6320_SRC_WATERMARK_LOW_MASK 0xffff0000 +#define AR6320_SRC_WATERMARK_HIGH_MASK 0x0000ffff +#define AR6320_DST_WATERMARK_LOW_MASK 0xffff0000 +#define AR6320_DST_WATERMARK_HIGH_MASK 0x0000ffff +#define AR6320_CURRENT_SRRI_ADDRESS 0x0044 +#define AR6320_CURRENT_DRRI_ADDRESS 0x0048 +#define AR6320_HOST_IS_SRC_RING_HIGH_WATERMARK_MASK 0x00000002 +#define AR6320_HOST_IS_SRC_RING_LOW_WATERMARK_MASK 0x00000004 +#define AR6320_HOST_IS_DST_RING_HIGH_WATERMARK_MASK 0x00000008 +#define AR6320_HOST_IS_DST_RING_LOW_WATERMARK_MASK 0x00000010 +#define AR6320_HOST_IS_ADDRESS 0x0030 +#define AR6320_HOST_IS_COPY_COMPLETE_MASK 0x00000001 +#define AR6320_HOST_IE_ADDRESS 0x002c +#define AR6320_HOST_IE_COPY_COMPLETE_MASK 0x00000001 +#define AR6320_SR_BA_ADDRESS 0x0000 +#define AR6320_SR_SIZE_ADDRESS 0x0004 +#define AR6320_DR_BA_ADDRESS 0x0008 +#define AR6320_DR_SIZE_ADDRESS 0x000c +#define AR6320_MISC_IE_ADDRESS 0x0034 +#define AR6320_MISC_IS_AXI_ERR_MASK 0x00000400 +#define AR6320_MISC_IS_DST_ADDR_ERR_MASK 0x00000200 +#define AR6320_MISC_IS_SRC_LEN_ERR_MASK 0x00000100 +#define AR6320_MISC_IS_DST_MAX_LEN_VIO_MASK 0x00000080 +#define AR6320_MISC_IS_DST_RING_OVERFLOW_MASK 0x00000040 +#define AR6320_MISC_IS_SRC_RING_OVERFLOW_MASK 0x00000020 +#define AR6320_SRC_WATERMARK_LOW_LSB 16 +#define AR6320_SRC_WATERMARK_HIGH_LSB 0 +#define AR6320_DST_WATERMARK_LOW_LSB 16 +#define AR6320_DST_WATERMARK_HIGH_LSB 0 +#define AR6320_SOC_GLOBAL_RESET_ADDRESS 0x0008 +#define AR6320_RTC_STATE_ADDRESS 0x0000 +#define AR6320_RTC_STATE_COLD_RESET_MASK 0x00002000 +#define AR6320_RTC_STATE_V_MASK 0x00000007 +#define AR6320_RTC_STATE_V_LSB 0 +#define AR6320_RTC_STATE_V_ON 3 +#define AR6320_FW_IND_EVENT_PENDING 1 +#define AR6320_FW_IND_INITIALIZED 2 +#define AR6320_CPU_INTR_ADDRESS 0x0010 +#define AR6320_SOC_LF_TIMER_CONTROL0_ADDRESS 0x00000050 +#define AR6320_SOC_LF_TIMER_CONTROL0_ENABLE_MASK 0x00000004 +#define AR6320_SOC_RESET_CONTROL_ADDRESS 0x00000000 +#define AR6320_SOC_RESET_CONTROL_CPU_WARM_RST_MASK 0x00000040 +#define AR6320_CORE_CTRL_ADDRESS 0x0000 +#define AR6320_CORE_CTRL_CPU_INTR_MASK 0x00002000 +#define AR6320_LOCAL_SCRATCH_OFFSET 0x000000c0 +#define AR6320_CLOCK_GPIO_OFFSET 0xffffffff +#define AR6320_CLOCK_GPIO_BT_CLK_OUT_EN_LSB 0 +#define AR6320_CLOCK_GPIO_BT_CLK_OUT_EN_MASK 0 +#define AR6320_SOC_CHIP_ID_ADDRESS 0x000000f0 +#define AR6320_SOC_CHIP_ID_VERSION_MASK 0xfffc0000 +#define AR6320_SOC_CHIP_ID_VERSION_LSB 18 +#define AR6320_SOC_CHIP_ID_REVISION_MASK 0x00000f00 +#define AR6320_SOC_CHIP_ID_REVISION_LSB 8 +#if defined(HIF_PCI) || defined(HIF_SNOC) || defined(HIF_AHB) +#define AR6320_SOC_POWER_REG_OFFSET 0x0000010c +/* Copy Engine Debug */ +#define AR6320_WLAN_DEBUG_INPUT_SEL_OFFSET 0x0000010c +#define AR6320_WLAN_DEBUG_INPUT_SEL_SRC_MSB 3 +#define AR6320_WLAN_DEBUG_INPUT_SEL_SRC_LSB 0 +#define AR6320_WLAN_DEBUG_INPUT_SEL_SRC_MASK 0x0000000f +#define AR6320_WLAN_DEBUG_CONTROL_OFFSET 0x00000108 +#define AR6320_WLAN_DEBUG_CONTROL_ENABLE_MSB 0 +#define AR6320_WLAN_DEBUG_CONTROL_ENABLE_LSB 0 +#define AR6320_WLAN_DEBUG_CONTROL_ENABLE_MASK 0x00000001 +#define AR6320_WLAN_DEBUG_OUT_OFFSET 0x00000110 +#define AR6320_WLAN_DEBUG_OUT_DATA_MSB 19 +#define AR6320_WLAN_DEBUG_OUT_DATA_LSB 0 +#define AR6320_WLAN_DEBUG_OUT_DATA_MASK 0x000fffff +#define AR6320_AMBA_DEBUG_BUS_OFFSET 0x0000011c +#define AR6320_AMBA_DEBUG_BUS_PCIE_DEBUG_SEL_MSB 13 +#define AR6320_AMBA_DEBUG_BUS_PCIE_DEBUG_SEL_LSB 8 +#define AR6320_AMBA_DEBUG_BUS_PCIE_DEBUG_SEL_MASK 0x00003f00 +#define AR6320_AMBA_DEBUG_BUS_SEL_MSB 4 +#define AR6320_AMBA_DEBUG_BUS_SEL_LSB 0 +#define AR6320_AMBA_DEBUG_BUS_SEL_MASK 0x0000001f +#define AR6320_CE_WRAPPER_DEBUG_OFFSET 0x0008 +#define AR6320_CE_WRAPPER_DEBUG_SEL_MSB 5 +#define AR6320_CE_WRAPPER_DEBUG_SEL_LSB 0 +#define AR6320_CE_WRAPPER_DEBUG_SEL_MASK 0x0000003f +#define AR6320_CE_DEBUG_OFFSET 0x0054 +#define AR6320_CE_DEBUG_SEL_MSB 5 +#define AR6320_CE_DEBUG_SEL_LSB 0 +#define AR6320_CE_DEBUG_SEL_MASK 0x0000003f +/* End */ + +/* PLL start */ +#define AR6320_EFUSE_OFFSET 0x0000032c +#define AR6320_EFUSE_XTAL_SEL_MSB 10 +#define AR6320_EFUSE_XTAL_SEL_LSB 8 +#define AR6320_EFUSE_XTAL_SEL_MASK 0x00000700 +#define AR6320_BB_PLL_CONFIG_OFFSET 0x000002f4 +#define AR6320_BB_PLL_CONFIG_OUTDIV_MSB 20 +#define AR6320_BB_PLL_CONFIG_OUTDIV_LSB 18 +#define AR6320_BB_PLL_CONFIG_OUTDIV_MASK 0x001c0000 +#define AR6320_BB_PLL_CONFIG_FRAC_MSB 17 +#define AR6320_BB_PLL_CONFIG_FRAC_LSB 0 +#define AR6320_BB_PLL_CONFIG_FRAC_MASK 0x0003ffff +#define AR6320_WLAN_PLL_SETTLE_TIME_MSB 10 +#define AR6320_WLAN_PLL_SETTLE_TIME_LSB 0 +#define AR6320_WLAN_PLL_SETTLE_TIME_MASK 0x000007ff +#define AR6320_WLAN_PLL_SETTLE_OFFSET 0x0018 +#define AR6320_WLAN_PLL_SETTLE_SW_MASK 0x000007ff +#define AR6320_WLAN_PLL_SETTLE_RSTMASK 0xffffffff +#define AR6320_WLAN_PLL_SETTLE_RESET 0x00000400 +#define AR6320_WLAN_PLL_CONTROL_NOPWD_MSB 18 +#define AR6320_WLAN_PLL_CONTROL_NOPWD_LSB 18 +#define AR6320_WLAN_PLL_CONTROL_NOPWD_MASK 0x00040000 +#define AR6320_WLAN_PLL_CONTROL_BYPASS_MSB 16 +#define AR6320_WLAN_PLL_CONTROL_BYPASS_LSB 16 +#define AR6320_WLAN_PLL_CONTROL_BYPASS_MASK 0x00010000 +#define AR6320_WLAN_PLL_CONTROL_BYPASS_RESET 0x1 +#define AR6320_WLAN_PLL_CONTROL_CLK_SEL_MSB 15 +#define AR6320_WLAN_PLL_CONTROL_CLK_SEL_LSB 14 +#define AR6320_WLAN_PLL_CONTROL_CLK_SEL_MASK 0x0000c000 +#define AR6320_WLAN_PLL_CONTROL_CLK_SEL_RESET 0x0 +#define AR6320_WLAN_PLL_CONTROL_REFDIV_MSB 13 +#define AR6320_WLAN_PLL_CONTROL_REFDIV_LSB 10 +#define AR6320_WLAN_PLL_CONTROL_REFDIV_MASK 0x00003c00 +#define AR6320_WLAN_PLL_CONTROL_REFDIV_RESET 0x0 +#define AR6320_WLAN_PLL_CONTROL_DIV_MSB 9 +#define AR6320_WLAN_PLL_CONTROL_DIV_LSB 0 +#define AR6320_WLAN_PLL_CONTROL_DIV_MASK 0x000003ff +#define AR6320_WLAN_PLL_CONTROL_DIV_RESET 0x11 +#define AR6320_WLAN_PLL_CONTROL_OFFSET 0x0014 +#define AR6320_WLAN_PLL_CONTROL_SW_MASK 0x001fffff +#define AR6320_WLAN_PLL_CONTROL_RSTMASK 0xffffffff +#define AR6320_WLAN_PLL_CONTROL_RESET 0x00010011 +#define AR6320_SOC_CORE_CLK_CTRL_OFFSET 0x00000114 +#define AR6320_SOC_CORE_CLK_CTRL_DIV_MSB 2 +#define AR6320_SOC_CORE_CLK_CTRL_DIV_LSB 0 +#define AR6320_SOC_CORE_CLK_CTRL_DIV_MASK 0x00000007 +#define AR6320_RTC_SYNC_STATUS_PLL_CHANGING_MSB 5 +#define AR6320_RTC_SYNC_STATUS_PLL_CHANGING_LSB 5 +#define AR6320_RTC_SYNC_STATUS_PLL_CHANGING_MASK 0x00000020 +#define AR6320_RTC_SYNC_STATUS_PLL_CHANGING_RESET 0x0 +#define AR6320_RTC_SYNC_STATUS_OFFSET 0x0244 +#define AR6320_SOC_CPU_CLOCK_OFFSET 0x00000020 +#define AR6320_SOC_CPU_CLOCK_STANDARD_MSB 1 +#define AR6320_SOC_CPU_CLOCK_STANDARD_LSB 0 +#define AR6320_SOC_CPU_CLOCK_STANDARD_MASK 0x00000003 +/* PLL end */ +#define AR6320_PCIE_INTR_CE_MASK(n) \ + (AR6320_PCIE_INTR_CE0_MASK << (n)) +#endif +#define AR6320_DRAM_BASE_ADDRESS AR6320_TARG_DRAM_START +#define AR6320_FW_INDICATOR_ADDRESS \ + (AR6320_SOC_CORE_BASE_ADDRESS + AR6320_SCRATCH_3_ADDRESS) +#define AR6320_SYSTEM_SLEEP_OFFSET AR6320_SOC_SYSTEM_SLEEP_OFFSET +#define AR6320_WLAN_SYSTEM_SLEEP_OFFSET 0x002c +#define AR6320_WLAN_RESET_CONTROL_OFFSET AR6320_SOC_RESET_CONTROL_OFFSET +#define AR6320_CLOCK_CONTROL_OFFSET AR6320_SOC_CLOCK_CONTROL_OFFSET +#define AR6320_CLOCK_CONTROL_SI0_CLK_MASK AR6320_SOC_CLOCK_CONTROL_SI0_CLK_MASK +#define AR6320_RESET_CONTROL_MBOX_RST_MASK 0x00000004 +#define AR6320_RESET_CONTROL_SI0_RST_MASK AR6320_SOC_RESET_CONTROL_SI0_RST_MASK +#define AR6320_GPIO_BASE_ADDRESS AR6320_WLAN_GPIO_BASE_ADDRESS +#define AR6320_GPIO_PIN0_OFFSET AR6320_WLAN_GPIO_PIN0_ADDRESS +#define AR6320_GPIO_PIN1_OFFSET AR6320_WLAN_GPIO_PIN1_ADDRESS +#define AR6320_GPIO_PIN0_CONFIG_MASK AR6320_WLAN_GPIO_PIN0_CONFIG_MASK +#define AR6320_GPIO_PIN1_CONFIG_MASK AR6320_WLAN_GPIO_PIN1_CONFIG_MASK +#define AR6320_SI_BASE_ADDRESS 0x00050000 +#define AR6320_CPU_CLOCK_OFFSET AR6320_SOC_CPU_CLOCK_OFFSET +#define AR6320_LPO_CAL_OFFSET AR6320_SOC_LPO_CAL_OFFSET +#define AR6320_GPIO_PIN10_OFFSET AR6320_WLAN_GPIO_PIN10_ADDRESS +#define AR6320_GPIO_PIN11_OFFSET AR6320_WLAN_GPIO_PIN11_ADDRESS +#define AR6320_GPIO_PIN12_OFFSET AR6320_WLAN_GPIO_PIN12_ADDRESS +#define AR6320_GPIO_PIN13_OFFSET AR6320_WLAN_GPIO_PIN13_ADDRESS +#define AR6320_CPU_CLOCK_STANDARD_LSB AR6320_SOC_CPU_CLOCK_STANDARD_LSB +#define AR6320_CPU_CLOCK_STANDARD_MASK AR6320_SOC_CPU_CLOCK_STANDARD_MASK +#define AR6320_LPO_CAL_ENABLE_LSB AR6320_SOC_LPO_CAL_ENABLE_LSB +#define AR6320_LPO_CAL_ENABLE_MASK AR6320_SOC_LPO_CAL_ENABLE_MASK +#define AR6320_ANALOG_INTF_BASE_ADDRESS AR6320_WLAN_ANALOG_INTF_BASE_ADDRESS +#define AR6320_MBOX_BASE_ADDRESS 0x00008000 +#define AR6320_INT_STATUS_ENABLE_ERROR_LSB 7 +#define AR6320_INT_STATUS_ENABLE_ERROR_MASK 0x00000080 +#define AR6320_INT_STATUS_ENABLE_CPU_LSB 6 +#define AR6320_INT_STATUS_ENABLE_CPU_MASK 0x00000040 +#define AR6320_INT_STATUS_ENABLE_COUNTER_LSB 4 +#define AR6320_INT_STATUS_ENABLE_COUNTER_MASK 0x00000010 +#define AR6320_INT_STATUS_ENABLE_MBOX_DATA_LSB 0 +#define AR6320_INT_STATUS_ENABLE_MBOX_DATA_MASK 0x0000000f +#define AR6320_ERROR_STATUS_ENABLE_RX_UNDERFLOW_LSB 17 +#define AR6320_ERROR_STATUS_ENABLE_RX_UNDERFLOW_MASK 0x00020000 +#define AR6320_ERROR_STATUS_ENABLE_TX_OVERFLOW_LSB 16 +#define AR6320_ERROR_STATUS_ENABLE_TX_OVERFLOW_MASK 0x00010000 +#define AR6320_COUNTER_INT_STATUS_ENABLE_BIT_LSB 24 +#define AR6320_COUNTER_INT_STATUS_ENABLE_BIT_MASK 0xff000000 +#define AR6320_INT_STATUS_ENABLE_ADDRESS 0x0828 +#define AR6320_CPU_INT_STATUS_ENABLE_BIT_LSB 8 +#define AR6320_CPU_INT_STATUS_ENABLE_BIT_MASK 0x0000ff00 +#define AR6320_HOST_INT_STATUS_ADDRESS 0x0800 +#define AR6320_CPU_INT_STATUS_ADDRESS 0x0801 +#define AR6320_ERROR_INT_STATUS_ADDRESS 0x0802 +#define AR6320_ERROR_INT_STATUS_WAKEUP_MASK 0x00040000 +#define AR6320_ERROR_INT_STATUS_WAKEUP_LSB 18 +#define AR6320_ERROR_INT_STATUS_RX_UNDERFLOW_MASK 0x00020000 +#define AR6320_ERROR_INT_STATUS_RX_UNDERFLOW_LSB 17 +#define AR6320_ERROR_INT_STATUS_TX_OVERFLOW_MASK 0x00010000 +#define AR6320_ERROR_INT_STATUS_TX_OVERFLOW_LSB 16 +#define AR6320_COUNT_DEC_ADDRESS 0x0840 +#define AR6320_HOST_INT_STATUS_CPU_MASK 0x00000040 +#define AR6320_HOST_INT_STATUS_CPU_LSB 6 +#define AR6320_HOST_INT_STATUS_ERROR_MASK 0x00000080 +#define AR6320_HOST_INT_STATUS_ERROR_LSB 7 +#define AR6320_HOST_INT_STATUS_COUNTER_MASK 0x00000010 +#define AR6320_HOST_INT_STATUS_COUNTER_LSB 4 +#define AR6320_RX_LOOKAHEAD_VALID_ADDRESS 0x0805 +#define AR6320_WINDOW_DATA_ADDRESS 0x0874 +#define AR6320_WINDOW_READ_ADDR_ADDRESS 0x087c +#define AR6320_WINDOW_WRITE_ADDR_ADDRESS 0x0878 +#define AR6320_HOST_INT_STATUS_MBOX_DATA_MASK 0x0f +#define AR6320_HOST_INT_STATUS_MBOX_DATA_LSB 0 + +struct targetdef_s ar6320_targetdef = { + .d_RTC_SOC_BASE_ADDRESS = AR6320_RTC_SOC_BASE_ADDRESS, + .d_RTC_WMAC_BASE_ADDRESS = AR6320_RTC_WMAC_BASE_ADDRESS, + .d_SYSTEM_SLEEP_OFFSET = AR6320_WLAN_SYSTEM_SLEEP_OFFSET, + .d_WLAN_SYSTEM_SLEEP_OFFSET = AR6320_WLAN_SYSTEM_SLEEP_OFFSET, + .d_WLAN_SYSTEM_SLEEP_DISABLE_LSB = + AR6320_WLAN_SYSTEM_SLEEP_DISABLE_LSB, + .d_WLAN_SYSTEM_SLEEP_DISABLE_MASK = + AR6320_WLAN_SYSTEM_SLEEP_DISABLE_MASK, + .d_CLOCK_CONTROL_OFFSET = AR6320_CLOCK_CONTROL_OFFSET, + .d_CLOCK_CONTROL_SI0_CLK_MASK = AR6320_CLOCK_CONTROL_SI0_CLK_MASK, + .d_RESET_CONTROL_OFFSET = AR6320_SOC_RESET_CONTROL_OFFSET, + .d_RESET_CONTROL_MBOX_RST_MASK = AR6320_RESET_CONTROL_MBOX_RST_MASK, + .d_RESET_CONTROL_SI0_RST_MASK = AR6320_RESET_CONTROL_SI0_RST_MASK, + .d_WLAN_RESET_CONTROL_OFFSET = AR6320_WLAN_RESET_CONTROL_OFFSET, + .d_WLAN_RESET_CONTROL_COLD_RST_MASK = + AR6320_WLAN_RESET_CONTROL_COLD_RST_MASK, + .d_WLAN_RESET_CONTROL_WARM_RST_MASK = + AR6320_WLAN_RESET_CONTROL_WARM_RST_MASK, + .d_GPIO_BASE_ADDRESS = AR6320_GPIO_BASE_ADDRESS, + .d_GPIO_PIN0_OFFSET = AR6320_GPIO_PIN0_OFFSET, + .d_GPIO_PIN1_OFFSET = AR6320_GPIO_PIN1_OFFSET, + .d_GPIO_PIN0_CONFIG_MASK = AR6320_GPIO_PIN0_CONFIG_MASK, + .d_GPIO_PIN1_CONFIG_MASK = AR6320_GPIO_PIN1_CONFIG_MASK, + .d_SI_CONFIG_BIDIR_OD_DATA_LSB = AR6320_SI_CONFIG_BIDIR_OD_DATA_LSB, + .d_SI_CONFIG_BIDIR_OD_DATA_MASK = AR6320_SI_CONFIG_BIDIR_OD_DATA_MASK, + .d_SI_CONFIG_I2C_LSB = AR6320_SI_CONFIG_I2C_LSB, + .d_SI_CONFIG_I2C_MASK = AR6320_SI_CONFIG_I2C_MASK, + .d_SI_CONFIG_POS_SAMPLE_LSB = AR6320_SI_CONFIG_POS_SAMPLE_LSB, + .d_SI_CONFIG_POS_SAMPLE_MASK = AR6320_SI_CONFIG_POS_SAMPLE_MASK, + .d_SI_CONFIG_INACTIVE_CLK_LSB = AR6320_SI_CONFIG_INACTIVE_CLK_LSB, + .d_SI_CONFIG_INACTIVE_CLK_MASK = AR6320_SI_CONFIG_INACTIVE_CLK_MASK, + .d_SI_CONFIG_INACTIVE_DATA_LSB = AR6320_SI_CONFIG_INACTIVE_DATA_LSB, + .d_SI_CONFIG_INACTIVE_DATA_MASK = AR6320_SI_CONFIG_INACTIVE_DATA_MASK, + .d_SI_CONFIG_DIVIDER_LSB = AR6320_SI_CONFIG_DIVIDER_LSB, + .d_SI_CONFIG_DIVIDER_MASK = AR6320_SI_CONFIG_DIVIDER_MASK, + .d_SI_BASE_ADDRESS = AR6320_SI_BASE_ADDRESS, + .d_SI_CONFIG_OFFSET = AR6320_SI_CONFIG_OFFSET, + .d_SI_TX_DATA0_OFFSET = AR6320_SI_TX_DATA0_OFFSET, + .d_SI_TX_DATA1_OFFSET = AR6320_SI_TX_DATA1_OFFSET, + .d_SI_RX_DATA0_OFFSET = AR6320_SI_RX_DATA0_OFFSET, + .d_SI_RX_DATA1_OFFSET = AR6320_SI_RX_DATA1_OFFSET, + .d_SI_CS_OFFSET = AR6320_SI_CS_OFFSET, + .d_SI_CS_DONE_ERR_MASK = AR6320_SI_CS_DONE_ERR_MASK, + .d_SI_CS_DONE_INT_MASK = AR6320_SI_CS_DONE_INT_MASK, + .d_SI_CS_START_LSB = AR6320_SI_CS_START_LSB, + .d_SI_CS_START_MASK = AR6320_SI_CS_START_MASK, + .d_SI_CS_RX_CNT_LSB = AR6320_SI_CS_RX_CNT_LSB, + .d_SI_CS_RX_CNT_MASK = AR6320_SI_CS_RX_CNT_MASK, + .d_SI_CS_TX_CNT_LSB = AR6320_SI_CS_TX_CNT_LSB, + .d_SI_CS_TX_CNT_MASK = AR6320_SI_CS_TX_CNT_MASK, + .d_BOARD_DATA_SZ = AR6320_BOARD_DATA_SZ, + .d_BOARD_EXT_DATA_SZ = AR6320_BOARD_EXT_DATA_SZ, + .d_MBOX_BASE_ADDRESS = AR6320_MBOX_BASE_ADDRESS, + .d_LOCAL_SCRATCH_OFFSET = AR6320_LOCAL_SCRATCH_OFFSET, + .d_CPU_CLOCK_OFFSET = AR6320_CPU_CLOCK_OFFSET, + .d_LPO_CAL_OFFSET = AR6320_LPO_CAL_OFFSET, + .d_GPIO_PIN10_OFFSET = AR6320_GPIO_PIN10_OFFSET, + .d_GPIO_PIN11_OFFSET = AR6320_GPIO_PIN11_OFFSET, + .d_GPIO_PIN12_OFFSET = AR6320_GPIO_PIN12_OFFSET, + .d_GPIO_PIN13_OFFSET = AR6320_GPIO_PIN13_OFFSET, + .d_CLOCK_GPIO_OFFSET = AR6320_CLOCK_GPIO_OFFSET, + .d_CPU_CLOCK_STANDARD_LSB = AR6320_CPU_CLOCK_STANDARD_LSB, + .d_CPU_CLOCK_STANDARD_MASK = AR6320_CPU_CLOCK_STANDARD_MASK, + .d_LPO_CAL_ENABLE_LSB = AR6320_LPO_CAL_ENABLE_LSB, + .d_LPO_CAL_ENABLE_MASK = AR6320_LPO_CAL_ENABLE_MASK, + .d_CLOCK_GPIO_BT_CLK_OUT_EN_LSB = AR6320_CLOCK_GPIO_BT_CLK_OUT_EN_LSB, + .d_CLOCK_GPIO_BT_CLK_OUT_EN_MASK = + AR6320_CLOCK_GPIO_BT_CLK_OUT_EN_MASK, + .d_ANALOG_INTF_BASE_ADDRESS = AR6320_ANALOG_INTF_BASE_ADDRESS, + .d_WLAN_MAC_BASE_ADDRESS = AR6320_WLAN_MAC_BASE_ADDRESS, + .d_FW_INDICATOR_ADDRESS = AR6320_FW_INDICATOR_ADDRESS, + .d_DRAM_BASE_ADDRESS = AR6320_DRAM_BASE_ADDRESS, + .d_SOC_CORE_BASE_ADDRESS = AR6320_SOC_CORE_BASE_ADDRESS, + .d_CORE_CTRL_ADDRESS = AR6320_CORE_CTRL_ADDRESS, +#if defined(HIF_PCI) || defined(HIF_SNOC) || defined(HIF_AHB) + .d_MSI_NUM_REQUEST = MSI_NUM_REQUEST, + .d_MSI_ASSIGN_FW = MSI_ASSIGN_FW, +#endif + .d_CORE_CTRL_CPU_INTR_MASK = AR6320_CORE_CTRL_CPU_INTR_MASK, + .d_SR_WR_INDEX_ADDRESS = AR6320_SR_WR_INDEX_ADDRESS, + .d_DST_WATERMARK_ADDRESS = AR6320_DST_WATERMARK_ADDRESS, + /* htt_rx.c */ + .d_RX_MSDU_END_4_FIRST_MSDU_MASK = + AR6320_RX_MSDU_END_4_FIRST_MSDU_MASK, + .d_RX_MSDU_END_4_FIRST_MSDU_LSB = AR6320_RX_MSDU_END_4_FIRST_MSDU_LSB, + .d_RX_MPDU_START_0_RETRY_LSB = AR6320_RX_MPDU_START_0_RETRY_LSB, + .d_RX_MPDU_START_0_RETRY_MASK = AR6320_RX_MPDU_START_0_RETRY_MASK, + .d_RX_MPDU_START_0_SEQ_NUM_MASK = AR6320_RX_MPDU_START_0_SEQ_NUM_MASK, + .d_RX_MPDU_START_0_SEQ_NUM_LSB = AR6320_RX_MPDU_START_0_SEQ_NUM_LSB, + .d_RX_MPDU_START_2_PN_47_32_LSB = AR6320_RX_MPDU_START_2_PN_47_32_LSB, + .d_RX_MPDU_START_2_PN_47_32_MASK = + AR6320_RX_MPDU_START_2_PN_47_32_MASK, + .d_RX_MPDU_START_2_TID_LSB = AR6320_RX_MPDU_START_2_TID_LSB, + .d_RX_MPDU_START_2_TID_MASK = AR6320_RX_MPDU_START_2_TID_MASK, + .d_RX_MSDU_END_1_KEY_ID_OCT_MASK = + AR6320_RX_MSDU_END_1_KEY_ID_OCT_MASK, + .d_RX_MSDU_END_1_KEY_ID_OCT_LSB = AR6320_RX_MSDU_END_1_KEY_ID_OCT_LSB, + .d_RX_MSDU_END_1_EXT_WAPI_PN_63_48_MASK = + AR6320_RX_MSDU_END_1_EXT_WAPI_PN_63_48_MASK, + .d_RX_MSDU_END_1_EXT_WAPI_PN_63_48_LSB = + AR6320_RX_MSDU_END_1_EXT_WAPI_PN_63_48_LSB, + .d_RX_MSDU_END_4_LAST_MSDU_MASK = AR6320_RX_MSDU_END_4_LAST_MSDU_MASK, + .d_RX_MSDU_END_4_LAST_MSDU_LSB = AR6320_RX_MSDU_END_4_LAST_MSDU_LSB, + .d_RX_ATTENTION_0_MCAST_BCAST_MASK = + AR6320_RX_ATTENTION_0_MCAST_BCAST_MASK, + .d_RX_ATTENTION_0_MCAST_BCAST_LSB = + AR6320_RX_ATTENTION_0_MCAST_BCAST_LSB, + .d_RX_ATTENTION_0_FRAGMENT_MASK = AR6320_RX_ATTENTION_0_FRAGMENT_MASK, + .d_RX_ATTENTION_0_FRAGMENT_LSB = AR6320_RX_ATTENTION_0_FRAGMENT_LSB, + .d_RX_ATTENTION_0_MPDU_LENGTH_ERR_MASK = + AR6320_RX_ATTENTION_0_MPDU_LENGTH_ERR_MASK, + .d_RX_FRAG_INFO_0_RING2_MORE_COUNT_MASK = + AR6320_RX_FRAG_INFO_0_RING2_MORE_COUNT_MASK, + .d_RX_FRAG_INFO_0_RING2_MORE_COUNT_LSB = + AR6320_RX_FRAG_INFO_0_RING2_MORE_COUNT_LSB, + .d_RX_MSDU_START_0_MSDU_LENGTH_MASK = + AR6320_RX_MSDU_START_0_MSDU_LENGTH_MASK, + .d_RX_MSDU_START_0_MSDU_LENGTH_LSB = + AR6320_RX_MSDU_START_0_MSDU_LENGTH_LSB, + .d_RX_MSDU_START_2_DECAP_FORMAT_OFFSET = + AR6320_RX_MSDU_START_2_DECAP_FORMAT_OFFSET, + .d_RX_MSDU_START_2_DECAP_FORMAT_MASK = + AR6320_RX_MSDU_START_2_DECAP_FORMAT_MASK, + .d_RX_MSDU_START_2_DECAP_FORMAT_LSB = + AR6320_RX_MSDU_START_2_DECAP_FORMAT_LSB, + .d_RX_MPDU_START_0_ENCRYPTED_MASK = + AR6320_RX_MPDU_START_0_ENCRYPTED_MASK, + .d_RX_MPDU_START_0_ENCRYPTED_LSB = + AR6320_RX_MPDU_START_0_ENCRYPTED_LSB, + .d_RX_ATTENTION_0_MORE_DATA_MASK = + AR6320_RX_ATTENTION_0_MORE_DATA_MASK, + .d_RX_ATTENTION_0_MSDU_DONE_MASK = + AR6320_RX_ATTENTION_0_MSDU_DONE_MASK, + .d_RX_ATTENTION_0_TCP_UDP_CHKSUM_FAIL_MASK = + AR6320_RX_ATTENTION_0_TCP_UDP_CHKSUM_FAIL_MASK, +#if defined(HIF_PCI) || defined(HIF_SNOC) || defined(HIF_AHB) + .d_CE_COUNT = AR6320_CE_COUNT, + .d_MSI_ASSIGN_CE_INITIAL = MSI_ASSIGN_CE_INITIAL, + .d_PCIE_INTR_ENABLE_ADDRESS = AR6320_PCIE_INTR_ENABLE_ADDRESS, + .d_PCIE_INTR_CLR_ADDRESS = AR6320_PCIE_INTR_CLR_ADDRESS, + .d_PCIE_INTR_FIRMWARE_MASK = AR6320_PCIE_INTR_FIRMWARE_MASK, + .d_PCIE_INTR_CE_MASK_ALL = AR6320_PCIE_INTR_CE_MASK_ALL, + /* PLL start */ + .d_EFUSE_OFFSET = AR6320_EFUSE_OFFSET, + .d_EFUSE_XTAL_SEL_MSB = AR6320_EFUSE_XTAL_SEL_MSB, + .d_EFUSE_XTAL_SEL_LSB = AR6320_EFUSE_XTAL_SEL_LSB, + .d_EFUSE_XTAL_SEL_MASK = AR6320_EFUSE_XTAL_SEL_MASK, + .d_BB_PLL_CONFIG_OFFSET = AR6320_BB_PLL_CONFIG_OFFSET, + .d_BB_PLL_CONFIG_OUTDIV_MSB = AR6320_BB_PLL_CONFIG_OUTDIV_MSB, + .d_BB_PLL_CONFIG_OUTDIV_LSB = AR6320_BB_PLL_CONFIG_OUTDIV_LSB, + .d_BB_PLL_CONFIG_OUTDIV_MASK = AR6320_BB_PLL_CONFIG_OUTDIV_MASK, + .d_BB_PLL_CONFIG_FRAC_MSB = AR6320_BB_PLL_CONFIG_FRAC_MSB, + .d_BB_PLL_CONFIG_FRAC_LSB = AR6320_BB_PLL_CONFIG_FRAC_LSB, + .d_BB_PLL_CONFIG_FRAC_MASK = AR6320_BB_PLL_CONFIG_FRAC_MASK, + .d_WLAN_PLL_SETTLE_TIME_MSB = AR6320_WLAN_PLL_SETTLE_TIME_MSB, + .d_WLAN_PLL_SETTLE_TIME_LSB = AR6320_WLAN_PLL_SETTLE_TIME_LSB, + .d_WLAN_PLL_SETTLE_TIME_MASK = AR6320_WLAN_PLL_SETTLE_TIME_MASK, + .d_WLAN_PLL_SETTLE_OFFSET = AR6320_WLAN_PLL_SETTLE_OFFSET, + .d_WLAN_PLL_SETTLE_SW_MASK = AR6320_WLAN_PLL_SETTLE_SW_MASK, + .d_WLAN_PLL_SETTLE_RSTMASK = AR6320_WLAN_PLL_SETTLE_RSTMASK, + .d_WLAN_PLL_SETTLE_RESET = AR6320_WLAN_PLL_SETTLE_RESET, + .d_WLAN_PLL_CONTROL_NOPWD_MSB = AR6320_WLAN_PLL_CONTROL_NOPWD_MSB, + .d_WLAN_PLL_CONTROL_NOPWD_LSB = AR6320_WLAN_PLL_CONTROL_NOPWD_LSB, + .d_WLAN_PLL_CONTROL_NOPWD_MASK = AR6320_WLAN_PLL_CONTROL_NOPWD_MASK, + .d_WLAN_PLL_CONTROL_BYPASS_MSB = AR6320_WLAN_PLL_CONTROL_BYPASS_MSB, + .d_WLAN_PLL_CONTROL_BYPASS_LSB = AR6320_WLAN_PLL_CONTROL_BYPASS_LSB, + .d_WLAN_PLL_CONTROL_BYPASS_MASK = AR6320_WLAN_PLL_CONTROL_BYPASS_MASK, + .d_WLAN_PLL_CONTROL_BYPASS_RESET = + AR6320_WLAN_PLL_CONTROL_BYPASS_RESET, + .d_WLAN_PLL_CONTROL_CLK_SEL_MSB = AR6320_WLAN_PLL_CONTROL_CLK_SEL_MSB, + .d_WLAN_PLL_CONTROL_CLK_SEL_LSB = AR6320_WLAN_PLL_CONTROL_CLK_SEL_LSB, + .d_WLAN_PLL_CONTROL_CLK_SEL_MASK = + AR6320_WLAN_PLL_CONTROL_CLK_SEL_MASK, + .d_WLAN_PLL_CONTROL_CLK_SEL_RESET = + AR6320_WLAN_PLL_CONTROL_CLK_SEL_RESET, + .d_WLAN_PLL_CONTROL_REFDIV_MSB = AR6320_WLAN_PLL_CONTROL_REFDIV_MSB, + .d_WLAN_PLL_CONTROL_REFDIV_LSB = AR6320_WLAN_PLL_CONTROL_REFDIV_LSB, + .d_WLAN_PLL_CONTROL_REFDIV_MASK = AR6320_WLAN_PLL_CONTROL_REFDIV_MASK, + .d_WLAN_PLL_CONTROL_REFDIV_RESET = + AR6320_WLAN_PLL_CONTROL_REFDIV_RESET, + .d_WLAN_PLL_CONTROL_DIV_MSB = AR6320_WLAN_PLL_CONTROL_DIV_MSB, + .d_WLAN_PLL_CONTROL_DIV_LSB = AR6320_WLAN_PLL_CONTROL_DIV_LSB, + .d_WLAN_PLL_CONTROL_DIV_MASK = AR6320_WLAN_PLL_CONTROL_DIV_MASK, + .d_WLAN_PLL_CONTROL_DIV_RESET = AR6320_WLAN_PLL_CONTROL_DIV_RESET, + .d_WLAN_PLL_CONTROL_OFFSET = AR6320_WLAN_PLL_CONTROL_OFFSET, + .d_WLAN_PLL_CONTROL_SW_MASK = AR6320_WLAN_PLL_CONTROL_SW_MASK, + .d_WLAN_PLL_CONTROL_RSTMASK = AR6320_WLAN_PLL_CONTROL_RSTMASK, + .d_WLAN_PLL_CONTROL_RESET = AR6320_WLAN_PLL_CONTROL_RESET, + .d_SOC_CORE_CLK_CTRL_OFFSET = AR6320_SOC_CORE_CLK_CTRL_OFFSET, + .d_SOC_CORE_CLK_CTRL_DIV_MSB = AR6320_SOC_CORE_CLK_CTRL_DIV_MSB, + .d_SOC_CORE_CLK_CTRL_DIV_LSB = AR6320_SOC_CORE_CLK_CTRL_DIV_LSB, + .d_SOC_CORE_CLK_CTRL_DIV_MASK = AR6320_SOC_CORE_CLK_CTRL_DIV_MASK, + .d_RTC_SYNC_STATUS_PLL_CHANGING_MSB = + AR6320_RTC_SYNC_STATUS_PLL_CHANGING_MSB, + .d_RTC_SYNC_STATUS_PLL_CHANGING_LSB = + AR6320_RTC_SYNC_STATUS_PLL_CHANGING_LSB, + .d_RTC_SYNC_STATUS_PLL_CHANGING_MASK = + AR6320_RTC_SYNC_STATUS_PLL_CHANGING_MASK, + .d_RTC_SYNC_STATUS_PLL_CHANGING_RESET = + AR6320_RTC_SYNC_STATUS_PLL_CHANGING_RESET, + .d_RTC_SYNC_STATUS_OFFSET = AR6320_RTC_SYNC_STATUS_OFFSET, + .d_SOC_CPU_CLOCK_OFFSET = AR6320_SOC_CPU_CLOCK_OFFSET, + .d_SOC_CPU_CLOCK_STANDARD_MSB = AR6320_SOC_CPU_CLOCK_STANDARD_MSB, + .d_SOC_CPU_CLOCK_STANDARD_LSB = AR6320_SOC_CPU_CLOCK_STANDARD_LSB, + .d_SOC_CPU_CLOCK_STANDARD_MASK = AR6320_SOC_CPU_CLOCK_STANDARD_MASK, + /* PLL end */ + .d_SOC_POWER_REG_OFFSET = AR6320_SOC_POWER_REG_OFFSET, + .d_PCIE_INTR_CAUSE_ADDRESS = AR6320_PCIE_INTR_CAUSE_ADDRESS, + .d_SOC_RESET_CONTROL_ADDRESS = AR6320_SOC_RESET_CONTROL_ADDRESS, + .d_SOC_RESET_CONTROL_PCIE_RST_SHORT_OVRD_MASK = + AR6320_SOC_RESET_CONTROL_PCIE_RST_SHORT_OVRD_MASK, + .d_SOC_RESET_CONTROL_PCIE_RST_SHORT_OVRD_LSB = + AR6320_SOC_RESET_CONTROL_PCIE_RST_SHORT_OVRD_LSB, + .d_SOC_RESET_CONTROL_CE_RST_MASK = + AR6320_SOC_RESET_CONTROL_CE_RST_MASK, + .d_SOC_RESET_CONTROL_CPU_WARM_RST_MASK = + AR6320_SOC_RESET_CONTROL_CPU_WARM_RST_MASK, + .d_CPU_INTR_ADDRESS = AR6320_CPU_INTR_ADDRESS, + .d_SOC_LF_TIMER_CONTROL0_ADDRESS = + AR6320_SOC_LF_TIMER_CONTROL0_ADDRESS, + .d_SOC_LF_TIMER_CONTROL0_ENABLE_MASK = + AR6320_SOC_LF_TIMER_CONTROL0_ENABLE_MASK, + + .d_WLAN_DEBUG_INPUT_SEL_OFFSET = AR6320_WLAN_DEBUG_INPUT_SEL_OFFSET, + .d_WLAN_DEBUG_INPUT_SEL_SRC_MSB = AR6320_WLAN_DEBUG_INPUT_SEL_SRC_MSB, + .d_WLAN_DEBUG_INPUT_SEL_SRC_LSB = AR6320_WLAN_DEBUG_INPUT_SEL_SRC_LSB, + .d_WLAN_DEBUG_INPUT_SEL_SRC_MASK = + AR6320_WLAN_DEBUG_INPUT_SEL_SRC_MASK, + .d_WLAN_DEBUG_CONTROL_OFFSET = AR6320_WLAN_DEBUG_CONTROL_OFFSET, + .d_WLAN_DEBUG_CONTROL_ENABLE_MSB = + AR6320_WLAN_DEBUG_CONTROL_ENABLE_MSB, + .d_WLAN_DEBUG_CONTROL_ENABLE_LSB = + AR6320_WLAN_DEBUG_CONTROL_ENABLE_LSB, + .d_WLAN_DEBUG_CONTROL_ENABLE_MASK = + AR6320_WLAN_DEBUG_CONTROL_ENABLE_MASK, + .d_WLAN_DEBUG_OUT_OFFSET = AR6320_WLAN_DEBUG_OUT_OFFSET, + .d_WLAN_DEBUG_OUT_DATA_MSB = AR6320_WLAN_DEBUG_OUT_DATA_MSB, + .d_WLAN_DEBUG_OUT_DATA_LSB = AR6320_WLAN_DEBUG_OUT_DATA_LSB, + .d_WLAN_DEBUG_OUT_DATA_MASK = AR6320_WLAN_DEBUG_OUT_DATA_MASK, + .d_AMBA_DEBUG_BUS_OFFSET = AR6320_AMBA_DEBUG_BUS_OFFSET, + .d_AMBA_DEBUG_BUS_PCIE_DEBUG_SEL_MSB = + AR6320_AMBA_DEBUG_BUS_PCIE_DEBUG_SEL_MSB, + .d_AMBA_DEBUG_BUS_PCIE_DEBUG_SEL_LSB = + AR6320_AMBA_DEBUG_BUS_PCIE_DEBUG_SEL_LSB, + .d_AMBA_DEBUG_BUS_PCIE_DEBUG_SEL_MASK = + AR6320_AMBA_DEBUG_BUS_PCIE_DEBUG_SEL_MASK, + .d_AMBA_DEBUG_BUS_SEL_MSB = AR6320_AMBA_DEBUG_BUS_SEL_MSB, + .d_AMBA_DEBUG_BUS_SEL_LSB = AR6320_AMBA_DEBUG_BUS_SEL_LSB, + .d_AMBA_DEBUG_BUS_SEL_MASK = AR6320_AMBA_DEBUG_BUS_SEL_MASK, +#endif + /* chip id start */ + .d_SOC_CHIP_ID_ADDRESS = AR6320_SOC_CHIP_ID_ADDRESS, + .d_SOC_CHIP_ID_VERSION_MASK = AR6320_SOC_CHIP_ID_VERSION_MASK, + .d_SOC_CHIP_ID_VERSION_LSB = AR6320_SOC_CHIP_ID_VERSION_LSB, + .d_SOC_CHIP_ID_REVISION_MASK = AR6320_SOC_CHIP_ID_REVISION_MASK, + .d_SOC_CHIP_ID_REVISION_LSB = AR6320_SOC_CHIP_ID_REVISION_LSB, + /* chip id end */ +}; + +struct hostdef_s ar6320_hostdef = { + .d_INT_STATUS_ENABLE_ERROR_LSB = AR6320_INT_STATUS_ENABLE_ERROR_LSB, + .d_INT_STATUS_ENABLE_ERROR_MASK = AR6320_INT_STATUS_ENABLE_ERROR_MASK, + .d_INT_STATUS_ENABLE_CPU_LSB = AR6320_INT_STATUS_ENABLE_CPU_LSB, + .d_INT_STATUS_ENABLE_CPU_MASK = AR6320_INT_STATUS_ENABLE_CPU_MASK, + .d_INT_STATUS_ENABLE_COUNTER_LSB = + AR6320_INT_STATUS_ENABLE_COUNTER_LSB, + .d_INT_STATUS_ENABLE_COUNTER_MASK = + AR6320_INT_STATUS_ENABLE_COUNTER_MASK, + .d_INT_STATUS_ENABLE_MBOX_DATA_LSB = + AR6320_INT_STATUS_ENABLE_MBOX_DATA_LSB, + .d_INT_STATUS_ENABLE_MBOX_DATA_MASK = + AR6320_INT_STATUS_ENABLE_MBOX_DATA_MASK, + .d_ERROR_STATUS_ENABLE_RX_UNDERFLOW_LSB = + AR6320_ERROR_STATUS_ENABLE_RX_UNDERFLOW_LSB, + .d_ERROR_STATUS_ENABLE_RX_UNDERFLOW_MASK = + AR6320_ERROR_STATUS_ENABLE_RX_UNDERFLOW_MASK, + .d_ERROR_STATUS_ENABLE_TX_OVERFLOW_LSB = + AR6320_ERROR_STATUS_ENABLE_TX_OVERFLOW_LSB, + .d_ERROR_STATUS_ENABLE_TX_OVERFLOW_MASK = + AR6320_ERROR_STATUS_ENABLE_TX_OVERFLOW_MASK, + .d_COUNTER_INT_STATUS_ENABLE_BIT_LSB = + AR6320_COUNTER_INT_STATUS_ENABLE_BIT_LSB, + .d_COUNTER_INT_STATUS_ENABLE_BIT_MASK = + AR6320_COUNTER_INT_STATUS_ENABLE_BIT_MASK, + .d_INT_STATUS_ENABLE_ADDRESS = AR6320_INT_STATUS_ENABLE_ADDRESS, + .d_CPU_INT_STATUS_ENABLE_BIT_LSB = + AR6320_CPU_INT_STATUS_ENABLE_BIT_LSB, + .d_CPU_INT_STATUS_ENABLE_BIT_MASK = + AR6320_CPU_INT_STATUS_ENABLE_BIT_MASK, + .d_HOST_INT_STATUS_ADDRESS = AR6320_HOST_INT_STATUS_ADDRESS, + .d_CPU_INT_STATUS_ADDRESS = AR6320_CPU_INT_STATUS_ADDRESS, + .d_ERROR_INT_STATUS_ADDRESS = AR6320_ERROR_INT_STATUS_ADDRESS, + .d_ERROR_INT_STATUS_WAKEUP_MASK = AR6320_ERROR_INT_STATUS_WAKEUP_MASK, + .d_ERROR_INT_STATUS_WAKEUP_LSB = AR6320_ERROR_INT_STATUS_WAKEUP_LSB, + .d_ERROR_INT_STATUS_RX_UNDERFLOW_MASK = + AR6320_ERROR_INT_STATUS_RX_UNDERFLOW_MASK, + .d_ERROR_INT_STATUS_RX_UNDERFLOW_LSB = + AR6320_ERROR_INT_STATUS_RX_UNDERFLOW_LSB, + .d_ERROR_INT_STATUS_TX_OVERFLOW_MASK = + AR6320_ERROR_INT_STATUS_TX_OVERFLOW_MASK, + .d_ERROR_INT_STATUS_TX_OVERFLOW_LSB = + AR6320_ERROR_INT_STATUS_TX_OVERFLOW_LSB, + .d_COUNT_DEC_ADDRESS = AR6320_COUNT_DEC_ADDRESS, + .d_HOST_INT_STATUS_CPU_MASK = AR6320_HOST_INT_STATUS_CPU_MASK, + .d_HOST_INT_STATUS_CPU_LSB = AR6320_HOST_INT_STATUS_CPU_LSB, + .d_HOST_INT_STATUS_ERROR_MASK = AR6320_HOST_INT_STATUS_ERROR_MASK, + .d_HOST_INT_STATUS_ERROR_LSB = AR6320_HOST_INT_STATUS_ERROR_LSB, + .d_HOST_INT_STATUS_COUNTER_MASK = AR6320_HOST_INT_STATUS_COUNTER_MASK, + .d_HOST_INT_STATUS_COUNTER_LSB = AR6320_HOST_INT_STATUS_COUNTER_LSB, + .d_RX_LOOKAHEAD_VALID_ADDRESS = AR6320_RX_LOOKAHEAD_VALID_ADDRESS, + .d_WINDOW_DATA_ADDRESS = AR6320_WINDOW_DATA_ADDRESS, + .d_WINDOW_READ_ADDR_ADDRESS = AR6320_WINDOW_READ_ADDR_ADDRESS, + .d_WINDOW_WRITE_ADDR_ADDRESS = AR6320_WINDOW_WRITE_ADDR_ADDRESS, + .d_SOC_GLOBAL_RESET_ADDRESS = AR6320_SOC_GLOBAL_RESET_ADDRESS, + .d_RTC_STATE_ADDRESS = AR6320_RTC_STATE_ADDRESS, + .d_RTC_STATE_COLD_RESET_MASK = AR6320_RTC_STATE_COLD_RESET_MASK, +#if defined(HIF_PCI) || defined(HIF_SNOC) || defined(HIF_AHB) + .d_PCIE_LOCAL_BASE_ADDRESS = AR6320_PCIE_LOCAL_BASE_ADDRESS, + .d_PCIE_SOC_WAKE_RESET = AR6320_PCIE_SOC_WAKE_RESET, + .d_PCIE_SOC_WAKE_ADDRESS = AR6320_PCIE_SOC_WAKE_ADDRESS, + .d_PCIE_SOC_WAKE_V_MASK = AR6320_PCIE_SOC_WAKE_V_MASK, + .d_MUX_ID_MASK = AR6320_MUX_ID_MASK, + .d_TRANSACTION_ID_MASK = AR6320_TRANSACTION_ID_MASK, + .d_FW_IND_HELPER = AR6320_FW_IND_HELPER, + .d_PCIE_SOC_RDY_STATUS_ADDRESS = PCIE_SOC_RDY_STATUS_ADDRESS, + .d_PCIE_SOC_RDY_STATUS_BAR_MASK = PCIE_SOC_RDY_STATUS_BAR_MASK, + .d_SOC_PCIE_BASE_ADDRESS = SOC_PCIE_BASE_ADDRESS, + .d_MSI_MAGIC_ADR_ADDRESS = MSI_MAGIC_ADR_ADDRESS, + .d_MSI_MAGIC_ADDRESS = MSI_MAGIC_ADDRESS, + .d_HOST_CE_COUNT = 8, + .d_ENABLE_MSI = 0, +#endif + .d_RTC_STATE_V_MASK = AR6320_RTC_STATE_V_MASK, + .d_RTC_STATE_V_LSB = AR6320_RTC_STATE_V_LSB, + .d_FW_IND_EVENT_PENDING = AR6320_FW_IND_EVENT_PENDING, + .d_FW_IND_INITIALIZED = AR6320_FW_IND_INITIALIZED, + .d_RTC_STATE_V_ON = AR6320_RTC_STATE_V_ON, +#if defined(SDIO_3_0) + .d_HOST_INT_STATUS_MBOX_DATA_MASK = + AR6320_HOST_INT_STATUS_MBOX_DATA_MASK, + .d_HOST_INT_STATUS_MBOX_DATA_LSB = + AR6320_HOST_INT_STATUS_MBOX_DATA_LSB, +#endif +}; + +#if defined(HIF_PCI) || defined(HIF_SNOC) || defined(HIF_AHB) +struct ce_reg_def ar6320_ce_targetdef = { + /* copy_engine.c */ + .d_DST_WR_INDEX_ADDRESS = AR6320_DST_WR_INDEX_ADDRESS, + .d_SRC_WATERMARK_ADDRESS = AR6320_SRC_WATERMARK_ADDRESS, + .d_SRC_WATERMARK_LOW_MASK = AR6320_SRC_WATERMARK_LOW_MASK, + .d_SRC_WATERMARK_HIGH_MASK = AR6320_SRC_WATERMARK_HIGH_MASK, + .d_DST_WATERMARK_LOW_MASK = AR6320_DST_WATERMARK_LOW_MASK, + .d_DST_WATERMARK_HIGH_MASK = AR6320_DST_WATERMARK_HIGH_MASK, + .d_CURRENT_SRRI_ADDRESS = AR6320_CURRENT_SRRI_ADDRESS, + .d_CURRENT_DRRI_ADDRESS = AR6320_CURRENT_DRRI_ADDRESS, + .d_HOST_IS_SRC_RING_HIGH_WATERMARK_MASK = + AR6320_HOST_IS_SRC_RING_HIGH_WATERMARK_MASK, + .d_HOST_IS_SRC_RING_LOW_WATERMARK_MASK = + AR6320_HOST_IS_SRC_RING_LOW_WATERMARK_MASK, + .d_HOST_IS_DST_RING_HIGH_WATERMARK_MASK = + AR6320_HOST_IS_DST_RING_HIGH_WATERMARK_MASK, + .d_HOST_IS_DST_RING_LOW_WATERMARK_MASK = + AR6320_HOST_IS_DST_RING_LOW_WATERMARK_MASK, + .d_HOST_IS_ADDRESS = AR6320_HOST_IS_ADDRESS, + .d_HOST_IS_COPY_COMPLETE_MASK = AR6320_HOST_IS_COPY_COMPLETE_MASK, + .d_CE_WRAPPER_BASE_ADDRESS = AR6320_CE_WRAPPER_BASE_ADDRESS, + .d_CE_WRAPPER_INTERRUPT_SUMMARY_ADDRESS = + AR6320_CE_WRAPPER_INTERRUPT_SUMMARY_ADDRESS, + .d_HOST_IE_ADDRESS = AR6320_HOST_IE_ADDRESS, + .d_HOST_IE_COPY_COMPLETE_MASK = AR6320_HOST_IE_COPY_COMPLETE_MASK, + .d_SR_BA_ADDRESS = AR6320_SR_BA_ADDRESS, + .d_SR_SIZE_ADDRESS = AR6320_SR_SIZE_ADDRESS, + .d_CE_CTRL1_ADDRESS = AR6320_CE_CTRL1_ADDRESS, + .d_CE_CTRL1_DMAX_LENGTH_MASK = AR6320_CE_CTRL1_DMAX_LENGTH_MASK, + .d_DR_BA_ADDRESS = AR6320_DR_BA_ADDRESS, + .d_DR_SIZE_ADDRESS = AR6320_DR_SIZE_ADDRESS, + .d_MISC_IE_ADDRESS = AR6320_MISC_IE_ADDRESS, + .d_MISC_IS_AXI_ERR_MASK = AR6320_MISC_IS_AXI_ERR_MASK, + .d_MISC_IS_DST_ADDR_ERR_MASK = AR6320_MISC_IS_DST_ADDR_ERR_MASK, + .d_MISC_IS_SRC_LEN_ERR_MASK = AR6320_MISC_IS_SRC_LEN_ERR_MASK, + .d_MISC_IS_DST_MAX_LEN_VIO_MASK = AR6320_MISC_IS_DST_MAX_LEN_VIO_MASK, + .d_MISC_IS_DST_RING_OVERFLOW_MASK = + AR6320_MISC_IS_DST_RING_OVERFLOW_MASK, + .d_MISC_IS_SRC_RING_OVERFLOW_MASK = + AR6320_MISC_IS_SRC_RING_OVERFLOW_MASK, + .d_SRC_WATERMARK_LOW_LSB = AR6320_SRC_WATERMARK_LOW_LSB, + .d_SRC_WATERMARK_HIGH_LSB = AR6320_SRC_WATERMARK_HIGH_LSB, + .d_DST_WATERMARK_LOW_LSB = AR6320_DST_WATERMARK_LOW_LSB, + .d_DST_WATERMARK_HIGH_LSB = AR6320_DST_WATERMARK_HIGH_LSB, + .d_CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_MASK = + AR6320_CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_MASK, + .d_CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_LSB = + AR6320_CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_LSB, + .d_CE_CTRL1_DMAX_LENGTH_LSB = AR6320_CE_CTRL1_DMAX_LENGTH_LSB, + .d_CE_CTRL1_SRC_RING_BYTE_SWAP_EN_MASK = + AR6320_CE_CTRL1_SRC_RING_BYTE_SWAP_EN_MASK, + .d_CE_CTRL1_DST_RING_BYTE_SWAP_EN_MASK = + AR6320_CE_CTRL1_DST_RING_BYTE_SWAP_EN_MASK, + .d_CE_CTRL1_SRC_RING_BYTE_SWAP_EN_LSB = + AR6320_CE_CTRL1_SRC_RING_BYTE_SWAP_EN_LSB, + .d_CE_CTRL1_DST_RING_BYTE_SWAP_EN_LSB = + AR6320_CE_CTRL1_DST_RING_BYTE_SWAP_EN_LSB, + .d_CE_WRAPPER_DEBUG_OFFSET = AR6320_CE_WRAPPER_DEBUG_OFFSET, + .d_CE_WRAPPER_DEBUG_SEL_MSB = AR6320_CE_WRAPPER_DEBUG_SEL_MSB, + .d_CE_WRAPPER_DEBUG_SEL_LSB = AR6320_CE_WRAPPER_DEBUG_SEL_LSB, + .d_CE_WRAPPER_DEBUG_SEL_MASK = AR6320_CE_WRAPPER_DEBUG_SEL_MASK, + .d_CE_DEBUG_OFFSET = AR6320_CE_DEBUG_OFFSET, + .d_CE_DEBUG_SEL_MSB = AR6320_CE_DEBUG_SEL_MSB, + .d_CE_DEBUG_SEL_LSB = AR6320_CE_DEBUG_SEL_LSB, + .d_CE_DEBUG_SEL_MASK = AR6320_CE_DEBUG_SEL_MASK, + .d_CE0_BASE_ADDRESS = AR6320_CE0_BASE_ADDRESS, + .d_CE1_BASE_ADDRESS = AR6320_CE1_BASE_ADDRESS, + +}; +#endif +#endif diff --git a/drivers/staging/qca-wifi-host-cmn/hif/src/ar6320v2def.h b/drivers/staging/qca-wifi-host-cmn/hif/src/ar6320v2def.h new file mode 100644 index 0000000000000000000000000000000000000000..7a27909cf68ebd8bfb856fc3286c61de19bb7fc8 --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/hif/src/ar6320v2def.h @@ -0,0 +1,824 @@ +/* + * Copyright (c) 2013-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef _AR6320V2DEF_H_ +#define _AR6320V2DEF_H_ + +/* Base Addresses */ +#define AR6320V2_RTC_SOC_BASE_ADDRESS 0x00000800 +#define AR6320V2_RTC_WMAC_BASE_ADDRESS 0x00001000 +#define AR6320V2_MAC_COEX_BASE_ADDRESS 0x0000f000 +#define AR6320V2_BT_COEX_BASE_ADDRESS 0x00002000 +#define AR6320V2_SOC_PCIE_BASE_ADDRESS 0x00038000 +#define AR6320V2_SOC_CORE_BASE_ADDRESS 0x0003a000 +#define AR6320V2_WLAN_UART_BASE_ADDRESS 0x0000c000 +#define AR6320V2_WLAN_SI_BASE_ADDRESS 0x00010000 +#define AR6320V2_WLAN_GPIO_BASE_ADDRESS 0x00005000 +#define AR6320V2_WLAN_ANALOG_INTF_BASE_ADDRESS 0x00006000 +#define AR6320V2_WLAN_MAC_BASE_ADDRESS 0x00010000 +#define AR6320V2_EFUSE_BASE_ADDRESS 0x00024000 +#define AR6320V2_FPGA_REG_BASE_ADDRESS 0x00039000 +#define AR6320V2_WLAN_UART2_BASE_ADDRESS 0x00054c00 +#define AR6320V2_DBI_BASE_ADDRESS 0x0003c000 + +#define AR6320V2_SCRATCH_3_ADDRESS 0x0028 +#define AR6320V2_TARG_DRAM_START 0x00400000 +#define AR6320V2_SOC_SYSTEM_SLEEP_OFFSET 0x000000c0 +#define AR6320V2_SOC_RESET_CONTROL_OFFSET 0x00000000 +#define AR6320V2_SOC_CLOCK_CONTROL_OFFSET 0x00000028 +#define AR6320V2_SOC_CLOCK_CONTROL_SI0_CLK_MASK 0x00000001 +#define AR6320V2_SOC_RESET_CONTROL_SI0_RST_MASK 0x00000000 +#define AR6320V2_WLAN_GPIO_PIN0_ADDRESS 0x00000068 +#define AR6320V2_WLAN_GPIO_PIN1_ADDRESS 0x0000006c +#define AR6320V2_WLAN_GPIO_PIN0_CONFIG_MASK 0x00007800 +#define AR6320V2_WLAN_GPIO_PIN1_CONFIG_MASK 0x00007800 +#define AR6320V2_SOC_CPU_CLOCK_OFFSET 0x00000020 +#define AR6320V2_SOC_LPO_CAL_OFFSET 0x000000e0 +#define AR6320V2_WLAN_GPIO_PIN10_ADDRESS 0x00000090 +#define AR6320V2_WLAN_GPIO_PIN11_ADDRESS 0x00000094 +#define AR6320V2_WLAN_GPIO_PIN12_ADDRESS 0x00000098 +#define AR6320V2_WLAN_GPIO_PIN13_ADDRESS 0x0000009c +#define AR6320V2_SOC_CPU_CLOCK_STANDARD_LSB 0 +#define AR6320V2_SOC_CPU_CLOCK_STANDARD_MASK 0x00000003 +#define AR6320V2_SOC_LPO_CAL_ENABLE_LSB 20 +#define AR6320V2_SOC_LPO_CAL_ENABLE_MASK 0x00100000 + +#define AR6320V2_WLAN_SYSTEM_SLEEP_DISABLE_LSB 0 +#define AR6320V2_WLAN_SYSTEM_SLEEP_DISABLE_MASK 0x00000001 +#define AR6320V2_WLAN_RESET_CONTROL_COLD_RST_MASK 0x00000008 +#define AR6320V2_WLAN_RESET_CONTROL_WARM_RST_MASK 0x00000004 +#define AR6320V2_SI_CONFIG_BIDIR_OD_DATA_LSB 18 +#define AR6320V2_SI_CONFIG_BIDIR_OD_DATA_MASK 0x00040000 +#define AR6320V2_SI_CONFIG_I2C_LSB 16 +#define AR6320V2_SI_CONFIG_I2C_MASK 0x00010000 +#define AR6320V2_SI_CONFIG_POS_SAMPLE_LSB 7 +#define AR6320V2_SI_CONFIG_POS_SAMPLE_MASK 0x00000080 +#define AR6320V2_SI_CONFIG_INACTIVE_CLK_LSB 4 +#define AR6320V2_SI_CONFIG_INACTIVE_CLK_MASK 0x00000010 +#define AR6320V2_SI_CONFIG_INACTIVE_DATA_LSB 5 +#define AR6320V2_SI_CONFIG_INACTIVE_DATA_MASK 0x00000020 +#define AR6320V2_SI_CONFIG_DIVIDER_LSB 0 +#define AR6320V2_SI_CONFIG_DIVIDER_MASK 0x0000000f +#define AR6320V2_SI_CONFIG_OFFSET 0x00000000 +#define AR6320V2_SI_TX_DATA0_OFFSET 0x00000008 +#define AR6320V2_SI_TX_DATA1_OFFSET 0x0000000c +#define AR6320V2_SI_RX_DATA0_OFFSET 0x00000010 +#define AR6320V2_SI_RX_DATA1_OFFSET 0x00000014 +#define AR6320V2_SI_CS_OFFSET 0x00000004 +#define AR6320V2_SI_CS_DONE_ERR_MASK 0x00000400 +#define AR6320V2_SI_CS_DONE_INT_MASK 0x00000200 +#define AR6320V2_SI_CS_START_LSB 8 +#define AR6320V2_SI_CS_START_MASK 0x00000100 +#define AR6320V2_SI_CS_RX_CNT_LSB 4 +#define AR6320V2_SI_CS_RX_CNT_MASK 0x000000f0 +#define AR6320V2_SI_CS_TX_CNT_LSB 0 +#define AR6320V2_SI_CS_TX_CNT_MASK 0x0000000f +#define AR6320V2_CE_COUNT 8 +#define AR6320V2_SR_WR_INDEX_ADDRESS 0x003c +#define AR6320V2_DST_WATERMARK_ADDRESS 0x0050 +#define AR6320V2_RX_MSDU_END_4_FIRST_MSDU_LSB 14 +#define AR6320V2_RX_MSDU_END_4_FIRST_MSDU_MASK 0x00004000 +#define AR6320V2_RX_MPDU_START_0_RETRY_LSB 14 +#define AR6320V2_RX_MPDU_START_0_RETRY_MASK 0x00004000 +#define AR6320V2_RX_MPDU_START_0_SEQ_NUM_LSB 16 +#define AR6320V2_RX_MPDU_START_0_SEQ_NUM_MASK 0x0fff0000 +#define AR6320V2_RX_MPDU_START_2_PN_47_32_LSB 0 +#define AR6320V2_RX_MPDU_START_2_PN_47_32_MASK 0x0000ffff +#define AR6320V2_RX_MPDU_START_2_TID_LSB 28 +#define AR6320V2_RX_MPDU_START_2_TID_MASK 0xf0000000 +#define AR6320V2_RX_MSDU_END_1_EXT_WAPI_PN_63_48_LSB 16 +#define AR6320V2_RX_MSDU_END_1_EXT_WAPI_PN_63_48_MASK 0xffff0000 +#define AR6320V2_RX_MSDU_END_4_LAST_MSDU_LSB 15 +#define AR6320V2_RX_MSDU_END_4_LAST_MSDU_MASK 0x00008000 +#define AR6320V2_RX_ATTENTION_0_MCAST_BCAST_LSB 2 +#define AR6320V2_RX_ATTENTION_0_MCAST_BCAST_MASK 0x00000004 +#define AR6320V2_RX_ATTENTION_0_FRAGMENT_LSB 13 +#define AR6320V2_RX_ATTENTION_0_FRAGMENT_MASK 0x00002000 +#define AR6320V2_RX_ATTENTION_0_MPDU_LENGTH_ERR_MASK 0x08000000 +#define AR6320V2_RX_FRAG_INFO_0_RING2_MORE_COUNT_LSB 16 +#define AR6320V2_RX_FRAG_INFO_0_RING2_MORE_COUNT_MASK 0x00ff0000 +#define AR6320V2_RX_MSDU_START_0_MSDU_LENGTH_LSB 0 +#define AR6320V2_RX_MSDU_START_0_MSDU_LENGTH_MASK 0x00003fff + +#define AR6320V2_RX_MSDU_START_2_DECAP_FORMAT_OFFSET 0x00000008 +#define AR6320V2_RX_MSDU_START_2_DECAP_FORMAT_LSB 8 +#define AR6320V2_RX_MSDU_START_2_DECAP_FORMAT_MASK 0x00000300 +#define AR6320V2_RX_MPDU_START_0_ENCRYPTED_LSB 13 +#define AR6320V2_RX_MPDU_START_0_ENCRYPTED_MASK 0x00002000 +#define AR6320V2_RX_ATTENTION_0_MORE_DATA_MASK 0x00000400 +#define AR6320V2_RX_ATTENTION_0_MSDU_DONE_MASK 0x80000000 +#define AR6320V2_RX_ATTENTION_0_TCP_UDP_CHKSUM_FAIL_MASK 0x00040000 +#define AR6320V2_DST_WR_INDEX_ADDRESS 0x0040 +#define AR6320V2_SRC_WATERMARK_ADDRESS 0x004c +#define AR6320V2_SRC_WATERMARK_LOW_MASK 0xffff0000 +#define AR6320V2_SRC_WATERMARK_HIGH_MASK 0x0000ffff +#define AR6320V2_DST_WATERMARK_LOW_MASK 0xffff0000 +#define AR6320V2_DST_WATERMARK_HIGH_MASK 0x0000ffff +#define AR6320V2_CURRENT_SRRI_ADDRESS 0x0044 +#define AR6320V2_CURRENT_DRRI_ADDRESS 0x0048 +#define AR6320V2_HOST_IS_SRC_RING_HIGH_WATERMARK_MASK 0x00000002 +#define AR6320V2_HOST_IS_SRC_RING_LOW_WATERMARK_MASK 0x00000004 +#define AR6320V2_HOST_IS_DST_RING_HIGH_WATERMARK_MASK 0x00000008 +#define AR6320V2_HOST_IS_DST_RING_LOW_WATERMARK_MASK 0x00000010 +#define AR6320V2_HOST_IS_ADDRESS 0x0030 +#define AR6320V2_HOST_IS_COPY_COMPLETE_MASK 0x00000001 +#define AR6320V2_HOST_IE_ADDRESS 0x002c +#define AR6320V2_HOST_IE_COPY_COMPLETE_MASK 0x00000001 +#define AR6320V2_SR_BA_ADDRESS 0x0000 +#define AR6320V2_SR_SIZE_ADDRESS 0x0004 +#define AR6320V2_DR_BA_ADDRESS 0x0008 +#define AR6320V2_DR_SIZE_ADDRESS 0x000c +#define AR6320V2_MISC_IE_ADDRESS 0x0034 +#define AR6320V2_MISC_IS_AXI_ERR_MASK 0x00000400 +#define AR6320V2_MISC_IS_DST_ADDR_ERR_MASK 0x00000200 +#define AR6320V2_MISC_IS_SRC_LEN_ERR_MASK 0x00000100 +#define AR6320V2_MISC_IS_DST_MAX_LEN_VIO_MASK 0x00000080 +#define AR6320V2_MISC_IS_DST_RING_OVERFLOW_MASK 0x00000040 +#define AR6320V2_MISC_IS_SRC_RING_OVERFLOW_MASK 0x00000020 +#define AR6320V2_SRC_WATERMARK_LOW_LSB 16 +#define AR6320V2_SRC_WATERMARK_HIGH_LSB 0 +#define AR6320V2_DST_WATERMARK_LOW_LSB 16 +#define AR6320V2_DST_WATERMARK_HIGH_LSB 0 +#define AR6320V2_SOC_GLOBAL_RESET_ADDRESS 0x0008 +#define AR6320V2_RTC_STATE_ADDRESS 0x0000 +#define AR6320V2_RTC_STATE_COLD_RESET_MASK 0x00002000 +#define AR6320V2_RTC_STATE_V_MASK 0x00000007 +#define AR6320V2_RTC_STATE_V_LSB 0 +#define AR6320V2_RTC_STATE_V_ON 3 +#define AR6320V2_FW_IND_EVENT_PENDING 1 +#define AR6320V2_FW_IND_INITIALIZED 2 +#define AR6320V2_CPU_INTR_ADDRESS 0x0010 +#define AR6320V2_SOC_LF_TIMER_CONTROL0_ADDRESS 0x00000050 +#define AR6320V2_SOC_LF_TIMER_CONTROL0_ENABLE_MASK 0x00000004 +#define AR6320V2_SOC_RESET_CONTROL_ADDRESS 0x00000000 +#define AR6320V2_SOC_RESET_CONTROL_CPU_WARM_RST_MASK 0x00000040 +#define AR6320V2_CORE_CTRL_ADDRESS 0x0000 +#define AR6320V2_CORE_CTRL_CPU_INTR_MASK 0x00002000 +#define AR6320V2_LOCAL_SCRATCH_OFFSET 0x000000c0 +#define AR6320V2_CLOCK_GPIO_OFFSET 0xffffffff +#define AR6320V2_CLOCK_GPIO_BT_CLK_OUT_EN_LSB 0 +#define AR6320V2_CLOCK_GPIO_BT_CLK_OUT_EN_MASK 0 +#define AR6320V2_SOC_CHIP_ID_ADDRESS 0x000000f0 +#define AR6320V2_SOC_CHIP_ID_VERSION_MASK 0xfffc0000 +#define AR6320V2_SOC_CHIP_ID_VERSION_LSB 18 +#define AR6320V2_SOC_CHIP_ID_REVISION_MASK 0x00000f00 +#define AR6320V2_SOC_CHIP_ID_REVISION_LSB 8 +#if defined(HIF_PCI) || defined(HIF_SNOC) || defined(HIF_AHB) +#define AR6320V2_CE_WRAPPER_BASE_ADDRESS 0x00034000 +#define AR6320V2_CE0_BASE_ADDRESS 0x00034400 +#define AR6320V2_CE1_BASE_ADDRESS 0x00034800 +#define AR6320V2_CE2_BASE_ADDRESS 0x00034c00 +#define AR6320V2_CE3_BASE_ADDRESS 0x00035000 +#define AR6320V2_CE4_BASE_ADDRESS 0x00035400 +#define AR6320V2_CE5_BASE_ADDRESS 0x00035800 +#define AR6320V2_CE6_BASE_ADDRESS 0x00035c00 +#define AR6320V2_CE7_BASE_ADDRESS 0x00036000 +#define AR6320V2_WLAN_ANALOG_INTF_PCIE_BASE_ADDRESS 0x00007800 +#define AR6320V2_CE_CTRL1_ADDRESS 0x0010 +#define AR6320V2_CE_CTRL1_DMAX_LENGTH_MASK 0x0000ffff +#define AR6320V2_CE_WRAPPER_INTERRUPT_SUMMARY_ADDRESS 0x0000 +#define AR6320V2_CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_MASK 0x0000ff00 +#define AR6320V2_CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_LSB 8 +#define AR6320V2_CE_CTRL1_DMAX_LENGTH_LSB 0 +#define AR6320V2_CE_CTRL1_SRC_RING_BYTE_SWAP_EN_MASK 0x00010000 +#define AR6320V2_CE_CTRL1_DST_RING_BYTE_SWAP_EN_MASK 0x00020000 +#define AR6320V2_CE_CTRL1_SRC_RING_BYTE_SWAP_EN_LSB 16 +#define AR6320V2_CE_CTRL1_DST_RING_BYTE_SWAP_EN_LSB 17 +#define AR6320V2_SOC_RESET_CONTROL_PCIE_RST_SHORT_OVRD_MASK 0x00000020 +#define AR6320V2_SOC_RESET_CONTROL_PCIE_RST_SHORT_OVRD_LSB 5 +#define AR6320V2_PCIE_SOC_WAKE_RESET 0x00000000 +#define AR6320V2_PCIE_SOC_WAKE_ADDRESS 0x0004 +#define AR6320V2_PCIE_SOC_WAKE_V_MASK 0x00000001 +#define AR6320V2_MUX_ID_MASK 0x0000 +#define AR6320V2_TRANSACTION_ID_MASK 0x3fff +#define AR6320V2_PCIE_LOCAL_BASE_ADDRESS 0x80000 +#define AR6320V2_FW_IND_HELPER 4 +#define AR6320V2_PCIE_INTR_ENABLE_ADDRESS 0x0008 +#define AR6320V2_PCIE_INTR_CLR_ADDRESS 0x0014 +#define AR6320V2_PCIE_INTR_FIRMWARE_MASK 0x00000400 +#define AR6320V2_PCIE_INTR_CE0_MASK 0x00000800 +#define AR6320V2_PCIE_INTR_CE_MASK_ALL 0x0007f800 +#define AR6320V2_PCIE_INTR_CAUSE_ADDRESS 0x000c +#define AR6320V2_SOC_RESET_CONTROL_CE_RST_MASK 0x00000001 +#define AR6320V2_SOC_POWER_REG_OFFSET 0x0000010c +/* Copy Engine Debug */ +#define AR6320V2_WLAN_DEBUG_INPUT_SEL_OFFSET 0x0000010c +#define AR6320V2_WLAN_DEBUG_INPUT_SEL_SRC_MSB 3 +#define AR6320V2_WLAN_DEBUG_INPUT_SEL_SRC_LSB 0 +#define AR6320V2_WLAN_DEBUG_INPUT_SEL_SRC_MASK 0x0000000f +#define AR6320V2_WLAN_DEBUG_CONTROL_OFFSET 0x00000108 +#define AR6320V2_WLAN_DEBUG_CONTROL_ENABLE_MSB 0 +#define AR6320V2_WLAN_DEBUG_CONTROL_ENABLE_LSB 0 +#define AR6320V2_WLAN_DEBUG_CONTROL_ENABLE_MASK 0x00000001 +#define AR6320V2_WLAN_DEBUG_OUT_OFFSET 0x00000110 +#define AR6320V2_WLAN_DEBUG_OUT_DATA_MSB 19 +#define AR6320V2_WLAN_DEBUG_OUT_DATA_LSB 0 +#define AR6320V2_WLAN_DEBUG_OUT_DATA_MASK 0x000fffff +#define AR6320V2_AMBA_DEBUG_BUS_OFFSET 0x0000011c +#define AR6320V2_AMBA_DEBUG_BUS_PCIE_DEBUG_SEL_MSB 13 +#define AR6320V2_AMBA_DEBUG_BUS_PCIE_DEBUG_SEL_LSB 8 +#define AR6320V2_AMBA_DEBUG_BUS_PCIE_DEBUG_SEL_MASK 0x00003f00 +#define AR6320V2_AMBA_DEBUG_BUS_SEL_MSB 4 +#define AR6320V2_AMBA_DEBUG_BUS_SEL_LSB 0 +#define AR6320V2_AMBA_DEBUG_BUS_SEL_MASK 0x0000001f +#define AR6320V2_CE_WRAPPER_DEBUG_OFFSET 0x0008 +#define AR6320V2_CE_WRAPPER_DEBUG_SEL_MSB 5 +#define AR6320V2_CE_WRAPPER_DEBUG_SEL_LSB 0 +#define AR6320V2_CE_WRAPPER_DEBUG_SEL_MASK 0x0000003f +#define AR6320V2_CE_DEBUG_OFFSET 0x0054 +#define AR6320V2_CE_DEBUG_SEL_MSB 5 +#define AR6320V2_CE_DEBUG_SEL_LSB 0 +#define AR6320V2_CE_DEBUG_SEL_MASK 0x0000003f +/* End */ + +/* PLL start */ +#define AR6320V2_EFUSE_OFFSET 0x0000032c +#define AR6320V2_EFUSE_XTAL_SEL_MSB 10 +#define AR6320V2_EFUSE_XTAL_SEL_LSB 8 +#define AR6320V2_EFUSE_XTAL_SEL_MASK 0x00000700 +#define AR6320V2_BB_PLL_CONFIG_OFFSET 0x000002f4 +#define AR6320V2_BB_PLL_CONFIG_OUTDIV_MSB 20 +#define AR6320V2_BB_PLL_CONFIG_OUTDIV_LSB 18 +#define AR6320V2_BB_PLL_CONFIG_OUTDIV_MASK 0x001c0000 +#define AR6320V2_BB_PLL_CONFIG_FRAC_MSB 17 +#define AR6320V2_BB_PLL_CONFIG_FRAC_LSB 0 +#define AR6320V2_BB_PLL_CONFIG_FRAC_MASK 0x0003ffff +#define AR6320V2_WLAN_PLL_SETTLE_TIME_MSB 10 +#define AR6320V2_WLAN_PLL_SETTLE_TIME_LSB 0 +#define AR6320V2_WLAN_PLL_SETTLE_TIME_MASK 0x000007ff +#define AR6320V2_WLAN_PLL_SETTLE_OFFSET 0x0018 +#define AR6320V2_WLAN_PLL_SETTLE_SW_MASK 0x000007ff +#define AR6320V2_WLAN_PLL_SETTLE_RSTMASK 0xffffffff +#define AR6320V2_WLAN_PLL_SETTLE_RESET 0x00000400 +#define AR6320V2_WLAN_PLL_CONTROL_NOPWD_MSB 18 +#define AR6320V2_WLAN_PLL_CONTROL_NOPWD_LSB 18 +#define AR6320V2_WLAN_PLL_CONTROL_NOPWD_MASK 0x00040000 +#define AR6320V2_WLAN_PLL_CONTROL_BYPASS_MSB 16 +#define AR6320V2_WLAN_PLL_CONTROL_BYPASS_LSB 16 +#define AR6320V2_WLAN_PLL_CONTROL_BYPASS_MASK 0x00010000 +#define AR6320V2_WLAN_PLL_CONTROL_BYPASS_RESET 0x1 +#define AR6320V2_WLAN_PLL_CONTROL_CLK_SEL_MSB 15 +#define AR6320V2_WLAN_PLL_CONTROL_CLK_SEL_LSB 14 +#define AR6320V2_WLAN_PLL_CONTROL_CLK_SEL_MASK 0x0000c000 +#define AR6320V2_WLAN_PLL_CONTROL_CLK_SEL_RESET 0x0 +#define AR6320V2_WLAN_PLL_CONTROL_REFDIV_MSB 13 +#define AR6320V2_WLAN_PLL_CONTROL_REFDIV_LSB 10 +#define AR6320V2_WLAN_PLL_CONTROL_REFDIV_MASK 0x00003c00 +#define AR6320V2_WLAN_PLL_CONTROL_REFDIV_RESET 0x0 +#define AR6320V2_WLAN_PLL_CONTROL_DIV_MSB 9 +#define AR6320V2_WLAN_PLL_CONTROL_DIV_LSB 0 +#define AR6320V2_WLAN_PLL_CONTROL_DIV_MASK 0x000003ff +#define AR6320V2_WLAN_PLL_CONTROL_DIV_RESET 0x11 +#define AR6320V2_WLAN_PLL_CONTROL_OFFSET 0x0014 +#define AR6320V2_WLAN_PLL_CONTROL_SW_MASK 0x001fffff +#define AR6320V2_WLAN_PLL_CONTROL_RSTMASK 0xffffffff +#define AR6320V2_WLAN_PLL_CONTROL_RESET 0x00010011 +#define AR6320V2_SOC_CORE_CLK_CTRL_OFFSET 0x00000114 +#define AR6320V2_SOC_CORE_CLK_CTRL_DIV_MSB 2 +#define AR6320V2_SOC_CORE_CLK_CTRL_DIV_LSB 0 +#define AR6320V2_SOC_CORE_CLK_CTRL_DIV_MASK 0x00000007 +#define AR6320V2_RTC_SYNC_STATUS_PLL_CHANGING_MSB 5 +#define AR6320V2_RTC_SYNC_STATUS_PLL_CHANGING_LSB 5 +#define AR6320V2_RTC_SYNC_STATUS_PLL_CHANGING_MASK 0x00000020 +#define AR6320V2_RTC_SYNC_STATUS_PLL_CHANGING_RESET 0x0 +#define AR6320V2_RTC_SYNC_STATUS_OFFSET 0x0244 +#define AR6320V2_SOC_CPU_CLOCK_OFFSET 0x00000020 +#define AR6320V2_SOC_CPU_CLOCK_STANDARD_MSB 1 +#define AR6320V2_SOC_CPU_CLOCK_STANDARD_LSB 0 +#define AR6320V2_SOC_CPU_CLOCK_STANDARD_MASK 0x00000003 +/* PLL end */ + +#define AR6320V2_PCIE_INTR_CE_MASK(n) \ + (AR6320V2_PCIE_INTR_CE0_MASK << (n)) +#endif +#define AR6320V2_DRAM_BASE_ADDRESS AR6320V2_TARG_DRAM_START +#define AR6320V2_FW_INDICATOR_ADDRESS \ + (AR6320V2_SOC_CORE_BASE_ADDRESS + AR6320V2_SCRATCH_3_ADDRESS) +#define AR6320V2_SYSTEM_SLEEP_OFFSET AR6320V2_SOC_SYSTEM_SLEEP_OFFSET +#define AR6320V2_WLAN_SYSTEM_SLEEP_OFFSET 0x002c +#define AR6320V2_WLAN_RESET_CONTROL_OFFSET AR6320V2_SOC_RESET_CONTROL_OFFSET +#define AR6320V2_CLOCK_CONTROL_OFFSET AR6320V2_SOC_CLOCK_CONTROL_OFFSET +#define AR6320V2_CLOCK_CONTROL_SI0_CLK_MASK \ + AR6320V2_SOC_CLOCK_CONTROL_SI0_CLK_MASK +#define AR6320V2_RESET_CONTROL_MBOX_RST_MASK 0x00000004 +#define AR6320V2_RESET_CONTROL_SI0_RST_MASK \ + AR6320V2_SOC_RESET_CONTROL_SI0_RST_MASK +#define AR6320V2_GPIO_BASE_ADDRESS AR6320V2_WLAN_GPIO_BASE_ADDRESS +#define AR6320V2_GPIO_PIN0_OFFSET AR6320V2_WLAN_GPIO_PIN0_ADDRESS +#define AR6320V2_GPIO_PIN1_OFFSET AR6320V2_WLAN_GPIO_PIN1_ADDRESS +#define AR6320V2_GPIO_PIN0_CONFIG_MASK AR6320V2_WLAN_GPIO_PIN0_CONFIG_MASK +#define AR6320V2_GPIO_PIN1_CONFIG_MASK AR6320V2_WLAN_GPIO_PIN1_CONFIG_MASK +#define AR6320V2_SI_BASE_ADDRESS 0x00050000 +#define AR6320V2_CPU_CLOCK_OFFSET AR6320V2_SOC_CPU_CLOCK_OFFSET +#define AR6320V2_LPO_CAL_OFFSET AR6320V2_SOC_LPO_CAL_OFFSET +#define AR6320V2_GPIO_PIN10_OFFSET AR6320V2_WLAN_GPIO_PIN10_ADDRESS +#define AR6320V2_GPIO_PIN11_OFFSET AR6320V2_WLAN_GPIO_PIN11_ADDRESS +#define AR6320V2_GPIO_PIN12_OFFSET AR6320V2_WLAN_GPIO_PIN12_ADDRESS +#define AR6320V2_GPIO_PIN13_OFFSET AR6320V2_WLAN_GPIO_PIN13_ADDRESS +#define AR6320V2_CPU_CLOCK_STANDARD_LSB AR6320V2_SOC_CPU_CLOCK_STANDARD_LSB +#define AR6320V2_CPU_CLOCK_STANDARD_MASK AR6320V2_SOC_CPU_CLOCK_STANDARD_MASK +#define AR6320V2_LPO_CAL_ENABLE_LSB AR6320V2_SOC_LPO_CAL_ENABLE_LSB +#define AR6320V2_LPO_CAL_ENABLE_MASK AR6320V2_SOC_LPO_CAL_ENABLE_MASK +#define AR6320V2_ANALOG_INTF_BASE_ADDRESS \ + AR6320V2_WLAN_ANALOG_INTF_BASE_ADDRESS +#define AR6320V2_MBOX_BASE_ADDRESS 0x00008000 +#define AR6320V2_INT_STATUS_ENABLE_ERROR_LSB 7 +#define AR6320V2_INT_STATUS_ENABLE_ERROR_MASK 0x00000080 +#define AR6320V2_INT_STATUS_ENABLE_CPU_LSB 6 +#define AR6320V2_INT_STATUS_ENABLE_CPU_MASK 0x00000040 +#define AR6320V2_INT_STATUS_ENABLE_COUNTER_LSB 4 +#define AR6320V2_INT_STATUS_ENABLE_COUNTER_MASK 0x00000010 +#define AR6320V2_INT_STATUS_ENABLE_MBOX_DATA_LSB 0 +#define AR6320V2_INT_STATUS_ENABLE_MBOX_DATA_MASK 0x0000000f +#define AR6320V2_ERROR_STATUS_ENABLE_RX_UNDERFLOW_LSB 17 +#define AR6320V2_ERROR_STATUS_ENABLE_RX_UNDERFLOW_MASK 0x00020000 +#define AR6320V2_ERROR_STATUS_ENABLE_TX_OVERFLOW_LSB 16 +#define AR6320V2_ERROR_STATUS_ENABLE_TX_OVERFLOW_MASK 0x00010000 +#define AR6320V2_COUNTER_INT_STATUS_ENABLE_BIT_LSB 24 +#define AR6320V2_COUNTER_INT_STATUS_ENABLE_BIT_MASK 0xff000000 +#define AR6320V2_INT_STATUS_ENABLE_ADDRESS 0x0828 +#define AR6320V2_CPU_INT_STATUS_ENABLE_BIT_LSB 8 +#define AR6320V2_CPU_INT_STATUS_ENABLE_BIT_MASK 0x0000ff00 +#define AR6320V2_HOST_INT_STATUS_ADDRESS 0x0800 +#define AR6320V2_CPU_INT_STATUS_ADDRESS 0x0801 +#define AR6320V2_ERROR_INT_STATUS_ADDRESS 0x0802 +#define AR6320V2_ERROR_INT_STATUS_WAKEUP_MASK 0x00040000 +#define AR6320V2_ERROR_INT_STATUS_WAKEUP_LSB 18 +#define AR6320V2_ERROR_INT_STATUS_RX_UNDERFLOW_MASK 0x00020000 +#define AR6320V2_ERROR_INT_STATUS_RX_UNDERFLOW_LSB 17 +#define AR6320V2_ERROR_INT_STATUS_TX_OVERFLOW_MASK 0x00010000 +#define AR6320V2_ERROR_INT_STATUS_TX_OVERFLOW_LSB 16 +#define AR6320V2_COUNT_DEC_ADDRESS 0x0840 +#define AR6320V2_HOST_INT_STATUS_CPU_MASK 0x00000040 +#define AR6320V2_HOST_INT_STATUS_CPU_LSB 6 +#define AR6320V2_HOST_INT_STATUS_ERROR_MASK 0x00000080 +#define AR6320V2_HOST_INT_STATUS_ERROR_LSB 7 +#define AR6320V2_HOST_INT_STATUS_COUNTER_MASK 0x00000010 +#define AR6320V2_HOST_INT_STATUS_COUNTER_LSB 4 +#define AR6320V2_RX_LOOKAHEAD_VALID_ADDRESS 0x0805 +#define AR6320V2_WINDOW_DATA_ADDRESS 0x0874 +#define AR6320V2_WINDOW_READ_ADDR_ADDRESS 0x087c +#define AR6320V2_WINDOW_WRITE_ADDR_ADDRESS 0x0878 +#define AR6320V2_HOST_INT_STATUS_MBOX_DATA_MASK 0x0f +#define AR6320V2_HOST_INT_STATUS_MBOX_DATA_LSB 0 + +struct targetdef_s ar6320v2_targetdef = { + .d_RTC_SOC_BASE_ADDRESS = AR6320V2_RTC_SOC_BASE_ADDRESS, + .d_RTC_WMAC_BASE_ADDRESS = AR6320V2_RTC_WMAC_BASE_ADDRESS, + .d_SYSTEM_SLEEP_OFFSET = AR6320V2_WLAN_SYSTEM_SLEEP_OFFSET, + .d_WLAN_SYSTEM_SLEEP_OFFSET = AR6320V2_WLAN_SYSTEM_SLEEP_OFFSET, + .d_WLAN_SYSTEM_SLEEP_DISABLE_LSB = + AR6320V2_WLAN_SYSTEM_SLEEP_DISABLE_LSB, + .d_WLAN_SYSTEM_SLEEP_DISABLE_MASK = + AR6320V2_WLAN_SYSTEM_SLEEP_DISABLE_MASK, + .d_CLOCK_CONTROL_OFFSET = AR6320V2_CLOCK_CONTROL_OFFSET, + .d_CLOCK_CONTROL_SI0_CLK_MASK = AR6320V2_CLOCK_CONTROL_SI0_CLK_MASK, + .d_RESET_CONTROL_OFFSET = AR6320V2_SOC_RESET_CONTROL_OFFSET, + .d_RESET_CONTROL_MBOX_RST_MASK = AR6320V2_RESET_CONTROL_MBOX_RST_MASK, + .d_RESET_CONTROL_SI0_RST_MASK = AR6320V2_RESET_CONTROL_SI0_RST_MASK, + .d_WLAN_RESET_CONTROL_OFFSET = AR6320V2_WLAN_RESET_CONTROL_OFFSET, + .d_WLAN_RESET_CONTROL_COLD_RST_MASK = + AR6320V2_WLAN_RESET_CONTROL_COLD_RST_MASK, + .d_WLAN_RESET_CONTROL_WARM_RST_MASK = + AR6320V2_WLAN_RESET_CONTROL_WARM_RST_MASK, + .d_GPIO_BASE_ADDRESS = AR6320V2_GPIO_BASE_ADDRESS, + .d_GPIO_PIN0_OFFSET = AR6320V2_GPIO_PIN0_OFFSET, + .d_GPIO_PIN1_OFFSET = AR6320V2_GPIO_PIN1_OFFSET, + .d_GPIO_PIN0_CONFIG_MASK = AR6320V2_GPIO_PIN0_CONFIG_MASK, + .d_GPIO_PIN1_CONFIG_MASK = AR6320V2_GPIO_PIN1_CONFIG_MASK, + .d_SI_CONFIG_BIDIR_OD_DATA_LSB = AR6320V2_SI_CONFIG_BIDIR_OD_DATA_LSB, + .d_SI_CONFIG_BIDIR_OD_DATA_MASK = + AR6320V2_SI_CONFIG_BIDIR_OD_DATA_MASK, + .d_SI_CONFIG_I2C_LSB = AR6320V2_SI_CONFIG_I2C_LSB, + .d_SI_CONFIG_I2C_MASK = AR6320V2_SI_CONFIG_I2C_MASK, + .d_SI_CONFIG_POS_SAMPLE_LSB = AR6320V2_SI_CONFIG_POS_SAMPLE_LSB, + .d_SI_CONFIG_POS_SAMPLE_MASK = AR6320V2_SI_CONFIG_POS_SAMPLE_MASK, + .d_SI_CONFIG_INACTIVE_CLK_LSB = AR6320V2_SI_CONFIG_INACTIVE_CLK_LSB, + .d_SI_CONFIG_INACTIVE_CLK_MASK = AR6320V2_SI_CONFIG_INACTIVE_CLK_MASK, + .d_SI_CONFIG_INACTIVE_DATA_LSB = AR6320V2_SI_CONFIG_INACTIVE_DATA_LSB, + .d_SI_CONFIG_INACTIVE_DATA_MASK = + AR6320V2_SI_CONFIG_INACTIVE_DATA_MASK, + .d_SI_CONFIG_DIVIDER_LSB = AR6320V2_SI_CONFIG_DIVIDER_LSB, + .d_SI_CONFIG_DIVIDER_MASK = AR6320V2_SI_CONFIG_DIVIDER_MASK, + .d_SI_BASE_ADDRESS = AR6320V2_SI_BASE_ADDRESS, + .d_SI_CONFIG_OFFSET = AR6320V2_SI_CONFIG_OFFSET, + .d_SI_TX_DATA0_OFFSET = AR6320V2_SI_TX_DATA0_OFFSET, + .d_SI_TX_DATA1_OFFSET = AR6320V2_SI_TX_DATA1_OFFSET, + .d_SI_RX_DATA0_OFFSET = AR6320V2_SI_RX_DATA0_OFFSET, + .d_SI_RX_DATA1_OFFSET = AR6320V2_SI_RX_DATA1_OFFSET, + .d_SI_CS_OFFSET = AR6320V2_SI_CS_OFFSET, + .d_SI_CS_DONE_ERR_MASK = AR6320V2_SI_CS_DONE_ERR_MASK, + .d_SI_CS_DONE_INT_MASK = AR6320V2_SI_CS_DONE_INT_MASK, + .d_SI_CS_START_LSB = AR6320V2_SI_CS_START_LSB, + .d_SI_CS_START_MASK = AR6320V2_SI_CS_START_MASK, + .d_SI_CS_RX_CNT_LSB = AR6320V2_SI_CS_RX_CNT_LSB, + .d_SI_CS_RX_CNT_MASK = AR6320V2_SI_CS_RX_CNT_MASK, + .d_SI_CS_TX_CNT_LSB = AR6320V2_SI_CS_TX_CNT_LSB, + .d_SI_CS_TX_CNT_MASK = AR6320V2_SI_CS_TX_CNT_MASK, + .d_BOARD_DATA_SZ = AR6320_BOARD_DATA_SZ, + .d_BOARD_EXT_DATA_SZ = AR6320_BOARD_EXT_DATA_SZ, + .d_MBOX_BASE_ADDRESS = AR6320V2_MBOX_BASE_ADDRESS, + .d_LOCAL_SCRATCH_OFFSET = AR6320V2_LOCAL_SCRATCH_OFFSET, + .d_CPU_CLOCK_OFFSET = AR6320V2_CPU_CLOCK_OFFSET, + .d_LPO_CAL_OFFSET = AR6320V2_LPO_CAL_OFFSET, + .d_GPIO_PIN10_OFFSET = AR6320V2_GPIO_PIN10_OFFSET, + .d_GPIO_PIN11_OFFSET = AR6320V2_GPIO_PIN11_OFFSET, + .d_GPIO_PIN12_OFFSET = AR6320V2_GPIO_PIN12_OFFSET, + .d_GPIO_PIN13_OFFSET = AR6320V2_GPIO_PIN13_OFFSET, + .d_CLOCK_GPIO_OFFSET = AR6320V2_CLOCK_GPIO_OFFSET, + .d_CPU_CLOCK_STANDARD_LSB = AR6320V2_CPU_CLOCK_STANDARD_LSB, + .d_CPU_CLOCK_STANDARD_MASK = AR6320V2_CPU_CLOCK_STANDARD_MASK, + .d_LPO_CAL_ENABLE_LSB = AR6320V2_LPO_CAL_ENABLE_LSB, + .d_LPO_CAL_ENABLE_MASK = AR6320V2_LPO_CAL_ENABLE_MASK, + .d_CLOCK_GPIO_BT_CLK_OUT_EN_LSB = + AR6320V2_CLOCK_GPIO_BT_CLK_OUT_EN_LSB, + .d_CLOCK_GPIO_BT_CLK_OUT_EN_MASK = + AR6320V2_CLOCK_GPIO_BT_CLK_OUT_EN_MASK, + .d_ANALOG_INTF_BASE_ADDRESS = AR6320V2_ANALOG_INTF_BASE_ADDRESS, + .d_WLAN_MAC_BASE_ADDRESS = AR6320V2_WLAN_MAC_BASE_ADDRESS, + .d_FW_INDICATOR_ADDRESS = AR6320V2_FW_INDICATOR_ADDRESS, + .d_DRAM_BASE_ADDRESS = AR6320V2_DRAM_BASE_ADDRESS, + .d_SOC_CORE_BASE_ADDRESS = AR6320V2_SOC_CORE_BASE_ADDRESS, + .d_CORE_CTRL_ADDRESS = AR6320V2_CORE_CTRL_ADDRESS, +#if defined(HIF_PCI) || defined(HIF_SNOC) || defined(HIF_AHB) + .d_MSI_NUM_REQUEST = MSI_NUM_REQUEST, + .d_MSI_ASSIGN_FW = MSI_ASSIGN_FW, +#endif + .d_CORE_CTRL_CPU_INTR_MASK = AR6320V2_CORE_CTRL_CPU_INTR_MASK, + .d_SR_WR_INDEX_ADDRESS = AR6320V2_SR_WR_INDEX_ADDRESS, + .d_DST_WATERMARK_ADDRESS = AR6320V2_DST_WATERMARK_ADDRESS, + /* htt_rx.c */ + .d_RX_MSDU_END_4_FIRST_MSDU_MASK = + AR6320V2_RX_MSDU_END_4_FIRST_MSDU_MASK, + .d_RX_MSDU_END_4_FIRST_MSDU_LSB = + AR6320V2_RX_MSDU_END_4_FIRST_MSDU_LSB, + .d_RX_MPDU_START_0_RETRY_MASK = + AR6320V2_RX_MPDU_START_0_RETRY_MASK, + .d_RX_MPDU_START_0_SEQ_NUM_MASK = + AR6320V2_RX_MPDU_START_0_SEQ_NUM_MASK, + .d_RX_MPDU_START_0_SEQ_NUM_MASK = + AR6320V2_RX_MPDU_START_0_SEQ_NUM_MASK, + .d_RX_MPDU_START_0_SEQ_NUM_LSB = AR6320V2_RX_MPDU_START_0_SEQ_NUM_LSB, + .d_RX_MPDU_START_2_PN_47_32_LSB = + AR6320V2_RX_MPDU_START_2_PN_47_32_LSB, + .d_RX_MPDU_START_2_PN_47_32_MASK = + AR6320V2_RX_MPDU_START_2_PN_47_32_MASK, + .d_RX_MPDU_START_2_TID_LSB = + AR6320V2_RX_MPDU_START_2_TID_LSB, + .d_RX_MPDU_START_2_TID_MASK = + AR6320V2_RX_MPDU_START_2_TID_MASK, + .d_RX_MSDU_END_1_EXT_WAPI_PN_63_48_MASK = + AR6320V2_RX_MSDU_END_1_EXT_WAPI_PN_63_48_MASK, + .d_RX_MSDU_END_1_EXT_WAPI_PN_63_48_LSB = + AR6320V2_RX_MSDU_END_1_EXT_WAPI_PN_63_48_LSB, + .d_RX_MSDU_END_4_LAST_MSDU_MASK = + AR6320V2_RX_MSDU_END_4_LAST_MSDU_MASK, + .d_RX_MSDU_END_4_LAST_MSDU_LSB = AR6320V2_RX_MSDU_END_4_LAST_MSDU_LSB, + .d_RX_ATTENTION_0_MCAST_BCAST_MASK = + AR6320V2_RX_ATTENTION_0_MCAST_BCAST_MASK, + .d_RX_ATTENTION_0_MCAST_BCAST_LSB = + AR6320V2_RX_ATTENTION_0_MCAST_BCAST_LSB, + .d_RX_ATTENTION_0_FRAGMENT_MASK = + AR6320V2_RX_ATTENTION_0_FRAGMENT_MASK, + .d_RX_ATTENTION_0_FRAGMENT_LSB = AR6320V2_RX_ATTENTION_0_FRAGMENT_LSB, + .d_RX_ATTENTION_0_MPDU_LENGTH_ERR_MASK = + AR6320V2_RX_ATTENTION_0_MPDU_LENGTH_ERR_MASK, + .d_RX_FRAG_INFO_0_RING2_MORE_COUNT_MASK = + AR6320V2_RX_FRAG_INFO_0_RING2_MORE_COUNT_MASK, + .d_RX_FRAG_INFO_0_RING2_MORE_COUNT_LSB = + AR6320V2_RX_FRAG_INFO_0_RING2_MORE_COUNT_LSB, + .d_RX_MSDU_START_0_MSDU_LENGTH_MASK = + AR6320V2_RX_MSDU_START_0_MSDU_LENGTH_MASK, + .d_RX_MSDU_START_0_MSDU_LENGTH_LSB = + AR6320V2_RX_MSDU_START_0_MSDU_LENGTH_LSB, + .d_RX_MSDU_START_2_DECAP_FORMAT_OFFSET = + AR6320V2_RX_MSDU_START_2_DECAP_FORMAT_OFFSET, + .d_RX_MSDU_START_2_DECAP_FORMAT_MASK = + AR6320V2_RX_MSDU_START_2_DECAP_FORMAT_MASK, + .d_RX_MSDU_START_2_DECAP_FORMAT_LSB = + AR6320V2_RX_MSDU_START_2_DECAP_FORMAT_LSB, + .d_RX_MPDU_START_0_ENCRYPTED_MASK = + AR6320V2_RX_MPDU_START_0_ENCRYPTED_MASK, + .d_RX_MPDU_START_0_ENCRYPTED_LSB = + AR6320V2_RX_MPDU_START_0_ENCRYPTED_LSB, + .d_RX_ATTENTION_0_MORE_DATA_MASK = + AR6320V2_RX_ATTENTION_0_MORE_DATA_MASK, + .d_RX_ATTENTION_0_MSDU_DONE_MASK = + AR6320V2_RX_ATTENTION_0_MSDU_DONE_MASK, + .d_RX_ATTENTION_0_TCP_UDP_CHKSUM_FAIL_MASK = + AR6320V2_RX_ATTENTION_0_TCP_UDP_CHKSUM_FAIL_MASK, +#if defined(HIF_PCI) || defined(HIF_SNOC) || defined(HIF_AHB) + .d_CE_COUNT = AR6320V2_CE_COUNT, + .d_MSI_ASSIGN_CE_INITIAL = MSI_ASSIGN_CE_INITIAL, + .d_PCIE_INTR_ENABLE_ADDRESS = AR6320V2_PCIE_INTR_ENABLE_ADDRESS, + .d_PCIE_INTR_CLR_ADDRESS = AR6320V2_PCIE_INTR_CLR_ADDRESS, + .d_PCIE_INTR_FIRMWARE_MASK = AR6320V2_PCIE_INTR_FIRMWARE_MASK, + .d_PCIE_INTR_CE_MASK_ALL = AR6320V2_PCIE_INTR_CE_MASK_ALL, + /* PLL start */ + .d_EFUSE_OFFSET = AR6320V2_EFUSE_OFFSET, + .d_EFUSE_XTAL_SEL_MSB = AR6320V2_EFUSE_XTAL_SEL_MSB, + .d_EFUSE_XTAL_SEL_LSB = AR6320V2_EFUSE_XTAL_SEL_LSB, + .d_EFUSE_XTAL_SEL_MASK = AR6320V2_EFUSE_XTAL_SEL_MASK, + .d_BB_PLL_CONFIG_OFFSET = AR6320V2_BB_PLL_CONFIG_OFFSET, + .d_BB_PLL_CONFIG_OUTDIV_MSB = AR6320V2_BB_PLL_CONFIG_OUTDIV_MSB, + .d_BB_PLL_CONFIG_OUTDIV_LSB = AR6320V2_BB_PLL_CONFIG_OUTDIV_LSB, + .d_BB_PLL_CONFIG_OUTDIV_MASK = AR6320V2_BB_PLL_CONFIG_OUTDIV_MASK, + .d_BB_PLL_CONFIG_FRAC_MSB = AR6320V2_BB_PLL_CONFIG_FRAC_MSB, + .d_BB_PLL_CONFIG_FRAC_LSB = AR6320V2_BB_PLL_CONFIG_FRAC_LSB, + .d_BB_PLL_CONFIG_FRAC_MASK = AR6320V2_BB_PLL_CONFIG_FRAC_MASK, + .d_WLAN_PLL_SETTLE_TIME_MSB = AR6320V2_WLAN_PLL_SETTLE_TIME_MSB, + .d_WLAN_PLL_SETTLE_TIME_LSB = AR6320V2_WLAN_PLL_SETTLE_TIME_LSB, + .d_WLAN_PLL_SETTLE_TIME_MASK = AR6320V2_WLAN_PLL_SETTLE_TIME_MASK, + .d_WLAN_PLL_SETTLE_OFFSET = AR6320V2_WLAN_PLL_SETTLE_OFFSET, + .d_WLAN_PLL_SETTLE_SW_MASK = AR6320V2_WLAN_PLL_SETTLE_SW_MASK, + .d_WLAN_PLL_SETTLE_RSTMASK = AR6320V2_WLAN_PLL_SETTLE_RSTMASK, + .d_WLAN_PLL_SETTLE_RESET = AR6320V2_WLAN_PLL_SETTLE_RESET, + .d_WLAN_PLL_CONTROL_NOPWD_MSB = AR6320V2_WLAN_PLL_CONTROL_NOPWD_MSB, + .d_WLAN_PLL_CONTROL_NOPWD_LSB = AR6320V2_WLAN_PLL_CONTROL_NOPWD_LSB, + .d_WLAN_PLL_CONTROL_NOPWD_MASK = AR6320V2_WLAN_PLL_CONTROL_NOPWD_MASK, + .d_WLAN_PLL_CONTROL_BYPASS_MSB = AR6320V2_WLAN_PLL_CONTROL_BYPASS_MSB, + .d_WLAN_PLL_CONTROL_BYPASS_LSB = AR6320V2_WLAN_PLL_CONTROL_BYPASS_LSB, + .d_WLAN_PLL_CONTROL_BYPASS_MASK = + AR6320V2_WLAN_PLL_CONTROL_BYPASS_MASK, + .d_WLAN_PLL_CONTROL_BYPASS_RESET = + AR6320V2_WLAN_PLL_CONTROL_BYPASS_RESET, + .d_WLAN_PLL_CONTROL_CLK_SEL_MSB = + AR6320V2_WLAN_PLL_CONTROL_CLK_SEL_MSB, + .d_WLAN_PLL_CONTROL_CLK_SEL_LSB = + AR6320V2_WLAN_PLL_CONTROL_CLK_SEL_LSB, + .d_WLAN_PLL_CONTROL_CLK_SEL_MASK = + AR6320V2_WLAN_PLL_CONTROL_CLK_SEL_MASK, + .d_WLAN_PLL_CONTROL_CLK_SEL_RESET = + AR6320V2_WLAN_PLL_CONTROL_CLK_SEL_RESET, + .d_WLAN_PLL_CONTROL_REFDIV_MSB = AR6320V2_WLAN_PLL_CONTROL_REFDIV_MSB, + .d_WLAN_PLL_CONTROL_REFDIV_LSB = AR6320V2_WLAN_PLL_CONTROL_REFDIV_LSB, + .d_WLAN_PLL_CONTROL_REFDIV_MASK = + AR6320V2_WLAN_PLL_CONTROL_REFDIV_MASK, + .d_WLAN_PLL_CONTROL_REFDIV_RESET = + AR6320V2_WLAN_PLL_CONTROL_REFDIV_RESET, + .d_WLAN_PLL_CONTROL_DIV_MSB = AR6320V2_WLAN_PLL_CONTROL_DIV_MSB, + .d_WLAN_PLL_CONTROL_DIV_LSB = AR6320V2_WLAN_PLL_CONTROL_DIV_LSB, + .d_WLAN_PLL_CONTROL_DIV_MASK = AR6320V2_WLAN_PLL_CONTROL_DIV_MASK, + .d_WLAN_PLL_CONTROL_DIV_RESET = AR6320V2_WLAN_PLL_CONTROL_DIV_RESET, + .d_WLAN_PLL_CONTROL_OFFSET = AR6320V2_WLAN_PLL_CONTROL_OFFSET, + .d_WLAN_PLL_CONTROL_SW_MASK = AR6320V2_WLAN_PLL_CONTROL_SW_MASK, + .d_WLAN_PLL_CONTROL_RSTMASK = AR6320V2_WLAN_PLL_CONTROL_RSTMASK, + .d_WLAN_PLL_CONTROL_RESET = AR6320V2_WLAN_PLL_CONTROL_RESET, + .d_SOC_CORE_CLK_CTRL_OFFSET = AR6320V2_SOC_CORE_CLK_CTRL_OFFSET, + .d_SOC_CORE_CLK_CTRL_DIV_MSB = AR6320V2_SOC_CORE_CLK_CTRL_DIV_MSB, + .d_SOC_CORE_CLK_CTRL_DIV_LSB = AR6320V2_SOC_CORE_CLK_CTRL_DIV_LSB, + .d_SOC_CORE_CLK_CTRL_DIV_MASK = AR6320V2_SOC_CORE_CLK_CTRL_DIV_MASK, + .d_RTC_SYNC_STATUS_PLL_CHANGING_MSB = + AR6320V2_RTC_SYNC_STATUS_PLL_CHANGING_MSB, + .d_RTC_SYNC_STATUS_PLL_CHANGING_LSB = + AR6320V2_RTC_SYNC_STATUS_PLL_CHANGING_LSB, + .d_RTC_SYNC_STATUS_PLL_CHANGING_MASK = + AR6320V2_RTC_SYNC_STATUS_PLL_CHANGING_MASK, + .d_RTC_SYNC_STATUS_PLL_CHANGING_RESET = + AR6320V2_RTC_SYNC_STATUS_PLL_CHANGING_RESET, + .d_RTC_SYNC_STATUS_OFFSET = AR6320V2_RTC_SYNC_STATUS_OFFSET, + .d_SOC_CPU_CLOCK_OFFSET = AR6320V2_SOC_CPU_CLOCK_OFFSET, + .d_SOC_CPU_CLOCK_STANDARD_MSB = AR6320V2_SOC_CPU_CLOCK_STANDARD_MSB, + .d_SOC_CPU_CLOCK_STANDARD_LSB = AR6320V2_SOC_CPU_CLOCK_STANDARD_LSB, + .d_SOC_CPU_CLOCK_STANDARD_MASK = AR6320V2_SOC_CPU_CLOCK_STANDARD_MASK, + /* PLL end */ + .d_SOC_POWER_REG_OFFSET = AR6320V2_SOC_POWER_REG_OFFSET, + .d_PCIE_INTR_CAUSE_ADDRESS = AR6320V2_PCIE_INTR_CAUSE_ADDRESS, + .d_SOC_RESET_CONTROL_ADDRESS = AR6320V2_SOC_RESET_CONTROL_ADDRESS, + .d_SOC_RESET_CONTROL_PCIE_RST_SHORT_OVRD_MASK = + AR6320V2_SOC_RESET_CONTROL_PCIE_RST_SHORT_OVRD_MASK, + .d_SOC_RESET_CONTROL_PCIE_RST_SHORT_OVRD_LSB = + AR6320V2_SOC_RESET_CONTROL_PCIE_RST_SHORT_OVRD_LSB, + .d_SOC_RESET_CONTROL_CE_RST_MASK = + AR6320V2_SOC_RESET_CONTROL_CE_RST_MASK, + .d_WLAN_DEBUG_INPUT_SEL_OFFSET = AR6320V2_WLAN_DEBUG_INPUT_SEL_OFFSET, + .d_WLAN_DEBUG_INPUT_SEL_SRC_MSB = + AR6320V2_WLAN_DEBUG_INPUT_SEL_SRC_MSB, + .d_WLAN_DEBUG_INPUT_SEL_SRC_LSB = + AR6320V2_WLAN_DEBUG_INPUT_SEL_SRC_LSB, + .d_WLAN_DEBUG_INPUT_SEL_SRC_MASK = + AR6320V2_WLAN_DEBUG_INPUT_SEL_SRC_MASK, + .d_WLAN_DEBUG_CONTROL_OFFSET = AR6320V2_WLAN_DEBUG_CONTROL_OFFSET, + .d_WLAN_DEBUG_CONTROL_ENABLE_MSB = + AR6320V2_WLAN_DEBUG_CONTROL_ENABLE_MSB, + .d_WLAN_DEBUG_CONTROL_ENABLE_LSB = + AR6320V2_WLAN_DEBUG_CONTROL_ENABLE_LSB, + .d_WLAN_DEBUG_CONTROL_ENABLE_MASK = + AR6320V2_WLAN_DEBUG_CONTROL_ENABLE_MASK, + .d_WLAN_DEBUG_OUT_OFFSET = AR6320V2_WLAN_DEBUG_OUT_OFFSET, + .d_WLAN_DEBUG_OUT_DATA_MSB = AR6320V2_WLAN_DEBUG_OUT_DATA_MSB, + .d_WLAN_DEBUG_OUT_DATA_LSB = AR6320V2_WLAN_DEBUG_OUT_DATA_LSB, + .d_WLAN_DEBUG_OUT_DATA_MASK = AR6320V2_WLAN_DEBUG_OUT_DATA_MASK, + .d_AMBA_DEBUG_BUS_OFFSET = AR6320V2_AMBA_DEBUG_BUS_OFFSET, + .d_AMBA_DEBUG_BUS_PCIE_DEBUG_SEL_MSB = + AR6320V2_AMBA_DEBUG_BUS_PCIE_DEBUG_SEL_MSB, + .d_AMBA_DEBUG_BUS_PCIE_DEBUG_SEL_LSB = + AR6320V2_AMBA_DEBUG_BUS_PCIE_DEBUG_SEL_LSB, + .d_AMBA_DEBUG_BUS_PCIE_DEBUG_SEL_MASK = + AR6320V2_AMBA_DEBUG_BUS_PCIE_DEBUG_SEL_MASK, + .d_AMBA_DEBUG_BUS_SEL_MSB = AR6320V2_AMBA_DEBUG_BUS_SEL_MSB, + .d_AMBA_DEBUG_BUS_SEL_LSB = AR6320V2_AMBA_DEBUG_BUS_SEL_LSB, + .d_AMBA_DEBUG_BUS_SEL_MASK = AR6320V2_AMBA_DEBUG_BUS_SEL_MASK, +#endif + .d_SOC_RESET_CONTROL_CPU_WARM_RST_MASK = + AR6320V2_SOC_RESET_CONTROL_CPU_WARM_RST_MASK, + .d_CPU_INTR_ADDRESS = AR6320V2_CPU_INTR_ADDRESS, + .d_SOC_LF_TIMER_CONTROL0_ADDRESS = + AR6320V2_SOC_LF_TIMER_CONTROL0_ADDRESS, + .d_SOC_LF_TIMER_CONTROL0_ENABLE_MASK = + AR6320V2_SOC_LF_TIMER_CONTROL0_ENABLE_MASK, + /* chip id start */ + .d_SOC_CHIP_ID_ADDRESS = AR6320V2_SOC_CHIP_ID_ADDRESS, + .d_SOC_CHIP_ID_VERSION_MASK = AR6320V2_SOC_CHIP_ID_VERSION_MASK, + .d_SOC_CHIP_ID_VERSION_LSB = AR6320V2_SOC_CHIP_ID_VERSION_LSB, + .d_SOC_CHIP_ID_REVISION_MASK = AR6320V2_SOC_CHIP_ID_REVISION_MASK, + .d_SOC_CHIP_ID_REVISION_LSB = AR6320V2_SOC_CHIP_ID_REVISION_LSB, + /* chip id end */ +}; + +struct hostdef_s ar6320v2_hostdef = { + .d_INT_STATUS_ENABLE_ERROR_LSB = AR6320V2_INT_STATUS_ENABLE_ERROR_LSB, + .d_INT_STATUS_ENABLE_ERROR_MASK = + AR6320V2_INT_STATUS_ENABLE_ERROR_MASK, + .d_INT_STATUS_ENABLE_CPU_LSB = AR6320V2_INT_STATUS_ENABLE_CPU_LSB, + .d_INT_STATUS_ENABLE_CPU_MASK = AR6320V2_INT_STATUS_ENABLE_CPU_MASK, + .d_INT_STATUS_ENABLE_COUNTER_LSB = + AR6320V2_INT_STATUS_ENABLE_COUNTER_LSB, + .d_INT_STATUS_ENABLE_COUNTER_MASK = + AR6320V2_INT_STATUS_ENABLE_COUNTER_MASK, + .d_INT_STATUS_ENABLE_MBOX_DATA_LSB = + AR6320V2_INT_STATUS_ENABLE_MBOX_DATA_LSB, + .d_INT_STATUS_ENABLE_MBOX_DATA_MASK = + AR6320V2_INT_STATUS_ENABLE_MBOX_DATA_MASK, + .d_ERROR_STATUS_ENABLE_RX_UNDERFLOW_LSB = + AR6320V2_ERROR_STATUS_ENABLE_RX_UNDERFLOW_LSB, + .d_ERROR_STATUS_ENABLE_RX_UNDERFLOW_MASK = + AR6320V2_ERROR_STATUS_ENABLE_RX_UNDERFLOW_MASK, + .d_ERROR_STATUS_ENABLE_TX_OVERFLOW_LSB = + AR6320V2_ERROR_STATUS_ENABLE_TX_OVERFLOW_LSB, + .d_ERROR_STATUS_ENABLE_TX_OVERFLOW_MASK = + AR6320V2_ERROR_STATUS_ENABLE_TX_OVERFLOW_MASK, + .d_COUNTER_INT_STATUS_ENABLE_BIT_LSB = + AR6320V2_COUNTER_INT_STATUS_ENABLE_BIT_LSB, + .d_COUNTER_INT_STATUS_ENABLE_BIT_MASK = + AR6320V2_COUNTER_INT_STATUS_ENABLE_BIT_MASK, + .d_INT_STATUS_ENABLE_ADDRESS = AR6320V2_INT_STATUS_ENABLE_ADDRESS, + .d_CPU_INT_STATUS_ENABLE_BIT_LSB = + AR6320V2_CPU_INT_STATUS_ENABLE_BIT_LSB, + .d_CPU_INT_STATUS_ENABLE_BIT_MASK = + AR6320V2_CPU_INT_STATUS_ENABLE_BIT_MASK, + .d_HOST_INT_STATUS_ADDRESS = AR6320V2_HOST_INT_STATUS_ADDRESS, + .d_CPU_INT_STATUS_ADDRESS = AR6320V2_CPU_INT_STATUS_ADDRESS, + .d_ERROR_INT_STATUS_ADDRESS = AR6320V2_ERROR_INT_STATUS_ADDRESS, + .d_ERROR_INT_STATUS_WAKEUP_MASK = + AR6320V2_ERROR_INT_STATUS_WAKEUP_MASK, + .d_ERROR_INT_STATUS_WAKEUP_LSB = AR6320V2_ERROR_INT_STATUS_WAKEUP_LSB, + .d_ERROR_INT_STATUS_RX_UNDERFLOW_MASK = + AR6320V2_ERROR_INT_STATUS_RX_UNDERFLOW_MASK, + .d_ERROR_INT_STATUS_RX_UNDERFLOW_LSB = + AR6320V2_ERROR_INT_STATUS_RX_UNDERFLOW_LSB, + .d_ERROR_INT_STATUS_TX_OVERFLOW_MASK = + AR6320V2_ERROR_INT_STATUS_TX_OVERFLOW_MASK, + .d_ERROR_INT_STATUS_TX_OVERFLOW_LSB = + AR6320V2_ERROR_INT_STATUS_TX_OVERFLOW_LSB, + .d_COUNT_DEC_ADDRESS = AR6320V2_COUNT_DEC_ADDRESS, + .d_HOST_INT_STATUS_CPU_MASK = AR6320V2_HOST_INT_STATUS_CPU_MASK, + .d_HOST_INT_STATUS_CPU_LSB = AR6320V2_HOST_INT_STATUS_CPU_LSB, + .d_HOST_INT_STATUS_ERROR_MASK = AR6320V2_HOST_INT_STATUS_ERROR_MASK, + .d_HOST_INT_STATUS_ERROR_LSB = AR6320V2_HOST_INT_STATUS_ERROR_LSB, + .d_HOST_INT_STATUS_COUNTER_MASK = + AR6320V2_HOST_INT_STATUS_COUNTER_MASK, + .d_HOST_INT_STATUS_COUNTER_LSB = AR6320V2_HOST_INT_STATUS_COUNTER_LSB, + .d_RX_LOOKAHEAD_VALID_ADDRESS = AR6320V2_RX_LOOKAHEAD_VALID_ADDRESS, + .d_WINDOW_DATA_ADDRESS = AR6320V2_WINDOW_DATA_ADDRESS, + .d_WINDOW_READ_ADDR_ADDRESS = AR6320V2_WINDOW_READ_ADDR_ADDRESS, + .d_WINDOW_WRITE_ADDR_ADDRESS = AR6320V2_WINDOW_WRITE_ADDR_ADDRESS, + .d_SOC_GLOBAL_RESET_ADDRESS = AR6320V2_SOC_GLOBAL_RESET_ADDRESS, + .d_RTC_STATE_ADDRESS = AR6320V2_RTC_STATE_ADDRESS, + .d_RTC_STATE_COLD_RESET_MASK = AR6320V2_RTC_STATE_COLD_RESET_MASK, + .d_RTC_STATE_V_MASK = AR6320V2_RTC_STATE_V_MASK, + .d_RTC_STATE_V_LSB = AR6320V2_RTC_STATE_V_LSB, + .d_FW_IND_EVENT_PENDING = AR6320V2_FW_IND_EVENT_PENDING, + .d_FW_IND_INITIALIZED = AR6320V2_FW_IND_INITIALIZED, + .d_RTC_STATE_V_ON = AR6320V2_RTC_STATE_V_ON, +#if defined(SDIO_3_0) + .d_HOST_INT_STATUS_MBOX_DATA_MASK = + AR6320V2_HOST_INT_STATUS_MBOX_DATA_MASK, + .d_HOST_INT_STATUS_MBOX_DATA_LSB = + AR6320V2_HOST_INT_STATUS_MBOX_DATA_LSB, +#endif +#if defined(HIF_PCI) || defined(HIF_SNOC) || defined(HIF_AHB) + .d_FW_IND_HELPER = AR6320V2_FW_IND_HELPER, + .d_MUX_ID_MASK = AR6320V2_MUX_ID_MASK, + .d_TRANSACTION_ID_MASK = AR6320V2_TRANSACTION_ID_MASK, + .d_PCIE_LOCAL_BASE_ADDRESS = AR6320V2_PCIE_LOCAL_BASE_ADDRESS, + .d_PCIE_SOC_WAKE_RESET = AR6320V2_PCIE_SOC_WAKE_RESET, + .d_PCIE_SOC_WAKE_ADDRESS = AR6320V2_PCIE_SOC_WAKE_ADDRESS, + .d_PCIE_SOC_WAKE_V_MASK = AR6320V2_PCIE_SOC_WAKE_V_MASK, + .d_PCIE_SOC_RDY_STATUS_ADDRESS = PCIE_SOC_RDY_STATUS_ADDRESS, + .d_PCIE_SOC_RDY_STATUS_BAR_MASK = PCIE_SOC_RDY_STATUS_BAR_MASK, + .d_SOC_PCIE_BASE_ADDRESS = SOC_PCIE_BASE_ADDRESS, + .d_MSI_MAGIC_ADR_ADDRESS = MSI_MAGIC_ADR_ADDRESS, + .d_MSI_MAGIC_ADDRESS = MSI_MAGIC_ADDRESS, + .d_HOST_CE_COUNT = 8, + .d_ENABLE_MSI = 0, +#endif +}; + +#if defined(HIF_PCI) || defined(HIF_SNOC) || defined(HIF_AHB) +struct ce_reg_def ar6320v2_ce_targetdef = { + /* copy_engine.c */ + .d_DST_WR_INDEX_ADDRESS = AR6320V2_DST_WR_INDEX_ADDRESS, + .d_SRC_WATERMARK_ADDRESS = AR6320V2_SRC_WATERMARK_ADDRESS, + .d_SRC_WATERMARK_LOW_MASK = AR6320V2_SRC_WATERMARK_LOW_MASK, + .d_SRC_WATERMARK_HIGH_MASK = AR6320V2_SRC_WATERMARK_HIGH_MASK, + .d_DST_WATERMARK_LOW_MASK = AR6320V2_DST_WATERMARK_LOW_MASK, + .d_DST_WATERMARK_HIGH_MASK = AR6320V2_DST_WATERMARK_HIGH_MASK, + .d_CURRENT_SRRI_ADDRESS = AR6320V2_CURRENT_SRRI_ADDRESS, + .d_CURRENT_DRRI_ADDRESS = AR6320V2_CURRENT_DRRI_ADDRESS, + .d_HOST_IS_SRC_RING_HIGH_WATERMARK_MASK = + AR6320V2_HOST_IS_SRC_RING_HIGH_WATERMARK_MASK, + .d_HOST_IS_SRC_RING_LOW_WATERMARK_MASK = + AR6320V2_HOST_IS_SRC_RING_LOW_WATERMARK_MASK, + .d_HOST_IS_DST_RING_HIGH_WATERMARK_MASK = + AR6320V2_HOST_IS_DST_RING_HIGH_WATERMARK_MASK, + .d_HOST_IS_DST_RING_LOW_WATERMARK_MASK = + AR6320V2_HOST_IS_DST_RING_LOW_WATERMARK_MASK, + .d_HOST_IS_ADDRESS = AR6320V2_HOST_IS_ADDRESS, + .d_HOST_IS_COPY_COMPLETE_MASK = AR6320V2_HOST_IS_COPY_COMPLETE_MASK, + .d_CE_WRAPPER_BASE_ADDRESS = AR6320V2_CE_WRAPPER_BASE_ADDRESS, + .d_CE_WRAPPER_INTERRUPT_SUMMARY_ADDRESS = + AR6320V2_CE_WRAPPER_INTERRUPT_SUMMARY_ADDRESS, + .d_HOST_IE_ADDRESS = AR6320V2_HOST_IE_ADDRESS, + .d_HOST_IE_COPY_COMPLETE_MASK = AR6320V2_HOST_IE_COPY_COMPLETE_MASK, + .d_SR_BA_ADDRESS = AR6320V2_SR_BA_ADDRESS, + .d_SR_SIZE_ADDRESS = AR6320V2_SR_SIZE_ADDRESS, + .d_CE_CTRL1_ADDRESS = AR6320V2_CE_CTRL1_ADDRESS, + .d_CE_CTRL1_DMAX_LENGTH_MASK = AR6320V2_CE_CTRL1_DMAX_LENGTH_MASK, + .d_DR_BA_ADDRESS = AR6320V2_DR_BA_ADDRESS, + .d_DR_SIZE_ADDRESS = AR6320V2_DR_SIZE_ADDRESS, + .d_MISC_IE_ADDRESS = AR6320V2_MISC_IE_ADDRESS, + .d_MISC_IS_AXI_ERR_MASK = AR6320V2_MISC_IS_AXI_ERR_MASK, + .d_MISC_IS_DST_ADDR_ERR_MASK = AR6320V2_MISC_IS_DST_ADDR_ERR_MASK, + .d_MISC_IS_SRC_LEN_ERR_MASK = AR6320V2_MISC_IS_SRC_LEN_ERR_MASK, + .d_MISC_IS_DST_MAX_LEN_VIO_MASK = + AR6320V2_MISC_IS_DST_MAX_LEN_VIO_MASK, + .d_MISC_IS_DST_RING_OVERFLOW_MASK = + AR6320V2_MISC_IS_DST_RING_OVERFLOW_MASK, + .d_MISC_IS_SRC_RING_OVERFLOW_MASK = + AR6320V2_MISC_IS_SRC_RING_OVERFLOW_MASK, + .d_SRC_WATERMARK_LOW_LSB = AR6320V2_SRC_WATERMARK_LOW_LSB, + .d_SRC_WATERMARK_HIGH_LSB = AR6320V2_SRC_WATERMARK_HIGH_LSB, + .d_DST_WATERMARK_LOW_LSB = AR6320V2_DST_WATERMARK_LOW_LSB, + .d_DST_WATERMARK_HIGH_LSB = AR6320V2_DST_WATERMARK_HIGH_LSB, + .d_CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_MASK = + AR6320V2_CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_MASK, + .d_CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_LSB = + AR6320V2_CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_LSB, + .d_CE_CTRL1_DMAX_LENGTH_LSB = AR6320V2_CE_CTRL1_DMAX_LENGTH_LSB, + .d_CE_CTRL1_SRC_RING_BYTE_SWAP_EN_MASK = + AR6320V2_CE_CTRL1_SRC_RING_BYTE_SWAP_EN_MASK, + .d_CE_CTRL1_DST_RING_BYTE_SWAP_EN_MASK = + AR6320V2_CE_CTRL1_DST_RING_BYTE_SWAP_EN_MASK, + .d_CE_CTRL1_SRC_RING_BYTE_SWAP_EN_LSB = + AR6320V2_CE_CTRL1_SRC_RING_BYTE_SWAP_EN_LSB, + .d_CE_CTRL1_DST_RING_BYTE_SWAP_EN_LSB = + AR6320V2_CE_CTRL1_DST_RING_BYTE_SWAP_EN_LSB, + .d_CE_WRAPPER_DEBUG_OFFSET = AR6320V2_CE_WRAPPER_DEBUG_OFFSET, + .d_CE_WRAPPER_DEBUG_SEL_MSB = AR6320V2_CE_WRAPPER_DEBUG_SEL_MSB, + .d_CE_WRAPPER_DEBUG_SEL_LSB = AR6320V2_CE_WRAPPER_DEBUG_SEL_LSB, + .d_CE_WRAPPER_DEBUG_SEL_MASK = AR6320V2_CE_WRAPPER_DEBUG_SEL_MASK, + .d_CE_DEBUG_OFFSET = AR6320V2_CE_DEBUG_OFFSET, + .d_CE_DEBUG_SEL_MSB = AR6320V2_CE_DEBUG_SEL_MSB, + .d_CE_DEBUG_SEL_LSB = AR6320V2_CE_DEBUG_SEL_LSB, + .d_CE_DEBUG_SEL_MASK = AR6320V2_CE_DEBUG_SEL_MASK, + .d_CE0_BASE_ADDRESS = AR6320V2_CE0_BASE_ADDRESS, + .d_CE1_BASE_ADDRESS = AR6320V2_CE1_BASE_ADDRESS, + +}; +#endif +#endif diff --git a/drivers/staging/qca-wifi-host-cmn/hif/src/ar900Bdef.c b/drivers/staging/qca-wifi-host-cmn/hif/src/ar900Bdef.c new file mode 100644 index 0000000000000000000000000000000000000000..b5b65f7da94b981e21395fc64008b1858a9d565f --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/hif/src/ar900Bdef.c @@ -0,0 +1,228 @@ +/* + * Copyright (c) 2010,2016 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. + */ + +#if defined(AR900B_HEADERS_DEF) +#define AR900B 1 + +#define WLAN_HEADERS 1 +#include "common_drv.h" +#include "AR900B/soc_addrs.h" +#include "AR900B/extra/hw/apb_map.h" +#include "AR900B/hw/gpio_athr_wlan_reg.h" +#ifdef WLAN_HEADERS +#include "AR900B/extra/hw/wifi_top_reg_map.h" +#include "AR900B/hw/rtc_soc_reg.h" +#endif +#include "AR900B/hw/si_reg.h" +#include "AR900B/extra/hw/pcie_local_reg.h" +#include "AR900B/hw/ce_wrapper_reg_csr.h" +#if 0 +#include "hw/soc_core_reg.h" +#include "hw/soc_pcie_reg.h" +#include "hw/ce_reg_csr.h" +#endif + +#include "AR900B/extra/hw/soc_core_reg.h" +#include "AR900B/hw/soc_pcie_reg.h" +#include "AR900B/extra/hw/ce_reg_csr.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Base address is defined in pcie_local_reg.h. Macros which access the + * registers include the base address in their definition. + */ +#define PCIE_LOCAL_BASE_ADDRESS 0 + +#define FW_EVENT_PENDING_ADDRESS (WIFICMN_SCRATCH_3_ADDRESS) +#define DRAM_BASE_ADDRESS TARG_DRAM_START + +/* Backwards compatibility -- TBDXXX */ + +#define MISSING 0 + +#define WLAN_SYSTEM_SLEEP_DISABLE_LSB WIFI_SYSTEM_SLEEP_DISABLE_LSB +#define WLAN_SYSTEM_SLEEP_DISABLE_MASK WIFI_SYSTEM_SLEEP_DISABLE_MASK +#define WLAN_RESET_CONTROL_COLD_RST_MASK WIFI_RESET_CONTROL_MAC_COLD_RST_MASK +#define WLAN_RESET_CONTROL_WARM_RST_MASK WIFI_RESET_CONTROL_MAC_WARM_RST_MASK +#define SOC_CLOCK_CONTROL_OFFSET SOC_CLOCK_CONTROL_ADDRESS +#define SOC_RESET_CONTROL_OFFSET SOC_RESET_CONTROL_ADDRESS +#define CPU_CLOCK_OFFSET SOC_CPU_CLOCK_ADDRESS +#define SOC_LPO_CAL_OFFSET SOC_LPO_CAL_ADDRESS +#define SOC_RESET_CONTROL_CE_RST_MASK WIFI_RESET_CONTROL_CE_RESET_MASK +#define WLAN_SYSTEM_SLEEP_OFFSET WIFI_SYSTEM_SLEEP_ADDRESS +#define WLAN_RESET_CONTROL_OFFSET WIFI_RESET_CONTROL_ADDRESS +#define CLOCK_CONTROL_OFFSET SOC_CLOCK_CONTROL_OFFSET +#define CLOCK_CONTROL_SI0_CLK_MASK SOC_CLOCK_CONTROL_SI0_CLK_MASK +#define RESET_CONTROL_SI0_RST_MASK SOC_RESET_CONTROL_SI0_RST_MASK +#define GPIO_BASE_ADDRESS WLAN_GPIO_BASE_ADDRESS +#define GPIO_PIN0_OFFSET WLAN_GPIO_PIN0_ADDRESS +#define GPIO_PIN1_OFFSET WLAN_GPIO_PIN1_ADDRESS +#define GPIO_PIN0_CONFIG_MASK WLAN_GPIO_PIN0_CONFIG_MASK +#define GPIO_PIN1_CONFIG_MASK WLAN_GPIO_PIN1_CONFIG_MASK +#define SI_BASE_ADDRESS WLAN_SI_BASE_ADDRESS +#define SCRATCH_BASE_ADDRESS SOC_CORE_BASE_ADDRESS +#define LOCAL_SCRATCH_OFFSET 0x18 +#define GPIO_PIN10_OFFSET WLAN_GPIO_PIN10_ADDRESS +#define GPIO_PIN11_OFFSET WLAN_GPIO_PIN11_ADDRESS +#define GPIO_PIN12_OFFSET WLAN_GPIO_PIN12_ADDRESS +#define GPIO_PIN13_OFFSET WLAN_GPIO_PIN13_ADDRESS +#define SI_CONFIG_OFFSET SI_CONFIG_ADDRESS +#define SI_TX_DATA0_OFFSET SI_TX_DATA0_ADDRESS +#define SI_TX_DATA1_OFFSET SI_TX_DATA1_ADDRESS +#define SI_RX_DATA0_OFFSET SI_RX_DATA0_ADDRESS +#define SI_RX_DATA1_OFFSET SI_RX_DATA1_ADDRESS +#define SI_CS_OFFSET SI_CS_ADDRESS +#define CPU_CLOCK_STANDARD_LSB SOC_CPU_CLOCK_STANDARD_LSB +#define CPU_CLOCK_STANDARD_MASK SOC_CPU_CLOCK_STANDARD_MASK +#define LPO_CAL_ENABLE_LSB SOC_LPO_CAL_ENABLE_LSB +#define LPO_CAL_ENABLE_MASK SOC_LPO_CAL_ENABLE_MASK +#define ANALOG_INTF_BASE_ADDRESS WLAN_ANALOG_INTF_BASE_ADDRESS +#define MBOX_BASE_ADDRESS MISSING +#define INT_STATUS_ENABLE_ERROR_LSB MISSING +#define INT_STATUS_ENABLE_ERROR_MASK MISSING +#define INT_STATUS_ENABLE_CPU_LSB MISSING +#define INT_STATUS_ENABLE_CPU_MASK MISSING +#define INT_STATUS_ENABLE_COUNTER_LSB MISSING +#define INT_STATUS_ENABLE_COUNTER_MASK MISSING +#define INT_STATUS_ENABLE_MBOX_DATA_LSB MISSING +#define INT_STATUS_ENABLE_MBOX_DATA_MASK MISSING +#define ERROR_STATUS_ENABLE_RX_UNDERFLOW_LSB MISSING +#define ERROR_STATUS_ENABLE_RX_UNDERFLOW_MASK MISSING +#define ERROR_STATUS_ENABLE_TX_OVERFLOW_LSB MISSING +#define ERROR_STATUS_ENABLE_TX_OVERFLOW_MASK MISSING +#define COUNTER_INT_STATUS_ENABLE_BIT_LSB MISSING +#define COUNTER_INT_STATUS_ENABLE_BIT_MASK MISSING +#define INT_STATUS_ENABLE_ADDRESS MISSING +#define CPU_INT_STATUS_ENABLE_BIT_LSB MISSING +#define CPU_INT_STATUS_ENABLE_BIT_MASK MISSING +#define HOST_INT_STATUS_ADDRESS MISSING +#define CPU_INT_STATUS_ADDRESS MISSING +#define ERROR_INT_STATUS_ADDRESS MISSING +#define ERROR_INT_STATUS_WAKEUP_MASK MISSING +#define ERROR_INT_STATUS_WAKEUP_LSB MISSING +#define ERROR_INT_STATUS_RX_UNDERFLOW_MASK MISSING +#define ERROR_INT_STATUS_RX_UNDERFLOW_LSB MISSING +#define ERROR_INT_STATUS_TX_OVERFLOW_MASK MISSING +#define ERROR_INT_STATUS_TX_OVERFLOW_LSB MISSING +#define COUNT_DEC_ADDRESS MISSING +#define HOST_INT_STATUS_CPU_MASK MISSING +#define HOST_INT_STATUS_CPU_LSB MISSING +#define HOST_INT_STATUS_ERROR_MASK MISSING +#define HOST_INT_STATUS_ERROR_LSB MISSING +#define HOST_INT_STATUS_COUNTER_MASK MISSING +#define HOST_INT_STATUS_COUNTER_LSB MISSING +#define RX_LOOKAHEAD_VALID_ADDRESS MISSING +#define WINDOW_DATA_ADDRESS MISSING +#define WINDOW_READ_ADDR_ADDRESS MISSING +#define WINDOW_WRITE_ADDR_ADDRESS MISSING +/* MAC Descriptor */ +#define RX_PPDU_END_ANTENNA_OFFSET_DWORD (RX_PPDU_END_25_RX_ANTENNA_OFFSET >> 2) +/* GPIO Register */ +#define GPIO_ENABLE_W1TS_LOW_ADDRESS WLAN_GPIO_ENABLE_W1TS_LOW_ADDRESS +#define GPIO_PIN0_CONFIG_LSB WLAN_GPIO_PIN0_CONFIG_LSB +#define GPIO_PIN0_PAD_PULL_LSB WLAN_GPIO_PIN0_PAD_PULL_LSB +#define GPIO_PIN0_PAD_PULL_MASK WLAN_GPIO_PIN0_PAD_PULL_MASK +/* CE descriptor */ +#define CE_SRC_DESC_SIZE_DWORD 2 +#define CE_DEST_DESC_SIZE_DWORD 2 +#define CE_SRC_DESC_SRC_PTR_OFFSET_DWORD 0 +#define CE_SRC_DESC_INFO_OFFSET_DWORD 1 +#define CE_DEST_DESC_DEST_PTR_OFFSET_DWORD 0 +#define CE_DEST_DESC_INFO_OFFSET_DWORD 1 +#if _BYTE_ORDER == _BIG_ENDIAN +#define CE_SRC_DESC_INFO_NBYTES_MASK 0xFFFF0000 +#define CE_SRC_DESC_INFO_NBYTES_SHIFT 16 +#define CE_SRC_DESC_INFO_GATHER_MASK 0x00008000 +#define CE_SRC_DESC_INFO_GATHER_SHIFT 15 +#define CE_SRC_DESC_INFO_BYTE_SWAP_MASK 0x00004000 +#define CE_SRC_DESC_INFO_BYTE_SWAP_SHIFT 14 +#define CE_SRC_DESC_INFO_HOST_INT_DISABLE_MASK 0x00002000 +#define CE_SRC_DESC_INFO_HOST_INT_DISABLE_SHIFT 13 +#define CE_SRC_DESC_INFO_TARGET_INT_DISABLE_MASK 0x00001000 +#define CE_SRC_DESC_INFO_TARGET_INT_DISABLE_SHIFT 12 +#define CE_SRC_DESC_INFO_META_DATA_MASK 0x00000FFF +#define CE_SRC_DESC_INFO_META_DATA_SHIFT 0 +#else +#define CE_SRC_DESC_INFO_NBYTES_MASK 0x0000FFFF +#define CE_SRC_DESC_INFO_NBYTES_SHIFT 0 +#define CE_SRC_DESC_INFO_GATHER_MASK 0x00010000 +#define CE_SRC_DESC_INFO_GATHER_SHIFT 16 +#define CE_SRC_DESC_INFO_BYTE_SWAP_MASK 0x00020000 +#define CE_SRC_DESC_INFO_BYTE_SWAP_SHIFT 17 +#define CE_SRC_DESC_INFO_HOST_INT_DISABLE_MASK 0x00040000 +#define CE_SRC_DESC_INFO_HOST_INT_DISABLE_SHIFT 18 +#define CE_SRC_DESC_INFO_TARGET_INT_DISABLE_MASK 0x00080000 +#define CE_SRC_DESC_INFO_TARGET_INT_DISABLE_SHIFT 19 +#define CE_SRC_DESC_INFO_META_DATA_MASK 0xFFF00000 +#define CE_SRC_DESC_INFO_META_DATA_SHIFT 20 +#endif +#if _BYTE_ORDER == _BIG_ENDIAN +#define CE_DEST_DESC_INFO_NBYTES_MASK 0xFFFF0000 +#define CE_DEST_DESC_INFO_NBYTES_SHIFT 16 +#define CE_DEST_DESC_INFO_GATHER_MASK 0x00008000 +#define CE_DEST_DESC_INFO_GATHER_SHIFT 15 +#define CE_DEST_DESC_INFO_BYTE_SWAP_MASK 0x00004000 +#define CE_DEST_DESC_INFO_BYTE_SWAP_SHIFT 14 +#define CE_DEST_DESC_INFO_HOST_INT_DISABLE_MASK 0x00002000 +#define CE_DEST_DESC_INFO_HOST_INT_DISABLE_SHIFT 13 +#define CE_DEST_DESC_INFO_TARGET_INT_DISABLE_MASK 0x00001000 +#define CE_DEST_DESC_INFO_TARGET_INT_DISABLE_SHIFT 12 +#define CE_DEST_DESC_INFO_META_DATA_MASK 0x00000FFF +#define CE_DEST_DESC_INFO_META_DATA_SHIFT 0 +#else +#define CE_DEST_DESC_INFO_NBYTES_MASK 0x0000FFFF +#define CE_DEST_DESC_INFO_NBYTES_SHIFT 0 +#define CE_DEST_DESC_INFO_GATHER_MASK 0x00010000 +#define CE_DEST_DESC_INFO_GATHER_SHIFT 16 +#define CE_DEST_DESC_INFO_BYTE_SWAP_MASK 0x00020000 +#define CE_DEST_DESC_INFO_BYTE_SWAP_SHIFT 17 +#define CE_DEST_DESC_INFO_HOST_INT_DISABLE_MASK 0x00040000 +#define CE_DEST_DESC_INFO_HOST_INT_DISABLE_SHIFT 18 +#define CE_DEST_DESC_INFO_TARGET_INT_DISABLE_MASK 0x00080000 +#define CE_DEST_DESC_INFO_TARGET_INT_DISABLE_SHIFT 19 +#define CE_DEST_DESC_INFO_META_DATA_MASK 0xFFF00000 +#define CE_DEST_DESC_INFO_META_DATA_SHIFT 20 +#endif + +#define MY_TARGET_DEF AR900B_TARGETdef +#define MY_HOST_DEF AR900B_HOSTdef +#define MY_CEREG_DEF AR900B_CE_TARGETdef +#define MY_TARGET_BOARD_DATA_SZ AR900B_BOARD_DATA_SZ +#define MY_TARGET_BOARD_EXT_DATA_SZ AR900B_BOARD_EXT_DATA_SZ +#include "targetdef.h" +#include "hostdef.h" +#else +#include "common_drv.h" +#include "targetdef.h" +#include "hostdef.h" +struct targetdef_s *AR900B_TARGETdef; +struct hostdef_s *AR900B_HOSTdef; +#endif /*AR900B_HEADERS_DEF */ diff --git a/drivers/staging/qca-wifi-host-cmn/hif/src/ar9888def.c b/drivers/staging/qca-wifi-host-cmn/hif/src/ar9888def.c new file mode 100644 index 0000000000000000000000000000000000000000..7336c52f17b20f35e82ce5065bf9ba9e90cffc01 --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/hif/src/ar9888def.c @@ -0,0 +1,208 @@ +/* + * Copyright (c) 2013,2016 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. + */ + +#if defined(AR9888_HEADERS_DEF) +#define AR9888 1 + +#define WLAN_HEADERS 1 +#include "common_drv.h" +#include "AR9888/v2/soc_addrs.h" +#include "AR9888/v2/hw/apb_athr_wlan_map.h" +#include "AR9888/v2/hw/gpio_athr_wlan_reg.h" +#include "AR9888/v2/hw/rtc_soc_reg.h" +#include "AR9888/v2/hw/rtc_wlan_reg.h" +#include "AR9888/v2/hw/si_reg.h" +#include "AR9888/v2/extra/hw/pcie_local_reg.h" + +#include "AR9888/v2/extra/hw/soc_core_reg.h" +#include "AR9888/v2/hw/soc_pcie_reg.h" +#include "AR9888/v2/extra/hw/ce_reg_csr.h" +#include "AR9888/v2/hw/ce_wrapper_reg_csr.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +/* TBDXXX: Eventually, this Base Address will be defined in HW header files */ +#define PCIE_LOCAL_BASE_ADDRESS 0x80000 + +#define FW_EVENT_PENDING_ADDRESS (SOC_CORE_BASE_ADDRESS+SCRATCH_3_ADDRESS) +#define DRAM_BASE_ADDRESS TARG_DRAM_START + +/* Backwards compatibility -- TBDXXX */ + +#define MISSING 0 + +#define SYSTEM_SLEEP_OFFSET SOC_SYSTEM_SLEEP_OFFSET +#define WLAN_SYSTEM_SLEEP_OFFSET SOC_SYSTEM_SLEEP_OFFSET +#define WLAN_RESET_CONTROL_OFFSET SOC_RESET_CONTROL_OFFSET +#define CLOCK_CONTROL_OFFSET SOC_CLOCK_CONTROL_OFFSET +#define CLOCK_CONTROL_SI0_CLK_MASK SOC_CLOCK_CONTROL_SI0_CLK_MASK +#define RESET_CONTROL_MBOX_RST_MASK MISSING +#define RESET_CONTROL_SI0_RST_MASK SOC_RESET_CONTROL_SI0_RST_MASK +#define GPIO_BASE_ADDRESS WLAN_GPIO_BASE_ADDRESS +#define GPIO_PIN0_OFFSET WLAN_GPIO_PIN0_ADDRESS +#define GPIO_PIN1_OFFSET WLAN_GPIO_PIN1_ADDRESS +#define GPIO_PIN0_CONFIG_MASK WLAN_GPIO_PIN0_CONFIG_MASK +#define GPIO_PIN1_CONFIG_MASK WLAN_GPIO_PIN1_CONFIG_MASK +#define SI_BASE_ADDRESS WLAN_SI_BASE_ADDRESS +#define SCRATCH_BASE_ADDRESS SOC_CORE_BASE_ADDRESS +#define LOCAL_SCRATCH_OFFSET 0x18 +#define CPU_CLOCK_OFFSET SOC_CPU_CLOCK_OFFSET +#define LPO_CAL_OFFSET SOC_LPO_CAL_OFFSET +#define GPIO_PIN10_OFFSET WLAN_GPIO_PIN10_ADDRESS +#define GPIO_PIN11_OFFSET WLAN_GPIO_PIN11_ADDRESS +#define GPIO_PIN12_OFFSET WLAN_GPIO_PIN12_ADDRESS +#define GPIO_PIN13_OFFSET WLAN_GPIO_PIN13_ADDRESS +#define CPU_CLOCK_STANDARD_LSB SOC_CPU_CLOCK_STANDARD_LSB +#define CPU_CLOCK_STANDARD_MASK SOC_CPU_CLOCK_STANDARD_MASK +#define LPO_CAL_ENABLE_LSB SOC_LPO_CAL_ENABLE_LSB +#define LPO_CAL_ENABLE_MASK SOC_LPO_CAL_ENABLE_MASK +#define ANALOG_INTF_BASE_ADDRESS WLAN_ANALOG_INTF_BASE_ADDRESS +#define MBOX_BASE_ADDRESS MISSING +#define INT_STATUS_ENABLE_ERROR_LSB MISSING +#define INT_STATUS_ENABLE_ERROR_MASK MISSING +#define INT_STATUS_ENABLE_CPU_LSB MISSING +#define INT_STATUS_ENABLE_CPU_MASK MISSING +#define INT_STATUS_ENABLE_COUNTER_LSB MISSING +#define INT_STATUS_ENABLE_COUNTER_MASK MISSING +#define INT_STATUS_ENABLE_MBOX_DATA_LSB MISSING +#define INT_STATUS_ENABLE_MBOX_DATA_MASK MISSING +#define ERROR_STATUS_ENABLE_RX_UNDERFLOW_LSB MISSING +#define ERROR_STATUS_ENABLE_RX_UNDERFLOW_MASK MISSING +#define ERROR_STATUS_ENABLE_TX_OVERFLOW_LSB MISSING +#define ERROR_STATUS_ENABLE_TX_OVERFLOW_MASK MISSING +#define COUNTER_INT_STATUS_ENABLE_BIT_LSB MISSING +#define COUNTER_INT_STATUS_ENABLE_BIT_MASK MISSING +#define INT_STATUS_ENABLE_ADDRESS MISSING +#define CPU_INT_STATUS_ENABLE_BIT_LSB MISSING +#define CPU_INT_STATUS_ENABLE_BIT_MASK MISSING +#define HOST_INT_STATUS_ADDRESS MISSING +#define CPU_INT_STATUS_ADDRESS MISSING +#define ERROR_INT_STATUS_ADDRESS MISSING +#define ERROR_INT_STATUS_WAKEUP_MASK MISSING +#define ERROR_INT_STATUS_WAKEUP_LSB MISSING +#define ERROR_INT_STATUS_RX_UNDERFLOW_MASK MISSING +#define ERROR_INT_STATUS_RX_UNDERFLOW_LSB MISSING +#define ERROR_INT_STATUS_TX_OVERFLOW_MASK MISSING +#define ERROR_INT_STATUS_TX_OVERFLOW_LSB MISSING +#define COUNT_DEC_ADDRESS MISSING +#define HOST_INT_STATUS_CPU_MASK MISSING +#define HOST_INT_STATUS_CPU_LSB MISSING +#define HOST_INT_STATUS_ERROR_MASK MISSING +#define HOST_INT_STATUS_ERROR_LSB MISSING +#define HOST_INT_STATUS_COUNTER_MASK MISSING +#define HOST_INT_STATUS_COUNTER_LSB MISSING +#define RX_LOOKAHEAD_VALID_ADDRESS MISSING +#define WINDOW_DATA_ADDRESS MISSING +#define WINDOW_READ_ADDR_ADDRESS MISSING +#define WINDOW_WRITE_ADDR_ADDRESS MISSING +/* MAC descriptor */ +#define RX_ATTENTION_0_PHY_DATA_TYPE_MASK MISSING +#define RX_MSDU_END_8_LRO_ELIGIBLE_MASK MISSING +#define RX_MSDU_END_8_LRO_ELIGIBLE_LSB MISSING +#define RX_MSDU_END_8_L3_HEADER_PADDING_LSB MISSING +#define RX_MSDU_END_8_L3_HEADER_PADDING_MASK MISSING +#define RX_PPDU_END_ANTENNA_OFFSET_DWORD (RX_PPDU_END_19_RX_ANTENNA_OFFSET >> 2) +#define MSDU_LINK_EXT_3_TCP_OVER_IPV4_CHECKSUM_EN_MASK MISSING +#define MSDU_LINK_EXT_3_TCP_OVER_IPV6_CHECKSUM_EN_MASK MISSING +#define MSDU_LINK_EXT_3_UDP_OVER_IPV4_CHECKSUM_EN_MASK MISSING +#define MSDU_LINK_EXT_3_UDP_OVER_IPV6_CHECKSUM_EN_MASK MISSING +#define MSDU_LINK_EXT_3_TCP_OVER_IPV4_CHECKSUM_EN_LSB MISSING +#define MSDU_LINK_EXT_3_TCP_OVER_IPV6_CHECKSUM_EN_LSB MISSING +#define MSDU_LINK_EXT_3_UDP_OVER_IPV4_CHECKSUM_EN_LSB MISSING +#define MSDU_LINK_EXT_3_UDP_OVER_IPV6_CHECKSUM_EN_LSB MISSING +/* GPIO Register */ + +#define GPIO_ENABLE_W1TS_LOW_ADDRESS WLAN_GPIO_ENABLE_W1TS_LOW_ADDRESS +#define GPIO_PIN0_CONFIG_LSB WLAN_GPIO_PIN0_CONFIG_LSB +#define GPIO_PIN0_PAD_PULL_LSB WLAN_GPIO_PIN0_PAD_PULL_LSB +#define GPIO_PIN0_PAD_PULL_MASK WLAN_GPIO_PIN0_PAD_PULL_MASK +/* CE descriptor */ +#define CE_SRC_DESC_SIZE_DWORD 2 +#define CE_DEST_DESC_SIZE_DWORD 2 +#define CE_SRC_DESC_SRC_PTR_OFFSET_DWORD 0 +#define CE_SRC_DESC_INFO_OFFSET_DWORD 1 +#define CE_DEST_DESC_DEST_PTR_OFFSET_DWORD 0 +#define CE_DEST_DESC_INFO_OFFSET_DWORD 1 +#define CE_SRC_DESC_INFO_HOST_INT_DISABLE_MASK MISSING +#define CE_SRC_DESC_INFO_HOST_INT_DISABLE_SHIFT MISSING +#define CE_SRC_DESC_INFO_TARGET_INT_DISABLE_MASK MISSING +#define CE_SRC_DESC_INFO_TARGET_INT_DISABLE_SHIFT MISSING +#define CE_DEST_DESC_INFO_HOST_INT_DISABLE_MASK MISSING +#define CE_DEST_DESC_INFO_HOST_INT_DISABLE_SHIFT MISSING +#define CE_DEST_DESC_INFO_TARGET_INT_DISABLE_MASK MISSING +#define CE_DEST_DESC_INFO_TARGET_INT_DISABLE_SHIFT MISSING +#if _BYTE_ORDER == _BIG_ENDIAN +#define CE_SRC_DESC_INFO_NBYTES_MASK 0xFFFF0000 +#define CE_SRC_DESC_INFO_NBYTES_SHIFT 16 +#define CE_SRC_DESC_INFO_GATHER_MASK 0x00008000 +#define CE_SRC_DESC_INFO_GATHER_SHIFT 15 +#define CE_SRC_DESC_INFO_BYTE_SWAP_MASK 0x00004000 +#define CE_SRC_DESC_INFO_BYTE_SWAP_SHIFT 14 +#define CE_SRC_DESC_INFO_META_DATA_MASK 0x00003FFF +#define CE_SRC_DESC_INFO_META_DATA_SHIFT 0 +#else +#define CE_SRC_DESC_INFO_NBYTES_MASK 0x0000FFFF +#define CE_SRC_DESC_INFO_NBYTES_SHIFT 0 +#define CE_SRC_DESC_INFO_GATHER_MASK 0x00010000 +#define CE_SRC_DESC_INFO_GATHER_SHIFT 16 +#define CE_SRC_DESC_INFO_BYTE_SWAP_MASK 0x00020000 +#define CE_SRC_DESC_INFO_BYTE_SWAP_SHIFT 17 +#define CE_SRC_DESC_INFO_META_DATA_MASK 0xFFFC0000 +#define CE_SRC_DESC_INFO_META_DATA_SHIFT 18 +#endif +#if _BYTE_ORDER == _BIG_ENDIAN +#define CE_DEST_DESC_INFO_NBYTES_MASK 0xFFFF0000 +#define CE_DEST_DESC_INFO_NBYTES_SHIFT 16 +#define CE_DEST_DESC_INFO_GATHER_MASK 0x00008000 +#define CE_DEST_DESC_INFO_GATHER_SHIFT 15 +#define CE_DEST_DESC_INFO_BYTE_SWAP_MASK 0x00004000 +#define CE_DEST_DESC_INFO_BYTE_SWAP_SHIFT 14 +#define CE_DEST_DESC_INFO_META_DATA_MASK 0x00003FFF +#define CE_DEST_DESC_INFO_META_DATA_SHIFT 0 +#else +#define CE_DEST_DESC_INFO_NBYTES_MASK 0x0000FFFF +#define CE_DEST_DESC_INFO_NBYTES_SHIFT 0 +#define CE_DEST_DESC_INFO_GATHER_MASK 0x00010000 +#define CE_DEST_DESC_INFO_GATHER_SHIFT 16 +#define CE_DEST_DESC_INFO_BYTE_SWAP_MASK 0x00020000 +#define CE_DEST_DESC_INFO_BYTE_SWAP_SHIFT 17 +#define CE_DEST_DESC_INFO_META_DATA_MASK 0xFFFC0000 +#define CE_DEST_DESC_INFO_META_DATA_SHIFT 18 +#endif + +#define MY_TARGET_DEF AR9888_TARGETdef +#define MY_HOST_DEF AR9888_HOSTdef +#define MY_CEREG_DEF AR9888_CE_TARGETdef +#define MY_TARGET_BOARD_DATA_SZ AR9888_BOARD_DATA_SZ +#define MY_TARGET_BOARD_EXT_DATA_SZ AR9888_BOARD_EXT_DATA_SZ +#include "targetdef.h" +#include "hostdef.h" +#else +#include "common_drv.h" +#include "targetdef.h" +#include "hostdef.h" +struct targetdef_s *AR9888_TARGETdef; +struct hostdef_s *AR9888_HOSTdef; +#endif /*AR9888_HEADERS_DEF */ diff --git a/drivers/staging/qca-wifi-host-cmn/hif/src/ar9888def.h b/drivers/staging/qca-wifi-host-cmn/hif/src/ar9888def.h new file mode 100644 index 0000000000000000000000000000000000000000..1ebe643d746e60f42034222ca921ca28d660fe94 --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/hif/src/ar9888def.h @@ -0,0 +1,600 @@ +/* + * Copyright (c) 2011-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef _AR9888DEF_H_ +#define _AR9888DEF_H_ + +/* Base Addresses */ +#define AR9888_RTC_SOC_BASE_ADDRESS 0x00004000 +#define AR9888_RTC_WMAC_BASE_ADDRESS 0x00005000 +#define AR9888_MAC_COEX_BASE_ADDRESS 0x00006000 +#define AR9888_BT_COEX_BASE_ADDRESS 0x00007000 +#define AR9888_SOC_PCIE_BASE_ADDRESS 0x00008000 +#define AR9888_SOC_CORE_BASE_ADDRESS 0x00009000 +#define AR9888_WLAN_UART_BASE_ADDRESS 0x0000c000 +#define AR9888_WLAN_SI_BASE_ADDRESS 0x00010000 +#define AR9888_WLAN_GPIO_BASE_ADDRESS 0x00014000 +#define AR9888_WLAN_ANALOG_INTF_BASE_ADDRESS 0x0001c000 +#define AR9888_WLAN_MAC_BASE_ADDRESS 0x00020000 +#define AR9888_EFUSE_BASE_ADDRESS 0x00030000 +#define AR9888_FPGA_REG_BASE_ADDRESS 0x00039000 +#define AR9888_WLAN_UART2_BASE_ADDRESS 0x00054c00 +#if defined(HIF_PCI) || defined(HIF_SNOC) || defined(HIF_AHB) +#define AR9888_CE_WRAPPER_BASE_ADDRESS 0x00057000 +#define AR9888_CE0_BASE_ADDRESS 0x00057400 +#define AR9888_CE1_BASE_ADDRESS 0x00057800 +#define AR9888_CE2_BASE_ADDRESS 0x00057c00 +#define AR9888_CE3_BASE_ADDRESS 0x00058000 +#define AR9888_CE4_BASE_ADDRESS 0x00058400 +#define AR9888_CE5_BASE_ADDRESS 0x00058800 +#define AR9888_CE6_BASE_ADDRESS 0x00058c00 +#define AR9888_CE7_BASE_ADDRESS 0x00059000 +#define AR9888_WLAN_ANALOG_INTF_PCIE_BASE_ADDRESS 0x0006c000 +#define AR9888_CE_CTRL1_ADDRESS 0x0010 +#define AR9888_CE_CTRL1_DMAX_LENGTH_MASK 0x0000ffff +#define AR9888_CE_WRAPPER_INTERRUPT_SUMMARY_ADDRESS 0x0000 +#define AR9888_CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_MASK 0x0000ff00 +#define AR9888_CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_LSB 8 +#define AR9888_CE_CTRL1_DMAX_LENGTH_LSB 0 +#define AR9888_CE_CTRL1_SRC_RING_BYTE_SWAP_EN_MASK 0x00010000 +#define AR9888_CE_CTRL1_DST_RING_BYTE_SWAP_EN_MASK 0x00020000 +#define AR9888_CE_CTRL1_SRC_RING_BYTE_SWAP_EN_LSB 16 +#define AR9888_CE_CTRL1_DST_RING_BYTE_SWAP_EN_LSB 17 +#define AR9888_SOC_RESET_CONTROL_PCIE_RST_SHORT_OVRD_MASK 0x00000004 +#define AR9888_SOC_RESET_CONTROL_PCIE_RST_SHORT_OVRD_LSB 2 +#define AR9888_PCIE_SOC_WAKE_RESET 0x00000000 +#define AR9888_PCIE_SOC_WAKE_ADDRESS 0x0004 +#define AR9888_PCIE_SOC_WAKE_V_MASK 0x00000001 +#define AR9888_PCIE_INTR_ENABLE_ADDRESS 0x0008 +#define AR9888_PCIE_INTR_CLR_ADDRESS 0x0014 +#define AR9888_PCIE_INTR_FIRMWARE_MASK 0x00000400 +#define AR9888_PCIE_INTR_CE0_MASK 0x00000800 +#define AR9888_PCIE_INTR_CE_MASK_ALL 0x0007f800 +#define AR9888_PCIE_INTR_CAUSE_ADDRESS 0x000c +#define AR9888_MUX_ID_MASK 0x0000 +#define AR9888_TRANSACTION_ID_MASK 0x3fff +#define AR9888_PCIE_LOCAL_BASE_ADDRESS 0x80000 +#define AR9888_SOC_RESET_CONTROL_CE_RST_MASK 0x00040000 +#define AR9888_PCIE_INTR_CE_MASK(n) (AR9888_PCIE_INTR_CE0_MASK << (n)) +#endif +#define AR9888_DBI_BASE_ADDRESS 0x00060000 +#define AR9888_SCRATCH_3_ADDRESS 0x0030 +#define AR9888_TARG_DRAM_START 0x00400000 +#define AR9888_SOC_SYSTEM_SLEEP_OFFSET 0x000000c4 +#define AR9888_SOC_RESET_CONTROL_OFFSET 0x00000000 +#define AR9888_SOC_CLOCK_CONTROL_OFFSET 0x00000028 +#define AR9888_SOC_CLOCK_CONTROL_SI0_CLK_MASK 0x00000001 +#define AR9888_SOC_RESET_CONTROL_SI0_RST_MASK 0x00000001 +#define AR9888_WLAN_GPIO_BASE_ADDRESS 0x00014000 +#define AR9888_WLAN_GPIO_PIN0_ADDRESS 0x00000028 +#define AR9888_WLAN_GPIO_PIN1_ADDRESS 0x0000002c +#define AR9888_WLAN_GPIO_PIN0_CONFIG_MASK 0x00007800 +#define AR9888_WLAN_GPIO_PIN1_CONFIG_MASK 0x00007800 +#define AR9888_WLAN_SI_BASE_ADDRESS 0x00010000 +#define AR9888_SOC_CPU_CLOCK_OFFSET 0x00000020 +#define AR9888_SOC_LPO_CAL_OFFSET 0x000000e0 +#define AR9888_WLAN_GPIO_PIN10_ADDRESS 0x00000050 +#define AR9888_WLAN_GPIO_PIN11_ADDRESS 0x00000054 +#define AR9888_WLAN_GPIO_PIN12_ADDRESS 0x00000058 +#define AR9888_WLAN_GPIO_PIN13_ADDRESS 0x0000005c +#define AR9888_SOC_CPU_CLOCK_STANDARD_LSB 0 +#define AR9888_SOC_CPU_CLOCK_STANDARD_MASK 0x00000003 +#define AR9888_SOC_LPO_CAL_ENABLE_LSB 20 +#define AR9888_SOC_LPO_CAL_ENABLE_MASK 0x00100000 +#define AR9888_WLAN_ANALOG_INTF_BASE_ADDRESS 0x0001c000 + +#define AR9888_WLAN_SYSTEM_SLEEP_DISABLE_LSB 0 +#define AR9888_WLAN_SYSTEM_SLEEP_DISABLE_MASK 0x00000001 +#define AR9888_WLAN_RESET_CONTROL_COLD_RST_MASK 0x00000008 +#define AR9888_WLAN_RESET_CONTROL_WARM_RST_MASK 0x00000004 +#define AR9888_SI_CONFIG_BIDIR_OD_DATA_LSB 18 +#define AR9888_SI_CONFIG_BIDIR_OD_DATA_MASK 0x00040000 +#define AR9888_SI_CONFIG_I2C_LSB 16 +#define AR9888_SI_CONFIG_I2C_MASK 0x00010000 +#define AR9888_SI_CONFIG_POS_SAMPLE_LSB 7 +#define AR9888_SI_CONFIG_POS_SAMPLE_MASK 0x00000080 +#define AR9888_SI_CONFIG_INACTIVE_CLK_LSB 4 +#define AR9888_SI_CONFIG_INACTIVE_CLK_MASK 0x00000010 +#define AR9888_SI_CONFIG_INACTIVE_DATA_LSB 5 +#define AR9888_SI_CONFIG_INACTIVE_DATA_MASK 0x00000020 +#define AR9888_SI_CONFIG_DIVIDER_LSB 0 +#define AR9888_SI_CONFIG_DIVIDER_MASK 0x0000000f +#define AR9888_SI_CONFIG_OFFSET 0x00000000 +#define AR9888_SI_TX_DATA0_OFFSET 0x00000008 +#define AR9888_SI_TX_DATA1_OFFSET 0x0000000c +#define AR9888_SI_RX_DATA0_OFFSET 0x00000010 +#define AR9888_SI_RX_DATA1_OFFSET 0x00000014 +#define AR9888_SI_CS_OFFSET 0x00000004 +#define AR9888_SI_CS_DONE_ERR_MASK 0x00000400 +#define AR9888_SI_CS_DONE_INT_MASK 0x00000200 +#define AR9888_SI_CS_START_LSB 8 +#define AR9888_SI_CS_START_MASK 0x00000100 +#define AR9888_SI_CS_RX_CNT_LSB 4 +#define AR9888_SI_CS_RX_CNT_MASK 0x000000f0 +#define AR9888_SI_CS_TX_CNT_LSB 0 +#define AR9888_SI_CS_TX_CNT_MASK 0x0000000f +#define AR9888_CE_COUNT 8 +#define AR9888_SR_WR_INDEX_ADDRESS 0x003c +#define AR9888_DST_WATERMARK_ADDRESS 0x0050 +#define AR9888_RX_MSDU_END_4_FIRST_MSDU_LSB 14 +#define AR9888_RX_MSDU_END_4_FIRST_MSDU_MASK 0x00004000 +#define AR9888_RX_MPDU_START_0_SEQ_NUM_LSB 16 +#define AR9888_RX_MPDU_START_0_SEQ_NUM_MASK 0x0fff0000 +#define AR9888_RX_MPDU_START_2_PN_47_32_LSB 0 +#define AR9888_RX_MPDU_START_2_PN_47_32_MASK 0x0000ffff +#define AR9888_RX_MSDU_END_1_KEY_ID_OCT_MASK 0x000000ff +#define AR9888_RX_MSDU_END_1_KEY_ID_OCT_LSB 0 +#define AR9888_RX_MSDU_END_1_EXT_WAPI_PN_63_48_LSB 16 +#define AR9888_RX_MSDU_END_1_EXT_WAPI_PN_63_48_MASK 0xffff0000 +#define AR9888_RX_MSDU_END_4_LAST_MSDU_LSB 15 +#define AR9888_RX_MSDU_END_4_LAST_MSDU_MASK 0x00008000 +#define AR9888_RX_ATTENTION_0_MCAST_BCAST_LSB 2 +#define AR9888_RX_ATTENTION_0_MCAST_BCAST_MASK 0x00000004 +#define AR9888_RX_ATTENTION_0_FRAGMENT_LSB 13 +#define AR9888_RX_ATTENTION_0_FRAGMENT_MASK 0x00002000 +#define AR9888_RX_ATTENTION_0_MPDU_LENGTH_ERR_MASK 0x08000000 +#define AR9888_RX_FRAG_INFO_0_RING2_MORE_COUNT_LSB 16 +#define AR9888_RX_FRAG_INFO_0_RING2_MORE_COUNT_MASK 0x00ff0000 +#define AR9888_RX_MSDU_START_0_MSDU_LENGTH_LSB 0 +#define AR9888_RX_MSDU_START_0_MSDU_LENGTH_MASK 0x00003fff +#define AR9888_RX_MSDU_START_2_DECAP_FORMAT_OFFSET 0x00000008 +#define AR9888_RX_MSDU_START_2_DECAP_FORMAT_LSB 8 +#define AR9888_RX_MSDU_START_2_DECAP_FORMAT_MASK 0x00000300 +#define AR9888_RX_MPDU_START_0_ENCRYPTED_LSB 13 +#define AR9888_RX_MPDU_START_0_ENCRYPTED_MASK 0x00002000 +#define AR9888_RX_ATTENTION_0_MORE_DATA_MASK 0x00000400 +#define AR9888_RX_ATTENTION_0_MSDU_DONE_MASK 0x80000000 +#define AR9888_RX_ATTENTION_0_TCP_UDP_CHKSUM_FAIL_MASK 0x00040000 +#define AR9888_DST_WR_INDEX_ADDRESS 0x0040 +#define AR9888_SRC_WATERMARK_ADDRESS 0x004c +#define AR9888_SRC_WATERMARK_LOW_MASK 0xffff0000 +#define AR9888_SRC_WATERMARK_HIGH_MASK 0x0000ffff +#define AR9888_DST_WATERMARK_LOW_MASK 0xffff0000 +#define AR9888_DST_WATERMARK_HIGH_MASK 0x0000ffff +#define AR9888_CURRENT_SRRI_ADDRESS 0x0044 +#define AR9888_CURRENT_DRRI_ADDRESS 0x0048 +#define AR9888_HOST_IS_SRC_RING_HIGH_WATERMARK_MASK 0x00000002 +#define AR9888_HOST_IS_SRC_RING_LOW_WATERMARK_MASK 0x00000004 +#define AR9888_HOST_IS_DST_RING_HIGH_WATERMARK_MASK 0x00000008 +#define AR9888_HOST_IS_DST_RING_LOW_WATERMARK_MASK 0x00000010 +#define AR9888_HOST_IS_ADDRESS 0x0030 +#define AR9888_HOST_IS_COPY_COMPLETE_MASK 0x00000001 +#define AR9888_HOST_IE_ADDRESS 0x002c +#define AR9888_HOST_IE_COPY_COMPLETE_MASK 0x00000001 +#define AR9888_SR_BA_ADDRESS 0x0000 +#define AR9888_SR_SIZE_ADDRESS 0x0004 +#define AR9888_DR_BA_ADDRESS 0x0008 +#define AR9888_DR_SIZE_ADDRESS 0x000c +#define AR9888_MISC_IE_ADDRESS 0x0034 +#define AR9888_MISC_IS_AXI_ERR_MASK 0x00000400 +#define AR9888_MISC_IS_DST_ADDR_ERR_MASK 0x00000200 +#define AR9888_MISC_IS_SRC_LEN_ERR_MASK 0x00000100 +#define AR9888_MISC_IS_DST_MAX_LEN_VIO_MASK 0x00000080 +#define AR9888_MISC_IS_DST_RING_OVERFLOW_MASK 0x00000040 +#define AR9888_MISC_IS_SRC_RING_OVERFLOW_MASK 0x00000020 +#define AR9888_SRC_WATERMARK_LOW_LSB 16 +#define AR9888_SRC_WATERMARK_HIGH_LSB 0 +#define AR9888_DST_WATERMARK_LOW_LSB 16 +#define AR9888_DST_WATERMARK_HIGH_LSB 0 +#define AR9888_SOC_GLOBAL_RESET_ADDRESS 0x0008 +#define AR9888_RTC_STATE_ADDRESS 0x0000 +#define AR9888_RTC_STATE_COLD_RESET_MASK 0x00000400 + +#define AR9888_RTC_STATE_V_MASK 0x00000007 +#define AR9888_RTC_STATE_V_LSB 0 +#define AR9888_RTC_STATE_V_ON 3 +#define AR9888_FW_IND_EVENT_PENDING 1 +#define AR9888_FW_IND_INITIALIZED 2 +#define AR9888_CPU_INTR_ADDRESS 0x0010 +#define AR9888_SOC_LF_TIMER_CONTROL0_ADDRESS 0x00000050 +#define AR9888_SOC_LF_TIMER_CONTROL0_ENABLE_MASK 0x00000004 +#define AR9888_SOC_RESET_CONTROL_ADDRESS 0x00000000 +#define AR9888_SOC_RESET_CONTROL_CPU_WARM_RST_MASK 0x00000040 +#define AR9888_CORE_CTRL_ADDRESS 0x0000 +#define AR9888_CORE_CTRL_CPU_INTR_MASK 0x00002000 +#define AR9888_LOCAL_SCRATCH_OFFSET 0x18 +#define AR9888_CLOCK_GPIO_OFFSET 0xffffffff +#define AR9888_CLOCK_GPIO_BT_CLK_OUT_EN_LSB 0 +#define AR9888_CLOCK_GPIO_BT_CLK_OUT_EN_MASK 0 + +#define AR9888_FW_EVENT_PENDING_ADDRESS \ + (AR9888_SOC_CORE_BASE_ADDRESS + AR9888_SCRATCH_3_ADDRESS) +#define AR9888_DRAM_BASE_ADDRESS AR9888_TARG_DRAM_START +#define AR9888_FW_INDICATOR_ADDRESS \ + (AR9888_SOC_CORE_BASE_ADDRESS + AR9888_SCRATCH_3_ADDRESS) +#define AR9888_SYSTEM_SLEEP_OFFSET AR9888_SOC_SYSTEM_SLEEP_OFFSET +#define AR9888_WLAN_SYSTEM_SLEEP_OFFSET AR9888_SOC_SYSTEM_SLEEP_OFFSET +#define AR9888_WLAN_RESET_CONTROL_OFFSET AR9888_SOC_RESET_CONTROL_OFFSET +#define AR9888_CLOCK_CONTROL_OFFSET AR9888_SOC_CLOCK_CONTROL_OFFSET +#define AR9888_CLOCK_CONTROL_SI0_CLK_MASK AR9888_SOC_CLOCK_CONTROL_SI0_CLK_MASK +#define AR9888_RESET_CONTROL_MBOX_RST_MASK MISSING +#define AR9888_RESET_CONTROL_SI0_RST_MASK AR9888_SOC_RESET_CONTROL_SI0_RST_MASK +#define AR9888_GPIO_BASE_ADDRESS AR9888_WLAN_GPIO_BASE_ADDRESS +#define AR9888_GPIO_PIN0_OFFSET AR9888_WLAN_GPIO_PIN0_ADDRESS +#define AR9888_GPIO_PIN1_OFFSET AR9888_WLAN_GPIO_PIN1_ADDRESS +#define AR9888_GPIO_PIN0_CONFIG_MASK AR9888_WLAN_GPIO_PIN0_CONFIG_MASK +#define AR9888_GPIO_PIN1_CONFIG_MASK AR9888_WLAN_GPIO_PIN1_CONFIG_MASK +#define AR9888_SI_BASE_ADDRESS AR9888_WLAN_SI_BASE_ADDRESS +#define AR9888_SCRATCH_BASE_ADDRESS AR9888_SOC_CORE_BASE_ADDRESS +#define AR9888_CPU_CLOCK_OFFSET AR9888_SOC_CPU_CLOCK_OFFSET +#define AR9888_LPO_CAL_OFFSET AR9888_SOC_LPO_CAL_OFFSET +#define AR9888_GPIO_PIN10_OFFSET AR9888_WLAN_GPIO_PIN10_ADDRESS +#define AR9888_GPIO_PIN11_OFFSET AR9888_WLAN_GPIO_PIN11_ADDRESS +#define AR9888_GPIO_PIN12_OFFSET AR9888_WLAN_GPIO_PIN12_ADDRESS +#define AR9888_GPIO_PIN13_OFFSET AR9888_WLAN_GPIO_PIN13_ADDRESS +#define AR9888_CPU_CLOCK_STANDARD_LSB AR9888_SOC_CPU_CLOCK_STANDARD_LSB +#define AR9888_CPU_CLOCK_STANDARD_MASK AR9888_SOC_CPU_CLOCK_STANDARD_MASK +#define AR9888_LPO_CAL_ENABLE_LSB AR9888_SOC_LPO_CAL_ENABLE_LSB +#define AR9888_LPO_CAL_ENABLE_MASK AR9888_SOC_LPO_CAL_ENABLE_MASK +#define AR9888_ANALOG_INTF_BASE_ADDRESS AR9888_WLAN_ANALOG_INTF_BASE_ADDRESS +#define AR9888_MBOX_BASE_ADDRESS MISSING +#define AR9888_INT_STATUS_ENABLE_ERROR_LSB MISSING +#define AR9888_INT_STATUS_ENABLE_ERROR_MASK MISSING +#define AR9888_INT_STATUS_ENABLE_CPU_LSB MISSING +#define AR9888_INT_STATUS_ENABLE_CPU_MASK MISSING +#define AR9888_INT_STATUS_ENABLE_COUNTER_LSB MISSING +#define AR9888_INT_STATUS_ENABLE_COUNTER_MASK MISSING +#define AR9888_INT_STATUS_ENABLE_MBOX_DATA_LSB MISSING +#define AR9888_INT_STATUS_ENABLE_MBOX_DATA_MASK MISSING +#define AR9888_ERROR_STATUS_ENABLE_RX_UNDERFLOW_LSB MISSING +#define AR9888_ERROR_STATUS_ENABLE_RX_UNDERFLOW_MASK MISSING +#define AR9888_ERROR_STATUS_ENABLE_TX_OVERFLOW_LSB MISSING +#define AR9888_ERROR_STATUS_ENABLE_TX_OVERFLOW_MASK MISSING +#define AR9888_COUNTER_INT_STATUS_ENABLE_BIT_LSB MISSING +#define AR9888_COUNTER_INT_STATUS_ENABLE_BIT_MASK MISSING +#define AR9888_INT_STATUS_ENABLE_ADDRESS MISSING +#define AR9888_CPU_INT_STATUS_ENABLE_BIT_LSB MISSING +#define AR9888_CPU_INT_STATUS_ENABLE_BIT_MASK MISSING +#define AR9888_HOST_INT_STATUS_ADDRESS MISSING +#define AR9888_CPU_INT_STATUS_ADDRESS MISSING +#define AR9888_ERROR_INT_STATUS_ADDRESS MISSING +#define AR9888_ERROR_INT_STATUS_WAKEUP_MASK MISSING +#define AR9888_ERROR_INT_STATUS_WAKEUP_LSB MISSING +#define AR9888_ERROR_INT_STATUS_RX_UNDERFLOW_MASK MISSING +#define AR9888_ERROR_INT_STATUS_RX_UNDERFLOW_LSB MISSING +#define AR9888_ERROR_INT_STATUS_TX_OVERFLOW_MASK MISSING +#define AR9888_ERROR_INT_STATUS_TX_OVERFLOW_LSB MISSING +#define AR9888_COUNT_DEC_ADDRESS MISSING +#define AR9888_HOST_INT_STATUS_CPU_MASK MISSING +#define AR9888_HOST_INT_STATUS_CPU_LSB MISSING +#define AR9888_HOST_INT_STATUS_ERROR_MASK MISSING +#define AR9888_HOST_INT_STATUS_ERROR_LSB MISSING +#define AR9888_HOST_INT_STATUS_COUNTER_MASK MISSING +#define AR9888_HOST_INT_STATUS_COUNTER_LSB MISSING +#define AR9888_RX_LOOKAHEAD_VALID_ADDRESS MISSING +#define AR9888_WINDOW_DATA_ADDRESS MISSING +#define AR9888_WINDOW_READ_ADDR_ADDRESS MISSING +#define AR9888_WINDOW_WRITE_ADDR_ADDRESS MISSING +#define AR9888_HOST_INT_STATUS_MBOX_DATA_MASK 0x0f +#define AR9888_HOST_INT_STATUS_MBOX_DATA_LSB 0 + +struct targetdef_s ar9888_targetdef = { + .d_RTC_SOC_BASE_ADDRESS = AR9888_RTC_SOC_BASE_ADDRESS, + .d_RTC_WMAC_BASE_ADDRESS = AR9888_RTC_WMAC_BASE_ADDRESS, + .d_SYSTEM_SLEEP_OFFSET = AR9888_WLAN_SYSTEM_SLEEP_OFFSET, + .d_WLAN_SYSTEM_SLEEP_OFFSET = AR9888_WLAN_SYSTEM_SLEEP_OFFSET, + .d_WLAN_SYSTEM_SLEEP_DISABLE_LSB = + AR9888_WLAN_SYSTEM_SLEEP_DISABLE_LSB, + .d_WLAN_SYSTEM_SLEEP_DISABLE_MASK = + AR9888_WLAN_SYSTEM_SLEEP_DISABLE_MASK, + .d_CLOCK_CONTROL_OFFSET = AR9888_CLOCK_CONTROL_OFFSET, + .d_CLOCK_CONTROL_SI0_CLK_MASK = AR9888_CLOCK_CONTROL_SI0_CLK_MASK, + .d_RESET_CONTROL_OFFSET = AR9888_SOC_RESET_CONTROL_OFFSET, + .d_RESET_CONTROL_MBOX_RST_MASK = AR9888_RESET_CONTROL_MBOX_RST_MASK, + .d_RESET_CONTROL_SI0_RST_MASK = AR9888_RESET_CONTROL_SI0_RST_MASK, + .d_WLAN_RESET_CONTROL_OFFSET = AR9888_WLAN_RESET_CONTROL_OFFSET, + .d_WLAN_RESET_CONTROL_COLD_RST_MASK = + AR9888_WLAN_RESET_CONTROL_COLD_RST_MASK, + .d_WLAN_RESET_CONTROL_WARM_RST_MASK = + AR9888_WLAN_RESET_CONTROL_WARM_RST_MASK, + .d_GPIO_BASE_ADDRESS = AR9888_GPIO_BASE_ADDRESS, + .d_GPIO_PIN0_OFFSET = AR9888_GPIO_PIN0_OFFSET, + .d_GPIO_PIN1_OFFSET = AR9888_GPIO_PIN1_OFFSET, + .d_GPIO_PIN0_CONFIG_MASK = AR9888_GPIO_PIN0_CONFIG_MASK, + .d_GPIO_PIN1_CONFIG_MASK = AR9888_GPIO_PIN1_CONFIG_MASK, + .d_SI_CONFIG_BIDIR_OD_DATA_LSB = AR9888_SI_CONFIG_BIDIR_OD_DATA_LSB, + .d_SI_CONFIG_BIDIR_OD_DATA_MASK = AR9888_SI_CONFIG_BIDIR_OD_DATA_MASK, + .d_SI_CONFIG_I2C_LSB = AR9888_SI_CONFIG_I2C_LSB, + .d_SI_CONFIG_I2C_MASK = AR9888_SI_CONFIG_I2C_MASK, + .d_SI_CONFIG_POS_SAMPLE_LSB = AR9888_SI_CONFIG_POS_SAMPLE_LSB, + .d_SI_CONFIG_POS_SAMPLE_MASK = AR9888_SI_CONFIG_POS_SAMPLE_MASK, + .d_SI_CONFIG_INACTIVE_CLK_LSB = AR9888_SI_CONFIG_INACTIVE_CLK_LSB, + .d_SI_CONFIG_INACTIVE_CLK_MASK = AR9888_SI_CONFIG_INACTIVE_CLK_MASK, + .d_SI_CONFIG_INACTIVE_DATA_LSB = AR9888_SI_CONFIG_INACTIVE_DATA_LSB, + .d_SI_CONFIG_INACTIVE_DATA_MASK = AR9888_SI_CONFIG_INACTIVE_DATA_MASK, + .d_SI_CONFIG_DIVIDER_LSB = AR9888_SI_CONFIG_DIVIDER_LSB, + .d_SI_CONFIG_DIVIDER_MASK = AR9888_SI_CONFIG_DIVIDER_MASK, + .d_SI_BASE_ADDRESS = AR9888_SI_BASE_ADDRESS, + .d_SI_CONFIG_OFFSET = AR9888_SI_CONFIG_OFFSET, + .d_SI_TX_DATA0_OFFSET = AR9888_SI_TX_DATA0_OFFSET, + .d_SI_TX_DATA1_OFFSET = AR9888_SI_TX_DATA1_OFFSET, + .d_SI_RX_DATA0_OFFSET = AR9888_SI_RX_DATA0_OFFSET, + .d_SI_RX_DATA1_OFFSET = AR9888_SI_RX_DATA1_OFFSET, + .d_SI_CS_OFFSET = AR9888_SI_CS_OFFSET, + .d_SI_CS_DONE_ERR_MASK = AR9888_SI_CS_DONE_ERR_MASK, + .d_SI_CS_DONE_INT_MASK = AR9888_SI_CS_DONE_INT_MASK, + .d_SI_CS_START_LSB = AR9888_SI_CS_START_LSB, + .d_SI_CS_START_MASK = AR9888_SI_CS_START_MASK, + .d_SI_CS_RX_CNT_LSB = AR9888_SI_CS_RX_CNT_LSB, + .d_SI_CS_RX_CNT_MASK = AR9888_SI_CS_RX_CNT_MASK, + .d_SI_CS_TX_CNT_LSB = AR9888_SI_CS_TX_CNT_LSB, + .d_SI_CS_TX_CNT_MASK = AR9888_SI_CS_TX_CNT_MASK, + .d_BOARD_DATA_SZ = AR9888_BOARD_DATA_SZ, + .d_BOARD_EXT_DATA_SZ = AR9888_BOARD_EXT_DATA_SZ, + .d_MBOX_BASE_ADDRESS = AR9888_MBOX_BASE_ADDRESS, + .d_LOCAL_SCRATCH_OFFSET = AR9888_LOCAL_SCRATCH_OFFSET, + .d_CPU_CLOCK_OFFSET = AR9888_CPU_CLOCK_OFFSET, + .d_LPO_CAL_OFFSET = AR9888_LPO_CAL_OFFSET, + .d_GPIO_PIN10_OFFSET = AR9888_GPIO_PIN10_OFFSET, + .d_GPIO_PIN11_OFFSET = AR9888_GPIO_PIN11_OFFSET, + .d_GPIO_PIN12_OFFSET = AR9888_GPIO_PIN12_OFFSET, + .d_GPIO_PIN13_OFFSET = AR9888_GPIO_PIN13_OFFSET, + .d_CLOCK_GPIO_OFFSET = AR9888_CLOCK_GPIO_OFFSET, + .d_CPU_CLOCK_STANDARD_LSB = AR9888_CPU_CLOCK_STANDARD_LSB, + .d_CPU_CLOCK_STANDARD_MASK = AR9888_CPU_CLOCK_STANDARD_MASK, + .d_LPO_CAL_ENABLE_LSB = AR9888_LPO_CAL_ENABLE_LSB, + .d_LPO_CAL_ENABLE_MASK = AR9888_LPO_CAL_ENABLE_MASK, + .d_CLOCK_GPIO_BT_CLK_OUT_EN_LSB = AR9888_CLOCK_GPIO_BT_CLK_OUT_EN_LSB, + .d_CLOCK_GPIO_BT_CLK_OUT_EN_MASK = + AR9888_CLOCK_GPIO_BT_CLK_OUT_EN_MASK, + .d_ANALOG_INTF_BASE_ADDRESS = AR9888_ANALOG_INTF_BASE_ADDRESS, + .d_WLAN_MAC_BASE_ADDRESS = AR9888_WLAN_MAC_BASE_ADDRESS, + .d_FW_INDICATOR_ADDRESS = AR9888_FW_INDICATOR_ADDRESS, + .d_DRAM_BASE_ADDRESS = AR9888_DRAM_BASE_ADDRESS, + .d_SOC_CORE_BASE_ADDRESS = AR9888_SOC_CORE_BASE_ADDRESS, + .d_CORE_CTRL_ADDRESS = AR9888_CORE_CTRL_ADDRESS, +#if defined(HIF_PCI) || defined(HIF_SNOC) || defined(HIF_AHB) + .d_MSI_NUM_REQUEST = MSI_NUM_REQUEST, + .d_MSI_ASSIGN_FW = MSI_ASSIGN_FW, +#endif + .d_CORE_CTRL_CPU_INTR_MASK = AR9888_CORE_CTRL_CPU_INTR_MASK, + .d_SR_WR_INDEX_ADDRESS = AR9888_SR_WR_INDEX_ADDRESS, + .d_DST_WATERMARK_ADDRESS = AR9888_DST_WATERMARK_ADDRESS, + /* htt_rx.c */ + .d_RX_MSDU_END_4_FIRST_MSDU_MASK = + AR9888_RX_MSDU_END_4_FIRST_MSDU_MASK, + .d_RX_MSDU_END_4_FIRST_MSDU_LSB = AR9888_RX_MSDU_END_4_FIRST_MSDU_LSB, + .d_RX_MPDU_START_0_SEQ_NUM_MASK = AR9888_RX_MPDU_START_0_SEQ_NUM_MASK, + .d_RX_MPDU_START_0_SEQ_NUM_LSB = AR9888_RX_MPDU_START_0_SEQ_NUM_LSB, + .d_RX_MPDU_START_2_PN_47_32_LSB = AR9888_RX_MPDU_START_2_PN_47_32_LSB, + .d_RX_MPDU_START_2_PN_47_32_MASK = + AR9888_RX_MPDU_START_2_PN_47_32_MASK, + .d_RX_MSDU_END_1_EXT_WAPI_PN_63_48_MASK = + AR9888_RX_MSDU_END_1_EXT_WAPI_PN_63_48_MASK, + .d_RX_MSDU_END_1_EXT_WAPI_PN_63_48_LSB = + AR9888_RX_MSDU_END_1_EXT_WAPI_PN_63_48_LSB, + .d_RX_MSDU_END_1_KEY_ID_OCT_MASK = + AR9888_RX_MSDU_END_1_KEY_ID_OCT_MASK, + .d_RX_MSDU_END_1_KEY_ID_OCT_LSB = AR9888_RX_MSDU_END_1_KEY_ID_OCT_LSB, + .d_RX_MSDU_END_4_LAST_MSDU_MASK = AR9888_RX_MSDU_END_4_LAST_MSDU_MASK, + .d_RX_MSDU_END_4_LAST_MSDU_LSB = AR9888_RX_MSDU_END_4_LAST_MSDU_LSB, + .d_RX_ATTENTION_0_MCAST_BCAST_MASK = + AR9888_RX_ATTENTION_0_MCAST_BCAST_MASK, + .d_RX_ATTENTION_0_MCAST_BCAST_LSB = + AR9888_RX_ATTENTION_0_MCAST_BCAST_LSB, + .d_RX_ATTENTION_0_FRAGMENT_MASK = AR9888_RX_ATTENTION_0_FRAGMENT_MASK, + .d_RX_ATTENTION_0_FRAGMENT_LSB = AR9888_RX_ATTENTION_0_FRAGMENT_LSB, + .d_RX_ATTENTION_0_MPDU_LENGTH_ERR_MASK = + AR9888_RX_ATTENTION_0_MPDU_LENGTH_ERR_MASK, + .d_RX_FRAG_INFO_0_RING2_MORE_COUNT_MASK = + AR9888_RX_FRAG_INFO_0_RING2_MORE_COUNT_MASK, + .d_RX_FRAG_INFO_0_RING2_MORE_COUNT_LSB = + AR9888_RX_FRAG_INFO_0_RING2_MORE_COUNT_LSB, + .d_RX_MSDU_START_0_MSDU_LENGTH_MASK = + AR9888_RX_MSDU_START_0_MSDU_LENGTH_MASK, + .d_RX_MSDU_START_0_MSDU_LENGTH_LSB = + AR9888_RX_MSDU_START_0_MSDU_LENGTH_LSB, + .d_RX_MSDU_START_2_DECAP_FORMAT_OFFSET = + AR9888_RX_MSDU_START_2_DECAP_FORMAT_OFFSET, + .d_RX_MSDU_START_2_DECAP_FORMAT_MASK = + AR9888_RX_MSDU_START_2_DECAP_FORMAT_MASK, + .d_RX_MSDU_START_2_DECAP_FORMAT_LSB = + AR9888_RX_MSDU_START_2_DECAP_FORMAT_LSB, + .d_RX_MPDU_START_0_ENCRYPTED_MASK = + AR9888_RX_MPDU_START_0_ENCRYPTED_MASK, + .d_RX_MPDU_START_0_ENCRYPTED_LSB = + AR9888_RX_MPDU_START_0_ENCRYPTED_LSB, + .d_RX_ATTENTION_0_MORE_DATA_MASK = + AR9888_RX_ATTENTION_0_MORE_DATA_MASK, + .d_RX_ATTENTION_0_MSDU_DONE_MASK = + AR9888_RX_ATTENTION_0_MSDU_DONE_MASK, + .d_RX_ATTENTION_0_TCP_UDP_CHKSUM_FAIL_MASK = + AR9888_RX_ATTENTION_0_TCP_UDP_CHKSUM_FAIL_MASK, +#if defined(HIF_PCI) || defined(HIF_SNOC) || defined(HIF_AHB) + .d_CE_COUNT = AR9888_CE_COUNT, + .d_MSI_ASSIGN_CE_INITIAL = MSI_ASSIGN_CE_INITIAL, + .d_PCIE_INTR_ENABLE_ADDRESS = AR9888_PCIE_INTR_ENABLE_ADDRESS, + .d_PCIE_INTR_CLR_ADDRESS = AR9888_PCIE_INTR_CLR_ADDRESS, + .d_PCIE_INTR_FIRMWARE_MASK = AR9888_PCIE_INTR_FIRMWARE_MASK, + .d_PCIE_INTR_CE_MASK_ALL = AR9888_PCIE_INTR_CE_MASK_ALL, + .d_PCIE_INTR_CAUSE_ADDRESS = AR9888_PCIE_INTR_CAUSE_ADDRESS, + .d_SOC_RESET_CONTROL_ADDRESS = AR9888_SOC_RESET_CONTROL_ADDRESS, + .d_SOC_RESET_CONTROL_PCIE_RST_SHORT_OVRD_MASK = + AR9888_SOC_RESET_CONTROL_PCIE_RST_SHORT_OVRD_MASK, + .d_SOC_RESET_CONTROL_PCIE_RST_SHORT_OVRD_LSB = + AR9888_SOC_RESET_CONTROL_PCIE_RST_SHORT_OVRD_LSB, + .d_SOC_RESET_CONTROL_CE_RST_MASK = + AR9888_SOC_RESET_CONTROL_CE_RST_MASK, +#endif + .d_SOC_RESET_CONTROL_CPU_WARM_RST_MASK = + AR9888_SOC_RESET_CONTROL_CPU_WARM_RST_MASK, + .d_CPU_INTR_ADDRESS = AR9888_CPU_INTR_ADDRESS, + .d_SOC_LF_TIMER_CONTROL0_ADDRESS = + AR9888_SOC_LF_TIMER_CONTROL0_ADDRESS, + .d_SOC_LF_TIMER_CONTROL0_ENABLE_MASK = + AR9888_SOC_LF_TIMER_CONTROL0_ENABLE_MASK, +}; + +struct hostdef_s ar9888_hostdef = { + .d_INT_STATUS_ENABLE_ERROR_LSB = AR9888_INT_STATUS_ENABLE_ERROR_LSB, + .d_INT_STATUS_ENABLE_ERROR_MASK = AR9888_INT_STATUS_ENABLE_ERROR_MASK, + .d_INT_STATUS_ENABLE_CPU_LSB = AR9888_INT_STATUS_ENABLE_CPU_LSB, + .d_INT_STATUS_ENABLE_CPU_MASK = AR9888_INT_STATUS_ENABLE_CPU_MASK, + .d_INT_STATUS_ENABLE_COUNTER_LSB = + AR9888_INT_STATUS_ENABLE_COUNTER_LSB, + .d_INT_STATUS_ENABLE_COUNTER_MASK = + AR9888_INT_STATUS_ENABLE_COUNTER_MASK, + .d_INT_STATUS_ENABLE_MBOX_DATA_LSB = + AR9888_INT_STATUS_ENABLE_MBOX_DATA_LSB, + .d_INT_STATUS_ENABLE_MBOX_DATA_MASK = + AR9888_INT_STATUS_ENABLE_MBOX_DATA_MASK, + .d_ERROR_STATUS_ENABLE_RX_UNDERFLOW_LSB = + AR9888_ERROR_STATUS_ENABLE_RX_UNDERFLOW_LSB, + .d_ERROR_STATUS_ENABLE_RX_UNDERFLOW_MASK = + AR9888_ERROR_STATUS_ENABLE_RX_UNDERFLOW_MASK, + .d_ERROR_STATUS_ENABLE_TX_OVERFLOW_LSB = + AR9888_ERROR_STATUS_ENABLE_TX_OVERFLOW_LSB, + .d_ERROR_STATUS_ENABLE_TX_OVERFLOW_MASK = + AR9888_ERROR_STATUS_ENABLE_TX_OVERFLOW_MASK, + .d_COUNTER_INT_STATUS_ENABLE_BIT_LSB = + AR9888_COUNTER_INT_STATUS_ENABLE_BIT_LSB, + .d_COUNTER_INT_STATUS_ENABLE_BIT_MASK = + AR9888_COUNTER_INT_STATUS_ENABLE_BIT_MASK, + .d_INT_STATUS_ENABLE_ADDRESS = AR9888_INT_STATUS_ENABLE_ADDRESS, + .d_CPU_INT_STATUS_ENABLE_BIT_LSB = + AR9888_CPU_INT_STATUS_ENABLE_BIT_LSB, + .d_CPU_INT_STATUS_ENABLE_BIT_MASK = + AR9888_CPU_INT_STATUS_ENABLE_BIT_MASK, + .d_HOST_INT_STATUS_ADDRESS = AR9888_HOST_INT_STATUS_ADDRESS, + .d_CPU_INT_STATUS_ADDRESS = AR9888_CPU_INT_STATUS_ADDRESS, + .d_ERROR_INT_STATUS_ADDRESS = AR9888_ERROR_INT_STATUS_ADDRESS, + .d_ERROR_INT_STATUS_WAKEUP_MASK = AR9888_ERROR_INT_STATUS_WAKEUP_MASK, + .d_ERROR_INT_STATUS_WAKEUP_LSB = AR9888_ERROR_INT_STATUS_WAKEUP_LSB, + .d_ERROR_INT_STATUS_RX_UNDERFLOW_MASK = + AR9888_ERROR_INT_STATUS_RX_UNDERFLOW_MASK, + .d_ERROR_INT_STATUS_RX_UNDERFLOW_LSB = + AR9888_ERROR_INT_STATUS_RX_UNDERFLOW_LSB, + .d_ERROR_INT_STATUS_TX_OVERFLOW_MASK = + AR9888_ERROR_INT_STATUS_TX_OVERFLOW_MASK, + .d_ERROR_INT_STATUS_TX_OVERFLOW_LSB = + AR9888_ERROR_INT_STATUS_TX_OVERFLOW_LSB, + .d_COUNT_DEC_ADDRESS = AR9888_COUNT_DEC_ADDRESS, + .d_HOST_INT_STATUS_CPU_MASK = AR9888_HOST_INT_STATUS_CPU_MASK, + .d_HOST_INT_STATUS_CPU_LSB = AR9888_HOST_INT_STATUS_CPU_LSB, + .d_HOST_INT_STATUS_ERROR_MASK = AR9888_HOST_INT_STATUS_ERROR_MASK, + .d_HOST_INT_STATUS_ERROR_LSB = AR9888_HOST_INT_STATUS_ERROR_LSB, + .d_HOST_INT_STATUS_COUNTER_MASK = AR9888_HOST_INT_STATUS_COUNTER_MASK, + .d_HOST_INT_STATUS_COUNTER_LSB = AR9888_HOST_INT_STATUS_COUNTER_LSB, + .d_RX_LOOKAHEAD_VALID_ADDRESS = AR9888_RX_LOOKAHEAD_VALID_ADDRESS, + .d_WINDOW_DATA_ADDRESS = AR9888_WINDOW_DATA_ADDRESS, + .d_WINDOW_READ_ADDR_ADDRESS = AR9888_WINDOW_READ_ADDR_ADDRESS, + .d_WINDOW_WRITE_ADDR_ADDRESS = AR9888_WINDOW_WRITE_ADDR_ADDRESS, + .d_SOC_GLOBAL_RESET_ADDRESS = AR9888_SOC_GLOBAL_RESET_ADDRESS, + .d_RTC_STATE_ADDRESS = AR9888_RTC_STATE_ADDRESS, + .d_RTC_STATE_COLD_RESET_MASK = AR9888_RTC_STATE_COLD_RESET_MASK, + .d_RTC_STATE_V_MASK = AR9888_RTC_STATE_V_MASK, + .d_RTC_STATE_V_LSB = AR9888_RTC_STATE_V_LSB, + .d_FW_IND_EVENT_PENDING = AR9888_FW_IND_EVENT_PENDING, + .d_FW_IND_INITIALIZED = AR9888_FW_IND_INITIALIZED, + .d_RTC_STATE_V_ON = AR9888_RTC_STATE_V_ON, +#if defined(SDIO_3_0) + .d_HOST_INT_STATUS_MBOX_DATA_MASK = + AR9888_HOST_INT_STATUS_MBOX_DATA_MASK, + .d_HOST_INT_STATUS_MBOX_DATA_LSB = + AR9888_HOST_INT_STATUS_MBOX_DATA_LSB, +#endif +#if defined(HIF_PCI) || defined(HIF_SNOC) || defined(HIF_AHB) + .d_MUX_ID_MASK = AR9888_MUX_ID_MASK, + .d_TRANSACTION_ID_MASK = AR9888_TRANSACTION_ID_MASK, + .d_PCIE_LOCAL_BASE_ADDRESS = AR9888_PCIE_LOCAL_BASE_ADDRESS, + .d_PCIE_SOC_WAKE_RESET = AR9888_PCIE_SOC_WAKE_RESET, + .d_PCIE_SOC_WAKE_ADDRESS = AR9888_PCIE_SOC_WAKE_ADDRESS, + .d_PCIE_SOC_WAKE_V_MASK = AR9888_PCIE_SOC_WAKE_V_MASK, + .d_PCIE_SOC_RDY_STATUS_ADDRESS = PCIE_SOC_RDY_STATUS_ADDRESS, + .d_PCIE_SOC_RDY_STATUS_BAR_MASK = PCIE_SOC_RDY_STATUS_BAR_MASK, + .d_SOC_PCIE_BASE_ADDRESS = SOC_PCIE_BASE_ADDRESS, + .d_MSI_MAGIC_ADR_ADDRESS = MSI_MAGIC_ADR_ADDRESS, + .d_MSI_MAGIC_ADDRESS = MSI_MAGIC_ADDRESS, + .d_HOST_CE_COUNT = 8, + .d_ENABLE_MSI = 0, +#endif +}; + +#if defined(HIF_PCI) || defined(HIF_SNOC) || defined(HIF_AHB) +struct ce_reg_def ar9888_ce_targetdef = { + /* copy_engine.c */ + .d_DST_WR_INDEX_ADDRESS = AR9888_DST_WR_INDEX_ADDRESS, + .d_SRC_WATERMARK_ADDRESS = AR9888_SRC_WATERMARK_ADDRESS, + .d_SRC_WATERMARK_LOW_MASK = AR9888_SRC_WATERMARK_LOW_MASK, + .d_SRC_WATERMARK_HIGH_MASK = AR9888_SRC_WATERMARK_HIGH_MASK, + .d_DST_WATERMARK_LOW_MASK = AR9888_DST_WATERMARK_LOW_MASK, + .d_DST_WATERMARK_HIGH_MASK = AR9888_DST_WATERMARK_HIGH_MASK, + .d_CURRENT_SRRI_ADDRESS = AR9888_CURRENT_SRRI_ADDRESS, + .d_CURRENT_DRRI_ADDRESS = AR9888_CURRENT_DRRI_ADDRESS, + .d_HOST_IS_SRC_RING_HIGH_WATERMARK_MASK = + AR9888_HOST_IS_SRC_RING_HIGH_WATERMARK_MASK, + .d_HOST_IS_SRC_RING_LOW_WATERMARK_MASK = + AR9888_HOST_IS_SRC_RING_LOW_WATERMARK_MASK, + .d_HOST_IS_DST_RING_HIGH_WATERMARK_MASK = + AR9888_HOST_IS_DST_RING_HIGH_WATERMARK_MASK, + .d_HOST_IS_DST_RING_LOW_WATERMARK_MASK = + AR9888_HOST_IS_DST_RING_LOW_WATERMARK_MASK, + .d_HOST_IS_ADDRESS = AR9888_HOST_IS_ADDRESS, + .d_HOST_IS_COPY_COMPLETE_MASK = AR9888_HOST_IS_COPY_COMPLETE_MASK, + .d_CE_WRAPPER_BASE_ADDRESS = AR9888_CE_WRAPPER_BASE_ADDRESS, + .d_CE_WRAPPER_INTERRUPT_SUMMARY_ADDRESS = + AR9888_CE_WRAPPER_INTERRUPT_SUMMARY_ADDRESS, + .d_HOST_IE_ADDRESS = AR9888_HOST_IE_ADDRESS, + .d_HOST_IE_COPY_COMPLETE_MASK = AR9888_HOST_IE_COPY_COMPLETE_MASK, + .d_SR_BA_ADDRESS = AR9888_SR_BA_ADDRESS, + .d_SR_SIZE_ADDRESS = AR9888_SR_SIZE_ADDRESS, + .d_CE_CTRL1_ADDRESS = AR9888_CE_CTRL1_ADDRESS, + .d_CE_CTRL1_DMAX_LENGTH_MASK = AR9888_CE_CTRL1_DMAX_LENGTH_MASK, + .d_DR_BA_ADDRESS = AR9888_DR_BA_ADDRESS, + .d_DR_SIZE_ADDRESS = AR9888_DR_SIZE_ADDRESS, + .d_MISC_IE_ADDRESS = AR9888_MISC_IE_ADDRESS, + .d_MISC_IS_AXI_ERR_MASK = AR9888_MISC_IS_AXI_ERR_MASK, + .d_MISC_IS_DST_ADDR_ERR_MASK = AR9888_MISC_IS_DST_ADDR_ERR_MASK, + .d_MISC_IS_SRC_LEN_ERR_MASK = AR9888_MISC_IS_SRC_LEN_ERR_MASK, + .d_MISC_IS_DST_MAX_LEN_VIO_MASK = AR9888_MISC_IS_DST_MAX_LEN_VIO_MASK, + .d_MISC_IS_DST_RING_OVERFLOW_MASK = + AR9888_MISC_IS_DST_RING_OVERFLOW_MASK, + .d_MISC_IS_SRC_RING_OVERFLOW_MASK = + AR9888_MISC_IS_SRC_RING_OVERFLOW_MASK, + .d_SRC_WATERMARK_LOW_LSB = AR9888_SRC_WATERMARK_LOW_LSB, + .d_SRC_WATERMARK_HIGH_LSB = AR9888_SRC_WATERMARK_HIGH_LSB, + .d_DST_WATERMARK_LOW_LSB = AR9888_DST_WATERMARK_LOW_LSB, + .d_DST_WATERMARK_HIGH_LSB = AR9888_DST_WATERMARK_HIGH_LSB, + .d_CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_MASK = + AR9888_CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_MASK, + .d_CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_LSB = + AR9888_CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_LSB, + .d_CE_CTRL1_DMAX_LENGTH_LSB = AR9888_CE_CTRL1_DMAX_LENGTH_LSB, + .d_CE_CTRL1_SRC_RING_BYTE_SWAP_EN_MASK = + AR9888_CE_CTRL1_SRC_RING_BYTE_SWAP_EN_MASK, + .d_CE_CTRL1_DST_RING_BYTE_SWAP_EN_MASK = + AR9888_CE_CTRL1_DST_RING_BYTE_SWAP_EN_MASK, + .d_CE_CTRL1_SRC_RING_BYTE_SWAP_EN_LSB = + AR9888_CE_CTRL1_SRC_RING_BYTE_SWAP_EN_LSB, + .d_CE_CTRL1_DST_RING_BYTE_SWAP_EN_LSB = + AR9888_CE_CTRL1_DST_RING_BYTE_SWAP_EN_LSB, + .d_CE0_BASE_ADDRESS = AR9888_CE0_BASE_ADDRESS, + .d_CE1_BASE_ADDRESS = AR9888_CE1_BASE_ADDRESS, + +}; +#endif +#endif diff --git a/drivers/staging/qca-wifi-host-cmn/hif/src/ath_procfs.c b/drivers/staging/qca-wifi-host-cmn/hif/src/ath_procfs.c new file mode 100644 index 0000000000000000000000000000000000000000..f1cb6f06fd313e62fb34b05eb12ed586259ca10a --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/hif/src/ath_procfs.c @@ -0,0 +1,232 @@ +/* + * Copyright (c) 2013-2014, 2016-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#if defined(CONFIG_ATH_PROCFS_DIAG_SUPPORT) +#include /* Specifically, a module */ +#include /* We're doing kernel work */ +#include /* We're doing kernel work */ +#include /* Necessary because we use the proc fs */ +#include /* for copy_from_user */ +#include "hif.h" +#include "hif_main.h" +#if defined(HIF_USB) +#include "if_usb.h" +#endif +#if defined(HIF_SDIO) +#include "if_sdio.h" +#endif +#include "hif_debug.h" +#include "pld_common.h" + +#define PROCFS_NAME "athdiagpfs" +#ifdef MULTI_IF_NAME +#define PROCFS_DIR "cld" MULTI_IF_NAME +#else +#define PROCFS_DIR "cld" +#endif + +/** + * This structure hold information about the /proc file + * + */ +static struct proc_dir_entry *proc_file, *proc_dir; + +static void *get_hif_hdl_from_file(struct file *file) +{ + struct hif_opaque_softc *scn; + + scn = (struct hif_opaque_softc *)PDE_DATA(file_inode(file)); + return (void *)scn; +} + +static ssize_t ath_procfs_diag_read(struct file *file, char __user *buf, + size_t count, loff_t *pos) +{ + hif_handle_t hif_hdl; + int rv; + uint8_t *read_buffer = NULL; + struct hif_softc *scn; + uint32_t offset = 0, memtype = 0; + + read_buffer = qdf_mem_malloc(count); + if (NULL == read_buffer) { + HIF_ERROR("%s: cdf_mem_alloc failed", __func__); + return -ENOMEM; + } + + hif_hdl = get_hif_hdl_from_file(file); + HIF_DBG("rd buff 0x%p cnt %zu offset 0x%x buf 0x%p", + read_buffer, count, (int)*pos, buf); + + scn = HIF_GET_SOFTC(hif_hdl); + if (scn->bus_type == QDF_BUS_TYPE_SNOC) { + memtype = ((uint32_t)(*pos) & 0xff000000) >> 24; + offset = (uint32_t)(*pos) & 0xffffff; + HIF_TRACE("%s: offset 0x%x memtype 0x%x, datalen %zu\n", + __func__, offset, memtype, count); + rv = pld_athdiag_read(scn->qdf_dev->dev, + offset, memtype, count, + (uint8_t *)read_buffer); + goto out; + } + + if ((count == 4) && ((((uint32_t) (*pos)) & 3) == 0)) { + /* reading a word? */ + rv = hif_diag_read_access(hif_hdl, (uint32_t)(*pos), + (uint32_t *)read_buffer); + } else { + rv = hif_diag_read_mem(hif_hdl, (uint32_t)(*pos), + (uint8_t *)read_buffer, count); + } + +out: + if (rv) + return -EIO; + + if (copy_to_user(buf, read_buffer, count)) { + qdf_mem_free(read_buffer); + HIF_ERROR("%s: copy_to_user error in /proc/%s", + __func__, PROCFS_NAME); + return -EFAULT; + } else + qdf_mem_free(read_buffer); + + return count; +} + +static ssize_t ath_procfs_diag_write(struct file *file, + const char __user *buf, + size_t count, loff_t *pos) +{ + hif_handle_t hif_hdl; + int rv; + uint8_t *write_buffer = NULL; + struct hif_softc *scn; + uint32_t offset = 0, memtype = 0; + + write_buffer = qdf_mem_malloc(count); + if (NULL == write_buffer) { + HIF_ERROR("%s: cdf_mem_alloc failed", __func__); + return -ENOMEM; + } + if (copy_from_user(write_buffer, buf, count)) { + qdf_mem_free(write_buffer); + HIF_ERROR("%s: copy_to_user error in /proc/%s", + __func__, PROCFS_NAME); + return -EFAULT; + } + + hif_hdl = get_hif_hdl_from_file(file); + HIF_DBG("wr buff 0x%p buf 0x%p cnt %zu offset 0x%x value 0x%x", + write_buffer, buf, count, + (int)*pos, *((uint32_t *) write_buffer)); + + scn = HIF_GET_SOFTC(hif_hdl); + if (scn->bus_type == QDF_BUS_TYPE_SNOC) { + memtype = ((uint32_t)(*pos) & 0xff000000) >> 24; + offset = (uint32_t)(*pos) & 0xffffff; + HIF_TRACE("%s: offset 0x%x memtype 0x%x, datalen %zu\n", + __func__, offset, memtype, count); + rv = pld_athdiag_write(scn->qdf_dev->dev, + offset, memtype, count, + (uint8_t *)write_buffer); + goto out; + } + + if ((count == 4) && ((((uint32_t) (*pos)) & 3) == 0)) { + /* reading a word? */ + uint32_t value = *((uint32_t *)write_buffer); + rv = hif_diag_write_access(hif_hdl, (uint32_t)(*pos), value); + } else { + rv = hif_diag_write_mem(hif_hdl, (uint32_t)(*pos), + (uint8_t *)write_buffer, count); + } + +out: + + qdf_mem_free(write_buffer); + if (rv == 0) { + return count; + } else { + return -EIO; + } +} + +static const struct file_operations athdiag_fops = { + .read = ath_procfs_diag_read, + .write = ath_procfs_diag_write, +}; + +/** + *This function is called when the module is loaded + * + */ +int athdiag_procfs_init(void *scn) +{ + proc_dir = proc_mkdir(PROCFS_DIR, NULL); + if (proc_dir == NULL) { + remove_proc_entry(PROCFS_DIR, NULL); + HIF_ERROR("%s: Error: Could not initialize /proc/%s", + __func__, PROCFS_DIR); + return -ENOMEM; + } + + proc_file = proc_create_data(PROCFS_NAME, + S_IRUSR | S_IWUSR, proc_dir, + &athdiag_fops, (void *)scn); + if (proc_file == NULL) { + remove_proc_entry(PROCFS_NAME, proc_dir); + HIF_ERROR("%s: Could not initialize /proc/%s", + __func__, PROCFS_NAME); + return -ENOMEM; + } + + HIF_DBG("/proc/%s/%s created", PROCFS_DIR, PROCFS_NAME); + return 0; /* everything is ok */ +} + +/** + *This function is called when the module is unloaded + * + */ +void athdiag_procfs_remove(void) +{ + if (proc_dir != NULL) { + remove_proc_entry(PROCFS_NAME, proc_dir); + HIF_DBG("/proc/%s/%s removed", PROCFS_DIR, PROCFS_NAME); + remove_proc_entry(PROCFS_DIR, NULL); + HIF_DBG("/proc/%s removed", PROCFS_DIR); + proc_dir = NULL; + } +} +#else +int athdiag_procfs_init(void *scn) +{ + return 0; +} +void athdiag_procfs_remove(void) {} +#endif diff --git a/drivers/staging/qca-wifi-host-cmn/hif/src/ce/ce_api.h b/drivers/staging/qca-wifi-host-cmn/hif/src/ce/ce_api.h new file mode 100644 index 0000000000000000000000000000000000000000..12e038a0a7c40235b6142251b52e22cf531057ec --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/hif/src/ce/ce_api.h @@ -0,0 +1,493 @@ +/* + * Copyright (c) 2013-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef __COPY_ENGINE_API_H__ +#define __COPY_ENGINE_API_H__ + +#include "ce_main.h" +#include "hif_main.h" + +/* TBDXXX: Use int return values for consistency with Target */ + +/* TBDXXX: Perhaps merge Host/Target-->common */ + +/* + * Copy Engine support: low-level Target-side Copy Engine API. + * This is a hardware access layer used by code that understands + * how to use copy engines. + */ + +/* + * A "struct CE_handle *" serves as an opaque pointer-sized + * handle to a specific copy engine. + */ +struct CE_handle; + +/* + * "Send Completion" callback type for Send Completion Notification. + * + * If a Send Completion callback is registered and one or more sends + * have completed, the callback is invoked. + * + * per_ce_send_context is a context supplied by the calling layer + * (via ce_send_cb_register). It is associated with a copy engine. + * + * per_transfer_send_context is context supplied by the calling layer + * (via the "send" call). It may be different for each invocation + * of send. + * + * The buffer parameter is the first byte sent of the first buffer + * sent (if more than one buffer). + * + * nbytes is the number of bytes of that buffer that were sent. + * + * transfer_id matches the value used when the buffer or + * buf_list was sent. + * + * Implementation note: Pops 1 completed send buffer from Source ring + */ +typedef void (*ce_send_cb)(struct CE_handle *copyeng, + void *per_ce_send_context, + void *per_transfer_send_context, + qdf_dma_addr_t buffer, + unsigned int nbytes, + unsigned int transfer_id, + unsigned int sw_index, + unsigned int hw_index, + uint32_t toeplitz_hash_result); + +/* + * "Buffer Received" callback type for Buffer Received Notification. + * + * Implementation note: Pops 1 completed recv buffer from Dest ring + */ +typedef void (*CE_recv_cb)(struct CE_handle *copyeng, + void *per_CE_recv_context, + void *per_transfer_recv_context, + qdf_dma_addr_t buffer, + unsigned int nbytes, + unsigned int transfer_id, + unsigned int flags); + +/* + * Copy Engine Watermark callback type. + * + * Allows upper layers to be notified when watermarks are reached: + * space is available and/or running short in a source ring + * buffers are exhausted and/or abundant in a destination ring + * + * The flags parameter indicates which condition triggered this + * callback. See CE_WM_FLAG_*. + * + * Watermark APIs are provided to allow upper layers "batch" + * descriptor processing and to allow upper layers to + * throttle/unthrottle. + */ +typedef void (*CE_watermark_cb)(struct CE_handle *copyeng, + void *per_CE_wm_context, unsigned int flags); + +#define CE_WM_FLAG_SEND_HIGH 1 +#define CE_WM_FLAG_SEND_LOW 2 +#define CE_WM_FLAG_RECV_HIGH 4 +#define CE_WM_FLAG_RECV_LOW 8 +#define CE_HTT_TX_CE 4 + +/* A list of buffers to be gathered and sent */ +struct ce_sendlist; + +/* Copy Engine settable attributes */ +struct CE_attr; + +/*==================Send=====================================================*/ + +/* ce_send flags */ +/* disable ring's byte swap, even if the default policy is to swap */ +#define CE_SEND_FLAG_SWAP_DISABLE 1 + +/* + * Queue a source buffer to be sent to an anonymous destination buffer. + * copyeng - which copy engine to use + * buffer - address of buffer + * nbytes - number of bytes to send + * transfer_id - arbitrary ID; reflected to destination + * flags - CE_SEND_FLAG_* values + * Returns 0 on success; otherwise an error status. + * + * Note: If no flags are specified, use CE's default data swap mode. + * + * Implementation note: pushes 1 buffer to Source ring + */ +int ce_send(struct CE_handle *copyeng, + void *per_transfer_send_context, + qdf_dma_addr_t buffer, + unsigned int nbytes, + unsigned int transfer_id, + unsigned int flags, + unsigned int user_flags); + +#ifdef WLAN_FEATURE_FASTPATH +int ce_send_fast(struct CE_handle *copyeng, qdf_nbuf_t msdu, + unsigned int transfer_id, uint32_t download_len); + +#endif + +void ce_update_tx_ring(struct CE_handle *ce_tx_hdl, uint32_t num_htt_cmpls); +extern qdf_nbuf_t ce_batch_send(struct CE_handle *ce_tx_hdl, + qdf_nbuf_t msdu, + uint32_t transfer_id, + uint32_t len, + uint32_t sendhead); + +extern int ce_send_single(struct CE_handle *ce_tx_hdl, + qdf_nbuf_t msdu, + uint32_t transfer_id, + uint32_t len); +/* + * Register a Send Callback function. + * This function is called as soon as the contents of a Send + * have reached the destination, unless disable_interrupts is + * requested. In this case, the callback is invoked when the + * send status is polled, shortly after the send completes. + */ +void ce_send_cb_register(struct CE_handle *copyeng, + ce_send_cb fn_ptr, + void *per_ce_send_context, int disable_interrupts); + +/* + * Return the size of a SendList. This allows the caller to allocate + * a SendList while the SendList structure remains opaque. + */ +unsigned int ce_sendlist_sizeof(void); + +/* Initialize a sendlist */ +void ce_sendlist_init(struct ce_sendlist *sendlist); + +/* Append a simple buffer (address/length) to a sendlist. */ +int ce_sendlist_buf_add(struct ce_sendlist *sendlist, + qdf_dma_addr_t buffer, + unsigned int nbytes, + uint32_t flags, /* OR-ed with internal flags */ + uint32_t user_flags); + +/* + * Queue a "sendlist" of buffers to be sent using gather to a single + * anonymous destination buffer + * copyeng - which copy engine to use + * sendlist - list of simple buffers to send using gather + * transfer_id - arbitrary ID; reflected to destination + * Returns 0 on success; otherwise an error status. + * + * Implemenation note: Pushes multiple buffers with Gather to Source ring. + */ +int ce_sendlist_send(struct CE_handle *copyeng, + void *per_transfer_send_context, + struct ce_sendlist *sendlist, + unsigned int transfer_id); + +/*==================Recv=====================================================*/ + +/* + * Make a buffer available to receive. The buffer must be at least of a + * minimal size appropriate for this copy engine (src_sz_max attribute). + * copyeng - which copy engine to use + * per_transfer_recv_context - context passed back to caller's recv_cb + * buffer - address of buffer in CE space + * Returns 0 on success; otherwise an error status. + * + * Implemenation note: Pushes a buffer to Dest ring. + */ +int ce_recv_buf_enqueue(struct CE_handle *copyeng, + void *per_transfer_recv_context, + qdf_dma_addr_t buffer); + +/* + * Register a Receive Callback function. + * This function is called as soon as data is received + * from the source. + */ +void ce_recv_cb_register(struct CE_handle *copyeng, + CE_recv_cb fn_ptr, + void *per_CE_recv_context, + int disable_interrupts); + +/*==================CE Watermark=============================================*/ + +/* + * Register a Watermark Callback function. + * This function is called as soon as a watermark level + * is crossed. A Watermark Callback function is free to + * handle received data "en masse"; but then some coordination + * is required with a registered Receive Callback function. + * [Suggestion: Either handle Receives in a Receive Callback + * or en masse in a Watermark Callback; but not both.] + */ +void ce_watermark_cb_register(struct CE_handle *copyeng, + CE_watermark_cb fn_ptr, + void *per_CE_wm_context); + +/* + * Set low/high watermarks for the send/source side of a copy engine. + * + * Typically, the destination side CPU manages watermarks for + * the receive side and the source side CPU manages watermarks + * for the send side. + * + * A low watermark of 0 is never hit (so the watermark function + * will never be called for a Low Watermark condition). + * + * A high watermark equal to nentries is never hit (so the + * watermark function will never be called for a High Watermark + * condition). + */ +void ce_send_watermarks_set(struct CE_handle *copyeng, + unsigned int low_alert_nentries, + unsigned int high_alert_nentries); + +/* Set low/high watermarks for the receive/destination side of copy engine. */ +void ce_recv_watermarks_set(struct CE_handle *copyeng, + unsigned int low_alert_nentries, + unsigned int high_alert_nentries); + +/* + * Return the number of entries that can be queued + * to a ring at an instant in time. + * + * For source ring, does not imply that destination-side + * buffers are available; merely indicates descriptor space + * in the source ring. + * + * For destination ring, does not imply that previously + * received buffers have been processed; merely indicates + * descriptor space in destination ring. + * + * Mainly for use with CE Watermark callback. + */ +unsigned int ce_send_entries_avail(struct CE_handle *copyeng); +unsigned int ce_recv_entries_avail(struct CE_handle *copyeng); + +/* + * Return the number of entries in the ring that are ready + * to be processed by software. + * + * For source ring, the number of descriptors that have + * been completed and can now be overwritten with new send + * descriptors. + * + * For destination ring, the number of descriptors that + * are available to be processed (newly received buffers). + */ +unsigned int ce_send_entries_done(struct CE_handle *copyeng); +unsigned int ce_recv_entries_done(struct CE_handle *copyeng); + +/* recv flags */ +/* Data is byte-swapped */ +#define CE_RECV_FLAG_SWAPPED 1 + +/* + * Supply data for the next completed unprocessed receive descriptor. + * + * For use + * with CE Watermark callback, + * in a recv_cb function when processing buf_lists + * in a recv_cb function in order to mitigate recv_cb's. + * + * Implemenation note: Pops buffer from Dest ring. + */ +int ce_completed_recv_next(struct CE_handle *copyeng, + void **per_CE_contextp, + void **per_transfer_contextp, + qdf_dma_addr_t *bufferp, + unsigned int *nbytesp, + unsigned int *transfer_idp, + unsigned int *flagsp); + +/* + * Supply data for the next completed unprocessed send descriptor. + * + * For use + * with CE Watermark callback + * in a send_cb function in order to mitigate send_cb's. + * + * Implementation note: Pops 1 completed send buffer from Source ring + */ +int ce_completed_send_next(struct CE_handle *copyeng, + void **per_CE_contextp, + void **per_transfer_contextp, + qdf_dma_addr_t *bufferp, + unsigned int *nbytesp, + unsigned int *transfer_idp, + unsigned int *sw_idx, + unsigned int *hw_idx, + uint32_t *toeplitz_hash_result); + +/*==================CE Engine Initialization=================================*/ + +/* Initialize an instance of a CE */ +struct CE_handle *ce_init(struct hif_softc *scn, + unsigned int CE_id, struct CE_attr *attr); + +/*==================CE Engine Shutdown=======================================*/ +/* + * Support clean shutdown by allowing the caller to revoke + * receive buffers. Target DMA must be stopped before using + * this API. + */ +QDF_STATUS +ce_revoke_recv_next(struct CE_handle *copyeng, + void **per_CE_contextp, + void **per_transfer_contextp, + qdf_dma_addr_t *bufferp); + +/* + * Support clean shutdown by allowing the caller to cancel + * pending sends. Target DMA must be stopped before using + * this API. + */ +QDF_STATUS +ce_cancel_send_next(struct CE_handle *copyeng, + void **per_CE_contextp, + void **per_transfer_contextp, + qdf_dma_addr_t *bufferp, + unsigned int *nbytesp, + unsigned int *transfer_idp, + uint32_t *toeplitz_hash_result); + +void ce_fini(struct CE_handle *copyeng); + +/*==================CE Interrupt Handlers====================================*/ +void ce_per_engine_service_any(int irq, struct hif_softc *scn); +int ce_per_engine_service(struct hif_softc *scn, unsigned int CE_id); +void ce_per_engine_servicereap(struct hif_softc *scn, unsigned int CE_id); + +/*===================CE cmpl interrupt Enable/Disable =======================*/ +void ce_disable_any_copy_compl_intr_nolock(struct hif_softc *scn); +void ce_enable_any_copy_compl_intr_nolock(struct hif_softc *scn); + +/* API to check if any of the copy engine pipes has + * pending frames for prcoessing + */ +bool ce_get_rx_pending(struct hif_softc *scn); + +/* CE_attr.flags values */ +#define CE_ATTR_NO_SNOOP 0x01 /* Use NonSnooping PCIe accesses? */ +#define CE_ATTR_BYTE_SWAP_DATA 0x02 /* Byte swap data words */ +#define CE_ATTR_SWIZZLE_DESCRIPTORS 0x04 /* Swizzle descriptors? */ +#define CE_ATTR_DISABLE_INTR 0x08 /* no interrupt on copy completion */ +#define CE_ATTR_ENABLE_POLL 0x10 /* poll for residue descriptors */ + +/* Attributes of an instance of a Copy Engine */ +struct CE_attr { + unsigned int flags; /* CE_ATTR_* values */ + unsigned int priority; /* TBD */ + unsigned int src_nentries; /* #entries in source ring - + * Must be a power of 2 */ + unsigned int src_sz_max; /* Max source send size for this CE. + * This is also the minimum size of + * a destination buffer. */ + unsigned int dest_nentries; /* #entries in destination ring - + * Must be a power of 2 */ + void *reserved; /* Future use */ +}; + +/* + * When using sendlist_send to transfer multiple buffer fragments, the + * transfer context of each fragment, except last one, will be filled + * with CE_SENDLIST_ITEM_CTXT. CE_completed_send will return success for + * each fragment done with send and the transfer context would be + * CE_SENDLIST_ITEM_CTXT. Upper layer could use this to identify the + * status of a send completion. + */ +#define CE_SENDLIST_ITEM_CTXT ((void *)0xcecebeef) + +/* + * This is an opaque type that is at least large enough to hold + * a sendlist. A sendlist can only be accessed through CE APIs, + * but this allows a sendlist to be allocated on the run-time + * stack. TBDXXX: un-opaque would be simpler... + */ +struct ce_sendlist { + unsigned int word[62]; +}; + +#define ATH_ISR_NOSCHED 0x0000 /* Do not schedule bottom half/DPC */ +#define ATH_ISR_SCHED 0x0001 /* Schedule the bottom half for execution */ +#define ATH_ISR_NOTMINE 0x0002 /* for shared IRQ's */ + +#ifdef IPA_OFFLOAD +void ce_ipa_get_resource(struct CE_handle *ce, + qdf_dma_addr_t *ce_sr_base_paddr, + uint32_t *ce_sr_ring_size, + qdf_dma_addr_t *ce_reg_paddr); +#else +/** + * ce_ipa_get_resource() - get uc resource on copyengine + * @ce: copyengine context + * @ce_sr_base_paddr: copyengine source ring base physical address + * @ce_sr_ring_size: copyengine source ring size + * @ce_reg_paddr: copyengine register physical address + * + * Copy engine should release resource to micro controller + * Micro controller needs + * - Copy engine source descriptor base address + * - Copy engine source descriptor size + * - PCI BAR address to access copy engine regiser + * + * Return: None + */ +static inline void ce_ipa_get_resource(struct CE_handle *ce, + qdf_dma_addr_t *ce_sr_base_paddr, + uint32_t *ce_sr_ring_size, + qdf_dma_addr_t *ce_reg_paddr) +{ + return; +} +#endif /* IPA_OFFLOAD */ + +static inline void ce_pkt_error_count_incr( + struct HIF_CE_state *_hif_state, + enum ol_ath_hif_pkt_ecodes _hif_ecode) +{ + struct hif_softc *scn = HIF_GET_SOFTC(_hif_state); + + if (_hif_ecode == HIF_PIPE_NO_RESOURCE) + (scn->pkt_stats.hif_pipe_no_resrc_count) + += 1; +} + +bool ce_check_rx_pending(struct CE_state *CE_state); +void *hif_ce_get_lro_ctx(struct hif_opaque_softc *hif_hdl, int ctx_id); +#if defined(FEATURE_LRO) +int ce_lro_flush_cb_register(struct hif_opaque_softc *scn, + void (handler)(void *), + void *(lro_init_handler)(void)); +int ce_lro_flush_cb_deregister(struct hif_opaque_softc *hif_hdl, + void (lro_deinit_cb)(void *)); +#endif + +int hif_ce_bus_early_suspend(struct hif_softc *scn); +int hif_ce_bus_late_resume(struct hif_softc *scn); +#endif /* __COPY_ENGINE_API_H__ */ diff --git a/drivers/staging/qca-wifi-host-cmn/hif/src/ce/ce_assignment.h b/drivers/staging/qca-wifi-host-cmn/hif/src/ce/ce_assignment.h new file mode 100644 index 0000000000000000000000000000000000000000..b7225d297905d4e0cc3506f48176d8220fad40af --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/hif/src/ce/ce_assignment.h @@ -0,0 +1,410 @@ +/* + * Copyright (c) 2014-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * Implementation of the Host-side Host InterFace (HIF) API + * for a Host/Target interconnect using Copy Engines over PCIe. + */ + +#ifndef __HIF_PCI_INTERNAL_H__ +#define __HIF_PCI_INTERNAL_H__ + +#ifndef CONFIG_WIN +#ifndef PEER_CACHEING_HOST_ENABLE +#define PEER_CACHEING_HOST_ENABLE 0 +#endif +#endif + +#define HIF_PCI_DEBUG ATH_DEBUG_MAKE_MODULE_MASK(0) +#define HIF_PCI_IPA_UC_ASSIGNED_CE 5 + +#if defined(WLAN_DEBUG) || defined(DEBUG) +static ATH_DEBUG_MASK_DESCRIPTION g_hif_debug_description[] = { + {HIF_PCI_DEBUG, "hif_pci"}, +}; + +ATH_DEBUG_INSTANTIATE_MODULE_VAR(hif, "hif", "PCIe Host Interface", + ATH_DEBUG_MASK_DEFAULTS | ATH_DEBUG_INFO, + ATH_DEBUG_DESCRIPTION_COUNT + (g_hif_debug_description), + g_hif_debug_description); +#endif + +#ifdef CONFIG_ATH_PCIE_ACCESS_DEBUG +/* globals are initialized to 0 by the compiler */; +spinlock_t pcie_access_log_lock; +unsigned int pcie_access_log_seqnum; +HIF_ACCESS_LOG pcie_access_log[PCIE_ACCESS_LOG_NUM]; +static void hif_target_dump_access_log(void); +#endif + +/* + * Host software's Copy Engine configuration. + * This table is derived from the CE_PCI TABLE, above. + */ +#ifdef BIG_ENDIAN_HOST +#define CE_ATTR_FLAGS CE_ATTR_BYTE_SWAP_DATA +#else +#define CE_ATTR_FLAGS 0 +#endif + +/* Maximum number of Copy Engine's supported */ +#define CE_HTT_H2T_MSG_SRC_NENTRIES 2048 +#define CE_HTT_H2T_MSG_SRC_NENTRIES_AR900B 4096 + +#define DIAG_CE_ID 7 +#define EPPING_CE_FLAGS_POLL \ + (CE_ATTR_DISABLE_INTR|CE_ATTR_ENABLE_POLL|CE_ATTR_FLAGS) + +#ifdef CONFIG_WIN +#define PIPEDIR_INOUT_H2H 4 +#endif + +#ifdef QCA_WIFI_3_0 +static struct CE_attr host_ce_config_wlan[] = { + /* host->target HTC control and raw streams */ + { /* CE0 */ CE_ATTR_FLAGS, 0, 16, 2048, 0, NULL,}, + /* target->host HTT + HTC control */ + { /* CE1 */ CE_ATTR_FLAGS, 0, 0, 2048, 512, NULL,}, + /* target->host WMI */ + { /* CE2 */ CE_ATTR_FLAGS, 0, 0, 2048, 128, NULL,}, + /* host->target WMI */ + { /* CE3 */ CE_ATTR_FLAGS, 0, 32, 2048, 0, NULL,}, + /* host->target HTT */ + { /* CE4 */ (CE_ATTR_FLAGS | CE_ATTR_DISABLE_INTR), 0, + CE_HTT_H2T_MSG_SRC_NENTRIES, 256, 0, NULL,}, + /* ipa_uc->target HTC control */ + { /* CE5 */ (CE_ATTR_FLAGS | CE_ATTR_DISABLE_INTR), 0, + CE_HTT_H2T_MSG_SRC_NENTRIES, 512, 0, NULL,}, + /* Target autonomous HIF_memcpy */ + { /* CE6 */ CE_ATTR_FLAGS, 0, 0, 0, 0, NULL,}, + /* ce_diag, the Diagnostic Window */ + { /* CE7 */ (CE_ATTR_FLAGS | CE_ATTR_DISABLE_INTR), 0, + 2, DIAG_TRANSFER_LIMIT, 2, NULL,}, + /* Target to uMC */ + { /* CE8 */ CE_ATTR_FLAGS, 0, 0, 0, 0, NULL,}, + /* target->host HTT */ + { /* CE9 */ CE_ATTR_FLAGS, 0, 0, 2048, 512, NULL,}, + /* target->host HTT */ + { /* CE10 */ CE_ATTR_FLAGS, 0, 0, 2048, 512, NULL,}, + /* target -> host PKTLOG */ + { /* CE11 */ CE_ATTR_FLAGS, 0, 0, 2048, 512, NULL,}, +}; + +static struct CE_pipe_config target_ce_config_wlan[] = { + /* host->target HTC control and raw streams */ + { /* CE0 */ 0, PIPEDIR_OUT, 32, 2048, CE_ATTR_FLAGS, 0,}, + /* target->host HTT */ + { /* CE1 */ 1, PIPEDIR_IN, 32, 2048, CE_ATTR_FLAGS, 0,}, + /* target->host WMI + HTC control */ + { /* CE2 */ 2, PIPEDIR_IN, 64, 2048, CE_ATTR_FLAGS, 0,}, + /* host->target WMI */ + { /* CE3 */ 3, PIPEDIR_OUT, 32, 2048, CE_ATTR_FLAGS, 0,}, + /* host->target HTT */ + { /* CE4 */ 4, PIPEDIR_OUT, 256, 256, + (CE_ATTR_FLAGS | CE_ATTR_DISABLE_INTR), 0,}, + /* NB: 50% of src nentries, since tx has 2 frags */ + /* ipa_uc->target */ + { /* CE5 */ 5, PIPEDIR_OUT, 1024, 64, + (CE_ATTR_FLAGS | CE_ATTR_DISABLE_INTR), 0,}, + /* Reserved for target autonomous HIF_memcpy */ + { /* CE6 */ 6, PIPEDIR_INOUT, 32, 16384, CE_ATTR_FLAGS, 0,}, + /* CE7 used only by Host */ + { /* CE7 */ 7, PIPEDIR_INOUT_H2H, 0, 0, + (CE_ATTR_FLAGS | CE_ATTR_DISABLE_INTR), 0,}, + /* CE8 used only by IPA */ + { /* CE8 */ 8, PIPEDIR_IN, 32, 2048, CE_ATTR_FLAGS, 0,}, + /* CE9 target->host HTT */ + { /* CE9 */ 9, PIPEDIR_IN, 32, 2048, CE_ATTR_FLAGS, 0,}, + /* CE10 target->host HTT */ + { /* CE10 */ 10, PIPEDIR_IN, 32, 2048, CE_ATTR_FLAGS, 0,}, + /* Target -> host PKTLOG */ + { /* CE11 */ 11, PIPEDIR_IN, 32, 2048, CE_ATTR_FLAGS, 0,}, +}; + +static struct CE_attr host_ce_config_wlan_epping_poll[] = { + /* host->target HTC control and raw streams */ + { /* CE0 */ CE_ATTR_FLAGS, 0, 16, 2048, 0, NULL,}, + /* target->host EP-ping */ + { /* CE1 */ EPPING_CE_FLAGS_POLL, 0, 0, 2048, 128, NULL,}, + /* target->host EP-ping */ + { /* CE2 */ EPPING_CE_FLAGS_POLL, 0, 0, 2048, 128, NULL,}, + /* host->target EP-ping */ + { /* CE3 */ CE_ATTR_FLAGS, 0, 128, 2048, 0, NULL,}, + /* host->target EP-ping */ + { /* CE4 */ CE_ATTR_FLAGS, 0, 128, 2048, 0, NULL,}, + /* EP-ping heartbeat */ + { /* CE5 */ CE_ATTR_FLAGS, 0, 0, 2048, 128, NULL,}, + /* unused */ + { /* CE6 */ CE_ATTR_FLAGS, 0, 0, 0, 0, NULL,}, + /* ce_diag, the Diagnostic Window */ + { /* CE7 */ CE_ATTR_FLAGS, 0, 2, DIAG_TRANSFER_LIMIT, 2, NULL,}, +}; + +static struct CE_attr host_ce_config_wlan_epping_irq[] = { + /* host->target HTC control and raw streams */ + { /* CE0 */ CE_ATTR_FLAGS, 0, 16, 2048, 0, NULL,}, + /* target->host EP-ping */ + { /* CE1 */ CE_ATTR_FLAGS, 0, 0, 2048, 128, NULL,}, + /* target->host EP-ping */ + { /* CE2 */ CE_ATTR_FLAGS, 0, 0, 2048, 128, NULL,}, + /* host->target EP-ping */ + { /* CE3 */ CE_ATTR_FLAGS, 0, 128, 2048, 0, NULL,}, + /* host->target EP-ping */ + { /* CE4 */ CE_ATTR_FLAGS, 0, 128, 2048, 0, NULL,}, + /* EP-ping heartbeat */ + { /* CE5 */ CE_ATTR_FLAGS, 0, 0, 2048, 128, NULL,}, + /* unused */ + { /* CE6 */ CE_ATTR_FLAGS, 0, 0, 0, 0, NULL,}, + /* ce_diag, the Diagnostic Window */ + { /* CE7 */ CE_ATTR_FLAGS, 0, 2, DIAG_TRANSFER_LIMIT, 2, NULL,}, +}; +/* + * EP-ping firmware's CE configuration + */ +static struct CE_pipe_config target_ce_config_wlan_epping[] = { + /* host->target HTC control and raw streams */ + { /* CE0 */ 0, PIPEDIR_OUT, 16, 2048, CE_ATTR_FLAGS, 0,}, + /* target->host EP-ping */ + { /* CE1 */ 1, PIPEDIR_IN, 128, 2048, CE_ATTR_FLAGS, 0,}, + /* target->host EP-ping */ + { /* CE2 */ 2, PIPEDIR_IN, 128, 2048, CE_ATTR_FLAGS, 0,}, + /* host->target EP-ping */ + { /* CE3 */ 3, PIPEDIR_OUT, 128, 2048, CE_ATTR_FLAGS, 0,}, + /* host->target EP-ping */ + { /* CE4 */ 4, PIPEDIR_OUT, 128, 2048, CE_ATTR_FLAGS, 0,}, + /* EP-ping heartbeat */ + { /* CE5 */ 5, PIPEDIR_IN, 128, 2048, CE_ATTR_FLAGS, 0,}, + /* unused */ + { /* CE6 */ 6, PIPEDIR_INOUT, 0, 0, CE_ATTR_FLAGS, 0,}, + /* CE7 used only by Host */ + { /* CE7 */ 7, PIPEDIR_INOUT_H2H, 0, 0, 0, 0,}, + /* CE8 used only by IPA */ + { /* CE8 */ 8, PIPEDIR_IN, 32, 2048, CE_ATTR_FLAGS, 0,} +}; +#else +static struct CE_attr host_ce_config_wlan[] = { + /* host->target HTC control and raw streams */ + { /* CE0 */ CE_ATTR_FLAGS, 0, 16, 256, 0, NULL,}, + /* target->host HTT + HTC control */ + { /* CE1 */ CE_ATTR_FLAGS, 0, 0, 2048, 512, NULL,}, + /* target->host WMI */ + { /* CE2 */ CE_ATTR_FLAGS, 0, 0, 2048, 32, NULL,}, + /* host->target WMI */ + { /* CE3 */ CE_ATTR_FLAGS, 0, 32, 2048, 0, NULL,}, + /* host->target HTT */ + { /* CE4 */ CE_ATTR_FLAGS | CE_ATTR_DISABLE_INTR, 0, + CE_HTT_H2T_MSG_SRC_NENTRIES, 256, 0, NULL,}, + /* ipa_uc->target HTC control */ + { /* CE5 */ CE_ATTR_FLAGS | CE_ATTR_DISABLE_INTR, 0, + 1024, 512, 0, NULL,}, + /* Target autonomous HIF_memcpy */ + { /* CE6 */ CE_ATTR_FLAGS, 0, 0, 0, 0, NULL,}, + /* ce_diag, the Diagnostic Window */ + { /* CE7 */ CE_ATTR_FLAGS | CE_ATTR_DISABLE_INTR, + 0, 2, DIAG_TRANSFER_LIMIT, 2, NULL,}, +}; + +static struct CE_pipe_config target_ce_config_wlan[] = { + /* host->target HTC control and raw streams */ + { /* CE0 */ 0, PIPEDIR_OUT, 32, 256, CE_ATTR_FLAGS, 0,}, + /* target->host HTT + HTC control */ + { /* CE1 */ 1, PIPEDIR_IN, 32, 2048, CE_ATTR_FLAGS, 0,}, + /* target->host WMI */ + { /* CE2 */ 2, PIPEDIR_IN, 32, 2048, CE_ATTR_FLAGS, 0,}, + /* host->target WMI */ + { /* CE3 */ 3, PIPEDIR_OUT, 32, 2048, CE_ATTR_FLAGS, 0,}, + /* host->target HTT */ + { /* CE4 */ 4, PIPEDIR_OUT, 256, 256, CE_ATTR_FLAGS, 0,}, + /* NB: 50% of src nentries, since tx has 2 frags */ + /* ipa_uc->target HTC control */ + { /* CE5 */ 5, PIPEDIR_OUT, 1024, 64, CE_ATTR_FLAGS, 0,}, + /* Reserved for target autonomous HIF_memcpy */ + { /* CE6 */ 6, PIPEDIR_INOUT, 32, 4096, CE_ATTR_FLAGS, 0,}, + /* CE7 used only by Host */ + { /* CE7 */ 7, PIPEDIR_INOUT_H2H, 0, 0, 0, 0,}, + /* CE8 used only by IPA */ + { /* CE8 */ 8, PIPEDIR_IN, 32, 2048, CE_ATTR_FLAGS, 0,} +}; + +static struct CE_attr host_ce_config_wlan_epping_poll[] = { + /* host->target HTC control and raw streams */ + { /* CE0 */ CE_ATTR_FLAGS, 0, 16, 256, 0, NULL,}, + /* target->host EP-ping */ + { /* CE1 */ EPPING_CE_FLAGS_POLL, 0, 0, 2048, 128, NULL,}, + /* target->host EP-ping */ + { /* CE2 */ EPPING_CE_FLAGS_POLL, 0, 0, 2048, 128, NULL,}, + /* host->target EP-ping */ + { /* CE3 */ CE_ATTR_FLAGS, 0, 128, 2048, 0, NULL,}, + /* host->target EP-ping */ + { /* CE4 */ CE_ATTR_FLAGS, 0, 128, 2048, 0, NULL,}, + /* EP-ping heartbeat */ + { /* CE5 */ CE_ATTR_FLAGS, 0, 0, 2048, 128, NULL,}, + /* unused */ + { /* CE6 */ CE_ATTR_FLAGS, 0, 0, 0, 0, NULL,}, + /* ce_diag, the Diagnostic Window */ + { /* CE7 */ CE_ATTR_FLAGS, 0, 2, DIAG_TRANSFER_LIMIT, 2, NULL,}, + { /* CE8 */ CE_ATTR_FLAGS, 0, 0, 0, 0, NULL,}, + /* The following CEs are not being used yet */ + { /* CE9 */ CE_ATTR_FLAGS, 0, 0, 0, 0, NULL,}, + { /* CE10 */ CE_ATTR_FLAGS, 0, 0, 0, 0, NULL,}, + { /* CE11 */ CE_ATTR_FLAGS, 0, 0, 0, 0, NULL,}, +}; +static struct CE_attr host_ce_config_wlan_epping_irq[] = { + /* host->target HTC control and raw streams */ + { /* CE0 */ CE_ATTR_FLAGS, 0, 16, 256, 0, NULL,}, + /* target->host EP-ping */ + { /* CE1 */ CE_ATTR_FLAGS, 0, 0, 2048, 128, NULL,}, + /* target->host EP-ping */ + { /* CE2 */ CE_ATTR_FLAGS, 0, 0, 2048, 128, NULL,}, + /* host->target EP-ping */ + { /* CE3 */ CE_ATTR_FLAGS, 0, 128, 2048, 0, NULL,}, + /* host->target EP-ping */ + { /* CE4 */ CE_ATTR_FLAGS, 0, 128, 2048, 0, NULL,}, + /* EP-ping heartbeat */ + { /* CE5 */ CE_ATTR_FLAGS, 0, 0, 2048, 128, NULL,}, + /* unused */ + { /* CE6 */ CE_ATTR_FLAGS, 0, 0, 0, 0, NULL,}, + /* ce_diag, the Diagnostic Window */ + { /* CE7 */ CE_ATTR_FLAGS, 0, 2, DIAG_TRANSFER_LIMIT, 2, NULL,}, + { /* CE8 */ CE_ATTR_FLAGS, 0, 0, 0, 0, NULL,}, + /* The following CEs are not being used yet */ + { /* CE9 */ CE_ATTR_FLAGS, 0, 0, 0, 0, NULL,}, + { /* CE10 */ CE_ATTR_FLAGS, 0, 0, 0, 0, NULL,}, + { /* CE11 */ CE_ATTR_FLAGS, 0, 0, 0, 0, NULL,}, +}; +/* + * EP-ping firmware's CE configuration + */ +static struct CE_pipe_config target_ce_config_wlan_epping[] = { + /* host->target HTC control and raw streams */ + { /* CE0 */ 0, PIPEDIR_OUT, 16, 256, CE_ATTR_FLAGS, 0,}, + /* target->host EP-ping */ + { /* CE1 */ 1, PIPEDIR_IN, 128, 2048, CE_ATTR_FLAGS, 0,}, + /* target->host EP-ping */ + { /* CE2 */ 2, PIPEDIR_IN, 128, 2048, CE_ATTR_FLAGS, 0,}, + /* host->target EP-ping */ + { /* CE3 */ 3, PIPEDIR_OUT, 128, 2048, CE_ATTR_FLAGS, 0,}, + /* host->target EP-ping */ + { /* CE4 */ 4, PIPEDIR_OUT, 128, 2048, CE_ATTR_FLAGS, 0,}, + /* EP-ping heartbeat */ + { /* CE5 */ 5, PIPEDIR_IN, 128, 2048, CE_ATTR_FLAGS, 0,}, + /* unused */ + { /* CE6 */ 6, PIPEDIR_INOUT, 0, 0, CE_ATTR_FLAGS, 0,}, + /* CE7 used only by Host */ + { /* CE7 */ 7, PIPEDIR_INOUT_H2H, 0, 0, 0, 0,}, + /* CE8 used only by IPA */ + { /* CE8 */ 8, PIPEDIR_IN, 32, 2048, CE_ATTR_FLAGS, 0,}, + { /* CE9 */ 9, PIPEDIR_IN, 0, 0, CE_ATTR_FLAGS, 0,}, + { /* CE10 */ 10, PIPEDIR_IN, 0, 0, CE_ATTR_FLAGS, 0,}, + { /* CE11 */ 11, PIPEDIR_IN, 0, 0, CE_ATTR_FLAGS, 0,}, +}; +#endif + +static struct CE_attr host_ce_config_wlan_ar9888[] = { + { /* CE0 */ CE_ATTR_FLAGS, 0, 16, 256, 0, NULL, }, /* host->target HTC control and raw streams */ + /* could be moved to share CE3 */ + { /* CE1 */ CE_ATTR_FLAGS, 0, 0, 512, 512, NULL, },/* target->host BMI + HTC control */ + { /* CE2 */ CE_ATTR_FLAGS, 0, 0, 2048, 128, NULL, },/* target->host WMI */ + { /* CE3 */ CE_ATTR_FLAGS, 0, 32, 2048, 0, NULL, },/* host->target WMI */ + { /* CE4 */ CE_ATTR_FLAGS | CE_ATTR_DISABLE_INTR, 0, + CE_HTT_H2T_MSG_SRC_NENTRIES_AR900B, 256, 0, NULL, }, /* host->target HTT */ +#if WLAN_FEATURE_FASTPATH + { /* CE5 */ CE_ATTR_FLAGS, 0, 0, 512, 512, NULL, }, /* target->host HTT messages */ +#else /* WLAN_FEATURE_FASTPATH */ + { /* CE5 */ CE_ATTR_FLAGS, 0, 0, 0, 0, NULL, }, /* unused */ +#endif /* WLAN_FEATURE_FASTPATH */ + { /* CE6 */ CE_ATTR_FLAGS, 0, 0, 0, 0, NULL, }, /* Target autonomous HIF_memcpy */ + { /* CE7 */ CE_ATTR_FLAGS, 0, 2, DIAG_TRANSFER_LIMIT, 2, NULL, }, /* ce_diag, the Diagnostic Window */ + { /* CE8 */ CE_ATTR_FLAGS, 0, 0, 0, 0, NULL, }, /* Target autonomous HIF_memcpy */ +}; + +static struct CE_attr host_ce_config_wlan_ar900b[] = { + { /* CE0 */ CE_ATTR_FLAGS, 0, 16, 256, 0, NULL, }, /* host->target HTC control and raw streams */ + /* could be moved to share CE3 */ + { /* CE1 */ CE_ATTR_FLAGS, 0, 0, 512, 512, NULL, },/* target->host BMI + HTC control */ + { /* CE2 */ CE_ATTR_FLAGS, 0, 0, 2048, 128, NULL, },/* target->host WMI */ + { /* CE3 */ CE_ATTR_FLAGS, 0, 32, 2048, 0, NULL, },/* host->target WMI */ + { /* CE4 */ CE_ATTR_FLAGS | CE_ATTR_DISABLE_INTR, 0, + CE_HTT_H2T_MSG_SRC_NENTRIES_AR900B, 256, 0, NULL, }, /* host->target HTT */ +#if WLAN_FEATURE_FASTPATH + { /* CE5 */ CE_ATTR_FLAGS, 0, 0, 512, 512, NULL, }, /* target->host HTT messages */ +#else /* WLAN_FEATURE_FASTPATH */ + { /* CE5 */ CE_ATTR_FLAGS, 0, 0, 0, 0, NULL, }, /* unused */ +#endif /* WLAN_FEATURE_FASTPATH */ + { /* CE6 */ CE_ATTR_FLAGS, 0, 0, 0, 0, NULL, }, /* Target autonomous HIF_memcpy */ + { /* CE7 */ CE_ATTR_FLAGS, 0, 2, DIAG_TRANSFER_LIMIT, 2, NULL, }, /* ce_diag, the Diagnostic Window */ + { /* CE8 */ CE_ATTR_FLAGS, 0, 0, 2048, 128, NULL, },/* target->host pktlog */ + { /* CE9 */ CE_ATTR_FLAGS, 0, 0, 0, 0, NULL, }, /* Target autonomous HIF_memcpy */ + { /* CE10 */ CE_ATTR_FLAGS, 0, 0, 0, 0, NULL, }, /* Target autonomous HIF_memcpy */ + { /* CE11 */ CE_ATTR_FLAGS, 0, 0, 0, 0, NULL, }, /* Target autonomous HIF_memcpy */ +}; + +static struct CE_pipe_config target_ce_config_wlan_ar9888[] = { + { /* CE0 */ 0, PIPEDIR_OUT, 32, 256, CE_ATTR_FLAGS, 0, }, /* host->target HTC control and raw streams */ + { /* CE1 */ 1, PIPEDIR_IN, 32, 512, CE_ATTR_FLAGS, 0, }, /* target->host HTC control */ + { /* CE2 */ 2, PIPEDIR_IN, 64, 2048, CE_ATTR_FLAGS, 0, }, /* target->host WMI */ + { /* CE3 */ 3, PIPEDIR_OUT, 32, 2048, CE_ATTR_FLAGS, 0, }, /* host->target WMI */ + { /* CE4 */ 4, PIPEDIR_OUT, 256, 256, CE_ATTR_FLAGS, 0, }, /* host->target HTT */ + /* NB: 50% of src nentries, since tx has 2 frags */ +#if WLAN_FEATURE_FASTPATH + { /* CE5 */ 5, PIPEDIR_IN, 32, 512, CE_ATTR_FLAGS, 0, }, /* target->host HTT */ +#else + { /* CE5 */ 5, PIPEDIR_OUT, 32, 2048, CE_ATTR_FLAGS, 0, }, /* unused */ +#endif + { /* CE6 */ 6, PIPEDIR_INOUT, 32, 4096, CE_ATTR_FLAGS, 0, },/* Reserved for target autonomous HIF_memcpy */ + /* CE7 used only by Host */ +}; + +static struct CE_pipe_config target_ce_config_wlan_ar900b[] = { + { /* CE0 */ 0, PIPEDIR_OUT, 32, 256, CE_ATTR_FLAGS, 0, }, /* host->target HTC control and raw streams */ + { /* CE1 */ 1, PIPEDIR_IN, 32, 512, CE_ATTR_FLAGS, 0, }, /* target->host HTC control */ + { /* CE2 */ 2, PIPEDIR_IN, 64, 2048, CE_ATTR_FLAGS, 0, }, /* target->host WMI */ + { /* CE3 */ 3, PIPEDIR_OUT, 32, 2048, CE_ATTR_FLAGS, 0, }, /* host->target WMI */ + { /* CE4 */ 4, PIPEDIR_OUT, 256, 256, CE_ATTR_FLAGS, 0, }, /* host->target HTT */ + /* NB: 50% of src nentries, since tx has 2 frags */ +#if WLAN_FEATURE_FASTPATH + { /* CE5 */ 5, PIPEDIR_IN, 32, 512, CE_ATTR_FLAGS, 0, }, /* target->host HTT */ +#else + { /* CE5 */ 5, PIPEDIR_OUT, 32, 2048, CE_ATTR_FLAGS, 0, }, /* unused */ +#endif + { /* CE6 */ 6, PIPEDIR_INOUT, 32, 4096, CE_ATTR_FLAGS, 0, },/* Reserved for target autonomous HIF_memcpy */ + { /* CE7 */ 7, PIPEDIR_INOUT, 0, 0, 0, 0, }, /* CE7 used only by Host */ + { /* CE8 */ 8, PIPEDIR_IN, 64, 2048, CE_ATTR_FLAGS + | CE_ATTR_DISABLE_INTR, 0, }, /* target->host packtlog */ +#if PEER_CACHEING_HOST_ENABLE + { /* CE9 */ 9, PIPEDIR_INOUT, 32, 2048, CE_ATTR_FLAGS | + CE_ATTR_DISABLE_INTR, 0, }, /* target autonomous qcache memcpy */ +#endif +}; + + + +static struct CE_attr *host_ce_config = host_ce_config_wlan; +static struct CE_pipe_config *target_ce_config = target_ce_config_wlan; +static int target_ce_config_sz = sizeof(target_ce_config_wlan); +#endif /* __HIF_PCI_INTERNAL_H__ */ diff --git a/drivers/staging/qca-wifi-host-cmn/hif/src/ce/ce_bmi.c b/drivers/staging/qca-wifi-host-cmn/hif/src/ce/ce_bmi.c new file mode 100644 index 0000000000000000000000000000000000000000..15fcdcbf5aa27508db8f63ca5795b4a4554ce83e --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/hif/src/ce/ce_bmi.c @@ -0,0 +1,281 @@ +/* + * Copyright (c) 2015-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#include "targcfg.h" +#include "qdf_lock.h" +#include "qdf_status.h" +#include "qdf_status.h" +#include /* qdf_atomic_read */ +#include +#include "hif_io32.h" +#include +#include "regtable.h" +#define ATH_MODULE_NAME hif +#include +#include "hif_main.h" +#include "ce_api.h" +#include "ce_bmi.h" +#include "qdf_trace.h" +#include "hif_debug.h" + +/* Track a BMI transaction that is in progress */ +#ifndef BIT +#define BIT(n) (1 << (n)) +#endif + +enum { + BMI_REQ_SEND_DONE = BIT(0), /* the bmi tx completion */ + BMI_RESP_RECV_DONE = BIT(1), /* the bmi respond is received */ +}; + +struct BMI_transaction { + struct HIF_CE_state *hif_state; + qdf_semaphore_t bmi_transaction_sem; + uint8_t *bmi_request_host; /* Req BMI msg in Host addr space */ + qdf_dma_addr_t bmi_request_CE; /* Req BMI msg in CE addr space */ + uint32_t bmi_request_length; /* Length of BMI request */ + uint8_t *bmi_response_host; /* Rsp BMI msg in Host addr space */ + qdf_dma_addr_t bmi_response_CE; /* Rsp BMI msg in CE addr space */ + unsigned int bmi_response_length; /* Length of received response */ + unsigned int bmi_timeout_ms; + uint32_t bmi_transaction_flags; /* flags for the transcation */ +}; + +/* + * send/recv completion functions for BMI. + * NB: The "net_buf" parameter is actually just a + * straight buffer, not an sk_buff. + */ +void hif_bmi_send_done(struct CE_handle *copyeng, void *ce_context, + void *transfer_context, qdf_dma_addr_t data, + unsigned int nbytes, + unsigned int transfer_id, unsigned int sw_index, + unsigned int hw_index, uint32_t toeplitz_hash_result) +{ + struct BMI_transaction *transaction = + (struct BMI_transaction *)transfer_context; + +#ifdef BMI_RSP_POLLING + /* + * Fix EV118783, Release a semaphore after sending + * no matter whether a response is been expecting now. + */ + qdf_semaphore_release(&transaction->bmi_transaction_sem); +#else + /* + * If a response is anticipated, we'll complete the + * transaction if the response has been received. + * If no response is anticipated, complete the + * transaction now. + */ + transaction->bmi_transaction_flags |= BMI_REQ_SEND_DONE; + + /* resp is't needed or has already been received, + * never assume resp comes later then this */ + if (!transaction->bmi_response_CE || + (transaction->bmi_transaction_flags & BMI_RESP_RECV_DONE)) { + qdf_semaphore_release(&transaction->bmi_transaction_sem); + } +#endif +} + +#ifndef BMI_RSP_POLLING +void hif_bmi_recv_data(struct CE_handle *copyeng, void *ce_context, + void *transfer_context, qdf_dma_addr_t data, + unsigned int nbytes, + unsigned int transfer_id, unsigned int flags) +{ + struct BMI_transaction *transaction = + (struct BMI_transaction *)transfer_context; + + transaction->bmi_response_length = nbytes; + transaction->bmi_transaction_flags |= BMI_RESP_RECV_DONE; + + /* when both send/recv are done, the sem can be released */ + if (transaction->bmi_transaction_flags & BMI_REQ_SEND_DONE) { + qdf_semaphore_release(&transaction->bmi_transaction_sem); + } +} +#endif + +QDF_STATUS hif_exchange_bmi_msg(struct hif_opaque_softc *hif_ctx, + qdf_dma_addr_t bmi_cmd_da, + qdf_dma_addr_t bmi_rsp_da, + uint8_t *bmi_request, + uint32_t request_length, + uint8_t *bmi_response, + uint32_t *bmi_response_lengthp, + uint32_t TimeoutMS) +{ + struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx); + struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(hif_ctx); + struct HIF_CE_pipe_info *send_pipe_info = + &(hif_state->pipe_info[BMI_CE_NUM_TO_TARG]); + struct CE_handle *ce_send_hdl = send_pipe_info->ce_hdl; + qdf_dma_addr_t CE_request, CE_response = 0; + struct BMI_transaction *transaction = NULL; + int status = QDF_STATUS_SUCCESS; + struct HIF_CE_pipe_info *recv_pipe_info = + &(hif_state->pipe_info[BMI_CE_NUM_TO_HOST]); + struct CE_handle *ce_recv = recv_pipe_info->ce_hdl; + unsigned int mux_id = 0; + unsigned int transaction_id = 0xffff; + unsigned int user_flags = 0; +#ifdef BMI_RSP_POLLING + qdf_dma_addr_t buf; + unsigned int completed_nbytes, id, flags; + int i; +#endif + + transaction = + (struct BMI_transaction *)qdf_mem_malloc(sizeof(*transaction)); + if (unlikely(!transaction)) { + HIF_ERROR("%s: no memory", __func__); + return QDF_STATUS_E_NOMEM; + } + transaction_id = (mux_id & MUX_ID_MASK) | + (transaction_id & TRANSACTION_ID_MASK); +#ifdef QCA_WIFI_3_0 + user_flags &= DESC_DATA_FLAG_MASK; +#endif + A_TARGET_ACCESS_LIKELY(scn); + + /* Initialize bmi_transaction_sem to block */ + qdf_semaphore_init(&transaction->bmi_transaction_sem); + qdf_semaphore_acquire(&transaction->bmi_transaction_sem); + + transaction->hif_state = hif_state; + transaction->bmi_request_host = bmi_request; + transaction->bmi_request_length = request_length; + transaction->bmi_response_length = 0; + transaction->bmi_timeout_ms = TimeoutMS; + transaction->bmi_transaction_flags = 0; + + /* + * CE_request = dma_map_single(dev, + * (void *)bmi_request, request_length, DMA_TO_DEVICE); + */ + CE_request = bmi_cmd_da; + transaction->bmi_request_CE = CE_request; + + if (bmi_response) { + + /* + * CE_response = dma_map_single(dev, bmi_response, + * BMI_DATASZ_MAX, DMA_FROM_DEVICE); + */ + CE_response = bmi_rsp_da; + transaction->bmi_response_host = bmi_response; + transaction->bmi_response_CE = CE_response; + /* dma_cache_sync(dev, bmi_response, + BMI_DATASZ_MAX, DMA_FROM_DEVICE); */ + qdf_mem_dma_sync_single_for_device(scn->qdf_dev, + CE_response, + BMI_DATASZ_MAX, + DMA_FROM_DEVICE); + ce_recv_buf_enqueue(ce_recv, transaction, + transaction->bmi_response_CE); + /* NB: see HIF_BMI_recv_done */ + } else { + transaction->bmi_response_host = NULL; + transaction->bmi_response_CE = 0; + } + + /* dma_cache_sync(dev, bmi_request, request_length, DMA_TO_DEVICE); */ + qdf_mem_dma_sync_single_for_device(scn->qdf_dev, CE_request, + request_length, DMA_TO_DEVICE); + + status = + ce_send(ce_send_hdl, transaction, + CE_request, request_length, + transaction_id, 0, user_flags); + ASSERT(status == QDF_STATUS_SUCCESS); + /* NB: see hif_bmi_send_done */ + + /* TBDXXX: handle timeout */ + + /* Wait for BMI request/response transaction to complete */ + /* Always just wait for BMI request here if + * BMI_RSP_POLLING is defined */ + while (qdf_semaphore_acquire + (&transaction->bmi_transaction_sem)) { + /*need some break out condition(time out?) */ + } + + if (bmi_response) { +#ifdef BMI_RSP_POLLING + /* Fix EV118783, do not wait a semaphore for the BMI response + * since the relative interruption may be lost. + * poll the BMI response instead. + */ + i = 0; + while (ce_completed_recv_next( + ce_recv, NULL, NULL, &buf, + &completed_nbytes, &id, + &flags) != QDF_STATUS_SUCCESS) { + if (i++ > BMI_RSP_TO_MILLISEC) { + HIF_ERROR("%s:error, can't get bmi response", + __func__); + status = QDF_STATUS_E_BUSY; + break; + } + OS_DELAY(1000); + } + + if ((status == QDF_STATUS_SUCCESS) && bmi_response_lengthp) + *bmi_response_lengthp = completed_nbytes; +#else + if ((status == QDF_STATUS_SUCCESS) && bmi_response_lengthp) { + *bmi_response_lengthp = + transaction->bmi_response_length; + } +#endif + + } + + /* dma_unmap_single(dev, transaction->bmi_request_CE, + request_length, DMA_TO_DEVICE); */ + /* bus_unmap_single(scn->sc_osdev, + transaction->bmi_request_CE, + request_length, BUS_DMA_TODEVICE); */ + + if (status != QDF_STATUS_SUCCESS) { + qdf_dma_addr_t unused_buffer; + unsigned int unused_nbytes; + unsigned int unused_id; + unsigned int toeplitz_hash_result; + + ce_cancel_send_next(ce_send_hdl, + NULL, NULL, &unused_buffer, + &unused_nbytes, &unused_id, + &toeplitz_hash_result); + } + + A_TARGET_ACCESS_UNLIKELY(scn); + qdf_mem_free(transaction); + return status; +} diff --git a/drivers/staging/qca-wifi-host-cmn/hif/src/ce/ce_bmi.h b/drivers/staging/qca-wifi-host-cmn/hif/src/ce/ce_bmi.h new file mode 100644 index 0000000000000000000000000000000000000000..1fb7c83a97dfdfb967b1fd6178bc3688c492070d --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/hif/src/ce/ce_bmi.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef __CE_BMI_H__ +#define __CE_BMI_H__ + +#include /* qdf_atomic_read */ +#include "qdf_lock.h" +#include "ce_api.h" +#include "cepci.h" + +void hif_bmi_recv_data(struct CE_handle *copyeng, void *ce_context, + void *transfer_context, qdf_dma_addr_t data, + unsigned int nbytes, + unsigned int transfer_id, unsigned int flags); +void hif_bmi_send_done(struct CE_handle *copyeng, void *ce_context, + void *transfer_context, qdf_dma_addr_t data, + unsigned int nbytes, + unsigned int transfer_id, unsigned int sw_index, + unsigned int hw_index, uint32_t toeplitz_hash_result); +#endif /* __CE_BMI_H__ */ diff --git a/drivers/staging/qca-wifi-host-cmn/hif/src/ce/ce_diag.c b/drivers/staging/qca-wifi-host-cmn/hif/src/ce/ce_diag.c new file mode 100644 index 0000000000000000000000000000000000000000..dd6fdf3e1828fb8914d630d92fb8af9b6b690b73 --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/hif/src/ce/ce_diag.c @@ -0,0 +1,519 @@ +/* + * Copyright (c) 2015-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#include "targcfg.h" +#include "qdf_lock.h" +#include "qdf_status.h" +#include "qdf_status.h" +#include /* qdf_atomic_read */ +#include +#include "hif_io32.h" +#include +#include "regtable.h" +#include +#include "hif_main.h" +#include "ce_api.h" +#include "qdf_trace.h" +#include "hif_debug.h" + +void +hif_ce_dump_target_memory(struct hif_softc *scn, void *ramdump_base, + uint32_t address, uint32_t size) +{ + uint32_t loc = address; + uint32_t val = 0; + uint32_t j = 0; + u8 *temp = ramdump_base; + + if (Q_TARGET_ACCESS_BEGIN(scn) < 0) + return; + + while (j < size) { + val = hif_read32_mb(scn->mem + loc + j); + qdf_mem_copy(temp, &val, 4); + j += 4; + temp += 4; + } + + Q_TARGET_ACCESS_END(scn); +} +/* + * TBDXXX: Should be a function call specific to each Target-type. + * This convoluted macro converts from Target CPU Virtual Address + * Space to CE Address Space. As part of this process, we + * conservatively fetch the current PCIE_BAR. MOST of the time, + * this should match the upper bits of PCI space for this device; + * but that's not guaranteed. + */ +#ifdef QCA_WIFI_3_0 +#define TARG_CPU_SPACE_TO_CE_SPACE(pci_addr, addr) \ + (scn->mem_pa + addr) +#else +#define TARG_CPU_SPACE_TO_CE_SPACE(pci_addr, addr) \ + (((hif_read32_mb((pci_addr) + \ + (SOC_CORE_BASE_ADDRESS|CORE_CTRL_ADDRESS)) & 0x7ff) << 21) \ + | 0x100000 | ((addr) & 0xfffff)) +#endif + +#define TARG_CPU_SPACE_TO_CE_SPACE_IPQ4019(pci_addr, addr) \ + (hif_read32_mb((pci_addr)+(WIFICMN_PCIE_BAR_REG_ADDRESS)) \ + | ((addr) & 0xfffff)) + +#define TARG_CPU_SPACE_TO_CE_SPACE_AR900B(pci_addr, addr) \ + (hif_read32_mb((pci_addr)+(WIFICMN_PCIE_BAR_REG_ADDRESS)) \ + | 0x100000 | ((addr) & 0xfffff)) + +#define SRAM_BASE_ADDRESS 0xc0000 +#define SRAM_END_ADDRESS 0x100000 +#define WIFI0_IPQ4019_BAR 0xa000000 +#define WIFI1_IPQ4019_BAR 0xa800000 + +/* Wait up to this many Ms for a Diagnostic Access CE operation to complete */ +#define DIAG_ACCESS_CE_TIMEOUT_MS 10 + +/** + * get_ce_phy_addr() - get the physical address of an soc virtual address + * @sc: hif context + * @address: soc virtual address + * @target_type: target type being used. + * + * Return: soc physical address + */ +static qdf_dma_addr_t get_ce_phy_addr(struct hif_softc *sc, uint32_t address, + unsigned int target_type) +{ + qdf_dma_addr_t ce_phy_addr; + struct hif_softc *scn = sc; + unsigned int region = address & 0xfffff; + unsigned int bar = address & 0xfff00000; + unsigned int sramregion = 0; + + if ((target_type == TARGET_TYPE_IPQ4019) && + (region >= SRAM_BASE_ADDRESS && region <= SRAM_END_ADDRESS) + && (bar == WIFI0_IPQ4019_BAR || + bar == WIFI1_IPQ4019_BAR || bar == 0)) { + sramregion = 1; + } + + if ((target_type == TARGET_TYPE_IPQ4019) && sramregion == 1) { + ce_phy_addr = + TARG_CPU_SPACE_TO_CE_SPACE_IPQ4019(sc->mem, address); + } else if ((target_type == TARGET_TYPE_AR900B) || + (target_type == TARGET_TYPE_QCA9984) || + (target_type == TARGET_TYPE_IPQ4019) || + (target_type == TARGET_TYPE_QCA9888)) { + ce_phy_addr = + TARG_CPU_SPACE_TO_CE_SPACE_AR900B(sc->mem, address); + } else { + ce_phy_addr = + TARG_CPU_SPACE_TO_CE_SPACE(sc->mem, address); + } + + return ce_phy_addr; +} + +/* + * Diagnostic read/write access is provided for startup/config/debug usage. + * Caller must guarantee proper alignment, when applicable, and single user + * at any moment. + */ + +#define FW_SRAM_ADDRESS 0x000C0000 + +QDF_STATUS hif_diag_read_mem(struct hif_opaque_softc *hif_ctx, + uint32_t address, uint8_t *data, int nbytes) +{ + struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx); + + struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(scn); + QDF_STATUS status = QDF_STATUS_SUCCESS; + qdf_dma_addr_t buf; + unsigned int completed_nbytes, orig_nbytes, remaining_bytes; + unsigned int id; + unsigned int flags; + struct CE_handle *ce_diag; + qdf_dma_addr_t CE_data; /* Host buffer address in CE space */ + qdf_dma_addr_t CE_data_base = 0; + void *data_buf = NULL; + int i; + unsigned int mux_id = 0; + unsigned int transaction_id = 0xffff; + qdf_dma_addr_t ce_phy_addr = address; + unsigned int toeplitz_hash_result; + unsigned int user_flags = 0; + unsigned int target_type = 0; + unsigned int boundary_addr = 0; + + transaction_id = (mux_id & MUX_ID_MASK) | + (transaction_id & TRANSACTION_ID_MASK); +#ifdef QCA_WIFI_3_0 + user_flags &= DESC_DATA_FLAG_MASK; +#endif + target_type = (hif_get_target_info_handle(hif_ctx))->target_type; + + /* This code cannot handle reads to non-memory space. Redirect to the + * register read fn but preserve the multi word read capability of + * this fn + */ + if ((target_type == TARGET_TYPE_IPQ4019) || + (target_type == TARGET_TYPE_AR900B) || + (target_type == TARGET_TYPE_QCA9984) || + (target_type == TARGET_TYPE_AR9888) || + (target_type == TARGET_TYPE_QCA9888)) + boundary_addr = FW_SRAM_ADDRESS; + else + boundary_addr = DRAM_BASE_ADDRESS; + + if (address < boundary_addr) { + + if ((address & 0x3) || ((uintptr_t) data & 0x3)) + return QDF_STATUS_E_INVAL; + + while ((nbytes >= 4) && + (QDF_STATUS_SUCCESS == (status = + hif_diag_read_access(hif_ctx, address, + (uint32_t *)data)))) { + + nbytes -= sizeof(uint32_t); + address += sizeof(uint32_t); + data += sizeof(uint32_t); + + } + + return status; + } + ce_diag = hif_state->ce_diag; + + A_TARGET_ACCESS_LIKELY(scn); + + /* + * Allocate a temporary bounce buffer to hold caller's data + * to be DMA'ed from Target. This guarantees + * 1) 4-byte alignment + * 2) Buffer in DMA-able space + */ + orig_nbytes = nbytes; + data_buf = qdf_mem_alloc_consistent(scn->qdf_dev, scn->qdf_dev->dev, + orig_nbytes, &CE_data_base); + if (!data_buf) { + status = QDF_STATUS_E_NOMEM; + goto done; + } + qdf_mem_set(data_buf, orig_nbytes, 0); + qdf_mem_dma_sync_single_for_device(scn->qdf_dev, CE_data_base, + orig_nbytes, DMA_FROM_DEVICE); + + remaining_bytes = orig_nbytes; + CE_data = CE_data_base; + while (remaining_bytes) { + nbytes = min(remaining_bytes, DIAG_TRANSFER_LIMIT); + { + status = ce_recv_buf_enqueue(ce_diag, NULL, CE_data); + if (status != QDF_STATUS_SUCCESS) + goto done; + } + + if (Q_TARGET_ACCESS_BEGIN(scn) < 0) { + status = QDF_STATUS_E_FAILURE; + goto done; + } + + /* convert soc virtual address to physical address */ + ce_phy_addr = get_ce_phy_addr(scn, address, target_type); + + if (Q_TARGET_ACCESS_END(scn) < 0) { + status = QDF_STATUS_E_FAILURE; + goto done; + } + + /* Request CE to send from Target(!) + * address to Host buffer */ + status = ce_send(ce_diag, NULL, ce_phy_addr, nbytes, + transaction_id, 0, user_flags); + if (status != QDF_STATUS_SUCCESS) + goto done; + + i = 0; + while (ce_completed_send_next(ce_diag, NULL, NULL, &buf, + &completed_nbytes, &id, NULL, NULL, + &toeplitz_hash_result) != QDF_STATUS_SUCCESS) { + qdf_mdelay(1); + if (i++ > DIAG_ACCESS_CE_TIMEOUT_MS) { + status = QDF_STATUS_E_BUSY; + goto done; + } + } + if (nbytes != completed_nbytes) { + status = QDF_STATUS_E_FAILURE; + goto done; + } + if (buf != ce_phy_addr) { + status = QDF_STATUS_E_FAILURE; + goto done; + } + + i = 0; + while (ce_completed_recv_next + (ce_diag, NULL, NULL, &buf, + &completed_nbytes, &id, + &flags) != QDF_STATUS_SUCCESS) { + qdf_mdelay(1); + if (i++ > DIAG_ACCESS_CE_TIMEOUT_MS) { + status = QDF_STATUS_E_BUSY; + goto done; + } + } + if (nbytes != completed_nbytes) { + status = QDF_STATUS_E_FAILURE; + goto done; + } + if (buf != CE_data) { + status = QDF_STATUS_E_FAILURE; + goto done; + } + + remaining_bytes -= nbytes; + address += nbytes; + CE_data += nbytes; + } + +done: + A_TARGET_ACCESS_UNLIKELY(scn); + + if (status == QDF_STATUS_SUCCESS) + qdf_mem_copy(data, data_buf, orig_nbytes); + else + HIF_ERROR("%s failure (0x%x)", __func__, address); + + if (data_buf) + qdf_mem_free_consistent(scn->qdf_dev, scn->qdf_dev->dev, + orig_nbytes, data_buf, CE_data_base, 0); + + return status; +} + +/* Read 4-byte aligned data from Target memory or register */ +QDF_STATUS hif_diag_read_access(struct hif_opaque_softc *hif_ctx, + uint32_t address, uint32_t *data) +{ + struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx); + + if (address >= DRAM_BASE_ADDRESS) { + /* Assume range doesn't cross this boundary */ + return hif_diag_read_mem(hif_ctx, address, (uint8_t *) data, + sizeof(uint32_t)); + } else { + if (Q_TARGET_ACCESS_BEGIN(scn) < 0) + return QDF_STATUS_E_FAILURE; + *data = A_TARGET_READ(scn, address); + if (Q_TARGET_ACCESS_END(scn) < 0) + return QDF_STATUS_E_FAILURE; + + return QDF_STATUS_SUCCESS; + } +} + +/** + * hif_diag_write_mem() - write data into the soc memory + * @hif_ctx: hif context + * @address: soc virtual address + * @data: data to copy into the soc address + * @nbytes: number of bytes to coppy + */ +QDF_STATUS hif_diag_write_mem(struct hif_opaque_softc *hif_ctx, + uint32_t address, uint8_t *data, int nbytes) +{ + struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx); + struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(hif_ctx); + QDF_STATUS status = QDF_STATUS_SUCCESS; + qdf_dma_addr_t buf; + unsigned int completed_nbytes, orig_nbytes, remaining_bytes; + unsigned int id; + unsigned int flags; + struct CE_handle *ce_diag; + void *data_buf = NULL; + qdf_dma_addr_t CE_data; /* Host buffer address in CE space */ + qdf_dma_addr_t CE_data_base = 0; + int i; + unsigned int mux_id = 0; + unsigned int transaction_id = 0xffff; + qdf_dma_addr_t ce_phy_addr = address; + unsigned int toeplitz_hash_result; + unsigned int user_flags = 0; + unsigned int target_type = 0; + ce_diag = hif_state->ce_diag; + transaction_id = (mux_id & MUX_ID_MASK) | + (transaction_id & TRANSACTION_ID_MASK); +#ifdef QCA_WIFI_3_0 + user_flags &= DESC_DATA_FLAG_MASK; +#endif + + A_TARGET_ACCESS_LIKELY(scn); + + /* + * Allocate a temporary bounce buffer to hold caller's data + * to be DMA'ed to Target. This guarantees + * 1) 4-byte alignment + * 2) Buffer in DMA-able space + */ + orig_nbytes = nbytes; + data_buf = qdf_mem_alloc_consistent(scn->qdf_dev, scn->qdf_dev->dev, + orig_nbytes, &CE_data_base); + if (!data_buf) { + status = A_NO_MEMORY; + goto done; + } + + /* Copy caller's data to allocated DMA buf */ + qdf_mem_copy(data_buf, data, orig_nbytes); + qdf_mem_dma_sync_single_for_device(scn->qdf_dev, CE_data_base, + orig_nbytes, DMA_TO_DEVICE); + + target_type = (hif_get_target_info_handle(hif_ctx))->target_type; + + if (Q_TARGET_ACCESS_BEGIN(scn) < 0) { + status = QDF_STATUS_E_FAILURE; + goto done; + } + + /* convert soc virtual address to physical address */ + ce_phy_addr = get_ce_phy_addr(scn, address, target_type); + + if (Q_TARGET_ACCESS_END(scn) < 0) { + status = QDF_STATUS_E_FAILURE; + goto done; + } + + remaining_bytes = orig_nbytes; + CE_data = CE_data_base; + while (remaining_bytes) { + nbytes = min(remaining_bytes, DIAG_TRANSFER_LIMIT); + + /* Set up to receive directly into Target(!) address */ + status = ce_recv_buf_enqueue(ce_diag, NULL, ce_phy_addr); + if (status != QDF_STATUS_SUCCESS) + goto done; + + /* + * Request CE to send caller-supplied data that + * was copied to bounce buffer to Target(!) address. + */ + status = ce_send(ce_diag, NULL, (qdf_dma_addr_t) CE_data, + nbytes, transaction_id, 0, user_flags); + + if (status != QDF_STATUS_SUCCESS) + goto done; + + /* poll for transfer complete */ + i = 0; + while (ce_completed_send_next(ce_diag, NULL, NULL, &buf, + &completed_nbytes, &id, + NULL, NULL, &toeplitz_hash_result) != + QDF_STATUS_SUCCESS) { + qdf_mdelay(1); + if (i++ > DIAG_ACCESS_CE_TIMEOUT_MS) { + status = QDF_STATUS_E_BUSY; + goto done; + } + } + + if (nbytes != completed_nbytes) { + status = QDF_STATUS_E_FAILURE; + goto done; + } + + if (buf != CE_data) { + status = QDF_STATUS_E_FAILURE; + goto done; + } + + i = 0; + while (ce_completed_recv_next + (ce_diag, NULL, NULL, &buf, + &completed_nbytes, &id, + &flags) != QDF_STATUS_SUCCESS) { + qdf_mdelay(1); + if (i++ > DIAG_ACCESS_CE_TIMEOUT_MS) { + status = QDF_STATUS_E_BUSY; + goto done; + } + } + + if (nbytes != completed_nbytes) { + status = QDF_STATUS_E_FAILURE; + goto done; + } + + if (buf != ce_phy_addr) { + status = QDF_STATUS_E_FAILURE; + goto done; + } + + remaining_bytes -= nbytes; + address += nbytes; + CE_data += nbytes; + } + +done: + A_TARGET_ACCESS_UNLIKELY(scn); + + if (data_buf) { + qdf_mem_free_consistent(scn->qdf_dev, scn->qdf_dev->dev, + orig_nbytes, data_buf, CE_data_base, 0); + } + + if (status != QDF_STATUS_SUCCESS) { + HIF_ERROR("%s failure (0x%llu)", __func__, + (uint64_t)ce_phy_addr); + } + + return status; +} + +/* Write 4B data to Target memory or register */ +QDF_STATUS hif_diag_write_access(struct hif_opaque_softc *hif_ctx, + uint32_t address, uint32_t data) +{ + struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx); + + if (address >= DRAM_BASE_ADDRESS) { + /* Assume range doesn't cross this boundary */ + uint32_t data_buf = data; + + return hif_diag_write_mem(hif_ctx, address, + (uint8_t *) &data_buf, + sizeof(uint32_t)); + } else { + if (Q_TARGET_ACCESS_BEGIN(scn) < 0) + return QDF_STATUS_E_FAILURE; + A_TARGET_WRITE(scn, address, data); + if (Q_TARGET_ACCESS_END(scn) < 0) + return QDF_STATUS_E_FAILURE; + + return QDF_STATUS_SUCCESS; + } +} diff --git a/drivers/staging/qca-wifi-host-cmn/hif/src/ce/ce_internal.h b/drivers/staging/qca-wifi-host-cmn/hif/src/ce/ce_internal.h new file mode 100644 index 0000000000000000000000000000000000000000..d542da2e1ab284790fb24a2f2ff2b4f9603705b4 --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/hif/src/ce/ce_internal.h @@ -0,0 +1,429 @@ +/* + * Copyright (c) 2013-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ +#ifndef __COPY_ENGINE_INTERNAL_H__ +#define __COPY_ENGINE_INTERNAL_H__ + +#include /* A_TARGET_WRITE */ + +/* Copy Engine operational state */ +enum CE_op_state { + CE_UNUSED, + CE_PAUSED, + CE_RUNNING, + CE_PENDING, +}; + +enum ol_ath_hif_ce_ecodes { + CE_RING_DELTA_FAIL = 0 +}; + +struct CE_src_desc; + +/* Copy Engine Ring internal state */ +struct CE_ring_state { + + /* Number of entries in this ring; must be power of 2 */ + unsigned int nentries; + unsigned int nentries_mask; + + /* + * For dest ring, this is the next index to be processed + * by software after it was/is received into. + * + * For src ring, this is the last descriptor that was sent + * and completion processed by software. + * + * Regardless of src or dest ring, this is an invariant + * (modulo ring size): + * write index >= read index >= sw_index + */ + unsigned int sw_index; + unsigned int write_index; /* cached copy */ + /* + * For src ring, this is the next index not yet processed by HW. + * This is a cached copy of the real HW index (read index), used + * for avoiding reading the HW index register more often than + * necessary. + * This extends the invariant: + * write index >= read index >= hw_index >= sw_index + * + * For dest ring, this is currently unused. + */ + unsigned int hw_index; /* cached copy */ + + /* Start of DMA-coherent area reserved for descriptors */ + void *base_addr_owner_space_unaligned; /* Host address space */ + qdf_dma_addr_t base_addr_CE_space_unaligned; /* CE address space */ + + /* + * Actual start of descriptors. + * Aligned to descriptor-size boundary. + * Points into reserved DMA-coherent area, above. + */ + void *base_addr_owner_space; /* Host address space */ + qdf_dma_addr_t base_addr_CE_space; /* CE address space */ + /* + * Start of shadow copy of descriptors, within regular memory. + * Aligned to descriptor-size boundary. + */ + char *shadow_base_unaligned; + struct CE_src_desc *shadow_base; + + unsigned int low_water_mark_nentries; + unsigned int high_water_mark_nentries; + void **per_transfer_context; + OS_DMA_MEM_CONTEXT(ce_dmacontext) /* OS Specific DMA context */ +}; + +/* Copy Engine internal state */ +struct CE_state { + struct hif_softc *scn; + unsigned int id; + unsigned int attr_flags; /* CE_ATTR_* */ + uint32_t ctrl_addr; /* relative to BAR */ + enum CE_op_state state; + +#ifdef WLAN_FEATURE_FASTPATH + fastpath_msg_handler fastpath_handler; + void *context; +#endif /* WLAN_FEATURE_FASTPATH */ + qdf_work_t oom_allocation_work; + + ce_send_cb send_cb; + void *send_context; + + CE_recv_cb recv_cb; + void *recv_context; + + /* misc_cbs - are any callbacks besides send and recv enabled? */ + uint8_t misc_cbs; + + CE_watermark_cb watermark_cb; + void *wm_context; + + /*Record the state of the copy compl interrupt */ + int disable_copy_compl_intr; + + unsigned int src_sz_max; + struct CE_ring_state *src_ring; + struct CE_ring_state *dest_ring; + atomic_t rx_pending; + + qdf_spinlock_t ce_index_lock; + bool force_break; /* Flag to indicate whether to + * break out the DPC context */ + + /* time in nanoseconds to yield control of napi poll */ + unsigned long long ce_service_yield_time; + unsigned int receive_count; /* count Num Of Receive Buffers + * handled for one interrupt + * DPC routine */ + /* epping */ + bool timer_inited; + qdf_timer_t poll_timer; + + /* datapath - for faster access, use bools instead of a bitmap */ + bool htt_tx_data; + bool htt_rx_data; + void (*lro_flush_cb)(void *); + void *lro_data; +}; + +/* Descriptor rings must be aligned to this boundary */ +#define CE_DESC_RING_ALIGN 8 +#define CLOCK_OVERRIDE 0x2 + +#ifdef QCA_WIFI_3_0 +#define HIF_CE_DESC_ADDR_TO_DMA(desc) \ + (qdf_dma_addr_t)(((uint64_t)(desc)->buffer_addr + \ + ((uint64_t)((desc)->buffer_addr_hi & 0x1F) << 32))) +#else +#define HIF_CE_DESC_ADDR_TO_DMA(desc) \ + (qdf_dma_addr_t)((desc)->buffer_addr) +#endif + +#ifdef QCA_WIFI_3_0 +struct CE_src_desc { + uint32_t buffer_addr:32; +#if _BYTE_ORDER == _BIG_ENDIAN + uint32_t gather:1, + enable_11h:1, + meta_data_low:2, /* fw_metadata_low */ + packet_result_offset:12, + toeplitz_hash_enable:1, + addr_y_search_disable:1, + addr_x_search_disable:1, + misc_int_disable:1, + target_int_disable:1, + host_int_disable:1, + dest_byte_swap:1, + byte_swap:1, + type:2, + tx_classify:1, + buffer_addr_hi:5; + uint32_t meta_data:16, /* fw_metadata_high */ + nbytes:16; /* length in register map */ +#else + uint32_t buffer_addr_hi:5, + tx_classify:1, + type:2, + byte_swap:1, /* src_byte_swap */ + dest_byte_swap:1, + host_int_disable:1, + target_int_disable:1, + misc_int_disable:1, + addr_x_search_disable:1, + addr_y_search_disable:1, + toeplitz_hash_enable:1, + packet_result_offset:12, + meta_data_low:2, /* fw_metadata_low */ + enable_11h:1, + gather:1; + uint32_t nbytes:16, /* length in register map */ + meta_data:16; /* fw_metadata_high */ +#endif + uint32_t toeplitz_hash_result:32; +}; + +struct CE_dest_desc { + uint32_t buffer_addr:32; +#if _BYTE_ORDER == _BIG_ENDIAN + uint32_t gather:1, + enable_11h:1, + meta_data_low:2, /* fw_metadata_low */ + packet_result_offset:12, + toeplitz_hash_enable:1, + addr_y_search_disable:1, + addr_x_search_disable:1, + misc_int_disable:1, + target_int_disable:1, + host_int_disable:1, + byte_swap:1, + src_byte_swap:1, + type:2, + tx_classify:1, + buffer_addr_hi:5; + uint32_t meta_data:16, /* fw_metadata_high */ + nbytes:16; /* length in register map */ +#else + uint32_t buffer_addr_hi:5, + tx_classify:1, + type:2, + src_byte_swap:1, + byte_swap:1, /* dest_byte_swap */ + host_int_disable:1, + target_int_disable:1, + misc_int_disable:1, + addr_x_search_disable:1, + addr_y_search_disable:1, + toeplitz_hash_enable:1, + packet_result_offset:12, + meta_data_low:2, /* fw_metadata_low */ + enable_11h:1, + gather:1; + uint32_t nbytes:16, /* length in register map */ + meta_data:16; /* fw_metadata_high */ +#endif + uint32_t toeplitz_hash_result:32; +}; +#else +struct CE_src_desc { + uint32_t buffer_addr; +#if _BYTE_ORDER == _BIG_ENDIAN + uint32_t meta_data:12, + target_int_disable:1, + host_int_disable:1, + byte_swap:1, + gather:1, + nbytes:16; +#else + + uint32_t nbytes:16, + gather:1, + byte_swap:1, + host_int_disable:1, + target_int_disable:1, + meta_data:12; +#endif +}; + +struct CE_dest_desc { + uint32_t buffer_addr; +#if _BYTE_ORDER == _BIG_ENDIAN + uint32_t meta_data:12, + target_int_disable:1, + host_int_disable:1, + byte_swap:1, + gather:1, + nbytes:16; +#else + uint32_t nbytes:16, + gather:1, + byte_swap:1, + host_int_disable:1, + target_int_disable:1, + meta_data:12; +#endif +}; +#endif /* QCA_WIFI_3_0 */ + +#define CE_SENDLIST_ITEMS_MAX 12 + +/** + * union ce_desc - unified data type for ce descriptors + * + * Both src and destination descriptors follow the same format. + * They use different data structures for different access symantics. + * Here we provice a unifying data type. + */ +union ce_desc { + struct CE_src_desc src_desc; + struct CE_dest_desc dest_desc; +}; + +/** + * enum hif_ce_event_type - HIF copy engine event type + * @HIF_RX_DESC_POST: event recorded before updating write index of RX ring. + * @HIF_RX_DESC_COMPLETION: event recorded before updating sw index of RX ring. + * @HIF_TX_GATHER_DESC_POST: post gather desc. (no write index update) + * @HIF_TX_DESC_POST: event recorded before updating write index of TX ring. + * @HIF_TX_DESC_SOFTWARE_POST: event recorded when dropping a write to the write + * index in a normal tx + * @HIF_TX_DESC_COMPLETION: event recorded before updating sw index of TX ring. + * @FAST_RX_WRITE_INDEX_UPDATE: event recorded before updating the write index + * of the RX ring in fastpath + * @FAST_RX_SOFTWARE_INDEX_UPDATE: event recorded before updating the software + * index of the RX ring in fastpath + * @FAST_TX_WRITE_INDEX_UPDATE: event recorded before updating the write index + * of the TX ring in fastpath + * @FAST_TX_WRITE_INDEX_SOFTWARE_UPDATE: recored when dropping a write to + * the wirte index in fastpath + * @FAST_TX_SOFTWARE_INDEX_UPDATE: event recorded before updating the software + * index of the RX ring in fastpath + * @HIF_IRQ_EVENT: event recorded in the irq before scheduling the bh + * @HIF_CE_TASKLET_ENTRY: records the start of the ce_tasklet + * @HIF_CE_TASKLET_RESCHEDULE: records the rescheduling of the wlan_tasklet + * @HIF_CE_TASKLET_EXIT: records the exit of the wlan tasklet without reschedule + * @HIF_CE_REAP_ENTRY: records when we process completion outside of a bh + * @HIF_CE_REAP_EXIT: records when we process completion outside of a bh + * @NAPI_SCHEDULE: records when napi is scheduled from the irq context + * @NAPI_POLL_ENTER: records the start of the napi poll function + * @NAPI_COMPLETE: records when interrupts are reenabled + * @NAPI_POLL_EXIT: records when the napi poll function returns + */ +enum hif_ce_event_type { + HIF_RX_DESC_POST, + HIF_RX_DESC_COMPLETION, + HIF_TX_GATHER_DESC_POST, + HIF_TX_DESC_POST, + HIF_TX_DESC_SOFTWARE_POST, + HIF_TX_DESC_COMPLETION, + FAST_RX_WRITE_INDEX_UPDATE, + FAST_RX_SOFTWARE_INDEX_UPDATE, + FAST_TX_WRITE_INDEX_UPDATE, + FAST_TX_WRITE_INDEX_SOFTWARE_UPDATE, + FAST_TX_SOFTWARE_INDEX_UPDATE, + RESUME_WRITE_INDEX_UPDATE, + + HIF_IRQ_EVENT = 0x10, + HIF_CE_TASKLET_ENTRY, + HIF_CE_TASKLET_RESCHEDULE, + HIF_CE_TASKLET_EXIT, + HIF_CE_REAP_ENTRY, + HIF_CE_REAP_EXIT, + NAPI_SCHEDULE, + NAPI_POLL_ENTER, + NAPI_COMPLETE, + NAPI_POLL_EXIT, + + HIF_RX_NBUF_ALLOC_FAILURE = 0x20, + HIF_RX_NBUF_MAP_FAILURE, + HIF_RX_NBUF_ENQUEUE_FAILURE, +}; + +void ce_init_ce_desc_event_log(int ce_id, int size); +void hif_record_ce_desc_event(struct hif_softc *scn, int ce_id, + enum hif_ce_event_type type, + union ce_desc *descriptor, void *memory, + int index); + +enum ce_sendlist_type_e { + CE_SIMPLE_BUFFER_TYPE, + /* TBDXXX: CE_RX_DESC_LIST, */ +}; + +/* + * There's a public "ce_sendlist" and a private "ce_sendlist_s". + * The former is an opaque structure with sufficient space + * to hold the latter. The latter is the actual structure + * definition and it is only used internally. The opaque version + * of the structure allows callers to allocate an instance on the + * run-time stack without knowing any of the details of the + * structure layout. + */ +struct ce_sendlist_s { + unsigned int num_items; + struct ce_sendlist_item { + enum ce_sendlist_type_e send_type; + dma_addr_t data; /* e.g. buffer or desc list */ + union { + unsigned int nbytes; /* simple buffer */ + unsigned int ndesc; /* Rx descriptor list */ + } u; + /* flags: externally-specified flags; + * OR-ed with internal flags */ + uint32_t flags; + uint32_t user_flags; + } item[CE_SENDLIST_ITEMS_MAX]; +}; + +bool hif_ce_service_should_yield(struct hif_softc *scn, struct CE_state + *ce_state); + +#ifdef WLAN_FEATURE_FASTPATH +void ce_h2t_tx_ce_cleanup(struct CE_handle *ce_hdl); +void ce_t2h_msg_ce_cleanup(struct CE_handle *ce_hdl); +#else +static inline void ce_h2t_tx_ce_cleanup(struct CE_handle *ce_hdl) +{ +} + +static inline void ce_t2h_msg_ce_cleanup(struct CE_handle *ce_hdl) +{ +} +#endif + +/* which ring of a CE? */ +#define CE_RING_SRC 0 +#define CE_RING_DEST 1 + +#define CDC_WAR_MAGIC_STR 0xceef0000 +#define CDC_WAR_DATA_CE 4 + +/* Additional internal-only ce_send flags */ +#define CE_SEND_FLAG_GATHER 0x00010000 /* Use Gather */ +#endif /* __COPY_ENGINE_INTERNAL_H__ */ diff --git a/drivers/staging/qca-wifi-host-cmn/hif/src/ce/ce_main.c b/drivers/staging/qca-wifi-host-cmn/hif/src/ce/ce_main.c new file mode 100644 index 0000000000000000000000000000000000000000..40aac77696a4abb23125e33098f972c033d303e8 --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/hif/src/ce/ce_main.c @@ -0,0 +1,3088 @@ +/* + * Copyright (c) 2013-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ +#include "targcfg.h" +#include "qdf_lock.h" +#include "qdf_status.h" +#include "qdf_status.h" +#include /* qdf_atomic_read */ +#include +#include "hif_io32.h" +#include +#include "regtable.h" +#define ATH_MODULE_NAME hif +#include +#include "hif_main.h" +#include "ce_api.h" +#include "qdf_trace.h" +#include "pld_common.h" +#include "hif_debug.h" +#include "ce_internal.h" +#include "ce_reg.h" +#include "ce_assignment.h" +#include "ce_tasklet.h" +#ifndef CONFIG_WIN +#include "qwlan_version.h" +#endif + +#define CE_POLL_TIMEOUT 10 /* ms */ + +#define AGC_DUMP 1 +#define CHANINFO_DUMP 2 +#define BB_WATCHDOG_DUMP 3 +#ifdef CONFIG_ATH_PCIE_ACCESS_DEBUG +#define PCIE_ACCESS_DUMP 4 +#endif +#include "mp_dev.h" + +/* Forward references */ +static int hif_post_recv_buffers_for_pipe(struct HIF_CE_pipe_info *pipe_info); + +/* + * Fix EV118783, poll to check whether a BMI response comes + * other than waiting for the interruption which may be lost. + */ +/* #define BMI_RSP_POLLING */ +#define BMI_RSP_TO_MILLISEC 1000 + +#ifdef CONFIG_BYPASS_QMI +#define BYPASS_QMI 1 +#else +#define BYPASS_QMI 0 +#endif + +#ifdef CONFIG_WIN +#define WDI_IPA_SERVICE_GROUP 5 +#define WDI_IPA_TX_SVC MAKE_SERVICE_ID(WDI_IPA_SERVICE_GROUP, 0) +#define HTT_DATA2_MSG_SVC MAKE_SERVICE_ID(HTT_SERVICE_GROUP, 1) +#define HTT_DATA3_MSG_SVC MAKE_SERVICE_ID(HTT_SERVICE_GROUP, 2) +#endif + +static int hif_post_recv_buffers(struct hif_softc *scn); +static void hif_config_rri_on_ddr(struct hif_softc *scn); + +/** + * hif_target_access_log_dump() - dump access log + * + * dump access log + * + * Return: n/a + */ +#ifdef CONFIG_ATH_PCIE_ACCESS_DEBUG +static void hif_target_access_log_dump(void) +{ + hif_target_dump_access_log(); +} +#endif + + +void hif_trigger_dump(struct hif_opaque_softc *hif_ctx, + uint8_t cmd_id, bool start) +{ + struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx); + + switch (cmd_id) { + case AGC_DUMP: + if (start) + priv_start_agc(scn); + else + priv_dump_agc(scn); + break; + case CHANINFO_DUMP: + if (start) + priv_start_cap_chaninfo(scn); + else + priv_dump_chaninfo(scn); + break; + case BB_WATCHDOG_DUMP: + priv_dump_bbwatchdog(scn); + break; +#ifdef CONFIG_ATH_PCIE_ACCESS_DEBUG + case PCIE_ACCESS_DUMP: + hif_target_access_log_dump(); + break; +#endif + default: + HIF_ERROR("%s: Invalid htc dump command", __func__); + break; + } +} + +static void ce_poll_timeout(void *arg) +{ + struct CE_state *CE_state = (struct CE_state *)arg; + if (CE_state->timer_inited) { + ce_per_engine_service(CE_state->scn, CE_state->id); + qdf_timer_mod(&CE_state->poll_timer, CE_POLL_TIMEOUT); + } +} + +static unsigned int roundup_pwr2(unsigned int n) +{ + int i; + unsigned int test_pwr2; + + if (!(n & (n - 1))) + return n; /* already a power of 2 */ + + test_pwr2 = 4; + for (i = 0; i < 29; i++) { + if (test_pwr2 > n) + return test_pwr2; + test_pwr2 = test_pwr2 << 1; + } + + QDF_ASSERT(0); /* n too large */ + return 0; +} + +#define ADRASTEA_SRC_WR_INDEX_OFFSET 0x3C +#define ADRASTEA_DST_WR_INDEX_OFFSET 0x40 + +static struct shadow_reg_cfg target_shadow_reg_cfg_map[] = { + { 0, ADRASTEA_SRC_WR_INDEX_OFFSET}, + { 3, ADRASTEA_SRC_WR_INDEX_OFFSET}, + { 4, ADRASTEA_SRC_WR_INDEX_OFFSET}, + { 5, ADRASTEA_SRC_WR_INDEX_OFFSET}, + { 7, ADRASTEA_SRC_WR_INDEX_OFFSET}, + { 1, ADRASTEA_DST_WR_INDEX_OFFSET}, + { 2, ADRASTEA_DST_WR_INDEX_OFFSET}, + { 7, ADRASTEA_DST_WR_INDEX_OFFSET}, + { 8, ADRASTEA_DST_WR_INDEX_OFFSET}, +#ifdef QCA_WIFI_3_0_ADRASTEA + { 9, ADRASTEA_DST_WR_INDEX_OFFSET}, + { 10, ADRASTEA_DST_WR_INDEX_OFFSET}, + { 11, ADRASTEA_DST_WR_INDEX_OFFSET}, +#endif +}; + +static struct shadow_reg_cfg target_shadow_reg_cfg_epping[] = { + { 0, ADRASTEA_SRC_WR_INDEX_OFFSET}, + { 3, ADRASTEA_SRC_WR_INDEX_OFFSET}, + { 4, ADRASTEA_SRC_WR_INDEX_OFFSET}, + { 7, ADRASTEA_SRC_WR_INDEX_OFFSET}, + { 1, ADRASTEA_DST_WR_INDEX_OFFSET}, + { 2, ADRASTEA_DST_WR_INDEX_OFFSET}, + { 5, ADRASTEA_DST_WR_INDEX_OFFSET}, + { 7, ADRASTEA_DST_WR_INDEX_OFFSET}, + { 8, ADRASTEA_DST_WR_INDEX_OFFSET}, +}; + +/* CE_PCI TABLE */ +/* + * NOTE: the table below is out of date, though still a useful reference. + * Refer to target_service_to_ce_map and hif_map_service_to_pipe for the actual + * mapping of HTC services to HIF pipes. + */ +/* + * This authoritative table defines Copy Engine configuration and the mapping + * of services/endpoints to CEs. A subset of this information is passed to + * the Target during startup as a prerequisite to entering BMI phase. + * See: + * target_service_to_ce_map - Target-side mapping + * hif_map_service_to_pipe - Host-side mapping + * target_ce_config - Target-side configuration + * host_ce_config - Host-side configuration + ============================================================================ + Purpose | Service / Endpoint | CE | Dire | Xfer | Xfer + | | | ctio | Size | Frequency + | | | n | | + ============================================================================ + tx | HTT_DATA (downlink) | CE 0 | h->t | medium - | very frequent + descriptor | | | | O(100B) | and regular + download | | | | | + ---------------------------------------------------------------------------- + rx | HTT_DATA (uplink) | CE 1 | t->h | small - | frequent and + indication | | | | O(10B) | regular + upload | | | | | + ---------------------------------------------------------------------------- + MSDU | DATA_BK (uplink) | CE 2 | t->h | large - | rare + upload | | | | O(1000B) | (frequent + e.g. noise | | | | | during IP1.0 + packets | | | | | testing) + ---------------------------------------------------------------------------- + MSDU | DATA_BK (downlink) | CE 3 | h->t | large - | very rare + download | | | | O(1000B) | (frequent + e.g. | | | | | during IP1.0 + misdirecte | | | | | testing) + d EAPOL | | | | | + packets | | | | | + ---------------------------------------------------------------------------- + n/a | DATA_BE, DATA_VI | CE 2 | t->h | | never(?) + | DATA_VO (uplink) | | | | + ---------------------------------------------------------------------------- + n/a | DATA_BE, DATA_VI | CE 3 | h->t | | never(?) + | DATA_VO (downlink) | | | | + ---------------------------------------------------------------------------- + WMI events | WMI_CONTROL (uplink) | CE 4 | t->h | medium - | infrequent + | | | | O(100B) | + ---------------------------------------------------------------------------- + WMI | WMI_CONTROL | CE 5 | h->t | medium - | infrequent + messages | (downlink) | | | O(100B) | + | | | | | + ---------------------------------------------------------------------------- + n/a | HTC_CTRL_RSVD, | CE 1 | t->h | | never(?) + | HTC_RAW_STREAMS | | | | + | (uplink) | | | | + ---------------------------------------------------------------------------- + n/a | HTC_CTRL_RSVD, | CE 0 | h->t | | never(?) + | HTC_RAW_STREAMS | | | | + | (downlink) | | | | + ---------------------------------------------------------------------------- + diag | none (raw CE) | CE 7 | t<>h | 4 | Diag Window + | | | | | infrequent + ============================================================================ + */ + +/* + * Map from service/endpoint to Copy Engine. + * This table is derived from the CE_PCI TABLE, above. + * It is passed to the Target at startup for use by firmware. + */ +static struct service_to_pipe target_service_to_ce_map_wlan[] = { + { + WMI_DATA_VO_SVC, + PIPEDIR_OUT, /* out = UL = host -> target */ + 3, + }, + { + WMI_DATA_VO_SVC, + PIPEDIR_IN, /* in = DL = target -> host */ + 2, + }, + { + WMI_DATA_BK_SVC, + PIPEDIR_OUT, /* out = UL = host -> target */ + 3, + }, + { + WMI_DATA_BK_SVC, + PIPEDIR_IN, /* in = DL = target -> host */ + 2, + }, + { + WMI_DATA_BE_SVC, + PIPEDIR_OUT, /* out = UL = host -> target */ + 3, + }, + { + WMI_DATA_BE_SVC, + PIPEDIR_IN, /* in = DL = target -> host */ + 2, + }, + { + WMI_DATA_VI_SVC, + PIPEDIR_OUT, /* out = UL = host -> target */ + 3, + }, + { + WMI_DATA_VI_SVC, + PIPEDIR_IN, /* in = DL = target -> host */ + 2, + }, + { + WMI_CONTROL_SVC, + PIPEDIR_OUT, /* out = UL = host -> target */ + 3, + }, + { + WMI_CONTROL_SVC, + PIPEDIR_IN, /* in = DL = target -> host */ + 2, + }, + { + HTC_CTRL_RSVD_SVC, + PIPEDIR_OUT, /* out = UL = host -> target */ + 0, /* could be moved to 3 (share with WMI) */ + }, + { + HTC_CTRL_RSVD_SVC, + PIPEDIR_IN, /* in = DL = target -> host */ + 2, + }, + { + HTC_RAW_STREAMS_SVC, /* not currently used */ + PIPEDIR_OUT, /* out = UL = host -> target */ + 0, + }, + { + HTC_RAW_STREAMS_SVC, /* not currently used */ + PIPEDIR_IN, /* in = DL = target -> host */ + 2, + }, + { + HTT_DATA_MSG_SVC, + PIPEDIR_OUT, /* out = UL = host -> target */ + 4, + }, + { + HTT_DATA_MSG_SVC, + PIPEDIR_IN, /* in = DL = target -> host */ + 1, + }, + { + WDI_IPA_TX_SVC, + PIPEDIR_OUT, /* in = DL = target -> host */ + 5, + }, +#if defined(QCA_WIFI_3_0_ADRASTEA) + { + HTT_DATA2_MSG_SVC, + PIPEDIR_IN, /* in = DL = target -> host */ + 9, + }, + { + HTT_DATA3_MSG_SVC, + PIPEDIR_IN, /* in = DL = target -> host */ + 10, + }, + { + PACKET_LOG_SVC, + PIPEDIR_IN, /* in = DL = target -> host */ + 11, + }, +#endif + /* (Additions here) */ + + { /* Must be last */ + 0, + 0, + 0, + }, +}; + +static struct service_to_pipe target_service_to_ce_map_ar900b[] = { + { + WMI_DATA_VO_SVC, + PIPEDIR_OUT, /* out = UL = host -> target */ + 3, + }, + { + WMI_DATA_VO_SVC, + PIPEDIR_IN, /* in = DL = target -> host */ + 2, + }, + { + WMI_DATA_BK_SVC, + PIPEDIR_OUT, /* out = UL = host -> target */ + 3, + }, + { + WMI_DATA_BK_SVC, + PIPEDIR_IN, /* in = DL = target -> host */ + 2, + }, + { + WMI_DATA_BE_SVC, + PIPEDIR_OUT, /* out = UL = host -> target */ + 3, + }, + { + WMI_DATA_BE_SVC, + PIPEDIR_IN, /* in = DL = target -> host */ + 2, + }, + { + WMI_DATA_VI_SVC, + PIPEDIR_OUT, /* out = UL = host -> target */ + 3, + }, + { + WMI_DATA_VI_SVC, + PIPEDIR_IN, /* in = DL = target -> host */ + 2, + }, + { + WMI_CONTROL_SVC, + PIPEDIR_OUT, /* out = UL = host -> target */ + 3, + }, + { + WMI_CONTROL_SVC, + PIPEDIR_IN, /* in = DL = target -> host */ + 2, + }, + { + HTC_CTRL_RSVD_SVC, + PIPEDIR_OUT, /* out = UL = host -> target */ + 0, /* could be moved to 3 (share with WMI) */ + }, + { + HTC_CTRL_RSVD_SVC, + PIPEDIR_IN, /* in = DL = target -> host */ + 1, + }, + { + HTC_RAW_STREAMS_SVC, /* not currently used */ + PIPEDIR_OUT, /* out = UL = host -> target */ + 0, + }, + { + HTC_RAW_STREAMS_SVC, /* not currently used */ + PIPEDIR_IN, /* in = DL = target -> host */ + 1, + }, + { + HTT_DATA_MSG_SVC, + PIPEDIR_OUT, /* out = UL = host -> target */ + 4, + }, +#if WLAN_FEATURE_FASTPATH + { + HTT_DATA_MSG_SVC, + PIPEDIR_IN, /* in = DL = target -> host */ + 5, + }, +#else /* WLAN_FEATURE_FASTPATH */ + { + HTT_DATA_MSG_SVC, + PIPEDIR_IN, /* in = DL = target -> host */ + 1, + }, +#endif /* WLAN_FEATURE_FASTPATH */ + + /* (Additions here) */ + + { /* Must be last */ + 0, + 0, + 0, + }, +}; + + +static struct service_to_pipe *target_service_to_ce_map = + target_service_to_ce_map_wlan; +static int target_service_to_ce_map_sz = sizeof(target_service_to_ce_map_wlan); + +static struct shadow_reg_cfg *target_shadow_reg_cfg = target_shadow_reg_cfg_map; +static int shadow_cfg_sz = sizeof(target_shadow_reg_cfg_map); + +static struct service_to_pipe target_service_to_ce_map_wlan_epping[] = { + {WMI_DATA_VO_SVC, PIPEDIR_OUT, 3,}, /* out = UL = host -> target */ + {WMI_DATA_VO_SVC, PIPEDIR_IN, 2,}, /* in = DL = target -> host */ + {WMI_DATA_BK_SVC, PIPEDIR_OUT, 4,}, /* out = UL = host -> target */ + {WMI_DATA_BK_SVC, PIPEDIR_IN, 1,}, /* in = DL = target -> host */ + {WMI_DATA_BE_SVC, PIPEDIR_OUT, 3,}, /* out = UL = host -> target */ + {WMI_DATA_BE_SVC, PIPEDIR_IN, 2,}, /* in = DL = target -> host */ + {WMI_DATA_VI_SVC, PIPEDIR_OUT, 3,}, /* out = UL = host -> target */ + {WMI_DATA_VI_SVC, PIPEDIR_IN, 2,}, /* in = DL = target -> host */ + {WMI_CONTROL_SVC, PIPEDIR_OUT, 3,}, /* out = UL = host -> target */ + {WMI_CONTROL_SVC, PIPEDIR_IN, 2,}, /* in = DL = target -> host */ + {HTC_CTRL_RSVD_SVC, PIPEDIR_OUT, 0,}, /* out = UL = host -> target */ + {HTC_CTRL_RSVD_SVC, PIPEDIR_IN, 2,}, /* in = DL = target -> host */ + {HTC_RAW_STREAMS_SVC, PIPEDIR_OUT, 0,}, /* out = UL = host -> target */ + {HTC_RAW_STREAMS_SVC, PIPEDIR_IN, 2,}, /* in = DL = target -> host */ + {HTT_DATA_MSG_SVC, PIPEDIR_OUT, 4,}, /* out = UL = host -> target */ + {HTT_DATA_MSG_SVC, PIPEDIR_IN, 1,}, /* in = DL = target -> host */ + {0, 0, 0,}, /* Must be last */ +}; + +/** + * ce_mark_datapath() - marks the ce_state->htt_rx_data accordingly + * @ce_state : pointer to the state context of the CE + * + * Description: + * Sets htt_rx_data attribute of the state structure if the + * CE serves one of the HTT DATA services. + * + * Return: + * false (attribute set to false) + * true (attribute set to true); + */ +static bool ce_mark_datapath(struct CE_state *ce_state) +{ + struct service_to_pipe *svc_map; + size_t map_sz; + int i; + bool rc = false; + struct hif_target_info *tgt_info; + + if (ce_state != NULL) { + tgt_info = &ce_state->scn->target_info; + + if (QDF_IS_EPPING_ENABLED(hif_get_conparam(ce_state->scn))) { + svc_map = target_service_to_ce_map_wlan_epping; + map_sz = sizeof(target_service_to_ce_map_wlan_epping) / + sizeof(struct service_to_pipe); + } else { + switch (tgt_info->target_type) { + default: + svc_map = target_service_to_ce_map_wlan; + map_sz = + sizeof(target_service_to_ce_map_wlan) / + sizeof(struct service_to_pipe); + break; + case TARGET_TYPE_AR900B: + case TARGET_TYPE_QCA9984: + case TARGET_TYPE_IPQ4019: + case TARGET_TYPE_QCA9888: + case TARGET_TYPE_AR9888: + case TARGET_TYPE_AR9888V2: + svc_map = target_service_to_ce_map_ar900b; + map_sz = + sizeof(target_service_to_ce_map_ar900b) + / sizeof(struct service_to_pipe); + break; + } + } + for (i = 0; i < map_sz; i++) { + if ((svc_map[i].pipenum == ce_state->id) && + ((svc_map[i].service_id == HTT_DATA_MSG_SVC) || + (svc_map[i].service_id == HTT_DATA2_MSG_SVC) || + (svc_map[i].service_id == HTT_DATA3_MSG_SVC))) { + /* HTT CEs are unidirectional */ + if (svc_map[i].pipedir == PIPEDIR_IN) + ce_state->htt_rx_data = true; + else + ce_state->htt_tx_data = true; + rc = true; + } + } + } + return rc; +} + +/** + * ce_ring_test_initial_indexes() - tests the initial ce ring indexes + * @ce_id: ce in question + * @ring: ring state being examined + * @type: "src_ring" or "dest_ring" string for identifying the ring + * + * Warns on non-zero index values. + * Causes a kernel panic if the ring is not empty durring initialization. + */ +static void ce_ring_test_initial_indexes(int ce_id, struct CE_ring_state *ring, + char *type) +{ + if (ring->write_index != 0 || ring->sw_index != 0) + HIF_ERROR("ce %d, %s, initial sw_index = %d, initial write_index =%d", + ce_id, type, ring->sw_index, ring->write_index); + if (ring->write_index != ring->sw_index) + QDF_BUG(0); +} + +int hif_ce_bus_early_suspend(struct hif_softc *scn) +{ + uint8_t ul_pipe, dl_pipe; + int ce_id, status, ul_is_polled, dl_is_polled; + struct CE_state *ce_state; + status = hif_map_service_to_pipe(&scn->osc, WMI_CONTROL_SVC, + &ul_pipe, &dl_pipe, + &ul_is_polled, &dl_is_polled); + if (status) { + HIF_ERROR("%s: pipe_mapping failure", __func__); + return status; + } + + for (ce_id = 0; ce_id < scn->ce_count; ce_id++) { + if (ce_id == ul_pipe) + continue; + if (ce_id == dl_pipe) + continue; + + ce_state = scn->ce_id_to_state[ce_id]; + qdf_spin_lock_bh(&ce_state->ce_index_lock); + if (ce_state->state == CE_RUNNING) + ce_state->state = CE_PAUSED; + qdf_spin_unlock_bh(&ce_state->ce_index_lock); + } + + return status; +} + +int hif_ce_bus_late_resume(struct hif_softc *scn) +{ + int ce_id; + struct CE_state *ce_state; + int write_index; + bool index_updated; + + for (ce_id = 0; ce_id < scn->ce_count; ce_id++) { + ce_state = scn->ce_id_to_state[ce_id]; + qdf_spin_lock_bh(&ce_state->ce_index_lock); + if (ce_state->state == CE_PENDING) { + write_index = ce_state->src_ring->write_index; + CE_SRC_RING_WRITE_IDX_SET(scn, ce_state->ctrl_addr, + write_index); + ce_state->state = CE_RUNNING; + index_updated = true; + } else { + index_updated = false; + } + + if (ce_state->state == CE_PAUSED) + ce_state->state = CE_RUNNING; + qdf_spin_unlock_bh(&ce_state->ce_index_lock); + + if (index_updated) + hif_record_ce_desc_event(scn, ce_id, + RESUME_WRITE_INDEX_UPDATE, + NULL, NULL, write_index); + } + + return 0; +} + +/** + * ce_oom_recovery() - try to recover rx ce from oom condition + * @context: CE_state of the CE with oom rx ring + * + * the executing work Will continue to be rescheduled untill + * at least 1 descriptor is successfully posted to the rx ring. + * + * return: none + */ +static void ce_oom_recovery(void *context) +{ + struct CE_state *ce_state = context; + struct hif_softc *scn = ce_state->scn; + struct HIF_CE_state *ce_softc = HIF_GET_CE_STATE(scn); + struct HIF_CE_pipe_info *pipe_info = + &ce_softc->pipe_info[ce_state->id]; + + hif_post_recv_buffers_for_pipe(pipe_info); +} + +/* + * Initialize a Copy Engine based on caller-supplied attributes. + * This may be called once to initialize both source and destination + * rings or it may be called twice for separate source and destination + * initialization. It may be that only one side or the other is + * initialized by software/firmware. + * + * This should be called durring the initialization sequence before + * interupts are enabled, so we don't have to worry about thread safety. + */ +struct CE_handle *ce_init(struct hif_softc *scn, + unsigned int CE_id, struct CE_attr *attr) +{ + struct CE_state *CE_state; + uint32_t ctrl_addr; + unsigned int nentries; + qdf_dma_addr_t base_addr; + bool malloc_CE_state = false; + bool malloc_src_ring = false; + + QDF_ASSERT(CE_id < scn->ce_count); + ctrl_addr = CE_BASE_ADDRESS(CE_id); + CE_state = scn->ce_id_to_state[CE_id]; + + if (!CE_state) { + CE_state = + (struct CE_state *)qdf_mem_malloc(sizeof(*CE_state)); + if (!CE_state) { + HIF_ERROR("%s: CE_state has no mem", __func__); + return NULL; + } + malloc_CE_state = true; + scn->ce_id_to_state[CE_id] = CE_state; + qdf_spinlock_create(&CE_state->ce_index_lock); + + CE_state->id = CE_id; + CE_state->ctrl_addr = ctrl_addr; + CE_state->state = CE_RUNNING; + CE_state->attr_flags = attr->flags; + } + CE_state->scn = scn; + + qdf_atomic_init(&CE_state->rx_pending); + if (attr == NULL) { + /* Already initialized; caller wants the handle */ + return (struct CE_handle *)CE_state; + } + + if (CE_state->src_sz_max) + QDF_ASSERT(CE_state->src_sz_max == attr->src_sz_max); + else + CE_state->src_sz_max = attr->src_sz_max; + + ce_init_ce_desc_event_log(CE_id, + attr->src_nentries + attr->dest_nentries); + + /* source ring setup */ + nentries = attr->src_nentries; + if (nentries) { + struct CE_ring_state *src_ring; + unsigned CE_nbytes; + char *ptr; + uint64_t dma_addr; + nentries = roundup_pwr2(nentries); + if (CE_state->src_ring) { + QDF_ASSERT(CE_state->src_ring->nentries == nentries); + } else { + CE_nbytes = sizeof(struct CE_ring_state) + + (nentries * sizeof(void *)); + ptr = qdf_mem_malloc(CE_nbytes); + if (!ptr) { + /* cannot allocate src ring. If the + * CE_state is allocated locally free + * CE_State and return error. + */ + HIF_ERROR("%s: src ring has no mem", __func__); + if (malloc_CE_state) { + /* allocated CE_state locally */ + scn->ce_id_to_state[CE_id] = NULL; + qdf_mem_free(CE_state); + malloc_CE_state = false; + } + return NULL; + } else { + /* we can allocate src ring. + * Mark that the src ring is + * allocated locally + */ + malloc_src_ring = true; + } + + src_ring = CE_state->src_ring = + (struct CE_ring_state *)ptr; + ptr += sizeof(struct CE_ring_state); + src_ring->nentries = nentries; + src_ring->nentries_mask = nentries - 1; + if (Q_TARGET_ACCESS_BEGIN(scn) < 0) + goto error_target_access; + src_ring->hw_index = + CE_SRC_RING_READ_IDX_GET_FROM_REGISTER(scn, + ctrl_addr); + src_ring->sw_index = src_ring->hw_index; + src_ring->write_index = + CE_SRC_RING_WRITE_IDX_GET_FROM_REGISTER(scn, + ctrl_addr); + + ce_ring_test_initial_indexes(CE_id, src_ring, + "src_ring"); + + if (Q_TARGET_ACCESS_END(scn) < 0) + goto error_target_access; + + src_ring->low_water_mark_nentries = 0; + src_ring->high_water_mark_nentries = nentries; + src_ring->per_transfer_context = (void **)ptr; + + /* Legacy platforms that do not support cache + * coherent DMA are unsupported + */ + src_ring->base_addr_owner_space_unaligned = + qdf_mem_alloc_consistent(scn->qdf_dev, + scn->qdf_dev->dev, + (nentries * + sizeof(struct CE_src_desc) + + CE_DESC_RING_ALIGN), + &base_addr); + if (src_ring->base_addr_owner_space_unaligned + == NULL) { + HIF_ERROR("%s: src ring has no DMA mem", + __func__); + goto error_no_dma_mem; + } + src_ring->base_addr_CE_space_unaligned = base_addr; + + if (src_ring-> + base_addr_CE_space_unaligned & (CE_DESC_RING_ALIGN + - 1)) { + src_ring->base_addr_CE_space = + (src_ring->base_addr_CE_space_unaligned + + CE_DESC_RING_ALIGN - + 1) & ~(CE_DESC_RING_ALIGN - 1); + + src_ring->base_addr_owner_space = + (void + *)(((size_t) src_ring-> + base_addr_owner_space_unaligned + + CE_DESC_RING_ALIGN - + 1) & ~(CE_DESC_RING_ALIGN - 1)); + } else { + src_ring->base_addr_CE_space = + src_ring->base_addr_CE_space_unaligned; + src_ring->base_addr_owner_space = + src_ring-> + base_addr_owner_space_unaligned; + } + /* + * Also allocate a shadow src ring in + * regular mem to use for faster access. + */ + src_ring->shadow_base_unaligned = + qdf_mem_malloc(nentries * + sizeof(struct CE_src_desc) + + CE_DESC_RING_ALIGN); + if (src_ring->shadow_base_unaligned == NULL) { + HIF_ERROR("%s: src ring no shadow_base mem", + __func__); + goto error_no_dma_mem; + } + src_ring->shadow_base = (struct CE_src_desc *) + (((size_t) src_ring->shadow_base_unaligned + + CE_DESC_RING_ALIGN - 1) & + ~(CE_DESC_RING_ALIGN - 1)); + + if (Q_TARGET_ACCESS_BEGIN(scn) < 0) + goto error_target_access; + dma_addr = src_ring->base_addr_CE_space; + CE_SRC_RING_BASE_ADDR_SET(scn, ctrl_addr, + (uint32_t)(dma_addr & 0xFFFFFFFF)); + + /* if SR_BA_ADDRESS_HIGH register exists */ + if (is_register_supported(SR_BA_ADDRESS_HIGH)) { + uint32_t tmp; + tmp = CE_SRC_RING_BASE_ADDR_HIGH_GET( + scn, ctrl_addr); + tmp &= ~0x1F; + dma_addr = ((dma_addr >> 32) & 0x1F)|tmp; + CE_SRC_RING_BASE_ADDR_HIGH_SET(scn, + ctrl_addr, (uint32_t)dma_addr); + } + CE_SRC_RING_SZ_SET(scn, ctrl_addr, nentries); + CE_SRC_RING_DMAX_SET(scn, ctrl_addr, attr->src_sz_max); +#ifdef BIG_ENDIAN_HOST + /* Enable source ring byte swap for big endian host */ + CE_SRC_RING_BYTE_SWAP_SET(scn, ctrl_addr, 1); +#endif + CE_SRC_RING_LOWMARK_SET(scn, ctrl_addr, 0); + CE_SRC_RING_HIGHMARK_SET(scn, ctrl_addr, nentries); + if (Q_TARGET_ACCESS_END(scn) < 0) + goto error_target_access; + } + } + + /* destination ring setup */ + nentries = attr->dest_nentries; + if (nentries) { + struct CE_ring_state *dest_ring; + unsigned CE_nbytes; + char *ptr; + uint64_t dma_addr; + + nentries = roundup_pwr2(nentries); + if (CE_state->dest_ring) { + QDF_ASSERT(CE_state->dest_ring->nentries == nentries); + } else { + CE_nbytes = sizeof(struct CE_ring_state) + + (nentries * sizeof(void *)); + ptr = qdf_mem_malloc(CE_nbytes); + if (!ptr) { + /* cannot allocate dst ring. If the CE_state + * or src ring is allocated locally free + * CE_State and src ring and return error. + */ + HIF_ERROR("%s: dest ring has no mem", + __func__); + goto error_no_dma_mem; + } + + dest_ring = CE_state->dest_ring = + (struct CE_ring_state *)ptr; + ptr += sizeof(struct CE_ring_state); + dest_ring->nentries = nentries; + dest_ring->nentries_mask = nentries - 1; + if (Q_TARGET_ACCESS_BEGIN(scn) < 0) + goto error_target_access; + dest_ring->sw_index = + CE_DEST_RING_READ_IDX_GET_FROM_REGISTER(scn, + ctrl_addr); + dest_ring->write_index = + CE_DEST_RING_WRITE_IDX_GET_FROM_REGISTER(scn, + ctrl_addr); + + ce_ring_test_initial_indexes(CE_id, dest_ring, + "dest_ring"); + + if (Q_TARGET_ACCESS_END(scn) < 0) + goto error_target_access; + + dest_ring->low_water_mark_nentries = 0; + dest_ring->high_water_mark_nentries = nentries; + dest_ring->per_transfer_context = (void **)ptr; + + /* Legacy platforms that do not support cache + * coherent DMA are unsupported */ + dest_ring->base_addr_owner_space_unaligned = + qdf_mem_alloc_consistent(scn->qdf_dev, + scn->qdf_dev->dev, + (nentries * + sizeof(struct CE_dest_desc) + + CE_DESC_RING_ALIGN), + &base_addr); + if (dest_ring->base_addr_owner_space_unaligned + == NULL) { + HIF_ERROR("%s: dest ring has no DMA mem", + __func__); + goto error_no_dma_mem; + } + dest_ring->base_addr_CE_space_unaligned = base_addr; + + /* Correctly initialize memory to 0 to + * prevent garbage data crashing system + * when download firmware + */ + qdf_mem_zero(dest_ring->base_addr_owner_space_unaligned, + nentries * sizeof(struct CE_dest_desc) + + CE_DESC_RING_ALIGN); + + if (dest_ring-> + base_addr_CE_space_unaligned & (CE_DESC_RING_ALIGN - + 1)) { + + dest_ring->base_addr_CE_space = + (dest_ring-> + base_addr_CE_space_unaligned + + CE_DESC_RING_ALIGN - + 1) & ~(CE_DESC_RING_ALIGN - 1); + + dest_ring->base_addr_owner_space = + (void + *)(((size_t) dest_ring-> + base_addr_owner_space_unaligned + + CE_DESC_RING_ALIGN - + 1) & ~(CE_DESC_RING_ALIGN - 1)); + } else { + dest_ring->base_addr_CE_space = + dest_ring->base_addr_CE_space_unaligned; + dest_ring->base_addr_owner_space = + dest_ring-> + base_addr_owner_space_unaligned; + } + + if (Q_TARGET_ACCESS_BEGIN(scn) < 0) + goto error_target_access; + dma_addr = dest_ring->base_addr_CE_space; + CE_DEST_RING_BASE_ADDR_SET(scn, ctrl_addr, + (uint32_t)(dma_addr & 0xFFFFFFFF)); + + /* if DR_BA_ADDRESS_HIGH exists */ + if (is_register_supported(DR_BA_ADDRESS_HIGH)) { + uint32_t tmp; + tmp = CE_DEST_RING_BASE_ADDR_HIGH_GET(scn, + ctrl_addr); + tmp &= ~0x1F; + dma_addr = ((dma_addr >> 32) & 0x1F)|tmp; + CE_DEST_RING_BASE_ADDR_HIGH_SET(scn, + ctrl_addr, (uint32_t)dma_addr); + } + + CE_DEST_RING_SZ_SET(scn, ctrl_addr, nentries); +#ifdef BIG_ENDIAN_HOST + /* Enable Dest ring byte swap for big endian host */ + CE_DEST_RING_BYTE_SWAP_SET(scn, ctrl_addr, 1); +#endif + CE_DEST_RING_LOWMARK_SET(scn, ctrl_addr, 0); + CE_DEST_RING_HIGHMARK_SET(scn, ctrl_addr, nentries); + if (Q_TARGET_ACCESS_END(scn) < 0) + goto error_target_access; + + /* epping */ + /* poll timer */ + if ((CE_state->attr_flags & CE_ATTR_ENABLE_POLL)) { + qdf_timer_init(scn->qdf_dev, + &CE_state->poll_timer, + ce_poll_timeout, + CE_state, + QDF_TIMER_TYPE_SW); + CE_state->timer_inited = true; + qdf_timer_mod(&CE_state->poll_timer, + CE_POLL_TIMEOUT); + } + } + } + + /* Enable CE error interrupts */ + if (Q_TARGET_ACCESS_BEGIN(scn) < 0) + goto error_target_access; + CE_ERROR_INTR_ENABLE(scn, ctrl_addr); + if (Q_TARGET_ACCESS_END(scn) < 0) + goto error_target_access; + + qdf_create_work(scn->qdf_dev, &CE_state->oom_allocation_work, + ce_oom_recovery, CE_state); + + /* update the htt_data attribute */ + ce_mark_datapath(CE_state); + + return (struct CE_handle *)CE_state; + +error_target_access: +error_no_dma_mem: + ce_fini((struct CE_handle *)CE_state); + return NULL; +} + +#ifdef WLAN_FEATURE_FASTPATH +/** + * hif_enable_fastpath() Update that we have enabled fastpath mode + * @hif_ctx: HIF context + * + * For use in data path + * + * Retrun: void + */ +void hif_enable_fastpath(struct hif_opaque_softc *hif_ctx) +{ + struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx); + + HIF_INFO("%s, Enabling fastpath mode", __func__); + scn->fastpath_mode_on = true; +} + +/** + * hif_is_fastpath_mode_enabled - API to query if fasthpath mode is enabled + * @hif_ctx: HIF Context + * + * For use in data path to skip HTC + * + * Return: bool + */ +bool hif_is_fastpath_mode_enabled(struct hif_opaque_softc *hif_ctx) +{ + struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx); + + return scn->fastpath_mode_on; +} + +/** + * hif_get_ce_handle - API to get CE handle for FastPath mode + * @hif_ctx: HIF Context + * @id: CopyEngine Id + * + * API to return CE handle for fastpath mode + * + * Return: void + */ +void *hif_get_ce_handle(struct hif_opaque_softc *hif_ctx, int id) +{ + struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx); + + return scn->ce_id_to_state[id]; +} + +/** + * ce_h2t_tx_ce_cleanup() Place holder function for H2T CE cleanup. + * No processing is required inside this function. + * @ce_hdl: Cope engine handle + * Using an assert, this function makes sure that, + * the TX CE has been processed completely. + * + * This is called while dismantling CE structures. No other thread + * should be using these structures while dismantling is occuring + * therfore no locking is needed. + * + * Return: none + */ +void +ce_h2t_tx_ce_cleanup(struct CE_handle *ce_hdl) +{ + struct CE_state *ce_state = (struct CE_state *)ce_hdl; + struct CE_ring_state *src_ring = ce_state->src_ring; + struct hif_softc *sc = ce_state->scn; + uint32_t sw_index, write_index; + if (hif_is_nss_wifi_enabled(sc)) + return; + + if (sc->fastpath_mode_on && ce_state->htt_tx_data) { + HIF_INFO("%s %d Fastpath mode ON, Cleaning up HTT Tx CE", + __func__, __LINE__); + sw_index = src_ring->sw_index; + write_index = src_ring->sw_index; + + /* At this point Tx CE should be clean */ + qdf_assert_always(sw_index == write_index); + } +} + +/** + * ce_t2h_msg_ce_cleanup() - Cleanup buffers on the t2h datapath msg queue. + * @ce_hdl: Handle to CE + * + * These buffers are never allocated on the fly, but + * are allocated only once during HIF start and freed + * only once during HIF stop. + * NOTE: + * The assumption here is there is no in-flight DMA in progress + * currently, so that buffers can be freed up safely. + * + * Return: NONE + */ +void ce_t2h_msg_ce_cleanup(struct CE_handle *ce_hdl) +{ + struct CE_state *ce_state = (struct CE_state *)ce_hdl; + struct CE_ring_state *dst_ring = ce_state->dest_ring; + qdf_nbuf_t nbuf; + int i; + + if (ce_state->scn->fastpath_mode_on == false) + return; + + if (!ce_state->htt_rx_data) + return; + + /* + * when fastpath_mode is on and for datapath CEs. Unlike other CE's, + * this CE is completely full: does not leave one blank space, to + * distinguish between empty queue & full queue. So free all the + * entries. + */ + for (i = 0; i < dst_ring->nentries; i++) { + nbuf = dst_ring->per_transfer_context[i]; + + /* + * The reasons for doing this check are: + * 1) Protect against calling cleanup before allocating buffers + * 2) In a corner case, FASTPATH_mode_on may be set, but we + * could have a partially filled ring, because of a memory + * allocation failure in the middle of allocating ring. + * This check accounts for that case, checking + * fastpath_mode_on flag or started flag would not have + * covered that case. This is not in performance path, + * so OK to do this. + */ + if (nbuf) + qdf_nbuf_free(nbuf); + } +} + +/** + * hif_update_fastpath_recv_bufs_cnt() - Increments the Rx buf count by 1 + * @scn: HIF handle + * + * Datapath Rx CEs are special case, where we reuse all the message buffers. + * Hence we have to post all the entries in the pipe, even, in the beginning + * unlike for other CE pipes where one less than dest_nentries are filled in + * the beginning. + * + * Return: None + */ +static void hif_update_fastpath_recv_bufs_cnt(struct hif_softc *scn) +{ + int pipe_num; + struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(scn); + + if (scn->fastpath_mode_on == false) + return; + + for (pipe_num = 0; pipe_num < scn->ce_count; pipe_num++) { + struct HIF_CE_pipe_info *pipe_info = + &hif_state->pipe_info[pipe_num]; + struct CE_state *ce_state = + scn->ce_id_to_state[pipe_info->pipe_num]; + + if (ce_state->htt_rx_data) + atomic_inc(&pipe_info->recv_bufs_needed); + } +} +#else +static inline void hif_update_fastpath_recv_bufs_cnt(struct hif_softc *scn) +{ +} + +static inline bool ce_is_fastpath_enabled(struct hif_softc *scn) +{ + return false; +} + +static inline bool ce_is_fastpath_handler_registered(struct CE_state *ce_state) +{ + return false; +} +#endif /* WLAN_FEATURE_FASTPATH */ + +void ce_fini(struct CE_handle *copyeng) +{ + struct CE_state *CE_state = (struct CE_state *)copyeng; + unsigned int CE_id = CE_state->id; + struct hif_softc *scn = CE_state->scn; + + CE_state->state = CE_UNUSED; + scn->ce_id_to_state[CE_id] = NULL; + + if (CE_state->src_ring) { + /* Cleanup the datapath Tx ring */ + ce_h2t_tx_ce_cleanup(copyeng); + + if (CE_state->src_ring->shadow_base_unaligned) + qdf_mem_free(CE_state->src_ring->shadow_base_unaligned); + if (CE_state->src_ring->base_addr_owner_space_unaligned) + qdf_mem_free_consistent(scn->qdf_dev, + scn->qdf_dev->dev, + (CE_state->src_ring->nentries * + sizeof(struct CE_src_desc) + + CE_DESC_RING_ALIGN), + CE_state->src_ring-> + base_addr_owner_space_unaligned, + CE_state->src_ring-> + base_addr_CE_space, 0); + qdf_mem_free(CE_state->src_ring); + } + if (CE_state->dest_ring) { + /* Cleanup the datapath Rx ring */ + ce_t2h_msg_ce_cleanup(copyeng); + + if (CE_state->dest_ring->base_addr_owner_space_unaligned) + qdf_mem_free_consistent(scn->qdf_dev, + scn->qdf_dev->dev, + (CE_state->dest_ring->nentries * + sizeof(struct CE_dest_desc) + + CE_DESC_RING_ALIGN), + CE_state->dest_ring-> + base_addr_owner_space_unaligned, + CE_state->dest_ring-> + base_addr_CE_space, 0); + qdf_mem_free(CE_state->dest_ring); + + /* epping */ + if (CE_state->timer_inited) { + CE_state->timer_inited = false; + qdf_timer_free(&CE_state->poll_timer); + } + } + + qdf_spinlock_destroy(&CE_state->ce_index_lock); + qdf_mem_free(CE_state); +} + +void hif_detach_htc(struct hif_opaque_softc *hif_ctx) +{ + struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(hif_ctx); + + qdf_mem_zero(&hif_state->msg_callbacks_pending, + sizeof(hif_state->msg_callbacks_pending)); + qdf_mem_zero(&hif_state->msg_callbacks_current, + sizeof(hif_state->msg_callbacks_current)); +} + +/* Send the first nbytes bytes of the buffer */ +QDF_STATUS +hif_send_head(struct hif_opaque_softc *hif_ctx, + uint8_t pipe, unsigned int transfer_id, unsigned int nbytes, + qdf_nbuf_t nbuf, unsigned int data_attr) +{ + struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx); + struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(hif_ctx); + struct HIF_CE_pipe_info *pipe_info = &(hif_state->pipe_info[pipe]); + struct CE_handle *ce_hdl = pipe_info->ce_hdl; + int bytes = nbytes, nfrags = 0; + struct ce_sendlist sendlist; + int status, i = 0; + unsigned int mux_id = 0; + + QDF_ASSERT(nbytes <= qdf_nbuf_len(nbuf)); + + transfer_id = + (mux_id & MUX_ID_MASK) | + (transfer_id & TRANSACTION_ID_MASK); + data_attr &= DESC_DATA_FLAG_MASK; + /* + * The common case involves sending multiple fragments within a + * single download (the tx descriptor and the tx frame header). + * So, optimize for the case of multiple fragments by not even + * checking whether it's necessary to use a sendlist. + * The overhead of using a sendlist for a single buffer download + * is not a big deal, since it happens rarely (for WMI messages). + */ + ce_sendlist_init(&sendlist); + do { + qdf_dma_addr_t frag_paddr; + int frag_bytes; + + frag_paddr = qdf_nbuf_get_frag_paddr(nbuf, nfrags); + frag_bytes = qdf_nbuf_get_frag_len(nbuf, nfrags); + /* + * Clear the packet offset for all but the first CE desc. + */ + if (i++ > 0) + data_attr &= ~QDF_CE_TX_PKT_OFFSET_BIT_M; + + status = ce_sendlist_buf_add(&sendlist, frag_paddr, + frag_bytes > + bytes ? bytes : frag_bytes, + qdf_nbuf_get_frag_is_wordstream + (nbuf, + nfrags) ? 0 : + CE_SEND_FLAG_SWAP_DISABLE, + data_attr); + if (status != QDF_STATUS_SUCCESS) { + HIF_ERROR("%s: error, frag_num %d larger than limit", + __func__, nfrags); + return status; + } + bytes -= frag_bytes; + nfrags++; + } while (bytes > 0); + + /* Make sure we have resources to handle this request */ + qdf_spin_lock_bh(&pipe_info->completion_freeq_lock); + if (pipe_info->num_sends_allowed < nfrags) { + qdf_spin_unlock_bh(&pipe_info->completion_freeq_lock); + ce_pkt_error_count_incr(hif_state, HIF_PIPE_NO_RESOURCE); + return QDF_STATUS_E_RESOURCES; + } + pipe_info->num_sends_allowed -= nfrags; + qdf_spin_unlock_bh(&pipe_info->completion_freeq_lock); + + if (qdf_unlikely(ce_hdl == NULL)) { + HIF_ERROR("%s: error CE handle is null", __func__); + return A_ERROR; + } + + QDF_NBUF_UPDATE_TX_PKT_COUNT(nbuf, QDF_NBUF_TX_PKT_HIF); + DPTRACE(qdf_dp_trace(nbuf, QDF_DP_TRACE_HIF_PACKET_PTR_RECORD, + qdf_nbuf_data_addr(nbuf), + sizeof(qdf_nbuf_data(nbuf)), QDF_TX)); + status = ce_sendlist_send(ce_hdl, nbuf, &sendlist, transfer_id); + QDF_ASSERT(status == QDF_STATUS_SUCCESS); + + return status; +} + +void hif_send_complete_check(struct hif_opaque_softc *hif_ctx, uint8_t pipe, + int force) +{ + struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx); + + if (!force) { + int resources; + /* + * Decide whether to actually poll for completions, or just + * wait for a later chance. If there seem to be plenty of + * resources left, then just wait, since checking involves + * reading a CE register, which is a relatively expensive + * operation. + */ + resources = hif_get_free_queue_number(hif_ctx, pipe); + /* + * If at least 50% of the total resources are still available, + * don't bother checking again yet. + */ + if (resources > (host_ce_config[pipe].src_nentries >> 1)) { + return; + } + } +#if ATH_11AC_TXCOMPACT + ce_per_engine_servicereap(scn, pipe); +#else + ce_per_engine_service(scn, pipe); +#endif +} + +uint16_t +hif_get_free_queue_number(struct hif_opaque_softc *hif_ctx, uint8_t pipe) +{ + struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(hif_ctx); + struct HIF_CE_pipe_info *pipe_info = &(hif_state->pipe_info[pipe]); + uint16_t rv; + + qdf_spin_lock_bh(&pipe_info->completion_freeq_lock); + rv = pipe_info->num_sends_allowed; + qdf_spin_unlock_bh(&pipe_info->completion_freeq_lock); + return rv; +} + +/* Called by lower (CE) layer when a send to Target completes. */ +static void +hif_pci_ce_send_done(struct CE_handle *copyeng, void *ce_context, + void *transfer_context, qdf_dma_addr_t CE_data, + unsigned int nbytes, unsigned int transfer_id, + unsigned int sw_index, unsigned int hw_index, + unsigned int toeplitz_hash_result) +{ + struct HIF_CE_pipe_info *pipe_info = + (struct HIF_CE_pipe_info *)ce_context; + struct HIF_CE_state *hif_state = pipe_info->HIF_CE_state; + struct hif_softc *scn = HIF_GET_SOFTC(hif_state); + unsigned int sw_idx = sw_index, hw_idx = hw_index; + struct hif_msg_callbacks *msg_callbacks = + &hif_state->msg_callbacks_current; + + do { + /* + * The upper layer callback will be triggered + * when last fragment is complteted. + */ + if (transfer_context != CE_SENDLIST_ITEM_CTXT) { + if (scn->target_status == TARGET_STATUS_RESET) + qdf_nbuf_free(transfer_context); + else + msg_callbacks->txCompletionHandler( + msg_callbacks->Context, + transfer_context, transfer_id, + toeplitz_hash_result); + } + + qdf_spin_lock(&pipe_info->completion_freeq_lock); + pipe_info->num_sends_allowed++; + qdf_spin_unlock(&pipe_info->completion_freeq_lock); + } while (ce_completed_send_next(copyeng, + &ce_context, &transfer_context, + &CE_data, &nbytes, &transfer_id, + &sw_idx, &hw_idx, + &toeplitz_hash_result) == QDF_STATUS_SUCCESS); +} + +/** + * hif_ce_do_recv(): send message from copy engine to upper layers + * @msg_callbacks: structure containing callback and callback context + * @netbuff: skb containing message + * @nbytes: number of bytes in the message + * @pipe_info: used for the pipe_number info + * + * Checks the packet length, configures the lenght in the netbuff, + * and calls the upper layer callback. + * + * return: None + */ +static inline void hif_ce_do_recv(struct hif_msg_callbacks *msg_callbacks, + qdf_nbuf_t netbuf, int nbytes, + struct HIF_CE_pipe_info *pipe_info) { + if (nbytes <= pipe_info->buf_sz) { + qdf_nbuf_set_pktlen(netbuf, nbytes); + msg_callbacks-> + rxCompletionHandler(msg_callbacks->Context, + netbuf, pipe_info->pipe_num); + } else { + HIF_ERROR("%s: Invalid Rx msg buf:%p nbytes:%d", + __func__, netbuf, nbytes); + qdf_nbuf_free(netbuf); + } +} + +/* Called by lower (CE) layer when data is received from the Target. */ +static void +hif_pci_ce_recv_data(struct CE_handle *copyeng, void *ce_context, + void *transfer_context, qdf_dma_addr_t CE_data, + unsigned int nbytes, unsigned int transfer_id, + unsigned int flags) +{ + struct HIF_CE_pipe_info *pipe_info = + (struct HIF_CE_pipe_info *)ce_context; + struct HIF_CE_state *hif_state = pipe_info->HIF_CE_state; + struct CE_state *ce_state = (struct CE_state *) copyeng; + struct hif_softc *scn = HIF_GET_SOFTC(hif_state); +#ifdef HIF_PCI + struct hif_pci_softc *hif_pci_sc = HIF_GET_PCI_SOFTC(hif_state); +#endif + struct hif_msg_callbacks *msg_callbacks = + &hif_state->msg_callbacks_current; + + do { +#ifdef HIF_PCI + hif_pm_runtime_mark_last_busy(hif_pci_sc->dev); +#endif + qdf_nbuf_unmap_single(scn->qdf_dev, + (qdf_nbuf_t) transfer_context, + QDF_DMA_FROM_DEVICE); + + atomic_inc(&pipe_info->recv_bufs_needed); + hif_post_recv_buffers_for_pipe(pipe_info); + if (scn->target_status == TARGET_STATUS_RESET) + qdf_nbuf_free(transfer_context); + else + hif_ce_do_recv(msg_callbacks, transfer_context, + nbytes, pipe_info); + + /* Set up force_break flag if num of receices reaches + * MAX_NUM_OF_RECEIVES */ + ce_state->receive_count++; + if (qdf_unlikely(hif_ce_service_should_yield(scn, ce_state))) { + ce_state->force_break = 1; + break; + } + } while (ce_completed_recv_next(copyeng, &ce_context, &transfer_context, + &CE_data, &nbytes, &transfer_id, + &flags) == QDF_STATUS_SUCCESS); + +} + +/* TBDXXX: Set CE High Watermark; invoke txResourceAvailHandler in response */ + +void +hif_post_init(struct hif_opaque_softc *hif_ctx, void *unused, + struct hif_msg_callbacks *callbacks) +{ + struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(hif_ctx); + +#ifdef CONFIG_ATH_PCIE_ACCESS_DEBUG + spin_lock_init(&pcie_access_log_lock); +#endif + /* Save callbacks for later installation */ + qdf_mem_copy(&hif_state->msg_callbacks_pending, callbacks, + sizeof(hif_state->msg_callbacks_pending)); + +} + +static int hif_completion_thread_startup(struct HIF_CE_state *hif_state) +{ + struct CE_handle *ce_diag = hif_state->ce_diag; + int pipe_num; + struct hif_softc *scn = HIF_GET_SOFTC(hif_state); + struct hif_msg_callbacks *hif_msg_callbacks = + &hif_state->msg_callbacks_current; + + /* daemonize("hif_compl_thread"); */ + + if (scn->ce_count == 0) { + HIF_ERROR("%s: Invalid ce_count", __func__); + return -EINVAL; + } + + if (!hif_msg_callbacks || + !hif_msg_callbacks->rxCompletionHandler || + !hif_msg_callbacks->txCompletionHandler) { + HIF_ERROR("%s: no completion handler registered", __func__); + return -EFAULT; + } + + A_TARGET_ACCESS_LIKELY(scn); + for (pipe_num = 0; pipe_num < scn->ce_count; pipe_num++) { + struct CE_attr attr; + struct HIF_CE_pipe_info *pipe_info; + + pipe_info = &hif_state->pipe_info[pipe_num]; + if (pipe_info->ce_hdl == ce_diag) { + continue; /* Handle Diagnostic CE specially */ + } + attr = host_ce_config[pipe_num]; + if (attr.src_nentries) { + /* pipe used to send to target */ + HIF_INFO_MED("%s: pipe_num:%d pipe_info:0x%p", + __func__, pipe_num, pipe_info); + ce_send_cb_register(pipe_info->ce_hdl, + hif_pci_ce_send_done, pipe_info, + attr.flags & CE_ATTR_DISABLE_INTR); + pipe_info->num_sends_allowed = attr.src_nentries - 1; + } + if (attr.dest_nentries) { + /* pipe used to receive from target */ + ce_recv_cb_register(pipe_info->ce_hdl, + hif_pci_ce_recv_data, pipe_info, + attr.flags & CE_ATTR_DISABLE_INTR); + } + + if (attr.src_nentries) + qdf_spinlock_create(&pipe_info->completion_freeq_lock); + } + + A_TARGET_ACCESS_UNLIKELY(scn); + return 0; +} + +/* + * Install pending msg callbacks. + * + * TBDXXX: This hack is needed because upper layers install msg callbacks + * for use with HTC before BMI is done; yet this HIF implementation + * needs to continue to use BMI msg callbacks. Really, upper layers + * should not register HTC callbacks until AFTER BMI phase. + */ +static void hif_msg_callbacks_install(struct hif_softc *scn) +{ + struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(scn); + + qdf_mem_copy(&hif_state->msg_callbacks_current, + &hif_state->msg_callbacks_pending, + sizeof(hif_state->msg_callbacks_pending)); +} + +void hif_get_default_pipe(struct hif_opaque_softc *hif_hdl, uint8_t *ULPipe, + uint8_t *DLPipe) +{ + int ul_is_polled, dl_is_polled; + + (void)hif_map_service_to_pipe(hif_hdl, HTC_CTRL_RSVD_SVC, + ULPipe, DLPipe, &ul_is_polled, &dl_is_polled); +} + +/** + * hif_dump_pipe_debug_count() - Log error count + * @scn: hif_softc pointer. + * + * Output the pipe error counts of each pipe to log file + * + * Return: N/A + */ +void hif_dump_pipe_debug_count(struct hif_softc *scn) +{ + struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(scn); + int pipe_num; + + if (hif_state == NULL) { + HIF_ERROR("%s hif_state is NULL", __func__); + return; + } + for (pipe_num = 0; pipe_num < scn->ce_count; pipe_num++) { + struct HIF_CE_pipe_info *pipe_info; + + pipe_info = &hif_state->pipe_info[pipe_num]; + + if (pipe_info->nbuf_alloc_err_count > 0 || + pipe_info->nbuf_dma_err_count > 0 || + pipe_info->nbuf_ce_enqueue_err_count) + HIF_ERROR( + "%s: pipe_id = %d, recv_bufs_needed = %d, nbuf_alloc_err_count = %u, nbuf_dma_err_count = %u, nbuf_ce_enqueue_err_count = %u", + __func__, pipe_info->pipe_num, + atomic_read(&pipe_info->recv_bufs_needed), + pipe_info->nbuf_alloc_err_count, + pipe_info->nbuf_dma_err_count, + pipe_info->nbuf_ce_enqueue_err_count); + } +} + +static void hif_post_recv_buffers_failure(struct HIF_CE_pipe_info *pipe_info, + void *nbuf, uint32_t *error_cnt, + enum hif_ce_event_type failure_type, + const char *failure_type_string) +{ + int bufs_needed_tmp = atomic_inc_return(&pipe_info->recv_bufs_needed); + struct CE_state *CE_state = (struct CE_state *)pipe_info->ce_hdl; + struct hif_softc *scn = HIF_GET_SOFTC(pipe_info->HIF_CE_state); + int ce_id = CE_state->id; + uint32_t error_cnt_tmp; + + qdf_spin_lock_bh(&pipe_info->recv_bufs_needed_lock); + error_cnt_tmp = ++(*error_cnt); + qdf_spin_unlock_bh(&pipe_info->recv_bufs_needed_lock); + HIF_DBG("%s: pipe_num %d, needed %d, err_cnt = %u, fail_type = %s", + __func__, pipe_info->pipe_num, bufs_needed_tmp, error_cnt_tmp, + failure_type_string); + hif_record_ce_desc_event(scn, ce_id, failure_type, + NULL, nbuf, bufs_needed_tmp); + /* if we fail to allocate the last buffer for an rx pipe, + * there is no trigger to refill the ce and we will + * eventually crash + */ + if (bufs_needed_tmp == CE_state->dest_ring->nentries - 1) + qdf_sched_work(scn->qdf_dev, &CE_state->oom_allocation_work); + +} + + + + +static int hif_post_recv_buffers_for_pipe(struct HIF_CE_pipe_info *pipe_info) +{ + struct CE_handle *ce_hdl; + qdf_size_t buf_sz; + struct hif_softc *scn = HIF_GET_SOFTC(pipe_info->HIF_CE_state); + QDF_STATUS ret; + uint32_t bufs_posted = 0; + + buf_sz = pipe_info->buf_sz; + if (buf_sz == 0) { + /* Unused Copy Engine */ + return 0; + } + + ce_hdl = pipe_info->ce_hdl; + + qdf_spin_lock_bh(&pipe_info->recv_bufs_needed_lock); + while (atomic_read(&pipe_info->recv_bufs_needed) > 0) { + qdf_dma_addr_t CE_data; /* CE space buffer address */ + qdf_nbuf_t nbuf; + int status; + + atomic_dec(&pipe_info->recv_bufs_needed); + qdf_spin_unlock_bh(&pipe_info->recv_bufs_needed_lock); + + nbuf = qdf_nbuf_alloc(scn->qdf_dev, buf_sz, 0, 4, false); + if (!nbuf) { + hif_post_recv_buffers_failure(pipe_info, nbuf, + &pipe_info->nbuf_alloc_err_count, + HIF_RX_NBUF_ALLOC_FAILURE, + "HIF_RX_NBUF_ALLOC_FAILURE"); + return 1; + } + + /* + * qdf_nbuf_peek_header(nbuf, &data, &unused); + * CE_data = dma_map_single(dev, data, buf_sz, ); + * DMA_FROM_DEVICE); + */ + ret = qdf_nbuf_map_single(scn->qdf_dev, nbuf, + QDF_DMA_FROM_DEVICE); + + if (unlikely(ret != QDF_STATUS_SUCCESS)) { + hif_post_recv_buffers_failure(pipe_info, nbuf, + &pipe_info->nbuf_dma_err_count, + HIF_RX_NBUF_MAP_FAILURE, + "HIF_RX_NBUF_MAP_FAILURE"); + qdf_nbuf_free(nbuf); + return 1; + } + + CE_data = qdf_nbuf_get_frag_paddr(nbuf, 0); + + qdf_mem_dma_sync_single_for_device(scn->qdf_dev, CE_data, + buf_sz, DMA_FROM_DEVICE); + status = ce_recv_buf_enqueue(ce_hdl, (void *)nbuf, CE_data); + QDF_ASSERT(status == QDF_STATUS_SUCCESS); + if (unlikely(status != EOK)) { + hif_post_recv_buffers_failure(pipe_info, nbuf, + &pipe_info->nbuf_ce_enqueue_err_count, + HIF_RX_NBUF_ENQUEUE_FAILURE, + "HIF_RX_NBUF_ENQUEUE_FAILURE"); + + qdf_nbuf_unmap_single(scn->qdf_dev, nbuf, + QDF_DMA_FROM_DEVICE); + qdf_nbuf_free(nbuf); + return 1; + } + + qdf_spin_lock_bh(&pipe_info->recv_bufs_needed_lock); + bufs_posted++; + } + pipe_info->nbuf_alloc_err_count = + (pipe_info->nbuf_alloc_err_count > bufs_posted) ? + pipe_info->nbuf_alloc_err_count - bufs_posted : 0; + pipe_info->nbuf_dma_err_count = + (pipe_info->nbuf_dma_err_count > bufs_posted) ? + pipe_info->nbuf_dma_err_count - bufs_posted : 0; + pipe_info->nbuf_ce_enqueue_err_count = + (pipe_info->nbuf_ce_enqueue_err_count > bufs_posted) ? + pipe_info->nbuf_ce_enqueue_err_count - bufs_posted : 0; + + qdf_spin_unlock_bh(&pipe_info->recv_bufs_needed_lock); + + return 0; +} + +/* + * Try to post all desired receive buffers for all pipes. + * Returns 0 for non fastpath rx copy engine as + * oom_allocation_work will be scheduled to recover any + * failures, non-zero if unable to completely replenish + * receive buffers for fastpath rx Copy engine. + */ +static int hif_post_recv_buffers(struct hif_softc *scn) +{ + struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(scn); + int pipe_num, rv = 0; + struct CE_state *ce_state; + + A_TARGET_ACCESS_LIKELY(scn); + for (pipe_num = 0; pipe_num < scn->ce_count; pipe_num++) { + struct HIF_CE_pipe_info *pipe_info; + ce_state = scn->ce_id_to_state[pipe_num]; + pipe_info = &hif_state->pipe_info[pipe_num]; + + if (hif_is_nss_wifi_enabled(scn) && + ce_state && (ce_state->htt_rx_data)) { + continue; + } + + if (hif_post_recv_buffers_for_pipe(pipe_info) && + ce_state->htt_rx_data && + scn->fastpath_mode_on) { + rv = 1; + goto done; + } + } + +done: + A_TARGET_ACCESS_UNLIKELY(scn); + + return rv; +} + +QDF_STATUS hif_start(struct hif_opaque_softc *hif_ctx) +{ + struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx); + struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(scn); + + hif_update_fastpath_recv_bufs_cnt(scn); + + hif_msg_callbacks_install(scn); + + if (hif_completion_thread_startup(hif_state)) + return QDF_STATUS_E_FAILURE; + + /* enable buffer cleanup */ + hif_state->started = true; + + /* Post buffers once to start things off. */ + if (hif_post_recv_buffers(scn)) { + /* cleanup is done in hif_ce_disable */ + HIF_ERROR("%s:failed to post buffers", __func__); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +static void hif_recv_buffer_cleanup_on_pipe(struct HIF_CE_pipe_info *pipe_info) +{ + struct hif_softc *scn; + struct CE_handle *ce_hdl; + uint32_t buf_sz; + struct HIF_CE_state *hif_state; + qdf_nbuf_t netbuf; + qdf_dma_addr_t CE_data; + void *per_CE_context; + + buf_sz = pipe_info->buf_sz; + if (buf_sz == 0) { + /* Unused Copy Engine */ + return; + } + + hif_state = pipe_info->HIF_CE_state; + if (!hif_state->started) { + return; + } + + scn = HIF_GET_SOFTC(hif_state); + ce_hdl = pipe_info->ce_hdl; + + if (scn->qdf_dev == NULL) { + return; + } + while (ce_revoke_recv_next + (ce_hdl, &per_CE_context, (void **)&netbuf, + &CE_data) == QDF_STATUS_SUCCESS) { + if (netbuf) { + qdf_nbuf_unmap_single(scn->qdf_dev, netbuf, + QDF_DMA_FROM_DEVICE); + qdf_nbuf_free(netbuf); + } + } +} + +static void hif_send_buffer_cleanup_on_pipe(struct HIF_CE_pipe_info *pipe_info) +{ + struct CE_handle *ce_hdl; + struct HIF_CE_state *hif_state; + struct hif_softc *scn; + qdf_nbuf_t netbuf; + void *per_CE_context; + qdf_dma_addr_t CE_data; + unsigned int nbytes; + unsigned int id; + uint32_t buf_sz; + uint32_t toeplitz_hash_result; + + buf_sz = pipe_info->buf_sz; + if (buf_sz == 0) { + /* Unused Copy Engine */ + return; + } + + hif_state = pipe_info->HIF_CE_state; + if (!hif_state->started) { + return; + } + + scn = HIF_GET_SOFTC(hif_state); + + ce_hdl = pipe_info->ce_hdl; + + while (ce_cancel_send_next + (ce_hdl, &per_CE_context, + (void **)&netbuf, &CE_data, &nbytes, + &id, &toeplitz_hash_result) == QDF_STATUS_SUCCESS) { + if (netbuf != CE_SENDLIST_ITEM_CTXT) { + /* + * Packets enqueued by htt_h2t_ver_req_msg() and + * htt_h2t_rx_ring_cfg_msg_ll() have already been + * freed in htt_htc_misc_pkt_pool_free() in + * wlantl_close(), so do not free them here again + * by checking whether it's the endpoint + * which they are queued in. + */ + if (id == scn->htc_htt_tx_endpoint) + return; + /* Indicate the completion to higher + * layer to free the buffer */ + if (hif_state->msg_callbacks_current. + txCompletionHandler) + hif_state->msg_callbacks_current. + txCompletionHandler(hif_state-> + msg_callbacks_current.Context, + netbuf, id, toeplitz_hash_result); + } + } +} + +/* + * Cleanup residual buffers for device shutdown: + * buffers that were enqueued for receive + * buffers that were to be sent + * Note: Buffers that had completed but which were + * not yet processed are on a completion queue. They + * are handled when the completion thread shuts down. + */ +static void hif_buffer_cleanup(struct HIF_CE_state *hif_state) +{ + int pipe_num; + struct hif_softc *scn = HIF_GET_SOFTC(hif_state); + struct CE_state *ce_state; + + for (pipe_num = 0; pipe_num < scn->ce_count; pipe_num++) { + struct HIF_CE_pipe_info *pipe_info; + + ce_state = scn->ce_id_to_state[pipe_num]; + if (hif_is_nss_wifi_enabled(scn) && ce_state && + ((ce_state->htt_tx_data) || + (ce_state->htt_rx_data))) { + continue; + } + + pipe_info = &hif_state->pipe_info[pipe_num]; + hif_recv_buffer_cleanup_on_pipe(pipe_info); + hif_send_buffer_cleanup_on_pipe(pipe_info); + } +} + +void hif_flush_surprise_remove(struct hif_opaque_softc *hif_ctx) +{ + struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx); + struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(scn); + + hif_buffer_cleanup(hif_state); +} + +static void hif_destroy_oom_work(struct hif_softc *scn) +{ + struct CE_state *ce_state; + int ce_id; + + for (ce_id = 0; ce_id < scn->ce_count; ce_id++) { + ce_state = scn->ce_id_to_state[ce_id]; + if (ce_state) + qdf_destroy_work(scn->qdf_dev, + &ce_state->oom_allocation_work); + } +} + +void hif_ce_stop(struct hif_softc *scn) +{ + struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(scn); + int pipe_num; + + /* + * before cleaning up any memory, ensure irq & + * bottom half contexts will not be re-entered + */ + hif_disable_isr(&scn->osc); + hif_destroy_oom_work(scn); + scn->hif_init_done = false; + + /* + * At this point, asynchronous threads are stopped, + * The Target should not DMA nor interrupt, Host code may + * not initiate anything more. So we just need to clean + * up Host-side state. + */ + + if (scn->athdiag_procfs_inited) { + athdiag_procfs_remove(); + scn->athdiag_procfs_inited = false; + } + + hif_buffer_cleanup(hif_state); + + for (pipe_num = 0; pipe_num < scn->ce_count; pipe_num++) { + struct HIF_CE_pipe_info *pipe_info; + + pipe_info = &hif_state->pipe_info[pipe_num]; + if (pipe_info->ce_hdl) { + ce_fini(pipe_info->ce_hdl); + pipe_info->ce_hdl = NULL; + pipe_info->buf_sz = 0; + } + } + + if (hif_state->sleep_timer_init) { + qdf_timer_stop(&hif_state->sleep_timer); + qdf_timer_free(&hif_state->sleep_timer); + hif_state->sleep_timer_init = false; + } + + hif_state->started = false; +} + +/** + * hif_get_target_ce_config() - get copy engine configuration + * @target_ce_config_ret: basic copy engine configuration + * @target_ce_config_sz_ret: size of the basic configuration in bytes + * @target_service_to_ce_map_ret: service mapping for the copy engines + * @target_service_to_ce_map_sz_ret: size of the mapping in bytes + * @target_shadow_reg_cfg_ret: shadow register configuration + * @shadow_cfg_sz_ret: size of the shadow register configuration in bytes + * + * providing accessor to these values outside of this file. + * currently these are stored in static pointers to const sections. + * there are multiple configurations that are selected from at compile time. + * Runtime selection would need to consider mode, target type and bus type. + * + * Return: return by parameter. + */ +void hif_get_target_ce_config(struct CE_pipe_config **target_ce_config_ret, + int *target_ce_config_sz_ret, + struct service_to_pipe **target_service_to_ce_map_ret, + int *target_service_to_ce_map_sz_ret, + struct shadow_reg_cfg **target_shadow_reg_cfg_ret, + int *shadow_cfg_sz_ret) +{ + *target_ce_config_ret = target_ce_config; + *target_ce_config_sz_ret = target_ce_config_sz; + *target_service_to_ce_map_ret = target_service_to_ce_map; + *target_service_to_ce_map_sz_ret = target_service_to_ce_map_sz; + + if (target_shadow_reg_cfg_ret) + *target_shadow_reg_cfg_ret = target_shadow_reg_cfg; + + if (shadow_cfg_sz_ret) + *shadow_cfg_sz_ret = shadow_cfg_sz; +} + +/** + * hif_wlan_enable(): call the platform driver to enable wlan + * @scn: HIF Context + * + * This function passes the con_mode and CE configuration to + * platform driver to enable wlan. + * + * Return: linux error code + */ +int hif_wlan_enable(struct hif_softc *scn) +{ + struct pld_wlan_enable_cfg cfg; + enum pld_driver_mode mode; + uint32_t con_mode = hif_get_conparam(scn); + + hif_get_target_ce_config((struct CE_pipe_config **)&cfg.ce_tgt_cfg, + &cfg.num_ce_tgt_cfg, + (struct service_to_pipe **)&cfg.ce_svc_cfg, + &cfg.num_ce_svc_pipe_cfg, + (struct shadow_reg_cfg **)&cfg.shadow_reg_cfg, + &cfg.num_shadow_reg_cfg); + + /* translate from structure size to array size */ + cfg.num_ce_tgt_cfg /= sizeof(struct CE_pipe_config); + cfg.num_ce_svc_pipe_cfg /= sizeof(struct service_to_pipe); + cfg.num_shadow_reg_cfg /= sizeof(struct shadow_reg_cfg); + + if (QDF_GLOBAL_FTM_MODE == con_mode) + mode = PLD_FTM; + else if (QDF_IS_EPPING_ENABLED(con_mode)) + mode = PLD_EPPING; + else + mode = PLD_MISSION; + + if (BYPASS_QMI) + return 0; + else + return pld_wlan_enable(scn->qdf_dev->dev, &cfg, + mode, QWLAN_VERSIONSTR); +} + +#define CE_EPPING_USES_IRQ true + +/** + * hif_ce_prepare_config() - load the correct static tables. + * @scn: hif context + * + * Epping uses different static attribute tables than mission mode. + */ +void hif_ce_prepare_config(struct hif_softc *scn) +{ + uint32_t mode = hif_get_conparam(scn); + struct hif_opaque_softc *hif_hdl = GET_HIF_OPAQUE_HDL(scn); + struct hif_target_info *tgt_info = hif_get_target_info_handle(hif_hdl); + + /* if epping is enabled we need to use the epping configuration. */ + if (QDF_IS_EPPING_ENABLED(mode)) { + if (CE_EPPING_USES_IRQ) + host_ce_config = host_ce_config_wlan_epping_irq; + else + host_ce_config = host_ce_config_wlan_epping_poll; + target_ce_config = target_ce_config_wlan_epping; + target_ce_config_sz = sizeof(target_ce_config_wlan_epping); + target_service_to_ce_map = + target_service_to_ce_map_wlan_epping; + target_service_to_ce_map_sz = + sizeof(target_service_to_ce_map_wlan_epping); + target_shadow_reg_cfg = target_shadow_reg_cfg_epping; + shadow_cfg_sz = sizeof(target_shadow_reg_cfg_epping); + } + + switch (tgt_info->target_type) { + default: + break; + case TARGET_TYPE_AR900B: + case TARGET_TYPE_QCA9984: + case TARGET_TYPE_IPQ4019: + case TARGET_TYPE_QCA9888: + host_ce_config = host_ce_config_wlan_ar900b; + target_ce_config = target_ce_config_wlan_ar900b; + target_ce_config_sz = sizeof(target_ce_config_wlan_ar900b); + + target_service_to_ce_map = target_service_to_ce_map_ar900b; + target_service_to_ce_map_sz = + sizeof(target_service_to_ce_map_ar900b); + break; + + case TARGET_TYPE_AR9888: + case TARGET_TYPE_AR9888V2: + host_ce_config = host_ce_config_wlan_ar9888; + target_ce_config = target_ce_config_wlan_ar9888; + target_ce_config_sz = sizeof(target_ce_config_wlan_ar9888); + + target_service_to_ce_map = target_service_to_ce_map_ar900b; + target_service_to_ce_map_sz = + sizeof(target_service_to_ce_map_ar900b); + break; + } +} + +/** + * hif_ce_open() - do ce specific allocations + * @hif_sc: pointer to hif context + * + * return: 0 for success or QDF_STATUS_E_NOMEM + */ +QDF_STATUS hif_ce_open(struct hif_softc *hif_sc) +{ + struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(hif_sc); + + qdf_spinlock_create(&hif_state->keep_awake_lock); + return QDF_STATUS_SUCCESS; +} + +/** + * hif_ce_close() - do ce specific free + * @hif_sc: pointer to hif context + */ +void hif_ce_close(struct hif_softc *hif_sc) +{ +} + +/** + * hif_unconfig_ce() - ensure resources from hif_config_ce are freed + * @hif_sc: hif context + * + * uses state variables to support cleaning up when hif_config_ce fails. + */ +void hif_unconfig_ce(struct hif_softc *hif_sc) +{ + int pipe_num; + struct HIF_CE_pipe_info *pipe_info; + struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(hif_sc); + + for (pipe_num = 0; pipe_num < hif_sc->ce_count; pipe_num++) { + pipe_info = &hif_state->pipe_info[pipe_num]; + if (pipe_info->ce_hdl) { + ce_unregister_irq(hif_state, (1 << pipe_num)); + hif_sc->request_irq_done = false; + ce_fini(pipe_info->ce_hdl); + pipe_info->ce_hdl = NULL; + pipe_info->buf_sz = 0; + qdf_spinlock_destroy(&pipe_info->recv_bufs_needed_lock); + } + } + if (hif_sc->athdiag_procfs_inited) { + athdiag_procfs_remove(); + hif_sc->athdiag_procfs_inited = false; + } +} + +#ifdef CONFIG_BYPASS_QMI +#define FW_SHARED_MEM (2 * 1024 * 1024) + +/** + * hif_post_static_buf_to_target() - post static buffer to WLAN FW + * @scn: pointer to HIF structure + * + * WLAN FW needs 2MB memory from DDR when QMI is disabled. + * + * Return: void + */ +static void hif_post_static_buf_to_target(struct hif_softc *scn) +{ + void *target_va; + phys_addr_t target_pa; + + target_va = qdf_mem_alloc_consistent(scn->qdf_dev, scn->qdf_dev->dev, + FW_SHARED_MEM, &target_pa); + if (NULL == target_va) { + HIF_TRACE("Memory allocation failed could not post target buf"); + return; + } + hif_write32_mb(scn->mem + BYPASS_QMI_TEMP_REGISTER, target_pa); + HIF_TRACE("target va %pK target pa %pa", target_va, &target_pa); +} +#else +static inline void hif_post_static_buf_to_target(struct hif_softc *scn) +{ + return; +} +#endif + +#ifdef WLAN_SUSPEND_RESUME_TEST +static void hif_fake_apps_init_ctx(struct hif_softc *scn) +{ + INIT_WORK(&scn->fake_apps_ctx.resume_work, + hif_fake_apps_resume_work); +} +#else +static inline void hif_fake_apps_init_ctx(struct hif_softc *scn) {} +#endif + +/** + * hif_config_ce() - configure copy engines + * @scn: hif context + * + * Prepares fw, copy engine hardware and host sw according + * to the attributes selected by hif_ce_prepare_config. + * + * also calls athdiag_procfs_init + * + * return: 0 for success nonzero for failure. + */ +int hif_config_ce(struct hif_softc *scn) +{ + struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(scn); + struct hif_opaque_softc *hif_hdl = GET_HIF_OPAQUE_HDL(scn); + struct HIF_CE_pipe_info *pipe_info; + int pipe_num; + struct CE_state *ce_state; +#ifdef ADRASTEA_SHADOW_REGISTERS + int i; +#endif + QDF_STATUS rv = QDF_STATUS_SUCCESS; + + scn->notice_send = true; + + hif_post_static_buf_to_target(scn); + + hif_state->fw_indicator_address = FW_INDICATOR_ADDRESS; + + hif_config_rri_on_ddr(scn); + + /* During CE initializtion */ + scn->ce_count = HOST_CE_COUNT; + for (pipe_num = 0; pipe_num < scn->ce_count; pipe_num++) { + struct CE_attr *attr; + pipe_info = &hif_state->pipe_info[pipe_num]; + pipe_info->pipe_num = pipe_num; + pipe_info->HIF_CE_state = hif_state; + attr = &host_ce_config[pipe_num]; + pipe_info->ce_hdl = ce_init(scn, pipe_num, attr); + ce_state = scn->ce_id_to_state[pipe_num]; + qdf_spinlock_create(&pipe_info->recv_bufs_needed_lock); + QDF_ASSERT(pipe_info->ce_hdl != NULL); + if (pipe_info->ce_hdl == NULL) { + rv = QDF_STATUS_E_FAILURE; + A_TARGET_ACCESS_UNLIKELY(scn); + goto err; + } + + if (pipe_num == DIAG_CE_ID) { + /* Reserve the ultimate CE for + * Diagnostic Window support */ + hif_state->ce_diag = pipe_info->ce_hdl; + continue; + } + + if (hif_is_nss_wifi_enabled(scn) && ce_state && + (ce_state->htt_rx_data)) + continue; + + pipe_info->buf_sz = (qdf_size_t) (attr->src_sz_max); + if (attr->dest_nentries > 0) { + atomic_set(&pipe_info->recv_bufs_needed, + init_buffer_count(attr->dest_nentries - 1)); + } else { + atomic_set(&pipe_info->recv_bufs_needed, 0); + } + ce_tasklet_init(hif_state, (1 << pipe_num)); + ce_register_irq(hif_state, (1 << pipe_num)); + scn->request_irq_done = true; + } + + if (athdiag_procfs_init(scn) != 0) { + A_TARGET_ACCESS_UNLIKELY(scn); + goto err; + } + scn->athdiag_procfs_inited = true; + + HIF_INFO_MED("%s: ce_init done", __func__); + + init_tasklet_workers(hif_hdl); + hif_fake_apps_init_ctx(scn); + + HIF_TRACE("%s: X, ret = %d", __func__, rv); + +#ifdef ADRASTEA_SHADOW_REGISTERS + HIF_INFO("%s, Using Shadow Registers instead of CE Registers", __func__); + for (i = 0; i < NUM_SHADOW_REGISTERS; i++) { + HIF_INFO("%s Shadow Register%d is mapped to address %x", + __func__, i, + (A_TARGET_READ(scn, (SHADOW_ADDRESS(i))) << 2)); + } +#endif + + return rv != QDF_STATUS_SUCCESS; + +err: + /* Failure, so clean up */ + hif_unconfig_ce(scn); + HIF_TRACE("%s: X, ret = %d", __func__, rv); + return QDF_STATUS_SUCCESS != QDF_STATUS_E_FAILURE; +} + +#ifdef WLAN_FEATURE_FASTPATH +/** + * hif_ce_fastpath_cb_register() - Register callback for fastpath msg handler + * @handler: Callback funtcion + * @context: handle for callback function + * + * Return: QDF_STATUS_SUCCESS on success or QDF_STATUS_E_FAILURE + */ +int hif_ce_fastpath_cb_register(struct hif_opaque_softc *hif_ctx, + fastpath_msg_handler handler, + void *context) +{ + struct CE_state *ce_state; + struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx); + int i; + + if (!scn) { + HIF_ERROR("%s: scn is NULL", __func__); + QDF_ASSERT(0); + return QDF_STATUS_E_FAILURE; + } + + if (!scn->fastpath_mode_on) { + HIF_WARN("%s: Fastpath mode disabled", __func__); + return QDF_STATUS_E_FAILURE; + } + + for (i = 0; i < scn->ce_count; i++) { + ce_state = scn->ce_id_to_state[i]; + if (ce_state->htt_rx_data) { + ce_state->fastpath_handler = handler; + ce_state->context = context; + } + } + + return QDF_STATUS_SUCCESS; +} +#endif + +#ifdef IPA_OFFLOAD +/** + * hif_ce_ipa_get_ce_resource() - get uc resource on hif + * @scn: bus context + * @ce_sr_base_paddr: copyengine source ring base physical address + * @ce_sr_ring_size: copyengine source ring size + * @ce_reg_paddr: copyengine register physical address + * + * IPA micro controller data path offload feature enabled, + * HIF should release copy engine related resource information to IPA UC + * IPA UC will access hardware resource with released information + * + * Return: None + */ +void hif_ce_ipa_get_ce_resource(struct hif_softc *scn, + qdf_dma_addr_t *ce_sr_base_paddr, + uint32_t *ce_sr_ring_size, + qdf_dma_addr_t *ce_reg_paddr) +{ + struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(scn); + struct HIF_CE_pipe_info *pipe_info = + &(hif_state->pipe_info[HIF_PCI_IPA_UC_ASSIGNED_CE]); + struct CE_handle *ce_hdl = pipe_info->ce_hdl; + + ce_ipa_get_resource(ce_hdl, ce_sr_base_paddr, ce_sr_ring_size, + ce_reg_paddr); + return; +} +#endif /* IPA_OFFLOAD */ + + +#ifdef ADRASTEA_SHADOW_REGISTERS + +/* + Current shadow register config + + ----------------------------------------------------------- + Shadow Register | CE | src/dst write index + ----------------------------------------------------------- + 0 | 0 | src + 1 No Config - Doesn't point to anything + 2 No Config - Doesn't point to anything + 3 | 3 | src + 4 | 4 | src + 5 | 5 | src + 6 No Config - Doesn't point to anything + 7 | 7 | src + 8 No Config - Doesn't point to anything + 9 No Config - Doesn't point to anything + 10 No Config - Doesn't point to anything + 11 No Config - Doesn't point to anything + ----------------------------------------------------------- + 12 No Config - Doesn't point to anything + 13 | 1 | dst + 14 | 2 | dst + 15 No Config - Doesn't point to anything + 16 No Config - Doesn't point to anything + 17 No Config - Doesn't point to anything + 18 No Config - Doesn't point to anything + 19 | 7 | dst + 20 | 8 | dst + 21 No Config - Doesn't point to anything + 22 No Config - Doesn't point to anything + 23 No Config - Doesn't point to anything + ----------------------------------------------------------- + + + ToDo - Move shadow register config to following in the future + This helps free up a block of shadow registers towards the end. + Can be used for other purposes + + ----------------------------------------------------------- + Shadow Register | CE | src/dst write index + ----------------------------------------------------------- + 0 | 0 | src + 1 | 3 | src + 2 | 4 | src + 3 | 5 | src + 4 | 7 | src + ----------------------------------------------------------- + 5 | 1 | dst + 6 | 2 | dst + 7 | 7 | dst + 8 | 8 | dst + ----------------------------------------------------------- + 9 No Config - Doesn't point to anything + 12 No Config - Doesn't point to anything + 13 No Config - Doesn't point to anything + 14 No Config - Doesn't point to anything + 15 No Config - Doesn't point to anything + 16 No Config - Doesn't point to anything + 17 No Config - Doesn't point to anything + 18 No Config - Doesn't point to anything + 19 No Config - Doesn't point to anything + 20 No Config - Doesn't point to anything + 21 No Config - Doesn't point to anything + 22 No Config - Doesn't point to anything + 23 No Config - Doesn't point to anything + ----------------------------------------------------------- +*/ + +u32 shadow_sr_wr_ind_addr(struct hif_softc *scn, u32 ctrl_addr) +{ + u32 addr = 0; + u32 ce = COPY_ENGINE_ID(ctrl_addr); + + switch (ce) { + case 0: + addr = SHADOW_VALUE0; + break; + case 3: + addr = SHADOW_VALUE3; + break; + case 4: + addr = SHADOW_VALUE4; + break; + case 5: + addr = SHADOW_VALUE5; + break; + case 7: + addr = SHADOW_VALUE7; + break; + default: + HIF_ERROR("invalid CE ctrl_addr (CE=%d)", ce); + QDF_ASSERT(0); + } + return addr; + +} + +u32 shadow_dst_wr_ind_addr(struct hif_softc *scn, u32 ctrl_addr) +{ + u32 addr = 0; + u32 ce = COPY_ENGINE_ID(ctrl_addr); + + switch (ce) { + case 1: + addr = SHADOW_VALUE13; + break; + case 2: + addr = SHADOW_VALUE14; + break; + case 5: + addr = SHADOW_VALUE17; + break; + case 7: + addr = SHADOW_VALUE19; + break; + case 8: + addr = SHADOW_VALUE20; + break; + case 9: + addr = SHADOW_VALUE21; + break; + case 10: + addr = SHADOW_VALUE22; + break; + case 11: + addr = SHADOW_VALUE23; + break; + default: + HIF_ERROR("invalid CE ctrl_addr (CE=%d)", ce); + QDF_ASSERT(0); + } + + return addr; + +} +#endif + +#if defined(FEATURE_LRO) +void *hif_ce_get_lro_ctx(struct hif_opaque_softc *hif_hdl, int ctx_id) +{ + struct CE_state *ce_state; + struct hif_softc *scn = HIF_GET_SOFTC(hif_hdl); + + ce_state = scn->ce_id_to_state[ctx_id]; + + return ce_state->lro_data; +} + +/** + * ce_lro_flush_cb_register() - register the LRO flush + * callback + * @scn: HIF context + * @handler: callback function + * @data: opaque data pointer to be passed back + * + * Store the LRO flush callback provided + * + * Return: Number of instances the callback is registered for + */ +int ce_lro_flush_cb_register(struct hif_opaque_softc *hif_hdl, + void (handler)(void *), + void *(lro_init_handler)(void)) +{ + int rc = 0; + int i; + struct CE_state *ce_state; + struct hif_softc *scn = HIF_GET_SOFTC(hif_hdl); + void *data = NULL; + + QDF_ASSERT(scn != NULL); + + if (scn != NULL) { + for (i = 0; i < scn->ce_count; i++) { + ce_state = scn->ce_id_to_state[i]; + if ((ce_state != NULL) && (ce_state->htt_rx_data)) { + data = lro_init_handler(); + if (data == NULL) { + HIF_ERROR("%s: Failed to init LRO for CE %d", + __func__, i); + continue; + } + ce_state->lro_flush_cb = handler; + ce_state->lro_data = data; + rc++; + } + } + } else { + HIF_ERROR("%s: hif_state NULL!", __func__); + } + return rc; +} + +/** + * ce_lro_flush_cb_deregister() - deregister the LRO flush + * callback + * @scn: HIF context + * + * Remove the LRO flush callback + * + * Return: Number of instances the callback is de-registered + */ +int ce_lro_flush_cb_deregister(struct hif_opaque_softc *hif_hdl, + void (lro_deinit_cb)(void *)) +{ + int rc = 0; + int i; + struct CE_state *ce_state; + struct hif_softc *scn = HIF_GET_SOFTC(hif_hdl); + + QDF_ASSERT(scn != NULL); + if (scn != NULL) { + for (i = 0; i < scn->ce_count; i++) { + ce_state = scn->ce_id_to_state[i]; + if ((ce_state != NULL) && (ce_state->htt_rx_data)) { + ce_state->lro_flush_cb = NULL; + lro_deinit_cb(ce_state->lro_data); + ce_state->lro_data = NULL; + rc++; + } + } + } else { + HIF_ERROR("%s: hif_state NULL!", __func__); + } + return rc; +} +#endif + +/** + * hif_map_service_to_pipe() - returns the ce ids pertaining to + * this service + * @scn: hif_softc pointer. + * @svc_id: Service ID for which the mapping is needed. + * @ul_pipe: address of the container in which ul pipe is returned. + * @dl_pipe: address of the container in which dl pipe is returned. + * @ul_is_polled: address of the container in which a bool + * indicating if the UL CE for this service + * is polled is returned. + * @dl_is_polled: address of the container in which a bool + * indicating if the DL CE for this service + * is polled is returned. + * + * Return: Indicates whether the service has been found in the table. + * Upon return, ul_is_polled is updated only if ul_pipe is updated. + * There will be warning logs if either leg has not been updated + * because it missed the entry in the table (but this is not an err). + */ +int hif_map_service_to_pipe(struct hif_opaque_softc *hif_hdl, uint16_t svc_id, + uint8_t *ul_pipe, uint8_t *dl_pipe, int *ul_is_polled, + int *dl_is_polled) +{ + int status = QDF_STATUS_E_INVAL; + unsigned int i; + struct service_to_pipe element; + struct service_to_pipe *tgt_svc_map_to_use; + size_t sz_tgt_svc_map_to_use; + struct hif_softc *scn = HIF_GET_SOFTC(hif_hdl); + uint32_t mode = hif_get_conparam(scn); + struct hif_target_info *tgt_info = hif_get_target_info_handle(hif_hdl); + bool dl_updated = false; + bool ul_updated = false; + + if (QDF_IS_EPPING_ENABLED(mode)) { + tgt_svc_map_to_use = target_service_to_ce_map_wlan_epping; + sz_tgt_svc_map_to_use = + sizeof(target_service_to_ce_map_wlan_epping); + } else { + switch (tgt_info->target_type) { + default: + tgt_svc_map_to_use = target_service_to_ce_map_wlan; + sz_tgt_svc_map_to_use = + sizeof(target_service_to_ce_map_wlan); + break; + case TARGET_TYPE_AR900B: + case TARGET_TYPE_QCA9984: + case TARGET_TYPE_IPQ4019: + case TARGET_TYPE_QCA9888: + case TARGET_TYPE_AR9888: + case TARGET_TYPE_AR9888V2: + tgt_svc_map_to_use = target_service_to_ce_map_ar900b; + sz_tgt_svc_map_to_use = + sizeof(target_service_to_ce_map_ar900b); + break; + } + } + + *dl_is_polled = 0; /* polling for received messages not supported */ + + for (i = 0; i < (sz_tgt_svc_map_to_use/sizeof(element)); i++) { + + memcpy(&element, &tgt_svc_map_to_use[i], sizeof(element)); + if (element.service_id == svc_id) { + if (element.pipedir == PIPEDIR_OUT) { + *ul_pipe = element.pipenum; + *ul_is_polled = + (host_ce_config[*ul_pipe].flags & + CE_ATTR_DISABLE_INTR) != 0; + ul_updated = true; + } else if (element.pipedir == PIPEDIR_IN) { + *dl_pipe = element.pipenum; + dl_updated = true; + } + status = QDF_STATUS_SUCCESS; + } + } + if (ul_updated == false) + HIF_WARN("%s: ul pipe is NOT updated for service %d", + __func__, svc_id); + if (dl_updated == false) + HIF_WARN("%s: dl pipe is NOT updated for service %d", + __func__, svc_id); + + return status; +} + +#ifdef SHADOW_REG_DEBUG +inline uint32_t DEBUG_CE_SRC_RING_READ_IDX_GET(struct hif_softc *scn, + uint32_t CE_ctrl_addr) +{ + uint32_t read_from_hw, srri_from_ddr = 0; + + read_from_hw = A_TARGET_READ(scn, CE_ctrl_addr + CURRENT_SRRI_ADDRESS); + + srri_from_ddr = SRRI_FROM_DDR_ADDR(VADDR_FOR_CE(scn, CE_ctrl_addr)); + + if (read_from_hw != srri_from_ddr) { + HIF_ERROR("%s: error: read from ddr = %d actual read from register = %d, CE_MISC_INT_STATUS_GET = 0x%x", + __func__, srri_from_ddr, read_from_hw, + CE_MISC_INT_STATUS_GET(scn, CE_ctrl_addr)); + QDF_ASSERT(0); + } + return srri_from_ddr; +} + + +inline uint32_t DEBUG_CE_DEST_RING_READ_IDX_GET(struct hif_softc *scn, + uint32_t CE_ctrl_addr) +{ + uint32_t read_from_hw, drri_from_ddr = 0; + + read_from_hw = A_TARGET_READ(scn, CE_ctrl_addr + CURRENT_DRRI_ADDRESS); + + drri_from_ddr = DRRI_FROM_DDR_ADDR(VADDR_FOR_CE(scn, CE_ctrl_addr)); + + if (read_from_hw != drri_from_ddr) { + HIF_ERROR("error: read from ddr = %d actual read from register = %d, CE_MISC_INT_STATUS_GET = 0x%x", + drri_from_ddr, read_from_hw, + CE_MISC_INT_STATUS_GET(scn, CE_ctrl_addr)); + QDF_ASSERT(0); + } + return drri_from_ddr; +} + +#endif + +#ifdef ADRASTEA_RRI_ON_DDR +/** + * hif_get_src_ring_read_index(): Called to get the SRRI + * + * @scn: hif_softc pointer + * @CE_ctrl_addr: base address of the CE whose RRI is to be read + * + * This function returns the SRRI to the caller. For CEs that + * dont have interrupts enabled, we look at the DDR based SRRI + * + * Return: SRRI + */ +inline unsigned int hif_get_src_ring_read_index(struct hif_softc *scn, + uint32_t CE_ctrl_addr) +{ + struct CE_attr attr; + + attr = host_ce_config[COPY_ENGINE_ID(CE_ctrl_addr)]; + if (attr.flags & CE_ATTR_DISABLE_INTR) + return CE_SRC_RING_READ_IDX_GET_FROM_DDR(scn, CE_ctrl_addr); + else + return A_TARGET_READ(scn, + (CE_ctrl_addr) + CURRENT_SRRI_ADDRESS); +} + +/** + * hif_get_dst_ring_read_index(): Called to get the DRRI + * + * @scn: hif_softc pointer + * @CE_ctrl_addr: base address of the CE whose RRI is to be read + * + * This function returns the DRRI to the caller. For CEs that + * dont have interrupts enabled, we look at the DDR based DRRI + * + * Return: DRRI + */ +inline unsigned int hif_get_dst_ring_read_index(struct hif_softc *scn, + uint32_t CE_ctrl_addr) +{ + struct CE_attr attr; + + attr = host_ce_config[COPY_ENGINE_ID(CE_ctrl_addr)]; + + if (attr.flags & CE_ATTR_DISABLE_INTR) + return CE_DEST_RING_READ_IDX_GET_FROM_DDR(scn, CE_ctrl_addr); + else + return A_TARGET_READ(scn, + (CE_ctrl_addr) + CURRENT_DRRI_ADDRESS); +} + +/** + * hif_config_rri_on_ddr(): Configure the RRI on DDR mechanism + * + * @scn: hif_softc pointer + * + * This function allocates non cached memory on ddr and sends + * the physical address of this memory to the CE hardware. The + * hardware updates the RRI on this particular location. + * + * Return: None + */ +static inline void hif_config_rri_on_ddr(struct hif_softc *scn) +{ + unsigned int i; + qdf_dma_addr_t paddr_rri_on_ddr; + uint32_t high_paddr, low_paddr; + scn->vaddr_rri_on_ddr = + (uint32_t *)qdf_mem_alloc_consistent(scn->qdf_dev, + scn->qdf_dev->dev, (CE_COUNT*sizeof(uint32_t)), + &paddr_rri_on_ddr); + + scn->paddr_rri_on_ddr = paddr_rri_on_ddr; + low_paddr = BITS0_TO_31(paddr_rri_on_ddr); + high_paddr = BITS32_TO_35(paddr_rri_on_ddr); + + HIF_INFO("%s using srri and drri from DDR", __func__); + + WRITE_CE_DDR_ADDRESS_FOR_RRI_LOW(scn, low_paddr); + WRITE_CE_DDR_ADDRESS_FOR_RRI_HIGH(scn, high_paddr); + + for (i = 0; i < CE_COUNT; i++) + CE_IDX_UPD_EN_SET(scn, CE_BASE_ADDRESS(i)); + + qdf_mem_zero(scn->vaddr_rri_on_ddr, CE_COUNT*sizeof(uint32_t)); + + return; +} +#else + +/** + * hif_config_rri_on_ddr(): Configure the RRI on DDR mechanism + * + * @scn: hif_softc pointer + * + * This is a dummy implementation for platforms that don't + * support this functionality. + * + * Return: None + */ +static inline void hif_config_rri_on_ddr(struct hif_softc *scn) +{ + return; +} +#endif + +/** + * hif_dump_ce_registers() - dump ce registers + * @scn: hif_opaque_softc pointer. + * + * Output the copy engine registers + * + * Return: 0 for success or error code + */ +int hif_dump_ce_registers(struct hif_softc *scn) +{ + struct hif_opaque_softc *hif_hdl = GET_HIF_OPAQUE_HDL(scn); + uint32_t ce_reg_address = CE0_BASE_ADDRESS; + uint32_t ce_reg_values[CE_USEFUL_SIZE >> 2]; + uint32_t ce_reg_word_size = CE_USEFUL_SIZE >> 2; + uint16_t i; + QDF_STATUS status; + + for (i = 0; i < scn->ce_count; i++, ce_reg_address += CE_OFFSET) { + if (scn->ce_id_to_state[i] == NULL) { + HIF_DBG("CE%d not used.", i); + continue; + } + + status = hif_diag_read_mem(hif_hdl, ce_reg_address, + (uint8_t *) &ce_reg_values[0], + ce_reg_word_size * sizeof(uint32_t)); + + if (status != QDF_STATUS_SUCCESS) { + HIF_ERROR("Dumping CE register failed!"); + return -EACCES; + } + HIF_ERROR("CE%d Registers:", i); + qdf_trace_hex_dump(QDF_MODULE_ID_HIF, QDF_TRACE_LEVEL_DEBUG, + (uint8_t *) &ce_reg_values[0], + ce_reg_word_size * sizeof(uint32_t)); + } + return 0; +} + +#ifdef QCA_NSS_WIFI_OFFLOAD_SUPPORT +struct hif_pipe_addl_info *hif_get_addl_pipe_info(struct hif_opaque_softc *osc, + struct hif_pipe_addl_info *hif_info, uint32_t pipe) +{ + struct hif_softc *scn = HIF_GET_SOFTC(osc); + struct hif_pci_softc *sc = HIF_GET_PCI_SOFTC(scn); + struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(osc); + struct HIF_CE_pipe_info *pipe_info = &(hif_state->pipe_info[pipe]); + struct CE_handle *ce_hdl = pipe_info->ce_hdl; + struct CE_state *ce_state = (struct CE_state *)ce_hdl; + struct CE_ring_state *src_ring = ce_state->src_ring; + struct CE_ring_state *dest_ring = ce_state->dest_ring; + + if (src_ring) { + hif_info->ul_pipe.nentries = src_ring->nentries; + hif_info->ul_pipe.nentries_mask = src_ring->nentries_mask; + hif_info->ul_pipe.sw_index = src_ring->sw_index; + hif_info->ul_pipe.write_index = src_ring->write_index; + hif_info->ul_pipe.hw_index = src_ring->hw_index; + hif_info->ul_pipe.base_addr_CE_space = + src_ring->base_addr_CE_space; + hif_info->ul_pipe.base_addr_owner_space = + src_ring->base_addr_owner_space; + } + + + if (dest_ring) { + hif_info->dl_pipe.nentries = dest_ring->nentries; + hif_info->dl_pipe.nentries_mask = dest_ring->nentries_mask; + hif_info->dl_pipe.sw_index = dest_ring->sw_index; + hif_info->dl_pipe.write_index = dest_ring->write_index; + hif_info->dl_pipe.hw_index = dest_ring->hw_index; + hif_info->dl_pipe.base_addr_CE_space = + dest_ring->base_addr_CE_space; + hif_info->dl_pipe.base_addr_owner_space = + dest_ring->base_addr_owner_space; + } + + hif_info->pci_mem = pci_resource_start(sc->pdev, 0); + hif_info->ctrl_addr = ce_state->ctrl_addr; + + return hif_info; +} + +uint32_t hif_set_nss_wifiol_mode(struct hif_opaque_softc *osc, uint32_t mode) +{ + struct hif_softc *scn = HIF_GET_SOFTC(osc); + + scn->nss_wifi_ol_mode = mode; + return 0; +} + +#endif + +void hif_disable_interrupt(struct hif_opaque_softc *osc, uint32_t pipe_num) +{ + struct hif_softc *scn = HIF_GET_SOFTC(osc); + struct CE_state *CE_state = scn->ce_id_to_state[pipe_num]; + uint32_t ctrl_addr = CE_state->ctrl_addr; + + Q_TARGET_ACCESS_BEGIN(scn); + CE_COPY_COMPLETE_INTR_DISABLE(scn, ctrl_addr); + Q_TARGET_ACCESS_END(scn); +} + +/** + * hif_fw_event_handler() - hif fw event handler + * @hif_state: pointer to hif ce state structure + * + * Process fw events and raise HTC callback to process fw events. + * + * Return: none + */ +static inline void hif_fw_event_handler(struct HIF_CE_state *hif_state) +{ + struct hif_msg_callbacks *msg_callbacks = + &hif_state->msg_callbacks_current; + + if (!msg_callbacks->fwEventHandler) + return; + + msg_callbacks->fwEventHandler(msg_callbacks->Context, + QDF_STATUS_E_FAILURE); +} + +#ifndef QCA_WIFI_3_0 +/** + * hif_fw_interrupt_handler() - FW interrupt handler + * @irq: irq number + * @arg: the user pointer + * + * Called from the PCI interrupt handler when a + * firmware-generated interrupt to the Host. + * + * Return: status of handled irq + */ +irqreturn_t hif_fw_interrupt_handler(int irq, void *arg) +{ + struct hif_softc *scn = arg; + struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(scn); + uint32_t fw_indicator_address, fw_indicator; + + if (Q_TARGET_ACCESS_BEGIN(scn) < 0) + return ATH_ISR_NOSCHED; + + fw_indicator_address = hif_state->fw_indicator_address; + /* For sudden unplug this will return ~0 */ + fw_indicator = A_TARGET_READ(scn, fw_indicator_address); + + if ((fw_indicator != ~0) && (fw_indicator & FW_IND_EVENT_PENDING)) { + /* ACK: clear Target-side pending event */ + A_TARGET_WRITE(scn, fw_indicator_address, + fw_indicator & ~FW_IND_EVENT_PENDING); + if (Q_TARGET_ACCESS_END(scn) < 0) + return ATH_ISR_SCHED; + + if (hif_state->started) { + hif_fw_event_handler(hif_state); + } else { + /* + * Probable Target failure before we're prepared + * to handle it. Generally unexpected. + */ + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + ("%s: Early firmware event indicated\n", + __func__)); + } + } else { + if (Q_TARGET_ACCESS_END(scn) < 0) + return ATH_ISR_SCHED; + } + + return ATH_ISR_SCHED; +} +#else +irqreturn_t hif_fw_interrupt_handler(int irq, void *arg) +{ + return ATH_ISR_SCHED; +} +#endif /* #ifdef QCA_WIFI_3_0 */ + + +/** + * hif_wlan_disable(): call the platform driver to disable wlan + * @scn: HIF Context + * + * This function passes the con_mode to platform driver to disable + * wlan. + * + * Return: void + */ +void hif_wlan_disable(struct hif_softc *scn) +{ + enum pld_driver_mode mode; + uint32_t con_mode = hif_get_conparam(scn); + + if (QDF_GLOBAL_FTM_MODE == con_mode) + mode = PLD_FTM; + else if (QDF_IS_EPPING_ENABLED(con_mode)) + mode = PLD_EPPING; + else + mode = PLD_MISSION; + + pld_wlan_disable(scn->qdf_dev->dev, mode); +} diff --git a/drivers/staging/qca-wifi-host-cmn/hif/src/ce/ce_main.h b/drivers/staging/qca-wifi-host-cmn/hif/src/ce/ce_main.h new file mode 100644 index 0000000000000000000000000000000000000000..4a68618bd1bc206eb96cb6b1fe2818880a405df3 --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/hif/src/ce/ce_main.h @@ -0,0 +1,196 @@ +/* + * Copyright (c) 2015-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef __CE_H__ +#define __CE_H__ + +#include "qdf_atomic.h" +#include "qdf_lock.h" +#include "hif_main.h" +#include "qdf_util.h" + +#define CE_HTT_T2H_MSG 1 +#define CE_HTT_H2T_MSG 4 + +#define CE_OFFSET 0x00000400 +#define CE_USEFUL_SIZE 0x00000058 + +/** + * enum ce_id_type + * + * @ce_id_type: Copy engine ID + */ +enum ce_id_type { + CE_ID_0, + CE_ID_1, + CE_ID_2, + CE_ID_3, + CE_ID_4, + CE_ID_5, + CE_ID_6, + CE_ID_7, + CE_ID_8, + CE_ID_9, + CE_ID_10, + CE_ID_11, + CE_ID_MAX +}; + +#ifdef CONFIG_WIN +#define QWLAN_VERSIONSTR "WIN" +#endif + +enum ol_ath_hif_pkt_ecodes { + HIF_PIPE_NO_RESOURCE = 0 +}; + +struct HIF_CE_state; + +/* Per-pipe state. */ +struct HIF_CE_pipe_info { + /* Handle of underlying Copy Engine */ + struct CE_handle *ce_hdl; + + /* Our pipe number; facilitiates use of pipe_info ptrs. */ + uint8_t pipe_num; + + /* Convenience back pointer to HIF_CE_state. */ + struct HIF_CE_state *HIF_CE_state; + + /* Instantaneous number of receive buffers that should be posted */ + atomic_t recv_bufs_needed; + qdf_size_t buf_sz; + qdf_spinlock_t recv_bufs_needed_lock; + + qdf_spinlock_t completion_freeq_lock; + /* Limit the number of outstanding send requests. */ + int num_sends_allowed; + + /* adding three counts for debugging ring buffer errors */ + uint32_t nbuf_alloc_err_count; + uint32_t nbuf_dma_err_count; + uint32_t nbuf_ce_enqueue_err_count; +}; + +/** + * struct ce_tasklet_entry + * + * @intr_tq: intr_tq + * @ce_id: ce_id + * @inited: inited + * @hif_ce_state: hif_ce_state + * @from_irq: from_irq + */ +struct ce_tasklet_entry { + struct tasklet_struct intr_tq; + enum ce_id_type ce_id; + bool inited; + void *hif_ce_state; +}; + +struct ce_stats { + uint32_t ce_per_cpu[CE_COUNT_MAX][QDF_MAX_AVAILABLE_CPU]; +}; + +struct HIF_CE_state { + struct hif_softc ol_sc; + bool started; + struct ce_tasklet_entry tasklets[CE_COUNT_MAX]; + qdf_spinlock_t keep_awake_lock; + unsigned int keep_awake_count; + bool verified_awake; + bool fake_sleep; + qdf_timer_t sleep_timer; + bool sleep_timer_init; + qdf_time_t sleep_ticks; + + /* Per-pipe state. */ + struct HIF_CE_pipe_info pipe_info[CE_COUNT_MAX]; + /* to be activated after BMI_DONE */ + struct hif_msg_callbacks msg_callbacks_pending; + /* current msg callbacks in use */ + struct hif_msg_callbacks msg_callbacks_current; + + /* Target address used to signal a pending firmware event */ + uint32_t fw_indicator_address; + + /* Copy Engine used for Diagnostic Accesses */ + struct CE_handle *ce_diag; + struct ce_stats stats; +}; + +/* + * HIA Map Definition + */ +struct host_interest_area_t { + uint32_t hi_interconnect_state; + uint32_t hi_early_alloc; + uint32_t hi_option_flag2; + uint32_t hi_board_data; + uint32_t hi_board_data_initialized; + uint32_t hi_failure_state; + uint32_t hi_rddi_msi_num; + uint32_t hi_pcie_perst_couple_en; + uint32_t hi_sw_protocol_version; +}; + +struct shadow_reg_cfg { + uint16_t ce_id; + uint16_t reg_offset; +}; + +void hif_ce_stop(struct hif_softc *scn); +int hif_dump_ce_registers(struct hif_softc *scn); +void +hif_ce_dump_target_memory(struct hif_softc *scn, void *ramdump_base, + uint32_t address, uint32_t size); + +#ifdef IPA_OFFLOAD +void hif_ce_ipa_get_ce_resource(struct hif_softc *scn, + qdf_dma_addr_t *ce_sr_base_paddr, + uint32_t *ce_sr_ring_size, + qdf_dma_addr_t *ce_reg_paddr); +#else +static inline +void hif_ce_ipa_get_ce_resource(struct hif_softc *scn, + qdf_dma_addr_t *ce_sr_base_paddr, + uint32_t *ce_sr_ring_size, + qdf_dma_addr_t *ce_reg_paddr) +{ + return; +} + +#endif +int hif_wlan_enable(struct hif_softc *scn); +void hif_wlan_disable(struct hif_softc *scn); +void hif_get_target_ce_config(struct CE_pipe_config **target_ce_config_ret, + int *target_ce_config_sz_ret, + struct service_to_pipe **target_service_to_ce_map_ret, + int *target_service_to_ce_map_sz_ret, + struct shadow_reg_cfg **target_shadow_reg_cfg_ret, + int *shadow_cfg_sz_ret); +#endif /* __CE_H__ */ diff --git a/drivers/staging/qca-wifi-host-cmn/hif/src/ce/ce_reg.h b/drivers/staging/qca-wifi-host-cmn/hif/src/ce/ce_reg.h new file mode 100644 index 0000000000000000000000000000000000000000..297e88f7c25b1ab9f121f4a7412c6dc459ee2ab0 --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/hif/src/ce/ce_reg.h @@ -0,0 +1,544 @@ +/* + * Copyright (c) 2015-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef __CE_REG_H__ +#define __CE_REG_H__ + +#define COPY_ENGINE_ID(COPY_ENGINE_BASE_ADDRESS) ((COPY_ENGINE_BASE_ADDRESS \ + - CE0_BASE_ADDRESS)/(CE1_BASE_ADDRESS - CE0_BASE_ADDRESS)) + +#define DST_WR_INDEX_ADDRESS (scn->target_ce_def->d_DST_WR_INDEX_ADDRESS) +#define SRC_WATERMARK_ADDRESS (scn->target_ce_def->d_SRC_WATERMARK_ADDRESS) +#define SRC_WATERMARK_LOW_MASK (scn->target_ce_def->d_SRC_WATERMARK_LOW_MASK) +#define SRC_WATERMARK_HIGH_MASK (scn->target_ce_def->d_SRC_WATERMARK_HIGH_MASK) +#define DST_WATERMARK_LOW_MASK (scn->target_ce_def->d_DST_WATERMARK_LOW_MASK) +#define DST_WATERMARK_HIGH_MASK (scn->target_ce_def->d_DST_WATERMARK_HIGH_MASK) +#define CURRENT_SRRI_ADDRESS (scn->target_ce_def->d_CURRENT_SRRI_ADDRESS) +#define CURRENT_DRRI_ADDRESS (scn->target_ce_def->d_CURRENT_DRRI_ADDRESS) + +#define SHADOW_VALUE0 (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_VALUE_0) +#define SHADOW_VALUE1 (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_VALUE_1) +#define SHADOW_VALUE2 (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_VALUE_2) +#define SHADOW_VALUE3 (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_VALUE_3) +#define SHADOW_VALUE4 (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_VALUE_4) +#define SHADOW_VALUE5 (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_VALUE_5) +#define SHADOW_VALUE6 (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_VALUE_6) +#define SHADOW_VALUE7 (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_VALUE_7) +#define SHADOW_VALUE8 (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_VALUE_8) +#define SHADOW_VALUE9 (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_VALUE_9) +#define SHADOW_VALUE10 (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_VALUE_10) +#define SHADOW_VALUE11 (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_VALUE_11) +#define SHADOW_VALUE12 (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_VALUE_12) +#define SHADOW_VALUE13 (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_VALUE_13) +#define SHADOW_VALUE14 (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_VALUE_14) +#define SHADOW_VALUE15 (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_VALUE_15) +#define SHADOW_VALUE16 (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_VALUE_16) +#define SHADOW_VALUE17 (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_VALUE_17) +#define SHADOW_VALUE18 (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_VALUE_18) +#define SHADOW_VALUE19 (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_VALUE_19) +#define SHADOW_VALUE20 (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_VALUE_20) +#define SHADOW_VALUE21 (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_VALUE_21) +#define SHADOW_VALUE22 (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_VALUE_22) +#define SHADOW_VALUE23 (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_VALUE_23) +#define SHADOW_ADDRESS0 (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_ADDRESS_0) +#define SHADOW_ADDRESS1 (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_ADDRESS_1) +#define SHADOW_ADDRESS2 (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_ADDRESS_2) +#define SHADOW_ADDRESS3 (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_ADDRESS_3) +#define SHADOW_ADDRESS4 (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_ADDRESS_4) +#define SHADOW_ADDRESS5 (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_ADDRESS_5) +#define SHADOW_ADDRESS6 (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_ADDRESS_6) +#define SHADOW_ADDRESS7 (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_ADDRESS_7) +#define SHADOW_ADDRESS8 (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_ADDRESS_8) +#define SHADOW_ADDRESS9 (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_ADDRESS_9) +#define SHADOW_ADDRESS10 (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_ADDRESS_10) +#define SHADOW_ADDRESS11 (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_ADDRESS_11) +#define SHADOW_ADDRESS12 (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_ADDRESS_12) +#define SHADOW_ADDRESS13 (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_ADDRESS_13) +#define SHADOW_ADDRESS14 (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_ADDRESS_14) +#define SHADOW_ADDRESS15 (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_ADDRESS_15) +#define SHADOW_ADDRESS16 (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_ADDRESS_16) +#define SHADOW_ADDRESS17 (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_ADDRESS_17) +#define SHADOW_ADDRESS18 (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_ADDRESS_18) +#define SHADOW_ADDRESS19 (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_ADDRESS_19) +#define SHADOW_ADDRESS20 (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_ADDRESS_20) +#define SHADOW_ADDRESS21 (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_ADDRESS_21) +#define SHADOW_ADDRESS22 (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_ADDRESS_22) +#define SHADOW_ADDRESS23 (scn->host_shadow_regs->d_A_LOCAL_SHADOW_REG_ADDRESS_23) + +#define SHADOW_ADDRESS(i) (SHADOW_ADDRESS0 + i*(SHADOW_ADDRESS1-SHADOW_ADDRESS0)) + +#define HOST_IS_SRC_RING_HIGH_WATERMARK_MASK \ + (scn->target_ce_def->d_HOST_IS_SRC_RING_HIGH_WATERMARK_MASK) +#define HOST_IS_SRC_RING_LOW_WATERMARK_MASK \ + (scn->target_ce_def->d_HOST_IS_SRC_RING_LOW_WATERMARK_MASK) +#define HOST_IS_DST_RING_HIGH_WATERMARK_MASK \ + (scn->target_ce_def->d_HOST_IS_DST_RING_HIGH_WATERMARK_MASK) +#define HOST_IS_DST_RING_LOW_WATERMARK_MASK \ + (scn->target_ce_def->d_HOST_IS_DST_RING_LOW_WATERMARK_MASK) +#define MISC_IS_ADDRESS (scn->target_ce_def->d_MISC_IS_ADDRESS) +#define HOST_IS_COPY_COMPLETE_MASK \ + (scn->target_ce_def->d_HOST_IS_COPY_COMPLETE_MASK) +#define CE_WRAPPER_BASE_ADDRESS (scn->target_ce_def->d_CE_WRAPPER_BASE_ADDRESS) +#define CE_WRAPPER_INTERRUPT_SUMMARY_ADDRESS \ + (scn->target_ce_def->d_CE_WRAPPER_INTERRUPT_SUMMARY_ADDRESS) +#define CE_DDR_ADDRESS_FOR_RRI_LOW \ + (scn->target_ce_def->d_CE_DDR_ADDRESS_FOR_RRI_LOW) +#define CE_DDR_ADDRESS_FOR_RRI_HIGH \ + (scn->target_ce_def->d_CE_DDR_ADDRESS_FOR_RRI_HIGH) +#define HOST_IE_COPY_COMPLETE_MASK \ + (scn->target_ce_def->d_HOST_IE_COPY_COMPLETE_MASK) +#define SR_BA_ADDRESS (scn->target_ce_def->d_SR_BA_ADDRESS) +#define SR_BA_ADDRESS_HIGH (scn->target_ce_def->d_SR_BA_ADDRESS_HIGH) +#define SR_SIZE_ADDRESS (scn->target_ce_def->d_SR_SIZE_ADDRESS) +#define CE_CTRL1_ADDRESS (scn->target_ce_def->d_CE_CTRL1_ADDRESS) +#define CE_CTRL1_DMAX_LENGTH_MASK \ + (scn->target_ce_def->d_CE_CTRL1_DMAX_LENGTH_MASK) +#define DR_BA_ADDRESS (scn->target_ce_def->d_DR_BA_ADDRESS) +#define DR_BA_ADDRESS_HIGH (scn->target_ce_def->d_DR_BA_ADDRESS_HIGH) +#define DR_SIZE_ADDRESS (scn->target_ce_def->d_DR_SIZE_ADDRESS) +#define CE_CMD_REGISTER (scn->target_ce_def->d_CE_CMD_REGISTER) +#define CE_MSI_ADDRESS (scn->target_ce_def->d_CE_MSI_ADDRESS) +#define CE_MSI_ADDRESS_HIGH (scn->target_ce_def->d_CE_MSI_ADDRESS_HIGH) +#define CE_MSI_DATA (scn->target_ce_def->d_CE_MSI_DATA) +#define CE_MSI_ENABLE_BIT (scn->target_ce_def->d_CE_MSI_ENABLE_BIT) +#define MISC_IE_ADDRESS (scn->target_ce_def->d_MISC_IE_ADDRESS) +#define MISC_IS_AXI_ERR_MASK (scn->target_ce_def->d_MISC_IS_AXI_ERR_MASK) +#define MISC_IS_DST_ADDR_ERR_MASK \ + (scn->target_ce_def->d_MISC_IS_DST_ADDR_ERR_MASK) +#define MISC_IS_SRC_LEN_ERR_MASK \ + (scn->target_ce_def->d_MISC_IS_SRC_LEN_ERR_MASK) +#define MISC_IS_DST_MAX_LEN_VIO_MASK \ + (scn->target_ce_def->d_MISC_IS_DST_MAX_LEN_VIO_MASK) +#define MISC_IS_DST_RING_OVERFLOW_MASK \ + (scn->target_ce_def->d_MISC_IS_DST_RING_OVERFLOW_MASK) +#define MISC_IS_SRC_RING_OVERFLOW_MASK \ + (scn->target_ce_def->d_MISC_IS_SRC_RING_OVERFLOW_MASK) +#define SRC_WATERMARK_LOW_LSB (scn->target_ce_def->d_SRC_WATERMARK_LOW_LSB) +#define SRC_WATERMARK_HIGH_LSB (scn->target_ce_def->d_SRC_WATERMARK_HIGH_LSB) +#define DST_WATERMARK_LOW_LSB (scn->target_ce_def->d_DST_WATERMARK_LOW_LSB) +#define DST_WATERMARK_HIGH_LSB (scn->target_ce_def->d_DST_WATERMARK_HIGH_LSB) +#define CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_MASK \ + (scn->target_ce_def->d_CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_MASK) +#define CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_LSB \ + (scn->target_ce_def->d_CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_LSB) +#define CE_CTRL1_DMAX_LENGTH_LSB (scn->target_ce_def->d_CE_CTRL1_DMAX_LENGTH_LSB) +#define CE_CTRL1_IDX_UPD_EN (scn->target_ce_def->d_CE_CTRL1_IDX_UPD_EN_MASK) +#define CE_CTRL1_SRC_RING_BYTE_SWAP_EN_MASK \ + (scn->target_ce_def->d_CE_CTRL1_SRC_RING_BYTE_SWAP_EN_MASK) +#define CE_CTRL1_DST_RING_BYTE_SWAP_EN_MASK \ + (scn->target_ce_def->d_CE_CTRL1_DST_RING_BYTE_SWAP_EN_MASK) +#define CE_CTRL1_SRC_RING_BYTE_SWAP_EN_LSB \ + (scn->target_ce_def->d_CE_CTRL1_SRC_RING_BYTE_SWAP_EN_LSB) +#define CE_CTRL1_DST_RING_BYTE_SWAP_EN_LSB \ + (scn->target_ce_def->d_CE_CTRL1_DST_RING_BYTE_SWAP_EN_LSB) +#define WLAN_DEBUG_INPUT_SEL_OFFSET \ + (scn->targetdef->d_WLAN_DEBUG_INPUT_SEL_OFFSET) +#define WLAN_DEBUG_INPUT_SEL_SRC_MSB \ + (scn->targetdef->d_WLAN_DEBUG_INPUT_SEL_SRC_MSB) +#define WLAN_DEBUG_INPUT_SEL_SRC_LSB \ + (scn->targetdef->d_WLAN_DEBUG_INPUT_SEL_SRC_LSB) +#define WLAN_DEBUG_INPUT_SEL_SRC_MASK \ + (scn->targetdef->d_WLAN_DEBUG_INPUT_SEL_SRC_MASK) +#define WLAN_DEBUG_CONTROL_OFFSET (scn->targetdef->d_WLAN_DEBUG_CONTROL_OFFSET) +#define WLAN_DEBUG_CONTROL_ENABLE_MSB \ + (scn->targetdef->d_WLAN_DEBUG_CONTROL_ENABLE_MSB) +#define WLAN_DEBUG_CONTROL_ENABLE_LSB \ + (scn->targetdef->d_WLAN_DEBUG_CONTROL_ENABLE_LSB) +#define WLAN_DEBUG_CONTROL_ENABLE_MASK \ + (scn->targetdef->d_WLAN_DEBUG_CONTROL_ENABLE_MASK) +#define WLAN_DEBUG_OUT_OFFSET (scn->targetdef->d_WLAN_DEBUG_OUT_OFFSET) +#define WLAN_DEBUG_OUT_DATA_MSB (scn->targetdef->d_WLAN_DEBUG_OUT_DATA_MSB) +#define WLAN_DEBUG_OUT_DATA_LSB (scn->targetdef->d_WLAN_DEBUG_OUT_DATA_LSB) +#define WLAN_DEBUG_OUT_DATA_MASK (scn->targetdef->d_WLAN_DEBUG_OUT_DATA_MASK) +#define AMBA_DEBUG_BUS_OFFSET (scn->targetdef->d_AMBA_DEBUG_BUS_OFFSET) +#define AMBA_DEBUG_BUS_PCIE_DEBUG_SEL_MSB \ + (scn->targetdef->d_AMBA_DEBUG_BUS_PCIE_DEBUG_SEL_MSB) +#define AMBA_DEBUG_BUS_PCIE_DEBUG_SEL_LSB \ + (scn->targetdef->d_AMBA_DEBUG_BUS_PCIE_DEBUG_SEL_LSB) +#define AMBA_DEBUG_BUS_PCIE_DEBUG_SEL_MASK \ + (scn->targetdef->d_AMBA_DEBUG_BUS_PCIE_DEBUG_SEL_MASK) +#define AMBA_DEBUG_BUS_SEL_MSB (scn->targetdef->d_AMBA_DEBUG_BUS_SEL_MSB) +#define AMBA_DEBUG_BUS_SEL_LSB (scn->targetdef->d_AMBA_DEBUG_BUS_SEL_LSB) +#define AMBA_DEBUG_BUS_SEL_MASK (scn->targetdef->d_AMBA_DEBUG_BUS_SEL_MASK) +#define CE_WRAPPER_DEBUG_OFFSET (scn->target_ce_def->d_CE_WRAPPER_DEBUG_OFFSET) +#define CE_WRAPPER_DEBUG_SEL_MSB (scn->target_ce_def->d_CE_WRAPPER_DEBUG_SEL_MSB) +#define CE_WRAPPER_DEBUG_SEL_LSB (scn->target_ce_def->d_CE_WRAPPER_DEBUG_SEL_LSB) +#define CE_WRAPPER_DEBUG_SEL_MASK (scn->target_ce_def->d_CE_WRAPPER_DEBUG_SEL_MASK) +#define CE_DEBUG_OFFSET (scn->target_ce_def->d_CE_DEBUG_OFFSET) +#define CE_DEBUG_SEL_MSB (scn->target_ce_def->d_CE_DEBUG_SEL_MSB) +#define CE_DEBUG_SEL_LSB (scn->target_ce_def->d_CE_DEBUG_SEL_LSB) +#define CE_DEBUG_SEL_MASK (scn->target_ce_def->d_CE_DEBUG_SEL_MASK) +#define HOST_IE_ADDRESS (scn->target_ce_def->d_HOST_IE_ADDRESS) +#define HOST_IS_ADDRESS (scn->target_ce_def->d_HOST_IS_ADDRESS) + +#define SRC_WATERMARK_LOW_SET(x) \ + (((x) << SRC_WATERMARK_LOW_LSB) & SRC_WATERMARK_LOW_MASK) +#define SRC_WATERMARK_HIGH_SET(x) \ + (((x) << SRC_WATERMARK_HIGH_LSB) & SRC_WATERMARK_HIGH_MASK) +#define DST_WATERMARK_LOW_SET(x) \ + (((x) << DST_WATERMARK_LOW_LSB) & DST_WATERMARK_LOW_MASK) +#define DST_WATERMARK_HIGH_SET(x) \ + (((x) << DST_WATERMARK_HIGH_LSB) & DST_WATERMARK_HIGH_MASK) +#define CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_GET(x) \ + (((x) & CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_MASK) >> \ + CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_LSB) +#define CE_CTRL1_DMAX_LENGTH_SET(x) \ + (((x) << CE_CTRL1_DMAX_LENGTH_LSB) & CE_CTRL1_DMAX_LENGTH_MASK) +#define CE_CTRL1_SRC_RING_BYTE_SWAP_EN_SET(x) \ + (((x) << CE_CTRL1_SRC_RING_BYTE_SWAP_EN_LSB) & \ + CE_CTRL1_SRC_RING_BYTE_SWAP_EN_MASK) +#define CE_CTRL1_DST_RING_BYTE_SWAP_EN_SET(x) \ + (((x) << CE_CTRL1_DST_RING_BYTE_SWAP_EN_LSB) & \ + CE_CTRL1_DST_RING_BYTE_SWAP_EN_MASK) +#define WLAN_DEBUG_INPUT_SEL_SRC_GET(x) \ + (((x) & WLAN_DEBUG_INPUT_SEL_SRC_MASK) >> \ + WLAN_DEBUG_INPUT_SEL_SRC_LSB) +#define WLAN_DEBUG_INPUT_SEL_SRC_SET(x) \ + (((x) << WLAN_DEBUG_INPUT_SEL_SRC_LSB) & \ + WLAN_DEBUG_INPUT_SEL_SRC_MASK) +#define WLAN_DEBUG_CONTROL_ENABLE_GET(x) \ + (((x) & WLAN_DEBUG_CONTROL_ENABLE_MASK) >> \ + WLAN_DEBUG_CONTROL_ENABLE_LSB) +#define WLAN_DEBUG_CONTROL_ENABLE_SET(x) \ + (((x) << WLAN_DEBUG_CONTROL_ENABLE_LSB) & \ + WLAN_DEBUG_CONTROL_ENABLE_MASK) +#define WLAN_DEBUG_OUT_DATA_GET(x) \ + (((x) & WLAN_DEBUG_OUT_DATA_MASK) >> WLAN_DEBUG_OUT_DATA_LSB) +#define WLAN_DEBUG_OUT_DATA_SET(x) \ + (((x) << WLAN_DEBUG_OUT_DATA_LSB) & WLAN_DEBUG_OUT_DATA_MASK) +#define AMBA_DEBUG_BUS_PCIE_DEBUG_SEL_GET(x) \ + (((x) & AMBA_DEBUG_BUS_PCIE_DEBUG_SEL_MASK) >> \ + AMBA_DEBUG_BUS_PCIE_DEBUG_SEL_LSB) +#define AMBA_DEBUG_BUS_PCIE_DEBUG_SEL_SET(x) \ + (((x) << AMBA_DEBUG_BUS_PCIE_DEBUG_SEL_LSB) & \ + AMBA_DEBUG_BUS_PCIE_DEBUG_SEL_MASK) +#define AMBA_DEBUG_BUS_SEL_GET(x) \ + (((x) & AMBA_DEBUG_BUS_SEL_MASK) >> AMBA_DEBUG_BUS_SEL_LSB) +#define AMBA_DEBUG_BUS_SEL_SET(x) \ + (((x) << AMBA_DEBUG_BUS_SEL_LSB) & AMBA_DEBUG_BUS_SEL_MASK) +#define CE_WRAPPER_DEBUG_SEL_GET(x) \ + (((x) & CE_WRAPPER_DEBUG_SEL_MASK) >> CE_WRAPPER_DEBUG_SEL_LSB) +#define CE_WRAPPER_DEBUG_SEL_SET(x) \ + (((x) << CE_WRAPPER_DEBUG_SEL_LSB) & CE_WRAPPER_DEBUG_SEL_MASK) +#define CE_DEBUG_SEL_GET(x) (((x) & CE_DEBUG_SEL_MASK) >> CE_DEBUG_SEL_LSB) +#define CE_DEBUG_SEL_SET(x) (((x) << CE_DEBUG_SEL_LSB) & CE_DEBUG_SEL_MASK) + +uint32_t DEBUG_CE_SRC_RING_READ_IDX_GET(struct hif_softc *scn, + uint32_t CE_ctrl_addr); +uint32_t DEBUG_CE_DEST_RING_READ_IDX_GET(struct hif_softc *scn, + uint32_t CE_ctrl_addr); + +#define BITS0_TO_31(val) ((uint32_t)((uint64_t)(paddr_rri_on_ddr)\ + & (uint64_t)(0xFFFFFFFF))) +#define BITS32_TO_35(val) ((uint32_t)(((uint64_t)(paddr_rri_on_ddr)\ + & (uint64_t)(0xF00000000))>>32)) + +#define VADDR_FOR_CE(scn, CE_ctrl_addr)\ + ((scn->vaddr_rri_on_ddr) + COPY_ENGINE_ID(CE_ctrl_addr)) + +#define SRRI_FROM_DDR_ADDR(addr) ((*(addr)) & 0xFFFF) +#define DRRI_FROM_DDR_ADDR(addr) (((*(addr))>>16) & 0xFFFF) + +#define CE_SRC_RING_READ_IDX_GET_FROM_REGISTER(scn, CE_ctrl_addr) \ + A_TARGET_READ(scn, (CE_ctrl_addr) + CURRENT_SRRI_ADDRESS) +#define CE_DEST_RING_READ_IDX_GET_FROM_REGISTER(scn, CE_ctrl_addr) \ + A_TARGET_READ(scn, (CE_ctrl_addr) + CURRENT_DRRI_ADDRESS) + +#ifdef ADRASTEA_RRI_ON_DDR +#ifdef SHADOW_REG_DEBUG +#define CE_SRC_RING_READ_IDX_GET_FROM_DDR(scn, CE_ctrl_addr)\ + DEBUG_CE_SRC_RING_READ_IDX_GET(scn, CE_ctrl_addr) +#define CE_DEST_RING_READ_IDX_GET_FROM_DDR(scn, CE_ctrl_addr)\ + DEBUG_CE_DEST_RING_READ_IDX_GET(scn, CE_ctrl_addr) +#else +#define CE_SRC_RING_READ_IDX_GET_FROM_DDR(scn, CE_ctrl_addr)\ + SRRI_FROM_DDR_ADDR(VADDR_FOR_CE(scn, CE_ctrl_addr)) +#define CE_DEST_RING_READ_IDX_GET_FROM_DDR(scn, CE_ctrl_addr)\ + DRRI_FROM_DDR_ADDR(VADDR_FOR_CE(scn, CE_ctrl_addr)) +#endif + +unsigned int hif_get_src_ring_read_index(struct hif_softc *scn, + uint32_t CE_ctrl_addr); +unsigned int hif_get_dst_ring_read_index(struct hif_softc *scn, + uint32_t CE_ctrl_addr); + +#define CE_SRC_RING_READ_IDX_GET(scn, CE_ctrl_addr)\ + hif_get_src_ring_read_index(scn, CE_ctrl_addr) +#define CE_DEST_RING_READ_IDX_GET(scn, CE_ctrl_addr)\ + hif_get_dst_ring_read_index(scn, CE_ctrl_addr) +#else +#define CE_SRC_RING_READ_IDX_GET(scn, CE_ctrl_addr) \ + CE_SRC_RING_READ_IDX_GET_FROM_REGISTER(scn, CE_ctrl_addr) +#define CE_DEST_RING_READ_IDX_GET(scn, CE_ctrl_addr)\ + CE_DEST_RING_READ_IDX_GET_FROM_REGISTER(scn, CE_ctrl_addr) + +/** + * if RRI on DDR is not enabled, get idx from ddr defaults to + * using the register value & force wake must be used for + * non interrupt processing. + */ +#define CE_SRC_RING_READ_IDX_GET_FROM_DDR(scn, CE_ctrl_addr)\ + A_TARGET_READ(scn, (CE_ctrl_addr) + CURRENT_SRRI_ADDRESS) +#endif + +#define CE_SRC_RING_BASE_ADDR_SET(scn, CE_ctrl_addr, addr) \ + A_TARGET_WRITE(scn, (CE_ctrl_addr) + SR_BA_ADDRESS, (addr)) + +#define CE_SRC_RING_BASE_ADDR_HIGH_SET(scn, CE_ctrl_addr, addr) \ + A_TARGET_WRITE(scn, (CE_ctrl_addr) + SR_BA_ADDRESS_HIGH, (addr)) + +#define CE_SRC_RING_BASE_ADDR_HIGH_GET(scn, CE_ctrl_addr) \ + A_TARGET_READ(scn, (CE_ctrl_addr) + SR_BA_ADDRESS_HIGH) + +#define CE_SRC_RING_SZ_SET(scn, CE_ctrl_addr, n) \ + A_TARGET_WRITE(scn, (CE_ctrl_addr) + SR_SIZE_ADDRESS, (n)) + +#define CE_SRC_RING_DMAX_SET(scn, CE_ctrl_addr, n) \ + A_TARGET_WRITE(scn, (CE_ctrl_addr) + CE_CTRL1_ADDRESS, \ + (A_TARGET_READ(scn, (CE_ctrl_addr) + \ + CE_CTRL1_ADDRESS) & ~CE_CTRL1_DMAX_LENGTH_MASK) | \ + CE_CTRL1_DMAX_LENGTH_SET(n)) + +#define CE_IDX_UPD_EN_SET(scn, CE_ctrl_addr) \ + A_TARGET_WRITE(scn, (CE_ctrl_addr) + CE_CTRL1_ADDRESS, \ + (A_TARGET_READ(scn, (CE_ctrl_addr) + CE_CTRL1_ADDRESS) \ + | CE_CTRL1_IDX_UPD_EN)) + +#define CE_CMD_REGISTER_GET(scn, CE_ctrl_addr) \ + A_TARGET_READ(scn, (CE_ctrl_addr) + CE_CMD_REGISTER) + +#define CE_CMD_REGISTER_SET(scn, CE_ctrl_addr, n) \ + A_TARGET_WRITE(scn, (CE_ctrl_addr) + CE_CMD_REGISTER, n) + +#define CE_MSI_ADDR_LOW_SET(scn, CE_ctrl_addr, addr) \ + A_TARGET_WRITE(scn, (CE_ctrl_addr) + CE_MSI_ADDRESS, (addr)) + +#define CE_MSI_ADDR_HIGH_SET(scn, CE_ctrl_addr, addr) \ + A_TARGET_WRITE(scn, (CE_ctrl_addr) + CE_MSI_ADDRESS_HIGH, (addr)) + +#define CE_MSI_DATA_SET(scn, CE_ctrl_addr, data) \ + A_TARGET_WRITE(scn, (CE_ctrl_addr) + CE_MSI_DATA, (data)) + +#define CE_CTRL_REGISTER1_SET(scn, CE_ctrl_addr, val) \ + A_TARGET_WRITE(scn, (CE_ctrl_addr) + CE_CTRL1_ADDRESS, val) + +#define CE_CTRL_REGISTER1_GET(scn, CE_ctrl_addr) \ + A_TARGET_READ(scn, (CE_ctrl_addr) + CE_CTRL1_ADDRESS) + +#define CE_SRC_RING_BYTE_SWAP_SET(scn, CE_ctrl_addr, n) \ + A_TARGET_WRITE(scn, (CE_ctrl_addr) + CE_CTRL1_ADDRESS, \ + (A_TARGET_READ(scn, \ + (CE_ctrl_addr) + CE_CTRL1_ADDRESS) \ + & ~CE_CTRL1_SRC_RING_BYTE_SWAP_EN_MASK) | \ + CE_CTRL1_SRC_RING_BYTE_SWAP_EN_SET(n)) + +#define CE_DEST_RING_BYTE_SWAP_SET(scn, CE_ctrl_addr, n) \ + A_TARGET_WRITE(scn, (CE_ctrl_addr)+CE_CTRL1_ADDRESS, \ + (A_TARGET_READ(scn, \ + (CE_ctrl_addr) + CE_CTRL1_ADDRESS) \ + & ~CE_CTRL1_DST_RING_BYTE_SWAP_EN_MASK) | \ + CE_CTRL1_DST_RING_BYTE_SWAP_EN_SET(n)) + + +#define CE_DEST_RING_BASE_ADDR_SET(scn, CE_ctrl_addr, addr) \ + A_TARGET_WRITE(scn, (CE_ctrl_addr) + DR_BA_ADDRESS, (addr)) + +#define CE_DEST_RING_BASE_ADDR_HIGH_SET(scn, CE_ctrl_addr, addr) \ + A_TARGET_WRITE(scn, (CE_ctrl_addr) + DR_BA_ADDRESS_HIGH, (addr)) + +#define CE_DEST_RING_BASE_ADDR_HIGH_GET(scn, CE_ctrl_addr) \ + A_TARGET_READ(scn, (CE_ctrl_addr) + DR_BA_ADDRESS_HIGH) + +#define CE_DEST_RING_SZ_SET(scn, CE_ctrl_addr, n) \ + A_TARGET_WRITE(scn, (CE_ctrl_addr) + DR_SIZE_ADDRESS, (n)) + +#define CE_SRC_RING_HIGHMARK_SET(scn, CE_ctrl_addr, n) \ + A_TARGET_WRITE(scn, (CE_ctrl_addr) + SRC_WATERMARK_ADDRESS, \ + (A_TARGET_READ(scn, \ + (CE_ctrl_addr) + SRC_WATERMARK_ADDRESS) \ + & ~SRC_WATERMARK_HIGH_MASK) | \ + SRC_WATERMARK_HIGH_SET(n)) + +#define CE_SRC_RING_LOWMARK_SET(scn, CE_ctrl_addr, n) \ + A_TARGET_WRITE(scn, (CE_ctrl_addr) + SRC_WATERMARK_ADDRESS, \ + (A_TARGET_READ(scn, \ + (CE_ctrl_addr) + SRC_WATERMARK_ADDRESS) \ + & ~SRC_WATERMARK_LOW_MASK) | \ + SRC_WATERMARK_LOW_SET(n)) + +#define CE_DEST_RING_HIGHMARK_SET(scn, CE_ctrl_addr, n) \ + A_TARGET_WRITE(scn, (CE_ctrl_addr) + DST_WATERMARK_ADDRESS, \ + (A_TARGET_READ(scn, \ + (CE_ctrl_addr) + DST_WATERMARK_ADDRESS) \ + & ~DST_WATERMARK_HIGH_MASK) | \ + DST_WATERMARK_HIGH_SET(n)) + +#define CE_DEST_RING_LOWMARK_SET(scn, CE_ctrl_addr, n) \ + A_TARGET_WRITE(scn, (CE_ctrl_addr) + DST_WATERMARK_ADDRESS, \ + (A_TARGET_READ(scn, \ + (CE_ctrl_addr) + DST_WATERMARK_ADDRESS) \ + & ~DST_WATERMARK_LOW_MASK) | \ + DST_WATERMARK_LOW_SET(n)) + +#define CE_COPY_COMPLETE_INTR_ENABLE(scn, CE_ctrl_addr) \ + A_TARGET_WRITE(scn, (CE_ctrl_addr) + HOST_IE_ADDRESS, \ + A_TARGET_READ(scn, \ + (CE_ctrl_addr) + HOST_IE_ADDRESS) | \ + HOST_IE_COPY_COMPLETE_MASK) + +#define CE_COPY_COMPLETE_INTR_DISABLE(scn, CE_ctrl_addr) \ + A_TARGET_WRITE(scn, (CE_ctrl_addr) + HOST_IE_ADDRESS, \ + A_TARGET_READ(scn, \ + (CE_ctrl_addr) + HOST_IE_ADDRESS) \ + & ~HOST_IE_COPY_COMPLETE_MASK) + +#define CE_BASE_ADDRESS(CE_id) \ + CE0_BASE_ADDRESS + ((CE1_BASE_ADDRESS - \ + CE0_BASE_ADDRESS)*(CE_id)) + +#define CE_WATERMARK_INTR_ENABLE(scn, CE_ctrl_addr) \ + A_TARGET_WRITE(scn, (CE_ctrl_addr) + HOST_IE_ADDRESS, \ + A_TARGET_READ(scn, \ + (CE_ctrl_addr) + HOST_IE_ADDRESS) | \ + CE_WATERMARK_MASK) + +#define CE_WATERMARK_INTR_DISABLE(scn, CE_ctrl_addr) \ + A_TARGET_WRITE(scn, (CE_ctrl_addr) + HOST_IE_ADDRESS, \ + A_TARGET_READ(scn, \ + (CE_ctrl_addr) + HOST_IE_ADDRESS) \ + & ~CE_WATERMARK_MASK) + +#define CE_ERROR_INTR_ENABLE(scn, CE_ctrl_addr) \ + A_TARGET_WRITE(scn, (CE_ctrl_addr) + MISC_IE_ADDRESS, \ + A_TARGET_READ(scn, \ + (CE_ctrl_addr) + MISC_IE_ADDRESS) | CE_ERROR_MASK) + +#define CE_MISC_INT_STATUS_GET(scn, CE_ctrl_addr) \ + A_TARGET_READ(scn, (CE_ctrl_addr) + MISC_IS_ADDRESS) + +#define CE_ENGINE_INT_STATUS_GET(scn, CE_ctrl_addr) \ + A_TARGET_READ(scn, (CE_ctrl_addr) + HOST_IS_ADDRESS) + +#define CE_ENGINE_INT_STATUS_CLEAR(scn, CE_ctrl_addr, mask) \ + A_TARGET_WRITE(scn, (CE_ctrl_addr) + HOST_IS_ADDRESS, (mask)) + +#define CE_WATERMARK_MASK (HOST_IS_SRC_RING_LOW_WATERMARK_MASK | \ + HOST_IS_SRC_RING_HIGH_WATERMARK_MASK | \ + HOST_IS_DST_RING_LOW_WATERMARK_MASK | \ + HOST_IS_DST_RING_HIGH_WATERMARK_MASK) + +#define CE_ERROR_MASK (MISC_IS_AXI_ERR_MASK | \ + MISC_IS_DST_ADDR_ERR_MASK | \ + MISC_IS_SRC_LEN_ERR_MASK | \ + MISC_IS_DST_MAX_LEN_VIO_MASK | \ + MISC_IS_DST_RING_OVERFLOW_MASK | \ + MISC_IS_SRC_RING_OVERFLOW_MASK) + +#define CE_SRC_RING_TO_DESC(baddr, idx) \ + (&(((struct CE_src_desc *)baddr)[idx])) +#define CE_DEST_RING_TO_DESC(baddr, idx) \ + (&(((struct CE_dest_desc *)baddr)[idx])) + +/* Ring arithmetic (modulus number of entries in ring, which is a pwr of 2). */ +#define CE_RING_DELTA(nentries_mask, fromidx, toidx) \ + (((int)(toidx)-(int)(fromidx)) & (nentries_mask)) + +#define CE_RING_IDX_INCR(nentries_mask, idx) \ + (((idx) + 1) & (nentries_mask)) + +#define CE_RING_IDX_ADD(nentries_mask, idx, num) \ + (((idx) + (num)) & (nentries_mask)) + +#define CE_INTERRUPT_SUMMARY(scn) \ + CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_GET( \ + A_TARGET_READ(scn, CE_WRAPPER_BASE_ADDRESS + \ + CE_WRAPPER_INTERRUPT_SUMMARY_ADDRESS)) + +#define READ_CE_DDR_ADDRESS_FOR_RRI_LOW(scn) \ + (A_TARGET_READ(scn, \ + CE_WRAPPER_BASE_ADDRESS + CE_DDR_ADDRESS_FOR_RRI_LOW)) + +#define READ_CE_DDR_ADDRESS_FOR_RRI_HIGH(scn) \ + (A_TARGET_READ(scn, \ + CE_WRAPPER_BASE_ADDRESS + CE_DDR_ADDRESS_FOR_RRI_HIGH)) + +#define WRITE_CE_DDR_ADDRESS_FOR_RRI_LOW(scn, val) \ + (A_TARGET_WRITE(scn, \ + CE_WRAPPER_BASE_ADDRESS + CE_DDR_ADDRESS_FOR_RRI_LOW, \ + val)) + +#define WRITE_CE_DDR_ADDRESS_FOR_RRI_HIGH(scn, val) \ + (A_TARGET_WRITE(scn, \ + CE_WRAPPER_BASE_ADDRESS + CE_DDR_ADDRESS_FOR_RRI_HIGH, \ + val)) + +/*Macro to increment CE packet errors*/ +#define OL_ATH_CE_PKT_ERROR_COUNT_INCR(_scn, _ce_ecode) \ + do { if (_ce_ecode == CE_RING_DELTA_FAIL) \ + (_scn->pkt_stats.ce_ring_delta_fail_count) \ + += 1; } while (0) + +/* Given a Copy Engine's ID, determine the interrupt number for that + * copy engine's interrupts. + */ +#define CE_ID_TO_INUM(id) (A_INUM_CE0_COPY_COMP_BASE + (id)) +#define CE_INUM_TO_ID(inum) ((inum) - A_INUM_CE0_COPY_COMP_BASE) +#define CE0_BASE_ADDRESS (scn->target_ce_def->d_CE0_BASE_ADDRESS) +#define CE1_BASE_ADDRESS (scn->target_ce_def->d_CE1_BASE_ADDRESS) + + +#ifdef ADRASTEA_SHADOW_REGISTERS +#define NUM_SHADOW_REGISTERS 24 +u32 shadow_sr_wr_ind_addr(struct hif_softc *scn, u32 ctrl_addr); +u32 shadow_dst_wr_ind_addr(struct hif_softc *scn, u32 ctrl_addr); +#endif + + +#ifdef ADRASTEA_SHADOW_REGISTERS +#define CE_SRC_RING_WRITE_IDX_SET(scn, CE_ctrl_addr, n) \ + A_TARGET_WRITE(scn, shadow_sr_wr_ind_addr(scn, CE_ctrl_addr), n) +#define CE_DEST_RING_WRITE_IDX_SET(scn, CE_ctrl_addr, n) \ + A_TARGET_WRITE(scn, shadow_dst_wr_ind_addr(scn, CE_ctrl_addr), n) + +#else + +#define CE_SRC_RING_WRITE_IDX_SET(scn, CE_ctrl_addr, n) \ + A_TARGET_WRITE(scn, (CE_ctrl_addr) + SR_WR_INDEX_ADDRESS, (n)) +#define CE_DEST_RING_WRITE_IDX_SET(scn, CE_ctrl_addr, n) \ + A_TARGET_WRITE(scn, (CE_ctrl_addr) + DST_WR_INDEX_ADDRESS, (n)) +#endif + +/* The write index read is only needed durring initialization because + * we keep track of the index that was last written. Thus the register + * is the only hardware supported location to read the initial value from. + */ +#define CE_SRC_RING_WRITE_IDX_GET_FROM_REGISTER(scn, CE_ctrl_addr) \ + A_TARGET_READ(scn, (CE_ctrl_addr) + SR_WR_INDEX_ADDRESS) +#define CE_DEST_RING_WRITE_IDX_GET_FROM_REGISTER(scn, CE_ctrl_addr) \ + A_TARGET_READ(scn, (CE_ctrl_addr) + DST_WR_INDEX_ADDRESS) + +#endif /* __CE_REG_H__ */ diff --git a/drivers/staging/qca-wifi-host-cmn/hif/src/ce/ce_service.c b/drivers/staging/qca-wifi-host-cmn/hif/src/ce/ce_service.c new file mode 100644 index 0000000000000000000000000000000000000000..84669c2308ab61f787ccd684865a8f9e6cc7b195 --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/hif/src/ce/ce_service.c @@ -0,0 +1,2334 @@ +/* + * Copyright (c) 2013-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#include "hif.h" +#include "hif_io32.h" +#include "ce_api.h" +#include "ce_main.h" +#include "ce_internal.h" +#include "ce_reg.h" +#include "qdf_lock.h" +#include "regtable.h" +#include "hif_main.h" +#include "hif_debug.h" +#include "hif_napi.h" + +#ifdef IPA_OFFLOAD +#ifdef QCA_WIFI_3_0 +#define CE_IPA_RING_INIT(ce_desc) \ + do { \ + ce_desc->gather = 0; \ + ce_desc->enable_11h = 0; \ + ce_desc->meta_data_low = 0; \ + ce_desc->packet_result_offset = 64; \ + ce_desc->toeplitz_hash_enable = 0; \ + ce_desc->addr_y_search_disable = 0; \ + ce_desc->addr_x_search_disable = 0; \ + ce_desc->misc_int_disable = 0; \ + ce_desc->target_int_disable = 0; \ + ce_desc->host_int_disable = 0; \ + ce_desc->dest_byte_swap = 0; \ + ce_desc->byte_swap = 0; \ + ce_desc->type = 2; \ + ce_desc->tx_classify = 1; \ + ce_desc->buffer_addr_hi = 0; \ + ce_desc->meta_data = 0; \ + ce_desc->nbytes = 128; \ + } while (0) +#else +#define CE_IPA_RING_INIT(ce_desc) \ + do { \ + ce_desc->byte_swap = 0; \ + ce_desc->nbytes = 60; \ + ce_desc->gather = 0; \ + } while (0) +#endif /* QCA_WIFI_3_0 */ +#endif /* IPA_OFFLOAD */ + +static int war1_allow_sleep; +/* io32 write workaround */ +static int hif_ce_war1; + +/** + * hif_ce_war_disable() - disable ce war gobally + */ +void hif_ce_war_disable(void) +{ + hif_ce_war1 = 0; +} + +/** + * hif_ce_war_enable() - enable ce war gobally + */ +void hif_ce_war_enable(void) +{ + hif_ce_war1 = 1; +} + +#ifdef CONFIG_SLUB_DEBUG_ON + +/** + * struct hif_ce_event - structure for detailing a ce event + * @type: what the event was + * @time: when it happened + * @descriptor: descriptor enqueued or dequeued + * @memory: virtual address that was used + * @index: location of the descriptor in the ce ring; + */ +struct hif_ce_desc_event { + uint16_t index; + enum hif_ce_event_type type; + uint64_t time; + union ce_desc descriptor; + void *memory; +}; + +/* max history to record per copy engine */ +#define HIF_CE_HISTORY_MAX 512 +qdf_atomic_t hif_ce_desc_history_index[CE_COUNT_MAX]; +struct hif_ce_desc_event hif_ce_desc_history[CE_COUNT_MAX][HIF_CE_HISTORY_MAX]; + + +/** + * get_next_record_index() - get the next record index + * @table_index: atomic index variable to increment + * @array_size: array size of the circular buffer + * + * Increment the atomic index and reserve the value. + * Takes care of buffer wrap. + * Guaranteed to be thread safe as long as fewer than array_size contexts + * try to access the array. If there are more than array_size contexts + * trying to access the array, full locking of the recording process would + * be needed to have sane logging. + */ +static int get_next_record_index(qdf_atomic_t *table_index, int array_size) +{ + int record_index = qdf_atomic_inc_return(table_index); + if (record_index == array_size) + qdf_atomic_sub(array_size, table_index); + + while (record_index >= array_size) + record_index -= array_size; + return record_index; +} + +/** + * hif_record_ce_desc_event() - record ce descriptor events + * @scn: hif_softc + * @ce_id: which ce is the event occuring on + * @type: what happened + * @descriptor: pointer to the descriptor posted/completed + * @memory: virtual address of buffer related to the descriptor + * @index: index that the descriptor was/will be at. + */ +void hif_record_ce_desc_event(struct hif_softc *scn, int ce_id, + enum hif_ce_event_type type, + union ce_desc *descriptor, + void *memory, int index) +{ + int record_index = get_next_record_index( + &hif_ce_desc_history_index[ce_id], HIF_CE_HISTORY_MAX); + + struct hif_ce_desc_event *event = + &hif_ce_desc_history[ce_id][record_index]; + event->type = type; + event->time = qdf_get_log_timestamp(); + + if (descriptor != NULL) + event->descriptor = *descriptor; + else + memset(&event->descriptor, 0, sizeof(union ce_desc)); + event->memory = memory; + event->index = index; +} + +/** + * ce_init_ce_desc_event_log() - initialize the ce event log + * @ce_id: copy engine id for which we are initializing the log + * @size: size of array to dedicate + * + * Currently the passed size is ignored in favor of a precompiled value. + */ +void ce_init_ce_desc_event_log(int ce_id, int size) +{ + qdf_atomic_init(&hif_ce_desc_history_index[ce_id]); +} +#else +void hif_record_ce_desc_event(struct hif_softc *scn, + int ce_id, enum hif_ce_event_type type, + union ce_desc *descriptor, void *memory, + int index) +{ +} + +inline void ce_init_ce_desc_event_log(int ce_id, int size) +{ +} +#endif + +/** + * hif_ce_service_should_yield() - return true if the service is hogging the cpu + * @scn: hif context + * @ce_state: context of the copy engine being serviced + * + * Return: true if the service should yield + */ +bool hif_ce_service_should_yield(struct hif_softc *scn, + struct CE_state *ce_state) +{ + bool yield, time_limit_reached, rxpkt_thresh_reached = 0; + + time_limit_reached = + sched_clock() > ce_state->ce_service_yield_time ? 1 : 0; + + if (!time_limit_reached) + rxpkt_thresh_reached = hif_max_num_receives_reached + (scn, ce_state->receive_count); + + yield = time_limit_reached || rxpkt_thresh_reached; + + if (yield) + hif_napi_update_yield_stats(ce_state, + time_limit_reached, + rxpkt_thresh_reached); + return yield; +} + +/* + * Support for Copy Engine hardware, which is mainly used for + * communication between Host and Target over a PCIe interconnect. + */ + +/* + * A single CopyEngine (CE) comprises two "rings": + * a source ring + * a destination ring + * + * Each ring consists of a number of descriptors which specify + * an address, length, and meta-data. + * + * Typically, one side of the PCIe interconnect (Host or Target) + * controls one ring and the other side controls the other ring. + * The source side chooses when to initiate a transfer and it + * chooses what to send (buffer address, length). The destination + * side keeps a supply of "anonymous receive buffers" available and + * it handles incoming data as it arrives (when the destination + * recieves an interrupt). + * + * The sender may send a simple buffer (address/length) or it may + * send a small list of buffers. When a small list is sent, hardware + * "gathers" these and they end up in a single destination buffer + * with a single interrupt. + * + * There are several "contexts" managed by this layer -- more, it + * may seem -- than should be needed. These are provided mainly for + * maximum flexibility and especially to facilitate a simpler HIF + * implementation. There are per-CopyEngine recv, send, and watermark + * contexts. These are supplied by the caller when a recv, send, + * or watermark handler is established and they are echoed back to + * the caller when the respective callbacks are invoked. There is + * also a per-transfer context supplied by the caller when a buffer + * (or sendlist) is sent and when a buffer is enqueued for recv. + * These per-transfer contexts are echoed back to the caller when + * the buffer is sent/received. + * Target TX harsh result toeplitz_hash_result + */ + +/* + * Guts of ce_send, used by both ce_send and ce_sendlist_send. + * The caller takes responsibility for any needed locking. + */ +int +ce_completed_send_next_nolock(struct CE_state *CE_state, + void **per_CE_contextp, + void **per_transfer_contextp, + qdf_dma_addr_t *bufferp, + unsigned int *nbytesp, + unsigned int *transfer_idp, + unsigned int *sw_idx, unsigned int *hw_idx, + uint32_t *toeplitz_hash_result); + +static +void war_ce_src_ring_write_idx_set(struct hif_softc *scn, + u32 ctrl_addr, unsigned int write_index) +{ + if (hif_ce_war1) { + void __iomem *indicator_addr; + + indicator_addr = scn->mem + ctrl_addr + DST_WATERMARK_ADDRESS; + + if (!war1_allow_sleep + && ctrl_addr == CE_BASE_ADDRESS(CDC_WAR_DATA_CE)) { + hif_write32_mb(indicator_addr, + (CDC_WAR_MAGIC_STR | write_index)); + } else { + unsigned long irq_flags; + local_irq_save(irq_flags); + hif_write32_mb(indicator_addr, 1); + + /* + * PCIE write waits for ACK in IPQ8K, there is no + * need to read back value. + */ + (void)hif_read32_mb(indicator_addr); + (void)hif_read32_mb(indicator_addr); /* conservative */ + + CE_SRC_RING_WRITE_IDX_SET(scn, + ctrl_addr, write_index); + + hif_write32_mb(indicator_addr, 0); + local_irq_restore(irq_flags); + } + } else { + CE_SRC_RING_WRITE_IDX_SET(scn, ctrl_addr, write_index); + } +} + +#ifdef CONFIG_SLUB_DEBUG_ON +/** + * ce_validate_nbytes() - validate nbytes for slub builds on tx descriptors + * @nbytes: nbytes value being written into a send descriptor + * @ce_state: context of the copy engine + + * nbytes should be non-zero and less than max configured for the copy engine + * + * Return: none + */ +static void ce_validate_nbytes(uint32_t nbytes, struct CE_state *ce_state) +{ + if (nbytes <= 0 || nbytes > ce_state->src_sz_max) + QDF_BUG(0); +} +#else +static void ce_validate_nbytes(uint32_t nbytes, struct CE_state *ce_state) +{ +} +#endif + +static int +ce_send_nolock(struct CE_handle *copyeng, + void *per_transfer_context, + qdf_dma_addr_t buffer, + uint32_t nbytes, + uint32_t transfer_id, + uint32_t flags, + uint32_t user_flags) +{ + int status; + struct CE_state *CE_state = (struct CE_state *)copyeng; + struct CE_ring_state *src_ring = CE_state->src_ring; + uint32_t ctrl_addr = CE_state->ctrl_addr; + unsigned int nentries_mask = src_ring->nentries_mask; + unsigned int sw_index = src_ring->sw_index; + unsigned int write_index = src_ring->write_index; + uint64_t dma_addr = buffer; + struct hif_softc *scn = CE_state->scn; + + if (Q_TARGET_ACCESS_BEGIN(scn) < 0) + return QDF_STATUS_E_FAILURE; + if (unlikely(CE_RING_DELTA(nentries_mask, + write_index, sw_index - 1) <= 0)) { + OL_ATH_CE_PKT_ERROR_COUNT_INCR(scn, CE_RING_DELTA_FAIL); + Q_TARGET_ACCESS_END(scn); + return QDF_STATUS_E_FAILURE; + } + { + enum hif_ce_event_type event_type; + struct CE_src_desc *src_ring_base = + (struct CE_src_desc *)src_ring->base_addr_owner_space; + struct CE_src_desc *shadow_base = + (struct CE_src_desc *)src_ring->shadow_base; + struct CE_src_desc *src_desc = + CE_SRC_RING_TO_DESC(src_ring_base, write_index); + struct CE_src_desc *shadow_src_desc = + CE_SRC_RING_TO_DESC(shadow_base, write_index); + + /* Update low 32 bits source descriptor address */ + shadow_src_desc->buffer_addr = + (uint32_t)(dma_addr & 0xFFFFFFFF); +#ifdef QCA_WIFI_3_0 + shadow_src_desc->buffer_addr_hi = + (uint32_t)((dma_addr >> 32) & 0x1F); + user_flags |= shadow_src_desc->buffer_addr_hi; + memcpy(&(((uint32_t *)shadow_src_desc)[1]), &user_flags, + sizeof(uint32_t)); +#endif + shadow_src_desc->target_int_disable = 0; + shadow_src_desc->host_int_disable = 0; + + shadow_src_desc->meta_data = transfer_id; + + /* + * Set the swap bit if: + * typical sends on this CE are swapped (host is big-endian) + * and this send doesn't disable the swapping + * (data is not bytestream) + */ + shadow_src_desc->byte_swap = + (((CE_state->attr_flags & CE_ATTR_BYTE_SWAP_DATA) + != 0) & ((flags & CE_SEND_FLAG_SWAP_DISABLE) == 0)); + shadow_src_desc->gather = ((flags & CE_SEND_FLAG_GATHER) != 0); + shadow_src_desc->nbytes = nbytes; + ce_validate_nbytes(nbytes, CE_state); + + *src_desc = *shadow_src_desc; + + src_ring->per_transfer_context[write_index] = + per_transfer_context; + + /* Update Source Ring Write Index */ + write_index = CE_RING_IDX_INCR(nentries_mask, write_index); + + /* WORKAROUND */ + if (shadow_src_desc->gather) { + event_type = HIF_TX_GATHER_DESC_POST; + } else if (qdf_unlikely(CE_state->state != CE_RUNNING)) { + event_type = HIF_TX_DESC_SOFTWARE_POST; + CE_state->state = CE_PENDING; + } else { + event_type = HIF_TX_DESC_POST; + war_ce_src_ring_write_idx_set(scn, ctrl_addr, + write_index); + } + + /* src_ring->write index hasn't been updated event though + * the register has allready been written to. + */ + hif_record_ce_desc_event(scn, CE_state->id, event_type, + (union ce_desc *) shadow_src_desc, per_transfer_context, + src_ring->write_index); + + src_ring->write_index = write_index; + status = QDF_STATUS_SUCCESS; + } + Q_TARGET_ACCESS_END(scn); + return status; +} + +int +ce_send(struct CE_handle *copyeng, + void *per_transfer_context, + qdf_dma_addr_t buffer, + uint32_t nbytes, + uint32_t transfer_id, + uint32_t flags, + uint32_t user_flag) +{ + struct CE_state *CE_state = (struct CE_state *)copyeng; + int status; + + qdf_spin_lock_bh(&CE_state->ce_index_lock); + status = ce_send_nolock(copyeng, per_transfer_context, buffer, nbytes, + transfer_id, flags, user_flag); + qdf_spin_unlock_bh(&CE_state->ce_index_lock); + + return status; +} + +unsigned int ce_sendlist_sizeof(void) +{ + return sizeof(struct ce_sendlist); +} + +void ce_sendlist_init(struct ce_sendlist *sendlist) +{ + struct ce_sendlist_s *sl = (struct ce_sendlist_s *)sendlist; + sl->num_items = 0; +} + +int +ce_sendlist_buf_add(struct ce_sendlist *sendlist, + qdf_dma_addr_t buffer, + uint32_t nbytes, + uint32_t flags, + uint32_t user_flags) +{ + struct ce_sendlist_s *sl = (struct ce_sendlist_s *)sendlist; + unsigned int num_items = sl->num_items; + struct ce_sendlist_item *item; + + if (num_items >= CE_SENDLIST_ITEMS_MAX) { + QDF_ASSERT(num_items < CE_SENDLIST_ITEMS_MAX); + return QDF_STATUS_E_RESOURCES; + } + + item = &sl->item[num_items]; + item->send_type = CE_SIMPLE_BUFFER_TYPE; + item->data = buffer; + item->u.nbytes = nbytes; + item->flags = flags; + item->user_flags = user_flags; + sl->num_items = num_items + 1; + return QDF_STATUS_SUCCESS; +} + +int +ce_sendlist_send(struct CE_handle *copyeng, + void *per_transfer_context, + struct ce_sendlist *sendlist, unsigned int transfer_id) +{ + int status = -ENOMEM; + struct ce_sendlist_s *sl = (struct ce_sendlist_s *)sendlist; + struct CE_state *CE_state = (struct CE_state *)copyeng; + struct CE_ring_state *src_ring = CE_state->src_ring; + unsigned int nentries_mask = src_ring->nentries_mask; + unsigned int num_items = sl->num_items; + unsigned int sw_index; + unsigned int write_index; + struct hif_softc *scn = CE_state->scn; + + QDF_ASSERT((num_items > 0) && (num_items < src_ring->nentries)); + + qdf_spin_lock_bh(&CE_state->ce_index_lock); + + if (CE_state->scn->fastpath_mode_on && CE_state->htt_tx_data && + Q_TARGET_ACCESS_BEGIN(scn) == 0) { + src_ring->sw_index = CE_SRC_RING_READ_IDX_GET_FROM_DDR( + scn, CE_state->ctrl_addr); + Q_TARGET_ACCESS_END(scn); + } + + sw_index = src_ring->sw_index; + write_index = src_ring->write_index; + + if (CE_RING_DELTA(nentries_mask, write_index, sw_index - 1) >= + num_items) { + struct ce_sendlist_item *item; + int i; + + /* handle all but the last item uniformly */ + for (i = 0; i < num_items - 1; i++) { + item = &sl->item[i]; + /* TBDXXX: Support extensible sendlist_types? */ + QDF_ASSERT(item->send_type == CE_SIMPLE_BUFFER_TYPE); + status = ce_send_nolock(copyeng, CE_SENDLIST_ITEM_CTXT, + (qdf_dma_addr_t) item->data, + item->u.nbytes, transfer_id, + item->flags | CE_SEND_FLAG_GATHER, + item->user_flags); + QDF_ASSERT(status == QDF_STATUS_SUCCESS); + } + /* provide valid context pointer for final item */ + item = &sl->item[i]; + /* TBDXXX: Support extensible sendlist_types? */ + QDF_ASSERT(item->send_type == CE_SIMPLE_BUFFER_TYPE); + status = ce_send_nolock(copyeng, per_transfer_context, + (qdf_dma_addr_t) item->data, + item->u.nbytes, + transfer_id, item->flags, + item->user_flags); + QDF_ASSERT(status == QDF_STATUS_SUCCESS); + QDF_NBUF_UPDATE_TX_PKT_COUNT((qdf_nbuf_t)per_transfer_context, + QDF_NBUF_TX_PKT_CE); + DPTRACE(qdf_dp_trace((qdf_nbuf_t)per_transfer_context, + QDF_DP_TRACE_CE_PACKET_PTR_RECORD, + (uint8_t *)&(((qdf_nbuf_t)per_transfer_context)->data), + sizeof(((qdf_nbuf_t)per_transfer_context)->data), + QDF_TX)); + } else { + /* + * Probably not worth the additional complexity to support + * partial sends with continuation or notification. We expect + * to use large rings and small sendlists. If we can't handle + * the entire request at once, punt it back to the caller. + */ + } + qdf_spin_unlock_bh(&CE_state->ce_index_lock); + + return status; +} + +#ifdef WLAN_FEATURE_FASTPATH +#ifdef QCA_WIFI_3_0 +static inline void +ce_buffer_addr_hi_set(struct CE_src_desc *shadow_src_desc, + uint64_t dma_addr, + uint32_t user_flags) +{ + shadow_src_desc->buffer_addr_hi = + (uint32_t)((dma_addr >> 32) & 0x1F); + user_flags |= shadow_src_desc->buffer_addr_hi; + memcpy(&(((uint32_t *)shadow_src_desc)[1]), &user_flags, + sizeof(uint32_t)); +} +#else +static inline void +ce_buffer_addr_hi_set(struct CE_src_desc *shadow_src_desc, + uint64_t dma_addr, + uint32_t user_flags) +{ +} +#endif + +#define SLOTS_PER_DATAPATH_TX 2 + +/** + * ce_send_fast() CE layer Tx buffer posting function + * @copyeng: copy engine handle + * @msdu: msdu to be sent + * @transfer_id: transfer_id + * @download_len: packet download length + * + * Assumption : Called with an array of MSDU's + * Function: + * For each msdu in the array + * 1. Check no. of available entries + * 2. Create src ring entries (allocated in consistent memory + * 3. Write index to h/w + * + * Return: No. of packets that could be sent + */ +int ce_send_fast(struct CE_handle *copyeng, qdf_nbuf_t msdu, + unsigned int transfer_id, uint32_t download_len) +{ + struct CE_state *ce_state = (struct CE_state *)copyeng; + struct hif_softc *scn = ce_state->scn; + struct hif_opaque_softc *hif_hdl = GET_HIF_OPAQUE_HDL(scn); + struct CE_ring_state *src_ring = ce_state->src_ring; + u_int32_t ctrl_addr = ce_state->ctrl_addr; + unsigned int nentries_mask = src_ring->nentries_mask; + unsigned int write_index; + unsigned int sw_index; + unsigned int frag_len; + uint64_t dma_addr; + uint32_t user_flags; + enum hif_ce_event_type type = FAST_TX_SOFTWARE_INDEX_UPDATE; + + qdf_spin_lock_bh(&ce_state->ce_index_lock); + Q_TARGET_ACCESS_BEGIN(scn); + + src_ring->sw_index = CE_SRC_RING_READ_IDX_GET_FROM_DDR(scn, ctrl_addr); + write_index = src_ring->write_index; + sw_index = src_ring->sw_index; + + hif_record_ce_desc_event(scn, ce_state->id, + FAST_TX_SOFTWARE_INDEX_UPDATE, + NULL, NULL, sw_index); + + if (qdf_unlikely(CE_RING_DELTA(nentries_mask, write_index, sw_index - 1) + < SLOTS_PER_DATAPATH_TX)) { + HIF_ERROR("Source ring full, required %d, available %d", + SLOTS_PER_DATAPATH_TX, + CE_RING_DELTA(nentries_mask, write_index, sw_index - 1)); + OL_ATH_CE_PKT_ERROR_COUNT_INCR(scn, CE_RING_DELTA_FAIL); + Q_TARGET_ACCESS_END(scn); + qdf_spin_unlock_bh(&ce_state->ce_index_lock); + return 0; + } + + { + struct CE_src_desc *src_ring_base = + (struct CE_src_desc *)src_ring->base_addr_owner_space; + struct CE_src_desc *shadow_base = + (struct CE_src_desc *)src_ring->shadow_base; + struct CE_src_desc *src_desc = + CE_SRC_RING_TO_DESC(src_ring_base, write_index); + struct CE_src_desc *shadow_src_desc = + CE_SRC_RING_TO_DESC(shadow_base, write_index); + + hif_pm_runtime_get_noresume(hif_hdl); + + /* + * First fill out the ring descriptor for the HTC HTT frame + * header. These are uncached writes. Should we use a local + * structure instead? + */ + /* HTT/HTC header can be passed as a argument */ + dma_addr = qdf_nbuf_get_frag_paddr(msdu, 0); + shadow_src_desc->buffer_addr = (uint32_t)(dma_addr & + 0xFFFFFFFF); + user_flags = qdf_nbuf_data_attr_get(msdu) & DESC_DATA_FLAG_MASK; + ce_buffer_addr_hi_set(shadow_src_desc, dma_addr, user_flags); + shadow_src_desc->meta_data = transfer_id; + shadow_src_desc->nbytes = qdf_nbuf_get_frag_len(msdu, 0); + ce_validate_nbytes(shadow_src_desc->nbytes, ce_state); + download_len -= shadow_src_desc->nbytes; + /* + * HTC HTT header is a word stream, so byte swap if CE byte + * swap enabled + */ + shadow_src_desc->byte_swap = ((ce_state->attr_flags & + CE_ATTR_BYTE_SWAP_DATA) != 0); + /* For the first one, it still does not need to write */ + shadow_src_desc->gather = 1; + *src_desc = *shadow_src_desc; + /* By default we could initialize the transfer context to this + * value + */ + src_ring->per_transfer_context[write_index] = + CE_SENDLIST_ITEM_CTXT; + write_index = CE_RING_IDX_INCR(nentries_mask, write_index); + + src_desc = CE_SRC_RING_TO_DESC(src_ring_base, write_index); + shadow_src_desc = CE_SRC_RING_TO_DESC(shadow_base, write_index); + /* + * Now fill out the ring descriptor for the actual data + * packet + */ + dma_addr = qdf_nbuf_get_frag_paddr(msdu, 1); + shadow_src_desc->buffer_addr = (uint32_t)(dma_addr & + 0xFFFFFFFF); + /* + * Clear packet offset for all but the first CE desc. + */ + user_flags &= ~QDF_CE_TX_PKT_OFFSET_BIT_M; + ce_buffer_addr_hi_set(shadow_src_desc, dma_addr, user_flags); + shadow_src_desc->meta_data = transfer_id; + + /* get actual packet length */ + frag_len = qdf_nbuf_get_frag_len(msdu, 1); + + /* download remaining bytes of payload */ + shadow_src_desc->nbytes = download_len; + ce_validate_nbytes(shadow_src_desc->nbytes, ce_state); + if (shadow_src_desc->nbytes > frag_len) + shadow_src_desc->nbytes = frag_len; + + /* Data packet is a byte stream, so disable byte swap */ + shadow_src_desc->byte_swap = 0; + /* For the last one, gather is not set */ + shadow_src_desc->gather = 0; + *src_desc = *shadow_src_desc; + src_ring->per_transfer_context[write_index] = msdu; + write_index = CE_RING_IDX_INCR(nentries_mask, write_index); + + DPTRACE(qdf_dp_trace(msdu, + QDF_DP_TRACE_CE_FAST_PACKET_PTR_RECORD, + qdf_nbuf_data_addr(msdu), + sizeof(qdf_nbuf_data(msdu)), QDF_TX)); + } + + src_ring->write_index = write_index; + + if (hif_pm_runtime_get(hif_hdl) == 0) { + if (qdf_likely(ce_state->state == CE_RUNNING)) { + type = FAST_TX_WRITE_INDEX_UPDATE; + war_ce_src_ring_write_idx_set(scn, ctrl_addr, + write_index); + } else + ce_state->state = CE_PENDING; + hif_pm_runtime_put(hif_hdl); + } + hif_record_ce_desc_event(scn, ce_state->id, type, + NULL, NULL, write_index); + + Q_TARGET_ACCESS_END(scn); + qdf_spin_unlock_bh(&ce_state->ce_index_lock); + + /* sent 1 packet */ + return 1; +} + +/** + * ce_is_fastpath_enabled() - returns true if fastpath mode is enabled + * @scn: Handle to HIF context + * + * Return: true if fastpath is enabled else false. + */ +static bool ce_is_fastpath_enabled(struct hif_softc *scn) +{ + return scn->fastpath_mode_on; +} + +/** + * ce_is_fastpath_handler_registered() - return true for datapath CEs and if + * fastpath is enabled. + * @ce_state: handle to copy engine + * + * Return: true if fastpath handler is registered for datapath CE. + */ +static bool ce_is_fastpath_handler_registered(struct CE_state *ce_state) +{ + if (ce_state->fastpath_handler) + return true; + else + return false; +} + + +#else +static inline bool ce_is_fastpath_enabled(struct hif_softc *scn) +{ + return false; +} + +static inline bool ce_is_fastpath_handler_registered(struct CE_state *ce_state) +{ + return false; +} +#endif /* WLAN_FEATURE_FASTPATH */ + +#ifndef AH_NEED_TX_DATA_SWAP +#define AH_NEED_TX_DATA_SWAP 0 +#endif + +/** + * ce_batch_send() - sends bunch of msdus at once + * @ce_tx_hdl : pointer to CE handle + * @msdu : list of msdus to be sent + * @transfer_id : transfer id + * @len : Downloaded length + * @sendhead : sendhead + * + * Assumption : Called with an array of MSDU's + * Function: + * For each msdu in the array + * 1. Send each msdu + * 2. Increment write index accordinlgy. + * + * Return: list of msds not sent + */ +qdf_nbuf_t ce_batch_send(struct CE_handle *ce_tx_hdl, qdf_nbuf_t msdu, + uint32_t transfer_id, u_int32_t len, uint32_t sendhead) +{ + struct CE_state *ce_state = (struct CE_state *)ce_tx_hdl; + struct hif_softc *scn = ce_state->scn; + struct CE_ring_state *src_ring = ce_state->src_ring; + u_int32_t ctrl_addr = ce_state->ctrl_addr; + /* A_target_id_t targid = TARGID(scn);*/ + + uint32_t nentries_mask = src_ring->nentries_mask; + uint32_t sw_index, write_index; + + struct CE_src_desc *src_desc_base = + (struct CE_src_desc *)src_ring->base_addr_owner_space; + uint32_t *src_desc; + + struct CE_src_desc lsrc_desc = {0}; + int deltacount = 0; + qdf_nbuf_t freelist = NULL, hfreelist = NULL, tempnext; + + sw_index = src_ring->sw_index; + write_index = src_ring->write_index; + + deltacount = CE_RING_DELTA(nentries_mask, write_index, sw_index-1); + + while (msdu) { + tempnext = qdf_nbuf_next(msdu); + + if (deltacount < 2) { + if (sendhead) + return msdu; + HIF_ERROR("%s: Out of descriptors", __func__); + src_ring->write_index = write_index; + war_ce_src_ring_write_idx_set(scn, ctrl_addr, + write_index); + + sw_index = src_ring->sw_index; + write_index = src_ring->write_index; + + deltacount = CE_RING_DELTA(nentries_mask, write_index, + sw_index-1); + if (freelist == NULL) { + freelist = msdu; + hfreelist = msdu; + } else { + qdf_nbuf_set_next(freelist, msdu); + freelist = msdu; + } + qdf_nbuf_set_next(msdu, NULL); + msdu = tempnext; + continue; + } + + src_desc = (uint32_t *)CE_SRC_RING_TO_DESC(src_desc_base, + write_index); + + src_desc[0] = qdf_nbuf_get_frag_paddr(msdu, 0); + + lsrc_desc.meta_data = transfer_id; + if (len > msdu->len) + len = msdu->len; + lsrc_desc.nbytes = len; + /* Data packet is a byte stream, so disable byte swap */ + lsrc_desc.byte_swap = AH_NEED_TX_DATA_SWAP; + lsrc_desc.gather = 0; /*For the last one, gather is not set*/ + + src_desc[1] = ((uint32_t *)&lsrc_desc)[1]; + + + src_ring->per_transfer_context[write_index] = msdu; + write_index = CE_RING_IDX_INCR(nentries_mask, write_index); + + if (sendhead) + break; + qdf_nbuf_set_next(msdu, NULL); + msdu = tempnext; + + } + + + src_ring->write_index = write_index; + war_ce_src_ring_write_idx_set(scn, ctrl_addr, write_index); + + return hfreelist; +} + +/** + * ce_update_tx_ring() - Advance sw index. + * @ce_tx_hdl : pointer to CE handle + * @num_htt_cmpls : htt completions received. + * + * Function: + * Increment the value of sw index of src ring + * according to number of htt completions + * received. + * + * Return: void + */ +void ce_update_tx_ring(struct CE_handle *ce_tx_hdl, uint32_t num_htt_cmpls) +{ + struct CE_state *ce_state = (struct CE_state *)ce_tx_hdl; + struct CE_ring_state *src_ring = ce_state->src_ring; + uint32_t nentries_mask = src_ring->nentries_mask; + /* + * Advance the s/w index: + * This effectively simulates completing the CE ring descriptors + */ + src_ring->sw_index = + CE_RING_IDX_ADD(nentries_mask, src_ring->sw_index, + num_htt_cmpls); +} + +/** + * ce_send_single() - sends + * @ce_tx_hdl : pointer to CE handle + * @msdu : msdu to be sent + * @transfer_id : transfer id + * @len : Downloaded length + * + * Function: + * 1. Send one msdu + * 2. Increment write index of src ring accordinlgy. + * + * Return: int: CE sent status + */ +int ce_send_single(struct CE_handle *ce_tx_hdl, qdf_nbuf_t msdu, + uint32_t transfer_id, u_int32_t len) +{ + struct CE_state *ce_state = (struct CE_state *)ce_tx_hdl; + struct hif_softc *scn = ce_state->scn; + struct CE_ring_state *src_ring = ce_state->src_ring; + uint32_t ctrl_addr = ce_state->ctrl_addr; + /*A_target_id_t targid = TARGID(scn);*/ + + uint32_t nentries_mask = src_ring->nentries_mask; + uint32_t sw_index, write_index; + + struct CE_src_desc *src_desc_base = + (struct CE_src_desc *)src_ring->base_addr_owner_space; + uint32_t *src_desc; + + struct CE_src_desc lsrc_desc = {0}; + + sw_index = src_ring->sw_index; + write_index = src_ring->write_index; + + if (qdf_unlikely(CE_RING_DELTA(nentries_mask, write_index, + sw_index-1) < 1)) { + /* ol_tx_stats_inc_ring_error(sc->scn->pdev_txrx_handle, 1); */ + HIF_ERROR("%s: ce send fail %d %d %d", __func__, nentries_mask, + write_index, sw_index); + return 1; + } + + src_desc = (uint32_t *)CE_SRC_RING_TO_DESC(src_desc_base, write_index); + + src_desc[0] = qdf_nbuf_get_frag_paddr(msdu, 0); + + lsrc_desc.meta_data = transfer_id; + lsrc_desc.nbytes = len; + /* Data packet is a byte stream, so disable byte swap */ + lsrc_desc.byte_swap = AH_NEED_TX_DATA_SWAP; + lsrc_desc.gather = 0; /* For the last one, gather is not set */ + + src_desc[1] = ((uint32_t *)&lsrc_desc)[1]; + + + src_ring->per_transfer_context[write_index] = msdu; + write_index = CE_RING_IDX_INCR(nentries_mask, write_index); + + src_ring->write_index = write_index; + war_ce_src_ring_write_idx_set(scn, ctrl_addr, write_index); + + return QDF_STATUS_SUCCESS; +} +/** + * ce_recv_buf_enqueue() - enqueue a recv buffer into a copy engine + * @coyeng: copy engine handle + * @per_recv_context: virtual address of the nbuf + * @buffer: physical address of the nbuf + * + * Return: 0 if the buffer is enqueued + */ +int +ce_recv_buf_enqueue(struct CE_handle *copyeng, + void *per_recv_context, qdf_dma_addr_t buffer) +{ + int status; + struct CE_state *CE_state = (struct CE_state *)copyeng; + struct CE_ring_state *dest_ring = CE_state->dest_ring; + uint32_t ctrl_addr = CE_state->ctrl_addr; + unsigned int nentries_mask = dest_ring->nentries_mask; + unsigned int write_index; + unsigned int sw_index; + uint64_t dma_addr = buffer; + struct hif_softc *scn = CE_state->scn; + + qdf_spin_lock_bh(&CE_state->ce_index_lock); + write_index = dest_ring->write_index; + sw_index = dest_ring->sw_index; + + if (Q_TARGET_ACCESS_BEGIN(scn) < 0) { + qdf_spin_unlock_bh(&CE_state->ce_index_lock); + return -EIO; + } + + if ((CE_RING_DELTA(nentries_mask, write_index, sw_index - 1) > 0) || + (ce_is_fastpath_enabled(scn) && CE_state->htt_rx_data)) { + struct CE_dest_desc *dest_ring_base = + (struct CE_dest_desc *)dest_ring->base_addr_owner_space; + struct CE_dest_desc *dest_desc = + CE_DEST_RING_TO_DESC(dest_ring_base, write_index); + + /* Update low 32 bit destination descriptor */ + dest_desc->buffer_addr = (uint32_t)(dma_addr & 0xFFFFFFFF); +#ifdef QCA_WIFI_3_0 + dest_desc->buffer_addr_hi = + (uint32_t)((dma_addr >> 32) & 0x1F); +#endif + dest_desc->nbytes = 0; + + dest_ring->per_transfer_context[write_index] = + per_recv_context; + + hif_record_ce_desc_event(scn, CE_state->id, HIF_RX_DESC_POST, + (union ce_desc *) dest_desc, per_recv_context, + write_index); + + /* Update Destination Ring Write Index */ + write_index = CE_RING_IDX_INCR(nentries_mask, write_index); + if (write_index != sw_index) { + CE_DEST_RING_WRITE_IDX_SET(scn, ctrl_addr, write_index); + dest_ring->write_index = write_index; + } + status = QDF_STATUS_SUCCESS; + } else + status = QDF_STATUS_E_FAILURE; + + Q_TARGET_ACCESS_END(scn); + qdf_spin_unlock_bh(&CE_state->ce_index_lock); + return status; +} + +void +ce_send_watermarks_set(struct CE_handle *copyeng, + unsigned int low_alert_nentries, + unsigned int high_alert_nentries) +{ + struct CE_state *CE_state = (struct CE_state *)copyeng; + uint32_t ctrl_addr = CE_state->ctrl_addr; + struct hif_softc *scn = CE_state->scn; + + CE_SRC_RING_LOWMARK_SET(scn, ctrl_addr, low_alert_nentries); + CE_SRC_RING_HIGHMARK_SET(scn, ctrl_addr, high_alert_nentries); +} + +void +ce_recv_watermarks_set(struct CE_handle *copyeng, + unsigned int low_alert_nentries, + unsigned int high_alert_nentries) +{ + struct CE_state *CE_state = (struct CE_state *)copyeng; + uint32_t ctrl_addr = CE_state->ctrl_addr; + struct hif_softc *scn = CE_state->scn; + + CE_DEST_RING_LOWMARK_SET(scn, ctrl_addr, + low_alert_nentries); + CE_DEST_RING_HIGHMARK_SET(scn, ctrl_addr, + high_alert_nentries); +} + +unsigned int ce_send_entries_avail(struct CE_handle *copyeng) +{ + struct CE_state *CE_state = (struct CE_state *)copyeng; + struct CE_ring_state *src_ring = CE_state->src_ring; + unsigned int nentries_mask = src_ring->nentries_mask; + unsigned int sw_index; + unsigned int write_index; + + qdf_spin_lock(&CE_state->ce_index_lock); + sw_index = src_ring->sw_index; + write_index = src_ring->write_index; + qdf_spin_unlock(&CE_state->ce_index_lock); + + return CE_RING_DELTA(nentries_mask, write_index, sw_index - 1); +} + +unsigned int ce_recv_entries_avail(struct CE_handle *copyeng) +{ + struct CE_state *CE_state = (struct CE_state *)copyeng; + struct CE_ring_state *dest_ring = CE_state->dest_ring; + unsigned int nentries_mask = dest_ring->nentries_mask; + unsigned int sw_index; + unsigned int write_index; + + qdf_spin_lock(&CE_state->ce_index_lock); + sw_index = dest_ring->sw_index; + write_index = dest_ring->write_index; + qdf_spin_unlock(&CE_state->ce_index_lock); + + return CE_RING_DELTA(nentries_mask, write_index, sw_index - 1); +} + +/* + * Guts of ce_send_entries_done. + * The caller takes responsibility for any necessary locking. + */ +static unsigned int +ce_send_entries_done_nolock(struct hif_softc *scn, + struct CE_state *CE_state) +{ + struct CE_ring_state *src_ring = CE_state->src_ring; + uint32_t ctrl_addr = CE_state->ctrl_addr; + unsigned int nentries_mask = src_ring->nentries_mask; + unsigned int sw_index; + unsigned int read_index; + + sw_index = src_ring->sw_index; + read_index = CE_SRC_RING_READ_IDX_GET(scn, ctrl_addr); + + return CE_RING_DELTA(nentries_mask, sw_index, read_index); +} + +unsigned int ce_send_entries_done(struct CE_handle *copyeng) +{ + struct CE_state *CE_state = (struct CE_state *)copyeng; + unsigned int nentries; + + qdf_spin_lock(&CE_state->ce_index_lock); + nentries = ce_send_entries_done_nolock(CE_state->scn, CE_state); + qdf_spin_unlock(&CE_state->ce_index_lock); + + return nentries; +} + +/* + * Guts of ce_recv_entries_done. + * The caller takes responsibility for any necessary locking. + */ +static unsigned int +ce_recv_entries_done_nolock(struct hif_softc *scn, + struct CE_state *CE_state) +{ + struct CE_ring_state *dest_ring = CE_state->dest_ring; + uint32_t ctrl_addr = CE_state->ctrl_addr; + unsigned int nentries_mask = dest_ring->nentries_mask; + unsigned int sw_index; + unsigned int read_index; + + sw_index = dest_ring->sw_index; + read_index = CE_DEST_RING_READ_IDX_GET(scn, ctrl_addr); + + return CE_RING_DELTA(nentries_mask, sw_index, read_index); +} + +unsigned int ce_recv_entries_done(struct CE_handle *copyeng) +{ + struct CE_state *CE_state = (struct CE_state *)copyeng; + unsigned int nentries; + + qdf_spin_lock(&CE_state->ce_index_lock); + nentries = ce_recv_entries_done_nolock(CE_state->scn, CE_state); + qdf_spin_unlock(&CE_state->ce_index_lock); + + return nentries; +} + +/* + * Guts of ce_completed_recv_next. + * The caller takes responsibility for any necessary locking. + */ +static int +ce_completed_recv_next_nolock(struct CE_state *CE_state, + void **per_CE_contextp, + void **per_transfer_contextp, + qdf_dma_addr_t *bufferp, + unsigned int *nbytesp, + unsigned int *transfer_idp, + unsigned int *flagsp) +{ + int status; + struct CE_ring_state *dest_ring = CE_state->dest_ring; + unsigned int nentries_mask = dest_ring->nentries_mask; + unsigned int sw_index = dest_ring->sw_index; + struct hif_softc *scn = CE_state->scn; + struct CE_dest_desc *dest_ring_base = + (struct CE_dest_desc *)dest_ring->base_addr_owner_space; + struct CE_dest_desc *dest_desc = + CE_DEST_RING_TO_DESC(dest_ring_base, sw_index); + int nbytes; + struct CE_dest_desc dest_desc_info; + /* + * By copying the dest_desc_info element to local memory, we could + * avoid extra memory read from non-cachable memory. + */ + dest_desc_info = *dest_desc; + nbytes = dest_desc_info.nbytes; + if (nbytes == 0) { + /* + * This closes a relatively unusual race where the Host + * sees the updated DRRI before the update to the + * corresponding descriptor has completed. We treat this + * as a descriptor that is not yet done. + */ + status = QDF_STATUS_E_FAILURE; + goto done; + } + + hif_record_ce_desc_event(scn, CE_state->id, HIF_RX_DESC_COMPLETION, + (union ce_desc *) dest_desc, + dest_ring->per_transfer_context[sw_index], + sw_index); + + dest_desc->nbytes = 0; + + /* Return data from completed destination descriptor */ + *bufferp = HIF_CE_DESC_ADDR_TO_DMA(&dest_desc_info); + *nbytesp = nbytes; + *transfer_idp = dest_desc_info.meta_data; + *flagsp = (dest_desc_info.byte_swap) ? CE_RECV_FLAG_SWAPPED : 0; + + if (per_CE_contextp) { + *per_CE_contextp = CE_state->recv_context; + } + + if (per_transfer_contextp) { + *per_transfer_contextp = + dest_ring->per_transfer_context[sw_index]; + } + dest_ring->per_transfer_context[sw_index] = 0; /* sanity */ + + /* Update sw_index */ + sw_index = CE_RING_IDX_INCR(nentries_mask, sw_index); + dest_ring->sw_index = sw_index; + status = QDF_STATUS_SUCCESS; + +done: + return status; +} + +int +ce_completed_recv_next(struct CE_handle *copyeng, + void **per_CE_contextp, + void **per_transfer_contextp, + qdf_dma_addr_t *bufferp, + unsigned int *nbytesp, + unsigned int *transfer_idp, unsigned int *flagsp) +{ + struct CE_state *CE_state = (struct CE_state *)copyeng; + int status; + + qdf_spin_lock_bh(&CE_state->ce_index_lock); + status = + ce_completed_recv_next_nolock(CE_state, per_CE_contextp, + per_transfer_contextp, bufferp, + nbytesp, transfer_idp, flagsp); + qdf_spin_unlock_bh(&CE_state->ce_index_lock); + + return status; +} + +/* NB: Modeled after ce_completed_recv_next_nolock */ +QDF_STATUS +ce_revoke_recv_next(struct CE_handle *copyeng, + void **per_CE_contextp, + void **per_transfer_contextp, qdf_dma_addr_t *bufferp) +{ + struct CE_state *CE_state; + struct CE_ring_state *dest_ring; + unsigned int nentries_mask; + unsigned int sw_index; + unsigned int write_index; + QDF_STATUS status; + struct hif_softc *scn; + + CE_state = (struct CE_state *)copyeng; + dest_ring = CE_state->dest_ring; + if (!dest_ring) { + return QDF_STATUS_E_FAILURE; + } + + scn = CE_state->scn; + qdf_spin_lock(&CE_state->ce_index_lock); + nentries_mask = dest_ring->nentries_mask; + sw_index = dest_ring->sw_index; + write_index = dest_ring->write_index; + if (write_index != sw_index) { + struct CE_dest_desc *dest_ring_base = + (struct CE_dest_desc *)dest_ring-> + base_addr_owner_space; + struct CE_dest_desc *dest_desc = + CE_DEST_RING_TO_DESC(dest_ring_base, sw_index); + + /* Return data from completed destination descriptor */ + *bufferp = HIF_CE_DESC_ADDR_TO_DMA(dest_desc); + + if (per_CE_contextp) { + *per_CE_contextp = CE_state->recv_context; + } + + if (per_transfer_contextp) { + *per_transfer_contextp = + dest_ring->per_transfer_context[sw_index]; + } + dest_ring->per_transfer_context[sw_index] = 0; /* sanity */ + + /* Update sw_index */ + sw_index = CE_RING_IDX_INCR(nentries_mask, sw_index); + dest_ring->sw_index = sw_index; + status = QDF_STATUS_SUCCESS; + } else { + status = QDF_STATUS_E_FAILURE; + } + qdf_spin_unlock(&CE_state->ce_index_lock); + + return status; +} + +/* + * Guts of ce_completed_send_next. + * The caller takes responsibility for any necessary locking. + */ +int +ce_completed_send_next_nolock(struct CE_state *CE_state, + void **per_CE_contextp, + void **per_transfer_contextp, + qdf_dma_addr_t *bufferp, + unsigned int *nbytesp, + unsigned int *transfer_idp, + unsigned int *sw_idx, + unsigned int *hw_idx, + uint32_t *toeplitz_hash_result) +{ + int status = QDF_STATUS_E_FAILURE; + struct CE_ring_state *src_ring = CE_state->src_ring; + uint32_t ctrl_addr = CE_state->ctrl_addr; + unsigned int nentries_mask = src_ring->nentries_mask; + unsigned int sw_index = src_ring->sw_index; + unsigned int read_index; + struct hif_softc *scn = CE_state->scn; + + if (src_ring->hw_index == sw_index) { + /* + * The SW completion index has caught up with the cached + * version of the HW completion index. + * Update the cached HW completion index to see whether + * the SW has really caught up to the HW, or if the cached + * value of the HW index has become stale. + */ + if (Q_TARGET_ACCESS_BEGIN(scn) < 0) + return QDF_STATUS_E_FAILURE; + src_ring->hw_index = + CE_SRC_RING_READ_IDX_GET_FROM_DDR(scn, ctrl_addr); + if (Q_TARGET_ACCESS_END(scn) < 0) + return QDF_STATUS_E_FAILURE; + } + read_index = src_ring->hw_index; + + if (sw_idx) + *sw_idx = sw_index; + + if (hw_idx) + *hw_idx = read_index; + + if ((read_index != sw_index) && (read_index != 0xffffffff)) { + struct CE_src_desc *shadow_base = + (struct CE_src_desc *)src_ring->shadow_base; + struct CE_src_desc *shadow_src_desc = + CE_SRC_RING_TO_DESC(shadow_base, sw_index); +#ifdef QCA_WIFI_3_0 + struct CE_src_desc *src_ring_base = + (struct CE_src_desc *)src_ring->base_addr_owner_space; + struct CE_src_desc *src_desc = + CE_SRC_RING_TO_DESC(src_ring_base, sw_index); +#endif + hif_record_ce_desc_event(scn, CE_state->id, + HIF_TX_DESC_COMPLETION, + (union ce_desc *) shadow_src_desc, + src_ring->per_transfer_context[sw_index], + sw_index); + + /* Return data from completed source descriptor */ + *bufferp = HIF_CE_DESC_ADDR_TO_DMA(shadow_src_desc); + *nbytesp = shadow_src_desc->nbytes; + *transfer_idp = shadow_src_desc->meta_data; +#ifdef QCA_WIFI_3_0 + *toeplitz_hash_result = src_desc->toeplitz_hash_result; +#else + *toeplitz_hash_result = 0; +#endif + if (per_CE_contextp) { + *per_CE_contextp = CE_state->send_context; + } + + if (per_transfer_contextp) { + *per_transfer_contextp = + src_ring->per_transfer_context[sw_index]; + } + src_ring->per_transfer_context[sw_index] = 0; /* sanity */ + + /* Update sw_index */ + sw_index = CE_RING_IDX_INCR(nentries_mask, sw_index); + src_ring->sw_index = sw_index; + status = QDF_STATUS_SUCCESS; + } + + return status; +} + +/* NB: Modeled after ce_completed_send_next */ +QDF_STATUS +ce_cancel_send_next(struct CE_handle *copyeng, + void **per_CE_contextp, + void **per_transfer_contextp, + qdf_dma_addr_t *bufferp, + unsigned int *nbytesp, + unsigned int *transfer_idp, + uint32_t *toeplitz_hash_result) +{ + struct CE_state *CE_state; + struct CE_ring_state *src_ring; + unsigned int nentries_mask; + unsigned int sw_index; + unsigned int write_index; + QDF_STATUS status; + struct hif_softc *scn; + + CE_state = (struct CE_state *)copyeng; + src_ring = CE_state->src_ring; + if (!src_ring) { + return QDF_STATUS_E_FAILURE; + } + + scn = CE_state->scn; + qdf_spin_lock(&CE_state->ce_index_lock); + nentries_mask = src_ring->nentries_mask; + sw_index = src_ring->sw_index; + write_index = src_ring->write_index; + + if (write_index != sw_index) { + struct CE_src_desc *src_ring_base = + (struct CE_src_desc *)src_ring->base_addr_owner_space; + struct CE_src_desc *src_desc = + CE_SRC_RING_TO_DESC(src_ring_base, sw_index); + + /* Return data from completed source descriptor */ + *bufferp = HIF_CE_DESC_ADDR_TO_DMA(src_desc); + *nbytesp = src_desc->nbytes; + *transfer_idp = src_desc->meta_data; +#ifdef QCA_WIFI_3_0 + *toeplitz_hash_result = src_desc->toeplitz_hash_result; +#else + *toeplitz_hash_result = 0; +#endif + + if (per_CE_contextp) { + *per_CE_contextp = CE_state->send_context; + } + + if (per_transfer_contextp) { + *per_transfer_contextp = + src_ring->per_transfer_context[sw_index]; + } + src_ring->per_transfer_context[sw_index] = 0; /* sanity */ + + /* Update sw_index */ + sw_index = CE_RING_IDX_INCR(nentries_mask, sw_index); + src_ring->sw_index = sw_index; + status = QDF_STATUS_SUCCESS; + } else { + status = QDF_STATUS_E_FAILURE; + } + qdf_spin_unlock(&CE_state->ce_index_lock); + + return status; +} + +/* Shift bits to convert IS_*_RING_*_WATERMARK_MASK to CE_WM_FLAG_*_* */ +#define CE_WM_SHFT 1 + +int +ce_completed_send_next(struct CE_handle *copyeng, + void **per_CE_contextp, + void **per_transfer_contextp, + qdf_dma_addr_t *bufferp, + unsigned int *nbytesp, + unsigned int *transfer_idp, + unsigned int *sw_idx, + unsigned int *hw_idx, + unsigned int *toeplitz_hash_result) +{ + struct CE_state *CE_state = (struct CE_state *)copyeng; + int status; + + qdf_spin_lock_bh(&CE_state->ce_index_lock); + status = + ce_completed_send_next_nolock(CE_state, per_CE_contextp, + per_transfer_contextp, bufferp, + nbytesp, transfer_idp, sw_idx, + hw_idx, toeplitz_hash_result); + qdf_spin_unlock_bh(&CE_state->ce_index_lock); + + return status; +} + +#ifdef ATH_11AC_TXCOMPACT +/* CE engine descriptor reap + * Similar to ce_per_engine_service , Only difference is ce_per_engine_service + * does recieve and reaping of completed descriptor , + * This function only handles reaping of Tx complete descriptor. + * The Function is called from threshold reap poll routine + * hif_send_complete_check so should not countain recieve functionality + * within it . + */ + +void ce_per_engine_servicereap(struct hif_softc *scn, unsigned int ce_id) +{ + void *CE_context; + void *transfer_context; + qdf_dma_addr_t buf; + unsigned int nbytes; + unsigned int id; + unsigned int sw_idx, hw_idx; + uint32_t toeplitz_hash_result; + struct CE_state *CE_state = scn->ce_id_to_state[ce_id]; + + if (Q_TARGET_ACCESS_BEGIN(scn) < 0) + return; + + hif_record_ce_desc_event(scn, ce_id, HIF_CE_REAP_ENTRY, + NULL, NULL, 0); + + /* Since this function is called from both user context and + * tasklet context the spinlock has to lock the bottom halves. + * This fix assumes that ATH_11AC_TXCOMPACT flag is always + * enabled in TX polling mode. If this is not the case, more + * bottom halve spin lock changes are needed. Due to data path + * performance concern, after internal discussion we've decided + * to make minimum change, i.e., only address the issue occured + * in this function. The possible negative effect of this minimum + * change is that, in the future, if some other function will also + * be opened to let the user context to use, those cases need to be + * addressed by change spin_lock to spin_lock_bh also. + */ + + qdf_spin_lock_bh(&CE_state->ce_index_lock); + + if (CE_state->send_cb) { + { + /* Pop completed send buffers and call the + * registered send callback for each + */ + while (ce_completed_send_next_nolock + (CE_state, &CE_context, + &transfer_context, &buf, + &nbytes, &id, &sw_idx, &hw_idx, + &toeplitz_hash_result) == + QDF_STATUS_SUCCESS) { + if (ce_id != CE_HTT_H2T_MSG) { + qdf_spin_unlock_bh( + &CE_state->ce_index_lock); + CE_state->send_cb( + (struct CE_handle *) + CE_state, CE_context, + transfer_context, buf, + nbytes, id, sw_idx, hw_idx, + toeplitz_hash_result); + qdf_spin_lock_bh( + &CE_state->ce_index_lock); + } else { + struct HIF_CE_pipe_info *pipe_info = + (struct HIF_CE_pipe_info *) + CE_context; + + qdf_spin_lock_bh(&pipe_info-> + completion_freeq_lock); + pipe_info->num_sends_allowed++; + qdf_spin_unlock_bh(&pipe_info-> + completion_freeq_lock); + } + } + } + } + + qdf_spin_unlock_bh(&CE_state->ce_index_lock); + + hif_record_ce_desc_event(scn, ce_id, HIF_CE_REAP_EXIT, + NULL, NULL, 0); + Q_TARGET_ACCESS_END(scn); +} + +#endif /*ATH_11AC_TXCOMPACT */ + +/* + * Number of times to check for any pending tx/rx completion on + * a copy engine, this count should be big enough. Once we hit + * this threashold we'll not check for any Tx/Rx comlpetion in same + * interrupt handling. Note that this threashold is only used for + * Rx interrupt processing, this can be used tor Tx as well if we + * suspect any infinite loop in checking for pending Tx completion. + */ +#define CE_TXRX_COMP_CHECK_THRESHOLD 20 + +#ifdef WLAN_FEATURE_FASTPATH +/** + * ce_fastpath_rx_handle() - Updates write_index and calls fastpath msg handler + * @ce_state: handle to copy engine state + * @cmpl_msdus: Rx msdus + * @num_cmpls: number of Rx msdus + * @ctrl_addr: CE control address + * + * Return: None + */ +static void ce_fastpath_rx_handle(struct CE_state *ce_state, + qdf_nbuf_t *cmpl_msdus, uint32_t num_cmpls, + uint32_t ctrl_addr) +{ + struct hif_softc *scn = ce_state->scn; + struct CE_ring_state *dest_ring = ce_state->dest_ring; + uint32_t nentries_mask = dest_ring->nentries_mask; + uint32_t write_index; + + qdf_spin_unlock(&ce_state->ce_index_lock); + (ce_state->fastpath_handler)(ce_state->context, cmpl_msdus, num_cmpls); + qdf_spin_lock(&ce_state->ce_index_lock); + + /* Update Destination Ring Write Index */ + write_index = dest_ring->write_index; + write_index = CE_RING_IDX_ADD(nentries_mask, write_index, num_cmpls); + + hif_record_ce_desc_event(scn, ce_state->id, + FAST_RX_WRITE_INDEX_UPDATE, + NULL, NULL, write_index); + + CE_DEST_RING_WRITE_IDX_SET(scn, ctrl_addr, write_index); + dest_ring->write_index = write_index; +} + +#define MSG_FLUSH_NUM 32 +/** + * ce_per_engine_service_fast() - CE handler routine to service fastpath messages + * @scn: hif_context + * @ce_id: Copy engine ID + * 1) Go through the CE ring, and find the completions + * 2) For valid completions retrieve context (nbuf) for per_transfer_context[] + * 3) Unmap buffer & accumulate in an array. + * 4) Call message handler when array is full or when exiting the handler + * + * Return: void + */ + +static void ce_per_engine_service_fast(struct hif_softc *scn, int ce_id) +{ + struct CE_state *ce_state = scn->ce_id_to_state[ce_id]; + struct hif_opaque_softc *hif_hdl = GET_HIF_OPAQUE_HDL(scn); + struct CE_ring_state *dest_ring = ce_state->dest_ring; + struct CE_dest_desc *dest_ring_base = + (struct CE_dest_desc *)dest_ring->base_addr_owner_space; + + uint32_t nentries_mask = dest_ring->nentries_mask; + uint32_t sw_index = dest_ring->sw_index; + uint32_t nbytes; + qdf_nbuf_t nbuf; + dma_addr_t paddr; + struct CE_dest_desc *dest_desc; + qdf_nbuf_t cmpl_msdus[MSG_FLUSH_NUM]; + uint32_t ctrl_addr = ce_state->ctrl_addr; + uint32_t nbuf_cmpl_idx = 0; + unsigned int more_comp_cnt = 0; + +more_data: + for (;;) { + + dest_desc = CE_DEST_RING_TO_DESC(dest_ring_base, + sw_index); + + /* + * The following 2 reads are from non-cached memory + */ + nbytes = dest_desc->nbytes; + + /* If completion is invalid, break */ + if (qdf_unlikely(nbytes == 0)) + break; + + + /* + * Build the nbuf list from valid completions + */ + nbuf = dest_ring->per_transfer_context[sw_index]; + + /* + * No lock is needed here, since this is the only thread + * that accesses the sw_index + */ + sw_index = CE_RING_IDX_INCR(nentries_mask, sw_index); + + /* + * CAREFUL : Uncached write, but still less expensive, + * since most modern caches use "write-combining" to + * flush multiple cache-writes all at once. + */ + dest_desc->nbytes = 0; + + /* + * Per our understanding this is not required on our + * since we are doing the same cache invalidation + * operation on the same buffer twice in succession, + * without any modifiication to this buffer by CPU in + * between. + * However, this code with 2 syncs in succession has + * been undergoing some testing at a customer site, + * and seemed to be showing no problems so far. Would + * like to validate from the customer, that this line + * is really not required, before we remove this line + * completely. + */ + paddr = QDF_NBUF_CB_PADDR(nbuf); + + qdf_mem_dma_sync_single_for_cpu(scn->qdf_dev, paddr, + (skb_end_pointer(nbuf) - (nbuf)->data), + DMA_FROM_DEVICE); + + qdf_nbuf_put_tail(nbuf, nbytes); + + qdf_assert_always(nbuf->data != NULL); + + QDF_NBUF_CB_RX_CTX_ID(nbuf) = + hif_get_rx_ctx_id(ce_state->id, hif_hdl); + cmpl_msdus[nbuf_cmpl_idx++] = nbuf; + + /* + * we are not posting the buffers back instead + * reusing the buffers + */ + if (nbuf_cmpl_idx == MSG_FLUSH_NUM) { + hif_record_ce_desc_event(scn, ce_state->id, + FAST_RX_SOFTWARE_INDEX_UPDATE, + NULL, NULL, sw_index); + dest_ring->sw_index = sw_index; + ce_fastpath_rx_handle(ce_state, cmpl_msdus, + MSG_FLUSH_NUM, ctrl_addr); + + ce_state->receive_count += MSG_FLUSH_NUM; + if (qdf_unlikely(hif_ce_service_should_yield( + scn, ce_state))) { + ce_state->force_break = 1; + qdf_atomic_set(&ce_state->rx_pending, 1); + return; + } + + nbuf_cmpl_idx = 0; + more_comp_cnt = 0; + } + } + + hif_record_ce_desc_event(scn, ce_state->id, + FAST_RX_SOFTWARE_INDEX_UPDATE, + NULL, NULL, sw_index); + + dest_ring->sw_index = sw_index; + + /* + * If there are not enough completions to fill the array, + * just call the message handler here + */ + if (nbuf_cmpl_idx) { + ce_fastpath_rx_handle(ce_state, cmpl_msdus, + nbuf_cmpl_idx, ctrl_addr); + + ce_state->receive_count += nbuf_cmpl_idx; + if (qdf_unlikely(hif_ce_service_should_yield(scn, ce_state))) { + ce_state->force_break = 1; + qdf_atomic_set(&ce_state->rx_pending, 1); + return; + } + + /* check for more packets after upper layer processing */ + nbuf_cmpl_idx = 0; + more_comp_cnt = 0; + goto more_data; + } + qdf_atomic_set(&ce_state->rx_pending, 0); + CE_ENGINE_INT_STATUS_CLEAR(scn, ctrl_addr, + HOST_IS_COPY_COMPLETE_MASK); + + if (ce_recv_entries_done_nolock(scn, ce_state)) { + if (more_comp_cnt++ < CE_TXRX_COMP_CHECK_THRESHOLD) { + goto more_data; + } else { + HIF_ERROR("%s:Potential infinite loop detected during Rx processing nentries_mask:0x%x sw read_idx:0x%x hw read_idx:0x%x", + __func__, nentries_mask, + ce_state->dest_ring->sw_index, + CE_DEST_RING_READ_IDX_GET(scn, ctrl_addr)); + } + } +} + +#else +static void ce_per_engine_service_fast(struct hif_softc *scn, int ce_id) +{ +} +#endif /* WLAN_FEATURE_FASTPATH */ + +/* Maximum amount of time in nano seconds before which the CE per engine service + * should yield. ~1 jiffie. + */ +#define CE_PER_ENGINE_SERVICE_MAX_YIELD_TIME_NS (10 * 1000 * 1000) + +/* + * Guts of interrupt handler for per-engine interrupts on a particular CE. + * + * Invokes registered callbacks for recv_complete, + * send_complete, and watermarks. + * + * Returns: number of messages processed + */ +int ce_per_engine_service(struct hif_softc *scn, unsigned int CE_id) +{ + struct CE_state *CE_state = scn->ce_id_to_state[CE_id]; + uint32_t ctrl_addr = CE_state->ctrl_addr; + void *CE_context; + void *transfer_context; + qdf_dma_addr_t buf; + unsigned int nbytes; + unsigned int id; + unsigned int flags; + uint32_t CE_int_status; + unsigned int more_comp_cnt = 0; + unsigned int more_snd_comp_cnt = 0; + unsigned int sw_idx, hw_idx; + uint32_t toeplitz_hash_result; + uint32_t mode = hif_get_conparam(scn); + + if (hif_is_nss_wifi_enabled(scn) && (CE_state->htt_rx_data)) + return CE_state->receive_count; + + if (Q_TARGET_ACCESS_BEGIN(scn) < 0) { + HIF_ERROR("[premature rc=0]"); + return 0; /* no work done */ + } + + /* Clear force_break flag and re-initialize receive_count to 0 */ + CE_state->receive_count = 0; + CE_state->force_break = 0; + CE_state->ce_service_yield_time = + sched_clock() + + (unsigned long long)CE_PER_ENGINE_SERVICE_MAX_YIELD_TIME_NS; + + + qdf_spin_lock(&CE_state->ce_index_lock); + /* + * With below check we make sure CE we are handling is datapath CE and + * fastpath is enabled. + */ + if (ce_is_fastpath_handler_registered(CE_state)) { + /* For datapath only Rx CEs */ + ce_per_engine_service_fast(scn, CE_id); + goto unlock_end; + } + +more_completions: + if (CE_state->recv_cb) { + + /* Pop completed recv buffers and call + * the registered recv callback for each + */ + while (ce_completed_recv_next_nolock + (CE_state, &CE_context, &transfer_context, + &buf, &nbytes, &id, &flags) == + QDF_STATUS_SUCCESS) { + qdf_spin_unlock(&CE_state->ce_index_lock); + CE_state->recv_cb((struct CE_handle *)CE_state, + CE_context, transfer_context, buf, + nbytes, id, flags); + + /* + * EV #112693 - + * [Peregrine][ES1][WB342][Win8x86][Performance] + * BSoD_0x133 occurred in VHT80 UDP_DL + * Break out DPC by force if number of loops in + * hif_pci_ce_recv_data reaches MAX_NUM_OF_RECEIVES + * to avoid spending too long time in + * DPC for each interrupt handling. Schedule another + * DPC to avoid data loss if we had taken + * force-break action before apply to Windows OS + * only currently, Linux/MAC os can expand to their + * platform if necessary + */ + + /* Break the receive processes by + * force if force_break set up + */ + if (qdf_unlikely(CE_state->force_break)) { + qdf_atomic_set(&CE_state->rx_pending, 1); + goto target_access_end; + } + qdf_spin_lock(&CE_state->ce_index_lock); + } + } + + /* + * Attention: We may experience potential infinite loop for below + * While Loop during Sending Stress test. + * Resolve the same way as Receive Case (Refer to EV #112693) + */ + + if (CE_state->send_cb) { + /* Pop completed send buffers and call + * the registered send callback for each + */ + +#ifdef ATH_11AC_TXCOMPACT + while (ce_completed_send_next_nolock + (CE_state, &CE_context, + &transfer_context, &buf, &nbytes, + &id, &sw_idx, &hw_idx, + &toeplitz_hash_result) == QDF_STATUS_SUCCESS) { + + if (CE_id != CE_HTT_H2T_MSG || + QDF_IS_EPPING_ENABLED(mode)) { + qdf_spin_unlock(&CE_state->ce_index_lock); + CE_state->send_cb((struct CE_handle *)CE_state, + CE_context, transfer_context, + buf, nbytes, id, sw_idx, + hw_idx, toeplitz_hash_result); + qdf_spin_lock(&CE_state->ce_index_lock); + } else { + struct HIF_CE_pipe_info *pipe_info = + (struct HIF_CE_pipe_info *)CE_context; + + qdf_spin_lock(&pipe_info-> + completion_freeq_lock); + pipe_info->num_sends_allowed++; + qdf_spin_unlock(&pipe_info-> + completion_freeq_lock); + } + } +#else /*ATH_11AC_TXCOMPACT */ + while (ce_completed_send_next_nolock + (CE_state, &CE_context, + &transfer_context, &buf, &nbytes, + &id, &sw_idx, &hw_idx, + &toeplitz_hash_result) == QDF_STATUS_SUCCESS) { + qdf_spin_unlock(&CE_state->ce_index_lock); + CE_state->send_cb((struct CE_handle *)CE_state, + CE_context, transfer_context, buf, + nbytes, id, sw_idx, hw_idx, + toeplitz_hash_result); + qdf_spin_lock(&CE_state->ce_index_lock); + } +#endif /*ATH_11AC_TXCOMPACT */ + } + +more_watermarks: + if (CE_state->misc_cbs) { + CE_int_status = CE_ENGINE_INT_STATUS_GET(scn, ctrl_addr); + if (CE_int_status & CE_WATERMARK_MASK) { + if (CE_state->watermark_cb) { + qdf_spin_unlock(&CE_state->ce_index_lock); + /* Convert HW IS bits to software flags */ + flags = + (CE_int_status & CE_WATERMARK_MASK) >> + CE_WM_SHFT; + + CE_state-> + watermark_cb((struct CE_handle *)CE_state, + CE_state->wm_context, flags); + qdf_spin_lock(&CE_state->ce_index_lock); + } + } + } + + /* + * Clear the misc interrupts (watermark) that were handled above, + * and that will be checked again below. + * Clear and check for copy-complete interrupts again, just in case + * more copy completions happened while the misc interrupts were being + * handled. + */ + CE_ENGINE_INT_STATUS_CLEAR(scn, ctrl_addr, + CE_WATERMARK_MASK | + HOST_IS_COPY_COMPLETE_MASK); + + /* + * Now that per-engine interrupts are cleared, verify that + * no recv interrupts arrive while processing send interrupts, + * and no recv or send interrupts happened while processing + * misc interrupts.Go back and check again.Keep checking until + * we find no more events to process. + */ + if (CE_state->recv_cb && ce_recv_entries_done_nolock(scn, CE_state)) { + if (QDF_IS_EPPING_ENABLED(mode) || + more_comp_cnt++ < CE_TXRX_COMP_CHECK_THRESHOLD) { + goto more_completions; + } else { + HIF_ERROR( + "%s:Potential infinite loop detected during Rx processing nentries_mask:0x%x sw read_idx:0x%x hw read_idx:0x%x", + __func__, CE_state->dest_ring->nentries_mask, + CE_state->dest_ring->sw_index, + CE_DEST_RING_READ_IDX_GET(scn, + CE_state->ctrl_addr)); + } + } + + if (CE_state->send_cb && ce_send_entries_done_nolock(scn, CE_state)) { + if (QDF_IS_EPPING_ENABLED(mode) || + more_snd_comp_cnt++ < CE_TXRX_COMP_CHECK_THRESHOLD) { + goto more_completions; + } else { + HIF_ERROR( + "%s:Potential infinite loop detected during send completion nentries_mask:0x%x sw read_idx:0x%x hw read_idx:0x%x", + __func__, CE_state->src_ring->nentries_mask, + CE_state->src_ring->sw_index, + CE_SRC_RING_READ_IDX_GET(scn, + CE_state->ctrl_addr)); + } + } + + if (CE_state->misc_cbs) { + CE_int_status = CE_ENGINE_INT_STATUS_GET(scn, ctrl_addr); + if (CE_int_status & CE_WATERMARK_MASK) { + if (CE_state->watermark_cb) { + goto more_watermarks; + } + } + } + + qdf_atomic_set(&CE_state->rx_pending, 0); + +unlock_end: + qdf_spin_unlock(&CE_state->ce_index_lock); +target_access_end: + if (Q_TARGET_ACCESS_END(scn) < 0) + HIF_ERROR("<--[premature rc=%d]", CE_state->receive_count); + return CE_state->receive_count; +} + +/* + * Handler for per-engine interrupts on ALL active CEs. + * This is used in cases where the system is sharing a + * single interrput for all CEs + */ + +void ce_per_engine_service_any(int irq, struct hif_softc *scn) +{ + int CE_id; + uint32_t intr_summary; + + if (Q_TARGET_ACCESS_BEGIN(scn) < 0) + return; + + if (!qdf_atomic_read(&scn->tasklet_from_intr)) { + for (CE_id = 0; CE_id < scn->ce_count; CE_id++) { + struct CE_state *CE_state = scn->ce_id_to_state[CE_id]; + if (qdf_atomic_read(&CE_state->rx_pending)) { + qdf_atomic_set(&CE_state->rx_pending, 0); + ce_per_engine_service(scn, CE_id); + } + } + + Q_TARGET_ACCESS_END(scn); + return; + } + + intr_summary = CE_INTERRUPT_SUMMARY(scn); + + for (CE_id = 0; intr_summary && (CE_id < scn->ce_count); CE_id++) { + if (intr_summary & (1 << CE_id)) { + intr_summary &= ~(1 << CE_id); + } else { + continue; /* no intr pending on this CE */ + } + + ce_per_engine_service(scn, CE_id); + } + + Q_TARGET_ACCESS_END(scn); +} + +/* + * Adjust interrupts for the copy complete handler. + * If it's needed for either send or recv, then unmask + * this interrupt; otherwise, mask it. + * + * Called with target_lock held. + */ +static void +ce_per_engine_handler_adjust(struct CE_state *CE_state, + int disable_copy_compl_intr) +{ + uint32_t ctrl_addr = CE_state->ctrl_addr; + struct hif_softc *scn = CE_state->scn; + + CE_state->disable_copy_compl_intr = disable_copy_compl_intr; + + if (Q_TARGET_ACCESS_BEGIN(scn) < 0) + return; + + if ((!disable_copy_compl_intr) && + (CE_state->send_cb || CE_state->recv_cb)) { + CE_COPY_COMPLETE_INTR_ENABLE(scn, ctrl_addr); + } else { + CE_COPY_COMPLETE_INTR_DISABLE(scn, ctrl_addr); + } + + if (CE_state->watermark_cb) { + CE_WATERMARK_INTR_ENABLE(scn, ctrl_addr); + } else { + CE_WATERMARK_INTR_DISABLE(scn, ctrl_addr); + } + Q_TARGET_ACCESS_END(scn); +} + +/*Iterate the CE_state list and disable the compl interrupt + * if it has been registered already. + */ +void ce_disable_any_copy_compl_intr_nolock(struct hif_softc *scn) +{ + int CE_id; + + if (Q_TARGET_ACCESS_BEGIN(scn) < 0) + return; + + for (CE_id = 0; CE_id < scn->ce_count; CE_id++) { + struct CE_state *CE_state = scn->ce_id_to_state[CE_id]; + uint32_t ctrl_addr = CE_state->ctrl_addr; + + /* if the interrupt is currently enabled, disable it */ + if (!CE_state->disable_copy_compl_intr + && (CE_state->send_cb || CE_state->recv_cb)) { + CE_COPY_COMPLETE_INTR_DISABLE(scn, ctrl_addr); + } + + if (CE_state->watermark_cb) { + CE_WATERMARK_INTR_DISABLE(scn, ctrl_addr); + } + } + Q_TARGET_ACCESS_END(scn); +} + +void ce_enable_any_copy_compl_intr_nolock(struct hif_softc *scn) +{ + int CE_id; + + if (Q_TARGET_ACCESS_BEGIN(scn) < 0) + return; + + for (CE_id = 0; CE_id < scn->ce_count; CE_id++) { + struct CE_state *CE_state = scn->ce_id_to_state[CE_id]; + uint32_t ctrl_addr = CE_state->ctrl_addr; + + /* + * If the CE is supposed to have copy complete interrupts + * enabled (i.e. there a callback registered, and the + * "disable" flag is not set), then re-enable the interrupt. + */ + if (!CE_state->disable_copy_compl_intr + && (CE_state->send_cb || CE_state->recv_cb)) { + CE_COPY_COMPLETE_INTR_ENABLE(scn, ctrl_addr); + } + + if (CE_state->watermark_cb) { + CE_WATERMARK_INTR_ENABLE(scn, ctrl_addr); + } + } + Q_TARGET_ACCESS_END(scn); +} + +/** + * ce_send_cb_register(): register completion handler + * @copyeng: CE_state representing the ce we are adding the behavior to + * @fn_ptr: callback that the ce should use when processing tx completions + * @disable_interrupts: if the interupts should be enabled or not. + * + * Caller should guarantee that no transactions are in progress before + * switching the callback function. + * + * Registers the send context before the fn pointer so that if the cb is valid + * the context should be valid. + * + * Beware that currently this function will enable completion interrupts. + */ +void +ce_send_cb_register(struct CE_handle *copyeng, + ce_send_cb fn_ptr, + void *ce_send_context, int disable_interrupts) +{ + struct CE_state *CE_state = (struct CE_state *)copyeng; + + if (CE_state == NULL) { + HIF_ERROR("%s: Error CE state = NULL", __func__); + return; + } + CE_state->send_context = ce_send_context; + CE_state->send_cb = fn_ptr; + ce_per_engine_handler_adjust(CE_state, disable_interrupts); +} + +/** + * ce_recv_cb_register(): register completion handler + * @copyeng: CE_state representing the ce we are adding the behavior to + * @fn_ptr: callback that the ce should use when processing rx completions + * @disable_interrupts: if the interupts should be enabled or not. + * + * Registers the send context before the fn pointer so that if the cb is valid + * the context should be valid. + * + * Caller should guarantee that no transactions are in progress before + * switching the callback function. + */ +void +ce_recv_cb_register(struct CE_handle *copyeng, + CE_recv_cb fn_ptr, + void *CE_recv_context, int disable_interrupts) +{ + struct CE_state *CE_state = (struct CE_state *)copyeng; + + if (CE_state == NULL) { + HIF_ERROR("%s: ERROR CE state = NULL", __func__); + return; + } + CE_state->recv_context = CE_recv_context; + CE_state->recv_cb = fn_ptr; + ce_per_engine_handler_adjust(CE_state, disable_interrupts); +} + +/** + * ce_watermark_cb_register(): register completion handler + * @copyeng: CE_state representing the ce we are adding the behavior to + * @fn_ptr: callback that the ce should use when processing watermark events + * + * Caller should guarantee that no watermark events are being processed before + * switching the callback function. + */ +void +ce_watermark_cb_register(struct CE_handle *copyeng, + CE_watermark_cb fn_ptr, void *CE_wm_context) +{ + struct CE_state *CE_state = (struct CE_state *)copyeng; + + CE_state->watermark_cb = fn_ptr; + CE_state->wm_context = CE_wm_context; + ce_per_engine_handler_adjust(CE_state, 0); + if (fn_ptr) { + CE_state->misc_cbs = 1; + } +} + +bool ce_get_rx_pending(struct hif_softc *scn) +{ + int CE_id; + + for (CE_id = 0; CE_id < scn->ce_count; CE_id++) { + struct CE_state *CE_state = scn->ce_id_to_state[CE_id]; + if (qdf_atomic_read(&CE_state->rx_pending)) + return true; + } + + return false; +} + +/** + * ce_check_rx_pending() - ce_check_rx_pending + * @CE_state: context of the copy engine to check + * + * Return: true if there per_engine_service + * didn't process all the rx descriptors. + */ +bool ce_check_rx_pending(struct CE_state *CE_state) +{ + if (qdf_atomic_read(&CE_state->rx_pending)) + return true; + else + return false; +} + +#ifdef IPA_OFFLOAD +/** + * ce_ipa_get_resource() - get uc resource on copyengine + * @ce: copyengine context + * @ce_sr_base_paddr: copyengine source ring base physical address + * @ce_sr_ring_size: copyengine source ring size + * @ce_reg_paddr: copyengine register physical address + * + * Copy engine should release resource to micro controller + * Micro controller needs + * - Copy engine source descriptor base address + * - Copy engine source descriptor size + * - PCI BAR address to access copy engine regiser + * + * Return: None + */ +void ce_ipa_get_resource(struct CE_handle *ce, + qdf_dma_addr_t *ce_sr_base_paddr, + uint32_t *ce_sr_ring_size, + qdf_dma_addr_t *ce_reg_paddr) +{ + struct CE_state *CE_state = (struct CE_state *)ce; + uint32_t ring_loop; + struct CE_src_desc *ce_desc; + qdf_dma_addr_t phy_mem_base; + struct hif_softc *scn = CE_state->scn; + + if (CE_UNUSED == CE_state->state) { + *ce_sr_base_paddr = 0; + *ce_sr_ring_size = 0; + return; + } + + /* Update default value for descriptor */ + for (ring_loop = 0; ring_loop < CE_state->src_ring->nentries; + ring_loop++) { + ce_desc = (struct CE_src_desc *) + ((char *)CE_state->src_ring->base_addr_owner_space + + ring_loop * (sizeof(struct CE_src_desc))); + CE_IPA_RING_INIT(ce_desc); + } + + /* Get BAR address */ + hif_read_phy_mem_base(CE_state->scn, &phy_mem_base); + + *ce_sr_base_paddr = CE_state->src_ring->base_addr_CE_space; + *ce_sr_ring_size = (uint32_t) (CE_state->src_ring->nentries * + sizeof(struct CE_src_desc)); + *ce_reg_paddr = phy_mem_base + CE_BASE_ADDRESS(CE_state->id) + + SR_WR_INDEX_ADDRESS; + return; +} +#endif /* IPA_OFFLOAD */ diff --git a/drivers/staging/qca-wifi-host-cmn/hif/src/ce/ce_tasklet.c b/drivers/staging/qca-wifi-host-cmn/hif/src/ce/ce_tasklet.c new file mode 100644 index 0000000000000000000000000000000000000000..910d90c53088fa53ddbde9ecab8ef79635373d77 --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/hif/src/ce/ce_tasklet.c @@ -0,0 +1,609 @@ +/* + * Copyright (c) 2015-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#include +#include +#include +#include +#include "qdf_lock.h" +#include "qdf_types.h" +#include "qdf_status.h" +#include "regtable.h" +#include "hif.h" +#include "hif_io32.h" +#include "ce_main.h" +#include "ce_api.h" +#include "ce_reg.h" +#include "ce_internal.h" +#include "ce_tasklet.h" +#include "pld_common.h" +#include "hif_debug.h" +#include "hif_napi.h" + + +/** + * struct tasklet_work + * + * @id: ce_id + * @work: work + */ +struct tasklet_work { + enum ce_id_type id; + void *data; + struct work_struct work; +}; + + +/** + * reschedule_ce_tasklet_work_handler() - reschedule work + * @work: struct work_struct + * + * Return: N/A + */ +static void reschedule_ce_tasklet_work_handler(struct work_struct *work) +{ + struct tasklet_work *ce_work = container_of(work, struct tasklet_work, + work); + struct hif_softc *scn = ce_work->data; + struct HIF_CE_state *hif_ce_state; + + if (NULL == scn) { + HIF_ERROR("%s: tasklet scn is null", __func__); + return; + } + + hif_ce_state = HIF_GET_CE_STATE(scn); + + if (scn->hif_init_done == false) { + HIF_ERROR("%s: wlan driver is unloaded", __func__); + return; + } + tasklet_schedule(&hif_ce_state->tasklets[ce_work->id].intr_tq); + return; +} + +static struct tasklet_work tasklet_workers[CE_ID_MAX]; +static bool work_initialized; + +/** + * init_tasklet_work() - init_tasklet_work + * @work: struct work_struct + * @work_handler: work_handler + * + * Return: N/A + */ +static void init_tasklet_work(struct work_struct *work, + work_func_t work_handler) +{ + INIT_WORK(work, work_handler); +} + +/** + * init_tasklet_workers() - init_tasklet_workers + * @scn: HIF Context + * + * Return: N/A + */ +void init_tasklet_workers(struct hif_opaque_softc *scn) +{ + uint32_t id; + + for (id = 0; id < CE_ID_MAX; id++) { + tasklet_workers[id].id = id; + tasklet_workers[id].data = scn; + init_tasklet_work(&tasklet_workers[id].work, + reschedule_ce_tasklet_work_handler); + } + work_initialized = true; +} + +#ifdef CONFIG_SLUB_DEBUG_ON +/** + * ce_schedule_tasklet() - schedule ce tasklet + * @tasklet_entry: struct ce_tasklet_entry + * + * Return: N/A + */ +static inline void ce_schedule_tasklet(struct ce_tasklet_entry *tasklet_entry) +{ + if (work_initialized && (tasklet_entry->ce_id < CE_ID_MAX)) + schedule_work(&tasklet_workers[tasklet_entry->ce_id].work); + else + HIF_ERROR("%s: work_initialized = %d, ce_id = %d", + __func__, work_initialized, tasklet_entry->ce_id); +} +#else +/** + * ce_schedule_tasklet() - schedule ce tasklet + * @tasklet_entry: struct ce_tasklet_entry + * + * Return: N/A + */ +static inline void ce_schedule_tasklet(struct ce_tasklet_entry *tasklet_entry) +{ + tasklet_schedule(&tasklet_entry->intr_tq); +} +#endif + +/** + * ce_tasklet() - ce_tasklet + * @data: data + * + * Return: N/A + */ +static void ce_tasklet(unsigned long data) +{ + struct ce_tasklet_entry *tasklet_entry = + (struct ce_tasklet_entry *)data; + struct HIF_CE_state *hif_ce_state = tasklet_entry->hif_ce_state; + struct hif_softc *scn = HIF_GET_SOFTC(hif_ce_state); + struct CE_state *CE_state = scn->ce_id_to_state[tasklet_entry->ce_id]; + + hif_record_ce_desc_event(scn, tasklet_entry->ce_id, + HIF_CE_TASKLET_ENTRY, NULL, NULL, 0); + + if (qdf_atomic_read(&scn->link_suspended)) { + HIF_ERROR("%s: ce %d tasklet fired after link suspend.", + __func__, tasklet_entry->ce_id); + QDF_BUG(0); + } + + ce_per_engine_service(scn, tasklet_entry->ce_id); + + if (CE_state->lro_flush_cb != NULL) { + CE_state->lro_flush_cb(CE_state->lro_data); + } + + if (ce_check_rx_pending(CE_state)) { + /* + * There are frames pending, schedule tasklet to process them. + * Enable the interrupt only when there is no pending frames in + * any of the Copy Engine pipes. + */ + hif_record_ce_desc_event(scn, tasklet_entry->ce_id, + HIF_CE_TASKLET_RESCHEDULE, NULL, NULL, 0); + ce_schedule_tasklet(tasklet_entry); + return; + } + + if (scn->target_status != TARGET_STATUS_RESET) + hif_irq_enable(scn, tasklet_entry->ce_id); + + hif_record_ce_desc_event(scn, tasklet_entry->ce_id, HIF_CE_TASKLET_EXIT, + NULL, NULL, 0); + + qdf_atomic_dec(&scn->active_tasklet_cnt); +} + +/** + * ce_tasklet_init() - ce_tasklet_init + * @hif_ce_state: hif_ce_state + * @mask: mask + * + * Return: N/A + */ +void ce_tasklet_init(struct HIF_CE_state *hif_ce_state, uint32_t mask) +{ + int i; + + for (i = 0; i < CE_COUNT_MAX; i++) { + if (mask & (1 << i)) { + hif_ce_state->tasklets[i].ce_id = i; + hif_ce_state->tasklets[i].inited = true; + hif_ce_state->tasklets[i].hif_ce_state = hif_ce_state; + tasklet_init(&hif_ce_state->tasklets[i].intr_tq, + ce_tasklet, + (unsigned long)&hif_ce_state->tasklets[i]); + } + } +} +/** + * ce_tasklet_kill() - ce_tasklet_kill + * @hif_ce_state: hif_ce_state + * + * Return: N/A + */ +void ce_tasklet_kill(struct hif_softc *scn) +{ + int i; + struct HIF_CE_state *hif_ce_state = HIF_GET_CE_STATE(scn); + + for (i = 0; i < CE_COUNT_MAX; i++) + if (hif_ce_state->tasklets[i].inited) { + tasklet_kill(&hif_ce_state->tasklets[i].intr_tq); + hif_ce_state->tasklets[i].inited = false; + } + qdf_atomic_set(&scn->active_tasklet_cnt, 0); +} + +#define HIF_CE_DRAIN_WAIT_CNT 20 +/** + * hif_drain_tasklets(): wait untill no tasklet is pending + * @scn: hif context + * + * Let running tasklets clear pending trafic. + * + * Return: 0 if no bottom half is in progress when it returns. + * -EFAULT if it times out. + */ +int hif_drain_tasklets(struct hif_softc *scn) +{ + uint32_t ce_drain_wait_cnt = 0; + int32_t tasklet_cnt; + + while ((tasklet_cnt = qdf_atomic_read(&scn->active_tasklet_cnt))) { + if (++ce_drain_wait_cnt > HIF_CE_DRAIN_WAIT_CNT) { + HIF_ERROR("%s: CE still not done with access: %d", + __func__, tasklet_cnt); + + return -EFAULT; + } + HIF_INFO("%s: Waiting for CE to finish access", __func__); + msleep(10); + } + return 0; +} + +#ifdef WLAN_SUSPEND_RESUME_TEST +/** + * hif_fake_apps_resume_work() - Work handler for fake apps resume callback + * @work: The work struct being passed from the linux kernel + * + * Return: none + */ +void hif_fake_apps_resume_work(struct work_struct *work) +{ + struct fake_apps_context *ctx = + container_of(work, struct fake_apps_context, resume_work); + + QDF_BUG(ctx->resume_callback); + ctx->resume_callback(0); + ctx->resume_callback = NULL; +} + +/** + * hif_fake_apps_suspend(): Setup unit-test related suspend state. Call after + * a normal WoW suspend has been completed. + * @hif_ctx: The HIF context to operate on + * @callback: The function to call when fake apps resume is triggered + * + * Set the fake suspend flag such that hif knows that it will need + * to fake the apps resume process using hdd_trigger_fake_apps_resume + * + * Return: none + */ +void hif_fake_apps_suspend(struct hif_opaque_softc *hif_ctx, + hif_fake_resume_callback callback) +{ + struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx); + + scn->fake_apps_ctx.resume_callback = callback; + set_bit(HIF_FA_SUSPENDED_BIT, &scn->fake_apps_ctx.state); +} + +/** + * hif_fake_apps_resume(): Cleanup unit-test related suspend state. Call before + * doing a normal WoW resume if suspend was initiated via fake apps + * suspend. + * @hif_ctx: The HIF context to operate on + * + * Return: none + */ +void hif_fake_apps_resume(struct hif_opaque_softc *hif_ctx) +{ + struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx); + + clear_bit(HIF_FA_SUSPENDED_BIT, &scn->fake_apps_ctx.state); + scn->fake_apps_ctx.resume_callback = NULL; +} + +/** + * hif_interrupt_is_fake_apps_resume(): Determines if the raised irq should + * trigger a fake apps resume. + * @hif_ctx: The HIF context to operate on + * @ce_id: The copy engine Id from the originating interrupt + * + * Return: true if the raised irq should trigger a fake apps resume + */ +static bool hif_interrupt_is_fake_apps_resume(struct hif_opaque_softc *hif_ctx, + int ce_id) +{ + struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx); + uint8_t ul_pipe, dl_pipe; + int ul_is_polled, dl_is_polled; + QDF_STATUS status; + + if (!test_bit(HIF_FA_SUSPENDED_BIT, &scn->fake_apps_ctx.state)) + return false; + + /* ensure passed ce_id matches wake irq */ + /* dl_pipe will be populated with the wake irq number */ + status = hif_map_service_to_pipe(hif_ctx, HTC_CTRL_RSVD_SVC, + &ul_pipe, &dl_pipe, + &ul_is_polled, &dl_is_polled); + + if (status) { + HIF_ERROR("%s: pipe_mapping failure", __func__); + return false; + } + + return ce_id == dl_pipe; +} + +/** + * hif_trigger_fake_apps_resume(): Trigger a fake apps resume by scheduling the + * previously registered callback for execution + * @hif_ctx: The HIF context to operate on + * + * Return: None + */ +static void hif_trigger_fake_apps_resume(struct hif_opaque_softc *hif_ctx) +{ + struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx); + + if (!test_and_clear_bit(HIF_FA_SUSPENDED_BIT, + &scn->fake_apps_ctx.state)) + return; + + schedule_work(&scn->fake_apps_ctx.resume_work); +} + +#else + +static inline bool +hif_interrupt_is_fake_apps_resume(struct hif_opaque_softc *hif_ctx, int ce_id) +{ + return false; +} + +static inline void +hif_trigger_fake_apps_resume(struct hif_opaque_softc *hif_ctx) +{ +} + +#endif /* End of WLAN_SUSPEND_RESUME_TEST */ + +/** + * hif_snoc_interrupt_handler() - hif_snoc_interrupt_handler + * @irq: irq coming from kernel + * @context: context + * + * Return: N/A + */ +static irqreturn_t hif_snoc_interrupt_handler(int irq, void *context) +{ + struct ce_tasklet_entry *tasklet_entry = context; + struct hif_softc *scn = HIF_GET_SOFTC(tasklet_entry->hif_ce_state); + + return ce_dispatch_interrupt(pld_get_ce_id(scn->qdf_dev->dev, irq), + tasklet_entry); +} + +/** + * hif_ce_increment_interrupt_count() - update ce stats + * @hif_ce_state: ce state + * @ce_id: ce id + * + * Return: none + */ +static inline void +hif_ce_increment_interrupt_count(struct HIF_CE_state *hif_ce_state, int ce_id) +{ + int cpu_id = qdf_get_cpu(); + + hif_ce_state->stats.ce_per_cpu[ce_id][cpu_id]++; +} + +/** + * hif_display_ce_stats() - display ce stats + * @hif_ce_state: ce state + * + * Return: none + */ +void hif_display_ce_stats(struct HIF_CE_state *hif_ce_state) +{ +#define STR_SIZE 128 + uint8_t i, j, pos; + char str_buffer[STR_SIZE]; + int size, ret; + + qdf_print("CE interrupt statistics:"); + for (i = 0; i < CE_COUNT_MAX; i++) { + size = STR_SIZE; + pos = 0; + for (j = 0; j < QDF_MAX_AVAILABLE_CPU; j++) { + ret = snprintf(str_buffer + pos, size, "[%d]:%d ", + j, hif_ce_state->stats.ce_per_cpu[i][j]); + if (ret <= 0 || ret >= size) + break; + size -= ret; + pos += ret; + } + qdf_print("CE id[%2d] - %s", i, str_buffer); + } +#undef STR_SIZE +} + +/** + * hif_clear_ce_stats() - clear ce stats + * @hif_ce_state: ce state + * + * Return: none + */ +void hif_clear_ce_stats(struct HIF_CE_state *hif_ce_state) +{ + qdf_mem_zero(&hif_ce_state->stats, sizeof(struct ce_stats)); +} + +/** + * ce_dispatch_interrupt() - dispatch an interrupt to a processing context + * @ce_id: ce_id + * @tasklet_entry: context + * + * Return: N/A + */ +irqreturn_t ce_dispatch_interrupt(int ce_id, + struct ce_tasklet_entry *tasklet_entry) +{ + struct HIF_CE_state *hif_ce_state = tasklet_entry->hif_ce_state; + struct hif_softc *scn = HIF_GET_SOFTC(hif_ce_state); + struct hif_opaque_softc *hif_hdl = GET_HIF_OPAQUE_HDL(scn); + + if (tasklet_entry->ce_id != ce_id) { + HIF_ERROR("%s: ce_id (expect %d, received %d) does not match", + __func__, tasklet_entry->ce_id, ce_id); + return IRQ_NONE; + } + if (unlikely(ce_id >= CE_COUNT_MAX)) { + HIF_ERROR("%s: ce_id=%d > CE_COUNT_MAX=%d", + __func__, tasklet_entry->ce_id, CE_COUNT_MAX); + return IRQ_NONE; + } + hif_irq_disable(scn, ce_id); + hif_record_ce_desc_event(scn, ce_id, HIF_IRQ_EVENT, NULL, NULL, 0); + hif_ce_increment_interrupt_count(hif_ce_state, ce_id); + + if (unlikely(hif_interrupt_is_fake_apps_resume(hif_hdl, ce_id))) { + hif_trigger_fake_apps_resume(hif_hdl); + hif_irq_enable(scn, ce_id); + return IRQ_HANDLED; + } + + qdf_atomic_inc(&scn->active_tasklet_cnt); + + if (hif_napi_enabled(hif_hdl, ce_id)) + hif_napi_schedule(hif_hdl, ce_id); + else + tasklet_schedule(&tasklet_entry->intr_tq); + + return IRQ_HANDLED; +} + +/** + * const char *ce_name + * + * @ce_name: ce_name + */ +const char *ce_name[] = { + "WLAN_CE_0", + "WLAN_CE_1", + "WLAN_CE_2", + "WLAN_CE_3", + "WLAN_CE_4", + "WLAN_CE_5", + "WLAN_CE_6", + "WLAN_CE_7", + "WLAN_CE_8", + "WLAN_CE_9", + "WLAN_CE_10", + "WLAN_CE_11", +}; +/** + * ce_unregister_irq() - ce_unregister_irq + * @hif_ce_state: hif_ce_state copy engine device handle + * @mask: which coppy engines to unregister for. + * + * Unregisters copy engine irqs matching mask. If a 1 is set at bit x, + * unregister for copy engine x. + * + * Return: QDF_STATUS + */ +QDF_STATUS ce_unregister_irq(struct HIF_CE_state *hif_ce_state, uint32_t mask) +{ + int id; + int ce_count; + int ret; + struct hif_softc *scn; + + if (hif_ce_state == NULL) { + HIF_WARN("%s: hif_ce_state = NULL", __func__); + return QDF_STATUS_SUCCESS; + } + + scn = HIF_GET_SOFTC(hif_ce_state); + ce_count = scn->ce_count; + /* we are removing interrupts, so better stop NAPI */ + ret = hif_napi_event(GET_HIF_OPAQUE_HDL(scn), + NAPI_EVT_INT_STATE, (void *)0); + if (ret != 0) + HIF_ERROR("%s: napi_event INT_STATE returned %d", + __func__, ret); + /* this is not fatal, continue */ + + for (id = 0; id < ce_count; id++) { + if ((mask & (1 << id)) && hif_ce_state->tasklets[id].inited) { + ret = pld_ce_free_irq(scn->qdf_dev->dev, id, + &hif_ce_state->tasklets[id]); + if (ret < 0) + HIF_ERROR( + "%s: pld_unregister_irq error - ce_id = %d, ret = %d", + __func__, id, ret); + } + } + return QDF_STATUS_SUCCESS; +} +/** + * ce_register_irq() - ce_register_irq + * @hif_ce_state: hif_ce_state + * @mask: which coppy engines to unregister for. + * + * Registers copy engine irqs matching mask. If a 1 is set at bit x, + * Register for copy engine x. + * + * Return: QDF_STATUS + */ +QDF_STATUS ce_register_irq(struct HIF_CE_state *hif_ce_state, uint32_t mask) +{ + int id; + int ce_count; + int ret; + unsigned long irqflags = IRQF_TRIGGER_RISING; + uint32_t done_mask = 0; + struct hif_softc *scn = HIF_GET_SOFTC(hif_ce_state); + + ce_count = scn->ce_count; + + for (id = 0; id < ce_count; id++) { + if ((mask & (1 << id)) && hif_ce_state->tasklets[id].inited) { + ret = pld_ce_request_irq(scn->qdf_dev->dev, id, + hif_snoc_interrupt_handler, + irqflags, ce_name[id], + &hif_ce_state->tasklets[id]); + if (ret) { + HIF_ERROR( + "%s: cannot register CE %d irq handler, ret = %d", + __func__, id, ret); + ce_unregister_irq(hif_ce_state, done_mask); + return QDF_STATUS_E_FAULT; + } else { + done_mask |= 1 << id; + } + } + } + + return QDF_STATUS_SUCCESS; +} diff --git a/drivers/staging/qca-wifi-host-cmn/hif/src/ce/ce_tasklet.h b/drivers/staging/qca-wifi-host-cmn/hif/src/ce/ce_tasklet.h new file mode 100644 index 0000000000000000000000000000000000000000..a6fbdfd84856fb53530b177032583d28cb48cb12 --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/hif/src/ce/ce_tasklet.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2015-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef __CE_TASKLET_H__ +#define __CE_TASKLET_H__ +#include "ce_main.h" +void init_tasklet_workers(struct hif_opaque_softc *scn); +void ce_tasklet_init(struct HIF_CE_state *hif_ce_state, uint32_t mask); +void ce_tasklet_kill(struct hif_softc *scn); +int hif_drain_tasklets(struct hif_softc *scn); +QDF_STATUS ce_register_irq(struct HIF_CE_state *hif_ce_state, uint32_t mask); +QDF_STATUS ce_unregister_irq(struct HIF_CE_state *hif_ce_state, uint32_t mask); +irqreturn_t ce_dispatch_interrupt(int irq, + struct ce_tasklet_entry *tasklet_entry); +void hif_display_ce_stats(struct HIF_CE_state *hif_ce_state); +void hif_clear_ce_stats(struct HIF_CE_state *hif_ce_state); +#endif /* __CE_TASKLET_H__ */ diff --git a/drivers/staging/qca-wifi-host-cmn/hif/src/dispatcher/ahb_api.h b/drivers/staging/qca-wifi-host-cmn/hif/src/dispatcher/ahb_api.h new file mode 100644 index 0000000000000000000000000000000000000000..2bba2ff92d8e56f02ee330f66c2b00ab47428430 --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/hif/src/dispatcher/ahb_api.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2013-2016 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 __AHB_API_H +#define __AHB_API_H + +QDF_STATUS hif_ahb_open(struct hif_softc *hif_ctx, + enum qdf_bus_type bus_type); +void hif_ahb_close(struct hif_softc *hif_ctx); + + +void hif_ahb_disable_isr(struct hif_softc *hif_ctx); +void hif_ahb_nointrs(struct hif_softc *scn); +void hif_ahb_reset_soc(struct hif_softc *hif_ctx); +QDF_STATUS hif_ahb_enable_bus(struct hif_softc *ol_sc, + struct device *dev, void *bdev, + const hif_bus_id *bid, + enum hif_enable_type type); +void hif_ahb_disable_bus(struct hif_softc *scn); +int hif_ahb_bus_configure(struct hif_softc *scn); +void hif_ahb_irq_disable(struct hif_softc *scn, int ce_id); +void hif_ahb_irq_enable(struct hif_softc *scn, int ce_id); +int hif_ahb_dump_registers(struct hif_softc *scn); + +int hif_ahb_configure_legacy_irq(struct hif_pci_softc *sc); +int hif_ahb_clk_enable_disable(struct device *dev, int enable); +void hif_ahb_device_reset(struct hif_softc *scn); +int hif_ahb_enable_radio(struct hif_pci_softc *sc, + struct platform_device *pdev, + const struct platform_device_id *id); + +#endif diff --git a/drivers/staging/qca-wifi-host-cmn/hif/src/dispatcher/dummy.c b/drivers/staging/qca-wifi-host-cmn/hif/src/dispatcher/dummy.c new file mode 100644 index 0000000000000000000000000000000000000000..1690e058d8deff92e6edd1e43ca05497ae147583 --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/hif/src/dispatcher/dummy.c @@ -0,0 +1,338 @@ +/* + * Copyright (c) 2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#include "qdf_types.h" +#include "dummy.h" +#include "hif_debug.h" + +/** + * hif_dummy_bus_prevent_linkdown() - prevent linkdown + * @hif_ctx: hif context + * @flag: weather to keep the bus alive or not + * + * Dummy function for busses and platforms that do not support + * link down. This may need to be replaced with a wakelock. + */ +void hif_dummy_bus_prevent_linkdown(struct hif_softc *scn, bool flag) +{ + HIF_ERROR("wlan: %s pcie power collapse ignored", + (flag ? "disable" : "enable")); +} + +/** + * hif_reset_soc(): reset soc + * + * this function resets soc + * + * @hif_ctx: HIF context + * + * Return: void + */ +/* Function to reset SoC */ +void hif_dummy_reset_soc(struct hif_softc *hif_ctx) +{ +} + +/** + * hif_dummy_suspend() - suspend the bus + * @hif_ctx: hif context + * + * dummy for busses that don't need to suspend. + * + * Return: 0 for success and non-zero for failure + */ +int hif_dummy_bus_suspend(struct hif_softc *hif_ctx) +{ + return 0; +} + +/** + * hif_dummy_resume() - hif resume API + * + * This function resumes the bus. but snoc doesn't need to resume. + * Therefore do nothing. + * + * Return: 0 for success and non-zero for failure + */ +int hif_dummy_bus_resume(struct hif_softc *hif_ctx) +{ + return 0; +} + +/** + * hif_dummy_suspend_noirq() - suspend the bus + * @hif_ctx: hif context + * + * dummy for busses that don't need to syncronize + * with interrupt disable. + * + * Return: 0 for success and non-zero for failure + */ +int hif_dummy_bus_suspend_noirq(struct hif_softc *hif_ctx) +{ + return 0; +} + +/** + * hif_dummy_resume_noirq() - resume the bus + * @hif_ctx: hif context + * + * dummy for busses that don't need to syncronize + * with interrupt disable. + * + * Return: 0 for success and non-zero for failure + */ +int hif_dummy_bus_resume_noirq(struct hif_softc *hif_ctx) +{ + return 0; +} + +/** + * hif_dummy_target_sleep_state_adjust() - api to adjust state of target + * @scn: hif context + * @sleep_ok: allow or deny target to go to sleep + * @wait_for_it: ensure target has change + */ +int hif_dummy_target_sleep_state_adjust(struct hif_softc *scn, + bool sleep_ok, bool wait_for_it) +{ + return 0; +} + +/** + * hif_dummy_enable_power_management - dummy call + * hif_ctx: hif context + * is_packet_log_enabled: true if packet log is enabled + */ +void hif_dummy_enable_power_management(struct hif_softc *hif_ctx, + bool is_packet_log_enabled) +{} + +/** + * hif_dummy_disable_power_management - dummy call + * hif_ctx: hif context + * + * Return: none + */ +void hif_dummy_disable_power_management(struct hif_softc *hif_ctx) +{} + +/** + * hif_dummy_disable_isr - dummy call + * hif_ctx: hif context + * + * Return: none + */ +void hif_dummy_disable_isr(struct hif_softc *scn) +{} + +/** + * hif_dummy_nointrs - dummy call + * hif_sc: hif context + * + * Return: none + */ +void hif_dummy_nointrs(struct hif_softc *hif_sc) +{} + +/** + * hif_dummy_bus_configure - dummy call + * hif_ctx: hif context + * + * Return: 0 for sucess + */ +int hif_dummy_bus_configure(struct hif_softc *hif_sc) +{ + return 0; +} + +/** + * hif_dummy_get_config_item - dummy call + * @hif_sc: hif context + * @opcode: configuration type + * @config: configuration value to set + * @config_len: configuration length + * + * Return: 0 for sucess + */ +QDF_STATUS +hif_dummy_get_config_item(struct hif_softc *hif_sc, + int opcode, void *config, uint32_t config_len) +{ + return 0; +} + +/** + * hif_dummy_set_mailbox_swap - dummy call + * @hif_sc: hif context + * + * Return: None + */ +void +hif_dummy_set_mailbox_swap(struct hif_softc *hif_sc) +{ + return; +} + +/** + * hif_dummy_claim_device - dummy call + * @hif_sc: hif context + * + * Return: None + */ +void +hif_dummy_claim_device(struct hif_softc *hif_sc) +{ + return; +} + +/** + * hif_dummy_cancel_deferred_target_sleep - dummy call + * @hif_sc: hif context + * + * Return: None + */ +void +hif_dummy_cancel_deferred_target_sleep(struct hif_softc *hif_sc) +{ + return; +} + +/** + * hif_dummy_irq_enable - dummy call + * hif_ctx: hif context + * @irq_id: irq id + * + * Return: none + */ +void hif_dummy_irq_enable(struct hif_softc *hif_sc, int irq_id) +{} + +/** + * hif_dummy_irq_disable - dummy call + * hif_ctx: hif context + * @irq_id: irq id + * + * Return: none + */ +void hif_dummy_irq_disable(struct hif_softc *hif_sc, int irq_id) +{} + +/** + * hif_dummy_dump_registers - dummy call + * hif_sc: hif context + * + * Return: 0 for sucess + */ +int hif_dummy_dump_registers(struct hif_softc *hif_sc) +{ + return 0; +} + +/** + * hif_dummy_dump_target_memory - dummy call + * @hif_sc: hif context + * @ramdump_base: base + * @address: address + * @size: size + * + * Return: None + */ +void hif_dummy_dump_target_memory(struct hif_softc *hif_sc, void *ramdump_base, + uint32_t address, uint32_t size) +{ +} + +/** + * hif_dummy_ipa_get_ce_resource - dummy call + * @scn: HIF context + * @sr_base_paddr: source base address + * @sr_ring_size: source ring size + * @reg_paddr: bus physical address + * + * Return: None + */ +void hif_dummy_ipa_get_ce_resource(struct hif_softc *hif_sc, + qdf_dma_addr_t *sr_base_paddr, + uint32_t *sr_ring_size, + qdf_dma_addr_t *reg_paddr) +{ +} + +/** + * hif_dummy_mask_interrupt_call - dummy call + * @hif_sc: hif context + * + * Return: None + */ +void +hif_dummy_mask_interrupt_call(struct hif_softc *hif_sc) +{ + return; +} + +/** + * hif_dummy_display_stats - dummy call + * hif_ctx: hif context + * + * Return: none + */ +void hif_dummy_display_stats(struct hif_softc *hif_ctx) +{} + +/** + * hif_dummy_clear_stats - dummy call + * hif_ctx: hif context + * + * Return: none + */ +void hif_dummy_clear_stats(struct hif_softc *hif_ctx) +{} +/** + * hif_dummy_set_bundle_mode() - dummy call + * @hif_sc: hif context + * @enabled: flag to enable/disable bundling + * @rx_bundle_cnt: bundle count to be used for RX + * + * Return: none + */ +void hif_dummy_set_bundle_mode(struct hif_softc *hif_ctx, + bool enabled, int rx_bundle_cnt) +{ + return; +} + +/** + * hif_dummy_bus_reset_resume() - dummy call + * @hif_sc: hif context + * + * Return: int 0 for success, non zero for failure + */ +int hif_dummy_bus_reset_resume(struct hif_softc *hif_ctx) +{ + return 0; +} diff --git a/drivers/staging/qca-wifi-host-cmn/hif/src/dispatcher/dummy.h b/drivers/staging/qca-wifi-host-cmn/hif/src/dispatcher/dummy.h new file mode 100644 index 0000000000000000000000000000000000000000..517f5c73cda59a2a3e2565e9a7a347140bb64dba --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/hif/src/dispatcher/dummy.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ +struct hif_softc; + +void hif_dummy_bus_prevent_linkdown(struct hif_softc *scn, bool flag); +void hif_dummy_reset_soc(struct hif_softc *scn); +int hif_dummy_bus_suspend(struct hif_softc *hif_ctx); +int hif_dummy_bus_resume(struct hif_softc *hif_ctx); +int hif_dummy_bus_suspend_noirq(struct hif_softc *hif_ctx); +int hif_dummy_bus_resume_noirq(struct hif_softc *hif_ctx); +int hif_dummy_target_sleep_state_adjust(struct hif_softc *scn, + bool sleep_ok, bool wait_for_it); +void hif_dummy_enable_power_management(struct hif_softc *hif_ctx, + bool is_packet_log_enabled); +void hif_dummy_disable_power_management(struct hif_softc *hif_ctx); +void hif_dummy_disable_isr(struct hif_softc *scn); +void hif_dummy_nointrs(struct hif_softc *hif_sc); +int hif_dummy_bus_configure(struct hif_softc *hif_sc); +QDF_STATUS hif_dummy_get_config_item(struct hif_softc *hif_sc, + int opcode, void *config, uint32_t config_len); +void hif_dummy_set_mailbox_swap(struct hif_softc *hif_sc); +void hif_dummy_claim_device(struct hif_softc *hif_sc); +void hif_dummy_cancel_deferred_target_sleep(struct hif_softc *hif_sc); +void hif_dummy_irq_enable(struct hif_softc *hif_sc, int irq_id); +void hif_dummy_irq_disable(struct hif_softc *hif_sc, int irq_id); +int hif_dummy_dump_registers(struct hif_softc *hif_sc); +void hif_dummy_dump_target_memory(struct hif_softc *hif_sc, void *ramdump_base, + uint32_t address, uint32_t size); +void hif_dummy_ipa_get_ce_resource(struct hif_softc *hif_sc, + qdf_dma_addr_t *sr_base_paddr, + uint32_t *sr_ring_size, + qdf_dma_addr_t *reg_paddr); +void hif_dummy_mask_interrupt_call(struct hif_softc *hif_sc); +void hif_dummy_display_stats(struct hif_softc *hif_ctx); +void hif_dummy_clear_stats(struct hif_softc *hif_ctx); +void hif_dummy_set_bundle_mode(struct hif_softc *hif_ctx, + bool enabled, int rx_bundle_cnt); +int hif_dummy_bus_reset_resume(struct hif_softc *hif_ctx); diff --git a/drivers/staging/qca-wifi-host-cmn/hif/src/dispatcher/multibus.c b/drivers/staging/qca-wifi-host-cmn/hif/src/dispatcher/multibus.c new file mode 100644 index 0000000000000000000000000000000000000000..0862fcdd6d63d43bb919b3ed76b39579aed9736d --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/hif/src/dispatcher/multibus.c @@ -0,0 +1,416 @@ +/* + * Copyright (c) 2016-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + + +/* this file dispatches functions to bus specific definitions */ +#include "hif_debug.h" +#include "hif.h" +#include "hif_main.h" +#include "hif_io32.h" +#include "multibus.h" +#include "dummy.h" +#if defined(HIF_PCI) || defined(HIF_SNOC) || defined(HIF_AHB) +#include "ce_main.h" +#endif +#include "htc_services.h" +#include "a_types.h" +#include "dummy.h" + +/** + * hif_intialize_default_ops() - intializes default operations values + * + * bus specific features should assign their dummy implementations here. + */ +static void hif_intialize_default_ops(struct hif_softc *hif_sc) +{ + struct hif_bus_ops *bus_ops = &hif_sc->bus_ops; + + /* must be filled in by hif_bus_open */ + bus_ops->hif_bus_close = NULL; + /* dummy implementations */ + bus_ops->hif_display_stats = + &hif_dummy_display_stats; + bus_ops->hif_clear_stats = + &hif_dummy_clear_stats; + bus_ops->hif_set_bundle_mode = &hif_dummy_set_bundle_mode; + bus_ops->hif_bus_reset_resume = &hif_dummy_bus_reset_resume; + bus_ops->hif_bus_suspend_noirq = &hif_dummy_bus_suspend_noirq; + bus_ops->hif_bus_resume_noirq = &hif_dummy_bus_resume_noirq; + bus_ops->hif_bus_early_suspend = &hif_dummy_bus_suspend; + bus_ops->hif_bus_late_resume = &hif_dummy_bus_resume; +} + +#define NUM_OPS (sizeof(struct hif_bus_ops) / sizeof(void *)) + +/** + * hif_verify_basic_ops() - ensure required bus apis are defined + * + * all bus operations must be defined to avoid crashes + * itterate over the structure and ensure all function pointers + * are non null. + * + * Return: QDF_STATUS_SUCCESS if all the operations are defined + */ +static QDF_STATUS hif_verify_basic_ops(struct hif_softc *hif_sc) +{ + struct hif_bus_ops *bus_ops = &hif_sc->bus_ops; + void **ops_array = (void *)bus_ops; + QDF_STATUS status = QDF_STATUS_SUCCESS; + int i; + + for (i = 0; i < NUM_OPS; i++) { + if (!ops_array[i]) { + HIF_ERROR("%s: function %d is null", __func__, i); + status = QDF_STATUS_E_NOSUPPORT; + } + } + return status; +} + +/** + * hif_bus_get_context_size - API to return size of the bus specific structure + * + * Return: sizeof of hif_pci_softc + */ +int hif_bus_get_context_size(enum qdf_bus_type bus_type) +{ + switch (bus_type) { + case QDF_BUS_TYPE_PCI: + return hif_pci_get_context_size(); + case QDF_BUS_TYPE_AHB: + return hif_ahb_get_context_size(); + case QDF_BUS_TYPE_SNOC: + return hif_snoc_get_context_size(); + case QDF_BUS_TYPE_SDIO: + return hif_sdio_get_context_size(); + case QDF_BUS_TYPE_USB: + return hif_usb_get_context_size(); + default: + return 0; + } +} + +/** + * hif_bus_open() - initialize the bus_ops and call the bus specific open + * hif_sc: hif_context + * bus_type: type of bus being enumerated + * + * Return: QDF_STATUS_SUCCESS or error + */ +QDF_STATUS hif_bus_open(struct hif_softc *hif_sc, + enum qdf_bus_type bus_type) +{ + QDF_STATUS status = QDF_STATUS_E_INVAL; + + hif_intialize_default_ops(hif_sc); + + switch (bus_type) { + case QDF_BUS_TYPE_PCI: + status = hif_initialize_pci_ops(hif_sc); + break; + case QDF_BUS_TYPE_SNOC: + status = hif_initialize_snoc_ops(&hif_sc->bus_ops); + break; + case QDF_BUS_TYPE_AHB: + status = hif_initialize_ahb_ops(&hif_sc->bus_ops); + break; + case QDF_BUS_TYPE_SDIO: + status = hif_initialize_sdio_ops(hif_sc); + break; + case QDF_BUS_TYPE_USB: + status = hif_initialize_usb_ops(&hif_sc->bus_ops); + break; + default: + status = QDF_STATUS_E_NOSUPPORT; + break; + } + + if (status != QDF_STATUS_SUCCESS) { + HIF_ERROR("%s: %d not supported", __func__, bus_type); + return status; + } + + status = hif_verify_basic_ops(hif_sc); + if (status != QDF_STATUS_SUCCESS) + return status; + + return hif_sc->bus_ops.hif_bus_open(hif_sc, bus_type); +} + +/** + * hif_bus_close() - close the bus + * @hif_sc: hif_context + */ +void hif_bus_close(struct hif_softc *hif_sc) +{ + hif_sc->bus_ops.hif_bus_close(hif_sc); +} + +/** + * hif_bus_prevent_linkdown() - prevent linkdown + * @hif_ctx: hif context + * @flag: true = keep bus alive false = let bus go to sleep + * + * Keeps the bus awake durring suspend. + */ +void hif_bus_prevent_linkdown(struct hif_softc *hif_sc, bool flag) +{ + hif_sc->bus_ops.hif_bus_prevent_linkdown(hif_sc, flag); +} + + +void hif_reset_soc(struct hif_opaque_softc *hif_ctx) +{ + struct hif_softc *hif_sc = HIF_GET_SOFTC(hif_ctx); + hif_sc->bus_ops.hif_reset_soc(hif_sc); +} + +int hif_bus_early_suspend(struct hif_opaque_softc *hif_ctx) +{ + struct hif_softc *hif_sc = HIF_GET_SOFTC(hif_ctx); + return hif_sc->bus_ops.hif_bus_early_suspend(hif_sc); +} + +int hif_bus_late_resume(struct hif_opaque_softc *hif_ctx) +{ + struct hif_softc *hif_sc = HIF_GET_SOFTC(hif_ctx); + return hif_sc->bus_ops.hif_bus_late_resume(hif_sc); +} + +int hif_bus_suspend(struct hif_opaque_softc *hif_ctx) +{ + struct hif_softc *hif_sc = HIF_GET_SOFTC(hif_ctx); + return hif_sc->bus_ops.hif_bus_suspend(hif_sc); +} + +int hif_bus_resume(struct hif_opaque_softc *hif_ctx) +{ + struct hif_softc *hif_sc = HIF_GET_SOFTC(hif_ctx); + return hif_sc->bus_ops.hif_bus_resume(hif_sc); +} + +int hif_bus_suspend_noirq(struct hif_opaque_softc *hif_ctx) +{ + struct hif_softc *hif_sc = HIF_GET_SOFTC(hif_ctx); + return hif_sc->bus_ops.hif_bus_suspend_noirq(hif_sc); +} + +int hif_bus_resume_noirq(struct hif_opaque_softc *hif_ctx) +{ + struct hif_softc *hif_sc = HIF_GET_SOFTC(hif_ctx); + return hif_sc->bus_ops.hif_bus_resume_noirq(hif_sc); +} + +int hif_target_sleep_state_adjust(struct hif_softc *hif_sc, + bool sleep_ok, bool wait_for_it) +{ + return hif_sc->bus_ops.hif_target_sleep_state_adjust(hif_sc, + sleep_ok, wait_for_it); +} + +void hif_disable_isr(struct hif_opaque_softc *hif_hdl) +{ + struct hif_softc *hif_sc = HIF_GET_SOFTC(hif_hdl); + hif_sc->bus_ops.hif_disable_isr(hif_sc); +} + +void hif_nointrs(struct hif_softc *hif_sc) +{ + hif_sc->bus_ops.hif_nointrs(hif_sc); +} + +QDF_STATUS hif_enable_bus(struct hif_softc *hif_sc, struct device *dev, + void *bdev, const hif_bus_id *bid, + enum hif_enable_type type) +{ + return hif_sc->bus_ops.hif_enable_bus(hif_sc, dev, bdev, bid, type); +} + +void hif_disable_bus(struct hif_softc *hif_sc) +{ + hif_sc->bus_ops.hif_disable_bus(hif_sc); +} + +int hif_bus_configure(struct hif_softc *hif_sc) +{ + return hif_sc->bus_ops.hif_bus_configure(hif_sc); +} + +QDF_STATUS hif_get_config_item(struct hif_opaque_softc *hif_ctx, + int opcode, void *config, uint32_t config_len) +{ + struct hif_softc *hif_sc = HIF_GET_SOFTC(hif_ctx); + return hif_sc->bus_ops.hif_get_config_item(hif_sc, opcode, config, + config_len); +} + +void hif_set_mailbox_swap(struct hif_opaque_softc *hif_ctx) +{ + struct hif_softc *hif_sc = HIF_GET_SOFTC(hif_ctx); + hif_sc->bus_ops.hif_set_mailbox_swap(hif_sc); +} + +void hif_claim_device(struct hif_opaque_softc *hif_ctx) +{ + struct hif_softc *hif_sc = HIF_GET_SOFTC(hif_ctx); + hif_sc->bus_ops.hif_claim_device(hif_sc); +} + +void hif_shutdown_device(struct hif_opaque_softc *hif_ctx) +{ + struct hif_softc *hif_sc = HIF_GET_SOFTC(hif_ctx); + hif_sc->bus_ops.hif_shutdown_device(hif_sc); +} + +void hif_stop(struct hif_opaque_softc *hif_ctx) +{ + struct hif_softc *hif_sc = HIF_GET_SOFTC(hif_ctx); + hif_sc->bus_ops.hif_stop(hif_sc); +} + +void hif_cancel_deferred_target_sleep(struct hif_softc *hif_sc) +{ + return hif_sc->bus_ops.hif_cancel_deferred_target_sleep(hif_sc); +} + +void hif_irq_enable(struct hif_softc *hif_sc, int irq_id) +{ + hif_sc->bus_ops.hif_irq_enable(hif_sc, irq_id); +} + +void hif_irq_disable(struct hif_softc *hif_sc, int irq_id) +{ + hif_sc->bus_ops.hif_irq_disable(hif_sc, irq_id); +} + +int hif_dump_registers(struct hif_opaque_softc *hif_hdl) +{ + struct hif_softc *hif_sc = HIF_GET_SOFTC(hif_hdl); + return hif_sc->bus_ops.hif_dump_registers(hif_sc); +} + +void hif_dump_target_memory(struct hif_opaque_softc *hif_hdl, + void *ramdump_base, + uint32_t address, uint32_t size) +{ + struct hif_softc *hif_sc = HIF_GET_SOFTC(hif_hdl); + hif_sc->bus_ops.hif_dump_target_memory(hif_sc, ramdump_base, + address, size); +} + +void hif_ipa_get_ce_resource(struct hif_opaque_softc *hif_hdl, + qdf_dma_addr_t *ce_sr_base_paddr, + uint32_t *ce_sr_ring_size, + qdf_dma_addr_t *ce_reg_paddr) +{ + struct hif_softc *hif_sc = HIF_GET_SOFTC(hif_hdl); + hif_sc->bus_ops.hif_ipa_get_ce_resource(hif_sc, ce_sr_base_paddr, + ce_sr_ring_size, ce_reg_paddr); +} + +void hif_mask_interrupt_call(struct hif_opaque_softc *hif_hdl) +{ + struct hif_softc *hif_sc = HIF_GET_SOFTC(hif_hdl); + hif_sc->bus_ops.hif_mask_interrupt_call(hif_sc); +} + +void hif_display_bus_stats(struct hif_opaque_softc *scn) +{ + struct hif_softc *hif_sc = HIF_GET_SOFTC(scn); + + hif_sc->bus_ops.hif_display_stats(hif_sc); +} + +void hif_clear_bus_stats(struct hif_opaque_softc *scn) +{ + struct hif_softc *hif_sc = HIF_GET_SOFTC(scn); + + hif_sc->bus_ops.hif_clear_stats(hif_sc); +} + +/** + * hif_enable_power_management() - enable power management after driver load + * @hif_hdl: opaque pointer to the hif context + * is_packet_log_enabled: true if packet log is enabled + * + * Driver load and firmware download are done in a high performance mode. + * Enable power management after the driver is loaded. + * packet log can require fewer power management features to be enabled. + */ +void hif_enable_power_management(struct hif_opaque_softc *hif_hdl, + bool is_packet_log_enabled) +{ + struct hif_softc *hif_sc = HIF_GET_SOFTC(hif_hdl); + hif_sc->bus_ops.hif_enable_power_management(hif_sc, + is_packet_log_enabled); +} + +/** + * hif_disable_power_management() - reset the bus power management + * @hif_hdl: opaque pointer to the hif context + * + * return the power management of the bus to its default state. + * This isn't necessarily a complete reversal of its counterpart. + * This should be called when unloading the driver. + */ +void hif_disable_power_management(struct hif_opaque_softc *hif_hdl) +{ + struct hif_softc *hif_sc = HIF_GET_SOFTC(hif_hdl); + hif_sc->bus_ops.hif_disable_power_management(hif_sc); +} + +/** + * hif_set_bundle_mode() - enable bundling and set default rx bundle cnt + * @scn: pointer to hif_opaque_softc structure + * @enabled: flag to enable/disable bundling + * @rx_bundle_cnt: bundle count to be used for RX + * + * Return: none + */ +void hif_set_bundle_mode(struct hif_opaque_softc *scn, bool enabled, + int rx_bundle_cnt) +{ + struct hif_softc *hif_sc = HIF_GET_SOFTC(scn); + hif_sc->bus_ops.hif_set_bundle_mode(hif_sc, enabled, rx_bundle_cnt); +} + +/** + * hif_bus_reset_resume() - resume the bus after reset + * @scn: struct hif_opaque_softc + * + * This function is called to tell the driver that USB device has been resumed + * and it has also been reset. The driver should redo any necessary + * initialization. This function resets WLAN SOC. + * + * Return: int 0 for success, non zero for failure + */ +int hif_bus_reset_resume(struct hif_opaque_softc *scn) + +{ + struct hif_softc *hif_sc = HIF_GET_SOFTC(scn); + return hif_sc->bus_ops.hif_bus_reset_resume(hif_sc); +} diff --git a/drivers/staging/qca-wifi-host-cmn/hif/src/dispatcher/multibus.h b/drivers/staging/qca-wifi-host-cmn/hif/src/dispatcher/multibus.h new file mode 100644 index 0000000000000000000000000000000000000000..5fdd9ca4f30895cc38e94f04932e2326144e0888 --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/hif/src/dispatcher/multibus.h @@ -0,0 +1,198 @@ +/* + * Copyright (c) 2016-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef _MULTIBUS_H_ +#define _MULTIBUS_H_ + +#include "osdep.h" +#include "qdf_status.h" +#include "hif_debug.h" + +struct hif_softc; + +struct hif_bus_ops { + QDF_STATUS (*hif_bus_open)(struct hif_softc *hif_sc, + enum qdf_bus_type bus_type); + void (*hif_bus_close)(struct hif_softc *hif_sc); + void (*hif_bus_prevent_linkdown)(struct hif_softc *hif_sc, bool flag); + void (*hif_reset_soc)(struct hif_softc *hif_sc); + int (*hif_bus_early_suspend)(struct hif_softc *hif_ctx); + int (*hif_bus_late_resume)(struct hif_softc *hif_ctx); + int (*hif_bus_suspend)(struct hif_softc *hif_ctx); + int (*hif_bus_resume)(struct hif_softc *hif_ctx); + int (*hif_bus_suspend_noirq)(struct hif_softc *hif_ctx); + int (*hif_bus_resume_noirq)(struct hif_softc *hif_ctx); + int (*hif_target_sleep_state_adjust)(struct hif_softc *scn, + bool sleep_ok, bool wait_for_it); + void (*hif_disable_isr)(struct hif_softc *hif_sc); + void (*hif_nointrs)(struct hif_softc *hif_sc); + QDF_STATUS (*hif_enable_bus)(struct hif_softc *hif_sc, + struct device *dev, void *bdev, const hif_bus_id *bid, + enum hif_enable_type type); + void (*hif_disable_bus)(struct hif_softc *hif_sc); + int (*hif_bus_configure)(struct hif_softc *hif_sc); + QDF_STATUS (*hif_get_config_item)(struct hif_softc *hif_sc, + int opcode, void *config, uint32_t config_len); + void (*hif_set_mailbox_swap)(struct hif_softc *hif_sc); + void (*hif_claim_device)(struct hif_softc *hif_sc); + void (*hif_shutdown_device)(struct hif_softc *hif_sc); + void (*hif_stop)(struct hif_softc *hif_sc); + void (*hif_cancel_deferred_target_sleep)(struct hif_softc *hif_sc); + void (*hif_irq_disable)(struct hif_softc *hif_sc, int ce_id); + void (*hif_irq_enable)(struct hif_softc *hif_sc, int ce_id); + int (*hif_dump_registers)(struct hif_softc *hif_sc); + void (*hif_dump_target_memory)(struct hif_softc *hif_sc, + void *ramdump_base, + uint32_t address, uint32_t size); + void (*hif_ipa_get_ce_resource)(struct hif_softc *hif_sc, + qdf_dma_addr_t *sr_base_paddr, + uint32_t *sr_ring_size, + qdf_dma_addr_t *reg_paddr); + void (*hif_mask_interrupt_call)(struct hif_softc *hif_sc); + void (*hif_enable_power_management)(struct hif_softc *hif_ctx, + bool is_packet_log_enabled); + void (*hif_disable_power_management)(struct hif_softc *hif_ctx); + void (*hif_display_stats)(struct hif_softc *hif_ctx); + void (*hif_clear_stats)(struct hif_softc *hif_ctx); + void (*hif_set_bundle_mode) (struct hif_softc *hif_ctx, bool enabled, + int rx_bundle_cnt); + int (*hif_bus_reset_resume)(struct hif_softc *hif_ctx); +}; + +#ifdef HIF_SNOC +QDF_STATUS hif_initialize_snoc_ops(struct hif_bus_ops *hif_sc); +int hif_snoc_get_context_size(void); +#else +static inline QDF_STATUS hif_initialize_snoc_ops(struct hif_bus_ops *hif_sc) +{ + HIF_ERROR("%s: not supported", __func__); + return QDF_STATUS_E_NOSUPPORT; +} +/** + * hif_snoc_get_context_size() - dummy when snoc isn't supported + * + * Return: 0 as an invalid size to indicate no support + */ +static inline int hif_snoc_get_context_size(void) +{ + return 0; +} +#endif /* HIF_SNOC */ + +#ifdef HIF_PCI +QDF_STATUS hif_initialize_pci_ops(struct hif_softc *hif_sc); +int hif_pci_get_context_size(void); +#else +static inline QDF_STATUS hif_initialize_pci_ops(struct hif_softc *hif_sc) +{ + HIF_ERROR("%s: not supported", __func__); + return QDF_STATUS_E_NOSUPPORT; +} +/** + * hif_pci_get_context_size() - dummy when pci isn't supported + * + * Return: 0 as an invalid size to indicate no support + */ +static inline int hif_pci_get_context_size(void) +{ + return 0; +} +#endif /* HIF_PCI */ + +#ifdef HIF_AHB +QDF_STATUS hif_initialize_ahb_ops(struct hif_bus_ops *bus_ops); +int hif_ahb_get_context_size(void); +#else +/** + * hif_initialize_ahb_ops() - dummy for when ahb not supported + * + * Return: QDF_STATUS_E_NOSUPPORT + */ +static inline QDF_STATUS hif_initialize_ahb_ops(struct hif_bus_ops *bus_ops) +{ + HIF_ERROR("%s: not supported", __func__); + return QDF_STATUS_E_NOSUPPORT; +} + +/** + * hif_ahb_get_context_size() - dummy for when ahb not supported + * + * Return: 0 as an invalid size to indicate no support + */ +static inline int hif_ahb_get_context_size(void) +{ + return 0; +} +#endif + +#ifdef HIF_SDIO +QDF_STATUS hif_initialize_sdio_ops(struct hif_softc *hif_sc); +int hif_sdio_get_context_size(void); +#else +/** + * hif_initialize_sdio_ops() - dummy for when sdio not supported + * + * Return: QDF_STATUS_E_NOSUPPORT + */ + +static inline QDF_STATUS hif_initialize_sdio_ops(struct hif_softc *hif_sc) +{ + HIF_ERROR("%s: not supported", __func__); + return QDF_STATUS_E_NOSUPPORT; +} + +/** + * hif_sdio_get_context_size() - dummy when sdio isn't supported + * + * Return: 0 as an invalid size to indicate no support + */ +static inline int hif_sdio_get_context_size(void) +{ + return 0; +} +#endif /* HIF_SDIO */ + +#ifdef HIF_USB +QDF_STATUS hif_initialize_usb_ops(struct hif_bus_ops *bus_ops); +int hif_usb_get_context_size(void); +#else +static inline QDF_STATUS hif_initialize_usb_ops(struct hif_bus_ops *bus_ops) +{ + HIF_ERROR("%s: not supported", __func__); + return QDF_STATUS_E_NOSUPPORT; +} +/** + * hif_usb_get_context_size() - dummy when usb isn't supported + * + * Return: 0 as an invalid size to indicate no support + */ +static inline int hif_usb_get_context_size(void) +{ + return 0; +} +#endif /* HIF_USB */ +#endif /* _MULTIBUS_H_ */ diff --git a/drivers/staging/qca-wifi-host-cmn/hif/src/dispatcher/multibus_ahb.c b/drivers/staging/qca-wifi-host-cmn/hif/src/dispatcher/multibus_ahb.c new file mode 100644 index 0000000000000000000000000000000000000000..d1bee78d607063a4b7c3afc3e3705115bc833647 --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/hif/src/dispatcher/multibus_ahb.c @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2016 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 "hif.h" +#include "hif_main.h" +#include "multibus.h" +#include "ce_main.h" +#include "if_pci.h" +#include "ahb_api.h" +#include "dummy.h" + +/** + * hif_initialize_ahb_ops() - initialize the ahb ops + * @bus_ops: hif_bus_ops table pointer to initialize + * + * This function will assign the set of callbacks that needs + * to be called for ipq4019 platform + * + * Return: QDF_STATUS_SUCCESS + */ +QDF_STATUS hif_initialize_ahb_ops(struct hif_bus_ops *bus_ops) +{ + bus_ops->hif_bus_open = &hif_ahb_open; + bus_ops->hif_bus_close = &hif_ahb_close; + bus_ops->hif_bus_prevent_linkdown = &hif_dummy_bus_prevent_linkdown; + bus_ops->hif_reset_soc = &hif_ahb_reset_soc; + bus_ops->hif_bus_suspend = &hif_dummy_bus_suspend; + bus_ops->hif_bus_resume = &hif_dummy_bus_resume; + bus_ops->hif_target_sleep_state_adjust = + &hif_dummy_target_sleep_state_adjust; + + bus_ops->hif_disable_isr = &hif_ahb_disable_isr; + bus_ops->hif_nointrs = &hif_ahb_nointrs; + bus_ops->hif_enable_bus = &hif_ahb_enable_bus; + bus_ops->hif_disable_bus = &hif_ahb_disable_bus; + bus_ops->hif_bus_configure = &hif_ahb_bus_configure; + bus_ops->hif_get_config_item = &hif_dummy_get_config_item; + bus_ops->hif_set_mailbox_swap = &hif_dummy_set_mailbox_swap; + bus_ops->hif_claim_device = &hif_dummy_claim_device; + bus_ops->hif_shutdown_device = &hif_ce_stop; + bus_ops->hif_stop = &hif_ce_stop; + bus_ops->hif_cancel_deferred_target_sleep = + &hif_dummy_cancel_deferred_target_sleep; + bus_ops->hif_irq_disable = &hif_ahb_irq_disable; + bus_ops->hif_irq_enable = &hif_ahb_irq_enable; + bus_ops->hif_dump_registers = &hif_ahb_dump_registers; + bus_ops->hif_dump_target_memory = &hif_dummy_dump_target_memory; + bus_ops->hif_ipa_get_ce_resource = &hif_dummy_ipa_get_ce_resource; + bus_ops->hif_mask_interrupt_call = &hif_dummy_mask_interrupt_call; + bus_ops->hif_enable_power_management = + &hif_dummy_enable_power_management; + bus_ops->hif_disable_power_management = + &hif_dummy_disable_power_management; + + return QDF_STATUS_SUCCESS; +} + +/** + * hif_ahb_get_context_size() - return the size of the snoc context + * + * Return the size of the context. (0 for invalid bus) + */ +int hif_ahb_get_context_size(void) +{ + return sizeof(struct HIF_CE_state); +} diff --git a/drivers/staging/qca-wifi-host-cmn/hif/src/dispatcher/multibus_pci.c b/drivers/staging/qca-wifi-host-cmn/hif/src/dispatcher/multibus_pci.c new file mode 100644 index 0000000000000000000000000000000000000000..545910515884e37f663600e298830e3fd9da43f9 --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/hif/src/dispatcher/multibus_pci.c @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#include "hif.h" +#include "hif_main.h" +#include "multibus.h" +#include "pci_api.h" +#include "hif_io32.h" +#include "dummy.h" +#include "ce_api.h" + +/** + * hif_initialize_pci_ops() - initialize the pci ops + * @bus_ops: hif_bus_ops table pointer to initialize + * + * Return: QDF_STATUS_SUCCESS + */ +QDF_STATUS hif_initialize_pci_ops(struct hif_softc *hif_sc) +{ + struct hif_bus_ops *bus_ops = &hif_sc->bus_ops; + + bus_ops->hif_bus_open = &hif_pci_open; + bus_ops->hif_bus_close = &hif_pci_close; + bus_ops->hif_bus_prevent_linkdown = &hif_pci_prevent_linkdown; + bus_ops->hif_reset_soc = &hif_pci_reset_soc; + bus_ops->hif_bus_suspend = &hif_pci_bus_suspend; + bus_ops->hif_bus_resume = &hif_pci_bus_resume; + + /* do not put the target to sleep for epping or maxperf mode */ + if (CONFIG_ATH_PCIE_MAX_PERF == 0 && + !QDF_IS_EPPING_ENABLED(hif_get_conparam(hif_sc))) + bus_ops->hif_target_sleep_state_adjust = + &hif_pci_target_sleep_state_adjust; + else + bus_ops->hif_target_sleep_state_adjust = + &hif_dummy_target_sleep_state_adjust; + + bus_ops->hif_disable_isr = &hif_pci_disable_isr; + bus_ops->hif_nointrs = &hif_pci_nointrs; + bus_ops->hif_enable_bus = &hif_pci_enable_bus; + bus_ops->hif_disable_bus = &hif_pci_disable_bus; + bus_ops->hif_bus_configure = &hif_pci_bus_configure; + bus_ops->hif_get_config_item = &hif_dummy_get_config_item; + bus_ops->hif_set_mailbox_swap = &hif_dummy_set_mailbox_swap; + bus_ops->hif_claim_device = &hif_dummy_claim_device; + bus_ops->hif_shutdown_device = &hif_ce_stop; + bus_ops->hif_stop = &hif_ce_stop; + bus_ops->hif_cancel_deferred_target_sleep = + &hif_pci_cancel_deferred_target_sleep; + bus_ops->hif_irq_disable = &hif_pci_irq_disable; + bus_ops->hif_irq_enable = &hif_pci_irq_enable; + bus_ops->hif_dump_registers = &hif_pci_dump_registers; + bus_ops->hif_dump_target_memory = &hif_ce_dump_target_memory; + bus_ops->hif_ipa_get_ce_resource = &hif_ce_ipa_get_ce_resource; + bus_ops->hif_mask_interrupt_call = &hif_dummy_mask_interrupt_call; + bus_ops->hif_enable_power_management = + &hif_pci_enable_power_management; + bus_ops->hif_disable_power_management = + &hif_pci_disable_power_management; + bus_ops->hif_display_stats = + &hif_pci_display_stats; + bus_ops->hif_clear_stats = + &hif_pci_clear_stats; + + return QDF_STATUS_SUCCESS; +} + +/** + * hif_pci_get_context_size() - return the size of the pci context + * + * Return the size of the context. (0 for invalid bus) + */ +int hif_pci_get_context_size(void) +{ + return sizeof(struct hif_pci_softc); +} diff --git a/drivers/staging/qca-wifi-host-cmn/hif/src/dispatcher/multibus_sdio.c b/drivers/staging/qca-wifi-host-cmn/hif/src/dispatcher/multibus_sdio.c new file mode 100644 index 0000000000000000000000000000000000000000..fc272025516a2073fc1327f18220ad89dca3776b --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/hif/src/dispatcher/multibus_sdio.c @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2016 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 "hif.h" +#include "hif_main.h" +#include "multibus.h" +#include "sdio_api.h" +#include "hif_io32.h" +#include "dummy.h" +#include "if_sdio.h" + +/** + * hif_initialize_sdio_ops() - initialize the pci ops + * @bus_ops: hif_bus_ops table pointer to initialize + * + * Return: QDF_STATUS_SUCCESS + */ +QDF_STATUS hif_initialize_sdio_ops(struct hif_softc *hif_sc) +{ + struct hif_bus_ops *bus_ops = &hif_sc->bus_ops; + + bus_ops->hif_bus_open = &hif_sdio_open; + bus_ops->hif_bus_close = &hif_sdio_close; + bus_ops->hif_bus_prevent_linkdown = &hif_dummy_bus_prevent_linkdown; + bus_ops->hif_reset_soc = &hif_dummy_reset_soc; + bus_ops->hif_bus_suspend = &hif_sdio_bus_suspend; + bus_ops->hif_bus_resume = &hif_sdio_bus_resume; + bus_ops->hif_target_sleep_state_adjust = + &hif_dummy_target_sleep_state_adjust; + bus_ops->hif_disable_isr = &hif_dummy_disable_isr; + bus_ops->hif_nointrs = &hif_dummy_nointrs; + bus_ops->hif_enable_bus = &hif_sdio_enable_bus; + bus_ops->hif_disable_bus = &hif_sdio_disable_bus; + bus_ops->hif_bus_configure = &hif_dummy_bus_configure; + bus_ops->hif_get_config_item = &hif_sdio_get_config_item; + bus_ops->hif_set_mailbox_swap = &hif_sdio_set_mailbox_swap; + bus_ops->hif_claim_device = &hif_sdio_claim_device; + bus_ops->hif_shutdown_device = &hif_sdio_shutdown; + bus_ops->hif_stop = &hif_sdio_stop; + bus_ops->hif_cancel_deferred_target_sleep = + &hif_dummy_cancel_deferred_target_sleep; + bus_ops->hif_irq_disable = &hif_dummy_irq_disable; + bus_ops->hif_irq_enable = &hif_dummy_irq_enable; + bus_ops->hif_dump_registers = &hif_dummy_dump_registers; + bus_ops->hif_dump_target_memory = &hif_dummy_dump_target_memory; + bus_ops->hif_ipa_get_ce_resource = &hif_dummy_ipa_get_ce_resource; + bus_ops->hif_mask_interrupt_call = &hif_sdio_mask_interrupt_call; + bus_ops->hif_enable_power_management = + &hif_dummy_enable_power_management; + bus_ops->hif_disable_power_management = + &hif_dummy_disable_power_management; + + return QDF_STATUS_SUCCESS; +} + +/** + * hif_sdio_get_context_size() - return the size of the sdio context + * + * Return the size of the context. (0 for invalid bus) + */ +int hif_sdio_get_context_size(void) +{ + return sizeof(struct hif_sdio_softc); +} diff --git a/drivers/staging/qca-wifi-host-cmn/hif/src/dispatcher/multibus_snoc.c b/drivers/staging/qca-wifi-host-cmn/hif/src/dispatcher/multibus_snoc.c new file mode 100644 index 0000000000000000000000000000000000000000..b9b41755fb405abe49f21638688ea640464f69cb --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/hif/src/dispatcher/multibus_snoc.c @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2016-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#include "hif.h" +#include "hif_main.h" +#include "multibus.h" +#include "ce_main.h" +#include "snoc_api.h" +#include "dummy.h" +#include "ce_api.h" + +/** + * hif_initialize_pci_ops() - initialize the pci ops + * @bus_ops: hif_bus_ops table pointer to initialize + * + * Return: QDF_STATUS_SUCCESS + */ +QDF_STATUS hif_initialize_snoc_ops(struct hif_bus_ops *bus_ops) +{ + bus_ops->hif_bus_open = &hif_snoc_open; + bus_ops->hif_bus_close = &hif_snoc_close; + bus_ops->hif_bus_prevent_linkdown = &hif_dummy_bus_prevent_linkdown; + bus_ops->hif_reset_soc = &hif_dummy_reset_soc; + bus_ops->hif_bus_early_suspend = &hif_ce_bus_early_suspend; + bus_ops->hif_bus_late_resume = &hif_ce_bus_late_resume; + bus_ops->hif_bus_suspend = &hif_snoc_bus_suspend; + bus_ops->hif_bus_resume = &hif_snoc_bus_resume; + bus_ops->hif_bus_suspend_noirq = &hif_snoc_bus_suspend_noirq; + /* snoc_bus_resume_noirq had no side effects, use dummy resume_noirq */ + bus_ops->hif_bus_resume_noirq = &hif_dummy_bus_resume_noirq; + bus_ops->hif_target_sleep_state_adjust = + &hif_dummy_target_sleep_state_adjust; + + bus_ops->hif_disable_isr = &hif_snoc_disable_isr; + bus_ops->hif_nointrs = &hif_snoc_nointrs; + bus_ops->hif_enable_bus = &hif_snoc_enable_bus; + bus_ops->hif_disable_bus = &hif_snoc_disable_bus; + bus_ops->hif_bus_configure = &hif_snoc_bus_configure; + bus_ops->hif_get_config_item = &hif_dummy_get_config_item; + bus_ops->hif_set_mailbox_swap = &hif_dummy_set_mailbox_swap; + bus_ops->hif_claim_device = &hif_dummy_claim_device; + bus_ops->hif_shutdown_device = &hif_ce_stop; + bus_ops->hif_stop = &hif_ce_stop; + bus_ops->hif_cancel_deferred_target_sleep = + &hif_dummy_cancel_deferred_target_sleep; + bus_ops->hif_irq_disable = &hif_snoc_irq_disable; + bus_ops->hif_irq_enable = &hif_snoc_irq_enable; + bus_ops->hif_dump_registers = &hif_snoc_dump_registers; + bus_ops->hif_dump_target_memory = &hif_ce_dump_target_memory; + bus_ops->hif_ipa_get_ce_resource = &hif_ce_ipa_get_ce_resource; + bus_ops->hif_mask_interrupt_call = &hif_dummy_mask_interrupt_call; + bus_ops->hif_enable_power_management = + &hif_dummy_enable_power_management; + bus_ops->hif_disable_power_management = + &hif_dummy_disable_power_management; + bus_ops->hif_display_stats = + &hif_snoc_display_stats; + bus_ops->hif_clear_stats = + &hif_snoc_clear_stats; + + return QDF_STATUS_SUCCESS; +} + +/** + * hif_snoc_get_context_size() - return the size of the snoc context + * + * Return the size of the context. (0 for invalid bus) + */ +int hif_snoc_get_context_size(void) +{ + return sizeof(struct HIF_CE_state); +} diff --git a/drivers/staging/qca-wifi-host-cmn/hif/src/dispatcher/multibus_usb.c b/drivers/staging/qca-wifi-host-cmn/hif/src/dispatcher/multibus_usb.c new file mode 100644 index 0000000000000000000000000000000000000000..0f3af6007cb88f2e2133b79bafa9e2aa20304d8e --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/hif/src/dispatcher/multibus_usb.c @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2016 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 "hif.h" +#include "hif_main.h" +#include "multibus.h" +#include "usb_api.h" +#include "hif_io32.h" +#include "dummy.h" +#include "if_usb.h" + +/** + * hif_initialize_usb_ops() - initialize the usb ops + * @bus_ops: hif_bus_ops table pointer to initialize + * + * Return: QDF_STATUS_SUCCESS + */ +QDF_STATUS hif_initialize_usb_ops(struct hif_bus_ops *bus_ops) +{ + bus_ops->hif_bus_open = &hif_usb_open; + bus_ops->hif_bus_close = &hif_usb_close; + bus_ops->hif_bus_prevent_linkdown = &hif_dummy_bus_prevent_linkdown; + bus_ops->hif_reset_soc = &hif_dummy_reset_soc; + bus_ops->hif_bus_suspend = &hif_usb_bus_suspend; + bus_ops->hif_bus_resume = &hif_usb_bus_resume; + bus_ops->hif_target_sleep_state_adjust = + &hif_dummy_target_sleep_state_adjust; + bus_ops->hif_disable_isr = &hif_usb_disable_isr; + bus_ops->hif_nointrs = &hif_usb_nointrs; + bus_ops->hif_enable_bus = &hif_usb_enable_bus; + bus_ops->hif_disable_bus = &hif_usb_disable_bus; + bus_ops->hif_bus_configure = &hif_usb_bus_configure; + bus_ops->hif_get_config_item = &hif_dummy_get_config_item; + bus_ops->hif_set_mailbox_swap = &hif_dummy_set_mailbox_swap; + bus_ops->hif_claim_device = &hif_dummy_claim_device; + bus_ops->hif_shutdown_device = &hif_usb_shutdown_bus_device; + bus_ops->hif_stop = &hif_usb_stop_device; + bus_ops->hif_bus_pkt_dl_len_set = &hif_dummy_bus_pkt_dl_len_set; + bus_ops->hif_cancel_deferred_target_sleep = + &hif_dummy_cancel_deferred_target_sleep; + bus_ops->hif_irq_disable = &hif_usb_irq_disable; + bus_ops->hif_irq_enable = &hif_usb_irq_enable; + bus_ops->hif_dump_registers = &hif_dummy_dump_registers; + bus_ops->hif_dump_target_memory = &hif_dummy_dump_target_memory; + bus_ops->hif_ipa_get_ce_resource = &hif_dummy_ipa_get_ce_resource; + bus_ops->hif_enable_power_management = + &hif_dummy_enable_power_management; + bus_ops->hif_disable_power_management = + &hif_dummy_disable_power_management; + bus_ops->hif_set_bundle_mode = hif_usb_set_bundle_mode; + bus_ops->hif_bus_reset_resume = hif_usb_bus_reset_resume; + + return QDF_STATUS_SUCCESS; +} + +/** + * hif_usb_get_context_size() - return the size of the usb context + * + * Return the size of the context. (0 for invalid bus) + */ +int hif_usb_get_context_size(void) +{ + return sizeof(struct hif_usb_softc); +} diff --git a/drivers/staging/qca-wifi-host-cmn/hif/src/dispatcher/pci_api.h b/drivers/staging/qca-wifi-host-cmn/hif/src/dispatcher/pci_api.h new file mode 100644 index 0000000000000000000000000000000000000000..6395cf484c12f663a2a011ee93ec3746b2c929ba --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/hif/src/dispatcher/pci_api.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ +#ifndef _PCI_API_H_ +#define _PCI_API_H_ +QDF_STATUS hif_pci_open(struct hif_softc *hif_ctx, + enum qdf_bus_type bus_type); +void hif_pci_close(struct hif_softc *hif_ctx); +void hif_pci_prevent_linkdown(struct hif_softc *scn, bool flag); +void hif_pci_reset_soc(struct hif_softc *ol_sc); +int hif_pci_bus_suspend(struct hif_softc *scn); +int hif_pci_bus_resume(struct hif_softc *scn); +int hif_pci_target_sleep_state_adjust(struct hif_softc *scn, + bool sleep_ok, bool wait_for_it); + +void hif_pci_disable_isr(struct hif_softc *scn); +void hif_pci_nointrs(struct hif_softc *scn); +QDF_STATUS hif_pci_enable_bus(struct hif_softc *scn, + struct device *dev, void *bdev, + const hif_bus_id *bid, + enum hif_enable_type type); +void hif_pci_disable_bus(struct hif_softc *scn); +int hif_pci_bus_configure(struct hif_softc *scn); +void hif_pci_irq_disable(struct hif_softc *scn, int ce_id); +void hif_pci_irq_enable(struct hif_softc *scn, int ce_id); +int hif_pci_dump_registers(struct hif_softc *scn); +void hif_pci_enable_power_management(struct hif_softc *hif_ctx, + bool is_packet_log_enabled); +void hif_pci_disable_power_management(struct hif_softc *hif_ctx); +void hif_pci_display_stats(struct hif_softc *hif_ctx); +void hif_pci_clear_stats(struct hif_softc *hif_ctx); +#endif /* _PCI_API_H_ */ diff --git a/drivers/staging/qca-wifi-host-cmn/hif/src/dispatcher/sdio_api.h b/drivers/staging/qca-wifi-host-cmn/hif/src/dispatcher/sdio_api.h new file mode 100644 index 0000000000000000000000000000000000000000..61f0a25a331e2be8683fdf988508fff0cbf60738 --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/hif/src/dispatcher/sdio_api.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2016 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. + */ + +QDF_STATUS hif_sdio_open(struct hif_softc *hif_sc, + enum qdf_bus_type bus_type); +void hif_sdio_close(struct hif_softc *hif_sc); +int hif_sdio_bus_suspend(struct hif_softc *hif_ctx); +int hif_sdio_bus_resume(struct hif_softc *hif_ctx); +QDF_STATUS hif_sdio_enable_bus(struct hif_softc *hif_sc, + struct device *dev, void *bdev, const hif_bus_id *bid, + enum hif_enable_type type); +void hif_sdio_disable_bus(struct hif_softc *hif_sc); +QDF_STATUS +hif_sdio_get_config_item(struct hif_softc *hif_sc, + int opcode, void *config, uint32_t config_len); +void hif_sdio_set_mailbox_swap(struct hif_softc *hif_sc); +void hif_sdio_claim_device(struct hif_softc *hif_sc); +void hif_sdio_mask_interrupt_call(struct hif_softc *scn); diff --git a/drivers/staging/qca-wifi-host-cmn/hif/src/dispatcher/snoc_api.h b/drivers/staging/qca-wifi-host-cmn/hif/src/dispatcher/snoc_api.h new file mode 100644 index 0000000000000000000000000000000000000000..06fc43d5aefd833b1e7075072a7e6756b58c71a0 --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/hif/src/dispatcher/snoc_api.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef _SNOC_API_H_ +#define _SNOC_API_H_ +QDF_STATUS hif_snoc_open(struct hif_softc *hif_ctx, + enum qdf_bus_type bus_type); +void hif_snoc_close(struct hif_softc *hif_ctx); +int hif_snoc_bus_suspend(struct hif_softc *hif_ctx); +int hif_snoc_bus_resume(struct hif_softc *hif_ctx); +int hif_snoc_bus_suspend_noirq(struct hif_softc *scn); +void hif_snoc_disable_isr(struct hif_softc *hif_ctx); +void hif_snoc_nointrs(struct hif_softc *scn); +QDF_STATUS hif_snoc_enable_bus(struct hif_softc *ol_sc, + struct device *dev, void *bdev, + const hif_bus_id *bid, + enum hif_enable_type type); +void hif_snoc_disable_bus(struct hif_softc *scn); +int hif_snoc_bus_configure(struct hif_softc *scn); +void hif_snoc_irq_disable(struct hif_softc *scn, int ce_id); +void hif_snoc_irq_enable(struct hif_softc *scn, int ce_id); +int hif_snoc_dump_registers(struct hif_softc *scn); +void hif_snoc_display_stats(struct hif_softc *hif_ctx); +void hif_snoc_clear_stats(struct hif_softc *hif_ctx); +#endif /* _SNOC_API_H_ */ diff --git a/drivers/staging/qca-wifi-host-cmn/hif/src/dispatcher/usb_api.h b/drivers/staging/qca-wifi-host-cmn/hif/src/dispatcher/usb_api.h new file mode 100644 index 0000000000000000000000000000000000000000..db8f2fdc841aa1bfb29ba16d0bdd3411d0e7efcc --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/hif/src/dispatcher/usb_api.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2016 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 _USB_API_H_ +#define _USB_API_H_ + +QDF_STATUS hif_usb_open(struct hif_softc *hif_ctx, + enum qdf_bus_type bus_type); +void hif_usb_close(struct hif_softc *hif_ctx); + + +void hif_usb_disable_isr(struct hif_softc *hif_ctx); +void hif_usb_nointrs(struct hif_softc *scn); +QDF_STATUS hif_usb_enable_bus(struct hif_softc *ol_sc, + struct device *dev, void *bdev, + const hif_bus_id *bid, + enum hif_enable_type type); +void hif_usb_disable_bus(struct hif_softc *scn); +int hif_usb_bus_configure(struct hif_softc *scn); +void hif_usb_irq_disable(struct hif_softc *scn, int ce_id); +void hif_usb_irq_enable(struct hif_softc *scn, int ce_id); +int hif_usb_dump_registers(struct hif_softc *scn); +int hif_usb_bus_suspend(struct hif_softc *hif_ctx); +int hif_usb_bus_resume(struct hif_softc *hif_ctx); +void hif_usb_stop_device(struct hif_softc *hif_sc); +void hif_usb_shutdown_bus_device(struct hif_softc *scn); +int hif_usb_bus_reset_resume(struct hif_softc *hif_ctx); +void hif_usb_set_bundle_mode(struct hif_opaque_softc *scn, + bool enabled, int rx_bundle_cnt); +#endif /*_USB_API_H_*/ diff --git a/drivers/staging/qca-wifi-host-cmn/hif/src/hif_debug.h b/drivers/staging/qca-wifi-host-cmn/hif/src/hif_debug.h new file mode 100644 index 0000000000000000000000000000000000000000..a51437bebf3140bd6b09bcee572ae153af4fa07d --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/hif/src/hif_debug.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2014, 2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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 __HIF_DEBUG_H__ +#define __HIF_DEBUG_H__ +#include "qdf_trace.h" + +#define HIF_ERROR(args ...) \ + QDF_TRACE(QDF_MODULE_ID_HIF, QDF_TRACE_LEVEL_ERROR, ## args) +#define HIF_WARN(args ...) \ + QDF_TRACE(QDF_MODULE_ID_HIF, QDF_TRACE_LEVEL_WARN, ## args) +#define HIF_INFO(args ...) \ + QDF_TRACE(QDF_MODULE_ID_HIF, QDF_TRACE_LEVEL_INFO, ## args) +#define HIF_INFO_HI(args ...) \ + QDF_TRACE(QDF_MODULE_ID_HIF, QDF_TRACE_LEVEL_INFO_HIGH, ## args) +#define HIF_INFO_MED(args ...) \ + QDF_TRACE(QDF_MODULE_ID_HIF, QDF_TRACE_LEVEL_INFO_MED, ## args) +#define HIF_INFO_LO(args ...) \ + QDF_TRACE(QDF_MODULE_ID_HIF, QDF_TRACE_LEVEL_INFO_LOW, ## args) +#define HIF_TRACE(args ...) \ + QDF_TRACE(QDF_MODULE_ID_HIF, QDF_TRACE_LEVEL_INFO, ## args) +#define HIF_DBG(args ...) \ + QDF_TRACE(QDF_MODULE_ID_HIF, QDF_TRACE_LEVEL_DEBUG, ## args) + +#define HIF_ENTER(fmt, ...) QDF_TRACE(QDF_MODULE_ID_HIF, QDF_TRACE_LEVEL_INFO, \ + "Enter: %s "fmt, __func__, ## __VA_ARGS__) + +#define HIF_EXIT(fmt, ...) QDF_TRACE(QDF_MODULE_ID_HIF, QDF_TRACE_LEVEL_INFO, \ + "Exit: %s "fmt, __func__, ## __VA_ARGS__) + +#endif /* __HIF_DEBUG_H__ */ diff --git a/drivers/staging/qca-wifi-host-cmn/hif/src/hif_hw_version.h b/drivers/staging/qca-wifi-host-cmn/hif/src/hif_hw_version.h new file mode 100644 index 0000000000000000000000000000000000000000..1d392e29822c837d55b0e1e2690a1421521c6d0f --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/hif/src/hif_hw_version.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + + +#ifndef HIF_HW_VERSION_H +#define HIF_HW_VERSION_H + +#define AR6004_VERSION_REV1_3 0x31c8088a +#define AR9888_REV2_VERSION 0x4100016c +#define AR9887_REV1_VERSION 0x4100016d +#define AR6320_REV1_VERSION 0x5000000 +#define AR6320_REV1_1_VERSION 0x5000001 +#define AR6320_REV1_3_VERSION 0x5000003 +#define AR6320_REV2_1_VERSION 0x5010000 +#define AR6320_REV3_VERSION 0x5020000 +#define AR6320_REV3_2_VERSION 0x5030000 +#define AR6320_DEV_VERSION 0x1000000 +#define QCA9377_REV1_1_VERSION 0x5020001 +#define QCA9379_REV1_VERSION 0x5040000 +#define WCN3990_v1 0x40000000 +#define WCN3990_v2 0x40010000 +#define WCN3990_v2_1 0x40010002 + +struct qwlan_hw { + u32 id; + u32 subid; + const char *name; +}; + +#endif /* HIF_HW_VERSION_H */ diff --git a/drivers/staging/qca-wifi-host-cmn/hif/src/hif_io32.h b/drivers/staging/qca-wifi-host-cmn/hif/src/hif_io32.h new file mode 100644 index 0000000000000000000000000000000000000000..8c398931546fa60e5deec036e6dbddcf4acbfa47 --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/hif/src/hif_io32.h @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2015-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef __HIF_IO32_H__ +#define __HIF_IO32_H__ + +#include +#include "hif.h" +#include "hif_main.h" + +#define hif_read32_mb(addr) ioread32((void __iomem *)addr) +#define hif_write32_mb(addr, value) \ + iowrite32((u32)(value), (void __iomem *)(addr)) + +#define Q_TARGET_ACCESS_BEGIN(scn) \ + hif_target_sleep_state_adjust(scn, false, true) +#define Q_TARGET_ACCESS_END(scn) \ + hif_target_sleep_state_adjust(scn, true, false) + +/* + * A_TARGET_ACCESS_LIKELY will not wait for the target to wake up before + * continuing execution. Because A_TARGET_ACCESS_LIKELY does not guarantee + * that the target is awake before continuing, Q_TARGET_ACCESS macros must + * protect the actual target access. Since Q_TARGET_ACCESS protect the actual + * target access, A_TARGET_ACCESS_LIKELY hints are optional. + * + * To ignore "LIKELY" hints, set CONFIG_TARGET_ACCESS_LIKELY to 0 + * (slightly worse performance, less power) + * + * To use "LIKELY" hints, set CONFIG_TARGET_ACCESS_LIKELY to 1 + * (slightly better performance, more power) + * + * note: if a bus doesn't use hif_target_sleep_state_adjust, this will have + * no impact. + */ +#define CONFIG_TARGET_ACCESS_LIKELY 0 +#if CONFIG_TARGET_ACCESS_LIKELY +#define A_TARGET_ACCESS_LIKELY(scn) \ + hif_target_sleep_state_adjust(scn, false, false) +#define A_TARGET_ACCESS_UNLIKELY(scn) \ + hif_target_sleep_state_adjust(scn, true, false) +#else /* CONFIG_ATH_PCIE_ACCESS_LIKELY */ +#define A_TARGET_ACCESS_LIKELY(scn) \ + do { \ + unsigned long unused = (unsigned long)(scn); \ + unused = unused; \ + } while (0) + +#define A_TARGET_ACCESS_UNLIKELY(scn) \ + do { \ + unsigned long unused = (unsigned long)(scn); \ + unused = unused; \ + } while (0) +#endif /* CONFIG_ATH_PCIE_ACCESS_LIKELY */ + + +#ifdef HIF_PCI +#include "hif_io32_pci.h" +#endif +#ifdef HIF_SNOC +#include "hif_io32_snoc.h" +#endif /* HIF_PCI */ + +#ifdef CONFIG_IO_MEM_ACCESS_DEBUG +uint32_t hif_target_read_checked(struct hif_softc *scn, + uint32_t offset); +void hif_target_write_checked(struct hif_softc *scn, uint32_t offset, + uint32_t value); + +#define A_TARGET_READ(scn, offset) \ + hif_target_read_checked(scn, (offset)) +#define A_TARGET_WRITE(scn, offset, value) \ + hif_target_write_checked(scn, (offset), (value)) +#else /* CONFIG_ATH_PCIE_ACCESS_DEBUG */ +#define A_TARGET_READ(scn, offset) \ + hif_read32_mb(scn->mem + (offset)) +#define A_TARGET_WRITE(scn, offset, value) \ + hif_write32_mb((scn->mem) + (offset), value) +#endif + +void hif_irq_enable(struct hif_softc *scn, int irq_id); +void hif_irq_disable(struct hif_softc *scn, int irq_id); + + +#endif /* __HIF_IO32_H__ */ diff --git a/drivers/staging/qca-wifi-host-cmn/hif/src/hif_main.c b/drivers/staging/qca-wifi-host-cmn/hif/src/hif_main.c new file mode 100644 index 0000000000000000000000000000000000000000..a57f429f5e1466642f86dc41f0ed77f51db86c59 --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/hif/src/hif_main.c @@ -0,0 +1,1105 @@ +/* + * Copyright (c) 2015-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#include "targcfg.h" +#include "qdf_lock.h" +#include "qdf_status.h" +#include "qdf_status.h" +#include /* qdf_atomic_read */ +#include +#include "hif_io32.h" +#include +#include "regtable.h" +#define ATH_MODULE_NAME hif +#include +#include "hif_main.h" +#include "hif_hw_version.h" +#if defined(HIF_PCI) || defined(HIF_SNOC) || defined(HIF_AHB) +#include "ce_tasklet.h" +#endif +#include "qdf_trace.h" +#include "qdf_status.h" +#include "hif_debug.h" +#include "mp_dev.h" +#include "ce_api.h" +#include "hif_napi.h" + +void hif_dump(struct hif_opaque_softc *hif_ctx, uint8_t cmd_id, bool start) +{ + hif_trigger_dump(hif_ctx, cmd_id, start); +} + +/** + * hif_get_target_id(): hif_get_target_id + * + * Return the virtual memory base address to the caller + * + * @scn: hif_softc + * + * Return: A_target_id_t + */ +A_target_id_t hif_get_target_id(struct hif_softc *scn) +{ + return scn->mem; +} + +/** + * hif_get_targetdef(): hif_get_targetdef + * @scn: scn + * + * Return: void * + */ +void *hif_get_targetdef(struct hif_opaque_softc *hif_ctx) +{ + struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx); + + return scn->targetdef; +} + +/** + * hif_vote_link_down(): unvote for link up + * + * Call hif_vote_link_down to release a previous request made using + * hif_vote_link_up. A hif_vote_link_down call should only be made + * after a corresponding hif_vote_link_up, otherwise you could be + * negating a vote from another source. When no votes are present + * hif will not guarantee the linkstate after hif_bus_suspend. + * + * SYNCHRONIZE WITH hif_vote_link_up by only calling in MC thread + * and initialization deinitialization sequencences. + * + * Return: n/a + */ +void hif_vote_link_down(struct hif_opaque_softc *hif_ctx) +{ + struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx); + QDF_BUG(scn); + + scn->linkstate_vote--; + if (scn->linkstate_vote == 0) + hif_bus_prevent_linkdown(scn, false); +} + +/** + * hif_vote_link_up(): vote to prevent bus from suspending + * + * Makes hif guarantee that fw can message the host normally + * durring suspend. + * + * SYNCHRONIZE WITH hif_vote_link_up by only calling in MC thread + * and initialization deinitialization sequencences. + * + * Return: n/a + */ +void hif_vote_link_up(struct hif_opaque_softc *hif_ctx) +{ + struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx); + QDF_BUG(scn); + + scn->linkstate_vote++; + if (scn->linkstate_vote == 1) + hif_bus_prevent_linkdown(scn, true); +} + +/** + * hif_can_suspend_link(): query if hif is permitted to suspend the link + * + * Hif will ensure that the link won't be suspended if the upperlayers + * don't want it to. + * + * SYNCHRONIZATION: MC thread is stopped before bus suspend thus + * we don't need extra locking to ensure votes dont change while + * we are in the process of suspending or resuming. + * + * Return: false if hif will guarantee link up durring suspend. + */ +bool hif_can_suspend_link(struct hif_opaque_softc *hif_ctx) +{ + struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx); + QDF_BUG(scn); + + return scn->linkstate_vote == 0; +} + +#ifndef CONFIG_WIN +#define QCA9984_HOST_INTEREST_ADDRESS -1 +#define QCA9888_HOST_INTEREST_ADDRESS -1 +#define IPQ4019_HOST_INTEREST_ADDRESS -1 +#endif + +/** + * hif_hia_item_address(): hif_hia_item_address + * @target_type: target_type + * @item_offset: item_offset + * + * Return: n/a + */ +uint32_t hif_hia_item_address(uint32_t target_type, uint32_t item_offset) +{ + switch (target_type) { + case TARGET_TYPE_AR6002: + return AR6002_HOST_INTEREST_ADDRESS + item_offset; + case TARGET_TYPE_AR6003: + return AR6003_HOST_INTEREST_ADDRESS + item_offset; + case TARGET_TYPE_AR6004: + return AR6004_HOST_INTEREST_ADDRESS + item_offset; + case TARGET_TYPE_AR6006: + return AR6006_HOST_INTEREST_ADDRESS + item_offset; + case TARGET_TYPE_AR9888: + return AR9888_HOST_INTEREST_ADDRESS + item_offset; + case TARGET_TYPE_AR6320: + case TARGET_TYPE_AR6320V2: + return AR6320_HOST_INTEREST_ADDRESS + item_offset; + case TARGET_TYPE_ADRASTEA: + /* ADRASTEA doesn't have a host interest address */ + ASSERT(0); + return 0; + case TARGET_TYPE_AR900B: + return AR900B_HOST_INTEREST_ADDRESS + item_offset; + case TARGET_TYPE_QCA9984: + return QCA9984_HOST_INTEREST_ADDRESS + item_offset; + case TARGET_TYPE_QCA9888: + return QCA9888_HOST_INTEREST_ADDRESS + item_offset; + case TARGET_TYPE_IPQ4019: + return IPQ4019_HOST_INTEREST_ADDRESS + item_offset; + + default: + ASSERT(0); + return 0; + } +} + +/** + * hif_max_num_receives_reached() - check max receive is reached + * @scn: HIF Context + * @count: unsigned int. + * + * Output check status as bool + * + * Return: bool + */ +bool hif_max_num_receives_reached(struct hif_softc *scn, unsigned int count) +{ + if (QDF_IS_EPPING_ENABLED(hif_get_conparam(scn))) + return count > 120; + else + return count > MAX_NUM_OF_RECEIVES; +} + +/** + * init_buffer_count() - initial buffer count + * @maxSize: qdf_size_t + * + * routine to modify the initial buffer count to be allocated on an os + * platform basis. Platform owner will need to modify this as needed + * + * Return: qdf_size_t + */ +qdf_size_t init_buffer_count(qdf_size_t maxSize) +{ + return maxSize; +} + +/** + * hif_save_htc_htt_config_endpoint() - save htt_tx_endpoint + * @hif_ctx: hif context + * @htc_htt_tx_endpoint: htt_tx_endpoint + * + * Return: void + */ +void hif_save_htc_htt_config_endpoint(struct hif_opaque_softc *hif_ctx, + int htc_htt_tx_endpoint) +{ + struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx); + + if (!scn) { + HIF_ERROR("%s: error: scn or scn->hif_sc is NULL!", + __func__); + return; + } + + scn->htc_htt_tx_endpoint = htc_htt_tx_endpoint; +} + +static const struct qwlan_hw qwlan_hw_list[] = { + { + .id = AR6320_REV1_VERSION, + .subid = 0, + .name = "QCA6174_REV1", + }, + { + .id = AR6320_REV1_1_VERSION, + .subid = 0x1, + .name = "QCA6174_REV1_1", + }, + { + .id = AR6320_REV1_3_VERSION, + .subid = 0x2, + .name = "QCA6174_REV1_3", + }, + { + .id = AR6320_REV2_1_VERSION, + .subid = 0x4, + .name = "QCA6174_REV2_1", + }, + { + .id = AR6320_REV2_1_VERSION, + .subid = 0x5, + .name = "QCA6174_REV2_2", + }, + { + .id = AR6320_REV3_VERSION, + .subid = 0x6, + .name = "QCA6174_REV2.3", + }, + { + .id = AR6320_REV3_VERSION, + .subid = 0x8, + .name = "QCA6174_REV3", + }, + { + .id = AR6320_REV3_VERSION, + .subid = 0x9, + .name = "QCA6174_REV3_1", + }, + { + .id = AR6320_REV3_2_VERSION, + .subid = 0xA, + .name = "AR6320_REV3_2_VERSION", + }, + { + .id = WCN3990_v1, + .subid = 0x0, + .name = "WCN3990_V1", + }, + { + .id = WCN3990_v2, + .subid = 0x0, + .name = "WCN3990_V2", + }, + { + .id = WCN3990_v2_1, + .subid = 0x0, + .name = "WCN3990_V2.1", + }, + { + .id = QCA9379_REV1_VERSION, + .subid = 0xC, + .name = "QCA9379_REV1", + }, + { + .id = QCA9379_REV1_VERSION, + .subid = 0xD, + .name = "QCA9379_REV1_1", + } +}; + +/** + * hif_get_hw_name(): get a human readable name for the hardware + * @info: Target Info + * + * Return: human readable name for the underlying wifi hardware. + */ +static const char *hif_get_hw_name(struct hif_target_info *info) +{ + int i; + + if (info->hw_name) + return info->hw_name; + + for (i = 0; i < ARRAY_SIZE(qwlan_hw_list); i++) { + if (info->target_version == qwlan_hw_list[i].id && + info->target_revision == qwlan_hw_list[i].subid) { + return qwlan_hw_list[i].name; + } + } + + info->hw_name = qdf_mem_malloc(64); + if (!info->hw_name) + return "Unknown Device (nomem)"; + + i = qdf_snprint(info->hw_name, 64, "HW_VERSION=%x.", + info->target_version); + if (i < 0) + return "Unknown Device (snprintf failure)"; + else + return info->hw_name; +} + +/** + * hif_get_hw_info(): hif_get_hw_info + * @scn: scn + * @version: version + * @revision: revision + * + * Return: n/a + */ +void hif_get_hw_info(struct hif_opaque_softc *scn, u32 *version, u32 *revision, + const char **target_name) +{ + struct hif_target_info *info = hif_get_target_info_handle(scn); + struct hif_softc *sc = HIF_GET_SOFTC(scn); + + if (sc->bus_type == QDF_BUS_TYPE_USB) + hif_usb_get_hw_info(sc); + + *version = info->target_version; + *revision = info->target_revision; + *target_name = hif_get_hw_name(info); +} + +/** + * hif_open(): hif_open + * @qdf_ctx: QDF Context + * @mode: Driver Mode + * @bus_type: Bus Type + * @cbk: CDS Callbacks + * + * API to open HIF Context + * + * Return: HIF Opaque Pointer + */ +struct hif_opaque_softc *hif_open(qdf_device_t qdf_ctx, uint32_t mode, + enum qdf_bus_type bus_type, + struct hif_driver_state_callbacks *cbk) +{ + struct hif_softc *scn; + QDF_STATUS status = QDF_STATUS_SUCCESS; + int bus_context_size = hif_bus_get_context_size(bus_type); + + if (bus_context_size == 0) { + HIF_ERROR("%s: context size 0 not allowed", __func__); + return NULL; + } + + scn = (struct hif_softc *)qdf_mem_malloc(bus_context_size); + if (!scn) { + HIF_ERROR("%s: cannot alloc memory for HIF context of size:%d", + __func__, bus_context_size); + return GET_HIF_OPAQUE_HDL(scn); + } + + scn->qdf_dev = qdf_ctx; + scn->hif_con_param = mode; + qdf_atomic_init(&scn->active_tasklet_cnt); + qdf_atomic_init(&scn->link_suspended); + qdf_atomic_init(&scn->tasklet_from_intr); + qdf_mem_copy(&scn->callbacks, cbk, sizeof(struct hif_driver_state_callbacks)); + scn->bus_type = bus_type; + status = hif_bus_open(scn, bus_type); + if (status != QDF_STATUS_SUCCESS) { + HIF_ERROR("%s: hif_bus_open error = %d, bus_type = %d", + __func__, status, bus_type); + qdf_mem_free(scn); + scn = NULL; + } + + return GET_HIF_OPAQUE_HDL(scn); +} + +/** + * hif_close(): hif_close + * @hif_ctx: hif_ctx + * + * Return: n/a + */ +void hif_close(struct hif_opaque_softc *hif_ctx) +{ + struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx); + + if (scn == NULL) { + HIF_ERROR("%s: hif_opaque_softc is NULL", __func__); + return; + } + + if (scn->athdiag_procfs_inited) { + athdiag_procfs_remove(); + scn->athdiag_procfs_inited = false; + } + + if (scn->target_info.hw_name) { + char *hw_name = scn->target_info.hw_name; + scn->target_info.hw_name = "ErrUnloading"; + qdf_mem_free(hw_name); + } + + if (scn->vaddr_rri_on_ddr) + qdf_mem_free_consistent(scn->qdf_dev, scn->qdf_dev->dev, + (CE_COUNT*sizeof(uint32_t)), + scn->vaddr_rri_on_ddr, scn->paddr_rri_on_ddr, + 0); + + scn->vaddr_rri_on_ddr = NULL; + hif_bus_close(scn); + qdf_mem_free(scn); +} + +/** + * hif_enable(): hif_enable + * @hif_ctx: hif_ctx + * @dev: dev + * @bdev: bus dev + * @bid: bus ID + * @bus_type: bus type + * @type: enable type + * + * Return: QDF_STATUS + */ +QDF_STATUS hif_enable(struct hif_opaque_softc *hif_ctx, struct device *dev, + void *bdev, const hif_bus_id *bid, + enum qdf_bus_type bus_type, + enum hif_enable_type type) +{ + QDF_STATUS status; + struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx); + + if (scn == NULL) { + HIF_ERROR("%s: hif_ctx = NULL", __func__); + return QDF_STATUS_E_NULL_VALUE; + } + + status = hif_enable_bus(scn, dev, bdev, bid, type); + if (status != QDF_STATUS_SUCCESS) { + HIF_ERROR("%s: hif_enable_bus error = %d", + __func__, status); + return status; + } + + if (hif_bus_configure(scn)) { + HIF_ERROR("%s: Target probe failed.", __func__); + hif_disable_bus(scn); + status = QDF_STATUS_E_FAILURE; + return status; + } + + /* + * Flag to avoid potential unallocated memory access from MSI + * interrupt handler which could get scheduled as soon as MSI + * is enabled, i.e to take care of the race due to the order + * in where MSI is enabled before the memory, that will be + * in interrupt handlers, is allocated. + */ + + scn->hif_init_done = true; + + HIF_TRACE("%s: OK", __func__); + + return QDF_STATUS_SUCCESS; +} + +void hif_disable(struct hif_opaque_softc *hif_ctx, enum hif_disable_type type) +{ + struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx); + + if (!scn) + return; + + hif_nointrs(scn); + if (scn->hif_init_done == false) + hif_shutdown_device(hif_ctx); + else + hif_stop(hif_ctx); + + hif_disable_bus(scn); + + hif_wlan_disable(scn); + + scn->notice_send = false; + + HIF_INFO("%s: X", __func__); +} + +void hif_display_stats(struct hif_opaque_softc *hif_ctx) +{ + hif_display_bus_stats(hif_ctx); +} + +void hif_clear_stats(struct hif_opaque_softc *hif_ctx) +{ + hif_clear_bus_stats(hif_ctx); +} + +/** + * hif_crash_shutdown_dump_bus_register() - dump bus registers + * @hif_ctx: hif_ctx + * + * Return: n/a + */ +#if defined(TARGET_RAMDUMP_AFTER_KERNEL_PANIC) \ +&& defined(DEBUG) + +static void hif_crash_shutdown_dump_bus_register(void *hif_ctx) +{ + struct hif_opaque_softc *scn = hif_ctx; + + if (hif_check_soc_status(scn)) + return; + + if (hif_dump_registers(scn)) + HIF_ERROR("Failed to dump bus registers!"); +} + +/** + * hif_crash_shutdown(): hif_crash_shutdown + * + * This function is called by the platform driver to dump CE registers + * + * @hif_ctx: hif_ctx + * + * Return: n/a + */ +void hif_crash_shutdown(struct hif_opaque_softc *hif_ctx) +{ + struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx); + + if (!hif_ctx) + return; + + if (scn->bus_type == QDF_BUS_TYPE_SNOC) { + HIF_INFO_MED("%s: RAM dump disabled for bustype %d", + __func__, scn->bus_type); + return; + } + + if (TARGET_STATUS_RESET == scn->target_status) { + HIF_INFO_MED("%s: Target is already asserted, ignore!", + __func__); + return; + } + + if (hif_is_load_or_unload_in_progress(scn)) { + HIF_ERROR("%s: Load/unload is in progress, ignore!", __func__); + return; + } + + hif_crash_shutdown_dump_bus_register(hif_ctx); + + if (ol_copy_ramdump(hif_ctx)) + goto out; + + HIF_INFO_MED("%s: RAM dump collecting completed!", __func__); + +out: + return; +} +#else +void hif_crash_shutdown(struct hif_opaque_softc *hif_ctx) +{ + HIF_INFO_MED("%s: Collecting target RAM dump disabled", + __func__); + return; +} +#endif /* TARGET_RAMDUMP_AFTER_KERNEL_PANIC */ + +#ifdef QCA_WIFI_3_0 +/** + * hif_check_fw_reg(): hif_check_fw_reg + * @scn: scn + * @state: + * + * Return: int + */ +int hif_check_fw_reg(struct hif_opaque_softc *scn) +{ + return 0; +} +#endif + +#ifdef IPA_OFFLOAD +/** + * hif_read_phy_mem_base(): hif_read_phy_mem_base + * @scn: scn + * @phy_mem_base: physical mem base + * + * Return: n/a + */ +void hif_read_phy_mem_base(struct hif_softc *scn, qdf_dma_addr_t *phy_mem_base) +{ + *phy_mem_base = scn->mem_pa; +} +#endif /* IPA_OFFLOAD */ + +/** + * hif_get_device_type(): hif_get_device_type + * @device_id: device_id + * @revision_id: revision_id + * @hif_type: returned hif_type + * @target_type: returned target_type + * + * Return: int + */ +int hif_get_device_type(uint32_t device_id, + uint32_t revision_id, + uint32_t *hif_type, uint32_t *target_type) +{ + int ret = 0; + + switch (device_id) { + case ADRASTEA_DEVICE_ID: + case ADRASTEA_DEVICE_ID_P2_E12: + + *hif_type = HIF_TYPE_ADRASTEA; + *target_type = TARGET_TYPE_ADRASTEA; + break; + + case AR9888_DEVICE_ID: + *hif_type = HIF_TYPE_AR9888; + *target_type = TARGET_TYPE_AR9888; + break; + + case AR6320_DEVICE_ID: + switch (revision_id) { + case AR6320_FW_1_1: + case AR6320_FW_1_3: + *hif_type = HIF_TYPE_AR6320; + *target_type = TARGET_TYPE_AR6320; + break; + + case AR6320_FW_2_0: + case AR6320_FW_3_0: + case AR6320_FW_3_2: + *hif_type = HIF_TYPE_AR6320V2; + *target_type = TARGET_TYPE_AR6320V2; + break; + + default: + HIF_ERROR("%s: error - dev_id = 0x%x, rev_id = 0x%x", + __func__, device_id, revision_id); + ret = -ENODEV; + goto end; + } + break; + + case AR9887_DEVICE_ID: + *hif_type = HIF_TYPE_AR9888; + *target_type = TARGET_TYPE_AR9888; + HIF_INFO(" *********** AR9887 **************"); + break; + + case QCA9984_DEVICE_ID: + *hif_type = HIF_TYPE_QCA9984; + *target_type = TARGET_TYPE_QCA9984; + HIF_INFO(" *********** QCA9984 *************"); + break; + + case QCA9888_DEVICE_ID: + *hif_type = HIF_TYPE_QCA9888; + *target_type = TARGET_TYPE_QCA9888; + HIF_INFO(" *********** QCA9888 *************"); + break; + + case AR900B_DEVICE_ID: + *hif_type = HIF_TYPE_AR900B; + *target_type = TARGET_TYPE_AR900B; + HIF_INFO(" *********** AR900B *************"); + break; + + case IPQ4019_DEVICE_ID: + *hif_type = HIF_TYPE_IPQ4019; + *target_type = TARGET_TYPE_IPQ4019; + HIF_INFO(" *********** IPQ4019 *************"); + break; + + default: + HIF_ERROR("%s: Unsupported device ID!", __func__); + ret = -ENODEV; + break; + } +end: + return ret; +} + +/** + * hif_needs_bmi() - return true if the soc needs bmi through the driver + * @hif_ctx: hif context + * + * Return: true if the soc needs driver bmi otherwise false + */ +bool hif_needs_bmi(struct hif_opaque_softc *hif_ctx) +{ + struct hif_softc *hif_sc = HIF_GET_SOFTC(hif_ctx); + return hif_sc->bus_type != QDF_BUS_TYPE_SNOC; +} + +/** + * hif_get_bus_type() - return the bus type + * + * Return: enum qdf_bus_type + */ +enum qdf_bus_type hif_get_bus_type(struct hif_opaque_softc *hif_hdl) +{ + struct hif_softc *scn = HIF_GET_SOFTC(hif_hdl); + return scn->bus_type; +} + +/** + * Target info and ini parameters are global to the driver + * Hence these structures are exposed to all the modules in + * the driver and they don't need to maintains multiple copies + * of the same info, instead get the handle from hif and + * modify them in hif + */ + +/** + * hif_get_ini_handle() - API to get hif_config_param handle + * @hif_ctx: HIF Context + * + * Return: pointer to hif_config_info + */ +struct hif_config_info *hif_get_ini_handle(struct hif_opaque_softc *hif_ctx) +{ + struct hif_softc *sc = HIF_GET_SOFTC(hif_ctx); + + return &sc->hif_config; +} + +/** + * hif_get_target_info_handle() - API to get hif_target_info handle + * @hif_ctx: HIF context + * + * Return: Pointer to hif_target_info + */ +struct hif_target_info *hif_get_target_info_handle( + struct hif_opaque_softc *hif_ctx) +{ + struct hif_softc *sc = HIF_GET_SOFTC(hif_ctx); + + return &sc->target_info; + +} + +#if defined(FEATURE_LRO) +/** + * hif_lro_flush_cb_register - API to register for LRO Flush Callback + * @scn: HIF Context + * @handler: Function pointer to be called by HIF + * @data: Private data to be used by the module registering to HIF + * + * Return: void + */ +void hif_lro_flush_cb_register(struct hif_opaque_softc *scn, + void (lro_flush_handler)(void *), + void *(lro_init_handler)(void)) +{ + if (hif_napi_enabled(scn, -1)) + hif_napi_lro_flush_cb_register(scn, lro_flush_handler, + lro_init_handler); + else + ce_lro_flush_cb_register(scn, lro_flush_handler, + lro_init_handler); +} + +/** + * hif_get_lro_info - Returns LRO instance for instance ID + * @ctx_id: LRO instance ID + * @hif_hdl: HIF Context + * + * Return: Pointer to LRO instance. + */ +void *hif_get_lro_info(int ctx_id, struct hif_opaque_softc *hif_hdl) +{ + void *data; + + if (hif_napi_enabled(hif_hdl, -1)) + data = hif_napi_get_lro_info(hif_hdl, ctx_id); + else + data = hif_ce_get_lro_ctx(hif_hdl, ctx_id); + + return data; +} + +/** + * hif_get_rx_ctx_id - Returns LRO instance ID based on underlying LRO instance + * @ctx_id: LRO context ID + * @hif_hdl: HIF Context + * + * Return: LRO instance ID + */ +int hif_get_rx_ctx_id(int ctx_id, struct hif_opaque_softc *hif_hdl) +{ + if (hif_napi_enabled(hif_hdl, -1)) + return NAPI_PIPE2ID(ctx_id); + else + return ctx_id; +} + +/** + * hif_lro_flush_cb_deregister - API to deregister for LRO Flush Callbacks + * @hif_hdl: HIF Context + * @lro_deinit_cb: LRO deinit callback + * + * Return: void + */ +void hif_lro_flush_cb_deregister(struct hif_opaque_softc *hif_hdl, + void (lro_deinit_cb)(void *)) +{ + hif_napi_lro_flush_cb_deregister(hif_hdl, lro_deinit_cb); + ce_lro_flush_cb_deregister(hif_hdl, lro_deinit_cb); +} +#else /* !defined(FEATURE_LRO) */ +int hif_get_rx_ctx_id(int ctx_id, struct hif_opaque_softc *hif_hdl) +{ + return 0; +} +#endif + +/** + * hif_get_target_status - API to get target status + * @hif_ctx: HIF Context + * + * Return: enum hif_target_status + */ +enum hif_target_status hif_get_target_status(struct hif_opaque_softc *hif_ctx) +{ + struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx); + + return scn->target_status; +} + +/** + * hif_set_target_status() - API to set target status + * @hif_ctx: HIF Context + * @status: Target Status + * + * Return: void + */ +void hif_set_target_status(struct hif_opaque_softc *hif_ctx, enum + hif_target_status status) +{ + struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx); + + scn->target_status = status; +} + +/** + * hif_init_ini_config() - API to initialize HIF configuration parameters + * @hif_ctx: HIF Context + * @cfg: HIF Configuration + * + * Return: void + */ +void hif_init_ini_config(struct hif_opaque_softc *hif_ctx, + struct hif_config_info *cfg) +{ + struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx); + + qdf_mem_copy(&scn->hif_config, cfg, sizeof(struct hif_config_info)); +} + +/** + * hif_get_conparam() - API to get driver mode in HIF + * @scn: HIF Context + * + * Return: driver mode of operation + */ +uint32_t hif_get_conparam(struct hif_softc *scn) +{ + if (!scn) + return 0; + + return scn->hif_con_param; +} + +/** + * hif_get_callbacks_handle() - API to get callbacks Handle + * @scn: HIF Context + * + * Return: pointer to HIF Callbacks + */ +struct hif_driver_state_callbacks *hif_get_callbacks_handle(struct hif_softc *scn) +{ + return &scn->callbacks; +} + +/** + * hif_is_driver_unloading() - API to query upper layers if driver is unloading + * @scn: HIF Context + * + * Return: True/False + */ +bool hif_is_driver_unloading(struct hif_softc *scn) +{ + struct hif_driver_state_callbacks *cbk = hif_get_callbacks_handle(scn); + + if (cbk && cbk->is_driver_unloading) + return cbk->is_driver_unloading(cbk->context); + + return false; +} + +/** + * hif_is_load_or_unload_in_progress() - API to query upper layers if + * load/unload in progress + * @scn: HIF Context + * + * Return: True/False + */ +bool hif_is_load_or_unload_in_progress(struct hif_softc *scn) +{ + struct hif_driver_state_callbacks *cbk = hif_get_callbacks_handle(scn); + + if (cbk && cbk->is_load_unload_in_progress) + return cbk->is_load_unload_in_progress(cbk->context); + + return false; +} + +/** + * hif_is_recovery_in_progress() - API to query upper layers if recovery in + * progress + * @scn: HIF Context + * + * Return: True/False + */ +bool hif_is_recovery_in_progress(struct hif_softc *scn) +{ + struct hif_driver_state_callbacks *cbk = hif_get_callbacks_handle(scn); + + if (cbk && cbk->is_recovery_in_progress) + return cbk->is_recovery_in_progress(cbk->context); + + return false; +} +#if defined(HIF_PCI) || defined(SNOC) || defined(HIF_AHB) +/** + * hif_batch_send() - API to access hif specific function + * ce_batch_send. + * @osc: HIF Context + * @msdu : list of msdus to be sent + * @transfer_id : transfer id + * @len : donwloaded length + * + * Return: list of msds not sent + */ +qdf_nbuf_t hif_batch_send(struct hif_opaque_softc *osc, qdf_nbuf_t msdu, + uint32_t transfer_id, u_int32_t len, uint32_t sendhead) +{ + void *ce_tx_hdl = hif_get_ce_handle(osc, CE_HTT_TX_CE); + return ce_batch_send((struct CE_handle *)ce_tx_hdl, msdu, transfer_id, + len, sendhead); +} + +/** + * hif_update_tx_ring() - API to access hif specific function + * ce_update_tx_ring. + * @osc: HIF Context + * @num_htt_cmpls : number of htt compl received. + * + * Return: void + */ +void hif_update_tx_ring(struct hif_opaque_softc *osc, u_int32_t num_htt_cmpls) +{ + void *ce_tx_hdl = hif_get_ce_handle(osc, CE_HTT_TX_CE); + ce_update_tx_ring(ce_tx_hdl, num_htt_cmpls); +} + + +/** + * hif_send_single() - API to access hif specific function + * ce_send_single. + * @osc: HIF Context + * @msdu : msdu to be sent + * @transfer_id: transfer id + * @len : downloaded length + * + * Return: msdu sent status + */ +int hif_send_single(struct hif_opaque_softc *osc, qdf_nbuf_t msdu, uint32_t + transfer_id, u_int32_t len) +{ + void *ce_tx_hdl = hif_get_ce_handle(osc, CE_HTT_TX_CE); + return ce_send_single((struct CE_handle *)ce_tx_hdl, msdu, transfer_id, + len); +} + +/** + * hif_send_fast() - API to access hif specific function + * ce_send_fast. + * @osc: HIF Context + * @msdu : array of msdus to be sent + * @num_msdus : number of msdus in an array + * @transfer_id: transfer id + * @download_len: download length + * + * Return: No. of packets that could be sent + */ +int hif_send_fast(struct hif_opaque_softc *osc, qdf_nbuf_t nbuf, + uint32_t transfer_id, uint32_t download_len) +{ + void *ce_tx_hdl = hif_get_ce_handle(osc, CE_HTT_TX_CE); + return ce_send_fast((struct CE_handle *)ce_tx_hdl, nbuf, + transfer_id, download_len); +} +#endif + +/** + * hif_reg_write() - API to access hif specific function + * hif_write32_mb. + * @hif_ctx : HIF Context + * @offset : offset on which value has to be written + * @value : value to be written + * + * Return: None + */ +void hif_reg_write(struct hif_opaque_softc *hif_ctx, uint32_t offset, + uint32_t value) +{ + struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx); + hif_write32_mb(scn->mem + offset, value); + +} + +/** + * hif_reg_read() - API to access hif specific function + * hif_read32_mb. + * @hif_ctx : HIF Context + * @offset : offset from which value has to be read + * + * Return: Read value + */ +uint32_t hif_reg_read(struct hif_opaque_softc *hif_ctx, uint32_t offset) +{ + + struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx); + return hif_read32_mb(scn->mem + offset); +} + +#if defined(HIF_USB) +/** + * hif_ramdump_handler(): generic ramdump handler + * @scn: struct hif_opaque_softc + * + * Return: None + */ + +void hif_ramdump_handler(struct hif_opaque_softc *scn) + +{ + if (hif_get_bus_type == QDF_BUS_TYPE_USB) + hif_usb_ramdump_handler(); +} +#endif diff --git a/drivers/staging/qca-wifi-host-cmn/hif/src/hif_main.h b/drivers/staging/qca-wifi-host-cmn/hif/src/hif_main.h new file mode 100644 index 0000000000000000000000000000000000000000..aa5cdaad8e989d0df687fdef5e3e2cd47e68ee19 --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/hif/src/hif_main.h @@ -0,0 +1,236 @@ +/* + * Copyright (c) 2013-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * NB: Inappropriate references to "HTC" are used in this (and other) + * HIF implementations. HTC is typically the calling layer, but it + * theoretically could be some alternative. + */ + +/* + * This holds all state needed to process a pending send/recv interrupt. + * The information is saved here as soon as the interrupt occurs (thus + * allowing the underlying CE to re-use the ring descriptor). The + * information here is eventually processed by a completion processing + * thread. + */ + +#ifndef __HIF_MAIN_H__ +#define __HIF_MAIN_H__ + +#include /* qdf_atomic_read */ +#include "qdf_lock.h" +#include "cepci.h" +#include "hif.h" +#include "multibus.h" + +#define HIF_MIN_SLEEP_INACTIVITY_TIME_MS 50 +#define HIF_SLEEP_INACTIVITY_TIMER_PERIOD_MS 60 + +/* + * This macro implementation is exposed for efficiency only. + * The implementation may change and callers should + * consider the targid to be a completely opaque handle. + */ +#define TARGID_TO_PCI_ADDR(targid) (*((A_target_id_t *)(targid))) + +#ifdef QCA_WIFI_3_0 +#define DISABLE_L1SS_STATES 1 +#endif + +#define MAX_NUM_OF_RECEIVES HIF_NAPI_MAX_RECEIVES + +#ifdef QCA_WIFI_3_0_ADRASTEA +#define ADRASTEA_BU 1 +#else +#define ADRASTEA_BU 0 +#endif + +#ifdef QCA_WIFI_3_0 +#define HAS_FW_INDICATOR 0 +#else +#define HAS_FW_INDICATOR 1 +#endif + + +#define AR9888_DEVICE_ID (0x003c) +#define AR6320_DEVICE_ID (0x003e) +#define AR6320_FW_1_1 (0x11) +#define AR6320_FW_1_3 (0x13) +#define AR6320_FW_2_0 (0x20) +#define AR6320_FW_3_0 (0x30) +#define AR6320_FW_3_2 (0x32) +#define ADRASTEA_DEVICE_ID (0xabcd) +#define ADRASTEA_DEVICE_ID_P2_E12 (0x7021) +#define AR9887_DEVICE_ID (0x0050) +#define AR900B_DEVICE_ID (0x0040) +#define QCA9984_DEVICE_ID (0x0046) +#define QCA9888_DEVICE_ID (0x0056) +#define IPQ4019_DEVICE_ID (0x12ef) + +#define HIF_GET_PCI_SOFTC(scn) ((struct hif_pci_softc *)scn) +#define HIF_GET_CE_STATE(scn) ((struct HIF_CE_state *)scn) +#define HIF_GET_SDIO_SOFTC(scn) ((struct hif_sdio_softc *)scn) +#define HIF_GET_USB_SOFTC(scn) ((struct hif_usb_softc *)scn) +#define HIF_GET_USB_DEVICE(scn) ((HIF_DEVICE_USB *)scn) +#define HIF_GET_SOFTC(scn) ((struct hif_softc *)scn) +#define GET_HIF_OPAQUE_HDL(scn) ((struct hif_opaque_softc *)scn) + +struct hif_ce_stats { + int hif_pipe_no_resrc_count; + int ce_ring_delta_fail_count; +}; + +#ifdef WLAN_SUSPEND_RESUME_TEST +struct fake_apps_context { + unsigned long state; + hif_fake_resume_callback resume_callback; + struct work_struct resume_work; +}; + +enum hif_fake_apps_state_bits { + HIF_FA_SUSPENDED_BIT = 0 +}; + +void hif_fake_apps_resume_work(struct work_struct *work); +#endif /* WLAN_SUSPEND_RESUME_TEST */ + +struct hif_softc { + struct hif_opaque_softc osc; + struct hif_config_info hif_config; + struct hif_target_info target_info; + void __iomem *mem; + enum qdf_bus_type bus_type; + struct hif_bus_ops bus_ops; + void *ce_id_to_state[CE_COUNT_MAX]; + qdf_device_t qdf_dev; + bool hif_init_done; + bool request_irq_done; + /* Packet statistics */ + struct hif_ce_stats pkt_stats; + enum hif_target_status target_status; + + struct targetdef_s *targetdef; + struct ce_reg_def *target_ce_def; + struct hostdef_s *hostdef; + struct host_shadow_regs_s *host_shadow_regs; + + bool recovery; + bool notice_send; + uint32_t ce_irq_summary; + /* No of copy engines supported */ + unsigned int ce_count; + atomic_t active_tasklet_cnt; + atomic_t link_suspended; + uint32_t *vaddr_rri_on_ddr; + qdf_dma_addr_t paddr_rri_on_ddr; + int linkstate_vote; + bool fastpath_mode_on; + atomic_t tasklet_from_intr; + int htc_htt_tx_endpoint; + qdf_dma_addr_t mem_pa; + bool athdiag_procfs_inited; +#ifdef FEATURE_NAPI + struct qca_napi_data napi_data; +#endif /* FEATURE_NAPI */ + struct hif_driver_state_callbacks callbacks; + uint32_t hif_con_param; +#ifdef QCA_NSS_WIFI_OFFLOAD_SUPPORT + uint32_t nss_wifi_ol_mode; +#endif +#ifdef WLAN_SUSPEND_RESUME_TEST + struct fake_apps_context fake_apps_ctx; +#endif /* WLAN_SUSPEND_RESUME_TEST */ +}; + +#ifdef QCA_NSS_WIFI_OFFLOAD_SUPPORT +static inline bool hif_is_nss_wifi_enabled(struct hif_softc *sc) +{ + return !!(sc->nss_wifi_ol_mode); +} +#else +static inline bool hif_is_nss_wifi_enabled(struct hif_softc *sc) +{ + return false; +} +#endif + +A_target_id_t hif_get_target_id(struct hif_softc *scn); +void hif_dump_pipe_debug_count(struct hif_softc *scn); +void hif_display_bus_stats(struct hif_opaque_softc *scn); +void hif_clear_bus_stats(struct hif_opaque_softc *scn); +bool hif_max_num_receives_reached(struct hif_softc *scn, unsigned int count); +void hif_shutdown_device(struct hif_opaque_softc *hif_ctx); +int hif_bus_configure(struct hif_softc *scn); +void hif_cancel_deferred_target_sleep(struct hif_softc *scn); +int hif_config_ce(struct hif_softc *scn); +void hif_unconfig_ce(struct hif_softc *scn); +void hif_ce_prepare_config(struct hif_softc *scn); +QDF_STATUS hif_ce_open(struct hif_softc *scn); +void hif_ce_close(struct hif_softc *scn); +int athdiag_procfs_init(void *scn); +void athdiag_procfs_remove(void); +/* routine to modify the initial buffer count to be allocated on an os + * platform basis. Platform owner will need to modify this as needed + */ +qdf_size_t init_buffer_count(qdf_size_t maxSize); + +irqreturn_t hif_fw_interrupt_handler(int irq, void *arg); +int hif_get_device_type(uint32_t device_id, + uint32_t revision_id, + uint32_t *hif_type, uint32_t *target_type); +/*These functions are exposed to HDD*/ +void hif_nointrs(struct hif_softc *scn); +void hif_bus_close(struct hif_softc *ol_sc); +QDF_STATUS hif_bus_open(struct hif_softc *ol_sc, + enum qdf_bus_type bus_type); +QDF_STATUS hif_enable_bus(struct hif_softc *ol_sc, struct device *dev, + void *bdev, const hif_bus_id *bid, enum hif_enable_type type); +void hif_disable_bus(struct hif_softc *scn); +void hif_bus_prevent_linkdown(struct hif_softc *scn, bool flag); +int hif_bus_get_context_size(enum qdf_bus_type bus_type); +void hif_read_phy_mem_base(struct hif_softc *scn, qdf_dma_addr_t *bar_value); +uint32_t hif_get_conparam(struct hif_softc *scn); +struct hif_driver_state_callbacks *hif_get_callbacks_handle(struct hif_softc *scn); +bool hif_is_driver_unloading(struct hif_softc *scn); +bool hif_is_load_or_unload_in_progress(struct hif_softc *scn); +bool hif_is_recovery_in_progress(struct hif_softc *scn); +void hif_wlan_disable(struct hif_softc *scn); +int hif_target_sleep_state_adjust(struct hif_softc *scn, + bool sleep_ok, + bool wait_for_it); +int hif_get_rx_ctx_id(int ctx_id, struct hif_opaque_softc *hif_hdl); +#ifdef HIF_USB +void hif_usb_get_hw_info(struct hif_softc *scn); +void hif_ramdump_handler(struct hif_opaque_softc *scn); + +#else +static inline void hif_usb_get_hw_info(struct hif_softc *scn) {} +static inline void hif_ramdump_handler(struct hif_opaque_softc *scn) {} +#endif + +#endif /* __HIF_MAIN_H__ */ diff --git a/drivers/staging/qca-wifi-host-cmn/hif/src/hif_napi.c b/drivers/staging/qca-wifi-host-cmn/hif/src/hif_napi.c new file mode 100644 index 0000000000000000000000000000000000000000..6e56312735213b04174e6e68ab52ff86edf21faf --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/hif/src/hif_napi.c @@ -0,0 +1,1676 @@ +/* + * Copyright (c) 2015-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: hif_napi.c + * + * HIF NAPI interface implementation + */ + +#include /* memset */ + +/* Linux headers */ +#include +#include +#include +#include +#include +#include +#ifdef HELIUMPLUS +#include +#include +#include +#endif +#include + +/* Driver headers */ +#include +#include +#include +#include +#include + +enum napi_decision_vector { + HIF_NAPI_NOEVENT = 0, + HIF_NAPI_INITED = 1, + HIF_NAPI_CONF_UP = 2 +}; +#define ENABLE_NAPI_MASK (HIF_NAPI_INITED | HIF_NAPI_CONF_UP) + +#ifdef HELIUMPLUS +static inline int hif_get_irq_for_ce(int ce_id) +{ + return pld_snoc_get_irq(ce_id); +} +#else /* HELIUMPLUS */ +static inline int hif_get_irq_for_ce(int ce_id) +{ + return -EINVAL; +} +static int hif_napi_cpu_migrate(struct qca_napi_data *napid, int cpu, + int action) +{ + return 0; +} + +int hif_napi_cpu_blacklist(struct qca_napi_data *napid, + enum qca_blacklist_op op) +{ + return 0; +} +#endif /* HELIUMPLUS */ + +/** + * hif_napi_create() - creates the NAPI structures for a given CE + * @hif : pointer to hif context + * @pipe_id: the CE id on which the instance will be created + * @poll : poll function to be used for this NAPI instance + * @budget : budget to be registered with the NAPI instance + * @scale : scale factor on the weight (to scaler budget to 1000) + * @flags : feature flags + * + * Description: + * Creates NAPI instances. This function is called + * unconditionally during initialization. It creates + * napi structures through the proper HTC/HIF calls. + * The structures are disabled on creation. + * Note that for each NAPI instance a separate dummy netdev is used + * + * Return: + * < 0: error + * = 0: + * > 0: id of the created object (for multi-NAPI, number of objects created) + */ +int hif_napi_create(struct hif_opaque_softc *hif_ctx, + int (*poll)(struct napi_struct *, int), + int budget, + int scale, + uint8_t flags) +{ + int i; + struct qca_napi_data *napid; + struct qca_napi_info *napii; + struct CE_state *ce_state; + struct hif_softc *hif = HIF_GET_SOFTC(hif_ctx); + int rc = 0; + + NAPI_DEBUG("-->(budget=%d, scale=%d)", + budget, scale); + NAPI_DEBUG("hif->napi_data.state = 0x%08x", + hif->napi_data.state); + NAPI_DEBUG("hif->napi_data.ce_map = 0x%08x", + hif->napi_data.ce_map); + + napid = &(hif->napi_data); + if (0 == (napid->state & HIF_NAPI_INITED)) { + memset(napid, 0, sizeof(struct qca_napi_data)); + qdf_spinlock_create(&(napid->lock)); + + napid->state |= HIF_NAPI_INITED; + napid->flags = flags; + + rc = hif_napi_cpu_init(hif_ctx); + if (rc != 0) { + HIF_ERROR("NAPI_initialization failed,. %d", rc); + rc = napid->ce_map; + goto hnc_err; + } + + HIF_INFO("%s: NAPI structures initialized, rc=%d", + __func__, rc); + } + for (i = 0; i < hif->ce_count; i++) { + ce_state = hif->ce_id_to_state[i]; + NAPI_DEBUG("ce %d: htt_rx=%d htt_tx=%d", + i, ce_state->htt_rx_data, + ce_state->htt_tx_data); + if (!ce_state->htt_rx_data) + continue; + + /* Now this is a CE where we need NAPI on */ + NAPI_DEBUG("Creating NAPI on pipe %d", i); + napii = qdf_mem_malloc(sizeof(*napii)); + napid->napis[i] = napii; + if (!napii) { + NAPI_DEBUG("NAPI alloc failure %d", i); + rc = -ENOMEM; + goto napii_alloc_failure; + } + } + + for (i = 0; i < hif->ce_count; i++) { + napii = napid->napis[i]; + if (!napii) + continue; + + NAPI_DEBUG("initializing NAPI for pipe %d", i); + memset(napii, 0, sizeof(struct qca_napi_info)); + napii->scale = scale; + napii->id = NAPI_PIPE2ID(i); + napii->hif_ctx = hif_ctx; + napii->irq = hif_get_irq_for_ce(i); + + if (napii->irq < 0) + HIF_WARN("%s: bad IRQ value for CE %d: %d", + __func__, i, napii->irq); + + init_dummy_netdev(&(napii->netdev)); + + NAPI_DEBUG("adding napi=%p to netdev=%p (poll=%p, bdgt=%d)", + &(napii->napi), &(napii->netdev), poll, budget); + netif_napi_add(&(napii->netdev), &(napii->napi), poll, budget); + + NAPI_DEBUG("after napi_add"); + NAPI_DEBUG("napi=0x%p, netdev=0x%p", + &(napii->napi), &(napii->netdev)); + NAPI_DEBUG("napi.dev_list.prev=0x%p, next=0x%p", + napii->napi.dev_list.prev, + napii->napi.dev_list.next); + NAPI_DEBUG("dev.napi_list.prev=0x%p, next=0x%p", + napii->netdev.napi_list.prev, + napii->netdev.napi_list.next); + + /* It is OK to change the state variable below without + * protection as there should be no-one around yet + */ + napid->ce_map |= (0x01 << i); + HIF_INFO("%s: NAPI id %d created for pipe %d", __func__, + napii->id, i); + } + NAPI_DEBUG("napi map = %x", napid->ce_map); + NAPI_DEBUG("NAPI ids created for all applicable pipes"); + return napid->ce_map; + +napii_alloc_failure: + for (i = 0; i < hif->ce_count; i++) { + napii = napid->napis[i]; + napid->napis[i] = NULL; + if (napii) + qdf_mem_free(napii); + } + +hnc_err: + NAPI_DEBUG("<--napi_instances_map=%x]", napid->ce_map); + return rc; +} + +/** + * + * hif_napi_destroy() - destroys the NAPI structures for a given instance + * @hif : pointer to hif context + * @ce_id : the CE id whose napi instance will be destroyed + * @force : if set, will destroy even if entry is active (de-activates) + * + * Description: + * Destroy a given NAPI instance. This function is called + * unconditionally during cleanup. + * Refuses to destroy an entry of it is still enabled (unless force=1) + * Marks the whole napi_data invalid if all instances are destroyed. + * + * Return: + * -EINVAL: specific entry has not been created + * -EPERM : specific entry is still active + * 0 < : error + * 0 = : success + */ +int hif_napi_destroy(struct hif_opaque_softc *hif_ctx, + uint8_t id, + int force) +{ + uint8_t ce = NAPI_ID2PIPE(id); + int rc = 0; + struct hif_softc *hif = HIF_GET_SOFTC(hif_ctx); + + NAPI_DEBUG("-->(id=%d, force=%d)", id, force); + + if (0 == (hif->napi_data.state & HIF_NAPI_INITED)) { + HIF_ERROR("%s: NAPI not initialized or entry %d not created", + __func__, id); + rc = -EINVAL; + } else if (0 == (hif->napi_data.ce_map & (0x01 << ce))) { + HIF_ERROR("%s: NAPI instance %d (pipe %d) not created", + __func__, id, ce); + if (hif->napi_data.napis[ce]) + HIF_ERROR("%s: memory allocated but ce_map not set %d (pipe %d)", + __func__, id, ce); + rc = -EINVAL; + } else { + struct qca_napi_data *napid; + struct qca_napi_info *napii; + + napid = &(hif->napi_data); + napii = napid->napis[ce]; + if (!napii) { + if (napid->ce_map & (0x01 << ce)) + HIF_ERROR("%s: napii & ce_map out of sync(ce %d)", + __func__, ce); + return -EINVAL; + } + + + if (hif->napi_data.state == HIF_NAPI_CONF_UP) { + if (force) { + napi_disable(&(napii->napi)); + HIF_INFO("%s: NAPI entry %d force disabled", + __func__, id); + NAPI_DEBUG("NAPI %d force disabled", id); + } else { + HIF_ERROR("%s: Cannot destroy active NAPI %d", + __func__, id); + rc = -EPERM; + } + } + if (0 == rc) { + NAPI_DEBUG("before napi_del"); + NAPI_DEBUG("napi.dlist.prv=0x%p, next=0x%p", + napii->napi.dev_list.prev, + napii->napi.dev_list.next); + NAPI_DEBUG("dev.napi_l.prv=0x%p, next=0x%p", + napii->netdev.napi_list.prev, + napii->netdev.napi_list.next); + + netif_napi_del(&(napii->napi)); + + napid->ce_map &= ~(0x01 << ce); + napid->napis[ce] = NULL; + napii->scale = 0; + qdf_mem_free(napii); + HIF_DBG("%s: NAPI %d destroyed\n", __func__, id); + + /* if there are no active instances and + * if they are all destroyed, + * set the whole structure to uninitialized state + */ + if (napid->ce_map == 0) { + rc = hif_napi_cpu_deinit(hif_ctx); + /* caller is tolerant to receiving !=0 rc */ + + qdf_spinlock_destroy(&(napid->lock)); + memset(napid, + 0, sizeof(struct qca_napi_data)); + HIF_INFO("%s: no NAPI instances. Zapped.", + __func__); + } + } + } + + return rc; +} + +/** + * hif_napi_lro_flush_cb_register() - init and register flush callback for LRO + * @hif_hdl: pointer to hif context + * @lro_flush_handler: register LRO flush callback + * @lro_init_handler: Callback for initializing LRO + * + * Return: positive value on success and 0 on failure + */ +int hif_napi_lro_flush_cb_register(struct hif_opaque_softc *hif_hdl, + void (lro_flush_handler)(void *), + void *(lro_init_handler)(void)) +{ + int rc = 0; + int i; + struct hif_softc *scn = HIF_GET_SOFTC(hif_hdl); + void *data = NULL; + struct qca_napi_data *napid; + struct qca_napi_info *napii; + + QDF_ASSERT(scn != NULL); + + napid = hif_napi_get_all(hif_hdl); + if (scn != NULL) { + for (i = 0; i < scn->ce_count; i++) { + napii = napid->napis[i]; + if (napii) { + data = lro_init_handler(); + if (data == NULL) { + HIF_ERROR("%s: Failed to init LRO for CE %d", + __func__, i); + continue; + } + napii->lro_flush_cb = lro_flush_handler; + napii->lro_ctx = data; + HIF_ERROR("Registering LRO for ce_id %d NAPI callback for %d flush_cb %p, lro_data %p\n", + i, napii->id, napii->lro_flush_cb, + napii->lro_ctx); + rc++; + } + } + } else { + HIF_ERROR("%s: hif_state NULL!", __func__); + } + return rc; +} + +/** + * hif_napi_lro_flush_cb_deregister() - Degregister and free LRO. + * @hif: pointer to hif context + * @lro_deinit_cb: LRO deinit callback + * + * Return: NONE + */ +void hif_napi_lro_flush_cb_deregister(struct hif_opaque_softc *hif_hdl, + void (lro_deinit_cb)(void *)) +{ + int i; + struct hif_softc *scn = HIF_GET_SOFTC(hif_hdl); + struct qca_napi_data *napid; + struct qca_napi_info *napii; + + QDF_ASSERT(scn != NULL); + + napid = hif_napi_get_all(hif_hdl); + if (scn != NULL) { + for (i = 0; i < scn->ce_count; i++) { + napii = napid->napis[i]; + if (napii) { + HIF_DBG("deRegistering LRO for ce_id %d NAPI callback for %d flush_cb %p, lro_data %p\n", + i, napii->id, napii->lro_flush_cb, + napii->lro_ctx); + napii->lro_flush_cb = NULL; + lro_deinit_cb(napii->lro_ctx); + napii->lro_ctx = NULL; + } + } + } else { + HIF_ERROR("%s: hif_state NULL!", __func__); + } +} + +/** + * hif_napi_get_lro_info() - returns the address LRO data for napi_id + * @hif: pointer to hif context + * @napi_id: napi instance + * + * Description: + * Returns the address of the LRO structure + * + * Return: + * : address of the LRO structure + */ +void *hif_napi_get_lro_info(struct hif_opaque_softc *hif_hdl, int napi_id) +{ + struct hif_softc *scn = HIF_GET_SOFTC(hif_hdl); + struct qca_napi_data *napid; + struct qca_napi_info *napii; + + napid = &(scn->napi_data); + napii = napid->napis[NAPI_ID2PIPE(napi_id)]; + + if (napii) + return napii->lro_ctx; + return 0; +} + +/** + * + * hif_napi_get_all() - returns the address of the whole HIF NAPI structure + * @hif: pointer to hif context + * + * Description: + * Returns the address of the whole structure + * + * Return: + * : address of the whole HIF NAPI structure + */ +inline struct qca_napi_data *hif_napi_get_all(struct hif_opaque_softc *hif_ctx) +{ + struct hif_softc *hif = HIF_GET_SOFTC(hif_ctx); + + return &(hif->napi_data); +} + +/** + * + * hif_napi_event() - reacts to events that impact NAPI + * @hif : pointer to hif context + * @evnt: event that has been detected + * @data: more data regarding the event + * + * Description: + * This function handles two types of events: + * 1- Events that change the state of NAPI (enabled/disabled): + * {NAPI_EVT_INI_FILE, NAPI_EVT_CMD_STATE} + * The state is retrievable by "hdd_napi_enabled(-1)" + * - NAPI will be on if either INI file is on and it has not been disabled + * by a subsequent vendor CMD, + * or it has been enabled by a vendor CMD. + * 2- Events that change the CPU affinity of a NAPI instance/IRQ: + * {NAPI_EVT_TPUT_STATE, NAPI_EVT_CPU_STATE} + * - NAPI will support a throughput mode (HI/LO), kept at napid->napi_mode + * - NAPI will switch throughput mode based on hdd_napi_throughput_policy() + * - In LO tput mode, NAPI will yield control if its interrupts to the system + * management functions. However in HI throughput mode, NAPI will actively + * manage its interrupts/instances (by trying to disperse them out to + * separate performance cores). + * - CPU eligibility is kept up-to-date by NAPI_EVT_CPU_STATE events. + * + * + In some cases (roaming peer management is the only case so far), a + * a client can trigger a "SERIALIZE" event. Basically, this means that the + * users is asking NAPI to go into a truly single execution context state. + * So, NAPI indicates to msm-irqbalancer that it wants to be blacklisted, + * (if called for the first time) and then moves all IRQs (for NAPI + * instances) to be collapsed to a single core. If called multiple times, + * it will just re-collapse the CPUs. This is because blacklist-on() API + * is reference-counted, and because the API has already been called. + * + * Such a user, should call "DESERIALIZE" (NORMAL) event, to set NAPI to go + * to its "normal" operation. Optionally, they can give a timeout value (in + * multiples of BusBandwidthCheckPeriod -- 100 msecs by default). In this + * case, NAPI will just set the current throughput state to uninitialized + * and set the delay period. Once policy handler is called, it would skip + * applying the policy delay period times, and otherwise apply the policy. + * + * Return: + * < 0: some error + * = 0: event handled successfully + */ +int hif_napi_event(struct hif_opaque_softc *hif_ctx, enum qca_napi_event event, + void *data) +{ + int rc = 0; + uint32_t prev_state; + int i; + struct napi_struct *napi; + struct hif_softc *hif = HIF_GET_SOFTC(hif_ctx); + struct qca_napi_data *napid = &(hif->napi_data); + enum qca_napi_tput_state tput_mode = QCA_NAPI_TPUT_UNINITIALIZED; + enum { + BLACKLIST_NOT_PENDING, + BLACKLIST_ON_PENDING, + BLACKLIST_OFF_PENDING + } blacklist_pending = BLACKLIST_NOT_PENDING; + + NAPI_DEBUG("%s: -->(event=%d, aux=%p)", __func__, event, data); + + if ((napid->state & HIF_NAPI_INITED) == 0) { + NAPI_DEBUG("%s: got event when NAPI not initialized", + __func__); + return -EINVAL; + } + qdf_spin_lock_bh(&(napid->lock)); + prev_state = napid->state; + switch (event) { + case NAPI_EVT_INI_FILE: + case NAPI_EVT_CMD_STATE: + case NAPI_EVT_INT_STATE: { + int on = (data != ((void *)0)); + + HIF_INFO("%s: recved evnt: STATE_CMD %d; v = %d (state=0x%0x)", + __func__, event, + on, prev_state); + if (on) + if (prev_state & HIF_NAPI_CONF_UP) { + HIF_INFO("%s: duplicate NAPI conf ON msg", + __func__); + } else { + HIF_INFO("%s: setting state to ON", + __func__); + napid->state |= HIF_NAPI_CONF_UP; + } + else /* off request */ + if (prev_state & HIF_NAPI_CONF_UP) { + HIF_INFO("%s: setting state to OFF", + __func__); + napid->state &= ~HIF_NAPI_CONF_UP; + } else { + HIF_INFO("%s: duplicate NAPI conf OFF msg", + __func__); + } + break; + } + /* case NAPI_INIT_FILE/CMD_STATE */ + + case NAPI_EVT_CPU_STATE: { + int cpu = ((unsigned long int)data >> 16); + int val = ((unsigned long int)data & 0x0ff); + + NAPI_DEBUG("%s: evt=CPU_STATE on CPU %d value=%d", + __func__, cpu, val); + + /* state has already been set by hnc_cpu_notify_cb */ + if ((val == QCA_NAPI_CPU_DOWN) && + (napid->napi_mode == QCA_NAPI_TPUT_HI) && /* we manage */ + (napid->napi_cpu[cpu].napis != 0)) { + NAPI_DEBUG("%s: Migrating NAPIs out of cpu %d", + __func__, cpu); + rc = hif_napi_cpu_migrate(napid, + cpu, + HNC_ACT_RELOCATE); + napid->napi_cpu[cpu].napis = 0; + } + /* in QCA_NAPI_TPUT_LO case, napis MUST == 0 */ + break; + } + + case NAPI_EVT_TPUT_STATE: { + tput_mode = (enum qca_napi_tput_state)data; + if (tput_mode == QCA_NAPI_TPUT_LO) { + /* from TPUT_HI -> TPUT_LO */ + NAPI_DEBUG("%s: Moving to napi_tput_LO state", + __func__); + blacklist_pending = BLACKLIST_OFF_PENDING; + /* + .*.Ideally we should "collapse" interrupts here, since + * we are "dispersing" interrupts in the "else" case. + * This allows the possibility that our interrupts may + * still be on the perf cluster the next time we enter + * high tput mode. However, the irq_balancer is free + * to move our interrupts to power cluster once + * blacklisting has been turned off in the "else" case. + */ + } else { + /* from TPUT_LO -> TPUT->HI */ + NAPI_DEBUG("%s: Moving to napi_tput_HI state", + __func__); + rc = hif_napi_cpu_migrate(napid, + HNC_ANY_CPU, + HNC_ACT_DISPERSE); + + blacklist_pending = BLACKLIST_ON_PENDING; + } + napid->napi_mode = tput_mode; + break; + } + + case NAPI_EVT_USR_SERIAL: { + unsigned long users = (unsigned long)data; + + NAPI_DEBUG("%s: User forced SERIALIZATION; users=%ld", + __func__, users); + + rc = hif_napi_cpu_migrate(napid, + HNC_ANY_CPU, + HNC_ACT_COLLAPSE); + if ((users == 0) && (rc == 0)) + blacklist_pending = BLACKLIST_ON_PENDING; + break; + } + case NAPI_EVT_USR_NORMAL: { + NAPI_DEBUG("%s: User forced DE-SERIALIZATION", __func__); + /* + * Deserialization timeout is handled at hdd layer; + * just mark current mode to uninitialized to ensure + * it will be set when the delay is over + */ + napid->napi_mode = QCA_NAPI_TPUT_UNINITIALIZED; + break; + } + default: { + HIF_ERROR("%s: unknown event: %d (data=0x%0lx)", + __func__, event, (unsigned long) data); + break; + } /* default */ + }; /* switch */ + + + switch (blacklist_pending) { + case BLACKLIST_ON_PENDING: + /* assume the control of WLAN IRQs */ + hif_napi_cpu_blacklist(napid, BLACKLIST_ON); + break; + case BLACKLIST_OFF_PENDING: + /* yield the control of WLAN IRQs */ + hif_napi_cpu_blacklist(napid, BLACKLIST_OFF); + break; + default: /* nothing to do */ + break; + } /* switch blacklist_pending */ + + qdf_spin_unlock_bh(&(napid->lock)); + + if (prev_state != napid->state) { + if (napid->state == ENABLE_NAPI_MASK) { + rc = 1; + for (i = 0; i < CE_COUNT_MAX; i++) { + struct qca_napi_info *napii = napid->napis[i]; + if (napii) { + napi = &(napii->napi); + NAPI_DEBUG("%s: enabling NAPI %d", + __func__, i); + napi_enable(napi); + } + } + } else { + rc = 0; + for (i = 0; i < CE_COUNT_MAX; i++) { + struct qca_napi_info *napii = napid->napis[i]; + if (napii) { + napi = &(napii->napi); + NAPI_DEBUG("%s: disabling NAPI %d", + __func__, i); + napi_disable(napi); + /* in case it is affined, remove it */ + irq_set_affinity_hint(napii->irq, NULL); + } + } + } + } else { + HIF_INFO("%s: no change in hif napi state (still %d)", + __func__, prev_state); + } + + NAPI_DEBUG("<--[rc=%d]", rc); + return rc; +} + +/** + * hif_napi_enabled() - checks whether NAPI is enabled for given ce or not + * @hif: hif context + * @ce : CE instance (or -1, to check if any CEs are enabled) + * + * Return: bool + */ +int hif_napi_enabled(struct hif_opaque_softc *hif_ctx, int ce) +{ + int rc; + struct hif_softc *hif = HIF_GET_SOFTC(hif_ctx); + + if (-1 == ce) + rc = ((hif->napi_data.state == ENABLE_NAPI_MASK)); + else + rc = ((hif->napi_data.state == ENABLE_NAPI_MASK) && + (hif->napi_data.ce_map & (0x01 << ce))); + return rc; +}; + +/** + * hif_napi_enable_irq() - enables bus interrupts after napi_complete + * + * @hif: hif context + * @id : id of NAPI instance calling this (used to determine the CE) + * + * Return: void + */ +inline void hif_napi_enable_irq(struct hif_opaque_softc *hif, int id) +{ + struct hif_softc *scn = HIF_GET_SOFTC(hif); + + hif_irq_enable(scn, NAPI_ID2PIPE(id)); +} + + +/** + * hif_napi_schedule() - schedules napi, updates stats + * @scn: hif context + * @ce_id: index of napi instance + * + * Return: void + */ +int hif_napi_schedule(struct hif_opaque_softc *hif_ctx, int ce_id) +{ + int cpu = smp_processor_id(); + struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx); + struct qca_napi_info *napii; + + hif_record_ce_desc_event(scn, ce_id, NAPI_SCHEDULE, + NULL, NULL, 0); + + napii = scn->napi_data.napis[ce_id]; + if (qdf_unlikely(!napii)) { + HIF_ERROR("%s, scheduling unallocated napi (ce:%d)", + __func__, ce_id); + qdf_atomic_dec(&scn->active_tasklet_cnt); + return false; + } + + napii->stats[cpu].napi_schedules++; + NAPI_DEBUG("scheduling napi %d (ce:%d)", napii->id, ce_id); + napi_schedule(&(napii->napi)); + + return true; +} + +/** + * hif_napi_correct_cpu() - correct the interrupt affinity for napi if needed + * @napi_info: pointer to qca_napi_info for the napi instance + * + * Return: true => interrupt already on correct cpu, no correction needed + * false => interrupt on wrong cpu, correction done for cpu affinity + * of the interrupt + */ +static inline +bool hif_napi_correct_cpu(struct qca_napi_info *napi_info) +{ + bool right_cpu = true; + int rc = 0; + cpumask_t cpumask; + int cpu ; + struct qca_napi_data *napid; + + napid = hif_napi_get_all(GET_HIF_OPAQUE_HDL(napi_info->hif_ctx)); + + if (napid->flags & QCA_NAPI_FEATURE_CPU_CORRECTION) { + + cpu = qdf_get_cpu(); + if (unlikely((hif_napi_cpu_blacklist(napid, + BLACKLIST_QUERY) > 0) && + (cpu != napi_info->cpu))) { + right_cpu = false; + + NAPI_DEBUG("interrupt on wrong CPU, correcting"); + cpumask.bits[0] = (0x01 << napi_info->cpu); + + irq_modify_status(napi_info->irq, IRQ_NO_BALANCING, 0); + rc = irq_set_affinity_hint(napi_info->irq, + &cpumask); + irq_modify_status(napi_info->irq, 0, IRQ_NO_BALANCING); + + if (rc) + HIF_ERROR("error setting irq affinity hint: %d", rc); + else + napi_info->stats[cpu].cpu_corrected++; + } + } + return right_cpu; +} + +/** + * hif_napi_poll() - NAPI poll routine + * @napi : pointer to NAPI struct as kernel holds it + * @budget: + * + * This is the body of the poll function. + * The poll function is called by kernel. So, there is a wrapper + * function in HDD, which in turn calls this function. + * Two main reasons why the whole thing is not implemented in HDD: + * a) references to things like ce_service that HDD is not aware of + * b) proximity to the implementation of ce_tasklet, which the body + * of this function should be very close to. + * + * NOTE TO THE MAINTAINER: + * Consider this function and ce_tasklet very tightly coupled pairs. + * Any changes to ce_tasklet or this function may likely need to be + * reflected in the counterpart. + * + * Returns: + * int: the amount of work done in this poll (<= budget) + */ +int hif_napi_poll(struct hif_opaque_softc *hif_ctx, + struct napi_struct *napi, + int budget) +{ + int rc = 0; /* default: no work done, also takes care of error */ + int normalized = 0; + int bucket; + int cpu = smp_processor_id(); + bool poll_on_right_cpu; + struct hif_softc *hif = HIF_GET_SOFTC(hif_ctx); + struct qca_napi_info *napi_info; + struct CE_state *ce_state = NULL; + + if (unlikely(NULL == hif)) { + HIF_ERROR("%s: hif context is NULL", __func__); + QDF_ASSERT(0); + goto out; + } + + napi_info = (struct qca_napi_info *) + container_of(napi, struct qca_napi_info, napi); + + NAPI_DEBUG("%s -->(napi(%d, irq=%d), budget=%d)", + __func__, napi_info->id, napi_info->irq, budget); + + napi_info->stats[cpu].napi_polls++; + + hif_record_ce_desc_event(hif, NAPI_ID2PIPE(napi_info->id), + NAPI_POLL_ENTER, NULL, NULL, cpu); + + rc = ce_per_engine_service(hif, NAPI_ID2PIPE(napi_info->id)); + NAPI_DEBUG("%s: ce_per_engine_service processed %d msgs", + __func__, rc); + + if (napi_info->lro_flush_cb) + napi_info->lro_flush_cb(napi_info->lro_ctx); + + /* do not return 0, if there was some work done, + * even if it is below the scale + */ + if (rc) { + napi_info->stats[cpu].napi_workdone += rc; + normalized = (rc / napi_info->scale); + if (normalized == 0) + normalized++; + bucket = normalized / (QCA_NAPI_BUDGET / QCA_NAPI_NUM_BUCKETS); + if (bucket >= QCA_NAPI_NUM_BUCKETS) { + bucket = QCA_NAPI_NUM_BUCKETS - 1; + HIF_ERROR("Bad bucket#(%d) > QCA_NAPI_NUM_BUCKETS(%d)", + bucket, QCA_NAPI_NUM_BUCKETS); + } + napi_info->stats[cpu].napi_budget_uses[bucket]++; + } else { + /* if ce_per engine reports 0, then poll should be terminated */ + NAPI_DEBUG("%s:%d: nothing processed by CE. Completing NAPI", + __func__, __LINE__); + } + + ce_state = hif->ce_id_to_state[NAPI_ID2PIPE(napi_info->id)]; + /* + * Not using the API hif_napi_correct_cpu directly in the if statement + * below since the API may not get evaluated if put at the end if any + * prior condition would evaluate to be true. The CPU correction + * check should kick in every poll. + */ + poll_on_right_cpu = hif_napi_correct_cpu(napi_info); + + if ((ce_state) && + (!ce_check_rx_pending(ce_state) || (0 == rc) || + !poll_on_right_cpu)) { + napi_info->stats[cpu].napi_completes++; + + hif_record_ce_desc_event(hif, ce_state->id, NAPI_COMPLETE, + NULL, NULL, 0); + if (normalized >= budget) + normalized = budget - 1; + + /* enable interrupts */ + napi_complete(napi); + hif_napi_enable_irq(hif_ctx, napi_info->id); + /* support suspend/resume */ + qdf_atomic_dec(&(hif->active_tasklet_cnt)); + + NAPI_DEBUG("%s:%d: napi_complete + enabling the interrupts", + __func__, __LINE__); + } else { + /* 4.4 kernel NAPI implementation requires drivers to + * return full work when they ask to be re-scheduled, + * or napi_complete and re-start with a fresh interrupt + */ + normalized = budget; + } + + hif_record_ce_desc_event(hif, NAPI_ID2PIPE(napi_info->id), + NAPI_POLL_EXIT, NULL, NULL, normalized); + + NAPI_DEBUG("%s <--[normalized=%d]", __func__, normalized); + return normalized; +out: + return rc; +} + +#ifdef HELIUMPLUS +/** + * + * hif_napi_update_yield_stats() - update NAPI yield related stats + * @cpu_id: CPU ID for which stats needs to be updates + * @ce_id: Copy Engine ID for which yield stats needs to be updates + * @time_limit_reached: indicates whether the time limit was reached + * @rxpkt_thresh_reached: indicates whether rx packet threshold was reached + * + * Return: None + */ +void hif_napi_update_yield_stats(struct CE_state *ce_state, + bool time_limit_reached, + bool rxpkt_thresh_reached) +{ + struct hif_softc *hif; + struct qca_napi_data *napi_data = NULL; + int ce_id = 0; + int cpu_id = 0; + + if (unlikely(NULL == ce_state)) { + QDF_ASSERT(NULL != ce_state); + return; + } + + hif = ce_state->scn; + + if (unlikely(NULL == hif)) { + QDF_ASSERT(NULL != hif); + return; + } else { + napi_data = &(hif->napi_data); + if (unlikely(NULL == napi_data)) { + QDF_ASSERT(NULL != napi_data); + return; + } + } + + if (unlikely(NULL == napi_data->napis[ce_id])) + return; + + ce_id = ce_state->id; + cpu_id = qdf_get_cpu(); + + if (time_limit_reached) + napi_data->napis[ce_id]->stats[cpu_id].time_limit_reached++; + else + napi_data->napis[ce_id]->stats[cpu_id].rxpkt_thresh_reached++; +} + +/** + * + * hif_napi_stats() - display NAPI CPU statistics + * @napid: pointer to qca_napi_data + * + * Description: + * Prints the various CPU cores on which the NAPI instances /CEs interrupts + * are being executed. Can be called from outside NAPI layer. + * + * Return: None + */ +void hif_napi_stats(struct qca_napi_data *napid) +{ + int i; + struct qca_napi_cpu *cpu; + + if (napid == NULL) { + qdf_print("%s: napiid struct is null", __func__); + return; + } + + cpu = napid->napi_cpu; + qdf_print("NAPI CPU TABLE"); + qdf_print("lilclhead=%d, bigclhead=%d", + napid->lilcl_head, napid->bigcl_head); + for (i = 0; i < NR_CPUS; i++) { + qdf_print("CPU[%02d]: state:%d crid=%02d clid=%02d " + "crmk:0x%0lx thmk:0x%0lx frq:%d " + "napi = 0x%08x lnk:%d", + i, + cpu[i].state, cpu[i].core_id, cpu[i].cluster_id, + cpu[i].core_mask.bits[0], + cpu[i].thread_mask.bits[0], + cpu[i].max_freq, cpu[i].napis, + cpu[i].cluster_nxt); + } +} + +#ifdef FEATURE_NAPI_DEBUG +/* + * Local functions + * - no argument checks, all internal/trusted callers + */ +static void hnc_dump_cpus(struct qca_napi_data *napid) +{ + hif_napi_stats(napid); +} +#else +static void hnc_dump_cpus(struct qca_napi_data *napid) { /* no-op */ }; +#endif /* FEATURE_NAPI_DEBUG */ +/** + * hnc_link_clusters() - partitions to cpu table into clusters + * @napid: pointer to NAPI data + * + * Takes in a CPU topology table and builds two linked lists + * (big cluster cores, list-head at bigcl_head, and little cluster + * cores, list-head at lilcl_head) out of it. + * + * If there are more than two clusters: + * - bigcl_head and lilcl_head will be different, + * - the cluster with highest cpufreq will be considered the "big" cluster. + * If there are more than one with the highest frequency, the *last* of such + * clusters will be designated as the "big cluster" + * - the cluster with lowest cpufreq will be considered the "li'l" cluster. + * If there are more than one clusters with the lowest cpu freq, the *first* + * of such clusters will be designated as the "little cluster" + * - We only support up to 32 clusters + * Return: 0 : OK + * !0: error (at least one of lil/big clusters could not be found) + */ +#define HNC_MIN_CLUSTER 0 +#define HNC_MAX_CLUSTER 31 +static int hnc_link_clusters(struct qca_napi_data *napid) +{ + int rc = 0; + + int i; + int it = 0; + uint32_t cl_done = 0x0; + int cl, curcl, curclhead = 0; + int more; + unsigned int lilfrq = INT_MAX; + unsigned int bigfrq = 0; + unsigned int clfrq = 0; + int prev = 0; + struct qca_napi_cpu *cpus = napid->napi_cpu; + + napid->lilcl_head = napid->bigcl_head = -1; + + do { + more = 0; + it++; curcl = -1; + for (i = 0; i < NR_CPUS; i++) { + cl = cpus[i].cluster_id; + NAPI_DEBUG("Processing cpu[%d], cluster=%d\n", + i, cl); + if ((cl < HNC_MIN_CLUSTER) || (cl > HNC_MAX_CLUSTER)) { + NAPI_DEBUG("Bad cluster (%d). SKIPPED\n", cl); + QDF_ASSERT(0); + /* continue if ASSERTs are disabled */ + continue; + }; + if (cpumask_weight(&(cpus[i].core_mask)) == 0) { + NAPI_DEBUG("Core mask 0. SKIPPED\n"); + continue; + } + if (cl_done & (0x01 << cl)) { + NAPI_DEBUG("Cluster already processed. " + "SKIPPED\n"); + continue; + } else { + if (more == 0) { + more = 1; + curcl = cl; + curclhead = i; /* row */ + clfrq = cpus[i].max_freq; + prev = -1; + }; + if ((curcl >= 0) && (curcl != cl)) { + NAPI_DEBUG("Entry cl(%d) != curcl(%d). " + "SKIPPED\n", + cl, curcl); + continue; + } + if (cpus[i].max_freq != clfrq) + NAPI_DEBUG("WARN: frq(%d)!=clfrq(%d)\n", + cpus[i].max_freq, clfrq); + if (clfrq >= bigfrq) { + bigfrq = clfrq; + napid->bigcl_head = curclhead; + NAPI_DEBUG("bigcl=%d\n", curclhead); + } + if (clfrq < lilfrq) { + lilfrq = clfrq; + napid->lilcl_head = curclhead; + NAPI_DEBUG("lilcl=%d\n", curclhead); + } + if (prev != -1) + cpus[prev].cluster_nxt = i; + + prev = i; + } + } + if (curcl >= 0) + cl_done |= (0x01 << curcl); + + } while (more); + + if (qdf_unlikely((napid->lilcl_head < 0) && (napid->bigcl_head < 0))) + rc = -EFAULT; + + hnc_dump_cpus(napid); /* if NAPI_DEBUG */ + return rc; +} +#undef HNC_MIN_CLUSTER +#undef HNC_MAX_CLUSTER + +/* + * hotplug function group + */ + +/** + * hnc_cpu_notify_cb() - handles CPU hotplug events + * + * On transitions to online, we onlu handle the ONLINE event, + * and ignore the PREP events, because we dont want to act too + * early. + * On transtion to offline, we act on PREP events, because + * we may need to move the irqs/NAPIs to another CPU before + * it is actually off-lined. + * + * Return: NOTIFY_OK (dont block action) + */ +static int hnc_cpu_notify_cb(struct notifier_block *nb, + unsigned long action, + void *hcpu) +{ + int rc = NOTIFY_OK; + unsigned long cpu = (unsigned long)hcpu; + struct hif_opaque_softc *hif; + struct qca_napi_data *napid = NULL; + + NAPI_DEBUG("-->%s(act=%ld, cpu=%ld)", __func__, action, cpu); + + napid = qdf_container_of(nb, struct qca_napi_data, hnc_cpu_notifier); + hif = &qdf_container_of(napid, struct hif_softc, napi_data)->osc; + + switch (action) { + case CPU_ONLINE: + napid->napi_cpu[cpu].state = QCA_NAPI_CPU_UP; + NAPI_DEBUG("%s: CPU %ld marked %d", + __func__, cpu, napid->napi_cpu[cpu].state); + break; + case CPU_DEAD: /* already dead; we have marked it before, but ... */ + case CPU_DEAD_FROZEN: + napid->napi_cpu[cpu].state = QCA_NAPI_CPU_DOWN; + NAPI_DEBUG("%s: CPU %ld marked %d", + __func__, cpu, napid->napi_cpu[cpu].state); + break; + case CPU_DOWN_PREPARE: + case CPU_DOWN_PREPARE_FROZEN: + napid->napi_cpu[cpu].state = QCA_NAPI_CPU_DOWN; + + NAPI_DEBUG("%s: CPU %ld marked %d; updating affinity", + __func__, cpu, napid->napi_cpu[cpu].state); + + /** + * we need to move any NAPIs on this CPU out. + * if we are in LO throughput mode, then this is valid + * if the CPU is the the low designated CPU. + */ + hif_napi_event(hif, + NAPI_EVT_CPU_STATE, + (void *) + ((cpu << 16) | napid->napi_cpu[cpu].state)); + break; + default: + NAPI_DEBUG("%s: ignored. action: %ld", __func__, action); + break; + } /* switch */ + NAPI_DEBUG("<--%s [%d]", __func__, rc); + return rc; +} + +/** + * hnc_hotplug_hook() - installs a hotplug notifier + * @hif_sc: hif_sc context + * @register: !0 => register , =0 => deregister + * + * Because the callback relies on the data layout of + * struct hif_softc & its napi_data member, this callback + * registration requires that the hif_softc is passed in. + * + * Note that this is different from the cpu notifier used by + * rx_thread (cds_schedule.c). + * We may consider combining these modifiers in the future. + * + * Return: 0: success + * <0: error + */ +static int hnc_hotplug_hook(struct hif_softc *hif_sc, int install) +{ + int rc = 0; + + NAPI_DEBUG("-->%s(%d)", __func__, install); + + if (install) { + hif_sc->napi_data.hnc_cpu_notifier.notifier_call + = hnc_cpu_notify_cb; + rc = register_hotcpu_notifier( + &hif_sc->napi_data.hnc_cpu_notifier); + } else { + unregister_hotcpu_notifier( + &hif_sc->napi_data.hnc_cpu_notifier); + } + + NAPI_DEBUG("<--%s()[%d]", __func__, rc); + return rc; +} + +/** + * hnc_install_tput() - installs a callback in the throughput detector + * @register: !0 => register; =0: unregister + * + * installs a callback to be called when wifi driver throughput (tx+rx) + * crosses a threshold. Currently, we are using the same criteria as + * TCP ack suppression (500 packets/100ms by default). + * + * Return: 0 : success + * <0: failure + */ + +static int hnc_tput_hook(int install) +{ + int rc = 0; + + /* + * Nothing, until the bw_calculation accepts registration + * it is now hardcoded in the wlan_hdd_main.c::hdd_bus_bw_compute_cbk + * hdd_napi_throughput_policy(...) + */ + return rc; +} + +/* + * Implementation of hif_napi_cpu API + */ + +/** + * hif_napi_cpu_init() - initialization of irq affinity block + * @ctx: pointer to qca_napi_data + * + * called by hif_napi_create, after the first instance is called + * - builds napi_rss_cpus table from cpu topology + * - links cores of the same clusters together + * - installs hot-plug notifier + * - installs throughput trigger notifier (when such mechanism exists) + * + * Return: 0: OK + * <0: error code + */ +int hif_napi_cpu_init(struct hif_opaque_softc *hif) +{ + int rc = 0; + int i; + struct qca_napi_data *napid = &HIF_GET_SOFTC(hif)->napi_data; + struct qca_napi_cpu *cpus = napid->napi_cpu; + + NAPI_DEBUG("--> "); + + if (cpus[0].state != QCA_NAPI_CPU_UNINITIALIZED) { + NAPI_DEBUG("NAPI RSS table already initialized.\n"); + rc = -EALREADY; + goto lab_rss_init; + } + + /* build CPU topology table */ + for_each_possible_cpu(i) { + cpus[i].state = ((cpumask_test_cpu(i, cpu_online_mask) + ? QCA_NAPI_CPU_UP + : QCA_NAPI_CPU_DOWN)); + cpus[i].core_id = topology_core_id(i); + cpus[i].cluster_id = topology_physical_package_id(i); + cpumask_copy(&(cpus[i].core_mask), + topology_core_cpumask(i)); + cpumask_copy(&(cpus[i].thread_mask), + topology_sibling_cpumask(i)); + cpus[i].max_freq = cpufreq_quick_get_max(i); + cpus[i].napis = 0x0; + cpus[i].cluster_nxt = -1; /* invalid */ + } + + /* link clusters together */ + rc = hnc_link_clusters(napid); + if (0 != rc) + goto lab_err_topology; + + /* install hotplug notifier */ + rc = hnc_hotplug_hook(HIF_GET_SOFTC(hif), 1); + if (0 != rc) + goto lab_err_hotplug; + + /* install throughput notifier */ + rc = hnc_tput_hook(1); + if (0 == rc) + goto lab_rss_init; + +lab_err_hotplug: + hnc_tput_hook(0); + hnc_hotplug_hook(HIF_GET_SOFTC(hif), 0); +lab_err_topology: + memset(napid->napi_cpu, 0, sizeof(struct qca_napi_cpu) * NR_CPUS); +lab_rss_init: + NAPI_DEBUG("<-- [rc=%d]", rc); + return rc; +} + +/** + * hif_napi_cpu_deinit() - clean-up of irq affinity block + * + * called by hif_napi_destroy, when the last instance is removed + * - uninstalls throughput and hotplug notifiers + * - clears cpu topology table + * Return: 0: OK + */ +int hif_napi_cpu_deinit(struct hif_opaque_softc *hif) +{ + int rc = 0; + struct qca_napi_data *napid = &HIF_GET_SOFTC(hif)->napi_data; + + NAPI_DEBUG("-->%s(...)", __func__); + + /* uninstall tput notifier */ + rc = hnc_tput_hook(0); + + /* uninstall hotplug notifier */ + rc = hnc_hotplug_hook(HIF_GET_SOFTC(hif), 0); + + /* clear the topology table */ + memset(napid->napi_cpu, 0, sizeof(struct qca_napi_cpu) * NR_CPUS); + + NAPI_DEBUG("<--%s[rc=%d]", __func__, rc); + + return rc; +} + +/** + * hncm_migrate_to() - migrates a NAPI to a CPU + * @napid: pointer to NAPI block + * @ce_id: CE_id of the NAPI instance + * @didx : index in the CPU topology table for the CPU to migrate to + * + * Migrates NAPI (identified by the CE_id) to the destination core + * Updates the napi_map of the destination entry + * + * Return: + * =0 : success + * <0 : error + */ +static int hncm_migrate_to(struct qca_napi_data *napid, + int napi_ce, + int didx) +{ + int rc = 0; + cpumask_t cpumask; + + NAPI_DEBUG("-->%s(napi_cd=%d, didx=%d)", __func__, napi_ce, didx); + + cpumask.bits[0] = (1 << didx); + if (!napid->napis[napi_ce]) + return -EINVAL; + + irq_modify_status(napid->napis[napi_ce]->irq, IRQ_NO_BALANCING, 0); + rc = irq_set_affinity_hint(napid->napis[napi_ce]->irq, &cpumask); + + /* unmark the napis bitmap in the cpu table */ + napid->napi_cpu[napid->napis[napi_ce]->cpu].napis &= ~(0x01 << napi_ce); + /* mark the napis bitmap for the new designated cpu */ + napid->napi_cpu[didx].napis |= (0x01 << napi_ce); + napid->napis[napi_ce]->cpu = didx; + + NAPI_DEBUG("<--%s[%d]", __func__, rc); + return rc; +} +/** + * hncm_dest_cpu() - finds a destination CPU for NAPI + * @napid: pointer to NAPI block + * @act : RELOCATE | COLLAPSE | DISPERSE + * + * Finds the designated destionation for the next IRQ. + * RELOCATE: translated to either COLLAPSE or DISPERSE based + * on napid->napi_mode (throughput state) + * COLLAPSE: All have the same destination: the first online CPU in lilcl + * DISPERSE: One of the CPU in bigcl, which has the smallest number of + * NAPIs on it + * + * Return: >=0 : index in the cpu topology table + * : < 0 : error + */ +static int hncm_dest_cpu(struct qca_napi_data *napid, int act) +{ + int destidx = -1; + int head, i; + + NAPI_DEBUG("-->%s(act=%d)", __func__, act); + if (act == HNC_ACT_RELOCATE) { + if (napid->napi_mode == QCA_NAPI_TPUT_LO) + act = HNC_ACT_COLLAPSE; + else + act = HNC_ACT_DISPERSE; + NAPI_DEBUG("%s: act changed from HNC_ACT_RELOCATE to %d", + __func__, act); + } + if (act == HNC_ACT_COLLAPSE) { + head = i = napid->lilcl_head; +retry_collapse: + while (i >= 0) { + if (napid->napi_cpu[i].state == QCA_NAPI_CPU_UP) { + destidx = i; + break; + } else { + i = napid->napi_cpu[i].cluster_nxt; + } + } + if ((destidx < 0) && (head == napid->lilcl_head)) { + NAPI_DEBUG("%s: COLLAPSE: no lilcl dest, try bigcl", + __func__); + head = i = napid->bigcl_head; + goto retry_collapse; + } + } else { /* HNC_ACT_DISPERSE */ + int smallest = 99; /* all 32 bits full */ + int smallidx = -1; + + head = i = napid->bigcl_head; +retry_disperse: + while (i >= 0) { + if ((napid->napi_cpu[i].state == QCA_NAPI_CPU_UP) && + (hweight32(napid->napi_cpu[i].napis) <= smallest)) { + smallest = napid->napi_cpu[i].napis; + smallidx = i; + } + i = napid->napi_cpu[i].cluster_nxt; + } + destidx = smallidx; + if ((destidx < 0) && (head == napid->bigcl_head)) { + NAPI_DEBUG("%s: DISPERSE: no bigcl dest, try lilcl", + __func__); + head = i = napid->lilcl_head; + goto retry_disperse; + } + } + NAPI_DEBUG("<--%s[dest=%d]", __func__, destidx); + return destidx; +} +/** + * hif_napi_cpu_migrate() - migrate IRQs away + * @cpu: -1: all CPUs specific CPU + * @act: COLLAPSE | DISPERSE + * + * Moves IRQs/NAPIs from specific or all CPUs (specified by @cpu) to eligible + * cores. Eligible cores are: + * act=COLLAPSE -> the first online core of the little cluster + * act=DISPERSE -> separate cores of the big cluster, so that each core will + * host minimum number of NAPIs/IRQs (napid->cpus[cpu].napis) + * + * Note that this function is called with a spinlock acquired already. + * + * Return: =0: success + * <0: error + */ + +int hif_napi_cpu_migrate(struct qca_napi_data *napid, int cpu, int action) +{ + int rc = 0; + struct qca_napi_cpu *cpup; + int i, dind; + uint32_t napis; + + NAPI_DEBUG("-->%s(.., cpu=%d, act=%d)", + __func__, cpu, action); + /* the following is really: hif_napi_enabled() with less overhead */ + if (napid->ce_map == 0) { + NAPI_DEBUG("%s: NAPI disabled. Not migrating.", __func__); + goto hncm_return; + } + + cpup = napid->napi_cpu; + + switch (action) { + case HNC_ACT_RELOCATE: + case HNC_ACT_DISPERSE: + case HNC_ACT_COLLAPSE: { + /* first find the src napi set */ + if (cpu == HNC_ANY_CPU) + napis = napid->ce_map; + else + napis = cpup[cpu].napis; + /* then clear the napi bitmap on each CPU */ + for (i = 0; i < NR_CPUS; i++) + cpup[i].napis = 0; + /* then for each of the NAPIs to disperse: */ + for (i = 0; i < CE_COUNT_MAX; i++) + if (napis & (1 << i)) { + /* find a destination CPU */ + dind = hncm_dest_cpu(napid, action); + if (dind >= 0) { + NAPI_DEBUG("Migrating NAPI ce%d to %d", + i, dind); + rc = hncm_migrate_to(napid, i, dind); + } else { + NAPI_DEBUG("No dest for NAPI ce%d", i); + hnc_dump_cpus(napid); + rc = -1; + } + } + break; + } + default: { + NAPI_DEBUG("%s: bad action: %d\n", __func__, action); + QDF_BUG(0); + break; + } + } /* switch action */ + +hncm_return: + hnc_dump_cpus(napid); + return rc; +} + + +/** + * hif_napi_bl_irq() - calls irq_modify_status to enable/disable blacklisting + * @napid: pointer to qca_napi_data structure + * @bl_flag: blacklist flag to enable/disable blacklisting + * + * The function enables/disables blacklisting for all the copy engine + * interrupts on which NAPI is enabled. + * + * Return: None + */ +static inline void hif_napi_bl_irq(struct qca_napi_data *napid, bool bl_flag) +{ + int i; + struct qca_napi_info *napii; + for (i = 0; i < CE_COUNT_MAX; i++) { + /* check if NAPI is enabled on the CE */ + if (!(napid->ce_map & (0x01 << i))) + continue; + + /*double check that NAPI is allocated for the CE */ + napii = napid->napis[i]; + if (!(napii)) + continue; + + if (bl_flag == true) + irq_modify_status(napii->irq, + 0, IRQ_NO_BALANCING); + else + irq_modify_status(napii->irq, + IRQ_NO_BALANCING, 0); + HIF_INFO("%s: bl_flag %d CE %d", __func__, bl_flag, i); + } +} + +/** + * hif_napi_cpu_blacklist() - en(dis)ables blacklisting for NAPI RX interrupts. + * @napid: pointer to qca_napi_data structure + * @op: blacklist operation to perform + * + * The function enables/disables/queries blacklisting for all CE RX + * interrupts with NAPI enabled. Besides blacklisting, it also enables/disables + * core_ctl_set_boost. + * Once blacklisting is enabled, the interrupts will not be managed by the IRQ + * balancer. + * + * Return: -EINVAL, in case IRQ_BLACKLISTING and CORE_CTL_BOOST is not enabled + * for BLACKLIST_QUERY op - blacklist refcount + * for BLACKLIST_ON op - return value from core_ctl_set_boost API + * for BLACKLIST_OFF op - return value from core_ctl_set_boost API + */ +int hif_napi_cpu_blacklist(struct qca_napi_data *napid, enum qca_blacklist_op op) +{ + int rc = 0; + static int ref_count; /* = 0 by the compiler */ + uint8_t flags = napid->flags; + bool bl_en = flags & QCA_NAPI_FEATURE_IRQ_BLACKLISTING; + bool ccb_en = flags & QCA_NAPI_FEATURE_CORE_CTL_BOOST; + + NAPI_DEBUG("-->%s(%d %d)", __func__, flags, op); + + if (!(bl_en && ccb_en)) { + rc = -EINVAL; + goto out; + } + + switch (op) { + case BLACKLIST_QUERY: + rc = ref_count; + break; + case BLACKLIST_ON: + ref_count++; + rc = 0; + if (ref_count == 1) { + rc = core_ctl_set_boost(true); + NAPI_DEBUG("boost_on() returns %d - refcnt=%d", + rc, ref_count); + hif_napi_bl_irq(napid, true); + } + break; + case BLACKLIST_OFF: + if (ref_count) { + ref_count--; + rc = 0; + if (ref_count == 0) { + rc = core_ctl_set_boost(false); + NAPI_DEBUG("boost_off() returns %d - refcnt=%d", + rc, ref_count); + hif_napi_bl_irq(napid, false); + } + } + break; + default: + NAPI_DEBUG("Invalid blacklist op: %d", op); + rc = -EINVAL; + } /* switch */ +out: + NAPI_DEBUG("<--%s[%d]", __func__, rc); + return rc; +} + +/** + * hif_napi_serialize() - [de-]serialize NAPI operations + * @hif: context + * @is_on: 1: serialize, 0: deserialize + * + * hif_napi_serialize(hif, 1) can be called multiple times. It will perform the + * following steps (see hif_napi_event for code): + * - put irqs of all NAPI instances on the same CPU + * - only for the first serialize call: blacklist + * + * hif_napi_serialize(hif, 0): + * - start a timer (multiple of BusBandwidthTimer -- default: 100 msec) + * - at the end of the timer, check the current throughput state and + * implement it. + */ +static unsigned long napi_serialize_reqs; +int hif_napi_serialize(struct hif_opaque_softc *hif, int is_on) +{ + int rc = -EINVAL; + + if (hif != NULL) + switch (is_on) { + case 0: { /* de-serialize */ + rc = hif_napi_event(hif, NAPI_EVT_USR_NORMAL, + (void *) 0); + napi_serialize_reqs = 0; + break; + } /* end de-serialize */ + case 1: { /* serialize */ + rc = hif_napi_event(hif, NAPI_EVT_USR_SERIAL, + (void *)napi_serialize_reqs++); + break; + } /* end serialize */ + default: + break; /* no-op */ + } /* switch */ + return rc; +} + +#endif /* ifdef HELIUMPLUS */ diff --git a/drivers/staging/qca-wifi-host-cmn/hif/src/ipq4019def.c b/drivers/staging/qca-wifi-host-cmn/hif/src/ipq4019def.c new file mode 100644 index 0000000000000000000000000000000000000000..ef0e281c1daaf71190084a748a8bfd12dcac3c94 --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/hif/src/ipq4019def.c @@ -0,0 +1,214 @@ +/* + * Copyright (c) 2015-2016 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. + */ + +#if defined(IPQ4019_HEADERS_DEF) +#define AR900B 1 + +#define WLAN_HEADERS 1 +#include "common_drv.h" +#include "IPQ4019/soc_addrs.h" +#include "IPQ4019/extra/hw/apb_map.h" +#ifdef WLAN_HEADERS +#include "IPQ4019/extra/hw/wifi_top_reg_map.h" +#include "IPQ4019/hw/rtc_soc_reg.h" +#endif +#include "IPQ4019/hw/ce_wrapper_reg_csr.h" + +#include "IPQ4019/extra/hw/soc_core_reg.h" +#include "IPQ4019/extra/hw/ce_reg_csr.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Base address is defined in pcie_local_reg.h. Macros which access the + * registers include the base address in their definition. + */ + +#define FW_EVENT_PENDING_ADDRESS (WIFICMN_SCRATCH_3_ADDRESS) +#define DRAM_BASE_ADDRESS TARG_DRAM_START + +/* Backwards compatibility -- TBDXXX */ + +#define MISSING 0 + +#define WLAN_SYSTEM_SLEEP_DISABLE_LSB WIFI_SYSTEM_SLEEP_DISABLE_LSB +#define WLAN_SYSTEM_SLEEP_DISABLE_MASK WIFI_SYSTEM_SLEEP_DISABLE_MASK +#define WLAN_RESET_CONTROL_COLD_RST_MASK WIFI_RESET_CONTROL_MAC_COLD_RST_MASK +#define WLAN_RESET_CONTROL_WARM_RST_MASK WIFI_RESET_CONTROL_MAC_WARM_RST_MASK +#define SOC_CLOCK_CONTROL_OFFSET SOC_CLOCK_CONTROL_ADDRESS +#define SOC_RESET_CONTROL_OFFSET SOC_RESET_CONTROL_ADDRESS +#define CPU_CLOCK_OFFSET SOC_CPU_CLOCK_ADDRESS +#define SOC_LPO_CAL_OFFSET SOC_LPO_CAL_ADDRESS +#define SOC_RESET_CONTROL_CE_RST_MASK WIFI_RESET_CONTROL_CE_RESET_MASK +#define WLAN_SYSTEM_SLEEP_OFFSET WIFI_SYSTEM_SLEEP_ADDRESS +#define WLAN_RESET_CONTROL_OFFSET WIFI_RESET_CONTROL_ADDRESS +#define CLOCK_CONTROL_OFFSET SOC_CLOCK_CONTROL_OFFSET +#define CLOCK_CONTROL_SI0_CLK_MASK SOC_CLOCK_CONTROL_SI0_CLK_MASK +#define RESET_CONTROL_SI0_RST_MASK SOC_RESET_CONTROL_SI0_RST_MASK +#define GPIO_BASE_ADDRESS WLAN_GPIO_BASE_ADDRESS +#define GPIO_PIN0_OFFSET MISSING +#define GPIO_PIN1_OFFSET MISSING +#define GPIO_PIN0_CONFIG_MASK MISSING +#define GPIO_PIN1_CONFIG_MASK MISSING +#define SCRATCH_BASE_ADDRESS SOC_CORE_BASE_ADDRESS +#define LOCAL_SCRATCH_OFFSET 0x18 +#define GPIO_PIN10_OFFSET WLAN_GPIO_PIN10_ADDRESS +#define GPIO_PIN11_OFFSET WLAN_GPIO_PIN11_ADDRESS +#define GPIO_PIN12_OFFSET WLAN_GPIO_PIN12_ADDRESS +#define GPIO_PIN13_OFFSET WLAN_GPIO_PIN13_ADDRESS +/*TBD:dakota Check if these can be removed for dakota */ +#define CPU_CLOCK_STANDARD_LSB SOC_CPU_CLOCK_STANDARD_LSB +#define CPU_CLOCK_STANDARD_MASK SOC_CPU_CLOCK_STANDARD_MASK +#define LPO_CAL_ENABLE_LSB SOC_LPO_CAL_ENABLE_LSB +#define LPO_CAL_ENABLE_MASK SOC_LPO_CAL_ENABLE_MASK +#define ANALOG_INTF_BASE_ADDRESS WLAN_ANALOG_INTF_BASE_ADDRESS +#define MBOX_BASE_ADDRESS MISSING +#define INT_STATUS_ENABLE_ERROR_LSB MISSING +#define INT_STATUS_ENABLE_ERROR_MASK MISSING +#define INT_STATUS_ENABLE_CPU_LSB MISSING +#define INT_STATUS_ENABLE_CPU_MASK MISSING +#define INT_STATUS_ENABLE_COUNTER_LSB MISSING +#define INT_STATUS_ENABLE_COUNTER_MASK MISSING +#define INT_STATUS_ENABLE_MBOX_DATA_LSB MISSING +#define INT_STATUS_ENABLE_MBOX_DATA_MASK MISSING +#define ERROR_STATUS_ENABLE_RX_UNDERFLOW_LSB MISSING +#define ERROR_STATUS_ENABLE_RX_UNDERFLOW_MASK MISSING +#define ERROR_STATUS_ENABLE_TX_OVERFLOW_LSB MISSING +#define ERROR_STATUS_ENABLE_TX_OVERFLOW_MASK MISSING +#define COUNTER_INT_STATUS_ENABLE_BIT_LSB MISSING +#define COUNTER_INT_STATUS_ENABLE_BIT_MASK MISSING +#define INT_STATUS_ENABLE_ADDRESS MISSING +#define CPU_INT_STATUS_ENABLE_BIT_LSB MISSING +#define CPU_INT_STATUS_ENABLE_BIT_MASK MISSING +#define HOST_INT_STATUS_ADDRESS MISSING +#define CPU_INT_STATUS_ADDRESS MISSING +#define ERROR_INT_STATUS_ADDRESS MISSING +#define ERROR_INT_STATUS_WAKEUP_MASK MISSING +#define ERROR_INT_STATUS_WAKEUP_LSB MISSING +#define ERROR_INT_STATUS_RX_UNDERFLOW_MASK MISSING +#define ERROR_INT_STATUS_RX_UNDERFLOW_LSB MISSING +#define ERROR_INT_STATUS_TX_OVERFLOW_MASK MISSING +#define ERROR_INT_STATUS_TX_OVERFLOW_LSB MISSING +#define COUNT_DEC_ADDRESS MISSING +#define HOST_INT_STATUS_CPU_MASK MISSING +#define HOST_INT_STATUS_CPU_LSB MISSING +#define HOST_INT_STATUS_ERROR_MASK MISSING +#define HOST_INT_STATUS_ERROR_LSB MISSING +#define HOST_INT_STATUS_COUNTER_MASK MISSING +#define HOST_INT_STATUS_COUNTER_LSB MISSING +#define RX_LOOKAHEAD_VALID_ADDRESS MISSING +#define WINDOW_DATA_ADDRESS MISSING +#define WINDOW_READ_ADDR_ADDRESS MISSING +#define WINDOW_WRITE_ADDR_ADDRESS MISSING +/* MAC Descriptor */ +#define RX_PPDU_END_ANTENNA_OFFSET_DWORD (RX_PPDU_END_25_RX_ANTENNA_OFFSET >> 2) +/* GPIO Register */ +#define GPIO_ENABLE_W1TS_LOW_ADDRESS MISSING +#define GPIO_PIN0_CONFIG_LSB MISSING +#define GPIO_PIN0_PAD_PULL_LSB MISSING +#define GPIO_PIN0_PAD_PULL_MASK MISSING +/* SI reg */ +#define SI_CONFIG_ERR_INT_MASK MISSING +#define SI_CONFIG_ERR_INT_LSB MISSING +/* CE descriptor */ +#define CE_SRC_DESC_SIZE_DWORD 2 +#define CE_DEST_DESC_SIZE_DWORD 2 +#define CE_SRC_DESC_SRC_PTR_OFFSET_DWORD 0 +#define CE_SRC_DESC_INFO_OFFSET_DWORD 1 +#define CE_DEST_DESC_DEST_PTR_OFFSET_DWORD 0 +#define CE_DEST_DESC_INFO_OFFSET_DWORD 1 +#if _BYTE_ORDER == _BIG_ENDIAN +#define CE_SRC_DESC_INFO_NBYTES_MASK 0xFFFF0000 +#define CE_SRC_DESC_INFO_NBYTES_SHIFT 16 +#define CE_SRC_DESC_INFO_GATHER_MASK 0x00008000 +#define CE_SRC_DESC_INFO_GATHER_SHIFT 15 +#define CE_SRC_DESC_INFO_BYTE_SWAP_MASK 0x00004000 +#define CE_SRC_DESC_INFO_BYTE_SWAP_SHIFT 14 +#define CE_SRC_DESC_INFO_HOST_INT_DISABLE_MASK 0x00002000 +#define CE_SRC_DESC_INFO_HOST_INT_DISABLE_SHIFT 13 +#define CE_SRC_DESC_INFO_TARGET_INT_DISABLE_MASK 0x00001000 +#define CE_SRC_DESC_INFO_TARGET_INT_DISABLE_SHIFT 12 +#define CE_SRC_DESC_INFO_META_DATA_MASK 0x00000FFF +#define CE_SRC_DESC_INFO_META_DATA_SHIFT 0 +#else +#define CE_SRC_DESC_INFO_NBYTES_MASK 0x0000FFFF +#define CE_SRC_DESC_INFO_NBYTES_SHIFT 0 +#define CE_SRC_DESC_INFO_GATHER_MASK 0x00010000 +#define CE_SRC_DESC_INFO_GATHER_SHIFT 16 +#define CE_SRC_DESC_INFO_BYTE_SWAP_MASK 0x00020000 +#define CE_SRC_DESC_INFO_BYTE_SWAP_SHIFT 17 +#define CE_SRC_DESC_INFO_HOST_INT_DISABLE_MASK 0x00040000 +#define CE_SRC_DESC_INFO_HOST_INT_DISABLE_SHIFT 18 +#define CE_SRC_DESC_INFO_TARGET_INT_DISABLE_MASK 0x00080000 +#define CE_SRC_DESC_INFO_TARGET_INT_DISABLE_SHIFT 19 +#define CE_SRC_DESC_INFO_META_DATA_MASK 0xFFF00000 +#define CE_SRC_DESC_INFO_META_DATA_SHIFT 20 +#endif +#if _BYTE_ORDER == _BIG_ENDIAN +#define CE_DEST_DESC_INFO_NBYTES_MASK 0xFFFF0000 +#define CE_DEST_DESC_INFO_NBYTES_SHIFT 16 +#define CE_DEST_DESC_INFO_GATHER_MASK 0x00008000 +#define CE_DEST_DESC_INFO_GATHER_SHIFT 15 +#define CE_DEST_DESC_INFO_BYTE_SWAP_MASK 0x00004000 +#define CE_DEST_DESC_INFO_BYTE_SWAP_SHIFT 14 +#define CE_DEST_DESC_INFO_HOST_INT_DISABLE_MASK 0x00002000 +#define CE_DEST_DESC_INFO_HOST_INT_DISABLE_SHIFT 13 +#define CE_DEST_DESC_INFO_TARGET_INT_DISABLE_MASK 0x00001000 +#define CE_DEST_DESC_INFO_TARGET_INT_DISABLE_SHIFT 12 +#define CE_DEST_DESC_INFO_META_DATA_MASK 0x00000FFF +#define CE_DEST_DESC_INFO_META_DATA_SHIFT 0 +#else +#define CE_DEST_DESC_INFO_NBYTES_MASK 0x0000FFFF +#define CE_DEST_DESC_INFO_NBYTES_SHIFT 0 +#define CE_DEST_DESC_INFO_GATHER_MASK 0x00010000 +#define CE_DEST_DESC_INFO_GATHER_SHIFT 16 +#define CE_DEST_DESC_INFO_BYTE_SWAP_MASK 0x00020000 +#define CE_DEST_DESC_INFO_BYTE_SWAP_SHIFT 17 +#define CE_DEST_DESC_INFO_HOST_INT_DISABLE_MASK 0x00040000 +#define CE_DEST_DESC_INFO_HOST_INT_DISABLE_SHIFT 18 +#define CE_DEST_DESC_INFO_TARGET_INT_DISABLE_MASK 0x00080000 +#define CE_DEST_DESC_INFO_TARGET_INT_DISABLE_SHIFT 19 +#define CE_DEST_DESC_INFO_META_DATA_MASK 0xFFF00000 +#define CE_DEST_DESC_INFO_META_DATA_SHIFT 20 +#endif + +#define MY_TARGET_DEF IPQ4019_TARGETdef +#define MY_HOST_DEF IPQ4019_HOSTdef +#define MY_CEREG_DEF IPQ4019_CE_TARGETdef +#define MY_TARGET_BOARD_DATA_SZ IPQ4019_BOARD_DATA_SZ +#define MY_TARGET_BOARD_EXT_DATA_SZ IPQ4019_BOARD_EXT_DATA_SZ +#include "targetdef.h" +#include "hostdef.h" +#else +#include "common_drv.h" +#include "targetdef.h" +#include "hostdef.h" +struct targetdef_s *IPQ4019_TARGETdef; +struct hostdef_s *IPQ4019_HOSTdef; +#endif /* IPQ4019_HEADERS_DEF */ diff --git a/drivers/staging/qca-wifi-host-cmn/hif/src/mp_dev.c b/drivers/staging/qca-wifi-host-cmn/hif/src/mp_dev.c new file mode 100644 index 0000000000000000000000000000000000000000..94ba0b13223a2b6ecbcd1cec3c6385a97bcb24ad --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/hif/src/mp_dev.c @@ -0,0 +1,329 @@ +/* + * Copyright (c) 2013-2014, 2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#include "hif_io32.h" +#include "hif_debug.h" +#include "mp_dev.h" + +/*chaninfo*/ +#define CHANINFOMEM_S2_READ_MASK 0x00000008 +#define CHANINFO_CTRL_CAPTURE_CHAN_INFO_MASK 0x00000001 +#define CHANINFO_CTRL_CHANINFOMEM_BW_MASK 0x00000030 +#define MULTICHAIN_ENABLE_RX_CHAIN_MASK_MASK 0x00000007 + +/*agc*/ +#define GAINS_MIN_OFFSETS_CF_AGC_HIST_ENABLE_MASK 0x00040000 +#define GAINS_MIN_OFFSETS_CF_AGC_HIST_GC_MASK 0x00080000 +#define GAINS_MIN_OFFSETS_CF_AGC_HIST_VOTING_MASK 0x00100000 +#define GAINS_MIN_OFFSETS_CF_AGC_HIST_PHY_ERR_MASK 0x00200000 +#define AGC_HISTORY_DUMP_MASK (\ + GAINS_MIN_OFFSETS_CF_AGC_HIST_ENABLE_MASK| \ + GAINS_MIN_OFFSETS_CF_AGC_HIST_GC_MASK| \ + GAINS_MIN_OFFSETS_CF_AGC_HIST_VOTING_MASK| \ + GAINS_MIN_OFFSETS_CF_AGC_HIST_PHY_ERR_MASK \ + ) + +#define BB_chaninfo_ctrl 0x1a370 +#define BB_multichain_enable 0x1a2a0 +#define BB_chn_tables_intf_addr 0x19894 +#define BB_chn1_tables_intf_addr 0x1a894 +#define BB_chn_tables_intf_data 0x19898 +#define BB_chn1_tables_intf_data 0x1a898 +#define BB_gains_min_offsets 0x19e08 +#define BB_chaninfo_tab_b0 0x03200 +#define BB_chaninfo_tab_b1 0x03300 +#define BB_watchdog_status 0x1a7c0 +#define BB_watchdog_ctrl_1 0x1a7c4 +#define BB_watchdog_ctrl_2 0x1a7c8 +#define BB_watchdog_status_B 0x1a7e0 + + +#define PHY_BB_CHN_TABLES_INTF_ADDR 0x19894 +#define PHY_BB_CHN_TABLES_INTF_DATA 0x19898 + +#define PHY_BB_CHN1_TABLES_INTF_ADDR 0x1a894 +#define PHY_BB_CHN1_TABLES_INTF_DATA 0x1a898 + + +struct priv_ctrl_ctx { + uint32_t chaninfo_ctrl_orig; + uint32_t gain_min_offsets_orig; + uint32_t anyreg_start; + uint32_t anyreg_len; +}; + +static struct priv_ctrl_ctx g_priv_dump_ctx; + +static inline void set_target_reg_bits(void __iomem *mem, uint32_t reg, + uint32_t bitmask, uint32_t val) +{ + uint32_t value = hif_read32_mb(mem + (reg)); + uint32_t shift = 0; + value &= ~(bitmask); + while (!((bitmask >> shift) & 0x01)) + shift++; + + value |= (((val) << shift) & (bitmask)); + hif_write32_mb(mem + (reg), value); +} + +static inline uint32_t get_target_reg_bits(void __iomem *mem, + uint32_t reg, uint32_t bitmask) +{ + uint32_t value = hif_read32_mb(mem + (reg)); + uint32_t shift = 0; + while (!((bitmask >> shift) & 0x01)) + shift++; + + return (value >> shift) & bitmask; +} + +void priv_start_cap_chaninfo(struct hif_softc *scn) +{ + set_target_reg_bits(scn->mem, BB_chaninfo_ctrl, + CHANINFO_CTRL_CAPTURE_CHAN_INFO_MASK, 1); +} + +void priv_start_agc(struct hif_softc *scn) +{ + g_priv_dump_ctx.gain_min_offsets_orig = + hif_read32_mb(scn->mem + BB_gains_min_offsets); + set_target_reg_bits(scn->mem, BB_gains_min_offsets, + AGC_HISTORY_DUMP_MASK, + 0x0f); +} + +static void priv_stop_agc(struct hif_softc *scn) +{ + set_target_reg_bits(scn->mem, BB_gains_min_offsets, + AGC_HISTORY_DUMP_MASK, + 0); +} + +void priv_dump_chaninfo(struct hif_softc *scn) +{ + uint32_t bw, val; + uint32_t len, i, tmp; + uint32_t chain_mask; + uint32_t chain0, chain1; + + chain_mask = + get_target_reg_bits(scn->mem, BB_multichain_enable, + MULTICHAIN_ENABLE_RX_CHAIN_MASK_MASK); + chain0 = chain_mask & 1; + chain1 = chain_mask & 2; + + HIF_TRACE("%s: E", __func__); + bw = get_target_reg_bits(scn->mem, BB_chaninfo_ctrl, + CHANINFO_CTRL_CHANINFOMEM_BW_MASK); + + if (bw == 0) + len = 53; + else if (bw == 1) + len = 57; + else if (bw == 2) + len = 59 * 2 - 1; + else + len = 60 * 2 + 61 * 2; + + /* + * each tone is 16 bit valid, write to 32bit buffer each. + * bw==0(legacy20): 53 tones. + * bw==1(ht/vht20): 57 tones. + * bw==2(ht/vht40): 59+58 tones. + * bw==3(vht80): 60*2+61*2 tones. + */ + + if (chain0) { + hif_write32_mb(scn->mem + BB_chn_tables_intf_addr, + 0x80003200); + } + if (chain1) { + hif_write32_mb(scn->mem + BB_chn1_tables_intf_addr, + 0x80003200); + } + + set_target_reg_bits(scn->mem, BB_chaninfo_ctrl, + CHANINFOMEM_S2_READ_MASK, 0); + + if (chain0) { + if (bw < 2) { + len = (bw == 0) ? 53 : 57; + for (i = 0; i < len; i++) { + val = + hif_read32_mb(scn->mem + + BB_chn_tables_intf_data) & + 0x0000ffff; + qdf_print("0x%x\t", val); + if (i % 4 == 0) + qdf_print("\n"); + } + } else { + len = (bw == 2) ? 59 : 60; + for (i = 0; i < len; i++) { + tmp = + hif_read32_mb(scn->mem + + BB_chn_tables_intf_data); + qdf_print("0x%x\t", ((tmp >> 16) & 0x0000ffff)); + qdf_print("0x%x\t", (tmp & 0x0000ffff)); + if (i % 2 == 0) + qdf_print("\n"); + } + if (bw > 2) { + /* bw == 3 for vht80 */ + hif_write32_mb(scn->mem + + BB_chn_tables_intf_addr, + 0x80003300); + len = 61; + for (i = 0; i < len; i++) { + tmp = + hif_read32_mb(scn->mem + + BB_chn_tables_intf_data); + qdf_print("0x%x\t", + ((tmp >> 16) & 0x0000ffff)); + qdf_print("0x%x\t", (tmp & 0x0000ffff)); + if (i % 2 == 0) + qdf_print("\n"); + } + } + } + } + if (chain1) { + if (bw < 2) { + len = (bw == 0) ? 53 : 57; + for (i = 0; i < len; i++) { + val = + hif_read32_mb(scn->mem + + BB_chn1_tables_intf_data) & + 0x0000ffff; + qdf_print("0x%x\t", val); + if (i % 4 == 0) + qdf_print("\n"); + } + } else { + len = (bw == 2) ? 59 : 60; + for (i = 0; i < len; i++) { + tmp = + hif_read32_mb(scn->mem + + BB_chn1_tables_intf_data); + qdf_print("0x%x\n", (tmp >> 16) & 0x0000ffff); + qdf_print("0x%x\n", tmp & 0x0000ffff); + if (i % 2 == 0) + qdf_print("\n"); + } + if (bw > 2) { + /* bw == 3 for vht80 */ + hif_write32_mb(scn->mem + + BB_chn1_tables_intf_addr, + 0x80003300); + len = 61; + for (i = 0; i < len; i++) { + tmp = + hif_read32_mb(scn->mem + + BB_chn1_tables_intf_data); + qdf_print("0x%x\t", + ((tmp >> 16) & 0x0000ffff)); + qdf_print("0x%x\t", (tmp & 0x0000ffff)); + if (i % 2 == 0) + qdf_print("\n"); + } + } + } + } + HIF_TRACE("%s: X", __func__); +} + +void priv_dump_agc(struct hif_softc *scn) +{ + int i, len = 30; /* check this value for Rome and Peregrine */ + uint32_t chain0, chain1, chain_mask, val; + + if (Q_TARGET_ACCESS_BEGIN(scn) < 0) + return; + + chain_mask = + get_target_reg_bits(scn->mem, BB_multichain_enable, + MULTICHAIN_ENABLE_RX_CHAIN_MASK_MASK); + chain0 = chain_mask & 1; + chain1 = chain_mask & 2; + + len = len << 1; /* each agc item is 64bit, total*2 */ + priv_stop_agc(scn); + + set_target_reg_bits(scn->mem, BB_chaninfo_ctrl, + CHANINFOMEM_S2_READ_MASK, 0); + + HIF_TRACE("%s: AGC history buffer dump: E", __func__); + if (chain0) { + for (i = 0; i < len; i++) { + hif_write32_mb(scn->mem + + PHY_BB_CHN_TABLES_INTF_ADDR, + BB_chaninfo_tab_b0 + i * 4); + val = hif_read32_mb(scn->mem + + PHY_BB_CHN_TABLES_INTF_DATA); + qdf_print("0x%x\t", val); + if (i % 4 == 0) + qdf_print("\n"); + } + } + if (chain1) { + for (i = 0; i < len; i++) { + hif_write32_mb(scn->mem + + PHY_BB_CHN1_TABLES_INTF_ADDR, + BB_chaninfo_tab_b0 + i * 4); + val = hif_read32_mb(scn->mem + + PHY_BB_CHN1_TABLES_INTF_DATA); + qdf_print("0x%x\t", val); + if (i % 4 == 0) + qdf_print("\n"); + } + } + HIF_TRACE("%s: AGC history buffer dump X", __func__); + /* restore original value */ + hif_write32_mb(scn->mem + BB_gains_min_offsets, + g_priv_dump_ctx.gain_min_offsets_orig); + + Q_TARGET_ACCESS_END(scn); + + return; +} + +void priv_dump_bbwatchdog(struct hif_softc *scn) +{ + uint32_t val; + + HIF_TRACE("%s: BB watchdog dump E", __func__); + val = hif_read32_mb(scn->mem + BB_watchdog_status); + qdf_print("0x%x\t", val); + val = hif_read32_mb(scn->mem + BB_watchdog_ctrl_1); + qdf_print("0x%x\t", val); + val = hif_read32_mb(scn->mem + BB_watchdog_ctrl_2); + qdf_print("0x%x\t", val); + val = hif_read32_mb(scn->mem + BB_watchdog_status_B); + qdf_print("0x%x", val); + HIF_TRACE("%s: BB watchdog dump X", __func__); +} diff --git a/drivers/staging/qca-wifi-host-cmn/hif/src/mp_dev.h b/drivers/staging/qca-wifi-host-cmn/hif/src/mp_dev.h new file mode 100644 index 0000000000000000000000000000000000000000..c09eabcab7318eb5af7cb2af9b0d274e32980e8d --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/hif/src/mp_dev.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2015-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef __MP_DEV_H__ +#define __MP_DEV_H__ +void priv_start_agc(struct hif_softc *scn); +void priv_dump_agc(struct hif_softc *scn); +void priv_start_cap_chaninfo(struct hif_softc *scn); +void priv_dump_chaninfo(struct hif_softc *scn); +void priv_dump_bbwatchdog(struct hif_softc *scn); +void hif_shutdown_device(struct hif_opaque_softc *scn); +#endif /* __MP_DEV_H__ */ diff --git a/drivers/staging/qca-wifi-host-cmn/hif/src/pcie/hif_io32_pci.h b/drivers/staging/qca-wifi-host-cmn/hif/src/pcie/hif_io32_pci.h new file mode 100644 index 0000000000000000000000000000000000000000..d1bf2759acded362e99b401063301deed5822013 --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/hif/src/pcie/hif_io32_pci.h @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2015-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef __HIF_IO32_PCI_H__ +#define __HIF_IO32_PCI_H__ + +#ifdef HIF_PCI + +#include "hif_main.h" +#include "regtable.h" +#include "ce_reg.h" +#include "qdf_atomic.h" +#include "if_pci.h" +/* + * For maximum performance and no power management, set this to 1. + * For power management at the cost of performance, set this to 0. + */ +#ifndef CONFIG_ATH_PCIE_MAX_PERF +#define CONFIG_ATH_PCIE_MAX_PERF 0 +#endif + +/* + * For keeping the target awake till the driver is + * loaded, set this to 1 + */ +#define CONFIG_ATH_PCIE_AWAKE_WHILE_DRIVER_LOAD 1 + +/* + * PCI-E L1 ASPPM sub-states + * To enable clock gating in L1 state, set this to 1. + * (less power, slightly more wakeup latency) + * To disable clock gating in L1 state, set this to 0. (slighly more power) + */ +#define CONFIG_PCIE_ENABLE_L1_CLOCK_GATE 1 + +/* + * PCIE_ACCESS_LOG_NUM specifies the number of + * read/write records to store + */ +#ifdef CONFIG_ATH_PCIE_ACCESS_DEBUG +#define PCIE_ACCESS_LOG_NUM 500 +#endif + +/* 64-bit MSI support */ +#define CONFIG_PCIE_64BIT_MSI 0 + +/* BAR0 ready checking for AR6320v2 */ +#define PCIE_BAR0_READY_CHECKING 0 + +/* AXI gating when L1, L2 to reduce power consumption */ +#define CONFIG_PCIE_ENABLE_AXI_CLK_GATE 0 + +irqreturn_t hif_fw_interrupt_handler(int irq, void *arg); +#endif /* HIF_PCI */ +#endif /* __HIF_IO32_PCI_H__ */ diff --git a/drivers/staging/qca-wifi-host-cmn/hif/src/pcie/if_pci.c b/drivers/staging/qca-wifi-host-cmn/hif/src/pcie/if_pci.c new file mode 100644 index 0000000000000000000000000000000000000000..07416f881d139cb467c1fbce0778988dcb498248 --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/hif/src/pcie/if_pci.c @@ -0,0 +1,4110 @@ +/* + * Copyright (c) 2013-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#include +#include +#include +#include +#ifdef CONFIG_PCI_MSM +#include +#endif +#include "hif_io32.h" +#include "if_pci.h" +#include "hif.h" +#include "hif_main.h" +#include "ce_main.h" +#include "ce_api.h" +#include "ce_internal.h" +#include "ce_reg.h" +#include "ce_bmi.h" +#include "regtable.h" +#include "hif_hw_version.h" +#include +#include +#include "qdf_status.h" +#include "qdf_atomic.h" +#include "pld_common.h" +#include "mp_dev.h" +#include "hif_debug.h" + +#include "if_pci_internal.h" +#include "ce_tasklet.h" +#include "targaddrs.h" + +#include "pci_api.h" +#include "ahb_api.h" + +/* Maximum ms timeout for host to wake up target */ +#define PCIE_WAKE_TIMEOUT 1000 +#define RAMDUMP_EVENT_TIMEOUT 2500 + +/* Setting SOC_GLOBAL_RESET during driver unload causes intermittent + * PCIe data bus error + * As workaround for this issue - changing the reset sequence to + * use TargetCPU warm reset * instead of SOC_GLOBAL_RESET + */ +#define CPU_WARM_RESET_WAR + +#ifdef CONFIG_WIN +extern int32_t frac, intval, ar900b_20_targ_clk, qca9888_20_targ_clk; +#endif + +/* + * Top-level interrupt handler for all PCI interrupts from a Target. + * When a block of MSI interrupts is allocated, this top-level handler + * is not used; instead, we directly call the correct sub-handler. + */ +struct ce_irq_reg_table { + uint32_t irq_enable; + uint32_t irq_status; +}; + +#ifndef QCA_WIFI_3_0_ADRASTEA +static inline void hif_pci_route_adrastea_interrupt(struct hif_pci_softc *sc) +{ + return; +} +#else +void hif_pci_route_adrastea_interrupt(struct hif_pci_softc *sc) +{ + struct hif_softc *scn = HIF_GET_SOFTC(sc); + unsigned int target_enable0, target_enable1; + unsigned int target_cause0, target_cause1; + + target_enable0 = hif_read32_mb(sc->mem + Q6_ENABLE_REGISTER_0); + target_enable1 = hif_read32_mb(sc->mem + Q6_ENABLE_REGISTER_1); + target_cause0 = hif_read32_mb(sc->mem + Q6_CAUSE_REGISTER_0); + target_cause1 = hif_read32_mb(sc->mem + Q6_CAUSE_REGISTER_1); + + if ((target_enable0 & target_cause0) || + (target_enable1 & target_cause1)) { + hif_write32_mb(sc->mem + Q6_ENABLE_REGISTER_0, 0); + hif_write32_mb(sc->mem + Q6_ENABLE_REGISTER_1, 0); + + if (scn->notice_send) + pld_intr_notify_q6(sc->dev); + } +} +#endif + +/** + * pci_dispatch_ce_irq() - pci_dispatch_ce_irq + * @scn: scn + * + * Return: N/A + */ +static void pci_dispatch_interrupt(struct hif_softc *scn) +{ + uint32_t intr_summary; + int id; + struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(scn); + + if (scn->hif_init_done != true) + return; + + if (Q_TARGET_ACCESS_BEGIN(scn) < 0) + return; + + intr_summary = CE_INTERRUPT_SUMMARY(scn); + + if (intr_summary == 0) { + if ((scn->target_status != TARGET_STATUS_RESET) && + (!qdf_atomic_read(&scn->link_suspended))) { + + hif_write32_mb(scn->mem + + (SOC_CORE_BASE_ADDRESS | + PCIE_INTR_ENABLE_ADDRESS), + HOST_GROUP0_MASK); + + hif_read32_mb(scn->mem + + (SOC_CORE_BASE_ADDRESS | + PCIE_INTR_ENABLE_ADDRESS)); + } + Q_TARGET_ACCESS_END(scn); + return; + } else { + Q_TARGET_ACCESS_END(scn); + } + + scn->ce_irq_summary = intr_summary; + for (id = 0; intr_summary && (id < scn->ce_count); id++) { + if (intr_summary & (1 << id)) { + intr_summary &= ~(1 << id); + ce_dispatch_interrupt(id, &hif_state->tasklets[id]); + } + } +} + +irqreturn_t hif_pci_interrupt_handler(int irq, void *arg) +{ + struct hif_pci_softc *sc = (struct hif_pci_softc *)arg; + struct hif_softc *scn = HIF_GET_SOFTC(sc); + struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(arg); + volatile int tmp; + uint16_t val; + uint32_t bar0; + uint32_t fw_indicator_address, fw_indicator; + bool ssr_irq = false; + unsigned int host_cause, host_enable; + + if (LEGACY_INTERRUPTS(sc)) { + if (Q_TARGET_ACCESS_BEGIN(scn) < 0) + return IRQ_HANDLED; + + if (ADRASTEA_BU) { + host_enable = hif_read32_mb(sc->mem + + PCIE_INTR_ENABLE_ADDRESS); + host_cause = hif_read32_mb(sc->mem + + PCIE_INTR_CAUSE_ADDRESS); + if (!(host_enable & host_cause)) { + hif_pci_route_adrastea_interrupt(sc); + return IRQ_HANDLED; + } + } + + /* Clear Legacy PCI line interrupts + * IMPORTANT: INTR_CLR regiser has to be set + * after INTR_ENABLE is set to 0, + * otherwise interrupt can not be really cleared */ + hif_write32_mb(sc->mem + + (SOC_CORE_BASE_ADDRESS | + PCIE_INTR_ENABLE_ADDRESS), 0); + + hif_write32_mb(sc->mem + + (SOC_CORE_BASE_ADDRESS | PCIE_INTR_CLR_ADDRESS), + ADRASTEA_BU ? + (host_enable & host_cause) : + HOST_GROUP0_MASK); + + if (ADRASTEA_BU) + hif_write32_mb(sc->mem + 0x2f100c , (host_cause >> 1)); + + /* IMPORTANT: this extra read transaction is required to + * flush the posted write buffer */ + if (!ADRASTEA_BU) { + tmp = + hif_read32_mb(sc->mem + + (SOC_CORE_BASE_ADDRESS | + PCIE_INTR_ENABLE_ADDRESS)); + + if (tmp == 0xdeadbeef) { + HIF_ERROR("BUG(%s): SoC returns 0xdeadbeef!!", + __func__); + + pci_read_config_word(sc->pdev, PCI_VENDOR_ID, &val); + HIF_ERROR("%s: PCI Vendor ID = 0x%04x", + __func__, val); + + pci_read_config_word(sc->pdev, PCI_DEVICE_ID, &val); + HIF_ERROR("%s: PCI Device ID = 0x%04x", + __func__, val); + + pci_read_config_word(sc->pdev, PCI_COMMAND, &val); + HIF_ERROR("%s: PCI Command = 0x%04x", __func__, + val); + + pci_read_config_word(sc->pdev, PCI_STATUS, &val); + HIF_ERROR("%s: PCI Status = 0x%04x", __func__, + val); + + pci_read_config_dword(sc->pdev, PCI_BASE_ADDRESS_0, + &bar0); + HIF_ERROR("%s: PCI BAR0 = 0x%08x", __func__, + bar0); + + HIF_ERROR("%s: RTC_STATE_ADDRESS = 0x%08x", + __func__, + hif_read32_mb(sc->mem + + PCIE_LOCAL_BASE_ADDRESS + + RTC_STATE_ADDRESS)); + HIF_ERROR("%s: PCIE_SOC_WAKE_ADDRESS = 0x%08x", + __func__, + hif_read32_mb(sc->mem + + PCIE_LOCAL_BASE_ADDRESS + + PCIE_SOC_WAKE_ADDRESS)); + HIF_ERROR("%s: 0x80008 = 0x%08x, 0x8000c = 0x%08x", + __func__, + hif_read32_mb(sc->mem + 0x80008), + hif_read32_mb(sc->mem + 0x8000c)); + HIF_ERROR("%s: 0x80010 = 0x%08x, 0x80014 = 0x%08x", + __func__, + hif_read32_mb(sc->mem + 0x80010), + hif_read32_mb(sc->mem + 0x80014)); + HIF_ERROR("%s: 0x80018 = 0x%08x, 0x8001c = 0x%08x", + __func__, + hif_read32_mb(sc->mem + 0x80018), + hif_read32_mb(sc->mem + 0x8001c)); + QDF_BUG(0); + } + + PCI_CLR_CAUSE0_REGISTER(sc); + } + + if (HAS_FW_INDICATOR) { + fw_indicator_address = hif_state->fw_indicator_address; + fw_indicator = A_TARGET_READ(scn, fw_indicator_address); + if ((fw_indicator != ~0) && + (fw_indicator & FW_IND_EVENT_PENDING)) + ssr_irq = true; + } + + if (Q_TARGET_ACCESS_END(scn) < 0) + return IRQ_HANDLED; + } + /* TBDXXX: Add support for WMAC */ + + if (ssr_irq) { + sc->irq_event = irq; + qdf_atomic_set(&scn->tasklet_from_intr, 1); + + qdf_atomic_inc(&scn->active_tasklet_cnt); + tasklet_schedule(&sc->intr_tq); + } else { + pci_dispatch_interrupt(scn); + } + + return IRQ_HANDLED; +} + +static irqreturn_t hif_pci_msi_fw_handler(int irq, void *arg) +{ + struct hif_pci_softc *sc = (struct hif_pci_softc *)arg; + + (irqreturn_t) hif_fw_interrupt_handler(sc->irq_event, arg); + + return IRQ_HANDLED; +} + +bool hif_pci_targ_is_present(struct hif_softc *scn, void *__iomem *mem) +{ + return 1; /* FIX THIS */ +} + +/** + * hif_pci_cancel_deferred_target_sleep() - cancels the defered target sleep + * @scn: hif_softc + * + * Return: void + */ +#if CONFIG_ATH_PCIE_MAX_PERF == 0 +void hif_pci_cancel_deferred_target_sleep(struct hif_softc *scn) +{ + struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(scn); + A_target_id_t pci_addr = scn->mem; + + qdf_spin_lock_irqsave(&hif_state->keep_awake_lock); + /* + * If the deferred sleep timer is running cancel it + * and put the soc into sleep. + */ + if (hif_state->fake_sleep == true) { + qdf_timer_stop(&hif_state->sleep_timer); + if (hif_state->verified_awake == false) { + hif_write32_mb(pci_addr + PCIE_LOCAL_BASE_ADDRESS + + PCIE_SOC_WAKE_ADDRESS, + PCIE_SOC_WAKE_RESET); + } + hif_state->fake_sleep = false; + } + qdf_spin_unlock_irqrestore(&hif_state->keep_awake_lock); +} +#else +inline void hif_pci_cancel_deferred_target_sleep(struct hif_softc *scn) +{ + return; +} +#endif + +#define A_PCIE_LOCAL_REG_READ(mem, addr) \ + hif_read32_mb((char *)(mem) + \ + PCIE_LOCAL_BASE_ADDRESS + (uint32_t)(addr)) + +#define A_PCIE_LOCAL_REG_WRITE(mem, addr, val) \ + hif_write32_mb(((char *)(mem) + \ + PCIE_LOCAL_BASE_ADDRESS + (uint32_t)(addr)), (val)) + +#ifdef QCA_WIFI_3_0 +/** + * hif_targ_is_awake() - check to see if the target is awake + * @hif_ctx: hif context + * + * emulation never goes to sleep + * + * Return: true if target is awake + */ +static bool hif_targ_is_awake(struct hif_softc *hif_ctx, void *__iomem *mem) +{ + return true; +} +#else +/** + * hif_targ_is_awake() - check to see if the target is awake + * @hif_ctx: hif context + * + * Return: true if the targets clocks are on + */ +static bool hif_targ_is_awake(struct hif_softc *scn, void *__iomem *mem) +{ + uint32_t val; + + if (scn->recovery) + return false; + val = hif_read32_mb(mem + PCIE_LOCAL_BASE_ADDRESS + + RTC_STATE_ADDRESS); + return (RTC_STATE_V_GET(val) & RTC_STATE_V_ON) == RTC_STATE_V_ON; +} +#endif + +#define ATH_PCI_RESET_WAIT_MAX 10 /* Ms */ +static void hif_pci_device_reset(struct hif_pci_softc *sc) +{ + void __iomem *mem = sc->mem; + int i; + uint32_t val; + struct hif_softc *scn = HIF_GET_SOFTC(sc); + + if (!scn->hostdef) + return; + + /* NB: Don't check resetok here. This form of reset + * is integral to correct operation. */ + + if (!SOC_GLOBAL_RESET_ADDRESS) { + return; + } + + if (!mem) { + return; + } + + HIF_ERROR("%s: Reset Device", __func__); + + /* + * NB: If we try to write SOC_GLOBAL_RESET_ADDRESS without first + * writing WAKE_V, the Target may scribble over Host memory! + */ + A_PCIE_LOCAL_REG_WRITE(mem, PCIE_SOC_WAKE_ADDRESS, + PCIE_SOC_WAKE_V_MASK); + for (i = 0; i < ATH_PCI_RESET_WAIT_MAX; i++) { + if (hif_targ_is_awake(scn, mem)) + break; + + qdf_mdelay(1); + } + + /* Put Target, including PCIe, into RESET. */ + val = A_PCIE_LOCAL_REG_READ(mem, SOC_GLOBAL_RESET_ADDRESS); + val |= 1; + A_PCIE_LOCAL_REG_WRITE(mem, SOC_GLOBAL_RESET_ADDRESS, val); + for (i = 0; i < ATH_PCI_RESET_WAIT_MAX; i++) { + if (A_PCIE_LOCAL_REG_READ(mem, RTC_STATE_ADDRESS) & + RTC_STATE_COLD_RESET_MASK) + break; + + qdf_mdelay(1); + } + + /* Pull Target, including PCIe, out of RESET. */ + val &= ~1; + A_PCIE_LOCAL_REG_WRITE(mem, SOC_GLOBAL_RESET_ADDRESS, val); + for (i = 0; i < ATH_PCI_RESET_WAIT_MAX; i++) { + if (! + (A_PCIE_LOCAL_REG_READ(mem, RTC_STATE_ADDRESS) & + RTC_STATE_COLD_RESET_MASK)) + break; + + qdf_mdelay(1); + } + + A_PCIE_LOCAL_REG_WRITE(mem, PCIE_SOC_WAKE_ADDRESS, PCIE_SOC_WAKE_RESET); +} + +/* CPU warm reset function + * Steps: + * 1. Disable all pending interrupts - so no pending interrupts on WARM reset + * 2. Clear the FW_INDICATOR_ADDRESS -so Traget CPU intializes FW + * correctly on WARM reset + * 3. Clear TARGET CPU LF timer interrupt + * 4. Reset all CEs to clear any pending CE tarnsactions + * 5. Warm reset CPU + */ +static void hif_pci_device_warm_reset(struct hif_pci_softc *sc) +{ + void __iomem *mem = sc->mem; + int i; + uint32_t val; + uint32_t fw_indicator; + struct hif_softc *scn = HIF_GET_SOFTC(sc); + + /* NB: Don't check resetok here. This form of reset is + * integral to correct operation. */ + + if (!mem) { + return; + } + + HIF_INFO_MED("%s: Target Warm Reset", __func__); + + /* + * NB: If we try to write SOC_GLOBAL_RESET_ADDRESS without first + * writing WAKE_V, the Target may scribble over Host memory! + */ + A_PCIE_LOCAL_REG_WRITE(mem, PCIE_SOC_WAKE_ADDRESS, + PCIE_SOC_WAKE_V_MASK); + for (i = 0; i < ATH_PCI_RESET_WAIT_MAX; i++) { + if (hif_targ_is_awake(scn, mem)) + break; + qdf_mdelay(1); + } + + /* + * Disable Pending interrupts + */ + val = + hif_read32_mb(mem + + (SOC_CORE_BASE_ADDRESS | + PCIE_INTR_CAUSE_ADDRESS)); + HIF_INFO_MED("%s: Host Intr Cause reg 0x%x : value : 0x%x", __func__, + (SOC_CORE_BASE_ADDRESS | PCIE_INTR_CAUSE_ADDRESS), val); + /* Target CPU Intr Cause */ + val = hif_read32_mb(mem + (SOC_CORE_BASE_ADDRESS | CPU_INTR_ADDRESS)); + HIF_INFO_MED("%s: Target CPU Intr Cause 0x%x", __func__, val); + + val = + hif_read32_mb(mem + + (SOC_CORE_BASE_ADDRESS | + PCIE_INTR_ENABLE_ADDRESS)); + hif_write32_mb((mem + + (SOC_CORE_BASE_ADDRESS | PCIE_INTR_ENABLE_ADDRESS)), 0); + hif_write32_mb((mem + (SOC_CORE_BASE_ADDRESS + PCIE_INTR_CLR_ADDRESS)), + HOST_GROUP0_MASK); + + qdf_mdelay(100); + + /* Clear FW_INDICATOR_ADDRESS */ + if (HAS_FW_INDICATOR) { + fw_indicator = hif_read32_mb(mem + FW_INDICATOR_ADDRESS); + hif_write32_mb(mem + FW_INDICATOR_ADDRESS, 0); + } + + /* Clear Target LF Timer interrupts */ + val = + hif_read32_mb(mem + + (RTC_SOC_BASE_ADDRESS + + SOC_LF_TIMER_CONTROL0_ADDRESS)); + HIF_INFO_MED("%s: addr 0x%x : 0x%x", __func__, + (RTC_SOC_BASE_ADDRESS + SOC_LF_TIMER_CONTROL0_ADDRESS), val); + val &= ~SOC_LF_TIMER_CONTROL0_ENABLE_MASK; + hif_write32_mb(mem + + (RTC_SOC_BASE_ADDRESS + SOC_LF_TIMER_CONTROL0_ADDRESS), + val); + + /* Reset CE */ + val = + hif_read32_mb(mem + + (RTC_SOC_BASE_ADDRESS | + SOC_RESET_CONTROL_ADDRESS)); + val |= SOC_RESET_CONTROL_CE_RST_MASK; + hif_write32_mb((mem + + (RTC_SOC_BASE_ADDRESS | SOC_RESET_CONTROL_ADDRESS)), + val); + val = + hif_read32_mb(mem + + (RTC_SOC_BASE_ADDRESS | + SOC_RESET_CONTROL_ADDRESS)); + qdf_mdelay(10); + + /* CE unreset */ + val &= ~SOC_RESET_CONTROL_CE_RST_MASK; + hif_write32_mb(mem + (RTC_SOC_BASE_ADDRESS | SOC_RESET_CONTROL_ADDRESS), + val); + val = + hif_read32_mb(mem + + (RTC_SOC_BASE_ADDRESS | + SOC_RESET_CONTROL_ADDRESS)); + qdf_mdelay(10); + + /* Read Target CPU Intr Cause */ + val = hif_read32_mb(mem + (SOC_CORE_BASE_ADDRESS | CPU_INTR_ADDRESS)); + HIF_INFO_MED("%s: Target CPU Intr Cause after CE reset 0x%x", + __func__, val); + + /* CPU warm RESET */ + val = + hif_read32_mb(mem + + (RTC_SOC_BASE_ADDRESS | + SOC_RESET_CONTROL_ADDRESS)); + val |= SOC_RESET_CONTROL_CPU_WARM_RST_MASK; + hif_write32_mb(mem + (RTC_SOC_BASE_ADDRESS | SOC_RESET_CONTROL_ADDRESS), + val); + val = + hif_read32_mb(mem + + (RTC_SOC_BASE_ADDRESS | + SOC_RESET_CONTROL_ADDRESS)); + HIF_INFO_MED("%s: RESET_CONTROL after cpu warm reset 0x%x", + __func__, val); + + qdf_mdelay(100); + HIF_INFO_MED("%s: Target Warm reset complete", __func__); + +} + +#ifndef QCA_WIFI_3_0 +int hif_check_fw_reg(struct hif_opaque_softc *hif_ctx) +{ + struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx); + struct hif_pci_softc *sc = HIF_GET_PCI_SOFTC(scn); + void __iomem *mem = sc->mem; + uint32_t val; + + if (Q_TARGET_ACCESS_BEGIN(scn) < 0) + return ATH_ISR_NOSCHED; + val = hif_read32_mb(mem + FW_INDICATOR_ADDRESS); + if (Q_TARGET_ACCESS_END(scn) < 0) + return ATH_ISR_SCHED; + + HIF_INFO_MED("%s: FW_INDICATOR register is 0x%x", __func__, val); + + if (val & FW_IND_HELPER) + return 0; + + return 1; +} +#endif + +int hif_check_soc_status(struct hif_opaque_softc *hif_ctx) +{ + struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx); + uint16_t device_id; + uint32_t val; + uint16_t timeout_count = 0; + struct hif_pci_softc *sc = HIF_GET_PCI_SOFTC(scn); + + /* Check device ID from PCIe configuration space for link status */ + pci_read_config_word(sc->pdev, PCI_DEVICE_ID, &device_id); + if (device_id != sc->devid) { + HIF_ERROR("%s: device ID does match (read 0x%x, expect 0x%x)", + __func__, device_id, sc->devid); + return -EACCES; + } + + /* Check PCIe local register for bar/memory access */ + val = hif_read32_mb(sc->mem + PCIE_LOCAL_BASE_ADDRESS + + RTC_STATE_ADDRESS); + HIF_INFO_MED("%s: RTC_STATE_ADDRESS is %08x", __func__, val); + + /* Try to wake up taget if it sleeps */ + hif_write32_mb(sc->mem + PCIE_LOCAL_BASE_ADDRESS + + PCIE_SOC_WAKE_ADDRESS, PCIE_SOC_WAKE_V_MASK); + HIF_INFO_MED("%s: PCIE_SOC_WAKE_ADDRESS is %08x", __func__, + hif_read32_mb(sc->mem + PCIE_LOCAL_BASE_ADDRESS + + PCIE_SOC_WAKE_ADDRESS)); + + /* Check if taget can be woken up */ + while (!hif_targ_is_awake(scn, sc->mem)) { + if (timeout_count >= PCIE_WAKE_TIMEOUT) { + HIF_ERROR("%s: wake up timeout, %08x, %08x", + __func__, + hif_read32_mb(sc->mem + + PCIE_LOCAL_BASE_ADDRESS + + RTC_STATE_ADDRESS), + hif_read32_mb(sc->mem + + PCIE_LOCAL_BASE_ADDRESS + + PCIE_SOC_WAKE_ADDRESS)); + return -EACCES; + } + + hif_write32_mb(sc->mem + PCIE_LOCAL_BASE_ADDRESS + + PCIE_SOC_WAKE_ADDRESS, PCIE_SOC_WAKE_V_MASK); + + qdf_mdelay(100); + timeout_count += 100; + } + + /* Check Power register for SoC internal bus issues */ + val = + hif_read32_mb(sc->mem + RTC_SOC_BASE_ADDRESS + + SOC_POWER_REG_OFFSET); + HIF_INFO_MED("%s: Power register is %08x", __func__, val); + + return 0; +} + +/** + * __hif_pci_dump_registers(): dump other PCI debug registers + * @scn: struct hif_softc + * + * This function dumps pci debug registers. The parrent function + * dumps the copy engine registers before calling this function. + * + * Return: void + */ +static void __hif_pci_dump_registers(struct hif_softc *scn) +{ + struct hif_pci_softc *sc = HIF_GET_PCI_SOFTC(scn); + void __iomem *mem = sc->mem; + uint32_t val, i, j; + uint32_t wrapper_idx[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + uint32_t ce_base; + + if (Q_TARGET_ACCESS_BEGIN(scn) < 0) + return; + + /* DEBUG_INPUT_SEL_SRC = 0x6 */ + val = + hif_read32_mb(mem + GPIO_BASE_ADDRESS + + WLAN_DEBUG_INPUT_SEL_OFFSET); + val &= ~WLAN_DEBUG_INPUT_SEL_SRC_MASK; + val |= WLAN_DEBUG_INPUT_SEL_SRC_SET(0x6); + hif_write32_mb(mem + GPIO_BASE_ADDRESS + WLAN_DEBUG_INPUT_SEL_OFFSET, + val); + + /* DEBUG_CONTROL_ENABLE = 0x1 */ + val = hif_read32_mb(mem + GPIO_BASE_ADDRESS + + WLAN_DEBUG_CONTROL_OFFSET); + val &= ~WLAN_DEBUG_CONTROL_ENABLE_MASK; + val |= WLAN_DEBUG_CONTROL_ENABLE_SET(0x1); + hif_write32_mb(mem + GPIO_BASE_ADDRESS + + WLAN_DEBUG_CONTROL_OFFSET, val); + + HIF_INFO_MED("%s: Debug: inputsel: %x dbgctrl: %x", __func__, + hif_read32_mb(mem + GPIO_BASE_ADDRESS + + WLAN_DEBUG_INPUT_SEL_OFFSET), + hif_read32_mb(mem + GPIO_BASE_ADDRESS + + WLAN_DEBUG_CONTROL_OFFSET)); + + HIF_INFO_MED("%s: Debug CE", __func__); + /* Loop CE debug output */ + /* AMBA_DEBUG_BUS_SEL = 0xc */ + val = hif_read32_mb(mem + GPIO_BASE_ADDRESS + AMBA_DEBUG_BUS_OFFSET); + val &= ~AMBA_DEBUG_BUS_SEL_MASK; + val |= AMBA_DEBUG_BUS_SEL_SET(0xc); + hif_write32_mb(mem + GPIO_BASE_ADDRESS + AMBA_DEBUG_BUS_OFFSET, val); + + for (i = 0; i < sizeof(wrapper_idx) / sizeof(uint32_t); i++) { + /* For (i=1,2,3,4,8,9) write CE_WRAPPER_DEBUG_SEL = i */ + val = hif_read32_mb(mem + CE_WRAPPER_BASE_ADDRESS + + CE_WRAPPER_DEBUG_OFFSET); + val &= ~CE_WRAPPER_DEBUG_SEL_MASK; + val |= CE_WRAPPER_DEBUG_SEL_SET(wrapper_idx[i]); + hif_write32_mb(mem + CE_WRAPPER_BASE_ADDRESS + + CE_WRAPPER_DEBUG_OFFSET, val); + + HIF_INFO_MED("%s: ce wrapper: %d amdbg: %x cewdbg: %x", + __func__, wrapper_idx[i], + hif_read32_mb(mem + GPIO_BASE_ADDRESS + + AMBA_DEBUG_BUS_OFFSET), + hif_read32_mb(mem + CE_WRAPPER_BASE_ADDRESS + + CE_WRAPPER_DEBUG_OFFSET)); + + if (wrapper_idx[i] <= 7) { + for (j = 0; j <= 5; j++) { + ce_base = CE_BASE_ADDRESS(wrapper_idx[i]); + /* For (j=0~5) write CE_DEBUG_SEL = j */ + val = + hif_read32_mb(mem + ce_base + + CE_DEBUG_OFFSET); + val &= ~CE_DEBUG_SEL_MASK; + val |= CE_DEBUG_SEL_SET(j); + hif_write32_mb(mem + ce_base + CE_DEBUG_OFFSET, + val); + + /* read (@gpio_athr_wlan_reg) + * WLAN_DEBUG_OUT_DATA */ + val = hif_read32_mb(mem + GPIO_BASE_ADDRESS + + WLAN_DEBUG_OUT_OFFSET); + val = WLAN_DEBUG_OUT_DATA_GET(val); + + HIF_INFO_MED("%s: module%d: cedbg: %x out: %x", + __func__, j, + hif_read32_mb(mem + ce_base + + CE_DEBUG_OFFSET), val); + } + } else { + /* read (@gpio_athr_wlan_reg) WLAN_DEBUG_OUT_DATA */ + val = + hif_read32_mb(mem + GPIO_BASE_ADDRESS + + WLAN_DEBUG_OUT_OFFSET); + val = WLAN_DEBUG_OUT_DATA_GET(val); + + HIF_INFO_MED("%s: out: %x", __func__, val); + } + } + + HIF_INFO_MED("%s: Debug PCIe:", __func__); + /* Loop PCIe debug output */ + /* Write AMBA_DEBUG_BUS_SEL = 0x1c */ + val = hif_read32_mb(mem + GPIO_BASE_ADDRESS + AMBA_DEBUG_BUS_OFFSET); + val &= ~AMBA_DEBUG_BUS_SEL_MASK; + val |= AMBA_DEBUG_BUS_SEL_SET(0x1c); + hif_write32_mb(mem + GPIO_BASE_ADDRESS + AMBA_DEBUG_BUS_OFFSET, val); + + for (i = 0; i <= 8; i++) { + /* For (i=1~8) write AMBA_DEBUG_BUS_PCIE_DEBUG_SEL = i */ + val = + hif_read32_mb(mem + GPIO_BASE_ADDRESS + + AMBA_DEBUG_BUS_OFFSET); + val &= ~AMBA_DEBUG_BUS_PCIE_DEBUG_SEL_MASK; + val |= AMBA_DEBUG_BUS_PCIE_DEBUG_SEL_SET(i); + hif_write32_mb(mem + GPIO_BASE_ADDRESS + AMBA_DEBUG_BUS_OFFSET, + val); + + /* read (@gpio_athr_wlan_reg) WLAN_DEBUG_OUT_DATA */ + val = + hif_read32_mb(mem + GPIO_BASE_ADDRESS + + WLAN_DEBUG_OUT_OFFSET); + val = WLAN_DEBUG_OUT_DATA_GET(val); + + HIF_INFO_MED("%s: amdbg: %x out: %x %x", __func__, + hif_read32_mb(mem + GPIO_BASE_ADDRESS + + WLAN_DEBUG_OUT_OFFSET), val, + hif_read32_mb(mem + GPIO_BASE_ADDRESS + + WLAN_DEBUG_OUT_OFFSET)); + } + + Q_TARGET_ACCESS_END(scn); +} + +/** + * hif_dump_registers(): dump bus debug registers + * @scn: struct hif_opaque_softc + * + * This function dumps hif bus debug registers + * + * Return: 0 for success or error code + */ +int hif_pci_dump_registers(struct hif_softc *hif_ctx) +{ + int status; + struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx); + + status = hif_dump_ce_registers(scn); + + if (status) + HIF_ERROR("%s: Dump CE Registers Failed", __func__); + + /* dump non copy engine pci registers */ + __hif_pci_dump_registers(scn); + + return 0; +} + +/* + * Handler for a per-engine interrupt on a PARTICULAR CE. + * This is used in cases where each CE has a private + * MSI interrupt. + */ +static irqreturn_t ce_per_engine_handler(int irq, void *arg) +{ + int CE_id = irq - MSI_ASSIGN_CE_INITIAL; + + /* + * NOTE: We are able to derive CE_id from irq because we + * use a one-to-one mapping for CE's 0..5. + * CE's 6 & 7 do not use interrupts at all. + * + * This mapping must be kept in sync with the mapping + * used by firmware. + */ + + ce_per_engine_service(arg, CE_id); + + return IRQ_HANDLED; +} + +#ifdef CONFIG_SLUB_DEBUG_ON + +/* worker thread to schedule wlan_tasklet in SLUB debug build */ +static void reschedule_tasklet_work_handler(void *arg) +{ + struct hif_pci_softc *sc = arg; + struct hif_softc *scn = HIF_GET_SOFTC(sc); + + if (!scn) { + HIF_ERROR("%s: hif_softc is NULL\n", __func__); + return; + } + + if (scn->hif_init_done == false) { + HIF_ERROR("%s: wlan driver is unloaded", __func__); + return; + } + + tasklet_schedule(&sc->intr_tq); + return; +} + +/** + * hif_init_reschedule_tasklet_work() - API to initialize reschedule tasklet + * work + * @sc: HIF PCI Context + * + * Return: void + */ +static void hif_init_reschedule_tasklet_work(struct hif_pci_softc *sc) +{ + qdf_create_work(0, &sc->reschedule_tasklet_work, + reschedule_tasklet_work_handler, NULL); +} +#else +static void hif_init_reschedule_tasklet_work(struct hif_pci_softc *sc) { } +#endif /* CONFIG_SLUB_DEBUG_ON */ + +void wlan_tasklet(unsigned long data) +{ + struct hif_pci_softc *sc = (struct hif_pci_softc *)data; + struct hif_softc *scn = HIF_GET_SOFTC(sc); + + if (scn->hif_init_done == false) + goto end; + + if (qdf_atomic_read(&scn->link_suspended)) + goto end; + + if (!ADRASTEA_BU) { + (irqreturn_t) hif_fw_interrupt_handler(sc->irq_event, scn); + if (scn->target_status == TARGET_STATUS_RESET) + goto end; + } + +end: + qdf_atomic_set(&scn->tasklet_from_intr, 0); + qdf_atomic_dec(&scn->active_tasklet_cnt); +} + +#ifdef FEATURE_RUNTIME_PM +static const char *hif_pm_runtime_state_to_string(uint32_t state) +{ + switch (state) { + case HIF_PM_RUNTIME_STATE_NONE: + return "INIT_STATE"; + case HIF_PM_RUNTIME_STATE_ON: + return "ON"; + case HIF_PM_RUNTIME_STATE_INPROGRESS: + return "INPROGRESS"; + case HIF_PM_RUNTIME_STATE_SUSPENDED: + return "SUSPENDED"; + default: + return "INVALID STATE"; + } +} + +#define HIF_PCI_RUNTIME_PM_STATS(_s, _sc, _name) \ + seq_printf(_s, "%30s: %u\n", #_name, _sc->pm_stats._name) +/** + * hif_pci_runtime_pm_warn() - Runtime PM Debugging API + * @sc: hif_pci_softc context + * @msg: log message + * + * log runtime pm stats when something seems off. + * + * Return: void + */ +static void hif_pci_runtime_pm_warn(struct hif_pci_softc *sc, const char *msg) +{ + struct hif_pm_runtime_lock *ctx; + + HIF_ERROR("%s: usage_count: %d, pm_state: %s, prevent_suspend_cnt: %d", + msg, atomic_read(&sc->dev->power.usage_count), + hif_pm_runtime_state_to_string( + atomic_read(&sc->pm_state)), + sc->prevent_suspend_cnt); + + HIF_ERROR("runtime_status: %d, runtime_error: %d, disable_depth: %d autosuspend_delay: %d", + sc->dev->power.runtime_status, + sc->dev->power.runtime_error, + sc->dev->power.disable_depth, + sc->dev->power.autosuspend_delay); + + HIF_ERROR("runtime_get: %u, runtime_put: %u, request_resume: %u", + sc->pm_stats.runtime_get, sc->pm_stats.runtime_put, + sc->pm_stats.request_resume); + + HIF_ERROR("allow_suspend: %u, prevent_suspend: %u", + sc->pm_stats.allow_suspend, + sc->pm_stats.prevent_suspend); + + HIF_ERROR("prevent_suspend_timeout: %u, allow_suspend_timeout: %u", + sc->pm_stats.prevent_suspend_timeout, + sc->pm_stats.allow_suspend_timeout); + + HIF_ERROR("Suspended: %u, resumed: %u count", + sc->pm_stats.suspended, + sc->pm_stats.resumed); + + HIF_ERROR("suspend_err: %u, runtime_get_err: %u", + sc->pm_stats.suspend_err, + sc->pm_stats.runtime_get_err); + + HIF_ERROR("Active Wakeup Sources preventing Runtime Suspend: "); + + list_for_each_entry(ctx, &sc->prevent_suspend_list, list) { + HIF_ERROR("source %s; timeout %d ms", ctx->name, ctx->timeout); + } + + WARN_ON(1); +} + +/** + * hif_pci_pm_runtime_debugfs_show(): show debug stats for runtimepm + * @s: file to print to + * @data: unused + * + * debugging tool added to the debug fs for displaying runtimepm stats + * + * Return: 0 + */ +static int hif_pci_pm_runtime_debugfs_show(struct seq_file *s, void *data) +{ + struct hif_pci_softc *sc = s->private; + static const char * const autopm_state[] = {"NONE", "ON", "INPROGRESS", + "SUSPENDED"}; + unsigned int msecs_age; + int pm_state = atomic_read(&sc->pm_state); + unsigned long timer_expires; + struct hif_pm_runtime_lock *ctx; + + seq_printf(s, "%30s: %s\n", "Runtime PM state", + autopm_state[pm_state]); + seq_printf(s, "%30s: %pf\n", "Last Resume Caller", + sc->pm_stats.last_resume_caller); + + if (pm_state == HIF_PM_RUNTIME_STATE_SUSPENDED) { + msecs_age = jiffies_to_msecs( + jiffies - sc->pm_stats.suspend_jiffies); + seq_printf(s, "%30s: %d.%03ds\n", "Suspended Since", + msecs_age / 1000, msecs_age % 1000); + } + + seq_printf(s, "%30s: %d\n", "PM Usage count", + atomic_read(&sc->dev->power.usage_count)); + + seq_printf(s, "%30s: %u\n", "prevent_suspend_cnt", + sc->prevent_suspend_cnt); + + HIF_PCI_RUNTIME_PM_STATS(s, sc, suspended); + HIF_PCI_RUNTIME_PM_STATS(s, sc, suspend_err); + HIF_PCI_RUNTIME_PM_STATS(s, sc, resumed); + HIF_PCI_RUNTIME_PM_STATS(s, sc, runtime_get); + HIF_PCI_RUNTIME_PM_STATS(s, sc, runtime_put); + HIF_PCI_RUNTIME_PM_STATS(s, sc, request_resume); + HIF_PCI_RUNTIME_PM_STATS(s, sc, prevent_suspend); + HIF_PCI_RUNTIME_PM_STATS(s, sc, allow_suspend); + HIF_PCI_RUNTIME_PM_STATS(s, sc, prevent_suspend_timeout); + HIF_PCI_RUNTIME_PM_STATS(s, sc, allow_suspend_timeout); + HIF_PCI_RUNTIME_PM_STATS(s, sc, runtime_get_err); + + timer_expires = sc->runtime_timer_expires; + if (timer_expires > 0) { + msecs_age = jiffies_to_msecs(timer_expires - jiffies); + seq_printf(s, "%30s: %d.%03ds\n", "Prevent suspend timeout", + msecs_age / 1000, msecs_age % 1000); + } + + spin_lock_bh(&sc->runtime_lock); + if (list_empty(&sc->prevent_suspend_list)) { + spin_unlock_bh(&sc->runtime_lock); + return 0; + } + + seq_printf(s, "%30s: ", "Active Wakeup_Sources"); + list_for_each_entry(ctx, &sc->prevent_suspend_list, list) { + seq_printf(s, "%s", ctx->name); + if (ctx->timeout) + seq_printf(s, "(%d ms)", ctx->timeout); + seq_puts(s, " "); + } + seq_puts(s, "\n"); + spin_unlock_bh(&sc->runtime_lock); + + return 0; +} +#undef HIF_PCI_RUNTIME_PM_STATS + +/** + * hif_pci_autopm_open() - open a debug fs file to access the runtime pm stats + * @inode + * @file + * + * Return: linux error code of single_open. + */ +static int hif_pci_runtime_pm_open(struct inode *inode, struct file *file) +{ + return single_open(file, hif_pci_pm_runtime_debugfs_show, + inode->i_private); +} + +static const struct file_operations hif_pci_runtime_pm_fops = { + .owner = THIS_MODULE, + .open = hif_pci_runtime_pm_open, + .release = single_release, + .read = seq_read, + .llseek = seq_lseek, +}; + +/** + * hif_runtime_pm_debugfs_create() - creates runtimepm debugfs entry + * @sc: pci context + * + * creates a debugfs entry to debug the runtime pm feature. + */ +static void hif_runtime_pm_debugfs_create(struct hif_pci_softc *sc) +{ + sc->pm_dentry = debugfs_create_file("cnss_runtime_pm", + S_IRUSR, NULL, sc, + &hif_pci_runtime_pm_fops); +} + +/** + * hif_runtime_pm_debugfs_remove() - removes runtimepm debugfs entry + * @sc: pci context + * + * removes the debugfs entry to debug the runtime pm feature. + */ +static void hif_runtime_pm_debugfs_remove(struct hif_pci_softc *sc) +{ + debugfs_remove(sc->pm_dentry); +} + +static void hif_runtime_init(struct device *dev, int delay) +{ + pm_runtime_set_autosuspend_delay(dev, delay); + pm_runtime_use_autosuspend(dev); + pm_runtime_allow(dev); + pm_runtime_mark_last_busy(dev); + pm_runtime_put_noidle(dev); + pm_suspend_ignore_children(dev, true); +} + +static void hif_runtime_exit(struct device *dev) +{ + pm_runtime_get_noresume(dev); + pm_runtime_set_active(dev); +} + +static void hif_pm_runtime_lock_timeout_fn(unsigned long data); + +/** + * hif_pm_runtime_start(): start the runtime pm + * @sc: pci context + * + * After this call, runtime pm will be active. + */ +static void hif_pm_runtime_start(struct hif_pci_softc *sc) +{ + struct hif_softc *ol_sc = HIF_GET_SOFTC(sc); + uint32_t mode = hif_get_conparam(ol_sc); + + if (!ol_sc->hif_config.enable_runtime_pm) { + HIF_INFO("%s: RUNTIME PM is disabled in ini\n", __func__); + return; + } + + if (mode == QDF_GLOBAL_FTM_MODE || QDF_IS_EPPING_ENABLED(mode)) { + HIF_INFO("%s: RUNTIME PM is disabled for FTM/EPPING mode\n", + __func__); + return; + } + + setup_timer(&sc->runtime_timer, hif_pm_runtime_lock_timeout_fn, + (unsigned long)sc); + + HIF_INFO("%s: Enabling RUNTIME PM, Delay: %d ms", __func__, + ol_sc->hif_config.runtime_pm_delay); + + hif_runtime_init(sc->dev, ol_sc->hif_config.runtime_pm_delay); + qdf_atomic_set(&sc->pm_state, HIF_PM_RUNTIME_STATE_ON); + hif_runtime_pm_debugfs_create(sc); +} + +/** + * hif_pm_runtime_stop(): stop runtime pm + * @sc: pci context + * + * Turns off runtime pm and frees corresponding resources + * that were acquired by hif_runtime_pm_start(). + */ +static void hif_pm_runtime_stop(struct hif_pci_softc *sc) +{ + struct hif_softc *ol_sc = HIF_GET_SOFTC(sc); + uint32_t mode = hif_get_conparam(ol_sc); + + if (!ol_sc->hif_config.enable_runtime_pm) + return; + + if (mode == QDF_GLOBAL_FTM_MODE || QDF_IS_EPPING_ENABLED(mode)) + return; + + hif_runtime_exit(sc->dev); + hif_pm_runtime_resume(sc->dev); + + qdf_atomic_set(&sc->pm_state, HIF_PM_RUNTIME_STATE_NONE); + + hif_runtime_pm_debugfs_remove(sc); + del_timer_sync(&sc->runtime_timer); + /* doesn't wait for penting trafic unlike cld-2.0 */ +} + +/** + * hif_pm_runtime_open(): initialize runtime pm + * @sc: pci data structure + * + * Early initialization + */ +static void hif_pm_runtime_open(struct hif_pci_softc *sc) +{ + spin_lock_init(&sc->runtime_lock); + + qdf_atomic_init(&sc->pm_state); + qdf_runtime_lock_init(&sc->prevent_linkdown_lock); + qdf_atomic_set(&sc->pm_state, HIF_PM_RUNTIME_STATE_NONE); + INIT_LIST_HEAD(&sc->prevent_suspend_list); +} + +/** + * hif_pm_runtime_sanitize_on_exit(): sanitize the pm usage count and state + * @sc: pci context + * + * Ensure we have only one vote against runtime suspend before closing + * the runtime suspend feature. + * + * all gets by the wlan driver should have been returned + * one vote should remain as part of cnss_runtime_exit + * + * needs to be revisited if we share the root complex. + */ +static void hif_pm_runtime_sanitize_on_exit(struct hif_pci_softc *sc) +{ + struct hif_pm_runtime_lock *ctx, *tmp; + + if (atomic_read(&sc->dev->power.usage_count) != 1) + hif_pci_runtime_pm_warn(sc, "Driver UnLoaded"); + else + return; + + spin_lock_bh(&sc->runtime_lock); + list_for_each_entry_safe(ctx, tmp, &sc->prevent_suspend_list, list) { + spin_unlock_bh(&sc->runtime_lock); + hif_pm_runtime_allow_suspend(GET_HIF_OPAQUE_HDL(sc), ctx); + spin_lock_bh(&sc->runtime_lock); + } + spin_unlock_bh(&sc->runtime_lock); + + /* ensure 1 and only 1 usage count so that when the wlan + * driver is re-insmodded runtime pm won't be + * disabled also ensures runtime pm doesn't get + * broken on by being less than 1. + */ + if (atomic_read(&sc->dev->power.usage_count) <= 0) + atomic_set(&sc->dev->power.usage_count, 1); + while (atomic_read(&sc->dev->power.usage_count) > 1) + hif_pm_runtime_put_auto(sc->dev); +} + +static int __hif_pm_runtime_allow_suspend(struct hif_pci_softc *hif_sc, + struct hif_pm_runtime_lock *lock); + +/** + * hif_pm_runtime_sanitize_on_ssr_exit() - Empty the suspend list on SSR + * @sc: PCIe Context + * + * API is used to empty the runtime pm prevent suspend list. + * + * Return: void + */ +static void hif_pm_runtime_sanitize_on_ssr_exit(struct hif_pci_softc *sc) +{ + struct hif_pm_runtime_lock *ctx, *tmp; + + spin_lock_bh(&sc->runtime_lock); + list_for_each_entry_safe(ctx, tmp, &sc->prevent_suspend_list, list) { + __hif_pm_runtime_allow_suspend(sc, ctx); + } + spin_unlock_bh(&sc->runtime_lock); +} + +/** + * hif_pm_runtime_close(): close runtime pm + * @sc: pci bus handle + * + * ensure runtime_pm is stopped before closing the driver + */ +static void hif_pm_runtime_close(struct hif_pci_softc *sc) +{ + struct hif_softc *scn = HIF_GET_SOFTC(sc); + + if (qdf_atomic_read(&sc->pm_state) == HIF_PM_RUNTIME_STATE_NONE) + return; + + hif_pm_runtime_stop(sc); + + hif_is_recovery_in_progress(scn) ? + hif_pm_runtime_sanitize_on_ssr_exit(sc) : + hif_pm_runtime_sanitize_on_exit(sc); +} +#else +static void hif_pm_runtime_close(struct hif_pci_softc *sc) {} +static void hif_pm_runtime_open(struct hif_pci_softc *sc) {} +static void hif_pm_runtime_start(struct hif_pci_softc *sc) {} +static void hif_pm_runtime_stop(struct hif_pci_softc *sc) {} +#endif + +/** + * hif_disable_power_gating() - disable HW power gating + * @hif_ctx: hif context + * + * disables pcie L1 power states + */ +static void hif_disable_power_gating(struct hif_opaque_softc *hif_ctx) +{ + struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx); + struct hif_pci_softc *sc = HIF_GET_PCI_SOFTC(hif_ctx); + + if (NULL == scn) { + HIF_ERROR("%s: Could not disable ASPM scn is null", + __func__); + return; + } + + /* Disable ASPM when pkt log is enabled */ + pci_read_config_dword(sc->pdev, 0x80, &sc->lcr_val); + pci_write_config_dword(sc->pdev, 0x80, (sc->lcr_val & 0xffffff00)); +} + +/** + * hif_enable_power_gating() - enable HW power gating + * @hif_ctx: hif context + * + * enables pcie L1 power states + */ +static void hif_enable_power_gating(struct hif_pci_softc *sc) +{ + if (NULL == sc) { + HIF_ERROR("%s: Could not disable ASPM scn is null", + __func__); + return; + } + + /* Re-enable ASPM after firmware/OTP download is complete */ + pci_write_config_dword(sc->pdev, 0x80, sc->lcr_val); +} + +/** + * hif_enable_power_management() - enable power management + * @hif_ctx: hif context + * + * Currently only does runtime pm. Eventually this function could + * consolidate other power state features such as only letting + * the soc sleep after the driver finishes loading and re-enabling + * aspm (hif_enable_power_gating). + */ +void hif_pci_enable_power_management(struct hif_softc *hif_sc, + bool is_packet_log_enabled) +{ + struct hif_pci_softc *pci_ctx = HIF_GET_PCI_SOFTC(hif_sc); + + if (pci_ctx == NULL) { + HIF_ERROR("%s, hif_ctx null", __func__); + return; + } + + hif_pm_runtime_start(pci_ctx); + + if (!is_packet_log_enabled) + hif_enable_power_gating(pci_ctx); + + if (!CONFIG_ATH_PCIE_MAX_PERF && + CONFIG_ATH_PCIE_AWAKE_WHILE_DRIVER_LOAD) { + if (hif_pci_target_sleep_state_adjust(hif_sc, true, false) < 0) + HIF_ERROR("%s, failed to set target to sleep", + __func__); + } +} + +/** + * hif_disable_power_management() - disable power management + * @hif_ctx: hif context + * + * Currently disables runtime pm. Should be updated to behave + * if runtime pm is not started. Should be updated to take care + * of aspm and soc sleep for driver load. + */ +void hif_pci_disable_power_management(struct hif_softc *hif_ctx) +{ + struct hif_pci_softc *pci_ctx = HIF_GET_PCI_SOFTC(hif_ctx); + + if (pci_ctx == NULL) { + HIF_ERROR("%s, hif_ctx null", __func__); + return; + } + + hif_pm_runtime_stop(pci_ctx); +} + +void hif_pci_display_stats(struct hif_softc *hif_ctx) +{ + struct hif_pci_softc *pci_ctx = HIF_GET_PCI_SOFTC(hif_ctx); + + if (pci_ctx == NULL) { + HIF_ERROR("%s, hif_ctx null", __func__); + return; + } + hif_display_ce_stats(&pci_ctx->ce_sc); +} + +void hif_pci_clear_stats(struct hif_softc *hif_ctx) +{ + struct hif_pci_softc *pci_ctx = HIF_GET_PCI_SOFTC(hif_ctx); + + if (pci_ctx == NULL) { + HIF_ERROR("%s, hif_ctx null", __func__); + return; + } + hif_clear_ce_stats(&pci_ctx->ce_sc); +} + +#define ATH_PCI_PROBE_RETRY_MAX 3 +/** + * hif_bus_open(): hif_bus_open + * @scn: scn + * @bus_type: bus type + * + * Return: n/a + */ +QDF_STATUS hif_pci_open(struct hif_softc *hif_ctx, enum qdf_bus_type bus_type) +{ + struct hif_pci_softc *sc = HIF_GET_PCI_SOFTC(hif_ctx); + + hif_ctx->bus_type = bus_type; + hif_pm_runtime_open(sc); + + qdf_spinlock_create(&sc->irq_lock); + + return hif_ce_open(hif_ctx); +} + +#ifdef BMI_RSP_POLLING +#define BMI_RSP_CB_REGISTER 0 +#else +#define BMI_RSP_CB_REGISTER 1 +#endif + +/** + * hif_register_bmi_callbacks() - register bmi callbacks + * @hif_sc: hif context + * + * Bmi phase uses different copy complete callbacks than mission mode. + */ +static void hif_register_bmi_callbacks(struct hif_softc *hif_sc) +{ + struct HIF_CE_pipe_info *pipe_info; + struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(hif_sc); + + /* + * Initially, establish CE completion handlers for use with BMI. + * These are overwritten with generic handlers after we exit BMI phase. + */ + pipe_info = &hif_state->pipe_info[BMI_CE_NUM_TO_TARG]; + ce_send_cb_register(pipe_info->ce_hdl, hif_bmi_send_done, pipe_info, 0); + + if (BMI_RSP_CB_REGISTER) { + pipe_info = &hif_state->pipe_info[BMI_CE_NUM_TO_HOST]; + ce_recv_cb_register( + pipe_info->ce_hdl, hif_bmi_recv_data, pipe_info, 0); + } +} + +/** + * hif_wake_target_cpu() - wake the target's cpu + * @scn: hif context + * + * Send an interrupt to the device to wake up the Target CPU + * so it has an opportunity to notice any changed state. + */ +static void hif_wake_target_cpu(struct hif_softc *scn) +{ + QDF_STATUS rv; + uint32_t core_ctrl; + struct hif_opaque_softc *hif_hdl = GET_HIF_OPAQUE_HDL(scn); + + rv = hif_diag_read_access(hif_hdl, + SOC_CORE_BASE_ADDRESS | CORE_CTRL_ADDRESS, + &core_ctrl); + QDF_ASSERT(rv == QDF_STATUS_SUCCESS); + /* A_INUM_FIRMWARE interrupt to Target CPU */ + core_ctrl |= CORE_CTRL_CPU_INTR_MASK; + + rv = hif_diag_write_access(hif_hdl, + SOC_CORE_BASE_ADDRESS | CORE_CTRL_ADDRESS, + core_ctrl); + QDF_ASSERT(rv == QDF_STATUS_SUCCESS); +} + +/** + * soc_wake_reset() - allow the target to go to sleep + * @scn: hif_softc + * + * Clear the force wake register. This is done by + * hif_sleep_entry and cancel defered timer sleep. + */ +static void soc_wake_reset(struct hif_softc *scn) +{ + hif_write32_mb(scn->mem + + PCIE_LOCAL_BASE_ADDRESS + + PCIE_SOC_WAKE_ADDRESS, + PCIE_SOC_WAKE_RESET); +} + +/** + * hif_sleep_entry() - gate target sleep + * @arg: hif context + * + * This function is the callback for the sleep timer. + * Check if last force awake critical section was at least + * HIF_MIN_SLEEP_INACTIVITY_TIME_MS time ago. if it was, + * allow the target to go to sleep and cancel the sleep timer. + * otherwise reschedule the sleep timer. + */ +static void hif_sleep_entry(void *arg) +{ + struct HIF_CE_state *hif_state = (struct HIF_CE_state *)arg; + struct hif_softc *scn = HIF_GET_SOFTC(hif_state); + uint32_t idle_ms; + + if (scn->recovery) + return; + + if (hif_is_driver_unloading(scn)) + return; + + qdf_spin_lock_irqsave(&hif_state->keep_awake_lock); + if (hif_state->verified_awake == false) { + idle_ms = qdf_system_ticks_to_msecs(qdf_system_ticks() + - hif_state->sleep_ticks); + if (idle_ms >= HIF_MIN_SLEEP_INACTIVITY_TIME_MS) { + if (!qdf_atomic_read(&scn->link_suspended)) { + soc_wake_reset(scn); + hif_state->fake_sleep = false; + } + } else { + qdf_timer_stop(&hif_state->sleep_timer); + qdf_timer_start(&hif_state->sleep_timer, + HIF_SLEEP_INACTIVITY_TIMER_PERIOD_MS); + } + } else { + qdf_timer_stop(&hif_state->sleep_timer); + qdf_timer_start(&hif_state->sleep_timer, + HIF_SLEEP_INACTIVITY_TIMER_PERIOD_MS); + } + qdf_spin_unlock_irqrestore(&hif_state->keep_awake_lock); +} + +#define HIF_HIA_MAX_POLL_LOOP 1000000 +#define HIF_HIA_POLLING_DELAY_MS 10 + +#ifdef CONFIG_WIN +static void hif_set_hia_extnd(struct hif_softc *scn) +{ + struct hif_opaque_softc *hif_hdl = GET_HIF_OPAQUE_HDL(scn); + struct hif_target_info *tgt_info = hif_get_target_info_handle(hif_hdl); + uint32_t target_type = tgt_info->target_type; + + HIF_TRACE("%s: E", __func__); + + if ((target_type == TARGET_TYPE_AR900B) || + target_type == TARGET_TYPE_QCA9984 || + target_type == TARGET_TYPE_QCA9888) { + /* CHIP revision is 8-11 bits of the CHIP_ID register 0xec + in RTC space */ + tgt_info->target_revision + = CHIP_ID_REVISION_GET(hif_read32_mb(scn->mem + + CHIP_ID_ADDRESS)); + qdf_print(KERN_INFO"chip_id 0x%x chip_revision 0x%x\n", + target_type, tgt_info->target_revision); + } + + { + uint32_t flag2_value = 0; + uint32_t flag2_targ_addr = + host_interest_item_address(target_type, + offsetof(struct host_interest_s, hi_skip_clock_init)); + + if ((ar900b_20_targ_clk != -1) && + (frac != -1) && (intval != -1)) { + hif_diag_read_access(hif_hdl, flag2_targ_addr, + &flag2_value); + qdf_print("\n Setting clk_override\n"); + flag2_value |= CLOCK_OVERRIDE; + + hif_diag_write_access(hif_hdl, flag2_targ_addr, + flag2_value); + qdf_print("\n CLOCK PLL val set %d\n", flag2_value); + } else { + qdf_print(KERN_INFO"\n CLOCK PLL skipped\n"); + } + } + + if (target_type == TARGET_TYPE_AR900B + || target_type == TARGET_TYPE_QCA9984 + || target_type == TARGET_TYPE_QCA9888) { + + /* for AR9980_2.0, 300 mhz clock is used, right now we assume + * this would be supplied through module parameters, + * if not supplied assumed default or same behavior as 1.0. + * Assume 1.0 clock can't be tuned, reset to defaults + */ + + qdf_print(KERN_INFO"%s: setting the target pll frac %x intval %x\n", + __func__, frac, intval); + + /* do not touch frac, and int val, let them be default -1, + * if desired, host can supply these through module params + */ + if (frac != -1 || intval != -1) { + uint32_t flag2_value = 0; + uint32_t flag2_targ_addr; + + flag2_targ_addr = + host_interest_item_address(target_type, + offsetof(struct host_interest_s, + hi_clock_info)); + hif_diag_read_access(hif_hdl, + flag2_targ_addr, &flag2_value); + qdf_print("\n ====> FRAC Val %x Address %x\n", frac, + flag2_value); + hif_diag_write_access(hif_hdl, flag2_value, frac); + qdf_print("\n INT Val %x Address %x\n", + intval, flag2_value + 4); + hif_diag_write_access(hif_hdl, + flag2_value + 4, intval); + } else { + qdf_print(KERN_INFO"%s: no frac provided, skipping pre-configuring PLL\n", + __func__); + } + + /* for 2.0 write 300 mhz into hi_desired_cpu_speed_hz */ + if ((target_type == TARGET_TYPE_AR900B) + && (tgt_info->target_revision == AR900B_REV_2) + && ar900b_20_targ_clk != -1) { + uint32_t flag2_value = 0; + uint32_t flag2_targ_addr; + + flag2_targ_addr + = host_interest_item_address(target_type, + offsetof(struct host_interest_s, + hi_desired_cpu_speed_hz)); + hif_diag_read_access(hif_hdl, flag2_targ_addr, + &flag2_value); + qdf_print("\n ====> hi_desired_cpu_speed_hz Address %x\n", + flag2_value); + hif_diag_write_access(hif_hdl, flag2_value, + ar900b_20_targ_clk/*300000000u*/); + } else if (target_type == TARGET_TYPE_QCA9888) { + uint32_t flag2_targ_addr; + + if (200000000u != qca9888_20_targ_clk) { + qca9888_20_targ_clk = 300000000u; + /* Setting the target clock speed to 300 mhz */ + } + + flag2_targ_addr + = host_interest_item_address(target_type, + offsetof(struct host_interest_s, + hi_desired_cpu_speed_hz)); + hif_diag_write_access(hif_hdl, flag2_targ_addr, + qca9888_20_targ_clk); + } else { + qdf_print(KERN_INFO"%s: targ_clk is not provided, skipping pre-configuring PLL\n", + __func__); + } + } else { + if (frac != -1 || intval != -1) { + uint32_t flag2_value = 0; + uint32_t flag2_targ_addr = + host_interest_item_address(target_type, + offsetof(struct host_interest_s, + hi_clock_info)); + hif_diag_read_access(hif_hdl, flag2_targ_addr, + &flag2_value); + qdf_print("\n ====> FRAC Val %x Address %x\n", frac, + flag2_value); + hif_diag_write_access(hif_hdl, flag2_value, frac); + qdf_print("\n INT Val %x Address %x\n", intval, + flag2_value + 4); + hif_diag_write_access(hif_hdl, flag2_value + 4, + intval); + } + } +} + +#else + +static void hif_set_hia_extnd(struct hif_softc *scn) +{ +} + +#endif + +/** + * hif_set_hia() - fill out the host interest area + * @scn: hif context + * + * This is replaced by hif_wlan_enable for integrated targets. + * This fills out the host interest area. The firmware will + * process these memory addresses when it is first brought out + * of reset. + * + * Return: 0 for success. + */ +static int hif_set_hia(struct hif_softc *scn) +{ + QDF_STATUS rv; + uint32_t interconnect_targ_addr = 0; + uint32_t pcie_state_targ_addr = 0; + uint32_t pipe_cfg_targ_addr = 0; + uint32_t svc_to_pipe_map = 0; + uint32_t pcie_config_flags = 0; + uint32_t flag2_value = 0; + uint32_t flag2_targ_addr = 0; +#ifdef QCA_WIFI_3_0 + uint32_t host_interest_area = 0; + uint8_t i; +#else + uint32_t ealloc_value = 0; + uint32_t ealloc_targ_addr = 0; + uint8_t banks_switched = 1; + uint32_t chip_id; +#endif + uint32_t pipe_cfg_addr; + struct hif_opaque_softc *hif_hdl = GET_HIF_OPAQUE_HDL(scn); + struct hif_target_info *tgt_info = hif_get_target_info_handle(hif_hdl); + uint32_t target_type = tgt_info->target_type; + int target_ce_config_sz, target_service_to_ce_map_sz; + static struct CE_pipe_config *target_ce_config; + struct service_to_pipe *target_service_to_ce_map; + + HIF_TRACE("%s: E", __func__); + + hif_get_target_ce_config(&target_ce_config, &target_ce_config_sz, + &target_service_to_ce_map, + &target_service_to_ce_map_sz, + NULL, NULL); + + if (ADRASTEA_BU) + return QDF_STATUS_SUCCESS; + +#ifdef QCA_WIFI_3_0 + i = 0; + while (i < HIF_HIA_MAX_POLL_LOOP) { + host_interest_area = hif_read32_mb(scn->mem + + A_SOC_CORE_SCRATCH_0_ADDRESS); + if ((host_interest_area & 0x01) == 0) { + qdf_mdelay(HIF_HIA_POLLING_DELAY_MS); + host_interest_area = 0; + i++; + if (i > HIF_HIA_MAX_POLL_LOOP && (i % 1000 == 0)) + HIF_ERROR("%s: poll timeout(%d)", __func__, i); + } else { + host_interest_area &= (~0x01); + hif_write32_mb(scn->mem + 0x113014, 0); + break; + } + } + + if (i >= HIF_HIA_MAX_POLL_LOOP) { + HIF_ERROR("%s: hia polling timeout", __func__); + return -EIO; + } + + if (host_interest_area == 0) { + HIF_ERROR("%s: host_interest_area = 0", __func__); + return -EIO; + } + + interconnect_targ_addr = host_interest_area + + offsetof(struct host_interest_area_t, + hi_interconnect_state); + + flag2_targ_addr = host_interest_area + + offsetof(struct host_interest_area_t, hi_option_flag2); + +#else + interconnect_targ_addr = hif_hia_item_address(target_type, + offsetof(struct host_interest_s, hi_interconnect_state)); + ealloc_targ_addr = hif_hia_item_address(target_type, + offsetof(struct host_interest_s, hi_early_alloc)); + flag2_targ_addr = hif_hia_item_address(target_type, + offsetof(struct host_interest_s, hi_option_flag2)); +#endif + /* Supply Target-side CE configuration */ + rv = hif_diag_read_access(hif_hdl, interconnect_targ_addr, + &pcie_state_targ_addr); + if (rv != QDF_STATUS_SUCCESS) { + HIF_ERROR("%s: interconnect_targ_addr = 0x%0x, ret = %d", + __func__, interconnect_targ_addr, rv); + goto done; + } + if (pcie_state_targ_addr == 0) { + rv = QDF_STATUS_E_FAILURE; + HIF_ERROR("%s: pcie state addr is 0", __func__); + goto done; + } + pipe_cfg_addr = pcie_state_targ_addr + + offsetof(struct pcie_state_s, + pipe_cfg_addr); + rv = hif_diag_read_access(hif_hdl, + pipe_cfg_addr, + &pipe_cfg_targ_addr); + if (rv != QDF_STATUS_SUCCESS) { + HIF_ERROR("%s: pipe_cfg_addr = 0x%0x, ret = %d", + __func__, pipe_cfg_addr, rv); + goto done; + } + if (pipe_cfg_targ_addr == 0) { + rv = QDF_STATUS_E_FAILURE; + HIF_ERROR("%s: pipe cfg addr is 0", __func__); + goto done; + } + + rv = hif_diag_write_mem(hif_hdl, pipe_cfg_targ_addr, + (uint8_t *) target_ce_config, + target_ce_config_sz); + + if (rv != QDF_STATUS_SUCCESS) { + HIF_ERROR("%s: write pipe cfg (%d)", __func__, rv); + goto done; + } + + rv = hif_diag_read_access(hif_hdl, + pcie_state_targ_addr + + offsetof(struct pcie_state_s, + svc_to_pipe_map), + &svc_to_pipe_map); + if (rv != QDF_STATUS_SUCCESS) { + HIF_ERROR("%s: get svc/pipe map (%d)", __func__, rv); + goto done; + } + if (svc_to_pipe_map == 0) { + rv = QDF_STATUS_E_FAILURE; + HIF_ERROR("%s: svc_to_pipe map is 0", __func__); + goto done; + } + + rv = hif_diag_write_mem(hif_hdl, + svc_to_pipe_map, + (uint8_t *) target_service_to_ce_map, + target_service_to_ce_map_sz); + if (rv != QDF_STATUS_SUCCESS) { + HIF_ERROR("%s: write svc/pipe map (%d)", __func__, rv); + goto done; + } + + rv = hif_diag_read_access(hif_hdl, + pcie_state_targ_addr + + offsetof(struct pcie_state_s, + config_flags), + &pcie_config_flags); + if (rv != QDF_STATUS_SUCCESS) { + HIF_ERROR("%s: get pcie config_flags (%d)", __func__, rv); + goto done; + } +#if (CONFIG_PCIE_ENABLE_L1_CLOCK_GATE) + pcie_config_flags |= PCIE_CONFIG_FLAG_ENABLE_L1; +#else + pcie_config_flags &= ~PCIE_CONFIG_FLAG_ENABLE_L1; +#endif /* CONFIG_PCIE_ENABLE_L1_CLOCK_GATE */ + pcie_config_flags |= PCIE_CONFIG_FLAG_CLK_SWITCH_WAIT; +#if (CONFIG_PCIE_ENABLE_AXI_CLK_GATE) + pcie_config_flags |= PCIE_CONFIG_FLAG_AXI_CLK_GATE; +#endif + rv = hif_diag_write_mem(hif_hdl, + pcie_state_targ_addr + + offsetof(struct pcie_state_s, + config_flags), + (uint8_t *) &pcie_config_flags, + sizeof(pcie_config_flags)); + if (rv != QDF_STATUS_SUCCESS) { + HIF_ERROR("%s: write pcie config_flags (%d)", __func__, rv); + goto done; + } + +#ifndef QCA_WIFI_3_0 + /* configure early allocation */ + ealloc_targ_addr = hif_hia_item_address(target_type, + offsetof( + struct host_interest_s, + hi_early_alloc)); + + rv = hif_diag_read_access(hif_hdl, ealloc_targ_addr, + &ealloc_value); + if (rv != QDF_STATUS_SUCCESS) { + HIF_ERROR("%s: get early alloc val (%d)", __func__, rv); + goto done; + } + + /* 1 bank is switched to IRAM, except ROME 1.0 */ + ealloc_value |= + ((HI_EARLY_ALLOC_MAGIC << HI_EARLY_ALLOC_MAGIC_SHIFT) & + HI_EARLY_ALLOC_MAGIC_MASK); + + rv = hif_diag_read_access(hif_hdl, + CHIP_ID_ADDRESS | + RTC_SOC_BASE_ADDRESS, &chip_id); + if (rv != QDF_STATUS_SUCCESS) { + HIF_ERROR("%s: get chip id val (%d)", __func__, rv); + goto done; + } + if (CHIP_ID_VERSION_GET(chip_id) == 0xD) { + tgt_info->target_revision = CHIP_ID_REVISION_GET(chip_id); + switch (CHIP_ID_REVISION_GET(chip_id)) { + case 0x2: /* ROME 1.3 */ + /* 2 banks are switched to IRAM */ + banks_switched = 2; + break; + case 0x4: /* ROME 2.1 */ + case 0x5: /* ROME 2.2 */ + banks_switched = 6; + break; + case 0x8: /* ROME 3.0 */ + case 0x9: /* ROME 3.1 */ + case 0xA: /* ROME 3.2 */ + banks_switched = 9; + break; + case 0x0: /* ROME 1.0 */ + case 0x1: /* ROME 1.1 */ + default: + /* 3 banks are switched to IRAM */ + banks_switched = 3; + break; + } + } + + ealloc_value |= + ((banks_switched << HI_EARLY_ALLOC_IRAM_BANKS_SHIFT) + & HI_EARLY_ALLOC_IRAM_BANKS_MASK); + + rv = hif_diag_write_access(hif_hdl, + ealloc_targ_addr, + ealloc_value); + if (rv != QDF_STATUS_SUCCESS) { + HIF_ERROR("%s: set early alloc val (%d)", __func__, rv); + goto done; + } +#endif + if ((target_type == TARGET_TYPE_AR900B) + || (target_type == TARGET_TYPE_QCA9984) + || (target_type == TARGET_TYPE_QCA9888) + || (target_type == TARGET_TYPE_AR9888)) { + hif_set_hia_extnd(scn); + } + + /* Tell Target to proceed with initialization */ + flag2_targ_addr = hif_hia_item_address(target_type, + offsetof( + struct host_interest_s, + hi_option_flag2)); + + rv = hif_diag_read_access(hif_hdl, flag2_targ_addr, + &flag2_value); + if (rv != QDF_STATUS_SUCCESS) { + HIF_ERROR("%s: get option val (%d)", __func__, rv); + goto done; + } + + flag2_value |= HI_OPTION_EARLY_CFG_DONE; + rv = hif_diag_write_access(hif_hdl, flag2_targ_addr, + flag2_value); + if (rv != QDF_STATUS_SUCCESS) { + HIF_ERROR("%s: set option val (%d)", __func__, rv); + goto done; + } + + hif_wake_target_cpu(scn); + +done: + + return rv; +} + +/** + * hif_bus_configure() - configure the pcie bus + * @hif_sc: pointer to the hif context. + * + * return: 0 for success. nonzero for failure. + */ +int hif_pci_bus_configure(struct hif_softc *hif_sc) +{ + int status = 0; + struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(hif_sc); + struct hif_opaque_softc *hif_hdl = GET_HIF_OPAQUE_HDL(hif_sc); + struct hif_target_info *tgt_info = hif_get_target_info_handle(hif_hdl); + + hif_ce_prepare_config(hif_sc); + + /* initialize sleep state adjust variables */ + hif_state->sleep_timer_init = true; + hif_state->keep_awake_count = 0; + hif_state->fake_sleep = false; + hif_state->sleep_ticks = 0; + + qdf_timer_init(NULL, &hif_state->sleep_timer, + hif_sleep_entry, (void *)hif_state, + QDF_TIMER_TYPE_WAKE_APPS); + hif_state->sleep_timer_init = true; + + if (ADRASTEA_BU) { + status = hif_wlan_enable(hif_sc); + + if (status) { + HIF_ERROR("%s: hif_wlan_enable error = %d", + __func__, status); + goto timer_free; + } + } + + A_TARGET_ACCESS_LIKELY(hif_sc); + + if (CONFIG_ATH_PCIE_MAX_PERF || + CONFIG_ATH_PCIE_AWAKE_WHILE_DRIVER_LOAD) { + /* Force AWAKE forever/till the driver is loaded */ + if (tgt_info->target_type != TARGET_TYPE_IPQ4019) { + if (hif_pci_target_sleep_state_adjust(hif_sc, + false, true) < 0) { + status = -EACCES; + goto disable_wlan; + } + } + } + + status = hif_config_ce(hif_sc); + if (status) + goto disable_wlan; + + status = hif_set_hia(hif_sc); + if (status) + goto unconfig_ce; + + HIF_INFO_MED("%s: hif_set_hia done", __func__); + + hif_register_bmi_callbacks(hif_sc); + + status = hif_configure_irq(hif_sc); + if (status < 0) + goto unconfig_ce; + + A_TARGET_ACCESS_UNLIKELY(hif_sc); + + return status; + +unconfig_ce: + hif_unconfig_ce(hif_sc); +disable_wlan: + A_TARGET_ACCESS_UNLIKELY(hif_sc); + if (ADRASTEA_BU) + hif_wlan_disable(hif_sc); + +timer_free: + qdf_timer_stop(&hif_state->sleep_timer); + qdf_timer_free(&hif_state->sleep_timer); + hif_state->sleep_timer_init = false; + + HIF_ERROR("%s: failed, status = %d", __func__, status); + return status; +} + +/** + * hif_bus_close(): hif_bus_close + * + * Return: n/a + */ +void hif_pci_close(struct hif_softc *hif_sc) +{ + struct hif_pci_softc *hif_pci_sc = HIF_GET_PCI_SOFTC(hif_sc); + hif_pm_runtime_close(hif_pci_sc); + hif_ce_close(hif_sc); +} + +#define BAR_NUM 0 + +static int hif_enable_pci(struct hif_pci_softc *sc, + struct pci_dev *pdev, + const struct pci_device_id *id) +{ + void __iomem *mem; + int ret = 0; + uint16_t device_id; + struct hif_softc *ol_sc = HIF_GET_SOFTC(sc); + + pci_read_config_word(pdev, PCI_DEVICE_ID, &device_id); + if (device_id != id->device) { + HIF_ERROR( + "%s: dev id mismatch, config id = 0x%x, probing id = 0x%x", + __func__, device_id, id->device); + /* pci link is down, so returing with error code */ + return -EIO; + } + + /* FIXME: temp. commenting out assign_resource + * call for dev_attach to work on 2.6.38 kernel + */ +#if (!defined(__LINUX_ARM_ARCH__)) + if (pci_assign_resource(pdev, BAR_NUM)) { + HIF_ERROR("%s: pci_assign_resource error", __func__); + return -EIO; + } +#endif + if (pci_enable_device(pdev)) { + HIF_ERROR("%s: pci_enable_device error", + __func__); + return -EIO; + } + + /* Request MMIO resources */ + ret = pci_request_region(pdev, BAR_NUM, "ath"); + if (ret) { + HIF_ERROR("%s: PCI MMIO reservation error", __func__); + ret = -EIO; + goto err_region; + } +#ifdef CONFIG_ARM_LPAE + /* if CONFIG_ARM_LPAE is enabled, we have to set 64 bits mask + * for 32 bits device also. */ + ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(64)); + if (ret) { + HIF_ERROR("%s: Cannot enable 64-bit pci DMA", __func__); + goto err_dma; + } + ret = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)); + if (ret) { + HIF_ERROR("%s: Cannot enable 64-bit DMA", __func__); + goto err_dma; + } +#else + ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); + if (ret) { + HIF_ERROR("%s: Cannot enable 32-bit pci DMA", __func__); + goto err_dma; + } + ret = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); + if (ret) { + HIF_ERROR("%s: Cannot enable 32-bit consistent DMA!", + __func__); + goto err_dma; + } +#endif + + PCI_CFG_TO_DISABLE_L1SS_STATES(pdev, 0x188); + + /* Set bus master bit in PCI_COMMAND to enable DMA */ + pci_set_master(pdev); + + /* Arrange for access to Target SoC registers. */ + mem = pci_iomap(pdev, BAR_NUM, 0); + if (!mem) { + HIF_ERROR("%s: PCI iomap error", __func__); + ret = -EIO; + goto err_iomap; + } + sc->mem = mem; + sc->pdev = pdev; + sc->dev = &pdev->dev; + sc->devid = id->device; + sc->cacheline_sz = dma_get_cache_alignment(); + ol_sc->mem = mem; + sc->pci_enabled = true; + return ret; + +err_iomap: + pci_clear_master(pdev); +err_dma: + pci_release_region(pdev, BAR_NUM); +err_region: + pci_disable_device(pdev); + return ret; +} + +static void hif_disable_pci(struct hif_pci_softc *sc) +{ + struct hif_softc *ol_sc = HIF_GET_SOFTC(sc); + + if (ol_sc == NULL) { + HIF_ERROR("%s: ol_sc = NULL", __func__); + return; + } + hif_pci_device_reset(sc); + pci_iounmap(sc->pdev, sc->mem); + sc->mem = NULL; + ol_sc->mem = NULL; + pci_clear_master(sc->pdev); + pci_release_region(sc->pdev, BAR_NUM); + pci_disable_device(sc->pdev); +} + +static int hif_pci_probe_tgt_wakeup(struct hif_pci_softc *sc) +{ + int ret = 0; + int targ_awake_limit = 500; +#ifndef QCA_WIFI_3_0 + uint32_t fw_indicator; +#endif + struct hif_softc *scn = HIF_GET_SOFTC(sc); + + /* + * Verify that the Target was started cleanly.* + * The case where this is most likely is with an AUX-powered + * Target and a Host in WoW mode. If the Host crashes, + * loses power, or is restarted (without unloading the driver) + * then the Target is left (aux) powered and running. On a + * subsequent driver load, the Target is in an unexpected state. + * We try to catch that here in order to reset the Target and + * retry the probe. + */ + hif_write32_mb(sc->mem + PCIE_LOCAL_BASE_ADDRESS + + PCIE_SOC_WAKE_ADDRESS, PCIE_SOC_WAKE_V_MASK); + while (!hif_targ_is_awake(scn, sc->mem)) { + if (0 == targ_awake_limit) { + HIF_ERROR("%s: target awake timeout", __func__); + ret = -EAGAIN; + goto end; + } + qdf_mdelay(1); + targ_awake_limit--; + } + +#if PCIE_BAR0_READY_CHECKING + { + int wait_limit = 200; + /* Synchronization point: wait the BAR0 is configured */ + while (wait_limit-- && + !(hif_read32_mb(sc->mem + + PCIE_LOCAL_BASE_ADDRESS + + PCIE_SOC_RDY_STATUS_ADDRESS) \ + & PCIE_SOC_RDY_STATUS_BAR_MASK)) { + qdf_mdelay(10); + } + if (wait_limit < 0) { + /* AR6320v1 doesn't support checking of BAR0 configuration, + takes one sec to wait BAR0 ready */ + HIF_INFO_MED("%s: AR6320v1 waits two sec for BAR0", + __func__); + } + } +#endif + +#ifndef QCA_WIFI_3_0 + fw_indicator = hif_read32_mb(sc->mem + FW_INDICATOR_ADDRESS); + hif_write32_mb(sc->mem + PCIE_LOCAL_BASE_ADDRESS + + PCIE_SOC_WAKE_ADDRESS, PCIE_SOC_WAKE_RESET); + + if (fw_indicator & FW_IND_INITIALIZED) { + HIF_ERROR("%s: Target is in an unknown state. EAGAIN", + __func__); + ret = -EAGAIN; + goto end; + } +#endif + +end: + return ret; +} + +static void wlan_tasklet_msi(unsigned long data) +{ + struct hif_tasklet_entry *entry = (struct hif_tasklet_entry *)data; + struct hif_pci_softc *sc = (struct hif_pci_softc *) entry->hif_handler; + struct hif_softc *scn = HIF_GET_SOFTC(sc); + + if (scn->hif_init_done == false) + goto irq_handled; + + if (qdf_atomic_read(&scn->link_suspended)) + goto irq_handled; + + qdf_atomic_inc(&scn->active_tasklet_cnt); + + if (entry->id == HIF_MAX_TASKLET_NUM) { + /* the last tasklet is for fw IRQ */ + (irqreturn_t)hif_fw_interrupt_handler(sc->irq_event, scn); + if (scn->target_status == TARGET_STATUS_RESET) + goto irq_handled; + } else if (entry->id < scn->ce_count) { + ce_per_engine_service(scn, entry->id); + } else { + HIF_ERROR("%s: ERROR - invalid CE_id = %d", + __func__, entry->id); + } + return; + +irq_handled: + qdf_atomic_dec(&scn->active_tasklet_cnt); + +} + +static int hif_configure_msi(struct hif_pci_softc *sc) +{ + int ret = 0; + int num_msi_desired; + int rv = -1; + struct hif_softc *scn = HIF_GET_SOFTC(sc); + + HIF_TRACE("%s: E", __func__); + + num_msi_desired = MSI_NUM_REQUEST; /* Multiple MSI */ + if (num_msi_desired < 1) { + HIF_ERROR("%s: MSI is not configured", __func__); + return -EINVAL; + } + + if (num_msi_desired > 1) { +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)) + rv = pci_enable_msi_range(sc->pdev, num_msi_desired, + num_msi_desired); +#else + rv = pci_enable_msi_block(sc->pdev, num_msi_desired); +#endif + } + HIF_TRACE("%s: num_msi_desired = %d, available_msi = %d", + __func__, num_msi_desired, rv); + + if (rv == 0 || rv >= HIF_MAX_TASKLET_NUM) { + int i; + + sc->num_msi_intrs = HIF_MAX_TASKLET_NUM; + sc->tasklet_entries[HIF_MAX_TASKLET_NUM-1].hif_handler = + (void *)sc; + sc->tasklet_entries[HIF_MAX_TASKLET_NUM-1].id = + HIF_MAX_TASKLET_NUM; + tasklet_init(&sc->intr_tq, wlan_tasklet_msi, + (unsigned long)&sc->tasklet_entries[ + HIF_MAX_TASKLET_NUM-1]); + ret = request_irq(sc->pdev->irq + MSI_ASSIGN_FW, + hif_pci_msi_fw_handler, + IRQF_SHARED, "wlan_pci", sc); + if (ret) { + HIF_ERROR("%s: request_irq failed", __func__); + goto err_intr; + } + for (i = 0; i <= scn->ce_count; i++) { + sc->tasklet_entries[i].hif_handler = (void *)sc; + sc->tasklet_entries[i].id = i; + tasklet_init(&sc->intr_tq, wlan_tasklet_msi, + (unsigned long)&sc->tasklet_entries[i]); + ret = request_irq((sc->pdev->irq + + i + MSI_ASSIGN_CE_INITIAL), + ce_per_engine_handler, IRQF_SHARED, + "wlan_pci", sc); + if (ret) { + HIF_ERROR("%s: request_irq failed", __func__); + goto err_intr; + } + } + } else if (rv > 0) { + HIF_TRACE("%s: use single msi", __func__); + + ret = pci_enable_msi(sc->pdev); + if (ret < 0) { + HIF_ERROR("%s: single MSI allocation failed", + __func__); + /* Try for legacy PCI line interrupts */ + sc->num_msi_intrs = 0; + } else { + sc->num_msi_intrs = 1; + tasklet_init(&sc->intr_tq, + wlan_tasklet, (unsigned long)sc); + ret = request_irq(sc->pdev->irq, + hif_pci_interrupt_handler, + IRQF_SHARED, "wlan_pci", sc); + if (ret) { + HIF_ERROR("%s: request_irq failed", __func__); + goto err_intr; + } + } + } else { + sc->num_msi_intrs = 0; + ret = -EIO; + HIF_ERROR("%s: do not support MSI, rv = %d", __func__, rv); + } + ret = pci_enable_msi(sc->pdev); + if (ret < 0) { + HIF_ERROR("%s: single MSI interrupt allocation failed", + __func__); + /* Try for legacy PCI line interrupts */ + sc->num_msi_intrs = 0; + } else { + sc->num_msi_intrs = 1; + tasklet_init(&sc->intr_tq, wlan_tasklet, (unsigned long)sc); + ret = request_irq(sc->pdev->irq, + hif_pci_interrupt_handler, IRQF_SHARED, + "wlan_pci", sc); + if (ret) { + HIF_ERROR("%s: request_irq failed", __func__); + goto err_intr; + } + } + + if (ret == 0) { + hif_write32_mb(sc->mem+(SOC_CORE_BASE_ADDRESS | + PCIE_INTR_ENABLE_ADDRESS), + HOST_GROUP0_MASK); + hif_write32_mb(sc->mem + + PCIE_LOCAL_BASE_ADDRESS + PCIE_SOC_WAKE_ADDRESS, + PCIE_SOC_WAKE_RESET); + } + HIF_TRACE("%s: X, ret = %d", __func__, ret); + + return ret; + +err_intr: +if (sc->num_msi_intrs >= 1) + pci_disable_msi(sc->pdev); + return ret; +} + +static int hif_pci_configure_legacy_irq(struct hif_pci_softc *sc) +{ + int ret = 0; + struct hif_softc *scn = HIF_GET_SOFTC(sc); + uint32_t target_type = scn->target_info.target_type; + + HIF_TRACE("%s: E", __func__); + + /* do notn support MSI or MSI IRQ failed */ + tasklet_init(&sc->intr_tq, wlan_tasklet, (unsigned long)sc); + ret = request_irq(sc->pdev->irq, + hif_pci_interrupt_handler, IRQF_SHARED, + "wlan_pci", sc); + if (ret) { + HIF_ERROR("%s: request_irq failed, ret = %d", __func__, ret); + goto end; + } + /* Use sc->irq instead of sc->pdev-irq + platform_device pdev doesn't have an irq field */ + sc->irq = sc->pdev->irq; + /* Use Legacy PCI Interrupts */ + hif_write32_mb(sc->mem+(SOC_CORE_BASE_ADDRESS | + PCIE_INTR_ENABLE_ADDRESS), + HOST_GROUP0_MASK); + hif_read32_mb(sc->mem+(SOC_CORE_BASE_ADDRESS | + PCIE_INTR_ENABLE_ADDRESS)); + hif_write32_mb(sc->mem + PCIE_LOCAL_BASE_ADDRESS + + PCIE_SOC_WAKE_ADDRESS, PCIE_SOC_WAKE_RESET); + + if ((target_type == TARGET_TYPE_IPQ4019) || + (target_type == TARGET_TYPE_AR900B) || + (target_type == TARGET_TYPE_QCA9984) || + (target_type == TARGET_TYPE_AR9888) || + (target_type == TARGET_TYPE_QCA9888)) { + hif_write32_mb(scn->mem + PCIE_LOCAL_BASE_ADDRESS + + PCIE_SOC_WAKE_ADDRESS, PCIE_SOC_WAKE_V_MASK); + } +end: + QDF_TRACE(QDF_MODULE_ID_HIF, QDF_TRACE_LEVEL_ERROR, + "%s: X, ret = %d", __func__, ret); + return ret; +} + +/** + * hif_nointrs(): disable IRQ + * + * This function stops interrupt(s) + * + * @scn: struct hif_softc + * + * Return: none + */ +void hif_pci_nointrs(struct hif_softc *scn) +{ + int i; + struct hif_pci_softc *sc = HIF_GET_PCI_SOFTC(scn); + struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(scn); + + if (scn->request_irq_done == false) + return; + if (sc->num_msi_intrs > 0) { + /* MSI interrupt(s) */ + for (i = 0; i < sc->num_msi_intrs; i++) { + free_irq(sc->irq + i, sc); + } + sc->num_msi_intrs = 0; + } else { + /* Legacy PCI line interrupt + Use sc->irq instead of sc->pdev-irq + platform_device pdev doesn't have an irq field */ + free_irq(sc->irq, sc); + } + ce_unregister_irq(hif_state, 0xfff); + scn->request_irq_done = false; +} + +/** + * hif_disable_bus(): hif_disable_bus + * + * This function disables the bus + * + * @bdev: bus dev + * + * Return: none + */ +void hif_pci_disable_bus(struct hif_softc *scn) +{ + struct hif_pci_softc *sc = HIF_GET_PCI_SOFTC(scn); + struct pci_dev *pdev; + void __iomem *mem; + struct hif_target_info *tgt_info = &scn->target_info; + + /* Attach did not succeed, all resources have been + * freed in error handler + */ + if (!sc) + return; + + pdev = sc->pdev; + if (ADRASTEA_BU) { + hif_vote_link_down(GET_HIF_OPAQUE_HDL(scn)); + + hif_write32_mb(sc->mem + PCIE_INTR_ENABLE_ADDRESS, 0); + hif_write32_mb(sc->mem + PCIE_INTR_CLR_ADDRESS, + HOST_GROUP0_MASK); + } + +#if defined(CPU_WARM_RESET_WAR) + /* Currently CPU warm reset sequence is tested only for AR9888_REV2 + * Need to enable for AR9888_REV1 once CPU warm reset sequence is + * verified for AR9888_REV1 + */ + if ((tgt_info->target_version == AR9888_REV2_VERSION) || (tgt_info->target_version == AR9887_REV1_VERSION)) + hif_pci_device_warm_reset(sc); + else + hif_pci_device_reset(sc); +#else + hif_pci_device_reset(sc); +#endif + mem = (void __iomem *)sc->mem; + if (mem) { + pci_disable_msi(pdev); + hif_dump_pipe_debug_count(scn); + if (scn->athdiag_procfs_inited) { + athdiag_procfs_remove(); + scn->athdiag_procfs_inited = false; + } + pci_iounmap(pdev, mem); + scn->mem = NULL; + pci_release_region(pdev, BAR_NUM); + pci_clear_master(pdev); + pci_disable_device(pdev); + } + HIF_INFO("%s: X", __func__); +} + +#define OL_ATH_PCI_PM_CONTROL 0x44 + +#ifdef FEATURE_RUNTIME_PM +/** + * hif_runtime_prevent_linkdown() - prevent or allow a runtime pm from occuring + * @scn: hif context + * @flag: prevent linkdown if true otherwise allow + * + * this api should only be called as part of bus prevent linkdown + */ +static void hif_runtime_prevent_linkdown(struct hif_softc *scn, bool flag) +{ + struct hif_pci_softc *sc = HIF_GET_PCI_SOFTC(scn); + struct hif_opaque_softc *hif_hdl = GET_HIF_OPAQUE_HDL(scn); + + if (flag) + qdf_runtime_pm_prevent_suspend(&sc->prevent_linkdown_lock); + else + qdf_runtime_pm_allow_suspend(&sc->prevent_linkdown_lock); +} +#else +static void hif_runtime_prevent_linkdown(struct hif_softc *scn, bool flag) +{ +} +#endif + +#if defined(CONFIG_PCI_MSM) +/** + * hif_bus_prevent_linkdown(): allow or permit linkdown + * @flag: true prevents linkdown, false allows + * + * Calls into the platform driver to vote against taking down the + * pcie link. + * + * Return: n/a + */ +void hif_pci_prevent_linkdown(struct hif_softc *scn, bool flag) +{ + HIF_ERROR("wlan: %s pcie power collapse", + (flag ? "disable" : "enable")); + hif_runtime_prevent_linkdown(scn, flag); + pld_wlan_pm_control(scn->qdf_dev->dev, flag); +} +#else +void hif_pci_prevent_linkdown(struct hif_softc *scn, bool flag) +{ + HIF_ERROR("wlan: %s pcie power collapse", + (flag ? "disable" : "enable")); + hif_runtime_prevent_linkdown(scn, flag); +} +#endif + +/** + * hif_bus_suspend_link_up() - suspend the bus + * + * Configures the pci irq line as a wakeup source. + * + * Return: 0 for success and non-zero for failure + */ +static int hif_bus_suspend_link_up(struct hif_softc *scn) +{ + struct pci_dev *pdev; + int status; + struct hif_pci_softc *sc = HIF_GET_PCI_SOFTC(scn); + + if (!sc) + return -EFAULT; + + pdev = sc->pdev; + + status = hif_drain_tasklets(scn); + if (status != 0) + return status; + + if (unlikely(enable_irq_wake(pdev->irq))) { + HIF_ERROR("%s: Fail to enable wake IRQ!", __func__); + return -EINVAL; + } + + hif_cancel_deferred_target_sleep(scn); + + return 0; +} + +/** + * hif_bus_resume_link_up() - hif bus resume API + * + * This function disables the wakeup source. + * + * Return: 0 for success and non-zero for failure + */ +static int hif_bus_resume_link_up(struct hif_softc *scn) +{ + struct pci_dev *pdev; + struct hif_pci_softc *sc = HIF_GET_PCI_SOFTC(scn); + + if (!sc) + return -EFAULT; + + pdev = sc->pdev; + + if (!pdev) { + HIF_ERROR("%s: pci_dev is null", __func__); + return -EFAULT; + } + + if (unlikely(disable_irq_wake(pdev->irq))) { + HIF_ERROR("%s: Fail to disable wake IRQ!", __func__); + return -EFAULT; + } + + return 0; +} + +/** + * hif_bus_suspend_link_down() - suspend the bus + * + * Suspends the hif layer taking care of draining recieve queues and + * shutting down copy engines if needed. Ensures opy engine interrupts + * are disabled when it returns. Prevents register access after it + * returns. + * + * Return: 0 for success and non-zero for failure + */ +static int hif_bus_suspend_link_down(struct hif_softc *scn) +{ + struct pci_dev *pdev; + struct hif_pci_softc *sc = HIF_GET_PCI_SOFTC(scn); + int status = 0; + + pdev = sc->pdev; + + disable_irq(pdev->irq); + + status = hif_drain_tasklets(scn); + if (status != 0) { + enable_irq(pdev->irq); + return status; + } + + /* Stop the HIF Sleep Timer */ + hif_cancel_deferred_target_sleep(scn); + + qdf_atomic_set(&scn->link_suspended, 1); + + return 0; +} + +/** + * hif_bus_resume_link_down() - hif bus resume API + * + * This function resumes the bus reenabling interupts. + * + * Return: 0 for success and non-zero for failure + */ +static int hif_bus_resume_link_down(struct hif_softc *scn) +{ + struct pci_dev *pdev; + struct hif_pci_softc *sc = HIF_GET_PCI_SOFTC(scn); + + if (!sc) + return -EFAULT; + + pdev = sc->pdev; + + if (!pdev) { + HIF_ERROR("%s: pci_dev is null", __func__); + return -EFAULT; + } + + qdf_atomic_set(&scn->link_suspended, 0); + + enable_irq(pdev->irq); + + return 0; +} + +/** + * hif_pci_suspend(): prepare hif for suspend + * + * chose suspend type based on link suspend voting. + * + * Return: 0 for success and non-zero error code for failure + */ +int hif_pci_bus_suspend(struct hif_softc *scn) +{ + if (hif_can_suspend_link(GET_HIF_OPAQUE_HDL(scn))) + return hif_bus_suspend_link_down(scn); + else + return hif_bus_suspend_link_up(scn); +} + +/** + * __hif_check_link_status() - API to check if PCIe link is active/not + * @scn: HIF Context + * + * API reads the PCIe config space to verify if PCIe link training is + * successful or not. + * + * Return: Success/Failure + */ +static int __hif_check_link_status(struct hif_softc *scn) +{ + uint16_t dev_id; + struct hif_pci_softc *sc = HIF_GET_PCI_SOFTC(scn); + struct hif_driver_state_callbacks *cbk = hif_get_callbacks_handle(scn); + + if (!sc) { + HIF_ERROR("%s: HIF Bus Context is Invalid", __func__); + return -EINVAL; + } + + pci_read_config_word(sc->pdev, PCI_DEVICE_ID, &dev_id); + + if (dev_id == sc->devid) + return 0; + + HIF_ERROR("%s: Invalid PCIe Config Space; PCIe link down dev_id:0x%04x", + __func__, dev_id); + + scn->recovery = true; + + if (cbk && cbk->set_recovery_in_progress) + cbk->set_recovery_in_progress(cbk->context, true); + else + HIF_ERROR("%s: Driver Global Recovery is not set", __func__); + + pld_is_pci_link_down(sc->dev); + return -EACCES; +} + +/** + * hif_bus_resume(): prepare hif for resume + * + * chose suspend type based on link suspend voting. + * + * Return: 0 for success and non-zero error code for failure + */ +int hif_pci_bus_resume(struct hif_softc *scn) +{ + int ret; + + ret = __hif_check_link_status(scn); + if (ret) + return ret; + + if (hif_can_suspend_link(GET_HIF_OPAQUE_HDL(scn))) + return hif_bus_resume_link_down(scn); + else + return hif_bus_resume_link_up(scn); +} + +#ifdef FEATURE_RUNTIME_PM +/** + * __hif_runtime_pm_set_state(): utility function + * @state: state to set + * + * indexes into the runtime pm state and sets it. + */ +static void __hif_runtime_pm_set_state(struct hif_softc *scn, + enum hif_pm_runtime_state state) +{ + struct hif_pci_softc *sc = HIF_GET_PCI_SOFTC(scn); + + if (NULL == sc) { + HIF_ERROR("%s: HIF_CTX not initialized", + __func__); + return; + } + + qdf_atomic_set(&sc->pm_state, state); +} + +/** + * hif_runtime_pm_set_state_inprogress(): adjust runtime pm state + * + * Notify hif that a runtime pm opperation has started + */ +static void hif_runtime_pm_set_state_inprogress(struct hif_softc *scn) +{ + __hif_runtime_pm_set_state(scn, HIF_PM_RUNTIME_STATE_INPROGRESS); +} + +/** + * hif_runtime_pm_set_state_on(): adjust runtime pm state + * + * Notify hif that a the runtime pm state should be on + */ +static void hif_runtime_pm_set_state_on(struct hif_softc *scn) +{ + __hif_runtime_pm_set_state(scn, HIF_PM_RUNTIME_STATE_ON); +} + +/** + * hif_runtime_pm_set_state_suspended(): adjust runtime pm state + * + * Notify hif that a runtime suspend attempt has been completed successfully + */ +static void hif_runtime_pm_set_state_suspended(struct hif_softc *scn) +{ + __hif_runtime_pm_set_state(scn, HIF_PM_RUNTIME_STATE_SUSPENDED); +} + +/** + * hif_log_runtime_suspend_success() - log a successful runtime suspend + */ +static void hif_log_runtime_suspend_success(struct hif_softc *hif_ctx) +{ + struct hif_pci_softc *sc = HIF_GET_PCI_SOFTC(hif_ctx); + if (sc == NULL) + return; + + sc->pm_stats.suspended++; + sc->pm_stats.suspend_jiffies = jiffies; +} + +/** + * hif_log_runtime_suspend_failure() - log a failed runtime suspend + * + * log a failed runtime suspend + * mark last busy to prevent immediate runtime suspend + */ +static void hif_log_runtime_suspend_failure(void *hif_ctx) +{ + struct hif_pci_softc *sc = HIF_GET_PCI_SOFTC(hif_ctx); + if (sc == NULL) + return; + + sc->pm_stats.suspend_err++; +} + +/** + * hif_log_runtime_resume_success() - log a successful runtime resume + * + * log a successfull runtime resume + * mark last busy to prevent immediate runtime suspend + */ +static void hif_log_runtime_resume_success(void *hif_ctx) +{ + struct hif_pci_softc *sc = HIF_GET_PCI_SOFTC(hif_ctx); + if (sc == NULL) + return; + + sc->pm_stats.resumed++; +} + +/** + * hif_process_runtime_suspend_failure() - bookkeeping of suspend failure + * + * Record the failure. + * mark last busy to delay a retry. + * adjust the runtime_pm state. + */ +void hif_process_runtime_suspend_failure(struct hif_opaque_softc *hif_ctx) +{ + struct hif_pci_softc *hif_pci_sc = HIF_GET_PCI_SOFTC(hif_ctx); + struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx); + + hif_log_runtime_suspend_failure(hif_ctx); + if (hif_pci_sc != NULL) + hif_pm_runtime_mark_last_busy(hif_pci_sc->dev); + hif_runtime_pm_set_state_on(scn); +} + +/** + * hif_pre_runtime_suspend() - bookkeeping before beginning runtime suspend + * + * Makes sure that the pci link will be taken down by the suspend opperation. + * If the hif layer is configured to leave the bus on, runtime suspend will + * not save any power. + * + * Set the runtime suspend state to in progress. + * + * return -EINVAL if the bus won't go down. otherwise return 0 + */ +int hif_pre_runtime_suspend(struct hif_opaque_softc *hif_ctx) +{ + struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx); + + if (!hif_can_suspend_link(hif_ctx)) { + HIF_ERROR("Runtime PM not supported for link up suspend"); + return -EINVAL; + } + + hif_runtime_pm_set_state_inprogress(scn); + return 0; +} + +/** + * hif_process_runtime_suspend_success() - bookkeeping of suspend success + * + * Record the success. + * adjust the runtime_pm state + */ +void hif_process_runtime_suspend_success(struct hif_opaque_softc *hif_ctx) +{ + struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx); + + hif_runtime_pm_set_state_suspended(scn); + hif_log_runtime_suspend_success(scn); +} + +/** + * hif_pre_runtime_resume() - bookkeeping before beginning runtime resume + * + * update the runtime pm state. + */ +void hif_pre_runtime_resume(struct hif_opaque_softc *hif_ctx) +{ + struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx); + + hif_runtime_pm_set_state_inprogress(scn); +} + +/** + * hif_process_runtime_resume_success() - bookkeeping after a runtime resume + * + * record the success. + * adjust the runtime_pm state + */ +void hif_process_runtime_resume_success(struct hif_opaque_softc *hif_ctx) +{ + struct hif_pci_softc *hif_pci_sc = HIF_GET_PCI_SOFTC(hif_ctx); + struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx); + + hif_log_runtime_resume_success(hif_ctx); + if (hif_pci_sc != NULL) + hif_pm_runtime_mark_last_busy(hif_pci_sc->dev); + hif_runtime_pm_set_state_on(scn); +} + +/** + * hif_runtime_suspend() - do the bus suspend part of a runtime suspend + * + * Return: 0 for success and non-zero error code for failure + */ +int hif_runtime_suspend(struct hif_opaque_softc *hif_ctx) +{ + return hif_pci_bus_suspend(HIF_GET_SOFTC(hif_ctx)); +} + +#ifdef WLAN_FEATURE_FASTPATH +/** + * hif_fastpath_resume() - resume fastpath for runtimepm + * + * ensure that the fastpath write index register is up to date + * since runtime pm may cause ce_send_fast to skip the register + * write. + */ +static void hif_fastpath_resume(struct hif_opaque_softc *hif_ctx) +{ + struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx); + struct CE_state *ce_state; + + if (!scn) + return; + + if (scn->fastpath_mode_on) { + if (Q_TARGET_ACCESS_BEGIN(scn) < 0) + return; + + ce_state = scn->ce_id_to_state[CE_HTT_H2T_MSG]; + qdf_spin_lock_bh(&ce_state->ce_index_lock); + + /*war_ce_src_ring_write_idx_set */ + CE_SRC_RING_WRITE_IDX_SET(scn, ce_state->ctrl_addr, + ce_state->src_ring->write_index); + qdf_spin_unlock_bh(&ce_state->ce_index_lock); + Q_TARGET_ACCESS_END(scn); + } +} +#else +static void hif_fastpath_resume(struct hif_opaque_softc *hif_ctx) {} +#endif + + +/** + * hif_runtime_resume() - do the bus resume part of a runtime resume + * + * Return: 0 for success and non-zero error code for failure + */ +int hif_runtime_resume(struct hif_opaque_softc *hif_ctx) +{ + int status = hif_pci_bus_resume(HIF_GET_SOFTC(hif_ctx)); + + hif_fastpath_resume(hif_ctx); + + return status; +} +#endif /* #ifdef FEATURE_RUNTIME_PM */ + +#if CONFIG_PCIE_64BIT_MSI +static void hif_free_msi_ctx(struct hif_softc *scn) +{ + struct hif_pci_softc *sc = scn->hif_sc; + struct hif_msi_info *info = &sc->msi_info; + struct device *dev = scn->qdf_dev->dev; + + OS_FREE_CONSISTENT(dev, 4, info->magic, info->magic_dma, + OS_GET_DMA_MEM_CONTEXT(scn, dmacontext)); + info->magic = NULL; + info->magic_dma = 0; +} +#else +static void hif_free_msi_ctx(struct hif_softc *scn) +{ +} +#endif + +void hif_pci_disable_isr(struct hif_softc *scn) +{ + struct hif_pci_softc *sc = HIF_GET_PCI_SOFTC(scn); + + hif_nointrs(scn); + hif_free_msi_ctx(scn); + /* Cancel the pending tasklet */ + ce_tasklet_kill(scn); + tasklet_kill(&sc->intr_tq); + qdf_atomic_set(&scn->active_tasklet_cnt, 0); +} + +/* Function to reset SoC */ +void hif_pci_reset_soc(struct hif_softc *hif_sc) +{ + struct hif_pci_softc *sc = HIF_GET_PCI_SOFTC(hif_sc); + struct hif_opaque_softc *ol_sc = GET_HIF_OPAQUE_HDL(hif_sc); + struct hif_target_info *tgt_info = hif_get_target_info_handle(ol_sc); + +#if defined(CPU_WARM_RESET_WAR) + /* Currently CPU warm reset sequence is tested only for AR9888_REV2 + * Need to enable for AR9888_REV1 once CPU warm reset sequence is + * verified for AR9888_REV1 + */ + if (tgt_info->target_version == AR9888_REV2_VERSION) + hif_pci_device_warm_reset(sc); + else + hif_pci_device_reset(sc); +#else + hif_pci_device_reset(sc); +#endif +} + +#ifdef CONFIG_PCI_MSM +static inline void hif_msm_pcie_debug_info(struct hif_pci_softc *sc) +{ + msm_pcie_debug_info(sc->pdev, 13, 1, 0, 0, 0); + msm_pcie_debug_info(sc->pdev, 13, 2, 0, 0, 0); +} +#else +static inline void hif_msm_pcie_debug_info(struct hif_pci_softc *sc) {}; +#endif + +/** + * hif_log_soc_wakeup_timeout() - API to log PCIe and SOC Info + * @sc: HIF PCIe Context + * + * API to log PCIe Config space and SOC info when SOC wakeup timeout happens + * + * Return: Failure to caller + */ +static int hif_log_soc_wakeup_timeout(struct hif_pci_softc *sc) +{ + uint16_t val; + uint32_t bar; + struct hif_opaque_softc *hif_hdl = GET_HIF_OPAQUE_HDL(sc); + struct hif_softc *scn = HIF_GET_SOFTC(sc); + struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(sc); + struct hif_config_info *cfg = hif_get_ini_handle(hif_hdl); + struct hif_driver_state_callbacks *cbk = hif_get_callbacks_handle(scn); + A_target_id_t pci_addr = scn->mem; + + HIF_ERROR("%s: keep_awake_count = %d", + __func__, hif_state->keep_awake_count); + + pci_read_config_word(sc->pdev, PCI_VENDOR_ID, &val); + + HIF_ERROR("%s: PCI Vendor ID = 0x%04x", __func__, val); + + pci_read_config_word(sc->pdev, PCI_DEVICE_ID, &val); + + HIF_ERROR("%s: PCI Device ID = 0x%04x", __func__, val); + + pci_read_config_word(sc->pdev, PCI_COMMAND, &val); + + HIF_ERROR("%s: PCI Command = 0x%04x", __func__, val); + + pci_read_config_word(sc->pdev, PCI_STATUS, &val); + + HIF_ERROR("%s: PCI Status = 0x%04x", __func__, val); + + pci_read_config_dword(sc->pdev, PCI_BASE_ADDRESS_0, &bar); + + HIF_ERROR("%s: PCI BAR 0 = 0x%08x", __func__, bar); + + HIF_ERROR("%s: SOC_WAKE_ADDR 0%08x", __func__, + hif_read32_mb(pci_addr + PCIE_LOCAL_BASE_ADDRESS + + PCIE_SOC_WAKE_ADDRESS)); + + HIF_ERROR("%s: RTC_STATE_ADDR 0x%08x", __func__, + hif_read32_mb(pci_addr + PCIE_LOCAL_BASE_ADDRESS + + RTC_STATE_ADDRESS)); + + HIF_ERROR("%s:error, wakeup target", __func__); + hif_msm_pcie_debug_info(sc); + + if (!cfg->enable_self_recovery) + QDF_BUG(0); + + scn->recovery = true; + + if (cbk->set_recovery_in_progress) + cbk->set_recovery_in_progress(cbk->context, true); + + pld_is_pci_link_down(sc->dev); + return -EACCES; +} + +/* + * For now, we use simple on-demand sleep/wake. + * Some possible improvements: + * -Use the Host-destined A_INUM_PCIE_AWAKE interrupt rather than spin/delay + * (or perhaps spin/delay for a short while, then convert to sleep/interrupt) + * Careful, though, these functions may be used by + * interrupt handlers ("atomic") + * -Don't use host_reg_table for this code; instead use values directly + * -Use a separate timer to track activity and allow Target to sleep only + * if it hasn't done anything for a while; may even want to delay some + * processing for a short while in order to "batch" (e.g.) transmit + * requests with completion processing into "windows of up time". Costs + * some performance, but improves power utilization. + * -On some platforms, it might be possible to eliminate explicit + * sleep/wakeup. Instead, take a chance that each access works OK. If not, + * recover from the failure by forcing the Target awake. + * -Change keep_awake_count to an atomic_t in order to avoid spin lock + * overhead in some cases. Perhaps this makes more sense when + * CONFIG_ATH_PCIE_ACCESS_LIKELY is used and less sense when LIKELY is + * disabled. + * -It is possible to compile this code out and simply force the Target + * to remain awake. That would yield optimal performance at the cost of + * increased power. See CONFIG_ATH_PCIE_MAX_PERF. + * + * Note: parameter wait_for_it has meaning only when waking (when sleep_ok==0). + */ +/** + * hif_target_sleep_state_adjust() - on-demand sleep/wake + * @scn: hif_softc pointer. + * @sleep_ok: bool + * @wait_for_it: bool + * + * Output the pipe error counts of each pipe to log file + * + * Return: int + */ +int hif_pci_target_sleep_state_adjust(struct hif_softc *scn, + bool sleep_ok, bool wait_for_it) +{ + struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(scn); + A_target_id_t pci_addr = scn->mem; + static int max_delay; + struct hif_pci_softc *sc = HIF_GET_PCI_SOFTC(scn); + static int debug; + + if (scn->recovery) + return -EACCES; + + if (qdf_atomic_read(&scn->link_suspended)) { + HIF_ERROR("%s:invalid access, PCIe link is down", __func__); + debug = true; + QDF_ASSERT(0); + return -EACCES; + } + + if (debug) { + wait_for_it = true; + HIF_ERROR("%s: doing debug for invalid access, PCIe link is suspended", + __func__); + QDF_ASSERT(0); + } + + if (sleep_ok) { + qdf_spin_lock_irqsave(&hif_state->keep_awake_lock); + hif_state->keep_awake_count--; + if (hif_state->keep_awake_count == 0) { + /* Allow sleep */ + hif_state->verified_awake = false; + hif_state->sleep_ticks = qdf_system_ticks(); + } + if (hif_state->fake_sleep == false) { + /* Set the Fake Sleep */ + hif_state->fake_sleep = true; + + /* Start the Sleep Timer */ + qdf_timer_stop(&hif_state->sleep_timer); + qdf_timer_start(&hif_state->sleep_timer, + HIF_SLEEP_INACTIVITY_TIMER_PERIOD_MS); + } + qdf_spin_unlock_irqrestore(&hif_state->keep_awake_lock); + } else { + qdf_spin_lock_irqsave(&hif_state->keep_awake_lock); + + if (hif_state->fake_sleep) { + hif_state->verified_awake = true; + } else { + if (hif_state->keep_awake_count == 0) { + /* Force AWAKE */ + hif_write32_mb(pci_addr + + PCIE_LOCAL_BASE_ADDRESS + + PCIE_SOC_WAKE_ADDRESS, + PCIE_SOC_WAKE_V_MASK); + } + } + hif_state->keep_awake_count++; + qdf_spin_unlock_irqrestore(&hif_state->keep_awake_lock); + + if (wait_for_it && !hif_state->verified_awake) { +#define PCIE_SLEEP_ADJUST_TIMEOUT 8000 /* 8Ms */ + int tot_delay = 0; + int curr_delay = 5; + + for (;; ) { + if (hif_targ_is_awake(scn, pci_addr)) { + hif_state->verified_awake = true; + break; + } else + if (!hif_pci_targ_is_present + (scn, pci_addr)) { + break; + } + + if (tot_delay > PCIE_SLEEP_ADJUST_TIMEOUT) + return hif_log_soc_wakeup_timeout(sc); + + OS_DELAY(curr_delay); + tot_delay += curr_delay; + + if (curr_delay < 50) + curr_delay += 5; + } + + /* + * NB: If Target has to come out of Deep Sleep, + * this may take a few Msecs. Typically, though + * this delay should be <30us. + */ + if (tot_delay > max_delay) + max_delay = tot_delay; + } + } + + if (debug && hif_state->verified_awake) { + debug = 0; + HIF_ERROR("%s: INTR_ENABLE_REG = 0x%08x, INTR_CAUSE_REG = 0x%08x, CPU_INTR_REG = 0x%08x, INTR_CLR_REG = 0x%08x, CE_INTERRUPT_SUMMARY_REG = 0x%08x", + __func__, + hif_read32_mb(sc->mem + SOC_CORE_BASE_ADDRESS + + PCIE_INTR_ENABLE_ADDRESS), + hif_read32_mb(sc->mem + SOC_CORE_BASE_ADDRESS + + PCIE_INTR_CAUSE_ADDRESS), + hif_read32_mb(sc->mem + SOC_CORE_BASE_ADDRESS + + CPU_INTR_ADDRESS), + hif_read32_mb(sc->mem + SOC_CORE_BASE_ADDRESS + + PCIE_INTR_CLR_ADDRESS), + hif_read32_mb(sc->mem + CE_WRAPPER_BASE_ADDRESS + + CE_WRAPPER_INTERRUPT_SUMMARY_ADDRESS)); + } + + return 0; +} + +#ifdef CONFIG_ATH_PCIE_ACCESS_DEBUG +uint32_t hif_target_read_checked(struct hif_softc *scn, uint32_t offset) +{ + uint32_t value; + void *addr; + + addr = scn->mem + offset; + value = hif_read32_mb(addr); + + { + unsigned long irq_flags; + int idx = pcie_access_log_seqnum % PCIE_ACCESS_LOG_NUM; + + spin_lock_irqsave(&pcie_access_log_lock, irq_flags); + pcie_access_log[idx].seqnum = pcie_access_log_seqnum; + pcie_access_log[idx].is_write = false; + pcie_access_log[idx].addr = addr; + pcie_access_log[idx].value = value; + pcie_access_log_seqnum++; + spin_unlock_irqrestore(&pcie_access_log_lock, irq_flags); + } + + return value; +} + +void +hif_target_write_checked(struct hif_softc *scn, uint32_t offset, uint32_t value) +{ + void *addr; + + addr = scn->mem + (offset); + hif_write32_mb(addr, value); + + { + unsigned long irq_flags; + int idx = pcie_access_log_seqnum % PCIE_ACCESS_LOG_NUM; + + spin_lock_irqsave(&pcie_access_log_lock, irq_flags); + pcie_access_log[idx].seqnum = pcie_access_log_seqnum; + pcie_access_log[idx].is_write = true; + pcie_access_log[idx].addr = addr; + pcie_access_log[idx].value = value; + pcie_access_log_seqnum++; + spin_unlock_irqrestore(&pcie_access_log_lock, irq_flags); + } +} + +/** + * hif_target_dump_access_log() - dump access log + * + * dump access log + * + * Return: n/a + */ +void hif_target_dump_access_log(void) +{ + int idx, len, start_idx, cur_idx; + unsigned long irq_flags; + + spin_lock_irqsave(&pcie_access_log_lock, irq_flags); + if (pcie_access_log_seqnum > PCIE_ACCESS_LOG_NUM) { + len = PCIE_ACCESS_LOG_NUM; + start_idx = pcie_access_log_seqnum % PCIE_ACCESS_LOG_NUM; + } else { + len = pcie_access_log_seqnum; + start_idx = 0; + } + + for (idx = 0; idx < len; idx++) { + cur_idx = (start_idx + idx) % PCIE_ACCESS_LOG_NUM; + HIF_ERROR("%s: idx:%d sn:%u wr:%d addr:%p val:%u.", + __func__, idx, + pcie_access_log[cur_idx].seqnum, + pcie_access_log[cur_idx].is_write, + pcie_access_log[cur_idx].addr, + pcie_access_log[cur_idx].value); + } + + pcie_access_log_seqnum = 0; + spin_unlock_irqrestore(&pcie_access_log_lock, irq_flags); +} +#endif + +#ifndef HIF_AHB +int hif_ahb_configure_legacy_irq(struct hif_pci_softc *sc) +{ + QDF_BUG(0); + return -EINVAL; +} +#endif + +/** + * hif_configure_irq() - configure interrupt + * + * This function configures interrupt(s) + * + * @sc: PCIe control struct + * @hif_hdl: struct HIF_CE_state + * + * Return: 0 - for success + */ +int hif_configure_irq(struct hif_softc *scn) +{ + int ret = 0; + struct hif_pci_softc *sc = HIF_GET_PCI_SOFTC(scn); + + HIF_TRACE("%s: E", __func__); + + hif_init_reschedule_tasklet_work(sc); + + if (ENABLE_MSI) { + ret = hif_configure_msi(sc); + if (ret == 0) + goto end; + } + /* MSI failed. Try legacy irq */ + switch (scn->target_info.target_type) { + case TARGET_TYPE_IPQ4019: + ret = hif_ahb_configure_legacy_irq(sc); + break; + default: + ret = hif_pci_configure_legacy_irq(sc); + break; + } + if (ret < 0) { + HIF_ERROR("%s: hif_pci_configure_legacy_irq error = %d", + __func__, ret); + return ret; + } +end: + scn->request_irq_done = true; + return 0; +} + +/** + * hif_target_sync() : ensure the target is ready + * @scn: hif controll structure + * + * Informs fw that we plan to use legacy interupts so that + * it can begin booting. Ensures that the fw finishes booting + * before continuing. Should be called before trying to write + * to the targets other registers for the first time. + * + * Return: none + */ +static void hif_target_sync(struct hif_softc *scn) +{ + hif_write32_mb(scn->mem+(SOC_CORE_BASE_ADDRESS | + PCIE_INTR_ENABLE_ADDRESS), + PCIE_INTR_FIRMWARE_MASK); + + hif_write32_mb(scn->mem + PCIE_LOCAL_BASE_ADDRESS + + PCIE_SOC_WAKE_ADDRESS, + PCIE_SOC_WAKE_V_MASK); + while (!hif_targ_is_awake(scn, scn->mem)) + ; + + if (HAS_FW_INDICATOR) { + int wait_limit = 500; + int fw_ind = 0; + HIF_TRACE("%s: Loop checking FW signal", __func__); + while (1) { + fw_ind = hif_read32_mb(scn->mem + + FW_INDICATOR_ADDRESS); + if (fw_ind & FW_IND_INITIALIZED) + break; + if (wait_limit-- < 0) + break; + hif_write32_mb(scn->mem+(SOC_CORE_BASE_ADDRESS | + PCIE_INTR_ENABLE_ADDRESS), + PCIE_INTR_FIRMWARE_MASK); + + qdf_mdelay(10); + } + if (wait_limit < 0) + HIF_TRACE("%s: FW signal timed out", + __func__); + else + HIF_TRACE("%s: Got FW signal, retries = %x", + __func__, 500-wait_limit); + } + hif_write32_mb(scn->mem + PCIE_LOCAL_BASE_ADDRESS + + PCIE_SOC_WAKE_ADDRESS, PCIE_SOC_WAKE_RESET); +} + +/** + * hif_enable_bus(): enable bus + * + * This function enables the bus + * + * @ol_sc: soft_sc struct + * @dev: device pointer + * @bdev: bus dev pointer + * bid: bus id pointer + * type: enum hif_enable_type such as HIF_ENABLE_TYPE_PROBE + * Return: QDF_STATUS + */ +QDF_STATUS hif_pci_enable_bus(struct hif_softc *ol_sc, + struct device *dev, void *bdev, + const hif_bus_id *bid, + enum hif_enable_type type) +{ + int ret = 0; + uint32_t hif_type, target_type; + struct hif_pci_softc *sc = HIF_GET_PCI_SOFTC(ol_sc); + struct hif_opaque_softc *hif_hdl = GET_HIF_OPAQUE_HDL(ol_sc); + uint16_t revision_id; + int probe_again = 0; + struct pci_dev *pdev = bdev; + const struct pci_device_id *id = (const struct pci_device_id *)bid; + struct hif_target_info *tgt_info; + + if (!ol_sc) { + HIF_ERROR("%s: hif_ctx is NULL", __func__); + return QDF_STATUS_E_NOMEM; + } + + HIF_TRACE("%s: con_mode = 0x%x, device_id = 0x%x", + __func__, hif_get_conparam(ol_sc), id->device); + + sc->pdev = pdev; + sc->dev = &pdev->dev; + sc->devid = id->device; + sc->cacheline_sz = dma_get_cache_alignment(); + tgt_info = hif_get_target_info_handle(hif_hdl); +again: + ret = hif_enable_pci(sc, pdev, id); + if (ret < 0) { + HIF_ERROR("%s: ERROR - hif_enable_pci error = %d", + __func__, ret); + goto err_enable_pci; + } + HIF_TRACE("%s: hif_enable_pci done", __func__); + + /* Temporary FIX: disable ASPM on peregrine. + * Will be removed after the OTP is programmed + */ + hif_disable_power_gating(hif_hdl); + + device_disable_async_suspend(&pdev->dev); + pci_read_config_word(pdev, 0x08, &revision_id); + + ret = hif_get_device_type(id->device, revision_id, + &hif_type, &target_type); + if (ret < 0) { + HIF_ERROR("%s: invalid device id/revision_id", __func__); + goto err_tgtstate; + } + HIF_TRACE("%s: hif_type = 0x%x, target_type = 0x%x", + __func__, hif_type, target_type); + + hif_register_tbl_attach(ol_sc, hif_type); + hif_target_register_tbl_attach(ol_sc, target_type); + + ret = hif_pci_probe_tgt_wakeup(sc); + if (ret < 0) { + HIF_ERROR("%s: ERROR - hif_pci_prob_wakeup error = %d", + __func__, ret); + if (ret == -EAGAIN) + probe_again++; + goto err_tgtstate; + } + HIF_TRACE("%s: hif_pci_probe_tgt_wakeup done", __func__); + + tgt_info->target_type = target_type; + + sc->soc_pcie_bar0 = pci_resource_start(pdev, BAR_NUM); + if (!sc->soc_pcie_bar0) { + HIF_ERROR("%s: ERROR - cannot get CE BAR0", __func__); + ret = -EIO; + goto err_tgtstate; + } + ol_sc->mem_pa = sc->soc_pcie_bar0; + + hif_target_sync(ol_sc); + + if (ADRASTEA_BU) + hif_vote_link_up(hif_hdl); + + return 0; + +err_tgtstate: + hif_disable_pci(sc); + sc->pci_enabled = false; + HIF_ERROR("%s: error, hif_disable_pci done", __func__); + return QDF_STATUS_E_ABORTED; + +err_enable_pci: + if (probe_again && (probe_again <= ATH_PCI_PROBE_RETRY_MAX)) { + int delay_time; + + HIF_INFO("%s: pci reprobe", __func__); + /* 10, 40, 90, 100, 100, ... */ + delay_time = max(100, 10 * (probe_again * probe_again)); + qdf_mdelay(delay_time); + goto again; + } + return ret; +} + +/** + * hif_pci_irq_enable() - ce_irq_enable + * @scn: hif_softc + * @ce_id: ce_id + * + * Return: void + */ +void hif_pci_irq_enable(struct hif_softc *scn, int ce_id) +{ + uint32_t tmp = 1 << ce_id; + struct hif_pci_softc *sc = HIF_GET_PCI_SOFTC(scn); + + qdf_spin_lock_irqsave(&sc->irq_lock); + scn->ce_irq_summary &= ~tmp; + if (scn->ce_irq_summary == 0) { + /* Enable Legacy PCI line interrupts */ + if (LEGACY_INTERRUPTS(sc) && + (scn->target_status != TARGET_STATUS_RESET) && + (!qdf_atomic_read(&scn->link_suspended))) { + + hif_write32_mb(scn->mem + + (SOC_CORE_BASE_ADDRESS | + PCIE_INTR_ENABLE_ADDRESS), + HOST_GROUP0_MASK); + + hif_read32_mb(scn->mem + + (SOC_CORE_BASE_ADDRESS | + PCIE_INTR_ENABLE_ADDRESS)); + } + } + if (scn->hif_init_done == true) + Q_TARGET_ACCESS_END(scn); + qdf_spin_unlock_irqrestore(&sc->irq_lock); + + /* check for missed firmware crash */ + hif_fw_interrupt_handler(0, scn); +} +/** + * hif_pci_irq_disable() - ce_irq_disable + * @scn: hif_softc + * @ce_id: ce_id + * + * Return: void + */ +void hif_pci_irq_disable(struct hif_softc *scn, int ce_id) +{ + /* For Rome only need to wake up target */ + /* target access is maintained untill interrupts are re-enabled */ + Q_TARGET_ACCESS_BEGIN(scn); +} + +#ifdef FEATURE_RUNTIME_PM + +void hif_pm_runtime_get_noresume(struct hif_opaque_softc *hif_ctx) +{ + struct hif_pci_softc *sc = HIF_GET_PCI_SOFTC(hif_ctx); + + if (NULL == sc) + return; + + sc->pm_stats.runtime_get++; + pm_runtime_get_noresume(sc->dev); +} + +/** + * hif_pm_runtime_get() - do a get opperation on the device + * + * A get opperation will prevent a runtime suspend untill a + * corresponding put is done. This api should be used when sending + * data. + * + * CONTRARY TO THE REGULAR RUNTIME PM, WHEN THE BUS IS SUSPENDED, + * THIS API WILL ONLY REQUEST THE RESUME AND NOT TO A GET!!! + * + * return: success if the bus is up and a get has been issued + * otherwise an error code. + */ +int hif_pm_runtime_get(struct hif_opaque_softc *hif_ctx) +{ + struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx); + struct hif_pci_softc *sc = HIF_GET_PCI_SOFTC(hif_ctx); + int ret; + int pm_state; + + if (NULL == scn) { + HIF_ERROR("%s: Could not do runtime get, scn is null", + __func__); + return -EFAULT; + } + + pm_state = qdf_atomic_read(&sc->pm_state); + + if (pm_state == HIF_PM_RUNTIME_STATE_ON || + pm_state == HIF_PM_RUNTIME_STATE_NONE) { + sc->pm_stats.runtime_get++; + ret = __hif_pm_runtime_get(sc->dev); + + /* Get can return 1 if the device is already active, just return + * success in that case + */ + if (ret > 0) + ret = 0; + + if (ret) + hif_pm_runtime_put(hif_ctx); + + if (ret && ret != -EINPROGRESS) { + sc->pm_stats.runtime_get_err++; + HIF_ERROR("%s: Runtime Get PM Error in pm_state:%d ret: %d", + __func__, qdf_atomic_read(&sc->pm_state), ret); + } + + return ret; + } + + sc->pm_stats.request_resume++; + sc->pm_stats.last_resume_caller = (void *)_RET_IP_; + ret = hif_pm_request_resume(sc->dev); + + return -EAGAIN; +} + +/** + * hif_pm_runtime_put() - do a put opperation on the device + * + * A put opperation will allow a runtime suspend after a corresponding + * get was done. This api should be used when sending data. + * + * This api will return a failure if runtime pm is stopped + * This api will return failure if it would decrement the usage count below 0. + * + * return: QDF_STATUS_SUCCESS if the put is performed + */ +int hif_pm_runtime_put(struct hif_opaque_softc *hif_ctx) +{ + struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx); + struct hif_pci_softc *sc = HIF_GET_PCI_SOFTC(hif_ctx); + int pm_state, usage_count; + char *error = NULL; + + if (NULL == scn) { + HIF_ERROR("%s: Could not do runtime put, scn is null", + __func__); + return -EFAULT; + } + usage_count = atomic_read(&sc->dev->power.usage_count); + + if (usage_count == 1) { + pm_state = qdf_atomic_read(&sc->pm_state); + + if (pm_state == HIF_PM_RUNTIME_STATE_NONE) + error = "Ignoring unexpected put when runtime pm is disabled"; + + } else if (usage_count == 0) { + error = "PUT Without a Get Operation"; + } + + if (error) { + hif_pci_runtime_pm_warn(sc, error); + return -EINVAL; + } + + sc->pm_stats.runtime_put++; + + hif_pm_runtime_mark_last_busy(sc->dev); + hif_pm_runtime_put_auto(sc->dev); + + return 0; +} + + +/** + * __hif_pm_runtime_prevent_suspend() - prevent runtime suspend for a protocol reason + * @hif_sc: pci context + * @lock: runtime_pm lock being acquired + * + * Return 0 if successful. + */ +static int __hif_pm_runtime_prevent_suspend(struct hif_pci_softc + *hif_sc, struct hif_pm_runtime_lock *lock) +{ + int ret = 0; + + /* + * We shouldn't be setting context->timeout to zero here when + * context is active as we will have a case where Timeout API's + * for the same context called back to back. + * eg: echo "1=T:10:T:20" > /d/cnss_runtime_pm + * Set context->timeout to zero in hif_pm_runtime_prevent_suspend + * API to ensure the timeout version is no more active and + * list entry of this context will be deleted during allow suspend. + */ + if (lock->active) + return 0; + + ret = __hif_pm_runtime_get(hif_sc->dev); + + /** + * The ret can be -EINPROGRESS, if Runtime status is RPM_RESUMING or + * RPM_SUSPENDING. Any other negative value is an error. + * We shouldn't be do runtime_put here as in later point allow + * suspend gets called with the the context and there the usage count + * is decremented, so suspend will be prevented. + */ + + if (ret < 0 && ret != -EINPROGRESS) { + hif_sc->pm_stats.runtime_get_err++; + hif_pci_runtime_pm_warn(hif_sc, + "Prevent Suspend Runtime PM Error"); + } + + hif_sc->prevent_suspend_cnt++; + + lock->active = true; + + list_add_tail(&lock->list, &hif_sc->prevent_suspend_list); + + hif_sc->pm_stats.prevent_suspend++; + + HIF_ERROR("%s: in pm_state:%s ret: %d", __func__, + hif_pm_runtime_state_to_string( + qdf_atomic_read(&hif_sc->pm_state)), + ret); + + return ret; +} + +static int __hif_pm_runtime_allow_suspend(struct hif_pci_softc *hif_sc, + struct hif_pm_runtime_lock *lock) +{ + int ret = 0; + int usage_count; + + if (hif_sc->prevent_suspend_cnt == 0) + return ret; + + if (!lock->active) + return ret; + + usage_count = atomic_read(&hif_sc->dev->power.usage_count); + + /* + * During Driver unload, platform driver increments the usage + * count to prevent any runtime suspend getting called. + * So during driver load in HIF_PM_RUNTIME_STATE_NONE state the + * usage_count should be one. Ideally this shouldn't happen as + * context->active should be active for allow suspend to happen + * Handling this case here to prevent any failures. + */ + if ((qdf_atomic_read(&hif_sc->pm_state) == HIF_PM_RUNTIME_STATE_NONE + && usage_count == 1) || usage_count == 0) { + hif_pci_runtime_pm_warn(hif_sc, + "Allow without a prevent suspend"); + return -EINVAL; + } + + list_del(&lock->list); + + hif_sc->prevent_suspend_cnt--; + + lock->active = false; + lock->timeout = 0; + + hif_pm_runtime_mark_last_busy(hif_sc->dev); + ret = hif_pm_runtime_put_auto(hif_sc->dev); + + HIF_ERROR("%s: in pm_state:%s ret: %d", __func__, + hif_pm_runtime_state_to_string( + qdf_atomic_read(&hif_sc->pm_state)), + ret); + + hif_sc->pm_stats.allow_suspend++; + return ret; +} + +/** + * hif_pm_runtime_lock_timeout_fn() - callback the runtime lock timeout + * @data: calback data that is the pci context + * + * if runtime locks are aquired with a timeout, this function releases + * the locks when the last runtime lock expires. + * + * dummy implementation until lock acquisition is implemented. + */ +static void hif_pm_runtime_lock_timeout_fn(unsigned long data) +{ + struct hif_pci_softc *hif_sc = (struct hif_pci_softc *)data; + unsigned long timer_expires; + struct hif_pm_runtime_lock *context, *temp; + + spin_lock_bh(&hif_sc->runtime_lock); + + timer_expires = hif_sc->runtime_timer_expires; + + /* Make sure we are not called too early, this should take care of + * following case + * + * CPU0 CPU1 (timeout function) + * ---- ---------------------- + * spin_lock_irq + * timeout function called + * + * mod_timer() + * + * spin_unlock_irq + * spin_lock_irq + */ + if (timer_expires > 0 && !time_after(timer_expires, jiffies)) { + hif_sc->runtime_timer_expires = 0; + list_for_each_entry_safe(context, temp, + &hif_sc->prevent_suspend_list, list) { + if (context->timeout) { + __hif_pm_runtime_allow_suspend(hif_sc, context); + hif_sc->pm_stats.allow_suspend_timeout++; + } + } + } + + spin_unlock_bh(&hif_sc->runtime_lock); +} + +int hif_pm_runtime_prevent_suspend(struct hif_opaque_softc *ol_sc, + struct hif_pm_runtime_lock *data) +{ + struct hif_softc *sc = HIF_GET_SOFTC(ol_sc); + struct hif_pci_softc *hif_sc = HIF_GET_PCI_SOFTC(ol_sc); + struct hif_pm_runtime_lock *context = data; + + if (!sc->hif_config.enable_runtime_pm) + return 0; + + if (!context) + return -EINVAL; + + if (in_irq()) + WARN_ON(1); + + spin_lock_bh(&hif_sc->runtime_lock); + context->timeout = 0; + __hif_pm_runtime_prevent_suspend(hif_sc, context); + spin_unlock_bh(&hif_sc->runtime_lock); + + return 0; +} + +int hif_pm_runtime_allow_suspend(struct hif_opaque_softc *ol_sc, + struct hif_pm_runtime_lock *data) +{ + struct hif_softc *sc = HIF_GET_SOFTC(ol_sc); + struct hif_pci_softc *hif_sc = HIF_GET_PCI_SOFTC(ol_sc); + struct hif_pm_runtime_lock *context = data; + + if (!sc->hif_config.enable_runtime_pm) + return 0; + + if (!context) + return -EINVAL; + + if (in_irq()) + WARN_ON(1); + + spin_lock_bh(&hif_sc->runtime_lock); + + __hif_pm_runtime_allow_suspend(hif_sc, context); + + /* The list can be empty as well in cases where + * we have one context in the list and the allow + * suspend came before the timer expires and we delete + * context above from the list. + * When list is empty prevent_suspend count will be zero. + */ + if (hif_sc->prevent_suspend_cnt == 0 && + hif_sc->runtime_timer_expires > 0) { + del_timer(&hif_sc->runtime_timer); + hif_sc->runtime_timer_expires = 0; + } + + spin_unlock_bh(&hif_sc->runtime_lock); + + return 0; +} + +/** + * hif_pm_runtime_prevent_suspend_timeout() - Prevent runtime suspend timeout + * @ol_sc: HIF context + * @lock: which lock is being acquired + * @delay: Timeout in milliseconds + * + * Prevent runtime suspend with a timeout after which runtime suspend would be + * allowed. This API uses a single timer to allow the suspend and timer is + * modified if the timeout is changed before timer fires. + * If the timeout is less than autosuspend_delay then use mark_last_busy instead + * of starting the timer. + * + * It is wise to try not to use this API and correct the design if possible. + * + * Return: 0 on success and negative error code on failure + */ +int hif_pm_runtime_prevent_suspend_timeout(struct hif_opaque_softc *ol_sc, + struct hif_pm_runtime_lock *lock, unsigned int delay) +{ + struct hif_softc *sc = HIF_GET_SOFTC(ol_sc); + struct hif_pci_softc *hif_sc = HIF_GET_PCI_SOFTC(sc); + + int ret = 0; + unsigned long expires; + struct hif_pm_runtime_lock *context = lock; + + if (hif_is_load_or_unload_in_progress(sc)) { + HIF_ERROR("%s: Load/unload in progress, ignore!", + __func__); + return -EINVAL; + } + + if (hif_is_recovery_in_progress(sc)) { + HIF_ERROR("%s: LOGP in progress, ignore!", __func__); + return -EINVAL; + } + + if (!sc->hif_config.enable_runtime_pm) + return 0; + + if (!context) + return -EINVAL; + + if (in_irq()) + WARN_ON(1); + + /* + * Don't use internal timer if the timeout is less than auto suspend + * delay. + */ + if (delay <= hif_sc->dev->power.autosuspend_delay) { + hif_pm_request_resume(hif_sc->dev); + hif_pm_runtime_mark_last_busy(hif_sc->dev); + return ret; + } + + expires = jiffies + msecs_to_jiffies(delay); + expires += !expires; + + spin_lock_bh(&hif_sc->runtime_lock); + + context->timeout = delay; + ret = __hif_pm_runtime_prevent_suspend(hif_sc, context); + hif_sc->pm_stats.prevent_suspend_timeout++; + + /* Modify the timer only if new timeout is after already configured + * timeout + */ + if (time_after(expires, hif_sc->runtime_timer_expires)) { + mod_timer(&hif_sc->runtime_timer, expires); + hif_sc->runtime_timer_expires = expires; + } + + spin_unlock_bh(&hif_sc->runtime_lock); + + HIF_ERROR("%s: pm_state: %s delay: %dms ret: %d\n", __func__, + hif_pm_runtime_state_to_string( + qdf_atomic_read(&hif_sc->pm_state)), + delay, ret); + + return ret; +} + +/** + * hif_runtime_lock_init() - API to initialize Runtime PM context + * @name: Context name + * + * This API initalizes the Runtime PM context of the caller and + * return the pointer. + * + * Return: None + */ +int hif_runtime_lock_init(qdf_runtime_lock_t *lock, const char *name) +{ + struct hif_pm_runtime_lock *context; + + context = qdf_mem_malloc(sizeof(*context)); + if (!context) { + HIF_ERROR("%s: No memory for Runtime PM wakelock context\n", + __func__); + return -ENOMEM; + } + + context->name = name ? name : "Default"; + lock->lock = context; + + return 0; +} + +/** + * hif_runtime_lock_deinit() - This API frees the runtime pm ctx + * @data: Runtime PM context + * + * Return: void + */ +void hif_runtime_lock_deinit(struct hif_opaque_softc *hif_ctx, + struct hif_pm_runtime_lock *data) +{ + struct hif_pm_runtime_lock *context = data; + struct hif_pci_softc *sc = HIF_GET_PCI_SOFTC(hif_ctx); + + if (!sc) + return; + + if (!context) + return; + + /* + * Ensure to delete the context list entry and reduce the usage count + * before freeing the context if context is active. + */ + spin_lock_bh(&sc->runtime_lock); + __hif_pm_runtime_allow_suspend(sc, context); + spin_unlock_bh(&sc->runtime_lock); + + qdf_mem_free(context); +} +#endif /* FEATURE_RUNTIME_PM */ diff --git a/drivers/staging/qca-wifi-host-cmn/hif/src/pcie/if_pci.h b/drivers/staging/qca-wifi-host-cmn/hif/src/pcie/if_pci.h new file mode 100644 index 0000000000000000000000000000000000000000..9c19b4a358ddd1e2dea7bfd923c2f2a1598e2150 --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/hif/src/pcie/if_pci.h @@ -0,0 +1,217 @@ +/* + * Copyright (c) 2013-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef __ATH_PCI_H__ +#define __ATH_PCI_H__ + +#include +#include +#include + +#define ATH_DBG_DEFAULT 0 +#include "hif.h" +#include "cepci.h" +#include "ce_main.h" + +/* An address (e.g. of a buffer) in Copy Engine space. */ + +#define HIF_MAX_TASKLET_NUM 11 +struct hif_tasklet_entry { + uint8_t id; /* 0 - 9: maps to CE, 10: fw */ + void *hif_handler; /* struct hif_pci_softc */ +}; + +/** + * enum hif_pm_runtime_state - Driver States for Runtime Power Management + * HIF_PM_RUNTIME_STATE_NONE: runtime pm is off + * HIF_PM_RUNTIME_STATE_ON: runtime pm is active and link is active + * HIF_PM_RUNTIME_STATE_INPROGRESS: a runtime suspend or resume is in progress + * HIF_PM_RUNTIME_STATE_SUSPENDED: the driver is runtime suspended + */ +enum hif_pm_runtime_state { + HIF_PM_RUNTIME_STATE_NONE, + HIF_PM_RUNTIME_STATE_ON, + HIF_PM_RUNTIME_STATE_INPROGRESS, + HIF_PM_RUNTIME_STATE_SUSPENDED, +}; + +#ifdef FEATURE_RUNTIME_PM + +/** + * struct hif_pm_runtime_lock - data structure for preventing runtime suspend + * @list - global list of runtime locks + * @active - true if this lock is preventing suspend + * @name - character string for tracking this lock + */ +struct hif_pm_runtime_lock { + struct list_head list; + bool active; + uint32_t timeout; + const char *name; +}; + +/* Debugging stats for Runtime PM */ +struct hif_pci_pm_stats { + u32 suspended; + u32 suspend_err; + u32 resumed; + u32 runtime_get; + u32 runtime_put; + u32 request_resume; + u32 allow_suspend; + u32 prevent_suspend; + u32 prevent_suspend_timeout; + u32 allow_suspend_timeout; + u32 runtime_get_err; + void *last_resume_caller; + unsigned long suspend_jiffies; +}; +#endif + +/** + * struct hif_msi_info - Structure to hold msi info + * @magic: cookie + * @magic_da: dma address + * @dmaContext: dma address + * + * Structure to hold MSI information for PCIe interrupts + */ +struct hif_msi_info { + void *magic; + dma_addr_t magic_da; + OS_DMA_MEM_CONTEXT(dmacontext) +}; + +struct hif_pci_softc { + struct HIF_CE_state ce_sc; + void __iomem *mem; /* PCI address. */ + /* For efficiency, should be first in struct */ + + struct device *dev; + struct pci_dev *pdev; + int num_msi_intrs; /* number of MSI interrupts granted */ + /* 0 --> using legacy PCI line interrupts */ + struct tasklet_struct intr_tq; /* tasklet */ + + struct hif_msi_info msi_info; + int irq; + int irq_event; + int cacheline_sz; + u16 devid; + qdf_dma_addr_t soc_pcie_bar0; + struct hif_tasklet_entry tasklet_entries[HIF_MAX_TASKLET_NUM]; + bool pci_enabled; + qdf_spinlock_t irq_lock; + qdf_work_t reschedule_tasklet_work; + uint32_t lcr_val; +#ifdef FEATURE_RUNTIME_PM + atomic_t pm_state; + uint32_t prevent_suspend_cnt; + struct hif_pci_pm_stats pm_stats; + struct work_struct pm_work; + spinlock_t runtime_lock; + struct timer_list runtime_timer; + struct list_head prevent_suspend_list; + unsigned long runtime_timer_expires; + qdf_runtime_lock_t prevent_linkdown_lock; +#ifdef WLAN_OPEN_SOURCE + struct dentry *pm_dentry; +#endif +#endif +}; + +bool hif_pci_targ_is_present(struct hif_softc *scn, void *__iomem *mem); +int hif_configure_irq(struct hif_softc *sc); +void hif_pci_cancel_deferred_target_sleep(struct hif_softc *scn); +void wlan_tasklet(unsigned long data); +irqreturn_t hif_pci_interrupt_handler(int irq, void *arg); + +/* + * A firmware interrupt to the Host is indicated by the + * low bit of SCRATCH_3_ADDRESS being set. + */ +#define FW_EVENT_PENDING_REG_ADDRESS SCRATCH_3_ADDRESS + +/* + * Typically, MSI Interrupts are used with PCIe. To force use of legacy + * "ABCD" PCI line interrupts rather than MSI, define + * FORCE_LEGACY_PCI_INTERRUPTS. + * Even when NOT forced, the driver may attempt to use legacy PCI interrupts + * MSI allocation fails + */ +#define LEGACY_INTERRUPTS(sc) ((sc)->num_msi_intrs == 0) + +/* + * There may be some pending tx frames during platform suspend. + * Suspend operation should be delayed until those tx frames are + * transfered from the host to target. This macro specifies how + * long suspend thread has to sleep before checking pending tx + * frame count. + */ +#define OL_ATH_TX_DRAIN_WAIT_DELAY 50 /* ms */ + +#define HIF_CE_DRAIN_WAIT_DELAY 10 /* ms */ +/* + * Wait time (in unit of OL_ATH_TX_DRAIN_WAIT_DELAY) for pending + * tx frame completion before suspend. Refer: hif_pci_suspend() + */ +#ifndef QCA_WIFI_3_0_EMU +#define OL_ATH_TX_DRAIN_WAIT_CNT 10 +#else +#define OL_ATH_TX_DRAIN_WAIT_CNT 60 +#endif + +#ifdef FEATURE_RUNTIME_PM +#include + +static inline int hif_pm_request_resume(struct device *dev) +{ + return pm_request_resume(dev); +} +static inline int __hif_pm_runtime_get(struct device *dev) +{ + return pm_runtime_get(dev); +} + +static inline int hif_pm_runtime_put_auto(struct device *dev) +{ + return pm_runtime_put_autosuspend(dev); +} + +static inline void hif_pm_runtime_mark_last_busy(struct device *dev) +{ + pm_runtime_mark_last_busy(dev); +} + +static inline int hif_pm_runtime_resume(struct device *dev) +{ + return pm_runtime_resume(dev); +} +#else +static inline void hif_pm_runtime_mark_last_busy(struct device *dev) { } +#endif /* FEATURE_RUNTIME_PM */ +#endif /* __ATH_PCI_H__ */ diff --git a/drivers/staging/qca-wifi-host-cmn/hif/src/pcie/if_pci_internal.h b/drivers/staging/qca-wifi-host-cmn/hif/src/pcie/if_pci_internal.h new file mode 100644 index 0000000000000000000000000000000000000000..b280f2be553ee79f1c48a910cd70273082ff56a9 --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/hif/src/pcie/if_pci_internal.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2015-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef __IF_PCI_INTERNAL_H__ +#define __IF_PCI_INTERNAL_H__ + +#ifdef DISABLE_L1SS_STATES +#define PCI_CFG_TO_DISABLE_L1SS_STATES(pdev, addr) \ +{ \ + uint32_t lcr_val; \ + pci_read_config_dword(pdev, addr, &lcr_val); \ + pci_write_config_dword(pdev, addr, (lcr_val & ~0x0000000f)); \ +} +#else +#define PCI_CFG_TO_DISABLE_L1SS_STATES(pdev, addr) +#endif + +#ifdef QCA_WIFI_3_0 +#define PCI_CLR_CAUSE0_REGISTER(sc) \ +{ \ + uint32_t tmp_cause0; \ + tmp_cause0 = hif_read32_mb(sc->mem + PCIE_INTR_CAUSE_ADDRESS); \ + hif_write32_mb(sc->mem + PCIE_INTR_CLR_ADDRESS, \ + PCIE_INTR_FIRMWARE_MASK | tmp_cause0); \ + hif_read32_mb(sc->mem + PCIE_INTR_CLR_ADDRESS); \ + hif_write32_mb(sc->mem + PCIE_INTR_CLR_ADDRESS, 0); \ + hif_read32_mb(sc->mem + PCIE_INTR_CLR_ADDRESS); \ +} +#else +#define PCI_CLR_CAUSE0_REGISTER(sc) +#endif +#endif /* __IF_PCI_INTERNAL_H__ */ diff --git a/drivers/staging/qca-wifi-host-cmn/hif/src/qca9888def.c b/drivers/staging/qca-wifi-host-cmn/hif/src/qca9888def.c new file mode 100644 index 0000000000000000000000000000000000000000..2c67094e399f9b6854e7dee026b62775e921dd8a --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/hif/src/qca9888def.c @@ -0,0 +1,225 @@ +/* + * Copyright (c) 2015,2016 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. + */ + +#if defined(QCA9888_HEADERS_DEF) +#define QCA9888 1 + +#define WLAN_HEADERS 1 +#include "common_drv.h" +#include "QCA9888/v2/soc_addrs.h" +#include "QCA9888/v2/extra/hw/apb_map.h" +#include "QCA9888/v2/hw/gpio_athr_wlan_reg.h" +#ifdef WLAN_HEADERS + +#include "QCA9888/v2/extra/hw/wifi_top_reg_map.h" +#include "QCA9888/v2/hw/rtc_soc_reg.h" + +#endif +#include "QCA9888/v2/hw/si_reg.h" +#include "QCA9888/v2/extra/hw/pcie_local_reg.h" +#include "QCA9888/v2/hw/ce_wrapper_reg_csr.h" + +#include "QCA9888/v2/extra/hw/soc_core_reg.h" +#include "QCA9888/v2/hw/soc_pcie_reg.h" +#include "QCA9888/v2/extra/hw/ce_reg_csr.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Base address is defined in pcie_local_reg.h. Macros which access the + * registers include the base address in their definition. + */ +#define PCIE_LOCAL_BASE_ADDRESS 0 + +#define FW_EVENT_PENDING_ADDRESS (WIFICMN_SCRATCH_3_ADDRESS) +#define DRAM_BASE_ADDRESS TARG_DRAM_START + +/* Backwards compatibility -- TBDXXX */ + +#define MISSING 0 + +#define WLAN_SYSTEM_SLEEP_DISABLE_LSB WIFI_SYSTEM_SLEEP_DISABLE_LSB +#define WLAN_SYSTEM_SLEEP_DISABLE_MASK WIFI_SYSTEM_SLEEP_DISABLE_MASK +#define WLAN_RESET_CONTROL_COLD_RST_MASK WIFI_RESET_CONTROL_MAC_COLD_RST_MASK +#define WLAN_RESET_CONTROL_WARM_RST_MASK WIFI_RESET_CONTROL_MAC_WARM_RST_MASK +#define SOC_CLOCK_CONTROL_OFFSET SOC_CLOCK_CONTROL_ADDRESS +#define SOC_RESET_CONTROL_OFFSET SOC_RESET_CONTROL_ADDRESS +#define CPU_CLOCK_OFFSET SOC_CPU_CLOCK_ADDRESS +#define SOC_LPO_CAL_OFFSET SOC_LPO_CAL_ADDRESS +#define SOC_RESET_CONTROL_CE_RST_MASK WIFI_RESET_CONTROL_CE_RESET_MASK +#define WLAN_SYSTEM_SLEEP_OFFSET WIFI_SYSTEM_SLEEP_ADDRESS +#define WLAN_RESET_CONTROL_OFFSET WIFI_RESET_CONTROL_ADDRESS +#define CLOCK_CONTROL_OFFSET SOC_CLOCK_CONTROL_OFFSET +#define CLOCK_CONTROL_SI0_CLK_MASK SOC_CLOCK_CONTROL_SI0_CLK_MASK +#define RESET_CONTROL_SI0_RST_MASK SOC_RESET_CONTROL_SI0_RST_MASK +#define GPIO_BASE_ADDRESS WLAN_GPIO_BASE_ADDRESS +#define GPIO_PIN0_OFFSET WLAN_GPIO_PIN0_ADDRESS +#define GPIO_PIN1_OFFSET WLAN_GPIO_PIN1_ADDRESS +#define GPIO_PIN0_CONFIG_MASK WLAN_GPIO_PIN0_CONFIG_MASK +#define GPIO_PIN1_CONFIG_MASK WLAN_GPIO_PIN1_CONFIG_MASK +#define SI_BASE_ADDRESS WLAN_SI_BASE_ADDRESS +#define SCRATCH_BASE_ADDRESS SOC_CORE_BASE_ADDRESS +#define LOCAL_SCRATCH_OFFSET 0x18 +#define GPIO_PIN10_OFFSET WLAN_GPIO_PIN10_ADDRESS +#define GPIO_PIN11_OFFSET WLAN_GPIO_PIN11_ADDRESS +#define GPIO_PIN12_OFFSET WLAN_GPIO_PIN12_ADDRESS +#define GPIO_PIN13_OFFSET WLAN_GPIO_PIN13_ADDRESS +#define SI_CONFIG_OFFSET SI_CONFIG_ADDRESS +#define SI_TX_DATA0_OFFSET SI_TX_DATA0_ADDRESS +#define SI_TX_DATA1_OFFSET SI_TX_DATA1_ADDRESS +#define SI_RX_DATA0_OFFSET SI_RX_DATA0_ADDRESS +#define SI_RX_DATA1_OFFSET SI_RX_DATA1_ADDRESS +#define SI_CS_OFFSET SI_CS_ADDRESS +#define CPU_CLOCK_STANDARD_LSB SOC_CPU_CLOCK_STANDARD_LSB +#define CPU_CLOCK_STANDARD_MASK SOC_CPU_CLOCK_STANDARD_MASK +#define LPO_CAL_ENABLE_LSB SOC_LPO_CAL_ENABLE_LSB +#define LPO_CAL_ENABLE_MASK SOC_LPO_CAL_ENABLE_MASK +#define ANALOG_INTF_BASE_ADDRESS WLAN_ANALOG_INTF_BASE_ADDRESS +#define MBOX_BASE_ADDRESS MISSING +#define INT_STATUS_ENABLE_ERROR_LSB MISSING +#define INT_STATUS_ENABLE_ERROR_MASK MISSING +#define INT_STATUS_ENABLE_CPU_LSB MISSING +#define INT_STATUS_ENABLE_CPU_MASK MISSING +#define INT_STATUS_ENABLE_COUNTER_LSB MISSING +#define INT_STATUS_ENABLE_COUNTER_MASK MISSING +#define INT_STATUS_ENABLE_MBOX_DATA_LSB MISSING +#define INT_STATUS_ENABLE_MBOX_DATA_MASK MISSING +#define ERROR_STATUS_ENABLE_RX_UNDERFLOW_LSB MISSING +#define ERROR_STATUS_ENABLE_RX_UNDERFLOW_MASK MISSING +#define ERROR_STATUS_ENABLE_TX_OVERFLOW_LSB MISSING +#define ERROR_STATUS_ENABLE_TX_OVERFLOW_MASK MISSING +#define COUNTER_INT_STATUS_ENABLE_BIT_LSB MISSING +#define COUNTER_INT_STATUS_ENABLE_BIT_MASK MISSING +#define INT_STATUS_ENABLE_ADDRESS MISSING +#define CPU_INT_STATUS_ENABLE_BIT_LSB MISSING +#define CPU_INT_STATUS_ENABLE_BIT_MASK MISSING +#define HOST_INT_STATUS_ADDRESS MISSING +#define CPU_INT_STATUS_ADDRESS MISSING +#define ERROR_INT_STATUS_ADDRESS MISSING +#define ERROR_INT_STATUS_WAKEUP_MASK MISSING +#define ERROR_INT_STATUS_WAKEUP_LSB MISSING +#define ERROR_INT_STATUS_RX_UNDERFLOW_MASK MISSING +#define ERROR_INT_STATUS_RX_UNDERFLOW_LSB MISSING +#define ERROR_INT_STATUS_TX_OVERFLOW_MASK MISSING +#define ERROR_INT_STATUS_TX_OVERFLOW_LSB MISSING +#define COUNT_DEC_ADDRESS MISSING +#define HOST_INT_STATUS_CPU_MASK MISSING +#define HOST_INT_STATUS_CPU_LSB MISSING +#define HOST_INT_STATUS_ERROR_MASK MISSING +#define HOST_INT_STATUS_ERROR_LSB MISSING +#define HOST_INT_STATUS_COUNTER_MASK MISSING +#define HOST_INT_STATUS_COUNTER_LSB MISSING +#define RX_LOOKAHEAD_VALID_ADDRESS MISSING +#define WINDOW_DATA_ADDRESS MISSING +#define WINDOW_READ_ADDR_ADDRESS MISSING +#define WINDOW_WRITE_ADDR_ADDRESS MISSING +/* MAC Descriptor */ +#define RX_PPDU_END_ANTENNA_OFFSET_DWORD (RX_PPDU_END_25_RX_ANTENNA_OFFSET >> 2) +/* GPIO Register */ +#define GPIO_ENABLE_W1TS_LOW_ADDRESS WLAN_GPIO_ENABLE_W1TS_LOW_ADDRESS +#define GPIO_PIN0_CONFIG_LSB WLAN_GPIO_PIN0_CONFIG_LSB +#define GPIO_PIN0_PAD_PULL_LSB WLAN_GPIO_PIN0_PAD_PULL_LSB +#define GPIO_PIN0_PAD_PULL_MASK WLAN_GPIO_PIN0_PAD_PULL_MASK +/* CE descriptor */ +#define CE_SRC_DESC_SIZE_DWORD 2 +#define CE_DEST_DESC_SIZE_DWORD 2 +#define CE_SRC_DESC_SRC_PTR_OFFSET_DWORD 0 +#define CE_SRC_DESC_INFO_OFFSET_DWORD 1 +#define CE_DEST_DESC_DEST_PTR_OFFSET_DWORD 0 +#define CE_DEST_DESC_INFO_OFFSET_DWORD 1 +#if _BYTE_ORDER == _BIG_ENDIAN +#define CE_SRC_DESC_INFO_NBYTES_MASK 0xFFFF0000 +#define CE_SRC_DESC_INFO_NBYTES_SHIFT 16 +#define CE_SRC_DESC_INFO_GATHER_MASK 0x00008000 +#define CE_SRC_DESC_INFO_GATHER_SHIFT 15 +#define CE_SRC_DESC_INFO_BYTE_SWAP_MASK 0x00004000 +#define CE_SRC_DESC_INFO_BYTE_SWAP_SHIFT 14 +#define CE_SRC_DESC_INFO_HOST_INT_DISABLE_MASK 0x00002000 +#define CE_SRC_DESC_INFO_HOST_INT_DISABLE_SHIFT 13 +#define CE_SRC_DESC_INFO_TARGET_INT_DISABLE_MASK 0x00001000 +#define CE_SRC_DESC_INFO_TARGET_INT_DISABLE_SHIFT 12 +#define CE_SRC_DESC_INFO_META_DATA_MASK 0x00000FFF +#define CE_SRC_DESC_INFO_META_DATA_SHIFT 0 +#else +#define CE_SRC_DESC_INFO_NBYTES_MASK 0x0000FFFF +#define CE_SRC_DESC_INFO_NBYTES_SHIFT 0 +#define CE_SRC_DESC_INFO_GATHER_MASK 0x00010000 +#define CE_SRC_DESC_INFO_GATHER_SHIFT 16 +#define CE_SRC_DESC_INFO_BYTE_SWAP_MASK 0x00020000 +#define CE_SRC_DESC_INFO_BYTE_SWAP_SHIFT 17 +#define CE_SRC_DESC_INFO_HOST_INT_DISABLE_MASK 0x00040000 +#define CE_SRC_DESC_INFO_HOST_INT_DISABLE_SHIFT 18 +#define CE_SRC_DESC_INFO_TARGET_INT_DISABLE_MASK 0x00080000 +#define CE_SRC_DESC_INFO_TARGET_INT_DISABLE_SHIFT 19 +#define CE_SRC_DESC_INFO_META_DATA_MASK 0xFFF00000 +#define CE_SRC_DESC_INFO_META_DATA_SHIFT 20 +#endif +#if _BYTE_ORDER == _BIG_ENDIAN +#define CE_DEST_DESC_INFO_NBYTES_MASK 0xFFFF0000 +#define CE_DEST_DESC_INFO_NBYTES_SHIFT 16 +#define CE_DEST_DESC_INFO_GATHER_MASK 0x00008000 +#define CE_DEST_DESC_INFO_GATHER_SHIFT 15 +#define CE_DEST_DESC_INFO_BYTE_SWAP_MASK 0x00004000 +#define CE_DEST_DESC_INFO_BYTE_SWAP_SHIFT 14 +#define CE_DEST_DESC_INFO_HOST_INT_DISABLE_MASK 0x00002000 +#define CE_DEST_DESC_INFO_HOST_INT_DISABLE_SHIFT 13 +#define CE_DEST_DESC_INFO_TARGET_INT_DISABLE_MASK 0x00001000 +#define CE_DEST_DESC_INFO_TARGET_INT_DISABLE_SHIFT 12 +#define CE_DEST_DESC_INFO_META_DATA_MASK 0x00000FFF +#define CE_DEST_DESC_INFO_META_DATA_SHIFT 0 +#else +#define CE_DEST_DESC_INFO_NBYTES_MASK 0x0000FFFF +#define CE_DEST_DESC_INFO_NBYTES_SHIFT 0 +#define CE_DEST_DESC_INFO_GATHER_MASK 0x00010000 +#define CE_DEST_DESC_INFO_GATHER_SHIFT 16 +#define CE_DEST_DESC_INFO_BYTE_SWAP_MASK 0x00020000 +#define CE_DEST_DESC_INFO_BYTE_SWAP_SHIFT 17 +#define CE_DEST_DESC_INFO_HOST_INT_DISABLE_MASK 0x00040000 +#define CE_DEST_DESC_INFO_HOST_INT_DISABLE_SHIFT 18 +#define CE_DEST_DESC_INFO_TARGET_INT_DISABLE_MASK 0x00080000 +#define CE_DEST_DESC_INFO_TARGET_INT_DISABLE_SHIFT 19 +#define CE_DEST_DESC_INFO_META_DATA_MASK 0xFFF00000 +#define CE_DEST_DESC_INFO_META_DATA_SHIFT 20 +#endif + +#define MY_TARGET_DEF QCA9888_TARGETdef +#define MY_HOST_DEF QCA9888_HOSTdef +#define MY_CEREG_DEF QCA9888_CE_TARGETdef +#define MY_TARGET_BOARD_DATA_SZ QCA9888_BOARD_DATA_SZ +#define MY_TARGET_BOARD_EXT_DATA_SZ QCA9888_BOARD_EXT_DATA_SZ +#include "targetdef.h" +#include "hostdef.h" +#else +#include "common_drv.h" +#include "targetdef.h" +#include "hostdef.h" +struct targetdef_s *QCA9888_TARGETdef; +struct hostdef_s *QCA9888_HOSTdef; +#endif /* QCA9888_HEADERS_DEF */ diff --git a/drivers/staging/qca-wifi-host-cmn/hif/src/qca9984def.c b/drivers/staging/qca-wifi-host-cmn/hif/src/qca9984def.c new file mode 100644 index 0000000000000000000000000000000000000000..61d09c75e8c6e0eb70c96e8ee6738b78f26a59d0 --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/hif/src/qca9984def.c @@ -0,0 +1,225 @@ +/* + * Copyright (c) 2015,2016 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. + */ + +#if defined(QCA9984_HEADERS_DEF) +#define QCA9984 1 + +#define WLAN_HEADERS 1 +#include "common_drv.h" +#include "QCA9984/soc_addrs.h" +#include "QCA9984/extra/hw/apb_map.h" +#include "QCA9984/hw/gpio_athr_wlan_reg.h" +#ifdef WLAN_HEADERS + +#include "QCA9984/extra/hw/wifi_top_reg_map.h" +#include "QCA9984/hw/rtc_soc_reg.h" + +#endif +#include "QCA9984/hw/si_reg.h" +#include "QCA9984/extra/hw/pcie_local_reg.h" +#include "QCA9984/hw/ce_wrapper_reg_csr.h" + +#include "QCA9984/extra/hw/soc_core_reg.h" +#include "QCA9984/hw/soc_pcie_reg.h" +#include "QCA9984/extra/hw/ce_reg_csr.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Base address is defined in pcie_local_reg.h. Macros which access the + * registers include the base address in their definition. + */ +#define PCIE_LOCAL_BASE_ADDRESS 0 + +#define FW_EVENT_PENDING_ADDRESS (WIFICMN_SCRATCH_3_ADDRESS) +#define DRAM_BASE_ADDRESS TARG_DRAM_START + +/* Backwards compatibility -- TBDXXX */ + +#define MISSING 0 + +#define WLAN_SYSTEM_SLEEP_DISABLE_LSB WIFI_SYSTEM_SLEEP_DISABLE_LSB +#define WLAN_SYSTEM_SLEEP_DISABLE_MASK WIFI_SYSTEM_SLEEP_DISABLE_MASK +#define WLAN_RESET_CONTROL_COLD_RST_MASK WIFI_RESET_CONTROL_MAC_COLD_RST_MASK +#define WLAN_RESET_CONTROL_WARM_RST_MASK WIFI_RESET_CONTROL_MAC_WARM_RST_MASK +#define SOC_CLOCK_CONTROL_OFFSET SOC_CLOCK_CONTROL_ADDRESS +#define SOC_RESET_CONTROL_OFFSET SOC_RESET_CONTROL_ADDRESS +#define CPU_CLOCK_OFFSET SOC_CPU_CLOCK_ADDRESS +#define SOC_LPO_CAL_OFFSET SOC_LPO_CAL_ADDRESS +#define SOC_RESET_CONTROL_CE_RST_MASK WIFI_RESET_CONTROL_CE_RESET_MASK +#define WLAN_SYSTEM_SLEEP_OFFSET WIFI_SYSTEM_SLEEP_ADDRESS +#define WLAN_RESET_CONTROL_OFFSET WIFI_RESET_CONTROL_ADDRESS +#define CLOCK_CONTROL_OFFSET SOC_CLOCK_CONTROL_OFFSET +#define CLOCK_CONTROL_SI0_CLK_MASK SOC_CLOCK_CONTROL_SI0_CLK_MASK +#define RESET_CONTROL_SI0_RST_MASK SOC_RESET_CONTROL_SI0_RST_MASK +#define GPIO_BASE_ADDRESS WLAN_GPIO_BASE_ADDRESS +#define GPIO_PIN0_OFFSET WLAN_GPIO_PIN0_ADDRESS +#define GPIO_PIN1_OFFSET WLAN_GPIO_PIN1_ADDRESS +#define GPIO_PIN0_CONFIG_MASK WLAN_GPIO_PIN0_CONFIG_MASK +#define GPIO_PIN1_CONFIG_MASK WLAN_GPIO_PIN1_CONFIG_MASK +#define SI_BASE_ADDRESS WLAN_SI_BASE_ADDRESS +#define SCRATCH_BASE_ADDRESS SOC_CORE_BASE_ADDRESS +#define LOCAL_SCRATCH_OFFSET 0x18 +#define GPIO_PIN10_OFFSET WLAN_GPIO_PIN10_ADDRESS +#define GPIO_PIN11_OFFSET WLAN_GPIO_PIN11_ADDRESS +#define GPIO_PIN12_OFFSET WLAN_GPIO_PIN12_ADDRESS +#define GPIO_PIN13_OFFSET WLAN_GPIO_PIN13_ADDRESS +#define SI_CONFIG_OFFSET SI_CONFIG_ADDRESS +#define SI_TX_DATA0_OFFSET SI_TX_DATA0_ADDRESS +#define SI_TX_DATA1_OFFSET SI_TX_DATA1_ADDRESS +#define SI_RX_DATA0_OFFSET SI_RX_DATA0_ADDRESS +#define SI_RX_DATA1_OFFSET SI_RX_DATA1_ADDRESS +#define SI_CS_OFFSET SI_CS_ADDRESS +#define CPU_CLOCK_STANDARD_LSB SOC_CPU_CLOCK_STANDARD_LSB +#define CPU_CLOCK_STANDARD_MASK SOC_CPU_CLOCK_STANDARD_MASK +#define LPO_CAL_ENABLE_LSB SOC_LPO_CAL_ENABLE_LSB +#define LPO_CAL_ENABLE_MASK SOC_LPO_CAL_ENABLE_MASK +#define ANALOG_INTF_BASE_ADDRESS WLAN_ANALOG_INTF_BASE_ADDRESS +#define MBOX_BASE_ADDRESS MISSING +#define INT_STATUS_ENABLE_ERROR_LSB MISSING +#define INT_STATUS_ENABLE_ERROR_MASK MISSING +#define INT_STATUS_ENABLE_CPU_LSB MISSING +#define INT_STATUS_ENABLE_CPU_MASK MISSING +#define INT_STATUS_ENABLE_COUNTER_LSB MISSING +#define INT_STATUS_ENABLE_COUNTER_MASK MISSING +#define INT_STATUS_ENABLE_MBOX_DATA_LSB MISSING +#define INT_STATUS_ENABLE_MBOX_DATA_MASK MISSING +#define ERROR_STATUS_ENABLE_RX_UNDERFLOW_LSB MISSING +#define ERROR_STATUS_ENABLE_RX_UNDERFLOW_MASK MISSING +#define ERROR_STATUS_ENABLE_TX_OVERFLOW_LSB MISSING +#define ERROR_STATUS_ENABLE_TX_OVERFLOW_MASK MISSING +#define COUNTER_INT_STATUS_ENABLE_BIT_LSB MISSING +#define COUNTER_INT_STATUS_ENABLE_BIT_MASK MISSING +#define INT_STATUS_ENABLE_ADDRESS MISSING +#define CPU_INT_STATUS_ENABLE_BIT_LSB MISSING +#define CPU_INT_STATUS_ENABLE_BIT_MASK MISSING +#define HOST_INT_STATUS_ADDRESS MISSING +#define CPU_INT_STATUS_ADDRESS MISSING +#define ERROR_INT_STATUS_ADDRESS MISSING +#define ERROR_INT_STATUS_WAKEUP_MASK MISSING +#define ERROR_INT_STATUS_WAKEUP_LSB MISSING +#define ERROR_INT_STATUS_RX_UNDERFLOW_MASK MISSING +#define ERROR_INT_STATUS_RX_UNDERFLOW_LSB MISSING +#define ERROR_INT_STATUS_TX_OVERFLOW_MASK MISSING +#define ERROR_INT_STATUS_TX_OVERFLOW_LSB MISSING +#define COUNT_DEC_ADDRESS MISSING +#define HOST_INT_STATUS_CPU_MASK MISSING +#define HOST_INT_STATUS_CPU_LSB MISSING +#define HOST_INT_STATUS_ERROR_MASK MISSING +#define HOST_INT_STATUS_ERROR_LSB MISSING +#define HOST_INT_STATUS_COUNTER_MASK MISSING +#define HOST_INT_STATUS_COUNTER_LSB MISSING +#define RX_LOOKAHEAD_VALID_ADDRESS MISSING +#define WINDOW_DATA_ADDRESS MISSING +#define WINDOW_READ_ADDR_ADDRESS MISSING +#define WINDOW_WRITE_ADDR_ADDRESS MISSING +/* MAC Descriptor */ +#define RX_PPDU_END_ANTENNA_OFFSET_DWORD (RX_PPDU_END_25_RX_ANTENNA_OFFSET >> 2) +/* GPIO Register */ +#define GPIO_ENABLE_W1TS_LOW_ADDRESS WLAN_GPIO_ENABLE_W1TS_LOW_ADDRESS +#define GPIO_PIN0_CONFIG_LSB WLAN_GPIO_PIN0_CONFIG_LSB +#define GPIO_PIN0_PAD_PULL_LSB WLAN_GPIO_PIN0_PAD_PULL_LSB +#define GPIO_PIN0_PAD_PULL_MASK WLAN_GPIO_PIN0_PAD_PULL_MASK +/* CE descriptor */ +#define CE_SRC_DESC_SIZE_DWORD 2 +#define CE_DEST_DESC_SIZE_DWORD 2 +#define CE_SRC_DESC_SRC_PTR_OFFSET_DWORD 0 +#define CE_SRC_DESC_INFO_OFFSET_DWORD 1 +#define CE_DEST_DESC_DEST_PTR_OFFSET_DWORD 0 +#define CE_DEST_DESC_INFO_OFFSET_DWORD 1 +#if _BYTE_ORDER == _BIG_ENDIAN +#define CE_SRC_DESC_INFO_NBYTES_MASK 0xFFFF0000 +#define CE_SRC_DESC_INFO_NBYTES_SHIFT 16 +#define CE_SRC_DESC_INFO_GATHER_MASK 0x00008000 +#define CE_SRC_DESC_INFO_GATHER_SHIFT 15 +#define CE_SRC_DESC_INFO_BYTE_SWAP_MASK 0x00004000 +#define CE_SRC_DESC_INFO_BYTE_SWAP_SHIFT 14 +#define CE_SRC_DESC_INFO_HOST_INT_DISABLE_MASK 0x00002000 +#define CE_SRC_DESC_INFO_HOST_INT_DISABLE_SHIFT 13 +#define CE_SRC_DESC_INFO_TARGET_INT_DISABLE_MASK 0x00001000 +#define CE_SRC_DESC_INFO_TARGET_INT_DISABLE_SHIFT 12 +#define CE_SRC_DESC_INFO_META_DATA_MASK 0x00000FFF +#define CE_SRC_DESC_INFO_META_DATA_SHIFT 0 +#else +#define CE_SRC_DESC_INFO_NBYTES_MASK 0x0000FFFF +#define CE_SRC_DESC_INFO_NBYTES_SHIFT 0 +#define CE_SRC_DESC_INFO_GATHER_MASK 0x00010000 +#define CE_SRC_DESC_INFO_GATHER_SHIFT 16 +#define CE_SRC_DESC_INFO_BYTE_SWAP_MASK 0x00020000 +#define CE_SRC_DESC_INFO_BYTE_SWAP_SHIFT 17 +#define CE_SRC_DESC_INFO_HOST_INT_DISABLE_MASK 0x00040000 +#define CE_SRC_DESC_INFO_HOST_INT_DISABLE_SHIFT 18 +#define CE_SRC_DESC_INFO_TARGET_INT_DISABLE_MASK 0x00080000 +#define CE_SRC_DESC_INFO_TARGET_INT_DISABLE_SHIFT 19 +#define CE_SRC_DESC_INFO_META_DATA_MASK 0xFFF00000 +#define CE_SRC_DESC_INFO_META_DATA_SHIFT 20 +#endif +#if _BYTE_ORDER == _BIG_ENDIAN +#define CE_DEST_DESC_INFO_NBYTES_MASK 0xFFFF0000 +#define CE_DEST_DESC_INFO_NBYTES_SHIFT 16 +#define CE_DEST_DESC_INFO_GATHER_MASK 0x00008000 +#define CE_DEST_DESC_INFO_GATHER_SHIFT 15 +#define CE_DEST_DESC_INFO_BYTE_SWAP_MASK 0x00004000 +#define CE_DEST_DESC_INFO_BYTE_SWAP_SHIFT 14 +#define CE_DEST_DESC_INFO_HOST_INT_DISABLE_MASK 0x00002000 +#define CE_DEST_DESC_INFO_HOST_INT_DISABLE_SHIFT 13 +#define CE_DEST_DESC_INFO_TARGET_INT_DISABLE_MASK 0x00001000 +#define CE_DEST_DESC_INFO_TARGET_INT_DISABLE_SHIFT 12 +#define CE_DEST_DESC_INFO_META_DATA_MASK 0x00000FFF +#define CE_DEST_DESC_INFO_META_DATA_SHIFT 0 +#else +#define CE_DEST_DESC_INFO_NBYTES_MASK 0x0000FFFF +#define CE_DEST_DESC_INFO_NBYTES_SHIFT 0 +#define CE_DEST_DESC_INFO_GATHER_MASK 0x00010000 +#define CE_DEST_DESC_INFO_GATHER_SHIFT 16 +#define CE_DEST_DESC_INFO_BYTE_SWAP_MASK 0x00020000 +#define CE_DEST_DESC_INFO_BYTE_SWAP_SHIFT 17 +#define CE_DEST_DESC_INFO_HOST_INT_DISABLE_MASK 0x00040000 +#define CE_DEST_DESC_INFO_HOST_INT_DISABLE_SHIFT 18 +#define CE_DEST_DESC_INFO_TARGET_INT_DISABLE_MASK 0x00080000 +#define CE_DEST_DESC_INFO_TARGET_INT_DISABLE_SHIFT 19 +#define CE_DEST_DESC_INFO_META_DATA_MASK 0xFFF00000 +#define CE_DEST_DESC_INFO_META_DATA_SHIFT 20 +#endif + +#define MY_TARGET_DEF QCA9984_TARGETdef +#define MY_HOST_DEF QCA9984_HOSTdef +#define MY_CEREG_DEF QCA9984_CE_TARGETdef +#define MY_TARGET_BOARD_DATA_SZ QCA9984_BOARD_DATA_SZ +#define MY_TARGET_BOARD_EXT_DATA_SZ QCA9984_BOARD_EXT_DATA_SZ +#include "targetdef.h" +#include "hostdef.h" +#else +#include "common_drv.h" +#include "targetdef.h" +#include "hostdef.h" +struct targetdef_s *QCA9984_TARGETdef; +struct hostdef_s *QCA9984_HOSTdef; +#endif /* QCA9984_HEADERS_DEF */ diff --git a/drivers/staging/qca-wifi-host-cmn/hif/src/regtable.c b/drivers/staging/qca-wifi-host-cmn/hif/src/regtable.c new file mode 100644 index 0000000000000000000000000000000000000000..19ede4afe9ba64f36d8a158e6369e1f89c21502e --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/hif/src/regtable.c @@ -0,0 +1,175 @@ +/* + * Copyright (c) 2013-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#include "targaddrs.h" +#include "cepci.h" +#include "regtable.h" +#include "ar6320def.h" +#include "ar6320v2def.h" +#include "hif_main.h" +#include "adrastea_reg_def.h" + +#include "targetdef.h" +#include "hostdef.h" + +void hif_target_register_tbl_attach(struct hif_softc *scn, u32 target_type) +{ + switch (target_type) { + case TARGET_TYPE_AR6320: + scn->targetdef = &ar6320_targetdef; + scn->target_ce_def = &ar6320_ce_targetdef; + break; + case TARGET_TYPE_AR6320V2: + scn->targetdef = &ar6320v2_targetdef; + scn->target_ce_def = &ar6320v2_ce_targetdef; + break; + case TARGET_TYPE_ADRASTEA: + scn->targetdef = &adrastea_targetdef; + scn->target_ce_def = &adrastea_ce_targetdef; + break; +#if defined(AR6002_HEADERS_DEF) + case TARGET_TYPE_AR6002: + scn->targetdef = AR6002_TARGETdef; + break; +#endif +#if defined(AR6003_HEADERS_DEF) + case TARGET_TYPE_AR6003: + scn->targetdef = AR6003_TARGETdef; + break; +#endif +#if defined(AR6004_HEADERS_DEF) + case TARGET_TYPE_AR6004: + scn->targetdef = AR6004_TARGETdef; + break; +#endif +#if defined(AR9888_HEADERS_DEF) + case TARGET_TYPE_AR9888: + scn->targetdef = AR9888_TARGETdef; + scn->target_ce_def = AR9888_CE_TARGETdef; + break; +#endif +#if defined(AR9888V2_HEADERS_DEF) + case TARGET_TYPE_AR9888V2: + scn->targetdef = AR9888V2_TARGETdef; + scn->target_ce_def = AR9888_CE_TARGETdef; + break; +#endif +#if defined(AR900B_HEADERS_DEF) + case TARGET_TYPE_AR900B: + scn->targetdef = AR900B_TARGETdef; + scn->target_ce_def = AR900B_CE_TARGETdef; + break; +#endif +#if defined(QCA9984_HEADERS_DEF) + case TARGET_TYPE_QCA9984: + scn->targetdef = QCA9984_TARGETdef; + scn->target_ce_def = QCA9984_CE_TARGETdef; + break; +#endif +#if defined(QCA9888_HEADERS_DEF) + case TARGET_TYPE_QCA9888: + scn->targetdef = QCA9888_TARGETdef; + scn->target_ce_def = QCA9888_CE_TARGETdef; + break; +#endif +#ifdef ATH_AHB +#if defined(IPQ4019_HEADERS_DEF) + case TARGET_TYPE_IPQ4019: + scn->targetdef = IPQ4019_TARGETdef; + scn->target_ce_def = IPQ4019_CE_TARGETdef; + break; +#endif +#endif + + default: + break; + } +} + +void hif_register_tbl_attach(struct hif_softc *scn, u32 hif_type) +{ + switch (hif_type) { + case HIF_TYPE_AR6320V2: + scn->hostdef = &ar6320v2_hostdef; + break; + case HIF_TYPE_ADRASTEA: + scn->hostdef = &adrastea_hostdef; + scn->host_shadow_regs = &adrastea_host_shadow_regs; + break; +#if defined(AR6002_HEADERS_DEF) + case HIF_TYPE_AR6002: + scn->hostdef = AR6002_HOSTdef; + break; +#endif +#if defined(AR6003_HEADERS_DEF) + case HIF_TYPE_AR6003: + scn->hostdef = AR6003_HOSTdef; + break; +#endif +#if defined(AR6004_HEADERS_DEF) + case HIF_TYPE_AR6004: + scn->hostdef = AR6004_HOSTdef; + break; +#endif +#if defined(AR9888_HEADERS_DEF) + case HIF_TYPE_AR9888: + scn->hostdef = AR9888_HOSTdef; + break; +#endif +#if defined(AR9888V2_HEADERS_DEF) + case HIF_TYPE_AR9888V2: + scn->hostdef = AR9888V2_HOSTdef; + break; +#endif +#if defined(AR900B_HEADERS_DEF) + case HIF_TYPE_AR900B: + scn->hostdef = AR900B_HOSTdef; + break; +#endif +#if defined(QCA9984_HEADERS_DEF) + case HIF_TYPE_QCA9984: + scn->hostdef = QCA9984_HOSTdef; + break; +#endif +#if defined(QCA9888_HEADERS_DEF) + case HIF_TYPE_QCA9888: + scn->hostdef = QCA9888_HOSTdef; + break; +#endif + +#ifdef ATH_AHB +#if defined(IPQ4019_HEADERS_DEF) + case HIF_TYPE_IPQ4019: + scn->hostdef = IPQ4019_HOSTdef; + break; +#endif +#endif + + default: + break; + } +} diff --git a/drivers/staging/qca-wifi-host-cmn/hif/src/sdio/hif_bmi_reg_access.c b/drivers/staging/qca-wifi-host-cmn/hif/src/sdio/hif_bmi_reg_access.c new file mode 100644 index 0000000000000000000000000000000000000000..26f653fdcc4e3a3fb73393aa3c312c943d340750 --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/hif/src/sdio/hif_bmi_reg_access.c @@ -0,0 +1,527 @@ +/* + * Copyright (c) 2013-2016 The Linux Foundation. All rights reserved. + * + ***Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#include "athdefs.h" +#include "a_types.h" +#include "a_osapi.h" +#define ATH_MODULE_NAME hif +#include "a_debug.h" +#define ATH_DEBUG_BMI ATH_DEBUG_MAKE_MODULE_MASK(0) +#include "hif.h" +#include "bmi.h" +#include "htc_api.h" +#include "if_sdio.h" +#include "regtable_sdio.h" + +#define BMI_COMMUNICATION_TIMEOUT 100000 + +static bool pending_events_func_check; +static uint32_t command_credits; +static uint32_t *p_bmi_cmd_credits = &command_credits; +/* BMI Access routines */ + +/** + * hif_bmi_buffer_send - call to send bmi buffer + * @device: hif context + * @buffer: buffer + * @length: length + * + * Return: QDF_STATUS_SUCCESS for success. + */ +static QDF_STATUS +hif_bmi_buffer_send(struct hif_sdio_dev *device, char *buffer, uint32_t length) +{ + QDF_STATUS status; + uint32_t timeout; + uint32_t address; + uint32_t mbox_address[HTC_MAILBOX_NUM_MAX]; + + hif_configure_device(device, HIF_DEVICE_GET_MBOX_ADDR, + &mbox_address[0], sizeof(mbox_address)); + + *p_bmi_cmd_credits = 0; + timeout = BMI_COMMUNICATION_TIMEOUT; + + while (timeout-- && !(*p_bmi_cmd_credits)) { + /* Read the counter register to get the command credits */ + address = + COUNT_DEC_ADDRESS + (HTC_MAILBOX_NUM_MAX + ENDPOINT1) * 4; + /* hit the credit counter with a 4-byte access, the first + * byte read will hit the counter and cause + * a decrement, while the remaining 3 bytes has no effect. + * The rationale behind this is to make all HIF accesses + * 4-byte aligned */ + status = + hif_read_write(device, address, + (uint8_t *) p_bmi_cmd_credits, 4, + HIF_RD_SYNC_BYTE_INC, NULL); + if (status != QDF_STATUS_SUCCESS) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + ("%s:Unable to decrement the credit count register\n", + __func__)); + return QDF_STATUS_E_FAILURE; + } + /* the counter is only 8=bits, ignore anything in the + *upper 3 bytes */ + (*p_bmi_cmd_credits) &= 0xFF; + } + + if (*p_bmi_cmd_credits) { + address = mbox_address[ENDPOINT1]; + status = hif_read_write(device, address, buffer, length, + HIF_WR_SYNC_BYTE_INC, NULL); + if (status != QDF_STATUS_SUCCESS) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + ("%s:Unable to send the BMI data to the device\n", + __func__)); + return QDF_STATUS_E_FAILURE; + } + } else { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + ("%s:BMI Communication timeout - hif_bmi_buffer_send\n", + __func__)); + return QDF_STATUS_E_FAILURE; + } + + return status; +} + +#if defined(SDIO_3_0) + +static QDF_STATUS +hif_bmi_read_write(struct hif_sdio_dev *device, + char *buffer, uint32_t length) +{ + QDF_STATUS status; + + status = hif_read_write(device, HOST_INT_STATUS_ADDRESS, + buffer, length, + HIF_RD_SYNC_BYTE_INC, NULL); + if (status != QDF_STATUS_SUCCESS) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + ("%s:Unable to read int status reg\n", + __func__)); + return QDF_STATUS_E_FAILURE; + } + *buffer = (HOST_INT_STATUS_MBOX_DATA_GET(*buffer) & (1 << ENDPOINT1)); + return status; +} +#else + +static QDF_STATUS +hif_bmi_read_write(struct hif_sdio_dev *device, + char *buffer, uint32_t length) +{ + QDF_STATUS status; + status = hif_read_write(device, RX_LOOKAHEAD_VALID_ADDRESS, + buffer, length, + HIF_RD_SYNC_BYTE_INC, NULL); + if (status != QDF_STATUS_SUCCESS) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + ("%s:Unable to read rx lookahead reg\n", + __func__)); + return QDF_STATUS_E_FAILURE; + } + *buffer &= (1 << ENDPOINT1); + return status; +} +#endif + +/** + * hif_bmi_buffer_receive - call when bmi buffer is received + * @device: hif context + * @buffer: buffer + * @length: length + * @want_timeout: timeout is needed or not + * + * Return: QDF_STATUS_SUCCESS for success. + */ +static QDF_STATUS +hif_bmi_buffer_receive(struct hif_sdio_dev *device, + char *buffer, uint32_t length, bool want_timeout) +{ + QDF_STATUS status; + uint32_t address; + uint32_t mbox_address[HTC_MAILBOX_NUM_MAX]; + struct _HIF_PENDING_EVENTS_INFO hif_pending_events; + static HIF_PENDING_EVENTS_FUNC get_pending_events_func; + + if (!pending_events_func_check) { + /* see if the HIF layer implements an alternative + * function to get pending events + * do this only once! */ + hif_configure_device(device, + HIF_DEVICE_GET_PENDING_EVENTS_FUNC, + &get_pending_events_func, + sizeof(get_pending_events_func)); + pending_events_func_check = true; + } + + hif_configure_device(device, HIF_DEVICE_GET_MBOX_ADDR, + &mbox_address[0], sizeof(mbox_address)); + + /* + * During normal bootup, small reads may be required. + * Rather than issue an HIF Read and then wait as the Target + * adds successive bytes to the FIFO, we wait here until + * we know that response data is available. + * + * This allows us to cleanly timeout on an unexpected + * Target failure rather than risk problems at the HIF level. In + * particular, this avoids SDIO timeouts and possibly garbage + * data on some host controllers. And on an interconnect + * such as Compact Flash (as well as some SDIO masters) which + * does not provide any indication on data timeout, it avoids + * a potential hang or garbage response. + * + * Synchronization is more difficult for reads larger than the + * size of the MBOX FIFO (128B), because the Target is unable + * to push the 129th byte of data until AFTER the Host posts an + * HIF Read and removes some FIFO data. So for large reads the + * Host proceeds to post an HIF Read BEFORE all the data is + * actually available to read. Fortunately, large BMI reads do + * not occur in practice -- they're supported for debug/development. + * + * So Host/Target BMI synchronization is divided into these cases: + * CASE 1: length < 4 + * Should not happen + * + * CASE 2: 4 <= length <= 128 + * Wait for first 4 bytes to be in FIFO + * If CONSERVATIVE_BMI_READ is enabled, also wait for + * a BMI command credit, which indicates that the ENTIRE + * response is available in the the FIFO + * + * CASE 3: length > 128 + * Wait for the first 4 bytes to be in FIFO + * + * For most uses, a small timeout should be sufficient and we will + * usually see a response quickly; but there may be some unusual + * (debug) cases of BMI_EXECUTE where we want an larger timeout. + * For now, we use an unbounded busy loop while waiting for + * BMI_EXECUTE. + * + * If BMI_EXECUTE ever needs to support longer-latency execution, + * especially in production, this code needs to be enhanced to sleep + * and yield. Also note that BMI_COMMUNICATION_TIMEOUT is currently + * a function of Host processor speed. + */ + if (length >= 4) { /* NB: Currently, always true */ + /* + * NB: word_available is declared static for esoteric reasons + * having to do with protection on some OSes. + */ + static uint32_t word_available; + uint32_t timeout; + + word_available = 0; + timeout = BMI_COMMUNICATION_TIMEOUT; + while ((!want_timeout || timeout--) && !word_available) { + + if (get_pending_events_func != NULL) { + status = get_pending_events_func(device, + &hif_pending_events, + NULL); + if (status != QDF_STATUS_SUCCESS) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + ("%s:Failed to get pending events\n", + __func__)); + break; + } + + if (hif_pending_events.available_recv_bytes >= + sizeof(uint32_t)) { + word_available = 1; + } + continue; + } + status = hif_bmi_read_write(device, + (uint8_t *) &word_available, + sizeof(word_available)); + if (status != QDF_STATUS_SUCCESS) + return QDF_STATUS_E_FAILURE; + } + + if (!word_available) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + ("%s:BMI Communication timeout FIFO empty\n", + __func__)); + return QDF_STATUS_E_FAILURE; + } + } + + address = mbox_address[ENDPOINT1]; + status = hif_read_write(device, address, buffer, length, + HIF_RD_SYNC_BYTE_INC, NULL); + if (status != QDF_STATUS_SUCCESS) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + ("%s:Unable to read the BMI data from the device\n", + __func__)); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * hif_reg_based_get_target_info - to retrieve target info + * @hif_ctx: hif context + * @targ_info: bmi target info + * + * Return: QDF_STATUS_SUCCESS for success. + */ +QDF_STATUS hif_reg_based_get_target_info(struct hif_opaque_softc *hif_ctx, + struct bmi_target_info + *targ_info) { + QDF_STATUS status; + uint32_t cid; + struct hif_sdio_softc *scn = HIF_GET_SDIO_SOFTC(hif_ctx); + struct hif_sdio_dev *device = scn->hif_handle; + + AR_DEBUG_PRINTF(ATH_DEBUG_BMI, + ("BMI Get Target Info: Enter (device: 0x%p)\n", + device)); + cid = BMI_GET_TARGET_INFO; + status = hif_bmi_buffer_send(device, (char *) &cid, sizeof(cid)); + if (status != QDF_STATUS_SUCCESS) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + ("%s:Unable to write to the device\n", + __func__)); + return QDF_STATUS_E_FAILURE; + } + + status = hif_bmi_buffer_receive(device, + (char *) &targ_info->target_ver, + sizeof(targ_info->target_ver), true); + if (status != QDF_STATUS_SUCCESS) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + ("%s:Unable to read Target Version from the device\n", + __func__)); + return QDF_STATUS_E_FAILURE; + } + + if (targ_info->target_ver == TARGET_VERSION_SENTINAL) { + /* Determine how many bytes are in the Target's targ_info */ + status = hif_bmi_buffer_receive(device, + (char *) &targ_info-> + target_info_byte_count, + sizeof(targ_info-> + target_info_byte_count), + true); + if (status != QDF_STATUS_SUCCESS) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + ("%s:Unable to read target Info\n", + __func__)); + return QDF_STATUS_E_FAILURE; + } + + /* + * The Target's targ_info doesn't match the Host's targ_info. + * We need to do some backwards compatibility work to make this + * OK.*/ + QDF_ASSERT(targ_info->target_info_byte_count == + sizeof(*targ_info)); + /* Read the remainder of the targ_info */ + status = hif_bmi_buffer_receive(device, + ((char *) targ_info) + + sizeof(targ_info-> + target_info_byte_count), + sizeof(*targ_info) - + sizeof(targ_info-> + target_info_byte_count), + true); + if (status != QDF_STATUS_SUCCESS) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + ("%s:Unable to read Target Info (%d bytes)\n", + __func__, targ_info->target_info_byte_count)); + return QDF_STATUS_E_FAILURE; + } + } else { + /* + * Target must be an AR6001 whose firmware does not + * support BMI_GET_TARGET_INFO. Construct the data + * that it would have sent. + */ + targ_info->target_info_byte_count = sizeof(*targ_info); + targ_info->target_type = TARGET_TYPE_AR6001; + } + + AR_DEBUG_PRINTF(ATH_DEBUG_BMI, + ("BMI Get Target Info: Exit (ver: 0x%x type: 0x%x)\n", + targ_info->target_ver, + targ_info->target_type)); + + return QDF_STATUS_SUCCESS; +} + +/** + * hif_exchange_bmi_msg - API to handle HIF-specific BMI message exchanges + * @hif_ctx: hif context + * @bmi_cmd_da: bmi cmd + * @bmi_rsp_da: bmi rsp + * @send_message: send message + * @length: length + * @response_message: response message + * @response_length: response length + * @timeout_ms: timeout in ms + * + * This API is synchronous + * and only allowed to be called from a context that can block (sleep) + * + * Return: QDF_STATUS_SUCCESS for success. + */ +QDF_STATUS hif_exchange_bmi_msg(struct hif_opaque_softc *hif_ctx, + qdf_dma_addr_t bmi_cmd_da, + qdf_dma_addr_t bmi_rsp_da, + uint8_t *send_message, + uint32_t length, + uint8_t *response_message, + uint32_t *response_length, + uint32_t timeout_ms) { + struct hif_sdio_softc *scn = HIF_GET_SDIO_SOFTC(hif_ctx); + struct hif_sdio_dev *device = scn->hif_handle; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + if (device == NULL) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + ("%s:Null device argument\n", + __func__)); + return QDF_STATUS_E_INVAL; + } + + status = hif_bmi_buffer_send(device, send_message, length); + if (QDF_IS_STATUS_ERROR(status)) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + ("%s:Unable to Send Message to device\n", + __func__)); + return status; + } + + if (response_message != NULL) { + status = hif_bmi_buffer_receive(device, response_message, + *response_length, + timeout_ms ? true : false); + if (QDF_IS_STATUS_ERROR(status)) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + ("%s:Unable to read response\n", + __func__)); + return status; + } + } + + return status; +} + +/** + * hif_bmi_raw_write - API to handle bmi raw buffer + * @device: hif context + * @buffer: buffer + * @length: length + * + * Return: QDF_STATUS_SUCCESS for success. + */ + +QDF_STATUS +hif_bmi_raw_write(struct hif_sdio_dev *device, char *buffer, + uint32_t length) { + return hif_bmi_buffer_send(device, buffer, length); +} + +/** + * hif_bmi_raw_read - call when bmi buffer is received + * @device: hif context + * @buffer: buffer + * @length: length + * @want_timeout: timeout is needed or not + * + * Return: QDF_STATUS_SUCCESS for success. + */ +QDF_STATUS +hif_bmi_raw_read(struct hif_sdio_dev *device, char *buffer, + uint32_t length, bool want_timeout) +{ + return hif_bmi_buffer_receive(device, buffer, length, + want_timeout); +} + +#ifdef BRINGUP_DEBUG +#define SDIO_SCRATCH_1_ADDRESS 0x864 +/*Functions used for debugging*/ +/** + * hif_bmi_write_scratch_register - API to write scratch register + * @device: hif context + * @buffer: buffer + * + * Return: QDF_STATUS_SUCCESS for success. + */ +QDF_STATUS hif_bmi_write_scratch_register(struct hif_sdio_dev *device, + uint32_t buffer) { + QDF_STATUS status = QDF_STATUS_SUCCESS; + + status = hif_read_write(device, SDIO_SCRATCH_1_ADDRESS, + (uint8_t *) &buffer, 4, + HIF_WR_SYNC_BYTE_INC, NULL); + if (status != QDF_STATUS_SUCCESS) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + ("%s: Unable to write to 0x%x\n", + __func__, SDIO_SCRATCH_1_ADDRESS)); + return QDF_STATUS_E_FAILURE; + } else { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + ("%s: wrote 0x%x to 0x%x\n", __func__, + buffer, SDIO_SCRATCH_1_ADDRESS)); + } + + return status; +} + +/** + * hif_bmi_read_scratch_register - API to read from scratch register + * @device: hif context + * + * Return: QDF_STATUS_SUCCESS for success. + */ +QDF_STATUS hif_bmi_read_scratch_register(struct hif_sdio_dev *device) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + uint32_t buffer = 0; + + status = hif_read_write(device, SDIO_SCRATCH_1_ADDRESS, + (uint8_t *) &buffer, 4, + HIF_RD_SYNC_BYTE_INC, NULL); + if (status != QDF_STATUS_SUCCESS) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + ("%s: Unable to read from 0x%x\n", + __func__, SDIO_SCRATCH_1_ADDRESS)); + return QDF_STATUS_E_FAILURE; + } else { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + ("%s: read 0x%x from 0x%x\n", __func__, + buffer, SDIO_SCRATCH_1_ADDRESS)); + } + + return status; +} +#endif diff --git a/drivers/staging/qca-wifi-host-cmn/hif/src/sdio/hif_diag_reg_access.c b/drivers/staging/qca-wifi-host-cmn/hif/src/sdio/hif_diag_reg_access.c new file mode 100644 index 0000000000000000000000000000000000000000..8d9e65b0c5f6e4ec19012e46813309b2c4cc47f3 --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/hif/src/sdio/hif_diag_reg_access.c @@ -0,0 +1,330 @@ +/* + * Copyright (c) 2013-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#include "athdefs.h" +#include "a_types.h" +#include "a_osapi.h" +#define ATH_MODULE_NAME hif +#include "a_debug.h" + +#include "targaddrs.h" +#include "hif.h" +#include "if_sdio.h" +#include "regtable_sdio.h" + +#define CPU_DBG_SEL_ADDRESS 0x00000483 +#define CPU_DBG_ADDRESS 0x00000484 +#define WORD_NON_ALIGNMENT_MASK 0x03 + +/** + * hif_ar6000_set_address_window_register - set the window address register (using 4-byte register access ). + * @hif_device: hif context + * @register_addr: register address + * @addr: addr + * + * This mitigates host interconnect issues with non-4byte aligned bus requests, + * some interconnects use bus adapters that impose strict limitations. + * Since diag window access is not intended for performance critical operations, + * the 4byte mode should be satisfactory as it generates 4X the bus activity. + * + * Return: QDF_STATUS_SUCCESS for success. + */ +static +QDF_STATUS hif_ar6000_set_address_window_register( + struct hif_sdio_dev *hif_device, + uint32_t register_addr, + uint32_t addr) +{ + QDF_STATUS status; + static uint32_t address; + + address = addr; + /*AR6320,just write the 4-byte address to window register*/ + status = hif_read_write(hif_device, + register_addr, + (char *) (&address), + 4, HIF_WR_SYNC_BYTE_INC, NULL); + + if (status != QDF_STATUS_SUCCESS) { + AR_DEBUG_PRINTF(ATH_LOG_ERR, + ("Cannot write 0x%x to window reg: 0x%X\n", + addr, register_addr)); + return status; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * hif_diag_read_access - Read from the AR6000 through its diagnostic window. + * @hif_ctx: hif context + * @address: address + * @data: data + * + * No cooperation from the Target is required for this. + * + * Return: QDF_STATUS_SUCCESS for success. + */ +QDF_STATUS hif_diag_read_access(struct hif_opaque_softc *hif_ctx, + uint32_t address, + uint32_t *data) +{ + QDF_STATUS status; + static uint32_t readvalue; + struct hif_sdio_softc *scn = HIF_GET_SDIO_SOFTC(hif_ctx); + struct hif_sdio_dev *hif_device = scn->hif_handle; + + if (address & WORD_NON_ALIGNMENT_MASK) { + AR_DEBUG_PRINTF(ATH_LOG_ERR, + ("[%s]addr is not 4 bytes align.addr[0x%08x]\n", + __func__, address)); + return QDF_STATUS_E_FAILURE; + } + + /* set window register to start read cycle */ + status = hif_ar6000_set_address_window_register(hif_device, + WINDOW_READ_ADDR_ADDRESS, + address); + + if (status != QDF_STATUS_SUCCESS) + return status; + + /* read the data */ + status = hif_read_write(hif_device, + WINDOW_DATA_ADDRESS, + (char *) &readvalue, + sizeof(uint32_t), HIF_RD_SYNC_BYTE_INC, NULL); + if (status != QDF_STATUS_SUCCESS) { + AR_DEBUG_PRINTF(ATH_LOG_ERR, + ("Cannot read from WINDOW_DATA_ADDRESS\n")); + return status; + } + + *data = readvalue; + return status; +} + +/** + * hif_diag_write_access - Write to the AR6000 through its diagnostic window. + * @hif_ctx: hif context + * @address: address + * @data: data + * + * No cooperation from the Target is required for this. + * + * Return: QDF_STATUS_SUCCESS for success. + */ +QDF_STATUS hif_diag_write_access(struct hif_opaque_softc *hif_ctx, + uint32_t address, uint32_t data) +{ + QDF_STATUS status; + static uint32_t write_value; + struct hif_sdio_softc *scn = HIF_GET_SDIO_SOFTC(hif_ctx); + struct hif_sdio_dev *hif_device = scn->hif_handle; + + if (address & WORD_NON_ALIGNMENT_MASK) { + AR_DEBUG_PRINTF(ATH_LOG_ERR, + ("[%s]addr is not 4 bytes align.addr[0x%08x]\n", + __func__, address)); + return QDF_STATUS_E_FAILURE; + } + + write_value = data; + + /* set write data */ + status = hif_read_write(hif_device, + WINDOW_DATA_ADDRESS, + (char *) &write_value, + sizeof(uint32_t), HIF_WR_SYNC_BYTE_INC, NULL); + if (status != QDF_STATUS_SUCCESS) { + AR_DEBUG_PRINTF(ATH_LOG_ERR, + ("Cannot write 0x%x to WINDOW_DATA_ADDRESS\n", + data)); + return status; + } + + /* set window register, which starts the write cycle */ + return hif_ar6000_set_address_window_register(hif_device, + WINDOW_WRITE_ADDR_ADDRESS, + address); +} + +/** + * hif_diag_write_mem - Write a block data to the AR6000 through its diagnostic window. + * @scn: hif context + * @address: address + * @data: data + * @nbytes: nbytes + * + * This function may take some time. + * No cooperation from the Target is required for this. + * + * Return: QDF_STATUS_SUCCESS for success. + */ +QDF_STATUS hif_diag_write_mem(struct hif_opaque_softc *scn, uint32_t address, + uint8_t *data, int nbytes) +{ + QDF_STATUS status; + int32_t i; + uint32_t tmp_data; + + if ((address & WORD_NON_ALIGNMENT_MASK) || + (nbytes & WORD_NON_ALIGNMENT_MASK)) { + AR_DEBUG_PRINTF(ATH_LOG_ERR, + ("[%s]addr or length is not 4 bytes" + " align.addr[0x%08x] len[0x%08x]\n", + __func__, address, nbytes)); + return QDF_STATUS_E_FAILURE; + } + + for (i = 0; i < nbytes; i += 4) { + tmp_data = + data[i] | (data[i + 1] << 8) | (data[i + 2] << 16) | + (data[i + 3] << 24); + status = hif_diag_write_access(scn, address + i, tmp_data); + if (status != QDF_STATUS_SUCCESS) { + AR_DEBUG_PRINTF(ATH_LOG_ERR, + ("Diag Write mem failed.addr[0x%08x]" + " value[0x%08x]\n", + address + i, tmp_data)); + return status; + } + } + + return QDF_STATUS_SUCCESS; +} + +/** + * hif_diag_read_mem - Read a block data to the AR6000 through its diagnostic window. + * @scn: hif context + * @data: data + * @nbytes: nbytes + * + * This function may take some time. + * No cooperation from the Target is required for this. + * + * Return: QDF_STATUS_SUCCESS for success. + */ +QDF_STATUS hif_diag_read_mem(struct hif_opaque_softc *scn, + uint32_t address, uint8_t *data, + int nbytes) +{ + QDF_STATUS status; + int32_t i; + uint32_t tmp_data; + + if ((address & WORD_NON_ALIGNMENT_MASK) || + (nbytes & WORD_NON_ALIGNMENT_MASK)) { + AR_DEBUG_PRINTF(ATH_LOG_ERR, + ("[%s]addr or length is not 4 bytes" + " align.addr[0x%08x] len[0x%08x]\n", + __func__, address, nbytes)); + return QDF_STATUS_E_FAILURE; + } + + for (i = 0; i < nbytes; i += 4) { + status = hif_diag_read_access(scn, address + i, &tmp_data); + if (status != QDF_STATUS_SUCCESS) { + AR_DEBUG_PRINTF(ATH_LOG_ERR, + ("Diag Write mem failed.addr[0x%08x]" + " value[0x%08x]\n", + address + i, tmp_data)); + return status; + } + data[i] = tmp_data & 0xff; + data[i + 1] = tmp_data >> 8 & 0xff; + data[i + 2] = tmp_data >> 16 & 0xff; + data[i + 3] = tmp_data >> 24 & 0xff; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * hif_ar6k_read_target_register - call to read target register values + * @hif_device: hif context + * @regsel: register selection + * @regval: reg value + * + * Return: QDF_STATUS_SUCCESS for success. + */ +QDF_STATUS hif_ar6k_read_target_register(struct hif_sdio_dev *hif_device, + int regsel, uint32_t *regval) +{ + QDF_STATUS status; + char vals[4]; + char register_selection[4]; + + register_selection[0] = regsel & 0xff; + register_selection[1] = regsel & 0xff; + register_selection[2] = regsel & 0xff; + register_selection[3] = regsel & 0xff; + status = hif_read_write(hif_device, CPU_DBG_SEL_ADDRESS, + register_selection, 4, + HIF_WR_SYNC_BYTE_FIX, NULL); + + if (status != QDF_STATUS_SUCCESS) { + AR_DEBUG_PRINTF(ATH_LOG_ERR, + ("Cannot write CPU_DBG_SEL (%d)\n", regsel)); + return status; + } + + status = hif_read_write(hif_device, + CPU_DBG_ADDRESS, + (char *) vals, + sizeof(vals), HIF_RD_SYNC_BYTE_INC, NULL); + if (status != QDF_STATUS_SUCCESS) { + AR_DEBUG_PRINTF(ATH_LOG_ERR, + ("Cannot read from CPU_DBG_ADDRESS\n")); + return status; + } + + *regval = vals[0] << 0 | vals[1] << 8 | + vals[2] << 16 | vals[3] << 24; + + return status; +} + +/** + * hif_ar6k_fetch_target_regs - call to fetch target reg values + * @hif_device: hif context + * @targregs: target regs + * + * Return: None + */ +void hif_ar6k_fetch_target_regs(struct hif_sdio_dev *hif_device, + uint32_t *targregs) +{ + int i; + uint32_t val; + + for (i = 0; i < AR6003_FETCH_TARG_REGS_COUNT; i++) { + val = 0xffffffff; + hif_ar6k_read_target_register(hif_device, i, &val); + targregs[i] = val; + } +} diff --git a/drivers/staging/qca-wifi-host-cmn/hif/src/sdio/hif_sdio.c b/drivers/staging/qca-wifi-host-cmn/hif/src/sdio/hif_sdio.c new file mode 100644 index 0000000000000000000000000000000000000000..218074555e2830cca30fa1ada45e0823911b65af --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/hif/src/sdio/hif_sdio.c @@ -0,0 +1,227 @@ +/* + * Copyright (c) 2013-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "qdf_net_types.h" +#include "a_types.h" +#include "athdefs.h" +#include "a_osapi.h" +#include +#include +#include +#include "hif_sdio_dev.h" +#include "if_sdio.h" +#include "regtable_sdio.h" + +#define ATH_MODULE_NAME hif_sdio + +/** + * hif_start() - start hif bus interface. + * @hif_ctx: HIF context + * + * Enables hif device interrupts + * + * Return: int + */ +uint32_t hif_start(struct hif_opaque_softc *hif_ctx) +{ + struct hif_sdio_softc *scn = HIF_GET_SDIO_SOFTC(hif_ctx); + struct hif_sdio_dev *hif_device = scn->hif_handle; + struct hif_sdio_device *htc_sdio_device = hif_dev_from_hif(hif_device); + + HIF_ENTER(); + hif_dev_enable_interrupts(htc_sdio_device); + HIF_EXIT(); + return QDF_STATUS_SUCCESS; +} + +/** + * hif_flush_surprise_remove() - remove hif bus interface. + * @hif_ctx: HIF context + * + * + * Return: none + */ +void hif_flush_surprise_remove(struct hif_opaque_softc *hif_ctx) +{ + +} + +/** + * hif_sdio_stop() - stop hif bus interface. + * @hif_ctx: HIF context + * + * Disable hif device interrupts and destroy hif context + * + * Return: none + */ +void hif_sdio_stop(struct hif_softc *hif_ctx) +{ + struct hif_sdio_softc *scn = HIF_GET_SDIO_SOFTC(hif_ctx); + struct hif_sdio_dev *hif_device = scn->hif_handle; + struct hif_sdio_device *htc_sdio_device = hif_dev_from_hif(hif_device); + + HIF_ENTER(); + if (htc_sdio_device != NULL) { + hif_dev_disable_interrupts(htc_sdio_device); + hif_dev_destroy(htc_sdio_device); + } + HIF_EXIT(); +} + +/** + * hif_send_head() - send data on hif bus interface. + * @hif_ctx: HIF context + * + * send tx data on a given pipe id + * + * Return: int + */ +QDF_STATUS hif_send_head(struct hif_opaque_softc *hif_ctx, uint8_t pipe, + uint32_t transfer_id, uint32_t nbytes, qdf_nbuf_t buf, + uint32_t data_attr) +{ + struct hif_sdio_softc *scn = HIF_GET_SDIO_SOFTC(hif_ctx); + struct hif_sdio_dev *hif_device = scn->hif_handle; + struct hif_sdio_device *htc_sdio_device = hif_dev_from_hif(hif_device); + + return hif_dev_send_buffer(htc_sdio_device, + transfer_id, pipe, + nbytes, buf); +} + +/** + * hif_map_service_to_pipe() - maps ul/dl pipe to service id. + * @hif_ctx: HIF hdl + * @ServiceId: sevice index + * @ULPipe: uplink pipe id + * @DLPipe: down-linklink pipe id + * @ul_is_polled: if ul is polling based + * @ul_is_polled: if dl is polling based + * + * Return: int + */ +int hif_map_service_to_pipe(struct hif_opaque_softc *hif_hdl, + uint16_t service_id, uint8_t *ul_pipe, + uint8_t *dl_pipe, int *ul_is_polled, + int *dl_is_polled) +{ + struct hif_sdio_softc *scn = HIF_GET_SDIO_SOFTC(hif_hdl); + struct hif_sdio_dev *hif_device = scn->hif_handle; + struct hif_sdio_device *htc_sdio_device = hif_dev_from_hif(hif_device); + + return hif_dev_map_service_to_pipe(htc_sdio_device, + service_id, ul_pipe, dl_pipe, + hif_device->swap_mailbox); +} + +/** + * hif_map_service_to_pipe() - maps ul/dl pipe to service id. + * @scn: HIF context + * @ServiceId: sevice index + * @ULPipe: uplink pipe id + * @DLPipe: down-linklink pipe id + * @ul_is_polled: if ul is polling based + * @ul_is_polled: if dl is polling based + * + * Return: int + */ +void hif_get_default_pipe(struct hif_opaque_softc *scn, uint8_t *ul_pipe, + uint8_t *dl_pipe) +{ + hif_map_service_to_pipe(scn, HTC_CTRL_RSVD_SVC, + ul_pipe, dl_pipe, NULL, NULL); +} + +/** + * hif_post_init() - create hif device after probe. + * @hif_ctx: HIF context + * @target: HIF target + * @callbacks: htc callbacks + * + * + * Return: int + */ +void hif_post_init(struct hif_opaque_softc *hif_ctx, void *target, + struct hif_msg_callbacks *callbacks) +{ + struct hif_sdio_softc *scn = HIF_GET_SDIO_SOFTC(hif_ctx); + struct hif_sdio_dev *hif_device = scn->hif_handle; + struct hif_sdio_device *htc_sdio_device = hif_dev_from_hif(hif_device); + + if (htc_sdio_device == NULL) + htc_sdio_device = hif_dev_create(hif_device, callbacks, target); + + if (htc_sdio_device) + hif_dev_setup(htc_sdio_device); + + return; +} + +/** + * hif_get_free_queue_number() - create hif device after probe. + * @hif_ctx: HIF context + * @pipe: pipe id + * + * SDIO uses credit based flow control at the HTC layer + * so transmit resource checks are bypassed + * Return: int + */ +uint16_t hif_get_free_queue_number(struct hif_opaque_softc *hif_ctx, + uint8_t pipe) +{ + uint16_t rv; + + rv = 1; + return rv; +} + +/** + * hif_send_complete_check() - check tx complete on a given pipe. + * @hif_ctx: HIF context + * @pipe: HIF target + * @force: check if need to pool for completion + * Decide whether to actually poll for completions, or just + * wait for a later chance. + * + * Return: int + */ +void hif_send_complete_check(struct hif_opaque_softc *hif_ctx, uint8_t pipe, + int force) +{ + +} diff --git a/drivers/staging/qca-wifi-host-cmn/hif/src/sdio/hif_sdio_common.h b/drivers/staging/qca-wifi-host-cmn/hif/src/sdio/hif_sdio_common.h new file mode 100644 index 0000000000000000000000000000000000000000..94e06aa9aa835a65f64cd6997c053a46b448a5a2 --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/hif/src/sdio/hif_sdio_common.h @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2013-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + + +#ifndef _HIF_SDIO_COMMON_H_ +#define _HIF_SDIO_COMMON_H_ + +/* SDIO manufacturer ID and Codes */ +#define MANUFACTURER_ID_AR6002_BASE 0x200 +#define MANUFACTURER_ID_AR6003_BASE 0x300 +#define MANUFACTURER_ID_AR6004_BASE 0x400 +#define MANUFACTURER_ID_AR6320_BASE 0x500 +#define MANUFACTURER_ID_QCA9377_BASE 0x700 +#define MANUFACTURER_ID_QCA9379_BASE 0x800 +#define MANUFACTURER_ID_AR6K_BASE_MASK 0xFF00 +#define MANUFACTURER_ID_AR6K_REV_MASK 0x00FF +#define FUNCTION_CLASS 0x0 +#define MANUFACTURER_CODE 0x271 + + /* Mailbox address in SDIO address space */ +#if defined(SDIO_3_0) +#define HIF_MBOX_BASE_ADDR 0x1000 +#define HIF_MBOX_DUMMY_WIDTH 0x800 +#else +#define HIF_MBOX_BASE_ADDR 0x800 +#define HIF_MBOX_DUMMY_WIDTH 0 +#endif + +#define HIF_MBOX_WIDTH 0x800 + +#define HIF_MBOX_START_ADDR(mbox) \ + (HIF_MBOX_BASE_ADDR + mbox * (HIF_MBOX_WIDTH + HIF_MBOX_DUMMY_WIDTH)) + +#define HIF_MBOX_END_ADDR(mbox) \ + (HIF_MBOX_START_ADDR(mbox) + HIF_MBOX_WIDTH - 1) + + /* extended MBOX address for larger MBOX writes to MBOX 0*/ +#if defined(SDIO_3_0) +#define HIF_MBOX0_EXTENDED_BASE_ADDR 0x5000 +#else +#define HIF_MBOX0_EXTENDED_BASE_ADDR 0x2800 +#endif +#define HIF_MBOX0_EXTENDED_WIDTH_AR6002 (6*1024) +#define HIF_MBOX0_EXTENDED_WIDTH_AR6003 (18*1024) + + /* version 1 of the chip has only a 12K extended mbox range */ +#define HIF_MBOX0_EXTENDED_BASE_ADDR_AR6003_V1 0x4000 +#define HIF_MBOX0_EXTENDED_WIDTH_AR6003_V1 (12*1024) + +#define HIF_MBOX0_EXTENDED_BASE_ADDR_AR6004 0x2800 +#define HIF_MBOX0_EXTENDED_WIDTH_AR6004 (18*1024) + + +#if defined(SDIO_3_0) +#define HIF_MBOX0_EXTENDED_BASE_ADDR_AR6320 0x5000 +#define HIF_MBOX0_EXTENDED_WIDTH_AR6320 (36*1024) +#define HIF_MBOX0_EXTENDED_WIDTH_AR6320_ROME_2_0 (56*1024) +#define HIF_MBOX1_EXTENDED_WIDTH_AR6320 (36*1024) +#define HIF_MBOX_DUMMY_SPACE_SIZE_AR6320 (2*1024) +#else +#define HIF_MBOX0_EXTENDED_BASE_ADDR_AR6320 0x2800 +#define HIF_MBOX0_EXTENDED_WIDTH_AR6320 (24*1024) +#define HIF_MBOX1_EXTENDED_WIDTH_AR6320 (24*1024) +#define HIF_MBOX_DUMMY_SPACE_SIZE_AR6320 0 +#endif + + + /* GMBOX addresses */ +#define HIF_GMBOX_BASE_ADDR 0x7000 +#define HIF_GMBOX_WIDTH 0x4000 + +/* for SDIO we recommend a 128-byte block size */ +#if defined(WITH_BACKPORTS) +#define HIF_DEFAULT_IO_BLOCK_SIZE 128 +#else +#define HIF_DEFAULT_IO_BLOCK_SIZE 256 +#endif + +#define FIFO_TIMEOUT_AND_CHIP_CONTROL 0x00000868 +#define FIFO_TIMEOUT_AND_CHIP_CONTROL_DISABLE_SLEEP_OFF 0xFFFEFFFF +#define FIFO_TIMEOUT_AND_CHIP_CONTROL_DISABLE_SLEEP_ON 0x10000 +/* In SDIO 2.0, asynchronous interrupt is not in SPEC + * requirement, but AR6003 support it, so the register + * is placed in vendor specific field 0xF0(bit0) + * In SDIO 3.0, the register is defined in SPEC, and its + * address is 0x16(bit1) */ +/* interrupt mode register of AR6003 */ +#define CCCR_SDIO_IRQ_MODE_REG_AR6003 0xF0 +/* mode to enable special 4-bit interrupt assertion without clock */ +#define SDIO_IRQ_MODE_ASYNC_4BIT_IRQ_AR6003 (1 << 0) + /* interrupt mode register of AR6320 */ +#define CCCR_SDIO_IRQ_MODE_REG_AR6320 0x16 +/* mode to enable special 4-bit interrupt assertion without clock */ +#define SDIO_IRQ_MODE_ASYNC_4BIT_IRQ_AR6320 (1 << 1) + +#define CCCR_SDIO_ASYNC_INT_DELAY_ADDRESS 0xF0 +#define CCCR_SDIO_ASYNC_INT_DELAY_LSB 0x06 +#define CCCR_SDIO_ASYNC_INT_DELAY_MASK 0xC0 + +/* Vendor Specific Driver Strength Settings */ +#define CCCR_SDIO_DRIVER_STRENGTH_ENABLE_ADDR 0xf2 +#define CCCR_SDIO_DRIVER_STRENGTH_ENABLE_MASK 0x0e +#define CCCR_SDIO_DRIVER_STRENGTH_ENABLE_A 0x02 +#define CCCR_SDIO_DRIVER_STRENGTH_ENABLE_C 0x04 +#define CCCR_SDIO_DRIVER_STRENGTH_ENABLE_D 0x08 + +#endif /* _HIF_SDIO_COMMON_H_ */ diff --git a/drivers/staging/qca-wifi-host-cmn/hif/src/sdio/hif_sdio_dev.c b/drivers/staging/qca-wifi-host-cmn/hif/src/sdio/hif_sdio_dev.c new file mode 100644 index 0000000000000000000000000000000000000000..b427148be85bb85a857b4c7cf319304db814c621 --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/hif/src/sdio/hif_sdio_dev.c @@ -0,0 +1,524 @@ +/* + * Copyright (c) 2013-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#define ATH_MODULE_NAME hif +#include "a_debug.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "hif_sdio_internal.h" +#include "if_sdio.h" +#include "regtable_sdio.h" + +/* under HL SDIO, with Interface Memory support, we have + * the following reasons to support 2 mboxs: + * a) we need place different buffers in different + * mempool, for example, data using Interface Memory, + * desc and other using DRAM, they need different SDIO + * mbox channels. + * b) currently, tx mempool in LL case is seperated from + * main mempool, the structure (descs at the beginning + * of every pool buffer) is different, because they only + * need store tx desc from host. To align with LL case, + * we also need 2 mbox support just as PCIe LL cases. + */ + +#define INVALID_MAILBOX_NUMBER 0xFF +/** + * hif_dev_map_pipe_to_mail_box() - maps pipe id to mailbox. + * @pdev: sdio device context + * @pipeid: pipe index + * + * + * Return: mailbox index + */ +uint8_t hif_dev_map_pipe_to_mail_box(struct hif_sdio_device *pdev, + uint8_t pipeid) +{ + /* TODO: temp version, should not hardcoded here, will be + * updated after HIF design */ + if (2 == pipeid || 3 == pipeid) + return 1; + else if (0 == pipeid || 1 == pipeid) + return 0; + else { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + ("%s: pipeid=%d,should not happen\n", + __func__, pipeid)); + qdf_assert(0); + return INVALID_MAILBOX_NUMBER; + } +} + +/** + * hif_dev_map_mail_box_to_pipe() - map sdio mailbox to htc pipe. + * @pdev: sdio device + * @mboxIndex: mailbox index + * @upload: boolean to decide mailbox index + * + * Disable hif device interrupts and destroy hif context + * + * Return: none + */ +uint8_t hif_dev_map_mail_box_to_pipe(struct hif_sdio_device *pdev, + uint8_t mbox_index, + bool upload) +{ + /* TODO: temp version, should not hardcoded here, will be + * updated after HIF design */ + if (mbox_index == 0) { + return upload ? 1 : 0; + } else if (mbox_index == 1) { + return upload ? 3 : 2; + } else { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + ("%s:--------------------mboxIndex=%d,upload=%d," + " should not happen\n", + __func__, mbox_index, upload)); + qdf_assert(0); + return 0xff; + } +} + +/** + * hif_dev_map_service_to_pipe() - maps ul/dl pipe to service id. + * @pDev: sdio device context + * @ServiceId: sevice index + * @ULPipe: uplink pipe id + * @DLPipe: down-linklink pipe id + * @SwapMapping: mailbox swap mapping + * + * Return: int + */ +QDF_STATUS hif_dev_map_service_to_pipe(struct hif_sdio_device *pdev, + uint16_t service_id, + uint8_t *ul_pipe, uint8_t *dl_pipe, + bool swap_mapping) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + switch (service_id) { + case HTT_DATA_MSG_SVC: + if (swap_mapping) { + *ul_pipe = 1; + *dl_pipe = 0; + } else { + *ul_pipe = 3; + *dl_pipe = 2; + } + break; + + case HTC_CTRL_RSVD_SVC: + case HTC_RAW_STREAMS_SVC: + *ul_pipe = 1; + *dl_pipe = 0; + break; + + case WMI_DATA_BE_SVC: + case WMI_DATA_BK_SVC: + case WMI_DATA_VI_SVC: + case WMI_DATA_VO_SVC: + *ul_pipe = 1; + *dl_pipe = 0; + break; + + case WMI_CONTROL_SVC: + if (swap_mapping) { + *ul_pipe = 3; + *dl_pipe = 2; + } else { + *ul_pipe = 1; + *dl_pipe = 0; + } + break; + + default: + status = !QDF_STATUS_SUCCESS; + break; + } + return status; +} + +/** + * hif_dev_alloc_rx_buffer() - allocate rx buffer. + * @pDev: sdio device context + * + * + * Return: htc buffer pointer + */ +HTC_PACKET *hif_dev_alloc_rx_buffer(struct hif_sdio_device *pdev) +{ + HTC_PACKET *packet; + qdf_nbuf_t netbuf; + uint32_t bufsize = 0, headsize = 0; + + bufsize = HIF_SDIO_RX_BUFFER_SIZE + HIF_SDIO_RX_DATA_OFFSET; + headsize = sizeof(HTC_PACKET); + netbuf = qdf_nbuf_alloc(NULL, bufsize + headsize, 0, 4, false); + if (netbuf == NULL) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + ("(%s)Allocate netbuf failed\n", __func__)); + return NULL; + } + packet = (HTC_PACKET *) qdf_nbuf_data(netbuf); + qdf_nbuf_reserve(netbuf, headsize); + + SET_HTC_PACKET_INFO_RX_REFILL(packet, + pdev, + qdf_nbuf_data(netbuf), + bufsize, ENDPOINT_0); + SET_HTC_PACKET_NET_BUF_CONTEXT(packet, netbuf); + return packet; +} + +/** + * hif_dev_create() - create hif device after probe. + * @scn: HIF context + * @callbacks: htc callbacks + * @target: HIF target + * + * + * Return: int + */ +struct hif_sdio_device *hif_dev_create(struct hif_sdio_dev *hif_device, + struct hif_msg_callbacks *callbacks, void *target) +{ + + QDF_STATUS status; + struct hif_sdio_device *pdev; + + pdev = qdf_mem_malloc(sizeof(struct hif_sdio_device)); + if (!pdev) { + A_ASSERT(false); + return NULL; + } + + qdf_spinlock_create(&pdev->Lock); + qdf_spinlock_create(&pdev->TxLock); + qdf_spinlock_create(&pdev->RxLock); + + pdev->HIFDevice = hif_device; + pdev->pTarget = target; + status = hif_configure_device(hif_device, + HIF_DEVICE_SET_HTC_CONTEXT, + (void *)pdev, sizeof(pdev)); + if (status != QDF_STATUS_SUCCESS) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + ("(%s)HIF_DEVICE_SET_HTC_CONTEXT failed!!!\n", + __func__)); + } + + A_MEMCPY(&pdev->hif_callbacks, callbacks, sizeof(*callbacks)); + + return pdev; +} + +/** + * hif_dev_destroy() - destroy hif device. + * @pDev: sdio device context + * + * + * Return: none + */ +void hif_dev_destroy(struct hif_sdio_device *pdev) +{ + QDF_STATUS status; + + status = hif_configure_device(pdev->HIFDevice, + HIF_DEVICE_SET_HTC_CONTEXT, + (void *)NULL, 0); + if (status != QDF_STATUS_SUCCESS) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + ("(%s)HIF_DEVICE_SET_HTC_CONTEXT failed!!!\n", + __func__)); + } + qdf_mem_free(pdev); +} + +/** + * hif_dev_from_hif() - get sdio device from hif device. + * @pDev: hif device context + * + * + * Return: hif sdio device context + */ +struct hif_sdio_device *hif_dev_from_hif(struct hif_sdio_dev *hif_device) +{ + struct hif_sdio_device *pdev = NULL; + QDF_STATUS status; + status = hif_configure_device(hif_device, + HIF_DEVICE_GET_HTC_CONTEXT, + (void **)&pdev, sizeof(struct hif_sdio_device)); + if (status != QDF_STATUS_SUCCESS) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + ("(%s)HTC_SDIO_CONTEXT is NULL!!!\n", + __func__)); + } + return pdev; +} + +/** + * hif_dev_disable_interrupts() - disable hif device interrupts. + * @pDev: sdio device context + * + * + * Return: int + */ +QDF_STATUS hif_dev_disable_interrupts(struct hif_sdio_device *pdev) +{ + struct MBOX_IRQ_ENABLE_REGISTERS regs; + QDF_STATUS status = QDF_STATUS_SUCCESS; + HIF_ENTER(); + + LOCK_HIF_DEV(pdev); + /* Disable all interrupts */ + pdev->IrqEnableRegisters.int_status_enable = 0; + pdev->IrqEnableRegisters.cpu_int_status_enable = 0; + pdev->IrqEnableRegisters.error_status_enable = 0; + pdev->IrqEnableRegisters.counter_int_status_enable = 0; + /* copy into our temp area */ + A_MEMCPY(®s, + &pdev->IrqEnableRegisters, sizeof(pdev->IrqEnableRegisters)); + + UNLOCK_HIF_DEV(pdev); + + /* always synchronous */ + status = hif_read_write(pdev->HIFDevice, + INT_STATUS_ENABLE_ADDRESS, + (char *) ®s, + sizeof(struct MBOX_IRQ_ENABLE_REGISTERS), + HIF_WR_SYNC_BYTE_INC, NULL); + + if (status != QDF_STATUS_SUCCESS) { + /* Can't write it for some reason */ + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + ("Failed to update interrupt control registers err: %d", + status)); + } + + /* To Do mask the host controller interrupts */ + hif_mask_interrupt(pdev->HIFDevice); + HIF_EXIT("status :%d", status); + return status; +} + +/** + * hif_dev_enable_interrupts() - enables hif device interrupts. + * @pDev: sdio device context + * + * + * Return: int + */ +QDF_STATUS hif_dev_enable_interrupts(struct hif_sdio_device *pdev) +{ + QDF_STATUS status; + struct MBOX_IRQ_ENABLE_REGISTERS regs; + HIF_ENTER(); + + /* for good measure, make sure interrupt are disabled + * before unmasking at the HIF layer. + * The rationale here is that between device insertion + * (where we clear the interrupts the first time) + * and when HTC is finally ready to handle interrupts, + * other software can perform target "soft" resets. + * The AR6K interrupt enables reset back to an "enabled" + * state when this happens. */ + hif_dev_disable_interrupts(pdev); + + /* Unmask the host controller interrupts */ + hif_un_mask_interrupt(pdev->HIFDevice); + + LOCK_HIF_DEV(pdev); + + /* Enable all the interrupts except for the internal + * AR6000 CPU interrupt */ + pdev->IrqEnableRegisters.int_status_enable = + INT_STATUS_ENABLE_ERROR_SET(0x01) | + INT_STATUS_ENABLE_CPU_SET(0x01) + | INT_STATUS_ENABLE_COUNTER_SET(0x01); + + /* enable 2 mboxs INT */ + pdev->IrqEnableRegisters.int_status_enable |= + INT_STATUS_ENABLE_MBOX_DATA_SET(0x01) | + INT_STATUS_ENABLE_MBOX_DATA_SET(0x02); + + /* Set up the CPU Interrupt Status Register, enable + * CPU sourced interrupt #0, #1. + * #0 is used for report assertion from target + * #1 is used for inform host that credit arrived + * */ + pdev->IrqEnableRegisters.cpu_int_status_enable = 0x03; + + /* Set up the Error Interrupt Status Register */ + pdev->IrqEnableRegisters.error_status_enable = + (ERROR_STATUS_ENABLE_RX_UNDERFLOW_SET(0x01) + | ERROR_STATUS_ENABLE_TX_OVERFLOW_SET(0x01)) >> 16; + + /* Set up the Counter Interrupt Status Register + * (only for debug interrupt to catch fatal errors) */ + pdev->IrqEnableRegisters.counter_int_status_enable = + (COUNTER_INT_STATUS_ENABLE_BIT_SET(AR6K_TARGET_DEBUG_INTR_MASK)) >> + 24; + + /* copy into our temp area */ + A_MEMCPY(®s, + &pdev->IrqEnableRegisters, + sizeof(struct MBOX_IRQ_ENABLE_REGISTERS)); + + UNLOCK_HIF_DEV(pdev); + + /* always synchronous */ + status = hif_read_write(pdev->HIFDevice, + INT_STATUS_ENABLE_ADDRESS, + (char *) ®s, + sizeof(struct MBOX_IRQ_ENABLE_REGISTERS), + HIF_WR_SYNC_BYTE_INC, NULL); + + if (status != QDF_STATUS_SUCCESS) { + /* Can't write it for some reason */ + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + ("Failed to update interrupt control registers err: %d\n", + status)); + + } + HIF_EXIT(); + return status; +} + +/** + * hif_dev_setup() - set up sdio device. + * @pDev: sdio device context + * + * + * Return: int + */ +QDF_STATUS hif_dev_setup(struct hif_sdio_device *pdev) +{ + QDF_STATUS status; + uint32_t blocksizes[MAILBOX_COUNT]; + HTC_CALLBACKS htc_callbacks; + struct hif_sdio_dev *hif_device = pdev->HIFDevice; + + HIF_ENTER(); + + status = hif_configure_device(hif_device, + HIF_DEVICE_GET_MBOX_ADDR, + &pdev->MailBoxInfo, + sizeof(pdev->MailBoxInfo)); + + if (status != QDF_STATUS_SUCCESS) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + ("(%s)HIF_DEVICE_GET_MBOX_ADDR failed!!!\n", + __func__)); + A_ASSERT(false); + } + + status = hif_configure_device(hif_device, + HIF_DEVICE_GET_MBOX_BLOCK_SIZE, + blocksizes, sizeof(blocksizes)); + if (status != QDF_STATUS_SUCCESS) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + ("(%s)HIF_DEVICE_GET_MBOX_BLOCK_SIZE failed!!!\n", + __func__)); + A_ASSERT(false); + } + + pdev->BlockSize = blocksizes[MAILBOX_FOR_BLOCK_SIZE]; + pdev->BlockMask = pdev->BlockSize - 1; + A_ASSERT((pdev->BlockSize & pdev->BlockMask) == 0); + + /* assume we can process HIF interrupt events asynchronously */ + pdev->HifIRQProcessingMode = HIF_DEVICE_IRQ_ASYNC_SYNC; + + /* see if the HIF layer overrides this assumption */ + hif_configure_device(hif_device, + HIF_DEVICE_GET_IRQ_PROC_MODE, + &pdev->HifIRQProcessingMode, + sizeof(pdev->HifIRQProcessingMode)); + + switch (pdev->HifIRQProcessingMode) { + case HIF_DEVICE_IRQ_SYNC_ONLY: + AR_DEBUG_PRINTF(ATH_DEBUG_WARN, + ("HIF Interrupt processing is SYNC ONLY\n")); + /* see if HIF layer wants HTC to yield */ + hif_configure_device(hif_device, + HIF_DEVICE_GET_IRQ_YIELD_PARAMS, + &pdev->HifIRQYieldParams, + sizeof(pdev->HifIRQYieldParams)); + + if (pdev->HifIRQYieldParams.recv_packet_yield_count > 0) { + AR_DEBUG_PRINTF(ATH_DEBUG_WARN, + ("HIF req of DSR yield per %d RECV packets\n", + pdev->HifIRQYieldParams. + recv_packet_yield_count)); + pdev->DSRCanYield = true; + } + break; + case HIF_DEVICE_IRQ_ASYNC_SYNC: + AR_DEBUG_PRINTF(ATH_DEBUG_TRC, + ("HIF Interrupt processing is ASYNC and SYNC\n")); + break; + default: + A_ASSERT(false); + break; + } + + pdev->HifMaskUmaskRecvEvent = NULL; + + /* see if the HIF layer implements the mask/unmask recv + * events function */ + hif_configure_device(hif_device, + HIF_DEVICE_GET_RECV_EVENT_MASK_UNMASK_FUNC, + &pdev->HifMaskUmaskRecvEvent, + sizeof(pdev->HifMaskUmaskRecvEvent)); + + status = hif_dev_disable_interrupts(pdev); + + qdf_mem_zero(&htc_callbacks, sizeof(HTC_CALLBACKS)); + /* the device layer handles these */ + htc_callbacks.rwCompletionHandler = hif_dev_rw_completion_handler; + htc_callbacks.dsrHandler = hif_dev_dsr_handler; + htc_callbacks.context = pdev; + status = hif_attach_htc(pdev->HIFDevice, &htc_callbacks); + + HIF_EXIT(); + return status; +} diff --git a/drivers/staging/qca-wifi-host-cmn/hif/src/sdio/hif_sdio_dev.h b/drivers/staging/qca-wifi-host-cmn/hif/src/sdio/hif_sdio_dev.h new file mode 100644 index 0000000000000000000000000000000000000000..e639febf27625bbb9ba25d8a43b56c81799346da --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/hif/src/sdio/hif_sdio_dev.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2013-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef HIF_SDIO_DEV_H_ +#define HIF_SDIO_DEV_H_ + +#include "qdf_net_types.h" +#include "a_types.h" +#include "athdefs.h" +#include "a_osapi.h" +#include +#include "athstartpack.h" +#include "hif_internal.h" + +struct hif_sdio_device *hif_dev_from_hif(struct hif_sdio_dev *hif_device); + +struct hif_sdio_device *hif_dev_create(struct hif_sdio_dev *hif_device, + struct hif_msg_callbacks *callbacks, + void *target); + +void hif_dev_destroy(struct hif_sdio_device *htc_sdio_device); + +QDF_STATUS hif_dev_setup(struct hif_sdio_device *htc_sdio_device); + +QDF_STATUS hif_dev_enable_interrupts(struct hif_sdio_device *htc_sdio_device); + +QDF_STATUS hif_dev_disable_interrupts(struct hif_sdio_device *htc_sdio_device); + +QDF_STATUS hif_dev_send_buffer(struct hif_sdio_device *htc_sdio_device, + unsigned int transfer_id, uint8_t pipe, + unsigned int nbytes, qdf_nbuf_t buf); + +QDF_STATUS hif_dev_map_service_to_pipe(struct hif_sdio_device *pdev, + uint16_t service_id, + uint8_t *ul_pipe, + uint8_t *dl_pipe, + bool swap_mapping); + +#endif /* HIF_SDIO_DEV_H_ */ diff --git a/drivers/staging/qca-wifi-host-cmn/hif/src/sdio/hif_sdio_internal.h b/drivers/staging/qca-wifi-host-cmn/hif/src/sdio/hif_sdio_internal.h new file mode 100644 index 0000000000000000000000000000000000000000..60d14d101ea425d1b5e09fcc33df95204ff101af --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/hif/src/sdio/hif_sdio_internal.h @@ -0,0 +1,156 @@ +/* + * Copyright (c) 2013-2014, 2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef _HIF_SDIO_INTERNAL_H_ +#define _HIF_SDIO_INTERNAL_H_ + +#include "a_debug.h" +#include "hif_sdio_dev.h" +#include "htc_packet.h" +#include "htc_api.h" +#include "hif_internal.h" + +#define HIF_SDIO_RX_BUFFER_SIZE 1792 +#define HIF_SDIO_RX_DATA_OFFSET 64 + +/* TODO: print output level and mask control */ +#define ATH_DEBUG_IRQ ATH_DEBUG_MAKE_MODULE_MASK(4) +#define ATH_DEBUG_XMIT ATH_DEBUG_MAKE_MODULE_MASK(5) +#define ATH_DEBUG_RECV ATH_DEBUG_MAKE_MODULE_MASK(6) + +#define ATH_DEBUG_MAX_MASK 32 + +#define OTHER_INTS_ENABLED (INT_STATUS_ENABLE_ERROR_MASK | \ + INT_STATUS_ENABLE_CPU_MASK | \ + INT_STATUS_ENABLE_COUNTER_MASK) + +/* HTC operational parameters */ +#define HTC_TARGET_RESPONSE_TIMEOUT 2000 /* in ms */ +#define HTC_TARGET_DEBUG_INTR_MASK 0x01 +#define HTC_TARGET_CREDIT_INTR_MASK 0xF0 + +#define MAILBOX_COUNT 4 +#define MAILBOX_FOR_BLOCK_SIZE 1 +#define MAILBOX_USED_COUNT 2 +#if defined(SDIO_3_0) +#define MAILBOX_LOOKAHEAD_SIZE_IN_WORD 2 +#else +#define MAILBOX_LOOKAHEAD_SIZE_IN_WORD 1 +#endif +#define AR6K_TARGET_DEBUG_INTR_MASK 0x01 + +PREPACK struct MBOX_IRQ_PROC_REGISTERS { + uint8_t host_int_status; + uint8_t cpu_int_status; + uint8_t error_int_status; + uint8_t counter_int_status; + uint8_t mbox_frame; + uint8_t rx_lookahead_valid; + uint8_t host_int_status2; + uint8_t gmbox_rx_avail; + uint32_t rx_lookahead[MAILBOX_LOOKAHEAD_SIZE_IN_WORD * MAILBOX_COUNT]; + uint32_t int_status_enable; +} POSTPACK; + +PREPACK struct MBOX_IRQ_ENABLE_REGISTERS { + uint8_t int_status_enable; + uint8_t cpu_int_status_enable; + uint8_t error_status_enable; + uint8_t counter_int_status_enable; +} POSTPACK; + +#define TOTAL_CREDIT_COUNTER_CNT 4 + +PREPACK struct MBOX_COUNTER_REGISTERS { + uint32_t counter[TOTAL_CREDIT_COUNTER_CNT]; +} POSTPACK; + +#define SDIO_NUM_DATA_RX_BUFFERS 64 +#define SDIO_DATA_RX_SIZE 1664 + +struct hif_sdio_device { + struct hif_sdio_dev *HIFDevice; + qdf_spinlock_t Lock; + qdf_spinlock_t TxLock; + qdf_spinlock_t RxLock; + struct MBOX_IRQ_PROC_REGISTERS IrqProcRegisters; + struct MBOX_IRQ_ENABLE_REGISTERS IrqEnableRegisters; + struct MBOX_COUNTER_REGISTERS MailBoxCounterRegisters; + struct hif_msg_callbacks hif_callbacks; + struct hif_device_mbox_info MailBoxInfo; + uint32_t BlockSize; + uint32_t BlockMask; + enum hif_device_irq_mode HifIRQProcessingMode; + struct hif_device_irq_yield_params HifIRQYieldParams; + bool DSRCanYield; + HIF_MASK_UNMASK_RECV_EVENT HifMaskUmaskRecvEvent; + int CurrentDSRRecvCount; + int RecheckIRQStatusCnt; + uint32_t RecvStateFlags; + void *pTarget; +}; + +#define LOCK_HIF_DEV(device) qdf_spin_lock(&(device)->Lock); +#define UNLOCK_HIF_DEV(device) qdf_spin_unlock(&(device)->Lock); +#define LOCK_HIF_DEV_RX(t) qdf_spin_lock(&(t)->RxLock); +#define UNLOCK_HIF_DEV_RX(t) qdf_spin_unlock(&(t)->RxLock); +#define LOCK_HIF_DEV_TX(t) qdf_spin_lock(&(t)->TxLock); +#define UNLOCK_HIF_DEV_TX(t) qdf_spin_unlock(&(t)->TxLock); + +#define DEV_CALC_RECV_PADDED_LEN(pDev, length) \ + (((length) + (pDev)->BlockMask) & (~((pDev)->BlockMask))) +#define DEV_CALC_SEND_PADDED_LEN(pDev, length) \ + DEV_CALC_RECV_PADDED_LEN(pDev, length) +#define DEV_IS_LEN_BLOCK_ALIGNED(pDev, length) \ + (((length) % (pDev)->BlockSize) == 0) + +#define HTC_RECV_WAIT_BUFFERS (1 << 0) +#define HTC_OP_STATE_STOPPING (1 << 0) + +#define HTC_RX_PKT_IGNORE_LOOKAHEAD (1 << 0) +#define HTC_RX_PKT_REFRESH_HDR (1 << 1) +#define HTC_RX_PKT_PART_OF_BUNDLE (1 << 2) +#define HTC_RX_PKT_NO_RECYCLE (1 << 3) +#define HTC_RX_PKT_LAST_BUNDLED_PKT_HAS_ADDTIONAL_BLOCK (1 << 4) + +#define IS_DEV_IRQ_PROCESSING_ASYNC_ALLOWED(pDev) \ + ((pDev)->HifIRQProcessingMode != HIF_DEVICE_IRQ_SYNC_ONLY) + +/* hif_sdio_dev.c */ +HTC_PACKET *hif_dev_alloc_rx_buffer(struct hif_sdio_device *pDev); + +uint8_t hif_dev_map_pipe_to_mail_box(struct hif_sdio_device *pDev, + uint8_t pipeid); +uint8_t hif_dev_map_mail_box_to_pipe(struct hif_sdio_device *pDev, + uint8_t mboxIndex, + bool upload); + +/* hif_sdio_recv.c */ +QDF_STATUS hif_dev_rw_completion_handler(void *context, QDF_STATUS status); +QDF_STATUS hif_dev_dsr_handler(void *context); + +#endif /* _HIF_SDIO_INTERNAL_H_ */ diff --git a/drivers/staging/qca-wifi-host-cmn/hif/src/sdio/hif_sdio_recv.c b/drivers/staging/qca-wifi-host-cmn/hif/src/sdio/hif_sdio_recv.c new file mode 100644 index 0000000000000000000000000000000000000000..1638c61b43554a55edcb2e9ddb2f59a6019b60a7 --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/hif/src/sdio/hif_sdio_recv.c @@ -0,0 +1,1442 @@ +/* + * Copyright (c) 2014-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#define ATH_MODULE_NAME hif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "hif_sdio_internal.h" +#include +#include "regtable_sdio.h" +#include "if_sdio.h" + +#define NBUF_ALLOC_FAIL_WAIT_TIME 100 + +static void hif_dev_dump_registers(struct hif_sdio_device *pdev, + struct MBOX_IRQ_PROC_REGISTERS *irq_proc_regs, + struct MBOX_IRQ_ENABLE_REGISTERS * + irq_enable_regs, + struct MBOX_COUNTER_REGISTERS * + mailbox_counter_registers) +{ + + AR_DEBUG_PRINTF(ATH_DEBUG_ANY, ("RegTable->")); + + if (irq_proc_regs != NULL) { + AR_DEBUG_PRINTF(ATH_DEBUG_ANY, + ("HostIntStatus: 0x%x ", + irq_proc_regs->host_int_status)); + AR_DEBUG_PRINTF(ATH_DEBUG_ANY, + ("CPUIntStatus: 0x%x ", + irq_proc_regs->cpu_int_status)); + AR_DEBUG_PRINTF(ATH_DEBUG_ANY, + ("ErrorIntStatus: 0x%x ", + irq_proc_regs->error_int_status)); + AR_DEBUG_PRINTF(ATH_DEBUG_ANY, + ("CounterIntStatus: 0x%x ", + irq_proc_regs->counter_int_status)); + AR_DEBUG_PRINTF(ATH_DEBUG_ANY, + ("MboxFrame: 0x%x ", + irq_proc_regs->mbox_frame)); + + AR_DEBUG_PRINTF(ATH_DEBUG_ANY, ("\nRegTable->")); + + AR_DEBUG_PRINTF(ATH_DEBUG_ANY, + ("RxLKAValid: 0x%x ", + irq_proc_regs->rx_lookahead_valid)); + AR_DEBUG_PRINTF(ATH_DEBUG_ANY, + ("RxLKA0: 0x%x", + irq_proc_regs->rx_lookahead[0])); + AR_DEBUG_PRINTF(ATH_DEBUG_ANY, + ("RxLKA1: 0x%x ", + irq_proc_regs->rx_lookahead[1])); + + AR_DEBUG_PRINTF(ATH_DEBUG_ANY, + ("RxLKA2: 0x%x ", + irq_proc_regs->rx_lookahead[2])); + AR_DEBUG_PRINTF(ATH_DEBUG_ANY, + ("RxLKA3: 0x%x", + irq_proc_regs->rx_lookahead[3])); + AR_DEBUG_PRINTF(ATH_DEBUG_ANY, ("\nRegTable->")); + + if (pdev->MailBoxInfo.gmbox_address != 0) { + /* if the target supports GMBOX hardware, + * dump some additional state */ + AR_DEBUG_PRINTF(ATH_DEBUG_ANY, + ("GMBOX-HostIntStatus2: 0x%x ", + irq_proc_regs->host_int_status2)); + AR_DEBUG_PRINTF(ATH_DEBUG_ANY, + ("GMBOX-RX-Avail: 0x%x ", + irq_proc_regs->gmbox_rx_avail)); + } + } + + if (irq_enable_regs != NULL) { + AR_DEBUG_PRINTF(ATH_DEBUG_ANY, + ("Int Status Enable: 0x%x\n", + irq_enable_regs->int_status_enable)); + AR_DEBUG_PRINTF(ATH_DEBUG_ANY, + ("Counter Int Status Enable: 0x%x\n", + irq_enable_regs->counter_int_status_enable)); + } + + if (mailbox_counter_registers != NULL) { + int i; + for (i = 0; i < 4; i++) { + AR_DEBUG_PRINTF(ATH_DEBUG_ANY, + ("Counter[%d]: 0x%x\n", i, + mailbox_counter_registers-> + counter[i])); + } + } + AR_DEBUG_PRINTF(ATH_DEBUG_ANY, + ("<------------------------------->\n")); +} + +static +QDF_STATUS hif_dev_alloc_and_prepare_rx_packets(struct hif_sdio_device *pdev, + uint32_t look_aheads[], + int messages, + HTC_PACKET_QUEUE *queue) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + HTC_PACKET *packet; + HTC_FRAME_HDR *hdr; + int i, j; + int num_messages; + int full_length; + bool no_recycle; + + /* lock RX while we assemble the packet buffers */ + LOCK_HIF_DEV_RX(pdev); + + for (i = 0; i < messages; i++) { + + hdr = (HTC_FRAME_HDR *) &look_aheads[i]; + if (hdr->EndpointID >= ENDPOINT_MAX) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + ("Invalid Endpoint in look-ahead: %d\n", + hdr->EndpointID)); + /* invalid endpoint */ + status = QDF_STATUS_E_PROTO; + break; + } + + if (hdr->PayloadLen > HTC_MAX_PAYLOAD_LENGTH) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + ("Payload length %d exceeds max HTC : %d !\n", + hdr->PayloadLen, + (uint32_t) HTC_MAX_PAYLOAD_LENGTH)); + status = QDF_STATUS_E_PROTO; + break; + } + + if ((hdr->Flags & HTC_FLAGS_RECV_BUNDLE_CNT_MASK) == 0) { + /* HTC header only indicates 1 message to fetch */ + num_messages = 1; + } else { + /* HTC header indicates that every packet to follow + * has the same padded length so that it can + * be optimally fetched as a full bundle */ + num_messages = + (hdr->Flags & HTC_FLAGS_RECV_BUNDLE_CNT_MASK) + >> HTC_FLAGS_RECV_BUNDLE_CNT_SHIFT; + /* the count doesn't include the starter frame, just + * a count of frames to follow */ + num_messages++; + /* A_ASSERT(numMessages <= target->MaxMsgPerBundle); */ + AR_DEBUG_PRINTF(ATH_DEBUG_RECV, + ("HTC header indicates :%d messages can be" + " fetched as a bundle\n", + num_messages)); + } + + full_length = + DEV_CALC_RECV_PADDED_LEN(pdev, + hdr->PayloadLen + + sizeof(HTC_FRAME_HDR)); + + /* get packet buffers for each message, if there was a + * bundle detected in the header, + * use pHdr as a template to fetch all packets in the bundle */ + for (j = 0; j < num_messages; j++) { + + /* reset flag, any packets allocated using the + * RecvAlloc() API cannot be recycled on cleanup, + * they must be explicitly returned */ + no_recycle = false; + packet = hif_dev_alloc_rx_buffer(pdev); + + if (packet == NULL) { + /* No error, simply need to mark that + * we are waiting for buffers. */ + pdev->RecvStateFlags |= HTC_RECV_WAIT_BUFFERS; + /* pDev->EpWaitingForBuffers = pEndpoint->Id; */ + status = QDF_STATUS_E_RESOURCES; + break; + } + /* AR_DEBUG_ASSERT(pPacket->Endpoint == + pEndpoint->Id); */ + /* clear flags */ + packet->PktInfo.AsRx.HTCRxFlags = 0; + packet->PktInfo.AsRx.IndicationFlags = 0; + packet->Status = QDF_STATUS_SUCCESS; + + if (no_recycle) + /* flag that these packets cannot be recycled, + * they have to be returned to the user */ + packet->PktInfo.AsRx.HTCRxFlags |= + HTC_RX_PKT_NO_RECYCLE; + /* add packet to queue (also incase we need to + * cleanup down below) */ + HTC_PACKET_ENQUEUE(queue, packet); + + /* + if (HTC_STOPPING(target)) { + status = QDF_STATUS_E_CANCELED; + break; + } + */ + + /* make sure message can fit in the endpoint buffer */ + if ((uint32_t) full_length > packet->BufferLength) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + ("Payload Length Error : header reports payload" + " of: %d (%d) endpoint buffer size: %d\n", + hdr->PayloadLen, full_length, + packet->BufferLength)); + status = QDF_STATUS_E_PROTO; + break; + } + + if (j > 0) { + /* for messages fetched in a bundle the expected + * lookahead is unknown as we are only using the + * lookahead of the first packet as a template + * of what to expect for lengths */ + packet->PktInfo.AsRx.HTCRxFlags |= + HTC_RX_PKT_REFRESH_HDR; + /* set it to something invalid */ + packet->PktInfo.AsRx.ExpectedHdr = 0xFFFFFFFF; + } else { + packet->PktInfo.AsRx.ExpectedHdr = + look_aheads[i]; + } + /* set the amount of data to fetch */ + packet->ActualLength = + hdr->PayloadLen + HTC_HDR_LENGTH; + packet->Endpoint = hdr->EndpointID; + packet->Completion = NULL; + } + + if (QDF_IS_STATUS_ERROR(status)) { + if (QDF_STATUS_E_RESOURCES == status) { + /* this is actually okay */ + status = QDF_STATUS_SUCCESS; + } + break; + } + + } + + UNLOCK_HIF_DEV_RX(pdev); + + if (QDF_IS_STATUS_ERROR(status)) { + while (!HTC_QUEUE_EMPTY(queue)) + packet = htc_packet_dequeue(queue); + } + + return status; +} + +static inline QDF_STATUS hif_dev_recv_packet(struct hif_sdio_device *pdev, + HTC_PACKET *packet, + uint32_t recv_length, uint8_t mbox_index) +{ + uint32_t padded_length; + QDF_STATUS status; + bool sync = (packet->Completion == NULL) ? true : false; + + /* adjust the length to be a multiple of block size if appropriate */ + padded_length = DEV_CALC_RECV_PADDED_LEN(pdev, recv_length); + + if (padded_length > packet->BufferLength) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + ("DevRecvPacket, Not enough space for" + " padlen:%d recvlen:%d bufferlen:%d\n", + padded_length, recv_length, + packet->BufferLength)); + if (packet->Completion != NULL) { + COMPLETE_HTC_PACKET(packet, QDF_STATUS_E_INVAL); + return QDF_STATUS_SUCCESS; + } + return QDF_STATUS_E_INVAL; + } + + /* mailbox index is saved in Endpoint member */ + AR_DEBUG_PRINTF(ATH_DEBUG_RECV, + ("hif_dev_recv_packet (0x%lX : hdr:0x%X) Len:%d," + " Padded Length: %d Mbox:0x%X\n", + (unsigned long)packet, + packet->PktInfo.AsRx.ExpectedHdr, recv_length, + padded_length, + pdev->MailBoxInfo.mbox_addresses[mbox_index])); + status = hif_read_write(pdev->HIFDevice, + pdev->MailBoxInfo.mbox_addresses[mbox_index], + packet->pBuffer, padded_length, + (sync ? HIF_RD_SYNC_BLOCK_FIX : + HIF_RD_ASYNC_BLOCK_FIX), + sync ? NULL : packet); + AR_DEBUG_PRINTF(ATH_DEBUG_RECV, ("EP%d, Seq:%d\n", + ((HTC_FRAME_HDR *) packet->pBuffer)-> + EndpointID, + ((HTC_FRAME_HDR *) packet->pBuffer)-> + ControlBytes1)); + if (status != QDF_STATUS_SUCCESS) { + AR_DEBUG_PRINTF(ATH_DEBUG_RECV, + ("hif_dev_recv_packet (0x%lX : hdr:0x%X) Failed\n", + (unsigned long)packet, + packet->PktInfo.AsRx.ExpectedHdr)); + } + if (sync) { + packet->Status = status; + if (status == QDF_STATUS_SUCCESS) { + HTC_FRAME_HDR *hdr = + (HTC_FRAME_HDR *) packet->pBuffer; + AR_DEBUG_PRINTF(ATH_DEBUG_RECV, + ("hif_dev_recv_packet " + "EP:%d,Len:%d,Flag:%d,CB:0x%02X,0x%02X\n", + hdr->EndpointID, hdr->PayloadLen, + hdr->Flags, hdr->ControlBytes0, + hdr->ControlBytes1)); + } + } + + return status; +} + +static inline QDF_STATUS hif_dev_process_trailer(struct hif_sdio_device *pdev, + uint8_t *buffer, int length, + uint32_t *next_look_aheads, + int *num_look_aheads, + HTC_ENDPOINT_ID from_endpoint) +{ + HTC_RECORD_HDR *record; + uint8_t *record_buf; + HTC_LOOKAHEAD_REPORT *look_ahead; + uint8_t *orig_buffer; + int orig_length; + QDF_STATUS status; + + AR_DEBUG_PRINTF(ATH_DEBUG_RECV, + ("+htc_process_trailer (length:%d)\n", length)); + + if (AR_DEBUG_LVL_CHECK(ATH_DEBUG_RECV)) + AR_DEBUG_PRINTBUF(buffer, length, "Recv Trailer"); + + orig_buffer = buffer; + orig_length = length; + status = QDF_STATUS_SUCCESS; + + while (length > 0) { + + if (length < sizeof(HTC_RECORD_HDR)) { + status = QDF_STATUS_E_PROTO; + break; + } + /* these are byte aligned structs */ + record = (HTC_RECORD_HDR *) buffer; + length -= sizeof(HTC_RECORD_HDR); + buffer += sizeof(HTC_RECORD_HDR); + + if (record->Length > length) { + /* no room left in buffer for record */ + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + (" invalid record len: %d (id:%d) buffer has:" + "%d bytes left\n", + record->Length, record->RecordID, + length)); + status = QDF_STATUS_E_PROTO; + break; + } + /* start of record follows the header */ + record_buf = buffer; + + switch (record->RecordID) { + case HTC_RECORD_CREDITS: + /* Process in HTC, ignore here */ + break; + case HTC_RECORD_LOOKAHEAD: + AR_DEBUG_ASSERT(record->Length >= + sizeof(HTC_LOOKAHEAD_REPORT)); + look_ahead = (HTC_LOOKAHEAD_REPORT *) record_buf; + if ((look_ahead->PreValid == + ((~look_ahead->PostValid) & 0xFF)) + && (next_look_aheads != NULL)) { + + AR_DEBUG_PRINTF(ATH_DEBUG_RECV, + (" look_ahead Report (pre valid:0x%X," + " post valid:0x%X) %d %d\n", + look_ahead->PreValid, + look_ahead->PostValid, + from_endpoint, + look_ahead->LookAhead0)); + /* look ahead bytes are valid, copy them over */ + ((uint8_t *) (&next_look_aheads[0]))[0] = + look_ahead->LookAhead0; + ((uint8_t *) (&next_look_aheads[0]))[1] = + look_ahead->LookAhead1; + ((uint8_t *) (&next_look_aheads[0]))[2] = + look_ahead->LookAhead2; + ((uint8_t *) (&next_look_aheads[0]))[3] = + look_ahead->LookAhead3; + + if (AR_DEBUG_LVL_CHECK(ATH_DEBUG_RECV)) { + debug_dump_bytes((uint8_t *) + next_look_aheads, 4, + "Next Look Ahead"); + } + /* just one normal lookahead */ + if (num_look_aheads != NULL) + *num_look_aheads = 1; + } + break; + case HTC_RECORD_LOOKAHEAD_BUNDLE: + AR_DEBUG_ASSERT(record->Length >= + sizeof(HTC_BUNDLED_LOOKAHEAD_REPORT)); + if (record->Length >= + sizeof(HTC_BUNDLED_LOOKAHEAD_REPORT) + && (next_look_aheads != NULL)) { + HTC_BUNDLED_LOOKAHEAD_REPORT + *pBundledLookAheadRpt; + int i; + + pBundledLookAheadRpt = + (HTC_BUNDLED_LOOKAHEAD_REPORT *) record_buf; + + if (AR_DEBUG_LVL_CHECK(ATH_DEBUG_RECV)) { + debug_dump_bytes(record_buf, + record->Length, + "Bundle look_ahead"); + } + + if ((record->Length / + (sizeof(HTC_BUNDLED_LOOKAHEAD_REPORT))) + > HTC_MAX_MSG_PER_BUNDLE) { + /* this should never happen, the target + * restricts the number of messages per + * bundle configured by the host */ + A_ASSERT(false); + status = QDF_STATUS_E_PROTO; + break; + } + for (i = 0; + i < + (int)(record->Length / + (sizeof + (HTC_BUNDLED_LOOKAHEAD_REPORT))); + i++) { + ((uint8_t *)(&next_look_aheads[i]))[0] = + pBundledLookAheadRpt->LookAhead0; + ((uint8_t *)(&next_look_aheads[i]))[1] = + pBundledLookAheadRpt->LookAhead1; + ((uint8_t *)(&next_look_aheads[i]))[2] = + pBundledLookAheadRpt->LookAhead2; + ((uint8_t *)(&next_look_aheads[i]))[3] = + pBundledLookAheadRpt->LookAhead3; + pBundledLookAheadRpt++; + } + + *num_look_aheads = i; + } + break; + default: + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + (" HIF unhandled record: id:%d length:%d\n", + record->RecordID, record->Length)); + break; + } + + if (QDF_IS_STATUS_ERROR(status)) + break; + + /* advance buffer past this record for next time around */ + buffer += record->Length; + length -= record->Length; + } + + if (QDF_IS_STATUS_ERROR(status)) + debug_dump_bytes(orig_buffer, orig_length, + "BAD Recv Trailer"); + + AR_DEBUG_PRINTF(ATH_DEBUG_RECV, ("-htc_process_trailer\n")); + return status; + +} + +/* process a received message (i.e. strip off header, + * process any trailer data). + * note : locks must be released when this function is called */ +static QDF_STATUS hif_dev_process_recv_header(struct hif_sdio_device *pdev, + HTC_PACKET *packet, + uint32_t *next_look_aheads, + int *num_look_aheads) +{ + uint8_t temp; + uint8_t *buf; + QDF_STATUS status = QDF_STATUS_SUCCESS; + uint16_t payloadLen; + uint32_t look_ahead, actual_length; + + buf = packet->pBuffer; + actual_length = packet->ActualLength; + + if (num_look_aheads != NULL) + *num_look_aheads = 0; + + AR_DEBUG_PRINTF(ATH_DEBUG_RECV, ("+HTCProcessRecvHeader\n")); + + if (AR_DEBUG_LVL_CHECK(ATH_DEBUG_RECV)) + AR_DEBUG_PRINTBUF(buf, packet->ActualLength, "HTC Recv PKT"); + + do { + /* note, we cannot assume the alignment of pBuffer, + * so we use the safe macros to + * retrieve 16 bit fields */ + payloadLen = HTC_GET_FIELD(buf, HTC_FRAME_HDR, + PAYLOADLEN); + + ((uint8_t *) &look_ahead)[0] = buf[0]; + ((uint8_t *) &look_ahead)[1] = buf[1]; + ((uint8_t *) &look_ahead)[2] = buf[2]; + ((uint8_t *) &look_ahead)[3] = buf[3]; + + if (packet->PktInfo.AsRx.HTCRxFlags & HTC_RX_PKT_REFRESH_HDR) { + /* refresh expected hdr, since this was unknown + * at the time we grabbed the packets + * as part of a bundle */ + packet->PktInfo.AsRx.ExpectedHdr = look_ahead; + /* refresh actual length since we now have the + * real header */ + packet->ActualLength = payloadLen + HTC_HDR_LENGTH; + + /* validate the actual header that was refreshed */ + if (packet->ActualLength > packet->BufferLength) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + ("Invalid HDR payload length (%d)" + " in bundled RECV (hdr: 0x%X)\n", + payloadLen, look_ahead)); + /* limit this to max buffer just to print out + * some of the buffer */ + packet->ActualLength = + min(packet->ActualLength, + packet->BufferLength); + status = QDF_STATUS_E_PROTO; + break; + } + + if (packet->Endpoint + != HTC_GET_FIELD(buf, HTC_FRAME_HDR, ENDPOINTID)) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + ("Refreshed HDR endpoint (%d) does not " + " match expected endpoint (%d)\n", + HTC_GET_FIELD(buf, + HTC_FRAME_HDR, + ENDPOINTID), + packet->Endpoint)); + status = QDF_STATUS_E_PROTO; + break; + } + } + + if (look_ahead != packet->PktInfo.AsRx.ExpectedHdr) { + /* somehow the lookahead that gave us the full read + * length did not reflect the actual header + * in the pending message */ + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + ("hif_dev_process_recv_header, lookahead mismatch!" + " (pPkt:0x%lX flags:0x%X), 0x%08X != 0x%08X\n", + (unsigned long)packet, + packet->PktInfo.AsRx.HTCRxFlags, + look_ahead, + packet->PktInfo.AsRx.ExpectedHdr)); +#ifdef ATH_DEBUG_MODULE + debug_dump_bytes((uint8_t *) &packet->PktInfo.AsRx. + ExpectedHdr, 4, + "Expected Message look_ahead"); + debug_dump_bytes(buf, sizeof(HTC_FRAME_HDR), + "Current Frame Header"); +#ifdef HTC_CAPTURE_LAST_FRAME + debug_dump_bytes((uint8_t *) &target->LastFrameHdr, + sizeof(HTC_FRAME_HDR), + "Last Frame Header"); + if (target->LastTrailerLength != 0) + debug_dump_bytes(target->LastTrailer, + target->LastTrailerLength, + "Last trailer"); +#endif +#endif + status = QDF_STATUS_E_PROTO; + break; + } + + /* get flags */ + temp = HTC_GET_FIELD(buf, HTC_FRAME_HDR, FLAGS); + + if (temp & HTC_FLAGS_RECV_TRAILER) { + /* this packet has a trailer */ + + /* extract the trailer length in control byte 0 */ + temp = + HTC_GET_FIELD(buf, HTC_FRAME_HDR, + CONTROLBYTES0); + + if ((temp < sizeof(HTC_RECORD_HDR)) + || (temp > payloadLen)) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + ("hif_dev_process_recv_header, invalid header" + "(payloadlength should be :%d, CB[0] is:%d)\n", + payloadLen, temp)); + status = QDF_STATUS_E_PROTO; + break; + } + + if (packet->PktInfo.AsRx. + HTCRxFlags & HTC_RX_PKT_IGNORE_LOOKAHEAD) { + /* this packet was fetched as part of an HTC + * bundle as the lookahead is not valid. + * Next packet may have already been fetched as + * part of the bundle */ + next_look_aheads = NULL; + num_look_aheads = NULL; + } + + /* process trailer data that follows HDR and + * application payload */ + status = hif_dev_process_trailer(pdev, + (buf + HTC_HDR_LENGTH + + payloadLen - temp), temp, + next_look_aheads, + num_look_aheads, + packet->Endpoint); + + if (QDF_IS_STATUS_ERROR(status)) + break; + } + } while (false); + + if (QDF_IS_STATUS_ERROR(status)) { + /* dump the whole packet */ + debug_dump_bytes(buf, packet->ActualLength, + "BAD HTC Recv PKT"); + } else { + if (AR_DEBUG_LVL_CHECK(ATH_DEBUG_RECV)) { + if (packet->ActualLength > 0) { + AR_DEBUG_PRINTBUF(packet->pBuffer, + packet->ActualLength, + "HTC - Application Msg"); + } + } + } + AR_DEBUG_PRINTF(ATH_DEBUG_RECV, + ("-hif_dev_process_recv_header\n")); + return status; +} + +static QDF_STATUS hif_dev_issue_recv_packet_bundle(struct hif_sdio_device *pdev, + HTC_PACKET_QUEUE *recv_pkt_queue, + HTC_PACKET_QUEUE * + sync_completion_queue, + uint8_t mail_box_index, + int *num_packets_fetched, + bool partial_bundle) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + int i, total_length = 0; + unsigned char *bundle_buffer = NULL; + HTC_PACKET *packet, *packet_rx_bundle; + HTC_TARGET *target = NULL; + uint32_t padded_length; + + int bundleSpaceRemaining = 0; + target = (HTC_TARGET *) pdev->pTarget; + + if ((HTC_PACKET_QUEUE_DEPTH(recv_pkt_queue) - HTC_MAX_MSG_PER_BUNDLE) > + 0) { + partial_bundle = true; + AR_DEBUG_PRINTF(ATH_DEBUG_WARN, + ("%s, partial bundle detected num: %d, %d\n", + __func__, + HTC_PACKET_QUEUE_DEPTH(recv_pkt_queue), + HTC_MAX_MSG_PER_BUNDLE)); + } + + bundleSpaceRemaining = + HTC_MAX_MSG_PER_BUNDLE * target->TargetCreditSize; + packet_rx_bundle = allocate_htc_bundle_packet(target); + if (!packet_rx_bundle) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + ("%s: packet_rx_bundle is NULL\n", __func__)); + qdf_sleep(NBUF_ALLOC_FAIL_WAIT_TIME); /* 100 msec sleep */ + return QDF_STATUS_E_NOMEM; + } + bundle_buffer = packet_rx_bundle->pBuffer; + + for (i = 0; + !HTC_QUEUE_EMPTY(recv_pkt_queue) && i < HTC_MAX_MSG_PER_BUNDLE; + i++) { + packet = htc_packet_dequeue(recv_pkt_queue); + A_ASSERT(packet != NULL); + padded_length = + DEV_CALC_RECV_PADDED_LEN(pdev, packet->ActualLength); + + if ((bundleSpaceRemaining - padded_length) < 0) { + /* exceeds what we can transfer, put the packet back */ + HTC_PACKET_ENQUEUE_TO_HEAD(recv_pkt_queue, packet); + break; + } + bundleSpaceRemaining -= padded_length; + + if (partial_bundle || + HTC_PACKET_QUEUE_DEPTH(recv_pkt_queue) > 0) { + packet->PktInfo.AsRx.HTCRxFlags |= + HTC_RX_PKT_IGNORE_LOOKAHEAD; + } + packet->PktInfo.AsRx.HTCRxFlags |= HTC_RX_PKT_PART_OF_BUNDLE; + + HTC_PACKET_ENQUEUE(sync_completion_queue, packet); + + total_length += padded_length; + } +#ifdef DEBUG_BUNDLE + qdf_print("Recv bundle count %d, length %d.\n", + HTC_PACKET_QUEUE_DEPTH(sync_completion_queue), total_length); +#endif + + status = hif_read_write(pdev->HIFDevice, + pdev->MailBoxInfo. + mbox_addresses[(int)mail_box_index], + bundle_buffer, total_length, + HIF_RD_SYNC_BLOCK_FIX, NULL); + + if (status != QDF_STATUS_SUCCESS) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + ("%s, hif_send Failed status:%d\n", + __func__, status)); + } else { + unsigned char *buffer = bundle_buffer; + *num_packets_fetched = i; + HTC_PACKET_QUEUE_ITERATE_ALLOW_REMOVE(sync_completion_queue, + packet) { + padded_length = + DEV_CALC_RECV_PADDED_LEN(pdev, + packet->ActualLength); + A_MEMCPY(packet->pBuffer, buffer, padded_length); + buffer += padded_length; + } HTC_PACKET_QUEUE_ITERATE_END; + } + /* free bundle space under Sync mode */ + free_htc_bundle_packet(target, packet_rx_bundle); + return status; +} + +QDF_STATUS hif_dev_recv_message_pending_handler(struct hif_sdio_device *pdev, + uint8_t mail_box_index, + uint32_t msg_look_aheads[], + int num_look_aheads, + bool *async_proc, + int *num_pkts_fetched) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + HTC_PACKET *packet; + bool asyncProc = false; + uint32_t look_aheads[HTC_MAX_MSG_PER_BUNDLE]; + int pkts_fetched; + HTC_PACKET_QUEUE recv_pkt_queue, sync_completed_pkts_queue; + bool partial_bundle; + HTC_ENDPOINT_ID id; + int total_fetched = 0; + + AR_DEBUG_PRINTF(ATH_DEBUG_RECV, + ("+HTCRecvMessagePendingHandler NumLookAheads: %d\n", + num_look_aheads)); + + if (num_pkts_fetched != NULL) + *num_pkts_fetched = 0; + + if (IS_DEV_IRQ_PROCESSING_ASYNC_ALLOWED(pdev)) { + /* We use async mode to get the packets if the + * device layer supports it. The device layer + * interfaces with HIF in which HIF may have + * restrictions on how interrupts are processed */ + asyncProc = true; + } + + if (async_proc != NULL) + /* indicate to caller how we decided to process this */ + *async_proc = asyncProc; + if (num_look_aheads > HTC_MAX_MSG_PER_BUNDLE) { + A_ASSERT(false); + return QDF_STATUS_E_PROTO; + } + A_MEMCPY(look_aheads, msg_look_aheads, + (sizeof(uint32_t)) * num_look_aheads); + while (true) { + + /* reset packets queues */ + INIT_HTC_PACKET_QUEUE(&recv_pkt_queue); + INIT_HTC_PACKET_QUEUE(&sync_completed_pkts_queue); + if (num_look_aheads > HTC_MAX_MSG_PER_BUNDLE) { + status = QDF_STATUS_E_PROTO; + A_ASSERT(false); + break; + } + + /* first lookahead sets the expected endpoint IDs for + * all packets in a bundle */ + id = ((HTC_FRAME_HDR *) &look_aheads[0])->EndpointID; + + if (id >= ENDPOINT_MAX) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + ("MsgPend, Invalid Endpoint in lookahead: %d\n", + id)); + status = QDF_STATUS_E_PROTO; + break; + } + /* try to allocate as many HTC RX packets indicated + * by the lookaheads these packets are stored + * in the recvPkt queue */ + status = hif_dev_alloc_and_prepare_rx_packets(pdev, + look_aheads, + num_look_aheads, + &recv_pkt_queue); + if (QDF_IS_STATUS_ERROR(status)) + break; + total_fetched += HTC_PACKET_QUEUE_DEPTH(&recv_pkt_queue); + + /* we've got packet buffers for all we can currently fetch, + * this count is not valid anymore */ + num_look_aheads = 0; + partial_bundle = false; + + /* now go fetch the list of HTC packets */ + while (!HTC_QUEUE_EMPTY(&recv_pkt_queue)) { + + pkts_fetched = 0; + if ((HTC_PACKET_QUEUE_DEPTH(&recv_pkt_queue) > 1)) { + /* there are enough packets to attempt a bundle + * transfer and recv bundling is allowed */ + status = hif_dev_issue_recv_packet_bundle(pdev, + &recv_pkt_queue, + asyncProc ? + NULL : + &sync_completed_pkts_queue, + mail_box_index, + &pkts_fetched, + partial_bundle); + if (QDF_IS_STATUS_ERROR(status)) { + while (!HTC_QUEUE_EMPTY( + &recv_pkt_queue)) { + qdf_nbuf_t netbuf; + + packet = htc_packet_dequeue( + &recv_pkt_queue); + if (packet == NULL) + break; + netbuf = (qdf_nbuf_t) packet-> + pNetBufContext; + if (netbuf) + qdf_nbuf_free(netbuf); + } + break; + } + + if (HTC_PACKET_QUEUE_DEPTH(&recv_pkt_queue) != + 0) { + /* we couldn't fetch all packets at one, + * time this creates a broken + * bundle */ + partial_bundle = true; + } + } + + /* see if the previous operation fetched any + * packets using bundling */ + if (0 == pkts_fetched) { + /* dequeue one packet */ + packet = htc_packet_dequeue(&recv_pkt_queue); + A_ASSERT(packet != NULL); + packet->Completion = NULL; + + if (HTC_PACKET_QUEUE_DEPTH(&recv_pkt_queue) > + 0) { + /* lookaheads in all packets except the + * last one in must be ignored */ + packet->PktInfo.AsRx.HTCRxFlags |= + HTC_RX_PKT_IGNORE_LOOKAHEAD; + } + + /* go fetch the packet */ + status = + hif_dev_recv_packet(pdev, packet, + packet->ActualLength, + mail_box_index); + if (QDF_IS_STATUS_ERROR(status)) + break; + /* sent synchronously, queue this packet for + * synchronous completion */ + HTC_PACKET_ENQUEUE(&sync_completed_pkts_queue, + packet); + } + } + + /* synchronous handling */ + if (pdev->DSRCanYield) { + /* for the SYNC case, increment count that tracks + * when the DSR should yield */ + pdev->CurrentDSRRecvCount++; + } + + /* in the sync case, all packet buffers are now filled, + * we can process each packet, check lookahead , then repeat */ + + /* unload sync completion queue */ + while (!HTC_QUEUE_EMPTY(&sync_completed_pkts_queue)) { + uint8_t pipeid; + qdf_nbuf_t netbuf; + + packet = htc_packet_dequeue(&sync_completed_pkts_queue); + A_ASSERT(packet != NULL); + + num_look_aheads = 0; + status = + hif_dev_process_recv_header(pdev, packet, + look_aheads, + &num_look_aheads); + if (QDF_IS_STATUS_ERROR(status)) + break; + + netbuf = (qdf_nbuf_t) packet->pNetBufContext; + /* set data length */ + qdf_nbuf_put_tail(netbuf, packet->ActualLength); + + if (pdev->hif_callbacks.rxCompletionHandler) { + pipeid = + hif_dev_map_mail_box_to_pipe(pdev, + mail_box_index, + true); + pdev->hif_callbacks.rxCompletionHandler(pdev-> + hif_callbacks. + Context, + netbuf, + pipeid); + } + } + if (QDF_IS_STATUS_ERROR(status)) + break; + + if (num_look_aheads == 0) { + /* no more look aheads */ + break; + } + /* check whether other OS contexts have queued any WMI + * command/data for WLAN. This check is needed only if WLAN + * Tx and Rx happens in same thread context */ + /* A_CHECK_DRV_TX(); */ + } + if (num_pkts_fetched != NULL) + *num_pkts_fetched = total_fetched; + + AR_DEBUG_PRINTF(ATH_DEBUG_RECV, ("-HTCRecvMessagePendingHandler\n")); + return status; +} + +/** + * hif_dev_service_cpu_interrupt() - service fatal interrupts + * synchronously + * + * @pDev: hif sdio device context + * + * Return: QDF_STATUS_SUCCESS for success + */ +static QDF_STATUS hif_dev_service_cpu_interrupt(struct hif_sdio_device *pdev) +{ + QDF_STATUS status; + uint8_t cpu_int_status; + uint8_t reg_buffer[4]; + + AR_DEBUG_PRINTF(ATH_DEBUG_IRQ, ("CPU Interrupt\n")); + cpu_int_status = pdev->IrqProcRegisters.cpu_int_status + & pdev->IrqEnableRegisters.cpu_int_status_enable; + A_ASSERT(cpu_int_status); + AR_DEBUG_PRINTF(ATH_DEBUG_IRQ, + ("Valid interrupt source(s) in CPU_INT_STATUS: 0x%x\n", + cpu_int_status)); + + /* Clear the interrupt */ + pdev->IrqProcRegisters.cpu_int_status &= ~cpu_int_status; + + /*set up the register transfer buffer to hit the register + * 4 times , this is done to make the access 4-byte aligned + * to mitigate issues with host bus interconnects that + * restrict bus transfer lengths to be a multiple of 4-bytes + * set W1C value to clear the interrupt, this hits the register + * first */ + reg_buffer[0] = cpu_int_status; + /* the remaining 4 values are set to zero which have no-effect */ + reg_buffer[1] = 0; + reg_buffer[2] = 0; + reg_buffer[3] = 0; + + status = hif_read_write(pdev->HIFDevice, + CPU_INT_STATUS_ADDRESS, + reg_buffer, 4, HIF_WR_SYNC_BYTE_FIX, NULL); + + A_ASSERT(status == QDF_STATUS_SUCCESS); + + /* The Interrupt sent to the Host is generated via bit0 + * of CPU INT register */ + if (cpu_int_status & 0x1) { + if (pdev && pdev->hif_callbacks.fwEventHandler) + /* It calls into HTC which propagates this + * to ol_target_failure() */ + pdev->hif_callbacks.fwEventHandler(pdev->hif_callbacks. + Context, QDF_STATUS_E_FAILURE); + } else + AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, + ("%s: Unable to call fwEventHandler," + " invalid input arguments\n", + __func__)); + + return status; +} + +/** + * hif_dev_service_error_interrupt() - service error interrupts + * synchronously + * + * @pDev: hif sdio device context + * + * Return: QDF_STATUS_SUCCESS for success + */ +static QDF_STATUS hif_dev_service_error_interrupt(struct hif_sdio_device *pdev) +{ + QDF_STATUS status; + uint8_t error_int_status; + uint8_t reg_buffer[4]; + + AR_DEBUG_PRINTF(ATH_DEBUG_IRQ, ("Error Interrupt\n")); + error_int_status = pdev->IrqProcRegisters.error_int_status & 0x0F; + A_ASSERT(error_int_status); + AR_DEBUG_PRINTF(ATH_DEBUG_IRQ, + ("Valid interrupt source in ERROR_INT_STATUS: 0x%x\n", + error_int_status)); + + if (ERROR_INT_STATUS_WAKEUP_GET(error_int_status)) { + /* Wakeup */ + AR_DEBUG_PRINTF(ATH_DEBUG_IRQ, ("Error : Wakeup\n")); + } + + if (ERROR_INT_STATUS_RX_UNDERFLOW_GET(error_int_status)) { + /* Rx Underflow */ + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Error : Rx Underflow\n")); + } + + if (ERROR_INT_STATUS_TX_OVERFLOW_GET(error_int_status)) { + /* Tx Overflow */ + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Error : Tx Overflow\n")); + } + + /* Clear the interrupt */ + pdev->IrqProcRegisters.error_int_status &= ~error_int_status; + + /* set up the register transfer buffer to hit the register + * 4 times , this is done to make the access 4-byte + * aligned to mitigate issues with host bus interconnects that + * restrict bus transfer lengths to be a multiple of 4-bytes */ + + /* set W1C value to clear the interrupt */ + reg_buffer[0] = error_int_status; + /* the remaining 4 values are set to zero which have no-effect */ + reg_buffer[1] = 0; + reg_buffer[2] = 0; + reg_buffer[3] = 0; + + status = hif_read_write(pdev->HIFDevice, + ERROR_INT_STATUS_ADDRESS, + reg_buffer, 4, HIF_WR_SYNC_BYTE_FIX, NULL); + + A_ASSERT(status == QDF_STATUS_SUCCESS); + return status; +} + +/** + * hif_dev_service_debug_interrupt() - service debug interrupts + * synchronously + * + * @pDev: hif sdio device context + * + * Return: QDF_STATUS_SUCCESS for success + */ +static QDF_STATUS hif_dev_service_debug_interrupt(struct hif_sdio_device *pdev) +{ + uint32_t dummy; + QDF_STATUS status; + + /* Send a target failure event to the application */ + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("Target debug interrupt\n")); + + /* clear the interrupt , the debug error interrupt is + * counter 0 */ + /* read counter to clear interrupt */ + status = hif_read_write(pdev->HIFDevice, + COUNT_DEC_ADDRESS, + (uint8_t *) &dummy, + 4, HIF_RD_SYNC_BYTE_INC, NULL); + + A_ASSERT(status == QDF_STATUS_SUCCESS); + return status; +} + +/** + * hif_dev_service_counter_interrupt() - service counter interrupts + * synchronously + * + * @pDev: hif sdio device context + * + * Return: QDF_STATUS_SUCCESS for success + */ +static +QDF_STATUS hif_dev_service_counter_interrupt(struct hif_sdio_device *pdev) +{ + uint8_t counter_int_status; + + AR_DEBUG_PRINTF(ATH_DEBUG_IRQ, ("Counter Interrupt\n")); + + counter_int_status = pdev->IrqProcRegisters.counter_int_status & + pdev->IrqEnableRegisters.counter_int_status_enable; + + AR_DEBUG_PRINTF(ATH_DEBUG_IRQ, + ("Valid interrupt source in COUNTER_INT_STATUS: 0x%x\n", + counter_int_status)); + + /* Check if the debug interrupt is pending + * NOTE: other modules like GMBOX may use the counter interrupt + * for credit flow control on other counters, we only need to + * check for the debug assertion counter interrupt */ + if (counter_int_status & AR6K_TARGET_DEBUG_INTR_MASK) + return hif_dev_service_debug_interrupt(pdev); + + return QDF_STATUS_SUCCESS; +} + +/** + * hif_dev_process_pending_irqs() - process pending interrupts + * synchronously + * + * @pDev: hif sdio device context + * @pDone: pending irq completion status + * @pASyncProcessing: sync/async processing flag + * Return: QDF_STATUS_SUCCESS for success + */ +static QDF_STATUS hif_dev_process_pending_irqs(struct hif_sdio_device *pdev, + bool *done, + bool *async_processing) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + uint8_t host_int_status = 0; + uint32_t look_ahead[MAILBOX_USED_COUNT]; + int i; + + qdf_mem_zero(&look_ahead, sizeof(look_ahead)); + AR_DEBUG_PRINTF(ATH_DEBUG_IRQ, + ("+ProcessPendingIRQs: (dev: 0x%lX)\n", + (unsigned long)pdev)); + + /* NOTE: the HIF implementation guarantees that the context + * of this call allows us to perform SYNCHRONOUS I/O, + * that is we can block, sleep or call any API that + * can block or switch thread/task ontexts. + * This is a fully schedulable context. */ + do { + + if (pdev->IrqEnableRegisters.int_status_enable == 0) { + /* interrupt enables have been cleared, do not try + * to process any pending interrupts that + * may result in more bus transactions. + * The target may be unresponsive at this point. */ + break; + } + status = hif_read_write(pdev->HIFDevice, + HOST_INT_STATUS_ADDRESS, + (uint8_t *) &pdev->IrqProcRegisters, + sizeof(pdev->IrqProcRegisters), + HIF_RD_SYNC_BYTE_INC, NULL); + + if (QDF_IS_STATUS_ERROR(status)) + break; + + if (AR_DEBUG_LVL_CHECK(ATH_DEBUG_IRQ)) { + hif_dev_dump_registers(pdev, + &pdev->IrqProcRegisters, + &pdev->IrqEnableRegisters, + &pdev->MailBoxCounterRegisters); + } + + /* Update only those registers that are enabled */ + host_int_status = pdev->IrqProcRegisters.host_int_status + & pdev->IrqEnableRegisters.int_status_enable; + + /* only look at mailbox status if the HIF layer did not + * provide this function, on some HIF interfaces reading + * the RX lookahead is not valid to do */ + for (i = 0; i < MAILBOX_USED_COUNT; i++) { + look_ahead[i] = 0; + if (host_int_status & (1 << i)) { + /* mask out pending mailbox value, we use + * "lookAhead" as the real flag for + * mailbox processing below */ + host_int_status &= ~(1 << i); + if (pdev->IrqProcRegisters. + rx_lookahead_valid & (1 << i)) { + /* mailbox has a message and the + * look ahead is valid */ + look_ahead[i] = + pdev-> + IrqProcRegisters.rx_lookahead[ + MAILBOX_LOOKAHEAD_SIZE_IN_WORD * + i]; + } + } + } /*end of for loop */ + } while (false); + + do { + bool bLookAheadValid = false; + /* did the interrupt status fetches succeed? */ + if (QDF_IS_STATUS_ERROR(status)) + break; + + for (i = 0; i < MAILBOX_USED_COUNT; i++) { + if (look_ahead[i] != 0) { + bLookAheadValid = true; + break; + } + } + + if ((0 == host_int_status) && !bLookAheadValid) { + /* nothing to process, the caller can use this + * to break out of a loop */ + *done = true; + break; + } + + if (bLookAheadValid) { + for (i = 0; i < MAILBOX_USED_COUNT; i++) { + int fetched = 0; + if (look_ahead[i] == 0) + continue; + AR_DEBUG_PRINTF(ATH_DEBUG_IRQ, + ("Pending mailbox[%d] message, look_ahead: 0x%X\n", + i, look_ahead[i])); + /* Mailbox Interrupt, the HTC layer may issue + * async requests to empty the mailbox... + * When emptying the recv mailbox we use the + * async handler from the completion routine of + * routine of the callers read request. + * This can improve performance by reducing + * the context switching when we rapidly + * pull packets */ + status = hif_dev_recv_message_pending_handler( + pdev, i, + &look_ahead + [i], 1, + async_processing, + &fetched); + if (QDF_IS_STATUS_ERROR(status)) + break; + + if (!fetched) { + /* HTC could not pull any messages out + * due to lack of resources force DSR + * handle to ack the interrupt */ + *async_processing = false; + pdev->RecheckIRQStatusCnt = 0; + } + } + } + + /* now handle the rest of them */ + AR_DEBUG_PRINTF(ATH_DEBUG_IRQ, + (" Valid interrupt source for OTHER interrupts: 0x%x\n", + host_int_status)); + + if (HOST_INT_STATUS_CPU_GET(host_int_status)) { + /* CPU Interrupt */ + status = hif_dev_service_cpu_interrupt(pdev); + if (QDF_IS_STATUS_ERROR(status)) + break; + } + + if (HOST_INT_STATUS_ERROR_GET(host_int_status)) { + /* Error Interrupt */ + status = hif_dev_service_error_interrupt(pdev); + if (QDF_IS_STATUS_ERROR(status)) + break; + } + + if (HOST_INT_STATUS_COUNTER_GET(host_int_status)) { + /* Counter Interrupt */ + status = hif_dev_service_counter_interrupt(pdev); + if (QDF_IS_STATUS_ERROR(status)) + break; + } + + } while (false); + + /* an optimization to bypass reading the IRQ status registers + * unecessarily which can re-wake the target, if upper layers + * determine that we are in a low-throughput mode, we can + * rely on taking another interrupt rather than re-checking + * the status registers which can re-wake the target. + * + * NOTE : for host interfaces that use the special + * GetPendingEventsFunc, this optimization cannot be used due to + * possible side-effects. For example, SPI requires the host + * to drain all messages from the mailbox before exiting + * the ISR routine. */ + if (!(*async_processing) && (pdev->RecheckIRQStatusCnt == 0)) { + AR_DEBUG_PRINTF(ATH_DEBUG_IRQ, + ("Bypassing IRQ Status re-check, forcing done\n")); + *done = true; + } + + AR_DEBUG_PRINTF(ATH_DEBUG_IRQ, + ("-ProcessPendingIRQs: (done:%d, async:%d) status=%d\n", + *done, *async_processing, status)); + + return status; +} + +#define DEV_CHECK_RECV_YIELD(pdev) \ + ((pdev)->CurrentDSRRecvCount >= \ + (pdev)->HifIRQYieldParams.recv_packet_yield_count) + +/** + * hif_dev_dsr_handler() - Synchronous interrupt handler + * + * @context: hif send context + * + * Return: 0 for success and non-zero for failure + */ +QDF_STATUS hif_dev_dsr_handler(void *context) +{ + struct hif_sdio_device *pdev = (struct hif_sdio_device *) context; + QDF_STATUS status = QDF_STATUS_SUCCESS; + bool done = false; + bool async_proc = false; + + AR_DEBUG_PRINTF(ATH_DEBUG_IRQ, + ("+DevDsrHandler: (dev: 0x%lX)\n", + (unsigned long)pdev)); + + /* reset the recv counter that tracks when we need + * to yield from the DSR */ + pdev->CurrentDSRRecvCount = 0; + /* reset counter used to flag a re-scan of IRQ + * status registers on the target */ + pdev->RecheckIRQStatusCnt = 0; + + while (!done) { + status = hif_dev_process_pending_irqs(pdev, &done, &async_proc); + if (QDF_IS_STATUS_ERROR(status)) + break; + + if (HIF_DEVICE_IRQ_SYNC_ONLY == pdev->HifIRQProcessingMode) { + /* the HIF layer does not allow async IRQ processing, + * override the asyncProc flag */ + async_proc = false; + /* this will cause us to re-enter ProcessPendingIRQ() + * and re-read interrupt status registers. + * This has a nice side effect of blocking us until all + * async read requests are completed. This behavior is + * required as we do not allow ASYNC processing + * in interrupt handlers (like Windows CE) */ + + if (pdev->DSRCanYield && DEV_CHECK_RECV_YIELD(pdev)) + /* ProcessPendingIRQs() pulled enough recv + * messages to satisfy the yield count, stop + * checking for more messages and return */ + break; + } + + if (async_proc) { + /* the function does some async I/O for performance, + * we need to exit the ISR immediately, the check below + * will prevent the interrupt from being + * Ack'd while we handle it asynchronously */ + break; + } + + } + + if (QDF_IS_STATUS_SUCCESS(status) && !async_proc) { + /* Ack the interrupt only if : + * 1. we did not get any errors in processing interrupts + * 2. there are no outstanding async processing requests */ + if (pdev->DSRCanYield) { + /* if the DSR can yield do not ACK the interrupt, there + * could be more pending messages. The HIF layer + * must ACK the interrupt on behalf of HTC */ + AR_DEBUG_PRINTF(ATH_DEBUG_IRQ, + (" Yield in effect (cur RX count: %d)\n", + pdev->CurrentDSRRecvCount)); + } else { + AR_DEBUG_PRINTF(ATH_DEBUG_IRQ, + (" Acking interrupt from DevDsrHandler\n")); + hif_ack_interrupt(pdev->HIFDevice); + } + } + + AR_DEBUG_PRINTF(ATH_DEBUG_IRQ, ("-DevDsrHandler\n")); + return status; +} diff --git a/drivers/staging/qca-wifi-host-cmn/hif/src/sdio/hif_sdio_send.c b/drivers/staging/qca-wifi-host-cmn/hif/src/sdio/hif_sdio_send.c new file mode 100644 index 0000000000000000000000000000000000000000..524fd76d0677a007963cb5490c018b68d3fa0b8f --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/hif/src/sdio/hif_sdio_send.c @@ -0,0 +1,197 @@ +/* + * Copyright (c) 2013-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "hif_sdio_internal.h" + +/* + * Data structure to record required sending context data + */ +struct hif_sendContext { + bool bNewAlloc; + struct hif_sdio_device *pDev; + qdf_nbuf_t netbuf; + unsigned int transferID; + unsigned int head_data_len; +}; + +/** + * hif_dev_rw_completion_handler() - Completion routine + * for ALL HIF layer async I/O + * @context: hif send context + * @status: completion routine sync/async context + * + * Return: 0 for success and non-zero for failure + */ +QDF_STATUS hif_dev_rw_completion_handler(void *context, QDF_STATUS status) +{ + struct hif_sendContext *send_context = + (struct hif_sendContext *)context; + unsigned int transfer_id = send_context->transferID; + struct hif_sdio_device *pdev = send_context->pDev; + qdf_nbuf_t buf = send_context->netbuf; + /* Fix Me: Do we need toeplitz_hash_result for SDIO */ + uint32_t toeplitz_hash_result = 0; + + if (send_context->bNewAlloc) + qdf_mem_free((void *)send_context); + else + qdf_nbuf_pull_head(buf, send_context->head_data_len); + if (pdev->hif_callbacks.txCompletionHandler) + pdev->hif_callbacks.txCompletionHandler(pdev->hif_callbacks. + Context, buf, + transfer_id, toeplitz_hash_result); + + return QDF_STATUS_SUCCESS; +} + +/** + * hif_dev_send_buffer() - send buffer to sdio device + * @pDev: sdio function + * @transferID: transfer id + * @pipe: ul/dl pipe + * @nbytes: no of bytes to transfer + * @buf: pointer to buffer + * + * Return: 0 for success and non-zero for failure + */ +QDF_STATUS hif_dev_send_buffer(struct hif_sdio_device *pdev, + unsigned int transfer_id, + uint8_t pipe, unsigned int nbytes, + qdf_nbuf_t buf) +{ + QDF_STATUS status; + uint32_t padded_length; + int frag_count = 0, i, head_data_len; + struct hif_sendContext *send_context; + unsigned char *pData; + uint32_t request = HIF_WR_ASYNC_BLOCK_INC; + uint8_t mbox_index = hif_dev_map_pipe_to_mail_box(pdev, pipe); + + padded_length = DEV_CALC_SEND_PADDED_LEN(pdev, nbytes); + A_ASSERT(padded_length - nbytes < HIF_DUMMY_SPACE_MASK + 1); + /* + * two most significant bytes to save dummy data count + * data written into the dummy space will not put into + * the final mbox FIFO. + */ + request |= ((padded_length - nbytes) << 16); + + frag_count = qdf_nbuf_get_num_frags(buf); + + if (frag_count > 1) { + /* header data length should be total sending length substract + * internal data length of netbuf */ + head_data_len = sizeof(struct hif_sendContext) + + (nbytes - qdf_nbuf_get_frag_len(buf, frag_count - 1)); + } else { + /* + * | hif_sendContext | netbuf->data + */ + head_data_len = sizeof(struct hif_sendContext); + } + + /* Check whether head room is enough to save extra head data */ + if ((head_data_len <= qdf_nbuf_headroom(buf)) && + (qdf_nbuf_tailroom(buf) >= (padded_length - nbytes))) { + send_context = + (struct hif_sendContext *)qdf_nbuf_push_head(buf, + head_data_len); + send_context->bNewAlloc = false; + } else { + send_context = + (struct hif_sendContext *) + qdf_mem_malloc(sizeof(struct hif_sendContext) + + padded_length); + send_context->bNewAlloc = true; + } + + send_context->netbuf = buf; + send_context->pDev = pdev; + send_context->transferID = transfer_id; + send_context->head_data_len = head_data_len; + /* + * Copy data to head part of netbuf or head of allocated buffer. + * if buffer is new allocated, the last buffer should be copied also. + * It assume last fragment is internal buffer of netbuf + * sometime total length of fragments larger than nbytes + */ + pData = (unsigned char *)send_context + sizeof(struct hif_sendContext); + for (i = 0; i < (send_context->bNewAlloc ? frag_count : frag_count - 1); + i++) { + int frag_len = qdf_nbuf_get_frag_len(buf, i); + unsigned char *frag_addr = qdf_nbuf_get_frag_vaddr(buf, i); + if (frag_len > nbytes) + frag_len = nbytes; + memcpy(pData, frag_addr, frag_len); + pData += frag_len; + nbytes -= frag_len; + if (nbytes <= 0) + break; + } + + /* Reset pData pointer and send_context out */ + pData = (unsigned char *)send_context + sizeof(struct hif_sendContext); + status = hif_read_write(pdev->HIFDevice, + pdev->MailBoxInfo.mbox_prop[mbox_index]. + extended_address, (char *)pData, padded_length, + request, (void *)send_context); + + if (status == QDF_STATUS_E_PENDING) + /* + * it will return QDF_STATUS_E_PENDING in native HIF + * implementation, which should be treated as successful + * result here. + */ + status = QDF_STATUS_SUCCESS; + /* release buffer or move back data pointer when failed */ + if (status != QDF_STATUS_SUCCESS) { + if (send_context->bNewAlloc) + qdf_mem_free(send_context); + else + qdf_nbuf_pull_head(buf, head_data_len); + } + + return status; +} diff --git a/drivers/staging/qca-wifi-host-cmn/hif/src/sdio/if_sdio.c b/drivers/staging/qca-wifi-host-cmn/hif/src/sdio/if_sdio.c new file mode 100644 index 0000000000000000000000000000000000000000..289e130e5e126dff8a43521424b61e3d542c37bf --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/hif/src/sdio/if_sdio.c @@ -0,0 +1,636 @@ +/* + * Copyright (c) 2013-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef EXPORT_SYMTAB +#define EXPORT_SYMTAB +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "bmi_msg.h" /* TARGET_TYPE_ */ +#include "if_sdio.h" +#include +#include +#include "regtable_sdio.h" +#include +#ifndef REMOVE_PKT_LOG +#include "ol_txrx_types.h" +#include "pktlog_ac_api.h" +#include "pktlog_ac.h" +#endif +#include "epping_main.h" + +#ifndef ATH_BUS_PM +#ifdef CONFIG_PM +#define ATH_BUS_PM +#endif /* CONFIG_PM */ +#endif /* ATH_BUS_PM */ + +#ifndef REMOVE_PKT_LOG +struct ol_pl_os_dep_funcs *g_ol_pl_os_dep_funcs = NULL; +#endif +#define HIF_SDIO_LOAD_TIMEOUT 1000 + +struct hif_sdio_softc *scn = NULL; +struct hif_softc *ol_sc; +static atomic_t hif_sdio_load_state; +/* Wait queue for MC thread */ +wait_queue_head_t sync_wait_queue; + +/** + * hif_sdio_probe() - configure sdio device + * @context: sdio device context + * @hif_handle: pointer to hif handle + * + * Return: 0 for success and non-zero for failure + */ +static A_STATUS hif_sdio_probe(void *context, void *hif_handle) +{ + int ret = 0; + struct HIF_DEVICE_OS_DEVICE_INFO os_dev_info; + struct sdio_func *func = NULL; + const struct sdio_device_id *id; + uint32_t target_type; + HIF_ENTER(); + + scn = (struct hif_sdio_softc *)qdf_mem_malloc(sizeof(*scn)); + if (!scn) { + ret = -ENOMEM; + goto err_alloc; + } + + scn->hif_handle = hif_handle; + hif_configure_device(hif_handle, HIF_DEVICE_GET_OS_DEVICE, + &os_dev_info, + sizeof(os_dev_info)); + + scn->aps_osdev.device = os_dev_info.os_dev; + scn->aps_osdev.bc.bc_bustype = QDF_BUS_TYPE_SDIO; + spin_lock_init(&scn->target_lock); + ol_sc = qdf_mem_malloc(sizeof(*ol_sc)); + if (!ol_sc) { + ret = -ENOMEM; + goto err_attach; + } + OS_MEMZERO(ol_sc, sizeof(*ol_sc)); + + { + /* + * Attach Target register table. This is needed early on + * even before BMI since PCI and HIF initialization + * directly access Target registers. + * + * TBDXXX: targetdef should not be global -- should be stored + * in per-device struct so that we can support multiple + * different Target types with a single Host driver. + * The whole notion of an "hif type" -- (not as in the hif + * module, but generic "Host Interface Type") is bizarre. + * At first, one one expect it to be things like SDIO, USB, PCI. + * But instead, it's an actual platform type. Inexplicably, the + * values used for HIF platform types are *different* from the + * values used for Target Types. + */ + +#if defined(CONFIG_AR9888_SUPPORT) + hif_register_tbl_attach(ol_sc, HIF_TYPE_AR9888); + target_register_tbl_attach(ol_sc, TARGET_TYPE_AR9888); + target_type = TARGET_TYPE_AR9888; +#elif defined(CONFIG_AR6320_SUPPORT) + id = ((struct hif_sdio_dev *) hif_handle)->id; + if (((id->device & MANUFACTURER_ID_AR6K_BASE_MASK) == + MANUFACTURER_ID_QCA9377_BASE) || + ((id->device & MANUFACTURER_ID_AR6K_BASE_MASK) == + MANUFACTURER_ID_QCA9379_BASE)) { + hif_register_tbl_attach(ol_sc, HIF_TYPE_AR6320V2); + target_register_tbl_attach(ol_sc, TARGET_TYPE_AR6320V2); + } else if ((id->device & MANUFACTURER_ID_AR6K_BASE_MASK) == + MANUFACTURER_ID_AR6320_BASE) { + int ar6kid = id->device & MANUFACTURER_ID_AR6K_REV_MASK; + if (ar6kid >= 1) { + /* v2 or higher silicon */ + hif_register_tbl_attach(ol_sc, + HIF_TYPE_AR6320V2); + target_register_tbl_attach(ol_sc, + TARGET_TYPE_AR6320V2); + } else { + /* legacy v1 silicon */ + hif_register_tbl_attach(ol_sc, + HIF_TYPE_AR6320); + target_register_tbl_attach(ol_sc, + TARGET_TYPE_AR6320); + } + } + target_type = TARGET_TYPE_AR6320; + +#endif + } + func = ((struct hif_sdio_dev *) hif_handle)->func; + scn->targetdef = ol_sc->targetdef; + scn->hostdef = ol_sc->hostdef; + scn->aps_osdev.bdev = func; + ol_sc->bus_type = scn->aps_osdev.bc.bc_bustype; + scn->ol_sc = *ol_sc; + ol_sc->target_info.target_type = target_type; + +#ifndef TARGET_DUMP_FOR_NON_QC_PLATFORM + scn->ramdump_base = ioremap(RAMDUMP_ADDR, RAMDUMP_SIZE); + scn->ramdump_size = RAMDUMP_SIZE; + if (scn->ramdump_base == NULL) { + scn->ramdump_base = 0; + scn->ramdump_size = 0; + } +#endif + + if (athdiag_procfs_init(scn) != 0) { + QDF_TRACE(QDF_MODULE_ID_HIF, QDF_TRACE_LEVEL_ERROR, + "%s athdiag_procfs_init failed", __func__); + ret = QDF_STATUS_E_FAILURE; + goto err_attach1; + } + + atomic_set(&hif_sdio_load_state, true); + wake_up_interruptible(&sync_wait_queue); + + return 0; + +err_attach1: + qdf_mem_free(ol_sc); +err_attach: + qdf_mem_free(scn); + scn = NULL; +err_alloc: + return ret; +} + +/** + * ol_ath_sdio_configure() - configure sdio device + * @hif_sc: pointer to sdio softc structure + * @dev: pointer to net device + * @hif_handle: pointer to sdio function + * + * Return: 0 for success and non-zero for failure + */ +int +ol_ath_sdio_configure(void *hif_sc, struct net_device *dev, + hif_handle_t *hif_hdl) +{ + struct hif_sdio_softc *sc = (struct hif_sdio_softc *)hif_sc; + int ret = 0; + + sc->aps_osdev.netdev = dev; + *hif_hdl = sc->hif_handle; + + return ret; +} + +/** + * hif_sdio_remove() - remove sdio device + * @conext: sdio device context + * @hif_handle: pointer to sdio function + * + * Return: 0 for success and non-zero for failure + */ +static A_STATUS hif_sdio_remove(void *context, void *hif_handle) +{ + HIF_ENTER(); + + if (!scn) { + QDF_TRACE(QDF_MODULE_ID_HIF, QDF_TRACE_LEVEL_ERROR, + "Global SDIO context is NULL"); + return A_ERROR; + } + + atomic_set(&hif_sdio_load_state, false); + athdiag_procfs_remove(); + +#ifndef TARGET_DUMP_FOR_NON_QC_PLATFORM + iounmap(scn->ramdump_base); +#endif + + if (scn) { + qdf_mem_free(scn); + scn = NULL; + } + + HIF_EXIT(); + + return 0; +} + +/** + * hif_sdio_suspend() - sdio suspend routine + * @context: sdio device context + * + * Return: 0 for success and non-zero for failure + */ +static A_STATUS hif_sdio_suspend(void *context) +{ + return 0; +} + +/** + * hif_sdio_resume() - sdio resume routine + * @context: sdio device context + * + * Return: 0 for success and non-zero for failure + */ +static A_STATUS hif_sdio_resume(void *context) +{ + return 0; +} + +/** + * hif_sdio_power_change() - change power state of sdio bus + * @conext: sdio device context + * @config: power state configurartion + * + * Return: 0 for success and non-zero for failure + */ +static A_STATUS hif_sdio_power_change(void *context, uint32_t config) +{ + return 0; +} + +/* + * Module glue. + */ +#include +static char *version = "HIF (Atheros/multi-bss)"; +static char *dev_info = "ath_hif_sdio"; + +/** + * init_ath_hif_sdio() - initialize hif sdio callbacks + * @param: none + * + * Return: 0 for success and non-zero for failure + */ +static int init_ath_hif_sdio(void) +{ + static int probed; + QDF_STATUS status; + struct osdrv_callbacks osdrv_callbacks; + HIF_ENTER(); + + qdf_mem_zero(&osdrv_callbacks, sizeof(osdrv_callbacks)); + osdrv_callbacks.device_inserted_handler = hif_sdio_probe; + osdrv_callbacks.device_removed_handler = hif_sdio_remove; + osdrv_callbacks.device_suspend_handler = hif_sdio_suspend; + osdrv_callbacks.device_resume_handler = hif_sdio_resume; + osdrv_callbacks.device_power_change_handler = hif_sdio_power_change; + + if (probed) + return -ENODEV; + probed++; + + QDF_TRACE(QDF_MODULE_ID_HIF, QDF_TRACE_LEVEL_INFO, "%s %d", __func__, + __LINE__); + status = hif_init(&osdrv_callbacks); + if (status != QDF_STATUS_SUCCESS) { + QDF_TRACE(QDF_MODULE_ID_HIF, QDF_TRACE_LEVEL_FATAL, + "%s hif_init failed!", __func__); + return -ENODEV; + } + QDF_TRACE(QDF_MODULE_ID_HIF, QDF_TRACE_LEVEL_ERROR, + "%s: %s\n", dev_info, version); + + return 0; +} + +/** + * hif_targ_is_awake(): check if target is awake + * + * This function returns true if the target is awake + * + * @scn: struct hif_softc + * @mem: mapped mem base + * + * Return: bool + */ +bool hif_targ_is_awake(struct hif_softc *scn, void *__iomem *mem) +{ + return true; +} + +/** + * hif_sdio_bus_suspend() - suspend the bus + * + * This function suspends the bus, but sdio doesn't need to suspend. + * Therefore do nothing. + * + * Return: 0 for success and non-zero for failure + */ +int hif_sdio_bus_suspend(struct hif_softc *hif_ctx) +{ + struct hif_sdio_softc *scn = HIF_GET_SDIO_SOFTC(hif_ctx); + struct hif_sdio_dev *hif_device = scn->hif_handle; + struct device *dev = &hif_device->func->dev; + + hif_device_suspend(dev); + return 0; +} + + +/** + * hif_sdio_bus_resume() - hif resume API + * + * This function resumes the bus. but sdio doesn't need to resume. + * Therefore do nothing. + * + * Return: 0 for success and non-zero for failure + */ +int hif_sdio_bus_resume(struct hif_softc *hif_ctx) +{ + struct hif_sdio_softc *scn = HIF_GET_SDIO_SOFTC(hif_ctx); + struct hif_sdio_dev *hif_device = scn->hif_handle; + struct device *dev = &hif_device->func->dev; + + hif_device_resume(dev); + return 0; +} + +/** + * hif_enable_power_gating() - enable HW power gating + * + * Return: n/a + */ +void hif_enable_power_gating(void *hif_ctx) +{ +} + +/** + * hif_disable_aspm() - hif_disable_aspm + * + * Return: n/a + */ +void hif_disable_aspm(void) +{ +} + +/** + * hif_sdio_close() - hif_bus_close + * + * Return: None + */ +void hif_sdio_close(struct hif_softc *hif_sc) +{ +} + +/** + * hif_sdio_open() - hif_bus_open + * @hif_sc: hif context + * @bus_type: bus type + * + * Return: QDF status + */ +QDF_STATUS hif_sdio_open(struct hif_softc *hif_sc, + enum qdf_bus_type bus_type) +{ + QDF_STATUS status; + + hif_sc->bus_type = bus_type; + status = init_ath_hif_sdio(); + + return status; +} + +/** + * hif_get_target_type() - Get the target type + * + * This function is used to query the target type. + * + * @ol_sc: ol_softc struct pointer + * @dev: device pointer + * @bdev: bus dev pointer + * @bid: bus id pointer + * @hif_type: HIF type such as HIF_TYPE_QCA6180 + * @target_type: target type such as TARGET_TYPE_QCA6180 + * + * Return: 0 for success + */ +int hif_get_target_type(struct hif_softc *ol_sc, struct device *dev, + void *bdev, const hif_bus_id *bid, uint32_t *hif_type, + uint32_t *target_type) +{ + + return 0; +} + +void hif_get_target_revision(struct hif_softc *ol_sc) +{ + struct hif_softc *ol_sc_local = (struct hif_softc *)ol_sc; + struct hif_opaque_softc *hif_hdl = GET_HIF_OPAQUE_HDL(ol_sc_local); + uint32_t chip_id = 0; + QDF_STATUS rv; + + rv = hif_diag_read_access(hif_hdl, + (CHIP_ID_ADDRESS | RTC_SOC_BASE_ADDRESS), &chip_id); + if (rv != QDF_STATUS_SUCCESS) { + HIF_ERROR("%s[%d]: get chip id fail\n", __func__, __LINE__); + } else { + ol_sc_local->target_info.target_revision = + CHIP_ID_REVISION_GET(chip_id); + } +} + +/** + * hif_sdio_enable_bus() - hif_enable_bus + * @hif_sc: hif context + * @dev: dev + * @bdev: bus dev + * @bid: bus id + * @type: bus type + * + * Return: QDF_STATUS + */ +QDF_STATUS hif_sdio_enable_bus(struct hif_softc *hif_sc, + struct device *dev, void *bdev, const hif_bus_id *bid, + enum hif_enable_type type) +{ + int ret = 0; + const struct sdio_device_id *id = (const struct sdio_device_id *)bid; + struct hif_sdio_softc *sc = HIF_GET_SDIO_SOFTC(hif_sc); + + init_waitqueue_head(&sync_wait_queue); + if (hif_sdio_device_inserted(dev, id)) { + HIF_ERROR("wlan: %s hif_sdio_device_inserted" + "failed", __func__); + return QDF_STATUS_E_NOMEM; + } + + wait_event_interruptible_timeout(sync_wait_queue, + atomic_read(&hif_sdio_load_state) == true, + HIF_SDIO_LOAD_TIMEOUT); + hif_sc->hostdef = ol_sc->hostdef; + hif_sc->targetdef = ol_sc->targetdef; + hif_sc->bus_type = ol_sc->bus_type; + hif_sc->target_info.target_type = ol_sc->target_info.target_type; + + sc->hif_handle = scn->hif_handle; + sc->aps_osdev.device = scn->aps_osdev.device; + sc->aps_osdev.bc.bc_bustype = scn->aps_osdev.bc.bc_bustype; + sc->target_lock = scn->target_lock; + sc->targetdef = scn->targetdef; + sc->hostdef = scn->hostdef; + sc->aps_osdev.bdev = scn->aps_osdev.bdev; + sc->ramdump_size = scn->ramdump_size; + sc->ramdump_base = scn->ramdump_base; + + return ret; +} + + +/** + * hif_sdio_disable_bus() - sdio disable bus + * @hif_sc: hif softc pointer + * + * Return: none + */ +void hif_sdio_disable_bus(struct hif_softc *hif_sc) +{ + struct hif_sdio_softc *sc = HIF_GET_SDIO_SOFTC(hif_sc); + struct sdio_func *func = sc->aps_osdev.bdev; + + hif_sdio_device_removed(func); +} + +/** + * hif_sdio_get_config_item - sdio configure bus + * @hif_sc: hif context + * @opcode: configuration type + * @config: configuration value to set + * @config_len: configuration length + * + * Return: QDF_STATUS_SUCCESS for sucess + */ +QDF_STATUS hif_sdio_get_config_item(struct hif_softc *hif_sc, + int opcode, void *config, uint32_t config_len) +{ + struct hif_sdio_softc *sc = HIF_GET_SDIO_SOFTC(hif_sc); + struct hif_sdio_dev *hif_device = sc->hif_handle; + + return hif_configure_device(hif_device, + opcode, config, config_len); +} + +/** + * hif_sdio_set_mailbox_swap - set mailbox swap + * @hif_sc: hif context + * + * Return: None + */ +void hif_sdio_set_mailbox_swap(struct hif_softc *hif_sc) +{ + struct hif_sdio_softc *scn = HIF_GET_SDIO_SOFTC(hif_sc); + struct hif_sdio_dev *hif_device = scn->hif_handle; + hif_device->swap_mailbox = true; + return; +} + +/** + * hif_sdio_claim_device - set mailbox swap + * @hif_sc: hif context + * + * Return: None + */ +void hif_sdio_claim_device(struct hif_softc *hif_sc) +{ + struct hif_sdio_softc *scn = HIF_GET_SDIO_SOFTC(hif_sc); + struct hif_sdio_dev *hif_device = scn->hif_handle; + hif_device->claimed_ctx = hif_sc; + return; +} + +/** + * hif_sdio_mask_interrupt_call() - disbale hif device irq + * @scn: pointr to softc structure + * + * Return: None + */ +void hif_sdio_mask_interrupt_call(struct hif_softc *scn) +{ + struct hif_sdio_softc *hif_ctx = HIF_GET_SDIO_SOFTC(scn); + struct hif_sdio_dev *hif_device = hif_ctx->hif_handle; + hif_mask_interrupt(hif_device); + return; +} + +/** + * hif_trigger_dump() - trigger various dump cmd + * @scn: struct hif_opaque_softc + * @cmd_id: dump command id + * @start: start/stop dump + * + * Return: None + */ +void hif_trigger_dump(struct hif_opaque_softc *scn, uint8_t cmd_id, bool start) +{ +} + +/** + * hif_check_fw_reg() - hif_check_fw_reg + * @scn: scn + * @state: + * + * Return: int + */ +int hif_check_fw_reg(struct hif_opaque_softc *scn) +{ + return 0; +} + +/** + * hif_wlan_disable() - call the platform driver to disable wlan + * @scn: scn + * + * Return: void + */ +void hif_wlan_disable(struct hif_softc *scn) +{ +} + +/** + * hif_config_target() - configure hif bus + * @hif_hdl: hif handle + * @state: + * + * Return: int + */ +int hif_config_target(void *hif_hdl) +{ + return 0; +} diff --git a/drivers/staging/qca-wifi-host-cmn/hif/src/sdio/if_sdio.h b/drivers/staging/qca-wifi-host-cmn/hif/src/sdio/if_sdio.h new file mode 100644 index 0000000000000000000000000000000000000000..12c65a9983cd28e245a2a1f63c9831e94e8ff053 --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/hif/src/sdio/if_sdio.h @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2013-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef __IF_SDIO_H__ +#define __IF_SDIO_H__ + +#include +#include +#include +#include +#include +#include +#include "a_osapi.h" +#include "hif_internal.h" + + +#define AR6320_HEADERS_DEF + +#define ATH_DBG_DEFAULT 0 + +#define RAMDUMP_ADDR 0x8F000000 +#define RAMDUMP_SIZE 0x700000 + +struct hif_sdio_softc { + struct hif_softc ol_sc; + struct device *dev; + struct _NIC_DEV aps_osdev; + struct tasklet_struct intr_tq; /* tasklet */ + + int irq; + /* + * Guard changes to Target HW state and to software + * structures that track hardware state. + */ + spinlock_t target_lock; + void *hif_handle; + void *ramdump_base; + unsigned long ramdump_address; + unsigned long ramdump_size; + struct targetdef_s *targetdef; + struct hostdef_s *hostdef; +}; + +#if defined(CONFIG_ATH_PROCFS_DIAG_SUPPORT) +int athdiag_procfs_init(void *scn); +void athdiag_procfs_remove(void); +#else +static inline int athdiag_procfs_init(void *scn) +{ + return 0; +} + +static inline void athdiag_procfs_remove(void) +{ + return; +} +#endif + +#ifndef REMOVE_PKT_LOG +extern int pktlogmod_init(void *context); +extern void pktlogmod_exit(void *context); +#endif + +#define DMA_MAPPING_ERROR(dev, addr) dma_mapping_error((dev), (addr)) + +int ath_sdio_probe(void *context, void *hif_handle); +void ath_sdio_remove(void *context, void *hif_handle); +int ath_sdio_suspend(void *context); +int ath_sdio_resume(void *context); + +/*These functions are exposed to HDD*/ +void hif_init_qdf_ctx(qdf_device_t qdf_dev, void *ol_sc); +void hif_deinit_qdf_ctx(void *ol_sc); + +int hif_sdio_device_inserted(struct device *dev, + const struct sdio_device_id *id); +void hif_sdio_stop(struct hif_softc *hif_ctx); +void hif_sdio_shutdown(struct hif_softc *hif_ctx); +void hif_sdio_device_removed(struct sdio_func *func); +int hif_device_suspend(struct device *dev); +int hif_device_resume(struct device *dev); +void hif_register_tbl_attach(struct hif_softc *scn, + u32 hif_type); +void target_register_tbl_attach(struct hif_softc *scn, + u32 target_type); +#endif /* __IF_SDIO_H__ */ diff --git a/drivers/staging/qca-wifi-host-cmn/hif/src/sdio/native_sdio/include/hif_internal.h b/drivers/staging/qca-wifi-host-cmn/hif/src/sdio/native_sdio/include/hif_internal.h new file mode 100644 index 0000000000000000000000000000000000000000..c7ad3a92ca51bf0b8b57e4991b7c3e8831c06009 --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/hif/src/sdio/native_sdio/include/hif_internal.h @@ -0,0 +1,422 @@ +/* + * Copyright (c) 2013-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef _HIF_INTERNAL_H_ +#define _HIF_INTERNAL_H_ + +#include "athdefs.h" +#include "a_types.h" +#include "a_osapi.h" +#include /* qdf_device_t, qdf_print */ +#include /* qdf_system_ticks, etc. */ +#include +#include +#include +#include "hif.h" +#include "hif_debug.h" +#include "hif_sdio_common.h" +#include +#include "hif_main.h" + +#define HIF_LINUX_MMC_SCATTER_SUPPORT + +#define BUS_REQUEST_MAX_NUM 64 + +#define SDIO_CLOCK_FREQUENCY_DEFAULT 25000000 +#define SDWLAN_ENABLE_DISABLE_TIMEOUT 20 +#define FLAGS_CARD_ENAB 0x02 +#define FLAGS_CARD_IRQ_UNMSK 0x04 + +#define HIF_MBOX_BLOCK_SIZE HIF_DEFAULT_IO_BLOCK_SIZE +#define HIF_MBOX0_BLOCK_SIZE 1 +#define HIF_MBOX1_BLOCK_SIZE HIF_MBOX_BLOCK_SIZE +#define HIF_MBOX2_BLOCK_SIZE HIF_MBOX_BLOCK_SIZE +#define HIF_MBOX3_BLOCK_SIZE HIF_MBOX_BLOCK_SIZE + +/* + * direction - Direction of transfer (HIF_SDIO_READ/HIF_SDIO_WRITE). + */ +#define HIF_SDIO_READ 0x00000001 +#define HIF_SDIO_WRITE 0x00000002 +#define HIF_SDIO_DIR_MASK (HIF_SDIO_READ | HIF_SDIO_WRITE) + +/* + * type - An interface may support different kind of rd/wr commands. + * For example: SDIO supports CMD52/CMD53s. In case of MSIO it + * translates to using different kinds of TPCs. The command type + * is thus divided into a basic and an extended command and can + * be specified using HIF_BASIC_IO/HIF_EXTENDED_IO. + */ +#define HIF_BASIC_IO 0x00000004 +#define HIF_EXTENDED_IO 0x00000008 +#define HIF_TYPE_MASK (HIF_BASIC_IO | HIF_EXTENDED_IO) + +/* + * This indicates the whether the command is to be executed in a + * blocking or non-blocking fashion (HIF_SYNCHRONOUS/ + * HIF_ASYNCHRONOUS). The read/write data paths in HTC have been + * implemented using the asynchronous mode allowing the the bus + * driver to indicate the completion of operation through the + * registered callback routine. The requirement primarily comes + * from the contexts these operations get called from (a driver's + * transmit context or the ISR context in case of receive). + * Support for both of these modes is essential. + */ +#define HIF_SYNCHRONOUS 0x00000010 +#define HIF_ASYNCHRONOUS 0x00000020 +#define HIF_EMODE_MASK (HIF_SYNCHRONOUS | HIF_ASYNCHRONOUS) + +/* + * An interface may support different kinds of commands based on + * the tradeoff between the amount of data it can carry and the + * setup time. Byte and Block modes are supported (HIF_BYTE_BASIS/ + * HIF_BLOCK_BASIS). In case of latter, the data is rounded off + * to the nearest block size by padding. The size of the block is + * configurable at compile time using the HIF_BLOCK_SIZE and is + * negotiated with the target during initialization after the + * AR6000 interrupts are enabled. + */ +#define HIF_BYTE_BASIS 0x00000040 +#define HIF_BLOCK_BASIS 0x00000080 +#define HIF_DMODE_MASK (HIF_BYTE_BASIS | HIF_BLOCK_BASIS) + +/* + * This indicates if the address has to be incremented on AR6000 + * after every read/write operation (HIF?FIXED_ADDRESS/ + * HIF_INCREMENTAL_ADDRESS). + */ +#define HIF_FIXED_ADDRESS 0x00000100 +#define HIF_INCREMENTAL_ADDRESS 0x00000200 +#define HIF_AMODE_MASK (HIF_FIXED_ADDRESS | \ + HIF_INCREMENTAL_ADDRESS) + +/* + * data written into the dummy space will not put into the final mbox FIFO + */ +#define HIF_DUMMY_SPACE_MASK 0xFFFF0000 + +/* + * data written into the dummy space will not put into the final mbox FIFO + */ +#define HIF_DUMMY_SPACE_MASK 0xFFFF0000 + + +#define HIF_WR_ASYNC_BYTE_FIX \ + (HIF_SDIO_WRITE | HIF_ASYNCHRONOUS | HIF_EXTENDED_IO | \ + HIF_BYTE_BASIS | HIF_FIXED_ADDRESS) +#define HIF_WR_ASYNC_BYTE_INC \ + (HIF_SDIO_WRITE | HIF_ASYNCHRONOUS | HIF_EXTENDED_IO | \ + HIF_BYTE_BASIS | HIF_INCREMENTAL_ADDRESS) +#define HIF_WR_ASYNC_BLOCK_INC \ + (HIF_SDIO_WRITE | HIF_ASYNCHRONOUS | HIF_EXTENDED_IO | \ + HIF_BLOCK_BASIS | HIF_INCREMENTAL_ADDRESS) +#define HIF_WR_SYNC_BYTE_FIX \ + (HIF_SDIO_WRITE | HIF_SYNCHRONOUS | HIF_EXTENDED_IO | \ + HIF_BYTE_BASIS | HIF_FIXED_ADDRESS) +#define HIF_WR_SYNC_BYTE_INC \ + (HIF_SDIO_WRITE | HIF_SYNCHRONOUS | HIF_EXTENDED_IO | \ + HIF_BYTE_BASIS | HIF_INCREMENTAL_ADDRESS) +#define HIF_WR_SYNC_BLOCK_INC \ + (HIF_SDIO_WRITE | HIF_SYNCHRONOUS | HIF_EXTENDED_IO | \ + HIF_BLOCK_BASIS | HIF_INCREMENTAL_ADDRESS) +#define HIF_WR_ASYNC_BLOCK_FIX \ + (HIF_SDIO_WRITE | HIF_ASYNCHRONOUS | HIF_EXTENDED_IO | \ + HIF_BLOCK_BASIS | HIF_FIXED_ADDRESS) +#define HIF_WR_SYNC_BLOCK_FIX \ + (HIF_SDIO_WRITE | HIF_SYNCHRONOUS | HIF_EXTENDED_IO | \ + HIF_BLOCK_BASIS | HIF_FIXED_ADDRESS) +#define HIF_RD_SYNC_BYTE_INC \ + (HIF_SDIO_READ | HIF_SYNCHRONOUS | HIF_EXTENDED_IO | \ + HIF_BYTE_BASIS | HIF_INCREMENTAL_ADDRESS) +#define HIF_RD_SYNC_BYTE_FIX \ + (HIF_SDIO_READ | HIF_SYNCHRONOUS | HIF_EXTENDED_IO | \ + HIF_BYTE_BASIS | HIF_FIXED_ADDRESS) +#define HIF_RD_ASYNC_BYTE_FIX \ + (HIF_SDIO_READ | HIF_ASYNCHRONOUS | HIF_EXTENDED_IO | \ + HIF_BYTE_BASIS | HIF_FIXED_ADDRESS) +#define HIF_RD_ASYNC_BLOCK_FIX \ + (HIF_SDIO_READ | HIF_ASYNCHRONOUS | HIF_EXTENDED_IO | \ + HIF_BLOCK_BASIS | HIF_FIXED_ADDRESS) +#define HIF_RD_ASYNC_BYTE_INC \ + (HIF_SDIO_READ | HIF_ASYNCHRONOUS | HIF_EXTENDED_IO | \ + HIF_BYTE_BASIS | HIF_INCREMENTAL_ADDRESS) +#define HIF_RD_ASYNC_BLOCK_INC \ + (HIF_SDIO_READ | HIF_ASYNCHRONOUS | HIF_EXTENDED_IO | \ + HIF_BLOCK_BASIS | HIF_INCREMENTAL_ADDRESS) +#define HIF_RD_SYNC_BLOCK_INC \ + (HIF_SDIO_READ | HIF_SYNCHRONOUS | HIF_EXTENDED_IO | \ + HIF_BLOCK_BASIS | HIF_INCREMENTAL_ADDRESS) +#define HIF_RD_SYNC_BLOCK_FIX \ + (HIF_SDIO_READ | HIF_SYNCHRONOUS | HIF_EXTENDED_IO | \ + HIF_BLOCK_BASIS | HIF_FIXED_ADDRESS) + +enum hif_sdio_device_state { + HIF_DEVICE_STATE_ON, + HIF_DEVICE_STATE_DEEPSLEEP, + HIF_DEVICE_STATE_CUTPOWER, + HIF_DEVICE_STATE_WOW +}; + +struct bus_request { + struct bus_request *next; /* link list of available requests */ + struct bus_request *inusenext; /* link list of in use requests */ + struct semaphore sem_req; + uint32_t address; /* request data */ + char *buffer; + uint32_t length; + uint32_t request; + void *context; + QDF_STATUS status; + struct HIF_SCATTER_REQ_PRIV *scatter_req; +}; + +struct hif_sdio_dev { + struct sdio_func *func; + qdf_spinlock_t asynclock; + struct task_struct *async_task; /* task to handle async commands */ + struct semaphore sem_async; /* wake up for async task */ + int async_shutdown; /* stop the async task */ + struct completion async_completion; /* thread completion */ + struct bus_request *asyncreq; /* request for async tasklet */ + struct bus_request *taskreq; /* async tasklet data */ + qdf_spinlock_t lock; + struct bus_request *bus_request_free_queue; /* free list */ + struct bus_request bus_request[BUS_REQUEST_MAX_NUM]; /* bus requests */ + void *claimed_ctx; + struct htc_callbacks htc_callbacks; + uint8_t *dma_buffer; + DL_LIST scatter_req_head; /* scatter request list head */ + bool scatter_enabled; /* scatter enabled flag */ + bool is_suspend; + bool is_disabled; + atomic_t irq_handling; + HIF_DEVICE_POWER_CHANGE_TYPE power_config; + enum hif_sdio_device_state device_state; + const struct sdio_device_id *id; + struct mmc_host *host; + void *htc_context; + bool swap_mailbox; +}; + +struct HIF_DEVICE_OS_DEVICE_INFO { + void *os_dev; +}; + +struct hif_mailbox_properties { + u_int32_t extended_address; /* extended address for larger writes */ + u_int32_t extended_size; +}; + +struct hif_device_irq_yield_params { + int recv_packet_yield_count; /* max number of packets to force DSR + to return */ +}; + +struct hif_device_mbox_info { + u_int32_t mbox_addresses[4]; /*first element for legacy HIFs and + return the address and ARRAY of 32bit words */ + struct hif_mailbox_properties mbox_prop[4]; + u_int32_t gmbox_address; + u_int32_t gmbox_size; + u_int32_t flags; /* flags to describe mbox behavior or usage */ +}; + +enum hif_device_irq_mode { + HIF_DEVICE_IRQ_SYNC_ONLY, /* DSR to process all + * interrupts before returning */ + HIF_DEVICE_IRQ_ASYNC_SYNC, /* DSR to process interrupts */ +}; + +struct osdrv_callbacks { + void *context; /* context to pass for all callbacks + * except device_removed_handler + * the device_removed_handler is only + * called if the device is claimed */ + int (*device_inserted_handler)(void *context, void *hif_handle); + int (*device_removed_handler)(void *claimed_ctx, + void *hif_handle); + int (*device_suspend_handler)(void *context); + int (*device_resume_handler)(void *context); + int (*device_wakeup_handler)(void *context); + int (*device_power_change_handler)(void *context, + HIF_DEVICE_POWER_CHANGE_TYPE + config); +}; + +/* other interrupts are pending, host + * needs to read the to monitor + */ +#define HIF_OTHER_EVENTS (1 << 0) +/* pending recv packet */ +#define HIF_RECV_MSG_AVAIL (1 << 1) + +struct _HIF_PENDING_EVENTS_INFO { + uint32_t events; + uint32_t look_ahead; + uint32_t available_recv_bytes; +}; + +/* hif-sdio pending events handler type, some HIF modules + * use special mechanisms to detect packet available and other interrupts + */ +typedef int (*HIF_PENDING_EVENTS_FUNC)(struct hif_sdio_dev *device, + struct _HIF_PENDING_EVENTS_INFO * + events, void *async_context); + +#define HIF_MASK_RECV true +#define HIF_UNMASK_RECV false +/* hif-sdio Handler type to mask receive events */ +typedef int (*HIF_MASK_UNMASK_RECV_EVENT)(struct hif_sdio_dev *device, + bool mask, + void *async_context); + +QDF_STATUS hif_configure_device(struct hif_sdio_dev *device, + enum hif_device_config_opcode opcode, + void *config, uint32_t config_len); + +QDF_STATUS hif_init(struct osdrv_callbacks *callbacks); + +QDF_STATUS hif_attach_htc(struct hif_sdio_dev *device, + HTC_CALLBACKS *callbacks); + +QDF_STATUS hif_read_write(struct hif_sdio_dev *device, + uint32_t address, + char *buffer, + uint32_t length, uint32_t request, void *context); + +void hif_ack_interrupt(struct hif_sdio_dev *device); + +void hif_mask_interrupt(struct hif_sdio_dev *device); + +void hif_un_mask_interrupt(struct hif_sdio_dev *device); + +QDF_STATUS hif_wait_for_pending_recv(struct hif_sdio_dev *device); + +struct _HIF_SCATTER_ITEM { + u_int8_t *buffer; /* CPU accessible address of buffer */ + int length; /* length of transfer to/from this buffer */ + void *caller_contexts[2]; /* caller context */ +}; + +struct _HIF_SCATTER_REQ; + +typedef void (*HIF_SCATTER_COMP_CB)(struct _HIF_SCATTER_REQ *); + +enum HIF_SCATTER_METHOD { + HIF_SCATTER_NONE = 0, + HIF_SCATTER_DMA_REAL, /* Real SG support no restrictions */ + HIF_SCATTER_DMA_BOUNCE, /* Uses SG DMA */ +}; + +struct _HIF_SCATTER_REQ { + DL_LIST list_link; /* link management */ + u_int32_t address; /* address for the read/write operation */ + u_int32_t request; /* request flags */ + u_int32_t total_length; /* total length of entire transfer */ + u_int32_t caller_flags; /* caller specific flags */ + HIF_SCATTER_COMP_CB completion_routine; /* completion callback */ + int completion_status; /* status of completion */ + void *context; /* caller context for this request */ + int valid_scatter_entries; /* no of valid entries */ + /* scatter method handled by HIF */ + enum HIF_SCATTER_METHOD scatter_method; + void *hif_private[4]; /* HIF private area */ + u_int8_t *scatter_bounce_buffer; /* bounce buffers */ + struct _HIF_SCATTER_ITEM scatter_list[1]; /* start of scatter list */ +}; + +typedef struct +_HIF_SCATTER_REQ * (*HIF_ALLOCATE_SCATTER_REQUEST)(struct hif_sdio_dev *device); +typedef void (*HIF_FREE_SCATTER_REQUEST)(struct hif_sdio_dev *device, + struct _HIF_SCATTER_REQ *request); +typedef QDF_STATUS (*HIF_READWRITE_SCATTER)(struct hif_sdio_dev *device, + struct _HIF_SCATTER_REQ *request); + +struct HIF_DEVICE_SCATTER_SUPPORT_INFO { + /* information returned from HIF layer */ + HIF_ALLOCATE_SCATTER_REQUEST allocate_req_func; + HIF_FREE_SCATTER_REQUEST free_req_func; + HIF_READWRITE_SCATTER read_write_scatter_func; + int max_scatter_entries; + int max_tx_size_per_scatter_req; +}; + +void hif_get_target_revision(struct hif_softc *ol_sc); +struct HIF_SCATTER_REQ_PRIV; + +#define HIF_DMA_BUFFER_SIZE (4 * 1024) +#define CMD53_FIXED_ADDRESS 1 +#define CMD53_INCR_ADDRESS 2 + +struct bus_request *hif_allocate_bus_request(struct hif_sdio_dev *device); +void hif_free_bus_request(struct hif_sdio_dev *device, + struct bus_request *busrequest); +void add_to_async_list(struct hif_sdio_dev *device, + struct bus_request *busrequest); +void hif_dump_cccr(struct hif_sdio_dev *hif_device); + +#ifdef HIF_LINUX_MMC_SCATTER_SUPPORT + +#define MAX_SCATTER_REQUESTS 4 +#define MAX_SCATTER_ENTRIES_PER_REQ 16 +#define MAX_SCATTER_REQ_TRANSFER_SIZE (32*1024) + +struct HIF_SCATTER_REQ_PRIV { + struct _HIF_SCATTER_REQ *hif_scatter_req; + struct hif_sdio_dev *device; /* this device */ + struct bus_request *busrequest; + /* scatter list for linux */ + struct scatterlist sgentries[MAX_SCATTER_ENTRIES_PER_REQ]; +}; + +#define ATH_DEBUG_SCATTER ATH_DEBUG_MAKE_MODULE_MASK(0) + +QDF_STATUS setup_hif_scatter_support(struct hif_sdio_dev *device, + struct HIF_DEVICE_SCATTER_SUPPORT_INFO *info); +void cleanup_hif_scatter_resources(struct hif_sdio_dev *device); +QDF_STATUS do_hif_read_write_scatter(struct hif_sdio_dev *device, + struct bus_request *busrequest); + +#else /* HIF_LINUX_MMC_SCATTER_SUPPORT */ + +static inline QDF_STATUS setup_hif_scatter_support(struct hif_sdio_dev *device, + struct HIF_DEVICE_SCATTER_SUPPORT_INFO *info) +{ + return QDF_STATUS_E_NOSUPPORT; +} + +static inline QDF_STATUS do_hif_read_write_scatter(struct hif_sdio_dev *device, + struct bus_request *busrequest) +{ + return QDF_STATUS_E_NOSUPPORT; +} + +#define cleanup_hif_scatter_resources(d) { } + +#endif /* HIF_LINUX_MMC_SCATTER_SUPPORT */ + +#endif /* _HIF_INTERNAL_H_ */ diff --git a/drivers/staging/qca-wifi-host-cmn/hif/src/sdio/native_sdio/src/hif.c b/drivers/staging/qca-wifi-host-cmn/hif/src/sdio/native_sdio/src/hif.c new file mode 100644 index 0000000000000000000000000000000000000000..f3a247f333349fafb06d456821c527eb0d168e0b --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/hif/src/sdio/native_sdio/src/hif.c @@ -0,0 +1,2725 @@ +/* + * Copyright (c) 2013-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "hif_sdio_dev.h" +#include "if_sdio.h" +#include "regtable_sdio.h" +#include "wma_api.h" +#include "hif_internal.h" + +/* by default setup a bounce buffer for the data packets, + * if the underlying host controller driver + * does not use DMA you may be able to skip this step + * and save the memory allocation and transfer time */ +#define HIF_USE_DMA_BOUNCE_BUFFER 1 +#define ATH_MODULE_NAME hif +#include "a_debug.h" + +#if HIF_USE_DMA_BOUNCE_BUFFER +/* macro to check if DMA buffer is WORD-aligned and DMA-able. + * Most host controllers assume the + * buffer is DMA'able and will bug-check otherwise (i.e. buffers on the stack). + * virt_addr_valid check fails on stack memory. + */ +#define BUFFER_NEEDS_BOUNCE(buffer) (((unsigned long)(buffer) & 0x3) || \ + !virt_addr_valid((buffer))) +#else +#define BUFFER_NEEDS_BOUNCE(buffer) (false) +#endif +#define MAX_HIF_DEVICES 2 +#ifdef HIF_MBOX_SLEEP_WAR +#define HIF_MIN_SLEEP_INACTIVITY_TIME_MS 50 +#define HIF_SLEEP_DISABLE_UPDATE_DELAY 1 +#define HIF_IS_WRITE_REQUEST_MBOX1_TO_3(request) \ + ((request->request & HIF_SDIO_WRITE) && \ + (request->address >= 0x1000 && \ + request->address < 0x1FFFF)) +#endif + +extern struct hif_sdio_softc *sc; + +unsigned int mmcbuswidth = 0; +module_param(mmcbuswidth, uint, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); +MODULE_PARM_DESC(mmcbuswidth, + "Set MMC driver Bus Width: 1-1Bit, 4-4Bit, 8-8Bit"); + +unsigned int mmcclock = 0; +module_param(mmcclock, uint, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); +MODULE_PARM_DESC(mmcclock, "Set MMC driver Clock value"); + +unsigned int brokenirq = 0; +module_param(brokenirq, uint, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); +MODULE_PARM_DESC(brokenirq, + "Set as 1 to use polling method instead of interrupt mode"); + +unsigned int forcesleepmode = 0; +module_param(forcesleepmode, uint, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); +MODULE_PARM_DESC(forcesleepmode, + "Set sleep mode: 0-host capbility, " + "1-force WOW, 2-force DeepSleep, 3-force CutPower"); + +#ifdef CONFIG_X86 +unsigned int asyncintdelay = 2; +module_param(asyncintdelay, uint, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); +MODULE_PARM_DESC(asyncintdelay, + "Delay clock count for aysnc interrupt, " + "2 is default, vaild values are 1 and 2"); +#else +unsigned int asyncintdelay = 0; +module_param(asyncintdelay, uint, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); +MODULE_PARM_DESC(asyncintdelay, + "Delay clock count for aysnc interrupt, " + "0 is default, vaild values are 1 and 2"); +#endif + +unsigned int forcecard = 0; +module_param(forcecard, uint, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); +MODULE_PARM_DESC(forcecard, + "Ignore card capabilities information to switch bus mode"); + +unsigned int debugcccr = 1; +module_param(debugcccr, uint, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); +MODULE_PARM_DESC(debugcccr, "Output this cccr values"); + +unsigned int writecccr1 = 0; +module_param(writecccr1, uint, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); +unsigned int writecccr1value = 0; +module_param(writecccr1value, uint, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); + +unsigned int writecccr2 = 0; +module_param(writecccr2, uint, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); +unsigned int writecccr2value = 0; +module_param(writecccr2value, uint, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); + +unsigned int writecccr3 = 0; +module_param(writecccr3, uint, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); +unsigned int writecccr3value = 0; +module_param(writecccr3value, uint, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); + +unsigned int writecccr4 = 0; +module_param(writecccr4, uint, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); + +unsigned int writecccr4value = 0; +module_param(writecccr4value, uint, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); + +unsigned int modstrength = 0; +module_param(modstrength, uint, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); +MODULE_PARM_DESC(modstrength, "Adjust internal driver strength"); + +#define dev_to_sdio_func(d) container_of(d, struct sdio_func, dev) +#define to_sdio_driver(d) container_of(d, struct sdio_driver, drv) +static int hif_device_inserted(struct sdio_func *func, + const struct sdio_device_id *id); +static void hif_device_removed(struct sdio_func *func); +static struct hif_sdio_dev *add_hif_device(struct sdio_func *func); +static struct hif_sdio_dev *get_hif_device(struct sdio_func *func); +static void del_hif_device(struct hif_sdio_dev *device); +static int func0_cmd52_write_byte(struct mmc_card *card, unsigned int address, + unsigned char byte); +static int func0_cmd52_read_byte(struct mmc_card *card, unsigned int address, + unsigned char *byte); + +int reset_sdio_on_unload = 0; +module_param(reset_sdio_on_unload, int, 0644); + +uint32_t nohifscattersupport = 1; + +uint32_t forcedriverstrength = 1; /* force driver strength to type D */ + +/* ------ Static Variables ------ */ +static const struct sdio_device_id ar6k_id_table[] = { +#ifdef AR6002_HEADERS_DEF + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6002_BASE | 0x0))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6002_BASE | 0x1))}, +#endif +#ifdef AR6003_HEADERS_DEF + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6003_BASE | 0x0))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6003_BASE | 0x1))}, +#endif +#ifdef AR6004_HEADERS_DEF + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6004_BASE | 0x0))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6004_BASE | 0x1))}, +#endif +#ifdef AR6320_HEADERS_DEF + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0x0))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0x1))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0x2))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0x3))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0x4))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0x5))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0x6))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0x7))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0x8))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0x9))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0xA))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0xB))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0xC))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0xD))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0xE))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0xF))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0x0))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0x1))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0x2))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0x3))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0x4))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0x5))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0x6))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0x7))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0x8))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0x9))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0xA))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0xB))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0xC))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0xD))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0xE))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0xF))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9379_BASE | 0x0))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9379_BASE | 0x1))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9379_BASE | 0x2))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9379_BASE | 0x3))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9379_BASE | 0x4))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9379_BASE | 0x5))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9379_BASE | 0x6))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9379_BASE | 0x7))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9379_BASE | 0x8))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9379_BASE | 0x9))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9379_BASE | 0xA))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9379_BASE | 0xB))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9379_BASE | 0xC))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9379_BASE | 0xD))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9379_BASE | 0xE))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9379_BASE | 0xF))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (0 | 0x0))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (0 | 0x1))}, +#endif + { /* null */ }, +}; + +#ifndef CONFIG_CNSS_SDIO +MODULE_DEVICE_TABLE(sdio, ar6k_id_table); + +static struct sdio_driver ar6k_driver = { + .name = "ar6k_wlan", + .id_table = ar6k_id_table, + .probe = hif_device_inserted, + .remove = hif_device_removed, +}; + +static const struct dev_pm_ops ar6k_device_pm_ops = { + .suspend = hif_device_suspend, + .resume = hif_device_resume, +}; + +#endif + +/* make sure we only unregister when registered. */ +static int registered; + +struct osdrv_callbacks osdrv_callbacks; +uint32_t onebitmode; +uint32_t busspeedlow; +uint32_t debughif; + +static struct hif_sdio_dev *hif_devices[MAX_HIF_DEVICES]; + +static void reset_all_cards(void); +static QDF_STATUS hif_disable_func(struct hif_sdio_dev *device, + struct sdio_func *func); +static QDF_STATUS hif_enable_func(struct hif_sdio_dev *device, + struct sdio_func *func); + +#if defined(WLAN_DEBUG) || defined(DEBUG) +ATH_DEBUG_INSTANTIATE_MODULE_VAR(hif, + "hif", + "(Linux MMC) Host Interconnect Framework", + ATH_DEBUG_MASK_DEFAULTS, 0, NULL); +#endif + +static int hif_sdio_init_callbacks(struct osdrv_callbacks *callbacks) +{ + int status = 0; + /* store the callback handlers */ + osdrv_callbacks = *callbacks; + + /* Register with bus driver core is done from HDD */ + AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("%s: HIFInit registering\n", + __func__)); + registered = 1; + + return status; +} +static void hif_sdio_remove_callbacks(void) +{ + qdf_mem_zero(&osdrv_callbacks, sizeof(osdrv_callbacks)); +} + + +/** + * hif_init() - Initializes the driver callbacks + * @callbacks: pointer to driver callback structure + * + * Return: 0 on success, error number otherwise. + */ +QDF_STATUS hif_init(struct osdrv_callbacks *callbacks) +{ + int status; + + AR_DEBUG_ASSERT(callbacks != NULL); + A_REGISTER_MODULE_DEBUG_INFO(hif); + + HIF_ENTER(); + + status = hif_sdio_init_callbacks(callbacks); + AR_DEBUG_ASSERT(status == 0); + + if (status != 0) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, + ("%s sdio_register_driver failed!", __func__)); + return QDF_STATUS_E_FAILURE; + } else { + AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, + ("%s sdio_register_driver successful", __func__)); + } + + return QDF_STATUS_SUCCESS; + +} + +/** + * __hif_read_write() - sdio read/write wrapper + * @device: pointer to hif device structure + * @address: address to read + * @buffer: buffer to hold read/write data + * @length: length to read/write + * @request: read/write/sync/async request + * @context: pointer to hold calling context + * + * Return: 0 on success, error number otherwise. + */ +static QDF_STATUS +__hif_read_write(struct hif_sdio_dev *device, + uint32_t address, + char *buffer, + uint32_t length, uint32_t request, void *context) +{ + uint8_t opcode; + QDF_STATUS status = QDF_STATUS_SUCCESS; + int ret; + uint8_t *tbuffer; + bool bounced = false; + + AR_DEBUG_ASSERT(device != NULL); + AR_DEBUG_ASSERT(device->func != NULL); + AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, + ("__hif_read_write, addr:0X%06X, len:%08d, %s, %s\n", + address, length, + request & HIF_SDIO_READ ? "Read " : "Write", + request & HIF_ASYNCHRONOUS ? "Async" : "Sync ")); + + do { + if (request & HIF_EXTENDED_IO) { + AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, + ("%s: Command type: CMD53\n", __func__)); + } else { + AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, + ("%s: Invalid command type: 0x%08x\n", + __func__, request)); + status = QDF_STATUS_E_INVAL; + break; + } + + if (request & HIF_BLOCK_BASIS) { + /* round to whole block length size */ + length = + (length / HIF_MBOX_BLOCK_SIZE) * + HIF_MBOX_BLOCK_SIZE; + AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, + ("%s: Block mode (BlockLen: %d)\n", + __func__, length)); + } else if (request & HIF_BYTE_BASIS) { + AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, + ("%s: Byte mode (BlockLen: %d)\n", + __func__, length)); + } else { + AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, + ("%s: Invalid data mode: 0x%08x\n", + __func__, request)); + status = QDF_STATUS_E_INVAL; + break; + } + if (request & HIF_SDIO_WRITE) { + struct hif_device_mbox_info MailBoxInfo; + unsigned int mboxLength = 0; + hif_configure_device(device, + HIF_DEVICE_GET_MBOX_ADDR, + &MailBoxInfo, sizeof(MailBoxInfo)); + if (address >= 0x800 && address < 0xC00) { + /* Host control register and CIS Window */ + mboxLength = 0; + } else if (address == MailBoxInfo.mbox_addresses[0] + || address == MailBoxInfo.mbox_addresses[1] + || address == MailBoxInfo.mbox_addresses[2] + || address == + MailBoxInfo.mbox_addresses[3]) { + mboxLength = HIF_MBOX_WIDTH; + } else if (address == + MailBoxInfo.mbox_prop[0].extended_address) { + mboxLength = + MailBoxInfo.mbox_prop[0].extended_size; + } else if (address == + MailBoxInfo.mbox_prop[1].extended_address) { + mboxLength = + MailBoxInfo.mbox_prop[1].extended_size; + } else { + AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, + ("Invalid written address: 0x%08x\n", + address)); + break; + } + AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, + ("address:%08X, Length:0x%08X, Dummy:0x%04X, " + "Final:0x%08X\n", + address, length, + (request & HIF_DUMMY_SPACE_MASK) >> 16, + mboxLength == + 0 ? address : address + (mboxLength - + length))); + if (mboxLength != 0) { + if (length > mboxLength) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, + ("%s: written length(0x%08X) " + "larger than mbox len(0x%08x)\n", + __func__, length, mboxLength)); + break; + } + address += (mboxLength - length); + /* + * plus dummy byte count + */ + address += ((request & + HIF_DUMMY_SPACE_MASK) >> 16); + } + } + + if (request & HIF_FIXED_ADDRESS) { + opcode = CMD53_FIXED_ADDRESS; + AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, + ("%s: Address mode: Fixed 0x%X\n", + __func__, address)); + } else if (request & HIF_INCREMENTAL_ADDRESS) { + opcode = CMD53_INCR_ADDRESS; + AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, + ("%s: Address mode: Incremental 0x%X\n", + __func__, address)); + } else { + AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, + ("%s: Invalid address mode: 0x%08x\n", + __func__, request)); + status = QDF_STATUS_E_INVAL; + break; + } + + if (request & HIF_SDIO_WRITE) { +#if HIF_USE_DMA_BOUNCE_BUFFER + if (BUFFER_NEEDS_BOUNCE(buffer)) { + AR_DEBUG_ASSERT(device->dma_buffer != NULL); + tbuffer = device->dma_buffer; + /* copy the write data to the dma buffer */ + AR_DEBUG_ASSERT(length <= HIF_DMA_BUFFER_SIZE); + if (length > HIF_DMA_BUFFER_SIZE) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, + ("%s: Invalid write length:" + "%d\n", __func__, length)); + status = QDF_STATUS_E_INVAL; + break; + } + memcpy(tbuffer, buffer, length); + bounced = true; + } else { + tbuffer = buffer; + } +#else + tbuffer = buffer; +#endif + if (opcode == CMD53_FIXED_ADDRESS && tbuffer != NULL) { + ret = + sdio_writesb(device->func, address, + tbuffer, + length); + AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, + ("%s: writesb ret=%d address:" + " 0x%X, len: %d, 0x%X\n", + __func__, ret, address, length, + *(int *)tbuffer)); + } else { + ret = + sdio_memcpy_toio(device->func, address, + tbuffer, length); + AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, + ("%s: writeio ret=%d address: " + " 0x%X, len: %d, 0x%X\n", + __func__, ret, address, length, + *(int *)tbuffer)); + } + } else if (request & HIF_SDIO_READ) { +#if HIF_USE_DMA_BOUNCE_BUFFER + if (BUFFER_NEEDS_BOUNCE(buffer)) { + AR_DEBUG_ASSERT(device->dma_buffer != NULL); + AR_DEBUG_ASSERT(length <= HIF_DMA_BUFFER_SIZE); + if (length > HIF_DMA_BUFFER_SIZE) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, + ("%s: Invalid read length: %d\n", + __func__, length)); + status = QDF_STATUS_E_INVAL; + break; + } + tbuffer = device->dma_buffer; + bounced = true; + } else { + tbuffer = buffer; + } +#else + tbuffer = buffer; +#endif + if (opcode == CMD53_FIXED_ADDRESS && tbuffer != NULL) { + ret = + sdio_readsb(device->func, tbuffer, + address, + length); + AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, + ("%s: readsb ret=%d address:" + " 0x%X, len: %d, 0x%X\n", + __func__, ret, address, length, + *(int *)tbuffer)); + } else { + ret = + sdio_memcpy_fromio(device->func, + tbuffer, + address, length); + AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, + ("%s: readio ret=%d address: 0x%X," + " len: %d, 0x%X\n", + __func__, ret, address, length, + *(int *)tbuffer)); + } +#if HIF_USE_DMA_BOUNCE_BUFFER + if (bounced) + memcpy(buffer, tbuffer, length); +#endif + } else { + AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, + ("%s: Invalid direction: 0x%08x\n", + __func__, request)); + status = QDF_STATUS_E_INVAL; + break; + } + + if (ret) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, + ("%s: SDIO bus operation failed! " + "MMC stack returned : %d\n", + __func__, ret)); + AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, + ("__hif_read_write, addr:0X%06X, " + "len:%08d, %s, %s\n", + address, length, + request & HIF_SDIO_READ ? "Read " : "Write", + request & HIF_ASYNCHRONOUS ? "Async" : + "Sync ")); + status = QDF_STATUS_E_FAILURE; + } + } while (false); + + return status; +} + +/** + * add_to_async_list() - add bus reqest to async task list + * @device: pointer to hif device + * @busrequest: pointer to type of bus request + * + * Return: None. + */ +void add_to_async_list(struct hif_sdio_dev *device, + struct bus_request *busrequest) +{ + struct bus_request *async; + struct bus_request *active; + + qdf_spin_lock_irqsave(&device->asynclock); + active = device->asyncreq; + if (active == NULL) { + device->asyncreq = busrequest; + device->asyncreq->inusenext = NULL; + } else { + for (async = device->asyncreq; + async != NULL; async = async->inusenext) { + active = async; + } + active->inusenext = busrequest; + busrequest->inusenext = NULL; + } + qdf_spin_unlock_irqrestore(&device->asynclock); +} + +/** + * hif_read_write() - queue a read/write request + * @device: pointer to hif device structure + * @address: address to read + * @buffer: buffer to hold read/write data + * @length: length to read/write + * @request: read/write/sync/async request + * @context: pointer to hold calling context + * + * Return: 0 on success, error number otherwise. + */ +QDF_STATUS +hif_read_write(struct hif_sdio_dev *device, + uint32_t address, + char *buffer, uint32_t length, + uint32_t request, void *context) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct bus_request *busrequest; + + AR_DEBUG_ASSERT(device != NULL); + AR_DEBUG_ASSERT(device->func != NULL); + AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, + ("%s: device 0x%p addr 0x%X buffer 0x%p " + "len %d req 0x%X context 0x%p", + __func__, device, address, buffer, + length, request, context)); + + /*sdio r/w action is not needed when suspend, so just return */ + if ((device->is_suspend == true) + && (device->power_config == HIF_DEVICE_POWER_CUT)) { + AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, ("skip io when suspending\n")); + return QDF_STATUS_SUCCESS; + } + do { + if ((request & HIF_ASYNCHRONOUS) || + (request & HIF_SYNCHRONOUS)) { + /* serialize all requests through the async thread */ + AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, + ("%s: Execution mode: %s\n", __func__, + (request & HIF_ASYNCHRONOUS) ? "Async" + : "Synch")); + busrequest = hif_allocate_bus_request(device); + if (busrequest == NULL) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, + ("no async bus requests " + "available (%s, addr:0x%X, len:%d)\n", + request & HIF_SDIO_READ ? "READ" : + "WRITE", address, length)); + return QDF_STATUS_E_FAILURE; + } + busrequest->address = address; + busrequest->buffer = buffer; + busrequest->length = length; + busrequest->request = request; + busrequest->context = context; + + add_to_async_list(device, busrequest); + + if (request & HIF_SYNCHRONOUS) { + AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, + ("%s: queued sync req: 0x%lX\n", + __func__, (unsigned long)busrequest)); + + /* wait for completion */ + up(&device->sem_async); + if (down_interruptible(&busrequest->sem_req) != + 0) { + /* interrupted, exit */ + return QDF_STATUS_E_FAILURE; + } else { + QDF_STATUS status = busrequest->status; + AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, + ("%s: sync return freeing 0x%lX: 0x%X\n", + __func__, + (unsigned long) + busrequest, + busrequest->status)); + AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, + ("%s: freeing req: 0x%X\n", + __func__, + (unsigned int) + request)); + hif_free_bus_request(device, + busrequest); + return status; + } + } else { + AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, + ("%s: queued async req: 0x%lX\n", + __func__, + (unsigned long)busrequest)); + up(&device->sem_async); + return QDF_STATUS_E_PENDING; + } + } else { + AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, + ("%s: Invalid execution mode: 0x%08x\n", + __func__, + (unsigned int)request)); + status = QDF_STATUS_E_INVAL; + break; + } + } while (0); + + return status; +} + +/** + * async_task() - thread function to serialize all bus requests + * @param: pointer to hif device + * + * thread function to serialize all requests, both sync and async + * Return: 0 on success, error number otherwise. + */ +static int async_task(void *param) +{ + struct hif_sdio_dev *device; + struct bus_request *request; + QDF_STATUS status; + + device = (struct hif_sdio_dev *) param; + set_current_state(TASK_INTERRUPTIBLE); + while (!device->async_shutdown) { + /* wait for work */ + if (down_interruptible(&device->sem_async) != 0) { + /* interrupted, exit */ + AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, + ("%s: async task interrupted\n", + __func__)); + break; + } + if (device->async_shutdown) { + AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, + ("%s: async task stopping\n", + __func__)); + break; + } + /* we want to hold the host over multiple cmds + * if possible, but holding the host blocks + * card interrupts */ + sdio_claim_host(device->func); + qdf_spin_lock_irqsave(&device->asynclock); + /* pull the request to work on */ + while (device->asyncreq != NULL) { + request = device->asyncreq; + if (request->inusenext != NULL) + device->asyncreq = request->inusenext; + else + device->asyncreq = NULL; + qdf_spin_unlock_irqrestore(&device->asynclock); + AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, + ("%s: async_task processing req: 0x%lX\n", + __func__, (unsigned long)request)); + + if (request->scatter_req != NULL) { + A_ASSERT(device->scatter_enabled); + /* pass the request to scatter routine which + * executes it synchronously, note, no need + * to free the request since scatter requests + * are maintained on a separate list */ + status = do_hif_read_write_scatter(device, + request); + } else { + /* call hif_read_write in sync mode */ + status = + __hif_read_write(device, + request->address, + request->buffer, + request->length, + request-> + request & + ~HIF_SYNCHRONOUS, + NULL); + if (request->request & HIF_ASYNCHRONOUS) { + void *context = request->context; + AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, + ("%s: freeing req: 0x%lX\n", + __func__, (unsigned long) + request)); + hif_free_bus_request(device, request); + AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, + ("%s: async_task completion req 0x%lX\n", + __func__, (unsigned long) + request)); + device->htc_callbacks. + rwCompletionHandler(context, + status); + } else { + AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, + ("%s: async_task upping req: 0x%lX\n", + __func__, (unsigned long) + request)); + request->status = status; + up(&request->sem_req); + } + } + qdf_spin_lock_irqsave(&device->asynclock); + } + qdf_spin_unlock_irqrestore(&device->asynclock); + sdio_release_host(device->func); + } + + complete_and_exit(&device->async_completion, 0); + + return 0; +} + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 16, 0)) +/** + * sdio_card_highspeed() - check if high speed supported + * @card: pointer to mmc card struct + * + * Return: non zero if card supports high speed. + */ +static inline int sdio_card_highspeed(struct mmc_card *card) +{ + return mmc_card_highspeed(card); +} +#else +static inline int sdio_card_highspeed(struct mmc_card *card) +{ + return mmc_card_hs(card); +} +#endif + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 16, 0)) +/** + * sdio_card_set_highspeed() - set high speed + * @card: pointer to mmc card struct + * + * Return: none. + */ +static inline void sdio_card_set_highspeed(struct mmc_card *card) +{ + mmc_card_set_highspeed(card); +} +#else +static inline void sdio_card_set_highspeed(struct mmc_card *card) +{ +} +#endif + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 16, 0)) +/** + * sdio_card_state() - set card state + * @card: pointer to mmc card struct + * + * Return: none. + */ +static inline void sdio_card_state(struct mmc_card *card) +{ + card->state &= ~MMC_STATE_HIGHSPEED; +} +#else +static inline void sdio_card_state(struct mmc_card *card) +{ +} +#endif + +/** + * reinit_sdio() - re-initialize sdio bus + * @param: pointer to hif device + * + * Return: 0 on success, error number otherwise. + */ +QDF_STATUS reinit_sdio(struct hif_sdio_dev *device) +{ + int32_t err = 0; + struct mmc_host *host; + struct mmc_card *card; + struct sdio_func *func; + uint8_t cmd52_resp; + uint32_t clock; + + func = device->func; + card = func->card; + host = card->host; + + sdio_claim_host(func); + + do { + /* Enable high speed */ + if (card->host->caps & MMC_CAP_SD_HIGHSPEED) { + AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, + ("%s: Set high speed mode\n", + __func__)); + err = func0_cmd52_read_byte(card, SDIO_CCCR_SPEED, + &cmd52_resp); + if (err) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + ("%s: CMD52 read to CCCR speed " + "register failed : %d\n", + __func__, err)); + sdio_card_state(card); + /* no need to break */ + } else { + err = func0_cmd52_write_byte(card, + SDIO_CCCR_SPEED, + (cmd52_resp | SDIO_SPEED_EHS)); + if (err) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + ("%s: CMD52 write to CCCR speed" + " register failed : %d\n", + __func__, err)); + break; + } + sdio_card_set_highspeed(card); + host->ios.timing = MMC_TIMING_SD_HS; + host->ops->set_ios(host, &host->ios); + } + } + + /* Set clock */ + if (sdio_card_highspeed(card)) + clock = 50000000; + else + clock = card->cis.max_dtr; + + if (clock > host->f_max) + clock = host->f_max; + /* + * In fpga mode the clk should be set to 12500000, + * or will result in scan channel setting timeout error. + * So in fpga mode, please set module parameter mmcclock + * to 12500000. + */ + if (mmcclock > 0) + clock = mmcclock; + host->ios.clock = clock; + host->ops->set_ios(host, &host->ios); + + + if (card->host->caps & MMC_CAP_4_BIT_DATA) { + /* CMD52: Set bus width & disable card detect resistor */ + err = func0_cmd52_write_byte(card, SDIO_CCCR_IF, + SDIO_BUS_CD_DISABLE | SDIO_BUS_WIDTH_4BIT); + if (err) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + ("%s: CMD52 to set bus mode " + "failed : %d\n", + __func__, err)); + break; + } + host->ios.bus_width = MMC_BUS_WIDTH_4; + host->ops->set_ios(host, &host->ios); + } + } while (0); + + sdio_release_host(func); + + return (err) ? QDF_STATUS_E_FAILURE : QDF_STATUS_SUCCESS; +} + +/* + * Setup IRQ mode for deep sleep and WoW + * Switch back to 1 bits mode when we suspend for + * WoW in order to detect SDIO irq without clock. + * Re-enable async 4-bit irq mode for some host controllers + * after resume. + */ +static int sdio_enable4bits(struct hif_sdio_dev *device, int enable) +{ + int ret = 0; + struct sdio_func *func = device->func; + struct mmc_card *card = func->card; + struct mmc_host *host = card->host; + + if (!(host->caps & (MMC_CAP_4_BIT_DATA))) + return 0; + + if (card->cccr.low_speed && !card->cccr.wide_bus) + return 0; + + sdio_claim_host(func); + do { + int setAsyncIRQ = 0; + __u16 manufacturer_id = + device->id->device & MANUFACTURER_ID_AR6K_BASE_MASK; + + /* Re-enable 4-bit ASYNC interrupt on AR6003x + * after system resume for some host controller */ + if (manufacturer_id == MANUFACTURER_ID_AR6003_BASE) { + setAsyncIRQ = 1; + ret = + func0_cmd52_write_byte(func->card, + CCCR_SDIO_IRQ_MODE_REG_AR6003, + enable ? + SDIO_IRQ_MODE_ASYNC_4BIT_IRQ_AR6003 + : 0); + } else if (manufacturer_id == MANUFACTURER_ID_AR6320_BASE + || manufacturer_id == MANUFACTURER_ID_QCA9377_BASE) { + unsigned char data = 0; + setAsyncIRQ = 1; + ret = + func0_cmd52_read_byte(func->card, + CCCR_SDIO_IRQ_MODE_REG_AR6320, + &data); + if (ret) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + ("%s: failed to read interrupt " + "extension register %d\n", + __func__, ret)); + sdio_release_host(func); + return ret; + } + if (enable) + data |= SDIO_IRQ_MODE_ASYNC_4BIT_IRQ_AR6320; + else + data &= ~SDIO_IRQ_MODE_ASYNC_4BIT_IRQ_AR6320; + ret = + func0_cmd52_write_byte(func->card, + CCCR_SDIO_IRQ_MODE_REG_AR6320, + data); + } + if (setAsyncIRQ) { + if (ret) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + ("%s: failed to setup 4-bit " + "ASYNC IRQ mode into %d err %d\n", + __func__, enable, ret)); + } else { + AR_DEBUG_PRINTF(ATH_DEBUG_INFO, + ("%s: Setup 4-bit ASYNC " + "IRQ mode into %d successfully\n", + __func__, enable)); + } + } + } while (0); + sdio_release_host(func); + + return ret; +} + + +/** + * power_state_change_notify() - SDIO bus power notification handler + * @config: hif device power change type + * + * Return: 0 on success, error number otherwise. + */ +QDF_STATUS +power_state_change_notify(struct hif_sdio_dev *device, + HIF_DEVICE_POWER_CHANGE_TYPE config) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct sdio_func *func = device->func; + int old_reset_val; + + AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, + ("%s: config type %d\n", + __func__, config)); + switch (config) { + case HIF_DEVICE_POWER_DOWN: + /* Disable 4bits to allow SDIO bus to detect + * DAT1 as interrupt source */ + sdio_enable4bits(device, 0); + break; + case HIF_DEVICE_POWER_CUT: + old_reset_val = reset_sdio_on_unload; + reset_sdio_on_unload = 1; + status = hif_disable_func(device, func); + reset_sdio_on_unload = old_reset_val; + if (!device->is_suspend) { + device->power_config = config; + mmc_detect_change(device->host, HZ / 3); + } + break; + case HIF_DEVICE_POWER_UP: + if (device->power_config == HIF_DEVICE_POWER_CUT) { + if (device->is_suspend) { + status = reinit_sdio(device); + /* set power_config before EnableFunc to + * passthrough sdio r/w action when resuming + * from cut power */ + device->power_config = config; + if (status == QDF_STATUS_SUCCESS) + status = hif_enable_func(device, func); + } else { + /* device->func is bad pointer at this time */ + mmc_detect_change(device->host, 0); + return QDF_STATUS_E_PENDING; + } + } else if (device->power_config == HIF_DEVICE_POWER_DOWN) { + int ret = sdio_enable4bits(device, 1); + status = (ret == 0) ? QDF_STATUS_SUCCESS : + QDF_STATUS_E_FAILURE; + } + break; + } + device->power_config = config; + + AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, + ("%s:\n", __func__)); + + return status; +} + +#ifdef SDIO_3_0 +/** + * set_extended_mbox_size() - set extended MBOX size + * @pinfo: sdio mailbox info + * + * Return: none. + */ +static void set_extended_mbox_size(struct hif_device_mbox_info *pinfo) +{ + pinfo->mbox_prop[0].extended_size = + HIF_MBOX0_EXTENDED_WIDTH_AR6320_ROME_2_0; + pinfo->mbox_prop[1].extended_size = + HIF_MBOX1_EXTENDED_WIDTH_AR6320; +} + +/** + * set_extended_mbox_address() - set extended MBOX address + * @pinfo: sdio mailbox info + * + * Return: none. + */ +static void set_extended_mbox_address(struct hif_device_mbox_info *pinfo) +{ + pinfo->mbox_prop[1].extended_address = + pinfo->mbox_prop[0].extended_address + + pinfo->mbox_prop[0].extended_size + + HIF_MBOX_DUMMY_SPACE_SIZE_AR6320; +} +#else +static void set_extended_mbox_size(struct hif_device_mbox_info *pinfo) +{ + pinfo->mbox_prop[0].extended_size = + HIF_MBOX0_EXTENDED_WIDTH_AR6320; +} +static inline void +set_extended_mbox_address(struct hif_device_mbox_info *pinfo) +{ + +} +#endif + +/** + * set_extended_mbox_window_info() - set extended MBOX window + * information for SDIO interconnects + * @manf_id: manufacturer id + * @pinfo: sdio mailbox info + * + * Return: none. + */ +static void set_extended_mbox_window_info(uint16_t manf_id, + struct hif_device_mbox_info *pinfo) +{ + switch (manf_id & MANUFACTURER_ID_AR6K_BASE_MASK) { + case MANUFACTURER_ID_AR6002_BASE: + /* MBOX 0 has an extended range */ + + pinfo->mbox_prop[0].extended_address = + HIF_MBOX0_EXTENDED_BASE_ADDR_AR6003_V1; + pinfo->mbox_prop[0].extended_size = + HIF_MBOX0_EXTENDED_WIDTH_AR6003_V1; + + pinfo->mbox_prop[0].extended_address = + HIF_MBOX0_EXTENDED_BASE_ADDR_AR6003_V1; + pinfo->mbox_prop[0].extended_size = + HIF_MBOX0_EXTENDED_WIDTH_AR6003_V1; + + pinfo->mbox_prop[0].extended_address = + HIF_MBOX0_EXTENDED_BASE_ADDR_AR6004; + pinfo->mbox_prop[0].extended_size = + HIF_MBOX0_EXTENDED_WIDTH_AR6004; + + break; + case MANUFACTURER_ID_AR6003_BASE: + /* MBOX 0 has an extended range */ + pinfo->mbox_prop[0].extended_address = + HIF_MBOX0_EXTENDED_BASE_ADDR_AR6003_V1; + pinfo->mbox_prop[0].extended_size = + HIF_MBOX0_EXTENDED_WIDTH_AR6003_V1; + pinfo->gmbox_address = HIF_GMBOX_BASE_ADDR; + pinfo->gmbox_size = HIF_GMBOX_WIDTH; + break; + case MANUFACTURER_ID_AR6004_BASE: + pinfo->mbox_prop[0].extended_address = + HIF_MBOX0_EXTENDED_BASE_ADDR_AR6004; + pinfo->mbox_prop[0].extended_size = + HIF_MBOX0_EXTENDED_WIDTH_AR6004; + pinfo->gmbox_address = HIF_GMBOX_BASE_ADDR; + pinfo->gmbox_size = HIF_GMBOX_WIDTH; + break; + case MANUFACTURER_ID_AR6320_BASE: { + uint16_t ManuRevID = + manf_id & MANUFACTURER_ID_AR6K_REV_MASK; + pinfo->mbox_prop[0].extended_address = + HIF_MBOX0_EXTENDED_BASE_ADDR_AR6320; + if (ManuRevID < 4) { + pinfo->mbox_prop[0].extended_size = + HIF_MBOX0_EXTENDED_WIDTH_AR6320; + } else { + /* from rome 2.0(0x504), the width has been extended to 56K */ + set_extended_mbox_size(pinfo); + } + set_extended_mbox_address(pinfo); + pinfo->gmbox_address = HIF_GMBOX_BASE_ADDR; + pinfo->gmbox_size = HIF_GMBOX_WIDTH; + break; + } + case MANUFACTURER_ID_QCA9377_BASE: + pinfo->mbox_prop[0].extended_address = + HIF_MBOX0_EXTENDED_BASE_ADDR_AR6320; + pinfo->mbox_prop[0].extended_size = + HIF_MBOX0_EXTENDED_WIDTH_AR6320_ROME_2_0; + pinfo->mbox_prop[1].extended_address = + pinfo->mbox_prop[0].extended_address + + pinfo->mbox_prop[0].extended_size + + HIF_MBOX_DUMMY_SPACE_SIZE_AR6320; + pinfo->mbox_prop[1].extended_size = + HIF_MBOX1_EXTENDED_WIDTH_AR6320; + pinfo->gmbox_address = HIF_GMBOX_BASE_ADDR; + pinfo->gmbox_size = HIF_GMBOX_WIDTH; + break; + default: + A_ASSERT(false); + break; + } +} + +/** + * hif_configure_device() - configure sdio device + * @device: pointer to hif device structure + * @opcode: configuration type + * @config: configuration value to set + * @configLen: configuration length + * + * Return: 0 on success, error number otherwise. + */ +QDF_STATUS +hif_configure_device(struct hif_sdio_dev *device, + enum hif_device_config_opcode opcode, + void *config, uint32_t config_len) +{ + uint32_t count; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + switch (opcode) { + case HIF_DEVICE_GET_MBOX_BLOCK_SIZE: + ((uint32_t *) config)[0] = HIF_MBOX0_BLOCK_SIZE; + ((uint32_t *) config)[1] = HIF_MBOX1_BLOCK_SIZE; + ((uint32_t *) config)[2] = HIF_MBOX2_BLOCK_SIZE; + ((uint32_t *) config)[3] = HIF_MBOX3_BLOCK_SIZE; + break; + + case HIF_DEVICE_GET_MBOX_ADDR: + for (count = 0; count < 4; count++) { + ((uint32_t *) config)[count] = + HIF_MBOX_START_ADDR(count); + } + + if (config_len >= sizeof(struct hif_device_mbox_info)) { + set_extended_mbox_window_info((uint16_t) device->func-> + device, + (struct hif_device_mbox_info *) + config); + } + + break; + case HIF_DEVICE_GET_PENDING_EVENTS_FUNC: + AR_DEBUG_PRINTF(ATH_DEBUG_WARN, + ("%s: configuration opcode %d\n", + __func__, opcode)); + status = QDF_STATUS_E_FAILURE; + break; + case HIF_DEVICE_GET_IRQ_PROC_MODE: + *((enum hif_device_irq_mode *) config) = + HIF_DEVICE_IRQ_SYNC_ONLY; + break; + case HIF_DEVICE_GET_RECV_EVENT_MASK_UNMASK_FUNC: + AR_DEBUG_PRINTF(ATH_DEBUG_WARN, + ("%s: configuration opcode %d\n", + __func__, opcode)); + status = QDF_STATUS_E_FAILURE; + break; + case HIF_CONFIGURE_QUERY_SCATTER_REQUEST_SUPPORT: + if (!device->scatter_enabled) + return QDF_STATUS_E_NOSUPPORT; + status = + setup_hif_scatter_support(device, + (struct HIF_DEVICE_SCATTER_SUPPORT_INFO *) + config); + if (QDF_IS_STATUS_ERROR(status)) + device->scatter_enabled = false; + break; + case HIF_DEVICE_GET_OS_DEVICE: + /* pass back a pointer to the SDIO function's "dev" struct */ + ((struct HIF_DEVICE_OS_DEVICE_INFO *) config)->os_dev = + &device->func->dev; + break; + case HIF_DEVICE_POWER_STATE_CHANGE: + status = + power_state_change_notify(device, + *(HIF_DEVICE_POWER_CHANGE_TYPE *) + config); + break; + case HIF_DEVICE_GET_IRQ_YIELD_PARAMS: + AR_DEBUG_PRINTF(ATH_DEBUG_WARN, + ("%s: configuration opcode %d\n", + __func__, opcode)); + status = QDF_STATUS_E_FAILURE; + break; + case HIF_DEVICE_SET_HTC_CONTEXT: + device->htc_context = config; + break; + case HIF_DEVICE_GET_HTC_CONTEXT: + if (config == NULL) { + AR_DEBUG_PRINTF(ATH_DEBUG_WARN, + ("%s: htc context is NULL\n", + __func__)); + return QDF_STATUS_E_FAILURE; + } + *(void **)config = device->htc_context; + break; + case HIF_BMI_DONE: + { + AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, + ("%s: BMI_DONE\n", __func__)); + break; + } + default: + AR_DEBUG_PRINTF(ATH_DEBUG_WARN, + ("%s: Unsupported configuration opcode: %d\n", + __func__, opcode)); + status = QDF_STATUS_E_FAILURE; + } + + return status; +} + +/** + * hif_sdio_shutdown() - hif-sdio shutdown routine + * @hif_ctx: pointer to hif_softc structore + * + * Return: None. + */ +void hif_sdio_shutdown(struct hif_softc *hif_ctx) +{ + struct hif_sdio_softc *scn = HIF_GET_SDIO_SOFTC(hif_ctx); + struct hif_sdio_dev *hif_device = scn->hif_handle; + + AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, + ("%s: Enter\n", __func__)); + if (hif_device != NULL) { + AR_DEBUG_ASSERT(hif_device->power_config == HIF_DEVICE_POWER_CUT + || hif_device->func != NULL); + } else { + int i; + /* since we are unloading the driver anyways, + * reset all cards in case the SDIO card is + * externally powered and we are unloading the SDIO + * stack. This avoids the problem when the SDIO stack + * is reloaded and attempts are made to re-enumerate + * a card that is already enumerated */ + AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, + ("%s: hif_shut_down_device, resetting\n", + __func__)); + reset_all_cards(); + + /* Unregister with bus driver core */ + if (registered) { + registered = 0; + AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, + ("%s: Unregistering with the bus driver\n", + __func__)); + hif_sdio_remove_callbacks(); + AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, + ("%s: Unregistered!", + __func__)); + } + + for (i = 0; i < MAX_HIF_DEVICES; ++i) { + if (hif_devices[i] && hif_devices[i]->func == NULL) { + AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, + ("%s: Remove pending hif_device %p\n", + __func__, hif_devices[i])); + del_hif_device(hif_devices[i]); + hif_devices[i] = NULL; + } + } + } + AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, + ("%s: Exit\n", __func__)); +} + +/** + * hif_irq_handler() - hif-sdio interrupt handler + * @func: pointer to sdio_func + * + * Return: None. + */ +static void hif_irq_handler(struct sdio_func *func) +{ + QDF_STATUS status; + struct hif_sdio_dev *device; + AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, + ("%s: Enter\n", __func__)); + + device = get_hif_device(func); + atomic_set(&device->irq_handling, 1); + /* release the host during intr so we can use + * it when we process cmds */ + sdio_release_host(device->func); + status = device->htc_callbacks.dsrHandler(device->htc_callbacks + .context); + sdio_claim_host(device->func); + atomic_set(&device->irq_handling, 0); + AR_DEBUG_ASSERT(status == QDF_STATUS_SUCCESS || + status == QDF_STATUS_E_CANCELED); + AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, + ("%s: Exit\n", __func__)); +} + +/** + * startup_task() - startup task to fill ol_softc + * @param: pointer to struct hif_sdio_dev + * + * Return: 0 on success, error number otherwise. + */ +static int startup_task(void *param) +{ + struct hif_sdio_dev *device; + + device = (struct hif_sdio_dev *) param; + AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, + ("%s: call HTC from startup_task\n", + __func__)); + /* start up inform DRV layer */ + if ((osdrv_callbacks. + device_inserted_handler(osdrv_callbacks.context, + device)) != QDF_STATUS_SUCCESS) { + AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, + ("%s: Device rejected\n", __func__)); + } + + return 0; +} + +static int enable_task(void *param) +{ + struct hif_sdio_dev *device; + device = (struct hif_sdio_dev *) param; + AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, + ("%s: call from resume_task\n", + __func__)); + + /* start up inform DRV layer */ + if (device && + device->claimed_ctx && + osdrv_callbacks.device_power_change_handler && + osdrv_callbacks.device_power_change_handler(device->claimed_ctx, + HIF_DEVICE_POWER_UP) != + QDF_STATUS_SUCCESS) { + AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, + ("%s: Device rejected\n", + __func__)); + } + + return 0; +} + +/** + * foce_drive_strength() - Set sdio drive strength + * @func: pointer to sdio_func + * + * Return: none. + */ +static void foce_drive_strength(struct sdio_func *func) +{ + unsigned int addr = SDIO_CCCR_DRIVE_STRENGTH; + unsigned char value = 0; + + uint32_t err = func0_cmd52_read_byte(func->card, + addr, &value); + if (err) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, + ("%s: Read CCCR 0x%02X failed: %d\n", + __func__, + (unsigned int) addr, + (unsigned int) err)); + } else { + value = (value & + (~(SDIO_DRIVE_DTSx_MASK << + SDIO_DRIVE_DTSx_SHIFT))) | + SDIO_DTSx_SET_TYPE_D; + err = func0_cmd52_write_byte(func->card, addr, + value); + if (err) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, + ("%s: Write CCCR 0x%02X to 0x%02X failed: %d\n", + __func__, + (unsigned int) addr, + (unsigned int) value, + (unsigned int) err)); + } else { + addr = CCCR_SDIO_DRIVER_STRENGTH_ENABLE_ADDR; + value = 0; + err = func0_cmd52_read_byte(func->card, + addr, &value); + if (err) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, + ("Read CCCR 0x%02X failed: %d\n", + (unsigned int) addr, + (unsigned int) err)); + } else { + value = (value & + (~CCCR_SDIO_DRIVER_STRENGTH_ENABLE_MASK)) + | CCCR_SDIO_DRIVER_STRENGTH_ENABLE_A + | CCCR_SDIO_DRIVER_STRENGTH_ENABLE_C + | CCCR_SDIO_DRIVER_STRENGTH_ENABLE_D; + err = func0_cmd52_write_byte(func->card, + addr, value); + if (err) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, + ("Write CCCR 0x%02X to 0x%02X failed: %d\n", + (unsigned int) addr, + (unsigned int) value, + (unsigned int) err)); + } + } + } + } +} + +/** + * write_cccr() - write CCCR + * @func: pointer to sdio_func + * + * Return: none. + */ +static void write_cccr(struct sdio_func *func) +{ + if (writecccr1) { + uint32_t err = func0_cmd52_write_byte(func->card, + writecccr1, + writecccr1value); + if (err) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, + ("Write CCCR 0x%02X to 0x%02X failed: %d\n", + (unsigned int)writecccr1, + (unsigned int)writecccr1value, + (unsigned int)err)); + } else { + AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, + ("Write CCCR 0x%02X to 0x%02X OK\n", + (unsigned int)writecccr1, + (unsigned int)writecccr1value)); + } + } + if (writecccr2) { + uint32_t err = func0_cmd52_write_byte(func->card, + writecccr2, + writecccr2value); + if (err) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, + ("Write CCCR 0x%02X to 0x%02X failed: %d\n", + (unsigned int)writecccr2, + (unsigned int)writecccr2value, + (unsigned int)err)); + } else { + AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, + ("Write CCCR 0x%02X to 0x%02X OK\n", + (unsigned int)writecccr2, + (unsigned int)writecccr2value)); + } + } + if (writecccr3) { + uint32_t err = func0_cmd52_write_byte(func->card, + writecccr3, + writecccr3value); + if (err) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, + ("Write CCCR 0x%02X to 0x%02X failed: %d\n", + (unsigned int)writecccr3, + (unsigned int)writecccr3value, + (unsigned int)err)); + } else { + AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, + ("Write CCCR 0x%02X to 0x%02X OK\n", + (unsigned int)writecccr3, + (unsigned int)writecccr3value)); + } + } + if (writecccr4) { + uint32_t err = func0_cmd52_write_byte(func->card, + writecccr4, + writecccr4value); + if (err) + AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, + ("Write CCCR 0x%02X to 0x%02X failed: %d\n", + (unsigned int)writecccr4, + (unsigned int)writecccr4value, + (unsigned int)err)); + else + AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, + ("Write CCCR 0x%02X to 0x%02X OK\n", + (unsigned int)writecccr4, + (unsigned int)writecccr4value)); + } +} + +/** + * hif_device_inserted() - hif-sdio driver probe handler + * @func: pointer to sdio_func + * @id: pointer to sdio_device_id + * + * Return: 0 on success, error number otherwise. + */ +static int hif_device_inserted(struct sdio_func *func, + const struct sdio_device_id *id) +{ + int i; + int ret; + struct hif_sdio_dev *device = NULL; + int count; + uint32_t clock, clock_set = 12500000; + + AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, + ("%s: Function: " + "0x%X, Vendor ID: 0x%X, Device ID: 0x%X, " + "block size: 0x%X/0x%X\n", + __func__, + func->num, func->vendor, id->device, + func->max_blksize, + func->cur_blksize)); + /* dma_mask should not be NULL, otherwise dma_map_single + * will crash. TODO: check why dma_mask is NULL here */ + if (func->dev.dma_mask == NULL) { + static u64 dma_mask = 0xFFFFFFFF; + func->dev.dma_mask = &dma_mask; + } + for (i = 0; i < MAX_HIF_DEVICES; ++i) { + struct hif_sdio_dev *hifdevice = hif_devices[i]; + if (hifdevice && hifdevice->power_config == HIF_DEVICE_POWER_CUT + && hifdevice->host == func->card->host) { + hifdevice->func = func; + hifdevice->power_config = HIF_DEVICE_POWER_UP; + sdio_set_drvdata(func, hifdevice); + device = get_hif_device(func); + + if (device->is_suspend) { + AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, + ("%s: Resume from suspend", + __func__)); + ret = reinit_sdio(device); + } + break; + } + } + + if (device == NULL) { + if (add_hif_device(func) == NULL) + return QDF_STATUS_E_FAILURE; + device = get_hif_device(func); + + for (i = 0; i < MAX_HIF_DEVICES; ++i) { + if (hif_devices[i] == NULL) { + hif_devices[i] = device; + break; + } + } + if (i == MAX_HIF_DEVICES) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, + ("%s: No more hif_devices[] slot for %p", + __func__, device)); + } + + device->id = id; + device->host = func->card->host; + device->is_disabled = true; +/* TODO: MMC SDIO3.0 Setting should also be modified in ReInit() + * function when Power Manage work. */ + sdio_claim_host(func); + /* force driver strength to type D */ + if (forcedriverstrength == 1) + foce_drive_strength(func); + write_cccr(func); + /* Set MMC Clock */ + if (mmcclock > 0) + clock_set = mmcclock; + if (sdio_card_highspeed(func->card)) + clock = 50000000; + else + clock = func->card->cis.max_dtr; + if (clock > device->host->f_max) + clock = device->host->f_max; + + AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, + ("%s: Dumping clocks (%d,%d)\n", + __func__, func->card->cis.max_dtr, + device->host->f_max)); + + /* only when mmcclock module parameter is specified, + * set the clock explicitly + */ + if (mmcclock > 0) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + ("Decrease host clock from %d to %d(%d,%d)\n", + clock, clock_set, + func->card->cis.max_dtr, + device->host->f_max)); + device->host->ios.clock = clock_set; + device->host->ops->set_ios(device->host, + &device->host->ios); + } + /* Set SDIO3.0 */ + /* Set MMC Bus Width: 1-1Bit, 4-4Bit, 8-8Bit */ + if (mmcbuswidth > 0) { + if (mmcbuswidth == 1) { + ret = + func0_cmd52_write_byte(func->card, + SDIO_CCCR_IF, + SDIO_BUS_CD_DISABLE + | + SDIO_BUS_WIDTH_1BIT); + if (ret) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + ("%s: CMD52 to set bus width failed: %d\n", + __func__, + ret)); + return ret; + } + device->host->ios.bus_width = + MMC_BUS_WIDTH_1; + device->host->ops->set_ios(device->host, + &device-> + host->ios); + } else if (mmcbuswidth == 4 + && (device->host-> + caps & MMC_CAP_4_BIT_DATA)) { + ret = + func0_cmd52_write_byte(func->card, + SDIO_CCCR_IF, + SDIO_BUS_CD_DISABLE + | + SDIO_BUS_WIDTH_4BIT); + if (ret) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + ("%s: CMD52 to bus width failed: %d\n", + __func__, + ret)); + return ret; + } + device->host->ios.bus_width = + MMC_BUS_WIDTH_4; + device->host->ops->set_ios(device->host, + &device-> + host->ios); + } else if (mmcbuswidth == 8 + && (device->host-> + caps & MMC_CAP_8_BIT_DATA)) { + ret = + func0_cmd52_write_byte(func->card, + SDIO_CCCR_IF, + SDIO_BUS_CD_DISABLE + | + SDIO_BUS_WIDTH_8BIT); + if (ret) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + ("%s: CMD52 to bus width failed: %d\n", + __func__, + ret)); + return ret; + } + device->host->ios.bus_width = + MMC_BUS_WIDTH_8; + device->host->ops->set_ios(device->host, + &device-> + host->ios); + } else { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + ("%s: MMC bus width %d is not supported.\n", + __func__, + mmcbuswidth)); + return ret = QDF_STATUS_E_FAILURE; + } + AR_DEBUG_PRINTF(ATH_DEBUG_ANY, + ("%s: Set MMC bus width to %dBit.\n", + __func__, mmcbuswidth)); + } + if (debugcccr) + hif_dump_cccr(device); + + sdio_release_host(func); + } + + qdf_spinlock_create(&device->lock); + + qdf_spinlock_create(&device->asynclock); + + DL_LIST_INIT(&device->scatter_req_head); + + if (!nohifscattersupport) { + /* try to allow scatter operation on all instances, + * unless globally overridden */ + device->scatter_enabled = true; + } else + device->scatter_enabled = false; + + /* Initialize the bus requests to be used later */ + qdf_mem_zero(device->bus_request, sizeof(device->bus_request)); + for (count = 0; count < BUS_REQUEST_MAX_NUM; count++) { + sema_init(&device->bus_request[count].sem_req, 0); + hif_free_bus_request(device, &device->bus_request[count]); + } + sema_init(&device->sem_async, 0); + + ret = hif_enable_func(device, func); + + return (ret == QDF_STATUS_SUCCESS || ret == QDF_STATUS_E_PENDING) + ? 0 : QDF_STATUS_E_FAILURE; +} + +/** + * hif_ack_interrupt() - Acknowledge hif device irq + * @device: pointer to struct hif_sdio_dev + * + * This should translate to an acknowledgment to the bus driver indicating that + * the previous interrupt request has been serviced and the all the relevant + * sources have been cleared. HTC is ready to process more interrupts. + * This should prevent the bus driver from raising an interrupt unless the + * previous one has been serviced and acknowledged using the previous API. + * + * Return: None. + */ +void hif_ack_interrupt(struct hif_sdio_dev *device) +{ + AR_DEBUG_ASSERT(device != NULL); + + /* Acknowledge our function IRQ */ +} + +/** + * hif_un_mask_interrupt() - Re-enable hif device irq + * @device: pointer to struct hif_sdio_dev + * + * + * Return: None. + */ +void hif_un_mask_interrupt(struct hif_sdio_dev *device) +{ + int ret; + + AR_DEBUG_ASSERT(device != NULL); + AR_DEBUG_ASSERT(device->func != NULL); + + HIF_ENTER(); + /* + * On HP Elitebook 8460P, interrupt mode is not stable + * in high throughput, so polling method should be used + * instead of interrupt mode. */ + if (brokenirq) { + AR_DEBUG_PRINTF(ATH_DEBUG_INFO, + ("%s: Using broken IRQ mode\n", + __func__)); + /* disable IRQ support even the capability exists */ + device->func->card->host->caps &= ~MMC_CAP_SDIO_IRQ; + } + /* Register the IRQ Handler */ + sdio_claim_host(device->func); + ret = sdio_claim_irq(device->func, hif_irq_handler); + sdio_release_host(device->func); + AR_DEBUG_ASSERT(ret == 0); + HIF_EXIT(); +} + +/** + * hif_mask_interrupt() - Disable hif device irq + * @device: pointer to struct hif_sdio_dev + * + * + * Return: None. + */ +void hif_mask_interrupt(struct hif_sdio_dev *device) +{ + int ret; + AR_DEBUG_ASSERT(device != NULL); + AR_DEBUG_ASSERT(device->func != NULL); + + HIF_ENTER(); + + /* Mask our function IRQ */ + sdio_claim_host(device->func); + while (atomic_read(&device->irq_handling)) { + sdio_release_host(device->func); + schedule_timeout_interruptible(HZ / 10); + sdio_claim_host(device->func); + } + ret = sdio_release_irq(device->func); + sdio_release_host(device->func); + if (ret) { + if (ret == -ETIMEDOUT) { + AR_DEBUG_PRINTF(ATH_DEBUG_WARN, + ("%s: Timeout to mask interrupt\n", + __func__)); + } else { + AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, + ("%s: Unable to mask interrupt %d\n", + __func__, ret)); + AR_DEBUG_ASSERT(ret == 0); + } + } + HIF_EXIT(); +} + +/** + * hif_allocate_bus_request() - Allocate hif bus request + * @device: pointer to struct hif_sdio_dev + * + * + * Return: pointer to struct bus_request structure. + */ +struct bus_request *hif_allocate_bus_request(struct hif_sdio_dev *device) +{ + struct bus_request *busrequest; + + qdf_spin_lock_irqsave(&device->lock); + busrequest = device->bus_request_free_queue; + /* Remove first in list */ + if (busrequest != NULL) + device->bus_request_free_queue = busrequest->next; + + /* Release lock */ + qdf_spin_unlock_irqrestore(&device->lock); + AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, + ("%s: hif_allocate_bus_request: 0x%p\n", + __func__, busrequest)); + + return busrequest; +} + +/** + * hif_free_bus_request() - Free hif bus request + * @device: pointer to struct hif_sdio_dev + * + * + * Return: None. + */ +void hif_free_bus_request(struct hif_sdio_dev *device, + struct bus_request *busrequest) +{ + AR_DEBUG_ASSERT(busrequest != NULL); + /* Acquire lock */ + qdf_spin_lock_irqsave(&device->lock); + + /* Insert first in list */ + busrequest->next = device->bus_request_free_queue; + busrequest->inusenext = NULL; + device->bus_request_free_queue = busrequest; + + /* Release lock */ + qdf_spin_unlock_irqrestore(&device->lock); +} + +static QDF_STATUS hif_disable_func(struct hif_sdio_dev *device, + struct sdio_func *func) +{ + int ret; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + HIF_ENTER(); + device = get_hif_device(func); + if (!IS_ERR(device->async_task)) { + init_completion(&device->async_completion); + device->async_shutdown = 1; + up(&device->sem_async); + wait_for_completion(&device->async_completion); + device->async_task = NULL; + sema_init(&device->sem_async, 0); + } + /* Disable the card */ + sdio_claim_host(device->func); + ret = sdio_disable_func(device->func); + if (ret) + status = QDF_STATUS_E_FAILURE; + + if (reset_sdio_on_unload && status == QDF_STATUS_SUCCESS) { + /* reset the SDIO interface. It's useful in automated testing + * where the card does not need to be removed at the end + * of the test. It is expected that the user will also + * un/reload the host controller driver to force the bus + * driver to re-enumerate the slot */ + AR_DEBUG_PRINTF(ATH_DEBUG_WARN, + ("%s: reseting SDIO card", + __func__)); + + /* sdio_f0_writeb() cannot be used here, this allows access + * to undefined registers in the range of: 0xF0-0xFF */ + + ret = + func0_cmd52_write_byte(device->func->card, + SDIO_CCCR_ABORT, + (1 << 3)); + if (ret) { + status = QDF_STATUS_E_FAILURE; + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + ("%s: reset failed : %d\n", + __func__, ret)); + } + } + + sdio_release_host(device->func); + + if (status == QDF_STATUS_SUCCESS) + device->is_disabled = true; + cleanup_hif_scatter_resources(device); + + HIF_EXIT(); + + return status; +} + +static QDF_STATUS hif_enable_func(struct hif_sdio_dev *device, + struct sdio_func *func) +{ + struct task_struct *task; + const char *task_name = NULL; + int (*taskFunc)(void *) = NULL; + int ret = QDF_STATUS_SUCCESS; + + HIF_ENTER("sdio_func 0x%p", func); + + device = get_hif_device(func); + + if (!device) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("HIF device is NULL\n")); + return QDF_STATUS_E_INVAL; + } + + if (device->is_disabled) { + int setAsyncIRQ = 0; + __u16 manufacturer_id = + device->id->device & MANUFACTURER_ID_AR6K_BASE_MASK; + /* enable the SDIO function */ + sdio_claim_host(func); + /* enable 4-bit ASYNC interrupt on AR6003x or later devices */ + if (manufacturer_id == MANUFACTURER_ID_AR6003_BASE) { + setAsyncIRQ = 1; + ret = + func0_cmd52_write_byte(func->card, + CCCR_SDIO_IRQ_MODE_REG_AR6003, + SDIO_IRQ_MODE_ASYNC_4BIT_IRQ_AR6003); + } else if (manufacturer_id == MANUFACTURER_ID_AR6320_BASE + || manufacturer_id == MANUFACTURER_ID_QCA9377_BASE) { + unsigned char data = 0; + setAsyncIRQ = 1; + ret = + func0_cmd52_read_byte(func->card, + CCCR_SDIO_IRQ_MODE_REG_AR6320, + &data); + if (ret) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + ("%s: failed to read irq reg %d\n", + __func__, ret)); + sdio_release_host(func); + return QDF_STATUS_E_FAILURE; + } + data |= SDIO_IRQ_MODE_ASYNC_4BIT_IRQ_AR6320; + ret = + func0_cmd52_write_byte(func->card, + CCCR_SDIO_IRQ_MODE_REG_AR6320, + data); + } + if (setAsyncIRQ) { + if (ret) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + ("%s: failed to enable ASYNC IRQ mode %d\n", + __func__, ret)); + sdio_release_host(func); + return QDF_STATUS_E_FAILURE; + } + AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, + ("%s: 4-bit ASYNC IRQ mode enabled\n", + __func__)); + } + + /* set CCCR 0xF0[7:6] to increase async interrupt delay clock to + * fix interrupt missing issue on dell 8460p */ + if (asyncintdelay != 0) { + unsigned char data = 0; + ret = + func0_cmd52_read_byte(func->card, + CCCR_SDIO_ASYNC_INT_DELAY_ADDRESS, + &data); + if (ret) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + ("%s: failed to read CCCR %d, val is %d\n", + __func__, + CCCR_SDIO_ASYNC_INT_DELAY_ADDRESS, + ret)); + sdio_release_host(func); + return QDF_STATUS_E_FAILURE; + } + data = (data & ~CCCR_SDIO_ASYNC_INT_DELAY_MASK) | + ((asyncintdelay << + CCCR_SDIO_ASYNC_INT_DELAY_LSB) & + CCCR_SDIO_ASYNC_INT_DELAY_MASK); + ret = + func0_cmd52_write_byte(func->card, + CCCR_SDIO_ASYNC_INT_DELAY_ADDRESS, + data); + if (ret) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + ("%s: failed to write CCCR %d, val is %d\n", + __func__, + CCCR_SDIO_ASYNC_INT_DELAY_ADDRESS, + ret)); + sdio_release_host(func); + return QDF_STATUS_E_FAILURE; + } + AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, + ("%s: Set async interrupt delay clock as %d.\n", + __func__, + asyncintdelay)); + } + /* give us some time to enable, in ms */ + func->enable_timeout = 100; + ret = sdio_enable_func(func); + if (ret) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, + ("%s: Unable to enable AR6K: 0x%X\n", + __func__, ret)); + sdio_release_host(func); + return QDF_STATUS_E_FAILURE; + } + ret = sdio_set_block_size(func, HIF_MBOX_BLOCK_SIZE); + + if (modstrength) { + unsigned int address = WINDOW_DATA_ADDRESS; + unsigned int value = 0x0FFF; + ret = + sdio_memcpy_toio(device->func, address, + &value, 4); + if (ret) { + AR_DEBUG_PRINTF(ATH_DEBUG_INFO, + ("memcpy_toio 0x%x 0x%x error:%d\n", + address, value, ret)); + } else { + AR_DEBUG_PRINTF(ATH_DEBUG_INFO, + ("memcpy_toio, 0x%x 0x%x OK\n", address, + value)); + address = WINDOW_WRITE_ADDR_ADDRESS; + value = 0x50F8; + ret = + sdio_memcpy_toio(device->func, address, + &value, 4); + if (ret) + AR_DEBUG_PRINTF(ATH_DEBUG_INFO, + ("memcpy_toio 0x%x 0x%x error:%d\n", + address, value, ret)); + else + AR_DEBUG_PRINTF(ATH_DEBUG_INFO, + ("memcpy_toio, 0x%x 0x%x OK\n", + address, value)); + } + }; + sdio_release_host(func); + if (ret) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, + ("%s: can't set block size 0x%x AR6K: 0x%X\n", + __func__, HIF_MBOX_BLOCK_SIZE, + ret)); + return QDF_STATUS_E_FAILURE; + } + device->is_disabled = false; + /* create async I/O thread */ + if (!device->async_task) { + device->async_shutdown = 0; + device->async_task = kthread_create(async_task, + (void *)device, + "AR6K Async"); + if (IS_ERR(device->async_task)) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, + ("%s: to create async task\n", + __func__)); + return QDF_STATUS_E_FAILURE; + } + AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, + ("%s: start async task\n", + __func__)); + wake_up_process(device->async_task); + } + } + + if (!device->claimed_ctx) { + taskFunc = startup_task; + task_name = "AR6K startup"; + ret = QDF_STATUS_SUCCESS; + } else { + taskFunc = enable_task; + task_name = "AR6K enable"; + ret = QDF_STATUS_E_PENDING; + } + /* create resume thread */ + task = kthread_create(taskFunc, (void *)device, task_name); + if (IS_ERR(task)) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, + ("%s: to create enabel task\n", + __func__)); + return QDF_STATUS_E_FAILURE; + } + wake_up_process(task); + + /* task will call the enable func, indicate pending */ + HIF_EXIT(); + + return ret; +} + +int hif_device_suspend(struct device *dev) +{ + struct sdio_func *func = dev_to_sdio_func(dev); + QDF_STATUS status = QDF_STATUS_SUCCESS; + int ret = QDF_STATUS_SUCCESS; +#if defined(MMC_PM_KEEP_POWER) + mmc_pm_flag_t pm_flag = 0; + HIF_DEVICE_POWER_CHANGE_TYPE config; + struct mmc_host *host = NULL; +#endif + + struct hif_sdio_dev *device = get_hif_device(func); + +#if defined(MMC_PM_KEEP_POWER) + if (device && device->func) + host = device->func->card->host; +#endif + + HIF_ENTER(); + if (device && device->claimed_ctx + && osdrv_callbacks.device_suspend_handler) { + device->is_suspend = true; + status = + osdrv_callbacks.device_suspend_handler(device->claimed_ctx); + +#if defined(MMC_PM_KEEP_POWER) + switch (forcesleepmode) { + case 0: /* depend on sdio host pm capbility */ + pm_flag = sdio_get_host_pm_caps(func); + break; + case 1: /* force WOW */ + pm_flag |= MMC_PM_KEEP_POWER | MMC_PM_WAKE_SDIO_IRQ; + break; + case 2: /* force DeepSleep */ + pm_flag &= ~MMC_PM_WAKE_SDIO_IRQ; + pm_flag |= MMC_PM_KEEP_POWER; + break; + case 3: /* force CutPower */ + pm_flag &= + ~(MMC_PM_WAKE_SDIO_IRQ | MMC_PM_WAKE_SDIO_IRQ); + break; + } + if (!(pm_flag & MMC_PM_KEEP_POWER)) { + /* cut power support */ + /* setting power_config before hif_configure_device to + * skip sdio r/w when suspending with cut power */ + AR_DEBUG_PRINTF(ATH_DEBUG_INFO, + ("hif_device_suspend: cut power enter\n")); + config = HIF_DEVICE_POWER_CUT; + device->power_config = config; + if ((device->claimed_ctx != NULL) + && osdrv_callbacks.device_removed_handler) { + status = osdrv_callbacks. + device_removed_handler(device-> + claimed_ctx, + device); + } + ret = hif_configure_device(device, + HIF_DEVICE_POWER_STATE_CHANGE, + &config, + sizeof + (HIF_DEVICE_POWER_CHANGE_TYPE)); + if (ret) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, + ("%s: hif config device failed: %d\n", + __func__, ret)); + return ret; + } + + hif_mask_interrupt(device); + device->device_state = HIF_DEVICE_STATE_CUTPOWER; + AR_DEBUG_PRINTF(ATH_DEBUG_INFO, + ("hif_device_suspend: cut power success\n")); + return ret; + } else { + ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER); + if (ret) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, + ("%s: set sdio pm flags failed %d\n", + __func__, ret)); + return ret; + } + + /* TODO:WOW support */ + if (pm_flag & MMC_PM_WAKE_SDIO_IRQ) { + AR_DEBUG_PRINTF(ATH_DEBUG_INFO, + ("hif_device_suspend: wow enter\n")); + config = HIF_DEVICE_POWER_DOWN; + ret = hif_configure_device(device, + HIF_DEVICE_POWER_STATE_CHANGE, + &config, + sizeof + (HIF_DEVICE_POWER_CHANGE_TYPE)); + + if (ret) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, + ("%s: hif config dev failed: %d\n", + __func__, ret)); + return ret; + } + ret = + sdio_set_host_pm_flags(func, + MMC_PM_WAKE_SDIO_IRQ); + if (ret) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, + ("%s: set sdio pm flags %d\n", + __func__, ret)); + return ret; + } + hif_mask_interrupt(device); + device->device_state = HIF_DEVICE_STATE_WOW; + AR_DEBUG_PRINTF(ATH_DEBUG_INFO, + ("hif_device_suspend: wow success\n")); + return ret; + } else { + /* deep sleep support */ + AR_DEBUG_PRINTF(ATH_DEBUG_INFO, + ("%s: deep sleep enter\n", + __func__)); + + /* + * Wait for some async clean handler finished. + * These handlers are part of vdev disconnect. + * As handlers are async,sleep is not suggested, + * some blocking method may be a good choice. + * But before adding callback function to these + * handler, sleep wait is a simple method. + */ + msleep(100); + hif_mask_interrupt(device); + device->device_state = + HIF_DEVICE_STATE_DEEPSLEEP; + AR_DEBUG_PRINTF(ATH_DEBUG_INFO, + ("%s: deep sleep done\n", + __func__)); + return ret; + } + } +#endif + } + + HIF_EXIT(); + + switch (status) { + case QDF_STATUS_SUCCESS: +#if defined(MMC_PM_KEEP_POWER) + if (host) { + host->pm_flags &= + ~(MMC_PM_KEEP_POWER | MMC_PM_WAKE_SDIO_IRQ); + } +#endif + return 0; + case QDF_STATUS_E_BUSY: +#if defined(MMC_PM_KEEP_POWER) + if (host) { + /* WAKE_SDIO_IRQ in order to wake up by DAT1 */ + host->pm_flags |= + (MMC_PM_KEEP_POWER | MMC_PM_WAKE_SDIO_IRQ); + host->pm_flags &= host->pm_caps; + } + return 0; +#else + return -EBUSY; /* Hack to support deep sleep and wow */ +#endif + default: + device->is_suspend = false; + + return QDF_STATUS_E_FAILURE; + } +} + +int hif_device_resume(struct device *dev) +{ + struct sdio_func *func = dev_to_sdio_func(dev); + QDF_STATUS status = QDF_STATUS_SUCCESS; + HIF_DEVICE_POWER_CHANGE_TYPE config; + struct hif_sdio_dev *device; + + device = get_hif_device(func); + + if (device->device_state == HIF_DEVICE_STATE_CUTPOWER) { + config = HIF_DEVICE_POWER_UP; + status = hif_configure_device(device, + HIF_DEVICE_POWER_STATE_CHANGE, + &config, + sizeof + (HIF_DEVICE_POWER_CHANGE_TYPE)); + if (status) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, + ("%s: hif_configure_device failed\n", + __func__)); + return status; + } + } else if (device->device_state == HIF_DEVICE_STATE_DEEPSLEEP) { + hif_un_mask_interrupt(device); + } else if (device->device_state == HIF_DEVICE_STATE_WOW) { + /*TODO:WOW support */ + hif_un_mask_interrupt(device); + } + + /* + * device_resume_handler do nothing now. If some operation + * should be added to this handler in power cut + * resume flow, do make sure those operation is not + * depent on what startup_task has done,or the resume + * flow will block. + */ + AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, + ("%s: +hif_device_resume\n", + __func__)); + if (device && device->claimed_ctx + && osdrv_callbacks.device_suspend_handler) { + status = + osdrv_callbacks.device_resume_handler(device->claimed_ctx); + device->is_suspend = false; + } + AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, + ("%s: -hif_device_resume\n", + __func__)); + device->device_state = HIF_DEVICE_STATE_ON; + + return QDF_IS_STATUS_SUCCESS(status) ? 0 : status; +} + +static void hif_device_removed(struct sdio_func *func) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct hif_sdio_dev *device; + AR_DEBUG_ASSERT(func != NULL); + + HIF_ENTER(); + + device = get_hif_device(func); + + if (device->power_config == HIF_DEVICE_POWER_CUT) { + device->func = NULL; /* func will be free by mmc stack */ + return; /* Just return for cut-off mode */ + } else { + int i; + for (i = 0; i < MAX_HIF_DEVICES; ++i) { + if (hif_devices[i] == device) + hif_devices[i] = NULL; + } + } + + if (device->claimed_ctx != NULL) + status = + osdrv_callbacks.device_removed_handler(device->claimed_ctx, + device); + + hif_mask_interrupt(device); + + if (device->is_disabled) + device->is_disabled = false; + else + status = hif_disable_func(device, func); + + + del_hif_device(device); + if (status != QDF_STATUS_SUCCESS) + AR_DEBUG_PRINTF(ATH_DEBUG_WARN, + ("%s: Unable to disable sdio func\n", + __func__)); + + HIF_EXIT(); +} + +/* + * This should be moved to AR6K HTC layer. + */ +QDF_STATUS hif_wait_for_pending_recv(struct hif_sdio_dev *device) +{ + int32_t cnt = 10; + uint8_t host_int_status; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + do { + while (atomic_read(&device->irq_handling)) { + /* wait until irq handler finished all the jobs */ + schedule_timeout_interruptible(HZ / 10); + } + /* check if there is any pending irq due to force done */ + host_int_status = 0; + status = hif_read_write(device, HOST_INT_STATUS_ADDRESS, + (uint8_t *) &host_int_status, + sizeof(host_int_status), + HIF_RD_SYNC_BYTE_INC, NULL); + host_int_status = + QDF_IS_STATUS_SUCCESS(status) ? + (host_int_status & (1 << 0)) : 0; + if (host_int_status) + /* wait until irq handler finishs its job */ + schedule_timeout_interruptible(1); + } while (host_int_status && --cnt > 0); + + if (host_int_status && cnt == 0) + AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, + ("%s: Unable clear up pending IRQ\n", + __func__)); + + return QDF_STATUS_SUCCESS; +} + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 15, 0)) && \ + !defined(WITH_BACKPORTS) +/** + * hif_sdio_set_drvdata() - set driver data + * @func: pointer to sdio function + * @hifdevice: pointer to hif device + * + * Return: non zero for success. + */ +static inline int hif_sdio_set_drvdata(struct sdio_func *func, + struct hif_sdio_dev *hifdevice) +{ + return sdio_set_drvdata(func, hifdevice); +} +#else +static inline int hif_sdio_set_drvdata(struct sdio_func *func, + struct hif_sdio_dev *hifdevice) +{ + sdio_set_drvdata(func, hifdevice); + return 0; +} +#endif + +static struct hif_sdio_dev *add_hif_device(struct sdio_func *func) +{ + struct hif_sdio_dev *hifdevice = NULL; + int ret = 0; + + HIF_ENTER(); + AR_DEBUG_ASSERT(func != NULL); + hifdevice = (struct hif_sdio_dev *) qdf_mem_malloc(sizeof( + struct hif_sdio_dev)); + AR_DEBUG_ASSERT(hifdevice != NULL); +#if HIF_USE_DMA_BOUNCE_BUFFER + hifdevice->dma_buffer = qdf_mem_malloc(HIF_DMA_BUFFER_SIZE); + AR_DEBUG_ASSERT(hifdevice->dma_buffer != NULL); +#endif + hifdevice->func = func; + hifdevice->power_config = HIF_DEVICE_POWER_UP; + hifdevice->device_state = HIF_DEVICE_STATE_ON; + ret = hif_sdio_set_drvdata(func, hifdevice); + HIF_EXIT("status %d", ret); + + return hifdevice; +} + +static struct hif_sdio_dev *get_hif_device(struct sdio_func *func) +{ + AR_DEBUG_ASSERT(func != NULL); + + return (struct hif_sdio_dev *) sdio_get_drvdata(func); +} + +static void del_hif_device(struct hif_sdio_dev *device) +{ + AR_DEBUG_ASSERT(device != NULL); + AR_DEBUG_PRINTF(ATH_DEBUG_TRACE, + ("%s: deleting hif device 0x%p\n", + __func__, device)); + if (device->dma_buffer != NULL) + qdf_mem_free(device->dma_buffer); + + qdf_mem_free(device); +} + +static void reset_all_cards(void) +{ +} + +void hif_release_device(struct hif_opaque_softc *hif_ctx) +{ + struct hif_sdio_softc *scn = HIF_GET_SDIO_SOFTC(hif_ctx); + struct hif_sdio_dev *hif_device = scn->hif_handle; + + hif_device->claimed_ctx = NULL; +} + +QDF_STATUS hif_attach_htc(struct hif_sdio_dev *device, + HTC_CALLBACKS *callbacks) +{ + if (device->htc_callbacks.context != NULL) + /* already in use! */ + return QDF_STATUS_E_FAILURE; + device->htc_callbacks = *callbacks; + + return QDF_STATUS_SUCCESS; +} + +void hif_detach_htc(struct hif_opaque_softc *hif_ctx) +{ + struct hif_sdio_softc *scn = HIF_GET_SDIO_SOFTC(hif_ctx); + struct hif_sdio_dev *hif_device = scn->hif_handle; + + qdf_mem_zero(&hif_device->htc_callbacks, + sizeof(hif_device->htc_callbacks)); +} + +#define SDIO_SET_CMD52_ARG(arg, rw, func, raw, address, writedata) \ + ((arg) = (((rw) & 1) << 31) | \ + ((func & 0x7) << 28) | \ + (((raw) & 1) << 27) | \ + (1 << 26) | \ + (((address) & 0x1FFFF) << 9) | \ + (1 << 8) | \ + ((writedata) & 0xFF)) + +#define SDIO_SET_CMD52_READ_ARG(arg, func, address) \ + SDIO_SET_CMD52_ARG(arg, 0, (func), 0, address, 0x00) +#define SDIO_SET_CMD52_WRITE_ARG(arg, func, address, value) \ + SDIO_SET_CMD52_ARG(arg, 1, (func), 0, address, value) + +static int func0_cmd52_write_byte(struct mmc_card *card, + unsigned int address, + unsigned char byte) +{ + struct mmc_command io_cmd; + unsigned long arg; + int status = 0; + + memset(&io_cmd, 0, sizeof(io_cmd)); + SDIO_SET_CMD52_WRITE_ARG(arg, 0, address, byte); + io_cmd.opcode = SD_IO_RW_DIRECT; + io_cmd.arg = arg; + io_cmd.flags = MMC_RSP_R5 | MMC_CMD_AC; + status = mmc_wait_for_cmd(card->host, &io_cmd, 0); + + if (status) + AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, + ("%s: mmc_wait_for_cmd returned %d\n", + __func__, status)); + + return status; +} + +static int func0_cmd52_read_byte(struct mmc_card *card, + unsigned int address, + unsigned char *byte) +{ + struct mmc_command io_cmd; + unsigned long arg; + int32_t err; + + memset(&io_cmd, 0, sizeof(io_cmd)); + SDIO_SET_CMD52_READ_ARG(arg, 0, address); + io_cmd.opcode = SD_IO_RW_DIRECT; + io_cmd.arg = arg; + io_cmd.flags = MMC_RSP_R5 | MMC_CMD_AC; + + err = mmc_wait_for_cmd(card->host, &io_cmd, 0); + + if ((!err) && (byte)) + *byte = io_cmd.resp[0] & 0xFF; + + if (err) + AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, + ("%s: mmc_wait_for_cmd returned %d\n", + __func__, err)); + + return err; +} + +void hif_dump_cccr(struct hif_sdio_dev *hif_device) +{ + int i; + uint8_t cccr_val; + uint32_t err; + + if (!hif_device || !hif_device->func || + !hif_device->func->card) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, + ("hif_dump_cccr incorrect input arguments\n")); + return; + } + + AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, ("hif_dump_cccr ")); + for (i = 0; i <= 0x16; i++) { + err = func0_cmd52_read_byte(hif_device->func->card, + i, &cccr_val); + if (err) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, + ("Reading CCCR 0x%02X failed: %d\n", + (unsigned int)i, (unsigned int)err)); + } else { + AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, + ("%X(%X) ", (unsigned int)i, + (unsigned int)cccr_val)); + } + } + + AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, ("\n")); +} + +#ifdef CONFIG_CNSS_SDIO +int hif_sdio_device_inserted(struct device *dev, + const struct sdio_device_id *id) +{ + struct sdio_func *func = dev_to_sdio_func(dev); + + return hif_device_inserted(func, id); +} + +void hif_sdio_device_removed(struct sdio_func *func) +{ + hif_device_removed(func); +} +#endif diff --git a/drivers/staging/qca-wifi-host-cmn/hif/src/sdio/native_sdio/src/hif_scatter.c b/drivers/staging/qca-wifi-host-cmn/hif/src/sdio/native_sdio/src/hif_scatter.c new file mode 100644 index 0000000000000000000000000000000000000000..71d042ff0d2177ca8c60f1a7a0a2d9b970e571da --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/hif/src/sdio/native_sdio/src/hif_scatter.c @@ -0,0 +1,474 @@ +/* + * Copyright (c) 2013-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include "hif_internal.h" +#include +#include "dl_list.h" +#define ATH_MODULE_NAME hif +#include "a_debug.h" + +#ifdef HIF_LINUX_MMC_SCATTER_SUPPORT + +#define _CMD53_ARG_READ 0 +#define _CMD53_ARG_WRITE 1 +#define _CMD53_ARG_BLOCK_BASIS 1 +#define _CMD53_ARG_FIXED_ADDRESS 0 +#define _CMD53_ARG_INCR_ADDRESS 1 + +#define SDIO_SET_CMD53_ARG(arg, rw, func, mode, opcode, address, bytes_blocks) \ + ((arg) = (((rw) & 1) << 31) | \ + ((func & 0x7) << 28) | \ + (((mode) & 1) << 27) | \ + (((opcode) & 1) << 26) | \ + (((address) & 0x1FFFF) << 9) | \ + ((bytes_blocks) & 0x1FF)) + +/** + * free_scatter_req() - free scattered request. + * @device: hif device context + * @pReq: scatter list node + * + * Return: none + */ +static void free_scatter_req(struct hif_sdio_dev *device, + struct _HIF_SCATTER_REQ *pReq) +{ + qdf_spin_lock_irqsave(&device->lock); + + dl_list_insert_tail(&device->scatter_req_head, &pReq->list_link); + + qdf_spin_unlock_irqrestore(&device->lock); +} + +/** + * alloc_scatter_req() - allocate scattered request. + * @device: hif device context + * + * + * Return: pointer to allocated scatter list node + */ +static struct _HIF_SCATTER_REQ *alloc_scatter_req(struct hif_sdio_dev *device) +{ + DL_LIST *item; + + qdf_spin_lock_irqsave(&device->lock); + + item = dl_list_remove_item_from_head(&device->scatter_req_head); + + qdf_spin_unlock_irqrestore(&device->lock); + + if (item != NULL) + return A_CONTAINING_STRUCT(item, + struct _HIF_SCATTER_REQ, list_link); + + return NULL; +} + +/** + * do_hif_read_write_scatter() - rd/wr scattered operation. + * @device: hif device context + * @busrequest: rd/wr bus request + * + * called by async task to perform the operation synchronously + * using direct MMC APIs + * Return: int + */ +QDF_STATUS do_hif_read_write_scatter(struct hif_sdio_dev *device, + struct bus_request *busrequest) +{ + int i; + uint8_t rw; + uint8_t opcode; + struct mmc_request mmcreq; + struct mmc_command cmd; + struct mmc_data data; + struct HIF_SCATTER_REQ_PRIV *req_priv; + struct _HIF_SCATTER_REQ *req; + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct scatterlist *sg; + + HIF_ENTER(); + + req_priv = busrequest->scatter_req; + + A_ASSERT(req_priv != NULL); + + req = req_priv->hif_scatter_req; + + memset(&mmcreq, 0, sizeof(struct mmc_request)); + memset(&cmd, 0, sizeof(struct mmc_command)); + memset(&data, 0, sizeof(struct mmc_data)); + + data.blksz = HIF_MBOX_BLOCK_SIZE; + data.blocks = req->total_length / HIF_MBOX_BLOCK_SIZE; + + AR_DEBUG_PRINTF(ATH_DEBUG_SCATTER, + ("HIF-SCATTER: (%s) Address: 0x%X, (BlockLen: %d, BlockCount: %d), (tot:%d,sg:%d)\n", + (req->request & HIF_SDIO_WRITE) ? "WRITE" : "READ", + req->address, data.blksz, data.blocks, + req->total_length, req->valid_scatter_entries)); + + if (req->request & HIF_SDIO_WRITE) { + rw = _CMD53_ARG_WRITE; + data.flags = MMC_DATA_WRITE; + } else { + rw = _CMD53_ARG_READ; + data.flags = MMC_DATA_READ; + } + + if (req->request & HIF_FIXED_ADDRESS) + opcode = _CMD53_ARG_FIXED_ADDRESS; + else + opcode = _CMD53_ARG_INCR_ADDRESS; + + /* fill SG entries */ + sg = req_priv->sgentries; + sg_init_table(sg, req->valid_scatter_entries); + + /* assemble SG list */ + for (i = 0; i < req->valid_scatter_entries; i++, sg++) { + /* setup each sg entry */ + if ((unsigned long)req->scatter_list[i].buffer & 0x3) { + /* note some scatter engines can handle unaligned + * buffers, print this as informational only */ + AR_DEBUG_PRINTF(ATH_DEBUG_SCATTER, + ("HIF: (%s) Scatter Buf is unaligned 0x%lx\n", + req-> + request & HIF_SDIO_WRITE ? "WRITE" : "READ", + (unsigned long)req->scatter_list[i]. + buffer)); + } + + AR_DEBUG_PRINTF(ATH_DEBUG_SCATTER, + (" %d: Addr:0x%lX, Len:%d\n", i, + (unsigned long)req->scatter_list[i].buffer, + req->scatter_list[i].length)); + + sg_set_buf(sg, req->scatter_list[i].buffer, + req->scatter_list[i].length); + } + /* set scatter-gather table for request */ + data.sg = req_priv->sgentries; + data.sg_len = req->valid_scatter_entries; + /* set command argument */ + SDIO_SET_CMD53_ARG(cmd.arg, + rw, + device->func->num, + _CMD53_ARG_BLOCK_BASIS, + opcode, req->address, data.blocks); + + cmd.opcode = SD_IO_RW_EXTENDED; + cmd.flags = MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_ADTC; + + mmcreq.cmd = &cmd; + mmcreq.data = &data; + + mmc_set_data_timeout(&data, device->func->card); + /* synchronous call to process request */ + mmc_wait_for_req(device->func->card->host, &mmcreq); + + if (cmd.error) { + status = QDF_STATUS_E_FAILURE; + AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, + ("HIF-SCATTER: cmd error: %d\n", cmd.error)); + } + + if (data.error) { + status = QDF_STATUS_E_FAILURE; + AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, + ("HIF-SCATTER: data error: %d\n", data.error)); + } + + if (QDF_IS_STATUS_ERROR(status)) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, + ("HIF-SCATTER: FAILED!!! (%s) Address: 0x%X, Block mode (BlockLen: %d, BlockCount: %d)\n", + (req->request & HIF_SDIO_WRITE) ? "WRITE" : "READ", + req->address, data.blksz, data.blocks)); + } + + /* set completion status, fail or success */ + req->completion_status = status; + + if (req->request & HIF_ASYNCHRONOUS) { + AR_DEBUG_PRINTF(ATH_DEBUG_SCATTER, + ("HIF-SCATTER: async_task completion routine req: 0x%lX (%d)\n", + (unsigned long)busrequest, status)); + /* complete the request */ + A_ASSERT(req->completion_routine != NULL); + req->completion_routine(req); + } else { + AR_DEBUG_PRINTF(ATH_DEBUG_SCATTER, + ("HIF-SCATTER async_task upping busreq : 0x%lX (%d)\n", + (unsigned long)busrequest, status)); + /* signal wait */ + up(&busrequest->sem_req); + } + HIF_EXIT(); + + return status; +} + +/** + * alloc_scatter_req() - callback to issue a read-write + * scatter request. + * @device: hif device context + * @pReq: rd/wr scatter request + * + * Return: int + */ +static QDF_STATUS hif_read_write_scatter(struct hif_sdio_dev *device, + struct _HIF_SCATTER_REQ *req) +{ + QDF_STATUS status = QDF_STATUS_E_INVAL; + uint32_t request = req->request; + struct HIF_SCATTER_REQ_PRIV *req_priv = + (struct HIF_SCATTER_REQ_PRIV *) req->hif_private[0]; + + do { + + A_ASSERT(req_priv != NULL); + + AR_DEBUG_PRINTF(ATH_DEBUG_SCATTER, + ("HIF-SCATTER: total len: %d Scatter Entries: %d\n", + req->total_length, + req->valid_scatter_entries)); + + if (!(request & HIF_EXTENDED_IO)) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, + ("HIF-SCATTER: Invalid command type: 0x%08x\n", + request)); + break; + } + + if (!(request & (HIF_SYNCHRONOUS | HIF_ASYNCHRONOUS))) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, + ("HIF-SCATTER: Invalid mode: 0x%08x\n", + request)); + break; + } + + if (!(request & HIF_BLOCK_BASIS)) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, + ("HIF-SCATTER: Invalid data mode: 0x%08x\n", + request)); + break; + } + + if (req->total_length > MAX_SCATTER_REQ_TRANSFER_SIZE) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, + ("HIF-SCATTER: Invalid length: %d\n", + req->total_length)); + break; + } + + if (req->total_length == 0) { + A_ASSERT(false); + break; + } + + /* add bus request to the async list for the async + * I/O thread to process */ + add_to_async_list(device, req_priv->busrequest); + + if (request & HIF_SYNCHRONOUS) { + AR_DEBUG_PRINTF(ATH_DEBUG_SCATTER, + ("HIF-SCATTER: queued sync req: 0x%lX\n", + (unsigned long)req_priv->busrequest)); + /* signal thread and wait */ + up(&device->sem_async); + if (down_interruptible(&req_priv->busrequest->sem_req) + != 0) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, + ("HIF-SCATTER: interrupted!\n")); + /* interrupted, exit */ + status = QDF_STATUS_E_FAILURE; + break; + } else { + status = req->completion_status; + } + } else { + AR_DEBUG_PRINTF(ATH_DEBUG_SCATTER, + ("HIF-SCATTER: queued async req: 0x%lX\n", + (unsigned long)req_priv->busrequest)); + /* wake thread, it will process and then take + * care of the async callback */ + up(&device->sem_async); + status = QDF_STATUS_SUCCESS; + } + + } while (false); + + if (QDF_IS_STATUS_ERROR(status) && (request & HIF_ASYNCHRONOUS)) { + req->completion_status = status; + req->completion_routine(req); + status = QDF_STATUS_SUCCESS; + } + + return status; +} + +/** + * setup_hif_scatter_support() - setup of HIF scatter resources + * scatter request. + * @device: hif device context + * @pInfo: scatter info + * + * Return: int + */ +QDF_STATUS setup_hif_scatter_support(struct hif_sdio_dev *device, + struct HIF_DEVICE_SCATTER_SUPPORT_INFO *info) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + int i; + struct HIF_SCATTER_REQ_PRIV *req_priv; + struct bus_request *busrequest; + + if (device->func->card->host->max_segs < + MAX_SCATTER_ENTRIES_PER_REQ) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + ("host only supports scatter of : %d entries," + "need: %d\n", + device->func->card->host->max_segs, + MAX_SCATTER_ENTRIES_PER_REQ)); + status = QDF_STATUS_E_NOSUPPORT; + goto end; + } + + AR_DEBUG_PRINTF(ATH_DEBUG_ANY, + ("max scatter req : %d entries: %d\n", + MAX_SCATTER_REQUESTS, + MAX_SCATTER_ENTRIES_PER_REQ)); + + for (i = 0; i < MAX_SCATTER_REQUESTS; i++) { + /* allocate the private request blob */ + req_priv = + (struct HIF_SCATTER_REQ_PRIV *) + qdf_mem_malloc(sizeof( + struct HIF_SCATTER_REQ_PRIV)); + if (NULL == req_priv) + goto end; + /* save the device instance */ + req_priv->device = device; + /* allocate the scatter request */ + req_priv->hif_scatter_req = + (struct _HIF_SCATTER_REQ *) + qdf_mem_malloc(sizeof(struct _HIF_SCATTER_REQ) + + (MAX_SCATTER_ENTRIES_PER_REQ - + 1) * (sizeof(struct _HIF_SCATTER_ITEM))); + + if (NULL == req_priv->hif_scatter_req) { + qdf_mem_free(req_priv); + goto end; + } + /* back pointer to the private struct */ + req_priv->hif_scatter_req->hif_private[0] = req_priv; + /* allocate a bus request for this scatter request */ + busrequest = hif_allocate_bus_request(device); + if (NULL == busrequest) { + qdf_mem_free(req_priv->hif_scatter_req); + qdf_mem_free(req_priv); + goto end; + } + /* assign the scatter request to this bus request */ + busrequest->scatter_req = req_priv; + /* point back to the request */ + req_priv->busrequest = busrequest; + /* req_priv it to the scatter pool */ + free_scatter_req(device, req_priv->hif_scatter_req); + } + + if (i != MAX_SCATTER_REQUESTS) { + status = QDF_STATUS_E_NOMEM; + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + ("failed to alloc scatter resources !\n")); + goto end; + } + + /* set scatter function pointers */ + info->allocate_req_func = alloc_scatter_req; + info->free_req_func = free_scatter_req; + info->read_write_scatter_func = hif_read_write_scatter; + info->max_scatter_entries = MAX_SCATTER_ENTRIES_PER_REQ; + info->max_tx_size_per_scatter_req = + MAX_SCATTER_REQ_TRANSFER_SIZE; + + status = QDF_STATUS_SUCCESS; + +end: + if (QDF_IS_STATUS_ERROR(status)) + cleanup_hif_scatter_resources(device); + + return status; +} + +/** + * cleanup_hif_scatter_resources() - cleanup HIF scatter resources + * scatter request. + * @device: hif device context + * + * + * Return: none + */ +void cleanup_hif_scatter_resources(struct hif_sdio_dev *device) +{ + struct HIF_SCATTER_REQ_PRIV *req_priv; + struct _HIF_SCATTER_REQ *req; + + /* empty the free list */ + + while (true) { + req = alloc_scatter_req(device); + + if (NULL == req) + break; + + req_priv = (struct HIF_SCATTER_REQ_PRIV *)req->hif_private[0]; + A_ASSERT(req_priv != NULL); + + if (req_priv->busrequest != NULL) { + req_priv->busrequest->scatter_req = NULL; + /* free bus request */ + hif_free_bus_request(device, req_priv->busrequest); + req_priv->busrequest = NULL; + } + + if (req_priv->hif_scatter_req != NULL) { + qdf_mem_free(req_priv->hif_scatter_req); + req_priv->hif_scatter_req = NULL; + } + + qdf_mem_free(req_priv); + } +} + +#endif /* HIF_LINUX_MMC_SCATTER_SUPPORT */ diff --git a/drivers/staging/qca-wifi-host-cmn/hif/src/sdio/regtable_sdio.c b/drivers/staging/qca-wifi-host-cmn/hif/src/sdio/regtable_sdio.c new file mode 100644 index 0000000000000000000000000000000000000000..83108dbc808402cce20a95f7573dc5c5735433f0 --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/hif/src/sdio/regtable_sdio.c @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2013-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#include "bmi_msg.h" +#include "cepci.h" + +#define MISSING 0 +#include "regtable_sdio.h" +#include "targaddrs.h" +#include "if_sdio.h" +#include "ar9888def.h" +#include "ar6320def.h" +#include "ar6320v2def.h" + +void target_register_tbl_attach(struct hif_softc *scn, u32 target_type) +{ + switch (target_type) { + case TARGET_TYPE_AR9888: + scn->targetdef = &ar9888_targetdef; + break; + case TARGET_TYPE_AR6320: + scn->targetdef = &ar6320_targetdef; + break; + case TARGET_TYPE_AR6320V2: + scn->targetdef = &ar6320v2_targetdef; + break; + default: + break; + } +} + +void hif_register_tbl_attach(struct hif_softc *scn, u32 hif_type) +{ + if (NULL == scn) { + QDF_TRACE(QDF_MODULE_ID_HIF, QDF_TRACE_LEVEL_ERROR, + "%s: sc is NULL", __func__); + return; + } + + switch (hif_type) { + case HIF_TYPE_AR9888: + scn->hostdef = &ar9888_hostdef; + break; + case HIF_TYPE_AR6320: + scn->hostdef = &ar6320_hostdef; + break; + case HIF_TYPE_AR6320V2: + scn->hostdef = &ar6320v2_hostdef; + break; + default: + break; + } +} diff --git a/drivers/staging/qca-wifi-host-cmn/hif/src/sdio/regtable_sdio.h b/drivers/staging/qca-wifi-host-cmn/hif/src/sdio/regtable_sdio.h new file mode 100644 index 0000000000000000000000000000000000000000..9006f9df06e5f16a45752562a0138fc036fae72e --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/hif/src/sdio/regtable_sdio.h @@ -0,0 +1,885 @@ +/* + * Copyright (c) 2013-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ +#ifndef _REGTABLE_SDIO_H_ +#define _REGTABLE_SDIO_H_ + +#define MISSING 0 +extern struct hif_sdio_softc *scn; + +struct targetdef_s { + uint32_t d_RTC_SOC_BASE_ADDRESS; + uint32_t d_RTC_WMAC_BASE_ADDRESS; + uint32_t d_SYSTEM_SLEEP_OFFSET; + uint32_t d_WLAN_SYSTEM_SLEEP_OFFSET; + uint32_t d_WLAN_SYSTEM_SLEEP_DISABLE_LSB; + uint32_t d_WLAN_SYSTEM_SLEEP_DISABLE_MASK; + uint32_t d_CLOCK_CONTROL_OFFSET; + uint32_t d_CLOCK_CONTROL_SI0_CLK_MASK; + uint32_t d_RESET_CONTROL_OFFSET; + uint32_t d_RESET_CONTROL_MBOX_RST_MASK; + uint32_t d_RESET_CONTROL_SI0_RST_MASK; + uint32_t d_WLAN_RESET_CONTROL_OFFSET; + uint32_t d_WLAN_RESET_CONTROL_COLD_RST_MASK; + uint32_t d_WLAN_RESET_CONTROL_WARM_RST_MASK; + uint32_t d_GPIO_BASE_ADDRESS; + uint32_t d_GPIO_PIN0_OFFSET; + uint32_t d_GPIO_PIN1_OFFSET; + uint32_t d_GPIO_PIN0_CONFIG_MASK; + uint32_t d_GPIO_PIN1_CONFIG_MASK; + uint32_t d_SI_CONFIG_BIDIR_OD_DATA_LSB; + uint32_t d_SI_CONFIG_BIDIR_OD_DATA_MASK; + uint32_t d_SI_CONFIG_I2C_LSB; + uint32_t d_SI_CONFIG_I2C_MASK; + uint32_t d_SI_CONFIG_POS_SAMPLE_LSB; + uint32_t d_SI_CONFIG_POS_SAMPLE_MASK; + uint32_t d_SI_CONFIG_INACTIVE_CLK_LSB; + uint32_t d_SI_CONFIG_INACTIVE_CLK_MASK; + uint32_t d_SI_CONFIG_INACTIVE_DATA_LSB; + uint32_t d_SI_CONFIG_INACTIVE_DATA_MASK; + uint32_t d_SI_CONFIG_DIVIDER_LSB; + uint32_t d_SI_CONFIG_DIVIDER_MASK; + uint32_t d_SI_BASE_ADDRESS; + uint32_t d_SI_CONFIG_OFFSET; + uint32_t d_SI_TX_DATA0_OFFSET; + uint32_t d_SI_TX_DATA1_OFFSET; + uint32_t d_SI_RX_DATA0_OFFSET; + uint32_t d_SI_RX_DATA1_OFFSET; + uint32_t d_SI_CS_OFFSET; + uint32_t d_SI_CS_DONE_ERR_MASK; + uint32_t d_SI_CS_DONE_INT_MASK; + uint32_t d_SI_CS_START_LSB; + uint32_t d_SI_CS_START_MASK; + uint32_t d_SI_CS_RX_CNT_LSB; + uint32_t d_SI_CS_RX_CNT_MASK; + uint32_t d_SI_CS_TX_CNT_LSB; + uint32_t d_SI_CS_TX_CNT_MASK; + uint32_t d_BOARD_DATA_SZ; + uint32_t d_BOARD_EXT_DATA_SZ; + uint32_t d_MBOX_BASE_ADDRESS; + uint32_t d_LOCAL_SCRATCH_OFFSET; + uint32_t d_CPU_CLOCK_OFFSET; + uint32_t d_LPO_CAL_OFFSET; + uint32_t d_GPIO_PIN10_OFFSET; + uint32_t d_GPIO_PIN11_OFFSET; + uint32_t d_GPIO_PIN12_OFFSET; + uint32_t d_GPIO_PIN13_OFFSET; + uint32_t d_CLOCK_GPIO_OFFSET; + uint32_t d_CPU_CLOCK_STANDARD_LSB; + uint32_t d_CPU_CLOCK_STANDARD_MASK; + uint32_t d_LPO_CAL_ENABLE_LSB; + uint32_t d_LPO_CAL_ENABLE_MASK; + uint32_t d_CLOCK_GPIO_BT_CLK_OUT_EN_LSB; + uint32_t d_CLOCK_GPIO_BT_CLK_OUT_EN_MASK; + uint32_t d_ANALOG_INTF_BASE_ADDRESS; + uint32_t d_WLAN_MAC_BASE_ADDRESS; + uint32_t d_FW_INDICATOR_ADDRESS; + uint32_t d_DRAM_BASE_ADDRESS; + uint32_t d_SOC_CORE_BASE_ADDRESS; + uint32_t d_CORE_CTRL_ADDRESS; + uint32_t d_MSI_NUM_REQUEST; + uint32_t d_MSI_ASSIGN_FW; + uint32_t d_CORE_CTRL_CPU_INTR_MASK; + uint32_t d_SR_WR_INDEX_ADDRESS; + uint32_t d_DST_WATERMARK_ADDRESS; + + /* htt_rx.c */ + uint32_t d_RX_MSDU_END_4_FIRST_MSDU_MASK; + uint32_t d_RX_MSDU_END_4_FIRST_MSDU_LSB; + uint32_t d_RX_MPDU_START_0_RETRY_LSB; + uint32_t d_RX_MPDU_START_0_RETRY_MASK; + uint32_t d_RX_MPDU_START_0_SEQ_NUM_MASK; + uint32_t d_RX_MPDU_START_0_SEQ_NUM_LSB; + uint32_t d_RX_MPDU_START_2_PN_47_32_LSB; + uint32_t d_RX_MPDU_START_2_PN_47_32_MASK; + uint32_t d_RX_MPDU_START_2_TID_LSB; + uint32_t d_RX_MPDU_START_2_TID_MASK; + uint32_t d_RX_MSDU_END_1_EXT_WAPI_PN_63_48_MASK; + uint32_t d_RX_MSDU_END_1_EXT_WAPI_PN_63_48_LSB; + uint32_t d_RX_MSDU_END_1_KEY_ID_OCT_MASK; + uint32_t d_RX_MSDU_END_1_KEY_ID_OCT_LSB; + uint32_t d_RX_MSDU_END_4_LAST_MSDU_MASK; + uint32_t d_RX_MSDU_END_4_LAST_MSDU_LSB; + uint32_t d_RX_ATTENTION_0_MCAST_BCAST_MASK; + uint32_t d_RX_ATTENTION_0_MCAST_BCAST_LSB; + uint32_t d_RX_ATTENTION_0_FRAGMENT_MASK; + uint32_t d_RX_ATTENTION_0_FRAGMENT_LSB; + uint32_t d_RX_ATTENTION_0_MPDU_LENGTH_ERR_MASK; + uint32_t d_RX_FRAG_INFO_0_RING2_MORE_COUNT_MASK; + uint32_t d_RX_FRAG_INFO_0_RING2_MORE_COUNT_LSB; + uint32_t d_RX_MSDU_START_0_MSDU_LENGTH_MASK; + uint32_t d_RX_MSDU_START_0_MSDU_LENGTH_LSB; + uint32_t d_RX_MSDU_START_2_DECAP_FORMAT_OFFSET; + uint32_t d_RX_MSDU_START_2_DECAP_FORMAT_MASK; + uint32_t d_RX_MSDU_START_2_DECAP_FORMAT_LSB; + uint32_t d_RX_MPDU_START_0_ENCRYPTED_MASK; + uint32_t d_RX_MPDU_START_0_ENCRYPTED_LSB; + uint32_t d_RX_ATTENTION_0_MORE_DATA_MASK; + uint32_t d_RX_ATTENTION_0_MSDU_DONE_MASK; + uint32_t d_RX_ATTENTION_0_TCP_UDP_CHKSUM_FAIL_MASK; + /* end */ + + /* PLL start */ + uint32_t d_EFUSE_OFFSET; + uint32_t d_EFUSE_XTAL_SEL_MSB; + uint32_t d_EFUSE_XTAL_SEL_LSB; + uint32_t d_EFUSE_XTAL_SEL_MASK; + uint32_t d_BB_PLL_CONFIG_OFFSET; + uint32_t d_BB_PLL_CONFIG_OUTDIV_MSB; + uint32_t d_BB_PLL_CONFIG_OUTDIV_LSB; + uint32_t d_BB_PLL_CONFIG_OUTDIV_MASK; + uint32_t d_BB_PLL_CONFIG_FRAC_MSB; + uint32_t d_BB_PLL_CONFIG_FRAC_LSB; + uint32_t d_BB_PLL_CONFIG_FRAC_MASK; + uint32_t d_WLAN_PLL_SETTLE_TIME_MSB; + uint32_t d_WLAN_PLL_SETTLE_TIME_LSB; + uint32_t d_WLAN_PLL_SETTLE_TIME_MASK; + uint32_t d_WLAN_PLL_SETTLE_OFFSET; + uint32_t d_WLAN_PLL_SETTLE_SW_MASK; + uint32_t d_WLAN_PLL_SETTLE_RSTMASK; + uint32_t d_WLAN_PLL_SETTLE_RESET; + uint32_t d_WLAN_PLL_CONTROL_NOPWD_MSB; + uint32_t d_WLAN_PLL_CONTROL_NOPWD_LSB; + uint32_t d_WLAN_PLL_CONTROL_NOPWD_MASK; + uint32_t d_WLAN_PLL_CONTROL_BYPASS_MSB; + uint32_t d_WLAN_PLL_CONTROL_BYPASS_LSB; + uint32_t d_WLAN_PLL_CONTROL_BYPASS_MASK; + uint32_t d_WLAN_PLL_CONTROL_BYPASS_RESET; + uint32_t d_WLAN_PLL_CONTROL_CLK_SEL_MSB; + uint32_t d_WLAN_PLL_CONTROL_CLK_SEL_LSB; + uint32_t d_WLAN_PLL_CONTROL_CLK_SEL_MASK; + uint32_t d_WLAN_PLL_CONTROL_CLK_SEL_RESET; + uint32_t d_WLAN_PLL_CONTROL_REFDIV_MSB; + uint32_t d_WLAN_PLL_CONTROL_REFDIV_LSB; + uint32_t d_WLAN_PLL_CONTROL_REFDIV_MASK; + uint32_t d_WLAN_PLL_CONTROL_REFDIV_RESET; + uint32_t d_WLAN_PLL_CONTROL_DIV_MSB; + uint32_t d_WLAN_PLL_CONTROL_DIV_LSB; + uint32_t d_WLAN_PLL_CONTROL_DIV_MASK; + uint32_t d_WLAN_PLL_CONTROL_DIV_RESET; + uint32_t d_WLAN_PLL_CONTROL_OFFSET; + uint32_t d_WLAN_PLL_CONTROL_SW_MASK; + uint32_t d_WLAN_PLL_CONTROL_RSTMASK; + uint32_t d_WLAN_PLL_CONTROL_RESET; + uint32_t d_SOC_CORE_CLK_CTRL_OFFSET; + uint32_t d_SOC_CORE_CLK_CTRL_DIV_MSB; + uint32_t d_SOC_CORE_CLK_CTRL_DIV_LSB; + uint32_t d_SOC_CORE_CLK_CTRL_DIV_MASK; + uint32_t d_RTC_SYNC_STATUS_PLL_CHANGING_MSB; + uint32_t d_RTC_SYNC_STATUS_PLL_CHANGING_LSB; + uint32_t d_RTC_SYNC_STATUS_PLL_CHANGING_MASK; + uint32_t d_RTC_SYNC_STATUS_PLL_CHANGING_RESET; + uint32_t d_RTC_SYNC_STATUS_OFFSET; + uint32_t d_SOC_CPU_CLOCK_OFFSET; + uint32_t d_SOC_CPU_CLOCK_STANDARD_MSB; + uint32_t d_SOC_CPU_CLOCK_STANDARD_LSB; + uint32_t d_SOC_CPU_CLOCK_STANDARD_MASK; + /* PLL end */ + + uint32_t d_SOC_POWER_REG_OFFSET; + uint32_t d_SOC_RESET_CONTROL_ADDRESS; + uint32_t d_SOC_RESET_CONTROL_CPU_WARM_RST_MASK; + uint32_t d_CPU_INTR_ADDRESS; + uint32_t d_SOC_LF_TIMER_CONTROL0_ADDRESS; + uint32_t d_SOC_LF_TIMER_CONTROL0_ENABLE_MASK; + + /* chip id start */ + uint32_t d_SOC_CHIP_ID_ADDRESS; + uint32_t d_SOC_CHIP_ID_VERSION_MASK; + uint32_t d_SOC_CHIP_ID_VERSION_LSB; + uint32_t d_SOC_CHIP_ID_REVISION_MASK; + uint32_t d_SOC_CHIP_ID_REVISION_LSB; + /* chip id end */ + + uint32_t d_A_SOC_CORE_SCRATCH_0_ADDRESS; + uint32_t d_A_SOC_CORE_SCRATCH_1_ADDRESS; + uint32_t d_A_SOC_CORE_SCRATCH_2_ADDRESS; + uint32_t d_A_SOC_CORE_SCRATCH_3_ADDRESS; + uint32_t d_A_SOC_CORE_SCRATCH_4_ADDRESS; + uint32_t d_A_SOC_CORE_SCRATCH_5_ADDRESS; + uint32_t d_A_SOC_CORE_SCRATCH_6_ADDRESS; + uint32_t d_A_SOC_CORE_SCRATCH_7_ADDRESS; + uint32_t d_A_SOC_CORE_SPARE_0_REGISTER; + uint32_t d_A_SOC_CORE_SPARE_1_REGISTER; + + uint32_t d_WLAN_DEBUG_INPUT_SEL_OFFSET; + uint32_t d_WLAN_DEBUG_INPUT_SEL_SRC_MSB; + uint32_t d_WLAN_DEBUG_INPUT_SEL_SRC_LSB; + uint32_t d_WLAN_DEBUG_INPUT_SEL_SRC_MASK; + uint32_t d_WLAN_DEBUG_CONTROL_OFFSET; + uint32_t d_WLAN_DEBUG_CONTROL_ENABLE_MSB; + uint32_t d_WLAN_DEBUG_CONTROL_ENABLE_LSB; + uint32_t d_WLAN_DEBUG_CONTROL_ENABLE_MASK; + uint32_t d_WLAN_DEBUG_OUT_OFFSET; + uint32_t d_WLAN_DEBUG_OUT_DATA_MSB; + uint32_t d_WLAN_DEBUG_OUT_DATA_LSB; + uint32_t d_WLAN_DEBUG_OUT_DATA_MASK; + uint32_t d_AMBA_DEBUG_BUS_OFFSET; + uint32_t d_AMBA_DEBUG_BUS_SEL_MSB; + uint32_t d_AMBA_DEBUG_BUS_SEL_LSB; + uint32_t d_AMBA_DEBUG_BUS_SEL_MASK; + +#ifdef QCA_WIFI_3_0_ADRASTEA + uint32_t d_Q6_ENABLE_REGISTER_0; + uint32_t d_Q6_ENABLE_REGISTER_1; + uint32_t d_Q6_CAUSE_REGISTER_0; + uint32_t d_Q6_CAUSE_REGISTER_1; + uint32_t d_Q6_CLEAR_REGISTER_0; + uint32_t d_Q6_CLEAR_REGISTER_1; +#endif +}; + +#define A_SOC_CORE_SPARE_0_REGISTER \ + (scn->targetdef->d_A_SOC_CORE_SPARE_0_REGISTER) +#define A_SOC_CORE_SCRATCH_0_ADDRESS \ + (scn->targetdef->d_A_SOC_CORE_SCRATCH_0_ADDRESS) +#define A_SOC_CORE_SCRATCH_1_ADDRESS \ + (scn->targetdef->d_A_SOC_CORE_SCRATCH_1_ADDRESS) +#define A_SOC_CORE_SCRATCH_2_ADDRESS \ + (scn->targetdef->d_A_SOC_CORE_SCRATCH_2_ADDRESS) +#define A_SOC_CORE_SCRATCH_3_ADDRESS \ + (scn->targetdef->d_A_SOC_CORE_SCRATCH_3_ADDRESS) +#define A_SOC_CORE_SCRATCH_4_ADDRESS \ + (scn->targetdef->d_A_SOC_CORE_SCRATCH_4_ADDRESS) +#define A_SOC_CORE_SCRATCH_5_ADDRESS \ + (scn->targetdef->d_A_SOC_CORE_SCRATCH_5_ADDRESS) +#define A_SOC_CORE_SCRATCH_6_ADDRESS \ + (scn->targetdef->d_A_SOC_CORE_SCRATCH_6_ADDRESS) +#define A_SOC_CORE_SCRATCH_7_ADDRESS \ + (scn->targetdef->d_A_SOC_CORE_SCRATCH_7_ADDRESS) +#define RTC_SOC_BASE_ADDRESS (scn->targetdef->d_RTC_SOC_BASE_ADDRESS) +#define RTC_WMAC_BASE_ADDRESS (scn->targetdef->d_RTC_WMAC_BASE_ADDRESS) +#define SYSTEM_SLEEP_OFFSET (scn->targetdef->d_SYSTEM_SLEEP_OFFSET) +#define WLAN_SYSTEM_SLEEP_OFFSET \ + (scn->targetdef->d_WLAN_SYSTEM_SLEEP_OFFSET) +#define WLAN_SYSTEM_SLEEP_DISABLE_LSB \ + (scn->targetdef->d_WLAN_SYSTEM_SLEEP_DISABLE_LSB) +#define WLAN_SYSTEM_SLEEP_DISABLE_MASK \ + (scn->targetdef->d_WLAN_SYSTEM_SLEEP_DISABLE_MASK) +#define CLOCK_CONTROL_OFFSET (scn->targetdef->d_CLOCK_CONTROL_OFFSET) +#define CLOCK_CONTROL_SI0_CLK_MASK \ + (scn->targetdef->d_CLOCK_CONTROL_SI0_CLK_MASK) +#define RESET_CONTROL_OFFSET (scn->targetdef->d_RESET_CONTROL_OFFSET) +#define RESET_CONTROL_MBOX_RST_MASK \ + (scn->targetdef->d_RESET_CONTROL_MBOX_RST_MASK) +#define RESET_CONTROL_SI0_RST_MASK \ + (scn->targetdef->d_RESET_CONTROL_SI0_RST_MASK) +#define WLAN_RESET_CONTROL_OFFSET \ + (scn->targetdef->d_WLAN_RESET_CONTROL_OFFSET) +#define WLAN_RESET_CONTROL_COLD_RST_MASK \ + (scn->targetdef->d_WLAN_RESET_CONTROL_COLD_RST_MASK) +#define WLAN_RESET_CONTROL_WARM_RST_MASK \ + (scn->targetdef->d_WLAN_RESET_CONTROL_WARM_RST_MASK) +#define GPIO_BASE_ADDRESS (scn->targetdef->d_GPIO_BASE_ADDRESS) +#define GPIO_PIN0_OFFSET (scn->targetdef->d_GPIO_PIN0_OFFSET) +#define GPIO_PIN1_OFFSET (scn->targetdef->d_GPIO_PIN1_OFFSET) +#define GPIO_PIN0_CONFIG_MASK (scn->targetdef->d_GPIO_PIN0_CONFIG_MASK) +#define GPIO_PIN1_CONFIG_MASK (scn->targetdef->d_GPIO_PIN1_CONFIG_MASK) +#define A_SOC_CORE_SCRATCH_0 (scn->targetdef->d_A_SOC_CORE_SCRATCH_0) +#define SI_CONFIG_BIDIR_OD_DATA_LSB \ + (scn->targetdef->d_SI_CONFIG_BIDIR_OD_DATA_LSB) +#define SI_CONFIG_BIDIR_OD_DATA_MASK \ + (scn->targetdef->d_SI_CONFIG_BIDIR_OD_DATA_MASK) +#define SI_CONFIG_I2C_LSB (scn->targetdef->d_SI_CONFIG_I2C_LSB) +#define SI_CONFIG_I2C_MASK \ + (scn->targetdef->d_SI_CONFIG_I2C_MASK) +#define SI_CONFIG_POS_SAMPLE_LSB \ + (scn->targetdef->d_SI_CONFIG_POS_SAMPLE_LSB) +#define SI_CONFIG_POS_SAMPLE_MASK \ + (scn->targetdef->d_SI_CONFIG_POS_SAMPLE_MASK) +#define SI_CONFIG_INACTIVE_CLK_LSB \ + (scn->targetdef->d_SI_CONFIG_INACTIVE_CLK_LSB) +#define SI_CONFIG_INACTIVE_CLK_MASK \ + (scn->targetdef->d_SI_CONFIG_INACTIVE_CLK_MASK) +#define SI_CONFIG_INACTIVE_DATA_LSB \ + (scn->targetdef->d_SI_CONFIG_INACTIVE_DATA_LSB) +#define SI_CONFIG_INACTIVE_DATA_MASK \ + (scn->targetdef->d_SI_CONFIG_INACTIVE_DATA_MASK) +#define SI_CONFIG_DIVIDER_LSB (scn->targetdef->d_SI_CONFIG_DIVIDER_LSB) +#define SI_CONFIG_DIVIDER_MASK (scn->targetdef->d_SI_CONFIG_DIVIDER_MASK) +#define SI_BASE_ADDRESS (scn->targetdef->d_SI_BASE_ADDRESS) +#define SI_CONFIG_OFFSET (scn->targetdef->d_SI_CONFIG_OFFSET) +#define SI_TX_DATA0_OFFSET (scn->targetdef->d_SI_TX_DATA0_OFFSET) +#define SI_TX_DATA1_OFFSET (scn->targetdef->d_SI_TX_DATA1_OFFSET) +#define SI_RX_DATA0_OFFSET (scn->targetdef->d_SI_RX_DATA0_OFFSET) +#define SI_RX_DATA1_OFFSET (scn->targetdef->d_SI_RX_DATA1_OFFSET) +#define SI_CS_OFFSET (scn->targetdef->d_SI_CS_OFFSET) +#define SI_CS_DONE_ERR_MASK (scn->targetdef->d_SI_CS_DONE_ERR_MASK) +#define SI_CS_DONE_INT_MASK (scn->targetdef->d_SI_CS_DONE_INT_MASK) +#define SI_CS_START_LSB (scn->targetdef->d_SI_CS_START_LSB) +#define SI_CS_START_MASK (scn->targetdef->d_SI_CS_START_MASK) +#define SI_CS_RX_CNT_LSB (scn->targetdef->d_SI_CS_RX_CNT_LSB) +#define SI_CS_RX_CNT_MASK (scn->targetdef->d_SI_CS_RX_CNT_MASK) +#define SI_CS_TX_CNT_LSB (scn->targetdef->d_SI_CS_TX_CNT_LSB) +#define SI_CS_TX_CNT_MASK (scn->targetdef->d_SI_CS_TX_CNT_MASK) +#define EEPROM_SZ (scn->targetdef->d_BOARD_DATA_SZ) +#define EEPROM_EXT_SZ (scn->targetdef->d_BOARD_EXT_DATA_SZ) +#define MBOX_BASE_ADDRESS (scn->targetdef->d_MBOX_BASE_ADDRESS) +#define LOCAL_SCRATCH_OFFSET (scn->targetdef->d_LOCAL_SCRATCH_OFFSET) +#define CPU_CLOCK_OFFSET (scn->targetdef->d_CPU_CLOCK_OFFSET) +#define LPO_CAL_OFFSET (scn->targetdef->d_LPO_CAL_OFFSET) +#define GPIO_PIN10_OFFSET (scn->targetdef->d_GPIO_PIN10_OFFSET) +#define GPIO_PIN11_OFFSET (scn->targetdef->d_GPIO_PIN11_OFFSET) +#define GPIO_PIN12_OFFSET (scn->targetdef->d_GPIO_PIN12_OFFSET) +#define GPIO_PIN13_OFFSET (scn->targetdef->d_GPIO_PIN13_OFFSET) +#define CLOCK_GPIO_OFFSET (scn->targetdef->d_CLOCK_GPIO_OFFSET) +#define CPU_CLOCK_STANDARD_LSB (scn->targetdef->d_CPU_CLOCK_STANDARD_LSB) +#define CPU_CLOCK_STANDARD_MASK (scn->targetdef->d_CPU_CLOCK_STANDARD_MASK) +#define LPO_CAL_ENABLE_LSB (scn->targetdef->d_LPO_CAL_ENABLE_LSB) +#define LPO_CAL_ENABLE_MASK (scn->targetdef->d_LPO_CAL_ENABLE_MASK) +#define CLOCK_GPIO_BT_CLK_OUT_EN_LSB \ + (scn->targetdef->d_CLOCK_GPIO_BT_CLK_OUT_EN_LSB) +#define CLOCK_GPIO_BT_CLK_OUT_EN_MASK \ + (scn->targetdef->d_CLOCK_GPIO_BT_CLK_OUT_EN_MASK) +#define ANALOG_INTF_BASE_ADDRESS (scn->targetdef->d_ANALOG_INTF_BASE_ADDRESS) +#define WLAN_MAC_BASE_ADDRESS (scn->targetdef->d_WLAN_MAC_BASE_ADDRESS) +#define FW_INDICATOR_ADDRESS (scn->targetdef->d_FW_INDICATOR_ADDRESS) +#define DRAM_BASE_ADDRESS (scn->targetdef->d_DRAM_BASE_ADDRESS) +#define SOC_CORE_BASE_ADDRESS (scn->targetdef->d_SOC_CORE_BASE_ADDRESS) +#define CORE_CTRL_ADDRESS (scn->targetdef->d_CORE_CTRL_ADDRESS) +#define CORE_CTRL_CPU_INTR_MASK (scn->targetdef->d_CORE_CTRL_CPU_INTR_MASK) +#define SOC_RESET_CONTROL_ADDRESS (scn->targetdef->d_SOC_RESET_CONTROL_ADDRESS) +#define SOC_RESET_CONTROL_CPU_WARM_RST_MASK \ + (scn->targetdef->d_SOC_RESET_CONTROL_CPU_WARM_RST_MASK) +#define CPU_INTR_ADDRESS (scn->targetdef->d_CPU_INTR_ADDRESS) +#define SOC_LF_TIMER_CONTROL0_ADDRESS \ + (scn->targetdef->d_SOC_LF_TIMER_CONTROL0_ADDRESS) +#define SOC_LF_TIMER_CONTROL0_ENABLE_MASK \ + (scn->targetdef->d_SOC_LF_TIMER_CONTROL0_ENABLE_MASK) + + +#define CHIP_ID_ADDRESS (scn->targetdef->d_SOC_CHIP_ID_ADDRESS) +#define SOC_CHIP_ID_REVISION_MASK (scn->targetdef->d_SOC_CHIP_ID_REVISION_MASK) +#define SOC_CHIP_ID_REVISION_LSB (scn->targetdef->d_SOC_CHIP_ID_REVISION_LSB) +#define SOC_CHIP_ID_VERSION_MASK (scn->targetdef->d_SOC_CHIP_ID_VERSION_MASK) +#define SOC_CHIP_ID_VERSION_LSB (scn->targetdef->d_SOC_CHIP_ID_VERSION_LSB) +#define CHIP_ID_REVISION_GET(x) \ + (((x) & SOC_CHIP_ID_REVISION_MASK) >> SOC_CHIP_ID_REVISION_LSB) +#define CHIP_ID_VERSION_GET(x) \ + (((x) & SOC_CHIP_ID_VERSION_MASK) >> SOC_CHIP_ID_VERSION_LSB) + +/* misc */ +#define SR_WR_INDEX_ADDRESS (scn->targetdef->d_SR_WR_INDEX_ADDRESS) +#define DST_WATERMARK_ADDRESS (scn->targetdef->d_DST_WATERMARK_ADDRESS) +#define SOC_POWER_REG_OFFSET (scn->targetdef->d_SOC_POWER_REG_OFFSET) +/* end */ + +/* htt_rx.c */ +#define RX_MSDU_END_4_FIRST_MSDU_MASK \ + (pdev->targetdef->d_RX_MSDU_END_4_FIRST_MSDU_MASK) +#define RX_MSDU_END_4_FIRST_MSDU_LSB \ + (pdev->targetdef->d_RX_MSDU_END_4_FIRST_MSDU_LSB) +#define RX_MPDU_START_0_RETRY_LSB \ + (pdev->targetdef->d_RX_MPDU_START_0_RETRY_LSB) +#define RX_MPDU_START_0_RETRY_MASK \ + (pdev->targetdef->d_RX_MPDU_START_0_RETRY_MASK) +#define RX_MPDU_START_0_SEQ_NUM_MASK \ + (pdev->targetdef->d_RX_MPDU_START_0_SEQ_NUM_MASK) +#define RX_MPDU_START_0_SEQ_NUM_LSB \ + (pdev->targetdef->d_RX_MPDU_START_0_SEQ_NUM_LSB) +#define RX_MPDU_START_2_PN_47_32_LSB \ + (pdev->targetdef->d_RX_MPDU_START_2_PN_47_32_LSB) +#define RX_MPDU_START_2_PN_47_32_MASK \ + (pdev->targetdef->d_RX_MPDU_START_2_PN_47_32_MASK) +#define RX_MPDU_START_2_TID_LSB \ + (pdev->targetdef->d_RX_MPDU_START_2_TID_LSB) +#define RX_MPDU_START_2_TID_MASK \ + (pdev->targetdef->d_RX_MPDU_START_2_TID_MASK) +#define RX_MSDU_END_1_KEY_ID_OCT_MASK \ + (pdev->targetdef->d_RX_MSDU_END_1_KEY_ID_OCT_MASK) +#define RX_MSDU_END_1_KEY_ID_OCT_LSB \ + (pdev->targetdef->d_RX_MSDU_END_1_KEY_ID_OCT_LSB) +#define RX_MSDU_END_1_EXT_WAPI_PN_63_48_MASK \ + (pdev->targetdef->d_RX_MSDU_END_1_EXT_WAPI_PN_63_48_MASK) +#define RX_MSDU_END_1_EXT_WAPI_PN_63_48_LSB \ + (pdev->targetdef->d_RX_MSDU_END_1_EXT_WAPI_PN_63_48_LSB) +#define RX_MSDU_END_4_LAST_MSDU_MASK \ + (pdev->targetdef->d_RX_MSDU_END_4_LAST_MSDU_MASK) +#define RX_MSDU_END_4_LAST_MSDU_LSB \ + (pdev->targetdef->d_RX_MSDU_END_4_LAST_MSDU_LSB) +#define RX_ATTENTION_0_MCAST_BCAST_MASK \ + (pdev->targetdef->d_RX_ATTENTION_0_MCAST_BCAST_MASK) +#define RX_ATTENTION_0_MCAST_BCAST_LSB \ + (pdev->targetdef->d_RX_ATTENTION_0_MCAST_BCAST_LSB) +#define RX_ATTENTION_0_FRAGMENT_MASK \ + (pdev->targetdef->d_RX_ATTENTION_0_FRAGMENT_MASK) +#define RX_ATTENTION_0_FRAGMENT_LSB \ + (pdev->targetdef->d_RX_ATTENTION_0_FRAGMENT_LSB) +#define RX_ATTENTION_0_MPDU_LENGTH_ERR_MASK \ + (pdev->targetdef->d_RX_ATTENTION_0_MPDU_LENGTH_ERR_MASK) +#define RX_FRAG_INFO_0_RING2_MORE_COUNT_MASK \ + (pdev->targetdef->d_RX_FRAG_INFO_0_RING2_MORE_COUNT_MASK) +#define RX_FRAG_INFO_0_RING2_MORE_COUNT_LSB \ + (pdev->targetdef->d_RX_FRAG_INFO_0_RING2_MORE_COUNT_LSB) +#define RX_MSDU_START_0_MSDU_LENGTH_MASK \ + (pdev->targetdef->d_RX_MSDU_START_0_MSDU_LENGTH_MASK) +#define RX_MSDU_START_0_MSDU_LENGTH_LSB \ + (pdev->targetdef->d_RX_MSDU_START_0_MSDU_LENGTH_LSB) +#define RX_MSDU_START_2_DECAP_FORMAT_OFFSET \ + (pdev->targetdef->d_RX_MSDU_START_2_DECAP_FORMAT_OFFSET) +#define RX_MSDU_START_2_DECAP_FORMAT_MASK \ + (pdev->targetdef->d_RX_MSDU_START_2_DECAP_FORMAT_MASK) +#define RX_MSDU_START_2_DECAP_FORMAT_LSB \ + (pdev->targetdef->d_RX_MSDU_START_2_DECAP_FORMAT_LSB) +#define RX_MPDU_START_0_ENCRYPTED_MASK \ + (pdev->targetdef->d_RX_MPDU_START_0_ENCRYPTED_MASK) +#define RX_MPDU_START_0_ENCRYPTED_LSB \ + (pdev->targetdef->d_RX_MPDU_START_0_ENCRYPTED_LSB) +#define RX_ATTENTION_0_MORE_DATA_MASK \ + (pdev->targetdef->d_RX_ATTENTION_0_MORE_DATA_MASK) +#define RX_ATTENTION_0_MSDU_DONE_MASK \ + (pdev->targetdef->d_RX_ATTENTION_0_MSDU_DONE_MASK) +#define RX_ATTENTION_0_TCP_UDP_CHKSUM_FAIL_MASK \ + (pdev->targetdef->d_RX_ATTENTION_0_TCP_UDP_CHKSUM_FAIL_MASK) +/* end */ + +/* copy_engine.c */ +/* end */ +/* PLL start */ +#define EFUSE_OFFSET (scn->targetdef->d_EFUSE_OFFSET) +#define EFUSE_XTAL_SEL_MSB (scn->targetdef->d_EFUSE_XTAL_SEL_MSB) +#define EFUSE_XTAL_SEL_LSB (scn->targetdef->d_EFUSE_XTAL_SEL_LSB) +#define EFUSE_XTAL_SEL_MASK (scn->targetdef->d_EFUSE_XTAL_SEL_MASK) +#define BB_PLL_CONFIG_OFFSET (scn->targetdef->d_BB_PLL_CONFIG_OFFSET) +#define BB_PLL_CONFIG_OUTDIV_MSB (scn->targetdef->d_BB_PLL_CONFIG_OUTDIV_MSB) +#define BB_PLL_CONFIG_OUTDIV_LSB (scn->targetdef->d_BB_PLL_CONFIG_OUTDIV_LSB) +#define BB_PLL_CONFIG_OUTDIV_MASK (scn->targetdef->d_BB_PLL_CONFIG_OUTDIV_MASK) +#define BB_PLL_CONFIG_FRAC_MSB (scn->targetdef->d_BB_PLL_CONFIG_FRAC_MSB) +#define BB_PLL_CONFIG_FRAC_LSB (scn->targetdef->d_BB_PLL_CONFIG_FRAC_LSB) +#define BB_PLL_CONFIG_FRAC_MASK (scn->targetdef->d_BB_PLL_CONFIG_FRAC_MASK) +#define WLAN_PLL_SETTLE_TIME_MSB (scn->targetdef->d_WLAN_PLL_SETTLE_TIME_MSB) +#define WLAN_PLL_SETTLE_TIME_LSB (scn->targetdef->d_WLAN_PLL_SETTLE_TIME_LSB) +#define WLAN_PLL_SETTLE_TIME_MASK (scn->targetdef->d_WLAN_PLL_SETTLE_TIME_MASK) +#define WLAN_PLL_SETTLE_OFFSET (scn->targetdef->d_WLAN_PLL_SETTLE_OFFSET) +#define WLAN_PLL_SETTLE_SW_MASK (scn->targetdef->d_WLAN_PLL_SETTLE_SW_MASK) +#define WLAN_PLL_SETTLE_RSTMASK (scn->targetdef->d_WLAN_PLL_SETTLE_RSTMASK) +#define WLAN_PLL_SETTLE_RESET (scn->targetdef->d_WLAN_PLL_SETTLE_RESET) +#define WLAN_PLL_CONTROL_NOPWD_MSB \ + (scn->targetdef->d_WLAN_PLL_CONTROL_NOPWD_MSB) +#define WLAN_PLL_CONTROL_NOPWD_LSB \ + (scn->targetdef->d_WLAN_PLL_CONTROL_NOPWD_LSB) +#define WLAN_PLL_CONTROL_NOPWD_MASK \ + (scn->targetdef->d_WLAN_PLL_CONTROL_NOPWD_MASK) +#define WLAN_PLL_CONTROL_BYPASS_MSB \ + (scn->targetdef->d_WLAN_PLL_CONTROL_BYPASS_MSB) +#define WLAN_PLL_CONTROL_BYPASS_LSB \ + (scn->targetdef->d_WLAN_PLL_CONTROL_BYPASS_LSB) +#define WLAN_PLL_CONTROL_BYPASS_MASK \ + (scn->targetdef->d_WLAN_PLL_CONTROL_BYPASS_MASK) +#define WLAN_PLL_CONTROL_BYPASS_RESET \ + (scn->targetdef->d_WLAN_PLL_CONTROL_BYPASS_RESET) +#define WLAN_PLL_CONTROL_CLK_SEL_MSB \ + (scn->targetdef->d_WLAN_PLL_CONTROL_CLK_SEL_MSB) +#define WLAN_PLL_CONTROL_CLK_SEL_LSB \ + (scn->targetdef->d_WLAN_PLL_CONTROL_CLK_SEL_LSB) +#define WLAN_PLL_CONTROL_CLK_SEL_MASK \ + (scn->targetdef->d_WLAN_PLL_CONTROL_CLK_SEL_MASK) +#define WLAN_PLL_CONTROL_CLK_SEL_RESET \ + (scn->targetdef->d_WLAN_PLL_CONTROL_CLK_SEL_RESET) +#define WLAN_PLL_CONTROL_REFDIV_MSB \ + (scn->targetdef->d_WLAN_PLL_CONTROL_REFDIV_MSB) +#define WLAN_PLL_CONTROL_REFDIV_LSB \ + (scn->targetdef->d_WLAN_PLL_CONTROL_REFDIV_LSB) +#define WLAN_PLL_CONTROL_REFDIV_MASK \ + (scn->targetdef->d_WLAN_PLL_CONTROL_REFDIV_MASK) +#define WLAN_PLL_CONTROL_REFDIV_RESET \ + (scn->targetdef->d_WLAN_PLL_CONTROL_REFDIV_RESET) +#define WLAN_PLL_CONTROL_DIV_MSB (scn->targetdef->d_WLAN_PLL_CONTROL_DIV_MSB) +#define WLAN_PLL_CONTROL_DIV_LSB (scn->targetdef->d_WLAN_PLL_CONTROL_DIV_LSB) +#define WLAN_PLL_CONTROL_DIV_MASK (scn->targetdef->d_WLAN_PLL_CONTROL_DIV_MASK) +#define WLAN_PLL_CONTROL_DIV_RESET \ + (scn->targetdef->d_WLAN_PLL_CONTROL_DIV_RESET) +#define WLAN_PLL_CONTROL_OFFSET (scn->targetdef->d_WLAN_PLL_CONTROL_OFFSET) +#define WLAN_PLL_CONTROL_SW_MASK (scn->targetdef->d_WLAN_PLL_CONTROL_SW_MASK) +#define WLAN_PLL_CONTROL_RSTMASK (scn->targetdef->d_WLAN_PLL_CONTROL_RSTMASK) +#define WLAN_PLL_CONTROL_RESET (scn->targetdef->d_WLAN_PLL_CONTROL_RESET) +#define SOC_CORE_CLK_CTRL_OFFSET (scn->targetdef->d_SOC_CORE_CLK_CTRL_OFFSET) +#define SOC_CORE_CLK_CTRL_DIV_MSB (scn->targetdef->d_SOC_CORE_CLK_CTRL_DIV_MSB) +#define SOC_CORE_CLK_CTRL_DIV_LSB (scn->targetdef->d_SOC_CORE_CLK_CTRL_DIV_LSB) +#define SOC_CORE_CLK_CTRL_DIV_MASK \ + (scn->targetdef->d_SOC_CORE_CLK_CTRL_DIV_MASK) +#define RTC_SYNC_STATUS_PLL_CHANGING_MSB \ + (scn->targetdef->d_RTC_SYNC_STATUS_PLL_CHANGING_MSB) +#define RTC_SYNC_STATUS_PLL_CHANGING_LSB \ + (scn->targetdef->d_RTC_SYNC_STATUS_PLL_CHANGING_LSB) +#define RTC_SYNC_STATUS_PLL_CHANGING_MASK \ + (scn->targetdef->d_RTC_SYNC_STATUS_PLL_CHANGING_MASK) +#define RTC_SYNC_STATUS_PLL_CHANGING_RESET \ + (scn->targetdef->d_RTC_SYNC_STATUS_PLL_CHANGING_RESET) +#define RTC_SYNC_STATUS_OFFSET (scn->targetdef->d_RTC_SYNC_STATUS_OFFSET) +#define SOC_CPU_CLOCK_OFFSET (scn->targetdef->d_SOC_CPU_CLOCK_OFFSET) +#define SOC_CPU_CLOCK_STANDARD_MSB \ + (scn->targetdef->d_SOC_CPU_CLOCK_STANDARD_MSB) +#define SOC_CPU_CLOCK_STANDARD_LSB \ + (scn->targetdef->d_SOC_CPU_CLOCK_STANDARD_LSB) +#define SOC_CPU_CLOCK_STANDARD_MASK \ + (scn->targetdef->d_SOC_CPU_CLOCK_STANDARD_MASK) +/* PLL end */ + +/* SET macros */ +#define WLAN_SYSTEM_SLEEP_DISABLE_SET(x) \ + (((x) << WLAN_SYSTEM_SLEEP_DISABLE_LSB) & \ + WLAN_SYSTEM_SLEEP_DISABLE_MASK) +#define SI_CONFIG_BIDIR_OD_DATA_SET(x) \ + (((x) << SI_CONFIG_BIDIR_OD_DATA_LSB) & SI_CONFIG_BIDIR_OD_DATA_MASK) +#define SI_CONFIG_I2C_SET(x) (((x) << SI_CONFIG_I2C_LSB) & SI_CONFIG_I2C_MASK) +#define SI_CONFIG_POS_SAMPLE_SET(x) \ + (((x) << SI_CONFIG_POS_SAMPLE_LSB) & SI_CONFIG_POS_SAMPLE_MASK) +#define SI_CONFIG_INACTIVE_CLK_SET(x) \ + (((x) << SI_CONFIG_INACTIVE_CLK_LSB) & SI_CONFIG_INACTIVE_CLK_MASK) +#define SI_CONFIG_INACTIVE_DATA_SET(x) \ + (((x) << SI_CONFIG_INACTIVE_DATA_LSB) & SI_CONFIG_INACTIVE_DATA_MASK) +#define SI_CONFIG_DIVIDER_SET(x) \ + (((x) << SI_CONFIG_DIVIDER_LSB) & SI_CONFIG_DIVIDER_MASK) +#define SI_CS_START_SET(x) (((x) << SI_CS_START_LSB) & SI_CS_START_MASK) +#define SI_CS_RX_CNT_SET(x) (((x) << SI_CS_RX_CNT_LSB) & SI_CS_RX_CNT_MASK) +#define SI_CS_TX_CNT_SET(x) (((x) << SI_CS_TX_CNT_LSB) & SI_CS_TX_CNT_MASK) +#define LPO_CAL_ENABLE_SET(x) \ + (((x) << LPO_CAL_ENABLE_LSB) & LPO_CAL_ENABLE_MASK) +#define CPU_CLOCK_STANDARD_SET(x) \ + (((x) << CPU_CLOCK_STANDARD_LSB) & CPU_CLOCK_STANDARD_MASK) +#define CLOCK_GPIO_BT_CLK_OUT_EN_SET(x) \ + (((x) << CLOCK_GPIO_BT_CLK_OUT_EN_LSB) & CLOCK_GPIO_BT_CLK_OUT_EN_MASK) +/* copy_engine.c */ +/* end */ +/* PLL start */ +#define EFUSE_XTAL_SEL_GET(x) \ + (((x) & EFUSE_XTAL_SEL_MASK) >> EFUSE_XTAL_SEL_LSB) +#define EFUSE_XTAL_SEL_SET(x) \ + (((x) << EFUSE_XTAL_SEL_LSB) & EFUSE_XTAL_SEL_MASK) +#define BB_PLL_CONFIG_OUTDIV_GET(x) \ + (((x) & BB_PLL_CONFIG_OUTDIV_MASK) >> BB_PLL_CONFIG_OUTDIV_LSB) +#define BB_PLL_CONFIG_OUTDIV_SET(x) \ + (((x) << BB_PLL_CONFIG_OUTDIV_LSB) & BB_PLL_CONFIG_OUTDIV_MASK) +#define BB_PLL_CONFIG_FRAC_GET(x) \ + (((x) & BB_PLL_CONFIG_FRAC_MASK) >> BB_PLL_CONFIG_FRAC_LSB) +#define BB_PLL_CONFIG_FRAC_SET(x) \ + (((x) << BB_PLL_CONFIG_FRAC_LSB) & BB_PLL_CONFIG_FRAC_MASK) +#define WLAN_PLL_SETTLE_TIME_GET(x) \ + (((x) & WLAN_PLL_SETTLE_TIME_MASK) >> WLAN_PLL_SETTLE_TIME_LSB) +#define WLAN_PLL_SETTLE_TIME_SET(x) \ + (((x) << WLAN_PLL_SETTLE_TIME_LSB) & WLAN_PLL_SETTLE_TIME_MASK) +#define WLAN_PLL_CONTROL_NOPWD_GET(x) \ + (((x) & WLAN_PLL_CONTROL_NOPWD_MASK) >> WLAN_PLL_CONTROL_NOPWD_LSB) +#define WLAN_PLL_CONTROL_NOPWD_SET(x) \ + (((x) << WLAN_PLL_CONTROL_NOPWD_LSB) & WLAN_PLL_CONTROL_NOPWD_MASK) +#define WLAN_PLL_CONTROL_BYPASS_GET(x) \ + (((x) & WLAN_PLL_CONTROL_BYPASS_MASK) >> WLAN_PLL_CONTROL_BYPASS_LSB) +#define WLAN_PLL_CONTROL_BYPASS_SET(x) \ + (((x) << WLAN_PLL_CONTROL_BYPASS_LSB) & WLAN_PLL_CONTROL_BYPASS_MASK) +#define WLAN_PLL_CONTROL_CLK_SEL_GET(x) \ + (((x) & WLAN_PLL_CONTROL_CLK_SEL_MASK) >> WLAN_PLL_CONTROL_CLK_SEL_LSB) +#define WLAN_PLL_CONTROL_CLK_SEL_SET(x) \ + (((x) << WLAN_PLL_CONTROL_CLK_SEL_LSB) & WLAN_PLL_CONTROL_CLK_SEL_MASK) +#define WLAN_PLL_CONTROL_REFDIV_GET(x) \ + (((x) & WLAN_PLL_CONTROL_REFDIV_MASK) >> WLAN_PLL_CONTROL_REFDIV_LSB) +#define WLAN_PLL_CONTROL_REFDIV_SET(x) \ + (((x) << WLAN_PLL_CONTROL_REFDIV_LSB) & WLAN_PLL_CONTROL_REFDIV_MASK) +#define WLAN_PLL_CONTROL_DIV_GET(x) \ + (((x) & WLAN_PLL_CONTROL_DIV_MASK) >> WLAN_PLL_CONTROL_DIV_LSB) +#define WLAN_PLL_CONTROL_DIV_SET(x) \ + (((x) << WLAN_PLL_CONTROL_DIV_LSB) & WLAN_PLL_CONTROL_DIV_MASK) +#define SOC_CORE_CLK_CTRL_DIV_GET(x) \ + (((x) & SOC_CORE_CLK_CTRL_DIV_MASK) >> SOC_CORE_CLK_CTRL_DIV_LSB) +#define SOC_CORE_CLK_CTRL_DIV_SET(x) \ + (((x) << SOC_CORE_CLK_CTRL_DIV_LSB) & SOC_CORE_CLK_CTRL_DIV_MASK) +#define RTC_SYNC_STATUS_PLL_CHANGING_GET(x) \ + (((x) & RTC_SYNC_STATUS_PLL_CHANGING_MASK) >> \ + RTC_SYNC_STATUS_PLL_CHANGING_LSB) +#define RTC_SYNC_STATUS_PLL_CHANGING_SET(x) \ + (((x) << RTC_SYNC_STATUS_PLL_CHANGING_LSB) & \ + RTC_SYNC_STATUS_PLL_CHANGING_MASK) +#define SOC_CPU_CLOCK_STANDARD_GET(x) \ + (((x) & SOC_CPU_CLOCK_STANDARD_MASK) >> SOC_CPU_CLOCK_STANDARD_LSB) +#define SOC_CPU_CLOCK_STANDARD_SET(x) \ + (((x) << SOC_CPU_CLOCK_STANDARD_LSB) & SOC_CPU_CLOCK_STANDARD_MASK) +/* PLL end */ + +#ifdef QCA_WIFI_3_0_ADRASTEA +#define Q6_ENABLE_REGISTER_0 \ + (scn->targetdef->d_Q6_ENABLE_REGISTER_0) +#define Q6_ENABLE_REGISTER_1 \ + (scn->targetdef->d_Q6_ENABLE_REGISTER_1) +#define Q6_CAUSE_REGISTER_0 \ + (scn->targetdef->d_Q6_CAUSE_REGISTER_0) +#define Q6_CAUSE_REGISTER_1 \ + (scn->targetdef->d_Q6_CAUSE_REGISTER_1) +#define Q6_CLEAR_REGISTER_0 \ + (scn->targetdef->d_Q6_CLEAR_REGISTER_0) +#define Q6_CLEAR_REGISTER_1 \ + (scn->targetdef->d_Q6_CLEAR_REGISTER_1) +#endif + +struct hostdef_s { + uint32_t d_INT_STATUS_ENABLE_ERROR_LSB; + uint32_t d_INT_STATUS_ENABLE_ERROR_MASK; + uint32_t d_INT_STATUS_ENABLE_CPU_LSB; + uint32_t d_INT_STATUS_ENABLE_CPU_MASK; + uint32_t d_INT_STATUS_ENABLE_COUNTER_LSB; + uint32_t d_INT_STATUS_ENABLE_COUNTER_MASK; + uint32_t d_INT_STATUS_ENABLE_MBOX_DATA_LSB; + uint32_t d_INT_STATUS_ENABLE_MBOX_DATA_MASK; + uint32_t d_ERROR_STATUS_ENABLE_RX_UNDERFLOW_LSB; + uint32_t d_ERROR_STATUS_ENABLE_RX_UNDERFLOW_MASK; + uint32_t d_ERROR_STATUS_ENABLE_TX_OVERFLOW_LSB; + uint32_t d_ERROR_STATUS_ENABLE_TX_OVERFLOW_MASK; + uint32_t d_COUNTER_INT_STATUS_ENABLE_BIT_LSB; + uint32_t d_COUNTER_INT_STATUS_ENABLE_BIT_MASK; + uint32_t d_INT_STATUS_ENABLE_ADDRESS; + uint32_t d_CPU_INT_STATUS_ENABLE_BIT_LSB; + uint32_t d_CPU_INT_STATUS_ENABLE_BIT_MASK; + uint32_t d_HOST_INT_STATUS_ADDRESS; + uint32_t d_CPU_INT_STATUS_ADDRESS; + uint32_t d_ERROR_INT_STATUS_ADDRESS; + uint32_t d_ERROR_INT_STATUS_WAKEUP_MASK; + uint32_t d_ERROR_INT_STATUS_WAKEUP_LSB; + uint32_t d_ERROR_INT_STATUS_RX_UNDERFLOW_MASK; + uint32_t d_ERROR_INT_STATUS_RX_UNDERFLOW_LSB; + uint32_t d_ERROR_INT_STATUS_TX_OVERFLOW_MASK; + uint32_t d_ERROR_INT_STATUS_TX_OVERFLOW_LSB; + uint32_t d_COUNT_DEC_ADDRESS; + uint32_t d_HOST_INT_STATUS_CPU_MASK; + uint32_t d_HOST_INT_STATUS_CPU_LSB; + uint32_t d_HOST_INT_STATUS_ERROR_MASK; + uint32_t d_HOST_INT_STATUS_ERROR_LSB; + uint32_t d_HOST_INT_STATUS_COUNTER_MASK; + uint32_t d_HOST_INT_STATUS_COUNTER_LSB; + uint32_t d_RX_LOOKAHEAD_VALID_ADDRESS; + uint32_t d_WINDOW_DATA_ADDRESS; + uint32_t d_WINDOW_READ_ADDR_ADDRESS; + uint32_t d_WINDOW_WRITE_ADDR_ADDRESS; + uint32_t d_SOC_GLOBAL_RESET_ADDRESS; + uint32_t d_RTC_STATE_ADDRESS; + uint32_t d_RTC_STATE_COLD_RESET_MASK; + uint32_t d_RTC_STATE_V_MASK; + uint32_t d_RTC_STATE_V_LSB; + uint32_t d_FW_IND_EVENT_PENDING; + uint32_t d_FW_IND_INITIALIZED; + uint32_t d_FW_IND_HELPER; + uint32_t d_RTC_STATE_V_ON; +#if defined(SDIO_3_0) + uint32_t d_HOST_INT_STATUS_MBOX_DATA_MASK; + uint32_t d_HOST_INT_STATUS_MBOX_DATA_LSB; +#endif + uint32_t d_MSI_MAGIC_ADR_ADDRESS; + uint32_t d_MSI_MAGIC_ADDRESS; + uint32_t d_ENABLE_MSI; + uint32_t d_MUX_ID_MASK; + uint32_t d_TRANSACTION_ID_MASK; + uint32_t d_DESC_DATA_FLAG_MASK; +}; +#define DESC_DATA_FLAG_MASK (scn->hostdef->d_DESC_DATA_FLAG_MASK) +#define MUX_ID_MASK (scn->hostdef->d_MUX_ID_MASK) +#define TRANSACTION_ID_MASK (scn->hostdef->d_TRANSACTION_ID_MASK) +#define ENABLE_MSI (scn->hostdef->d_ENABLE_MSI) +#define INT_STATUS_ENABLE_ERROR_LSB \ + (scn->hostdef->d_INT_STATUS_ENABLE_ERROR_LSB) +#define INT_STATUS_ENABLE_ERROR_MASK \ + (scn->hostdef->d_INT_STATUS_ENABLE_ERROR_MASK) +#define INT_STATUS_ENABLE_CPU_LSB (scn->hostdef->d_INT_STATUS_ENABLE_CPU_LSB) +#define INT_STATUS_ENABLE_CPU_MASK (scn->hostdef->d_INT_STATUS_ENABLE_CPU_MASK) +#define INT_STATUS_ENABLE_COUNTER_LSB \ + (scn->hostdef->d_INT_STATUS_ENABLE_COUNTER_LSB) +#define INT_STATUS_ENABLE_COUNTER_MASK \ + (scn->hostdef->d_INT_STATUS_ENABLE_COUNTER_MASK) +#define INT_STATUS_ENABLE_MBOX_DATA_LSB \ + (scn->hostdef->d_INT_STATUS_ENABLE_MBOX_DATA_LSB) +#define INT_STATUS_ENABLE_MBOX_DATA_MASK \ + (scn->hostdef->d_INT_STATUS_ENABLE_MBOX_DATA_MASK) +#define ERROR_STATUS_ENABLE_RX_UNDERFLOW_LSB \ + (scn->hostdef->d_ERROR_STATUS_ENABLE_RX_UNDERFLOW_LSB) +#define ERROR_STATUS_ENABLE_RX_UNDERFLOW_MASK \ + (scn->hostdef->d_ERROR_STATUS_ENABLE_RX_UNDERFLOW_MASK) +#define ERROR_STATUS_ENABLE_TX_OVERFLOW_LSB \ + (scn->hostdef->d_ERROR_STATUS_ENABLE_TX_OVERFLOW_LSB) +#define ERROR_STATUS_ENABLE_TX_OVERFLOW_MASK \ + (scn->hostdef->d_ERROR_STATUS_ENABLE_TX_OVERFLOW_MASK) +#define COUNTER_INT_STATUS_ENABLE_BIT_LSB \ + (scn->hostdef->d_COUNTER_INT_STATUS_ENABLE_BIT_LSB) +#define COUNTER_INT_STATUS_ENABLE_BIT_MASK \ + (scn->hostdef->d_COUNTER_INT_STATUS_ENABLE_BIT_MASK) +#define INT_STATUS_ENABLE_ADDRESS \ + (scn->hostdef->d_INT_STATUS_ENABLE_ADDRESS) +#define CPU_INT_STATUS_ENABLE_BIT_LSB \ + (scn->hostdef->d_CPU_INT_STATUS_ENABLE_BIT_LSB) +#define CPU_INT_STATUS_ENABLE_BIT_MASK \ + (scn->hostdef->d_CPU_INT_STATUS_ENABLE_BIT_MASK) +#define HOST_INT_STATUS_ADDRESS (scn->hostdef->d_HOST_INT_STATUS_ADDRESS) +#define CPU_INT_STATUS_ADDRESS (scn->hostdef->d_CPU_INT_STATUS_ADDRESS) +#define ERROR_INT_STATUS_ADDRESS (scn->hostdef->d_ERROR_INT_STATUS_ADDRESS) +#define ERROR_INT_STATUS_WAKEUP_MASK \ + (scn->hostdef->d_ERROR_INT_STATUS_WAKEUP_MASK) +#define ERROR_INT_STATUS_WAKEUP_LSB \ + (scn->hostdef->d_ERROR_INT_STATUS_WAKEUP_LSB) +#define ERROR_INT_STATUS_RX_UNDERFLOW_MASK \ + (scn->hostdef->d_ERROR_INT_STATUS_RX_UNDERFLOW_MASK) +#define ERROR_INT_STATUS_RX_UNDERFLOW_LSB \ + (scn->hostdef->d_ERROR_INT_STATUS_RX_UNDERFLOW_LSB) +#define ERROR_INT_STATUS_TX_OVERFLOW_MASK \ + (scn->hostdef->d_ERROR_INT_STATUS_TX_OVERFLOW_MASK) +#define ERROR_INT_STATUS_TX_OVERFLOW_LSB \ + (scn->hostdef->d_ERROR_INT_STATUS_TX_OVERFLOW_LSB) +#define COUNT_DEC_ADDRESS (scn->hostdef->d_COUNT_DEC_ADDRESS) +#define HOST_INT_STATUS_CPU_MASK (scn->hostdef->d_HOST_INT_STATUS_CPU_MASK) +#define HOST_INT_STATUS_CPU_LSB (scn->hostdef->d_HOST_INT_STATUS_CPU_LSB) +#define HOST_INT_STATUS_ERROR_MASK (scn->hostdef->d_HOST_INT_STATUS_ERROR_MASK) +#define HOST_INT_STATUS_ERROR_LSB (scn->hostdef->d_HOST_INT_STATUS_ERROR_LSB) +#define HOST_INT_STATUS_COUNTER_MASK \ + (scn->hostdef->d_HOST_INT_STATUS_COUNTER_MASK) +#define HOST_INT_STATUS_COUNTER_LSB \ + (scn->hostdef->d_HOST_INT_STATUS_COUNTER_LSB) +#define RX_LOOKAHEAD_VALID_ADDRESS (scn->hostdef->d_RX_LOOKAHEAD_VALID_ADDRESS) +#define WINDOW_DATA_ADDRESS (scn->hostdef->d_WINDOW_DATA_ADDRESS) +#define WINDOW_READ_ADDR_ADDRESS (scn->hostdef->d_WINDOW_READ_ADDR_ADDRESS) +#define WINDOW_WRITE_ADDR_ADDRESS (scn->hostdef->d_WINDOW_WRITE_ADDR_ADDRESS) +#define SOC_GLOBAL_RESET_ADDRESS (scn->hostdef->d_SOC_GLOBAL_RESET_ADDRESS) +#define RTC_STATE_ADDRESS (scn->hostdef->d_RTC_STATE_ADDRESS) +#define RTC_STATE_COLD_RESET_MASK (scn->hostdef->d_RTC_STATE_COLD_RESET_MASK) +#define RTC_STATE_V_MASK (scn->hostdef->d_RTC_STATE_V_MASK) +#define RTC_STATE_V_LSB (scn->hostdef->d_RTC_STATE_V_LSB) +#define FW_IND_EVENT_PENDING (scn->hostdef->d_FW_IND_EVENT_PENDING) +#define FW_IND_INITIALIZED (scn->hostdef->d_FW_IND_INITIALIZED) +#define FW_IND_HELPER (scn->hostdef->d_FW_IND_HELPER) +#define RTC_STATE_V_ON (scn->hostdef->d_RTC_STATE_V_ON) +#if defined(SDIO_3_0) +#define HOST_INT_STATUS_MBOX_DATA_MASK \ + (scn->hostdef->d_HOST_INT_STATUS_MBOX_DATA_MASK) +#define HOST_INT_STATUS_MBOX_DATA_LSB \ + (scn->hostdef->d_HOST_INT_STATUS_MBOX_DATA_LSB) +#endif + +#if !defined(MSI_MAGIC_ADR_ADDRESS) +#define MSI_MAGIC_ADR_ADDRESS 0 +#define MSI_MAGIC_ADDRESS 0 +#endif + +/* SET/GET macros */ +#define INT_STATUS_ENABLE_ERROR_SET(x) \ + (((x) << INT_STATUS_ENABLE_ERROR_LSB) & INT_STATUS_ENABLE_ERROR_MASK) +#define INT_STATUS_ENABLE_CPU_SET(x) \ + (((x) << INT_STATUS_ENABLE_CPU_LSB) & INT_STATUS_ENABLE_CPU_MASK) +#define INT_STATUS_ENABLE_COUNTER_SET(x) \ + (((x) << INT_STATUS_ENABLE_COUNTER_LSB) & \ + INT_STATUS_ENABLE_COUNTER_MASK) +#define INT_STATUS_ENABLE_MBOX_DATA_SET(x) \ + (((x) << INT_STATUS_ENABLE_MBOX_DATA_LSB) & \ + INT_STATUS_ENABLE_MBOX_DATA_MASK) +#define CPU_INT_STATUS_ENABLE_BIT_SET(x) \ + (((x) << CPU_INT_STATUS_ENABLE_BIT_LSB) & \ + CPU_INT_STATUS_ENABLE_BIT_MASK) +#define ERROR_STATUS_ENABLE_RX_UNDERFLOW_SET(x) \ + (((x) << ERROR_STATUS_ENABLE_RX_UNDERFLOW_LSB) & \ + ERROR_STATUS_ENABLE_RX_UNDERFLOW_MASK) +#define ERROR_STATUS_ENABLE_TX_OVERFLOW_SET(x) \ + (((x) << ERROR_STATUS_ENABLE_TX_OVERFLOW_LSB) & \ + ERROR_STATUS_ENABLE_TX_OVERFLOW_MASK) +#define COUNTER_INT_STATUS_ENABLE_BIT_SET(x) \ + (((x) << COUNTER_INT_STATUS_ENABLE_BIT_LSB) & \ + COUNTER_INT_STATUS_ENABLE_BIT_MASK) +#define ERROR_INT_STATUS_WAKEUP_GET(x) \ + (((x) & ERROR_INT_STATUS_WAKEUP_MASK) >> \ + ERROR_INT_STATUS_WAKEUP_LSB) +#define ERROR_INT_STATUS_RX_UNDERFLOW_GET(x) \ + (((x) & ERROR_INT_STATUS_RX_UNDERFLOW_MASK) >> \ + ERROR_INT_STATUS_RX_UNDERFLOW_LSB) +#define ERROR_INT_STATUS_TX_OVERFLOW_GET(x) \ + (((x) & ERROR_INT_STATUS_TX_OVERFLOW_MASK) >> \ + ERROR_INT_STATUS_TX_OVERFLOW_LSB) +#define HOST_INT_STATUS_CPU_GET(x) \ + (((x) & HOST_INT_STATUS_CPU_MASK) >> HOST_INT_STATUS_CPU_LSB) +#define HOST_INT_STATUS_ERROR_GET(x) \ + (((x) & HOST_INT_STATUS_ERROR_MASK) >> HOST_INT_STATUS_ERROR_LSB) +#define HOST_INT_STATUS_COUNTER_GET(x) \ + (((x) & HOST_INT_STATUS_COUNTER_MASK) >> HOST_INT_STATUS_COUNTER_LSB) +#define RTC_STATE_V_GET(x) \ + (((x) & RTC_STATE_V_MASK) >> RTC_STATE_V_LSB) +#if defined(SDIO_3_0) +#define HOST_INT_STATUS_MBOX_DATA_GET(x) \ + (((x) & HOST_INT_STATUS_MBOX_DATA_MASK) >> \ + HOST_INT_STATUS_MBOX_DATA_LSB) +#endif + +#define INVALID_REG_LOC_DUMMY_DATA 0xAA + +#define AR6320_CORE_CLK_DIV_ADDR 0x403fa8 +#define AR6320_CPU_PLL_INIT_DONE_ADDR 0x403fd0 +#define AR6320_CPU_SPEED_ADDR 0x403fa4 +#define AR6320V2_CORE_CLK_DIV_ADDR 0x403fd8 +#define AR6320V2_CPU_PLL_INIT_DONE_ADDR 0x403fd0 +#define AR6320V2_CPU_SPEED_ADDR 0x403fd4 +#define AR6320V3_CORE_CLK_DIV_ADDR 0x404028 +#define AR6320V3_CPU_PLL_INIT_DONE_ADDR 0x404020 +#define AR6320V3_CPU_SPEED_ADDR 0x404024 + +typedef enum { + SOC_REFCLK_UNKNOWN = -1, /* Unsupported ref clock -- use PLL Bypass */ + SOC_REFCLK_48_MHZ = 0, + SOC_REFCLK_19_2_MHZ = 1, + SOC_REFCLK_24_MHZ = 2, + SOC_REFCLK_26_MHZ = 3, + SOC_REFCLK_37_4_MHZ = 4, + SOC_REFCLK_38_4_MHZ = 5, + SOC_REFCLK_40_MHZ = 6, + SOC_REFCLK_52_MHZ = 7, +} A_refclk_speed_t; + +#define A_REFCLK_UNKNOWN SOC_REFCLK_UNKNOWN +#define A_REFCLK_48_MHZ SOC_REFCLK_48_MHZ +#define A_REFCLK_19_2_MHZ SOC_REFCLK_19_2_MHZ +#define A_REFCLK_24_MHZ SOC_REFCLK_24_MHZ +#define A_REFCLK_26_MHZ SOC_REFCLK_26_MHZ +#define A_REFCLK_37_4_MHZ SOC_REFCLK_37_4_MHZ +#define A_REFCLK_38_4_MHZ SOC_REFCLK_38_4_MHZ +#define A_REFCLK_40_MHZ SOC_REFCLK_40_MHZ +#define A_REFCLK_52_MHZ SOC_REFCLK_52_MHZ + +#define TARGET_CPU_FREQ 176000000 + +struct wlan_pll_s { + uint32_t refdiv; + uint32_t div; + uint32_t rnfrac; + uint32_t outdiv; +}; + +struct cmnos_clock_s { + A_refclk_speed_t refclk_speed; + uint32_t refclk_hz; + uint32_t pll_settling_time; /* 50us */ + struct wlan_pll_s wlan_pll; +}; + +typedef struct TGT_REG_SECTION { + uint32_t start_addr; + uint32_t end_addr; +} tgt_reg_section; + + +typedef struct TGT_REG_TABLE { + tgt_reg_section *section; + uint32_t section_size; +} tgt_reg_table; +#endif /* _REGTABLE_SDIO_H_ */ diff --git a/drivers/staging/qca-wifi-host-cmn/hif/src/snoc/hif_io32_snoc.h b/drivers/staging/qca-wifi-host-cmn/hif/src/snoc/hif_io32_snoc.h new file mode 100644 index 0000000000000000000000000000000000000000..417e01eb2176afb22f5dcede95c344c0e7b39cc0 --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/hif/src/snoc/hif_io32_snoc.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2015-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: hif_io32_snoc.h + * + * snoc specific implementations and configurations + */ + +#ifndef __HIF_IO32_SNOC_H__ +#define __HIF_IO32_SNOC_H__ + +#include "hif.h" +#include "regtable.h" +#include "ce_reg.h" +#include "qdf_atomic.h" +#include "hif_main.h" +#include "hif_debug.h" + +static inline void ce_enable_irq_in_individual_register(struct hif_softc *scn, + int ce_id) +{ + uint32_t offset; + offset = HOST_IE_ADDRESS + CE_BASE_ADDRESS(ce_id); + hif_write32_mb(scn->mem + offset, 1); +} + +static inline void ce_disable_irq_in_individual_register(struct hif_softc *scn, + int ce_id) +{ + uint32_t offset; + offset = HOST_IE_ADDRESS + CE_BASE_ADDRESS(ce_id); + hif_write32_mb(scn->mem + offset, 0); + hif_read32_mb(scn->mem + offset); +} +#endif diff --git a/drivers/staging/qca-wifi-host-cmn/hif/src/snoc/if_ahb.c b/drivers/staging/qca-wifi-host-cmn/hif/src/snoc/if_ahb.c new file mode 100644 index 0000000000000000000000000000000000000000..6f986fd14bbe59a172949bf3eb8bff4edcc840b0 --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/hif/src/snoc/if_ahb.c @@ -0,0 +1,424 @@ +/* + * Copyright (c) 2013-2016 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. + */ + +/** + * DOC: if_ahb.c + * + * c file for ahb specific implementations. + */ + +#include "hif.h" +#include "hif_main.h" +#include "hif_debug.h" +#include "hif_io32.h" +#include "ce_main.h" +#include "ce_tasklet.h" +#include "if_ahb.h" +#include "if_pci.h" +#include "ahb_api.h" +#include "pci_api.h" + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0) +#define IRQF_DISABLED 0x00000020 +#endif +/** + * hif_disable_isr() - disable isr + * + * This function disables isr and kills tasklets + * + * @hif_ctx: struct hif_softc + * + * Return: void + */ +void hif_ahb_disable_isr(struct hif_softc *scn) +{ + struct hif_pci_softc *sc = HIF_GET_PCI_SOFTC(scn); + + hif_nointrs(scn); + ce_tasklet_kill(scn); + tasklet_kill(&sc->intr_tq); + qdf_atomic_set(&scn->active_tasklet_cnt, 0); +} + +/** + * hif_dump_registers() - dump bus debug registers + * @scn: struct hif_opaque_softc + * + * This function dumps hif bus debug registers + * + * Return: 0 for success or error code + */ +int hif_ahb_dump_registers(struct hif_softc *hif_ctx) +{ + int status; + struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx); + + status = hif_dump_ce_registers(scn); + if (status) + HIF_ERROR("%s: Dump CE Registers Failed status %d", __func__, + status); + + return 0; +} + +/** + * hif_ahb_close() - hif_bus_close + * @scn: pointer to the hif context. + * + * This is a callback function for hif_bus_close. + * + * + * Return: n/a + */ +void hif_ahb_close(struct hif_softc *scn) +{ + hif_ce_close(scn); +} + +/** + * hif_bus_open() - hif_ahb open + * @hif_ctx: hif context + * @bus_type: bus type + * + * This is a callback function for hif_bus_open. + * + * Return: n/a + */ +QDF_STATUS hif_ahb_open(struct hif_softc *hif_ctx, enum qdf_bus_type bus_type) +{ + + struct hif_pci_softc *sc = HIF_GET_PCI_SOFTC(hif_ctx); + + qdf_spinlock_create(&sc->irq_lock); + return hif_ce_open(hif_ctx); +} + +/** + * hif_bus_configure() - Configure the bus + * @scn: pointer to the hif context. + * + * This function configure the ahb bus + * + * return: 0 for success. nonzero for failure. + */ +int hif_ahb_bus_configure(struct hif_softc *scn) +{ + return hif_pci_bus_configure(scn); +} + +/** + * hif_configure_msi_ahb - Configure MSI interrupts + * @sc : pointer to the hif context + * + * return: 0 for success. nonzero for failure. + */ + +int hif_configure_msi_ahb(struct hif_pci_softc *sc) +{ + return 0; +} + +/** + * hif_ahb_configure_legacy_irq() - Configure Legacy IRQ + * @sc: pointer to the hif context. + * + * This function registers the irq handler and enables legacy interrupts + * + * return: 0 for success. nonzero for failure. + */ +int hif_ahb_configure_legacy_irq(struct hif_pci_softc *sc) +{ + int ret = 0; + struct hif_softc *scn = HIF_GET_SOFTC(sc); + struct platform_device *pdev = (struct platform_device *)sc->pdev; + int irq = 0; + + /* do not support MSI or MSI IRQ failed */ + tasklet_init(&sc->intr_tq, wlan_tasklet, (unsigned long)sc); + irq = platform_get_irq_byname(pdev, "legacy"); + if (irq < 0) { + dev_err(&pdev->dev, "Unable to get irq\n"); + ret = -1; + goto end; + } + ret = request_irq(irq, hif_pci_interrupt_handler, + IRQF_DISABLED, "wlan_ahb", sc); + if (ret) { + dev_err(&pdev->dev, "ath_request_irq failed\n"); + ret = -1; + goto end; + } + sc->irq = irq; + + /* Use Legacy PCI Interrupts */ + hif_write32_mb(sc->mem+(SOC_CORE_BASE_ADDRESS | + PCIE_INTR_ENABLE_ADDRESS), + PCIE_INTR_FIRMWARE_MASK | PCIE_INTR_CE_MASK_ALL); + /* read once to flush */ + hif_read32_mb(sc->mem+(SOC_CORE_BASE_ADDRESS | + PCIE_INTR_ENABLE_ADDRESS) + ); + +end: + return ret; +} + +/** + * hif_target_sync() : ensure the target is ready + * @scn: hif control structure + * + * Informs fw that we plan to use legacy interupts so that + * it can begin booting. Ensures that the fw finishes booting + * before continuing. Should be called before trying to write + * to the targets other registers for the first time. + * + * Return: none + */ +int hif_target_sync_ahb(struct hif_softc *scn) +{ + hif_write32_mb(scn->mem + FW_INDICATOR_ADDRESS, FW_IND_HOST_READY); + if (HAS_FW_INDICATOR) { + int wait_limit = 500; + int fw_ind = 0; + + while (1) { + fw_ind = hif_read32_mb(scn->mem + + FW_INDICATOR_ADDRESS); + if (fw_ind & FW_IND_INITIALIZED) + break; + if (wait_limit-- < 0) + break; + hif_write32_mb(scn->mem+(SOC_CORE_BASE_ADDRESS | + PCIE_INTR_ENABLE_ADDRESS), + PCIE_INTR_FIRMWARE_MASK); + qdf_mdelay(10); + } + if (wait_limit < 0) { + HIF_TRACE("%s: FW signal timed out", __func__); + return -EIO; + } else { + HIF_TRACE("%s: Got FW signal, retries = %x", __func__, + 500-wait_limit); + } + } + + return 0; +} + +/** + * hif_disable_bus() - Disable the bus + * @scn : pointer to the hif context + * + * This function disables the bus and helds the target in reset state + * + * Return: none + */ +void hif_ahb_disable_bus(struct hif_softc *scn) +{ + struct hif_pci_softc *sc = HIF_GET_PCI_SOFTC(scn); + void __iomem *mem; + struct platform_device *pdev = (struct platform_device *)sc->pdev; + struct resource *memres = NULL; + int mem_pa_size = 0; + + /*Disable WIFI clock input*/ + if (sc->mem) { + memres = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!memres) { + HIF_INFO("%s: Failed to get IORESOURCE_MEM\n", + __func__); + return; + } + mem_pa_size = memres->end - memres->start + 1; + + hif_ahb_clk_enable_disable(&pdev->dev, 0); + + hif_ahb_device_reset(scn); + mem = (void __iomem *)sc->mem; + if (mem) { + devm_iounmap(&pdev->dev, mem); + devm_release_mem_region(&pdev->dev, scn->mem_pa, + mem_pa_size); + sc->mem = NULL; + } + } + scn->mem = NULL; +} + +/** + * hif_enable_bus() - Enable the bus + * @dev: dev + * @bdev: bus dev + * @bid: bus id + * @type: bus type + * + * This function enables the radio bus by enabling necessary + * clocks and waits for the target to get ready to proceed futher + * + * Return: QDF_STATUS + */ +QDF_STATUS hif_ahb_enable_bus(struct hif_softc *ol_sc, + struct device *dev, void *bdev, + const hif_bus_id *bid, + enum hif_enable_type type) +{ + int ret = 0; + int hif_type; + int target_type; + const struct platform_device_id *id = (struct platform_device_id *)bid; + struct platform_device *pdev = bdev; + struct hif_target_info *tgt_info = NULL; + struct resource *memres = NULL; + void __iomem *mem = NULL; + uint32_t revision_id = 0; + struct hif_pci_softc *sc = HIF_GET_PCI_SOFTC(ol_sc); + + sc->pdev = (struct pci_dev *)pdev; + sc->dev = &pdev->dev; + sc->devid = id->driver_data; + + ret = hif_get_device_type(id->driver_data, revision_id, + &hif_type, &target_type); + if (ret < 0) { + HIF_ERROR("%s: invalid device ret %d id %d revision_id %d", + __func__, ret, (int)id->driver_data, revision_id); + return QDF_STATUS_E_FAILURE; + } + + memres = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!memres) { + HIF_INFO("%s: Failed to get IORESOURCE_MEM\n", __func__); + return -EIO; + } + + ret = dma_set_mask(dev, DMA_BIT_MASK(32)); + if (ret) { + HIF_INFO("ath: 32-bit DMA not available\n"); + goto err_cleanup1; + } + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0) + ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32)); +#else + ret = dma_set_coherent_mask(dev, DMA_BIT_MASK(32)); +#endif + if (ret) { + HIF_ERROR("%s: failed to set dma mask error = %d", + __func__, ret); + return ret; + } + + /* Arrange for access to Target SoC registers. */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0) + mem = devm_ioremap_resource(&pdev->dev, memres); +#else + mem = devm_request_and_ioremap(&pdev->dev, memres); +#endif + if (IS_ERR(mem)) { + HIF_INFO("ath: ioremap error\n"); + ret = PTR_ERR(mem); + goto err_cleanup1; + } + + sc->mem = mem; + ol_sc->mem = mem; + ol_sc->mem_pa = memres->start; + + tgt_info = hif_get_target_info_handle((struct hif_opaque_softc *)ol_sc); + + tgt_info->target_type = target_type; + hif_register_tbl_attach(ol_sc, hif_type); + hif_target_register_tbl_attach(ol_sc, target_type); + + if (hif_ahb_enable_radio(sc, pdev, id) != 0) { + HIF_INFO("error in enabling soc\n"); + return -EIO; + } + + if (hif_target_sync_ahb(ol_sc) < 0) { + ret = -EIO; + goto err_target_sync; + } + HIF_TRACE("%s: X - hif_type = 0x%x, target_type = 0x%x", + __func__, hif_type, target_type); + + return QDF_STATUS_SUCCESS; +err_target_sync: + HIF_INFO("Error: Disabling target\n"); + hif_ahb_disable_bus(ol_sc); +err_cleanup1: + return ret; +} + + +/** + * hif_reset_soc() - reset soc + * + * @hif_ctx: HIF context + * + * This function resets soc and helds the + * target in reset state + * + * Return: void + */ +/* Function to reset SoC */ +void hif_ahb_reset_soc(struct hif_softc *hif_ctx) +{ + hif_ahb_device_reset(hif_ctx); +} + + +/** + * hif_nointrs() - disable IRQ + * + * @scn: struct hif_softc + * + * This function stops interrupt(s) + * + * Return: none + */ +void hif_ahb_nointrs(struct hif_softc *scn) +{ + hif_pci_nointrs(scn); +} + +/** + * ce_irq_enable() - enable copy engine IRQ + * @scn: struct hif_softc + * @ce_id: ce_id + * + * This function enables the interrupt for the radio. + * + * Return: N/A + */ +void hif_ahb_irq_enable(struct hif_softc *scn, int ce_id) +{ + hif_pci_irq_enable(scn, ce_id); +} + +/** + * ce_irq_disable() - disable copy engine IRQ + * @scn: struct hif_softc + * @ce_id: ce_id + * + * Return: N/A + */ +void hif_ahb_irq_disable(struct hif_softc *scn, int ce_id) +{ + +} diff --git a/drivers/staging/qca-wifi-host-cmn/hif/src/snoc/if_ahb.h b/drivers/staging/qca-wifi-host-cmn/hif/src/snoc/if_ahb.h new file mode 100644 index 0000000000000000000000000000000000000000..e420ecf4228ce6c9671188578740bf448676a18d --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/hif/src/snoc/if_ahb.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2013-2016 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. + */ + +/** + * DOC: if_ahb.h + * + * h file for ahb specific implementations. + */ + +#ifndef __IF_AHB_H +#define __IF_AHB_H + +#define GCC_BASE 0x1800000 +#define GCC_SIZE 0x60000 +#define GCC_FEPLL_PLL_DIV 0x2f020 +#define GCC_FEPLL_PLL_CLK_WIFI_0_SEL_MASK 0x00000300 +#define GCC_FEPLL_PLL_CLK_WIFI_0_SEL_SHIFT 8 +#define GCC_FEPLL_PLL_CLK_WIFI_1_SEL_MASK 0x00003000 +#define GCC_FEPLL_PLL_CLK_WIFI_1_SEL_SHIFT 12 + + +/* These registers are outsize Wifi space. */ +/* TBD: Should we add these offsets as device tree properties? */ +#define TCSR_BASE 0x1900000 +#define TCSR_SIZE 0x80000 +#define TCSR_WIFI0_GLB_CFG 0x49000 +#define TCSR_WIFI1_GLB_CFG 0x49004 +#define TCSR_WCSS0_HALTREQ 0x52000 +#define TCSR_WCSS1_HALTREQ 0x52004 +#define TCSR_WCSS0_HALTACK 0x52010 +#define TCSR_WCSS1_HALTACK 0x52014 +#define ATH_AHB_RESET_WAIT_MAX 10 /* Ms */ +#endif diff --git a/drivers/staging/qca-wifi-host-cmn/hif/src/snoc/if_ahb_reset.c b/drivers/staging/qca-wifi-host-cmn/hif/src/snoc/if_ahb_reset.c new file mode 100644 index 0000000000000000000000000000000000000000..b4848ef2732123500415d6d5cdbb492d0069a7d1 --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/hif/src/snoc/if_ahb_reset.c @@ -0,0 +1,389 @@ +/* + * Copyright (c) 2013-2016 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. + */ + +/** + * DOC: if_ahb_reset.c + * + * c file for ahb ipq4019 specific implementations. + */ + +#include "hif.h" +#include "hif_main.h" +#include "hif_debug.h" +#include "hif_io32.h" +#include "ce_main.h" +#include "ce_tasklet.h" +#include "ahb_api.h" +#include "if_ahb.h" + +#include +#include +#include +#include +#include +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0) +#include +#endif + +/** + * clk_enable_disable() - Enable/disable clock + * @dev : pointer to device structure + * @str : clock name + * @enable : should be true, if the clock needs to be enabled + * should be false, if the clock needs to be enabled + * + * This is a helper function for hif_ahb_clk_enable_disable to enable + * disable clocks. + * clk_prepare_enable will enable the clock + * clk_disable_unprepare will disable the clock + * + * Return: zero on success, non-zero incase of error. + */ + +static int clk_enable_disable(struct device *dev, const char *str, int enable) +{ + struct clk *clk_t = NULL; + int ret; + + clk_t = clk_get(dev, str); + if (IS_ERR(clk_t)) { + HIF_INFO("%s: Failed to get %s clk %ld\n", + __func__, str, PTR_ERR(clk_t)); + return -EFAULT; + } + if (true == enable) { + /* Prepare and Enable clk */ + ret = clk_prepare_enable(clk_t); + if (ret) { + HIF_INFO("%s: err enabling clk %s , error:%d\n", + __func__, str, ret); + return ret; + } + } else { + /* Disable and unprepare clk */ + clk_disable_unprepare(clk_t); + } + return 0; +} + + +/** + * hif_ahb_clk_enable_disable() - Enable/disable ahb clock + * @dev : pointer to device structure + * @enable : should be true, if the clock needs to be enabled + * should be false, if the clock needs to be enabled + * + * This functions helps to enable/disable all the necesasary clocks + * for bus access. + * + * Return: zero on success, non-zero incase of error + */ +int hif_ahb_clk_enable_disable(struct device *dev, int enable) +{ + int ret; + + ret = clk_enable_disable(dev, "wifi_wcss_cmd", enable); + if (ret) + return ret; + ret = clk_enable_disable(dev, "wifi_wcss_ref", enable); + if (ret) + return ret; + ret = clk_enable_disable(dev, "wifi_wcss_rtc", enable); + if (ret) + return ret; + return 0; +} + +/** + * hif_enable_radio() - Enable the target radio. + * @sc : pointer to the hif context + * + * This function helps to release the target from reset state + * + * Return : zero on success, non-zero incase of error. + */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0) +int hif_ahb_enable_radio(struct hif_pci_softc *sc, + struct platform_device *pdev, + const struct platform_device_id *id) +{ + struct reset_control *reset_ctl = NULL; + uint32_t msi_addr, msi_base, wifi_core_id; + struct hif_softc *scn = HIF_GET_SOFTC(sc); + struct device_node *dev_node = pdev->dev.of_node; + bool msienable = false; + int ret = 0; + + ret = of_property_read_u32(dev_node, "qca,msi_addr", &msi_addr); + if (ret) { + HIF_INFO("%s: Unable to get msi_addr - error:%d\n", + __func__, ret); + return -EIO; + } + ret = of_property_read_u32(dev_node, "qca,msi_base", &msi_base); + if (ret) { + HIF_INFO("%s: Unable to get msi_base - error:%d\n", + __func__, ret); + return -EIO; + } + ret = of_property_read_u32(dev_node, "core-id", &wifi_core_id); + if (ret) { + HIF_INFO("%s: Unable to get core-id - error:%d\n", + __func__, ret); + return -EIO; + } + + /* Program the above values into Wifi scratch regists */ + if (msienable) { + hif_write32_mb(sc->mem + FW_AXI_MSI_ADDR, msi_addr); + hif_write32_mb(sc->mem + FW_AXI_MSI_DATA, msi_base); + } + + /* TBD: Temporary changes. Frequency should be + retrieved through clk_xxx once kernel GCC driver is available */ + { + void __iomem *mem_gcc; + uint32_t clk_sel; + uint32_t gcc_fepll_pll_div; + uint32_t wifi_cpu_freq[4] = {266700000, 250000000, 222200000, + 200000000}; + uint32_t current_freq = 0; + + /* Enable WIFI clock input */ + if (scn->target_info.target_type == TARGET_TYPE_IPQ4019) { + ret = hif_ahb_clk_enable_disable(&pdev->dev, 1); + if (ret) { + HIF_INFO("%s:Error while enabling clock :%d\n", + __func__, ret); + return ret; + } + } + + mem_gcc = ioremap_nocache(GCC_BASE, GCC_SIZE); + if (IS_ERR(mem_gcc)) { + HIF_INFO("%s: GCC ioremap failed\n", __func__); + return PTR_ERR(mem_gcc); + } + gcc_fepll_pll_div = hif_read32_mb(mem_gcc + GCC_FEPLL_PLL_DIV); + clk_sel = (wifi_core_id == 0) ? ((gcc_fepll_pll_div & + GCC_FEPLL_PLL_CLK_WIFI_0_SEL_MASK) >> + GCC_FEPLL_PLL_CLK_WIFI_0_SEL_SHIFT) : + ((gcc_fepll_pll_div & GCC_FEPLL_PLL_CLK_WIFI_1_SEL_MASK) + >> GCC_FEPLL_PLL_CLK_WIFI_1_SEL_SHIFT); + current_freq = wifi_cpu_freq[clk_sel]; + + HIF_INFO("Wifi%d CPU frequency %u\n", wifi_core_id, + current_freq); + hif_write32_mb(sc->mem + FW_CPU_PLL_CONFIG, gcc_fepll_pll_div); + iounmap(mem_gcc); + } + + /* De-assert radio cold reset */ + reset_ctl = reset_control_get(&pdev->dev, "wifi_radio_cold"); + if (IS_ERR(reset_ctl)) { + HIF_INFO("%s: Failed to get radio cold reset control\n", + __func__); + ret = PTR_ERR(reset_ctl); + goto err_reset; + } + reset_control_deassert(reset_ctl); + reset_control_put(reset_ctl); + + /* De-assert radio warm reset */ + reset_ctl = reset_control_get(&pdev->dev, "wifi_radio_warm"); + if (IS_ERR(reset_ctl)) { + HIF_INFO("%s: Failed to get radio warm reset control\n", + __func__); + ret = PTR_ERR(reset_ctl); + goto err_reset; + } + reset_control_deassert(reset_ctl); + reset_control_put(reset_ctl); + + /* De-assert radio srif reset */ + reset_ctl = reset_control_get(&pdev->dev, "wifi_radio_srif"); + if (IS_ERR(reset_ctl)) { + HIF_INFO("%s: Failed to get radio srif reset control\n", + __func__); + ret = PTR_ERR(reset_ctl); + goto err_reset; + } + reset_control_deassert(reset_ctl); + reset_control_put(reset_ctl); + + /* De-assert target CPU reset */ + reset_ctl = reset_control_get(&pdev->dev, "wifi_cpu_init"); + if (IS_ERR(reset_ctl)) { + HIF_INFO("%s: Failed to get cpu init reset control", __func__); + ret = PTR_ERR(reset_ctl); + goto err_reset; + } + reset_control_deassert(reset_ctl); + reset_control_put(reset_ctl); + + return 0; + +err_reset: + return -EIO; +} +#else +int hif_ahb_enable_radio(struct hif_pci_softc *sc, + struct platform_device *pdev, + const struct platform_device_id *id) +{ + qdf_print("%s:%d:Reset routines not available in kernel version.\n", + __func__, __LINE__); + return -EIO; +} +#endif + +/* "wifi_core_warm" is the other reset type */ +#define AHB_RESET_TYPE "wifi_core_cold" + +/** + * hif_ahb_device_reset() - Disable the radio and held the radio is reset state. + * @scn : pointer to the hif context + * + * This function will hold the target in reset state. + * Will be called while unload the driver or any graceful unload path. + * + * Return : n/a. + */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0) +void hif_ahb_device_reset(struct hif_softc *scn) +{ + struct reset_control *resetctl = NULL; + struct reset_control *core_resetctl = NULL; + struct hif_pci_softc *sc = HIF_GET_PCI_SOFTC(scn); + struct platform_device *pdev = (struct platform_device *)(sc->pdev); + uint32_t glb_cfg_offset; + uint32_t haltreq_offset; + uint32_t haltack_offset; + void __iomem *mem_tcsr; + uint32_t wifi_core_id; + uint32_t reg_value; + int wait_limit = ATH_AHB_RESET_WAIT_MAX; + + + wifi_core_id = hif_read32_mb(sc->mem + WLAN_SUBSYSTEM_CORE_ID_ADDRESS); + glb_cfg_offset = (wifi_core_id == 0) ? TCSR_WIFI0_GLB_CFG : + TCSR_WIFI1_GLB_CFG; + haltreq_offset = (wifi_core_id == 0) ? TCSR_WCSS0_HALTREQ : + TCSR_WCSS1_HALTREQ; + haltack_offset = (wifi_core_id == 0) ? TCSR_WCSS0_HALTACK : + TCSR_WCSS1_HALTACK; + + mem_tcsr = ioremap_nocache(TCSR_BASE, TCSR_SIZE); + if (IS_ERR(mem_tcsr)) { + HIF_INFO("%s: TCSR ioremap failed\n", __func__); + return; + } + reg_value = hif_read32_mb(mem_tcsr + haltreq_offset); + hif_write32_mb(mem_tcsr + haltreq_offset, reg_value | 0x1); + /* Wait for halt ack before asserting reset */ + while (wait_limit) { + + if (hif_read32_mb(mem_tcsr + haltack_offset) & 0x1) + break; + + qdf_mdelay(1); + wait_limit--; + } + + reg_value = hif_read32_mb(mem_tcsr + glb_cfg_offset); + hif_write32_mb(mem_tcsr + glb_cfg_offset, reg_value | (1 << 25)); + + core_resetctl = reset_control_get(&pdev->dev, AHB_RESET_TYPE); + if (IS_ERR(core_resetctl)) { + HIF_INFO("Failed to get wifi core cold reset control\n"); + return; + } + + /* Reset wifi core */ + reset_control_assert(core_resetctl); + + /* TBD: Check if we should also assert other bits (radio_cold, radio_ + warm, radio_srif, cpu_ini) */ + qdf_mdelay(1); /* TBD: Get reqd delay from HW team */ + + /* Assert radio cold reset */ + resetctl = reset_control_get(&pdev->dev, "wifi_radio_cold"); + if (IS_ERR(resetctl)) { + HIF_INFO("%s: Failed to get radio cold reset control\n", + __func__); + return; + } + reset_control_assert(resetctl); + qdf_mdelay(1); /* TBD: Get reqd delay from HW team */ + reset_control_put(resetctl); + + /* Assert radio warm reset */ + resetctl = reset_control_get(&pdev->dev, "wifi_radio_warm"); + if (IS_ERR(resetctl)) { + HIF_INFO("%s: Failed to get radio warm reset control\n", + __func__); + return; + } + reset_control_assert(resetctl); + qdf_mdelay(1); /* TBD: Get reqd delay from HW team */ + reset_control_put(resetctl); + + /* Assert radio srif reset */ + resetctl = reset_control_get(&pdev->dev, "wifi_radio_srif"); + if (IS_ERR(resetctl)) { + HIF_INFO("%s: Failed to get radio srif reset control\n", + __func__); + return; + } + reset_control_assert(resetctl); + qdf_mdelay(1); /* TBD: Get reqd delay from HW team */ + reset_control_put(resetctl); + + /* Assert target CPU reset */ + resetctl = reset_control_get(&pdev->dev, "wifi_cpu_init"); + if (IS_ERR(resetctl)) { + HIF_INFO("%s: Failed to get cpu init reset control", __func__); + return; + } + reset_control_assert(resetctl); + qdf_mdelay(10); /* TBD: Get reqd delay from HW team */ + reset_control_put(resetctl); + + /* Clear gbl_cfg and haltreq before clearing Wifi core reset */ + reg_value = hif_read32_mb(mem_tcsr + haltreq_offset); + hif_write32_mb(mem_tcsr + haltreq_offset, reg_value & ~0x1); + reg_value = hif_read32_mb(mem_tcsr + glb_cfg_offset); + hif_write32_mb(mem_tcsr + glb_cfg_offset, reg_value & ~(1 << 25)); + + /* de-assert wifi core reset */ + reset_control_deassert(core_resetctl); + + qdf_mdelay(1); /* TBD: Get reqd delay from HW team */ + + /* TBD: Check if we should de-assert other bits here */ + reset_control_put(core_resetctl); + iounmap(mem_tcsr); + HIF_INFO("Reset complete for wifi core id : %d\n", wifi_core_id); +} +#else +void hif_ahb_device_reset(struct hif_softc *scn) +{ + qdf_print("%s:%d:Reset routines not available in kernel version.\n", + __func__, __LINE__); +} +#endif diff --git a/drivers/staging/qca-wifi-host-cmn/hif/src/snoc/if_snoc.c b/drivers/staging/qca-wifi-host-cmn/hif/src/snoc/if_snoc.c new file mode 100644 index 0000000000000000000000000000000000000000..3450ecfbfdb7bee453dd7972a6607151243c9f05 --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/hif/src/snoc/if_snoc.c @@ -0,0 +1,458 @@ +/* + * Copyright (c) 2015-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: if_snoc.c + * + * c file for snoc specif implementations. + */ + +#include "hif.h" +#include "hif_main.h" +#include "hif_debug.h" +#include "hif_io32.h" +#include "ce_main.h" +#include "ce_tasklet.h" +#include "snoc_api.h" +#include +#include "pld_common.h" +#include "qdf_util.h" +#ifdef IPA_OFFLOAD +#include +#endif + +/** + * hif_disable_isr(): disable isr + * + * This function disables isr and kills tasklets + * + * @hif_ctx: struct hif_softc + * + * Return: void + */ +void hif_snoc_disable_isr(struct hif_softc *scn) +{ + hif_nointrs(scn); + ce_tasklet_kill(scn); + qdf_atomic_set(&scn->active_tasklet_cnt, 0); +} + +/** + * hif_dump_registers(): dump bus debug registers + * @scn: struct hif_opaque_softc + * + * This function dumps hif bus debug registers + * + * Return: 0 for success or error code + */ +int hif_snoc_dump_registers(struct hif_softc *hif_ctx) +{ + int status; + struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx); + + status = hif_dump_ce_registers(scn); + if (status) + HIF_ERROR("%s: Dump CE Registers Failed", __func__); + + return 0; +} + +void hif_snoc_display_stats(struct hif_softc *hif_ctx) +{ + struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(hif_ctx); + + if (hif_state == NULL) { + HIF_ERROR("%s, hif_ctx null", __func__); + return; + } + hif_display_ce_stats(hif_state); +} + +void hif_snoc_clear_stats(struct hif_softc *hif_ctx) +{ + struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(hif_ctx); + + if (hif_state == NULL) { + HIF_ERROR("%s, hif_ctx null", __func__); + return; + } + hif_clear_ce_stats(hif_state); +} + +/** + * hif_snoc_close(): hif_bus_close + * + * Return: n/a + */ +void hif_snoc_close(struct hif_softc *scn) +{ + hif_ce_close(scn); +} + +/** + * hif_bus_open(): hif_bus_open + * @hif_ctx: hif context + * @bus_type: bus type + * + * Return: n/a + */ +QDF_STATUS hif_snoc_open(struct hif_softc *hif_ctx, enum qdf_bus_type bus_type) +{ + return hif_ce_open(hif_ctx); +} + +/** + * hif_snoc_get_soc_info() - populates scn with hw info + * + * fills in the virtual and physical base address as well as + * soc version info. + * + * return 0 or QDF_STATUS_E_FAILURE + */ +static QDF_STATUS hif_snoc_get_soc_info(struct hif_softc *scn) +{ + int ret; + struct pld_soc_info soc_info; + + qdf_mem_zero(&soc_info, sizeof(soc_info)); + + ret = pld_get_soc_info(scn->qdf_dev->dev, &soc_info); + if (ret < 0) { + HIF_ERROR("%s: pld_get_soc_info error = %d", __func__, ret); + return QDF_STATUS_E_FAILURE; + } + + scn->mem = soc_info.v_addr; + scn->mem_pa = soc_info.p_addr; + + scn->target_info.soc_version = soc_info.soc_id; + scn->target_info.target_version = soc_info.soc_id; + scn->target_info.target_revision = 0; + return QDF_STATUS_SUCCESS; +} + +/** + * hif_bus_configure() - configure the snoc bus + * @scn: pointer to the hif context. + * + * return: 0 for success. nonzero for failure. + */ +int hif_snoc_bus_configure(struct hif_softc *scn) +{ + int ret; + + ret = hif_snoc_get_soc_info(scn); + if (ret) + return ret; + + hif_ce_prepare_config(scn); + + ret = hif_wlan_enable(scn); + if (ret) { + HIF_ERROR("%s: hif_wlan_enable error = %d", + __func__, ret); + return ret; + } + + ret = hif_config_ce(scn); + if (ret) + hif_wlan_disable(scn); + return ret; +} + +/** + * hif_snoc_get_target_type(): Get the target type + * + * This function is used to query the target type. + * + * @ol_sc: hif_softc struct pointer + * @dev: device pointer + * @bdev: bus dev pointer + * @bid: bus id pointer + * @hif_type: HIF type such as HIF_TYPE_QCA6180 + * @target_type: target type such as TARGET_TYPE_QCA6180 + * + * Return: 0 for success + */ +static inline int hif_snoc_get_target_type(struct hif_softc *ol_sc, + struct device *dev, void *bdev, const hif_bus_id *bid, + uint32_t *hif_type, uint32_t *target_type) +{ + /* TODO: need to use HW version. Hard code for now */ +#ifdef QCA_WIFI_3_0_ADRASTEA + *hif_type = HIF_TYPE_ADRASTEA; + *target_type = TARGET_TYPE_ADRASTEA; +#else + *hif_type = 0; + *target_type = 0; +#endif + return 0; +} + +#ifdef IPA_OFFLOAD +static int hif_set_dma_coherent_mask(struct device *dev) +{ + uint8_t addr_bits; + + if (hif_get_ipa_hw_type() < IPA_HW_v3_0) + addr_bits = DMA_COHERENT_MASK_BELOW_IPA_VER_3; + else + addr_bits = DMA_COHERENT_MASK_IPA_VER_3_AND_ABOVE; + + return qdf_set_dma_coherent_mask(dev, addr_bits); +} +#else +static int hif_set_dma_coherent_mask(struct device *dev) +{ + return qdf_set_dma_coherent_mask(dev, 37); +} +#endif + +/** + * hif_enable_bus(): hif_enable_bus + * @dev: dev + * @bdev: bus dev + * @bid: bus id + * @type: bus type + * + * Return: QDF_STATUS + */ +QDF_STATUS hif_snoc_enable_bus(struct hif_softc *ol_sc, + struct device *dev, void *bdev, + const hif_bus_id *bid, + enum hif_enable_type type) +{ + int ret; + int hif_type; + int target_type; + + if (!ol_sc) { + HIF_ERROR("%s: hif_ctx is NULL", __func__); + return QDF_STATUS_E_NOMEM; + } + + ret = hif_set_dma_coherent_mask(dev); + if (ret) { + HIF_ERROR("%s: failed to set dma mask error = %d", + __func__, ret); + return ret; + } + + ret = qdf_device_init_wakeup(ol_sc->qdf_dev, true); + if (ret == -EEXIST) + HIF_WARN("%s: device_init_wakeup already done", + __func__); + else if (ret) { + HIF_ERROR("%s: device_init_wakeup: err= %d", + __func__, ret); + return ret; + } + + ret = hif_snoc_get_target_type(ol_sc, dev, bdev, bid, + &hif_type, &target_type); + if (ret < 0) { + HIF_ERROR("%s: invalid device id/revision_id", __func__); + return QDF_STATUS_E_FAILURE; + } + + ol_sc->target_info.target_type = target_type; + + hif_register_tbl_attach(ol_sc, hif_type); + hif_target_register_tbl_attach(ol_sc, target_type); + + /* the bus should remain on durring suspend for snoc */ + hif_vote_link_up(GET_HIF_OPAQUE_HDL(ol_sc)); + + HIF_TRACE("%s: X - hif_type = 0x%x, target_type = 0x%x", + __func__, hif_type, target_type); + + return QDF_STATUS_SUCCESS; +} + +/** + * hif_disable_bus(): hif_disable_bus + * + * This function disables the bus + * + * @bdev: bus dev + * + * Return: none + */ +void hif_snoc_disable_bus(struct hif_softc *scn) +{ + int ret; + + hif_vote_link_down(GET_HIF_OPAQUE_HDL(scn)); + + ret = qdf_device_init_wakeup(scn->qdf_dev, false); + if (ret) + HIF_ERROR("%s: device_init_wakeup: err %d", __func__, ret); +} + +/** + * hif_nointrs(): disable IRQ + * + * This function stops interrupt(s) + * + * @scn: struct hif_softc + * + * Return: none + */ +void hif_snoc_nointrs(struct hif_softc *scn) +{ + struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(scn); + if (scn->request_irq_done) { + ce_unregister_irq(hif_state, 0xfff); + scn->request_irq_done = false; + } +} + +/** + * ce_irq_enable() - enable copy engine IRQ + * @scn: struct hif_softc + * @ce_id: ce_id + * + * Return: N/A + */ +void hif_snoc_irq_enable(struct hif_softc *scn, + int ce_id) +{ + ce_enable_irq_in_individual_register(scn, ce_id); +} + +/** + * ce_irq_disable() - disable copy engine IRQ + * @scn: struct hif_softc + * @ce_id: ce_id + * + * Return: N/A + */ +void hif_snoc_irq_disable(struct hif_softc *scn, int ce_id) +{ + ce_disable_irq_in_individual_register(scn, ce_id); +} + +/* + * hif_snoc_setup_wakeup_sources() - enable/disable irq wake on correct irqs + * @hif_softc: hif context + * + * Firmware will send a wakeup request to the HTC_CTRL_RSVD_SVC when waking up + * the host driver. Ensure that the copy complete interrupt from this copy + * engine can wake up the apps processor. + * + * Return: 0 for success + */ +static +QDF_STATUS hif_snoc_setup_wakeup_sources(struct hif_softc *scn, bool enable) +{ + struct hif_opaque_softc *hif_hdl = GET_HIF_OPAQUE_HDL(scn); + uint8_t ul_pipe, dl_pipe; + int ul_is_polled, dl_is_polled; + int irq_to_wake_on; + + QDF_STATUS status; + int ret; + + status = hif_map_service_to_pipe(hif_hdl, HTC_CTRL_RSVD_SVC, + &ul_pipe, &dl_pipe, + &ul_is_polled, &dl_is_polled); + if (status) { + HIF_ERROR("%s: pipe_mapping failure", __func__); + return status; + } + + irq_to_wake_on = icnss_get_irq(dl_pipe); + if (irq_to_wake_on < 0) { + HIF_ERROR("%s: failed to map ce to irq", __func__); + return QDF_STATUS_E_RESOURCES; + } + + if (enable) + ret = enable_irq_wake(irq_to_wake_on); + else + ret = disable_irq_wake(irq_to_wake_on); + + if (ret) { + HIF_ERROR("%s: Fail to setup wake IRQ!", __func__); + return QDF_STATUS_E_RESOURCES; + } + + HIF_INFO("%s: expecting wake from ce %d, irq %d enable %d", + __func__, dl_pipe, irq_to_wake_on, enable); + return QDF_STATUS_SUCCESS; +} + +/** + * hif_snoc_bus_suspend() - prepare to suspend the bus + * @scn: hif context + * + * Setup wakeup interrupt configuration. + * Disable CE interrupts (wakeup interrupt will still wake apps) + * Drain tasklets. - make sure that we don't suspend while processing + * the wakeup message. + * + * Return: 0 on success. + */ +int hif_snoc_bus_suspend(struct hif_softc *scn) +{ + if (hif_snoc_setup_wakeup_sources(scn, true) != QDF_STATUS_SUCCESS) + return -EFAULT; + return 0; +} + +/** + * hif_snoc_bus_resume() - snoc bus resume function + * @scn: hif context + * + * Clear wakeup interrupt configuration. + * Reenable ce interrupts + * + * Return: 0 on success + */ +int hif_snoc_bus_resume(struct hif_softc *scn) +{ + if (hif_snoc_setup_wakeup_sources(scn, false) != QDF_STATUS_SUCCESS) + QDF_BUG(0); + + return 0; +} + +/** + * hif_snoc_bus_suspend_noirq() - ensure there are no pending transactions + * @scn: hif context + * + * Ensure that if we recieved the wakeup message before the irq + * was disabled that the message is pocessed before suspending. + * + * Return: -EBUSY if we fail to flush the tasklets. + */ +int hif_snoc_bus_suspend_noirq(struct hif_softc *scn) +{ + if (hif_drain_tasklets(scn) != 0) + return -EBUSY; + return 0; +} diff --git a/drivers/staging/qca-wifi-host-cmn/hif/src/usb/hif_usb.c b/drivers/staging/qca-wifi-host-cmn/hif/src/usb/hif_usb.c new file mode 100644 index 0000000000000000000000000000000000000000..c4035a12eef1a0a773be665cdb94175059604a70 --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/hif/src/usb/hif_usb.c @@ -0,0 +1,918 @@ +/* + * Copyright (c) 2013-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ +#include +#include +#include +#include +#include +#include +#include +#include "qdf_net_types.h" +#include +#include +#include +#define ATH_MODULE_NAME hif +#include + +#if defined(WLAN_DEBUG) || defined(DEBUG) +static ATH_DEBUG_MASK_DESCRIPTION g_hif_debug_description[] = { + {USB_HIF_DEBUG_CTRL_TRANS, "Control Transfers"}, + {USB_HIF_DEBUG_BULK_IN, "BULK In Transfers"}, + {USB_HIF_DEBUG_BULK_OUT, "BULK Out Transfers"}, + {USB_HIF_DEBUG_DUMP_DATA, "Dump data"}, + {USB_HIF_DEBUG_ENUM, "Enumeration"}, +}; + +ATH_DEBUG_INSTANTIATE_MODULE_VAR(hif, + "hif", + "USB Host Interface", + ATH_DEBUG_MASK_DEFAULTS | ATH_DEBUG_INFO | + USB_HIF_DEBUG_ENUM, + ATH_DEBUG_DESCRIPTION_COUNT + (g_hif_debug_description), + g_hif_debug_description); + +#endif + +#ifdef USB_ISOC_SUPPORT +unsigned int hif_usb_isoch_vo = 1; +#else +unsigned int hif_usb_isoch_vo; +#endif +unsigned int hif_usb_disable_rxdata2 = 1; + +/** + * usb_hif_usb_transmit_complete() - completion routing for tx urb's + * @urb: pointer to urb for which tx completion is called + * + * Return: none + */ +static void usb_hif_usb_transmit_complete(struct urb *urb) +{ + HIF_URB_CONTEXT *urb_context = (HIF_URB_CONTEXT *) urb->context; + qdf_nbuf_t buf; + HIF_USB_PIPE *pipe = urb_context->pipe; + struct hif_usb_send_context *send_context; + + HIF_DBG("+%s: pipe: %d, stat:%d, len:%d", __func__, + pipe->logical_pipe_num, urb->status, urb->actual_length); + + /* this urb is not pending anymore */ + usb_hif_remove_pending_transfer(urb_context); + + if (urb->status != 0) { + HIF_ERROR("%s: pipe: %d, failed:%d", + __func__, pipe->logical_pipe_num, urb->status); + } + + buf = urb_context->buf; + send_context = urb_context->send_context; + + if (send_context->new_alloc) + qdf_mem_free(send_context); + else + qdf_nbuf_pull_head(buf, send_context->head_data_len); + + urb_context->buf = NULL; + usb_hif_cleanup_transmit_urb(urb_context); + + /* note: queue implements a lock */ + skb_queue_tail(&pipe->io_comp_queue, buf); + HIF_USB_SCHEDULE_WORK(pipe) + + HIF_DBG("-%s", __func__); +} + +/** + * hif_send_internal() - HIF internal routine to prepare and submit tx urbs + * @hif_usb_device: pointer to HIF_DEVICE_USB structure + * @pipe_id: HIF pipe on which data is to be sent + * @hdr_buf: any header buf to be prepended, currently ignored + * @buf: qdf_nbuf_t containing data to be transmitted + * @nbytes: number of bytes to be transmitted + * + * Return: QDF_STATUS_SUCCESS on success and error QDF status on failure + */ +static QDF_STATUS hif_send_internal(HIF_DEVICE_USB *hif_usb_device, + uint8_t pipe_id, + qdf_nbuf_t hdr_buf, + qdf_nbuf_t buf, unsigned int nbytes) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + HIF_DEVICE_USB *device = hif_usb_device; + HIF_USB_PIPE *pipe = &device->pipes[pipe_id]; + HIF_URB_CONTEXT *urb_context; + uint8_t *data; + uint32_t len; + struct urb *urb; + int usb_status; + int i; + struct hif_usb_send_context *send_context; + int frag_count = 0, head_data_len, tmp_frag_count = 0; + unsigned char *data_ptr; + + HIF_DBG("+%s pipe : %d, buf:0x%p nbytes %u", + __func__, pipe_id, buf, nbytes); + + frag_count = qdf_nbuf_get_num_frags(buf); + if (frag_count > 1) { /* means have extra fragment buf in skb */ + /* header data length should be total sending length substract + * internal data length of netbuf + * | hif_usb_send_context | fragments except internal buffer | + * netbuf->data + */ + head_data_len = sizeof(struct hif_usb_send_context); + while (tmp_frag_count < (frag_count - 1)) { + head_data_len = + head_data_len + + qdf_nbuf_get_frag_len(buf, tmp_frag_count); + tmp_frag_count = tmp_frag_count + 1; + } + } else { + /* + * | hif_usb_send_context | netbuf->data + */ + head_data_len = sizeof(struct hif_usb_send_context); + } + + /* Check whether head room is enough to save extra head data */ + if (head_data_len <= qdf_nbuf_headroom(buf)) { + send_context = (struct hif_usb_send_context *) + qdf_nbuf_push_head(buf, head_data_len); + send_context->new_alloc = false; + } else { + send_context = + qdf_mem_malloc(sizeof(struct hif_usb_send_context) + + head_data_len + nbytes); + if (send_context == NULL) { + HIF_ERROR("%s: qdf_mem_malloc failed", __func__); + status = QDF_STATUS_E_NOMEM; + goto err; + } + send_context->new_alloc = true; + } + send_context->netbuf = buf; + send_context->hif_usb_device = hif_usb_device; + send_context->transfer_id = pipe_id; + send_context->head_data_len = head_data_len; + /* + * Copy data to head part of netbuf or head of allocated buffer. + * if buffer is new allocated, the last buffer should be copied also. + * It assume last fragment is internal buffer of netbuf + * sometime total length of fragments larger than nbytes + */ + data_ptr = (unsigned char *)send_context + + sizeof(struct hif_usb_send_context); + for (i = 0; + i < (send_context->new_alloc ? frag_count : frag_count - 1); i++) { + int frag_len = qdf_nbuf_get_frag_len(buf, i); + unsigned char *frag_addr = qdf_nbuf_get_frag_vaddr(buf, i); + qdf_mem_copy(data_ptr, frag_addr, frag_len); + data_ptr += frag_len; + } + /* Reset pData pointer and send out */ + data_ptr = (unsigned char *)send_context + + sizeof(struct hif_usb_send_context); + + urb_context = usb_hif_alloc_urb_from_pipe(pipe); + if (NULL == urb_context) { + /* TODO : note, it is possible to run out of urbs if 2 + * endpoints map to the same pipe ID + */ + HIF_ERROR("%s pipe:%d no urbs left. URB Cnt : %d", + __func__, pipe_id, pipe->urb_cnt); + status = QDF_STATUS_E_RESOURCES; + goto err; + } + urb_context->send_context = send_context; + urb = urb_context->urb; + urb_context->buf = buf; + data = data_ptr; + len = nbytes; + + usb_fill_bulk_urb(urb, + device->udev, + pipe->usb_pipe_handle, + data, + (len % pipe->max_packet_size) == + 0 ? (len + 1) : len, + usb_hif_usb_transmit_complete, urb_context); + + if ((len % pipe->max_packet_size) == 0) + /* hit a max packet boundary on this pipe */ + + HIF_DBG + ("athusb bulk send submit:%d, 0x%X (ep:0x%2.2X), %d bytes", + pipe->logical_pipe_num, pipe->usb_pipe_handle, + pipe->ep_address, nbytes); + + usb_hif_enqueue_pending_transfer(pipe, urb_context); + usb_status = usb_submit_urb(urb, GFP_ATOMIC); + if (usb_status) { + if (send_context->new_alloc) + qdf_mem_free(send_context); + else + qdf_nbuf_pull_head(buf, head_data_len); + urb_context->buf = NULL; + HIF_ERROR("athusb : usb bulk transmit failed %d", + usb_status); + usb_hif_remove_pending_transfer(urb_context); + usb_hif_cleanup_transmit_urb(urb_context); + status = QDF_STATUS_E_FAILURE; + goto err; + } + +err: + if (!QDF_IS_STATUS_SUCCESS(status) && + (status != QDF_STATUS_E_RESOURCES)) { + HIF_ERROR("athusb send failed %d", status); + } + + HIF_DBG("-%s pipe : %d", __func__, pipe_id); + + return status; +} + +/** + * hif_send_head() - HIF routine exposed to upper layers to send data + * @scn: pointer to hif_opaque_softc structure + * @pipe_id: HIF pipe on which data is to be sent + * @transfer_id: endpoint ID on which data is to be sent + * @nbytes: number of bytes to be transmitted + * @wbuf: qdf_nbuf_t containing data to be transmitted + * @hdr_buf: any header buf to be prepended, currently ignored + * @data_attr: data_attr field from cvg_nbuf_cb of wbuf + * + * Return: QDF_STATUS_SUCCESS on success and error QDF status on failure + */ +QDF_STATUS hif_send_head(struct hif_opaque_softc *scn, uint8_t pipe_id, + uint32_t transfer_id, uint32_t nbytes, + qdf_nbuf_t wbuf, uint32_t data_attr) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + HIF_DEVICE_USB *device = HIF_GET_USB_DEVICE(scn); + HIF_TRACE("+%s", __func__); + status = hif_send_internal(device, pipe_id, NULL, wbuf, nbytes); + HIF_TRACE("-%s", __func__); + return status; +} + +/** + * hif_get_free_queue_number() - get # of free TX resources in a given HIF pipe + * @scn: pointer to hif_opaque_softc structure + * @pipe_id: HIF pipe which is being polled for free resources + * + * Return: # of free resources in pipe_id + */ +uint16_t hif_get_free_queue_number(struct hif_opaque_softc *scn, uint8_t pipe_id) +{ + HIF_DEVICE_USB *device = HIF_GET_USB_DEVICE(scn); + + return device->pipes[pipe_id].urb_cnt; +} + +/** + * hif_post_init() - copy HTC callbacks to HIF + * @scn: pointer to hif_opaque_softc structure + * @target: pointer to HTC_TARGET structure + * @callbacks: htc callbacks + * + * Return: none + */ +void hif_post_init(struct hif_opaque_softc *scn, void *target, + struct hif_msg_callbacks *callbacks) +{ + HIF_DEVICE_USB *device = HIF_GET_USB_DEVICE(scn); + + qdf_mem_copy(&device->htc_callbacks, callbacks, + sizeof(device->htc_callbacks)); +} + +/** + * hif_detach_htc() - remove HTC callbacks from HIF + * @scn: pointer to hif_opaque_softc structure + * + * Return: none + */ +void hif_detach_htc(struct hif_opaque_softc *scn) +{ + HIF_DEVICE_USB *device = HIF_GET_USB_DEVICE(scn); + usb_hif_flush_all(device); + qdf_mem_zero(&device->htc_callbacks, sizeof(device->htc_callbacks)); +} + +/** + * hif_usb_device_deinit() - de- init HIF_DEVICE_USB, cleanup pipe resources + * @sc: pointer to hif_usb_softc structure + * + * Return: None + */ +void hif_usb_device_deinit(struct hif_usb_softc *sc) +{ + HIF_DEVICE_USB *device = &sc->hif_hdl; + + HIF_TRACE("+%s", __func__); + + usb_hif_cleanup_pipe_resources(device); + + usb_set_intfdata(device->interface, NULL); + + if (device->diag_cmd_buffer != NULL) + qdf_mem_free(device->diag_cmd_buffer); + + if (device->diag_resp_buffer != NULL) + qdf_mem_free(device->diag_resp_buffer); + + HIF_TRACE("-%s", __func__); +} + +/** + * hif_usb_device_init() - init HIF_DEVICE_USB, setup pipe resources + * @sc: pointer to hif_usb_softc structure + * + * Return: QDF_STATUS_SUCCESS on success or a QDF error + */ +QDF_STATUS hif_usb_device_init(struct hif_usb_softc *sc) +{ + int i; + HIF_DEVICE_USB *device = &sc->hif_hdl; + struct usb_interface *interface = sc->interface; + struct usb_device *dev = interface_to_usbdev(interface); + QDF_STATUS status = QDF_STATUS_SUCCESS; + HIF_USB_PIPE *pipe; + + HIF_TRACE("+%s", __func__); + + do { + + usb_set_intfdata(interface, device); + qdf_spinlock_create(&(device->cs_lock)); + qdf_spinlock_create(&(device->rx_lock)); + qdf_spinlock_create(&(device->tx_lock)); + device->udev = dev; + device->interface = interface; + + HIF_ERROR("%s device %p device->udev %p device->interface %p", + __func__, + device, + device->udev, + device->interface); + + for (i = 0; i < HIF_USB_PIPE_MAX; i++) { + pipe = &device->pipes[i]; + + HIF_USB_INIT_WORK(pipe); + skb_queue_head_init(&pipe->io_comp_queue); + } + + device->diag_cmd_buffer = + qdf_mem_malloc(USB_CTRL_MAX_DIAG_CMD_SIZE); + if (NULL == device->diag_cmd_buffer) { + status = QDF_STATUS_E_NOMEM; + break; + } + device->diag_resp_buffer = + qdf_mem_malloc(USB_CTRL_MAX_DIAG_RESP_SIZE); + if (NULL == device->diag_resp_buffer) { + status = QDF_STATUS_E_NOMEM; + break; + } + + status = usb_hif_setup_pipe_resources(device); + + } while (false); + + if (status != QDF_STATUS_SUCCESS) + HIF_ERROR("%s: abnormal condition", __func__); + + HIF_TRACE("+%s", __func__); + return status; +} + +/** + * hif_start() - Enable HIF TX and RX + * @scn: pointer to hif_opaque_softc structure + * + * Return: QDF_STATUS_SUCCESS if success else an appropriate QDF_STATUS error + */ +QDF_STATUS hif_start(struct hif_opaque_softc *scn) +{ + HIF_DEVICE_USB *device = HIF_GET_USB_DEVICE(scn); + int i; + + HIF_TRACE("+%s", __func__); + usb_hif_prestart_recv_pipes(device); + + /* set the TX resource avail threshold for each TX pipe */ + for (i = HIF_TX_CTRL_PIPE; i <= HIF_TX_DATA_HP_PIPE; i++) { + device->pipes[i].urb_cnt_thresh = + device->pipes[i].urb_alloc / 2; + } + + HIF_TRACE("-%s", __func__); + return QDF_STATUS_SUCCESS; +} + +/** + * hif_usb_stop_device() - Stop/flush all HIF communication + * @scn: pointer to hif_opaque_softc structure + * + * Return: none + */ +void hif_usb_stop_device(struct hif_softc *hif_sc) +{ + HIF_DEVICE_USB *device = HIF_GET_USB_DEVICE(hif_sc); + + HIF_TRACE("+%s", __func__); + + usb_hif_flush_all(device); + + HIF_TRACE("-%s", __func__); +} + +/** + * hif_get_default_pipe() - get default pipes for HIF TX/RX + * @scn: pointer to hif_opaque_softc structure + * @ul_pipe: pointer to TX pipe + * @ul_pipe: pointer to TX pipe + * + * Return: none + */ +void hif_get_default_pipe(struct hif_opaque_softc *scn, uint8_t *ul_pipe, + uint8_t *dl_pipe) +{ + *ul_pipe = HIF_TX_CTRL_PIPE; + *dl_pipe = HIF_RX_CTRL_PIPE; +} + +#if defined(USB_MULTI_IN_TEST) || defined(USB_ISOC_TEST) +/** + * hif_map_service_to_pipe() - maps ul/dl pipe to service id. + * @scn: HIF context + * @svc_id: sevice index + * @ul_pipe: pointer to uplink pipe id + * @dl_pipe: pointer to down-linklink pipe id + * @ul_is_polled: if ul is polling based + * @ul_is_polled: if dl is polling based + * + * Return: QDF_STATUS_SUCCESS if success else an appropriate QDF_STATUS error + */ +int hif_map_service_to_pipe(struct hif_opaque_softc *scn, uint16_t svc_id, + uint8_t *ul_pipe, uint8_t *dl_pipe, + int *ul_is_polled, int *dl_is_polled) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + + switch (svc_id) { + case HTC_CTRL_RSVD_SVC: + case WMI_CONTROL_SVC: + case HTC_RAW_STREAMS_SVC: + *ul_pipe = HIF_TX_CTRL_PIPE; + *dl_pipe = HIF_RX_DATA_PIPE; + break; + case WMI_DATA_BE_SVC: + *ul_pipe = HIF_TX_DATA_LP_PIPE; + *dl_pipe = HIF_RX_DATA_PIPE; + break; + case WMI_DATA_BK_SVC: + *ul_pipe = HIF_TX_DATA_MP_PIPE; + *dl_pipe = HIF_RX_DATA2_PIPE; + break; + case WMI_DATA_VI_SVC: + *ul_pipe = HIF_TX_DATA_HP_PIPE; + *dl_pipe = HIF_RX_DATA_PIPE; + break; + case WMI_DATA_VO_SVC: + *ul_pipe = HIF_TX_DATA_LP_PIPE; + *dl_pipe = HIF_RX_DATA_PIPE; + break; + default: + status = QDF_STATUS_E_FAILURE; + break; + } + + return status; +} +#else + +#ifdef QCA_TX_HTT2_SUPPORT +#define USB_TX_CHECK_HTT2_SUPPORT 1 +#else +#define USB_TX_CHECK_HTT2_SUPPORT 0 +#endif + +/** + * hif_map_service_to_pipe() - maps ul/dl pipe to service id. + * @scn: HIF context + * @svc_id: sevice index + * @ul_pipe: pointer to uplink pipe id + * @dl_pipe: pointer to down-linklink pipe id + * @ul_is_polled: if ul is polling based + * @ul_is_polled: if dl is polling based + * + * Return: QDF_STATUS_SUCCESS if success else an appropriate QDF_STATUS error + */ +int hif_map_service_to_pipe(struct hif_opaque_softc *scn, uint16_t svc_id, + uint8_t *ul_pipe, uint8_t *dl_pipe, + int *ul_is_polled, int *dl_is_polled) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + + switch (svc_id) { + case HTC_CTRL_RSVD_SVC: + case WMI_CONTROL_SVC: + *ul_pipe = HIF_TX_CTRL_PIPE; + *dl_pipe = HIF_RX_DATA_PIPE; + break; + case WMI_DATA_BE_SVC: + case WMI_DATA_BK_SVC: + *ul_pipe = HIF_TX_DATA_LP_PIPE; + if (hif_usb_disable_rxdata2) + *dl_pipe = HIF_RX_DATA_PIPE; + else + *dl_pipe = HIF_RX_DATA2_PIPE; + break; + case WMI_DATA_VI_SVC: + *ul_pipe = HIF_TX_DATA_MP_PIPE; + if (hif_usb_disable_rxdata2) + *dl_pipe = HIF_RX_DATA_PIPE; + else + *dl_pipe = HIF_RX_DATA2_PIPE; + break; + case WMI_DATA_VO_SVC: + *ul_pipe = HIF_TX_DATA_HP_PIPE; + if (hif_usb_disable_rxdata2) + *dl_pipe = HIF_RX_DATA_PIPE; + else + *dl_pipe = HIF_RX_DATA2_PIPE; + break; + case HTC_RAW_STREAMS_SVC: + *ul_pipe = HIF_TX_CTRL_PIPE; + *dl_pipe = HIF_RX_DATA_PIPE; + break; + case HTT_DATA_MSG_SVC: + *ul_pipe = HIF_TX_DATA_LP_PIPE; + if (hif_usb_disable_rxdata2) + *dl_pipe = HIF_RX_DATA_PIPE; + else + *dl_pipe = HIF_RX_DATA2_PIPE; + break; + case HTT_DATA2_MSG_SVC: + if (USB_TX_CHECK_HTT2_SUPPORT) { + *ul_pipe = HIF_TX_DATA_HP_PIPE; + if (hif_usb_disable_rxdata2) + *dl_pipe = HIF_RX_DATA_PIPE; + else + *dl_pipe = HIF_RX_DATA2_PIPE; + } + break; + default: + status = QDF_STATUS_E_FAILURE; + break; + } + + return status; +} +#endif + +/** + * hif_ctrl_msg_exchange() - send usb ctrl message and receive response + * @macp: pointer to HIF_DEVICE_USB + * @send_req_val: USB send message request value + * @send_msg: pointer to data to send + * @len: length in bytes of the data to send + * @response_req_val: USB response message request value + * @response_msg: pointer to response msg + * @response_len: length of the response message + * + * Return: QDF_STATUS_SUCCESS if success else an appropriate QDF_STATUS error + */ +static QDF_STATUS hif_ctrl_msg_exchange(HIF_DEVICE_USB *macp, + uint8_t send_req_val, + uint8_t *send_msg, + uint32_t len, + uint8_t response_req_val, + uint8_t *response_msg, + uint32_t *response_len) +{ + QDF_STATUS status; + + do { + + /* send command */ + status = usb_hif_submit_ctrl_out(macp, send_req_val, 0, 0, + send_msg, len); + + if (!QDF_IS_STATUS_SUCCESS(status)) + break; + + if (NULL == response_msg) { + /* no expected response */ + break; + } + + /* get response */ + status = usb_hif_submit_ctrl_in(macp, response_req_val, 0, 0, + response_msg, *response_len); + + if (!QDF_IS_STATUS_SUCCESS(status)) + break; + + } while (false); + + return status; +} + +/** + * hif_exchange_bmi_msg() - send/recev ctrl message of type BMI_CMD/BMI_RESP + * @scn: pointer to hif_opaque_softc + * @bmi_request: pointer to data to send + * @request_length: length in bytes of the data to send + * @bmi_response: pointer to response msg + * @bmi_response_length: length of the response message + * @timeout_ms: timeout to wait for response (ignored in current implementation) + * + * Return: QDF_STATUS_SUCCESS if success else an appropriate QDF_STATUS error + */ + +QDF_STATUS hif_exchange_bmi_msg(struct hif_opaque_softc *scn, + qdf_dma_addr_t cmd, qdf_dma_addr_t rsp, + uint8_t *bmi_request, + uint32_t request_length, + uint8_t *bmi_response, + uint32_t *bmi_response_lengthp, + uint32_t timeout_ms) +{ + HIF_DEVICE_USB *macp = HIF_GET_USB_DEVICE(scn); + + return hif_ctrl_msg_exchange(macp, + USB_CONTROL_REQ_SEND_BMI_CMD, + bmi_request, + request_length, + USB_CONTROL_REQ_RECV_BMI_RESP, + bmi_response, bmi_response_lengthp); +} + +/** + * hif_diag_read_access() - Read data from target memory or register + * @scn: pointer to hif_opaque_softc + * @address: register address to read from + * @data: pointer to buffer to store the value read from the register + * + * Return: QDF_STATUS_SUCCESS if success else an appropriate QDF_STATUS error + */ +QDF_STATUS hif_diag_read_access(struct hif_opaque_softc *scn, uint32_t address, + uint32_t *data) +{ + HIF_DEVICE_USB *macp = HIF_GET_USB_DEVICE(scn); + QDF_STATUS status; + USB_CTRL_DIAG_CMD_READ *cmd; + uint32_t respLength; + + cmd = (USB_CTRL_DIAG_CMD_READ *) macp->diag_cmd_buffer; + + qdf_mem_zero(cmd, sizeof(*cmd)); + cmd->Cmd = USB_CTRL_DIAG_CC_READ; + cmd->Address = address; + respLength = sizeof(USB_CTRL_DIAG_RESP_READ); + + status = hif_ctrl_msg_exchange(macp, + USB_CONTROL_REQ_DIAG_CMD, + (uint8_t *) cmd, + sizeof(*cmd), + USB_CONTROL_REQ_DIAG_RESP, + macp->diag_resp_buffer, &respLength); + + if (QDF_IS_STATUS_SUCCESS(status)) { + USB_CTRL_DIAG_RESP_READ *pResp = + (USB_CTRL_DIAG_RESP_READ *) macp->diag_resp_buffer; + *data = pResp->ReadValue; + status = QDF_STATUS_SUCCESS; + } else { + status = QDF_STATUS_E_FAILURE; + } + + return status; +} + +/** + * hif_diag_write_access() - write data to target memory or register + * @scn: pointer to hif_opaque_softc + * @address: register address to write to + * @data: value to be written to the address + * + * Return: QDF_STATUS_SUCCESS if success else an appropriate QDF_STATUS error + */ +QDF_STATUS hif_diag_write_access(struct hif_opaque_softc *scn, + uint32_t address, + uint32_t data) +{ + HIF_DEVICE_USB *macp = HIF_GET_USB_DEVICE(scn); + USB_CTRL_DIAG_CMD_WRITE *cmd; + + cmd = (USB_CTRL_DIAG_CMD_WRITE *) macp->diag_cmd_buffer; + + qdf_mem_zero(cmd, sizeof(*cmd)); + cmd->Cmd = USB_CTRL_DIAG_CC_WRITE; + cmd->Address = address; + cmd->Value = data; + + return hif_ctrl_msg_exchange(macp, + USB_CONTROL_REQ_DIAG_CMD, + (uint8_t *) cmd, + sizeof(*cmd), 0, NULL, 0); +} + +/** + * hif_dump_info() - dump info about all HIF pipes and endpoints + * @scn: pointer to hif_opaque_softc + * + * Return: none + */ +void hif_dump_info(struct hif_opaque_softc *scn) +{ + HIF_DEVICE_USB *device = HIF_GET_USB_DEVICE(scn); + HIF_USB_PIPE *pipe = NULL; + struct usb_host_interface *iface_desc = NULL; + struct usb_endpoint_descriptor *ep_desc; + uint8_t i = 0; + + for (i = 0; i < HIF_USB_PIPE_MAX; i++) { + pipe = &device->pipes[i]; + HIF_ERROR("PipeIndex : %d URB Cnt : %d PipeHandle : %x", + i, pipe->urb_cnt, + pipe->usb_pipe_handle); + if (usb_pipeisoc(pipe->usb_pipe_handle)) + HIF_INFO("Pipe Type ISOC"); + else if (usb_pipebulk(pipe->usb_pipe_handle)) + HIF_INFO("Pipe Type BULK"); + else if (usb_pipeint(pipe->usb_pipe_handle)) + HIF_INFO("Pipe Type INT"); + else if (usb_pipecontrol(pipe->usb_pipe_handle)) + HIF_INFO("Pipe Type control"); + } + + for (i = 0; i < iface_desc->desc.bNumEndpoints; i++) { + ep_desc = &iface_desc->endpoint[i].desc; + if (ep_desc) { + HIF_INFO( + "ep_desc : %p Index : %d: DescType : %d Addr : %d Maxp : %d Atrrib : %d", + ep_desc, i, ep_desc->bDescriptorType, + ep_desc->bEndpointAddress, + ep_desc->wMaxPacketSize, + ep_desc->bmAttributes); + if ((ep_desc) && (usb_endpoint_type(ep_desc) == + USB_ENDPOINT_XFER_ISOC)) { + HIF_INFO("ISOC EP Detected"); + } + } + } + +} + +/** + * hif_flush_surprise_remove() - Cleanup residual buffers for device shutdown + * @scn: HIF context + * + * Not applicable to USB bus + * + * Return: none + */ +void hif_flush_surprise_remove(struct hif_opaque_softc *scn) +{ +/* TO DO... */ +} + +/** + * hif_diag_read_mem() -read nbytes of data from target memory or register + * @scn: pointer to hif_opaque_softc + * @address: register address to read from + * @data: buffer to store the value read + * @nbytes: number of bytes to be read from 'address' + * + * Return: QDF_STATUS_SUCCESS if success else an appropriate QDF_STATUS error + */ +QDF_STATUS hif_diag_read_mem(struct hif_opaque_softc *scn, + uint32_t address, uint8_t *data, + int nbytes) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + + HIF_TRACE("+%s", __func__); + + if ((address & 0x3) || ((uintptr_t)data & 0x3)) + return QDF_STATUS_E_IO; + + while ((nbytes >= 4) && + QDF_IS_STATUS_SUCCESS(status = + hif_diag_read_access(scn, + address, + (uint32_t *)data))) { + + nbytes -= sizeof(uint32_t); + address += sizeof(uint32_t); + data += sizeof(uint32_t); + + } + HIF_TRACE("-%s", __func__); + return status; +} + +/** + * hif_diag_write_mem() -write nbytes of data to target memory or register + * @scn: pointer to hif_opaque_softc + * @address: register address to write to + * @data: buffer containing data to be written + * @nbytes: number of bytes to be written + * + * Return: QDF_STATUS_SUCCESS if success else an appropriate QDF_STATUS error + */ +QDF_STATUS hif_diag_write_mem(struct hif_opaque_softc *scn, + uint32_t address, + uint8_t *data, int nbytes) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + HIF_TRACE("+%s", __func__); + + if ((address & 0x3) || ((uintptr_t)data & 0x3)) + return QDF_STATUS_E_IO; + + while (nbytes >= 4 && + QDF_IS_STATUS_SUCCESS(status = + hif_diag_write_access(scn, + address, + *((uint32_t *)data)))) { + + nbytes -= sizeof(uint32_t); + address += sizeof(uint32_t); + data += sizeof(uint32_t); + + } + HIF_TRACE("-%s", __func__); + return status; +} + +void hif_send_complete_check(struct hif_opaque_softc *scn, + uint8_t PipeID, int force) +{ + /* NO-OP*/ +} + +/* diagnostic command defnitions */ +#define USB_CTRL_DIAG_CC_READ 0 +#define USB_CTRL_DIAG_CC_WRITE 1 +#define USB_CTRL_DIAG_CC_WARM_RESET 2 + +void hif_suspend_wow(struct hif_opaque_softc *scn) +{ + HIF_INFO("HIFsuspendwow - TODO"); +} + +/** + * hif_usb_set_bundle_mode() - enable bundling and set default rx bundle cnt + * @scn: pointer to hif_opaque_softc structure + * @enabled: flag to enable/disable bundling + * @rx_bundle_cnt: bundle count to be used for RX + * + * Return: none + */ +void hif_usb_set_bundle_mode(struct hif_softc *scn, + bool enabled, int rx_bundle_cnt) +{ + HIF_DEVICE_USB *device = HIF_GET_USB_DEVICE(scn); + + device->is_bundle_enabled = enabled; + device->rx_bundle_cnt = rx_bundle_cnt; + if (device->is_bundle_enabled && (device->rx_bundle_cnt == 0)) + device->rx_bundle_cnt = 1; + + device->rx_bundle_buf_len = device->rx_bundle_cnt * + HIF_USB_RX_BUNDLE_ONE_PKT_SIZE; + + HIF_DBG("athusb bundle %s cnt %d", enabled ? "enabled" : "disabled", + rx_bundle_cnt); +} diff --git a/drivers/staging/qca-wifi-host-cmn/hif/src/usb/hif_usb_internal.h b/drivers/staging/qca-wifi-host-cmn/hif/src/usb/hif_usb_internal.h new file mode 100644 index 0000000000000000000000000000000000000000..217d2950e242951ede0418e7ecba2b895e627e9e --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/hif/src/usb/hif_usb_internal.h @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2013-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ +#ifndef _HIF_USB_INTERNAL_H +#define _HIF_USB_INTERNAL_H + +#include +#include "a_types.h" +#include "athdefs.h" +#include "a_osapi.h" +#include "a_usb_defs.h" +#include +#include +#include "hif.h" +#include "if_usb.h" + +#define TX_URB_COUNT 32 +#define RX_URB_COUNT 32 + +#define HIF_USB_RX_BUFFER_SIZE (1792 + 8) +#define HIF_USB_RX_BUNDLE_ONE_PKT_SIZE (1792 + 8) + +#ifdef HIF_USB_TASKLET +#define HIF_USB_SCHEDULE_WORK(pipe)\ + tasklet_schedule(&pipe->io_complete_tasklet); + +#define HIF_USB_INIT_WORK(pipe)\ + tasklet_init(&pipe->io_complete_tasklet,\ + usb_hif_io_comp_tasklet,\ + (long unsigned int)pipe); + +#define HIF_USB_FLUSH_WORK(pipe) flush_work(&pipe->io_complete_work); +#else +#define HIF_USB_SCHEDULE_WORK(pipe) schedule_work(&pipe->io_complete_work); +#define HIF_USB_INIT_WORK(pipe)\ + INIT_WORK(&pipe->io_complete_work,\ + usb_hif_io_comp_work); +#define HIF_USB_FLUSH_WORK(pipe) +#endif + +/* debug masks */ +#define USB_HIF_DEBUG_CTRL_TRANS ATH_DEBUG_MAKE_MODULE_MASK(0) +#define USB_HIF_DEBUG_BULK_IN ATH_DEBUG_MAKE_MODULE_MASK(1) +#define USB_HIF_DEBUG_BULK_OUT ATH_DEBUG_MAKE_MODULE_MASK(2) +#define USB_HIF_DEBUG_ENUM ATH_DEBUG_MAKE_MODULE_MASK(3) +#define USB_HIF_DEBUG_DUMP_DATA ATH_DEBUG_MAKE_MODULE_MASK(4) +#define USB_HIF_SUSPEND ATH_DEBUG_MAKE_MODULE_MASK(5) +#define USB_HIF_ISOC_SUPPORT ATH_DEBUG_MAKE_MODULE_MASK(6) + +struct _HIF_USB_PIPE; + +typedef struct _HIF_URB_CONTEXT { + DL_LIST link; + struct _HIF_USB_PIPE *pipe; + qdf_nbuf_t buf; + struct urb *urb; + struct hif_usb_send_context *send_context; +} HIF_URB_CONTEXT; + +#define HIF_USB_PIPE_FLAG_TX (1 << 0) + +/* + * Data structure to record required sending context data + */ +struct hif_usb_send_context { + A_BOOL new_alloc; + HIF_DEVICE_USB *hif_usb_device; + qdf_nbuf_t netbuf; + unsigned int transfer_id; + unsigned int head_data_len; +}; + +extern unsigned int hif_usb_disable_rxdata2; + +extern QDF_STATUS usb_hif_submit_ctrl_in(HIF_DEVICE_USB *macp, + uint8_t req, + uint16_t value, + uint16_t index, + void *data, uint32_t size); + +extern QDF_STATUS usb_hif_submit_ctrl_out(HIF_DEVICE_USB *macp, + uint8_t req, + uint16_t value, + uint16_t index, + void *data, uint32_t size); + +QDF_STATUS usb_hif_setup_pipe_resources(HIF_DEVICE_USB *device); +void usb_hif_cleanup_pipe_resources(HIF_DEVICE_USB *device); +void usb_hif_prestart_recv_pipes(HIF_DEVICE_USB *device); +void usb_hif_start_recv_pipes(HIF_DEVICE_USB *device); +void usb_hif_flush_all(HIF_DEVICE_USB *device); +void usb_hif_cleanup_transmit_urb(HIF_URB_CONTEXT *urb_context); +void usb_hif_enqueue_pending_transfer(HIF_USB_PIPE *pipe, + HIF_URB_CONTEXT *urb_context); +void usb_hif_remove_pending_transfer(HIF_URB_CONTEXT *urb_context); +HIF_URB_CONTEXT *usb_hif_alloc_urb_from_pipe(HIF_USB_PIPE *pipe); +#ifdef HIF_USB_TASKLET +void usb_hif_io_comp_tasklet(long unsigned int context); +#else +void usb_hif_io_comp_work(struct work_struct *work); +#endif +QDF_STATUS hif_diag_write_warm_reset(struct usb_interface *interface, + uint32_t address, uint32_t data); +#endif diff --git a/drivers/staging/qca-wifi-host-cmn/hif/src/usb/if_usb.c b/drivers/staging/qca-wifi-host-cmn/hif/src/usb/if_usb.c new file mode 100644 index 0000000000000000000000000000000000000000..0808626f48df2577fa6eca923a4f9590a9c0580c --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/hif/src/usb/if_usb.c @@ -0,0 +1,724 @@ +/* + * Copyright (c) 2013-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#include +#include +#include "if_usb.h" +#include "hif_usb_internal.h" +#include "bmi_msg.h" /* TARGET_TYPE_ */ +#include "regtable_usb.h" +#include "ol_fw.h" +#include "hif_debug.h" +#include "epping_main.h" +#include "hif_main.h" +#include "qwlan_version.h" + +#define DELAY_FOR_TARGET_READY 200 /* 200ms */ + +/* Save memory addresses where we save FW ram dump, and then we could obtain + * them by symbol table. + */ +uint32_t fw_stack_addr; +void *fw_ram_seg_addr[FW_RAM_SEG_CNT]; + + + +static int hif_usb_unload_dev_num = -1; +struct hif_usb_softc *g_usb_sc = NULL; + +void hif_usb_device_deinit(struct hif_usb_softc *sc); +QDF_STATUS hif_usb_device_init(struct hif_usb_softc *sc); + +/** + * hif_usb_diag_write_cold_reset() - reset SOC by sending a diag command + * @scn: pointer to ol_softc structure + * + * Return: QDF_STATUS_SUCCESS if success else an appropriate QDF_STATUS error + */ +static inline QDF_STATUS +hif_usb_diag_write_cold_reset(struct hif_softc *scn) +{ + struct hif_opaque_softc *hif_hdl = GET_HIF_OPAQUE_HDL(scn); + + + HIF_DBG("%s: resetting SOC", __func__); + + return hif_diag_write_access(hif_hdl, + (ROME_USB_SOC_RESET_CONTROL_COLD_RST_LSB | + ROME_USB_RTC_SOC_BASE_ADDRESS), + SOC_RESET_CONTROL_COLD_RST_SET(1)); +} + +/** + * hif_usb_procfs_init() - create init procfs + * @scn: pointer to hif_usb_softc structure + * + * Return: int 0 if success else an appropriate error number + */ +static int +hif_usb_procfs_init(struct hif_softc *scn) +{ + int ret = 0; + + HIF_ENTER(); + + if (athdiag_procfs_init(scn) != 0) { + HIF_ERROR("athdiag_procfs_init failed"); + ret = A_ERROR; + } + + scn->athdiag_procfs_inited = true; + + HIF_EXIT(); + return ret; +} + +/** + * hif_nointrs(): disable IRQ + * @scn: pointer to struct hif_softc + * + * This function stops interrupt(s) + * + * Return: none + */ +void hif_usb_nointrs(struct hif_softc *scn) +{ + +} + +/** + * hif_usb_reboot() - called at reboot time to reset WLAN SOC + * @nb: pointer to notifier_block registered during register_reboot_notifier + * @val: code indicating reboot reason + * @v: unused pointer + * + * Return: int 0 if success else an appropriate error number + */ +static int hif_usb_reboot(struct notifier_block *nb, unsigned long val, + void *v) +{ + struct hif_usb_softc *sc; + + HIF_ENTER(); + sc = container_of(nb, struct hif_usb_softc, reboot_notifier); + /* do cold reset */ + hif_usb_diag_write_cold_reset(HIF_GET_SOFTC(sc)); + HIF_EXIT(); + return NOTIFY_DONE; +} + +/** + * hif_usb_disable_lpm() - Disable lpm feature of usb2.0 + * @udev: pointer to usb_device for which LPM is to be disabled + * + * LPM needs to be disabled to avoid usb2.0 probe timeout + * + * Return: int 0 if success else an appropriate error number + */ +static int hif_usb_disable_lpm(struct usb_device *udev) +{ + struct usb_hcd *hcd; + int ret = -EPERM; + + HIF_ENTER(); + + if (!udev || !udev->bus) { + HIF_ERROR("Invalid input parameters"); + goto exit; + } + + hcd = bus_to_hcd(udev->bus); + if (udev->usb2_hw_lpm_enabled) { + if (hcd->driver->set_usb2_hw_lpm) { + ret = hcd->driver->set_usb2_hw_lpm(hcd, udev, false); + if (!ret) { + udev->usb2_hw_lpm_enabled = false; + udev->usb2_hw_lpm_capable = false; + HIF_TRACE("%s: LPM is disabled", __func__); + } else { + HIF_TRACE("%s: Fail to disable LPM", + __func__); + } + } else { + HIF_TRACE("%s: hcd doesn't support LPM", + __func__); + } + } else { + HIF_TRACE("%s: LPM isn't enabled", __func__); + } +exit: + HIF_EXIT(); + return ret; +} + +/** + * hif_usb_enable_bus() - enable usb bus + * @ol_sc: hif_softc struct + * @dev: device pointer + * @bdev: bus dev pointer + * @bid: bus id pointer + * @type: enum hif_enable_type such as HIF_ENABLE_TYPE_PROBE + * + * Return: QDF_STATUS_SUCCESS on success and error QDF status on failure + */ +QDF_STATUS hif_usb_enable_bus(struct hif_softc *scn, + struct device *dev, void *bdev, + const hif_bus_id *bid, + enum hif_enable_type type) + +{ + struct usb_interface *interface = (struct usb_interface *)bdev; + struct usb_device_id *id = (struct usb_device_id *)bid; + int ret = 0; + struct hif_usb_softc *sc; + struct usb_device *usbdev = interface_to_usbdev(interface); + int vendor_id, product_id; + + usb_get_dev(usbdev); + + if (!scn) { + HIF_ERROR("%s: hif_ctx is NULL", __func__); + goto err_usb; + } + + sc = HIF_GET_USB_SOFTC(scn); + + HIF_INFO("%s hif_softc %p usbdev %p interface %p\n", + __func__, + scn, + usbdev, + interface); + + vendor_id = qdf_le16_to_cpu(usbdev->descriptor.idVendor); + product_id = qdf_le16_to_cpu(usbdev->descriptor.idProduct); + + HIF_ERROR("%s: con_mode = 0x%x, vendor_id = 0x%x product_id = 0x%x", + __func__, hif_get_conparam(scn), vendor_id, product_id); + + sc->pdev = (void *)usbdev; + sc->dev = &usbdev->dev; + sc->devid = id->idProduct; + + if ((usb_control_msg(usbdev, usb_sndctrlpipe(usbdev, 0), + USB_REQ_SET_CONFIGURATION, 0, 1, 0, NULL, 0, + HZ)) < 0) { + HIF_ERROR("%s[%d]", __func__, __LINE__); + goto err_usb; + } + + usb_set_interface(usbdev, 0, 0); + /* disable lpm to avoid usb2.0 probe timeout */ + hif_usb_disable_lpm(usbdev); + + /* params need to be added - TO DO + scn->enableuartprint = 1; + scn->enablefwlog = 0; + scn->max_no_of_peers = 1; */ + + sc->interface = interface; + sc->reboot_notifier.notifier_call = hif_usb_reboot; + register_reboot_notifier(&sc->reboot_notifier); + + if (hif_usb_device_init(sc) != QDF_STATUS_SUCCESS) { + HIF_ERROR("ath: %s: hif_usb_device_init failed", __func__); + goto err_reset; + } + + if (hif_usb_procfs_init(scn)) + goto err_reset; + + hif_usb_unload_dev_num = usbdev->devnum; + g_usb_sc = sc; + HIF_EXIT(); + return 0; + +err_reset: + hif_usb_diag_write_cold_reset(scn); + g_usb_sc = NULL; + hif_usb_unload_dev_num = -1; + unregister_reboot_notifier(&sc->reboot_notifier); +err_usb: + ret = QDF_STATUS_E_FAILURE; + usb_put_dev(usbdev); + return ret; +} + + +/** + * hif_usb_close(): close bus, delete hif_sc + * @ol_sc: soft_sc struct + * + * Return: none + */ +void hif_usb_close(struct hif_softc *scn) +{ + g_usb_sc = NULL; +} + +/** + * hif_usb_disable_bus(): This function disables usb bus + * @hif_ctx: pointer to struct hif_softc + * + * Return: none + */ +void hif_usb_disable_bus(struct hif_softc *hif_ctx) +{ + struct hif_usb_softc *sc = HIF_GET_USB_SOFTC(hif_ctx); + struct usb_interface *interface = sc->interface; + struct usb_device *udev = interface_to_usbdev(interface); + + HIF_TRACE("%s: trying to remove hif_usb!", __func__); + + /* disable lpm to avoid following cold reset will + * cause xHCI U1/U2 timeout + */ + usb_disable_lpm(udev); + + /* wait for disable lpm */ + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(msecs_to_jiffies(DELAY_FOR_TARGET_READY)); + set_current_state(TASK_RUNNING); + + /* do cold reset */ + hif_usb_diag_write_cold_reset(hif_ctx); + + if (g_usb_sc->suspend_state) + hif_bus_resume(GET_HIF_OPAQUE_HDL(hif_ctx)); + + unregister_reboot_notifier(&sc->reboot_notifier); + usb_put_dev(interface_to_usbdev(interface)); + + hif_usb_device_deinit(sc); + + HIF_TRACE("%s hif_usb removed !!!!!!", __func__); +} + +/** + * hif_usb_bus_suspend() - suspend the bus + * @hif_ctx: hif_ctx + * + * This function suspends the bus, but usb doesn't need to suspend. + * Therefore just remove all the pending urb transactions + * + * Return: 0 for success and non-zero for failure + */ +int hif_usb_bus_suspend(struct hif_softc *hif_ctx) +{ + struct hif_usb_softc *sc = HIF_GET_USB_SOFTC(hif_ctx); + HIF_DEVICE_USB *device = HIF_GET_USB_DEVICE(hif_ctx); + + HIF_ENTER(); + sc->suspend_state = 1; + usb_hif_flush_all(device); + HIF_EXIT(); + return 0; +} + +/** + * hif_usb_bus_resume() - hif resume API + * @hif_ctx: struct hif_opaque_softc + * + * This function resumes the bus. but usb doesn't need to resume. + * Post recv urbs for RX data pipe + * + * Return: 0 for success and non-zero for failure + */ +int hif_usb_bus_resume(struct hif_softc *hif_ctx) +{ + struct hif_usb_softc *sc = HIF_GET_USB_SOFTC(hif_ctx); + HIF_DEVICE_USB *device = HIF_GET_USB_DEVICE(hif_ctx); + + HIF_ENTER(); + sc->suspend_state = 0; + usb_hif_start_recv_pipes(device); + + HIF_EXIT(); + return 0; +} + +/** + * hif_usb_bus_reset_resume() - resume the bus after reset + * @scn: struct hif_opaque_softc + * + * This function is called to tell the driver that USB device has been resumed + * and it has also been reset. The driver should redo any necessary + * initialization. This function resets WLAN SOC. + * + * Return: int 0 for success, non zero for failure + */ +int hif_usb_bus_reset_resume(struct hif_softc *hif_ctx) +{ + int ret = 0; + HIF_ENTER(); + if (hif_usb_diag_write_cold_reset(hif_ctx) != QDF_STATUS_SUCCESS) + ret = 1; + + HIF_EXIT(); + return ret; +} + +/** + * hif_usb_open()- initialization routine for usb bus + * @ol_sc: ol_sc + * @bus_type: bus type + * + * Return: QDF_STATUS_SUCCESS on success and error QDF status on failure + */ +QDF_STATUS hif_usb_open(struct hif_softc *hif_ctx, + enum qdf_bus_type bus_type) +{ + hif_ctx->bus_type = bus_type; + return QDF_STATUS_SUCCESS; +} + +/** + * hif_usb_disable_isr(): disable isr + * @hif_ctx: struct hif_softc + * + * Return: void + */ +void hif_usb_disable_isr(struct hif_softc *hif_ctx) +{ + /* TODO */ +} + +/** + * hif_usb_reg_tbl_attach()- attach hif, target register tables + * @scn: pointer to ol_softc structure + * + * Attach host and target register tables based on target_type, target_version + * + * Return: none + */ +void hif_usb_reg_tbl_attach(struct hif_softc *scn) +{ + u_int32_t hif_type, target_type; + int32_t ret = 0; + uint32_t chip_id; + QDF_STATUS rv; + struct hif_target_info *tgt_info = &scn->target_info; + struct hif_opaque_softc *hif_hdl = GET_HIF_OPAQUE_HDL(scn); + + if (scn->hostdef == NULL && scn->targetdef == NULL) { + switch (tgt_info->target_type) { + case TARGET_TYPE_AR6320: + switch (tgt_info->target_version) { + case AR6320_REV1_VERSION: + case AR6320_REV1_1_VERSION: + case AR6320_REV1_3_VERSION: + hif_type = HIF_TYPE_AR6320; + target_type = TARGET_TYPE_AR6320; + break; + case AR6320_REV2_1_VERSION: + case AR6320_REV3_VERSION: + case QCA9377_REV1_1_VERSION: + case QCA9379_REV1_VERSION: + hif_type = HIF_TYPE_AR6320V2; + target_type = TARGET_TYPE_AR6320V2; + break; + default: + ret = -1; + break; + } + break; + default: + ret = -1; + break; + } + + if (ret) + return; + + /* assign target register table if we find + corresponding type */ + hif_register_tbl_attach(scn, hif_type); + target_register_tbl_attach(scn, target_type); + /* read the chip revision*/ + rv = hif_diag_read_access(hif_hdl, + (CHIP_ID_ADDRESS | + RTC_SOC_BASE_ADDRESS), + &chip_id); + if (rv != QDF_STATUS_SUCCESS) { + HIF_ERROR("%s: get chip id val (%d)", __func__, + rv); + } + tgt_info->target_revision = + CHIP_ID_REVISION_GET(chip_id); + } +} + +/** + * hif_usb_get_hw_info()- attach register table for USB + * @hif_ctx: pointer to hif_softc structure + + * This function is used to attach the host and target register tables. + * Ideally, we should not attach register tables as a part of this function. + * There is scope of cleanup to move register table attach during + * initialization for USB bus. + * + * The reason we are doing register table attach for USB here is that, it relies + * on target_info->target_type and target_info->target_version, + * which get populated during bmi_firmware_download. "hif_get_fw_info" is the + * only initialization related call into HIF there after. + * + * To fix this, we can move the "get target info, functionality currently in + * bmi_firmware_download into hif initialization functions. This change will + * affect all buses. Can be taken up as a part of convergence. + * + * Return: none + */ +void hif_usb_get_hw_info(struct hif_softc *hif_ctx) +{ + hif_usb_reg_tbl_attach(hif_ctx); +} + + +/** + * hif_bus_configure() - configure the bus + * @scn: pointer to the hif context. + * + * return: 0 for success. nonzero for failure. + */ +int hif_usb_bus_configure(struct hif_softc *scn) +{ + return 0; +} + +/** + * hif_usb_irq_enable() - hif_usb_irq_enable + * @scn: hif_softc + * @ce_id: ce_id + * + * Return: void + */ +void hif_usb_irq_enable(struct hif_softc *scn, int ce_id) +{ +} + +/** + * hif_usb_irq_disable() - hif_usb_irq_disable + * @scn: hif_softc + * @ce_id: ce_id + * + * Return: void + */ +void hif_usb_irq_disable(struct hif_softc *scn, int ce_id) +{ +} + +/** + * hif_usb_shutdown_bus_device() - This function shuts down the device + * @scn: hif opaque pointer + * + * Return: void + */ +void hif_usb_shutdown_bus_device(struct hif_softc *scn) +{ +} + +/** + * hif_trigger_dump() - trigger various dump cmd + * @scn: struct hif_opaque_softc + * @cmd_id: dump command id + * @start: start/stop dump + * + * Return: None + */ +void hif_trigger_dump(struct hif_opaque_softc *scn, uint8_t cmd_id, bool start) +{ +} + +/** + * hif_wlan_disable() - call the platform driver to disable wlan + * @scn: scn + * + * Return: void + */ +void hif_wlan_disable(struct hif_softc *scn) +{ +} + +/** + * hif_fw_assert_ramdump_pattern() - handle firmware assert with ramdump pattern + * @sc: pointer to hif_usb_softc structure + * + * Return: void + */ + +void hif_fw_assert_ramdump_pattern(struct hif_usb_softc *sc) +{ + uint32_t *reg, pattern, i = 0; + uint32_t len; + uint8_t *data; + uint8_t *ram_ptr = NULL; + char *fw_ram_seg_name[FW_RAM_SEG_CNT] = {"DRAM", "IRAM", "AXI"}; + size_t fw_ram_reg_size[FW_RAM_SEG_CNT] = { + FW_RAMDUMP_DRAMSIZE, + FW_RAMDUMP_IRAMSIZE, + FW_RAMDUMP_AXISIZE }; + + data = sc->fw_data; + len = sc->fw_data_len; + pattern = *((A_UINT32 *) data); + + qdf_assert(sc->ramdump_index < FW_RAM_SEG_CNT); + i = sc->ramdump_index; + reg = (uint32_t *) (data + 4); + if (sc->fw_ram_dumping == 0) { + sc->fw_ram_dumping = 1; + HIF_ERROR("Firmware %s dump:\n", fw_ram_seg_name[i]); + sc->ramdump[i] = + qdf_mem_malloc(sizeof(struct fw_ramdump) + + fw_ram_reg_size[i]); + if (!sc->ramdump[i]) { + pr_err("Fail to allocate memory for ram dump"); + QDF_BUG(0); + } + (sc->ramdump[i])->mem = (uint8_t *) (sc->ramdump[i] + 1); + fw_ram_seg_addr[i] = (sc->ramdump[i])->mem; + HIF_ERROR("FW %s start addr = %#08x\n", + fw_ram_seg_name[i], *reg); + HIF_ERROR("Memory addr for %s = %p\n", + fw_ram_seg_name[i], + (sc->ramdump[i])->mem); + (sc->ramdump[i])->start_addr = *reg; + (sc->ramdump[i])->length = 0; + } + reg++; + ram_ptr = (sc->ramdump[i])->mem + (sc->ramdump[i])->length; + (sc->ramdump[i])->length += (len - 8); + if (sc->ramdump[i]->length <= fw_ram_reg_size[i]) { + qdf_mem_copy(ram_ptr, (A_UINT8 *) reg, len - 8); + } else { + HIF_ERROR("memory copy overlap\n"); + QDF_BUG(0); + } + + if (pattern == FW_RAMDUMP_END_PATTERN) { + HIF_ERROR("%s memory size = %d\n", fw_ram_seg_name[i], + (sc->ramdump[i])->length); + if (i == (FW_RAM_SEG_CNT - 1)) + QDF_BUG(0); + + sc->ramdump_index++; + sc->fw_ram_dumping = 0; + } +} + +/** + * hif_usb_ramdump_handler(): dump bus debug registers + * @scn: struct hif_opaque_softc + * + * This function is to receive information of firmware crash dump, and + * save it in host memory. It consists of 5 parts: registers, call stack, + * DRAM dump, IRAM dump, and AXI dump, and they are reported to host in order. + * + * registers: wrapped in a USB packet by starting as FW_ASSERT_PATTERN and + * 60 registers. + * call stack: wrapped in multiple USB packets, and each of them starts as + * FW_REG_PATTERN and contains multiple double-words. The tail + * of the last packet is FW_REG_END_PATTERN. + * DRAM dump: wrapped in multiple USB pakcets, and each of them start as + * FW_RAMDUMP_PATTERN and contains multiple double-wors. The tail + * of the last packet is FW_RAMDUMP_END_PATTERN; + * IRAM dump and AXI dump are with the same format as DRAM dump. + * + * Return: 0 for success or error code + */ + +void hif_usb_ramdump_handler(struct hif_opaque_softc *scn) +{ + uint32_t *reg, pattern, i, start_addr = 0; + uint32_t len; + uint8_t *data; + uint8_t str_buf[128]; + uint32_t remaining; + struct hif_usb_softc *sc = HIF_GET_USB_SOFTC(scn); + struct hif_softc *hif_ctx = HIF_GET_SOFTC(scn); + struct hif_target_info *tgt_info = &hif_ctx->target_info; + + data = sc->fw_data; + len = sc->fw_data_len; + pattern = *((A_UINT32 *) data); + + if (pattern == FW_ASSERT_PATTERN) { + HIF_ERROR("Firmware crash detected...\n"); + HIF_ERROR("Host SW version: %s\n", QWLAN_VERSIONSTR); + HIF_ERROR("target_type: %d.target_version %d. target_revision%d.", + tgt_info->target_type, + tgt_info->target_version, + tgt_info->target_revision); + + reg = (uint32_t *) (data + 4); + print_hex_dump(KERN_DEBUG, " ", DUMP_PREFIX_OFFSET, 16, 4, reg, + min_t(A_UINT32, len - 4, FW_REG_DUMP_CNT * 4), + false); + sc->fw_ram_dumping = 0; + + } else if (pattern == FW_REG_PATTERN) { + reg = (uint32_t *) (data + 4); + start_addr = *reg++; + if (sc->fw_ram_dumping == 0) { + pr_err("Firmware stack dump:"); + sc->fw_ram_dumping = 1; + fw_stack_addr = start_addr; + } + remaining = len - 8; + /* len is in byte, but it's printed in double-word. */ + for (i = 0; i < (len - 8); i += 16) { + if ((*reg == FW_REG_END_PATTERN) && (i == len - 12)) { + sc->fw_ram_dumping = 0; + pr_err("Stack start address = %#08x\n", + fw_stack_addr); + break; + } + hex_dump_to_buffer(reg, remaining, 16, 4, str_buf, + sizeof(str_buf), false); + pr_err("%#08x: %s\n", start_addr + i, str_buf); + remaining -= 16; + reg += 4; + } + } else if ((!sc->enable_self_recovery) && + ((pattern & FW_RAMDUMP_PATTERN_MASK) == + FW_RAMDUMP_PATTERN)) { + hif_fw_assert_ramdump_pattern(sc); + } +} + +#ifndef QCA_WIFI_3_0 +/** + * hif_check_fw_reg(): hif_check_fw_reg + * @scn: scn + * @state: + * + * Return: int + */ +int hif_check_fw_reg(struct hif_opaque_softc *scn) +{ + return 0; +} +#endif diff --git a/drivers/staging/qca-wifi-host-cmn/hif/src/usb/if_usb.h b/drivers/staging/qca-wifi-host-cmn/hif/src/usb/if_usb.h new file mode 100644 index 0000000000000000000000000000000000000000..1232602d4542f50c91a9c3971543b9f8b8306b15 --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/hif/src/usb/if_usb.h @@ -0,0 +1,163 @@ +/* + * Copyright (c) 2013-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ +#ifndef __ATH_USB_H__ +#define __ATH_USB_H__ + +#include + +/* + * There may be some pending tx frames during platform suspend. + * Suspend operation should be delayed until those tx frames are + * transfered from the host to target. This macro specifies how + * long suspend thread has to sleep before checking pending tx + * frame count. + */ +#define OL_ATH_TX_DRAIN_WAIT_DELAY 50 /* ms */ +/* + * Wait time (in unit of OL_ATH_TX_DRAIN_WAIT_DELAY) for pending + * tx frame completion before suspend. Refer: hif_pci_suspend() + */ +#define OL_ATH_TX_DRAIN_WAIT_CNT 10 + +#define CONFIG_COPY_ENGINE_SUPPORT /* TBDXXX: here for now */ +#define ATH_DBG_DEFAULT 0 +#include +#include +#include +#include "osapi_linux.h" +#include "hif_main.h" +#include "hif.h" + +#define FW_REG_DUMP_CNT 60 + +/* Magic patterns for FW to report crash information (Rome USB) */ +#define FW_ASSERT_PATTERN 0x0000c600 +#define FW_REG_PATTERN 0x0000d600 +#define FW_REG_END_PATTERN 0x0000e600 +#define FW_RAMDUMP_PATTERN 0x0000f600 +#define FW_RAMDUMP_END_PATTERN 0x0000f601 +#define FW_RAMDUMP_PATTERN_MASK 0xfffffff0 +#define FW_RAMDUMP_DRAMSIZE 0x00098000 +#define FW_RAMDUMP_IRAMSIZE 0x000C0000 +#define FW_RAMDUMP_AXISIZE 0x00020000 + +/* FW RAM segments (Rome USB) */ +enum { + FW_RAM_SEG_DRAM, + FW_RAM_SEG_IRAM, + FW_RAM_SEG_AXI, + FW_RAM_SEG_CNT +}; + +/* Allocate 384K memory to save each segment of ram dump */ +#define FW_RAMDUMP_SEG_SIZE 393216 + +/* structure to save RAM dump information */ +struct fw_ramdump { + uint32_t start_addr; + uint32_t length; + uint8_t *mem; +}; + +/* USB Endpoint definition */ +typedef enum { + HIF_TX_CTRL_PIPE = 0, + HIF_TX_DATA_LP_PIPE, + HIF_TX_DATA_MP_PIPE, + HIF_TX_DATA_HP_PIPE, + HIF_RX_CTRL_PIPE, + HIF_RX_DATA_PIPE, + HIF_RX_DATA2_PIPE, + HIF_RX_INT_PIPE, + HIF_USB_PIPE_MAX +} HIF_USB_PIPE_ID; + +#define HIF_USB_PIPE_INVALID HIF_USB_PIPE_MAX + +typedef struct _HIF_USB_PIPE { + DL_LIST urb_list_head; + DL_LIST urb_pending_list; + int32_t urb_alloc; + int32_t urb_cnt; + int32_t urb_cnt_thresh; + unsigned int usb_pipe_handle; + uint32_t flags; + uint8_t ep_address; + uint8_t logical_pipe_num; + struct _HIF_DEVICE_USB *device; + uint16_t max_packet_size; +#ifdef HIF_USB_TASKLET + struct tasklet_struct io_complete_tasklet; +#else + struct work_struct io_complete_work; +#endif + struct sk_buff_head io_comp_queue; + struct usb_endpoint_descriptor *ep_desc; + int32_t urb_prestart_cnt; +} HIF_USB_PIPE; + +typedef struct _HIF_DEVICE_USB { + struct hif_softc ol_sc; + qdf_spinlock_t cs_lock; + qdf_spinlock_t tx_lock; + qdf_spinlock_t rx_lock; + struct hif_msg_callbacks htc_callbacks; + struct usb_device *udev; + struct usb_interface *interface; + HIF_USB_PIPE pipes[HIF_USB_PIPE_MAX]; + uint8_t *diag_cmd_buffer; + uint8_t *diag_resp_buffer; + void *claimed_context; + A_BOOL is_bundle_enabled; + uint16_t rx_bundle_cnt; + uint32_t rx_bundle_buf_len; +} HIF_DEVICE_USB; + + +struct hif_usb_softc { + struct _HIF_DEVICE_USB hif_hdl; + /* For efficiency, should be first in struct */ + struct device *dev; + struct usb_dev *pdev; + /* + * Guard changes to Target HW state and to software + * structures that track hardware state. + */ + u16 devid; + struct usb_interface *interface; + struct notifier_block reboot_notifier; /* default mode before reboot */ + u8 suspend_state; + u8 *fw_data; + u32 fw_data_len; + /* structure to save FW RAM dump (Rome USB) */ + struct fw_ramdump *ramdump[FW_RAM_SEG_CNT]; + uint8_t ramdump_index; + bool fw_ram_dumping; + /* enable FW self-recovery for Rome USB */ + bool enable_self_recovery; +}; +#endif /* __ATH_USB_H__ */ diff --git a/drivers/staging/qca-wifi-host-cmn/hif/src/usb/regtable_usb.c b/drivers/staging/qca-wifi-host-cmn/hif/src/usb/regtable_usb.c new file mode 100644 index 0000000000000000000000000000000000000000..1e9ea190ed4874f3d5fc41f215207112f7e38263 --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/hif/src/usb/regtable_usb.c @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2014-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#include "bmi_msg.h" +#include "targaddrs.h" +#include "regtable_usb.h" +#include "ar9888def.h" +#include "ar6320def.h" +#include "ar6320v2def.h" +#include "hif_debug.h" + +void target_register_tbl_attach(struct hif_softc *scn, + uint32_t target_type) +{ + switch (target_type) { + case TARGET_TYPE_AR9888: + scn->targetdef = &ar9888_targetdef; + break; + case TARGET_TYPE_AR6320: + scn->targetdef = &ar6320_targetdef; + break; + case TARGET_TYPE_AR6320V2: + scn->targetdef = &ar6320v2_targetdef; + break; + default: + HIF_ERROR("%s: unknown target_type %u", __func__, target_type); + break; + } +} +void hif_register_tbl_attach(struct hif_softc *scn, uint32_t hif_type) +{ + switch (hif_type) { + case HIF_TYPE_AR9888: + scn->hostdef = &ar9888_hostdef; + break; + case HIF_TYPE_AR6320: + scn->hostdef = &ar6320_hostdef; + break; + case HIF_TYPE_AR6320V2: + scn->hostdef = &ar6320v2_hostdef; + break; + default: + HIF_ERROR("%s: unknown hif_type %u", __func__, hif_type); + break; + } +} diff --git a/drivers/staging/qca-wifi-host-cmn/hif/src/usb/regtable_usb.h b/drivers/staging/qca-wifi-host-cmn/hif/src/usb/regtable_usb.h new file mode 100644 index 0000000000000000000000000000000000000000..7d489892ea637498795bd28de5490066de0a4cd5 --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/hif/src/usb/regtable_usb.h @@ -0,0 +1,1295 @@ +/* + * Copyright (c) 2013-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ +#ifndef _REGTABLE_USB_H_ +#define _REGTABLE_USB_H_ +#include "if_usb.h" + +#define MISSING 0 + +typedef struct targetdef_s { + u_int32_t d_RTC_SOC_BASE_ADDRESS; + u_int32_t d_RTC_WMAC_BASE_ADDRESS; + u_int32_t d_SYSTEM_SLEEP_OFFSET; + u_int32_t d_WLAN_SYSTEM_SLEEP_OFFSET; + u_int32_t d_WLAN_SYSTEM_SLEEP_DISABLE_LSB; + u_int32_t d_WLAN_SYSTEM_SLEEP_DISABLE_MASK; + u_int32_t d_CLOCK_CONTROL_OFFSET; + u_int32_t d_CLOCK_CONTROL_SI0_CLK_MASK; + u_int32_t d_RESET_CONTROL_OFFSET; + u_int32_t d_RESET_CONTROL_MBOX_RST_MASK; + u_int32_t d_RESET_CONTROL_SI0_RST_MASK; + u_int32_t d_WLAN_RESET_CONTROL_OFFSET; + u_int32_t d_WLAN_RESET_CONTROL_COLD_RST_MASK; + u_int32_t d_WLAN_RESET_CONTROL_WARM_RST_MASK; + u_int32_t d_GPIO_BASE_ADDRESS; + u_int32_t d_GPIO_PIN0_OFFSET; + u_int32_t d_GPIO_PIN1_OFFSET; + u_int32_t d_GPIO_PIN0_CONFIG_MASK; + u_int32_t d_GPIO_PIN1_CONFIG_MASK; + u_int32_t d_SI_CONFIG_BIDIR_OD_DATA_LSB; + u_int32_t d_SI_CONFIG_BIDIR_OD_DATA_MASK; + u_int32_t d_SI_CONFIG_I2C_LSB; + u_int32_t d_SI_CONFIG_I2C_MASK; + u_int32_t d_SI_CONFIG_POS_SAMPLE_LSB; + u_int32_t d_SI_CONFIG_POS_SAMPLE_MASK; + u_int32_t d_SI_CONFIG_INACTIVE_CLK_LSB; + u_int32_t d_SI_CONFIG_INACTIVE_CLK_MASK; + u_int32_t d_SI_CONFIG_INACTIVE_DATA_LSB; + u_int32_t d_SI_CONFIG_INACTIVE_DATA_MASK; + u_int32_t d_SI_CONFIG_DIVIDER_LSB; + u_int32_t d_SI_CONFIG_DIVIDER_MASK; + u_int32_t d_SI_BASE_ADDRESS; + u_int32_t d_SI_CONFIG_OFFSET; + u_int32_t d_SI_TX_DATA0_OFFSET; + u_int32_t d_SI_TX_DATA1_OFFSET; + u_int32_t d_SI_RX_DATA0_OFFSET; + u_int32_t d_SI_RX_DATA1_OFFSET; + u_int32_t d_SI_CS_OFFSET; + u_int32_t d_SI_CS_DONE_ERR_MASK; + u_int32_t d_SI_CS_DONE_INT_MASK; + u_int32_t d_SI_CS_START_LSB; + u_int32_t d_SI_CS_START_MASK; + u_int32_t d_SI_CS_RX_CNT_LSB; + u_int32_t d_SI_CS_RX_CNT_MASK; + u_int32_t d_SI_CS_TX_CNT_LSB; + u_int32_t d_SI_CS_TX_CNT_MASK; + u_int32_t d_BOARD_DATA_SZ; + u_int32_t d_BOARD_EXT_DATA_SZ; + u_int32_t d_MBOX_BASE_ADDRESS; + u_int32_t d_LOCAL_SCRATCH_OFFSET; + u_int32_t d_CPU_CLOCK_OFFSET; + u_int32_t d_LPO_CAL_OFFSET; + u_int32_t d_GPIO_PIN10_OFFSET; + u_int32_t d_GPIO_PIN11_OFFSET; + u_int32_t d_GPIO_PIN12_OFFSET; + u_int32_t d_GPIO_PIN13_OFFSET; + u_int32_t d_CLOCK_GPIO_OFFSET; + u_int32_t d_CPU_CLOCK_STANDARD_LSB; + u_int32_t d_CPU_CLOCK_STANDARD_MASK; + u_int32_t d_LPO_CAL_ENABLE_LSB; + u_int32_t d_LPO_CAL_ENABLE_MASK; + u_int32_t d_CLOCK_GPIO_BT_CLK_OUT_EN_LSB; + u_int32_t d_CLOCK_GPIO_BT_CLK_OUT_EN_MASK; + u_int32_t d_ANALOG_INTF_BASE_ADDRESS; + u_int32_t d_WLAN_MAC_BASE_ADDRESS; + u_int32_t d_CE0_BASE_ADDRESS; + u_int32_t d_CE1_BASE_ADDRESS; + u_int32_t d_FW_INDICATOR_ADDRESS; + u_int32_t d_DRAM_BASE_ADDRESS; + u_int32_t d_SOC_CORE_BASE_ADDRESS; + u_int32_t d_CORE_CTRL_ADDRESS; + u_int32_t d_CE_COUNT; + u_int32_t d_MSI_NUM_REQUEST; + u_int32_t d_MSI_ASSIGN_FW; + u_int32_t d_MSI_ASSIGN_CE_INITIAL; + u_int32_t d_PCIE_INTR_ENABLE_ADDRESS; + u_int32_t d_PCIE_INTR_CLR_ADDRESS; + u_int32_t d_PCIE_INTR_FIRMWARE_MASK; + u_int32_t d_PCIE_INTR_CE_MASK_ALL; + u_int32_t d_CORE_CTRL_CPU_INTR_MASK; + u_int32_t d_SR_WR_INDEX_ADDRESS; + u_int32_t d_DST_WATERMARK_ADDRESS; + + /* htt_rx.c */ + u_int32_t d_RX_MSDU_END_4_FIRST_MSDU_MASK; + u_int32_t d_RX_MSDU_END_4_FIRST_MSDU_LSB; + uint32_t d_RX_MPDU_START_0_RETRY_LSB; + uint32_t d_RX_MPDU_START_0_RETRY_MASK; + u_int32_t d_RX_MPDU_START_0_SEQ_NUM_MASK; + u_int32_t d_RX_MPDU_START_0_SEQ_NUM_LSB; + u_int32_t d_RX_MPDU_START_2_PN_47_32_LSB; + u_int32_t d_RX_MPDU_START_2_PN_47_32_MASK; + uint32_t d_RX_MPDU_START_2_TID_LSB; + uint32_t d_RX_MPDU_START_2_TID_MASK; + u_int32_t d_RX_MSDU_END_1_EXT_WAPI_PN_63_48_MASK; + u_int32_t d_RX_MSDU_END_1_EXT_WAPI_PN_63_48_LSB; + u_int32_t d_RX_MSDU_END_1_KEY_ID_OCT_MASK; + u_int32_t d_RX_MSDU_END_1_KEY_ID_OCT_LSB; + u_int32_t d_RX_MSDU_END_4_LAST_MSDU_MASK; + u_int32_t d_RX_MSDU_END_4_LAST_MSDU_LSB; + u_int32_t d_RX_ATTENTION_0_MCAST_BCAST_MASK; + u_int32_t d_RX_ATTENTION_0_MCAST_BCAST_LSB; + u_int32_t d_RX_ATTENTION_0_FRAGMENT_MASK; + u_int32_t d_RX_ATTENTION_0_FRAGMENT_LSB; + u_int32_t d_RX_ATTENTION_0_MPDU_LENGTH_ERR_MASK; + u_int32_t d_RX_FRAG_INFO_0_RING2_MORE_COUNT_MASK; + u_int32_t d_RX_FRAG_INFO_0_RING2_MORE_COUNT_LSB; + u_int32_t d_RX_MSDU_START_0_MSDU_LENGTH_MASK; + u_int32_t d_RX_MSDU_START_0_MSDU_LENGTH_LSB; + u_int32_t d_RX_MSDU_START_2_DECAP_FORMAT_OFFSET; + u_int32_t d_RX_MSDU_START_2_DECAP_FORMAT_MASK; + u_int32_t d_RX_MSDU_START_2_DECAP_FORMAT_LSB; + u_int32_t d_RX_MPDU_START_0_ENCRYPTED_MASK; + u_int32_t d_RX_MPDU_START_0_ENCRYPTED_LSB; + u_int32_t d_RX_ATTENTION_0_MORE_DATA_MASK; + u_int32_t d_RX_ATTENTION_0_MSDU_DONE_MASK; + u_int32_t d_RX_ATTENTION_0_TCP_UDP_CHKSUM_FAIL_MASK; + /* end */ + /* copy_engine.c */ + u_int32_t d_DST_WR_INDEX_ADDRESS; + u_int32_t d_SRC_WATERMARK_ADDRESS; + u_int32_t d_SRC_WATERMARK_LOW_MASK; + u_int32_t d_SRC_WATERMARK_HIGH_MASK; + u_int32_t d_DST_WATERMARK_LOW_MASK; + u_int32_t d_DST_WATERMARK_HIGH_MASK; + u_int32_t d_CURRENT_SRRI_ADDRESS; + u_int32_t d_CURRENT_DRRI_ADDRESS; + u_int32_t d_HOST_IS_SRC_RING_HIGH_WATERMARK_MASK; + u_int32_t d_HOST_IS_SRC_RING_LOW_WATERMARK_MASK; + u_int32_t d_HOST_IS_DST_RING_HIGH_WATERMARK_MASK; + u_int32_t d_HOST_IS_DST_RING_LOW_WATERMARK_MASK; + u_int32_t d_HOST_IS_ADDRESS; + u_int32_t d_HOST_IS_COPY_COMPLETE_MASK; + u_int32_t d_CE_WRAPPER_BASE_ADDRESS; + u_int32_t d_CE_WRAPPER_INTERRUPT_SUMMARY_ADDRESS; + u_int32_t d_HOST_IE_ADDRESS; + u_int32_t d_HOST_IE_COPY_COMPLETE_MASK; + u_int32_t d_SR_BA_ADDRESS; + u_int32_t d_SR_SIZE_ADDRESS; + u_int32_t d_CE_CTRL1_ADDRESS; + u_int32_t d_CE_CTRL1_DMAX_LENGTH_MASK; + u_int32_t d_DR_BA_ADDRESS; + u_int32_t d_DR_SIZE_ADDRESS; + u_int32_t d_MISC_IE_ADDRESS; + u_int32_t d_MISC_IS_AXI_ERR_MASK; + u_int32_t d_MISC_IS_DST_ADDR_ERR_MASK; + u_int32_t d_MISC_IS_SRC_LEN_ERR_MASK; + u_int32_t d_MISC_IS_DST_MAX_LEN_VIO_MASK; + u_int32_t d_MISC_IS_DST_RING_OVERFLOW_MASK; + u_int32_t d_MISC_IS_SRC_RING_OVERFLOW_MASK; + u_int32_t d_SRC_WATERMARK_LOW_LSB; + u_int32_t d_SRC_WATERMARK_HIGH_LSB; + u_int32_t d_DST_WATERMARK_LOW_LSB; + u_int32_t d_DST_WATERMARK_HIGH_LSB; + u_int32_t d_CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_MASK; + u_int32_t d_CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_LSB; + u_int32_t d_CE_CTRL1_DMAX_LENGTH_LSB; + u_int32_t d_CE_CTRL1_SRC_RING_BYTE_SWAP_EN_MASK; + u_int32_t d_CE_CTRL1_DST_RING_BYTE_SWAP_EN_MASK; + u_int32_t d_CE_CTRL1_SRC_RING_BYTE_SWAP_EN_LSB; + u_int32_t d_CE_CTRL1_DST_RING_BYTE_SWAP_EN_LSB; + u_int32_t d_WLAN_DEBUG_INPUT_SEL_OFFSET; + u_int32_t d_WLAN_DEBUG_INPUT_SEL_SRC_MSB; + u_int32_t d_WLAN_DEBUG_INPUT_SEL_SRC_LSB; + u_int32_t d_WLAN_DEBUG_INPUT_SEL_SRC_MASK; + u_int32_t d_WLAN_DEBUG_CONTROL_OFFSET; + u_int32_t d_WLAN_DEBUG_CONTROL_ENABLE_MSB; + u_int32_t d_WLAN_DEBUG_CONTROL_ENABLE_LSB; + u_int32_t d_WLAN_DEBUG_CONTROL_ENABLE_MASK; + u_int32_t d_WLAN_DEBUG_OUT_OFFSET; + u_int32_t d_WLAN_DEBUG_OUT_DATA_MSB; + u_int32_t d_WLAN_DEBUG_OUT_DATA_LSB; + u_int32_t d_WLAN_DEBUG_OUT_DATA_MASK; + u_int32_t d_AMBA_DEBUG_BUS_OFFSET; + u_int32_t d_AMBA_DEBUG_BUS_PCIE_DEBUG_SEL_MSB; + u_int32_t d_AMBA_DEBUG_BUS_PCIE_DEBUG_SEL_LSB; + u_int32_t d_AMBA_DEBUG_BUS_PCIE_DEBUG_SEL_MASK; + u_int32_t d_AMBA_DEBUG_BUS_SEL_MSB; + u_int32_t d_AMBA_DEBUG_BUS_SEL_LSB; + u_int32_t d_AMBA_DEBUG_BUS_SEL_MASK; + u_int32_t d_CE_WRAPPER_DEBUG_OFFSET; + u_int32_t d_CE_WRAPPER_DEBUG_SEL_MSB; + u_int32_t d_CE_WRAPPER_DEBUG_SEL_LSB; + u_int32_t d_CE_WRAPPER_DEBUG_SEL_MASK; + u_int32_t d_CE_DEBUG_OFFSET; + u_int32_t d_CE_DEBUG_SEL_MSB; + u_int32_t d_CE_DEBUG_SEL_LSB; + u_int32_t d_CE_DEBUG_SEL_MASK; + /* end */ + /* PLL start */ + u_int32_t d_EFUSE_OFFSET; + u_int32_t d_EFUSE_XTAL_SEL_MSB; + u_int32_t d_EFUSE_XTAL_SEL_LSB; + u_int32_t d_EFUSE_XTAL_SEL_MASK; + u_int32_t d_BB_PLL_CONFIG_OFFSET; + u_int32_t d_BB_PLL_CONFIG_OUTDIV_MSB; + u_int32_t d_BB_PLL_CONFIG_OUTDIV_LSB; + u_int32_t d_BB_PLL_CONFIG_OUTDIV_MASK; + u_int32_t d_BB_PLL_CONFIG_FRAC_MSB; + u_int32_t d_BB_PLL_CONFIG_FRAC_LSB; + u_int32_t d_BB_PLL_CONFIG_FRAC_MASK; + u_int32_t d_WLAN_PLL_SETTLE_TIME_MSB; + u_int32_t d_WLAN_PLL_SETTLE_TIME_LSB; + u_int32_t d_WLAN_PLL_SETTLE_TIME_MASK; + u_int32_t d_WLAN_PLL_SETTLE_OFFSET; + u_int32_t d_WLAN_PLL_SETTLE_SW_MASK; + u_int32_t d_WLAN_PLL_SETTLE_RSTMASK; + u_int32_t d_WLAN_PLL_SETTLE_RESET; + u_int32_t d_WLAN_PLL_CONTROL_NOPWD_MSB; + u_int32_t d_WLAN_PLL_CONTROL_NOPWD_LSB; + u_int32_t d_WLAN_PLL_CONTROL_NOPWD_MASK; + u_int32_t d_WLAN_PLL_CONTROL_BYPASS_MSB; + u_int32_t d_WLAN_PLL_CONTROL_BYPASS_LSB; + u_int32_t d_WLAN_PLL_CONTROL_BYPASS_MASK; + u_int32_t d_WLAN_PLL_CONTROL_BYPASS_RESET; + u_int32_t d_WLAN_PLL_CONTROL_CLK_SEL_MSB; + u_int32_t d_WLAN_PLL_CONTROL_CLK_SEL_LSB; + u_int32_t d_WLAN_PLL_CONTROL_CLK_SEL_MASK; + u_int32_t d_WLAN_PLL_CONTROL_CLK_SEL_RESET; + u_int32_t d_WLAN_PLL_CONTROL_REFDIV_MSB; + u_int32_t d_WLAN_PLL_CONTROL_REFDIV_LSB; + u_int32_t d_WLAN_PLL_CONTROL_REFDIV_MASK; + u_int32_t d_WLAN_PLL_CONTROL_REFDIV_RESET; + u_int32_t d_WLAN_PLL_CONTROL_DIV_MSB; + u_int32_t d_WLAN_PLL_CONTROL_DIV_LSB; + u_int32_t d_WLAN_PLL_CONTROL_DIV_MASK; + u_int32_t d_WLAN_PLL_CONTROL_DIV_RESET; + u_int32_t d_WLAN_PLL_CONTROL_OFFSET; + u_int32_t d_WLAN_PLL_CONTROL_SW_MASK; + u_int32_t d_WLAN_PLL_CONTROL_RSTMASK; + u_int32_t d_WLAN_PLL_CONTROL_RESET; + u_int32_t d_SOC_CORE_CLK_CTRL_OFFSET; + u_int32_t d_SOC_CORE_CLK_CTRL_DIV_MSB; + u_int32_t d_SOC_CORE_CLK_CTRL_DIV_LSB; + u_int32_t d_SOC_CORE_CLK_CTRL_DIV_MASK; + u_int32_t d_RTC_SYNC_STATUS_PLL_CHANGING_MSB; + u_int32_t d_RTC_SYNC_STATUS_PLL_CHANGING_LSB; + u_int32_t d_RTC_SYNC_STATUS_PLL_CHANGING_MASK; + u_int32_t d_RTC_SYNC_STATUS_PLL_CHANGING_RESET; + u_int32_t d_RTC_SYNC_STATUS_OFFSET; + u_int32_t d_SOC_CPU_CLOCK_OFFSET; + u_int32_t d_SOC_CPU_CLOCK_STANDARD_MSB; + u_int32_t d_SOC_CPU_CLOCK_STANDARD_LSB; + u_int32_t d_SOC_CPU_CLOCK_STANDARD_MASK; + /* PLL end */ + u_int32_t d_SOC_POWER_REG_OFFSET; + u_int32_t d_PCIE_INTR_CAUSE_ADDRESS; + u_int32_t d_SOC_RESET_CONTROL_ADDRESS; + u_int32_t d_SOC_RESET_CONTROL_PCIE_RST_SHORT_OVRD_MASK; + u_int32_t d_SOC_RESET_CONTROL_PCIE_RST_SHORT_OVRD_LSB; + u_int32_t d_SOC_RESET_CONTROL_CE_RST_MASK; + u_int32_t d_SOC_RESET_CONTROL_CPU_WARM_RST_MASK; + u_int32_t d_CPU_INTR_ADDRESS; + u_int32_t d_SOC_LF_TIMER_CONTROL0_ADDRESS; + u_int32_t d_SOC_LF_TIMER_CONTROL0_ENABLE_MASK; + /* chip id start */ + u_int32_t d_SOC_CHIP_ID_ADDRESS; + u_int32_t d_SOC_CHIP_ID_VERSION_MASK; + u_int32_t d_SOC_CHIP_ID_VERSION_LSB; + u_int32_t d_SOC_CHIP_ID_REVISION_MASK; + u_int32_t d_SOC_CHIP_ID_REVISION_LSB; + /* chip id end */ +} TARGET_REGISTER_TABLE; + +#define RTC_SOC_BASE_ADDRESS \ + (scn->targetdef->d_RTC_SOC_BASE_ADDRESS) +#define RTC_WMAC_BASE_ADDRESS \ + (scn->targetdef->d_RTC_WMAC_BASE_ADDRESS) +#define SYSTEM_SLEEP_OFFSET \ + (scn->targetdef->d_SYSTEM_SLEEP_OFFSET) +#define WLAN_SYSTEM_SLEEP_OFFSET \ + (scn->targetdef->d_WLAN_SYSTEM_SLEEP_OFFSET) +#define WLAN_SYSTEM_SLEEP_DISABLE_LSB \ + (scn->targetdef->d_WLAN_SYSTEM_SLEEP_DISABLE_LSB) +#define WLAN_SYSTEM_SLEEP_DISABLE_MASK \ + (scn->targetdef->d_WLAN_SYSTEM_SLEEP_DISABLE_MASK) +#define CLOCK_CONTROL_OFFSET \ + (scn->targetdef->d_CLOCK_CONTROL_OFFSET) +#define CLOCK_CONTROL_SI0_CLK_MASK \ + (scn->targetdef->d_CLOCK_CONTROL_SI0_CLK_MASK) +#define RESET_CONTROL_OFFSET \ + (scn->targetdef->d_RESET_CONTROL_OFFSET) +#define RESET_CONTROL_MBOX_RST_MASK \ + (scn->targetdef->d_RESET_CONTROL_MBOX_RST_MASK) +#define RESET_CONTROL_SI0_RST_MASK \ + (scn->targetdef->d_RESET_CONTROL_SI0_RST_MASK) +#define WLAN_RESET_CONTROL_OFFSET \ + (scn->targetdef->d_WLAN_RESET_CONTROL_OFFSET) +#define WLAN_RESET_CONTROL_COLD_RST_MASK \ + (scn->targetdef->d_WLAN_RESET_CONTROL_COLD_RST_MASK) +#define WLAN_RESET_CONTROL_WARM_RST_MASK \ + (scn->targetdef->d_WLAN_RESET_CONTROL_WARM_RST_MASK) +#define GPIO_BASE_ADDRESS \ + (scn->targetdef->d_GPIO_BASE_ADDRESS) +#define GPIO_PIN0_OFFSET \ + (scn->targetdef->d_GPIO_PIN0_OFFSET) +#define GPIO_PIN1_OFFSET \ + (scn->targetdef->d_GPIO_PIN1_OFFSET) +#define GPIO_PIN0_CONFIG_MASK \ + (scn->targetdef->d_GPIO_PIN0_CONFIG_MASK) +#define GPIO_PIN1_CONFIG_MASK \ + (scn->targetdef->d_GPIO_PIN1_CONFIG_MASK) +#define SI_CONFIG_BIDIR_OD_DATA_LSB \ + (scn->targetdef->d_SI_CONFIG_BIDIR_OD_DATA_LSB) +#define SI_CONFIG_BIDIR_OD_DATA_MASK \ + (scn->targetdef->d_SI_CONFIG_BIDIR_OD_DATA_MASK) +#define SI_CONFIG_I2C_LSB \ + (scn->targetdef->d_SI_CONFIG_I2C_LSB) +#define SI_CONFIG_I2C_MASK \ + (scn->targetdef->d_SI_CONFIG_I2C_MASK) +#define SI_CONFIG_POS_SAMPLE_LSB \ + (scn->targetdef->d_SI_CONFIG_POS_SAMPLE_LSB) +#define SI_CONFIG_POS_SAMPLE_MASK \ + (scn->targetdef->d_SI_CONFIG_POS_SAMPLE_MASK) +#define SI_CONFIG_INACTIVE_CLK_LSB \ + (scn->targetdef->d_SI_CONFIG_INACTIVE_CLK_LSB) +#define SI_CONFIG_INACTIVE_CLK_MASK \ + (scn->targetdef->d_SI_CONFIG_INACTIVE_CLK_MASK) +#define SI_CONFIG_INACTIVE_DATA_LSB \ + (scn->targetdef->d_SI_CONFIG_INACTIVE_DATA_LSB) +#define SI_CONFIG_INACTIVE_DATA_MASK \ + (scn->targetdef->d_SI_CONFIG_INACTIVE_DATA_MASK) +#define SI_CONFIG_DIVIDER_LSB \ + (scn->targetdef->d_SI_CONFIG_DIVIDER_LSB) +#define SI_CONFIG_DIVIDER_MASK \ + (scn->targetdef->d_SI_CONFIG_DIVIDER_MASK) +#define SI_BASE_ADDRESS \ + (scn->targetdef->d_SI_BASE_ADDRESS) +#define SI_CONFIG_OFFSET \ + (scn->targetdef->d_SI_CONFIG_OFFSET) +#define SI_TX_DATA0_OFFSET \ + (scn->targetdef->d_SI_TX_DATA0_OFFSET) +#define SI_TX_DATA1_OFFSET \ + (scn->targetdef->d_SI_TX_DATA1_OFFSET) +#define SI_RX_DATA0_OFFSET \ + (scn->targetdef->d_SI_RX_DATA0_OFFSET) +#define SI_RX_DATA1_OFFSET \ + (scn->targetdef->d_SI_RX_DATA1_OFFSET) +#define SI_CS_OFFSET \ + (scn->targetdef->d_SI_CS_OFFSET) +#define SI_CS_DONE_ERR_MASK \ + (scn->targetdef->d_SI_CS_DONE_ERR_MASK) +#define SI_CS_DONE_INT_MASK \ + (scn->targetdef->d_SI_CS_DONE_INT_MASK) +#define SI_CS_START_LSB \ + (scn->targetdef->d_SI_CS_START_LSB) +#define SI_CS_START_MASK \ + (scn->targetdef->d_SI_CS_START_MASK) +#define SI_CS_RX_CNT_LSB \ + (scn->targetdef->d_SI_CS_RX_CNT_LSB) +#define SI_CS_RX_CNT_MASK \ + (scn->targetdef->d_SI_CS_RX_CNT_MASK) +#define SI_CS_TX_CNT_LSB \ + (scn->targetdef->d_SI_CS_TX_CNT_LSB) +#define SI_CS_TX_CNT_MASK \ + (scn->targetdef->d_SI_CS_TX_CNT_MASK) +#define EEPROM_SZ \ + (scn->targetdef->d_BOARD_DATA_SZ) +#define EEPROM_EXT_SZ \ + (scn->targetdef->d_BOARD_EXT_DATA_SZ) +#define MBOX_BASE_ADDRESS \ + (scn->targetdef->d_MBOX_BASE_ADDRESS) +#define LOCAL_SCRATCH_OFFSET \ + (scn->targetdef->d_LOCAL_SCRATCH_OFFSET) +#define CPU_CLOCK_OFFSET \ + (scn->targetdef->d_CPU_CLOCK_OFFSET) +#define LPO_CAL_OFFSET \ + (scn->targetdef->d_LPO_CAL_OFFSET) +#define GPIO_PIN10_OFFSET \ + (scn->targetdef->d_GPIO_PIN10_OFFSET) +#define GPIO_PIN11_OFFSET \ + (scn->targetdef->d_GPIO_PIN11_OFFSET) +#define GPIO_PIN12_OFFSET \ + (scn->targetdef->d_GPIO_PIN12_OFFSET) +#define GPIO_PIN13_OFFSET \ + (scn->targetdef->d_GPIO_PIN13_OFFSET) +#define CLOCK_GPIO_OFFSET \ + (scn->targetdef->d_CLOCK_GPIO_OFFSET) +#define CPU_CLOCK_STANDARD_LSB \ + (scn->targetdef->d_CPU_CLOCK_STANDARD_LSB) +#define CPU_CLOCK_STANDARD_MASK \ + (scn->targetdef->d_CPU_CLOCK_STANDARD_MASK) +#define LPO_CAL_ENABLE_LSB \ + (scn->targetdef->d_LPO_CAL_ENABLE_LSB) +#define LPO_CAL_ENABLE_MASK \ + (scn->targetdef->d_LPO_CAL_ENABLE_MASK) +#define CLOCK_GPIO_BT_CLK_OUT_EN_LSB \ + (scn->targetdef->d_CLOCK_GPIO_BT_CLK_OUT_EN_LSB) +#define CLOCK_GPIO_BT_CLK_OUT_EN_MASK \ + (scn->targetdef->d_CLOCK_GPIO_BT_CLK_OUT_EN_MASK) +#define ANALOG_INTF_BASE_ADDRESS \ + (scn->targetdef->d_ANALOG_INTF_BASE_ADDRESS) +#define WLAN_MAC_BASE_ADDRESS \ + (scn->targetdef->d_WLAN_MAC_BASE_ADDRESS) +#define CE0_BASE_ADDRESS \ + (scn->targetdef->d_CE0_BASE_ADDRESS) +#define CE1_BASE_ADDRESS \ + (scn->targetdef->d_CE1_BASE_ADDRESS) +#define FW_INDICATOR_ADDRESS \ + (scn->targetdef->d_FW_INDICATOR_ADDRESS) +#define DRAM_BASE_ADDRESS \ + (scn->targetdef->d_DRAM_BASE_ADDRESS) +#define SOC_CORE_BASE_ADDRESS \ + (scn->targetdef->d_SOC_CORE_BASE_ADDRESS) +#define CORE_CTRL_ADDRESS \ + (scn->targetdef->d_CORE_CTRL_ADDRESS) +#define CE_COUNT \ + (scn->targetdef->d_CE_COUNT) +#define PCIE_INTR_ENABLE_ADDRESS \ + (scn->targetdef->d_PCIE_INTR_ENABLE_ADDRESS) +#define PCIE_INTR_CLR_ADDRESS \ + (scn->targetdef->d_PCIE_INTR_CLR_ADDRESS) +#define PCIE_INTR_FIRMWARE_MASK \ + (scn->targetdef->d_PCIE_INTR_FIRMWARE_MASK) +#define PCIE_INTR_CE_MASK_ALL \ + (scn->targetdef->d_PCIE_INTR_CE_MASK_ALL) +#define CORE_CTRL_CPU_INTR_MASK \ + (scn->targetdef->d_CORE_CTRL_CPU_INTR_MASK) +#define PCIE_INTR_CAUSE_ADDRESS \ + (scn->targetdef->d_PCIE_INTR_CAUSE_ADDRESS) +#define SOC_RESET_CONTROL_ADDRESS \ + (scn->targetdef->d_SOC_RESET_CONTROL_ADDRESS) +#define SOC_RESET_CONTROL_CE_RST_MASK \ + (scn->targetdef->d_SOC_RESET_CONTROL_CE_RST_MASK) +#define SOC_RESET_CONTROL_CPU_WARM_RST_MASK\ + (scn->targetdef->d_SOC_RESET_CONTROL_CPU_WARM_RST_MASK) +#define CPU_INTR_ADDRESS \ + (scn->targetdef->d_CPU_INTR_ADDRESS) +#define SOC_LF_TIMER_CONTROL0_ADDRESS \ + (scn->targetdef->d_SOC_LF_TIMER_CONTROL0_ADDRESS) +#define SOC_LF_TIMER_CONTROL0_ENABLE_MASK \ + (scn->targetdef->d_SOC_LF_TIMER_CONTROL0_ENABLE_MASK) +#define SOC_RESET_CONTROL_PCIE_RST_SHORT_OVRD_LSB \ + (scn->targetdef->d_SOC_RESET_CONTROL_PCIE_RST_SHORT_OVRD_LSB) +#define SOC_RESET_CONTROL_PCIE_RST_SHORT_OVRD_MASK \ + (scn->targetdef->d_SOC_RESET_CONTROL_PCIE_RST_SHORT_OVRD_MASK) + +#define SOC_RESET_CONTROL_PCIE_RST_SHORT_OVRD_GET(x) \ + (((x) & SOC_RESET_CONTROL_PCIE_RST_SHORT_OVRD_MASK) >> \ + SOC_RESET_CONTROL_PCIE_RST_SHORT_OVRD_LSB) +#define SOC_RESET_CONTROL_PCIE_RST_SHORT_OVRD_SET(x) \ + (((x) << SOC_RESET_CONTROL_PCIE_RST_SHORT_OVRD_LSB) & \ + SOC_RESET_CONTROL_PCIE_RST_SHORT_OVRD_MASK) + +/* hif_pci.c */ +#define CHIP_ID_ADDRESS \ + (scn->targetdef->d_SOC_CHIP_ID_ADDRESS) +#define SOC_CHIP_ID_REVISION_MASK \ + (scn->targetdef->d_SOC_CHIP_ID_REVISION_MASK) +#define SOC_CHIP_ID_REVISION_LSB \ + (scn->targetdef->d_SOC_CHIP_ID_REVISION_LSB) +#define SOC_CHIP_ID_VERSION_MASK \ + (scn->targetdef->d_SOC_CHIP_ID_VERSION_MASK) +#define SOC_CHIP_ID_VERSION_LSB \ + (scn->targetdef->d_SOC_CHIP_ID_VERSION_LSB) +#define CHIP_ID_REVISION_GET(x) \ + (((x) & SOC_CHIP_ID_REVISION_MASK) >> SOC_CHIP_ID_REVISION_LSB) +#define CHIP_ID_VERSION_GET(x) \ + (((x) & SOC_CHIP_ID_VERSION_MASK) >> SOC_CHIP_ID_VERSION_LSB) +/* hif_pci.c end */ + +/* misc */ +#define SR_WR_INDEX_ADDRESS \ + (scn->targetdef->d_SR_WR_INDEX_ADDRESS) +#define DST_WATERMARK_ADDRESS \ + (scn->targetdef->d_DST_WATERMARK_ADDRESS) +#define SOC_POWER_REG_OFFSET \ + (scn->targetdef->d_SOC_POWER_REG_OFFSET) +/* end */ + +/* htt_rx.c */ +#define RX_MSDU_END_4_FIRST_MSDU_MASK \ + (pdev->targetdef->d_RX_MSDU_END_4_FIRST_MSDU_MASK) +#define RX_MSDU_END_4_FIRST_MSDU_LSB \ + (pdev->targetdef->d_RX_MSDU_END_4_FIRST_MSDU_LSB) +#define RX_MPDU_START_0_RETRY_LSB \ + (pdev->targetdef->d_RX_MPDU_START_0_RETRY_LSB) +#define RX_MPDU_START_0_RETRY_MASK \ + (pdev->targetdef->d_RX_MPDU_START_0_RETRY_MASK) +#define RX_MPDU_START_0_SEQ_NUM_MASK \ + (pdev->targetdef->d_RX_MPDU_START_0_SEQ_NUM_MASK) +#define RX_MPDU_START_0_SEQ_NUM_LSB \ + (pdev->targetdef->d_RX_MPDU_START_0_SEQ_NUM_LSB) +#define RX_MPDU_START_2_PN_47_32_LSB \ + (pdev->targetdef->d_RX_MPDU_START_2_PN_47_32_LSB) +#define RX_MPDU_START_2_PN_47_32_MASK \ + (pdev->targetdef->d_RX_MPDU_START_2_PN_47_32_MASK) +#define RX_MPDU_START_2_TID_LSB \ + (pdev->targetdef->d_RX_MPDU_START_2_TID_LSB) +#define RX_MPDU_START_2_TID_MASK \ + (pdev->targetdef->d_RX_MPDU_START_2_TID_MASK) +#define RX_MSDU_END_1_KEY_ID_OCT_MASK \ + (pdev->targetdef->d_RX_MSDU_END_1_KEY_ID_OCT_MASK) +#define RX_MSDU_END_1_KEY_ID_OCT_LSB \ + (pdev->targetdef->d_RX_MSDU_END_1_KEY_ID_OCT_LSB) +#define RX_MSDU_END_1_EXT_WAPI_PN_63_48_MASK \ + (pdev->targetdef->d_RX_MSDU_END_1_EXT_WAPI_PN_63_48_MASK) +#define RX_MSDU_END_1_EXT_WAPI_PN_63_48_LSB\ + (pdev->targetdef->d_RX_MSDU_END_1_EXT_WAPI_PN_63_48_LSB) +#define RX_MSDU_END_4_LAST_MSDU_MASK \ + (pdev->targetdef->d_RX_MSDU_END_4_LAST_MSDU_MASK) +#define RX_MSDU_END_4_LAST_MSDU_LSB \ + (pdev->targetdef->d_RX_MSDU_END_4_LAST_MSDU_LSB) +#define RX_ATTENTION_0_MCAST_BCAST_MASK \ + (pdev->targetdef->d_RX_ATTENTION_0_MCAST_BCAST_MASK) +#define RX_ATTENTION_0_MCAST_BCAST_LSB \ + (pdev->targetdef->d_RX_ATTENTION_0_MCAST_BCAST_LSB) +#define RX_ATTENTION_0_FRAGMENT_MASK \ + (pdev->targetdef->d_RX_ATTENTION_0_FRAGMENT_MASK) +#define RX_ATTENTION_0_FRAGMENT_LSB \ + (pdev->targetdef->d_RX_ATTENTION_0_FRAGMENT_LSB) +#define RX_ATTENTION_0_MPDU_LENGTH_ERR_MASK\ + (pdev->targetdef->d_RX_ATTENTION_0_MPDU_LENGTH_ERR_MASK) +#define RX_FRAG_INFO_0_RING2_MORE_COUNT_MASK \ + (pdev->targetdef->d_RX_FRAG_INFO_0_RING2_MORE_COUNT_MASK) +#define RX_FRAG_INFO_0_RING2_MORE_COUNT_LSB\ + (pdev->targetdef->d_RX_FRAG_INFO_0_RING2_MORE_COUNT_LSB) +#define RX_MSDU_START_0_MSDU_LENGTH_MASK \ + (pdev->targetdef->d_RX_MSDU_START_0_MSDU_LENGTH_MASK) +#define RX_MSDU_START_0_MSDU_LENGTH_LSB \ + (pdev->targetdef->d_RX_MSDU_START_0_MSDU_LENGTH_LSB) +#define RX_MSDU_START_2_DECAP_FORMAT_OFFSET\ + (pdev->targetdef->d_RX_MSDU_START_2_DECAP_FORMAT_OFFSET) +#define RX_MSDU_START_2_DECAP_FORMAT_MASK \ + (pdev->targetdef->d_RX_MSDU_START_2_DECAP_FORMAT_MASK) +#define RX_MSDU_START_2_DECAP_FORMAT_LSB \ + (pdev->targetdef->d_RX_MSDU_START_2_DECAP_FORMAT_LSB) +#define RX_MPDU_START_0_ENCRYPTED_MASK \ + (pdev->targetdef->d_RX_MPDU_START_0_ENCRYPTED_MASK) +#define RX_MPDU_START_0_ENCRYPTED_LSB \ + (pdev->targetdef->d_RX_MPDU_START_0_ENCRYPTED_LSB) +#define RX_ATTENTION_0_MORE_DATA_MASK \ + (pdev->targetdef->d_RX_ATTENTION_0_MORE_DATA_MASK) +#define RX_ATTENTION_0_MSDU_DONE_MASK \ + (pdev->targetdef->d_RX_ATTENTION_0_MSDU_DONE_MASK) +#define RX_ATTENTION_0_TCP_UDP_CHKSUM_FAIL_MASK \ + (pdev->targetdef->d_RX_ATTENTION_0_TCP_UDP_CHKSUM_FAIL_MASK) +/* end */ + +/* copy_engine.c */ +#define DST_WR_INDEX_ADDRESS \ + (scn->targetdef->d_DST_WR_INDEX_ADDRESS) +#define SRC_WATERMARK_ADDRESS \ + (scn->targetdef->d_SRC_WATERMARK_ADDRESS) +#define SRC_WATERMARK_LOW_MASK \ + (scn->targetdef->d_SRC_WATERMARK_LOW_MASK) +#define SRC_WATERMARK_HIGH_MASK \ + (scn->targetdef->d_SRC_WATERMARK_HIGH_MASK) +#define DST_WATERMARK_LOW_MASK \ + (scn->targetdef->d_DST_WATERMARK_LOW_MASK) +#define DST_WATERMARK_HIGH_MASK \ + (scn->targetdef->d_DST_WATERMARK_HIGH_MASK) +#define CURRENT_SRRI_ADDRESS \ + (scn->targetdef->d_CURRENT_SRRI_ADDRESS) +#define CURRENT_DRRI_ADDRESS \ + (scn->targetdef->d_CURRENT_DRRI_ADDRESS) +#define HOST_IS_SRC_RING_HIGH_WATERMARK_MASK \ + (scn->targetdef->d_HOST_IS_SRC_RING_HIGH_WATERMARK_MASK) +#define HOST_IS_SRC_RING_LOW_WATERMARK_MASK\ + (scn->targetdef->d_HOST_IS_SRC_RING_LOW_WATERMARK_MASK) +#define HOST_IS_DST_RING_HIGH_WATERMARK_MASK \ + (scn->targetdef->d_HOST_IS_DST_RING_HIGH_WATERMARK_MASK) +#define HOST_IS_DST_RING_LOW_WATERMARK_MASK\ + (scn->targetdef->d_HOST_IS_DST_RING_LOW_WATERMARK_MASK) +#define HOST_IS_ADDRESS \ + (scn->targetdef->d_HOST_IS_ADDRESS) +#define HOST_IS_COPY_COMPLETE_MASK \ + (scn->targetdef->d_HOST_IS_COPY_COMPLETE_MASK) +#define CE_WRAPPER_BASE_ADDRESS \ + (scn->targetdef->d_CE_WRAPPER_BASE_ADDRESS) +#define CE_WRAPPER_INTERRUPT_SUMMARY_ADDRESS \ + (scn->targetdef->d_CE_WRAPPER_INTERRUPT_SUMMARY_ADDRESS) +#define HOST_IE_ADDRESS \ + (scn->targetdef->d_HOST_IE_ADDRESS) +#define HOST_IE_COPY_COMPLETE_MASK \ + (scn->targetdef->d_HOST_IE_COPY_COMPLETE_MASK) +#define SR_BA_ADDRESS \ + (scn->targetdef->d_SR_BA_ADDRESS) +#define SR_SIZE_ADDRESS \ + (scn->targetdef->d_SR_SIZE_ADDRESS) +#define CE_CTRL1_ADDRESS \ + (scn->targetdef->d_CE_CTRL1_ADDRESS) +#define CE_CTRL1_DMAX_LENGTH_MASK \ + (scn->targetdef->d_CE_CTRL1_DMAX_LENGTH_MASK) +#define DR_BA_ADDRESS \ + (scn->targetdef->d_DR_BA_ADDRESS) +#define DR_SIZE_ADDRESS \ + (scn->targetdef->d_DR_SIZE_ADDRESS) +#define MISC_IE_ADDRESS \ + (scn->targetdef->d_MISC_IE_ADDRESS) +#define MISC_IS_AXI_ERR_MASK \ + (scn->targetdef->d_MISC_IS_AXI_ERR_MASK) +#define MISC_IS_DST_ADDR_ERR_MASK \ + (scn->targetdef->d_MISC_IS_DST_ADDR_ERR_MASK) +#define MISC_IS_SRC_LEN_ERR_MASK \ + (scn->targetdef->d_MISC_IS_SRC_LEN_ERR_MASK) +#define MISC_IS_DST_MAX_LEN_VIO_MASK \ + (scn->targetdef->d_MISC_IS_DST_MAX_LEN_VIO_MASK) +#define MISC_IS_DST_RING_OVERFLOW_MASK \ + (scn->targetdef->d_MISC_IS_DST_RING_OVERFLOW_MASK) +#define MISC_IS_SRC_RING_OVERFLOW_MASK \ + (scn->targetdef->d_MISC_IS_SRC_RING_OVERFLOW_MASK) +#define SRC_WATERMARK_LOW_LSB \ + (scn->targetdef->d_SRC_WATERMARK_LOW_LSB) +#define SRC_WATERMARK_HIGH_LSB \ + (scn->targetdef->d_SRC_WATERMARK_HIGH_LSB) +#define DST_WATERMARK_LOW_LSB \ + (scn->targetdef->d_DST_WATERMARK_LOW_LSB) +#define DST_WATERMARK_HIGH_LSB \ + (scn->targetdef->d_DST_WATERMARK_HIGH_LSB) +#define CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_MASK \ + (scn->targetdef->d_CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_MASK) +#define CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_LSB \ + (scn->targetdef->d_CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_LSB) +#define CE_CTRL1_DMAX_LENGTH_LSB \ + (scn->targetdef->d_CE_CTRL1_DMAX_LENGTH_LSB) +#define CE_CTRL1_SRC_RING_BYTE_SWAP_EN_MASK\ + (scn->targetdef->d_CE_CTRL1_SRC_RING_BYTE_SWAP_EN_MASK) +#define CE_CTRL1_DST_RING_BYTE_SWAP_EN_MASK\ + (scn->targetdef->d_CE_CTRL1_DST_RING_BYTE_SWAP_EN_MASK) +#define CE_CTRL1_SRC_RING_BYTE_SWAP_EN_LSB \ + (scn->targetdef->d_CE_CTRL1_SRC_RING_BYTE_SWAP_EN_LSB) +#define CE_CTRL1_DST_RING_BYTE_SWAP_EN_LSB \ + (scn->targetdef->d_CE_CTRL1_DST_RING_BYTE_SWAP_EN_LSB) +#define WLAN_DEBUG_INPUT_SEL_OFFSET \ + (scn->targetdef->d_WLAN_DEBUG_INPUT_SEL_OFFSET) +#define WLAN_DEBUG_INPUT_SEL_SRC_MSB \ + (scn->targetdef->d_WLAN_DEBUG_INPUT_SEL_SRC_MSB) +#define WLAN_DEBUG_INPUT_SEL_SRC_LSB \ + (scn->targetdef->d_WLAN_DEBUG_INPUT_SEL_SRC_LSB) +#define WLAN_DEBUG_INPUT_SEL_SRC_MASK \ + (scn->targetdef->d_WLAN_DEBUG_INPUT_SEL_SRC_MASK) +#define WLAN_DEBUG_CONTROL_OFFSET \ + (scn->targetdef->d_WLAN_DEBUG_CONTROL_OFFSET) +#define WLAN_DEBUG_CONTROL_ENABLE_MSB \ + (scn->targetdef->d_WLAN_DEBUG_CONTROL_ENABLE_MSB) +#define WLAN_DEBUG_CONTROL_ENABLE_LSB \ + (scn->targetdef->d_WLAN_DEBUG_CONTROL_ENABLE_LSB) +#define WLAN_DEBUG_CONTROL_ENABLE_MASK \ + (scn->targetdef->d_WLAN_DEBUG_CONTROL_ENABLE_MASK) +#define WLAN_DEBUG_OUT_OFFSET \ + (scn->targetdef->d_WLAN_DEBUG_OUT_OFFSET) +#define WLAN_DEBUG_OUT_DATA_MSB \ + (scn->targetdef->d_WLAN_DEBUG_OUT_DATA_MSB) +#define WLAN_DEBUG_OUT_DATA_LSB \ + (scn->targetdef->d_WLAN_DEBUG_OUT_DATA_LSB) +#define WLAN_DEBUG_OUT_DATA_MASK \ + (scn->targetdef->d_WLAN_DEBUG_OUT_DATA_MASK) +#define AMBA_DEBUG_BUS_OFFSET \ + (scn->targetdef->d_AMBA_DEBUG_BUS_OFFSET) +#define AMBA_DEBUG_BUS_PCIE_DEBUG_SEL_MSB \ + (scn->targetdef->d_AMBA_DEBUG_BUS_PCIE_DEBUG_SEL_MSB) +#define AMBA_DEBUG_BUS_PCIE_DEBUG_SEL_LSB \ + (scn->targetdef->d_AMBA_DEBUG_BUS_PCIE_DEBUG_SEL_LSB) +#define AMBA_DEBUG_BUS_PCIE_DEBUG_SEL_MASK \ + (scn->targetdef->d_AMBA_DEBUG_BUS_PCIE_DEBUG_SEL_MASK) +#define AMBA_DEBUG_BUS_SEL_MSB \ + (scn->targetdef->d_AMBA_DEBUG_BUS_SEL_MSB) +#define AMBA_DEBUG_BUS_SEL_LSB \ + (scn->targetdef->d_AMBA_DEBUG_BUS_SEL_LSB) +#define AMBA_DEBUG_BUS_SEL_MASK \ + (scn->targetdef->d_AMBA_DEBUG_BUS_SEL_MASK) +#define CE_WRAPPER_DEBUG_OFFSET \ + (scn->targetdef->d_CE_WRAPPER_DEBUG_OFFSET) +#define CE_WRAPPER_DEBUG_SEL_MSB \ + (scn->targetdef->d_CE_WRAPPER_DEBUG_SEL_MSB) +#define CE_WRAPPER_DEBUG_SEL_LSB \ + (scn->targetdef->d_CE_WRAPPER_DEBUG_SEL_LSB) +#define CE_WRAPPER_DEBUG_SEL_MASK \ + (scn->targetdef->d_CE_WRAPPER_DEBUG_SEL_MASK) +#define CE_DEBUG_OFFSET \ + (scn->targetdef->d_CE_DEBUG_OFFSET) +#define CE_DEBUG_SEL_MSB \ + (scn->targetdef->d_CE_DEBUG_SEL_MSB) +#define CE_DEBUG_SEL_LSB \ + (scn->targetdef->d_CE_DEBUG_SEL_LSB) +#define CE_DEBUG_SEL_MASK \ + (scn->targetdef->d_CE_DEBUG_SEL_MASK) +/* end */ +/* PLL start */ +#define EFUSE_OFFSET \ + (scn->targetdef->d_EFUSE_OFFSET) +#define EFUSE_XTAL_SEL_MSB \ + (scn->targetdef->d_EFUSE_XTAL_SEL_MSB) +#define EFUSE_XTAL_SEL_LSB \ + (scn->targetdef->d_EFUSE_XTAL_SEL_LSB) +#define EFUSE_XTAL_SEL_MASK \ + (scn->targetdef->d_EFUSE_XTAL_SEL_MASK) +#define BB_PLL_CONFIG_OFFSET \ + (scn->targetdef->d_BB_PLL_CONFIG_OFFSET) +#define BB_PLL_CONFIG_OUTDIV_MSB \ + (scn->targetdef->d_BB_PLL_CONFIG_OUTDIV_MSB) +#define BB_PLL_CONFIG_OUTDIV_LSB \ + (scn->targetdef->d_BB_PLL_CONFIG_OUTDIV_LSB) +#define BB_PLL_CONFIG_OUTDIV_MASK \ + (scn->targetdef->d_BB_PLL_CONFIG_OUTDIV_MASK) +#define BB_PLL_CONFIG_FRAC_MSB \ + (scn->targetdef->d_BB_PLL_CONFIG_FRAC_MSB) +#define BB_PLL_CONFIG_FRAC_LSB \ + (scn->targetdef->d_BB_PLL_CONFIG_FRAC_LSB) +#define BB_PLL_CONFIG_FRAC_MASK \ + (scn->targetdef->d_BB_PLL_CONFIG_FRAC_MASK) +#define WLAN_PLL_SETTLE_TIME_MSB \ + (scn->targetdef->d_WLAN_PLL_SETTLE_TIME_MSB) +#define WLAN_PLL_SETTLE_TIME_LSB \ + (scn->targetdef->d_WLAN_PLL_SETTLE_TIME_LSB) +#define WLAN_PLL_SETTLE_TIME_MASK \ + (scn->targetdef->d_WLAN_PLL_SETTLE_TIME_MASK) +#define WLAN_PLL_SETTLE_OFFSET \ + (scn->targetdef->d_WLAN_PLL_SETTLE_OFFSET) +#define WLAN_PLL_SETTLE_SW_MASK \ + (scn->targetdef->d_WLAN_PLL_SETTLE_SW_MASK) +#define WLAN_PLL_SETTLE_RSTMASK \ + (scn->targetdef->d_WLAN_PLL_SETTLE_RSTMASK) +#define WLAN_PLL_SETTLE_RESET \ + (scn->targetdef->d_WLAN_PLL_SETTLE_RESET) +#define WLAN_PLL_CONTROL_NOPWD_MSB \ + (scn->targetdef->d_WLAN_PLL_CONTROL_NOPWD_MSB) +#define WLAN_PLL_CONTROL_NOPWD_LSB \ + (scn->targetdef->d_WLAN_PLL_CONTROL_NOPWD_LSB) +#define WLAN_PLL_CONTROL_NOPWD_MASK \ + (scn->targetdef->d_WLAN_PLL_CONTROL_NOPWD_MASK) +#define WLAN_PLL_CONTROL_BYPASS_MSB \ + (scn->targetdef->d_WLAN_PLL_CONTROL_BYPASS_MSB) +#define WLAN_PLL_CONTROL_BYPASS_LSB \ + (scn->targetdef->d_WLAN_PLL_CONTROL_BYPASS_LSB) +#define WLAN_PLL_CONTROL_BYPASS_MASK \ + (scn->targetdef->d_WLAN_PLL_CONTROL_BYPASS_MASK) +#define WLAN_PLL_CONTROL_BYPASS_RESET \ + (scn->targetdef->d_WLAN_PLL_CONTROL_BYPASS_RESET) +#define WLAN_PLL_CONTROL_CLK_SEL_MSB \ + (scn->targetdef->d_WLAN_PLL_CONTROL_CLK_SEL_MSB) +#define WLAN_PLL_CONTROL_CLK_SEL_LSB \ + (scn->targetdef->d_WLAN_PLL_CONTROL_CLK_SEL_LSB) +#define WLAN_PLL_CONTROL_CLK_SEL_MASK \ + (scn->targetdef->d_WLAN_PLL_CONTROL_CLK_SEL_MASK) +#define WLAN_PLL_CONTROL_CLK_SEL_RESET \ + (scn->targetdef->d_WLAN_PLL_CONTROL_CLK_SEL_RESET) +#define WLAN_PLL_CONTROL_REFDIV_MSB \ + (scn->targetdef->d_WLAN_PLL_CONTROL_REFDIV_MSB) +#define WLAN_PLL_CONTROL_REFDIV_LSB \ + (scn->targetdef->d_WLAN_PLL_CONTROL_REFDIV_LSB) +#define WLAN_PLL_CONTROL_REFDIV_MASK \ + (scn->targetdef->d_WLAN_PLL_CONTROL_REFDIV_MASK) +#define WLAN_PLL_CONTROL_REFDIV_RESET \ + (scn->targetdef->d_WLAN_PLL_CONTROL_REFDIV_RESET) +#define WLAN_PLL_CONTROL_DIV_MSB \ + (scn->targetdef->d_WLAN_PLL_CONTROL_DIV_MSB) +#define WLAN_PLL_CONTROL_DIV_LSB \ + (scn->targetdef->d_WLAN_PLL_CONTROL_DIV_LSB) +#define WLAN_PLL_CONTROL_DIV_MASK \ + (scn->targetdef->d_WLAN_PLL_CONTROL_DIV_MASK) +#define WLAN_PLL_CONTROL_DIV_RESET \ + (scn->targetdef->d_WLAN_PLL_CONTROL_DIV_RESET) +#define WLAN_PLL_CONTROL_OFFSET \ + (scn->targetdef->d_WLAN_PLL_CONTROL_OFFSET) +#define WLAN_PLL_CONTROL_SW_MASK \ + (scn->targetdef->d_WLAN_PLL_CONTROL_SW_MASK) +#define WLAN_PLL_CONTROL_RSTMASK \ + (scn->targetdef->d_WLAN_PLL_CONTROL_RSTMASK) +#define WLAN_PLL_CONTROL_RESET \ + (scn->targetdef->d_WLAN_PLL_CONTROL_RESET) +#define SOC_CORE_CLK_CTRL_OFFSET \ + (scn->targetdef->d_SOC_CORE_CLK_CTRL_OFFSET) +#define SOC_CORE_CLK_CTRL_DIV_MSB \ + (scn->targetdef->d_SOC_CORE_CLK_CTRL_DIV_MSB) +#define SOC_CORE_CLK_CTRL_DIV_LSB \ + (scn->targetdef->d_SOC_CORE_CLK_CTRL_DIV_LSB) +#define SOC_CORE_CLK_CTRL_DIV_MASK \ + (scn->targetdef->d_SOC_CORE_CLK_CTRL_DIV_MASK) +#define RTC_SYNC_STATUS_PLL_CHANGING_MSB \ + (scn->targetdef->d_RTC_SYNC_STATUS_PLL_CHANGING_MSB) +#define RTC_SYNC_STATUS_PLL_CHANGING_LSB \ + (scn->targetdef->d_RTC_SYNC_STATUS_PLL_CHANGING_LSB) +#define RTC_SYNC_STATUS_PLL_CHANGING_MASK \ + (scn->targetdef->d_RTC_SYNC_STATUS_PLL_CHANGING_MASK) +#define RTC_SYNC_STATUS_PLL_CHANGING_RESET \ + (scn->targetdef->d_RTC_SYNC_STATUS_PLL_CHANGING_RESET) +#define RTC_SYNC_STATUS_OFFSET \ + (scn->targetdef->d_RTC_SYNC_STATUS_OFFSET) +#define SOC_CPU_CLOCK_OFFSET \ + (scn->targetdef->d_SOC_CPU_CLOCK_OFFSET) +#define SOC_CPU_CLOCK_STANDARD_MSB \ + (scn->targetdef->d_SOC_CPU_CLOCK_STANDARD_MSB) +#define SOC_CPU_CLOCK_STANDARD_LSB \ + (scn->targetdef->d_SOC_CPU_CLOCK_STANDARD_LSB) +#define SOC_CPU_CLOCK_STANDARD_MASK \ + (scn->targetdef->d_SOC_CPU_CLOCK_STANDARD_MASK) +/* PLL end */ + +/* SET macros */ +#define WLAN_SYSTEM_SLEEP_DISABLE_SET(x) \ + (((x) << WLAN_SYSTEM_SLEEP_DISABLE_LSB) & \ + WLAN_SYSTEM_SLEEP_DISABLE_MASK) +#define SI_CONFIG_BIDIR_OD_DATA_SET(x) \ + (((x) << SI_CONFIG_BIDIR_OD_DATA_LSB) & \ + SI_CONFIG_BIDIR_OD_DATA_MASK) +#define SI_CONFIG_I2C_SET(x) \ + (((x) << SI_CONFIG_I2C_LSB) & SI_CONFIG_I2C_MASK) +#define SI_CONFIG_POS_SAMPLE_SET(x) \ + (((x) << SI_CONFIG_POS_SAMPLE_LSB) & \ + SI_CONFIG_POS_SAMPLE_MASK) +#define SI_CONFIG_INACTIVE_CLK_SET(x) \ + (((x) << SI_CONFIG_INACTIVE_CLK_LSB) & \ + SI_CONFIG_INACTIVE_CLK_MASK) +#define SI_CONFIG_INACTIVE_DATA_SET(x) \ + (((x) << SI_CONFIG_INACTIVE_DATA_LSB) & \ + SI_CONFIG_INACTIVE_DATA_MASK) +#define SI_CONFIG_DIVIDER_SET(x) \ + (((x) << SI_CONFIG_DIVIDER_LSB) & SI_CONFIG_DIVIDER_MASK) +#define SI_CS_START_SET(x) \ + (((x) << SI_CS_START_LSB) & SI_CS_START_MASK) +#define SI_CS_RX_CNT_SET(x) \ + (((x) << SI_CS_RX_CNT_LSB) & SI_CS_RX_CNT_MASK) +#define SI_CS_TX_CNT_SET(x) \ + (((x) << SI_CS_TX_CNT_LSB) & SI_CS_TX_CNT_MASK) +#define LPO_CAL_ENABLE_SET(x) \ + (((x) << LPO_CAL_ENABLE_LSB) & LPO_CAL_ENABLE_MASK) +#define CPU_CLOCK_STANDARD_SET(x) \ + (((x) << CPU_CLOCK_STANDARD_LSB) & CPU_CLOCK_STANDARD_MASK) +#define CLOCK_GPIO_BT_CLK_OUT_EN_SET(x) \ + (((x) << CLOCK_GPIO_BT_CLK_OUT_EN_LSB) & \ + CLOCK_GPIO_BT_CLK_OUT_EN_MASK) +/* copy_engine.c */ +#define SRC_WATERMARK_LOW_SET(x) \ + (((x) << SRC_WATERMARK_LOW_LSB) & SRC_WATERMARK_LOW_MASK) +#define SRC_WATERMARK_HIGH_SET(x) \ + (((x) << SRC_WATERMARK_HIGH_LSB) & SRC_WATERMARK_HIGH_MASK) +#define DST_WATERMARK_LOW_SET(x) \ + (((x) << DST_WATERMARK_LOW_LSB) & DST_WATERMARK_LOW_MASK) +#define DST_WATERMARK_HIGH_SET(x) \ + (((x) << DST_WATERMARK_HIGH_LSB) & DST_WATERMARK_HIGH_MASK) +#define CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_GET(x) (((x) & \ + CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_MASK) >> \ + CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_LSB) +#define CE_CTRL1_DMAX_LENGTH_SET(x) \ + (((x) << CE_CTRL1_DMAX_LENGTH_LSB) & CE_CTRL1_DMAX_LENGTH_MASK) +#define CE_CTRL1_SRC_RING_BYTE_SWAP_EN_SET(x) \ + (((x) << CE_CTRL1_SRC_RING_BYTE_SWAP_EN_LSB) & \ + CE_CTRL1_SRC_RING_BYTE_SWAP_EN_MASK) +#define CE_CTRL1_DST_RING_BYTE_SWAP_EN_SET(x) \ + (((x) << CE_CTRL1_DST_RING_BYTE_SWAP_EN_LSB) & \ + CE_CTRL1_DST_RING_BYTE_SWAP_EN_MASK) +#define WLAN_DEBUG_INPUT_SEL_SRC_GET(x) \ + (((x) & \ + WLAN_DEBUG_INPUT_SEL_SRC_MASK) >> \ + WLAN_DEBUG_INPUT_SEL_SRC_LSB) +#define WLAN_DEBUG_INPUT_SEL_SRC_SET(x) \ + (((x) << WLAN_DEBUG_INPUT_SEL_SRC_LSB) & \ + WLAN_DEBUG_INPUT_SEL_SRC_MASK) +#define WLAN_DEBUG_CONTROL_ENABLE_GET(x) \ + (((x) & \ + WLAN_DEBUG_CONTROL_ENABLE_MASK) >> \ + WLAN_DEBUG_CONTROL_ENABLE_LSB) +#define WLAN_DEBUG_CONTROL_ENABLE_SET(x) \ + (((x) << WLAN_DEBUG_CONTROL_ENABLE_LSB) & \ + WLAN_DEBUG_CONTROL_ENABLE_MASK) +#define WLAN_DEBUG_OUT_DATA_GET(x) \ + (((x) & WLAN_DEBUG_OUT_DATA_MASK) >> WLAN_DEBUG_OUT_DATA_LSB) +#define WLAN_DEBUG_OUT_DATA_SET(x) \ + (((x) << WLAN_DEBUG_OUT_DATA_LSB) & WLAN_DEBUG_OUT_DATA_MASK) +#define AMBA_DEBUG_BUS_PCIE_DEBUG_SEL_GET(x) \ + (((x) & \ + AMBA_DEBUG_BUS_PCIE_DEBUG_SEL_MASK) >> \ + AMBA_DEBUG_BUS_PCIE_DEBUG_SEL_LSB) +#define AMBA_DEBUG_BUS_PCIE_DEBUG_SEL_SET(x) \ + (((x) << AMBA_DEBUG_BUS_PCIE_DEBUG_SEL_LSB) & \ + AMBA_DEBUG_BUS_PCIE_DEBUG_SEL_MASK) +#define AMBA_DEBUG_BUS_SEL_GET(x) \ + (((x) & AMBA_DEBUG_BUS_SEL_MASK) >> AMBA_DEBUG_BUS_SEL_LSB) +#define AMBA_DEBUG_BUS_SEL_SET(x) \ + (((x) << AMBA_DEBUG_BUS_SEL_LSB) & AMBA_DEBUG_BUS_SEL_MASK) +#define CE_WRAPPER_DEBUG_SEL_GET(x) \ + (((x) & CE_WRAPPER_DEBUG_SEL_MASK) >> CE_WRAPPER_DEBUG_SEL_LSB) +#define CE_WRAPPER_DEBUG_SEL_SET(x) \ + (((x) << CE_WRAPPER_DEBUG_SEL_LSB) & CE_WRAPPER_DEBUG_SEL_MASK) +#define CE_DEBUG_SEL_GET(x) \ + (((x) & CE_DEBUG_SEL_MASK) >> CE_DEBUG_SEL_LSB) +#define CE_DEBUG_SEL_SET(x) \ + (((x) << CE_DEBUG_SEL_LSB) & CE_DEBUG_SEL_MASK) +/* end */ +/* PLL start */ +#define EFUSE_XTAL_SEL_GET(x) \ + (((x) & EFUSE_XTAL_SEL_MASK) >> EFUSE_XTAL_SEL_LSB) +#define EFUSE_XTAL_SEL_SET(x) \ + (((x) << EFUSE_XTAL_SEL_LSB) & EFUSE_XTAL_SEL_MASK) +#define BB_PLL_CONFIG_OUTDIV_GET(x) \ + (((x) & BB_PLL_CONFIG_OUTDIV_MASK) >> BB_PLL_CONFIG_OUTDIV_LSB) +#define BB_PLL_CONFIG_OUTDIV_SET(x) \ + (((x) << BB_PLL_CONFIG_OUTDIV_LSB) & BB_PLL_CONFIG_OUTDIV_MASK) +#define BB_PLL_CONFIG_FRAC_GET(x) \ + (((x) & BB_PLL_CONFIG_FRAC_MASK) >> BB_PLL_CONFIG_FRAC_LSB) +#define BB_PLL_CONFIG_FRAC_SET(x) \ + (((x) << BB_PLL_CONFIG_FRAC_LSB) & BB_PLL_CONFIG_FRAC_MASK) +#define WLAN_PLL_SETTLE_TIME_GET(x) \ + (((x) & WLAN_PLL_SETTLE_TIME_MASK) >> WLAN_PLL_SETTLE_TIME_LSB) +#define WLAN_PLL_SETTLE_TIME_SET(x) \ + (((x) << WLAN_PLL_SETTLE_TIME_LSB) & WLAN_PLL_SETTLE_TIME_MASK) +#define WLAN_PLL_CONTROL_NOPWD_GET(x) \ + (((x) & \ + WLAN_PLL_CONTROL_NOPWD_MASK) >> \ + WLAN_PLL_CONTROL_NOPWD_LSB) +#define WLAN_PLL_CONTROL_NOPWD_SET(x) \ + (((x) << WLAN_PLL_CONTROL_NOPWD_LSB) & \ + WLAN_PLL_CONTROL_NOPWD_MASK) +#define WLAN_PLL_CONTROL_BYPASS_GET(x) \ + (((x) & \ + WLAN_PLL_CONTROL_BYPASS_MASK) >> \ + WLAN_PLL_CONTROL_BYPASS_LSB) +#define WLAN_PLL_CONTROL_BYPASS_SET(x) \ + (((x) << WLAN_PLL_CONTROL_BYPASS_LSB) & \ + WLAN_PLL_CONTROL_BYPASS_MASK) +#define WLAN_PLL_CONTROL_CLK_SEL_GET(x) \ + (((x) & \ + WLAN_PLL_CONTROL_CLK_SEL_MASK) >> \ + WLAN_PLL_CONTROL_CLK_SEL_LSB) +#define WLAN_PLL_CONTROL_CLK_SEL_SET(x) \ + (((x) << WLAN_PLL_CONTROL_CLK_SEL_LSB) & \ + WLAN_PLL_CONTROL_CLK_SEL_MASK) +#define WLAN_PLL_CONTROL_REFDIV_GET(x) \ + (((x) & \ + WLAN_PLL_CONTROL_REFDIV_MASK) >> \ + WLAN_PLL_CONTROL_REFDIV_LSB) +#define WLAN_PLL_CONTROL_REFDIV_SET(x) \ + (((x) << WLAN_PLL_CONTROL_REFDIV_LSB) & \ + WLAN_PLL_CONTROL_REFDIV_MASK) +#define WLAN_PLL_CONTROL_DIV_GET(x) \ + (((x) & \ + WLAN_PLL_CONTROL_DIV_MASK) >> \ + WLAN_PLL_CONTROL_DIV_LSB) +#define WLAN_PLL_CONTROL_DIV_SET(x) \ + (((x) << WLAN_PLL_CONTROL_DIV_LSB) & \ + WLAN_PLL_CONTROL_DIV_MASK) +#define SOC_CORE_CLK_CTRL_DIV_GET(x) \ + (((x) & \ + SOC_CORE_CLK_CTRL_DIV_MASK) >> \ + SOC_CORE_CLK_CTRL_DIV_LSB) +#define SOC_CORE_CLK_CTRL_DIV_SET(x) \ + (((x) << SOC_CORE_CLK_CTRL_DIV_LSB) & \ + SOC_CORE_CLK_CTRL_DIV_MASK) +#define RTC_SYNC_STATUS_PLL_CHANGING_GET(x) \ + (((x) & \ + RTC_SYNC_STATUS_PLL_CHANGING_MASK) >> \ + RTC_SYNC_STATUS_PLL_CHANGING_LSB) +#define RTC_SYNC_STATUS_PLL_CHANGING_SET(x) \ + (((x) << RTC_SYNC_STATUS_PLL_CHANGING_LSB) & \ + RTC_SYNC_STATUS_PLL_CHANGING_MASK) +#define SOC_CPU_CLOCK_STANDARD_GET(x) \ + (((x) & \ + SOC_CPU_CLOCK_STANDARD_MASK) >> \ + SOC_CPU_CLOCK_STANDARD_LSB) +#define SOC_CPU_CLOCK_STANDARD_SET(x) \ + (((x) << SOC_CPU_CLOCK_STANDARD_LSB) & \ + SOC_CPU_CLOCK_STANDARD_MASK) +/* PLL end */ + +typedef struct hostdef_s { + uint32_t d_INT_STATUS_ENABLE_ERROR_LSB; + uint32_t d_INT_STATUS_ENABLE_ERROR_MASK; + uint32_t d_INT_STATUS_ENABLE_CPU_LSB; + uint32_t d_INT_STATUS_ENABLE_CPU_MASK; + uint32_t d_INT_STATUS_ENABLE_COUNTER_LSB; + uint32_t d_INT_STATUS_ENABLE_COUNTER_MASK; + uint32_t d_INT_STATUS_ENABLE_MBOX_DATA_LSB; + uint32_t d_INT_STATUS_ENABLE_MBOX_DATA_MASK; + uint32_t d_ERROR_STATUS_ENABLE_RX_UNDERFLOW_LSB; + uint32_t d_ERROR_STATUS_ENABLE_RX_UNDERFLOW_MASK; + uint32_t d_ERROR_STATUS_ENABLE_TX_OVERFLOW_LSB; + uint32_t d_ERROR_STATUS_ENABLE_TX_OVERFLOW_MASK; + uint32_t d_COUNTER_INT_STATUS_ENABLE_BIT_LSB; + uint32_t d_COUNTER_INT_STATUS_ENABLE_BIT_MASK; + uint32_t d_INT_STATUS_ENABLE_ADDRESS; + uint32_t d_CPU_INT_STATUS_ENABLE_BIT_LSB; + uint32_t d_CPU_INT_STATUS_ENABLE_BIT_MASK; + uint32_t d_HOST_INT_STATUS_ADDRESS; + uint32_t d_CPU_INT_STATUS_ADDRESS; + uint32_t d_ERROR_INT_STATUS_ADDRESS; + uint32_t d_ERROR_INT_STATUS_WAKEUP_MASK; + uint32_t d_ERROR_INT_STATUS_WAKEUP_LSB; + uint32_t d_ERROR_INT_STATUS_RX_UNDERFLOW_MASK; + uint32_t d_ERROR_INT_STATUS_RX_UNDERFLOW_LSB; + uint32_t d_ERROR_INT_STATUS_TX_OVERFLOW_MASK; + uint32_t d_ERROR_INT_STATUS_TX_OVERFLOW_LSB; + uint32_t d_COUNT_DEC_ADDRESS; + uint32_t d_HOST_INT_STATUS_CPU_MASK; + uint32_t d_HOST_INT_STATUS_CPU_LSB; + uint32_t d_HOST_INT_STATUS_ERROR_MASK; + uint32_t d_HOST_INT_STATUS_ERROR_LSB; + uint32_t d_HOST_INT_STATUS_COUNTER_MASK; + uint32_t d_HOST_INT_STATUS_COUNTER_LSB; + uint32_t d_RX_LOOKAHEAD_VALID_ADDRESS; + uint32_t d_WINDOW_DATA_ADDRESS; + uint32_t d_WINDOW_READ_ADDR_ADDRESS; + uint32_t d_WINDOW_WRITE_ADDR_ADDRESS; + uint32_t d_SOC_GLOBAL_RESET_ADDRESS; + uint32_t d_RTC_STATE_ADDRESS; + uint32_t d_RTC_STATE_COLD_RESET_MASK; + uint32_t d_PCIE_LOCAL_BASE_ADDRESS; + uint32_t d_PCIE_SOC_WAKE_RESET; + uint32_t d_PCIE_SOC_WAKE_ADDRESS; + uint32_t d_PCIE_SOC_WAKE_V_MASK; + uint32_t d_RTC_STATE_V_MASK; + uint32_t d_RTC_STATE_V_LSB; + uint32_t d_FW_IND_EVENT_PENDING; + uint32_t d_FW_IND_INITIALIZED; + uint32_t d_RTC_STATE_V_ON; +#if defined(SDIO_3_0) + uint32_t d_HOST_INT_STATUS_MBOX_DATA_MASK; + uint32_t d_HOST_INT_STATUS_MBOX_DATA_LSB; +#endif + uint32_t d_PCIE_SOC_RDY_STATUS_ADDRESS; + uint32_t d_PCIE_SOC_RDY_STATUS_BAR_MASK; + uint32_t d_SOC_PCIE_BASE_ADDRESS; + uint32_t d_MSI_MAGIC_ADR_ADDRESS; + uint32_t d_MSI_MAGIC_ADDRESS; +} HOST_REGISTER_TABLE; + +#define INT_STATUS_ENABLE_ERROR_LSB \ + (scn->hostdef->d_INT_STATUS_ENABLE_ERROR_LSB) +#define INT_STATUS_ENABLE_ERROR_MASK \ + (scn->hostdef->d_INT_STATUS_ENABLE_ERROR_MASK) +#define INT_STATUS_ENABLE_CPU_LSB \ + (scn->hostdef->d_INT_STATUS_ENABLE_CPU_LSB) +#define INT_STATUS_ENABLE_CPU_MASK \ + (scn->hostdef->d_INT_STATUS_ENABLE_CPU_MASK) +#define INT_STATUS_ENABLE_COUNTER_LSB \ + (scn->hostdef->d_INT_STATUS_ENABLE_COUNTER_LSB) +#define INT_STATUS_ENABLE_COUNTER_MASK \ + (scn->hostdef->d_INT_STATUS_ENABLE_COUNTER_MASK) +#define INT_STATUS_ENABLE_MBOX_DATA_LSB \ + (scn->hostdef->d_INT_STATUS_ENABLE_MBOX_DATA_LSB) +#define INT_STATUS_ENABLE_MBOX_DATA_MASK \ + (scn->hostdef->d_INT_STATUS_ENABLE_MBOX_DATA_MASK) +#define ERROR_STATUS_ENABLE_RX_UNDERFLOW_LSB \ + (scn->hostdef->d_ERROR_STATUS_ENABLE_RX_UNDERFLOW_LSB) +#define ERROR_STATUS_ENABLE_RX_UNDERFLOW_MASK \ + (scn->hostdef->d_ERROR_STATUS_ENABLE_RX_UNDERFLOW_MASK) +#define ERROR_STATUS_ENABLE_TX_OVERFLOW_LSB\ + (scn->hostdef->d_ERROR_STATUS_ENABLE_TX_OVERFLOW_LSB) +#define ERROR_STATUS_ENABLE_TX_OVERFLOW_MASK \ + (scn->hostdef->d_ERROR_STATUS_ENABLE_TX_OVERFLOW_MASK) +#define COUNTER_INT_STATUS_ENABLE_BIT_LSB \ + (scn->hostdef->d_COUNTER_INT_STATUS_ENABLE_BIT_LSB) +#define COUNTER_INT_STATUS_ENABLE_BIT_MASK \ + (scn->hostdef->d_COUNTER_INT_STATUS_ENABLE_BIT_MASK) +#define INT_STATUS_ENABLE_ADDRESS \ + (scn->hostdef->d_INT_STATUS_ENABLE_ADDRESS) +#define CPU_INT_STATUS_ENABLE_BIT_LSB \ + (scn->hostdef->d_CPU_INT_STATUS_ENABLE_BIT_LSB) +#define CPU_INT_STATUS_ENABLE_BIT_MASK \ + (scn->hostdef->d_CPU_INT_STATUS_ENABLE_BIT_MASK) +#define HOST_INT_STATUS_ADDRESS \ + (scn->hostdef->d_HOST_INT_STATUS_ADDRESS) +#define CPU_INT_STATUS_ADDRESS \ + (scn->hostdef->d_CPU_INT_STATUS_ADDRESS) +#define ERROR_INT_STATUS_ADDRESS \ + (scn->hostdef->d_ERROR_INT_STATUS_ADDRESS) +#define ERROR_INT_STATUS_WAKEUP_MASK \ + (scn->hostdef->d_ERROR_INT_STATUS_WAKEUP_MASK) +#define ERROR_INT_STATUS_WAKEUP_LSB \ + (scn->hostdef->d_ERROR_INT_STATUS_WAKEUP_LSB) +#define ERROR_INT_STATUS_RX_UNDERFLOW_MASK \ + (scn->hostdef->d_ERROR_INT_STATUS_RX_UNDERFLOW_MASK) +#define ERROR_INT_STATUS_RX_UNDERFLOW_LSB \ + (scn->hostdef->d_ERROR_INT_STATUS_RX_UNDERFLOW_LSB) +#define ERROR_INT_STATUS_TX_OVERFLOW_MASK \ + (scn->hostdef->d_ERROR_INT_STATUS_TX_OVERFLOW_MASK) +#define ERROR_INT_STATUS_TX_OVERFLOW_LSB \ + (scn->hostdef->d_ERROR_INT_STATUS_TX_OVERFLOW_LSB) +#define COUNT_DEC_ADDRESS \ + (scn->hostdef->d_COUNT_DEC_ADDRESS) +#define HOST_INT_STATUS_CPU_MASK \ + (scn->hostdef->d_HOST_INT_STATUS_CPU_MASK) +#define HOST_INT_STATUS_CPU_LSB \ + (scn->hostdef->d_HOST_INT_STATUS_CPU_LSB) +#define HOST_INT_STATUS_ERROR_MASK \ + (scn->hostdef->d_HOST_INT_STATUS_ERROR_MASK) +#define HOST_INT_STATUS_ERROR_LSB \ + (scn->hostdef->d_HOST_INT_STATUS_ERROR_LSB) +#define HOST_INT_STATUS_COUNTER_MASK \ + (scn->hostdef->d_HOST_INT_STATUS_COUNTER_MASK) +#define HOST_INT_STATUS_COUNTER_LSB \ + (scn->hostdef->d_HOST_INT_STATUS_COUNTER_LSB) +#define RX_LOOKAHEAD_VALID_ADDRESS \ + (scn->hostdef->d_RX_LOOKAHEAD_VALID_ADDRESS) +#define WINDOW_DATA_ADDRESS \ + (scn->hostdef->d_WINDOW_DATA_ADDRESS) +#define WINDOW_READ_ADDR_ADDRESS \ + (scn->hostdef->d_WINDOW_READ_ADDR_ADDRESS) +#define WINDOW_WRITE_ADDR_ADDRESS \ + (scn->hostdef->d_WINDOW_WRITE_ADDR_ADDRESS) +#define SOC_GLOBAL_RESET_ADDRESS \ + (scn->hostdef->d_SOC_GLOBAL_RESET_ADDRESS) +#define RTC_STATE_ADDRESS \ + (scn->hostdef->d_RTC_STATE_ADDRESS) +#define RTC_STATE_COLD_RESET_MASK \ + (scn->hostdef->d_RTC_STATE_COLD_RESET_MASK) +#define PCIE_LOCAL_BASE_ADDRESS \ + (scn->hostdef->d_PCIE_LOCAL_BASE_ADDRESS) +#define PCIE_SOC_WAKE_RESET \ + (scn->hostdef->d_PCIE_SOC_WAKE_RESET) +#define PCIE_SOC_WAKE_ADDRESS \ + (scn->hostdef->d_PCIE_SOC_WAKE_ADDRESS) +#define PCIE_SOC_WAKE_V_MASK \ + (scn->hostdef->d_PCIE_SOC_WAKE_V_MASK) +#define RTC_STATE_V_MASK \ + (scn->hostdef->d_RTC_STATE_V_MASK) +#define RTC_STATE_V_LSB \ + (scn->hostdef->d_RTC_STATE_V_LSB) +#define FW_IND_EVENT_PENDING \ + (scn->hostdef->d_FW_IND_EVENT_PENDING) +#define FW_IND_INITIALIZED \ + (scn->hostdef->d_FW_IND_INITIALIZED) +#define RTC_STATE_V_ON \ + (scn->hostdef->d_RTC_STATE_V_ON) +#if defined(SDIO_3_0) +#define HOST_INT_STATUS_MBOX_DATA_MASK \ + (scn->hostdef->d_HOST_INT_STATUS_MBOX_DATA_MASK) +#define HOST_INT_STATUS_MBOX_DATA_LSB \ + (scn->hostdef->d_HOST_INT_STATUS_MBOX_DATA_LSB) +#endif + +#if !defined(SOC_PCIE_BASE_ADDRESS) +#define SOC_PCIE_BASE_ADDRESS 0 +#endif + +#if !defined(PCIE_SOC_RDY_STATUS_ADDRESS) +#define PCIE_SOC_RDY_STATUS_ADDRESS 0 +#define PCIE_SOC_RDY_STATUS_BAR_MASK 0 +#endif + +#if !defined(MSI_MAGIC_ADR_ADDRESS) +#define MSI_MAGIC_ADR_ADDRESS 0 +#define MSI_MAGIC_ADDRESS 0 +#endif + +/* SET/GET macros */ +#define INT_STATUS_ENABLE_ERROR_SET(x) \ + (((x) << INT_STATUS_ENABLE_ERROR_LSB) & \ + INT_STATUS_ENABLE_ERROR_MASK) +#define INT_STATUS_ENABLE_CPU_SET(x) \ + (((x) << INT_STATUS_ENABLE_CPU_LSB) & \ + INT_STATUS_ENABLE_CPU_MASK) +#define INT_STATUS_ENABLE_COUNTER_SET(x) \ + (((x) << INT_STATUS_ENABLE_COUNTER_LSB) & \ + INT_STATUS_ENABLE_COUNTER_MASK) +#define INT_STATUS_ENABLE_MBOX_DATA_SET(x) \ + (((x) << INT_STATUS_ENABLE_MBOX_DATA_LSB) & \ + INT_STATUS_ENABLE_MBOX_DATA_MASK) +#define CPU_INT_STATUS_ENABLE_BIT_SET(x) \ + (((x) << CPU_INT_STATUS_ENABLE_BIT_LSB) & \ + CPU_INT_STATUS_ENABLE_BIT_MASK) +#define ERROR_STATUS_ENABLE_RX_UNDERFLOW_SET(x) \ + (((x) << ERROR_STATUS_ENABLE_RX_UNDERFLOW_LSB) & \ + ERROR_STATUS_ENABLE_RX_UNDERFLOW_MASK) +#define ERROR_STATUS_ENABLE_TX_OVERFLOW_SET(x)\ + (((x) << ERROR_STATUS_ENABLE_TX_OVERFLOW_LSB) & \ + ERROR_STATUS_ENABLE_TX_OVERFLOW_MASK) +#define COUNTER_INT_STATUS_ENABLE_BIT_SET(x) \ + (((x) << COUNTER_INT_STATUS_ENABLE_BIT_LSB) & \ + COUNTER_INT_STATUS_ENABLE_BIT_MASK) +#define ERROR_INT_STATUS_WAKEUP_GET(x) \ + (((x) & ERROR_INT_STATUS_WAKEUP_MASK) >> \ + ERROR_INT_STATUS_WAKEUP_LSB) +#define ERROR_INT_STATUS_RX_UNDERFLOW_GET(x) \ + (((x) & ERROR_INT_STATUS_RX_UNDERFLOW_MASK) >> \ + ERROR_INT_STATUS_RX_UNDERFLOW_LSB) +#define ERROR_INT_STATUS_TX_OVERFLOW_GET(x) \ + (((x) & ERROR_INT_STATUS_TX_OVERFLOW_MASK) >> \ + ERROR_INT_STATUS_TX_OVERFLOW_LSB) +#define HOST_INT_STATUS_CPU_GET(x) \ + (((x) & HOST_INT_STATUS_CPU_MASK) >> \ + HOST_INT_STATUS_CPU_LSB) +#define HOST_INT_STATUS_ERROR_GET(x) \ + (((x) & HOST_INT_STATUS_ERROR_MASK) >> \ + HOST_INT_STATUS_ERROR_LSB) +#define HOST_INT_STATUS_COUNTER_GET(x) \ + (((x) & HOST_INT_STATUS_COUNTER_MASK) >> \ + HOST_INT_STATUS_COUNTER_LSB) +#define RTC_STATE_V_GET(x) \ + (((x) & RTC_STATE_V_MASK) >> RTC_STATE_V_LSB) +#if defined(SDIO_3_0) +#define HOST_INT_STATUS_MBOX_DATA_GET(x) \ + (((x) & HOST_INT_STATUS_MBOX_DATA_MASK) >> \ + HOST_INT_STATUS_MBOX_DATA_LSB) +#endif + +#define INVALID_REG_LOC_DUMMY_DATA 0xAA + + + +#define ROME_USB_RTC_SOC_BASE_ADDRESS 0x00000800 +#define ROME_USB_SOC_RESET_CONTROL_COLD_RST_LSB 0x0 +#define SOC_RESET_CONTROL_COLD_RST_LSB 8 +#define SOC_RESET_CONTROL_COLD_RST_MASK 0x00000100 +#define SOC_RESET_CONTROL_COLD_RST_SET(x) \ + (((x) << SOC_RESET_CONTROL_COLD_RST_LSB) & \ + SOC_RESET_CONTROL_COLD_RST_MASK) + +#define AR6320_CORE_CLK_DIV_ADDR 0x403fa8 +#define AR6320_CPU_PLL_INIT_DONE_ADDR 0x403fd0 +#define AR6320_CPU_SPEED_ADDR 0x403fa4 +#define AR6320V2_CORE_CLK_DIV_ADDR 0x403fd8 +#define AR6320V2_CPU_PLL_INIT_DONE_ADDR 0x403fd0 +#define AR6320V2_CPU_SPEED_ADDR 0x403fd4 +#define AR6320V3_CORE_CLK_DIV_ADDR 0x404028 +#define AR6320V3_CPU_PLL_INIT_DONE_ADDR 0x404020 +#define AR6320V3_CPU_SPEED_ADDR 0x404024 + +typedef enum { + /* Unsupported ref clock -- use PLL Bypass */ + SOC_REFCLK_UNKNOWN = -1, + SOC_REFCLK_48_MHZ = 0, + SOC_REFCLK_19_2_MHZ = 1, + SOC_REFCLK_24_MHZ = 2, + SOC_REFCLK_26_MHZ = 3, + SOC_REFCLK_37_4_MHZ = 4, + SOC_REFCLK_38_4_MHZ = 5, + SOC_REFCLK_40_MHZ = 6, + SOC_REFCLK_52_MHZ = 7, +} A_refclk_speed_t; + +#define A_REFCLK_UNKNOWN SOC_REFCLK_UNKNOWN +#define A_REFCLK_48_MHZ SOC_REFCLK_48_MHZ +#define A_REFCLK_19_2_MHZ SOC_REFCLK_19_2_MHZ +#define A_REFCLK_24_MHZ SOC_REFCLK_24_MHZ +#define A_REFCLK_26_MHZ SOC_REFCLK_26_MHZ +#define A_REFCLK_37_4_MHZ SOC_REFCLK_37_4_MHZ +#define A_REFCLK_38_4_MHZ SOC_REFCLK_38_4_MHZ +#define A_REFCLK_40_MHZ SOC_REFCLK_40_MHZ +#define A_REFCLK_52_MHZ SOC_REFCLK_52_MHZ + +#define TARGET_CPU_FREQ 176000000 + +struct wlan_pll_s { + u_int32_t refdiv; + u_int32_t div; + u_int32_t rnfrac; + u_int32_t outdiv; +}; + +struct cmnos_clock_s { + A_refclk_speed_t refclk_speed; + u_int32_t refclk_hz; + u_int32_t pll_settling_time; /* 50us */ + struct wlan_pll_s wlan_pll; +}; + +typedef struct TGT_REG_SECTION { + u_int32_t start_addr; + u_int32_t end_addr; +} tgt_reg_section; + +typedef struct TGT_REG_TABLE { + tgt_reg_section *section; + u_int32_t section_size; +} tgt_reg_table; +void target_register_tbl_attach(struct hif_softc *scn, + uint32_t target_type); +void hif_register_tbl_attach(struct hif_softc *scn, + uint32_t target_type); +#endif diff --git a/drivers/staging/qca-wifi-host-cmn/hif/src/usb/usbdrv.c b/drivers/staging/qca-wifi-host-cmn/hif/src/usb/usbdrv.c new file mode 100644 index 0000000000000000000000000000000000000000..1cb1d4430156aad4e2aa7aba653949ca53174efb --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/hif/src/usb/usbdrv.c @@ -0,0 +1,1267 @@ +/* + * Copyright (c) 2013-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#define ATH_MODULE_NAME hif +#include "a_debug.h" +#include "hif_usb_internal.h" +#include "if_usb.h" +#include "cds_api.h" +#include "hif_debug.h" + +#define IS_BULK_EP(attr) (((attr) & 3) == 0x02) +#define IS_INT_EP(attr) (((attr) & 3) == 0x03) +#define IS_ISOC_EP(attr) (((attr) & 3) == 0x01) +#define IS_DIR_IN(addr) ((addr) & 0x80) + +#define IS_FW_CRASH_DUMP(x)(((x == FW_ASSERT_PATTERN) || \ + (x == FW_REG_PATTERN) || \ + ((x & FW_RAMDUMP_PATTERN_MASK) == \ + FW_RAMDUMP_PATTERN)) ? 1 : 0) + +static void usb_hif_post_recv_transfers(HIF_USB_PIPE *recv_pipe, + int buffer_length); +static void usb_hif_post_recv_bundle_transfers + (HIF_USB_PIPE *recv_pipe, + int buffer_length); +static void usb_hif_cleanup_recv_urb(HIF_URB_CONTEXT *urb_context); + + +/** + * usb_hif_free_urb_to_pipe() - add urb back to urb list of a pipe + * @pipe: pointer to HIF_USB_PIPE + * @urb_context: pointer to HIF_URB_CONTEXT + * + * Return: none + */ +static void usb_hif_free_urb_to_pipe(HIF_USB_PIPE *pipe, + HIF_URB_CONTEXT *urb_context) +{ + qdf_spin_lock_irqsave(&pipe->device->cs_lock); + pipe->urb_cnt++; + DL_ListAdd(&pipe->urb_list_head, &urb_context->link); + qdf_spin_unlock_irqrestore(&pipe->device->cs_lock); +} + +/** + * usb_hif_alloc_urb_from_pipe() - remove urb back from urb list of a pipe + * @pipe: pointer to HIF_USB_PIPE + * + * Return: HIF_URB_CONTEXT urb context removed from the urb list + */ +HIF_URB_CONTEXT *usb_hif_alloc_urb_from_pipe(HIF_USB_PIPE *pipe) +{ + HIF_URB_CONTEXT *urb_context = NULL; + DL_LIST *item; + + qdf_spin_lock_irqsave(&pipe->device->cs_lock); + item = dl_list_remove_item_from_head(&pipe->urb_list_head); + if (item != NULL) { + urb_context = A_CONTAINING_STRUCT(item, HIF_URB_CONTEXT, link); + pipe->urb_cnt--; + } + qdf_spin_unlock_irqrestore(&pipe->device->cs_lock); + + return urb_context; +} + +/** + * usb_hif_dequeue_pending_transfer() - remove urb from pending xfer list + * @pipe: pointer to HIF_USB_PIPE + * + * Return: HIF_URB_CONTEXT urb context removed from the pending xfer list + */ +static HIF_URB_CONTEXT *usb_hif_dequeue_pending_transfer + (HIF_USB_PIPE *pipe) +{ + HIF_URB_CONTEXT *urb_context = NULL; + DL_LIST *item; + + qdf_spin_lock_irqsave(&pipe->device->cs_lock); + item = dl_list_remove_item_from_head(&pipe->urb_pending_list); + if (item != NULL) + urb_context = A_CONTAINING_STRUCT(item, HIF_URB_CONTEXT, link); + qdf_spin_unlock_irqrestore(&pipe->device->cs_lock); + + return urb_context; +} + +/** + * usb_hif_enqueue_pending_transfer() - add urb to pending xfer list + * @pipe: pointer to HIF_USB_PIPE + * @urb_context: pointer to HIF_URB_CONTEXT to be added to the xfer list + * + * Return: none + */ +void usb_hif_enqueue_pending_transfer(HIF_USB_PIPE *pipe, + HIF_URB_CONTEXT *urb_context) +{ + qdf_spin_lock_irqsave(&pipe->device->cs_lock); + dl_list_insert_tail(&pipe->urb_pending_list, &urb_context->link); + qdf_spin_unlock_irqrestore(&pipe->device->cs_lock); +} + + +/** + * usb_hif_remove_pending_transfer() - remove urb from its own list + * @urb_context: pointer to HIF_URB_CONTEXT to be removed + * + * Return: none + */ +void +usb_hif_remove_pending_transfer(HIF_URB_CONTEXT *urb_context) +{ + qdf_spin_lock_irqsave(&urb_context->pipe->device->cs_lock); + dl_list_remove(&urb_context->link); + qdf_spin_unlock_irqrestore(&urb_context->pipe->device->cs_lock); +} + +/** + * usb_hif_alloc_pipe_resources() - allocate urb_cnt urbs to a HIF pipe + * @pipe: pointer to HIF_USB_PIPE to which resources will be allocated + * @urb_cnt: number of urbs to be added to the HIF pipe + * + * Return: QDF_STATUS_SUCCESS if success else an appropriate QDF_STATUS error + */ +static QDF_STATUS usb_hif_alloc_pipe_resources + (HIF_USB_PIPE *pipe, int urb_cnt) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + int i; + HIF_URB_CONTEXT *urb_context; + + DL_LIST_INIT(&pipe->urb_list_head); + DL_LIST_INIT(&pipe->urb_pending_list); + + for (i = 0; i < urb_cnt; i++) { + urb_context = qdf_mem_malloc(sizeof(*urb_context)); + if (NULL == urb_context) { + status = QDF_STATUS_E_NOMEM; + HIF_ERROR("urb_context is null"); + break; + } + urb_context->pipe = pipe; + urb_context->urb = usb_alloc_urb(0, GFP_KERNEL); + + if (NULL == urb_context->urb) { + status = QDF_STATUS_E_NOMEM; + qdf_mem_free(urb_context); + HIF_ERROR("urb_context->urb is null"); + break; + } + + /* note we are only allocate the urb contexts here, the actual + * URB is + * allocated from the kernel as needed to do a transaction + */ + pipe->urb_alloc++; + + usb_hif_free_urb_to_pipe(pipe, urb_context); + } + + HIF_DBG("athusb: alloc resources lpipe:%d hpipe:0x%X urbs:%d", + pipe->logical_pipe_num, + pipe->usb_pipe_handle, + pipe->urb_alloc); + return status; +} + +/** + * usb_hif_free_pipe_resources() - free urb resources allocated to a HIF pipe + * @pipe: pointer to HIF_USB_PIPE + * + * Return: none + */ +static void usb_hif_free_pipe_resources(HIF_USB_PIPE *pipe) +{ + HIF_URB_CONTEXT *urb_context; + + if (NULL == pipe->device) { + /* nothing allocated for this pipe */ + HIF_ERROR("pipe->device is null"); + return; + } + + HIF_TRACE("athusb: free resources lpipe:%d hpipe:0x%X urbs:%d avail:%d", + pipe->logical_pipe_num, + pipe->usb_pipe_handle, pipe->urb_alloc, + pipe->urb_cnt); + + if (pipe->urb_alloc != pipe->urb_cnt) { + HIF_ERROR("athusb: urb leak! lpipe:%d hpipe:0x%X urbs:%d avail:%d", + pipe->logical_pipe_num, + pipe->usb_pipe_handle, pipe->urb_alloc, + pipe->urb_cnt); + } + + while (true) { + urb_context = usb_hif_alloc_urb_from_pipe(pipe); + if (NULL == urb_context) + break; + + if (urb_context->buf) { + qdf_nbuf_free(urb_context->buf); + urb_context->buf = NULL; + } + + usb_free_urb(urb_context->urb); + urb_context->urb = NULL; + qdf_mem_free(urb_context); + } + +} + +/** + * usb_hif_get_logical_pipe_num() - get pipe number for a particular enpoint + * @device: pointer to HIF_DEVICE_USB structure + * @ep_address: endpoint address + * @urb_count: number of urb resources to be allocated to the pipe + * + * Return: uint8_t pipe number corresponding to ep_address + */ +static uint8_t usb_hif_get_logical_pipe_num + (HIF_DEVICE_USB *device, + uint8_t ep_address, + int *urb_count) +{ + uint8_t pipe_num = HIF_USB_PIPE_INVALID; + + switch (ep_address) { + case USB_EP_ADDR_APP_CTRL_IN: + pipe_num = HIF_RX_CTRL_PIPE; + *urb_count = RX_URB_COUNT; + break; + case USB_EP_ADDR_APP_DATA_IN: + pipe_num = HIF_RX_DATA_PIPE; + *urb_count = RX_URB_COUNT; + break; + case USB_EP_ADDR_APP_INT_IN: + pipe_num = HIF_RX_INT_PIPE; + *urb_count = RX_URB_COUNT; + break; + case USB_EP_ADDR_APP_DATA2_IN: + pipe_num = HIF_RX_DATA2_PIPE; + *urb_count = RX_URB_COUNT; + break; + case USB_EP_ADDR_APP_CTRL_OUT: + pipe_num = HIF_TX_CTRL_PIPE; + *urb_count = TX_URB_COUNT; + break; + case USB_EP_ADDR_APP_DATA_LP_OUT: + pipe_num = HIF_TX_DATA_LP_PIPE; + *urb_count = TX_URB_COUNT; + break; + case USB_EP_ADDR_APP_DATA_MP_OUT: + pipe_num = HIF_TX_DATA_MP_PIPE; + *urb_count = TX_URB_COUNT; + break; + case USB_EP_ADDR_APP_DATA_HP_OUT: + pipe_num = HIF_TX_DATA_HP_PIPE; + *urb_count = TX_URB_COUNT; + break; + default: + /* note: there may be endpoints not currently used */ + break; + } + + return pipe_num; +} + +/** + * usb_hif_get_logical_pipe_num() - setup urb resources for all pipes + * @device: pointer to HIF_DEVICE_USB structure + * + * Return: QDF_STATUS_SUCCESS if success else an appropriate QDF_STATUS error + */ +QDF_STATUS usb_hif_setup_pipe_resources(HIF_DEVICE_USB *device) +{ + struct usb_interface *interface = device->interface; + struct usb_host_interface *iface_desc = interface->cur_altsetting; + struct usb_endpoint_descriptor *endpoint; + int i; + int urbcount; + QDF_STATUS status = QDF_STATUS_SUCCESS; + HIF_USB_PIPE *pipe; + uint8_t pipe_num; + + /* walk decriptors and setup pipes */ + for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { + endpoint = &iface_desc->endpoint[i].desc; + + if (IS_BULK_EP(endpoint->bmAttributes)) { + HIF_DBG("%s Bulk Ep:0x%2.2X " "maxpktsz:%d", + IS_DIR_IN(endpoint->bEndpointAddress) ? + "RX" : "TX", + endpoint->bEndpointAddress, + qdf_le16_to_cpu(endpoint->wMaxPacketSize)); + } else if (IS_INT_EP(endpoint->bmAttributes)) { + HIF_DBG("%s Int Ep:0x%2.2X maxpktsz:%d interval:%d", + IS_DIR_IN(endpoint->bEndpointAddress) ? + "RX" : "TX", + endpoint->bEndpointAddress, + qdf_le16_to_cpu(endpoint->wMaxPacketSize), + endpoint->bInterval); + } else if (IS_ISOC_EP(endpoint->bmAttributes)) { + /* TODO for ISO */ + HIF_DBG("%s ISOC Ep:0x%2.2X maxpktsz:%d interval:%d", + IS_DIR_IN(endpoint->bEndpointAddress) ? + "RX" : "TX", + endpoint->bEndpointAddress, + qdf_le16_to_cpu(endpoint->wMaxPacketSize), + endpoint->bInterval); + } + urbcount = 0; + + pipe_num = usb_hif_get_logical_pipe_num(device, + endpoint->bEndpointAddress, + &urbcount); + if (HIF_USB_PIPE_INVALID == pipe_num) + continue; + + pipe = &device->pipes[pipe_num]; + if (pipe->device != NULL) { + /*pipe was already setup */ + continue; + } + + pipe->device = device; + pipe->logical_pipe_num = pipe_num; + pipe->ep_address = endpoint->bEndpointAddress; + pipe->max_packet_size = + qdf_le16_to_cpu(endpoint->wMaxPacketSize); + + if (IS_BULK_EP(endpoint->bmAttributes)) { + if (IS_DIR_IN(pipe->ep_address)) { + pipe->usb_pipe_handle = + usb_rcvbulkpipe(device->udev, + pipe->ep_address); + } else { + pipe->usb_pipe_handle = + usb_sndbulkpipe(device->udev, + pipe->ep_address); + } + } else if (IS_INT_EP(endpoint->bmAttributes)) { + if (IS_DIR_IN(pipe->ep_address)) { + pipe->usb_pipe_handle = + usb_rcvintpipe(device->udev, + pipe->ep_address); + } else { + pipe->usb_pipe_handle = + usb_sndintpipe(device->udev, + pipe->ep_address); + } + } else if (IS_ISOC_EP(endpoint->bmAttributes)) { + /* TODO for ISO */ + if (IS_DIR_IN(pipe->ep_address)) { + pipe->usb_pipe_handle = + usb_rcvisocpipe(device->udev, + pipe->ep_address); + } else { + pipe->usb_pipe_handle = + usb_sndisocpipe(device->udev, + pipe->ep_address); + } + } + pipe->ep_desc = endpoint; + + if (!IS_DIR_IN(pipe->ep_address)) + pipe->flags |= HIF_USB_PIPE_FLAG_TX; + + status = usb_hif_alloc_pipe_resources(pipe, urbcount); + + if (!QDF_IS_STATUS_SUCCESS(status)) + break; + + } + + return status; +} + + +/** + * usb_hif_cleanup_pipe_resources() - free urb resources for all pipes + * @device: pointer to HIF_DEVICE_USB structure + * + * Return: none + */ +void usb_hif_cleanup_pipe_resources(HIF_DEVICE_USB *device) +{ + int i; + + for (i = 0; i < HIF_USB_PIPE_MAX; i++) + usb_hif_free_pipe_resources(&device->pipes[i]); +} + +/** + * usb_hif_flush_pending_transfers() - kill pending urbs for a pipe + * @pipe: pointer to HIF_USB_PIPE structure + * + * Return: none + */ +static void usb_hif_flush_pending_transfers(HIF_USB_PIPE *pipe) +{ + HIF_URB_CONTEXT *urb_context; + + HIF_TRACE("+%s pipe : %d", __func__, pipe->logical_pipe_num); + + while (1) { + urb_context = usb_hif_dequeue_pending_transfer(pipe); + if (NULL == urb_context) { + HIF_WARN("urb_context is NULL"); + break; + } + HIF_TRACE(" pending urb ctxt: 0x%p", urb_context); + if (urb_context->urb != NULL) { + HIF_TRACE(" killing urb: 0x%p", urb_context->urb); + /* killing the URB will cause the completion routines to + * run + */ + usb_kill_urb(urb_context->urb); + } + } + HIF_TRACE("-%s", __func__); +} + +/** + * usb_hif_flush_all() - flush pending transfers for all pipes for a usb bus + * @device: pointer to HIF_DEVICE_USB structure + * + * Return: none + */ +void usb_hif_flush_all(HIF_DEVICE_USB *device) +{ + int i; + HIF_USB_PIPE *pipe; + HIF_TRACE("+%s", __func__); + + for (i = 0; i < HIF_USB_PIPE_MAX; i++) { + if (device->pipes[i].device != NULL) { + usb_hif_flush_pending_transfers(&device->pipes[i]); + pipe = &device->pipes[i]; + + HIF_USB_FLUSH_WORK(pipe); + } + } + + HIF_TRACE("-%s", __func__); +} + +/** + * usb_hif_cleanup_recv_urb() - cleanup recv urb + * @urb_context: pointer to HIF_URB_CONTEXT structure + * + * Return: none + */ +static void usb_hif_cleanup_recv_urb(HIF_URB_CONTEXT *urb_context) +{ + HIF_TRACE("+%s", __func__); + + if (urb_context->buf != NULL) { + qdf_nbuf_free(urb_context->buf); + urb_context->buf = NULL; + } + + usb_hif_free_urb_to_pipe(urb_context->pipe, urb_context); + HIF_TRACE("-%s", __func__); +} + +/** + * usb_hif_cleanup_transmit_urb() - cleanup transmit urb + * @urb_context: pointer to HIF_URB_CONTEXT structure + * + * Return: none + */ +void usb_hif_cleanup_transmit_urb(HIF_URB_CONTEXT *urb_context) +{ + usb_hif_free_urb_to_pipe(urb_context->pipe, urb_context); +} + +/** + * usb_hif_usb_recv_prestart_complete() - completion routine for prestart rx urb + * @urb: urb for which the completion routine is being called + * + * Return: none + */ +static void usb_hif_usb_recv_prestart_complete + (struct urb *urb) +{ + HIF_URB_CONTEXT *urb_context = (HIF_URB_CONTEXT *) urb->context; + QDF_STATUS status = QDF_STATUS_SUCCESS; + qdf_nbuf_t buf = NULL; + HIF_USB_PIPE *pipe = urb_context->pipe; + + HIF_DBG("+%s: recv pipe: %d, stat:%d,len:%d urb:0x%p", + __func__, + pipe->logical_pipe_num, + urb->status, urb->actual_length, + urb); + + /* this urb is not pending anymore */ + usb_hif_remove_pending_transfer(urb_context); + + do { + if (urb->status != 0) { + status = A_ECOMM; + switch (urb->status) { + case -ECONNRESET: + case -ENOENT: + case -ESHUTDOWN: + /* NOTE: no need to spew these errors when + * device is removed + * or urb is killed due to driver shutdown + */ + status = A_ECANCELED; + break; + default: + HIF_ERROR("%s recv pipe: %d (ep:0x%2.2X), failed:%d", + __func__, + pipe->logical_pipe_num, + pipe->ep_address, + urb->status); + break; + } + break; + } + + if (urb->actual_length == 0) + break; + + buf = urb_context->buf; + /* we are going to pass it up */ + urb_context->buf = NULL; + qdf_nbuf_put_tail(buf, urb->actual_length); + + if (AR_DEBUG_LVL_CHECK(USB_HIF_DEBUG_DUMP_DATA)) { + uint8_t *data; + uint32_t len; + qdf_nbuf_peek_header(buf, &data, &len); + debug_dump_bytes(data, len, "hif recv data"); + } + /* note: queue implements a lock */ + skb_queue_tail(&pipe->io_comp_queue, buf); + + HIF_USB_SCHEDULE_WORK(pipe); + } while (false); + + usb_hif_cleanup_recv_urb(urb_context); + + /* Prestart URBs runs out and now start working receive pipe. */ + if (--pipe->urb_prestart_cnt == 0) + usb_hif_start_recv_pipes(pipe->device); + + HIF_DBG("-%s", __func__); +} + +/** + * usb_hif_usb_recv_complete() - completion routine for rx urb + * @urb: urb for which the completion routine is being called + * + * Return: none + */ +static void usb_hif_usb_recv_complete(struct urb *urb) +{ + HIF_URB_CONTEXT *urb_context = (HIF_URB_CONTEXT *) urb->context; + QDF_STATUS status = QDF_STATUS_SUCCESS; + qdf_nbuf_t buf = NULL; + HIF_USB_PIPE *pipe = urb_context->pipe; + struct hif_usb_softc *sc = HIF_GET_USB_SOFTC(pipe->device); + + HIF_DBG("+%s: recv pipe: %d, stat:%d,len:%d urb:0x%p", + __func__, + pipe->logical_pipe_num, + urb->status, urb->actual_length, + urb); + + /* this urb is not pending anymore */ + usb_hif_remove_pending_transfer(urb_context); + + do { + + if (urb->status != 0) { + status = A_ECOMM; + switch (urb->status) { +#ifdef RX_SG_SUPPORT + case -EOVERFLOW: + urb->actual_length = HIF_USB_RX_BUFFER_SIZE; + status = QDF_STATUS_SUCCESS; + break; +#endif + case -ECONNRESET: + case -ENOENT: + case -ESHUTDOWN: + /* NOTE: no need to spew these errors when + * device is removed + * or urb is killed due to driver shutdown + */ + status = A_ECANCELED; + break; + default: + HIF_ERROR("%s recv pipe: %d (ep:0x%2.2X), failed:%d", + __func__, + pipe->logical_pipe_num, + pipe->ep_address, + urb->status); + break; + } + break; + } + + if (urb->actual_length == 0) + break; + + buf = urb_context->buf; + /* we are going to pass it up */ + urb_context->buf = NULL; + qdf_nbuf_put_tail(buf, urb->actual_length); + if (AR_DEBUG_LVL_CHECK(USB_HIF_DEBUG_DUMP_DATA)) { + uint8_t *data; + uint32_t len; + qdf_nbuf_peek_header(buf, &data, &len); + debug_dump_bytes(data, len, "hif recv data"); + } + + /* note: queue implements a lock */ + skb_queue_tail(&pipe->io_comp_queue, buf); + HIF_USB_SCHEDULE_WORK(pipe); + } while (false); + + usb_hif_cleanup_recv_urb(urb_context); + + /* Only re-submit URB when STATUS is success and HIF is not at the + suspend state. + */ + if (QDF_IS_STATUS_SUCCESS(status) && !sc->suspend_state) { + if (pipe->urb_cnt >= pipe->urb_cnt_thresh) { + /* our free urbs are piling up, post more transfers */ + usb_hif_post_recv_transfers(pipe, + HIF_USB_RX_BUFFER_SIZE); + } + } else { + HIF_ERROR("%s: pipe: %d, fail to post URB: status(%d) suspend (%d)", + __func__, + pipe->logical_pipe_num, + urb->status, + sc->suspend_state); + } + + HIF_DBG("-%s", __func__); +} + +/** + * usb_hif_usb_recv_bundle_complete() - completion routine for rx bundling urb + * @urb: urb for which the completion routine is being called + * + * Return: none + */ +static void usb_hif_usb_recv_bundle_complete(struct urb *urb) +{ + HIF_URB_CONTEXT *urb_context = (HIF_URB_CONTEXT *) urb->context; + QDF_STATUS status = QDF_STATUS_SUCCESS; + qdf_nbuf_t buf = NULL; + HIF_USB_PIPE *pipe = urb_context->pipe; + uint8_t *netdata, *netdata_new; + uint32_t netlen, netlen_new; + HTC_FRAME_HDR *HtcHdr; + uint16_t payloadLen; + qdf_nbuf_t new_skb = NULL; + + HIF_DBG("+%s: recv pipe: %d, stat:%d,len:%d urb:0x%p", + __func__, + pipe->logical_pipe_num, + urb->status, urb->actual_length, + urb); + + /* this urb is not pending anymore */ + usb_hif_remove_pending_transfer(urb_context); + + do { + + if (urb->status != 0) { + status = A_ECOMM; + switch (urb->status) { + case -ECONNRESET: + case -ENOENT: + case -ESHUTDOWN: + /* NOTE: no need to spew these errors when + * device is removed + * or urb is killed due to driver shutdown + */ + status = A_ECANCELED; + break; + default: + HIF_ERROR("%s recv pipe: %d (ep:0x%2.2X), failed:%d", + __func__, + pipe->logical_pipe_num, + pipe->ep_address, + urb->status); + break; + } + break; + } + + if (urb->actual_length == 0) + break; + + buf = urb_context->buf; + + if (AR_DEBUG_LVL_CHECK(USB_HIF_DEBUG_DUMP_DATA)) { + uint8_t *data; + uint32_t len; + qdf_nbuf_peek_header(buf, &data, &len); + debug_dump_bytes(data, len, "hif recv data"); + } + + qdf_nbuf_peek_header(buf, &netdata, &netlen); + netlen = urb->actual_length; + + do { + uint16_t frame_len; + + if (IS_FW_CRASH_DUMP(*(uint32_t *) netdata)) + frame_len = netlen; + else { + /* Hack into HTC header for bundle processing */ + HtcHdr = (HTC_FRAME_HDR *) netdata; + if (HtcHdr->EndpointID >= ENDPOINT_MAX) { + HIF_ERROR("athusb: Rx: invalid EndpointID=%d", + HtcHdr->EndpointID); + break; + } + + payloadLen = HtcHdr->PayloadLen; + payloadLen = qdf_le16_to_cpu(payloadLen); + + if (payloadLen > HIF_USB_RX_BUFFER_SIZE) { + HIF_ERROR("athusb: payloadLen too long %u", + payloadLen); + break; + } + frame_len = (HTC_HDR_LENGTH + payloadLen); + } + + if (netlen < frame_len) { + HIF_ERROR("athusb: subframe length %d not fitted into bundle packet length %d" + , netlen, frame_len); + break; + } + + /* allocate a new skb and copy */ + new_skb = + qdf_nbuf_alloc(NULL, frame_len, 0, 4, false); + if (new_skb == NULL) { + HIF_ERROR("athusb: allocate skb (len=%u) failed" + , frame_len); + break; + } + + qdf_nbuf_peek_header(new_skb, &netdata_new, + &netlen_new); + qdf_mem_copy(netdata_new, netdata, frame_len); + qdf_nbuf_put_tail(new_skb, frame_len); + skb_queue_tail(&pipe->io_comp_queue, new_skb); + new_skb = NULL; + netdata += frame_len; + netlen -= frame_len; + } while (netlen); + HIF_USB_SCHEDULE_WORK(pipe); + } while (false); + + if (urb_context->buf == NULL) + HIF_ERROR("athusb: buffer in urb_context is NULL"); + + /* reset urb_context->buf ==> seems not necessary */ + usb_hif_free_urb_to_pipe(urb_context->pipe, urb_context); + + if (QDF_IS_STATUS_SUCCESS(status)) { + if (pipe->urb_cnt >= pipe->urb_cnt_thresh) { + /* our free urbs are piling up, post more transfers */ + usb_hif_post_recv_bundle_transfers(pipe, + pipe->device->rx_bundle_buf_len); + } + } + + HIF_DBG("-%s", __func__); +} + +/** + * usb_hif_post_recv_prestart_transfers() - post prestart recv urbs for a pipe + * @recv_pipe: rx data pipe + * @prestart_urb: number of prestart recv urbs to be posted + * + * Return: none + */ +static void usb_hif_post_recv_prestart_transfers + (HIF_USB_PIPE *recv_pipe, + int prestart_urb) +{ + HIF_URB_CONTEXT *urb_context; + uint8_t *data; + uint32_t len; + struct urb *urb; + int i, usb_status, buffer_length = HIF_USB_RX_BUFFER_SIZE; + + HIF_TRACE("+%s", __func__); + + for (i = 0; i < prestart_urb; i++) { + urb_context = usb_hif_alloc_urb_from_pipe(recv_pipe); + if (NULL == urb_context) + break; + + urb_context->buf = + qdf_nbuf_alloc(NULL, buffer_length, 0, 4, false); + if (NULL == urb_context->buf) { + usb_hif_cleanup_recv_urb(urb_context); + break; + } + + qdf_nbuf_peek_header(urb_context->buf, &data, &len); + + urb = urb_context->urb; + + usb_fill_bulk_urb(urb, + recv_pipe->device->udev, + recv_pipe->usb_pipe_handle, + data, + buffer_length, + usb_hif_usb_recv_prestart_complete, + urb_context); + + HIF_DBG("athusb bulk recv submit:%d, 0x%X (ep:0x%2.2X), %d bytes, buf:0x%p", + recv_pipe->logical_pipe_num, + recv_pipe->usb_pipe_handle, + recv_pipe->ep_address, buffer_length, + urb_context->buf); + + usb_hif_enqueue_pending_transfer(recv_pipe, urb_context); + + usb_status = usb_submit_urb(urb, GFP_ATOMIC); + + if (usb_status) { + HIF_ERROR("athusb : usb bulk recv failed %d", + usb_status); + usb_hif_remove_pending_transfer(urb_context); + usb_hif_cleanup_recv_urb(urb_context); + break; + } else + recv_pipe->urb_prestart_cnt++; + + } + + HIF_TRACE("-%s", __func__); +} + +/** + * usb_hif_post_recv_transfers() - post recv urbs for a given pipe + * @recv_pipe: recv pipe for which urbs need to be posted + * @buffer_length: buffer length of the recv urbs + * + * Return: none + */ +static void usb_hif_post_recv_transfers(HIF_USB_PIPE *recv_pipe, + int buffer_length) +{ + HIF_URB_CONTEXT *urb_context; + uint8_t *data; + uint32_t len; + struct urb *urb; + int usb_status; + + HIF_TRACE("+%s", __func__); + + while (1) { + + urb_context = usb_hif_alloc_urb_from_pipe(recv_pipe); + if (NULL == urb_context) + break; + + urb_context->buf = qdf_nbuf_alloc(NULL, buffer_length, 0, + 4, false); + if (NULL == urb_context->buf) { + usb_hif_cleanup_recv_urb(urb_context); + break; + } + + qdf_nbuf_peek_header(urb_context->buf, &data, &len); + + urb = urb_context->urb; + + usb_fill_bulk_urb(urb, + recv_pipe->device->udev, + recv_pipe->usb_pipe_handle, + data, + buffer_length, + usb_hif_usb_recv_complete, urb_context); + + HIF_DBG("athusb bulk recv submit:%d, 0x%X (ep:0x%2.2X), %d bytes, buf:0x%p", + recv_pipe->logical_pipe_num, + recv_pipe->usb_pipe_handle, + recv_pipe->ep_address, buffer_length, + urb_context->buf); + + usb_hif_enqueue_pending_transfer(recv_pipe, urb_context); + + usb_status = usb_submit_urb(urb, GFP_ATOMIC); + + if (usb_status) { + HIF_ERROR("athusb : usb bulk recv failed %d", + usb_status); + usb_hif_remove_pending_transfer(urb_context); + usb_hif_cleanup_recv_urb(urb_context); + break; + } + } + + HIF_TRACE("-%s", __func__); + +} + +/** + * usb_hif_post_recv_bundle_transfers() - post recv urbs for a given pipe + * @recv_pipe: recv pipe for which urbs need to be posted + * @buffer_length: maximum length of rx bundle + * + * Return: none + */ +static void usb_hif_post_recv_bundle_transfers + (HIF_USB_PIPE *recv_pipe, + int buffer_length) +{ + HIF_URB_CONTEXT *urb_context; + uint8_t *data; + uint32_t len; + struct urb *urb; + int usb_status; + + HIF_TRACE("+%s", __func__); + + while (1) { + + urb_context = usb_hif_alloc_urb_from_pipe(recv_pipe); + if (NULL == urb_context) + break; + + if (NULL == urb_context->buf) { + urb_context->buf = + qdf_nbuf_alloc(NULL, buffer_length, 0, 4, false); + if (NULL == urb_context->buf) { + usb_hif_cleanup_recv_urb(urb_context); + break; + } + } + + qdf_nbuf_peek_header(urb_context->buf, &data, &len); + + urb = urb_context->urb; + usb_fill_bulk_urb(urb, + recv_pipe->device->udev, + recv_pipe->usb_pipe_handle, + data, + buffer_length, + usb_hif_usb_recv_bundle_complete, + urb_context); + + HIF_DBG("athusb bulk recv submit:%d, 0x%X (ep:0x%2.2X), %d bytes, buf:0x%p", + recv_pipe->logical_pipe_num, + recv_pipe->usb_pipe_handle, + recv_pipe->ep_address, buffer_length, + urb_context->buf); + + usb_hif_enqueue_pending_transfer(recv_pipe, urb_context); + + usb_status = usb_submit_urb(urb, GFP_ATOMIC); + + if (usb_status) { + HIF_ERROR("athusb : usb bulk recv failed %d", + usb_status); + usb_hif_remove_pending_transfer(urb_context); + usb_hif_free_urb_to_pipe(urb_context->pipe, + urb_context); + break; + } + + } + + HIF_TRACE("-%s", __func__); + +} + +/** + * usb_hif_prestart_recv_pipes() - post prestart recv urbs + * @device: HIF device for which prestart recv urbs need to be posted + * + * Return: none + */ +void usb_hif_prestart_recv_pipes(HIF_DEVICE_USB *device) +{ + HIF_USB_PIPE *pipe = &device->pipes[HIF_RX_DATA_PIPE]; + + /* + * USB driver learn to support bundle or not until the firmware + * download and ready. Only allocate some URBs for control message + * communication during the initial phase then start the final + * working pipe after all information understood. + */ + usb_hif_post_recv_prestart_transfers(pipe, 8); +} + +/** + * usb_hif_start_recv_pipes() - start recv urbs + * @device: HIF device for which recv urbs need to be posted + * + * This function is called after all prestart recv urbs are exhausted + * + * Return: none + */ +void usb_hif_start_recv_pipes(HIF_DEVICE_USB *device) +{ + HIF_USB_PIPE *pipe; + uint32_t buf_len; + + HIF_ENTER(); + pipe = &device->pipes[HIF_RX_DATA_PIPE]; + pipe->urb_cnt_thresh = pipe->urb_alloc / 2; + + HIF_TRACE("Post URBs to RX_DATA_PIPE: %d", + device->pipes[HIF_RX_DATA_PIPE].urb_cnt); + if (device->is_bundle_enabled) { + usb_hif_post_recv_bundle_transfers(pipe, + pipe->device->rx_bundle_buf_len); + } else { + buf_len = HIF_USB_RX_BUFFER_SIZE; + usb_hif_post_recv_transfers(pipe, buf_len); + } + + HIF_DBG("athusb bulk recv len %d", buf_len); + + if (!hif_usb_disable_rxdata2) { + HIF_TRACE("Post URBs to RX_DATA2_PIPE: %d", + device->pipes[HIF_RX_DATA2_PIPE].urb_cnt); + + pipe = &device->pipes[HIF_RX_DATA2_PIPE]; + pipe->urb_cnt_thresh = pipe->urb_alloc / 2; + usb_hif_post_recv_transfers(pipe, HIF_USB_RX_BUFFER_SIZE); + } + + HIF_EXIT(); +} + +/** + * usb_hif_submit_ctrl_out() - send out a ctrl urb + * @device: HIF device for which urb needs to be posted + * @req: request value for the ctrl message + * @value: USB message value + * @index: USB message index value + * @data: pointer to data containing ctrl message to send + * @size: size of the control message to send + * + * Return: QDF_STATUS_SUCCESS if success else an appropriate QDF_STATUS error + */ +QDF_STATUS usb_hif_submit_ctrl_out(HIF_DEVICE_USB *device, + uint8_t req, + uint16_t value, + uint16_t index, + void *data, + uint32_t size) +{ + int32_t result = 0; + QDF_STATUS ret = QDF_STATUS_SUCCESS; + uint8_t *buf = NULL; + + do { + + if (size > 0) { + buf = qdf_mem_malloc(size); + if (NULL == buf) { + ret = QDF_STATUS_E_NOMEM; + break; + } + qdf_mem_copy(buf, (uint8_t *) data, size); + } + + HIF_DBG("ctrl-out req:0x%2.2X, value:0x%4.4X index:0x%4.4X, datasize:%d", + req, value, index, size); + + result = usb_control_msg(device->udev, + usb_sndctrlpipe(device->udev, 0), + req, + USB_DIR_OUT | USB_TYPE_VENDOR | + USB_RECIP_DEVICE, value, index, buf, + size, 2 * HZ); + + if (result < 0) { + HIF_ERROR("%s failed,result = %d", __func__, result); + ret = QDF_STATUS_E_FAILURE; + } + + } while (false); + + if (buf != NULL) + qdf_mem_free(buf); + + return ret; +} + +/** + * usb_hif_submit_ctrl_in() - recv a resonse to the ctrl message sent out + * @device: HIF device for which urb needs to be received + * @req: request value for the ctrl message + * @value: USB message value + * @index: USB message index value + * @data: pointer to data containing ctrl message to be received + * @size: size of the control message to be received + * + * Return: QDF_STATUS_SUCCESS if success else an appropriate QDF_STATUS error + */ +QDF_STATUS usb_hif_submit_ctrl_in(HIF_DEVICE_USB *device, + uint8_t req, + uint16_t value, + uint16_t index, + void *data, + uint32_t size) +{ + int32_t result = 0; + QDF_STATUS ret = QDF_STATUS_SUCCESS; + uint8_t *buf = NULL; + + do { + + if (size > 0) { + buf = qdf_mem_malloc(size); + if (NULL == buf) { + ret = QDF_STATUS_E_NOMEM; + break; + } + } + + HIF_DBG("ctrl-in req:0x%2.2X, value:0x%4.4X index:0x%4.4X, datasize:%d", + req, value, index, size); + + result = usb_control_msg(device->udev, + usb_rcvctrlpipe(device->udev, 0), + req, + USB_DIR_IN | USB_TYPE_VENDOR | + USB_RECIP_DEVICE, value, index, buf, + size, 2 * HZ); + + if (result < 0) { + HIF_ERROR("%s failed, result = %d", __func__, result); + ret = QDF_STATUS_E_FAILURE; + break; + } + + qdf_mem_copy((uint8_t *) data, buf, size); + + } while (false); + + if (buf != NULL) + qdf_mem_free(buf); + + return ret; +} + +/** + * usb_hif_io_complete() - transmit call back for tx urb + * @pipe: pointer to HIF_USB_PIPE + * + * Return: none + */ +void usb_hif_io_complete(HIF_USB_PIPE *pipe) +{ + qdf_nbuf_t buf; + HIF_DEVICE_USB *device; + HTC_FRAME_HDR *HtcHdr; + uint8_t *data; + uint32_t len; + struct hif_usb_softc *sc = HIF_GET_USB_SOFTC(pipe->device); + device = pipe->device; + + HIF_ENTER(); + + while ((buf = skb_dequeue(&pipe->io_comp_queue))) { + if (pipe->flags & HIF_USB_PIPE_FLAG_TX) { + HIF_DBG("+athusb xmit callback " "buf:0x%p", buf); + HtcHdr = (HTC_FRAME_HDR *) + qdf_nbuf_get_frag_vaddr(buf, 0); + +#ifdef ATH_11AC_TXCOMPACT +/* ATH_11AC_TXCOMPACT does not support High Latency mode */ +#else + device->htc_callbacks.txCompletionHandler(device-> + htc_callbacks. + Context, buf, + HtcHdr-> + EndpointID, 0); +#endif + HIF_DBG("-athusb xmit callback"); + } else { + HIF_DBG("+athusb recv callback buf:" "0x%p", buf); + qdf_nbuf_peek_header(buf, &data, &len); + + if (IS_FW_CRASH_DUMP(*((uint32_t *) data))) { + sc->fw_data = data; + sc->fw_data_len = len; + device->htc_callbacks.fwEventHandler( + device->htc_callbacks.Context, + QDF_STATUS_E_USB_ERROR); + qdf_nbuf_free(buf); + } else { + device->htc_callbacks.rxCompletionHandler( + device->htc_callbacks.Context, buf, + pipe->logical_pipe_num); + } + HIF_DBG("-athusb recv callback"); + } + } + + HIF_EXIT(); +} + +#ifdef HIF_USB_TASKLET +/** + * usb_hif_io_comp_tasklet() - per pipe tasklet routine + * @context: pointer to HIF USB pipe + * + * Return: none + */ +void usb_hif_io_comp_tasklet(long unsigned int context) +{ + HIF_USB_PIPE *pipe = (HIF_USB_PIPE *) context; + usb_hif_io_complete(pipe); +} + +#else +/** + * usb_hif_io_comp_work() - per pipe work queue + * @work: pointer to struct work_struct + * + * Return: none + */ +void usb_hif_io_comp_work(struct work_struct *work) +{ + HIF_USB_PIPE *pipe = container_of(work, HIF_USB_PIPE, io_complete_work); + usb_hif_io_complete(pipe); +} +#endif diff --git a/drivers/staging/qca-wifi-host-cmn/htc/dl_list.h b/drivers/staging/qca-wifi-host-cmn/htc/dl_list.h new file mode 100644 index 0000000000000000000000000000000000000000..1b5d72f780e206b98d6d25924e715c601dcfbdab --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/htc/dl_list.h @@ -0,0 +1,208 @@ +/* + * Copyright (c) 2013-2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* ============================================================================== */ +/* Double-link list definitions (adapted from Atheros SDIO stack) */ +/* */ +/* Author(s): ="Atheros" */ +/* ============================================================================== */ + +#ifndef __DL_LIST_H___ +#define __DL_LIST_H___ + +#define A_CONTAINING_STRUCT(address, struct_type, field_name) \ + ((struct_type *)((char *)(address) - (char *)(&((struct_type *)0)->field_name))) + +/* list functions */ +/* pointers for the list */ +typedef struct _DL_LIST { + struct _DL_LIST *pPrev; + struct _DL_LIST *pNext; +} DL_LIST, *PDL_LIST; +/* + * DL_LIST_INIT , initialize doubly linked list + */ +#define DL_LIST_INIT(pList) \ + {(pList)->pPrev = pList; (pList)->pNext = pList; } + +/* faster macro to init list and add a single item */ +#define DL_LIST_INIT_AND_ADD(pList,pItem) \ + { (pList)->pPrev = (pItem); \ + (pList)->pNext = (pItem); \ + (pItem)->pNext = (pList); \ + (pItem)->pPrev = (pList); \ + } + +#define DL_LIST_IS_EMPTY(pList) (((pList)->pPrev == (pList)) && ((pList)->pNext == (pList))) +#define DL_LIST_GET_ITEM_AT_HEAD(pList) (pList)->pNext +#define DL_LIST_GET_ITEM_AT_TAIL(pList) (pList)->pPrev +/* + * ITERATE_OVER_LIST pStart is the list, pTemp is a temp list member + * NOT: do not use this function if the items in the list are deleted inside the + * iteration loop + */ +#define ITERATE_OVER_LIST(pStart, pTemp) \ + for((pTemp) =(pStart)->pNext; pTemp != (pStart); (pTemp) = (pTemp)->pNext) + +static __inline bool dl_list_is_entry_in_list(const DL_LIST *pList, + const DL_LIST *pEntry) +{ + const DL_LIST *pTmp; + + if (pList == pEntry) + return true; + + ITERATE_OVER_LIST(pList, pTmp) { + if (pTmp == pEntry) { + return true; + } + } + + return false; +} + +/* safe iterate macro that allows the item to be removed from the list + * the iteration continues to the next item in the list + */ +#define ITERATE_OVER_LIST_ALLOW_REMOVE(pStart,pItem,st,offset) \ + { \ + PDL_LIST pTemp; \ + pTemp = (pStart)->pNext; \ + while (pTemp != (pStart)) { \ + (pItem) = A_CONTAINING_STRUCT(pTemp,st,offset); \ + pTemp = pTemp->pNext; \ + +#define ITERATE_IS_VALID(pStart) dl_list_is_entry_in_list(pStart, pTemp) +#define ITERATE_RESET(pStart) pTemp=(pStart)->pNext + +#define ITERATE_END }} + +/* + * dl_list_insert_tail - insert pAdd to the end of the list + */ +static __inline PDL_LIST dl_list_insert_tail(PDL_LIST pList, PDL_LIST pAdd) +{ + /* insert at tail */ + pAdd->pPrev = pList->pPrev; + pAdd->pNext = pList; + if (pList->pPrev) { + pList->pPrev->pNext = pAdd; + } + pList->pPrev = pAdd; + return pAdd; +} + +/* + * dl_list_insert_head - insert pAdd into the head of the list + */ +static __inline PDL_LIST dl_list_insert_head(PDL_LIST pList, PDL_LIST pAdd) +{ + /* insert at head */ + pAdd->pPrev = pList; + pAdd->pNext = pList->pNext; + pList->pNext->pPrev = pAdd; + pList->pNext = pAdd; + return pAdd; +} + +#define DL_ListAdd(pList,pItem) dl_list_insert_head((pList),(pItem)) +/* + * dl_list_remove - remove pDel from list + */ +static __inline PDL_LIST dl_list_remove(PDL_LIST pDel) +{ + if (pDel->pNext != NULL) { + pDel->pNext->pPrev = pDel->pPrev; + } + if (pDel->pPrev != NULL) { + pDel->pPrev->pNext = pDel->pNext; + } + + /* point back to itself just to be safe, incase remove is called again */ + pDel->pNext = pDel; + pDel->pPrev = pDel; + return pDel; +} + +/* + * dl_list_remove_item_from_head - get a list item from the head + */ +static __inline PDL_LIST dl_list_remove_item_from_head(PDL_LIST pList) +{ + PDL_LIST pItem = NULL; + if (pList->pNext != pList) { + pItem = pList->pNext; + /* remove the first item from head */ + dl_list_remove(pItem); + } + return pItem; +} + +static __inline PDL_LIST dl_list_remove_item_from_tail(PDL_LIST pList) +{ + PDL_LIST pItem = NULL; + if (pList->pPrev != pList) { + pItem = pList->pPrev; + /* remove the item from tail */ + dl_list_remove(pItem); + } + return pItem; +} + +/* transfer src list items to the tail of the destination list */ +static __inline void dl_list_transfer_items_to_tail(PDL_LIST pDest, PDL_LIST pSrc) +{ + /* only concatenate if src is not empty */ + if (!DL_LIST_IS_EMPTY(pSrc)) { + /* cut out circular list in src and re-attach to end of dest */ + pSrc->pPrev->pNext = pDest; + pSrc->pNext->pPrev = pDest->pPrev; + pDest->pPrev->pNext = pSrc->pNext; + pDest->pPrev = pSrc->pPrev; + /* terminate src list, it is now empty */ + pSrc->pPrev = pSrc; + pSrc->pNext = pSrc; + } +} + +/* transfer src list items to the head of the destination list */ +static __inline void dl_list_transfer_items_to_head(PDL_LIST pDest, PDL_LIST pSrc) +{ + /* only concatenate if src is not empty */ + if (!DL_LIST_IS_EMPTY(pSrc)) { + /* cut out circular list in src and re-attach to start of dest */ + pSrc->pNext->pPrev = pDest; + pDest->pNext->pPrev = pSrc->pPrev; + pSrc->pPrev->pNext = pDest->pNext; + pDest->pNext = pSrc->pNext; + /* terminate src list, it is now empty */ + pSrc->pPrev = pSrc; + pSrc->pNext = pSrc; + } +} + +#endif /* __DL_LIST_H___ */ diff --git a/drivers/staging/qca-wifi-host-cmn/htc/htc.c b/drivers/staging/qca-wifi-host-cmn/htc/htc.c new file mode 100644 index 0000000000000000000000000000000000000000..61104aaefd6ada8bfe43e6f73813e54bff663259 --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/htc/htc.c @@ -0,0 +1,1032 @@ +/* + * Copyright (c) 2013-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#include "htc_debug.h" +#include "htc_internal.h" +#include +#include /* qdf_nbuf_t */ +#include /* qdf_print */ + +#define MAX_HTC_RX_BUNDLE 2 + +#if defined(WLAN_DEBUG) || defined(DEBUG) +static ATH_DEBUG_MASK_DESCRIPTION g_htc_debug_description[] = { + {ATH_DEBUG_SEND, "Send"}, + {ATH_DEBUG_RECV, "Recv"}, + {ATH_DEBUG_SYNC, "Sync"}, + {ATH_DEBUG_DUMP, "Dump Data (RX or TX)"}, + {ATH_DEBUG_SETUP, "Setup"}, +}; + +ATH_DEBUG_INSTANTIATE_MODULE_VAR(htc, + "htc", + "Host Target Communications", + ATH_DEBUG_MASK_DEFAULTS | ATH_DEBUG_INFO | + ATH_DEBUG_SETUP, + ATH_DEBUG_DESCRIPTION_COUNT + (g_htc_debug_description), + g_htc_debug_description); + +#endif + +extern unsigned int htc_credit_flow; + +static void reset_endpoint_states(HTC_TARGET *target); + +static void destroy_htc_tx_ctrl_packet(HTC_PACKET *pPacket) +{ + qdf_nbuf_t netbuf; + netbuf = (qdf_nbuf_t) GET_HTC_PACKET_NET_BUF_CONTEXT(pPacket); + AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("free ctrl netbuf :0x%p\n", netbuf)); + if (netbuf != NULL) { + qdf_nbuf_free(netbuf); + } + + qdf_mem_free(pPacket); +} + +static HTC_PACKET *build_htc_tx_ctrl_packet(qdf_device_t osdev) +{ + HTC_PACKET *pPacket = NULL; + qdf_nbuf_t netbuf; + + do { + pPacket = (HTC_PACKET *) qdf_mem_malloc(sizeof(HTC_PACKET)); + if (NULL == pPacket) { + break; + } + netbuf = qdf_nbuf_alloc(osdev, HTC_CONTROL_BUFFER_SIZE, + 20, 4, true); + if (NULL == netbuf) { + qdf_mem_free(pPacket); + pPacket = NULL; + qdf_print("%s: nbuf alloc failed\n", __func__); + break; + } + AR_DEBUG_PRINTF(ATH_DEBUG_TRC, + ("alloc ctrl netbuf :0x%p \n", netbuf)); + SET_HTC_PACKET_NET_BUF_CONTEXT(pPacket, netbuf); + } while (false); + + return pPacket; +} + +void htc_free_control_tx_packet(HTC_TARGET *target, HTC_PACKET *pPacket) +{ + +#ifdef TODO_FIXME + LOCK_HTC(target); + HTC_PACKET_ENQUEUE(&target->ControlBufferTXFreeList, pPacket); + UNLOCK_HTC(target); + /* TODO_FIXME netbufs cannot be RESET! */ +#else + destroy_htc_tx_ctrl_packet(pPacket); +#endif + +} + +HTC_PACKET *htc_alloc_control_tx_packet(HTC_TARGET *target) +{ +#ifdef TODO_FIXME + HTC_PACKET *pPacket; + + LOCK_HTC(target); + pPacket = htc_packet_dequeue(&target->ControlBufferTXFreeList); + UNLOCK_HTC(target); + + return pPacket; +#else + return build_htc_tx_ctrl_packet(target->osdev); +#endif +} + +/* Set the target failure handling callback */ +void htc_set_target_failure_callback(HTC_HANDLE HTCHandle, + HTC_TARGET_FAILURE Callback) +{ + HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle); + target->HTCInitInfo.TargetFailure = Callback; +} + +void htc_dump(HTC_HANDLE HTCHandle, uint8_t CmdId, bool start) +{ + HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle); + hif_dump(target->hif_dev, CmdId, start); +} + +/* cleanup the HTC instance */ +static void htc_cleanup(HTC_TARGET *target) +{ + HTC_PACKET *pPacket; + /* qdf_nbuf_t netbuf; */ + + if (target->hif_dev != NULL) { + hif_detach_htc(target->hif_dev); + hif_mask_interrupt_call(target->hif_dev); + target->hif_dev = NULL; + } + + while (true) { + pPacket = allocate_htc_packet_container(target); + if (NULL == pPacket) { + break; + } + qdf_mem_free(pPacket); + } + + pPacket = target->pBundleFreeList; + while (pPacket) { + HTC_PACKET *pPacketTmp = (HTC_PACKET *) pPacket->ListLink.pNext; + qdf_mem_free(pPacket); + pPacket = pPacketTmp; + } +#ifdef TODO_FIXME + while (true) { + pPacket = htc_alloc_control_tx_packet(target); + if (NULL == pPacket) { + break; + } + netbuf = (qdf_nbuf_t) GET_HTC_PACKET_NET_BUF_CONTEXT(pPacket); + if (netbuf != NULL) { + qdf_nbuf_free(netbuf); + } + + qdf_mem_free(pPacket); + } +#endif + + qdf_spinlock_destroy(&target->HTCLock); + qdf_spinlock_destroy(&target->HTCRxLock); + qdf_spinlock_destroy(&target->HTCTxLock); + qdf_spinlock_destroy(&target->HTCCreditLock); + + /* free our instance */ + qdf_mem_free(target); +} + +#ifdef FEATURE_RUNTIME_PM +/** + * htc_runtime_pm_init(): runtime pm related intialization + * + * need to initialize a work item. + */ +static void htc_runtime_pm_init(HTC_TARGET *target) +{ + qdf_create_work(0, &target->queue_kicker, htc_kick_queues, target); +} + +/** + * htc_runtime_suspend() - runtime suspend HTC + * + * @htc_ctx: HTC context pointer + * + * This is a dummy function for symmetry. + * + * Return: 0 for success + */ +int htc_runtime_suspend(HTC_HANDLE htc_ctx) +{ + return 0; +} + +/** + * htc_runtime_resume(): resume htc + * + * The htc message queue needs to be kicked off after + * a runtime resume. Otherwise messages would get stuck. + * + * @htc_ctx: HTC context pointer + * + * Return: 0 for success; + */ +int htc_runtime_resume(HTC_HANDLE htc_ctx) +{ + HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(htc_ctx); + + if (target == NULL) + return 0; + + qdf_sched_work(0, &target->queue_kicker); + return 0; +} +#else +static inline void htc_runtime_pm_init(HTC_TARGET *target) { } +#endif + +/* registered target arrival callback from the HIF layer */ +HTC_HANDLE htc_create(void *ol_sc, HTC_INIT_INFO *pInfo, qdf_device_t osdev, + uint32_t con_mode) +{ + struct hif_msg_callbacks htcCallbacks; + HTC_ENDPOINT *pEndpoint = NULL; + HTC_TARGET *target = NULL; + int i; + + if (ol_sc == NULL) { + HTC_ERROR("%s: ol_sc = NULL", __func__); + return NULL; + } + HTC_TRACE("+htc_create .. HIF :%p", ol_sc); + + A_REGISTER_MODULE_DEBUG_INFO(htc); + + target = (HTC_TARGET *) qdf_mem_malloc(sizeof(HTC_TARGET)); + if (target == NULL) { + HTC_ERROR("%s: Unable to allocate memory", __func__); + return NULL; + } + + htc_runtime_pm_init(target); + qdf_spinlock_create(&target->HTCLock); + qdf_spinlock_create(&target->HTCRxLock); + qdf_spinlock_create(&target->HTCTxLock); + qdf_spinlock_create(&target->HTCCreditLock); + target->is_nodrop_pkt = false; + + do { + qdf_mem_copy(&target->HTCInitInfo, pInfo, + sizeof(HTC_INIT_INFO)); + target->host_handle = pInfo->pContext; + target->osdev = osdev; + target->con_mode = con_mode; + + reset_endpoint_states(target); + + INIT_HTC_PACKET_QUEUE(&target->ControlBufferTXFreeList); + + for (i = 0; i < HTC_PACKET_CONTAINER_ALLOCATION; i++) { + HTC_PACKET *pPacket = + (HTC_PACKET *) qdf_mem_malloc(sizeof(HTC_PACKET)); + if (pPacket != NULL) { + free_htc_packet_container(target, pPacket); + } + } + +#ifdef TODO_FIXME + for (i = 0; i < NUM_CONTROL_TX_BUFFERS; i++) { + pPacket = build_htc_tx_ctrl_packet(); + if (NULL == pPacket) { + break; + } + htc_free_control_tx_packet(target, pPacket); + } +#endif + + /* setup HIF layer callbacks */ + qdf_mem_zero(&htcCallbacks, sizeof(struct hif_msg_callbacks)); + htcCallbacks.Context = target; + htcCallbacks.rxCompletionHandler = htc_rx_completion_handler; + htcCallbacks.txCompletionHandler = htc_tx_completion_handler; + htcCallbacks.txResourceAvailHandler = htc_tx_resource_avail_handler; + htcCallbacks.fwEventHandler = htc_fw_event_handler; + target->hif_dev = ol_sc; + + /* Get HIF default pipe for HTC message exchange */ + pEndpoint = &target->endpoint[ENDPOINT_0]; + + hif_post_init(target->hif_dev, target, &htcCallbacks); + hif_get_default_pipe(target->hif_dev, &pEndpoint->UL_PipeID, + &pEndpoint->DL_PipeID); + + } while (false); + + htc_recv_init(target); + + HTC_TRACE("-htc_create: (0x%p)", target); + + return (HTC_HANDLE) target; +} + +void htc_destroy(HTC_HANDLE HTCHandle) +{ + HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle); + AR_DEBUG_PRINTF(ATH_DEBUG_TRC, + ("+htc_destroy .. Destroying :0x%p\n", target)); + hif_stop(htc_get_hif_device(HTCHandle)); + if (target) + htc_cleanup(target); + AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("-htc_destroy\n")); +} + +/* get the low level HIF device for the caller , the caller may wish to do low level + * HIF requests */ +void *htc_get_hif_device(HTC_HANDLE HTCHandle) +{ + HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle); + return target->hif_dev; +} + +static void htc_control_tx_complete(void *Context, HTC_PACKET *pPacket) +{ + HTC_TARGET *target = (HTC_TARGET *) Context; + AR_DEBUG_PRINTF(ATH_DEBUG_TRC, + ("+-htc_control_tx_complete 0x%p (l:%d) \n", pPacket, + pPacket->ActualLength)); + htc_free_control_tx_packet(target, pPacket); +} + +/* TODO, this is just a temporary max packet size */ +#define MAX_MESSAGE_SIZE 1536 + +/** + * htc_setup_epping_credit_allocation() - allocate credits/HTC buffers to WMI + * @scn: pointer to hif_opaque_softc + * @pEntry: pointer to tx credit allocation entry + * @credits: number of credits + * + * Return: None + */ +static void +htc_setup_epping_credit_allocation(struct hif_opaque_softc *scn, + HTC_SERVICE_TX_CREDIT_ALLOCATION *pEntry, + int credits) +{ + switch (hif_get_bus_type(scn)) { + case QDF_BUS_TYPE_PCI: + pEntry++; + pEntry->service_id = WMI_DATA_BE_SVC; + pEntry->CreditAllocation = (credits >> 1); + + pEntry++; + pEntry->service_id = WMI_DATA_BK_SVC; + pEntry->CreditAllocation = (credits >> 1); + break; + case QDF_BUS_TYPE_SDIO: + pEntry++; + pEntry->service_id = WMI_DATA_BE_SVC; + pEntry->CreditAllocation = credits; + break; + default: + break; + } + return; +} + +/** + * htc_setup_target_buffer_assignments() - setup target buffer assignments + * @target: HTC Target Pointer + * + * Return: A_STATUS + */ +static +A_STATUS htc_setup_target_buffer_assignments(HTC_TARGET *target) +{ + HTC_SERVICE_TX_CREDIT_ALLOCATION *pEntry; + A_STATUS status; + int credits; + int creditsPerMaxMsg; + + creditsPerMaxMsg = MAX_MESSAGE_SIZE / target->TargetCreditSize; + if (MAX_MESSAGE_SIZE % target->TargetCreditSize) { + creditsPerMaxMsg++; + } + + /* TODO, this should be configured by the caller! */ + + credits = target->TotalTransmitCredits; + pEntry = &target->ServiceTxAllocTable[0]; + + /* + * Allocate all credists/HTC buffers to WMI. + * no buffers are used/required for data. data always + * remains on host. + */ + status = A_OK; + pEntry++; + pEntry->service_id = WMI_CONTROL_SVC; + pEntry->CreditAllocation = credits; + + if (HTC_IS_EPPING_ENABLED(target->con_mode)) { + /* endpoint ping is a testing tool directly on top of HTC in + * both target and host sides. + * In target side, the endppint ping fw has no wlan stack and the + * FW mboxping app directly sits on HTC and it simply drops + * or loops back TX packets. For rx perf, FW mboxping app + * generates packets and passes packets to HTC to send to host. + * There is no WMI mesage exchanges between host and target + * in endpoint ping case. + * In host side, the endpoint ping driver is a Ethernet driver + * and it directly sits on HTC. Only HIF, HTC, QDF, ADF are + * used by the endpoint ping driver. There is no wifi stack + * at all in host side also. For tx perf use case, + * the user space mboxping app sends the raw packets to endpoint + * ping driver and it directly forwards to HTC for transmission + * to stress the bus. For the rx perf, HTC passes the received + * packets to endpoint ping driver and it is passed to the user + * space through the Ethernet interface. + * For credit allocation, in SDIO bus case, only BE service is + * used for tx/rx perf testing so that all credits are given + * to BE service. In PCIe and USB bus case, endpoint ping uses both + * BE and BK services to stress the bus so that the total credits + * are equally distributed to BE and BK services. + */ + + htc_setup_epping_credit_allocation(target->hif_dev, + pEntry, credits); + } + + if (A_SUCCESS(status)) { + int i; + for (i = 0; i < HTC_MAX_SERVICE_ALLOC_ENTRIES; i++) { + if (target->ServiceTxAllocTable[i].service_id != 0) { + AR_DEBUG_PRINTF(ATH_DEBUG_INIT, + ("HTC Service Index : %d TX : 0x%2.2X : alloc:%d\n", + i, + target->ServiceTxAllocTable[i]. + service_id, + target->ServiceTxAllocTable[i]. + CreditAllocation)); + } + } + } + + return status; +} + +uint8_t htc_get_credit_allocation(HTC_TARGET *target, uint16_t service_id) +{ + uint8_t allocation = 0; + int i; + + for (i = 0; i < HTC_MAX_SERVICE_ALLOC_ENTRIES; i++) { + if (target->ServiceTxAllocTable[i].service_id == service_id) { + allocation = + target->ServiceTxAllocTable[i].CreditAllocation; + } + } + + if (0 == allocation) { + AR_DEBUG_PRINTF(ATH_DEBUG_INIT, + ("HTC Service TX : 0x%2.2X : allocation is zero!\n", + service_id)); + } + + return allocation; +} + +A_STATUS htc_wait_target(HTC_HANDLE HTCHandle) +{ + A_STATUS status = A_OK; + HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle); + HTC_READY_EX_MSG *pReadyMsg; + HTC_SERVICE_CONNECT_REQ connect; + HTC_SERVICE_CONNECT_RESP resp; + HTC_READY_MSG *rdy_msg; + uint16_t htc_rdy_msg_id; + uint8_t i = 0; + HTC_PACKET *rx_bundle_packet, *temp_bundle_packet; + + AR_DEBUG_PRINTF(ATH_DEBUG_TRC, + ("htc_wait_target - Enter (target:0x%p)\n", HTCHandle)); + AR_DEBUG_PRINTF(ATH_DEBUG_ANY, ("+HWT\n")); + + do { + + status = hif_start(target->hif_dev); + if (A_FAILED(status)) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERROR, ("hif_start failed\n")); + break; + } + + status = htc_wait_recv_ctrl_message(target); + + if (A_FAILED(status)) { + break; + } + + if (target->CtrlResponseLength < (sizeof(HTC_READY_EX_MSG))) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + ("Invalid HTC Ready Msg Len:%d! \n", + target->CtrlResponseLength)); + status = A_ECOMM; + break; + } + + pReadyMsg = (HTC_READY_EX_MSG *) target->CtrlResponseBuffer; + + rdy_msg = &pReadyMsg->Version2_0_Info; + htc_rdy_msg_id = + HTC_GET_FIELD(rdy_msg, HTC_READY_MSG, MESSAGEID); + if (htc_rdy_msg_id != HTC_MSG_READY_ID) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + ("Invalid HTC Ready Msg : 0x%X ! \n", + htc_rdy_msg_id)); + status = A_ECOMM; + break; + } + + target->TotalTransmitCredits = + HTC_GET_FIELD(rdy_msg, HTC_READY_MSG, CREDITCOUNT); + target->TargetCreditSize = + (int)HTC_GET_FIELD(rdy_msg, HTC_READY_MSG, CREDITSIZE); + target->MaxMsgsPerHTCBundle = + (uint8_t) pReadyMsg->MaxMsgsPerHTCBundle; + /* for old fw this value is set to 0. But the minimum value should be 1, + * i.e., no bundling */ + if (target->MaxMsgsPerHTCBundle < 1) + target->MaxMsgsPerHTCBundle = 1; + + AR_DEBUG_PRINTF(ATH_DEBUG_INIT, + ("Target Ready! : transmit resources : %d size:%d, MaxMsgsPerHTCBundle = %d\n", + target->TotalTransmitCredits, + target->TargetCreditSize, + target->MaxMsgsPerHTCBundle)); + + if ((0 == target->TotalTransmitCredits) + || (0 == target->TargetCreditSize)) { + status = A_ECOMM; + break; + } + + /* Allocate expected number of RX bundle buffer allocation */ + if (HTC_RX_BUNDLE_ENABLED(target)) { + temp_bundle_packet = NULL; + for (i = 0; i < MAX_HTC_RX_BUNDLE; i++) { + rx_bundle_packet = + allocate_htc_bundle_packet(target); + if (rx_bundle_packet != NULL) + rx_bundle_packet->ListLink.pNext = + (DL_LIST *)temp_bundle_packet; + else + break; + + temp_bundle_packet = rx_bundle_packet; + } + target->pBundleFreeList = temp_bundle_packet; + } + + /* done processing */ + target->CtrlResponseProcessing = false; + + htc_setup_target_buffer_assignments(target); + + /* setup our pseudo HTC control endpoint connection */ + qdf_mem_zero(&connect, sizeof(connect)); + qdf_mem_zero(&resp, sizeof(resp)); + connect.EpCallbacks.pContext = target; + connect.EpCallbacks.EpTxComplete = htc_control_tx_complete; + connect.EpCallbacks.EpRecv = htc_control_rx_complete; + connect.MaxSendQueueDepth = NUM_CONTROL_TX_BUFFERS; + connect.service_id = HTC_CTRL_RSVD_SVC; + + /* connect fake service */ + status = htc_connect_service((HTC_HANDLE) target, + &connect, &resp); + + } while (false); + + AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("htc_wait_target - Exit (%d)\n", status)); + AR_DEBUG_PRINTF(ATH_DEBUG_ANY, ("-HWT\n")); + return status; +} + +/* start HTC, this is called after all services are connected */ +static A_STATUS htc_config_target_hif_pipe(HTC_TARGET *target) +{ + + return A_OK; +} + +static void reset_endpoint_states(HTC_TARGET *target) +{ + HTC_ENDPOINT *pEndpoint; + int i; + + for (i = ENDPOINT_0; i < ENDPOINT_MAX; i++) { + pEndpoint = &target->endpoint[i]; + pEndpoint->service_id = 0; + pEndpoint->MaxMsgLength = 0; + pEndpoint->MaxTxQueueDepth = 0; + pEndpoint->Id = i; + INIT_HTC_PACKET_QUEUE(&pEndpoint->TxQueue); + INIT_HTC_PACKET_QUEUE(&pEndpoint->TxLookupQueue); + INIT_HTC_PACKET_QUEUE(&pEndpoint->RxBufferHoldQueue); + pEndpoint->target = target; + pEndpoint->TxCreditFlowEnabled = (bool)htc_credit_flow; + qdf_atomic_init(&pEndpoint->TxProcessCount); + } +} + +/** + * htc_start() - Main HTC function to trigger HTC start + * @HTCHandle: pointer to HTC handle + * + * Return: A_OK for success or an appropriate A_STATUS error + */ +A_STATUS htc_start(HTC_HANDLE HTCHandle) +{ + qdf_nbuf_t netbuf; + A_STATUS status = A_OK; + HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle); + HTC_SETUP_COMPLETE_EX_MSG *pSetupComp; + HTC_PACKET *pSendPacket; + + AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("htc_start Enter\n")); + + do { + + htc_config_target_hif_pipe(target); + + /* allocate a buffer to send */ + pSendPacket = htc_alloc_control_tx_packet(target); + if (NULL == pSendPacket) { + AR_DEBUG_ASSERT(false); + qdf_print("%s: allocControlTxPacket failed\n", + __func__); + status = A_NO_MEMORY; + break; + } + + netbuf = + (qdf_nbuf_t) GET_HTC_PACKET_NET_BUF_CONTEXT(pSendPacket); + /* assemble setup complete message */ + qdf_nbuf_put_tail(netbuf, sizeof(HTC_SETUP_COMPLETE_EX_MSG)); + pSetupComp = + (HTC_SETUP_COMPLETE_EX_MSG *) qdf_nbuf_data(netbuf); + qdf_mem_zero(pSetupComp, sizeof(HTC_SETUP_COMPLETE_EX_MSG)); + + HTC_SET_FIELD(pSetupComp, HTC_SETUP_COMPLETE_EX_MSG, + MESSAGEID, HTC_MSG_SETUP_COMPLETE_EX_ID); + + if (!htc_credit_flow) { + AR_DEBUG_PRINTF(ATH_DEBUG_INIT, + ("HTC will not use TX credit flow control\n")); + pSetupComp->SetupFlags |= + HTC_SETUP_COMPLETE_FLAGS_DISABLE_TX_CREDIT_FLOW; + } else { + AR_DEBUG_PRINTF(ATH_DEBUG_INIT, + ("HTC using TX credit flow control\n")); + } + + if ((hif_get_bus_type(target->hif_dev) == QDF_BUS_TYPE_SDIO) || + (hif_get_bus_type(target->hif_dev) == QDF_BUS_TYPE_USB)) { + if (HTC_RX_BUNDLE_ENABLED(target)) + pSetupComp->SetupFlags |= + HTC_SETUP_COMPLETE_FLAGS_ENABLE_BUNDLE_RECV; + hif_set_bundle_mode(target->hif_dev, true, + HTC_MAX_MSG_PER_BUNDLE_RX); + } + + SET_HTC_PACKET_INFO_TX(pSendPacket, + NULL, + (uint8_t *) pSetupComp, + sizeof(HTC_SETUP_COMPLETE_EX_MSG), + ENDPOINT_0, HTC_SERVICE_TX_PACKET_TAG); + + status = htc_send_pkt((HTC_HANDLE) target, pSendPacket); + if (A_FAILED(status)) { + break; + } + + } while (false); + + AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("htc_start Exit\n")); + return status; +} + +/*flush all queued buffers for surpriseremove case*/ +void htc_flush_surprise_remove(HTC_HANDLE HTCHandle) +{ + HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle); + int i; + HTC_ENDPOINT *pEndpoint; +#ifdef RX_SG_SUPPORT + qdf_nbuf_t netbuf; + qdf_nbuf_queue_t *rx_sg_queue = &target->RxSgQueue; +#endif + + AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("+htc_flush_surprise_remove\n")); + + /* cleanup endpoints */ + for (i = 0; i < ENDPOINT_MAX; i++) { + pEndpoint = &target->endpoint[i]; + htc_flush_rx_hold_queue(target, pEndpoint); + htc_flush_endpoint_tx(target, pEndpoint, HTC_TX_PACKET_TAG_ALL); + } + + hif_flush_surprise_remove(target->hif_dev); + +#ifdef RX_SG_SUPPORT + LOCK_HTC_RX(target); + while ((netbuf = qdf_nbuf_queue_remove(rx_sg_queue)) != NULL) + qdf_nbuf_free(netbuf); + RESET_RX_SG_CONFIG(target); + UNLOCK_HTC_RX(target); +#endif + + reset_endpoint_states(target); + + AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("-htc_flush_surprise_remove \n")); +} + +/* stop HTC communications, i.e. stop interrupt reception, and flush all queued buffers */ +void htc_stop(HTC_HANDLE HTCHandle) +{ + HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle); + int i; + HTC_ENDPOINT *pEndpoint; +#ifdef RX_SG_SUPPORT + qdf_nbuf_t netbuf; + qdf_nbuf_queue_t *rx_sg_queue = &target->RxSgQueue; +#endif + + AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("+htc_stop\n")); + + /* cleanup endpoints */ + for (i = 0; i < ENDPOINT_MAX; i++) { + pEndpoint = &target->endpoint[i]; + htc_flush_rx_hold_queue(target, pEndpoint); + htc_flush_endpoint_tx(target, pEndpoint, HTC_TX_PACKET_TAG_ALL); + if (pEndpoint->ul_is_polled) { + qdf_timer_stop(&pEndpoint->ul_poll_timer); + qdf_timer_free(&pEndpoint->ul_poll_timer); + } + } + + /* Note: htc_flush_endpoint_tx for all endpoints should be called before + * hif_stop - otherwise htc_tx_completion_handler called from + * hif_send_buffer_cleanup_on_pipe for residual tx frames in HIF layer, + * might queue the packet again to HIF Layer - which could cause tx + * buffer leak + */ + + hif_stop(target->hif_dev); + +#ifdef RX_SG_SUPPORT + LOCK_HTC_RX(target); + while ((netbuf = qdf_nbuf_queue_remove(rx_sg_queue)) != NULL) + qdf_nbuf_free(netbuf); + RESET_RX_SG_CONFIG(target); + UNLOCK_HTC_RX(target); +#endif + + reset_endpoint_states(target); + + AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("-htc_stop\n")); +} + +void htc_dump_credit_states(HTC_HANDLE HTCHandle) +{ + HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle); + HTC_ENDPOINT *pEndpoint; + int i; + + for (i = 0; i < ENDPOINT_MAX; i++) { + pEndpoint = &target->endpoint[i]; + if (0 == pEndpoint->service_id) + continue; + + AR_DEBUG_PRINTF(ATH_DEBUG_ANY, + ("--- EP : %d service_id: 0x%X --------------\n", + pEndpoint->Id, pEndpoint->service_id)); + AR_DEBUG_PRINTF(ATH_DEBUG_ANY, + (" TxCredits : %d\n", + pEndpoint->TxCredits)); + AR_DEBUG_PRINTF(ATH_DEBUG_ANY, + (" TxCreditSize : %d\n", + pEndpoint->TxCreditSize)); + AR_DEBUG_PRINTF(ATH_DEBUG_ANY, + (" TxCreditsPerMaxMsg : %d\n", + pEndpoint->TxCreditsPerMaxMsg)); + AR_DEBUG_PRINTF(ATH_DEBUG_ANY, + (" TxQueueDepth : %d\n", + HTC_PACKET_QUEUE_DEPTH(&pEndpoint->TxQueue))); + AR_DEBUG_PRINTF(ATH_DEBUG_ANY, + ("----------------------------------------------------\n")); + } +} + +bool htc_get_endpoint_statistics(HTC_HANDLE HTCHandle, + HTC_ENDPOINT_ID Endpoint, + HTC_ENDPOINT_STAT_ACTION Action, + HTC_ENDPOINT_STATS *pStats) +{ +#ifdef HTC_EP_STAT_PROFILING + HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle); + bool clearStats = false; + bool sample = false; + + switch (Action) { + case HTC_EP_STAT_SAMPLE: + sample = true; + break; + case HTC_EP_STAT_SAMPLE_AND_CLEAR: + sample = true; + clearStats = true; + break; + case HTC_EP_STAT_CLEAR: + clearStats = true; + break; + default: + break; + } + + A_ASSERT(Endpoint < ENDPOINT_MAX); + + /* lock out TX and RX while we sample and/or clear */ + LOCK_HTC_TX(target); + LOCK_HTC_RX(target); + + if (sample) { + A_ASSERT(pStats != NULL); + /* return the stats to the caller */ + qdf_mem_copy(pStats, &target->endpoint[Endpoint].endpoint_stats, + sizeof(HTC_ENDPOINT_STATS)); + } + + if (clearStats) { + /* reset stats */ + qdf_mem_zero(&target->endpoint[Endpoint].endpoint_stats, + sizeof(HTC_ENDPOINT_STATS)); + } + + UNLOCK_HTC_RX(target); + UNLOCK_HTC_TX(target); + + return true; +#else + return false; +#endif +} + +void *htc_get_targetdef(HTC_HANDLE htc_handle) +{ + HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(htc_handle); + + return hif_get_targetdef(target->hif_dev); +} + +#ifdef IPA_OFFLOAD +/** + * htc_ipa_get_ce_resource() - get uc resource on lower layer + * @htc_handle: htc context + * @ce_sr_base_paddr: copyengine source ring base physical address + * @ce_sr_ring_size: copyengine source ring size + * @ce_reg_paddr: copyengine register physical address + * + * Return: None + */ +void htc_ipa_get_ce_resource(HTC_HANDLE htc_handle, + qdf_dma_addr_t *ce_sr_base_paddr, + uint32_t *ce_sr_ring_size, + qdf_dma_addr_t *ce_reg_paddr) +{ + HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(htc_handle); + + if (target->hif_dev != NULL) { + hif_ipa_get_ce_resource(target->hif_dev, + ce_sr_base_paddr, + ce_sr_ring_size, ce_reg_paddr); + } +} +#endif /* IPA_OFFLOAD */ + +#if defined(DEBUG_HL_LOGGING) && defined(CONFIG_HL_SUPPORT) + +void htc_dump_bundle_stats(HTC_HANDLE HTCHandle) +{ + HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle); + int total, i; + + total = 0; + for (i = 0; i < HTC_MAX_MSG_PER_BUNDLE_RX; i++) + total += target->rx_bundle_stats[i]; + + if (total) { + AR_DEBUG_PRINTF(ATH_DEBUG_ANY, ("RX Bundle stats:\n")); + AR_DEBUG_PRINTF(ATH_DEBUG_ANY, ("Total RX packets: %d\n", + total)); + AR_DEBUG_PRINTF(ATH_DEBUG_ANY, ( + "Number of bundle: Number of packets\n")); + for (i = 0; i < HTC_MAX_MSG_PER_BUNDLE_RX; i++) + AR_DEBUG_PRINTF(ATH_DEBUG_ANY, + ("%10d:%10d(%2d%s)\n", (i+1), + target->rx_bundle_stats[i], + ((target->rx_bundle_stats[i]*100)/ + total), "%")); + } + + + total = 0; + for (i = 0; i < HTC_MAX_MSG_PER_BUNDLE_TX; i++) + total += target->tx_bundle_stats[i]; + + if (total) { + AR_DEBUG_PRINTF(ATH_DEBUG_ANY, ("TX Bundle stats:\n")); + AR_DEBUG_PRINTF(ATH_DEBUG_ANY, ("Total TX packets: %d\n", + total)); + AR_DEBUG_PRINTF(ATH_DEBUG_ANY, + ("Number of bundle: Number of packets\n")); + for (i = 0; i < HTC_MAX_MSG_PER_BUNDLE_TX; i++) + AR_DEBUG_PRINTF(ATH_DEBUG_ANY, + ("%10d:%10d(%2d%s)\n", (i+1), + target->tx_bundle_stats[i], + ((target->tx_bundle_stats[i]*100)/ + total), "%")); + } +} + +void htc_clear_bundle_stats(HTC_HANDLE HTCHandle) +{ + HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle); + + qdf_mem_zero(&target->rx_bundle_stats, sizeof(target->rx_bundle_stats)); + qdf_mem_zero(&target->tx_bundle_stats, sizeof(target->tx_bundle_stats)); +} +#endif + +/** + * htc_vote_link_down - API to vote for link down + * @htc_handle: HTC handle + * + * API for upper layers to call HIF to vote for link down + * + * Return: void + */ +void htc_vote_link_down(HTC_HANDLE htc_handle) +{ + HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(htc_handle); + + if (!target->hif_dev) + return; + + hif_vote_link_down(target->hif_dev); +} + +/** + * htc_vote_link_up - API to vote for link up + * @htc_handle: HTC Handle + * + * API for upper layers to call HIF to vote for link up + * + * Return: void + */ +void htc_vote_link_up(HTC_HANDLE htc_handle) +{ + HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(htc_handle); + + if (!target->hif_dev) + return; + + hif_vote_link_up(target->hif_dev); +} + +/** + * htc_can_suspend_link - API to query HIF for link status + * @htc_handle: HTC Handle + * + * API for upper layers to call HIF to query if the link can suspend + * + * Return: void + */ +bool htc_can_suspend_link(HTC_HANDLE htc_handle) +{ + HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(htc_handle); + + if (!target->hif_dev) + return false; + + return hif_can_suspend_link(target->hif_dev); +} + +#ifdef FEATURE_RUNTIME_PM +int htc_pm_runtime_get(HTC_HANDLE htc_handle) +{ + HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(htc_handle); + + HTC_INFO("%s: %pS\n", __func__, (void *)_RET_IP_); + return hif_pm_runtime_get(target->hif_dev); +} + +int htc_pm_runtime_put(HTC_HANDLE htc_handle) +{ + HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(htc_handle); + + HTC_INFO("%s: %pS\n", __func__, (void *)_RET_IP_); + return hif_pm_runtime_put(target->hif_dev); +} +#endif diff --git a/drivers/staging/qca-wifi-host-cmn/htc/htc_api.h b/drivers/staging/qca-wifi-host-cmn/htc/htc_api.h new file mode 100644 index 0000000000000000000000000000000000000000..3a517e3c9325d95d3012497c9cc50fc6480d8abd --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/htc/htc_api.h @@ -0,0 +1,781 @@ +/* + * Copyright (c) 2013-2014, 2016-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef _HTC_API_H_ +#define _HTC_API_H_ + +#include +#include +#include /* qdf_device_t */ +#include "htc_packet.h" + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* TODO.. for BMI */ +#define ENDPOINT1 0 +/* TODO -remove me, but we have to fix BMI first */ +#define HTC_MAILBOX_NUM_MAX 4 + +/* this is the amount of header room required by users of HTC */ +#define HTC_HEADER_LEN HTC_HDR_LENGTH + +#define HTC_HTT_TRANSFER_HDRSIZE 24 + +typedef void *HTC_HANDLE; + +typedef uint16_t HTC_SERVICE_ID; + +typedef void (*HTC_TARGET_FAILURE)(void *Instance, QDF_STATUS Status); + +typedef struct _HTC_INIT_INFO { + void *pContext; /* context for target notifications */ + void (*TargetFailure)(void *Instance, QDF_STATUS Status); + void (*TargetSendSuspendComplete)(void *ctx, bool is_nack); + void (*target_initial_wakeup_cb)(void); +} HTC_INIT_INFO; + +/* Struct for HTC layer packet stats*/ +struct ol_ath_htc_stats { + int htc_get_pkt_q_fail_count; + int htc_pkt_q_empty_count; + int htc_send_q_empty_count; +}; + +/* To resume HTT Tx queue during runtime resume */ +typedef void (*HTC_EP_RESUME_TX_QUEUE)(void *); + +/* per service connection send completion */ +typedef void (*HTC_EP_SEND_PKT_COMPLETE)(void *, HTC_PACKET *); +/* per service connection callback when a plurality of packets have been sent + * The HTC_PACKET_QUEUE is a temporary queue object (e.g. freed on return from the callback) + * to hold a list of completed send packets. + * If the handler cannot fully traverse the packet queue before returning, it should + * transfer the items of the queue into the caller's private queue using: + * HTC_PACKET_ENQUEUE() */ +typedef void (*HTC_EP_SEND_PKT_COMP_MULTIPLE)(void *, + HTC_PACKET_QUEUE *); +/* per service connection pkt received */ +typedef void (*HTC_EP_RECV_PKT)(void *, HTC_PACKET *); +/* per service connection callback when a plurality of packets are received + * The HTC_PACKET_QUEUE is a temporary queue object (e.g. freed on return from the callback) + * to hold a list of recv packets. + * If the handler cannot fully traverse the packet queue before returning, it should + * transfer the items of the queue into the caller's private queue using: + * HTC_PACKET_ENQUEUE() */ +typedef void (*HTC_EP_RECV_PKT_MULTIPLE)(void *, HTC_PACKET_QUEUE *); + +/* Optional per service connection receive buffer re-fill callback, + * On some OSes (like Linux) packets are allocated from a global pool and indicated up + * to the network stack. The driver never gets the packets back from the OS. For these OSes + * a refill callback can be used to allocate and re-queue buffers into HTC. + * + * On other OSes, the network stack can call into the driver's OS-specifc "return_packet" handler and + * the driver can re-queue these buffers into HTC. In this regard a refill callback is + * unnecessary */ +typedef void (*HTC_EP_RECV_REFILL)(void *, HTC_ENDPOINT_ID Endpoint); + +/* Optional per service connection receive buffer allocation callback. + * On some systems packet buffers are an extremely limited resource. Rather than + * queue largest-possible-sized buffers to HTC, some systems would rather + * allocate a specific size as the packet is received. The trade off is + * slightly more processing (callback invoked for each RX packet) + * for the benefit of committing fewer buffer resources into HTC. + * + * The callback is provided the length of the pending packet to fetch. This includes the + * HTC header length plus the length of payload. The callback can return a pointer to + * the allocated HTC packet for immediate use. + * + * Alternatively a variant of this handler can be used to allocate large receive packets as needed. + * For example an application can use the refill mechanism for normal packets and the recv-alloc mechanism to + * handle the case where a large packet buffer is required. This can significantly reduce the + * amount of "committed" memory used to receive packets. + * + * */ +typedef HTC_PACKET *(*HTC_EP_RECV_ALLOC)(void *, + HTC_ENDPOINT_ID Endpoint, + int Length); + +typedef enum _HTC_SEND_FULL_ACTION { + HTC_SEND_FULL_KEEP = 0, /* packet that overflowed should be kept in the queue */ + HTC_SEND_FULL_DROP = 1, /* packet that overflowed should be dropped */ +} HTC_SEND_FULL_ACTION; + +/* Optional per service connection callback when a send queue is full. This can occur if the + * host continues queueing up TX packets faster than credits can arrive + * To prevent the host (on some Oses like Linux) from continuously queueing packets + * and consuming resources, this callback is provided so that that the host + * can disable TX in the subsystem (i.e. network stack). + * This callback is invoked for each packet that "overflows" the HTC queue. The callback can + * determine whether the new packet that overflowed the queue can be kept (HTC_SEND_FULL_KEEP) or + * dropped (HTC_SEND_FULL_DROP). If a packet is dropped, the EpTxComplete handler will be called + * and the packet's status field will be set to A_NO_RESOURCE. + * Other OSes require a "per-packet" indication for each completed TX packet, this + * closed loop mechanism will prevent the network stack from overunning the NIC + * The packet to keep or drop is passed for inspection to the registered handler the handler + * must ONLY inspect the packet, it may not free or reclaim the packet. */ +typedef HTC_SEND_FULL_ACTION (*HTC_EP_SEND_QUEUE_FULL)(void *, + HTC_PACKET * + pPacket); + +typedef struct _HTC_EP_CALLBACKS { + void *pContext; /* context for each callback */ + HTC_EP_SEND_PKT_COMPLETE EpTxComplete; /* tx completion callback for connected endpoint */ + HTC_EP_RECV_PKT EpRecv; /* receive callback for connected endpoint */ + HTC_EP_RECV_REFILL EpRecvRefill; /* OPTIONAL receive re-fill callback for connected endpoint */ + HTC_EP_SEND_QUEUE_FULL EpSendFull; /* OPTIONAL send full callback */ + HTC_EP_RECV_ALLOC EpRecvAlloc; /* OPTIONAL recv allocation callback */ + HTC_EP_RECV_ALLOC EpRecvAllocThresh; /* OPTIONAL recv allocation callback based on a threshold */ + HTC_EP_SEND_PKT_COMP_MULTIPLE EpTxCompleteMultiple; /* OPTIONAL completion handler for multiple complete + indications (EpTxComplete must be NULL) */ + HTC_EP_RECV_PKT_MULTIPLE EpRecvPktMultiple; /* OPTIONAL completion handler for multiple + recv packet indications (EpRecv must be NULL) */ + HTC_EP_RESUME_TX_QUEUE ep_resume_tx_queue; + int RecvAllocThreshold; /* if EpRecvAllocThresh is non-NULL, HTC will compare the + threshold value to the current recv packet length and invoke + the EpRecvAllocThresh callback to acquire a packet buffer */ + int RecvRefillWaterMark; /* if a EpRecvRefill handler is provided, this value + can be used to set a trigger refill callback + when the recv queue drops below this value + if set to 0, the refill is only called when packets + are empty */ +} HTC_EP_CALLBACKS; + +/* service connection information */ +typedef struct _HTC_SERVICE_CONNECT_REQ { + HTC_SERVICE_ID service_id; /* service ID to connect to */ + uint16_t ConnectionFlags; /* connection flags, see htc protocol definition */ + uint8_t *pMetaData; /* ptr to optional service-specific meta-data */ + uint8_t MetaDataLength; /* optional meta data length */ + HTC_EP_CALLBACKS EpCallbacks; /* endpoint callbacks */ + int MaxSendQueueDepth; /* maximum depth of any send queue */ + uint32_t LocalConnectionFlags; /* HTC flags for the host-side (local) connection */ + unsigned int MaxSendMsgSize; /* override max message size in send direction */ +} HTC_SERVICE_CONNECT_REQ; + +#define HTC_LOCAL_CONN_FLAGS_ENABLE_SEND_BUNDLE_PADDING (1 << 0) /* enable send bundle padding for this endpoint */ + +/* service connection response information */ +typedef struct _HTC_SERVICE_CONNECT_RESP { + uint8_t *pMetaData; /* caller supplied buffer to optional meta-data */ + uint8_t BufferLength; /* length of caller supplied buffer */ + uint8_t ActualLength; /* actual length of meta data */ + HTC_ENDPOINT_ID Endpoint; /* endpoint to communicate over */ + unsigned int MaxMsgLength; /* max length of all messages over this endpoint */ + uint8_t ConnectRespCode; /* connect response code from target */ +} HTC_SERVICE_CONNECT_RESP; + +/* endpoint distribution structure */ +typedef struct _HTC_ENDPOINT_CREDIT_DIST { + struct _HTC_ENDPOINT_CREDIT_DIST *pNext; + struct _HTC_ENDPOINT_CREDIT_DIST *pPrev; + HTC_SERVICE_ID service_id; /* Service ID (set by HTC) */ + HTC_ENDPOINT_ID Endpoint; /* endpoint for this distribution struct (set by HTC) */ + uint32_t DistFlags; /* distribution flags, distribution function can + set default activity using SET_EP_ACTIVE() macro */ + int TxCreditsNorm; /* credits for normal operation, anything above this + indicates the endpoint is over-subscribed, this field + is only relevant to the credit distribution function */ + int TxCreditsMin; /* floor for credit distribution, this field is + only relevant to the credit distribution function */ + int TxCreditsAssigned; /* number of credits assigned to this EP, this field + is only relevant to the credit dist function */ + int TxCredits; /* current credits available, this field is used by + HTC to determine whether a message can be sent or + must be queued */ + int TxCreditsToDist; /* pending credits to distribute on this endpoint, this + is set by HTC when credit reports arrive. + The credit distribution functions sets this to zero + when it distributes the credits */ + int TxCreditsSeek; /* this is the number of credits that the current pending TX + packet needs to transmit. This is set by HTC when + and endpoint needs credits in order to transmit */ + int TxCreditSize; /* size in bytes of each credit (set by HTC) */ + int TxCreditsPerMaxMsg; /* credits required for a maximum sized messages (set by HTC) */ + void *pHTCReserved; /* reserved for HTC use */ + int TxQueueDepth; /* current depth of TX queue , i.e. messages waiting for credits + This field is valid only when HTC_CREDIT_DIST_ACTIVITY_CHANGE + or HTC_CREDIT_DIST_SEND_COMPLETE is indicated on an endpoint + that has non-zero credits to recover + */ +} HTC_ENDPOINT_CREDIT_DIST; + +#define HTC_EP_ACTIVE ((uint32_t) (1u << 31)) + +/* macro to check if an endpoint has gone active, useful for credit + * distributions */ +#define IS_EP_ACTIVE(epDist) ((epDist)->DistFlags & HTC_EP_ACTIVE) +#define SET_EP_ACTIVE(epDist) (epDist)->DistFlags |= HTC_EP_ACTIVE + +/* credit distibution code that is passed into the distrbution function, + * there are mandatory and optional codes that must be handled */ +typedef enum _HTC_CREDIT_DIST_REASON { + HTC_CREDIT_DIST_SEND_COMPLETE = 0, /* credits available as a result of completed + send operations (MANDATORY) resulting in credit reports */ + HTC_CREDIT_DIST_ACTIVITY_CHANGE = 1, /* a change in endpoint activity occured (OPTIONAL) */ + HTC_CREDIT_DIST_SEEK_CREDITS, /* an endpoint needs to "seek" credits (OPTIONAL) */ + HTC_DUMP_CREDIT_STATE /* for debugging, dump any state information that is kept by + the distribution function */ +} HTC_CREDIT_DIST_REASON; + +typedef void (*HTC_CREDIT_DIST_CALLBACK)(void *Context, + HTC_ENDPOINT_CREDIT_DIST * + pEPList, + HTC_CREDIT_DIST_REASON + Reason); + +typedef void (*HTC_CREDIT_INIT_CALLBACK)(void *Context, + HTC_ENDPOINT_CREDIT_DIST * + pEPList, int TotalCredits); + +/* endpoint statistics action */ +typedef enum _HTC_ENDPOINT_STAT_ACTION { + HTC_EP_STAT_SAMPLE = 0, /* only read statistics */ + HTC_EP_STAT_SAMPLE_AND_CLEAR = 1, /* sample and immediately clear statistics */ + HTC_EP_STAT_CLEAR /* clear only */ +} HTC_ENDPOINT_STAT_ACTION; + +/* endpoint statistics */ +typedef struct _HTC_ENDPOINT_STATS { + uint32_t TxPosted; /* number of TX packets posted to the endpoint */ + uint32_t TxCreditLowIndications; /* number of times the host set the credit-low flag in a send message on + this endpoint */ + uint32_t TxIssued; /* running count of total TX packets issued */ + uint32_t TxPacketsBundled; /* running count of TX packets that were issued in bundles */ + uint32_t TxBundles; /* running count of TX bundles that were issued */ + uint32_t TxDropped; /* tx packets that were dropped */ + uint32_t TxCreditRpts; /* running count of total credit reports received for this endpoint */ + uint32_t TxCreditRptsFromRx; /* credit reports received from this endpoint's RX packets */ + uint32_t TxCreditRptsFromOther; /* credit reports received from RX packets of other endpoints */ + uint32_t TxCreditRptsFromEp0; /* credit reports received from endpoint 0 RX packets */ + uint32_t TxCreditsFromRx; /* count of credits received via Rx packets on this endpoint */ + uint32_t TxCreditsFromOther; /* count of credits received via another endpoint */ + uint32_t TxCreditsFromEp0; /* count of credits received via another endpoint */ + uint32_t TxCreditsConsummed; /* count of consummed credits */ + uint32_t TxCreditsReturned; /* count of credits returned */ + uint32_t RxReceived; /* count of RX packets received */ + uint32_t RxLookAheads; /* count of lookahead records + found in messages received on this endpoint */ + uint32_t RxPacketsBundled; /* count of recv packets received in a bundle */ + uint32_t RxBundleLookAheads; /* count of number of bundled lookaheads */ + uint32_t RxBundleIndFromHdr; /* count of the number of bundle indications from the HTC header */ + uint32_t RxAllocThreshHit; /* count of the number of times the recv allocation threshhold was hit */ + uint32_t RxAllocThreshBytes; /* total number of bytes */ +} HTC_ENDPOINT_STATS; + +/* ------ Function Prototypes ------ */ +/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + @desc: Create an instance of HTC over the underlying HIF device + @function name: htc_create + @input: HifDevice - hif device handle, + pInfo - initialization information + osdev - QDF device structure + con_mode - driver connection mode + @output: + @return: HTC_HANDLE on success, NULL on failure + @notes: + @example: + @see also: htc_destroy + +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +HTC_HANDLE htc_create(void *HifDevice, HTC_INIT_INFO *pInfo, qdf_device_t osdev, + uint32_t con_mode); +/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + @desc: Get the underlying HIF device handle + @function name: htc_get_hif_device + @input: HTCHandle - handle passed into the AddInstance callback + @output: + @return: opaque HIF device handle usable in HIF API calls. + @notes: + @example: + @see also: + +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +void *htc_get_hif_device(HTC_HANDLE HTCHandle); +/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + @desc: Set credit distribution parameters + @function name: htc_set_credit_distribution + @input: HTCHandle - HTC handle + pCreditDistCont - caller supplied context to pass into distribution functions + CreditDistFunc - Distribution function callback + CreditDistInit - Credit Distribution initialization callback + ServicePriorityOrder - Array containing list of service IDs, lowest index + is highestpriority + ListLength - number of elements in ServicePriorityOrder + @output: + @return: + @notes : The user can set a custom credit distribution function to handle + special requirementsfor each endpoint. A default credit distribution + routine can be used by setting CreditInitFunc to NULL. The default + credit distribution is only provided for simple "fair" credit distribution + without regard to any prioritization. + + @example: + @see also: + +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +void htc_set_credit_distribution(HTC_HANDLE HTCHandle, + void *pCreditDistContext, + HTC_CREDIT_DIST_CALLBACK CreditDistFunc, + HTC_CREDIT_INIT_CALLBACK CreditInitFunc, + HTC_SERVICE_ID ServicePriorityOrder[], + int ListLength); +/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + @desc: Wait for the target to indicate the HTC layer is ready + @function name: htc_wait_target + @input: HTCHandle - HTC handle + @output: + @return: + @notes: This API blocks until the target responds with an HTC ready message. + The caller should not connect services until the target has indicated it is + ready. + @example: + @see also: htc_connect_service + +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +A_STATUS htc_wait_target(HTC_HANDLE HTCHandle); +/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + @desc: Start target service communications + @function name: htc_start + @input: HTCHandle - HTC handle + @output: + @return: + @notes: This API indicates to the target that the service connection phase + is completeand the target can freely start all connected services. This + API should only be called AFTER all service connections have been made. + TCStart will issue a SETUP_COMPLETE message to the target to indicate that + all service connections have been made and the target can start + communicating over the endpoints. + @example: + @see also: htc_connect_service + +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +A_STATUS htc_start(HTC_HANDLE HTCHandle); +/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + @desc: Add receive packet to HTC + @function name: htc_add_receive_pkt + @input: HTCHandle - HTC handle + pPacket - HTC receive packet to add + @output: + @return: A_OK on success + @notes: user must supply HTC packets for capturing incomming HTC frames. + The caller must initialize each HTC packet using the + SET_HTC_PACKET_INFO_RX_REFILL() macro. + @example: + @see also: + +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +A_STATUS htc_add_receive_pkt(HTC_HANDLE HTCHandle, HTC_PACKET *pPacket); +/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + @desc: Connect to an HTC service + @function name: htc_connect_service + @input: HTCHandle - HTC handle + pReq - connection details + @output: pResp - connection response + @return: + @notes: Service connections must be performed before htc_start. + User provides callback handlersfor various endpoint events. + @example: + @see also: htc_start + +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +A_STATUS htc_connect_service(HTC_HANDLE HTCHandle, + HTC_SERVICE_CONNECT_REQ *pReq, + HTC_SERVICE_CONNECT_RESP *pResp); +/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + @desc: HTC register log dump + @function name: htc_dump + @input: HTCHandle - HTC handle + CmdId - Log command + start - start/print logs + @output: + @return: + @notes: Register logs will be started/printed. + be flushed. + @example: + @see also: + +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ + +void htc_dump(HTC_HANDLE HTCHandle, uint8_t CmdId, bool start); +/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + @desc: Send an HTC packet + @function name: htc_send_pkt + @input: HTCHandle - HTC handle + pPacket - packet to send + @output: + @return: A_OK + @notes: Caller must initialize packet using SET_HTC_PACKET_INFO_TX() macro. + This interface is fully asynchronous. On error, HTC SendPkt will + call the registered Endpoint callback to cleanup the packet. + @example: + @see also: htc_flush_endpoint + +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +A_STATUS htc_send_pkt(HTC_HANDLE HTCHandle, HTC_PACKET *pPacket); +/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + @desc: Send an HTC packet containing a tx descriptor and data + @function name: htc_send_data_pkt + @input: HTCHandle - HTC handle + pPacket - packet to send + @output: + @return: A_OK + @notes: Caller must initialize packet using SET_HTC_PACKET_INFO_TX() macro. + Caller must provide headroom in an initial fragment added to the + network buffer to store a HTC_FRAME_HDR. + This interface is fully asynchronous. On error, htc_send_data_pkt will + call the registered Endpoint EpDataTxComplete callback to cleanup + the packet. + @example: + @see also: htc_send_pkt + +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +#ifdef ATH_11AC_TXCOMPACT +A_STATUS htc_send_data_pkt(HTC_HANDLE HTCHandle, qdf_nbuf_t netbuf, + int Epid, int ActualLength); +#else /*ATH_11AC_TXCOMPACT */ +A_STATUS htc_send_data_pkt(HTC_HANDLE HTCHandle, HTC_PACKET *pPacket, + uint8_t more_data); +#endif /*ATH_11AC_TXCOMPACT */ +/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + @desc: Flush HTC when target is removed surprisely service communications + @function name: htc_flush_surprise_remove + @input: HTCHandle - HTC handle + @output: + @return: + @notes: All receive and pending TX packets will + be flushed. + @example: + @see also: + +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +void htc_flush_surprise_remove(HTC_HANDLE HTCHandle); +/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + @desc: Stop HTC service communications + @function name: htc_stop + @input: HTCHandle - HTC handle + @output: + @return: + @notes: HTC communications is halted. All receive and pending TX packets will + be flushed. + @example: + @see also: + +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +void htc_stop(HTC_HANDLE HTCHandle); +/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + @desc: Destory HTC service + @function name: htc_destroy + @input: HTCHandle + @output: + @return: + @notes: This cleans up all resources allocated by htc_create(). + @example: + @see also: htc_create + +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +void htc_destroy(HTC_HANDLE HTCHandle); +/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + @desc: Flush pending TX packets + @function name: htc_flush_endpoint + @input: HTCHandle - HTC handle + Endpoint - Endpoint to flush + Tag - flush tag + @output: + @return: + @notes: The Tag parameter is used to selectively flush packets with matching tags. + The value of 0 forces all packets to be flush regardless of tag. + @example: + @see also: htc_send_pkt + +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +void htc_flush_endpoint(HTC_HANDLE HTCHandle, HTC_ENDPOINT_ID Endpoint, + HTC_TX_TAG Tag); +/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + @desc: Dump credit distribution state + @function name: htc_dump_credit_states + @input: HTCHandle - HTC handle + @output: + @return: + @notes: This dumps all credit distribution information to the debugger + @example: + @see also: + +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +void htc_dump_credit_states(HTC_HANDLE HTCHandle); +/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + @desc: Indicate a traffic activity change on an endpoint + @function name: htc_indicate_activity_change + @input: HTCHandle - HTC handle + Endpoint - endpoint in which activity has changed + Active - true if active, false if it has become inactive + @output: + @return: + @notes: This triggers the registered credit distribution function to + re-adjust credits for active/inactive endpoints. + @example: + @see also: + +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +void htc_indicate_activity_change(HTC_HANDLE HTCHandle, + HTC_ENDPOINT_ID Endpoint, bool Active); + +/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + @desc: Get endpoint statistics + @function name: htc_get_endpoint_statistics + @input: HTCHandle - HTC handle + Endpoint - Endpoint identifier + Action - action to take with statistics + @output: + pStats - statistics that were sampled (can be NULL if Action is HTC_EP_STAT_CLEAR) + + @return: true if statistics profiling is enabled, otherwise false. + + @notes : Statistics is a compile-time option and this function may return + false if HTC is not compiled with profiling. + + The caller can specify the statistic "action" to take when sampling + the statistics. This includes : + + HTC_EP_STAT_SAMPLE : The pStats structure is filled with the current + values. + HTC_EP_STAT_SAMPLE_AND_CLEAR : The structure is filled and the current + statisticsare cleared. + + HTC_EP_STAT_CLEA : the statistics are cleared, the called can pass a NULL + value forpStats + + @example: + @see also: + +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +bool htc_get_endpoint_statistics(HTC_HANDLE HTCHandle, + HTC_ENDPOINT_ID Endpoint, + HTC_ENDPOINT_STAT_ACTION Action, + HTC_ENDPOINT_STATS *pStats); + +/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + @desc: Unblock HTC message reception + @function name: htc_unblock_recv + @input: HTCHandle - HTC handle + @output: + @return: + @notes: + HTC will block the receiver if the EpRecvAlloc callback fails to provide a + packet. The caller can use this API to indicate to HTC when resources + (buffers) are available such that the receiver can be unblocked and HTC + may re-attempt fetching the pending message. + + This API is not required if the user uses the EpRecvRefill callback or uses + the HTCAddReceivePacket()API to recycle or provide receive packets to HTC. + + @example: + @see also: + +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +void htc_unblock_recv(HTC_HANDLE HTCHandle); + +/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + @desc: send a series of HTC packets + @function name: htc_send_pkts_multiple + @input: HTCHandle - HTC handle + pPktQueue - local queue holding packets to send + @output: + @return: A_OK + @notes: Caller must initialize each packet using SET_HTC_PACKET_INFO_TX() macro. + The queue must only contain packets directed at the same endpoint. + Caller supplies a pointer to an HTC_PACKET_QUEUE structure holding the TX packets in FIFO order. + This API will remove the packets from the pkt queue and place them into the HTC Tx Queue + and bundle messages where possible. + The caller may allocate the pkt queue on the stack to hold the packets. + This interface is fully asynchronous. On error, htc_send_pkts will + call the registered Endpoint callback to cleanup the packet. + @example: + @see also: htc_flush_endpoint + +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +A_STATUS htc_send_pkts_multiple(HTC_HANDLE HTCHandle, + HTC_PACKET_QUEUE *pPktQueue); + +/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + @desc: Add multiple receive packets to HTC + @function name: htc_add_receive_pkt_multiple + @input: HTCHandle - HTC handle + pPktQueue - HTC receive packet queue holding packets to add + @output: + @return: A_OK on success + @notes: user must supply HTC packets for capturing incomming HTC frames. The caller + must initialize each HTC packet using the SET_HTC_PACKET_INFO_RX_REFILL() + macro. The queue must only contain recv packets for the same endpoint. + Caller supplies a pointer to an HTC_PACKET_QUEUE structure holding the recv packet. + This API will remove the packets from the pkt queue and place them into internal + recv packet list. + The caller may allocate the pkt queue on the stack to hold the packets. + @example: + @see also: + +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +A_STATUS htc_add_receive_pkt_multiple(HTC_HANDLE HTCHandle, + HTC_PACKET_QUEUE *pPktQueue); + +/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + @desc: Check if an endpoint is marked active + @function name: htc_is_endpoint_active + @input: HTCHandle - HTC handle + Endpoint - endpoint to check for active state + @output: + @return: returns true if Endpoint is Active + @notes: + @example: + @see also: + +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +bool htc_is_endpoint_active(HTC_HANDLE HTCHandle, + HTC_ENDPOINT_ID Endpoint); + +/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + @desc: Set up nodrop pkt flag for mboxping nodrop pkt + @function name: htc_set_nodrop_pkt + @input: HTCHandle - HTC handle + isNodropPkt - indicates whether it is nodrop pkt + @output: + @return: + @notes: + @example: + @see also: + +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +void htc_set_nodrop_pkt(HTC_HANDLE HTCHandle, A_BOOL isNodropPkt); + +/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + @desc: Get the number of recv buffers currently queued into an HTC endpoint + @function name: htc_get_num_recv_buffers + @input: HTCHandle - HTC handle + Endpoint - endpoint to check + @output: + @return: returns number of buffers in queue + @notes: + @example: + @see also: + +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +int htc_get_num_recv_buffers(HTC_HANDLE HTCHandle, + HTC_ENDPOINT_ID Endpoint); + +/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + @desc: Set the target failure handling callback in HTC layer + @function name: htc_set_target_failure_callback + @input: HTCHandle - HTC handle + Callback - target failure handling callback + @output: + @return: + @notes: + @example: + @see also: + +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ +void htc_set_target_failure_callback(HTC_HANDLE HTCHandle, + HTC_TARGET_FAILURE Callback); + +/* internally used functions for testing... */ +void htc_enable_recv(HTC_HANDLE HTCHandle); +void htc_disable_recv(HTC_HANDLE HTCHandle); +A_STATUS HTCWaitForPendingRecv(HTC_HANDLE HTCHandle, + uint32_t TimeoutInMs, + bool *pbIsRecvPending); + +/* function to fetch stats from htc layer*/ +struct ol_ath_htc_stats *ieee80211_ioctl_get_htc_stats(HTC_HANDLE + HTCHandle); +/** + * htc_get_tx_queue_depth() - get the tx queue depth of an htc endpoint + * @htc_handle: htc handle + * @enpoint_id: endpoint to check + * + * Return: htc_handle tx queue depth + */ +int htc_get_tx_queue_depth(HTC_HANDLE *htc_handle, HTC_ENDPOINT_ID endpoint_id); + +#ifdef HIF_USB +#define HTCReturnReceivePkt(target, p, osbuf) \ + do { \ + A_NETBUF_FREE(osbuf); \ + if (p->Status == A_CLONE) { \ + qdf_mem_free(p); \ + } \ + } while (0) +#else +#define HTCReturnReceivePkt(target, p, osbuf) htc_add_receive_pkt(target, p) +#endif + +#ifdef WLAN_FEATURE_FASTPATH +void htc_ctrl_msg_cmpl(HTC_HANDLE htc_pdev, HTC_ENDPOINT_ID htc_ep_id); + +#define HTC_TX_DESC_FILL(_htc_tx_desc, _download_len, _ep_id, _seq_no) \ +do { \ + HTC_WRITE32((_htc_tx_desc), \ + SM((_download_len), HTC_FRAME_HDR_PAYLOADLEN) | \ + SM((_ep_id), HTC_FRAME_HDR_ENDPOINTID)); \ + \ + HTC_WRITE32((uint32_t *)(_htc_tx_desc) + 1, \ + SM((_seq_no), HTC_FRAME_HDR_CONTROLBYTES1));\ +} while (0) +#endif /* WLAN_FEATURE_FASTPATH */ + +#ifdef __cplusplus +} +#endif +void htc_get_control_endpoint_tx_host_credits(HTC_HANDLE HTCHandle, int *credit); +void htc_dump_counter_info(HTC_HANDLE HTCHandle); +void *htc_get_targetdef(HTC_HANDLE htc_handle); +#ifdef FEATURE_RUNTIME_PM +int htc_runtime_suspend(HTC_HANDLE htc_ctx); +int htc_runtime_resume(HTC_HANDLE htc_ctx); +#endif +void htc_global_credit_flow_disable(void); +void htc_global_credit_flow_enable(void); + +/* Disable ASPM : Disable PCIe low power */ +bool htc_can_suspend_link(HTC_HANDLE HTCHandle); +void htc_vote_link_down(HTC_HANDLE HTCHandle); +void htc_vote_link_up(HTC_HANDLE HTCHandle); +#ifdef IPA_OFFLOAD +void htc_ipa_get_ce_resource(HTC_HANDLE htc_handle, + qdf_dma_addr_t *ce_sr_base_paddr, + uint32_t *ce_sr_ring_size, + qdf_dma_addr_t *ce_reg_paddr); +#else +#define htc_ipa_get_ce_resource(htc_handle, \ + ce_sr_base_paddr, \ + ce_sr_ring_size, \ + ce_reg_paddr) /* NO-OP */ +#endif /* IPA_OFFLOAD */ + +#if defined(DEBUG_HL_LOGGING) && defined(CONFIG_HL_SUPPORT) + +/** + * htc_dump_bundle_stats() - dump tx and rx htc message bundle stats + * @HTCHandle: htc handle + * + * Return: None + */ +void htc_dump_bundle_stats(HTC_HANDLE HTCHandle); + +/** + * htc_clear_bundle_stats() - clear tx and rx htc message bundle stats + * @HTCHandle: htc handle + * + * Return: None + */ +void htc_clear_bundle_stats(HTC_HANDLE HTCHandle); +#endif + +#ifdef FEATURE_RUNTIME_PM +int htc_pm_runtime_get(HTC_HANDLE htc_handle); +int htc_pm_runtime_put(HTC_HANDLE htc_handle); +#else +static inline int htc_pm_runtime_get(HTC_HANDLE htc_handle) { return 0; } +static inline int htc_pm_runtime_put(HTC_HANDLE htc_handle) { return 0; } +#endif +#endif /* _HTC_API_H_ */ diff --git a/drivers/staging/qca-wifi-host-cmn/htc/htc_debug.h b/drivers/staging/qca-wifi-host-cmn/htc/htc_debug.h new file mode 100644 index 0000000000000000000000000000000000000000..c3c0a7ae8a4bba93d419325905c6f9159711ce2e --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/htc/htc_debug.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2013-2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef HTC_DEBUG_H_ +#define HTC_DEBUG_H_ + +#define ATH_MODULE_NAME htc +#include "a_debug.h" +#include "qdf_trace.h" + +/* ------- Debug related stuff ------- */ + +#define ATH_DEBUG_SEND ATH_DEBUG_MAKE_MODULE_MASK(0) +#define ATH_DEBUG_RECV ATH_DEBUG_MAKE_MODULE_MASK(1) +#define ATH_DEBUG_SYNC ATH_DEBUG_MAKE_MODULE_MASK(2) +#define ATH_DEBUG_DUMP ATH_DEBUG_MAKE_MODULE_MASK(3) +#define ATH_DEBUG_SETUP ATH_DEBUG_MAKE_MODULE_MASK(4) +#define HTC_ERROR(args ...) \ + QDF_TRACE(QDF_MODULE_ID_HTC, QDF_TRACE_LEVEL_ERROR, ## args) +#define HTC_WARN(args ...) \ + QDF_TRACE(QDF_MODULE_ID_HTC, QDF_TRACE_LEVEL_WARN, ## args) +#define HTC_INFO(args ...) \ + QDF_TRACE(QDF_MODULE_ID_HTC, QDF_TRACE_LEVEL_INFO, ## args) +#define HTC_TRACE(args ...) \ + QDF_TRACE(QDF_MODULE_ID_HTC, QDF_TRACE_LEVEL_DEBUG, ## args) +#endif /*HTC_DEBUG_H_ */ diff --git a/drivers/staging/qca-wifi-host-cmn/htc/htc_internal.h b/drivers/staging/qca-wifi-host-cmn/htc/htc_internal.h new file mode 100644 index 0000000000000000000000000000000000000000..596628cead6aaa65f93e70888b46e28a01a0df3b --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/htc/htc_internal.h @@ -0,0 +1,359 @@ +/* + * Copyright (c) 2013-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef _HTC_INTERNAL_H_ +#define _HTC_INTERNAL_H_ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#include "htc_api.h" +#include "htc_packet.h" +#include +#include +#include +#include +#include +#include +#include +#include + +/* HTC operational parameters */ +#define HTC_TARGET_RESPONSE_TIMEOUT 2000 /* in ms */ +#define HTC_TARGET_DEBUG_INTR_MASK 0x01 +#define HTC_TARGET_CREDIT_INTR_MASK 0xF0 +#define HTC_MIN_MSG_PER_BUNDLE 2 +#if defined(HIF_USB) +#define HTC_MAX_MSG_PER_BUNDLE_RX 11 +#define HTC_MAX_MSG_PER_BUNDLE_TX 8 +#else +#define HTC_MAX_MSG_PER_BUNDLE_RX 64 +#define HTC_MAX_MSG_PER_BUNDLE 16 +#define HTC_MAX_MSG_PER_BUNDLE_TX 32 +#endif + +/* + * HTC_MAX_TX_BUNDLE_SEND_LIMIT - + * This value is in units of tx frame fragments. + * It needs to be at least as large as the maximum number of tx frames in a + * HTC download bundle times the average number of fragments in each such frame + * (In certain operating systems, such as Linux, we expect to only have + * a single fragment per frame anyway.) + */ +#define HTC_MAX_TX_BUNDLE_SEND_LIMIT 255 + +#define HTC_PACKET_CONTAINER_ALLOCATION 32 +#define NUM_CONTROL_TX_BUFFERS 2 +#define HTC_CONTROL_BUFFER_SIZE (HTC_MAX_CONTROL_MESSAGE_LENGTH + HTC_HDR_LENGTH) +#define HTC_CONTROL_BUFFER_ALIGN 32 +#define HTC_TARGET_RESPONSE_POLL_MS 10 +#if !defined(A_SIMOS_DEVHOST) +#define HTC_TARGET_MAX_RESPONSE_POLL 200 /* actual HW */ +#else +#define HTC_TARGET_MAX_RESPONSE_POLL 600 /* host + target simulation */ +#endif + +#define HTC_SERVICE_TX_PACKET_TAG HTC_TX_PACKET_TAG_INTERNAL + +#define HTC_CREDIT_HISTORY_MAX 1024 + +#define HTC_IS_EPPING_ENABLED(_x) ((_x) == QDF_GLOBAL_EPPING_MODE) + +typedef enum { + HTC_REQUEST_CREDIT, + HTC_PROCESS_CREDIT_REPORT, + HTC_SUSPEND_ACK, + HTC_SUSPEND_NACK, + HTC_INITIAL_WAKE_UP, +} htc_credit_exchange_type; + +typedef struct { + htc_credit_exchange_type type; + uint64_t time; + uint32_t tx_credit; + uint32_t htc_tx_queue_depth; +} HTC_CREDIT_HISTORY; + +typedef struct _HTC_ENDPOINT { + HTC_ENDPOINT_ID Id; + + /* service ID this endpoint is bound to + * non-zero value means this endpoint is in use + */ + HTC_SERVICE_ID service_id; + + HTC_EP_CALLBACKS EpCallBacks; /* callbacks associated with this endpoint */ + HTC_PACKET_QUEUE TxQueue; /* HTC frame buffer TX queue */ + int MaxTxQueueDepth; /* max depth of the TX queue before we need to + call driver's full handler */ + int MaxMsgLength; /* max length of endpoint message */ + uint8_t UL_PipeID; + uint8_t DL_PipeID; + int ul_is_polled; /* Need to call HIF to get tx completion callbacks? */ + qdf_timer_t ul_poll_timer; + int ul_poll_timer_active; + int ul_outstanding_cnt; + int dl_is_polled; /* Need to call HIF to fetch rx? (Not currently supported.) */ +#if 0 /* not currently supported */ + qdf_timer_t dl_poll_timer; +#endif + + HTC_PACKET_QUEUE TxLookupQueue; /* lookup queue to match netbufs to htc packets */ + HTC_PACKET_QUEUE RxBufferHoldQueue; /* temporary hold queue for back compatibility */ + uint8_t SeqNo; /* TX seq no (helpful) for debugging */ + qdf_atomic_t TxProcessCount; /* serialization */ + struct _HTC_TARGET *target; + int TxCredits; /* TX credits available on this endpoint */ + int TxCreditSize; /* size in bytes of each credit (set by HTC) */ + int TxCreditsPerMaxMsg; /* credits required per max message (precalculated) */ +#ifdef HTC_EP_STAT_PROFILING + HTC_ENDPOINT_STATS endpoint_stats; /* endpoint statistics */ +#endif + bool TxCreditFlowEnabled; +} HTC_ENDPOINT; + +#ifdef HTC_EP_STAT_PROFILING +#define INC_HTC_EP_STAT(p, stat, count) ((p)->endpoint_stats.stat += (count)) +#else +#define INC_HTC_EP_STAT(p, stat, count) +#endif + +typedef struct { + uint16_t service_id; + uint8_t CreditAllocation; +} HTC_SERVICE_TX_CREDIT_ALLOCATION; + +#define HTC_MAX_SERVICE_ALLOC_ENTRIES 8 + +/* Error codes for HTC layer packet stats*/ +enum ol_ath_htc_pkt_ecodes { + GET_HTC_PKT_Q_FAIL = 0, /* error- get packet at head of HTC_PACKET_Q */ + HTC_PKT_Q_EMPTY, + HTC_SEND_Q_EMPTY +}; +/* our HTC target state */ +typedef struct _HTC_TARGET { + struct hif_opaque_softc *hif_dev; + HTC_ENDPOINT endpoint[ENDPOINT_MAX]; + qdf_spinlock_t HTCLock; + qdf_spinlock_t HTCRxLock; + qdf_spinlock_t HTCTxLock; + qdf_spinlock_t HTCCreditLock; + uint32_t HTCStateFlags; + void *host_handle; + HTC_INIT_INFO HTCInitInfo; + HTC_PACKET *pHTCPacketStructPool; /* pool of HTC packets */ + HTC_PACKET_QUEUE ControlBufferTXFreeList; + uint8_t CtrlResponseBuffer[HTC_MAX_CONTROL_MESSAGE_LENGTH]; + int CtrlResponseLength; + qdf_event_t ctrl_response_valid; + bool CtrlResponseProcessing; + int TotalTransmitCredits; + HTC_SERVICE_TX_CREDIT_ALLOCATION + ServiceTxAllocTable[HTC_MAX_SERVICE_ALLOC_ENTRIES]; + int TargetCreditSize; +#ifdef RX_SG_SUPPORT + qdf_nbuf_queue_t RxSgQueue; + bool IsRxSgInprogress; + uint32_t CurRxSgTotalLen; /* current total length */ + uint32_t ExpRxSgTotalLen; /* expected total length */ +#endif + qdf_device_t osdev; + struct ol_ath_htc_stats htc_pkt_stats; + HTC_PACKET *pBundleFreeList; + uint32_t ce_send_cnt; + uint32_t TX_comp_cnt; + uint8_t MaxMsgsPerHTCBundle; + qdf_work_t queue_kicker; + +#ifdef HIF_SDIO + A_UINT16 AltDataCreditSize; +#endif + A_UINT32 avail_tx_credits; +#if defined(DEBUG_HL_LOGGING) && defined(CONFIG_HL_SUPPORT) + A_UINT32 rx_bundle_stats[HTC_MAX_MSG_PER_BUNDLE_RX]; + A_UINT32 tx_bundle_stats[HTC_MAX_MSG_PER_BUNDLE_TX]; +#endif + + uint32_t con_mode; + + /* + * This flag is from the mboxping tool. It indicates that we cannot + * drop it. Besides, nodrop pkts have higher priority than normal pkts. + */ + A_BOOL is_nodrop_pkt; +} HTC_TARGET; + +#if defined ENABLE_BUNDLE_TX +#define HTC_TX_BUNDLE_ENABLED(target) (target->MaxMsgsPerHTCBundle > 1) +#else +#define HTC_TX_BUNDLE_ENABLED(target) 0 +#endif + +#if defined ENABLE_BUNDLE_RX +#define HTC_RX_BUNDLE_ENABLED(target) (target->MaxMsgsPerHTCBundle > 1) +#else +#define HTC_RX_BUNDLE_ENABLED(target) 0 +#endif + +#define HTC_ENABLE_BUNDLE(target) (target->MaxMsgsPerHTCBundle > 1) + +#ifdef RX_SG_SUPPORT +#define RESET_RX_SG_CONFIG(_target) \ + _target->ExpRxSgTotalLen = 0; \ + _target->CurRxSgTotalLen = 0; \ + _target->IsRxSgInprogress = false; +#endif + +#define HTC_STATE_STOPPING (1 << 0) +#define HTC_STOPPING(t) ((t)->HTCStateFlags & HTC_STATE_STOPPING) +#define LOCK_HTC(t) qdf_spin_lock_bh(&(t)->HTCLock); +#define UNLOCK_HTC(t) qdf_spin_unlock_bh(&(t)->HTCLock); +#define LOCK_HTC_RX(t) qdf_spin_lock_bh(&(t)->HTCRxLock); +#define UNLOCK_HTC_RX(t) qdf_spin_unlock_bh(&(t)->HTCRxLock); +#define LOCK_HTC_TX(t) qdf_spin_lock_bh(&(t)->HTCTxLock); +#define UNLOCK_HTC_TX(t) qdf_spin_unlock_bh(&(t)->HTCTxLock); +#define LOCK_HTC_CREDIT(t) qdf_spin_lock_bh(&(t)->HTCCreditLock); +#define UNLOCK_HTC_CREDIT(t) qdf_spin_unlock_bh(&(t)->HTCCreditLock); + +#define GET_HTC_TARGET_FROM_HANDLE(hnd) ((HTC_TARGET *)(hnd)) + +#define IS_TX_CREDIT_FLOW_ENABLED(ep) ((ep)->TxCreditFlowEnabled) + +#define HTC_POLL_CLEANUP_PERIOD_MS 10 /* milliseconds */ + +/* Macro to Increment the HTC_PACKET_ERRORS for Tx.*/ +#define OL_ATH_HTC_PKT_ERROR_COUNT_INCR(_target, _ecode) \ + do { \ + if (_ecode == GET_HTC_PKT_Q_FAIL) \ + (_target->htc_pkt_stats.htc_get_pkt_q_fail_count) += 1 \ + ; \ + if (_ecode == HTC_PKT_Q_EMPTY) \ + (_target->htc_pkt_stats.htc_pkt_q_empty_count) += 1 \ + ; \ + if (_ecode == HTC_SEND_Q_EMPTY) \ + (_target->htc_pkt_stats.htc_send_q_empty_count) += 1 \ + ; \ + } while (0); +/* internal HTC functions */ + +QDF_STATUS htc_rx_completion_handler(void *Context, qdf_nbuf_t netbuf, + uint8_t pipeID); +QDF_STATUS htc_tx_completion_handler(void *Context, qdf_nbuf_t netbuf, + unsigned int transferID, uint32_t toeplitz_hash_result); + +HTC_PACKET *allocate_htc_bundle_packet(HTC_TARGET *target); +void free_htc_bundle_packet(HTC_TARGET *target, HTC_PACKET *pPacket); + +HTC_PACKET *allocate_htc_packet_container(HTC_TARGET *target); +void free_htc_packet_container(HTC_TARGET *target, HTC_PACKET *pPacket); +void htc_flush_rx_hold_queue(HTC_TARGET *target, HTC_ENDPOINT *pEndpoint); +void htc_flush_endpoint_tx(HTC_TARGET *target, HTC_ENDPOINT *pEndpoint, + HTC_TX_TAG Tag); +void htc_recv_init(HTC_TARGET *target); +A_STATUS htc_wait_recv_ctrl_message(HTC_TARGET *target); +void htc_free_control_tx_packet(HTC_TARGET *target, HTC_PACKET *pPacket); +HTC_PACKET *htc_alloc_control_tx_packet(HTC_TARGET *target); +uint8_t htc_get_credit_allocation(HTC_TARGET *target, uint16_t service_id); +void htc_tx_resource_avail_handler(void *context, uint8_t pipeID); +void htc_control_rx_complete(void *Context, HTC_PACKET *pPacket); +void htc_process_credit_rpt(HTC_TARGET *target, + HTC_CREDIT_REPORT *pRpt, + int NumEntries, HTC_ENDPOINT_ID FromEndpoint); +void htc_fw_event_handler(void *context, QDF_STATUS status); +void htc_send_complete_check_cleanup(void *context); +#ifdef FEATURE_RUNTIME_PM +void htc_kick_queues(void *context); +#endif + +void htc_credit_record(htc_credit_exchange_type type, uint32_t tx_credit, + uint32_t htc_tx_queue_depth); + +static inline void htc_send_complete_poll_timer_stop(HTC_ENDPOINT * + pEndpoint) { + LOCK_HTC_TX(pEndpoint->target); + if (pEndpoint->ul_poll_timer_active) { + /* qdf_timer_stop(&pEndpoint->ul_poll_timer); */ + pEndpoint->ul_poll_timer_active = 0; + } + UNLOCK_HTC_TX(pEndpoint->target); +} + +static inline void htc_send_complete_poll_timer_start(HTC_ENDPOINT * + pEndpoint) { + LOCK_HTC_TX(pEndpoint->target); + if (pEndpoint->ul_outstanding_cnt + && !pEndpoint->ul_poll_timer_active) { + /* + qdf_timer_start( + &pEndpoint->ul_poll_timer, HTC_POLL_CLEANUP_PERIOD_MS); + */ + pEndpoint->ul_poll_timer_active = 1; + } + UNLOCK_HTC_TX(pEndpoint->target); +} + +static inline void +htc_send_complete_check(HTC_ENDPOINT *pEndpoint, int force) { + /* + * Stop the polling-cleanup timer that will result in a later call to + * this function. It may get started again below, if there are still + * outsending sends. + */ + htc_send_complete_poll_timer_stop(pEndpoint); + /* + * Check whether HIF has any prior sends that have finished, + * have not had the post-processing done. + */ + hif_send_complete_check(pEndpoint->target->hif_dev, + pEndpoint->UL_PipeID, force); + /* + * If there are still outstanding sends after polling, start a timer + * to check again a little later. + */ + htc_send_complete_poll_timer_start(pEndpoint); +} + +#ifdef __cplusplus +} +#endif + +#ifndef DEBUG_BUNDLE +#define DEBUG_BUNDLE 0 +#endif + +#if defined(HIF_SDIO) || defined(HIF_USB) +#ifndef ENABLE_BUNDLE_TX +#define ENABLE_BUNDLE_TX 1 +#endif + +#ifndef ENABLE_BUNDLE_RX +#define ENABLE_BUNDLE_RX 1 +#endif +#endif /*defined(HIF_SDIO) || defined(HIF_USB)*/ +#endif /* !_HTC_HOST_INTERNAL_H_ */ diff --git a/drivers/staging/qca-wifi-host-cmn/htc/htc_packet.h b/drivers/staging/qca-wifi-host-cmn/htc/htc_packet.h new file mode 100644 index 0000000000000000000000000000000000000000..a6814a490aff3042338cd7827c12548318ec3f04 --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/htc/htc_packet.h @@ -0,0 +1,311 @@ +/* + * Copyright (c) 2013-2014, 2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef HTC_PACKET_H_ +#define HTC_PACKET_H_ + +#include +#include "dl_list.h" + +/* ------ Endpoint IDS ------ */ +typedef enum { + ENDPOINT_UNUSED = -1, + ENDPOINT_0 = 0, + ENDPOINT_1 = 1, + ENDPOINT_2 = 2, + ENDPOINT_3, + ENDPOINT_4, + ENDPOINT_5, + ENDPOINT_6, + ENDPOINT_7, + ENDPOINT_8, + ENDPOINT_MAX, +} HTC_ENDPOINT_ID; + +struct _HTC_PACKET; + +typedef void (*HTC_PACKET_COMPLETION)(void *, struct _HTC_PACKET *); + +typedef uint16_t HTC_TX_TAG; + +typedef struct _HTC_TX_PACKET_INFO { + HTC_TX_TAG Tag; /* tag used to selective flush packets */ + int CreditsUsed; /* number of credits used for this TX packet (HTC internal) */ + uint8_t SendFlags; /* send flags (HTC internal) */ + int SeqNo; /* internal seq no for debugging (HTC internal) */ + uint32_t Flags; /* internal use */ +} HTC_TX_PACKET_INFO; + +/** + * HTC_TX_PACKET_TAG_XXX - #defines for tagging packets for special handling + * HTC_TX_PACKET_TAG_ALL: zero is reserved and used to flush ALL packets + * HTC_TX_PACKET_TAG_INTERNAL: internal tags start here + * HTC_TX_PACKET_TAG_USER_DEFINED: user-defined tags start here + * HTC_TX_PACKET_TAG_BUNDLED: indicate this is a bundled tx packet + * HTC_TX_PACKET_TAG_AUTO_PM: indicate a power management wmi command + */ +#define HTC_TX_PACKET_TAG_ALL 0 +#define HTC_TX_PACKET_TAG_INTERNAL 1 +#define HTC_TX_PACKET_TAG_USER_DEFINED (HTC_TX_PACKET_TAG_INTERNAL + 9) +#define HTC_TX_PACKET_TAG_BUNDLED (HTC_TX_PACKET_TAG_USER_DEFINED + 1) +#define HTC_TX_PACKET_TAG_AUTO_PM (HTC_TX_PACKET_TAG_USER_DEFINED + 2) + +/* Tag packet for runtime put after sending */ +#define HTC_TX_PACKET_TAG_RUNTIME_PUT (HTC_TX_PACKET_TAG_USER_DEFINED + 3) + + +#define HTC_TX_PACKET_FLAG_FIXUP_NETBUF (1 << 0) + +typedef struct _HTC_RX_PACKET_INFO { + uint32_t ExpectedHdr; /* HTC internal use */ + uint32_t HTCRxFlags; /* HTC internal use */ + uint32_t IndicationFlags; /* indication flags set on each RX packet indication */ +} HTC_RX_PACKET_INFO; + +#define HTC_RX_FLAGS_INDICATE_MORE_PKTS (1 << 0) /* more packets on this endpoint are being fetched */ +#define HTC_PACKET_MAGIC_COOKIE 0xdeadbeef + +/* wrapper around endpoint-specific packets */ +typedef struct _HTC_PACKET { + DL_LIST ListLink; /* double link */ + void *pPktContext; /* caller's per packet specific context */ + + uint8_t *pBufferStart; /* the true buffer start , the caller can + store the real buffer start here. In + receive callbacks, the HTC layer sets pBuffer + to the start of the payload past the header. This + field allows the caller to reset pBuffer when it + recycles receive packets back to HTC */ + /* + * Pointer to the start of the buffer. In the transmit + * direction this points to the start of the payload. In the + * receive direction, however, the buffer when queued up + * points to the start of the HTC header but when returned + * to the caller points to the start of the payload + */ + uint8_t *pBuffer; /* payload start (RX/TX) */ + uint32_t BufferLength; /* length of buffer */ + uint32_t ActualLength; /* actual length of payload */ + HTC_ENDPOINT_ID Endpoint; /* endpoint that this packet was sent/recv'd from */ + A_STATUS Status; /* completion status */ + union { + HTC_TX_PACKET_INFO AsTx; /* Tx Packet specific info */ + HTC_RX_PACKET_INFO AsRx; /* Rx Packet specific info */ + } PktInfo; + + /* the following fields are for internal HTC use */ + uint32_t netbufOrigHeadRoom; + HTC_PACKET_COMPLETION Completion; /* completion */ + void *pContext; /* HTC private completion context */ + void *pNetBufContext; /* optimization for network-oriented data, the HTC packet + can pass the network buffer corresponding to the HTC packet + lower layers may optimized the transfer knowing this is + a network buffer */ + uint32_t magic_cookie; +} HTC_PACKET; + +#define COMPLETE_HTC_PACKET(p, status) \ + { \ + (p)->Status = (status); \ + (p)->Completion((p)->pContext, (p)); \ + } + +#define INIT_HTC_PACKET_INFO(p, b, len) \ + { \ + (p)->pBufferStart = (b); \ + (p)->BufferLength = (len); \ + } + +/* macro to set an initial RX packet for refilling HTC */ +#define SET_HTC_PACKET_INFO_RX_REFILL(p, c, b, len, ep) \ + do { \ + (p)->pPktContext = (c); \ + (p)->pBuffer = (b); \ + (p)->pBufferStart = (b); \ + (p)->BufferLength = (len); \ + (p)->Endpoint = (ep); \ + } while (0) + +/* fast macro to recycle an RX packet that will be re-queued to HTC */ +#define HTC_PACKET_RESET_RX(p) \ + { (p)->pBuffer = (p)->pBufferStart; (p)->ActualLength = 0; } + +/* macro to set packet parameters for TX */ +#define SET_HTC_PACKET_INFO_TX(p, c, b, len, ep, tag) \ + do { \ + (p)->pPktContext = (c); \ + (p)->pBuffer = (b); \ + (p)->ActualLength = (len); \ + (p)->Endpoint = (ep); \ + (p)->PktInfo.AsTx.Tag = (tag); \ + (p)->PktInfo.AsTx.Flags = 0; \ + (p)->PktInfo.AsTx.SendFlags = 0; \ + } while (0) + +#define SET_HTC_PACKET_NET_BUF_CONTEXT(p, nb) \ + do { \ + (p)->pNetBufContext = (nb); \ + } while (0) + +#define GET_HTC_PACKET_NET_BUF_CONTEXT(p) (p)->pNetBufContext + +/* HTC Packet Queueing Macros */ +typedef struct _HTC_PACKET_QUEUE { + DL_LIST QueueHead; + int Depth; +} HTC_PACKET_QUEUE; + +/* initialize queue */ +#define INIT_HTC_PACKET_QUEUE(pQ) \ + { \ + DL_LIST_INIT(&(pQ)->QueueHead); \ + (pQ)->Depth = 0; \ + } + +/* enqueue HTC packet to the tail of the queue */ +#define HTC_PACKET_ENQUEUE(pQ, p) \ + { dl_list_insert_tail(&(pQ)->QueueHead, &(p)->ListLink); \ + (pQ)->Depth++; \ + } + +/* enqueue HTC packet to the tail of the queue */ +#define HTC_PACKET_ENQUEUE_TO_HEAD(pQ, p) \ + { dl_list_insert_head(&(pQ)->QueueHead, &(p)->ListLink); \ + (pQ)->Depth++; \ + } +/* test if a queue is empty */ +#define HTC_QUEUE_EMPTY(pQ) ((pQ)->Depth == 0) +/* get packet at head without removing it */ +static inline HTC_PACKET *htc_get_pkt_at_head(HTC_PACKET_QUEUE *queue) +{ + if (queue->Depth == 0) { + return NULL; + } + return + A_CONTAINING_STRUCT((DL_LIST_GET_ITEM_AT_HEAD(&queue->QueueHead)), + HTC_PACKET, ListLink); +} + +/* remove a packet from a queue, where-ever it is in the queue */ +#define HTC_PACKET_REMOVE(pQ, p) \ + { \ + dl_list_remove(&(p)->ListLink); \ + (pQ)->Depth--; \ + } + +/* dequeue an HTC packet from the head of the queue */ +static inline HTC_PACKET *htc_packet_dequeue(HTC_PACKET_QUEUE *queue) +{ + DL_LIST *pItem = dl_list_remove_item_from_head(&queue->QueueHead); + if (pItem != NULL) { + queue->Depth--; + return A_CONTAINING_STRUCT(pItem, HTC_PACKET, ListLink); + } + return NULL; +} + +/* dequeue an HTC packet from the tail of the queue */ +static inline HTC_PACKET *htc_packet_dequeue_tail(HTC_PACKET_QUEUE *queue) +{ + DL_LIST *pItem = dl_list_remove_item_from_tail(&queue->QueueHead); + if (pItem != NULL) { + queue->Depth--; + return A_CONTAINING_STRUCT(pItem, HTC_PACKET, ListLink); + } + return NULL; +} + +#define HTC_PACKET_QUEUE_DEPTH(pQ) (pQ)->Depth + +#define HTC_GET_ENDPOINT_FROM_PKT(p) (p)->Endpoint +#define HTC_GET_TAG_FROM_PKT(p) (p)->PktInfo.AsTx.Tag + +/* transfer the packets from one queue to the tail of another queue */ +#define HTC_PACKET_QUEUE_TRANSFER_TO_TAIL(pQDest, pQSrc) \ + { \ + dl_list_transfer_items_to_tail(&(pQDest)->QueueHead, &(pQSrc)->QueueHead); \ + (pQDest)->Depth += (pQSrc)->Depth; \ + (pQSrc)->Depth = 0; \ + } + +/* + * Transfer the packets from one queue to the head of another queue. + * This xfer_to_head(q1,q2) is basically equivalent to xfer_to_tail(q2,q1), + * but it updates the queue descriptor object for the initial queue to refer + * to the concatenated queue. + */ +#define HTC_PACKET_QUEUE_TRANSFER_TO_HEAD(pQDest, pQSrc) \ + { \ + dl_list_transfer_items_to_head(&(pQDest)->QueueHead, &(pQSrc)->QueueHead); \ + (pQDest)->Depth += (pQSrc)->Depth; \ + (pQSrc)->Depth = 0; \ + } + +/* fast version to init and add a single packet to a queue */ +#define INIT_HTC_PACKET_QUEUE_AND_ADD(pQ, pP) \ + { \ + DL_LIST_INIT_AND_ADD(&(pQ)->QueueHead, &(pP)->ListLink) \ + (pQ)->Depth = 1; \ + } + +#define HTC_PACKET_QUEUE_ITERATE_ALLOW_REMOVE(pQ, pPTemp) \ + ITERATE_OVER_LIST_ALLOW_REMOVE(&(pQ)->QueueHead, (pPTemp), HTC_PACKET, ListLink) + +#define HTC_PACKET_QUEUE_ITERATE_IS_VALID(pQ) ITERATE_IS_VALID(&(pQ)->QueueHead) +#define HTC_PACKET_QUEUE_ITERATE_RESET(pQ) ITERATE_RESET(&(pQ)->QueueHead) + +#define HTC_PACKET_QUEUE_ITERATE_END ITERATE_END + +/** + * htc_packet_set_magic_cookie() - set magic cookie in htc packet + * htc_pkt - pointer to htc packet + * value - value to set in magic cookie + * + * This API sets the magic cookie passed in htc packet. + * + * Return : None + */ +static inline void htc_packet_set_magic_cookie(HTC_PACKET *htc_pkt, + uint32_t value) +{ + htc_pkt->magic_cookie = value; +} + +/** + * htc_packet_set_magic_cookie() - get magic cookie in htc packet + * htc_pkt - pointer to htc packet + * + * This API returns the magic cookie in htc packet. + * + * Return : magic cookie + */ +static inline uint32_t htc_packet_get_magic_cookie(HTC_PACKET *htc_pkt) +{ + return htc_pkt->magic_cookie; +} + +#endif /*HTC_PACKET_H_ */ diff --git a/drivers/staging/qca-wifi-host-cmn/htc/htc_recv.c b/drivers/staging/qca-wifi-host-cmn/htc/htc_recv.c new file mode 100644 index 0000000000000000000000000000000000000000..4db2c1b26114142a3dbeea0f50886a91cad00354 --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/htc/htc_recv.c @@ -0,0 +1,771 @@ +/* + * Copyright (c) 2013-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#include "htc_debug.h" +#include "htc_internal.h" +#include /* qdf_nbuf_t */ + +/* HTC Control message receive timeout msec */ +#define HTC_CONTROL_RX_TIMEOUT 3000 + +#if defined(WLAN_DEBUG) || defined(DEBUG) +void debug_dump_bytes(uint8_t *buffer, uint16_t length, char *pDescription) +{ + int8_t stream[60]; + int8_t byteOffsetStr[10]; + uint32_t i; + uint16_t offset, count, byteOffset; + + A_PRINTF("<---------Dumping %d Bytes : %s ------>\n", length, + pDescription); + + count = 0; + offset = 0; + byteOffset = 0; + for (i = 0; i < length; i++) { + A_SNPRINTF(stream + offset, (sizeof(stream) - offset), + "%02X ", buffer[i]); + count++; + offset += 3; + + if (count == 16) { + count = 0; + offset = 0; + A_SNPRINTF(byteOffsetStr, sizeof(byteOffset), "%4.4X", + byteOffset); + A_PRINTF("[%s]: %s\n", byteOffsetStr, stream); + qdf_mem_zero(stream, 60); + byteOffset += 16; + } + } + + if (offset != 0) { + A_SNPRINTF(byteOffsetStr, sizeof(byteOffset), "%4.4X", + byteOffset); + A_PRINTF("[%s]: %s\n", byteOffsetStr, stream); + } + + A_PRINTF("<------------------------------------------------->\n"); +} +#else +void debug_dump_bytes(uint8_t *buffer, uint16_t length, char *pDescription) +{ +} +#endif + +static A_STATUS htc_process_trailer(HTC_TARGET *target, + uint8_t *pBuffer, + int Length, HTC_ENDPOINT_ID FromEndpoint); + +static void do_recv_completion(HTC_ENDPOINT *pEndpoint, + HTC_PACKET_QUEUE *pQueueToIndicate) +{ + + do { + + if (HTC_QUEUE_EMPTY(pQueueToIndicate)) { + /* nothing to indicate */ + break; + } + + if (pEndpoint->EpCallBacks.EpRecvPktMultiple != NULL) { + AR_DEBUG_PRINTF(ATH_DEBUG_RECV, + (" HTC calling ep %d, recv multiple callback (%d pkts) \n", + pEndpoint->Id, + HTC_PACKET_QUEUE_DEPTH + (pQueueToIndicate))); + /* a recv multiple handler is being used, pass the queue to the handler */ + pEndpoint->EpCallBacks.EpRecvPktMultiple(pEndpoint-> + EpCallBacks. + pContext, + pQueueToIndicate); + INIT_HTC_PACKET_QUEUE(pQueueToIndicate); + } else { + HTC_PACKET *pPacket; + /* using legacy EpRecv */ + while (!HTC_QUEUE_EMPTY(pQueueToIndicate)) { + pPacket = htc_packet_dequeue(pQueueToIndicate); + if (pEndpoint->EpCallBacks.EpRecv == NULL) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + ("HTC ep %d has NULL recv callback on packet %p\n", + pEndpoint->Id, + pPacket)); + if (pPacket) + qdf_nbuf_free( + pPacket->pPktContext); + continue; + } + AR_DEBUG_PRINTF(ATH_DEBUG_RECV, + ("HTC calling ep %d recv callback on packet %p\n", + pEndpoint->Id, pPacket)); + pEndpoint->EpCallBacks.EpRecv(pEndpoint-> + EpCallBacks. + pContext, + pPacket); + } + } + + } while (false); + +} + +static void recv_packet_completion(HTC_TARGET *target, HTC_ENDPOINT *pEndpoint, + HTC_PACKET *pPacket) +{ + HTC_PACKET_QUEUE container; + INIT_HTC_PACKET_QUEUE_AND_ADD(&container, pPacket); + /* do completion */ + do_recv_completion(pEndpoint, &container); +} + +void htc_control_rx_complete(void *Context, HTC_PACKET *pPacket) +{ + /* TODO, can't really receive HTC control messages yet.... */ + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + ("Invalid call to htc_control_rx_complete\n")); +} + +void htc_unblock_recv(HTC_HANDLE HTCHandle) +{ + /* TODO find the Need in new model */ +} + +void htc_enable_recv(HTC_HANDLE HTCHandle) +{ + + /* TODO find the Need in new model */ +} + +void htc_disable_recv(HTC_HANDLE HTCHandle) +{ + + /* TODO find the Need in new model */ +} + +int htc_get_num_recv_buffers(HTC_HANDLE HTCHandle, HTC_ENDPOINT_ID Endpoint) +{ + HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle); + HTC_ENDPOINT *pEndpoint = &target->endpoint[Endpoint]; + return HTC_PACKET_QUEUE_DEPTH(&pEndpoint->RxBufferHoldQueue); +} + +HTC_PACKET *allocate_htc_packet_container(HTC_TARGET *target) +{ + HTC_PACKET *pPacket; + + LOCK_HTC_RX(target); + + if (NULL == target->pHTCPacketStructPool) { + UNLOCK_HTC_RX(target); + return NULL; + } + + pPacket = target->pHTCPacketStructPool; + target->pHTCPacketStructPool = (HTC_PACKET *) pPacket->ListLink.pNext; + + UNLOCK_HTC_RX(target); + + pPacket->ListLink.pNext = NULL; + return pPacket; +} + +void free_htc_packet_container(HTC_TARGET *target, HTC_PACKET *pPacket) +{ + LOCK_HTC_RX(target); + + if (NULL == target->pHTCPacketStructPool) { + target->pHTCPacketStructPool = pPacket; + pPacket->ListLink.pNext = NULL; + } else { + pPacket->ListLink.pNext = + (DL_LIST *) target->pHTCPacketStructPool; + target->pHTCPacketStructPool = pPacket; + } + + UNLOCK_HTC_RX(target); +} + +#ifdef RX_SG_SUPPORT +qdf_nbuf_t rx_sg_to_single_netbuf(HTC_TARGET *target) +{ + qdf_nbuf_t skb; + uint8_t *anbdata; + uint8_t *anbdata_new; + uint32_t anblen; + qdf_nbuf_t new_skb = NULL; + uint32_t sg_queue_len; + qdf_nbuf_queue_t *rx_sg_queue = &target->RxSgQueue; + + sg_queue_len = qdf_nbuf_queue_len(rx_sg_queue); + + if (sg_queue_len <= 1) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + ("rx_sg_to_single_netbuf: invalid sg queue len %u\n")); + goto _failed; + } + + new_skb = qdf_nbuf_alloc(target->ExpRxSgTotalLen, 0, 4, false); + if (new_skb == NULL) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + ("rx_sg_to_single_netbuf: can't allocate %u size netbuf\n", + target->ExpRxSgTotalLen)); + goto _failed; + } + + qdf_nbuf_peek_header(new_skb, &anbdata_new, &anblen); + + skb = qdf_nbuf_queue_remove(rx_sg_queue); + do { + qdf_nbuf_peek_header(skb, &anbdata, &anblen); + qdf_mem_copy(anbdata_new, anbdata, qdf_nbuf_len(skb)); + qdf_nbuf_put_tail(new_skb, qdf_nbuf_len(skb)); + anbdata_new += qdf_nbuf_len(skb); + qdf_nbuf_free(skb); + skb = qdf_nbuf_queue_remove(rx_sg_queue); + } while (skb != NULL); + + RESET_RX_SG_CONFIG(target); + return new_skb; + +_failed: + + while ((skb = qdf_nbuf_queue_remove(rx_sg_queue)) != NULL) + qdf_nbuf_free(skb); + + RESET_RX_SG_CONFIG(target); + return NULL; +} +#endif + +#ifdef CONFIG_WIN +#define HTC_MSG_NACK_SUSPEND 7 +#endif + +QDF_STATUS htc_rx_completion_handler(void *Context, qdf_nbuf_t netbuf, + uint8_t pipeID) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + HTC_FRAME_HDR *HtcHdr; + HTC_TARGET *target = (HTC_TARGET *) Context; + uint8_t *netdata; + uint32_t netlen; + HTC_ENDPOINT *pEndpoint; + HTC_PACKET *pPacket; + uint16_t payloadLen; + uint32_t trailerlen = 0; + uint8_t htc_ep_id; + +#ifdef RX_SG_SUPPORT + LOCK_HTC_RX(target); + if (target->IsRxSgInprogress) { + target->CurRxSgTotalLen += qdf_nbuf_len(netbuf); + qdf_nbuf_queue_add(&target->RxSgQueue, netbuf); + if (target->CurRxSgTotalLen == target->ExpRxSgTotalLen) { + netbuf = rx_sg_to_single_netbuf(target); + if (netbuf == NULL) { + UNLOCK_HTC_RX(target); + goto _out; + } + } else { + netbuf = NULL; + UNLOCK_HTC_RX(target); + goto _out; + } + } + UNLOCK_HTC_RX(target); +#endif + + netdata = qdf_nbuf_data(netbuf); + netlen = qdf_nbuf_len(netbuf); + + HtcHdr = (HTC_FRAME_HDR *) netdata; + + do { + + htc_ep_id = HTC_GET_FIELD(HtcHdr, HTC_FRAME_HDR, ENDPOINTID); + + if (htc_ep_id >= ENDPOINT_MAX) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + ("HTC Rx: invalid EndpointID=%d\n", + htc_ep_id)); + debug_dump_bytes((uint8_t *) HtcHdr, + sizeof(HTC_FRAME_HDR), "BAD HTC Header"); + status = QDF_STATUS_E_FAILURE; + QDF_BUG(0); + break; + } + + pEndpoint = &target->endpoint[htc_ep_id]; + + /* + * If this endpoint that received a message from the target has + * a to-target HIF pipe whose send completions are polled rather + * than interrupt-driven, this is a good point to ask HIF to check + * whether it has any completed sends to handle. + */ + if (pEndpoint->ul_is_polled) { + htc_send_complete_check(pEndpoint, 1); + } + + payloadLen = HTC_GET_FIELD(HtcHdr, HTC_FRAME_HDR, PAYLOADLEN); + + if (netlen < (payloadLen + HTC_HDR_LENGTH)) { +#ifdef RX_SG_SUPPORT + LOCK_HTC_RX(target); + target->IsRxSgInprogress = true; + qdf_nbuf_queue_init(&target->RxSgQueue); + qdf_nbuf_queue_add(&target->RxSgQueue, netbuf); + target->ExpRxSgTotalLen = (payloadLen + HTC_HDR_LENGTH); + target->CurRxSgTotalLen += netlen; + UNLOCK_HTC_RX(target); + netbuf = NULL; + break; +#else + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + ("HTC Rx: insufficient length, got:%d expected =%zu\n", + netlen, payloadLen + HTC_HDR_LENGTH)); + debug_dump_bytes((uint8_t *) HtcHdr, + sizeof(HTC_FRAME_HDR), + "BAD RX packet length"); + status = QDF_STATUS_E_FAILURE; + QDF_BUG(0); + break; +#endif + } +#ifdef HTC_EP_STAT_PROFILING + LOCK_HTC_RX(target); + INC_HTC_EP_STAT(pEndpoint, RxReceived, 1); + UNLOCK_HTC_RX(target); +#endif + + /* if (IS_TX_CREDIT_FLOW_ENABLED(pEndpoint)) { */ + { + uint8_t temp; + A_STATUS temp_status; + /* get flags to check for trailer */ + temp = HTC_GET_FIELD(HtcHdr, HTC_FRAME_HDR, FLAGS); + if (temp & HTC_FLAGS_RECV_TRAILER) { + /* extract the trailer length */ + temp = + HTC_GET_FIELD(HtcHdr, HTC_FRAME_HDR, + CONTROLBYTES0); + if ((temp < sizeof(HTC_RECORD_HDR)) + || (temp > payloadLen)) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + ("htc_rx_completion_handler, invalid header (payloadlength should be :%d, CB[0] is:%d)\n", + payloadLen, temp)); + status = QDF_STATUS_E_INVAL; + break; + } + + trailerlen = temp; + /* process trailer data that follows HDR + application payload */ + temp_status = htc_process_trailer(target, + ((uint8_t *) HtcHdr + + HTC_HDR_LENGTH + + payloadLen - temp), + temp, htc_ep_id); + if (A_FAILED(temp_status)) { + status = QDF_STATUS_E_FAILURE; + break; + } + + } + } + + if (((int)payloadLen - (int)trailerlen) <= 0) { + /* zero length packet with trailer data, just drop these */ + break; + } + + if (htc_ep_id == ENDPOINT_0) { + uint16_t message_id; + HTC_UNKNOWN_MSG *htc_msg; + bool wow_nack; + + /* remove HTC header */ + qdf_nbuf_pull_head(netbuf, HTC_HDR_LENGTH); + netdata = qdf_nbuf_data(netbuf); + netlen = qdf_nbuf_len(netbuf); + + htc_msg = (HTC_UNKNOWN_MSG *) netdata; + message_id = + HTC_GET_FIELD(htc_msg, HTC_UNKNOWN_MSG, MESSAGEID); + + switch (message_id) { + default: + /* handle HTC control message */ + if (target->CtrlResponseProcessing) { + /* this is a fatal error, target should not be sending unsolicited messages + * on the endpoint 0 */ + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + ("HTC Rx Ctrl still processing\n")); + status = QDF_STATUS_E_FAILURE; + QDF_BUG(false); + break; + } + + LOCK_HTC_RX(target); + target->CtrlResponseLength = + min((int)netlen, + HTC_MAX_CONTROL_MESSAGE_LENGTH); + qdf_mem_copy(target->CtrlResponseBuffer, + netdata, + target->CtrlResponseLength); + + /* Requester will clear this flag */ + target->CtrlResponseProcessing = true; + UNLOCK_HTC_RX(target); + + qdf_event_set(&target->ctrl_response_valid); + break; +#ifdef HTC_MSG_WAKEUP_FROM_SUSPEND_ID + case HTC_MSG_WAKEUP_FROM_SUSPEND_ID: + AR_DEBUG_PRINTF(ATH_DEBUG_ANY, + ("Received initial wake up")); + LOCK_HTC_CREDIT(target); + htc_credit_record(HTC_INITIAL_WAKE_UP, + pEndpoint->TxCredits, + HTC_PACKET_QUEUE_DEPTH( + &pEndpoint->TxQueue)); + UNLOCK_HTC_CREDIT(target); + if (target->HTCInitInfo.target_initial_wakeup_cb) + target->HTCInitInfo.target_initial_wakeup_cb(); + else + AR_DEBUG_PRINTF(ATH_DEBUG_ANY, + ("No initial wake up cb")); + break; +#endif + case HTC_MSG_SEND_SUSPEND_COMPLETE: + wow_nack = false; + LOCK_HTC_CREDIT(target); + htc_credit_record(HTC_SUSPEND_ACK, + pEndpoint->TxCredits, + HTC_PACKET_QUEUE_DEPTH( + &pEndpoint->TxQueue)); + UNLOCK_HTC_CREDIT(target); + target->HTCInitInfo.TargetSendSuspendComplete( + target->HTCInitInfo.pContext, + wow_nack); + + break; + case HTC_MSG_NACK_SUSPEND: + wow_nack = true; + LOCK_HTC_CREDIT(target); + htc_credit_record(HTC_SUSPEND_ACK, + pEndpoint->TxCredits, + HTC_PACKET_QUEUE_DEPTH( + &pEndpoint->TxQueue)); + UNLOCK_HTC_CREDIT(target); + + target->HTCInitInfo.TargetSendSuspendComplete( + target->HTCInitInfo.pContext, + wow_nack); + break; + } + + qdf_nbuf_free(netbuf); + netbuf = NULL; + break; + } + + /* the current message based HIF architecture allocates net bufs for recv packets + * since this layer bridges that HIF to upper layers , which expects HTC packets, + * we form the packets here + * TODO_FIXME */ + pPacket = allocate_htc_packet_container(target); + if (NULL == pPacket) { + status = QDF_STATUS_E_RESOURCES; + break; + } + pPacket->Status = QDF_STATUS_SUCCESS; + pPacket->Endpoint = htc_ep_id; + pPacket->pPktContext = netbuf; + pPacket->pBuffer = qdf_nbuf_data(netbuf) + HTC_HDR_LENGTH; + pPacket->ActualLength = netlen - HTC_HEADER_LEN - trailerlen; + + qdf_nbuf_pull_head(netbuf, HTC_HEADER_LEN); + qdf_nbuf_set_pktlen(netbuf, pPacket->ActualLength); + + recv_packet_completion(target, pEndpoint, pPacket); + /* recover the packet container */ + free_htc_packet_container(target, pPacket); + netbuf = NULL; + + } while (false); + +#ifdef RX_SG_SUPPORT +_out: +#endif + + if (netbuf != NULL) { + qdf_nbuf_free(netbuf); + } + + return status; + +} + +A_STATUS htc_add_receive_pkt_multiple(HTC_HANDLE HTCHandle, + HTC_PACKET_QUEUE *pPktQueue) +{ + HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle); + HTC_ENDPOINT *pEndpoint; + HTC_PACKET *pFirstPacket; + A_STATUS status = A_OK; + HTC_PACKET *pPacket; + + pFirstPacket = htc_get_pkt_at_head(pPktQueue); + + if (NULL == pFirstPacket) { + A_ASSERT(false); + return A_EINVAL; + } + + AR_DEBUG_ASSERT(pFirstPacket->Endpoint < ENDPOINT_MAX); + + AR_DEBUG_PRINTF(ATH_DEBUG_RECV, + ("+- htc_add_receive_pkt_multiple : endPointId: %d, cnt:%d, length: %d\n", + pFirstPacket->Endpoint, + HTC_PACKET_QUEUE_DEPTH(pPktQueue), + pFirstPacket->BufferLength)); + + pEndpoint = &target->endpoint[pFirstPacket->Endpoint]; + + LOCK_HTC_RX(target); + + do { + + if (HTC_STOPPING(target)) { + status = A_ERROR; + break; + } + + /* store receive packets */ + HTC_PACKET_QUEUE_TRANSFER_TO_TAIL(&pEndpoint->RxBufferHoldQueue, + pPktQueue); + + } while (false); + + UNLOCK_HTC_RX(target); + + if (A_FAILED(status)) { + /* walk through queue and mark each one canceled */ + HTC_PACKET_QUEUE_ITERATE_ALLOW_REMOVE(pPktQueue, pPacket) { + pPacket->Status = A_ECANCELED; + } + HTC_PACKET_QUEUE_ITERATE_END; + + do_recv_completion(pEndpoint, pPktQueue); + } + + return status; +} + +A_STATUS htc_add_receive_pkt(HTC_HANDLE HTCHandle, HTC_PACKET *pPacket) +{ + HTC_PACKET_QUEUE queue; + INIT_HTC_PACKET_QUEUE_AND_ADD(&queue, pPacket); + return htc_add_receive_pkt_multiple(HTCHandle, &queue); +} + +void htc_flush_rx_hold_queue(HTC_TARGET *target, HTC_ENDPOINT *pEndpoint) +{ + HTC_PACKET *pPacket; + HTC_PACKET_QUEUE container; + + LOCK_HTC_RX(target); + + while (1) { + pPacket = htc_packet_dequeue(&pEndpoint->RxBufferHoldQueue); + if (NULL == pPacket) { + break; + } + UNLOCK_HTC_RX(target); + pPacket->Status = A_ECANCELED; + pPacket->ActualLength = 0; + AR_DEBUG_PRINTF(ATH_DEBUG_RECV, + (" Flushing RX packet:%p, length:%d, ep:%d \n", + pPacket, pPacket->BufferLength, + pPacket->Endpoint)); + INIT_HTC_PACKET_QUEUE_AND_ADD(&container, pPacket); + /* give the packet back */ + do_recv_completion(pEndpoint, &container); + LOCK_HTC_RX(target); + } + + UNLOCK_HTC_RX(target); +} + +void htc_recv_init(HTC_TARGET *target) +{ + /* Initialize ctrl_response_valid to block */ + qdf_event_create(&target->ctrl_response_valid); +} + +/* polling routine to wait for a control packet to be received */ +A_STATUS htc_wait_recv_ctrl_message(HTC_TARGET *target) +{ +/* int count = HTC_TARGET_MAX_RESPONSE_POLL; */ + + AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("+HTCWaitCtrlMessageRecv\n")); + + /* Wait for BMI request/response transaction to complete */ + if (qdf_wait_single_event(&target->ctrl_response_valid, + HTC_CONTROL_RX_TIMEOUT)) { + return A_ERROR; + } + + LOCK_HTC_RX(target); + /* caller will clear this flag */ + target->CtrlResponseProcessing = true; + + UNLOCK_HTC_RX(target); + +#if 0 + while (count > 0) { + + LOCK_HTC_RX(target); + + if (target->CtrlResponseValid) { + target->CtrlResponseValid = false; + /* caller will clear this flag */ + target->CtrlResponseProcessing = true; + UNLOCK_HTC_RX(target); + break; + } + + UNLOCK_HTC_RX(target); + + count--; + A_MSLEEP(HTC_TARGET_RESPONSE_POLL_MS); + } + + if (count <= 0) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + ("-HTCWaitCtrlMessageRecv: Timeout!\n")); + return A_ECOMM; + } +#endif + + AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("-HTCWaitCtrlMessageRecv success\n")); + return A_OK; +} + +static A_STATUS htc_process_trailer(HTC_TARGET *target, + uint8_t *pBuffer, + int Length, HTC_ENDPOINT_ID FromEndpoint) +{ + HTC_RECORD_HDR *pRecord; + uint8_t htc_rec_id; + uint8_t htc_rec_len; + uint8_t *pRecordBuf; + uint8_t *pOrigBuffer; + int origLength; + A_STATUS status; + + AR_DEBUG_PRINTF(ATH_DEBUG_RECV, + ("+htc_process_trailer (length:%d) \n", Length)); + + if (AR_DEBUG_LVL_CHECK(ATH_DEBUG_RECV)) { + AR_DEBUG_PRINTBUF(pBuffer, Length, "Recv Trailer"); + } + + pOrigBuffer = pBuffer; + origLength = Length; + status = A_OK; + + while (Length > 0) { + + if (Length < sizeof(HTC_RECORD_HDR)) { + status = A_EPROTO; + break; + } + /* these are byte aligned structs */ + pRecord = (HTC_RECORD_HDR *) pBuffer; + Length -= sizeof(HTC_RECORD_HDR); + pBuffer += sizeof(HTC_RECORD_HDR); + + htc_rec_len = HTC_GET_FIELD(pRecord, HTC_RECORD_HDR, LENGTH); + htc_rec_id = HTC_GET_FIELD(pRecord, HTC_RECORD_HDR, RECORDID); + + if (htc_rec_len > Length) { + /* no room left in buffer for record */ + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + (" invalid record length: %d (id:%d) buffer has: %d bytes left \n", + htc_rec_len, htc_rec_id, Length)); + status = A_EPROTO; + break; + } + /* start of record follows the header */ + pRecordBuf = pBuffer; + + switch (htc_rec_id) { + case HTC_RECORD_CREDITS: + AR_DEBUG_ASSERT(htc_rec_len >= + sizeof(HTC_CREDIT_REPORT)); + htc_process_credit_rpt(target, + (HTC_CREDIT_REPORT *) pRecordBuf, + htc_rec_len / + (sizeof(HTC_CREDIT_REPORT)), + FromEndpoint); + break; + +#ifdef HIF_SDIO + case HTC_RECORD_LOOKAHEAD: + /* Process in HIF layer */ + break; + + case HTC_RECORD_LOOKAHEAD_BUNDLE: + /* Process in HIF layer */ + break; +#endif /* HIF_SDIO */ + + default: + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + (" HTC unhandled record: id:%d length:%d \n", + htc_rec_id, htc_rec_len)); + break; + } + + if (A_FAILED(status)) { + break; + } + + /* advance buffer past this record for next time around */ + pBuffer += htc_rec_len; + Length -= htc_rec_len; + } + + if (A_FAILED(status)) { + debug_dump_bytes(pOrigBuffer, origLength, "BAD Recv Trailer"); + } + + AR_DEBUG_PRINTF(ATH_DEBUG_RECV, ("-htc_process_trailer \n")); + return status; + +} diff --git a/drivers/staging/qca-wifi-host-cmn/htc/htc_send.c b/drivers/staging/qca-wifi-host-cmn/htc/htc_send.c new file mode 100644 index 0000000000000000000000000000000000000000..2ee6c7b9f985842aca2cc7d43407c46f65e8ac9b --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/htc/htc_send.c @@ -0,0 +1,2180 @@ +/* + * Copyright (c) 2013-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#include "htc_debug.h" +#include "htc_internal.h" +#include /* qdf_mem_malloc */ +#include /* qdf_nbuf_t */ + + +/* #define USB_HIF_SINGLE_PIPE_DATA_SCHED */ +/* #ifdef USB_HIF_SINGLE_PIPE_DATA_SCHED */ +#define DATA_EP_SIZE 4 +/* #endif */ +#define HTC_DATA_RESOURCE_THRS 256 +#define HTC_DATA_MINDESC_PERPACKET 2 + +typedef enum _HTC_SEND_QUEUE_RESULT { + HTC_SEND_QUEUE_OK = 0, /* packet was queued */ + HTC_SEND_QUEUE_DROP = 1, /* this packet should be dropped */ +} HTC_SEND_QUEUE_RESULT; + +#ifndef DEBUG_CREDIT +#define DEBUG_CREDIT 0 +#endif + +#if DEBUG_CREDIT +/* bit mask to enable debug certain endpoint */ +static unsigned ep_debug_mask = + (1 << ENDPOINT_0) | (1 << ENDPOINT_1) | (1 << ENDPOINT_2); +#endif + +/* HTC Control Path Credit History */ +uint32_t g_htc_credit_history_idx = 0; +HTC_CREDIT_HISTORY htc_credit_history_buffer[HTC_CREDIT_HISTORY_MAX]; + +/** + * htc_credit_record() - records tx que state & credit transactions + * @type: type of echange can be HTC_REQUEST_CREDIT + * or HTC_PROCESS_CREDIT_REPORT + * @tx_credits: current number of tx_credits + * @htc_tx_queue_depth: current hct tx queue depth + * + * This function records the credits and pending commands whenever a command is + * sent or credits are returned. Call this after the credits have been updated + * according to the transaction. Call this before dequeing commands. + * + * Consider making this function accept an HTC_ENDPOINT and find the current + * credits and queue depth itself. + * + * Consider moving the LOCK_HTC_CREDIT(target); logic into this function as well. + */ +void htc_credit_record(htc_credit_exchange_type type, uint32_t tx_credit, + uint32_t htc_tx_queue_depth) { + if (HTC_CREDIT_HISTORY_MAX <= g_htc_credit_history_idx) + g_htc_credit_history_idx = 0; + + htc_credit_history_buffer[g_htc_credit_history_idx].type = type; + htc_credit_history_buffer[g_htc_credit_history_idx].time = + qdf_get_log_timestamp(); + htc_credit_history_buffer[g_htc_credit_history_idx].tx_credit = + tx_credit; + htc_credit_history_buffer[g_htc_credit_history_idx].htc_tx_queue_depth = + htc_tx_queue_depth; + g_htc_credit_history_idx++; +} + +void htc_dump_counter_info(HTC_HANDLE HTCHandle) +{ + HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle); + + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + ("\n%s: ce_send_cnt = %d, TX_comp_cnt = %d\n", + __func__, target->ce_send_cnt, target->TX_comp_cnt)); +} + +int htc_get_tx_queue_depth(HTC_HANDLE *htc_handle, HTC_ENDPOINT_ID endpoint_id) +{ + HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(htc_handle); + HTC_ENDPOINT *endpoint = &target->endpoint[endpoint_id]; + + return HTC_PACKET_QUEUE_DEPTH(&endpoint->TxQueue); +} + +void htc_get_control_endpoint_tx_host_credits(HTC_HANDLE HTCHandle, int *credits) +{ + HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle); + HTC_ENDPOINT *pEndpoint; + int i; + + if (!credits || !target) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("%s: invalid args", __func__)); + return; + } + + *credits = 0; + LOCK_HTC_TX(target); + for (i = 0; i < ENDPOINT_MAX; i++) { + pEndpoint = &target->endpoint[i]; + if (pEndpoint->service_id == WMI_CONTROL_SVC) { + *credits = pEndpoint->TxCredits; + break; + } + } + UNLOCK_HTC_TX(target); +} + +static inline void restore_tx_packet(HTC_TARGET *target, HTC_PACKET *pPacket) +{ + if (pPacket->PktInfo.AsTx.Flags & HTC_TX_PACKET_FLAG_FIXUP_NETBUF) { + qdf_nbuf_t netbuf = GET_HTC_PACKET_NET_BUF_CONTEXT(pPacket); + qdf_nbuf_unmap(target->osdev, netbuf, QDF_DMA_TO_DEVICE); + qdf_nbuf_pull_head(netbuf, sizeof(HTC_FRAME_HDR)); + pPacket->PktInfo.AsTx.Flags &= ~HTC_TX_PACKET_FLAG_FIXUP_NETBUF; + } + +} + +static void do_send_completion(HTC_ENDPOINT *pEndpoint, + HTC_PACKET_QUEUE *pQueueToIndicate) +{ + do { + + if (HTC_QUEUE_EMPTY(pQueueToIndicate)) { + /* nothing to indicate */ + break; + } + + if (pEndpoint->EpCallBacks.EpTxCompleteMultiple != NULL) { + AR_DEBUG_PRINTF(ATH_DEBUG_SEND, + (" HTC calling ep %d, send complete multiple callback (%d pkts) \n", + pEndpoint->Id, + HTC_PACKET_QUEUE_DEPTH + (pQueueToIndicate))); + /* a multiple send complete handler is being used, pass the queue to the handler */ + pEndpoint->EpCallBacks.EpTxCompleteMultiple(pEndpoint-> + EpCallBacks. + pContext, + pQueueToIndicate); + /* all packets are now owned by the callback, reset queue to be safe */ + INIT_HTC_PACKET_QUEUE(pQueueToIndicate); + } else { + HTC_PACKET *pPacket; + /* using legacy EpTxComplete */ + do { + pPacket = htc_packet_dequeue(pQueueToIndicate); + AR_DEBUG_PRINTF(ATH_DEBUG_SEND, + (" HTC calling ep %d send complete callback on packet %p \n", + pEndpoint->Id, pPacket)); + pEndpoint->EpCallBacks.EpTxComplete(pEndpoint-> + EpCallBacks. + pContext, + pPacket); + } while (!HTC_QUEUE_EMPTY(pQueueToIndicate)); + } + + } while (false); + +} + +static void send_packet_completion(HTC_TARGET *target, HTC_PACKET *pPacket) +{ + HTC_ENDPOINT *pEndpoint = &target->endpoint[pPacket->Endpoint]; + HTC_PACKET_QUEUE container; + + restore_tx_packet(target, pPacket); + INIT_HTC_PACKET_QUEUE_AND_ADD(&container, pPacket); + + /* do completion */ + do_send_completion(pEndpoint, &container); +} + +void htc_send_complete_check_cleanup(void *context) +{ + HTC_ENDPOINT *pEndpoint = (HTC_ENDPOINT *) context; + htc_send_complete_check(pEndpoint, 1); +} + +HTC_PACKET *allocate_htc_bundle_packet(HTC_TARGET *target) +{ + HTC_PACKET *pPacket; + HTC_PACKET_QUEUE *pQueueSave; + qdf_nbuf_t netbuf; + LOCK_HTC_TX(target); + if (NULL == target->pBundleFreeList) { + UNLOCK_HTC_TX(target); + netbuf = qdf_nbuf_alloc(NULL, + target->MaxMsgsPerHTCBundle * + target->TargetCreditSize, 0, 4, false); + AR_DEBUG_ASSERT(netbuf); + if (!netbuf) { + return NULL; + } + pPacket = qdf_mem_malloc(sizeof(HTC_PACKET)); + AR_DEBUG_ASSERT(pPacket); + if (!pPacket) { + qdf_nbuf_free(netbuf); + return NULL; + } + pQueueSave = qdf_mem_malloc(sizeof(HTC_PACKET_QUEUE)); + AR_DEBUG_ASSERT(pQueueSave); + if (!pQueueSave) { + qdf_nbuf_free(netbuf); + qdf_mem_free(pPacket); + return NULL; + } + INIT_HTC_PACKET_QUEUE(pQueueSave); + pPacket->pContext = pQueueSave; + SET_HTC_PACKET_NET_BUF_CONTEXT(pPacket, netbuf); + pPacket->pBuffer = qdf_nbuf_data(netbuf); + pPacket->BufferLength = qdf_nbuf_len(netbuf); + + /* store the original head room so that we can restore this when we "free" the packet */ + /* free packet puts the packet back on the free list */ + pPacket->netbufOrigHeadRoom = qdf_nbuf_headroom(netbuf); + return pPacket; + } + /* already done malloc - restore from free list */ + pPacket = target->pBundleFreeList; + AR_DEBUG_ASSERT(pPacket); + if (!pPacket) { + UNLOCK_HTC_TX(target); + return NULL; + } + target->pBundleFreeList = (HTC_PACKET *) pPacket->ListLink.pNext; + UNLOCK_HTC_TX(target); + pPacket->ListLink.pNext = NULL; + + return pPacket; +} + +void free_htc_bundle_packet(HTC_TARGET *target, HTC_PACKET *pPacket) +{ + uint32_t curentHeadRoom; + qdf_nbuf_t netbuf; + HTC_PACKET_QUEUE *pQueueSave; + + netbuf = GET_HTC_PACKET_NET_BUF_CONTEXT(pPacket); + AR_DEBUG_ASSERT(netbuf); + if (!netbuf) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("\n%s: Invalid netbuf in HTC " + "Packet\n", __func__)); + return; + } + /* HIF adds data to the headroom section of the nbuf, restore the original */ + /* size. If this is not done, headroom keeps shrinking with every HIF send */ + /* and eventually HIF ends up doing another malloc big enough to store the */ + /* data + its header */ + + curentHeadRoom = qdf_nbuf_headroom(netbuf); + qdf_nbuf_pull_head(netbuf, + pPacket->netbufOrigHeadRoom - curentHeadRoom); + qdf_nbuf_trim_tail(netbuf, qdf_nbuf_len(netbuf)); + + /* restore the pBuffer pointer. HIF changes this */ + pPacket->pBuffer = qdf_nbuf_data(netbuf); + pPacket->BufferLength = qdf_nbuf_len(netbuf); + + /* restore queue */ + pQueueSave = (HTC_PACKET_QUEUE *) pPacket->pContext; + AR_DEBUG_ASSERT(pQueueSave); + + INIT_HTC_PACKET_QUEUE(pQueueSave); + + LOCK_HTC_TX(target); + if (target->pBundleFreeList == NULL) { + target->pBundleFreeList = pPacket; + pPacket->ListLink.pNext = NULL; + } else { + pPacket->ListLink.pNext = (DL_LIST *) target->pBundleFreeList; + target->pBundleFreeList = pPacket; + } + UNLOCK_HTC_TX(target); +} + +#if defined(DEBUG_HL_LOGGING) && defined(CONFIG_HL_SUPPORT) + +/** + * htc_send_update_tx_bundle_stats() - update tx bundle stats depends + * on max bundle size + * @target: hif context + * @data_len: tx data len + * @TxCreditSize: endpoint tx credit size + * + * Return: None + */ +static inline void +htc_send_update_tx_bundle_stats(HTC_TARGET *target, + qdf_size_t data_len, + int TxCreditSize) +{ + if ((data_len / TxCreditSize) <= HTC_MAX_MSG_PER_BUNDLE_TX) + target->tx_bundle_stats[(data_len / TxCreditSize) - 1]++; + + return; +} + +/** + * htc_issue_tx_bundle_stats_inc() - increment in tx bundle stats + * on max bundle size + * @target: hif context + * + * Return: None + */ +static inline void +htc_issue_tx_bundle_stats_inc(HTC_TARGET *target) +{ + target->tx_bundle_stats[0]++; +} +#else + +static inline void +htc_send_update_tx_bundle_stats(HTC_TARGET *target, + qdf_size_t data_len, + int TxCreditSize) +{ + return; +} + +static inline void +htc_issue_tx_bundle_stats_inc(HTC_TARGET *target) +{ + return; +} +#endif + +#if defined(HIF_USB) || defined(HIF_SDIO) +#ifdef ENABLE_BUNDLE_TX +static A_STATUS htc_send_bundled_netbuf(HTC_TARGET *target, + HTC_ENDPOINT *pEndpoint, + unsigned char *pBundleBuffer, + HTC_PACKET *pPacketTx) +{ + qdf_size_t data_len; + A_STATUS status; + qdf_nbuf_t bundleBuf; + uint32_t data_attr = 0; + + bundleBuf = GET_HTC_PACKET_NET_BUF_CONTEXT(pPacketTx); + data_len = pBundleBuffer - qdf_nbuf_data(bundleBuf); + qdf_nbuf_put_tail(bundleBuf, data_len); + SET_HTC_PACKET_INFO_TX(pPacketTx, + target, + pBundleBuffer, + data_len, + pEndpoint->Id, HTC_TX_PACKET_TAG_BUNDLED); + LOCK_HTC_TX(target); + HTC_PACKET_ENQUEUE(&pEndpoint->TxLookupQueue, pPacketTx); + UNLOCK_HTC_TX(target); +#if DEBUG_BUNDLE + qdf_print(" Send bundle EP%d buffer size:0x%x, total:0x%x, count:%d.\n", + pEndpoint->Id, + pEndpoint->TxCreditSize, + data_len, data_len / pEndpoint->TxCreditSize); +#endif + + htc_send_update_tx_bundle_stats(target, data_len, + pEndpoint->TxCreditSize); + + status = hif_send_head(target->hif_dev, + pEndpoint->UL_PipeID, + pEndpoint->Id, data_len, + bundleBuf, data_attr); + if (status != A_OK) { + qdf_print("%s:hif_send_head failed(len=%zu).\n", __func__, + data_len); + } + return status; +} + +/** + * htc_issue_packets_bundle() - HTC function to send bundle packets from a queue + * @target: HTC target on which packets need to be sent + * @pEndpoint: logical endpoint on which packets needs to be sent + * @pPktQueue: HTC packet queue containing the list of packets to be sent + * + * Return: void + */ +static void htc_issue_packets_bundle(HTC_TARGET *target, + HTC_ENDPOINT *pEndpoint, + HTC_PACKET_QUEUE *pPktQueue) +{ + int i, frag_count, nbytes; + qdf_nbuf_t netbuf, bundleBuf; + unsigned char *pBundleBuffer = NULL; + HTC_PACKET *pPacket = NULL, *pPacketTx = NULL; + HTC_FRAME_HDR *pHtcHdr; + int last_credit_pad = 0; + int creditPad, creditRemainder, transferLength, bundlesSpaceRemaining = + 0; + HTC_PACKET_QUEUE *pQueueSave = NULL; + + bundlesSpaceRemaining = + target->MaxMsgsPerHTCBundle * pEndpoint->TxCreditSize; + pPacketTx = allocate_htc_bundle_packet(target); + if (!pPacketTx) { + /* good time to panic */ + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + ("allocate_htc_bundle_packet failed \n")); + AR_DEBUG_ASSERT(false); + return; + } + bundleBuf = GET_HTC_PACKET_NET_BUF_CONTEXT(pPacketTx); + pBundleBuffer = qdf_nbuf_data(bundleBuf); + pQueueSave = (HTC_PACKET_QUEUE *) pPacketTx->pContext; + while (1) { + pPacket = htc_packet_dequeue(pPktQueue); + if (pPacket == NULL) { + break; + } + creditPad = 0; + transferLength = pPacket->ActualLength + HTC_HDR_LENGTH; + creditRemainder = transferLength % pEndpoint->TxCreditSize; + if (creditRemainder != 0) { + if (transferLength < pEndpoint->TxCreditSize) { + creditPad = + pEndpoint->TxCreditSize - transferLength; + } else { + creditPad = creditRemainder; + } + transferLength += creditPad; + } + + if (bundlesSpaceRemaining < transferLength) { + /* send out previous buffer */ + htc_send_bundled_netbuf(target, pEndpoint, + pBundleBuffer - last_credit_pad, + pPacketTx); + if (HTC_PACKET_QUEUE_DEPTH(pPktQueue) < + HTC_MIN_MSG_PER_BUNDLE) { + return; + } + bundlesSpaceRemaining = + target->MaxMsgsPerHTCBundle * + pEndpoint->TxCreditSize; + pPacketTx = allocate_htc_bundle_packet(target); + if (!pPacketTx) { + /* good time to panic */ + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + ("allocate_htc_bundle_packet failed \n")); + AR_DEBUG_ASSERT(false); + return; + } + bundleBuf = GET_HTC_PACKET_NET_BUF_CONTEXT(pPacketTx); + pBundleBuffer = qdf_nbuf_data(bundleBuf); + pQueueSave = (HTC_PACKET_QUEUE *) pPacketTx->pContext; + } + + bundlesSpaceRemaining -= transferLength; + netbuf = GET_HTC_PACKET_NET_BUF_CONTEXT(pPacket); + + if (hif_get_bus_type(target->hif_dev) != QDF_BUS_TYPE_USB) { + pHtcHdr = + (HTC_FRAME_HDR *) + qdf_nbuf_get_frag_vaddr(netbuf, 0); + HTC_WRITE32(pHtcHdr, + SM(pPacket->ActualLength, + HTC_FRAME_HDR_PAYLOADLEN) | + SM(pPacket->PktInfo.AsTx.SendFlags | + HTC_FLAGS_SEND_BUNDLE, + HTC_FRAME_HDR_FLAGS) | + SM(pPacket->Endpoint, + HTC_FRAME_HDR_ENDPOINTID)); + HTC_WRITE32((uint32_t *) pHtcHdr + 1, + SM(pPacket->PktInfo.AsTx.SeqNo, + HTC_FRAME_HDR_CONTROLBYTES1) | SM(creditPad, + HTC_FRAME_HDR_RESERVED)); + pHtcHdr->reserved = creditPad; + } + frag_count = qdf_nbuf_get_num_frags(netbuf); + nbytes = pPacket->ActualLength + HTC_HDR_LENGTH; + for (i = 0; i < frag_count && nbytes > 0; i++) { + int frag_len = qdf_nbuf_get_frag_len(netbuf, i); + unsigned char *frag_addr = + qdf_nbuf_get_frag_vaddr(netbuf, i); + if (frag_len > nbytes) { + frag_len = nbytes; + } + qdf_mem_copy(pBundleBuffer, frag_addr, frag_len); + nbytes -= frag_len; + pBundleBuffer += frag_len; + } + HTC_PACKET_ENQUEUE(pQueueSave, pPacket); + pBundleBuffer += creditPad; + + if (hif_get_bus_type(target->hif_dev) == QDF_BUS_TYPE_USB) { + /* last one can't be packed. */ + last_credit_pad = creditPad; + } + + } + if (pBundleBuffer != qdf_nbuf_data(bundleBuf)) { + /* send out remaining buffer */ + htc_send_bundled_netbuf(target, pEndpoint, + pBundleBuffer - last_credit_pad, + pPacketTx); + } else { + free_htc_bundle_packet(target, pPacketTx); + } +} +#endif /* ENABLE_BUNDLE_TX */ +#else +static void htc_issue_packets_bundle(HTC_TARGET *target, + HTC_ENDPOINT *pEndpoint, + HTC_PACKET_QUEUE *pPktQueue) +{ +} +#endif + +/** + * htc_issue_packets() - HTC function to send packets from a queue + * @target: HTC target on which packets need to be sent + * @pEndpoint: logical endpoint on which packets needs to be sent + * @pPktQueue: HTC packet queue containing the list of packets to be sent + * + * Return: QDF_STATUS_SUCCESS on success and error QDF status on failure + */ +static A_STATUS htc_issue_packets(HTC_TARGET *target, + HTC_ENDPOINT *pEndpoint, + HTC_PACKET_QUEUE *pPktQueue) +{ + A_STATUS status = A_OK; + qdf_nbuf_t netbuf; + HTC_PACKET *pPacket = NULL; + uint16_t payloadLen; + HTC_FRAME_HDR *pHtcHdr; + uint32_t data_attr = 0; + enum qdf_bus_type bus_type; + QDF_STATUS ret; + + bus_type = hif_get_bus_type(target->hif_dev); + + AR_DEBUG_PRINTF(ATH_DEBUG_SEND, + ("+htc_issue_packets: Queue: %p, Pkts %d \n", pPktQueue, + HTC_PACKET_QUEUE_DEPTH(pPktQueue))); + while (true) { + if (HTC_TX_BUNDLE_ENABLED(target) && + HTC_PACKET_QUEUE_DEPTH(pPktQueue) >= + HTC_MIN_MSG_PER_BUNDLE) { + switch (bus_type) { + case QDF_BUS_TYPE_SDIO: + if (!IS_TX_CREDIT_FLOW_ENABLED(pEndpoint)) + break; + case QDF_BUS_TYPE_USB: + htc_issue_packets_bundle(target, + pEndpoint, + pPktQueue); + break; + default: + break; + } + } + /* if not bundling or there was a packet that could not be placed in a bundle, + * and send it by normal way + */ + pPacket = htc_packet_dequeue(pPktQueue); + if (NULL == pPacket) { + /* local queue is fully drained */ + break; + } + + netbuf = GET_HTC_PACKET_NET_BUF_CONTEXT(pPacket); + AR_DEBUG_ASSERT(netbuf); + /* Non-credit enabled endpoints have been mapped and setup by now, + * so no need to revisit the HTC headers + */ + if (IS_TX_CREDIT_FLOW_ENABLED(pEndpoint)) { + + payloadLen = pPacket->ActualLength; + /* setup HTC frame header */ + + pHtcHdr = (HTC_FRAME_HDR *) + qdf_nbuf_get_frag_vaddr(netbuf, 0); + AR_DEBUG_ASSERT(pHtcHdr); + + HTC_WRITE32(pHtcHdr, + SM(payloadLen, + HTC_FRAME_HDR_PAYLOADLEN) | SM(pPacket-> + PktInfo. + AsTx. + SendFlags, + HTC_FRAME_HDR_FLAGS) + | SM(pPacket->Endpoint, + HTC_FRAME_HDR_ENDPOINTID)); + HTC_WRITE32(((uint32_t *) pHtcHdr) + 1, + SM(pPacket->PktInfo.AsTx.SeqNo, + HTC_FRAME_HDR_CONTROLBYTES1)); + + /* + * Now that the HTC frame header has been added, the netbuf can be + * mapped. This only applies to non-data frames, since data frames + * were already mapped as they entered into the driver. + * Check the "FIXUP_NETBUF" flag to see whether this is a data netbuf + * that is already mapped, or a non-data netbuf that needs to be + * mapped. + */ + if (pPacket->PktInfo.AsTx. + Flags & HTC_TX_PACKET_FLAG_FIXUP_NETBUF) { + ret = qdf_nbuf_map(target->osdev, + GET_HTC_PACKET_NET_BUF_CONTEXT + (pPacket), QDF_DMA_TO_DEVICE); + if (ret != QDF_STATUS_SUCCESS) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + ("%s: nbuf map failed, endpoint %p\n", + __func__, pEndpoint)); + status = A_ERROR; + break; + } + } + } + LOCK_HTC_TX(target); + /* store in look up queue to match completions */ + HTC_PACKET_ENQUEUE(&pEndpoint->TxLookupQueue, pPacket); + INC_HTC_EP_STAT(pEndpoint, TxIssued, 1); + pEndpoint->ul_outstanding_cnt++; + UNLOCK_HTC_TX(target); + + hif_send_complete_check(target->hif_dev, pEndpoint->UL_PipeID, false); + htc_packet_set_magic_cookie(pPacket, HTC_PACKET_MAGIC_COOKIE); + status = hif_send_head(target->hif_dev, + pEndpoint->UL_PipeID, pEndpoint->Id, + HTC_HDR_LENGTH + pPacket->ActualLength, + netbuf, data_attr); + +#if DEBUG_BUNDLE + qdf_print(" Send single EP%d buffer size:0x%x, total:0x%x.\n", + pEndpoint->Id, + pEndpoint->TxCreditSize, + HTC_HDR_LENGTH + pPacket->ActualLength); +#endif + htc_issue_tx_bundle_stats_inc(target); + + target->ce_send_cnt++; + + if (qdf_unlikely(A_FAILED(status))) { + if (status != A_NO_RESOURCE) { + /* TODO : if more than 1 endpoint maps to the same PipeID it is possible + * to run out of resources in the HIF layer. Don't emit the error */ + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + ("hif_send Failed status:%d \n", + status)); + } + LOCK_HTC_TX(target); + target->ce_send_cnt--; + pEndpoint->ul_outstanding_cnt--; + HTC_PACKET_REMOVE(&pEndpoint->TxLookupQueue, pPacket); + /* reclaim credits */ + pEndpoint->TxCredits += + pPacket->PktInfo.AsTx.CreditsUsed; + htc_packet_set_magic_cookie(pPacket, 0); + /* put it back into the callers queue */ + HTC_PACKET_ENQUEUE_TO_HEAD(pPktQueue, pPacket); + UNLOCK_HTC_TX(target); + break; + } + + /* + * For HTT messages without a response from fw, + * do the runtime put here. + * otherwise runtime put will be done when the fw response comes + */ + if (pPacket->PktInfo.AsTx.Tag == HTC_TX_PACKET_TAG_RUNTIME_PUT) + hif_pm_runtime_put(target->hif_dev); + } + if (qdf_unlikely(A_FAILED(status))) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + ("htc_issue_packets, failed pkt:0x%p status:%d", + pPacket, status)); + } + + AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("-htc_issue_packets \n")); + + return status; +} + +#ifdef FEATURE_RUNTIME_PM +/** + * extract_htc_pm_packtes(): move pm packets from endpoint into queue + * @endpoint: which enpoint to extract packets from + * @queue: a queue to store extracted packets in. + * + * remove pm packets from the endpoint's tx queue. + * queue them into a queue + */ +static void extract_htc_pm_packets(HTC_ENDPOINT *endpoint, + HTC_PACKET_QUEUE *queue) +{ + HTC_PACKET *packet; + + /* only WMI endpoint has power management packets */ + if (endpoint->service_id != WMI_CONTROL_SVC) + return; + + ITERATE_OVER_LIST_ALLOW_REMOVE(&endpoint->TxQueue.QueueHead, packet, + HTC_PACKET, ListLink) { + if (packet->PktInfo.AsTx.Tag == HTC_TX_PACKET_TAG_AUTO_PM) { + HTC_PACKET_REMOVE(&endpoint->TxQueue, packet); + HTC_PACKET_ENQUEUE(queue, packet); + } + } ITERATE_END +} + +/** + * queue_htc_pm_packets(): queue pm packets with priority + * @endpoint: enpoint to queue packets to + * @queue: queue of pm packets to enque + * + * suspend resume packets get special treatment & priority. + * need to queue them at the front of the queue. + */ +static void queue_htc_pm_packets(HTC_ENDPOINT *endpoint, + HTC_PACKET_QUEUE *queue) +{ + if (endpoint->service_id != WMI_CONTROL_SVC) + return; + + HTC_PACKET_QUEUE_TRANSFER_TO_HEAD(&endpoint->TxQueue, queue); +} +#else +static void extract_htc_pm_packets(HTC_ENDPOINT *endpoint, + HTC_PACKET_QUEUE *queue) +{} + +static void queue_htc_pm_packets(HTC_ENDPOINT *endpoint, + HTC_PACKET_QUEUE *queue) +{} +#endif + +/** + * get_htc_send_packets_credit_based() - get packets based on available credits + * @target: HTC target on which packets need to be sent + * @pEndpoint: logical endpoint on which packets needs to be sent + * @pQueue: HTC packet queue containing the list of packets to be sent + * + * Get HTC send packets from TX queue on an endpoint based on available credits. + * The function moves the packets from TX queue of the endpoint to pQueue. + * + * Return: None + */ +static void get_htc_send_packets_credit_based(HTC_TARGET *target, + HTC_ENDPOINT *pEndpoint, + HTC_PACKET_QUEUE *pQueue) +{ + int creditsRequired; + int remainder; + uint8_t sendFlags; + HTC_PACKET *pPacket; + unsigned int transferLength; + HTC_PACKET_QUEUE *tx_queue; + HTC_PACKET_QUEUE pm_queue; + bool do_pm_get = false; + + /****** NOTE : the TX lock is held when this function is called *****************/ + AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("+get_htc_send_packets_credit_based\n")); + + INIT_HTC_PACKET_QUEUE(&pm_queue); + extract_htc_pm_packets(pEndpoint, &pm_queue); + if (HTC_QUEUE_EMPTY(&pm_queue)) { + tx_queue = &pEndpoint->TxQueue; + do_pm_get = true; + } else { + tx_queue = &pm_queue; + } + + /* loop until we can grab as many packets out of the queue as we can */ + while (true) { + if (do_pm_get && hif_pm_runtime_get(target->hif_dev)) { + /* bus suspended, runtime resume issued */ + QDF_ASSERT(HTC_PACKET_QUEUE_DEPTH(pQueue) == 0); + break; + } + + sendFlags = 0; + /* get packet at head, but don't remove it */ + pPacket = htc_get_pkt_at_head(tx_queue); + if (pPacket == NULL) { + if (do_pm_get) + hif_pm_runtime_put(target->hif_dev); + break; + } + + AR_DEBUG_PRINTF(ATH_DEBUG_SEND, + (" Got head packet:%p , Queue Depth: %d\n", + pPacket, + HTC_PACKET_QUEUE_DEPTH(tx_queue))); + + transferLength = pPacket->ActualLength + HTC_HDR_LENGTH; + + if (transferLength <= pEndpoint->TxCreditSize) { + creditsRequired = 1; + } else { + /* figure out how many credits this message requires */ + creditsRequired = + transferLength / pEndpoint->TxCreditSize; + remainder = transferLength % pEndpoint->TxCreditSize; + + if (remainder) { + creditsRequired++; + } + } + + AR_DEBUG_PRINTF(ATH_DEBUG_SEND, + (" Credits Required:%d Got:%d\n", + creditsRequired, pEndpoint->TxCredits)); + + if (pEndpoint->Id == ENDPOINT_0) { + /* + * endpoint 0 is special, it always has a credit and + * does not require credit based flow control + */ + creditsRequired = 0; + } else { + + if (pEndpoint->TxCredits < creditsRequired) { +#if DEBUG_CREDIT + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + (" EP%d, No Credit now. %d < %d\n", + pEndpoint->Id, + pEndpoint->TxCredits, + creditsRequired)); +#endif + if (do_pm_get) + hif_pm_runtime_put(target->hif_dev); + break; + } + + pEndpoint->TxCredits -= creditsRequired; + INC_HTC_EP_STAT(pEndpoint, TxCreditsConsummed, + creditsRequired); + + /* check if we need credits back from the target */ + if (pEndpoint->TxCredits <= + pEndpoint->TxCreditsPerMaxMsg) { + /* tell the target we need credits ASAP! */ + sendFlags |= HTC_FLAGS_NEED_CREDIT_UPDATE; + + if (pEndpoint->service_id == WMI_CONTROL_SVC) { + LOCK_HTC_CREDIT(target); + htc_credit_record(HTC_REQUEST_CREDIT, + pEndpoint->TxCredits, + HTC_PACKET_QUEUE_DEPTH + (tx_queue)); + UNLOCK_HTC_CREDIT(target); + } + + INC_HTC_EP_STAT(pEndpoint, + TxCreditLowIndications, 1); +#if DEBUG_CREDIT + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + (" EP%d Needs Credits\n", + pEndpoint->Id)); +#endif + } + } + + /* now we can fully dequeue */ + pPacket = htc_packet_dequeue(tx_queue); + if (pPacket) { + /* save the number of credits this packet consumed */ + pPacket->PktInfo.AsTx.CreditsUsed = creditsRequired; + /* save send flags */ + pPacket->PktInfo.AsTx.SendFlags = sendFlags; + + /* queue this packet into the caller's queue */ + HTC_PACKET_ENQUEUE(pQueue, pPacket); + } + } + + if (!HTC_QUEUE_EMPTY(&pm_queue)) + queue_htc_pm_packets(pEndpoint, &pm_queue); + + AR_DEBUG_PRINTF(ATH_DEBUG_SEND, + ("-get_htc_send_packets_credit_based\n")); + +} + +static void get_htc_send_packets(HTC_TARGET *target, + HTC_ENDPOINT *pEndpoint, + HTC_PACKET_QUEUE *pQueue, int Resources) +{ + + HTC_PACKET *pPacket; + HTC_PACKET_QUEUE *tx_queue; + HTC_PACKET_QUEUE pm_queue; + bool do_pm_get; + + /****** NOTE : the TX lock is held when this function is called *****************/ + AR_DEBUG_PRINTF(ATH_DEBUG_SEND, + ("+get_htc_send_packets %d resources\n", Resources)); + + INIT_HTC_PACKET_QUEUE(&pm_queue); + extract_htc_pm_packets(pEndpoint, &pm_queue); + if (HTC_QUEUE_EMPTY(&pm_queue)) { + tx_queue = &pEndpoint->TxQueue; + do_pm_get = true; + } else { + tx_queue = &pm_queue; + } + + /* loop until we can grab as many packets out of the queue as we can */ + while (Resources > 0) { + int num_frags; + + if (do_pm_get && hif_pm_runtime_get(target->hif_dev)) { + /* bus suspended, runtime resume issued */ + QDF_ASSERT(HTC_PACKET_QUEUE_DEPTH(pQueue) == 0); + break; + } + + pPacket = htc_packet_dequeue(tx_queue); + if (pPacket == NULL) { + if (do_pm_get) + hif_pm_runtime_put(target->hif_dev); + break; + } + AR_DEBUG_PRINTF(ATH_DEBUG_SEND, + (" Got packet:%p , New Queue Depth: %d\n", + pPacket, + HTC_PACKET_QUEUE_DEPTH(tx_queue))); + /* For non-credit path the sequence number is already embedded + * in the constructed HTC header + */ +#if 0 + pPacket->PktInfo.AsTx.SeqNo = pEndpoint->SeqNo; + pEndpoint->SeqNo++; +#endif + pPacket->PktInfo.AsTx.SendFlags = 0; + pPacket->PktInfo.AsTx.CreditsUsed = 0; + /* queue this packet into the caller's queue */ + HTC_PACKET_ENQUEUE(pQueue, pPacket); + + /* + * FIX THIS: + * For now, avoid calling qdf_nbuf_get_num_frags before calling + * qdf_nbuf_map, because the MacOS version of qdf_nbuf_t doesn't + * support qdf_nbuf_get_num_frags until after qdf_nbuf_map has + * been done. + * Assume that the non-data netbufs, i.e. the WMI message netbufs, + * consist of a single fragment. + */ + num_frags = + (pPacket->PktInfo.AsTx. + Flags & HTC_TX_PACKET_FLAG_FIXUP_NETBUF) ? 1 + /* WMI messages are in a single-fragment network buffer */ : + qdf_nbuf_get_num_frags(GET_HTC_PACKET_NET_BUF_CONTEXT + (pPacket)); + Resources -= num_frags; + } + + if (!HTC_QUEUE_EMPTY(&pm_queue)) + queue_htc_pm_packets(pEndpoint, &pm_queue); + + AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("-get_htc_send_packets\n")); + +} + +/** + * htc_try_send() - Send packets in a queue on an endpoint + * @target: HTC target on which packets need to be sent + * @pEndpoint: logical endpoint on which packets needs to be sent + * @pCallersSendQueue: packet queue containing the list of packets to be sent + * + * Return: HTC_SEND_QUEUE_RESULT indicates whether the packet was queued to be + * sent or the packet should be dropped by the upper layer + */ +static HTC_SEND_QUEUE_RESULT htc_try_send(HTC_TARGET *target, + HTC_ENDPOINT *pEndpoint, + HTC_PACKET_QUEUE *pCallersSendQueue) +{ + HTC_PACKET_QUEUE sendQueue; /* temp queue to hold packets at various stages */ + HTC_PACKET *pPacket; + int tx_resources; + int overflow; + HTC_SEND_QUEUE_RESULT result = HTC_SEND_QUEUE_OK; + + AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("+htc_try_send (Queue:%p Depth:%d)\n", + pCallersSendQueue, + (pCallersSendQueue == + NULL) ? 0 : + HTC_PACKET_QUEUE_DEPTH + (pCallersSendQueue))); + + /* init the local send queue */ + INIT_HTC_PACKET_QUEUE(&sendQueue); + + do { + + if (NULL == pCallersSendQueue) { + /* caller didn't provide a queue, just wants us to check queues and send */ + break; + } + + if (HTC_QUEUE_EMPTY(pCallersSendQueue)) { + /* empty queue */ + OL_ATH_HTC_PKT_ERROR_COUNT_INCR(target, + HTC_PKT_Q_EMPTY); + result = HTC_SEND_QUEUE_DROP; + break; + } + + if (HTC_PACKET_QUEUE_DEPTH(&pEndpoint->TxQueue) >= + pEndpoint->MaxTxQueueDepth) { + /* we've already overflowed */ + overflow = HTC_PACKET_QUEUE_DEPTH(pCallersSendQueue); + } else { + /* figure out how much we will overflow by */ + overflow = HTC_PACKET_QUEUE_DEPTH(&pEndpoint->TxQueue); + overflow += HTC_PACKET_QUEUE_DEPTH(pCallersSendQueue); + /* figure out how much we will overflow the TX queue by */ + overflow -= pEndpoint->MaxTxQueueDepth; + } + + /* if overflow is negative or zero, we are okay */ + if (overflow > 0) { + AR_DEBUG_PRINTF(ATH_DEBUG_SEND, + (" Endpoint %d, TX queue will overflow :%d , Tx Depth:%d, Max:%d \n", + pEndpoint->Id, overflow, + HTC_PACKET_QUEUE_DEPTH(&pEndpoint-> + TxQueue), + pEndpoint->MaxTxQueueDepth)); + } + if ((overflow <= 0) + || (pEndpoint->EpCallBacks.EpSendFull == NULL)) { + /* all packets will fit or caller did not provide send full indication handler + * -- just move all of them to the local sendQueue object */ + HTC_PACKET_QUEUE_TRANSFER_TO_TAIL(&sendQueue, + pCallersSendQueue); + } else { + int i; + int goodPkts = + HTC_PACKET_QUEUE_DEPTH(pCallersSendQueue) - + overflow; + + A_ASSERT(goodPkts >= 0); + /* we have overflowed, and a callback is provided */ + /* dequeue all non-overflow packets into the sendqueue */ + for (i = 0; i < goodPkts; i++) { + /* pop off caller's queue */ + pPacket = htc_packet_dequeue(pCallersSendQueue); + A_ASSERT(pPacket != NULL); + /* insert into local queue */ + HTC_PACKET_ENQUEUE(&sendQueue, pPacket); + } + + /* the caller's queue has all the packets that won't fit */ + /* walk through the caller's queue and indicate each one to the send full handler */ + ITERATE_OVER_LIST_ALLOW_REMOVE(&pCallersSendQueue-> + QueueHead, pPacket, + HTC_PACKET, ListLink) { + + AR_DEBUG_PRINTF(ATH_DEBUG_SEND, + (" Indicating overflowed TX packet: %p \n", + pPacket)); + /* + * Remove headroom reserved for HTC_FRAME_HDR before giving + * the packet back to the user via the EpSendFull callback. + */ + restore_tx_packet(target, pPacket); + + if (pEndpoint->EpCallBacks. + EpSendFull(pEndpoint->EpCallBacks.pContext, + pPacket) == HTC_SEND_FULL_DROP) { + /* callback wants the packet dropped */ + INC_HTC_EP_STAT(pEndpoint, TxDropped, + 1); + /* leave this one in the caller's queue for cleanup */ + } else { + /* callback wants to keep this packet, remove from caller's queue */ + HTC_PACKET_REMOVE(pCallersSendQueue, + pPacket); + /* put it in the send queue */ + /* add HTC_FRAME_HDR space reservation again */ + qdf_nbuf_push_head + (GET_HTC_PACKET_NET_BUF_CONTEXT + (pPacket), sizeof(HTC_FRAME_HDR)); + + HTC_PACKET_ENQUEUE(&sendQueue, pPacket); + } + + } + ITERATE_END; + + if (HTC_QUEUE_EMPTY(&sendQueue)) { + /* no packets made it in, caller will cleanup */ + OL_ATH_HTC_PKT_ERROR_COUNT_INCR(target, + HTC_SEND_Q_EMPTY); + result = HTC_SEND_QUEUE_DROP; + break; + } + } + + } while (false); + + if (result != HTC_SEND_QUEUE_OK) { + AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("-htc_try_send: %d\n", + result)); + return result; + } + + if (!IS_TX_CREDIT_FLOW_ENABLED(pEndpoint)) { + tx_resources = + hif_get_free_queue_number(target->hif_dev, + pEndpoint->UL_PipeID); + } else { + tx_resources = 0; + } + + LOCK_HTC_TX(target); + + if (!HTC_QUEUE_EMPTY(&sendQueue)) { + if (target->is_nodrop_pkt) { + /* + * nodrop pkts have higher priority than normal pkts, + * insert nodrop pkt to head for proper + * start/termination of test. + */ + HTC_PACKET_QUEUE_TRANSFER_TO_HEAD(&pEndpoint->TxQueue, + &sendQueue); + target->is_nodrop_pkt = false; + } else { + /* transfer packets to tail */ + HTC_PACKET_QUEUE_TRANSFER_TO_TAIL(&pEndpoint->TxQueue, + &sendQueue); + A_ASSERT(HTC_QUEUE_EMPTY(&sendQueue)); + INIT_HTC_PACKET_QUEUE(&sendQueue); + } + } + + /* increment tx processing count on entry */ + if (qdf_atomic_inc_return(&pEndpoint->TxProcessCount) > 1) { + /* another thread or task is draining the TX queues on this endpoint + * that thread will reset the tx processing count when the queue is drained */ + qdf_atomic_dec(&pEndpoint->TxProcessCount); + UNLOCK_HTC_TX(target); + AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("-htc_try_send (busy) \n")); + return HTC_SEND_QUEUE_OK; + } + + /***** beyond this point only 1 thread may enter ******/ + + /* now drain the endpoint TX queue for transmission as long as we have enough + * transmit resources */ + while (true) { + + if (HTC_PACKET_QUEUE_DEPTH(&pEndpoint->TxQueue) == 0) { + break; + } + + if (IS_TX_CREDIT_FLOW_ENABLED(pEndpoint)) { +#if DEBUG_CREDIT + int cred = pEndpoint->TxCredits; +#endif + /* credit based mechanism provides flow control based on target transmit resource availability, we + * assume that the HIF layer will always have bus resources greater than target transmit resources */ + get_htc_send_packets_credit_based(target, pEndpoint, + &sendQueue); +#if DEBUG_CREDIT + if (ep_debug_mask & (1 << pEndpoint->Id)) { + if (cred - pEndpoint->TxCredits > 0) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + (" Decrease EP%d %d - %d = %d credits.\n", + pEndpoint->Id, cred, + cred - + pEndpoint->TxCredits, + pEndpoint->TxCredits)); + } + } +#endif + } else { + /* + * Header and payload belongs to the different + * fragments and consume 2 resource for one HTC + * package but USB combine into one transfer.And + * one WMI message only consumes one single resource. + */ + if (hif_get_bus_type(target->hif_dev) == + QDF_BUS_TYPE_USB && + HTC_TX_BUNDLE_ENABLED(target) && tx_resources) { + if (pEndpoint->service_id == + WMI_CONTROL_SVC) + tx_resources = + HTC_MAX_MSG_PER_BUNDLE_TX; + else + tx_resources = + (HTC_MAX_MSG_PER_BUNDLE_TX * 2); + } + /* get all the packets for this endpoint that we can for this pass */ + get_htc_send_packets(target, pEndpoint, &sendQueue, + tx_resources); + } + + if (HTC_PACKET_QUEUE_DEPTH(&sendQueue) == 0) { + /* didn't get any packets due to a lack of resources or TX queue was drained */ + break; + } + + UNLOCK_HTC_TX(target); + + /* send what we can */ + result = htc_issue_packets(target, pEndpoint, &sendQueue); + if (result) { + int i; + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + ("htc_issue_packets, failed status:%d put it back to head of callersSendQueue", + result)); + + for (i = HTC_PACKET_QUEUE_DEPTH(&sendQueue); i > 0; i--) + hif_pm_runtime_put(target->hif_dev); + LOCK_HTC_TX(target); + HTC_PACKET_QUEUE_TRANSFER_TO_HEAD(&pEndpoint->TxQueue, + &sendQueue); + break; + } + + if (!IS_TX_CREDIT_FLOW_ENABLED(pEndpoint)) { + tx_resources = + hif_get_free_queue_number(target->hif_dev, + pEndpoint->UL_PipeID); + } + + LOCK_HTC_TX(target); + + } + + /* done with this endpoint, we can clear the count */ + qdf_atomic_init(&pEndpoint->TxProcessCount); + + UNLOCK_HTC_TX(target); + + AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("-htc_try_send: \n")); + + return HTC_SEND_QUEUE_OK; +} + +#ifdef USB_HIF_SINGLE_PIPE_DATA_SCHED +static uint16_t htc_send_pkts_sched_check(HTC_HANDLE HTCHandle, HTC_ENDPOINT_ID id) +{ + HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle); + HTC_ENDPOINT *pEndpoint; + HTC_ENDPOINT_ID eid; + HTC_PACKET_QUEUE *pTxQueue; + uint16_t resources; + uint16_t acQueueStatus[DATA_EP_SIZE] = { 0, 0, 0, 0 }; + + if (id < ENDPOINT_2 || id > ENDPOINT_5) { + return 1; + } + + for (eid = ENDPOINT_2; eid <= ENDPOINT_5; eid++) { + pEndpoint = &target->endpoint[eid]; + pTxQueue = &pEndpoint->TxQueue; + + if (HTC_QUEUE_EMPTY(pTxQueue)) { + acQueueStatus[eid - 2] = 1; + } + } + + switch (id) { + case ENDPOINT_2: /* BE */ + return acQueueStatus[0] && acQueueStatus[2] + && acQueueStatus[3]; + case ENDPOINT_3: /* BK */ + return acQueueStatus[0] && acQueueStatus[1] && acQueueStatus[2] + && acQueueStatus[3]; + case ENDPOINT_4: /* VI */ + return acQueueStatus[2] && acQueueStatus[3]; + case ENDPOINT_5: /* VO */ + return acQueueStatus[3]; + default: + return 0; + } + +} + +static A_STATUS htc_send_pkts_sched_queue(HTC_TARGET *target, + HTC_PACKET_QUEUE *pPktQueue, + HTC_ENDPOINT_ID eid) +{ + HTC_ENDPOINT *pEndpoint; + HTC_PACKET_QUEUE *pTxQueue; + HTC_PACKET *pPacket; + int goodPkts; + + pEndpoint = &target->endpoint[eid]; + pTxQueue = &pEndpoint->TxQueue; + + LOCK_HTC_TX(target); + + goodPkts = + pEndpoint->MaxTxQueueDepth - + HTC_PACKET_QUEUE_DEPTH(&pEndpoint->TxQueue); + + if (goodPkts > 0) { + while (!HTC_QUEUE_EMPTY(pPktQueue)) { + pPacket = htc_packet_dequeue(pPktQueue); + HTC_PACKET_ENQUEUE(pTxQueue, pPacket); + goodPkts--; + + if (goodPkts <= 0) { + break; + } + } + } + + if (HTC_PACKET_QUEUE_DEPTH(pPktQueue)) { + ITERATE_OVER_LIST_ALLOW_REMOVE(&pPktQueue->QueueHead, pPacket, + HTC_PACKET, ListLink) { + + if (pEndpoint->EpCallBacks. + EpSendFull(pEndpoint->EpCallBacks.pContext, + pPacket) == HTC_SEND_FULL_DROP) { + INC_HTC_EP_STAT(pEndpoint, TxDropped, 1); + } else { + HTC_PACKET_REMOVE(pPktQueue, pPacket); + HTC_PACKET_ENQUEUE(pTxQueue, pPacket); + } + } + ITERATE_END; + } + + UNLOCK_HTC_TX(target); + + return A_OK; +} + +#endif + +A_STATUS htc_send_pkts_multiple(HTC_HANDLE HTCHandle, HTC_PACKET_QUEUE *pPktQueue) +{ + HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle); + HTC_ENDPOINT *pEndpoint; + HTC_PACKET *pPacket; + qdf_nbuf_t netbuf; + HTC_FRAME_HDR *pHtcHdr; + QDF_STATUS status; + + AR_DEBUG_PRINTF(ATH_DEBUG_SEND, + ("+htc_send_pkts_multiple: Queue: %p, Pkts %d \n", + pPktQueue, HTC_PACKET_QUEUE_DEPTH(pPktQueue))); + + /* get packet at head to figure out which endpoint these packets will go into */ + pPacket = htc_get_pkt_at_head(pPktQueue); + if (NULL == pPacket) { + OL_ATH_HTC_PKT_ERROR_COUNT_INCR(target, GET_HTC_PKT_Q_FAIL); + AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("-htc_send_pkts_multiple \n")); + return A_EINVAL; + } + + AR_DEBUG_ASSERT(pPacket->Endpoint < ENDPOINT_MAX); + pEndpoint = &target->endpoint[pPacket->Endpoint]; + + if (!pEndpoint->service_id) { + AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("%s service_id is invalid\n", + __func__)); + return A_EINVAL; + } + +#ifdef HTC_EP_STAT_PROFILING + LOCK_HTC_TX(target); + INC_HTC_EP_STAT(pEndpoint, TxPosted, HTC_PACKET_QUEUE_DEPTH(pPktQueue)); + UNLOCK_HTC_TX(target); +#endif + + /* provide room in each packet's netbuf for the HTC frame header */ + HTC_PACKET_QUEUE_ITERATE_ALLOW_REMOVE(pPktQueue, pPacket) { + netbuf = GET_HTC_PACKET_NET_BUF_CONTEXT(pPacket); + AR_DEBUG_ASSERT(netbuf); + + qdf_nbuf_push_head(netbuf, sizeof(HTC_FRAME_HDR)); + /* setup HTC frame header */ + pHtcHdr = (HTC_FRAME_HDR *) qdf_nbuf_get_frag_vaddr(netbuf, 0); + AR_DEBUG_ASSERT(pHtcHdr); + HTC_WRITE32(pHtcHdr, + SM(pPacket->ActualLength, + HTC_FRAME_HDR_PAYLOADLEN) | SM(pPacket->Endpoint, + HTC_FRAME_HDR_ENDPOINTID)); + + LOCK_HTC_TX(target); + + pPacket->PktInfo.AsTx.SeqNo = pEndpoint->SeqNo; + pEndpoint->SeqNo++; + + HTC_WRITE32(((uint32_t *) pHtcHdr) + 1, + SM(pPacket->PktInfo.AsTx.SeqNo, + HTC_FRAME_HDR_CONTROLBYTES1)); + + UNLOCK_HTC_TX(target); + /* + * Now that the HTC frame header has been added, the netbuf can be + * mapped. This only applies to non-data frames, since data frames + * were already mapped as they entered into the driver. + */ + status = qdf_nbuf_map(target->osdev, + GET_HTC_PACKET_NET_BUF_CONTEXT(pPacket), + QDF_DMA_TO_DEVICE); + if (status != QDF_STATUS_SUCCESS) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + ("%s: nbuf map failed, endpoint %p, seq_no. %d\n", + __func__, pEndpoint, pEndpoint->SeqNo)); + return A_ERROR; + } + + pPacket->PktInfo.AsTx.Flags |= HTC_TX_PACKET_FLAG_FIXUP_NETBUF; + } + HTC_PACKET_QUEUE_ITERATE_END; + +#ifdef USB_HIF_SINGLE_PIPE_DATA_SCHED + if (!htc_send_pkts_sched_check(HTCHandle, pEndpoint->Id)) { + htc_send_pkts_sched_queue(HTCHandle, pPktQueue, pEndpoint->Id); + } else { + htc_try_send(target, pEndpoint, pPktQueue); + } +#else + htc_try_send(target, pEndpoint, pPktQueue); +#endif + + /* do completion on any packets that couldn't get in */ + if (!HTC_QUEUE_EMPTY(pPktQueue)) { + + HTC_PACKET_QUEUE_ITERATE_ALLOW_REMOVE(pPktQueue, pPacket) { + /* remove the headroom reserved for HTC_FRAME_HDR */ + restore_tx_packet(target, pPacket); + + if (HTC_STOPPING(target)) { + pPacket->Status = A_ECANCELED; + } else { + pPacket->Status = A_NO_RESOURCE; + } + } + HTC_PACKET_QUEUE_ITERATE_END; + + do_send_completion(pEndpoint, pPktQueue); + } + + AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("-htc_send_pkts_multiple \n")); + + return A_OK; +} + +/* HTC API - htc_send_pkt */ +A_STATUS htc_send_pkt(HTC_HANDLE HTCHandle, HTC_PACKET *pPacket) +{ + HTC_PACKET_QUEUE queue; + + if (HTCHandle == NULL || pPacket == NULL) { + return A_ERROR; + } + + AR_DEBUG_PRINTF(ATH_DEBUG_SEND, + ("+-htc_send_pkt: Enter endPointId: %d, buffer: %p, length: %d \n", + pPacket->Endpoint, pPacket->pBuffer, + pPacket->ActualLength)); + INIT_HTC_PACKET_QUEUE_AND_ADD(&queue, pPacket); + return htc_send_pkts_multiple(HTCHandle, &queue); +} + +#ifdef ATH_11AC_TXCOMPACT +/** + * htc_send_data_pkt() - send single data packet on an endpoint + * @HTCHandle: pointer to HTC handle + * @netbuf: network buffer containing the data to be sent + * @ActualLength: length of data that needs to be transmitted + * + * Return: A_OK for success or an appropriate A_STATUS error + */ +A_STATUS htc_send_data_pkt(HTC_HANDLE HTCHandle, qdf_nbuf_t netbuf, int Epid, + int ActualLength) +{ + HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle); + HTC_ENDPOINT *pEndpoint; + HTC_FRAME_HDR *pHtcHdr; + A_STATUS status = A_OK; + int tx_resources; + uint32_t data_attr = 0; + + pEndpoint = &target->endpoint[Epid]; + + tx_resources = + hif_get_free_queue_number(target->hif_dev, pEndpoint->UL_PipeID); + + if (tx_resources < HTC_DATA_RESOURCE_THRS) { + if (pEndpoint->ul_is_polled) { + hif_send_complete_check(pEndpoint->target->hif_dev, + pEndpoint->UL_PipeID, 1); + tx_resources = + hif_get_free_queue_number(target->hif_dev, + pEndpoint->UL_PipeID); + } + if (tx_resources < HTC_DATA_MINDESC_PERPACKET) { + return A_ERROR; + } + } + + if (hif_pm_runtime_get(target->hif_dev)) + return A_ERROR; + + pHtcHdr = (HTC_FRAME_HDR *) qdf_nbuf_get_frag_vaddr(netbuf, 0); + AR_DEBUG_ASSERT(pHtcHdr); + + data_attr = qdf_nbuf_data_attr_get(netbuf); + + HTC_WRITE32(pHtcHdr, SM(ActualLength, HTC_FRAME_HDR_PAYLOADLEN) | + SM(Epid, HTC_FRAME_HDR_ENDPOINTID)); + /* + * If the HIF pipe for the data endpoint is polled rather than + * interrupt-driven, this is a good point to check whether any + * data previously sent through the HIF pipe have finished being + * sent. + * Since this may result in callbacks to htc_tx_completion_handler, + * which can take the HTC tx lock, make the hif_send_complete_check + * call before acquiring the HTC tx lock. + * Call hif_send_complete_check directly, rather than calling + * htc_send_complete_check, and call the PollTimerStart separately + * after calling hif_send_head, so the timer will be started to + * check for completion of the new outstanding download (in the + * unexpected event that other polling calls don't catch it). + */ + + LOCK_HTC_TX(target); + + HTC_WRITE32(((uint32_t *) pHtcHdr) + 1, + SM(pEndpoint->SeqNo, HTC_FRAME_HDR_CONTROLBYTES1)); + + pEndpoint->SeqNo++; + + QDF_NBUF_UPDATE_TX_PKT_COUNT(netbuf, QDF_NBUF_TX_PKT_HTC); + DPTRACE(qdf_dp_trace(netbuf, QDF_DP_TRACE_HTC_PACKET_PTR_RECORD, + qdf_nbuf_data_addr(netbuf), + sizeof(qdf_nbuf_data(netbuf)), QDF_TX)); + status = hif_send_head(target->hif_dev, + pEndpoint->UL_PipeID, + pEndpoint->Id, ActualLength, netbuf, data_attr); + + UNLOCK_HTC_TX(target); + return status; +} +#else /*ATH_11AC_TXCOMPACT */ + +/** + * htc_send_data_pkt() - htc_send_data_pkt + * @HTCHandle: pointer to HTC handle + * @pPacket: pointer to HTC_PACKET + * @more_data: indicates whether more data is to follow + * + * Return: A_OK for success or an appropriate A_STATUS error + */ +A_STATUS htc_send_data_pkt(HTC_HANDLE HTCHandle, HTC_PACKET *pPacket, + uint8_t more_data) +{ + HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle); + HTC_ENDPOINT *pEndpoint; + HTC_FRAME_HDR *pHtcHdr; + HTC_PACKET_QUEUE sendQueue; + qdf_nbuf_t netbuf = NULL; + int tx_resources; + A_STATUS status = A_OK; + uint32_t data_attr = 0; + + if (pPacket) { + AR_DEBUG_ASSERT(pPacket->Endpoint < ENDPOINT_MAX); + pEndpoint = &target->endpoint[pPacket->Endpoint]; + + /* add HTC_FRAME_HDR in the initial fragment */ + netbuf = GET_HTC_PACKET_NET_BUF_CONTEXT(pPacket); + pHtcHdr = (HTC_FRAME_HDR *) qdf_nbuf_get_frag_vaddr(netbuf, 0); + AR_DEBUG_ASSERT(pHtcHdr); + + HTC_WRITE32(pHtcHdr, + SM(pPacket->ActualLength, + HTC_FRAME_HDR_PAYLOADLEN) | SM(pPacket->PktInfo. + AsTx.SendFlags, + HTC_FRAME_HDR_FLAGS) + | SM(pPacket->Endpoint, HTC_FRAME_HDR_ENDPOINTID)); + /* + * If the HIF pipe for the data endpoint is polled rather than + * interrupt-driven, this is a good point to check whether any + * data previously sent through the HIF pipe have finished being + * sent. + * Since this may result in callbacks to htc_tx_completion_handler, + * which can take the HTC tx lock, make the hif_send_complete_check + * call before acquiring the HTC tx lock. + * Call hif_send_complete_check directly, rather than calling + * htc_send_complete_check, and call the PollTimerStart separately + * after calling hif_send_head, so the timer will be started to + * check for completion of the new outstanding download (in the + * unexpected event that other polling calls don't catch it). + */ + if (pEndpoint->ul_is_polled) { + htc_send_complete_poll_timer_stop(pEndpoint); + hif_send_complete_check(pEndpoint->target->hif_dev, + pEndpoint->UL_PipeID, 0); + } + + LOCK_HTC_TX(target); + + pPacket->PktInfo.AsTx.SeqNo = pEndpoint->SeqNo; + pEndpoint->SeqNo++; + + HTC_WRITE32(((uint32_t *) pHtcHdr) + 1, + SM(pPacket->PktInfo.AsTx.SeqNo, + HTC_FRAME_HDR_CONTROLBYTES1)); + + /* append new packet to pEndpoint->TxQueue */ + HTC_PACKET_ENQUEUE(&pEndpoint->TxQueue, pPacket); + if (HTC_TX_BUNDLE_ENABLED(target) && (more_data)) { + UNLOCK_HTC_TX(target); + return A_OK; + } + } else { + LOCK_HTC_TX(target); + pEndpoint = &target->endpoint[1]; + } + + /* increment tx processing count on entry */ + qdf_atomic_inc(&pEndpoint->TxProcessCount); + if (qdf_atomic_read(&pEndpoint->TxProcessCount) > 1) { + /* + * Another thread or task is draining the TX queues on this endpoint. + * That thread will reset the tx processing count when the queue is + * drained. + */ + qdf_atomic_dec(&pEndpoint->TxProcessCount); + UNLOCK_HTC_TX(target); + return A_OK; + } + + /***** beyond this point only 1 thread may enter ******/ + + INIT_HTC_PACKET_QUEUE(&sendQueue); + if (IS_TX_CREDIT_FLOW_ENABLED(pEndpoint)) { +#if DEBUG_CREDIT + int cred = pEndpoint->TxCredits; +#endif + get_htc_send_packets_credit_based(target, pEndpoint, &sendQueue); +#if DEBUG_CREDIT + if (ep_debug_mask & (1 << pEndpoint->Id)) { + if (cred - pEndpoint->TxCredits > 0) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + (" Decrease EP%d %d - %d = %d credits.\n", + pEndpoint->Id, cred, + cred - pEndpoint->TxCredits, + pEndpoint->TxCredits)); + } + } +#endif + UNLOCK_HTC_TX(target); + } + + else if (HTC_TX_BUNDLE_ENABLED(target)) { + + if ((hif_get_bus_type(target->hif_dev) == QDF_BUS_TYPE_USB) && + hif_get_free_queue_number(target->hif_dev, + pEndpoint->UL_PipeID)) { + /* + * Header and payload belongs to the different fragments + * and consume 2 resource for one HTC package but USB + * combine into one transfer. + */ + get_htc_send_packets(target, pEndpoint, &sendQueue, + (HTC_MAX_MSG_PER_BUNDLE_TX * 2)); + } else { + /* Dequeue max packets from endpoint tx queue */ + get_htc_send_packets(target, pEndpoint, &sendQueue, + HTC_MAX_TX_BUNDLE_SEND_LIMIT); + } + + UNLOCK_HTC_TX(target); + } + else { + /* + * Now drain the endpoint TX queue for transmission as long as we have + * enough transmit resources + */ + tx_resources = + hif_get_free_queue_number(target->hif_dev, + pEndpoint->UL_PipeID); + get_htc_send_packets(target, pEndpoint, &sendQueue, tx_resources); + UNLOCK_HTC_TX(target); + } + QDF_NBUF_UPDATE_TX_PKT_COUNT(netbuf, QDF_NBUF_TX_PKT_HTC); + DPTRACE(qdf_dp_trace(netbuf, QDF_DP_TRACE_HTC_PACKET_PTR_RECORD, + qdf_nbuf_data_addr(netbuf), + sizeof(qdf_nbuf_data(netbuf)), QDF_TX)); + + /* send what we can */ + while (true) { + if (HTC_TX_BUNDLE_ENABLED(target) && + (HTC_PACKET_QUEUE_DEPTH(&sendQueue) >= + HTC_MIN_MSG_PER_BUNDLE) && + (hif_get_bus_type(target->hif_dev) == QDF_BUS_TYPE_SDIO || + hif_get_bus_type(target->hif_dev) == QDF_BUS_TYPE_USB)) { + htc_issue_packets_bundle(target, pEndpoint, &sendQueue); + } + pPacket = htc_packet_dequeue(&sendQueue); + if (pPacket == NULL) { + break; + } + netbuf = GET_HTC_PACKET_NET_BUF_CONTEXT(pPacket); + + LOCK_HTC_TX(target); + /* store in look up queue to match completions */ + HTC_PACKET_ENQUEUE(&pEndpoint->TxLookupQueue, pPacket); + INC_HTC_EP_STAT(pEndpoint, TxIssued, 1); + pEndpoint->ul_outstanding_cnt++; + UNLOCK_HTC_TX(target); + + status = hif_send_head(target->hif_dev, + pEndpoint->UL_PipeID, + pEndpoint->Id, + HTC_HDR_LENGTH + pPacket->ActualLength, + netbuf, data_attr); +#if DEBUG_BUNDLE + qdf_print(" Send single EP%d buffer size:0x%x, total:0x%x.\n", + pEndpoint->Id, + pEndpoint->TxCreditSize, + HTC_HDR_LENGTH + pPacket->ActualLength); +#endif + + htc_issue_tx_bundle_stats_inc(target); + + if (qdf_unlikely(A_FAILED(status))) { + LOCK_HTC_TX(target); + pEndpoint->ul_outstanding_cnt--; + /* remove this packet from the tx completion queue */ + HTC_PACKET_REMOVE(&pEndpoint->TxLookupQueue, pPacket); + + /* + * Don't bother reclaiming credits - HTC flow control + * is not applicable to tx data. + * In LL systems, there is no download flow control, + * since there's virtually no download delay. + * In HL systems, the txrx SW explicitly performs the + * tx flow control. + */ + /* pEndpoint->TxCredits += pPacket->PktInfo.AsTx.CreditsUsed; */ + + /* put this frame back at the front of the sendQueue */ + HTC_PACKET_ENQUEUE_TO_HEAD(&sendQueue, pPacket); + + /* put the sendQueue back at the front of pEndpoint->TxQueue */ + HTC_PACKET_QUEUE_TRANSFER_TO_HEAD(&pEndpoint->TxQueue, + &sendQueue); + UNLOCK_HTC_TX(target); + break; /* still need to reset TxProcessCount */ + } + } + /* done with this endpoint, we can clear the count */ + qdf_atomic_init(&pEndpoint->TxProcessCount); + + if (pEndpoint->ul_is_polled) { + /* + * Start a cleanup timer to poll for download completion. + * The download completion should be noticed promptly from + * other polling calls, but the timer provides a safety net + * in case other polling calls don't occur as expected. + */ + htc_send_complete_poll_timer_start(pEndpoint); + } + + return status; +} +#endif /*ATH_11AC_TXCOMPACT */ + +/* + * In the adapted HIF layer, qdf_nbuf_t are passed between HIF and HTC, + * since upper layers expects HTC_PACKET containers we use the completed netbuf + * and lookup its corresponding HTC packet buffer from a lookup list. + * This is extra overhead that can be fixed by re-aligning HIF interfaces + * with HTC. + * + */ +static HTC_PACKET *htc_lookup_tx_packet(HTC_TARGET *target, + HTC_ENDPOINT *pEndpoint, + qdf_nbuf_t netbuf) +{ + HTC_PACKET *pPacket = NULL; + HTC_PACKET *pFoundPacket = NULL; + HTC_PACKET_QUEUE lookupQueue; + + INIT_HTC_PACKET_QUEUE(&lookupQueue); + LOCK_HTC_TX(target); + + /* mark that HIF has indicated the send complete for another packet */ + pEndpoint->ul_outstanding_cnt--; + + /* Dequeue first packet directly because of in-order completion */ + pPacket = htc_packet_dequeue(&pEndpoint->TxLookupQueue); + if (qdf_unlikely(!pPacket)) { + UNLOCK_HTC_TX(target); + return NULL; + } + if (netbuf == (qdf_nbuf_t) GET_HTC_PACKET_NET_BUF_CONTEXT(pPacket)) { + UNLOCK_HTC_TX(target); + return pPacket; + } else { + HTC_PACKET_ENQUEUE(&lookupQueue, pPacket); + } + + /* + * Move TX lookup queue to temp queue because most of packets that are not index 0 + * are not top 10 packets. + */ + HTC_PACKET_QUEUE_TRANSFER_TO_TAIL(&lookupQueue, + &pEndpoint->TxLookupQueue); + UNLOCK_HTC_TX(target); + + ITERATE_OVER_LIST_ALLOW_REMOVE(&lookupQueue.QueueHead, pPacket, + HTC_PACKET, ListLink) { + + if (NULL == pPacket) { + pFoundPacket = pPacket; + break; + } + /* check for removal */ + if (netbuf == + (qdf_nbuf_t) GET_HTC_PACKET_NET_BUF_CONTEXT(pPacket)) { + /* found it */ + HTC_PACKET_REMOVE(&lookupQueue, pPacket); + pFoundPacket = pPacket; + break; + } + + } + ITERATE_END; + + LOCK_HTC_TX(target); + HTC_PACKET_QUEUE_TRANSFER_TO_HEAD(&pEndpoint->TxLookupQueue, + &lookupQueue); + UNLOCK_HTC_TX(target); + + return pFoundPacket; +} + +/** + * htc_tx_completion_handler() - htc tx completion handler + * @Context: pointer to HTC_TARGET structure + * @netbuf: pointer to netbuf for which completion handler is being called + * @EpID: end point Id on which the packet was sent + * @toeplitz_hash_result: toeplitz hash result + * + * Return: QDF_STATUS_SUCCESS for success or an appropriate QDF_STATUS error + */ +QDF_STATUS htc_tx_completion_handler(void *Context, + qdf_nbuf_t netbuf, unsigned int EpID, + uint32_t toeplitz_hash_result) +{ + HTC_TARGET *target = (HTC_TARGET *) Context; + HTC_ENDPOINT *pEndpoint; + HTC_PACKET *pPacket; +#ifdef USB_HIF_SINGLE_PIPE_DATA_SCHED + HTC_ENDPOINT_ID eid[DATA_EP_SIZE] = { ENDPOINT_5, ENDPOINT_4, + ENDPOINT_2, ENDPOINT_3 }; + int epidIdx; + uint16_t resourcesThresh[DATA_EP_SIZE]; /* urb resources */ + uint16_t resources; + uint16_t resourcesMax; +#endif + + pEndpoint = &target->endpoint[EpID]; + target->TX_comp_cnt++; + + do { + pPacket = htc_lookup_tx_packet(target, pEndpoint, netbuf); + if (NULL == pPacket) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + ("HTC TX lookup failed!\n")); + /* may have already been flushed and freed */ + netbuf = NULL; + break; + } + if (pPacket->PktInfo.AsTx.Tag != HTC_TX_PACKET_TAG_AUTO_PM) + hif_pm_runtime_put(target->hif_dev); + + if (pPacket->PktInfo.AsTx.Tag == HTC_TX_PACKET_TAG_BUNDLED) { + HTC_PACKET *pPacketTemp; + HTC_PACKET_QUEUE *pQueueSave = + (HTC_PACKET_QUEUE *) pPacket->pContext; + HTC_PACKET_QUEUE_ITERATE_ALLOW_REMOVE(pQueueSave, + pPacketTemp) { + pPacket->Status = A_OK; + send_packet_completion(target, pPacketTemp); + } + HTC_PACKET_QUEUE_ITERATE_END; + free_htc_bundle_packet(target, pPacket); + + if (hif_get_bus_type(target->hif_dev) == QDF_BUS_TYPE_USB) { + if (!IS_TX_CREDIT_FLOW_ENABLED(pEndpoint)) + htc_try_send(target, pEndpoint, NULL); + } + + return QDF_STATUS_SUCCESS; + } + /* will be giving this buffer back to upper layers */ + netbuf = NULL; + pPacket->Status = QDF_STATUS_SUCCESS; + send_packet_completion(target, pPacket); + + } while (false); + + if (!IS_TX_CREDIT_FLOW_ENABLED(pEndpoint)) { + /* note: when using TX credit flow, the re-checking of queues happens + * when credits flow back from the target. + * in the non-TX credit case, we recheck after the packet completes */ + htc_try_send(target, pEndpoint, NULL); + } + + return QDF_STATUS_SUCCESS; +} + +#ifdef WLAN_FEATURE_FASTPATH +/** + * htc_ctrl_msg_cmpl(): checks for tx completion for the endpoint specified + * @HTC_HANDLE : pointer to the htc target context + * @htc_ep_id : end point id + * + * checks HTC tx completion + * + * Return: none + */ +void htc_ctrl_msg_cmpl(HTC_HANDLE htc_pdev, HTC_ENDPOINT_ID htc_ep_id) +{ + HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(htc_pdev); + HTC_ENDPOINT *pendpoint = &target->endpoint[htc_ep_id]; + + htc_send_complete_check(pendpoint, 1); +} +#endif + +/* callback when TX resources become available */ +void htc_tx_resource_avail_handler(void *context, uint8_t pipeID) +{ + int i; + HTC_TARGET *target = (HTC_TARGET *) context; + HTC_ENDPOINT *pEndpoint = NULL; + + for (i = 0; i < ENDPOINT_MAX; i++) { + pEndpoint = &target->endpoint[i]; + if (pEndpoint->service_id != 0) { + if (pEndpoint->UL_PipeID == pipeID) { + break; + } + } + } + + if (i >= ENDPOINT_MAX) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + ("Invalid pipe indicated for TX resource avail : %d!\n", + pipeID)); + return; + } + + AR_DEBUG_PRINTF(ATH_DEBUG_SEND, + ("HIF indicated more resources for pipe:%d \n", + pipeID)); + + htc_try_send(target, pEndpoint, NULL); +} + +#ifdef FEATURE_RUNTIME_PM +/** + * htc_kick_queues(): resumes tx transactions of suspended endpoints + * @context: pointer to the htc target context + * + * Iterates throught the enpoints and provides a context to empty queues + * int the hif layer when they are stalled due to runtime suspend. + * + * Return: none + */ +void htc_kick_queues(void *context) +{ + int i; + HTC_TARGET *target = (HTC_TARGET *)context; + HTC_ENDPOINT *endpoint = NULL; + + for (i = 0; i < ENDPOINT_MAX; i++) { + endpoint = &target->endpoint[i]; + + if (endpoint->service_id == 0) + continue; + + if (endpoint->EpCallBacks.ep_resume_tx_queue) + endpoint->EpCallBacks.ep_resume_tx_queue( + endpoint->EpCallBacks.pContext); + + htc_try_send(target, endpoint, NULL); + } +} +#endif + +/* flush endpoint TX queue */ +void htc_flush_endpoint_tx(HTC_TARGET *target, HTC_ENDPOINT *pEndpoint, + HTC_TX_TAG Tag) +{ + HTC_PACKET *pPacket; + + LOCK_HTC_TX(target); + while (HTC_PACKET_QUEUE_DEPTH(&pEndpoint->TxQueue)) { + pPacket = htc_packet_dequeue(&pEndpoint->TxQueue); + + if (pPacket) { + /* let the sender know the packet was not delivered */ + pPacket->Status = A_ECANCELED; + send_packet_completion(target, pPacket); + } + } + UNLOCK_HTC_TX(target); +} + +/* HTC API to flush an endpoint's TX queue*/ +void htc_flush_endpoint(HTC_HANDLE HTCHandle, HTC_ENDPOINT_ID Endpoint, + HTC_TX_TAG Tag) +{ + HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle); + HTC_ENDPOINT *pEndpoint = &target->endpoint[Endpoint]; + + if (pEndpoint->service_id == 0) { + AR_DEBUG_ASSERT(false); + /* not in use.. */ + return; + } + + htc_flush_endpoint_tx(target, pEndpoint, Tag); +} + +/* HTC API to indicate activity to the credit distribution function */ +void htc_indicate_activity_change(HTC_HANDLE HTCHandle, + HTC_ENDPOINT_ID Endpoint, bool Active) +{ + /* TODO */ +} + +bool htc_is_endpoint_active(HTC_HANDLE HTCHandle, HTC_ENDPOINT_ID Endpoint) +{ + return true; +} + +void htc_set_nodrop_pkt(HTC_HANDLE HTCHandle, A_BOOL isNodropPkt) +{ + HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle); + target->is_nodrop_pkt = isNodropPkt; +} + +/** + * htc_process_credit_rpt() - process credit report, call distribution function + * @target: pointer to HTC_TARGET + * @pRpt: pointer to HTC_CREDIT_REPORT + * @NumEntries: number of entries in credit report + * @FromEndpoint: endpoint for which credit report is received + * + * Return: A_OK for success or an appropriate A_STATUS error + */ +void htc_process_credit_rpt(HTC_TARGET *target, HTC_CREDIT_REPORT *pRpt, + int NumEntries, HTC_ENDPOINT_ID FromEndpoint) +{ + int i; + HTC_ENDPOINT *pEndpoint; + int totalCredits = 0; + uint8_t rpt_credits, rpt_ep_id; + + AR_DEBUG_PRINTF(ATH_DEBUG_SEND, + ("+htc_process_credit_rpt, Credit Report Entries:%d \n", + NumEntries)); + + /* lock out TX while we update credits */ + LOCK_HTC_TX(target); + + for (i = 0; i < NumEntries; i++, pRpt++) { + + rpt_ep_id = HTC_GET_FIELD(pRpt, HTC_CREDIT_REPORT, ENDPOINTID); + + if (rpt_ep_id >= ENDPOINT_MAX) { + AR_DEBUG_ASSERT(false); + break; + } + + rpt_credits = HTC_GET_FIELD(pRpt, HTC_CREDIT_REPORT, CREDITS); + + pEndpoint = &target->endpoint[rpt_ep_id]; +#if DEBUG_CREDIT + if (ep_debug_mask & (1 << pEndpoint->Id)) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + (" Increase EP%d %d + %d = %d credits\n", + rpt_ep_id, pEndpoint->TxCredits, + rpt_credits, + pEndpoint->TxCredits + rpt_credits)); + } +#endif + +#ifdef HTC_EP_STAT_PROFILING + + INC_HTC_EP_STAT(pEndpoint, TxCreditRpts, 1); + INC_HTC_EP_STAT(pEndpoint, TxCreditsReturned, rpt_credits); + + if (FromEndpoint == rpt_ep_id) { + /* this credit report arrived on the same endpoint indicating it arrived in an RX + * packet */ + INC_HTC_EP_STAT(pEndpoint, TxCreditsFromRx, + rpt_credits); + INC_HTC_EP_STAT(pEndpoint, TxCreditRptsFromRx, 1); + } else if (FromEndpoint == ENDPOINT_0) { + /* this credit arrived on endpoint 0 as a NULL message */ + INC_HTC_EP_STAT(pEndpoint, TxCreditsFromEp0, + rpt_credits); + INC_HTC_EP_STAT(pEndpoint, TxCreditRptsFromEp0, 1); + } else { + /* arrived on another endpoint */ + INC_HTC_EP_STAT(pEndpoint, TxCreditsFromOther, + rpt_credits); + INC_HTC_EP_STAT(pEndpoint, TxCreditRptsFromOther, 1); + } + +#endif + + pEndpoint->TxCredits += rpt_credits; + + if (pEndpoint->service_id == WMI_CONTROL_SVC) { + LOCK_HTC_CREDIT(target); + htc_credit_record(HTC_PROCESS_CREDIT_REPORT, + pEndpoint->TxCredits, + HTC_PACKET_QUEUE_DEPTH(&pEndpoint-> + TxQueue)); + UNLOCK_HTC_CREDIT(target); + } + + if (pEndpoint->TxCredits + && HTC_PACKET_QUEUE_DEPTH(&pEndpoint->TxQueue)) { + UNLOCK_HTC_TX(target); +#ifdef ATH_11AC_TXCOMPACT + htc_try_send(target, pEndpoint, NULL); +#else + if (pEndpoint->service_id == HTT_DATA_MSG_SVC) { + htc_send_data_pkt(target, NULL, 0); + } else { + htc_try_send(target, pEndpoint, NULL); + } +#endif + LOCK_HTC_TX(target); + } + totalCredits += rpt_credits; + } + + AR_DEBUG_PRINTF(ATH_DEBUG_SEND, + (" Report indicated %d credits to distribute \n", + totalCredits)); + + UNLOCK_HTC_TX(target); + + AR_DEBUG_PRINTF(ATH_DEBUG_SEND, ("-htc_process_credit_rpt \n")); +} + +/* function to fetch stats from htc layer*/ +struct ol_ath_htc_stats *ieee80211_ioctl_get_htc_stats(HTC_HANDLE HTCHandle) +{ + HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle); + + return &(target->htc_pkt_stats); +} diff --git a/drivers/staging/qca-wifi-host-cmn/htc/htc_services.c b/drivers/staging/qca-wifi-host-cmn/htc/htc_services.c new file mode 100644 index 0000000000000000000000000000000000000000..0cfe8bae150761ee7584d7000fa482632f46c391 --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/htc/htc_services.c @@ -0,0 +1,426 @@ +/* + * Copyright (c) 2013-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#include "htc_debug.h" +#include "htc_internal.h" +#include +#include /* qdf_nbuf_t */ + +/* use credit flow control over HTC */ +unsigned int htc_credit_flow = 1; +#ifndef DEBUG_CREDIT +#define DEBUG_CREDIT 0 +#endif + +/* HTC credit flow global disable */ +void htc_global_credit_flow_disable(void) +{ + htc_credit_flow = 0; +} + +/* HTC credit flow global enable */ +void htc_global_credit_flow_enable(void) +{ + htc_credit_flow = 1; +} + +#ifdef HIF_SDIO + +/** + * htc_alt_data_credit_size_update() - update tx credit size info + * on max bundle size + * @target: hif context + * @ul_pipe: endpoint ul pipe id + * @dl_pipe: endpoint dl pipe id + * @txCreditSize: endpoint tx credit size + * + * + * When AltDataCreditSize is non zero, it indicates the credit size for + * HTT and all other services on Mbox0. Mbox1 has WMI_CONTROL_SVC which + * uses the default credit size. Use AltDataCreditSize only when + * mailbox is swapped. Mailbox swap bit is set by bmi_target_ready at + * the end of BMI phase. + * + * The Credit Size is a parameter associated with the mbox rather than + * a service. Multiple services can run on this mbox. + * + * If AltDataCreditSize is 0, that means the firmware doesn't support + * this feature. Default to the TargetCreditSize + * + * Return: None + */ +static inline void +htc_alt_data_credit_size_update(HTC_TARGET *target, + uint8_t *ul_pipe, + uint8_t *dl_pipe, + int *txCreditSize) +{ + if ((target->AltDataCreditSize) && + (*ul_pipe == 1) && (*dl_pipe == 0)) + *txCreditSize = target->AltDataCreditSize; + + return; +} +#else + +static inline void +htc_alt_data_credit_size_update(HTC_TARGET *target, + uint8_t *ul_pipe, + uint8_t *dl_pipe, + int *txCreditSize) +{ + return; +} +#endif + +A_STATUS htc_connect_service(HTC_HANDLE HTCHandle, + HTC_SERVICE_CONNECT_REQ *pConnectReq, + HTC_SERVICE_CONNECT_RESP *pConnectResp) +{ + HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle); + A_STATUS status = A_OK; + HTC_PACKET *pSendPacket = NULL; + HTC_CONNECT_SERVICE_RESPONSE_MSG *pResponseMsg; + HTC_CONNECT_SERVICE_MSG *pConnectMsg; + HTC_ENDPOINT_ID assignedEndpoint = ENDPOINT_MAX; + HTC_ENDPOINT *pEndpoint; + unsigned int maxMsgSize = 0; + qdf_nbuf_t netbuf; + uint8_t txAlloc; + int length; + bool disableCreditFlowCtrl = false; + uint16_t conn_flags; + uint16_t rsp_msg_id, rsp_msg_serv_id, rsp_msg_max_msg_size; + uint8_t rsp_msg_status, rsp_msg_end_id, rsp_msg_serv_meta_len; + + AR_DEBUG_PRINTF(ATH_DEBUG_TRC, + ("+htc_connect_service, target:%p SvcID:0x%X\n", target, + pConnectReq->service_id)); + + do { + + AR_DEBUG_ASSERT(pConnectReq->service_id != 0); + + if (HTC_CTRL_RSVD_SVC == pConnectReq->service_id) { + /* special case for pseudo control service */ + assignedEndpoint = ENDPOINT_0; + maxMsgSize = HTC_MAX_CONTROL_MESSAGE_LENGTH; + txAlloc = 0; + + } else { + + txAlloc = htc_get_credit_allocation(target, + pConnectReq->service_id); + + if (!txAlloc) { + AR_DEBUG_PRINTF(ATH_DEBUG_TRC, + ("Service %d does not allocate target credits!\n", + pConnectReq->service_id)); + } + + /* allocate a packet to send to the target */ + pSendPacket = htc_alloc_control_tx_packet(target); + + if (NULL == pSendPacket) { + AR_DEBUG_ASSERT(false); + status = A_NO_MEMORY; + break; + } + + netbuf = + (qdf_nbuf_t) + GET_HTC_PACKET_NET_BUF_CONTEXT(pSendPacket); + length = + sizeof(HTC_CONNECT_SERVICE_MSG) + + pConnectReq->MetaDataLength; + + /* assemble connect service message */ + qdf_nbuf_put_tail(netbuf, length); + pConnectMsg = + (HTC_CONNECT_SERVICE_MSG *) qdf_nbuf_data(netbuf); + + if (NULL == pConnectMsg) { + AR_DEBUG_ASSERT(0); + status = A_EFAULT; + break; + } + + qdf_mem_zero(pConnectMsg, + sizeof(HTC_CONNECT_SERVICE_MSG)); + + conn_flags = + (pConnectReq-> + ConnectionFlags & ~HTC_SET_RECV_ALLOC_MASK) | + HTC_CONNECT_FLAGS_SET_RECV_ALLOCATION(txAlloc); + HTC_SET_FIELD(pConnectMsg, HTC_CONNECT_SERVICE_MSG, + MESSAGEID, HTC_MSG_CONNECT_SERVICE_ID); + HTC_SET_FIELD(pConnectMsg, HTC_CONNECT_SERVICE_MSG, + SERVICE_ID, pConnectReq->service_id); + HTC_SET_FIELD(pConnectMsg, HTC_CONNECT_SERVICE_MSG, + CONNECTIONFLAGS, conn_flags); + + if (pConnectReq-> + ConnectionFlags & + HTC_CONNECT_FLAGS_DISABLE_CREDIT_FLOW_CTRL) { + disableCreditFlowCtrl = true; + } + + if (!htc_credit_flow) { + disableCreditFlowCtrl = true; + } + + /* check caller if it wants to transfer meta data */ + if ((pConnectReq->pMetaData != NULL) && + (pConnectReq->MetaDataLength <= + HTC_SERVICE_META_DATA_MAX_LENGTH)) { + /* copy meta data into message buffer (after header ) */ + qdf_mem_copy((uint8_t *) pConnectMsg + + sizeof(HTC_CONNECT_SERVICE_MSG), + pConnectReq->pMetaData, + pConnectReq->MetaDataLength); + + HTC_SET_FIELD(pConnectMsg, + HTC_CONNECT_SERVICE_MSG, + SERVICEMETALENGTH, + pConnectReq->MetaDataLength); + } + + SET_HTC_PACKET_INFO_TX(pSendPacket, + NULL, + (uint8_t *) pConnectMsg, + length, + ENDPOINT_0, + HTC_SERVICE_TX_PACKET_TAG); + + status = htc_send_pkt((HTC_HANDLE) target, pSendPacket); + /* we don't own it anymore */ + pSendPacket = NULL; + if (A_FAILED(status)) { + break; + } + + /* wait for response */ + status = htc_wait_recv_ctrl_message(target); + if (A_FAILED(status)) { + break; + } + /* we controlled the buffer creation so it has to be properly aligned */ + pResponseMsg = + (HTC_CONNECT_SERVICE_RESPONSE_MSG *) target-> + CtrlResponseBuffer; + + rsp_msg_id = HTC_GET_FIELD(pResponseMsg, + HTC_CONNECT_SERVICE_RESPONSE_MSG, + MESSAGEID); + rsp_msg_serv_id = + HTC_GET_FIELD(pResponseMsg, + HTC_CONNECT_SERVICE_RESPONSE_MSG, + SERVICEID); + rsp_msg_status = + HTC_GET_FIELD(pResponseMsg, + HTC_CONNECT_SERVICE_RESPONSE_MSG, + STATUS); + rsp_msg_end_id = + HTC_GET_FIELD(pResponseMsg, + HTC_CONNECT_SERVICE_RESPONSE_MSG, + ENDPOINTID); + rsp_msg_max_msg_size = + HTC_GET_FIELD(pResponseMsg, + HTC_CONNECT_SERVICE_RESPONSE_MSG, + MAXMSGSIZE); + rsp_msg_serv_meta_len = + HTC_GET_FIELD(pResponseMsg, + HTC_CONNECT_SERVICE_RESPONSE_MSG, + SERVICEMETALENGTH); + + if ((rsp_msg_id != HTC_MSG_CONNECT_SERVICE_RESPONSE_ID) + || (target->CtrlResponseLength < + sizeof(HTC_CONNECT_SERVICE_RESPONSE_MSG))) { + /* this message is not valid */ + AR_DEBUG_ASSERT(false); + status = A_EPROTO; + break; + } + + AR_DEBUG_PRINTF(ATH_DEBUG_TRC, + ("htc_connect_service, service 0x%X connect response from target status:%d, assigned ep: %d\n", + rsp_msg_serv_id, rsp_msg_status, + rsp_msg_end_id)); + + pConnectResp->ConnectRespCode = rsp_msg_status; + + /* check response status */ + if (rsp_msg_status != HTC_SERVICE_SUCCESS) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + (" Target failed service 0x%X connect request (status:%d)\n", + rsp_msg_serv_id, + rsp_msg_status)); + status = A_EPROTO; +/* TODO: restore the ifdef when FW supports services 301 and 302 (HTT_MSG_DATA[23]_MSG_SVC) +#ifdef QCA_TX_HTT2_SUPPORT +*/ + /* Keep work and not to block the control message. */ + target->CtrlResponseProcessing = false; +/*#endif */ /* QCA_TX_HTT2_SUPPORT */ + break; + } + + assignedEndpoint = (HTC_ENDPOINT_ID) rsp_msg_end_id; + maxMsgSize = rsp_msg_max_msg_size; + + if ((pConnectResp->pMetaData != NULL) && + (rsp_msg_serv_meta_len > 0) && + (rsp_msg_serv_meta_len <= + HTC_SERVICE_META_DATA_MAX_LENGTH)) { + /* caller supplied a buffer and the target responded with data */ + int copyLength = + min((int)pConnectResp->BufferLength, + (int)rsp_msg_serv_meta_len); + /* copy the meta data */ + qdf_mem_copy(pConnectResp->pMetaData, + ((uint8_t *) pResponseMsg) + + sizeof + (HTC_CONNECT_SERVICE_RESPONSE_MSG), + copyLength); + pConnectResp->ActualLength = copyLength; + } + /* done processing response buffer */ + target->CtrlResponseProcessing = false; + } + + /* the rest of these are parameter checks so set the error status */ + status = A_EPROTO; + + if (assignedEndpoint >= ENDPOINT_MAX) { + AR_DEBUG_ASSERT(false); + break; + } + + if (0 == maxMsgSize) { + AR_DEBUG_ASSERT(false); + break; + } + + pEndpoint = &target->endpoint[assignedEndpoint]; + pEndpoint->Id = assignedEndpoint; + if (pEndpoint->service_id != 0) { + /* endpoint already in use! */ + AR_DEBUG_ASSERT(false); + break; + } + + /* return assigned endpoint to caller */ + pConnectResp->Endpoint = assignedEndpoint; + pConnectResp->MaxMsgLength = maxMsgSize; + + /* setup the endpoint */ + /* service_id marks the endpoint in use */ + pEndpoint->service_id = pConnectReq->service_id; + pEndpoint->MaxTxQueueDepth = pConnectReq->MaxSendQueueDepth; + pEndpoint->MaxMsgLength = maxMsgSize; + pEndpoint->TxCredits = txAlloc; + pEndpoint->TxCreditSize = target->TargetCreditSize; + pEndpoint->TxCreditsPerMaxMsg = + maxMsgSize / target->TargetCreditSize; + if (maxMsgSize % target->TargetCreditSize) { + pEndpoint->TxCreditsPerMaxMsg++; + } +#if DEBUG_CREDIT + qdf_print(" Endpoint%d initial credit:%d, size:%d.\n", + pEndpoint->Id, pEndpoint->TxCredits, + pEndpoint->TxCreditSize); +#endif + + /* copy all the callbacks */ + pEndpoint->EpCallBacks = pConnectReq->EpCallbacks; + + status = hif_map_service_to_pipe(target->hif_dev, + pEndpoint->service_id, + &pEndpoint->UL_PipeID, + &pEndpoint->DL_PipeID, + &pEndpoint->ul_is_polled, + &pEndpoint->dl_is_polled); + if (A_FAILED(status)) { + break; + } + + htc_alt_data_credit_size_update(target, + &pEndpoint->UL_PipeID, + &pEndpoint->DL_PipeID, + &pEndpoint->TxCreditSize); + + qdf_assert(!pEndpoint->dl_is_polled); /* not currently supported */ + + if (pEndpoint->ul_is_polled) { + qdf_timer_init(target->osdev, + &pEndpoint->ul_poll_timer, + htc_send_complete_check_cleanup, + pEndpoint, + QDF_TIMER_TYPE_SW); + } + + AR_DEBUG_PRINTF(ATH_DEBUG_SETUP, + ("HTC Service:0x%4.4X, ULpipe:%d DLpipe:%d id:%d Ready\n", + pEndpoint->service_id, pEndpoint->UL_PipeID, + pEndpoint->DL_PipeID, pEndpoint->Id)); + + if (disableCreditFlowCtrl && pEndpoint->TxCreditFlowEnabled) { + pEndpoint->TxCreditFlowEnabled = false; + AR_DEBUG_PRINTF(ATH_DEBUG_WARN, + ("HTC Service:0x%4.4X ep:%d TX flow control disabled\n", + pEndpoint->service_id, + assignedEndpoint)); + } + + } while (false); + + AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("-htc_connect_service\n")); + + return status; +} + +void htc_set_credit_distribution(HTC_HANDLE HTCHandle, + void *pCreditDistContext, + HTC_CREDIT_DIST_CALLBACK CreditDistFunc, + HTC_CREDIT_INIT_CALLBACK CreditInitFunc, + HTC_SERVICE_ID ServicePriorityOrder[], + int ListLength) +{ + /* NOT Supported, this transport does not use a credit based flow control mechanism */ + +} + +void htc_fw_event_handler(void *context, QDF_STATUS status) +{ + HTC_TARGET *target = (HTC_TARGET *) context; + HTC_INIT_INFO *initInfo = &target->HTCInitInfo; + + /* check if target failure handler exists and pass error code to it. */ + if (target->HTCInitInfo.TargetFailure != NULL) { + initInfo->TargetFailure(initInfo->pContext, status); + } +} diff --git a/drivers/staging/qca-wifi-host-cmn/pld_stub/inc/pld_common.h b/drivers/staging/qca-wifi-host-cmn/pld_stub/inc/pld_common.h new file mode 100644 index 0000000000000000000000000000000000000000..83ed961f4e3f9d3893370fdf9b628199fe1b6550 --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/pld_stub/inc/pld_common.h @@ -0,0 +1,227 @@ +/* + * Copyright (c) 2016 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 __PLD_COMMON_H__ +#define __PLD_COMMON_H__ + +#ifdef CONFIG_PLD_STUB + +/** + * struct pld_ce_tgt_pipe_cfg - copy engine target pipe configuration + * @pipe_num: pipe number + * @pipe_dir: pipe direction + * @nentries: number of entries + * @nbytes_max: max number of bytes + * @flags: flags + * @reserved: reserved + * + * pld_ce_tgt_pipe_cfg is used to store copy engine target pipe + * configuration. + */ +struct pld_ce_tgt_pipe_cfg { + u32 pipe_num; + u32 pipe_dir; + u32 nentries; + u32 nbytes_max; + u32 flags; + u32 reserved; +}; + +/** + * struct pld_ce_svc_pipe_cfg - copy engine service pipe configuration + * @service_id: service ID + * @pipe_dir: pipe direction + * @pipe_num: pipe number + * + * pld_ce_svc_pipe_cfg is used to store copy engine service pipe + * configuration. + */ +struct pld_ce_svc_pipe_cfg { + u32 service_id; + u32 pipe_dir; + u32 pipe_num; +}; + +/** + * struct pld_shadow_reg_cfg - shadow register configuration + * @ce_id: copy engine ID + * @reg_offset: register offset + * + * pld_shadow_reg_cfg is used to store shadow register configuration. + */ +struct pld_shadow_reg_cfg { + u16 ce_id; + u16 reg_offset; +}; + +/** + * struct pld_wlan_enable_cfg - WLAN FW configuration + * @num_ce_tgt_cfg: number of CE target configuration + * @ce_tgt_cfg: CE target configuration + * @num_ce_svc_pipe_cfg: number of CE service configuration + * @ce_svc_cfg: CE service configuration + * @num_shadow_reg_cfg: number of shadow register configuration + * @shadow_reg_cfg: shadow register configuration + * + * pld_wlan_enable_cfg stores WLAN FW configurations. It will be + * passed to WLAN FW when WLAN host driver calls wlan_enable. + */ +struct pld_wlan_enable_cfg { + u32 num_ce_tgt_cfg; + struct pld_ce_tgt_pipe_cfg *ce_tgt_cfg; + u32 num_ce_svc_pipe_cfg; + struct pld_ce_svc_pipe_cfg *ce_svc_cfg; + u32 num_shadow_reg_cfg; + struct pld_shadow_reg_cfg *shadow_reg_cfg; +}; + +/** + * enum pld_driver_mode - WLAN host driver mode + * @PLD_MISSION: mission mode + * @PLD_FTM: FTM mode + * @PLD_EPPING: EPPING mode + * @PLD_WALTEST: WAL test mode, FW standalone test mode + * @PLD_OFF: OFF mode + */ +enum pld_driver_mode { + PLD_MISSION, + PLD_FTM, + PLD_EPPING, + PLD_WALTEST, + PLD_OFF +}; + +#define PLD_MAX_TIMESTAMP_LEN 32 + +/** + * struct pld_soc_info - SOC information + * @v_addr: virtual address of preallocated memory + * @p_addr: physical address of preallcoated memory + * @chip_id: chip ID + * @chip_family: chip family + * @board_id: board ID + * @soc_id: SOC ID + * @fw_version: FW version + * @fw_build_timestamp: FW build timestamp + * + * pld_soc_info is used to store WLAN SOC information. + */ +struct pld_soc_info { + void __iomem *v_addr; + phys_addr_t p_addr; + u32 chip_id; + u32 chip_family; + u32 board_id; + u32 soc_id; + u32 fw_version; + char fw_build_timestamp[PLD_MAX_TIMESTAMP_LEN + 1]; +}; + +/** + * enum pld_runtime_request - PM runtime request + * @PLD_PM_RUNTIME_GET: pm_runtime_get + * @PLD_PM_RUNTIME_PUT: pm_runtime_put + * @PLD_PM_RUNTIME_MARK_LAST_BUSY: pm_runtime_mark_last_busy + * @PLD_PM_RUNTIME_RESUME: pm_runtime_resume + * @PLD_PM_RUNTIME_PUT_NOIDLE: pm_runtime_put_noidle + * @PLD_PM_REQUEST_RESUME: pm_request_resume + * @PLD_PM_RUNTIME_PUT_AUTO: pm_runtime_put_auto + */ +enum pld_runtime_request { + PLD_PM_RUNTIME_GET, + PLD_PM_RUNTIME_PUT, + PLD_PM_RUNTIME_MARK_LAST_BUSY, + PLD_PM_RUNTIME_RESUME, + PLD_PM_RUNTIME_PUT_NOIDLE, + PLD_PM_REQUEST_RESUME, + PLD_PM_RUNTIME_PUT_AUTO, +}; + +static inline int pld_wlan_enable(struct device *dev, + struct pld_wlan_enable_cfg *config, + enum pld_driver_mode mode, + const char *host_version) +{ + return 0; +} +static inline int pld_wlan_disable(struct device *dev, + enum pld_driver_mode mode) +{ + return 0; +} +static inline void pld_is_pci_link_down(struct device *dev) +{ + return; +} +static inline int pld_wlan_pm_control(struct device *dev, bool vote) +{ + return 0; +} +static inline void pld_intr_notify_q6(struct device *dev) +{ + return; +} +static inline int pld_ce_request_irq(struct device *dev, unsigned int ce_id, + irqreturn_t (*handler)(int, void *), + unsigned long flags, const char *name, + void *ctx) +{ + return 0; +} +static inline int pld_ce_free_irq(struct device *dev, + unsigned int ce_id, void *ctx) +{ + return 0; +} +static inline int pld_get_soc_info(struct device *dev, + struct pld_soc_info *info) +{ + return 0; +} +static inline int pld_get_ce_id(struct device *dev, int irq) +{ + return 0; +} +static inline int pld_pm_runtime_request(struct device *dev, + enum pld_runtime_request request) +{ + return 0; +} +static inline void pld_runtime_init(struct device *dev, int auto_delay) +{ + return; +} +static inline void pld_runtime_exit(struct device *dev) +{ + return; +} +static inline int pld_athdiag_read(struct device *dev, + uint32_t offset, uint32_t memtype, + uint32_t datalen, uint8_t *output) +{ + return 0; +} +static inline int pld_athdiag_write(struct device *dev, + uint32_t offset, uint32_t memtype, + uint32_t datalen, uint8_t *input) +{ + return 0; +} + +#endif +#endif diff --git a/drivers/staging/qca-wifi-host-cmn/qdf/Kbuild b/drivers/staging/qca-wifi-host-cmn/qdf/Kbuild new file mode 100644 index 0000000000000000000000000000000000000000..2d5281ae5db4260dd850f9daeff4a224a0200dd3 --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/qdf/Kbuild @@ -0,0 +1,88 @@ +ifeq ($(obj),) +obj := . +endif + +DEPTH := ../.. + +include $(obj)/$(DEPTH)/os/linux/Makefile-linux.common + +ifeq ($(ATH_SUPPORT_HTC),1) +INCS = -include $(COMINC)/compat.h -I$(COMINC) -I$(WLAN_TOP)/os/$(OS)/include -I$(WLAN_TOP)/os/$(OS)/src -I$(KERNELPATH)/include +INCS += -I$(WLAN_TOP)/asf/include +endif + +INCS += -Iinclude/nbuf -Iinclude/net -Iinclude/os +INCS += -Inbuf/linux -Inet/linux -Ios/linux +INCS += -I$(WLAN_TOP)/../../include +INCS += -I$(WLAN_TOP)/cmn_dev/qdf/inc +INCS += -I$(WLAN_TOP)/cmn_dev/qdf/linux/src + +obj-m += qdf.o + +EXTRA_CFLAGS+= $(INCS) $(COPTS) -Wno-unused-function + +ifeq ($(strip ${QCA_PARTNER_MAKE_F_SUPPORT}),1) +MOD_CFLAGS = -D"KBUILD_STR(s)=\#s" -D"KBUILD_BASENAME=KBUILD_STR(qdf.mod)" -D"KBUILD_MODNAME=KBUILD_STR(qdf)" +endif + +qdf-objs := \ +linux/src/qdf_defer.o \ +linux/src/qdf_event.o \ +linux/src/qdf_list.o \ +linux/src/qdf_lock.o \ +linux/src/qdf_mc_timer.o \ +linux/src/qdf_mem.o \ +linux/src/qdf_module.o \ +linux/src/qdf_nbuf.o \ +linux/src/qdf_perf.o \ +linux/src/qdf_threads.o +#linux/src/qdf_net.o \ +#linux/src/qdf_net_event.o \ +#linux/src/qdf_net_ioctl.o +#linux/src/qdf_net_wext.o + + +ifeq ($(BUILD_ADF_NET_IOCTL),1) +EXTRA_CFLAGS+= -DADF_NET_IOCTL_SUPPORT +#adf-objs += os/linux/adf_os_netlink_pvt.o \ +# net/linux/adf_net_event.o \ +# net/linux/adf_net_wext.o \ +# net/linux/adf_net_ioctl.o +endif + +ifeq ($(BUILD_ADF_DEFER_PVT),1) +#adf-objs += os/linux/adf_os_defer_pvt.o +endif +ifeq ($(BUILD_ADF_IRQ_PVT),1) +#adf-objs += os/linux/adf_os_irq_pvt.o +endif + +ifeq ($(BUILD_ADF_PERF_PROFILING),1) +#adf-objs += os/linux/adf_os_perf_pvt.o +ifeq ($(BUILD_ADF_MIPS_PERF_PROFILING),1) +#adf-objs += os/linux/adf_os_mips_perf_pvt.o +endif +endif + +# os/linux/adf_os_pci_pvt.o \ +# net/linux/adf_net_ioctl.o \ +# net/linux/adf_net_pseudo.o \ + +clean-files := modules.order + +ifeq ($(strip ${QCA_PARTNER_MAKE_F_SUPPORT}),1) +all: qdf.ko + +qdf.mod.o: qdf.mod.c + ${CC} -c -o $@ ${EXTRA_CFLAGS} ${MOD_CFLAGS} $< + +adf.o: ${adf-objs} + $(LD) -m elf32btsmip -r -o adf.o $(adf-objs) + $(KERNELPATH)/scripts/mod/modpost qdf.o + +qdf.ko: qdf.o qdf.mod.o + $(LD) $(LDOPTS) -o qdf.ko qdf.o qdf.mod.o + +%.o: %.c + ${CC} -c -o $@ ${EXTRA_CFLAGS} $< +endif diff --git a/drivers/staging/qca-wifi-host-cmn/qdf/inc/osdep.h b/drivers/staging/qca-wifi-host-cmn/qdf/inc/osdep.h new file mode 100644 index 0000000000000000000000000000000000000000..24c0601287cabe440f9a4a05910c446023353f8a --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/qdf/inc/osdep.h @@ -0,0 +1,187 @@ +/* + * Copyright (c) 2013-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: osdep + * This file provides OS abstraction for osdependent APIs. + */ + +#ifndef _OSDEP_H +#define _OSDEP_H + +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * ATH_DEBUG - + * Control whether debug features (printouts, assertions) are compiled + * into the driver. + */ +#ifndef ATH_DEBUG +#define ATH_DEBUG 1 /* default: include debug code */ +#endif + +#if ATH_DEBUG +#ifndef ASSERT +#define ASSERT(expr) qdf_assert(expr) +#endif +#else +#define ASSERT(expr) +#endif /* ATH_DEBUG */ + +/* + * Need to define byte order based on the CPU configuration. + */ +#ifndef _LITTLE_ENDIAN +#define _LITTLE_ENDIAN 1234 +#endif +#ifndef _BIG_ENDIAN +#define _BIG_ENDIAN 4321 +#endif +#ifdef __BIG_ENDIAN +#define _BYTE_ORDER _BIG_ENDIAN +#else +#define _BYTE_ORDER _LITTLE_ENDIAN +#endif + +/* + * Deduce if tasklets are available. If not then + * fall back to using the immediate work queue. + */ +#define qdf_sysctl_decl(f, ctl, write, filp, buffer, lenp, ppos) \ + f(struct ctl_table *ctl, int32_t write, void *buffer, \ + size_t *lenp, loff_t *ppos) + +#define QDF_SYSCTL_PROC_DOINTVEC(ctl, write, filp, buffer, lenp, ppos) \ + __QDF_SYSCTL_PROC_DOINTVEC(ctl, write, filp, buffer, lenp, ppos) + +#define QDF_SYSCTL_PROC_DOSTRING(ctl, write, filp, buffer, lenp, ppos) \ + __QDF_SYSCTL_PROC_DOSTRING(ctl, write, filp, buffer, lenp, ppos) + +#define EOK (0) + +#ifndef false +#define false 0 +#endif +#ifndef true +#define true 1 +#endif + +#ifndef ARPHRD_IEEE80211 +#define ARPHRD_IEEE80211 801 /* IEEE 802.11. */ +#endif + +/* + * Normal Delay functions. Time specified in microseconds. + */ +#define OS_DELAY(_us) qdf_udelay(_us) + +/* + * memory data manipulation functions. + */ +#define OS_MEMCPY(_dst, _src, _len) qdf_mem_copy(_dst, _src, _len) +#define OS_MEMMOVE(_dst, _src, _len) qdf_mem_move(_dst, _src, _len) +#define OS_MEMZERO(_buf, _len) qdf_mem_zero(_buf, _len) +#define OS_MEMSET(_buf, _ch, _len) qdf_mem_set(_buf, _len, _ch) +#define OS_MEMCMP(_mem1, _mem2, _len) qdf_mem_cmp(_mem1, _mem2, _len) + + +/* + * System time interface + */ +typedef qdf_time_t systime_t; +typedef qdf_time_t systick_t; + +/** + * os_get_timestamp() - gives the timestamp in ticks + * Return: unsigned long + */ +static inline qdf_time_t os_get_timestamp(void) +{ + /* Fix double conversion from jiffies to ms */ + return qdf_system_ticks(); +} + +struct _NIC_DEV; + +static inline unsigned char *os_malloc(osdev_t nic_dev, + unsigned long size_in_bytes, + int32_t gfp) +{ + return qdf_mem_malloc(size_in_bytes); +} + +#define OS_FREE(_p) qdf_mem_free(_p) + +#define OS_DMA_MEM_CONTEXT(context) \ + dma_addr_t context; + +#define OS_GET_DMA_MEM_CONTEXT(var, field) \ + &(var->field) + +#define OS_COPY_DMA_MEM_CONTEXT(dst, src) \ + *dst = *src + +#define OS_ZERO_DMA_MEM_CONTEXT(context) \ + *context = 0 + +/* + * Timer Interfaces. Use these macros to declare timer + * and retrieve timer argument. This is mainly for resolving + * different argument types for timer function in different OS. + */ +#define os_timer_func(_fn) \ + void _fn(void *timer_arg) + +#define OS_GET_TIMER_ARG(_arg, _type) \ + ((_arg) = (_type)(timer_arg)) + +#define OS_DECLARE_TIMER(_fn) void _fn(void *) + +#define OS_INIT_TIMER(_osdev, _timer, _fn, _ctx, type) \ + qdf_timer_init(_osdev, _timer, _fn, _ctx, type) + +#define OS_SET_TIMER(_timer, _ms) qdf_timer_mod(_timer, _ms) + +#define OS_CANCEL_TIMER(_timer) qdf_timer_stop(_timer) + +#define OS_FREE_TIMER(_timer) qdf_timer_stop(_timer) + +/* + * These are required for network manager support + */ +#ifndef SET_NETDEV_DEV +#define SET_NETDEV_DEV(ndev, pdev) +#endif + +#endif /* end of _OSDEP_H */ diff --git a/drivers/staging/qca-wifi-host-cmn/qdf/inc/qdf_atomic.h b/drivers/staging/qca-wifi-host-cmn/qdf/inc/qdf_atomic.h new file mode 100644 index 0000000000000000000000000000000000000000..39c09d14af81dd4c7c97b7dda57395c1220217ad --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/qdf/inc/qdf_atomic.h @@ -0,0 +1,244 @@ +/* + * Copyright (c) 2014-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: qdf_atomic.h + * This file provides OS abstraction for atomic APIs. + */ + +#ifndef _QDF_ATOMIC_H +#define _QDF_ATOMIC_H + +#include + +/** + * qdf_atomic_t - atomic type of variable + * + * Use this when you want a simple resource counter etc. which is atomic + * across multiple CPU's. These maybe slower than usual counters on some + * platforms/OS'es, so use them with caution. + */ + +typedef __qdf_atomic_t qdf_atomic_t; + +/** + * qdf_atomic_init() - initialize an atomic type variable + * @v: A pointer to an opaque atomic variable + * + * Return: None + */ +static inline QDF_STATUS qdf_atomic_init(qdf_atomic_t *v) +{ + return __qdf_atomic_init(v); +} + +/** + * qdf_atomic_read() - read the value of an atomic variable + * @v: A pointer to an opaque atomic variable + * + * Return: The current value of the variable + */ +static inline int32_t qdf_atomic_read(qdf_atomic_t *v) +{ + return __qdf_atomic_read(v); +} + +/** + * qdf_atomic_inc() - increment the value of an atomic variable + * @v: A pointer to an opaque atomic variable + * + * Return: None + */ +static inline void qdf_atomic_inc(qdf_atomic_t *v) +{ + __qdf_atomic_inc(v); +} + +/** + * qdf_atomic_dec() - decrement the value of an atomic variable + * @v: A pointer to an opaque atomic variable + * + * Return: None + */ +static inline void qdf_atomic_dec(qdf_atomic_t *v) +{ + __qdf_atomic_dec(v); +} + +/** + * qdf_atomic_add() - add a value to the value of an atomic variable + * @i: The amount by which to increase the atomic counter + * @v: A pointer to an opaque atomic variable + * + * Return: None + */ +static inline void qdf_atomic_add(int i, qdf_atomic_t *v) +{ + __qdf_atomic_add(i, v); +} + +/** + * qdf_atomic_sub() - Subtract a value from an atomic variable + * @i: the amount by which to decrease the atomic counter + * @v: a pointer to an opaque atomic variable + * + * Return: none + */ +static inline void qdf_atomic_sub(int i, qdf_atomic_t *v) +{ + __qdf_atomic_sub(i, v); +} + +/** + * qdf_atomic_dec_and_test() - decrement an atomic variable and check if the + * new value is zero + * @v: A pointer to an opaque atomic variable + * + * Return: + * true (non-zero) if the new value is zero, + * false (0) if the new value is non-zero + */ +static inline int32_t qdf_atomic_dec_and_test(qdf_atomic_t *v) +{ + return __qdf_atomic_dec_and_test(v); +} + +/** + * qdf_atomic_set() - set a value to the value of an atomic variable + * @v: A pointer to an opaque atomic variable + * @i: required value to set + * + * Atomically sets the value of v to i + * Return: None + */ +static inline void qdf_atomic_set(qdf_atomic_t *v, int i) +{ + __qdf_atomic_set(v, i); +} + +/** + * qdf_atomic_inc_return() - return the incremented value of an atomic variable + * @v: A pointer to an opaque atomic variable + * + * Return: The current value of the variable + */ +static inline int32_t qdf_atomic_inc_return(qdf_atomic_t *v) +{ + return __qdf_atomic_inc_return(v); +} + +/** + * qdf_atomic_set_bit - Atomically set a bit in memory + * @nr: bit to set + * @addr: the address to start counting from + * + * Return: none + */ +static inline void qdf_atomic_set_bit(int nr, volatile unsigned long *addr) +{ + __qdf_atomic_set_bit(nr, addr); +} + +/** + * qdf_atomic_clear_bit - Atomically clear a bit in memory + * @nr: bit to clear + * @addr: the address to start counting from + * + * Return: none + */ +static inline void qdf_atomic_clear_bit(int nr, volatile unsigned long *addr) +{ + __qdf_atomic_clear_bit(nr, addr); +} + +/** + * qdf_atomic_change_bit - Atomically toggle a bit in memory + * from addr + * @nr: bit to change + * @addr: the address to start counting from + * + * Return: none + */ +static inline void qdf_atomic_change_bit(int nr, volatile unsigned long *addr) +{ + __qdf_atomic_change_bit(nr, addr); +} + +/** + * qdf_atomic_test_and_set_bit - Atomically set a bit and return its old value + * @nr: Bit to set + * @addr: the address to start counting from + * + * Return: return nr bit old value + */ +static inline int qdf_atomic_test_and_set_bit(int nr, + volatile unsigned long *addr) +{ + return __qdf_atomic_test_and_set_bit(nr, addr); +} + +/** + * qdf_atomic_test_and_clear_bit - Atomically clear a bit and return its old + * value + * @nr: bit to clear + * @addr: the address to start counting from + * + * Return: return nr bit old value + */ +static inline int qdf_atomic_test_and_clear_bit(int nr, + volatile unsigned long *addr) +{ + return __qdf_atomic_test_and_clear_bit(nr, addr); +} + +/** + * qdf_atomic_test_and_change_bit - Atomically toggle a bit and return its old + * value + * @nr: bit to change + * @addr: the address to start counting from + * + * Return: return nr bit old value + */ +static inline int qdf_atomic_test_and_change_bit(int nr, + volatile unsigned long *addr) +{ + return __qdf_atomic_test_and_change_bit(nr, addr); +} + +/** + * qdf_atomic_test_bit - Atomically get the nr-th bit value starting from addr + * @nr: bit to get + * @addr: the address to start counting from + * + * Return: return nr bit value + */ +static inline int qdf_atomic_test_bit(int nr, volatile unsigned long *addr) +{ + return __qdf_atomic_test_bit(nr, addr); +} + +#endif diff --git a/drivers/staging/qca-wifi-host-cmn/qdf/inc/qdf_debugfs.h b/drivers/staging/qca-wifi-host-cmn/qdf/inc/qdf_debugfs.h new file mode 100644 index 0000000000000000000000000000000000000000..1babb1f02213cb5d95904a886ae143af429df6b2 --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/qdf/inc/qdf_debugfs.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2017 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. + */ + +/** + * DOC: qdf_debugfs.h + * This file provides OS abstraction for debug filesystem APIs. + */ + +#ifndef _QDF_DEBUGFS_H +#define _QDF_DEBUGFS_H + +#include +#include + +#ifdef WLAN_DEBUGFS +/** + * qdf_debugfs_init() - initialize debugfs + * + * Return: QDF_STATUS + */ +QDF_STATUS qdf_debugfs_init(void); + +/** + * qdf_debugfs_exit() - cleanup debugfs + * + * Return: QDF_STATUS + */ +QDF_STATUS qdf_debugfs_exit(void); + +#else + +static inline QDF_STATUS qdf_debugfs_init(void) +{ + return QDF_STATUS_E_NOSUPPORT; +} + +static inline QDF_STATUS qdf_debugfs_exit(void) +{ + return QDF_STATUS_E_NOSUPPORT; +} + +#endif /* WLAN_DEBUGFS */ +#endif /* _QDF_DEBUGFS_H */ diff --git a/drivers/staging/qca-wifi-host-cmn/qdf/inc/qdf_defer.h b/drivers/staging/qca-wifi-host-cmn/qdf/inc/qdf_defer.h new file mode 100644 index 0000000000000000000000000000000000000000..5e2f6ffa3b2ae5b77ae8ed4c58adacead9b5a51a --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/qdf/inc/qdf_defer.h @@ -0,0 +1,308 @@ +/* + * Copyright (c) 2014-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: qdf_defer.h + * This file abstracts deferred execution API's. + */ + +#ifndef __QDF_DEFER_H +#define __QDF_DEFER_H + +#include +#include + +/** + * TODO This implements work queues (worker threads, kernel threads etc.). + * Note that there is no cancel on a scheduled work. You cannot free a work + * item if its queued. You cannot know if a work item is queued or not unless + * its running, hence you know its not queued. + * + * so if, say, a module is asked to unload itself, how exactly will it make + * sure that the work's not queued, for OS'es that dont provide such a + * mechanism?? + */ + +/* + * Representation of a work queue. + */ +typedef __qdf_work_t qdf_work_t; +typedef __qdf_delayed_work_t qdf_delayed_work_t; +typedef __qdf_workqueue_t qdf_workqueue_t; + +/* + * Representation of a bottom half. + */ +typedef __qdf_bh_t qdf_bh_t; + +/** + * qdf_create_bh - creates the bottom half deferred handler + * @hdl: os handle + * @bh: pointer to bottom + * @func: deferred function to run at bottom half interrupt context. + * @arg: argument for the deferred function + * Return: none + */ +static inline void qdf_create_bh(qdf_handle_t hdl, qdf_bh_t *bh, + qdf_defer_fn_t func, void *arg) +{ + __qdf_init_bh(hdl, bh, func, arg); +} + +/** + * qdf_sched - schedule a bottom half (DPC) + * @hdl: OS handle + * @bh: pointer to bottom + * Return: none + */ +static inline void qdf_sched_bh(qdf_handle_t hdl, qdf_bh_t *bh) +{ + __qdf_sched_bh(hdl, bh); +} + +/** + * qdf_destroy_bh - destroy the bh (synchronous) + * @hdl: OS handle + * @bh: pointer to bottom + * Return: none + */ +static inline void qdf_destroy_bh(qdf_handle_t hdl, qdf_bh_t *bh) +{ + __qdf_disable_bh(hdl, bh); +} + +/*********************Non-Interrupt Context deferred Execution***************/ + +/** + * qdf_create_work - create a work/task queue, This runs in non-interrupt + * context, so can be preempted by H/W & S/W intr + * @hdl: OS handle + * @work: pointer to work + * @func: deferred function to run at bottom half non-interrupt context. + * @arg: argument for the deferred function + * Return: none + */ +static inline void qdf_create_work(qdf_handle_t hdl, qdf_work_t *work, + qdf_defer_fn_t func, void *arg) +{ + __qdf_init_work(hdl, work, func, arg); +} + +/** + * qdf_create_delayed_work - create a delayed work/task, This runs in + * non-interrupt context, so can be preempted by H/W & S/W intr + * @hdl: OS handle + * @work: pointer to work + * @func: deferred function to run at bottom half non-interrupt context. + * @arg: argument for the deferred function + * Return: none + */ +static inline void qdf_create_delayed_work(qdf_handle_t hdl, + qdf_delayed_work_t *work, + qdf_defer_fn_t func, void *arg) +{ + __qdf_init_delayed_work(hdl, work, func, arg); +} + +/** + * qdf_create_workqueue - create a workqueue, This runs in non-interrupt + * context, so can be preempted by H/W & S/W intr + * @name: string + * Return: pointer of type qdf_workqueue_t + */ +static inline qdf_workqueue_t *qdf_create_workqueue(char *name) +{ + return __qdf_create_workqueue(name); +} + +/** + * qdf_queue_work - Queue the work/task + * @hdl: OS handle + * @wqueue: pointer to workqueue + * @work: pointer to work + * Return: none + */ +static inline void +qdf_queue_work(qdf_handle_t hdl, qdf_workqueue_t *wqueue, qdf_work_t *work) +{ + return __qdf_queue_work(hdl, wqueue, work); +} + +/** + * qdf_queue_delayed_work - Queue the delayed work/task + * @hdl: OS handle + * @wqueue: pointer to workqueue + * @work: pointer to work + * @delay: delay interval + * Return: none + */ +static inline void qdf_queue_delayed_work(qdf_handle_t hdl, + qdf_workqueue_t *wqueue, + qdf_delayed_work_t *work, + uint32_t delay) +{ + return __qdf_queue_delayed_work(hdl, wqueue, work, delay); +} + +/** + * qdf_flush_workqueue - flush the workqueue + * @hdl: OS handle + * @wqueue: pointer to workqueue + * Return: none + */ +static inline void qdf_flush_workqueue(qdf_handle_t hdl, + qdf_workqueue_t *wqueue) +{ + return __qdf_flush_workqueue(hdl, wqueue); +} + +/** + * qdf_destroy_workqueue - Destroy the workqueue + * @hdl: OS handle + * @wqueue: pointer to workqueue + * Return: none + */ +static inline void qdf_destroy_workqueue(qdf_handle_t hdl, + qdf_workqueue_t *wqueue) +{ + return __qdf_destroy_workqueue(hdl, wqueue); +} + +/** + * qdf_sched_work - Schedule a deferred task on non-interrupt context + * @hdl: OS handle + * @work: pointer to work + * Retrun: none + */ +static inline void qdf_sched_work(qdf_handle_t hdl, qdf_work_t *work) +{ + __qdf_sched_work(hdl, work); +} + +/** + * qdf_sched_delayed_work() - Schedule a delayed task + * @hdl: OS handle + * @work: pointer to delayed work + * @delay: delay interval + * Return: none + */ +static inline void qdf_sched_delayed_work(qdf_handle_t hdl, + qdf_delayed_work_t *work, + uint32_t delay) +{ + __qdf_sched_delayed_work(hdl, work, delay); +} + +/** + * qdf_cancel_work() - Cancel a work + * @hdl: OS handle + * @work: pointer to work + * + * Cancel work and wait for its execution to finish. + * This function can be used even if the work re-queues + * itself or migrates to another workqueue. On return + * from this function, work is guaranteed to be not + * pending or executing on any CPU. The caller must + * ensure that the workqueue on which work was last + * queued can't be destroyed before this function returns. + * + * Return: true if work was pending, false otherwise + */ +static inline bool qdf_cancel_work(qdf_handle_t hdl, + qdf_work_t *work) +{ + return __qdf_cancel_work(hdl, work); +} + +/** + * qdf_cancel_delayed_work() - Cancel a delayed work + * @hdl: OS handle + * @work: pointer to delayed work + * + * This is qdf_cancel_work for delayed works. + * + * Return: true if work was pending, false otherwise + */ +static inline bool qdf_cancel_delayed_work(qdf_handle_t hdl, + qdf_delayed_work_t *work) +{ + return __qdf_cancel_delayed_work(hdl, work); +} + +/** + * qdf_flush_work - Flush a deferred task on non-interrupt context + * @hdl: OS handle + * @work: pointer to work + * + * Wait until work has finished execution. work is guaranteed to be + * idle on return if it hasn't been requeued since flush started. + * + * Return: none + */ +static inline void qdf_flush_work(qdf_handle_t hdl, qdf_work_t *work) +{ + __qdf_flush_work(hdl, work); +} + +/** + * qdf_flush_delayed_work() - Flush a delayed work + * @hdl: OS handle + * @work: pointer to delayed work + * + * This is qdf_flush_work for delayed works. + * + * Return: none + */ +static inline void qdf_flush_delayed_work(qdf_handle_t hdl, + qdf_delayed_work_t *work) +{ + __qdf_flush_delayed_work(hdl, work); +} + +/** + * qdf_disable_work - disable the deferred task (synchronous) + * @hdl: OS handle + * @work: pointer to work + * Return: unsigned int + */ +static inline uint32_t qdf_disable_work(qdf_handle_t hdl, qdf_work_t *work) +{ + return __qdf_disable_work(hdl, work); +} + +/** + * qdf_destroy_work - destroy the deferred task (synchronous) + * @hdl: OS handle + * @work: pointer to work + * Return: none + */ +static inline void qdf_destroy_work(qdf_handle_t hdl, qdf_work_t *work) +{ + __qdf_disable_work(hdl, work); +} + +#endif /*_QDF_DEFER_H*/ diff --git a/drivers/staging/qca-wifi-host-cmn/qdf/inc/qdf_event.h b/drivers/staging/qca-wifi-host-cmn/qdf/inc/qdf_event.h new file mode 100644 index 0000000000000000000000000000000000000000..4825cd238112129739cd4d147c45006c1e6c93dd --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/qdf/inc/qdf_event.h @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2014-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: qdf_event.h + * This file provides OS abstraction for event APIs. + */ + +#if !defined(__QDF_EVENT_H) +#define __QDF_EVENT_H + +/* Include Files */ +#include "qdf_status.h" +#include +#include +#include + +/* Preprocessor definitions and constants */ +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +typedef __qdf_event_t qdf_event_t; +/* Function declarations and documenation */ + +QDF_STATUS qdf_event_create(qdf_event_t *event); + +QDF_STATUS qdf_event_set(qdf_event_t *event); + +QDF_STATUS qdf_event_reset(qdf_event_t *event); + +QDF_STATUS qdf_event_destroy(qdf_event_t *event); + +QDF_STATUS qdf_wait_single_event(qdf_event_t *event, + uint32_t timeout); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* __QDF_EVENT_H */ diff --git a/drivers/staging/qca-wifi-host-cmn/qdf/inc/qdf_list.h b/drivers/staging/qca-wifi-host-cmn/qdf/inc/qdf_list.h new file mode 100644 index 0000000000000000000000000000000000000000..171bb3270d3fe83733ff7bcf0b4efd62424efbf2 --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/qdf/inc/qdf_list.h @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2014-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + + +/** + * DOC: qdf_list.h + * QCA driver framework (QDF) list APIs + * Definitions for QDF Linked Lists API + * + * Lists are implemented as a doubly linked list. An item in a list can + * be of any type as long as the datatype contains a field of type + * qdf_link_t. + * + * In general, a list is a doubly linked list of items with a pointer + * to the front of the list and a pointer to the end of the list. The + * list items contain a forward and back link. + * + * QDF linked list APIs are NOT thread safe so make sure to use appropriate + * locking mechanisms to assure operations on the list are thread safe. + */ + +#if !defined(__QDF_LIST_H) +#define __QDF_LIST_H + +/* Include Files */ +#include +#include +#include +#include + +typedef __qdf_list_node_t qdf_list_node_t; +typedef __qdf_list_t qdf_list_t; +/* Function declarations */ +QDF_STATUS qdf_list_insert_front(qdf_list_t *list, qdf_list_node_t *node); + +QDF_STATUS qdf_list_insert_back_size(qdf_list_t *list, qdf_list_node_t *node, + uint32_t *size); + +QDF_STATUS qdf_list_remove_front(qdf_list_t *list, qdf_list_node_t **node1); + +QDF_STATUS qdf_list_peek_next(qdf_list_t *list, qdf_list_node_t *node, + qdf_list_node_t **node1); + +/** + * qdf_list_create() - Initialize list head + * @list: object of list + * @max_size: max size of the list + * Return: none + */ +static inline void qdf_list_create(__qdf_list_t *list, uint32_t max_size) +{ + __qdf_list_create(list, max_size); +} + + +/** + * qdf_list_destroy() - Destroy the list + * @list: object of list + * Return: none + */ +static inline void qdf_list_destroy(qdf_list_t *list) +{ + if (list->count != 0) { + QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR, + "%s: list length not equal to zero", __func__); + QDF_ASSERT(0); + } +} + +/** + * qdf_list_size() - gives the size of the list + * @list: object of list + * @size: size of the list + * Return: uint32_t + */ +static inline uint32_t qdf_list_size(qdf_list_t *list) +{ + return list->count; +} + +QDF_STATUS qdf_list_insert_back(qdf_list_t *list, qdf_list_node_t *node); + +QDF_STATUS qdf_list_remove_back(qdf_list_t *list, qdf_list_node_t **node1); + +QDF_STATUS qdf_list_peek_front(qdf_list_t *list, qdf_list_node_t **node1); + +QDF_STATUS qdf_list_remove_node(qdf_list_t *list, + qdf_list_node_t *node_to_remove); + +bool qdf_list_empty(qdf_list_t *list); + +#endif /* __QDF_LIST_H */ diff --git a/drivers/staging/qca-wifi-host-cmn/qdf/inc/qdf_lock.h b/drivers/staging/qca-wifi-host-cmn/qdf/inc/qdf_lock.h new file mode 100644 index 0000000000000000000000000000000000000000..915f66ad6d2e98f59cf5998589fc6aa349d9b10e --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/qdf/inc/qdf_lock.h @@ -0,0 +1,509 @@ +/* + * Copyright (c) 2014-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * @file qdf_lock.h + * This file abstracts locking operations. + */ + +#ifndef _QDF_LOCK_H +#define _QDF_LOCK_H + +#include +#include +#include +#include + +#ifndef QDF_LOCK_STATS +#define QDF_LOCK_STATS 0 +#endif +#ifndef QDF_LOCK_STATS_DESTROY_PRINT +#define QDF_LOCK_STATS_DESTROY_PRINT 0 +#endif +#ifndef QDF_LOCK_STATS_BUG_ON +#define QDF_LOCK_STATS_BUG_ON 0 +#endif +#ifndef QDF_LOCK_STATS_LIST +#define QDF_LOCK_STATS_LIST 0 +#endif + +#define QDF_MAX_HOLD_TIME_ALOWED_SPINLOCK_IRQ 1000 +#define QDF_MAX_HOLD_TIME_ALOWED_SPINLOCK_BH 5000 +#define QDF_MAX_HOLD_TIME_ALOWED_SPINLOCK 5000 + +#if !QDF_LOCK_STATS +struct lock_stats {}; +#define BEFORE_LOCK(x...) do {} while (0) +#define AFTER_LOCK(x...) do {} while (0) +#define BEFORE_TRYLOCK(x...) do {} while (0) +#define AFTER_TRYLOCK(x...) do {} while (0) +#define BEFORE_UNLOCK(x...) do {} while (0) +#define qdf_lock_stats_create(x...) do {} while (0) +#define qdf_lock_stats_destroy(x...) do {} while (0) +#define qdf_lock_stats_init(x...) do {} while (0) +#define qdf_lock_stats_deinit(x...) do {} while (0) +#else +void qdf_lock_stats_init(void); +void qdf_lock_stats_deinit(void); +struct qdf_lock_cookie; +struct lock_stats { + const char *initialization_fn; + const char *acquired_by; + int line; + int acquired; + int contended; + uint64_t contention_time; + uint64_t non_contention_time; + uint64_t held_time; + uint64_t last_acquired; + uint64_t max_contention_wait; + uint64_t max_held_time; + int num_large_contentions; + int num_large_holds; + struct qdf_lock_cookie *cookie; +}; +#define LARGE_CONTENTION QDF_LOG_TIMESTAMP_CYCLES_PER_10_US + +#define BEFORE_LOCK(lock, was_locked) \ +do { \ + uint64_t BEFORE_LOCK_time; \ + uint64_t AFTER_LOCK_time; \ + bool BEFORE_LOCK_is_locked = was_locked; \ + BEFORE_LOCK_time = qdf_get_log_timestamp(); \ + do {} while (0) + + +#define AFTER_LOCK(lock, func) \ + lock->stats.acquired_by = func; \ + AFTER_LOCK_time = qdf_get_log_timestamp(); \ + lock->stats.acquired++; \ + lock->stats.last_acquired = AFTER_LOCK_time; \ + if (BEFORE_LOCK_is_locked) { \ + lock->stats.contended++; \ + lock->stats.contention_time += \ + (AFTER_LOCK_time - BEFORE_LOCK_time); \ + } else { \ + lock->stats.non_contention_time += \ + (AFTER_LOCK_time - BEFORE_LOCK_time); \ + } \ +\ + if (AFTER_LOCK_time - BEFORE_LOCK_time > LARGE_CONTENTION) \ + lock->stats.num_large_contentions++; \ +\ + if (AFTER_LOCK_time - BEFORE_LOCK_time > \ + lock->stats.max_contention_wait) \ + lock->stats.max_contention_wait = \ + AFTER_LOCK_time - BEFORE_LOCK_time; \ +} while (0) + +#define BEFORE_TRYLOCK(lock) \ +do { \ + uint64_t BEFORE_LOCK_time; \ + uint64_t AFTER_LOCK_time; \ + BEFORE_LOCK_time = qdf_get_log_timestamp(); \ + do {} while (0) + +#define AFTER_TRYLOCK(lock, trylock_return, func) \ + AFTER_LOCK_time = qdf_get_log_timestamp(); \ + if (trylock_return) { \ + lock->stats.acquired++; \ + lock->stats.last_acquired = AFTER_LOCK_time; \ + lock->stats.non_contention_time += \ + (AFTER_LOCK_time - BEFORE_LOCK_time); \ + lock->stats.acquired_by = func; \ + } \ +} while (0) + +/* max_hold_time in US */ +#define BEFORE_UNLOCK(lock, max_hold_time) \ +do {\ + uint64_t held_time = qdf_get_log_timestamp() - \ + lock->stats.last_acquired; \ + lock->stats.held_time += held_time; \ +\ + if (held_time > lock->stats.max_held_time) \ + lock->stats.max_held_time = held_time; \ +\ + if (held_time > LARGE_CONTENTION) \ + lock->stats.num_large_holds++; \ + if (QDF_LOCK_STATS_BUG_ON && max_hold_time && \ + held_time > qdf_usecs_to_log_timestamp(max_hold_time)) { \ + qdf_print("BEFORE_UNLOCK: lock held too long (%lluus)\n", \ + qdf_log_timestamp_to_usecs(held_time)); \ + QDF_BUG(0); \ + } \ + lock->stats.acquired_by = NULL; \ +} while (0) + +void qdf_lock_stats_cookie_destroy(struct lock_stats *stats); +void qdf_lock_stats_cookie_create(struct lock_stats *stats, + const char *func, int line); + +static inline void qdf_lock_stats_destroy(struct lock_stats *stats) +{ + if (QDF_LOCK_STATS_DESTROY_PRINT) { + qdf_print("%s: lock: %s %d \t" + "acquired:\t%d\tcontended:\t%d\t" + "contention_time\t%llu\tmax_contention_wait:\t%llu\t" + "non_contention_time\t%llu\t" + "held_time\t%llu\tmax_held:\t%llu\t\n" + , __func__, stats->initialization_fn, stats->line, + stats->acquired, stats->contended, + qdf_log_timestamp_to_usecs(stats->contention_time), + qdf_log_timestamp_to_usecs(stats->max_contention_wait), + qdf_log_timestamp_to_usecs(stats->non_contention_time), + qdf_log_timestamp_to_usecs(stats->held_time), + qdf_log_timestamp_to_usecs(stats->max_held_time)); + } + + if (QDF_LOCK_STATS_LIST) + qdf_lock_stats_cookie_destroy(stats); +} + +#ifndef MEMORY_DEBUG +#define qdf_mem_malloc_debug(x, y, z) qdf_mem_malloc(x) +#endif + +/* qdf_lock_stats_create() - initialize the lock stats structure + * + */ +static inline void qdf_lock_stats_create(struct lock_stats *stats, + const char *func, int line) +{ + qdf_mem_zero(stats, sizeof(*stats)); + stats->initialization_fn = func; + stats->line = line; + + if (QDF_LOCK_STATS_LIST) + qdf_lock_stats_cookie_create(stats, func, line); +} +#endif + +#include + +#define WIFI_POWER_EVENT_DEFAULT_WAKELOCK_TIMEOUT 0 +#define WIFI_POWER_EVENT_WAKELOCK_TAKEN 0 +#define WIFI_POWER_EVENT_WAKELOCK_RELEASED 1 + +/** + * qdf_semaphore_acquire_timeout() - Take the semaphore before timeout + * @m: semaphore to take + * @timeout: maximum time to try to take the semaphore + * Return: int + */ +static inline int qdf_semaphore_acquire_timeout(struct semaphore *m, + unsigned long timeout) +{ + return __qdf_semaphore_acquire_timeout(m, timeout); +} + +struct qdf_spinlock { + __qdf_spinlock_t lock; + struct lock_stats stats; +}; + +/** + * @brief Platform spinlock object + */ +typedef struct qdf_spinlock qdf_spinlock_t; + + +/** + * @brief Platform mutex object + */ +typedef __qdf_semaphore_t qdf_semaphore_t; +typedef __qdf_mutex_t qdf_mutex_t; + +/* function Declaration */ +QDF_STATUS qdf_mutex_create(qdf_mutex_t *m, const char *func, int line); +#define qdf_mutex_create(m) qdf_mutex_create(m, __func__, __LINE__) + +QDF_STATUS qdf_mutex_acquire(qdf_mutex_t *m); + +QDF_STATUS qdf_mutex_release(qdf_mutex_t *m); + +QDF_STATUS qdf_mutex_destroy(qdf_mutex_t *lock); + +/** + * qdf_spinlock_create - Initialize a spinlock + * @lock: spinlock object pointer + * Return: none + */ +static inline void qdf_spinlock_create(qdf_spinlock_t *lock, const char *func, + int line) +{ + __qdf_spinlock_create(&lock->lock); + + /* spinlock stats create relies on the spinlock working allread */ + qdf_lock_stats_create(&lock->stats, func, line); +} + +#define qdf_spinlock_create(x) qdf_spinlock_create(x, __func__, __LINE__) + +/** + * qdf_spinlock_destroy - Delete a spinlock + * @lock: spinlock object pointer + * Return: none + */ +static inline void qdf_spinlock_destroy(qdf_spinlock_t *lock) +{ + qdf_lock_stats_destroy(&lock->stats); + __qdf_spinlock_destroy(&lock->lock); +} + +/** + * qdf_spin_is_locked() - check if the spinlock is locked + * @lock: spinlock object + * + * Return: nonzero if lock is held. + */ +static inline int qdf_spin_is_locked(qdf_spinlock_t *lock) +{ + return __qdf_spin_is_locked(&lock->lock); +} + +/** + * qdf_spin_trylock_bh() - spin trylock bottomhalf + * @lock: spinlock object + * + * Return: nonzero if lock is acquired + */ +static inline int qdf_spin_trylock_bh(qdf_spinlock_t *lock, const char *func) +{ + int trylock_return; + BEFORE_TRYLOCK(lock); + trylock_return = __qdf_spin_trylock_bh(&lock->lock); + AFTER_TRYLOCK(lock, trylock_return, func); + + return trylock_return; +} +#define qdf_spin_trylock_bh(lock) qdf_spin_trylock_bh(lock, __func__) + +int qdf_spin_trylock_bh_outline(qdf_spinlock_t *lock); + +/** + * qdf_spin_lock_bh() - locks the spinlock mutex in soft irq context + * @lock: spinlock object pointer + * Return: none + */ +static inline void qdf_spin_lock_bh(qdf_spinlock_t *lock, const char *func) +{ + BEFORE_LOCK(lock, qdf_spin_is_locked(lock)); + __qdf_spin_lock_bh(&lock->lock); + AFTER_LOCK(lock, func); +} + +#define qdf_spin_lock_bh(lock) qdf_spin_lock_bh(lock, __func__) + +void qdf_spin_lock_bh_outline(qdf_spinlock_t *lock); + +/** + * qdf_spin_unlock_bh() - unlocks the spinlock mutex in soft irq context + * @lock: spinlock object pointer + * Return: none + */ +static inline void qdf_spin_unlock_bh(qdf_spinlock_t *lock) +{ + BEFORE_UNLOCK(lock, QDF_MAX_HOLD_TIME_ALOWED_SPINLOCK_BH); + __qdf_spin_unlock_bh(&lock->lock); +} + +void qdf_spin_unlock_bh_outline(qdf_spinlock_t *lock); + +/** + * qdf_spinlock_irq_exec - Execute the input function with spinlock held + * and interrupt disabled. + * @hdl: OS handle + * @lock: spinlock to be held for the critical region + * @func: critical region function that to be executed + * @context: context of the critical region function + * Return: Boolean status returned by the critical region function + */ +static inline bool qdf_spinlock_irq_exec(qdf_handle_t hdl, + qdf_spinlock_t *lock, + qdf_irqlocked_func_t func, void *arg) +{ + return __qdf_spinlock_irq_exec(hdl, &lock->lock, func, arg); +} + +/** + * qdf_spin_lock() - Acquire a Spinlock(SMP) & disable Preemption (Preemptive) + * @lock: Lock object + * + * Return: none + */ +static inline void qdf_spin_lock(qdf_spinlock_t *lock, const char *func) +{ + BEFORE_LOCK(lock, qdf_spin_is_locked(lock)); + __qdf_spin_lock(&lock->lock); + AFTER_LOCK(lock, func); +} +#define qdf_spin_lock(lock) qdf_spin_lock(lock, __func__) + +/** + * qdf_spin_unlock() - Unlock the spinlock and enables the Preemption + * @lock: Lock object + * + * Return: none + */ +static inline void qdf_spin_unlock(qdf_spinlock_t *lock) +{ + BEFORE_UNLOCK(lock, QDF_MAX_HOLD_TIME_ALOWED_SPINLOCK); + __qdf_spin_unlock(&lock->lock); +} + +/** + * qdf_spin_lock_irq() - Acquire a Spinlock(SMP) & save the irq state + * @lock: Lock object + * @flags: flags + * + * Return: none + */ +static inline void qdf_spin_lock_irq(qdf_spinlock_t *lock, unsigned long flags, + const char *func) +{ + BEFORE_LOCK(lock, qdf_spin_is_locked(lock)); + __qdf_spin_lock_irq(&lock->lock.spinlock, flags); + AFTER_LOCK(lock, func); +} +#define qdf_spin_lock_irq(lock, flags) qdf_spin_lock_irq(lock, flags, __func__) + +/** + * qdf_spin_lock_irqsave() - Acquire a Spinlock (SMP) & disable Preemption + * (Preemptive) and disable IRQs + * @lock: Lock object + * + * Return: none + */ +static inline void qdf_spin_lock_irqsave(qdf_spinlock_t *lock, const char *func) +{ + BEFORE_LOCK(lock, qdf_spin_is_locked(lock)); + __qdf_spin_lock_irqsave(&lock->lock); + AFTER_LOCK(lock, func); +} +#define qdf_spin_lock_irqsave(lock) qdf_spin_lock_irqsave(lock, __func__) + +/** + * qdf_spin_unlock_irqrestore() - Unlock the spinlock and enables the + * Preemption and enable IRQ + * @lock: Lock object + * + * Return: none + */ +static inline void qdf_spin_unlock_irqrestore(qdf_spinlock_t *lock) +{ + BEFORE_UNLOCK(lock, QDF_MAX_HOLD_TIME_ALOWED_SPINLOCK_IRQ); + __qdf_spin_unlock_irqrestore(&lock->lock); +} + +/** + * qdf_spin_unlock_irq() - Unlock a Spinlock(SMP) & save the restore state + * @lock: Lock object + * @flags: flags + * + * Return: none + */ +static inline void qdf_spin_unlock_irq(qdf_spinlock_t *lock, + unsigned long flags) +{ + BEFORE_UNLOCK(lock, QDF_MAX_HOLD_TIME_ALOWED_SPINLOCK_IRQ); + __qdf_spin_unlock_irq(&lock->lock.spinlock, flags); +} + +/** + * qdf_semaphore_init() - initialize a semaphore + * @m: Semaphore to initialize + * Return: None + */ +static inline void qdf_semaphore_init(qdf_semaphore_t *m) +{ + __qdf_semaphore_init(m); +} + +/** + * qdf_semaphore_acquire() - take the semaphore + * @m: Semaphore to take + * Return: int + */ +static inline int qdf_semaphore_acquire(qdf_semaphore_t *m) +{ + return __qdf_semaphore_acquire(m); +} + +/** + * qdf_semaphore_release() - give the semaphore + * @m: Semaphore to give + * Return: None + */ +static inline void qdf_semaphore_release(qdf_semaphore_t *m) +{ + __qdf_semaphore_release(m); +} + +/** + * qdf_semaphore_acquire_intr - Take the semaphore, interruptible version + * @osdev: OS Device + * @m: mutex to take + * Return: int + */ +static inline int qdf_semaphore_acquire_intr(qdf_semaphore_t *m) +{ + return __qdf_semaphore_acquire_intr(m); +} + +QDF_STATUS qdf_wake_lock_create(qdf_wake_lock_t *lock, const char *name); + +QDF_STATUS qdf_wake_lock_acquire(qdf_wake_lock_t *lock, uint32_t reason); + +const char *qdf_wake_lock_name(qdf_wake_lock_t *lock); +QDF_STATUS qdf_wake_lock_timeout_acquire(qdf_wake_lock_t *lock, + uint32_t msec); + +QDF_STATUS qdf_wake_lock_release(qdf_wake_lock_t *lock, uint32_t reason); + +QDF_STATUS qdf_wake_lock_destroy(qdf_wake_lock_t *lock); + +struct hif_pm_runtime_lock; +typedef struct qdf_runtime_lock { + struct hif_pm_runtime_lock *lock; +} qdf_runtime_lock_t; + +QDF_STATUS qdf_runtime_pm_get(void); +QDF_STATUS qdf_runtime_pm_put(void); +QDF_STATUS qdf_runtime_pm_prevent_suspend(qdf_runtime_lock_t *lock); +QDF_STATUS qdf_runtime_pm_allow_suspend(qdf_runtime_lock_t *lock); + +QDF_STATUS __qdf_runtime_lock_init(qdf_runtime_lock_t *lock, const char *name); + +#define qdf_runtime_lock_init(lock) __qdf_runtime_lock_init(lock, #lock) + +void qdf_runtime_lock_deinit(qdf_runtime_lock_t *lock); + +QDF_STATUS qdf_spinlock_acquire(qdf_spinlock_t *lock); + +QDF_STATUS qdf_spinlock_release(qdf_spinlock_t *lock); +#endif /* _QDF_LOCK_H */ diff --git a/drivers/staging/qca-wifi-host-cmn/qdf/inc/qdf_mc_timer.h b/drivers/staging/qca-wifi-host-cmn/qdf/inc/qdf_mc_timer.h new file mode 100644 index 0000000000000000000000000000000000000000..9f5d99edf32c9d1edda6256e6533fccd9c3605af --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/qdf/inc/qdf_mc_timer.h @@ -0,0 +1,287 @@ +/* + * Copyright (c) 2014-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: qdf_mc_timer + * QCA driver framework timer APIs serialized to MC thread + */ + +#if !defined(__QDF_MC_TIMER_H) +#define __QDF_MC_TIMER_H + +/* Include Files */ +#include +#include +#include +#include + +#ifdef TIMER_MANAGER +#include +#endif + +/* Preprocessor definitions and constants */ +#define QDF_TIMER_STATE_COOKIE (0x12) +#define QDF_MC_TIMER_TO_MS_UNIT (1000) +#define QDF_MC_TIMER_TO_SEC_UNIT (1000000) + +/* Type declarations */ +/* qdf Timer callback function prototype (well, actually a prototype for + a pointer to this callback function) */ +typedef void (*qdf_mc_timer_callback_t)(void *user_data); + +typedef enum { + QDF_TIMER_STATE_UNUSED = QDF_TIMER_STATE_COOKIE, + QDF_TIMER_STATE_STOPPED, + QDF_TIMER_STATE_STARTING, + QDF_TIMER_STATE_RUNNING, +} QDF_TIMER_STATE; + +#ifdef TIMER_MANAGER +struct qdf_mc_timer_s; +typedef struct qdf_mc_timer_node_s { + qdf_list_node_t node; + char *file_name; + unsigned int line_num; + struct qdf_mc_timer_s *qdf_timer; +} qdf_mc_timer_node_t; +#endif + +typedef struct qdf_mc_timer_s { +#ifdef TIMER_MANAGER + qdf_mc_timer_node_t *timer_node; +#endif + qdf_mc_timer_platform_t platform_info; + qdf_mc_timer_callback_t callback; + void *user_data; + qdf_mutex_t lock; + QDF_TIMER_TYPE type; + QDF_TIMER_STATE state; +} qdf_mc_timer_t; + + +void qdf_try_allowing_sleep(QDF_TIMER_TYPE type); + +/* Function declarations and documenation */ +#ifdef TIMER_MANAGER +void qdf_mc_timer_manager_init(void); +void qdf_mc_timer_manager_exit(void); +#else +/** + * qdf_mc_timer_manager_init() - initialize QDF debug timer manager + * This API initializes QDF timer debug functionality. + * + * Return: none + */ +static inline void qdf_mc_timer_manager_init(void) +{ +} + +/** + * qdf_mc_timer_manager_exit() - exit QDF timer debug functionality + * This API exists QDF timer debug functionality + * + * Return: none + */ +static inline void qdf_mc_timer_manager_exit(void) +{ +} +#endif +/** + * qdf_mc_timer_get_current_state() - get the current state of the timer + * @timer: Pointer to timer object + * + * Return: + * QDF_TIMER_STATE - qdf timer state + */ + +QDF_TIMER_STATE qdf_mc_timer_get_current_state(qdf_mc_timer_t *timer); + +/** + * qdf_mc_timer_init() - initialize a QDF timer + * @timer: Pointer to timer object + * @timer_type: Type of timer + * @callback: Callback to be called after timer expiry + * @ser_data: User data which will be passed to callback function + * + * This API initializes a QDF Timer object. + * + * qdf_mc_timer_init() initializes a QDF Timer object. A timer must be + * initialized by calling qdf_mc_timer_initialize() before it may be used in + * any other timer functions. + * + * Attempting to initialize timer that is already initialized results in + * a failure. A destroyed timer object can be re-initialized with a call to + * qdf_mc_timer_init(). The results of otherwise referencing the object + * after it has been destroyed are undefined. + * + * Calls to QDF timer functions to manipulate the timer such + * as qdf_mc_timer_set() will fail if the timer is not initialized or has + * been destroyed. Therefore, don't use the timer after it has been + * destroyed until it has been re-initialized. + * + * All callback will be executed within the CDS main thread unless it is + * initialized from the Tx thread flow, in which case it will be executed + * within the tx thread flow. + * + * Return: + * QDF_STATUS_SUCCESS - Timer is initialized successfully + * QDF failure status - Timer initialization failed + */ +#ifdef TIMER_MANAGER +#define qdf_mc_timer_init(timer, timer_type, callback, userdata) \ + qdf_mc_timer_init_debug(timer, timer_type, callback, userdata, \ + __FILE__, __LINE__) + +QDF_STATUS qdf_mc_timer_init_debug(qdf_mc_timer_t *timer, + QDF_TIMER_TYPE timer_type, + qdf_mc_timer_callback_t callback, + void *user_data, char *file_name, + uint32_t line_num); +#else +QDF_STATUS qdf_mc_timer_init(qdf_mc_timer_t *timer, QDF_TIMER_TYPE timer_type, + qdf_mc_timer_callback_t callback, + void *user_data); +#endif + +/** + * qdf_mc_timer_destroy() - destroy QDF timer + * @timer: Pointer to timer object + * + * qdf_mc_timer_destroy() function shall destroy the timer object. + * After a successful return from \a qdf_mc_timer_destroy() the timer + * object becomes, in effect, uninitialized. + * + * A destroyed timer object can be re-initialized by calling + * qdf_mc_timer_init(). The results of otherwise referencing the object + * after it has been destroyed are undefined. + * + * Calls to QDF timer functions to manipulate the timer, such + * as qdf_mc_timer_set() will fail if the lock is destroyed. Therefore, + * don't use the timer after it has been destroyed until it has + * been re-initialized. + * + * Return: + * QDF_STATUS_SUCCESS - Timer is initialized successfully + * QDF failure status - Timer initialization failed + */ +QDF_STATUS qdf_mc_timer_destroy(qdf_mc_timer_t *timer); + +/** + * qdf_mc_timer_start() - start a QDF Timer object + * @timer: Pointer to timer object + * @expiration_time: Time to expire + * + * qdf_mc_timer_start() function starts a timer to expire after the + * specified interval, thus running the timer callback function when + * the interval expires. + * + * A timer only runs once (a one-shot timer). To re-start the + * timer, qdf_mc_timer_start() has to be called after the timer runs + * or has been cancelled. + * + * Return: + * QDF_STATUS_SUCCESS - Timer is initialized successfully + * QDF failure status - Timer initialization failed + */ +QDF_STATUS qdf_mc_timer_start(qdf_mc_timer_t *timer, uint32_t expiration_time); + +/** + * qdf_mc_timer_stop() - stop a QDF Timer + * @timer: Pointer to timer object + * qdf_mc_timer_stop() function stops a timer that has been started but + * has not expired, essentially cancelling the 'start' request. + * + * After a timer is stopped, it goes back to the state it was in after it + * was created and can be started again via a call to qdf_mc_timer_start(). + * + * Return: + * QDF_STATUS_SUCCESS - Timer is initialized successfully + * QDF failure status - Timer initialization failed + */ +QDF_STATUS qdf_mc_timer_stop(qdf_mc_timer_t *timer); + +/** + * qdf_mc_timer_get_system_ticks() - get the system time in 10ms ticks + * + * qdf_mc_timer_get_system_ticks() function returns the current number + * of timer ticks in 10msec intervals. This function is suitable timestamping + * and calculating time intervals by calculating the difference between two + * timestamps. + * + * Return: + * The current system tick count (in 10msec intervals). This + * function cannot fail. + */ +unsigned long qdf_mc_timer_get_system_ticks(void); + +/** + * qdf_mc_timer_get_system_time() - Get the system time in milliseconds + * + * qdf_mc_timer_get_system_time() function returns the number of milliseconds + * that have elapsed since the system was started + * + * Return: + * The current system time in milliseconds + */ +unsigned long qdf_mc_timer_get_system_time(void); + +/** + * qdf_get_monotonic_boottime_ns() - Get kernel boottime in ns + * + * Return: kernel boottime in nano sec + */ +s64 qdf_get_monotonic_boottime_ns(void); + +/** + * qdf_timer_module_init() - initializes a QDF timer module. + * + * This API initializes the QDF timer module. This needs to be called + * exactly once prior to using any QDF timers. + * + * Return: none + */ +void qdf_timer_module_init(void); + +/** + * qdf_timer_module_deinit() - Deinitializes a QDF timer module. + * + * This API deinitializes the QDF timer module. + * Return: none + */ +void qdf_timer_module_deinit(void); + +/** + * qdf_get_time_of_the_day_in_hr_min_sec_usec() - Get system time + * @tbuf: Pointer to time stamp buffer + * @len: Time buffer size + * + * This function updates the 'tbuf' with system time in hr:min:sec:msec format + * + * Return: None + */ +void qdf_get_time_of_the_day_in_hr_min_sec_usec(char *tbuf, int len); +#endif /* __QDF_MC_TIMER_H */ diff --git a/drivers/staging/qca-wifi-host-cmn/qdf/inc/qdf_mem.h b/drivers/staging/qca-wifi-host-cmn/qdf/inc/qdf_mem.h new file mode 100644 index 0000000000000000000000000000000000000000..35b7b66bfe8e3b27e90bc5ff3cc14189750d494e --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/qdf/inc/qdf_mem.h @@ -0,0 +1,303 @@ +/* + * Copyright (c) 2014-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: qdf_mem + * QCA driver framework (QDF) memory management APIs + */ + +#if !defined(__QDF_MEMORY_H) +#define __QDF_MEMORY_H + +/* Include Files */ +#include +#include + +/** + * struct qdf_mem_dma_page_t - Allocated dmaable page + * @page_v_addr_start: Page start virtual address + * @page_v_addr_end: Page end virtual address + * @page_p_addr: Page start physical address + */ +struct qdf_mem_dma_page_t { + char *page_v_addr_start; + char *page_v_addr_end; + qdf_dma_addr_t page_p_addr; +}; + +/** + * struct qdf_mem_multi_page_t - multiple page allocation information storage + * @num_element_per_page: Number of element in single page + * @num_pages: Number of allocation needed pages + * @dma_pages: page information storage in case of coherent memory + * @cacheable_pages: page information storage in case of cacheable memory + */ +struct qdf_mem_multi_page_t { + uint16_t num_element_per_page; + uint16_t num_pages; + struct qdf_mem_dma_page_t *dma_pages; + void **cacheable_pages; +}; + + +/* Preprocessor definitions and constants */ + +typedef __qdf_mempool_t qdf_mempool_t; +#ifdef MEMORY_DEBUG +void qdf_mem_clean(void); + +void qdf_mem_init(void); + +void qdf_mem_exit(void); + +#else +/** + * qdf_mem_init() - initialize qdf memory debug functionality + * + * Return: none + */ +static inline void qdf_mem_init(void) +{ +} + +/** + * qdf_mem_exit() - exit qdf memory debug functionality + * + * Return: none + */ +static inline void qdf_mem_exit(void) +{ +} +#endif + +#ifdef MEMORY_DEBUG +#define qdf_mem_malloc(size) \ + qdf_mem_malloc_debug(size, __FILE__, __LINE__) +void *qdf_mem_malloc_debug(size_t size, char *file_name, uint32_t line_num); +#else +void * +qdf_mem_malloc(qdf_size_t size); +#endif + +void *qdf_mem_alloc_outline(qdf_device_t osdev, qdf_size_t size); + +/** + * qdf_mem_free() - free QDF memory + * @ptr: Pointer to the starting address of the memory to be free'd. + * This function will free the memory pointed to by 'ptr'. + * Return: + * None + */ +void qdf_mem_free(void *ptr); + +void qdf_mem_set(void *ptr, uint32_t num_bytes, uint32_t value); + +void qdf_mem_zero(void *ptr, uint32_t num_bytes); + +void qdf_mem_copy(void *dst_addr, const void *src_addr, uint32_t num_bytes); + +void qdf_mem_move(void *dst_addr, const void *src_addr, uint32_t num_bytes); + +void qdf_mem_free_outline(void *buf); + +void *qdf_mem_alloc_consistent(qdf_device_t osdev, void *dev, qdf_size_t size, + qdf_dma_addr_t *paddr); + +void qdf_mem_free_consistent(qdf_device_t osdev, void *dev, qdf_size_t size, + void *vaddr, qdf_dma_addr_t paddr, + qdf_dma_context_t memctx); + +void qdf_mem_zero_outline(void *buf, qdf_size_t size); + +/** + * qdf_mem_cmp() - memory compare + * @memory1: pointer to one location in memory to compare. + * @memory2: pointer to second location in memory to compare. + * @num_bytes: the number of bytes to compare. + * + * Function to compare two pieces of memory, similar to memcmp function + * in standard C. + * Return: + * int32_t - returns an int value that tells if the memory + * locations are equal or not equal. + * 0 -- equal + * < 0 -- *memory1 is less than *memory2 + * > 0 -- *memory1 is bigger than *memory2 + */ +static inline int32_t qdf_mem_cmp(const void *memory1, const void *memory2, + uint32_t num_bytes) +{ + return __qdf_mem_cmp(memory1, memory2, num_bytes); +} + +/** + * qdf_str_cmp - Compare two strings + * @str1: First string + * @str2: Second string + * Return: =0 equal + * >0 not equal, if str1 sorts lexicographically after str2 + * <0 not equal, if str1 sorts lexicographically before str2 + */ +static inline int32_t qdf_str_cmp(const char *str1, const char *str2) +{ + return __qdf_str_cmp(str1, str2); +} + +/** + * qdf_str_lcopy - Copy from one string to another + * @dest: destination string + * @src: source string + * @bytes: limit of num bytes to copy + * Return: =0 returns the initial value of dest + */ +static inline uint32_t qdf_str_lcopy(char *dest, const char *src, uint32_t bytes) +{ + return __qdf_str_lcopy(dest, src, bytes); +} + +/** + * qdf_mem_map_nbytes_single - Map memory for DMA + * @osdev: pomter OS device context + * @buf: pointer to memory to be dma mapped + * @dir: DMA map direction + * @nbytes: number of bytes to be mapped. + * @phy_addr: ponter to recive physical address. + * + * Return: success/failure + */ +static inline uint32_t qdf_mem_map_nbytes_single(qdf_device_t osdev, void *buf, + qdf_dma_dir_t dir, int nbytes, + uint32_t *phy_addr) +{ +#if defined(HIF_PCI) + return __qdf_mem_map_nbytes_single(osdev, buf, dir, nbytes, phy_addr); +#else + return 0; +#endif +} + +/** + * qdf_mem_unmap_nbytes_single() - un_map memory for DMA + * @osdev: pomter OS device context + * @phy_addr: physical address of memory to be dma unmapped + * @dir: DMA unmap direction + * @nbytes: number of bytes to be unmapped. + * + * Return: none + */ +static inline void qdf_mem_unmap_nbytes_single(qdf_device_t osdev, + uint32_t phy_addr, + qdf_dma_dir_t dir, + int nbytes) +{ +#if defined(HIF_PCI) + __qdf_mem_unmap_nbytes_single(osdev, phy_addr, dir, nbytes); +#endif +} + +/** + * qdf_mempool_init - Create and initialize memory pool + * @osdev: platform device object + * @pool_addr: address of the pool created + * @elem_cnt: no. of elements in pool + * @elem_size: size of each pool element in bytes + * @flags: flags + * Return: Handle to memory pool or NULL if allocation failed + */ +static inline int qdf_mempool_init(qdf_device_t osdev, + qdf_mempool_t *pool_addr, int elem_cnt, + size_t elem_size, uint32_t flags) +{ + return __qdf_mempool_init(osdev, pool_addr, elem_cnt, elem_size, + flags); +} + +/** + * qdf_mempool_destroy - Destroy memory pool + * @osdev: platform device object + * @Handle: to memory pool + * Return: none + */ +static inline void qdf_mempool_destroy(qdf_device_t osdev, qdf_mempool_t pool) +{ + __qdf_mempool_destroy(osdev, pool); +} + +/** + * qdf_mempool_alloc - Allocate an element memory pool + * @osdev: platform device object + * @Handle: to memory pool + * Return: Pointer to the allocated element or NULL if the pool is empty + */ +static inline void *qdf_mempool_alloc(qdf_device_t osdev, qdf_mempool_t pool) +{ + return (void *)__qdf_mempool_alloc(osdev, pool); +} + +/** + * qdf_mempool_free - Free a memory pool element + * @osdev: Platform device object + * @pool: Handle to memory pool + * @buf: Element to be freed + * Return: none + */ +static inline void qdf_mempool_free(qdf_device_t osdev, qdf_mempool_t pool, + void *buf) +{ + __qdf_mempool_free(osdev, pool, buf); +} + +void qdf_mem_dma_sync_single_for_device(qdf_device_t osdev, + qdf_dma_addr_t bus_addr, + qdf_size_t size, + __dma_data_direction direction); + +void qdf_mem_dma_sync_single_for_cpu(qdf_device_t osdev, + qdf_dma_addr_t bus_addr, + qdf_size_t size, + __dma_data_direction direction); +/** + * qdf_str_len() - returns the length of a string + * @str: input string + * Return: + * length of string + */ +static inline int32_t qdf_str_len(const char *str) +{ + return __qdf_str_len(str); +} + +void qdf_mem_multi_pages_alloc(qdf_device_t osdev, + struct qdf_mem_multi_page_t *pages, + size_t element_size, uint16_t element_num, + qdf_dma_context_t memctxt, bool cacheable); +void qdf_mem_multi_pages_free(qdf_device_t osdev, + struct qdf_mem_multi_page_t *pages, + qdf_dma_context_t memctxt, bool cacheable); + + +#endif /* __QDF_MEMORY_H */ diff --git a/drivers/staging/qca-wifi-host-cmn/qdf/inc/qdf_module.h b/drivers/staging/qca-wifi-host-cmn/qdf/inc/qdf_module.h new file mode 100644 index 0000000000000000000000000000000000000000..23e13eecf4dbffd88f78e586b1208c19bc196c7d --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/qdf/inc/qdf_module.h @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2010-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * @file qdf_module.h + * This file abstracts "kernel module" semantics. + */ + +#ifndef _QDF_MODULE_H +#define _QDF_MODULE_H + +#include + +typedef uint32_t (*module_init_func_t)(void); + +/** + * qdf_virt_module_init - Specify the module's entry point. + */ +#define qdf_virt_module_init(_mod_init_func) \ + __qdf_virt_module_init(_mod_init_func) + +/** + * qdf_virt_module_exit - Specify the module's exit point. + */ +#define qdf_virt_module_exit(_mod_exit_func) \ + __qdf_virt_module_exit(_mod_exit_func) + +/** + * qdf_virt_module_name - Specify the module's name. + */ +#define qdf_virt_module_name(_name) __qdf_virt_module_name(_name) + + +/** + * qdf_export_symbol - Export a symbol from a module. + */ +#define qdf_export_symbol(_sym) __qdf_export_symbol(_sym) + +/** + * qdf_declare_param - Declare a module parameter. + */ +#define qdf_declare_param(name, _type) __qdf_declare_param(name, _type) + +#endif /*_QDF_MODULE_H*/ diff --git a/drivers/staging/qca-wifi-host-cmn/qdf/inc/qdf_nbuf.h b/drivers/staging/qca-wifi-host-cmn/qdf/inc/qdf_nbuf.h new file mode 100644 index 0000000000000000000000000000000000000000..6a887b122347e635e442d63171f71b2f87d9abee --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/qdf/inc/qdf_nbuf.h @@ -0,0 +1,2290 @@ +/* + * Copyright (c) 2014-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: qdf_nbuf_public network buffer API + * This file defines the network buffer abstraction. + */ + +#ifndef _QDF_NBUF_H +#define _QDF_NBUF_H + +#include +#include +#include +#include +#include +#include + +#define IPA_NBUF_OWNER_ID 0xaa55aa55 +#define QDF_NBUF_PKT_TRAC_TYPE_EAPOL 0x02 +#define QDF_NBUF_PKT_TRAC_TYPE_DHCP 0x04 +#define QDF_NBUF_PKT_TRAC_TYPE_MGMT_ACTION 0x08 +#define QDF_NBUF_PKT_TRAC_TYPE_ARP 0x10 +#define QDF_NBUF_PKT_TRAC_MAX_STRING 12 +#define QDF_NBUF_PKT_TRAC_PROTO_STRING 4 +#define QDF_NBUF_PKT_ERROR 1 + +#define QDF_NBUF_TRAC_IPV4_OFFSET 14 +#define QDF_NBUF_TRAC_IPV4_HEADER_SIZE 20 +#define QDF_NBUF_TRAC_DHCP_SRV_PORT 67 +#define QDF_NBUF_TRAC_DHCP_CLI_PORT 68 +#define QDF_NBUF_TRAC_ETH_TYPE_OFFSET 12 +#define QDF_NBUF_TRAC_EAPOL_ETH_TYPE 0x888E +#define QDF_NBUF_TRAC_WAPI_ETH_TYPE 0x88b4 +#define QDF_NBUF_TRAC_ARP_ETH_TYPE 0x0806 +#define QDF_NBUF_TRAC_IPV4_ETH_TYPE 0x0800 +#define QDF_NBUF_TRAC_IPV6_ETH_TYPE 0x86dd +#define QDF_NBUF_DEST_MAC_OFFSET 0 +#define QDF_NBUF_SRC_MAC_OFFSET 6 +#define QDF_NBUF_TRAC_IPV4_PROTO_TYPE_OFFSET 23 +#define QDF_NBUF_TRAC_IPV4_DEST_ADDR_OFFSET 30 +#define QDF_NBUF_TRAC_IPV6_PROTO_TYPE_OFFSET 20 +#define QDF_NBUF_TRAC_IPV4_ADDR_MCAST_MASK 0xE0000000 +#define QDF_NBUF_TRAC_IPV4_ADDR_BCAST_MASK 0xF0000000 +#define QDF_NBUF_TRAC_IPV6_DEST_ADDR_OFFSET 38 +#define QDF_NBUF_TRAC_IPV6_DEST_ADDR 0xFF00 +#define QDF_NBUF_TRAC_ICMP_TYPE 1 +#define QDF_NBUF_TRAC_TCP_TYPE 6 +#define QDF_NBUF_TRAC_UDP_TYPE 17 +#define QDF_NBUF_TRAC_ICMPV6_TYPE 0x3a + +/* EAPOL Related MASK */ +#define EAPOL_PACKET_TYPE_OFFSET 15 +#define EAPOL_KEY_INFO_OFFSET 19 +#define EAPOL_PKT_LEN_OFFSET 16 +#define EAPOL_KEY_LEN_OFFSET 21 +#define EAPOL_MASK 0x8013 +#define EAPOL_M1_BIT_MASK 0x8000 +#define EAPOL_M2_BIT_MASK 0x0001 +#define EAPOL_M3_BIT_MASK 0x8013 +#define EAPOL_M4_BIT_MASK 0x0003 + +/* ARP Related MASK */ +#define QDF_NBUF_PKT_ARP_OPCODE_OFFSET 20 +#define QDF_NBUF_PKT_ARPOP_REQ 1 +#define QDF_NBUF_PKT_ARPOP_REPLY 2 +#define QDF_NBUF_PKT_ARP_SRC_IP_OFFSET 28 +#define QDF_NBUF_PKT_ARP_TGT_IP_OFFSET 38 + +/* Tracked Packet types */ +#define QDF_NBUF_TX_PKT_INVALID 0 +#define QDF_NBUF_TX_PKT_DATA_TRACK 1 +#define QDF_NBUF_TX_PKT_MGMT_TRACK 2 + +/* Different Packet states */ +#define QDF_NBUF_TX_PKT_HDD 1 +#define QDF_NBUF_TX_PKT_TXRX_ENQUEUE 2 +#define QDF_NBUF_TX_PKT_TXRX_DEQUEUE 3 +#define QDF_NBUF_TX_PKT_TXRX 4 +#define QDF_NBUF_TX_PKT_HTT 5 +#define QDF_NBUF_TX_PKT_HTC 6 +#define QDF_NBUF_TX_PKT_HIF 7 +#define QDF_NBUF_TX_PKT_CE 8 +#define QDF_NBUF_TX_PKT_FREE 9 +#define QDF_NBUF_TX_PKT_STATE_MAX 10 + +/* Enable flag to print TSO specific prints in datapath */ +#ifdef TSO_DEBUG_LOG_ENABLE +#define TSO_DEBUG(args ...) printk(args) +#else +#define TSO_DEBUG(args ...) +#endif + +/** + * struct mon_rx_status - This will have monitor mode rx_status extracted from + * htt_rx_desc used later to update radiotap information. + * @tsft: Time Synchronization Function timer + * @chan_freq: Capture channel frequency + * @chan_num: Capture channel number + * @chan_flags: Bitmap of Channel flags, IEEE80211_CHAN_TURBO, + * IEEE80211_CHAN_CCK... + * @ht_flags: HT flags, only present for HT frames. + * @vht_flags: VHT flags, only present for VHT frames. + * @vht_flag_values1-5: Contains corresponding data for flags field + * @rate: Rate in terms 500Kbps + * @rtap_flags: Bit map of available fields in the radiotap + * @ant_signal_db: Rx packet RSSI + * @nr_ant: Number of Antennas used for streaming + * @mcs: MCS index of Rx frame + * @bw: bandwidth of rx frame + * @is_stbc: Is STBC enabled + * @sgi: Rx frame short guard interval + * @ldpc: ldpc enabled + * @beamformed: Is frame beamformed. + */ +struct mon_rx_status { + uint64_t tsft; + uint16_t chan_freq; + uint16_t chan_num; + uint16_t chan_flags; + uint16_t ht_flags; + uint16_t vht_flags; + uint16_t vht_flag_values6; + uint8_t rate; + uint8_t rtap_flags; + uint8_t ant_signal_db; + uint8_t nr_ant; + uint8_t mcs; + uint8_t bw; + uint8_t vht_flag_values1; + uint8_t vht_flag_values2; + uint8_t vht_flag_values3[4]; + uint8_t vht_flag_values4; + uint8_t vht_flag_values5; + uint8_t is_stbc; + uint8_t sgi; + uint8_t ldpc; + uint8_t beamformed; +}; + +/* DHCP Related Mask */ +#define QDF_DHCP_OPTION53 (0x35) +#define QDF_DHCP_OPTION53_LENGTH (1) +#define QDF_DHCP_OPTION53_OFFSET (0x11A) +#define QDF_DHCP_OPTION53_LENGTH_OFFSET (0x11B) +#define QDF_DHCP_OPTION53_STATUS_OFFSET (0x11C) +#define DHCP_PKT_LEN_OFFSET 16 +#define DHCP_TRANSACTION_ID_OFFSET 46 +#define QDF_DHCP_DISCOVER (1) +#define QDF_DHCP_OFFER (2) +#define QDF_DHCP_REQUEST (3) +#define QDF_DHCP_DECLINE (4) +#define QDF_DHCP_ACK (5) +#define QDF_DHCP_NAK (6) +#define QDF_DHCP_RELEASE (7) +#define QDF_DHCP_INFORM (8) + +/* ARP Related Mask */ +#define ARP_SUB_TYPE_OFFSET 20 +#define ARP_REQUEST (1) +#define ARP_RESPONSE (2) + +/* IPV4 header fields offset values */ +#define IPV4_PKT_LEN_OFFSET 16 +#define IPV4_TCP_SEQ_NUM_OFFSET 38 +#define IPV4_SRC_ADDR_OFFSET 26 +#define IPV4_DST_ADDR_OFFSET 30 +#define IPV4_SRC_PORT_OFFSET 34 +#define IPV4_DST_PORT_OFFSET 36 + +/* IPV4 ICMP Related Mask */ +#define ICMP_SEQ_NUM_OFFSET 40 +#define ICMP_SUBTYPE_OFFSET 34 +#define ICMP_REQUEST 0x08 +#define ICMP_RESPONSE 0x00 + +#define IPV6_ADDR_STR "%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:"\ + "%02x%02x:%02x%02x" + +/* IPV6 header fields offset values */ +#define IPV6_PKT_LEN_OFFSET 18 +#define IPV6_TCP_SEQ_NUM_OFFSET 58 +#define IPV6_SRC_ADDR_OFFSET 22 +#define IPV6_DST_ADDR_OFFSET 38 +#define IPV6_SRC_PORT_OFFSET 54 +#define IPV6_DST_PORT_OFFSET 56 + +/* IPV6 ICMPV6 Related Mask */ +#define ICMPV6_SEQ_NUM_OFFSET 60 +#define ICMPV6_SUBTYPE_OFFSET 54 +#define ICMPV6_REQUEST 0x80 +#define ICMPV6_RESPONSE 0x81 +#define ICMPV6_RS 0x85 +#define ICMPV6_RA 0x86 +#define ICMPV6_NS 0x87 +#define ICMPV6_NA 0x88 + +#define QDF_NBUF_IPA_CHECK_MASK 0x80000000 + +/** + * qdf_proto_type - protocol type + * @QDF_PROTO_TYPE_DHCP - DHCP + * @QDF_PROTO_TYPE_EAPOL - EAPOL + * @QDF_PROTO_TYPE_ARP - ARP + * @QDF_PROTO_TYPE_MGMT - MGMT + * QDF_PROTO_TYPE_EVENT - EVENT + */ +enum qdf_proto_type { + QDF_PROTO_TYPE_DHCP, + QDF_PROTO_TYPE_EAPOL, + QDF_PROTO_TYPE_ARP, + QDF_PROTO_TYPE_MGMT, + QDF_PROTO_TYPE_EVENT, + QDF_PROTO_TYPE_MAX +}; + +/** + * qdf_proto_subtype - subtype of packet + * @QDF_PROTO_EAPOL_M1 - EAPOL 1/4 + * @QDF_PROTO_EAPOL_M2 - EAPOL 2/4 + * @QDF_PROTO_EAPOL_M3 - EAPOL 3/4 + * @QDF_PROTO_EAPOL_M4 - EAPOL 4/4 + * @QDF_PROTO_DHCP_DISCOVER - discover + * @QDF_PROTO_DHCP_REQUEST - request + * @QDF_PROTO_DHCP_OFFER - offer + * @QDF_PROTO_DHCP_ACK - ACK + * @QDF_PROTO_DHCP_NACK - NACK + * @QDF_PROTO_DHCP_RELEASE - release + * @QDF_PROTO_DHCP_INFORM - inform + * @QDF_PROTO_DHCP_DECLINE - decline + * @QDF_PROTO_ARP_REQ - arp request + * @QDF_PROTO_ARP_RES - arp response + * @QDF_PROTO_ICMP_REQ - icmp request + * @QDF_PROTO_ICMP_RES - icmp response + * @QDF_PROTO_ICMPV6_REQ - icmpv6 request + * @QDF_PROTO_ICMPV6_RES - icmpv6 response + * @QDF_PROTO_ICMPV6_RS - icmpv6 rs packet + * @QDF_PROTO_ICMPV6_RA - icmpv6 ra packet + * @QDF_PROTO_ICMPV6_NS - icmpv6 ns packet + * @QDF_PROTO_ICMPV6_NA - icmpv6 na packet + * @QDF_PROTO_IPV4_UDP - ipv4 udp + * @QDF_PROTO_IPV4_TCP - ipv4 tcp + * @QDF_PROTO_IPV6_UDP - ipv6 udp + * @QDF_PROTO_IPV6_TCP - ipv6 tcp + * @QDF_PROTO_MGMT_ASSOC -assoc + * @QDF_PROTO_MGMT_DISASSOC - disassoc + * @QDF_PROTO_MGMT_AUTH - auth + * @QDF_PROTO_MGMT_DEAUTH - deauth + * QDF_ROAM_SYNCH - roam synch indication from fw + * QDF_ROAM_COMPLETE - roam complete cmd to fw + * QDF_ROAM_EVENTID - roam eventid from fw + */ +enum qdf_proto_subtype { + QDF_PROTO_INVALID, + QDF_PROTO_EAPOL_M1, + QDF_PROTO_EAPOL_M2, + QDF_PROTO_EAPOL_M3, + QDF_PROTO_EAPOL_M4, + QDF_PROTO_DHCP_DISCOVER, + QDF_PROTO_DHCP_REQUEST, + QDF_PROTO_DHCP_OFFER, + QDF_PROTO_DHCP_ACK, + QDF_PROTO_DHCP_NACK, + QDF_PROTO_DHCP_RELEASE, + QDF_PROTO_DHCP_INFORM, + QDF_PROTO_DHCP_DECLINE, + QDF_PROTO_ARP_REQ, + QDF_PROTO_ARP_RES, + QDF_PROTO_ICMP_REQ, + QDF_PROTO_ICMP_RES, + QDF_PROTO_ICMPV6_REQ, + QDF_PROTO_ICMPV6_RES, + QDF_PROTO_ICMPV6_RS, + QDF_PROTO_ICMPV6_RA, + QDF_PROTO_ICMPV6_NS, + QDF_PROTO_ICMPV6_NA, + QDF_PROTO_IPV4_UDP, + QDF_PROTO_IPV4_TCP, + QDF_PROTO_IPV6_UDP, + QDF_PROTO_IPV6_TCP, + QDF_PROTO_MGMT_ASSOC, + QDF_PROTO_MGMT_DISASSOC, + QDF_PROTO_MGMT_AUTH, + QDF_PROTO_MGMT_DEAUTH, + QDF_ROAM_SYNCH, + QDF_ROAM_COMPLETE, + QDF_ROAM_EVENTID, + QDF_PROTO_SUBTYPE_MAX +}; + +/** + * @qdf_nbuf_t - Platform indepedent packet abstraction + */ +typedef __qdf_nbuf_t qdf_nbuf_t; + +/** + * @qdf_dma_map_cb_t - Dma map callback prototype + */ +typedef void (*qdf_dma_map_cb_t)(void *arg, qdf_nbuf_t buf, + qdf_dma_map_t dmap); + +/** + * @qdf_nbuf_queue_t - Platform independent packet queue abstraction + */ +typedef __qdf_nbuf_queue_t qdf_nbuf_queue_t; + +/* BUS/DMA mapping routines */ + +static inline QDF_STATUS +qdf_nbuf_dmamap_create(qdf_device_t osdev, qdf_dma_map_t *dmap) +{ + return __qdf_nbuf_dmamap_create(osdev, dmap); +} + +static inline void +qdf_nbuf_dmamap_destroy(qdf_device_t osdev, qdf_dma_map_t dmap) +{ + __qdf_nbuf_dmamap_destroy(osdev, dmap); +} + +static inline void +qdf_nbuf_dmamap_set_cb(qdf_dma_map_t dmap, qdf_dma_map_cb_t cb, void *arg) +{ + __qdf_nbuf_dmamap_set_cb(dmap, cb, arg); +} + +static inline void +qdf_nbuf_set_send_complete_flag(qdf_nbuf_t buf, bool flag) +{ + __qdf_nbuf_set_send_complete_flag(buf, flag); +} + +static inline QDF_STATUS +qdf_nbuf_map(qdf_device_t osdev, qdf_nbuf_t buf, qdf_dma_dir_t dir) +{ + return __qdf_nbuf_map(osdev, buf, dir); +} + +static inline void +qdf_nbuf_unmap(qdf_device_t osdev, qdf_nbuf_t buf, qdf_dma_dir_t dir) +{ + __qdf_nbuf_unmap(osdev, buf, dir); +} + +static inline QDF_STATUS +qdf_nbuf_map_nbytes(qdf_device_t osdev, qdf_nbuf_t buf, + qdf_dma_dir_t dir, int nbytes) +{ + return __qdf_nbuf_map_nbytes(osdev, buf, dir, nbytes); +} + +static inline void +qdf_nbuf_unmap_nbytes(qdf_device_t osdev, + qdf_nbuf_t buf, qdf_dma_dir_t dir, int nbytes) +{ + __qdf_nbuf_unmap_nbytes(osdev, buf, dir, nbytes); +} + +#ifndef REMOVE_INIT_DEBUG_CODE +static inline void +qdf_nbuf_sync_for_cpu(qdf_device_t osdev, qdf_nbuf_t buf, qdf_dma_dir_t dir) +{ + __qdf_nbuf_sync_for_cpu(osdev, buf, dir); +} +#endif + +static inline QDF_STATUS +qdf_nbuf_map_single(qdf_device_t osdev, qdf_nbuf_t buf, qdf_dma_dir_t dir) +{ + return __qdf_nbuf_map_single(osdev, buf, dir); +} + +static inline QDF_STATUS +qdf_nbuf_map_nbytes_single( + qdf_device_t osdev, qdf_nbuf_t buf, qdf_dma_dir_t dir, int nbytes) +{ + return __qdf_nbuf_map_nbytes_single(osdev, buf, dir, nbytes); +} + +static inline void +qdf_nbuf_unmap_single(qdf_device_t osdev, qdf_nbuf_t buf, qdf_dma_dir_t dir) +{ + __qdf_nbuf_unmap_single(osdev, buf, dir); +} + +static inline void +qdf_nbuf_unmap_nbytes_single( + qdf_device_t osdev, qdf_nbuf_t buf, qdf_dma_dir_t dir, int nbytes) +{ + return __qdf_nbuf_unmap_nbytes_single(osdev, buf, dir, nbytes); +} + +static inline int qdf_nbuf_get_num_frags(qdf_nbuf_t buf) +{ + return __qdf_nbuf_get_num_frags(buf); +} + +/** + * qdf_nbuf_get_frag_len() - get fragment length + * @buf: Network buffer + * @frag_num: Fragment number + * + * Return: Fragment length + */ +static inline int qdf_nbuf_get_frag_len(qdf_nbuf_t buf, int frag_num) +{ + QDF_BUG(!(frag_num >= QDF_NBUF_CB_TX_MAX_EXTRA_FRAGS)); + return __qdf_nbuf_get_frag_len(buf, frag_num); +} + +/** + * qdf_nbuf_get_frag_vaddr() - get fragment virtual address + * @buf: Network buffer + * @frag_num: Fragment number + * + * Return: Fragment virtual address + */ +static inline unsigned char *qdf_nbuf_get_frag_vaddr(qdf_nbuf_t buf, + int frag_num) +{ + QDF_BUG(!(frag_num >= QDF_NBUF_CB_TX_MAX_EXTRA_FRAGS)); + return __qdf_nbuf_get_frag_vaddr(buf, frag_num); +} + +/** + * qdf_nbuf_get_frag_vaddr_always() - get fragment virtual address + * @buf: Network buffer + * + * Return: Fragment virtual address + */ +static inline unsigned char * +qdf_nbuf_get_frag_vaddr_always(qdf_nbuf_t buf) +{ + return __qdf_nbuf_get_frag_vaddr_always(buf); +} + +/** + * qdf_nbuf_get_frag_paddr() - get fragment physical address + * @buf: Network buffer + * @frag_num: Fragment number + * + * Return: Fragment physical address + */ +static inline qdf_dma_addr_t qdf_nbuf_get_frag_paddr(qdf_nbuf_t buf, + unsigned int frag_num) +{ + QDF_BUG(!(frag_num >= QDF_NBUF_CB_TX_MAX_EXTRA_FRAGS)); + return __qdf_nbuf_get_frag_paddr(buf, frag_num); +} + +/** + * qdf_nbuf_get_frag_is_wordstream() - is fragment wordstream + * @buf: Network buffer + * @frag_num: Fragment number + * + * Return: Fragment wordstream or not + */ +static inline int qdf_nbuf_get_frag_is_wordstream(qdf_nbuf_t buf, int frag_num) +{ + QDF_BUG(!(frag_num >= QDF_NBUF_CB_TX_MAX_EXTRA_FRAGS)); + return __qdf_nbuf_get_frag_is_wordstream(buf, frag_num); +} + +static inline int qdf_nbuf_ipa_owned_get(qdf_nbuf_t buf) +{ + return __qdf_nbuf_ipa_owned_get(buf); +} + +static inline void qdf_nbuf_ipa_owned_set(qdf_nbuf_t buf) +{ + __qdf_nbuf_ipa_owned_set(buf); +} + +static inline int qdf_nbuf_ipa_priv_get(qdf_nbuf_t buf) +{ + return __qdf_nbuf_ipa_priv_get(buf); +} + +static inline void qdf_nbuf_ipa_priv_set(qdf_nbuf_t buf, uint32_t priv) +{ + + QDF_BUG(!(priv & QDF_NBUF_IPA_CHECK_MASK)); + __qdf_nbuf_ipa_priv_set(buf, priv); +} + +/** + * qdf_nbuf_set_frag_is_wordstream() - set fragment wordstream + * @buf: Network buffer + * @frag_num: Fragment number + * @is_wordstream: Wordstream + * + * Return: none + */ +static inline void +qdf_nbuf_set_frag_is_wordstream(qdf_nbuf_t buf, + int frag_num, int is_wordstream) +{ + QDF_BUG(!(frag_num >= QDF_NBUF_CB_TX_MAX_EXTRA_FRAGS)); + __qdf_nbuf_set_frag_is_wordstream(buf, frag_num, is_wordstream); +} + +static inline void +qdf_nbuf_set_vdev_ctx(qdf_nbuf_t buf, void *vdev_ctx) +{ + __qdf_nbuf_set_vdev_ctx(buf, vdev_ctx); +} + +static inline void +qdf_nbuf_set_fctx_type(qdf_nbuf_t buf, void *ctx, uint8_t type) +{ + __qdf_nbuf_set_fctx_type(buf, ctx, type); +} + +static inline void * +qdf_nbuf_get_vdev_ctx(qdf_nbuf_t buf) +{ + return __qdf_nbuf_get_vdev_ctx(buf); +} + +static inline void *qdf_nbuf_get_fctx(qdf_nbuf_t buf) +{ + return __qdf_nbuf_get_fctx(buf); +} + +static inline uint8_t qdf_nbuf_get_ftype(qdf_nbuf_t buf) +{ + return __qdf_nbuf_get_ftype(buf); +} + +static inline qdf_dma_addr_t +qdf_nbuf_mapped_paddr_get(qdf_nbuf_t buf) +{ + return __qdf_nbuf_mapped_paddr_get(buf); +} + +static inline void +qdf_nbuf_mapped_paddr_set(qdf_nbuf_t buf, qdf_dma_addr_t paddr) +{ + __qdf_nbuf_mapped_paddr_set(buf, paddr); +} + +static inline void +qdf_nbuf_frag_push_head(qdf_nbuf_t buf, + int frag_len, char *frag_vaddr, + qdf_dma_addr_t frag_paddr) +{ + __qdf_nbuf_frag_push_head(buf, frag_len, frag_vaddr, frag_paddr); +} + +#define qdf_nbuf_num_frags_init(_nbuf) __qdf_nbuf_num_frags_init((_nbuf)) + +/* For efficiency, it is the responsibility of the caller to ensure that val + * is either 0 or 1. + */ +static inline void +qdf_nbuf_set_chfrag_start(qdf_nbuf_t buf, uint8_t val) +{ + __qdf_nbuf_set_chfrag_start(buf, val); +} + +static inline int qdf_nbuf_is_chfrag_start(qdf_nbuf_t buf) +{ + return __qdf_nbuf_is_chfrag_start(buf); +} + +/* For efficiency, it is the responsibility of the caller to ensure that val + * is either 0 or 1. + */ +static inline void qdf_nbuf_set_chfrag_end(qdf_nbuf_t buf, uint8_t val) +{ + __qdf_nbuf_set_chfrag_end(buf, val); +} + +static inline int qdf_nbuf_is_chfrag_end(qdf_nbuf_t buf) +{ + return __qdf_nbuf_is_chfrag_end(buf); +} + +static inline void +qdf_nbuf_dma_map_info(qdf_dma_map_t bmap, qdf_dmamap_info_t *sg) +{ + __qdf_nbuf_dma_map_info(bmap, sg); +} + +#ifdef MEMORY_DEBUG +void qdf_net_buf_debug_init(void); +void qdf_net_buf_debug_exit(void); +void qdf_net_buf_debug_clean(void); +void qdf_net_buf_debug_add_node(qdf_nbuf_t net_buf, size_t size, + uint8_t *file_name, uint32_t line_num); +void qdf_net_buf_debug_release_skb(qdf_nbuf_t net_buf); + +/* nbuf allocation rouines */ + +#define qdf_nbuf_alloc(d, s, r, a, p) \ + qdf_nbuf_alloc_debug(d, s, r, a, p, __FILE__, __LINE__) +static inline qdf_nbuf_t +qdf_nbuf_alloc_debug(qdf_device_t osdev, qdf_size_t size, int reserve, + int align, int prio, uint8_t *file_name, + uint32_t line_num) +{ + qdf_nbuf_t net_buf; + net_buf = __qdf_nbuf_alloc(osdev, size, reserve, align, prio); + + /* Store SKB in internal QDF tracking table */ + if (qdf_likely(net_buf)) + qdf_net_buf_debug_add_node(net_buf, size, file_name, line_num); + + return net_buf; +} + +static inline void qdf_nbuf_free(qdf_nbuf_t net_buf) +{ + /* Remove SKB from internal QDF tracking table */ + if (qdf_likely(net_buf)) + qdf_net_buf_debug_delete_node(net_buf); + + __qdf_nbuf_free(net_buf); +} + +#define qdf_nbuf_clone(buf) \ + qdf_nbuf_clone_debug(buf, __FILE__, __LINE__) + +/** + * qdf_nbuf_clone_debug() - clone the nbuf (copy is readonly) + * @buf: nbuf to clone from + * @file_name: pointer to file name + * @line_num: line number + * + * This function clones the nbuf and creates a memory tracking + * node corresponding to that cloned skbuff structure. + * + * Return: cloned buffer + */ +static inline qdf_nbuf_t +qdf_nbuf_clone_debug(qdf_nbuf_t buf, uint8_t *file_name, + uint32_t line_num) +{ + qdf_nbuf_t cloned_buf; + + cloned_buf = __qdf_nbuf_clone(buf); + + /* Store SKB in internal QDF tracking table */ + if (qdf_likely(cloned_buf)) + qdf_net_buf_debug_add_node(cloned_buf, 0, file_name, line_num); + + return cloned_buf; +} + +#define qdf_nbuf_copy(buf) \ + qdf_nbuf_copy_debug(buf, __FILE__, __LINE__) + +/** + * qdf_nbuf_copy_debug() - returns a private copy of the buf + * @buf: nbuf to copy from + * @file_name: pointer to file name + * @line_num: line number + * + * This API returns a private copy of the buf, the buf returned is completely + * modifiable by callers. It also creates a memory tracking node corresponding + * to that new skbuff structure. + * + * Return: copied buffer + */ +static inline qdf_nbuf_t +qdf_nbuf_copy_debug(qdf_nbuf_t buf, uint8_t *file_name, + uint32_t line_num) +{ + qdf_nbuf_t copied_buf; + + copied_buf = __qdf_nbuf_copy(buf); + + /* Store SKB in internal QDF tracking table */ + if (qdf_likely(copied_buf)) + qdf_net_buf_debug_add_node(copied_buf, 0, file_name, line_num); + + return copied_buf; +} + +#else + +static inline void qdf_net_buf_debug_release_skb(qdf_nbuf_t net_buf) +{ + return; +} + +/* Nbuf allocation rouines */ + +static inline qdf_nbuf_t +qdf_nbuf_alloc(qdf_device_t osdev, + qdf_size_t size, int reserve, int align, int prio) +{ + return __qdf_nbuf_alloc(osdev, size, reserve, align, prio); +} + +static inline void qdf_nbuf_free(qdf_nbuf_t buf) +{ + __qdf_nbuf_free(buf); +} + +/** + * qdf_nbuf_clone() - clone the nbuf (copy is readonly) + * @buf: Pointer to network buffer + * + * This function clones the nbuf and returns new sk_buff + * structure. + * + * Return: cloned skb + */ +static inline qdf_nbuf_t qdf_nbuf_clone(qdf_nbuf_t buf) +{ + return __qdf_nbuf_clone(buf); +} + +/** + * qdf_nbuf_copy() - returns a private copy of the buf + * @buf: Pointer to network buffer + * + * This API returns a private copy of the buf, the buf returned is completely + * modifiable by callers + * + * Return: skb or NULL + */ +static inline qdf_nbuf_t qdf_nbuf_copy(qdf_nbuf_t buf) +{ + return __qdf_nbuf_copy(buf); +} + +#endif + +#ifdef WLAN_FEATURE_FASTPATH +/** + * qdf_nbuf_init_fast() - before put buf into pool,turn it to init state + * + * @buf: buf instance + * Return: data pointer of this buf where new data has to be + * put, or NULL if there is not enough room in this buf. + */ + +static inline void qdf_nbuf_init_fast(qdf_nbuf_t nbuf) +{ + atomic_set(&nbuf->users, 1); + nbuf->data = nbuf->head + NET_SKB_PAD; + skb_reset_tail_pointer(nbuf); +} +#endif /* WLAN_FEATURE_FASTPATH */ + +static inline void qdf_nbuf_tx_free(qdf_nbuf_t buf_list, int tx_err) +{ + __qdf_nbuf_tx_free(buf_list, tx_err); +} + +static inline void qdf_nbuf_ref(qdf_nbuf_t buf) +{ + __qdf_nbuf_ref(buf); +} + +static inline int qdf_nbuf_shared(qdf_nbuf_t buf) +{ + return __qdf_nbuf_shared(buf); +} + +static inline QDF_STATUS qdf_nbuf_cat(qdf_nbuf_t dst, qdf_nbuf_t src) +{ + return __qdf_nbuf_cat(dst, src); +} + +/** + * @qdf_nbuf_copy_bits() - return the length of the copy bits for skb + * @skb: SKB pointer + * @offset: offset + * @len: Length + * @to: To + * + * Return: int32_t + */ +static inline int32_t +qdf_nbuf_copy_bits(qdf_nbuf_t nbuf, uint32_t offset, uint32_t len, void *to) +{ + return __qdf_nbuf_copy_bits(nbuf, offset, len, to); +} + + +/* nbuf manipulation routines */ + +/** + * @qdf_nbuf_head() - return the address of an nbuf's buffer + * @buf: netbuf + * + * Return: head address + */ +static inline uint8_t *qdf_nbuf_head(qdf_nbuf_t buf) +{ + return __qdf_nbuf_head(buf); +} + +/** + * qdf_nbuf_data() - Return the address of the start of data within an nbuf + * @buf: Network buffer + * + * Return: Data address + */ +static inline uint8_t *qdf_nbuf_data(qdf_nbuf_t buf) +{ + return __qdf_nbuf_data(buf); +} + +/** + * qdf_nbuf_data_addr() - Return the address of skb->data + * @buf: Network buffer + * + * Return: Data address + */ +static inline uint8_t *qdf_nbuf_data_addr(qdf_nbuf_t buf) +{ + return __qdf_nbuf_data_addr(buf); +} + +/** + * qdf_nbuf_headroom() - amount of headroom int the current nbuf + * @buf: Network buffer + * + * Return: Amount of head room + */ +static inline uint32_t qdf_nbuf_headroom(qdf_nbuf_t buf) +{ + return __qdf_nbuf_headroom(buf); +} + +/** + * qdf_nbuf_tailroom() - amount of tail space available + * @buf: Network buffer + * + * Return: amount of tail room + */ +static inline uint32_t qdf_nbuf_tailroom(qdf_nbuf_t buf) +{ + return __qdf_nbuf_tailroom(buf); +} + +/** + * qdf_nbuf_push_head() - push data in the front + * @buf: Network buf instance + * @size: Size to be pushed + * + * Return: New data pointer of this buf after data has been pushed, + * or NULL if there is not enough room in this buf. + */ +static inline uint8_t *qdf_nbuf_push_head(qdf_nbuf_t buf, qdf_size_t size) +{ + return __qdf_nbuf_push_head(buf, size); +} + +/** + * qdf_nbuf_put_tail() - puts data in the end + * @buf: Network buf instance + * @size: Size to be pushed + * + * Return: Data pointer of this buf where new data has to be + * put, or NULL if there is not enough room in this buf. + */ +static inline uint8_t *qdf_nbuf_put_tail(qdf_nbuf_t buf, qdf_size_t size) +{ + return __qdf_nbuf_put_tail(buf, size); +} + +/** + * qdf_nbuf_pull_head() - pull data out from the front + * @buf: Network buf instance + * @size: Size to be popped + * + * Return: New data pointer of this buf after data has been popped, + * or NULL if there is not sufficient data to pull. + */ +static inline uint8_t *qdf_nbuf_pull_head(qdf_nbuf_t buf, qdf_size_t size) +{ + return __qdf_nbuf_pull_head(buf, size); +} + +/** + * qdf_nbuf_trim_tail() - trim data out from the end + * @buf: Network buf instance + * @size: Size to be popped + * + * Return: none + */ +static inline void qdf_nbuf_trim_tail(qdf_nbuf_t buf, qdf_size_t size) +{ + __qdf_nbuf_trim_tail(buf, size); +} + +/** + * qdf_nbuf_len() - get the length of the buf + * @buf: Network buf instance + * + * Return: total length of this buf. + */ +static inline qdf_size_t qdf_nbuf_len(qdf_nbuf_t buf) +{ + return __qdf_nbuf_len(buf); +} + +/** + * qdf_nbuf_set_pktlen() - set the length of the buf + * @buf: Network buf instance + * @size: Size to be set + * + * Return: none + */ +static inline void qdf_nbuf_set_pktlen(qdf_nbuf_t buf, uint32_t len) +{ + __qdf_nbuf_set_pktlen(buf, len); +} + +/** + * qdf_nbuf_reserve() - trim data out from the end + * @buf: Network buf instance + * @size: Size to be popped + * + * Return: none + */ +static inline void qdf_nbuf_reserve(qdf_nbuf_t buf, qdf_size_t size) +{ + __qdf_nbuf_reserve(buf, size); +} + +/** + * qdf_nbuf_peek_header() - return the data pointer & length of the header + * @buf: Network nbuf + * @addr: Data pointer + * @len: Length of the data + * + * Return: none + */ +static inline void +qdf_nbuf_peek_header(qdf_nbuf_t buf, uint8_t **addr, uint32_t *len) +{ + __qdf_nbuf_peek_header(buf, addr, len); +} + +/* nbuf queue routines */ + +/** + * qdf_nbuf_queue_init() - initialize buf queue + * @head: Network buf queue head + * + * Return: none + */ +static inline void qdf_nbuf_queue_init(qdf_nbuf_queue_t *head) +{ + __qdf_nbuf_queue_init(head); +} + +/** + * qdf_nbuf_queue_add() - append a nbuf to the tail of the buf queue + * @head: Network buf queue head + * @buf: Network buf + * + * Return: none + */ +static inline void qdf_nbuf_queue_add(qdf_nbuf_queue_t *head, qdf_nbuf_t buf) +{ + __qdf_nbuf_queue_add(head, buf); +} + +/** + * qdf_nbuf_queue_insert_head() - insert nbuf at the head of queue + * @head: Network buf queue head + * @buf: Network buf + * + * Return: none + */ +static inline void +qdf_nbuf_queue_insert_head(qdf_nbuf_queue_t *head, qdf_nbuf_t buf) +{ + __qdf_nbuf_queue_insert_head(head, buf); +} + +/** + * qdf_nbuf_queue_remove() - retrieve a buf from the head of the buf queue + * @head: Network buf queue head + * + * Return: The head buf in the buf queue. + */ +static inline qdf_nbuf_t qdf_nbuf_queue_remove(qdf_nbuf_queue_t *head) +{ + return __qdf_nbuf_queue_remove(head); +} + +/** + * qdf_nbuf_queue_len() - get the length of the queue + * @head: Network buf queue head + * + * Return: length of the queue + */ +static inline uint32_t qdf_nbuf_queue_len(qdf_nbuf_queue_t *head) +{ + return __qdf_nbuf_queue_len(head); +} + +/** + * qdf_nbuf_queue_next() - get the next guy/packet of the given buffer + * @buf: Network buffer + * + * Return: next buffer/packet + */ +static inline qdf_nbuf_t qdf_nbuf_queue_next(qdf_nbuf_t buf) +{ + return __qdf_nbuf_queue_next(buf); +} + +/** + * @qdf_nbuf_is_queue_empty() - check if the buf queue is empty + * @nbq: Network buf queue handle + * + * Return: true if queue is empty + * false if queue is not emty + */ +static inline bool qdf_nbuf_is_queue_empty(qdf_nbuf_queue_t *nbq) +{ + return __qdf_nbuf_is_queue_empty(nbq); +} + +static inline qdf_nbuf_queue_t * +qdf_nbuf_queue_append(qdf_nbuf_queue_t *dest, qdf_nbuf_queue_t *src) +{ + return __qdf_nbuf_queue_append(dest, src); +} + +static inline void +qdf_nbuf_queue_free(qdf_nbuf_queue_t *head) +{ + __qdf_nbuf_queue_free(head); +} + +static inline qdf_nbuf_t +qdf_nbuf_queue_first(qdf_nbuf_queue_t *head) +{ + return __qdf_nbuf_queue_first(head); +} + +/** + * qdf_nbuf_next() - get the next packet in the linked list + * @buf: Network buffer + * + * This function can be used when nbufs are directly linked into a list, + * rather than using a separate network buffer queue object. + * + * Return: next network buffer in the linked list + */ +static inline qdf_nbuf_t qdf_nbuf_next(qdf_nbuf_t buf) +{ + return __qdf_nbuf_next(buf); +} + +/** + * qdf_nbuf_get_protocol() - return the protocol value of the skb + * @skb: Pointer to network buffer + * + * Return: skb protocol + */ +static inline uint16_t qdf_nbuf_get_protocol(struct sk_buff *skb) +{ + return __qdf_nbuf_get_protocol(skb); +} + +/** + * qdf_nbuf_get_ip_summed() - return the ip checksum value of the skb + * @skb: Pointer to network buffer + * + * Return: skb ip_summed + */ +static inline uint8_t qdf_nbuf_get_ip_summed(struct sk_buff *skb) +{ + return __qdf_nbuf_get_ip_summed(skb); +} + +/** + * qdf_nbuf_set_ip_summed() - sets the ip_summed value of the skb + * @skb: Pointer to network buffer + * @ip_summed: ip checksum + * + * Return: none + */ +static inline void qdf_nbuf_set_ip_summed(struct sk_buff *skb, + uint8_t ip_summed) +{ + __qdf_nbuf_set_ip_summed(skb, ip_summed); +} + +/** + * qdf_nbuf_set_next() - add a packet to a linked list + * @this_buf: Predecessor buffer + * @next_buf: Successor buffer + * + * This function can be used to directly link nbufs, rather than using + * a separate network buffer queue object. + * + * Return: none + */ +static inline void qdf_nbuf_set_next(qdf_nbuf_t this_buf, qdf_nbuf_t next_buf) +{ + __qdf_nbuf_set_next(this_buf, next_buf); +} + +/* nbuf extension routines */ + +/** + * qdf_nbuf_set_next_ext() - link extension of this packet contained in a new + * nbuf + * @this_buf: predecessor buffer + * @next_buf: successor buffer + * + * This function is used to link up many nbufs containing a single logical + * packet - not a collection of packets. Do not use for linking the first + * extension to the head + * + * Return: none + */ +static inline void +qdf_nbuf_set_next_ext(qdf_nbuf_t this_buf, qdf_nbuf_t next_buf) +{ + __qdf_nbuf_set_next_ext(this_buf, next_buf); +} + +/** + * qdf_nbuf_next_ext() - get the next packet extension in the linked list + * @buf: Network buffer + * + * Return: Next network buffer in the linked list + */ +static inline qdf_nbuf_t qdf_nbuf_next_ext(qdf_nbuf_t buf) +{ + return __qdf_nbuf_next_ext(buf); +} + +/** + * qdf_nbuf_append_ext_list() - link list of packet extensions to the head + * segment + * @head_buf: Network buf holding head segment (single) + * @ext_list: Network buf list holding linked extensions to the head + * @ext_len: Total length of all buffers in the extension list + * + * This function is used to link up a list of packet extensions (seg1, 2, + * ...) to the nbuf holding the head segment (seg0) + * + * Return: none + */ +static inline void +qdf_nbuf_append_ext_list(qdf_nbuf_t head_buf, qdf_nbuf_t ext_list, + qdf_size_t ext_len) +{ + __qdf_nbuf_append_ext_list(head_buf, ext_list, ext_len); +} + +/** + * qdf_nbuf_get_ext_list() - Get the link to extended nbuf list. + * @head_buf: Network buf holding head segment (single) + * + * This ext_list is populated when we have Jumbo packet, for example in case of + * monitor mode amsdu packet reception, and are stiched using frags_list. + * + * Return: Network buf list holding linked extensions from head buf. + */ +static inline qdf_nbuf_t qdf_nbuf_get_ext_list(qdf_nbuf_t head_buf) +{ + return (qdf_nbuf_t)__qdf_nbuf_get_ext_list(head_buf); +} + +/** + * qdf_nbuf_get_tx_cksum() - gets the tx checksum offload demand + * @buf: Network buffer + * + * Return: qdf_nbuf_tx_cksum_t checksum offload demand for the frame + */ +static inline qdf_nbuf_tx_cksum_t qdf_nbuf_get_tx_cksum(qdf_nbuf_t buf) +{ + return __qdf_nbuf_get_tx_cksum(buf); +} + +/** + * qdf_nbuf_set_rx_cksum() - drivers that support hw checksumming use this to + * indicate checksum info to the stack. + * @buf: Network buffer + * @cksum: Checksum + * + * Return: none + */ +static inline void +qdf_nbuf_set_rx_cksum(qdf_nbuf_t buf, qdf_nbuf_rx_cksum_t *cksum) +{ + __qdf_nbuf_set_rx_cksum(buf, cksum); +} + +/** + * qdf_nbuf_get_tid() - this function extracts the TID value from nbuf + * @buf: Network buffer + * + * Return: TID value + */ +static inline uint8_t qdf_nbuf_get_tid(qdf_nbuf_t buf) +{ + return __qdf_nbuf_get_tid(buf); +} + +/** + * qdf_nbuf_set_tid() - this function sets the TID value in nbuf + * @buf: Network buffer + * @tid: TID value + * + * Return: none + */ +static inline void qdf_nbuf_set_tid(qdf_nbuf_t buf, uint8_t tid) +{ + __qdf_nbuf_set_tid(buf, tid); +} + +/** + * qdf_nbuf_get_exemption_type() - this function extracts the exemption type + * from nbuf + * @buf: Network buffer + * + * Return: Exemption type + */ +static inline uint8_t qdf_nbuf_get_exemption_type(qdf_nbuf_t buf) +{ + return __qdf_nbuf_get_exemption_type(buf); +} + +/** + * qdf_nbuf_set_protocol() - this function peeks data into the buffer at given + * offset + * @buf: Network buffer + * @proto: Protocol + * + * Return: none + */ +static inline void qdf_nbuf_set_protocol(qdf_nbuf_t buf, uint16_t proto) +{ + __qdf_nbuf_set_protocol(buf, proto); +} + +/** + * qdf_nbuf_trace_get_proto_type() - this function return packet proto type + * @buf: Network buffer + * + * Return: Packet protocol type + */ +static inline uint8_t qdf_nbuf_trace_get_proto_type(qdf_nbuf_t buf) +{ + return __qdf_nbuf_trace_get_proto_type(buf); +} + +/** + * qdf_nbuf_reg_trace_cb() - this function registers protocol trace callback + * @cb_func_ptr: Callback pointer + * + * Return: none + */ +static inline void qdf_nbuf_reg_trace_cb(qdf_nbuf_trace_update_t cb_func_ptr) +{ + __qdf_nbuf_reg_trace_cb(cb_func_ptr); +} + + +/** + * qdf_nbuf_set_tx_parallel_dnload_frm() - set tx parallel download + * @buf: Network buffer + * @candi: Candidate of parallel download frame + * + * This function stores a flag specifying this TX frame is suitable for + * downloading though a 2nd TX data pipe that is used for short frames for + * protocols that can accept out-of-order delivery. + * + * Return: none + */ +static inline void +qdf_nbuf_set_tx_parallel_dnload_frm(qdf_nbuf_t buf, uint8_t candi) +{ + __qdf_nbuf_set_tx_htt2_frm(buf, candi); +} + +/** + * qdf_nbuf_get_tx_parallel_dnload_frm() - get tx parallel download + * @buf: Network buffer + * + * This function return whether this TX frame is allow to download though a 2nd + * TX data pipe or not. + * + * Return: none + */ +static inline uint8_t qdf_nbuf_get_tx_parallel_dnload_frm(qdf_nbuf_t buf) +{ + return __qdf_nbuf_get_tx_htt2_frm(buf); +} + +/** + * qdf_nbuf_get_dhcp_subtype() - get the subtype + * of DHCP packet. + * @buf: Pointer to DHCP packet buffer + * + * This func. returns the subtype of DHCP packet. + * + * Return: subtype of the DHCP packet. + */ +static inline enum qdf_proto_subtype +qdf_nbuf_get_dhcp_subtype(qdf_nbuf_t buf) +{ + return __qdf_nbuf_data_get_dhcp_subtype(qdf_nbuf_data(buf)); +} + +/** + * qdf_nbuf_data_get_dhcp_subtype() - get the subtype + * of DHCP packet. + * @buf: Pointer to DHCP packet data buffer + * + * This func. returns the subtype of DHCP packet. + * + * Return: subtype of the DHCP packet. + */ +static inline enum qdf_proto_subtype +qdf_nbuf_data_get_dhcp_subtype(uint8_t *data) +{ + return __qdf_nbuf_data_get_dhcp_subtype(data); +} + +/** + * qdf_nbuf_get_eapol_subtype() - get the subtype + * of EAPOL packet. + * @buf: Pointer to EAPOL packet buffer + * + * This func. returns the subtype of EAPOL packet. + * + * Return: subtype of the EAPOL packet. + */ +static inline enum qdf_proto_subtype +qdf_nbuf_get_eapol_subtype(qdf_nbuf_t buf) +{ + return __qdf_nbuf_data_get_eapol_subtype(qdf_nbuf_data(buf)); +} + +/** + * qdf_nbuf_data_get_eapol_subtype() - get the subtype + * of EAPOL packet. + * @data: Pointer to EAPOL packet data buffer + * + * This func. returns the subtype of EAPOL packet. + * + * Return: subtype of the EAPOL packet. + */ +static inline enum qdf_proto_subtype +qdf_nbuf_data_get_eapol_subtype(uint8_t *data) +{ + return __qdf_nbuf_data_get_eapol_subtype(data); +} + +/** + * qdf_nbuf_get_arp_subtype() - get the subtype + * of ARP packet. + * @buf: Pointer to ARP packet buffer + * + * This func. returns the subtype of ARP packet. + * + * Return: subtype of the ARP packet. + */ +static inline enum qdf_proto_subtype +qdf_nbuf_get_arp_subtype(qdf_nbuf_t buf) +{ + return __qdf_nbuf_data_get_arp_subtype(qdf_nbuf_data(buf)); +} + +/** + * qdf_nbuf_data_get_arp_subtype() - get the subtype + * of ARP packet. + * @data: Pointer to ARP packet data buffer + * + * This func. returns the subtype of ARP packet. + * + * Return: subtype of the ARP packet. + */ +static inline enum qdf_proto_subtype +qdf_nbuf_data_get_arp_subtype(uint8_t *data) +{ + return __qdf_nbuf_data_get_arp_subtype(data); +} + +/** + * qdf_nbuf_get_icmp_subtype() - get the subtype + * of IPV4 ICMP packet. + * @buf: Pointer to IPV4 ICMP packet buffer + * + * This func. returns the subtype of ICMP packet. + * + * Return: subtype of the ICMP packet. + */ +static inline enum qdf_proto_subtype +qdf_nbuf_get_icmp_subtype(qdf_nbuf_t buf) +{ + return __qdf_nbuf_data_get_icmp_subtype(qdf_nbuf_data(buf)); +} + +/** + * qdf_nbuf_data_get_icmp_subtype() - get the subtype + * of IPV4 ICMP packet. + * @data: Pointer to IPV4 ICMP packet data buffer + * + * This func. returns the subtype of ICMP packet. + * + * Return: subtype of the ICMP packet. + */ +static inline enum qdf_proto_subtype +qdf_nbuf_data_get_icmp_subtype(uint8_t *data) +{ + return __qdf_nbuf_data_get_icmp_subtype(data); +} + +/** + * qdf_nbuf_get_icmpv6_subtype() - get the subtype + * of IPV6 ICMPV6 packet. + * @buf: Pointer to IPV6 ICMPV6 packet buffer + * + * This func. returns the subtype of ICMPV6 packet. + * + * Return: subtype of the ICMPV6 packet. + */ +static inline enum qdf_proto_subtype +qdf_nbuf_get_icmpv6_subtype(qdf_nbuf_t buf) +{ + return __qdf_nbuf_data_get_icmpv6_subtype(qdf_nbuf_data(buf)); +} + +/** + * qdf_nbuf_data_get_icmpv6_subtype() - get the subtype + * of IPV6 ICMPV6 packet. + * @data: Pointer to IPV6 ICMPV6 packet data buffer + * + * This func. returns the subtype of ICMPV6 packet. + * + * Return: subtype of the ICMPV6 packet. + */ +static inline enum qdf_proto_subtype +qdf_nbuf_data_get_icmpv6_subtype(uint8_t *data) +{ + return __qdf_nbuf_data_get_icmpv6_subtype(data); +} + +/** + * qdf_nbuf_data_get_ipv4_proto() - get the proto type + * of IPV4 packet. + * @data: Pointer to IPV4 packet data buffer + * + * This func. returns the proto type of IPV4 packet. + * + * Return: proto type of IPV4 packet. + */ +static inline uint8_t +qdf_nbuf_data_get_ipv4_proto(uint8_t *data) +{ + return __qdf_nbuf_data_get_ipv4_proto(data); +} + +/** + * qdf_nbuf_data_get_ipv6_proto() - get the proto type + * of IPV6 packet. + * @data: Pointer to IPV6 packet data buffer + * + * This func. returns the proto type of IPV6 packet. + * + * Return: proto type of IPV6 packet. + */ +static inline uint8_t +qdf_nbuf_data_get_ipv6_proto(uint8_t *data) +{ + return __qdf_nbuf_data_get_ipv6_proto(data); +} + +/** + * qdf_nbuf_is_ipv4_pkt() - check if packet is a ipv4 packet or not + * @buf: buffer + * + * This api is for Tx packets. + * + * Return: true if packet is ipv4 packet + */ +static inline +bool qdf_nbuf_is_ipv4_pkt(qdf_nbuf_t buf) +{ + return __qdf_nbuf_data_is_ipv4_pkt(qdf_nbuf_data(buf)); +} + +/** + * qdf_nbuf_data_is_ipv4_pkt() - check if packet is a ipv4 packet or not + * @data: data + * + * This api is for Tx packets. + * + * Return: true if packet is ipv4 packet + */ +static inline +bool qdf_nbuf_data_is_ipv4_pkt(uint8_t *data) +{ + return __qdf_nbuf_data_is_ipv4_pkt(data); +} + +/** + * qdf_nbuf_is_ipv4_dhcp_pkt() - check if packet is a dhcp packet or not + * @buf: buffer + * + * This api is for ipv4 packet. + * + * Return: true if packet is DHCP packet + */ +static inline +bool qdf_nbuf_is_ipv4_dhcp_pkt(qdf_nbuf_t buf) +{ + return __qdf_nbuf_data_is_ipv4_dhcp_pkt(qdf_nbuf_data(buf)); +} + +/** + * qdf_nbuf_data_is_ipv4_dhcp_pkt() - check if it is DHCP packet. + * @data: Pointer to DHCP packet data buffer + * + * This func. checks whether it is a DHCP packet or not. + * + * Return: true if it is a DHCP packet + * false if not + */ +static inline +bool qdf_nbuf_data_is_ipv4_dhcp_pkt(uint8_t *data) +{ + return __qdf_nbuf_data_is_ipv4_dhcp_pkt(data); +} + +/** + * qdf_nbuf_is_ipv4_eapol_pkt() - check if packet is a eapol packet or not + * @buf: buffer + * + * This api is for ipv4 packet. + * + * Return: true if packet is EAPOL packet + */ +static inline +bool qdf_nbuf_is_ipv4_eapol_pkt(qdf_nbuf_t buf) +{ + return __qdf_nbuf_data_is_ipv4_eapol_pkt(qdf_nbuf_data(buf)); +} + +/** + * qdf_nbuf_data_is_ipv4_eapol_pkt() - check if it is EAPOL packet. + * @data: Pointer to EAPOL packet data buffer + * + * This func. checks whether it is a EAPOL packet or not. + * + * Return: true if it is a EAPOL packet + * false if not + */ +static inline +bool qdf_nbuf_data_is_ipv4_eapol_pkt(uint8_t *data) +{ + return __qdf_nbuf_data_is_ipv4_eapol_pkt(data); +} + +/** + * qdf_nbuf_is_ipv4_wapi_pkt() - check if packet is a wapi packet or not + * @buf: buffer + * + * This api is for ipv4 packet. + * + * Return: true if packet is WAPI packet + */ +static inline +bool qdf_nbuf_is_ipv4_wapi_pkt(qdf_nbuf_t buf) +{ + return __qdf_nbuf_is_ipv4_wapi_pkt(buf); +} + +/** + * qdf_nbuf_is_ipv4_arp_pkt() - check if packet is a arp packet or not + * @buf: buffer + * + * This api is for ipv4 packet. + * + * Return: true if packet is ARP packet + */ +static inline +bool qdf_nbuf_is_ipv4_arp_pkt(qdf_nbuf_t buf) +{ + return __qdf_nbuf_data_is_ipv4_arp_pkt(qdf_nbuf_data(buf)); +} + +/** + * qdf_nbuf_data_is_ipv4_arp_pkt() - check if it is ARP packet. + * @data: Pointer to ARP packet data buffer + * + * This func. checks whether it is a ARP packet or not. + * + * Return: TRUE if it is a ARP packet + * FALSE if not + */ +static inline +bool qdf_nbuf_data_is_ipv4_arp_pkt(uint8_t *data) +{ + return __qdf_nbuf_data_is_ipv4_arp_pkt(data); +} + +/** + * qdf_nbuf_data_is_arp_req() - check if ARP packet is request. + * @buf: buffer + * + * This func. checks whether it is a ARP request or not. + * + * Return: true if it is a ARP request or fALSE if not + */ +static inline +bool qdf_nbuf_data_is_arp_req(qdf_nbuf_t buf) +{ + return __qdf_nbuf_data_is_arp_req(qdf_nbuf_data(buf)); +} + +/** + * qdf_nbuf_data_is_arp_rsp() - check if ARP packet is response. + * @buf: buffer + * + * This func. checks whether it is a ARP response or not. + * + * Return: true if it is a ARP response or fALSE if not + */ +static inline +bool qdf_nbuf_data_is_arp_rsp(qdf_nbuf_t buf) +{ + return __qdf_nbuf_data_is_arp_rsp(qdf_nbuf_data(buf)); +} + +/** + * qdf_nbuf_data_get_arp_src_ip() - get ARP packet source IP gateway. + * @buf: buffer + * + * Return: ARP packet source IP value. + */ +static inline +uint32_t qdf_nbuf_get_arp_src_ip(qdf_nbuf_t buf) +{ + return __qdf_nbuf_get_arp_src_ip(qdf_nbuf_data(buf)); +} + +/** + * qdf_nbuf_data_get_arp_tgt_ip() - get ARP packet target IP gateway. + * @buf: buffer + * + * Return: ARP packet target IP value. + */ +static inline +uint32_t qdf_nbuf_get_arp_tgt_ip(qdf_nbuf_t buf) +{ + return __qdf_nbuf_get_arp_tgt_ip(qdf_nbuf_data(buf)); +} + +/** + * qdf_nbuf_is_ipv6_pkt() - check if it is IPV6 packet. + * @buf: Pointer to IPV6 packet buffer + * + * This func. checks whether it is a IPV6 packet or not. + * + * Return: TRUE if it is a IPV6 packet + * FALSE if not + */ +static inline +bool qdf_nbuf_is_ipv6_pkt(qdf_nbuf_t buf) +{ + return __qdf_nbuf_data_is_ipv6_pkt(qdf_nbuf_data(buf)); +} + +/** + * qdf_nbuf_data_is_ipv6_pkt() - check if it is IPV6 packet. + * @data: Pointer to IPV6 packet data buffer + * + * This func. checks whether it is a IPV6 packet or not. + * + * Return: TRUE if it is a IPV6 packet + * FALSE if not + */ +static inline +bool qdf_nbuf_data_is_ipv6_pkt(uint8_t *data) +{ + return __qdf_nbuf_data_is_ipv6_pkt(data); +} + +/** + * qdf_nbuf_data_is_ipv4_mcast_pkt() - check if it is IPV4 multicast packet. + * @data: Pointer to IPV4 packet data buffer + * + * This func. checks whether it is a IPV4 multicast packet or not. + * + * Return: TRUE if it is a IPV4 multicast packet + * FALSE if not + */ +static inline +bool qdf_nbuf_data_is_ipv4_mcast_pkt(uint8_t *data) +{ + return __qdf_nbuf_data_is_ipv4_mcast_pkt(data); +} + +/** + * qdf_nbuf_data_is_ipv6_mcast_pkt() - check if it is IPV6 multicast packet. + * @data: Pointer to IPV6 packet data buffer + * + * This func. checks whether it is a IPV6 multicast packet or not. + * + * Return: TRUE if it is a IPV6 multicast packet + * FALSE if not + */ +static inline +bool qdf_nbuf_data_is_ipv6_mcast_pkt(uint8_t *data) +{ + return __qdf_nbuf_data_is_ipv6_mcast_pkt(data); +} + +/** + * qdf_nbuf_is_icmp_pkt() - check if it is IPV4 ICMP packet. + * @buf: Pointer to IPV4 ICMP packet buffer + * + * This func. checks whether it is a ICMP packet or not. + * + * Return: TRUE if it is a ICMP packet + * FALSE if not + */ +static inline +bool qdf_nbuf_is_icmp_pkt(qdf_nbuf_t buf) +{ + return __qdf_nbuf_data_is_icmp_pkt(qdf_nbuf_data(buf)); +} + +/** + * qdf_nbuf_data_is_icmp_pkt() - check if it is IPV4 ICMP packet. + * @data: Pointer to IPV4 ICMP packet data buffer + * + * This func. checks whether it is a ICMP packet or not. + * + * Return: TRUE if it is a ICMP packet + * FALSE if not + */ +static inline +bool qdf_nbuf_data_is_icmp_pkt(uint8_t *data) +{ + return __qdf_nbuf_data_is_icmp_pkt(data); +} + +/** + * qdf_nbuf_is_icmpv6_pkt() - check if it is IPV6 ICMPV6 packet. + * @buf: Pointer to IPV6 ICMPV6 packet buffer + * + * This func. checks whether it is a ICMPV6 packet or not. + * + * Return: TRUE if it is a ICMPV6 packet + * FALSE if not + */ +static inline +bool qdf_nbuf_is_icmpv6_pkt(qdf_nbuf_t buf) +{ + return __qdf_nbuf_data_is_icmpv6_pkt(qdf_nbuf_data(buf)); +} + +/** + * qdf_nbuf_data_is_icmpv6_pkt() - check if it is IPV6 ICMPV6 packet. + * @data: Pointer to IPV6 ICMPV6 packet data buffer + * + * This func. checks whether it is a ICMPV6 packet or not. + * + * Return: TRUE if it is a ICMPV6 packet + * FALSE if not + */ +static inline +bool qdf_nbuf_data_is_icmpv6_pkt(uint8_t *data) +{ + return __qdf_nbuf_data_is_icmpv6_pkt(data); +} + +/** + * qdf_nbuf_is_ipv4_udp_pkt() - check if it is IPV4 UDP packet. + * @buf: Pointer to IPV4 UDP packet buffer + * + * This func. checks whether it is a IPV4 UDP packet or not. + * + * Return: TRUE if it is a IPV4 UDP packet + * FALSE if not + */ +static inline +bool qdf_nbuf_is_ipv4_udp_pkt(qdf_nbuf_t buf) +{ + return __qdf_nbuf_data_is_ipv4_udp_pkt(qdf_nbuf_data(buf)); +} + +/** + * qdf_nbuf_data_is_ipv4_udp_pkt() - check if it is IPV4 UDP packet. + * @data: Pointer to IPV4 UDP packet data buffer + * + * This func. checks whether it is a IPV4 UDP packet or not. + * + * Return: TRUE if it is a IPV4 UDP packet + * FALSE if not + */ +static inline +bool qdf_nbuf_data_is_ipv4_udp_pkt(uint8_t *data) +{ + return __qdf_nbuf_data_is_ipv4_udp_pkt(data); +} + +/** + * qdf_nbuf_is_ipv4_tcp_pkt() - check if it is IPV4 TCP packet. + * @buf: Pointer to IPV4 TCP packet buffer + * + * This func. checks whether it is a IPV4 TCP packet or not. + * + * Return: TRUE if it is a IPV4 TCP packet + * FALSE if not + */ +static inline +bool qdf_nbuf_is_ipv4_tcp_pkt(qdf_nbuf_t buf) +{ + return __qdf_nbuf_data_is_ipv4_tcp_pkt(qdf_nbuf_data(buf)); +} + +/** + * qdf_nbuf_data_is_ipv4_tcp_pkt() - check if it is IPV4 TCP packet. + * @data: Pointer to IPV4 TCP packet data buffer + * + * This func. checks whether it is a IPV4 TCP packet or not. + * + * Return: TRUE if it is a IPV4 TCP packet + * FALSE if not + */ +static inline +bool qdf_nbuf_data_is_ipv4_tcp_pkt(uint8_t *data) +{ + return __qdf_nbuf_data_is_ipv4_tcp_pkt(data); +} + +/** + * qdf_nbuf_is_ipv6_udp_pkt() - check if it is IPV6 UDP packet. + * @buf: Pointer to IPV6 UDP packet buffer + * + * This func. checks whether it is a IPV6 UDP packet or not. + * + * Return: TRUE if it is a IPV6 UDP packet + * FALSE if not + */ +static inline +bool qdf_nbuf_is_ipv6_udp_pkt(qdf_nbuf_t buf) +{ + return __qdf_nbuf_data_is_ipv6_udp_pkt(qdf_nbuf_data(buf)); +} + +/** + * qdf_nbuf_data_is_ipv6_udp_pkt() - check if it is IPV6 UDP packet. + * @data: Pointer to IPV6 UDP packet data buffer + * + * This func. checks whether it is a IPV6 UDP packet or not. + * + * Return: TRUE if it is a IPV6 UDP packet + * FALSE if not + */ +static inline +bool qdf_nbuf_data_is_ipv6_udp_pkt(uint8_t *data) +{ + return __qdf_nbuf_data_is_ipv6_udp_pkt(data); +} + +/** + * qdf_nbuf_is_ipv6_tcp_pkt() - check if it is IPV6 TCP packet. + * @buf: Pointer to IPV6 TCP packet buffer + * + * This func. checks whether it is a IPV6 TCP packet or not. + * + * Return: TRUE if it is a IPV6 TCP packet + * FALSE if not + */ +static inline +bool qdf_nbuf_is_ipv6_tcp_pkt(qdf_nbuf_t buf) +{ + return __qdf_nbuf_data_is_ipv6_tcp_pkt(qdf_nbuf_data(buf)); +} + +/** + * qdf_nbuf_data_is_ipv6_tcp_pkt() - check if it is IPV6 TCP packet. + * @data: Pointer to IPV6 TCP packet data buffer + * + * This func. checks whether it is a IPV6 TCP packet or not. + * + * Return: TRUE if it is a IPV6 TCP packet + * FALSE if not + */ +static inline +bool qdf_nbuf_data_is_ipv6_tcp_pkt(uint8_t *data) +{ + return __qdf_nbuf_data_is_ipv6_tcp_pkt(data); +} + +/** + * qdf_invalidate_range() - invalidate virtual address range + * @start: start address of the address range + * @end: end address of the address range + * + * Note that this function does not write back the cache entries. + * + * Return: none + */ +static inline void qdf_invalidate_range(void *start, void *end) +{ + __qdf_invalidate_range(start, end); +} + +/** + * qdf_nbuf_reset_num_frags() - decrement the number of fragments + * @buf: Network buffer + * + * Return: Number of fragments + */ +static inline void qdf_nbuf_reset_num_frags(qdf_nbuf_t buf) +{ + __qdf_nbuf_reset_num_frags(buf); +} + +/** + * qdf_dmaaddr_to_32s - return high and low parts of dma_addr + * + * Returns the high and low 32-bits of the DMA addr in the provided ptrs + * + * Return: N/A + */ +static inline void qdf_dmaaddr_to_32s(qdf_dma_addr_t dmaaddr, + uint32_t *lo, uint32_t *hi) +{ + return __qdf_dmaaddr_to_32s(dmaaddr, lo, hi); +} + +/** + * qdf_nbuf_is_tso() - is the network buffer a jumbo packet? + * @buf: Network buffer + * + * Return: 1 - this is a jumbo packet 0 - not a jumbo packet + */ +static inline uint8_t qdf_nbuf_is_tso(qdf_nbuf_t nbuf) +{ + return __qdf_nbuf_is_tso(nbuf); +} + +/** + * qdf_nbuf_get_tso_info() - function to divide a jumbo TSO + * network buffer into segments + * @nbuf: network buffer to be segmented + * @tso_info: This is the output. The information about the + * TSO segments will be populated within this. + * + * This function fragments a TCP jumbo packet into smaller + * segments to be transmitted by the driver. It chains the TSO + * segments created into a list. + * + * Return: number of TSO segments + */ +static inline uint32_t qdf_nbuf_get_tso_info(qdf_device_t osdev, + qdf_nbuf_t nbuf, struct qdf_tso_info_t *tso_info) +{ + return __qdf_nbuf_get_tso_info(osdev, nbuf, tso_info); +} + +/** + * qdf_nbuf_unmap_tso_segment() - function to dma unmap TSO segment element + * + * @osdev: qdf device handle + * @tso_seg: TSO segment element to be unmapped + * @is_last_seg: whether this is last tso seg or not + * + * Return: none + */ +static inline void qdf_nbuf_unmap_tso_segment(qdf_device_t osdev, + struct qdf_tso_seg_elem_t *tso_seg, + bool is_last_seg) +{ + return __qdf_nbuf_unmap_tso_segment(osdev, tso_seg, is_last_seg); +} + +/** + * qdf_nbuf_get_tso_num_seg() - function to calculate the number + * of TCP segments within the TSO jumbo packet + * @nbuf: TSO jumbo network buffer to be segmented + * + * This function calculates the number of TCP segments that the + network buffer can be divided into. + * + * Return: number of TCP segments + */ +static inline uint32_t qdf_nbuf_get_tso_num_seg(qdf_nbuf_t nbuf) +{ + return __qdf_nbuf_get_tso_num_seg(nbuf); +} + +/** + * qdf_nbuf_inc_users() - function to increment the number of + * users referencing this network buffer + * + * @nbuf: network buffer + * + * This function increments the number of users referencing this + * network buffer + * + * Return: the network buffer + */ +static inline qdf_nbuf_t qdf_nbuf_inc_users(qdf_nbuf_t nbuf) +{ + return __qdf_nbuf_inc_users(nbuf); +} + +/** + * qdf_nbuf_get_users() - function to get the number of users referencing this + * network buffer + * + * @nbuf: network buffer + * + * Return: number of user references to nbuf. + */ +static inline int qdf_nbuf_get_users(qdf_nbuf_t nbuf) +{ + return __qdf_nbuf_get_users(nbuf); +} + +/** + * qdf_nbuf_data_attr_get() - Get data_attr field from cvg_nbuf_cb + * + * @nbuf: Network buffer (skb on linux) + * + * This function returns the values of data_attr field + * in struct cvg_nbuf_cb{}, to which skb->cb is typecast. + * This value is actually the value programmed in CE descriptor. + * + * Return: Value of data_attr + */ +static inline uint32_t qdf_nbuf_data_attr_get(qdf_nbuf_t buf) +{ + return __qdf_nbuf_data_attr_get(buf); +} + +/** + * qdf_nbuf_data_attr_set() - Sets data_attr field in cvg_nbuf_cb + * + * @nbuf: Network buffer (skb on linux) + * @data_attr: Value to be stored cvg_nbuf_cb->data_attr + * + * This function stores the value to be programmed in CE + * descriptor as part skb->cb which is typecast to struct cvg_nbuf_cb{} + * + * Return: void + */ +static inline +void qdf_nbuf_data_attr_set(qdf_nbuf_t buf, uint32_t data_attr) +{ + __qdf_nbuf_data_attr_set(buf, data_attr); +} + +/** + * qdf_nbuf_tx_info_get() - Parse skb and get Tx metadata + * + * @nbuf: Network buffer (skb on linux) + * + * This function parses the payload to figure out relevant + * Tx meta-data e.g. whether to enable tx_classify bit + * in CE. + * + * Return: void + */ +#define qdf_nbuf_tx_info_get __qdf_nbuf_tx_info_get + +void qdf_nbuf_set_state(qdf_nbuf_t nbuf, uint8_t current_state); +void qdf_nbuf_tx_desc_count_display(void); +void qdf_nbuf_tx_desc_count_clear(void); + +static inline qdf_nbuf_t +qdf_nbuf_realloc_headroom(qdf_nbuf_t buf, uint32_t headroom) +{ + return __qdf_nbuf_realloc_headroom(buf, headroom); +} + +static inline qdf_nbuf_t +qdf_nbuf_realloc_tailroom(qdf_nbuf_t buf, uint32_t tailroom) +{ + return __qdf_nbuf_realloc_tailroom(buf, tailroom); +} + +static inline qdf_nbuf_t +qdf_nbuf_expand(qdf_nbuf_t buf, uint32_t headroom, uint32_t tailroom) +{ + return __qdf_nbuf_expand(buf, headroom, tailroom); +} + +static inline qdf_nbuf_t +qdf_nbuf_unshare(qdf_nbuf_t buf) +{ + return __qdf_nbuf_unshare(buf); +} + +static inline bool +qdf_nbuf_is_cloned(qdf_nbuf_t buf) +{ + return __qdf_nbuf_is_cloned(buf); +} + +static inline void +qdf_nbuf_frag_info(qdf_nbuf_t buf, qdf_sglist_t *sg) +{ + __qdf_nbuf_frag_info(buf, sg); +} + +static inline qdf_nbuf_tx_cksum_t +qdf_nbuf_tx_cksum_info(qdf_nbuf_t buf, uint8_t **hdr_off, uint8_t **where) +{ + return __qdf_nbuf_tx_cksum_info(buf, hdr_off, where); +} + +static inline void qdf_nbuf_reset_ctxt(__qdf_nbuf_t nbuf) +{ + __qdf_nbuf_reset_ctxt(nbuf); +} + +static inline void +qdf_nbuf_set_rx_info(__qdf_nbuf_t nbuf, void *info, uint32_t len) +{ + __qdf_nbuf_set_rx_info(nbuf, info, len); +} + +static inline void *qdf_nbuf_get_rx_info(__qdf_nbuf_t nbuf) +{ + return __qdf_nbuf_get_rx_info(nbuf); +} + +static inline void qdf_nbuf_init(qdf_nbuf_t buf) +{ + __qdf_nbuf_init(buf); +} + +static inline void *qdf_nbuf_network_header(qdf_nbuf_t buf) +{ + return __qdf_nbuf_network_header(buf); +} + +static inline void *qdf_nbuf_transport_header(qdf_nbuf_t buf) +{ + return __qdf_nbuf_transport_header(buf); +} + +static inline qdf_size_t qdf_nbuf_tcp_tso_size(qdf_nbuf_t buf) +{ + return __qdf_nbuf_tcp_tso_size(buf); +} + +static inline void *qdf_nbuf_get_cb(qdf_nbuf_t nbuf) +{ + return __qdf_nbuf_get_cb(nbuf); +} + +static inline uint32_t qdf_nbuf_get_nr_frags(qdf_nbuf_t nbuf) +{ + return __qdf_nbuf_get_nr_frags(nbuf); +} + +static inline qdf_size_t qdf_nbuf_headlen(qdf_nbuf_t buf) +{ + return __qdf_nbuf_headlen(buf); +} + +static inline QDF_STATUS qdf_nbuf_frag_map(qdf_device_t osdev, + qdf_nbuf_t buf, int offset, + qdf_dma_dir_t dir, int cur_frag) +{ + return __qdf_nbuf_frag_map(osdev, buf, offset, dir, cur_frag); +} + +static inline bool qdf_nbuf_tso_tcp_v4(qdf_nbuf_t buf) +{ + return __qdf_nbuf_tso_tcp_v4(buf); +} + +static inline bool qdf_nbuf_tso_tcp_v6(qdf_nbuf_t buf) +{ + return __qdf_nbuf_tso_tcp_v6(buf); +} + +static inline uint32_t qdf_nbuf_tcp_seq(qdf_nbuf_t buf) +{ + return __qdf_nbuf_tcp_seq(buf); +} + +static inline qdf_size_t qdf_nbuf_l2l3l4_hdr_len(qdf_nbuf_t buf) +{ + return __qdf_nbuf_l2l3l4_hdr_len(buf); +} + +static inline bool qdf_nbuf_is_nonlinear(qdf_nbuf_t buf) +{ + return __qdf_nbuf_is_nonlinear(buf); +} + +static inline uint32_t +qdf_nbuf_get_frag_size(qdf_nbuf_t buf, uint32_t frag_num) +{ + return __qdf_nbuf_get_frag_size(buf, frag_num); +} + +static inline uint32_t qdf_nbuf_get_priority(qdf_nbuf_t buf) +{ + return __qdf_nbuf_get_priority(buf); +} + +static inline void qdf_nbuf_set_priority(qdf_nbuf_t buf, uint32_t p) +{ + __qdf_nbuf_set_priority(buf, p); +} + +static inline uint16_t +qdf_nbuf_get_queue_mapping(qdf_nbuf_t buf) +{ + return __qdf_nbuf_get_queue_mapping(buf); +} + +static inline uint8_t * +qdf_nbuf_get_priv_ptr(qdf_nbuf_t buf) +{ + return __qdf_nbuf_get_priv_ptr(buf); +} + +/** + * qdf_nbuf_update_radiotap() - update radiotap at head of nbuf. + * @rx_status: rx_status containing required info to update radiotap + * @nbuf: Pointer to nbuf + * @headroom_sz: Available headroom size + * + * Return: radiotap length. + */ +unsigned int qdf_nbuf_update_radiotap(struct mon_rx_status *rx_status, + qdf_nbuf_t nbuf, uint32_t headroom_sz); + +/** + * qdf_nbuf_mark_wakeup_frame() - mark wakeup frame. + * @buf: Pointer to nbuf + * + * Return: None + */ +static inline void +qdf_nbuf_mark_wakeup_frame(qdf_nbuf_t buf) +{ + __qdf_nbuf_mark_wakeup_frame(buf); +} + +/** + * qdf_nbuf_reg_free_cb - Registers nbuf free callback + * @cb_func_ptr: Callback pointer + * + * This function registers nbuf free callback + * + * Return: void + */ +static inline void +qdf_nbuf_reg_free_cb(qdf_nbuf_free_t cb_func_ptr) +{ + __qdf_nbuf_reg_free_cb(cb_func_ptr); +} + +#endif /* _QDF_NBUF_H */ diff --git a/drivers/staging/qca-wifi-host-cmn/qdf/inc/qdf_net_types.h b/drivers/staging/qca-wifi-host-cmn/qdf/inc/qdf_net_types.h new file mode 100644 index 0000000000000000000000000000000000000000..9b4fd6d0ea3baef14e2cc4bc803d67d19363538a --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/qdf/inc/qdf_net_types.h @@ -0,0 +1,458 @@ +/* + * Copyright (c) 2014-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: qdf_net_types + * This file defines types used in the networking stack abstraction. + */ + +#ifndef _QDF_NET_TYPES_H +#define _QDF_NET_TYPES_H + +#include /* uint8_t, etc. */ +#include + +/* Extended Traffic ID passed to target if the TID is unknown */ +#define QDF_NBUF_TX_EXT_TID_INVALID 0x1f + +/** + * qdf_nbuf_exemption_type - QDF net buf exemption types for encryption + * @QDF_NBUF_EXEMPT_NO_EXEMPTION: No exemption + * @QDF_NBUF_EXEMPT_ALWAYS: Exempt always + * @QDF_NBUF_EXEMPT_ON_KEY_MAPPING_KEY_UNAVAILABLE: Exempt on key mapping + */ +enum qdf_nbuf_exemption_type { + QDF_NBUF_EXEMPT_NO_EXEMPTION = 0, + QDF_NBUF_EXEMPT_ALWAYS, + QDF_NBUF_EXEMPT_ON_KEY_MAPPING_KEY_UNAVAILABLE +}; + +typedef __wsum_t wsum_t; +typedef __in6_addr_t in6_addr_t; + + +#define QDF_NET_MAC_ADDR_MAX_LEN 6 +#define QDF_NET_IF_NAME_SIZE 64 +#define QDF_NET_ETH_LEN QDF_NET_MAC_ADDR_MAX_LEN +#define QDF_NET_MAX_MCAST_ADDR 64 + +/* Extended Traffic ID passed to target if the TID is unknown */ +#define QDF_NBUF_TX_EXT_TID_INVALID 0x1f + +#define QDF_ETH_TYPE_IPV4 0x0800 /* IPV4 */ +#define QDF_ETH_TYPE_IPV6 0x86dd /* IPV6 */ + +typedef struct qdf_net_ethaddr { + uint8_t addr[QDF_NET_ETH_LEN]; +} qdf_net_ethaddr_t; + + +typedef struct { + uint16_t source; + uint16_t dest; + uint32_t seq; + uint32_t ack_seq; +#if defined(QDF_LITTLE_ENDIAN_MACHINE) + uint16_t res1:4, + doff:4, + fin:1, + syn:1, + rst:1, + psh:1, + ack:1, + urg:1, + ece:1, + cwr:1; +#elif defined(QDF_BIG_ENDIAN_MACHINE) + uint16_t doff:4, + res1:4, + cwr:1, + ece:1, + urg:1, + ack:1, + psh:1, + rst:1, + syn:1, + fin:1; +#else +#error "Adjust your byte order" +#endif + uint16_t window; + uint16_t check; + uint16_t urg_ptr; +} qdf_net_tcphdr_t; + +typedef struct { +#if defined(QDF_LITTLE_ENDIAN_MACHINE) + uint8_t ip_hl:4, + ip_version:4; +#elif defined(QDF_BIG_ENDIAN_MACHINE) + uint8_t ip_version:4, + ip_hl:4; +#else +#error "Please fix" +#endif + uint8_t ip_tos; + uint16_t ip_len; + uint16_t ip_id; + uint16_t ip_frag_off; + uint8_t ip_ttl; + uint8_t ip_proto; + uint16_t ip_check; + uint32_t ip_saddr; + uint32_t ip_daddr; + /*The options start here. */ +} qdf_net_iphdr_t; + +/* V3 group record types [grec_type] */ +#define IGMPV3_MODE_IS_INCLUDE 1 +#define IGMPV3_MODE_IS_EXCLUDE 2 +#define IGMPV3_CHANGE_TO_INCLUDE 3 +#define IGMPV3_CHANGE_TO_EXCLUDE 4 +#define IGMPV3_ALLOW_NEW_SOURCES 5 +#define IGMPV3_BLOCK_OLD_SOURCES 6 + +/** + * qdf_net_cmd_vid_t - Command for set/unset vid + */ +typedef uint16_t qdf_net_cmd_vid_t ; /*get/set vlan id*/ + +/** + * typedef qdf_nbuf_tx_cksum_t - transmit checksum offload types + * @QDF_NBUF_TX_CKSUM_NONE: No checksum offload + * @QDF_NBUF_TX_CKSUM_IP: IP header checksum offload + * @QDF_NBUF_TX_CKSUM_TCP_UDP: TCP/UDP checksum offload + * @QDF_NBUF_TX_CKSUM_TCP_UDP_IP: TCP/UDP and IP header checksum offload + */ + +typedef enum { + QDF_NBUF_TX_CKSUM_NONE, + QDF_NBUF_TX_CKSUM_IP, + QDF_NBUF_TX_CKSUM_TCP_UDP, + QDF_NBUF_TX_CKSUM_TCP_UDP_IP, + +} qdf_nbuf_tx_cksum_t; + +/** + * typedef qdf_nbuf_l4_rx_cksum_type_t - receive checksum API types + * @QDF_NBUF_RX_CKSUM_TCP: Rx checksum TCP + * @QDF_NBUF_RX_CKSUM_UDP: Rx checksum UDP + * @QDF_NBUF_RX_CKSUM_TCPIPV6: Rx checksum TCP IPV6 + * @QDF_NBUF_RX_CKSUM_UDPIPV6: Rx checksum UDP IPV6 + * @QDF_NBUF_RX_CKSUM_TCP_NOPSEUDOHEADER: Rx checksum TCP no pseudo header + * @QDF_NBUF_RX_CKSUM_UDP_NOPSEUDOHEADER: Rx checksum UDP no pseudo header + * @QDF_NBUF_RX_CKSUM_TCPSUM16: Rx checksum TCP SUM16 + */ +typedef enum { + QDF_NBUF_RX_CKSUM_TCP = 0x0001, + QDF_NBUF_RX_CKSUM_UDP = 0x0002, + QDF_NBUF_RX_CKSUM_TCPIPV6 = 0x0010, + QDF_NBUF_RX_CKSUM_UDPIPV6 = 0x0020, + QDF_NBUF_RX_CKSUM_TCP_NOPSEUDOHEADER = 0x0100, + QDF_NBUF_RX_CKSUM_UDP_NOPSEUDOHEADER = 0x0200, + QDF_NBUF_RX_CKSUM_TCPSUM16 = 0x1000, +} qdf_nbuf_l4_rx_cksum_type_t; + +/** + * typedef qdf_nbuf_l4_rx_cksum_result_t - receive checksum status types + * @QDF_NBUF_RX_CKSUM_NONE: Device failed to checksum + * @QDF_NBUF_RX_CKSUM_TCP_UDP_HW: TCP/UDP cksum successful and value returned + * @QDF_NBUF_RX_CKSUM_TCP_UDP_UNNECESSARY: TCP/UDP cksum successful, no value + */ +typedef enum { + QDF_NBUF_RX_CKSUM_NONE = 0x0000, + QDF_NBUF_RX_CKSUM_TCP_UDP_HW = 0x0010, + QDF_NBUF_RX_CKSUM_TCP_UDP_UNNECESSARY = 0x0020, +} qdf_nbuf_l4_rx_cksum_result_t; + +/** + * typedef qdf_nbuf_rx_cksum_t - receive checksum type + * @l4_type: L4 type + * @l4_result: L4 result + */ +typedef struct { + qdf_nbuf_l4_rx_cksum_type_t l4_type; + qdf_nbuf_l4_rx_cksum_result_t l4_result; + uint32_t val; +} qdf_nbuf_rx_cksum_t; + +#define QDF_ARP_REQ 1 /* ARP request */ +#define QDF_ARP_RSP 2 /* ARP response */ +#define QDF_ARP_RREQ 3 /* RARP request */ +#define QDF_ARP_RRSP 4 /* RARP response */ + +#define QDF_NEXTHDR_ICMP 58 /* ICMP for IPv6. */ + +/* Neighbor Discovery */ +#define QDF_ND_RSOL 133 /* Router Solicitation */ +#define QDF_ND_RADVT 134 /* Router Advertisement */ +#define QDF_ND_NSOL 135 /* Neighbor Solicitation */ +#define QDF_ND_NADVT 136 /* Neighbor Advertisement */ + +/** + * typedef qdf_net_udphdr_t - UDP header info + * @src_port: source port + * @dst_port: destination port + * @udp_len: length + * @udp_cksum: checksum + */ +typedef struct { + uint16_t src_port; + uint16_t dst_port; + uint16_t udp_len; + uint16_t udp_cksum; +} qdf_net_udphdr_t; + +/** + * typedef qdf_net_dhcphdr_t - DHCP header info + * @dhcp_msg_type: message type + * @dhcp_hw_type: hardware type + * @dhcp_hw_addr_len: hardware address length + * @dhcp_num_hops: number of hops + * @dhcp_transc_id: transaction id + * @dhcp_secs_elapsed: time elapsed + * @dhcp_flags: flags + * @dhcp_ciaddr: client IP + * @dhcp_yiaddr: device IP + * @dhcp_siaddr_nip: Server IP + * @dhcp_gateway_nip: relay agent IP + * @dhcp_chaddr: LLC hardware address + * @dhcp_sname: server host name + * @dhcp_file: boot file name + * @dhcp_cookie: cookie + */ +typedef struct { + uint8_t dhcp_msg_type; + uint8_t dhcp_hw_type; + uint8_t dhcp_hw_addr_len; + uint8_t dhcp_num_hops; + uint32_t dhcp_transc_id; + uint16_t dhcp_secs_elapsed; + uint16_t dhcp_flags; + uint32_t dhcp_ciaddr; + uint32_t dhcp_yiaddr; + uint32_t dhcp_siaddr_nip; + uint32_t dhcp_gateway_nip; + uint8_t dhcp_chaddr[16]; + uint8_t dhcp_sname[64]; + uint8_t dhcp_file[128]; + uint8_t dhcp_cookie[4]; +} qdf_net_dhcphdr_t; + + +/** + * qdf_net_vlanhdr_t - Vlan header + */ +typedef struct qdf_net_vlanhdr { + uint16_t tpid; +#if defined(QDF_LITTLE_ENDIAN_MACHINE) + uint16_t vid:12; /* Vlan id*/ + uint8_t cfi:1; /* reserved for CFI, don't use*/ + uint8_t prio:3; /* Priority*/ +#elif defined(QDF_BIG_ENDIAN_MACHINE) + uint8_t prio:3; /* Priority*/ + uint8_t cfi:1; /* reserved for CFI, don't use*/ + uint16_t vid:12; /* Vlan id*/ +#else +#error "Please fix" +#endif +} qdf_net_vlanhdr_t; + +typedef struct qdf_net_vid { +#if defined(QDF_LITTLE_ENDIAN_MACHINE) + uint16_t val:12; + uint8_t res:4; +#elif defined(QDF_BIG_ENDIAN_MACHINE) + uint8_t res:4; + uint16_t val:12; +#else +#error "Please fix" +#endif +} qdf_net_vid_t; + +typedef enum { + QDF_NET_TSO_NONE, + QDF_NET_TSO_IPV4, /**< for tsp ipv4 only*/ + QDF_NET_TSO_ALL, /**< ip4 & ipv6*/ +} qdf_net_tso_type_t; + +/** + * qdf_net_dev_info_t - Basic device info + */ +typedef struct { + uint8_t if_name[QDF_NET_IF_NAME_SIZE]; + uint8_t dev_addr[QDF_NET_MAC_ADDR_MAX_LEN]; + uint16_t header_len; + uint16_t mtu_size; + uint32_t unit; +} qdf_net_dev_info_t; + +/** + * qdf_nbuf_tso_t - For TCP large Segment Offload + */ +typedef struct { + qdf_net_tso_type_t type; + uint16_t mss; + uint8_t hdr_off; +} qdf_nbuf_tso_t; + +/** + * qdf_net_wireless_event_t - Wireless events + * QDF_IEEE80211_ASSOC = station associate (bss mode) + * QDF_IEEE80211_REASSOC = station re-associate (bss mode) + * QDF_IEEE80211_DISASSOC = station disassociate (bss mode) + * QDF_IEEE80211_JOIN = station join (ap mode) + * QDF_IEEE80211_LEAVE = station leave (ap mode) + * QDF_IEEE80211_SCAN = scan complete, results available + * QDF_IEEE80211_REPLAY = sequence counter replay detected + * QDF_IEEE80211_MICHAEL = Michael MIC failure detected + * QDF_IEEE80211_REJOIN = station re-associate (ap mode) + * QDF_CUSTOM_PUSH_BUTTON = WPS push button + */ +typedef enum qdf_net_wireless_events { + QDF_IEEE80211_ASSOC = __QDF_IEEE80211_ASSOC, + QDF_IEEE80211_REASSOC = __QDF_IEEE80211_REASSOC, + QDF_IEEE80211_DISASSOC = __QDF_IEEE80211_DISASSOC, + QDF_IEEE80211_JOIN = __QDF_IEEE80211_JOIN, + QDF_IEEE80211_LEAVE = __QDF_IEEE80211_LEAVE, + QDF_IEEE80211_SCAN = __QDF_IEEE80211_SCAN, + QDF_IEEE80211_REPLAY = __QDF_IEEE80211_REPLAY, + QDF_IEEE80211_MICHAEL = __QDF_IEEE80211_MICHAEL, + QDF_IEEE80211_REJOIN = __QDF_IEEE80211_REJOIN, + QDF_CUSTOM_PUSH_BUTTON = __QDF_CUSTOM_PUSH_BUTTON +} qdf_net_wireless_event_t; + +/** + * qdf_net_ipv6_addr_t - IPv6 Address + */ +typedef struct { + union { + uint8_t u6_addr8[16]; + uint16_t u6_addr16[8]; + uint32_t u6_addr32[4]; + } in6_u; +#define s6_addr32 in6_u.u6_addr32 +} qdf_net_ipv6_addr_t; + +/** + * qdf_net_ipv6hdr_t - IPv6 Header + */ +typedef struct { +#if defined(QDF_LITTLE_ENDIAN_MACHINE) + uint8_t ipv6_priority:4, + ipv6_version:4; +#elif defined(QDF_BIG_ENDIAN_MACHINE) + uint8_t ipv6_version:4, + ipv6_priority:4; +#else +#error "Please fix" +#endif + uint8_t ipv6_flow_lbl[3]; + + uint16_t ipv6_payload_len; + uint8_t ipv6_nexthdr, + ipv6_hop_limit; + + qdf_net_ipv6_addr_t ipv6_saddr, + ipv6_daddr; +} qdf_net_ipv6hdr_t; + +/** + * qdf_net_icmpv6hdr_t - ICMPv6 Header + */ +typedef struct { + uint8_t icmp6_type; + uint8_t icmp6_code; + uint16_t icmp6_cksum; + + union { + uint32_t un_data32[1]; + uint16_t un_data16[2]; + uint8_t un_data8[4]; + + struct { + uint16_t identifier; + uint16_t sequence; + } u_echo; + + struct { +#if defined(QDF_LITTLE_ENDIAN_MACHINE) + uint32_t reserved:5, + override:1, + solicited:1, + router:1, + reserved2:24; +#elif defined(QDF_BIG_ENDIAN_MACHINE) + uint32_t router:1, + solicited:1, + override:1, + reserved:29; +#else +#error "Please fix" +#endif + } u_nd_advt; + + struct { + uint8_t hop_limit; +#if defined(QDF_LITTLE_ENDIAN_MACHINE) + uint8_t reserved:6, + other:1, + managed:1; + +#elif defined(QDF_BIG_ENDIAN_MACHINE) + uint8_t managed:1, + other:1, + reserved:6; +#else +#error "Please fix" +#endif + uint16_t rt_lifetime; + } u_nd_ra; + + } icmp6_dataun; + +} qdf_net_icmpv6hdr_t; + +/** + * qdf_net_nd_msg_t - Neighbor Discovery Message + */ +typedef struct { + qdf_net_icmpv6hdr_t nd_icmph; + qdf_net_ipv6_addr_t nd_target; + uint8_t nd_opt[0]; +} qdf_net_nd_msg_t; + + +static inline int32_t qdf_csum_ipv6(const in6_addr_t *saddr, + const in6_addr_t *daddr, + __u32 len, unsigned short proto, + wsum_t sum) +{ + return (int32_t)__qdf_csum_ipv6(saddr, daddr, len, proto, sum); +} + +#endif /*_QDF_NET_TYPES_H*/ diff --git a/drivers/staging/qca-wifi-host-cmn/qdf/inc/qdf_perf.h b/drivers/staging/qca-wifi-host-cmn/qdf/inc/qdf_perf.h new file mode 100644 index 0000000000000000000000000000000000000000..4350dcc51dee3da8758d625218398110ca398dfb --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/qdf/inc/qdf_perf.h @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: qdf_perf + * This file provides OS abstraction perf API's. + */ + +#ifndef _QDF_PERF_H +#define _QDF_PERF_H + +/* headers */ +#include + +#ifdef QCA_PERF_PROFILING + +/* Typedefs */ +typedef __qdf_perf_id_t qdf_perf_id_t; + +typedef int (*proc_read_t)(char *page, char **start, off_t off, int count, + int *eof, void *data); +typedef int (*proc_write_t)(struct file *file, const char *buf, + unsigned long count, void *data); +typedef void (*perf_sample_t)(struct qdf_perf_entry *entry, + uint8_t done); + +typedef void (*perf_init_t)(struct qdf_perf_entry *entry, uint32_t def_val); + +/** + * typedef proc_api_tbl_t - contains functions to read, write to proc FS + * @proc_read: function pointer to read function + * @proc_write: function pointer to write function + * @sample: function pointer to sample function + * @init: function pointer to init function + * @def_val: int contains default value + */ +typedef struct proc_api_tbl { + proc_read_t proc_read; + proc_write_t proc_write; + perf_sample_t sample; + perf_init_t init; + uint32_t def_val; +} proc_api_tbl_t; + +proc_api_tbl_t api_tbl[]; + +/* Macros */ +#define INIT_API(name, val) { \ + .proc_read = read_##name, \ + .proc_write = write_##name, \ + .sample = sample_event, \ + .init = init_##name, \ + .def_val = val, \ +} + +#define PERF_ENTRY(hdl) ((qdf_perf_entry_t *)hdl) + +#define qdf_perf_init(_parent, _id, _ctr_type) \ + __qdf_perf_init((_parent), (_id), (_ctr_type)) + +#define qdf_perf_destroy(_id) __qdf_perf_destroy((_id)) + +#define qdf_perf_start(_id) __qdf_perf_start((_id)) + +#define qdf_perf_end(_id) __qdf_perf_end((_id)) + +/* Extern declarations */ +extern __qdf_perf_id_t + __qdf_perf_init(qdf_perf_id_t parent, + uint8_t *id_name, + qdf_perf_cntr_t type)(__qdf_perf_id_t parent, + uint8_t *id_name, + uint32_t type); + +extern bool __qdf_perf_destroy(qdf_perf_id_t id)(__qdf_perf_id_t id); + +extern void __qdf_perf_start(qdf_perf_id_t id)(__qdf_perf_id_t id); +extern void __qdf_perf_end(qdf_perf_id_t id)(__qdf_perf_id_t id); + +extern int +qdf_perfmod_init(void); +extern void +qdf_perfmod_exit(void); + +#else /* !QCA_PERF_PROFILING */ + +#define qdf_perfmod_init() +#define qdf_perfmod_exit() +#define DECLARE_N_EXPORT_PERF_CNTR(id) +#define START_PERF_CNTR(_id, _name) +#define END_PERF_CNTR(_id) + +#endif /* QCA_PERF_PROFILING */ + +#endif /* end of _QDF_PERF_H */ diff --git a/drivers/staging/qca-wifi-host-cmn/qdf/inc/qdf_status.h b/drivers/staging/qca-wifi-host-cmn/qdf/inc/qdf_status.h new file mode 100644 index 0000000000000000000000000000000000000000..0a58c4eb48436c71a1ebaf859c7594e6bbebce38 --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/qdf/inc/qdf_status.h @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2014-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: qdf_status + * QCA driver framework (QDF) status codes + * Basic status codes/definitions used by QDF + */ + +#if !defined(__QDF_STATUS_H) +#define __QDF_STATUS_H + +/** + * typedef QDF_STATUS - QDF error codes + * @QDF_STATUS_SUCCESS: success + * @QDF_STATUS_E_RESOURCES: system resource(other than memory) not available + * @QDF_STATUS_E_NOMEM: not enough memory + * @QDF_STATUS_E_AGAIN: try again + * @QDF_STATUS_E_INVAL: invalid request + * @QDF_STATUS_E_FAULT: system fault + * @QDF_STATUS_E_ALREADY: another request already in progress + * @QDF_STATUS_E_BADMSG: bad message + * @QDF_STATUS_E_BUSY: device or resource busy + * @QDF_STATUS_E_CANCELED: request cancelled + * @QDF_STATUS_E_ABORTED: request aborted + * @QDF_STATUS_E_NOSUPPORT: request not supported + * @QDF_STATUS_E_PERM: operation not permitted + * @QDF_STATUS_E_EMPTY: empty condition + * @QDF_STATUS_E_EXISTS: existence failure + * @QDF_STATUS_E_TIMEOUT: operation timeout + * @QDF_STATUS_E_FAILURE: unknown reason do not use unless nothign else applies + * @QDF_STATUS_E_NOENT: No such file or directory + * @QDF_STATUS_E_E2BIG: Arg list too long + * @QDF_STATUS_E_NOSPC: no space left on device + * @QDF_STATUS_E_ADDRNOTAVAIL: Cannot assign requested address + * @QDF_STATUS_E_ENXIO: No such device or address + * @QDF_STATUS_E_NETDOWN: network is down + * @QDF_STATUS_E_IO: I/O Error + * @QDF_STATUS_E_PENDING: pending status + * @QDF_STATUS_E_NETRESET: Network dropped connection because of reset + * @QDF_STATUS_E_SIG: Exit due to received SIGINT + * @QDF_STATUS_E_PROTO: protocol error + * @QDF_STATUS_NOT_INITIALIZED: resource not initialized + * @QDF_STATUS_E_NULL_VALUE: request is null + * @QDF_STATUS_PMC_PENDING: request pendign in pmc + * @QDF_STATUS_PMC_DISABLED: pmc is disabled + * @QDF_STATUS_PMC_NOT_NOW: pmc not ready now + * @QDF_STATUS_PMC_AC_POWER: pmc ac power + * @QDF_STATUS_PMC_SYS_ERROR: pmc system error + * @QDF_STATUS_HEARTBEAT_TMOUT: hearbeat timeout error + * @QDF_STATUS_NTH_BEACON_DELIVERY: Nth beacon delivery + * @QDF_STATUS_CSR_WRONG_STATE: csr in wrong state + * @QDF_STATUS_FT_PREAUTH_KEY_SUCCESS: ft preauth key success + * @QDF_STATUS_FT_PREAUTH_KEY_FAILED: ft preauth key failed + * @QDF_STATUS_CMD_NOT_QUEUED: command not queued + * @QDF_STATUS_FW_MSG_TIMEDOUT: target message timeout + * @QDF_STATUS_E_USB_ERROR: USB transaction error + * @QDF_STATUS_MAX: not a realy value just a place holder for max + */ +typedef enum { + QDF_STATUS_SUCCESS, + QDF_STATUS_E_RESOURCES, + QDF_STATUS_E_NOMEM, + QDF_STATUS_E_AGAIN, + QDF_STATUS_E_INVAL, + QDF_STATUS_E_FAULT, + QDF_STATUS_E_ALREADY, + QDF_STATUS_E_BADMSG, + QDF_STATUS_E_BUSY, + QDF_STATUS_E_CANCELED, + QDF_STATUS_E_ABORTED, + QDF_STATUS_E_NOSUPPORT, + QDF_STATUS_E_PERM, + QDF_STATUS_E_EMPTY, + QDF_STATUS_E_EXISTS, + QDF_STATUS_E_TIMEOUT, + QDF_STATUS_E_FAILURE, + QDF_STATUS_E_NOENT, + QDF_STATUS_E_E2BIG, + QDF_STATUS_E_NOSPC, + QDF_STATUS_E_ADDRNOTAVAIL, + QDF_STATUS_E_ENXIO, + QDF_STATUS_E_NETDOWN, + QDF_STATUS_E_IO, + QDF_STATUS_E_PENDING, + QDF_STATUS_E_NETRESET, + QDF_STATUS_E_SIG, + QDF_STATUS_E_PROTO, + QDF_STATUS_NOT_INITIALIZED, + QDF_STATUS_E_NULL_VALUE, + QDF_STATUS_PMC_PENDING, + QDF_STATUS_PMC_DISABLED, + QDF_STATUS_PMC_NOT_NOW, + QDF_STATUS_PMC_AC_POWER, + QDF_STATUS_PMC_SYS_ERROR, + QDF_STATUS_HEARTBEAT_TMOUT, + QDF_STATUS_NTH_BEACON_DELIVERY, + QDF_STATUS_CSR_WRONG_STATE, + QDF_STATUS_FT_PREAUTH_KEY_SUCCESS, + QDF_STATUS_FT_PREAUTH_KEY_FAILED, + QDF_STATUS_CMD_NOT_QUEUED, + QDF_STATUS_FW_MSG_TIMEDOUT, + QDF_STATUS_E_USB_ERROR, + QDF_STATUS_MAX +} QDF_STATUS; + +#define QDF_IS_STATUS_SUCCESS(status) (QDF_STATUS_SUCCESS == (status)) +#define QDF_IS_STATUS_ERROR(status) (QDF_STATUS_SUCCESS != (status)) + +#endif /* if !defined __QDF_STATUS_H */ diff --git a/drivers/staging/qca-wifi-host-cmn/qdf/inc/qdf_threads.h b/drivers/staging/qca-wifi-host-cmn/qdf/inc/qdf_threads.h new file mode 100644 index 0000000000000000000000000000000000000000..d68166013545d1cecf15cdd7d1df34f73e653808 --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/qdf/inc/qdf_threads.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2014-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: qdf_threads + * QCA driver framework (QDF) thread related APIs + */ + +#if !defined(__QDF_THREADS_H) +#define __QDF_THREADS_H + +#include + +/* Function declarations and documenation */ + +void qdf_sleep(uint32_t ms_interval); + +void qdf_sleep_us(uint32_t us_interval); + +void qdf_busy_wait(uint32_t us_interval); + +#endif /* __QDF_THREADS_H */ diff --git a/drivers/staging/qca-wifi-host-cmn/qdf/inc/qdf_time.h b/drivers/staging/qca-wifi-host-cmn/qdf/inc/qdf_time.h new file mode 100644 index 0000000000000000000000000000000000000000..140b88660a72c98c4e56f219e460999eda509d85 --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/qdf/inc/qdf_time.h @@ -0,0 +1,233 @@ +/* + * Copyright (c) 2014-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: qdf_time + * This file abstracts time related functionality. + */ + +#ifndef _QDF_OS_TIME_H +#define _QDF_OS_TIME_H + +#include +#include "qdf_util.h" + +typedef __qdf_time_t qdf_time_t; + +/** + * qdf_system_ticks - Count the number of ticks elapsed from the time when + * the system booted + * + * Return: ticks + */ +static inline qdf_time_t qdf_system_ticks(void) +{ + return __qdf_system_ticks(); +} + +/** + * qdf_system_ticks_to_msecs - convert ticks to milliseconds + * @clock_ticks: Number of ticks + * + * Return: unsigned int Time in milliseconds + */ +static inline uint32_t qdf_system_ticks_to_msecs(unsigned long clock_ticks) +{ + return __qdf_system_ticks_to_msecs(clock_ticks); +} + +/** + * qdf_system_msecs_to_ticks - convert milliseconds to ticks + * @msec: Time in milliseconds + * + * Return: unsigned long number of ticks + */ +static inline qdf_time_t qdf_system_msecs_to_ticks(uint32_t msecs) +{ + return __qdf_system_msecs_to_ticks(msecs); +} + +/** + * qdf_get_system_uptime - Return a monotonically increasing time + * This increments once per HZ ticks + * + * Return: qdf_time_t system up time in ticks + */ +static inline qdf_time_t qdf_get_system_uptime(void) +{ + return __qdf_get_system_uptime(); +} + +/** + * qdf_get_bootbased_boottime_ns() - Get the bootbased time in nanoseconds + * + * qdf_get_bootbased_boottime_ns() function returns the number of nanoseconds + * that have elapsed since the system was booted. It also includes the time when + * system was suspended. + * + * Return: + * The time since system booted in nanoseconds + */ +static inline s64 qdf_get_bootbased_boottime_ns(void) +{ + return ktime_get_boot_ns(); +} + +/** + * qdf_get_system_timestamp - Return current timestamp + * + * Return: unsigned long timestamp in ms. + */ +static inline unsigned long qdf_get_system_timestamp(void) +{ + return __qdf_get_system_timestamp(); +} + +/** + * qdf_udelay - delay in microseconds + * @usecs: Number of microseconds to delay + * + * Return: none + */ +static inline void qdf_udelay(int usecs) +{ + __qdf_udelay(usecs); +} + +/** + * qdf_mdelay - Delay in milliseconds. + * @msec: Number of milliseconds to delay + * + * Return: none + */ +static inline void qdf_mdelay(int msecs) +{ + __qdf_mdelay(msecs); +} + +/** + * qdf_system_time_after() - Check if a is later than b + * @a: Time stamp value a + * @b: Time stamp value b + * + * Return: + * true if a < b else false + */ +static inline bool qdf_system_time_after(qdf_time_t a, qdf_time_t b) +{ + return __qdf_system_time_after(a, b); +} + +/** + * qdf_system_time_before() - Check if a is before b + * @a: Time stamp value a + * @b: Time stamp value b + * + * Return: + * true if a is before b else false + */ +static inline bool qdf_system_time_before(qdf_time_t a, qdf_time_t b) +{ + return __qdf_system_time_before(a, b); +} + +/** + * qdf_system_time_after_eq() - Check if a atleast as recent as b, if not + * later + * @a: Time stamp value a + * @b: Time stamp value b + * + * Return: + * true if a >= b else false + */ +static inline bool qdf_system_time_after_eq(qdf_time_t a, qdf_time_t b) +{ + return __qdf_system_time_after_eq(a, b); +} + +/** + * enum qdf_timestamp_unit - what unit the qdf timestamp is in + * @KERNEL_LOG: boottime time in uS (micro seconds) + * @QTIMER: QTIME in (1/19200)S + * + * This enum is used to distinguish which timer source is used. + */ +enum qdf_timestamp_unit { + KERNEL_LOG, + QTIMER, +}; + +#ifdef QCA_WIFI_3_0_ADRASTEA +#define QDF_LOG_TIMESTAMP_UNIT QTIMER +#define QDF_LOG_TIMESTAMP_CYCLES_PER_10_US 192 +#else +#define QDF_LOG_TIMESTAMP_UNIT KERNEL_LOG +#define QDF_LOG_TIMESTAMP_CYCLES_PER_10_US 10 +#endif + +static inline unsigned long long qdf_log_timestamp_to_usecs(uint64_t time) +{ + if ((time * 10) < time) { + time = qdf_do_div(time, QDF_LOG_TIMESTAMP_CYCLES_PER_10_US); + return time * 10; + } + return qdf_do_div(time * 10, QDF_LOG_TIMESTAMP_CYCLES_PER_10_US); +} + +static inline uint64_t qdf_usecs_to_log_timestamp(uint64_t usecs) +{ + return qdf_do_div(usecs * QDF_LOG_TIMESTAMP_CYCLES_PER_10_US, 10); +} + +/** + * qdf_get_log_timestamp - get time stamp for logging + * For adrastea this API returns QTIMER tick which is needed to synchronize + * host and fw log timestamps + * For ROME and other discrete solution this API returns system boot time stamp + * + * Return: + * QTIMER ticks(19.2MHz) for adrastea + * System tick for rome and other future discrete solutions + */ +static inline uint64_t qdf_get_log_timestamp(void) +{ + return __qdf_get_log_timestamp(); +} + +/** + * qdf_get_monotonic_boottime - get monotonic kernel boot time + * This API is similar to qdf_get_system_boottime but it includes + * time spent in suspend. + * + * Return: Time in microseconds + */ +static inline uint64_t qdf_get_monotonic_boottime(void) +{ + return __qdf_get_monotonic_boottime(); +} + +#endif diff --git a/drivers/staging/qca-wifi-host-cmn/qdf/inc/qdf_timer.h b/drivers/staging/qca-wifi-host-cmn/qdf/inc/qdf_timer.h new file mode 100644 index 0000000000000000000000000000000000000000..32afd2587ff5c8a4397132beba86a555728098e6 --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/qdf/inc/qdf_timer.h @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2014-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: qdf_timer + * This file abstracts OS timers running in soft IRQ context. + */ + +#ifndef _QDF_TIMER_H +#define _QDF_TIMER_H + +#include +#include + +/* Platform timer object */ +typedef __qdf_timer_t qdf_timer_t; + +/** + * qdf_timer_init() - initialize a timer + * @hdl: OS handle + * @timer: Timer object pointer + * @func: Timer function + * @arg: Arguement of timer function + * @type: deferrable or non deferrable timer type + * + * Timer type QDF_TIMER_TYPE_SW means its a deferrable sw timer which will + * not cause CPU wake upon expiry + * Timer type QDF_TIMER_TYPE_WAKE_APPS means its a non-deferrable timer which + * will cause CPU wake up on expiry + * + * Return: none + */ +static inline void qdf_timer_init(qdf_handle_t hdl, qdf_timer_t *timer, + qdf_timer_func_t func, void *arg, + QDF_TIMER_TYPE type) +{ + __qdf_timer_init(hdl, timer, func, arg, type); +} + +/** + * qdf_timer_start() - start a one-shot timer + * @timer: Timer object pointer + * @msec: Expiration period in milliseconds + * + * Return: none + */ +static inline void +qdf_timer_start(qdf_timer_t *timer, int msec) +{ + __qdf_timer_start(timer, msec); +} + +/** + * qdf_timer_mod() - modify existing timer to new timeout value + * @timer: Timer object pointer + * @msec: Expiration period in milliseconds + * + * Return: none + */ +static inline void qdf_timer_mod(qdf_timer_t *timer, int msec) +{ + __qdf_timer_mod(timer, msec); +} + +/** + * qdf_timer_stop() - cancel qdf timer + * @timer: Timer object pointer + * + * return: bool TRUE Timer was cancelled and deactived + * FALSE Timer was cancelled but already got fired. + * + * The function will return after any running timer completes. + */ +static inline bool qdf_timer_stop(qdf_timer_t *timer) +{ + return __qdf_timer_stop(timer); +} + + +/** + * qdf_timer_sync_cancel - Cancel a timer synchronously + * The function will return after any running timer completes. + * @timer: timer object pointer + * + * return: bool TRUE timer was cancelled and deactived + * FALSE timer was not cancelled + */ +static inline bool qdf_timer_sync_cancel(qdf_timer_t *timer) +{ + return __qdf_timer_sync_cancel(timer); +} + + +/** + * qdf_timer_free() - free qdf timer + * @timer: Timer object pointer + * + * The function will return after any running timer completes. + * Return: none + */ +static inline void qdf_timer_free(qdf_timer_t *timer) +{ + __qdf_timer_free(timer); +} + +#endif /* _QDF_TIMER_H */ diff --git a/drivers/staging/qca-wifi-host-cmn/qdf/inc/qdf_trace.h b/drivers/staging/qca-wifi-host-cmn/qdf/inc/qdf_trace.h new file mode 100644 index 0000000000000000000000000000000000000000..4e0aa4e3dcca4af4e5c1310cbd802e54b6a1dc4f --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/qdf/inc/qdf_trace.h @@ -0,0 +1,520 @@ +/* + * Copyright (c) 2014-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#if !defined(__QDF_TRACE_H) +#define __QDF_TRACE_H + +/** + * DOC: qdf_trace + * QCA driver framework trace APIs + * Trace, logging, and debugging definitions and APIs + */ + +/* Include Files */ +#include /* For QDF_MODULE_ID... */ +#include /* For va_list... */ +#include +#include +#include + +/* Type declarations */ + +#define FL(x) "%s: %d: " x, __func__, __LINE__ + +/* + * Log levels + */ +#define QDF_DEBUG_FUNCTRACE 0x01 +#define QDF_DEBUG_LEVEL0 0x02 +#define QDF_DEBUG_LEVEL1 0x04 +#define QDF_DEBUG_LEVEL2 0x08 +#define QDF_DEBUG_LEVEL3 0x10 +#define QDF_DEBUG_ERROR 0x20 +#define QDF_DEBUG_CFG 0x40 + +#ifdef CONFIG_MCL +/* By default Data Path module will have all log levels enabled, except debug + * log level. Debug level will be left up to the framework or user space modules + * to be enabled when issue is detected + */ +#define QDF_DATA_PATH_TRACE_LEVEL \ + ((1 << QDF_TRACE_LEVEL_FATAL) | (1 << QDF_TRACE_LEVEL_ERROR) | \ + (1 << QDF_TRACE_LEVEL_WARN) | (1 << QDF_TRACE_LEVEL_INFO) | \ + (1 << QDF_TRACE_LEVEL_INFO_HIGH) | (1 << QDF_TRACE_LEVEL_INFO_MED) | \ + (1 << QDF_TRACE_LEVEL_INFO_LOW)) + +/* Preprocessor definitions and constants */ +#define ASSERT_BUFFER_SIZE (512) + +#define MAX_QDF_TRACE_RECORDS 4000 +#define INVALID_QDF_TRACE_ADDR 0xffffffff +#define DEFAULT_QDF_TRACE_DUMP_COUNT 0 + +#include + +#define DUMP_DP_TRACE 0 +#define ENABLE_DP_TRACE_LIVE_MODE 1 +#define CLEAR_DP_TRACE_BUFFER 2 + +#ifdef TRACE_RECORD + +#define MTRACE(p) p +#define NO_SESSION 0xFF + +#else +#define MTRACE(p) { } + +#endif + +/** + * typedef struct qdf_trace_record_s - keep trace record + * @qtime: qtimer ticks + * @time: user timestamp + * @module: module name + * @code: hold record of code + * @session: hold record of session + * @data: hold data + * @pid: hold pid of the process + */ +typedef struct qdf_trace_record_s { + uint64_t qtime; + char time[18]; + uint8_t module; + uint8_t code; + uint16_t session; + uint32_t data; + uint32_t pid; +} qdf_trace_record_t, *tp_qdf_trace_record; + +/** + * typedef struct s_qdf_trace_data - MTRACE logs are stored in ring buffer + * @head: position of first record + * @tail: position of last record + * @num: count of total record + * @num_since_last_dump: count from last dump + * @enable: config for controlling the trace + * @dump_count: Dump after number of records reach this number + */ +typedef struct s_qdf_trace_data { + uint32_t head; + uint32_t tail; + uint32_t num; + uint16_t num_since_last_dump; + uint8_t enable; + uint16_t dump_count; +} t_qdf_trace_data; + +#define CASE_RETURN_STRING(str) case ((str)): return (uint8_t *)(# str); + +/* DP Trace Implementation */ +#ifdef FEATURE_DP_TRACE +#define DPTRACE(p) p +#else +#define DPTRACE(p) +#endif + +#define MAX_QDF_DP_TRACE_RECORDS 4000 +#define QDF_DP_TRACE_RECORD_SIZE 16 +#define INVALID_QDF_DP_TRACE_ADDR 0xffffffff +#define QDF_DP_TRACE_VERBOSITY_HIGH 3 +#define QDF_DP_TRACE_VERBOSITY_MEDIUM 2 +#define QDF_DP_TRACE_VERBOSITY_LOW 1 +#define QDF_DP_TRACE_VERBOSITY_DEFAULT 0 + +/** + * enum QDF_DP_TRACE_ID - Generic ID to identify various events in data path + * @QDF_DP_TRACE_INVALID - invalid + * @QDF_DP_TRACE_DROP_PACKET_RECORD - record drop packet + * @QDF_DP_TRACE_EAPOL_PACKET_RECORD - record EAPOL packet + * @QDF_DP_TRACE_DHCP_PACKET_RECORD - record DHCP packet + * @QDF_DP_TRACE_ARP_PACKET_RECORD - record ARP packet + * @QDF_DP_TRACE_MGMT_PACKET_RECORD - record MGMT pacekt + * QDF_DP_TRACE_EVENT_RECORD - record events + * @QDF_DP_TRACE_DEFAULT_VERBOSITY - below this are part of default verbosity + * @QDF_DP_TRACE_HDD_TX_TIMEOUT - HDD tx timeout + * @QDF_DP_TRACE_HDD_SOFTAP_TX_TIMEOUT- SOFTAP HDD tx timeout + * @QDF_DP_TRACE_HDD_TX_PACKET_PTR_RECORD - HDD layer ptr record + * @QDF_DP_TRACE_CE_PACKET_PTR_RECORD - CE layer ptr record + * @QDF_DP_TRACE_CE_FAST_PACKET_PTR_RECORD- CE fastpath ptr record + * @QDF_DP_TRACE_FREE_PACKET_PTR_RECORD - tx completion ptr record + * @QDF_DP_TRACE_RX_HTT_PACKET_PTR_RECORD - HTT RX record + * @QDF_DP_TRACE_RX_OFFLOAD_HTT_PACKET_PTR_RECORD- HTT RX offload record + * @QDF_DP_TRACE_RX_HDD_PACKET_PTR_RECORD - HDD RX record + * @QDF_DP_TRACE_LOW_VERBOSITY - below this are part of low verbosity + * @QDF_DP_TRACE_TXRX_QUEUE_PACKET_PTR_RECORD -tx queue ptr record + * @QDF_DP_TRACE_TXRX_PACKET_PTR_RECORD - txrx packet ptr record + * @QDF_DP_TRACE_TXRX_FAST_PACKET_PTR_RECORD - txrx fast path record + * @QDF_DP_TRACE_HTT_PACKET_PTR_RECORD - htt packet ptr record + * @QDF_DP_TRACE_HTC_PACKET_PTR_RECORD - htc packet ptr record + * @QDF_DP_TRACE_HIF_PACKET_PTR_RECORD - hif packet ptr record + * @QDF_DP_TRACE_RX_TXRX_PACKET_PTR_RECORD - txrx packet ptr record + * @QDF_DP_TRACE_MED_VERBOSITY - below this are part of med verbosity + * @QDF_DP_TRACE_HDD_TX_PACKET_RECORD - record 32 bytes of tx pkt at HDD + * @QDF_DP_TRACE_HDD_RX_PACKET_RECORD - record 32 bytes of rx pkt at HDD + * @QDF_DP_TRACE_HIGH_VERBOSITY - below this are part of high verbosity + */ +enum QDF_DP_TRACE_ID { + QDF_DP_TRACE_INVALID, + QDF_DP_TRACE_DROP_PACKET_RECORD, + QDF_DP_TRACE_EAPOL_PACKET_RECORD, + QDF_DP_TRACE_DHCP_PACKET_RECORD, + QDF_DP_TRACE_ARP_PACKET_RECORD, + QDF_DP_TRACE_MGMT_PACKET_RECORD, + QDF_DP_TRACE_EVENT_RECORD, + QDF_DP_TRACE_DEFAULT_VERBOSITY, + QDF_DP_TRACE_HDD_TX_TIMEOUT, + QDF_DP_TRACE_HDD_SOFTAP_TX_TIMEOUT, + QDF_DP_TRACE_HDD_TX_PACKET_PTR_RECORD, + QDF_DP_TRACE_CE_PACKET_PTR_RECORD, + QDF_DP_TRACE_CE_FAST_PACKET_PTR_RECORD, + QDF_DP_TRACE_FREE_PACKET_PTR_RECORD, + QDF_DP_TRACE_RX_HTT_PACKET_PTR_RECORD, + QDF_DP_TRACE_RX_OFFLOAD_HTT_PACKET_PTR_RECORD, + QDF_DP_TRACE_RX_HDD_PACKET_PTR_RECORD, + QDF_DP_TRACE_LOW_VERBOSITY, + QDF_DP_TRACE_TXRX_QUEUE_PACKET_PTR_RECORD, + QDF_DP_TRACE_TXRX_PACKET_PTR_RECORD, + QDF_DP_TRACE_TXRX_FAST_PACKET_PTR_RECORD, + QDF_DP_TRACE_HTT_PACKET_PTR_RECORD, + QDF_DP_TRACE_HTC_PACKET_PTR_RECORD, + QDF_DP_TRACE_HIF_PACKET_PTR_RECORD, + QDF_DP_TRACE_RX_TXRX_PACKET_PTR_RECORD, + QDF_DP_TRACE_MED_VERBOSITY, + QDF_DP_TRACE_HDD_TX_PACKET_RECORD, + QDF_DP_TRACE_HDD_RX_PACKET_RECORD, + QDF_DP_TRACE_HIGH_VERBOSITY, + QDF_DP_TRACE_MAX +}; + +/** + * qdf_proto_dir - direction + * @QDF_TX: TX direction + * @QDF_RX: RX direction + * @QDF_NA: not applicable + */ +enum qdf_proto_dir { + QDF_TX, + QDF_RX, + QDF_NA +}; + +/** + * struct qdf_dp_trace_ptr_buf - pointer record buffer + * @cookie: cookie value + * @msdu_id: msdu_id + * @status: completion status + */ +struct qdf_dp_trace_ptr_buf { + uint64_t cookie; + uint16_t msdu_id; + uint16_t status; +}; + +/** + * struct qdf_dp_trace_proto_buf - proto packet buffer + * @sa: source address + * @da: destination address + * @vdev_id : vdev id + * @type: packet type + * @subtype: packet subtype + * @dir: direction + */ +struct qdf_dp_trace_proto_buf { + struct qdf_mac_addr sa; + struct qdf_mac_addr da; + uint8_t vdev_id; + uint8_t type; + uint8_t subtype; + uint8_t dir; +}; + +/** + * struct qdf_dp_trace_mgmt_buf - mgmt packet buffer + * @vdev_id : vdev id + * @type: packet type + * @subtype: packet subtype + */ +struct qdf_dp_trace_mgmt_buf { + uint8_t vdev_id; + uint8_t type; + uint8_t subtype; +}; + +/** + * struct qdf_dp_trace_event_buf - event buffer + * @vdev_id : vdev id + * @type: packet type + * @subtype: packet subtype + */ +struct qdf_dp_trace_event_buf { + uint8_t vdev_id; + uint8_t type; + uint8_t subtype; +}; + +/** + * struct qdf_dp_trace_record_s - Describes a record in DP trace + * @time: time when it got stored + * @code: Describes the particular event + * @data: buffer to store data + * @size: Length of the valid data stored in this record + * @pid : process id which stored the data in this record + */ +struct qdf_dp_trace_record_s { + char time[20]; + uint8_t code; + uint8_t data[QDF_DP_TRACE_RECORD_SIZE]; + uint8_t size; + uint32_t pid; +}; + +/** + * struct qdf_dp_trace_data - Parameters to configure/control DP trace + * @head: Position of first record + * @tail: Position of last record + * @num: Current index + * @proto_bitmap: defines which protocol to be traced + * @no_of_record: defines every nth packet to be traced + * @verbosity : defines verbosity level + * @enable: enable/disable DP trace + * @count: current packet number + */ +struct s_qdf_dp_trace_data { + uint32_t head; + uint32_t tail; + uint32_t num; + uint8_t proto_bitmap; + uint8_t no_of_record; + uint8_t verbosity; + bool enable; + uint32_t tx_count; + uint32_t rx_count; + bool live_mode; +}; + + +/* Function declarations and documenation */ + +/** + * qdf_trace_set_level() - Set the trace level for a particular module + * @level : trace level + * + * Trace level is a member of the QDF_TRACE_LEVEL enumeration indicating + * the severity of the condition causing the trace message to be issued. + * More severe conditions are more likely to be logged. + * + * This is an external API that allows trace levels to be set for each module. + * + * Return: nothing + */ +void qdf_trace_set_level(QDF_MODULE_ID module, QDF_TRACE_LEVEL level); + +/** + * qdf_trace_get_level() - get the trace level + * @level : trace level + * + * This is an external API that returns a bool value to signify if a + * particular trace level is set for the specified module. + * A member of the QDF_TRACE_LEVEL enumeration indicating the severity + * of the condition causing the trace message to be issued. + * + * Note that individual trace levels are the only valid values + * for this API. QDF_TRACE_LEVEL_NONE and QDF_TRACE_LEVEL_ALL + * are not valid input and will return false + * + * Return: + * false - the specified trace level for the specified module is OFF + * true - the specified trace level for the specified module is ON + */ +bool qdf_trace_get_level(QDF_MODULE_ID module, QDF_TRACE_LEVEL level); + +typedef void (*tp_qdf_trace_cb)(void *p_mac, tp_qdf_trace_record, uint16_t); +typedef void (*tp_qdf_state_info_cb) (char **buf, uint16_t *size); +void qdf_register_debugcb_init(void); +void qdf_register_debug_callback(QDF_MODULE_ID module_id, + tp_qdf_state_info_cb qdf_state_infocb); +QDF_STATUS qdf_state_info_dump_all(char *buf, uint16_t size, + uint16_t *driver_dump_size); +void qdf_trace(uint8_t module, uint8_t code, uint16_t session, uint32_t data); +void qdf_trace_register(QDF_MODULE_ID, tp_qdf_trace_cb); +QDF_STATUS qdf_trace_spin_lock_init(void); +void qdf_trace_init(void); +void qdf_trace_enable(uint32_t, uint8_t enable); +void qdf_trace_dump_all(void *, uint8_t, uint8_t, uint32_t, uint32_t); + + +#ifdef FEATURE_DP_TRACE +void qdf_dp_trace_log_pkt(uint8_t session_id, struct sk_buff *skb, + enum qdf_proto_dir dir); +void qdf_dp_trace_init(void); +void qdf_dp_trace_spin_lock_init(void); +void qdf_dp_trace_set_value(uint8_t proto_bitmap, uint8_t no_of_records, + uint8_t verbosity); +void qdf_dp_trace_set_track(qdf_nbuf_t nbuf, enum qdf_proto_dir dir); +void qdf_dp_trace(qdf_nbuf_t nbuf, enum QDF_DP_TRACE_ID code, + uint8_t *data, uint8_t size, enum qdf_proto_dir dir); +void qdf_dp_trace_dump_all(uint32_t count); +typedef void (*tp_qdf_dp_trace_cb)(struct qdf_dp_trace_record_s* , uint16_t); +void qdf_dp_display_record(struct qdf_dp_trace_record_s *record, + uint16_t index); +void qdf_dp_trace_ptr(qdf_nbuf_t nbuf, enum QDF_DP_TRACE_ID code, + uint8_t *data, uint8_t size, uint16_t msdu_id, uint16_t status); + +void qdf_dp_display_ptr_record(struct qdf_dp_trace_record_s *pRecord, + uint16_t recIndex); +uint8_t qdf_dp_get_proto_bitmap(void); +void +qdf_dp_trace_proto_pkt(enum QDF_DP_TRACE_ID code, uint8_t vdev_id, + uint8_t *sa, uint8_t *da, enum qdf_proto_type type, + enum qdf_proto_subtype subtype, enum qdf_proto_dir dir); +void qdf_dp_display_proto_pkt(struct qdf_dp_trace_record_s *record, + uint16_t index); +void qdf_dp_trace_enable_live_mode(void); +void qdf_dp_trace_clear_buffer(void); +void qdf_dp_trace_mgmt_pkt(enum QDF_DP_TRACE_ID code, uint8_t vdev_id, + enum qdf_proto_type type, enum qdf_proto_subtype subtype); +void qdf_dp_display_mgmt_pkt(struct qdf_dp_trace_record_s *record, + uint16_t index); +void qdf_dp_display_event_record(struct qdf_dp_trace_record_s *record, + uint16_t index); +void qdf_dp_trace_record_event(enum QDF_DP_TRACE_ID code, uint8_t vdev_id, + enum qdf_proto_type type, enum qdf_proto_subtype subtype); +#else +static inline +void qdf_dp_trace_log_pkt(uint8_t session_id, struct sk_buff *skb, + enum qdf_proto_dir dir) +{ +} +static inline +void qdf_dp_trace_init(void) +{ +} +static inline +void qdf_dp_trace_set_track(qdf_nbuf_t nbuf, enum qdf_proto_dir dir) +{ +} +static inline +void qdf_dp_trace_set_value(uint8_t proto_bitmap, uint8_t no_of_records, + uint8_t verbosity) +{ +} +static inline +void qdf_dp_trace_dump_all(uint32_t count) +{ +} + +static inline +void qdf_dp_trace_enable_live_mode(void) +{ +} + +static inline +void qdf_dp_trace_clear_buffer(void) +{ +} + +#endif + + +void qdf_trace_hex_dump(QDF_MODULE_ID module, QDF_TRACE_LEVEL level, + void *data, int buf_len); + +void qdf_trace_display(void); + +void qdf_trace_set_value(QDF_MODULE_ID module, QDF_TRACE_LEVEL level, + uint8_t on); + +void qdf_trace_set_module_trace_level(QDF_MODULE_ID module, uint32_t level); + +void __printf(3, 4) qdf_snprintf(char *str_buffer, unsigned int size, + char *str_format, ...); + +#define QDF_SNPRINTF qdf_snprintf + +#ifdef TSOSEG_DEBUG +static inline +int qdf_tso_seg_dbg_record(struct qdf_tso_seg_elem_t *tsoseg, + uint16_t caller) +{ + int rc = -1; + + if (tsoseg != NULL) { + tsoseg->dbg.cur++; tsoseg->dbg.cur &= 0x0f; + tsoseg->dbg.history[tsoseg->dbg.cur] = caller; + rc = tsoseg->dbg.cur; + } + return rc; +}; +static inline void qdf_tso_seg_dbg_bug(char *msg) +{ + qdf_print(msg); + QDF_BUG(0); +}; + +static inline void +qdf_tso_seg_dbg_setowner(struct qdf_tso_seg_elem_t *tsoseg, void *owner) +{ + tsoseg->dbg.txdesc = owner; +}; + +static inline void +qdf_tso_seg_dbg_zero(struct qdf_tso_seg_elem_t *tsoseg) +{ + memset(tsoseg, 0, offsetof(struct qdf_tso_seg_elem_t, dbg)); + return; +}; + +#else +static inline +int qdf_tso_seg_dbg_record(struct qdf_tso_seg_elem_t *tsoseg, + uint16_t caller) +{ + return 0; +}; +static inline void qdf_tso_seg_dbg_bug(char *msg) +{ +}; +static inline void +qdf_tso_seg_dbg_setowner(struct qdf_tso_seg_elem_t *tsoseg, void *owner) +{ +}; +static inline int +qdf_tso_seg_dbg_zero(struct qdf_tso_seg_elem_t *tsoseg) +{ + memset(tsoseg, 0, sizeof(struct qdf_tso_seg_elem_t)); + return 0; +}; + +#endif /* TSOSEG_DEBUG */ +#else + +#define DPTRACE(x) +#define qdf_trace_hex_dump(x, y, z, q) + +#endif /* CONFIG_MCL */ + +#endif /* __QDF_TRACE_H */ diff --git a/drivers/staging/qca-wifi-host-cmn/qdf/inc/qdf_types.h b/drivers/staging/qca-wifi-host-cmn/qdf/inc/qdf_types.h new file mode 100644 index 0000000000000000000000000000000000000000..937fccf8a0684a1892d3a5e1be74978434009ea3 --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/qdf/inc/qdf_types.h @@ -0,0 +1,676 @@ +/* + * Copyright (c) 2014-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: qdf_types.h + * QCA driver framework (QDF) basic type definitions + */ + +#if !defined(__QDF_TYPES_H) +#define __QDF_TYPES_H + +/* Include Files */ +#include + +/* Preprocessor definitions and constants */ +#define QDF_MAX_SGLIST 4 + +/** + * struct qdf_sglist - scatter-gather list + * @nsegs: total number of segments + * struct __sg_segs - scatter-gather segment list + * @vaddr: Virtual address of the segment + * @len: Length of the segment + */ +typedef struct qdf_sglist { + uint32_t nsegs; + struct __sg_segs { + uint8_t *vaddr; + uint32_t len; + } sg_segs[QDF_MAX_SGLIST]; +} qdf_sglist_t; + +#define QDF_MAX_SCATTER __QDF_MAX_SCATTER + +/** + * QDF_SWAP_U16 - swap input u16 value + * @_x: variable to swap + */ +#define QDF_SWAP_U16(_x) \ + ((((_x) << 8) & 0xFF00) | (((_x) >> 8) & 0x00FF)) + +/** + * QDF_SWAP_U32 - swap input u32 value + * @_x: variable to swap + */ +#define QDF_SWAP_U32(_x) \ + (((((_x) << 24) & 0xFF000000) | (((_x) >> 24) & 0x000000FF)) | \ + ((((_x) << 8) & 0x00FF0000) | (((_x) >> 8) & 0x0000FF00))) + +/* ticks per second */ +#define QDF_TICKS_PER_SECOND (1000) + +/** + * QDF_ARRAY_SIZE - get array size + * @_arr: array variable name + */ +#define QDF_ARRAY_SIZE(_arr) (sizeof(_arr) / sizeof((_arr)[0])) + +#define QDF_MAX_SCATTER __QDF_MAX_SCATTER + +/** + * qdf_packed - denotes structure is packed. + */ +#define qdf_packed __qdf_packed + +typedef void *qdf_net_handle_t; + +typedef void *qdf_netlink_handle_t; +typedef void *qdf_drv_handle_t; +typedef void *qdf_os_handle_t; +typedef void *qdf_pm_t; + + +/** + * typedef qdf_handle_t - handles opaque to each other + */ +typedef void *qdf_handle_t; + +/** + * typedef qdf_device_t - Platform/bus generic handle. + * Used for bus specific functions. + */ +typedef __qdf_device_t qdf_device_t; + +/** + * typedef qdf_size_t - size of an object + */ +typedef __qdf_size_t qdf_size_t; + +/** + * typedef __qdf_off_t - offset for API's that need them. + */ +typedef __qdf_off_t qdf_off_t; + +/** + * typedef qdf_dma_map_t - DMA mapping object. + */ +typedef __qdf_dma_map_t qdf_dma_map_t; + +/** + * tyepdef qdf_dma_addr_t - DMA address. + */ +typedef __qdf_dma_addr_t qdf_dma_addr_t; + +/** + * typedef __qdf_dma_size_t - DMA size. + */ +typedef __qdf_dma_size_t qdf_dma_size_t; + +/** + * tyepdef qdf_dma_context_t - DMA context. + */ +typedef __qdf_dma_context_t qdf_dma_context_t; + +/** + * struct qdf_dma_map_info - Information inside a DMA map. + * @nsegs: total number mapped segments + * struct __dma_segs - Information of physical address. + * @paddr: physical(dam'able) address of the segment + * @len: length of the segment + */ +typedef struct qdf_dma_map_info { + uint32_t nsegs; + struct __dma_segs { + qdf_dma_addr_t paddr; + qdf_dma_size_t len; + } dma_segs[QDF_MAX_SCATTER]; +} qdf_dmamap_info_t; + +#define qdf_iomem_t __qdf_iomem_t; + +/** + * typedef enum QDF_TIMER_TYPE - QDF timer type + * @QDF_TIMER_TYPE_SW: Deferrable SW timer it will not cause CPU to wake up + * on expiry + * @QDF_TIMER_TYPE_WAKE_APPS: Non deferrable timer which will cause CPU to + * wake up on expiry + */ +typedef enum { + QDF_TIMER_TYPE_SW, + QDF_TIMER_TYPE_WAKE_APPS +} QDF_TIMER_TYPE; + +/** + * tyepdef qdf_resource_type_t - hw resources + * @QDF_RESOURCE_TYPE_MEM: memory resource + * @QDF_RESOURCE_TYPE_IO: io resource + * Define the hw resources the OS has allocated for the device + * Note that start defines a mapped area. + */ +typedef enum { + QDF_RESOURCE_TYPE_MEM, + QDF_RESOURCE_TYPE_IO, +} qdf_resource_type_t; + +/** + * tyepdef qdf_resource_t - representation of a h/w resource. + * @start: start + * @end: end + * @type: resource type + */ +typedef struct { + uint64_t start; + uint64_t end; + qdf_resource_type_t type; +} qdf_resource_t; + +/** + * typedef qdf_dma_dir_t - DMA directions + * @QDF_DMA_BIDIRECTIONAL: bidirectional data + * @QDF_DMA_TO_DEVICE: data going from device to memory + * @QDF_DMA_FROM_DEVICE: data going from memory to device + */ +typedef enum { + QDF_DMA_BIDIRECTIONAL = __QDF_DMA_BIDIRECTIONAL, + QDF_DMA_TO_DEVICE = __QDF_DMA_TO_DEVICE, + QDF_DMA_FROM_DEVICE = __QDF_DMA_FROM_DEVICE, +} qdf_dma_dir_t; + +/* work queue(kernel thread)/DPC function callback */ +typedef void (*qdf_defer_fn_t)(void *); + +/* + * Prototype of the critical region function that is to be + * executed with spinlock held and interrupt disalbed + */ +typedef bool (*qdf_irqlocked_func_t)(void *); + +/* Prototype of timer function */ +typedef void (*qdf_timer_func_t)(void *); + +#define qdf_offsetof(type, field) offsetof(type, field) + +/** + * typedef QDF_MODULE_ID - QDF Module IDs + * @QDF_MODULE_ID_TLSHIM: TLSHIM module ID + * @QDF_MODULE_ID_WMI: WMI module ID + * @QDF_MODULE_ID_HTT: HTT module ID + * @QDF_MODULE_ID_RSV4: Reserved + * @QDF_MODULE_ID_HDD: HDD module ID + * @QDF_MODULE_ID_SME: SME module ID + * @QDF_MODULE_ID_PE: PE module ID + * @QDF_MODULE_ID_WMA: WMA module ID + * @QDF_MODULE_ID_SYS: SYS module ID + * @QDF_MODULE_ID_QDF: QDF module ID + * @QDF_MODULE_ID_SAP: SAP module ID + * @QDF_MODULE_ID_HDD_SOFTAP: HDD SAP module ID + * @QDF_MODULE_ID_HDD_DATA: HDD DATA module ID + * @QDF_MODULE_ID_HDD_SAP_DATA: HDD SAP DATA module ID + * @QDF_MODULE_ID_HIF: HIF module ID + * @QDF_MODULE_ID_HTC: HTC module ID + * @QDF_MODULE_ID_TXRX: TXRX module ID + * @QDF_MODULE_ID_QDF_DEVICE: QDF DEVICE module ID + * @QDF_MODULE_ID_CFG: CFG module ID + * @QDF_MODULE_ID_BMI: BMI module ID + * @QDF_MODULE_ID_EPPING: EPPING module ID + * @QDF_MODULE_ID_QVIT: QVIT module ID + * @QDF_MODULE_ID_MAX: Max place holder module ID + * + * These are generic IDs that identify the various modules in the software + * system + * 0 is unused for historical purposes + * 3 & 4 are unused for historical purposes + */ +typedef enum { + QDF_MODULE_ID_TLSHIM = 1, + QDF_MODULE_ID_WMI = 2, + QDF_MODULE_ID_HTT = 3, + QDF_MODULE_ID_RSV4 = 4, + QDF_MODULE_ID_HDD = 5, + QDF_MODULE_ID_SME = 6, + QDF_MODULE_ID_PE = 7, + QDF_MODULE_ID_WMA = 8, + QDF_MODULE_ID_SYS = 9, + QDF_MODULE_ID_QDF = 10, + QDF_MODULE_ID_SAP = 11, + QDF_MODULE_ID_HDD_SOFTAP = 12, + QDF_MODULE_ID_HDD_DATA = 14, + QDF_MODULE_ID_HDD_SAP_DATA = 15, + QDF_MODULE_ID_HIF = 16, + QDF_MODULE_ID_HTC = 17, + QDF_MODULE_ID_TXRX = 18, + QDF_MODULE_ID_QDF_DEVICE = 19, + QDF_MODULE_ID_CFG = 20, + QDF_MODULE_ID_BMI = 21, + QDF_MODULE_ID_EPPING = 22, + QDF_MODULE_ID_QVIT = 23, + QDF_MODULE_ID_MAX +} QDF_MODULE_ID; + +/** + * typedef enum QDF_TRACE_LEVEL - Debug Trace level + * @QDF_TRACE_LEVEL_NONE: no trace will be logged. This value is in place + * for the qdf_trace_setlevel() to allow the user to turn off all traces + * @QDF_TRACE_LEVEL_FATAL: enable trace for fatal Error + * @QDF_TRACE_LEVEL_ERROR: enable trace for errors + * @QDF_TRACE_LEVEL_WARN: enable trace for warnings + * @QDF_TRACE_LEVEL_INFO: enable trace for information + * @QDF_TRACE_LEVEL_INFO_HIGH: enable high level trace information + * @QDF_TRACE_LEVEL_INFO_MED: enable middle level trace information + * @QDF_TRACE_LEVEL_INFO_LOW: enable low level trace information + * @QDF_TRACE_LEVEL_DEBUG: enable trace for debugging + * @QDF_TRACE_LEVEL_ALL: enable all trace + * @QDF_TRACE_LEVEL_MAX: enable max level trace + */ +typedef enum { + QDF_TRACE_LEVEL_NONE = 0, + QDF_TRACE_LEVEL_FATAL, + QDF_TRACE_LEVEL_ERROR, + QDF_TRACE_LEVEL_WARN, + QDF_TRACE_LEVEL_INFO, + QDF_TRACE_LEVEL_INFO_HIGH, + QDF_TRACE_LEVEL_INFO_MED, + QDF_TRACE_LEVEL_INFO_LOW, + QDF_TRACE_LEVEL_DEBUG, + QDF_TRACE_LEVEL_ALL, + QDF_TRACE_LEVEL_MAX +} QDF_TRACE_LEVEL; + +/** + * enum tQDF_ADAPTER_MODE - Concurrency role. + * @QDF_STA_MODE: STA mode + * @QDF_SAP_MODE: SAP mode + * @QDF_P2P_CLIENT_MODE: P2P client mode + * @QDF_P2P_GO_MODE: P2P GO mode + * @QDF_FTM_MODE: FTM mode + * @QDF_IBSS_MODE: IBSS mode + * @QDF_MONITOR_MODE: Monitor mode + * @QDF_P2P_DEVICE_MODE: P2P device mode + * @QDF_OCB_MODE: OCB device mode + * @QDF_EPPING_MODE: EPPING device mode + * @QDF_QVIT_MODE: QVIT device mode + * @QDF_NDI_MODE: NAN datapath mode + * @QDF_MAX_NO_OF_MODE: Max place holder + * + * These are generic IDs that identify the various roles + * in the software system + */ +enum tQDF_ADAPTER_MODE { + QDF_STA_MODE, + QDF_SAP_MODE, + QDF_P2P_CLIENT_MODE, + QDF_P2P_GO_MODE, + QDF_FTM_MODE, + QDF_IBSS_MODE, + QDF_MONITOR_MODE, + QDF_P2P_DEVICE_MODE, + QDF_OCB_MODE, + QDF_EPPING_MODE, + QDF_QVIT_MODE, + QDF_NDI_MODE, + QDF_MAX_NO_OF_MODE +}; + +/** + * enum tQDF_GLOBAL_CON_MODE - global config mode when + * driver is loaded. + * + * @QDF_GLOBAL_MISSION_MODE: mission mode (STA, SAP...) + * @QDF_GLOBAL_MONITOR_MODE: Monitor Mode + * @QDF_GLOBAL_FTM_MODE: FTM mode + * @QDF_GLOBAL_IBSS_MODE: IBSS mode + * @QDF_GLOBAL_EPPING_MODE: EPPING mode + * @QDF_GLOBAL_QVIT_MODE: QVIT global mode + * @QDF_GLOBAL_MAX_MODE: Max place holder + */ +enum tQDF_GLOBAL_CON_MODE { + QDF_GLOBAL_MISSION_MODE, + QDF_GLOBAL_MONITOR_MODE = 4, + QDF_GLOBAL_FTM_MODE = 5, + QDF_GLOBAL_IBSS_MODE = 6, + QDF_GLOBAL_EPPING_MODE = 8, + QDF_GLOBAL_QVIT_MODE = 9, + QDF_GLOBAL_MAX_MODE +}; + +#define QDF_IS_EPPING_ENABLED(mode) (mode == QDF_GLOBAL_EPPING_MODE) + + +#ifdef CONFIG_MCL +/** + * qdf_trace_msg()- logging API + * @module: Module identifier. A member of the QDF_MODULE_ID enumeration that + * identifies the module issuing the trace message. + * @level: Trace level. A member of the QDF_TRACE_LEVEL enumeration indicating + * the severity of the condition causing the trace message to be issued. + * More severe conditions are more likely to be logged. + * @str_format: Format string. The message to be logged. This format string + * contains printf-like replacement parameters, which follow this + * parameter in the variable argument list. + * + * Users wishing to add tracing information to their code should use + * QDF_TRACE. QDF_TRACE() will compile into a call to qdf_trace_msg() when + * tracing is enabled. + * + * Return: nothing + * + * implemented in qdf_trace.c + */ +void __printf(3, 4) qdf_trace_msg(QDF_MODULE_ID module, QDF_TRACE_LEVEL level, + char *str_format, ...); + +#define qdf_print(args...) \ + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, ## args) + +#else +#define qdf_print printk +#endif /* CONFIG_MCL */ + +#define qdf_vprint __qdf_vprint +#define qdf_snprint __qdf_snprint + +#ifdef WLAN_OPEN_P2P_INTERFACE +/* This should match with WLAN_MAX_INTERFACES */ +#define QDF_MAX_CONCURRENCY_PERSONA (4) +#else +#define QDF_MAX_CONCURRENCY_PERSONA (3) +#endif + +#define QDF_STA_MASK (1 << QDF_STA_MODE) +#define QDF_SAP_MASK (1 << QDF_SAP_MODE) +#define QDF_P2P_CLIENT_MASK (1 << QDF_P2P_CLIENT_MODE) +#define QDF_P2P_GO_MASK (1 << QDF_P2P_GO_MODE) + +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH + +/** + * typedef tQDF_MCC_TO_SCC_SWITCH_MODE - MCC to SCC switch mode. + * @QDF_MCC_TO_SCC_SWITCH_DISABLE: Disable switch + * @QDF_MCC_TO_SCC_SWITCH_ENABLE: Enable switch + * @QDF_MCC_TO_SCC_SWITCH_FORCE: Force switch with SAP restart + * @QDF_MCC_TO_SCC_SWITCH_FORCE_WITHOUT_DISCONNECTION: Force switch without + * restart of SAP + * @QDF_MCC_TO_SCC_SWITCH_WITH_FAVORITE_CHANNEL: Switch using fav channel(s) + * without SAP restart + * @QDF_MCC_TO_SCC_SWITCH_MAX: max switch + */ +typedef enum { + QDF_MCC_TO_SCC_SWITCH_DISABLE = 0, + QDF_MCC_TO_SCC_SWITCH_ENABLE, + QDF_MCC_TO_SCC_SWITCH_FORCE, + QDF_MCC_TO_SCC_SWITCH_FORCE_WITHOUT_DISCONNECTION, + QDF_MCC_TO_SCC_SWITCH_WITH_FAVORITE_CHANNEL, + QDF_MCC_TO_SCC_SWITCH_MAX +} tQDF_MCC_TO_SCC_SWITCH_MODE; +#endif + +#if !defined(NULL) +#ifdef __cplusplus +#define NULL 0 +#else +#define NULL ((void *)0) +#endif +#endif + +/* typedef for QDF Context... */ +typedef void *v_CONTEXT_t; + +#define QDF_MAC_ADDR_SIZE (6) +#define QDF_MAC_ADDRESS_STR "%02x:%02x:%02x:%02x:%02x:%02x" +#define QDF_MAC_ADDR_ARRAY(a) \ + (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5] + +/** + * struct qdf_mac_addr - mac address array + * @bytes: MAC address bytes + */ +struct qdf_mac_addr { + uint8_t bytes[QDF_MAC_ADDR_SIZE]; +}; + +/** + * This macro is used to initialize a QDF MacAddress to the broadcast + * MacAddress. It is used like this... + */ +#define QDF_MAC_ADDR_BROADCAST_INITIALIZER \ + { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff } } + +/** + * This macro is used to initialize a QDF MacAddress to zero + * It is used like this... + */ +#define QDF_MAC_ADDR_ZERO_INITIALIZER { { 0, 0, 0, 0, 0, 0 } } + +#define QDF_IPV4_ADDR_SIZE (4) +#define QDF_IPV6_ADDR_SIZE (16) +#define QDF_MAX_NUM_CHAN (128) + +/** + * struct qdf_tso_frag_t - fragments of a single TCP segment + * @paddr_low_32: Lower 32 bits of the buffer pointer + * @paddr_upper_16: upper 16 bits of the buffer pointer + * @length: length of the buffer + * @vaddr: virtual address + * + * This structure holds the fragments of a single TCP segment of a + * given jumbo TSO network buffer + */ +struct qdf_tso_frag_t { + uint16_t length; + unsigned char *vaddr; + qdf_dma_addr_t paddr; +}; + +#define FRAG_NUM_MAX 6 +#define TSO_SEG_MAGIC_COOKIE 0x7EED + +/** + * struct qdf_tso_flags_t - TSO specific flags + * @tso_enable: Enable transmit segmentation offload + * @tcp_flags_mask: Tcp_flag is inserted into the header based + * on the mask + * @l2_len: L2 length for the msdu + * @ip_len: IP length for the msdu + * @tcp_seq_num: TCP sequence number + * @ip_id: IP identification number + * + * This structure holds the TSO specific flags extracted from the TSO network + * buffer for a given TCP segment + */ +struct qdf_tso_flags_t { + uint32_t tso_enable:1, + reserved_0a:6, + fin:1, + syn:1, + rst:1, + psh:1, + ack:1, + urg:1, + ece:1, + cwr:1, + ns:1, + tcp_flags_mask:9, + reserved_0b:7; + + uint32_t l2_len:16, + ip_len:16; + + uint32_t tcp_seq_num; + + uint32_t ip_id:16, + ipv4_checksum_en:1, + udp_ipv4_checksum_en:1, + udp_ipv6_checksum_en:1, + tcp_ipv4_checksum_en:1, + tcp_ipv6_checksum_en:1, + partial_checksum_en:1, + reserved_3a:10; + + uint32_t checksum_offset:14, + reserved_4a:2, + payload_start_offset:14, + reserved_4b:2; + + uint32_t payload_end_offset:14, + reserved_5:18; +}; + +/** + * struct qdf_tso_seg_t - single TSO segment + * @tso_flags: TSO flags + * @num_frags: number of fragments + * @total_len: total length of the packet + * @tso_frags: array holding the fragments + * + * This structure holds the information of a single TSO segment of a jumbo + * TSO network buffer + */ +struct qdf_tso_seg_t { + struct qdf_tso_flags_t tso_flags; + uint32_t num_frags; + uint32_t total_len; + struct qdf_tso_frag_t tso_frags[FRAG_NUM_MAX]; +}; + +/** + * TSO seg elem action caller locations: goes into dbg.history below. + * Needed to be defined outside of the feature so that + * callers can be coded without ifdefs (even if they get + * resolved to nothing) + */ +enum tsoseg_dbg_caller_e { + TSOSEG_LOC_UNDEFINED, + TSOSEG_LOC_INIT1, + TSOSEG_LOC_INIT2, + TSOSEG_LOC_DEINIT, + TSOSEG_LOC_PREPARETSO, + TSOSEG_LOC_TXPREPLLFAST, + TSOSEG_LOC_UNMAPTSO, + TSOSEG_LOC_ALLOC, + TSOSEG_LOC_FREE, +}; +#ifdef TSOSEG_DEBUG + +#define MAX_TSO_SEG_ACT_HISTORY 16 +struct qdf_tso_seg_dbg_t { + void *txdesc; /* owner - (ol_txrx_tx_desc_t *) */ + int cur; /* index of last valid entry */ + uint16_t history[MAX_TSO_SEG_ACT_HISTORY]; +}; +#endif /* TSOSEG_DEBUG */ + +/** + * qdf_tso_seg_elem_t - tso segment element + * @seg: instance of segment + * @next: pointer to the next segment + */ +struct qdf_tso_seg_elem_t { + struct qdf_tso_seg_t seg; + uint16_t cookie:15, + on_freelist:1; + struct qdf_tso_seg_elem_t *next; +#ifdef TSOSEG_DEBUG + struct qdf_tso_seg_dbg_t dbg; +#endif /* TSOSEG_DEBUG */ +}; + +/** + * struct qdf_tso_num_seg_t - single element to count for num of seg + * @tso_cmn_num_seg: num of seg in a jumbo skb + * + * This structure holds the information of num of segments of a jumbo + * TSO network buffer. + */ +struct qdf_tso_num_seg_t { + uint32_t tso_cmn_num_seg; +}; + +/** + * qdf_tso_num_seg_elem_t - num of tso segment element for jumbo skb + * @num_seg: instance of num of seg + * @next: pointer to the next segment + */ +struct qdf_tso_num_seg_elem_t { + struct qdf_tso_num_seg_t num_seg; + struct qdf_tso_num_seg_elem_t *next; +}; + +/** + * struct qdf_tso_info_t - TSO information extracted + * @is_tso: is this is a TSO frame + * @num_segs: number of segments + * @tso_seg_list: list of TSO segments for this jumbo packet + * @curr_seg: segment that is currently being processed + * @tso_num_seg_list: num of tso seg for this jumbo packet + * @msdu_stats_idx: msdu index for tso stats + * + * This structure holds the TSO information extracted after parsing the TSO + * jumbo network buffer. It contains a chain of the TSO segments belonging to + * the jumbo packet + */ +struct qdf_tso_info_t { + uint8_t is_tso; + uint32_t num_segs; + struct qdf_tso_seg_elem_t *tso_seg_list; + struct qdf_tso_seg_elem_t *curr_seg; + struct qdf_tso_num_seg_elem_t *tso_num_seg_list; + uint32_t msdu_stats_idx; +}; + +/** + * Used to set classify bit in CE desc. + */ +#define QDF_CE_TX_CLASSIFY_BIT_S 5 + +/** + * QDF_CE_TX_PKT_TYPE_BIT_S - 2 bits starting at bit 6 in CE desc. + */ +#define QDF_CE_TX_PKT_TYPE_BIT_S 6 + +/** + * QDF_CE_TX_PKT_OFFSET_BIT_S - 12 bits --> 16-27, in the CE desciptor + * the length of HTT/HTC descriptor + */ +#define QDF_CE_TX_PKT_OFFSET_BIT_S 16 + +/** + * QDF_CE_TX_PKT_OFFSET_BIT_M - Mask for packet offset in the CE descriptor. + */ +#define QDF_CE_TX_PKT_OFFSET_BIT_M 0x0fff0000 + +/** + * enum qdf_suspend_type - type of suspend + * @QDF_SYSTEM_SUSPEND: System suspend triggered wlan suspend + * @QDF_RUNTIME_SUSPEND: Runtime pm inactivity timer triggered wlan suspend + */ +enum qdf_suspend_type { + QDF_SYSTEM_SUSPEND, + QDF_RUNTIME_SUSPEND +}; + +#endif /* __QDF_TYPES_H */ diff --git a/drivers/staging/qca-wifi-host-cmn/qdf/inc/qdf_util.h b/drivers/staging/qca-wifi-host-cmn/qdf/inc/qdf_util.h new file mode 100644 index 0000000000000000000000000000000000000000..964de860443381f7e0fd8961cf0f485916e1ab15 --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/qdf/inc/qdf_util.h @@ -0,0 +1,541 @@ +/* + * Copyright (c) 2014-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: qdf_util.h + * This file defines utility functions. + */ + +#ifndef _QDF_UTIL_H +#define _QDF_UTIL_H + +#include + +#ifdef QCA_CONFIG_SMP +#define QDF_MAX_AVAILABLE_CPU 8 +#else +#define QDF_MAX_AVAILABLE_CPU 1 +#endif + +/** + * qdf_unlikely - Compiler-dependent macro denoting code likely to execute + * @_expr: expression to be checked + */ +#define qdf_unlikely(_expr) __qdf_unlikely(_expr) + +/** + * qdf_likely - Compiler-dependent macro denoting code unlikely to execute + * @_expr: expression to be checked + */ +#define qdf_likely(_expr) __qdf_likely(_expr) + +/** + * qdf_mb - read + write memory barrier. + */ +#define qdf_mb() __qdf_mb() + +/** + * qdf_assert - assert "expr" evaluates to false. + */ +#ifdef QDF_DEBUG +#define qdf_assert(expr) __qdf_assert(expr) +#else +#define qdf_assert(expr) +#endif /* QDF_DEBUG */ + +/** + * qdf_assert_always - alway assert "expr" evaluates to false. + */ +#define qdf_assert_always(expr) __qdf_assert(expr) + +/** + * qdf_target_assert_always - alway target assert "expr" evaluates to false. + */ +#define qdf_target_assert_always(expr) __qdf_target_assert(expr) + +/** + * QDF_MAX - get maximum of two values + * @_x: 1st arguement + * @_y: 2nd arguement + */ +#define QDF_MAX(_x, _y) (((_x) > (_y)) ? (_x) : (_y)) + +/** + * QDF_MIN - get minimum of two values + * @_x: 1st arguement + * @_y: 2nd arguement + */ +#define QDF_MIN(_x, _y) (((_x) < (_y)) ? (_x) : (_y)) + +/** + * qdf_status_to_os_return - returns the status to OS. + * @status: enum QDF_STATUS + * + * returns: int status success/failure + */ +static inline int qdf_status_to_os_return(QDF_STATUS status) +{ + return __qdf_status_to_os_return(status); +} + +/** + * qdf_set_bit() - set bit in address + * @nr: bit number to be set + * @addr: address buffer pointer + * + * Return: none + */ +#define qdf_set_bit(nr, addr) __qdf_set_bit(nr, addr) + +/** + * qdf_container_of - cast a member of a structure out to the containing + * structure + * @ptr: the pointer to the member. + * @type: the type of the container struct this is embedded in. + * @member: the name of the member within the struct. + */ +#define qdf_container_of(ptr, type, member) \ + __qdf_container_of(ptr, type, member) + +/** + * qdf_is_pwr2 - test input value is power of 2 integer + * @value: input integer + */ +#define QDF_IS_PWR2(value) (((value) ^ ((value)-1)) == ((value) << 1) - 1) + +/** + * qdf_roundup() - roundup the input value + * @x: value to roundup + * @y: input value rounded to multiple of this + * + * Return: rounded value + */ +#define qdf_roundup(x, y) __qdf_roundup(x, y) + +/** + * qdf_is_macaddr_equal() - compare two QDF MacAddress + * @mac_addr1: Pointer to one qdf MacAddress to compare + * @mac_addr2: Pointer to the other qdf MacAddress to compare + * + * This function returns a bool that tells if a two QDF MacAddress' + * are equivalent. + * + * Return: true if the MacAddress's are equal + * not true if the MacAddress's are not equal + */ +static inline bool qdf_is_macaddr_equal(struct qdf_mac_addr *mac_addr1, + struct qdf_mac_addr *mac_addr2) +{ + return __qdf_is_macaddr_equal(mac_addr1, mac_addr2); +} + + +/** + * qdf_is_macaddr_zero() - check for a MacAddress of all zeros. + * @mac_addr: pointer to the struct qdf_mac_addr to check. + * + * This function returns a bool that tells if a MacAddress is made up of + * all zeros. + * + * Return: true if the MacAddress is all Zeros + * false if the MacAddress is not all Zeros. + */ +static inline bool qdf_is_macaddr_zero(struct qdf_mac_addr *mac_addr) +{ + struct qdf_mac_addr zero_mac_addr = QDF_MAC_ADDR_ZERO_INITIALIZER; + return qdf_is_macaddr_equal(mac_addr, &zero_mac_addr); +} + +/** + * qdf_zero_macaddr() - zero out a MacAddress + * @mac_addr: pointer to the struct qdf_mac_addr to zero. + * + * This function zeros out a QDF MacAddress type. + * + * Return: none + */ +static inline void qdf_zero_macaddr(struct qdf_mac_addr *mac_addr) +{ + __qdf_zero_macaddr(mac_addr); +} + + +/** + * qdf_is_macaddr_group() - check for a MacAddress is a 'group' address + * @mac_addr1: pointer to the qdf MacAddress to check + * + * This function returns a bool that tells if a the input QDF MacAddress + * is a "group" address. Group addresses have the 'group address bit' turned + * on in the MacAddress. Group addresses are made up of Broadcast and + * Multicast addresses. + * + * Return: true if the input MacAddress is a Group address + * false if the input MacAddress is not a Group address + */ +static inline bool qdf_is_macaddr_group(struct qdf_mac_addr *mac_addr) +{ + return mac_addr->bytes[0] & 0x01; +} + + +/** + * qdf_is_macaddr_broadcast() - check for a MacAddress is a broadcast address + * @mac_addr: Pointer to the qdf MacAddress to check + * + * This function returns a bool that tells if a the input QDF MacAddress + * is a "broadcast" address. + * + * Return: true if the input MacAddress is a broadcast address + * flase if the input MacAddress is not a broadcast address + */ +static inline bool qdf_is_macaddr_broadcast(struct qdf_mac_addr *mac_addr) +{ + struct qdf_mac_addr broadcast_mac_addr = + QDF_MAC_ADDR_BROADCAST_INITIALIZER; + return qdf_is_macaddr_equal(mac_addr, &broadcast_mac_addr); +} + +/** + * qdf_copy_macaddr() - copy a QDF MacAddress + * @dst_addr: pointer to the qdf MacAddress to copy TO (the destination) + * @src_addr: pointer to the qdf MacAddress to copy FROM (the source) + * + * This function copies a QDF MacAddress into another QDF MacAddress. + * + * Return: none + */ +static inline void qdf_copy_macaddr(struct qdf_mac_addr *dst_addr, + struct qdf_mac_addr *src_addr) +{ + *dst_addr = *src_addr; +} + +/** + * qdf_set_macaddr_broadcast() - set a QDF MacAddress to the 'broadcast' + * @mac_addr: pointer to the qdf MacAddress to set to broadcast + * + * This function sets a QDF MacAddress to the 'broadcast' MacAddress. Broadcast + * MacAddress contains all 0xFF bytes. + * + * Return: none + */ +static inline void qdf_set_macaddr_broadcast(struct qdf_mac_addr *mac_addr) +{ + __qdf_set_macaddr_broadcast(mac_addr); +} + +/** + * qdf_set_u16() - Assign 16-bit unsigned value to a byte array base on CPU's + * endianness. + * @ptr: Starting address of a byte array + * @value: The value to assign to the byte array + * + * Caller must validate the byte array has enough space to hold the vlaue + * + * Return: The address to the byte after the assignment. This may or may not + * be valid. Caller to verify. + */ +static inline uint8_t *qdf_set_u16(uint8_t *ptr, uint16_t value) +{ +#if defined(ANI_BIG_BYTE_ENDIAN) + *(ptr) = (uint8_t) (value >> 8); + *(ptr + 1) = (uint8_t) (value); +#else + *(ptr + 1) = (uint8_t) (value >> 8); + *(ptr) = (uint8_t) (value); +#endif + return ptr + 2; +} + +/** + * qdf_get_u16() - Retrieve a 16-bit unsigned value from a byte array base on + * CPU's endianness. + * @ptr: Starting address of a byte array + * @value: Pointer to a caller allocated buffer for 16 bit value. Value is to + * assign to this location. + * + * Caller must validate the byte array has enough space to hold the vlaue + * + * Return: The address to the byte after the assignment. This may or may not + * be valid. Caller to verify. + */ +static inline uint8_t *qdf_get_u16(uint8_t *ptr, uint16_t *value) +{ +#if defined(ANI_BIG_BYTE_ENDIAN) + *value = (((uint16_t) (*ptr << 8)) | ((uint16_t) (*(ptr + 1)))); +#else + *value = (((uint16_t) (*(ptr + 1) << 8)) | ((uint16_t) (*ptr))); +#endif + return ptr + 2; +} + +/** + * qdf_get_u32() - retrieve a 32-bit unsigned value from a byte array base on + * CPU's endianness. + * @ptr: Starting address of a byte array + * @value: Pointer to a caller allocated buffer for 32 bit value. Value is to + * assign to this location. + * + * Caller must validate the byte array has enough space to hold the vlaue + * + * Return: The address to the byte after the assignment. This may or may not + * be valid. Caller to verify. + */ +static inline uint8_t *qdf_get_u32(uint8_t *ptr, uint32_t *value) +{ +#if defined(ANI_BIG_BYTE_ENDIAN) + *value = ((uint32_t) (*(ptr) << 24) | + (uint32_t) (*(ptr + 1) << 16) | + (uint32_t) (*(ptr + 2) << 8) | (uint32_t) (*(ptr + 3))); +#else + *value = ((uint32_t) (*(ptr + 3) << 24) | + (uint32_t) (*(ptr + 2) << 16) | + (uint32_t) (*(ptr + 1) << 8) | (uint32_t) (*(ptr))); +#endif + return ptr + 4; +} + +/** + * qdf_ntohs - Convert a 16-bit value from network byte order to host byte order + */ +#define qdf_ntohs(x) __qdf_ntohs(x) + +/** + * qdf_ntohl - Convert a 32-bit value from network byte order to host byte order + */ +#define qdf_ntohl(x) __qdf_ntohl(x) + +/** + * qdf_htons - Convert a 16-bit value from host byte order to network byte order + */ +#define qdf_htons(x) __qdf_htons(x) + +/** + * qdf_htonl - Convert a 32-bit value from host byte order to network byte order + */ +#define qdf_htonl(x) __qdf_htonl(x) + +/** + * qdf_cpu_to_le16 - Convert a 16-bit value from CPU byte order to + * little-endian byte order + */ +#define qdf_cpu_to_le16(x) __qdf_cpu_to_le16(x) + +/** + * qdf_cpu_to_le32 - Convert a 32-bit value from CPU byte order to + * little-endian byte order + */ +#define qdf_cpu_to_le32(x) __qdf_cpu_to_le32(x) + +/** + * qdf_cpu_to_le64 - Convert a 64-bit value from CPU byte order to + * little-endian byte order + */ +#define qdf_cpu_to_le64(x) __qdf_cpu_to_le64(x) + +/** + * qdf_be32_to_cpu - Convert a 32-bit value from big-endian byte order + * to CPU byte order + */ +#define qdf_be32_to_cpu(x) __qdf_be32_to_cpu(x) + +/** + * qdf_be64_to_cpu - Convert a 64-bit value from big-endian byte order + * to CPU byte order + */ +#define qdf_be64_to_cpu(x) __qdf_be64_to_cpu(x) + +/** + * qdf_le32_to_cpu - Convert a 32-bit value from little-endian byte + * order to CPU byte order + */ +#define qdf_le32_to_cpu(x) __qdf_le32_to_cpu(x) + +/** + * qdf_le64_to_cpu - Convert a 64-bit value from little-endian byte + * order to CPU byte order + */ +#define qdf_le64_to_cpu(x) __qdf_le64_to_cpu(x) + +/** + * qdf_le16_to_cpu - Convert a 16-bit value from little-endian byte order + * to CPU byte order + * @x: value to be converted + */ +#define qdf_le16_to_cpu(x) __qdf_le16_to_cpu(x) + +/** + * qdf_function - replace with the name of the current function + */ +#define qdf_function __qdf_function + +/** + * qdf_get_pwr2() - get next power of 2 integer from input value + * @value: input value to find next power of 2 integer + * + * Get next power of 2 integer from input value + * + * Return: Power of 2 integer + */ +static inline int qdf_get_pwr2(int value) +{ + int log2; + if (QDF_IS_PWR2(value)) + return value; + + log2 = 0; + while (value) { + value >>= 1; + log2++; + } + return 1 << log2; +} + +static inline +int qdf_get_cpu(void) +{ + return __qdf_get_cpu(); +} + +/** + * qdf_device_init_wakeup() - allow a device to wake up the aps system + * @qdf_dev: the qdf device context + * @enable: enable/disable the device as a wakup source + * + * Return: 0 or errno + */ +static inline int qdf_device_init_wakeup(qdf_device_t qdf_dev, bool enable) +{ + return __qdf_device_init_wakeup(qdf_dev, enable); +} + +static inline +uint64_t qdf_get_totalramsize(void) +{ + return __qdf_get_totalramsize(); +} + +/** + * qdf_get_lower_32_bits() - get lower 32 bits from an address. + * @addr: address + * + * This api returns the lower 32 bits of an address. + * + * Return: lower 32 bits. + */ +static inline +uint32_t qdf_get_lower_32_bits(qdf_dma_addr_t addr) +{ + return __qdf_get_lower_32_bits(addr); +} + +/** + * qdf_get_upper_32_bits() - get upper 32 bits from an address. + * @addr: address + * + * This api returns the upper 32 bits of an address. + * + * Return: upper 32 bits. + */ +static inline +uint32_t qdf_get_upper_32_bits(qdf_dma_addr_t addr) +{ + return __qdf_get_upper_32_bits(addr); +} + +/** + * qdf_rounddown_pow_of_two() - Round down to nearest power of two + * @n: number to be tested + * + * Test if the input number is power of two, and return the nearest power of two + * + * Return: number rounded down to the nearest power of two + */ +static inline +unsigned long qdf_rounddown_pow_of_two(unsigned long n) +{ + return __qdf_rounddown_pow_of_two(n); +} + +/** + * qdf_is_group_addr() - checks whether addr is multi cast + * @mac_addr: address to be checked for multicast + * + * Check if the input mac addr is multicast addr + * + * Return: true if multicast addr else false + */ +static inline +bool qdf_is_group_addr(uint8_t *mac_addr) +{ + if (mac_addr[0] & 0x01) + return true; + else + return false; +} + +/** + * qdf_set_dma_coherent_mask() - set max number of bits allowed in dma addr + * @dev: device pointer + * @addr_bits: max number of bits allowed in dma address + * + * This API sets the maximum allowed number of bits in the dma address. + * + * Return: 0 - success, non zero - failure + */ +static inline +int qdf_set_dma_coherent_mask(struct device *dev, uint8_t addr_bits) +{ + return __qdf_set_dma_coherent_mask(dev, addr_bits); +} + +/** + * qdf_do_div() - wrapper function for kernel macro(do_div). + * @dividend: Dividend value + * @divisor : Divisor value + * + * Return: Quotient + */ +static inline +uint64_t qdf_do_div(uint64_t dividend, uint32_t divisor) +{ + return __qdf_do_div(dividend, divisor); +} + +/** + * qdf_do_mod() - wrapper function for kernel macro(do_div). + * @dividend: Dividend value + * @divisor : Divisor value + * + * Return: Modulo + */ +static inline +uint64_t qdf_do_mod(uint64_t dividend, uint32_t divisor) +{ + return __qdf_do_mod(dividend, divisor); +} +#endif /*_QDF_UTIL_H*/ diff --git a/drivers/staging/qca-wifi-host-cmn/qdf/linux/src/i_osdep.h b/drivers/staging/qca-wifi-host-cmn/qdf/linux/src/i_osdep.h new file mode 100644 index 0000000000000000000000000000000000000000..c18fe1a6ca26666a20b76304c22f418d4230b2a5 --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/qdf/linux/src/i_osdep.h @@ -0,0 +1,212 @@ +/* + * Copyright (c) 2013-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: i_osdep + * QCA driver framework OS dependent types + */ + +#ifndef _I_OSDEP_H +#define _I_OSDEP_H + +#ifdef CONFIG_MCL +#include +#include +#else +#include +#endif + +/* + * Byte Order stuff + */ +#define le16toh(_x) le16_to_cpu(_x) +#define htole16(_x) cpu_to_le16(_x) +#define htobe16(_x) cpu_to_be16(_x) +#define le32toh(_x) le32_to_cpu(_x) +#define htole32(_x) cpu_to_le32(_x) +#define be16toh(_x) be16_to_cpu(_x) +#define be32toh(_x) be32_to_cpu(_x) +#define htobe32(_x) cpu_to_be32(_x) + +typedef struct timer_list os_timer_t; + +#ifdef CONFIG_SMP +/* Undo the one provided by the kernel to debug spin locks */ +#undef spin_lock +#undef spin_unlock +#undef spin_trylock + +#define spin_lock(x) \ + do { \ + spin_lock_bh(x); \ + } while (0) + +#define spin_unlock(x) \ + do { \ + if (!spin_is_locked(x)) { \ + WARN_ON(1); \ + printk(KERN_EMERG " %s:%d unlock addr=%p, %s \n", __func__, __LINE__, x, \ + !spin_is_locked(x) ? "Not locked" : ""); \ + } \ + spin_unlock_bh(x); \ + } while (0) +#define spin_trylock(x) spin_trylock_bh(x) +#define OS_SUPPORT_ASYNC_Q 1 /* support for handling asyn function calls */ + +#else +#define OS_SUPPORT_ASYNC_Q 0 +#endif /* ifdef CONFIG_SMP */ + +/** + * struct os_mest_t - maintain attributes of message + * @mesg_next: pointer to the nexgt message + * @mest_type: type of message + * @mesg_len: length of the message + */ +typedef struct _os_mesg_t { + STAILQ_ENTRY(_os_mesg_t) mesg_next; + uint16_t mesg_type; + uint16_t mesg_len; +} os_mesg_t; + +/** + * struct qdf_bus_context - Bus to hal context handoff + * @bc_tag: bus context tag + * @cal_in_flash: calibration data stored in flash + * @bc_handle: bus context handle + * @bc_bustype: bus type + */ +typedef struct qdf_bus_context { + void *bc_tag; + int cal_in_flash; + char *bc_handle; + enum qdf_bus_type bc_bustype; +} QDF_BUS_CONTEXT; + +typedef struct _NIC_DEV *osdev_t; + +typedef void (*os_mesg_handler_t)(void *ctx, uint16_t mesg_type, + uint16_t mesg_len, + void *mesg); + + +/** + * typedef os_mesg_queue_t - Object to maintain message queue + * @dev_handle: OS handle + * @num_queued: number of queued messages + * @mesg_len: message length + * @mesg_queue_buf: pointer to message queue buffer + * @mesg_head: queued mesg buffers + * @mesg_free_head: free mesg buffers + * @lock: spinlock object + * @ev_handler_lock: spinlock object to event handler + * @task: pointer to task + * @_timer: instance of timer + * @handler: message handler + * @ctx: pointer to context + * @is_synchronous: bit to save synchronous status + * @del_progress: delete in progress + */ +typedef struct { + osdev_t dev_handle; + int32_t num_queued; + int32_t mesg_len; + uint8_t *mesg_queue_buf; + STAILQ_HEAD(, _os_mesg_t) mesg_head; + STAILQ_HEAD(, _os_mesg_t) mesg_free_head; + spinlock_t lock; + spinlock_t ev_handler_lock; +#ifdef USE_SOFTINTR + void *_task; +#else + os_timer_t _timer; +#endif + os_mesg_handler_t handler; + void *ctx; + uint8_t is_synchronous:1; + uint8_t del_progress; +} os_mesg_queue_t; + +/** + * struct _NIC_DEV - Definition of OS-dependent device structure. + * It'll be opaque to the actual ATH layer. + * @qdf_dev: qdf device + * @bdev: bus device handle + * @netdev: net device handle (wifi%d) + * @intr_tq: tasklet + * @devstats: net device statistics + * @bc: hal bus context + * @device: generic device + * @event_queue: instance to wait queue + * @wmi_timeout: init timeout + * @wmi_timeout_unintr: init timeout (uninterrupted wait) + * @is_device_asleep: keep device status, sleep or awakei + * @acfg_event_list: event list + * @acfg_event_queue_lock: queue lock + * @acfg_event_os_work: schedule or create work + * @acfg_netlink_wq_init_done: Work queue ready + * @osdev_acfg_handle: acfg handle + */ +struct _NIC_DEV { + qdf_device_t qdf_dev; + void *bdev; + struct net_device *netdev; + qdf_bh_t intr_tq; + struct net_device_stats devstats; + QDF_BUS_CONTEXT bc; +#ifdef ATH_PERF_PWR_OFFLOAD + struct device *device; + wait_queue_head_t event_queue; + unsigned int wmi_timeout; + unsigned int wmi_timeout_unintr; +#endif /* PERF_PWR_OFFLOAD */ +#if OS_SUPPORT_ASYNC_Q + os_mesg_queue_t async_q; +#endif +#ifdef ATH_BUS_PM + uint8_t is_device_asleep; +#endif /* ATH_BUS_PM */ + qdf_nbuf_queue_t acfg_event_list; + qdf_spinlock_t acfg_event_queue_lock; + qdf_work_t acfg_event_os_work; + uint8_t acfg_netlink_wq_init_done; + +#ifdef UMAC_SUPPORT_ACFG +#ifdef ACFG_NETLINK_TX + void *osdev_acfg_handle; +#endif /* ACFG_NETLINK_TX */ +#endif /* UMAC_SUPPORT_ACFG */ + +}; + +#define __QDF_SYSCTL_PROC_DOINTVEC(ctl, write, filp, buffer, lenp, ppos) \ + proc_dointvec(ctl, write, buffer, lenp, ppos) + +#define __QDF_SYSCTL_PROC_DOSTRING(ctl, write, filp, buffer, lenp, ppos) \ + proc_dostring(ctl, write, filp, buffer, lenp, ppos) + +#endif /* _I_OSDEP_H */ diff --git a/drivers/staging/qca-wifi-host-cmn/qdf/linux/src/i_qdf_atomic.h b/drivers/staging/qca-wifi-host-cmn/qdf/linux/src/i_qdf_atomic.h new file mode 100644 index 0000000000000000000000000000000000000000..4d5f5eb30bd3e47cc522d28809057fb5a473c040 --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/qdf/linux/src/i_qdf_atomic.h @@ -0,0 +1,237 @@ +/* + * Copyright (c) 2014-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: i_qdf_atomic.h + * This file provides OS dependent atomic APIs. + */ + +#ifndef I_QDF_ATOMIC_H +#define I_QDF_ATOMIC_H + +#include /* QDF_STATUS */ +#include +#include + +typedef atomic_t __qdf_atomic_t; + +/** + * __qdf_atomic_init() - initialize an atomic type variable + * @v: A pointer to an opaque atomic variable + * + * Return: QDF_STATUS + */ +static inline QDF_STATUS __qdf_atomic_init(__qdf_atomic_t *v) +{ + atomic_set(v, 0); + return QDF_STATUS_SUCCESS; +} + +/** + * __qdf_atomic_read() - read the value of an atomic variable + * @v: A pointer to an opaque atomic variable + * + * Return: The current value of the variable + */ +static inline int32_t __qdf_atomic_read(__qdf_atomic_t *v) +{ + return atomic_read(v); +} + +/** + * __qdf_atomic_inc() - increment the value of an atomic variable + * @v: A pointer to an opaque atomic variable + * + * Return: None + */ +static inline void __qdf_atomic_inc(__qdf_atomic_t *v) +{ + atomic_inc(v); +} + +/** + * __qdf_atomic_dec() - decrement the value of an atomic variable + * @v: A pointer to an opaque atomic variable + * + * Return: None + */ +static inline void __qdf_atomic_dec(__qdf_atomic_t *v) +{ + atomic_dec(v); +} + +/** + * __qdf_atomic_add() - add a value to the value of an atomic variable + * @i: The amount by which to increase the atomic counter + * @v: A pointer to an opaque atomic variable + * + * Return: None + */ +static inline void __qdf_atomic_add(int i, __qdf_atomic_t *v) +{ + atomic_add(i, v); +} + +/** + * __qdf_atomic_sub() - Subtract a value from an atomic variable + * @i: the amount by which to decrease the atomic counter + * @v: a pointer to an opaque atomic variable + * + * Return: none + */ +static inline void __qdf_atomic_sub(int i, __qdf_atomic_t *v) +{ + atomic_sub(i, v); +} + +/** + * __qdf_atomic_dec_and_test() - decrement an atomic variable and check if the + * new value is zero + * @v: A pointer to an opaque atomic variable + * + * Return: + * true (non-zero) if the new value is zero, + * false (0) if the new value is non-zero + */ +static inline int32_t __qdf_atomic_dec_and_test(__qdf_atomic_t *v) +{ + return atomic_dec_and_test(v); +} + +/** + * __qdf_atomic_set() - set a value to the value of an atomic variable + * @v: A pointer to an opaque atomic variable + * + * Return: None + */ +static inline void __qdf_atomic_set(__qdf_atomic_t *v, int i) +{ + atomic_set(v, i); +} + +/** + * __qdf_atomic_inc_return() - return the incremented value of an atomic variable + * @v: A pointer to an opaque atomic variable + * + * Return: The current value of the variable + */ +static inline int32_t __qdf_atomic_inc_return(__qdf_atomic_t *v) +{ + return atomic_inc_return(v); +} + +/** + * __qdf_atomic_set_bit - Atomically set a bit in memory + * @nr: bit to set + * @addr: the address to start counting from + * + * Return: none + */ +static inline void __qdf_atomic_set_bit(int nr, volatile unsigned long *addr) +{ + set_bit(nr, addr); +} + +/** + * __qdf_atomic_clear_bit - Atomically clear a bit in memory + * @nr: bit to clear + * @addr: the address to start counting from + * + * Return: none + */ +static inline void __qdf_atomic_clear_bit(int nr, volatile unsigned long *addr) +{ + clear_bit(nr, addr); +} + +/** + * __qdf_atomic_change_bit - Atomically toggle a bit in memory + * from addr + * @nr: bit to change + * @addr: the address to start counting from + * + * Return: none + */ +static inline void __qdf_atomic_change_bit(int nr, volatile unsigned long *addr) +{ + change_bit(nr, addr); +} + +/** + * __qdf_atomic_test_and_set_bit - Atomically set a bit and return its old value + * @nr: Bit to set + * @addr: the address to start counting from + * + * Return: return nr bit old value + */ +static inline int __qdf_atomic_test_and_set_bit(int nr, + volatile unsigned long *addr) +{ + return test_and_set_bit(nr, addr); +} + +/** + * __qdf_atomic_test_and_clear_bit - Atomically clear a bit and return its old + * value + * @nr: bit to clear + * @addr: the address to start counting from + * + * Return: return nr bit old value + */ +static inline int __qdf_atomic_test_and_clear_bit(int nr, + volatile unsigned long *addr) +{ + return test_and_clear_bit(nr, addr); +} + +/** + * __qdf_atomic_test_and_change_bit - Atomically toggle a bit and return its old + * value + * @nr: bit to change + * @addr: the address to start counting from + * + * Return: return nr bit old value + */ +static inline int __qdf_atomic_test_and_change_bit(int nr, + volatile unsigned long *addr) +{ + return test_and_change_bit(nr, addr); +} + +/** + * __qdf_atomic_test_bit - Atomically get the nr-th bit value starting from addr + * @nr: bit to get + * @addr: the address to start counting from + * + * Return: return nr bit value + */ +static inline int __qdf_atomic_test_bit(int nr, volatile unsigned long *addr) +{ + return test_bit(nr, addr); +} + +#endif diff --git a/drivers/staging/qca-wifi-host-cmn/qdf/linux/src/i_qdf_debugfs.h b/drivers/staging/qca-wifi-host-cmn/qdf/linux/src/i_qdf_debugfs.h new file mode 100644 index 0000000000000000000000000000000000000000..4f64484a3cdffb987f3a27349a32dd252dde1f67 --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/qdf/linux/src/i_qdf_debugfs.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2017 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. + */ + +/** + * DOC: qdf_debugfs.h + * Linux specific implementation for debug filesystem APIs. + */ + + +#ifndef _I_QDF_DEBUGFS_H +#define _I_QDF_DEBUGFS_H + +#include +#include + +#ifdef WLAN_DEBUGFS + +struct dentry *qdf_debugfs_get_root(void); + +#endif /* WLAN_DEBUGFS */ +#endif /* _I_QDF_DEBUGFS_H */ diff --git a/drivers/staging/qca-wifi-host-cmn/qdf/linux/src/i_qdf_defer.h b/drivers/staging/qca-wifi-host-cmn/qdf/linux/src/i_qdf_defer.h new file mode 100644 index 0000000000000000000000000000000000000000..d2a2f730487d1225c1af0848d1150f0834a0d5c7 --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/qdf/linux/src/i_qdf_defer.h @@ -0,0 +1,396 @@ +/* + * Copyright (c) 2014-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: i_qdf_defer.h + * This file provides OS dependent deferred API's. + */ + +#ifndef _I_QDF_DEFER_H +#define _I_QDF_DEFER_H + +#include +#include +#include +#include +#include +#include + +typedef struct tasklet_struct __qdf_bh_t; +typedef struct workqueue_struct __qdf_workqueue_t; + +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 19) +typedef struct work_struct __qdf_work_t; +typedef struct work_struct __qdf_delayed_work_t; +#else + +/** + * __qdf_work_t - wrapper around the real task func + * @work: Instance of work + * @fn: function pointer to the handler + * @arg: pointer to argument + */ +typedef struct { + struct work_struct work; + qdf_defer_fn_t fn; + void *arg; +} __qdf_work_t; + +/** + * __qdf_delayed_work_t - wrapper around the real work func + * @dwork: Instance of delayed work + * @fn: function pointer to the handler + * @arg: pointer to argument + */ +typedef struct { + struct delayed_work dwork; + qdf_defer_fn_t fn; + void *arg; +} __qdf_delayed_work_t; + +extern void __qdf_defer_func(struct work_struct *work); +extern void __qdf_defer_delayed_func(struct work_struct *work); +#endif + +typedef void (*__qdf_bh_fn_t)(unsigned long arg); + +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 19) +/** + * __qdf_init_work - Initialize a work/task queue, This runs in non-interrupt + * context, so can be preempted by H/W & S/W intr + * @hdl: OS handle + * @work: pointer to work + * @func: deferred function to run at bottom half non-interrupt context. + * @arg: argument for the deferred function + * Return: none + */ +static inline QDF_STATUS __qdf_init_work(qdf_handle_t hdl, + __qdf_work_t *work, + qdf_defer_fn_t func, void *arg) +{ + /*Initilize func and argument in work struct */ + INIT_WORK(&work->work, __qdf_defer_func); + return QDF_STATUS_SUCCESS; +} + +/** + * __qdf_init_delayed_work - create a work/task, This runs in non-interrupt + * context, so can be preempted by H/W & S/W intr + * @hdl: OS handle + * @work: pointer to work + * @func: deferred function to run at bottom half non-interrupt context. + * @arg: argument for the deferred function + * Return: none + */ +static inline uint32_t __qdf_init_delayed_work(qdf_handle_t hdl, + __qdf_delayed_work_t *work, + qdf_defer_fn_t func, void *arg) +{ + INIT_WORK(work, func, arg); + return QDF_STATUS_SUCCESS; +} + +/** + * __qdf_queue_work - Queue the work/task + * @hdl: OS handle + * @wqueue: pointer to workqueue + * @work: pointer to work + * Return: none + */ +static inline void __qdf_queue_work(qdf_handle_t hdl, + __qdf_workqueue_t *wqueue, + __qdf_work_t *work) +{ + queue_work(wqueue, work); +} + +/** + * __qdf_queue_delayed_work - Queue the delayed work/task + * @hdl: OS handle + * @wqueue: pointer to workqueue + * @work: pointer to work + * @delay: delay interval + * Return: none + */ +static inline void __qdf_queue_delayed_work(qdf_handle_t hdl, + __qdf_workqueue_t *wqueue, + __qdf_delayed_work_t *work, + uint32_t delay) +{ + queue_delayed_work(wqueue, work, delay); +} + +/** + * __qdf_sched_work - Schedule a deferred task on non-interrupt context + * @hdl: OS handle + * @work: pointer to work + * Retrun: none + */ +static inline QDF_STATUS __qdf_sched_work(qdf_handle_t hdl, __qdf_work_t *work) +{ + schedule_work(work); + return QDF_STATUS_SUCCESS; +} + +/** + * __qdf_sched_delayed_work() - Schedule a delayed work + * @hdl: OS handle + * @work: pointer to delayed work + * @delay: delay interval + * Return: none + */ +static inline QDF_STATUS __qdf_sched_delayed_work(qdf_handle_t hdl, + __qdf_delayed_work_t *work, + uint32_t delay) +{ + schedule_delayed_work(work, delay); + return QDF_STATUS_SUCCESS; +} + +/** + * __qdf_cancel_work() - Cancel a work + * @hdl: OS handle + * @work: pointer to work + * Return: true if work was pending, false otherwise + */ +static inline bool __qdf_cancel_work(qdf_handle_t hdl, + __qdf_work_t *work) +{ + return cancel_work_sync(work); +} + +/** + * __qdf_cancel_delayed_work() - Cancel a delayed work + * @hdl: OS handle + * @work: pointer to delayed work + * Return: true if work was pending, false otherwise + */ +static inline bool __qdf_cancel_delayed_work(qdf_handle_t hdl, + __qdf_delayed_work_t *work) +{ + return cancel_delayed_work_sync(work); +} + +/** + * __qdf_flush_work - Flush a deferred task on non-interrupt context + * @hdl: OS handle + * @work: pointer to work + * Return: none + */ +static inline uint32_t __qdf_flush_work(qdf_handle_t hdl, __qdf_work_t *work) +{ + flush_work(work); + return QDF_STATUS_SUCCESS; +} + +/** + * __qdf_flush_delayed_work() - Flush a delayed work + * @hdl: OS handle + * @work: pointer to delayed work + * Return: none + */ +static inline uint32_t __qdf_flush_delayed_work(qdf_handle_t hdl, + __qdf_delayed_work_t *work) +{ + flush_delayed_work(work); + return QDF_STATUS_SUCCESS; +} + +#else +static inline QDF_STATUS __qdf_init_work(qdf_handle_t hdl, + __qdf_work_t *work, + qdf_defer_fn_t func, void *arg) +{ + work->fn = func; + work->arg = arg; + INIT_WORK(&work->work, __qdf_defer_func); + return QDF_STATUS_SUCCESS; +} + +static inline uint32_t __qdf_init_delayed_work(qdf_handle_t hdl, + __qdf_delayed_work_t *work, + qdf_defer_fn_t func, void *arg) +{ + /*Initilize func and argument in work struct */ + work->fn = func; + work->arg = arg; + INIT_DELAYED_WORK(&work->dwork, __qdf_defer_delayed_func); + return QDF_STATUS_SUCCESS; +} + +static inline void __qdf_queue_work(qdf_handle_t hdl, + __qdf_workqueue_t *wqueue, + __qdf_work_t *work) +{ + queue_work(wqueue, &work->work); +} + +static inline void __qdf_queue_delayed_work(qdf_handle_t hdl, + __qdf_workqueue_t *wqueue, + __qdf_delayed_work_t *work, + uint32_t delay) +{ + queue_delayed_work(wqueue, &work->dwork, delay); +} + +static inline QDF_STATUS __qdf_sched_work(qdf_handle_t hdl, __qdf_work_t *work) +{ + schedule_work(&work->work); + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS __qdf_sched_delayed_work(qdf_handle_t hdl, + __qdf_delayed_work_t *work, + uint32_t delay) +{ + schedule_delayed_work(&work->dwork, delay); + return QDF_STATUS_SUCCESS; +} + +static inline bool __qdf_cancel_work(qdf_handle_t hdl, + __qdf_work_t *work) +{ + return cancel_work_sync(&work->work); +} + +static inline bool __qdf_cancel_delayed_work(qdf_handle_t hdl, + __qdf_delayed_work_t *work) +{ + return cancel_delayed_work_sync(&work->dwork); +} + +static inline uint32_t __qdf_flush_work(qdf_handle_t hdl, __qdf_work_t *work) +{ + flush_work(&work->work); + return QDF_STATUS_SUCCESS; +} +static inline uint32_t __qdf_flush_delayed_work(qdf_handle_t hdl, + __qdf_delayed_work_t *work) +{ + flush_delayed_work(&work->dwork); + return QDF_STATUS_SUCCESS; +} + +#endif + +/** + * __qdf_create_workqueue - create a workqueue, This runs in non-interrupt + * context, so can be preempted by H/W & S/W intr + * @name: string + * Return: pointer of type qdf_workqueue_t + */ +static inline __qdf_workqueue_t *__qdf_create_workqueue(char *name) +{ + return create_workqueue(name); +} + +/** + * __qdf_flush_workqueue - flush the workqueue + * @hdl: OS handle + * @wqueue: pointer to workqueue + * Return: none + */ +static inline void __qdf_flush_workqueue(qdf_handle_t hdl, + __qdf_workqueue_t *wqueue) +{ + flush_workqueue(wqueue); +} + +/** + * __qdf_destroy_workqueue - Destroy the workqueue + * @hdl: OS handle + * @wqueue: pointer to workqueue + * Return: none + */ +static inline void __qdf_destroy_workqueue(qdf_handle_t hdl, + __qdf_workqueue_t *wqueue) +{ + destroy_workqueue(wqueue); +} + +/** + * __qdf_init_bh - creates the Bottom half deferred handler + * @hdl: OS handle + * @bh: pointer to bottom + * @func: deferred function to run at bottom half interrupt context. + * @arg: argument for the deferred function + * Return: none + */ +static inline QDF_STATUS __qdf_init_bh(qdf_handle_t hdl, + struct tasklet_struct *bh, + qdf_defer_fn_t func, void *arg) +{ + tasklet_init(bh, (__qdf_bh_fn_t) func, (unsigned long)arg); + return QDF_STATUS_SUCCESS; +} + +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 19) +#else +#endif + +/** + * __qdf_sched_bh - schedule a bottom half (DPC) + * @hdl: OS handle + * @bh: pointer to bottom + * Return: none + */ +static inline QDF_STATUS +__qdf_sched_bh(qdf_handle_t hdl, struct tasklet_struct *bh) +{ + tasklet_schedule(bh); + return QDF_STATUS_SUCCESS; +} + +/** + * __qdf_disable_work - disable the deferred task (synchronous) + * @hdl: OS handle + * @work: pointer to work + * Return: unsigned int + */ +static inline QDF_STATUS +__qdf_disable_work(qdf_handle_t hdl, __qdf_work_t *work) +{ + if (cancel_work_sync(&work->work)) + return QDF_STATUS_E_ALREADY; + + return QDF_STATUS_SUCCESS; +} + +/** + * __qdf_disable_bh - destroy the bh (synchronous) + * @hdl: OS handle + * @bh: pointer to bottom + * Return: none + */ +static inline QDF_STATUS +__qdf_disable_bh(qdf_handle_t hdl, struct tasklet_struct *bh) +{ + tasklet_kill(bh); + return QDF_STATUS_SUCCESS; +} + +#endif /*_I_QDF_DEFER_H*/ diff --git a/drivers/staging/qca-wifi-host-cmn/qdf/linux/src/i_qdf_event.h b/drivers/staging/qca-wifi-host-cmn/qdf/linux/src/i_qdf_event.h new file mode 100644 index 0000000000000000000000000000000000000000..2c634423a7204a5dc3f50926b70ae00c5f56b8fe --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/qdf/linux/src/i_qdf_event.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2014-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: i_qdf_event.h + * This file provides OS dependent event API's. + */ + +#if !defined(__I_QDF_EVENT_H) +#define __I_QDF_EVENT_H + +#include + +/** + * qdf_event_t - manages events + * @complete: instance to completion + * @cookie: unsigned int + */ +typedef struct qdf_evt { + struct completion complete; + uint32_t cookie; +} __qdf_event_t; + +/* Preprocessor definitions and constants */ +#define LINUX_EVENT_COOKIE 0x12341234 + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) +#define INIT_COMPLETION(event) reinit_completion(&event) +#endif + +#endif /*__I_QDF_EVENT_H*/ diff --git a/drivers/staging/qca-wifi-host-cmn/qdf/linux/src/i_qdf_list.h b/drivers/staging/qca-wifi-host-cmn/qdf/linux/src/i_qdf_list.h new file mode 100644 index 0000000000000000000000000000000000000000..23cef762313f74867e88a8a5bf769c1905f94fbd --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/qdf/linux/src/i_qdf_list.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2014-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: i_qdf_list.h + * This file provides OS dependent list API's. + */ + +#if !defined(__I_QDF_LIST_H) +#define __I_QDF_LIST_H + +#include + +/* Type declarations */ +typedef struct list_head __qdf_list_node_t; + +/* Preprocessor definitions and constants */ + +typedef struct qdf_list_s { + __qdf_list_node_t anchor; + uint32_t count; + uint32_t max_size; +} __qdf_list_t; + +/** + * __qdf_list_create() - Initialize list head + * @list: object of list + * @max_size: max size of the list + * Return: none + */ +static inline void __qdf_list_create(__qdf_list_t *list, uint32_t max_size) +{ + INIT_LIST_HEAD(&list->anchor); + list->count = 0; + list->max_size = max_size; +} + +bool qdf_list_has_node(__qdf_list_t *list, __qdf_list_node_t *node); +#endif diff --git a/drivers/staging/qca-wifi-host-cmn/qdf/linux/src/i_qdf_lock.h b/drivers/staging/qca-wifi-host-cmn/qdf/linux/src/i_qdf_lock.h new file mode 100644 index 0000000000000000000000000000000000000000..d062db2f191a1a06cab9473a9c364a1fbd09b922 --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/qdf/linux/src/i_qdf_lock.h @@ -0,0 +1,341 @@ +/* + * Copyright (c) 2014-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: i_qdf_lock.h + * Linux-specific definitions for QDF Lock API's + */ + +#if !defined(__I_QDF_LOCK_H) +#define __I_QDF_LOCK_H + +/* Include Files */ +#include +#include +#include +#include +#include +#include +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 27) +#include +#else +#include +#endif +#include +#include + +/* define for flag */ +#define QDF_LINUX_UNLOCK_BH 1 + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +enum { + LOCK_RELEASED = 0x11223344, + LOCK_ACQUIRED, + LOCK_DESTROYED +}; + +/** + * typedef struct - __qdf_mutex_t + * @m_lock: Mutex lock + * @cookie: Lock cookie + * @process_id: Process ID to track lock + * @state: Lock status + * @refcount: Reference count for recursive lock + * @stats: a structure that contains usage statistics + */ +struct qdf_lock_s { + struct mutex m_lock; + uint32_t cookie; + int process_id; + uint32_t state; + uint8_t refcount; + struct lock_stats stats; +}; + +typedef struct qdf_lock_s __qdf_mutex_t; + +/** + * typedef struct - qdf_spinlock_t + * @spinlock: Spin lock + * @flags: Lock flag + */ +typedef struct __qdf_spinlock { + spinlock_t spinlock; + unsigned long flags; +} __qdf_spinlock_t; + +typedef struct semaphore __qdf_semaphore_t; + +typedef struct wakeup_source qdf_wake_lock_t; + +#define LINUX_LOCK_COOKIE 0x12345678 + +/* Function declarations and documenation */ + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 37) +/** + * __qdf_semaphore_init() - initialize the semaphore + * @m: Semaphore object + * + * Return: QDF_STATUS_SUCCESS + */ +static inline QDF_STATUS __qdf_semaphore_init(struct semaphore *m) +{ + init_MUTEX(m); + return QDF_STATUS_SUCCESS; +} +#else +static inline QDF_STATUS __qdf_semaphore_init(struct semaphore *m) +{ + sema_init(m, 1); + return QDF_STATUS_SUCCESS; +} +#endif + +/** + * __qdf_semaphore_acquire() - acquire semaphore + * @m: Semaphore object + * + * Return: 0 + */ +static inline int __qdf_semaphore_acquire(struct semaphore *m) +{ + down(m); + return 0; +} + +/** + * __qdf_semaphore_acquire_intr() - down_interruptible allows a user-space + * process that is waiting on a semaphore to be interrupted by the user. + * If the operation is interrupted, the function returns a nonzero value, + * and the caller does not hold the semaphore. + * Always checking the return value and responding accordingly. + * @osdev: OS device handle + * @m: Semaphore object + * + * Return: int + */ +static inline int __qdf_semaphore_acquire_intr(struct semaphore *m) +{ + return down_interruptible(m); +} + +/** + * __qdf_semaphore_release() - release semaphore + * @m: Semaphore object + * + * Return: result of UP operation in integer + */ +static inline void __qdf_semaphore_release(struct semaphore *m) +{ + up(m); +} + +/** + * __qdf_semaphore_acquire_timeout() - Take the semaphore before timeout + * @m: semaphore to take + * @timeout: maximum time to try to take the semaphore + * Return: int + */ +static inline int __qdf_semaphore_acquire_timeout(struct semaphore *m, + unsigned long timeout) +{ + unsigned long jiffie_val = msecs_to_jiffies(timeout); + return down_timeout(m, jiffie_val); +} + +/** + * __qdf_spinlock_create() - initialize spin lock + * @lock: Spin lock object + * + * Return: QDF_STATUS_SUCCESS + */ +static inline QDF_STATUS __qdf_spinlock_create(__qdf_spinlock_t *lock) +{ + spin_lock_init(&lock->spinlock); + lock->flags = 0; + return QDF_STATUS_SUCCESS; +} + +#define __qdf_spinlock_destroy(lock) + +/** + * __qdf_spin_lock() - Acquire a Spinlock(SMP) & disable Preemption (Preemptive) + * @lock: Lock object + * + * Return: none + */ +static inline void __qdf_spin_lock(__qdf_spinlock_t *lock) +{ + spin_lock(&lock->spinlock); +} + +/** + * __qdf_spin_unlock() - Unlock the spinlock and enables the Preemption + * @lock: Lock object + * + * Return: none + */ +static inline void __qdf_spin_unlock(__qdf_spinlock_t *lock) +{ + spin_unlock(&lock->spinlock); +} + +/** + * __qdf_spin_lock_irqsave() - Acquire a Spinlock (SMP) & disable Preemption + * (Preemptive) and disable IRQs + * @lock: Lock object + * + * Return: none + */ +static inline void __qdf_spin_lock_irqsave(__qdf_spinlock_t *lock) +{ + spin_lock_irqsave(&lock->spinlock, lock->flags); +} + +/** + * __qdf_spin_unlock_irqrestore() - Unlock the spinlock and enables the + * Preemption and enable IRQ + * @lock: Lock object + * + * Return: none + */ +static inline void __qdf_spin_unlock_irqrestore(__qdf_spinlock_t *lock) +{ + spin_unlock_irqrestore(&lock->spinlock, lock->flags); +} + +/* + * Synchronous versions - only for OS' that have interrupt disable + */ +#define __qdf_spin_lock_irq(_p_lock, _flags) spin_lock_irqsave(_p_lock, _flags) +#define __qdf_spin_unlock_irq(_p_lock, _flags) \ + spin_unlock_irqrestore(_p_lock, _flags) + +/** + * __qdf_spin_is_locked(__qdf_spinlock_t *lock) + * @lock: spinlock object + * + * Return: nonzero if lock is held. + */ +static inline int __qdf_spin_is_locked(__qdf_spinlock_t *lock) +{ + return spin_is_locked(&lock->spinlock); +} + +/** + * __qdf_spin_trylock_bh() - spin trylock bottomhalf + * @lock: spinlock object + * + * Return: nonzero if lock is acquired + */ +static inline int __qdf_spin_trylock_bh(__qdf_spinlock_t *lock) +{ + if (likely(irqs_disabled() || in_irq() || in_softirq())) { + return spin_trylock(&lock->spinlock); + } else { + if (spin_trylock_bh(&lock->spinlock)) { + lock->flags |= QDF_LINUX_UNLOCK_BH; + return 1; + } else { + return 0; + } + } +} + +/** + * __qdf_spin_lock_bh() - Acquire the spinlock and disable bottom halves + * @lock: Lock object + * + * Return: none + */ +static inline void __qdf_spin_lock_bh(__qdf_spinlock_t *lock) +{ + if (likely(irqs_disabled() || in_irq() || in_softirq())) { + spin_lock(&lock->spinlock); + } else { + spin_lock_bh(&lock->spinlock); + lock->flags |= QDF_LINUX_UNLOCK_BH; + } +} + +/** + * __qdf_spin_unlock_bh() - Release the spinlock and enable bottom halves + * @lock: Lock object + * + * Return: none + */ +static inline void __qdf_spin_unlock_bh(__qdf_spinlock_t *lock) +{ + if (unlikely(lock->flags & QDF_LINUX_UNLOCK_BH)) { + lock->flags &= ~QDF_LINUX_UNLOCK_BH; + spin_unlock_bh(&lock->spinlock); + } else + spin_unlock(&lock->spinlock); +} + +/** + * __qdf_spinlock_irq_exec - Execute the input function with spinlock held and interrupt disabled. + * @hdl: OS handle + * @lock: spinlock to be held for the critical region + * @func: critical region function that to be executed + * @context: context of the critical region function + * @return - Boolean status returned by the critical region function + */ +static inline bool __qdf_spinlock_irq_exec(qdf_handle_t hdl, + __qdf_spinlock_t *lock, + qdf_irqlocked_func_t func, + void *arg) +{ + unsigned long flags; + bool ret; + + spin_lock_irqsave(&lock->spinlock, flags); + ret = func(arg); + spin_unlock_irqrestore(&lock->spinlock, flags); + + return ret; +} + +/** + * __qdf_in_softirq() - in soft irq context + * + * Return: true if in softirs context else false + */ +static inline bool __qdf_in_softirq(void) +{ + return in_softirq(); +} + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __I_QDF_LOCK_H */ diff --git a/drivers/staging/qca-wifi-host-cmn/qdf/linux/src/i_qdf_mc_timer.h b/drivers/staging/qca-wifi-host-cmn/qdf/linux/src/i_qdf_mc_timer.h new file mode 100644 index 0000000000000000000000000000000000000000..f7d6df7ad18ebe72bc4c35695e708b664023497e --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/qdf/linux/src/i_qdf_mc_timer.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2014-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: i_qdf_mc_timer.h + * Linux-specific definitions for QDF timers serialized to MC thread + */ + +#if !defined(__I_QDF_MC_TIMER_H) +#define __I_QDF_MC_TIMER_H + +/* Include Files */ +#include +#include +#include +#include +#include +#include + +/* Preprocessor definitions and constants */ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ +/* Type declarations */ + +typedef struct qdf_mc_timer_platform_s { + struct timer_list timer; + int thread_id; + uint32_t cookie; + qdf_spinlock_t spinlock; +} qdf_mc_timer_platform_t; + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* __I_QDF_MC_TIMER_H */ diff --git a/drivers/staging/qca-wifi-host-cmn/qdf/linux/src/i_qdf_mem.h b/drivers/staging/qca-wifi-host-cmn/qdf/linux/src/i_qdf_mem.h new file mode 100644 index 0000000000000000000000000000000000000000..ebc2868bf22b053f4879a9aa687e721c3ecdaab4 --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/qdf/linux/src/i_qdf_mem.h @@ -0,0 +1,213 @@ +/* + * Copyright (c) 2014-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: i_qdf_mem.h + * Linux-specific definitions for QDF memory API's + */ + +#ifndef __I_QDF_MEM_H +#define __I_QDF_MEM_H + +#ifdef __KERNEL__ +#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17) +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 33) +#include +#else +#include +#endif +#endif +#include +#include +#include +#include /* pci_alloc_consistent */ +#if CONFIG_MCL +#include +#else +#include +#endif +#else +/* + * Provide dummy defs for kernel data types, functions, and enums + * used in this header file. + */ +#define GFP_KERNEL 0 +#define GFP_ATOMIC 0 +#define kzalloc(size, flags) NULL +#define vmalloc(size) NULL +#define kfree(buf) +#define vfree(buf) +#define pci_alloc_consistent(dev, size, paddr) NULL +#define __qdf_mempool_t void* +#endif /* __KERNEL__ */ +#include + +#ifdef __KERNEL__ +typedef struct mempool_elem { + STAILQ_ENTRY(mempool_elem) mempool_entry; +} mempool_elem_t; + +/** + * typedef __qdf_mempool_ctxt_t - Memory pool context + * @pool_id: pool identifier + * @flags: flags + * @elem_size: size of each pool element in bytes + * @pool_mem: pool_addr address of the pool created + * @mem_size: Total size of the pool in bytes + * @free_list: free pool list + * @lock: spinlock object + * @max_elem: Maximum number of elements in tha pool + * @free_cnt: Number of free elements available + */ +typedef struct __qdf_mempool_ctxt { + int pool_id; + u_int32_t flags; + size_t elem_size; + void *pool_mem; + u_int32_t mem_size; + STAILQ_HEAD(, mempool_elem) free_list; + spinlock_t lock; + u_int32_t max_elem; + u_int32_t free_cnt; +} __qdf_mempool_ctxt_t; + +#endif /* __KERNEL__ */ + +/* typedef for dma_data_direction */ +typedef enum dma_data_direction __dma_data_direction; + +/** + * __qdf_str_cmp() - Compare two strings + * @str1: First string + * @str2: Second string + * + * Return: =0 equal + * >0 not equal, if str1 sorts lexicographically after str2 + * <0 not equal, if str1 sorts lexicographically before str2 + */ +static inline int32_t __qdf_str_cmp(const char *str1, const char *str2) +{ + return strcmp(str1, str2); +} + +/** + * __qdf_str_lcopy() - Copy from one string to another + * @dest: destination string + * @src: source string + * @bytes: limit of num bytes to copy + * + * @return: 0 returns the initial value of dest + */ +static inline uint32_t __qdf_str_lcopy(char *dest, const char *src, + uint32_t bytes) +{ + return strlcpy(dest, src, bytes); +} + +/** + * __qdf_mem_map_nbytes_single - Map memory for DMA + * @osdev: pomter OS device context + * @buf: pointer to memory to be dma mapped + * @dir: DMA map direction + * @nbytes: number of bytes to be mapped. + * @phy_addr: ponter to recive physical address. + * + * Return: success/failure + */ +static inline uint32_t __qdf_mem_map_nbytes_single(qdf_device_t osdev, + void *buf, qdf_dma_dir_t dir, + int nbytes, + uint32_t *phy_addr) +{ + /* assume that the OS only provides a single fragment */ + *phy_addr = dma_map_single(osdev->dev, buf, nbytes, dir); + return dma_mapping_error(osdev->dev, *phy_addr) ? + QDF_STATUS_E_FAILURE : QDF_STATUS_SUCCESS; +} + +/** + * __qdf_mem_unmap_nbytes_single() - un_map memory for DMA + * + * @osdev: pomter OS device context + * @phy_addr: physical address of memory to be dma unmapped + * @dir: DMA unmap direction + * @nbytes: number of bytes to be unmapped. + * + * @return - none + */ +static inline void __qdf_mem_unmap_nbytes_single(qdf_device_t osdev, + uint32_t phy_addr, + qdf_dma_dir_t dir, int nbytes) +{ + dma_unmap_single(osdev->dev, phy_addr, nbytes, dir); +} +#ifdef __KERNEL__ + +typedef __qdf_mempool_ctxt_t *__qdf_mempool_t; + +int __qdf_mempool_init(qdf_device_t osdev, __qdf_mempool_t *pool, int pool_cnt, + size_t pool_entry_size, u_int32_t flags); +void __qdf_mempool_destroy(qdf_device_t osdev, __qdf_mempool_t pool); +void *__qdf_mempool_alloc(qdf_device_t osdev, __qdf_mempool_t pool); +void __qdf_mempool_free(qdf_device_t osdev, __qdf_mempool_t pool, void *buf); + +#define __qdf_mempool_elem_size(_pool) ((_pool)->elem_size); +#endif + +/** + * __qdf_str_len() - returns the length of a string + * @str: input string + * Return: + * length of string + */ +static inline int32_t __qdf_str_len(const char *str) +{ + return strlen(str); +} + +/** + * __qdf_mem_cmp() - memory compare + * @memory1: pointer to one location in memory to compare. + * @memory2: pointer to second location in memory to compare. + * @num_bytes: the number of bytes to compare. + * + * Function to compare two pieces of memory, similar to memcmp function + * in standard C. + * Return: + * int32_t - returns an int value that tells if the memory + * locations are equal or not equal. + * 0 -- equal + * < 0 -- *memory1 is less than *memory2 + * > 0 -- *memory1 is bigger than *memory2 + */ +static inline int32_t __qdf_mem_cmp(const void *memory1, const void *memory2, + uint32_t num_bytes) +{ + return (int32_t) memcmp(memory1, memory2, num_bytes); +} + +#endif /* __I_QDF_MEM_H */ diff --git a/drivers/staging/qca-wifi-host-cmn/qdf/linux/src/i_qdf_module.h b/drivers/staging/qca-wifi-host-cmn/qdf/linux/src/i_qdf_module.h new file mode 100644 index 0000000000000000000000000000000000000000..795d3659c6cbc63e5be59fbe3a4b4edff329376f --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/qdf/linux/src/i_qdf_module.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2010-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: i_qdf_module.h + * Linux-specific definitions for QDF module API's + */ + +#ifndef _I_QDF_MODULE_H +#define _I_QDF_MODULE_H + +#include +#include +#include +#include + + +#define __qdf_virt_module_init(_x) \ + static int _x##_mod(void) \ + { \ + uint32_t st; \ + st = (_x)(); \ + if (st != QDF_STATUS_SUCCESS) \ + return QDF_STATUS_E_INVAL; \ + else \ + return 0; \ + } \ + module_init(_x##_mod); + +#define __qdf_virt_module_exit(_x) module_exit(_x) + +#define __qdf_virt_module_name(_name) MODULE_LICENSE("Proprietary"); + +#define __qdf_export_symbol(_sym) EXPORT_SYMBOL(_sym) + +#define __qdf_declare_param(_name, _type) \ + module_param(_name, _type, 0600) + +#endif /* _I_QDF_MODULE_H */ diff --git a/drivers/staging/qca-wifi-host-cmn/qdf/linux/src/i_qdf_nbuf.h b/drivers/staging/qca-wifi-host-cmn/qdf/linux/src/i_qdf_nbuf.h new file mode 100644 index 0000000000000000000000000000000000000000..9e1ca509dc7069183d613803fcca825bdbc6e20f --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/qdf/linux/src/i_qdf_nbuf.h @@ -0,0 +1,1729 @@ +/* + * Copyright (c) 2014-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: i_qdf_nbuf.h + * This file provides OS dependent nbuf API's. + */ + +#ifndef _I_QDF_NBUF_H +#define _I_QDF_NBUF_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Use socket buffer as the underlying implentation as skbuf . + * Linux use sk_buff to represent both packet and data, + * so we use sk_buffer to represent both skbuf . + */ +typedef struct sk_buff *__qdf_nbuf_t; + +#define QDF_NBUF_CB_TX_MAX_OS_FRAGS 1 + +/* QDF_NBUF_CB_TX_MAX_EXTRA_FRAGS - + * max tx fragments added by the driver + * The driver will always add one tx fragment (the tx descriptor) + */ +#define QDF_NBUF_CB_TX_MAX_EXTRA_FRAGS 2 +#define QDF_NBUF_CB_PACKET_TYPE_EAPOL 1 +#define QDF_NBUF_CB_PACKET_TYPE_ARP 2 +#define QDF_NBUF_CB_PACKET_TYPE_WAPI 3 +#define QDF_NBUF_CB_PACKET_TYPE_DHCP 4 + +/* mark the first packet after wow wakeup */ +#define QDF_MARK_FIRST_WAKEUP_PACKET 0x80000000 + +/* + * Make sure that qdf_dma_addr_t in the cb block is always 64 bit aligned + */ +typedef union { + uint64_t u64; + qdf_dma_addr_t dma_addr; +} qdf_paddr_t; + +/** + * struct qdf_nbuf_cb - network buffer control block contents (skb->cb) + * - data passed between layers of the driver. + * + * Notes: + * 1. Hard limited to 48 bytes. Please count your bytes + * 2. The size of this structure has to be easily calculatable and + * consistently so: do not use any conditional compile flags + * 3. Split into a common part followed by a tx/rx overlay + * 4. There is only one extra frag, which represents the HTC/HTT header + * + * @common.paddr : physical addressed retrived by dma_map of nbuf->data + * @rx.lro_flags : hardware assisted flags: + * @rx.lro_eligible : flag to indicate whether the MSDU is LRO eligible + * @rx.tcp_proto : L4 protocol is TCP + * @rx.tcp_pure_ack : A TCP ACK packet with no payload + * @rx.ipv6_proto : L3 protocol is IPV6 + * @rx.ip_offset : offset to IP header + * @rx.tcp_offset : offset to TCP header + * @rx.tcp_udp_chksum : L4 payload checksum + * @rx.tcp_seq_num : TCP sequence number + * @rx.tcp_ack_num : TCP ACK number + * @rx.flow_id_toeplitz: 32-bit 5-tuple Toeplitz hash + * @tx.extra_frag : represent HTC/HTT header + * @tx.efrag.vaddr : virtual address of ~ + * @tx.efrag.paddr : physical/DMA address of ~ + * @tx.efrag.len : length of efrag pointed by the above pointers + * @tx.efrag.num : number of extra frags ( 0 or 1) + * @tx.efrag.flags.nbuf : flag, nbuf payload to be swapped (wordstream) + * @tx.efrag.flags.efrag : flag, efrag payload to be swapped (wordstream) + * @tx.efrag.flags.chfrag_start: used by WIN + * @tx.efrags.flags.chfrag_end: used by WIN + * @tx.data_attr : value that is programmed into CE descr, includes: + * + (1) CE classification enablement bit + * + (2) packet type (802.3 or Ethernet type II) + * + (3) packet offset (usually length of HTC/HTT descr) + * @tx.trace : combined structure for DP and protocol trace + * @tx.trace.packet_state: {NBUF_TX_PKT_[(HDD)|(TXRX_ENQUEUE)|(TXRX_DEQUEUE)| + * + (TXRX)|(HTT)|(HTC)|(HIF)|(CE)|(FREE)] + * @tx.trace.is_packet_priv: flag, pkt generated internally or come from NS + * @tx.trace.packet_track: {NBUF_TX_PKT_[(DATA)|(MGMT)]_TRACK} + * @tx.trace.proto_type : bitmap of NBUF_PKT_TRAC_TYPE[(EAPOL)|(DHCP)| + * + (MGMT_ACTION)] - 4 bits + * @tx.trace.dp_trace : flag (Datapath trace) + * @tx.trace.htt2_frm : flag (high-latency path only) + * @tx.trace.vdev_id : vdev (for protocol trace) + * @tx.ipa.owned : packet owned by IPA + * @tx.ipa.priv : private data, used by IPA + * @tx.desc_id : tx desc id, used to sync between host and fw + */ +struct qdf_nbuf_cb { + /* common */ + qdf_paddr_t paddr; /* of skb->data */ + /* valid only in one direction */ + union { + /* Note: MAX: 40 bytes */ + struct { + uint32_t lro_eligible:1, + peer_cached_buf_frm:1, + tcp_proto:1, + tcp_pure_ack:1, + ipv6_proto:1, + ip_offset:7, + tcp_offset:7, + rx_ctx_id:4; + uint32_t tcp_udp_chksum:16, + tcp_win:16; + uint32_t tcp_seq_num; + uint32_t tcp_ack_num; + uint32_t flow_id_toeplitz; + uint32_t map_index; + union { + uint8_t packet_state; + uint8_t dp_trace:1, + rsrvd:7; + } trace; + } rx; /* 20 bytes */ + + /* Note: MAX: 40 bytes */ + struct { + struct { + unsigned char *vaddr; + qdf_paddr_t paddr; + uint16_t len; + union { + struct { + uint8_t flag_efrag:1, + flag_nbuf:1, + num:1, + flag_chfrag_start:1, + flag_chfrag_end:1, + flag_ext_header:1, + reserved:2; + } bits; + uint8_t u8; + } flags; + } extra_frag; /* 19 bytes */ + union { + struct { + uint8_t ftype; + uint32_t submit_ts; + void *fctx; + void *vdev_ctx; + } win; /* 21 bytes*/ + struct { + uint32_t data_attr; /* 4 bytes */ + struct{ + uint8_t packet_state:7, + is_packet_priv:1; + uint8_t packet_track:4, + proto_type:4; + uint8_t dp_trace:1, + is_bcast:1, + is_mcast:1, + packet_type:3, + /* used only for hl*/ + htt2_frm:1, + print:1; + uint8_t vdev_id; + } trace; /* 4 bytes */ + struct { + uint32_t owned:1, + priv:31; + } ipa; /* 4 */ + uint16_t desc_id; /* 2 bytes */ + } mcl;/* 14 bytes*/ + } dev; + } tx; /* 40 bytes */ + } u; +}; /* struct qdf_nbuf_cb: MAX 48 bytes */ + +/** + * access macros to qdf_nbuf_cb + * Note: These macros can be used as L-values as well as R-values. + * When used as R-values, they effectively function as "get" macros + * When used as L_values, they effectively function as "set" macros + */ + +#define QDF_NBUF_CB_PADDR(skb) \ + (((struct qdf_nbuf_cb *)((skb)->cb))->paddr.dma_addr) + +#define QDF_NBUF_CB_RX_LRO_ELIGIBLE(skb) \ + (((struct qdf_nbuf_cb *)((skb)->cb))->u.rx.lro_eligible) +#define QDF_NBUF_CB_RX_PEER_CACHED_FRM(skb) \ + (((struct qdf_nbuf_cb *)((skb)->cb))->u.rx.peer_cached_buf_frm) +#define QDF_NBUF_CB_RX_CTX_ID(skb) \ + (((struct qdf_nbuf_cb *)((skb)->cb))->u.rx.rx_ctx_id) +#define QDF_NBUF_CB_RX_TCP_PROTO(skb) \ + (((struct qdf_nbuf_cb *)((skb)->cb))->u.rx.tcp_proto) +#define QDF_NBUF_CB_RX_TCP_PURE_ACK(skb) \ + (((struct qdf_nbuf_cb *)((skb)->cb))->u.rx.tcp_pure_ack) +#define QDF_NBUF_CB_RX_IPV6_PROTO(skb) \ + (((struct qdf_nbuf_cb *)((skb)->cb))->u.rx.ipv6_proto) +#define QDF_NBUF_CB_RX_IP_OFFSET(skb) \ + (((struct qdf_nbuf_cb *)((skb)->cb))->u.rx.ip_offset) +#define QDF_NBUF_CB_RX_TCP_OFFSET(skb) \ + (((struct qdf_nbuf_cb *)((skb)->cb))->u.rx.tcp_offset) +#define QDF_NBUF_CB_RX_TCP_CHKSUM(skb) \ + (((struct qdf_nbuf_cb *)((skb)->cb))->u.rx.tcp_udp_chksum) +#define QDF_NBUF_CB_RX_TCP_OFFSET(skb) \ + (((struct qdf_nbuf_cb *)((skb)->cb))->u.rx.tcp_offset) +#define QDF_NBUF_CB_RX_TCP_WIN(skb) \ + (((struct qdf_nbuf_cb *)((skb)->cb))->u.rx.tcp_win) +#define QDF_NBUF_CB_RX_TCP_SEQ_NUM(skb) \ + (((struct qdf_nbuf_cb *)((skb)->cb))->u.rx.tcp_seq_num) +#define QDF_NBUF_CB_RX_TCP_ACK_NUM(skb) \ + (((struct qdf_nbuf_cb *)((skb)->cb))->u.rx.tcp_ack_num) +#define QDF_NBUF_CB_RX_FLOW_ID_TOEPLITZ(skb) \ + (((struct qdf_nbuf_cb *)((skb)->cb))->u.rx.flow_id_toeplitz) +#define QDF_NBUF_CB_RX_DP_TRACE(skb) \ + (((struct qdf_nbuf_cb *)((skb)->cb))->u.rx.trace.dp_trace) + +#define QDF_NBUF_CB_TX_EXTRA_FRAG_VADDR(skb) \ + (((struct qdf_nbuf_cb *)((skb)->cb))->u.tx.extra_frag.vaddr) +#define QDF_NBUF_CB_TX_EXTRA_FRAG_PADDR(skb) \ + (((struct qdf_nbuf_cb *)((skb)->cb))->u.tx.extra_frag.paddr.dma_addr) +#define QDF_NBUF_CB_TX_EXTRA_FRAG_LEN(skb) \ + (((struct qdf_nbuf_cb *)((skb)->cb))->u.tx.extra_frag.len) +#define QDF_NBUF_CB_TX_NUM_EXTRA_FRAGS(skb) \ + (((struct qdf_nbuf_cb *)((skb)->cb))->u.tx.extra_frag.flags.bits.num) +#define QDF_NBUF_CB_TX_EXTRA_FRAG_WORDSTR_FLAGS(skb) \ + (((struct qdf_nbuf_cb *)((skb)->cb))->u.tx.extra_frag.flags.u8) +#define QDF_NBUF_CB_TX_EXTRA_FRAG_FLAGS_CHFRAG_START(skb) \ + (((struct qdf_nbuf_cb *) \ + ((skb)->cb))->u.tx.extra_frag.flags.bits.flag_chfrag_start) +#define QDF_NBUF_CB_TX_EXTRA_FRAG_FLAGS_CHFRAG_END(skb) \ + (((struct qdf_nbuf_cb *) \ + ((skb)->cb))->u.tx.extra_frag.flags.bits.flag_chfrag_end) +#define QDF_NBUF_CB_TX_EXTRA_FRAG_FLAGS_EXT_HEADER(skb) \ + (((struct qdf_nbuf_cb *) \ + ((skb)->cb))->u.tx.extra_frag.flags.bits.flag_ext_header) +#define QDF_NBUF_CB_TX_EXTRA_FRAG_WORDSTR_EFRAG(skb) \ + (((struct qdf_nbuf_cb *) \ + ((skb)->cb))->u.tx.extra_frag.flags.bits.flag_efrag) +#define QDF_NBUF_CB_TX_EXTRA_FRAG_WORDSTR_NBUF(skb) \ + (((struct qdf_nbuf_cb *) \ + ((skb)->cb))->u.tx.extra_frag.flags.bits.flag_nbuf) +#define QDF_NBUF_CB_TX_DATA_ATTR(skb) \ + (((struct qdf_nbuf_cb *)((skb)->cb))->u.tx.dev.mcl.data_attr) +#define QDF_NBUF_CB_TX_PACKET_STATE(skb) \ + (((struct qdf_nbuf_cb *) \ + ((skb)->cb))->u.tx.dev.mcl.trace.packet_state) +#define QDF_NBUF_CB_TX_IS_PACKET_PRIV(skb) \ + (((struct qdf_nbuf_cb *) \ + ((skb)->cb))->u.tx.dev.mcl.trace.is_packet_priv) +#define QDF_NBUF_CB_TX_PACKET_TRACK(skb) \ + (((struct qdf_nbuf_cb *) \ + ((skb)->cb))->u.tx.dev.mcl.trace.packet_track) +#define QDF_NBUF_CB_TX_PROTO_TYPE(skb) \ + (((struct qdf_nbuf_cb *) \ + ((skb)->cb))->u.tx.dev.mcl.trace.proto_type) +#define QDF_NBUF_UPDATE_TX_PKT_COUNT(skb, PACKET_STATE) \ + qdf_nbuf_set_state(skb, PACKET_STATE) +#define QDF_NBUF_GET_PACKET_TRACK(skb) \ + (((struct qdf_nbuf_cb *)((skb)->cb))->u.tx.dev.mcl.trace.packet_track) +#define QDF_NBUF_CB_TX_DP_TRACE(skb) \ + (((struct qdf_nbuf_cb *)((skb)->cb))->u.tx.dev.mcl.trace.dp_trace) +#define QDF_NBUF_CB_DP_TRACE_PRINT(skb) \ + (((struct qdf_nbuf_cb *)((skb)->cb))->u.tx.dev.mcl.trace.print) +#define QDF_NBUF_CB_TX_HL_HTT2_FRM(skb) \ + (((struct qdf_nbuf_cb *)((skb)->cb))->u.tx.dev.mcl.trace.htt2_frm) +#define QDF_NBUF_CB_TX_VDEV_ID(skb) \ + (((struct qdf_nbuf_cb *)((skb)->cb))->u.tx.dev.mcl.trace.vdev_id) +#define QDF_NBUF_CB_GET_IS_BCAST(skb) \ + (((struct qdf_nbuf_cb *)((skb)->cb))->u.tx.dev.mcl.trace.is_bcast) +#define QDF_NBUF_CB_GET_IS_MCAST(skb) \ + (((struct qdf_nbuf_cb *)((skb)->cb))->u.tx.dev.mcl.trace.is_mcast) +#define QDF_NBUF_CB_GET_PACKET_TYPE(skb) \ + (((struct qdf_nbuf_cb *)((skb)->cb))->u.tx.dev.mcl.trace.packet_type) +#define QDF_NBUF_CB_TX_IPA_OWNED(skb) \ + (((struct qdf_nbuf_cb *)((skb)->cb))->u.tx.dev.mcl.ipa.owned) +#define QDF_NBUF_CB_TX_IPA_PRIV(skb) \ + (((struct qdf_nbuf_cb *)((skb)->cb))->u.tx.dev.mcl.ipa.priv) +#define QDF_NBUF_CB_TX_DESC_ID(skb) \ + (((struct qdf_nbuf_cb *)((skb)->cb))->u.tx.dev.mcl.desc_id) +#define QDF_NBUF_CB_TX_FTYPE(skb) \ + (((struct qdf_nbuf_cb *)((skb)->cb))->u.tx.dev.win.ftype) +#define QDF_NBUF_CB_TX_SUBMIT_TS(skb) \ + (((struct qdf_nbuf_cb *)((skb)->cb))->u.tx.dev.win.submit_ts) +#define QDF_NBUF_CB_TX_FCTX(skb) \ + (((struct qdf_nbuf_cb *)((skb)->cb))->u.tx.dev.win.fctx) +#define QDF_NBUF_CB_TX_VDEV_CTX(skb) \ + (((struct qdf_nbuf_cb *)((skb)->cb))->u.tx.dev.win.vdev_ctx) + + +/* assume the OS provides a single fragment */ +#define __qdf_nbuf_get_num_frags(skb) \ + (QDF_NBUF_CB_TX_NUM_EXTRA_FRAGS(skb) + 1) + +#define __qdf_nbuf_reset_num_frags(skb) \ + do { \ + QDF_NBUF_CB_TX_NUM_EXTRA_FRAGS(skb) = 0; \ + } while (0) + +/** + * end of nbuf->cb access macros + */ + +typedef void (*qdf_nbuf_trace_update_t)(char *); +typedef void (*qdf_nbuf_free_t)(__qdf_nbuf_t); + +#define __qdf_nbuf_mapped_paddr_get(skb) QDF_NBUF_CB_PADDR(skb) + +#define __qdf_nbuf_mapped_paddr_set(skb, paddr) \ + do { \ + QDF_NBUF_CB_PADDR(skb) = paddr; \ + } while (0) + +#define __qdf_nbuf_frag_push_head( \ + skb, frag_len, frag_vaddr, frag_paddr) \ + do { \ + QDF_NBUF_CB_TX_NUM_EXTRA_FRAGS(skb) = 1; \ + QDF_NBUF_CB_TX_EXTRA_FRAG_VADDR(skb) = frag_vaddr; \ + QDF_NBUF_CB_TX_EXTRA_FRAG_PADDR(skb) = frag_paddr; \ + QDF_NBUF_CB_TX_EXTRA_FRAG_LEN(skb) = frag_len; \ + } while (0) + +#define __qdf_nbuf_get_frag_vaddr(skb, frag_num) \ + ((frag_num < QDF_NBUF_CB_TX_NUM_EXTRA_FRAGS(skb)) ? \ + QDF_NBUF_CB_TX_EXTRA_FRAG_VADDR(skb) : ((skb)->data)) + +#define __qdf_nbuf_get_frag_vaddr_always(skb) \ + QDF_NBUF_CB_TX_EXTRA_FRAG_VADDR(skb) + +#define __qdf_nbuf_get_frag_paddr(skb, frag_num) \ + ((frag_num < QDF_NBUF_CB_TX_NUM_EXTRA_FRAGS(skb)) ? \ + QDF_NBUF_CB_TX_EXTRA_FRAG_PADDR(skb) : \ + /* assume that the OS only provides a single fragment */ \ + QDF_NBUF_CB_PADDR(skb)) + +#define __qdf_nbuf_get_frag_len(skb, frag_num) \ + ((frag_num < QDF_NBUF_CB_TX_NUM_EXTRA_FRAGS(skb)) ? \ + QDF_NBUF_CB_TX_EXTRA_FRAG_LEN(skb) : (skb)->len) + +#define __qdf_nbuf_get_frag_is_wordstream(skb, frag_num) \ + ((frag_num < QDF_NBUF_CB_TX_NUM_EXTRA_FRAGS(skb)) \ + ? (QDF_NBUF_CB_TX_EXTRA_FRAG_WORDSTR_EFRAG(skb)) \ + : (QDF_NBUF_CB_TX_EXTRA_FRAG_WORDSTR_NBUF(skb))) + +#define __qdf_nbuf_set_frag_is_wordstream(skb, frag_num, is_wstrm) \ + do { \ + if (frag_num >= QDF_NBUF_CB_TX_NUM_EXTRA_FRAGS(skb)) \ + frag_num = QDF_NBUF_CB_TX_MAX_EXTRA_FRAGS; \ + if (frag_num) \ + QDF_NBUF_CB_TX_EXTRA_FRAG_WORDSTR_EFRAG(skb) = \ + is_wstrm; \ + else \ + QDF_NBUF_CB_TX_EXTRA_FRAG_WORDSTR_NBUF(skb) = \ + is_wstrm; \ + } while (0) + +#define __qdf_nbuf_set_vdev_ctx(skb, vdev_ctx) \ + do { \ + QDF_NBUF_CB_TX_VDEV_CTX((skb)) = (vdev_ctx); \ + } while (0) + +#define __qdf_nbuf_get_vdev_ctx(skb) \ + QDF_NBUF_CB_TX_VDEV_CTX((skb)) + +#define __qdf_nbuf_set_fctx_type(skb, ctx, type) \ + do { \ + QDF_NBUF_CB_TX_FCTX((skb)) = (ctx); \ + QDF_NBUF_CB_TX_FTYPE((skb)) = (type); \ + } while (0) + +#define __qdf_nbuf_get_fctx(skb) \ + QDF_NBUF_CB_TX_FCTX((skb)) + +#define __qdf_nbuf_get_ftype(skb) \ + QDF_NBUF_CB_TX_FTYPE((skb)) + +#define __qdf_nbuf_set_chfrag_start(skb, val) \ + do { \ + (QDF_NBUF_CB_TX_EXTRA_FRAG_FLAGS_CHFRAG_START((skb))) = val; \ + } while (0) + +#define __qdf_nbuf_is_chfrag_start(skb) \ + (QDF_NBUF_CB_TX_EXTRA_FRAG_FLAGS_CHFRAG_START((skb))) + +#define __qdf_nbuf_set_chfrag_end(skb, val) \ + do { \ + (QDF_NBUF_CB_TX_EXTRA_FRAG_FLAGS_CHFRAG_END((skb))) = val; \ + } while (0) + +#define __qdf_nbuf_is_chfrag_end(skb) \ + (QDF_NBUF_CB_TX_EXTRA_FRAG_FLAGS_CHFRAG_END((skb))) + +#define __qdf_nbuf_trace_set_proto_type(skb, proto_type) \ + do { \ + QDF_NBUF_CB_TX_PROTO_TYPE(skb) = (proto_type); \ + } while (0) + +#define __qdf_nbuf_trace_get_proto_type(skb) \ + QDF_NBUF_CB_TX_PROTO_TYPE(skb) + +#define __qdf_nbuf_data_attr_get(skb) \ + QDF_NBUF_CB_TX_DATA_ATTR(skb) +#define __qdf_nbuf_data_attr_set(skb, data_attr) \ + do { \ + QDF_NBUF_CB_TX_DATA_ATTR(skb) = (data_attr); \ + } while (0) + +#define __qdf_nbuf_ipa_owned_get(skb) \ + QDF_NBUF_CB_TX_IPA_OWNED(skb) + +#define __qdf_nbuf_ipa_owned_set(skb) \ + do { \ + QDF_NBUF_CB_TX_IPA_OWNED(skb) = 1; \ + } while (0) + +#define __qdf_nbuf_ipa_priv_get(skb) \ + QDF_NBUF_CB_TX_IPA_PRIV(skb) + +#define __qdf_nbuf_ipa_priv_set(skb, priv) \ + do { \ + QDF_NBUF_CB_TX_IPA_PRIV(skb) = (priv); \ + } while (0) + +/** + * __qdf_nbuf_num_frags_init() - init extra frags + * @skb: sk buffer + * + * Return: none + */ +static inline +void __qdf_nbuf_num_frags_init(struct sk_buff *skb) +{ + QDF_NBUF_CB_TX_NUM_EXTRA_FRAGS(skb) = 0; +} + +typedef enum { + CB_FTYPE_MCAST2UCAST = 1, + CB_FTYPE_TSO = 2, + CB_FTYPE_TSO_SG = 3, + CB_FTYPE_SG = 4, +} CB_FTYPE; + +/* + * prototypes. Implemented in qdf_nbuf.c + */ +__qdf_nbuf_t __qdf_nbuf_alloc(__qdf_device_t osdev, size_t size, int reserve, + int align, int prio); +void __qdf_nbuf_free(struct sk_buff *skb); +QDF_STATUS __qdf_nbuf_map(__qdf_device_t osdev, + struct sk_buff *skb, qdf_dma_dir_t dir); +void __qdf_nbuf_unmap(__qdf_device_t osdev, + struct sk_buff *skb, qdf_dma_dir_t dir); +QDF_STATUS __qdf_nbuf_map_single(__qdf_device_t osdev, + struct sk_buff *skb, qdf_dma_dir_t dir); +void __qdf_nbuf_unmap_single(__qdf_device_t osdev, + struct sk_buff *skb, qdf_dma_dir_t dir); +void __qdf_nbuf_reg_trace_cb(qdf_nbuf_trace_update_t cb_func_ptr); +void __qdf_nbuf_reg_free_cb(qdf_nbuf_free_t cb_func_ptr); + +QDF_STATUS __qdf_nbuf_dmamap_create(qdf_device_t osdev, __qdf_dma_map_t *dmap); +void __qdf_nbuf_dmamap_destroy(qdf_device_t osdev, __qdf_dma_map_t dmap); +void __qdf_nbuf_dmamap_set_cb(__qdf_dma_map_t dmap, void *cb, void *arg); +QDF_STATUS __qdf_nbuf_map_nbytes(qdf_device_t osdev, struct sk_buff *skb, + qdf_dma_dir_t dir, int nbytes); +void __qdf_nbuf_unmap_nbytes(qdf_device_t osdev, struct sk_buff *skb, + qdf_dma_dir_t dir, int nbytes); +#ifndef REMOVE_INIT_DEBUG_CODE +void __qdf_nbuf_sync_for_cpu(qdf_device_t osdev, struct sk_buff *skb, + qdf_dma_dir_t dir); +#endif +QDF_STATUS __qdf_nbuf_map_nbytes_single( + qdf_device_t osdev, struct sk_buff *buf, qdf_dma_dir_t dir, int nbytes); +void __qdf_nbuf_unmap_nbytes_single( + qdf_device_t osdev, struct sk_buff *buf, qdf_dma_dir_t dir, int nbytes); +void __qdf_nbuf_dma_map_info(__qdf_dma_map_t bmap, qdf_dmamap_info_t *sg); +uint32_t __qdf_nbuf_get_frag_size(__qdf_nbuf_t nbuf, uint32_t cur_frag); +void __qdf_nbuf_frag_info(struct sk_buff *skb, qdf_sglist_t *sg); +void qdf_net_buf_debug_delete_node(struct sk_buff *net_buf); +QDF_STATUS __qdf_nbuf_frag_map( + qdf_device_t osdev, __qdf_nbuf_t nbuf, + int offset, qdf_dma_dir_t dir, int cur_frag); + +bool __qdf_nbuf_is_ipv4_wapi_pkt(struct sk_buff *skb); +bool __qdf_nbuf_data_is_ipv4_pkt(uint8_t *data); +bool __qdf_nbuf_data_is_ipv6_pkt(uint8_t *data); +bool __qdf_nbuf_data_is_ipv4_mcast_pkt(uint8_t *data); +bool __qdf_nbuf_data_is_ipv6_mcast_pkt(uint8_t *data); +bool __qdf_nbuf_data_is_icmp_pkt(uint8_t *data); +bool __qdf_nbuf_data_is_icmpv6_pkt(uint8_t *data); +bool __qdf_nbuf_data_is_ipv4_udp_pkt(uint8_t *data); +bool __qdf_nbuf_data_is_ipv4_tcp_pkt(uint8_t *data); +bool __qdf_nbuf_data_is_ipv6_udp_pkt(uint8_t *data); +bool __qdf_nbuf_data_is_ipv6_tcp_pkt(uint8_t *data); +bool __qdf_nbuf_data_is_ipv4_dhcp_pkt(uint8_t *data); +bool __qdf_nbuf_data_is_ipv4_eapol_pkt(uint8_t *data); +bool __qdf_nbuf_data_is_ipv4_arp_pkt(uint8_t *data); +bool __qdf_nbuf_data_is_arp_req(uint8_t *data); +bool __qdf_nbuf_data_is_arp_rsp(uint8_t *data); +uint32_t __qdf_nbuf_get_arp_src_ip(uint8_t *data); +uint32_t __qdf_nbuf_get_arp_tgt_ip(uint8_t *data); +enum qdf_proto_subtype __qdf_nbuf_data_get_dhcp_subtype(uint8_t *data); +enum qdf_proto_subtype __qdf_nbuf_data_get_eapol_subtype(uint8_t *data); +enum qdf_proto_subtype __qdf_nbuf_data_get_arp_subtype(uint8_t *data); +enum qdf_proto_subtype __qdf_nbuf_data_get_icmp_subtype(uint8_t *data); +enum qdf_proto_subtype __qdf_nbuf_data_get_icmpv6_subtype(uint8_t *data); +uint8_t __qdf_nbuf_data_get_ipv4_proto(uint8_t *data); +uint8_t __qdf_nbuf_data_get_ipv6_proto(uint8_t *data); + +/** + * __qdf_to_status() - OS to QDF status conversion + * @error : OS error + * + * Return: QDF status + */ +static inline QDF_STATUS __qdf_to_status(signed int error) +{ + switch (error) { + case 0: + return QDF_STATUS_SUCCESS; + case ENOMEM: + case -ENOMEM: + return QDF_STATUS_E_NOMEM; + default: + return QDF_STATUS_E_NOSUPPORT; + } +} + +/** + * __qdf_nbuf_len() - return the amount of valid data in the skb + * @skb: Pointer to network buffer + * + * This API returns the amount of valid data in the skb, If there are frags + * then it returns total length. + * + * Return: network buffer length + */ +static inline size_t __qdf_nbuf_len(struct sk_buff *skb) +{ + int i, extra_frag_len = 0; + + i = QDF_NBUF_CB_TX_NUM_EXTRA_FRAGS(skb); + if (i > 0) + extra_frag_len = QDF_NBUF_CB_TX_EXTRA_FRAG_LEN(skb); + + return extra_frag_len + skb->len; +} + +/** + * __qdf_nbuf_cat() - link two nbufs + * @dst: Buffer to piggyback into + * @src: Buffer to put + * + * Link tow nbufs the new buf is piggybacked into the older one. The older + * (src) skb is released. + * + * Return: QDF_STATUS (status of the call) if failed the src skb + * is released + */ +static inline QDF_STATUS +__qdf_nbuf_cat(struct sk_buff *dst, struct sk_buff *src) +{ + QDF_STATUS error = 0; + + qdf_assert(dst && src); + + /* + * Since pskb_expand_head unconditionally reallocates the skb->head + * buffer, first check whether the current buffer is already large + * enough. + */ + if (skb_tailroom(dst) < src->len) { + error = pskb_expand_head(dst, 0, src->len, GFP_ATOMIC); + if (error) + return __qdf_to_status(error); + } + memcpy(skb_tail_pointer(dst), src->data, src->len); + + skb_put(dst, src->len); + dev_kfree_skb_any(src); + + return __qdf_to_status(error); +} + +/* + * nbuf manipulation routines + */ +/** + * __qdf_nbuf_headroom() - return the amount of tail space available + * @buf: Pointer to network buffer + * + * Return: amount of tail room + */ +static inline int __qdf_nbuf_headroom(struct sk_buff *skb) +{ + return skb_headroom(skb); +} + +/** + * __qdf_nbuf_tailroom() - return the amount of tail space available + * @buf: Pointer to network buffer + * + * Return: amount of tail room + */ +static inline uint32_t __qdf_nbuf_tailroom(struct sk_buff *skb) +{ + return skb_tailroom(skb); +} + +/** + * __qdf_nbuf_push_head() - Push data in the front + * @skb: Pointer to network buffer + * @size: size to be pushed + * + * Return: New data pointer of this buf after data has been pushed, + * or NULL if there is not enough room in this buf. + */ +#ifdef CONFIG_MCL +static inline uint8_t *__qdf_nbuf_push_head(struct sk_buff *skb, size_t size) +{ + if (QDF_NBUF_CB_PADDR(skb)) + QDF_NBUF_CB_PADDR(skb) -= size; + + return skb_push(skb, size); +} +#else +static inline uint8_t *__qdf_nbuf_push_head(struct sk_buff *skb, size_t size) +{ + return skb_push(skb, size); +} +#endif + +/** + * __qdf_nbuf_put_tail() - Puts data in the end + * @skb: Pointer to network buffer + * @size: size to be pushed + * + * Return: data pointer of this buf where new data has to be + * put, or NULL if there is not enough room in this buf. + */ +static inline uint8_t *__qdf_nbuf_put_tail(struct sk_buff *skb, size_t size) +{ + if (skb_tailroom(skb) < size) { + if (unlikely(pskb_expand_head(skb, 0, + size - skb_tailroom(skb), GFP_ATOMIC))) { + dev_kfree_skb_any(skb); + return NULL; + } + } + return skb_put(skb, size); +} + +/** + * __qdf_nbuf_pull_head() - pull data out from the front + * @skb: Pointer to network buffer + * @size: size to be popped + * + * Return: New data pointer of this buf after data has been popped, + * or NULL if there is not sufficient data to pull. + */ +#ifdef CONFIG_MCL +static inline uint8_t *__qdf_nbuf_pull_head(struct sk_buff *skb, size_t size) +{ + if (QDF_NBUF_CB_PADDR(skb)) + QDF_NBUF_CB_PADDR(skb) += size; + + return skb_pull(skb, size); +} +#else +static inline uint8_t *__qdf_nbuf_pull_head(struct sk_buff *skb, size_t size) +{ + return skb_pull(skb, size); +} +#endif +/** + * __qdf_nbuf_trim_tail() - trim data out from the end + * @skb: Pointer to network buffer + * @size: size to be popped + * + * Return: none + */ +static inline void __qdf_nbuf_trim_tail(struct sk_buff *skb, size_t size) +{ + return skb_trim(skb, skb->len - size); +} + + +/* + * prototypes. Implemented in qdf_nbuf.c + */ +qdf_nbuf_tx_cksum_t __qdf_nbuf_get_tx_cksum(struct sk_buff *skb); +QDF_STATUS __qdf_nbuf_set_rx_cksum(struct sk_buff *skb, + qdf_nbuf_rx_cksum_t *cksum); +uint8_t __qdf_nbuf_get_tid(struct sk_buff *skb); +void __qdf_nbuf_set_tid(struct sk_buff *skb, uint8_t tid); +uint8_t __qdf_nbuf_get_exemption_type(struct sk_buff *skb); +void __qdf_nbuf_ref(struct sk_buff *skb); +int __qdf_nbuf_shared(struct sk_buff *skb); + +/* + * qdf_nbuf_pool_delete() implementation - do nothing in linux + */ +#define __qdf_nbuf_pool_delete(osdev) + +/** + * __qdf_nbuf_clone() - clone the nbuf (copy is readonly) + * @skb: Pointer to network buffer + * + * if GFP_ATOMIC is overkill then we can check whether its + * called from interrupt context and then do it or else in + * normal case use GFP_KERNEL + * + * example use "in_irq() || irqs_disabled()" + * + * Return: cloned skb + */ +static inline struct sk_buff *__qdf_nbuf_clone(struct sk_buff *skb) +{ + return skb_clone(skb, GFP_ATOMIC); +} + +/** + * __qdf_nbuf_copy() - returns a private copy of the skb + * @skb: Pointer to network buffer + * + * This API returns a private copy of the skb, the skb returned is completely + * modifiable by callers + * + * Return: skb or NULL + */ +static inline struct sk_buff *__qdf_nbuf_copy(struct sk_buff *skb) +{ + return skb_copy(skb, GFP_ATOMIC); +} + +#define __qdf_nbuf_reserve skb_reserve + + +/** + * __qdf_nbuf_head() - return the pointer the skb's head pointer + * @skb: Pointer to network buffer + * + * Return: Pointer to head buffer + */ +static inline uint8_t *__qdf_nbuf_head(struct sk_buff *skb) +{ + return skb->head; +} + +/** + * __qdf_nbuf_data() - return the pointer to data header in the skb + * @skb: Pointer to network buffer + * + * Return: Pointer to skb data + */ +static inline uint8_t *__qdf_nbuf_data(struct sk_buff *skb) +{ + return skb->data; +} + +static inline uint8_t *__qdf_nbuf_data_addr(struct sk_buff *skb) +{ + return (uint8_t *)&skb->data; +} + +/** + * __qdf_nbuf_get_protocol() - return the protocol value of the skb + * @skb: Pointer to network buffer + * + * Return: skb protocol + */ +static inline uint16_t __qdf_nbuf_get_protocol(struct sk_buff *skb) +{ + return skb->protocol; +} + +/** + * __qdf_nbuf_get_ip_summed() - return the ip checksum value of the skb + * @skb: Pointer to network buffer + * + * Return: skb ip_summed + */ +static inline uint8_t __qdf_nbuf_get_ip_summed(struct sk_buff *skb) +{ + return skb->ip_summed; +} + +/** + * __qdf_nbuf_set_ip_summed() - sets the ip_summed value of the skb + * @skb: Pointer to network buffer + * @ip_summed: ip checksum + * + * Return: none + */ +static inline void __qdf_nbuf_set_ip_summed(struct sk_buff *skb, + uint8_t ip_summed) +{ + skb->ip_summed = ip_summed; +} + +/** + * __qdf_nbuf_get_priority() - return the priority value of the skb + * @skb: Pointer to network buffer + * + * Return: skb priority + */ +static inline uint32_t __qdf_nbuf_get_priority(struct sk_buff *skb) +{ + return skb->priority; +} + +/** + * __qdf_nbuf_set_priority() - sets the priority value of the skb + * @skb: Pointer to network buffer + * @p: priority + * + * Return: none + */ +static inline void __qdf_nbuf_set_priority(struct sk_buff *skb, uint32_t p) +{ + skb->priority = p; +} + +/** + * __qdf_nbuf_set_next() - sets the next skb pointer of the current skb + * @skb: Current skb + * @next_skb: Next skb + * + * Return: void + */ +static inline void +__qdf_nbuf_set_next(struct sk_buff *skb, struct sk_buff *skb_next) +{ + skb->next = skb_next; +} + +/** + * __qdf_nbuf_next() - return the next skb pointer of the current skb + * @skb: Current skb + * + * Return: the next skb pointed to by the current skb + */ +static inline struct sk_buff *__qdf_nbuf_next(struct sk_buff *skb) +{ + return skb->next; +} + +/** + * __qdf_nbuf_set_next_ext() - sets the next skb pointer of the current skb + * @skb: Current skb + * @next_skb: Next skb + * + * This fn is used to link up extensions to the head skb. Does not handle + * linking to the head + * + * Return: none + */ +static inline void +__qdf_nbuf_set_next_ext(struct sk_buff *skb, struct sk_buff *skb_next) +{ + skb->next = skb_next; +} + +/** + * __qdf_nbuf_next_ext() - return the next skb pointer of the current skb + * @skb: Current skb + * + * Return: the next skb pointed to by the current skb + */ +static inline struct sk_buff *__qdf_nbuf_next_ext(struct sk_buff *skb) +{ + return skb->next; +} + +/** + * __qdf_nbuf_append_ext_list() - link list of packet extensions to the head + * @skb_head: head_buf nbuf holding head segment (single) + * @ext_list: nbuf list holding linked extensions to the head + * @ext_len: Total length of all buffers in the extension list + * + * This function is used to link up a list of packet extensions (seg1, 2,* ...) + * to the nbuf holding the head segment (seg0) + * + * Return: none + */ +static inline void +__qdf_nbuf_append_ext_list(struct sk_buff *skb_head, + struct sk_buff *ext_list, size_t ext_len) +{ + skb_shinfo(skb_head)->frag_list = ext_list; + skb_head->data_len = ext_len; + skb_head->len += skb_head->data_len; +} + +/** + * __qdf_nbuf_get_ext_list() - Get the link to extended nbuf list. + * @head_buf: Network buf holding head segment (single) + * + * This ext_list is populated when we have Jumbo packet, for example in case of + * monitor mode amsdu packet reception, and are stiched using frags_list. + * + * Return: Network buf list holding linked extensions from head buf. + */ +static inline struct sk_buff *__qdf_nbuf_get_ext_list(struct sk_buff *head_buf) +{ + return (skb_shinfo(head_buf)->frag_list); +} + +/** + * __qdf_nbuf_tx_free() - free skb list + * @skb: Pointer to network buffer + * @tx_err: TX error + * + * Return: none + */ +static inline void __qdf_nbuf_tx_free(struct sk_buff *bufs, int tx_err) +{ + while (bufs) { + struct sk_buff *next = __qdf_nbuf_next(bufs); + + if (QDF_NBUF_CB_TX_IS_PACKET_PRIV(bufs)) { + if (qdf_likely(bufs)) + qdf_net_buf_debug_delete_node(bufs); + } + __qdf_nbuf_free(bufs); + bufs = next; + } +} + +/** + * __qdf_nbuf_get_age() - return the checksum value of the skb + * @skb: Pointer to network buffer + * + * Return: checksum value + */ +static inline uint32_t __qdf_nbuf_get_age(struct sk_buff *skb) +{ + return skb->csum; +} + +/** + * __qdf_nbuf_set_age() - sets the checksum value of the skb + * @skb: Pointer to network buffer + * @v: Value + * + * Return: none + */ +static inline void __qdf_nbuf_set_age(struct sk_buff *skb, uint32_t v) +{ + skb->csum = v; +} + +/** + * __qdf_nbuf_adj_age() - adjusts the checksum/age value of the skb + * @skb: Pointer to network buffer + * @adj: Adjustment value + * + * Return: none + */ +static inline void __qdf_nbuf_adj_age(struct sk_buff *skb, uint32_t adj) +{ + skb->csum -= adj; +} + +/** + * __qdf_nbuf_copy_bits() - return the length of the copy bits for skb + * @skb: Pointer to network buffer + * @offset: Offset value + * @len: Length + * @to: Destination pointer + * + * Return: length of the copy bits for skb + */ +static inline int32_t +__qdf_nbuf_copy_bits(struct sk_buff *skb, int32_t offset, int32_t len, void *to) +{ + return skb_copy_bits(skb, offset, to, len); +} + +/** + * __qdf_nbuf_set_pktlen() - sets the length of the skb and adjust the tail + * @skb: Pointer to network buffer + * @len: Packet length + * + * Return: none + */ +static inline void __qdf_nbuf_set_pktlen(struct sk_buff *skb, uint32_t len) +{ + if (skb->len > len) { + skb_trim(skb, len); + } else { + if (skb_tailroom(skb) < len - skb->len) { + if (unlikely(pskb_expand_head(skb, 0, + len - skb->len - skb_tailroom(skb), + GFP_ATOMIC))) { + dev_kfree_skb_any(skb); + qdf_assert(0); + } + } + skb_put(skb, (len - skb->len)); + } +} + +/** + * __qdf_nbuf_set_protocol() - sets the protocol value of the skb + * @skb: Pointer to network buffer + * @protocol: Protocol type + * + * Return: none + */ +static inline void +__qdf_nbuf_set_protocol(struct sk_buff *skb, uint16_t protocol) +{ + skb->protocol = protocol; +} + +#define __qdf_nbuf_set_tx_htt2_frm(skb, candi) \ + do { \ + QDF_NBUF_CB_TX_HL_HTT2_FRM(skb) = (candi); \ + } while (0) + +#define __qdf_nbuf_get_tx_htt2_frm(skb) \ + QDF_NBUF_CB_TX_HL_HTT2_FRM(skb) + +void __qdf_dmaaddr_to_32s(qdf_dma_addr_t dmaaddr, + uint32_t *lo, uint32_t *hi); + +uint32_t __qdf_nbuf_get_tso_info(qdf_device_t osdev, struct sk_buff *skb, + struct qdf_tso_info_t *tso_info); + +void __qdf_nbuf_unmap_tso_segment(qdf_device_t osdev, + struct qdf_tso_seg_elem_t *tso_seg, + bool is_last_seg); + +#ifdef FEATURE_TSO +uint32_t __qdf_nbuf_get_tso_num_seg(struct sk_buff *skb); + +#else +static inline uint32_t __qdf_nbuf_get_tso_num_seg(struct sk_buff *skb) +{ + return 0; +} + +#endif /* FEATURE_TSO */ + +static inline bool __qdf_nbuf_is_tso(struct sk_buff *skb) +{ + if (skb_is_gso(skb) && + (skb_is_gso_v6(skb) || + (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV4))) + return true; + else + return false; +} + +struct sk_buff *__qdf_nbuf_inc_users(struct sk_buff *skb); + +int __qdf_nbuf_get_users(struct sk_buff *skb); + +/** + * __qdf_nbuf_tx_info_get() - Modify pkt_type, set pkt_subtype, + * and get hw_classify by peeking + * into packet + * @nbuf: Network buffer (skb on Linux) + * @pkt_type: Pkt type (from enum htt_pkt_type) + * @pkt_subtype: Bit 4 of this field in HTT descriptor + * needs to be set in case of CE classification support + * Is set by this macro. + * @hw_classify: This is a flag which is set to indicate + * CE classification is enabled. + * Do not set this bit for VLAN packets + * OR for mcast / bcast frames. + * + * This macro parses the payload to figure out relevant Tx meta-data e.g. + * whether to enable tx_classify bit in CE. + * + * Overrides pkt_type only if required for 802.3 frames (original ethernet) + * If protocol is less than ETH_P_802_3_MIN (0x600), then + * it is the length and a 802.3 frame else it is Ethernet Type II + * (RFC 894). + * Bit 4 in pkt_subtype is the tx_classify bit + * + * Return: void + */ +#define __qdf_nbuf_tx_info_get(skb, pkt_type, \ + pkt_subtype, hw_classify) \ +do { \ + struct ethhdr *eh = (struct ethhdr *)skb->data; \ + uint16_t ether_type = ntohs(eh->h_proto); \ + bool is_mc_bc; \ + \ + is_mc_bc = is_broadcast_ether_addr((uint8_t *)eh) || \ + is_multicast_ether_addr((uint8_t *)eh); \ + \ + if (likely((ether_type != ETH_P_8021Q) && !is_mc_bc)) { \ + hw_classify = 1; \ + pkt_subtype = 0x01 << \ + HTT_TX_CLASSIFY_BIT_S; \ + } \ + \ + if (unlikely(ether_type < ETH_P_802_3_MIN)) \ + pkt_type = htt_pkt_type_ethernet; \ + \ +} while (0) + +/** + * nbuf private buffer routines + */ + +/** + * __qdf_nbuf_peek_header() - return the header's addr & m_len + * @skb: Pointer to network buffer + * @addr: Pointer to store header's addr + * @m_len: network buffer length + * + * Return: none + */ +static inline void +__qdf_nbuf_peek_header(struct sk_buff *skb, uint8_t **addr, uint32_t *len) +{ + *addr = skb->data; + *len = skb->len; +} + +/** + * typedef struct __qdf_nbuf_queue_t - network buffer queue + * @head: Head pointer + * @tail: Tail pointer + * @qlen: Queue length + */ +typedef struct __qdf_nbuf_qhead { + struct sk_buff *head; + struct sk_buff *tail; + unsigned int qlen; +} __qdf_nbuf_queue_t; + +/******************Functions *************/ + +/** + * __qdf_nbuf_queue_init() - initiallize the queue head + * @qhead: Queue head + * + * Return: QDF status + */ +static inline QDF_STATUS __qdf_nbuf_queue_init(__qdf_nbuf_queue_t *qhead) +{ + memset(qhead, 0, sizeof(struct __qdf_nbuf_qhead)); + return QDF_STATUS_SUCCESS; +} + +/** + * __qdf_nbuf_queue_add() - add an skb in the tail of the queue + * @qhead: Queue head + * @skb: Pointer to network buffer + * + * This is a lockless version, driver must acquire locks if it + * needs to synchronize + * + * Return: none + */ +static inline void +__qdf_nbuf_queue_add(__qdf_nbuf_queue_t *qhead, struct sk_buff *skb) +{ + skb->next = NULL; /*Nullify the next ptr */ + + if (!qhead->head) + qhead->head = skb; + else + qhead->tail->next = skb; + + qhead->tail = skb; + qhead->qlen++; +} + +/** + * __qdf_nbuf_queue_append() - Append src list at the end of dest list + * @dest: target netbuf queue + * @src: source netbuf queue + * + * Return: target netbuf queue + */ +static inline __qdf_nbuf_queue_t * +__qdf_nbuf_queue_append(__qdf_nbuf_queue_t *dest, __qdf_nbuf_queue_t *src) +{ + if (!dest) + return NULL; + else if (!src || !(src->head)) + return dest; + + if (!(dest->head)) + dest->head = src->head; + else + dest->tail->next = src->head; + + dest->tail = src->tail; + dest->qlen += src->qlen; + return dest; +} + +/** + * __qdf_nbuf_queue_insert_head() - add an skb at the head of the queue + * @qhead: Queue head + * @skb: Pointer to network buffer + * + * This is a lockless version, driver must acquire locks if it needs to + * synchronize + * + * Return: none + */ +static inline void +__qdf_nbuf_queue_insert_head(__qdf_nbuf_queue_t *qhead, __qdf_nbuf_t skb) +{ + if (!qhead->head) { + /*Empty queue Tail pointer Must be updated */ + qhead->tail = skb; + } + skb->next = qhead->head; + qhead->head = skb; + qhead->qlen++; +} + +/** + * __qdf_nbuf_queue_remove() - remove a skb from the head of the queue + * @qhead: Queue head + * + * This is a lockless version. Driver should take care of the locks + * + * Return: skb or NULL + */ +static inline +struct sk_buff *__qdf_nbuf_queue_remove(__qdf_nbuf_queue_t *qhead) +{ + __qdf_nbuf_t tmp = NULL; + + if (qhead->head) { + qhead->qlen--; + tmp = qhead->head; + if (qhead->head == qhead->tail) { + qhead->head = NULL; + qhead->tail = NULL; + } else { + qhead->head = tmp->next; + } + tmp->next = NULL; + } + return tmp; +} + +/** + * __qdf_nbuf_queue_free() - free a queue + * @qhead: head of queue + * + * Return: QDF status + */ +static inline QDF_STATUS +__qdf_nbuf_queue_free(__qdf_nbuf_queue_t *qhead) +{ + __qdf_nbuf_t buf = NULL; + + while ((buf = __qdf_nbuf_queue_remove(qhead)) != NULL) + __qdf_nbuf_free(buf); + return QDF_STATUS_SUCCESS; +} + + +/** + * __qdf_nbuf_queue_first() - returns the first skb in the queue + * @qhead: head of queue + * + * Return: NULL if the queue is empty + */ +static inline struct sk_buff * +__qdf_nbuf_queue_first(__qdf_nbuf_queue_t *qhead) +{ + return qhead->head; +} + +/** + * __qdf_nbuf_queue_len() - return the queue length + * @qhead: Queue head + * + * Return: Queue length + */ +static inline uint32_t __qdf_nbuf_queue_len(__qdf_nbuf_queue_t *qhead) +{ + return qhead->qlen; +} + +/** + * __qdf_nbuf_queue_next() - return the next skb from packet chain + * @skb: Pointer to network buffer + * + * This API returns the next skb from packet chain, remember the skb is + * still in the queue + * + * Return: NULL if no packets are there + */ +static inline struct sk_buff *__qdf_nbuf_queue_next(struct sk_buff *skb) +{ + return skb->next; +} + +/** + * __qdf_nbuf_is_queue_empty() - check if the queue is empty or not + * @qhead: Queue head + * + * Return: true if length is 0 else false + */ +static inline bool __qdf_nbuf_is_queue_empty(__qdf_nbuf_queue_t *qhead) +{ + return qhead->qlen == 0; +} + +/* + * Use sk_buff_head as the implementation of qdf_nbuf_queue_t. + * Because the queue head will most likely put in some structure, + * we don't use pointer type as the definition. + */ + +/* + * Use sk_buff_head as the implementation of qdf_nbuf_queue_t. + * Because the queue head will most likely put in some structure, + * we don't use pointer type as the definition. + */ + +static inline void +__qdf_nbuf_set_send_complete_flag(struct sk_buff *skb, bool flag) +{ + return; +} + +/** + * __qdf_nbuf_realloc_headroom() - This keeps the skb shell intact + * expands the headroom + * in the data region. In case of failure the skb is released. + * @skb: sk buff + * @headroom: size of headroom + * + * Return: skb or NULL + */ +static inline struct sk_buff * +__qdf_nbuf_realloc_headroom(struct sk_buff *skb, uint32_t headroom) +{ + if (pskb_expand_head(skb, headroom, 0, GFP_ATOMIC)) { + dev_kfree_skb_any(skb); + skb = NULL; + } + return skb; +} + +/** + * __qdf_nbuf_realloc_tailroom() - This keeps the skb shell intact + * exapnds the tailroom + * in data region. In case of failure it releases the skb. + * @skb: sk buff + * @tailroom: size of tailroom + * + * Return: skb or NULL + */ +static inline struct sk_buff * +__qdf_nbuf_realloc_tailroom(struct sk_buff *skb, uint32_t tailroom) +{ + if (likely(!pskb_expand_head(skb, 0, tailroom, GFP_ATOMIC))) + return skb; + /** + * unlikely path + */ + dev_kfree_skb_any(skb); + return NULL; +} + +/** + * __qdf_nbuf_unshare() - skb unshare + * @skb: sk buff + * + * create a version of the specified nbuf whose contents + * can be safely modified without affecting other + * users.If the nbuf is a clone then this function + * creates a new copy of the data. If the buffer is not + * a clone the original buffer is returned. + * + * Return: skb or NULL + */ +static inline struct sk_buff * +__qdf_nbuf_unshare(struct sk_buff *skb) +{ + return skb_unshare(skb, GFP_ATOMIC); +} + +/** + * __qdf_nbuf_is_cloned() - test whether the nbuf is cloned or not + *@buf: sk buff + * + * Return: true/false + */ +static inline bool __qdf_nbuf_is_cloned(struct sk_buff *skb) +{ + return skb_cloned(skb); +} + +/** + * __qdf_nbuf_pool_init() - init pool + * @net: net handle + * + * Return: QDF status + */ +static inline QDF_STATUS __qdf_nbuf_pool_init(qdf_net_handle_t net) +{ + return QDF_STATUS_SUCCESS; +} + +/* + * adf_nbuf_pool_delete() implementation - do nothing in linux + */ +#define __qdf_nbuf_pool_delete(osdev) + +/** + * __qdf_nbuf_expand() - Expand both tailroom & headroom. In case of failure + * release the skb. + * @skb: sk buff + * @headroom: size of headroom + * @tailroom: size of tailroom + * + * Return: skb or NULL + */ +static inline struct sk_buff * +__qdf_nbuf_expand(struct sk_buff *skb, uint32_t headroom, uint32_t tailroom) +{ + if (likely(!pskb_expand_head(skb, headroom, tailroom, GFP_ATOMIC))) + return skb; + + dev_kfree_skb_any(skb); + return NULL; +} + +/** + * __qdf_nbuf_tx_cksum_info() - tx checksum info + * + * Return: true/false + */ +static inline bool +__qdf_nbuf_tx_cksum_info(struct sk_buff *skb, uint8_t **hdr_off, + uint8_t **where) +{ + qdf_assert(0); + return false; +} + +/** + * __qdf_nbuf_reset_ctxt() - mem zero control block + * @nbuf: buffer + * + * Return: none + */ +static inline void __qdf_nbuf_reset_ctxt(__qdf_nbuf_t nbuf) +{ + qdf_mem_zero(nbuf->cb, sizeof(nbuf->cb)); +} + +/** + * __qdf_nbuf_network_header() - get network header + * @buf: buffer + * + * Return: network header pointer + */ +static inline void *__qdf_nbuf_network_header(__qdf_nbuf_t buf) +{ + return skb_network_header(buf); +} + +/** + * __qdf_nbuf_transport_header() - get transport header + * @buf: buffer + * + * Return: transport header pointer + */ +static inline void *__qdf_nbuf_transport_header(__qdf_nbuf_t buf) +{ + return skb_transport_header(buf); +} + +/** + * __qdf_nbuf_tcp_tso_size() - return the size of TCP segment size (MSS), + * passed as part of network buffer by network stack + * @skb: sk buff + * + * Return: TCP MSS size + * */ +static inline size_t __qdf_nbuf_tcp_tso_size(struct sk_buff *skb) +{ + return skb_shinfo(skb)->gso_size; +} + +/** + * __qdf_nbuf_init() - Re-initializes the skb for re-use + * @nbuf: sk buff + * + * Return: none + */ +static inline void __qdf_nbuf_init(__qdf_nbuf_t nbuf) +{ + atomic_set(&nbuf->users, 1); + nbuf->data = nbuf->head + NET_SKB_PAD; + skb_reset_tail_pointer(nbuf); +} + +/** + * __qdf_nbuf_set_rx_info() - set rx info + * @nbuf: sk buffer + * @info: rx info + * @len: length + * + * Return: none + */ +static inline void +__qdf_nbuf_set_rx_info(__qdf_nbuf_t nbuf, void *info, uint32_t len) +{ + /* Customer may have skb->cb size increased, e.g. to 96 bytes, + * then len's large enough to save the rs status info struct + */ + uint8_t offset = sizeof(struct qdf_nbuf_cb); + uint32_t max = sizeof(((struct sk_buff *)0)->cb)-offset; + + len = (len > max ? max : len); + + memcpy(((uint8_t *)(nbuf->cb) + offset), info, len); +} + +/** + * __qdf_nbuf_get_rx_info() - get rx info + * @nbuf: sk buffer + * + * Return: rx_info + */ +static inline void * +__qdf_nbuf_get_rx_info(__qdf_nbuf_t nbuf) +{ + uint8_t offset = sizeof(struct qdf_nbuf_cb); + return (void *)((uint8_t *)(nbuf->cb) + offset); +} + +/* + * __qdf_nbuf_get_cb() - returns a pointer to skb->cb + * @nbuf: sk buff + * + * Return: void ptr + */ +static inline void * +__qdf_nbuf_get_cb(__qdf_nbuf_t nbuf) +{ + return (void *)nbuf->cb; +} + +/** + * __qdf_nbuf_headlen() - return the length of linear buffer of the skb + * @skb: sk buff + * + * Return: head size + */ +static inline size_t +__qdf_nbuf_headlen(struct sk_buff *skb) +{ + return skb_headlen(skb); +} + +/** + * __qdf_nbuf_get_nr_frags() - return the number of fragments in an skb, + * @skb: sk buff + * + * Return: number of fragments + */ +static inline size_t __qdf_nbuf_get_nr_frags(struct sk_buff *skb) +{ + return skb_shinfo(skb)->nr_frags; +} + +/** + * __qdf_nbuf_tso_tcp_v4() - to check if the TSO TCP pkt is a IPv4 or not. + * @buf: sk buff + * + * Return: true/false + */ +static inline bool __qdf_nbuf_tso_tcp_v4(struct sk_buff *skb) +{ + return skb_shinfo(skb)->gso_type == SKB_GSO_TCPV4 ? 1 : 0; +} + +/** + * __qdf_nbuf_tso_tcp_v6() - to check if the TSO TCP pkt is a IPv6 or not. + * @buf: sk buff + * + * Return: true/false + */ +static inline bool __qdf_nbuf_tso_tcp_v6(struct sk_buff *skb) +{ + return skb_shinfo(skb)->gso_type == SKB_GSO_TCPV6 ? 1 : 0; +} + +/** + * __qdf_nbuf_l2l3l4_hdr_len() - return the l2+l3+l4 hdr lenght of the skb + * @skb: sk buff + * + * Return: size of l2+l3+l4 header length + */ +static inline size_t __qdf_nbuf_l2l3l4_hdr_len(struct sk_buff *skb) +{ + return skb_transport_offset(skb) + tcp_hdrlen(skb); +} + +/** + * __qdf_nbuf_is_nonlinear() - test whether the nbuf is nonlinear or not + * @buf: sk buff + * + * Return: true/false + */ +static inline bool __qdf_nbuf_is_nonlinear(struct sk_buff *skb) +{ + if (skb_is_nonlinear(skb)) + return true; + else + return false; +} + +/** + * __qdf_nbuf_tcp_seq() - get the TCP sequence number of the skb + * @buf: sk buff + * + * Return: TCP sequence number + */ +static inline uint32_t __qdf_nbuf_tcp_seq(struct sk_buff *skb) +{ + return ntohl(tcp_hdr(skb)->seq); +} + +/** + * __qdf_nbuf_get_priv_ptr() - get the priv pointer from the nbuf'f private space + *@buf: sk buff + * + * Return: data pointer to typecast into your priv structure + */ +static inline uint8_t * +__qdf_nbuf_get_priv_ptr(struct sk_buff *skb) +{ + return &skb->cb[8]; +} + +/** + * __qdf_invalidate_range() - invalidate virtual address range + * @start: start address of the address range + * @end: end address of the address range + * + * Note that this function does not write back the cache entries. + * + * Return: none + */ +#ifdef MSM_PLATFORM +static inline void __qdf_invalidate_range(void *start, void *end) +{ + dmac_inv_range(start, end); +} + +#else +static inline void __qdf_invalidate_range(void *start, void *end) +{ + /* TODO figure out how to invalidate cache on x86 and other + non-MSM platform */ + pr_err("Cache invalidate not yet implemneted for non-MSM platforms\n"); + return; +} +#endif + +/** + * __qdf_nbuf_mark_wakeup_frame() - mark wakeup frame. + * @buf: Pointer to nbuf + * + * Return: None + */ +static inline void +__qdf_nbuf_mark_wakeup_frame(__qdf_nbuf_t buf) +{ + buf->mark |= QDF_MARK_FIRST_WAKEUP_PACKET; +} + +/** + * __qdf_nbuf_get_queue_mapping() - get the queue mapping set by linux kernel + * + * @buf: sk buff + * + * Return: Queue mapping + */ +static inline uint16_t +__qdf_nbuf_get_queue_mapping(struct sk_buff *skb) +{ + return skb->queue_mapping; +} +#endif /*_I_QDF_NET_BUF_H */ diff --git a/drivers/staging/qca-wifi-host-cmn/qdf/linux/src/i_qdf_net_types.h b/drivers/staging/qca-wifi-host-cmn/qdf/linux/src/i_qdf_net_types.h new file mode 100644 index 0000000000000000000000000000000000000000..0ec7d75fba964a60509d2711072bf0734930e811 --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/qdf/linux/src/i_qdf_net_types.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2014-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: i_qdf_net_types + * This file provides OS dependent net types API's. + */ + +#ifndef _I_QDF_NET_TYPES_H +#define _I_QDF_NET_TYPES_H + +#include /* uint8_t, etc. */ +#include +#include + +typedef struct in6_addr __in6_addr_t; +typedef __wsum __wsum_t; + +static inline int32_t __qdf_csum_ipv6(const struct in6_addr *saddr, + const struct in6_addr *daddr, + __u32 len, unsigned short proto, + __wsum sum) +{ + return csum_ipv6_magic((struct in6_addr *)saddr, + (struct in6_addr *)daddr, len, proto, sum); +} + +#endif /* _I_QDF_NET_TYPES_H */ diff --git a/drivers/staging/qca-wifi-host-cmn/qdf/linux/src/i_qdf_perf.h b/drivers/staging/qca-wifi-host-cmn/qdf/linux/src/i_qdf_perf.h new file mode 100644 index 0000000000000000000000000000000000000000..4471860d96c410977dadc245dbed52c263ad8593 --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/qdf/linux/src/i_qdf_perf.h @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: i_qdf_perf + * This file provides OS dependent perf API's. + */ + +#ifndef _I_QDF_PERF_H +#define _I_QDF_PERF_H + +#ifdef QCA_PERF_PROFILING + +#if (QCA_MIPS74K_PERF_PROFILING || QCA_MIPS24KK_PERF_PROFILING) +#include +#endif + +/* #defines required for structures */ +#define MAX_SAMPLES_SHIFT 5 /* change this only*/ +#define MAX_SAMPLES (1 << MAX_SAMPLES_SHIFT) +#define INC_SAMPLES(x) ((x + 1) & (MAX_SAMPLES - 1)) +#define MAX_SAMPLE_SZ (sizeof(uint32_t) * MAX_SAMPLES) +#define PER_SAMPLE_SZ sizeof(uint32_t) + +/** + * typedef qdf_perf_entry_t - performance entry + * @list: pointer to next + * @child: pointer tochild + * @parent: pointer to top + * @type: perf cntr + * @name: string + * @proc: pointer to proc entry + * @start_tsc: array at start tsc + * @end_tsc: array at ent tsc + * @samples: array of samples + * @sample_idx: sample index + * @lock_irq: lock irq + */ +typedef struct qdf_os_perf_entry { + struct list_head list; + struct list_head child; + + struct qdf_perf_entry *parent; + + qdf_perf_cntr_t type; + uint8_t *name; + + struct proc_dir_entry *proc; + + uint64_t start_tsc[MAX_SAMPLES]; + uint64_t end_tsc[MAX_SAMPLES]; + + uint32_t samples[MAX_SAMPLES]; + uint32_t sample_idx; + + spinlock_t lock_irq; + +} qdf_perf_entry_t; + +/* typedefs */ +typedef void *__qdf_perf_id_t; + +#endif /* QCA_PERF_PROFILING */ +#endif /* _I_QDF_PERF_H */ diff --git a/drivers/staging/qca-wifi-host-cmn/qdf/linux/src/i_qdf_time.h b/drivers/staging/qca-wifi-host-cmn/qdf/linux/src/i_qdf_time.h new file mode 100644 index 0000000000000000000000000000000000000000..fddf36a3cbc803bd9b4b86c0821b697045a8f74a --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/qdf/linux/src/i_qdf_time.h @@ -0,0 +1,238 @@ +/* + * Copyright (c) 2014-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: i_qdf_time + * This file provides OS dependent time API's. + */ + +#ifndef _I_QDF_TIME_H +#define _I_QDF_TIME_H + +#include +#include +#ifdef MSM_PLATFORM +#include +#else +#include +#endif +#ifdef CONFIG_CNSS +#include +#endif + +typedef unsigned long __qdf_time_t; + +/** + * __qdf_system_ticks() - get system ticks + * + * Return: system tick in jiffies + */ +static inline __qdf_time_t __qdf_system_ticks(void) +{ + return jiffies; +} + +/** + * __qdf_system_ticks_to_msecs() - convert system ticks into milli seconds + * @ticks: System ticks + * + * Return: system tick converted into milli seconds + */ +static inline uint32_t __qdf_system_ticks_to_msecs(unsigned long ticks) +{ + return jiffies_to_msecs(ticks); +} + +/** + * __qdf_system_msecs_to_ticks() - convert milli seconds into system ticks + * @msecs: Milli seconds + * + * Return: milli seconds converted into system ticks + */ +static inline __qdf_time_t __qdf_system_msecs_to_ticks(uint32_t msecs) +{ + return msecs_to_jiffies(msecs); +} + +/** + * __qdf_get_system_uptime() - get system uptime + * + * Return: system uptime in jiffies + */ +static inline __qdf_time_t __qdf_get_system_uptime(void) +{ + return jiffies; +} + +static inline unsigned long __qdf_get_system_timestamp(void) +{ + return (jiffies / HZ) * 1000 + (jiffies % HZ) * (1000 / HZ); +} + +#ifdef CONFIG_ARM +/** + * __qdf_udelay() - delay execution for given microseconds + * @usecs: Micro seconds to delay + * + * Return: none + */ +static inline void __qdf_udelay(uint32_t usecs) +{ + /* + * This is in support of XScale build. They have a limit on the udelay + * value, so we have to make sure we don't approach the limit + */ + uint32_t mticks; + uint32_t leftover; + int i; + /* slice into 1024 usec chunks (simplifies calculation) */ + mticks = usecs >> 10; + leftover = usecs - (mticks << 10); + for (i = 0; i < mticks; i++) + udelay(1024); + udelay(leftover); +} +#else +static inline void __qdf_udelay(uint32_t usecs) +{ + /* Normal Delay functions. Time specified in microseconds */ + udelay(usecs); +} +#endif + +/** + * __qdf_mdelay() - delay execution for given milliseconds + * @usecs: Milliseconds to delay + * + * Return: none + */ +static inline void __qdf_mdelay(uint32_t msecs) +{ + mdelay(msecs); +} + +/** + * __qdf_system_time_after() - Check if a is later than b + * @a: Time stamp value a + * @b: Time stamp value b + * + * Return: + * true if a < b else false + */ +static inline bool __qdf_system_time_after(__qdf_time_t a, __qdf_time_t b) +{ + return (long)(b) - (long)(a) < 0; +} + +/** + * __qdf_system_time_before() - Check if a is before b + * @a: Time stamp value a + * @b: Time stamp value b + * + * Return: + * true if a is before b else false + */ +static inline bool __qdf_system_time_before(__qdf_time_t a, __qdf_time_t b) +{ + return __qdf_system_time_after(b, a); +} + +/** + * __qdf_system_time_after_eq() - Check if a atleast as recent as b, if not + * later + * @a: Time stamp value a + * @b: Time stamp value b + * + * Return: + * true if a >= b else false + */ +static inline bool __qdf_system_time_after_eq(__qdf_time_t a, __qdf_time_t b) +{ + return (long)(a) - (long)(b) >= 0; +} + +/** + * __qdf_get_monotonic_boottime() - get monotonic kernel boot time + * This API is similar to qdf_get_system_boottime but it includes + * time spent in suspend. + * + * Return: Time in microseconds + */ +static inline uint64_t __qdf_get_monotonic_boottime(void) +{ + struct timespec ts; + + get_monotonic_boottime(&ts); + + return ((uint64_t) ts.tv_sec * 1000000) + (ts.tv_nsec / 1000); +} + +#ifdef QCA_WIFI_3_0_ADRASTEA +#include + +/** + * __qdf_get_log_timestamp() - get QTIMER ticks + * + * Returns QTIMER(19.2 MHz) clock ticks. To convert it into seconds + * divide it by 19200. + * + * Return: QTIMER(19.2 MHz) clock ticks + */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)) +static inline uint64_t __qdf_get_log_timestamp(void) +{ + return arch_counter_get_cntvct(); +} +#else +static inline uint64_t __qdf_get_log_timestamp(void) +{ + return arch_counter_get_cntpct(); +} +#endif /* LINUX_VERSION_CODE */ +#else + +/** + * __qdf_get_log_timestamp - get time stamp for logging + * For adrastea this API returns QTIMER tick which is needed to synchronize + * host and fw log timestamps + * For ROME and other discrete solution this API returns system boot time stamp + * + * Return: + * QTIMER ticks(19.2MHz) for adrastea + * System tick for rome and other future discrete solutions + */ +static inline uint64_t __qdf_get_log_timestamp(void) +{ + struct timespec ts; + + ktime_get_ts(&ts); + + return ((uint64_t) ts.tv_sec * 1000000) + (ts.tv_nsec / 1000); +} +#endif /* QCA_WIFI_3_0_ADRASTEA */ + +#endif diff --git a/drivers/staging/qca-wifi-host-cmn/qdf/linux/src/i_qdf_timer.h b/drivers/staging/qca-wifi-host-cmn/qdf/linux/src/i_qdf_timer.h new file mode 100644 index 0000000000000000000000000000000000000000..92695c7fdc3fad0c6315c14036c83d66e5064cc5 --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/qdf/linux/src/i_qdf_timer.h @@ -0,0 +1,173 @@ +/* + * Copyright (c) 2014-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: i_qdf_timer + * This file provides OS dependent timer API's. + */ + +#ifndef _I_QDF_TIMER_H +#define _I_QDF_TIMER_H + +#include +#include +#include +#include +#include + +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 9, 0) +#define setup_deferrable_timer(timer, fn, data) \ + __setup_timer((timer), (fn), (data), TIMER_DEFERRABLE) +#endif + +/* timer data type */ +typedef struct timer_list __qdf_timer_t; + +typedef void (*qdf_dummy_timer_func_t)(unsigned long arg); + +/** + * __qdf_timer_init() - initialize a softirq timer + * @hdl: OS handle + * @timer: Pointer to timer object + * @func: Function pointer + * @arg: Arguement + * @type: deferrable or non deferrable timer type + * + * Timer type QDF_TIMER_TYPE_SW means its a deferrable sw timer which will + * not cause CPU wake upon expiry + * Timer type QDF_TIMER_TYPE_WAKE_APPS means its a non-deferrable timer which + * will cause CPU wake up on expiry + * + * Return: QDF_STATUS + */ +static inline QDF_STATUS __qdf_timer_init(qdf_handle_t hdl, + struct timer_list *timer, + qdf_timer_func_t func, void *arg, + QDF_TIMER_TYPE type) +{ + if (type == QDF_TIMER_TYPE_SW) { + if (object_is_on_stack(timer)) + setup_deferrable_timer_on_stack( + timer, (qdf_dummy_timer_func_t)func, + (unsigned long)arg); + else + setup_deferrable_timer(timer, + (qdf_dummy_timer_func_t)func, + (unsigned long)arg); + } else { + if (object_is_on_stack(timer)) + setup_timer_on_stack(timer, + (qdf_dummy_timer_func_t)func, + (unsigned long)arg); + else + setup_timer(timer, (qdf_dummy_timer_func_t)func, + (unsigned long)arg); + } + + return QDF_STATUS_SUCCESS; +} + +/** + * __qdf_timer_start() - start a qdf softirq timer + * @timer: Pointer to timer object + * @delay: Delay in milli seconds + * + * Return: QDF_STATUS + */ +static inline QDF_STATUS __qdf_timer_start(struct timer_list *timer, + uint32_t delay) +{ + timer->expires = jiffies + msecs_to_jiffies(delay); + add_timer(timer); + + return QDF_STATUS_SUCCESS; +} + +/** + * __qdf_timer_mod() - modify a timer + * @timer: Pointer to timer object + * @delay: Delay in milli seconds + * + * Return: QDF_STATUS + */ +static inline QDF_STATUS __qdf_timer_mod(struct timer_list *timer, + uint32_t delay) +{ + mod_timer(timer, jiffies + msecs_to_jiffies(delay)); + + return QDF_STATUS_SUCCESS; +} + +/** + * __qdf_timer_stop() - cancel a timer + * @timer: Pointer to timer object + * + * Return: true if timer was cancelled and deactived, + * false if timer was cancelled but already got fired. + */ +static inline bool __qdf_timer_stop(struct timer_list *timer) +{ + if (likely(del_timer(timer))) + return 1; + else + return 0; +} + +/** + * __qdf_timer_free() - free a qdf timer + * @timer: Pointer to timer object + * + * Return: None + */ +static inline void __qdf_timer_free(struct timer_list *timer) +{ + del_timer_sync(timer); + + if (object_is_on_stack(timer)) + destroy_timer_on_stack(timer); +} + +/** + * __qdf_sostirq_timer_sync_cancel() - Synchronously canel a timer + * @timer: Pointer to timer object + * + * Synchronization Rules: + * 1. caller must make sure timer function will not use + * qdf_set_timer to add iteself again. + * 2. caller must not hold any lock that timer function + * is likely to hold as well. + * 3. It can't be called from interrupt context. + * + * Return: true if timer was cancelled and deactived, + * false if timer was cancelled but already got fired. + */ +static inline bool __qdf_timer_sync_cancel(struct timer_list *timer) +{ + return del_timer_sync(timer); +} + +#endif /*_QDF_TIMER_PVT_H*/ diff --git a/drivers/staging/qca-wifi-host-cmn/qdf/linux/src/i_qdf_trace.h b/drivers/staging/qca-wifi-host-cmn/qdf/linux/src/i_qdf_trace.h new file mode 100644 index 0000000000000000000000000000000000000000..7ef3fc3c95c811f757b2eb30b74f51398a935a47 --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/qdf/linux/src/i_qdf_trace.h @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2014-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: i_qdf_trace.h + * + * Linux-specific definitions for QDF trace + * + */ + +#if !defined(__I_QDF_TRACE_H) +#define __I_QDF_TRACE_H + +#if !defined(__printf) +#define __printf(a, b) +#endif + +#ifdef CONFIG_MCL +/* QDF_TRACE is the macro invoked to add trace messages to code. See the + * documenation for qdf_trace_msg() for the parameters etc. for this function. + * + * NOTE: Code QDF_TRACE() macros into the source code. Do not code directly + * to the qdf_trace_msg() function. + * + * NOTE 2: qdf tracing is totally turned off if WLAN_DEBUG is *not* defined. + * This allows us to build 'performance' builds where we can measure performance + * without being bogged down by all the tracing in the code + */ +#if defined(WLAN_DEBUG) || defined(DEBUG) +#define QDF_TRACE qdf_trace_msg +#define QDF_TRACE_HEX_DUMP qdf_trace_hex_dump +#else +#define QDF_TRACE(arg ...) +#define QDF_TRACE_HEX_DUMP(arg ...) +#endif +#else + +#define qdf_trace(log_level, args...) \ + do { \ + extern int qdf_dbg_mask; \ + if (qdf_dbg_mask >= log_level) { \ + printk("qdf: "args); \ + printk("\n"); \ + } \ + } while (0) +#define QDF_TRACE(x, y, args...) printk(args) + +#endif /* CONFIG_MCL */ + +#define QDF_ENABLE_TRACING +#define qdf_scnprintf scnprintf + +#ifdef QDF_ENABLE_TRACING + +#define QDF_ASSERT(_condition) \ + do { \ + if (!(_condition)) { \ + pr_err("QDF ASSERT in %s Line %d\n", \ + __func__, __LINE__); \ + WARN_ON(1); \ + } \ + } while (0) + +#else + +/* This code will be used for compilation if tracing is to be compiled out */ +/* of the code so these functions/macros are 'do nothing' */ +static inline void qdf_trace_msg(QDF_MODULE_ID module, ...) +{ +} + +#define QDF_ASSERT(_condition) + +#endif + +#ifdef PANIC_ON_BUG + +#define QDF_BUG(_condition) \ + do { \ + if (!(_condition)) { \ + pr_err("QDF BUG in %s Line %d\n", \ + __func__, __LINE__); \ + BUG_ON(1); \ + } \ + } while (0) + +#else + +#define QDF_BUG(_condition) \ + do { \ + if (!(_condition)) { \ + pr_err("QDF BUG in %s Line %d\n", \ + __func__, __LINE__); \ + WARN_ON(1); \ + } \ + } while (0) + +#endif + +#endif /* __I_QDF_TRACE_H */ diff --git a/drivers/staging/qca-wifi-host-cmn/qdf/linux/src/i_qdf_types.h b/drivers/staging/qca-wifi-host-cmn/qdf/linux/src/i_qdf_types.h new file mode 100644 index 0000000000000000000000000000000000000000..f915d0a9bcf24554bf020fe8018f463097e97c5c --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/qdf/linux/src/i_qdf_types.h @@ -0,0 +1,321 @@ +/* + * Copyright (c) 2014-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: i_qdf_types.h + * This file provides OS dependent types API's. + */ + +#if !defined(__I_QDF_TYPES_H) +#define __I_QDF_TYPES_H + +#include + +#ifndef __KERNEL__ +#define __iomem +#endif +#include +#include +#include + +#ifndef __ahdecl +#ifdef __i386__ +#define __ahdecl __attribute__((regparm(0))) +#else +#define __ahdecl +#endif +#endif + +#ifdef __KERNEL__ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#else + +/* + * Hack - coexist with prior defs of dma_addr_t. + * Eventually all other defs of dma_addr_t should be removed. + * At that point, the "already_defined" wrapper can be removed. + */ +#ifndef __dma_addr_t_already_defined__ +#define __dma_addr_t_already_defined__ +typedef unsigned long dma_addr_t; +#endif + +#define SIOCGIWAP 0 +#define IWEVCUSTOM 0 +#define IWEVREGISTERED 0 +#define IWEVEXPIRED 0 +#define SIOCGIWSCAN 0 +#define DMA_TO_DEVICE 0 +#define DMA_BIDIRECTIONAL 0 +#define DMA_FROM_DEVICE 0 +#define __iomem +#endif /* __KERNEL__ */ + +/* + * max sg that we support + */ +#define __QDF_MAX_SCATTER 1 + +#if defined(__LITTLE_ENDIAN_BITFIELD) +#define QDF_LITTLE_ENDIAN_MACHINE +#elif defined(__BIG_ENDIAN_BITFIELD) +#define QDF_BIG_ENDIAN_MACHINE +#else +#error "Please fix " +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) || !defined(__KERNEL__) +#ifndef __bool_already_defined__ +#define __bool_already_defined__ + +/** + * bool - This is an enum for boolean + * @false: zero + * @true: one + */ +typedef enum bool { + false = 0, + true = 1, +} bool; +#endif /* __bool_already_defined__ */ +#endif + +#define __qdf_packed __attribute__((packed)) + +typedef int (*__qdf_os_intr)(void *); +/** + * Private definitions of general data types + */ +typedef dma_addr_t __qdf_dma_addr_t; +typedef size_t __qdf_dma_size_t; +typedef dma_addr_t __qdf_dma_context_t; + +#define qdf_dma_mem_context(context) dma_addr_t context +#define qdf_get_dma_mem_context(var, field) ((qdf_dma_context_t)(var->field)) + +/** + * typedef struct __qdf_resource_t - qdf resource type + * @paddr: Physical address + * @paddr: Virtual address + * @len: Length + */ +typedef struct __qdf_resource { + unsigned long paddr; + void __iomem *vaddr; + unsigned long len; +} __qdf_resource_t; + +struct __qdf_mempool_ctxt; + +#define MAX_MEM_POOLS 64 + +/** + * enum qdf_bus_type - Supported Bus types + * @QDF_BUS_TYPE_NONE: None Bus type for error check + * @QDF_BUS_TYPE_PCI: PCI Bus + * @QDF_BUS_TYPE_AHB: AHB Bus + * @QDF_BUS_TYPE_SNOC: SNOC Bus + * @QDF_BUS_TYPE_SIM: Simulator + * @QDF_BUS_TYPE_USB: USB Bus + */ +enum qdf_bus_type { + QDF_BUS_TYPE_NONE = -1, + QDF_BUS_TYPE_PCI = 0, + QDF_BUS_TYPE_AHB, + QDF_BUS_TYPE_SNOC, + QDF_BUS_TYPE_SIM, + QDF_BUS_TYPE_SDIO, + QDF_BUS_TYPE_USB +}; + +/** + * struct __qdf_device - generic qdf device type + * @drv: Pointer to driver + * @drv_hdl: Pointer to driver handle + * @drv_name: Pointer to driver name + * @irq: IRQ + * @dev: Pointer to device + * @res: QDF resource + * @func: Interrupt handler + * @mem_pool: array to pointer to mem context + */ +struct __qdf_device { + void *drv; + void *drv_hdl; + char *drv_name; + int irq; + struct device *dev; + __qdf_resource_t res; + __qdf_os_intr func; + struct __qdf_mempool_ctxt *mem_pool[MAX_MEM_POOLS]; + enum qdf_bus_type bus_type; +#ifdef CONFIG_MCL + const struct hif_bus_id *bid; +#endif +}; +typedef struct __qdf_device *__qdf_device_t; + +typedef size_t __qdf_size_t; +typedef off_t __qdf_off_t; +typedef uint8_t __iomem *__qdf_iomem_t; + +typedef uint32_t ath_dma_addr_t; + +/** + * typedef __qdf_segment_t - segment of memory + * @daddr: dma address + * @len: lenght of segment + */ +typedef struct __qdf_segment { + dma_addr_t daddr; + uint32_t len; +} __qdf_segment_t; + +/** + * __qdf_dma_map - dma map of memory + * @mapped: mapped address + * @nsegs: number of segments + * @coherent: coherency status + * @seg: segment of memory + */ +struct __qdf_dma_map { + uint32_t mapped; + uint32_t nsegs; + uint32_t coherent; + __qdf_segment_t seg[__QDF_MAX_SCATTER]; +}; +typedef struct __qdf_dma_map *__qdf_dma_map_t; +typedef uint32_t ath_dma_addr_t; + +/** + * __qdf_net_wireless_evcode - enum for event code + * @__QDF_IEEE80211_ASSOC: association event code + * @__QDF_IEEE80211_REASSOC: reassociation event code + * @__QDF_IEEE80211_DISASSOC: disassociation event code + * @__QDF_IEEE80211_JOIN: join event code + * @__QDF_IEEE80211_LEAVE: leave event code + * @__QDF_IEEE80211_SCAN: scan event code + * @__QDF_IEEE80211_REPLAY: replay event code + * @__QDF_IEEE80211_MICHAEL:michael event code + * @__QDF_IEEE80211_REJOIN: rejoin event code + * @__QDF_CUSTOM_PUSH_BUTTON: push button event code + */ +enum __qdf_net_wireless_evcode { + __QDF_IEEE80211_ASSOC = SIOCGIWAP, + __QDF_IEEE80211_REASSOC = IWEVCUSTOM, + __QDF_IEEE80211_DISASSOC = SIOCGIWAP, + __QDF_IEEE80211_JOIN = IWEVREGISTERED, + __QDF_IEEE80211_LEAVE = IWEVEXPIRED, + __QDF_IEEE80211_SCAN = SIOCGIWSCAN, + __QDF_IEEE80211_REPLAY = IWEVCUSTOM, + __QDF_IEEE80211_MICHAEL = IWEVCUSTOM, + __QDF_IEEE80211_REJOIN = IWEVCUSTOM, + __QDF_CUSTOM_PUSH_BUTTON = IWEVCUSTOM, +}; + +#define __qdf_print printk +#define __qdf_vprint vprintk +#define __qdf_snprint snprintf +#define __qdf_vsnprint vsnprintf + +#define __QDF_DMA_BIDIRECTIONAL DMA_BIDIRECTIONAL +#define __QDF_DMA_TO_DEVICE DMA_TO_DEVICE +#ifndef __ubicom32__ +#define __QDF_DMA_FROM_DEVICE DMA_FROM_DEVICE +#else +#define __QDF_DMA_FROM_DEVICE DMA_TO_DEVICE +#endif +#define __qdf_inline inline + +/* + * 1. GNU C/C++ Compiler + * + * How to detect gcc : __GNUC__ + * How to detect gcc version : + * major version : __GNUC__ (2 = 2.x, 3 = 3.x, 4 = 4.x) + * minor version : __GNUC_MINOR__ + * + * 2. Microsoft C/C++ Compiler + * + * How to detect msc : _MSC_VER + * How to detect msc version : + * _MSC_VER (1200 = MSVC 6.0, 1300 = MSVC 7.0, ...) + * + */ + +/* + * MACROs to help with compiler and OS specifics. May need to get a little + * more sophisticated than this and define these to specific 'VERSIONS' of + * the compiler and OS. Until we have a need for that, lets go with this + */ +#if defined(_MSC_VER) + +#define QDF_COMPILER_MSC +/* assuming that if we build with MSC, OS is WinMobile */ +#define QDF_OS_WINMOBILE + +#elif defined(__GNUC__) + +#define QDF_COMPILER_GNUC +#define QDF_OS_LINUX /* assuming if building with GNUC, OS is Linux */ + +#endif + +#if defined(QDF_COMPILER_MSC) + + +/* + * Does nothing on Windows. packing individual structs is not + * supported on the Windows compiler + */ +#define QDF_PACK_STRUCT_1 +#define QDF_PACK_STRUCT_2 +#define QDF_PACK_STRUCT_4 +#define QDF_PACK_STRUCT_8 +#define QDF_PACK_STRUCT_16 + +#elif defined(QDF_COMPILER_GNUC) + +#else +#error "Compiling with an unknown compiler!!" +#endif + +#endif /* __I_QDF_TYPES_H */ diff --git a/drivers/staging/qca-wifi-host-cmn/qdf/linux/src/i_qdf_util.h b/drivers/staging/qca-wifi-host-cmn/qdf/linux/src/i_qdf_util.h new file mode 100644 index 0000000000000000000000000000000000000000..d9cccddef136f778448c1ff74baa77be3f626eea --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/qdf/linux/src/i_qdf_util.h @@ -0,0 +1,403 @@ +/* + * Copyright (c) 2014-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: i_qdf_util.h + * This file provides OS dependent API's. + */ + +#ifndef _I_QDF_UTIL_H +#define _I_QDF_UTIL_H + +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +#if LINUX_VERSION_CODE <= KERNEL_VERSION(3, 3, 8) +#include +#else +#if defined(__LINUX_MIPS32_ARCH__) || defined(__LINUX_MIPS64_ARCH__) +#include +#else +#endif +#endif + +#include +#include +#include + +#ifdef QCA_PARTNER_PLATFORM +#include "ath_carr_pltfrm.h" +#else +#include +#endif + +/* + * Generic compiler-dependent macros if defined by the OS + */ +#define __qdf_unlikely(_expr) unlikely(_expr) +#define __qdf_likely(_expr) likely(_expr) + +/** + * __qdf_status_to_os_return() - translates qdf_status types to linux return types + * @status: status to translate + * + * Translates error types that linux may want to handle specially. + * + * return: 0 or the linux error code that most closely matches the QDF_STATUS. + * defaults to -1 (EPERM) + */ +static inline int __qdf_status_to_os_return(QDF_STATUS status) +{ + switch (status) { + case QDF_STATUS_SUCCESS: + return 0; + case QDF_STATUS_E_RESOURCES: + return -EBUSY; + case QDF_STATUS_E_NOMEM: + return -ENOMEM; + case QDF_STATUS_E_AGAIN: + return -EAGAIN; + case QDF_STATUS_E_INVAL: + return -EINVAL; + case QDF_STATUS_E_FAULT: + return -EFAULT; + case QDF_STATUS_E_ALREADY: + return -EALREADY; + case QDF_STATUS_E_BADMSG: + return -EBADMSG; + case QDF_STATUS_E_BUSY: + return -EBUSY; + case QDF_STATUS_E_CANCELED: + return -ECANCELED; + case QDF_STATUS_E_ABORTED: + return -ECONNABORTED; + case QDF_STATUS_E_PERM: + return -EPERM; + case QDF_STATUS_E_EXISTS: + return -EEXIST; + case QDF_STATUS_E_NOENT: + return -ENOENT; + case QDF_STATUS_E_E2BIG: + return -E2BIG; + case QDF_STATUS_E_NOSPC: + return -ENOSPC; + case QDF_STATUS_E_ADDRNOTAVAIL: + return -EADDRNOTAVAIL; + case QDF_STATUS_E_ENXIO: + return -ENXIO; + case QDF_STATUS_E_NETDOWN: + return -ENETDOWN; + case QDF_STATUS_E_IO: + return -EIO; + case QDF_STATUS_E_NETRESET: + return -ENETRESET; + default: + return -EPERM; + } +} + +/** + * __qdf_set_bit() - set bit in address + * @nr: bit number to be set + * @addr: address buffer pointer + * + * Return: none + */ +static inline void __qdf_set_bit(unsigned int nr, unsigned long *addr) +{ + __set_bit(nr, addr); +} + +/** + * __qdf_set_macaddr_broadcast() - set a QDF MacAddress to the 'broadcast' + * @mac_addr: pointer to the qdf MacAddress to set to broadcast + * + * This function sets a QDF MacAddress to the 'broadcast' MacAddress. Broadcast + * MacAddress contains all 0xFF bytes. + * + * Return: none + */ +static inline void __qdf_set_macaddr_broadcast(struct qdf_mac_addr *mac_addr) +{ + memset(mac_addr, 0xff, QDF_MAC_ADDR_SIZE); +} + +/** + * __qdf_zero_macaddr() - zero out a MacAddress + * @mac_addr: pointer to the struct qdf_mac_addr to zero. + * + * This function zeros out a QDF MacAddress type. + * + * Return: none + */ +static inline void __qdf_zero_macaddr(struct qdf_mac_addr *mac_addr) +{ + memset(mac_addr, 0, QDF_MAC_ADDR_SIZE); +} + +/** + * __qdf_is_macaddr_equal() - compare two QDF MacAddress + * @mac_addr1: Pointer to one qdf MacAddress to compare + * @mac_addr2: Pointer to the other qdf MacAddress to compare + * + * This function returns a bool that tells if a two QDF MacAddress' + * are equivalent. + * + * Return: true if the MacAddress's are equal + * not true if the MacAddress's are not equal + */ +static inline bool __qdf_is_macaddr_equal(struct qdf_mac_addr *mac_addr1, + struct qdf_mac_addr *mac_addr2) +{ + return 0 == memcmp(mac_addr1, mac_addr2, QDF_MAC_ADDR_SIZE); +} + +/** + * qdf_in_interrupt - returns true if in interrupt context + */ +#define qdf_in_interrupt in_interrupt + +/** + * @brief memory barriers. + */ +#define __qdf_min(_a, _b) ((_a) < (_b) ? _a : _b) +#define __qdf_max(_a, _b) ((_a) > (_b) ? _a : _b) + +#define MEMINFO_KB(x) ((x) << (PAGE_SHIFT - 10)) /* In kilobytes */ + +/** + * @brief Assert + */ +#define __qdf_assert(expr) do { \ + if (unlikely(!(expr))) { \ + pr_err("Assertion failed! %s:%s %s:%d\n", \ + # expr, __func__, __FILE__, __LINE__); \ + dump_stack(); \ + QDF_BUG(0); \ + } \ +} while (0) + +/** + * @brief Assert + */ +#define __qdf_target_assert(expr) do { \ + if (unlikely(!(expr))) { \ + qdf_print("Assertion failed! %s:%s %s:%d\n", \ + #expr, __FUNCTION__, __FILE__, __LINE__); \ + dump_stack(); \ + panic("Take care of the TARGET ASSERT first\n"); \ + } \ +} while (0) + +#define __qdf_cpu_to_le64 cpu_to_le64 +#define __qdf_container_of(ptr, type, member) container_of(ptr, type, member) + +#define __qdf_ntohs ntohs +#define __qdf_ntohl ntohl + +#define __qdf_htons htons +#define __qdf_htonl htonl + +#define __qdf_cpu_to_le16 cpu_to_le16 +#define __qdf_cpu_to_le32 cpu_to_le32 +#define __qdf_cpu_to_le64 cpu_to_le64 + +#define __qdf_le16_to_cpu le16_to_cpu +#define __qdf_le32_to_cpu le32_to_cpu + +#define __qdf_be32_to_cpu be32_to_cpu +#define __qdf_be64_to_cpu be64_to_cpu +#define __qdf_le64_to_cpu le64_to_cpu +#define __qdf_le16_to_cpu le16_to_cpu + +/** + * @brief memory barriers. + */ +#define __qdf_wmb() wmb() +#define __qdf_rmb() rmb() +#define __qdf_mb() mb() + +#define __qdf_roundup(x, y) roundup(x, y) + +#ifdef QCA_CONFIG_SMP +/** + * __qdf_get_cpu() - get cpu_index + * + * Return: cpu_index + */ +static inline +int __qdf_get_cpu(void) +{ + int cpu_index = get_cpu(); + + put_cpu(); + return cpu_index; +} +#else +static inline +int __qdf_get_cpu(void) +{ + return 0; +} +#endif + +static inline int __qdf_device_init_wakeup(__qdf_device_t qdf_dev, bool enable) +{ + return device_init_wakeup(qdf_dev->dev, enable); +} + +/** + * __qdf_get_totalramsize() - Get total ram size in Kb + * + * Return: Total ram size in Kb + */ +static inline uint64_t +__qdf_get_totalramsize(void) +{ + struct sysinfo meminfo; + si_meminfo(&meminfo); + return MEMINFO_KB(meminfo.totalram); +} + +/** + * __qdf_get_lower_32_bits() - get lower 32 bits from an address. + * @addr: address + * + * This api returns the lower 32 bits of an address. + * + * Return: lower 32 bits. + */ +static inline +uint32_t __qdf_get_lower_32_bits(__qdf_dma_addr_t addr) +{ + return lower_32_bits(addr); +} + +/** + * __qdf_get_upper_32_bits() - get upper 32 bits from an address. + * @addr: address + * + * This api returns the upper 32 bits of an address. + * + * Return: upper 32 bits. + */ +static inline +uint32_t __qdf_get_upper_32_bits(__qdf_dma_addr_t addr) +{ + return upper_32_bits(addr); +} + +/** + * __qdf_rounddown_pow_of_two() - Round down to nearest power of two + * @n: number to be tested + * + * Test if the input number is power of two, and return the nearest power of two + * + * Return: number rounded down to the nearest power of two + */ +static inline +unsigned long __qdf_rounddown_pow_of_two(unsigned long n) +{ + if (is_power_of_2(n)) + return n; /* already a power of 2 */ + + return __rounddown_pow_of_two(n); +} + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0) + +/** + * __qdf_set_dma_coherent_mask() - set max number of bits allowed in dma addr + * @dev: device pointer + * @addr_bits: max number of bits allowed in dma address + * + * This API sets the maximum allowed number of bits in the dma address. + * + * Return: 0 - success, non zero - failure + */ +static inline +int __qdf_set_dma_coherent_mask(struct device *dev, uint8_t addr_bits) +{ + return dma_set_mask_and_coherent(dev, DMA_BIT_MASK(addr_bits)); +} + +#else + +/** + * __qdf_set_dma_coherent_mask() - set max number of bits allowed in dma addr + * @dev: device pointer + * @addr_bits: max number of bits allowed in dma address + * + * This API sets the maximum allowed number of bits in the dma address. + * + * Return: 0 - success, non zero - failure + */ +static inline +int __qdf_set_dma_coherent_mask(struct device *dev, uint8_t addr_bits) +{ + return dma_set_coherent_mask(dev, DMA_BIT_MASK(addr_bits)); +} +#endif + +/** + * __qdf_do_div() - wrapper function for kernel macro(do_div). + * @dividend: Dividend value + * @divisor : Divisor value + * + * Return: Quotient + */ +static inline +uint64_t __qdf_do_div(uint64_t dividend, uint32_t divisor) +{ + do_div(dividend, divisor); + /*do_div macro updates dividend with Quotient of dividend/divisor */ + return dividend; +} + +/** + * __qdf_do_mod() - wrapper function for kernel macro(do_div). + * @dividend: Dividend value + * @divisor : Divisor value + * + * Return: Modulo + */ +static inline +uint64_t __qdf_do_mod(uint64_t dividend, uint32_t divisor) +{ + return do_div(dividend, divisor); +} + +#endif /*_I_QDF_UTIL_H*/ diff --git a/drivers/staging/qca-wifi-host-cmn/qdf/linux/src/qdf_debugfs.c b/drivers/staging/qca-wifi-host-cmn/qdf/linux/src/qdf_debugfs.c new file mode 100644 index 0000000000000000000000000000000000000000..04302f9014ada4e348a6907964fae818bdfdf31d --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/qdf/linux/src/qdf_debugfs.c @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2017 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. + */ + +/** + * DOC: qdf_debugfs + * This file provides QDF debug file system APIs + */ + +#include +#include + +/* entry for root debugfs directory*/ +static struct dentry *qdf_debugfs_root; + +QDF_STATUS qdf_debugfs_init(void) +{ + qdf_debugfs_root = debugfs_create_dir(KBUILD_MODNAME"_qdf", NULL); + + if (!qdf_debugfs_root) + return QDF_STATUS_E_FAILURE; + + return QDF_STATUS_SUCCESS; +} +EXPORT_SYMBOL(qdf_debugfs_init); + +QDF_STATUS qdf_debugfs_exit(void) +{ + debugfs_remove_recursive(qdf_debugfs_root); + qdf_debugfs_root = NULL; + + return QDF_STATUS_SUCCESS; +} +EXPORT_SYMBOL(qdf_debugfs_exit); + +struct dentry *qdf_debugfs_get_root(void) +{ + return qdf_debugfs_root; +} diff --git a/drivers/staging/qca-wifi-host-cmn/qdf/linux/src/qdf_defer.c b/drivers/staging/qca-wifi-host-cmn/qdf/linux/src/qdf_defer.c new file mode 100644 index 0000000000000000000000000000000000000000..de3678bc1fde927223fef4c25f2b7fc6302910ff --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/qdf/linux/src/qdf_defer.c @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2014-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: qdf_defer.c + * This file provides OS dependent deferred API's. + */ + +#include +#include +#include +#include + +#include "i_qdf_defer.h" + +/** + * __qdf_defer_func() - defer work handler + * @work: Pointer to defer work + * + * Return: none + */ +void __qdf_defer_func(struct work_struct *work) +{ + __qdf_work_t *ctx = container_of(work, __qdf_work_t, work); + if (ctx->fn == NULL) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "No callback registered !!"); + return; + } + ctx->fn(ctx->arg); +} +EXPORT_SYMBOL(__qdf_defer_func); + +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 19) +/** + * __qdf_defer_delayed_func() - defer work handler + * @dwork: Pointer to defer work + * + * Return: none + */ +void +__qdf_defer_delayed_func(struct work_struct *dwork) +{ + return; +} +#else +void +__qdf_defer_delayed_func(struct work_struct *dwork) +{ + __qdf_delayed_work_t *ctx = container_of(dwork, __qdf_delayed_work_t, + dwork.work); + if (ctx->fn == NULL) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "BugCheck: Callback is not initilized while creating delayed work queue"); + return; + } + ctx->fn(ctx->arg); +} +#endif +EXPORT_SYMBOL(__qdf_defer_delayed_func); diff --git a/drivers/staging/qca-wifi-host-cmn/qdf/linux/src/qdf_event.c b/drivers/staging/qca-wifi-host-cmn/qdf/linux/src/qdf_event.c new file mode 100644 index 0000000000000000000000000000000000000000..9ad2080746c5bbe8c847a31bb0b97f5e7018c651 --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/qdf/linux/src/qdf_event.c @@ -0,0 +1,260 @@ +/* + * Copyright (c) 2014-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: qdf_event.c + * + * This source file contains linux specific definitions for QDF event APIs + * The APIs mentioned in this file are used for initializing, setting, + * resetting, destroying an event and waiting on an occurance of an event + * among multiple events. + */ + +/* Include Files */ +#include "qdf_event.h" +#include + +/* Function Definitions and Documentation */ + +/** + * qdf_event_create() - initializes a QDF event + * @event: Pointer to the opaque event object to initialize + * + * The qdf_event_create() function initializes the specified event. Upon + * successful initialization, the state of the event becomes initialized + * and not signalled. + * + * An event must be initialized before it may be used in any other event + * functions. + * Attempting to initialize an already initialized event results in + * a failure. + * + * Return: QDF status + */ +QDF_STATUS qdf_event_create(qdf_event_t *event) +{ + /* check for null pointer */ + if (NULL == event) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "NULL event passed into %s", __func__); + QDF_ASSERT(0); + return QDF_STATUS_E_FAULT; + } + + /* check for 'already initialized' event */ + if (LINUX_EVENT_COOKIE == event->cookie) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "Initialized event passed into %s", __func__); + QDF_ASSERT(0); + return QDF_STATUS_E_BUSY; + } + + /* initialize new event */ + init_completion(&event->complete); + event->cookie = LINUX_EVENT_COOKIE; + + return QDF_STATUS_SUCCESS; +} +EXPORT_SYMBOL(qdf_event_create); + +/** + * qdf_event_set() - sets a QDF event + * @event: The event to set to the signalled state + * + * The state of the specified event is set to signalled by calling + * qdf_event_set(). + * + * Any threads waiting on the event as a result of a qdf_event_wait() will + * be unblocked and available to be scheduled for execution when the event + * is signaled by a call to qdf_event_set(). + * + * Return: QDF status + */ +QDF_STATUS qdf_event_set(qdf_event_t *event) +{ + /* check for null pointer */ + if (NULL == event) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "NULL event passed into %s", __func__); + QDF_ASSERT(0); + return QDF_STATUS_E_FAULT; + } + + /* check if event refers to an initialized object */ + if (LINUX_EVENT_COOKIE != event->cookie) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "Uninitialized event passed into %s", __func__); + QDF_ASSERT(0); + return QDF_STATUS_E_INVAL; + } + + complete(&event->complete); + + return QDF_STATUS_SUCCESS; +} +EXPORT_SYMBOL(qdf_event_set); + +/** + * qdf_event_reset() - resets a QDF event + * @event: The event to set to the NOT signalled state + * + * This function isn't required for Linux. Therefore, it doesn't do much. + * + * The state of the specified event is set to 'NOT signalled' by calling + * qdf_event_reset(). The state of the event remains NOT signalled until an + * explicit call to qdf_event_set(). + * + * This function sets the event to a NOT signalled state even if the event was + * signalled multiple times before being signaled. + * + * Return: QDF status + */ +QDF_STATUS qdf_event_reset(qdf_event_t *event) +{ + /* check for null pointer */ + if (NULL == event) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "NULL event passed into %s", __func__); + QDF_ASSERT(0); + return QDF_STATUS_E_FAULT; + } + + /* check to make sure it is an 'already initialized' event */ + if (LINUX_EVENT_COOKIE != event->cookie) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "Uninitialized event passed into %s", __func__); + QDF_ASSERT(0); + return QDF_STATUS_E_INVAL; + } + + /* (re)initialize event */ + INIT_COMPLETION(event->complete); + return QDF_STATUS_SUCCESS; +} +EXPORT_SYMBOL(qdf_event_reset); + +/** + * qdf_event_destroy() - Destroys a QDF event + * @event: The event object to be destroyed. + * + * This function doesn't do much in Linux. There is no need for the caller + * to explicitly destroy an event after use. + * + * The os_event_destroy() function shall destroy the event object + * referenced by event. After a successful return from qdf_event_destroy() + * the event object becomes, in effect, uninitialized. + * + * A destroyed event object can be reinitialized using qdf_event_create(); + * the results of otherwise referencing the object after it has been destroyed + * are undefined. Calls to QDF event functions to manipulate the lock such + * as qdf_event_set() will fail if the event is destroyed. Therefore, + * don't use the event after it has been destroyed until it has + * been re-initialized. + * + * Return: QDF status + */ +QDF_STATUS qdf_event_destroy(qdf_event_t *event) +{ + /* check for null pointer */ + if (NULL == event) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "NULL event passed into %s", __func__); + QDF_ASSERT(0); + return QDF_STATUS_E_FAULT; + } + + /* check to make sure it is an 'already initialized' event */ + if (LINUX_EVENT_COOKIE != event->cookie) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "Uninitialized event passed into %s", __func__); + QDF_ASSERT(0); + return QDF_STATUS_E_INVAL; + } + + /* make sure nobody is waiting on the event */ + complete_all(&event->complete); + + /* destroy the event */ + memset(event, 0, sizeof(qdf_event_t)); + + return QDF_STATUS_SUCCESS; +} +EXPORT_SYMBOL(qdf_event_destroy); + +/** + * qdf_wait_single_event() - Waits for a single event to be set. + * This API waits for the event to be set. + * + * @event: Pointer to an event to wait on. + * @timeout: Timeout value (in milliseconds). This function returns + * if this interval elapses, regardless if any of the events have + * been set. An input value of 0 for this timeout parameter means + * to wait infinitely, meaning a timeout will never occur. + * + * Return: QDF status + */ +QDF_STATUS qdf_wait_single_event(qdf_event_t *event, uint32_t timeout) +{ + if (in_interrupt()) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s cannot be called from interrupt context!!!", + __func__); + QDF_ASSERT(0); + return QDF_STATUS_E_FAULT; + } + + /* check for null pointer */ + if (NULL == event) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "NULL event passed into %s", __func__); + QDF_ASSERT(0); + return QDF_STATUS_E_FAULT; + } + + /* check if cookie is same as that of initialized event */ + if (LINUX_EVENT_COOKIE != event->cookie) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "Uninitialized event passed into %s", __func__); + QDF_ASSERT(0); + return QDF_STATUS_E_INVAL; + } + + if (timeout) { + long ret; + ret = wait_for_completion_timeout(&event->complete, + msecs_to_jiffies(timeout)); + if (0 >= ret) + return QDF_STATUS_E_TIMEOUT; + } else { + wait_for_completion(&event->complete); + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO, + "Signaled for completion %s", __func__); + return QDF_STATUS_SUCCESS; + } + return QDF_STATUS_SUCCESS; +} +EXPORT_SYMBOL(qdf_wait_single_event); diff --git a/drivers/staging/qca-wifi-host-cmn/qdf/linux/src/qdf_list.c b/drivers/staging/qca-wifi-host-cmn/qdf/linux/src/qdf_list.c new file mode 100644 index 0000000000000000000000000000000000000000..4d373beb104243b39e19cb7561278e168a7d3f12 --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/qdf/linux/src/qdf_list.c @@ -0,0 +1,257 @@ +/* + * Copyright (c) 2014-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: qdf_list.c + * + * QCA driver framework list manipulation APIs. QDF linked list + * APIs are NOT thread safe so make sure to use appropriate locking mechanisms + * to assure operations on the list are thread safe. + */ + +/* Include files */ +#include +#include + +/* Function declarations and documenation */ + +/** + * qdf_list_insert_front() - insert input node at front of the list + * @list: Pointer to list + * @node: Pointer to input node + * + * Return: QDF status + */ +QDF_STATUS qdf_list_insert_front(qdf_list_t *list, qdf_list_node_t *node) +{ + list_add(node, &list->anchor); + list->count++; + return QDF_STATUS_SUCCESS; +} +EXPORT_SYMBOL(qdf_list_insert_front); + +/** + * qdf_list_insert_back() - insert input node at back of the list + * @list: Pointer to list + * @node: Pointer to input node + * + * Return: QDF status + */ +QDF_STATUS qdf_list_insert_back(qdf_list_t *list, qdf_list_node_t *node) +{ + list_add_tail(node, &list->anchor); + list->count++; + return QDF_STATUS_SUCCESS; +} +EXPORT_SYMBOL(qdf_list_insert_back); + +/** + * qdf_list_insert_back_size() - insert input node at back of list and save + * list size + * @list: Pointer to list + * @node: Pointer to input node + * @p_size: Pointer to store list size + * + * Return: QDF status + */ +QDF_STATUS qdf_list_insert_back_size(qdf_list_t *list, + qdf_list_node_t *node, uint32_t *p_size) +{ + list_add_tail(node, &list->anchor); + list->count++; + *p_size = list->count; + return QDF_STATUS_SUCCESS; +} +EXPORT_SYMBOL(qdf_list_insert_back_size); + +/** + * qdf_list_remove_front() - remove node from front of the list + * @list: Pointer to list + * @node2: Double pointer to store the node which is removed from list + * + * Return: QDF status + */ +QDF_STATUS qdf_list_remove_front(qdf_list_t *list, qdf_list_node_t **node2) +{ + struct list_head *listptr; + + if (list_empty(&list->anchor)) + return QDF_STATUS_E_EMPTY; + + listptr = list->anchor.next; + *node2 = listptr; + list_del(list->anchor.next); + list->count--; + + return QDF_STATUS_SUCCESS; +} +EXPORT_SYMBOL(qdf_list_remove_front); + +/** + * qdf_list_remove_back() - remove node from end of the list + * @list: Pointer to list + * @node2: Double pointer to store node which is removed from list + * + * Return: QDF status + */ +QDF_STATUS qdf_list_remove_back(qdf_list_t *list, qdf_list_node_t **node2) +{ + struct list_head *listptr; + + if (list_empty(&list->anchor)) + return QDF_STATUS_E_EMPTY; + + listptr = list->anchor.prev; + *node2 = listptr; + list_del(list->anchor.prev); + list->count--; + + return QDF_STATUS_SUCCESS; +} +EXPORT_SYMBOL(qdf_list_remove_back); + +/** + * qdf_list_has_node() - check if a node is in a list + * @list: pointer to the list being searched + * @node: pointer to the node to search for + * + * It is expected that the list being checked is locked + * when this function is being called. + * + * Return: true if the node is in the list + */ +bool qdf_list_has_node(qdf_list_t *list, qdf_list_node_t *node) +{ + qdf_list_node_t *tmp; + + list_for_each(tmp, &list->anchor) { + if (tmp == node) + return true; + } + return false; +} + +/** + * qdf_list_remove_node() - remove input node from list + * @list: Pointer to list + * @node_to_remove: Pointer to node which needs to be removed + * + * verifies that the node is in the list before removing it. + * It is expected that the list being removed from is locked + * when this function is being called. + * + * Return: QDF status + */ +QDF_STATUS qdf_list_remove_node(qdf_list_t *list, + qdf_list_node_t *node_to_remove) +{ + if (list_empty(&list->anchor)) + return QDF_STATUS_E_EMPTY; + + /* verify that node_to_remove is indeed part of list list */ + if (!qdf_list_has_node(list, node_to_remove)) + return QDF_STATUS_E_INVAL; + + list_del(node_to_remove); + list->count--; + + return QDF_STATUS_SUCCESS; +} +EXPORT_SYMBOL(qdf_list_remove_node); + +/** + * qdf_list_peek_front() - peek front node from list + * @list: Pointer to list + * @node2: Double pointer to store peeked node pointer + * + * Return: QDF status + */ +QDF_STATUS qdf_list_peek_front(qdf_list_t *list, qdf_list_node_t **node2) +{ + struct list_head *listptr; + if (list_empty(&list->anchor)) + return QDF_STATUS_E_EMPTY; + + listptr = list->anchor.next; + *node2 = listptr; + return QDF_STATUS_SUCCESS; +} +EXPORT_SYMBOL(qdf_list_peek_front); + +/** + * qdf_list_peek_next() - peek next node of input node in the list + * @list: Pointer to list + * @node: Pointer to input node + * @node2: Double pointer to store peeked node pointer + * + * Return: QDF status + */ +QDF_STATUS qdf_list_peek_next(qdf_list_t *list, qdf_list_node_t *node, + qdf_list_node_t **node2) +{ + struct list_head *listptr; + int found = 0; + qdf_list_node_t *tmp; + + if ((list == NULL) || (node == NULL) || (node2 == NULL)) + return QDF_STATUS_E_FAULT; + + if (list_empty(&list->anchor)) + return QDF_STATUS_E_EMPTY; + + /* verify that node is indeed part of list list */ + list_for_each(tmp, &list->anchor) { + if (tmp == node) { + found = 1; + break; + } + } + + if (found == 0) + return QDF_STATUS_E_INVAL; + + listptr = node->next; + if (listptr == &list->anchor) + return QDF_STATUS_E_EMPTY; + + *node2 = listptr; + + return QDF_STATUS_SUCCESS; +} +EXPORT_SYMBOL(qdf_list_peek_next); + +/** + * qdf_list_empty() - check if the list is empty + * @list: pointer to the list + * + * Return: true if the list is empty and false otherwise. + */ +bool qdf_list_empty(qdf_list_t *list) +{ + return list_empty(&list->anchor); +} +EXPORT_SYMBOL(qdf_list_empty); diff --git a/drivers/staging/qca-wifi-host-cmn/qdf/linux/src/qdf_lock.c b/drivers/staging/qca-wifi-host-cmn/qdf/linux/src/qdf_lock.c new file mode 100644 index 0000000000000000000000000000000000000000..b05f43782eab33bc1372df670379999bb6d75684 --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/qdf/linux/src/qdf_lock.c @@ -0,0 +1,841 @@ +/* + * Copyright (c) 2014-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#include +#include +#include + +#include +#ifdef CONFIG_MCL +#include +#include +#include +#endif +#include + +/* Function declarations and documenation */ +typedef __qdf_mutex_t qdf_mutex_t; + +/** + * qdf_mutex_create() - Initialize a mutex + * @m: mutex to initialize + * + * Returns: QDF_STATUS + * =0 success + * else fail status + */ +#undef qdf_mutex_create +QDF_STATUS qdf_mutex_create(qdf_mutex_t *lock, const char *func, int line) +{ + /* check for invalid pointer */ + if (lock == NULL) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: NULL pointer passed in", __func__); + return QDF_STATUS_E_FAULT; + } + /* check for 'already initialized' lock */ + if (LINUX_LOCK_COOKIE == lock->cookie) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: already initialized lock", __func__); + return QDF_STATUS_E_BUSY; + } + + if (in_interrupt()) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s cannot be called from interrupt context!!!", + __func__); + return QDF_STATUS_E_FAULT; + } + + qdf_lock_stats_create(&lock->stats, func, line); + + /* initialize new lock */ + mutex_init(&lock->m_lock); + lock->cookie = LINUX_LOCK_COOKIE; + lock->state = LOCK_RELEASED; + lock->process_id = 0; + lock->refcount = 0; + + return QDF_STATUS_SUCCESS; +} +EXPORT_SYMBOL(qdf_mutex_create); + +/** + * qdf_mutex_acquire() - acquire a QDF lock + * @lock: Pointer to the opaque lock object to acquire + * + * A lock object is acquired by calling qdf_mutex_acquire(). If the lock + * is already locked, the calling thread shall block until the lock becomes + * available. This operation shall return with the lock object referenced by + * lock in the locked state with the calling thread as its owner. + * + * Return: + * QDF_STATUS_SUCCESS: lock was successfully initialized + * QDF failure reason codes: lock is not initialized and can't be used + */ +QDF_STATUS qdf_mutex_acquire(qdf_mutex_t *lock) +{ + int rc; + /* check for invalid pointer */ + if (lock == NULL) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: NULL pointer passed in", __func__); + QDF_ASSERT(0); + return QDF_STATUS_E_FAULT; + } + /* check if lock refers to an initialized object */ + if (LINUX_LOCK_COOKIE != lock->cookie) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: uninitialized lock", __func__); + QDF_ASSERT(0); + return QDF_STATUS_E_INVAL; + } + + if (in_interrupt()) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s cannot be called from interrupt context!!!", + __func__); + QDF_ASSERT(0); + return QDF_STATUS_E_FAULT; + } + if ((lock->process_id == current->pid) && + (lock->state == LOCK_ACQUIRED)) { + lock->refcount++; +#ifdef QDF_NESTED_LOCK_DEBUG + pe_err("%s: %x %d %d", __func__, lock, current->pid, + lock->refcount); +#endif + return QDF_STATUS_SUCCESS; + } + + BEFORE_LOCK(lock, mutex_is_locked(&lock->m_lock)); + /* acquire a Lock */ + mutex_lock(&lock->m_lock); + AFTER_LOCK(lock, __func__); + rc = mutex_is_locked(&lock->m_lock); + if (rc == 0) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: unable to lock mutex (rc = %d)", __func__, rc); + QDF_ASSERT(0); + return QDF_STATUS_E_FAILURE; + } +#ifdef QDF_NESTED_LOCK_DEBUG + pe_err("%s: %x %d", __func__, lock, current->pid); +#endif + if (LOCK_DESTROYED != lock->state) { + lock->process_id = current->pid; + lock->refcount++; + lock->state = LOCK_ACQUIRED; + return QDF_STATUS_SUCCESS; + } else { + /* lock is already destroyed */ + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: Lock is already destroyed", __func__); + mutex_unlock(&lock->m_lock); + QDF_ASSERT(0); + return QDF_STATUS_E_FAILURE; + } +} +EXPORT_SYMBOL(qdf_mutex_acquire); + +/** + * qdf_mutex_release() - release a QDF lock + * @lock: Pointer to the opaque lock object to be released + * + * qdf_mutex_release() function shall release the lock object + * referenced by 'lock'. + * + * If a thread attempts to release a lock that it unlocked or is not + * initialized, an error is returned. + * + * Return: + * QDF_STATUS_SUCCESS: lock was successfully initialized + * QDF failure reason codes: lock is not initialized and can't be used + */ +QDF_STATUS qdf_mutex_release(qdf_mutex_t *lock) +{ + /* check for invalid pointer */ + if (lock == NULL) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: NULL pointer passed in", __func__); + QDF_ASSERT(0); + return QDF_STATUS_E_FAULT; + } + + /* check if lock refers to an uninitialized object */ + if (LINUX_LOCK_COOKIE != lock->cookie) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: uninitialized lock", __func__); + QDF_ASSERT(0); + return QDF_STATUS_E_INVAL; + } + + if (in_interrupt()) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s cannot be called from interrupt context!!!", + __func__); + QDF_ASSERT(0); + return QDF_STATUS_E_FAULT; + } + + /* current_thread = get_current_thread_id(); + * Check thread ID of caller against thread ID + * of the thread which acquire the lock + */ + if (lock->process_id != current->pid) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: current task pid does not match original task pid!!", + __func__); +#ifdef QDF_NESTED_LOCK_DEBUG + pe_err("%s: Lock held by=%d being released by=%d", + __func__, lock->process_id, current->pid); +#endif + QDF_ASSERT(0); + return QDF_STATUS_E_PERM; + } + if ((lock->process_id == current->pid) && + (lock->state == LOCK_ACQUIRED)) { + if (lock->refcount > 0) + lock->refcount--; + } +#ifdef QDF_NESTED_LOCK_DEBUG + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, "%s: %x %d %d", __func__, lock, lock->process_id, + lock->refcount); +#endif + if (lock->refcount) + return QDF_STATUS_SUCCESS; + + lock->process_id = 0; + lock->refcount = 0; + lock->state = LOCK_RELEASED; + /* release a Lock */ + BEFORE_UNLOCK(lock, 0); + mutex_unlock(&lock->m_lock); +#ifdef QDF_NESTED_LOCK_DEBUG + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, "%s: Freeing lock %x %d %d", lock, lock->process_id, + lock->refcount); +#endif + return QDF_STATUS_SUCCESS; +} +EXPORT_SYMBOL(qdf_mutex_release); + +/** + * qdf_wake_lock_name() - This function returns the name of the wakelock + * @lock: Pointer to the wakelock + * + * This function returns the name of the wakelock + * + * Return: Pointer to the name if it is valid or a default string + */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)) +const char *qdf_wake_lock_name(qdf_wake_lock_t *lock) +{ + if (lock->name) + return lock->name; + return "UNNAMED_WAKELOCK"; +} +#else +const char *qdf_wake_lock_name(qdf_wake_lock_t *lock) +{ + return "NO_WAKELOCK_SUPPORT"; +} +#endif +EXPORT_SYMBOL(qdf_wake_lock_name); + +/** + * qdf_wake_lock_create() - initializes a wake lock + * @lock: The wake lock to initialize + * @name: Name of wake lock + * + * Return: + * QDF status success: if wake lock is initialized + * QDF status failure: if wake lock was not initialized + */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)) +QDF_STATUS qdf_wake_lock_create(qdf_wake_lock_t *lock, const char *name) +{ + wakeup_source_init(lock, name); + return QDF_STATUS_SUCCESS; +} +#else +QDF_STATUS qdf_wake_lock_create(qdf_wake_lock_t *lock, const char *name) +{ + return QDF_STATUS_SUCCESS; +} +#endif +EXPORT_SYMBOL(qdf_wake_lock_create); + +/** + * qdf_wake_lock_acquire() - acquires a wake lock + * @lock: The wake lock to acquire + * @reason: Reason for wakelock + * + * Return: + * QDF status success: if wake lock is acquired + * QDF status failure: if wake lock was not acquired + */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)) +QDF_STATUS qdf_wake_lock_acquire(qdf_wake_lock_t *lock, uint32_t reason) +{ +#ifdef CONFIG_MCL + host_diag_log_wlock(reason, qdf_wake_lock_name(lock), + WIFI_POWER_EVENT_DEFAULT_WAKELOCK_TIMEOUT, + WIFI_POWER_EVENT_WAKELOCK_TAKEN); +#endif + __pm_stay_awake(lock); + return QDF_STATUS_SUCCESS; +} +#else +QDF_STATUS qdf_wake_lock_acquire(qdf_wake_lock_t *lock, uint32_t reason) +{ + return QDF_STATUS_SUCCESS; +} +#endif +EXPORT_SYMBOL(qdf_wake_lock_acquire); + +/** + * qdf_wake_lock_timeout_acquire() - acquires a wake lock with a timeout + * @lock: The wake lock to acquire + * @reason: Reason for wakelock + * + * Return: + * QDF status success: if wake lock is acquired + * QDF status failure: if wake lock was not acquired + */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)) +QDF_STATUS qdf_wake_lock_timeout_acquire(qdf_wake_lock_t *lock, uint32_t msec) +{ + /* Wakelock for Rx is frequent. + * It is reported only during active debug + */ + __pm_wakeup_event(lock, msec); + return QDF_STATUS_SUCCESS; +} +#else +QDF_STATUS qdf_wake_lock_timeout_acquire(qdf_wake_lock_t *lock, uint32_t msec) +{ + return QDF_STATUS_SUCCESS; +} +#endif +EXPORT_SYMBOL(qdf_wake_lock_timeout_acquire); + +/** + * qdf_wake_lock_release() - releases a wake lock + * @lock: the wake lock to release + * @reason: Reason for wakelock + * + * Return: + * QDF status success: if wake lock is acquired + * QDF status failure: if wake lock was not acquired + */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)) +QDF_STATUS qdf_wake_lock_release(qdf_wake_lock_t *lock, uint32_t reason) +{ +#ifdef CONFIG_MCL + host_diag_log_wlock(reason, qdf_wake_lock_name(lock), + WIFI_POWER_EVENT_DEFAULT_WAKELOCK_TIMEOUT, + WIFI_POWER_EVENT_WAKELOCK_RELEASED); +#endif + __pm_relax(lock); + return QDF_STATUS_SUCCESS; +} +#else +QDF_STATUS qdf_wake_lock_release(qdf_wake_lock_t *lock, uint32_t reason) +{ + return QDF_STATUS_SUCCESS; +} +#endif +EXPORT_SYMBOL(qdf_wake_lock_release); + +/** + * qdf_wake_lock_destroy() - destroys a wake lock + * @lock: The wake lock to destroy + * + * Return: + * QDF status success: if wake lock is acquired + * QDF status failure: if wake lock was not acquired + */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)) +QDF_STATUS qdf_wake_lock_destroy(qdf_wake_lock_t *lock) +{ + wakeup_source_trash(lock); + return QDF_STATUS_SUCCESS; +} +#else +QDF_STATUS qdf_wake_lock_destroy(qdf_wake_lock_t *lock) +{ + return QDF_STATUS_SUCCESS; +} +#endif +EXPORT_SYMBOL(qdf_wake_lock_destroy); + +#ifdef CONFIG_MCL +/** + * qdf_runtime_pm_get() - do a get opperation on the device + * + * A get opperation will prevent a runtime suspend untill a + * corresponding put is done. This api should be used when sending + * data. + * + * CONTRARY TO THE REGULAR RUNTIME PM, WHEN THE BUS IS SUSPENDED, + * THIS API WILL ONLY REQUEST THE RESUME AND NOT TO A GET!!! + * + * return: success if the bus is up and a get has been issued + * otherwise an error code. + */ +QDF_STATUS qdf_runtime_pm_get(void) +{ + void *ol_sc; + int ret; + + ol_sc = cds_get_context(QDF_MODULE_ID_HIF); + + if (ol_sc == NULL) { + QDF_ASSERT(0); + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: HIF context is null!", __func__); + return QDF_STATUS_E_INVAL; + } + + ret = hif_pm_runtime_get(ol_sc); + + if (ret) + return QDF_STATUS_E_FAILURE; + return QDF_STATUS_SUCCESS; +} +EXPORT_SYMBOL(qdf_runtime_pm_get); + +/** + * qdf_runtime_pm_put() - do a put opperation on the device + * + * A put opperation will allow a runtime suspend after a corresponding + * get was done. This api should be used when sending data. + * + * This api will return a failure if the hif module hasn't been + * initialized + * + * return: QDF_STATUS_SUCCESS if the put is performed + */ +QDF_STATUS qdf_runtime_pm_put(void) +{ + void *ol_sc; + int ret; + + ol_sc = cds_get_context(QDF_MODULE_ID_HIF); + + if (ol_sc == NULL) { + QDF_ASSERT(0); + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: HIF context is null!", __func__); + return QDF_STATUS_E_INVAL; + } + + ret = hif_pm_runtime_put(ol_sc); + + if (ret) + return QDF_STATUS_E_FAILURE; + return QDF_STATUS_SUCCESS; +} +EXPORT_SYMBOL(qdf_runtime_pm_put); + +/** + * qdf_runtime_pm_prevent_suspend() - prevent a runtime bus suspend + * @lock: an opaque context for tracking + * + * The lock can only be acquired once per lock context and is tracked. + * + * return: QDF_STATUS_SUCCESS or failure code. + */ +QDF_STATUS qdf_runtime_pm_prevent_suspend(qdf_runtime_lock_t *lock) +{ + void *ol_sc; + int ret; + + ol_sc = cds_get_context(QDF_MODULE_ID_HIF); + + if (ol_sc == NULL) { + QDF_ASSERT(0); + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: HIF context is null!", __func__); + return QDF_STATUS_E_INVAL; + } + + ret = hif_pm_runtime_prevent_suspend(ol_sc, lock->lock); + + if (ret) + return QDF_STATUS_E_FAILURE; + return QDF_STATUS_SUCCESS; +} +EXPORT_SYMBOL(qdf_runtime_pm_prevent_suspend); + +/** + * qdf_runtime_pm_allow_suspend() - prevent a runtime bus suspend + * @lock: an opaque context for tracking + * + * The lock can only be acquired once per lock context and is tracked. + * + * return: QDF_STATUS_SUCCESS or failure code. + */ +QDF_STATUS qdf_runtime_pm_allow_suspend(qdf_runtime_lock_t *lock) +{ + void *ol_sc; + int ret; + ol_sc = cds_get_context(QDF_MODULE_ID_HIF); + + if (ol_sc == NULL) { + QDF_ASSERT(0); + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: HIF context is null!", __func__); + return QDF_STATUS_E_INVAL; + } + + ret = hif_pm_runtime_allow_suspend(ol_sc, lock->lock); + if (ret) + return QDF_STATUS_E_FAILURE; + return QDF_STATUS_SUCCESS; +} +EXPORT_SYMBOL(qdf_runtime_pm_allow_suspend); + +/** + * qdf_runtime_lock_init() - initialize runtime lock + * @name: name of the runtime lock + * + * Initialize a runtime pm lock. This lock can be used + * to prevent the runtime pm system from putting the bus + * to sleep. + * + * Return: runtime_pm_lock_t + */ +QDF_STATUS __qdf_runtime_lock_init(qdf_runtime_lock_t *lock, const char *name) +{ + int ret = hif_runtime_lock_init(lock, name); + + if (ret) + return QDF_STATUS_E_NOMEM; + + return QDF_STATUS_SUCCESS; +} +EXPORT_SYMBOL(__qdf_runtime_lock_init); + +/** + * qdf_runtime_lock_deinit() - deinitialize runtime pm lock + * @lock: the lock to deinitialize + * + * Ensures the lock is released. Frees the runtime lock. + * + * Return: void + */ +void qdf_runtime_lock_deinit(qdf_runtime_lock_t *lock) +{ + void *hif_ctx = cds_get_context(QDF_MODULE_ID_HIF); + hif_runtime_lock_deinit(hif_ctx, lock->lock); +} +EXPORT_SYMBOL(qdf_runtime_lock_deinit); + +#endif /* CONFIG_MCL */ + +/** + * qdf_spinlock_acquire() - acquires a spin lock + * @lock: Spin lock to acquire + * + * Return: + * QDF status success: if wake lock is acquired + */ +QDF_STATUS qdf_spinlock_acquire(qdf_spinlock_t *lock) +{ + spin_lock(&lock->lock.spinlock); + return QDF_STATUS_SUCCESS; +} +EXPORT_SYMBOL(qdf_spinlock_acquire); + + +/** + * qdf_spinlock_release() - release a spin lock + * @lock: Spin lock to release + * + * Return: + * QDF status success : if wake lock is acquired + */ +QDF_STATUS qdf_spinlock_release(qdf_spinlock_t *lock) +{ + spin_unlock(&lock->lock.spinlock); + return QDF_STATUS_SUCCESS; +} +EXPORT_SYMBOL(qdf_spinlock_release); + +/** + * qdf_mutex_destroy() - destroy a QDF lock + * @lock: Pointer to the opaque lock object to be destroyed + * + * function shall destroy the lock object referenced by lock. After a + * successful return from qdf_mutex_destroy() + * the lock object becomes, in effect, uninitialized. + * + * A destroyed lock object can be reinitialized using qdf_mutex_create(); + * the results of otherwise referencing the object after it has been destroyed + * are undefined. Calls to QDF lock functions to manipulate the lock such + * as qdf_mutex_acquire() will fail if the lock is destroyed. Therefore, + * don't use the lock after it has been destroyed until it has + * been re-initialized. + * + * Return: + * QDF_STATUS_SUCCESS: lock was successfully initialized + * QDF failure reason codes: lock is not initialized and can't be used + */ +QDF_STATUS qdf_mutex_destroy(qdf_mutex_t *lock) +{ + /* check for invalid pointer */ + if (NULL == lock) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: NULL pointer passed in", __func__); + return QDF_STATUS_E_FAULT; + } + + if (LINUX_LOCK_COOKIE != lock->cookie) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: uninitialized lock", __func__); + return QDF_STATUS_E_INVAL; + } + + if (in_interrupt()) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s cannot be called from interrupt context!!!", + __func__); + return QDF_STATUS_E_FAULT; + } + + /* check if lock is released */ + if (!mutex_trylock(&lock->m_lock)) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: lock is not released", __func__); + return QDF_STATUS_E_BUSY; + } + lock->cookie = 0; + lock->state = LOCK_DESTROYED; + lock->process_id = 0; + lock->refcount = 0; + + qdf_lock_stats_destroy(&lock->stats); + mutex_unlock(&lock->m_lock); + + return QDF_STATUS_SUCCESS; +} +EXPORT_SYMBOL(qdf_mutex_destroy); + +/** + * qdf_spin_trylock_bh_outline() - spin trylock bottomhalf + * @lock: spinlock object + * Return: nonzero if lock is acquired + */ +int qdf_spin_trylock_bh_outline(qdf_spinlock_t *lock) +{ + return qdf_spin_trylock_bh(lock); +} +EXPORT_SYMBOL(qdf_spin_trylock_bh_outline); + +/** + * qdf_spin_lock_bh_outline() - locks the spinlock in soft irq context + * @lock: spinlock object pointer + * Return: none + */ +void qdf_spin_lock_bh_outline(qdf_spinlock_t *lock) +{ + qdf_spin_lock_bh(lock); +} +EXPORT_SYMBOL(qdf_spin_lock_bh_outline); + +/** + * qdf_spin_unlock_bh_outline() - unlocks spinlock in soft irq context + * @lock: spinlock object pointer + * Return: none + */ +void qdf_spin_unlock_bh_outline(qdf_spinlock_t *lock) +{ + qdf_spin_unlock_bh(lock); +} +EXPORT_SYMBOL(qdf_spin_unlock_bh_outline); + +#if QDF_LOCK_STATS_LIST +struct qdf_lock_cookie { + union { + struct { + struct lock_stats *stats; + const char *func; + int line; + } cookie; + struct { + struct qdf_lock_cookie *next; + } empty_node; + } u; +}; + +#ifndef QDF_LOCK_STATS_LIST_SIZE +#define QDF_LOCK_STATS_LIST_SIZE 256 +#endif + +static qdf_spinlock_t qdf_lock_list_spinlock; +static struct qdf_lock_cookie lock_cookies[QDF_LOCK_STATS_LIST_SIZE]; +static struct qdf_lock_cookie *lock_cookie_freelist; +static qdf_atomic_t lock_cookie_get_failures; +static qdf_atomic_t lock_cookie_untracked_num; +/* dummy value */ +#define DUMMY_LOCK_COOKIE 0xc00c1e + +/** + * qdf_is_lock_cookie - check if memory is a valid lock cookie + * + * return true if the memory is within the range of the lock cookie + * memory. + */ +static bool qdf_is_lock_cookie(struct qdf_lock_cookie *lock_cookie) +{ + return lock_cookie >= &lock_cookies[0] && + lock_cookie <= &lock_cookies[QDF_LOCK_STATS_LIST_SIZE-1]; +} + +/** + * qdf_is_lock_cookie_free() - check if the lock cookie is on the freelist + * @lock_cookie: lock cookie to check + * + * Check that the next field of the lock cookie points to a lock cookie. + * currently this is only true if the cookie is on the freelist. + * + * Checking for the function and line being NULL and 0 should also have worked. + */ +static bool qdf_is_lock_cookie_free(struct qdf_lock_cookie *lock_cookie) +{ + struct qdf_lock_cookie *tmp = lock_cookie->u.empty_node.next; + + return qdf_is_lock_cookie(tmp) || (tmp == NULL); +} + +static struct qdf_lock_cookie *qdf_get_lock_cookie(void) +{ + struct qdf_lock_cookie *lock_cookie; + + qdf_spin_lock_bh(&qdf_lock_list_spinlock); + lock_cookie = lock_cookie_freelist; + if (lock_cookie_freelist) + lock_cookie_freelist = lock_cookie_freelist->u.empty_node.next; + qdf_spin_unlock_bh(&qdf_lock_list_spinlock); + return lock_cookie; +} + +static void __qdf_put_lock_cookie(struct qdf_lock_cookie *lock_cookie) +{ + if (!qdf_is_lock_cookie(lock_cookie)) + QDF_BUG(0); + + lock_cookie->u.empty_node.next = lock_cookie_freelist; + lock_cookie_freelist = lock_cookie; +} + +static void qdf_put_lock_cookie(struct qdf_lock_cookie *lock_cookie) +{ + qdf_spin_lock_bh(&qdf_lock_list_spinlock); + __qdf_put_lock_cookie(lock_cookie); + qdf_spin_unlock_bh(&qdf_lock_list_spinlock); +} + +void qdf_lock_stats_init(void) +{ + int i; + + for (i = 0; i < QDF_LOCK_STATS_LIST_SIZE; i++) + __qdf_put_lock_cookie(&lock_cookies[i]); + + /* stats must be allocated for the spinlock before the cookie, + otherwise this qdf_lock_list_spinlock wouldnt get intialized + propperly */ + qdf_spinlock_create(&qdf_lock_list_spinlock); + qdf_atomic_init(&lock_cookie_get_failures); + qdf_atomic_init(&lock_cookie_untracked_num); +} + +void qdf_lock_stats_deinit(void) +{ + int i; + + qdf_spinlock_destroy(&qdf_lock_list_spinlock); + for (i = 0; i < QDF_LOCK_STATS_LIST_SIZE; i++) { + if (!qdf_is_lock_cookie_free(&lock_cookies[i])) + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: lock_not_destroyed, fun: %s, line %d", + __func__, lock_cookies[i].u.cookie.func, + lock_cookies[i].u.cookie.line); + } +} + +/* allocated separate memory in case the lock memory is freed without + running the deinitialization code. The cookie list will not be + corrupted. */ +void qdf_lock_stats_cookie_create(struct lock_stats *stats, + const char *func, int line) +{ + struct qdf_lock_cookie *cookie = qdf_get_lock_cookie(); + + if (cookie == NULL) { + int count; + qdf_atomic_inc(&lock_cookie_get_failures); + count = qdf_atomic_inc_return(&lock_cookie_untracked_num); + stats->cookie = (void *) DUMMY_LOCK_COOKIE; + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: cookie allocation failure, using dummy (%s:%d) count %d", + __func__, func, line, count); + return; + } + + stats->cookie = cookie; + stats->cookie->u.cookie.stats = stats; + stats->cookie->u.cookie.func = func; + stats->cookie->u.cookie.line = line; +} + +void qdf_lock_stats_cookie_destroy(struct lock_stats *stats) +{ + struct qdf_lock_cookie *cookie = stats->cookie; + + if (cookie == NULL) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: Double cookie destroy", __func__); + QDF_ASSERT(0); + return; + } + + stats->cookie = NULL; + if (cookie == (void *)DUMMY_LOCK_COOKIE) { + qdf_atomic_dec(&lock_cookie_untracked_num); + return; + } + + cookie->u.cookie.stats = NULL; + cookie->u.cookie.func = NULL; + cookie->u.cookie.line = 0; + + qdf_put_lock_cookie(cookie); +} +#endif diff --git a/drivers/staging/qca-wifi-host-cmn/qdf/linux/src/qdf_mc_timer.c b/drivers/staging/qca-wifi-host-cmn/qdf/linux/src/qdf_mc_timer.c new file mode 100644 index 0000000000000000000000000000000000000000..e64104515147e90960cd6ba20dfe922b95bdbd50 --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/qdf/linux/src/qdf_mc_timer.c @@ -0,0 +1,731 @@ +/* + * Copyright (c) 2014-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: qdf_mc_timer + * QCA driver framework timer APIs serialized to MC thread + */ + +/* Include Files */ +#include +#include +#include "qdf_lock.h" +#include "qdf_list.h" +#include "qdf_mem.h" +#include +#ifdef CONFIG_MCL +#include +#endif +/* Preprocessor definitions and constants */ + +#define LINUX_TIMER_COOKIE 0x12341234 +#define LINUX_INVALID_TIMER_COOKIE 0xfeedface +#define TMR_INVALID_ID (0) + +/* Type declarations */ + +/* Static Variable Definitions */ +static unsigned int persistent_timer_count; +static qdf_mutex_t persistent_timer_count_lock; + +/* Function declarations and documenation */ + +/** + * qdf_try_allowing_sleep() - clean up timer states after it has been deactivated + * @type: timer type + * + * Clean up timer states after it has been deactivated check and try to allow + * sleep after a timer has been stopped or expired. + * + * Return: none + */ +void qdf_try_allowing_sleep(QDF_TIMER_TYPE type) +{ + if (QDF_TIMER_TYPE_WAKE_APPS == type) { + + persistent_timer_count--; + if (0 == persistent_timer_count) { + /* since the number of persistent timers has + decreased from 1 to 0, the timer should allow + sleep + */ + } + } +} +EXPORT_SYMBOL(qdf_try_allowing_sleep); + +/** + * qdf_mc_timer_get_current_state() - get the current state of the timer + * @timer: Pointer to timer object + * + * Return: + * QDF_TIMER_STATE - qdf timer state + */ +QDF_TIMER_STATE qdf_mc_timer_get_current_state(qdf_mc_timer_t *timer) +{ + if (NULL == timer) { + QDF_ASSERT(0); + return QDF_TIMER_STATE_UNUSED; + } + + switch (timer->state) { + case QDF_TIMER_STATE_STOPPED: + case QDF_TIMER_STATE_STARTING: + case QDF_TIMER_STATE_RUNNING: + case QDF_TIMER_STATE_UNUSED: + return timer->state; + default: + QDF_ASSERT(0); + return QDF_TIMER_STATE_UNUSED; + } +} +EXPORT_SYMBOL(qdf_mc_timer_get_current_state); + +/** + * qdf_timer_module_init() - initializes a QDF timer module. + * + * This API initializes the QDF timer module. This needs to be called + * exactly once prior to using any QDF timers. + * + * Return: none + */ +void qdf_timer_module_init(void) +{ + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO_HIGH, + "Initializing the QDF MC timer module"); + qdf_mutex_create(&persistent_timer_count_lock); +} +EXPORT_SYMBOL(qdf_timer_module_init); + +#ifdef TIMER_MANAGER + +qdf_list_t qdf_timer_list; +qdf_spinlock_t qdf_timer_list_lock; + +static void qdf_timer_clean(void); + +/** + * qdf_mc_timer_manager_init() - initialize QDF debug timer manager + * + * This API initializes QDF timer debug functionality. + * + * Return: none + */ +void qdf_mc_timer_manager_init(void) +{ + qdf_list_create(&qdf_timer_list, 1000); + qdf_spinlock_create(&qdf_timer_list_lock); + return; +} +EXPORT_SYMBOL(qdf_mc_timer_manager_init); + +/** + * qdf_timer_clean() - clean up QDF timer debug functionality + * + * This API cleans up QDF timer debug functionality and prints which QDF timers + * are leaked. This is called during driver unload. + * + * Return: none + */ +static void qdf_timer_clean(void) +{ + uint32_t list_size; + qdf_list_node_t *node; + QDF_STATUS qdf_status; + + qdf_mc_timer_node_t *timer_node; + + list_size = qdf_list_size(&qdf_timer_list); + + if (!list_size) + return; + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: List is not Empty. list_size %d ", + __func__, (int)list_size); + + do { + qdf_spin_lock_irqsave(&qdf_timer_list_lock); + qdf_status = qdf_list_remove_front(&qdf_timer_list, &node); + qdf_spin_unlock_irqrestore(&qdf_timer_list_lock); + if (QDF_STATUS_SUCCESS == qdf_status) { + timer_node = (qdf_mc_timer_node_t *) node; + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_FATAL, + "timer Leak@ File %s, @Line %d", + timer_node->file_name, + (int)timer_node->line_num); + qdf_mem_free(timer_node); + } + } while (qdf_status == QDF_STATUS_SUCCESS); +} +EXPORT_SYMBOL(qdf_timer_clean); + +/** + * qdf_mc_timer_manager_exit() - exit QDF timer debug functionality + * + * This API exists QDF timer debug functionality + * + * Return: none + */ +void qdf_mc_timer_manager_exit(void) +{ + qdf_timer_clean(); + qdf_list_destroy(&qdf_timer_list); +} +EXPORT_SYMBOL(qdf_mc_timer_manager_exit); +#endif + +/** + * qdf_mc_timer_init() - initialize a QDF timer + * @timer: Pointer to timer object + * @timer_type: Type of timer + * @callback: Callback to be called after timer expiry + * @ser_data: User data which will be passed to callback function + * + * This API initializes a QDF timer object. + * + * qdf_mc_timer_init() initializes a QDF timer object. A timer must be + * initialized by calling qdf_mc_timer_initialize() before it may be used in + * any other timer functions. + * + * Attempting to initialize timer that is already initialized results in + * a failure. A destroyed timer object can be re-initialized with a call to + * qdf_mc_timer_init(). The results of otherwise referencing the object + * after it has been destroyed are undefined. + * + * Calls to QDF timer functions to manipulate the timer such + * as qdf_mc_timer_set() will fail if the timer is not initialized or has + * been destroyed. Therefore, don't use the timer after it has been + * destroyed until it has been re-initialized. + * + * All callback will be executed within the CDS main thread unless it is + * initialized from the Tx thread flow, in which case it will be executed + * within the tx thread flow. + * + * Return: + * QDF_STATUS_SUCCESS: timer is initialized successfully + * QDF failure status: timer initialization failed + */ +#ifdef TIMER_MANAGER +QDF_STATUS qdf_mc_timer_init_debug(qdf_mc_timer_t *timer, + QDF_TIMER_TYPE timer_type, + qdf_mc_timer_callback_t callback, + void *user_data, char *file_name, + uint32_t line_num) +{ + QDF_STATUS qdf_status; + + /* check for invalid pointer */ + if ((timer == NULL) || (callback == NULL)) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: Null params being passed", __func__); + QDF_ASSERT(0); + return QDF_STATUS_E_FAULT; + } + + timer->timer_node = qdf_mem_malloc(sizeof(qdf_mc_timer_node_t)); + + if (timer->timer_node == NULL) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: Not able to allocate memory for time_node", + __func__); + QDF_ASSERT(0); + return QDF_STATUS_E_NOMEM; + } + + qdf_mem_set(timer->timer_node, sizeof(qdf_mc_timer_node_t), 0); + + timer->timer_node->file_name = file_name; + timer->timer_node->line_num = line_num; + timer->timer_node->qdf_timer = timer; + + qdf_spin_lock_irqsave(&qdf_timer_list_lock); + qdf_status = qdf_list_insert_front(&qdf_timer_list, + &timer->timer_node->node); + qdf_spin_unlock_irqrestore(&qdf_timer_list_lock); + if (QDF_STATUS_SUCCESS != qdf_status) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: Unable to insert node into List qdf_status %d", + __func__, qdf_status); + } + + /* set the various members of the timer structure + * with arguments passed or with default values + */ + qdf_spinlock_create(&timer->platform_info.spinlock); + if (QDF_TIMER_TYPE_SW == timer_type) + init_timer_deferrable(&(timer->platform_info.timer)); + else + init_timer(&(timer->platform_info.timer)); +#ifdef CONFIG_MCL + timer->platform_info.timer.function = cds_linux_timer_callback; +#else + timer->platform_info.timer.function = NULL; +#endif + timer->platform_info.timer.data = (unsigned long)timer; + timer->callback = callback; + timer->user_data = user_data; + timer->type = timer_type; + timer->platform_info.cookie = LINUX_TIMER_COOKIE; + timer->platform_info.thread_id = 0; + timer->state = QDF_TIMER_STATE_STOPPED; + + return QDF_STATUS_SUCCESS; +} +#else +QDF_STATUS qdf_mc_timer_init(qdf_mc_timer_t *timer, QDF_TIMER_TYPE timer_type, + qdf_mc_timer_callback_t callback, + void *user_data) +{ + /* check for invalid pointer */ + if ((timer == NULL) || (callback == NULL)) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: Null params being passed", __func__); + QDF_ASSERT(0); + return QDF_STATUS_E_FAULT; + } + + /* set the various members of the timer structure + * with arguments passed or with default values + */ + qdf_spinlock_create(&timer->platform_info.spinlock); + if (QDF_TIMER_TYPE_SW == timer_type) + init_timer_deferrable(&(timer->platform_info.timer)); + else + init_timer(&(timer->platform_info.timer)); +#ifdef CONFIG_MCL + timer->platform_info.timer.function = cds_linux_timer_callback; +#else + timer->platform_info.timer.function = NULL; +#endif + timer->platform_info.timer.data = (unsigned long)timer; + timer->callback = callback; + timer->user_data = user_data; + timer->type = timer_type; + timer->platform_info.cookie = LINUX_TIMER_COOKIE; + timer->platform_info.thread_id = 0; + timer->state = QDF_TIMER_STATE_STOPPED; + + return QDF_STATUS_SUCCESS; +} +#endif + +/** + * qdf_mc_timer_destroy() - destroy QDF timer + * @timer: Pointer to timer object + * + * qdf_mc_timer_destroy() function shall destroy the timer object. + * After a successful return from \a qdf_mc_timer_destroy() the timer + * object becomes, in effect, uninitialized. + * + * A destroyed timer object can be re-initialized by calling + * qdf_mc_timer_init(). The results of otherwise referencing the object + * after it has been destroyed are undefined. + * + * Calls to QDF timer functions to manipulate the timer, such + * as qdf_mc_timer_set() will fail if the lock is destroyed. Therefore, + * don't use the timer after it has been destroyed until it has + * been re-initialized. + * + * Return: + * QDF_STATUS_SUCCESS - timer is initialized successfully + * QDF failure status - timer initialization failed + */ +#ifdef TIMER_MANAGER +QDF_STATUS qdf_mc_timer_destroy(qdf_mc_timer_t *timer) +{ + QDF_STATUS v_status = QDF_STATUS_SUCCESS; + + /* check for invalid pointer */ + if (NULL == timer) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: Null timer pointer being passed", __func__); + QDF_ASSERT(0); + return QDF_STATUS_E_FAULT; + } + + /* Check if timer refers to an uninitialized object */ + if (LINUX_TIMER_COOKIE != timer->platform_info.cookie) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: Cannot destroy uninitialized timer", __func__); + QDF_ASSERT(0); + return QDF_STATUS_E_INVAL; + } + + qdf_spin_lock_irqsave(&qdf_timer_list_lock); + v_status = qdf_list_remove_node(&qdf_timer_list, + &timer->timer_node->node); + qdf_spin_unlock_irqrestore(&qdf_timer_list_lock); + if (v_status != QDF_STATUS_SUCCESS) { + QDF_ASSERT(0); + return QDF_STATUS_E_INVAL; + } + qdf_mem_free(timer->timer_node); + + qdf_spin_lock_irqsave(&timer->platform_info.spinlock); + + switch (timer->state) { + + case QDF_TIMER_STATE_STARTING: + v_status = QDF_STATUS_E_BUSY; + break; + + case QDF_TIMER_STATE_RUNNING: + /* Stop the timer first */ + del_timer(&(timer->platform_info.timer)); + v_status = QDF_STATUS_SUCCESS; + break; + case QDF_TIMER_STATE_STOPPED: + v_status = QDF_STATUS_SUCCESS; + break; + + case QDF_TIMER_STATE_UNUSED: + v_status = QDF_STATUS_E_ALREADY; + break; + + default: + v_status = QDF_STATUS_E_FAULT; + break; + } + + if (QDF_STATUS_SUCCESS == v_status) { + timer->platform_info.cookie = LINUX_INVALID_TIMER_COOKIE; + timer->state = QDF_TIMER_STATE_UNUSED; + qdf_spin_unlock_irqrestore(&timer->platform_info.spinlock); + qdf_spinlock_destroy(&timer->platform_info.spinlock); + return v_status; + } + + qdf_spin_unlock_irqrestore(&timer->platform_info.spinlock); + + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: Cannot destroy timer in state = %d", __func__, + timer->state); + QDF_ASSERT(0); + + return v_status; +} +EXPORT_SYMBOL(qdf_mc_timer_destroy); + +#else + +/** + * qdf_mc_timer_destroy() - destroy QDF timer + * @timer: Pointer to timer object + * + * qdf_mc_timer_destroy() function shall destroy the timer object. + * After a successful return from \a qdf_mc_timer_destroy() the timer + * object becomes, in effect, uninitialized. + * + * A destroyed timer object can be re-initialized by calling + * qdf_mc_timer_init(). The results of otherwise referencing the object + * after it has been destroyed are undefined. + * + * Calls to QDF timer functions to manipulate the timer, such + * as qdf_mc_timer_set() will fail if the lock is destroyed. Therefore, + * don't use the timer after it has been destroyed until it has + * been re-initialized. + * + * Return: + * QDF_STATUS_SUCCESS - timer is initialized successfully + * QDF failure status - timer initialization failed + */ +QDF_STATUS qdf_mc_timer_destroy(qdf_mc_timer_t *timer) +{ + QDF_STATUS v_status = QDF_STATUS_SUCCESS; + + /* check for invalid pointer */ + if (NULL == timer) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: Null timer pointer being passed", __func__); + QDF_ASSERT(0); + return QDF_STATUS_E_FAULT; + } + + /* check if timer refers to an uninitialized object */ + if (LINUX_TIMER_COOKIE != timer->platform_info.cookie) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: Cannot destroy uninitialized timer", __func__); + QDF_ASSERT(0); + return QDF_STATUS_E_INVAL; + } + qdf_spin_lock_irqsave(&timer->platform_info.spinlock); + + switch (timer->state) { + + case QDF_TIMER_STATE_STARTING: + v_status = QDF_STATUS_E_BUSY; + break; + + case QDF_TIMER_STATE_RUNNING: + /* Stop the timer first */ + del_timer(&(timer->platform_info.timer)); + v_status = QDF_STATUS_SUCCESS; + break; + + case QDF_TIMER_STATE_STOPPED: + v_status = QDF_STATUS_SUCCESS; + break; + + case QDF_TIMER_STATE_UNUSED: + v_status = QDF_STATUS_E_ALREADY; + break; + + default: + v_status = QDF_STATUS_E_FAULT; + break; + } + + if (QDF_STATUS_SUCCESS == v_status) { + timer->platform_info.cookie = LINUX_INVALID_TIMER_COOKIE; + timer->state = QDF_TIMER_STATE_UNUSED; + qdf_spin_unlock_irqrestore(&timer->platform_info.spinlock); + return v_status; + } + + qdf_spin_unlock_irqrestore(&timer->platform_info.spinlock); + + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: Cannot destroy timer in state = %d", __func__, + timer->state); + QDF_ASSERT(0); + + return v_status; +} +EXPORT_SYMBOL(qdf_mc_timer_destroy); +#endif + +/** + * qdf_mc_timer_start() - start a QDF timer object + * @timer: Pointer to timer object + * @expiration_time: Time to expire + * + * qdf_mc_timer_start() function starts a timer to expire after the + * specified interval, thus running the timer callback function when + * the interval expires. + * + * A timer only runs once (a one-shot timer). To re-start the + * timer, qdf_mc_timer_start() has to be called after the timer runs + * or has been cancelled. + * + * Return: + * QDF_STATUS_SUCCESS: timer is initialized successfully + * QDF failure status: timer initialization failed + */ +QDF_STATUS qdf_mc_timer_start(qdf_mc_timer_t *timer, uint32_t expiration_time) +{ + /* check for invalid pointer */ + if (NULL == timer) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s Null timer pointer being passed", __func__); + QDF_ASSERT(0); + return QDF_STATUS_E_INVAL; + } + + /* check if timer refers to an uninitialized object */ + if (LINUX_TIMER_COOKIE != timer->platform_info.cookie) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: Cannot start uninitialized timer", __func__); + QDF_ASSERT(0); + + return QDF_STATUS_E_INVAL; + } + + /* check if timer has expiration time less than 10 ms */ + if (expiration_time < 10) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: Cannot start a timer with expiration less than 10 ms", + __func__); + QDF_ASSERT(0); + return QDF_STATUS_E_INVAL; + } + + /* make sure the remainer of the logic isn't interrupted */ + qdf_spin_lock_irqsave(&timer->platform_info.spinlock); + + /* ensure if the timer can be started */ + if (QDF_TIMER_STATE_STOPPED != timer->state) { + qdf_spin_unlock_irqrestore(&timer->platform_info.spinlock); + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: Cannot start timer in state = %d ", __func__, + timer->state); + return QDF_STATUS_E_ALREADY; + } + + /* start the timer */ + mod_timer(&(timer->platform_info.timer), + jiffies + msecs_to_jiffies(expiration_time)); + + timer->state = QDF_TIMER_STATE_RUNNING; + + /* get the thread ID on which the timer is being started */ + timer->platform_info.thread_id = current->pid; + + if (QDF_TIMER_TYPE_WAKE_APPS == timer->type) { + persistent_timer_count++; + if (1 == persistent_timer_count) { + /* since we now have one persistent timer, + * we need to disallow sleep + * sleep_negate_okts(sleep_client_handle); + */ + } + } + + qdf_spin_unlock_irqrestore(&timer->platform_info.spinlock); + + return QDF_STATUS_SUCCESS; +} +EXPORT_SYMBOL(qdf_mc_timer_start); + +/** + * qdf_mc_timer_stop() - stop a QDF timer + * @timer: Pointer to timer object + * qdf_mc_timer_stop() function stops a timer that has been started but + * has not expired, essentially cancelling the 'start' request. + * + * After a timer is stopped, it goes back to the state it was in after it + * was created and can be started again via a call to qdf_mc_timer_start(). + * + * Return: + * QDF_STATUS_SUCCESS: timer is initialized successfully + * QDF failure status: timer initialization failed + */ +QDF_STATUS qdf_mc_timer_stop(qdf_mc_timer_t *timer) +{ + /* check for invalid pointer */ + if (NULL == timer) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s Null timer pointer being passed", __func__); + QDF_ASSERT(0); + return QDF_STATUS_E_INVAL; + } + + /* check if timer refers to an uninitialized object */ + if (LINUX_TIMER_COOKIE != timer->platform_info.cookie) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: Cannot stop uninitialized timer", __func__); + QDF_ASSERT(0); + + return QDF_STATUS_E_INVAL; + } + + /* ensure the timer state is correct */ + qdf_spin_lock_irqsave(&timer->platform_info.spinlock); + + if (QDF_TIMER_STATE_RUNNING != timer->state) { + qdf_spin_unlock_irqrestore(&timer->platform_info.spinlock); + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: Cannot stop timer in state = %d", + __func__, timer->state); + return QDF_STATUS_SUCCESS; + } + + timer->state = QDF_TIMER_STATE_STOPPED; + + del_timer(&(timer->platform_info.timer)); + + qdf_spin_unlock_irqrestore(&timer->platform_info.spinlock); + + qdf_try_allowing_sleep(timer->type); + + return QDF_STATUS_SUCCESS; +} +EXPORT_SYMBOL(qdf_mc_timer_stop); + +/** + * qdf_mc_timer_get_system_ticks() - get the system time in 10ms ticks + + * qdf_mc_timer_get_system_ticks() function returns the current number + * of timer ticks in 10msec intervals. This function is suitable timestamping + * and calculating time intervals by calculating the difference between two + * timestamps. + * + * Return: + * The current system tick count (in 10msec intervals). This + * function cannot fail. + */ +unsigned long qdf_mc_timer_get_system_ticks(void) +{ + return jiffies_to_msecs(jiffies) / 10; +} +EXPORT_SYMBOL(qdf_mc_timer_get_system_ticks); + +/** + * qdf_mc_timer_get_system_time() - Get the system time in milliseconds + * + * qdf_mc_timer_get_system_time() function returns the number of milliseconds + * that have elapsed since the system was started + * + * Return: + * The current system time in milliseconds + */ +unsigned long qdf_mc_timer_get_system_time(void) +{ + struct timeval tv; + do_gettimeofday(&tv); + return tv.tv_sec * 1000 + tv.tv_usec / 1000; +} +EXPORT_SYMBOL(qdf_mc_timer_get_system_time); + +s64 qdf_get_monotonic_boottime_ns(void) +{ + struct timespec ts; + + ktime_get_ts(&ts); + return timespec_to_ns(&ts); +} +EXPORT_SYMBOL(qdf_get_monotonic_boottime_ns); + +/** + * qdf_timer_module_deinit() - Deinitializes a QDF timer module. + * + * This API deinitializes the QDF timer module. + * Return: none + */ +void qdf_timer_module_deinit(void) +{ + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO_HIGH, + "De-Initializing the QDF MC timer module"); + qdf_mutex_destroy(&persistent_timer_count_lock); +} +EXPORT_SYMBOL(qdf_timer_module_deinit); + +void qdf_get_time_of_the_day_in_hr_min_sec_usec(char *tbuf, int len) +{ + struct timeval tv; + struct rtc_time tm; + unsigned long local_time; + + /* Format the Log time R#: [hr:min:sec.microsec] */ + do_gettimeofday(&tv); + /* Convert rtc to local time */ + local_time = (u32)(tv.tv_sec - (sys_tz.tz_minuteswest * 60)); + rtc_time_to_tm(local_time, &tm); + scnprintf(tbuf, len, + "[%02d:%02d:%02d.%06lu]", + tm.tm_hour, tm.tm_min, tm.tm_sec, tv.tv_usec); +} +EXPORT_SYMBOL(qdf_get_time_of_the_day_in_hr_min_sec_usec); diff --git a/drivers/staging/qca-wifi-host-cmn/qdf/linux/src/qdf_mem.c b/drivers/staging/qca-wifi-host-cmn/qdf/linux/src/qdf_mem.c new file mode 100644 index 0000000000000000000000000000000000000000..fa16ba94b38064b09dd2a679041fdc86c4cac323 --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/qdf/linux/src/qdf_mem.c @@ -0,0 +1,1525 @@ +/* + * Copyright (c) 2014-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: qdf_mem + * This file provides OS dependent memory management APIs + */ + +#include "qdf_debugfs.h" +#include "qdf_mem.h" +#include "qdf_nbuf.h" +#include "qdf_lock.h" +#include "qdf_mc_timer.h" +#include "qdf_module.h" +#include +#include "qdf_atomic.h" +#include +#include +#include + +#ifdef CONFIG_MCL +#include +#else +#define host_log_low_resource_failure(code) do {} while (0) +#endif + +#if defined(CONFIG_CNSS) +#include +#endif + +#ifdef CONFIG_WCNSS_MEM_PRE_ALLOC +#include +#endif + +#ifdef MEMORY_DEBUG +#include +qdf_list_t qdf_mem_list; +qdf_spinlock_t qdf_mem_list_lock; + +static uint8_t WLAN_MEM_HEADER[] = { 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, + 0x67, 0x68 }; +static uint8_t WLAN_MEM_TAIL[] = { 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, + 0x86, 0x87 }; + +/** + * struct s_qdf_mem_struct - memory object to dubug + * @node: node to the list + * @filename: name of file + * @line_num: line number + * @size: size of the file + * @header: array that contains header + * @in_use: memory usage count + */ +struct s_qdf_mem_struct { + qdf_list_node_t node; + char *file_name; + unsigned int line_num; + unsigned int size; + uint8_t header[8]; + qdf_atomic_t in_use; +}; +#endif /* MEMORY_DEBUG */ + +/* Preprocessor Definitions and Constants */ +#define QDF_GET_MEMORY_TIME_THRESHOLD 300 + +int qdf_dbg_mask; +qdf_declare_param(qdf_dbg_mask, int); +EXPORT_SYMBOL(qdf_dbg_mask); + +u_int8_t prealloc_disabled = 1; +qdf_declare_param(prealloc_disabled, byte); +EXPORT_SYMBOL(prealloc_disabled); + +#if defined WLAN_DEBUGFS && defined MEMORY_DEBUG + +/** + * struct __qdf_mem_stat - qdf memory statistics + * @kmalloc: total kmalloc allocations + * @dma: total dma allocations + */ +static struct __qdf_mem_stat { + qdf_atomic_t kmalloc; + qdf_atomic_t dma; +} qdf_mem_stat; + + +/** + * struct __qdf_mem_info - memory statistics + * @file_name: the file which allocated memory + * @line_num: the line at which allocation happened + * @size: the size of allocation + * @count: how many allocations of same type + * + */ +struct __qdf_mem_info { + char *file_name; + unsigned int line_num; + unsigned int size; + unsigned int count; +}; + +/* Debugfs root directory for qdf_mem */ +static struct dentry *qdf_mem_debugfs_root; + +/* + * A table to identify duplicates in close proximity. The table depth defines + * the proximity scope. A deeper table takes more time. Chose any optimum value. + * + */ +#define QDF_MEM_STAT_TABLE_SIZE 4 +static struct __qdf_mem_info qdf_mem_info_table[QDF_MEM_STAT_TABLE_SIZE]; + +static inline void qdf_mem_kmalloc_inc(qdf_size_t size) +{ + qdf_atomic_add(size, &qdf_mem_stat.kmalloc); +} + +static inline void qdf_mem_dma_inc(qdf_size_t size) +{ + qdf_atomic_add(size, &qdf_mem_stat.dma); +} + +static inline void qdf_mem_kmalloc_dec(qdf_size_t size) +{ + qdf_atomic_sub(size, &qdf_mem_stat.kmalloc); +} + +static inline void qdf_mem_dma_dec(qdf_size_t size) +{ + qdf_atomic_sub(size, &qdf_mem_stat.dma); +} + + +/** + * qdf_mem_info_table_init() - initialize the stat table + * + * Return: None + */ +static void qdf_mem_info_table_init(void) +{ + memset(&qdf_mem_info_table, 0, sizeof(qdf_mem_info_table)); +} + +/** + * qdf_mem_get_node() - increase the node usage count + * @n: node + * + * An increased usage count will block the memory from getting released. + * Initially the usage count is incremented from qdf_mem_malloc_debug(). + * Corresponding qdf_mem_free() will decrement the reference count and frees up + * the memory when the usage count reaches zero. Here decrement and test is an + * atomic operation in qdf_mem_free() to avoid any race condition. + * + * If a caller wants to take the ownership of an allocated memory, it can call + * this function with the associated node. + * + * Return: None + * + */ +static void qdf_mem_get_node(qdf_list_node_t *n) +{ + struct s_qdf_mem_struct *m = container_of(n, typeof(*m), node); + + qdf_atomic_inc(&m->in_use); +} + +/** + * qdf_mem_put_node_free() - decrease the node usage count and free memory + * @n: node + * + * Additionally it releases the memory when the usage count reaches zero. Usage + * count is decremented and tested against zero in qdf_mem_free(). If the count + * is 0, the node and associated memory gets freed. + * + * Return: None + * + */ +static void qdf_mem_put_node_free(qdf_list_node_t *n) +{ + struct s_qdf_mem_struct *m = container_of(n, typeof(*m), node); + + /* qdf_mem_free() is expecting the same address returned by + * qdf_mem_malloc_debug(), which is 'm + sizeof(s_qdf_mem_struct)' */ + qdf_mem_free(m + 1); +} + +/** + * qdf_mem_get_first() - get the first node. + * + * Return: node + */ +static qdf_list_node_t *qdf_mem_get_first(void) +{ + QDF_STATUS status; + qdf_list_node_t *node = NULL; + + qdf_spin_lock_bh(&qdf_mem_list_lock); + status = qdf_list_peek_front(&qdf_mem_list, &node); + if (QDF_STATUS_SUCCESS == status) + qdf_mem_get_node(node); + qdf_spin_unlock_bh(&qdf_mem_list_lock); + + return node; +} + +/** + * qdf_mem_get_next() - get the next node + * @n: node + * + * Return: next node + */ +static qdf_list_node_t *qdf_mem_get_next(qdf_list_node_t *n) +{ + QDF_STATUS status; + qdf_list_node_t *node = NULL; + + qdf_spin_lock_bh(&qdf_mem_list_lock); + status = qdf_list_peek_next(&qdf_mem_list, n, &node); + if (QDF_STATUS_SUCCESS == status) + qdf_mem_get_node(node); + + qdf_spin_unlock_bh(&qdf_mem_list_lock); + + qdf_mem_put_node_free(n); + + return node; + +} + +static void qdf_mem_seq_print_header(struct seq_file *seq) +{ + seq_puts(seq, "\n"); + seq_puts(seq, "filename line size x no [ total ]\n"); + seq_puts(seq, "\n"); +} + +/** + * qdf_mem_info_table_insert() - insert node into an array + * @n: node + * + * Return: + * true - success + * false - failure + */ +static bool qdf_mem_info_table_insert(qdf_list_node_t *n) +{ + int i; + struct __qdf_mem_info *t = qdf_mem_info_table; + bool dup; + bool consumed; + struct s_qdf_mem_struct *m = (struct s_qdf_mem_struct *)n; + + for (i = 0; i < QDF_MEM_STAT_TABLE_SIZE; i++) { + if (!t[i].count) { + t[i].file_name = m->file_name; + t[i].line_num = m->line_num; + t[i].size = m->size; + t[i].count++; + break; + } + dup = !strcmp(t[i].file_name, m->file_name) && + (t[i].line_num == m->line_num) && + (t[i].size == m->size); + if (dup) { + t[i].count++; + break; + } + } + + consumed = (i < QDF_MEM_STAT_TABLE_SIZE); + + return consumed; +} + +/** + * qdf_mem_seq_print() - print the table using seq_printf + * @seq: seq_file handle + * + * Node table will be cleared once printed. + * + * Return: None + */ +static void qdf_mem_seq_print(struct seq_file *seq) +{ + int i; + struct __qdf_mem_info *t = qdf_mem_info_table; + + for (i = 0; i < QDF_MEM_STAT_TABLE_SIZE && t[i].count; i++) { + seq_printf(seq, + "%-35s%6d\t%6d x %4d\t[%7d]\n", + kbasename(t[i].file_name), + t[i].line_num, t[i].size, + t[i].count, + t[i].size * t[i].count); + } + + qdf_mem_info_table_init(); +} + +/** + * qdf_mem_seq_start() - sequential callback to start + * @seq: seq_file handle + * @pos: The start position of the sequence + * + * Return: + * SEQ_START_TOKEN - Prints header + * None zero value - Node + * NULL - End of the sequence + */ +static void *qdf_mem_seq_start(struct seq_file *seq, loff_t *pos) +{ + if (*pos == 0) { + qdf_mem_info_table_init(); + return SEQ_START_TOKEN; + } else if (seq->private) { + return qdf_mem_get_next(seq->private); + } + + return NULL; +} + +/** + * qdf_mem_seq_next() - next sequential callback + * @seq: seq_file handle + * @v: the current iterator + * @pos: the current position [not used] + * + * Get the next node and release previous node. + * + * Return: + * None zero value - Next node + * NULL - No more to process in the list + */ +static void *qdf_mem_seq_next(struct seq_file *seq, void *v, loff_t *pos) +{ + qdf_list_node_t *node; + + ++*pos; + + if (v == SEQ_START_TOKEN) + node = qdf_mem_get_first(); + else + node = qdf_mem_get_next(v); + + return node; +} + +/** + * qdf_mem_seq_stop() - stop sequential callback + * @seq: seq_file handle + * @v: current iterator + * + * Return: None + */ +static void qdf_mem_seq_stop(struct seq_file *seq, void *v) +{ + seq->private = v; +} + +/** + * qdf_mem_seq_show() - print sequential callback + * @seq: seq_file handle + * @v: current iterator + * + * Return: 0 - success + */ +static int qdf_mem_seq_show(struct seq_file *seq, void *v) +{ + + if (v == SEQ_START_TOKEN) { + qdf_mem_seq_print_header(seq); + return 0; + } + + while (!qdf_mem_info_table_insert(v)) + qdf_mem_seq_print(seq); + + return 0; +} + +/* sequential file operation table */ +static const struct seq_operations qdf_mem_seq_ops = { + .start = qdf_mem_seq_start, + .next = qdf_mem_seq_next, + .stop = qdf_mem_seq_stop, + .show = qdf_mem_seq_show, +}; + + +static int qdf_mem_debugfs_open(struct inode *inode, struct file *file) +{ + return seq_open(file, &qdf_mem_seq_ops); +} + +/* debugfs file operation table */ +static const struct file_operations fops_qdf_mem_debugfs = { + .owner = THIS_MODULE, + .open = qdf_mem_debugfs_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + +/** + * qdf_mem_debugfs_init() - initialize routine + * + * Return: QDF_STATUS + */ +static QDF_STATUS qdf_mem_debugfs_init(void) +{ + struct dentry *qdf_debugfs_root = qdf_debugfs_get_root(); + + if (!qdf_debugfs_root) + return QDF_STATUS_E_FAILURE; + + qdf_mem_debugfs_root = debugfs_create_dir("mem", qdf_debugfs_root); + + if (!qdf_mem_debugfs_root) + return QDF_STATUS_E_FAILURE; + + debugfs_create_file("list", + S_IRUSR | S_IWUSR, + qdf_mem_debugfs_root, + NULL, + &fops_qdf_mem_debugfs); + + debugfs_create_atomic_t("kmalloc", + S_IRUSR | S_IWUSR, + qdf_mem_debugfs_root, + &qdf_mem_stat.kmalloc); + + debugfs_create_atomic_t("dma", + S_IRUSR | S_IWUSR, + qdf_mem_debugfs_root, + &qdf_mem_stat.dma); + + return QDF_STATUS_SUCCESS; +} + + +/** + * qdf_mem_debugfs_exit() - cleanup routine + * + * Return: None + */ +static void qdf_mem_debugfs_exit(void) +{ + debugfs_remove_recursive(qdf_mem_debugfs_root); + qdf_mem_debugfs_root = NULL; +} + +#else /* WLAN_DEBUGFS && MEMORY_DEBUG */ + +static inline void qdf_mem_kmalloc_inc(qdf_size_t size) {} +static inline void qdf_mem_dma_inc(qdf_size_t size) {} +static inline void qdf_mem_kmalloc_dec(qdf_size_t size) {} +static inline void qdf_mem_dma_dec(qdf_size_t size) {} + +#ifdef MEMORY_DEBUG + +static QDF_STATUS qdf_mem_debugfs_init(void) +{ + return QDF_STATUS_E_NOSUPPORT; +} +static void qdf_mem_debugfs_exit(void) {} + +#endif + +#endif /* WLAN_DEBUGFS && MEMORY_DEBUG */ + +/** + * __qdf_mempool_init() - Create and initialize memory pool + * + * @osdev: platform device object + * @pool_addr: address of the pool created + * @elem_cnt: no. of elements in pool + * @elem_size: size of each pool element in bytes + * @flags: flags + * + * return: Handle to memory pool or NULL if allocation failed + */ +int __qdf_mempool_init(qdf_device_t osdev, __qdf_mempool_t *pool_addr, + int elem_cnt, size_t elem_size, u_int32_t flags) +{ + __qdf_mempool_ctxt_t *new_pool = NULL; + u_int32_t align = L1_CACHE_BYTES; + unsigned long aligned_pool_mem; + int pool_id; + int i; + + if (prealloc_disabled) { + /* TBD: We can maintain a list of pools in qdf_device_t + * to help debugging + * when pre-allocation is not enabled + */ + new_pool = (__qdf_mempool_ctxt_t *) + kmalloc(sizeof(__qdf_mempool_ctxt_t), GFP_KERNEL); + if (new_pool == NULL) + return QDF_STATUS_E_NOMEM; + + memset(new_pool, 0, sizeof(*new_pool)); + /* TBD: define flags for zeroing buffers etc */ + new_pool->flags = flags; + new_pool->elem_size = elem_size; + new_pool->max_elem = elem_cnt; + *pool_addr = new_pool; + return 0; + } + + for (pool_id = 0; pool_id < MAX_MEM_POOLS; pool_id++) { + if (osdev->mem_pool[pool_id] == NULL) + break; + } + + if (pool_id == MAX_MEM_POOLS) + return -ENOMEM; + + new_pool = osdev->mem_pool[pool_id] = (__qdf_mempool_ctxt_t *) + kmalloc(sizeof(__qdf_mempool_ctxt_t), GFP_KERNEL); + if (new_pool == NULL) + return -ENOMEM; + + memset(new_pool, 0, sizeof(*new_pool)); + /* TBD: define flags for zeroing buffers etc */ + new_pool->flags = flags; + new_pool->pool_id = pool_id; + + /* Round up the element size to cacheline */ + new_pool->elem_size = roundup(elem_size, L1_CACHE_BYTES); + new_pool->mem_size = elem_cnt * new_pool->elem_size + + ((align)?(align - 1):0); + + new_pool->pool_mem = kzalloc(new_pool->mem_size, GFP_KERNEL); + if (new_pool->pool_mem == NULL) { + /* TBD: Check if we need get_free_pages above */ + kfree(new_pool); + osdev->mem_pool[pool_id] = NULL; + return -ENOMEM; + } + + spin_lock_init(&new_pool->lock); + + /* Initialize free list */ + aligned_pool_mem = (unsigned long)(new_pool->pool_mem) + + ((align) ? (unsigned long)(new_pool->pool_mem)%align:0); + STAILQ_INIT(&new_pool->free_list); + + for (i = 0; i < elem_cnt; i++) + STAILQ_INSERT_TAIL(&(new_pool->free_list), + (mempool_elem_t *)(aligned_pool_mem + + (new_pool->elem_size * i)), mempool_entry); + + + new_pool->free_cnt = elem_cnt; + *pool_addr = new_pool; + return 0; +} +EXPORT_SYMBOL(__qdf_mempool_init); + +/** + * __qdf_mempool_destroy() - Destroy memory pool + * @osdev: platform device object + * @Handle: to memory pool + * + * Returns: none + */ +void __qdf_mempool_destroy(qdf_device_t osdev, __qdf_mempool_t pool) +{ + int pool_id = 0; + + if (!pool) + return; + + if (prealloc_disabled) { + kfree(pool); + return; + } + + pool_id = pool->pool_id; + + /* TBD: Check if free count matches elem_cnt if debug is enabled */ + kfree(pool->pool_mem); + kfree(pool); + osdev->mem_pool[pool_id] = NULL; +} +EXPORT_SYMBOL(__qdf_mempool_destroy); + +/** + * __qdf_mempool_alloc() - Allocate an element memory pool + * + * @osdev: platform device object + * @Handle: to memory pool + * + * Return: Pointer to the allocated element or NULL if the pool is empty + */ +void *__qdf_mempool_alloc(qdf_device_t osdev, __qdf_mempool_t pool) +{ + void *buf = NULL; + + if (!pool) + return NULL; + + if (prealloc_disabled) + return qdf_mem_malloc(pool->elem_size); + + spin_lock_bh(&pool->lock); + + buf = STAILQ_FIRST(&pool->free_list); + if (buf != NULL) { + STAILQ_REMOVE_HEAD(&pool->free_list, mempool_entry); + pool->free_cnt--; + } + + /* TBD: Update free count if debug is enabled */ + spin_unlock_bh(&pool->lock); + + return buf; +} +EXPORT_SYMBOL(__qdf_mempool_alloc); + +/** + * __qdf_mempool_free() - Free a memory pool element + * @osdev: Platform device object + * @pool: Handle to memory pool + * @buf: Element to be freed + * + * Returns: none + */ +void __qdf_mempool_free(qdf_device_t osdev, __qdf_mempool_t pool, void *buf) +{ + if (!pool) + return; + + + if (prealloc_disabled) + return qdf_mem_free(buf); + + spin_lock_bh(&pool->lock); + pool->free_cnt++; + + STAILQ_INSERT_TAIL + (&pool->free_list, (mempool_elem_t *)buf, mempool_entry); + spin_unlock_bh(&pool->lock); +} +EXPORT_SYMBOL(__qdf_mempool_free); + +/** + * qdf_mem_alloc_outline() - allocation QDF memory + * @osdev: platform device object + * @size: Number of bytes of memory to allocate. + * + * This function will dynamicallly allocate the specified number of bytes of + * memory. + * + * Return: + * Upon successful allocate, returns a non-NULL pointer to the allocated + * memory. If this function is unable to allocate the amount of memory + * specified (for any reason) it returns NULL. + */ +void * +qdf_mem_alloc_outline(qdf_device_t osdev, size_t size) +{ + return qdf_mem_malloc(size); +} +EXPORT_SYMBOL(qdf_mem_alloc_outline); + +/** + * qdf_mem_free_outline() - QDF memory free API + * @ptr: Pointer to the starting address of the memory to be free'd. + * + * This function will free the memory pointed to by 'ptr'. It also checks + * is memory is corrupted or getting double freed and panic. + * + * Return: none + */ +void +qdf_mem_free_outline(void *buf) +{ + qdf_mem_free(buf); +} +EXPORT_SYMBOL(qdf_mem_free_outline); + +/** + * qdf_mem_zero_outline() - zero out memory + * @buf: pointer to memory that will be set to zero + * @size: number of bytes zero + * + * This function sets the memory location to all zeros, essentially clearing + * the memory. + * + * Return: none + */ +void +qdf_mem_zero_outline(void *buf, qdf_size_t size) +{ + qdf_mem_zero(buf, size); +} +EXPORT_SYMBOL(qdf_mem_zero_outline); + +#ifdef CONFIG_WCNSS_MEM_PRE_ALLOC +/** + * qdf_mem_prealloc_get() - conditionally pre-allocate memory + * @size: the number of bytes to allocate + * + * If size if greater than WCNSS_PRE_ALLOC_GET_THRESHOLD, this function returns + * a chunk of pre-allocated memory. If size if less than or equal to + * WCNSS_PRE_ALLOC_GET_THRESHOLD, or an error occurs, NULL is returned instead. + * + * Return: NULL on failure, non-NULL on success + */ +static void *qdf_mem_prealloc_get(size_t size) +{ + void *mem; + + if (size <= WCNSS_PRE_ALLOC_GET_THRESHOLD) + return NULL; + + mem = wcnss_prealloc_get(size); + if (mem) + memset(mem, 0, size); + + return mem; +} + +static inline bool qdf_mem_prealloc_put(void *ptr) +{ + return wcnss_prealloc_put(ptr); +} +#else +static inline void *qdf_mem_prealloc_get(size_t size) +{ + return NULL; +} + +static inline bool qdf_mem_prealloc_put(void *ptr) +{ + return false; +} +#endif /* CONFIG_WCNSS_MEM_PRE_ALLOC */ + +/* External Function implementation */ +#ifdef MEMORY_DEBUG + +/** + * qdf_mem_init() - initialize qdf memory debug functionality + * + * Return: none + */ +void qdf_mem_init(void) +{ + /* Initalizing the list with maximum size of 60000 */ + qdf_list_create(&qdf_mem_list, 60000); + qdf_spinlock_create(&qdf_mem_list_lock); + qdf_net_buf_debug_init(); + qdf_mem_debugfs_init(); + return; +} +EXPORT_SYMBOL(qdf_mem_init); + +/** + * qdf_mem_clean() - display memory leak debug info and free leaked pointers + * + * Return: none + */ +void qdf_mem_clean(void) +{ + uint32_t list_size; + list_size = qdf_list_size(&qdf_mem_list); + if (list_size) { + qdf_list_node_t *node; + QDF_STATUS qdf_status; + + struct s_qdf_mem_struct *mem_struct; + char *prev_mleak_file = ""; + unsigned int prev_mleak_line_num = 0; + unsigned int prev_mleak_sz = 0; + unsigned int mleak_cnt = 0; + + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO, + "%s: List is not Empty. list_size %d ", + __func__, (int)list_size); + + do { + qdf_spin_lock(&qdf_mem_list_lock); + qdf_status = + qdf_list_remove_front(&qdf_mem_list, &node); + qdf_spin_unlock(&qdf_mem_list_lock); + if (QDF_STATUS_SUCCESS == qdf_status) { + mem_struct = (struct s_qdf_mem_struct *)node; + /* Take care to log only once multiple memory + leaks from the same place */ + if (strcmp(prev_mleak_file, + mem_struct->file_name) + || (prev_mleak_line_num != + mem_struct->line_num) + || (prev_mleak_sz != mem_struct->size)) { + if (mleak_cnt != 0) { + QDF_TRACE(QDF_MODULE_ID_QDF, + QDF_TRACE_LEVEL_FATAL, + "%d Time Memory Leak@ File %s, @Line %d, size %d", + mleak_cnt, + prev_mleak_file, + prev_mleak_line_num, + prev_mleak_sz); + } + prev_mleak_file = mem_struct->file_name; + prev_mleak_line_num = + mem_struct->line_num; + prev_mleak_sz = mem_struct->size; + mleak_cnt = 0; + } + mleak_cnt++; + kfree((void *)mem_struct); + } + } while (qdf_status == QDF_STATUS_SUCCESS); + + /* Print last memory leak from the module */ + if (mleak_cnt) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_FATAL, + "%d Time memory Leak@ File %s, @Line %d, size %d", + mleak_cnt, prev_mleak_file, + prev_mleak_line_num, prev_mleak_sz); + } +#ifdef CONFIG_HALT_KMEMLEAK + BUG_ON(0); +#endif + } +} +EXPORT_SYMBOL(qdf_mem_clean); + +/** + * qdf_mem_exit() - exit qdf memory debug functionality + * + * Return: none + */ +void qdf_mem_exit(void) +{ + qdf_mem_debugfs_exit(); + qdf_net_buf_debug_exit(); + qdf_mem_clean(); + qdf_list_destroy(&qdf_mem_list); +} +EXPORT_SYMBOL(qdf_mem_exit); + +/** + * qdf_mem_malloc_debug() - debug version of QDF memory allocation API + * @size: Number of bytes of memory to allocate. + * @file_name: File name from which memory allocation is called + * @line_num: Line number from which memory allocation is called + * + * This function will dynamicallly allocate the specified number of bytes of + * memory and ad it in qdf tracking list to check against memory leaks and + * corruptions + * + * Return: + * Upon successful allocate, returns a non-NULL pointer to the allocated + * memory. If this function is unable to allocate the amount of memory + * specified (for any reason) it returns %NULL. + */ +void *qdf_mem_malloc_debug(size_t size, + char *file_name, uint32_t line_num) +{ + struct s_qdf_mem_struct *mem_struct; + void *mem_ptr = NULL; + uint32_t new_size; + int flags = GFP_KERNEL; + unsigned long time_before_kzalloc; + + if (size > (1024 * 1024) || size == 0) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: called with invalid arg; passed in %zu !!!", + __func__, size); + return NULL; + } + + mem_ptr = qdf_mem_prealloc_get(size); + if (mem_ptr) + return mem_ptr; + + if (in_interrupt() || irqs_disabled() || in_atomic()) + flags = GFP_ATOMIC; + + new_size = size + sizeof(struct s_qdf_mem_struct) + 8;/*TBD: what is 8*/ + time_before_kzalloc = qdf_mc_timer_get_system_time(); + mem_struct = (struct s_qdf_mem_struct *)kzalloc(new_size, flags); + /** + * If time taken by kmalloc is greater than + * QDF_GET_MEMORY_TIME_THRESHOLD msec + */ + if (qdf_mc_timer_get_system_time() - time_before_kzalloc >= + QDF_GET_MEMORY_TIME_THRESHOLD) + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: kzalloc took %lu msec for size %zu called from %p_s at line %d", + __func__, + qdf_mc_timer_get_system_time() - time_before_kzalloc, + size, (void *)_RET_IP_, line_num); + + if (mem_struct != NULL) { + QDF_STATUS qdf_status; + + mem_struct->file_name = file_name; + mem_struct->line_num = line_num; + mem_struct->size = size; + qdf_atomic_inc(&mem_struct->in_use); + qdf_mem_kmalloc_inc(size); + + qdf_mem_copy(&mem_struct->header[0], + &WLAN_MEM_HEADER[0], sizeof(WLAN_MEM_HEADER)); + + qdf_mem_copy((uint8_t *) (mem_struct + 1) + size, + &WLAN_MEM_TAIL[0], sizeof(WLAN_MEM_TAIL)); + + qdf_spin_lock_irqsave(&qdf_mem_list_lock); + qdf_status = qdf_list_insert_front(&qdf_mem_list, + &mem_struct->node); + qdf_spin_unlock_irqrestore(&qdf_mem_list_lock); + if (QDF_STATUS_SUCCESS != qdf_status) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: Unable to insert node into List qdf_status %d", + __func__, qdf_status); + } + + mem_ptr = (void *)(mem_struct + 1); + } + + if (!mem_ptr) + host_log_low_resource_failure(WIFI_EVENT_MEMORY_FAILURE); + + return mem_ptr; +} +EXPORT_SYMBOL(qdf_mem_malloc_debug); + +/** + * qdf_mem_validate_node_for_free() - validate that the node is in a list + * @qdf_node: node to check for being in a list + * + * qdf_node should be a non null value. + * + * Return: true if the node validly linked in an anchored doubly linked list + */ +static bool qdf_mem_validate_node_for_free(qdf_list_node_t *qdf_node) +{ + struct list_head *node = qdf_node; + + /* + * if the node is an empty list, it is not tied to an anchor node + * and must have been removed with list_del_init + */ + if (list_empty(node)) + return false; + + if (node->prev == NULL) + return false; + + if (node->next == NULL) + return false; + + if (node->prev->next != node) + return false; + + if (node->next->prev != node) + return false; + + return true; +} + + + +/** + * qdf_mem_free() - QDF memory free API + * @ptr: Pointer to the starting address of the memory to be free'd. + * + * This function will free the memory pointed to by 'ptr'. It also checks + * is memory is corrupted or getting double freed and panic. + * + * Return: none + */ +void qdf_mem_free(void *ptr) +{ + struct s_qdf_mem_struct *mem_struct; + + /* freeing a null pointer is valid */ + if (qdf_unlikely(ptr == NULL)) + return; + + mem_struct = ((struct s_qdf_mem_struct *)ptr) - 1; + + if (qdf_unlikely(mem_struct == NULL)) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_FATAL, + "%s: null mem_struct", __func__); + QDF_BUG(0); + } + + if (qdf_mem_prealloc_put(ptr)) + return; + + if (!qdf_atomic_dec_and_test(&mem_struct->in_use)) + return; + + qdf_spin_lock_irqsave(&qdf_mem_list_lock); + + /* + * invalid memory access when checking the header/tailer + * would be a use after free and would indicate a double free + * or invalid pointer passed. + */ + if (qdf_mem_cmp(mem_struct->header, &WLAN_MEM_HEADER[0], + sizeof(WLAN_MEM_HEADER))) + goto error; + + /* + * invalid memory access while checking validate node + * would indicate corruption in the nodes pointed to + */ + if (!qdf_mem_validate_node_for_free(&mem_struct->node)) + goto error; + + /* + * invalid memory access here is unlikely and would imply + * that the size value was corrupted/incorrect. + * It is unlikely that the above checks would pass in a + * double free case. + */ + if (qdf_mem_cmp((uint8_t *) ptr + mem_struct->size, + &WLAN_MEM_TAIL[0], sizeof(WLAN_MEM_TAIL))) + goto error; + + /* + * make the node an empty list before doing the spin unlock + * The empty list check will guarantee that we avoid a race condition. + */ + list_del_init(&mem_struct->node); + qdf_mem_list.count--; + qdf_spin_unlock_irqrestore(&qdf_mem_list_lock); + qdf_mem_kmalloc_dec(mem_struct->size); + kfree(mem_struct); + return; + +error: + if (!qdf_list_has_node(&qdf_mem_list, &mem_struct->node)) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_FATAL, + "%s: Unallocated memory (double free?)", + __func__); + qdf_spin_unlock_irqrestore(&qdf_mem_list_lock); + QDF_BUG(0); + } + + if (qdf_mem_cmp(mem_struct->header, &WLAN_MEM_HEADER[0], + sizeof(WLAN_MEM_HEADER))) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_FATAL, + "Memory Header is corrupted."); + qdf_spin_unlock_irqrestore(&qdf_mem_list_lock); + QDF_BUG(0); + } + + if (!qdf_mem_validate_node_for_free(&mem_struct->node)) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_FATAL, + "Memory_struct is corrupted."); + qdf_spin_unlock_irqrestore(&qdf_mem_list_lock); + QDF_BUG(0); + } + + if (qdf_mem_cmp((uint8_t *) ptr + mem_struct->size, + &WLAN_MEM_TAIL[0], sizeof(WLAN_MEM_TAIL))) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_FATAL, + "Memory Trailer is corrupted. mem_info: Filename %s, line_num %d", + mem_struct->file_name, (int)mem_struct->line_num); + qdf_spin_unlock_irqrestore(&qdf_mem_list_lock); + QDF_BUG(0); + } + + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_FATAL, + "%s unexpected error", __func__); + qdf_spin_unlock_irqrestore(&qdf_mem_list_lock); + QDF_BUG(0); +} +EXPORT_SYMBOL(qdf_mem_free); +#else + +/** + * qdf_mem_malloc() - allocation QDF memory + * @size: Number of bytes of memory to allocate. + * + * This function will dynamicallly allocate the specified number of bytes of + * memory. + * + * Return: + * Upon successful allocate, returns a non-NULL pointer to the allocated + * memory. If this function is unable to allocate the amount of memory + * specified (for any reason) it returns NULL. + */ +void *qdf_mem_malloc(size_t size) +{ + int flags = GFP_KERNEL; + void *mem; + + mem = qdf_mem_prealloc_get(size); + if (mem) + return mem; + + if (in_interrupt() || irqs_disabled()) + flags = GFP_ATOMIC; + + return kzalloc(size, flags); +} +EXPORT_SYMBOL(qdf_mem_malloc); + +/** + * qdf_mem_free() - free QDF memory + * @ptr: Pointer to the starting address of the memory to be free'd. + * + * This function will free the memory pointed to by 'ptr'. + * + * Return: None + */ +void qdf_mem_free(void *ptr) +{ + if (ptr == NULL) + return; + + if (qdf_mem_prealloc_put(ptr)) + return; + + kfree(ptr); +} +EXPORT_SYMBOL(qdf_mem_free); +#endif + +/** + * qdf_mem_multi_pages_alloc() - allocate large size of kernel memory + * @osdev: OS device handle pointer + * @pages: Multi page information storage + * @element_size: Each element size + * @element_num: Total number of elements should be allocated + * @memctxt: Memory context + * @cacheable: Coherent memory or cacheable memory + * + * This function will allocate large size of memory over multiple pages. + * Large size of contiguous memory allocation will fail frequently, then + * instead of allocate large memory by one shot, allocate through multiple, non + * contiguous memory and combine pages when actual usage + * + * Return: None + */ +void qdf_mem_multi_pages_alloc(qdf_device_t osdev, + struct qdf_mem_multi_page_t *pages, + size_t element_size, uint16_t element_num, + qdf_dma_context_t memctxt, bool cacheable) +{ + uint16_t page_idx; + struct qdf_mem_dma_page_t *dma_pages; + void **cacheable_pages = NULL; + uint16_t i; + + pages->num_element_per_page = PAGE_SIZE / element_size; + if (!pages->num_element_per_page) { + qdf_print("Invalid page %d or element size %d", + (int)PAGE_SIZE, (int)element_size); + goto out_fail; + } + + pages->num_pages = element_num / pages->num_element_per_page; + if (element_num % pages->num_element_per_page) + pages->num_pages++; + + if (cacheable) { + /* Pages information storage */ + pages->cacheable_pages = qdf_mem_malloc( + pages->num_pages * sizeof(pages->cacheable_pages)); + if (!pages->cacheable_pages) { + qdf_print("Cacheable page storage alloc fail"); + goto out_fail; + } + + cacheable_pages = pages->cacheable_pages; + for (page_idx = 0; page_idx < pages->num_pages; page_idx++) { + cacheable_pages[page_idx] = qdf_mem_malloc(PAGE_SIZE); + if (!cacheable_pages[page_idx]) { + qdf_print("cacheable page alloc fail, pi %d", + page_idx); + goto page_alloc_fail; + } + } + pages->dma_pages = NULL; + } else { + pages->dma_pages = qdf_mem_malloc( + pages->num_pages * sizeof(struct qdf_mem_dma_page_t)); + if (!pages->dma_pages) { + qdf_print("dmaable page storage alloc fail"); + goto out_fail; + } + + dma_pages = pages->dma_pages; + for (page_idx = 0; page_idx < pages->num_pages; page_idx++) { + dma_pages->page_v_addr_start = + qdf_mem_alloc_consistent(osdev, osdev->dev, + PAGE_SIZE, + &dma_pages->page_p_addr); + if (!dma_pages->page_v_addr_start) { + qdf_print("dmaable page alloc fail pi %d", + page_idx); + goto page_alloc_fail; + } + dma_pages->page_v_addr_end = + dma_pages->page_v_addr_start + PAGE_SIZE; + dma_pages++; + } + pages->cacheable_pages = NULL; + } + return; + +page_alloc_fail: + if (cacheable) { + for (i = 0; i < page_idx; i++) + qdf_mem_free(pages->cacheable_pages[i]); + qdf_mem_free(pages->cacheable_pages); + } else { + dma_pages = pages->dma_pages; + for (i = 0; i < page_idx; i++) { + qdf_mem_free_consistent(osdev, osdev->dev, PAGE_SIZE, + dma_pages->page_v_addr_start, + dma_pages->page_p_addr, memctxt); + dma_pages++; + } + qdf_mem_free(pages->dma_pages); + } + +out_fail: + pages->cacheable_pages = NULL; + pages->dma_pages = NULL; + pages->num_pages = 0; + return; +} +EXPORT_SYMBOL(qdf_mem_multi_pages_alloc); + +/** + * qdf_mem_multi_pages_free() - free large size of kernel memory + * @osdev: OS device handle pointer + * @pages: Multi page information storage + * @memctxt: Memory context + * @cacheable: Coherent memory or cacheable memory + * + * This function will free large size of memory over multiple pages. + * + * Return: None + */ +void qdf_mem_multi_pages_free(qdf_device_t osdev, + struct qdf_mem_multi_page_t *pages, + qdf_dma_context_t memctxt, bool cacheable) +{ + unsigned int page_idx; + struct qdf_mem_dma_page_t *dma_pages; + + if (cacheable) { + for (page_idx = 0; page_idx < pages->num_pages; page_idx++) + qdf_mem_free(pages->cacheable_pages[page_idx]); + qdf_mem_free(pages->cacheable_pages); + } else { + dma_pages = pages->dma_pages; + for (page_idx = 0; page_idx < pages->num_pages; page_idx++) { + qdf_mem_free_consistent(osdev, osdev->dev, PAGE_SIZE, + dma_pages->page_v_addr_start, + dma_pages->page_p_addr, memctxt); + dma_pages++; + } + qdf_mem_free(pages->dma_pages); + } + + pages->cacheable_pages = NULL; + pages->dma_pages = NULL; + pages->num_pages = 0; + return; +} +EXPORT_SYMBOL(qdf_mem_multi_pages_free); + +/** + * qdf_mem_copy() - copy memory + * @dst_addr: Pointer to destination memory location (to copy to) + * @src_addr: Pointer to source memory location (to copy from) + * @num_bytes: Number of bytes to copy. + * + * Copy host memory from one location to another, similar to memcpy in + * standard C. Note this function does not specifically handle overlapping + * source and destination memory locations. Calling this function with + * overlapping source and destination memory locations will result in + * unpredictable results. Use qdf_mem_move() if the memory locations + * for the source and destination are overlapping (or could be overlapping!) + * + * Return: none + */ +void qdf_mem_copy(void *dst_addr, const void *src_addr, uint32_t num_bytes) +{ + if (0 == num_bytes) { + /* special case where dst_addr or src_addr can be NULL */ + return; + } + + if ((dst_addr == NULL) || (src_addr == NULL)) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s called with NULL parameter, source:%p destination:%p", + __func__, src_addr, dst_addr); + QDF_ASSERT(0); + return; + } + memcpy(dst_addr, src_addr, num_bytes); +} +EXPORT_SYMBOL(qdf_mem_copy); + +/** + * qdf_mem_zero() - zero out memory + * @ptr: pointer to memory that will be set to zero + * @num_bytes: number of bytes zero + * + * This function sets the memory location to all zeros, essentially clearing + * the memory. + * + * Return: None + */ +void qdf_mem_zero(void *ptr, uint32_t num_bytes) +{ + if (0 == num_bytes) { + /* special case where ptr can be NULL */ + return; + } + + if (ptr == NULL) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s called with NULL parameter ptr", __func__); + return; + } + memset(ptr, 0, num_bytes); +} +EXPORT_SYMBOL(qdf_mem_zero); + +/** + * qdf_mem_set() - set (fill) memory with a specified byte value. + * @ptr: Pointer to memory that will be set + * @num_bytes: Number of bytes to be set + * @value: Byte set in memory + * + * Return: None + */ +void qdf_mem_set(void *ptr, uint32_t num_bytes, uint32_t value) +{ + if (ptr == NULL) { + qdf_print("%s called with NULL parameter ptr", __func__); + return; + } + memset(ptr, value, num_bytes); +} +EXPORT_SYMBOL(qdf_mem_set); + +/** + * qdf_mem_move() - move memory + * @dst_addr: pointer to destination memory location (to move to) + * @src_addr: pointer to source memory location (to move from) + * @num_bytes: number of bytes to move. + * + * Move host memory from one location to another, similar to memmove in + * standard C. Note this function *does* handle overlapping + * source and destination memory locations. + + * Return: None + */ +void qdf_mem_move(void *dst_addr, const void *src_addr, uint32_t num_bytes) +{ + if (0 == num_bytes) { + /* special case where dst_addr or src_addr can be NULL */ + return; + } + + if ((dst_addr == NULL) || (src_addr == NULL)) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s called with NULL parameter, source:%p destination:%p", + __func__, src_addr, dst_addr); + QDF_ASSERT(0); + return; + } + memmove(dst_addr, src_addr, num_bytes); +} +EXPORT_SYMBOL(qdf_mem_move); + +#if defined(A_SIMOS_DEVHOST) || defined(HIF_SDIO) || defined(HIF_USB) +/** + * qdf_mem_alloc_consistent() - allocates consistent qdf memory + * @osdev: OS device handle + * @dev: Pointer to device handle + * @size: Size to be allocated + * @phy_addr: Physical address + * + * Return: pointer of allocated memory or null if memory alloc fails + */ +void *qdf_mem_alloc_consistent(qdf_device_t osdev, void *dev, qdf_size_t size, + qdf_dma_addr_t *phy_addr) +{ + void *vaddr; + + vaddr = qdf_mem_malloc(size); + *phy_addr = ((uintptr_t) vaddr); + /* using this type conversion to suppress "cast from pointer to integer + * of different size" warning on some platforms + */ + BUILD_BUG_ON(sizeof(*phy_addr) < sizeof(vaddr)); + return vaddr; +} + +#else +void *qdf_mem_alloc_consistent(qdf_device_t osdev, void *dev, qdf_size_t size, + qdf_dma_addr_t *phy_addr) +{ + int flags = GFP_KERNEL; + void *alloc_mem = NULL; + + if (in_interrupt() || irqs_disabled() || in_atomic()) + flags = GFP_ATOMIC; + + alloc_mem = dma_alloc_coherent(dev, size, phy_addr, flags); + if (alloc_mem == NULL) + qdf_print("%s Warning: unable to alloc consistent memory of size %zu!\n", + __func__, size); + qdf_mem_dma_inc(size); + return alloc_mem; +} + +#endif +EXPORT_SYMBOL(qdf_mem_alloc_consistent); + +#if defined(A_SIMOS_DEVHOST) || defined(HIF_SDIO) || defined(HIF_USB) +/** + * qdf_mem_free_consistent() - free consistent qdf memory + * @osdev: OS device handle + * @size: Size to be allocated + * @vaddr: virtual address + * @phy_addr: Physical address + * @mctx: Pointer to DMA context + * + * Return: none + */ +inline void qdf_mem_free_consistent(qdf_device_t osdev, void *dev, + qdf_size_t size, void *vaddr, + qdf_dma_addr_t phy_addr, + qdf_dma_context_t memctx) +{ + qdf_mem_free(vaddr); + return; +} + +#else +inline void qdf_mem_free_consistent(qdf_device_t osdev, void *dev, + qdf_size_t size, void *vaddr, + qdf_dma_addr_t phy_addr, + qdf_dma_context_t memctx) +{ + dma_free_coherent(dev, size, vaddr, phy_addr); + qdf_mem_dma_dec(size); +} + +#endif +EXPORT_SYMBOL(qdf_mem_free_consistent); + +/** + * qdf_mem_dma_sync_single_for_device() - assign memory to device + * @osdev: OS device handle + * @bus_addr: dma address to give to the device + * @size: Size of the memory block + * @direction: direction data will be DMAed + * + * Assign memory to the remote device. + * The cache lines are flushed to ram or invalidated as needed. + * + * Return: none + */ +void qdf_mem_dma_sync_single_for_device(qdf_device_t osdev, + qdf_dma_addr_t bus_addr, + qdf_size_t size, + enum dma_data_direction direction) +{ + dma_sync_single_for_device(osdev->dev, bus_addr, size, direction); +} +EXPORT_SYMBOL(qdf_mem_dma_sync_single_for_device); + +/** + * qdf_mem_dma_sync_single_for_cpu() - assign memory to CPU + * @osdev: OS device handle + * @bus_addr: dma address to give to the cpu + * @size: Size of the memory block + * @direction: direction data will be DMAed + * + * Assign memory to the CPU. + * + * Return: none + */ +void qdf_mem_dma_sync_single_for_cpu(qdf_device_t osdev, + qdf_dma_addr_t bus_addr, + qdf_size_t size, + enum dma_data_direction direction) +{ + dma_sync_single_for_cpu(osdev->dev, bus_addr, size, direction); +} +EXPORT_SYMBOL(qdf_mem_dma_sync_single_for_cpu); diff --git a/drivers/staging/qca-wifi-host-cmn/qdf/linux/src/qdf_module.c b/drivers/staging/qca-wifi-host-cmn/qdf/linux/src/qdf_module.c new file mode 100644 index 0000000000000000000000000000000000000000..98770cd7bf33f741d3b53c0caa57f859821fc886 --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/qdf/linux/src/qdf_module.c @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: i_qdf_module.h + * Linux-specific definitions for QDF module API's + */ + +#include +#include + +MODULE_AUTHOR("Qualcomm Atheros Inc."); +MODULE_DESCRIPTION("Qualcomm Atheros Device Framework Module"); +MODULE_LICENSE("Dual BSD/GPL"); + +#ifndef EXPORT_SYMTAB +#define EXPORT_SYMTAB +#endif + +/** + * qdf_mod_init() - module initialization + * + * Return: int + */ +static int __init +qdf_mod_init(void) +{ + qdf_perfmod_init(); + return 0; +} +module_init(qdf_mod_init); + +/** + * qdf_mod_exit() - module remove + * + * Return: int + */ +static void __exit +qdf_mod_exit(void) +{ + qdf_perfmod_exit(); +} +module_exit(qdf_mod_exit); diff --git a/drivers/staging/qca-wifi-host-cmn/qdf/linux/src/qdf_nbuf.c b/drivers/staging/qca-wifi-host-cmn/qdf/linux/src/qdf_nbuf.c new file mode 100644 index 0000000000000000000000000000000000000000..c5e34fd5ebca96c4ca090205802364d6ae47bbf0 --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/qdf/linux/src/qdf_nbuf.c @@ -0,0 +1,2704 @@ +/* + * Copyright (c) 2014-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: qdf_nbuf.c + * QCA driver framework(QDF) network buffer management APIs + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(FEATURE_TSO) +#include +#include +#include +#include +#include +#endif /* FEATURE_TSO */ + +/* Packet Counter */ +static uint32_t nbuf_tx_mgmt[QDF_NBUF_TX_PKT_STATE_MAX]; +static uint32_t nbuf_tx_data[QDF_NBUF_TX_PKT_STATE_MAX]; + +/** + * qdf_nbuf_tx_desc_count_display() - Displays the packet counter + * + * Return: none + */ +void qdf_nbuf_tx_desc_count_display(void) +{ + qdf_print("Current Snapshot of the Driver:\n"); + qdf_print("Data Packets:\n"); + qdf_print("HDD %d TXRX_Q %d TXRX %d HTT %d", + nbuf_tx_data[QDF_NBUF_TX_PKT_HDD] - + (nbuf_tx_data[QDF_NBUF_TX_PKT_TXRX] + + nbuf_tx_data[QDF_NBUF_TX_PKT_TXRX_ENQUEUE] - + nbuf_tx_data[QDF_NBUF_TX_PKT_TXRX_DEQUEUE]), + nbuf_tx_data[QDF_NBUF_TX_PKT_TXRX_ENQUEUE] - + nbuf_tx_data[QDF_NBUF_TX_PKT_TXRX_DEQUEUE], + nbuf_tx_data[QDF_NBUF_TX_PKT_TXRX] - + nbuf_tx_data[QDF_NBUF_TX_PKT_HTT], + nbuf_tx_data[QDF_NBUF_TX_PKT_HTT] - + nbuf_tx_data[QDF_NBUF_TX_PKT_HTC]); + qdf_print(" HTC %d HIF %d CE %d TX_COMP %d\n", + nbuf_tx_data[QDF_NBUF_TX_PKT_HTC] - + nbuf_tx_data[QDF_NBUF_TX_PKT_HIF], + nbuf_tx_data[QDF_NBUF_TX_PKT_HIF] - + nbuf_tx_data[QDF_NBUF_TX_PKT_CE], + nbuf_tx_data[QDF_NBUF_TX_PKT_CE] - + nbuf_tx_data[QDF_NBUF_TX_PKT_FREE], + nbuf_tx_data[QDF_NBUF_TX_PKT_FREE]); + qdf_print("Mgmt Packets:\n"); + qdf_print("TXRX_Q %d TXRX %d HTT %d HTC %d HIF %d CE %d TX_COMP %d\n", + nbuf_tx_mgmt[QDF_NBUF_TX_PKT_TXRX_ENQUEUE] - + nbuf_tx_mgmt[QDF_NBUF_TX_PKT_TXRX_DEQUEUE], + nbuf_tx_mgmt[QDF_NBUF_TX_PKT_TXRX] - + nbuf_tx_mgmt[QDF_NBUF_TX_PKT_HTT], + nbuf_tx_mgmt[QDF_NBUF_TX_PKT_HTT] - + nbuf_tx_mgmt[QDF_NBUF_TX_PKT_HTC], + nbuf_tx_mgmt[QDF_NBUF_TX_PKT_HTC] - + nbuf_tx_mgmt[QDF_NBUF_TX_PKT_HIF], + nbuf_tx_mgmt[QDF_NBUF_TX_PKT_HIF] - + nbuf_tx_mgmt[QDF_NBUF_TX_PKT_CE], + nbuf_tx_mgmt[QDF_NBUF_TX_PKT_CE] - + nbuf_tx_mgmt[QDF_NBUF_TX_PKT_FREE], + nbuf_tx_mgmt[QDF_NBUF_TX_PKT_FREE]); +} +EXPORT_SYMBOL(qdf_nbuf_tx_desc_count_display); + +/** + * qdf_nbuf_tx_desc_count_update() - Updates the layer packet counter + * @packet_type : packet type either mgmt/data + * @current_state : layer at which the packet currently present + * + * Return: none + */ +static inline void qdf_nbuf_tx_desc_count_update(uint8_t packet_type, + uint8_t current_state) +{ + switch (packet_type) { + case QDF_NBUF_TX_PKT_MGMT_TRACK: + nbuf_tx_mgmt[current_state]++; + break; + case QDF_NBUF_TX_PKT_DATA_TRACK: + nbuf_tx_data[current_state]++; + break; + default: + break; + } +} +EXPORT_SYMBOL(qdf_nbuf_tx_desc_count_update); + +/** + * qdf_nbuf_tx_desc_count_clear() - Clears packet counter for both data, mgmt + * + * Return: none + */ +void qdf_nbuf_tx_desc_count_clear(void) +{ + memset(nbuf_tx_mgmt, 0, sizeof(nbuf_tx_mgmt)); + memset(nbuf_tx_data, 0, sizeof(nbuf_tx_data)); +} +EXPORT_SYMBOL(qdf_nbuf_tx_desc_count_clear); + +/** + * qdf_nbuf_set_state() - Updates the packet state + * @nbuf: network buffer + * @current_state : layer at which the packet currently is + * + * This function updates the packet state to the layer at which the packet + * currently is + * + * Return: none + */ +void qdf_nbuf_set_state(qdf_nbuf_t nbuf, uint8_t current_state) +{ + /* + * Only Mgmt, Data Packets are tracked. WMI messages + * such as scan commands are not tracked + */ + uint8_t packet_type; + packet_type = QDF_NBUF_CB_TX_PACKET_TRACK(nbuf); + + if ((packet_type != QDF_NBUF_TX_PKT_DATA_TRACK) && + (packet_type != QDF_NBUF_TX_PKT_MGMT_TRACK)) { + return; + } + QDF_NBUF_CB_TX_PACKET_STATE(nbuf) = current_state; + qdf_nbuf_tx_desc_count_update(packet_type, + current_state); +} +EXPORT_SYMBOL(qdf_nbuf_set_state); + +/* globals do not need to be initialized to NULL/0 */ +qdf_nbuf_trace_update_t qdf_trace_update_cb; +qdf_nbuf_free_t nbuf_free_cb; + +/** + * __qdf_nbuf_alloc() - Allocate nbuf + * @hdl: Device handle + * @size: Netbuf requested size + * @reserve: headroom to start with + * @align: Align + * @prio: Priority + * + * This allocates an nbuf aligns if needed and reserves some space in the front, + * since the reserve is done after alignment the reserve value if being + * unaligned will result in an unaligned address. + * + * Return: nbuf or %NULL if no memory + */ +struct sk_buff *__qdf_nbuf_alloc(qdf_device_t osdev, size_t size, int reserve, + int align, int prio) +{ + struct sk_buff *skb; + unsigned long offset; + + if (align) + size += (align - 1); + + skb = dev_alloc_skb(size); + + if (!skb) { + pr_info("ERROR:NBUF alloc failed\n"); + return NULL; + } + memset(skb->cb, 0x0, sizeof(skb->cb)); + + /* + * The default is for netbuf fragments to be interpreted + * as wordstreams rather than bytestreams. + */ + QDF_NBUF_CB_TX_EXTRA_FRAG_WORDSTR_EFRAG(skb) = 1; + QDF_NBUF_CB_TX_EXTRA_FRAG_WORDSTR_NBUF(skb) = 1; + + /* + * XXX:how about we reserve first then align + * Align & make sure that the tail & data are adjusted properly + */ + + if (align) { + offset = ((unsigned long)skb->data) % align; + if (offset) + skb_reserve(skb, align - offset); + } + + /* + * NOTE:alloc doesn't take responsibility if reserve unaligns the data + * pointer + */ + skb_reserve(skb, reserve); + + return skb; +} +EXPORT_SYMBOL(__qdf_nbuf_alloc); + +/** + * __qdf_nbuf_free() - free the nbuf its interrupt safe + * @skb: Pointer to network buffer + * + * Return: none + */ +void __qdf_nbuf_free(struct sk_buff *skb) +{ + if (nbuf_free_cb) + nbuf_free_cb(skb); + else + dev_kfree_skb_any(skb); +} +EXPORT_SYMBOL(__qdf_nbuf_free); + +/** + * __qdf_nbuf_map() - map a buffer to local bus address space + * @osdev: OS device + * @bmap: Bitmap + * @skb: Pointer to network buffer + * @dir: Direction + * + * Return: QDF_STATUS + */ +#ifdef QDF_OS_DEBUG +QDF_STATUS +__qdf_nbuf_map(qdf_device_t osdev, struct sk_buff *skb, qdf_dma_dir_t dir) +{ + struct skb_shared_info *sh = skb_shinfo(skb); + qdf_assert((dir == QDF_DMA_TO_DEVICE) + || (dir == QDF_DMA_FROM_DEVICE)); + + /* + * Assume there's only a single fragment. + * To support multiple fragments, it would be necessary to change + * qdf_nbuf_t to be a separate object that stores meta-info + * (including the bus address for each fragment) and a pointer + * to the underlying sk_buff. + */ + qdf_assert(sh->nr_frags == 0); + + return __qdf_nbuf_map_single(osdev, skb, dir); +} +EXPORT_SYMBOL(__qdf_nbuf_map); + +#else +QDF_STATUS +__qdf_nbuf_map(qdf_device_t osdev, struct sk_buff *skb, qdf_dma_dir_t dir) +{ + return __qdf_nbuf_map_single(osdev, skb, dir); +} +EXPORT_SYMBOL(__qdf_nbuf_map); +#endif +/** + * __qdf_nbuf_unmap() - to unmap a previously mapped buf + * @osdev: OS device + * @skb: Pointer to network buffer + * @dir: dma direction + * + * Return: none + */ +void +__qdf_nbuf_unmap(qdf_device_t osdev, struct sk_buff *skb, + qdf_dma_dir_t dir) +{ + qdf_assert((dir == QDF_DMA_TO_DEVICE) + || (dir == QDF_DMA_FROM_DEVICE)); + + /* + * Assume there's a single fragment. + * If this is not true, the assertion in __qdf_nbuf_map will catch it. + */ + __qdf_nbuf_unmap_single(osdev, skb, dir); +} +EXPORT_SYMBOL(__qdf_nbuf_unmap); + +/** + * __qdf_nbuf_map_single() - map a single buffer to local bus address space + * @osdev: OS device + * @skb: Pointer to network buffer + * @dir: Direction + * + * Return: QDF_STATUS + */ +#if defined(A_SIMOS_DEVHOST) || defined (HIF_USB) +QDF_STATUS +__qdf_nbuf_map_single(qdf_device_t osdev, qdf_nbuf_t buf, qdf_dma_dir_t dir) +{ + qdf_dma_addr_t paddr; + + QDF_NBUF_CB_PADDR(buf) = paddr = (uintptr_t)buf->data; + BUILD_BUG_ON(sizeof(paddr) < sizeof(buf->data)); + BUILD_BUG_ON(sizeof(QDF_NBUF_CB_PADDR(buf)) < sizeof(buf->data)); + return QDF_STATUS_SUCCESS; +} +EXPORT_SYMBOL(__qdf_nbuf_map_single); +#else +QDF_STATUS +__qdf_nbuf_map_single(qdf_device_t osdev, qdf_nbuf_t buf, qdf_dma_dir_t dir) +{ + qdf_dma_addr_t paddr; + + /* assume that the OS only provides a single fragment */ + QDF_NBUF_CB_PADDR(buf) = paddr = + dma_map_single(osdev->dev, buf->data, + skb_end_pointer(buf) - buf->data, dir); + return dma_mapping_error(osdev->dev, paddr) + ? QDF_STATUS_E_FAILURE + : QDF_STATUS_SUCCESS; +} +EXPORT_SYMBOL(__qdf_nbuf_map_single); +#endif +/** + * __qdf_nbuf_unmap_single() - unmap a previously mapped buf + * @osdev: OS device + * @skb: Pointer to network buffer + * @dir: Direction + * + * Return: none + */ +#if defined(A_SIMOS_DEVHOST) || defined (HIF_USB) +void __qdf_nbuf_unmap_single(qdf_device_t osdev, qdf_nbuf_t buf, + qdf_dma_dir_t dir) +{ + return; +} +#else +void __qdf_nbuf_unmap_single(qdf_device_t osdev, qdf_nbuf_t buf, + qdf_dma_dir_t dir) +{ + if (QDF_NBUF_CB_PADDR(buf)) + dma_unmap_single(osdev->dev, QDF_NBUF_CB_PADDR(buf), + skb_end_pointer(buf) - buf->data, dir); +} +#endif +EXPORT_SYMBOL(__qdf_nbuf_unmap_single); + +/** + * __qdf_nbuf_set_rx_cksum() - set rx checksum + * @skb: Pointer to network buffer + * @cksum: Pointer to checksum value + * + * Return: QDF_STATUS + */ +QDF_STATUS +__qdf_nbuf_set_rx_cksum(struct sk_buff *skb, qdf_nbuf_rx_cksum_t *cksum) +{ + switch (cksum->l4_result) { + case QDF_NBUF_RX_CKSUM_NONE: + skb->ip_summed = CHECKSUM_NONE; + break; + case QDF_NBUF_RX_CKSUM_TCP_UDP_UNNECESSARY: + skb->ip_summed = CHECKSUM_UNNECESSARY; + break; + case QDF_NBUF_RX_CKSUM_TCP_UDP_HW: + skb->ip_summed = CHECKSUM_PARTIAL; + skb->csum = cksum->val; + break; + default: + pr_err("Unknown checksum type\n"); + qdf_assert(0); + return QDF_STATUS_E_NOSUPPORT; + } + return QDF_STATUS_SUCCESS; +} +EXPORT_SYMBOL(__qdf_nbuf_set_rx_cksum); + +/** + * __qdf_nbuf_get_tx_cksum() - get tx checksum + * @skb: Pointer to network buffer + * + * Return: TX checksum value + */ +qdf_nbuf_tx_cksum_t __qdf_nbuf_get_tx_cksum(struct sk_buff *skb) +{ + switch (skb->ip_summed) { + case CHECKSUM_NONE: + return QDF_NBUF_TX_CKSUM_NONE; + case CHECKSUM_PARTIAL: + /* XXX ADF and Linux checksum don't map with 1-to-1. This is + * not 100% correct */ + return QDF_NBUF_TX_CKSUM_TCP_UDP; + case CHECKSUM_COMPLETE: + return QDF_NBUF_TX_CKSUM_TCP_UDP_IP; + default: + return QDF_NBUF_TX_CKSUM_NONE; + } +} +EXPORT_SYMBOL(__qdf_nbuf_get_tx_cksum); + +/** + * __qdf_nbuf_get_tid() - get tid + * @skb: Pointer to network buffer + * + * Return: tid + */ +uint8_t __qdf_nbuf_get_tid(struct sk_buff *skb) +{ + return skb->priority; +} +EXPORT_SYMBOL(__qdf_nbuf_get_tid); + +/** + * __qdf_nbuf_set_tid() - set tid + * @skb: Pointer to network buffer + * + * Return: none + */ +void __qdf_nbuf_set_tid(struct sk_buff *skb, uint8_t tid) +{ + skb->priority = tid; +} +EXPORT_SYMBOL(__qdf_nbuf_set_tid); + +/** + * __qdf_nbuf_set_tid() - set tid + * @skb: Pointer to network buffer + * + * Return: none + */ +uint8_t __qdf_nbuf_get_exemption_type(struct sk_buff *skb) +{ + return QDF_NBUF_EXEMPT_NO_EXEMPTION; +} +EXPORT_SYMBOL(__qdf_nbuf_get_exemption_type); + +/** + * __qdf_nbuf_reg_trace_cb() - register trace callback + * @cb_func_ptr: Pointer to trace callback function + * + * Return: none + */ +void __qdf_nbuf_reg_trace_cb(qdf_nbuf_trace_update_t cb_func_ptr) +{ + qdf_trace_update_cb = cb_func_ptr; + return; +} +EXPORT_SYMBOL(__qdf_nbuf_reg_trace_cb); + +/** + * __qdf_nbuf_data_get_dhcp_subtype() - get the subtype + * of DHCP packet. + * @data: Pointer to DHCP packet data buffer + * + * This func. returns the subtype of DHCP packet. + * + * Return: subtype of the DHCP packet. + */ +enum qdf_proto_subtype +__qdf_nbuf_data_get_dhcp_subtype(uint8_t *data) +{ + enum qdf_proto_subtype subtype = QDF_PROTO_INVALID; + + if ((data[QDF_DHCP_OPTION53_OFFSET] == QDF_DHCP_OPTION53) && + (data[QDF_DHCP_OPTION53_LENGTH_OFFSET] == + QDF_DHCP_OPTION53_LENGTH)) { + + switch (data[QDF_DHCP_OPTION53_STATUS_OFFSET]) { + case QDF_DHCP_DISCOVER: + subtype = QDF_PROTO_DHCP_DISCOVER; + break; + case QDF_DHCP_REQUEST: + subtype = QDF_PROTO_DHCP_REQUEST; + break; + case QDF_DHCP_OFFER: + subtype = QDF_PROTO_DHCP_OFFER; + break; + case QDF_DHCP_ACK: + subtype = QDF_PROTO_DHCP_ACK; + break; + case QDF_DHCP_NAK: + subtype = QDF_PROTO_DHCP_NACK; + break; + case QDF_DHCP_RELEASE: + subtype = QDF_PROTO_DHCP_RELEASE; + break; + case QDF_DHCP_INFORM: + subtype = QDF_PROTO_DHCP_INFORM; + break; + case QDF_DHCP_DECLINE: + subtype = QDF_PROTO_DHCP_DECLINE; + break; + default: + break; + } + } + + return subtype; +} + +/** + * __qdf_nbuf_data_get_eapol_subtype() - get the subtype + * of EAPOL packet. + * @data: Pointer to EAPOL packet data buffer + * + * This func. returns the subtype of EAPOL packet. + * + * Return: subtype of the EAPOL packet. + */ +enum qdf_proto_subtype +__qdf_nbuf_data_get_eapol_subtype(uint8_t *data) +{ + uint16_t eapol_key_info; + enum qdf_proto_subtype subtype = QDF_PROTO_INVALID; + uint16_t mask; + + eapol_key_info = (uint16_t)(*(uint16_t *) + (data + EAPOL_KEY_INFO_OFFSET)); + + mask = eapol_key_info & EAPOL_MASK; + switch (mask) { + case EAPOL_M1_BIT_MASK: + subtype = QDF_PROTO_EAPOL_M1; + break; + case EAPOL_M2_BIT_MASK: + subtype = QDF_PROTO_EAPOL_M2; + break; + case EAPOL_M3_BIT_MASK: + subtype = QDF_PROTO_EAPOL_M3; + break; + case EAPOL_M4_BIT_MASK: + subtype = QDF_PROTO_EAPOL_M4; + break; + default: + break; + } + + return subtype; +} + +/** + * __qdf_nbuf_data_get_arp_subtype() - get the subtype + * of ARP packet. + * @data: Pointer to ARP packet data buffer + * + * This func. returns the subtype of ARP packet. + * + * Return: subtype of the ARP packet. + */ +enum qdf_proto_subtype +__qdf_nbuf_data_get_arp_subtype(uint8_t *data) +{ + uint16_t subtype; + enum qdf_proto_subtype proto_subtype = QDF_PROTO_INVALID; + + subtype = (uint16_t)(*(uint16_t *) + (data + ARP_SUB_TYPE_OFFSET)); + + switch (QDF_SWAP_U16(subtype)) { + case ARP_REQUEST: + proto_subtype = QDF_PROTO_ARP_REQ; + break; + case ARP_RESPONSE: + proto_subtype = QDF_PROTO_ARP_RES; + break; + default: + break; + } + + return proto_subtype; +} + +/** + * __qdf_nbuf_data_get_icmp_subtype() - get the subtype + * of IPV4 ICMP packet. + * @data: Pointer to IPV4 ICMP packet data buffer + * + * This func. returns the subtype of ICMP packet. + * + * Return: subtype of the ICMP packet. + */ +enum qdf_proto_subtype +__qdf_nbuf_data_get_icmp_subtype(uint8_t *data) +{ + uint8_t subtype; + enum qdf_proto_subtype proto_subtype = QDF_PROTO_INVALID; + + subtype = (uint8_t)(*(uint8_t *) + (data + ICMP_SUBTYPE_OFFSET)); + + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_DEBUG, + "ICMP proto type: 0x%02x", subtype); + + switch (subtype) { + case ICMP_REQUEST: + proto_subtype = QDF_PROTO_ICMP_REQ; + break; + case ICMP_RESPONSE: + proto_subtype = QDF_PROTO_ICMP_RES; + break; + default: + break; + } + + return proto_subtype; +} + +/** + * __qdf_nbuf_data_get_icmpv6_subtype() - get the subtype + * of IPV6 ICMPV6 packet. + * @data: Pointer to IPV6 ICMPV6 packet data buffer + * + * This func. returns the subtype of ICMPV6 packet. + * + * Return: subtype of the ICMPV6 packet. + */ +enum qdf_proto_subtype +__qdf_nbuf_data_get_icmpv6_subtype(uint8_t *data) +{ + uint8_t subtype; + enum qdf_proto_subtype proto_subtype = QDF_PROTO_INVALID; + + subtype = (uint8_t)(*(uint8_t *) + (data + ICMPV6_SUBTYPE_OFFSET)); + + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_DEBUG, + "ICMPv6 proto type: 0x%02x", subtype); + + switch (subtype) { + case ICMPV6_REQUEST: + proto_subtype = QDF_PROTO_ICMPV6_REQ; + break; + case ICMPV6_RESPONSE: + proto_subtype = QDF_PROTO_ICMPV6_RES; + break; + case ICMPV6_RS: + proto_subtype = QDF_PROTO_ICMPV6_RS; + break; + case ICMPV6_RA: + proto_subtype = QDF_PROTO_ICMPV6_RA; + break; + case ICMPV6_NS: + proto_subtype = QDF_PROTO_ICMPV6_NS; + break; + case ICMPV6_NA: + proto_subtype = QDF_PROTO_ICMPV6_NA; + break; + default: + break; + } + + return proto_subtype; +} + +/** + * __qdf_nbuf_data_get_ipv4_proto() - get the proto type + * of IPV4 packet. + * @data: Pointer to IPV4 packet data buffer + * + * This func. returns the proto type of IPV4 packet. + * + * Return: proto type of IPV4 packet. + */ +uint8_t +__qdf_nbuf_data_get_ipv4_proto(uint8_t *data) +{ + uint8_t proto_type; + + proto_type = (uint8_t)(*(uint8_t *)(data + + QDF_NBUF_TRAC_IPV4_PROTO_TYPE_OFFSET)); + return proto_type; +} + +/** + * __qdf_nbuf_data_get_ipv6_proto() - get the proto type + * of IPV6 packet. + * @data: Pointer to IPV6 packet data buffer + * + * This func. returns the proto type of IPV6 packet. + * + * Return: proto type of IPV6 packet. + */ +uint8_t +__qdf_nbuf_data_get_ipv6_proto(uint8_t *data) +{ + uint8_t proto_type; + + proto_type = (uint8_t)(*(uint8_t *)(data + + QDF_NBUF_TRAC_IPV6_PROTO_TYPE_OFFSET)); + return proto_type; +} + +/** + * __qdf_nbuf_data_is_ipv4_pkt() - check if packet is a ipv4 packet + * @data: Pointer to network data + * + * This api is for Tx packets. + * + * Return: true if packet is ipv4 packet + * false otherwise + */ +bool __qdf_nbuf_data_is_ipv4_pkt(uint8_t *data) +{ + uint16_t ether_type; + + ether_type = (uint16_t)(*(uint16_t *)(data + + QDF_NBUF_TRAC_ETH_TYPE_OFFSET)); + + if (ether_type == QDF_SWAP_U16(QDF_NBUF_TRAC_IPV4_ETH_TYPE)) + return true; + else + return false; +} + +/** + * __qdf_nbuf_data_is_ipv4_dhcp_pkt() - check if skb data is a dhcp packet + * @data: Pointer to network data buffer + * + * This api is for ipv4 packet. + * + * Return: true if packet is DHCP packet + * false otherwise + */ +bool __qdf_nbuf_data_is_ipv4_dhcp_pkt(uint8_t *data) +{ + uint16_t sport; + uint16_t dport; + + sport = (uint16_t)(*(uint16_t *)(data + QDF_NBUF_TRAC_IPV4_OFFSET + + QDF_NBUF_TRAC_IPV4_HEADER_SIZE)); + dport = (uint16_t)(*(uint16_t *)(data + QDF_NBUF_TRAC_IPV4_OFFSET + + QDF_NBUF_TRAC_IPV4_HEADER_SIZE + + sizeof(uint16_t))); + + if (((sport == QDF_SWAP_U16(QDF_NBUF_TRAC_DHCP_SRV_PORT)) && + (dport == QDF_SWAP_U16(QDF_NBUF_TRAC_DHCP_CLI_PORT))) || + ((sport == QDF_SWAP_U16(QDF_NBUF_TRAC_DHCP_CLI_PORT)) && + (dport == QDF_SWAP_U16(QDF_NBUF_TRAC_DHCP_SRV_PORT)))) + return true; + else + return false; +} + +/** + * __qdf_nbuf_data_is_ipv4_eapol_pkt() - check if skb data is a eapol packet + * @data: Pointer to network data buffer + * + * This api is for ipv4 packet. + * + * Return: true if packet is EAPOL packet + * false otherwise. + */ +bool __qdf_nbuf_data_is_ipv4_eapol_pkt(uint8_t *data) +{ + uint16_t ether_type; + + ether_type = (uint16_t)(*(uint16_t *)(data + + QDF_NBUF_TRAC_ETH_TYPE_OFFSET)); + + if (ether_type == QDF_SWAP_U16(QDF_NBUF_TRAC_EAPOL_ETH_TYPE)) + return true; + else + return false; +} + +/** + * __qdf_nbuf_is_ipv4_wapi_pkt() - check if skb data is a wapi packet + * @skb: Pointer to network buffer + * + * This api is for ipv4 packet. + * + * Return: true if packet is WAPI packet + * false otherwise. + */ +bool __qdf_nbuf_is_ipv4_wapi_pkt(struct sk_buff *skb) +{ + uint16_t ether_type; + + ether_type = (uint16_t)(*(uint16_t *)(skb->data + + QDF_NBUF_TRAC_ETH_TYPE_OFFSET)); + + if (ether_type == QDF_SWAP_U16(QDF_NBUF_TRAC_WAPI_ETH_TYPE)) + return true; + else + return false; +} + +/** + * __qdf_nbuf_data_is_ipv4_arp_pkt() - check if skb data is a arp packet + * @data: Pointer to network data buffer + * + * This api is for ipv4 packet. + * + * Return: true if packet is ARP packet + * false otherwise. + */ +bool __qdf_nbuf_data_is_ipv4_arp_pkt(uint8_t *data) +{ + uint16_t ether_type; + + ether_type = (uint16_t)(*(uint16_t *)(data + + QDF_NBUF_TRAC_ETH_TYPE_OFFSET)); + + if (ether_type == QDF_SWAP_U16(QDF_NBUF_TRAC_ARP_ETH_TYPE)) + return true; + else + return false; +} + +/** + * __qdf_nbuf_data_is_arp_req() - check if skb data is a arp request + * @data: Pointer to network data buffer + * + * This api is for ipv4 packet. + * + * Return: true if packet is ARP request + * false otherwise. + */ +bool __qdf_nbuf_data_is_arp_req(uint8_t *data) +{ + uint16_t op_code; + + op_code = (uint16_t)(*(uint16_t *)(data + + QDF_NBUF_PKT_ARP_OPCODE_OFFSET)); + + if (op_code == QDF_SWAP_U16(QDF_NBUF_PKT_ARPOP_REQ)) + return true; + else + return false; +} + +/** + * __qdf_nbuf_data_is_arp_rsp() - check if skb data is a arp response + * @data: Pointer to network data buffer + * + * This api is for ipv4 packet. + * + * Return: true if packet is ARP response + * false otherwise. + */ +bool __qdf_nbuf_data_is_arp_rsp(uint8_t *data) +{ + uint16_t op_code; + + op_code = (uint16_t)(*(uint16_t *)(data + + QDF_NBUF_PKT_ARP_OPCODE_OFFSET)); + + if (op_code == QDF_SWAP_U16(QDF_NBUF_PKT_ARPOP_REPLY)) + return true; + else + return false; +} + +/** + * __qdf_nbuf_data_get_arp_src_ip() - get arp src IP + * @data: Pointer to network data buffer + * + * This api is for ipv4 packet. + * + * Return: ARP packet source IP value. + */ +uint32_t __qdf_nbuf_get_arp_src_ip(uint8_t *data) +{ + uint32_t src_ip; + + src_ip = (uint32_t)(*(uint32_t *)(data + + QDF_NBUF_PKT_ARP_SRC_IP_OFFSET)); + + return src_ip; +} + +/** + * __qdf_nbuf_data_get_arp_tgt_ip() - get arp target IP + * @data: Pointer to network data buffer + * + * This api is for ipv4 packet. + * + * Return: ARP packet target IP value. + */ +uint32_t __qdf_nbuf_get_arp_tgt_ip(uint8_t *data) +{ + uint32_t tgt_ip; + + tgt_ip = (uint32_t)(*(uint32_t *)(data + + QDF_NBUF_PKT_ARP_TGT_IP_OFFSET)); + + return tgt_ip; +} + +/** + * __qdf_nbuf_data_is_ipv6_pkt() - check if it is IPV6 packet. + * @data: Pointer to IPV6 packet data buffer + * + * This func. checks whether it is a IPV6 packet or not. + * + * Return: TRUE if it is a IPV6 packet + * FALSE if not + */ +bool __qdf_nbuf_data_is_ipv6_pkt(uint8_t *data) +{ + uint16_t ether_type; + + ether_type = (uint16_t)(*(uint16_t *)(data + + QDF_NBUF_TRAC_ETH_TYPE_OFFSET)); + + if (ether_type == QDF_SWAP_U16(QDF_NBUF_TRAC_IPV6_ETH_TYPE)) + return true; + else + return false; +} + +/** + * __qdf_nbuf_data_is_ipv4_mcast_pkt() - check if it is IPV4 multicast packet. + * @data: Pointer to IPV4 packet data buffer + * + * This func. checks whether it is a IPV4 multicast packet or not. + * + * Return: TRUE if it is a IPV4 multicast packet + * FALSE if not + */ +bool __qdf_nbuf_data_is_ipv4_mcast_pkt(uint8_t *data) +{ + if (__qdf_nbuf_data_is_ipv4_pkt(data)) { + uint32_t *dst_addr = + (uint32_t *)(data + QDF_NBUF_TRAC_IPV4_DEST_ADDR_OFFSET); + + /* + * Check first word of the IPV4 address and if it is + * equal to 0xE then it represents multicast IP. + */ + if ((*dst_addr & QDF_NBUF_TRAC_IPV4_ADDR_BCAST_MASK) == + QDF_NBUF_TRAC_IPV4_ADDR_MCAST_MASK) + return true; + else + return false; + } else + return false; +} + +/** + * __qdf_nbuf_data_is_ipv6_mcast_pkt() - check if it is IPV6 multicast packet. + * @data: Pointer to IPV6 packet data buffer + * + * This func. checks whether it is a IPV6 multicast packet or not. + * + * Return: TRUE if it is a IPV6 multicast packet + * FALSE if not + */ +bool __qdf_nbuf_data_is_ipv6_mcast_pkt(uint8_t *data) +{ + if (__qdf_nbuf_data_is_ipv6_pkt(data)) { + uint16_t *dst_addr; + + dst_addr = (uint16_t *) + (data + QDF_NBUF_TRAC_IPV6_DEST_ADDR_OFFSET); + + /* + * Check first byte of the IP address and if it + * 0xFF00 then it is a IPV6 mcast packet. + */ + if (*dst_addr == + QDF_SWAP_U16(QDF_NBUF_TRAC_IPV6_DEST_ADDR)) + return true; + else + return false; + } else + return false; +} + +/** + * __qdf_nbuf_data_is_icmp_pkt() - check if it is IPV4 ICMP packet. + * @data: Pointer to IPV4 ICMP packet data buffer + * + * This func. checks whether it is a ICMP packet or not. + * + * Return: TRUE if it is a ICMP packet + * FALSE if not + */ +bool __qdf_nbuf_data_is_icmp_pkt(uint8_t *data) +{ + if (__qdf_nbuf_data_is_ipv4_pkt(data)) { + uint8_t pkt_type; + + pkt_type = (uint8_t)(*(uint8_t *)(data + + QDF_NBUF_TRAC_IPV4_PROTO_TYPE_OFFSET)); + + if (pkt_type == QDF_NBUF_TRAC_ICMP_TYPE) + return true; + else + return false; + } else + return false; +} + +/** + * __qdf_nbuf_data_is_icmpv6_pkt() - check if it is IPV6 ICMPV6 packet. + * @data: Pointer to IPV6 ICMPV6 packet data buffer + * + * This func. checks whether it is a ICMPV6 packet or not. + * + * Return: TRUE if it is a ICMPV6 packet + * FALSE if not + */ +bool __qdf_nbuf_data_is_icmpv6_pkt(uint8_t *data) +{ + if (__qdf_nbuf_data_is_ipv6_pkt(data)) { + uint8_t pkt_type; + + pkt_type = (uint8_t)(*(uint8_t *)(data + + QDF_NBUF_TRAC_IPV6_PROTO_TYPE_OFFSET)); + + if (pkt_type == QDF_NBUF_TRAC_ICMPV6_TYPE) + return true; + else + return false; + } else + return false; +} + +/** + * __qdf_nbuf_data_is_ipv4_udp_pkt() - check if it is IPV4 UDP packet. + * @data: Pointer to IPV4 UDP packet data buffer + * + * This func. checks whether it is a IPV4 UDP packet or not. + * + * Return: TRUE if it is a IPV4 UDP packet + * FALSE if not + */ +bool __qdf_nbuf_data_is_ipv4_udp_pkt(uint8_t *data) +{ + if (__qdf_nbuf_data_is_ipv4_pkt(data)) { + uint8_t pkt_type; + + pkt_type = (uint8_t)(*(uint8_t *)(data + + QDF_NBUF_TRAC_IPV4_PROTO_TYPE_OFFSET)); + + if (pkt_type == QDF_NBUF_TRAC_UDP_TYPE) + return true; + else + return false; + } else + return false; +} + +/** + * __qdf_nbuf_data_is_ipv4_tcp_pkt() - check if it is IPV4 TCP packet. + * @data: Pointer to IPV4 TCP packet data buffer + * + * This func. checks whether it is a IPV4 TCP packet or not. + * + * Return: TRUE if it is a IPV4 TCP packet + * FALSE if not + */ +bool __qdf_nbuf_data_is_ipv4_tcp_pkt(uint8_t *data) +{ + if (__qdf_nbuf_data_is_ipv4_pkt(data)) { + uint8_t pkt_type; + + pkt_type = (uint8_t)(*(uint8_t *)(data + + QDF_NBUF_TRAC_IPV4_PROTO_TYPE_OFFSET)); + + if (pkt_type == QDF_NBUF_TRAC_TCP_TYPE) + return true; + else + return false; + } else + return false; +} + +/** + * __qdf_nbuf_data_is_ipv6_udp_pkt() - check if it is IPV6 UDP packet. + * @data: Pointer to IPV6 UDP packet data buffer + * + * This func. checks whether it is a IPV6 UDP packet or not. + * + * Return: TRUE if it is a IPV6 UDP packet + * FALSE if not + */ +bool __qdf_nbuf_data_is_ipv6_udp_pkt(uint8_t *data) +{ + if (__qdf_nbuf_data_is_ipv6_pkt(data)) { + uint8_t pkt_type; + + pkt_type = (uint8_t)(*(uint8_t *)(data + + QDF_NBUF_TRAC_IPV6_PROTO_TYPE_OFFSET)); + + if (pkt_type == QDF_NBUF_TRAC_UDP_TYPE) + return true; + else + return false; + } else + return false; +} + +/** + * __qdf_nbuf_data_is_ipv6_tcp_pkt() - check if it is IPV6 TCP packet. + * @data: Pointer to IPV6 TCP packet data buffer + * + * This func. checks whether it is a IPV6 TCP packet or not. + * + * Return: TRUE if it is a IPV6 TCP packet + * FALSE if not + */ +bool __qdf_nbuf_data_is_ipv6_tcp_pkt(uint8_t *data) +{ + if (__qdf_nbuf_data_is_ipv6_pkt(data)) { + uint8_t pkt_type; + + pkt_type = (uint8_t)(*(uint8_t *)(data + + QDF_NBUF_TRAC_IPV6_PROTO_TYPE_OFFSET)); + + if (pkt_type == QDF_NBUF_TRAC_TCP_TYPE) + return true; + else + return false; + } else + return false; +} + +#ifdef MEMORY_DEBUG +#define QDF_NET_BUF_TRACK_MAX_SIZE (1024) + +/** + * struct qdf_nbuf_track_t - Network buffer track structure + * + * @p_next: Pointer to next + * @net_buf: Pointer to network buffer + * @file_name: File name + * @line_num: Line number + * @size: Size + */ +struct qdf_nbuf_track_t { + struct qdf_nbuf_track_t *p_next; + qdf_nbuf_t net_buf; + uint8_t *file_name; + uint32_t line_num; + size_t size; +}; + +static spinlock_t g_qdf_net_buf_track_lock[QDF_NET_BUF_TRACK_MAX_SIZE]; +typedef struct qdf_nbuf_track_t QDF_NBUF_TRACK; + +static QDF_NBUF_TRACK *gp_qdf_net_buf_track_tbl[QDF_NET_BUF_TRACK_MAX_SIZE]; +static struct kmem_cache *nbuf_tracking_cache; +static QDF_NBUF_TRACK *qdf_net_buf_track_free_list; +static spinlock_t qdf_net_buf_track_free_list_lock; +static uint32_t qdf_net_buf_track_free_list_count; +static uint32_t qdf_net_buf_track_used_list_count; +static uint32_t qdf_net_buf_track_max_used; +static uint32_t qdf_net_buf_track_max_free; +static uint32_t qdf_net_buf_track_max_allocated; + +/** + * update_max_used() - update qdf_net_buf_track_max_used tracking variable + * + * tracks the max number of network buffers that the wlan driver was tracking + * at any one time. + * + * Return: none + */ +static inline void update_max_used(void) +{ + int sum; + + if (qdf_net_buf_track_max_used < + qdf_net_buf_track_used_list_count) + qdf_net_buf_track_max_used = qdf_net_buf_track_used_list_count; + sum = qdf_net_buf_track_free_list_count + + qdf_net_buf_track_used_list_count; + if (qdf_net_buf_track_max_allocated < sum) + qdf_net_buf_track_max_allocated = sum; +} + +/** + * update_max_free() - update qdf_net_buf_track_free_list_count + * + * tracks the max number tracking buffers kept in the freelist. + * + * Return: none + */ +static inline void update_max_free(void) +{ + if (qdf_net_buf_track_max_free < + qdf_net_buf_track_free_list_count) + qdf_net_buf_track_max_free = qdf_net_buf_track_free_list_count; +} + +/** + * qdf_nbuf_track_alloc() - allocate a cookie to track nbufs allocated by wlan + * + * This function pulls from a freelist if possible and uses kmem_cache_alloc. + * This function also ads fexibility to adjust the allocation and freelist + * scheems. + * + * Return: a pointer to an unused QDF_NBUF_TRACK structure may not be zeroed. + */ +static QDF_NBUF_TRACK *qdf_nbuf_track_alloc(void) +{ + int flags = GFP_KERNEL; + unsigned long irq_flag; + QDF_NBUF_TRACK *new_node = NULL; + + spin_lock_irqsave(&qdf_net_buf_track_free_list_lock, irq_flag); + qdf_net_buf_track_used_list_count++; + if (qdf_net_buf_track_free_list != NULL) { + new_node = qdf_net_buf_track_free_list; + qdf_net_buf_track_free_list = + qdf_net_buf_track_free_list->p_next; + qdf_net_buf_track_free_list_count--; + } + update_max_used(); + spin_unlock_irqrestore(&qdf_net_buf_track_free_list_lock, irq_flag); + + if (new_node != NULL) + return new_node; + + if (in_interrupt() || irqs_disabled() || in_atomic()) + flags = GFP_ATOMIC; + + return kmem_cache_alloc(nbuf_tracking_cache, flags); +} + +/* FREEQ_POOLSIZE initial and minimum desired freelist poolsize */ +#define FREEQ_POOLSIZE 2048 + +/** + * qdf_nbuf_track_free() - free the nbuf tracking cookie. + * + * Matches calls to qdf_nbuf_track_alloc. + * Either frees the tracking cookie to kernel or an internal + * freelist based on the size of the freelist. + * + * Return: none + */ +static void qdf_nbuf_track_free(QDF_NBUF_TRACK *node) +{ + unsigned long irq_flag; + + if (!node) + return; + + /* Try to shrink the freelist if free_list_count > than FREEQ_POOLSIZE + * only shrink the freelist if it is bigger than twice the number of + * nbufs in use. If the driver is stalling in a consistent bursty + * fasion, this will keep 3/4 of thee allocations from the free list + * while also allowing the system to recover memory as less frantic + * traffic occurs. + */ + + spin_lock_irqsave(&qdf_net_buf_track_free_list_lock, irq_flag); + + qdf_net_buf_track_used_list_count--; + if (qdf_net_buf_track_free_list_count > FREEQ_POOLSIZE && + (qdf_net_buf_track_free_list_count > + qdf_net_buf_track_used_list_count << 1)) { + kmem_cache_free(nbuf_tracking_cache, node); + } else { + node->p_next = qdf_net_buf_track_free_list; + qdf_net_buf_track_free_list = node; + qdf_net_buf_track_free_list_count++; + } + update_max_free(); + spin_unlock_irqrestore(&qdf_net_buf_track_free_list_lock, irq_flag); +} + +/** + * qdf_nbuf_track_prefill() - prefill the nbuf tracking cookie freelist + * + * Removes a 'warmup time' characteristic of the freelist. Prefilling + * the freelist first makes it performant for the first iperf udp burst + * as well as steady state. + * + * Return: None + */ +static void qdf_nbuf_track_prefill(void) +{ + int i; + QDF_NBUF_TRACK *node, *head; + + /* prepopulate the freelist */ + head = NULL; + for (i = 0; i < FREEQ_POOLSIZE; i++) { + node = qdf_nbuf_track_alloc(); + if (node == NULL) + continue; + node->p_next = head; + head = node; + } + while (head) { + node = head->p_next; + qdf_nbuf_track_free(head); + head = node; + } + + /* prefilled buffers should not count as used */ + qdf_net_buf_track_max_used = 0; +} + +/** + * qdf_nbuf_track_memory_manager_create() - manager for nbuf tracking cookies + * + * This initializes the memory manager for the nbuf tracking cookies. Because + * these cookies are all the same size and only used in this feature, we can + * use a kmem_cache to provide tracking as well as to speed up allocations. + * To avoid the overhead of allocating and freeing the buffers (including SLUB + * features) a freelist is prepopulated here. + * + * Return: None + */ +static void qdf_nbuf_track_memory_manager_create(void) +{ + spin_lock_init(&qdf_net_buf_track_free_list_lock); + nbuf_tracking_cache = kmem_cache_create("qdf_nbuf_tracking_cache", + sizeof(QDF_NBUF_TRACK), + 0, 0, NULL); + + qdf_nbuf_track_prefill(); +} + +/** + * qdf_nbuf_track_memory_manager_destroy() - manager for nbuf tracking cookies + * + * Empty the freelist and print out usage statistics when it is no longer + * needed. Also the kmem_cache should be destroyed here so that it can warn if + * any nbuf tracking cookies were leaked. + * + * Return: None + */ +static void qdf_nbuf_track_memory_manager_destroy(void) +{ + QDF_NBUF_TRACK *node, *tmp; + unsigned long irq_flag; + + spin_lock_irqsave(&qdf_net_buf_track_free_list_lock, irq_flag); + node = qdf_net_buf_track_free_list; + + if (qdf_net_buf_track_max_used > FREEQ_POOLSIZE * 4) + qdf_print("%s: unexpectedly large max_used count %d", + __func__, qdf_net_buf_track_max_used); + + if (qdf_net_buf_track_max_used < qdf_net_buf_track_max_allocated) + qdf_print("%s: %d unused trackers were allocated", + __func__, + qdf_net_buf_track_max_allocated - + qdf_net_buf_track_max_used); + + if (qdf_net_buf_track_free_list_count > FREEQ_POOLSIZE && + qdf_net_buf_track_free_list_count > 3*qdf_net_buf_track_max_used/4) + qdf_print("%s: check freelist shrinking functionality", + __func__); + + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO, + "%s: %d residual freelist size\n", + __func__, qdf_net_buf_track_free_list_count); + + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO, + "%s: %d max freelist size observed\n", + __func__, qdf_net_buf_track_max_free); + + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO, + "%s: %d max buffers used observed\n", + __func__, qdf_net_buf_track_max_used); + + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO, + "%s: %d max buffers allocated observed\n", + __func__, qdf_net_buf_track_max_allocated); + + while (node) { + tmp = node; + node = node->p_next; + kmem_cache_free(nbuf_tracking_cache, tmp); + qdf_net_buf_track_free_list_count--; + } + + if (qdf_net_buf_track_free_list_count != 0) + qdf_print("%s: %d unfreed tracking memory lost in freelist\n", + __func__, qdf_net_buf_track_free_list_count); + + if (qdf_net_buf_track_used_list_count != 0) + qdf_print("%s: %d unfreed tracking memory still in use\n", + __func__, qdf_net_buf_track_used_list_count); + + spin_unlock_irqrestore(&qdf_net_buf_track_free_list_lock, irq_flag); + kmem_cache_destroy(nbuf_tracking_cache); + qdf_net_buf_track_free_list = NULL; +} + +/** + * qdf_net_buf_debug_init() - initialize network buffer debug functionality + * + * QDF network buffer debug feature tracks all SKBs allocated by WLAN driver + * in a hash table and when driver is unloaded it reports about leaked SKBs. + * WLAN driver module whose allocated SKB is freed by network stack are + * suppose to call qdf_net_buf_debug_release_skb() such that the SKB is not + * reported as memory leak. + * + * Return: none + */ +void qdf_net_buf_debug_init(void) +{ + uint32_t i; + + qdf_nbuf_track_memory_manager_create(); + + for (i = 0; i < QDF_NET_BUF_TRACK_MAX_SIZE; i++) { + gp_qdf_net_buf_track_tbl[i] = NULL; + spin_lock_init(&g_qdf_net_buf_track_lock[i]); + } + + return; +} +EXPORT_SYMBOL(qdf_net_buf_debug_init); + +/** + * qdf_net_buf_debug_init() - exit network buffer debug functionality + * + * Exit network buffer tracking debug functionality and log SKB memory leaks + * As part of exiting the functionality, free the leaked memory and + * cleanup the tracking buffers. + * + * Return: none + */ +void qdf_net_buf_debug_exit(void) +{ + uint32_t i; + unsigned long irq_flag; + QDF_NBUF_TRACK *p_node; + QDF_NBUF_TRACK *p_prev; + + for (i = 0; i < QDF_NET_BUF_TRACK_MAX_SIZE; i++) { + spin_lock_irqsave(&g_qdf_net_buf_track_lock[i], irq_flag); + p_node = gp_qdf_net_buf_track_tbl[i]; + while (p_node) { + p_prev = p_node; + p_node = p_node->p_next; + qdf_print("SKB buf memory Leak@ File %s, @Line %d, size %zu\n", + p_prev->file_name, p_prev->line_num, + p_prev->size); + qdf_nbuf_track_free(p_prev); + } + spin_unlock_irqrestore(&g_qdf_net_buf_track_lock[i], irq_flag); + } + + qdf_nbuf_track_memory_manager_destroy(); + + return; +} +EXPORT_SYMBOL(qdf_net_buf_debug_exit); + +/** + * qdf_net_buf_debug_hash() - hash network buffer pointer + * + * Return: hash value + */ +static uint32_t qdf_net_buf_debug_hash(qdf_nbuf_t net_buf) +{ + uint32_t i; + + i = (uint32_t) (((uintptr_t) net_buf) >> 4); + i += (uint32_t) (((uintptr_t) net_buf) >> 14); + i &= (QDF_NET_BUF_TRACK_MAX_SIZE - 1); + + return i; +} + +/** + * qdf_net_buf_debug_look_up() - look up network buffer in debug hash table + * + * Return: If skb is found in hash table then return pointer to network buffer + * else return %NULL + */ +static QDF_NBUF_TRACK *qdf_net_buf_debug_look_up(qdf_nbuf_t net_buf) +{ + uint32_t i; + QDF_NBUF_TRACK *p_node; + + i = qdf_net_buf_debug_hash(net_buf); + p_node = gp_qdf_net_buf_track_tbl[i]; + + while (p_node) { + if (p_node->net_buf == net_buf) + return p_node; + p_node = p_node->p_next; + } + + return NULL; +} + +/** + * qdf_net_buf_debug_add_node() - store skb in debug hash table + * + * Return: none + */ +void qdf_net_buf_debug_add_node(qdf_nbuf_t net_buf, size_t size, + uint8_t *file_name, uint32_t line_num) +{ + uint32_t i; + unsigned long irq_flag; + QDF_NBUF_TRACK *p_node; + QDF_NBUF_TRACK *new_node; + + new_node = qdf_nbuf_track_alloc(); + + i = qdf_net_buf_debug_hash(net_buf); + spin_lock_irqsave(&g_qdf_net_buf_track_lock[i], irq_flag); + + p_node = qdf_net_buf_debug_look_up(net_buf); + + if (p_node) { + qdf_print("Double allocation of skb ! Already allocated from %p %s %d current alloc from %p %s %d", + p_node->net_buf, p_node->file_name, p_node->line_num, + net_buf, file_name, line_num); + qdf_nbuf_track_free(new_node); + } else { + p_node = new_node; + if (p_node) { + p_node->net_buf = net_buf; + p_node->file_name = file_name; + p_node->line_num = line_num; + p_node->size = size; + p_node->p_next = gp_qdf_net_buf_track_tbl[i]; + gp_qdf_net_buf_track_tbl[i] = p_node; + } else + qdf_print( + "Mem alloc failed ! Could not track skb from %s %d of size %zu", + file_name, line_num, size); + } + spin_unlock_irqrestore(&g_qdf_net_buf_track_lock[i], irq_flag); + + return; +} +EXPORT_SYMBOL(qdf_net_buf_debug_add_node); + +/** + * qdf_net_buf_debug_delete_node() - remove skb from debug hash table + * + * Return: none + */ +void qdf_net_buf_debug_delete_node(qdf_nbuf_t net_buf) +{ + uint32_t i; + bool found = false; + QDF_NBUF_TRACK *p_head; + QDF_NBUF_TRACK *p_node; + unsigned long irq_flag; + QDF_NBUF_TRACK *p_prev; + + i = qdf_net_buf_debug_hash(net_buf); + spin_lock_irqsave(&g_qdf_net_buf_track_lock[i], irq_flag); + + p_head = gp_qdf_net_buf_track_tbl[i]; + + /* Unallocated SKB */ + if (!p_head) + goto done; + + p_node = p_head; + /* Found at head of the table */ + if (p_head->net_buf == net_buf) { + gp_qdf_net_buf_track_tbl[i] = p_node->p_next; + found = true; + goto done; + } + + /* Search in collision list */ + while (p_node) { + p_prev = p_node; + p_node = p_node->p_next; + if ((NULL != p_node) && (p_node->net_buf == net_buf)) { + p_prev->p_next = p_node->p_next; + found = true; + break; + } + } + +done: + spin_unlock_irqrestore(&g_qdf_net_buf_track_lock[i], irq_flag); + + if (!found) { + qdf_print("Unallocated buffer ! Double free of net_buf %p ?", + net_buf); + QDF_ASSERT(0); + } else { + qdf_nbuf_track_free(p_node); + } + + return; +} +EXPORT_SYMBOL(qdf_net_buf_debug_delete_node); + +/** + * qdf_net_buf_debug_release_skb() - release skb to avoid memory leak + * @net_buf: Network buf holding head segment (single) + * + * WLAN driver module whose allocated SKB is freed by network stack are + * suppose to call this API before returning SKB to network stack such + * that the SKB is not reported as memory leak. + * + * Return: none + */ +void qdf_net_buf_debug_release_skb(qdf_nbuf_t net_buf) +{ + qdf_nbuf_t ext_list = qdf_nbuf_get_ext_list(net_buf); + + while (ext_list) { + /* + * Take care to free if it is Jumbo packet connected using + * frag_list + */ + qdf_nbuf_t next; + + next = qdf_nbuf_queue_next(ext_list); + qdf_net_buf_debug_delete_node(ext_list); + ext_list = next; + } + qdf_net_buf_debug_delete_node(net_buf); +} +EXPORT_SYMBOL(qdf_net_buf_debug_release_skb); + +#else +void qdf_net_buf_debug_delete_node(qdf_nbuf_t net_buf) +{ +} +EXPORT_SYMBOL(qdf_net_buf_debug_delete_node); +#endif /*MEMORY_DEBUG */ + +#if defined(FEATURE_TSO) + +/** + * struct qdf_tso_cmn_seg_info_t - TSO common info structure + * + * @ethproto: ethernet type of the msdu + * @ip_tcp_hdr_len: ip + tcp length for the msdu + * @l2_len: L2 length for the msdu + * @eit_hdr: pointer to EIT header + * @eit_hdr_len: EIT header length for the msdu + * @eit_hdr_dma_map_addr: dma addr for EIT header + * @tcphdr: pointer to tcp header + * @ipv4_csum_en: ipv4 checksum enable + * @tcp_ipv4_csum_en: TCP ipv4 checksum enable + * @tcp_ipv6_csum_en: TCP ipv6 checksum enable + * @ip_id: IP id + * @tcp_seq_num: TCP sequence number + * + * This structure holds the TSO common info that is common + * across all the TCP segments of the jumbo packet. + */ +struct qdf_tso_cmn_seg_info_t { + uint16_t ethproto; + uint16_t ip_tcp_hdr_len; + uint16_t l2_len; + uint8_t *eit_hdr; + uint32_t eit_hdr_len; + qdf_dma_addr_t eit_hdr_dma_map_addr; + struct tcphdr *tcphdr; + uint16_t ipv4_csum_en; + uint16_t tcp_ipv4_csum_en; + uint16_t tcp_ipv6_csum_en; + uint16_t ip_id; + uint32_t tcp_seq_num; +}; + +/** + * __qdf_nbuf_get_tso_cmn_seg_info() - get TSO common + * information + * @osdev: qdf device handle + * @skb: skb buffer + * @tso_info: Parameters common to all segements + * + * Get the TSO information that is common across all the TCP + * segments of the jumbo packet + * + * Return: 0 - success 1 - failure + */ +static uint8_t __qdf_nbuf_get_tso_cmn_seg_info(qdf_device_t osdev, + struct sk_buff *skb, + struct qdf_tso_cmn_seg_info_t *tso_info) +{ + /* Get ethernet type and ethernet header length */ + tso_info->ethproto = vlan_get_protocol(skb); + + /* Determine whether this is an IPv4 or IPv6 packet */ + if (tso_info->ethproto == htons(ETH_P_IP)) { /* IPv4 */ + /* for IPv4, get the IP ID and enable TCP and IP csum */ + struct iphdr *ipv4_hdr = ip_hdr(skb); + tso_info->ip_id = ntohs(ipv4_hdr->id); + tso_info->ipv4_csum_en = 1; + tso_info->tcp_ipv4_csum_en = 1; + if (qdf_unlikely(ipv4_hdr->protocol != IPPROTO_TCP)) { + qdf_print("TSO IPV4 proto 0x%x not TCP\n", + ipv4_hdr->protocol); + return 1; + } + } else if (tso_info->ethproto == htons(ETH_P_IPV6)) { /* IPv6 */ + /* for IPv6, enable TCP csum. No IP ID or IP csum */ + tso_info->tcp_ipv6_csum_en = 1; + } else { + qdf_print("TSO: ethertype 0x%x is not supported!\n", + tso_info->ethproto); + return 1; + } + + tso_info->l2_len = (skb_network_header(skb) - skb_mac_header(skb)); + tso_info->tcphdr = tcp_hdr(skb); + tso_info->tcp_seq_num = ntohl(tcp_hdr(skb)->seq); + /* get pointer to the ethernet + IP + TCP header and their length */ + tso_info->eit_hdr = skb->data; + tso_info->eit_hdr_len = (skb_transport_header(skb) + - skb_mac_header(skb)) + tcp_hdrlen(skb); + tso_info->eit_hdr_dma_map_addr = dma_map_single(osdev->dev, + tso_info->eit_hdr, + tso_info->eit_hdr_len, + DMA_TO_DEVICE); + if (unlikely(dma_mapping_error(osdev->dev, + tso_info->eit_hdr_dma_map_addr))) { + qdf_print("DMA mapping error!\n"); + qdf_assert(0); + return 1; + } + + if (tso_info->ethproto == htons(ETH_P_IP)) { + /* inlcude IPv4 header length for IPV4 (total length) */ + tso_info->ip_tcp_hdr_len = + tso_info->eit_hdr_len - tso_info->l2_len; + } else if (tso_info->ethproto == htons(ETH_P_IPV6)) { + /* exclude IPv6 header length for IPv6 (payload length) */ + tso_info->ip_tcp_hdr_len = tcp_hdrlen(skb); + } + /* + * The length of the payload (application layer data) is added to + * tso_info->ip_tcp_hdr_len before passing it on to the msdu link ext + * descriptor. + */ + + TSO_DEBUG("%s seq# %u eit hdr len %u l2 len %u skb len %u\n", __func__, + tso_info->tcp_seq_num, + tso_info->eit_hdr_len, + tso_info->l2_len, + skb->len); + return 0; +} + + +/** + * qdf_dmaaddr_to_32s - return high and low parts of dma_addr + * + * Returns the high and low 32-bits of the DMA addr in the provided ptrs + * + * Return: N/A + */ +void __qdf_dmaaddr_to_32s(qdf_dma_addr_t dmaaddr, + uint32_t *lo, uint32_t *hi) +{ + if (sizeof(dmaaddr) > sizeof(uint32_t)) { + *lo = lower_32_bits(dmaaddr); + *hi = upper_32_bits(dmaaddr); + } else { + *lo = dmaaddr; + *hi = 0; + } +} + +/** + * __qdf_nbuf_fill_tso_cmn_seg_info() - Init function for each TSO nbuf segment + * + * @curr_seg: Segment whose contents are initialized + * @tso_cmn_info: Parameters common to all segements + * + * Return: None + */ +static inline void __qdf_nbuf_fill_tso_cmn_seg_info( + struct qdf_tso_seg_elem_t *curr_seg, + struct qdf_tso_cmn_seg_info_t *tso_cmn_info) +{ + /* Initialize the flags to 0 */ + memset(&curr_seg->seg, 0x0, sizeof(curr_seg->seg)); + + /* + * The following fields remain the same across all segments of + * a jumbo packet + */ + curr_seg->seg.tso_flags.tso_enable = 1; + curr_seg->seg.tso_flags.ipv4_checksum_en = + tso_cmn_info->ipv4_csum_en; + curr_seg->seg.tso_flags.tcp_ipv6_checksum_en = + tso_cmn_info->tcp_ipv6_csum_en; + curr_seg->seg.tso_flags.tcp_ipv4_checksum_en = + tso_cmn_info->tcp_ipv4_csum_en; + curr_seg->seg.tso_flags.tcp_flags_mask = 0x1FF; + + /* The following fields change for the segments */ + curr_seg->seg.tso_flags.ip_id = tso_cmn_info->ip_id; + tso_cmn_info->ip_id++; + + curr_seg->seg.tso_flags.syn = tso_cmn_info->tcphdr->syn; + curr_seg->seg.tso_flags.rst = tso_cmn_info->tcphdr->rst; + curr_seg->seg.tso_flags.psh = tso_cmn_info->tcphdr->psh; + curr_seg->seg.tso_flags.ack = tso_cmn_info->tcphdr->ack; + curr_seg->seg.tso_flags.urg = tso_cmn_info->tcphdr->urg; + curr_seg->seg.tso_flags.ece = tso_cmn_info->tcphdr->ece; + curr_seg->seg.tso_flags.cwr = tso_cmn_info->tcphdr->cwr; + + curr_seg->seg.tso_flags.tcp_seq_num = tso_cmn_info->tcp_seq_num; + + /* + * First fragment for each segment always contains the ethernet, + * IP and TCP header + */ + curr_seg->seg.tso_frags[0].vaddr = tso_cmn_info->eit_hdr; + curr_seg->seg.tso_frags[0].length = tso_cmn_info->eit_hdr_len; + curr_seg->seg.total_len = curr_seg->seg.tso_frags[0].length; + curr_seg->seg.tso_frags[0].paddr = tso_cmn_info->eit_hdr_dma_map_addr; + + TSO_DEBUG("%s %d eit hdr %p eit_hdr_len %d tcp_seq_num %u tso_info->total_len %u\n", + __func__, __LINE__, tso_cmn_info->eit_hdr, + tso_cmn_info->eit_hdr_len, + curr_seg->seg.tso_flags.tcp_seq_num, + curr_seg->seg.total_len); + + +} + +/** + * __qdf_nbuf_get_tso_info() - function to divide a TSO nbuf + * into segments + * @nbuf: network buffer to be segmented + * @tso_info: This is the output. The information about the + * TSO segments will be populated within this. + * + * This function fragments a TCP jumbo packet into smaller + * segments to be transmitted by the driver. It chains the TSO + * segments created into a list. + * + * Return: number of TSO segments + */ +uint32_t __qdf_nbuf_get_tso_info(qdf_device_t osdev, struct sk_buff *skb, + struct qdf_tso_info_t *tso_info) +{ + /* common accross all segments */ + struct qdf_tso_cmn_seg_info_t tso_cmn_info; + /* segment specific */ + void *tso_frag_vaddr; + qdf_dma_addr_t tso_frag_paddr = 0; + uint32_t num_seg = 0; + struct qdf_tso_seg_elem_t *curr_seg; + struct qdf_tso_num_seg_elem_t *total_num_seg; + struct skb_frag_struct *frag = NULL; + uint32_t tso_frag_len = 0; /* tso segment's fragment length*/ + uint32_t skb_frag_len = 0; /* skb's fragment length (continous memory)*/ + uint32_t skb_proc = skb->len; /* bytes of skb pending processing */ + uint32_t tso_seg_size = skb_shinfo(skb)->gso_size; + int j = 0; /* skb fragment index */ + + memset(&tso_cmn_info, 0x0, sizeof(tso_cmn_info)); + + if (qdf_unlikely(__qdf_nbuf_get_tso_cmn_seg_info(osdev, + skb, &tso_cmn_info))) { + qdf_print("TSO: error getting common segment info\n"); + return 0; + } + total_num_seg = tso_info->tso_num_seg_list; + curr_seg = tso_info->tso_seg_list; + + /* length of the first chunk of data in the skb */ + skb_frag_len = skb_headlen(skb); + + /* the 0th tso segment's 0th fragment always contains the EIT header */ + /* update the remaining skb fragment length and TSO segment length */ + skb_frag_len -= tso_cmn_info.eit_hdr_len; + skb_proc -= tso_cmn_info.eit_hdr_len; + + /* get the address to the next tso fragment */ + tso_frag_vaddr = skb->data + tso_cmn_info.eit_hdr_len; + /* get the length of the next tso fragment */ + tso_frag_len = min(skb_frag_len, tso_seg_size); + tso_frag_paddr = dma_map_single(osdev->dev, + tso_frag_vaddr, tso_frag_len, DMA_TO_DEVICE); + TSO_DEBUG("%s[%d] skb frag len %d tso frag len %d\n", __func__, + __LINE__, skb_frag_len, tso_frag_len); + num_seg = tso_info->num_segs; + tso_info->num_segs = 0; + tso_info->is_tso = 1; + total_num_seg->num_seg.tso_cmn_num_seg = 0; + + while (num_seg && curr_seg) { + int i = 1; /* tso fragment index */ + uint8_t more_tso_frags = 1; + + tso_info->num_segs++; + total_num_seg->num_seg.tso_cmn_num_seg++; + + __qdf_nbuf_fill_tso_cmn_seg_info(curr_seg, + &tso_cmn_info); + + if (unlikely(skb_proc == 0)) + return tso_info->num_segs; + + curr_seg->seg.tso_flags.ip_len = tso_cmn_info.ip_tcp_hdr_len; + /* frag len is added to ip_len in while loop below*/ + + curr_seg->seg.num_frags++; + + while (more_tso_frags) { + curr_seg->seg.tso_frags[i].vaddr = tso_frag_vaddr; + curr_seg->seg.tso_frags[i].length = tso_frag_len; + curr_seg->seg.total_len += tso_frag_len; + curr_seg->seg.tso_flags.ip_len += tso_frag_len; + curr_seg->seg.num_frags++; + skb_proc = skb_proc - tso_frag_len; + + /* increment the TCP sequence number */ + tso_cmn_info.tcp_seq_num += tso_frag_len; + curr_seg->seg.tso_frags[i].paddr = tso_frag_paddr; + TSO_DEBUG("%s[%d] frag %d frag len %d total_len %u vaddr %p\n", + __func__, __LINE__, + i, + tso_frag_len, + curr_seg->seg.total_len, + curr_seg->seg.tso_frags[i].vaddr); + + /* if there is no more data left in the skb */ + if (!skb_proc) + return tso_info->num_segs; + + /* get the next payload fragment information */ + /* check if there are more fragments in this segment */ + if (tso_frag_len < tso_seg_size) { + tso_seg_size = tso_seg_size - tso_frag_len; + more_tso_frags = 1; + i++; + } else { + more_tso_frags = 0; + /* reset i and the tso payload size */ + i = 1; + tso_seg_size = skb_shinfo(skb)->gso_size; + } + + /* if the next fragment is contiguous */ + if (tso_frag_len < skb_frag_len) { + tso_frag_vaddr = tso_frag_vaddr + tso_frag_len; + skb_frag_len = skb_frag_len - tso_frag_len; + tso_frag_len = min(skb_frag_len, tso_seg_size); + + } else { /* the next fragment is not contiguous */ + if (skb_shinfo(skb)->nr_frags == 0) { + qdf_print("TSO: nr_frags == 0!\n"); + qdf_assert(0); + return 0; + } + if (j >= skb_shinfo(skb)->nr_frags) { + qdf_print("TSO: nr_frags %d j %d\n", + skb_shinfo(skb)->nr_frags, j); + qdf_assert(0); + return 0; + } + frag = &skb_shinfo(skb)->frags[j]; + skb_frag_len = skb_frag_size(frag); + tso_frag_len = min(skb_frag_len, tso_seg_size); + tso_frag_vaddr = skb_frag_address_safe(frag); + j++; + } + TSO_DEBUG("%s[%d] skb frag len %d tso frag %d len tso_seg_size %d\n", + __func__, __LINE__, skb_frag_len, tso_frag_len, + tso_seg_size); + + tso_frag_paddr = + dma_map_single(osdev->dev, + tso_frag_vaddr, + tso_frag_len, + DMA_TO_DEVICE); + if (unlikely(dma_mapping_error(osdev->dev, + tso_frag_paddr))) { + qdf_print("DMA mapping error!\n"); + qdf_assert(0); + return 0; + } + } + num_seg--; + /* if TCP FIN flag was set, set it in the last segment */ + if (!num_seg) + curr_seg->seg.tso_flags.fin = tso_cmn_info.tcphdr->fin; + + curr_seg = curr_seg->next; + } + return tso_info->num_segs; +} +EXPORT_SYMBOL(__qdf_nbuf_get_tso_info); + +/** + * __qdf_nbuf_unmap_tso_segment() - function to dma unmap TSO segment element + * + * @osdev: qdf device handle + * @tso_seg: TSO segment element to be unmapped + * @is_last_seg: whether this is last tso seg or not + * + * Return: none + */ +void __qdf_nbuf_unmap_tso_segment(qdf_device_t osdev, + struct qdf_tso_seg_elem_t *tso_seg, + bool is_last_seg) +{ + uint32_t num_frags = 0; + + if (tso_seg->seg.num_frags > 0) + num_frags = tso_seg->seg.num_frags - 1; + + /*Num of frags in a tso seg cannot be less than 2 */ + if (num_frags < 1) { + qdf_assert(0); + qdf_print("ERROR: num of frags in a tso segment is %d\n", + (num_frags + 1)); + return; + } + + while (num_frags) { + /*Do dma unmap the tso seg except the 0th frag */ + if (0 == tso_seg->seg.tso_frags[num_frags].paddr) { + qdf_print("ERROR: TSO seg frag %d mapped physical address is NULL\n", + num_frags); + qdf_assert(0); + return; + } + qdf_tso_seg_dbg_record(tso_seg, TSOSEG_LOC_UNMAPTSO); + dma_unmap_single(osdev->dev, + tso_seg->seg.tso_frags[num_frags].paddr, + tso_seg->seg.tso_frags[num_frags].length, + QDF_DMA_TO_DEVICE); + tso_seg->seg.tso_frags[num_frags].paddr = 0; + num_frags--; + } + + if (is_last_seg) { + /*Do dma unmap for the tso seg 0th frag */ + if (0 == tso_seg->seg.tso_frags[0].paddr) { + qdf_print("ERROR: TSO seg frag 0 mapped physical address is NULL\n"); + qdf_assert(0); + return; + } + dma_unmap_single(osdev->dev, + tso_seg->seg.tso_frags[0].paddr, + tso_seg->seg.tso_frags[0].length, + QDF_DMA_TO_DEVICE); + tso_seg->seg.tso_frags[0].paddr = 0; + } +} +EXPORT_SYMBOL(__qdf_nbuf_unmap_tso_segment); + +/** + * __qdf_nbuf_get_tso_num_seg() - function to divide a TSO nbuf + * into segments + * @nbuf: network buffer to be segmented + * @tso_info: This is the output. The information about the + * TSO segments will be populated within this. + * + * This function fragments a TCP jumbo packet into smaller + * segments to be transmitted by the driver. It chains the TSO + * segments created into a list. + * + * Return: 0 - success, 1 - failure + */ +uint32_t __qdf_nbuf_get_tso_num_seg(struct sk_buff *skb) +{ + uint32_t gso_size, tmp_len, num_segs = 0; + + gso_size = skb_shinfo(skb)->gso_size; + tmp_len = skb->len - ((skb_transport_header(skb) - skb_mac_header(skb)) + + tcp_hdrlen(skb)); + while (tmp_len) { + num_segs++; + if (tmp_len > gso_size) + tmp_len -= gso_size; + else + break; + } + return num_segs; +} +EXPORT_SYMBOL(__qdf_nbuf_get_tso_num_seg); + +#endif /* FEATURE_TSO */ + +struct sk_buff *__qdf_nbuf_inc_users(struct sk_buff *skb) +{ + atomic_inc(&skb->users); + return skb; +} +EXPORT_SYMBOL(__qdf_nbuf_inc_users); + +int __qdf_nbuf_get_users(struct sk_buff *skb) +{ + return atomic_read(&skb->users); +} +EXPORT_SYMBOL(__qdf_nbuf_get_users); + +/** + * __qdf_nbuf_ref() - Reference the nbuf so it can get held until the last free. + * @skb: sk_buff handle + * + * Return: none + */ + +void __qdf_nbuf_ref(struct sk_buff *skb) +{ + skb_get(skb); +} +EXPORT_SYMBOL(__qdf_nbuf_ref); + +/** + * __qdf_nbuf_shared() - Check whether the buffer is shared + * @skb: sk_buff buffer + * + * Return: true if more than one person has a reference to this buffer. + */ +int __qdf_nbuf_shared(struct sk_buff *skb) +{ + return skb_shared(skb); +} +EXPORT_SYMBOL(__qdf_nbuf_shared); + +/** + * __qdf_nbuf_dmamap_create() - create a DMA map. + * @osdev: qdf device handle + * @dmap: dma map handle + * + * This can later be used to map networking buffers. They : + * - need space in adf_drv's software descriptor + * - are typically created during adf_drv_create + * - need to be created before any API(qdf_nbuf_map) that uses them + * + * Return: QDF STATUS + */ +QDF_STATUS +__qdf_nbuf_dmamap_create(qdf_device_t osdev, __qdf_dma_map_t *dmap) +{ + QDF_STATUS error = QDF_STATUS_SUCCESS; + /* + * driver can tell its SG capablity, it must be handled. + * Bounce buffers if they are there + */ + (*dmap) = kzalloc(sizeof(struct __qdf_dma_map), GFP_KERNEL); + if (!(*dmap)) + error = QDF_STATUS_E_NOMEM; + + return error; +} +EXPORT_SYMBOL(__qdf_nbuf_dmamap_create); +/** + * __qdf_nbuf_dmamap_destroy() - delete a dma map + * @osdev: qdf device handle + * @dmap: dma map handle + * + * Return: none + */ +void +__qdf_nbuf_dmamap_destroy(qdf_device_t osdev, __qdf_dma_map_t dmap) +{ + kfree(dmap); +} +EXPORT_SYMBOL(__qdf_nbuf_dmamap_destroy); + +/** + * __qdf_nbuf_map_nbytes_single() - map nbytes + * @osdev: os device + * @buf: buffer + * @dir: direction + * @nbytes: number of bytes + * + * Return: QDF_STATUS + */ +#ifdef A_SIMOS_DEVHOST +QDF_STATUS __qdf_nbuf_map_nbytes_single( + qdf_device_t osdev, struct sk_buff *buf, + qdf_dma_dir_t dir, int nbytes) +{ + qdf_dma_addr_t paddr; + + QDF_NBUF_CB_PADDR(buf) = paddr = buf->data; + return QDF_STATUS_SUCCESS; +} +EXPORT_SYMBOL(__qdf_nbuf_map_nbytes_single); +#else +QDF_STATUS __qdf_nbuf_map_nbytes_single( + qdf_device_t osdev, struct sk_buff *buf, + qdf_dma_dir_t dir, int nbytes) +{ + qdf_dma_addr_t paddr; + + /* assume that the OS only provides a single fragment */ + QDF_NBUF_CB_PADDR(buf) = paddr = + dma_map_single(osdev->dev, buf->data, + nbytes, dir); + return dma_mapping_error(osdev->dev, paddr) ? + QDF_STATUS_E_FAULT : QDF_STATUS_SUCCESS; +} +EXPORT_SYMBOL(__qdf_nbuf_map_nbytes_single); +#endif +/** + * __qdf_nbuf_unmap_nbytes_single() - unmap nbytes + * @osdev: os device + * @buf: buffer + * @dir: direction + * @nbytes: number of bytes + * + * Return: none + */ +#if defined(A_SIMOS_DEVHOST) +void +__qdf_nbuf_unmap_nbytes_single( + qdf_device_t osdev, struct sk_buff *buf, qdf_dma_dir_t dir, int nbytes) +{ + return; +} +EXPORT_SYMBOL(__qdf_nbuf_unmap_nbytes_single); + +#else +void +__qdf_nbuf_unmap_nbytes_single( + qdf_device_t osdev, struct sk_buff *buf, qdf_dma_dir_t dir, int nbytes) +{ + if (0 == QDF_NBUF_CB_PADDR(buf)) { + qdf_print("ERROR: NBUF mapped physical address is NULL\n"); + return; + } + dma_unmap_single(osdev->dev, QDF_NBUF_CB_PADDR(buf), + nbytes, dir); +} +EXPORT_SYMBOL(__qdf_nbuf_unmap_nbytes_single); +#endif +/** + * __qdf_nbuf_map_nbytes() - get the dma map of the nbuf + * @osdev: os device + * @skb: skb handle + * @dir: dma direction + * @nbytes: number of bytes to be mapped + * + * Return: QDF_STATUS + */ +#ifdef QDF_OS_DEBUG +QDF_STATUS +__qdf_nbuf_map_nbytes( + qdf_device_t osdev, + struct sk_buff *skb, + qdf_dma_dir_t dir, + int nbytes) +{ + struct skb_shared_info *sh = skb_shinfo(skb); + qdf_assert((dir == QDF_DMA_TO_DEVICE) || (dir == QDF_DMA_FROM_DEVICE)); + + /* + * Assume there's only a single fragment. + * To support multiple fragments, it would be necessary to change + * adf_nbuf_t to be a separate object that stores meta-info + * (including the bus address for each fragment) and a pointer + * to the underlying sk_buff. + */ + qdf_assert(sh->nr_frags == 0); + + return __qdf_nbuf_map_nbytes_single(osdev, skb, dir, nbytes); +} +EXPORT_SYMBOL(__qdf_nbuf_map_nbytes); +#else +QDF_STATUS +__qdf_nbuf_map_nbytes( + qdf_device_t osdev, + struct sk_buff *skb, + qdf_dma_dir_t dir, + int nbytes) +{ + return __qdf_nbuf_map_nbytes_single(osdev, skb, dir, nbytes); +} +EXPORT_SYMBOL(__qdf_nbuf_map_nbytes); +#endif +/** + * __qdf_nbuf_unmap_nbytes() - to unmap a previously mapped buf + * @osdev: OS device + * @skb: skb handle + * @dir: direction + * @nbytes: number of bytes + * + * Return: none + */ +void +__qdf_nbuf_unmap_nbytes( + qdf_device_t osdev, + struct sk_buff *skb, + qdf_dma_dir_t dir, + int nbytes) +{ + qdf_assert((dir == QDF_DMA_TO_DEVICE) || (dir == QDF_DMA_FROM_DEVICE)); + + /* + * Assume there's a single fragment. + * If this is not true, the assertion in __adf_nbuf_map will catch it. + */ + __qdf_nbuf_unmap_nbytes_single(osdev, skb, dir, nbytes); +} +EXPORT_SYMBOL(__qdf_nbuf_unmap_nbytes); + +/** + * __qdf_nbuf_dma_map_info() - return the dma map info + * @bmap: dma map + * @sg: dma map info + * + * Return: none + */ +void +__qdf_nbuf_dma_map_info(__qdf_dma_map_t bmap, qdf_dmamap_info_t *sg) +{ + qdf_assert(bmap->mapped); + qdf_assert(bmap->nsegs <= QDF_MAX_SCATTER); + + memcpy(sg->dma_segs, bmap->seg, bmap->nsegs * + sizeof(struct __qdf_segment)); + sg->nsegs = bmap->nsegs; +} +EXPORT_SYMBOL(__qdf_nbuf_dma_map_info); +/** + * __qdf_nbuf_frag_info() - return the frag data & len, where frag no. is + * specified by the index + * @skb: sk buff + * @sg: scatter/gather list of all the frags + * + * Return: none + */ +#if defined(__QDF_SUPPORT_FRAG_MEM) +void +__qdf_nbuf_frag_info(struct sk_buff *skb, qdf_sglist_t *sg) +{ + qdf_assert(skb != NULL); + sg->sg_segs[0].vaddr = skb->data; + sg->sg_segs[0].len = skb->len; + sg->nsegs = 1; + + for (int i = 1; i <= sh->nr_frags; i++) { + skb_frag_t *f = &sh->frags[i - 1]; + sg->sg_segs[i].vaddr = (uint8_t *)(page_address(f->page) + + f->page_offset); + sg->sg_segs[i].len = f->size; + + qdf_assert(i < QDF_MAX_SGLIST); + } + sg->nsegs += i; + +} +EXPORT_SYMBOL(__qdf_nbuf_frag_info); +#else +#ifdef QDF_OS_DEBUG +void +__qdf_nbuf_frag_info(struct sk_buff *skb, qdf_sglist_t *sg) +{ + + struct skb_shared_info *sh = skb_shinfo(skb); + + qdf_assert(skb != NULL); + sg->sg_segs[0].vaddr = skb->data; + sg->sg_segs[0].len = skb->len; + sg->nsegs = 1; + + qdf_assert(sh->nr_frags == 0); +} +EXPORT_SYMBOL(__qdf_nbuf_frag_info); +#else +void +__qdf_nbuf_frag_info(struct sk_buff *skb, qdf_sglist_t *sg) +{ + sg->sg_segs[0].vaddr = skb->data; + sg->sg_segs[0].len = skb->len; + sg->nsegs = 1; +} +EXPORT_SYMBOL(__qdf_nbuf_frag_info); +#endif +#endif +/** + * __qdf_nbuf_get_frag_size() - get frag size + * @nbuf: sk buffer + * @cur_frag: current frag + * + * Return: frag size + */ +uint32_t +__qdf_nbuf_get_frag_size(__qdf_nbuf_t nbuf, uint32_t cur_frag) +{ + struct skb_shared_info *sh = skb_shinfo(nbuf); + const skb_frag_t *frag = sh->frags + cur_frag; + return skb_frag_size(frag); +} +EXPORT_SYMBOL(__qdf_nbuf_get_frag_size); + +/** + * __qdf_nbuf_frag_map() - dma map frag + * @osdev: os device + * @nbuf: sk buff + * @offset: offset + * @dir: direction + * @cur_frag: current fragment + * + * Return: QDF status + */ +#ifdef A_SIMOS_DEVHOST +QDF_STATUS __qdf_nbuf_frag_map( + qdf_device_t osdev, __qdf_nbuf_t nbuf, + int offset, qdf_dma_dir_t dir, int cur_frag) +{ + int32_t paddr, frag_len; + + QDF_NBUF_CB_PADDR(nbuf) = paddr = nbuf->data; + return QDF_STATUS_SUCCESS; +} +EXPORT_SYMBOL(__qdf_nbuf_frag_map); +#else +QDF_STATUS __qdf_nbuf_frag_map( + qdf_device_t osdev, __qdf_nbuf_t nbuf, + int offset, qdf_dma_dir_t dir, int cur_frag) +{ + dma_addr_t paddr, frag_len; + + struct skb_shared_info *sh = skb_shinfo(nbuf); + const skb_frag_t *frag = sh->frags + cur_frag; + frag_len = skb_frag_size(frag); + + QDF_NBUF_CB_TX_EXTRA_FRAG_PADDR(nbuf) = paddr = + skb_frag_dma_map(osdev->dev, frag, offset, frag_len, dir); + return dma_mapping_error(osdev->dev, paddr) ? + QDF_STATUS_E_FAULT : QDF_STATUS_SUCCESS; +} +EXPORT_SYMBOL(__qdf_nbuf_frag_map); +#endif +/** + * __qdf_nbuf_dmamap_set_cb() - setup the map callback for a dma map + * @dmap: dma map + * @cb: callback + * @arg: argument + * + * Return: none + */ +void +__qdf_nbuf_dmamap_set_cb(__qdf_dma_map_t dmap, void *cb, void *arg) +{ + return; +} +EXPORT_SYMBOL(__qdf_nbuf_dmamap_set_cb); + + +#ifndef REMOVE_INIT_DEBUG_CODE +/** + * __qdf_nbuf_sync_single_for_cpu() - nbuf sync + * @osdev: os device + * @buf: sk buff + * @dir: direction + * + * Return: none + */ +#if defined(A_SIMOS_DEVHOST) +static void __qdf_nbuf_sync_single_for_cpu( + qdf_device_t osdev, qdf_nbuf_t buf, qdf_dma_dir_t dir) +{ + return; +} +#else +static void __qdf_nbuf_sync_single_for_cpu( + qdf_device_t osdev, qdf_nbuf_t buf, qdf_dma_dir_t dir) +{ + if (0 == QDF_NBUF_CB_PADDR(buf)) { + qdf_print("ERROR: NBUF mapped physical address is NULL\n"); + return; + } + dma_sync_single_for_cpu(osdev->dev, QDF_NBUF_CB_PADDR(buf), + skb_end_offset(buf) - skb_headroom(buf), dir); +} +#endif +/** + * __qdf_nbuf_sync_for_cpu() - nbuf sync + * @osdev: os device + * @skb: sk buff + * @dir: direction + * + * Return: none + */ +void +__qdf_nbuf_sync_for_cpu(qdf_device_t osdev, + struct sk_buff *skb, qdf_dma_dir_t dir) +{ + qdf_assert( + (dir == QDF_DMA_TO_DEVICE) || (dir == QDF_DMA_FROM_DEVICE)); + + /* + * Assume there's a single fragment. + * If this is not true, the assertion in __adf_nbuf_map will catch it. + */ + __qdf_nbuf_sync_single_for_cpu(osdev, skb, dir); +} +EXPORT_SYMBOL(__qdf_nbuf_sync_for_cpu); +#endif + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)) +/** + * qdf_nbuf_update_radiotap_vht_flags() - Update radiotap header VHT flags + * @rx_status: Pointer to rx_status. + * @rtap_buf: Buf to which VHT info has to be updated. + * @rtap_len: Current length of radiotap buffer + * + * Return: Length of radiotap after VHT flags updated. + */ +static unsigned int qdf_nbuf_update_radiotap_vht_flags( + struct mon_rx_status *rx_status, + int8_t *rtap_buf, + uint32_t rtap_len) +{ + uint16_t vht_flags = 0; + + /* IEEE80211_RADIOTAP_VHT u16, u8, u8, u8[4], u8, u8, u16 */ + vht_flags |= IEEE80211_RADIOTAP_VHT_KNOWN_STBC | + IEEE80211_RADIOTAP_VHT_KNOWN_GI | + IEEE80211_RADIOTAP_VHT_KNOWN_LDPC_EXTRA_OFDM_SYM | + IEEE80211_RADIOTAP_VHT_KNOWN_BEAMFORMED | + IEEE80211_RADIOTAP_VHT_KNOWN_BANDWIDTH; + put_unaligned_le16(vht_flags, &rtap_buf[rtap_len]); + rtap_len += 2; + + rtap_buf[rtap_len] |= + (rx_status->is_stbc ? + IEEE80211_RADIOTAP_VHT_FLAG_STBC : 0) | + (rx_status->sgi ? IEEE80211_RADIOTAP_VHT_FLAG_SGI : 0) | + (rx_status->ldpc ? + IEEE80211_RADIOTAP_VHT_FLAG_LDPC_EXTRA_OFDM_SYM : 0) | + (rx_status->beamformed ? + IEEE80211_RADIOTAP_VHT_FLAG_BEAMFORMED : 0); + rtap_len += 1; + + rtap_buf[rtap_len] = (rx_status->vht_flag_values2); + rtap_len += 1; + rtap_buf[rtap_len] = (rx_status->vht_flag_values3[0]); + rtap_len += 1; + rtap_buf[rtap_len] = (rx_status->vht_flag_values3[1]); + rtap_len += 1; + rtap_buf[rtap_len] = (rx_status->vht_flag_values3[2]); + rtap_len += 1; + rtap_buf[rtap_len] = (rx_status->vht_flag_values3[3]); + rtap_len += 1; + rtap_buf[rtap_len] = (rx_status->vht_flag_values4); + rtap_len += 1; + rtap_buf[rtap_len] = (rx_status->vht_flag_values5); + rtap_len += 1; + put_unaligned_le16(rx_status->vht_flag_values6, + &rtap_buf[rtap_len]); + rtap_len += 2; + + return rtap_len; +} + +#define NORMALIZED_TO_NOISE_FLOOR (-96) + +/* This is the length for radiotap, combined length + * (Mandatory part struct ieee80211_radiotap_header + RADIOTAP_HEADER_LEN) + * cannot be more than available headroom_sz. + * Max size current radiotap we are populating is less than 100 bytes, + * increase this when we add more radiotap elements. + */ +#define RADIOTAP_HEADER_LEN (sizeof(struct ieee80211_radiotap_header) + 100) + +/** + * qdf_nbuf_update_radiotap() - Update radiotap header from rx_status + * @rx_status: Pointer to rx_status. + * @nbuf: nbuf pointer to which radiotap has to be updated + * @headroom_sz: Available headroom size. + * + * Return: length of rtap_len updated. + */ +unsigned int qdf_nbuf_update_radiotap(struct mon_rx_status *rx_status, + qdf_nbuf_t nbuf, uint32_t headroom_sz) +{ + uint8_t rtap_buf[RADIOTAP_HEADER_LEN] = {0}; + struct ieee80211_radiotap_header *rthdr = + (struct ieee80211_radiotap_header *)rtap_buf; + uint32_t rtap_hdr_len = sizeof(struct ieee80211_radiotap_header); + uint32_t rtap_len = rtap_hdr_len; + + /* IEEE80211_RADIOTAP_TSFT __le64 microseconds*/ + rthdr->it_present = cpu_to_le32(1 << IEEE80211_RADIOTAP_TSFT); + put_unaligned_le64(rx_status->tsft, &rtap_buf[rtap_len]); + rtap_len += 8; + + /* IEEE80211_RADIOTAP_FLAGS u8 */ + rthdr->it_present |= cpu_to_le32(1 << IEEE80211_RADIOTAP_FLAGS); + rtap_buf[rtap_len] = rx_status->rtap_flags; + rtap_len += 1; + + /* IEEE80211_RADIOTAP_RATE u8 500kb/s */ + if (!rx_status->ht_flags && !rx_status->vht_flags) { + rthdr->it_present |= cpu_to_le32(1 << IEEE80211_RADIOTAP_RATE); + rtap_buf[rtap_len] = rx_status->rate; + } else + rtap_buf[rtap_len] = 0; + rtap_len += 1; + + /* IEEE80211_RADIOTAP_CHANNEL 2 x __le16 MHz, bitmap */ + rthdr->it_present |= cpu_to_le32(1 << IEEE80211_RADIOTAP_CHANNEL); + put_unaligned_le16(rx_status->chan_freq, &rtap_buf[rtap_len]); + rtap_len += 2; + /* Channel flags. */ + put_unaligned_le16(rx_status->chan_flags, &rtap_buf[rtap_len]); + rtap_len += 2; + + /* IEEE80211_RADIOTAP_DBM_ANTSIGNAL s8 decibels from one milliwatt + * (dBm) + */ + rthdr->it_present |= cpu_to_le32(1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL); + /* + * rssi_comb is int dB, need to convert it to dBm. + * normalize value to noise floor of -96 dBm + */ + rtap_buf[rtap_len] = rx_status->ant_signal_db + + NORMALIZED_TO_NOISE_FLOOR; + rtap_len += 1; + + /* IEEE80211_RADIOTAP_ANTENNA u8 antenna index */ + rthdr->it_present |= cpu_to_le32(1 << IEEE80211_RADIOTAP_ANTENNA); + rtap_buf[rtap_len] = rx_status->nr_ant; + rtap_len += 1; + + if (rx_status->ht_flags) { + /* IEEE80211_RADIOTAP_VHT u8, u8, u8 */ + rthdr->it_present |= cpu_to_le32(1 << IEEE80211_RADIOTAP_MCS); + rtap_buf[rtap_len] = IEEE80211_RADIOTAP_MCS_HAVE_BW | + IEEE80211_RADIOTAP_MCS_HAVE_MCS | + IEEE80211_RADIOTAP_MCS_HAVE_GI; + rtap_len += 1; + + if (rx_status->sgi) + rtap_buf[rtap_len] |= IEEE80211_RADIOTAP_MCS_SGI; + if (rx_status->bw) + rtap_buf[rtap_len] |= IEEE80211_RADIOTAP_MCS_BW_40; + rtap_len += 1; + + rtap_buf[rtap_len] = rx_status->mcs; + rtap_len += 1; + } + + if (rx_status->vht_flags) { + /* IEEE80211_RADIOTAP_VHT u16, u8, u8, u8[4], u8, u8, u16 */ + rthdr->it_present |= cpu_to_le32(1 << IEEE80211_RADIOTAP_VHT); + rtap_len = qdf_nbuf_update_radiotap_vht_flags(rx_status, + rtap_buf, + rtap_len); + } + rthdr->it_len = cpu_to_le16(rtap_len); + + if ((headroom_sz - rtap_len) < 0) { + qdf_print("ERROR: not enough space to update radiotap\n"); + return 0; + } + qdf_nbuf_pull_head(nbuf, headroom_sz - rtap_len); + qdf_mem_copy(qdf_nbuf_data(nbuf), rtap_buf, rtap_len); + return rtap_len; +} +#else +static unsigned int qdf_nbuf_update_radiotap_vht_flags( + struct mon_rx_status *rx_status, + int8_t *rtap_buf, + uint32_t rtap_len) +{ + qdf_print("ERROR: struct ieee80211_radiotap_header not supported"); + return 0; +} + +unsigned int qdf_nbuf_update_radiotap(struct mon_rx_status *rx_status, + qdf_nbuf_t nbuf, uint32_t headroom_sz) +{ + qdf_print("ERROR: struct ieee80211_radiotap_header not supported"); + return 0; +} +#endif + +/** + * __qdf_nbuf_reg_free_cb() - register nbuf free callback + * @cb_func_ptr: function pointer to the nbuf free callback + * + * This function registers a callback function for nbuf free. + * + * Return: none + */ +void __qdf_nbuf_reg_free_cb(qdf_nbuf_free_t cb_func_ptr) +{ + nbuf_free_cb = cb_func_ptr; + return; +} diff --git a/drivers/staging/qca-wifi-host-cmn/qdf/linux/src/qdf_perf.c b/drivers/staging/qca-wifi-host-cmn/qdf/linux/src/qdf_perf.c new file mode 100644 index 0000000000000000000000000000000000000000..4705aac0810cc7bbf0b40fe0e3d2a4b26c1dca33 --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/qdf/linux/src/qdf_perf.c @@ -0,0 +1,198 @@ +/* + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: qdf_perf + * This file provides OS dependent perf API's. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#ifdef QCA_PERF_PROFILING + +qdf_perf_entry_t perf_root = {{0, 0} }; + +/** + * qdf_perfmod_init() - Module init + * + * return: int + */ +int +qdf_perfmod_init(void) +{ + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO, + "Perf Debug Module Init"); + INIT_LIST_HEAD(&perf_root.list); + INIT_LIST_HEAD(&perf_root.child); + perf_root.proc = proc_mkdir(PROCFS_PERF_DIRNAME, 0); + return 0; +} +EXPORT_SYMBOL(qdf_perfmod_init); + +/** + * qdf_perfmod_exit() - Module exit + * + * Return: none + */ +void +qdf_perfmod_exit(void) +{ + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO, + "Perf Debug Module Exit"); + remove_proc_entry(PROCFS_PERF_DIRNAME, 0); +} +EXPORT_SYMBOL(qdf_perfmod_exit); + +/** + * __qdf_perf_init() - Create the perf entry + * @parent: parent perf id + * @id_name: name of perf id + * @type: type of perf counter + * + * return: perf id + */ +qdf_perf_id_t +__qdf_perf_init(qdf_perf_id_t parent, uint8_t *id_name, + qdf_perf_cntr_t type) +{ + qdf_perf_entry_t *entry = NULL; + qdf_perf_entry_t *pentry = PERF_ENTRY(parent); + + if (type >= CNTR_LAST) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s:%s Invalid perf-type", __FILE__, __func__); + goto done; + } + + if (!pentry) + pentry = &perf_root; + entry = kmalloc(sizeof(struct qdf_perf_entry), GFP_ATOMIC); + + if (!entry) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + " Out of Memory,:%s", __func__); + return NULL; + } + + memset(entry, 0, sizeof(struct qdf_perf_entry)); + + INIT_LIST_HEAD(&entry->list); + INIT_LIST_HEAD(&entry->child); + + spin_lock_init(&entry->lock_irq); + + list_add_tail(&entry->list, &pentry->child); + + entry->name = id_name; + entry->type = type; + + if (type == CNTR_GROUP) { + entry->proc = proc_mkdir(id_name, pentry->proc); + goto done; + } + + entry->parent = pentry; + entry->proc = create_proc_entry(id_name, S_IFREG|S_IRUGO|S_IWUSR, + pentry->proc); + entry->proc->data = entry; + entry->proc->read_proc = api_tbl[type].proc_read; + entry->proc->write_proc = api_tbl[type].proc_write; + + /* + * Initialize the Event with default values + */ + api_tbl[type].init(entry, api_tbl[type].def_val); + +done: + return entry; +} +EXPORT_SYMBOL(__qdf_perf_init); + +/** + * __qdf_perf_destroy - Destroy the perf entry + * @id: pointer to qdf_perf_id_t + * + * @return: bool + */ +bool __qdf_perf_destroy(qdf_perf_id_t id) +{ + qdf_perf_entry_t *entry = PERF_ENTRY(id), + *parent = entry->parent; + + if (!list_empty(&entry->child)) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "Child's are alive, Can't delete"); + return A_FALSE; + } + + remove_proc_entry(entry->name, parent->proc); + + list_del(&entry->list); + + vfree(entry); + + return true; +} +EXPORT_SYMBOL(__qdf_perf_destroy); + +/** + * __qdf_perf_start - Start the sampling + * @id: Instance of qdf_perf_id_t + * + * Returns: none + */ +void __qdf_perf_start(qdf_perf_id_t id) +{ + qdf_perf_entry_t *entry = PERF_ENTRY(id); + + api_tbl[entry->type].sample(entry, 0); +} +EXPORT_SYMBOL(__qdf_perf_start); + +/** + * __qdf_perf_end - Stop sampling + * @id: Instance of qdf_perf_id_t + * + * Returns: none + */ +void __qdf_perf_end(qdf_perf_id_t id) +{ + qdf_perf_entry_t *entry = PERF_ENTRY(id); + + api_tbl[entry->type].sample(entry, 1); +} +EXPORT_SYMBOL(__qdf_perf_end); + +#endif /* QCA_PERF_PROFILING */ diff --git a/drivers/staging/qca-wifi-host-cmn/qdf/linux/src/qdf_threads.c b/drivers/staging/qca-wifi-host-cmn/qdf/linux/src/qdf_threads.c new file mode 100644 index 0000000000000000000000000000000000000000..679af0cab07d11c71f162ee35d2e62385ab6e8b4 --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/qdf/linux/src/qdf_threads.c @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2014-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: qdf_threads + * QCA driver framework (QDF) thread APIs + */ + +/* Include Files */ +#include +#include +#include +#include +#include +#include +#include +#include + +/* Function declarations and documenation */ + +/** + * qdf_sleep() - sleep + * @ms_interval : Number of milliseconds to suspend the current thread. + * A value of 0 may or may not cause the current thread to yield. + * + * This function suspends the execution of the current thread + * until the specified time out interval elapses. + * + * Return: none + */ +void qdf_sleep(uint32_t ms_interval) +{ + if (in_interrupt()) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s cannot be called from interrupt context!!!", + __func__); + return; + } + msleep_interruptible(ms_interval); +} +EXPORT_SYMBOL(qdf_sleep); + +/** + * qdf_sleep_us() - sleep + * @us_interval : Number of microseconds to suspend the current thread. + * A value of 0 may or may not cause the current thread to yield. + * + * This function suspends the execution of the current thread + * until the specified time out interval elapses. + * + * Return : none + */ +void qdf_sleep_us(uint32_t us_interval) +{ + unsigned long timeout = usecs_to_jiffies(us_interval) + 1; + if (in_interrupt()) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s cannot be called from interrupt context!!!", + __func__); + return; + } + + while (timeout && !signal_pending(current)) + timeout = schedule_timeout_interruptible(timeout); +} +EXPORT_SYMBOL(qdf_sleep_us); + +/** + * qdf_busy_wait() - busy wait + * @us_interval : Number of microseconds to busy wait. + * + * This function places the current thread in busy wait until the specified + * time out interval elapses. If the interval is greater than 50us on WM, the + * behaviour is undefined. + * + * Return : none + */ +void qdf_busy_wait(uint32_t us_interval) +{ + udelay(us_interval); +} +EXPORT_SYMBOL(qdf_busy_wait); diff --git a/drivers/staging/qca-wifi-host-cmn/qdf/linux/src/qdf_trace.c b/drivers/staging/qca-wifi-host-cmn/qdf/linux/src/qdf_trace.c new file mode 100644 index 0000000000000000000000000000000000000000..eaf3d0c9e691f41a74a07a91150230812720bb72 --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/qdf/linux/src/qdf_trace.c @@ -0,0 +1,1723 @@ +/* + * Copyright (c) 2014-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: qdf_trace + * QCA driver framework (QDF) trace APIs + * Trace, logging, and debugging definitions and APIs + */ + +/* Include Files */ +#include +#include +#include "qdf_time.h" +#include "qdf_mc_timer.h" +/* Preprocessor definitions and constants */ + +#define QDF_TRACE_BUFFER_SIZE (512) + +enum qdf_timestamp_unit qdf_log_timestamp_type = QDF_LOG_TIMESTAMP_UNIT; + +/* macro to map qdf trace levels into the bitmask */ +#define QDF_TRACE_LEVEL_TO_MODULE_BITMASK(_level) ((1 << (_level))) + +/** + * typedef struct module_trace_info - Trace level for a module, as a bitmask. + * The bits in this mask are ordered by QDF_TRACE_LEVEL. For example, + * each bit represents one of the bits in QDF_TRACE_LEVEL that may be turned + * on to have traces at that level logged, i.e. if QDF_TRACE_LEVEL_ERROR is + * == 2, then if bit 2 (low order) is turned ON, then ERROR traces will be + * printed to the trace log. Note that all bits turned OFF means no traces + * @module_trace_level: trace level + * @module_name_str: 3 character string name for the module + */ +typedef struct { + uint16_t module_trace_level; + unsigned char module_name_str[4]; +} module_trace_info; + +#define QDF_DEFAULT_TRACE_LEVEL \ + ((1 << QDF_TRACE_LEVEL_FATAL) | (1 << QDF_TRACE_LEVEL_ERROR)) + +/* Array of static data that contains all of the per module trace + * information. This includes the trace level for the module and + * the 3 character 'name' of the module for marking the trace logs + */ +module_trace_info g_qdf_trace_info[QDF_MODULE_ID_MAX] = { + [QDF_MODULE_ID_TLSHIM] = {QDF_DEFAULT_TRACE_LEVEL, "DP"}, + [QDF_MODULE_ID_WMI] = {QDF_DEFAULT_TRACE_LEVEL, "WMI"}, + [QDF_MODULE_ID_HDD] = {QDF_DEFAULT_TRACE_LEVEL, "HDD"}, + [QDF_MODULE_ID_SME] = {QDF_DEFAULT_TRACE_LEVEL, "SME"}, + [QDF_MODULE_ID_PE] = {QDF_DEFAULT_TRACE_LEVEL, "PE "}, + [QDF_MODULE_ID_WMA] = {QDF_DEFAULT_TRACE_LEVEL, "WMA"}, + [QDF_MODULE_ID_SYS] = {QDF_DEFAULT_TRACE_LEVEL, "SYS"}, + [QDF_MODULE_ID_QDF] = {QDF_DEFAULT_TRACE_LEVEL, "QDF"}, + [QDF_MODULE_ID_SAP] = {QDF_DEFAULT_TRACE_LEVEL, "SAP"}, + [QDF_MODULE_ID_HDD_SOFTAP] = {QDF_DEFAULT_TRACE_LEVEL, "HSP"}, + [QDF_MODULE_ID_HDD_DATA] = {QDF_DEFAULT_TRACE_LEVEL, "HDP"}, + [QDF_MODULE_ID_HDD_SAP_DATA] = {QDF_DEFAULT_TRACE_LEVEL, "SDP"}, + [QDF_MODULE_ID_BMI] = {QDF_DEFAULT_TRACE_LEVEL, "BMI"}, + [QDF_MODULE_ID_HIF] = {QDF_DEFAULT_TRACE_LEVEL, "HIF"}, + [QDF_MODULE_ID_TXRX] = {QDF_DEFAULT_TRACE_LEVEL, "TRX"}, + [QDF_MODULE_ID_HTT] = {QDF_DEFAULT_TRACE_LEVEL, "HTT"}, +}; + +/* Static and Global variables */ +static spinlock_t ltrace_lock; + +static qdf_trace_record_t g_qdf_trace_tbl[MAX_QDF_TRACE_RECORDS]; +/* global qdf trace data */ +static t_qdf_trace_data g_qdf_trace_data; +/* + * all the call back functions for dumping MTRACE messages from ring buffer + * are stored in qdf_trace_cb_table,these callbacks are initialized during init + * only so, we will make a copy of these call back functions and maintain in to + * qdf_trace_restore_cb_table. Incase if we make modifications to + * qdf_trace_cb_table, we can certainly retrieve all the call back functions + * back from Restore Table + */ +static tp_qdf_trace_cb qdf_trace_cb_table[QDF_MODULE_ID_MAX]; +static tp_qdf_trace_cb qdf_trace_restore_cb_table[QDF_MODULE_ID_MAX]; +static tp_qdf_state_info_cb qdf_state_info_table[QDF_MODULE_ID_MAX]; + +#ifdef FEATURE_DP_TRACE +/* Static and Global variables */ +static spinlock_t l_dp_trace_lock; + +static struct qdf_dp_trace_record_s + g_qdf_dp_trace_tbl[MAX_QDF_DP_TRACE_RECORDS]; + +/* + * all the options to configure/control DP trace are + * defined in this structure + */ +static struct s_qdf_dp_trace_data g_qdf_dp_trace_data; +/* + * all the call back functions for dumping DPTRACE messages from ring buffer + * are stored in qdf_dp_trace_cb_table, callbacks are initialized during init + */ +static tp_qdf_dp_trace_cb qdf_dp_trace_cb_table[QDF_DP_TRACE_MAX+1]; +#endif +/** + * qdf_trace_set_level() - Set the trace level for a particular module + * @module: Module id + * @level : trace level + * + * Trace level is a member of the QDF_TRACE_LEVEL enumeration indicating + * the severity of the condition causing the trace message to be issued. + * More severe conditions are more likely to be logged. + * + * This is an external API that allows trace levels to be set for each module. + * + * Return: None + */ +void qdf_trace_set_level(QDF_MODULE_ID module, QDF_TRACE_LEVEL level) +{ + /* make sure the caller is passing in a valid LEVEL */ + if (level >= QDF_TRACE_LEVEL_MAX) { + pr_err("%s: Invalid trace level %d passed in!\n", __func__, + level); + return; + } + + /* Treat 'none' differently. NONE means we have to run off all + * the bits in the bit mask so none of the traces appear. Anything + * other than 'none' means we need to turn ON a bit in the bitmask + */ + if (QDF_TRACE_LEVEL_NONE == level) + g_qdf_trace_info[module].module_trace_level = + QDF_TRACE_LEVEL_NONE; + else + /* set the desired bit in the bit mask for the module trace + * level */ + g_qdf_trace_info[module].module_trace_level |= + QDF_TRACE_LEVEL_TO_MODULE_BITMASK(level); +} +EXPORT_SYMBOL(qdf_trace_set_level); + +/** + * qdf_trace_set_module_trace_level() - Set module trace level + * @module: Module id + * @level: Trace level for a module, as a bitmask as per 'module_trace_info' + * + * Sets the module trace level where the trace level is given as a bit mask + * + * Return: None + */ +void qdf_trace_set_module_trace_level(QDF_MODULE_ID module, uint32_t level) +{ + if (module < 0 || module >= QDF_MODULE_ID_MAX) { + pr_err("%s: Invalid module id %d passed\n", __func__, module); + return; + } + g_qdf_trace_info[module].module_trace_level = level; +} +EXPORT_SYMBOL(qdf_trace_set_module_trace_level); + +/** + * qdf_trace_set_value() - Set module trace value + * @module: Module id + * @level: Trace level for a module, as a bitmask as per 'module_trace_info' + * @on: set/clear the desired bit in the bit mask + * + * Return: None + */ +void qdf_trace_set_value(QDF_MODULE_ID module, QDF_TRACE_LEVEL level, + uint8_t on) +{ + /* make sure the caller is passing in a valid LEVEL */ + if (level < 0 || level >= QDF_TRACE_LEVEL_MAX) { + pr_err("%s: Invalid trace level %d passed in!\n", __func__, + level); + return; + } + + /* make sure the caller is passing in a valid module */ + if (module < 0 || module >= QDF_MODULE_ID_MAX) { + pr_err("%s: Invalid module id %d passed in!\n", __func__, + module); + return; + } + + /* Treat 'none' differently. NONE means we have to turn off all + the bits in the bit mask so none of the traces appear */ + if (QDF_TRACE_LEVEL_NONE == level) { + g_qdf_trace_info[module].module_trace_level = + QDF_TRACE_LEVEL_NONE; + } + /* Treat 'All' differently. All means we have to turn on all + the bits in the bit mask so all of the traces appear */ + else if (QDF_TRACE_LEVEL_ALL == level) { + g_qdf_trace_info[module].module_trace_level = 0xFFFF; + } else { + if (on) + /* set the desired bit in the bit mask for the module + trace level */ + g_qdf_trace_info[module].module_trace_level |= + QDF_TRACE_LEVEL_TO_MODULE_BITMASK(level); + else + /* clear the desired bit in the bit mask for the module + trace level */ + g_qdf_trace_info[module].module_trace_level &= + ~(QDF_TRACE_LEVEL_TO_MODULE_BITMASK(level)); + } +} +EXPORT_SYMBOL(qdf_trace_set_value); + +/** + * qdf_trace_get_level() - get the trace level + * @module: module Id + * @level: trace level + * + * This is an external API that returns a bool value to signify if a + * particular trace level is set for the specified module. + * A member of the QDF_TRACE_LEVEL enumeration indicating the severity + * of the condition causing the trace message to be issued. + * + * Note that individual trace levels are the only valid values + * for this API. QDF_TRACE_LEVEL_NONE and QDF_TRACE_LEVEL_ALL + * are not valid input and will return false + * + * Return: + * false - the specified trace level for the specified module is OFF + * true - the specified trace level for the specified module is ON + */ +bool qdf_trace_get_level(QDF_MODULE_ID module, QDF_TRACE_LEVEL level) +{ + bool trace_on = false; + + if ((QDF_TRACE_LEVEL_NONE == level) || + (QDF_TRACE_LEVEL_ALL == level) || (level >= QDF_TRACE_LEVEL_MAX)) { + trace_on = false; + } else { + trace_on = (level & g_qdf_trace_info[module].module_trace_level) + ? true : false; + } + + return trace_on; +} +EXPORT_SYMBOL(qdf_trace_get_level); + +/** + * qdf_snprintf() - wrapper function to snprintf + * @str_buffer: string Buffer + * @size: defines the size of the data record + * @str_format: Format string in which the message to be logged. This format + * string contains printf-like replacement parameters, which follow + * this parameter in the variable argument list. + * + * Return: None + */ +void qdf_snprintf(char *str_buffer, unsigned int size, char *str_format, ...) +{ + va_list val; + + va_start(val, str_format); + snprintf(str_buffer, size, str_format, val); + va_end(val); +} +EXPORT_SYMBOL(qdf_snprintf); + +#ifdef QDF_ENABLE_TRACING + +/** + * qdf_trace_msg() - externally called trace function + * @module: Module identifier a member of the QDF_MODULE_ID + * enumeration that identifies the module issuing the trace message. + * @level: Trace level a member of the QDF_TRACE_LEVEL enumeration + * indicating the severity of the condition causing the trace message + * to be issued. More severe conditions are more likely to be logged. + * @str_format: Format string in which the message to be logged. This format + * string contains printf-like replacement parameters, which follow + * this parameter in the variable argument list. + * + * Checks the level of severity and accordingly prints the trace messages + * + * Return: None + */ +void qdf_trace_msg(QDF_MODULE_ID module, QDF_TRACE_LEVEL level, + char *str_format, ...) +{ + char str_buffer[QDF_TRACE_BUFFER_SIZE]; + int n; + + /* Print the trace message when the desired level bit is set in + the module tracel level mask */ + if (g_qdf_trace_info[module].module_trace_level & + QDF_TRACE_LEVEL_TO_MODULE_BITMASK(level)) { + /* the trace level strings in an array. these are ordered in + * the same order as the trace levels are defined in the enum + * (see QDF_TRACE_LEVEL) so we can index into this array with + * the level and get the right string. The qdf trace levels + * are... none, Fatal, Error, Warning, Info, info_high, info_med, + * info_low, Debug + */ + static const char *TRACE_LEVEL_STR[] = { " ", "F ", "E ", "W ", + "I ", "IH", "IM", "IL", "D" }; + va_list val; + va_start(val, str_format); + + /* print the prefix string into the string buffer... */ + n = snprintf(str_buffer, QDF_TRACE_BUFFER_SIZE, + "wlan: [%d:%2s:%3s] ", + in_interrupt() ? 0 : current->pid, + (char *)TRACE_LEVEL_STR[level], + (char *)g_qdf_trace_info[module].module_name_str); + + /* print the formatted log message after the prefix string */ + if ((n >= 0) && (n < QDF_TRACE_BUFFER_SIZE)) { + vsnprintf(str_buffer + n, QDF_TRACE_BUFFER_SIZE - n, + str_format, val); +#if defined(WLAN_LOGGING_SOCK_SVC_ENABLE) + wlan_log_to_user(level, (char *)str_buffer, + strlen(str_buffer)); +#else + pr_err("%s\n", str_buffer); +#endif + } + va_end(val); + } +} +EXPORT_SYMBOL(qdf_trace_msg); + +/** + * qdf_trace_display() - Display trace + * + * Return: None + */ +void qdf_trace_display(void) +{ + QDF_MODULE_ID module_id; + + pr_err + (" 1)FATAL 2)ERROR 3)WARN 4)INFO 5)INFO_H 6)INFO_M 7)INFO_L 8)DEBUG\n"); + for (module_id = 0; module_id < QDF_MODULE_ID_MAX; ++module_id) { + pr_err + ("%2d)%s %s %s %s %s %s %s %s %s\n", + (int)module_id, g_qdf_trace_info[module_id].module_name_str, + (g_qdf_trace_info[module_id]. + module_trace_level & (1 << QDF_TRACE_LEVEL_FATAL)) ? "X" : + " ", + (g_qdf_trace_info[module_id]. + module_trace_level & (1 << QDF_TRACE_LEVEL_ERROR)) ? "X" : + " ", + (g_qdf_trace_info[module_id]. + module_trace_level & (1 << QDF_TRACE_LEVEL_WARN)) ? "X" : + " ", + (g_qdf_trace_info[module_id]. + module_trace_level & (1 << QDF_TRACE_LEVEL_INFO)) ? "X" : + " ", + (g_qdf_trace_info[module_id]. + module_trace_level & (1 << QDF_TRACE_LEVEL_INFO_HIGH)) ? "X" + : " ", + (g_qdf_trace_info[module_id]. + module_trace_level & (1 << QDF_TRACE_LEVEL_INFO_MED)) ? "X" + : " ", + (g_qdf_trace_info[module_id]. + module_trace_level & (1 << QDF_TRACE_LEVEL_INFO_LOW)) ? "X" + : " ", + (g_qdf_trace_info[module_id]. + module_trace_level & (1 << QDF_TRACE_LEVEL_DEBUG)) ? "X" : + " "); + } +} +EXPORT_SYMBOL(qdf_trace_display); + +#define ROW_SIZE 16 +/* Buffer size = data bytes(2 hex chars plus space) + NULL */ +#define BUFFER_SIZE ((ROW_SIZE * 3) + 1) + +/** + * qdf_trace_hex_dump() - externally called hex dump function + * @module: Module identifier a member of the QDF_MODULE_ID enumeration that + * identifies the module issuing the trace message. + * @level: Trace level a member of the QDF_TRACE_LEVEL enumeration indicating + * the severity of the condition causing the trace message to be + * issued. More severe conditions are more likely to be logged. + * @data: The base address of the buffer to be logged. + * @buf_len: The size of the buffer to be logged. + * + * Checks the level of severity and accordingly prints the trace messages + * + * Return: None + */ +void qdf_trace_hex_dump(QDF_MODULE_ID module, QDF_TRACE_LEVEL level, + void *data, int buf_len) +{ + const u8 *ptr = data; + int i, linelen, remaining = buf_len; + unsigned char linebuf[BUFFER_SIZE]; + + if (!(g_qdf_trace_info[module].module_trace_level & + QDF_TRACE_LEVEL_TO_MODULE_BITMASK(level))) + return; + + for (i = 0; i < buf_len; i += ROW_SIZE) { + linelen = min(remaining, ROW_SIZE); + remaining -= ROW_SIZE; + + hex_dump_to_buffer(ptr + i, linelen, ROW_SIZE, 1, + linebuf, sizeof(linebuf), false); + + qdf_trace_msg(module, level, "%.8x: %s", i, linebuf); + } +} +EXPORT_SYMBOL(qdf_trace_hex_dump); + +#endif + +/** + * qdf_trace_enable() - Enable MTRACE for specific modules + * @bitmask_of_module_id: Bitmask according to enum of the modules. + * 32[dec] = 0010 0000 [bin] + * 64[dec] = 0100 0000 [bin] + * 128[dec] = 1000 0000 [bin] + * @enable: can be true or false true implies enabling MTRACE false implies + * disabling MTRACE. + * + * Enable MTRACE for specific modules whose bits are set in bitmask and enable + * is true. if enable is false it disables MTRACE for that module. set the + * bitmask according to enum value of the modules. + * This functions will be called when you issue ioctl as mentioned following + * [iwpriv wlan0 setdumplog ]. + * - Decimal number, i.e. 64 decimal value shows only SME module, + * 128 decimal value shows only PE module, 192 decimal value shows PE and SME. + * + * Return: None + */ +void qdf_trace_enable(uint32_t bitmask_of_module_id, uint8_t enable) +{ + int i; + if (bitmask_of_module_id) { + for (i = 0; i < QDF_MODULE_ID_MAX; i++) { + if (((bitmask_of_module_id >> i) & 1)) { + if (enable) { + if (NULL != + qdf_trace_restore_cb_table[i]) { + qdf_trace_cb_table[i] = + qdf_trace_restore_cb_table[i]; + } + } else { + qdf_trace_restore_cb_table[i] = + qdf_trace_cb_table[i]; + qdf_trace_cb_table[i] = NULL; + } + } + } + } else { + if (enable) { + for (i = 0; i < QDF_MODULE_ID_MAX; i++) { + if (NULL != qdf_trace_restore_cb_table[i]) { + qdf_trace_cb_table[i] = + qdf_trace_restore_cb_table[i]; + } + } + } else { + for (i = 0; i < QDF_MODULE_ID_MAX; i++) { + qdf_trace_restore_cb_table[i] = + qdf_trace_cb_table[i]; + qdf_trace_cb_table[i] = NULL; + } + } + } +} +EXPORT_SYMBOL(qdf_trace_enable); + +/** + * qdf_trace_init() - initializes qdf trace structures and variables + * + * Called immediately after cds_preopen, so that we can start recording HDD + * events ASAP. + * + * Return: None + */ +void qdf_trace_init(void) +{ + uint8_t i; + g_qdf_trace_data.head = INVALID_QDF_TRACE_ADDR; + g_qdf_trace_data.tail = INVALID_QDF_TRACE_ADDR; + g_qdf_trace_data.num = 0; + g_qdf_trace_data.enable = true; + g_qdf_trace_data.dump_count = DEFAULT_QDF_TRACE_DUMP_COUNT; + g_qdf_trace_data.num_since_last_dump = 0; + + for (i = 0; i < QDF_MODULE_ID_MAX; i++) { + qdf_trace_cb_table[i] = NULL; + qdf_trace_restore_cb_table[i] = NULL; + } +} +EXPORT_SYMBOL(qdf_trace_init); + +/** + * qdf_trace() - puts the messages in to ring-buffer + * @module: Enum of module, basically module id. + * @param: Code to be recorded + * @session: Session ID of the log + * @data: Actual message contents + * + * This function will be called from each module who wants record the messages + * in circular queue. Before calling this functions make sure you have + * registered your module with qdf through qdf_trace_register function. + * + * Return: None + */ +void qdf_trace(uint8_t module, uint8_t code, uint16_t session, uint32_t data) +{ + tp_qdf_trace_record rec = NULL; + unsigned long flags; + char time[18]; + + if (!g_qdf_trace_data.enable) + return; + + /* if module is not registered, don't record for that module */ + if (NULL == qdf_trace_cb_table[module]) + return; + + qdf_get_time_of_the_day_in_hr_min_sec_usec(time, sizeof(time)); + /* Aquire the lock so that only one thread at a time can fill the ring + * buffer + */ + spin_lock_irqsave(<race_lock, flags); + + g_qdf_trace_data.num++; + + if (g_qdf_trace_data.num > MAX_QDF_TRACE_RECORDS) + g_qdf_trace_data.num = MAX_QDF_TRACE_RECORDS; + + if (INVALID_QDF_TRACE_ADDR == g_qdf_trace_data.head) { + /* first record */ + g_qdf_trace_data.head = 0; + g_qdf_trace_data.tail = 0; + } else { + /* queue is not empty */ + uint32_t tail = g_qdf_trace_data.tail + 1; + + if (MAX_QDF_TRACE_RECORDS == tail) + tail = 0; + + if (g_qdf_trace_data.head == tail) { + /* full */ + if (MAX_QDF_TRACE_RECORDS == ++g_qdf_trace_data.head) + g_qdf_trace_data.head = 0; + } + g_qdf_trace_data.tail = tail; + } + + rec = &g_qdf_trace_tbl[g_qdf_trace_data.tail]; + rec->code = code; + rec->session = session; + rec->data = data; + rec->qtime = qdf_get_log_timestamp(); + scnprintf(rec->time, sizeof(rec->time), "%s", time); + rec->module = module; + rec->pid = (in_interrupt() ? 0 : current->pid); + g_qdf_trace_data.num_since_last_dump++; + spin_unlock_irqrestore(<race_lock, flags); +} +EXPORT_SYMBOL(qdf_trace); + +/** + * qdf_trace_spin_lock_init() - initializes the lock variable before use + * + * This function will be called from cds_alloc_global_context, we will have lock + * available to use ASAP + * + * Return: None + */ +QDF_STATUS qdf_trace_spin_lock_init(void) +{ + spin_lock_init(<race_lock); + + return QDF_STATUS_SUCCESS; +} +EXPORT_SYMBOL(qdf_trace_spin_lock_init); + +/** + * qdf_trace_register() - registers the call back functions + * @module_iD: enum value of module + * @qdf_trace_callback: call back functions to display the messages in + * particular format. + * + * Registers the call back functions to display the messages in particular + * format mentioned in these call back functions. This functions should be + * called by interested module in their init part as we will be ready to + * register as soon as modules are up. + * + * Return: None + */ +void qdf_trace_register(QDF_MODULE_ID module_iD, + tp_qdf_trace_cb qdf_trace_callback) +{ + qdf_trace_cb_table[module_iD] = qdf_trace_callback; +} +EXPORT_SYMBOL(qdf_trace_register); + +/** + * qdf_trace_dump_all() - Dump data from ring buffer via call back functions + * registered with QDF + * @p_mac: Context of particular module + * @code: Reason code + * @session: Session id of log + * @count: Number of lines to dump starting from tail to head + * + * This function will be called up on issueing ioctl call as mentioned following + * [iwpriv wlan0 dumplog 0 0 ] + * + * - number lines to dump starting from tail to head. + * + * - if anybody wants to know how many messages were + * recorded for particular module/s mentioned by setbit in bitmask from last + * messages. It is optional, if you don't provide then it will dump + * everything from buffer. + * + * Return: None + */ +void qdf_trace_dump_all(void *p_mac, uint8_t code, uint8_t session, + uint32_t count, uint32_t bitmask_of_module) +{ + qdf_trace_record_t p_record; + int32_t i, tail; + + if (!g_qdf_trace_data.enable) { + QDF_TRACE(QDF_MODULE_ID_SYS, + QDF_TRACE_LEVEL_ERROR, "Tracing Disabled"); + return; + } + + QDF_TRACE(QDF_MODULE_ID_SYS, QDF_TRACE_LEVEL_INFO, + "Total Records: %d, Head: %d, Tail: %d", + g_qdf_trace_data.num, g_qdf_trace_data.head, + g_qdf_trace_data.tail); + + /* aquire the lock so that only one thread at a time can read + * the ring buffer + */ + spin_lock(<race_lock); + + if (g_qdf_trace_data.head != INVALID_QDF_TRACE_ADDR) { + i = g_qdf_trace_data.head; + tail = g_qdf_trace_data.tail; + + if (count) { + if (count > g_qdf_trace_data.num) + count = g_qdf_trace_data.num; + if (tail >= (count - 1)) + i = tail - count + 1; + else if (count != MAX_QDF_TRACE_RECORDS) + i = MAX_QDF_TRACE_RECORDS - ((count - 1) - + tail); + } + + p_record = g_qdf_trace_tbl[i]; + /* right now we are not using num_since_last_dump member but + * in future we might re-visit and use this member to track + * how many latest messages got added while we were dumping + * from ring buffer + */ + g_qdf_trace_data.num_since_last_dump = 0; + spin_unlock(<race_lock); + for (;; ) { + if ((code == 0 || (code == p_record.code)) && + (qdf_trace_cb_table[p_record.module] != NULL)) { + if (0 == bitmask_of_module) { + qdf_trace_cb_table[p_record. + module] (p_mac, + &p_record, + (uint16_t) + i); + } else { + if (bitmask_of_module & + (1 << p_record.module)) { + qdf_trace_cb_table[p_record. + module] + (p_mac, &p_record, + (uint16_t) i); + } + } + } + + if (i == tail) + break; + i += 1; + + spin_lock(<race_lock); + if (MAX_QDF_TRACE_RECORDS == i) { + i = 0; + p_record = g_qdf_trace_tbl[0]; + } else { + p_record = g_qdf_trace_tbl[i]; + } + spin_unlock(<race_lock); + } + } else { + spin_unlock(<race_lock); + } +} +EXPORT_SYMBOL(qdf_trace_dump_all); + +/** + * qdf_register_debugcb_init() - initializes debug callbacks + * to NULL + * + * Return: None + */ +void qdf_register_debugcb_init(void) +{ + uint8_t i; + + for (i = 0; i < QDF_MODULE_ID_MAX; i++) + qdf_state_info_table[i] = NULL; +} +EXPORT_SYMBOL(qdf_register_debugcb_init); + +/** + * qdf_register_debug_callback() - stores callback handlers to print + * state information + * @module_id: module id of layer + * @qdf_state_infocb: callback to be registered + * + * This function is used to store callback handlers to print + * state information + * + * Return: None + */ +void qdf_register_debug_callback(QDF_MODULE_ID module_id, + tp_qdf_state_info_cb qdf_state_infocb) +{ + qdf_state_info_table[module_id] = qdf_state_infocb; +} +EXPORT_SYMBOL(qdf_register_debug_callback); + +/** + * qdf_state_info_dump_all() - it invokes callback of layer which registered + * its callback to print its state information. + * @buf: buffer pointer to be passed + * @size: size of buffer to be filled + * @driver_dump_size: actual size of buffer used + * + * Return: QDF_STATUS_SUCCESS on success + */ +QDF_STATUS qdf_state_info_dump_all(char *buf, uint16_t size, + uint16_t *driver_dump_size) +{ + uint8_t module, ret = QDF_STATUS_SUCCESS; + uint16_t buf_len = size; + char *buf_ptr = buf; + + for (module = 0; module < QDF_MODULE_ID_MAX; module++) { + if (NULL != qdf_state_info_table[module]) { + qdf_state_info_table[module](&buf_ptr, &buf_len); + if (!buf_len) { + ret = QDF_STATUS_E_NOMEM; + break; + } + } + } + + *driver_dump_size = size - buf_len; + return ret; +} +EXPORT_SYMBOL(qdf_state_info_dump_all); + +#ifdef FEATURE_DP_TRACE +static void qdf_dp_unused(struct qdf_dp_trace_record_s *record, + uint16_t index) +{ + qdf_print("%s: QDF_DP_TRACE_MAX event should not be generated", + __func__); +} + +/** + * qdf_dp_trace_init() - enables the DP trace + * Called during driver load and it enables DP trace + * + * Return: None + */ +void qdf_dp_trace_init(void) +{ + uint8_t i; + + qdf_dp_trace_spin_lock_init(); + g_qdf_dp_trace_data.head = INVALID_QDF_DP_TRACE_ADDR; + g_qdf_dp_trace_data.tail = INVALID_QDF_DP_TRACE_ADDR; + g_qdf_dp_trace_data.num = 0; + g_qdf_dp_trace_data.proto_bitmap = QDF_NBUF_PKT_TRAC_TYPE_EAPOL | + QDF_NBUF_PKT_TRAC_TYPE_DHCP | + QDF_NBUF_PKT_TRAC_TYPE_MGMT_ACTION | + QDF_NBUF_PKT_TRAC_TYPE_ARP; + g_qdf_dp_trace_data.no_of_record = 0; + g_qdf_dp_trace_data.verbosity = QDF_DP_TRACE_VERBOSITY_HIGH; + g_qdf_dp_trace_data.enable = true; + g_qdf_dp_trace_data.tx_count = 0; + g_qdf_dp_trace_data.rx_count = 0; + g_qdf_dp_trace_data.live_mode = 0; + + for (i = 0; i < ARRAY_SIZE(qdf_dp_trace_cb_table); i++) + qdf_dp_trace_cb_table[i] = qdf_dp_display_record; + + qdf_dp_trace_cb_table[QDF_DP_TRACE_TXRX_PACKET_PTR_RECORD] = + qdf_dp_trace_cb_table[QDF_DP_TRACE_TXRX_FAST_PACKET_PTR_RECORD] = + qdf_dp_trace_cb_table[QDF_DP_TRACE_FREE_PACKET_PTR_RECORD] = + qdf_dp_display_ptr_record; + qdf_dp_trace_cb_table[QDF_DP_TRACE_EAPOL_PACKET_RECORD] = + qdf_dp_trace_cb_table[QDF_DP_TRACE_DHCP_PACKET_RECORD] = + qdf_dp_trace_cb_table[QDF_DP_TRACE_ARP_PACKET_RECORD] = + qdf_dp_display_proto_pkt; + qdf_dp_trace_cb_table[QDF_DP_TRACE_MGMT_PACKET_RECORD] = + qdf_dp_display_mgmt_pkt; + qdf_dp_trace_cb_table[QDF_DP_TRACE_EVENT_RECORD] = + qdf_dp_display_event_record; + + qdf_dp_trace_cb_table[QDF_DP_TRACE_MAX] = qdf_dp_unused; +} +EXPORT_SYMBOL(qdf_dp_trace_init); + +/** + * qdf_dp_trace_set_value() - Configure the value to control DP trace + * @proto_bitmap: defines the protocol to be tracked + * @no_of_records: defines the nth packet which is traced + * @verbosity: defines the verbosity level + * + * Return: None + */ +void qdf_dp_trace_set_value(uint8_t proto_bitmap, uint8_t no_of_record, + uint8_t verbosity) +{ + g_qdf_dp_trace_data.proto_bitmap = proto_bitmap; + g_qdf_dp_trace_data.no_of_record = no_of_record; + g_qdf_dp_trace_data.verbosity = verbosity; + return; +} +EXPORT_SYMBOL(qdf_dp_trace_set_value); + +/** + * qdf_dp_trace_enable_track() - enable the tracing for netbuf + * @code: defines the event + * + * In High verbosity all codes are logged. + * For Med/Low and Default case code which has + * less value than corresponding verbosity codes + * are logged. + * + * Return: true or false depends on whether tracing enabled + */ +static bool qdf_dp_trace_enable_track(enum QDF_DP_TRACE_ID code) +{ + switch (g_qdf_dp_trace_data.verbosity) { + case QDF_DP_TRACE_VERBOSITY_HIGH: + return true; + case QDF_DP_TRACE_VERBOSITY_MEDIUM: + if (code <= QDF_DP_TRACE_MED_VERBOSITY) + return true; + return false; + case QDF_DP_TRACE_VERBOSITY_LOW: + if (code <= QDF_DP_TRACE_LOW_VERBOSITY) + return true; + return false; + case QDF_DP_TRACE_VERBOSITY_DEFAULT: + if (code <= QDF_DP_TRACE_DEFAULT_VERBOSITY) + return true; + return false; + default: + return false; + } +} +EXPORT_SYMBOL(qdf_dp_trace_enable_track); + +/** + * qdf_dp_get_proto_bitmap() - get dp trace proto bitmap + * + * Return: proto bitmap + */ +uint8_t qdf_dp_get_proto_bitmap(void) +{ + if (g_qdf_dp_trace_data.enable) + return g_qdf_dp_trace_data.proto_bitmap; + else + return 0; +} + +/** + * qdf_dp_trace_set_track() - Marks whether the packet needs to be traced + * @nbuf: defines the netbuf + * @dir: direction + * + * Return: None + */ +void qdf_dp_trace_set_track(qdf_nbuf_t nbuf, enum qdf_proto_dir dir) +{ + uint32_t count = 0; + + spin_lock_bh(&l_dp_trace_lock); + if (QDF_TX == dir) + count = ++g_qdf_dp_trace_data.tx_count; + else if (QDF_RX == dir) + count = ++g_qdf_dp_trace_data.rx_count; + + if ((g_qdf_dp_trace_data.no_of_record != 0) && + (count % g_qdf_dp_trace_data.no_of_record == 0)) { + if (QDF_TX == dir) + QDF_NBUF_CB_TX_DP_TRACE(nbuf) = 1; + else if (QDF_RX == dir) + QDF_NBUF_CB_RX_DP_TRACE(nbuf) = 1; + } + spin_unlock_bh(&l_dp_trace_lock); + return; +} +EXPORT_SYMBOL(qdf_dp_trace_set_track); + +#define DPTRACE_PRINT(args...) \ + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO, ## args) + +/** + * dump_hex_trace() - Display the data in buffer + * @str: string to prepend the hexdump with. + * @buf: buffer which contains data to be displayed + * @buf_len: defines the size of the data to be displayed + * + * Return: None + */ +static void dump_hex_trace(char *str, uint8_t *buf, uint8_t buf_len) +{ + unsigned char linebuf[BUFFER_SIZE]; + const u8 *ptr = buf; + int i, linelen, remaining = buf_len; + + /* Dump the bytes in the last line */ + for (i = 0; i < buf_len; i += ROW_SIZE) { + linelen = min(remaining, ROW_SIZE); + remaining -= ROW_SIZE; + + hex_dump_to_buffer(ptr + i, linelen, ROW_SIZE, 1, + linebuf, sizeof(linebuf), false); + + DPTRACE_PRINT("DPT: %s: %s", str, linebuf); + } +} + +/** + * qdf_dp_code_to_string() - convert dptrace code to string + * @code: dptrace code + * + * Return: string version of code + */ +static +const char *qdf_dp_code_to_string(enum QDF_DP_TRACE_ID code) +{ + switch (code) { + case QDF_DP_TRACE_DROP_PACKET_RECORD: + return "DROP:"; + case QDF_DP_TRACE_EAPOL_PACKET_RECORD: + return "EAPOL:"; + case QDF_DP_TRACE_DHCP_PACKET_RECORD: + return "DHCP:"; + case QDF_DP_TRACE_ARP_PACKET_RECORD: + return "ARP:"; + case QDF_DP_TRACE_MGMT_PACKET_RECORD: + return "MGMT:"; + case QDF_DP_TRACE_EVENT_RECORD: + return "EVENT:"; + case QDF_DP_TRACE_HDD_TX_PACKET_PTR_RECORD: + return "HDD: TX: PTR:"; + case QDF_DP_TRACE_HDD_TX_PACKET_RECORD: + return "HDD: TX: DATA:"; + case QDF_DP_TRACE_CE_PACKET_PTR_RECORD: + return "CE: TX: PTR:"; + case QDF_DP_TRACE_CE_FAST_PACKET_PTR_RECORD: + return "CE: TX: FAST: PTR:"; + case QDF_DP_TRACE_FREE_PACKET_PTR_RECORD: + return "FREE: TX: PTR:"; + case QDF_DP_TRACE_RX_HTT_PACKET_PTR_RECORD: + return "HTT: RX: PTR:"; + case QDF_DP_TRACE_RX_OFFLOAD_HTT_PACKET_PTR_RECORD: + return "HTT: RX: OF: PTR:"; + case QDF_DP_TRACE_RX_HDD_PACKET_PTR_RECORD: + return "HDD: RX: PTR:"; + case QDF_DP_TRACE_HDD_RX_PACKET_RECORD: + return "HDD: RX: DATA:"; + case QDF_DP_TRACE_TXRX_QUEUE_PACKET_PTR_RECORD: + return "TXRX: TX: Q: PTR:"; + case QDF_DP_TRACE_TXRX_PACKET_PTR_RECORD: + return "TXRX: TX: PTR:"; + case QDF_DP_TRACE_TXRX_FAST_PACKET_PTR_RECORD: + return "TXRX: TX: FAST: PTR:"; + case QDF_DP_TRACE_HTT_PACKET_PTR_RECORD: + return "HTT: TX: PTR:"; + case QDF_DP_TRACE_HTC_PACKET_PTR_RECORD: + return "HTC: TX: PTR:"; + case QDF_DP_TRACE_HIF_PACKET_PTR_RECORD: + return "HIF: TX: PTR:"; + case QDF_DP_TRACE_RX_TXRX_PACKET_PTR_RECORD: + return "TXRX: RX: PTR:"; + case QDF_DP_TRACE_HDD_TX_TIMEOUT: + return "HDD: STA: TO:"; + case QDF_DP_TRACE_HDD_SOFTAP_TX_TIMEOUT: + return "HDD: SAP: TO:"; + default: + return "Invalid"; + } +} + +/** + * qdf_dp_dir_to_str() - convert direction to string + * @dir: direction + * + * Return: string version of direction + */ +static const char *qdf_dp_dir_to_str(enum qdf_proto_dir dir) +{ + switch (dir) { + case QDF_TX: + return " --> "; + case QDF_RX: + return " <-- "; + default: + return "invalid"; + } +} + +/** + * qdf_dp_type_to_str() - convert packet type to string + * @type: type + * + * Return: string version of packet type + */ +static const char *qdf_dp_type_to_str(enum qdf_proto_type type) +{ + switch (type) { + case QDF_PROTO_TYPE_DHCP: + return "DHCP"; + case QDF_PROTO_TYPE_EAPOL: + return "EAPOL"; + case QDF_PROTO_TYPE_ARP: + return "ARP"; + case QDF_PROTO_TYPE_MGMT: + return "MGMT"; + case QDF_PROTO_TYPE_EVENT: + return "EVENT"; + default: + return "invalid"; + } +} + +/** + * qdf_dp_subtype_to_str() - convert packet subtype to string + * @type: type + * + * Return: string version of packet subtype + */ +static const char *qdf_dp_subtype_to_str(enum qdf_proto_subtype subtype) +{ + switch (subtype) { + case QDF_PROTO_EAPOL_M1: + return "M1"; + case QDF_PROTO_EAPOL_M2: + return "M2"; + case QDF_PROTO_EAPOL_M3: + return "M3"; + case QDF_PROTO_EAPOL_M4: + return "M4"; + case QDF_PROTO_DHCP_DISCOVER: + return "DISCOVER"; + case QDF_PROTO_DHCP_REQUEST: + return "REQUEST"; + case QDF_PROTO_DHCP_OFFER: + return "OFFER"; + case QDF_PROTO_DHCP_ACK: + return "ACK"; + case QDF_PROTO_DHCP_NACK: + return "NACK"; + case QDF_PROTO_DHCP_RELEASE: + return "RELEASE"; + case QDF_PROTO_DHCP_INFORM: + return "INFORM"; + case QDF_PROTO_DHCP_DECLINE: + return "DECLINE"; + case QDF_PROTO_ARP_REQ: + return "REQUEST"; + case QDF_PROTO_ARP_RES: + return "RESPONSE"; + case QDF_PROTO_MGMT_ASSOC: + return "ASSOC"; + case QDF_PROTO_MGMT_DISASSOC: + return "DISASSOC"; + case QDF_PROTO_MGMT_AUTH: + return "AUTH"; + case QDF_PROTO_MGMT_DEAUTH: + return "DEAUTH"; + case QDF_ROAM_SYNCH: + return "ROAM SYNCH"; + case QDF_ROAM_COMPLETE: + return "ROAM COMPLETE"; + case QDF_ROAM_EVENTID: + return "ROAM EVENTID"; + default: + return "invalid"; + } +} + +/** + * qdf_dp_enable_check() - check if dptrace is enable or not + * @nbuf: nbuf + * @code: dptrace code + * + * Return: true/false + */ +static bool qdf_dp_enable_check(qdf_nbuf_t nbuf, enum QDF_DP_TRACE_ID code, + enum qdf_proto_dir dir) +{ + /* Return when Dp trace is not enabled */ + if (!g_qdf_dp_trace_data.enable) + return false; + + if (qdf_dp_trace_enable_track(code) == false) + return false; + + if ((nbuf) && ((QDF_NBUF_CB_TX_PACKET_TRACK(nbuf) != + QDF_NBUF_TX_PKT_DATA_TRACK) || + ((dir == QDF_TX) && (QDF_NBUF_CB_TX_DP_TRACE(nbuf) == 0)) || + ((dir == QDF_RX) && (QDF_NBUF_CB_RX_DP_TRACE(nbuf) == 0)))) + return false; + + return true; +} + +/** + * qdf_dp_add_record() - add dp trace record + * @code: dptrace code + * @data: data pointer + * @size: size of buffer + * @print: true to print it in kmsg + * + * Return: none + */ +static void qdf_dp_add_record(enum QDF_DP_TRACE_ID code, + uint8_t *data, uint8_t size, bool print) +{ + struct qdf_dp_trace_record_s *rec = NULL; + int index; + spin_lock_bh(&l_dp_trace_lock); + + g_qdf_dp_trace_data.num++; + + if (g_qdf_dp_trace_data.num > MAX_QDF_DP_TRACE_RECORDS) + g_qdf_dp_trace_data.num = MAX_QDF_DP_TRACE_RECORDS; + + if (INVALID_QDF_DP_TRACE_ADDR == g_qdf_dp_trace_data.head) { + /* first record */ + g_qdf_dp_trace_data.head = 0; + g_qdf_dp_trace_data.tail = 0; + } else { + /* queue is not empty */ + g_qdf_dp_trace_data.tail++; + + if (MAX_QDF_DP_TRACE_RECORDS == g_qdf_dp_trace_data.tail) + g_qdf_dp_trace_data.tail = 0; + + if (g_qdf_dp_trace_data.head == g_qdf_dp_trace_data.tail) { + /* full */ + if (MAX_QDF_DP_TRACE_RECORDS == + ++g_qdf_dp_trace_data.head) + g_qdf_dp_trace_data.head = 0; + } + } + + rec = &g_qdf_dp_trace_tbl[g_qdf_dp_trace_data.tail]; + index = g_qdf_dp_trace_data.tail; + rec->code = code; + rec->size = 0; + if (data != NULL && size > 0) { + if (size > QDF_DP_TRACE_RECORD_SIZE) + size = QDF_DP_TRACE_RECORD_SIZE; + + rec->size = size; + qdf_mem_copy(rec->data, data, size); + } + qdf_get_time_of_the_day_in_hr_min_sec_usec(rec->time, + sizeof(rec->time)); + rec->pid = (in_interrupt() ? 0 : current->pid); + spin_unlock_bh(&l_dp_trace_lock); + + if ((g_qdf_dp_trace_data.live_mode || (print == true)) && + (rec->code < QDF_DP_TRACE_MAX)) + qdf_dp_trace_cb_table[rec->code] (rec, index); +} + + +/** + * qdf_log_eapol_pkt() - log EAPOL packet + * @session_id: vdev_id + * @skb: skb pointer + * @dir: direction + * + * Return: true/false + */ +static bool qdf_log_eapol_pkt(uint8_t session_id, struct sk_buff *skb, + enum qdf_proto_dir dir) +{ + enum qdf_proto_subtype subtype; + + if ((qdf_dp_get_proto_bitmap() & QDF_NBUF_PKT_TRAC_TYPE_EAPOL) && + ((dir == QDF_TX && QDF_NBUF_CB_PACKET_TYPE_EAPOL == + QDF_NBUF_CB_GET_PACKET_TYPE(skb)) || + (dir == QDF_RX && qdf_nbuf_is_ipv4_eapol_pkt(skb) == true))) { + + subtype = qdf_nbuf_get_eapol_subtype(skb); + DPTRACE(qdf_dp_trace_proto_pkt(QDF_DP_TRACE_EAPOL_PACKET_RECORD, + session_id, (skb->data + QDF_NBUF_SRC_MAC_OFFSET), + (skb->data + QDF_NBUF_DEST_MAC_OFFSET), + QDF_PROTO_TYPE_EAPOL, subtype, dir)); + if (QDF_TX == dir) + QDF_NBUF_CB_TX_DP_TRACE(skb) = 1; + else if (QDF_RX == dir) + QDF_NBUF_CB_RX_DP_TRACE(skb) = 1; + + QDF_NBUF_CB_DP_TRACE_PRINT(skb) = true; + return true; + } + return false; +} + +/** + * qdf_log_dhcp_pkt() - log DHCP packet + * @session_id: vdev_id + * @skb: skb pointer + * @dir: direction + * + * Return: true/false + */ +static bool qdf_log_dhcp_pkt(uint8_t session_id, struct sk_buff *skb, + enum qdf_proto_dir dir) +{ + enum qdf_proto_subtype subtype = QDF_PROTO_INVALID; + + if ((qdf_dp_get_proto_bitmap() & QDF_NBUF_PKT_TRAC_TYPE_DHCP) && + ((dir == QDF_TX && QDF_NBUF_CB_PACKET_TYPE_DHCP == + QDF_NBUF_CB_GET_PACKET_TYPE(skb)) || + (dir == QDF_RX && qdf_nbuf_is_ipv4_dhcp_pkt(skb) == true))) { + + subtype = qdf_nbuf_get_dhcp_subtype(skb); + DPTRACE(qdf_dp_trace_proto_pkt(QDF_DP_TRACE_DHCP_PACKET_RECORD, + session_id, (skb->data + QDF_NBUF_SRC_MAC_OFFSET), + (skb->data + QDF_NBUF_DEST_MAC_OFFSET), + QDF_PROTO_TYPE_DHCP, subtype, dir)); + if (QDF_TX == dir) + QDF_NBUF_CB_TX_DP_TRACE(skb) = 1; + else if (QDF_RX == dir) + QDF_NBUF_CB_RX_DP_TRACE(skb) = 1; + + QDF_NBUF_CB_DP_TRACE_PRINT(skb) = true; + return true; + } + return false; +} + +/** + * qdf_log_arp_pkt() - log ARP packet + * @session_id: vdev_id + * @skb: skb pointer + * @dir: direction + * + * Return: true/false + */ +static bool qdf_log_arp_pkt(uint8_t session_id, struct sk_buff *skb, + enum qdf_proto_dir dir) +{ + enum qdf_proto_subtype proto_subtype; + + if ((qdf_dp_get_proto_bitmap() & QDF_NBUF_PKT_TRAC_TYPE_ARP) && + ((dir == QDF_TX && QDF_NBUF_CB_PACKET_TYPE_ARP == + QDF_NBUF_CB_GET_PACKET_TYPE(skb)) || + (dir == QDF_RX && qdf_nbuf_is_ipv4_arp_pkt(skb) == true))) { + + proto_subtype = qdf_nbuf_get_arp_subtype(skb); + DPTRACE(qdf_dp_trace_proto_pkt(QDF_DP_TRACE_ARP_PACKET_RECORD, + session_id, (skb->data + QDF_NBUF_SRC_MAC_OFFSET), + (skb->data + QDF_NBUF_DEST_MAC_OFFSET), + QDF_PROTO_TYPE_ARP, proto_subtype, dir)); + if (QDF_TX == dir) + QDF_NBUF_CB_TX_DP_TRACE(skb) = 1; + else if (QDF_RX == dir) + QDF_NBUF_CB_RX_DP_TRACE(skb) = 1; + + QDF_NBUF_CB_DP_TRACE_PRINT(skb) = true; + return true; + } + return false; +} + +/** + * qdf_dp_trace_log_pkt() - log packet type enabled through iwpriv + * @session_id: vdev_id + * @skb: skb pointer + * @dir: direction + * + * Return: none + */ +void qdf_dp_trace_log_pkt(uint8_t session_id, struct sk_buff *skb, + enum qdf_proto_dir dir) +{ + if (qdf_dp_get_proto_bitmap()) { + if (qdf_log_arp_pkt(session_id, + skb, dir) == false) { + if (qdf_log_dhcp_pkt(session_id, + skb, dir) == false) { + if (qdf_log_eapol_pkt(session_id, + skb, dir) == false) { + return; + } + } + } + } +} +EXPORT_SYMBOL(qdf_dp_trace_log_pkt); + +/** + * qdf_dp_display_mgmt_pkt() - display proto packet + * @record: dptrace record + * @index: index + * + * Return: none + */ +void qdf_dp_display_mgmt_pkt(struct qdf_dp_trace_record_s *record, + uint16_t index) +{ + struct qdf_dp_trace_mgmt_buf *buf = + (struct qdf_dp_trace_mgmt_buf *)record->data; + + DPTRACE_PRINT("DPT: %04d: %s: %s vdev_id %d", index, + record->time, qdf_dp_code_to_string(record->code), + buf->vdev_id); + DPTRACE_PRINT("DPT: Type %s Subtype %s", qdf_dp_type_to_str(buf->type), + qdf_dp_subtype_to_str(buf->subtype)); +} +EXPORT_SYMBOL(qdf_dp_display_mgmt_pkt); + +/** + * qdf_dp_trace_mgmt_pkt() - record mgmt packet + * @code: dptrace code + * @vdev_id: vdev id + * @type: proto type + * @subtype: proto subtype + * + * Return: none + */ +void qdf_dp_trace_mgmt_pkt(enum QDF_DP_TRACE_ID code, uint8_t vdev_id, + enum qdf_proto_type type, enum qdf_proto_subtype subtype) +{ + struct qdf_dp_trace_mgmt_buf buf; + int buf_size = sizeof(struct qdf_dp_trace_mgmt_buf); + + if (qdf_dp_enable_check(NULL, code, QDF_NA) == false) + return; + + if (buf_size > QDF_DP_TRACE_RECORD_SIZE) + QDF_BUG(0); + + buf.type = type; + buf.subtype = subtype; + buf.vdev_id = vdev_id; + qdf_dp_add_record(code, (uint8_t *)&buf, buf_size, true); +} +EXPORT_SYMBOL(qdf_dp_trace_mgmt_pkt); + +/** + * qdf_dp_display_event_record() - display event records + * @record: dptrace record + * @index: index + * + * Return: none + */ +void qdf_dp_display_event_record(struct qdf_dp_trace_record_s *record, + uint16_t index) +{ + struct qdf_dp_trace_event_buf *buf = + (struct qdf_dp_trace_event_buf *)record->data; + + DPTRACE_PRINT("DPT: %04d: %s: %s vdev_id %d", index, + record->time, qdf_dp_code_to_string(record->code), + buf->vdev_id); + DPTRACE_PRINT("DPT: Type %s Subtype %s", qdf_dp_type_to_str(buf->type), + qdf_dp_subtype_to_str(buf->subtype)); +} +EXPORT_SYMBOL(qdf_dp_display_event_record); + +/** + * qdf_dp_trace_record_event() - record events + * @code: dptrace code + * @vdev_id: vdev id + * @type: proto type + * @subtype: proto subtype + * + * Return: none + */ +void qdf_dp_trace_record_event(enum QDF_DP_TRACE_ID code, uint8_t vdev_id, + enum qdf_proto_type type, enum qdf_proto_subtype subtype) +{ + struct qdf_dp_trace_event_buf buf; + int buf_size = sizeof(struct qdf_dp_trace_event_buf); + + if (qdf_dp_enable_check(NULL, code, QDF_NA) == false) + return; + + if (buf_size > QDF_DP_TRACE_RECORD_SIZE) + QDF_BUG(0); + + buf.type = type; + buf.subtype = subtype; + buf.vdev_id = vdev_id; + qdf_dp_add_record(code, (uint8_t *)&buf, buf_size, true); +} +EXPORT_SYMBOL(qdf_dp_trace_record_event); + +/** + * qdf_dp_display_proto_pkt() - display proto packet + * @record: dptrace record + * @index: index + * + * Return: none + */ +void qdf_dp_display_proto_pkt(struct qdf_dp_trace_record_s *record, + uint16_t index) +{ + struct qdf_dp_trace_proto_buf *buf = + (struct qdf_dp_trace_proto_buf *)record->data; + + DPTRACE_PRINT("DPT: %04d: %s: %s vdev_id %d", index, + record->time, qdf_dp_code_to_string(record->code), + buf->vdev_id); + DPTRACE_PRINT("DPT: SA: " QDF_MAC_ADDRESS_STR " %s DA: " + QDF_MAC_ADDRESS_STR " Type %s Subtype %s", + QDF_MAC_ADDR_ARRAY(buf->sa.bytes), qdf_dp_dir_to_str(buf->dir), + QDF_MAC_ADDR_ARRAY(buf->da.bytes), + qdf_dp_type_to_str(buf->type), + qdf_dp_subtype_to_str(buf->subtype)); +} +EXPORT_SYMBOL(qdf_dp_display_proto_pkt); + +/** + * qdf_dp_trace_proto_pkt() - record proto packet + * @code: dptrace code + * @vdev_id: vdev id + * @sa: source mac address + * @da: destination mac address + * @type: proto type + * @subtype: proto subtype + * @dir: direction + * + * Return: none + */ +void qdf_dp_trace_proto_pkt(enum QDF_DP_TRACE_ID code, uint8_t vdev_id, + uint8_t *sa, uint8_t *da, enum qdf_proto_type type, + enum qdf_proto_subtype subtype, enum qdf_proto_dir dir) +{ + struct qdf_dp_trace_proto_buf buf; + int buf_size = sizeof(struct qdf_dp_trace_ptr_buf); + + if (qdf_dp_enable_check(NULL, code, dir) == false) + return; + + if (buf_size > QDF_DP_TRACE_RECORD_SIZE) + QDF_BUG(0); + + memcpy(&buf.sa, sa, QDF_NET_ETH_LEN); + memcpy(&buf.da, da, QDF_NET_ETH_LEN); + buf.dir = dir; + buf.type = type; + buf.subtype = subtype; + buf.vdev_id = vdev_id; + qdf_dp_add_record(code, (uint8_t *)&buf, buf_size, true); +} +EXPORT_SYMBOL(qdf_dp_trace_proto_pkt); + +/** + * qdf_dp_display_ptr_record() - display record + * @record: dptrace record + * @index: index + * + * Return: none + */ +void qdf_dp_display_ptr_record(struct qdf_dp_trace_record_s *record, + uint16_t index) +{ + struct qdf_dp_trace_ptr_buf *buf = + (struct qdf_dp_trace_ptr_buf *)record->data; + + if (record->code == QDF_DP_TRACE_FREE_PACKET_PTR_RECORD) + DPTRACE_PRINT("DPT: %04d: %s: %s msdu_id: %d, status: %d", + index, record->time, + qdf_dp_code_to_string(record->code), buf->msdu_id, + buf->status); + else + DPTRACE_PRINT("DPT: %04d: %s: %s msdu_id: %d, vdev_id: %d", + index, + record->time, qdf_dp_code_to_string(record->code), + buf->msdu_id, buf->status); + dump_hex_trace("cookie", (uint8_t *)&buf->cookie, sizeof(buf->cookie)); +} +EXPORT_SYMBOL(qdf_dp_display_ptr_record); + +/** + * qdf_dp_trace_ptr() - record dptrace + * @code: dptrace code + * @data: data + * @size: size of data + * @msdu_id: msdu_id + * @status: return status + * + * Return: none + */ +void qdf_dp_trace_ptr(qdf_nbuf_t nbuf, enum QDF_DP_TRACE_ID code, + uint8_t *data, uint8_t size, uint16_t msdu_id, uint16_t status) +{ + struct qdf_dp_trace_ptr_buf buf; + int buf_size = sizeof(struct qdf_dp_trace_ptr_buf); + + if (qdf_dp_enable_check(nbuf, code, QDF_TX) == false) + return; + + if (buf_size > QDF_DP_TRACE_RECORD_SIZE) + QDF_BUG(0); + + qdf_mem_copy(&buf.cookie, data, size); + buf.msdu_id = msdu_id; + buf.status = status; + qdf_dp_add_record(code, (uint8_t *)&buf, buf_size, + QDF_NBUF_CB_DP_TRACE_PRINT(nbuf)); +} +EXPORT_SYMBOL(qdf_dp_trace_ptr); + +/** + * qdf_dp_display_trace() - Displays a record in DP trace + * @pRecord : pointer to a record in DP trace + * @recIndex : record index + * + * Return: None + */ +void qdf_dp_display_record(struct qdf_dp_trace_record_s *pRecord, + uint16_t recIndex) +{ + DPTRACE_PRINT("DPT: %04d: %s: %s", recIndex, + pRecord->time, qdf_dp_code_to_string(pRecord->code)); + switch (pRecord->code) { + case QDF_DP_TRACE_HDD_TX_TIMEOUT: + DPTRACE_PRINT("DPT: HDD TX Timeout\n"); + break; + case QDF_DP_TRACE_HDD_SOFTAP_TX_TIMEOUT: + DPTRACE_PRINT("DPT: HDD SoftAP TX Timeout\n"); + break; + case QDF_DP_TRACE_HDD_TX_PACKET_RECORD: + case QDF_DP_TRACE_HDD_RX_PACKET_RECORD: + dump_hex_trace("DATA", pRecord->data, pRecord->size); + break; + default: + dump_hex_trace("cookie", pRecord->data, pRecord->size); + } +} +EXPORT_SYMBOL(qdf_dp_display_record); + + +/** + * qdf_dp_trace() - Stores the data in buffer + * @nbuf : defines the netbuf + * @code : defines the event + * @data : defines the data to be stored + * @size : defines the size of the data record + * + * Return: None + */ +void qdf_dp_trace(qdf_nbuf_t nbuf, enum QDF_DP_TRACE_ID code, + uint8_t *data, uint8_t size, enum qdf_proto_dir dir) +{ + + if (qdf_dp_enable_check(nbuf, code, dir) == false) + return; + + qdf_dp_add_record(code, data, size, + (nbuf != NULL) ? QDF_NBUF_CB_DP_TRACE_PRINT(nbuf) : false); +} +EXPORT_SYMBOL(qdf_dp_trace); + +/** + * qdf_dp_trace_spin_lock_init() - initializes the lock variable before use + * This function will be called from cds_alloc_global_context, we will have lock + * available to use ASAP + * + * Return: None + */ +void qdf_dp_trace_spin_lock_init(void) +{ + spin_lock_init(&l_dp_trace_lock); +} +EXPORT_SYMBOL(qdf_dp_trace_spin_lock_init); + +/** + * qdf_dp_trace_enable_live_mode() - enable live mode for dptrace + * + * Return: none + */ +void qdf_dp_trace_enable_live_mode(void) +{ + g_qdf_dp_trace_data.live_mode = 1; + +} +EXPORT_SYMBOL(qdf_dp_trace_enable_live_mode); + + +/** + * qdf_dp_trace_clear_buffer() - clear dp trace buffer + * + * Return: none + */ +void qdf_dp_trace_clear_buffer(void) +{ + g_qdf_dp_trace_data.head = INVALID_QDF_DP_TRACE_ADDR; + g_qdf_dp_trace_data.tail = INVALID_QDF_DP_TRACE_ADDR; + g_qdf_dp_trace_data.num = 0; + g_qdf_dp_trace_data.proto_bitmap = QDF_NBUF_PKT_TRAC_TYPE_EAPOL | + QDF_NBUF_PKT_TRAC_TYPE_DHCP | + QDF_NBUF_PKT_TRAC_TYPE_MGMT_ACTION | + QDF_NBUF_PKT_TRAC_TYPE_ARP; + g_qdf_dp_trace_data.no_of_record = 0; + g_qdf_dp_trace_data.verbosity = QDF_DP_TRACE_VERBOSITY_HIGH; + g_qdf_dp_trace_data.enable = true; + g_qdf_dp_trace_data.tx_count = 0; + g_qdf_dp_trace_data.rx_count = 0; + g_qdf_dp_trace_data.live_mode = 0; + + memset(g_qdf_dp_trace_tbl, 0, + MAX_QDF_DP_TRACE_RECORDS * sizeof(struct qdf_dp_trace_record_s)); +} +EXPORT_SYMBOL(qdf_dp_trace_clear_buffer); + +/** + * qdf_dp_trace_dump_all() - Dump data from ring buffer via call back functions + * registered with QDF + * @code: Reason code + * @count: Number of lines to dump starting from tail to head + * + * Return: None + */ +void qdf_dp_trace_dump_all(uint32_t count) +{ + struct qdf_dp_trace_record_s p_record; + int32_t i, tail; + + if (!g_qdf_dp_trace_data.enable) { + QDF_TRACE(QDF_MODULE_ID_SYS, + QDF_TRACE_LEVEL_ERROR, "Tracing Disabled"); + return; + } + + QDF_TRACE(QDF_MODULE_ID_SYS, QDF_TRACE_LEVEL_ERROR, + "Total Records: %d, Head: %d, Tail: %d", + g_qdf_dp_trace_data.num, g_qdf_dp_trace_data.head, + g_qdf_dp_trace_data.tail); + + /* aquire the lock so that only one thread at a time can read + * the ring buffer + */ + spin_lock_bh(&l_dp_trace_lock); + + if (g_qdf_dp_trace_data.head != INVALID_QDF_DP_TRACE_ADDR) { + i = g_qdf_dp_trace_data.head; + tail = g_qdf_dp_trace_data.tail; + + if (count) { + if (count > g_qdf_dp_trace_data.num) + count = g_qdf_dp_trace_data.num; + if (tail >= (count - 1)) + i = tail - count + 1; + else if (count != MAX_QDF_DP_TRACE_RECORDS) + i = MAX_QDF_DP_TRACE_RECORDS - ((count - 1) - + tail); + } + + p_record = g_qdf_dp_trace_tbl[i]; + spin_unlock_bh(&l_dp_trace_lock); + for (;; ) { + + qdf_dp_trace_cb_table[p_record. + code] (&p_record, (uint16_t)i); + if (i == tail) + break; + i += 1; + + spin_lock_bh(&l_dp_trace_lock); + if (MAX_QDF_DP_TRACE_RECORDS == i) + i = 0; + + p_record = g_qdf_dp_trace_tbl[i]; + spin_unlock_bh(&l_dp_trace_lock); + } + } else { + spin_unlock_bh(&l_dp_trace_lock); + } +} +EXPORT_SYMBOL(qdf_dp_trace_dump_all); +#endif diff --git a/drivers/staging/qca-wifi-host-cmn/wmi/inc/wmi_unified_api.h b/drivers/staging/qca-wifi-host-cmn/wmi/inc/wmi_unified_api.h new file mode 100644 index 0000000000000000000000000000000000000000..1c9cfc02a2d46040828dff7f784ebd6f334a7c29 --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/wmi/inc/wmi_unified_api.h @@ -0,0 +1,1379 @@ +/* + * Copyright (c) 2013-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * This file contains the API definitions for the Unified Wireless Module + * Interface (WMI). + */ + +#ifndef _WMI_UNIFIED_API_H_ +#define _WMI_UNIFIED_API_H_ + +#include +#include "a_types.h" +#include "ol_defines.h" +#ifdef CONFIG_MCL +#include "wmi.h" +#endif +#include "htc_api.h" +#include "wmi_unified_param.h" + +typedef qdf_nbuf_t wmi_buf_t; +#define wmi_buf_data(_buf) qdf_nbuf_data(_buf) + +#define WMI_LOGD(args ...) \ + QDF_TRACE(QDF_MODULE_ID_WMI, QDF_TRACE_LEVEL_DEBUG, ## args) +#define WMI_LOGI(args ...) \ + QDF_TRACE(QDF_MODULE_ID_WMI, QDF_TRACE_LEVEL_INFO, ## args) +#define WMI_LOGW(args ...) \ + QDF_TRACE(QDF_MODULE_ID_WMI, QDF_TRACE_LEVEL_WARN, ## args) +#define WMI_LOGE(args ...) \ + QDF_TRACE(QDF_MODULE_ID_WMI, QDF_TRACE_LEVEL_ERROR, ## args) +#define WMI_LOGP(args ...) \ + QDF_TRACE(QDF_MODULE_ID_WMI, QDF_TRACE_LEVEL_FATAL, ## args) + +#define WMI_DEBUG_ALWAYS + +#ifdef WMI_DEBUG_ALWAYS +#define WMI_LOGA(args ...) \ + QDF_TRACE(QDF_MODULE_ID_WMI, QDF_TRACE_LEVEL_FATAL, ## args) +#else +#define WMI_LOGA(args ...) +#endif + +/** + * struct wmi_ops - service callbacks to upper layer + * @service_ready_cbk: service ready callback + * @service_ready_ext_cbk: service ready ext callback + * @ready_cbk: ready calback + * @wma_process_fw_event_handler_cbk: generic event handler callback + */ +struct wmi_rx_ops { + + int (*wma_process_fw_event_handler_cbk)(void *ctx, + void *ev, uint8_t rx_ctx); +}; + +/** + * enum wmi_target_type - type of supported wmi command + * @WMI_TLV_TARGET: tlv based target + * @WMI_NON_TLV_TARGET: non-tlv based target + * + */ +enum wmi_target_type { + WMI_TLV_TARGET, + WMI_NON_TLV_TARGET +}; + +/** + * enum wmi_rx_exec_ctx - wmi rx execution context + * @WMI_RX_WORK_CTX: work queue context execution provided by WMI layer + * @WMI_RX_UMAC_CTX: execution context provided by umac layer + * + */ +enum wmi_rx_exec_ctx { + WMI_RX_WORK_CTX, + WMI_RX_UMAC_CTX +}; + +/** + * attach for unified WMI + * + * @param scn_handle : handle to SCN. + * @param target_type : type of supported wmi command + * @param use_cookie : flag to indicate cookie based allocation + * @param ops : handle to wmi ops + * @return opaque handle. + */ +void *wmi_unified_attach(void *scn_handle, + osdev_t osdev, enum wmi_target_type target_type, + bool use_cookie, struct wmi_rx_ops *ops); + + +/** + * wmi_mgmt_cmd_record() - Wrapper function for mgmt command logging macro + * + * @wmi_handle: wmi handle + * @cmd: mgmt command + * @header: pointer to 802.11 header + * @vdev_id: vdev id + * @chanfreq: channel frequency + * + * Return: none + */ +void wmi_mgmt_cmd_record(wmi_unified_t wmi_handle, uint32_t cmd, + void *header, uint32_t vdev_id, uint32_t chanfreq); + +/** + * detach for unified WMI + * + * @param wmi_handle : handle to WMI. + * @return void. + */ +void wmi_unified_detach(struct wmi_unified *wmi_handle); + +void +wmi_unified_remove_work(struct wmi_unified *wmi_handle); + +/** + * generic function to allocate WMI buffer + * + * @param wmi_handle : handle to WMI. + * @param len : length of the buffer + * @return wmi_buf_t. + */ +#ifdef MEMORY_DEBUG +#define wmi_buf_alloc(h, l) wmi_buf_alloc_debug(h, l, __FILE__, __LINE__) +wmi_buf_t +wmi_buf_alloc_debug(wmi_unified_t wmi_handle, uint16_t len, + uint8_t *file_name, uint32_t line_num); +#else +wmi_buf_t wmi_buf_alloc(wmi_unified_t wmi_handle, uint16_t len); +#endif + +/** + * generic function frees WMI net buffer + * + * @param net_buf : Pointer ot net_buf to be freed + */ +void wmi_buf_free(wmi_buf_t net_buf); + +/** + * generic function to send unified WMI command + * + * @param wmi_handle : handle to WMI. + * @param buf : wmi command buffer + * @param buflen : wmi command buffer length + * @param cmd_id : WMI cmd id + * @return 0 on success and -ve on failure. + */ +QDF_STATUS +wmi_unified_cmd_send(wmi_unified_t wmi_handle, wmi_buf_t buf, uint32_t buflen, + uint32_t cmd_id); + +/** + * wmi_unified_register_event_handler() - WMI event handler + * registration function + * + * @wmi_handle: handle to WMI. + * @event_id: WMI event ID + * @handler_func: Event handler call back function + * @rx_ctx: rx event processing context + * + * @return 0 on success and -ve on failure. + */ +int +wmi_unified_register_event_handler(wmi_unified_t wmi_handle, + uint32_t event_id, + wmi_unified_event_handler handler_func, + uint8_t rx_ctx); + +/** + * WMI event handler unregister function + * + * @param wmi_handle : handle to WMI. + * @param event_id : WMI event ID + * @return 0 on success and -ve on failure. + */ +int +wmi_unified_unregister_event_handler(wmi_unified_t wmi_handle, + uint32_t event_id); + +/** + * request wmi to connet its htc service. + * @param wmi_handle : handle to WMI. + * @param htc_handle : handle to HTC. + * @return void + */ +int +wmi_unified_connect_htc_service(struct wmi_unified *wmi_handle, + void *htc_handle); + +/* + * WMI API to verify the host has enough credits to suspend + * @param wmi_handle : handle to WMI. + */ + +int wmi_is_suspend_ready(wmi_unified_t wmi_handle); + +/** + * WMI API to get updated host_credits + * @param wmi_handle : handle to WMI. + */ + +int wmi_get_host_credits(wmi_unified_t wmi_handle); + +/** + * WMI API to get WMI Pending Commands in the HTC queue + * @param wmi_handle : handle to WMI. + */ + +int wmi_get_pending_cmds(wmi_unified_t wmi_handle); + +/** + * WMI API to set target suspend state + * @param wmi_handle : handle to WMI. + * @param val : suspend state boolean + */ +void wmi_set_target_suspend(wmi_unified_t wmi_handle, bool val); + +/** + * WMI API to set bus suspend state + * @param wmi_handle: handle to WMI. + * @param val: suspend state boolean + */ +void wmi_set_is_wow_bus_suspended(wmi_unified_t wmi_handle, A_BOOL val); + +/** + * WMI API to set crash injection state + * @param wmi_handle: handle to WMI. + * @param val: crash injection state boolean + */ +void wmi_tag_crash_inject(wmi_unified_t wmi_handle, A_BOOL flag); + +/** + * WMI API to set target assert + * + * @wmi_handle : handle to WMI. + * @val : target assert config value. + * + * @Return : none. + */ +void wmi_set_tgt_assert(wmi_unified_t wmi_handle, bool val); + +/** + * generic function to block unified WMI command + * @param wmi_handle : handle to WMI. + * @return 0 on success and -ve on failure. + */ +int +wmi_stop(wmi_unified_t wmi_handle); + +/** + * API to flush all the previous packets associated with the wmi endpoint + * + * @param wmi_handle : handle to WMI. + */ +void +wmi_flush_endpoint(wmi_unified_t wmi_handle); + +/** + * API to handle wmi rx event after UMAC has taken care of execution + * context + * + * @param wmi_handle : handle to WMI. + * @param evt_buf : wmi event buffer + */ +void __wmi_control_rx(struct wmi_unified *wmi_handle, wmi_buf_t evt_buf); +#ifdef FEATURE_RUNTIME_PM +void +wmi_set_runtime_pm_inprogress(wmi_unified_t wmi_handle, bool val); +bool wmi_get_runtime_pm_inprogress(wmi_unified_t wmi_handle); +#else +static inline void +wmi_set_runtime_pm_inprogress(wmi_unified_t wmi_handle, bool val) +{ + return; +} +static inline bool wmi_get_runtime_pm_inprogress(wmi_unified_t wmi_handle) +{ + return false; +} +#endif + +/** + * UMAC Callback to process fw event. + * @param wmi_handle : handle to WMI. + * @param evt_buf : wmi event buffer + */ +void wmi_process_fw_event(struct wmi_unified *wmi_handle, wmi_buf_t evt_buf); +uint16_t wmi_get_max_msg_len(wmi_unified_t wmi_handle); + + +QDF_STATUS wmi_unified_vdev_create_send(void *wmi_hdl, + uint8_t macaddr[IEEE80211_ADDR_LEN], + struct vdev_create_params *param); + +QDF_STATUS wmi_unified_vdev_delete_send(void *wmi_hdl, + uint8_t if_id); + +QDF_STATUS wmi_unified_vdev_restart_send(void *wmi_hdl, + uint8_t macaddr[IEEE80211_ADDR_LEN], + struct vdev_start_params *param); + +QDF_STATUS wmi_unified_vdev_stop_send(void *wmi_hdl, + uint8_t vdev_id); + +QDF_STATUS wmi_unified_vdev_up_send(void *wmi_hdl, + uint8_t bssid[IEEE80211_ADDR_LEN], + struct vdev_up_params *params); + +QDF_STATUS wmi_unified_vdev_down_send(void *wmi_hdl, + uint8_t vdev_id); + +QDF_STATUS wmi_unified_vdev_start_send(void *wmi_hdl, + struct vdev_start_params *req); + +QDF_STATUS wmi_unified_hidden_ssid_vdev_restart_send(void *wmi_hdl, + struct hidden_ssid_vdev_restart_params *restart_params); + +QDF_STATUS wmi_unified_vdev_set_param_send(void *wmi_hdl, + struct vdev_set_params *param); + +QDF_STATUS wmi_unified_peer_delete_send(void *wmi_hdl, + uint8_t + peer_addr[IEEE80211_ADDR_LEN], + uint8_t vdev_id); + +QDF_STATUS wmi_unified_peer_flush_tids_send(void *wmi_hdl, + uint8_t peer_addr[IEEE80211_ADDR_LEN], + struct peer_flush_params *param); + +QDF_STATUS wmi_set_peer_param_send(void *wmi_hdl, + uint8_t peer_addr[IEEE80211_ADDR_LEN], + struct peer_set_params *param); + +QDF_STATUS wmi_unified_peer_create_send(void *wmi_hdl, + struct peer_create_params *param); + +QDF_STATUS wmi_unified_stats_request_send(void *wmi_hdl, + uint8_t macaddr[IEEE80211_ADDR_LEN], + struct stats_request_params *param); + +QDF_STATUS wmi_unified_green_ap_ps_send(void *wmi_hdl, + uint32_t value, uint8_t mac_id); + + +QDF_STATUS wmi_unified_wow_enable_send(void *wmi_hdl, + struct wow_cmd_params *param, + uint8_t mac_id); + +QDF_STATUS wmi_unified_wow_wakeup_send(void *wmi_hdl); + +QDF_STATUS wmi_unified_wow_add_wakeup_event_send(void *wmi_hdl, + struct wow_add_wakeup_params *param); + +QDF_STATUS wmi_unified_wow_add_wakeup_pattern_send(void *wmi_hdl, + struct wow_add_wakeup_pattern_params *param); + +QDF_STATUS wmi_unified_wow_remove_wakeup_pattern_send(void *wmi_hdl, + struct wow_remove_wakeup_pattern_params *param); + +#ifdef WMI_NON_TLV_SUPPORT +QDF_STATUS wmi_unified_packet_log_enable_send(void *wmi_hdl, + WMI_HOST_PKTLOG_EVENT PKTLOG_EVENT); +#else +QDF_STATUS wmi_unified_packet_log_enable_send(void *wmi_hdl, + uint8_t macaddr[IEEE80211_ADDR_LEN], + struct packet_enable_params *param); +#endif + +QDF_STATUS wmi_unified_packet_log_disable_send(void *wmi_hdl); + +QDF_STATUS wmi_unified_suspend_send(void *wmi_hdl, + struct suspend_params *param, + uint8_t mac_id); + +QDF_STATUS wmi_unified_resume_send(void *wmi_hdl, + uint8_t mac_id); + +QDF_STATUS +wmi_unified_pdev_param_send(void *wmi_hdl, + struct pdev_params *param, + uint8_t mac_id); + +QDF_STATUS wmi_unified_beacon_tmpl_send_cmd(void *wmi_hdl, + struct beacon_tmpl_params *param); + + +QDF_STATUS wmi_unified_beacon_send_cmd(void *wmi_hdl, + struct beacon_params *param); + +QDF_STATUS wmi_unified_peer_assoc_send(void *wmi_hdl, + struct peer_assoc_params *param); + +QDF_STATUS wmi_unified_sta_ps_cmd_send(void *wmi_hdl, + struct sta_ps_params *param); + +QDF_STATUS wmi_unified_ap_ps_cmd_send(void *wmi_hdl, + uint8_t macaddr[IEEE80211_ADDR_LEN], + struct ap_ps_params *param); + +QDF_STATUS wmi_unified_scan_start_cmd_send(void *wmi_hdl, + struct scan_start_params *param); + +QDF_STATUS wmi_unified_scan_stop_cmd_send(void *wmi_hdl, + struct scan_stop_params *param); + +QDF_STATUS wmi_unified_scan_chan_list_cmd_send(void *wmi_hdl, + struct scan_chan_list_params *param); + + +QDF_STATUS wmi_crash_inject(void *wmi_hdl, + struct crash_inject *param); + +QDF_STATUS wmi_unified_pdev_utf_cmd_send(void *wmi_hdl, + struct pdev_utf_params *param, + uint8_t mac_id); + +QDF_STATUS wmi_unified_dbglog_cmd_send(void *wmi_hdl, + struct dbglog_params *param); + +QDF_STATUS wmi_mgmt_unified_cmd_send(void *wmi_hdl, + struct wmi_mgmt_params *param); + +QDF_STATUS wmi_unified_modem_power_state(void *wmi_hdl, + uint32_t param_value); + +QDF_STATUS wmi_unified_set_sta_ps_mode(void *wmi_hdl, + uint32_t vdev_id, uint8_t val); +QDF_STATUS +wmi_unified_set_sta_uapsd_auto_trig_cmd(void *wmi_hdl, + struct sta_uapsd_trig_params *param); + +QDF_STATUS wmi_unified_get_temperature(void *wmi_hdl); + +QDF_STATUS wmi_unified_set_p2pgo_oppps_req(void *wmi_hdl, + struct p2p_ps_params *oppps); + +QDF_STATUS wmi_unified_set_p2pgo_noa_req_cmd(void *wmi_hdl, + struct p2p_ps_params *noa); + +QDF_STATUS wmi_unified_set_smps_params(void *wmi_hdl, uint8_t vdev_id, + int value); + +QDF_STATUS wmi_unified_set_mimops(void *wmi_hdl, uint8_t vdev_id, int value); + +QDF_STATUS wmi_unified_ocb_set_utc_time(void *wmi_hdl, + struct ocb_utc_param *utc); + +QDF_STATUS wmi_unified_ocb_start_timing_advert(void *wmi_hdl, + struct ocb_timing_advert_param *timing_advert); + +QDF_STATUS wmi_unified_ocb_stop_timing_advert(void *wmi_hdl, + struct ocb_timing_advert_param *timing_advert); + +QDF_STATUS wmi_unified_ocb_set_config(void *wmi_hdl, + struct ocb_config_param *config, uint32_t *ch_mhz); + +QDF_STATUS wmi_unified_ocb_get_tsf_timer(void *wmi_hdl, + uint8_t vdev_id); + +QDF_STATUS wmi_unified_lro_config_cmd(void *wmi_hdl, + struct wmi_lro_config_cmd_t *wmi_lro_cmd); + +QDF_STATUS wmi_unified_set_thermal_mgmt_cmd(void *wmi_hdl, + struct thermal_cmd_params *thermal_info); + +QDF_STATUS wmi_unified_peer_rate_report_cmd(void *wmi_hdl, + struct wmi_peer_rate_report_params *rate_report_params); + +QDF_STATUS wmi_unified_set_mcc_channel_time_quota_cmd + (void *wmi_hdl, + uint32_t adapter_1_chan_freq, + uint32_t adapter_1_quota, uint32_t adapter_2_chan_freq); + +QDF_STATUS wmi_unified_set_mcc_channel_time_latency_cmd + (void *wmi_hdl, + uint32_t mcc_channel_freq, uint32_t mcc_channel_time_latency); + +QDF_STATUS wmi_unified_set_enable_disable_mcc_adaptive_scheduler_cmd( + void *wmi_hdl, uint32_t mcc_adaptive_scheduler, + uint32_t pdev_id); + +#ifndef WMI_NON_TLV_SUPPORT +QDF_STATUS wmi_unified_bcn_buf_ll_cmd(void *wmi_hdl, + wmi_bcn_send_from_host_cmd_fixed_param *param); +#endif + +QDF_STATUS wmi_unified_set_sta_sa_query_param_cmd(void *wmi_hdl, + uint8_t vdev_id, uint32_t max_retries, + uint32_t retry_interval); + + +QDF_STATUS wmi_unified_set_sta_keep_alive_cmd(void *wmi_hdl, + struct sta_params *params); + +QDF_STATUS wmi_unified_vdev_set_gtx_cfg_cmd(void *wmi_hdl, uint32_t if_id, + struct wmi_gtx_config *gtx_info); + +#ifndef WMI_NON_TLV_SUPPORT +QDF_STATUS wmi_unified_process_update_edca_param(void *wmi_hdl, + uint8_t vdev_id, + wmi_wmm_vparams gwmm_param[WMI_MAX_NUM_AC]); +#endif + + +QDF_STATUS wmi_unified_probe_rsp_tmpl_send_cmd(void *wmi_hdl, + uint8_t vdev_id, + struct wmi_probe_resp_params *probe_rsp_info, + uint8_t *frm); + +QDF_STATUS wmi_unified_setup_install_key_cmd(void *wmi_hdl, + struct set_key_params *key_params); + +QDF_STATUS wmi_unified_encrypt_decrypt_send_cmd(void *wmi_hdl, + struct encrypt_decrypt_req_params *params); + +QDF_STATUS wmi_unified_p2p_go_set_beacon_ie_cmd(void *wmi_hdl, + A_UINT32 vdev_id, uint8_t *p2p_ie); + + +QDF_STATUS wmi_unified_set_gateway_params_cmd(void *wmi_hdl, + struct gateway_update_req_param *req); + +QDF_STATUS wmi_unified_set_rssi_monitoring_cmd(void *wmi_hdl, + struct rssi_monitor_param *req); + +QDF_STATUS wmi_unified_scan_probe_setoui_cmd(void *wmi_hdl, + struct scan_mac_oui *psetoui); + +QDF_STATUS wmi_unified_reset_passpoint_network_list_cmd(void *wmi_hdl, + struct wifi_passpoint_req_param *req); + +QDF_STATUS wmi_unified_set_passpoint_network_list_cmd(void *wmi_hdl, + struct wifi_passpoint_req_param *req); + +#ifndef WMI_NON_TLV_SUPPORT +QDF_STATUS wmi_unified_roam_scan_offload_mode_cmd(void *wmi_hdl, + wmi_start_scan_cmd_fixed_param *scan_cmd_fp, + struct roam_offload_scan_params *roam_req); +#endif + +QDF_STATUS wmi_unified_roam_scan_offload_rssi_thresh_cmd(void *wmi_hdl, + struct roam_offload_scan_rssi_params *roam_req); + +QDF_STATUS wmi_unified_roam_scan_filter_cmd(void *wmi_hdl, + struct roam_scan_filter_params *roam_req); + +QDF_STATUS wmi_unified_set_epno_network_list_cmd(void *wmi_hdl, + struct wifi_enhanched_pno_params *req); + +QDF_STATUS wmi_unified_ipa_offload_control_cmd(void *wmi_hdl, + struct ipa_offload_control_params *ipa_offload); + +QDF_STATUS wmi_unified_extscan_get_capabilities_cmd(void *wmi_hdl, + struct extscan_capabilities_params *pgetcapab); + +QDF_STATUS wmi_unified_extscan_get_cached_results_cmd(void *wmi_hdl, + struct extscan_cached_result_params *pcached_results); + + +QDF_STATUS wmi_unified_extscan_stop_change_monitor_cmd(void *wmi_hdl, + struct extscan_capabilities_reset_params *reset_req); + + +QDF_STATUS wmi_unified_extscan_start_change_monitor_cmd(void *wmi_hdl, + struct extscan_set_sig_changereq_params * + psigchange); + +QDF_STATUS wmi_unified_extscan_stop_hotlist_monitor_cmd(void *wmi_hdl, + struct extscan_bssid_hotlist_reset_params *photlist_reset); + +QDF_STATUS wmi_unified_stop_extscan_cmd(void *wmi_hdl, + struct extscan_stop_req_params *pstopcmd); + +QDF_STATUS wmi_unified_start_extscan_cmd(void *wmi_hdl, + struct wifi_scan_cmd_req_params *pstart); + +QDF_STATUS wmi_unified_plm_stop_cmd(void *wmi_hdl, + const struct plm_req_params *plm); + +QDF_STATUS wmi_unified_plm_start_cmd(void *wmi_hdl, + const struct plm_req_params *plm, + uint32_t *gchannel_list); + +QDF_STATUS wmi_unified_pno_stop_cmd(void *wmi_hdl, uint8_t vdev_id); + +#ifdef FEATURE_WLAN_SCAN_PNO +QDF_STATUS wmi_unified_pno_start_cmd(void *wmi_hdl, + struct pno_scan_req_params *pno, + uint32_t *gchannel_freq_list); +#endif + +QDF_STATUS wmi_unified_set_ric_req_cmd(void *wmi_hdl, void *msg, + uint8_t is_add_ts); + +QDF_STATUS wmi_unified_process_ll_stats_clear_cmd + (void *wmi_hdl, const struct ll_stats_clear_params *clear_req, + uint8_t addr[IEEE80211_ADDR_LEN]); + +QDF_STATUS wmi_unified_process_ll_stats_set_cmd + (void *wmi_hdl, const struct ll_stats_set_params *set_req); + +QDF_STATUS wmi_unified_process_ll_stats_get_cmd + (void *wmi_hdl, const struct ll_stats_get_params *get_req, + uint8_t addr[IEEE80211_ADDR_LEN]); + +QDF_STATUS wmi_unified_get_stats_cmd(void *wmi_hdl, + struct pe_stats_req *get_stats_param, + uint8_t addr[IEEE80211_ADDR_LEN]); + +/** + * wmi_unified_congestion_request_cmd() - send request to fw to get CCA + * @wmi_hdl: wma handle + * @vdev_id: vdev id + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_congestion_request_cmd(void *wmi_hdl, + uint8_t vdev_id); + +QDF_STATUS wmi_unified_snr_request_cmd(void *wmi_hdl); + +QDF_STATUS wmi_unified_snr_cmd(void *wmi_hdl, uint8_t vdev_id); + +QDF_STATUS wmi_unified_link_status_req_cmd(void *wmi_hdl, + struct link_status_params *link_status); + +#ifndef WMI_NON_TLV_SUPPORT +QDF_STATUS wmi_unified_lphb_config_hbenable_cmd(void *wmi_hdl, + wmi_hb_set_enable_cmd_fixed_param *params); + +QDF_STATUS wmi_unified_lphb_config_tcp_params_cmd(void *wmi_hdl, + wmi_hb_set_tcp_params_cmd_fixed_param *lphb_conf_req); + +QDF_STATUS wmi_unified_lphb_config_tcp_pkt_filter_cmd(void *wmi_hdl, + wmi_hb_set_tcp_pkt_filter_cmd_fixed_param *g_hb_tcp_filter_fp); + +QDF_STATUS wmi_unified_lphb_config_udp_params_cmd(void *wmi_hdl, + wmi_hb_set_udp_params_cmd_fixed_param *lphb_conf_req); + +QDF_STATUS wmi_unified_lphb_config_udp_pkt_filter_cmd(void *wmi_hdl, + wmi_hb_set_udp_pkt_filter_cmd_fixed_param *lphb_conf_req); + +QDF_STATUS wmi_unified_process_dhcp_ind(void *wmi_hdl, + wmi_peer_set_param_cmd_fixed_param *ta_dhcp_ind); + +QDF_STATUS wmi_unified_get_link_speed_cmd(void *wmi_hdl, + wmi_mac_addr peer_macaddr); + +QDF_STATUS wmi_unified_egap_conf_params_cmd(void *wmi_hdl, + wmi_ap_ps_egap_param_cmd_fixed_param *egap_params); + +#endif + +QDF_STATUS wmi_unified_action_frame_patterns_cmd(void *wmi_hdl, + struct action_wakeup_set_param *action_params); + +QDF_STATUS wmi_unified_fw_profiling_data_cmd(void *wmi_hdl, + uint32_t cmd, uint32_t value1, uint32_t value2); + +QDF_STATUS wmi_unified_wow_sta_ra_filter_cmd(void *wmi_hdl, + uint8_t vdev_id, uint8_t default_pattern, + uint16_t rate_limit_interval); + +QDF_STATUS wmi_unified_nat_keepalive_en_cmd(void *wmi_hdl, uint8_t vdev_id); + +QDF_STATUS wmi_unified_csa_offload_enable(void *wmi_hdl, uint8_t vdev_id); + +QDF_STATUS wmi_unified_start_oem_data_cmd(void *wmi_hdl, + uint32_t data_len, + uint8_t *data); + +QDF_STATUS wmi_unified_dfs_phyerr_filter_offload_en_cmd(void *wmi_hdl, + bool dfs_phyerr_filter_offload); + +#ifndef WMI_NON_TLV_SUPPORT +QDF_STATUS wmi_unified_pktlog_wmi_send_cmd(void *wmi_hdl, + WMI_PKTLOG_EVENT pktlog_event, + uint32_t cmd_id, + uint8_t user_triggered); +#endif + +QDF_STATUS wmi_unified_add_wow_wakeup_event_cmd(void *wmi_hdl, + uint32_t vdev_id, + uint32_t *bitmap, + bool enable); + +QDF_STATUS wmi_unified_wow_patterns_to_fw_cmd(void *wmi_hdl, + uint8_t vdev_id, uint8_t ptrn_id, + const uint8_t *ptrn, uint8_t ptrn_len, + uint8_t ptrn_offset, const uint8_t *mask, + uint8_t mask_len, bool user, + uint8_t default_patterns); + +QDF_STATUS wmi_unified_wow_delete_pattern_cmd(void *wmi_hdl, uint8_t ptrn_id, + uint8_t vdev_id); + +QDF_STATUS wmi_unified_host_wakeup_ind_to_fw_cmd(void *wmi_hdl); +QDF_STATUS wmi_unified_del_ts_cmd(void *wmi_hdl, uint8_t vdev_id, + uint8_t ac); + +QDF_STATUS wmi_unified_aggr_qos_cmd(void *wmi_hdl, + struct aggr_add_ts_param *aggr_qos_rsp_msg); + +QDF_STATUS wmi_unified_add_ts_cmd(void *wmi_hdl, + struct add_ts_param *msg); + +QDF_STATUS wmi_unified_enable_disable_packet_filter_cmd(void *wmi_hdl, + uint8_t vdev_id, bool enable); + +QDF_STATUS wmi_unified_config_packet_filter_cmd(void *wmi_hdl, + uint8_t vdev_id, struct rcv_pkt_filter_config *rcv_filter_param, + uint8_t filter_id, bool enable); + +QDF_STATUS wmi_unified_add_clear_mcbc_filter_cmd(void *wmi_hdl, + uint8_t vdev_id, + struct qdf_mac_addr multicast_addr, + bool clearList); + +QDF_STATUS wmi_unified_send_gtk_offload_cmd(void *wmi_hdl, uint8_t vdev_id, + struct gtk_offload_params *params, + bool enable_offload, + uint32_t gtk_offload_opcode); + +QDF_STATUS wmi_unified_process_gtk_offload_getinfo_cmd(void *wmi_hdl, + uint8_t vdev_id, + uint64_t offload_req_opcode); + +QDF_STATUS wmi_unified_process_add_periodic_tx_ptrn_cmd(void *wmi_hdl, + struct periodic_tx_pattern * + pAddPeriodicTxPtrnParams, + uint8_t vdev_id); + +QDF_STATUS wmi_unified_process_del_periodic_tx_ptrn_cmd(void *wmi_hdl, + uint8_t vdev_id, + uint8_t pattern_id); + +QDF_STATUS wmi_unified_stats_ext_req_cmd(void *wmi_hdl, + struct stats_ext_params *preq); + +QDF_STATUS wmi_unified_enable_ext_wow_cmd(void *wmi_hdl, + struct ext_wow_params *params); + +QDF_STATUS wmi_unified_set_app_type2_params_in_fw_cmd(void *wmi_hdl, + struct app_type2_params *appType2Params); + +QDF_STATUS wmi_unified_set_auto_shutdown_timer_cmd(void *wmi_hdl, + uint32_t timer_val); + +QDF_STATUS wmi_unified_nan_req_cmd(void *wmi_hdl, + struct nan_req_params *nan_req); + +QDF_STATUS wmi_unified_process_dhcpserver_offload_cmd(void *wmi_hdl, + struct dhcp_offload_info_params *pDhcpSrvOffloadInfo); + +QDF_STATUS wmi_unified_process_ch_avoid_update_cmd(void *wmi_hdl); + +QDF_STATUS wmi_unified_send_regdomain_info_to_fw_cmd(void *wmi_hdl, + uint32_t reg_dmn, uint16_t regdmn2G, + uint16_t regdmn5G, int8_t ctl2G, + int8_t ctl5G); + +QDF_STATUS wmi_unified_set_tdls_offchan_mode_cmd(void *wmi_hdl, + struct tdls_channel_switch_params *chan_switch_params); + +QDF_STATUS wmi_unified_update_fw_tdls_state_cmd(void *wmi_hdl, + void *tdls_param, uint8_t tdls_state); + +QDF_STATUS wmi_unified_update_tdls_peer_state_cmd(void *wmi_hdl, + struct tdls_peer_state_params *peerStateParams, + uint32_t *ch_mhz); + +QDF_STATUS wmi_unified_process_fw_mem_dump_cmd(void *wmi_hdl, + struct fw_dump_req_param *mem_dump_req); + +QDF_STATUS wmi_unified_process_set_ie_info_cmd(void *wmi_hdl, + struct vdev_ie_info_param *ie_info); + +QDF_STATUS wmi_unified_ocb_set_utc_time_cmd(void *wmi_hdl, + struct ocb_utc_param *utc); + +QDF_STATUS wmi_unified_dcc_get_stats_cmd(void *wmi_hdl, + struct dcc_get_stats_param *get_stats_param); + +QDF_STATUS wmi_unified_dcc_clear_stats(void *wmi_hdl, + uint32_t vdev_id, uint32_t dcc_stats_bitmap); + +QDF_STATUS wmi_unified_dcc_update_ndl(void *wmi_hdl, + struct dcc_update_ndl_param *update_ndl_param); + +QDF_STATUS wmi_unified_save_fw_version_cmd(void *wmi_hdl, + void *evt_buf); + +#ifdef CONFIG_MCL +QDF_STATUS wmi_unified_send_init_cmd(void *wmi_hdl, + wmi_resource_config *res_cfg, + uint8_t num_mem_chunks, struct wmi_host_mem_chunk *mem_chunk, + bool action); +#endif + +QDF_STATUS wmi_unified_send_saved_init_cmd(void *wmi_hdl); + +QDF_STATUS wmi_unified_set_base_macaddr_indicate_cmd(void *wmi_hdl, + uint8_t *custom_addr); + +QDF_STATUS wmi_unified_log_supported_evt_cmd(void *wmi_hdl, + uint8_t *event, + uint32_t len); + +QDF_STATUS wmi_unified_enable_specific_fw_logs_cmd(void *wmi_hdl, + struct wmi_wifi_start_log *start_log); + +QDF_STATUS wmi_unified_flush_logs_to_fw_cmd(void *wmi_hdl); + +QDF_STATUS wmi_unified_pdev_set_pcl_cmd(void *wmi_hdl, + struct wmi_pcl_chan_weights *msg); + +QDF_STATUS wmi_unified_soc_set_hw_mode_cmd(void *wmi_hdl, + uint32_t hw_mode_index); + +QDF_STATUS wmi_unified_pdev_set_dual_mac_config_cmd(void *wmi_hdl, + struct wmi_dual_mac_config *msg); + +QDF_STATUS wmi_unified_enable_arp_ns_offload_cmd(void *wmi_hdl, + struct host_offload_req_param *arp_offload_req, + struct host_offload_req_param *ns_offload_req, + bool arp_only, + uint8_t vdev_id); + +/** + * wmi_unified_conf_hw_filter_mode_cmd() - Configure hardware filter + * @wmi_hdl: wmi handle + * @vdev_id: device identifier + * @config_bitmap: bitmap of packet types to drop + * + * The hardware filter is only effective in DTIM mode. Use this configuration + * to blanket drop broadcast/multicast packets at the hardware level, without + * waking up the firmware + * + * Return: QDF_STATUS + */ +QDF_STATUS wmi_unified_conf_hw_filter_mode_cmd(void *wmi_hdl, + uint8_t vdev_id, + uint8_t config_bitmap); + +QDF_STATUS wmi_unified_set_led_flashing_cmd(void *wmi_hdl, + struct flashing_req_params *flashing); + +QDF_STATUS wmi_unified_app_type1_params_in_fw_cmd(void *wmi_hdl, + struct app_type1_params *app_type1_params); + +QDF_STATUS wmi_unified_set_ssid_hotlist_cmd(void *wmi_hdl, + struct ssid_hotlist_request_params *request); + +QDF_STATUS wmi_unified_roam_synch_complete_cmd(void *wmi_hdl, + uint8_t vdev_id); + +QDF_STATUS wmi_unified_unit_test_cmd(void *wmi_hdl, + struct wmi_unit_test_cmd *wmi_utest); + +QDF_STATUS wmi_unified_roam_invoke_cmd(void *wmi_hdl, + struct wmi_roam_invoke_cmd *roaminvoke, + uint32_t ch_hz); + +QDF_STATUS wmi_unified_roam_scan_offload_cmd(void *wmi_hdl, + uint32_t command, uint32_t vdev_id); + +#ifndef WMI_NON_TLV_SUPPORT +QDF_STATUS wmi_unified_send_roam_scan_offload_ap_cmd(void *wmi_hdl, + wmi_ap_profile *ap_profile_p, + uint32_t vdev_id); +#endif + +QDF_STATUS wmi_unified_roam_scan_offload_scan_period(void *wmi_hdl, + uint32_t scan_period, + uint32_t scan_age, + uint32_t vdev_id); + +QDF_STATUS wmi_unified_roam_scan_offload_chan_list_cmd(void *wmi_hdl, + uint8_t chan_count, + uint32_t *chan_list, + uint8_t list_type, uint32_t vdev_id); + +QDF_STATUS wmi_unified_roam_scan_offload_rssi_change_cmd(void *wmi_hdl, + uint32_t vdev_id, + int32_t rssi_change_thresh, + uint32_t bcn_rssi_weight, + uint32_t hirssi_delay_btw_scans); + +/** + * wmi_unified_set_per_roam_config() - set PER roam config in FW + * @wmi_hdl: wmi handle + * @req_buf: per roam config request buffer + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_set_per_roam_config(void *wmi_hdl, + struct wmi_per_roam_config_req *req_buf); + +QDF_STATUS wmi_unified_get_buf_extscan_hotlist_cmd(void *wmi_hdl, + struct ext_scan_setbssi_hotlist_params * + photlist, int *buf_len); + +/** + * wmi_unified_set_active_bpf_mode_cmd() - config active BPF mode in FW + * @wmi_hdl: the WMI handle + * @vdev_id: the Id of the vdev to apply the configuration to + * @ucast_mode: the active BPF mode to configure for unicast packets + * @mcast_bcast_mode: the active BPF mode to configure for multicast/broadcast + * packets + */ +QDF_STATUS +wmi_unified_set_active_bpf_mode_cmd(void *wmi_hdl, + uint8_t vdev_id, + FW_ACTIVE_BPF_MODE ucast_mode, + FW_ACTIVE_BPF_MODE mcast_bcast_mode); + +QDF_STATUS wmi_unified_stats_request_send(void *wmi_hdl, + uint8_t macaddr[IEEE80211_ADDR_LEN], + struct stats_request_params *param); + +QDF_STATUS wmi_unified_pdev_get_tpc_config_cmd_send(void *wmi_hdl, + uint32_t param); + +QDF_STATUS wmi_unified_set_bwf_cmd_send(void *wmi_hdl, + struct set_bwf_params *param); + +QDF_STATUS wmi_unified_set_atf_cmd_send(void *wmi_hdl, + struct set_atf_params *param); + +QDF_STATUS wmi_unified_pdev_fips_cmd_send(void *wmi_hdl, + struct fips_params *param); + +QDF_STATUS wmi_unified_wlan_profile_enable_cmd_send(void *wmi_hdl, + struct wlan_profile_params *param); + +QDF_STATUS wmi_unified_wlan_profile_trigger_cmd_send(void *wmi_hdl, + struct wlan_profile_params *param); + +QDF_STATUS wmi_unified_set_chan_cmd_send(void *wmi_hdl, + struct channel_param *param); + +QDF_STATUS wmi_unified_set_ht_ie_cmd_send(void *wmi_hdl, + struct ht_ie_params *param); + +QDF_STATUS wmi_unified_set_vht_ie_cmd_send(void *wmi_hdl, + struct vht_ie_params *param); + +QDF_STATUS wmi_unified_wmm_update_cmd_send(void *wmi_hdl, + struct wmm_update_params *param); + +QDF_STATUS wmi_unified_set_ant_switch_tbl_cmd_send(void *wmi_hdl, + struct ant_switch_tbl_params *param); + +QDF_STATUS wmi_unified_set_ratepwr_table_cmd_send(void *wmi_hdl, + struct ratepwr_table_params *param); + +QDF_STATUS wmi_unified_get_ratepwr_table_cmd_send(void *wmi_hdl); + +QDF_STATUS wmi_unified_set_ctl_table_cmd_send(void *wmi_hdl, + struct ctl_table_params *param); + +QDF_STATUS wmi_unified_set_mimogain_table_cmd_send(void *wmi_hdl, + struct mimogain_table_params *param); + +QDF_STATUS wmi_unified_set_ratepwr_chainmsk_cmd_send(void *wmi_hdl, + struct ratepwr_chainmsk_params *param); + +QDF_STATUS wmi_unified_set_macaddr_cmd_send(void *wmi_hdl, + struct macaddr_params *param); + +QDF_STATUS wmi_unified_pdev_scan_start_cmd_send(void *wmi_hdl); + +QDF_STATUS wmi_unified_pdev_scan_end_cmd_send(void *wmi_hdl); + +QDF_STATUS wmi_unified_set_acparams_cmd_send(void *wmi_hdl, + struct acparams_params *param); + +QDF_STATUS wmi_unified_set_vap_dscp_tid_map_cmd_send(void *wmi_hdl, + struct vap_dscp_tid_map_params *param); + +QDF_STATUS wmi_unified_proxy_ast_reserve_cmd_send(void *wmi_hdl, + struct proxy_ast_reserve_params *param); + +QDF_STATUS wmi_unified_pdev_qvit_cmd_send(void *wmi_hdl, + struct pdev_qvit_params *param); + +QDF_STATUS wmi_unified_mcast_group_update_cmd_send(void *wmi_hdl, + struct mcast_group_update_params *param); + +QDF_STATUS wmi_unified_peer_add_wds_entry_cmd_send(void *wmi_hdl, + struct peer_add_wds_entry_params *param); + +QDF_STATUS wmi_unified_peer_del_wds_entry_cmd_send(void *wmi_hdl, + struct peer_del_wds_entry_params *param); + +QDF_STATUS wmi_unified_peer_update_wds_entry_cmd_send(void *wmi_hdl, + struct peer_update_wds_entry_params *param); + +QDF_STATUS wmi_unified_phyerr_enable_cmd_send(void *wmi_hdl); + +QDF_STATUS wmi_unified_phyerr_enable_cmd_send(void *wmi_hdl); + +QDF_STATUS wmi_unified_phyerr_disable_cmd_send(void *wmi_hdl); + +QDF_STATUS wmi_unified_smart_ant_enable_cmd_send(void *wmi_hdl, + struct smart_ant_enable_params *param); + +QDF_STATUS wmi_unified_smart_ant_set_rx_ant_cmd_send(void *wmi_hdl, + struct smart_ant_rx_ant_params *param); + +QDF_STATUS wmi_unified_smart_ant_set_tx_ant_cmd_send(void *wmi_hdl, + uint8_t macaddr[IEEE80211_ADDR_LEN], + struct smart_ant_tx_ant_params *param); + +QDF_STATUS wmi_unified_smart_ant_set_training_info_cmd_send(void *wmi_hdl, + uint8_t macaddr[IEEE80211_ADDR_LEN], + struct smart_ant_training_info_params *param); + +QDF_STATUS wmi_unified_smart_ant_node_config_cmd_send(void *wmi_hdl, + uint8_t macaddr[IEEE80211_ADDR_LEN], + struct smart_ant_node_config_params *param); + +QDF_STATUS wmi_unified_smart_ant_enable_tx_feedback_cmd_send(void *wmi_hdl, + struct smart_ant_enable_tx_feedback_params *param); + +QDF_STATUS wmi_unified_vdev_spectral_configure_cmd_send(void *wmi_hdl, + struct vdev_spectral_configure_params *param); + +QDF_STATUS wmi_unified_vdev_spectral_enable_cmd_send(void *wmi_hdl, + struct vdev_spectral_enable_params *param); + +QDF_STATUS wmi_unified_bss_chan_info_request_cmd_send(void *wmi_hdl, + struct bss_chan_info_request_params *param); + +QDF_STATUS wmi_unified_thermal_mitigation_param_cmd_send(void *wmi_hdl, + struct thermal_mitigation_params *param); + +QDF_STATUS wmi_unified_vdev_set_neighbour_rx_cmd_send(void *wmi_hdl, + uint8_t macaddr[IEEE80211_ADDR_LEN], + struct set_neighbour_rx_params *param); + +QDF_STATUS wmi_unified_vdev_set_fwtest_param_cmd_send(void *wmi_hdl, + struct set_fwtest_params *param); + +QDF_STATUS wmi_unified_vdev_config_ratemask_cmd_send(void *wmi_hdl, + struct config_ratemask_params *param); + +QDF_STATUS wmi_unified_vdev_install_key_cmd_send(void *wmi_hdl, + uint8_t macaddr[IEEE80211_ADDR_LEN], + struct vdev_install_key_params *param); + +QDF_STATUS wmi_unified_pdev_set_regdomain_cmd_send(void *wmi_hdl, + struct pdev_set_regdomain_params *param); + +QDF_STATUS wmi_unified_set_quiet_mode_cmd_send(void *wmi_hdl, + struct set_quiet_mode_params *param); + +QDF_STATUS wmi_unified_set_beacon_filter_cmd_send(void *wmi_hdl, + struct set_beacon_filter_params *param); + +QDF_STATUS wmi_unified_remove_beacon_filter_cmd_send(void *wmi_hdl, + struct remove_beacon_filter_params *param); + +QDF_STATUS wmi_unified_addba_clearresponse_cmd_send(void *wmi_hdl, + uint8_t macaddr[IEEE80211_ADDR_LEN], + struct addba_clearresponse_params *param); + +QDF_STATUS wmi_unified_addba_send_cmd_send(void *wmi_hdl, + uint8_t macaddr[IEEE80211_ADDR_LEN], + struct addba_send_params *param); + +QDF_STATUS wmi_unified_delba_send_cmd_send(void *wmi_hdl, + uint8_t macaddr[IEEE80211_ADDR_LEN], + struct delba_send_params *param); + +QDF_STATUS wmi_unified_addba_setresponse_cmd_send(void *wmi_hdl, + uint8_t macaddr[IEEE80211_ADDR_LEN], + struct addba_setresponse_params *param); + +QDF_STATUS wmi_unified_singleamsdu_cmd_send(void *wmi_hdl, + uint8_t macaddr[IEEE80211_ADDR_LEN], + struct singleamsdu_params *param); + +QDF_STATUS wmi_unified_set_qboost_param_cmd_send(void *wmi_hdl, + uint8_t macaddr[IEEE80211_ADDR_LEN], + struct set_qboost_params *param); + +QDF_STATUS wmi_unified_mu_scan_cmd_send(void *wmi_hdl, + struct mu_scan_params *param); + +QDF_STATUS wmi_unified_lteu_config_cmd_send(void *wmi_hdl, + struct lteu_config_params *param); + +QDF_STATUS wmi_unified_set_psmode_cmd_send(void *wmi_hdl, + struct set_ps_mode_params *param); + +QDF_STATUS wmi_unified_init_cmd_send(void *wmi_hdl, + target_resource_config *res_cfg, + uint8_t num_mem_chunks, + struct wmi_host_mem_chunk *mem_chunk); + +bool wmi_service_enabled(void *wmi_hdl, uint32_t service_id); + +QDF_STATUS wmi_save_service_bitmap(void *wmi_hdl, void *evt_buf); + +QDF_STATUS wmi_save_fw_version(void *wmi_hdl, void *evt_buf); + +QDF_STATUS wmi_get_target_cap_from_service_ready(void *wmi_hdl, + void *evt_buf, target_capability_info *ev); + +QDF_STATUS wmi_extract_hal_reg_cap(void *wmi_hdl, void *evt_buf, + TARGET_HAL_REG_CAPABILITIES *hal_reg_cap); + +host_mem_req *wmi_extract_host_mem_req_from_service_ready(void *wmi_hdl, + void *evt_buf, uint8_t *num_entries); + +uint32_t wmi_ready_extract_init_status(void *wmi_hdl, void *ev); + +QDF_STATUS wmi_ready_extract_mac_addr(void *wmi_hdl, + void *ev, uint8_t *macaddr); + +QDF_STATUS wmi_extract_fw_version(void *wmi_hdl, + void *ev, struct wmi_host_fw_ver *fw_ver); + +QDF_STATUS wmi_extract_fw_abi_version(void *wmi_hdl, + void *ev, struct wmi_host_fw_abi_ver *fw_ver); + +QDF_STATUS wmi_check_and_update_fw_version(void *wmi_hdl, void *ev); + +uint8_t *wmi_extract_dbglog_data_len(void *wmi_hdl, + void *evt_b, uint16_t *len); + +QDF_STATUS wmi_send_ext_resource_config(void *wmi_hdl, + wmi_host_ext_resource_config *ext_cfg); + +QDF_STATUS wmi_unified_nf_dbr_dbm_info_get_cmd_send(void *wmi_hdl); + +QDF_STATUS wmi_unified_packet_power_info_get_cmd_send(void *wmi_hdl, + struct packet_power_info_params *param); + +QDF_STATUS wmi_unified_gpio_config_cmd_send(void *wmi_hdl, + struct gpio_config_params *param); + +QDF_STATUS wmi_unified_gpio_output_cmd_send(void *wmi_hdl, + struct gpio_output_params *param); + +QDF_STATUS wmi_unified_rtt_meas_req_test_cmd_send(void *wmi_hdl, + struct rtt_meas_req_test_params *param); + +QDF_STATUS wmi_unified_rtt_meas_req_cmd_send(void *wmi_hdl, + struct rtt_meas_req_params *param); + +QDF_STATUS wmi_unified_rtt_keepalive_req_cmd_send(void *wmi_hdl, + struct rtt_keepalive_req_params *param); + +QDF_STATUS wmi_unified_lci_set_cmd_send(void *wmi_hdl, + struct lci_set_params *param); + +QDF_STATUS wmi_unified_lcr_set_cmd_send(void *wmi_hdl, + struct lcr_set_params *param); + +QDF_STATUS wmi_unified_send_periodic_chan_stats_config_cmd(void *wmi_hdl, + struct periodic_chan_stats_params *param); + +QDF_STATUS +wmi_send_atf_peer_request_cmd(void *wmi_hdl, + struct atf_peer_request_params *param); + +QDF_STATUS +wmi_send_set_atf_grouping_cmd(void *wmi_hdl, + struct atf_grouping_params *param); +/* Extract APIs */ + +QDF_STATUS wmi_extract_wds_addr_event(void *wmi_hdl, + void *evt_buf, uint16_t len, wds_addr_event_t *wds_ev); + +QDF_STATUS wmi_extract_dcs_interference_type(void *wmi_hdl, + void *evt_buf, uint32_t *interference_type); + +QDF_STATUS wmi_extract_dcs_cw_int(void *wmi_hdl, void *evt_buf, + wmi_host_ath_dcs_cw_int *cw_int); + +QDF_STATUS wmi_extract_dcs_im_tgt_stats(void *wmi_hdl, void *evt_buf, + wmi_host_dcs_im_tgt_stats_t *wlan_stat); + +QDF_STATUS wmi_extract_fips_event_error_status(void *wmi_hdl, void *evt_buf, + uint32_t *err_status); + +QDF_STATUS wmi_extract_fips_event_data(void *wmi_hdl, void *evt_buf, + uint32_t *data_len, uint32_t **data); +QDF_STATUS wmi_extract_vdev_start_resp(void *wmi_hdl, void *evt_buf, + wmi_host_vdev_start_resp *vdev_rsp); +QDF_STATUS wmi_extract_tbttoffset_update_params(void *wmi_hdl, void *evt_buf, + uint32_t *vdev_map, uint32_t **tbttoffset_list); + +QDF_STATUS wmi_extract_mgmt_rx_params(void *wmi_hdl, void *evt_buf, + wmi_host_mgmt_rx_hdr *hdr, uint8_t **bufp); + +QDF_STATUS wmi_extract_vdev_stopped_param(void *wmi_hdl, void *evt_buf, + uint32_t *vdev_id); + +QDF_STATUS wmi_extract_vdev_roam_param(void *wmi_hdl, void *evt_buf, + wmi_host_roam_event *ev); + +QDF_STATUS wmi_extract_vdev_scan_ev_param(void *wmi_hdl, void *evt_buf, + wmi_host_scan_event *param); + +QDF_STATUS wmi_extract_mu_ev_param(void *wmi_hdl, void *evt_buf, + wmi_host_mu_report_event *param); + +QDF_STATUS wmi_extract_pdev_tpc_config_ev_param(void *wmi_hdl, void *evt_buf, + wmi_host_pdev_tpc_config_event *param); + +QDF_STATUS wmi_extract_gpio_input_ev_param(void *wmi_hdl, + void *evt_buf, uint32_t *gpio_num); + +QDF_STATUS wmi_extract_pdev_reserve_ast_ev_param(void *wmi_hdl, + void *evt_buf, uint32_t *result); + +QDF_STATUS wmi_extract_nfcal_power_ev_param(void *wmi_hdl, void *evt_buf, + wmi_host_pdev_nfcal_power_all_channels_event *param); + +QDF_STATUS wmi_extract_pdev_tpc_ev_param(void *wmi_hdl, void *evt_buf, + wmi_host_pdev_tpc_event *param); + +QDF_STATUS wmi_extract_pdev_generic_buffer_ev_param(void *wmi_hdl, + void *evt_buf, + wmi_host_pdev_generic_buffer_event *param); + +QDF_STATUS wmi_extract_mgmt_tx_compl_param(void *wmi_hdl, void *evt_buf, + wmi_host_mgmt_tx_compl_event *param); + +QDF_STATUS wmi_extract_swba_vdev_map(void *wmi_hdl, void *evt_buf, + uint32_t *vdev_map); + +QDF_STATUS wmi_extract_swba_tim_info(void *wmi_hdl, void *evt_buf, + uint32_t idx, wmi_host_tim_info *tim_info); + +QDF_STATUS wmi_extract_swba_noa_info(void *wmi_hdl, void *evt_buf, + uint32_t idx, wmi_host_p2p_noa_info *p2p_desc); + +QDF_STATUS wmi_extract_peer_sta_ps_statechange_ev(void *wmi_hdl, + void *evt_buf, wmi_host_peer_sta_ps_statechange_event *ev); + +QDF_STATUS wmi_extract_peer_sta_kickout_ev(void *wmi_hdl, void *evt_buf, + wmi_host_peer_sta_kickout_event *ev); + +QDF_STATUS wmi_extract_peer_ratecode_list_ev(void *wmi_hdl, void *evt_buf, + uint8_t *peer_mac, wmi_sa_rate_cap *rate_cap); + +QDF_STATUS wmi_extract_bcnflt_stats(void *wmi_hdl, void *evt_buf, + uint32_t index, wmi_host_bcnflt_stats *bcnflt_stats); + +QDF_STATUS wmi_extract_rtt_hdr(void *wmi_hdl, void *evt_buf, + wmi_host_rtt_event_hdr *ev); + +QDF_STATUS wmi_extract_rtt_ev(void *wmi_hdl, void *evt_buf, + wmi_host_rtt_meas_event *ev, uint8_t *hdump, + uint16_t hdump_len); + +QDF_STATUS wmi_extract_rtt_error_report_ev(void *wmi_hdl, void *evt_buf, + wmi_host_rtt_error_report_event *ev); + +QDF_STATUS wmi_extract_chan_stats(void *wmi_hdl, void *evt_buf, + uint32_t index, wmi_host_chan_stats *chan_stats); + +QDF_STATUS wmi_extract_thermal_stats(void *wmi_hdl, void *evt_buf, + uint32_t *temp, uint32_t *level); + +QDF_STATUS wmi_extract_thermal_level_stats(void *wmi_hdl, void *evt_buf, + uint8_t idx, uint32_t *levelcount, uint32_t *dccount); + +QDF_STATUS wmi_extract_comb_phyerr(void *wmi_hdl, void *evt_buf, + uint16_t datalen, uint16_t *buf_offset, + wmi_host_phyerr_t *phyerr); + +QDF_STATUS wmi_extract_single_phyerr(void *wmi_hdl, void *evt_buf, + uint16_t datalen, uint16_t *buf_offset, + wmi_host_phyerr_t *phyerr); + +QDF_STATUS wmi_extract_composite_phyerr(void *wmi_hdl, void *evt_buf, + uint16_t datalen, wmi_host_phyerr_t *phyerr); + +QDF_STATUS wmi_extract_profile_ctx(void *wmi_hdl, void *evt_buf, + wmi_host_wlan_profile_ctx_t *profile_ctx); + +QDF_STATUS wmi_extract_profile_data(void *wmi_hdl, void *evt_buf, uint8_t idx, + wmi_host_wlan_profile_t *profile_data); + +QDF_STATUS wmi_extract_chan_info_event(void *wmi_hdl, void *evt_buf, + wmi_host_chan_info_event *chan_info); + +QDF_STATUS wmi_extract_channel_hopping_event(void *wmi_hdl, void *evt_buf, + wmi_host_pdev_channel_hopping_event *ch_hopping); + +QDF_STATUS wmi_extract_stats_param(void *wmi_hdl, void *evt_buf, + wmi_host_stats_event *stats_param); + +QDF_STATUS wmi_extract_pdev_stats(void *wmi_hdl, void *evt_buf, + uint32_t index, + wmi_host_pdev_stats *pdev_stats); + +QDF_STATUS wmi_extract_pdev_ext_stats(void *wmi_hdl, void *evt_buf, + uint32_t index, + wmi_host_pdev_ext_stats *pdev_ext_stats); + +QDF_STATUS wmi_extract_peer_extd_stats(void *wmi_hdl, void *evt_buf, + uint32_t index, + wmi_host_peer_extd_stats *peer_extd_stats); + +QDF_STATUS wmi_extract_bss_chan_info_event(void *wmi_hdl, void *evt_buf, + wmi_host_pdev_bss_chan_info_event *bss_chan_info); + +QDF_STATUS wmi_extract_inst_rssi_stats_event(void *wmi_hdl, void *evt_buf, + wmi_host_inst_stats_resp *inst_rssi_resp); + +QDF_STATUS wmi_extract_peer_stats(void *wmi_hdl, void *evt_buf, + uint32_t index, wmi_host_peer_stats *peer_stats); + +QDF_STATUS wmi_extract_tx_data_traffic_ctrl_ev(void *wmi_hdl, void *evt_buf, + wmi_host_tx_data_traffic_ctrl_event *ev); + +QDF_STATUS wmi_extract_vdev_stats(void *wmi_hdl, void *evt_buf, + uint32_t index, wmi_host_vdev_stats *vdev_stats); + +QDF_STATUS wmi_extract_vdev_extd_stats(void *wmi_hdl, void *evt_buf, + uint32_t index, wmi_host_vdev_extd_stats *vdev_extd_stats); + +QDF_STATUS wmi_unified_send_power_dbg_cmd(void *wmi_hdl, + struct wmi_power_dbg_params *param); +QDF_STATUS wmi_unified_send_sar_limit_cmd(void *wmi_hdl, + struct sar_limit_cmd_params *params); +QDF_STATUS wmi_unified_send_adapt_dwelltime_params_cmd(void *wmi_hdl, + struct wmi_adaptive_dwelltime_params * + wmi_param); +QDF_STATUS wmi_unified_fw_test_cmd(void *wmi_hdl, + struct set_fwtest_params *wmi_fwtest); + +/** + * wmi_unified_get_rcpi_cmd() - get rcpi request + * @wmi_hdl: wma handle + * @get_rcpi_param: rcpi params + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_get_rcpi_cmd(void *wmi_hdl, + struct rcpi_req *get_rcpi_param); + +QDF_STATUS wmi_unified_set_arp_stats_req(void *wmi_hdl, + struct set_arp_stats *req_buf); +QDF_STATUS wmi_unified_get_arp_stats_req(void *wmi_hdl, + struct get_arp_stats *req_buf); +#endif /* _WMI_UNIFIED_API_H_ */ diff --git a/drivers/staging/qca-wifi-host-cmn/wmi/inc/wmi_unified_non_tlv.h b/drivers/staging/qca-wifi-host-cmn/wmi/inc/wmi_unified_non_tlv.h new file mode 100644 index 0000000000000000000000000000000000000000..2c8661e1142e7afd451b5b55d0b6513f7d0f49c4 --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/wmi/inc/wmi_unified_non_tlv.h @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#include +#include "a_types.h" +#include "wmi_unified_param.h" +#include "legacy/wmi.h" +#include "legacy/wmi_unified.h" +#include "ol_defines.h" /* Fix Me: wmi_unified_t structure definition */ + +QDF_STATUS send_vdev_create_cmd_non_tlv(wmi_unified_t wmi_handle, + uint8_t macaddr[IEEE80211_ADDR_LEN], + struct vdev_create_params *param); + +QDF_STATUS send_vdev_delete_cmd_non_tlv(wmi_unified_t wmi_handle, + uint8_t if_id); + +QDF_STATUS send_vdev_stop_cmd_non_tlv(wmi_unified_t wmi, + uint8_t vdev_id); + +QDF_STATUS send_vdev_down_cmd_non_tlv(wmi_unified_t wmi, + uint8_t vdev_id); + +QDF_STATUS send_peer_flush_tids_cmd_non_tlv(wmi_unified_t wmi, + uint8_t peer_addr[IEEE80211_ADDR_LEN], + struct peer_flush_params *param); + +QDF_STATUS send_peer_delete_cmd_non_tlv(wmi_unified_t wmi, + uint8_t peer_addr[IEEE80211_ADDR_LEN], + uint8_t vdev_id); + +QDF_STATUS send_peer_param_cmd_non_tlv(wmi_unified_t wmi, + uint8_t peer_addr[IEEE80211_ADDR_LEN], + struct peer_set_params *param); + +QDF_STATUS send_vdev_up_cmd_non_tlv(wmi_unified_t wmi, + uint8_t bssid[IEEE80211_ADDR_LEN], + struct vdev_up_params *params); + +QDF_STATUS send_peer_create_cmd_non_tlv(wmi_unified_t wmi, + struct peer_create_params *param); + +QDF_STATUS send_green_ap_ps_cmd_non_tlv(wmi_unified_t wmi_handle, + uint32_t value, uint8_t mac_id); + +QDF_STATUS +send_pdev_utf_cmd_non_tlv(wmi_unified_t wmi_handle, + struct pdev_utf_params *param, + uint8_t mac_id); + +QDF_STATUS +send_pdev_param_cmd_non_tlv(wmi_unified_t wmi_handle, + struct pdev_params *param, + uint8_t mac_id); + +QDF_STATUS send_suspend_cmd_non_tlv(wmi_unified_t wmi_handle, + struct suspend_params *param, + uint8_t mac_id); + +QDF_STATUS send_resume_cmd_non_tlv(wmi_unified_t wmi_handle, + uint8_t mac_id); + +QDF_STATUS send_wow_enable_cmd_non_tlv(wmi_unified_t wmi_handle, + struct wow_cmd_params *param, + uint8_t mac_id); + +QDF_STATUS send_set_ap_ps_param_cmd_non_tlv(wmi_unified_t wmi_handle, + uint8_t *peer_addr, + struct ap_ps_params *param); + +QDF_STATUS send_set_sta_ps_param_cmd_non_tlv(wmi_unified_t wmi_handle, + struct sta_ps_params *param); + +QDF_STATUS send_crash_inject_cmd_non_tlv(wmi_unified_t wmi_handle, + struct crash_inject *param); + +QDF_STATUS +send_dbglog_cmd_non_tlv(wmi_unified_t wmi_handle, + struct dbglog_params *dbglog_param); + +QDF_STATUS send_vdev_set_param_cmd_non_tlv(wmi_unified_t wmi_handle, + struct vdev_set_params *param); + +QDF_STATUS send_stats_request_cmd_non_tlv(wmi_unified_t wmi_handle, + uint8_t macaddr[IEEE80211_ADDR_LEN], + struct stats_request_params *param); + +QDF_STATUS send_beacon_send_cmd_non_tlv(wmi_unified_t wmi_handle, + struct beacon_params *param); + +QDF_STATUS send_peer_assoc_cmd_non_tlv(wmi_unified_t wmi_handle, + struct peer_assoc_params *param); + +QDF_STATUS send_scan_start_cmd_non_tlv(wmi_unified_t wmi_handle, + struct scan_start_params *param); + +QDF_STATUS send_scan_stop_cmd_non_tlv(wmi_unified_t wmi_handle, + struct scan_stop_params *param); + +QDF_STATUS send_scan_chan_list_cmd_non_tlv(wmi_unified_t wmi_handle, + struct scan_chan_list_params *param); diff --git a/drivers/staging/qca-wifi-host-cmn/wmi/inc/wmi_unified_param.h b/drivers/staging/qca-wifi-host-cmn/wmi/inc/wmi_unified_param.h new file mode 100644 index 0000000000000000000000000000000000000000..0f41b4ffea17c957624b361bb2d346d2b29f9aaf --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/wmi/inc/wmi_unified_param.h @@ -0,0 +1,6864 @@ +/* + * Copyright (c) 2016-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * This file contains the API definitions for the Unified Wireless Module + * Interface (WMI). + */ + +#ifndef _WMI_UNIFIED_PARAM_H_ +#define _WMI_UNIFIED_PARAM_H_ + +#define MAC_MAX_KEY_LENGTH 32 +#define MAC_PN_LENGTH 8 +#define MAX_MAC_HEADER_LEN 32 +#define MIN_MAC_HEADER_LEN 24 +#define QOS_CONTROL_LEN 2 + +#define IEEE80211_ADDR_LEN 6 /* size of 802.11 address */ +#define WMI_MAC_MAX_SSID_LENGTH 32 +#define WMI_SCAN_MAX_NUM_SSID 0x0A +#define mgmt_tx_dl_frm_len 64 +#define WMI_SMPS_MASK_LOWER_16BITS 0xFF +#define WMI_SMPS_MASK_UPPER_3BITS 0x7 +#define WMI_SMPS_PARAM_VALUE_S 29 +#define WMI_MAX_NUM_ARGS 8 +/* The size of the utc time in bytes. */ +#define WMI_SIZE_UTC_TIME (10) +/* The size of the utc time error in bytes. */ +#define WMI_SIZE_UTC_TIME_ERROR (5) +#define WMI_MCC_MIN_CHANNEL_QUOTA 20 +#define WMI_MCC_MAX_CHANNEL_QUOTA 80 +#define WMI_MCC_MIN_NON_ZERO_CHANNEL_LATENCY 30 +#define WMI_BEACON_TX_BUFFER_SIZE (512) +#define WMI_WIFI_SCANNING_MAC_OUI_LENGTH 3 +#define WMI_EXTSCAN_MAX_SIGNIFICANT_CHANGE_APS 64 +#define WMI_RSSI_THOLD_DEFAULT -300 +#define WMI_NLO_FREQ_THRESH 1000 +#define WMI_SEC_TO_MSEC(sec) (sec * 1000) +#define WMI_MSEC_TO_USEC(msec) (msec * 1000) +#define WMI_ETH_LEN 64 +#define WMI_QOS_NUM_TSPEC_MAX 2 +#define WMI_QOS_NUM_AC_MAX 4 +#define WMI_IPV4_ADDR_LEN 4 +#define WMI_KEEP_ALIVE_NULL_PKT 1 +#define WMI_KEEP_ALIVE_UNSOLICIT_ARP_RSP 2 +#define WMI_MAC_MAX_KEY_LENGTH 32 +#define WMI_KRK_KEY_LEN 16 +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +#define WMI_BTK_KEY_LEN 32 +#define WMI_ROAM_R0KH_ID_MAX_LEN 48 +#define WMI_ROAM_SCAN_PSK_SIZE 32 +#endif +#define WMI_NOISE_FLOOR_DBM_DEFAULT (-96) +#define WMI_MAC_IPV6_ADDR_LEN 16 +#define WMI_OFFLOAD_DISABLE 0 +#define WMI_OFFLOAD_ENABLE 1 +#ifdef WLAN_NS_OFFLOAD +/* support only one IPv6 offload */ +#define WMI_MAC_NS_OFFLOAD_SIZE 1 +/* Number of target IP V6 addresses for NS offload */ +#define WMI_MAC_NUM_TARGET_IPV6_NS_OFFLOAD_NA 16 +#define WMI_IPV6_ADDR_VALID 1 +#endif /* WLAN_NS_OFFLOAD */ +#define WMI_EXTSCAN_MAX_HOTLIST_SSIDS 8 +#define WMI_ROAM_MAX_CHANNELS 80 +#ifdef FEATURE_WLAN_EXTSCAN +#define WMI_MAX_EXTSCAN_MSG_SIZE 1536 +#define WMI_EXTSCAN_REST_TIME 100 +#define WMI_EXTSCAN_MAX_SCAN_TIME 50000 +#define WMI_EXTSCAN_BURST_DURATION 150 +#endif +#define WMI_SCAN_NPROBES_DEFAULT (2) +#define WMI_SEC_TO_MSEC(sec) (sec * 1000) /* sec to msec */ +#define WMI_MSEC_TO_USEC(msec) (msec * 1000) /* msec to usec */ +#define WMI_NLO_FREQ_THRESH 1000 /* in MHz */ + +#define MAX_UTF_EVENT_LENGTH 2048 +#define MAX_WMI_UTF_LEN 252 +#define MAX_WMI_QVIT_LEN 252 +#define THERMAL_LEVELS 4 +#define WMI_HOST_BCN_FLT_MAX_SUPPORTED_IES 256 +#define WMI_HOST_BCN_FLT_MAX_ELEMS_IE_LIST \ + (WMI_HOST_BCN_FLT_MAX_SUPPORTED_IES/32) +#define LTEU_MAX_BINS 10 +#define ATF_ACTIVED_MAX_CLIENTS 50 +#define ATF_ACTIVED_MAX_ATFGROUPS 8 +#define CTL_5G_SIZE 1536 +#define CTL_2G_SIZE 684 +#define MAX_CTL_SIZE (CTL_5G_SIZE > CTL_2G_SIZE ? CTL_5G_SIZE : CTL_2G_SIZE) +#define IEEE80211_MICBUF_SIZE (8+8) +#define IEEE80211_TID_SIZE 17 +#define WME_NUM_AC 4 +#define SMART_ANT_MODE_SERIAL 0 +#define SMART_ANT_MODE_PARALLEL 1 +#define IEEE80211_WEP_NKID 4 /* number of key ids */ +#define WPI_IV_LEN 16 +#define WMI_SCAN_MAX_NUM_BSSID 10 +#define MAX_CHANS 1023 +#define TARGET_OEM_CONFIGURE_LCI 0x0A +#define RTT_LCI_ALTITUDE_MASK 0x3FFFFFFF +#define TARGET_OEM_CONFIGURE_LCR 0x09 +#define RTT_TIMEOUT_MS 180 +#define MAX_SUPPORTED_RATES 128 +#define WMI_HOST_MAX_BUFFER_SIZE 1712 +#define WMI_HAL_MAX_SANTENNA 4 + +#ifdef CONFIG_WIN +#if ATH_SUPPORT_FIPS +#define FIPS_ALIGN 4 +#define FIPS_ALIGNTO(__addr, __to) ((((unsigned long int)(__addr)) + (__to) - 1) & ~((__to) - 1)) +#define FIPS_IS_ALIGNED(__addr, __to) (!(((unsigned long int)(__addr)) & ((__to)-1))) +#endif +#endif + +#define WMI_HOST_F_MS(_v, _f) \ + (((_v) & (_f)) >> (_f##_S)) + +#define WMI_HOST_F_RMW(_var, _v, _f) \ + do { \ + (_var) &= ~(_f); \ + (_var) |= (((_v) << (_f##_S)) & (_f)); \ + } while (0) + +/* TXBF capabilities masks */ +#define WMI_HOST_TXBF_CONF_SU_TX_BFEE_S 0 +#define WMI_HOST_TXBF_CONF_SU_TX_BFEE_M 0x1 +#define WMI_HOST_TXBF_CONF_SU_TX_BFEE \ + (WMI_HOST_TXBF_CONF_SU_TX_BFEE_M << WMI_HOST_TXBF_CONF_SU_TX_BFEE_S) +#define WMI_HOST_TXBF_CONF_SU_TX_BFEE_GET(x) \ + WMI_HOST_F_MS(x, WMI_HOST_TXBF_CONF_SU_TX_BFEE) +#define WMI_HOST_TXBF_CONF_SU_TX_BFEE_SET(x, z) \ + WMI_HOST_F_RMW(x, z, WMI_HOST_TXBF_CONF_SU_TX_BFEE) + +#define WMI_HOST_TXBF_CONF_MU_TX_BFEE_S 1 +#define WMI_HOST_TXBF_CONF_MU_TX_BFEE_M 0x1 +#define WMI_HOST_TXBF_CONF_MU_TX_BFEE \ + (WMI_HOST_TXBF_CONF_MU_TX_BFEE_M << WMI_HOST_TXBF_CONF_MU_TX_BFEE_S) +#define WMI_HOST_TXBF_CONF_MU_TX_BFEE_GET(x) \ + WMI_HOST_F_MS(x, WMI_HOST_TXBF_CONF_MU_TX_BFEE) +#define WMI_HOST_TXBF_CONF_MU_TX_BFEE_SET(x, z) \ + WMI_HOST_F_RMW(x, z, WMI_HOST_TXBF_CONF_MU_TX_BFEE) + +#define WMI_HOST_TXBF_CONF_SU_TX_BFER_S 2 +#define WMI_HOST_TXBF_CONF_SU_TX_BFER_M 0x1 +#define WMI_HOST_TXBF_CONF_SU_TX_BFER \ + (WMI_HOST_TXBF_CONF_SU_TX_BFER_M << WMI_HOST_TXBF_CONF_SU_TX_BFER_S) +#define WMI_HOST_TXBF_CONF_SU_TX_BFER_GET(x) \ + WMI_HOST_F_MS(x, WMI_HOST_TXBF_CONF_SU_TX_BFER) +#define WMI_HOST_TXBF_CONF_SU_TX_BFER_SET(x, z) \ + WMI_HOST_F_RMW(x, z, WMI_HOST_TXBF_CONF_SU_TX_BFER) + +#define WMI_HOST_TXBF_CONF_MU_TX_BFER_S 3 +#define WMI_HOST_TXBF_CONF_MU_TX_BFER_M 0x1 +#define WMI_HOST_TXBF_CONF_MU_TX_BFER \ + (WMI_HOST_TXBF_CONF_MU_TX_BFER_M << WMI_HOST_TXBF_CONF_MU_TX_BFER_S) +#define WMI_HOST_TXBF_CONF_MU_TX_BFER_GET(x) \ + WMI_HOST_F_MS(x, WMI_HOST_TXBF_CONF_MU_TX_BFER) +#define WMI_HOST_TXBF_CONF_MU_TX_BFER_SET(x, z) \ + WMI_HOST_F_RMW(x, z, WMI_HOST_TXBF_CONF_MU_TX_BFER) + +#define WMI_HOST_TXBF_CONF_STS_CAP_S 4 +#define WMI_HOST_TXBF_CONF_STS_CAP_M 0x7 +#define WMI_HOST_TXBF_CONF_STS_CAP \ + (WMI_HOST_TXBF_CONF_STS_CAP_M << WMI_HOST_TXBF_CONF_STS_CAP_S) +#define WMI_HOST_TXBF_CONF_STS_CAP_GET(x) \ + WMI_HOST_F_MS(x, WMI_HOST_TXBF_CONF_STS_CAP); +#define WMI_HOST_TXBF_CONF_STS_CAP_SET(x, z) \ + WMI_HOST_F_RMW(x, z, WMI_HOST_TXBF_CONF_STS_CAP) + +#define WMI_HOST_TXBF_CONF_IMPLICIT_BF_S 7 +#define WMI_HOST_TXBF_CONF_IMPLICIT_BF_M 0x1 +#define WMI_HOST_TXBF_CONF_IMPLICIT_BF \ + (WMI_HOST_TXBF_CONF_IMPLICIT_BF_M << WMI_HOST_TXBF_CONF_IMPLICIT_BF_S) +#define WMI_HOST_TXBF_CONF_IMPLICIT_BF_GET(x) \ + WMI_HOST_F_MS(x, WMI_HOST_TXBF_CONF_IMPLICIT_BF) +#define WMI_HOST_TXBF_CONF_IMPLICIT_BF_SET(x, z) \ + WMI_HOST_F_RMW(x, z, WMI_HOST_TXBF_CONF_IMPLICIT_BF) + +#define WMI_HOST_TXBF_CONF_BF_SND_DIM_S 8 +#define WMI_HOST_TXBF_CONF_BF_SND_DIM_M 0x7 +#define WMI_HOST_TXBF_CONF_BF_SND_DIM \ + (WMI_HOST_TXBF_CONF_BF_SND_DIM_M << WMI_HOST_TXBF_CONF_BF_SND_DIM_S) +#define WMI_HOST_TXBF_CONF_BF_SND_DIM_GET(x) \ + WMI_HOST_F_MS(x, WMI_HOST_TXBF_CONF_BF_SND_DIM) +#define WMI_HOST_TXBF_CONF_BF_SND_DIM_SET(x, z) \ + WMI_HOST_F_RMW(x, z, WMI_HOST_TXBF_CONF_BF_SND_DIM) + +#define WMI_HOST_TPC_RATE_MAX 160 +#define WMI_HOST_TPC_TX_NUM_CHAIN 4 +#define WMI_HOST_RXG_CAL_CHAN_MAX 4 +#define WMI_HOST_MAX_NUM_CHAINS 4 +#define WMI_MAX_NUM_OF_RATE_THRESH 4 + +#define PROBE_REQ_BITMAP_LEN 8 + +#include "qdf_atomic.h" + +#ifdef BIG_ENDIAN_HOST + /* This API is used in copying in elements to WMI message, + since WMI message uses multilpes of 4 bytes, This API + converts length into multiples of 4 bytes, and performs copy + */ +#define WMI_HOST_IF_MSG_COPY_CHAR_ARRAY(destp, srcp, len) do { \ + int j; \ + u_int32_t *src, *dest; \ + src = (u_int32_t *)srcp; \ + dest = (u_int32_t *)destp; \ + for (j = 0; j < roundup(len, sizeof(u_int32_t))/4; j++) { \ + *(dest+j) = qdf_le32_to_cpu(*(src+j)); \ + } \ +} while (0) +#else + +#define WMI_HOST_IF_MSG_COPY_CHAR_ARRAY(destp, srcp, len) OS_MEMCPY(destp,\ + srcp, len) + +#endif + +/** macro to convert MAC address from WMI word format to char array */ +#define WMI_HOST_MAC_ADDR_TO_CHAR_ARRAY(pwmi_mac_addr, c_macaddr) do { \ + (c_macaddr)[0] = ((pwmi_mac_addr)->mac_addr31to0) & 0xff; \ + (c_macaddr)[1] = (((pwmi_mac_addr)->mac_addr31to0) >> 8) & 0xff; \ + (c_macaddr)[2] = (((pwmi_mac_addr)->mac_addr31to0) >> 16) & 0xff; \ + (c_macaddr)[3] = (((pwmi_mac_addr)->mac_addr31to0) >> 24) & 0xff; \ + (c_macaddr)[4] = ((pwmi_mac_addr)->mac_addr47to32) & 0xff; \ + (c_macaddr)[5] = (((pwmi_mac_addr)->mac_addr47to32) >> 8) & 0xff; \ + } while (0) + +#define TARGET_INIT_STATUS_SUCCESS 0x0 +#define TARGET_INIT_STATUS_GEN_FAILED 0x1 +#define TARGET_GET_INIT_STATUS_REASON(status) ((status) & 0xffff) +#define TARGET_GET_INIT_STATUS_MODULE_ID(status) (((status) >> 16) & 0xffff) + +#define MAX_ASSOC_IE_LENGTH 1024 +typedef uint32_t TARGET_INIT_STATUS; + +typedef enum { + WMI_HOST_MODE_11A = 0, /* 11a Mode */ + WMI_HOST_MODE_11G = 1, /* 11b/g Mode */ + WMI_HOST_MODE_11B = 2, /* 11b Mode */ + WMI_HOST_MODE_11GONLY = 3, /* 11g only Mode */ + WMI_HOST_MODE_11NA_HT20 = 4, /* 11a HT20 mode */ + WMI_HOST_MODE_11NG_HT20 = 5, /* 11g HT20 mode */ + WMI_HOST_MODE_11NA_HT40 = 6, /* 11a HT40 mode */ + WMI_HOST_MODE_11NG_HT40 = 7, /* 11g HT40 mode */ + WMI_HOST_MODE_11AC_VHT20 = 8, + WMI_HOST_MODE_11AC_VHT40 = 9, + WMI_HOST_MODE_11AC_VHT80 = 10, + WMI_HOST_MODE_11AC_VHT20_2G = 11, + WMI_HOST_MODE_11AC_VHT40_2G = 12, + WMI_HOST_MODE_11AC_VHT80_2G = 13, + WMI_HOST_MODE_11AC_VHT80_80 = 14, + WMI_HOST_MODE_11AC_VHT160 = 15, + WMI_HOST_MODE_UNKNOWN = 16, + WMI_HOST_MODE_MAX = 16 +} WMI_HOST_WLAN_PHY_MODE; + + +/** + * enum wmi_dwelltime_adaptive_mode: dwelltime_mode + * @WMI_DWELL_MODE_DEFAULT: Use firmware default mode + * @WMI_DWELL_MODE_CONSERVATIVE: Conservative adaptive mode + * @WMI_DWELL_MODE_MODERATE: Moderate adaptive mode + * @WMI_DWELL_MODE_AGGRESSIVE: Aggressive adaptive mode + * @WMI_DWELL_MODE_STATIC: static adaptive mode + */ +enum wmi_dwelltime_adaptive_mode { + WMI_DWELL_MODE_DEFAULT = 0, + WMI_DWELL_MODE_CONSERVATIVE = 1, + WMI_DWELL_MODE_MODERATE = 2, + WMI_DWELL_MODE_AGGRESSIVE = 3, + WMI_DWELL_MODE_STATIC = 4 +}; + +#define MAX_NUM_CHAN 128 + +/* WME stream classes */ +#define WMI_HOST_AC_BE 0 /* best effort */ +#define WMI_HOST_AC_BK 1 /* background */ +#define WMI_HOST_AC_VI 2 /* video */ +#define WMI_HOST_AC_VO 3 /* voice */ +#define WMI_TID_TO_AC(_tid) (\ + (((_tid) == 0) || ((_tid) == 3)) ? WMI_HOST_AC_BE : \ + (((_tid) == 1) || ((_tid) == 2)) ? WMI_HOST_AC_BK : \ + (((_tid) == 4) || ((_tid) == 5)) ? WMI_HOST_AC_VI : \ + WMI_HOST_AC_VO) + +/** + * struct vdev_create_params - vdev create cmd parameter + * @if_id: interface id + * @type: interface type + * @subtype: interface subtype + */ +struct vdev_create_params { + uint8_t if_id; + uint32_t type; + uint32_t subtype; + uint8_t nss_2g; + uint8_t nss_5g; +}; + +/** + * struct vdev_delete_params - vdev delete cmd parameter + * @if_id: interface id + */ +struct vdev_delete_params { + uint8_t if_id; +}; + +/** + * struct channel_param - Channel paramters with all + * info required by target. + * @chan_id: channel id + * @pwr: channel power + * @mhz: channel frequency + * @half_rate: is half rate + * @quarter_rate: is quarter rate + * @dfs_set: is dfs channel + * @dfs_set_cfreq2: is secondary freq dfs channel + * @is_chan_passive: is this passive channel + * @allow_ht: HT allowed in chan + * @allow_vht: VHT allowed on chan + * @phy_mode: phymode (vht80 or ht40 or ...) + * @cfreq1: centre frequency on primary + * @cfreq2: centre frequency on secondary + * @maxpower: max power for channel + * @minpower: min power for channel + * @maxreqpower: Max regulatory power + * @antennamac: Max antenna + * @reg_class_id: Regulatory class id. + */ + +struct channel_param { + uint8_t chan_id; + uint8_t pwr; + uint32_t mhz; + uint32_t half_rate:1, + quarter_rate:1, + dfs_set:1, + dfs_set_cfreq2:1, + is_chan_passive:1, + allow_ht:1, + allow_vht:1; + uint32_t phy_mode; + uint32_t cfreq1; + uint32_t cfreq2; + int8_t maxpower; + int8_t minpower; + int8_t maxregpower; + uint8_t antennamax; + uint8_t reg_class_id; +}; + +/** + * struct vdev_stop_params - vdev stop cmd parameter + * @vdev_id: vdev id + */ +struct vdev_stop_params { + uint8_t vdev_id; +}; + +/** + * struct vdev_up_params - vdev up cmd parameter + * @vdev_id: vdev id + * @assoc_id: association id + */ +struct vdev_up_params { + uint8_t vdev_id; + uint16_t assoc_id; +}; + +/** + * struct vdev_down_params - vdev down cmd parameter + * @vdev_id: vdev id + */ +struct vdev_down_params { + uint8_t vdev_id; +}; + +/** + * struct mac_ssid - mac ssid structure + * @length: + * @mac_ssid[WMI_MAC_MAX_SSID_LENGTH]: + */ +struct mac_ssid { + uint8_t length; + uint8_t mac_ssid[WMI_MAC_MAX_SSID_LENGTH]; +} qdf_packed; + +/** + * struct vdev_start_params - vdev start cmd parameter + * @vdev_id: vdev id + * @chan_freq: channel frequency + * @chan_mode: channel mode + * @band_center_freq1: center freq 1 + * @band_center_freq2: center freq 2 + * @flags: flags to set like pmf_enabled etc. + * @is_dfs: flag to check if dfs enabled + * @beacon_intval: beacon interval + * @dtim_period: dtim period + * @max_txpow: max tx power + * @is_restart: flag to check if it is vdev + * @ssid: ssid and ssid length info + * @preferred_tx_streams: preferred tx streams + * @preferred_rx_streams: preferred rx streams + * @intr_update: flag to check if need to update + * required wma interface params + * @intr_ssid: pointer to wma interface ssid + * @intr_flags: poiter to wma interface flags + * @requestor_id: to update requestor id + * @disable_hw_ack: to update disable hw ack flag + * @info: to update channel info + * @reg_info_1: to update min power, max power, + * reg power and reg class id + * @reg_info_2: to update antennamax + * @oper_mode: Operating mode + * @dfs_pri_multiplier: DFS primary multiplier + * allow pulse if they are within multiple of PRI for the radar type + * @dot11_mode: Phy mode (VHT20/VHT80...) + * @disable_hw_ack: Disable hw ack if chan is dfs channel for cac + * @channel_param: Channel params required by target. + */ +struct vdev_start_params { + uint8_t vdev_id; + uint32_t chan_freq; + uint32_t chan_mode; + uint32_t band_center_freq1; + uint32_t band_center_freq2; + uint32_t flags; + bool is_dfs; + uint32_t beacon_intval; + uint32_t dtim_period; + int32_t max_txpow; + bool is_restart; + bool is_half_rate; + bool is_quarter_rate; + uint32_t dis_hw_ack; + uint32_t flag_dfs; + uint8_t hidden_ssid; + uint8_t pmf_enabled; + struct mac_ssid ssid; + uint32_t num_noa_descriptors; + uint32_t preferred_rx_streams; + uint32_t preferred_tx_streams; +#ifdef WMI_NON_TLV_SUPPORT + uint8_t oper_mode; + int32_t dfs_pri_multiplier; + uint8_t dot11_mode; + uint8_t disable_hw_ack; + struct channel_param channel; +#endif +}; + +/** + * struct hidden_ssid_vdev_restart_params - + * vdev restart cmd parameter + * @session_id: session id + * @ssid_len: ssid length + * @ssid: ssid + * @flags: flags + * @requestor_id: requestor id + * @disable_hw_ack: flag to disable hw ack feature + * @mhz: channel frequency + * @band_center_freq1: center freq 1 + * @band_center_freq2: center freq 2 + * @info: channel info + * @reg_info_1: contains min power, max power, + * reg power and reg class id + * @reg_info_2: contains antennamax + * @hidden_ssid_restart_in_progress: + * flag to check if restart is in progress + */ +struct hidden_ssid_vdev_restart_params { + uint8_t session_id; + uint32_t ssid_len; + uint32_t ssid[8]; + uint32_t flags; + uint32_t requestor_id; + uint32_t disable_hw_ack; + uint32_t mhz; + uint32_t band_center_freq1; + uint32_t band_center_freq2; + uint32_t info; + uint32_t reg_info_1; + uint32_t reg_info_2; + qdf_atomic_t hidden_ssid_restart_in_progress; +}; + +/** + * struct vdev_set_params - vdev set cmd parameter + * @if_id: vdev id + * @param_id: parameter id + * @param_value: parameter value + */ +struct vdev_set_params { + uint32_t if_id; + uint32_t param_id; + uint32_t param_value; +}; + +/** + * struct vdev_install_key_params - vdev key set cmd parameter + * @wk_keylen: key length + * @wk_flags: key flags + * @ic_cipher: cipher + * @if_id: vdev id + * @is_group_key: Group key + * @wk_keyix: key index + * @def_keyid: default key index + * @wk_keytsc: Key TSC + * @wk_keyrsc: key RSC + * @key_data: pounter to key data + * @force_none: force + * @is_host_based_crypt: Host based encrypt + * @is_xmit_or_recv_key: xmit or recieve key + * @wk_recviv: WAPI recv IV + * @wk_txiv: WAPI TX IV + */ +struct vdev_install_key_params { + uint8_t wk_keylen; + uint16_t wk_flags; + uint8_t ic_cipher; + uint8_t if_id; + bool is_group_key; + uint16_t wk_keyix; + uint8_t def_keyid; + uint64_t wk_keytsc; + uint64_t *wk_keyrsc; + uint8_t *key_data; + uint8_t force_none; + bool is_host_based_crypt; + bool is_xmit_or_recv_key; +#if ATH_SUPPORT_WAPI + uint8_t *wk_recviv; + uint32_t *wk_txiv; +#endif +}; + +/** + * struct peer_delete_params - peer delete cmd parameter + * @vdev_id: vdev id + */ +struct peer_delete_params { + uint8_t vdev_id; +}; + +/** + * struct peer_flush_params - peer flush cmd parameter + * @peer_tid_bitmap: peer tid bitmap + * @vdev_id: vdev id + */ +struct peer_flush_params { + uint32_t peer_tid_bitmap; + uint8_t vdev_id; +}; + +/** + * struct peer_set_params - peer set cmd parameter + * @param_id: parameter id + * @param_value: parameter value + * @vdev_id: vdev id + */ +struct peer_set_params { + uint32_t param_id; + uint32_t param_value; + uint32_t vdev_id; +}; + +/** + * struct peer_create_params - peer create cmd parameter + * @peer_addr: peer mac addr + * @peer_type: peer type + * @vdev_id: vdev id + */ +struct peer_create_params { + const uint8_t *peer_addr; + uint32_t peer_type; + uint32_t vdev_id; +}; + +/** + * struct peer_remove_params - peer remove cmd parameter + * @bssid: bss id + * @vdev_id: vdev id + * @roam_synch_in_progress: flag to indicate if roaming is in progress + */ +struct peer_remove_params { + uint8_t *bssid; + uint8_t vdev_id; + bool roam_synch_in_progress; +}; + +/** + * Stats ID enums defined in host + */ +typedef enum { + WMI_HOST_REQUEST_PEER_STAT = 0x01, + WMI_HOST_REQUEST_AP_STAT = 0x02, + WMI_HOST_REQUEST_PDEV_STAT = 0x04, + WMI_HOST_REQUEST_VDEV_STAT = 0x08, + WMI_HOST_REQUEST_BCNFLT_STAT = 0x10, + WMI_HOST_REQUEST_VDEV_RATE_STAT = 0x20, + WMI_HOST_REQUEST_INST_STAT = 0x40, + WMI_HOST_REQUEST_PEER_EXTD_STAT = 0x80, + WMI_HOST_REQUEST_VDEV_EXTD_STAT = 0x100, +} wmi_host_stats_id; + +typedef struct { + uint16_t cfg_retry_count; + uint16_t retry_count; +} wmi_host_inst_rssi_args; + +/** + * struct stats_request_params - stats_request cmd parameter + * @stats_id: statistics id + * @vdev_id: vdev id + * @wmi_host_inst_rssi_args: Instantaneous rssi stats args + */ +struct stats_request_params { + uint32_t stats_id; + uint32_t vdev_id; +#ifdef WMI_NON_TLV_SUPPORT + wmi_host_inst_rssi_args rssi_args; +#endif +}; + +/** + * struct bss_chan_info_request_params - BSS chan info params + * @param: parameter value + */ +struct bss_chan_info_request_params { + uint32_t param; +}; + +/** + * struct green_ap_ps_params - green ap ps cmd parameter + * @value: parameter value + */ +struct green_ap_ps_params { + uint32_t value; +}; + +/** + * struct wow_cmd_params - wow cmd parameter + * @enable: wow enable or disable flag + * @can_suspend_link: flag to indicate if link can be suspended + * @pause_iface_config: interface config + */ +struct wow_cmd_params { + bool enable; + bool can_suspend_link; + uint8_t pause_iface_config; + uint32_t flags; +}; + +/** + * struct wow_add_wakeup_params - wow wakeup parameter + * @type: param type + */ +struct wow_add_wakeup_params { + uint32_t type; +}; + +/** + * struct wow_add_wakeup_pattern_params - Add WoW pattern params + * @pattern_bytes: pointer to pattern bytes + * @mask_bytes: pointer to mask bytes + * @pattern_len: pattern length + * @pattern_id: pattern id + */ +struct wow_add_wakeup_pattern_params { + uint8_t *pattern_bytes; + uint8_t *mask_bytes; + uint32_t pattern_len; + uint32_t pattern_id; +}; + +/** + * struct wow_remove_wakeup_pattern params - WoW remove pattern param + * @pattern_bytes: pointer to pattern bytes + * @mask_bytes: Mask bytes + * @pattern_id: pattern identifier + */ +struct wow_remove_wakeup_pattern_params { + uint32_t *pattern_bytes; + uint32_t *mask_bytes; + uint32_t pattern_id; +}; + + +/** + * struct packet_enable_params - packet enable cmd parameter + * @vdev_id: vdev id + * @enable: flag to indicate if parameter can be enabled or disabled + */ +struct packet_enable_params { + uint8_t vdev_id; + bool enable; +}; + +/** + * struct suspend_params - suspend cmd parameter + * @disable_target_intr: disable target interrupt + */ +struct suspend_params { + uint8_t disable_target_intr; +}; + +/** + * struct pdev_params - pdev set cmd parameter + * @param_id: parameter id + * @param_value: parameter value + */ +struct pdev_params { + uint32_t param_id; + uint32_t param_value; +}; + +/** + * struct beacon_tmpl_params - beacon template cmd parameter + * @vdev_id: vdev id + * @tim_ie_offset: tim ie offset + * @tmpl_len: beacon template length + * @tmpl_len_aligned: beacon template alignment + * @frm: beacon template parameter + */ +struct beacon_tmpl_params { + uint8_t vdev_id; + uint32_t tim_ie_offset; + uint32_t tmpl_len; + uint32_t tmpl_len_aligned; + uint8_t *frm; +}; + +#ifdef CONFIG_MCL +/** + * struct beacon_params - beacon cmd parameter + * @vdev_id: vdev id + * @tim_ie_offset: tim ie offset + * @tmpl_len: beacon template length + * @tmpl_len_aligned: beacon template alignment + * @frm: beacon template parameter + */ +struct beacon_params { + uint8_t vdev_id; + uint32_t tim_ie_offset; + uint32_t tmpl_len; + uint32_t tmpl_len_aligned; + uint8_t *frm; +}; +#else +/** + * struct beacon_params - beacon cmd parameter + * @vdev_id: vdev id + * @beaconInterval: Beacon interval + * @wbuf: beacon buffer + * @frame_ctrl: frame control field + * @bcn_txant: beacon antenna + * @is_dtim_count_zero: is it dtim beacon + * @is_bitctl_reqd: is Bit control required + * @is_high_latency: Is this high latency target + */ +struct beacon_params { + uint8_t vdev_id; + uint16_t beaconInterval; + qdf_nbuf_t wbuf; + uint16_t frame_ctrl; + uint32_t bcn_txant; + bool is_dtim_count_zero; + bool is_bitctl_reqd; + bool is_high_latency; +}; +#endif + +/** + * struct bcn_prb_template_params - beacon probe template parameter + * @vdev_id: vdev id + * @buf_len: Template length + * @caps: capabilities field + * @erp: ERP field + */ +struct bcn_prb_template_params { + uint8_t vdev_id; + int buf_len; + uint16_t caps; + uint8_t erp; +}; + +#define WMI_MAX_SUPPORTED_RATES 128 +/** + * struct target_rate_set - Rate set bitmap + * @num_rate: number of rates in rates bitmap + * @rates: rates (each 8bit value) packed into a 32 bit word. + * the rates are filled from least significant byte to most + * significant byte. + */ +typedef struct { + uint32_t num_rates; + uint32_t rates[(WMI_MAX_SUPPORTED_RATES / 4) + 1]; +} target_rate_set; + +/** + * struct wmi_host_mac_addr - host mac addr 2 word representation of MAC addr + * @mac_addr31to0: upper 4 bytes of MAC address + * @mac_addr47to32: lower 2 bytes of MAC address + */ +typedef struct { + uint32_t mac_addr31to0; + uint32_t mac_addr47to32; +} wmi_host_mac_addr; + +/** + * struct peer_assoc_params - peer assoc cmd parameter + * @peer_macaddr: peer mac address + * @vdev_id: vdev id + * @peer_new_assoc: peer association type + * @peer_associd: peer association id + * @peer_flags: peer flags + * @peer_caps: peer capabalities + * @peer_listen_intval: peer listen interval + * @peer_ht_caps: HT capabalities + * @peer_max_mpdu: 0 : 8k , 1 : 16k, 2 : 32k, 3 : 64k + * @peer_mpdu_density: 3 : 0~7 : 2^(11nAMPDUdensity -4) + * @peer_rate_caps: peer rate capabalities + * @peer_nss: peer nss + * @peer_phymode: peer phymode + * @peer_ht_info: peer HT info + * @peer_legacy_rates: peer legacy rates + * @peer_ht_rates: peer ht rates + * @rx_max_rate: max rx rates + * @rx_mcs_set: rx mcs + * @tx_max_rate: max tx rates + * @tx_mcs_set: tx mcs + * @vht_capable: VHT capabalities + * @tx_max_mcs_nss: max tx MCS and NSS + * @peer_bw_rxnss_override: Peer BW RX NSS overriden or not. + * @is_pmf_enabled: PMF enabled + * @is_wme_set: WME enabled + * @qos_flag: QoS Flags + * @apsd_flag: APSD flags + * @ht_flag: HT flags + * @bw_40: 40 capabale + * @bw_80: 80 capabale + * @bw_160: 160 capabale + * @stbc_flag: STBC flag + * @ldpc_flag: LDPC flag + * @static_mimops_flag: statis MIMO PS flags + * @dynamic_mimops_flag: Dynamic MIMO PS flags + * @spatial_mux_flag: spatial MUX flags + * @vht_flag: VHT flags + * @vht_ng_flag: VHT on 11N/G flags + * @need_ptk_4_way: Needs 4 way handshake + * @need_gtk_2_way: Needs 2 way GTK + * @auth_flag: Is peer authenticated + * @safe_mode_enabled: Safe enabled for this peer + * @amsdu_disable: AMSDU disble + * @peer_mac: Peer mac address + */ +struct peer_assoc_params { + wmi_host_mac_addr peer_macaddr; + uint32_t vdev_id; + uint32_t peer_new_assoc; + uint32_t peer_associd; + uint32_t peer_flags; + uint32_t peer_caps; + uint32_t peer_listen_intval; + uint32_t peer_ht_caps; + uint32_t peer_max_mpdu; + uint32_t peer_mpdu_density; + uint32_t peer_rate_caps; + uint32_t peer_nss; + uint32_t peer_vht_caps; + uint32_t peer_phymode; + uint32_t peer_ht_info[2]; + target_rate_set peer_legacy_rates; + target_rate_set peer_ht_rates; + uint32_t rx_max_rate; + uint32_t rx_mcs_set; + uint32_t tx_max_rate; + uint32_t tx_mcs_set; + uint8_t vht_capable; +#ifdef WMI_NON_TLV_SUPPORT + uint32_t tx_max_mcs_nss; + uint32_t peer_bw_rxnss_override; + bool is_pmf_enabled; + bool is_wme_set; + bool qos_flag; + bool apsd_flag; + bool ht_flag; + bool bw_40; + bool bw_80; + bool bw_160; + bool stbc_flag; + bool ldpc_flag; + bool static_mimops_flag; + bool dynamic_mimops_flag; + bool spatial_mux_flag; + bool vht_flag; + bool vht_ng_flag; + bool need_ptk_4_way; + bool need_gtk_2_way; + bool auth_flag; + bool safe_mode_enabled; + bool amsdu_disable; + /* Use common structure */ + uint8_t peer_mac[IEEE80211_ADDR_LEN]; +#endif +}; + +/** + * struct sta_ps_params - sta ps cmd parameter + * @vdev_id: vdev id + * @param: sta ps paramter + * @value: sta ps parameter value + */ +struct sta_ps_params { + uint32_t vdev_id; + uint32_t param; + uint32_t value; +}; + +/** + * struct ap_ps_params - ap ps cmd parameter + * @vdev_id: vdev id + * @param: ap ps paramter + * @value: ap ps paramter value + */ +struct ap_ps_params { + uint32_t vdev_id; + uint32_t param; + uint32_t value; +}; + +/** + * struct vendor_oui - probe request ie vendor oui information + * @oui_type: type of the vendor oui (3 valid octets) + * @oui_subtype: subtype of the vendor oui (1 valid octet) + */ +struct vendor_oui { + uint32_t oui_type; + uint32_t oui_subtype; +}; + +#define WMI_HOST_SCAN_CHAN_FREQ_SHIFT 0 +#define WMI_HOST_SCAN_CHAN_FREQ_MASK 0xffff +#define WMI_HOST_SCAN_CHAN_MODE_SHIFT 16 +#define WMI_HOST_SCAN_CHAN_MODE_MASK 0xff + +/** + * struct scan_start_params - start scan cmd parameter + * @scan_id: scan id + * @scan_req_id: requeted scan id + * @vdev_id: vdev id + * @scan_priority: scan priority + * @notify_scan_events: flag to indicate if scan to be notified + * @dwell_time_active: active dwell time + * @dwell_time_passive: passive dwell time + * @min_rest_time: min rest time + * @max_rest_time: max rest time + * @repeat_probe_time: repeat probe time + * @probe_spacing_time: probe spacing time + * @idle_time: idle time + * @max_scan_time: max scan time + * @probe_delay: probe delay + * @scan_ctrl_flags: scan control flag + * @burst_duration: burst duration + * @num_chan: no of channel + * @num_bssid: no of bssid + * @num_ssids: no of ssid + * @ie_len: ie length + * @n_probes: no of probe + * @chan_list: channel list + * @ie_len_with_pad: ie length with padding + * @num_ssid: no of ssid + * @sid: pointer to mac_ssid structure + * @uie_fieldOffset: ie field offset + * @mac_add_bytes: mac address bytes + * @is_strict_pscan_en: Is this a strict passive scan + * @is_promiscous_mode: Is promiscous mode + * @is_phy_error: is Phy error + * @add_cck_rates: Add cck rates + * @chan_stat_enable: channel stats enabled + * @offchan_tx_mgmt: Offchan tx scan + * @offchan_tx_data: offchan tx data + * @add_bcast_probe_reqd: Add bcast probe request + * @bssid_list: Lisst of bssid to scan + * @ie_data: IE data buffer pointer + * @passive_flag: Is this passive scan + * @enable_scan_randomization: enable scan randomization feature + * @mac_addr: MAC address used with randomization + * @mac_addr_mask: MAC address mask used with randomization, bits that + * are 0 in the mask should be randomized, bits that are 1 should + * be taken from the @mac_addr + * @ie_whitelist: set to true for enabling ie whitelisting + * @probe_req_ie_bitmap: contains IEs to be included in probe req + * @num_vendor_oui: number of vendor OUIs + * @oui_field_len: size of total number of OUIs + * @voui: pointer to OUI buffer + */ +struct scan_start_params { + uint32_t scan_id; + uint32_t scan_req_id; + uint32_t vdev_id; + uint32_t scan_priority; + uint32_t notify_scan_events; + uint32_t dwell_time_active; + uint32_t dwell_time_passive; + uint32_t min_rest_time; + uint32_t max_rest_time; + uint32_t repeat_probe_time; + uint32_t probe_spacing_time; + uint32_t idle_time; + uint32_t max_scan_time; + uint32_t probe_delay; + uint32_t scan_ctrl_flags; + uint32_t burst_duration; + uint32_t num_chan; + uint32_t num_bssid; + uint32_t num_ssids; + uint32_t ie_len; + uint32_t n_probes; + uint32_t *chan_list; + uint32_t ie_len_with_pad; + struct mac_ssid ssid[WMI_SCAN_MAX_NUM_SSID]; + uint8_t *ie_base; + uint16_t uie_fieldOffset; + uint8_t mac_add_bytes[IEEE80211_ADDR_LEN]; +#ifdef WMI_NON_TLV_SUPPORT + bool is_strict_pscan_en; + bool is_promiscous_mode; + bool is_phy_error; + bool add_cck_rates; + bool chan_stat_enable; + bool offchan_tx_mgmt; + bool offchan_tx_data; + bool add_bcast_probe_reqd; + uint8_t bssid_list[WMI_SCAN_MAX_NUM_BSSID][IEEE80211_ADDR_LEN]; + uint8_t *ie_data; + int passive_flag; +#endif + /* mac address randomization attributes */ + bool enable_scan_randomization; + uint8_t mac_addr[QDF_MAC_ADDR_SIZE]; + uint8_t mac_addr_mask[QDF_MAC_ADDR_SIZE]; + + /* probe req ie whitelisting attrs */ + bool ie_whitelist; + uint32_t probe_req_ie_bitmap[PROBE_REQ_BITMAP_LEN]; + uint32_t num_vendor_oui; + uint32_t oui_field_len; + uint8_t *voui; +}; + +/** + * struct scan_stop_params - stop scan cmd parameter + * @requestor: scan requestor + * @scan_id: scan id + * @req_type: scan request type + * @vdev_id: vdev id + * @all_scans: Stop all scans + * @vap_scans: stop vap scans + * @specific_scan: specific scan + * @flags: scan flags + * @ss_scan_id: ss scan id + */ +struct scan_stop_params { + uint32_t requestor; + uint32_t scan_id; + uint32_t req_type; + uint32_t vdev_id; +#ifdef WMI_NON_TLV_SUPPORT + bool all_scans; + bool vap_scans; + bool specific_scan; + uint32_t flags; + uint32_t ss_scan_id; +#endif +}; + +/** + * struct scan_chan_list_params - scan channel list cmd parameter + * @num_scan_chans: no of scan channels + * @chan_info: pointer to wmi channel info + */ +#ifdef CONFIG_MCL +/* TODO: This needs clean-up based on how its processed. */ +typedef struct { + /* TLV tag and len; tag equals WMITLV_TAG_STRUC_wmi_channel */ + uint32_t tlv_header; + /** primary 20 MHz channel frequency in mhz */ + uint32_t mhz; + /** Center frequency 1 in MHz*/ + uint32_t band_center_freq1; + /** Center frequency 2 in MHz - valid only for 11acvht 80plus80 mode*/ + uint32_t band_center_freq2; + /** channel info described below */ + uint32_t info; + /** contains min power, max power, reg power and reg class id. */ + uint32_t reg_info_1; + /** contains antennamax */ + uint32_t reg_info_2; +} wmi_channel_param; + +struct scan_chan_list_params { + uint8_t num_scan_chans; + wmi_channel_param *chan_info; +}; +#else +/** + * struct scan_chan_list_params - scan channel list cmd parameter + * @num_chan: no of scan channels + * @nallchans: nall chans + * @ch_param: pointer to channel_paramw + */ +struct scan_chan_list_params { + uint8_t num_chan; + uint16_t nallchans; + struct channel_param ch_param[1]; +}; +#endif + +/** + * struct fw_hang_params - fw hang command parameters + * @type: 0:unused 1: ASSERT, 2:not respond detect command, 3:simulate ep-full + * @delay_time_ms: 0xffffffff means the simulate will delay for random time (0 ~0xffffffff ms) + */ +struct fw_hang_params { + uint32_t type; + uint32_t delay_time_ms; +}; + +/** + * struct pdev_utf_params - pdev utf command parameters + * @utf_payload: + * @len: + * @is_ar900b: is it 900b target + */ +struct pdev_utf_params { + uint8_t *utf_payload; + uint32_t len; +#ifdef WMI_NON_TLV_SUPPORT + bool is_ar900b; +#endif +}; + +/*Adding this due to dependency on wmi_unified.h + */ +typedef struct { + uint32_t len; + uint32_t msgref; + uint32_t segmentInfo; +} QVIT_SEG_HDR_INFO_STRUCT; + +struct pdev_qvit_params { + uint8_t *utf_payload; + uint32_t len; +}; +/** + * struct crash_inject - crash inject command parameters + * @type: crash inject type + * @delay_time_ms: time in milliseconds for FW to delay the crash + */ +struct crash_inject { + uint32_t type; + uint32_t delay_time_ms; +}; + +/** + * struct dbglog_params - fw deboglog command parameters + * @param: command parameter + * @val: parameter value + * @module_id_bitmap: fixed length module id bitmap + * @bitmap_len: module id bitmap length + * @cfgvalid: cfgvalid + */ +struct dbglog_params { + uint32_t param; + uint32_t val; + uint32_t *module_id_bitmap; + uint32_t bitmap_len; +#ifdef WMI_NON_TLV_SUPPORT + uint32_t cfgvalid[2]; +#endif +}; + +/** + * struct seg_hdr_info - header info + * @len: length + * @msgref: message refrence + * @segmentInfo: segment info + * @pad: padding + */ +struct seg_hdr_info { + uint32_t len; + uint32_t msgref; + uint32_t segmentInfo; + uint32_t pad; +}; + +/** + * struct wmi_mgmt_params - wmi mgmt cmd paramters + * @tx_frame: management tx frame + * @frm_len: frame length + * @vdev_id: vdev id + * @tx_complete_cb: tx download callback handler + * @tx_ota_post_proc_cb: OTA complition handler + * @chanfreq: channel frequency + * @pdata: frame data + * @wmi_desc: command descriptor + * @desc_id: descriptor id relyaed back by target + * @macaddr - macaddr of peer + */ +struct wmi_mgmt_params { + void *tx_frame; + uint16_t frm_len; + uint8_t vdev_id; + uint16_t chanfreq; + void *pdata; + uint16_t desc_id; + uint8_t *macaddr; + void *qdf_ctx; +}; + +/** + * struct p2p_ps_params - P2P powersave related params + * @opp_ps: opportunistic power save + * @ctwindow: CT window + * @count: count + * @duration: duration + * @interval: interval + * @single_noa_duration: single shot noa duration + * @ps_selection: power save selection + * @session_id: session id + */ +struct p2p_ps_params { + uint8_t opp_ps; + uint32_t ctwindow; + uint8_t count; + uint32_t duration; + uint32_t interval; + uint32_t single_noa_duration; + uint8_t ps_selection; + uint8_t session_id; +}; + + +/** + * struct ta_uapsd_trig_params - uapsd trigger parameter + * @vdevid: vdev id + * @peer_addr: peer address + * @auto_triggerparam: trigger parameters + * @num_ac: no of access category + */ +struct sta_uapsd_trig_params { + uint32_t vdevid; + uint8_t peer_addr[IEEE80211_ADDR_LEN]; + uint8_t *auto_triggerparam; + uint32_t num_ac; +}; + +/** + * struct ocb_utc_param + * @vdev_id: session id + * @utc_time: number of nanoseconds from Jan 1st 1958 + * @time_error: the error in the UTC time. All 1's for unknown + */ +struct ocb_utc_param { + uint32_t vdev_id; + uint8_t utc_time[WMI_SIZE_UTC_TIME]; + uint8_t time_error[WMI_SIZE_UTC_TIME_ERROR]; +}; + +/** + * struct ocb_timing_advert_param + * @vdev_id: session id + * @chan_freq: frequency on which to advertise + * @repeat_rate: the number of times it will send TA in 5 seconds + * @timestamp_offset: offset of the timestamp field in the TA frame + * @time_value_offset: offset of the time_value field in the TA frame + * @template_length: size in bytes of the TA frame + * @template_value: the TA frame + */ +struct ocb_timing_advert_param { + uint32_t vdev_id; + uint32_t chan_freq; + uint32_t repeat_rate; + uint32_t timestamp_offset; + uint32_t time_value_offset; + uint32_t template_length; + uint8_t *template_value; +}; + +/** + * struct dcc_get_stats_param + * @vdev_id: session id + * @channel_count: number of dcc channels + * @request_array_len: size in bytes of the request array + * @request_array: the request array + */ +struct dcc_get_stats_param { + uint32_t vdev_id; + uint32_t channel_count; + uint32_t request_array_len; + void *request_array; +}; + +/** + * struct dcc_update_ndl_param + * @vdev_id: session id + * @channel_count: number of channels to be updated + * @dcc_ndl_chan_list_len: size in bytes of the ndl_chan array + * @dcc_ndl_chan_list: the ndl_chan array + * @dcc_ndl_active_state_list_len: size in bytes of the active_state array + * @dcc_ndl_active_state_list: the active state array + */ +struct dcc_update_ndl_param { + uint32_t vdev_id; + uint32_t channel_count; + uint32_t dcc_ndl_chan_list_len; + void *dcc_ndl_chan_list; + uint32_t dcc_ndl_active_state_list_len; + void *dcc_ndl_active_state_list; +}; + +/** + * struct ocb_config_sched + * @chan_freq: frequency of the channel + * @total_duration: duration of the schedule + * @guard_interval: guard interval on the start of the schedule + */ +struct ocb_config_sched { + uint32_t chan_freq; + uint32_t total_duration; + uint32_t guard_interval; +}; + +/** + * OCB structures + */ + +#define WMI_NUM_AC (4) +#define WMI_OCB_CHANNEL_MAX (5) +#define WMI_MAX_NUM_AC 4 +struct wmi_ocb_qos_params { + uint8_t aifsn; + uint8_t cwmin; + uint8_t cwmax; +}; +/** + * struct ocb_config_channel + * @chan_freq: frequency of the channel + * @bandwidth: bandwidth of the channel, either 10 or 20 MHz + * @mac_address: MAC address assigned to this channel + * @qos_params: QoS parameters + * @max_pwr: maximum transmit power of the channel (dBm) + * @min_pwr: minimum transmit power of the channel (dBm) + * @reg_pwr: maximum transmit power specified by the regulatory domain (dBm) + * @antenna_max: maximum antenna gain specified by the regulatory domain (dB) + */ +struct ocb_config_channel { + uint32_t chan_freq; + uint32_t bandwidth; + struct qdf_mac_addr mac_address; + struct wmi_ocb_qos_params qos_params[WMI_MAX_NUM_AC]; + uint32_t max_pwr; + uint32_t min_pwr; + uint8_t reg_pwr; + uint8_t antenna_max; + uint16_t flags; +}; + +/** + * struct ocb_config_param + * @session_id: session id + * @channel_count: number of channels + * @schedule_size: size of the channel schedule + * @flags: reserved + * @channels: array of OCB channels + * @schedule: array of OCB schedule elements + * @dcc_ndl_chan_list_len: size of the ndl_chan array + * @dcc_ndl_chan_list: array of dcc channel info + * @dcc_ndl_active_state_list_len: size of the active state array + * @dcc_ndl_active_state_list: array of active states + * @adapter: the OCB adapter + * @dcc_stats_callback: callback for the response event + */ +struct ocb_config_param { + uint8_t session_id; + uint32_t channel_count; + uint32_t schedule_size; + uint32_t flags; + struct ocb_config_channel *channels; + struct ocb_config_sched *schedule; + uint32_t dcc_ndl_chan_list_len; + void *dcc_ndl_chan_list; + uint32_t dcc_ndl_active_state_list_len; + void *dcc_ndl_active_state_list; +}; + +enum wmi_peer_rate_report_cond_phy_type { + WMI_PEER_RATE_REPORT_COND_11B = 0, + WMI_PEER_RATE_REPORT_COND_11A_G, + WMI_PEER_RATE_REPORT_COND_11N, + WMI_PEER_RATE_REPORT_COND_11AC, + WMI_PEER_RATE_REPORT_COND_MAX_NUM +}; + +/** + * struct report_rate_delta - peer specific parameters + * @percent: percentage + * @delta_min: rate min delta + */ +struct report_rate_delta { + uint32_t percent; /* in unit of 12.5% */ + uint32_t delta_min; /* in unit of Mbps */ +}; + +/** + * struct report_rate_per_phy - per phy report parameters + * @cond_flags: condition flag val + * @delta: rate delta + * @report_rate_threshold: rate threshold + */ +struct report_rate_per_phy { + /* + * PEER_RATE_REPORT_COND_FLAG_DELTA, + * PEER_RATE_REPORT_COND_FLAG_THRESHOLD + * Any of these two conditions or both of + * them can be set. + */ + uint32_t cond_flags; + struct report_rate_delta delta; + /* + * In unit of Mbps. There are at most 4 thresholds + * If the threshold count is less than 4, set zero to + * the one following the last threshold + */ + uint32_t report_rate_threshold[WMI_MAX_NUM_OF_RATE_THRESH]; +}; + +/** + * struct peer_rate_report_params - peer rate report parameters + * @rate_report_enable: enable rate report param + * @backoff_time: backoff time + * @timer_period: timer + * @report_per_phy: report per phy type + */ +struct wmi_peer_rate_report_params { + uint32_t rate_report_enable; + uint32_t backoff_time; /* in unit of msecond */ + uint32_t timer_period; /* in unit of msecond */ + /* + *In the following field, the array index means the phy type, + * please see enum wmi_peer_rate_report_cond_phy_type for detail + */ + struct report_rate_per_phy report_per_phy[ + WMI_PEER_RATE_REPORT_COND_MAX_NUM]; + +}; + +/** + * struct t_thermal_cmd_params - thermal command parameters + * @min_temp: minimum temprature + * @max_temp: maximum temprature + * @thermal_enable: thermal enable + */ +struct thermal_cmd_params { + uint16_t min_temp; + uint16_t max_temp; + uint8_t thermal_enable; +}; + +#define WMI_LRO_IPV4_SEED_ARR_SZ 5 +#define WMI_LRO_IPV6_SEED_ARR_SZ 11 + +/** + * struct wmi_lro_config_cmd_t - set LRO init parameters + * @lro_enable: indicates whether lro is enabled + * @tcp_flag: If the TCP flags from the packet do not match + * the values in this field after masking with TCP flags mask + * below, packet is not LRO eligible + * @tcp_flag_mask: field for comparing the TCP values provided + * above with the TCP flags field in the received packet + * @toeplitz_hash_ipv4: contains seed needed to compute the flow id + * 5-tuple toeplitz hash for ipv4 packets + * @toeplitz_hash_ipv6: contains seed needed to compute the flow id + * 5-tuple toeplitz hash for ipv6 packets + */ +struct wmi_lro_config_cmd_t { + uint32_t lro_enable; + uint32_t tcp_flag:9, + tcp_flag_mask:9; + uint32_t toeplitz_hash_ipv4[WMI_LRO_IPV4_SEED_ARR_SZ]; + uint32_t toeplitz_hash_ipv6[WMI_LRO_IPV6_SEED_ARR_SZ]; +}; + +/** + * struct gtx_config_t - GTX config + * @gtx_rt_mask: for HT and VHT rate masks + * @gtx_usrcfg: host request for GTX mask + * @gtx_threshold: PER Threshold (default: 10%) + * @gtx_margin: PER margin (default: 2%) + * @gtx_tcpstep: TCP step (default: 1) + * @gtx_tpcMin: TCP min (default: 5) + * @gtx_bwmask: BW mask (20/40/80/160 Mhz) + */ +struct wmi_gtx_config { + uint32_t gtx_rt_mask[2]; + uint32_t gtx_usrcfg; + uint32_t gtx_threshold; + uint32_t gtx_margin; + uint32_t gtx_tpcstep; + uint32_t gtx_tpcmin; + uint32_t gtx_bwmask; +}; + +/** + * struct wmi_probe_resp_params - send probe response parameters + * @bssId: BSSID + * @pProbeRespTemplate: probe response template + * @probeRespTemplateLen: probe response template length + * @ucProxyProbeReqValidIEBmap: valid IE bitmap + */ +struct wmi_probe_resp_params { + uint8_t bssId[IEEE80211_ADDR_LEN]; + uint8_t *pProbeRespTemplate; + uint32_t probeRespTemplateLen; + uint32_t ucProxyProbeReqValidIEBmap[8]; +}; + +/* struct set_key_params: structure containing + * installation key parameters + * @vdev_id: vdev id + * @key_len: key length + * @key_idx: key index + * @peer_mac: peer mac address + * @key_flags: key flags, 0:pairwise key, 1:group key, 2:static key + * @key_cipher: key cipher based on security mode + * @key_txmic_len: tx mic length + * @key_rxmic_len: rx mic length + * @rx_iv: receive IV, applicable only in case of WAPI + * @tx_iv: transmit IV, applicable only in case of WAPI + * @key_data: key data + */ +struct set_key_params { + uint8_t vdev_id; + uint16_t key_len; + uint32_t key_idx; + uint8_t peer_mac[IEEE80211_ADDR_LEN]; + uint32_t key_flags; + uint32_t key_cipher; + uint32_t key_txmic_len; + uint32_t key_rxmic_len; +#ifdef FEATURE_WLAN_WAPI + uint8_t rx_iv[16]; + uint8_t tx_iv[16]; +#endif + uint8_t key_data[WMI_MAC_MAX_KEY_LENGTH]; +}; + +/** + * struct sta_params - sta keep alive parameters + * @vdev_id: vdev id + * @method: keep alive method + * @timeperiod: time to keep alive + * @hostv4addr: host ipv4 address + * @destv4addr: destination ipv4 address + * @destmac: destination mac address + */ +struct sta_params { + uint8_t vdev_id; + uint32_t method; + uint32_t timeperiod; + uint8_t *hostv4addr; + uint8_t *destv4addr; + uint8_t *destmac; +}; + +/** + * struct gateway_update_req_param - gateway parameter update request + * @request_id: request id + * @session_id: session id + * @max_retries: Max ARP/NS retry attempts + * @timeout: Retry interval + * @ipv4_addr_type: on ipv4 network + * @ipv6_addr_type: on ipv6 network + * @gw_mac_addr: gateway mac addr + * @ipv4_addr: ipv4 addr + * @ipv6_addr: ipv6 addr + */ +struct gateway_update_req_param { + uint32_t request_id; + uint32_t session_id; + uint32_t max_retries; + uint32_t timeout; + uint32_t ipv4_addr_type; + uint32_t ipv6_addr_type; + struct qdf_mac_addr gw_mac_addr; + uint8_t ipv4_addr[QDF_IPV4_ADDR_SIZE]; + uint8_t ipv6_addr[QDF_IPV6_ADDR_SIZE]; +}; + +/** + * struct rssi_monitor_param - rssi monitoring + * @request_id: request id + * @session_id: session id + * @min_rssi: minimum rssi + * @max_rssi: maximum rssi + * @control: flag to indicate start or stop + */ +struct rssi_monitor_param { + uint32_t request_id; + uint32_t session_id; + int8_t min_rssi; + int8_t max_rssi; + bool control; +}; + +/** + * struct scan_mac_oui - oui paramters + * @oui: oui parameters + * @vdev_id: session id + * @enb_probe_req_sno_randomization: set to true for enabling + * seq number randomization of probe req frames + * @ie_whitelist: set to true for enabling ie whitelisting + * @probe_req_ie_bitmap: contains IEs to be included in probe req + * @num_vendor_oui: number of vendor OUIs + * @oui_field_len: size of total number of OUIs + * @voui: pointer to OUI buffer + */ +struct scan_mac_oui { + uint8_t oui[WMI_WIFI_SCANNING_MAC_OUI_LENGTH]; + uint32_t vdev_id; + bool enb_probe_req_sno_randomization; + /* probe req ie whitelisting attrs */ + bool ie_whitelist; + uint32_t probe_req_ie_bitmap[PROBE_REQ_BITMAP_LEN]; + uint32_t num_vendor_oui; + uint32_t oui_field_len; + uint8_t *voui; +}; + +#define WMI_PASSPOINT_REALM_LEN 256 +#define WMI_PASSPOINT_ROAMING_CONSORTIUM_ID_NUM 16 +#define WMI_PASSPOINT_PLMN_LEN 3 +/** + * struct wifi_passpoint_network_param - passpoint network block + * @id: identifier of this network block + * @realm: null terminated UTF8 encoded realm, 0 if unspecified + * @roaming_consortium_ids: roaming consortium ids to match, 0s if unspecified + * @plmn: mcc/mnc combination as per rules, 0s if unspecified + */ +struct wifi_passpoint_network_param { + uint32_t id; + uint8_t realm[WMI_PASSPOINT_REALM_LEN]; + int64_t roaming_consortium_ids[WMI_PASSPOINT_ROAMING_CONSORTIUM_ID_NUM]; + uint8_t plmn[WMI_PASSPOINT_PLMN_LEN]; +}; + +/** + * struct wifi_passpoint_req_param - passpoint request + * @request_id: request identifier + * @num_networks: number of networks + * @networks: passpoint networks + */ +struct wifi_passpoint_req_param { + uint32_t request_id; + uint32_t session_id; + uint32_t num_networks; + struct wifi_passpoint_network_param networks[]; +}; + +/* struct mobility_domain_info - structure containing + * mobility domain info + * @mdie_present: mobility domain present or not + * @mobility_domain: mobility domain + */ +struct mobility_domain_info { + uint8_t mdie_present; + uint16_t mobility_domain; +}; + +#define WMI_HOST_ROAM_OFFLOAD_NUM_MCS_SET (16) + +/* This TLV will be filled only in case roam offload + * for wpa2-psk/pmkid/ese/11r is enabled */ +typedef struct { + /* + * TLV tag and len; tag equals + * WMITLV_TAG_STRUC_wmi_roam_offload_fixed_param + */ + uint32_t tlv_header; + uint32_t rssi_cat_gap; /* gap for every category bucket */ + uint32_t prefer_5g; /* prefer select 5G candidate */ + uint32_t select_5g_margin; + uint32_t reassoc_failure_timeout; /* reassoc failure timeout */ + uint32_t capability; + uint32_t ht_caps_info; + uint32_t ampdu_param; + uint32_t ht_ext_cap; + uint32_t ht_txbf; + uint32_t asel_cap; + uint32_t qos_enabled; + uint32_t qos_caps; + uint32_t wmm_caps; + /* since this is 4 byte aligned, we don't declare it as tlv array */ + uint32_t mcsset[WMI_HOST_ROAM_OFFLOAD_NUM_MCS_SET >> 2]; +} roam_offload_param; + +/* struct roam_offload_scan_params - structure + * containing roaming offload scan parameters + * @is_roam_req_valid: flag to tell whether roam req + * is valid or NULL + * @mode: stores flags for scan + * @vdev_id: vdev id + * @roam_offload_enabled: flag for offload enable + * @psk_pmk: pre shared key/pairwise master key + * @pmk_len: length of PMK + * @prefer_5ghz: prefer select 5G candidate + * @roam_rssi_cat_gap: gap for every category bucket + * @select_5ghz_margin: select 5 Ghz margin + * @krk: KRK + * @btk: BTK + * @reassoc_failure_timeout: reassoc failure timeout + * @rokh_id_length: r0kh id length + * @rokh_id: r0kh id + * @roam_key_mgmt_offload_enabled: roam offload flag + * @auth_mode: authentication mode + * @fw_okc: use OKC in firmware + * @fw_pmksa_cache: use PMKSA cache in firmware + * @is_ese_assoc: flag to determine ese assoc + * @mdid: mobility domain info + * @roam_offload_params: roam offload tlv params + */ +struct roam_offload_scan_params { + uint8_t is_roam_req_valid; + uint32_t mode; + uint32_t vdev_id; +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + uint8_t roam_offload_enabled; + uint8_t psk_pmk[WMI_ROAM_SCAN_PSK_SIZE]; + uint32_t pmk_len; + uint8_t prefer_5ghz; + uint8_t roam_rssi_cat_gap; + uint8_t select_5ghz_margin; + uint8_t krk[WMI_KRK_KEY_LEN]; + uint8_t btk[WMI_BTK_KEY_LEN]; + uint32_t reassoc_failure_timeout; + uint32_t rokh_id_length; + uint8_t rokh_id[WMI_ROAM_R0KH_ID_MAX_LEN]; + uint8_t roam_key_mgmt_offload_enabled; + int auth_mode; + bool fw_okc; + bool fw_pmksa_cache; +#endif + bool is_ese_assoc; + struct mobility_domain_info mdid; +#ifndef WMI_NON_TLV_SUPPORT + /* THis is not available in non tlv target. + * please remove this and replace with a host based + * structure */ + roam_offload_param roam_offload_params; +#endif + uint32_t assoc_ie_length; + uint8_t assoc_ie[MAX_ASSOC_IE_LENGTH]; +}; + +/* struct roam_offload_scan_rssi_params - structure containing + * parameters for roam offload scan based on RSSI + * @rssi_thresh: rssi threshold + * @rssi_thresh_diff: difference in rssi threshold + * @hi_rssi_scan_max_count: 5G scan max count + * @hi_rssi_scan_rssi_delta: 5G scan rssi change threshold value + * @hi_rssi_scan_rssi_ub: 5G scan upper bound + * @raise_rssi_thresh_5g: flag to determine penalty and boost thresholds + * @session_id: vdev id + * @penalty_threshold_5g: RSSI threshold below which 5GHz RSSI is penalized + * @boost_threshold_5g: RSSI threshold above which 5GHz RSSI is favored + * @raise_factor_5g: factor by which 5GHz RSSI is boosted + * @drop_factor_5g: factor by which 5GHz RSSI is penalized + * @max_raise_rssi_5g: maximum boost that can be applied to a 5GHz RSSI + * @max_drop_rssi_5g: maximum penalty that can be applied to a 5GHz RSSI + * @good_rssi_threshold: RSSI below which roam is kicked in by background + * scan although rssi is still good + * @roam_earlystop_thres_min: Minimum RSSI threshold value for early stop, + * unit is dB above NF + * @roam_earlystop_thres_max: Maximum RSSI threshold value for early stop, + * unit is dB above NF + * @dense_rssi_thresh_offset: dense roam RSSI threshold difference + * @dense_min_aps_cnt: dense roam minimum APs + * @initial_dense_status: dense status detected by host + * @traffic_threshold: dense roam RSSI threshold + */ +struct roam_offload_scan_rssi_params { + int8_t rssi_thresh; + uint8_t rssi_thresh_diff; + uint32_t hi_rssi_scan_max_count; + uint32_t hi_rssi_scan_rssi_delta; + int32_t hi_rssi_scan_rssi_ub; + int raise_rssi_thresh_5g; + uint8_t session_id; + uint32_t penalty_threshold_5g; + uint32_t boost_threshold_5g; + uint8_t raise_factor_5g; + uint8_t drop_factor_5g; + int max_raise_rssi_5g; + int max_drop_rssi_5g; + uint32_t good_rssi_threshold; + uint32_t roam_earlystop_thres_min; + uint32_t roam_earlystop_thres_max; + int dense_rssi_thresh_offset; + int dense_min_aps_cnt; + int initial_dense_status; + int traffic_threshold; +}; + +/** + * struct wifi_epno_network - enhanced pno network block + * @ssid: ssid + * @rssi_threshold: threshold for considering this SSID as found, required + * granularity for this threshold is 4dBm to 8dBm + * @flags: WIFI_PNO_FLAG_XXX + * @auth_bit_field: auth bit field for matching WPA IE + */ +struct wifi_epno_network_params { + struct mac_ssid ssid; + int8_t rssi_threshold; + uint8_t flags; + uint8_t auth_bit_field; +}; + +/** + * struct wifi_enhanched_pno_params - enhanced pno network params + * @request_id: request id number + * @session_id: session_id number + * @min_5ghz_rssi: minimum 5GHz RSSI for a BSSID to be considered + * @min_24ghz_rssi: minimum 2.4GHz RSSI for a BSSID to be considered + * @initial_score_max: maximum score that a network can have before bonuses + * @current_connection_bonus: only report when there is a network's score this + * much higher than the current connection + * @same_network_bonus: score bonus for all n/w with the same network flag + * @secure_bonus: score bonus for networks that are not open + * @band_5ghz_bonus: 5GHz RSSI score bonus (applied to all 5GHz networks) + * @num_networks: number of ssids + * @networks: EPNO networks + */ +struct wifi_enhanched_pno_params { + uint32_t request_id; + uint32_t session_id; + uint32_t min_5ghz_rssi; + uint32_t min_24ghz_rssi; + uint32_t initial_score_max; + uint32_t current_connection_bonus; + uint32_t same_network_bonus; + uint32_t secure_bonus; + uint32_t band_5ghz_bonus; + uint32_t num_networks; + struct wifi_epno_network_params networks[]; +}; + +enum { + WMI_AP_RX_DATA_OFFLOAD = 0x00, + WMI_STA_RX_DATA_OFFLOAD = 0x01, +}; + +/** + * enum extscan_configuration_flags - extscan config flags + * @WMI_EXTSCAN_LP_EXTENDED_BATCHING: extended batching + */ +enum wmi_extscan_configuration_flags { + WMI_EXTSCAN_LP_EXTENDED_BATCHING = 0x00000001, +}; + +/** + * enum extscan_report_events_type - extscan report events type + * @EXTSCAN_REPORT_EVENTS_BUFFER_FULL: report only when scan history is % full + * @EXTSCAN_REPORT_EVENTS_EACH_SCAN: report a scan completion event after scan + * @EXTSCAN_REPORT_EVENTS_FULL_RESULTS: forward scan results + * (beacons/probe responses + IEs) + * in real time to HAL, in addition to completion events. + * Note: To keep backward compatibility, + * fire completion events regardless of REPORT_EVENTS_EACH_SCAN. + * @EXTSCAN_REPORT_EVENTS_NO_BATCH: controls batching, + * 0 => batching, 1 => no batching + */ +enum wmi_extscan_report_events_type { + WMI_EXTSCAN_REPORT_EVENTS_BUFFER_FULL = 0x00, + WMI_EXTSCAN_REPORT_EVENTS_EACH_SCAN = 0x01, + WMI_EXTSCAN_REPORT_EVENTS_FULL_RESULTS = 0x02, + WMI_EXTSCAN_REPORT_EVENTS_NO_BATCH = 0x04, +}; + +/** + * struct ipa_offload_control_params - ipa offload parameters + * @offload_type: ipa offload type + * @vdev_id: vdev id + * @enable: ipa offload enable/disable + */ +struct ipa_offload_control_params { + uint32_t offload_type; + uint32_t vdev_id; + uint32_t enable; +}; + +/** + * struct extscan_capabilities_params - ext scan capablities + * @request_id: request_id + * @session_id: session_id + */ +struct extscan_capabilities_params { + uint32_t request_id; + uint8_t session_id; +}; + +/** + * struct extscan_capabilities_reset_params - ext scan capablities reset parameter + * @request_id: request_id + * @session_id: session_id + */ +struct extscan_capabilities_reset_params { + uint32_t request_id; + uint8_t session_id; +}; + +/** + * struct extscan_bssid_hotlist_reset_params - ext scan hotlist reset parameter + * @request_id: request_id + * @session_id: session_id + */ +struct extscan_bssid_hotlist_reset_params { + uint32_t request_id; + uint8_t session_id; +}; + +/** + * struct extscan_stop_req_params - ext scan stop parameter + * @request_id: request_id + * @session_id: session_id + */ +struct extscan_stop_req_params { + uint32_t request_id; + uint8_t session_id; +}; + +/** + * struct ap_threshold_params - ap threshold parameter + * @bssid: mac address + * @low: low threshold + * @high: high threshold + */ +struct ap_threshold_params { + struct qdf_mac_addr bssid; + int32_t low; + int32_t high; +}; + +/** + * struct extscan_set_sig_changereq_params - ext scan channel parameter + * @request_id: mac address + * @session_id: low threshold + * @rssi_sample_size: Number of samples for averaging RSSI + * @lostap_sample_size: Number of missed samples to confirm AP loss + * @min_breaching: Number of APs breaching threshold required for firmware + * @num_ap: no of scanned ap + * @ap: ap threshold parameter + */ +struct extscan_set_sig_changereq_params { + uint32_t request_id; + uint8_t session_id; + uint32_t rssi_sample_size; + uint32_t lostap_sample_size; + uint32_t min_breaching; + uint32_t num_ap; + struct ap_threshold_params ap[WMI_EXTSCAN_MAX_SIGNIFICANT_CHANGE_APS]; +}; + +/** + * struct extscan_cached_result_params - ext scan cached parameter + * @request_id: mac address + * @session_id: low threshold + * @flush: cached results flush + */ +struct extscan_cached_result_params { + uint32_t request_id; + uint8_t session_id; + bool flush; +}; + +/* Set PNO */ +#define WMI_PNO_MAX_NETW_CHANNELS 26 +#define WMI_PNO_MAX_NETW_CHANNELS_EX 60 +#define WMI_PNO_MAX_SUPP_NETWORKS 16 + +/* + * size based of dot11 declaration without extra IEs as we will not carry those + * for PNO + */ +#define WMI_PNO_MAX_PB_REQ_SIZE 450 + +#define WMI_PNO_24G_DEFAULT_CH 1 +#define WMI_PNO_5G_DEFAULT_CH 36 + +/** + * enum pno_mode - pno mode types + * @WMI_PNO_MODE_IMMEDIATE: immidiate mode + * @WMI_PNO_MODE_ON_SUSPEND: suspend on mode + * @WMI_PNO_MODE_ON_RESUME: resume on mode + * @WMI_PNO_MODE_MAX: max range + */ +enum pno_mode { + WMI_PNO_MODE_IMMEDIATE, + WMI_PNO_MODE_ON_SUSPEND, + WMI_PNO_MODE_ON_RESUME, + WMI_PNO_MODE_MAX +}; + +/** + * struct pno_nw_type - pno nw type + * @ssid: mac ssid + * @authentication: authentication type + * @encryption: encryption type + * @bcastNetwType: broadcast nw type + * @ucChannelCount: uc channel count + * @aChannels: pno channel + * @rssiThreshold: rssi threshold + */ +struct pno_nw_type { + struct mac_ssid ssid; + uint32_t authentication; + uint32_t encryption; + uint32_t bcastNetwType; + uint8_t ucChannelCount; + uint8_t aChannels[WMI_PNO_MAX_NETW_CHANNELS_EX]; + int32_t rssiThreshold; +}; + +/** + * struct pno_scan_req_params - PNO Scan request structure + * @enable: flag to enable or disable + * @modePNO: PNO Mode + * @ucNetworksCount: Number of networks + * @do_passive_scan: Flag to request passive scan to fw + * @aNetworks: Preferred network list + * @sessionId: Session identifier + * @fast_scan_period: Fast Scan period + * @slow_scan_period: Slow scan period + * @delay_start_time: delay in seconds to use before starting the first scan + * @fast_scan_max_cycles: Fast scan max cycles + * @us24GProbeTemplateLen: 2.4G probe template length + * @p24GProbeTemplate: 2.4G probe template + * @us5GProbeTemplateLen: 5G probe template length + * @p5GProbeTemplate: 5G probe template + * @pno_channel_prediction: PNO channel prediction feature status + * @top_k_num_of_channels: top K number of channels are used for tanimoto + * distance calculation. + * @stationary_thresh: threshold value to determine that the STA is stationary. + * @pnoscan_adaptive_dwell_mode: adaptive dwelltime mode for pno scan + * @channel_prediction_full_scan: periodic timer upon which a full scan needs + * to be triggered. + * @enable_pno_scan_randomization: enable pno scan randomization feature + * @mac_addr: MAC address used with randomization + * @mac_addr_mask: MAC address mask used with randomization, bits that + * are 0 in the mask should be randomized, bits that are 1 should + * be taken from the @mac_addr + * @ie_whitelist: set to true for enabling ie whitelisting + * @probe_req_ie_bitmap: contains IEs to be included in probe req + * @num_vendor_oui: number of vendor OUIs + * @oui_field_len: size of total number of OUIs + * @voui: pointer to OUI buffer + */ +struct pno_scan_req_params { + uint8_t enable; + enum pno_mode modePNO; + uint8_t ucNetworksCount; + bool do_passive_scan; + struct pno_nw_type aNetworks[WMI_PNO_MAX_SUPP_NETWORKS]; + uint8_t sessionId; + uint32_t fast_scan_period; + uint32_t slow_scan_period; + uint32_t delay_start_time; + uint8_t fast_scan_max_cycles; + uint32_t active_min_time; + uint32_t active_max_time; + uint32_t passive_min_time; + uint32_t passive_max_time; + uint16_t us24GProbeTemplateLen; + uint8_t p24GProbeTemplate[WMI_PNO_MAX_PB_REQ_SIZE]; + uint16_t us5GProbeTemplateLen; + uint8_t p5GProbeTemplate[WMI_PNO_MAX_PB_REQ_SIZE]; +#ifdef FEATURE_WLAN_SCAN_PNO + bool pno_channel_prediction; + uint8_t top_k_num_of_channels; + uint8_t stationary_thresh; + enum wmi_dwelltime_adaptive_mode pnoscan_adaptive_dwell_mode; + uint32_t channel_prediction_full_scan; +#endif + /* mac address randomization attributes */ + bool enable_pno_scan_randomization; + uint8_t mac_addr[QDF_MAC_ADDR_SIZE]; + uint8_t mac_addr_mask[QDF_MAC_ADDR_SIZE]; + + /* probe req ie whitelisting attrs */ + bool ie_whitelist; + uint32_t probe_req_ie_bitmap[PROBE_REQ_BITMAP_LEN]; + uint32_t num_vendor_oui; + uint32_t oui_field_len; + uint8_t *voui; +}; + +#define WMI_WLAN_EXTSCAN_MAX_CHANNELS 36 +#define WMI_WLAN_EXTSCAN_MAX_BUCKETS 16 +#define WMI_WLAN_EXTSCAN_MAX_HOTLIST_APS 128 +#define WMI_WLAN_EXTSCAN_MAX_SIGNIFICANT_CHANGE_APS 64 +#define WMI_EXTSCAN_MAX_HOTLIST_SSIDS 8 + +/** + * struct wifi_scan_channelspec_params - wifi scan channel parameter + * @channel: Frequency in MHz + * @dwellTimeMs: dwell time + * @flush: cached results flush + * @passive: passive scan + * @chnlClass: channel class + */ +struct wifi_scan_channelspec_params { + uint32_t channel; + uint32_t dwellTimeMs; + bool passive; + uint8_t chnlClass; +}; + +/** + * enum wmi_wifi_band - wifi band + * @WMI_WIFI_BAND_UNSPECIFIED: unspecified band + * @WMI_WIFI_BAND_BG: 2.4 GHz + * @WMI_WIFI_BAND_A: 5 GHz without DFS + * @WMI_WIFI_BAND_ABG: 2.4 GHz + 5 GHz; no DFS + * @WMI_WIFI_BAND_A_DFS_ONLY: 5 GHz DFS only + * @WMI_WIFI_BAND_A_WITH_DFS: 5 GHz with DFS + * @WMI_WIFI_BAND_ABG_WITH_DFS: 2.4 GHz + 5 GHz with DFS + * @WMI_WIFI_BAND_MAX: max range + */ +enum wmi_wifi_band { + WMI_WIFI_BAND_UNSPECIFIED, + WMI_WIFI_BAND_BG = 1, + WMI_WIFI_BAND_A = 2, + WMI_WIFI_BAND_ABG = 3, + WMI_WIFI_BAND_A_DFS_ONLY = 4, + /* 5 is reserved */ + WMI_WIFI_BAND_A_WITH_DFS = 6, + WMI_WIFI_BAND_ABG_WITH_DFS = 7, + /* Keep it last */ + WMI_WIFI_BAND_MAX +}; + +/** + * struct wifi_scan_bucket_params - wifi scan bucket spec + * @bucket: bucket identifier + * @band: wifi band + * @period: Desired period, in millisecond; if this is too + * low, the firmware should choose to generate results as fast as + * it can instead of failing the command byte + * for exponential backoff bucket this is the min_period + * @reportEvents: 0 => normal reporting (reporting rssi history + * only, when rssi history buffer is % full) + * 1 => same as 0 + report a scan completion event after scanning + * this bucket + * 2 => same as 1 + forward scan results + * (beacons/probe responses + IEs) in real time to HAL + * @max_period: if max_period is non zero or different than period, + * then this bucket is an exponential backoff bucket and + * the scan period will grow exponentially as per formula: + * actual_period(N) = period ^ (N/(step_count+1)) to a + * maximum period of max_period + * @exponent: for exponential back off bucket: multiplier: + * new_period = old_period * exponent + * @step_count: for exponential back off bucket, number of scans performed + * at a given period and until the exponent is applied + * @numChannels: channels to scan; these may include DFS channels + * Note that a given channel may appear in multiple buckets + * @min_dwell_time_active: per bucket minimum active dwell time + * @max_dwell_time_active: per bucket maximum active dwell time + * @min_dwell_time_passive: per bucket minimum passive dwell time + * @max_dwell_time_passive: per bucket maximum passive dwell time + * @channels: Channel list + */ +struct wifi_scan_bucket_params { + uint8_t bucket; + enum wmi_wifi_band band; + uint32_t period; + uint32_t reportEvents; + uint32_t max_period; + uint32_t exponent; + uint32_t step_count; + uint32_t numChannels; + uint32_t min_dwell_time_active; + uint32_t max_dwell_time_active; + uint32_t min_dwell_time_passive; + uint32_t max_dwell_time_passive; + struct wifi_scan_channelspec_params channels[WMI_WLAN_EXTSCAN_MAX_CHANNELS]; +}; + +/** + * struct wifi_scan_cmd_req_params - wifi scan command request params + * @basePeriod: base timer period + * @maxAPperScan: max ap per scan + * @report_threshold_percent: report threshold + * in %, when buffer is this much full, wake up host + * @report_threshold_num_scans: report threshold number of scans + * in number of scans, wake up host after these many scans + * @requestId: request id + * @sessionId: session id + * @numBuckets: number of buckets + * @min_dwell_time_active: per bucket minimum active dwell time + * @max_dwell_time_active: per bucket maximum active dwell time + * @min_dwell_time_passive: per bucket minimum passive dwell time + * @max_dwell_time_passive: per bucket maximum passive dwell time + * @configuration_flags: configuration flags + * @extscan_adaptive_dwell_mode: adaptive dwelltime mode for extscan + * @buckets: buckets array + */ +struct wifi_scan_cmd_req_params { + uint32_t basePeriod; + uint32_t maxAPperScan; + + uint32_t report_threshold_percent; + uint32_t report_threshold_num_scans; + + uint32_t requestId; + uint8_t sessionId; + uint32_t numBuckets; + + uint32_t min_dwell_time_active; + uint32_t max_dwell_time_active; + uint32_t min_dwell_time_passive; + uint32_t max_dwell_time_passive; + uint32_t configuration_flags; + enum wmi_dwelltime_adaptive_mode extscan_adaptive_dwell_mode; + struct wifi_scan_bucket_params buckets[WMI_WLAN_EXTSCAN_MAX_BUCKETS]; +}; + +#define WMI_CFG_VALID_CHANNEL_LIST_LEN 100 +/* Occupied channel list remains static */ +#define WMI_CHANNEL_LIST_STATIC 1 +/* Occupied channel list can be learnt after init */ +#define WMI_CHANNEL_LIST_DYNAMIC_INIT 2 +/* Occupied channel list can be learnt after flush */ +#define WMI_CHANNEL_LIST_DYNAMIC_FLUSH 3 +/* Occupied channel list can be learnt after update */ +#define WMI_CHANNEL_LIST_DYNAMIC_UPDATE 4 + +/** + * struct plm_req_params - plm req parameter + * @diag_token: Dialog token + * @meas_token: measurement token + * @num_bursts: total number of bursts + * @burst_int: burst interval in seconds + * @meas_duration:in TU's,STA goes off-ch + * @burst_len: no of times the STA should cycle through PLM ch list + * @desired_tx_pwr: desired tx power + * @mac_addr: MC dest addr + * @plm_num_ch: channel numbers + * @plm_ch_list: channel list + * @session_id: session id + * @enable: enable/disable + */ +struct plm_req_params { + uint16_t diag_token; + uint16_t meas_token; + uint16_t num_bursts; + uint16_t burst_int; + uint16_t meas_duration; + /* no of times the STA should cycle through PLM ch list */ + uint8_t burst_len; + int8_t desired_tx_pwr; + struct qdf_mac_addr mac_addr; + /* no of channels */ + uint8_t plm_num_ch; + /* channel numbers */ + uint8_t plm_ch_list[WMI_CFG_VALID_CHANNEL_LIST_LEN]; + uint8_t session_id; + bool enable; +}; + +#define MAX_SSID_ALLOWED_LIST 4 +#define MAX_BSSID_AVOID_LIST 16 +#define MAX_BSSID_FAVORED 16 + + +/** + * struct mac_ts_info_tfc - mac ts info parameters + * @burstSizeDefn: burst size + * @reserved: reserved + * @ackPolicy: ack policy + * @psb: psb + * @aggregation: aggregation + * @accessPolicy: access policy + * @direction: direction + * @tsid: direction + * @trafficType: traffic type + */ +struct mac_ts_info_tfc { +#ifndef ANI_LITTLE_BIT_ENDIAN + uint8_t burstSizeDefn:1; + uint8_t reserved:7; +#else + uint8_t reserved:7; + uint8_t burstSizeDefn:1; +#endif + +#ifndef ANI_LITTLE_BIT_ENDIAN + uint16_t ackPolicy:2; + uint16_t userPrio:3; + uint16_t psb:1; + uint16_t aggregation:1; + uint16_t accessPolicy:2; + uint16_t direction:2; + uint16_t tsid:4; + uint16_t trafficType:1; +#else + uint16_t trafficType:1; + uint16_t tsid:4; + uint16_t direction:2; + uint16_t accessPolicy:2; + uint16_t aggregation:1; + uint16_t psb:1; + uint16_t userPrio:3; + uint16_t ackPolicy:2; +#endif +} qdf_packed; + +/** + * struct mac_ts_info_sch - mac ts info schedule parameters + * @rsvd: reserved + * @schedule: schedule bit + */ +struct mac_ts_info_sch { +#ifndef ANI_LITTLE_BIT_ENDIAN + uint8_t rsvd:7; + uint8_t schedule:1; +#else + uint8_t schedule:1; + uint8_t rsvd:7; +#endif +} qdf_packed; + +/** + * struct mac_ts_info_sch - mac ts info schedule parameters + * @traffic: mac tfc parameter + * @schedule: mac schedule parameters + */ +struct mac_ts_info { + struct mac_ts_info_tfc traffic; + struct mac_ts_info_sch schedule; +} qdf_packed; + +/** + * struct mac_tspec_ie - mac ts spec + * @type: type + * @length: length + * @tsinfo: tsinfo + * @nomMsduSz: nomMsduSz + * @maxMsduSz: maxMsduSz + * @minSvcInterval: minSvcInterval + * @maxSvcInterval: maxSvcInterval + * @inactInterval: inactInterval + * @suspendInterval: suspendInterval + * @svcStartTime: svcStartTime + * @minDataRate: minDataRate + * @meanDataRate: meanDataRate + * @peakDataRate: peakDataRate + * @maxBurstSz: maxBurstSz + * @delayBound: delayBound + * @minPhyRate: minPhyRate + * @surplusBw: surplusBw + * @mediumTime: mediumTime + */ +struct mac_tspec_ie { + uint8_t type; + uint8_t length; + struct mac_ts_info tsinfo; + uint16_t nomMsduSz; + uint16_t maxMsduSz; + uint32_t minSvcInterval; + uint32_t maxSvcInterval; + uint32_t inactInterval; + uint32_t suspendInterval; + uint32_t svcStartTime; + uint32_t minDataRate; + uint32_t meanDataRate; + uint32_t peakDataRate; + uint32_t maxBurstSz; + uint32_t delayBound; + uint32_t minPhyRate; + uint16_t surplusBw; + uint16_t mediumTime; +} qdf_packed; + +/** + * struct add_ts_param - ADDTS related parameters + * @staIdx: station index + * @tspecIdx: TSPEC handler uniquely identifying a TSPEC for a STA in a BSS + * @tspec: tspec value + * @status: CDF status + * @sessionId: session id + * @tsm_interval: TSM interval period passed from UMAC to WMI + * @setRICparams: RIC parameters + * @sme_session_id: sme session id + */ +struct add_ts_param { + uint16_t staIdx; + uint16_t tspecIdx; + struct mac_tspec_ie tspec; + QDF_STATUS status; + uint8_t sessionId; +#ifdef FEATURE_WLAN_ESE + uint16_t tsm_interval; +#endif /* FEATURE_WLAN_ESE */ +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + uint8_t setRICparams; +#endif /* WLAN_FEATURE_ROAM_OFFLOAD */ + uint8_t sme_session_id; +}; + +/** + * struct delts_req_info - DELTS request parameter + * @tsinfo: ts info + * @tspec: ts spec + * @wmeTspecPresent: wme ts spec flag + * @wsmTspecPresent: wsm ts spec flag + * @lleTspecPresent: lle ts spec flag + */ +struct delts_req_info { + struct mac_ts_info tsinfo; + struct mac_tspec_ie tspec; + uint8_t wmeTspecPresent:1; + uint8_t wsmTspecPresent:1; + uint8_t lleTspecPresent:1; +}; + +/** + * struct del_ts_params - DELTS related parameters + * @staIdx: station index + * @tspecIdx: TSPEC identifier uniquely identifying a TSPEC for a STA in a BSS + * @bssId: BSSID + * @sessionId: session id + * @userPrio: user priority + * @delTsInfo: DELTS info + * @setRICparams: RIC parameters + */ +struct del_ts_params { + uint16_t staIdx; + uint16_t tspecIdx; + uint8_t bssId[IEEE80211_ADDR_LEN]; + uint8_t sessionId; + uint8_t userPrio; +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + struct delts_req_info delTsInfo; + uint8_t setRICparams; +#endif /* WLAN_FEATURE_ROAM_OFFLOAD */ +}; + +/** + * struct ll_stats_clear_params - ll stats clear parameter + * @req_id: request id + * @sta_id: sta id + * @stats_clear_mask: stats clear mask + * @stop_req: stop request + */ +struct ll_stats_clear_params { + uint32_t req_id; + uint8_t sta_id; + uint32_t stats_clear_mask; + uint8_t stop_req; +}; + +/** + * struct ll_stats_set_params - ll stats get parameter + * @req_id: request id + * @sta_id: sta id + * @mpdu_size_threshold: mpdu sixe threshold + * @aggressive_statistics_gathering: aggressive_statistics_gathering + */ +struct ll_stats_set_params { + uint32_t req_id; + uint8_t sta_id; + uint32_t mpdu_size_threshold; + uint32_t aggressive_statistics_gathering; +}; + +/** + * struct ll_stats_get_params - ll stats parameter + * @req_id: request id + * @sta_id: sta id + * @param_id_mask: param is mask + */ +struct ll_stats_get_params { + uint32_t req_id; + uint8_t sta_id; + uint32_t param_id_mask; +}; + +/** + * struct pe_stats_req - pe stats parameter + * @msg_type: message type is same as the request type + * @msg_len: length of the entire request + * @sta_id: Per STA stats request must contain valid + * @stats_mask: categories of stats requested + * @session_id: wsm ts spec flag + */ +struct pe_stats_req { + /* Common for all types are requests */ + uint16_t msg_type; + uint16_t msg_len; + uint32_t sta_id; + /* categories of stats requested. look at ePEStatsMask */ + uint32_t stats_mask; + uint8_t session_id; +}; + +/** + * struct link_status_params - link stats parameter + * @msg_type: message type is same as the request type + * @msg_len: length of the entire request + * @link_status: wme ts spec flag + * @session_id: wsm ts spec flag + */ +struct link_status_params { + uint16_t msg_type; + uint16_t msg_len; + uint8_t link_status; + uint8_t session_id; +}; + +/** + * struct dhcp_stop_ind_params - DHCP Stop indication message + * @msgtype: message type is same as the request type + * @msglen: length of the entire request + * @device_mode: Mode of the device(ex:STA, AP) + * @adapter_macaddr: MAC address of the adapter + * @peer_macaddr: MAC address of the connected peer + */ +struct dhcp_stop_ind_params { + uint16_t msgtype; + uint16_t msglen; + uint8_t device_mode; + struct qdf_mac_addr adapter_macaddr; + struct qdf_mac_addr peer_macaddr; +}; + +/** + * struct aggr_add_ts_param - ADDTS parameters + * @staIdx: station index + * @tspecIdx: TSPEC handler uniquely identifying a TSPEC for a STA in a BSS + * @tspec: tspec value + * @status: CDF status + * @sessionId: session id + */ +struct aggr_add_ts_param { + uint16_t staIdx; + uint16_t tspecIdx; + struct mac_tspec_ie tspec[WMI_QOS_NUM_AC_MAX]; + QDF_STATUS status[WMI_QOS_NUM_AC_MAX]; + uint8_t sessionId; +}; + +#define WMI_MAX_FILTER_TEST_DATA_LEN 8 +#define WMI_MAX_NUM_MULTICAST_ADDRESS 240 +#define WMI_MAX_NUM_FILTERS 20 +#define WMI_MAX_NUM_TESTS_PER_FILTER 10 + +/** + * enum packet_filter_type - packet filter type + * @WMI_RCV_FILTER_TYPE_INVALID: invalid type + * @WMI_RCV_FILTER_TYPE_FILTER_PKT: filter packet type + * @WMI_RCV_FILTER_TYPE_BUFFER_PKT: buffer packet type + * @WMI_RCV_FILTER_TYPE_MAX_ENUM_SIZE: max enum size + */ +enum packet_filter_type { + WMI_RCV_FILTER_TYPE_INVALID, + WMI_RCV_FILTER_TYPE_FILTER_PKT, + WMI_RCV_FILTER_TYPE_BUFFER_PKT, + WMI_RCV_FILTER_TYPE_MAX_ENUM_SIZE +}; + +/** + * enum packet_protocol_type - packet protocol type + * @WMI_FILTER_HDR_TYPE_INVALID: invalid type + * @WMI_FILTER_HDR_TYPE_MAC: mac type + * @WMI_FILTER_HDR_TYPE_ARP: trp type + * @WMI_FILTER_HDR_TYPE_IPV4: ipv4 type + * @WMI_FILTER_HDR_TYPE_IPV6: ipv6 type + * @WMI_FILTER_HDR_TYPE_UDP: udp type + * @WMI_FILTER_HDR_TYPE_MAX: max type + */ +enum packet_protocol_type { + WMI_FILTER_HDR_TYPE_INVALID, + WMI_FILTER_HDR_TYPE_MAC, + WMI_FILTER_HDR_TYPE_ARP, + WMI_FILTER_HDR_TYPE_IPV4, + WMI_FILTER_HDR_TYPE_IPV6, + WMI_FILTER_HDR_TYPE_UDP, + WMI_FILTER_HDR_TYPE_MAX +}; + +/** + * enum packet_filter_comp_type - packet filter comparison type + * @WMI_FILTER_CMP_TYPE_INVALID: invalid type + * @WMI_FILTER_CMP_TYPE_EQUAL: type equal + * @WMI_FILTER_CMP_TYPE_MASK_EQUAL: mask equal + * @WMI_FILTER_CMP_TYPE_NOT_EQUAL: type not equal + * @WMI_FILTER_CMP_TYPE_MASK_NOT_EQUAL: mask not equal + * @WMI_FILTER_CMP_TYPE_MAX: max type + */ +enum packet_filter_comp_type { + WMI_FILTER_CMP_TYPE_INVALID, + WMI_FILTER_CMP_TYPE_EQUAL, + WMI_FILTER_CMP_TYPE_MASK_EQUAL, + WMI_FILTER_CMP_TYPE_NOT_EQUAL, + WMI_FILTER_CMP_TYPE_MASK_NOT_EQUAL, + WMI_FILTER_CMP_TYPE_MAX +}; + +/** + * struct rcv_pkt_filter_params - recieve packet filter parameters + * @protocolLayer - protocol layer + * @cmpFlag - comparison flag + * @dataLength - data length + * @dataOffset - data offset + * @reserved - resserved + * @compareData - compare data + * @dataMask - data mask + */ +struct rcv_pkt_filter_params { + enum packet_protocol_type protocolLayer; + enum packet_filter_comp_type cmpFlag; + uint16_t dataLength; + uint8_t dataOffset; + uint8_t reserved; + uint8_t compareData[WMI_MAX_FILTER_TEST_DATA_LEN]; + uint8_t dataMask[WMI_MAX_FILTER_TEST_DATA_LEN]; +}; + +/** + * struct rcv_pkt_filter_config - recieve packet filter info + * @filterId - filter id + * @filterType - filter type + * @numFieldParams - no of fields + * @coalesceTime - reserved parameter + * @self_macaddr - self mac address + * @bssid - Bssid of the connected AP + * @paramsData - data parameter + */ +struct rcv_pkt_filter_config { + uint8_t filterId; + enum packet_filter_type filterType; + uint32_t numFieldParams; + uint32_t coalesceTime; + struct qdf_mac_addr self_macaddr; + struct qdf_mac_addr bssid; + struct rcv_pkt_filter_params paramsData[WMI_MAX_NUM_TESTS_PER_FILTER]; +}; + +/** + * struct vdev_ie_info_param - IE info + * @vdev_id - vdev for which the IE is being sent + * @ie_id - ID of the IE + * @length - length of the IE data + * @data - IE data + * + * This structure is used to store the IE information. + */ +struct vdev_ie_info_param { + uint32_t vdev_id; + uint32_t ie_id; + uint32_t length; + uint32_t ie_source; + uint32_t band; + uint8_t *data; +}; + +#define WMI_MAX_NUM_FW_SEGMENTS 4 + +/** + * struct fw_dump_seg_req_param - individual segment details + * @seg_id - segment id. + * @seg_start_addr_lo - lower address of the segment. + * @seg_start_addr_hi - higher address of the segment. + * @seg_length - length of the segment. + * @dst_addr_lo - lower address of the destination buffer. + * @dst_addr_hi - higher address of the destination buffer. + * + * This structure carries the information to firmware about the + * individual segments. This structure is part of firmware memory + * dump request. + */ +struct fw_dump_seg_req_param { + uint8_t seg_id; + uint32_t seg_start_addr_lo; + uint32_t seg_start_addr_hi; + uint32_t seg_length; + uint32_t dst_addr_lo; + uint32_t dst_addr_hi; +}; + +/** + * struct fw_dump_req_param - firmware memory dump request details. + * @request_id - request id. + * @num_seg - requested number of segments. + * @fw_dump_seg_req - individual segment information. + * + * This structure carries information about the firmware + * memory dump request. + */ +struct fw_dump_req_param { + uint32_t request_id; + uint32_t num_seg; + struct fw_dump_seg_req_param segment[WMI_MAX_NUM_FW_SEGMENTS]; +}; + +#define WMI_TDLS_MAX_SUPP_CHANNELS 128 +#define WMI_TDLS_MAX_SUPP_OPER_CLASSES 32 +#define WMI_2_4_GHZ_MAX_FREQ 3000 + +/** + * struct tdls_update_ch_params - channel parameters + * @chanId: ID of the channel + * @pwr: power level + * @dfsSet: is dfs supported or not + * @half_rate: is the channel operating at 10MHz + * @quarter_rate: is the channel operating at 5MHz + */ +struct tdls_update_ch_params { + uint8_t chanId; + uint8_t pwr; + bool dfsSet; + bool half_rate; + bool quarter_rate; +}; + +/** + * struct tdls_peer_cap_params - TDLS peer capablities parameters + * @isPeerResponder: is peer responder or not + * @peerUapsdQueue: peer uapsd queue + * @peerMaxSp: peer max SP value + * @peerBuffStaSupport: peer buffer sta supported or not + * @peerOffChanSupport: peer offchannel support + * @peerCurrOperClass: peer current operating class + * @selfCurrOperClass: self current operating class + * @peerChanLen: peer channel length + * @peerChan: peer channel list + * @peerOperClassLen: peer operating class length + * @peerOperClass: peer operating class + * @prefOffChanNum: peer offchannel number + * @prefOffChanBandwidth: peer offchannel bandwidth + * @opClassForPrefOffChan: operating class for offchannel + */ +struct tdls_peer_cap_params { + uint8_t isPeerResponder; + uint8_t peerUapsdQueue; + uint8_t peerMaxSp; + uint8_t peerBuffStaSupport; + uint8_t peerOffChanSupport; + uint8_t peerCurrOperClass; + uint8_t selfCurrOperClass; + uint8_t peerChanLen; + struct tdls_update_ch_params peerChan[WMI_TDLS_MAX_SUPP_CHANNELS]; + uint8_t peerOperClassLen; + uint8_t peerOperClass[WMI_TDLS_MAX_SUPP_OPER_CLASSES]; + uint8_t prefOffChanNum; + uint8_t prefOffChanBandwidth; + uint8_t opClassForPrefOffChan; +}; + +/** + * struct tdls_peer_state_params - TDLS peer state parameters + * @vdevId: vdev id + * @peerMacAddr: peer mac address + * @peerCap: peer capabality + */ +struct tdls_peer_state_params { + uint32_t vdevId; + uint8_t peerMacAddr[IEEE80211_ADDR_LEN]; + uint32_t peerState; + struct tdls_peer_cap_params peerCap; +}; + +/** + * struct wmi_tdls_params - TDLS parameters + * @vdev_id: vdev id + * @tdls_state: TDLS state + * @notification_interval_ms: notification inerval + * @tx_discovery_threshold: tx discovery threshold + * @tx_teardown_threshold: tx teardown threashold + * @rssi_teardown_threshold: RSSI teardown threshold + * @rssi_delta: RSSI delta + * @tdls_options: TDLS options + * @peer_traffic_ind_window: raffic indication window + * @peer_traffic_response_timeout: traffic response timeout + * @puapsd_mask: uapsd mask + * @puapsd_inactivity_time: uapsd inactivity time + * @puapsd_rx_frame_threshold: uapsd rx frame threshold + * @teardown_notification_ms: tdls teardown notification interval + * @tdls_peer_kickout_threshold: tdls packet threshold for + * peer kickout operation + */ +struct wmi_tdls_params { + uint32_t vdev_id; + uint32_t tdls_state; + uint32_t notification_interval_ms; + uint32_t tx_discovery_threshold; + uint32_t tx_teardown_threshold; + int32_t rssi_teardown_threshold; + int32_t rssi_delta; + uint32_t tdls_options; + uint32_t peer_traffic_ind_window; + uint32_t peer_traffic_response_timeout; + uint32_t puapsd_mask; + uint32_t puapsd_inactivity_time; + uint32_t puapsd_rx_frame_threshold; + uint32_t teardown_notification_ms; + uint32_t tdls_peer_kickout_threshold; +}; + +/** + * struct tdls_chan_switch_params - channel switch parameter structure + * @vdev_id: vdev ID + * @peer_mac_addr: Peer mac address + * @tdls_off_ch_bw_offset: Target off-channel bandwitdh offset + * @tdls_off_ch: Target Off Channel + * @oper_class: Operating class for target channel + * @is_responder: Responder or initiator + */ +struct tdls_channel_switch_params { + uint32_t vdev_id; + uint8_t peer_mac_addr[IEEE80211_ADDR_LEN]; + uint16_t tdls_off_ch_bw_offset; + uint8_t tdls_off_ch; + uint8_t tdls_sw_mode; + uint8_t oper_class; + uint8_t is_responder; +}; + +/** + * struct dhcp_offload_info_params - dhcp offload parameters + * @vdev_id: request data length + * @dhcpSrvOffloadEnabled: dhcp offload enabled + * @dhcpClientNum: dhcp client no + * @dhcpSrvIP: dhcp server ip + */ +struct dhcp_offload_info_params { + uint32_t vdev_id; + uint32_t dhcpSrvOffloadEnabled; + uint32_t dhcpClientNum; + uint32_t dhcpSrvIP; +}; + +/** + * struct nan_req_params - NAN request params + * @request_data_len: request data length + * @request_data: request data + */ +struct nan_req_params { + uint16_t request_data_len; + uint8_t request_data[]; +}; + + +/** + * struct app_type2_params - app type2parameter + * @vdev_id: vdev id + * @rc4_key: rc4 key + * @rc4_key_len: rc4 key length + * @ip_id: NC id + * @ip_device_ip: NC IP addres + * @ip_server_ip: Push server IP address + * @tcp_src_port: NC TCP port + * @tcp_dst_port: Push server TCP port + * @tcp_seq: tcp sequence + * @tcp_ack_seq: tcp ack sequence + * @keepalive_init: Initial ping interval + * @keepalive_min: Minimum ping interval + * @keepalive_max: Maximum ping interval + * @keepalive_inc: Increment of ping interval + * @gateway_mac: gateway mac address + * @tcp_tx_timeout_val: tcp tx timeout value + * @tcp_rx_timeout_val: tcp rx timeout value + */ +struct app_type2_params { + uint8_t vdev_id; + uint8_t rc4_key[16]; + uint32_t rc4_key_len; + /** ip header parameter */ + uint32_t ip_id; + uint32_t ip_device_ip; + uint32_t ip_server_ip; + /** tcp header parameter */ + uint16_t tcp_src_port; + uint16_t tcp_dst_port; + uint32_t tcp_seq; + uint32_t tcp_ack_seq; + uint32_t keepalive_init; + uint32_t keepalive_min; + uint32_t keepalive_max; + uint32_t keepalive_inc; + struct qdf_mac_addr gateway_mac; + uint32_t tcp_tx_timeout_val; + uint32_t tcp_rx_timeout_val; +}; + +/** + * struct app_type1_params - app type1 parameter + * @vdev_id: vdev id + * @wakee_mac_addr: mac address + * @identification_id: identification id + * @password: password + * @id_length: id length + * @pass_length: password length + */ +struct app_type1_params { + uint8_t vdev_id; + struct qdf_mac_addr wakee_mac_addr; + uint8_t identification_id[8]; + uint8_t password[16]; + uint32_t id_length; + uint32_t pass_length; +}; + +/** + * enum wmi_ext_wow_type - wow type + * @WMI_EXT_WOW_TYPE_APP_TYPE1: only enable wakeup for app type1 + * @WMI_EXT_WOW_TYPE_APP_TYPE2: only enable wakeup for app type2 + * @WMI_EXT_WOW_TYPE_APP_TYPE1_2: enable wakeup for app type1&2 + */ +enum wmi_ext_wow_type { + WMI_EXT_WOW_TYPE_APP_TYPE1, + WMI_EXT_WOW_TYPE_APP_TYPE2, + WMI_EXT_WOW_TYPE_APP_TYPE1_2, +}; + +/** + * struct ext_wow_params - ext wow parameters + * @vdev_id: vdev id + * @type: wow type + * @wakeup_pin_num: wake up gpio no + */ +struct ext_wow_params { + uint8_t vdev_id; + enum wmi_ext_wow_type type; + uint32_t wakeup_pin_num; +}; + +/** + * struct stats_ext_params - ext stats request + * @vdev_id: vdev id + * @request_data_len: request data length + * @request_data: request data + */ +struct stats_ext_params { + uint32_t vdev_id; + uint32_t request_data_len; + uint8_t request_data[]; +}; + +#define WMI_PERIODIC_TX_PTRN_MAX_SIZE 1536 +/** + * struct periodic_tx_pattern - periodic tx pattern + * @mac_address: MAC Address for the adapter + * @ucPtrnId: Pattern ID + * @ucPtrnSize: Pattern size + * @usPtrnIntervalMs: in ms + * @ucPattern: Pattern buffer + */ +struct periodic_tx_pattern { + struct qdf_mac_addr mac_address; + uint8_t ucPtrnId; + uint16_t ucPtrnSize; + uint32_t usPtrnIntervalMs; + uint8_t ucPattern[WMI_PERIODIC_TX_PTRN_MAX_SIZE]; +}; + +#define WMI_GTK_OFFLOAD_KEK_BYTES 16 +#define WMI_GTK_OFFLOAD_KCK_BYTES 16 +#define WMI_GTK_OFFLOAD_ENABLE 0 +#define WMI_GTK_OFFLOAD_DISABLE 1 + +/** + * struct gtk_offload_params - gtk offload parameters + * @ulFlags: optional flags + * @aKCK: Key confirmation key + * @aKEK: key encryption key + * @ullKeyReplayCounter: replay counter + * @bssid: bss id + */ +struct gtk_offload_params { + uint32_t ulFlags; + uint8_t aKCK[WMI_GTK_OFFLOAD_KCK_BYTES]; + uint8_t aKEK[WMI_GTK_OFFLOAD_KEK_BYTES]; + uint64_t ullKeyReplayCounter; + struct qdf_mac_addr bssid; +}; + +/** + * struct flashing_req_params - led flashing parameter + * @reqId: request id + * @pattern_id: pattern identifier. 0: disconnected 1: connected + * @led_x0: led flashing parameter0 + * @led_x1: led flashing parameter1 + */ +struct flashing_req_params { + uint32_t req_id; + uint32_t pattern_id; + uint32_t led_x0; + uint32_t led_x1; +}; + +#define MAX_MEM_CHUNKS 32 +/** + * struct wmi_host_mem_chunk - host memory chunk structure + * @vaddr: Pointer to virtual address + * @paddr: Physical address + * @memctx: qdf memory context for mapped address. + * @len: length of chunk + * @req_id: request id from target + */ +struct wmi_host_mem_chunk { + uint32_t *vaddr; + uint32_t paddr; + qdf_dma_mem_context(memctx); + uint32_t len; + uint32_t req_id; +}; + +/** + * struct target_resource_config - Resource config given to target + * This structure is union of wmi_resource_config defined + * by both TLV and non-TLV target. + */ +struct target_resource_config { + uint32_t num_vdevs; + uint32_t num_peers; + uint32_t num_active_peers; + uint32_t num_offload_peers; + uint32_t num_offload_reorder_buffs; + uint32_t num_peer_keys; + uint32_t num_tids; + uint32_t ast_skid_limit; + uint32_t tx_chain_mask; + uint32_t rx_chain_mask; + uint32_t rx_timeout_pri[4]; + uint32_t rx_decap_mode; + uint32_t scan_max_pending_req; + uint32_t bmiss_offload_max_vdev; + uint32_t roam_offload_max_vdev; + uint32_t roam_offload_max_ap_profiles; + uint32_t num_mcast_groups; + uint32_t num_mcast_table_elems; + uint32_t mcast2ucast_mode; + uint32_t tx_dbg_log_size; + uint32_t num_wds_entries; + uint32_t dma_burst_size; + uint32_t mac_aggr_delim; + uint32_t rx_skip_defrag_timeout_dup_detection_check; + uint32_t vow_config; + uint32_t gtk_offload_max_vdev; + uint32_t num_msdu_desc; /* Number of msdu desc */ + uint32_t max_frag_entries; + /* End common */ + + /* Added in MCL */ + uint32_t num_tdls_vdevs; + uint32_t num_tdls_conn_table_entries; + uint32_t beacon_tx_offload_max_vdev; + uint32_t num_multicast_filter_entries; + uint32_t num_wow_filters; + uint32_t num_keep_alive_pattern; + uint32_t keep_alive_pattern_size; + uint32_t max_tdls_concurrent_sleep_sta; + uint32_t max_tdls_concurrent_buffer_sta; + uint32_t wmi_send_separate; + uint32_t num_ocb_vdevs; + uint32_t num_ocb_channels; + uint32_t num_ocb_schedules; +}; + +/** + * struct wmi_wifi_start_log - Structure to store the params sent to start/ + * stop logging + * @name: Attribute which indicates the type of logging like per packet + * statistics, connectivity etc. + * @verbose_level: Verbose level which can be 0,1,2,3 + * @flag: Flag field for future use + */ +struct wmi_wifi_start_log { + uint32_t ring_id; + uint32_t verbose_level; + uint32_t flag; +}; + +/** + * struct wmi_pcl_list - Format of PCL + * @pcl_list: List of preferred channels + * @weight_list: Weights of the PCL + * @pcl_len: Number of channels in the PCL + */ +struct wmi_pcl_list { + uint8_t pcl_list[128]; + uint8_t weight_list[128]; + uint32_t pcl_len; +}; + +/** + * struct wmi_pcl_chan_weights - Params to get the valid weighed list + * @pcl_list: Preferred channel list already sorted in the order of preference + * @pcl_len: Length of the PCL + * @saved_chan_list: Valid channel list updated as part of + * WMA_UPDATE_CHAN_LIST_REQ + * @saved_num_chan: Length of the valid channel list + * @weighed_valid_list: Weights of the valid channel list. This will have one + * to one mapping with valid_chan_list. FW expects channel order and size to be + * as per the list provided in WMI_SCAN_CHAN_LIST_CMDID. + * @weight_list: Weights assigned by policy manager + */ +struct wmi_pcl_chan_weights { + uint8_t pcl_list[MAX_NUM_CHAN]; + uint32_t pcl_len; + uint8_t saved_chan_list[MAX_NUM_CHAN]; + uint32_t saved_num_chan; + uint8_t weighed_valid_list[MAX_NUM_CHAN]; + uint8_t weight_list[MAX_NUM_CHAN]; +}; + +/** + * struct wmi_hw_mode_params - HW mode params + * @mac0_tx_ss: MAC0 Tx spatial stream + * @mac0_rx_ss: MAC0 Rx spatial stream + * @mac1_tx_ss: MAC1 Tx spatial stream + * @mac1_rx_ss: MAC1 Rx spatial stream + * @mac0_bw: MAC0 bandwidth + * @mac1_bw: MAC1 bandwidth + * @dbs_cap: DBS capabality + * @agile_dfs_cap: Agile DFS capabality + */ +struct wmi_hw_mode_params { + uint8_t mac0_tx_ss; + uint8_t mac0_rx_ss; + uint8_t mac1_tx_ss; + uint8_t mac1_rx_ss; + uint8_t mac0_bw; + uint8_t mac1_bw; + uint8_t dbs_cap; + uint8_t agile_dfs_cap; +}; + +/** + * struct wmi_dual_mac_config - Dual MAC configuration + * @scan_config: Scan configuration + * @fw_mode_config: FW mode configuration + * @set_dual_mac_cb: Callback function to be executed on response to the command + */ +struct wmi_dual_mac_config { + uint32_t scan_config; + uint32_t fw_mode_config; + void *set_dual_mac_cb; +}; + +#ifdef WLAN_NS_OFFLOAD +/** + * struct ns_offload_req_params - ns offload request paramter + * @srcIPv6Addr: src ipv6 address + * @selfIPv6Addr: self ipv6 address + * @targetIPv6Addr: target ipv6 address + * @self_macaddr: self mac address + * @srcIPv6AddrValid: src ipv6 address valid flag + * @targetIPv6AddrValid: target ipv6 address valid flag + * @target_ipv6_addr_ac_type: target ipv6 address type + * @slotIdx: slot index + */ +struct ns_offload_req_params { + uint8_t srcIPv6Addr[WMI_MAC_IPV6_ADDR_LEN]; + uint8_t selfIPv6Addr[WMI_MAC_NUM_TARGET_IPV6_NS_OFFLOAD_NA][WMI_MAC_IPV6_ADDR_LEN]; + uint8_t targetIPv6Addr[WMI_MAC_NUM_TARGET_IPV6_NS_OFFLOAD_NA][WMI_MAC_IPV6_ADDR_LEN]; + struct qdf_mac_addr self_macaddr; + uint8_t srcIPv6AddrValid; + uint8_t targetIPv6AddrValid[WMI_MAC_NUM_TARGET_IPV6_NS_OFFLOAD_NA]; + uint8_t target_ipv6_addr_ac_type[WMI_MAC_NUM_TARGET_IPV6_NS_OFFLOAD_NA]; + uint8_t slotIdx; +}; +#endif /* WLAN_NS_OFFLOAD */ + +/** + * struct host_offload_req_param - arp offload parameter + * @offloadType: offload type + * @enableOrDisable: enable or disable + * @num_ns_offload_count: offload count + */ +struct host_offload_req_param { + uint8_t offloadType; + uint8_t enableOrDisable; + uint32_t num_ns_offload_count; + union { + uint8_t hostIpv4Addr[WMI_IPV4_ADDR_LEN]; + uint8_t hostIpv6Addr[WMI_MAC_IPV6_ADDR_LEN]; + } params; +#ifdef WLAN_NS_OFFLOAD + struct ns_offload_req_params nsOffloadInfo; +#endif /* WLAN_NS_OFFLOAD */ + struct qdf_mac_addr bssid; +}; + +/** + * struct ssid_hotlist_param - param for SSID Hotlist + * @ssid: SSID which is being hotlisted + * @band: Band in which the given SSID should be scanned + * @rssi_low: Low bound on RSSI + * @rssi_high: High bound on RSSI + */ +struct ssid_hotlist_param { + struct mac_ssid ssid; + uint8_t band; + int32_t rssi_low; + int32_t rssi_high; +}; + +/** + * struct roam_scan_filter_params - Structure holding roaming scan + * parameters + * @op_bitmap: bitmap to determine reason of roaming + * @session_id: vdev id + * @num_bssid_black_list: The number of BSSID's that we should + * avoid connecting to. It is like a + * blacklist of BSSID's. + * @num_ssid_white_list: The number of SSID profiles that are + * in the Whitelist. When roaming, we + * consider the BSSID's with this SSID + * also for roaming apart from the connected one's + * @num_bssid_preferred_list: Number of BSSID's which have a preference over + * others + * @bssid_avoid_list: Blacklist SSID's + * @ssid_allowed_list: Whitelist SSID's + * @bssid_favored: Favorable BSSID's + * @bssid_favored_factor: RSSI to be added to this BSSID to prefer it + * + * This structure holds all the key parameters related to + * initial connection and roaming connections. + */ + +struct roam_scan_filter_params { + uint32_t op_bitmap; + uint8_t session_id; + uint32_t num_bssid_black_list; + uint32_t num_ssid_white_list; + uint32_t num_bssid_preferred_list; + struct qdf_mac_addr bssid_avoid_list[MAX_BSSID_AVOID_LIST]; + struct mac_ssid ssid_allowed_list[MAX_SSID_ALLOWED_LIST]; + struct qdf_mac_addr bssid_favored[MAX_BSSID_FAVORED]; + uint8_t bssid_favored_factor[MAX_BSSID_FAVORED]; +}; + +/** + * struct ssid_hotlist_request_params - set SSID hotlist request struct + * @request_id: ID of the request + * @session_id: ID of the session + * @lost_ssid_sample_size: Number of consecutive scans in which the SSID + * must not be seen in order to consider the SSID "lost" + * @ssid_count: Number of valid entries in the @ssids array + * @ssids: Array that defines the SSIDs that are in the hotlist + */ +struct ssid_hotlist_request_params { + uint32_t request_id; + uint8_t session_id; + uint32_t lost_ssid_sample_size; + uint32_t ssid_count; + struct ssid_hotlist_param ssids[WMI_EXTSCAN_MAX_HOTLIST_SSIDS]; +}; + +/** + * struct wmi_unit_test_cmd - unit test command parameters + * @vdev_id: vdev id + * @module_id: module id + * @num_args: number of arguments + * @args: arguments + */ +struct wmi_unit_test_cmd { + uint32_t vdev_id; + uint32_t module_id; + uint32_t num_args; + uint32_t args[WMI_MAX_NUM_ARGS]; +}; + +/** + * struct wmi_roam_invoke_cmd - roam invoke command + * @vdev_id: vdev id + * @bssid: mac address + * @channel: channel + * @frame_len: frame length, includs mac header, fixed params and ies + * @frame_buf: buffer contaning probe response or beacon + */ +struct wmi_roam_invoke_cmd { + uint32_t vdev_id; + uint8_t bssid[IEEE80211_ADDR_LEN]; + uint32_t channel; + uint32_t frame_len; + uint8_t *frame_buf; +}; + +/** + * struct ext_scan_setbssi_hotlist_params - set hotlist request + * @requestId: request identifier + * @sessionId: session identifier + * @lost_ap_sample_size: number of samples to confirm AP loss + * @numAp: Number of hotlist APs + * @ap: hotlist APs + */ +struct ext_scan_setbssi_hotlist_params { + uint32_t requestId; + uint8_t sessionId; + + uint32_t lost_ap_sample_size; + uint32_t numAp; + struct ap_threshold_params ap[WMI_WLAN_EXTSCAN_MAX_HOTLIST_APS]; +}; + +/** + * struct TARGET_HAL_REG_CAPABILITIES - This is replication of REG table + * structure defined by target. This is added here to remove dependency + * on FW headers so that host can be agnostic to different defintions in + * both the targets. + */ +typedef struct { + uint32_t eeprom_rd; /* regdomain value specified in EEPROM */ + uint32_t eeprom_rd_ext; /* regdomain */ + uint32_t regcap1; /* CAP1 capabilities bit map */ + uint32_t regcap2; /* REGDMN EEPROM CAP */ + uint32_t wireless_modes; /* REGDMN MODE */ + uint32_t low_2ghz_chan; + uint32_t high_2ghz_chan; + uint32_t low_5ghz_chan; + uint32_t high_5ghz_chan; +} TARGET_HAL_REG_CAPABILITIES; + +/** + * struct host_mem_req - Host memory request paramseters request by target + * @req_id: Request id to identify the request. + * @unit_size: Size of single unit requested. + * @num_unit_info: Memory chunk info + * @num_units: number of units requested. + */ +typedef struct { + uint32_t req_id; + uint32_t unit_size; + uint32_t num_unit_info; + uint32_t num_units; +} host_mem_req; + +#define WMI_HOST_DSCP_MAP_MAX (64) + +/** + * struct wmi_host_ext_resource_config - Extended resource config + * @host_platform_config: Host plaform configuration. + * @fw_featuew_bitmap: FW feature requested bitmap. + */ +typedef struct { + uint32_t host_platform_config; + +#define WMI_HOST_FW_FEATURE_LTEU_SUPPORT 0x0001 +#define WMI_HOST_FW_FEATURE_COEX_GPIO_SUPPORT 0x0002 +#define WMI_HOST_FW_FEATURE_AUX_RADIO_SPECTRAL_INTF 0x0004 +#define WMI_HOST_FW_FEATURE_AUX_RADIO_CHAN_LOAD_INTF 0x0008 +#define WMI_HOST_FW_FEATURE_BSS_CHANNEL_INFO_64 0x0010 +#define WMI_HOST_FW_FEATURE_PEER_STATS 0x0020 +#define WMI_HOST_FW_FEATURE_VDEV_STATS 0x0040 + /** + * @brief fw_feature_bitmask - Enable/Disable features in FW + * @details + * The bits in fw_feature_bitmask are used as shown by the masks below: + * 0x0001 - LTEU Config enable/disable + * 0x0002 - COEX GPIO Config enable/disable + * 0x0004 - Aux Radio enhancement for spectral scan enable/disable + * 0x0008 - Aux Radio enhancement for chan load scan enable/disable + * 0x0010 - BSS channel info stats enable/disable + * The features in question are enabled by setting + * the feature's bit to 1, + * or disabled by setting the feature's bit to 0. + */ + uint32_t fw_feature_bitmap; + + /* add new members here */ +} wmi_host_ext_resource_config; + +/** + * struct set_neighbour_rx_params - Neighbour RX params + * @vdev_id: vdev id + * @idx: index of param + * @action: action + * @type: Type of param + */ +struct set_neighbour_rx_params { + uint8_t vdev_id; + uint32_t idx; + uint32_t action; + uint32_t type; +}; + +/** + * struct set_fwtest_params - FW test params + * @arg: FW param id + * @value: value + */ +struct set_fwtest_params { + uint32_t arg; + uint32_t value; +}; + +/** + * struct config_ratemask_params - ratemask config parameters + * @vdev_id: vdev id + * @type: Type + * @lower32: Lower 32 bits + * @higher32: Hogher 32 bits + */ +struct config_ratemask_params { + uint8_t vdev_id; + uint8_t type; + uint32_t lower32; + uint32_t higher32; +}; + +/** + * struct peer_add_wds_entry_params - WDS peer entry add params + * @dest_addr: Pointer to destination macaddr + * @peer_addr: Pointer to peer mac addr + * @flags: flags + */ +struct peer_add_wds_entry_params { + const uint8_t *dest_addr; + uint8_t *peer_addr; + uint32_t flags; +}; + +/** + * struct peer_del_wds_entry_params - WDS peer entry del params + * @dest_addr: Pointer to destination macaddr + */ +struct peer_del_wds_entry_params { + uint8_t *dest_addr; +}; + +/** + * struct peer_updatewds_entry_params - WDS peer entry update params + * @wds_macaddr: Pointer to destination macaddr + * @peer_add: Pointer to peer mac addr + * @flags: flags + */ +struct peer_update_wds_entry_params { + uint8_t *wds_macaddr; + uint8_t *peer_macaddr; + uint32_t flags; +}; + +/** + * struct set_ps_mode_params - PS mode params + * @vdev_id: vdev id + * @psmode: PS mode + */ +struct set_ps_mode_params { + uint8_t vdev_id; + uint8_t psmode; +}; + +/** + * @struct tt_level_config - Set Thermal throttlling config + * @tmplwm: Temperature low water mark + * @tmphwm: Temperature high water mark + * @dcoffpercent: dc off percentage + * @priority: priority + */ +typedef struct { + uint32_t tmplwm; + uint32_t tmphwm; + uint32_t dcoffpercent; + uint32_t priority; +} tt_level_config; + +/** + * struct thermal_mitigation_params - Thermal mitigation params + * @enable: Enable/Disable Thermal mitigation + * @dc: DC + * @dc_per_event: DC per event + * @tt_level_config: TT level config params + */ +struct thermal_mitigation_params { + uint32_t enable; + uint32_t dc; + uint32_t dc_per_event; + tt_level_config levelconf[THERMAL_LEVELS]; +}; + +/** + * struct smart_ant_enable_params - Smart antenna params + * @enable: Enable/Disable + * @mode: SA mode + * @rx_antenna: RX antenna config + * @gpio_pin : GPIO pin config + * @gpio_func : GPIO function config + */ +struct smart_ant_enable_params { + uint32_t enable; + uint32_t mode; + uint32_t rx_antenna; + uint32_t gpio_pin[WMI_HAL_MAX_SANTENNA]; + uint32_t gpio_func[WMI_HAL_MAX_SANTENNA]; +}; + +/** + * struct smart_ant_rx_ant_params - RX antenna params + * @antenna: RX antenna + */ +struct smart_ant_rx_ant_params { + uint32_t antenna; +}; + +/** + * struct smart_ant_tx_ant_params - TX antenna param + * @antenna_array: Antenna arry + * @vdev_id: VDEV id + */ +struct smart_ant_tx_ant_params { + uint32_t *antenna_array; + uint8_t vdev_id; +}; + +/** + * struct smart_ant_training_info_params - SA training params + * @vdev_id: VDEV id + * @rate_array: Rates array + * @antenna_array: Antenna array + * @numpkts: num packets for training + */ +struct smart_ant_training_info_params { + uint8_t vdev_id; + uint32_t *rate_array; + uint32_t *antenna_array; + uint32_t numpkts; +}; + +/** + * struct smart_ant_node_config_params - SA node config params + * @vdev_id: VDEV id + * @cmd_id: Command id + * @args_count: Arguments count + */ +struct smart_ant_node_config_params { + uint8_t vdev_id; + uint32_t cmd_id; + uint16_t args_count; + uint32_t *args_arr; +}; +/** + * struct smart_ant_enable_tx_feedback_params - SA tx feeback params + * @enable: Enable TX feedback for SA + */ +struct smart_ant_enable_tx_feedback_params { + int enable; +}; + +/** + * struct vdev_spectral_configure_params - SPectral config params + * @vdev_id: VDEV id + * @count: count + * @period: period + * @spectral_pri: Spectral priority + * @fft_size: FFT size + * @gc_enable: GC enable + * @restart_enable: restart enabled + * @noise_floor_ref: Noise floor reference + * @init_delay: Init delays + * @nb_tone_thr: NB tone threshold + * @str_bin_thr: STR BIN threshold + * @wb_rpt_mode: WB BIN threshold + * @rssi_rpt_mode: RSSI report mode + * @rssi_thr: RSSI threshold + * @pwr_format: Power format + * @rpt_mode: Report mdoe + * @bin_scale: BIN scale + * @dBm_adj: DBM adjust + * @chn_mask: chain mask + */ +struct vdev_spectral_configure_params { + uint8_t vdev_id; + uint16_t count; + uint16_t period; + uint16_t spectral_pri; + uint16_t fft_size; + uint16_t gc_enable; + uint16_t restart_enable; + uint16_t noise_floor_ref; + uint16_t init_delay; + uint16_t nb_tone_thr; + uint16_t str_bin_thr; + uint16_t wb_rpt_mode; + uint16_t rssi_rpt_mode; + uint16_t rssi_thr; + uint16_t pwr_format; + uint16_t rpt_mode; + uint16_t bin_scale; + uint16_t dBm_adj; + uint16_t chn_mask; +}; + +/** + * struct vdev_spectral_enable_params - Spectral enabled params + * @vdev_id: VDEV id + * @active_valid: Active valid + * @active: active + * @enabled_valid: Enabled valid + * @enabled: enabled + */ +struct vdev_spectral_enable_params { + uint8_t vdev_id; + uint8_t active_valid; + uint8_t active; + uint8_t enabled_valid; + uint8_t enabled; +}; + +/** + * struct pdev_set_regdomain_params - PDEV set reg domain params + * @currentRDinuse: Current Reg domain + * @currentRD2G: Current Reg domain 2G + * @currentRD5G: Current Reg domain 5G + * @ctl_2G: CTL 2G + * @ctl_5G: CTL 5G + * @dfsDomain: DFS domain + */ +struct pdev_set_regdomain_params { + uint16_t currentRDinuse; + uint16_t currentRD2G; + uint16_t currentRD5G; + uint32_t ctl_2G; + uint32_t ctl_5G; + uint8_t dfsDomain; +}; + +/** + * struct set_quiet_mode_params - Set quiet mode params + * @enabled: Enabled + * @period: Quite period + * @intval: Quite interval + * @duration: Quite duration + * @offset: offset + */ +struct set_quiet_mode_params { + uint8_t enabled; + uint8_t period; + uint16_t intval; + uint16_t duration; + uint16_t offset; +}; + +/** + * struct set_beacon_filter_params - Set beacon filter params + * @vdev_id: VDEV id + * @ie: Pointer to IE fields + */ +struct set_beacon_filter_params { + uint8_t vdev_id; + uint32_t *ie; +}; + +/** + * struct remove_beacon_filter_params - Remove beacon filter params + * @vdev_id: VDEV id + */ +struct remove_beacon_filter_params { + uint8_t vdev_id; +}; + +/** + * struct mgmt_params - Mgmt params + * @vdev_id: vdev id + * @buf_len: lenght of frame buffer + * @wbuf: frame buffer + */ +struct mgmt_params { + int vdev_id; + uint32_t buf_len; + qdf_nbuf_t wbuf; +}; + +/** + * struct addba_clearresponse_params - Addba clear response params + * @vdev_id: VDEV id + */ +struct addba_clearresponse_params { + uint8_t vdev_id; +}; + +/** + * struct addba_send_params - ADDBA send params + * @vdev_id: vdev id + * @tidno: TID + * @buffersize: buffer size + */ +struct addba_send_params { + uint8_t vdev_id; + uint8_t tidno; + uint16_t buffersize; +}; + +/** + * struct delba_send_params - DELBA send params + * @vdev_id: vdev id + * @tidno: TID + * @initiator: initiator + * @reasoncode: reason code + */ +struct delba_send_params { + uint8_t vdev_id; + uint8_t tidno; + uint8_t initiator; + uint16_t reasoncode; +}; +/** + * struct addba_setresponse_arams - Set ADDBA response params + * @vdev_id: vdev id + * @tidno: TID + * @statuscode: status code in response + */ +struct addba_setresponse_params { + uint8_t vdev_id; + uint8_t tidno; + uint16_t statuscode; +}; + +/** + * struct singleamsdu_params - Single AMSDU params + * @vdev_id: vdev is + * @tidno: TID + */ +struct singleamsdu_params { + uint8_t vdev_id; + uint8_t tidno; +}; + +/** + * struct set_qbosst_params - Set QBOOST params + * @vdev_id: vdev id + * @value: value + */ +struct set_qboost_params { + uint8_t vdev_id; + uint32_t value; +}; + +/** + * struct mu_scan_params - MU scan params + * @id: id + * @type: type + * @duration: Duration + * @lteu_tx_power: LTEU tx power + */ +struct mu_scan_params { + uint8_t id; + uint8_t type; + uint32_t duration; + uint32_t lteu_tx_power; +}; + +/** + * struct lteu_config_params - LTEU config params + * @lteu_gpio_start: start MU/AP scan after GPIO toggle + * @lteu_num_bins: no. of elements in the following arrays + * @use_actual_nf: whether to use the actual NF obtained or a hardcoded one + * @lteu_weight: weights for MU algo + * @lteu_thresh: thresholds for MU algo + * @lteu_gamma: gamma's for MU algo + * @lteu_scan_timeout: timeout in ms to gpio toggle + * @alpha_num_ssid: alpha for num active bssid calculation + * @wifi_tx_power: Wifi Tx power + */ +struct lteu_config_params { + uint8_t lteu_gpio_start; + uint8_t lteu_num_bins; + uint8_t use_actual_nf; + uint32_t lteu_weight[LTEU_MAX_BINS]; + uint32_t lteu_thresh[LTEU_MAX_BINS]; + uint32_t lteu_gamma[LTEU_MAX_BINS]; + uint32_t lteu_scan_timeout; + uint32_t alpha_num_bssid; + uint32_t wifi_tx_power; +}; + +struct wmi_macaddr_t { + /** upper 4 bytes of MAC address */ + uint32_t mac_addr31to0; + /** lower 2 bytes of MAC address */ + uint32_t mac_addr47to32; +}; + +/** + * struct atf_peer_info - ATF peer info params + * @peer_macaddr: peer mac addr + * @percentage_peer: percentage of air time for this peer + */ +typedef struct { + struct wmi_macaddr_t peer_macaddr; + uint32_t percentage_peer; +} atf_peer_info; + +/** + * struct bwf_peer_info_t - BWF peer info params + * @peer_macaddr: peer mac addr + * @throughput: Throughput + * @max_airtime: Max airtime + * @priority: Priority level + * @reserved: Reserved array + */ +typedef struct { + struct wmi_macaddr_t peer_macaddr; + uint32_t throughput; + uint32_t max_airtime; + uint32_t priority; + uint32_t reserved[4]; +} bwf_peer_info; + +/** + * struct set_bwf_params - BWF params + * @num_peers: number of peers + * @atf_peer_info: BWF peer info + */ +struct set_bwf_params { + uint32_t num_peers; + bwf_peer_info peer_info[1]; +}; + +/** + * struct set_atf_params - ATF params + * @num_peers: number of peers + * @atf_peer_info: ATF peer info + */ +struct set_atf_params { + uint32_t num_peers; + atf_peer_info peer_info[ATF_ACTIVED_MAX_CLIENTS]; +}; + +/** + * struct atf_peer_ext_info - ATF peer ext info params + * @peer_macaddr: peer mac address + * @group_index: group index + * @atf_index_reserved: ATF index rsvd + */ +typedef struct { + struct wmi_macaddr_t peer_macaddr; + uint32_t group_index; + uint32_t atf_index_reserved; +} atf_peer_ext_info; + +/** + * struct atf_peer_request_params - ATF peer req params + * @num_peers: number of peers + * @atf_peer_ext_info: ATF peer ext info + */ +struct atf_peer_request_params { + uint32_t num_peers; + atf_peer_ext_info peer_ext_info[ATF_ACTIVED_MAX_CLIENTS]; +}; + +/** + * struct atf_group_info - ATF group info params + * @percentage_group: Percentage AT for group + * @atf_group_units_reserved: ATF group information + */ +typedef struct { + uint32_t percentage_group; + uint32_t atf_group_units_reserved; +} atf_group_info; + +/** + * struct atf_grouping_params - ATF grouping params + * @num_groups: number of groups + * @group_inf: Group informaition + */ +struct atf_grouping_params { + uint32_t num_groups; + atf_group_info group_info[ATF_ACTIVED_MAX_ATFGROUPS]; +}; + +/** + * struct wlan_profile_params - WLAN profile params + * @param_id: param id + * @profile_id: profile id + * @enable: enable + */ +struct wlan_profile_params { + uint32_t param_id; + uint32_t profile_id; + uint32_t enable; +}; + +/* struct ht_ie_params - HT IE params + * @ie_len: IE length + * @ie_data: pointer to IE data + */ +struct ht_ie_params { + uint32_t ie_len; + uint8_t *ie_data; +}; + +/* struct vht_ie_params - VHT IE params + * @ie_len: IE length + * @ie_data: pointer to IE data + */ +struct vht_ie_params { + uint32_t ie_len; + uint8_t *ie_data; +}; + +/** + * struct wmi_host_wmeParams - WME params + * @wmep_acm: ACM paramete + * @wmep_aifsn: AIFSN parameters + * @wmep_logcwmin: cwmin in exponential form + * @wmep_logcwmax: cwmax in exponential form + * @wmep_txopLimit: txopLimit + * @wmep_noackPolicy: No-Ack Policy: 0=ack, 1=no-ack + */ +struct wmi_host_wmeParams { + u_int8_t wmep_acm; + u_int8_t wmep_aifsn; + u_int8_t wmep_logcwmin; + u_int8_t wmep_logcwmax; + u_int16_t wmep_txopLimit; + u_int8_t wmep_noackPolicy; +}; + +/** + * struct wmm_update_params - WMM update params + * @wmep_array: WME params for each AC + */ +struct wmm_update_params { + struct wmi_host_wmeParams *wmep_array; +}; + +/** + * struct ant_switch_tbl_params - Antenna switch table params + * @ant_ctrl_common1: ANtenna control common param 1 + * @ant_ctrl_common2: Antenna control commn param 2 + */ +struct ant_switch_tbl_params { + uint32_t ant_ctrl_common1; + uint32_t ant_ctrl_common2; +}; + +/** + * struct ratepwr_table_params - Rate power table params + * @ratepwr_tbl: pointer to rate power table + * @ratepwr_len: rate power table len + */ +struct ratepwr_table_params { + uint8_t *ratepwr_tbl; + uint16_t ratepwr_len; +}; + +/** + * struct ctl_table_params - Ctl table params + * @ctl_array: pointer to ctl array + * @ctl_len: ctl length + * @is_acfg_ctl: is acfg_ctl table + */ +struct ctl_table_params { + uint8_t *ctl_array; + uint16_t ctl_len; + bool is_acfg_ctl; +}; + +/** + * struct mimogain_table_params - MIMO gain table params + * @array_gain: pointer to array gain table + * @tbl_len: table length + * @multichain_gain_bypass: bypass multichain gain + */ +struct mimogain_table_params { + uint8_t *array_gain; + uint16_t tbl_len; + bool multichain_gain_bypass; +}; + +/** + * struct ratepwr_chainmask_params - Rate power chainmask params + * @ratepwr_chain_tbl: pointer to ratepwr chain table + * @num_rate: number of rate in table + * @pream_type: preamble type + * @ops: ops + */ +struct ratepwr_chainmsk_params { + uint32_t *ratepwr_chain_tbl; + uint16_t num_rate; + uint8_t pream_type; + uint8_t ops; +}; + +struct macaddr_params { + uint8_t *macaddr; +}; + +/** + * struct acparams_params - acparams config structure + * @ac: AC to configure + * @use_rts: Use rts for this AC + * @aggrsize_scaling: Aggregrate size scaling for the AC + * @min_kbps: min kbps req + */ +struct acparams_params { + uint8_t ac; + uint8_t use_rts; + uint8_t aggrsize_scaling; + uint32_t min_kbps; +}; + +/** + * struct vap_dscp_tid_map_params - DSCP tid map params + * @vdev_id: vdev id + * @dscp_to_tid_map: pointer to arry of tid to dscp map table + */ +struct vap_dscp_tid_map_params { + uint8_t vdev_id; + uint32_t *dscp_to_tid_map; +}; + +/** + * struct proxy_ast_reserve_params - Proxy AST reserve params + * @macaddr: macaddr for proxy ast entry + */ +struct proxy_ast_reserve_params { + uint8_t *macaddr; +}; + +/** + * struct fips_params - FIPS params config + * @key: pointer to key + * @key_len: length of key + * @data: pointer data buf + * @data_len: lenght of sata buf + * @mode: mode + * @op: operation + */ +struct fips_params { + uint8_t *key; + uint32_t key_len; + uint8_t *data; + uint32_t data_len; + uint32_t mode; + uint32_t op; +}; + +/** + * struct mcast_group_update_param - Mcast group table update to target + * @action: Addition/deletion + * @wildcard: iwldcard table entry? + * @mcast_ip_addr: mcast ip address to be updated + * @mcast_ip_addr_bytes: mcast ip addr bytes + * @ucast_mac_addr: ucast peer mac subscribed to mcast ip + * @filter_mode: filter mode + * @nsrcs: number of entries in source list + * @srcs: source mac accpted + * @mask: mask + * @vap_id: vdev id + * @is_action_delete: is delete + * @is_filter_mode_snoop: + * @is_mcast_addr_len: + */ +struct mcast_group_update_params { + int action; + int wildcard; + uint8_t *mcast_ip_addr; + int mcast_ip_addr_bytes; + uint8_t *ucast_mac_addr; + uint8_t filter_mode; + uint8_t nsrcs; + uint8_t *srcs; + uint8_t *mask; + uint8_t vap_id; + bool is_action_delete; + bool is_filter_mode_snoop; + bool is_mcast_addr_len; +}; + +/** + * struct periodic_chan_stats_param - periodic channel stats req param + * @stats_period: stats period update + * @enable: enable/disable + */ +struct periodic_chan_stats_params { + uint32_t stats_period; + bool enable; +}; + +/** + * struct packet_power_info_params - packet power info params + * @rate_flags: rate flags + * @nss: number of spatial streams + * @preamble: preamble + * @hw_rate: + */ +struct packet_power_info_params { + uint16_t rate_flags; + uint16_t nss; + uint16_t preamble; + uint16_t hw_rate; +}; + +/** + * WMI_GPIO_CONFIG_CMDID + */ +enum { + WMI_HOST_GPIO_PULL_NONE, + WMI_HOST_GPIO_PULL_UP, + WMI_HOST_GPIO_PULL_DOWN, +}; + +/** + * WMI_GPIO_INTTYPE + */ +enum { + WMI_HOST_GPIO_INTTYPE_DISABLE, + WMI_HOST_GPIO_INTTYPE_RISING_EDGE, + WMI_HOST_GPIO_INTTYPE_FALLING_EDGE, + WMI_HOST_GPIO_INTTYPE_BOTH_EDGE, + WMI_HOST_GPIO_INTTYPE_LEVEL_LOW, + WMI_HOST_GPIO_INTTYPE_LEVEL_HIGH +}; + +/** + * struct wmi_host_gpio_input_event - GPIO input event structure + * @gpio_num: GPIO number which changed state + */ +typedef struct { + uint32_t gpio_num; /* GPIO number which changed state */ +} wmi_host_gpio_input_event; + +/** + * struct gpio_config_params - GPIO config params + * @gpio_num: GPIO number to config + * @input: input/output + * @pull_type: pull type + * @intr_mode: int mode + */ +struct gpio_config_params { + uint32_t gpio_num; + uint32_t input; + uint32_t pull_type; + uint32_t intr_mode; +}; + +/** + * struct gpio_output_params - GPIO output params + * @gpio_num: GPIO number to configure + * @set: set/reset + */ +struct gpio_output_params { + uint32_t gpio_num; + uint32_t set; +}; + +#define WMI_HOST_RTT_REPORT_CFR 0 +#define WMI_HOST_RTT_NO_REPORT_CFR 1 +#define WMI_HOST_RTT_AGGREGATE_REPORT_NON_CFR 2 +/** + * struct rtt_meas_req_test_params + * @peer: peer mac address + * @req_frame_type: RTT request frame type + * @req_bw: requested bandwidth + * @req_preamble: Preamble + * @req_num_req: num of requests + * @req_report_type: report type + * @num_measurements: number of measurements + * @asap_mode: priority + * @lci_requested: LCI requested + * @loc_civ_requested: + * @channel_param: channel param + * @req_id: requested id + */ +struct rtt_meas_req_test_params { + uint8_t peer[IEEE80211_ADDR_LEN]; + int req_frame_type; + int req_bw; + int req_preamble; + int req_num_req; + int req_report_type; + uint32_t num_measurements; + uint32_t asap_mode; + uint32_t lci_requested; + uint32_t loc_civ_requested; + struct channel_param channel; + uint8_t req_id; +}; + +/** + * struct rtt_meas_req_params - RTT measurement request params + * @req_id: Request id + * @vdev_id: vdev id + * @sta_mac_addr: pointer to station mac address + * @spoof_mac_addr: pointer to spoof mac address + * @is_mode_na: 11NA + * @is_mode_ac: AC + * @is_bw_20: 20 + * @is_bw_40: 40 + * @is_bw_80: 80 + * @num_probe_rqst: number of probe request + * @channel_param: channel param + */ +struct rtt_meas_req_params { + uint8_t req_id; + uint8_t vdev_id; + uint8_t *sta_mac_addr; + uint8_t *spoof_mac_addr; + bool is_mode_na; + bool is_mode_ac; + bool is_bw_20; + bool is_bw_40; + bool is_bw_80; + uint32_t num_probe_rqst; + struct channel_param channel; +}; + +/** + * struct lci_set_params - LCI params + * @lci_data: pointer to LCI data + * @latitude_unc: latitude + * @latitude_0_12: bits 0 to 1 of latitude + * @latitude_2_33: bits 2 to 33 of latitude + * @longitude_unc: longitude + * @longitude_0_1: bits 0 to 1 of longitude + * @longitude_2_33: bits 2 to 33 of longitude + * @altitude_type: altitude type + * @altitude_unc_0_3: altitude bits 0 - 3 + * @altitude_unc_4_5: altitude bits 4 - 5 + * @altitude: altitude + * @datum: dataum + * @reg_loc_agmt: + * @reg_loc_dse: + * @dep_sta: + * @version: version + */ +struct lci_set_params { + void *lci_data; + uint8_t latitude_unc:6, + latitude_0_1:2; + uint32_t latitude_2_33; + uint8_t longitude_unc:6, + longitude_0_1:2; + uint32_t longitude_2_33; + uint8_t altitude_type:4, + altitude_unc_0_3:4; + uint32_t altitude_unc_4_5:2, + altitude:30; + uint8_t datum:3, + reg_loc_agmt:1, + reg_loc_dse:1, + dep_sta:1, + version:2; +}; + +/** + * struct lcr_set_params - LCR params + * @lcr_data: pointer to lcr data + */ +struct lcr_set_params { + void *lcr_data; +}; + +/** + * struct rtt_keepalive_req_params - RTT keepalive params + * @macaddr: pointer to macaddress + * @req_id: Request id + * @vdev_id: vdev id + * @stop: start/stop + */ +struct rtt_keepalive_req_params { + uint8_t *macaddr; + uint8_t req_id; + uint8_t vdev_id; + bool stop; +}; + +/** + * struct wmi_host_stats_event - Stats event params + * @stats_id: stats id of type wmi_host_stats_event + * @num_pdev_stats: number of pdev stats event structures 0 or 1 + * @num_pdev_ext_stats: number of pdev ext stats event structures + * @num_vdev_stats: number of vdev stats + * @num_peer_stats: number of peer stats event structures 0 or max peers + * @num_bcnflt_stats: number of beacon filter stats + * @num_chan_stats: number of channel stats + */ +typedef struct { + wmi_host_stats_id stats_id; + uint32_t num_pdev_stats; + uint32_t num_pdev_ext_stats; + uint32_t num_vdev_stats; + uint32_t num_peer_stats; + uint32_t num_bcnflt_stats; + uint32_t num_chan_stats; +} wmi_host_stats_event; + +/** + * struct wmi_host_peer_extd_stats - peer extd stats event structure + * @peer_macaddr: Peer mac address + * @inactive_time: inactive time in secs + * @peer_chain_rssi: peer rssi + * @rx_duration: RX duration + * @peer_tx_bytes: TX bytes + * @peer_rx_bytes: RX bytes + * @last_tx_rate_code: Tx rate code of last frame + * @last_tx_power: Tx power latest + * @atf_tokens_allocated: atf tokens allocated + * @atf_tokens_utilized: atf tokens utilized + * @reserved: for future use + */ +typedef struct { + wmi_host_mac_addr peer_macaddr; + uint32_t inactive_time; + uint32_t peer_chain_rssi; + uint32_t rx_duration; + uint32_t peer_tx_bytes; + uint32_t peer_rx_bytes; + uint32_t last_tx_rate_code; + uint32_t last_tx_power; + uint32_t atf_tokens_allocated; + uint32_t atf_tokens_utilized; + uint32_t reserved[4]; +} wmi_host_peer_extd_stats; + +/** + * struct wmi_host_pdev_ext_stats - peer ext stats structure + * @rx_rssi_comb: RX rssi + * @rx_rssi_chain0: RX rssi chain 0 + * @rx_rssi_chain1: RX rssi chain 1 + * @rx_rssi_chain2: RX rssi chain 2 + * @rx_rssi_chain3: RX rssi chain 3 + * @rx_mcs: RX MCS array + * @tx_mcs: TX MCS array + * @ack_rssi: Ack rssi + */ +typedef struct { + uint32_t rx_rssi_comb; + uint32_t rx_rssi_chain0; + uint32_t rx_rssi_chain1; + uint32_t rx_rssi_chain2; + uint32_t rx_rssi_chain3; + uint32_t rx_mcs[10]; + uint32_t tx_mcs[10]; + uint32_t ack_rssi; +} wmi_host_pdev_ext_stats; + +/** + * struct wmi_host_dbg_tx_stats - Debug stats + * @comp_queued: Num HTT cookies queued to dispatch list + * @comp_delivered: Num HTT cookies dispatched + * @msdu_enqued: Num MSDU queued to WAL + * @mpdu_enqued: Num MPDU queue to WAL + * @wmm_drop: Num MSDUs dropped by WMM limit + * @local_enqued: Num Local frames queued + * @local_freed: Num Local frames done + * @hw_queued: Num queued to HW + * @hw_reaped: Num PPDU reaped from HW + * @underrun: Num underruns + * @hw_paused: HW Paused. + * @tx_abort: Num PPDUs cleaned up in TX abort + * @mpdus_requed: Num MPDUs requed by SW + * @tx_ko: excessive retries + * @tx_xretry: + * @data_rc: data hw rate code + * @self_triggers: Scheduler self triggers + * @sw_retry_failure: frames dropped due to excessive sw retries + * @illgl_rate_phy_err: illegal rate phy errors + * @pdev_cont_xretry: wal pdev continous xretry + * @pdev_tx_timeout: wal pdev continous xretry + * @pdev_resets: wal pdev resets + * @stateless_tid_alloc_failure: frames dropped due to non-availability of + * stateless TIDs + * @phy_underrun: PhY/BB underrun + * @txop_ovf: MPDU is more than txop limit + * @seq_posted: Number of Sequences posted + * @seq_failed_queueing: Number of Sequences failed queueing + * @seq_completed: Number of Sequences completed + * @seq_restarted: Number of Sequences restarted + * @mu_seq_posted: Number of MU Sequences posted + * @mpdus_sw_flush: Num MPDUs flushed by SW, HWPAUSED, SW TXABORT + * (Reset,channel change) + * @mpdus_hw_filter: Num MPDUs filtered by HW, all filter condition + * (TTL expired) + * @mpdus_truncated: Num MPDUs truncated by PDG (TXOP, TBTT, + * PPDU_duration based on rate, dyn_bw) + * @mpdus_ack_failed: Num MPDUs that was tried but didn't receive ACK or BA + * @mpdus_expired: Num MPDUs that was dropped du to expiry. + * @mc_dropr: Num mc drops + */ +typedef struct { + int32_t comp_queued; + int32_t comp_delivered; + int32_t msdu_enqued; + int32_t mpdu_enqued; + int32_t wmm_drop; + int32_t local_enqued; + int32_t local_freed; + int32_t hw_queued; + int32_t hw_reaped; + int32_t underrun; + uint32_t hw_paused; + int32_t tx_abort; + int32_t mpdus_requed; + uint32_t tx_ko; + uint32_t tx_xretry; + uint32_t data_rc; + uint32_t self_triggers; + uint32_t sw_retry_failure; + uint32_t illgl_rate_phy_err; + uint32_t pdev_cont_xretry; + uint32_t pdev_tx_timeout; + uint32_t pdev_resets; + uint32_t stateless_tid_alloc_failure; + uint32_t phy_underrun; + uint32_t txop_ovf; + uint32_t seq_posted; + uint32_t seq_failed_queueing; + uint32_t seq_completed; + uint32_t seq_restarted; + uint32_t mu_seq_posted; + int32_t mpdus_sw_flush; + int32_t mpdus_hw_filter; + int32_t mpdus_truncated; + int32_t mpdus_ack_failed; + int32_t mpdus_expired; + uint32_t mc_drop; +} wmi_host_dbg_tx_stats; + +/** + * struct wmi_host_dbg_rx_stats - RX Debug stats + * @mid_ppdu_route_change: Cnts any change in ring routing mid-ppdu + * @status_rcvd: Total number of statuses processed + * @r0_frags: Extra frags on rings 0 + * @r1_frags: Extra frags on rings 1 + * @r2_frags: Extra frags on rings 2 + * @r3_frags: Extra frags on rings 3 + * @htt_msdus: MSDUs delivered to HTT + * @htt_mpdus: MPDUs delivered to HTT + * @loc_msdus: MSDUs delivered to local stack + * @loc_mpdus: MPDUS delivered to local stack + * @oversize_amsdu: AMSDUs that have more MSDUs than the status ring size + * @phy_errs: Number of PHY errors + * @phy_err_drop: Number of PHY errors drops + * @mpdu_errs: Number of mpdu errors - FCS, MIC, ENC etc. + * @pdev_rx_timeout: Number of rx inactivity timeouts + * @rx_ovfl_errs: Number of rx overflow errors. + */ +typedef struct { + int32_t mid_ppdu_route_change; + int32_t status_rcvd; + int32_t r0_frags; + int32_t r1_frags; + int32_t r2_frags; + int32_t r3_frags; + int32_t htt_msdus; + int32_t htt_mpdus; + int32_t loc_msdus; + int32_t loc_mpdus; + int32_t oversize_amsdu; + int32_t phy_errs; + int32_t phy_err_drop; + int32_t mpdu_errs; + uint32_t pdev_rx_timeout; + int32_t rx_ovfl_errs; +} wmi_host_dbg_rx_stats; + +/** struct wmi_host_dbg_mem_stats - memory stats + * @iram_free_size: IRAM free size on target + * @dram_free_size: DRAM free size on target + * @sram_free_size: SRAM free size on target + */ +typedef struct { + uint32_t iram_free_size; + uint32_t dram_free_size; + /* Only Non-TLV */ + uint32_t sram_free_size; +} wmi_host_dbg_mem_stats; + +typedef struct { + /* Only TLV */ + int32_t dummy;/* REMOVE THIS ONCE REAL PEER STAT COUNTERS ARE ADDED */ +} wmi_host_dbg_peer_stats; + +/** + * struct wmi_host_dbg_stats - host debug stats + * @tx: TX stats of type wmi_host_dbg_tx_stats + * @rx: RX stats of type wmi_host_dbg_rx_stats + * @mem: Memory stats of type wmi_host_dbg_mem_stats + * @peer: peer stats of type wmi_host_dbg_peer_stats + */ +typedef struct { + wmi_host_dbg_tx_stats tx; + wmi_host_dbg_rx_stats rx; + wmi_host_dbg_mem_stats mem; + wmi_host_dbg_peer_stats peer; +} wmi_host_dbg_stats; + +/** + * struct wmi_host_pdev_stats - PDEV stats + * @chan_nf: Channel noise floor + * @tx_frame_count: TX frame count + * @rx_frame_count: RX frame count + * @rx_clear_count: rx clear count + * @cycle_count: cycle count + * @phy_err_count: Phy error count + * @chan_tx_pwr: Channel Tx Power + * @pdev_stats: WAL dbg stats + * @ackRcvBad: + * @rtsBad: + * @rtsGood: + * @fcsBad: + * @noBeacons: + * @mib_int_count: + */ +typedef struct { + int32_t chan_nf; + uint32_t tx_frame_count; + uint32_t rx_frame_count; + uint32_t rx_clear_count; + uint32_t cycle_count; + uint32_t phy_err_count; + uint32_t chan_tx_pwr; + wmi_host_dbg_stats pdev_stats; + uint32_t ackRcvBad; + uint32_t rtsBad; + uint32_t rtsGood; + uint32_t fcsBad; + uint32_t noBeacons; + uint32_t mib_int_count; +} wmi_host_pdev_stats; + +/** + * struct wmi_host_snr_info - WMI host Signal to noise ration info + * @bcn_snr: beacon SNR + * @dat_snr: Data frames SNR + */ +typedef struct { + int32_t bcn_snr; + int32_t dat_snr; +} wmi_host_snr_info; + +#define WMI_HOST_MAX_TX_RATE_VALUES 10 /*Max Tx Rates */ +#define WMI_HOST_MAX_RSSI_VALUES 10 /*Max Rssi values */ + +/* The WLAN_MAX_AC macro cannot be changed without breaking + * * WMI compatibility. + * * The maximum value of access category + * */ +#define WMI_HOST_WLAN_MAX_AC 4 + +/** + * struct wmi_host_vdev_stats - vdev stats structure + * @vdev_id: unique id identifying the VDEV, generated by the caller + * Rest all Only TLV + * @vdev_snr: wmi_host_snr_info + * @tx_frm_cnt: Total number of packets(per AC) that were successfully + * transmitted (with and without retries, + * including multi-cast, broadcast) + * @rx_frm_cnt: Total number of packets that were successfully received + * (after appropriate filter rules including multi-cast, broadcast) + * @multiple_retry_cnt: The number of MSDU packets and MMPDU frames per AC + * that the 802.11 station successfully transmitted after + * more than one retransmission attempt + * @fail_cnt: Total number packets(per AC) failed to transmit + * @rts_fail_cnt: Total number of RTS/CTS sequence failures for transmission + * of a packet + * @rts_succ_cnt: Total number of RTS/CTS sequence success for transmission + * of a packet + * @rx_err_cnt: The receive error count. HAL will provide the + * RxP FCS error global + * @rx_discard_cnt: The sum of the receive error count and + * dropped-receive-buffer error count (FCS error) + * @ack_fail_cnt: Total number packets failed transmit because of no + * ACK from the remote entity + * @tx_rate_history:History of last ten transmit rate, in units of 500 kbit/sec + * @bcn_rssi_history: History of last ten Beacon rssi of the connected Bss + */ +typedef struct { + uint32_t vdev_id; + /* Rest all Only TLV */ + wmi_host_snr_info vdev_snr; + uint32_t tx_frm_cnt[WMI_HOST_WLAN_MAX_AC]; + uint32_t rx_frm_cnt; + uint32_t multiple_retry_cnt[WMI_HOST_WLAN_MAX_AC]; + uint32_t fail_cnt[WMI_HOST_WLAN_MAX_AC]; + uint32_t rts_fail_cnt; + uint32_t rts_succ_cnt; + uint32_t rx_err_cnt; + uint32_t rx_discard_cnt; + uint32_t ack_fail_cnt; + uint32_t tx_rate_history[WMI_HOST_MAX_TX_RATE_VALUES]; + uint32_t bcn_rssi_history[WMI_HOST_MAX_RSSI_VALUES]; +} wmi_host_vdev_stats; + +/** + * struct wmi_host_vdev_extd_stats - VDEV extended stats + * @vdev_id: unique id identifying the VDEV, generated by the caller + * @ppdu_aggr_cnt: No of Aggrs Queued to HW + * @ppdu_noack: No of PPDU's not Acked includes both aggr and nonaggr's + * @mpdu_queued: No of MPDU/Subframes's queued to HW in Aggregates + * @ppdu_nonaggr_cnt: No of NonAggr/MPDU/Subframes's queued to HW + * in Legacy NonAggregates + * @mpdu_sw_requed: No of MPDU/Subframes's SW requeued includes + * both Aggr and NonAggr + * @mpdu_suc_retry: No of MPDU/Subframes's transmitted Successfully + * after Single/mul HW retry + * @mpdu_suc_multitry: No of MPDU/Subframes's transmitted Success + * after Multiple HW retry + * @mpdu_fail_retry: No of MPDU/Subframes's failed transmission + * after Multiple HW retry + * @reserved[13]: for future extensions set to 0x0 + */ +typedef struct { + uint32_t vdev_id; + uint32_t ppdu_aggr_cnt; + uint32_t ppdu_noack; + uint32_t mpdu_queued; + uint32_t ppdu_nonaggr_cnt; + uint32_t mpdu_sw_requed; + uint32_t mpdu_suc_retry; + uint32_t mpdu_suc_multitry; + uint32_t mpdu_fail_retry; + uint32_t reserved[13]; +} wmi_host_vdev_extd_stats; + +/** + * struct wmi_host_peer_stats - peer stats + * @peer_macaddr: peer MAC address + * @peer_rssi: rssi + * @peer_rssi_seq_num: rssi sequence number + * @peer_tx_rate: last tx data rate used for peer + * @peer_rx_rate: last rx data rate used for peer + * @currentper: Current PER + * @retries: Retries happend during transmission + * @txratecount: Maximum Aggregation Size + * @max4msframelen: Max4msframelen of tx rates used + * @totalsubframes: Total no of subframes + * @txbytes: No of bytes transmitted to the client + * @nobuffs[4]: Packet Loss due to buffer overflows + * @excretries[4]: Packet Loss due to excessive retries + * @peer_rssi_changed: how many times peer's RSSI changed by a + * non-negligible amount + */ +typedef struct { + wmi_host_mac_addr peer_macaddr; + uint32_t peer_rssi; + uint32_t peer_rssi_seq_num; + uint32_t peer_tx_rate; + uint32_t peer_rx_rate; + uint32_t currentper; + uint32_t retries; + uint32_t txratecount; + uint32_t max4msframelen; + uint32_t totalsubframes; + uint32_t txbytes; + uint32_t nobuffs[4]; + uint32_t excretries[4]; + uint32_t peer_rssi_changed; +} wmi_host_peer_stats; + +typedef struct { + uint32_t dummy; +} wmi_host_bcnflt_stats; + +/** + * struct wmi_host_chan_stats - WMI chan stats + * @chan_mhz: Primary channel freq of the channel for which stats are sent + * @sampling_period_us: Time spent on the channel + * @rx_clear_count: Aggregate duration over a sampling period for + * which channel activity was observed + * @tx_duration_us: Accumalation of the TX PPDU duration over a sampling period + * @rx_duration_us: Accumalation of the RX PPDU duration over a sampling period + */ +typedef struct { + uint32_t chan_mhz; + uint32_t sampling_period_us; + uint32_t rx_clear_count; + uint32_t tx_duration_us; + uint32_t rx_duration_us; +} wmi_host_chan_stats; + +#define WMI_EVENT_ID_INVALID 0 +/** + * Host based ENUM IDs for events to abstract target enums for event_id + */ +typedef enum { + wmi_service_ready_event_id = 0, + wmi_ready_event_id, + wmi_dbg_msg_event_id, + wmi_scan_event_id, + wmi_echo_event_id, + wmi_update_stats_event_id, + wmi_inst_rssi_stats_event_id, + wmi_vdev_start_resp_event_id, + wmi_vdev_standby_req_event_id, + wmi_vdev_resume_req_event_id, + wmi_vdev_stopped_event_id, + wmi_peer_sta_kickout_event_id, + wmi_host_swba_event_id, + wmi_tbttoffset_update_event_id, + wmi_mgmt_rx_event_id, + wmi_chan_info_event_id, + wmi_phyerr_event_id, + wmi_roam_event_id, + wmi_profile_match, + wmi_debug_print_event_id, + wmi_pdev_qvit_event_id, + wmi_wlan_profile_data_event_id, + wmi_rtt_meas_report_event_id, + wmi_tsf_meas_report_event_id, + wmi_rtt_error_report_event_id, + wmi_rtt_keepalive_event_id, + wmi_oem_cap_event_id, + wmi_oem_meas_report_event_id, + wmi_oem_report_event_id, + wmi_nan_event_id, + wmi_wow_wakeup_host_event_id, + wmi_gtk_offload_status_event_id, + wmi_gtk_rekey_fail_event_id, + wmi_dcs_interference_event_id, + wmi_pdev_tpc_config_event_id, + wmi_csa_handling_event_id, + wmi_gpio_input_event_id, + wmi_peer_ratecode_list_event_id, + wmi_generic_buffer_event_id, + wmi_mcast_buf_release_event_id, + wmi_mcast_list_ageout_event_id, + wmi_vdev_get_keepalive_event_id, + wmi_wds_peer_event_id, + wmi_peer_sta_ps_statechg_event_id, + wmi_pdev_fips_event_id, + wmi_tt_stats_event_id, + wmi_pdev_channel_hopping_event_id, + wmi_pdev_ani_cck_level_event_id, + wmi_pdev_ani_ofdm_level_event_id, + wmi_pdev_reserve_ast_entry_event_id, + wmi_pdev_nfcal_power_event_id, + wmi_pdev_tpc_event_id, + wmi_pdev_get_ast_info_event_id, + wmi_pdev_temperature_event_id, + wmi_pdev_nfcal_power_all_channels_event_id, + wmi_pdev_bss_chan_info_event_id, + wmi_mu_report_event_id, + wmi_pdev_utf_event_id, + wmi_pdev_dump_event_id, + wmi_tx_pause_event_id, + wmi_dfs_radar_event_id, + wmi_pdev_l1ss_track_event_id, + wmi_service_ready_ext_event_id, + wmi_vdev_install_key_complete_event_id, + wmi_vdev_mcc_bcn_intvl_change_req_event_id, + wmi_vdev_tsf_report_event_id, + wmi_peer_info_event_id, + wmi_peer_tx_fail_cnt_thr_event_id, + wmi_peer_estimated_linkspeed_event_id, + wmi_peer_state_event_id, + wmi_offload_bcn_tx_status_event_id, + wmi_offload_prob_resp_tx_status_event_id, + wmi_mgmt_tx_completion_event_id, + wmi_tx_delba_complete_event_id, + wmi_tx_addba_complete_event_id, + wmi_ba_rsp_ssn_event_id, + wmi_aggr_state_trig_event_id, + wmi_roam_synch_event_id, + wmi_p2p_disc_event_id, + wmi_p2p_noa_event_id, + wmi_pdev_resume_event_id, + wmi_do_wow_disable_ack_event_id, + wmi_wow_initial_wakeup_event_id, + wmi_stats_ext_event_id, + wmi_iface_link_stats_event_id, + wmi_peer_link_stats_event_id, + wmi_radio_link_stats_link, + wmi_update_fw_mem_dump_event_id, + wmi_diag_event_id_log_supported_event_id, + wmi_nlo_match_event_id, + wmi_nlo_scan_complete_event_id, + wmi_apfind_event_id, + wmi_passpoint_match_event_id, + wmi_chatter_pc_query_event_id, + wmi_pdev_ftm_intg_event_id, + wmi_wlan_freq_avoid_event_id, + wmi_thermal_mgmt_event_id, + wmi_diag_container_event_id, + wmi_host_auto_shutdown_event_id, + wmi_update_whal_mib_stats_event_id, + wmi_update_vdev_rate_stats_event_id, + wmi_diag_event_id, + wmi_ocb_set_sched_event_id, + wmi_dbg_mesg_flush_complete_event_id, + wmi_rssi_breach_event_id, + wmi_uploadh_event_id, + wmi_captureh_event_id, + wmi_rfkill_state_change_event_id, + wmi_tdls_peer_event_id, + wmi_batch_scan_enabled_event_id, + wmi_batch_scan_result_event_id, + wmi_lpi_result_event_id, + wmi_lpi_status_event_id, + wmi_lpi_handoff_event_id, + wmi_extscan_start_stop_event_id, + wmi_extscan_operation_event_id, + wmi_extscan_table_usage_event_id, + wmi_extscan_cached_results_event_id, + wmi_extscan_wlan_change_results_event_id, + wmi_extscan_hotlist_match_event_id, + wmi_extscan_capabilities_event_id, + wmi_extscan_hotlist_ssid_match_event_id, + wmi_mdns_stats_event_id, + wmi_sap_ofl_add_sta_event_id, + wmi_sap_ofl_del_sta_event_id, + wmi_ocb_set_config_resp_event_id, + wmi_ocb_get_tsf_timer_resp_event_id, + wmi_dcc_get_stats_resp_event_id, + wmi_dcc_update_ndl_resp_event_id, + wmi_dcc_stats_event_id, + wmi_soc_set_hw_mode_resp_event_id, + wmi_soc_hw_mode_transition_event_id, + wmi_soc_set_dual_mac_config_resp_event_id, + wmi_tx_data_traffic_ctrl_event_id, + wmi_update_rcpi_event_id, + wmi_get_arp_stats_req_id, + + wmi_events_max, +} wmi_conv_event_id; + +#define WMI_UNAVAILABLE_PARAM 0 +/** + * Host based ENUM IDs for PDEV params to abstract target enums + */ +typedef enum { + wmi_pdev_param_tx_chain_mask = 0, + wmi_pdev_param_rx_chain_mask, + wmi_pdev_param_txpower_limit2g, + wmi_pdev_param_txpower_limit5g, + wmi_pdev_param_txpower_scale, + wmi_pdev_param_beacon_gen_mode, + wmi_pdev_param_beacon_tx_mode, + wmi_pdev_param_resmgr_offchan_mode, + wmi_pdev_param_protection_mode, + wmi_pdev_param_dynamic_bw, + wmi_pdev_param_non_agg_sw_retry_th, + wmi_pdev_param_agg_sw_retry_th, + wmi_pdev_param_sta_kickout_th, + wmi_pdev_param_ac_aggrsize_scaling, + wmi_pdev_param_ltr_enable, + wmi_pdev_param_ltr_ac_latency_be, + wmi_pdev_param_ltr_ac_latency_bk, + wmi_pdev_param_ltr_ac_latency_vi, + wmi_pdev_param_ltr_ac_latency_vo, + wmi_pdev_param_ltr_ac_latency_timeout, + wmi_pdev_param_ltr_sleep_override, + wmi_pdev_param_ltr_rx_override, + wmi_pdev_param_ltr_tx_activity_timeout, + wmi_pdev_param_l1ss_enable, + wmi_pdev_param_dsleep_enable, + wmi_pdev_param_pcielp_txbuf_flush, + wmi_pdev_param_pcielp_txbuf_watermark, + wmi_pdev_param_pcielp_txbuf_tmo_en, + wmi_pdev_param_pcielp_txbuf_tmo_value, + wmi_pdev_param_pdev_stats_update_period, + wmi_pdev_param_vdev_stats_update_period, + wmi_pdev_param_peer_stats_update_period, + wmi_pdev_param_bcnflt_stats_update_period, + wmi_pdev_param_pmf_qos, + wmi_pdev_param_arp_ac_override, + wmi_pdev_param_dcs, + wmi_pdev_param_ani_enable, + wmi_pdev_param_ani_poll_period, + wmi_pdev_param_ani_listen_period, + wmi_pdev_param_ani_ofdm_level, + wmi_pdev_param_ani_cck_level, + wmi_pdev_param_dyntxchain, + wmi_pdev_param_proxy_sta, + wmi_pdev_param_idle_ps_config, + wmi_pdev_param_power_gating_sleep, + wmi_pdev_param_aggr_burst, + wmi_pdev_param_rx_decap_mode, + wmi_pdev_param_fast_channel_reset, + wmi_pdev_param_burst_dur, + wmi_pdev_param_burst_enable, + wmi_pdev_param_smart_antenna_default_antenna, + wmi_pdev_param_igmpmld_override, + wmi_pdev_param_igmpmld_tid, + wmi_pdev_param_antenna_gain, + wmi_pdev_param_rx_filter, + wmi_pdev_set_mcast_to_ucast_tid, + wmi_pdev_param_proxy_sta_mode, + wmi_pdev_param_set_mcast2ucast_mode, + wmi_pdev_param_set_mcast2ucast_buffer, + wmi_pdev_param_remove_mcast2ucast_buffer, + wmi_pdev_peer_sta_ps_statechg_enable, + wmi_pdev_param_igmpmld_ac_override, + wmi_pdev_param_block_interbss, + wmi_pdev_param_set_disable_reset_cmdid, + wmi_pdev_param_set_msdu_ttl_cmdid, + wmi_pdev_param_set_ppdu_duration_cmdid, + wmi_pdev_param_txbf_sound_period_cmdid, + wmi_pdev_param_set_promisc_mode_cmdid, + wmi_pdev_param_set_burst_mode_cmdid, + wmi_pdev_param_en_stats, + wmi_pdev_param_mu_group_policy, + wmi_pdev_param_noise_detection, + wmi_pdev_param_noise_threshold, + wmi_pdev_param_dpd_enable, + wmi_pdev_param_set_mcast_bcast_echo, + wmi_pdev_param_atf_strict_sch, + wmi_pdev_param_atf_sched_duration, + wmi_pdev_param_ant_plzn, + wmi_pdev_param_mgmt_retry_limit, + wmi_pdev_param_sensitivity_level, + wmi_pdev_param_signed_txpower_2g, + wmi_pdev_param_signed_txpower_5g, + wmi_pdev_param_enable_per_tid_amsdu, + wmi_pdev_param_enable_per_tid_ampdu, + wmi_pdev_param_cca_threshold, + wmi_pdev_param_rts_fixed_rate, + wmi_pdev_param_cal_period, + wmi_pdev_param_pdev_reset, + wmi_pdev_param_wapi_mbssid_offset, + wmi_pdev_param_arp_srcaddr, + wmi_pdev_param_arp_dstaddr, + wmi_pdev_param_txpower_decr_db, + wmi_pdev_param_rx_batchmode, + wmi_pdev_param_packet_aggr_delay, + wmi_pdev_param_atf_obss_noise_sch, + wmi_pdev_param_atf_obss_noise_scaling_factor, + wmi_pdev_param_cust_txpower_scale, + wmi_pdev_param_atf_dynamic_enable, + wmi_pdev_param_atf_ssid_group_policy, + wmi_pdev_param_rfkill_enable, + wmi_pdev_param_hw_rfkill_config, + wmi_pdev_param_low_power_rf_enable, + wmi_pdev_param_l1ss_track, + wmi_pdev_param_hyst_en, + wmi_pdev_param_power_collapse_enable, + wmi_pdev_param_led_sys_state, + wmi_pdev_param_led_enable, + wmi_pdev_param_audio_over_wlan_latency, + wmi_pdev_param_audio_over_wlan_enable, + wmi_pdev_param_whal_mib_stats_update_enable, + wmi_pdev_param_vdev_rate_stats_update_period, + wmi_pdev_param_cts_cbw, + wmi_pdev_param_wnts_config, + wmi_pdev_param_adaptive_early_rx_enable, + wmi_pdev_param_adaptive_early_rx_min_sleep_slop, + wmi_pdev_param_adaptive_early_rx_inc_dec_step, + wmi_pdev_param_early_rx_fix_sleep_slop, + wmi_pdev_param_bmiss_based_adaptive_bto_enable, + wmi_pdev_param_bmiss_bto_min_bcn_timeout, + wmi_pdev_param_bmiss_bto_inc_dec_step, + wmi_pdev_param_bto_fix_bcn_timeout, + wmi_pdev_param_ce_based_adaptive_bto_enable, + wmi_pdev_param_ce_bto_combo_ce_value, + wmi_pdev_param_tx_chain_mask_2g, + wmi_pdev_param_rx_chain_mask_2g, + wmi_pdev_param_tx_chain_mask_5g, + wmi_pdev_param_rx_chain_mask_5g, + wmi_pdev_param_tx_chain_mask_cck, + wmi_pdev_param_tx_chain_mask_1ss, + + wmi_pdev_param_max, +} wmi_conv_pdev_params_id; + + +/** + * Host based ENUM IDs for VDEV params to abstract target enums + */ +typedef enum { + wmi_vdev_param_rts_threshold = 0, + wmi_vdev_param_fragmentation_threshold, + wmi_vdev_param_beacon_interval, + wmi_vdev_param_listen_interval, + wmi_vdev_param_multicast_rate, + wmi_vdev_param_mgmt_tx_rate, + wmi_vdev_param_slot_time, + wmi_vdev_param_preamble, + wmi_vdev_param_swba_time, + wmi_vdev_stats_update_period, + wmi_vdev_pwrsave_ageout_time, + wmi_vdev_host_swba_interval, + wmi_vdev_param_dtim_period, + wmi_vdev_oc_scheduler_air_time_limit, + wmi_vdev_param_wds, + wmi_vdev_param_atim_window, + wmi_vdev_param_bmiss_count_max, + wmi_vdev_param_bmiss_first_bcnt, + wmi_vdev_param_bmiss_final_bcnt, + wmi_vdev_param_feature_wmm, + wmi_vdev_param_chwidth, + wmi_vdev_param_chextoffset, + wmi_vdev_param_disable_htprotection, + wmi_vdev_param_sta_quickkickout, + wmi_vdev_param_mgmt_rate, + wmi_vdev_param_protection_mode, + wmi_vdev_param_fixed_rate, + wmi_vdev_param_sgi, + wmi_vdev_param_ldpc, + wmi_vdev_param_tx_stbc, + wmi_vdev_param_rx_stbc, + wmi_vdev_param_intra_bss_fwd, + wmi_vdev_param_def_keyid, + wmi_vdev_param_nss, + wmi_vdev_param_bcast_data_rate, + wmi_vdev_param_mcast_data_rate, + wmi_vdev_param_mcast_indicate, + wmi_vdev_param_dhcp_indicate, + wmi_vdev_param_unknown_dest_indicate, + wmi_vdev_param_ap_keepalive_min_idle_inactive_time_secs, + wmi_vdev_param_ap_keepalive_max_idle_inactive_time_secs, + wmi_vdev_param_ap_keepalive_max_unresponsive_time_secs, + wmi_vdev_param_ap_enable_nawds, + wmi_vdev_param_mcast2ucast_set, + wmi_vdev_param_enable_rtscts, + wmi_vdev_param_rc_num_retries, + wmi_vdev_param_txbf, + wmi_vdev_param_packet_powersave, + wmi_vdev_param_drop_unencry, + wmi_vdev_param_tx_encap_type, + wmi_vdev_param_ap_detect_out_of_sync_sleeping_sta_time_secs, + wmi_vdev_param_cabq_maxdur, + wmi_vdev_param_mfptest_set, + wmi_vdev_param_rts_fixed_rate, + wmi_vdev_param_vht_sgimask, + wmi_vdev_param_vht80_ratemask, + wmi_vdev_param_early_rx_adjust_enable, + wmi_vdev_param_early_rx_tgt_bmiss_num, + wmi_vdev_param_early_rx_bmiss_sample_cycle, + wmi_vdev_param_early_rx_slop_step, + wmi_vdev_param_early_rx_init_slop, + wmi_vdev_param_early_rx_adjust_pause, + wmi_vdev_param_proxy_sta, + wmi_vdev_param_meru_vc, + wmi_vdev_param_rx_decap_type, + wmi_vdev_param_bw_nss_ratemask, + wmi_vdev_param_sensor_ap, + wmi_vdev_param_beacon_rate, + wmi_vdev_param_dtim_enable_cts, + wmi_vdev_param_sta_kickout, + wmi_vdev_param_tx_pwrlimit, + wmi_vdev_param_snr_num_for_cal, + wmi_vdev_param_roam_fw_offload, + wmi_vdev_param_enable_rmc, + wmi_vdev_param_ibss_max_bcn_lost_ms, + wmi_vdev_param_max_rate, + wmi_vdev_param_early_rx_drift_sample, + wmi_vdev_param_set_ibss_tx_fail_cnt_thr, + wmi_vdev_param_ebt_resync_timeout, + wmi_vdev_param_aggr_trig_event_enable, + wmi_vdev_param_is_ibss_power_save_allowed, + wmi_vdev_param_is_power_collapse_allowed, + wmi_vdev_param_is_awake_on_txrx_enabled, + wmi_vdev_param_inactivity_cnt, + wmi_vdev_param_txsp_end_inactivity_time_ms, + wmi_vdev_param_dtim_policy, + wmi_vdev_param_ibss_ps_warmup_time_secs, + wmi_vdev_param_ibss_ps_1rx_chain_in_atim_window_enable, + wmi_vdev_param_rx_leak_window, + wmi_vdev_param_stats_avg_factor, + wmi_vdev_param_disconnect_th, + wmi_vdev_param_rtscts_rate, + wmi_vdev_param_mcc_rtscts_protection_enable, + wmi_vdev_param_mcc_broadcast_probe_enable, + wmi_vdev_param_capabilities, + + wmi_vdev_param_max, +} wmi_conv_vdev_param_id; + +/** + * Host based ENUM IDs for service bits to abstract target enums + */ +typedef enum { + wmi_service_beacon_offload = 0, + wmi_service_scan_offload, + wmi_service_roam_offload, + wmi_service_bcn_miss_offload, + wmi_service_sta_pwrsave, + wmi_service_sta_advanced_pwrsave, + wmi_service_ap_uapsd, + wmi_service_ap_dfs, + wmi_service_11ac, + wmi_service_blockack, + wmi_service_phyerr, + wmi_service_bcn_filter, + wmi_service_rtt, + wmi_service_ratectrl, + wmi_service_wow, + wmi_service_ratectrl_cache, + wmi_service_iram_tids, + wmi_service_burst, + wmi_service_smart_antenna_sw_support, + wmi_service_gtk_offload, + wmi_service_scan_sch, + wmi_service_csa_offload, + wmi_service_chatter, + wmi_service_coex_freqavoid, + wmi_service_packet_power_save, + wmi_service_force_fw_hang, + wmi_service_smart_antenna_hw_support, + wmi_service_gpio, + wmi_sta_uapsd_basic_auto_trig, + wmi_sta_uapsd_var_auto_trig, + wmi_service_sta_keep_alive, + wmi_service_tx_encap, + wmi_service_ap_ps_detect_out_of_sync, + wmi_service_early_rx, + wmi_service_enhanced_proxy_sta, + wmi_service_tt, + wmi_service_atf, + wmi_service_peer_caching, + wmi_service_coex_gpio, + wmi_service_aux_spectral_intf, + wmi_service_aux_chan_load_intf, + wmi_service_bss_channel_info_64, + wmi_service_ext_res_cfg_support, + wmi_service_mesh, + wmi_service_restrt_chnl_support, + wmi_service_roam_scan_offload, + wmi_service_arpns_offload, + wmi_service_nlo, + wmi_service_sta_dtim_ps_modulated_dtim, + wmi_service_sta_smps, + wmi_service_fwtest, + wmi_service_sta_wmmac, + wmi_service_tdls, + wmi_service_mcc_bcn_interval_change, + wmi_service_adaptive_ocs, + wmi_service_ba_ssn_support, + wmi_service_filter_ipsec_natkeepalive, + wmi_service_wlan_hb, + wmi_service_lte_ant_share_support, + wmi_service_batch_scan, + wmi_service_qpower, + wmi_service_plmreq, + wmi_service_thermal_mgmt, + wmi_service_rmc, + wmi_service_mhf_offload, + wmi_service_coex_sar, + wmi_service_bcn_txrate_override, + wmi_service_nan, + wmi_service_l1ss_stat, + wmi_service_estimate_linkspeed, + wmi_service_obss_scan, + wmi_service_tdls_offchan, + wmi_service_tdls_uapsd_buffer_sta, + wmi_service_tdls_uapsd_sleep_sta, + wmi_service_ibss_pwrsave, + wmi_service_lpass, + wmi_service_extscan, + wmi_service_d0wow, + wmi_service_hsoffload, + wmi_service_roam_ho_offload, + wmi_service_rx_full_reorder, + wmi_service_dhcp_offload, + wmi_service_sta_rx_ipa_offload_support, + wmi_service_mdns_offload, + wmi_service_sap_auth_offload, + wmi_service_dual_band_simultaneous_support, + wmi_service_ocb, + wmi_service_ap_arpns_offload, + wmi_service_per_band_chainmask_support, + wmi_service_packet_filter_offload, + wmi_service_mgmt_tx_htt, + wmi_service_mgmt_tx_wmi, + wmi_service_ext_msg, + wmi_service_mawc, + + wmi_service_peer_stats, + wmi_service_mesh_11s, + wmi_service_periodic_chan_stat_support, + wmi_service_tx_mode_push_only, + wmi_service_tx_mode_push_pull, + wmi_service_tx_mode_dynamic, + + wmi_services_max, +} wmi_conv_service_ids; +#define WMI_SERVICE_UNAVAILABLE 0xFFFF + +/** + * struct target_capability_info - Target capabilities in service ready + * @phy_capability: PHY capabilities + * @max_frag_entry: Maximum frag entries + * @num_rf_chains: Number of RF chains supported + * @ht_cap_info: HT cap info + * @vht_cap_info: VHT cap info + * @vht_supp_mcs: VHT Supported MCS + * @hw_min_tx_power: HW minimum tx power + * @hw_max_tx_power: HW maximum tx power + * @sys_cap_info: sys capability info + * @min_pkt_size_enable: Enterprise mode short pkt enable + * @max_bcn_ie_size: Max beacon and probe rsp IE offload size + * @max_num_scan_channels: Max scan channels + * @max_supported_macs: max supported MCS + * @wmi_fw_sub_feat_caps: FW sub feature capabilities + * @txrx_chainmask: TXRX chain mask + * @default_dbs_hw_mode_index: DBS hw mode index + * @num_msdu_desc: number of msdu desc + */ +typedef struct { + uint32_t phy_capability; + uint32_t max_frag_entry; + uint32_t num_rf_chains; + uint32_t ht_cap_info; + uint32_t vht_cap_info; + uint32_t vht_supp_mcs; + uint32_t hw_min_tx_power; + uint32_t hw_max_tx_power; + uint32_t sys_cap_info; + uint32_t min_pkt_size_enable; + uint32_t max_bcn_ie_size; + uint32_t max_num_scan_channels; + uint32_t max_supported_macs; + uint32_t wmi_fw_sub_feat_caps; + uint32_t txrx_chainmask; + uint32_t default_dbs_hw_mode_index; + uint32_t num_msdu_desc; +} target_capability_info; + +/** + * enum WMI_DBG_PARAM - Debug params + * @WMI_DBGLOG_LOG_LEVEL: Set the loglevel + * @WMI_DBGLOG_VAP_ENABLE: Enable VAP level debug + * @WMI_DBGLOG_VAP_DISABLE: Disable VAP level debug + * @WMI_DBGLOG_MODULE_ENABLE: Enable MODULE level debug + * @WMI_DBGLOG_MODULE_DISABLE: Disable MODULE level debug + * @WMI_DBGLOG_MOD_LOG_LEVEL: Enable MODULE level debug + * @WMI_DBGLOG_TYPE: set type of the debug output + * @WMI_DBGLOG_REPORT_ENABLE: Enable Disable debug + */ +typedef enum { + WMI_DBGLOG_LOG_LEVEL = 0x1, + WMI_DBGLOG_VAP_ENABLE, + WMI_DBGLOG_VAP_DISABLE, + WMI_DBGLOG_MODULE_ENABLE, + WMI_DBGLOG_MODULE_DISABLE, + WMI_DBGLOG_MOD_LOG_LEVEL, + WMI_DBGLOG_TYPE, + WMI_DBGLOG_REPORT_ENABLE +} WMI_DBG_PARAM; + +/** + * struct wmi_host_fw_ver - FW version in non-tlv target + * @sw_version: Versin info + * @sw_version_1: Second dword of version + */ +struct wmi_host_fw_ver { + uint32_t sw_version; + uint32_t sw_version_1; +}; + +/** + * struct wmi_host_fw_abi_ver - FW version in non-tlv target + * @sw_version: Versin info + * @abi_version: ABI version + */ +struct wmi_host_fw_abi_ver { + uint32_t sw_version; + uint32_t abi_version; +}; + +/** + * struct target_resource_config - Resource config sent from host to target + * abstracted out to include union of both configs + * @num_vdevs: Number vdevs configured + * @num_peers: Number of peers + * @num_active_peers: Number of active peers for peer cache + * @num_offload_peers: Number of offload peers + * @num_offload_reorder_buffs: number of offload reorder buffs + * @num_peer_keys: number of peer keys + * @num_tids: number of tids + * @ast_skid_limit: AST skid limit + * @tx_chain_mask: TX chain mask + * @rx_chain_mask: RX chain mask + * @rx_timeout_pri: RX reorder timeout per AC + * @rx_decap_mode: RX decap mode + * @scan_max_pending_req: Scan mac pending req + * @bmiss_offload_max_vdev: Beacom miss offload max vdevs + * @roam_offload_max_vdev: Roam offload max vdevs + * @roam_offload_max_ap_profiles: roam offload max ap profiles + * @num_mcast_groups: num mcast groups + * @num_mcast_table_elems: number of macst table elems + * @mcast2ucast_mode: mcast enhance mode + * @tx_dbg_log_size: DBG log buf size + * @num_wds_entries: number of WDS entries + * @dma_burst_size: DMA burst size. + * @mac_aggr_delim: Mac aggr delim + * @rx_skip_defrag_timeout_dup_detection_check: Defrag dup check in host? + * @vow_config: vow configuration + * @gtk_offload_max_vdev: Max vdevs for GTK offload + * @num_msdu_desc: Number of msdu desc + * @max_frag_entries: Max frag entries + * End common + * @max_peer_ext_stats: Max peer EXT stats + * @smart_ant_cap: Smart antenna capabilities + * @BK_Minfree: BIN configuration for BK traffic + * @BE_Minfree: BIN configuration for BE traffic + * @VI_Minfree: BIN configuration for VI traffic + * @VO_Minfree: BIN configuration for VO traffic + * @rx_batchmode: RX batch mode + * @tt_support: Thermal throttling support + * @atf_config: ATF config + * @iphdr_pad_config: ipheader pad config + * @qwrap_config: Qwrap configuration + * @alloc_frag_desc_for_data_pkt: Frag desc for data + * Added in MCL + * @num_tdls_vdevs: + * @num_tdls_conn_table_entries: + * @beacon_tx_offload_max_vdev: + * @num_multicast_filter_entries: + * @num_wow_filters: + * @num_keep_alive_pattern: + * @keep_alive_pattern_size: + * @max_tdls_concurrent_sleep_sta: + * @max_tdls_concurrent_buffer_sta: + * @wmi_send_separate: + * @num_ocb_vdevs: + * @num_ocb_channels: + * @num_ocb_schedules: + */ +typedef struct { + uint32_t num_vdevs; + uint32_t num_peers; + uint32_t num_active_peers; + uint32_t num_offload_peers; + uint32_t num_offload_reorder_buffs; + uint32_t num_peer_keys; + uint32_t num_tids; + uint32_t ast_skid_limit; + uint32_t tx_chain_mask; + uint32_t rx_chain_mask; + uint32_t rx_timeout_pri[4]; + uint32_t rx_decap_mode; + uint32_t scan_max_pending_req; + uint32_t bmiss_offload_max_vdev; + uint32_t roam_offload_max_vdev; + uint32_t roam_offload_max_ap_profiles; + uint32_t num_mcast_groups; + uint32_t num_mcast_table_elems; + uint32_t mcast2ucast_mode; + uint32_t tx_dbg_log_size; + uint32_t num_wds_entries; + uint32_t dma_burst_size; + uint32_t mac_aggr_delim; + uint32_t rx_skip_defrag_timeout_dup_detection_check; + uint32_t vow_config; + uint32_t gtk_offload_max_vdev; + uint32_t num_msdu_desc; /* Number of msdu desc */ + uint32_t max_frag_entries; + /* End common */ + + /* Added for Beeliner */ + uint32_t max_peer_ext_stats; + uint32_t smart_ant_cap; + uint32_t BK_Minfree; + uint32_t BE_Minfree; + uint32_t VI_Minfree; + uint32_t VO_Minfree; + uint32_t rx_batchmode; + uint32_t tt_support; + uint32_t atf_config; + uint32_t iphdr_pad_config; + uint32_t + qwrap_config:16, + alloc_frag_desc_for_data_pkt:16; + + /* Added in MCL */ + uint32_t num_tdls_vdevs; + uint32_t num_tdls_conn_table_entries; + uint32_t beacon_tx_offload_max_vdev; + uint32_t num_multicast_filter_entries; + uint32_t num_wow_filters; + uint32_t num_keep_alive_pattern; + uint32_t keep_alive_pattern_size; + uint32_t max_tdls_concurrent_sleep_sta; + uint32_t max_tdls_concurrent_buffer_sta; + uint32_t wmi_send_separate; + uint32_t num_ocb_vdevs; + uint32_t num_ocb_channels; + uint32_t num_ocb_schedules; +} target_resource_config; + +/** + * struct wds_addr_event - WDS addr event structure + * @event_type: event type add/delete + * @peer_mac: peer mac + * @dest_mac: destination mac address + */ +typedef struct { + uint32_t event_type[4]; + u_int8_t peer_mac[IEEE80211_ADDR_LEN]; + u_int8_t dest_mac[IEEE80211_ADDR_LEN]; +} wds_addr_event_t; +/** + * Enum replicated for host abstraction with FW + */ +typedef enum { + /* Event respose of START CMD */ + WMI_HOST_VDEV_START_RESP_EVENT = 0, + /* Event respose of RESTART CMD */ + WMI_HOST_VDEV_RESTART_RESP_EVENT, +} WMI_HOST_START_EVENT_PARAM; + +/** + * struct wmi_host_vdev_start_resp - VDEV start response + * @vdev_id: vdev id + * @requestor_id: requestor id that requested the VDEV start request + * @resp_type: Respose of Event type START/RESTART + * @status: status of the response + * @chain_mask: Vdev chain mask + * @smps_mode: Vdev mimo power save mode + * @mac_id: mac_id field contains the MAC identifier that the + * VDEV is bound to. The valid range is 0 to (num_macs-1). + * @cfgd_tx_streams: Configured Transmit Streams + * @cfgd_rx_streams: Configured Receive Streams + */ +typedef struct { + uint32_t vdev_id; + uint32_t requestor_id; + WMI_HOST_START_EVENT_PARAM resp_type; + uint32_t status; + uint32_t chain_mask; + uint32_t smps_mode; + uint32_t mac_id; + uint32_t cfgd_tx_streams; + uint32_t cfgd_rx_streams; +} wmi_host_vdev_start_resp; + +#define WMI_HOST_ATH_MAX_ANTENNA 4 +/** + * struct wmi_host_mgmt_rx_hdr - host mgmt header params + * @channel: channel on which this frame is received + * @snr: snr information used to cal rssi + * @rssi_ctl[WMI_HOST_ATH_MAX_ANTENNA]: RSSI of PRI 20MHz for each chain. + * @rate: Rate kbps + * @phy_mode: rx phy mode WLAN_PHY_MODE + * @buf_len: length of the frame + * @status: rx status + * @flags: information about the management frame e.g. can give a + * scan source for a scan result mgmt frame + * @rssi: combined RSSI, i.e. the sum of the snr + noise floor (dBm units) + * @tsf_delta: + */ +typedef struct { + uint32_t channel; + uint32_t snr; + uint8_t rssi_ctl[WMI_HOST_ATH_MAX_ANTENNA]; + uint32_t rate; + uint32_t phy_mode; + uint32_t buf_len; + uint32_t status; + uint32_t flags; + int32_t rssi; + uint32_t tsf_delta; +} wmi_host_mgmt_rx_hdr; + +/** + * struct wmi_host_roam_event - host roam event param + * @vdev_id: vdev id + * @reason: roam reason + * @rssi: RSSI + */ +typedef struct { + uint32_t vdev_id; + uint32_t reason; + uint32_t rssi; +} wmi_host_roam_event; + +/** + * ENUM wmi_host_scan_event_type - Scan event type + */ +enum wmi_host_scan_event_type { + WMI_HOST_SCAN_EVENT_STARTED = 0x1, + WMI_HOST_SCAN_EVENT_COMPLETED = 0x2, + WMI_HOST_SCAN_EVENT_BSS_CHANNEL = 0x4, + WMI_HOST_SCAN_EVENT_FOREIGN_CHANNEL = 0x8, + WMI_HOST_SCAN_EVENT_DEQUEUED = 0x10, + WMI_HOST_SCAN_EVENT_PREEMPTED = 0x20, + WMI_HOST_SCAN_EVENT_START_FAILED = 0x40, + WMI_HOST_SCAN_EVENT_RESTARTED = 0x80, + WMI_HOST_SCAN_EVENT_FOREIGN_CHANNEL_EXIT = 0x100, + WMI_HOST_SCAN_EVENT_INVALID = 0x200, + WMI_HOST_SCAN_EVENT_MAX = 0x8000 +}; + +/** + * ENUM wmi_host_scan_completion_reason - Scan completion event type + */ +enum wmi_host_scan_completion_reason { + /** scan related events */ + WMI_HOST_SCAN_REASON_NONE = 0xFF, + WMI_HOST_SCAN_REASON_COMPLETED = 0, + WMI_HOST_SCAN_REASON_CANCELLED = 1, + WMI_HOST_SCAN_REASON_PREEMPTED = 2, + WMI_HOST_SCAN_REASON_TIMEDOUT = 3, + WMI_HOST_SCAN_REASON_INTERNAL_FAILURE = 4, + WMI_HOST_SCAN_REASON_MAX, +}; + +/** + * struct wmi_host_scan_event - Scan event response from target + * @event: event type + * @reason: Reason for event + * @channel_freq: channel frequency + * @requestor: requestor id + * @scan_id: scan id + * @vdev_id: vdev id + */ +typedef struct { + uint32_t event; + uint32_t reason; + uint32_t channel_freq; + uint32_t requestor; + uint32_t scan_id; + uint32_t vdev_id; +} wmi_host_scan_event; + +/** + * struct wmi_host_pdev_reserve_ast_entry_event - Reserve AST entry + * @result: result + */ +typedef struct { + uint32_t result; +} wmi_host_pdev_reserve_ast_entry_event; + +/** + * struct wmi_host_mcast_ageout_entry - mcast aged-out entry + * @grp_addr: IPv4/6 mcast group addr + * @vdev_id: vdev id + */ +typedef struct { + uint8_t grp_addr[16]; + uint32_t vdev_id; +} wmi_host_mcast_ageout_entry; + +/** + * struct wmi_host_mcast_list_ageout_event - List of mcast entry aged-out + * @num_entry: Number of mcast entries timed-out + * @entry: List of wmi_host_mcast_ageout_entry + */ +typedef struct { + uint32_t num_entry; + wmi_host_mcast_ageout_entry entry[1]; +} wmi_host_mcast_list_ageout_event; + +/** + * struct wmi_host_pdev_nfcal_power_all_channels_event - NF cal event data + * @nfdBr: + * chan0: {NFCalPower_chain0, NFCalPower_chain1, + * NFCalPower_chain2, NFCalPower_chain3}, + * chan1: {NFCalPower_chain0, NFCalPower_chain1, + * NFCalPower_chain2, NFCalPower_chain3}, + * chan2: {NFCalPower_chain0, NFCalPower_chain1, + * NFCalPower_chain2, NFCalPower_chain3}, + * chan3: {NFCalPower_chain0, NFCalPower_chain1, + * NFCalPower_chain2, NFCalPower_chain3}, + * @nfdBr: + * chan0: {NFCalPower_chain0, NFCalPower_chain1, + * NFCalPower_chain2, NFCalPower_chain3}, + * chan1: {NFCalPower_chain0, NFCalPower_chain1, + * NFCalPower_chain2, NFCalPower_chain3}, + * chan2: {NFCalPower_chain0, NFCalPower_chain1, + * NFCalPower_chain2, NFCalPower_chain3}, + * chan3: {NFCalPower_chain0, NFCalPower_chain1, + * NFCalPower_chain2, NFCalPower_chain3}, + * @freqNum: frequency number + */ +typedef struct { + int8_t nfdBr[WMI_HOST_RXG_CAL_CHAN_MAX * WMI_HOST_MAX_NUM_CHAINS]; + int8_t nfdBm[WMI_HOST_RXG_CAL_CHAN_MAX * WMI_HOST_MAX_NUM_CHAINS]; + uint32_t freqNum[WMI_HOST_RXG_CAL_CHAN_MAX]; +} wmi_host_pdev_nfcal_power_all_channels_event; + +/** + * struct wmi_host_pdev_tpc_event - WMI host pdev TPC event + * @tpc: + */ +typedef struct { + uint32_t tpc[1]; +} wmi_host_pdev_tpc_event; + +/** + * struct wmi_host_pdev_generic_buffer_event + * @buf_type: Buffer type + * @frag_id: Frag id + * @more_frag: more frags pending + * @buf_len: buffer length + * @buf_info: variable length buffer + */ +typedef struct { + uint32_t buf_type; + uint32_t frag_id; + uint32_t more_frag; + uint32_t buf_len; + uint32_t buf_info[1]; +} wmi_host_pdev_generic_buffer_event; +/** + * Enum for host buffer event + */ +enum { + WMI_HOST_BUFFER_TYPE_RATEPWR_TABLE, + WMI_HOST_BUFFER_TYPE_CTL_TABLE, +}; + +/** + * struct wmi_host_pdev_tpc_config_event - host pdev tpc config event + * @regDomain: + * @chanFreq: + * @phyMode: + * @twiceAntennaReduction: + * @twiceMaxRDPower: + * @twiceAntennaGain: + * @powerLimit: + * @rateMax: + * @numTxChain: + * @ctl: + * @flags: + * @maxRegAllowedPower: + * @maxRegAllowedPowerAGCDD: + * @maxRegAllowedPowerAGSTBC: + * @maxRegAllowedPowerAGTXBF: + * @ratesArray: + */ +typedef struct { + uint32_t regDomain; + uint32_t chanFreq; + uint32_t phyMode; + uint32_t twiceAntennaReduction; + uint32_t twiceMaxRDPower; + int32_t twiceAntennaGain; + uint32_t powerLimit; + uint32_t rateMax; + uint32_t numTxChain; + uint32_t ctl; + uint32_t flags; + int8_t maxRegAllowedPower[WMI_HOST_TPC_TX_NUM_CHAIN]; + int8_t maxRegAllowedPowerAGCDD[WMI_HOST_TPC_TX_NUM_CHAIN][WMI_HOST_TPC_TX_NUM_CHAIN]; + int8_t maxRegAllowedPowerAGSTBC[WMI_HOST_TPC_TX_NUM_CHAIN][WMI_HOST_TPC_TX_NUM_CHAIN]; + int8_t maxRegAllowedPowerAGTXBF[WMI_HOST_TPC_TX_NUM_CHAIN][WMI_HOST_TPC_TX_NUM_CHAIN]; + uint8_t ratesArray[WMI_HOST_TPC_RATE_MAX]; +} wmi_host_pdev_tpc_config_event; +/** + * Enums for TPC event + */ +typedef enum { + WMI_HOST_TPC_CONFIG_EVENT_FLAG_TABLE_CDD = 0x1, + WMI_HOST_TPC_CONFIG_EVENT_FLAG_TABLE_STBC = 0x2, + WMI_HOST_TPC_CONFIG_EVENT_FLAG_TABLE_TXBF = 0x4, +} WMI_HOST_TPC_CONFIG_EVENT_FLAG; + +/** + * Medium Utilization evaluation algorithms + * These algorithms can be complementary rather than exclusive. + */ +typedef enum { + WMI_HOST_MU_BASIC_ALGO = 0x1, + WMI_HOST_MU_PER_BSSID_ALGO = 0x2, + WMI_HOST_MU_HIDDEN_NODE_ALGO = 0x4, +} WMI_HOST_MU_ALGO_TYPE; +/* max MU alg combinations supported by target */ +#define WMI_HOST_MU_MAX_ALGO_TYPE 3 + +/** + * struct wmi_host_mu_report_event - WMI_MU_REPORT_EVENTID + * @mu_request_id: request id + * @status_reason: MU_STATUS_REASON + * @total_mu: MU_ALG_TYPE combinations + * @num_active_bssid: number of active bssid + */ +typedef struct { + uint32_t mu_request_id; + uint32_t status_reason; + uint32_t total_mu[WMI_HOST_MU_MAX_ALGO_TYPE]; + uint32_t num_active_bssid; +} wmi_host_mu_report_event; + +/** + * struct wmi_host_mgmt_tx_compl_event - TX completion event + * @desc_id: from tx_send_cmd + * @status: WMI_MGMT_TX_COMP_STATUS_TYPE + */ +typedef struct { + uint32_t desc_id; + uint32_t status; +} wmi_host_mgmt_tx_compl_event; + +#define WMI_HOST_TIM_BITMAP_ARRAY_SIZE 17 + +/** + * struct wmi_host_tim_info - TIM info in SWBA event + * @tim_len: TIM length + * @tim_mcast: + * @tim_bitmap: TIM bitmap + * @tim_changed: TIM changed + * @tim_num_ps_pending: TIM num PS sta pending + */ +typedef struct { + uint32_t tim_len; + uint32_t tim_mcast; + uint32_t tim_bitmap[WMI_HOST_TIM_BITMAP_ARRAY_SIZE]; + uint32_t tim_changed; + uint32_t tim_num_ps_pending; +} wmi_host_tim_info; + +/** + * struct wmi_host_p2p_noa_descriptor - NoA desc in SWBA event + * @type_count: Absence count + * @duration: NoA duration + * @interval: NoA interval + * @start_time: start time + */ +typedef struct { + uint32_t type_count; + uint32_t duration; + uint32_t interval; + uint32_t start_time; +} wmi_host_p2p_noa_descriptor; +/* Maximum number of NOA Descriptors supported */ +#define WMI_HOST_P2P_MAX_NOA_DESCRIPTORS 4 +/** + * struct wmi_host_p2p_noa_info - p2p noa information + * @modified: NoA modified + * @index: Index + * @oppPS: Oppurtunstic ps + * @ctwindow: CT window + * @num_descriptors: number of descriptors + * @noa_descriptors: noa descriptors + */ +typedef struct { + uint8_t modified; + uint8_t index; + uint8_t oppPS; + uint8_t ctwindow; + uint8_t num_descriptors; + wmi_host_p2p_noa_descriptor + noa_descriptors[WMI_HOST_P2P_MAX_NOA_DESCRIPTORS]; +} wmi_host_p2p_noa_info; + +/** + * struct wmi_host_peer_sta_kickout_event + * @peer_macaddr: peer mac address + * @reason: kickout reason + * @rssi: rssi + */ +typedef struct { + uint8_t peer_macaddr[IEEE80211_ADDR_LEN]; + uint32_t reason; + uint32_t rssi; +} wmi_host_peer_sta_kickout_event; + +/** + * struct wmi_host_peer_sta_ps_statechange_event - ST ps state change event + * @peer_macaddr: peer mac address + * @peer_ps_stats: peer PS state + */ +typedef struct { + uint8_t peer_macaddr[IEEE80211_ADDR_LEN]; + uint32_t peer_ps_state; +} wmi_host_peer_sta_ps_statechange_event; + +/* Maximum CCK, OFDM rates supported */ +#define WMI_SA_MAX_CCK_OFDM_RATES 12 +/* Maximum MCS rates supported; 4 rates in each dword */ +#define WMI_SA_MAX_MCS_RATES 40 +#define WMI_SA_MAX_RATE_COUNTERS 4 +/* Maximum rate series used for transmission */ +#define SA_MAX_RATE_SERIES 2 + +#define SA_MAX_LEGACY_RATE_DWORDS 3 +#define SA_MAX_HT_RATE_DWORDS 10 +#define SA_BYTES_IN_DWORD 4 +#define SA_MASK_BYTE 0xff +/* TODO: ratecode_160 needs to add for future chips */ +/** + * struct wmi_sa_rate_cap - smart antenna rat capabilities + * @ratecode_legacy: Rate code array for CCK OFDM + * @ratecode_20: Rate code array for 20MHz BW + * @ratecode_40: Rate code array for 40MHz BW + * @ratecode_80: Rate code array for 80MHz BW + * @ratecount: Max Rate count for each mode + */ +typedef struct { + uint8_t ratecode_legacy[WMI_SA_MAX_CCK_OFDM_RATES]; + uint8_t ratecode_20[WMI_SA_MAX_MCS_RATES]; + uint8_t ratecode_40[WMI_SA_MAX_MCS_RATES]; + uint8_t ratecode_80[WMI_SA_MAX_MCS_RATES]; + uint8_t ratecount[WMI_SA_MAX_RATE_COUNTERS]; +} wmi_sa_rate_cap; + +/** Preamble types to be used with VDEV fixed rate configuration */ +typedef enum { + WMI_HOST_RATE_PREAMBLE_OFDM, + WMI_HOST_RATE_PREAMBLE_CCK, + WMI_HOST_RATE_PREAMBLE_HT, + WMI_HOST_RATE_PREAMBLE_VHT, +} WMI_HOST_RATE_PREAMBLE; + +#define WMI_HOST_FIXED_RATE_NONE (0xff) + +/** slot time long */ +#define WMI_HOST_VDEV_SLOT_TIME_LONG 0x1 +/** slot time short */ +#define WMI_HOST_VDEV_SLOT_TIME_SHORT 0x2 +/** preablbe long */ +#define WMI_HOST_VDEV_PREAMBLE_LONG 0x1 +/** preablbe short */ +#define WMI_HOST_VDEV_PREAMBLE_SHORT 0x2 +/** found a better AP */ +#define WMI_HOST_ROAM_REASON_BETTER_AP 0x1 +/** beacon miss detected */ +#define WMI_HOST_ROAM_REASON_BMISS 0x2 +/** deauth/disassoc received */ +#define WMI_HOST_ROAM_REASON_DEAUTH 0x2 +/** connected AP's low rssi condition detected */ +#define WMI_HOST_ROAM_REASON_LOW_RSSI 0x3 +/** found another AP that matches SSID and Security profile in + * WMI_ROAM_AP_PROFILE, found during scan triggered upon FINAL_BMISS + */ +#define WMI_HOST_ROAM_REASON_SUITABLE_AP 0x4 +/** LFR3.0 roaming failed, indicate the disconnection to host */ +#define WMI_HOST_ROAM_REASON_HO_FAILED 0x5 + +/** values for vdev_type */ +#define WMI_HOST_VDEV_TYPE_AP 0x1 +#define WMI_HOST_VDEV_TYPE_STA 0x2 +#define WMI_HOST_VDEV_TYPE_IBSS 0x3 +#define WMI_HOST_VDEV_TYPE_MONITOR 0x4 + +/** values for vdev_subtype */ +#define WMI_HOST_VDEV_SUBTYPE_P2P_DEVICE 0x1 +#define WMI_HOST_VDEV_SUBTYPE_P2P_CLIENT 0x2 +#define WMI_HOST_VDEV_SUBTYPE_P2P_GO 0x3 +#define WMI_HOST_VDEV_SUBTYPE_PROXY_STA 0x4 +#define WMI_HOST_VDEV_SUBTYPE_MESH 0x5 + +#define WMI_HOST_MGMT_TID 17 +/* Disable aging & learning */ +#define WMI_HOST_WDS_FLAG_STATIC 0x1 + +/** + * Peer param enum abstracted from target + */ +typedef enum { + /** mimo powersave state */ + WMI_HOST_PEER_MIMO_PS_STATE = 0x1, + /** enable/disable AMPDU . initial value (enabled) */ + WMI_HOST_PEER_AMPDU = 0x2, + /** authorize/unauthorize peer. initial value is unauthorized (0) */ + WMI_HOST_PEER_AUTHORIZE = 0x3, + /** peer channel bandwidth */ + WMI_HOST_PEER_CHWIDTH = 0x4, + /** peer NSS */ + WMI_HOST_PEER_NSS = 0x5, + /** USE 4 ADDR */ + WMI_HOST_PEER_USE_4ADDR = 0x6, + /** Enable extended peer stats */ + WMI_HOST_PEER_EXT_STATS_ENABLE = 0x7, + /*Use FIXED Pwr */ + WMI_HOST_PEER_USE_FIXED_PWR = 0x8, + /* Set peer fixed rate */ + WMI_HOST_PEER_PARAM_FIXED_RATE = 0x9, + /* Whitelist peer TIDs */ + WMI_HOST_PEER_SET_MU_WHITELIST = 0xa, + /* set group membership status */ + WMI_HOST_PEER_MEMBERSHIP = 0xb, + WMI_HOST_PEER_USERPOS = 0xc, +} PEER_PARAM_ENUM; +#define WMI_HOST_PEER_MIMO_PS_NONE 0x0 +#define WMI_HOST_PEER_MIMO_PS_STATIC 0x1 +#define WMI_HOST_PEER_MIMO_PS_DYNAMIC 0x2 +typedef enum { + HOST_PLATFORM_HIGH_PERF, + HOST_PLATFORM_LOW_PERF, +} HOST_PLATFORM_TYPE; + +enum wmi_host_sta_ps_mode { + /** enable power save for the given STA VDEV */ + WMI_HOST_STA_PS_MODE_DISABLED = 0, + /** disable power save for a given STA VDEV */ + WMI_HOST_STA_PS_MODE_ENABLED = 1, +}; +enum wmi_host_sta_powersave_param { + /** + * Controls how frames are retrievd from AP while STA is sleeping + * + * (see enum wmi_sta_ps_param_rx_wake_policy) + */ + WMI_HOST_STA_PS_PARAM_RX_WAKE_POLICY = 0, + + /** + * The STA will go active after this many TX + * + * (see enum wmi_sta_ps_param_tx_wake_threshold) + */ + WMI_HOST_STA_PS_PARAM_TX_WAKE_THRESHOLD = 1, + + /** + * Number of PS-Poll to send before STA wakes up + * + * (see enum wmi_sta_ps_param_pspoll_count) + * + */ + WMI_HOST_STA_PS_PARAM_PSPOLL_COUNT = 2, + + /** + * TX/RX inactivity time in msec before going to sleep. + * + * The power save SM will monitor tx/rx activity on the VDEV, if no + * activity for the specified msec of the parameter + * the Power save SM will go to sleep. + */ + WMI_HOST_STA_PS_PARAM_INACTIVITY_TIME = 3, + + /** + * Set uapsd configuration. + * + * (see enum wmi_sta_ps_param_uapsd) + */ + WMI_HOST_STA_PS_PARAM_UAPSD = 4, +}; +/* prefix used by scan requestor ids on the host + * replicated here form wmi_unified.h*/ +#define WMI_HOST_P_SCAN_REQUESTOR_ID_PREFIX 0xA000 +/* prefix used by scan request ids generated on the host */ +/* host cycles through the lower 12 bits to generate ids */ +#define WMI_HOST_P_SCAN_REQ_ID_PREFIX 0xA000 + +#define WMI_HOST_RC_DS_FLAG 0x01 /* Dual stream flag */ +#define WMI_HOST_RC_CW40_FLAG 0x02 /* CW 40 */ +#define WMI_HOST_RC_SGI_FLAG 0x04 /* Short Guard Interval */ +#define WMI_HOST_RC_HT_FLAG 0x08 /* HT */ +#define WMI_HOST_RC_RTSCTS_FLAG 0x10 /* RTS-CTS */ +#define WMI_HOST_RC_TX_STBC_FLAG 0x20 /* TX STBC */ +#define WMI_HOST_RC_RX_STBC_FLAG 0xC0 /* RX STBC ,2 bits */ +#define WMI_HOST_RC_RX_STBC_FLAG_S 6 /* RX STBC ,2 bits */ +#define WMI_HOST_RC_WEP_TKIP_FLAG 0x100 /* WEP/TKIP encryption */ +#define WMI_HOST_RC_TS_FLAG 0x200 /* Three stream flag */ +#define WMI_HOST_RC_UAPSD_FLAG 0x400 /* UAPSD Rate Control */ + +/** HT Capabilities*/ +#define WMI_HOST_HT_CAP_ENABLED 0x0001 /* HT Enabled/ disabled */ +/* Short Guard Interval with HT20 */ +#define WMI_HOST_HT_CAP_HT20_SGI 0x0002 +#define WMI_HOST_HT_CAP_DYNAMIC_SMPS 0x0004 /* Dynamic MIMO powersave */ +#define WMI_HOST_HT_CAP_TX_STBC 0x0008 /* B3 TX STBC */ +#define WMI_HOST_HT_CAP_TX_STBC_MASK_SHIFT 3 +#define WMI_HOST_HT_CAP_RX_STBC 0x0030 /* B4-B5 RX STBC */ +#define WMI_HOST_HT_CAP_RX_STBC_MASK_SHIFT 4 +#define WMI_HOST_HT_CAP_LDPC 0x0040 /* LDPC supported */ +#define WMI_HOST_HT_CAP_L_SIG_TXOP_PROT 0x0080 /* L-SIG TXOP Protection */ +#define WMI_HOST_HT_CAP_MPDU_DENSITY 0x0700 /* MPDU Density */ +#define WMI_HOST_HT_CAP_MPDU_DENSITY_MASK_SHIFT 8 +#define WMI_HOST_HT_CAP_HT40_SGI 0x0800 +#define WMI_HOST_HT_CAP_IBF_BFER 0x1000 + +/* These macros should be used when we wish to advertise STBC support for + * only 1SS or 2SS or 3SS. */ +#define WMI_HOST_HT_CAP_RX_STBC_1SS 0x0010 /* B4-B5 RX STBC */ +#define WMI_HOST_HT_CAP_RX_STBC_2SS 0x0020 /* B4-B5 RX STBC */ +#define WMI_HOST_HT_CAP_RX_STBC_3SS 0x0030 /* B4-B5 RX STBC */ + + +#define WMI_HOST_HT_CAP_DEFAULT_ALL (WMI_HOST_HT_CAP_ENABLED | \ + WMI_HOST_HT_CAP_HT20_SGI | \ + WMI_HOST_HT_CAP_HT40_SGI | \ + WMI_HOST_HT_CAP_TX_STBC | \ + WMI_HOST_HT_CAP_RX_STBC | \ + WMI_HOST_HT_CAP_LDPC) + +/* WMI_HOST_VHT_CAP_* these maps to ieee 802.11ac vht capability information + field. The fields not defined here are not supported, or reserved. + Do not change these masks and if you have to add new one follow the + bitmask as specified by 802.11ac draft. +*/ + +#define WMI_HOST_VHT_CAP_MAX_MPDU_LEN_MASK 0x00000003 +#define WMI_HOST_VHT_CAP_RX_LDPC 0x00000010 +#define WMI_HOST_VHT_CAP_SGI_80MHZ 0x00000020 +#define WMI_HOST_VHT_CAP_SGI_160MHZ 0x00000040 +#define WMI_HOST_VHT_CAP_TX_STBC 0x00000080 +#define WMI_HOST_VHT_CAP_RX_STBC_MASK 0x00000300 +#define WMI_HOST_VHT_CAP_RX_STBC_MASK_SHIFT 8 +#define WMI_HOST_VHT_CAP_SU_BFER 0x00000800 +#define WMI_HOST_VHT_CAP_SU_BFEE 0x00001000 +#define WMI_HOST_VHT_CAP_MAX_CS_ANT_MASK 0x0000E000 +#define WMI_HOST_VHT_CAP_MAX_CS_ANT_MASK_SHIFT 13 +#define WMI_HOST_VHT_CAP_MAX_SND_DIM_MASK 0x00070000 +#define WMI_HOST_VHT_CAP_MAX_SND_DIM_MASK_SHIFT 16 +#define WMI_HOST_VHT_CAP_MU_BFER 0x00080000 +#define WMI_HOST_VHT_CAP_MU_BFEE 0x00100000 +#define WMI_HOST_VHT_CAP_MAX_AMPDU_LEN_EXP 0x03800000 +#define WMI_HOST_VHT_CAP_MAX_AMPDU_LEN_EXP_SHIT 23 +#define WMI_HOST_VHT_CAP_RX_FIXED_ANT 0x10000000 +#define WMI_HOST_VHT_CAP_TX_FIXED_ANT 0x20000000 + +#define WMI_HOST_VHT_CAP_MAX_MPDU_LEN_11454 0x00000002 + +/* These macros should be used when we wish to advertise STBC support for + * only 1SS or 2SS or 3SS. */ +#define WMI_HOST_VHT_CAP_RX_STBC_1SS 0x00000100 +#define WMI_HOST_VHT_CAP_RX_STBC_2SS 0x00000200 +#define WMI_HOST_VHT_CAP_RX_STBC_3SS 0x00000300 + +#define WMI_HOST_VHT_CAP_DEFAULT_ALL (WMI_HOST_VHT_CAP_MAX_MPDU_LEN_11454 | \ + WMI_HOST_VHT_CAP_SGI_80MHZ | \ + WMI_HOST_VHT_CAP_TX_STBC | \ + WMI_HOST_VHT_CAP_RX_STBC_MASK | \ + WMI_HOST_VHT_CAP_RX_LDPC | \ + WMI_HOST_VHT_CAP_MAX_AMPDU_LEN_EXP | \ + WMI_HOST_VHT_CAP_RX_FIXED_ANT | \ + WMI_HOST_VHT_CAP_TX_FIXED_ANT) + +/* Interested readers refer to Rx/Tx MCS Map definition as defined in + 802.11ac +*/ +#define WMI_HOST_VHT_MAX_MCS_4_SS_MASK(r, ss) ((3 & (r)) << (((ss) - 1) << 1)) +#define WMI_HOST_VHT_MAX_SUPP_RATE_MASK 0x1fff0000 +#define WMI_HOST_VHT_MAX_SUPP_RATE_MASK_SHIFT 16 + +/** U-APSD configuration of peer station from (re)assoc request and TSPECs */ +enum wmi_host_ap_ps_param_uapsd { + WMI_HOST_AP_PS_UAPSD_AC0_DELIVERY_EN = (1 << 0), + WMI_HOST_AP_PS_UAPSD_AC0_TRIGGER_EN = (1 << 1), + WMI_HOST_AP_PS_UAPSD_AC1_DELIVERY_EN = (1 << 2), + WMI_HOST_AP_PS_UAPSD_AC1_TRIGGER_EN = (1 << 3), + WMI_HOST_AP_PS_UAPSD_AC2_DELIVERY_EN = (1 << 4), + WMI_HOST_AP_PS_UAPSD_AC2_TRIGGER_EN = (1 << 5), + WMI_HOST_AP_PS_UAPSD_AC3_DELIVERY_EN = (1 << 6), + WMI_HOST_AP_PS_UAPSD_AC3_TRIGGER_EN = (1 << 7), +}; +/** U-APSD maximum service period of peer station */ +enum wmi_host_ap_ps_peer_param_max_sp { + WMI_HOST_AP_PS_PEER_PARAM_MAX_SP_UNLIMITED = 0, + WMI_HOST_AP_PS_PEER_PARAM_MAX_SP_2 = 1, + WMI_HOST_AP_PS_PEER_PARAM_MAX_SP_4 = 2, + WMI_HOST_AP_PS_PEER_PARAM_MAX_SP_6 = 3, + + /* keep last! */ + MAX_HOST_WMI_AP_PS_PEER_PARAM_MAX_SP, +}; + +#define WMI_HOST_UAPSD_AC_TYPE_DELI 0 +#define WMI_HOST_UAPSD_AC_TYPE_TRIG 1 + +#define WMI_HOST_UAPSD_AC_BIT_MASK(ac, type) \ + ((type == WMI_HOST_UAPSD_AC_TYPE_DELI) ? (1<<(ac<<1)) :\ + (1<<((ac<<1)+1))) + +enum wmi_host_ap_ps_peer_param_wnm_sleep { + WMI_HOST_AP_PS_PEER_PARAM_WNM_SLEEP_ENABLE, + WMI_HOST_AP_PS_PEER_PARAM_WNM_SLEEP_DISABLE, +}; + +enum wmi_host_ap_ps_peer_param { + /** Set uapsd configuration for a given peer. + * + * This will include the delivery and trigger enabled state for every AC. + * The host MLME needs to set this based on AP capability and stations + * request Set in the association request received from the station. + * + * Lower 8 bits of the value specify the UAPSD configuration. + * + * (see enum wmi_ap_ps_param_uapsd) + * The default value is 0. + */ + WMI_HOST_AP_PS_PEER_PARAM_UAPSD = 0, + + /** + * Set the service period for a UAPSD capable station + * + * The service period from wme ie in the (re)assoc request frame. + * + * (see enum wmi_ap_ps_peer_param_max_sp) + */ + WMI_HOST_AP_PS_PEER_PARAM_MAX_SP = 1, + + /** Time in seconds for aging out buffered frames + * for STA in power save */ + WMI_HOST_AP_PS_PEER_PARAM_AGEOUT_TIME = 2, + + /** Specify frame types that are considered SIFS + * RESP trigger frame */ + WMI_HOST_AP_PS_PEER_PARAM_SIFS_RESP_FRMTYPE = 3, + + /** Specifies the trigger state of TID. + * Valid only for UAPSD frame type */ + WMI_HOST_AP_PS_PEER_PARAM_SIFS_RESP_UAPSD = 4, + + /** Specifies the WNM sleep state of a STA */ + WMI_HOST_AP_PS_PEER_PARAM_WNM_SLEEP = 5, +}; +#define WMI_HOST_RXERR_CRC 0x01 /* CRC error on frame */ +#define WMI_HOST_RXERR_DECRYPT 0x08 /* non-Michael decrypt error */ +#define WMI_HOST_RXERR_MIC 0x10 /* Michael MIC decrypt error */ +#define WMI_HOST_RXERR_KEY_CACHE_MISS 0x20 /* No/incorrect key matter in h/w */ + +enum wmi_host_sta_ps_param_uapsd { + WMI_HOST_STA_PS_UAPSD_AC0_DELIVERY_EN = (1 << 0), + WMI_HOST_STA_PS_UAPSD_AC0_TRIGGER_EN = (1 << 1), + WMI_HOST_STA_PS_UAPSD_AC1_DELIVERY_EN = (1 << 2), + WMI_HOST_STA_PS_UAPSD_AC1_TRIGGER_EN = (1 << 3), + WMI_HOST_STA_PS_UAPSD_AC2_DELIVERY_EN = (1 << 4), + WMI_HOST_STA_PS_UAPSD_AC2_TRIGGER_EN = (1 << 5), + WMI_HOST_STA_PS_UAPSD_AC3_DELIVERY_EN = (1 << 6), + WMI_HOST_STA_PS_UAPSD_AC3_TRIGGER_EN = (1 << 7), +}; + +enum wmi_host_sta_ps_param_rx_wake_policy { + /* Wake up when ever there is an RX activity on the VDEV. In this mode + * the Power save SM(state machine) will come out of sleep by either + * sending null frame (or) a data frame (with PS==0) in response to TIM + * bit set in the received beacon frame from AP. + */ + WMI_HOST_STA_PS_RX_WAKE_POLICY_WAKE = 0, + + /* Here the power save state machine will not wakeup in response to TIM + * bit, instead it will send a PSPOLL (or) UASPD trigger based on UAPSD + * configuration setup by WMISET_PS_SET_UAPSD WMI command. When all + * access categories are delivery-enabled, the station will send a UAPSD + * trigger frame, otherwise it will send a PS-Poll. + */ + WMI_HOST_STA_PS_RX_WAKE_POLICY_POLL_UAPSD = 1, +}; +enum wmi_host_sta_ps_param_pspoll_count { + WMI_HOST_STA_PS_PSPOLL_COUNT_NO_MAX = 0, + /* Values greater than 0 indicate the maximum numer of PS-Poll frames FW + * will send before waking up. + */ +}; +/** Number of tx frames/beacon that cause the power save SM to wake up. + * + * Value 1 causes the SM to wake up for every TX. Value 0 has a special + * meaning, It will cause the SM to never wake up. This is useful if you want + * to keep the system to sleep all the time for some kind of test mode . host + * can change this parameter any time. It will affect at the next tx frame. + */ +enum wmi_host_sta_ps_param_tx_wake_threshold { + WMI_HOST_STA_PS_TX_WAKE_THRESHOLD_NEVER = 0, + WMI_HOST_STA_PS_TX_WAKE_THRESHOLD_ALWAYS = 1, + + /* Values greater than one indicate that many TX attempts per beacon + * interval before the STA will wake up + */ +}; +/* + * Transmit power scale factor. + * + */ +typedef enum { + WMI_HOST_TP_SCALE_MAX = 0, /* no scaling (default) */ + WMI_HOST_TP_SCALE_50 = 1, /* 50% of max (-3 dBm) */ + WMI_HOST_TP_SCALE_25 = 2, /* 25% of max (-6 dBm) */ + WMI_HOST_TP_SCALE_12 = 3, /* 12% of max (-9 dBm) */ + WMI_HOST_TP_SCALE_MIN = 4, /* min, but still on */ + WMI_HOST_TP_SCALE_SIZE = 5, /* max num of enum */ +} WMI_HOST_TP_SCALE; +enum { + WMI_HOST_RATEPWR_TABLE_OPS_SET, + WMI_HOST_RATEPWR_TABLE_OPS_GET, +}; +/* reserved up through 0xF */ +/** + * struct wmi_host_dcs_mib_stats - WLAN IM stats from target to host + * Below statistics are sent from target to host periodically. + * These are collected at target as long as target is running + * and target chip is not in sleep. + * @listen_time: + * @reg_tx_frame_cnt: + * @reg_rx_frame_cnt: + * @reg_rxclr_cnt: + * @reg_cycle_cnt: delta cycle count + * @reg_rxclr_ext_cnt: + * @reg_ofdm_phyerr_cnt: + * @reg_cck_phyerr_cnt: CCK err count since last reset, read from register + */ +typedef struct _hp_dcs_mib_stats { + int32_t listen_time; + uint32_t reg_tx_frame_cnt; + uint32_t reg_rx_frame_cnt; + uint32_t reg_rxclr_cnt; + uint32_t reg_cycle_cnt; + uint32_t reg_rxclr_ext_cnt; + uint32_t reg_ofdm_phyerr_cnt; + uint32_t reg_cck_phyerr_cnt; +} wmi_host_dcs_mib_stats_t; + +/** + * struct wmi_host_dcs_im_tgt_stats - DCS IM target stats + * @reg_tsf32: current running TSF from the TSF-1 + * @last_ack_rssi: Known last frame rssi, in case of multiple stations, if + * and at different ranges, this would not gaurantee that + * this is the least rssi. + * @tx_waste_time: Sum of all the failed durations in the last + * one second interval. + * @rx_time: count how many times the hal_rxerr_phy is marked, in this + * time period + * @phyerr_cnt: + * @mib_stats: wmi_host_dcs_mib_stats_t - collected mib stats as explained + * in mib structure + */ +typedef struct _wmi_host_dcs_im_tgt_stats { + uint32_t reg_tsf32; + uint32_t last_ack_rssi; + uint32_t tx_waste_time; + uint32_t rx_time; + uint32_t phyerr_cnt; + wmi_host_dcs_mib_stats_t mib_stats; +} wmi_host_dcs_im_tgt_stats_t; + +/** + * Enum for pktlog req + */ +typedef enum { + WMI_HOST_PKTLOG_EVENT_RX = 0x1, + WMI_HOST_PKTLOG_EVENT_TX = 0x2, + WMI_HOST_PKTLOG_EVENT_RCF = 0x4, /* Rate Control Find */ + WMI_HOST_PKTLOG_EVENT_RCU = 0x8, /* Rate Control Update */ + WMI_HOST_PKTLOG_EVENT_DBG_PRINT = 0x10, /* DEBUG prints */ + /* To support Smart Antenna */ + WMI_HOST_PKTLOG_EVENT_SMART_ANTENNA = 0x20, + WMI_HOST_PKTLOG_EVENT_H_INFO = 0x40, + WMI_HOST_PKTLOG_EVENT_STEERING = 0x80, +} WMI_HOST_PKTLOG_EVENT; + +/** + * wmi_host_phyerr + * + */ +#define WMI_HOST_PHY_ERROR_SPECTRAL_SCAN 0x26 +#define WMI_HOST_PHY_ERROR_FALSE_RADAR_EXT 0x24 + +#define WMI_HOST_AR900B_DFS_PHYERR_MASK 0x4 +#define WMI_HOST_AR900B_SPECTRAL_PHYERR_MASK 0x4000000 + +/** + * struct wmi_host_perchain_rssi_info - per chain RSSI info + * @rssi_pri20: RSSI on primary 20 + * @rssi_sec20: RSSI on secomdary 20 + * @rssi_sec40: RSSI secondary 40 + * @rssi_sec80: RSSI secondary 80 + */ +typedef struct wmi_host_perchain_rssi_info { + int8_t rssi_pri20; + int8_t rssi_sec20; + int8_t rssi_sec40; + int8_t rssi_sec80; +} wmi_host_perchain_rssi_info_t; + +/** + * struct _wmi_host_rf_info - RF measurement information + * @rssi_comb: RSSI Information + * @pc_rssi_info[4]: For now, we know we are getting information + * for only 4 chains at max. For future extensions + * use a define + * @noise_floor: Noise floor information + */ +typedef struct _wmi_host_rf_info { + int8_t rssi_comb; + wmi_host_perchain_rssi_info_t pc_rssi_info[4]; + int16_t noise_floor[4]; +} wmi_host_rf_info_t; + +/** + * struct _wmi_host_chan_info + * @center_freq1: center frequency 1 in MHz + * @center_freq2: center frequency 2 in MHz -valid only for + * 11ACVHT 80PLUS80 mode + * @chan_width: channel width in MHz + */ +typedef struct _wmi_host_chan_info { + u_int16_t center_freq1; + u_int16_t center_freq2; + u_int8_t chan_width; +} wmi_host_chan_info_t; + +/** + * struct wmi_host_phyerr + * @rf_info: + * @chan_info: + * @tsf64: + * @phy_err_code: + * @tsf_timestamp: + * @bufp: + * @buf_len: + * @phy_err_mask0: + * @phy_err_mask1: + */ +typedef struct _wmi_host_phyerr { + wmi_host_rf_info_t rf_info; + wmi_host_chan_info_t chan_info; + uint64_t tsf64; + int32_t phy_err_code; + uint32_t tsf_timestamp; + uint8_t *bufp; + uint32_t buf_len; + uint32_t phy_err_mask0; + uint32_t phy_err_mask1; +} wmi_host_phyerr_t; + +/** + * struct wmi_host_rtt_event_hdr + * @req_id: request id + * @status: status + * @meas_done: measurement done flag + * @meas_type: measurement type + * @report_type: report type + * @v3_status: v2 status + * @v3_finish: + * @v3_tm_start: + * @num_ap: number of AP + * @result: resuult + * @dest_mac: destination mac + */ +typedef struct { + uint16_t req_id; + uint16_t status:1, + meas_done:1, + meas_type:3, + report_type:3, + v3_status:2, + v3_finish:1, + v3_tm_start:1, + num_ap:4; + uint16_t result; + uint8_t dest_mac[IEEE80211_ADDR_LEN]; +} wmi_host_rtt_event_hdr; + +/** + * struct wmi_host_rtt_meas_event - RTT measurement event + * @chain_mask: + * @bw: + * @rsvd: + * @txrxchain_mask: Bit:0-3:chain mask + * Bit 4-5: band width info + * 00 --Legacy 20, 01 --HT/VHT20 + * 10 --HT/VHT40, 11 -- VHT80 + * @tod: resolution of 0.1ns + * @toa: resolution of 0.1ns + * @t3: + * @t4: + * @rssi0: + * @rssi1: + * @rssi2: + * @rssi3: + */ +typedef struct { + uint32_t chain_mask:3, + bw:2, + rsvd:27; + uint32_t txrxchain_mask; + uint64_t tod; + uint64_t toa; + uint64_t t3; + uint64_t t4; + uint32_t rssi0; + uint32_t rssi1; + uint32_t rssi2; + uint32_t rssi3; +} wmi_host_rtt_meas_event; + +/*----RTT Report event definition ----*/ +typedef enum { + /* rtt cmd header parsing error --terminate */ + WMI_HOST_RTT_COMMAND_HEADER_ERROR = 0, + /* rtt body parsing error -- skip current STA REQ */ + WMI_HOST_RTT_COMMAND_ERROR, + /* rtt no resource -- terminate */ + WMI_HOST_RTT_MODULE_BUSY, + /* STA exceed the support limit -- only server the first n STA */ + WMI_HOST_RTT_TOO_MANY_STA, + /* any allocate failure */ + WMI_HOST_RTT_NO_RESOURCE, + /* can not find vdev with vdev ID - skip current STA REQ */ + WMI_HOST_RTT_VDEV_ERROR, + /* Tx failure -- continiue and measure number */ + WMI_HOST_RTT_TRANSIMISSION_ERROR, + /* wait for first TM timer expire-terminate current STA measurement */ + WMI_HOST_RTT_TM_TIMER_EXPIRE, + /* we do not support RTT measurement with this type of frame */ + WMI_HOST_RTT_FRAME_TYPE_NOSUPPORT, + /* whole RTT measurement timer expire-terminate + ** current STA measurement */ + WMI_HOST_RTT_TIMER_EXPIRE, + /* channel swicth failed */ + WMI_HOST_RTT_CHAN_SWITCH_ERROR, + /* TMR trans error, this dest peer will be skipped */ + WMI_HOST_RTT_TMR_TRANS_ERROR, + /* V3 only. If both CFR and Token mismatch, do not report */ + WMI_HOST_RTT_NO_REPORT_BAD_CFR_TOKEN, + /* For First TM, if CFR is bad, then do not report */ + WMI_HOST_RTT_NO_REPORT_FIRST_TM_BAD_CFR, + /* do not allow report type2 mix with type 0, 1 */ + WMI_HOST_RTT_REPORT_TYPE2_MIX, + /* LCI Configuration OK. - Responder only */ + WMI_HOST_RTT_LCI_CFG_OK, + /* LCR configuration OK. - Responder only */ + WMI_HOST_RTT_LCR_CFG_OK, + /* Bad configuration LCI (or) LCR request - Responder only */ + WMI_HOST_RTT_CFG_ERROR, + WMI_HOST_WMI_RTT_REJECT_MAX, +} WMI_HOST_RTT_ERROR_INDICATOR; +typedef struct { + wmi_host_rtt_event_hdr hdr; + WMI_HOST_RTT_ERROR_INDICATOR reject_reason; +} wmi_host_rtt_error_report_event; + +#if defined(AR9888) +typedef enum { + WMI_HOST_PROF_CPU_IDLE, + WMI_HOST_PROF_PPDU_PROC, + WMI_HOST_PROF_PPDU_POST, + WMI_HOST_PROF_HTT_TX_INPUT, + WMI_HOST_PROF_MSDU_ENQ, + WMI_HOST_PROF_PPDU_POST_HAL, + WMI_HOST_PROF_COMPUTE_TX_TIME, + + /* Add new ID's above this. */ + WMI_HOST_PROF_MAX_ID, +} wmi_host_profile_id_t; +#endif + +#define WMI_HOST_WLAN_PROFILE_MAX_HIST 3 +#define WMI_HOST_WLAN_PROFILE_MAX_BIN_CNT 32 + +#if defined(AR9888) +#define WMI_HOST_MAX_PROFILE WMI_HOST_PROF_MAX_ID +#else +#define WMI_HOST_MAX_PROFILE WMI_HOST_WLAN_PROFILE_MAX_BIN_CNT +#endif + +/** + * struct wmi_host_wlan_profile - Host profile param + * @id: profile id + * @cnt: Count + * @tot: + * @min: minimum + * @max: Mac + * @hist_intvl: history interval + * @hist: profile data history + */ +typedef struct { + uint32_t id; + uint32_t cnt; + uint32_t tot; + uint32_t min; + uint32_t max; + uint32_t hist_intvl; + uint32_t hist[WMI_HOST_WLAN_PROFILE_MAX_HIST]; +} wmi_host_wlan_profile_t; + +/** + * struct wmi_host_wlan_profile_ctx_t - profile context + * @tot: time in us + * @tx_msdu_cnt: MSDU TX count + * @tx_mpdu_cnt: MPDU tx count + * @tx_ppdu_cnt: PPDU tx count + * @rx_msdu_cnt: MSDU RX count + * @rx_mpdu_cnt: MPDU RXcount + * @bin_count: Bin count + */ +typedef struct { + uint32_t tot; + uint32_t tx_msdu_cnt; + uint32_t tx_mpdu_cnt; + uint32_t tx_ppdu_cnt; + uint32_t rx_msdu_cnt; + uint32_t rx_mpdu_cnt; + uint32_t bin_count; +} wmi_host_wlan_profile_ctx_t; + +/** + * struct wmi_host_chan_info_event - Channel info WMI event + * @err_code: Error code + * @freq: Channel freq + * @cmd_flags: Read flags + * @noise_floor: Noise Floor value + * @rx_clear_count: rx clear count + * @cycle_count: cycle count + * @chan_tx_pwr_range: channel tx power per range + * @chan_tx_pwr_tp: channel tx power per throughput + * @rx_frame_count: rx frame count + * @rx_11b_mode_data_duration: 11b mode data duration + */ +typedef struct { + uint32_t err_code; + uint32_t freq; + uint32_t cmd_flags; + uint32_t noise_floor; + uint32_t rx_clear_count; + uint32_t cycle_count; + uint32_t chan_tx_pwr_range; + uint32_t chan_tx_pwr_tp; + uint32_t rx_frame_count; + uint32_t rx_11b_mode_data_duration; +} wmi_host_chan_info_event; + +/** + * struct wmi_host_pdev_channel_hopping_event + * @noise_floor_report_iter: Noise threshold iterations with high values + * @noise_floor_total_iter: Total noise threshold iterations + */ +typedef struct { + uint32_t noise_floor_report_iter; + uint32_t noise_floor_total_iter; +} wmi_host_pdev_channel_hopping_event; + +/** + * struct wmi_host_pdev_bss_chan_info_event + * @freq: Units in MHz + * @noise_floor: units are dBm + * @rx_clear_count_low: + * @rx_clear_count_high: + * @cycle_count_low: + * @cycle_count_high: + * @tx_cycle_count_low: + * @tx_cycle_count_high: + * @rx_cycle_count_low: + * @rx_cycle_count_high: + * @rx_bss_cycle_count_low: + * @rx_bss_cycle_count_high: + * @reserved: + */ +typedef struct { + uint32_t freq; + uint32_t noise_floor; + uint32_t rx_clear_count_low; + uint32_t rx_clear_count_high; + uint32_t cycle_count_low; + uint32_t cycle_count_high; + uint32_t tx_cycle_count_low; + uint32_t tx_cycle_count_high; + uint32_t rx_cycle_count_low; + uint32_t rx_cycle_count_high; + uint32_t rx_bss_cycle_count_low; + uint32_t rx_bss_cycle_count_high; + uint32_t reserved; +} wmi_host_pdev_bss_chan_info_event; + +#define WMI_HOST_INST_STATS_INVALID_RSSI 0 +/** + * struct wmi_host_inst_stats_resp + * @iRSSI: Instantaneous RSSI + * @peer_macaddr: peer mac address + */ +typedef struct { + uint32_t iRSSI; + wmi_host_mac_addr peer_macaddr; +} wmi_host_inst_stats_resp; + +/* Event definition and new structure addition to send event + * to host to block/unblock tx data traffic based on peer_ast_idx or vdev id + */ +#define WMI_HOST_INVALID_PEER_AST_INDEX 0xffff +#define WMI_HOST_TX_DATA_TRAFFIC_CTRL_BLOCK 0x1 +#define WMI_HOST_TX_DATA_TRAFFIC_CTRL_UNBLOCK 0x2 +/** + * struct wmi_host_tx_data_traffic_ctrl_event + * @peer_ast_idx: For vdev based control, peer_ast_idx will be + * WMI_INVALID_PEER_AST_INDEX + * @vdev_id: only applies if peer_ast_idx == INVALID + * @ctrl_cmd: WMI_TX_DATA_TRAFFIC_CTRL_BLOCK or + * WMI_TX_DATA_TRAFFIC_CTRL_UNBLOCK + */ +typedef struct { + uint32_t peer_ast_idx; + uint32_t vdev_id; + uint32_t ctrl_cmd; +} wmi_host_tx_data_traffic_ctrl_event; + +/** + * struct wmi_host_ath_dcs_cw_int + * @channel: either number or freq in mhz + */ +typedef struct { + uint32_t channel; +} wmi_host_ath_dcs_cw_int; + +#define WMI_MAX_POWER_DBG_ARGS 8 + +/** + * struct wmi_power_dbg_params - power debug command parameter + * @pdev_id: subsystem identifier + * @module_id: parameter id + * @num_arg: no of arguments + * @args: arguments + */ +struct wmi_power_dbg_params { + uint32_t pdev_id; + uint32_t module_id; + uint32_t num_args; + uint32_t args[WMI_MAX_POWER_DBG_ARGS]; +}; + +/** + * struct wmi_adaptive_dwelltime_params - the adaptive dwelltime params + * @vdev_id: vdev id + * @is_enabled: Adaptive dwell time is enabled/disabled + * @dwelltime_mode: global default adaptive dwell mode + * @lpf_weight: weight to calculate the average low pass + * filter for channel congestion + * @passive_mon_intval: intval to monitor wifi activity in passive scan in msec + * @wifi_act_threshold: % of wifi activity used in passive scan 0-100 + * + */ +struct wmi_adaptive_dwelltime_params { + uint32_t vdev_id; + bool is_enabled; + enum wmi_dwelltime_adaptive_mode dwelltime_mode; + uint8_t lpf_weight; + uint8_t passive_mon_intval; + uint8_t wifi_act_threshold; +}; + +/** + * struct wmi_per_roam_config - per based roaming parameters + * @enable: if PER based roaming is enabled/disabled + * @tx_high_rate_thresh: high rate threshold at which PER based + * roam will stop in tx path + * @rx_high_rate_thresh: high rate threshold at which PER based + * roam will stop in rx path + * @tx_low_rate_thresh: rate below which traffic will be considered + * for PER based roaming in Tx path + * @rx_low_rate_thresh: rate below which traffic will be considered + * for PER based roaming in Tx path + * @tx_rate_thresh_percnt: % above which when traffic is below low_rate_thresh + * will be considered for PER based scan in tx path + * @rx_rate_thresh_percnt: % above which when traffic is below low_rate_thresh + * will be considered for PER based scan in rx path + * @per_rest_time: time for which PER based roam will wait once it + * issues a roam scan. + * @tx_per_mon_time: Minimum time required to be considered as valid scenario + * for PER based roam in tx path + * @rx_per_mon_time: Minimum time required to be considered as valid scenario + * for PER based roam in rx path + */ +struct wmi_per_roam_config { + uint32_t enable; + uint32_t tx_high_rate_thresh; + uint32_t rx_high_rate_thresh; + uint32_t tx_low_rate_thresh; + uint32_t rx_low_rate_thresh; + uint32_t tx_rate_thresh_percnt; + uint32_t rx_rate_thresh_percnt; + uint32_t per_rest_time; + uint32_t tx_per_mon_time; + uint32_t rx_per_mon_time; + uint32_t min_candidate_rssi; +}; + +/** + * struct wmi_per_roam_config_req: PER based roaming config request + * @vdev_id: vdev id on which config needs to be set + * @per_config: PER config + */ +struct wmi_per_roam_config_req { + uint8_t vdev_id; + struct wmi_per_roam_config per_config; +}; + +/** + * struct wmi_fw_dump_seg_req - individual segment details + * @seg_id - segment id. + * @seg_start_addr_lo - lower address of the segment. + * @seg_start_addr_hi - higher address of the segment. + * @seg_length - length of the segment. + * @dst_addr_lo - lower address of the destination buffer. + * @dst_addr_hi - higher address of the destination buffer. + * + * This structure carries the information to firmware about the + * individual segments. This structure is part of firmware memory + * dump request. + */ +struct wmi_fw_dump_seg_req { + uint8_t seg_id; + uint32_t seg_start_addr_lo; + uint32_t seg_start_addr_hi; + uint32_t seg_length; + uint32_t dst_addr_lo; + uint32_t dst_addr_hi; +}; + +/** + * enum wmi_userspace_log_level - Log level at userspace + * @WMI_LOG_LEVEL_NO_COLLECTION: verbose_level 0 corresponds to no collection + * @WMI_LOG_LEVEL_NORMAL_COLLECT: verbose_level 1 correspond to normal log + * level with minimal user impact. This is the default value. + * @WMI_LOG_LEVEL_ISSUE_REPRO: verbose_level 2 are enabled when user is lazily + * trying to reproduce a problem, wifi performances and power can be impacted + * but device should not otherwise be significantly impacted + * @WMI_LOG_LEVEL_ACTIVE: verbose_level 3+ are used when trying to + * actively debug a problem + * + * Various log levels defined in the userspace for logging applications + */ +enum wmi_userspace_log_level { + WMI_LOG_LEVEL_NO_COLLECTION, + WMI_LOG_LEVEL_NORMAL_COLLECT, + WMI_LOG_LEVEL_ISSUE_REPRO, + WMI_LOG_LEVEL_ACTIVE, +}; + +/** + * struct encrypt_decrypt_req_params - encrypt/decrypt params + * @vdev_id: virtual device id + * @key_flag: This indicates firmware to encrypt/decrypt payload + * see ENCRYPT_DECRYPT_FLAG + * @key_idx: Index used in storing key + * @key_cipher: cipher used for encryption/decryption + * Eg: see WMI_CIPHER_AES_CCM for CCMP + * @key_len: length of key data + * @key_txmic_len: length of Tx MIC + * @key_rxmic_len: length of Rx MIC + * @key_data: Key + * @pn: packet number + * @mac_header: MAC header + * @data_len: length of data + * @data: pointer to payload + */ +struct encrypt_decrypt_req_params { + uint32_t vdev_id; + uint8_t key_flag; + uint32_t key_idx; + uint32_t key_cipher; + uint32_t key_len; + uint32_t key_txmic_len; + uint32_t key_rxmic_len; + uint8_t key_data[MAC_MAX_KEY_LENGTH]; + uint8_t pn[MAC_PN_LENGTH]; + uint8_t mac_header[MAX_MAC_HEADER_LEN]; + uint32_t data_len; + uint8_t *data; +}; + +#define MAX_SAR_LIMIT_ROWS_SUPPORTED 64 +/** + * struct sar_limit_cmd_row - sar limts row + * @band_id: Optional param for frequency band + * @chain_id: Optional param for antenna chain id + * @mod_id: Optional param for modulation scheme + * @limit_value: Mandatory param providing power limits in steps of 0.5 dbm + * @validity_bitmap: bitmap of valid optional params in sar_limit_cmd_row struct + */ +struct sar_limit_cmd_row { + uint32_t band_id; + uint32_t chain_id; + uint32_t mod_id; + uint32_t limit_value; + uint32_t validity_bitmap; +}; + +/** + * struct sar_limit_cmd_params - sar limts params + * @sar_enable: flag to enable SAR + * @num_limit_rows: number of items in sar_limits + * @commit_limits: indicates firmware to start apply new SAR values + * @sar_limit_row_list: pointer to array of sar limit rows + */ +struct sar_limit_cmd_params { + uint32_t sar_enable; + uint32_t num_limit_rows; + uint32_t commit_limits; + struct sar_limit_cmd_row *sar_limit_row_list; +}; + +/** + * enum rcpi_measurement_type - for identifying type of rcpi measurement + * @RCPI_MEASUREMENT_TYPE_AVG_MGMT: avg rcpi of mgmt frames + * @RCPI_MEASUREMENT_TYPE_AVG_DATA: avg rcpi of data frames + * @RCPI_MEASUREMENT_TYPE_LAST_MGMT: rcpi of last mgmt frame + * @RCPI_MEASUREMENT_TYPE_LAST_DATA: rcpi of last data frame + * + */ +enum rcpi_measurement_type { + RCPI_MEASUREMENT_TYPE_AVG_MGMT = 0x1, + RCPI_MEASUREMENT_TYPE_AVG_DATA = 0x2, + RCPI_MEASUREMENT_TYPE_LAST_MGMT = 0x3, + RCPI_MEASUREMENT_TYPE_LAST_DATA = 0x4, +}; + +/** + * struct rcpi_req - rcpi parameter + * @vdev_id: virtual device id + * @measurement_type: type of rcpi from enum wmi_rcpi_measurement_type + * @mac_addr: peer mac addr for which measurement is required + */ +struct rcpi_req { + uint32_t vdev_id; + enum rcpi_measurement_type measurement_type; + uint8_t mac_addr[IEEE80211_ADDR_LEN]; +}; + +#define WMI_SUPPORTED_ACTION_CATEGORY 256 +#define WMI_SUPPORTED_ACTION_CATEGORY_ELE_LIST (WMI_SUPPORTED_ACTION_CATEGORY/32) + +/** + * struct action_wakeup_set_param - action wakeup set params + * @vdev_id: virtual device id + * @operation: 0 reset to fw default, 1 set the bits, + * 2 add the setting bits, 3 delete the setting bits + * @action_category_map: bit mapping. + */ +struct action_wakeup_set_param { + uint32_t vdev_id; + uint32_t operation; + uint32_t action_category_map[WMI_SUPPORTED_ACTION_CATEGORY_ELE_LIST]; +}; + +/** + * struct set_arp_stats - set/reset arp stats + * @vdev_id: vdev_id + * @flag: enable/disable stats + * @pkt_type: type of packet(1 - arp) + * @ip_addr: subnet ipv4 address in case of encrypted packets + */ +struct set_arp_stats { + uint32_t vdev_id; + uint8_t flag; + uint8_t pkt_type; + uint32_t ip_addr; +}; + +/** + * struct get_arp_stats - get arp stats from firmware + * @pkt_type: packet type(1 - ARP) + * @vdev_id: vdev_id + */ +struct get_arp_stats { + uint8_t pkt_type; + uint32_t vdev_id; +}; + +#endif /* _WMI_UNIFIED_PARAM_H_ */ diff --git a/drivers/staging/qca-wifi-host-cmn/wmi/inc/wmi_unified_priv.h b/drivers/staging/qca-wifi-host-cmn/wmi/inc/wmi_unified_priv.h new file mode 100644 index 0000000000000000000000000000000000000000..03d9eb16782aad5ed2a961c37f1b727d3981059e --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/wmi/inc/wmi_unified_priv.h @@ -0,0 +1,1267 @@ +/* + * Copyright (c) 2013-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * This file contains the API definitions for the Unified Wireless + * Module Interface (WMI). + */ +#ifndef _WMI_UNIFIED_PRIV_H_ +#define _WMI_UNIFIED_PRIV_H_ +#include +#include "a_types.h" +#include "wmi_unified_param.h" +#include "qdf_atomic.h" + +#define WMI_UNIFIED_MAX_EVENT 0x100 +#define WMI_MAX_CMDS 1024 + +typedef qdf_nbuf_t wmi_buf_t; + +#ifdef WMI_INTERFACE_EVENT_LOGGING + +#define WMI_EVENT_DEBUG_MAX_ENTRY (1024) +#define WMI_EVENT_DEBUG_ENTRY_MAX_LENGTH (16) +/* wmi_mgmt commands */ +#define WMI_MGMT_EVENT_DEBUG_MAX_ENTRY (256) + +/** + * struct wmi_command_debug - WMI command log buffer data type + * @ command - Store WMI Command id + * @ data - Stores WMI command data + * @ time - Time of WMI command handling + */ +struct wmi_command_debug { + uint32_t command; + /*16 bytes of WMI cmd excluding TLV and WMI headers */ + uint32_t data[WMI_EVENT_DEBUG_ENTRY_MAX_LENGTH/sizeof(uint32_t)]; + uint64_t time; +}; + +/** + * struct wmi_event_debug - WMI event log buffer data type + * @ command - Store WMI Event id + * @ data - Stores WMI Event data + * @ time - Time of WMI Event handling + */ +struct wmi_event_debug { + uint32_t event; + /*16 bytes of WMI event data excluding TLV header */ + uint32_t data[WMI_EVENT_DEBUG_ENTRY_MAX_LENGTH/sizeof(uint32_t)]; + uint64_t time; +}; + +/** + * struct wmi_command_header - Type for accessing frame data + * @ type - 802.11 Frame type + * @ subType - 802.11 Frame subtype + * @ protVer - 802.11 Version + */ +struct wmi_command_header { +#ifndef ANI_LITTLE_BIT_ENDIAN + + uint32_t sub_type:4; + uint32_t type:2; + uint32_t prot_ver:2; + +#else + + uint32_t prot_ver:2; + uint32_t type:2; + uint32_t sub_type:4; + +#endif +}; + +/** + * struct wmi_log_buf_t - WMI log buffer information type + * @buf - Refernce to WMI log buffer + * @ length - length of buffer + * @ buf_tail_idx - Tail index of buffer + * @ p_buf_tail_idx - refernce to buffer tail index. It is added to accommodate + * unified design since MCL uses global variable for buffer tail index + */ +struct wmi_log_buf_t { + void *buf; + uint32_t length; + uint32_t buf_tail_idx; + uint32_t *p_buf_tail_idx; +}; + +/** + * struct wmi_debug_log_info - Meta data to hold information of all buffers + * used for WMI logging + * @wmi_command_log_buf_info - Buffer info for WMI Command log + * @wmi_command_tx_cmp_log_buf_info - Buffer info for WMI Command Tx completion + * log + * @wmi_event_log_buf_info - Buffer info for WMI Event log + * @wmi_rx_event_log_buf_info - Buffer info for WMI event received log + * @wmi_mgmt_command_log_buf_info - Buffer info for WMI Management Command log + * @wmi_mgmt_command_tx_cmp_log_buf_info - Buffer info for WMI Management + * Command Tx completion log + * @wmi_mgmt_event_log_buf_info - Buffer info for WMI Management event log + * @wmi_record_lock - Lock WMI recording + * @wmi_logging_enable - Enable/Disable state for WMI logging + * @buf_offset_command - Offset from where WMI command data should be logged + * @buf_offset_event - Offset from where WMI event data should be logged + * @is_management_record - Function refernce to check if command/event is + * management record + * @wmi_id_to_name - Function refernce to API to convert Command id to + * string name + * @wmi_log_debugfs_dir - refernce to debugfs directory + */ +struct wmi_debug_log_info { + struct wmi_log_buf_t wmi_command_log_buf_info; + struct wmi_log_buf_t wmi_command_tx_cmp_log_buf_info; + + struct wmi_log_buf_t wmi_event_log_buf_info; + struct wmi_log_buf_t wmi_rx_event_log_buf_info; + + struct wmi_log_buf_t wmi_mgmt_command_log_buf_info; + struct wmi_log_buf_t wmi_mgmt_command_tx_cmp_log_buf_info; + struct wmi_log_buf_t wmi_mgmt_event_log_buf_info; + + qdf_spinlock_t wmi_record_lock; + bool wmi_logging_enable; + uint32_t buf_offset_command; + uint32_t buf_offset_event; + bool (*is_management_record)(uint32_t cmd_id); + uint8_t *(*wmi_id_to_name)(uint32_t cmd_id); + struct dentry *wmi_log_debugfs_dir; + uint8_t wmi_instance_id; +}; + +#endif /*WMI_INTERFACE_EVENT_LOGGING */ + +#ifdef WLAN_OPEN_SOURCE +struct fwdebug { + struct sk_buff_head fwlog_queue; + struct completion fwlog_completion; + A_BOOL fwlog_open; +}; +#endif /* WLAN_OPEN_SOURCE */ + +struct wmi_ops { +QDF_STATUS (*send_vdev_create_cmd)(wmi_unified_t wmi_handle, + uint8_t macaddr[IEEE80211_ADDR_LEN], + struct vdev_create_params *param); + +QDF_STATUS (*send_vdev_delete_cmd)(wmi_unified_t wmi_handle, + uint8_t if_id); + +QDF_STATUS (*send_vdev_stop_cmd)(wmi_unified_t wmi, + uint8_t vdev_id); + +QDF_STATUS (*send_conf_hw_filter_mode_cmd)(wmi_unified_t wmi, uint8_t vdev_id, + uint8_t mode_bitmap); + +QDF_STATUS (*send_vdev_down_cmd)(wmi_unified_t wmi, + uint8_t vdev_id); + +QDF_STATUS (*send_vdev_start_cmd)(wmi_unified_t wmi, + struct vdev_start_params *req); + +QDF_STATUS (*send_hidden_ssid_vdev_restart_cmd)(wmi_unified_t wmi_handle, + struct hidden_ssid_vdev_restart_params *restart_params); + +QDF_STATUS (*send_peer_flush_tids_cmd)(wmi_unified_t wmi, + uint8_t peer_addr[IEEE80211_ADDR_LEN], + struct peer_flush_params *param); + +QDF_STATUS (*send_peer_delete_cmd)(wmi_unified_t wmi, + uint8_t peer_addr[IEEE80211_ADDR_LEN], + uint8_t vdev_id); + +QDF_STATUS (*send_peer_param_cmd)(wmi_unified_t wmi, + uint8_t peer_addr[IEEE80211_ADDR_LEN], + struct peer_set_params *param); + +QDF_STATUS (*send_vdev_up_cmd)(wmi_unified_t wmi, + uint8_t bssid[IEEE80211_ADDR_LEN], + struct vdev_up_params *params); + +QDF_STATUS (*send_peer_create_cmd)(wmi_unified_t wmi, + struct peer_create_params *param); + +QDF_STATUS (*send_green_ap_ps_cmd)(wmi_unified_t wmi_handle, + uint32_t value, uint8_t mac_id); + +QDF_STATUS +(*send_pdev_utf_cmd)(wmi_unified_t wmi_handle, + struct pdev_utf_params *param, + uint8_t mac_id); + +QDF_STATUS +(*send_pdev_param_cmd)(wmi_unified_t wmi_handle, + struct pdev_params *param, + uint8_t mac_id); + +QDF_STATUS (*send_suspend_cmd)(wmi_unified_t wmi_handle, + struct suspend_params *param, + uint8_t mac_id); + +QDF_STATUS (*send_resume_cmd)(wmi_unified_t wmi_handle, + uint8_t mac_id); + +QDF_STATUS (*send_wow_enable_cmd)(wmi_unified_t wmi_handle, + struct wow_cmd_params *param, + uint8_t mac_id); + +QDF_STATUS (*send_set_ap_ps_param_cmd)(wmi_unified_t wmi_handle, + uint8_t *peer_addr, + struct ap_ps_params *param); + +QDF_STATUS (*send_set_sta_ps_param_cmd)(wmi_unified_t wmi_handle, + struct sta_ps_params *param); + +QDF_STATUS (*send_crash_inject_cmd)(wmi_unified_t wmi_handle, + struct crash_inject *param); + +QDF_STATUS +(*send_dbglog_cmd)(wmi_unified_t wmi_handle, + struct dbglog_params *dbglog_param); + +QDF_STATUS (*send_vdev_set_param_cmd)(wmi_unified_t wmi_handle, + struct vdev_set_params *param); + +QDF_STATUS (*send_stats_request_cmd)(wmi_unified_t wmi_handle, + uint8_t macaddr[IEEE80211_ADDR_LEN], + struct stats_request_params *param); + +#ifdef CONFIG_WIN +QDF_STATUS (*send_packet_log_enable_cmd)(wmi_unified_t wmi_handle, + WMI_HOST_PKTLOG_EVENT PKTLOG_EVENT); +#else +QDF_STATUS (*send_packet_log_enable_cmd)(wmi_unified_t wmi_handle, + uint8_t macaddr[IEEE80211_ADDR_LEN], + struct packet_enable_params *param); +#endif + +QDF_STATUS (*send_packet_log_disable_cmd)(wmi_unified_t wmi_handle); + +QDF_STATUS (*send_beacon_send_cmd)(wmi_unified_t wmi_handle, + struct beacon_params *param); + +QDF_STATUS (*send_beacon_tmpl_send_cmd)(wmi_unified_t wmi_handle, + struct beacon_tmpl_params *param); + +QDF_STATUS (*send_peer_assoc_cmd)(wmi_unified_t wmi_handle, + struct peer_assoc_params *param); + +QDF_STATUS (*send_scan_start_cmd)(wmi_unified_t wmi_handle, + struct scan_start_params *param); + +QDF_STATUS (*send_scan_stop_cmd)(wmi_unified_t wmi_handle, + struct scan_stop_params *param); + +QDF_STATUS (*send_scan_chan_list_cmd)(wmi_unified_t wmi_handle, + struct scan_chan_list_params *param); + +QDF_STATUS (*send_mgmt_cmd)(wmi_unified_t wmi_handle, + struct wmi_mgmt_params *param); + +QDF_STATUS (*send_modem_power_state_cmd)(wmi_unified_t wmi_handle, + uint32_t param_value); + +QDF_STATUS (*send_set_sta_ps_mode_cmd)(wmi_unified_t wmi_handle, + uint32_t vdev_id, uint8_t val); + +QDF_STATUS (*send_get_temperature_cmd)(wmi_unified_t wmi_handle); + +QDF_STATUS (*send_set_p2pgo_oppps_req_cmd)(wmi_unified_t wmi_handle, + struct p2p_ps_params *oppps); + +QDF_STATUS (*send_set_p2pgo_noa_req_cmd)(wmi_unified_t wmi_handle, + struct p2p_ps_params *noa); + +QDF_STATUS (*send_set_smps_params_cmd)(wmi_unified_t wmi_handle, + uint8_t vdev_id, + int value); + +QDF_STATUS (*send_set_mimops_cmd)(wmi_unified_t wmi_handle, + uint8_t vdev_id, int value); + +QDF_STATUS (*send_set_sta_uapsd_auto_trig_cmd)(wmi_unified_t wmi_handle, + struct sta_uapsd_trig_params *param); + +QDF_STATUS (*send_ocb_set_utc_time_cmd)(wmi_unified_t wmi_handle, + struct ocb_utc_param *utc); + +QDF_STATUS (*send_ocb_get_tsf_timer_cmd)(wmi_unified_t wmi_handle, + uint8_t vdev_id); + +QDF_STATUS (*send_ocb_start_timing_advert_cmd)(wmi_unified_t wmi_handle, + struct ocb_timing_advert_param *timing_advert); + +QDF_STATUS (*send_ocb_stop_timing_advert_cmd)(wmi_unified_t wmi_handle, + struct ocb_timing_advert_param *timing_advert); + +QDF_STATUS (*send_dcc_get_stats_cmd)(wmi_unified_t wmi_handle, + struct dcc_get_stats_param *get_stats_param); + +QDF_STATUS (*send_dcc_clear_stats_cmd)(wmi_unified_t wmi_handle, + uint32_t vdev_id, uint32_t dcc_stats_bitmap); + +QDF_STATUS (*send_dcc_update_ndl_cmd)(wmi_unified_t wmi_handle, + struct dcc_update_ndl_param *update_ndl_param); + +QDF_STATUS (*send_ocb_set_config_cmd)(wmi_unified_t wmi_handle, + struct ocb_config_param *config, uint32_t *ch_mhz); + +QDF_STATUS (*send_lro_config_cmd)(wmi_unified_t wmi_handle, + struct wmi_lro_config_cmd_t *wmi_lro_cmd); + +QDF_STATUS (*send_set_thermal_mgmt_cmd)(wmi_unified_t wmi_handle, + struct thermal_cmd_params *thermal_info); + +QDF_STATUS (*send_peer_rate_report_cmd)(wmi_unified_t wmi_handle, + struct wmi_peer_rate_report_params *rate_report_params); + +QDF_STATUS (*send_set_mcc_channel_time_quota_cmd) + (wmi_unified_t wmi_handle, + uint32_t adapter_1_chan_freq, + uint32_t adapter_1_quota, uint32_t adapter_2_chan_freq); + +QDF_STATUS (*send_set_mcc_channel_time_latency_cmd) + (wmi_unified_t wmi_handle, + uint32_t mcc_channel_freq, uint32_t mcc_channel_time_latency); + +QDF_STATUS (*send_set_enable_disable_mcc_adaptive_scheduler_cmd)( + wmi_unified_t wmi_handle, uint32_t mcc_adaptive_scheduler, + uint32_t pdev_id); + +QDF_STATUS (*send_p2p_go_set_beacon_ie_cmd)(wmi_unified_t wmi_handle, + A_UINT32 vdev_id, uint8_t *p2p_ie); + +QDF_STATUS (*send_probe_rsp_tmpl_send_cmd)(wmi_unified_t wmi_handle, + uint8_t vdev_id, + struct wmi_probe_resp_params *probe_rsp_info, + uint8_t *frm); + +QDF_STATUS (*send_setup_install_key_cmd)(wmi_unified_t wmi_handle, + struct set_key_params *key_params); + +QDF_STATUS (*send_vdev_set_gtx_cfg_cmd)(wmi_unified_t wmi_handle, + uint32_t if_id, + struct wmi_gtx_config *gtx_info); + +QDF_STATUS (*send_set_sta_keep_alive_cmd)(wmi_unified_t wmi_handle, + struct sta_params *params); + +QDF_STATUS (*send_set_sta_sa_query_param_cmd)(wmi_unified_t wmi_handle, + uint8_t vdev_id, uint32_t max_retries, + uint32_t retry_interval); + +QDF_STATUS (*send_set_gateway_params_cmd)(wmi_unified_t wmi_handle, + struct gateway_update_req_param *req); + +QDF_STATUS (*send_set_rssi_monitoring_cmd)(wmi_unified_t wmi_handle, + struct rssi_monitor_param *req); + +QDF_STATUS (*send_scan_probe_setoui_cmd)(wmi_unified_t wmi_handle, + struct scan_mac_oui *psetoui); + +QDF_STATUS (*send_reset_passpoint_network_list_cmd)(wmi_unified_t wmi_handle, + struct wifi_passpoint_req_param *req); + +QDF_STATUS (*send_roam_scan_offload_rssi_thresh_cmd)(wmi_unified_t wmi_handle, + struct roam_offload_scan_rssi_params *roam_req); + +QDF_STATUS (*send_roam_scan_filter_cmd)(wmi_unified_t wmi_handle, + struct roam_scan_filter_params *roam_req); + +QDF_STATUS (*send_set_passpoint_network_list_cmd)(wmi_unified_t wmi_handle, + struct wifi_passpoint_req_param *req); + +QDF_STATUS (*send_set_epno_network_list_cmd)(wmi_unified_t wmi_handle, + struct wifi_enhanched_pno_params *req); + +QDF_STATUS (*send_extscan_get_capabilities_cmd)(wmi_unified_t wmi_handle, + struct extscan_capabilities_params *pgetcapab); + +QDF_STATUS (*send_extscan_get_cached_results_cmd)(wmi_unified_t wmi_handle, + struct extscan_cached_result_params *pcached_results); + +QDF_STATUS (*send_extscan_stop_change_monitor_cmd)(wmi_unified_t wmi_handle, + struct extscan_capabilities_reset_params *reset_req); + +QDF_STATUS (*send_extscan_start_change_monitor_cmd)(wmi_unified_t wmi_handle, + struct extscan_set_sig_changereq_params * + psigchange); + +QDF_STATUS (*send_extscan_stop_hotlist_monitor_cmd)(wmi_unified_t wmi_handle, + struct extscan_bssid_hotlist_reset_params *photlist_reset); + +QDF_STATUS (*send_stop_extscan_cmd)(wmi_unified_t wmi_handle, + struct extscan_stop_req_params *pstopcmd); + +QDF_STATUS (*send_start_extscan_cmd)(wmi_unified_t wmi_handle, + struct wifi_scan_cmd_req_params *pstart); + +QDF_STATUS (*send_plm_stop_cmd)(wmi_unified_t wmi_handle, + const struct plm_req_params *plm); + + +QDF_STATUS (*send_plm_start_cmd)(wmi_unified_t wmi_handle, + const struct plm_req_params *plm, + uint32_t *gchannel_list); + +QDF_STATUS (*send_csa_offload_enable_cmd)(wmi_unified_t wmi_handle, + uint8_t vdev_id); + +QDF_STATUS (*send_pno_stop_cmd)(wmi_unified_t wmi_handle, uint8_t vdev_id); + +#ifdef FEATURE_WLAN_SCAN_PNO +QDF_STATUS (*send_pno_start_cmd)(wmi_unified_t wmi_handle, + struct pno_scan_req_params *pno, + uint32_t *gchannel_freq_list); +#endif + +QDF_STATUS (*send_ipa_offload_control_cmd)(wmi_unified_t wmi_handle, + struct ipa_offload_control_params *ipa_offload); + +QDF_STATUS (*send_set_ric_req_cmd)(wmi_unified_t wmi_handle, void *msg, + uint8_t is_add_ts); + +QDF_STATUS (*send_process_ll_stats_clear_cmd) + (wmi_unified_t wmi_handle, + const struct ll_stats_clear_params *clear_req, + uint8_t addr[IEEE80211_ADDR_LEN]); + +QDF_STATUS (*send_process_ll_stats_set_cmd) + (wmi_unified_t wmi_handle, const struct ll_stats_set_params *set_req); + +QDF_STATUS (*send_process_ll_stats_get_cmd) + (wmi_unified_t wmi_handle, const struct ll_stats_get_params *get_req, + uint8_t addr[IEEE80211_ADDR_LEN]); + +QDF_STATUS (*send_get_stats_cmd)(wmi_unified_t wmi_handle, + struct pe_stats_req *get_stats_param, + uint8_t addr[IEEE80211_ADDR_LEN]); + +QDF_STATUS (*send_congestion_cmd)(wmi_unified_t wmi_handle, + A_UINT8 vdev_id); + +QDF_STATUS (*send_snr_request_cmd)(wmi_unified_t wmi_handle); + +QDF_STATUS (*send_snr_cmd)(wmi_unified_t wmi_handle, uint8_t vdev_id); + +QDF_STATUS (*send_link_status_req_cmd)(wmi_unified_t wmi_handle, + struct link_status_params *link_status); +#ifdef CONFIG_MCL +QDF_STATUS (*send_lphb_config_hbenable_cmd)(wmi_unified_t wmi_handle, + wmi_hb_set_enable_cmd_fixed_param *params); + +QDF_STATUS (*send_lphb_config_tcp_params_cmd)(wmi_unified_t wmi_handle, + wmi_hb_set_tcp_params_cmd_fixed_param *lphb_conf_req); + +QDF_STATUS (*send_lphb_config_tcp_pkt_filter_cmd)(wmi_unified_t wmi_handle, + wmi_hb_set_tcp_pkt_filter_cmd_fixed_param *g_hb_tcp_filter_fp); + +QDF_STATUS (*send_lphb_config_udp_params_cmd)(wmi_unified_t wmi_handle, + wmi_hb_set_udp_params_cmd_fixed_param *lphb_conf_req); + +QDF_STATUS (*send_lphb_config_udp_pkt_filter_cmd)(wmi_unified_t wmi_handle, + wmi_hb_set_udp_pkt_filter_cmd_fixed_param *lphb_conf_req); + +QDF_STATUS (*send_process_dhcp_ind_cmd)(wmi_unified_t wmi_handle, + wmi_peer_set_param_cmd_fixed_param *ta_dhcp_ind); + +QDF_STATUS (*send_get_link_speed_cmd)(wmi_unified_t wmi_handle, + wmi_mac_addr peer_macaddr); + +QDF_STATUS (*send_egap_conf_params_cmd)(wmi_unified_t wmi_handle, + wmi_ap_ps_egap_param_cmd_fixed_param *egap_params); + +QDF_STATUS (*send_process_update_edca_param_cmd)(wmi_unified_t wmi_handle, + uint8_t vdev_id, + wmi_wmm_vparams gwmm_param[WMI_MAX_NUM_AC]); + +QDF_STATUS (*send_bcn_buf_ll_cmd)(wmi_unified_t wmi_handle, + wmi_bcn_send_from_host_cmd_fixed_param * param); + +QDF_STATUS (*send_roam_scan_offload_mode_cmd)(wmi_unified_t wmi_handle, + wmi_start_scan_cmd_fixed_param * scan_cmd_fp, + struct roam_offload_scan_params *roam_req); + +QDF_STATUS (*send_roam_scan_offload_ap_profile_cmd)(wmi_unified_t wmi_handle, + wmi_ap_profile * ap_profile_p, + uint32_t vdev_id); + +QDF_STATUS (*send_pktlog_wmi_send_cmd)(wmi_unified_t wmi_handle, + WMI_PKTLOG_EVENT pktlog_event, + WMI_CMD_ID cmd_id, uint8_t user_triggered); +#endif + +QDF_STATUS (*send_action_frame_patterns_cmd)(wmi_unified_t wmi_handle, + struct action_wakeup_set_param *action_params); + +QDF_STATUS (*send_fw_profiling_cmd)(wmi_unified_t wmi_handle, + uint32_t cmd, uint32_t value1, uint32_t value2); + +QDF_STATUS (*send_wow_sta_ra_filter_cmd)(wmi_unified_t wmi_handle, + uint8_t vdev_id, uint8_t default_pattern, + uint16_t rate_limit_interval); + +QDF_STATUS (*send_nat_keepalive_en_cmd)(wmi_unified_t wmi_handle, uint8_t vdev_id); + +QDF_STATUS (*send_start_oem_data_cmd)(wmi_unified_t wmi_handle, + uint32_t data_len, + uint8_t *data); + +QDF_STATUS +(*send_dfs_phyerr_filter_offload_en_cmd)(wmi_unified_t wmi_handle, + bool dfs_phyerr_filter_offload); + +QDF_STATUS (*send_add_wow_wakeup_event_cmd)(wmi_unified_t wmi_handle, + uint32_t vdev_id, + uint32_t *bitmap, + bool enable); + +QDF_STATUS (*send_wow_patterns_to_fw_cmd)(wmi_unified_t wmi_handle, + uint8_t vdev_id, uint8_t ptrn_id, + const uint8_t *ptrn, uint8_t ptrn_len, + uint8_t ptrn_offset, const uint8_t *mask, + uint8_t mask_len, bool user, + uint8_t default_patterns); + +QDF_STATUS (*send_wow_delete_pattern_cmd)(wmi_unified_t wmi_handle, uint8_t ptrn_id, + uint8_t vdev_id); + +QDF_STATUS (*send_host_wakeup_ind_to_fw_cmd)(wmi_unified_t wmi_handle); + +QDF_STATUS (*send_del_ts_cmd)(wmi_unified_t wmi_handle, uint8_t vdev_id, + uint8_t ac); + +QDF_STATUS (*send_aggr_qos_cmd)(wmi_unified_t wmi_handle, + struct aggr_add_ts_param *aggr_qos_rsp_msg); + +QDF_STATUS (*send_add_ts_cmd)(wmi_unified_t wmi_handle, + struct add_ts_param *msg); + +QDF_STATUS (*send_enable_disable_packet_filter_cmd)(wmi_unified_t wmi_handle, + uint8_t vdev_id, bool enable); + +QDF_STATUS (*send_config_packet_filter_cmd)(wmi_unified_t wmi_handle, + uint8_t vdev_id, struct rcv_pkt_filter_config *rcv_filter_param, + uint8_t filter_id, bool enable); + +QDF_STATUS (*send_add_clear_mcbc_filter_cmd)(wmi_unified_t wmi_handle, + uint8_t vdev_id, + struct qdf_mac_addr multicast_addr, + bool clearList); + +QDF_STATUS (*send_gtk_offload_cmd)(wmi_unified_t wmi_handle, uint8_t vdev_id, + struct gtk_offload_params *params, + bool enable_offload, + uint32_t gtk_offload_opcode); + +QDF_STATUS (*send_process_gtk_offload_getinfo_cmd)(wmi_unified_t wmi_handle, + uint8_t vdev_id, + uint64_t offload_req_opcode); + +QDF_STATUS (*send_process_add_periodic_tx_ptrn_cmd)(wmi_unified_t wmi_handle, + struct periodic_tx_pattern * + pAddPeriodicTxPtrnParams, + uint8_t vdev_id); + +QDF_STATUS (*send_process_del_periodic_tx_ptrn_cmd)(wmi_unified_t wmi_handle, + uint8_t vdev_id, + uint8_t pattern_id); + +QDF_STATUS (*send_stats_ext_req_cmd)(wmi_unified_t wmi_handle, + struct stats_ext_params *preq); + +QDF_STATUS (*send_enable_ext_wow_cmd)(wmi_unified_t wmi_handle, + struct ext_wow_params *params); + +QDF_STATUS (*send_set_app_type2_params_in_fw_cmd)(wmi_unified_t wmi_handle, + struct app_type2_params *appType2Params); + +QDF_STATUS (*send_set_auto_shutdown_timer_cmd)(wmi_unified_t wmi_handle, + uint32_t timer_val); + +QDF_STATUS (*send_nan_req_cmd)(wmi_unified_t wmi_handle, + struct nan_req_params *nan_req); + +QDF_STATUS (*send_process_dhcpserver_offload_cmd)(wmi_unified_t wmi_handle, + struct dhcp_offload_info_params *pDhcpSrvOffloadInfo); + +QDF_STATUS (*send_process_ch_avoid_update_cmd)(wmi_unified_t wmi_handle); + +QDF_STATUS (*send_regdomain_info_to_fw_cmd)(wmi_unified_t wmi_handle, + uint32_t reg_dmn, uint16_t regdmn2G, + uint16_t regdmn5G, int8_t ctl2G, + int8_t ctl5G); + +QDF_STATUS (*send_set_tdls_offchan_mode_cmd)(wmi_unified_t wmi_handle, + struct tdls_channel_switch_params *chan_switch_params); + +QDF_STATUS (*send_update_fw_tdls_state_cmd)(wmi_unified_t wmi_handle, + void *tdls_param, uint8_t tdls_state); + +QDF_STATUS (*send_update_tdls_peer_state_cmd)(wmi_unified_t wmi_handle, + struct tdls_peer_state_params *peerStateParams, + uint32_t *ch_mhz); + + +QDF_STATUS (*send_process_fw_mem_dump_cmd)(wmi_unified_t wmi_handle, + struct fw_dump_req_param *mem_dump_req); + +QDF_STATUS (*send_process_set_ie_info_cmd)(wmi_unified_t wmi_handle, + struct vdev_ie_info_param *ie_info); + +#ifdef CONFIG_MCL +QDF_STATUS (*send_init_cmd)(wmi_unified_t wmi_handle, + wmi_resource_config *res_cfg, + uint8_t num_mem_chunks, struct wmi_host_mem_chunk *mem_chunk, + bool action); +#endif + +QDF_STATUS (*save_fw_version_cmd)(wmi_unified_t wmi_handle, void *evt_buf); + +QDF_STATUS (*check_and_update_fw_version_cmd)(wmi_unified_t wmi_hdl, void *ev); + +QDF_STATUS (*send_saved_init_cmd)(wmi_unified_t wmi_handle); + +QDF_STATUS (*send_set_base_macaddr_indicate_cmd)(wmi_unified_t wmi_handle, + uint8_t *custom_addr); + +QDF_STATUS (*send_log_supported_evt_cmd)(wmi_unified_t wmi_handle, + uint8_t *event, + uint32_t len); + +QDF_STATUS (*send_enable_specific_fw_logs_cmd)(wmi_unified_t wmi_handle, + struct wmi_wifi_start_log *start_log); + +QDF_STATUS (*send_flush_logs_to_fw_cmd)(wmi_unified_t wmi_handle); + +QDF_STATUS (*send_pdev_set_pcl_cmd)(wmi_unified_t wmi_handle, + struct wmi_pcl_chan_weights *msg); + +QDF_STATUS (*send_pdev_set_hw_mode_cmd)(wmi_unified_t wmi_handle, + uint32_t hw_mode_index); + +QDF_STATUS (*send_pdev_set_dual_mac_config_cmd)(wmi_unified_t wmi_handle, + struct wmi_dual_mac_config *msg); + +QDF_STATUS (*send_enable_arp_ns_offload_cmd)(wmi_unified_t wmi_handle, + struct host_offload_req_param *arp_offload_req, + struct host_offload_req_param *ns_offload_req, + bool arp_only, + uint8_t vdev_id); + +QDF_STATUS (*send_set_led_flashing_cmd)(wmi_unified_t wmi_handle, + struct flashing_req_params *flashing); + +QDF_STATUS (*send_app_type1_params_in_fw_cmd)(wmi_unified_t wmi_handle, + struct app_type1_params *app_type1_params); + +QDF_STATUS (*send_set_ssid_hotlist_cmd)(wmi_unified_t wmi_handle, + struct ssid_hotlist_request_params *request); + +QDF_STATUS (*send_process_roam_synch_complete_cmd)(wmi_unified_t wmi_handle, + uint8_t vdev_id); + +QDF_STATUS (*send_unit_test_cmd)(wmi_unified_t wmi_handle, + struct wmi_unit_test_cmd *wmi_utest); + +QDF_STATUS (*send_roam_invoke_cmd)(wmi_unified_t wmi_handle, + struct wmi_roam_invoke_cmd *roaminvoke, + uint32_t ch_hz); + +QDF_STATUS (*send_roam_scan_offload_cmd)(wmi_unified_t wmi_handle, + uint32_t command, uint32_t vdev_id); + +QDF_STATUS (*send_roam_scan_offload_scan_period_cmd)(wmi_unified_t wmi_handle, + uint32_t scan_period, + uint32_t scan_age, + uint32_t vdev_id); + +QDF_STATUS (*send_roam_scan_offload_chan_list_cmd)(wmi_unified_t wmi_handle, + uint8_t chan_count, + uint32_t *chan_list, + uint8_t list_type, uint32_t vdev_id); + +QDF_STATUS (*send_roam_scan_offload_rssi_change_cmd)(wmi_unified_t wmi_handle, + uint32_t vdev_id, + int32_t rssi_change_thresh, + uint32_t bcn_rssi_weight, + uint32_t hirssi_delay_btw_scans); + +QDF_STATUS (*send_per_roam_config_cmd)(wmi_unified_t wmi_handle, + struct wmi_per_roam_config_req *req_buf); + +QDF_STATUS (*send_set_arp_stats_req_cmd)(wmi_unified_t wmi_handle, + struct set_arp_stats *req_buf); + +QDF_STATUS (*send_get_arp_stats_req_cmd)(wmi_unified_t wmi_handle, + struct get_arp_stats *req_buf); + +QDF_STATUS (*send_get_buf_extscan_hotlist_cmd)(wmi_unified_t wmi_handle, + struct ext_scan_setbssi_hotlist_params * + photlist, int *buf_len); + +QDF_STATUS (*send_set_active_bpf_mode_cmd)(wmi_unified_t wmi_handle, + uint8_t vdev_id, + FW_ACTIVE_BPF_MODE ucast_mode, + FW_ACTIVE_BPF_MODE mcast_bcast_mode); + +QDF_STATUS (*send_pdev_get_tpc_config_cmd)(wmi_unified_t wmi_handle, + uint32_t param); + +QDF_STATUS (*send_set_bwf_cmd)(wmi_unified_t wmi_handle, + struct set_bwf_params *param); + +QDF_STATUS (*send_set_atf_cmd)(wmi_unified_t wmi_handle, + struct set_atf_params *param); + +QDF_STATUS (*send_pdev_fips_cmd)(wmi_unified_t wmi_handle, + struct fips_params *param); + +QDF_STATUS (*send_wlan_profile_enable_cmd)(wmi_unified_t wmi_handle, + struct wlan_profile_params *param); + +QDF_STATUS (*send_wlan_profile_trigger_cmd)(wmi_unified_t wmi_handle, + struct wlan_profile_params *param); + +QDF_STATUS (*send_pdev_set_chan_cmd)(wmi_unified_t wmi_handle, + struct channel_param *param); + +QDF_STATUS (*send_set_ht_ie_cmd)(wmi_unified_t wmi_handle, + struct ht_ie_params *param); + +QDF_STATUS (*send_set_vht_ie_cmd)(wmi_unified_t wmi_handle, + struct vht_ie_params *param); + +QDF_STATUS (*send_wmm_update_cmd)(wmi_unified_t wmi_handle, + struct wmm_update_params *param); + +QDF_STATUS (*send_set_ant_switch_tbl_cmd)(wmi_unified_t wmi_handle, + struct ant_switch_tbl_params *param); + +QDF_STATUS (*send_set_ratepwr_table_cmd)(wmi_unified_t wmi_handle, + struct ratepwr_table_params *param); + +QDF_STATUS (*send_get_ratepwr_table_cmd)(wmi_unified_t wmi_handle); + +QDF_STATUS (*send_set_ctl_table_cmd)(wmi_unified_t wmi_handle, + struct ctl_table_params *param); + +QDF_STATUS (*send_set_mimogain_table_cmd)(wmi_unified_t wmi_handle, + struct mimogain_table_params *param); + +QDF_STATUS (*send_set_ratepwr_chainmsk_cmd)(wmi_unified_t wmi_handle, + struct ratepwr_chainmsk_params *param); + +QDF_STATUS (*send_set_macaddr_cmd)(wmi_unified_t wmi_handle, + struct macaddr_params *param); + +QDF_STATUS (*send_pdev_scan_start_cmd)(wmi_unified_t wmi_handle); + +QDF_STATUS (*send_pdev_scan_end_cmd)(wmi_unified_t wmi_handle); + +QDF_STATUS (*send_set_acparams_cmd)(wmi_unified_t wmi_handle, + struct acparams_params *param); + +QDF_STATUS (*send_set_vap_dscp_tid_map_cmd)(wmi_unified_t wmi_handle, + struct vap_dscp_tid_map_params *param); + +QDF_STATUS (*send_proxy_ast_reserve_cmd)(wmi_unified_t wmi_handle, + struct proxy_ast_reserve_params *param); + +QDF_STATUS (*send_pdev_qvit_cmd)(wmi_unified_t wmi_handle, + struct pdev_qvit_params *param); + +QDF_STATUS (*send_mcast_group_update_cmd)(wmi_unified_t wmi_handle, + struct mcast_group_update_params *param); + +QDF_STATUS (*send_peer_add_wds_entry_cmd)(wmi_unified_t wmi_handle, + struct peer_add_wds_entry_params *param); + +QDF_STATUS (*send_peer_del_wds_entry_cmd)(wmi_unified_t wmi_handle, + struct peer_del_wds_entry_params *param); + +QDF_STATUS (*send_peer_update_wds_entry_cmd)(wmi_unified_t wmi_handle, + struct peer_update_wds_entry_params *param); + +QDF_STATUS (*send_phyerr_enable_cmd)(wmi_unified_t wmi_handle); + +QDF_STATUS (*send_phyerr_disable_cmd)(wmi_unified_t wmi_handle); + +QDF_STATUS (*send_smart_ant_enable_cmd)(wmi_unified_t wmi_handle, + struct smart_ant_enable_params *param); + +QDF_STATUS (*send_smart_ant_set_rx_ant_cmd)(wmi_unified_t wmi_handle, + struct smart_ant_rx_ant_params *param); + +QDF_STATUS (*send_smart_ant_set_tx_ant_cmd)(wmi_unified_t wmi_handle, + uint8_t macaddr[IEEE80211_ADDR_LEN], + struct smart_ant_tx_ant_params *param); + +QDF_STATUS (*send_smart_ant_set_training_info_cmd)(wmi_unified_t wmi_handle, + uint8_t macaddr[IEEE80211_ADDR_LEN], + struct smart_ant_training_info_params *param); + +QDF_STATUS (*send_smart_ant_set_node_config_cmd)(wmi_unified_t wmi_handle, + uint8_t macaddr[IEEE80211_ADDR_LEN], + struct smart_ant_node_config_params *param); + +QDF_STATUS (*send_smart_ant_enable_tx_feedback_cmd)(wmi_unified_t wmi_handle, + struct smart_ant_enable_tx_feedback_params *param); + +QDF_STATUS (*send_vdev_spectral_configure_cmd)(wmi_unified_t wmi_handle, + struct vdev_spectral_configure_params *param); + +QDF_STATUS (*send_vdev_spectral_enable_cmd)(wmi_unified_t wmi_handle, + struct vdev_spectral_enable_params *param); + +QDF_STATUS (*send_bss_chan_info_request_cmd)(wmi_unified_t wmi_handle, + struct bss_chan_info_request_params *param); + +QDF_STATUS (*send_thermal_mitigation_param_cmd)(wmi_unified_t wmi_handle, + struct thermal_mitigation_params *param); + +QDF_STATUS (*send_vdev_set_neighbour_rx_cmd)(wmi_unified_t wmi_handle, + uint8_t macaddr[IEEE80211_ADDR_LEN], + struct set_neighbour_rx_params *param); + +QDF_STATUS (*send_vdev_set_fwtest_param_cmd)(wmi_unified_t wmi_handle, + struct set_fwtest_params *param); + +QDF_STATUS (*send_vdev_config_ratemask_cmd)(wmi_unified_t wmi_handle, + struct config_ratemask_params *param); + +QDF_STATUS (*send_vdev_install_key_cmd)(wmi_unified_t wmi_handle, + uint8_t macaddr[IEEE80211_ADDR_LEN], + struct vdev_install_key_params *param); + +QDF_STATUS (*send_wow_wakeup_cmd)(wmi_unified_t wmi_handle); + +QDF_STATUS (*send_wow_add_wakeup_event_cmd)(wmi_unified_t wmi_handle, + struct wow_add_wakeup_params *param); + +QDF_STATUS (*send_wow_add_wakeup_pattern_cmd)(wmi_unified_t wmi_handle, + struct wow_add_wakeup_pattern_params *param); + +QDF_STATUS (*send_wow_remove_wakeup_pattern_cmd)(wmi_unified_t wmi_handle, + struct wow_remove_wakeup_pattern_params *param); + +QDF_STATUS (*send_pdev_set_regdomain_cmd)(wmi_unified_t wmi_handle, + struct pdev_set_regdomain_params *param); + +QDF_STATUS (*send_set_quiet_mode_cmd)(wmi_unified_t wmi_handle, + struct set_quiet_mode_params *param); + +QDF_STATUS (*send_set_beacon_filter_cmd)(wmi_unified_t wmi_handle, + struct set_beacon_filter_params *param); + +QDF_STATUS (*send_remove_beacon_filter_cmd)(wmi_unified_t wmi_handle, + struct remove_beacon_filter_params *param); +/* +QDF_STATUS (*send_mgmt_cmd)(wmi_unified_t wmi_handle, + uint8_t macaddr[IEEE80211_ADDR_LEN], + struct mgmt_params *param); + */ + +QDF_STATUS (*send_addba_clearresponse_cmd)(wmi_unified_t wmi_handle, + uint8_t macaddr[IEEE80211_ADDR_LEN], + struct addba_clearresponse_params *param); + +QDF_STATUS (*send_addba_send_cmd)(wmi_unified_t wmi_handle, + uint8_t macaddr[IEEE80211_ADDR_LEN], + struct addba_send_params *param); + +QDF_STATUS (*send_delba_send_cmd)(wmi_unified_t wmi_handle, + uint8_t macaddr[IEEE80211_ADDR_LEN], + struct delba_send_params *param); + +QDF_STATUS (*send_addba_setresponse_cmd)(wmi_unified_t wmi_handle, + uint8_t macaddr[IEEE80211_ADDR_LEN], + struct addba_setresponse_params *param); + +QDF_STATUS (*send_singleamsdu_cmd)(wmi_unified_t wmi_handle, + uint8_t macaddr[IEEE80211_ADDR_LEN], + struct singleamsdu_params *param); + +QDF_STATUS (*send_set_qboost_param_cmd)(wmi_unified_t wmi_handle, + uint8_t macaddr[IEEE80211_ADDR_LEN], + struct set_qboost_params *param); + +QDF_STATUS (*send_mu_scan_cmd)(wmi_unified_t wmi_handle, + struct mu_scan_params *param); + +QDF_STATUS (*send_lteu_config_cmd)(wmi_unified_t wmi_handle, + struct lteu_config_params *param); + +QDF_STATUS (*send_set_ps_mode_cmd)(wmi_unified_t wmi_handle, + struct set_ps_mode_params *param); +void (*save_service_bitmap)(wmi_unified_t wmi_handle, + void *evt_buf); +bool (*is_service_enabled)(wmi_unified_t wmi_handle, + uint32_t service_id); +QDF_STATUS (*get_target_cap_from_service_ready)(wmi_unified_t wmi_handle, + void *evt_buf, target_capability_info *ev); + +QDF_STATUS (*extract_fw_version)(wmi_unified_t wmi_handle, + void *ev, struct wmi_host_fw_ver *fw_ver); + +QDF_STATUS (*extract_fw_abi_version)(wmi_unified_t wmi_handle, + void *ev, struct wmi_host_fw_abi_ver *fw_ver); + +QDF_STATUS (*extract_hal_reg_cap)(wmi_unified_t wmi_handle, void *evt_buf, + TARGET_HAL_REG_CAPABILITIES *hal_reg_cap); + +host_mem_req * (*extract_host_mem_req)(wmi_unified_t wmi_handle, + void *evt_buf, uint8_t *num_entries); + +QDF_STATUS (*init_cmd_send)(wmi_unified_t wmi_handle, + target_resource_config *res_cfg, + uint8_t num_mem_chunks, + struct wmi_host_mem_chunk *mem_chunk); + +QDF_STATUS (*save_fw_version)(wmi_unified_t wmi_handle, void *evt_buf); +uint32_t (*ready_extract_init_status)(wmi_unified_t wmi_hdl, void *ev); +QDF_STATUS (*ready_extract_mac_addr)(wmi_unified_t wmi_hdl, void *ev, + uint8_t *macaddr); +QDF_STATUS (*check_and_update_fw_version)(wmi_unified_t wmi_hdl, void *ev); +uint8_t* (*extract_dbglog_data_len)(wmi_unified_t wmi_handle, void *evt_buf, + uint16_t *len); +QDF_STATUS (*send_ext_resource_config)(wmi_unified_t wmi_handle, + wmi_host_ext_resource_config *ext_cfg); + +QDF_STATUS (*send_nf_dbr_dbm_info_get_cmd)(wmi_unified_t wmi_handle); + +QDF_STATUS (*send_packet_power_info_get_cmd)(wmi_unified_t wmi_handle, + struct packet_power_info_params *param); + +QDF_STATUS (*send_gpio_config_cmd)(wmi_unified_t wmi_handle, + struct gpio_config_params *param); + +QDF_STATUS (*send_gpio_output_cmd)(wmi_unified_t wmi_handle, + struct gpio_output_params *param); + +QDF_STATUS (*send_rtt_meas_req_test_cmd)(wmi_unified_t wmi_handle, + struct rtt_meas_req_test_params *param); + +QDF_STATUS (*send_rtt_meas_req_cmd)(wmi_unified_t wmi_handle, + struct rtt_meas_req_params *param); + +QDF_STATUS (*send_rtt_keepalive_req_cmd)(wmi_unified_t wmi_handle, + struct rtt_keepalive_req_params *param); + +QDF_STATUS (*send_lci_set_cmd)(wmi_unified_t wmi_handle, + struct lci_set_params *param); + +QDF_STATUS (*send_lcr_set_cmd)(wmi_unified_t wmi_handle, + struct lcr_set_params *param); + +QDF_STATUS (*send_periodic_chan_stats_config_cmd)(wmi_unified_t wmi_handle, + struct periodic_chan_stats_params *param); + +QDF_STATUS +(*send_atf_peer_request_cmd)(wmi_unified_t wmi_handle, + struct atf_peer_request_params *param); + +QDF_STATUS +(*send_set_atf_grouping_cmd)(wmi_unified_t wmi_handle, + struct atf_grouping_params *param); + +QDF_STATUS (*extract_wds_addr_event)(wmi_unified_t wmi_handle, + void *evt_buf, uint16_t len, wds_addr_event_t *wds_ev); + +QDF_STATUS (*extract_dcs_interference_type)(wmi_unified_t wmi_handle, + void *evt_buf, uint32_t *interference_type); + +QDF_STATUS (*extract_dcs_cw_int)(wmi_unified_t wmi_handle, void *evt_buf, + wmi_host_ath_dcs_cw_int *cw_int); + +QDF_STATUS (*extract_dcs_im_tgt_stats)(wmi_unified_t wmi_handle, void *evt_buf, + wmi_host_dcs_im_tgt_stats_t *wlan_stat); + +QDF_STATUS (*extract_fips_event_error_status)(wmi_unified_t wmi_handle, + void *evt_buf, uint32_t *err_status); + +QDF_STATUS (*extract_fips_event_data)(wmi_unified_t wmi_handle, + void *evt_buf, uint32_t *data_len, uint32_t **data); +QDF_STATUS (*extract_vdev_start_resp)(wmi_unified_t wmi_handle, void *evt_buf, + wmi_host_vdev_start_resp *vdev_rsp); + +QDF_STATUS (*extract_tbttoffset_update_params)(void *wmi_hdl, void *evt_buf, + uint32_t *vdev_map, uint32_t **tbttoffset_list); + +QDF_STATUS (*extract_mgmt_rx_params)(wmi_unified_t wmi_handle, void *evt_buf, + wmi_host_mgmt_rx_hdr *hdr, uint8_t **bufp); + +QDF_STATUS (*extract_vdev_stopped_param)(wmi_unified_t wmi_handle, + void *evt_buf, uint32_t *vdev_id); + +QDF_STATUS (*extract_vdev_roam_param)(wmi_unified_t wmi_handle, void *evt_buf, + wmi_host_roam_event *param); + +QDF_STATUS (*extract_vdev_scan_ev_param)(wmi_unified_t wmi_handle, + void *evt_buf, wmi_host_scan_event *param); + +QDF_STATUS (*extract_mu_ev_param)(wmi_unified_t wmi_handle, void *evt_buf, + wmi_host_mu_report_event *param); + +QDF_STATUS (*extract_pdev_tpc_config_ev_param)(wmi_unified_t wmi_handle, + void *evt_buf, wmi_host_pdev_tpc_config_event *param); + +QDF_STATUS (*extract_gpio_input_ev_param)(wmi_unified_t wmi_handle, + void *evt_buf, uint32_t *gpio_num); + +QDF_STATUS (*extract_pdev_reserve_ast_ev_param)(wmi_unified_t wmi_handle, + void *evt_buf, uint32_t *result); + +QDF_STATUS (*extract_nfcal_power_ev_param)(wmi_unified_t wmi_handle, + void *evt_buf, + wmi_host_pdev_nfcal_power_all_channels_event *param); + +QDF_STATUS (*extract_pdev_tpc_ev_param)(wmi_unified_t wmi_handle, + void *evt_buf, wmi_host_pdev_tpc_event *param); + +QDF_STATUS (*extract_pdev_generic_buffer_ev_param)(wmi_unified_t wmi_handle, + void *evt_buf, wmi_host_pdev_generic_buffer_event *param); + +QDF_STATUS (*extract_mgmt_tx_compl_param)(wmi_unified_t wmi_handle, + void *evt_buf, wmi_host_mgmt_tx_compl_event *param); + +QDF_STATUS (*extract_swba_vdev_map)(wmi_unified_t wmi_handle, void *evt_buf, + uint32_t *vdev_map); + +QDF_STATUS (*extract_swba_tim_info)(wmi_unified_t wmi_handle, void *evt_buf, + uint32_t idx, wmi_host_tim_info *tim_info); + +QDF_STATUS (*extract_swba_noa_info)(wmi_unified_t wmi_handle, void *evt_buf, + uint32_t idx, wmi_host_p2p_noa_info *p2p_desc); + +QDF_STATUS (*extract_peer_sta_ps_statechange_ev)(wmi_unified_t wmi_handle, + void *evt_buf, wmi_host_peer_sta_ps_statechange_event *ev); + +QDF_STATUS (*extract_peer_sta_kickout_ev)(wmi_unified_t wmi_handle, + void *evt_buf, wmi_host_peer_sta_kickout_event *ev); + +QDF_STATUS (*extract_peer_ratecode_list_ev)(wmi_unified_t wmi_handle, + void *evt_buf, uint8_t *peer_mac, wmi_sa_rate_cap *rate_cap); + +QDF_STATUS (*extract_comb_phyerr)(wmi_unified_t wmi_handle, void *evt_buf, + uint16_t datalen, uint16_t *buf_offset, wmi_host_phyerr_t *phyerr); + +QDF_STATUS (*extract_single_phyerr)(wmi_unified_t wmi_handle, void *evt_buf, + uint16_t datalen, uint16_t *buf_offset, wmi_host_phyerr_t *phyerr); + +QDF_STATUS (*extract_composite_phyerr)(wmi_unified_t wmi_handle, void *evt_buf, + uint16_t datalen, wmi_host_phyerr_t *phyerr); + +QDF_STATUS (*extract_rtt_hdr)(wmi_unified_t wmi_handle, void *evt_buf, + wmi_host_rtt_event_hdr *ev); + +QDF_STATUS (*extract_rtt_ev)(wmi_unified_t wmi_handle, void *evt_buf, + wmi_host_rtt_meas_event *ev, uint8_t *hdump, uint16_t hdump_len); + +QDF_STATUS (*extract_rtt_error_report_ev)(wmi_unified_t wmi_handle, + void *evt_buf, wmi_host_rtt_error_report_event *ev); + +QDF_STATUS (*extract_all_stats_count)(wmi_unified_t wmi_handle, void *evt_buf, + wmi_host_stats_event *stats_param); + +QDF_STATUS (*extract_pdev_stats)(wmi_unified_t wmi_handle, void *evt_buf, + uint32_t index, wmi_host_pdev_stats *pdev_stats); + +QDF_STATUS (*extract_pdev_ext_stats)(wmi_unified_t wmi_handle, void *evt_buf, + uint32_t index, wmi_host_pdev_ext_stats *pdev_ext_stats); + +QDF_STATUS (*extract_vdev_stats)(wmi_unified_t wmi_handle, void *evt_buf, + uint32_t index, wmi_host_vdev_stats *vdev_stats); + +QDF_STATUS (*extract_peer_stats)(wmi_unified_t wmi_handle, void *evt_buf, + uint32_t index, wmi_host_peer_stats *peer_stats); + +QDF_STATUS (*extract_bcnflt_stats)(wmi_unified_t wmi_handle, void *evt_buf, + uint32_t index, wmi_host_bcnflt_stats *bcnflt_stats); + +QDF_STATUS (*extract_peer_extd_stats)(wmi_unified_t wmi_handle, void *evt_buf, + uint32_t index, wmi_host_peer_extd_stats *peer_extd_stats); + +QDF_STATUS (*extract_chan_stats)(wmi_unified_t wmi_handle, void *evt_buf, + uint32_t index, wmi_host_chan_stats *chan_stats); + +QDF_STATUS (*extract_thermal_stats)(wmi_unified_t wmi_handle, void *evt_buf, + uint32_t *temp, uint32_t *level); + +QDF_STATUS (*extract_thermal_level_stats)(wmi_unified_t wmi_handle, + void *evt_buf, uint8_t idx, uint32_t *levelcount, + uint32_t *dccount); + +QDF_STATUS (*extract_profile_ctx)(wmi_unified_t wmi_handle, void *evt_buf, + wmi_host_wlan_profile_ctx_t *profile_ctx); + +QDF_STATUS (*extract_profile_data)(wmi_unified_t wmi_handle, void *evt_buf, + uint8_t idx, + wmi_host_wlan_profile_t *profile_data); + +QDF_STATUS (*extract_chan_info_event)(wmi_unified_t wmi_handle, void *evt_buf, + wmi_host_chan_info_event *chan_info); + +QDF_STATUS (*extract_channel_hopping_event)(wmi_unified_t wmi_handle, + void *evt_buf, + wmi_host_pdev_channel_hopping_event *ch_hopping); + +QDF_STATUS (*extract_bss_chan_info_event)(wmi_unified_t wmi_handle, + void *evt_buf, + wmi_host_pdev_bss_chan_info_event *bss_chan_info); + +QDF_STATUS (*extract_inst_rssi_stats_event)(wmi_unified_t wmi_handle, + void *evt_buf, wmi_host_inst_stats_resp *inst_rssi_resp); + +QDF_STATUS (*extract_tx_data_traffic_ctrl_ev)(wmi_unified_t wmi_handle, + void *evt_buf, wmi_host_tx_data_traffic_ctrl_event *ev); + +QDF_STATUS (*extract_vdev_extd_stats)(wmi_unified_t wmi_handle, void *evt_buf, + uint32_t index, wmi_host_vdev_extd_stats *vdev_extd_stats); + +QDF_STATUS (*send_power_dbg_cmd)(wmi_unified_t wmi_handle, + struct wmi_power_dbg_params *param); + +QDF_STATUS (*send_adapt_dwelltime_params_cmd)(wmi_unified_t wmi_handle, + struct wmi_adaptive_dwelltime_params *dwelltime_params); + +QDF_STATUS (*send_fw_test_cmd)(wmi_unified_t wmi_handle, + struct set_fwtest_params *wmi_fwtest); + +QDF_STATUS (*send_encrypt_decrypt_send_cmd)(wmi_unified_t wmi_handle, + struct encrypt_decrypt_req_params *params); + +QDF_STATUS (*send_sar_limit_cmd)(wmi_unified_t wmi_handle, + struct sar_limit_cmd_params *params); +uint16_t (*wmi_set_htc_tx_tag)(wmi_unified_t wmi_handle, + wmi_buf_t buf, uint32_t cmd_id); + +QDF_STATUS (*send_get_rcpi_cmd)(wmi_unified_t wmi_handle, + struct rcpi_req *get_rcpi_param); +}; + +struct target_abi_version { + A_UINT32 abi_version_0; + /** WMI Major and Minor versions */ + A_UINT32 abi_version_1; + /** WMI change revision */ + A_UINT32 abi_version_ns_0; + /** ABI version namespace first four dwords */ + A_UINT32 abi_version_ns_1; + /** ABI version namespace second four dwords */ + A_UINT32 abi_version_ns_2; + /** ABI version namespace third four dwords */ + A_UINT32 abi_version_ns_3; + /** ABI version namespace fourth four dwords */ +}; + +/** + * struct wmi_init_cmd - Saved wmi INIT command + * @buf: Buffer containing the wmi INIT command + * @buf_len: Length of the buffer + */ +struct wmi_cmd_init { + wmi_buf_t buf; + uint32_t buf_len; +}; + +struct wmi_unified { + void *scn_handle; /* handle to device */ + osdev_t osdev; /* handle to use OS-independent services */ + qdf_atomic_t pending_cmds; + HTC_ENDPOINT_ID wmi_endpoint_id; + uint16_t max_msg_len; + uint32_t event_id[WMI_UNIFIED_MAX_EVENT]; + wmi_unified_event_handler event_handler[WMI_UNIFIED_MAX_EVENT]; + enum wmi_rx_exec_ctx ctx[WMI_UNIFIED_MAX_EVENT]; + uint32_t max_event_idx; + void *htc_handle; + qdf_spinlock_t eventq_lock; + qdf_nbuf_queue_t event_queue; + struct work_struct rx_event_work; + int wmi_stop_in_progress; +#ifndef WMI_NON_TLV_SUPPORT + struct _wmi_abi_version fw_abi_version; + struct _wmi_abi_version final_abi_vers; +#endif + struct wmi_cmd_init saved_wmi_init_cmd; + uint32_t num_of_diag_events_logs; + uint32_t *events_logs_list; + struct host_offload_req_param arp_info; +#ifdef WLAN_OPEN_SOURCE + struct fwdebug dbglog; + struct dentry *debugfs_phy; +#endif /* WLAN_OPEN_SOURCE */ + +#ifdef WMI_INTERFACE_EVENT_LOGGING + struct wmi_debug_log_info log_info; +#endif /*WMI_INTERFACE_EVENT_LOGGING */ + + qdf_atomic_t is_target_suspended; + +#ifdef FEATURE_RUNTIME_PM + qdf_atomic_t runtime_pm_inprogress; +#endif + qdf_atomic_t is_wow_bus_suspended; + bool tag_crash_inject; + bool tgt_force_assert_enable; + enum wmi_target_type target_type; + struct wmi_rx_ops rx_ops; + struct wmi_ops *ops; + bool use_cookie; + bool wmi_stopinprogress; + qdf_spinlock_t ctx_lock; +#ifdef WMI_TLV_AND_NON_TLV_SUPPORT + /* WMI service bitmap recieved from target */ + uint32_t wmi_service_bitmap[wmi_services_max]; + uint32_t wmi_events[wmi_events_max]; + uint32_t pdev_param[wmi_pdev_param_max]; + uint32_t vdev_param[wmi_vdev_param_max]; + uint32_t services[wmi_services_max]; +#endif +}; +#ifdef WMI_NON_TLV_SUPPORT +/* ONLY_NON_TLV_TARGET:TLV attach dummy function defintion for case when + * driver supports only NON-TLV target (WIN mainline) */ +#define wmi_tlv_attach(x) qdf_print("TLV Unavailable\n") +#else +void wmi_tlv_attach(wmi_unified_t wmi_handle); +#endif +void wmi_non_tlv_attach(wmi_unified_t wmi_handle); + +/** + * wmi_align() - provides word aligned parameter + * @param: parameter to be aligned + * + * Return: word aligned parameter + */ +static inline uint32_t wmi_align(uint32_t param) +{ + return roundup(param, sizeof(uint32_t)); +} +#endif diff --git a/drivers/staging/qca-wifi-host-cmn/wmi/inc/wmi_unified_tlv.h b/drivers/staging/qca-wifi-host-cmn/wmi/inc/wmi_unified_tlv.h new file mode 100644 index 0000000000000000000000000000000000000000..060526fcd1589294e10f798658d6ab58ee108bdb --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/wmi/inc/wmi_unified_tlv.h @@ -0,0 +1,630 @@ +/* + * Copyright (c) 2016-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ +#ifndef _WMI_UNIFIED_TLV_H_ +#define _WMI_UNIFIED_TLV_H_ +#include +#include "a_types.h" +#include "wmi_unified_param.h" +#include "wmi.h" +#include "wmi_unified.h" +#include "ol_defines.h" /* Fix Me: wmi_unified_t structure definition */ + +QDF_STATUS send_vdev_create_cmd_tlv(wmi_unified_t wmi_handle, + uint8_t macaddr[IEEE80211_ADDR_LEN], + struct vdev_create_params *param); + +QDF_STATUS send_vdev_delete_cmd_tlv(wmi_unified_t wmi_handle, + uint8_t if_id); + +QDF_STATUS send_vdev_stop_cmd_tlv(wmi_unified_t wmi, + uint8_t vdev_id); + +QDF_STATUS send_vdev_down_cmd_tlv(wmi_unified_t wmi, + uint8_t vdev_id); + +QDF_STATUS send_vdev_start_cmd_tlv(wmi_unified_t wmi, + struct vdev_start_params *req); + +QDF_STATUS send_hidden_ssid_vdev_restart_cmd_tlv(wmi_unified_t wmi_handle, + struct hidden_ssid_vdev_restart_params *restart_params); + +QDF_STATUS send_peer_flush_tids_cmd_tlv(wmi_unified_t wmi, + uint8_t peer_addr[IEEE80211_ADDR_LEN], + struct peer_flush_params *param); + +QDF_STATUS send_peer_delete_cmd_tlv(wmi_unified_t wmi, + uint8_t peer_addr[IEEE80211_ADDR_LEN], + uint8_t vdev_id); + +QDF_STATUS send_peer_param_cmd_tlv(wmi_unified_t wmi, + uint8_t peer_addr[IEEE80211_ADDR_LEN], + struct peer_set_params *param); + +QDF_STATUS send_vdev_up_cmd_tlv(wmi_unified_t wmi, + uint8_t bssid[IEEE80211_ADDR_LEN], + struct vdev_up_params *params); + +QDF_STATUS send_peer_create_cmd_tlv(wmi_unified_t wmi, + struct peer_create_params *param); + +QDF_STATUS send_green_ap_ps_cmd_tlv(wmi_unified_t wmi_handle, + uint32_t value, uint8_t mac_id); + +QDF_STATUS +send_pdev_utf_cmd_tlv(wmi_unified_t wmi_handle, + struct pdev_utf_params *param, + uint8_t mac_id); + +QDF_STATUS +send_pdev_param_cmd_tlv(wmi_unified_t wmi_handle, + struct pdev_params *param, + uint8_t mac_id); + +QDF_STATUS send_suspend_cmd_tlv(wmi_unified_t wmi_handle, + struct suspend_params *param, + uint8_t mac_id); + +QDF_STATUS send_resume_cmd_tlv(wmi_unified_t wmi_handle, + uint8_t mac_id); + +QDF_STATUS send_wow_enable_cmd_tlv(wmi_unified_t wmi_handle, + struct wow_cmd_params *param, + uint8_t mac_id); + +QDF_STATUS send_set_ap_ps_param_cmd_tlv(wmi_unified_t wmi_handle, + uint8_t *peer_addr, + struct ap_ps_params *param); + +QDF_STATUS send_set_sta_ps_param_cmd_tlv(wmi_unified_t wmi_handle, + struct sta_ps_params *param); + +QDF_STATUS send_crash_inject_cmd_tlv(wmi_unified_t wmi_handle, + struct crash_inject *param); + +QDF_STATUS +send_dbglog_cmd_tlv(wmi_unified_t wmi_handle, + struct dbglog_params *dbglog_param); + + +QDF_STATUS send_vdev_set_param_cmd_tlv(wmi_unified_t wmi_handle, + struct vdev_set_params *param); + +QDF_STATUS send_stats_request_cmd_tlv(wmi_unified_t wmi_handle, + uint8_t macaddr[IEEE80211_ADDR_LEN], + struct stats_request_params *param); + +#ifdef CONFIG_WIN +QDF_STATUS send_packet_log_enable_cmd_tlv(wmi_unified_t wmi_handle, + WMI_HOST_PKTLOG_EVENT PKTLOG_EVENT); +#else +QDF_STATUS send_packet_log_enable_cmd_tlv(wmi_unified_t wmi_handle, + uint8_t macaddr[IEEE80211_ADDR_LEN], + struct packet_enable_params *param); +#endif +QDF_STATUS send_beacon_send_cmd_tlv(wmi_unified_t wmi_handle, + struct beacon_params *param); + +QDF_STATUS send_peer_assoc_cmd_tlv(wmi_unified_t wmi_handle, + struct peer_assoc_params *param); + +QDF_STATUS send_scan_start_cmd_tlv(wmi_unified_t wmi_handle, + struct scan_start_params *param); + +QDF_STATUS send_scan_stop_cmd_tlv(wmi_unified_t wmi_handle, + struct scan_stop_params *param); + +QDF_STATUS send_scan_chan_list_cmd_tlv(wmi_unified_t wmi_handle, + struct scan_chan_list_params *param); + +QDF_STATUS send_mgmt_cmd_tlv(wmi_unified_t wmi_handle, + struct wmi_mgmt_params *param); + +QDF_STATUS send_modem_power_state_cmd_tlv(wmi_unified_t wmi_handle, + uint32_t param_value); + +QDF_STATUS send_set_sta_ps_mode_cmd_tlv(wmi_unified_t wmi_handle, + uint32_t vdev_id, uint8_t val); + +QDF_STATUS send_set_sta_uapsd_auto_trig_cmd_tlv(wmi_unified_t wmi_handle, + struct sta_uapsd_trig_params *param); + +QDF_STATUS send_get_temperature_cmd_tlv(wmi_unified_t wmi_handle); + +QDF_STATUS send_set_p2pgo_oppps_req_cmd_tlv(wmi_unified_t wmi_handle, + struct p2p_ps_params *oppps); + +QDF_STATUS send_set_p2pgo_noa_req_cmd_tlv(wmi_unified_t wmi_handle, + struct p2p_ps_params *noa); + +QDF_STATUS send_set_smps_params_cmd_tlv(wmi_unified_t wmi_handle, + uint8_t vdev_id, + int value); + +QDF_STATUS send_set_mimops_cmd_tlv(wmi_unified_t wmi_handle, + uint8_t vdev_id, int value); + +QDF_STATUS send_ocb_set_utc_time_cmd_tlv(wmi_unified_t wmi_handle, + struct ocb_utc_param *utc); + +QDF_STATUS send_ocb_start_timing_advert_cmd_tlv(wmi_unified_t wmi_handle, + struct ocb_timing_advert_param *timing_advert); + +QDF_STATUS send_ocb_stop_timing_advert_cmd_tlv(wmi_unified_t wmi_handle, + struct ocb_timing_advert_param *timing_advert); + +QDF_STATUS send_ocb_get_tsf_timer_cmd_tlv(wmi_unified_t wmi_handle, + uint8_t vdev_id); + +QDF_STATUS send_dcc_get_stats_cmd_tlv(wmi_unified_t wmi_handle, + struct dcc_get_stats_param *get_stats_param); + +QDF_STATUS send_dcc_clear_stats_cmd_tlv(wmi_unified_t wmi_handle, + uint32_t vdev_id, uint32_t dcc_stats_bitmap); + +QDF_STATUS send_dcc_update_ndl_cmd_tlv(wmi_unified_t wmi_handle, + struct dcc_update_ndl_param *update_ndl_param); + +QDF_STATUS send_ocb_set_config_cmd_tlv(wmi_unified_t wmi_handle, + struct ocb_config_param *config, uint32_t *ch_mhz); +QDF_STATUS send_lro_config_cmd_tlv(wmi_unified_t wmi_handle, + struct wmi_lro_config_cmd_t *wmi_lro_cmd); + +QDF_STATUS send_set_thermal_mgmt_cmd_tlv(wmi_unified_t wmi_handle, + struct thermal_cmd_params *thermal_info); + +QDF_STATUS send_peer_rate_report_cmd_tlv(wmi_unified_t wmi_handle, + struct wmi_peer_rate_report_params *rate_report_params); + +QDF_STATUS send_set_mcc_channel_time_quota_cmd_tlv + (wmi_unified_t wmi_handle, + uint32_t adapter_1_chan_freq, + uint32_t adapter_1_quota, uint32_t adapter_2_chan_freq); + +QDF_STATUS send_set_mcc_channel_time_latency_cmd_tlv + (wmi_unified_t wmi_handle, + uint32_t mcc_channel_freq, uint32_t mcc_channel_time_latency); + +QDF_STATUS send_set_enable_disable_mcc_adaptive_scheduler_cmd_tlv( + wmi_unified_t wmi_handle, uint32_t mcc_adaptive_scheduler, + uint32_t pdev_id); + +QDF_STATUS send_p2p_go_set_beacon_ie_cmd_tlv(wmi_unified_t wmi_handle, + A_UINT32 vdev_id, uint8_t *p2p_ie); + +QDF_STATUS send_probe_rsp_tmpl_send_cmd_tlv(wmi_unified_t wmi_handle, + uint8_t vdev_id, + struct wmi_probe_resp_params *probe_rsp_info, + uint8_t *frm); + +QDF_STATUS send_setup_install_key_cmd_tlv(wmi_unified_t wmi_handle, + struct set_key_params *key_params); + +QDF_STATUS send_process_update_edca_param_cmd_tlv(wmi_unified_t wmi_handle, + uint8_t vdev_id, + wmi_wmm_vparams gwmm_param[WMI_MAX_NUM_AC]); + +QDF_STATUS send_vdev_set_gtx_cfg_cmd_tlv(wmi_unified_t wmi_handle, + uint32_t if_id, + struct wmi_gtx_config *gtx_info); + +QDF_STATUS send_set_sta_keep_alive_cmd_tlv(wmi_unified_t wmi_handle, + struct sta_params *params); + +QDF_STATUS send_set_sta_sa_query_param_cmd_tlv(wmi_unified_t wmi_handle, + uint8_t vdev_id, uint32_t max_retries, + uint32_t retry_interval); + +QDF_STATUS send_bcn_buf_ll_cmd_tlv(wmi_unified_t wmi_handle, + wmi_bcn_send_from_host_cmd_fixed_param *param); + +QDF_STATUS send_set_gateway_params_cmd_tlv(wmi_unified_t wmi_handle, + struct gateway_update_req_param *req); + +QDF_STATUS send_set_rssi_monitoring_cmd_tlv(wmi_unified_t wmi_handle, + struct rssi_monitor_param *req); + +QDF_STATUS send_ipa_offload_control_cmd_tlv(wmi_unified_t wmi_handle, + struct ipa_offload_control_params *ipa_offload); + +QDF_STATUS send_scan_probe_setoui_cmd_tlv(wmi_unified_t wmi_handle, + struct scan_mac_oui *psetoui); + +QDF_STATUS send_reset_passpoint_network_list_cmd_tlv(wmi_unified_t wmi_handle, + struct wifi_passpoint_req_param *req); + +QDF_STATUS send_set_passpoint_network_list_cmd_tlv(wmi_unified_t wmi_handle, + struct wifi_passpoint_req_param *req); + +QDF_STATUS send_roam_scan_offload_mode_cmd_tlv(wmi_unified_t wmi_handle, + wmi_start_scan_cmd_fixed_param *scan_cmd_fp, + struct roam_offload_scan_params *roam_req); + +QDF_STATUS send_roam_scan_offload_rssi_thresh_cmd_tlv(wmi_unified_t wmi_handle, + struct roam_offload_scan_rssi_params *roam_req); + +QDF_STATUS send_roam_scan_filter_cmd_tlv(wmi_unified_t wmi_handle, + struct roam_scan_filter_params *roam_req); + +QDF_STATUS send_set_ric_req_cmd_tlv(wmi_unified_t wmi_handle, void *msg, + uint8_t is_add_ts); + +QDF_STATUS send_set_epno_network_list_cmd_tlv(wmi_unified_t wmi_handle, + struct wifi_enhanched_pno_params *req); + +QDF_STATUS send_extscan_get_capabilities_cmd_tlv(wmi_unified_t wmi_handle, + struct extscan_capabilities_params *pgetcapab); + +QDF_STATUS send_extscan_get_cached_results_cmd_tlv(wmi_unified_t wmi_handle, + struct extscan_cached_result_params *pcached_results); + +QDF_STATUS send_extscan_stop_change_monitor_cmd_tlv(wmi_unified_t wmi_handle, + struct extscan_capabilities_reset_params *reset_req); + +QDF_STATUS send_extscan_start_change_monitor_cmd_tlv(wmi_unified_t wmi_handle, + struct extscan_set_sig_changereq_params * + psigchange); + +QDF_STATUS send_extscan_stop_hotlist_monitor_cmd_tlv(wmi_unified_t wmi_handle, + struct extscan_bssid_hotlist_reset_params *photlist_reset); + +QDF_STATUS send_stop_extscan_cmd_tlv(wmi_unified_t wmi_handle, + struct extscan_stop_req_params *pstopcmd); + +QDF_STATUS send_start_extscan_cmd_tlv(wmi_unified_t wmi_handle, + struct wifi_scan_cmd_req_params *pstart); + +QDF_STATUS send_plm_stop_cmd_tlv(wmi_unified_t wmi_handle, + const struct plm_req_params *plm); + +QDF_STATUS send_plm_start_cmd_tlv(wmi_unified_t wmi_handle, + const struct plm_req_params *plm, + uint32_t *gchannel_list); + +QDF_STATUS send_pno_stop_cmd_tlv(wmi_unified_t wmi_handle, uint8_t vdev_id); + +QDF_STATUS send_pno_start_cmd_tlv(wmi_unified_t wmi_handle, + struct pno_scan_req_params *pno, + uint32_t *gchannel_freq_list); + +QDF_STATUS send_process_ll_stats_clear_cmd_tlv + (wmi_unified_t wmi_handle, + const struct ll_stats_clear_params *clear_req, + uint8_t addr[IEEE80211_ADDR_LEN]); + +QDF_STATUS send_process_ll_stats_set_cmd_tlv + (wmi_unified_t wmi_handle, const struct ll_stats_set_params *set_req); + +QDF_STATUS send_process_ll_stats_get_cmd_tlv + (wmi_unified_t wmi_handle, const struct ll_stats_get_params *get_req, + uint8_t addr[IEEE80211_ADDR_LEN]); + +QDF_STATUS send_get_stats_cmd_tlv(wmi_unified_t wmi_handle, + struct pe_stats_req *get_stats_param, + uint8_t addr[IEEE80211_ADDR_LEN]); + +/** + * send_congestion_cmd_tlv() - send request to fw to get CCA + * @wmi_handle: wmi handle + * @vdev_id: vdev id + * + * Return: CDF status + */ +QDF_STATUS send_congestion_cmd_tlv(wmi_unified_t wmi_handle, + A_UINT8 vdev_id); + +QDF_STATUS send_snr_request_cmd_tlv(wmi_unified_t wmi_handle); + +QDF_STATUS send_snr_cmd_tlv(wmi_unified_t wmi_handle, uint8_t vdev_id); + +QDF_STATUS send_link_status_req_cmd_tlv(wmi_unified_t wmi_handle, + struct link_status_params *link_status); + +QDF_STATUS send_lphb_config_hbenable_cmd_tlv(wmi_unified_t wmi_handle, + wmi_hb_set_enable_cmd_fixed_param *params); + +QDF_STATUS send_lphb_config_tcp_params_cmd_tlv(wmi_unified_t wmi_handle, + wmi_hb_set_tcp_params_cmd_fixed_param *lphb_conf_req); + +QDF_STATUS send_lphb_config_tcp_pkt_filter_cmd_tlv(wmi_unified_t wmi_handle, + wmi_hb_set_tcp_pkt_filter_cmd_fixed_param *g_hb_tcp_filter_fp); + +QDF_STATUS send_lphb_config_udp_params_cmd_tlv(wmi_unified_t wmi_handle, + wmi_hb_set_udp_params_cmd_fixed_param *lphb_conf_req); + +QDF_STATUS send_lphb_config_udp_pkt_filter_cmd_tlv(wmi_unified_t wmi_handle, + wmi_hb_set_udp_pkt_filter_cmd_fixed_param *lphb_conf_req); + +QDF_STATUS send_process_dhcp_ind_cmd_tlv(wmi_unified_t wmi_handle, + wmi_peer_set_param_cmd_fixed_param *ta_dhcp_ind); + +QDF_STATUS send_get_link_speed_cmd_tlv(wmi_unified_t wmi_handle, + wmi_mac_addr peer_macaddr); + +QDF_STATUS send_egap_conf_params_cmd_tlv(wmi_unified_t wmi_handle, + wmi_ap_ps_egap_param_cmd_fixed_param *egap_params); + +QDF_STATUS send_action_frame_patterns_cmd_tlv(wmi_unified_t wmi_handle, + struct action_wakeup_set_param *action_params); + +QDF_STATUS send_fw_profiling_cmd_tlv(wmi_unified_t wmi_handle, + uint32_t cmd, uint32_t value1, uint32_t value2); + +QDF_STATUS send_wow_sta_ra_filter_cmd_tlv(wmi_unified_t wmi_handle, + uint8_t vdev_id, uint8_t default_pattern, + uint16_t rate_limit_interval); + +QDF_STATUS send_nat_keepalive_en_cmd_tlv(wmi_unified_t wmi_handle, uint8_t vdev_id); + +QDF_STATUS send_csa_offload_enable_cmd_tlv(wmi_unified_t wmi_handle, + uint8_t vdev_id); + +QDF_STATUS send_start_oem_data_cmd_tlv(wmi_unified_t wmi_handle, + uint32_t data_len, + uint8_t *data); + +QDF_STATUS +send_dfs_phyerr_filter_offload_en_cmd_tlv(wmi_unified_t wmi_handle, + bool dfs_phyerr_filter_offload); + +QDF_STATUS send_pktlog_wmi_send_cmd_tlv(wmi_unified_t wmi_handle, + WMI_PKTLOG_EVENT pktlog_event, + WMI_CMD_ID cmd_id, uint8_t user_triggered); + +QDF_STATUS send_add_wow_wakeup_event_cmd_tlv(wmi_unified_t wmi_handle, + uint32_t vdev_id, + uint32_t *event_bitmap, + bool enable); + +QDF_STATUS send_wow_patterns_to_fw_cmd_tlv(wmi_unified_t wmi_handle, + uint8_t vdev_id, uint8_t ptrn_id, + const uint8_t *ptrn, uint8_t ptrn_len, + uint8_t ptrn_offset, const uint8_t *mask, + uint8_t mask_len, bool user, + uint8_t default_patterns); + +QDF_STATUS send_wow_delete_pattern_cmd_tlv(wmi_unified_t wmi_handle, uint8_t ptrn_id, + uint8_t vdev_id); + +QDF_STATUS send_host_wakeup_ind_to_fw_cmd_tlv(wmi_unified_t wmi_handle); + +QDF_STATUS send_del_ts_cmd_tlv(wmi_unified_t wmi_handle, uint8_t vdev_id, + uint8_t ac); + +QDF_STATUS send_aggr_qos_cmd_tlv(wmi_unified_t wmi_handle, + struct aggr_add_ts_param *aggr_qos_rsp_msg); + +QDF_STATUS send_add_ts_cmd_tlv(wmi_unified_t wmi_handle, + struct add_ts_param *msg); + +QDF_STATUS send_enable_disable_packet_filter_cmd_tlv(wmi_unified_t wmi_handle, + uint8_t vdev_id, bool enable); + +QDF_STATUS send_config_packet_filter_cmd_tlv(wmi_unified_t wmi_handle, + uint8_t vdev_id, struct rcv_pkt_filter_config *rcv_filter_param, + uint8_t filter_id, bool enable); + +QDF_STATUS send_add_clear_mcbc_filter_cmd_tlv(wmi_unified_t wmi_handle, + uint8_t vdev_id, + struct qdf_mac_addr multicast_addr, + bool clearList); + +QDF_STATUS send_gtk_offload_cmd_tlv(wmi_unified_t wmi_handle, uint8_t vdev_id, + struct gtk_offload_params *params, + bool enable_offload, + uint32_t gtk_offload_opcode); + +QDF_STATUS send_process_gtk_offload_getinfo_cmd_tlv(wmi_unified_t wmi_handle, + uint8_t vdev_id, + uint64_t offload_req_opcode); + +QDF_STATUS send_process_add_periodic_tx_ptrn_cmd_tlv(wmi_unified_t wmi_handle, + struct periodic_tx_pattern * + pAddPeriodicTxPtrnParams, + uint8_t vdev_id); + +QDF_STATUS send_process_del_periodic_tx_ptrn_cmd_tlv(wmi_unified_t wmi_handle, + uint8_t vdev_id, + uint8_t pattern_id); + +QDF_STATUS send_stats_ext_req_cmd_tlv(wmi_unified_t wmi_handle, + struct stats_ext_params *preq); + +QDF_STATUS send_enable_ext_wow_cmd_tlv(wmi_unified_t wmi_handle, + struct ext_wow_params *params); + +QDF_STATUS send_set_app_type2_params_in_fw_cmd_tlv(wmi_unified_t wmi_handle, + struct app_type2_params *appType2Params); + +QDF_STATUS send_set_auto_shutdown_timer_cmd_tlv(wmi_unified_t wmi_handle, + uint32_t timer_val); + +QDF_STATUS send_nan_req_cmd_tlv(wmi_unified_t wmi_handle, + struct nan_req_params *nan_req); + +QDF_STATUS send_process_dhcpserver_offload_cmd_tlv(wmi_unified_t wmi_handle, + struct dhcp_offload_info_params *pDhcpSrvOffloadInfo); + +QDF_STATUS send_process_ch_avoid_update_cmd_tlv(wmi_unified_t wmi_handle); + +QDF_STATUS send_regdomain_info_to_fw_cmd_tlv(wmi_unified_t wmi_handle, + uint32_t reg_dmn, uint16_t regdmn2G, + uint16_t regdmn5G, int8_t ctl2G, + int8_t ctl5G); + +QDF_STATUS send_set_tdls_offchan_mode_cmd_tlv(wmi_unified_t wmi_handle, + struct tdls_channel_switch_params *chan_switch_params); + +QDF_STATUS send_update_fw_tdls_state_cmd_tlv(wmi_unified_t wmi_handle, + void *tdls_param, uint8_t tdls_state); + +QDF_STATUS send_update_tdls_peer_state_cmd_tlv(wmi_unified_t wmi_handle, + struct tdls_peer_state_params *peerStateParams, + uint32_t *ch_mhz); + + +QDF_STATUS send_process_fw_mem_dump_cmd_tlv(wmi_unified_t wmi_handle, + struct fw_dump_req_param *mem_dump_req); + +QDF_STATUS send_process_set_ie_info_cmd_tlv(wmi_unified_t wmi_handle, + struct vdev_ie_info_param *ie_info); + +QDF_STATUS send_init_cmd_tlv(wmi_unified_t wmi_handle, + wmi_resource_config *res_cfg, + uint8_t num_mem_chunks, struct wmi_host_mem_chunk *mem_chunk, + bool action); + +QDF_STATUS send_saved_init_cmd_tlv(wmi_unified_t wmi_handle); + +QDF_STATUS save_fw_version_cmd_tlv(wmi_unified_t wmi_handle, void *evt_buf); + +QDF_STATUS check_and_update_fw_version_cmd_tlv(wmi_unified_t wmi_hdl, void *ev); + +QDF_STATUS send_set_base_macaddr_indicate_cmd_tlv(wmi_unified_t wmi_handle, + uint8_t *custom_addr); + +QDF_STATUS send_log_supported_evt_cmd_tlv(wmi_unified_t wmi_handle, + uint8_t *event, + uint32_t len); + +QDF_STATUS send_enable_specific_fw_logs_cmd_tlv(wmi_unified_t wmi_handle, + struct wmi_wifi_start_log *start_log); + +QDF_STATUS send_flush_logs_to_fw_cmd_tlv(wmi_unified_t wmi_handle); + +QDF_STATUS send_pdev_set_pcl_cmd_tlv(wmi_unified_t wmi_handle, + struct wmi_pcl_chan_weights *msg); + +QDF_STATUS send_pdev_set_hw_mode_cmd_tlv(wmi_unified_t wmi_handle, + uint32_t hw_mode_index); + +QDF_STATUS send_soc_set_dual_mac_config_cmd_tlv(wmi_unified_t wmi_handle, + struct wmi_dual_mac_config *msg); + +static void fill_arp_offload_params_tlv(wmi_unified_t wmi_handle, + struct host_offload_req_param *offload_req, uint8_t **buf_ptr); + +static void fill_ns_offload_params_tlv(wmi_unified_t wmi_handle, + struct host_offload_req_param *offload_req, uint8_t **buf_ptr); + +static void fill_nsoffload_ext_tlv(wmi_unified_t wmi_handle, + struct host_offload_req_param *offload_req, uint8_t **buf_ptr); + +QDF_STATUS send_enable_arp_ns_offload_cmd_tlv(wmi_unified_t wmi_handle, + struct host_offload_req_param *arp_offload_req, + struct host_offload_req_param *ns_offload_req, + bool arp_only, + uint8_t vdev_id); + +/** + * send_conf_hw_filter_cmd_tlv() - configure hw filter mode to firmware + * @wmi: wmi handle + * @vdev_id: Id of the vdev to configure + * @mode_bitmap: the hw filter mode to configure + * + * Return: QDF_STATUS + */ +QDF_STATUS send_conf_hw_filter_cmd_tlv(wmi_unified_t wmi, uint8_t vdev_id, + uint8_t mode_bitmap); + +QDF_STATUS send_set_led_flashing_cmd_tlv(wmi_unified_t wmi_handle, + struct flashing_req_params *flashing); + +QDF_STATUS send_app_type1_params_in_fw_cmd_tlv(wmi_unified_t wmi_handle, + struct app_type1_params *app_type1_params); + +QDF_STATUS +send_set_ssid_hotlist_cmd_tlv(wmi_unified_t wmi_handle, + struct ssid_hotlist_request_params *request); + +QDF_STATUS send_process_roam_synch_complete_cmd_tlv(wmi_unified_t wmi_handle, + uint8_t vdev_id); + +QDF_STATUS send_unit_test_cmd_tlv(wmi_unified_t wmi_handle, + struct wmi_unit_test_cmd *wmi_utest); + +QDF_STATUS send_roam_invoke_cmd_tlv(wmi_unified_t wmi_handle, + struct wmi_roam_invoke_cmd *roaminvoke, + uint32_t ch_hz); + +QDF_STATUS send_roam_scan_offload_cmd_tlv(wmi_unified_t wmi_handle, + uint32_t command, uint32_t vdev_id); + +QDF_STATUS send_roam_scan_offload_ap_profile_cmd_tlv(wmi_unified_t wmi_handle, + wmi_ap_profile *ap_profile_p, + uint32_t vdev_id); + +QDF_STATUS send_roam_scan_offload_scan_period_cmd_tlv(wmi_unified_t wmi_handle, + uint32_t scan_period, + uint32_t scan_age, + uint32_t vdev_id); + +QDF_STATUS send_roam_scan_offload_chan_list_cmd_tlv(wmi_unified_t wmi_handle, + uint8_t chan_count, + uint32_t *chan_list, + uint8_t list_type, uint32_t vdev_id); + +QDF_STATUS send_roam_scan_offload_rssi_change_cmd_tlv(wmi_unified_t wmi_handle, + uint32_t vdev_id, + int32_t rssi_change_thresh, + uint32_t bcn_rssi_weight, + uint32_t hirssi_delay_btw_scans); + +/** + * send_per_roam_config_cmd_tlv() - set per roaming config to FW + * @wmi_handle: wmi handle + * @req_buf: per roam config buffer + * + * Return: QDF status + */ +QDF_STATUS send_per_roam_config_cmd_tlv(wmi_unified_t wmi_handle, + struct wmi_per_roam_config_req *req_buf); + +QDF_STATUS send_get_buf_extscan_hotlist_cmd_tlv(wmi_unified_t wmi_handle, + struct ext_scan_setbssi_hotlist_params * + photlist, int *buf_len); + +/** + * send_set_active_bpf_mode_cmd_tlv() - configure active BPF mode in FW + * @wmi_handle: the WMI handle + * @vdev_id: the Id of the vdev to apply the configuration to + * @ucast_mode: the active BPF mode to configure for unicast packets + * @mcast_bcast_mode: the active BPF mode to configure for multicast/broadcast + * packets + * + * Return: QDF status + */ +QDF_STATUS +send_set_active_bpf_mode_cmd_tlv(wmi_unified_t wmi_handle, + uint8_t vdev_id, + FW_ACTIVE_BPF_MODE ucast_mode, + FW_ACTIVE_BPF_MODE mcast_bcast_mode); + +QDF_STATUS send_set_arp_stats_req_cmd_tlv(wmi_unified_t wmi_handle, + struct set_arp_stats *req_buf); +QDF_STATUS send_get_arp_stats_req_cmd_tlv(wmi_unified_t wmi_handle, + struct get_arp_stats *req_buf); +#endif diff --git a/drivers/staging/qca-wifi-host-cmn/wmi/inc/wmi_version_whitelist.h b/drivers/staging/qca-wifi-host-cmn/wmi/inc/wmi_version_whitelist.h new file mode 100644 index 0000000000000000000000000000000000000000..74605952f8fd459c8b38a0785bf2d4e99ad85e5f --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/wmi/inc/wmi_version_whitelist.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2013-2014, 2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * Every Product Line or chipset or team can have its own Whitelist table. + * The following is a list of versions that the present software can support + * even though its versions are incompatible. Any entry here means that the + * indicated version does not break WMI compatibility even though it has + * a minor version change. + */ +#ifndef _WMI_VERSION_WHITELIST_H_ +#define _WMI_VERSION_WHITELIST_H_ +static wmi_whitelist_version_info version_whitelist[] = { + {0, 0, 0x5F414351, 0x00004C4D, 0, 0} + /* Placeholder: Major=0, Minor=0, Namespace="QCA_ML" (Dummy entry) */ +}; +#endif /* _WMI_VERSION_WHITELIST_H_ */ diff --git a/drivers/staging/qca-wifi-host-cmn/wmi/src/wmi_tlv_helper.c b/drivers/staging/qca-wifi-host-cmn/wmi/src/wmi_tlv_helper.c new file mode 100644 index 0000000000000000000000000000000000000000..1246152010630ef6f81c9e3a19a81b26b4d46fd1 --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/wmi/src/wmi_tlv_helper.c @@ -0,0 +1,1323 @@ +/* + * Copyright (c) 2013-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#include "wmi_tlv_platform.c" +#include "wmi_tlv_defs.h" +#include "wmi_version.h" + +#define WMITLV_GET_ATTRIB_NUM_TLVS 0xFFFFFFFF + +#define WMITLV_GET_CMDID(val) (val & 0x00FFFFFF) +#define WMITLV_GET_NUM_TLVS(val) ((val >> 24) & 0xFF) + +#define WMITLV_GET_TAGID(val) (val & 0x00000FFF) +#define WMITLV_GET_TAG_STRUCT_SIZE(val) ((val >> 12) & 0x000001FF) +#define WMITLV_GET_TAG_ARRAY_SIZE(val) ((val >> 21) & 0x000001FF) +#define WMITLV_GET_TAG_VARIED(val) ((val >> 30) & 0x00000001) + +#define WMITLV_SET_ATTRB0(id) ((WMITLV_GET_TAG_NUM_TLV_ATTRIB(id) << 24) | \ + (id & 0x00FFFFFF)) +#define WMITLV_SET_ATTRB1(tagID, tagStructSize, tagArraySize, tagVaried) \ + (((tagVaried&0x1)<<30) | ((tagArraySize&0x1FF)<<21) | \ + ((tagStructSize&0x1FF)<<12) | (tagID&0xFFF)) + +#define WMITLV_OP_SET_TLV_ATTRIB_macro(param_ptr, param_len, wmi_cmd_event_id, \ + elem_tlv_tag, elem_struc_type, elem_name, var_len, arr_size) \ + WMITLV_SET_ATTRB1(elem_tlv_tag, sizeof(elem_struc_type), arr_size, var_len), + +#define WMITLV_GET_CMD_EVT_ATTRB_LIST(id) \ + WMITLV_SET_ATTRB0(id), \ + WMITLV_TABLE(id,SET_TLV_ATTRIB, NULL, 0) + +A_UINT32 cmd_attr_list[] = { + WMITLV_ALL_CMD_LIST(WMITLV_GET_CMD_EVT_ATTRB_LIST) +}; + +A_UINT32 evt_attr_list[] = { + WMITLV_ALL_EVT_LIST(WMITLV_GET_CMD_EVT_ATTRB_LIST) +}; + +#ifdef NO_DYNAMIC_MEM_ALLOC +static wmitlv_cmd_param_info *g_wmi_static_cmd_param_info_buf; +A_UINT32 g_wmi_static_max_cmd_param_tlvs; +#endif + + +/** + * wmitlv_set_static_param_tlv_buf() - tlv helper function + * @param_tlv_buf: tlv buffer parameter + * @max_tlvs_accomodated: max no of tlv entries + * + * + * WMI TLV Helper function to set the static cmd_param_tlv structure + * and number of TLVs that can be accomodated in the structure. + * This function should be used when dynamic memory allocation is not + * supported. When dynamic memory allocation is not supported by any + * component then NO_DYNAMIC_MEMALLOC macro has to be defined in respective + * tlv_platform.c file. And respective component has to allocate + * cmd_param_tlv structure buffer to accomodate whatever number of TLV's. + * Both the buffer address and number of TLV's that can be accomodated in + * the buffer should be sent as arguments to this function. + * + * Return None + */ +void +wmitlv_set_static_param_tlv_buf(void *param_tlv_buf, + A_UINT32 max_tlvs_accomodated) +{ +#ifdef NO_DYNAMIC_MEM_ALLOC + g_wmi_static_cmd_param_info_buf = param_tlv_buf; + g_wmi_static_max_cmd_param_tlvs = max_tlvs_accomodated; +#endif +} + +/** + * wmitlv_get_attributes() - tlv helper function + * @is_cmd_id: boolean for command attribute + * @cmd_event_id: command event id + * @curr_tlv_order: tlv order + * @tlv_attr_ptr: pointer to tlv attribute + * + * + * WMI TLV Helper functions to find the attributes of the + * Command/Event TLVs. + * + * Return: 0 if success. Return >=1 if failure. + */ +static +A_UINT32 wmitlv_get_attributes(A_UINT32 is_cmd_id, A_UINT32 cmd_event_id, + A_UINT32 curr_tlv_order, + wmitlv_attributes_struc *tlv_attr_ptr) +{ + A_UINT32 i, base_index, num_tlvs, num_entries; + A_UINT32 *pAttrArrayList; + + if (is_cmd_id) { + pAttrArrayList = &cmd_attr_list[0]; + num_entries = QDF_ARRAY_SIZE(cmd_attr_list); + } else { + pAttrArrayList = &evt_attr_list[0]; + num_entries = QDF_ARRAY_SIZE(evt_attr_list); + } + + for (i = 0; i < num_entries; i++) { + num_tlvs = WMITLV_GET_NUM_TLVS(pAttrArrayList[i]); + if (WMITLV_GET_CMDID(cmd_event_id) == + WMITLV_GET_CMDID(pAttrArrayList[i])) { + tlv_attr_ptr->cmd_num_tlv = num_tlvs; + /* Return success from here when only number of TLVS for + * this command/event is required */ + if (curr_tlv_order == WMITLV_GET_ATTRIB_NUM_TLVS) { + wmi_tlv_print_verbose + ("%s: WMI TLV attribute definitions for %s:0x%x found; num_of_tlvs:%d\n", + __func__, (is_cmd_id ? "Cmd" : "Evt"), + cmd_event_id, num_tlvs); + return 0; + } + + /* Return failure if tlv_order is more than the expected + * number of TLVs */ + if (curr_tlv_order >= num_tlvs) { + wmi_tlv_print_error + ("%s: ERROR: TLV order %d greater than num_of_tlvs:%d for %s:0x%x\n", + __func__, curr_tlv_order, num_tlvs, + (is_cmd_id ? "Cmd" : "Evt"), cmd_event_id); + return 1; + } + + base_index = i + 1; /* index to first TLV attributes */ + wmi_tlv_print_verbose + ("%s: WMI TLV attributes for %s:0x%x tlv[%d]:0x%x\n", + __func__, (is_cmd_id ? "Cmd" : "Evt"), + cmd_event_id, curr_tlv_order, + pAttrArrayList[(base_index + curr_tlv_order)]); + tlv_attr_ptr->tag_order = curr_tlv_order; + tlv_attr_ptr->tag_id = + WMITLV_GET_TAGID(pAttrArrayList + [(base_index + curr_tlv_order)]); + tlv_attr_ptr->tag_struct_size = + WMITLV_GET_TAG_STRUCT_SIZE(pAttrArrayList + [(base_index + + curr_tlv_order)]); + tlv_attr_ptr->tag_varied_size = + WMITLV_GET_TAG_VARIED(pAttrArrayList + [(base_index + + curr_tlv_order)]); + tlv_attr_ptr->tag_array_size = + WMITLV_GET_TAG_ARRAY_SIZE(pAttrArrayList + [(base_index + + curr_tlv_order)]); + return 0; + } + i += num_tlvs; + } + + wmi_tlv_print_error + ("%s: ERROR: Didn't found WMI TLV attribute definitions for %s:0x%x\n", + __func__, (is_cmd_id ? "Cmd" : "Evt"), cmd_event_id); + return 1; +} + +/** + * wmitlv_check_tlv_params() - tlv helper function + * @os_handle: os context handle + * @param_struc_ptr: pointer to tlv structure + * @is_cmd_id: boolean for command attribute + * @wmi_cmd_event_id: command event id + * + * + * Helper Function to vaidate the prepared TLV's for + * an WMI event/command to be sent. + * + * Return: 0 if success. Return < 0 if failure. + */ +static int +wmitlv_check_tlv_params(void *os_handle, void *param_struc_ptr, + A_UINT32 param_buf_len, A_UINT32 is_cmd_id, + A_UINT32 wmi_cmd_event_id) +{ + wmitlv_attributes_struc attr_struct_ptr; + A_UINT32 buf_idx = 0; + A_UINT32 tlv_index = 0; + A_UINT8 *buf_ptr = (unsigned char *)param_struc_ptr; + A_UINT32 expected_num_tlvs, expected_tlv_len; + A_INT32 error = -1; + + /* 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) { + wmi_tlv_print_error + ("%s: ERROR: Couldn't get expected number of TLVs for Cmd=%d\n", + __func__, wmi_cmd_event_id); + goto Error_wmitlv_check_tlv_params; + } + + /* NOTE: the returned number of TLVs is in "attr_struct_ptr.cmd_num_tlv" */ + + expected_num_tlvs = attr_struct_ptr.cmd_num_tlv; + + while ((buf_idx + WMI_TLV_HDR_SIZE) <= param_buf_len) { + A_UINT32 curr_tlv_tag = + WMITLV_GET_TLVTAG(WMITLV_GET_HDR(buf_ptr)); + A_UINT32 curr_tlv_len = + WMITLV_GET_TLVLEN(WMITLV_GET_HDR(buf_ptr)); + + if ((buf_idx + WMI_TLV_HDR_SIZE + curr_tlv_len) > param_buf_len) { + wmi_tlv_print_error + ("%s: ERROR: Invalid TLV length for Cmd=%d Tag_order=%d buf_idx=%d Tag:%d Len:%d TotalLen:%d\n", + __func__, wmi_cmd_event_id, tlv_index, buf_idx, + curr_tlv_tag, curr_tlv_len, param_buf_len); + goto Error_wmitlv_check_tlv_params; + } + + /* 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) { + wmi_tlv_print_error + ("%s: ERROR: No TLV attributes found for Cmd=%d Tag_order=%d\n", + __func__, wmi_cmd_event_id, tlv_index); + goto Error_wmitlv_check_tlv_params; + } + + /* Found the TLV that we wanted */ + wmi_tlv_print_verbose("%s: [tlv %d]: tag=%d, len=%d\n", + __func__, tlv_index, curr_tlv_tag, + curr_tlv_len); + + /* Validating Tag ID order */ + if (curr_tlv_tag != attr_struct_ptr.tag_id) { + wmi_tlv_print_error + ("%s: ERROR: TLV has wrong tag in order for Cmd=0x%x. Given=%d, Expected=%d.\n", + __func__, wmi_cmd_event_id, curr_tlv_tag, + attr_struct_ptr.tag_id); + goto Error_wmitlv_check_tlv_params; + } + + /* Validate Tag length */ + /* Array TLVs length checking needs special handling */ + if ((curr_tlv_tag >= WMITLV_TAG_FIRST_ARRAY_ENUM) + && (curr_tlv_tag <= WMITLV_TAG_LAST_ARRAY_ENUM)) { + if (attr_struct_ptr.tag_varied_size == WMITLV_SIZE_FIX) { + /* Array size can't be invalid for fixed size Array TLV */ + if (WMITLV_ARR_SIZE_INVALID == + attr_struct_ptr.tag_array_size) { + wmi_tlv_print_error + ("%s: ERROR: array_size can't be invalid for Array TLV Cmd=0x%x Tag=%d\n", + __func__, wmi_cmd_event_id, + curr_tlv_tag); + goto Error_wmitlv_check_tlv_params; + } + + expected_tlv_len = + attr_struct_ptr.tag_array_size * + attr_struct_ptr.tag_struct_size; + /* Paddding is only required for Byte array Tlvs all other + * array tlv's should be aligned to 4 bytes during their + * definition */ + if (WMITLV_TAG_ARRAY_BYTE == + attr_struct_ptr.tag_id) { + expected_tlv_len = + roundup(expected_tlv_len, + sizeof(A_UINT32)); + } + + if (curr_tlv_len != expected_tlv_len) { + wmi_tlv_print_error + ("%s: ERROR: TLV has wrong length for Cmd=0x%x. Tag_order=%d Tag=%d, Given_Len:%d Expected_Len=%d.\n", + __func__, wmi_cmd_event_id, + tlv_index, curr_tlv_tag, + curr_tlv_len, expected_tlv_len); + goto Error_wmitlv_check_tlv_params; + } + } else { + /* Array size should be invalid for variable size Array TLV */ + if (WMITLV_ARR_SIZE_INVALID != + attr_struct_ptr.tag_array_size) { + wmi_tlv_print_error + ("%s: ERROR: array_size should be invalid for Array TLV Cmd=0x%x Tag=%d\n", + __func__, wmi_cmd_event_id, + curr_tlv_tag); + goto Error_wmitlv_check_tlv_params; + } + + /* Incase of variable length TLV's, there is no expectation + * on the length field so do whatever checking you can + * depending on the TLV tag if TLV length is non-zero */ + if (curr_tlv_len != 0) { + /* Verify TLV length is aligned to the size of structure */ + if ((curr_tlv_len % + attr_struct_ptr.tag_struct_size) != + 0) { + wmi_tlv_print_error + ("%s: ERROR: TLV length %d for Cmd=0x%x is not aligned to size of structure(%d bytes)\n", + __func__, curr_tlv_len, + wmi_cmd_event_id, + attr_struct_ptr. + tag_struct_size); + goto Error_wmitlv_check_tlv_params; + } + + if (curr_tlv_tag == + WMITLV_TAG_ARRAY_STRUC) { + A_UINT8 *tlv_buf_ptr = NULL; + A_UINT32 in_tlv_len; + A_UINT32 idx; + A_UINT32 num_of_elems; + + /* Verify length of inner TLVs */ + + num_of_elems = + curr_tlv_len / + attr_struct_ptr. + tag_struct_size; + /* Set tlv_buf_ptr to the first inner TLV address */ + tlv_buf_ptr = + buf_ptr + WMI_TLV_HDR_SIZE; + for (idx = 0; + idx < num_of_elems; + idx++) { + in_tlv_len = + WMITLV_GET_TLVLEN + (WMITLV_GET_HDR + (tlv_buf_ptr)); + if ((in_tlv_len + + WMI_TLV_HDR_SIZE) + != + attr_struct_ptr. + tag_struct_size) { + wmi_tlv_print_error + ("%s: ERROR: TLV has wrong length for Cmd=0x%x. Tag_order=%d Tag=%d, Given_Len:%zu Expected_Len=%d.\n", + __func__, + wmi_cmd_event_id, + tlv_index, + curr_tlv_tag, + (in_tlv_len + + + WMI_TLV_HDR_SIZE), + attr_struct_ptr. + tag_struct_size); + goto Error_wmitlv_check_tlv_params; + } + tlv_buf_ptr += + in_tlv_len + + WMI_TLV_HDR_SIZE; + } + } else + if ((curr_tlv_tag == + WMITLV_TAG_ARRAY_UINT32) + || (curr_tlv_tag == + WMITLV_TAG_ARRAY_BYTE) + || (curr_tlv_tag == + WMITLV_TAG_ARRAY_FIXED_STRUC)) { + /* Nothing to verify here */ + } else { + wmi_tlv_print_error + ("%s ERROR Need to handle the Array tlv %d for variable length for Cmd=0x%x\n", + __func__, + attr_struct_ptr.tag_id, + wmi_cmd_event_id); + goto Error_wmitlv_check_tlv_params; + } + } + } + } else { + /* Non-array TLV. */ + + if ((curr_tlv_len + WMI_TLV_HDR_SIZE) != + attr_struct_ptr.tag_struct_size) { + wmi_tlv_print_error + ("%s: ERROR: TLV has wrong length for Cmd=0x%x. Given=%zu, Expected=%d.\n", + __func__, wmi_cmd_event_id, + (curr_tlv_len + WMI_TLV_HDR_SIZE), + attr_struct_ptr.tag_struct_size); + goto Error_wmitlv_check_tlv_params; + } + } + + /* Check TLV length is aligned to 4 bytes or not */ + if ((curr_tlv_len % sizeof(A_UINT32)) != 0) { + wmi_tlv_print_error + ("%s: ERROR: TLV length %d for Cmd=0x%x is not aligned to %zu bytes\n", + __func__, curr_tlv_len, wmi_cmd_event_id, + sizeof(A_UINT32)); + goto Error_wmitlv_check_tlv_params; + } + + tlv_index++; + buf_ptr += curr_tlv_len + WMI_TLV_HDR_SIZE; + buf_idx += curr_tlv_len + WMI_TLV_HDR_SIZE; + } + + if (tlv_index != expected_num_tlvs) { + wmi_tlv_print_verbose + ("%s: INFO: Less number of TLVs filled for Cmd=0x%x Filled %d Expected=%d\n", + __func__, wmi_cmd_event_id, tlv_index, expected_num_tlvs); + } + + return 0; +Error_wmitlv_check_tlv_params: + return error; +} + +/** + * wmitlv_check_event_tlv_params() - tlv helper function + * @os_handle: os context handle + * @param_struc_ptr: pointer to tlv structure + * @is_cmd_id: boolean for command attribute + * @wmi_cmd_event_id: command event id + * + * + * Helper Function to vaidate the prepared TLV's for + * an WMI event/command to be sent. + * + * Return: 0 if success. Return < 0 if failure. + */ +int +wmitlv_check_event_tlv_params(void *os_handle, void *param_struc_ptr, + A_UINT32 param_buf_len, A_UINT32 wmi_cmd_event_id) +{ + A_UINT32 is_cmd_id = 0; + + return wmitlv_check_tlv_params + (os_handle, param_struc_ptr, param_buf_len, is_cmd_id, + wmi_cmd_event_id); +} + +/** + * wmitlv_check_command_tlv_params() - tlv helper function + * @os_handle: os context handle + * @param_struc_ptr: pointer to tlv structure + * @is_cmd_id: boolean for command attribute + * @wmi_cmd_event_id: command event id + * + * + * Helper Function to vaidate the prepared TLV's for + * an WMI event/command to be sent. + * + * Return: 0 if success. Return < 0 if failure. + */ +int +wmitlv_check_command_tlv_params(void *os_handle, void *param_struc_ptr, + A_UINT32 param_buf_len, + A_UINT32 wmi_cmd_event_id) +{ + A_UINT32 is_cmd_id = 1; + + return wmitlv_check_tlv_params + (os_handle, param_struc_ptr, param_buf_len, is_cmd_id, + wmi_cmd_event_id); +} + +/** + * wmitlv_check_and_pad_tlvs() - tlv helper function + * @os_handle: os context handle + * @param_buf_len: length of tlv parameter + * @param_struc_ptr: pointer to tlv structure + * @is_cmd_id: boolean for command attribute + * @wmi_cmd_event_id: command event id + * @wmi_cmd_struct_ptr: wmi command structure + * + * + * vaidate the TLV's coming for an event/command and + * also pads data to TLV's if necessary + * + * Return: 0 if success. Return < 0 if failure. + */ +static int +wmitlv_check_and_pad_tlvs(void *os_handle, void *param_struc_ptr, + A_UINT32 param_buf_len, A_UINT32 is_cmd_id, + A_UINT32 wmi_cmd_event_id, void **wmi_cmd_struct_ptr) +{ + wmitlv_attributes_struc attr_struct_ptr; + A_UINT32 buf_idx = 0; + A_UINT32 tlv_index = 0; + A_UINT32 num_of_elems = 0; + int tlv_size_diff = 0; + A_UINT8 *buf_ptr = (unsigned char *)param_struc_ptr; + wmitlv_cmd_param_info *cmd_param_tlvs_ptr = NULL; + A_UINT32 remaining_expected_tlvs = 0xFFFFFFFF; + A_UINT32 len_wmi_cmd_struct_buf; + A_INT32 error = -1; + + /* 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) { + wmi_tlv_print_error + ("%s: ERROR: Couldn't get expected number of TLVs for Cmd=%d\n", + __func__, wmi_cmd_event_id); + return error; + } + /* NOTE: the returned number of TLVs is in "attr_struct_ptr.cmd_num_tlv" */ + + /* Create base structure of format wmi_cmd_event_id##_param_tlvs */ + len_wmi_cmd_struct_buf = + attr_struct_ptr.cmd_num_tlv * sizeof(wmitlv_cmd_param_info); +#ifndef NO_DYNAMIC_MEM_ALLOC + /* Dynamic memory allocation supported */ + wmi_tlv_os_mem_alloc(os_handle, *wmi_cmd_struct_ptr, + len_wmi_cmd_struct_buf); +#else + /* Dynamic memory allocation is not supported. Use the buffer + * g_wmi_static_cmd_param_info_buf, which should be set using + * wmi_tlv_set_static_param_tlv_buf(), + * for base structure of format wmi_cmd_event_id##_param_tlvs */ + *wmi_cmd_struct_ptr = g_wmi_static_cmd_param_info_buf; + if (attr_struct_ptr.cmd_num_tlv > g_wmi_static_max_cmd_param_tlvs) { + /* Error: Expecting more TLVs that accomodated for static structure */ + wmi_tlv_print_error + ("%s: Error: Expecting more TLVs that accomodated for static structure. Expected:%d Accomodated:%d\n", + __func__, attr_struct_ptr.cmd_num_tlv, + g_wmi_static_max_cmd_param_tlvs); + return error; + } +#endif + if (*wmi_cmd_struct_ptr == NULL) { + /* Error: unable to alloc memory */ + wmi_tlv_print_error + ("%s: Error: unable to alloc memory (size=%d) for TLV\n", + __func__, len_wmi_cmd_struct_buf); + return error; + } + + cmd_param_tlvs_ptr = (wmitlv_cmd_param_info *) *wmi_cmd_struct_ptr; + wmi_tlv_OS_MEMZERO(cmd_param_tlvs_ptr, len_wmi_cmd_struct_buf); + remaining_expected_tlvs = attr_struct_ptr.cmd_num_tlv; + + while (((buf_idx + WMI_TLV_HDR_SIZE) <= param_buf_len) + && (remaining_expected_tlvs)) { + A_UINT32 curr_tlv_tag = + WMITLV_GET_TLVTAG(WMITLV_GET_HDR(buf_ptr)); + A_UINT32 curr_tlv_len = + WMITLV_GET_TLVLEN(WMITLV_GET_HDR(buf_ptr)); + int num_padding_bytes = 0; + + /* 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) { + wmi_tlv_print_error + ("%s: ERROR: No TLV attributes found for Cmd=%d Tag_order=%d\n", + __func__, wmi_cmd_event_id, tlv_index); + goto Error_wmitlv_check_and_pad_tlvs; + } + + /* Found the TLV that we wanted */ + wmi_tlv_print_verbose("%s: [tlv %d]: tag=%d, len=%d\n", + __func__, tlv_index, curr_tlv_tag, + curr_tlv_len); + + /* Validating Tag order */ + if (curr_tlv_tag != attr_struct_ptr.tag_id) { + wmi_tlv_print_error + ("%s: ERROR: TLV has wrong tag in order for Cmd=0x%x. Given=%d, Expected=%d.\n", + __func__, wmi_cmd_event_id, curr_tlv_tag, + attr_struct_ptr.tag_id); + goto Error_wmitlv_check_and_pad_tlvs; + } + + if ((curr_tlv_tag >= WMITLV_TAG_FIRST_ARRAY_ENUM) + && (curr_tlv_tag <= WMITLV_TAG_LAST_ARRAY_ENUM)) { + /* Current Tag is an array of some kind. */ + /* Skip the TLV header of this array */ + buf_ptr += WMI_TLV_HDR_SIZE; + buf_idx += WMI_TLV_HDR_SIZE; + } else { + /* Non-array TLV. */ + curr_tlv_len += WMI_TLV_HDR_SIZE; + } + + if (attr_struct_ptr.tag_varied_size == WMITLV_SIZE_FIX) { + /* This TLV is fixed length */ + if (WMITLV_ARR_SIZE_INVALID == + attr_struct_ptr.tag_array_size) { + tlv_size_diff = + curr_tlv_len - + attr_struct_ptr.tag_struct_size; + num_of_elems = + (curr_tlv_len > WMI_TLV_HDR_SIZE) ? 1 : 0; + } else { + tlv_size_diff = + curr_tlv_len - + (attr_struct_ptr.tag_struct_size * + attr_struct_ptr.tag_array_size); + num_of_elems = attr_struct_ptr.tag_array_size; + } + } else { + /* This TLV has a variable number of elements */ + if (WMITLV_TAG_ARRAY_STRUC == attr_struct_ptr.tag_id) { + A_UINT32 in_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; + 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 { + tlv_size_diff = 0; + num_of_elems = 0; + } + } else + if ((WMITLV_TAG_ARRAY_UINT32 == + attr_struct_ptr.tag_id) + || (WMITLV_TAG_ARRAY_BYTE == + attr_struct_ptr.tag_id) + || (WMITLV_TAG_ARRAY_FIXED_STRUC == + attr_struct_ptr.tag_id)) { + tlv_size_diff = 0; + num_of_elems = + curr_tlv_len / + attr_struct_ptr.tag_struct_size; + } else { + wmi_tlv_print_error + ("%s ERROR Need to handle this tag ID for variable length %d\n", + __func__, attr_struct_ptr.tag_id); + goto Error_wmitlv_check_and_pad_tlvs; + } + } + + if ((WMITLV_TAG_ARRAY_STRUC == attr_struct_ptr.tag_id) && + (tlv_size_diff != 0)) { + void *new_tlv_buf = NULL; + A_UINT8 *tlv_buf_ptr = NULL; + A_UINT32 in_tlv_len; + A_UINT32 i; + + if (attr_struct_ptr.tag_varied_size == WMITLV_SIZE_FIX) { + /* This is not allowed. The tag WMITLV_TAG_ARRAY_STRUC can + * only be used with variable-length structure array + * should not have a fixed number of elements (contradicting). + * Use WMITLV_TAG_ARRAY_FIXED_STRUC tag for fixed size + * structure array(where structure never change without + * breaking compatibility) */ + wmi_tlv_print_error + ("%s: ERROR: TLV (tag=%d) should be variable-length and not fixed length\n", + __func__, curr_tlv_tag); + goto Error_wmitlv_check_and_pad_tlvs; + } + + /* Warning: Needs to allocate a larger structure and pad with zeros */ + wmi_tlv_print_verbose + ("%s: WARN: TLV array of structures needs padding. tlv_size_diff=%d\n", + __func__, tlv_size_diff); + + /* incoming structure length */ + in_tlv_len = + WMITLV_GET_TLVLEN(WMITLV_GET_HDR(buf_ptr)) + + WMI_TLV_HDR_SIZE; +#ifndef NO_DYNAMIC_MEM_ALLOC + wmi_tlv_os_mem_alloc(os_handle, new_tlv_buf, + (num_of_elems * + attr_struct_ptr.tag_struct_size)); + if (new_tlv_buf == NULL) { + /* Error: unable to alloc memory */ + wmi_tlv_print_error + ("%s: Error: unable to alloc memory (size=%d) for padding the TLV array %d\n", + __func__, + (num_of_elems * + attr_struct_ptr.tag_struct_size), + curr_tlv_tag); + goto Error_wmitlv_check_and_pad_tlvs; + } + + wmi_tlv_OS_MEMZERO(new_tlv_buf, + (num_of_elems * + attr_struct_ptr.tag_struct_size)); + tlv_buf_ptr = (A_UINT8 *) new_tlv_buf; + for (i = 0; i < num_of_elems; i++) { + if (tlv_size_diff > 0) { + /* Incoming structure size is greater than expected + * structure size. so copy the number of bytes equal + * to expected structure size */ + wmi_tlv_OS_MEMCPY(tlv_buf_ptr, + (void *)(buf_ptr + + i * + in_tlv_len), + attr_struct_ptr. + tag_struct_size); + } else { + /* Incoming structure size is smaller than expected + * structure size. so copy the number of bytes equal + * to incoming structure size */ + wmi_tlv_OS_MEMCPY(tlv_buf_ptr, + (void *)(buf_ptr + + i * + in_tlv_len), + in_tlv_len); + } + tlv_buf_ptr += attr_struct_ptr.tag_struct_size; + } +#else + { + A_UINT8 *src_addr; + A_UINT8 *dst_addr; + A_UINT32 buf_mov_len; + + if (tlv_size_diff < 0) { + /* 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)) { + src_addr = + buf_ptr + curr_tlv_len; + 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 */ + tlv_buf_ptr = buf_ptr; + for (i = 0; i < num_of_elems; 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); + } + + /* Set the padding bytes to zeroes */ + wmi_tlv_OS_MEMZERO(src_addr, + num_padding_bytes); + + tlv_buf_ptr += + attr_struct_ptr. + tag_struct_size; + } + + /* 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; + + new_tlv_buf = buf_ptr; + } else { + /* Incoming structure size is greater than expected size + * then this needs shrinking for each element in the array */ + + /* Find amount of bytes to be shrinked for one element */ + num_padding_bytes = tlv_size_diff * -1; + + /* Move subsequent elements of array up by number of bytes + * to be shrinked for one element */ + tlv_buf_ptr = buf_ptr; + for (i = 0; i < (num_of_elems - 1); i++) { + src_addr = + tlv_buf_ptr + in_tlv_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); + + tlv_buf_ptr += + attr_struct_ptr. + tag_struct_size; + } + + /* Move subsequent TLVs by number of bytes to be shrinked + * for all elements */ + if (param_buf_len > + (buf_idx + curr_tlv_len)) { + src_addr = + buf_ptr + curr_tlv_len; + 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); + } + + /* Update the number of padding bytes to total number of + * bytes shrinked for all elements in the array */ + num_padding_bytes = + num_padding_bytes * num_of_elems; + + new_tlv_buf = buf_ptr; + } + } +#endif + cmd_param_tlvs_ptr[tlv_index].tlv_ptr = new_tlv_buf; + cmd_param_tlvs_ptr[tlv_index].num_elements = + num_of_elems; + cmd_param_tlvs_ptr[tlv_index].buf_is_allocated = 1; /* Indicates that buffer is allocated */ + + } else if (tlv_size_diff >= 0) { + /* Warning: some parameter truncation */ + if (tlv_size_diff > 0) { + wmi_tlv_print_verbose + ("%s: WARN: TLV truncated. tlv_size_diff=%d, curr_tlv_len=%d\n", + __func__, tlv_size_diff, curr_tlv_len); + } + /* TODO: this next line needs more comments and explanation */ + cmd_param_tlvs_ptr[tlv_index].tlv_ptr = + (attr_struct_ptr.tag_varied_size + && !curr_tlv_len) ? NULL : (void *)buf_ptr; + cmd_param_tlvs_ptr[tlv_index].num_elements = + num_of_elems; + cmd_param_tlvs_ptr[tlv_index].buf_is_allocated = 0; /* Indicates that buffer is not allocated */ + } else { + void *new_tlv_buf = NULL; + + /* Warning: Needs to allocate a larger structure and pad with zeros */ + wmi_tlv_print_verbose + ("%s: WARN: TLV needs padding. tlv_size_diff=%d\n", + __func__, tlv_size_diff); +#ifndef NO_DYNAMIC_MEM_ALLOC + /* Dynamic memory allocation is supported */ + wmi_tlv_os_mem_alloc(os_handle, new_tlv_buf, + (curr_tlv_len - tlv_size_diff)); + if (new_tlv_buf == NULL) { + /* Error: unable to alloc memory */ + wmi_tlv_print_error + ("%s: Error: unable to alloc memory (size=%d) for padding the TLV %d\n", + __func__, (curr_tlv_len - tlv_size_diff), + curr_tlv_tag); + goto Error_wmitlv_check_and_pad_tlvs; + } + + wmi_tlv_OS_MEMZERO(new_tlv_buf, + (curr_tlv_len - tlv_size_diff)); + wmi_tlv_OS_MEMCPY(new_tlv_buf, (void *)buf_ptr, + curr_tlv_len); +#else + /* Dynamic memory allocation is not supported. Padding has + * to be done with in the existing buffer assuming we have + * enough space to grow */ + { + /* Note: tlv_size_diff is a value less than zero */ + /* Move the Subsequent TLVs by amount of bytes needs to be padded */ + A_UINT8 *src_addr; + A_UINT8 *dst_addr; + A_UINT32 src_len; + + num_padding_bytes = (tlv_size_diff * -1); + + src_addr = buf_ptr + curr_tlv_len; + dst_addr = + buf_ptr + curr_tlv_len + num_padding_bytes; + src_len = + param_buf_len - (buf_idx + curr_tlv_len); + + wmi_tlv_OS_MEMMOVE(dst_addr, src_addr, src_len); + + /* Set the padding bytes to zeroes */ + wmi_tlv_OS_MEMZERO(src_addr, num_padding_bytes); + + new_tlv_buf = buf_ptr; + } +#endif + cmd_param_tlvs_ptr[tlv_index].tlv_ptr = new_tlv_buf; + cmd_param_tlvs_ptr[tlv_index].num_elements = + num_of_elems; + cmd_param_tlvs_ptr[tlv_index].buf_is_allocated = 1; /* Indicates that buffer is allocated */ + } + + tlv_index++; + remaining_expected_tlvs--; + buf_ptr += curr_tlv_len + num_padding_bytes; + buf_idx += curr_tlv_len + num_padding_bytes; + } + + return 0; +Error_wmitlv_check_and_pad_tlvs: + if (is_cmd_id) { + wmitlv_free_allocated_command_tlvs(wmi_cmd_event_id, + wmi_cmd_struct_ptr); + } else { + wmitlv_free_allocated_event_tlvs(wmi_cmd_event_id, + wmi_cmd_struct_ptr); + } + *wmi_cmd_struct_ptr = NULL; + return error; +} + +/** + * wmitlv_check_and_pad_event_tlvs() - tlv helper function + * @os_handle: os context handle + * @param_struc_ptr: pointer to tlv structure + * @param_buf_len: length of tlv parameter + * @wmi_cmd_event_id: command event id + * @wmi_cmd_struct_ptr: wmi command structure + * + * + * validate and pad(if necessary) for incoming WMI Event TLVs + * + * Return: 0 if success. Return < 0 if failure. + */ +int +wmitlv_check_and_pad_event_tlvs(void *os_handle, void *param_struc_ptr, + A_UINT32 param_buf_len, + A_UINT32 wmi_cmd_event_id, + void **wmi_cmd_struct_ptr) +{ + A_UINT32 is_cmd_id = 0; + return wmitlv_check_and_pad_tlvs + (os_handle, param_struc_ptr, param_buf_len, is_cmd_id, + wmi_cmd_event_id, wmi_cmd_struct_ptr); +} + +/** + * wmitlv_check_and_pad_command_tlvs() - tlv helper function + * @os_handle: os context handle + * @param_struc_ptr: pointer to tlv structure + * @param_buf_len: length of tlv parameter + * @wmi_cmd_event_id: command event id + * @wmi_cmd_struct_ptr: wmi command structure + * + * + * validate and pad(if necessary) for incoming WMI Command TLVs + * + * Return: 0 if success. Return < 0 if failure. + */ +int +wmitlv_check_and_pad_command_tlvs(void *os_handle, void *param_struc_ptr, + A_UINT32 param_buf_len, + A_UINT32 wmi_cmd_event_id, + void **wmi_cmd_struct_ptr) +{ + A_UINT32 is_cmd_id = 1; + return wmitlv_check_and_pad_tlvs + (os_handle, param_struc_ptr, param_buf_len, is_cmd_id, + wmi_cmd_event_id, wmi_cmd_struct_ptr); +} + +/** + * wmitlv_free_allocated_tlvs() - tlv helper function + * @is_cmd_id: bollean to check if cmd or event tlv + * @cmd_event_id: command or event id + * @wmi_cmd_struct_ptr: wmi command structure + * + * + * free any allocated buffers for WMI Event/Command TLV processing + * + * Return: none + */ +static void wmitlv_free_allocated_tlvs(A_UINT32 is_cmd_id, + A_UINT32 cmd_event_id, + void **wmi_cmd_struct_ptr) +{ + void *ptr = *wmi_cmd_struct_ptr; + + if (!ptr) { + wmi_tlv_print_error("%s: Nothing to free for CMD/Event 0x%x\n", + __func__, cmd_event_id); + return; + } +#ifndef NO_DYNAMIC_MEM_ALLOC + +/* macro to free that previously allocated memory for this TLV. When (op==FREE_TLV_ELEM). */ +#define WMITLV_OP_FREE_TLV_ELEM_macro(param_ptr, param_len, wmi_cmd_event_id, elem_tlv_tag, elem_struc_type, elem_name, var_len, arr_size) \ + if ((((WMITLV_TYPEDEF_STRUCT_PARAMS_TLVS(wmi_cmd_event_id) *)ptr)->WMITLV_FIELD_BUF_IS_ALLOCATED(elem_name)) && \ + (((WMITLV_TYPEDEF_STRUCT_PARAMS_TLVS(wmi_cmd_event_id) *)ptr)->elem_name != NULL)) \ + { \ + wmi_tlv_os_mem_free(((WMITLV_TYPEDEF_STRUCT_PARAMS_TLVS(wmi_cmd_event_id) *)ptr)->elem_name); \ + } + +#define WMITLV_FREE_TLV_ELEMS(id) \ +case id: \ +{ \ + WMITLV_TABLE(id, FREE_TLV_ELEM, NULL, 0) \ +} \ +break; + + if (is_cmd_id) { + switch (cmd_event_id) { + WMITLV_ALL_CMD_LIST(WMITLV_FREE_TLV_ELEMS); + default: + wmi_tlv_print_error + ("%s: ERROR: Cannot find the TLVs attributes for Cmd=0x%x, %d\n", + __func__, cmd_event_id, cmd_event_id); + } + } else { + switch (cmd_event_id) { + WMITLV_ALL_EVT_LIST(WMITLV_FREE_TLV_ELEMS); + default: + wmi_tlv_print_error + ("%s: ERROR: Cannot find the TLVs attributes for Cmd=0x%x, %d\n", + __func__, cmd_event_id, cmd_event_id); + } + } + + wmi_tlv_os_mem_free(*wmi_cmd_struct_ptr); + *wmi_cmd_struct_ptr = NULL; +#endif + + return; +} + +/** + * wmitlv_free_allocated_command_tlvs() - tlv helper function + * @cmd_event_id: command or event id + * @wmi_cmd_struct_ptr: wmi command structure + * + * + * free any allocated buffers for WMI Event/Command TLV processing + * + * Return: none + */ +void wmitlv_free_allocated_command_tlvs(A_UINT32 cmd_event_id, + void **wmi_cmd_struct_ptr) +{ + wmitlv_free_allocated_tlvs(1, cmd_event_id, wmi_cmd_struct_ptr); +} + +/** + * wmitlv_free_allocated_event_tlvs() - tlv helper function + * @cmd_event_id: command or event id + * @wmi_cmd_struct_ptr: wmi command structure + * + * + * free any allocated buffers for WMI Event/Command TLV processing + * + * Return: none + */ +void wmitlv_free_allocated_event_tlvs(A_UINT32 cmd_event_id, + void **wmi_cmd_struct_ptr) +{ + wmitlv_free_allocated_tlvs(0, cmd_event_id, wmi_cmd_struct_ptr); +} + +/** + * wmi_versions_are_compatible() - tlv helper function + * @vers1: host wmi version + * @vers2: target wmi version + * + * + * check if two given wmi versions are compatible + * + * Return: none + */ +int +wmi_versions_are_compatible(wmi_abi_version *vers1, wmi_abi_version *vers2) +{ + if ((vers1->abi_version_ns_0 != vers2->abi_version_ns_0) || + (vers1->abi_version_ns_1 != vers2->abi_version_ns_1) || + (vers1->abi_version_ns_2 != vers2->abi_version_ns_2) || + (vers1->abi_version_ns_3 != vers2->abi_version_ns_3)) { + /* The namespaces are different. Incompatible. */ + return 0; + } + + if (vers1->abi_version_0 != vers2->abi_version_0) { + /* The major or minor versions are different. Incompatible */ + return 0; + } + /* We ignore the build version */ + return 1; +} + +/** + * wmi_versions_can_downgrade() - tlv helper function + * @version_whitelist_table: version table + * @my_vers: host version + * @opp_vers: target version + * @out_vers: downgraded version + * + * + * check if target wmi version can be downgraded + * + * Return: 0 if success. Return < 0 if failure. + */ +static int +wmi_versions_can_downgrade(int num_whitelist, + wmi_whitelist_version_info *version_whitelist_table, + wmi_abi_version *my_vers, + wmi_abi_version *opp_vers, + wmi_abi_version *out_vers) +{ + A_UINT8 can_try_to_downgrade; + A_UINT32 my_major_vers = WMI_VER_GET_MAJOR(my_vers->abi_version_0); + A_UINT32 my_minor_vers = WMI_VER_GET_MINOR(my_vers->abi_version_0); + A_UINT32 opp_major_vers = WMI_VER_GET_MAJOR(opp_vers->abi_version_0); + A_UINT32 opp_minor_vers = WMI_VER_GET_MINOR(opp_vers->abi_version_0); + A_UINT32 downgraded_minor_vers; + + if ((my_vers->abi_version_ns_0 != opp_vers->abi_version_ns_0) || + (my_vers->abi_version_ns_1 != opp_vers->abi_version_ns_1) || + (my_vers->abi_version_ns_2 != opp_vers->abi_version_ns_2) || + (my_vers->abi_version_ns_3 != opp_vers->abi_version_ns_3)) { + /* The namespaces are different. Incompatible. */ + can_try_to_downgrade = false; + } else if (my_major_vers != opp_major_vers) { + /* Major version is different. Incompatible and cannot downgrade. */ + can_try_to_downgrade = false; + } else { + /* Same major version. */ + + if (my_minor_vers < opp_minor_vers) { + /* Opposite party is newer. Incompatible and cannot downgrade. */ + can_try_to_downgrade = false; + } else if (my_minor_vers > opp_minor_vers) { + /* Opposite party is older. Check whitelist if we can downgrade */ + can_try_to_downgrade = true; + } else { + /* Same version */ + wmi_tlv_OS_MEMCPY(out_vers, my_vers, + sizeof(wmi_abi_version)); + return 1; + } + } + + if (!can_try_to_downgrade) { + wmi_tlv_print_error("%s: Warning: incompatible WMI version.\n", + __func__); + wmi_tlv_OS_MEMCPY(out_vers, my_vers, sizeof(wmi_abi_version)); + return 0; + } + /* Try to see we can downgrade the supported version */ + downgraded_minor_vers = my_minor_vers; + while (downgraded_minor_vers > opp_minor_vers) { + A_UINT8 downgraded = false; + int i; + + for (i = 0; i < num_whitelist; i++) { + if (version_whitelist_table[i].major != my_major_vers) { + continue; /* skip */ + } + if ((version_whitelist_table[i].namespace_0 != + my_vers->abi_version_ns_0) + || (version_whitelist_table[i].namespace_1 != + my_vers->abi_version_ns_1) + || (version_whitelist_table[i].namespace_2 != + my_vers->abi_version_ns_2) + || (version_whitelist_table[i].namespace_3 != + my_vers->abi_version_ns_3)) { + continue; /* skip */ + } + if (version_whitelist_table[i].minor == + downgraded_minor_vers) { + /* Found the next version that I can downgrade */ + wmi_tlv_print_error + ("%s: Note: found a whitelist entry to downgrade. wh. list ver: %d,%d,0x%x 0x%x 0x%x 0x%x\n", + __func__, version_whitelist_table[i].major, + version_whitelist_table[i].minor, + version_whitelist_table[i].namespace_0, + version_whitelist_table[i].namespace_1, + version_whitelist_table[i].namespace_2, + version_whitelist_table[i].namespace_3); + downgraded_minor_vers--; + downgraded = true; + break; + } + } + if (!downgraded) { + break; /* Done since we did not find any whitelist to downgrade version */ + } + } + wmi_tlv_OS_MEMCPY(out_vers, my_vers, sizeof(wmi_abi_version)); + out_vers->abi_version_0 = + WMI_VER_GET_VERSION_0(my_major_vers, downgraded_minor_vers); + if (downgraded_minor_vers != opp_minor_vers) { + wmi_tlv_print_error + ("%s: Warning: incompatible WMI version and cannot downgrade.\n", + __func__); + return 0; /* Incompatible */ + } else { + return 1; /* Compatible */ + } +} + +/** + * wmi_cmp_and_set_abi_version() - tlv helper function + * @version_whitelist_table: version table + * @my_vers: host version + * @opp_vers: target version + * @out_vers: downgraded version + * + * This routine will compare and set the WMI ABI version. + * First, compare my version with the opposite side's version. + * If incompatible, then check the whitelist to see if our side can downgrade. + * Finally, fill in the final ABI version into the output, out_vers. + * Return 0 if the output version is compatible + * Else return 1 if the output version is incompatible + * + * Return: 0 if the output version is compatible else < 0. + */ +int +wmi_cmp_and_set_abi_version(int num_whitelist, + wmi_whitelist_version_info * + version_whitelist_table, + struct _wmi_abi_version *my_vers, + struct _wmi_abi_version *opp_vers, + struct _wmi_abi_version *out_vers) +{ + wmi_tlv_print_verbose + ("%s: Our WMI Version: Mj=%d, Mn=%d, bd=%d, ns0=0x%x ns1:0x%x ns2:0x%x ns3:0x%x\n", + __func__, WMI_VER_GET_MAJOR(my_vers->abi_version_0), + WMI_VER_GET_MINOR(my_vers->abi_version_0), my_vers->abi_version_1, + my_vers->abi_version_ns_0, my_vers->abi_version_ns_1, + my_vers->abi_version_ns_2, my_vers->abi_version_ns_3); + + wmi_tlv_print_verbose + ("%s: Opposite side WMI Version: Mj=%d, Mn=%d, bd=%d, ns0=0x%x ns1:0x%x ns2:0x%x ns3:0x%x\n", + __func__, WMI_VER_GET_MAJOR(opp_vers->abi_version_0), + WMI_VER_GET_MINOR(opp_vers->abi_version_0), + opp_vers->abi_version_1, opp_vers->abi_version_ns_0, + opp_vers->abi_version_ns_1, opp_vers->abi_version_ns_2, + opp_vers->abi_version_ns_3); + + /* By default, the output version is our version. */ + wmi_tlv_OS_MEMCPY(out_vers, my_vers, sizeof(wmi_abi_version)); + if (!wmi_versions_are_compatible(my_vers, opp_vers)) { + /* Our host version and the given firmware version are incompatible. */ + if (wmi_versions_can_downgrade + (num_whitelist, version_whitelist_table, my_vers, opp_vers, + out_vers)) { + /* We can downgrade our host versions to match firmware. */ + wmi_tlv_print_error + ("%s: Host downgraded WMI Versions to match fw. Ret version: Mj=%d, Mn=%d, bd=%d, ns0=0x%x ns1:0x%x ns2:0x%x ns3:0x%x\n", + __func__, + WMI_VER_GET_MAJOR(out_vers->abi_version_0), + WMI_VER_GET_MINOR(out_vers->abi_version_0), + out_vers->abi_version_1, + out_vers->abi_version_ns_0, + out_vers->abi_version_ns_1, + out_vers->abi_version_ns_2, + out_vers->abi_version_ns_3); + return 0; /* Compatible */ + } else { + /* Warn: We cannot downgrade our host versions to match firmware. */ + wmi_tlv_print_error + ("%s: WARN: Host WMI Versions mismatch with fw. Ret version: Mj=%d, Mn=%d, bd=%d, ns0=0x%x ns1:0x%x ns2:0x%x ns3:0x%x\n", + __func__, + WMI_VER_GET_MAJOR(out_vers->abi_version_0), + WMI_VER_GET_MINOR(out_vers->abi_version_0), + out_vers->abi_version_1, + out_vers->abi_version_ns_0, + out_vers->abi_version_ns_1, + out_vers->abi_version_ns_2, + out_vers->abi_version_ns_3); + + return 1; /* Incompatible */ + } + } else { + /* We are compatible. Our host version is the output version */ + wmi_tlv_print_verbose + ("%s: Host and FW Compatible WMI Versions. Ret version: Mj=%d, Mn=%d, bd=%d, ns0=0x%x ns1:0x%x ns2:0x%x ns3:0x%x\n", + __func__, WMI_VER_GET_MAJOR(out_vers->abi_version_0), + WMI_VER_GET_MINOR(out_vers->abi_version_0), + out_vers->abi_version_1, out_vers->abi_version_ns_0, + out_vers->abi_version_ns_1, out_vers->abi_version_ns_2, + out_vers->abi_version_ns_3); + return 0; /* Compatible */ + } +} diff --git a/drivers/staging/qca-wifi-host-cmn/wmi/src/wmi_tlv_platform.c b/drivers/staging/qca-wifi-host-cmn/wmi/src/wmi_tlv_platform.c new file mode 100644 index 0000000000000000000000000000000000000000..d7858aed6d4f8fecf53b470cac307d5c713374bc --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/wmi/src/wmi_tlv_platform.c @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2013-2014, 2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * LMAC offload interface functions for WMI TLV Interface + */ + +#include "ol_if_athvar.h" +#include /* qdf_mem_malloc,free, etc. */ +#include +#include "htc_api.h" +#include "wmi.h" + + +/* Following macro definitions use OS or platform specific functions */ +#define dummy_print(fmt, ...) {} +#define wmi_tlv_print_verbose dummy_print +#define wmi_tlv_print_error qdf_print +#define wmi_tlv_OS_MEMCPY OS_MEMCPY +#define wmi_tlv_OS_MEMZERO OS_MEMZERO +#define wmi_tlv_OS_MEMMOVE OS_MEMMOVE + +#ifndef NO_DYNAMIC_MEM_ALLOC +#define wmi_tlv_os_mem_alloc(scn, ptr, numBytes) \ + { \ + (ptr) = qdf_mem_malloc(numBytes); \ + } +#define wmi_tlv_os_mem_free qdf_mem_free +#endif diff --git a/drivers/staging/qca-wifi-host-cmn/wmi/src/wmi_unified.c b/drivers/staging/qca-wifi-host-cmn/wmi/src/wmi_unified.c new file mode 100644 index 0000000000000000000000000000000000000000..391276ca3c3415e8adaec82e9fb4f89e8bb6d8c7 --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/wmi/src/wmi_unified.c @@ -0,0 +1,1918 @@ +/* + * Copyright (c) 2015-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * Host WMI unified implementation + */ +#include "athdefs.h" +#include "osapi_linux.h" +#include "a_types.h" +#include "a_debug.h" +#include "ol_if_athvar.h" +#include "ol_defines.h" +#include "htc_api.h" +#include "htc_api.h" +#include "dbglog_host.h" +#include "wmi_unified_priv.h" +#include "wmi_unified_param.h" + +#include + +/* This check for CONFIG_WIN temporary added due to redeclaration compilation +error in MCL. Error is caused due to inclusion of wmi.h in wmi_unified_api.h +which gets included here through ol_if_athvar.h. Eventually it is expected that +wmi.h will be removed from wmi_unified_api.h after cleanup, which will need +WMI_CMD_HDR to be defined here. */ +#ifdef CONFIG_WIN +/* Copied from wmi.h */ +#undef MS +#define MS(_v, _f) (((_v) & _f##_MASK) >> _f##_LSB) +#undef SM +#define SM(_v, _f) (((_v) << _f##_LSB) & _f##_MASK) +#undef WO +#define WO(_f) ((_f##_OFFSET) >> 2) + +#undef GET_FIELD +#define GET_FIELD(_addr, _f) MS(*((A_UINT32 *)(_addr) + WO(_f)), _f) +#undef SET_FIELD +#define SET_FIELD(_addr, _f, _val) \ + (*((A_UINT32 *)(_addr) + WO(_f)) = \ + (*((A_UINT32 *)(_addr) + WO(_f)) & ~_f##_MASK) | SM(_val, _f)) + +#define WMI_GET_FIELD(_msg_buf, _msg_type, _f) \ + GET_FIELD(_msg_buf, _msg_type ## _ ## _f) + +#define WMI_SET_FIELD(_msg_buf, _msg_type, _f, _val) \ + SET_FIELD(_msg_buf, _msg_type ## _ ## _f, _val) + +#define WMI_EP_APASS 0x0 +#define WMI_EP_LPASS 0x1 +#define WMI_EP_SENSOR 0x2 + +/* + * * Control Path + * */ +typedef PREPACK struct { + A_UINT32 commandId:24, + reserved:2, /* used for WMI endpoint ID */ + plt_priv:6; /* platform private */ +} POSTPACK WMI_CMD_HDR; /* used for commands and events */ + +#define WMI_CMD_HDR_COMMANDID_LSB 0 +#define WMI_CMD_HDR_COMMANDID_MASK 0x00ffffff +#define WMI_CMD_HDR_COMMANDID_OFFSET 0x00000000 +#define WMI_CMD_HDR_WMI_ENDPOINTID_MASK 0x03000000 +#define WMI_CMD_HDR_WMI_ENDPOINTID_OFFSET 24 +#define WMI_CMD_HDR_PLT_PRIV_LSB 24 +#define WMI_CMD_HDR_PLT_PRIV_MASK 0xff000000 +#define WMI_CMD_HDR_PLT_PRIV_OFFSET 0x00000000 +/* end of copy wmi.h */ +#endif /* CONFIG_WIN */ + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 3, 0)) +/* TODO Cleanup this backported function */ +static int qcacld_bp_seq_printf(struct seq_file *m, const char *f, ...) +{ + va_list args; + + va_start(args, f); + seq_printf(m, f, args); + va_end(args); + + return m->count; +} + +#define seq_printf(m, fmt, ...) qcacld_bp_seq_printf((m), fmt, ##__VA_ARGS__) +#endif + +#define WMI_MIN_HEAD_ROOM 64 + +#ifdef WMI_INTERFACE_EVENT_LOGGING +#ifndef MAX_WMI_INSTANCES +#ifdef CONFIG_MCL +#define MAX_WMI_INSTANCES 1 +#else +#define MAX_WMI_INSTANCES 3 +#endif +#endif + +/* WMI commands */ +uint32_t g_wmi_command_buf_idx = 0; +struct wmi_command_debug wmi_command_log_buffer[WMI_EVENT_DEBUG_MAX_ENTRY]; + +/* WMI commands TX completed */ +uint32_t g_wmi_command_tx_cmp_buf_idx = 0; +struct wmi_command_debug + wmi_command_tx_cmp_log_buffer[WMI_EVENT_DEBUG_MAX_ENTRY]; + +/* WMI events when processed */ +uint32_t g_wmi_event_buf_idx = 0; +struct wmi_event_debug wmi_event_log_buffer[WMI_EVENT_DEBUG_MAX_ENTRY]; + +/* WMI events when queued */ +uint32_t g_wmi_rx_event_buf_idx = 0; +struct wmi_event_debug wmi_rx_event_log_buffer[WMI_EVENT_DEBUG_MAX_ENTRY]; + +#define WMI_COMMAND_RECORD(h, a, b) { \ + if (wmi_log_max_entry <= \ + *(h->log_info.wmi_command_log_buf_info.p_buf_tail_idx)) \ + *(h->log_info.wmi_command_log_buf_info.p_buf_tail_idx) = 0;\ + ((struct wmi_command_debug *)h->log_info.wmi_command_log_buf_info.buf)\ + [*(h->log_info.wmi_command_log_buf_info.p_buf_tail_idx)]\ + .command = a; \ + qdf_mem_copy(((struct wmi_command_debug *)h->log_info. \ + wmi_command_log_buf_info.buf) \ + [*(h->log_info.wmi_command_log_buf_info.p_buf_tail_idx)].data,\ + b, wmi_record_max_length); \ + ((struct wmi_command_debug *)h->log_info.wmi_command_log_buf_info.buf)\ + [*(h->log_info.wmi_command_log_buf_info.p_buf_tail_idx)].\ + time = qdf_get_log_timestamp(); \ + (*(h->log_info.wmi_command_log_buf_info.p_buf_tail_idx))++; \ + h->log_info.wmi_command_log_buf_info.length++; \ +} + +#define WMI_COMMAND_TX_CMP_RECORD(h, a, b) { \ + if (wmi_log_max_entry <= \ + *(h->log_info.wmi_command_tx_cmp_log_buf_info.p_buf_tail_idx))\ + *(h->log_info.wmi_command_tx_cmp_log_buf_info.p_buf_tail_idx) = 0;\ + ((struct wmi_command_debug *)h->log_info. \ + wmi_command_tx_cmp_log_buf_info.buf) \ + [*(h->log_info.wmi_command_tx_cmp_log_buf_info. \ + p_buf_tail_idx)]. \ + command = a; \ + qdf_mem_copy(((struct wmi_command_debug *)h->log_info. \ + wmi_command_tx_cmp_log_buf_info.buf) \ + [*(h->log_info.wmi_command_tx_cmp_log_buf_info. \ + p_buf_tail_idx)]. \ + data, b, wmi_record_max_length); \ + ((struct wmi_command_debug *)h->log_info. \ + wmi_command_tx_cmp_log_buf_info.buf) \ + [*(h->log_info.wmi_command_tx_cmp_log_buf_info. \ + p_buf_tail_idx)]. \ + time = qdf_get_log_timestamp(); \ + (*(h->log_info.wmi_command_tx_cmp_log_buf_info.p_buf_tail_idx))++;\ + h->log_info.wmi_command_tx_cmp_log_buf_info.length++; \ +} + +#define WMI_EVENT_RECORD(h, a, b) { \ + if (wmi_log_max_entry <= \ + *(h->log_info.wmi_event_log_buf_info.p_buf_tail_idx)) \ + *(h->log_info.wmi_event_log_buf_info.p_buf_tail_idx) = 0;\ + ((struct wmi_event_debug *)h->log_info.wmi_event_log_buf_info.buf)\ + [*(h->log_info.wmi_event_log_buf_info.p_buf_tail_idx)]. \ + event = a; \ + qdf_mem_copy(((struct wmi_event_debug *)h->log_info. \ + wmi_event_log_buf_info.buf) \ + [*(h->log_info.wmi_event_log_buf_info.p_buf_tail_idx)].data, b,\ + wmi_record_max_length); \ + ((struct wmi_event_debug *)h->log_info.wmi_event_log_buf_info.buf)\ + [*(h->log_info.wmi_event_log_buf_info.p_buf_tail_idx)].time =\ + qdf_get_log_timestamp(); \ + (*(h->log_info.wmi_event_log_buf_info.p_buf_tail_idx))++; \ + h->log_info.wmi_event_log_buf_info.length++; \ +} + +#define WMI_RX_EVENT_RECORD(h, a, b) { \ + if (wmi_log_max_entry <= \ + *(h->log_info.wmi_rx_event_log_buf_info.p_buf_tail_idx))\ + *(h->log_info.wmi_rx_event_log_buf_info.p_buf_tail_idx) = 0;\ + ((struct wmi_event_debug *)h->log_info.wmi_rx_event_log_buf_info.buf)\ + [*(h->log_info.wmi_rx_event_log_buf_info.p_buf_tail_idx)].\ + event = a; \ + qdf_mem_copy(((struct wmi_event_debug *)h->log_info. \ + wmi_rx_event_log_buf_info.buf) \ + [*(h->log_info.wmi_rx_event_log_buf_info.p_buf_tail_idx)].\ + data, b, wmi_record_max_length); \ + ((struct wmi_event_debug *)h->log_info.wmi_rx_event_log_buf_info.buf)\ + [*(h->log_info.wmi_rx_event_log_buf_info.p_buf_tail_idx)].\ + time = qdf_get_log_timestamp(); \ + (*(h->log_info.wmi_rx_event_log_buf_info.p_buf_tail_idx))++; \ + h->log_info.wmi_rx_event_log_buf_info.length++; \ +} + +uint32_t g_wmi_mgmt_command_buf_idx = 0; +struct +wmi_command_debug wmi_mgmt_command_log_buffer[WMI_MGMT_EVENT_DEBUG_MAX_ENTRY]; + +/* wmi_mgmt commands TX completed */ +uint32_t g_wmi_mgmt_command_tx_cmp_buf_idx = 0; +struct wmi_command_debug +wmi_mgmt_command_tx_cmp_log_buffer[WMI_MGMT_EVENT_DEBUG_MAX_ENTRY]; + +/* wmi_mgmt events when processed */ +uint32_t g_wmi_mgmt_event_buf_idx = 0; +struct wmi_event_debug +wmi_mgmt_event_log_buffer[WMI_MGMT_EVENT_DEBUG_MAX_ENTRY]; + +#define WMI_MGMT_COMMAND_RECORD(a, b, c, d, e) { \ + if (WMI_MGMT_EVENT_DEBUG_MAX_ENTRY <= \ + g_wmi_mgmt_command_buf_idx) \ + g_wmi_mgmt_command_buf_idx = 0; \ + wmi_mgmt_command_log_buffer[g_wmi_mgmt_command_buf_idx].command = a; \ + wmi_mgmt_command_log_buffer[g_wmi_mgmt_command_buf_idx].data[0] = b; \ + wmi_mgmt_command_log_buffer[g_wmi_mgmt_command_buf_idx].data[1] = c; \ + wmi_mgmt_command_log_buffer[g_wmi_mgmt_command_buf_idx].data[2] = d; \ + wmi_mgmt_command_log_buffer[g_wmi_mgmt_command_buf_idx].data[3] = e; \ + wmi_mgmt_command_log_buffer[g_wmi_mgmt_command_buf_idx].time = \ + qdf_get_log_timestamp(); \ + g_wmi_mgmt_command_buf_idx++; \ +} + +#define WMI_MGMT_COMMAND_TX_CMP_RECORD(h, a, b) { \ + if (wmi_mgmt_log_max_entry <= \ + *(h->log_info.wmi_mgmt_command_tx_cmp_log_buf_info. \ + p_buf_tail_idx)) \ + *(h->log_info.wmi_mgmt_command_tx_cmp_log_buf_info. \ + p_buf_tail_idx) = 0; \ + ((struct wmi_command_debug *)h->log_info. \ + wmi_mgmt_command_tx_cmp_log_buf_info.buf) \ + [*(h->log_info.wmi_mgmt_command_tx_cmp_log_buf_info. \ + p_buf_tail_idx)].command = a; \ + qdf_mem_copy(((struct wmi_command_debug *)h->log_info. \ + wmi_mgmt_command_tx_cmp_log_buf_info.buf)\ + [*(h->log_info.wmi_mgmt_command_tx_cmp_log_buf_info. \ + p_buf_tail_idx)].data, b, \ + wmi_record_max_length); \ + ((struct wmi_command_debug *)h->log_info. \ + wmi_mgmt_command_tx_cmp_log_buf_info.buf) \ + [*(h->log_info.wmi_mgmt_command_tx_cmp_log_buf_info. \ + p_buf_tail_idx)].time = \ + qdf_get_log_timestamp(); \ + (*(h->log_info.wmi_mgmt_command_tx_cmp_log_buf_info. \ + p_buf_tail_idx))++; \ + h->log_info.wmi_mgmt_command_tx_cmp_log_buf_info.length++; \ +} + +#define WMI_MGMT_EVENT_RECORD(h, a, b) { \ + if (wmi_mgmt_log_max_entry <= \ + *(h->log_info.wmi_mgmt_event_log_buf_info.p_buf_tail_idx))\ + *(h->log_info.wmi_mgmt_event_log_buf_info.p_buf_tail_idx) = 0;\ + ((struct wmi_event_debug *)h->log_info.wmi_mgmt_event_log_buf_info.buf)\ + [*(h->log_info.wmi_mgmt_event_log_buf_info.p_buf_tail_idx)]\ + .event = a; \ + qdf_mem_copy(((struct wmi_event_debug *)h->log_info. \ + wmi_mgmt_event_log_buf_info.buf) \ + [*(h->log_info.wmi_mgmt_event_log_buf_info.p_buf_tail_idx)].\ + data, b, wmi_record_max_length); \ + ((struct wmi_event_debug *)h->log_info.wmi_mgmt_event_log_buf_info.buf)\ + [*(h->log_info.wmi_mgmt_event_log_buf_info.p_buf_tail_idx)].\ + time = qdf_get_log_timestamp(); \ + (*(h->log_info.wmi_mgmt_event_log_buf_info.p_buf_tail_idx))++; \ + h->log_info.wmi_mgmt_event_log_buf_info.length++; \ +} + +/* These are defined to made it as module param, which can be configured */ +uint32_t wmi_log_max_entry = WMI_EVENT_DEBUG_MAX_ENTRY; +uint32_t wmi_mgmt_log_max_entry = WMI_MGMT_EVENT_DEBUG_MAX_ENTRY; +uint32_t wmi_record_max_length = WMI_EVENT_DEBUG_ENTRY_MAX_LENGTH; +uint32_t wmi_display_size = 100; + +/** + * wmi_log_init() - Initialize WMI event logging + * @wmi_handle: WMI handle. + * + * Return: Initialization status + */ +#ifdef CONFIG_MCL +static QDF_STATUS wmi_log_init(struct wmi_unified *wmi_handle) +{ + struct wmi_log_buf_t *cmd_log_buf = + &wmi_handle->log_info.wmi_command_log_buf_info; + struct wmi_log_buf_t *cmd_tx_cmpl_log_buf = + &wmi_handle->log_info.wmi_command_tx_cmp_log_buf_info; + + struct wmi_log_buf_t *event_log_buf = + &wmi_handle->log_info.wmi_event_log_buf_info; + struct wmi_log_buf_t *rx_event_log_buf = + &wmi_handle->log_info.wmi_rx_event_log_buf_info; + + struct wmi_log_buf_t *mgmt_cmd_log_buf = + &wmi_handle->log_info.wmi_mgmt_command_log_buf_info; + struct wmi_log_buf_t *mgmt_cmd_tx_cmp_log_buf = + &wmi_handle->log_info.wmi_mgmt_command_tx_cmp_log_buf_info; + struct wmi_log_buf_t *mgmt_event_log_buf = + &wmi_handle->log_info.wmi_mgmt_event_log_buf_info; + + /* WMI commands */ + cmd_log_buf->length = 0; + cmd_log_buf->buf_tail_idx = 0; + cmd_log_buf->buf = wmi_command_log_buffer; + cmd_log_buf->p_buf_tail_idx = &g_wmi_command_buf_idx; + + /* WMI commands TX completed */ + cmd_tx_cmpl_log_buf->length = 0; + cmd_tx_cmpl_log_buf->buf_tail_idx = 0; + cmd_tx_cmpl_log_buf->buf = wmi_command_tx_cmp_log_buffer; + cmd_tx_cmpl_log_buf->p_buf_tail_idx = &g_wmi_command_tx_cmp_buf_idx; + + /* WMI events when processed */ + event_log_buf->length = 0; + event_log_buf->buf_tail_idx = 0; + event_log_buf->buf = wmi_event_log_buffer; + event_log_buf->p_buf_tail_idx = &g_wmi_event_buf_idx; + + /* WMI events when queued */ + rx_event_log_buf->length = 0; + rx_event_log_buf->buf_tail_idx = 0; + rx_event_log_buf->buf = wmi_rx_event_log_buffer; + rx_event_log_buf->p_buf_tail_idx = &g_wmi_rx_event_buf_idx; + + /* WMI Management commands */ + mgmt_cmd_log_buf->length = 0; + mgmt_cmd_log_buf->buf_tail_idx = 0; + mgmt_cmd_log_buf->buf = wmi_mgmt_command_log_buffer; + mgmt_cmd_log_buf->p_buf_tail_idx = &g_wmi_mgmt_command_buf_idx; + + /* WMI Management commands Tx completed*/ + mgmt_cmd_tx_cmp_log_buf->length = 0; + mgmt_cmd_tx_cmp_log_buf->buf_tail_idx = 0; + mgmt_cmd_tx_cmp_log_buf->buf = wmi_mgmt_command_tx_cmp_log_buffer; + mgmt_cmd_tx_cmp_log_buf->p_buf_tail_idx = + &g_wmi_mgmt_command_tx_cmp_buf_idx; + + /* WMI Management events when processed*/ + mgmt_event_log_buf->length = 0; + mgmt_event_log_buf->buf_tail_idx = 0; + mgmt_event_log_buf->buf = wmi_mgmt_event_log_buffer; + mgmt_event_log_buf->p_buf_tail_idx = &g_wmi_mgmt_event_buf_idx; + + qdf_spinlock_create(&wmi_handle->log_info.wmi_record_lock); + wmi_handle->log_info.wmi_logging_enable = 1; + + return QDF_STATUS_SUCCESS; +} +#else +static QDF_STATUS wmi_log_init(struct wmi_unified *wmi_handle) +{ + struct wmi_log_buf_t *cmd_log_buf = + &wmi_handle->log_info.wmi_command_log_buf_info; + struct wmi_log_buf_t *cmd_tx_cmpl_log_buf = + &wmi_handle->log_info.wmi_command_tx_cmp_log_buf_info; + + struct wmi_log_buf_t *event_log_buf = + &wmi_handle->log_info.wmi_event_log_buf_info; + struct wmi_log_buf_t *rx_event_log_buf = + &wmi_handle->log_info.wmi_rx_event_log_buf_info; + + struct wmi_log_buf_t *mgmt_cmd_log_buf = + &wmi_handle->log_info.wmi_mgmt_command_log_buf_info; + struct wmi_log_buf_t *mgmt_cmd_tx_cmp_log_buf = + &wmi_handle->log_info.wmi_mgmt_command_tx_cmp_log_buf_info; + struct wmi_log_buf_t *mgmt_event_log_buf = + &wmi_handle->log_info.wmi_mgmt_event_log_buf_info; + + wmi_handle->log_info.wmi_logging_enable = 0; + + /* WMI commands */ + cmd_log_buf->length = 0; + cmd_log_buf->buf_tail_idx = 0; + cmd_log_buf->buf = (struct wmi_command_debug *) qdf_mem_malloc( + wmi_log_max_entry * sizeof(struct wmi_command_debug)); + + if (!cmd_log_buf->buf) { + qdf_print("no memory for WMI command log buffer..\n"); + return QDF_STATUS_E_NOMEM; + } + cmd_log_buf->p_buf_tail_idx = &cmd_log_buf->buf_tail_idx; + + /* WMI commands TX completed */ + cmd_tx_cmpl_log_buf->length = 0; + cmd_tx_cmpl_log_buf->buf_tail_idx = 0; + cmd_tx_cmpl_log_buf->buf = (struct wmi_command_debug *) qdf_mem_malloc( + wmi_log_max_entry * sizeof(struct wmi_command_debug)); + + if (!cmd_tx_cmpl_log_buf->buf) { + qdf_print("no memory for WMI Command Tx Complete log buffer..\n"); + return QDF_STATUS_E_NOMEM; + } + cmd_tx_cmpl_log_buf->p_buf_tail_idx = + &cmd_tx_cmpl_log_buf->buf_tail_idx; + + /* WMI events when processed */ + event_log_buf->length = 0; + event_log_buf->buf_tail_idx = 0; + event_log_buf->buf = (struct wmi_event_debug *) qdf_mem_malloc( + wmi_log_max_entry * sizeof(struct wmi_event_debug)); + + if (!event_log_buf->buf) { + qdf_print("no memory for WMI Event log buffer..\n"); + return QDF_STATUS_E_NOMEM; + } + event_log_buf->p_buf_tail_idx = &event_log_buf->buf_tail_idx; + + /* WMI events when queued */ + rx_event_log_buf->length = 0; + rx_event_log_buf->buf_tail_idx = 0; + rx_event_log_buf->buf = (struct wmi_event_debug *) qdf_mem_malloc( + wmi_log_max_entry * sizeof(struct wmi_event_debug)); + + if (!rx_event_log_buf->buf) { + qdf_print("no memory for WMI Event Rx log buffer..\n"); + return QDF_STATUS_E_NOMEM; + } + rx_event_log_buf->p_buf_tail_idx = &rx_event_log_buf->buf_tail_idx; + + /* WMI Management commands */ + mgmt_cmd_log_buf->length = 0; + mgmt_cmd_log_buf->buf_tail_idx = 0; + mgmt_cmd_log_buf->buf = (struct wmi_command_debug *) qdf_mem_malloc( + wmi_mgmt_log_max_entry * + sizeof(struct wmi_command_debug)); + + if (!mgmt_cmd_log_buf->buf) { + qdf_print("no memory for WMI Management Command log buffer..\n"); + return QDF_STATUS_E_NOMEM; + } + mgmt_cmd_log_buf->p_buf_tail_idx = &mgmt_cmd_log_buf->buf_tail_idx; + + /* WMI Management commands Tx completed*/ + mgmt_cmd_tx_cmp_log_buf->length = 0; + mgmt_cmd_tx_cmp_log_buf->buf_tail_idx = 0; + mgmt_cmd_tx_cmp_log_buf->buf = (struct wmi_command_debug *) + qdf_mem_malloc( + wmi_mgmt_log_max_entry * + sizeof(struct wmi_command_debug)); + + if (!mgmt_cmd_tx_cmp_log_buf->buf) { + qdf_print("no memory for WMI Management Command Tx complete log buffer..\n"); + return QDF_STATUS_E_NOMEM; + } + mgmt_cmd_tx_cmp_log_buf->p_buf_tail_idx = + &mgmt_cmd_tx_cmp_log_buf->buf_tail_idx; + + /* WMI Management events when processed*/ + mgmt_event_log_buf->length = 0; + mgmt_event_log_buf->buf_tail_idx = 0; + + mgmt_event_log_buf->buf = (struct wmi_event_debug *) qdf_mem_malloc( + wmi_mgmt_log_max_entry * + sizeof(struct wmi_event_debug)); + + if (!mgmt_event_log_buf->buf) { + qdf_print("no memory for WMI Management Event log buffer..\n"); + return QDF_STATUS_E_NOMEM; + } + mgmt_event_log_buf->p_buf_tail_idx = &mgmt_event_log_buf->buf_tail_idx; + + qdf_spinlock_create(&wmi_handle->log_info.wmi_record_lock); + wmi_handle->log_info.wmi_logging_enable = 1; + + return QDF_STATUS_SUCCESS; +} +#endif + +/** + * wmi_log_buffer_free() - Free all dynamic allocated buffer memory for + * event logging + * @wmi_handle: WMI handle. + * + * Return: None + */ +#ifndef CONFIG_MCL +static inline void wmi_log_buffer_free(struct wmi_unified *wmi_handle) +{ + if (wmi_handle->log_info.wmi_command_log_buf_info.buf) + qdf_mem_free(wmi_handle->log_info.wmi_command_log_buf_info.buf); + if (wmi_handle->log_info.wmi_command_tx_cmp_log_buf_info.buf) + qdf_mem_free( + wmi_handle->log_info.wmi_command_tx_cmp_log_buf_info.buf); + if (wmi_handle->log_info.wmi_event_log_buf_info.buf) + qdf_mem_free(wmi_handle->log_info.wmi_event_log_buf_info.buf); + if (wmi_handle->log_info.wmi_rx_event_log_buf_info.buf) + qdf_mem_free( + wmi_handle->log_info.wmi_rx_event_log_buf_info.buf); + if (wmi_handle->log_info.wmi_mgmt_command_log_buf_info.buf) + qdf_mem_free( + wmi_handle->log_info.wmi_mgmt_command_log_buf_info.buf); + if (wmi_handle->log_info.wmi_mgmt_command_tx_cmp_log_buf_info.buf) + qdf_mem_free( + wmi_handle->log_info.wmi_mgmt_command_tx_cmp_log_buf_info.buf); + if (wmi_handle->log_info.wmi_mgmt_event_log_buf_info.buf) + qdf_mem_free( + wmi_handle->log_info.wmi_mgmt_event_log_buf_info.buf); + wmi_handle->log_info.wmi_logging_enable = 0; + qdf_spinlock_destroy(&wmi_handle->log_info.wmi_record_lock); +} +#else +static inline void wmi_log_buffer_free(struct wmi_unified *wmi_handle) +{ + wmi_handle->log_info.wmi_logging_enable = 0; + qdf_spinlock_destroy(&wmi_handle->log_info.wmi_record_lock); +} +#endif + +#ifdef CONFIG_MCL +const int8_t * const debugfs_dir[] = {"WMI0", "WMI1", "WMI2"}; +#else +const int8_t * const debugfs_dir[] = {"WMI0"}; +#endif + +/* debugfs routines*/ + +/** + * debug_wmi_##func_base##_show() - debugfs functions to display content of + * command and event buffers. Macro uses max buffer length to display + * buffer when it is wraparound. + * + * @m: debugfs handler to access wmi_handle + * @v: Variable arguments (not used) + * + * Return: Length of characters printed + */ +#define GENERATE_COMMAND_DEBUG_SHOW_FUNCS(func_base, wmi_ring_size) \ + static int debug_wmi_##func_base##_show(struct seq_file *m, \ + void *v) \ + { \ + wmi_unified_t wmi_handle = (wmi_unified_t) m->private; \ + struct wmi_log_buf_t *wmi_log = \ + &wmi_handle->log_info.wmi_##func_base##_buf_info;\ + int pos, nread, outlen; \ + int i; \ + \ + if (!wmi_log->length) \ + return seq_printf(m, \ + "no elements to read from ring buffer!\n"); \ + \ + if (wmi_log->length <= wmi_ring_size) \ + nread = wmi_log->length; \ + else \ + nread = wmi_ring_size; \ + \ + if (*(wmi_log->p_buf_tail_idx) == 0) \ + /* tail can be 0 after wrap-around */ \ + pos = wmi_ring_size - 1; \ + else \ + pos = *(wmi_log->p_buf_tail_idx) - 1; \ + \ + outlen = 0; \ + qdf_spin_lock(&wmi_handle->log_info.wmi_record_lock); \ + while (nread--) { \ + struct wmi_command_debug *wmi_record; \ + \ + wmi_record = (struct wmi_command_debug *) \ + &(((struct wmi_command_debug *)wmi_log->buf)[pos]);\ + outlen += seq_printf(m, "CMD ID = %x\n", \ + (wmi_record->command)); \ + outlen += seq_printf(m, "CMD = "); \ + for (i = 0; i < (wmi_record_max_length/ \ + sizeof(uint32_t)); i++) \ + outlen += seq_printf(m, "%x ", \ + wmi_record->data[i]); \ + outlen += seq_printf(m, "\n"); \ + \ + if (pos == 0) \ + pos = wmi_ring_size - 1; \ + else \ + pos--; \ + } \ + outlen += seq_printf(m, "Length = %d\n", wmi_log->length);\ + qdf_spin_unlock(&wmi_handle->log_info.wmi_record_lock); \ + \ + return outlen; \ + } \ + +#define GENERATE_EVENT_DEBUG_SHOW_FUNCS(func_base, wmi_ring_size) \ + static int debug_wmi_##func_base##_show(struct seq_file *m, \ + void *v) \ + { \ + wmi_unified_t wmi_handle = (wmi_unified_t) m->private; \ + struct wmi_log_buf_t *wmi_log = \ + &wmi_handle->log_info.wmi_##func_base##_buf_info;\ + int pos, nread, outlen; \ + int i; \ + \ + if (!wmi_log->length) \ + return seq_printf(m, \ + "no elements to read from ring buffer!\n"); \ + \ + if (wmi_log->length <= wmi_ring_size) \ + nread = wmi_log->length; \ + else \ + nread = wmi_ring_size; \ + \ + if (*(wmi_log->p_buf_tail_idx) == 0) \ + /* tail can be 0 after wrap-around */ \ + pos = wmi_ring_size - 1; \ + else \ + pos = *(wmi_log->p_buf_tail_idx) - 1; \ + \ + outlen = 0; \ + qdf_spin_lock(&wmi_handle->log_info.wmi_record_lock); \ + while (nread--) { \ + struct wmi_event_debug *wmi_record; \ + \ + wmi_record = (struct wmi_event_debug *) \ + &(((struct wmi_event_debug *)wmi_log->buf)[pos]);\ + outlen += seq_printf(m, "Event ID = %x\n", \ + (wmi_record->event)); \ + outlen += seq_printf(m, "CMD = "); \ + for (i = 0; i < (wmi_record_max_length/ \ + sizeof(uint32_t)); i++) \ + outlen += seq_printf(m, "%x ", \ + wmi_record->data[i]); \ + outlen += seq_printf(m, "\n"); \ + \ + if (pos == 0) \ + pos = wmi_ring_size - 1; \ + else \ + pos--; \ + } \ + outlen += seq_printf(m, "Length = %d\n", wmi_log->length);\ + qdf_spin_unlock(&wmi_handle->log_info.wmi_record_lock); \ + \ + return outlen; \ + } + +GENERATE_COMMAND_DEBUG_SHOW_FUNCS(command_log, wmi_display_size); +GENERATE_COMMAND_DEBUG_SHOW_FUNCS(command_tx_cmp_log, wmi_display_size); +GENERATE_EVENT_DEBUG_SHOW_FUNCS(event_log, wmi_display_size); +GENERATE_EVENT_DEBUG_SHOW_FUNCS(rx_event_log, wmi_display_size); +GENERATE_COMMAND_DEBUG_SHOW_FUNCS(mgmt_command_log, wmi_display_size); +GENERATE_COMMAND_DEBUG_SHOW_FUNCS(mgmt_command_tx_cmp_log, + wmi_display_size); +GENERATE_EVENT_DEBUG_SHOW_FUNCS(mgmt_event_log, wmi_display_size); + +/** + * debug_wmi_enable_show() - debugfs functions to display enable state of + * wmi logging feature. + * + * @m: debugfs handler to access wmi_handle + * @v: Variable arguments (not used) + * + * Return: always 1 + */ +static int debug_wmi_enable_show(struct seq_file *m, void *v) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) m->private; + + return seq_printf(m, "%d\n", wmi_handle->log_info.wmi_logging_enable); + +} + +/** + * debug_wmi_log_size_show() - debugfs functions to display configured size of + * wmi logging command/event buffer and management command/event buffer. + * + * @m: debugfs handler to access wmi_handle + * @v: Variable arguments (not used) + * + * Return: Length of characters printed + */ +static int debug_wmi_log_size_show(struct seq_file *m, void *v) +{ + + seq_printf(m, "WMI command/event log max size:%d\n", wmi_log_max_entry); + return seq_printf(m, "WMI management command/events log max size:%d\n", + wmi_mgmt_log_max_entry); +} + +/** + * debug_wmi_##func_base##_write() - debugfs functions to clear + * wmi logging command/event buffer and management command/event buffer. + * + * @file: file handler to access wmi_handle + * @buf: received data buffer + * @count: length of received buffer + * @ppos: Not used + * + * Return: count + */ +#define GENERATE_DEBUG_WRITE_FUNCS(func_base, wmi_ring_size, wmi_record_type)\ + static ssize_t debug_wmi_##func_base##_write(struct file *file, \ + const char __user *buf, \ + size_t count, loff_t *ppos) \ + { \ + int k, ret; \ + wmi_unified_t wmi_handle = file->private_data; \ + struct wmi_log_buf_t *wmi_log = &wmi_handle->log_info. \ + wmi_##func_base##_buf_info; \ + \ + ret = sscanf(buf, "%d", &k); \ + if ((ret != 1) || (k != 0)) { \ + qdf_print("Wrong input, echo 0 to clear the wmi buffer\n");\ + return -EINVAL; \ + } \ + \ + qdf_spin_lock(&wmi_handle->log_info.wmi_record_lock); \ + qdf_mem_zero(wmi_log->buf, wmi_ring_size * \ + sizeof(struct wmi_record_type)); \ + wmi_log->length = 0; \ + *(wmi_log->p_buf_tail_idx) = 0; \ + qdf_spin_unlock(&wmi_handle->log_info.wmi_record_lock); \ + \ + return count; \ + } + +GENERATE_DEBUG_WRITE_FUNCS(command_log, wmi_log_max_entry, + wmi_command_debug); +GENERATE_DEBUG_WRITE_FUNCS(command_tx_cmp_log, wmi_log_max_entry, + wmi_command_debug); +GENERATE_DEBUG_WRITE_FUNCS(event_log, wmi_log_max_entry, + wmi_event_debug); +GENERATE_DEBUG_WRITE_FUNCS(rx_event_log, wmi_log_max_entry, + wmi_event_debug); +GENERATE_DEBUG_WRITE_FUNCS(mgmt_command_log, wmi_mgmt_log_max_entry, + wmi_command_debug); +GENERATE_DEBUG_WRITE_FUNCS(mgmt_command_tx_cmp_log, + wmi_mgmt_log_max_entry, wmi_command_debug); +GENERATE_DEBUG_WRITE_FUNCS(mgmt_event_log, wmi_mgmt_log_max_entry, + wmi_event_debug); + +/** + * debug_wmi_enable_write() - debugfs functions to enable/disable + * wmi logging feature. + * + * @file: file handler to access wmi_handle + * @buf: received data buffer + * @count: length of received buffer + * @ppos: Not used + * + * Return: count + */ +static ssize_t debug_wmi_enable_write(struct file *file, const char __user *buf, + size_t count, loff_t *ppos) +{ + wmi_unified_t wmi_handle = file->private_data; + int k, ret; + + ret = sscanf(buf, "%d", &k); + if ((ret != 1) || ((k != 0) && (k != 1))) + return -EINVAL; + + wmi_handle->log_info.wmi_logging_enable = k; + return count; +} + +/** + * debug_wmi_log_size_write() - reserved. + * + * @file: file handler to access wmi_handle + * @buf: received data buffer + * @count: length of received buffer + * @ppos: Not used + * + * Return: count + */ +static ssize_t debug_wmi_log_size_write(struct file *file, + const char __user *buf, size_t count, loff_t *ppos) +{ + return -EINVAL; +} + +/* Structure to maintain debug information */ +struct wmi_debugfs_info { + const char *name; + struct dentry *de[MAX_WMI_INSTANCES]; + const struct file_operations *ops; +}; + +#define DEBUG_FOO(func_base) { .name = #func_base, \ + .ops = &debug_##func_base##_ops } + +/** + * debug_##func_base##_open() - Open debugfs entry for respective command + * and event buffer. + * + * @inode: node for debug dir entry + * @file: file handler + * + * Return: open status + */ +#define GENERATE_DEBUG_STRUCTS(func_base) \ + static int debug_##func_base##_open(struct inode *inode, \ + struct file *file) \ + { \ + return single_open(file, debug_##func_base##_show, \ + inode->i_private); \ + } \ + \ + \ + static struct file_operations debug_##func_base##_ops = { \ + .open = debug_##func_base##_open, \ + .read = seq_read, \ + .llseek = seq_lseek, \ + .write = debug_##func_base##_write, \ + .release = single_release, \ + }; + +GENERATE_DEBUG_STRUCTS(wmi_command_log); +GENERATE_DEBUG_STRUCTS(wmi_command_tx_cmp_log); +GENERATE_DEBUG_STRUCTS(wmi_event_log); +GENERATE_DEBUG_STRUCTS(wmi_rx_event_log); +GENERATE_DEBUG_STRUCTS(wmi_mgmt_command_log); +GENERATE_DEBUG_STRUCTS(wmi_mgmt_command_tx_cmp_log); +GENERATE_DEBUG_STRUCTS(wmi_mgmt_event_log); +GENERATE_DEBUG_STRUCTS(wmi_enable); +GENERATE_DEBUG_STRUCTS(wmi_log_size); + +struct wmi_debugfs_info wmi_debugfs_infos[] = { + DEBUG_FOO(wmi_command_log), + DEBUG_FOO(wmi_command_tx_cmp_log), + DEBUG_FOO(wmi_event_log), + DEBUG_FOO(wmi_rx_event_log), + DEBUG_FOO(wmi_mgmt_command_log), + DEBUG_FOO(wmi_mgmt_command_tx_cmp_log), + DEBUG_FOO(wmi_mgmt_event_log), + DEBUG_FOO(wmi_enable), + DEBUG_FOO(wmi_log_size), +}; + +#define NUM_DEBUG_INFOS (sizeof(wmi_debugfs_infos) / \ + sizeof(wmi_debugfs_infos[0])) + +/** + * wmi_debugfs_create() - Create debug_fs entry for wmi logging. + * + * @wmi_handle: wmi handle + * @par_entry: debug directory entry + * @id: Index to debug info data array + * + * Return: none + */ +static void wmi_debugfs_create(wmi_unified_t wmi_handle, + struct dentry *par_entry, int id) +{ + int i; + + if (par_entry == NULL || (id < 0) || (id >= MAX_WMI_INSTANCES)) + goto out; + + for (i = 0; i < NUM_DEBUG_INFOS; ++i) { + + wmi_debugfs_infos[i].de[id] = debugfs_create_file( + wmi_debugfs_infos[i].name, 0644, par_entry, + wmi_handle, wmi_debugfs_infos[i].ops); + + if (wmi_debugfs_infos[i].de[id] == NULL) { + qdf_print("%s: debug Entry creation failed!\n", + __func__); + goto out; + } + } + + return; + +out: + qdf_print("%s: debug Entry creation failed!\n", __func__); + wmi_log_buffer_free(wmi_handle); + return; +} + +/** + * wmi_debugfs_remove() - Remove debugfs entry for wmi logging. + * @wmi_handle: wmi handle + * @dentry: debugfs directory entry + * @id: Index to debug info data array + * + * Return: none + */ +static void wmi_debugfs_remove(wmi_unified_t wmi_handle) +{ + int i; + struct dentry *dentry = wmi_handle->log_info.wmi_log_debugfs_dir; + int id = wmi_handle->log_info.wmi_instance_id; + + if (dentry && (!(id < 0) || (id >= MAX_WMI_INSTANCES))) { + for (i = 0; i < NUM_DEBUG_INFOS; ++i) { + if (wmi_debugfs_infos[i].de[id]) + wmi_debugfs_infos[i].de[id] = NULL; + } + } + + if (dentry) + debugfs_remove_recursive(dentry); +} + +/** + * wmi_debugfs_init() - debugfs functions to create debugfs directory and to + * create debugfs enteries. + * + * @h: wmi handler + * + * Return: init status + */ +static QDF_STATUS wmi_debugfs_init(wmi_unified_t wmi_handle) +{ + static int wmi_index; + + if (wmi_index < MAX_WMI_INSTANCES) + wmi_handle->log_info.wmi_log_debugfs_dir = + debugfs_create_dir(debugfs_dir[wmi_index], NULL); + + if (wmi_handle->log_info.wmi_log_debugfs_dir == NULL) { + qdf_print("error while creating debugfs dir for %s\n", + debugfs_dir[wmi_index]); + return QDF_STATUS_E_FAILURE; + } + + wmi_debugfs_create(wmi_handle, wmi_handle->log_info.wmi_log_debugfs_dir, + wmi_index); + wmi_handle->log_info.wmi_instance_id = wmi_index++; + + return QDF_STATUS_SUCCESS; +} + +/** + * wmi_mgmt_cmd_record() - Wrapper function for mgmt command logging macro + * + * @wmi_handle: wmi handle + * @cmd: mgmt command + * @header: pointer to 802.11 header + * @vdev_id: vdev id + * @chanfreq: channel frequency + * + * Return: none + */ +void wmi_mgmt_cmd_record(wmi_unified_t wmi_handle, uint32_t cmd, + void *header, uint32_t vdev_id, uint32_t chanfreq) +{ + qdf_spin_lock_bh(&wmi_handle->log_info.wmi_record_lock); + + WMI_MGMT_COMMAND_RECORD(cmd, + ((struct wmi_command_header *)header)->type, + ((struct wmi_command_header *)header)->sub_type, + vdev_id, chanfreq); + + qdf_spin_unlock_bh(&wmi_handle->log_info.wmi_record_lock); +} +#else +/** + * wmi_debugfs_remove() - Remove debugfs entry for wmi logging. + * @wmi_handle: wmi handle + * @dentry: debugfs directory entry + * @id: Index to debug info data array + * + * Return: none + */ +static void wmi_debugfs_remove(wmi_unified_t wmi_handle) { } +void wmi_mgmt_cmd_record(wmi_unified_t wmi_handle, uint32_t cmd, + void *header, uint32_t vdev_id, uint32_t chanfreq) { } +#endif /*WMI_INTERFACE_EVENT_LOGGING */ + +int wmi_get_host_credits(wmi_unified_t wmi_handle); +/* WMI buffer APIs */ + +#ifdef MEMORY_DEBUG +wmi_buf_t +wmi_buf_alloc_debug(wmi_unified_t wmi_handle, uint16_t len, uint8_t *file_name, + uint32_t line_num) +{ + wmi_buf_t wmi_buf; + + if (roundup(len + WMI_MIN_HEAD_ROOM, 4) > wmi_handle->max_msg_len) { + QDF_ASSERT(0); + return NULL; + } + + wmi_buf = qdf_nbuf_alloc_debug(NULL, + roundup(len + WMI_MIN_HEAD_ROOM, 4), + WMI_MIN_HEAD_ROOM, 4, false, file_name, + line_num); + + if (!wmi_buf) + return NULL; + + /* Clear the wmi buffer */ + OS_MEMZERO(qdf_nbuf_data(wmi_buf), len); + + /* + * Set the length of the buffer to match the allocation size. + */ + qdf_nbuf_set_pktlen(wmi_buf, len); + + return wmi_buf; +} + +void wmi_buf_free(wmi_buf_t net_buf) +{ + qdf_nbuf_free(net_buf); +} +#else +wmi_buf_t wmi_buf_alloc(wmi_unified_t wmi_handle, uint16_t len) +{ + wmi_buf_t wmi_buf; + + if (roundup(len + WMI_MIN_HEAD_ROOM, 4) > wmi_handle->max_msg_len) { + QDF_ASSERT(0); + return NULL; + } + + wmi_buf = qdf_nbuf_alloc(NULL, roundup(len + WMI_MIN_HEAD_ROOM, 4), + WMI_MIN_HEAD_ROOM, 4, false); + if (!wmi_buf) + return NULL; + + /* Clear the wmi buffer */ + OS_MEMZERO(qdf_nbuf_data(wmi_buf), len); + + /* + * Set the length of the buffer to match the allocation size. + */ + qdf_nbuf_set_pktlen(wmi_buf, len); + return wmi_buf; +} + +void wmi_buf_free(wmi_buf_t net_buf) +{ + qdf_nbuf_free(net_buf); +} +#endif + +/** + * wmi_get_max_msg_len() - get maximum WMI message length + * @wmi_handle: WMI handle. + * + * This function returns the maximum WMI message length + * + * Return: maximum WMI message length + */ +uint16_t wmi_get_max_msg_len(wmi_unified_t wmi_handle) +{ + return wmi_handle->max_msg_len - WMI_MIN_HEAD_ROOM; +} + +#ifndef WMI_CMD_STRINGS +static uint8_t *wmi_id_to_name(uint32_t wmi_command) +{ + return "Invalid WMI cmd"; +} +#endif + + +#ifndef WMI_NON_TLV_SUPPORT +static inline void wma_log_cmd_id(uint32_t cmd_id, uint32_t tag) +{ + WMI_LOGD("Send WMI command:%s command_id:%d htc_tag:%d", + wmi_id_to_name(cmd_id), cmd_id, tag); +} +#endif + +#ifndef WMI_NON_TLV_SUPPORT +/** + * wmi_is_pm_resume_cmd() - check if a cmd is part of the resume sequence + * @cmd_id: command to check + * + * Return: true if the command is part of the resume sequence. + */ +static bool wmi_is_pm_resume_cmd(uint32_t cmd_id) +{ + switch (cmd_id) { + case WMI_WOW_HOSTWAKEUP_FROM_SLEEP_CMDID: + case WMI_PDEV_RESUME_CMDID: + return true; + + default: + return false; + } +} +#else +static bool wmi_is_pm_resume_cmd(uint32_t cmd_id) +{ + return false; +} +#endif + +/** + * wmi_unified_cmd_send() - WMI command API + * @wmi_handle: handle to wmi + * @buf: wmi buf + * @len: wmi buffer length + * @cmd_id: wmi command id + * + * Note, it is NOT safe to access buf after calling this function! + * + * Return: 0 on success + */ +QDF_STATUS wmi_unified_cmd_send(wmi_unified_t wmi_handle, wmi_buf_t buf, + uint32_t len, uint32_t cmd_id) +{ + HTC_PACKET *pkt; + A_STATUS status; + uint16_t htc_tag = 0; + + if (wmi_get_runtime_pm_inprogress(wmi_handle)) { + htc_tag = + (A_UINT16)wmi_handle->ops->wmi_set_htc_tx_tag( + wmi_handle, buf, cmd_id); + } else if (qdf_atomic_read(&wmi_handle->is_target_suspended) && + (!wmi_is_pm_resume_cmd(cmd_id))) { + QDF_TRACE(QDF_MODULE_ID_WMI, QDF_TRACE_LEVEL_ERROR, + "%s: Target is suspended", __func__); + QDF_ASSERT(0); + return QDF_STATUS_E_BUSY; + } + if (wmi_handle->wmi_stopinprogress) { + QDF_TRACE(QDF_MODULE_ID_WMI, QDF_TRACE_LEVEL_ERROR, + "WMI stop in progress\n"); + return QDF_STATUS_E_INVAL; + } + + /* Do sanity check on the TLV parameter structure */ +#ifndef WMI_NON_TLV_SUPPORT + if (wmi_handle->target_type == WMI_TLV_TARGET) { + void *buf_ptr = (void *)qdf_nbuf_data(buf); + + if (wmitlv_check_command_tlv_params(NULL, buf_ptr, len, cmd_id) + != 0) { + QDF_TRACE(QDF_MODULE_ID_WMI, QDF_TRACE_LEVEL_ERROR, + "\nERROR: %s: Invalid WMI Param Buffer for Cmd:%d", + __func__, cmd_id); + return QDF_STATUS_E_INVAL; + } + } +#endif + + if (qdf_nbuf_push_head(buf, sizeof(WMI_CMD_HDR)) == NULL) { + QDF_TRACE(QDF_MODULE_ID_WMI, QDF_TRACE_LEVEL_ERROR, + "%s, Failed to send cmd %x, no memory", + __func__, cmd_id); + return QDF_STATUS_E_NOMEM; + } + + WMI_SET_FIELD(qdf_nbuf_data(buf), WMI_CMD_HDR, COMMANDID, cmd_id); + + qdf_atomic_inc(&wmi_handle->pending_cmds); + if (qdf_atomic_read(&wmi_handle->pending_cmds) >= WMI_MAX_CMDS) { + QDF_TRACE(QDF_MODULE_ID_WMI, QDF_TRACE_LEVEL_ERROR, + "\n%s: hostcredits = %d", __func__, + wmi_get_host_credits(wmi_handle)); + htc_dump_counter_info(wmi_handle->htc_handle); + qdf_atomic_dec(&wmi_handle->pending_cmds); + QDF_TRACE(QDF_MODULE_ID_WMI, QDF_TRACE_LEVEL_ERROR, + "%s: MAX %d WMI Pending cmds reached.", __func__, + WMI_MAX_CMDS); + QDF_BUG(0); + return QDF_STATUS_E_BUSY; + } + + pkt = qdf_mem_malloc(sizeof(*pkt)); + if (!pkt) { + qdf_atomic_dec(&wmi_handle->pending_cmds); + QDF_TRACE(QDF_MODULE_ID_WMI, QDF_TRACE_LEVEL_ERROR, + "%s, Failed to alloc htc packet %x, no memory", + __func__, cmd_id); + return QDF_STATUS_E_NOMEM; + } + + SET_HTC_PACKET_INFO_TX(pkt, + NULL, + qdf_nbuf_data(buf), len + sizeof(WMI_CMD_HDR), + wmi_handle->wmi_endpoint_id, htc_tag); + + SET_HTC_PACKET_NET_BUF_CONTEXT(pkt, buf); +#ifndef WMI_NON_TLV_SUPPORT + wma_log_cmd_id(cmd_id, htc_tag); +#endif + +#ifdef WMI_INTERFACE_EVENT_LOGGING + if (wmi_handle->log_info.wmi_logging_enable) { + qdf_spin_lock_bh(&wmi_handle->log_info.wmi_record_lock); + if (!wmi_handle->log_info.is_management_record(cmd_id)) { + WMI_COMMAND_RECORD(wmi_handle, cmd_id, + ((uint32_t *) qdf_nbuf_data(buf) + + wmi_handle->log_info.buf_offset_command)); + } + qdf_spin_unlock_bh(&wmi_handle->log_info.wmi_record_lock); + } +#endif + + status = htc_send_pkt(wmi_handle->htc_handle, pkt); + + if (A_OK != status) { + qdf_atomic_dec(&wmi_handle->pending_cmds); + QDF_TRACE(QDF_MODULE_ID_WMI, QDF_TRACE_LEVEL_ERROR, + "%s %d, htc_send_pkt failed", __func__, __LINE__); + qdf_mem_free(pkt); + + } + if (status) + return QDF_STATUS_E_FAILURE; + + return QDF_STATUS_SUCCESS; +} + +/** + * wmi_unified_get_event_handler_ix() - gives event handler's index + * @wmi_handle: handle to wmi + * @event_id: wmi event id + * + * Return: event handler's index + */ +static int wmi_unified_get_event_handler_ix(wmi_unified_t wmi_handle, + uint32_t event_id) +{ + uint32_t idx = 0; + int32_t invalid_idx = -1; + + for (idx = 0; (idx < wmi_handle->max_event_idx && + idx < WMI_UNIFIED_MAX_EVENT); ++idx) { + if (wmi_handle->event_id[idx] == event_id && + wmi_handle->event_handler[idx] != NULL) { + return idx; + } + } + + return invalid_idx; +} + +/** + * wmi_unified_register_event_handler() - register wmi event handler + * @wmi_handle: handle to wmi + * @event_id: wmi event id + * @handler_func: wmi event handler function + * @rx_ctx: rx execution context for wmi rx events + * + * Return: 0 on success + */ +int wmi_unified_register_event_handler(wmi_unified_t wmi_handle, + uint32_t event_id, + wmi_unified_event_handler handler_func, + uint8_t rx_ctx) +{ + uint32_t idx = 0; + uint32_t evt_id; + +#ifdef WMI_TLV_AND_NON_TLV_SUPPORT + if (event_id >= wmi_events_max || + wmi_handle->wmi_events[event_id] == WMI_EVENT_ID_INVALID) { + qdf_print("%s: Event id %d is unavailable\n", + __func__, event_id); + return QDF_STATUS_E_FAILURE; + } + evt_id = wmi_handle->wmi_events[event_id]; +#else + evt_id = event_id; +#endif + if (wmi_unified_get_event_handler_ix(wmi_handle, evt_id) != -1) { + qdf_print("%s : event handler already registered 0x%x\n", + __func__, evt_id); + return QDF_STATUS_E_FAILURE; + } + if (wmi_handle->max_event_idx == WMI_UNIFIED_MAX_EVENT) { + qdf_print("%s : no more event handlers 0x%x\n", + __func__, evt_id); + return QDF_STATUS_E_FAILURE; + } + idx = wmi_handle->max_event_idx; + wmi_handle->event_handler[idx] = handler_func; + wmi_handle->event_id[idx] = evt_id; + qdf_spin_lock_bh(&wmi_handle->ctx_lock); + wmi_handle->ctx[idx] = rx_ctx; + qdf_spin_unlock_bh(&wmi_handle->ctx_lock); + wmi_handle->max_event_idx++; + + return 0; +} + +/** + * wmi_unified_unregister_event_handler() - unregister wmi event handler + * @wmi_handle: handle to wmi + * @event_id: wmi event id + * + * Return: 0 on success + */ +int wmi_unified_unregister_event_handler(wmi_unified_t wmi_handle, + uint32_t event_id) +{ + uint32_t idx = 0; + uint32_t evt_id; + +#ifdef WMI_TLV_AND_NON_TLV_SUPPORT + if (event_id >= wmi_events_max || + wmi_handle->wmi_events[event_id] == WMI_EVENT_ID_INVALID) { + qdf_print("%s: Event id %d is unavailable\n", + __func__, event_id); + return QDF_STATUS_E_FAILURE; + } + evt_id = wmi_handle->wmi_events[event_id]; +#else + evt_id = event_id; +#endif + + idx = wmi_unified_get_event_handler_ix(wmi_handle, evt_id); + if (idx == -1) { + qdf_print("%s : event handler is not registered: evt id 0x%x\n", + __func__, evt_id); + return QDF_STATUS_E_FAILURE; + } + wmi_handle->event_handler[idx] = NULL; + wmi_handle->event_id[idx] = 0; + --wmi_handle->max_event_idx; + wmi_handle->event_handler[idx] = + wmi_handle->event_handler[wmi_handle->max_event_idx]; + wmi_handle->event_id[idx] = + wmi_handle->event_id[wmi_handle->max_event_idx]; + + return 0; +} + +/** + * wmi_process_fw_event_default_ctx() - process in default caller context + * @wmi_handle: handle to wmi + * @htc_packet: pointer to htc packet + * @exec_ctx: execution context for wmi fw event + * + * Event process by below function will be in default caller context. + * wmi internally provides rx work thread processing context. + * + * Return: none + */ +static void wmi_process_fw_event_default_ctx(struct wmi_unified *wmi_handle, + HTC_PACKET *htc_packet, uint8_t exec_ctx) +{ + wmi_buf_t evt_buf; + evt_buf = (wmi_buf_t) htc_packet->pPktContext; + +#ifdef WMI_NON_TLV_SUPPORT + wmi_handle->rx_ops.wma_process_fw_event_handler_cbk + (wmi_handle->scn_handle, evt_buf, exec_ctx); +#else + wmi_handle->rx_ops.wma_process_fw_event_handler_cbk(wmi_handle, + evt_buf, exec_ctx); +#endif + + return; +} + +/** + * wmi_process_fw_event_worker_thread_ctx() - process in worker thread context + * @wmi_handle: handle to wmi + * @htc_packet: pointer to htc packet + * + * Event process by below function will be in worker thread context. + * Use this method for events which are not critical and not + * handled in protocol stack. + * + * Return: none + */ +static void wmi_process_fw_event_worker_thread_ctx + (struct wmi_unified *wmi_handle, HTC_PACKET *htc_packet) +{ + wmi_buf_t evt_buf; + uint32_t id; + uint8_t *data; + + evt_buf = (wmi_buf_t) htc_packet->pPktContext; + id = WMI_GET_FIELD(qdf_nbuf_data(evt_buf), WMI_CMD_HDR, COMMANDID); + data = qdf_nbuf_data(evt_buf); + +#ifdef WMI_INTERFACE_EVENT_LOGGING + if (wmi_handle->log_info.wmi_logging_enable) { + qdf_spin_lock_bh(&wmi_handle->log_info.wmi_record_lock); + /* Exclude 4 bytes of TLV header */ + WMI_RX_EVENT_RECORD(wmi_handle, id, ((uint8_t *) data + + wmi_handle->log_info.buf_offset_event)); + qdf_spin_unlock_bh(&wmi_handle->log_info.wmi_record_lock); + } +#endif + qdf_spin_lock_bh(&wmi_handle->eventq_lock); + qdf_nbuf_queue_add(&wmi_handle->event_queue, evt_buf); + qdf_spin_unlock_bh(&wmi_handle->eventq_lock); + schedule_work(&wmi_handle->rx_event_work); + return; +} + +/** + * wmi_control_rx() - process fw events callbacks + * @ctx: handle to wmi + * @htc_packet: pointer to htc packet + * + * Return: none + */ +static void wmi_control_rx(void *ctx, HTC_PACKET *htc_packet) +{ + struct wmi_unified *wmi_handle = (struct wmi_unified *)ctx; + wmi_buf_t evt_buf; + uint32_t id; + uint32_t idx = 0; + enum wmi_rx_exec_ctx exec_ctx; + + evt_buf = (wmi_buf_t) htc_packet->pPktContext; + id = WMI_GET_FIELD(qdf_nbuf_data(evt_buf), WMI_CMD_HDR, COMMANDID); + idx = wmi_unified_get_event_handler_ix(wmi_handle, id); + if (qdf_unlikely(idx == A_ERROR)) { + qdf_print + ("%s :event handler is not registered: event id 0x%x\n", + __func__, id); + qdf_nbuf_free(evt_buf); + return; + } + qdf_spin_lock_bh(&wmi_handle->ctx_lock); + exec_ctx = wmi_handle->ctx[idx]; + qdf_spin_unlock_bh(&wmi_handle->ctx_lock); + + if (exec_ctx == WMI_RX_WORK_CTX) { + wmi_process_fw_event_worker_thread_ctx + (wmi_handle, htc_packet); + } else if (exec_ctx > WMI_RX_WORK_CTX) { + wmi_process_fw_event_default_ctx + (wmi_handle, htc_packet, exec_ctx); + } else { + qdf_print("%s :Invalid event context %d\n", __func__, exec_ctx); + qdf_nbuf_free(evt_buf); + } + +} + +/** + * wmi_process_fw_event() - process any fw event + * @wmi_handle: wmi handle + * @evt_buf: fw event buffer + * + * This function process fw event in caller context + * + * Return: none + */ +void wmi_process_fw_event(struct wmi_unified *wmi_handle, wmi_buf_t evt_buf) +{ + __wmi_control_rx(wmi_handle, evt_buf); +} + +/** + * __wmi_control_rx() - process serialize wmi event callback + * @wmi_handle: wmi handle + * @evt_buf: fw event buffer + * + * Return: none + */ +void __wmi_control_rx(struct wmi_unified *wmi_handle, wmi_buf_t evt_buf) +{ + uint32_t id; + uint8_t *data; + uint32_t len; + void *wmi_cmd_struct_ptr = NULL; +#ifndef WMI_NON_TLV_SUPPORT + int tlv_ok_status = 0; +#endif + uint32_t idx = 0; + + id = WMI_GET_FIELD(qdf_nbuf_data(evt_buf), WMI_CMD_HDR, COMMANDID); + + if (qdf_nbuf_pull_head(evt_buf, sizeof(WMI_CMD_HDR)) == NULL) + goto end; + + data = qdf_nbuf_data(evt_buf); + len = qdf_nbuf_len(evt_buf); + +#ifndef WMI_NON_TLV_SUPPORT + if (wmi_handle->target_type == WMI_TLV_TARGET) { + /* Validate and pad(if necessary) the TLVs */ + tlv_ok_status = + wmitlv_check_and_pad_event_tlvs(wmi_handle->scn_handle, + data, len, id, + &wmi_cmd_struct_ptr); + if (tlv_ok_status != 0) { + QDF_TRACE(QDF_MODULE_ID_WMI, QDF_TRACE_LEVEL_ERROR, + "%s: Error: id=0x%d, wmitlv check status=%d\n", + __func__, id, tlv_ok_status); + goto end; + } + } +#endif + + idx = wmi_unified_get_event_handler_ix(wmi_handle, id); + if (idx == A_ERROR) { + QDF_TRACE(QDF_MODULE_ID_WMI, QDF_TRACE_LEVEL_ERROR, + "%s : event handler is not registered: event id 0x%x\n", + __func__, id); + goto end; + } +#ifdef WMI_INTERFACE_EVENT_LOGGING + if (wmi_handle->log_info.wmi_logging_enable) { + qdf_spin_lock_bh(&wmi_handle->log_info.wmi_record_lock); + /* Exclude 4 bytes of TLV header */ + if (wmi_handle->log_info.is_management_record(id)) { + WMI_MGMT_EVENT_RECORD(wmi_handle, id, ((uint8_t *) data + + wmi_handle->log_info.buf_offset_event)); + } else { + WMI_EVENT_RECORD(wmi_handle, id, ((uint8_t *) data + + wmi_handle->log_info.buf_offset_event)); + } + qdf_spin_unlock_bh(&wmi_handle->log_info.wmi_record_lock); + } +#endif + /* Call the WMI registered event handler */ + if (wmi_handle->target_type == WMI_TLV_TARGET) + wmi_handle->event_handler[idx] (wmi_handle->scn_handle, + wmi_cmd_struct_ptr, len); + else + wmi_handle->event_handler[idx] (wmi_handle->scn_handle, + data, len); + +end: + /* Free event buffer and allocated event tlv */ +#ifndef WMI_NON_TLV_SUPPORT + if (wmi_handle->target_type == WMI_TLV_TARGET) + wmitlv_free_allocated_event_tlvs(id, &wmi_cmd_struct_ptr); +#endif + qdf_nbuf_free(evt_buf); + +} + +/** + * wmi_rx_event_work() - process rx event in rx work queue context + * @work: rx work queue struct + * + * This function process any fw event to serialize it through rx worker thread. + * + * Return: none + */ +static void wmi_rx_event_work(struct work_struct *work) +{ + struct wmi_unified *wmi = container_of(work, struct wmi_unified, + rx_event_work); + wmi_buf_t buf; + + qdf_spin_lock_bh(&wmi->eventq_lock); + buf = qdf_nbuf_queue_remove(&wmi->event_queue); + qdf_spin_unlock_bh(&wmi->eventq_lock); + while (buf) { + __wmi_control_rx(wmi, buf); + qdf_spin_lock_bh(&wmi->eventq_lock); + buf = qdf_nbuf_queue_remove(&wmi->event_queue); + qdf_spin_unlock_bh(&wmi->eventq_lock); + } +} + +#ifdef FEATURE_RUNTIME_PM +/** + * wmi_runtime_pm_init() - initialize runtime pm wmi variables + * @wmi_handle: wmi context + */ +static void wmi_runtime_pm_init(struct wmi_unified *wmi_handle) +{ + qdf_atomic_init(&wmi_handle->runtime_pm_inprogress); +} + +/** + * wmi_set_runtime_pm_inprogress() - set runtime pm progress flag + * @wmi_handle: wmi context + * @val: runtime pm progress flag + */ +void wmi_set_runtime_pm_inprogress(wmi_unified_t wmi_handle, A_BOOL val) +{ + qdf_atomic_set(&wmi_handle->runtime_pm_inprogress, val); +} + +/** + * wmi_get_runtime_pm_inprogress() - get runtime pm progress flag + * @wmi_handle: wmi context + */ +inline bool wmi_get_runtime_pm_inprogress(wmi_unified_t wmi_handle) +{ + return qdf_atomic_read(&wmi_handle->runtime_pm_inprogress); +} +#else +static void wmi_runtime_pm_init(struct wmi_unified *wmi_handle) +{ +} +#endif + +/** + * wmi_unified_attach() - attach for unified WMI + * @scn_handle: handle to SCN + * @osdev: OS device context + * @target_type: TLV or not-TLV based target + * @use_cookie: cookie based allocation enabled/disabled + * @ops: umac rx callbacks + * + * @Return: wmi handle. + */ +void *wmi_unified_attach(void *scn_handle, + osdev_t osdev, enum wmi_target_type target_type, + bool use_cookie, struct wmi_rx_ops *rx_ops) +{ + struct wmi_unified *wmi_handle; + +#ifndef WMI_NON_TLV_SUPPORT + wmi_handle = + (struct wmi_unified *)os_malloc(NULL, + sizeof(struct wmi_unified), + GFP_ATOMIC); +#else + wmi_handle = + (struct wmi_unified *) qdf_mem_malloc( + sizeof(struct wmi_unified)); +#endif + if (wmi_handle == NULL) { + qdf_print("allocation of wmi handle failed %zu\n", + sizeof(struct wmi_unified)); + return NULL; + } + OS_MEMZERO(wmi_handle, sizeof(struct wmi_unified)); + wmi_handle->scn_handle = scn_handle; + qdf_atomic_init(&wmi_handle->pending_cmds); + qdf_atomic_init(&wmi_handle->is_target_suspended); + wmi_runtime_pm_init(wmi_handle); + qdf_spinlock_create(&wmi_handle->eventq_lock); + qdf_nbuf_queue_init(&wmi_handle->event_queue); + INIT_WORK(&wmi_handle->rx_event_work, wmi_rx_event_work); +#ifdef WMI_INTERFACE_EVENT_LOGGING + if (QDF_STATUS_SUCCESS == wmi_log_init(wmi_handle)) { + wmi_debugfs_init(wmi_handle); + } +#endif + /* Attach mc_thread context processing function */ + wmi_handle->rx_ops.wma_process_fw_event_handler_cbk = + rx_ops->wma_process_fw_event_handler_cbk; + wmi_handle->target_type = target_type; + if (target_type == WMI_TLV_TARGET) + wmi_tlv_attach(wmi_handle); + else + wmi_non_tlv_attach(wmi_handle); + /* Assign target cookie capablity */ + wmi_handle->use_cookie = use_cookie; + wmi_handle->osdev = osdev; + wmi_handle->wmi_stopinprogress = 0; + qdf_spinlock_create(&wmi_handle->ctx_lock); + + return wmi_handle; +} + +/** + * wmi_unified_detach() - detach for unified WMI + * + * @wmi_handle : handle to wmi. + * + * @Return: none. + */ +void wmi_unified_detach(struct wmi_unified *wmi_handle) +{ + wmi_buf_t buf; + + cancel_work_sync(&wmi_handle->rx_event_work); + + wmi_debugfs_remove(wmi_handle); + + buf = qdf_nbuf_queue_remove(&wmi_handle->event_queue); + while (buf) { + qdf_nbuf_free(buf); + buf = qdf_nbuf_queue_remove(&wmi_handle->event_queue); + } + +#ifdef WMI_INTERFACE_EVENT_LOGGING + wmi_log_buffer_free(wmi_handle); +#endif + + qdf_spinlock_destroy(&wmi_handle->eventq_lock); + qdf_spinlock_destroy(&wmi_handle->ctx_lock); + OS_FREE(wmi_handle); + wmi_handle = NULL; +} + +/** + * wmi_unified_remove_work() - detach for WMI work + * @wmi_handle: handle to WMI + * + * A function that does not fully detach WMI, but just remove work + * queue items associated with it. This is used to make sure that + * before any other processing code that may destroy related contexts + * (HTC, etc), work queue processing on WMI has already been stopped. + * + * Return: None + */ +void +wmi_unified_remove_work(struct wmi_unified *wmi_handle) +{ + wmi_buf_t buf; + + QDF_TRACE(QDF_MODULE_ID_WMI, QDF_TRACE_LEVEL_INFO, + "Enter: %s", __func__); + cancel_work_sync(&wmi_handle->rx_event_work); + qdf_spin_lock_bh(&wmi_handle->eventq_lock); + buf = qdf_nbuf_queue_remove(&wmi_handle->event_queue); + while (buf) { + qdf_nbuf_free(buf); + buf = qdf_nbuf_queue_remove(&wmi_handle->event_queue); + } + qdf_spin_unlock_bh(&wmi_handle->eventq_lock); + QDF_TRACE(QDF_MODULE_ID_WMI, QDF_TRACE_LEVEL_INFO, + "Done: %s", __func__); +} + +/** + * wmi_htc_tx_complete() - Process htc tx completion + * + * @ctx: handle to wmi + * @htc_packet: pointer to htc packet + * + * @Return: none. + */ +static void wmi_htc_tx_complete(void *ctx, HTC_PACKET *htc_pkt) +{ + struct wmi_unified *wmi_handle = (struct wmi_unified *)ctx; + wmi_buf_t wmi_cmd_buf = GET_HTC_PACKET_NET_BUF_CONTEXT(htc_pkt); + u_int8_t *buf_ptr; + u_int32_t len; +#ifdef WMI_INTERFACE_EVENT_LOGGING + uint32_t cmd_id; +#endif + + ASSERT(wmi_cmd_buf); +#ifdef WMI_INTERFACE_EVENT_LOGGING + if (wmi_handle->log_info.wmi_logging_enable) { + cmd_id = WMI_GET_FIELD(qdf_nbuf_data(wmi_cmd_buf), + WMI_CMD_HDR, COMMANDID); + + WMI_LOGD("Sent WMI command:%s command_id:0x%x over dma and recieved tx complete interupt", + wmi_id_to_name(cmd_id), cmd_id); + + qdf_spin_lock_bh(&wmi_handle->log_info.wmi_record_lock); + /* Record 16 bytes of WMI cmd tx complete data + - exclude TLV and WMI headers */ + if (wmi_handle->log_info.is_management_record(cmd_id)) { + WMI_MGMT_COMMAND_TX_CMP_RECORD(wmi_handle, cmd_id, + ((uint32_t *) qdf_nbuf_data(wmi_cmd_buf) + + wmi_handle->log_info.buf_offset_command)); + } else { + WMI_COMMAND_TX_CMP_RECORD(wmi_handle, cmd_id, + ((uint32_t *) qdf_nbuf_data(wmi_cmd_buf) + + wmi_handle->log_info.buf_offset_command)); + } + + qdf_spin_unlock_bh(&wmi_handle->log_info.wmi_record_lock); + } +#endif + buf_ptr = (u_int8_t *) wmi_buf_data(wmi_cmd_buf); + len = qdf_nbuf_len(wmi_cmd_buf); + qdf_mem_zero(buf_ptr, len); + qdf_nbuf_free(wmi_cmd_buf); + qdf_mem_free(htc_pkt); + qdf_atomic_dec(&wmi_handle->pending_cmds); +} + +/** + * wmi_get_host_credits() - WMI API to get updated host_credits + * + * @wmi_handle: handle to WMI. + * + * @Return: updated host_credits. + */ +int +wmi_unified_connect_htc_service(struct wmi_unified *wmi_handle, + void *htc_handle) +{ + + int status; + HTC_SERVICE_CONNECT_RESP response; + HTC_SERVICE_CONNECT_REQ connect; + + OS_MEMZERO(&connect, sizeof(connect)); + OS_MEMZERO(&response, sizeof(response)); + + /* meta data is unused for now */ + connect.pMetaData = NULL; + connect.MetaDataLength = 0; + /* these fields are the same for all service endpoints */ + connect.EpCallbacks.pContext = wmi_handle; + connect.EpCallbacks.EpTxCompleteMultiple = + NULL /* Control path completion ar6000_tx_complete */; + connect.EpCallbacks.EpRecv = wmi_control_rx /* Control path rx */; + connect.EpCallbacks.EpRecvRefill = NULL /* ar6000_rx_refill */; + connect.EpCallbacks.EpSendFull = NULL /* ar6000_tx_queue_full */; + connect.EpCallbacks.EpTxComplete = + wmi_htc_tx_complete /* ar6000_tx_queue_full */; + + /* connect to control service */ + connect.service_id = WMI_CONTROL_SVC; + status = htc_connect_service(htc_handle, &connect, + &response); + + if (status != EOK) { + qdf_print + ("Failed to connect to WMI CONTROL service status:%d \n", + status); + return status; + } + wmi_handle->wmi_endpoint_id = response.Endpoint; + wmi_handle->htc_handle = htc_handle; + wmi_handle->max_msg_len = response.MaxMsgLength; + + return EOK; +} + +/** + * wmi_get_host_credits() - WMI API to get updated host_credits + * + * @wmi_handle: handle to WMI. + * + * @Return: updated host_credits. + */ +int wmi_get_host_credits(wmi_unified_t wmi_handle) +{ + int host_credits = 0; + + htc_get_control_endpoint_tx_host_credits(wmi_handle->htc_handle, + &host_credits); + return host_credits; +} + +/** + * wmi_get_pending_cmds() - WMI API to get WMI Pending Commands in the HTC + * queue + * + * @wmi_handle: handle to WMI. + * + * @Return: Pending Commands in the HTC queue. + */ +int wmi_get_pending_cmds(wmi_unified_t wmi_handle) +{ + return qdf_atomic_read(&wmi_handle->pending_cmds); +} + +/** + * wmi_set_target_suspend() - WMI API to set target suspend state + * + * @wmi_handle: handle to WMI. + * @val: suspend state boolean. + * + * @Return: none. + */ +void wmi_set_target_suspend(wmi_unified_t wmi_handle, A_BOOL val) +{ + qdf_atomic_set(&wmi_handle->is_target_suspended, val); +} + +/** + * WMI API to set crash injection state + * @param wmi_handle: handle to WMI. + * @param val: crash injection state boolean. + */ +void wmi_tag_crash_inject(wmi_unified_t wmi_handle, A_BOOL flag) +{ + wmi_handle->tag_crash_inject = flag; +} + +/** + * WMI API to set bus suspend state + * @param wmi_handle: handle to WMI. + * @param val: suspend state boolean. + */ +void wmi_set_is_wow_bus_suspended(wmi_unified_t wmi_handle, A_BOOL val) +{ + qdf_atomic_set(&wmi_handle->is_wow_bus_suspended, val); +} + +/** + * wmi_set_tgt_assert() - set target assert configuration + * + * @wmi_handle : handle to WMI. + * @val : target assert config value + * + * @Return: none. + */ +void wmi_set_tgt_assert(wmi_unified_t wmi_handle, bool val) +{ + wmi_handle->tgt_force_assert_enable = val; +} +#ifdef WMI_NON_TLV_SUPPORT +/** + * API to flush all the previous packets associated with the wmi endpoint + * + * @param wmi_handle : handle to WMI. + */ +void +wmi_flush_endpoint(wmi_unified_t wmi_handle) +{ + htc_flush_endpoint(wmi_handle->htc_handle, + wmi_handle->wmi_endpoint_id, 0); +} + +/** + * generic function to block unified WMI command + * @param wmi_handle : handle to WMI. + * @return 0 on success and -ve on failure. + */ +int +wmi_stop(wmi_unified_t wmi_handle) +{ + QDF_TRACE(QDF_MODULE_ID_WMI, QDF_TRACE_LEVEL_INFO, + "WMI Stop\n"); + wmi_handle->wmi_stopinprogress = 1; + return 0; +} +#endif diff --git a/drivers/staging/qca-wifi-host-cmn/wmi/src/wmi_unified_api.c b/drivers/staging/qca-wifi-host-cmn/wmi/src/wmi_unified_api.c new file mode 100644 index 0000000000000000000000000000000000000000..7ce9bd4fd2e126d520b1ed1cae2964a6d313ac95 --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/wmi/src/wmi_unified_api.c @@ -0,0 +1,6289 @@ +/* + * Copyright (c) 2016-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ +#include "athdefs.h" +#include "osapi_linux.h" +#include "a_types.h" +#include "a_debug.h" +#include "ol_if_athvar.h" +#include "ol_defines.h" +#include "wmi_unified_priv.h" +#include "wmi_unified_param.h" + +/** + * wmi_unified_vdev_create_send() - send VDEV create command to fw + * @wmi_handle: wmi handle + * @param: pointer to hold vdev create parameter + * @macaddr: vdev mac address + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_vdev_create_send(void *wmi_hdl, + uint8_t macaddr[IEEE80211_ADDR_LEN], + struct vdev_create_params *param) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_vdev_create_cmd) + return wmi_handle->ops->send_vdev_create_cmd(wmi_handle, + macaddr, param); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_vdev_delete_send() - send VDEV delete command to fw + * @wmi_handle: wmi handle + * @if_id: vdev id + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_vdev_delete_send(void *wmi_hdl, + uint8_t if_id) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_vdev_delete_cmd) + return wmi_handle->ops->send_vdev_delete_cmd(wmi_handle, + if_id); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_vdev_stop_send() - send vdev stop command to fw + * @wmi: wmi handle + * @vdev_id: vdev id + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_vdev_stop_send(void *wmi_hdl, + uint8_t vdev_id) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_vdev_stop_cmd) + return wmi_handle->ops->send_vdev_stop_cmd(wmi_handle, + vdev_id); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_vdev_down_send() - send vdev down command to fw + * @wmi: wmi handle + * @vdev_id: vdev id + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_vdev_down_send(void *wmi_hdl, uint8_t vdev_id) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_vdev_down_cmd) + return wmi_handle->ops->send_vdev_down_cmd(wmi_handle, vdev_id); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_vdev_start_send() - send vdev start command to fw + * @wmi: wmi handle + * @vdev_id: vdev id + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_vdev_start_send(void *wmi_hdl, + struct vdev_start_params *req) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_vdev_start_cmd) + return wmi_handle->ops->send_vdev_start_cmd(wmi_handle, req); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_hidden_ssid_vdev_restart_send() - restart vdev to set hidden ssid + * @wmi: wmi handle + * @restart_params: vdev restart params + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_hidden_ssid_vdev_restart_send(void *wmi_hdl, + struct hidden_ssid_vdev_restart_params *restart_params) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_hidden_ssid_vdev_restart_cmd) + return wmi_handle->ops->send_hidden_ssid_vdev_restart_cmd( + wmi_handle, restart_params); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_peer_flush_tids_send() - flush peer tids packets in fw + * @wmi: wmi handle + * @peer_addr: peer mac address + * @param: pointer to hold peer flush tid parameter + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_peer_flush_tids_send(void *wmi_hdl, + uint8_t peer_addr[IEEE80211_ADDR_LEN], + struct peer_flush_params *param) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_peer_flush_tids_cmd) + return wmi_handle->ops->send_peer_flush_tids_cmd(wmi_handle, + peer_addr, param); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_peer_delete_send() - send PEER delete command to fw + * @wmi: wmi handle + * @peer_addr: peer mac addr + * @vdev_id: vdev id + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_peer_delete_send(void *wmi_hdl, + uint8_t + peer_addr[IEEE80211_ADDR_LEN], + uint8_t vdev_id) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_peer_delete_cmd) + return wmi_handle->ops->send_peer_delete_cmd(wmi_handle, + peer_addr, vdev_id); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_set_peer_param() - set peer parameter in fw + * @wmi_ctx: wmi handle + * @peer_addr: peer mac address + * @param : pointer to hold peer set parameter + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_set_peer_param_send(void *wmi_hdl, + uint8_t peer_addr[IEEE80211_ADDR_LEN], + struct peer_set_params *param) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_peer_param_cmd) + return wmi_handle->ops->send_peer_param_cmd(wmi_handle, + peer_addr, param); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_vdev_up_send() - send vdev up command in fw + * @wmi: wmi handle + * @bssid: bssid + * @vdev_up_params: pointer to hold vdev up parameter + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_vdev_up_send(void *wmi_hdl, + uint8_t bssid[IEEE80211_ADDR_LEN], + struct vdev_up_params *params) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_vdev_up_cmd) + return wmi_handle->ops->send_vdev_up_cmd(wmi_handle, bssid, + params); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_peer_create_send() - send peer create command to fw + * @wmi: wmi handle + * @peer_addr: peer mac address + * @peer_type: peer type + * @vdev_id: vdev id + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_peer_create_send(void *wmi_hdl, + struct peer_create_params *param) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_peer_create_cmd) + return wmi_handle->ops->send_peer_create_cmd(wmi_handle, param); + + return QDF_STATUS_E_FAILURE; +} + +#ifdef FEATURE_GREEN_AP +/** + * wmi_unified_green_ap_ps_send() - enable green ap powersave command + * @wmi_handle: wmi handle + * @value: value + * @mac_id: mac id to have radio context + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_green_ap_ps_send(void *wmi_hdl, + uint32_t value, uint8_t mac_id) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_green_ap_ps_cmd) + return wmi_handle->ops->send_green_ap_ps_cmd(wmi_handle, value, + mac_id); + + return QDF_STATUS_E_FAILURE; +} +#else +QDF_STATUS wmi_unified_green_ap_ps_send(void *wmi_hdl, + uint32_t value, uint8_t mac_id) +{ + return 0; +} +#endif /* FEATURE_GREEN_AP */ + +/** + * wmi_unified_pdev_utf_cmd() - send utf command to fw + * @wmi_handle: wmi handle + * @param: pointer to pdev_utf_params + * @mac_id: mac id to have radio context + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS +wmi_unified_pdev_utf_cmd_send(void *wmi_hdl, + struct pdev_utf_params *param, + uint8_t mac_id) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_pdev_utf_cmd) + return wmi_handle->ops->send_pdev_utf_cmd(wmi_handle, param, + mac_id); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_pdev_param_send() - set pdev parameters + * @wmi_handle: wmi handle + * @param: pointer to pdev parameter + * @mac_id: radio context + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failures, + * errno on failure + */ +QDF_STATUS +wmi_unified_pdev_param_send(void *wmi_hdl, + struct pdev_params *param, + uint8_t mac_id) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_pdev_param_cmd) + return wmi_handle->ops->send_pdev_param_cmd(wmi_handle, param, + mac_id); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_suspend_send() - WMI suspend function + * @param wmi_handle : handle to WMI. + * @param param : pointer to hold suspend parameter + * @mac_id: radio context + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_suspend_send(void *wmi_hdl, + struct suspend_params *param, + uint8_t mac_id) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_suspend_cmd) + return wmi_handle->ops->send_suspend_cmd(wmi_handle, param, + mac_id); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_resume_send - WMI resume function + * @param wmi_handle : handle to WMI. + * @mac_id: radio context + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_resume_send(void *wmi_hdl, + uint8_t mac_id) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_resume_cmd) + return wmi_handle->ops->send_resume_cmd(wmi_handle, + mac_id); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_wow_enable_send() - WMI wow enable function + * @param wmi_handle : handle to WMI. + * @param param : pointer to hold wow enable parameter + * @mac_id: radio context + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_wow_enable_send(void *wmi_hdl, + struct wow_cmd_params *param, + uint8_t mac_id) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_wow_enable_cmd) + return wmi_handle->ops->send_wow_enable_cmd(wmi_handle, param, + mac_id); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_wow_wakeup_send() - WMI wow wakeup function + * @param wmi_hdl : handle to WMI. + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_wow_wakeup_send(void *wmi_hdl) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_wow_wakeup_cmd) + return wmi_handle->ops->send_wow_wakeup_cmd(wmi_handle); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_wow_add_wakeup_event_send() - WMI wow wakeup function + * @param wmi_handle : handle to WMI. + * @param: pointer to wow wakeup event parameter structure + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_wow_add_wakeup_event_send(void *wmi_hdl, + struct wow_add_wakeup_params *param) +{ + wmi_unified_t wmi = (wmi_unified_t) wmi_hdl; + + if (wmi->ops->send_wow_add_wakeup_event_cmd) + return wmi->ops->send_wow_add_wakeup_event_cmd(wmi, + param); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_wow_add_wakeup_pattern_send() - WMI wow wakeup pattern function + * @param wmi_handle : handle to WMI. + * @param: pointer to wow wakeup pattern parameter structure + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_wow_add_wakeup_pattern_send(void *wmi_hdl, + struct wow_add_wakeup_pattern_params *param) +{ + wmi_unified_t wmi = (wmi_unified_t) wmi_hdl; + + if (wmi->ops->send_wow_add_wakeup_pattern_cmd) + return wmi->ops->send_wow_add_wakeup_pattern_cmd(wmi, param); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_wow_remove_wakeup_pattern_send() - WMI wow wakeup pattern function + * @param wmi_handle : handle to WMI. + * @param: pointer to wow wakeup pattern parameter structure + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_wow_remove_wakeup_pattern_send(void *wmi_hdl, + struct wow_remove_wakeup_pattern_params *param) +{ + wmi_unified_t wmi = (wmi_unified_t) wmi_hdl; + + if (wmi->ops->send_wow_remove_wakeup_pattern_cmd) + return wmi->ops->send_wow_remove_wakeup_pattern_cmd(wmi, param); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_ap_ps_cmd_send() - set ap powersave parameters + * @wma_ctx: wma context + * @peer_addr: peer mac address + * @param: pointer to ap_ps parameter structure + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_ap_ps_cmd_send(void *wmi_hdl, + uint8_t *peer_addr, + struct ap_ps_params *param) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_set_ap_ps_param_cmd) + return wmi_handle->ops->send_set_ap_ps_param_cmd(wmi_handle, + peer_addr, + param); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_sta_ps_cmd_send() - set sta powersave parameters + * @wma_ctx: wma context + * @peer_addr: peer mac address + * @param: pointer to sta_ps parameter structure + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_sta_ps_cmd_send(void *wmi_hdl, + struct sta_ps_params *param) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_set_sta_ps_param_cmd) + return wmi_handle->ops->send_set_sta_ps_param_cmd(wmi_handle, + param); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_crash_inject() - inject fw crash + * @wma_handle: wma handle + * @param: ponirt to crash inject paramter structure + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_crash_inject(void *wmi_hdl, + struct crash_inject *param) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_crash_inject_cmd) + return wmi_handle->ops->send_crash_inject_cmd(wmi_handle, + param); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_dbglog_cmd_send() - set debug log level + * @param wmi_handle : handle to WMI. + * @param param : pointer to hold dbglog level parameter + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS +wmi_unified_dbglog_cmd_send(void *wmi_hdl, + struct dbglog_params *dbglog_param) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_dbglog_cmd) + return wmi_handle->ops->send_dbglog_cmd(wmi_handle, + dbglog_param); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_vdev_set_param_send() - WMI vdev set parameter function + * @param wmi_handle : handle to WMI. + * @param macaddr : MAC address + * @param param : pointer to hold vdev set parameter + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_vdev_set_param_send(void *wmi_hdl, + struct vdev_set_params *param) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_vdev_set_param_cmd) + return wmi_handle->ops->send_vdev_set_param_cmd(wmi_handle, + param); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_stats_request_send() - WMI request stats function + * @param wmi_handle : handle to WMI. + * @param macaddr : MAC address + * @param param : pointer to hold stats request parameter + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_stats_request_send(void *wmi_hdl, + uint8_t macaddr[IEEE80211_ADDR_LEN], + struct stats_request_params *param) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_stats_request_cmd) + return wmi_handle->ops->send_stats_request_cmd(wmi_handle, + macaddr, param); + + return QDF_STATUS_E_FAILURE; +} + +#ifndef WMI_NON_TLV_SUPPORT +/** + * wmi_unified_packet_log_enable_send() - WMI request stats function + * @param wmi_handle : handle to WMI. + * @param macaddr : MAC address + * @param param : pointer to hold stats request parameter + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_packet_log_enable_send(void *wmi_hdl, + uint8_t macaddr[IEEE80211_ADDR_LEN], + struct packet_enable_params *param) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_packet_log_enable_cmd) + return wmi_handle->ops->send_packet_log_enable_cmd(wmi_handle, + macaddr, param); + + return QDF_STATUS_E_FAILURE; +} +#else +/** + * wmi_unified_packet_log_enable_send() - WMI request stats function + * @param wmi_handle : handle to WMI. + * @param macaddr : MAC address + * @param param : pointer to hold stats request parameter + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_packet_log_enable_send(void *wmi_hdl, + WMI_HOST_PKTLOG_EVENT PKTLOG_EVENT) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_packet_log_enable_cmd) + return wmi_handle->ops->send_packet_log_enable_cmd(wmi_handle, + PKTLOG_EVENT); + + return QDF_STATUS_E_FAILURE; +} + +#endif +/** + * wmi_unified_packet_log_disable__send() - WMI pktlog disable function + * @param wmi_handle : handle to WMI. + * @param PKTLOG_EVENT : packet log event + * @return QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_packet_log_disable_send(void *wmi_hdl) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_packet_log_disable_cmd) + return wmi_handle->ops->send_packet_log_disable_cmd(wmi_handle); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_beacon_send_cmd() - WMI beacon send function + * @param wmi_handle : handle to WMI. + * @param macaddr : MAC address + * @param param : pointer to hold beacon send cmd parameter + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_beacon_send_cmd(void *wmi_hdl, + struct beacon_params *param) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_beacon_send_cmd) + return wmi_handle->ops->send_beacon_send_cmd(wmi_handle, + param); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_beacon_tmpl_send_cmd() - WMI beacon send function + * @param wmi_handle : handle to WMI. + * @param macaddr : MAC address + * @param param : pointer to hold beacon send cmd parameter + * + * @return QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_beacon_tmpl_send_cmd(void *wmi_hdl, + struct beacon_tmpl_params *param) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_beacon_tmpl_send_cmd) + return wmi_handle->ops->send_beacon_tmpl_send_cmd(wmi_handle, + param); + + return QDF_STATUS_E_FAILURE; +} +/** + * wmi_unified_peer_assoc_send() - WMI peer assoc function + * @param wmi_handle : handle to WMI. + * @param macaddr : MAC address + * @param param : pointer to peer assoc parameter + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_peer_assoc_send(void *wmi_hdl, + struct peer_assoc_params *param) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_peer_assoc_cmd) + return wmi_handle->ops->send_peer_assoc_cmd(wmi_handle, + param); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_scan_start_cmd_send() - WMI scan start function + * @param wmi_handle : handle to WMI. + * @param macaddr : MAC address + * @param param : pointer to hold scan start cmd parameter + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_scan_start_cmd_send(void *wmi_hdl, + struct scan_start_params *param) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_scan_start_cmd) + return wmi_handle->ops->send_scan_start_cmd(wmi_handle, + param); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_scan_stop_cmd_send() - WMI scan start function + * @param wmi_handle : handle to WMI. + * @param macaddr : MAC address + * @param param : pointer to hold scan start cmd parameter + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_scan_stop_cmd_send(void *wmi_hdl, + struct scan_stop_params *param) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_scan_stop_cmd) + return wmi_handle->ops->send_scan_stop_cmd(wmi_handle, + param); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_scan_chan_list_cmd_send() - WMI scan channel list function + * @param wmi_handle : handle to WMI. + * @param macaddr : MAC address + * @param param : pointer to hold scan channel list parameter + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_scan_chan_list_cmd_send(void *wmi_hdl, + struct scan_chan_list_params *param) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_scan_chan_list_cmd) + return wmi_handle->ops->send_scan_chan_list_cmd(wmi_handle, + param); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_mgmt_unified_cmd_send() - management cmd over wmi layer + * @wmi_hdl : handle to WMI. + * @param : pointer to hold mgmt cmd parameter + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_mgmt_unified_cmd_send(void *wmi_hdl, + struct wmi_mgmt_params *param) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_mgmt_cmd) + return wmi_handle->ops->send_mgmt_cmd(wmi_handle, + param); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_modem_power_state() - set modem power state to fw + * @wmi_hdl: wmi handle + * @param_value: parameter value + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_modem_power_state(void *wmi_hdl, + uint32_t param_value) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_modem_power_state_cmd) + return wmi_handle->ops->send_modem_power_state_cmd(wmi_handle, + param_value); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_set_sta_ps_mode() - set sta powersave params in fw + * @wmi_hdl: wmi handle + * @vdev_id: vdev id + * @val: value + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure. + */ +QDF_STATUS wmi_unified_set_sta_ps_mode(void *wmi_hdl, + uint32_t vdev_id, uint8_t val) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_set_sta_ps_mode_cmd) + return wmi_handle->ops->send_set_sta_ps_mode_cmd(wmi_handle, + vdev_id, val); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_set_mimops() - set MIMO powersave + * @wmi_hdl: wmi handle + * @vdev_id: vdev id + * @value: value + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure. + */ +QDF_STATUS wmi_unified_set_mimops(void *wmi_hdl, uint8_t vdev_id, int value) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_set_mimops_cmd) + return wmi_handle->ops->send_set_mimops_cmd(wmi_handle, + vdev_id, value); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_set_smps_params() - set smps params + * @wmi_hdl: wmi handle + * @vdev_id: vdev id + * @value: value + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure. + */ +QDF_STATUS wmi_unified_set_smps_params(void *wmi_hdl, uint8_t vdev_id, + int value) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_set_smps_params_cmd) + return wmi_handle->ops->send_set_smps_params_cmd(wmi_handle, + vdev_id, value); + + return QDF_STATUS_E_FAILURE; +} + + +/** + * wmi_set_p2pgo_oppps_req() - send p2p go opp power save request to fw + * @wmi_hdl: wmi handle + * @opps: p2p opp power save parameters + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_set_p2pgo_oppps_req(void *wmi_hdl, + struct p2p_ps_params *oppps) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_set_p2pgo_oppps_req_cmd) + return wmi_handle->ops->send_set_p2pgo_oppps_req_cmd(wmi_handle, + oppps); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_set_p2pgo_noa_req_cmd() - send p2p go noa request to fw + * @wmi_hdl: wmi handle + * @noa: p2p power save parameters + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_set_p2pgo_noa_req_cmd(void *wmi_hdl, + struct p2p_ps_params *noa) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_set_p2pgo_noa_req_cmd) + return wmi_handle->ops->send_set_p2pgo_noa_req_cmd(wmi_handle, + noa); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_get_temperature() - get pdev temperature req + * @wmi_hdl: wmi handle + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure. + */ +QDF_STATUS wmi_unified_get_temperature(void *wmi_hdl) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_get_temperature_cmd) + return wmi_handle->ops->send_get_temperature_cmd(wmi_handle); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_set_sta_uapsd_auto_trig_cmd() - set uapsd auto trigger command + * @wmi_hdl: wmi handle + * @end_set_sta_ps_mode_cmd: cmd paramter strcture + * + * This function sets the trigger + * uapsd params such as service interval, delay interval + * and suspend interval which will be used by the firmware + * to send trigger frames periodically when there is no + * traffic on the transmit side. + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure. + */ +QDF_STATUS +wmi_unified_set_sta_uapsd_auto_trig_cmd(void *wmi_hdl, + struct sta_uapsd_trig_params *param) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_set_sta_uapsd_auto_trig_cmd) + return wmi_handle->ops->send_set_sta_uapsd_auto_trig_cmd(wmi_handle, + param); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_ocb_start_timing_advert() - start sending the timing advertisement + * frames on a channel + * @wmi_handle: pointer to the wmi handle + * @timing_advert: pointer to the timing advertisement struct + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_ocb_start_timing_advert(void *wmi_hdl, + struct ocb_timing_advert_param *timing_advert) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_ocb_start_timing_advert_cmd) + return wmi_handle->ops->send_ocb_start_timing_advert_cmd(wmi_handle, + timing_advert); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_ocb_stop_timing_advert() - stop sending the timing advertisement + * frames on a channel + * @wmi_handle: pointer to the wmi handle + * @timing_advert: pointer to the timing advertisement struct + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_ocb_stop_timing_advert(void *wmi_hdl, + struct ocb_timing_advert_param *timing_advert) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_ocb_stop_timing_advert_cmd) + return wmi_handle->ops->send_ocb_stop_timing_advert_cmd(wmi_handle, + timing_advert); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_ocb_set_utc_time_cmd() - get ocb tsf timer val + * @wmi_handle: pointer to the wmi handle + * @vdev_id: vdev id + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_ocb_set_utc_time_cmd(void *wmi_hdl, + struct ocb_utc_param *utc) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_ocb_set_utc_time_cmd) + return wmi_handle->ops->send_ocb_set_utc_time_cmd(wmi_handle, + utc); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_ocb_get_tsf_timer() - get ocb tsf timer val + * @wmi_handle: pointer to the wmi handle + * @vdev_id: vdev id + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_ocb_get_tsf_timer(void *wmi_hdl, + uint8_t vdev_id) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_ocb_get_tsf_timer_cmd) + return wmi_handle->ops->send_ocb_get_tsf_timer_cmd(wmi_handle, + vdev_id); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_dcc_get_stats_cmd() - get the DCC channel stats + * @wmi_handle: pointer to the wmi handle + * @get_stats_param: pointer to the dcc stats + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_dcc_get_stats_cmd(void *wmi_hdl, + struct dcc_get_stats_param *get_stats_param) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_dcc_get_stats_cmd) + return wmi_handle->ops->send_dcc_get_stats_cmd(wmi_handle, + get_stats_param); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_dcc_clear_stats() - command to clear the DCC stats + * @wmi_handle: pointer to the wmi handle + * @clear_stats_param: parameters to the command + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_dcc_clear_stats(void *wmi_hdl, + uint32_t vdev_id, uint32_t dcc_stats_bitmap) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_dcc_clear_stats_cmd) + return wmi_handle->ops->send_dcc_clear_stats_cmd(wmi_handle, + vdev_id, dcc_stats_bitmap); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_dcc_update_ndl() - command to update the NDL data + * @wmi_handle: pointer to the wmi handle + * @update_ndl_param: pointer to the request parameters + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failures + */ +QDF_STATUS wmi_unified_dcc_update_ndl(void *wmi_hdl, + struct dcc_update_ndl_param *update_ndl_param) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_dcc_update_ndl_cmd) + return wmi_handle->ops->send_dcc_update_ndl_cmd(wmi_handle, + update_ndl_param); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_ocb_set_config() - send the OCB config to the FW + * @wmi_handle: pointer to the wmi handle + * @config: the OCB configuration + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failures + */ +QDF_STATUS wmi_unified_ocb_set_config(void *wmi_hdl, + struct ocb_config_param *config, uint32_t *ch_mhz) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_ocb_set_config_cmd) + return wmi_handle->ops->send_ocb_set_config_cmd(wmi_handle, + config, ch_mhz); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_set_enable_disable_mcc_adaptive_scheduler_cmd() - control mcc scheduler + * @wmi_handle: wmi handle + * @mcc_adaptive_scheduler: enable/disable + * + * This function enable/disable mcc adaptive scheduler in fw. + * + * Return: QDF_STATUS_SUCCESS for sucess or error code + */ +QDF_STATUS wmi_unified_set_enable_disable_mcc_adaptive_scheduler_cmd( + void *wmi_hdl, uint32_t mcc_adaptive_scheduler, + uint32_t pdev_id) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_set_enable_disable_mcc_adaptive_scheduler_cmd) + return wmi_handle->ops->send_set_enable_disable_mcc_adaptive_scheduler_cmd(wmi_handle, + mcc_adaptive_scheduler, pdev_id); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_set_mcc_channel_time_latency_cmd() - set MCC channel time latency + * @wmi: wmi handle + * @mcc_channel: mcc channel + * @mcc_channel_time_latency: MCC channel time latency. + * + * Currently used to set time latency for an MCC vdev/adapter using operating + * channel of it and channel number. The info is provided run time using + * iwpriv command: iwpriv setMccLatency . + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_set_mcc_channel_time_latency_cmd(void *wmi_hdl, + uint32_t mcc_channel_freq, uint32_t mcc_channel_time_latency) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_set_mcc_channel_time_latency_cmd) + return wmi_handle->ops->send_set_mcc_channel_time_latency_cmd(wmi_handle, + mcc_channel_freq, + mcc_channel_time_latency); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_set_mcc_channel_time_quota_cmd() - set MCC channel time quota + * @wmi: wmi handle + * @adapter_1_chan_number: adapter 1 channel number + * @adapter_1_quota: adapter 1 quota + * @adapter_2_chan_number: adapter 2 channel number + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_set_mcc_channel_time_quota_cmd(void *wmi_hdl, + uint32_t adapter_1_chan_freq, + uint32_t adapter_1_quota, uint32_t adapter_2_chan_freq) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_set_mcc_channel_time_quota_cmd) + return wmi_handle->ops->send_set_mcc_channel_time_quota_cmd(wmi_handle, + adapter_1_chan_freq, + adapter_1_quota, + adapter_2_chan_freq); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_set_thermal_mgmt_cmd() - set thermal mgmt command to fw + * @wmi_handle: Pointer to wmi handle + * @thermal_info: Thermal command information + * + * This function sends the thermal management command + * to the firmware + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_set_thermal_mgmt_cmd(void *wmi_hdl, + struct thermal_cmd_params *thermal_info) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_set_thermal_mgmt_cmd) + return wmi_handle->ops->send_set_thermal_mgmt_cmd(wmi_handle, + thermal_info); + + return QDF_STATUS_E_FAILURE; +} + + +/** + * wmi_unified_lro_config_cmd() - process the LRO config command + * @wmi: Pointer to wmi handle + * @wmi_lro_cmd: Pointer to LRO configuration parameters + * + * This function sends down the LRO configuration parameters to + * the firmware to enable LRO, sets the TCP flags and sets the + * seed values for the toeplitz hash generation + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_lro_config_cmd(void *wmi_hdl, + struct wmi_lro_config_cmd_t *wmi_lro_cmd) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_lro_config_cmd) + return wmi_handle->ops->send_lro_config_cmd(wmi_handle, + wmi_lro_cmd); + + return QDF_STATUS_E_FAILURE; +} + +#ifndef WMI_NON_TLV_SUPPORT +/** + * wmi_unified_peer_rate_report_cmd() - process the peer rate report command + * @wmi_hdl: Pointer to wmi handle + * @rate_report_params: Pointer to peer rate report parameters + * + * + * Return: QDF_STATUS_SUCCESS for success otherwise failure + */ +QDF_STATUS wmi_unified_peer_rate_report_cmd(void *wmi_hdl, + struct wmi_peer_rate_report_params *rate_report_params) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_peer_rate_report_cmd) + return wmi_handle->ops->send_peer_rate_report_cmd(wmi_handle, + rate_report_params); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_bcn_buf_ll_cmd() - prepare and send beacon buffer to fw for LL + * @wmi_hdl: wmi handle + * @param: bcn ll cmd parameter + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_bcn_buf_ll_cmd(void *wmi_hdl, + wmi_bcn_send_from_host_cmd_fixed_param *param) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_bcn_buf_ll_cmd) + return wmi_handle->ops->send_bcn_buf_ll_cmd(wmi_handle, + param); + + return QDF_STATUS_E_FAILURE; +} +#endif + +/** + * wmi_unified_set_sta_sa_query_param_cmd() - set sta sa query parameters + * @wmi_hdl: wmi handle + * @vdev_id: vdev id + * @max_retries: max retries + * @retry_interval: retry interval + * This function sets sta query related parameters in fw. + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ + +QDF_STATUS wmi_unified_set_sta_sa_query_param_cmd(void *wmi_hdl, + uint8_t vdev_id, uint32_t max_retries, + uint32_t retry_interval) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_set_sta_sa_query_param_cmd) + return wmi_handle->ops->send_set_sta_sa_query_param_cmd(wmi_handle, + vdev_id, max_retries, + retry_interval); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_set_sta_keep_alive_cmd() - set sta keep alive parameters + * @wmi_hdl: wmi handle + * @params: sta keep alive parameter + * + * This function sets keep alive related parameters in fw. + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_set_sta_keep_alive_cmd(void *wmi_hdl, + struct sta_params *params) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_set_sta_keep_alive_cmd) + return wmi_handle->ops->send_set_sta_keep_alive_cmd(wmi_handle, + params); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_vdev_set_gtx_cfg_cmd() - set GTX params + * @wmi_hdl: wmi handle + * @if_id: vdev id + * @gtx_info: GTX config params + * + * This function set GTX related params in firmware. + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_vdev_set_gtx_cfg_cmd(void *wmi_hdl, uint32_t if_id, + struct wmi_gtx_config *gtx_info) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_vdev_set_gtx_cfg_cmd) + return wmi_handle->ops->send_vdev_set_gtx_cfg_cmd(wmi_handle, + if_id, gtx_info); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_process_update_edca_param() - update EDCA params + * @wmi_hdl: wmi handle + * @edca_params: edca parameters + * + * This function updates EDCA parameters to the target + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +#ifndef WMI_NON_TLV_SUPPORT +QDF_STATUS wmi_unified_process_update_edca_param(void *wmi_hdl, + uint8_t vdev_id, + wmi_wmm_vparams gwmm_param[WMI_MAX_NUM_AC]) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_process_update_edca_param_cmd) + return wmi_handle->ops->send_process_update_edca_param_cmd(wmi_handle, + vdev_id, gwmm_param); + + return QDF_STATUS_E_FAILURE; +} +#endif + +/** + * wmi_unified_probe_rsp_tmpl_send_cmd() - send probe response template to fw + * @wmi_hdl: wmi handle + * @vdev_id: vdev id + * @probe_rsp_info: probe response info + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_probe_rsp_tmpl_send_cmd(void *wmi_hdl, + uint8_t vdev_id, + struct wmi_probe_resp_params *probe_rsp_info, + uint8_t *frm) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_probe_rsp_tmpl_send_cmd) + return wmi_handle->ops->send_probe_rsp_tmpl_send_cmd(wmi_handle, + vdev_id, probe_rsp_info, + frm); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_setup_install_key_cmd - send key to install to fw + * @wmi_hdl: wmi handle + * @key_params: key parameters + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_setup_install_key_cmd(void *wmi_hdl, + struct set_key_params *key_params) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_setup_install_key_cmd) + return wmi_handle->ops->send_setup_install_key_cmd(wmi_handle, + key_params); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_p2p_go_set_beacon_ie_cmd() - set beacon IE for p2p go + * @wma_handle: wma handle + * @vdev_id: vdev id + * @p2p_ie: p2p IE + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_p2p_go_set_beacon_ie_cmd(void *wmi_hdl, + A_UINT32 vdev_id, uint8_t *p2p_ie) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_p2p_go_set_beacon_ie_cmd) + return wmi_handle->ops->send_p2p_go_set_beacon_ie_cmd(wmi_handle, + vdev_id, p2p_ie); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_set_gateway_params_cmd() - set gateway parameters + * @wmi_hdl: wmi handle + * @req: gateway parameter update request structure + * + * This function reads the incoming @req and fill in the destination + * WMI structure and sends down the gateway configs down to the firmware + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failures; + * error number otherwise + */ +QDF_STATUS wmi_unified_set_gateway_params_cmd(void *wmi_hdl, + struct gateway_update_req_param *req) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_set_gateway_params_cmd) + return wmi_handle->ops->send_set_gateway_params_cmd(wmi_handle, + req); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_set_rssi_monitoring_cmd() - set rssi monitoring + * @wmi_hdl: wmi handle + * @req: rssi monitoring request structure + * + * This function reads the incoming @req and fill in the destination + * WMI structure and send down the rssi monitoring configs down to the firmware + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failures; + * error number otherwise + */ +QDF_STATUS wmi_unified_set_rssi_monitoring_cmd(void *wmi_hdl, + struct rssi_monitor_param *req) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_set_rssi_monitoring_cmd) + return wmi_handle->ops->send_set_rssi_monitoring_cmd(wmi_handle, + req); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_scan_probe_setoui_cmd() - set scan probe OUI + * @wmi_hdl: wmi handle + * @psetoui: OUI parameters + * + * set scan probe OUI parameters in firmware + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_scan_probe_setoui_cmd(void *wmi_hdl, + struct scan_mac_oui *psetoui) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_scan_probe_setoui_cmd) + return wmi_handle->ops->send_scan_probe_setoui_cmd(wmi_handle, + psetoui); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_reset_passpoint_network_list_cmd() - reset passpoint network list + * @wmi_hdl: wmi handle + * @req: passpoint network request structure + * + * This function sends down WMI command with network id set to wildcard id. + * firmware shall clear all the config entries + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_reset_passpoint_network_list_cmd(void *wmi_hdl, + struct wifi_passpoint_req_param *req) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_reset_passpoint_network_list_cmd) + return wmi_handle->ops->send_reset_passpoint_network_list_cmd(wmi_handle, + req); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_set_passpoint_network_list_cmd() - set passpoint network list + * @wmi_hdl: wmi handle + * @req: passpoint network request structure + * + * This function reads the incoming @req and fill in the destination + * WMI structure and send down the passpoint configs down to the firmware + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_set_passpoint_network_list_cmd(void *wmi_hdl, + struct wifi_passpoint_req_param *req) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_set_passpoint_network_list_cmd) + return wmi_handle->ops->send_set_passpoint_network_list_cmd(wmi_handle, + req); + + return QDF_STATUS_E_FAILURE; +} + +/** wmi_unified_set_epno_network_list_cmd() - set epno network list + * @wmi_hdl: wmi handle + * @req: epno config params request structure + * + * This function reads the incoming epno config request structure + * and constructs the WMI message to the firmware. + * + * Returns: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failures, + * error number otherwise + */ +QDF_STATUS wmi_unified_set_epno_network_list_cmd(void *wmi_hdl, + struct wifi_enhanched_pno_params *req) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_set_epno_network_list_cmd) + return wmi_handle->ops->send_set_epno_network_list_cmd(wmi_handle, + req); + + return QDF_STATUS_E_FAILURE; +} + +#ifndef WMI_NON_TLV_SUPPORT +/** + * wmi_unified_roam_scan_offload_mode_cmd() - set roam scan parameters + * @wmi_hdl: wmi handle + * @scan_cmd_fp: scan related parameters + * @roam_req: roam related parameters + * + * This function reads the incoming @roam_req and fill in the destination + * WMI structure and send down the roam scan configs down to the firmware + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_roam_scan_offload_mode_cmd(void *wmi_hdl, + wmi_start_scan_cmd_fixed_param *scan_cmd_fp, + struct roam_offload_scan_params *roam_req) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_roam_scan_offload_mode_cmd) + return wmi_handle->ops->send_roam_scan_offload_mode_cmd( + wmi_handle, scan_cmd_fp, roam_req); + + return QDF_STATUS_E_FAILURE; +} +#endif + +/** + * wmi_unified_roam_scan_offload_rssi_thresh_cmd() - set roam scan rssi + * parameters + * @wmi_hdl: wmi handle + * @roam_req: roam rssi related parameters + * + * This function reads the incoming @roam_req and fill in the destination + * WMI structure and send down the roam scan rssi configs down to the firmware + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_roam_scan_offload_rssi_thresh_cmd(void *wmi_hdl, + struct roam_offload_scan_rssi_params + *roam_req) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_roam_scan_offload_rssi_thresh_cmd) + return wmi_handle->ops->send_roam_scan_offload_rssi_thresh_cmd( + wmi_handle, roam_req); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_roam_scan_filter_cmd() - send roam scan whitelist, + * blacklist and preferred list + * @wmi_hdl: wmi handle + * @roam_req: roam scan lists related parameters + * + * This function reads the incoming @roam_req and fill in the destination + * WMI structure and send down the different roam scan lists down to the fw + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_roam_scan_filter_cmd(void *wmi_hdl, + struct roam_scan_filter_params *roam_req) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_roam_scan_filter_cmd) + return wmi_handle->ops->send_roam_scan_filter_cmd( + wmi_handle, roam_req); + + return QDF_STATUS_E_FAILURE; +} + +/** wmi_unified_ipa_offload_control_cmd() - ipa offload control parameter + * @wmi_hdl: wmi handle + * @ipa_offload: ipa offload control parameter + * + * Returns: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failures, + * error number otherwise + */ +QDF_STATUS wmi_unified_ipa_offload_control_cmd(void *wmi_hdl, + struct ipa_offload_control_params *ipa_offload) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_ipa_offload_control_cmd) + return wmi_handle->ops->send_ipa_offload_control_cmd(wmi_handle, + ipa_offload); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_extscan_get_capabilities_cmd() - extscan get capabilities + * @wmi_hdl: wmi handle + * @pgetcapab: get capabilities params + * + * This function send request to fw to get extscan capabilities. + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_extscan_get_capabilities_cmd(void *wmi_hdl, + struct extscan_capabilities_params *pgetcapab) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_extscan_get_capabilities_cmd) + return wmi_handle->ops->send_extscan_get_capabilities_cmd(wmi_handle, + pgetcapab); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_extscan_get_cached_results_cmd() - extscan get cached results + * @wmi_hdl: wmi handle + * @pcached_results: cached results parameters + * + * This function send request to fw to get cached results. + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_extscan_get_cached_results_cmd(void *wmi_hdl, + struct extscan_cached_result_params *pcached_results) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_extscan_get_cached_results_cmd) + return wmi_handle->ops->send_extscan_get_cached_results_cmd(wmi_handle, + pcached_results); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_extscan_stop_change_monitor_cmd() - send stop change monitor cmd + * @wmi_hdl: wmi handle + * @reset_req: Reset change request params + * + * This function sends stop change monitor request to fw. + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_extscan_stop_change_monitor_cmd(void *wmi_hdl, + struct extscan_capabilities_reset_params *reset_req) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_extscan_stop_change_monitor_cmd) + return wmi_handle->ops->send_extscan_stop_change_monitor_cmd(wmi_handle, + reset_req); + + return QDF_STATUS_E_FAILURE; +} + + + +/** + * wmi_unified_extscan_start_change_monitor_cmd() - start change monitor cmd + * @wmi_hdl: wmi handle + * @psigchange: change monitor request params + * + * This function sends start change monitor request to fw. + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_extscan_start_change_monitor_cmd(void *wmi_hdl, + struct extscan_set_sig_changereq_params * + psigchange) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_extscan_start_change_monitor_cmd) + return wmi_handle->ops->send_extscan_start_change_monitor_cmd(wmi_handle, + psigchange); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_extscan_stop_hotlist_monitor_cmd() - stop hotlist monitor + * @wmi_hdl: wmi handle + * @photlist_reset: hotlist reset params + * + * This function configures hotlist monitor to stop in fw. + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_extscan_stop_hotlist_monitor_cmd(void *wmi_hdl, + struct extscan_bssid_hotlist_reset_params *photlist_reset) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_extscan_stop_hotlist_monitor_cmd) + return wmi_handle->ops->send_extscan_stop_hotlist_monitor_cmd(wmi_handle, + photlist_reset); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_stop_extscan_cmd() - stop extscan command to fw. + * @wmi_hdl: wmi handle + * @pstopcmd: stop scan command request params + * + * This function sends stop extscan request to fw. + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure. + */ +QDF_STATUS wmi_unified_stop_extscan_cmd(void *wmi_hdl, + struct extscan_stop_req_params *pstopcmd) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_stop_extscan_cmd) + return wmi_handle->ops->send_stop_extscan_cmd(wmi_handle, + pstopcmd); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_start_extscan_cmd() - start extscan command to fw. + * @wmi_hdl: wmi handle + * @pstart: scan command request params + * + * This function sends start extscan request to fw. + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure. + */ +QDF_STATUS wmi_unified_start_extscan_cmd(void *wmi_hdl, + struct wifi_scan_cmd_req_params *pstart) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_start_extscan_cmd) + return wmi_handle->ops->send_start_extscan_cmd(wmi_handle, + pstart); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_plm_stop_cmd() - plm stop request + * @wmi_hdl: wmi handle + * @plm: plm request parameters + * + * This function request FW to stop PLM. + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_plm_stop_cmd(void *wmi_hdl, + const struct plm_req_params *plm) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_plm_stop_cmd) + return wmi_handle->ops->send_plm_stop_cmd(wmi_handle, + plm); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_plm_start_cmd() - plm start request + * @wmi_hdl: wmi handle + * @plm: plm request parameters + * + * This function request FW to start PLM. + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_plm_start_cmd(void *wmi_hdl, + const struct plm_req_params *plm, + uint32_t *gchannel_list) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_plm_start_cmd) + return wmi_handle->ops->send_plm_start_cmd(wmi_handle, + plm, gchannel_list); + + return QDF_STATUS_E_FAILURE; +} + +/** + * send_pno_stop_cmd() - PNO stop request + * @wmi_hdl: wmi handle + * @vdev_id: vdev id + * + * This function request FW to stop ongoing PNO operation. + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_pno_stop_cmd(void *wmi_hdl, uint8_t vdev_id) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_pno_stop_cmd) + return wmi_handle->ops->send_pno_stop_cmd(wmi_handle, + vdev_id); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_pno_start_cmd() - PNO start request + * @wmi_hdl: wmi handle + * @pno: PNO request + * @gchannel_freq_list: channel frequency list + * + * This function request FW to start PNO request. + * Request: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +#ifdef FEATURE_WLAN_SCAN_PNO +QDF_STATUS wmi_unified_pno_start_cmd(void *wmi_hdl, + struct pno_scan_req_params *pno, + uint32_t *gchannel_freq_list) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_pno_start_cmd) + return wmi_handle->ops->send_pno_start_cmd(wmi_handle, + pno, gchannel_freq_list); + + return QDF_STATUS_E_FAILURE; +} +#endif + +/* wmi_unified_set_ric_req_cmd() - set ric request element + * @wmi_hdl: wmi handle + * @msg: message + * @is_add_ts: is addts required + * + * This function sets ric request element for 11r roaming. + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_set_ric_req_cmd(void *wmi_hdl, void *msg, + uint8_t is_add_ts) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_set_ric_req_cmd) + return wmi_handle->ops->send_set_ric_req_cmd(wmi_handle, msg, + is_add_ts); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_process_ll_stats_clear_cmd() - clear link layer stats + * @wmi_hdl: wmi handle + * @clear_req: ll stats clear request command params + * @addr: mac address + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_process_ll_stats_clear_cmd(void *wmi_hdl, + const struct ll_stats_clear_params *clear_req, + uint8_t addr[IEEE80211_ADDR_LEN]) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_process_ll_stats_clear_cmd) + return wmi_handle->ops->send_process_ll_stats_clear_cmd(wmi_handle, + clear_req, addr); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_process_ll_stats_get_cmd() - link layer stats get request + * @wmi_hdl:wmi handle + * @get_req:ll stats get request command params + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_process_ll_stats_get_cmd(void *wmi_hdl, + const struct ll_stats_get_params *get_req, + uint8_t addr[IEEE80211_ADDR_LEN]) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_process_ll_stats_get_cmd) + return wmi_handle->ops->send_process_ll_stats_get_cmd(wmi_handle, + get_req, addr); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_get_stats_cmd() - get stats request + * @wmi_hdl: wma handle + * @get_stats_param: stats params + * @addr: mac address + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_get_stats_cmd(void *wmi_hdl, + struct pe_stats_req *get_stats_param, + uint8_t addr[IEEE80211_ADDR_LEN]) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_get_stats_cmd) + return wmi_handle->ops->send_get_stats_cmd(wmi_handle, + get_stats_param, addr); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_congestion_request_cmd() - send request to fw to get CCA + * @wmi_hdl: wma handle + * @vdev_id: vdev id + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_congestion_request_cmd(void *wmi_hdl, + uint8_t vdev_id) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_congestion_cmd) + return wmi_handle->ops->send_congestion_cmd(wmi_handle, + vdev_id); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_process_ll_stats_set_cmd() - link layer stats set request + * @wmi_handle: wmi handle + * @set_req: ll stats set request command params + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_process_ll_stats_set_cmd(void *wmi_hdl, + const struct ll_stats_set_params *set_req) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_process_ll_stats_set_cmd) + return wmi_handle->ops->send_process_ll_stats_set_cmd(wmi_handle, + set_req); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_snr_request_cmd() - send request to fw to get RSSI stats + * @wmi_handle: wmi handle + * @rssi_req: get RSSI request + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_snr_request_cmd(void *wmi_hdl) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_snr_request_cmd) + return wmi_handle->ops->send_snr_request_cmd(wmi_handle); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_snr_cmd() - get RSSI from fw + * @wmi_handle: wmi handle + * @vdev_id: vdev id + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_snr_cmd(void *wmi_hdl, uint8_t vdev_id) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_snr_cmd) + return wmi_handle->ops->send_snr_cmd(wmi_handle, + vdev_id); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_link_status_req_cmd() - process link status request from UMAC + * @wmi_handle: wmi handle + * @link_status: get link params + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_link_status_req_cmd(void *wmi_hdl, + struct link_status_params *link_status) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_link_status_req_cmd) + return wmi_handle->ops->send_link_status_req_cmd(wmi_handle, + link_status); + + return QDF_STATUS_E_FAILURE; +} + +#ifdef FEATURE_WLAN_LPHB + +/** + * wmi_unified_lphb_config_hbenable_cmd() - enable command of LPHB configuration requests + * @wmi_handle: wmi handle + * @lphb_conf_req: configuration info + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_lphb_config_hbenable_cmd(void *wmi_hdl, + wmi_hb_set_enable_cmd_fixed_param *params) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_lphb_config_hbenable_cmd) + return wmi_handle->ops->send_lphb_config_hbenable_cmd(wmi_handle, + params); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_lphb_config_tcp_params_cmd() - set tcp params of LPHB configuration requests + * @wmi_handle: wmi handle + * @lphb_conf_req: lphb config request + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_lphb_config_tcp_params_cmd(void *wmi_hdl, + wmi_hb_set_tcp_params_cmd_fixed_param *lphb_conf_req) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_lphb_config_tcp_params_cmd) + return wmi_handle->ops->send_lphb_config_tcp_params_cmd(wmi_handle, + lphb_conf_req); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_lphb_config_tcp_pkt_filter_cmd() - configure tcp packet filter command of LPHB + * @wmi_handle: wmi handle + * @lphb_conf_req: lphb config request + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_lphb_config_tcp_pkt_filter_cmd(void *wmi_hdl, + wmi_hb_set_tcp_pkt_filter_cmd_fixed_param *g_hb_tcp_filter_fp) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_lphb_config_tcp_pkt_filter_cmd) + return wmi_handle->ops->send_lphb_config_tcp_pkt_filter_cmd(wmi_handle, + g_hb_tcp_filter_fp); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_lphb_config_udp_params_cmd() - configure udp param command of LPHB + * @wmi_handle: wmi handle + * @lphb_conf_req: lphb config request + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_lphb_config_udp_params_cmd(void *wmi_hdl, + wmi_hb_set_udp_params_cmd_fixed_param *lphb_conf_req) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_lphb_config_udp_params_cmd) + return wmi_handle->ops->send_lphb_config_udp_params_cmd(wmi_handle, + lphb_conf_req); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_lphb_config_udp_pkt_filter_cmd() - configure udp pkt filter command of LPHB + * @wmi_handle: wmi handle + * @lphb_conf_req: lphb config request + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_lphb_config_udp_pkt_filter_cmd(void *wmi_hdl, + wmi_hb_set_udp_pkt_filter_cmd_fixed_param *lphb_conf_req) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_lphb_config_udp_pkt_filter_cmd) + return wmi_handle->ops->send_lphb_config_udp_pkt_filter_cmd(wmi_handle, + lphb_conf_req); + + return QDF_STATUS_E_FAILURE; +} +#endif /* FEATURE_WLAN_LPHB */ + +/** + * wmi_unified_process_dhcp_ind() - process dhcp indication from SME + * @wmi_handle: wmi handle + * @ta_dhcp_ind: DHCP indication parameter + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +#ifndef WMI_NON_TLV_SUPPORT +QDF_STATUS wmi_unified_process_dhcp_ind(void *wmi_hdl, + wmi_peer_set_param_cmd_fixed_param *ta_dhcp_ind) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_process_dhcp_ind_cmd) + return wmi_handle->ops->send_process_dhcp_ind_cmd(wmi_handle, + ta_dhcp_ind); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_get_link_speed_cmd() -send command to get linkspeed + * @wmi_handle: wmi handle + * @pLinkSpeed: link speed info + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_get_link_speed_cmd(void *wmi_hdl, + wmi_mac_addr peer_macaddr) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_get_link_speed_cmd) + return wmi_handle->ops->send_get_link_speed_cmd(wmi_handle, + peer_macaddr); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_egap_conf_params_cmd() - send wmi cmd of egap configuration params + * @wmi_handle: wmi handler + * @egap_params: pointer to egap_params + * + * Return: 0 for success, otherwise appropriate error code + */ +QDF_STATUS wmi_unified_egap_conf_params_cmd(void *wmi_hdl, + wmi_ap_ps_egap_param_cmd_fixed_param *egap_params) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_egap_conf_params_cmd) + return wmi_handle->ops->send_egap_conf_params_cmd(wmi_handle, + egap_params); + + return QDF_STATUS_E_FAILURE; +} + +#endif + +/** + * wmi_unified_action_frame_patterns_cmd() - send wmi cmd of action filter params + * @wmi_handle: wmi handler + * @action_params: pointer to action_params + * + * Return: 0 for success, otherwise appropriate error code + */ +QDF_STATUS wmi_unified_action_frame_patterns_cmd(void *wmi_hdl, + struct action_wakeup_set_param *action_params) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_action_frame_patterns_cmd) + return wmi_handle->ops->send_action_frame_patterns_cmd( + wmi_handle, + action_params); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_fw_profiling_data_cmd() - send FW profiling cmd to WLAN FW + * @wmi_handl: wmi handle + * @cmd: Profiling command index + * @value1: parameter1 value + * @value2: parameter2 value + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_fw_profiling_data_cmd(void *wmi_hdl, + uint32_t cmd, uint32_t value1, uint32_t value2) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_fw_profiling_cmd) + return wmi_handle->ops->send_fw_profiling_cmd(wmi_handle, + cmd, value1, value2); + + return QDF_STATUS_E_FAILURE; +} + +#ifdef FEATURE_WLAN_RA_FILTERING +/** + * wmi_unified_wow_sta_ra_filter_cmd() - set RA filter pattern in fw + * @wmi_handle: wmi handle + * @vdev_id: vdev id + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_wow_sta_ra_filter_cmd(void *wmi_hdl, + uint8_t vdev_id, uint8_t default_pattern, + uint16_t rate_limit_interval) +{ + + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_wow_sta_ra_filter_cmd) + return wmi_handle->ops->send_wow_sta_ra_filter_cmd(wmi_handle, + vdev_id, default_pattern, rate_limit_interval); + + return QDF_STATUS_E_FAILURE; + +} +#endif /* FEATURE_WLAN_RA_FILTERING */ + +/** + * wmi_unified_nat_keepalive_en_cmd() - enable NAT keepalive filter + * @wmi_handle: wmi handle + * @vdev_id: vdev id + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_nat_keepalive_en_cmd(void *wmi_hdl, uint8_t vdev_id) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_nat_keepalive_en_cmd) + return wmi_handle->ops->send_nat_keepalive_en_cmd(wmi_handle, + vdev_id); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_csa_offload_enable() - send CSA offload enable command + * @wmi_hdl: wmi handle + * @vdev_id: vdev id + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_csa_offload_enable(void *wmi_hdl, uint8_t vdev_id) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_csa_offload_enable_cmd) + return wmi_handle->ops->send_csa_offload_enable_cmd(wmi_handle, + vdev_id); + + return QDF_STATUS_E_FAILURE; +} +/** + * wmi_unified_start_oem_data_cmd() - start OEM data request to target + * @wmi_handle: wmi handle + * @startOemDataReq: start request params + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_start_oem_data_cmd(void *wmi_hdl, + uint32_t data_len, + uint8_t *data) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_start_oem_data_cmd) + return wmi_handle->ops->send_start_oem_data_cmd(wmi_handle, + data_len, data); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_dfs_phyerr_filter_offload_en_cmd() - enable dfs phyerr filter + * @wmi_handle: wmi handle + * @dfs_phyerr_filter_offload: is dfs phyerr filter offload + * + * Send WMI_DFS_PHYERR_FILTER_ENA_CMDID or + * WMI_DFS_PHYERR_FILTER_DIS_CMDID command + * to firmware based on phyerr filtering + * offload status. + * + * Return: 1 success, 0 failure + */ +QDF_STATUS +wmi_unified_dfs_phyerr_filter_offload_en_cmd(void *wmi_hdl, + bool dfs_phyerr_filter_offload) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_dfs_phyerr_filter_offload_en_cmd) + return wmi_handle->ops->send_dfs_phyerr_filter_offload_en_cmd(wmi_handle, + dfs_phyerr_filter_offload); + + return QDF_STATUS_E_FAILURE; +} + +#if !defined(REMOVE_PKT_LOG) +/** + * wmi_unified_pktlog_wmi_send_cmd() - send pktlog enable/disable command to target + * @wmi_handle: wmi handle + * @pktlog_event: pktlog event + * @cmd_id: pktlog cmd id + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +#ifndef WMI_NON_TLV_SUPPORT +QDF_STATUS wmi_unified_pktlog_wmi_send_cmd(void *wmi_hdl, + WMI_PKTLOG_EVENT pktlog_event, + uint32_t cmd_id, + uint8_t user_triggered) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_pktlog_wmi_send_cmd) + return wmi_handle->ops->send_pktlog_wmi_send_cmd(wmi_handle, + pktlog_event, cmd_id, user_triggered); + + return QDF_STATUS_E_FAILURE; +} +#endif +#endif /* REMOVE_PKT_LOG */ + +/** + * wmi_unified_add_wow_wakeup_event_cmd() - Configures wow wakeup events. + * @wmi_handle: wmi handle + * @vdev_id: vdev id + * @bitmap: Event bitmap + * @enable: enable/disable + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_add_wow_wakeup_event_cmd(void *wmi_hdl, + uint32_t vdev_id, + uint32_t *bitmap, + bool enable) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_add_wow_wakeup_event_cmd) + return wmi_handle->ops->send_add_wow_wakeup_event_cmd( + wmi_handle, vdev_id, bitmap, enable); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_wow_patterns_to_fw_cmd() - Sends WOW patterns to FW. + * @wmi_handle: wmi handle + * @vdev_id: vdev id + * @ptrn_id: pattern id + * @ptrn: pattern + * @ptrn_len: pattern length + * @ptrn_offset: pattern offset + * @mask: mask + * @mask_len: mask length + * @user: true for user configured pattern and false for default pattern + * @default_patterns: default patterns + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_wow_patterns_to_fw_cmd(void *wmi_hdl, + uint8_t vdev_id, uint8_t ptrn_id, + const uint8_t *ptrn, uint8_t ptrn_len, + uint8_t ptrn_offset, const uint8_t *mask, + uint8_t mask_len, bool user, + uint8_t default_patterns) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_wow_patterns_to_fw_cmd) + return wmi_handle->ops->send_wow_patterns_to_fw_cmd(wmi_handle, + vdev_id, ptrn_id, ptrn, + ptrn_len, ptrn_offset, mask, + mask_len, user, default_patterns); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_wow_delete_pattern_cmd() - delete wow pattern in target + * @wmi_handle: wmi handle + * @ptrn_id: pattern id + * @vdev_id: vdev id + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_wow_delete_pattern_cmd(void *wmi_hdl, uint8_t ptrn_id, + uint8_t vdev_id) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_wow_delete_pattern_cmd) + return wmi_handle->ops->send_wow_delete_pattern_cmd(wmi_handle, + ptrn_id, vdev_id); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_host_wakeup_ind_to_fw_cmd() - send wakeup ind to fw + * @wmi_handle: wmi handle + * + * Sends host wakeup indication to FW. On receiving this indication, + * FW will come out of WOW. + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_host_wakeup_ind_to_fw_cmd(void *wmi_hdl) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_host_wakeup_ind_to_fw_cmd) + return wmi_handle->ops->send_host_wakeup_ind_to_fw_cmd(wmi_handle); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_del_ts_cmd() - send DELTS request to fw + * @wmi_handle: wmi handle + * @msg: delts params + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_del_ts_cmd(void *wmi_hdl, uint8_t vdev_id, + uint8_t ac) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_del_ts_cmd) + return wmi_handle->ops->send_del_ts_cmd(wmi_handle, + vdev_id, ac); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_aggr_qos_cmd() - send aggr qos request to fw + * @wmi_handle: handle to wmi + * @aggr_qos_rsp_msg - combined struct for all ADD_TS requests. + * + * A function to handle WMI_AGGR_QOS_REQ. This will send out + * ADD_TS requestes to firmware in loop for all the ACs with + * active flow. + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_aggr_qos_cmd(void *wmi_hdl, + struct aggr_add_ts_param *aggr_qos_rsp_msg) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_aggr_qos_cmd) + return wmi_handle->ops->send_aggr_qos_cmd(wmi_handle, + aggr_qos_rsp_msg); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_add_ts_cmd() - send ADDTS request to fw + * @wmi_handle: wmi handle + * @msg: ADDTS params + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_add_ts_cmd(void *wmi_hdl, + struct add_ts_param *msg) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_add_ts_cmd) + return wmi_handle->ops->send_add_ts_cmd(wmi_handle, + msg); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_enable_disable_packet_filter_cmd() - enable/disable packet filter in target + * @wmi_handle: wmi handle + * @vdev_id: vdev id + * @enable: Flag to enable/disable packet filter + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_enable_disable_packet_filter_cmd(void *wmi_hdl, + uint8_t vdev_id, bool enable) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_enable_disable_packet_filter_cmd) + return wmi_handle->ops->send_enable_disable_packet_filter_cmd( + wmi_handle, vdev_id, enable); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_config_packet_filter_cmd() - configure packet filter in target + * @wmi_handle: wmi handle + * @vdev_id: vdev id + * @rcv_filter_param: Packet filter parameters + * @filter_id: Filter id + * @enable: Flag to add/delete packet filter configuration + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_config_packet_filter_cmd(void *wmi_hdl, + uint8_t vdev_id, struct rcv_pkt_filter_config *rcv_filter_param, + uint8_t filter_id, bool enable) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_config_packet_filter_cmd) + return wmi_handle->ops->send_config_packet_filter_cmd(wmi_handle, + vdev_id, rcv_filter_param, + filter_id, enable); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_add_clear_mcbc_filter_cmd() - set mcast filter command to fw + * @wmi_handle: wmi handle + * @vdev_id: vdev id + * @multicastAddr: mcast address + * @clearList: clear list flag + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_add_clear_mcbc_filter_cmd(void *wmi_hdl, + uint8_t vdev_id, + struct qdf_mac_addr multicast_addr, + bool clearList) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_add_clear_mcbc_filter_cmd) + return wmi_handle->ops->send_add_clear_mcbc_filter_cmd(wmi_handle, + vdev_id, multicast_addr, clearList); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_send_gtk_offload_cmd() - send GTK offload command to fw + * @wmi_handle: wmi handle + * @vdev_id: vdev id + * @params: GTK offload parameters + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_send_gtk_offload_cmd(void *wmi_hdl, uint8_t vdev_id, + struct gtk_offload_params *params, + bool enable_offload, + uint32_t gtk_offload_opcode) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_gtk_offload_cmd) + return wmi_handle->ops->send_gtk_offload_cmd(wmi_handle, + vdev_id, params, + enable_offload, gtk_offload_opcode); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_process_gtk_offload_getinfo_cmd() - send GTK offload cmd to fw + * @wmi_handle: wmi handle + * @params: GTK offload params + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_process_gtk_offload_getinfo_cmd(void *wmi_hdl, + uint8_t vdev_id, + uint64_t offload_req_opcode) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_process_gtk_offload_getinfo_cmd) + return wmi_handle->ops->send_process_gtk_offload_getinfo_cmd(wmi_handle, + vdev_id, + offload_req_opcode); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_process_add_periodic_tx_ptrn_cmd - add periodic tx ptrn + * @wmi_handle: wmi handle + * @pAddPeriodicTxPtrnParams: tx ptrn params + * + * Retrun: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_process_add_periodic_tx_ptrn_cmd(void *wmi_hdl, + struct periodic_tx_pattern * + pAddPeriodicTxPtrnParams, + uint8_t vdev_id) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_process_add_periodic_tx_ptrn_cmd) + return wmi_handle->ops->send_process_add_periodic_tx_ptrn_cmd(wmi_handle, + pAddPeriodicTxPtrnParams, + vdev_id); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_process_del_periodic_tx_ptrn_cmd - del periodic tx ptrn + * @wmi_handle: wmi handle + * @vdev_id: vdev id + * @pattern_id: pattern id + * + * Retrun: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_process_del_periodic_tx_ptrn_cmd(void *wmi_hdl, + uint8_t vdev_id, + uint8_t pattern_id) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_process_del_periodic_tx_ptrn_cmd) + return wmi_handle->ops->send_process_del_periodic_tx_ptrn_cmd(wmi_handle, + vdev_id, + pattern_id); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_stats_ext_req_cmd() - request ext stats from fw + * @wmi_handle: wmi handle + * @preq: stats ext params + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_stats_ext_req_cmd(void *wmi_hdl, + struct stats_ext_params *preq) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_stats_ext_req_cmd) + return wmi_handle->ops->send_stats_ext_req_cmd(wmi_handle, + preq); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_enable_ext_wow_cmd() - enable ext wow in fw + * @wmi_handle: wmi handle + * @params: ext wow params + * + * Return:QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_enable_ext_wow_cmd(void *wmi_hdl, + struct ext_wow_params *params) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_enable_ext_wow_cmd) + return wmi_handle->ops->send_enable_ext_wow_cmd(wmi_handle, + params); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_set_app_type2_params_in_fw_cmd() - set app type2 params in fw + * @wmi_handle: wmi handle + * @appType2Params: app type2 params + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_set_app_type2_params_in_fw_cmd(void *wmi_hdl, + struct app_type2_params *appType2Params) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_set_app_type2_params_in_fw_cmd) + return wmi_handle->ops->send_set_app_type2_params_in_fw_cmd(wmi_handle, + appType2Params); + + return QDF_STATUS_E_FAILURE; + +} + +/** + * wmi_unified_set_auto_shutdown_timer_cmd() - sets auto shutdown timer in firmware + * @wmi_handle: wmi handle + * @timer_val: auto shutdown timer value + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_set_auto_shutdown_timer_cmd(void *wmi_hdl, + uint32_t timer_val) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_set_auto_shutdown_timer_cmd) + return wmi_handle->ops->send_set_auto_shutdown_timer_cmd(wmi_handle, + timer_val); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_nan_req_cmd() - to send nan request to target + * @wmi_handle: wmi handle + * @nan_req: request data which will be non-null + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_nan_req_cmd(void *wmi_hdl, + struct nan_req_params *nan_req) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_nan_req_cmd) + return wmi_handle->ops->send_nan_req_cmd(wmi_handle, + nan_req); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_process_dhcpserver_offload_cmd() - enable DHCP server offload + * @wmi_handle: wmi handle + * @pDhcpSrvOffloadInfo: DHCP server offload info + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_process_dhcpserver_offload_cmd(void *wmi_hdl, + struct dhcp_offload_info_params *pDhcpSrvOffloadInfo) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_process_dhcpserver_offload_cmd) + return wmi_handle->ops->send_process_dhcpserver_offload_cmd(wmi_handle, + pDhcpSrvOffloadInfo); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_process_ch_avoid_update_cmd() - handles channel avoid update request + * @wmi_handle: wmi handle + * @ch_avoid_update_req: channel avoid update params + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_process_ch_avoid_update_cmd(void *wmi_hdl) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_process_ch_avoid_update_cmd) + return wmi_handle->ops->send_process_ch_avoid_update_cmd(wmi_handle); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_send_regdomain_info_to_fw_cmd() - send regdomain info to fw + * @wmi_handle: wmi handle + * @reg_dmn: reg domain + * @regdmn2G: 2G reg domain + * @regdmn5G: 5G reg domain + * @ctl2G: 2G test limit + * @ctl5G: 5G test limit + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_send_regdomain_info_to_fw_cmd(void *wmi_hdl, + uint32_t reg_dmn, uint16_t regdmn2G, + uint16_t regdmn5G, int8_t ctl2G, + int8_t ctl5G) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_regdomain_info_to_fw_cmd) + return wmi_handle->ops->send_regdomain_info_to_fw_cmd(wmi_handle, + reg_dmn, regdmn2G, + regdmn5G, ctl2G, + ctl5G); + + return QDF_STATUS_E_FAILURE; +} + + +/** + * wmi_unified_set_tdls_offchan_mode_cmd() - set tdls off channel mode + * @wmi_handle: wmi handle + * @chan_switch_params: Pointer to tdls channel switch parameter structure + * + * This function sets tdls off channel mode + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failures; + * Negative errno otherwise + */ +QDF_STATUS wmi_unified_set_tdls_offchan_mode_cmd(void *wmi_hdl, + struct tdls_channel_switch_params *chan_switch_params) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_set_tdls_offchan_mode_cmd) + return wmi_handle->ops->send_set_tdls_offchan_mode_cmd(wmi_handle, + chan_switch_params); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_update_fw_tdls_state_cmd() - send enable/disable tdls for a vdev + * @wmi_handle: wmi handle + * @pwmaTdlsparams: TDLS params + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_update_fw_tdls_state_cmd(void *wmi_hdl, + void *tdls_param, uint8_t tdls_state) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_update_fw_tdls_state_cmd) + return wmi_handle->ops->send_update_fw_tdls_state_cmd(wmi_handle, + tdls_param, tdls_state); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_update_tdls_peer_state_cmd() - update TDLS peer state + * @wmi_handle: wmi handle + * @peerStateParams: TDLS peer state params + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_update_tdls_peer_state_cmd(void *wmi_hdl, + struct tdls_peer_state_params *peerStateParams, + uint32_t *ch_mhz) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_update_tdls_peer_state_cmd) + return wmi_handle->ops->send_update_tdls_peer_state_cmd(wmi_handle, + peerStateParams, ch_mhz); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_process_fw_mem_dump_cmd() - Function to request fw memory dump from + * firmware + * @wmi_handle: Pointer to wmi handle + * @mem_dump_req: Pointer for mem_dump_req + * + * This function sends memory dump request to firmware + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + * + */ +QDF_STATUS wmi_unified_process_fw_mem_dump_cmd(void *wmi_hdl, + struct fw_dump_req_param *mem_dump_req) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_process_fw_mem_dump_cmd) + return wmi_handle->ops->send_process_fw_mem_dump_cmd(wmi_handle, + mem_dump_req); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_process_set_ie_info_cmd() - Function to send IE info to firmware + * @wmi_handle: Pointer to WMi handle + * @ie_data: Pointer for ie data + * + * This function sends IE information to firmware + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + * + */ +QDF_STATUS wmi_unified_process_set_ie_info_cmd(void *wmi_hdl, + struct vdev_ie_info_param *ie_info) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_process_set_ie_info_cmd) + return wmi_handle->ops->send_process_set_ie_info_cmd(wmi_handle, + ie_info); + + return QDF_STATUS_E_FAILURE; +} +#ifdef CONFIG_MCL +/** + * wmi_unified_send_init_cmd() - wmi init command + * @wmi_handle: pointer to wmi handle + * @res_cfg: resource config + * @num_mem_chunks: no of mem chunck + * @mem_chunk: pointer to mem chunck structure + * + * This function sends IE information to firmware + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + * + */ +QDF_STATUS wmi_unified_send_init_cmd(void *wmi_hdl, + wmi_resource_config *res_cfg, + uint8_t num_mem_chunks, struct wmi_host_mem_chunk *mem_chunk, + bool action) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_init_cmd) + return wmi_handle->ops->send_init_cmd(wmi_handle, + res_cfg, num_mem_chunks, mem_chunk, action); + + return QDF_STATUS_E_FAILURE; +} +#endif +/** + * wmi_unified_send_saved_init_cmd() - wmi init command + * @wmi_handle: pointer to wmi handle + * + * This function sends IE information to firmware + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + * + */ +QDF_STATUS wmi_unified_send_saved_init_cmd(void *wmi_hdl) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_saved_init_cmd) + return wmi_handle->ops->send_saved_init_cmd(wmi_handle); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_save_fw_version_cmd() - save fw version + * @wmi_handle: pointer to wmi handle + * @res_cfg: resource config + * @num_mem_chunks: no of mem chunck + * @mem_chunk: pointer to mem chunck structure + * + * This function sends IE information to firmware + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + * + */ +QDF_STATUS wmi_unified_save_fw_version_cmd(void *wmi_hdl, + void *evt_buf) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->save_fw_version_cmd) + return wmi_handle->ops->save_fw_version_cmd(wmi_handle, + evt_buf); + + return QDF_STATUS_E_FAILURE; +} + +/** + * send_set_base_macaddr_indicate_cmd() - set base mac address in fw + * @wmi_hdl: wmi handle + * @custom_addr: base mac address + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_set_base_macaddr_indicate_cmd(void *wmi_hdl, + uint8_t *custom_addr) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_set_base_macaddr_indicate_cmd) + return wmi_handle->ops->send_set_base_macaddr_indicate_cmd(wmi_handle, + custom_addr); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_log_supported_evt_cmd() - Enable/Disable FW diag/log events + * @wmi_hdl: wmi handle + * @event: Event received from FW + * @len: Length of the event + * + * Enables the low frequency events and disables the high frequency + * events. Bit 17 indicates if the event if low/high frequency. + * 1 - high frequency, 0 - low frequency + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failures + */ +QDF_STATUS wmi_unified_log_supported_evt_cmd(void *wmi_hdl, + uint8_t *event, + uint32_t len) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_log_supported_evt_cmd) + return wmi_handle->ops->send_log_supported_evt_cmd(wmi_handle, + event, len); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_enable_specific_fw_logs_cmd() - Start/Stop logging of diag log id + * @wmi_hdl: wmi handle + * @start_log: Start logging related parameters + * + * Send the command to the FW based on which specific logging of diag + * event/log id can be started/stopped + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_enable_specific_fw_logs_cmd(void *wmi_hdl, + struct wmi_wifi_start_log *start_log) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_enable_specific_fw_logs_cmd) + return wmi_handle->ops->send_enable_specific_fw_logs_cmd(wmi_handle, + start_log); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_flush_logs_to_fw_cmd() - Send log flush command to FW + * @wmi_hdl: WMI handle + * + * This function is used to send the flush command to the FW, + * that will flush the fw logs that are residue in the FW + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_flush_logs_to_fw_cmd(void *wmi_hdl) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_flush_logs_to_fw_cmd) + return wmi_handle->ops->send_flush_logs_to_fw_cmd(wmi_handle); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_pdev_set_pcl_cmd() - Send WMI_SOC_SET_PCL_CMDID to FW + * @wmi_hdl: wmi handle + * @msg: PCL structure containing the PCL and the number of channels + * + * WMI_SOC_SET_PCL_CMDID provides a Preferred Channel List (PCL) to the WLAN + * firmware. The DBS Manager is the consumer of this information in the WLAN + * firmware. The channel list will be used when a Virtual DEVice (VDEV) needs + * to migrate to a new channel without host driver involvement. An example of + * this behavior is Legacy Fast Roaming (LFR 3.0). Generally, the host will + * manage the channel selection without firmware involvement. + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_pdev_set_pcl_cmd(void *wmi_hdl, + struct wmi_pcl_chan_weights *msg) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_pdev_set_pcl_cmd) + return wmi_handle->ops->send_pdev_set_pcl_cmd(wmi_handle, msg); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_soc_set_hw_mode_cmd() - Send WMI_SOC_SET_HW_MODE_CMDID to FW + * @wmi_hdl: wmi handle + * @msg: Structure containing the following parameters + * + * - hw_mode_index: The HW_Mode field is a enumerated type that is selected + * from the HW_Mode table, which is returned in the WMI_SERVICE_READY_EVENTID. + * + * Provides notification to the WLAN firmware that host driver is requesting a + * HardWare (HW) Mode change. This command is needed to support iHelium in the + * configurations that include the Dual Band Simultaneous (DBS) feature. + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_soc_set_hw_mode_cmd(void *wmi_hdl, + uint32_t hw_mode_index) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_pdev_set_hw_mode_cmd) + return wmi_handle->ops->send_pdev_set_hw_mode_cmd(wmi_handle, + hw_mode_index); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_pdev_set_dual_mac_config_cmd() - Set dual mac config to FW + * @wmi_hdl: wmi handle + * @msg: Dual MAC config parameters + * + * Configures WLAN firmware with the dual MAC features + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failures. + */ +QDF_STATUS wmi_unified_pdev_set_dual_mac_config_cmd(void *wmi_hdl, + struct wmi_dual_mac_config *msg) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_pdev_set_dual_mac_config_cmd) + return wmi_handle->ops->send_pdev_set_dual_mac_config_cmd(wmi_handle, + msg); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_enable_arp_ns_offload_cmd() - enable ARP NS offload + * @wmi_hdl: wmi handle + * @param: offload request + * @arp_only: flag + * + * To configure ARP NS off load data to firmware + * when target goes to wow mode. + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_enable_arp_ns_offload_cmd(void *wmi_hdl, + struct host_offload_req_param *arp_offload_req, + struct host_offload_req_param *ns_offload_req, + bool arp_only, + uint8_t vdev_id) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_enable_arp_ns_offload_cmd) + return wmi_handle->ops->send_enable_arp_ns_offload_cmd(wmi_handle, + arp_offload_req, ns_offload_req, arp_only, + vdev_id); + + return QDF_STATUS_E_FAILURE; +} + +QDF_STATUS wmi_unified_conf_hw_filter_mode_cmd(void *wmi_hdl, + uint8_t vdev_id, + uint8_t mode_bitmap) +{ + wmi_unified_t wmi = wmi_hdl; + + if (!wmi->ops->send_conf_hw_filter_mode_cmd) + return QDF_STATUS_E_FAILURE; + + return wmi->ops->send_conf_hw_filter_mode_cmd(wmi, vdev_id, + mode_bitmap); +} + +/** + * wmi_unified_set_led_flashing_cmd() - set led flashing in fw + * @wmi_hdl: wmi handle + * @flashing: flashing request + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_set_led_flashing_cmd(void *wmi_hdl, + struct flashing_req_params *flashing) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_set_led_flashing_cmd) + return wmi_handle->ops->send_set_led_flashing_cmd(wmi_handle, + flashing); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_app_type1_params_in_fw_cmd() - set app type1 params in fw + * @wmi_hdl: wmi handle + * @appType1Params: app type1 params + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_app_type1_params_in_fw_cmd(void *wmi_hdl, + struct app_type1_params *app_type1_params) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_app_type1_params_in_fw_cmd) + return wmi_handle->ops->send_app_type1_params_in_fw_cmd(wmi_handle, + app_type1_params); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_set_ssid_hotlist_cmd() - Handle an SSID hotlist set request + * @wmi_hdl: wmi handle + * @request: SSID hotlist set request + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS +wmi_unified_set_ssid_hotlist_cmd(void *wmi_hdl, + struct ssid_hotlist_request_params *request) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_set_ssid_hotlist_cmd) + return wmi_handle->ops->send_set_ssid_hotlist_cmd(wmi_handle, + request); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_roam_synch_complete_cmd() - roam synch complete command to fw. + * @wmi_hdl: wmi handle + * @vdev_id: vdev id + * + * This function sends roam synch complete event to fw. + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_roam_synch_complete_cmd(void *wmi_hdl, + uint8_t vdev_id) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_process_roam_synch_complete_cmd) + return wmi_handle->ops->send_process_roam_synch_complete_cmd(wmi_handle, + vdev_id); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_fw_test_cmd() - send fw test command to fw. + * @wmi_hdl: wmi handle + * @wmi_fwtest: fw test command + * + * This function sends fw test command to fw. + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_fw_test_cmd(void *wmi_hdl, + struct set_fwtest_params *wmi_fwtest) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_fw_test_cmd) + return wmi_handle->ops->send_fw_test_cmd(wmi_handle, + wmi_fwtest); + + return QDF_STATUS_E_FAILURE; + +} + +/** + * wmi_unified_unit_test_cmd() - send unit test command to fw. + * @wmi_hdl: wmi handle + * @wmi_utest: unit test command + * + * This function send unit test command to fw. + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_unit_test_cmd(void *wmi_hdl, + struct wmi_unit_test_cmd *wmi_utest) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_unit_test_cmd) + return wmi_handle->ops->send_unit_test_cmd(wmi_handle, + wmi_utest); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified__roam_invoke_cmd() - send roam invoke command to fw. + * @wmi_hdl: wmi handle + * @roaminvoke: roam invoke command + * + * Send roam invoke command to fw for fastreassoc. + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_roam_invoke_cmd(void *wmi_hdl, + struct wmi_roam_invoke_cmd *roaminvoke, + uint32_t ch_hz) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_roam_invoke_cmd) + return wmi_handle->ops->send_roam_invoke_cmd(wmi_handle, + roaminvoke, ch_hz); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_roam_scan_offload_cmd() - set roam offload command + * @wmi_hdl: wmi handle + * @command: command + * @vdev_id: vdev id + * + * This function set roam offload command to fw. + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_roam_scan_offload_cmd(void *wmi_hdl, + uint32_t command, uint32_t vdev_id) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_roam_scan_offload_cmd) + return wmi_handle->ops->send_roam_scan_offload_cmd(wmi_handle, + command, vdev_id); + + return QDF_STATUS_E_FAILURE; +} +#ifndef WMI_NON_TLV_SUPPORT +/** + * wmi_unified_send_roam_scan_offload_ap_cmd() - set roam ap profile in fw + * @wmi_hdl: wmi handle + * @ap_profile_p: ap profile + * @vdev_id: vdev id + * + * Send WMI_ROAM_AP_PROFILE to firmware + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_send_roam_scan_offload_ap_cmd(void *wmi_hdl, + wmi_ap_profile *ap_profile_p, + uint32_t vdev_id) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_roam_scan_offload_ap_profile_cmd) + return wmi_handle->ops->send_roam_scan_offload_ap_profile_cmd(wmi_handle, + ap_profile_p, vdev_id); + + return QDF_STATUS_E_FAILURE; +} +#endif +/** + * wmi_unified_roam_scan_offload_scan_period() - set roam offload scan period + * @wmi_handle: wmi handle + * @scan_period: scan period + * @scan_age: scan age + * @vdev_id: vdev id + * + * Send WMI_ROAM_SCAN_PERIOD parameters to fw. + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_roam_scan_offload_scan_period(void *wmi_hdl, + uint32_t scan_period, + uint32_t scan_age, + uint32_t vdev_id) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_roam_scan_offload_scan_period_cmd) + return wmi_handle->ops->send_roam_scan_offload_scan_period_cmd(wmi_handle, + scan_period, scan_age, vdev_id); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_roam_scan_offload_chan_list_cmd() - set roam offload channel list + * @wmi_handle: wmi handle + * @chan_count: channel count + * @chan_list: channel list + * @list_type: list type + * @vdev_id: vdev id + * + * Set roam offload channel list. + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_roam_scan_offload_chan_list_cmd(void *wmi_hdl, + uint8_t chan_count, + uint32_t *chan_list, + uint8_t list_type, uint32_t vdev_id) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_roam_scan_offload_chan_list_cmd) + return wmi_handle->ops->send_roam_scan_offload_chan_list_cmd(wmi_handle, + chan_count, chan_list, + list_type, vdev_id); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_roam_scan_offload_rssi_change_cmd() - set roam offload RSSI th + * @wmi_hdl: wmi handle + * @rssi_change_thresh: RSSI Change threshold + * @bcn_rssi_weight: beacon RSSI weight + * @vdev_id: vdev id + * + * Send WMI_ROAM_SCAN_RSSI_CHANGE_THRESHOLD parameters to fw. + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_roam_scan_offload_rssi_change_cmd(void *wmi_hdl, + uint32_t vdev_id, + int32_t rssi_change_thresh, + uint32_t bcn_rssi_weight, + uint32_t hirssi_delay_btw_scans) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_roam_scan_offload_rssi_change_cmd) + return wmi_handle->ops->send_roam_scan_offload_rssi_change_cmd(wmi_handle, + vdev_id, rssi_change_thresh, + bcn_rssi_weight, hirssi_delay_btw_scans); + + return QDF_STATUS_E_FAILURE; +} + +QDF_STATUS wmi_unified_set_per_roam_config(void *wmi_hdl, + struct wmi_per_roam_config_req *req_buf) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_per_roam_config_cmd) + return wmi_handle->ops->send_per_roam_config_cmd(wmi_handle, + req_buf); + + return QDF_STATUS_E_FAILURE; +} + +QDF_STATUS wmi_unified_set_arp_stats_req(void *wmi_hdl, + struct set_arp_stats *req_buf) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_set_arp_stats_req_cmd) + return wmi_handle->ops->send_set_arp_stats_req_cmd(wmi_handle, + req_buf); + + return QDF_STATUS_E_FAILURE; +} + +QDF_STATUS wmi_unified_get_arp_stats_req(void *wmi_hdl, + struct get_arp_stats *req_buf) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_get_arp_stats_req_cmd) + return wmi_handle->ops->send_get_arp_stats_req_cmd(wmi_handle, + req_buf); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_get_buf_extscan_hotlist_cmd() - prepare hotlist command + * @wmi_hdl: wmi handle + * @photlist: hotlist command params + * @buf_len: buffer length + * + * This function fills individual elements for hotlist request and + * TLV for bssid entries + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure. + */ +QDF_STATUS wmi_unified_get_buf_extscan_hotlist_cmd(void *wmi_hdl, + struct ext_scan_setbssi_hotlist_params * + photlist, int *buf_len) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_get_buf_extscan_hotlist_cmd) + return wmi_handle->ops->send_get_buf_extscan_hotlist_cmd(wmi_handle, + photlist, buf_len); + + return QDF_STATUS_E_FAILURE; +} + +QDF_STATUS +wmi_unified_set_active_bpf_mode_cmd(void *wmi_hdl, + uint8_t vdev_id, + FW_ACTIVE_BPF_MODE ucast_mode, + FW_ACTIVE_BPF_MODE mcast_bcast_mode) +{ + wmi_unified_t wmi = (wmi_unified_t)wmi_hdl; + + if (!wmi->ops->send_set_active_bpf_mode_cmd) { + WMI_LOGI("send_set_active_bpf_mode_cmd op is NULL"); + return QDF_STATUS_E_FAILURE; + } + + return wmi->ops->send_set_active_bpf_mode_cmd(wmi, vdev_id, + ucast_mode, + mcast_bcast_mode); +} + +/** + * wmi_unified_pdev_get_tpc_config_cmd_send() - WMI get tpc config function + * @param wmi_handle : handle to WMI. + * @param param : tpc config param + * + * @return QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_pdev_get_tpc_config_cmd_send(void *wmi_hdl, + uint32_t param) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_pdev_get_tpc_config_cmd) + return wmi_handle->ops->send_pdev_get_tpc_config_cmd(wmi_handle, + param); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_set_bwf_cmd_send() - WMI set bwf function + * @param wmi_handle : handle to WMI. + * @param param : pointer to set bwf param + * + * @return QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_set_bwf_cmd_send(void *wmi_hdl, + struct set_bwf_params *param) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_set_bwf_cmd) + return wmi_handle->ops->send_set_bwf_cmd(wmi_handle, param); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_set_atf_cmd_send() - WMI set atf function + * @param wmi_handle : handle to WMI. + * @param param : pointer to set atf param + * + * @return QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_set_atf_cmd_send(void *wmi_hdl, + struct set_atf_params *param) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_set_atf_cmd) + return wmi_handle->ops->send_set_atf_cmd(wmi_handle, param); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_pdev_fips_cmd_send() - WMI pdev fips cmd function + * @param wmi_handle : handle to WMI. + * @param param : pointer to hold pdev fips param + * + * @return QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_pdev_fips_cmd_send(void *wmi_hdl, + struct fips_params *param) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_pdev_fips_cmd) + return wmi_handle->ops->send_pdev_fips_cmd(wmi_handle, param); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_wlan_profile_enable_cmd_send() - WMI wlan profile enable cmd function + * @param wmi_handle : handle to WMI. + * @param param : pointer to hold wlan profile param + * + * @return QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_wlan_profile_enable_cmd_send(void *wmi_hdl, + struct wlan_profile_params *param) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_wlan_profile_enable_cmd) + return wmi_handle->ops->send_wlan_profile_enable_cmd(wmi_handle, + param); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_wlan_profile_trigger_cmd_send() - WMI wlan profile trigger cmd function + * @param wmi_handle : handle to WMI. + * @param param : pointer to hold wlan profile param + * + * @return QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_wlan_profile_trigger_cmd_send(void *wmi_hdl, + struct wlan_profile_params *param) +{ + wmi_unified_t wmi = (wmi_unified_t) wmi_hdl; + + if (wmi->ops->send_wlan_profile_trigger_cmd) + return wmi->ops->send_wlan_profile_trigger_cmd(wmi, + param); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_set_chan_cmd_send() - WMI set channel cmd function + * @param wmi_handle : handle to WMI. + * @param param : pointer to hold channel param + * + * @return QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_set_chan_cmd_send(void *wmi_hdl, + struct channel_param *param) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_pdev_set_chan_cmd) + return wmi_handle->ops->send_pdev_set_chan_cmd(wmi_handle, + param); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_set_ht_ie_cmd_send() - WMI set channel cmd function + * @param wmi_handle : handle to WMI. + * @param param : pointer to hold channel param + * + * @return QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_set_ht_ie_cmd_send(void *wmi_hdl, + struct ht_ie_params *param) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_set_ht_ie_cmd) + return wmi_handle->ops->send_set_ht_ie_cmd(wmi_handle, param); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_set_vht_ie_cmd_send() - WMI set channel cmd function + * @param wmi_handle : handle to WMI. + * @param param : pointer to hold channel param + * + * @return QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_set_vht_ie_cmd_send(void *wmi_hdl, + struct vht_ie_params *param) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_set_vht_ie_cmd) + return wmi_handle->ops->send_set_vht_ie_cmd(wmi_handle, param); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_wmm_update_cmd_send() - WMI wmm update cmd function + * @param wmi_handle : handle to WMI. + * @param param : pointer to hold wmm param + * + * @return QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_wmm_update_cmd_send(void *wmi_hdl, + struct wmm_update_params *param) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_wmm_update_cmd) + return wmi_handle->ops->send_wmm_update_cmd(wmi_handle, param); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_set_ant_switch_tbl_cmd_send() - WMI ant switch tbl cmd function + * @param wmi_handle : handle to WMI. + * @param param : pointer to hold ant switch tbl param + * + * @return QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_set_ant_switch_tbl_cmd_send(void *wmi_hdl, + struct ant_switch_tbl_params *param) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_set_ant_switch_tbl_cmd) + return wmi_handle->ops->send_set_ant_switch_tbl_cmd(wmi_handle, + param); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_set_ratepwr_table_cmd_send() - WMI ratepwr table cmd function + * @param wmi_handle : handle to WMI. + * @param param : pointer to hold ratepwr table param + * + * @return QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_set_ratepwr_table_cmd_send(void *wmi_hdl, + struct ratepwr_table_params *param) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_set_ratepwr_table_cmd) + return wmi_handle->ops->send_set_ratepwr_table_cmd(wmi_handle, + param); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_get_ratepwr_table_cmd_send() - WMI ratepwr table cmd function + * @param wmi_handle : handle to WMI. + * + * @return QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_get_ratepwr_table_cmd_send(void *wmi_hdl) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_get_ratepwr_table_cmd) + return wmi_handle->ops->send_get_ratepwr_table_cmd(wmi_handle); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_set_ctl_table_cmd_send() - WMI ctl table cmd function + * @param wmi_handle : handle to WMI. + * @param param : pointer to hold ctl table param + * + * @return QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_set_ctl_table_cmd_send(void *wmi_hdl, + struct ctl_table_params *param) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_set_ctl_table_cmd) + return wmi_handle->ops->send_set_ctl_table_cmd(wmi_handle, + param); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_set_mimogain_table_cmd_send() - WMI set mimogain cmd function + * @param wmi_handle : handle to WMI. + * @param param : pointer to hold mimogain param + * + * @return QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_set_mimogain_table_cmd_send(void *wmi_hdl, + struct mimogain_table_params *param) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_set_mimogain_table_cmd) + return wmi_handle->ops->send_set_mimogain_table_cmd(wmi_handle, + param); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_set_ratepwr_chainmsk_cmd_send() - WMI ratepwr + * chainmsk cmd function + * @param wmi_handle : handle to WMI. + * @param param : pointer to hold ratepwr chainmsk param + * + * @return QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_set_ratepwr_chainmsk_cmd_send(void *wmi_hdl, + struct ratepwr_chainmsk_params *param) +{ + wmi_unified_t wmi = (wmi_unified_t) wmi_hdl; + + if (wmi->ops->send_set_ratepwr_chainmsk_cmd) + return wmi->ops->send_set_ratepwr_chainmsk_cmd(wmi, param); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_set_macaddr_cmd_send() - WMI set macaddr cmd function + * @param wmi_handle : handle to WMI. + * @param param : pointer to hold macaddr param + * + * @return QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_set_macaddr_cmd_send(void *wmi_hdl, + struct macaddr_params *param) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_set_macaddr_cmd) + return wmi_handle->ops->send_set_macaddr_cmd(wmi_handle, param); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_pdev_scan_start_cmd_send() - WMI pdev scan start cmd function + * @param wmi_handle : handle to WMI. + * + * @return QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_pdev_scan_start_cmd_send(void *wmi_hdl) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_pdev_scan_start_cmd) + return wmi_handle->ops->send_pdev_scan_start_cmd(wmi_handle); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_pdev_scan_end_cmd_send() - WMI pdev scan end cmd function + * @param wmi_handle : handle to WMI. + * + * @return QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_pdev_scan_end_cmd_send(void *wmi_hdl) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_pdev_scan_end_cmd) + return wmi_handle->ops->send_pdev_scan_end_cmd(wmi_handle); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_set_acparams_cmd_send() - WMI set acparams cmd function + * @param wmi_handle : handle to WMI. + * @param param : pointer to hold acparams param + * + * @return QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_set_acparams_cmd_send(void *wmi_hdl, + struct acparams_params *param) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_set_acparams_cmd) + return wmi_handle->ops->send_set_acparams_cmd(wmi_handle, + param); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_set_vap_dscp_tid_map_cmd_send() - WMI set vap dscp + * tid map cmd function + * @param wmi_handle : handle to WMI. + * @param param : pointer to hold dscp param + * + * @return QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_set_vap_dscp_tid_map_cmd_send(void *wmi_hdl, + struct vap_dscp_tid_map_params *param) +{ + wmi_unified_t wmi = (wmi_unified_t) wmi_hdl; + + if (wmi->ops->send_set_vap_dscp_tid_map_cmd) + return wmi->ops->send_set_vap_dscp_tid_map_cmd(wmi, param); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_proxy_ast_reserve_cmd_send() - WMI proxy ast + * reserve cmd function + * @param wmi_handle : handle to WMI. + * @param param : pointer to hold ast param + * + * @return QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_proxy_ast_reserve_cmd_send(void *wmi_hdl, + struct proxy_ast_reserve_params *param) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_proxy_ast_reserve_cmd) + return wmi_handle->ops->send_proxy_ast_reserve_cmd(wmi_handle, + param); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_pdev_qvit_cmd_send() - WMI pdev qvit cmd function + * @param wmi_handle : handle to WMI. + * @param param : pointer to hold qvit param + * + * @return QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_pdev_qvit_cmd_send(void *wmi_hdl, + struct pdev_qvit_params *param) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_pdev_qvit_cmd) + return wmi_handle->ops->send_pdev_qvit_cmd(wmi_handle, param); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_mcast_group_update_cmd_send() - WMI mcast grp update cmd function + * @param wmi_handle : handle to WMI. + * @param param : pointer to hold mcast grp param + * + * @return QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_mcast_group_update_cmd_send(void *wmi_hdl, + struct mcast_group_update_params *param) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_mcast_group_update_cmd) + return wmi_handle->ops->send_mcast_group_update_cmd(wmi_handle, + param); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_peer_add_wds_entry_cmd_send() - WMI add wds entry cmd function + * @param wmi_handle : handle to WMI. + * @param param : pointer to hold wds entry param + * + * @return QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_peer_add_wds_entry_cmd_send(void *wmi_hdl, + struct peer_add_wds_entry_params *param) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_peer_add_wds_entry_cmd) + return wmi_handle->ops->send_peer_add_wds_entry_cmd(wmi_handle, + param); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_peer_del_wds_entry_cmd_send() - WMI del wds entry cmd function + * @param wmi_handle : handle to WMI. + * @param param : pointer to hold wds entry param + * + * @return QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_peer_del_wds_entry_cmd_send(void *wmi_hdl, + struct peer_del_wds_entry_params *param) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_peer_del_wds_entry_cmd) + return wmi_handle->ops->send_peer_del_wds_entry_cmd(wmi_handle, + param); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_peer_update_wds_entry_cmd_send() - WMI update wds entry cmd function + * @param wmi_handle : handle to WMI. + * @param param : pointer to hold wds entry param + * + * @return QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_peer_update_wds_entry_cmd_send(void *wmi_hdl, + struct peer_update_wds_entry_params *param) +{ + wmi_unified_t wmi = (wmi_unified_t) wmi_hdl; + + if (wmi->ops->send_peer_update_wds_entry_cmd) + return wmi->ops->send_peer_update_wds_entry_cmd(wmi, param); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_phyerr_enable_cmd_send() - WMI phyerr enable cmd function + * @param wmi_handle : handle to WMI. + * @param param : pointer to hold phyerr enable param + * + * @return QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_phyerr_enable_cmd_send(void *wmi_hdl) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_phyerr_enable_cmd) + return wmi_handle->ops->send_phyerr_enable_cmd(wmi_handle); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_phyerr_disable_cmd_send() - WMI phyerr disable cmd function + * @param wmi_handle : handle to WMI. + * @param param : pointer to hold phyerr disable param + * + * @return QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_phyerr_disable_cmd_send(void *wmi_hdl) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_phyerr_disable_cmd) + return wmi_handle->ops->send_phyerr_disable_cmd(wmi_handle); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_smart_ant_enable_cmd_send() - WMI smart ant enable function + * @param wmi_handle : handle to WMI. + * @param param : pointer to hold antenna param + * + * @return QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_smart_ant_enable_cmd_send(void *wmi_hdl, + struct smart_ant_enable_params *param) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_smart_ant_enable_cmd) + return wmi_handle->ops->send_smart_ant_enable_cmd(wmi_handle, + param); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_smart_ant_set_rx_ant_cmd_send() - WMI set rx antenna function + * @param wmi_handle : handle to WMI. + * @param param : pointer to hold antenna param + * + * @return QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_smart_ant_set_rx_ant_cmd_send(void *wmi_hdl, + struct smart_ant_rx_ant_params *param) +{ + wmi_unified_t wmi = (wmi_unified_t) wmi_hdl; + + if (wmi->ops->send_smart_ant_set_rx_ant_cmd) + return wmi->ops->send_smart_ant_set_rx_ant_cmd(wmi, param); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_smart_ant_set_tx_ant_cmd_send() - WMI set tx antenna function + * @param wmi_handle : handle to WMI. + * @param param : pointer to hold antenna param + * + * @return QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_smart_ant_set_tx_ant_cmd_send(void *wmi_hdl, + uint8_t macaddr[IEEE80211_ADDR_LEN], + struct smart_ant_tx_ant_params *param) +{ + wmi_unified_t wmi = (wmi_unified_t) wmi_hdl; + + if (wmi->ops->send_smart_ant_set_tx_ant_cmd) + return wmi->ops->send_smart_ant_set_tx_ant_cmd(wmi, macaddr, + param); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_smart_ant_set_training_info_cmd_send() - WMI set tx antenna function + * @param wmi_handle : handle to WMI. + * @param param : pointer to hold antenna param + * + * @return QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_smart_ant_set_training_info_cmd_send(void *wmi_hdl, + uint8_t macaddr[IEEE80211_ADDR_LEN], + struct smart_ant_training_info_params *param) +{ + wmi_unified_t wmi = (wmi_unified_t) wmi_hdl; + + if (wmi->ops->send_smart_ant_set_training_info_cmd) + return wmi->ops->send_smart_ant_set_training_info_cmd(wmi, + macaddr, param); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_smart_ant_node_config_cmd_send() - WMI set node config function + * @param wmi_handle : handle to WMI. + * @param macaddr : MAC address + * @param param : pointer to hold node parameter + * + * @return QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_smart_ant_node_config_cmd_send(void *wmi_hdl, + uint8_t macaddr[IEEE80211_ADDR_LEN], + struct smart_ant_node_config_params *param) +{ + wmi_unified_t wmi = (wmi_unified_t) wmi_hdl; + + if (wmi->ops->send_smart_ant_set_node_config_cmd) + return wmi->ops->send_smart_ant_set_node_config_cmd(wmi, + macaddr, param); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_smart_ant_enable_tx_feedback_cmd_send() - WMI set tx antenna function + * @param wmi_handle : handle to WMI. + * @param param : pointer to hold antenna param + * + * @return QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_smart_ant_enable_tx_feedback_cmd_send(void *wmi_hdl, + struct smart_ant_enable_tx_feedback_params *param) +{ + wmi_unified_t wmi = (wmi_unified_t) wmi_hdl; + + if (wmi->ops->send_smart_ant_enable_tx_feedback_cmd) + return wmi->ops->send_smart_ant_enable_tx_feedback_cmd(wmi, + param); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_vdev_spectral_configure_cmd_send() - WMI set spectral config function + * @param wmi_handle : handle to WMI. + * @param param : pointer to hold spectral config param + * + * @return QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_vdev_spectral_configure_cmd_send(void *wmi_hdl, + struct vdev_spectral_configure_params *param) +{ + wmi_unified_t wmi = (wmi_unified_t) wmi_hdl; + + if (wmi->ops->send_vdev_spectral_configure_cmd) + return wmi->ops->send_vdev_spectral_configure_cmd(wmi, param); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_vdev_spectral_enable_cmd_send() - WMI enable spectral function + * @param wmi_handle : handle to WMI. + * @param param : pointer to hold enable spectral param + * + * @return QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_vdev_spectral_enable_cmd_send(void *wmi_hdl, + struct vdev_spectral_enable_params *param) +{ + wmi_unified_t wmi = (wmi_unified_t) wmi_hdl; + + if (wmi->ops->send_vdev_spectral_enable_cmd) + return wmi->ops->send_vdev_spectral_enable_cmd(wmi, param); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_bss_chan_info_request_cmd_send() - WMI bss chan info request function + * @param wmi_handle : handle to WMI. + * @param param : pointer to hold chan info param + * + * @return QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_bss_chan_info_request_cmd_send(void *wmi_hdl, + struct bss_chan_info_request_params *param) +{ + wmi_unified_t wmi = (wmi_unified_t) wmi_hdl; + + if (wmi->ops->send_bss_chan_info_request_cmd) + return wmi->ops->send_bss_chan_info_request_cmd(wmi, param); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_thermal_mitigation_param_cmd_send() - WMI thermal mitigation function + * @param wmi_handle : handle to WMI. + * @param param : pointer to hold thermal mitigation param + * + * @return QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_thermal_mitigation_param_cmd_send(void *wmi_hdl, + struct thermal_mitigation_params *param) +{ + wmi_unified_t wmi = (wmi_unified_t) wmi_hdl; + + if (wmi->ops->send_thermal_mitigation_param_cmd) + return wmi->ops->send_thermal_mitigation_param_cmd(wmi, param); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_vdev_set_neighbour_rx_cmd_send() - WMI set neighbour rx function + * @param wmi_handle : handle to WMI. + * @param macaddr : MAC address + * @param param : pointer to hold neighbour rx parameter + * + * @return QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_vdev_set_neighbour_rx_cmd_send(void *wmi_hdl, + uint8_t macaddr[IEEE80211_ADDR_LEN], + struct set_neighbour_rx_params *param) +{ + wmi_unified_t wmi = (wmi_unified_t) wmi_hdl; + + if (wmi->ops->send_vdev_set_neighbour_rx_cmd) + return wmi->ops->send_vdev_set_neighbour_rx_cmd(wmi, + macaddr, param); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_vdev_set_fwtest_param_cmd_send() - WMI set fwtest function + * @param wmi_handle : handle to WMI. + * @param param : pointer to hold fwtest param + * + * @return QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_vdev_set_fwtest_param_cmd_send(void *wmi_hdl, + struct set_fwtest_params *param) +{ + wmi_unified_t wmi = (wmi_unified_t) wmi_hdl; + + if (wmi->ops->send_vdev_set_fwtest_param_cmd) + return wmi->ops->send_vdev_set_fwtest_param_cmd(wmi, param); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_vdev_config_ratemask_cmd_send() - WMI config ratemask function + * @param wmi_handle : handle to WMI. + * @param param : pointer to hold config ratemask param + * + * @return QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_vdev_config_ratemask_cmd_send(void *wmi_hdl, + struct config_ratemask_params *param) +{ + wmi_unified_t wmi = (wmi_unified_t) wmi_hdl; + + if (wmi->ops->send_vdev_config_ratemask_cmd) + return wmi->ops->send_vdev_config_ratemask_cmd(wmi, param); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_vdev_install_key_cmd_send() - WMI install key function + * @param wmi_handle : handle to WMI. + * @param macaddr : MAC address + * @param param : pointer to hold key parameter + * + * @return QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_vdev_install_key_cmd_send(void *wmi_hdl, + uint8_t macaddr[IEEE80211_ADDR_LEN], + struct vdev_install_key_params *param) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_vdev_install_key_cmd) + return wmi_handle->ops->send_vdev_install_key_cmd(wmi_handle, + macaddr, param); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_pdev_set_regdomain_params_cmd_send() - WMI set regdomain function + * @param wmi_handle : handle to WMI. + * @param param : pointer to hold regdomain param + * + * @return QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_pdev_set_regdomain_cmd_send(void *wmi_hdl, + struct pdev_set_regdomain_params *param) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_pdev_set_regdomain_cmd) + return wmi_handle->ops->send_pdev_set_regdomain_cmd(wmi_handle, + param); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_set_quiet_mode_cmd_send() - WMI set quiet mode function + * @param wmi_handle : handle to WMI. + * @param param : pointer to hold quiet mode param + * + * @return QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_set_quiet_mode_cmd_send(void *wmi_hdl, + struct set_quiet_mode_params *param) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_set_quiet_mode_cmd) + return wmi_handle->ops->send_set_quiet_mode_cmd(wmi_handle, + param); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_set_beacon_filter_cmd_send() - WMI set beacon filter function + * @param wmi_handle : handle to WMI. + * @param param : pointer to hold beacon filter param + * + * @return QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_set_beacon_filter_cmd_send(void *wmi_hdl, + struct set_beacon_filter_params *param) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_set_beacon_filter_cmd) + return wmi_handle->ops->send_set_beacon_filter_cmd(wmi_handle, + param); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_remove_beacon_filter_cmd_send() - WMI set beacon filter function + * @param wmi_handle : handle to WMI. + * @param param : pointer to hold beacon filter param + * + * @return QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_remove_beacon_filter_cmd_send(void *wmi_hdl, + struct remove_beacon_filter_params *param) +{ + wmi_unified_t wmi = (wmi_unified_t) wmi_hdl; + + if (wmi->ops->send_remove_beacon_filter_cmd) + return wmi->ops->send_remove_beacon_filter_cmd(wmi, param); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_mgmt_cmd_send() - WMI mgmt cmd function + * @param wmi_handle : handle to WMI. + * @param macaddr : MAC address + * @param param : pointer to hold mgmt parameter + * + * @return QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +#if 0 +QDF_STATUS wmi_unified_mgmt_cmd_send(void *wmi_hdl, + uint8_t macaddr[IEEE80211_ADDR_LEN], + struct mgmt_params *param) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_mgmt_cmd) + return wmi_handle->ops->send_mgmt_cmd(wmi_handle, + macaddr, param); + + return QDF_STATUS_E_FAILURE; +} +#endif + +/** + * wmi_unified_addba_clearresponse_cmd_send() - WMI addba resp cmd function + * @param wmi_handle : handle to WMI. + * @param macaddr : MAC address + * @param param : pointer to hold addba resp parameter + * + * @return QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_addba_clearresponse_cmd_send(void *wmi_hdl, + uint8_t macaddr[IEEE80211_ADDR_LEN], + struct addba_clearresponse_params *param) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_addba_clearresponse_cmd) + return wmi_handle->ops->send_addba_clearresponse_cmd(wmi_handle, + macaddr, param); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_addba_send_cmd_send() - WMI addba send function + * @param wmi_handle : handle to WMI. + * @param macaddr : MAC address + * @param param : pointer to hold addba parameter + * + * @return QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_addba_send_cmd_send(void *wmi_hdl, + uint8_t macaddr[IEEE80211_ADDR_LEN], + struct addba_send_params *param) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_addba_send_cmd) + return wmi_handle->ops->send_addba_send_cmd(wmi_handle, + macaddr, param); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_delba_send_cmd_send() - WMI delba cmd function + * @param wmi_handle : handle to WMI. + * @param macaddr : MAC address + * @param param : pointer to hold delba parameter + * + * @return QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_delba_send_cmd_send(void *wmi_hdl, + uint8_t macaddr[IEEE80211_ADDR_LEN], + struct delba_send_params *param) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_delba_send_cmd) + return wmi_handle->ops->send_delba_send_cmd(wmi_handle, + macaddr, param); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_addba_setresponse_cmd_send() - WMI addba set resp cmd function + * @param wmi_handle : handle to WMI. + * @param macaddr : MAC address + * @param param : pointer to hold addba set resp parameter + * + * @return QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_addba_setresponse_cmd_send(void *wmi_hdl, + uint8_t macaddr[IEEE80211_ADDR_LEN], + struct addba_setresponse_params *param) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_addba_setresponse_cmd) + return wmi_handle->ops->send_addba_setresponse_cmd(wmi_handle, + macaddr, param); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_singleamsdu_cmd_send() - WMI singleamsdu function + * @param wmi_handle : handle to WMI. + * @param macaddr : MAC address + * @param param : pointer to hold singleamsdu parameter + * + * @return QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_singleamsdu_cmd_send(void *wmi_hdl, + uint8_t macaddr[IEEE80211_ADDR_LEN], + struct singleamsdu_params *param) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_singleamsdu_cmd) + return wmi_handle->ops->send_singleamsdu_cmd(wmi_handle, + macaddr, param); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_set_qboost_param_cmd_send() - WMI set_qboost function + * @param wmi_handle : handle to WMI. + * @param macaddr : MAC address + * @param param : pointer to hold set_qboost parameter + * + * @return QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_set_qboost_param_cmd_send(void *wmi_hdl, + uint8_t macaddr[IEEE80211_ADDR_LEN], + struct set_qboost_params *param) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_set_qboost_param_cmd) + return wmi_handle->ops->send_set_qboost_param_cmd(wmi_handle, + macaddr, param); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_mu_scan_cmd_send() - WMI set mu scan function + * @param wmi_handle : handle to WMI. + * @param param : pointer to hold mu scan param + * + * @return QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_mu_scan_cmd_send(void *wmi_hdl, + struct mu_scan_params *param) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_mu_scan_cmd) + return wmi_handle->ops->send_mu_scan_cmd(wmi_handle, param); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_lteu_config_cmd_send() - WMI set mu scan function + * @param wmi_handle : handle to WMI. + * @param param : pointer to hold mu scan param + * + * @return QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_lteu_config_cmd_send(void *wmi_hdl, + struct lteu_config_params *param) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_lteu_config_cmd) + return wmi_handle->ops->send_lteu_config_cmd(wmi_handle, param); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_set_psmode_cmd_send() - WMI set mu scan function + * @param wmi_handle : handle to WMI. + * @param param : pointer to hold mu scan param + * + * @return QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_set_psmode_cmd_send(void *wmi_hdl, + struct set_ps_mode_params *param) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_set_ps_mode_cmd) + return wmi_handle->ops->send_set_ps_mode_cmd(wmi_handle, param); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_init_cmd_send() - send initialization cmd to fw + * @wmi_handle: wmi handle + * @param tgt_res_cfg: pointer to target resource configuration + * @param num_mem_chunks: Number of memory chunks + * @param mem_chunks: pointer to target memory chunks + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_init_cmd_send(void *wmi_hdl, + target_resource_config *res_cfg, uint8_t num_mem_chunks, + struct wmi_host_mem_chunk *mem_chunk) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->init_cmd_send) + return wmi_handle->ops->init_cmd_send(wmi_handle, res_cfg, + num_mem_chunks, mem_chunk); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_save_service_bitmap() - save service bitmap + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_save_service_bitmap(void *wmi_hdl, void *evt_buf) +{ + struct wmi_unified *wmi_handle = (struct wmi_unified *) wmi_hdl; + + if (wmi_handle->ops->save_service_bitmap) { + wmi_handle->ops->save_service_bitmap(wmi_handle, evt_buf); + return 0; + } + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_save_fw_version() - Save fw version + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_save_fw_version(void *wmi_hdl, void *evt_buf) +{ + struct wmi_unified *wmi_handle = (struct wmi_unified *) wmi_hdl; + + if (wmi_handle->ops->save_fw_version) { + wmi_handle->ops->save_fw_version(wmi_handle, evt_buf); + return 0; + } + return QDF_STATUS_E_FAILURE; + +} + +/** + * wmi_check_and_update_fw_version() - Ready and fw version check + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_check_and_update_fw_version(void *wmi_hdl, void *evt_buf) +{ + struct wmi_unified *wmi_handle = (struct wmi_unified *) wmi_hdl; + + if (wmi_handle->ops->check_and_update_fw_version) + return wmi_handle->ops->check_and_update_fw_version(wmi_handle, + evt_buf); + + return QDF_STATUS_E_FAILURE; + +} + +/** + * wmi_service_enabled() - Check if service enabled + * @param wmi_handle: wmi handle + * @param service_id: service identifier + * + * Return: 1 enabled, 0 disabled + */ +#ifdef WMI_NON_TLV_SUPPORT +bool wmi_service_enabled(void *wmi_hdl, uint32_t service_id) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if ((service_id < wmi_services_max) && + (wmi_handle->services[service_id] != WMI_SERVICE_UNAVAILABLE)) { + if (wmi_handle->ops->is_service_enabled) { + return wmi_handle->ops->is_service_enabled(wmi_handle, + wmi_handle->services[service_id]); + } + } else { + qdf_print("Support not added yet for Service %d\n", service_id); + } + return false; +} +#endif + +/** + * wmi_get_target_cap_from_service_ready() - extract service ready event + * @wmi_handle: wmi handle + * @param evt_buf: pointer to received event buffer + * @param ev: pointer to hold target capability information extracted from even + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_get_target_cap_from_service_ready(void *wmi_hdl, + void *evt_buf, target_capability_info *ev) +{ + wmi_unified_t wmi = (wmi_unified_t) wmi_hdl; + + if (wmi->ops->get_target_cap_from_service_ready) + return wmi->ops->get_target_cap_from_service_ready(wmi, + evt_buf, ev); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_extract_fw_version() - extract fw version + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * @param fw_ver: Pointer to hold fw version + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_extract_fw_version(void *wmi_hdl, + void *evt_buf, struct wmi_host_fw_ver *fw_ver) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->extract_fw_version) + return wmi_handle->ops->extract_fw_version(wmi_handle, + evt_buf, fw_ver); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_extract_fw_abi_version() - extract fw abi version + * @wmi_handle: wmi handle + * @param evt_buf: Pointer to event buffer + * @param fw_ver: Pointer to hold fw abi version + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_extract_fw_abi_version(void *wmi_hdl, + void *evt_buf, struct wmi_host_fw_abi_ver *fw_ver) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->extract_fw_abi_version) + return wmi_handle->ops->extract_fw_abi_version(wmi_handle, + evt_buf, fw_ver); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_extract_hal_reg_cap() - extract HAL registered capabilities + * @wmi_handle: wmi handle + * @param evt_buf: Pointer to event buffer + * @param hal_reg_cap: pointer to hold HAL reg capabilities + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_extract_hal_reg_cap(void *wmi_hdl, void *evt_buf, + TARGET_HAL_REG_CAPABILITIES *hal_reg_cap) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->extract_hal_reg_cap) + return wmi_handle->ops->extract_hal_reg_cap(wmi_handle, + evt_buf, hal_reg_cap); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_extract_host_mem_req_from_service_ready() - Extract host memory + * request event + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * @param num_entries: pointer to hold number of entries requested + * + * Return: Number of entries requested + */ +host_mem_req *wmi_extract_host_mem_req_from_service_ready(void *wmi_hdl, + void *evt_buf, uint8_t *num_entries) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->extract_host_mem_req) + return wmi_handle->ops->extract_host_mem_req(wmi_handle, + evt_buf, num_entries); + + *num_entries = 0; + return NULL; +} + +/** + * wmi_ready_extract_init_status() - Extract init status from ready event + * @wmi_handle: wmi handle + * @param ev: Pointer to event buffer + * + * Return: ready status + */ +uint32_t wmi_ready_extract_init_status(void *wmi_hdl, void *ev) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->ready_extract_init_status) + return wmi_handle->ops->ready_extract_init_status(wmi_handle, + ev); + + + return 1; + +} + +/** + * wmi_ready_extract_mac_addr() - extract mac address from ready event + * @wmi_handle: wmi handle + * @param ev: pointer to event buffer + * @param macaddr: Pointer to hold MAC address + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_ready_extract_mac_addr(void *wmi_hdl, void *ev, uint8_t *macaddr) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->ready_extract_mac_addr) + return wmi_handle->ops->ready_extract_mac_addr(wmi_handle, + ev, macaddr); + + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_extract_dbglog_data_len() - extract debuglog data length + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * @param len: length of buffer + * + * Return: length + */ +uint8_t *wmi_extract_dbglog_data_len(void *wmi_hdl, void *evt_buf, + uint16_t *len) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->extract_dbglog_data_len) + return wmi_handle->ops->extract_dbglog_data_len(wmi_handle, + evt_buf, len); + + + return NULL; +} + +/** + * wmi_send_ext_resource_config() - send extended resource configuration + * @wmi_handle: wmi handle + * @param ext_cfg: pointer to extended resource configuration + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_send_ext_resource_config(void *wmi_hdl, + wmi_host_ext_resource_config *ext_cfg) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_ext_resource_config) + return wmi_handle->ops->send_ext_resource_config(wmi_handle, + ext_cfg); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_nf_dbr_dbm_info_get_cmd_send() - WMI request nf info function + * @param wmi_handle : handle to WMI. + * + * @return QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_nf_dbr_dbm_info_get_cmd_send(void *wmi_hdl) +{ + wmi_unified_t wmi = (wmi_unified_t) wmi_hdl; + + if (wmi->ops->send_nf_dbr_dbm_info_get_cmd) + return wmi->ops->send_nf_dbr_dbm_info_get_cmd(wmi); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_packet_power_info_get_cmd_send() - WMI get packet power info function + * @param wmi_handle : handle to WMI. + * @param param : pointer to hold packet power info param + * + * @return QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_packet_power_info_get_cmd_send(void *wmi_hdl, + struct packet_power_info_params *param) +{ + wmi_unified_t wmi = (wmi_unified_t) wmi_hdl; + + if (wmi->ops->send_packet_power_info_get_cmd) + return wmi->ops->send_packet_power_info_get_cmd(wmi, param); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_gpio_config_cmd_send() - WMI gpio config function + * @param wmi_handle : handle to WMI. + * @param param : pointer to hold gpio config param + * + * @return QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_gpio_config_cmd_send(void *wmi_hdl, + struct gpio_config_params *param) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_gpio_config_cmd) + return wmi_handle->ops->send_gpio_config_cmd(wmi_handle, param); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_gpio_output_cmd_send() - WMI gpio config function + * @param wmi_handle : handle to WMI. + * @param param : pointer to hold gpio config param + * + * @return QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_gpio_output_cmd_send(void *wmi_hdl, + struct gpio_output_params *param) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_gpio_output_cmd) + return wmi_handle->ops->send_gpio_output_cmd(wmi_handle, param); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_rtt_meas_req_test_cmd_send() - WMI rtt meas req test function + * @param wmi_handle : handle to WMI. + * @param param : pointer to hold rtt meas req test param + * + * @return QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_rtt_meas_req_test_cmd_send(void *wmi_hdl, + struct rtt_meas_req_test_params *param) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_rtt_meas_req_test_cmd) + return wmi_handle->ops->send_rtt_meas_req_test_cmd(wmi_handle, + param); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_rtt_meas_req_cmd_send() - WMI rtt meas req function + * @param wmi_handle : handle to WMI. + * @param param : pointer to hold rtt meas req param + * + * @return QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_rtt_meas_req_cmd_send(void *wmi_hdl, + struct rtt_meas_req_params *param) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_rtt_meas_req_cmd) + return wmi_handle->ops->send_rtt_meas_req_cmd(wmi_handle, + param); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_lci_set_cmd_send() - WMI lci set function + * @param wmi_handle : handle to WMI. + * @param param : pointer to hold lci param + * + * @return QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_lci_set_cmd_send(void *wmi_hdl, + struct lci_set_params *param) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_lci_set_cmd) + return wmi_handle->ops->send_lci_set_cmd(wmi_handle, param); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_lcr_set_cmd_send() - WMI lcr set function + * @param wmi_handle : handle to WMI. + * @param param : pointer to hold lcr param + * + * @return QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_lcr_set_cmd_send(void *wmi_hdl, + struct lcr_set_params *param) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_lcr_set_cmd) + return wmi_handle->ops->send_lcr_set_cmd(wmi_handle, param); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_rtt_keepalive_req_cmd_send() - WMI rtt meas req test function + * @param wmi_handle : handle to WMI. + * @param param : pointer to hold rtt meas req test param + * + * @return QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_rtt_keepalive_req_cmd_send(void *wmi_hdl, + struct rtt_keepalive_req_params *param) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_rtt_keepalive_req_cmd) + return wmi_handle->ops->send_rtt_keepalive_req_cmd(wmi_handle, + param); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_send_periodic_chan_stats_config_cmd() - send periodic chan stats cmd + * to fw + * @wmi_handle: wmi handle + * @param: pointer to hold periodic chan stats param + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_send_periodic_chan_stats_config_cmd(void *wmi_hdl, + struct periodic_chan_stats_params *param) +{ + wmi_unified_t wmi = (wmi_unified_t) wmi_hdl; + + if (wmi->ops->send_periodic_chan_stats_config_cmd) + return wmi->ops->send_periodic_chan_stats_config_cmd(wmi, + param); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_send_atf_peer_request_cmd() - send atf peer request command to fw + * @wmi_handle: wmi handle + * @param: pointer to atf peer request param + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS +wmi_send_atf_peer_request_cmd(void *wmi_hdl, + struct atf_peer_request_params *param) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_atf_peer_request_cmd) + return wmi_handle->ops->send_atf_peer_request_cmd(wmi_handle, + param); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_send_set_atf_grouping_cmd() - send set atf grouping command to fw + * @wmi_handle: wmi handle + * @param: pointer to set atf grouping param + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS +wmi_send_set_atf_grouping_cmd(void *wmi_hdl, + struct atf_grouping_params *param) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_set_atf_grouping_cmd) + return wmi_handle->ops->send_set_atf_grouping_cmd(wmi_handle, + param); + + return QDF_STATUS_E_FAILURE; + +} + + +/* Extract - APIs */ +/** + * wmi_extract_wds_addr_event - Extract WDS addr WMI event + * + * @param wmi_handle : handle to WMI. + * @param evt_buf : pointer to event buffer + * @param len : length of the event buffer + * @param wds_ev: pointer to strct to extract + * @return QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_extract_wds_addr_event(void *wmi_hdl, void *evt_buf, + uint16_t len, wds_addr_event_t *wds_ev) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->extract_wds_addr_event) { + return wmi_handle->ops->extract_wds_addr_event(wmi_handle, + evt_buf, len, wds_ev); + } + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_extract_dcs_interference_type() - extract dcs interference type + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * @param interference_type: Pointer to hold interference type + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_extract_dcs_interference_type(void *wmi_hdl, + void *evt_buf, uint32_t *interference_type) +{ + wmi_unified_t wmi = (wmi_unified_t) wmi_hdl; + + if (wmi->ops->extract_dcs_interference_type) { + return wmi->ops->extract_dcs_interference_type(wmi, + evt_buf, interference_type); + } + return QDF_STATUS_E_FAILURE; +} + +/* + * wmi_extract_dcs_cw_int() - extract dcs cw interference from event + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * @param cw_int: Pointer to hold cw interference + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_extract_dcs_cw_int(void *wmi_hdl, void *evt_buf, + wmi_host_ath_dcs_cw_int *cw_int) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->extract_dcs_cw_int) { + return wmi_handle->ops->extract_dcs_cw_int(wmi_handle, + evt_buf, cw_int); + } + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_extract_dcs_im_tgt_stats() - extract dcs im target stats from event + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * @param wlan_stat: Pointer to hold wlan stats + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_extract_dcs_im_tgt_stats(void *wmi_hdl, void *evt_buf, + wmi_host_dcs_im_tgt_stats_t *wlan_stat) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->extract_dcs_im_tgt_stats) { + return wmi_handle->ops->extract_dcs_im_tgt_stats(wmi_handle, + evt_buf, wlan_stat); + } + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_extract_fips_event_error_status() - extract fips event error status + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * @param err_status: Pointer to hold error status + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_extract_fips_event_error_status(void *wmi_hdl, void *evt_buf, + uint32_t *err_status) +{ + wmi_unified_t wmi = (wmi_unified_t) wmi_hdl; + + if (wmi->ops->extract_fips_event_error_status) { + return wmi->ops->extract_fips_event_error_status(wmi, + evt_buf, err_status); + } + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_extract_fips_event_data() - extract fips event data + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * @param data_len: Pointer to hold fips data length + * @param data: Double pointer to hold fips data + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_extract_fips_event_data(void *wmi_hdl, void *evt_buf, + uint32_t *data_len, uint32_t **data) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->extract_fips_event_data) { + return wmi_handle->ops->extract_fips_event_data(wmi_handle, + evt_buf, data_len, data); + } + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_extract_vdev_start_resp() - extract vdev start response + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * @param vdev_rsp: Pointer to hold vdev response + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_extract_vdev_start_resp(void *wmi_hdl, void *evt_buf, + wmi_host_vdev_start_resp *vdev_rsp) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->extract_vdev_start_resp) + return wmi_handle->ops->extract_vdev_start_resp(wmi_handle, + evt_buf, vdev_rsp); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_extract_tbttoffset_update_params() - extract tbtt offset update param + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * @param vdev_map: Pointer to hold vdev map + * @param tbttoffset_list: Pointer to tbtt offset list + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_extract_tbttoffset_update_params(void *wmi_hdl, void *evt_buf, + uint32_t *vdev_map, uint32_t **tbttoffset_list) +{ + wmi_unified_t wmi = (wmi_unified_t) wmi_hdl; + + if (wmi->ops->extract_tbttoffset_update_params) + return wmi->ops->extract_tbttoffset_update_params(wmi, + evt_buf, vdev_map, tbttoffset_list); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_extract_mgmt_rx_params() - extract management rx params from event + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * @param hdr: Pointer to hold header + * @param bufp: Pointer to hold pointer to rx param buffer + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_extract_mgmt_rx_params(void *wmi_hdl, void *evt_buf, + wmi_host_mgmt_rx_hdr *hdr, uint8_t **bufp) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->extract_mgmt_rx_params) + return wmi_handle->ops->extract_mgmt_rx_params(wmi_handle, + evt_buf, hdr, bufp); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_extract_vdev_stopped_param() - extract vdev stop param from event + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * @param vdev_id: Pointer to hold vdev identifier + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_extract_vdev_stopped_param(void *wmi_hdl, void *evt_buf, + uint32_t *vdev_id) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->extract_vdev_stopped_param) + return wmi_handle->ops->extract_vdev_stopped_param(wmi_handle, + evt_buf, vdev_id); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_extract_vdev_roam_param() - extract vdev roam param from event + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * @param param: Pointer to hold roam param + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_extract_vdev_roam_param(void *wmi_hdl, void *evt_buf, + wmi_host_roam_event *param) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->extract_vdev_roam_param) + return wmi_handle->ops->extract_vdev_roam_param(wmi_handle, + evt_buf, param); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_extract_vdev_scan_ev_param() - extract vdev scan param from event + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * @param param: Pointer to hold vdev scan param + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_extract_vdev_scan_ev_param(void *wmi_hdl, void *evt_buf, + wmi_host_scan_event *param) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->extract_vdev_scan_ev_param) + return wmi_handle->ops->extract_vdev_scan_ev_param(wmi_handle, + evt_buf, param); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_extract_mu_ev_param() - extract mu param from event + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * @param param: Pointer to hold mu report + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_extract_mu_ev_param(void *wmi_hdl, void *evt_buf, + wmi_host_mu_report_event *param) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->extract_mu_ev_param) + return wmi_handle->ops->extract_mu_ev_param(wmi_handle, evt_buf, + param); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_extract_pdev_tpc_config_ev_param() - extract pdev tpc configuration + * param from event + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * @param param: Pointer to hold tpc configuration + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_extract_pdev_tpc_config_ev_param(void *wmi_hdl, void *evt_buf, + wmi_host_pdev_tpc_config_event *param) +{ + wmi_unified_t wmi = (wmi_unified_t) wmi_hdl; + + if (wmi->ops->extract_pdev_tpc_config_ev_param) + return wmi->ops->extract_pdev_tpc_config_ev_param(wmi, + evt_buf, param); + + return QDF_STATUS_E_FAILURE; + +} + +/** + * wmi_extract_gpio_input_ev_param() - extract gpio input param from event + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * @param gpio_num: Pointer to hold gpio number + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_extract_gpio_input_ev_param(void *wmi_hdl, + void *evt_buf, uint32_t *gpio_num) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->extract_gpio_input_ev_param) + return wmi_handle->ops->extract_gpio_input_ev_param(wmi_handle, + evt_buf, gpio_num); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_extract_pdev_reserve_ast_ev_param() - extract reserve ast entry + * param from event + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * @param result: Pointer to hold reserve ast entry param + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_extract_pdev_reserve_ast_ev_param(void *wmi_hdl, + void *evt_buf, uint32_t *result) +{ + wmi_unified_t wmi = (wmi_unified_t) wmi_hdl; + + if (wmi->ops->extract_pdev_reserve_ast_ev_param) + return wmi->ops->extract_pdev_reserve_ast_ev_param(wmi, + evt_buf, result); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_extract_nfcal_power_ev_param() - extract noise floor calibration + * power param from event + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * @param param: Pointer to hold nf cal power param + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_extract_nfcal_power_ev_param(void *wmi_hdl, void *evt_buf, + wmi_host_pdev_nfcal_power_all_channels_event *param) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->extract_nfcal_power_ev_param) + return wmi_handle->ops->extract_nfcal_power_ev_param(wmi_handle, + evt_buf, param); + + return QDF_STATUS_E_FAILURE; + +} + +/** + * wmi_extract_pdev_tpc_ev_param() - extract tpc param from event + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * @param param: Pointer to hold tpc param + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_extract_pdev_tpc_ev_param(void *wmi_hdl, void *evt_buf, + wmi_host_pdev_tpc_event *param) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->extract_pdev_tpc_ev_param) + return wmi_handle->ops->extract_pdev_tpc_ev_param(wmi_handle, + evt_buf, param); + + return QDF_STATUS_E_FAILURE; + +} + +/** + * wmi_extract_pdev_generic_buffer_ev_param() - extract pdev generic buffer + * from event + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * @param param: Pointer to generic buffer param + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_extract_pdev_generic_buffer_ev_param(void *wmi_hdl, + void *evt_buf, wmi_host_pdev_generic_buffer_event *param) +{ + wmi_unified_t wmi = (wmi_unified_t) wmi_hdl; + + if (wmi->ops->extract_pdev_generic_buffer_ev_param) + return wmi->ops->extract_pdev_generic_buffer_ev_param(wmi, + evt_buf, param); + + return QDF_STATUS_E_FAILURE; + +} + +/** + * wmi_extract_mgmt_tx_compl_param() - extract mgmt tx completion param + * from event + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * @param param: Pointer to mgmt tx completion param + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_extract_mgmt_tx_compl_param(void *wmi_hdl, void *evt_buf, + wmi_host_mgmt_tx_compl_event *param) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->extract_mgmt_tx_compl_param) + return wmi_handle->ops->extract_mgmt_tx_compl_param(wmi_handle, + evt_buf, param); + + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_extract_swba_vdev_map() - extract swba vdev map from event + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * @param vdev_map: Pointer to hold vdev map + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_extract_swba_vdev_map(void *wmi_hdl, void *evt_buf, + uint32_t *vdev_map) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->extract_swba_vdev_map) + return wmi_handle->ops->extract_swba_vdev_map(wmi_handle, + evt_buf, vdev_map); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_extract_swba_tim_info() - extract swba tim info from event + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * @param idx: Index to bcn info + * @param tim_info: Pointer to hold tim info + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_extract_swba_tim_info(void *wmi_hdl, void *evt_buf, + uint32_t idx, wmi_host_tim_info *tim_info) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->extract_swba_tim_info) + return wmi_handle->ops->extract_swba_tim_info(wmi_handle, + evt_buf, idx, tim_info); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_extract_swba_noa_info() - extract swba NoA information from event + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * @param idx: Index to bcn info + * @param p2p_desc: Pointer to hold p2p NoA info + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_extract_swba_noa_info(void *wmi_hdl, void *evt_buf, + uint32_t idx, wmi_host_p2p_noa_info *p2p_desc) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->extract_swba_noa_info) + return wmi_handle->ops->extract_swba_noa_info(wmi_handle, + evt_buf, idx, p2p_desc); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_extract_peer_sta_ps_statechange_ev() - extract peer sta ps state + * from event + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * @param ev: Pointer to hold peer param and ps state + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_extract_peer_sta_ps_statechange_ev(void *wmi_hdl, void *evt_buf, + wmi_host_peer_sta_ps_statechange_event *ev) +{ + wmi_unified_t wmi = (wmi_unified_t) wmi_hdl; + + if (wmi->ops->extract_peer_sta_ps_statechange_ev) + return wmi->ops->extract_peer_sta_ps_statechange_ev(wmi, + evt_buf, ev); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_extract_peer_sta_kickout_ev() - extract peer sta kickout event + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * @param ev: Pointer to hold peer param + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_extract_peer_sta_kickout_ev(void *wmi_hdl, void *evt_buf, + wmi_host_peer_sta_kickout_event *ev) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->extract_peer_sta_kickout_ev) + return wmi_handle->ops->extract_peer_sta_kickout_ev(wmi_handle, + evt_buf, ev); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_extract_peer_ratecode_list_ev() - extract peer ratecode from event + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * @param peer_mac: Pointer to hold peer mac address + * @param rate_cap: Pointer to hold ratecode + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_extract_peer_ratecode_list_ev(void *wmi_hdl, void *evt_buf, + uint8_t *peer_mac, wmi_sa_rate_cap *rate_cap) +{ + wmi_unified_t wmi = (wmi_unified_t) wmi_hdl; + + if (wmi->ops->extract_peer_ratecode_list_ev) + return wmi->ops->extract_peer_ratecode_list_ev(wmi, + evt_buf, peer_mac, rate_cap); + + return QDF_STATUS_E_FAILURE; + +} + +/** + * wmi_extract_comb_phyerr() - extract comb phy error from event + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * @param datalen: data length of event buffer + * @param buf_offset: Pointer to hold value of current event buffer offset + * post extraction + * @param phyer: Pointer to hold phyerr + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_extract_comb_phyerr(void *wmi_hdl, void *evt_buf, + uint16_t datalen, uint16_t *buf_offset, wmi_host_phyerr_t *phyerr) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->extract_comb_phyerr) + return wmi_handle->ops->extract_comb_phyerr(wmi_handle, + evt_buf, datalen, buf_offset, phyerr); + + return QDF_STATUS_E_FAILURE; + +} + +/** + * wmi_extract_single_phyerr() - extract single phy error from event + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * @param datalen: data length of event buffer + * @param buf_offset: Pointer to hold value of current event buffer offset + * post extraction + * @param phyerr: Pointer to hold phyerr + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_extract_single_phyerr(void *wmi_hdl, void *evt_buf, + uint16_t datalen, uint16_t *buf_offset, wmi_host_phyerr_t *phyerr) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->extract_single_phyerr) + return wmi_handle->ops->extract_single_phyerr(wmi_handle, + evt_buf, datalen, buf_offset, phyerr); + + return QDF_STATUS_E_FAILURE; + +} + +/** + * wmi_extract_composite_phyerr() - extract composite phy error from event + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * @param datalen: Length of event buffer + * @param phyerr: Pointer to hold phy error + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_extract_composite_phyerr(void *wmi_hdl, void *evt_buf, + uint16_t datalen, wmi_host_phyerr_t *phyerr) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->extract_composite_phyerr) + return wmi_handle->ops->extract_composite_phyerr(wmi_handle, + evt_buf, datalen, phyerr); + + return QDF_STATUS_E_FAILURE; + +} + +/** + * wmi_extract_stats_param() - extract all stats count from event + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * @param stats_param: Pointer to hold stats count + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_extract_stats_param(void *wmi_hdl, void *evt_buf, + wmi_host_stats_event *stats_param) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->extract_all_stats_count) + return wmi_handle->ops->extract_all_stats_count(wmi_handle, + evt_buf, stats_param); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_extract_pdev_stats() - extract pdev stats from event + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * @param index: Index into pdev stats + * @param pdev_stats: Pointer to hold pdev stats + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_extract_pdev_stats(void *wmi_hdl, void *evt_buf, + uint32_t index, wmi_host_pdev_stats *pdev_stats) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->extract_pdev_stats) + return wmi_handle->ops->extract_pdev_stats(wmi_handle, + evt_buf, index, pdev_stats); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_extract_pdev_ext_stats() - extract extended pdev stats from event + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * @param index: Index into extended pdev stats + * @param pdev_ext_stats: Pointer to hold extended pdev stats + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_extract_pdev_ext_stats(void *wmi_hdl, void *evt_buf, + uint32_t index, wmi_host_pdev_ext_stats *pdev_ext_stats) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->extract_pdev_ext_stats) + return wmi_handle->ops->extract_pdev_ext_stats(wmi_handle, + evt_buf, index, pdev_ext_stats); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_extract_peer_stats() - extract peer stats from event + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * @param index: Index into peer stats + * @param peer_stats: Pointer to hold peer stats + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_extract_peer_stats(void *wmi_hdl, void *evt_buf, + uint32_t index, wmi_host_peer_stats *peer_stats) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->extract_peer_stats) + return wmi_handle->ops->extract_peer_stats(wmi_handle, + evt_buf, index, peer_stats); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_extract_vdev_stats() - extract vdev stats from event + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * @param index: Index into vdev stats + * @param vdev_stats: Pointer to hold vdev stats + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_extract_vdev_stats(void *wmi_hdl, void *evt_buf, + uint32_t index, wmi_host_vdev_stats *vdev_stats) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->extract_vdev_stats) + return wmi_handle->ops->extract_vdev_stats(wmi_handle, + evt_buf, index, vdev_stats); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_extract_rtt_hdr() - extract rtt header from event + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * @param ev: Pointer to hold rtt header + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_extract_rtt_hdr(void *wmi_hdl, void *evt_buf, + wmi_host_rtt_event_hdr *ev) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->extract_rtt_hdr) + return wmi_handle->ops->extract_rtt_hdr(wmi_handle, + evt_buf, ev); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_extract_bcnflt_stats() - extract bcn fault stats from event + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * @param index: Index into bcn fault stats + * @param bcnflt_stats: Pointer to hold bcn fault stats + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_extract_bcnflt_stats(void *wmi_hdl, void *evt_buf, + uint32_t index, wmi_host_bcnflt_stats *bcnflt_stats) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->extract_bcnflt_stats) + return wmi_handle->ops->extract_bcnflt_stats(wmi_handle, + evt_buf, index, bcnflt_stats); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_extract_rtt_ev() - extract rtt event + * @wmi_handle: wmi handle + * @param evt_buf: Pointer to event buffer + * @param ev: Pointer to hold rtt event + * @param hdump: Pointer to hold hex dump + * @param hdump_len: hex dump length + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_extract_rtt_ev(void *wmi_hdl, void *evt_buf, + wmi_host_rtt_meas_event *ev, uint8_t *hdump, uint16_t hdump_len) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->extract_rtt_ev) + return wmi_handle->ops->extract_rtt_ev(wmi_handle, + evt_buf, ev, hdump, hdump_len); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_extract_peer_extd_stats() - extract extended peer stats from event + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * @param index: Index into extended peer stats + * @param peer_extd_stats: Pointer to hold extended peer stats + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_extract_peer_extd_stats(void *wmi_hdl, void *evt_buf, + uint32_t index, wmi_host_peer_extd_stats *peer_extd_stats) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->extract_peer_extd_stats) + return wmi_handle->ops->extract_peer_extd_stats(wmi_handle, + evt_buf, index, peer_extd_stats); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_extract_rtt_error_report_ev() - extract rtt error report from event + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * @param wds_ev: Pointer to hold rtt error report + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_extract_rtt_error_report_ev(void *wmi_hdl, void *evt_buf, + wmi_host_rtt_error_report_event *ev) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->extract_rtt_error_report_ev) + return wmi_handle->ops->extract_rtt_error_report_ev(wmi_handle, + evt_buf, ev); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_extract_chan_stats() - extract chan stats from event + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * @param index: Index into chan stats + * @param chanstats: Pointer to hold chan stats + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_extract_chan_stats(void *wmi_hdl, void *evt_buf, + uint32_t index, wmi_host_chan_stats *chan_stats) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->extract_chan_stats) + return wmi_handle->ops->extract_chan_stats(wmi_handle, + evt_buf, index, chan_stats); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_extract_thermal_stats() - extract thermal stats from event + * @wmi_handle: wmi handle + * @param evt_buf: Pointer to event buffer + * @param temp: Pointer to hold extracted temperature + * @param level: Pointer to hold extracted level + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_extract_thermal_stats(void *wmi_hdl, void *evt_buf, + uint32_t *temp, uint32_t *level) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->extract_thermal_stats) + return wmi_handle->ops->extract_thermal_stats(wmi_handle, + evt_buf, temp, level); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_extract_profile_ctx() - extract profile context from event + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * @param profile_ctx: Pointer to hold profile context + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_extract_profile_ctx(void *wmi_hdl, void *evt_buf, + wmi_host_wlan_profile_ctx_t *profile_ctx) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->extract_profile_ctx) + return wmi_handle->ops->extract_profile_ctx(wmi_handle, + evt_buf, profile_ctx); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_extract_thermal_level_stats() - extract thermal level stats from + * event + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * @param idx: Index to level stats + * @param levelcount: Pointer to hold levelcount + * @param dccount: Pointer to hold dccount + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_extract_thermal_level_stats(void *wmi_hdl, void *evt_buf, + uint8_t idx, uint32_t *levelcount, uint32_t *dccount) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->extract_thermal_level_stats) + return wmi_handle->ops->extract_thermal_level_stats(wmi_handle, + evt_buf, idx, levelcount, dccount); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_extract_profile_data() - extract profile data from event + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * @idx index: index of profile data + * @param profile_data: Pointer to hold profile data + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_extract_profile_data(void *wmi_hdl, void *evt_buf, uint8_t idx, + wmi_host_wlan_profile_t *profile_data) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->extract_profile_data) + return wmi_handle->ops->extract_profile_data(wmi_handle, + evt_buf, idx, profile_data); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_extract_chan_info_event() - extract chan information from event + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * @param chan_info: Pointer to hold chan information + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_extract_chan_info_event(void *wmi_hdl, void *evt_buf, + wmi_host_chan_info_event *chan_info) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->extract_chan_info_event) + return wmi_handle->ops->extract_chan_info_event(wmi_handle, + evt_buf, chan_info); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_extract_channel_hopping_event() - extract channel hopping param + * from event + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * @param ch_hopping: Pointer to hold channel hopping param + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_extract_channel_hopping_event(void *wmi_hdl, void *evt_buf, + wmi_host_pdev_channel_hopping_event *ch_hopping) +{ + wmi_unified_t wmi = (wmi_unified_t) wmi_hdl; + + if (wmi->ops->extract_channel_hopping_event) + return wmi->ops->extract_channel_hopping_event(wmi, + evt_buf, ch_hopping); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_extract_bss_chan_info_event() - extract bss channel information + * from event + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * @param bss_chan_info: Pointer to hold bss channel information + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_extract_bss_chan_info_event(void *wmi_hdl, void *evt_buf, + wmi_host_pdev_bss_chan_info_event *bss_chan_info) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->extract_bss_chan_info_event) + return wmi_handle->ops->extract_bss_chan_info_event(wmi_handle, + evt_buf, bss_chan_info); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_extract_inst_rssi_stats_event() - extract inst rssi stats from event + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * @param inst_rssi_resp: Pointer to hold inst rssi response + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_extract_inst_rssi_stats_event(void *wmi_hdl, void *evt_buf, + wmi_host_inst_stats_resp *inst_rssi_resp) +{ + wmi_unified_t wmi = (wmi_unified_t) wmi_hdl; + + if (wmi->ops->extract_inst_rssi_stats_event) + return wmi->ops->extract_inst_rssi_stats_event(wmi, + evt_buf, inst_rssi_resp); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_extract_tx_data_traffic_ctrl_ev() - extract tx data traffic control + * from event + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * @param index: Index into chan stats + * @param ev: Pointer to hold data traffic control + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_extract_tx_data_traffic_ctrl_ev(void *wmi_hdl, void *evt_buf, + wmi_host_tx_data_traffic_ctrl_event *ev) +{ + wmi_unified_t wmi = (wmi_unified_t) wmi_hdl; + + if (wmi->ops->extract_tx_data_traffic_ctrl_ev) + return wmi->ops->extract_tx_data_traffic_ctrl_ev(wmi, + evt_buf, ev); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_extract_vdev_extd_stats() - extract extended vdev stats from event + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * @param index: Index into extended vdev stats + * @param vdev_extd_stats: Pointer to hold extended vdev stats + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_extract_vdev_extd_stats(void *wmi_hdl, void *evt_buf, + uint32_t index, wmi_host_vdev_extd_stats *vdev_extd_stats) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->extract_vdev_extd_stats) + return wmi_handle->ops->extract_vdev_extd_stats(wmi_handle, + evt_buf, index, vdev_extd_stats); + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_send_adapt_dwelltime_params_cmd() - send wmi cmd of + * adaptive dwelltime configuration params + * @wma_handle: wma handler + * @dwelltime_params: pointer to dwelltime_params + * + * Return: QDF_STATUS_SUCCESS on success and QDF failure reason code for failure + */ +QDF_STATUS wmi_unified_send_adapt_dwelltime_params_cmd(void *wmi_hdl, + struct wmi_adaptive_dwelltime_params *dwelltime_params) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_adapt_dwelltime_params_cmd) + return wmi_handle->ops-> + send_adapt_dwelltime_params_cmd(wmi_handle, + dwelltime_params); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_send_power_dbg_cmd() - send power debug commands + * @wmi_handle: wmi handle + * @param: wmi power debug parameter + * + * Send WMI_POWER_DEBUG_CMDID parameters to fw. + * + * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_** on error + */ +QDF_STATUS wmi_unified_send_power_dbg_cmd(void *wmi_hdl, + struct wmi_power_dbg_params *param) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_power_dbg_cmd) + return wmi_handle->ops->send_power_dbg_cmd(wmi_handle, + param); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_send_sar_limit_cmd() - send sar limit cmd to fw + * @wmi_hdl: wmi handle + * @params: sar limit command params + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_send_sar_limit_cmd(void *wmi_hdl, + struct sar_limit_cmd_params *params) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_sar_limit_cmd) + return wmi_handle->ops->send_sar_limit_cmd( + wmi_handle, + params); + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_encrypt_decrypt_send_cmd() - send encryptdecrypt cmd to fw + * @wmi_hdl: wmi handle + * @params: encrypt/decrypt params + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_encrypt_decrypt_send_cmd(void *wmi_hdl, + struct encrypt_decrypt_req_params *params) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_encrypt_decrypt_send_cmd) + return wmi_handle->ops->send_encrypt_decrypt_send_cmd( + wmi_handle, + params); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_get_rcpi_cmd() - get rcpi request + * @wmi_hdl: wma handle + * @get_rcpi_param: rcpi params + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_get_rcpi_cmd(void *wmi_hdl, + struct rcpi_req *get_rcpi_param) +{ + wmi_unified_t wmi_handle = (wmi_unified_t) wmi_hdl; + + if (wmi_handle->ops->send_get_rcpi_cmd) + return wmi_handle->ops->send_get_rcpi_cmd(wmi_handle, + get_rcpi_param); + + return QDF_STATUS_E_FAILURE; +} diff --git a/drivers/staging/qca-wifi-host-cmn/wmi/src/wmi_unified_non_tlv.c b/drivers/staging/qca-wifi-host-cmn/wmi/src/wmi_unified_non_tlv.c new file mode 100644 index 0000000000000000000000000000000000000000..9511b7730f0e57f7118313841f092fdd1ca1302b --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/wmi/src/wmi_unified_non_tlv.c @@ -0,0 +1,8039 @@ +/* + * Copyright (c) 2016-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#include "athdefs.h" +#include "osapi_linux.h" +#include "a_types.h" +#include "a_debug.h" +#include "ol_if_athvar.h" +#include "ol_defines.h" +#include "wmi_unified_api.h" +#include "wmi_unified_priv.h" + +#ifdef WMI_NON_TLV_SUPPORT +#include "legacy/wmi.h" +#include "legacy/wmi_unified.h" +/** + * send_vdev_create_cmd_non_tlv() - send VDEV create command to fw + * @wmi_handle: wmi handle + * @param: pointer to hold vdev create parameter + * @macaddr: vdev mac address + * + * Return: 0 for success or error code + */ +QDF_STATUS send_vdev_create_cmd_non_tlv(wmi_unified_t wmi_handle, + uint8_t macaddr[IEEE80211_ADDR_LEN], + struct vdev_create_params *param) +{ + wmi_vdev_create_cmd *cmd; + wmi_buf_t buf; + int32_t len = sizeof(wmi_vdev_create_cmd); + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + qdf_print("%s:wmi_buf_alloc failed\n", __func__); + return QDF_STATUS_E_NOMEM; + } + cmd = (wmi_vdev_create_cmd *)wmi_buf_data(buf); + cmd->vdev_id = param->if_id; + cmd->vdev_type = param->type; + cmd->vdev_subtype = param->subtype; + WMI_CHAR_ARRAY_TO_MAC_ADDR(macaddr, &cmd->vdev_macaddr); + qdf_print("%s: ID = %d Type = %d, Subtype = %d " + "VAP Addr = %02x:%02x:%02x:%02x:%02x:%02x:\n", + __func__, param->if_id, param->type, param->subtype, + macaddr[0], macaddr[1], macaddr[2], + macaddr[3], macaddr[4], macaddr[5]); + return wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_VDEV_CREATE_CMDID); +} + +/** + * send_vdev_delete_cmd_non_tlv() - send VDEV delete command to fw + * @wmi_handle: wmi handle + * @if_id: vdev id + * + * Return: 0 for success or error code + */ +QDF_STATUS send_vdev_delete_cmd_non_tlv(wmi_unified_t wmi_handle, + uint8_t if_id) +{ + wmi_vdev_delete_cmd *cmd; + wmi_buf_t buf; + int32_t len = sizeof(wmi_vdev_delete_cmd); + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + qdf_print("%s:wmi_buf_alloc failed\n", __func__); + return QDF_STATUS_E_NOMEM; + } + cmd = (wmi_vdev_delete_cmd *)wmi_buf_data(buf); + cmd->vdev_id = if_id; + qdf_print("%s for vap %d (%p)\n", __func__, if_id, wmi_handle); + return wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_VDEV_DELETE_CMDID); +} + +/** + * send_vdev_stop_cmd_non_tlv() - send vdev stop command to fw + * @wmi: wmi handle + * @vdev_id: vdev id + * + * Return: 0 for success or erro code + */ +QDF_STATUS send_vdev_stop_cmd_non_tlv(wmi_unified_t wmi, + uint8_t vdev_id) +{ + wmi_vdev_stop_cmd *cmd; + wmi_buf_t buf; + int len = sizeof(wmi_vdev_stop_cmd); + + buf = wmi_buf_alloc(wmi, len); + if (!buf) { + qdf_print("%s:wmi_buf_alloc failed\n", __func__); + return QDF_STATUS_E_NOMEM; + } + cmd = (wmi_vdev_stop_cmd *)wmi_buf_data(buf); + cmd->vdev_id = vdev_id; + + return wmi_unified_cmd_send(wmi, buf, len, WMI_VDEV_STOP_CMDID); +} + +/** + * send_vdev_down_cmd_non_tlv() - send vdev down command to fw + * @wmi_handle: wmi handle + * @vdev_id: vdev id + * + * Return: 0 for success or error code + */ +QDF_STATUS send_vdev_down_cmd_non_tlv(wmi_unified_t wmi_handle, + uint8_t vdev_id) +{ + wmi_vdev_down_cmd *cmd; + wmi_buf_t buf; + int len = sizeof(wmi_vdev_down_cmd); + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + qdf_print("%s:wmi_buf_alloc failed\n", __func__); + return QDF_STATUS_E_NOMEM; + } + cmd = (wmi_vdev_down_cmd *)wmi_buf_data(buf); + cmd->vdev_id = vdev_id; + qdf_print("%s for vap %d (%p)\n", __func__, vdev_id, wmi_handle); + return wmi_unified_cmd_send(wmi_handle, buf, len, WMI_VDEV_DOWN_CMDID); +} + +/** + * send_vdev_start_cmd_non_tlv() - send vdev start command to fw + * @wmi: wmi handle + * @vdev_id: vdev id + * + * Return: 0 for success or error code + */ +QDF_STATUS send_vdev_start_cmd_non_tlv(wmi_unified_t wmi, + struct vdev_start_params *param) +{ + wmi_vdev_start_request_cmd *cmd; + wmi_buf_t buf; + int len = sizeof(wmi_vdev_start_request_cmd); + int ret; + + buf = wmi_buf_alloc(wmi, len); + if (!buf) { + qdf_print("%s:wmi_buf_alloc failed\n", __func__); + return QDF_STATUS_E_NOMEM; + } + + cmd = (wmi_vdev_start_request_cmd *)wmi_buf_data(buf); + cmd->vdev_id = param->vdev_id; + + cmd->chan.mhz = param->channel.mhz; + + WMI_SET_CHANNEL_MODE(&cmd->chan, param->channel.phy_mode); + + cmd->chan.band_center_freq1 = param->channel.cfreq1; + cmd->chan.band_center_freq2 = param->channel.cfreq2; + cmd->disable_hw_ack = param->disable_hw_ack; + + WMI_SET_CHANNEL_MIN_POWER(&cmd->chan, param->channel.minpower); + WMI_SET_CHANNEL_MAX_POWER(&cmd->chan, param->channel.maxpower); + WMI_SET_CHANNEL_REG_POWER(&cmd->chan, param->channel.maxregpower); + WMI_SET_CHANNEL_ANTENNA_MAX(&cmd->chan, param->channel.antennamax); + WMI_SET_CHANNEL_REG_CLASSID(&cmd->chan, param->channel.reg_class_id); + + if (param->channel.dfs_set) + WMI_SET_CHANNEL_FLAG(&cmd->chan, WMI_CHAN_FLAG_DFS); + + if (param->channel.dfs_set_cfreq2) + WMI_SET_CHANNEL_FLAG(&cmd->chan, WMI_CHAN_FLAG_DFS_CFREQ2); + + if (param->channel.half_rate) + WMI_SET_CHANNEL_FLAG(&cmd->chan, WMI_CHAN_FLAG_HALF); + + if (param->channel.quarter_rate) + WMI_SET_CHANNEL_FLAG(&cmd->chan, WMI_CHAN_FLAG_QUARTER); + + if (param->is_restart) { + qdf_print("VDEV RESTART\n"); + ret = wmi_unified_cmd_send(wmi, buf, len, + WMI_VDEV_RESTART_REQUEST_CMDID); + } else { + qdf_print("VDEV START\n"); + ret = wmi_unified_cmd_send(wmi, buf, len, + WMI_VDEV_START_REQUEST_CMDID); + } + return ret; + +/* +For VDEV_RESTART command, the sequence of code remains the same except the +command sent as WMI_VDEV_RESTART_REQUEST_CMDID instead of START_REQUEST. + +In that case, can we introduce a flag that takes in to check if start or +restart and use the same function?? Currently implemented as two separate +functions in OL layer +*/ +} + +/** + * send_vdev_set_neighbour_rx_cmd_non_tlv() - set neighbour rx param in fw + * @wmi_handle: wmi handle + * @macaddr: vdev mac address + * @param: pointer to hold neigbour rx param + * Return: 0 for success or error code + */ +QDF_STATUS send_vdev_set_neighbour_rx_cmd_non_tlv(wmi_unified_t wmi_handle, + uint8_t macaddr[IEEE80211_ADDR_LEN], + struct set_neighbour_rx_params *param) +{ + wmi_vdev_filter_nrp_config_cmd *cmd; + wmi_buf_t buf; + int len = sizeof(wmi_vdev_filter_nrp_config_cmd); + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + qdf_print("%s:wmi_buf_alloc failed\n", __func__); + return QDF_STATUS_E_FAILURE; + } + cmd = (wmi_vdev_filter_nrp_config_cmd *)wmi_buf_data(buf); + cmd->vdev_id = param->vdev_id; + cmd->bssid_idx = param->idx; + cmd->action = param->action; + cmd->type = param->type; + WMI_CHAR_ARRAY_TO_MAC_ADDR(macaddr, &cmd->addr); + return wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_VDEV_FILTER_NEIGHBOR_RX_PACKETS_CMDID); +} + +/** + * send_vdev_set_fwtest_param_cmd_non_tlv() - send fwtest param in fw + * @wmi_handle: wmi handle + * @param: pointer to hold fwtest param + * + * Return: 0 for success or error code + */ +QDF_STATUS send_vdev_set_fwtest_param_cmd_non_tlv(wmi_unified_t wmi_handle, + struct set_fwtest_params *param) +{ + wmi_fwtest_set_param_cmd *cmd; + wmi_buf_t buf; + int len = sizeof(wmi_fwtest_set_param_cmd); + + buf = wmi_buf_alloc(wmi_handle, len); + + if (!buf) { + qdf_print("%s:wmi_buf_alloc failed\n", __func__); + return QDF_STATUS_E_FAILURE; + } + + cmd = (wmi_fwtest_set_param_cmd *)wmi_buf_data(buf); + cmd->param_id = param->arg; + cmd->param_value = param->value; + + return wmi_unified_cmd_send(wmi_handle, buf, len, WMI_FWTEST_CMDID); +} + +/** + * send_vdev_config_ratemask_cmd_non_tlv() - config ratemask param in fw + * @wmi_handle: wmi handle + * @param: pointer to hold config ratemask params + * + * Return: 0 for success or error code + */ +QDF_STATUS send_vdev_config_ratemask_cmd_non_tlv(wmi_unified_t wmi_handle, + struct config_ratemask_params *param) +{ + wmi_vdev_config_ratemask *cmd; + wmi_buf_t buf; + int len = sizeof(wmi_vdev_config_ratemask); + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + qdf_print("%s:wmi_buf_alloc failed\n", __func__); + return QDF_STATUS_E_FAILURE; + } + cmd = (wmi_vdev_config_ratemask *)wmi_buf_data(buf); + cmd->vdev_id = param->vdev_id; + cmd->type = param->type; + cmd->mask_lower32 = param->lower32; + cmd->mask_higher32 = param->higher32; + qdf_print("Setting vdev ratemask vdev id = 0x%X, type = 0x%X," + "mask_l32 = 0x%X mask_h32 = 0x%X\n", + param->vdev_id, param->type, param->lower32, param->higher32); + return wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_VDEV_RATEMASK_CMDID); +} + +/** + * send_vdev_install_key_cmd_non_tlv() - config security key in fw + * @wmi_handle: wmi handle + * @param: pointer to hold key params + * @macaddr: vdev mac address + * + * Return: 0 for success or error code + */ +QDF_STATUS send_vdev_install_key_cmd_non_tlv(wmi_unified_t wmi_handle, + uint8_t macaddr[IEEE80211_ADDR_LEN], + struct vdev_install_key_params *param) +{ + wmi_vdev_install_key_cmd *cmd; + wmi_buf_t buf; + /* length depends on ieee key length */ + int len = sizeof(wmi_vdev_install_key_cmd) + param->wk_keylen; + uint8_t wmi_cipher_type; + int i; + + /* Cipher MAP has to be in the same order as ieee80211_cipher_type */ + static const u_int8_t wmi_ciphermap[] = { + WMI_CIPHER_WEP, /* IEEE80211_CIPHER_WEP */ + WMI_CIPHER_TKIP, /* IEEE80211_CIPHER_TKIP */ + WMI_CIPHER_AES_OCB, /* IEEE80211_CIPHER_AES_OCB */ + WMI_CIPHER_AES_CCM, /* IEEE80211_CIPHER_AES_CCM */ +#if ATH_SUPPORT_WAPI + WMI_CIPHER_WAPI, /* IEEE80211_CIPHER_WAPI */ +#else + (u_int8_t) 0xff, /* IEEE80211_CIPHER_WAPI */ +#endif + WMI_CIPHER_CKIP, /* IEEE80211_CIPHER_CKIP */ + WMI_CIPHER_AES_CMAC, + WMI_CIPHER_AES_CCM, /* IEEE80211_CIPHER_AES_CCM 256 */ + WMI_CIPHER_AES_CMAC, + WMI_CIPHER_AES_GCM, /* IEEE80211_CIPHER_AES_GCM */ + WMI_CIPHER_AES_GCM, /* IEEE80211_CIPHER_AES_GCM 256 */ + WMI_CIPHER_AES_GMAC, + WMI_CIPHER_AES_GMAC, + WMI_CIPHER_NONE, /* IEEE80211_CIPHER_NONE */ + }; + + if (param->force_none == 1) { + wmi_cipher_type = WMI_CIPHER_NONE; + } else if ((!param->is_host_based_crypt)) { + KASSERT(param->ic_cipher < + (sizeof(wmi_ciphermap)/sizeof(wmi_ciphermap[0])), + ("invalid cipher type %u", param->ic_cipher)); + wmi_cipher_type = wmi_ciphermap[param->ic_cipher]; + } else + wmi_cipher_type = WMI_CIPHER_NONE; + + /* ieee_key length does not have mic keylen */ + if ((wmi_cipher_type == WMI_CIPHER_TKIP) || + (wmi_cipher_type == WMI_CIPHER_WAPI)) + len = len + IEEE80211_MICBUF_SIZE; + + len = roundup(len, sizeof(u_int32_t)); + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + qdf_print("%s:wmi_buf_alloc failed\n", __func__); + return QDF_STATUS_E_NOMEM; + } + cmd = (wmi_vdev_install_key_cmd *)wmi_buf_data(buf); + + cmd->vdev_id = param->if_id; + WMI_CHAR_ARRAY_TO_MAC_ADDR(macaddr, &cmd->peer_macaddr); + + /* Mapping ieee key flags to WMI key flags */ + if (param->is_group_key) { + cmd->key_flags |= GROUP_USAGE; + /* send the ieee keyix for multicast */ + cmd->key_ix = param->wk_keyix; + } else if (param->is_xmit_or_recv_key) { + cmd->key_flags |= PAIRWISE_USAGE; + /* Target expects keyix 0 for unicast + other than static wep cipher */ + if (param->wk_keyix >= (IEEE80211_WEP_NKID + 1)) + cmd->key_ix = 0; + else + cmd->key_ix = param->wk_keyix; + } + /* If this WEP key is the default xmit key, TX_USAGE flag is enabled */ + if (param->def_keyid == 1) + cmd->key_flags |= TX_USAGE; + + cmd->key_len = param->wk_keylen; + cmd->key_cipher = wmi_cipher_type; + /* setting the mic lengths. Just Added for TKIP alone */ + if ((wmi_cipher_type == WMI_CIPHER_TKIP) || + (wmi_cipher_type == WMI_CIPHER_WAPI)) { + cmd->key_txmic_len = 8; + cmd->key_rxmic_len = 8; + } + + /* target will use the same rsc counter for + various tids from from ieee key rsc */ + if ((wmi_cipher_type == WMI_CIPHER_TKIP) || + (wmi_cipher_type == WMI_CIPHER_AES_OCB) + || (wmi_cipher_type == WMI_CIPHER_AES_CCM)) { + qdf_mem_copy(&cmd->key_rsc_counter, ¶m->wk_keyrsc[0], + sizeof(param->wk_keyrsc[0])); + qdf_mem_copy(&cmd->key_tsc_counter, ¶m->wk_keytsc, + sizeof(param->wk_keytsc)); + } + +#ifdef ATH_SUPPORT_WAPI + if (wmi_cipher_type == WMI_CIPHER_WAPI) { + int j; + /* For WAPI, TSC and RSC has to be initialized with predefined + * value.Here, Indicating TSC, RSC to target as part of set + * key message + */ + /* since wk_recviv and wk_txiv initialized in reverse order, + * Before indicating the Target FW, Reversing TSC and RSC + */ + for (i = (WPI_IV_LEN-1), j = 0; i >= 0; i--, j++) + *(((uint8_t *)&cmd->wpi_key_rsc_counter)+j) = + param->wk_recviv[i]; + + for (i = (WPI_IV_LEN/4-1), j = 0; i >= 0; i--, j++) + *(((uint32_t *)&cmd->wpi_key_tsc_counter)+j) = + param->wk_txiv[i]; + + qdf_print("RSC:"); + for (i = 0; i < 16; i++) + qdf_print("0x%x ", + *(((uint8_t *)&cmd->wpi_key_rsc_counter)+i)); + qdf_print("\n"); + + qdf_print("TSC:"); + for (i = 0; i < 16; i++) + qdf_print("0x%x ", + *(((uint8_t *)&cmd->wpi_key_tsc_counter)+i)); + qdf_print("\n"); + } +#endif + + qdf_mem_copy(cmd->key_data, param->key_data, cmd->key_len); + return wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_VDEV_INSTALL_KEY_CMDID); + +} + +/** + * send_peer_flush_tids_cmd_non_tlv() - flush peer tids packets in fw + * @wmi_handle: wmi handle + * @peer_addr: peer mac address + * @param: pointer to hold peer flush tid parameter + * + * Return: 0 for sucess or error code + */ +QDF_STATUS send_peer_flush_tids_cmd_non_tlv(wmi_unified_t wmi_handle, + uint8_t peer_addr[IEEE80211_ADDR_LEN], + struct peer_flush_params *param) +{ + wmi_peer_flush_tids_cmd *cmd; + wmi_buf_t buf; + int len = sizeof(wmi_peer_flush_tids_cmd); + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + qdf_print("%s:wmi_buf_alloc failed\n", __func__); + return QDF_STATUS_E_NOMEM; + } + cmd = (wmi_peer_flush_tids_cmd *)wmi_buf_data(buf); + WMI_CHAR_ARRAY_TO_MAC_ADDR(peer_addr, &cmd->peer_macaddr); + cmd->peer_tid_bitmap = param->peer_tid_bitmap; + cmd->vdev_id = param->vdev_id; + return wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_PEER_FLUSH_TIDS_CMDID); +} + +/** + * send_peer_delete_cmd_non_tlv() - send PEER delete command to fw + * @wmi_handle: wmi handle + * @peer_addr: peer mac addr + * @vdev_id: vdev id + * + * Return: 0 for success or error code + */ +QDF_STATUS send_peer_delete_cmd_non_tlv(wmi_unified_t wmi_handle, + uint8_t + peer_addr[IEEE80211_ADDR_LEN], + uint8_t vdev_id) +{ + wmi_peer_delete_cmd *cmd; + wmi_buf_t buf; + int len = sizeof(wmi_peer_delete_cmd); + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + qdf_print("%s:wmi_buf_alloc failed\n", __func__); + return QDF_STATUS_E_NOMEM; + } + cmd = (wmi_peer_delete_cmd *)wmi_buf_data(buf); + WMI_CHAR_ARRAY_TO_MAC_ADDR(peer_addr, &cmd->peer_macaddr); + cmd->vdev_id = vdev_id; + return wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_PEER_DELETE_CMDID); +} + +/** + * send_peer_param_cmd_non_tlv() - set peer parameter in fw + * @wmi_handle: wmi handle + * @peer_addr: peer mac address + * @param : pointer to hold peer set parameter + * + * Return: 0 for success or error code + */ +QDF_STATUS send_peer_param_cmd_non_tlv(wmi_unified_t wmi_handle, + uint8_t peer_addr[IEEE80211_ADDR_LEN], + struct peer_set_params *param) +{ + wmi_peer_set_param_cmd *cmd; + wmi_buf_t buf; + int len = sizeof(wmi_peer_set_param_cmd); + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + qdf_print("%s: wmi_buf_alloc failed\n", __func__); + return QDF_STATUS_E_NOMEM; + } + cmd = (wmi_peer_set_param_cmd *)wmi_buf_data(buf); + WMI_CHAR_ARRAY_TO_MAC_ADDR(peer_addr, &cmd->peer_macaddr); + cmd->param_id = param->param_id; + cmd->param_value = param->param_value; + cmd->vdev_id = param->vdev_id; + return wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_PEER_SET_PARAM_CMDID); +} + +/** + * send_vdev_up_cmd_non_tlv() - send vdev up command in fw + * @wmi_handle: wmi handle + * @bssid: bssid + * @vdev_up_params: pointer to hold vdev up parameter + * + * Return: 0 for success or error code + */ +QDF_STATUS send_vdev_up_cmd_non_tlv(wmi_unified_t wmi_handle, + uint8_t bssid[IEEE80211_ADDR_LEN], + struct vdev_up_params *param) +{ + wmi_vdev_up_cmd *cmd; + wmi_buf_t buf; + int len = sizeof(wmi_vdev_up_cmd); + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + qdf_print("%s:wmi_buf_alloc failed\n", __func__); + return QDF_STATUS_E_NOMEM; + } + cmd = (wmi_vdev_up_cmd *)wmi_buf_data(buf); + cmd->vdev_id = param->vdev_id; + cmd->vdev_assoc_id = param->assoc_id; + WMI_CHAR_ARRAY_TO_MAC_ADDR(bssid, &cmd->vdev_bssid); + qdf_print("%s for vap %d (%p)\n", __func__, param->vdev_id, wmi_handle); + return wmi_unified_cmd_send(wmi_handle, buf, len, WMI_VDEV_UP_CMDID); +} + +/** + * send_peer_create_cmd_non_tlv() - send peer create command to fw + * @wmi_handle: wmi handle + * @param: pointer to hold peer create parameter + * + * Return: 0 for success or error code + */ +QDF_STATUS send_peer_create_cmd_non_tlv(wmi_unified_t wmi_handle, + struct peer_create_params *param) +{ + wmi_peer_create_cmd *cmd; + wmi_buf_t buf; + int len = sizeof(wmi_peer_create_cmd); + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + qdf_print("%s:wmi_buf_alloc failed\n", __func__); + return QDF_STATUS_E_NOMEM; + } + cmd = (wmi_peer_create_cmd *)wmi_buf_data(buf); + WMI_CHAR_ARRAY_TO_MAC_ADDR(param->peer_addr, &cmd->peer_macaddr); + cmd->vdev_id = param->vdev_id; + return wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_PEER_CREATE_CMDID); +} + +/** + * send_peer_add_wds_entry_cmd_non_tlv() - send peer add command to fw + * @wmi_handle: wmi handle + * @param: pointer holding peer details + * + * Return: 0 for success or error code + */ +QDF_STATUS send_peer_add_wds_entry_cmd_non_tlv(wmi_unified_t wmi_handle, + struct peer_add_wds_entry_params *param) +{ + wmi_peer_add_wds_entry_cmd *cmd; + wmi_buf_t buf; + int len = sizeof(wmi_peer_add_wds_entry_cmd); + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + qdf_print("%s: wmi_buf_alloc failed\n", __func__); + return QDF_STATUS_E_FAILURE; + } + cmd = (wmi_peer_add_wds_entry_cmd *)wmi_buf_data(buf); + WMI_CHAR_ARRAY_TO_MAC_ADDR(param->dest_addr, &cmd->wds_macaddr); + WMI_CHAR_ARRAY_TO_MAC_ADDR(param->peer_addr, &cmd->peer_macaddr); + cmd->flags = param->flags; + return wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_PEER_ADD_WDS_ENTRY_CMDID); +} + +/** + * send_peer_del_wds_entry_cmd_non_tlv() - send peer delete command to fw + * @wmi_handle: wmi handle + * @param: pointer holding peer details + * + * Return: 0 for success or error code + */ +QDF_STATUS send_peer_del_wds_entry_cmd_non_tlv(wmi_unified_t wmi_handle, + struct peer_del_wds_entry_params *param) +{ + wmi_peer_remove_wds_entry_cmd *cmd; + wmi_buf_t buf; + int len = sizeof(wmi_peer_remove_wds_entry_cmd); + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + qdf_print("%s: wmi_buf_alloc failed\n", __func__); + return QDF_STATUS_E_NOMEM; + } + cmd = (wmi_peer_remove_wds_entry_cmd *)wmi_buf_data(buf); + WMI_CHAR_ARRAY_TO_MAC_ADDR(param->dest_addr, &cmd->wds_macaddr); + return wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_PEER_REMOVE_WDS_ENTRY_CMDID); +} + +/** + * send_peer_update_wds_entry_cmd_non_tlv() - send peer update command to fw + * @wmi_handle: wmi handle + * @param: pointer holding peer details + * + * Return: 0 for success or error code + */ +QDF_STATUS send_peer_update_wds_entry_cmd_non_tlv(wmi_unified_t wmi_handle, + struct peer_update_wds_entry_params *param) +{ + wmi_peer_update_wds_entry_cmd *cmd; + wmi_buf_t buf; + int len = sizeof(wmi_peer_update_wds_entry_cmd); + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + qdf_print("%s: wmi_buf_alloc failed\n", __func__); + return QDF_STATUS_E_NOMEM; + } + + /* wmi_buf_alloc returns zeroed command buffer */ + cmd = (wmi_peer_update_wds_entry_cmd *)wmi_buf_data(buf); + cmd->flags = (param->flags) ? WMI_WDS_FLAG_STATIC : 0; + if (param->wds_macaddr) + WMI_CHAR_ARRAY_TO_MAC_ADDR(param->wds_macaddr, + &cmd->wds_macaddr); + if (param->peer_macaddr) + WMI_CHAR_ARRAY_TO_MAC_ADDR(param->peer_macaddr, + &cmd->peer_macaddr); + return wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_PEER_UPDATE_WDS_ENTRY_CMDID); +} + +/** + * send_green_ap_ps_cmd_non_tlv() - enable green ap powersave command + * @wmi_handle: wmi handle + * @value: value + * @mac_id: mac id to have radio context + * + * Return: 0 for success or error code + */ +QDF_STATUS send_green_ap_ps_cmd_non_tlv(wmi_unified_t wmi_handle, + uint32_t value, uint8_t mac_id) +{ + wmi_pdev_green_ap_ps_enable_cmd *cmd; + wmi_buf_t buf; + int len = 0; + int ret; + + len = sizeof(wmi_pdev_green_ap_ps_enable_cmd); + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + qdf_print("%s:wmi_buf_alloc failed\n", __func__); + return QDF_STATUS_E_NOMEM; + } + + cmd = (wmi_pdev_green_ap_ps_enable_cmd *)wmi_buf_data(buf); + cmd->enable = value; + + ret = wmi_unified_cmd_send(wmi_handle, + buf, + len, + WMI_PDEV_GREEN_AP_PS_ENABLE_CMDID); + +#ifdef OL_GREEN_AP_DEBUG_CONFIG_INTERACTIONS + qdf_print("%s: Sent WMI_PDEV_GREEN_AP_PS_ENABLE_CMDID.\n" + "enable=%u status=%d\n", + __func__, + value, + ret); +#endif /* OL_GREEN_AP_DEBUG_CONFIG_INTERACTIONS */ + return ret; +} + +/** + * send_pdev_utf_cmd_non_tlv() - send utf command to fw + * @wmi_handle: wmi handle + * @param: pointer to pdev_utf_params + * @mac_id: mac id to have radio context + * + * Return: 0 for success or error code + */ +QDF_STATUS +send_pdev_utf_cmd_non_tlv(wmi_unified_t wmi_handle, + struct pdev_utf_params *param, + uint8_t mac_id) +{ + wmi_buf_t buf; + u_int8_t *cmd; + int ret = 0; + /* We can initialize the value and increment.*/ + static uint8_t msgref = 1; + uint8_t segNumber = 0, segInfo, numSegments; + uint16_t chunkLen, totalBytes; + uint8_t *bufpos; + struct seg_hdr_info segHdrInfo; + + bufpos = param->utf_payload; + totalBytes = param->len; + numSegments = (uint8_t) (totalBytes / MAX_WMI_UTF_LEN); + + if (param->len - (numSegments * MAX_WMI_UTF_LEN)) + numSegments++; + + while (param->len) { + if (param->len > MAX_WMI_UTF_LEN) + chunkLen = MAX_WMI_UTF_LEN; /* MAX messsage.. */ + else + chunkLen = param->len; + + buf = wmi_buf_alloc(wmi_handle, + (chunkLen + sizeof(segHdrInfo))); + if (!buf) { + qdf_print("%s:wmi_buf_alloc failed\n", __func__); + return QDF_STATUS_E_FAILURE; + } + + cmd = (uint8_t *)wmi_buf_data(buf); + + segHdrInfo.len = totalBytes; + segHdrInfo.msgref = msgref; + segInfo = ((numSegments << 4) & 0xF0) | (segNumber & 0xF); + segHdrInfo.segmentInfo = segInfo; + + segNumber++; + + qdf_mem_copy(cmd, &segHdrInfo, sizeof(segHdrInfo)); +#ifdef BIG_ENDIAN_HOST + if (param->is_ar900b) { + + /* for big endian host, copy engine byte_swap is + * enable But this ART command frame buffer content is + * in network byte order. + * Need to byte swap the mgmt frame buffer content - so + * when copy engine does byte_swap - target gets buffer + * content in the correct order + */ + int i; + uint32_t *destp, *srcp; + destp = (uint32_t *)(&(cmd[sizeof(segHdrInfo)])); + srcp = (uint32_t *)bufpos; + for (i = 0; i < (roundup(chunkLen, + sizeof(uint32_t)) / 4); i++) { + *destp = qdf_le32_to_cpu(*srcp); + destp++; srcp++; + } + } else { + qdf_mem_copy(&cmd[sizeof(segHdrInfo)], + bufpos, chunkLen); + } +#else + qdf_mem_copy(&cmd[sizeof(segHdrInfo)], bufpos, chunkLen); +#endif + + ret = wmi_unified_cmd_send(wmi_handle, buf, + (chunkLen + sizeof(segHdrInfo)), + WMI_PDEV_UTF_CMDID); + + if (ret != 0) + break; + + param->len -= chunkLen; + bufpos += chunkLen; + } + + msgref++; + + return ret; +} + +/** + * send_pdev_qvit_cmd_non_tlv() - send qvit command to fw + * @wmi_handle: wmi handle + * @param: pointer to pdev_qvit_params + * + * Return: 0 for success or error code + */ +QDF_STATUS +send_pdev_qvit_cmd_non_tlv(wmi_unified_t wmi_handle, + struct pdev_qvit_params *param) +{ + wmi_buf_t buf; + u_int8_t *cmd; + int ret = 0; + /* We can initialize the value and increment.*/ + static u_int8_t msgref = 1; + u_int8_t segNumber = 0, segInfo, numSegments; + u_int16_t chunkLen, totalBytes; + u_int8_t *bufpos; + QVIT_SEG_HDR_INFO_STRUCT segHdrInfo; + +/* +#ifdef QVIT_DEBUG + qdf_print(KERN_INFO "QVIT: %s: called\n", __func__); +#endif +*/ + bufpos = param->utf_payload; + totalBytes = param->len; + numSegments = (totalBytes / MAX_WMI_QVIT_LEN); + + if (param->len - (numSegments * MAX_WMI_QVIT_LEN)) + numSegments++; + + while (param->len) { + if (param->len > MAX_WMI_QVIT_LEN) + chunkLen = MAX_WMI_QVIT_LEN; /* MAX messsage.. */ + else + chunkLen = param->len; + + buf = wmi_buf_alloc(wmi_handle, + (chunkLen + sizeof(segHdrInfo))); + if (!buf) { + qdf_print(KERN_ERR "QVIT: %s: wmi_buf_alloc failed\n", + __func__); + return QDF_STATUS_E_FAILURE; + } + + cmd = (u_int8_t *)wmi_buf_data(buf); + + segHdrInfo.len = totalBytes; + segHdrInfo.msgref = msgref; + segInfo = ((numSegments << 4) & 0xF0) | (segNumber & 0xF); + segHdrInfo.segmentInfo = segInfo; + + segNumber++; + + qdf_mem_copy(cmd, &segHdrInfo, sizeof(segHdrInfo)); + qdf_mem_copy(&cmd[sizeof(segHdrInfo)], bufpos, chunkLen); + + ret = wmi_unified_cmd_send(wmi_handle, buf, + (chunkLen + sizeof(segHdrInfo)), + WMI_PDEV_QVIT_CMDID); + if (ret != 0) { + qdf_print + (KERN_ERR "QVIT: %s: wmi_unified_cmd_send failed\n", + __func__); + break; + } + + param->len -= chunkLen; + bufpos += chunkLen; + } + + msgref++; + + return ret; +} + +/** + * send_pdev_param_cmd_non_tlv() - set pdev parameters + * @wmi_handle: wmi handle + * @param: pointer to pdev parameter + * @mac_id: radio context + * + * Return: 0 on success, errno on failure + */ +QDF_STATUS +send_pdev_param_cmd_non_tlv(wmi_unified_t wmi_handle, + struct pdev_params *param, uint8_t mac_id) +{ + wmi_pdev_set_param_cmd *cmd; + wmi_buf_t buf; + int len = sizeof(wmi_pdev_set_param_cmd); + + if ((param->param_id < wmi_pdev_param_max) && + (wmi_handle->pdev_param[param->param_id] + != WMI_UNAVAILABLE_PARAM)) { + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + qdf_print("%s:wmi_buf_alloc failed\n", __func__); + return QDF_STATUS_E_FAILURE; + } + cmd = (wmi_pdev_set_param_cmd *)wmi_buf_data(buf); + cmd->param_id = wmi_handle->pdev_param[param->param_id]; + cmd->param_value = param->param_value; + return wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_PDEV_SET_PARAM_CMDID); + } + return QDF_STATUS_E_FAILURE; +} + +/** + * send_suspend_cmd_non_tlv() - WMI suspend function + * + * @param wmi_handle : handle to WMI. + * @param param : pointer to hold suspend parameter + * @mac_id: radio context + * @return QDF_STATUS_SUCCESS on success and -ve on failure. + */ +QDF_STATUS send_suspend_cmd_non_tlv(wmi_unified_t wmi_handle, + struct suspend_params *param, + uint8_t mac_id) +{ + wmi_pdev_suspend_cmd *cmd; + wmi_buf_t wmibuf; + uint32_t len = sizeof(wmi_pdev_suspend_cmd); + + /*send the comand to Target to ignore the + * PCIE reset so as to ensure that Host and target + * states are in sync*/ + wmibuf = wmi_buf_alloc(wmi_handle, len); + if (wmibuf == NULL) + return QDF_STATUS_E_FAILURE; + + cmd = (wmi_pdev_suspend_cmd *)wmi_buf_data(wmibuf); + if (param->disable_target_intr) + cmd->suspend_opt = WMI_PDEV_SUSPEND_AND_DISABLE_INTR; + else + cmd->suspend_opt = WMI_PDEV_SUSPEND; + + /* + * Flush pending packets in HTC endpoint queue + * + */ + wmi_flush_endpoint(wmi_handle); + + return wmi_unified_cmd_send(wmi_handle, wmibuf, len, + WMI_PDEV_SUSPEND_CMDID); +} + +/** + * send_resume_cmd_non_tlv() - WMI resume function + * + * @param wmi_handle : handle to WMI. + * @mac_id: radio context + * @return QDF_STATUS_SUCCESS on success and -ve on failure. + */ +QDF_STATUS send_resume_cmd_non_tlv(wmi_unified_t wmi_handle, + uint8_t mac_id) +{ + wmi_buf_t wmibuf; + + wmibuf = wmi_buf_alloc(wmi_handle, 0); + if (wmibuf == NULL) + return QDF_STATUS_E_NOMEM; + return wmi_unified_cmd_send(wmi_handle, wmibuf, 0, + WMI_PDEV_RESUME_CMDID); +} + +/** + * send_wow_enable_cmd_non_tlv() - WMI wow enable function + * + * @param wmi_handle : handle to WMI. + * @param param : pointer to hold wow enable parameter + * @mac_id: radio context + * @return QDF_STATUS_SUCCESS on success and -ve on failure. + */ +QDF_STATUS send_wow_enable_cmd_non_tlv(wmi_unified_t wmi_handle, + struct wow_cmd_params *param, uint8_t mac_id) +{ + QDF_STATUS res; + wmi_buf_t buf = NULL; + + buf = wmi_buf_alloc(wmi_handle, 4); + if (!buf) { + qdf_print("buf alloc failed\n"); + return QDF_STATUS_E_NOMEM; + } + res = wmi_unified_cmd_send(wmi_handle, buf, 4, WMI_WOW_ENABLE_CMDID); + qdf_print("send_wow_enable result: %d\n", res); + return (res == QDF_STATUS_SUCCESS) ? + QDF_STATUS_SUCCESS : QDF_STATUS_E_FAILURE; +} + +/** + * send_wow_wakeup_cmd_non_tlv() - WMI wow wakeup function + * + * @param wmi_handle : handle to WMI. + * @return QDF_STATUS_SUCCESS on success and -ve on failure. + */ +QDF_STATUS send_wow_wakeup_cmd_non_tlv(wmi_unified_t wmi_handle) +{ + QDF_STATUS res; + wmi_buf_t buf = NULL; + + buf = wmi_buf_alloc(wmi_handle, 4); + if (!buf) { + qdf_print("buf alloc failed\n"); + return QDF_STATUS_E_NOMEM; + } + res = wmi_unified_cmd_send(wmi_handle, buf, 4, + WMI_WOW_HOSTWAKEUP_FROM_SLEEP_CMDID); + qdf_print("ol_wow_wakeup result: %d\n", res); + return (res == QDF_STATUS_SUCCESS) ? + QDF_STATUS_SUCCESS : QDF_STATUS_E_FAILURE; +} + +/** + * send_wow_add_wakeup_event_cmd_non_tlv() - WMI wow add wakeup event function + * + * @param wmi_handle : handle to WMI. + * @param param : pointer to hold wow wakeup event parameter + * @return QDF_STATUS_SUCCESS on success and -ve on failure. + */ +QDF_STATUS send_wow_add_wakeup_event_cmd_non_tlv(wmi_unified_t wmi_handle, + struct wow_add_wakeup_params *param) +{ + QDF_STATUS res; + WMI_WOW_ADD_DEL_EVT_CMD *cmd; + wmi_buf_t buf = NULL; + int len = sizeof(WMI_WOW_ADD_DEL_EVT_CMD); + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + qdf_print("buf alloc failed\n"); + return QDF_STATUS_E_NOMEM; + } + cmd = (WMI_WOW_ADD_DEL_EVT_CMD *)wmi_buf_data(buf); + cmd->is_add = 1; + cmd->event_bitmap = param->type; + res = wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_WOW_ENABLE_DISABLE_WAKE_EVENT_CMDID); + return (res == QDF_STATUS_SUCCESS) ? + QDF_STATUS_SUCCESS : QDF_STATUS_E_FAILURE; +} + +/** + * send_wow_add_wakeup_pattern_cmd_non_tlv() - WMI wow add wakeup pattern function + * + * @param wmi_handle : handle to WMI. + * @param param : pointer to hold wow wakeup pattern parameter + * @return QDF_STATUS_SUCCESS on success and -ve on failure. + */ +QDF_STATUS send_wow_add_wakeup_pattern_cmd_non_tlv(wmi_unified_t wmi_handle, + struct wow_add_wakeup_pattern_params *param) +{ + WOW_BITMAP_PATTERN_T bitmap_pattern; + uint32_t j; + /* + struct ol_wow_info *wowInfo; + OL_WOW_PATTERN *pattern; + struct ol_ath_softc_net80211 *scn = OL_ATH_SOFTC_NET80211(ic); + */ + QDF_STATUS res; + WMI_WOW_ADD_PATTERN_CMD *cmd; + wmi_buf_t buf = NULL; + int len = sizeof(WMI_WOW_ADD_PATTERN_CMD); + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + qdf_print("buf alloc failed\n"); + return QDF_STATUS_E_NOMEM; + } + cmd = (WMI_WOW_ADD_PATTERN_CMD *)wmi_buf_data(buf); + cmd->pattern_id = param->pattern_id; + cmd->pattern_type = WOW_BITMAP_PATTERN; + + for (j = 0; j < WOW_DEFAULT_BITMAP_PATTERN_SIZE; j++) + bitmap_pattern.patternbuf[j] = param->pattern_bytes[j]; + + for (j = 0; j < WOW_DEFAULT_BITMASK_SIZE; j++) + bitmap_pattern.bitmaskbuf[j] = param->mask_bytes[j]; + + bitmap_pattern.pattern_offset = 0; + + cmd->pattern_info.bitmap = bitmap_pattern; + res = wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_WOW_ADD_WAKE_PATTERN_CMDID); + + return (res == QDF_STATUS_SUCCESS) ? + QDF_STATUS_SUCCESS : QDF_STATUS_E_FAILURE; +} + +/** + * send_wow_remove_wakeup_pattern_cmd_non_tlv() - WMI wow remove wakeup + * pattern function + * + * @param wmi_handle : handle to WMI. + * @param param : pointer to hold wow wakeup pattern parameter + * @return QDF_STATUS_SUCCESS on success and -ve on failure. + */ +QDF_STATUS send_wow_remove_wakeup_pattern_cmd_non_tlv(wmi_unified_t wmi_handle, + struct wow_remove_wakeup_pattern_params *param) +{ + WMI_WOW_DEL_PATTERN_CMD *cmd; + QDF_STATUS res; + wmi_buf_t buf = NULL; + int len = sizeof(WMI_WOW_DEL_PATTERN_CMD); + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + qdf_print("buf alloc failed\n"); + return QDF_STATUS_E_NOMEM; + } + cmd = (WMI_WOW_DEL_PATTERN_CMD *)wmi_buf_data(buf); + cmd->pattern_id = param->pattern_id; + cmd->pattern_type = WOW_BITMAP_PATTERN; + res = wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_WOW_DEL_WAKE_PATTERN_CMDID); + return (res == QDF_STATUS_SUCCESS) ? + QDF_STATUS_SUCCESS : QDF_STATUS_E_FAILURE; +} + +/** + * send_set_ap_ps_param_cmd_non_tlv() - set ap powersave parameters + * @param wmi_handle : handle to WMI. + * @peer_addr: peer mac address + * @param: pointer to ap_ps parameter structure + * + * Return: 0 for success or error code + */ +QDF_STATUS send_set_ap_ps_param_cmd_non_tlv(wmi_unified_t wmi_handle, + uint8_t *peer_addr, + struct ap_ps_params *param) +{ + wmi_ap_ps_peer_cmd *cmd; + wmi_buf_t buf; + + buf = wmi_buf_alloc(wmi_handle, sizeof(*cmd)); + if (!buf) { + qdf_print("%s: wmi_buf_alloc failed\n", __func__); + return QDF_STATUS_E_FAILURE; + } + + cmd = (wmi_ap_ps_peer_cmd *)wmi_buf_data(buf); + cmd->vdev_id = param->vdev_id; + WMI_CHAR_ARRAY_TO_MAC_ADDR(peer_addr, &cmd->peer_macaddr); + cmd->param = param->param; + cmd->value = param->value; + + return wmi_unified_cmd_send(wmi_handle, buf, sizeof(*cmd), + WMI_AP_PS_PEER_PARAM_CMDID); +} + +/** + * send_set_sta_ps_param_cmd_non_tlv() - set sta powersave parameters + * @param wmi_handle : handle to WMI. + * @param: pointer to sta_ps parameter structure + * + * Return: 0 for success or error code + */ +QDF_STATUS send_set_sta_ps_param_cmd_non_tlv(wmi_unified_t wmi_handle, + struct sta_ps_params *param) +{ + wmi_sta_powersave_param_cmd *cmd; + wmi_buf_t buf; + + buf = wmi_buf_alloc(wmi_handle, sizeof(*cmd)); + if (!buf) { + qdf_print("%s: wmi_buf_alloc failed\n", __func__); + return QDF_STATUS_E_FAILURE; + } + + cmd = (wmi_sta_powersave_param_cmd *)wmi_buf_data(buf); + cmd->vdev_id = param->vdev_id; + cmd->param = param->param; + cmd->value = param->value; + + return wmi_unified_cmd_send(wmi_handle, buf, sizeof(*cmd), + WMI_STA_POWERSAVE_PARAM_CMDID); +} + +/** + * send_set_ps_mode_cmd_non_tlv() - set powersave mode + * @wmi_handle: wmi handle + * @param: pointer to ps_mode parameter structure + * + * Return: 0 for success or error code + */ +QDF_STATUS send_set_ps_mode_cmd_non_tlv(wmi_unified_t wmi_handle, + struct set_ps_mode_params *param) +{ + wmi_sta_powersave_mode_cmd *cmd; + wmi_buf_t buf; + int ret; + + buf = wmi_buf_alloc(wmi_handle, sizeof(*cmd)); + if (!buf) { + qdf_print("%s: wmi_buf_alloc failed\n", __func__); + return QDF_STATUS_E_FAILURE; + } + qdf_print("%s:set psmode=%d\n", __func__, param->psmode); + cmd = (wmi_sta_powersave_mode_cmd *)wmi_buf_data(buf); + cmd->vdev_id = param->vdev_id; + cmd->sta_ps_mode = param->psmode; + + ret = wmi_unified_cmd_send(wmi_handle, buf, sizeof(*cmd), + WMI_STA_POWERSAVE_MODE_CMDID); + + return ret; +} + +/** + * send_crash_inject_cmd_non_tlv() - inject fw crash + * @param wmi_handle : handle to WMI. + * @param: ponirt to crash inject paramter structure + * + * Return: 0 for success or return error + */ +QDF_STATUS send_crash_inject_cmd_non_tlv(wmi_unified_t wmi_handle, + struct crash_inject *param) +{ + WMI_FORCE_FW_HANG_CMD *cmd; + wmi_buf_t buf; + int32_t len = sizeof(WMI_FORCE_FW_HANG_CMD); + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + qdf_print("%s:wmi_buf_alloc failed\n", __func__); + return QDF_STATUS_E_FAILURE; + } + cmd = (WMI_FORCE_FW_HANG_CMD *)wmi_buf_data(buf); + cmd->type = 1; + /* Should this be param->type ? */ + cmd->delay_time_ms = param->delay_time_ms; + return wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_FORCE_FW_HANG_CMDID); +} + +/** + * send_dbglog_cmd_non_tlv() - set debug log level + * + * @param wmi_handle : handle to WMI. + * @param param : pointer to hold dbglog level parameter + * @return QDF_STATUS_SUCCESS on success and -ve on failure. + */ +QDF_STATUS +send_dbglog_cmd_non_tlv(wmi_unified_t wmi_handle, + struct dbglog_params *dbglog_param) +{ + wmi_buf_t osbuf; + WMI_DBGLOG_CFG_CMD *cmd; + QDF_STATUS status; + + osbuf = wmi_buf_alloc(wmi_handle, sizeof(*cmd)); + if (osbuf == NULL) + return QDF_STATUS_E_NOMEM; + + qdf_nbuf_put_tail(osbuf, sizeof(*cmd)); + + cmd = (WMI_DBGLOG_CFG_CMD *)(wmi_buf_data(osbuf)); + + qdf_print("wmi_dbg_cfg_send: mod[0]%08x dbgcfg%08x cfgvalid[0] %08x" + " cfgvalid[1] %08x\n", + dbglog_param->module_id_bitmap[0], + dbglog_param->val, dbglog_param->cfgvalid[0], + dbglog_param->cfgvalid[1]); + + cmd->config.cfgvalid[0] = dbglog_param->cfgvalid[0]; + cmd->config.cfgvalid[1] = dbglog_param->cfgvalid[1]; + cmd->config.config.mod_id[0] = dbglog_param->module_id_bitmap[0]; + cmd->config.config.dbg_config = dbglog_param->val; + + status = wmi_unified_cmd_send(wmi_handle, osbuf, + sizeof(WMI_DBGLOG_CFG_CMD), + WMI_DBGLOG_CFG_CMDID); + + return status; +} + +/** + * send_vdev_set_param_cmd_non_tlv() - WMI vdev set parameter function + * + * @param wmi_handle : handle to WMI. + * @param param : pointer to hold vdev set parameter + * @return QDF_STATUS_SUCCESS on success and -ve on failure. + */ +QDF_STATUS send_vdev_set_param_cmd_non_tlv(wmi_unified_t wmi_handle, + struct vdev_set_params *param) +{ + wmi_vdev_set_param_cmd *cmd; + wmi_buf_t buf; + int len = sizeof(wmi_vdev_set_param_cmd); + + if ((param->param_id < wmi_vdev_param_max) && + (wmi_handle->vdev_param[param->param_id] != + WMI_UNAVAILABLE_PARAM)) { + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + qdf_print("%s:wmi_buf_alloc failed\n", __func__); + return QDF_STATUS_E_FAILURE; + } + cmd = (wmi_vdev_set_param_cmd *)wmi_buf_data(buf); + cmd->vdev_id = param->if_id; + cmd->param_id = wmi_handle->vdev_param[param->param_id]; + cmd->param_value = param->param_value; + return wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_VDEV_SET_PARAM_CMDID); + } + return QDF_STATUS_E_FAILURE; +} + +/** + * get_stats_id_non_tlv() - Get stats identifier function + * + * @param host_stats_id: host stats identifier value + * @return stats_id based on host_stats_id + */ +static uint32_t get_stats_id_non_tlv(wmi_host_stats_id host_stats_id) +{ + uint32_t stats_id = 0; + + if (host_stats_id & WMI_HOST_REQUEST_PEER_STAT) + stats_id |= WMI_REQUEST_PEER_STAT; + if (host_stats_id & WMI_HOST_REQUEST_AP_STAT) + stats_id |= WMI_REQUEST_AP_STAT; + if (host_stats_id & WMI_HOST_REQUEST_INST_STAT) + stats_id |= WMI_REQUEST_INST_STAT; + if (host_stats_id & WMI_HOST_REQUEST_PEER_EXTD_STAT) + stats_id |= WMI_REQUEST_PEER_EXTD_STAT; + + return stats_id; +} +/** + * send_stats_request_cmd_non_tlv() - WMI request stats function + * + * @param wmi_handle : handle to WMI. + * @param macaddr : MAC address + * @param param : pointer to hold stats request parameter + * @return QDF_STATUS_SUCCESS on success and -ve on failure. + */ +QDF_STATUS send_stats_request_cmd_non_tlv(wmi_unified_t wmi_handle, + uint8_t macaddr[IEEE80211_ADDR_LEN], + struct stats_request_params *param) +{ + wmi_buf_t buf; + wmi_request_stats_cmd *cmd; + uint8_t len = sizeof(wmi_request_stats_cmd); + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + qdf_print("%s:wmi_buf_alloc failed\n", __func__); + return QDF_STATUS_E_INVAL; + } + + cmd = (wmi_request_stats_cmd *)wmi_buf_data(buf); + cmd->stats_id = get_stats_id_non_tlv(param->stats_id); + cmd->vdev_id = param->vdev_id; + WMI_CHAR_ARRAY_TO_MAC_ADDR(macaddr, &cmd->peer_macaddr); + cmd->inst_rssi_args.cfg_retry_count = param->rssi_args.cfg_retry_count; + cmd->inst_rssi_args.retry_count = param->rssi_args.retry_count; + + if (wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_REQUEST_STATS_CMDID)) { + return QDF_STATUS_E_INVAL; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * send_bss_chan_info_request_cmd_non_tlv() - WMI request bss chan info + * + * @param wmi_handle : handle to WMI. + * @param param : pointer to hold bss chan info request parameter + * @return QDF_STATUS_SUCCESS on success and -ve on failure. + */ +QDF_STATUS send_bss_chan_info_request_cmd_non_tlv(wmi_unified_t wmi_handle, + struct bss_chan_info_request_params *param) +{ + wmi_buf_t buf; + wmi_pdev_bss_chan_info_request *cmd; + u_int8_t len = sizeof(wmi_pdev_bss_chan_info_request); + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + qdf_print("%s:wmi_buf_alloc failed\n", __func__); + return QDF_STATUS_E_INVAL; + } + + cmd = (wmi_pdev_bss_chan_info_request *)wmi_buf_data(buf); + cmd->param = param->param; + cmd->reserved = 0; + + if (wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_PDEV_BSS_CHAN_INFO_REQUEST_CMDID)) { + return QDF_STATUS_E_INVAL; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * send_packet_log_enable_cmd_non_tlv() - WMI request stats function + * + * @param wmi_handle : handle to WMI. + * @param PKTLOG_EVENT : packet log event + * @return QDF_STATUS_SUCCESS on success and -ve on failure. + */ +QDF_STATUS send_packet_log_enable_cmd_non_tlv(wmi_unified_t wmi_handle, + WMI_HOST_PKTLOG_EVENT PKTLOG_EVENT) +{ + wmi_pdev_pktlog_enable_cmd *cmd; + int len = 0; + wmi_buf_t buf; + + len = sizeof(wmi_pdev_pktlog_enable_cmd); + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + qdf_print("%s:wmi_buf_alloc failed\n", __func__); + return QDF_STATUS_E_NOMEM; + } + cmd = (wmi_pdev_pktlog_enable_cmd *)wmi_buf_data(buf); + cmd->evlist = PKTLOG_EVENT; + if (wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_PDEV_PKTLOG_ENABLE_CMDID)) { + return QDF_STATUS_E_FAILURE; + } + return QDF_STATUS_SUCCESS; +} + +/** + * send_packet_log_disable_cmd_non_tlv() - WMI disable packet log send function + * + * @param wmi_handle : handle to WMI. + * @return QDF_STATUS_SUCCESS on success and -ve on failure. + */ +QDF_STATUS send_packet_log_disable_cmd_non_tlv(wmi_unified_t wmi_handle) +{ + int len = 0; + wmi_buf_t buf; + + buf = wmi_buf_alloc(wmi_handle, 0); + if (!buf) { + qdf_print("%s:wmi_buf_alloc failed\n", __func__); + return QDF_STATUS_E_NOMEM; + } + if (wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_PDEV_PKTLOG_DISABLE_CMDID)) { + return QDF_STATUS_E_FAILURE; + } + return QDF_STATUS_SUCCESS; +} + +/** + * send_beacon_send_cmd_non_tlv() - WMI beacon send function + * + * @param wmi_handle : handle to WMI. + * @param param : pointer to hold beacon send cmd parameter + * @return QDF_STATUS_SUCCESS on success and -ve on failure. + */ +QDF_STATUS send_beacon_send_cmd_non_tlv(wmi_unified_t wmi_handle, + struct beacon_params *param) +{ + if (param->is_high_latency) { + wmi_bcn_tx_cmd *cmd; + wmi_buf_t wmi_buf; + int bcn_len = qdf_nbuf_len(param->wbuf); + int len = sizeof(wmi_bcn_tx_hdr) + bcn_len; + + /************************************************************* + * TODO: Once we have the host target transport framework for + * sending management frames this wmi function will be replaced + * with calls to HTT. The buffer will changed to match the right + * format to be used with HTT. + *************************************************************/ + wmi_buf = wmi_buf_alloc(wmi_handle, roundup(len, + sizeof(u_int32_t))); + if (!wmi_buf) { + qdf_print("%s: wmi_buf_alloc failed\n", __func__); + return QDF_STATUS_E_NOMEM; + } + cmd = (wmi_bcn_tx_cmd *)wmi_buf_data(wmi_buf); + cmd->hdr.vdev_id = param->vdev_id; + cmd->hdr.buf_len = bcn_len; + +#ifdef BIG_ENDIAN_HOST + { + /* for big endian host, copy engine byte_swap is enabled + * But the beacon buffer content is in network byte + * order Need to byte swap the beacon buffer content - + * so when copy engine does byte_swap - target gets + * buffer content in the correct order + */ + int i; + u_int32_t *destp, *srcp; + destp = (u_int32_t *)cmd->bufp; + srcp = (u_int32_t *)wmi_buf_data(param->wbuf); + for (i = 0; i < (roundup(bcn_len, + sizeof(u_int32_t))/4); i++) { + *destp = qdf_le32_to_cpu(*srcp); + destp++; srcp++; + } + } +#else + qdf_mem_copy(cmd->bufp, wmi_buf_data(param->wbuf), bcn_len); +#endif +#ifdef DEBUG_BEACON + qdf_print("%s frm length %d\n", __func__, bcn_len); +#endif + wmi_unified_cmd_send(wmi_handle, wmi_buf, + roundup(len, sizeof(u_int32_t)), WMI_BCN_TX_CMDID); + } else { + wmi_bcn_send_from_host_cmd_t *cmd; + wmi_buf_t wmi_buf; + int bcn_len = qdf_nbuf_len(param->wbuf); + int len = sizeof(wmi_bcn_send_from_host_cmd_t); + A_UINT32 dtim_flag = 0; + + /* get the DTIM count */ + + if (param->is_dtim_count_zero) { + dtim_flag |= WMI_BCN_SEND_DTIM_ZERO; + if (param->is_bitctl_reqd) { + /* deliver CAB traffic in next DTIM beacon */ + dtim_flag |= WMI_BCN_SEND_DTIM_BITCTL_SET; + } + } + /* Map the beacon buffer to DMA region */ + + wmi_buf = wmi_buf_alloc(wmi_handle, roundup(len, + sizeof(u_int32_t))); + if (!wmi_buf) { + qdf_print("%s: wmi_buf_alloc failed\n", __func__); + return QDF_STATUS_E_NOMEM; + } + + + cmd = (wmi_bcn_send_from_host_cmd_t *)wmi_buf_data(wmi_buf); + cmd->vdev_id = param->vdev_id; + cmd->data_len = bcn_len; + cmd->frame_ctrl = param->frame_ctrl; + cmd->dtim_flag = dtim_flag; + cmd->frag_ptr = qdf_nbuf_get_frag_paddr(param->wbuf, 0); +#if SUPPORT_64BIT_CHANGES + cmd->virt_addr = (uintptr_t)param->wbuf; +#else + cmd->virt_addr = (A_UINT32)param->wbuf; +#endif + cmd->bcn_antenna = param->bcn_txant; + wmi_unified_cmd_send(wmi_handle, wmi_buf, len, + WMI_PDEV_SEND_BCN_CMDID); + } + return QDF_STATUS_SUCCESS; +} + +#if 0 +/** + * send_bcn_prb_template_cmd_non_tlv() - WMI beacon probe template function + * + * @param wmi_handle : handle to WMI. + * @param macaddr : MAC address + * @param param : pointer to hold beacon prb template cmd parameter + * @return QDF_STATUS_SUCCESS on success and -ve on failure. + */ +QDF_STATUS send_bcn_prb_template_cmd_non_tlv(wmi_unified_t wmi_handle, + struct bcn_prb_template_params *param) +{ + wmi_bcn_prb_tmpl_cmd *cmd; + wmi_buf_t buf; + wmi_bcn_prb_info *template; + int len = sizeof(wmi_bcn_prb_tmpl_cmd); + int ret; + + /* + * The target will store this information for use with + * the beacons and probes. + */ + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + qdf_print("%s: wmi_buf_alloc failed\n", __func__); + return QDF_STATUS_E_NOMEM; + } + cmd = (wmi_bcn_prb_tmpl_cmd *)wmi_buf_data(buf); + cmd->vdev_id = param->vdev_id; + cmd->buf_len = param->buf_len; + template = &cmd->bcn_prb_info; + template->caps = param->caps; + template->erp = param->erp; + + /* TODO: Few more elements to be added and copied to the template + * buffer */ + + /* Send the beacon probe template to the target */ + ret = wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_BCN_PRB_TMPL_CMDID); + return ret; +} +#endif + +/** + * send_peer_assoc_cmd_non_tlv() - WMI peer assoc function + * + * @param wmi_handle : handle to WMI. + * @param param : pointer to peer assoc parameter + * @return QDF_STATUS_SUCCESS on success and -ve on failure. + */ +QDF_STATUS send_peer_assoc_cmd_non_tlv(wmi_unified_t wmi_handle, + struct peer_assoc_params *param) +{ + wmi_peer_assoc_complete_cmd *cmd; + int len = sizeof(wmi_peer_assoc_complete_cmd); +#ifdef BIG_ENDIAN_HOST + int i; +#endif + + wmi_buf_t buf; + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + qdf_print("%s: wmi_buf_alloc failed\n", __func__); + return QDF_STATUS_E_FAILURE; + } + cmd = (wmi_peer_assoc_complete_cmd *)wmi_buf_data(buf); + WMI_CHAR_ARRAY_TO_MAC_ADDR(param->peer_mac, &cmd->peer_macaddr); + cmd->vdev_id = param->vdev_id; + cmd->peer_new_assoc = param->peer_new_assoc; + cmd->peer_associd = param->peer_associd; + cmd->peer_bw_rxnss_override = 0; + + /* + * The target only needs a subset of the flags maintained in the host. + * Just populate those flags and send it down + */ + cmd->peer_flags = 0; + + if (param->is_pmf_enabled) + cmd->peer_flags |= WMI_PEER_PMF_ENABLED; + + /* + * Do not enable HT/VHT if WMM/wme is disabled for vap. + */ + if (param->is_wme_set) { + + if (param->qos_flag) + cmd->peer_flags |= WMI_PEER_QOS; + if (param->apsd_flag) + cmd->peer_flags |= WMI_PEER_APSD; + if (param->ht_flag) + cmd->peer_flags |= WMI_PEER_HT; + if (param->bw_40) + cmd->peer_flags |= WMI_PEER_40MHZ; + if (param->bw_80) + cmd->peer_flags |= WMI_PEER_80MHZ; + if (param->bw_160) + cmd->peer_flags |= WMI_PEER_160MHZ; + + /* Typically if STBC is enabled for VHT it should be enabled + * for HT as well */ + if (param->stbc_flag) + cmd->peer_flags |= WMI_PEER_STBC; + + /* Typically if LDPC is enabled for VHT it should be enabled + * for HT as well */ + if (param->ldpc_flag) + cmd->peer_flags |= WMI_PEER_LDPC; + + if (param->static_mimops_flag) + cmd->peer_flags |= WMI_PEER_STATIC_MIMOPS; + if (param->dynamic_mimops_flag) + cmd->peer_flags |= WMI_PEER_DYN_MIMOPS; + if (param->spatial_mux_flag) + cmd->peer_flags |= WMI_PEER_SPATIAL_MUX; + if (param->vht_flag) + cmd->peer_flags |= WMI_PEER_VHT; + if (param->vht_ng_flag) + cmd->peer_flags |= WMI_PEER_VHT_2G; + } + /* + * Suppress authorization for all AUTH modes that need 4-way handshake + * (during re-association). + * Authorization will be done for these modes on key installation. + */ + if (param->auth_flag) + cmd->peer_flags |= WMI_PEER_AUTH; + if (param->need_ptk_4_way) + cmd->peer_flags |= WMI_PEER_NEED_PTK_4_WAY; + else + cmd->peer_flags &= ~WMI_PEER_NEED_PTK_4_WAY; + if (param->need_gtk_2_way) + cmd->peer_flags |= WMI_PEER_NEED_GTK_2_WAY; + /* safe mode bypass the 4-way handshake */ + if (param->safe_mode_enabled) + cmd->peer_flags &= + ~(WMI_PEER_NEED_PTK_4_WAY | WMI_PEER_NEED_GTK_2_WAY); + /* Disable AMSDU for station transmit, if user configures it */ + /* Disable AMSDU for AP transmit to 11n Stations, if user configures + * it */ + if (param->amsdu_disable) + cmd->peer_flags |= WMI_PEER_AMSDU_DISABLE; + cmd->peer_caps = param->peer_caps; + cmd->peer_listen_intval = param->peer_listen_intval; + cmd->peer_ht_caps = param->peer_ht_caps; + cmd->peer_max_mpdu = param->peer_max_mpdu; + cmd->peer_mpdu_density = param->peer_mpdu_density; + cmd->peer_vht_caps = param->peer_vht_caps; + + /* Update peer rate information */ + cmd->peer_rate_caps = param->peer_rate_caps; + cmd->peer_legacy_rates.num_rates = param->peer_legacy_rates.num_rates; + /* NOTE: cmd->peer_legacy_rates.rates is of type A_UINT32 */ + /* ni->ni_rates.rs_rates is of type u_int8_t */ + /** + * for cmd->peer_legacy_rates.rates: + * rates (each 8bit value) packed into a 32 bit word. + * the rates are filled from least significant byte to most + * significant byte. + */ + qdf_mem_copy(cmd->peer_legacy_rates.rates, + param->peer_legacy_rates.rates, + param->peer_legacy_rates.num_rates); +#ifdef BIG_ENDIAN_HOST + for (i = 0; + i < param->peer_legacy_rates.num_rates/sizeof(A_UINT32) + 1; + i++) + cmd->peer_legacy_rates.rates[i] = + qdf_le32_to_cpu(cmd->peer_legacy_rates.rates[i]); +#endif + + cmd->peer_ht_rates.num_rates = param->peer_ht_rates.num_rates; + qdf_mem_copy(cmd->peer_ht_rates.rates, param->peer_ht_rates.rates, + param->peer_ht_rates.num_rates); + +#ifdef BIG_ENDIAN_HOST + for (i = 0; i < param->peer_ht_rates.num_rates/sizeof(A_UINT32) + 1; + i++) + cmd->peer_ht_rates.rates[i] = + qdf_le32_to_cpu(cmd->peer_ht_rates.rates[i]); +#endif + + if (param->ht_flag && + (param->peer_ht_rates.num_rates == 0)) { + /* Workaround for EV 116382: The node is marked HT but with + * supported rx mcs set is set to 0. 11n spec mandates MCS0-7 + * for a HT STA. So forcing the supported rx mcs rate to MCS + * 0-7. + * This workaround will be removed once we get clarification + * from WFA regarding this STA behavior + */ + u_int8_t temp_ni_rates[8] = { + 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7}; + cmd->peer_ht_rates.num_rates = 8; + qdf_mem_copy(cmd->peer_ht_rates.rates, temp_ni_rates, + cmd->peer_ht_rates.num_rates); + } + /* Target asserts if node is marked HT and all MCS is set to 0. + Mark the node as non-HT if all the mcs rates are disabled through + iwpriv */ + if (cmd->peer_ht_rates.num_rates == 0) + cmd->peer_flags &= ~WMI_PEER_HT; + + cmd->peer_nss = param->peer_nss; + + if (param->vht_capable) { + wmi_vht_rate_set *mcs; + mcs = &cmd->peer_vht_rates; + mcs->rx_max_rate = param->rx_max_rate; + mcs->rx_mcs_set = param->rx_mcs_set; + mcs->tx_max_rate = param->tx_max_rate; + mcs->tx_mcs_set = param->tx_mcs_set; + mcs->tx_max_mcs_nss = param->tx_max_mcs_nss; + } + + cmd->peer_phymode = param->peer_phymode; + /*Send bandwidth-NSS mapping to FW*/ + cmd->peer_bw_rxnss_override |= param->peer_bw_rxnss_override; + + return wmi_unified_cmd_send(wmi_handle, buf, len, WMI_PEER_ASSOC_CMDID); +} + +/** + * send_scan_start_cmd_non_tlv() - WMI scan start function + * + * @param wmi_handle : handle to WMI. + * @param param : pointer to hold scan start cmd parameter + * @return QDF_STATUS_SUCCESS on success and -ve on failure. + */ +QDF_STATUS send_scan_start_cmd_non_tlv(wmi_unified_t wmi_handle, + struct scan_start_params *param) +{ + wmi_start_scan_cmd *cmd; + wmi_buf_t buf; + wmi_chan_list *chan_list; + wmi_bssid_list *bssid_list; + wmi_ssid_list *ssid_list; + wmi_ie_data *ie_data; + A_UINT32 *tmp_ptr; + int i, len = sizeof(wmi_start_scan_cmd); + +#ifdef TEST_CODE + len += sizeof(wmi_chan_list) + 3 * sizeof(A_UINT32); +#else + if (param->num_chan) { + len += sizeof(wmi_chan_list) + (param->num_chan - 1) + * sizeof(A_UINT32); + } +#endif + if (param->num_ssids) { + len += sizeof(wmi_ssid_list) + (param->num_ssids - 1) + * sizeof(wmi_ssid); + } + if (param->num_bssid) { + len += sizeof(wmi_bssid_list) + (param->num_bssid - 1) + * sizeof(wmi_mac_addr); + } + if (param->ie_len) { + i = param->ie_len % sizeof(A_UINT32); + if (i) + len += sizeof(A_UINT32) - i; + len += 2 * sizeof(A_UINT32) + param->ie_len; + } + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + qdf_print("%s: wmi_buf_alloc failed\n", __func__); + return QDF_STATUS_E_NOMEM; + } + cmd = (wmi_start_scan_cmd *)wmi_buf_data(buf); + OS_MEMZERO(cmd, len); + cmd->vdev_id = param->vdev_id; + cmd->scan_priority = param->scan_priority; + cmd->scan_id = param->scan_id; + cmd->scan_req_id = param->scan_req_id; + /** Scan events subscription */ + cmd->notify_scan_events = WMI_SCAN_EVENT_STARTED | + WMI_SCAN_EVENT_COMPLETED | + WMI_SCAN_EVENT_BSS_CHANNEL | + WMI_SCAN_EVENT_FOREIGN_CHANNEL | + WMI_SCAN_EVENT_DEQUEUED +#if QCA_LTEU_SUPPORT + | WMI_SCAN_EVENT_INVALID +#endif + ; + + /** Max. active channel dwell time */ + cmd->dwell_time_active = param->dwell_time_active; + /** Passive channel dwell time */ + cmd->dwell_time_passive = param->dwell_time_passive; + + /** Scan control flags */ + cmd->scan_ctrl_flags = (param->passive_flag) ? + WMI_SCAN_FLAG_PASSIVE : 0; + + if (param->is_promiscous_mode) + cmd->scan_ctrl_flags |= WMI_SCAN_PROMISCOUS_MODE; + + if (param->is_phy_error) + cmd->scan_ctrl_flags |= WMI_SCAN_CAPTURE_PHY_ERROR; + + /** send multiple braodcast probe req with this delay in between */ + cmd->repeat_probe_time = param->repeat_probe_time; + /** delay between channel change and first probe request */ + cmd->probe_delay = param->probe_delay; + /** idle time on channel for which if no traffic is seen + then scanner can switch to off channel */ + cmd->idle_time = param->idle_time; + cmd->min_rest_time = param->min_rest_time; + /** maximum rest time allowed on bss channel, overwrites + * other conditions and changes channel to off channel + * even if min beacon count, idle time requirements are not met. + */ + cmd->max_rest_time = param->max_rest_time; + /** maxmimum scan time allowed */ +#if IPQ4019_EMU + cmd->max_scan_time = 0xffffffff; +#else + cmd->max_scan_time = param->max_scan_time; +#endif + cmd->scan_ctrl_flags |= WMI_SCAN_ADD_OFDM_RATES; + /* add cck rates if required */ + if (param->add_cck_rates) + cmd->scan_ctrl_flags |= WMI_SCAN_ADD_CCK_RATES; + /** It enables the Channel stat event indication to host */ + if (param->chan_stat_enable) + cmd->scan_ctrl_flags |= WMI_SCAN_CHAN_STAT_EVENT; + if (param->add_bcast_probe_reqd) + cmd->scan_ctrl_flags |= WMI_SCAN_ADD_BCAST_PROBE_REQ; + /* off channel TX control */ + if (param->offchan_tx_mgmt) + cmd->scan_ctrl_flags |= WMI_SCAN_OFFCHAN_MGMT_TX; + if (param->offchan_tx_data) + cmd->scan_ctrl_flags |= WMI_SCAN_OFFCHAN_DATA_TX; + tmp_ptr = (A_UINT32 *) (cmd + 1); +#ifdef TEST_CODE +#define DEFAULT_TIME 150 + cmd->min_rest_time = DEFAULT_TIME; + cmd->idle_time = 10*DEFAULT_TIME; + cmd->max_rest_time = 30*DEFAULT_TIME; + chan_list = (wmi_chan_list *) tmp_ptr; + chan_list->tag = WMI_CHAN_LIST_TAG; + chan_list->num_chan = 4; + chan_list->channel_list[0] = 2412; /* 1 */ + chan_list->channel_list[1] = 2437; /* 6 */ + chan_list->channel_list[2] = 5180; /* 36 */- + chan_list->channel_list[3] = 5680; /* 136 */ + tmp_ptr += (2 + chan_list->num_chan); /* increase by words */- +#else +#define FREQUENCY_THRESH 1000 + if (param->num_chan) { + chan_list = (wmi_chan_list *) tmp_ptr; + chan_list->tag = WMI_CHAN_LIST_TAG; + chan_list->num_chan = param->num_chan; + qdf_mem_copy(chan_list->channel_list, param->chan_list, + ((param->num_chan) * sizeof(uint32_t))); + tmp_ptr += (2 + param->num_chan); /* increase by words */ + } +#endif + if (param->num_ssids) { + ssid_list = (wmi_ssid_list *) tmp_ptr; + ssid_list->tag = WMI_SSID_LIST_TAG; + ssid_list->num_ssids = param->num_ssids; + for (i = 0; i < param->num_ssids; ++i) { + ssid_list->ssids[i].ssid_len = param->ssid[i].length; + WMI_HOST_IF_MSG_COPY_CHAR_ARRAY( + ssid_list->ssids[i].ssid, + param->ssid[i].mac_ssid, + param->ssid[i].length); + } + tmp_ptr += (2 + (sizeof(wmi_ssid) * + param->num_ssids)/sizeof(A_UINT32)); + } + if (param->num_bssid) { + bssid_list = (wmi_bssid_list *) tmp_ptr; + bssid_list->tag = WMI_BSSID_LIST_TAG; + bssid_list->num_bssid = param->num_bssid; + for (i = 0; i < param->num_bssid; ++i) { + WMI_CHAR_ARRAY_TO_MAC_ADDR(&(param->bssid_list[i][0]), + &bssid_list->bssid_list[i]); + } + tmp_ptr += (2 + (sizeof(wmi_mac_addr) * + param->num_bssid)/sizeof(A_UINT32)); + } + if (param->ie_len) { + ie_data = (wmi_ie_data *) tmp_ptr; + ie_data->tag = WMI_IE_TAG; + ie_data->ie_len = param->ie_len; + WMI_HOST_IF_MSG_COPY_CHAR_ARRAY(ie_data->ie_data, + param->ie_data, param->ie_len); + } + qdf_print("Sending SCAN START cmd\n"); + return wmi_unified_cmd_send(wmi_handle, buf, len, WMI_START_SCAN_CMDID); +} + +/** + * send_scan_stop_cmd_non_tlv() - WMI scan stop function + * + * @param wmi_handle : handle to WMI. + * @param param : pointer to hold scan start cmd parameter + * @return QDF_STATUS_SUCCESS on success and -ve on failure. + */ +QDF_STATUS send_scan_stop_cmd_non_tlv(wmi_unified_t wmi_handle, + struct scan_stop_params *param) +{ + wmi_stop_scan_cmd *cmd = NULL; + wmi_buf_t buf; + u_int32_t len = sizeof(wmi_stop_scan_cmd); + wmi_scan_event wmi_scn_event; + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + qdf_print("%s: wmi_buf_alloc failed\n", __func__); + return QDF_STATUS_E_NOMEM; + } + cmd = (wmi_stop_scan_cmd *)wmi_buf_data(buf); + OS_MEMZERO(cmd, len); + /* scan scheduler is not supportd yet */ + cmd->scan_id = param->scan_id; + cmd->requestor = param->requestor; + cmd->vdev_id = param->vdev_id; + + if (param->all_scans) { + /* Cancelling all scans - always match scan id */ + cmd->req_type = WMI_SCAN_STOP_ALL; + } else if (param->vap_scans) { + /*- + * Cancelling VAP scans - report a match if scan was requested + * by the same VAP trying to cancel it. + */ + cmd->req_type = WMI_SCN_STOP_VAP_ALL; + } else if (param->specific_scan) { + /*- + * Cancelling specific scan - report a match if specified scan + * id matches the request's scan id. + */ + cmd->req_type = WMI_SCAN_STOP_ONE; + } + + wmi_unified_cmd_send(wmi_handle, buf, len, WMI_STOP_SCAN_CMDID); + /* send a synchronous cancel command */ + if (param->flags) { + OS_MEMZERO(&wmi_scn_event, sizeof(wmi_scn_event)); + wmi_scn_event.event = WMI_SCAN_EVENT_COMPLETED; + wmi_scn_event.reason = WMI_SCAN_REASON_CANCELLED; + wmi_scn_event.requestor = param->requestor; + wmi_scn_event.scan_id = param->ss_scan_id; + } + return QDF_STATUS_SUCCESS; +} + +/** + * send_scan_chan_list_cmd_non_tlv() - WMI scan channel list function + * + * @param wmi_handle : handle to WMI. + * @param param : pointer to hold scan channel list parameter + * @return QDF_STATUS_SUCCESS on success and -ve on failure. + */ +QDF_STATUS send_scan_chan_list_cmd_non_tlv(wmi_unified_t wmi_handle, + struct scan_chan_list_params *param) +{ + uint32_t i; + wmi_buf_t buf; + wmi_scan_chan_list_cmd *cmd; + int len = sizeof(wmi_scan_chan_list_cmd); + + len = sizeof(wmi_scan_chan_list_cmd) + + sizeof(wmi_channel)*param->nallchans; + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + qdf_print("%s:wmi_buf_alloc failed\n", __func__); + return QDF_STATUS_E_NOMEM; + } + + cmd = (wmi_scan_chan_list_cmd *)wmi_buf_data(buf); + cmd->num_scan_chans = param->nallchans; + OS_MEMZERO(cmd->chan_info, sizeof(wmi_channel)*cmd->num_scan_chans); + + + for (i = 0; i < param->nallchans; ++i) { + cmd->chan_info[i].mhz = param->ch_param[i].mhz; + + if (param->ch_param[i].is_chan_passive) + WMI_SET_CHANNEL_FLAG(&(cmd->chan_info[i]), + WMI_CHAN_FLAG_PASSIVE); + + if (param->ch_param[i].allow_vht) + WMI_SET_CHANNEL_FLAG(&(cmd->chan_info[i]), + WMI_CHAN_FLAG_ALLOW_VHT); + else if (param->ch_param[i].allow_ht) + WMI_SET_CHANNEL_FLAG(&(cmd->chan_info[i]), + WMI_CHAN_FLAG_ALLOW_HT); + + cmd->chan_info[i].band_center_freq1 = + param->ch_param[i].cfreq1; + cmd->chan_info[i].band_center_freq2 = + param->ch_param[i].cfreq2; + WMI_SET_CHANNEL_MODE(&cmd->chan_info[i], + param->ch_param[i].phy_mode); + + if (param->ch_param[i].half_rate) + WMI_SET_CHANNEL_FLAG(&(cmd->chan_info[i]), + WMI_CHAN_FLAG_HALF); + if (param->ch_param[i].quarter_rate) + WMI_SET_CHANNEL_FLAG(&(cmd->chan_info[i]), + WMI_CHAN_FLAG_QUARTER); + + /* also fill in power information */ + WMI_SET_CHANNEL_MIN_POWER(&cmd->chan_info[i], + param->ch_param[i].minpower); + WMI_SET_CHANNEL_MAX_POWER(&cmd->chan_info[i], + param->ch_param[i].maxpower); + WMI_SET_CHANNEL_REG_POWER(&cmd->chan_info[i], + param->ch_param[i].maxregpower); + WMI_SET_CHANNEL_ANTENNA_MAX(&cmd->chan_info[i], + param->ch_param[i].antennamax); + WMI_SET_CHANNEL_REG_CLASSID(&cmd->chan_info[i], + param->ch_param[i].reg_class_id); + } + + wmi_unified_cmd_send(wmi_handle, buf, len, WMI_SCAN_CHAN_LIST_CMDID); + return QDF_STATUS_SUCCESS; +} + +/** + * send_thermal_mitigation_param_cmd_non_tlv() - WMI scan channel list function + * + * @param wmi_handle : handle to WMI. + * @param param : pointer to hold thermal mitigation param + * @return QDF_STATUS_SUCCESS on success and -ve on failure. + */ +QDF_STATUS send_thermal_mitigation_param_cmd_non_tlv(wmi_unified_t wmi_handle, + struct thermal_mitigation_params *param) +{ + wmi_buf_t buf = NULL; + tt_config_t *cmd = NULL; + int error = 0; + int32_t len = 0; + int i = 0; + + len = sizeof(tt_config_t); + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + qdf_print("%s:wmi_buf_alloc failed\n", __func__); + return QDF_STATUS_E_NOMEM; + } + cmd = (tt_config_t *) wmi_buf_data(buf); + cmd->enable = param->enable; + cmd->dc = param->dc; + cmd->dc_per_event = param->dc_per_event; + for (i = 0; i < THERMAL_LEVELS; i++) { + cmd->levelconf[i].tmplwm = param->levelconf[i].tmplwm; + cmd->levelconf[i].tmphwm = param->levelconf[i].tmphwm; + cmd->levelconf[i].dcoffpercent = + param->levelconf[i].dcoffpercent; + cmd->levelconf[i].prio = param->levelconf[i].priority; + } + + error = wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_TT_SET_CONF_CMDID); + return error; +} + +/** + * send_phyerr_enable_cmd_non_tlv() - WMI phyerr enable function + * + * @param wmi_handle : handle to WMI. + * @return QDF_STATUS_SUCCESS on success and -ve on failure. + */ +QDF_STATUS send_phyerr_enable_cmd_non_tlv(wmi_unified_t wmi_handle) +{ + wmi_buf_t buf; + + /* + * Passing a NULL pointer to wmi_unified_cmd_send() panics it, + * so let's just use a 32 byte fake array for now. + */ + buf = wmi_buf_alloc(wmi_handle, 32); + if (buf == NULL) { + /* XXX error? */ + return QDF_STATUS_E_NOMEM; + } + + qdf_print("%s: about to send\n", __func__); + if (wmi_unified_cmd_send(wmi_handle, buf, 32, + WMI_PDEV_DFS_ENABLE_CMDID) != QDF_STATUS_SUCCESS) { + qdf_print("%s: send failed\n", __func__); + return QDF_STATUS_E_FAILURE; + } + return QDF_STATUS_SUCCESS; +} + +/** + * send_phyerr_disable_cmd_non_tlv() - WMI phyerr disable function + * + * @param wmi_handle : handle to WMI. + * @return QDF_STATUS_SUCCESS on success and -ve on failure. + */ +QDF_STATUS send_phyerr_disable_cmd_non_tlv(wmi_unified_t wmi_handle) +{ + wmi_buf_t buf; + + /* + * Passing a NULL pointer to wmi_unified_cmd_send() panics it, + * so let's just use a 32 byte fake array for now. + */ + buf = wmi_buf_alloc(wmi_handle, 32); + if (buf == NULL) { + /* XXX error? */ + return QDF_STATUS_E_NOMEM; + } + + qdf_print("%s: about to send\n", __func__); + if (wmi_unified_cmd_send(wmi_handle, buf, 32, + WMI_PDEV_DFS_DISABLE_CMDID) != QDF_STATUS_SUCCESS) { + qdf_print("%s: send failed\n", __func__); + return QDF_STATUS_E_FAILURE; + } + return QDF_STATUS_SUCCESS; +} + +/** + * send_smart_ant_enable_cmd_non_tlv() - WMI smart ant enable function + * + * @param wmi_handle : handle to WMI. + * @param param : pointer to antenna param + * @return QDF_STATUS_SUCCESS on success and -ve on failure. + */ +QDF_STATUS send_smart_ant_enable_cmd_non_tlv(wmi_unified_t wmi_handle, + struct smart_ant_enable_params *param) +{ + /* Send WMI COMMAND to Enable */ + wmi_pdev_smart_ant_enable_cmd *cmd; + wmi_buf_t buf; + int len = 0; + int ret; + + len = sizeof(wmi_pdev_smart_ant_enable_cmd); + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + qdf_print("%s:wmi_buf_alloc failed\n", __func__); + return QDF_STATUS_E_NOMEM; + } + + cmd = (wmi_pdev_smart_ant_enable_cmd *)wmi_buf_data(buf); + cmd->enable = param->enable; + cmd->mode = param->mode; + cmd->rx_antenna = param->rx_antenna; + cmd->tx_default_antenna = param->rx_antenna; + + if (param->mode == SMART_ANT_MODE_SERIAL) { + cmd->gpio_pin[0] = param->gpio_pin[0]; + cmd->gpio_pin[1] = param->gpio_pin[1]; + cmd->gpio_pin[2] = 0; + cmd->gpio_pin[3] = 0; + + cmd->gpio_func[0] = param->gpio_func[0]; + cmd->gpio_func[1] = param->gpio_func[1]; + cmd->gpio_func[2] = 0; + cmd->gpio_func[3] = 0; + + } else if (param->mode == SMART_ANT_MODE_PARALLEL) { + cmd->gpio_pin[0] = param->gpio_pin[0]; + cmd->gpio_pin[1] = param->gpio_pin[1]; + cmd->gpio_pin[2] = param->gpio_pin[2]; + cmd->gpio_pin[3] = param->gpio_pin[3]; + + cmd->gpio_func[0] = param->gpio_func[0]; + cmd->gpio_func[1] = param->gpio_func[1]; + cmd->gpio_func[2] = param->gpio_func[2]; + cmd->gpio_func[3] = param->gpio_func[3]; + } + + ret = wmi_unified_cmd_send(wmi_handle, + buf, + len, + WMI_PDEV_SMART_ANT_ENABLE_CMDID); + + if (ret != 0) { + qdf_print(" %s :WMI Failed\n", __func__); + qdf_print("%s: Failed to send WMI_PDEV_SMART_ANT_ENABLE_CMDID.\n" + "enable:%d mode:%d rx_antenna: 0x%08x PINS: " + "[%d %d %d %d] Func[%d %d %d %d] cmdstatus=%d\n", + __func__, + cmd->enable, + cmd->mode, + cmd->rx_antenna, + cmd->gpio_pin[0], + cmd->gpio_pin[1], + cmd->gpio_pin[2], + cmd->gpio_pin[3], + cmd->gpio_func[0], + cmd->gpio_func[1], + cmd->gpio_func[2], + cmd->gpio_func[3], + ret); + wmi_buf_free(buf); + } + return ret; +} +/** + * send_smart_ant_set_rx_ant_cmd_non_tlv() - WMI set rx antenna function + * + * @param wmi_handle : handle to WMI. + * @param param : pointer to rx antenna param + * @return QDF_STATUS_SUCCESS on success and -ve on failure. + */ +QDF_STATUS send_smart_ant_set_rx_ant_cmd_non_tlv(wmi_unified_t wmi_handle, + struct smart_ant_rx_ant_params *param) +{ + wmi_pdev_smart_ant_set_rx_antenna_cmd *cmd; + wmi_buf_t buf; + int len = 0; + int ret; + + len = sizeof(wmi_pdev_smart_ant_set_rx_antenna_cmd); + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + qdf_print("%s:wmi_buf_alloc failed\n", __func__); + return QDF_STATUS_E_NOMEM; + } + + cmd = (wmi_pdev_smart_ant_set_rx_antenna_cmd *)wmi_buf_data(buf); + cmd->rx_antenna = param->antenna; + ret = wmi_unified_cmd_send(wmi_handle, + buf, + len, + WMI_PDEV_SMART_ANT_SET_RX_ANTENNA_CMDID); + + if (ret != 0) { + qdf_print(" %s :WMI Failed\n", __func__); + qdf_print("%s: Failed to send WMI_PDEV_SMART_ANT_SET_RX_ANTENNA_CMDID.\n" + " rx_antenna: 0x%08x cmdstatus=%d\n", + __func__, + cmd->rx_antenna, + ret); + wmi_buf_free(buf); + } + return ret; +} + +/** + * send_smart_ant_set_tx_ant_cmd_non_tlv() - WMI set tx antenna function + * @param wmi_handle : handle to WMI. + * @param macaddr : vdev mac address + * @param param : pointer to tx antenna param + * @return QDF_STATUS_SUCCESS on success and -ve on failure. + */ +QDF_STATUS send_smart_ant_set_tx_ant_cmd_non_tlv(wmi_unified_t wmi_handle, + uint8_t macaddr[IEEE80211_ADDR_LEN], + struct smart_ant_tx_ant_params *param) +{ + wmi_peer_sant_set_tx_antenna_cmd *cmd; + wmi_buf_t buf; + int len = 0; + int ret; + + len = sizeof(wmi_peer_sant_set_tx_antenna_cmd); + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + qdf_print("%s:wmi_buf_alloc failed\n", __func__); + return QDF_STATUS_E_NOMEM; + } + + cmd = (wmi_peer_sant_set_tx_antenna_cmd *)wmi_buf_data(buf); + cmd->vdev_id = param->vdev_id; + WMI_CHAR_ARRAY_TO_MAC_ADDR(macaddr, &cmd->peer_macaddr); + + cmd->antenna_series[0] = param->antenna_array[0]; + cmd->antenna_series[1] = param->antenna_array[1]; + ret = wmi_unified_cmd_send(wmi_handle, + buf, + len, + WMI_PEER_SMART_ANT_SET_TX_ANTENNA_CMDID); + + if (ret != 0) { + qdf_print(" %s :WMI Failed\n", __func__); + qdf_print("%s: Failed to send WMI_PEER_SMART_ANT_SET_TX_ANTENNA_CMDID.\n" + " Node: %s tx_antennas: [0x%08x 0x%08x] cmdstatus=%d\n", + __func__, + ether_sprintf(macaddr), + cmd->antenna_series[0], + cmd->antenna_series[1], + ret); + wmi_buf_free(buf); + } + return ret; +} + +/** + * send_smart_ant_set_training_info_cmd_non_tlv() - WMI set smart antenna + * training information function + * @param wmi_handle : handle to WMI. + * @macaddr : vdev mac address + * @param param : pointer to tx antenna param + * @return QDF_STATUS_SUCCESS on success and -ve on failure. + */ +QDF_STATUS send_smart_ant_set_training_info_cmd_non_tlv( + wmi_unified_t wmi_handle, + uint8_t macaddr[IEEE80211_ADDR_LEN], + struct smart_ant_training_info_params *param) +{ + wmi_peer_sant_set_train_antenna_cmd *cmd; + wmi_buf_t buf; + int len = 0; + int ret; + + len = sizeof(wmi_peer_sant_set_train_antenna_cmd); + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + qdf_print("%s:wmi_buf_alloc failed\n", __func__); + return QDF_STATUS_E_NOMEM; + } + + cmd = (wmi_peer_sant_set_train_antenna_cmd *)wmi_buf_data(buf); + cmd->vdev_id = param->vdev_id; + WMI_CHAR_ARRAY_TO_MAC_ADDR(macaddr, &cmd->peer_macaddr); + qdf_mem_copy(&cmd->train_rate_series[0], ¶m->rate_array[0], + (sizeof(uint32_t)*SMART_ANT_MAX_RATE_SERIES)); + qdf_mem_copy(&cmd->train_antenna_series[0], ¶m->antenna_array[0], + (sizeof(uint32_t)*SMART_ANT_MAX_RATE_SERIES)); + cmd->num_pkts = param->numpkts; + ret = wmi_unified_cmd_send(wmi_handle, + buf, + len, + WMI_PEER_SMART_ANT_SET_TRAIN_INFO_CMDID); + + if (ret != 0) { + qdf_print(" %s :WMI Failed\n", __func__); + qdf_print("%s: Failed to Send WMI_PEER_SMART_ANT_SET_TRAIN_INFO_CMDID.\n" + " Train Node: %s rate_array[0x%02x 0x%02x] " + "tx_antennas: [0x%08x 0x%08x] cmdstatus=%d\n", + __func__, + ether_sprintf(macaddr), + cmd->train_rate_series[0], + cmd->train_rate_series[1], + cmd->train_antenna_series[0], + cmd->train_antenna_series[1], + ret); + wmi_buf_free(buf); + } + return ret; +} + +/** + * send_smart_ant_set_node_config_cmd_non_tlv() - WMI set node + * configuration function + * @param wmi_handle : handle to WMI. + * @macaddr : vdev mad address + * @param param : pointer to tx antenna param + * @return QDF_STATUS_SUCCESS on success and -ve on failure. + */ +QDF_STATUS send_smart_ant_set_node_config_cmd_non_tlv(wmi_unified_t wmi_handle, + uint8_t macaddr[IEEE80211_ADDR_LEN], + struct smart_ant_node_config_params *param) +{ + wmi_peer_sant_set_node_config_ops_cmd *cmd; + wmi_buf_t buf; + int len = 0; + int ret; + int i = 0; + + len = sizeof(wmi_peer_sant_set_node_config_ops_cmd); + + if ((param->args_count == 0) || (param->args_count > + (sizeof(cmd->args) / sizeof(cmd->args[0])))) { + qdf_print("%s: Can't send a command with %d arguments\n", + __func__, param->args_count); + return QDF_STATUS_E_FAILURE; + } + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + qdf_print("%s:wmi_buf_alloc failed\n", __func__); + return QDF_STATUS_E_NOMEM; + } + + cmd = (wmi_peer_sant_set_node_config_ops_cmd *)wmi_buf_data(buf); + cmd->vdev_id = param->vdev_id; + WMI_CHAR_ARRAY_TO_MAC_ADDR(macaddr, &cmd->peer_macaddr); + cmd->cmd_id = param->cmd_id; + cmd->args_count = param->args_count; + for (i = 0; i < param->args_count; i++) + cmd->args[i] = param->args_arr[i]; + + ret = wmi_unified_cmd_send(wmi_handle, + buf, + len, + WMI_PEER_SMART_ANT_SET_NODE_CONFIG_OPS_CMDID); + + if (ret != 0) { + qdf_print(" %s :WMI Failed\n", __func__); + qdf_print("%s: Sent " + "WMI_PEER_SMART_ANT_SET_NODE_CONFIG_OPS_CMDID, cmd_id:" + " 0x%x\n Node: %s cmdstatus=%d\n", + __func__, param->cmd_id, ether_sprintf(macaddr), ret); + } + return ret; +} + +/** + * send_smart_ant_enable_tx_feedback_cmd_non_tlv() - WMI enable smart antenna + * tx feedback function + * @param wmi_handle : handle to WMI. + * @param param : pointer to hold enable param + * @return QDF_STATUS_SUCCESS on success and -ve on failure. + */ +QDF_STATUS send_smart_ant_enable_tx_feedback_cmd_non_tlv( + wmi_unified_t wmi_handle, + struct smart_ant_enable_tx_feedback_params *param) +{ + uint32_t types = 0; + int len = 0; + wmi_buf_t buf; + wmi_pdev_pktlog_enable_cmd *cmd; + + if (param->enable == 1) { + types |= WMI_PKTLOG_EVENT_TX; + types |= WMI_PKTLOG_EVENT_SMART_ANTENNA; + + len = sizeof(wmi_pdev_pktlog_enable_cmd); + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + qdf_print("%s:wmi_buf_alloc failed\n", __func__); + return QDF_STATUS_E_FAILURE; + } + cmd = (wmi_pdev_pktlog_enable_cmd *)wmi_buf_data(buf); + cmd->evlist = types; + /*enabling the pktlog for smart antenna tx feedback*/ + if (wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_PDEV_PKTLOG_ENABLE_CMDID)) + return QDF_STATUS_E_FAILURE; + return QDF_STATUS_SUCCESS; + } else if (param->enable == 0) { + buf = wmi_buf_alloc(wmi_handle, 0); + if (!buf) { + qdf_print("%s:wmi_buf_alloc failed\n", __func__); + return QDF_STATUS_E_FAILURE; + } + if (!wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_PDEV_PKTLOG_DISABLE_CMDID)) + return QDF_STATUS_E_FAILURE; + return QDF_STATUS_SUCCESS; + } else + return QDF_STATUS_E_FAILURE; +} + +/** + * send_vdev_spectral_configure_cmd_non_tlv() - send VDEV spectral configure + * command to fw + * @wmi_handle: wmi handle + * @param: pointer to hold spectral config parameter + * + * Return: 0 for success or error code + */ +QDF_STATUS send_vdev_spectral_configure_cmd_non_tlv(wmi_unified_t wmi_handle, + struct vdev_spectral_configure_params *param) +{ + wmi_vdev_spectral_configure_cmd *cmd; + wmi_buf_t buf; + int len = 0; + int ret; + + len = sizeof(wmi_vdev_spectral_configure_cmd); + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + qdf_print("%s:wmi_buf_alloc failed\n", __func__); + return QDF_STATUS_E_NOMEM; + } + + cmd = (wmi_vdev_spectral_configure_cmd *)wmi_buf_data(buf); + + cmd->vdev_id = param->vdev_id; + + cmd->spectral_scan_count = param->count; + cmd->spectral_scan_period = param->period; + cmd->spectral_scan_priority = param->spectral_pri; + cmd->spectral_scan_fft_size = param->fft_size; + cmd->spectral_scan_gc_ena = param->gc_enable; + cmd->spectral_scan_restart_ena = param->restart_enable; + cmd->spectral_scan_noise_floor_ref = param->noise_floor_ref; + cmd->spectral_scan_init_delay = param->init_delay; + cmd->spectral_scan_nb_tone_thr = param->nb_tone_thr; + cmd->spectral_scan_str_bin_thr = param->str_bin_thr; + cmd->spectral_scan_wb_rpt_mode = param->wb_rpt_mode; + cmd->spectral_scan_rssi_rpt_mode = param->rssi_rpt_mode; + cmd->spectral_scan_rssi_thr = param->rssi_thr; + cmd->spectral_scan_pwr_format = param->pwr_format; + cmd->spectral_scan_rpt_mode = param->rpt_mode; + cmd->spectral_scan_bin_scale = param->bin_scale; + cmd->spectral_scan_dBm_adj = param->dBm_adj; + cmd->spectral_scan_chn_mask = param->chn_mask; + + ret = wmi_unified_cmd_send(wmi_handle, + buf, + len, + WMI_VDEV_SPECTRAL_SCAN_CONFIGURE_CMDID); +#ifdef OL_SPECTRAL_DEBUG_CONFIG_INTERACTIONS + qdf_print("%s: Sent " + "WMI_VDEV_SPECTRAL_SCAN_CONFIGURE_CMDID\n", __func__); + + qdf_print("vdev_id = %u\n" + "spectral_scan_count = %u\n" + "spectral_scan_period = %u\n" + "spectral_scan_priority = %u\n" + "spectral_scan_fft_size = %u\n" + "spectral_scan_gc_ena = %u\n" + "spectral_scan_restart_ena = %u\n" + "spectral_scan_noise_floor_ref = %u\n" + "spectral_scan_init_delay = %u\n" + "spectral_scan_nb_tone_thr = %u\n" + "spectral_scan_str_bin_thr = %u\n" + "spectral_scan_wb_rpt_mode = %u\n" + "spectral_scan_rssi_rpt_mode = %u\n" + "spectral_scan_rssi_thr = %u\n" + "spectral_scan_pwr_format = %u\n" + "spectral_scan_rpt_mode = %u\n" + "spectral_scan_bin_scale = %u\n" + "spectral_scan_dBm_adj = %u\n" + "spectral_scan_chn_mask = %u\n", + param->vdev_id, + param->count, + param->period, + param->spectral_pri, + param->fft_size, + param->gc_enable, + param->restart_enable, + param->noise_floor_ref, + param->init_delay, + param->nb_tone_thr, + param->str_bin_thr, + param->wb_rpt_mode, + param->rssi_rpt_mode, + param->rssi_thr, + param->pwr_format, + param->rpt_mode, + param->bin_scale, + param->dBm_adj, + param->chn_mask); + qdf_print("%s: Status: %d\n\n", __func__, ret); +#endif /* OL_SPECTRAL_DEBUG_CONFIG_INTERACTIONS */ + + return ret; +} + +/** + * send_vdev_spectral_enable_cmd_non_tlv() - send VDEV spectral configure + * command to fw + * @wmi_handle: wmi handle + * @param: pointer to hold spectral enable parameter + * + * Return: 0 for success or error code + */ +QDF_STATUS send_vdev_spectral_enable_cmd_non_tlv(wmi_unified_t wmi_handle, + struct vdev_spectral_enable_params *param) +{ + wmi_vdev_spectral_enable_cmd *cmd; + wmi_buf_t buf; + int len = 0; + int ret; + + len = sizeof(wmi_vdev_spectral_enable_cmd); + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + qdf_print("%s:wmi_buf_alloc failed\n", __func__); + return QDF_STATUS_E_NOMEM; + } + + cmd = (wmi_vdev_spectral_enable_cmd *)wmi_buf_data(buf); + + cmd->vdev_id = param->vdev_id; + + if (param->active_valid) { + cmd->trigger_cmd = param->active ? 1 : 2; + /* 1: Trigger, 2: Clear Trigger */ + } else { + cmd->trigger_cmd = 0; /* 0: Ignore */ + } + + if (param->enabled_valid) { + cmd->enable_cmd = param->enabled ? 1 : 2; + /* 1: Enable 2: Disable */ + } else { + cmd->enable_cmd = 0; /* 0: Ignore */ + } + +#ifdef OL_SPECTRAL_DEBUG_CONFIG_INTERACTIONS + qdf_print + ("%s: Sent WMI_VDEV_SPECTRAL_SCAN_ENABLE_CMDID\n", __func__); + + qdf_print("vdev_id = %u\n" + "trigger_cmd = %u\n" + "enable_cmd = %u\n", + cmd->vdev_id, + cmd->trigger_cmd, + cmd->enable_cmd); + + qdf_print("%s: Status: %d\n\n", __func__, ret); +#endif /* OL_SPECTRAL_DEBUG_CONFIG_INTERACTIONS */ + + ret = wmi_unified_cmd_send(wmi_handle, + buf, + len, + WMI_VDEV_SPECTRAL_SCAN_ENABLE_CMDID); + return ret; +} + +/** + * send_pdev_set_regdomain_cmd_non_tlv() - send set regdomain command to fw + * @wmi_handle: wmi handle + * @param: pointer to pdev regdomain params + * + * Return: 0 for success or error code + */ +QDF_STATUS +send_pdev_set_regdomain_cmd_non_tlv(wmi_unified_t wmi_handle, + struct pdev_set_regdomain_params *param) +{ + wmi_pdev_set_regdomain_cmd *cmd; + wmi_buf_t buf; + + int len = sizeof(wmi_pdev_set_regdomain_cmd); + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + qdf_print("%s:wmi_buf_alloc failed\n", __func__); + return QDF_STATUS_E_FAILURE; + } + + cmd = (wmi_pdev_set_regdomain_cmd *)wmi_buf_data(buf); + + cmd->reg_domain = param->currentRDinuse; + cmd->reg_domain_2G = param->currentRD2G; + cmd->reg_domain_5G = param->currentRD5G; + cmd->conformance_test_limit_2G = param->ctl_2G; + cmd->conformance_test_limit_5G = param->ctl_5G; + cmd->dfs_domain = param->dfsDomain; + + return wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_PDEV_SET_REGDOMAIN_CMDID); +} + +/** + * send_set_quiet_mode_cmd_non_tlv() - send set quiet mode command to fw + * @wmi_handle: wmi handle + * @param: pointer to quiet mode params + * + * Return: 0 for success or error code + */ +QDF_STATUS +send_set_quiet_mode_cmd_non_tlv(wmi_unified_t wmi_handle, + struct set_quiet_mode_params *param) +{ + wmi_buf_t buf; + wmi_pdev_set_quiet_cmd *quiet_cmd; + int len = sizeof(wmi_pdev_set_quiet_cmd); + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + qdf_print("%s:wmi_buf_alloc failed\n", __func__); + return QDF_STATUS_E_NOMEM; + } + quiet_cmd = (wmi_pdev_set_quiet_cmd *)wmi_buf_data(buf); + quiet_cmd->enabled = param->enabled; + quiet_cmd->period = (param->period)*(param->intval); + quiet_cmd->duration = param->duration; + quiet_cmd->next_start = param->offset; + wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_PDEV_SET_QUIET_MODE_CMDID); + return QDF_STATUS_SUCCESS; +} + +/** + * send_set_beacon_filter_cmd_non_tlv() - send beacon filter command to fw + * @wmi_handle: wmi handle + * @param: pointer to beacon filter params + * + * Return: 0 for success or error code + */ +QDF_STATUS +send_set_beacon_filter_cmd_non_tlv(wmi_unified_t wmi_handle, + struct set_beacon_filter_params *param) +{ + /* Issue WMI command to set beacon filter */ + int i; + wmi_add_bcn_filter_cmd_t *cmd; + QDF_STATUS res; + wmi_buf_t buf = NULL; + int len = sizeof(wmi_add_bcn_filter_cmd_t); + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + qdf_print("buf alloc failed\n"); + return QDF_STATUS_E_NOMEM; + } + cmd = (wmi_add_bcn_filter_cmd_t *)wmi_buf_data(buf); + cmd->vdev_id = param->vdev_id; + qdf_print("vdev_id: %d\n", cmd->vdev_id); + + for (i = 0; i < BCN_FLT_MAX_ELEMS_IE_LIST; i++) + cmd->ie_map[i] = 0; + + if (param->ie) { + for (i = 0; i < BCN_FLT_MAX_ELEMS_IE_LIST; i++) + cmd->ie_map[i] = param->ie[i]; + } + res = wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_ADD_BCN_FILTER_CMDID); + return (res == QDF_STATUS_SUCCESS) ? + QDF_STATUS_SUCCESS : QDF_STATUS_E_FAILURE; +} + +/** + * send_remove_beacon_filter_cmd_non_tlv() - send remove beacon filter command + * to fw + * @wmi_handle: wmi handle + * @param: pointer to remove beacon filter params + * + * Return: 0 for success or error code + */ +QDF_STATUS +send_remove_beacon_filter_cmd_non_tlv(wmi_unified_t wmi_handle, + struct remove_beacon_filter_params *param) +{ + wmi_rmv_bcn_filter_cmd_t *cmd; + QDF_STATUS res; + wmi_buf_t buf = NULL; + int len = sizeof(wmi_rmv_bcn_filter_cmd_t); + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + qdf_print("buf alloc failed\n"); + return QDF_STATUS_E_NOMEM; + } + cmd = (wmi_rmv_bcn_filter_cmd_t *)wmi_buf_data(buf); + cmd->vdev_id = param->vdev_id; + res = wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_RMV_BCN_FILTER_CMDID); + return (res == QDF_STATUS_SUCCESS) ? + QDF_STATUS_SUCCESS : QDF_STATUS_E_FAILURE; +} + +/** + * send_mgmt_cmd_non_tlv() - send mgmt command to fw + * @wmi_handle: wmi handle + * @param: pointer to mgmt params + * Return: 0 for success or error code + */ +QDF_STATUS +send_mgmt_cmd_non_tlv(wmi_unified_t wmi_handle, + struct wmi_mgmt_params *param) +{ + wmi_mgmt_tx_cmd *cmd; + wmi_buf_t wmi_buf; + int len = sizeof(wmi_mgmt_tx_hdr) + param->frm_len; + + wmi_buf = wmi_buf_alloc(wmi_handle, roundup(len, sizeof(u_int32_t))); + if (!wmi_buf) { + qdf_print("%s: wmi_buf_alloc failed\n", __func__); + return QDF_STATUS_E_FAILURE; + } + cmd = (wmi_mgmt_tx_cmd *)wmi_buf_data(wmi_buf); + cmd->hdr.vdev_id = param->vdev_id; + WMI_CHAR_ARRAY_TO_MAC_ADDR(param->macaddr, &cmd->hdr.peer_macaddr); + cmd->hdr.buf_len = param->frm_len; + + +#ifdef BIG_ENDIAN_HOST + { + /* for big endian host, copy engine byte_swap is enabled + * But the mgmt frame buffer content is in network byte order + * Need to byte swap the mgmt frame buffer content - so when + * copy engine does byte_swap - target gets buffer content in + * the correct order + */ + int i; + u_int32_t *destp, *srcp; + destp = (u_int32_t *)cmd->bufp; + srcp = (u_int32_t *)wmi_buf_data(param->tx_frame); + for (i = 0; i < (roundup(param->frm_len, + sizeof(u_int32_t))/4); i++) { + *destp = qdf_le32_to_cpu(*srcp); + destp++; srcp++; + } + } +#else + qdf_mem_copy(cmd->bufp, wmi_buf_data(param->tx_frame), param->frm_len); +#endif + + /* Send the management frame buffer to the target */ + wmi_unified_cmd_send(wmi_handle, wmi_buf, roundup(len, + sizeof(u_int32_t)), WMI_MGMT_TX_CMDID); + return QDF_STATUS_SUCCESS; +} + +/** + * send_addba_clearresponse_cmd_non_tlv() - send addba clear response command + * to fw + * @wmi_handle: wmi handle + * @param: pointer to addba clearresp params + * @macaddr: vdev mac address + * Return: 0 for success or error code + */ +QDF_STATUS +send_addba_clearresponse_cmd_non_tlv(wmi_unified_t wmi_handle, + uint8_t macaddr[IEEE80211_ADDR_LEN], + struct addba_clearresponse_params *param) +{ + wmi_addba_clear_resp_cmd *cmd; + wmi_buf_t buf; + int len = sizeof(wmi_addba_clear_resp_cmd); + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + qdf_print("%s: wmi_buf_alloc failed\n", __func__); + return QDF_STATUS_E_FAILURE; + } + cmd = (wmi_addba_clear_resp_cmd *)wmi_buf_data(buf); + cmd->vdev_id = param->vdev_id; + WMI_CHAR_ARRAY_TO_MAC_ADDR(macaddr, &cmd->peer_macaddr); + + /* Send the management frame buffer to the target */ + wmi_unified_cmd_send(wmi_handle, buf, len, WMI_ADDBA_CLEAR_RESP_CMDID); + return QDF_STATUS_SUCCESS; +} + +/** + * send_addba_send_cmd_non_tlv() - send addba send command to fw + * @wmi_handle: wmi handle + * @param: pointer to addba send params + * @macaddr: vdev mac address + * Return: 0 for success or error code + */ +QDF_STATUS +send_addba_send_cmd_non_tlv(wmi_unified_t wmi_handle, + uint8_t macaddr[IEEE80211_ADDR_LEN], + struct addba_send_params *param) +{ + wmi_addba_send_cmd *cmd; + wmi_buf_t buf; + int len = sizeof(wmi_addba_send_cmd); + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + qdf_print("%s: wmi_buf_alloc failed\n", __func__); + return QDF_STATUS_E_FAILURE; + } + cmd = (wmi_addba_send_cmd *)wmi_buf_data(buf); + cmd->vdev_id = param->vdev_id; + WMI_CHAR_ARRAY_TO_MAC_ADDR(macaddr, &cmd->peer_macaddr); + cmd->tid = param->tidno; + cmd->buffersize = param->buffersize; + + /* Send the management frame buffer to the target */ + wmi_unified_cmd_send(wmi_handle, buf, len, WMI_ADDBA_SEND_CMDID); + return QDF_STATUS_SUCCESS; +} + +/** + * send_delba_send_cmd_non_tlv() - send delba send command to fw + * @wmi_handle: wmi handle + * @param: pointer to delba send params + * @macaddr: vdev mac address + * Return: 0 for success or error code + */ +QDF_STATUS +send_delba_send_cmd_non_tlv(wmi_unified_t wmi_handle, + uint8_t macaddr[IEEE80211_ADDR_LEN], + struct delba_send_params *param) +{ + wmi_delba_send_cmd *cmd; + wmi_buf_t buf; + int len = sizeof(wmi_delba_send_cmd); + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + qdf_print("%s: wmi_buf_alloc failed\n", __func__); + return QDF_STATUS_E_NOMEM; + } + + cmd = (wmi_delba_send_cmd *)wmi_buf_data(buf); + cmd->vdev_id = param->vdev_id; + WMI_CHAR_ARRAY_TO_MAC_ADDR(macaddr, &cmd->peer_macaddr); + cmd->tid = param->tidno; + cmd->initiator = param->initiator; + cmd->reasoncode = param->reasoncode; + + /* send the management frame buffer to the target */ + wmi_unified_cmd_send(wmi_handle, buf, len, WMI_DELBA_SEND_CMDID); + return QDF_STATUS_SUCCESS; +} + +/** + * send_addba_setresponse_cmd_non_tlv() - send addba set response command to fw + * @wmi_handle: wmi handle + * @param: pointer to addba setresp params + * @macaddr: vdev mac address + * Return: 0 for success or error code + */ +QDF_STATUS +send_addba_setresponse_cmd_non_tlv(wmi_unified_t wmi_handle, + uint8_t macaddr[IEEE80211_ADDR_LEN], + struct addba_setresponse_params *param) +{ + wmi_addba_setresponse_cmd *cmd; + wmi_buf_t buf; + int len = sizeof(wmi_addba_setresponse_cmd); + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + qdf_print("%s: wmi_buf_alloc failed\n", __func__); + return QDF_STATUS_E_NOMEM; + } + + cmd = (wmi_addba_setresponse_cmd *)wmi_buf_data(buf); + cmd->vdev_id = param->vdev_id; + WMI_CHAR_ARRAY_TO_MAC_ADDR(macaddr, &cmd->peer_macaddr); + cmd->tid = param->tidno; + cmd->statuscode = param->statuscode; + + /* send the management frame buffer to the target */ + wmi_unified_cmd_send(wmi_handle, buf, len, WMI_ADDBA_SET_RESP_CMDID); + return QDF_STATUS_SUCCESS; +} + +/** + * send_singleamsdu_cmd_non_tlv() - send single amsdu command to fw + * @wmi_handle: wmi handle + * @param: pointer to single amsdu params + * @macaddr: vdev mac address + * Return: 0 for success or error code + */ +QDF_STATUS +send_singleamsdu_cmd_non_tlv(wmi_unified_t wmi_handle, + uint8_t macaddr[IEEE80211_ADDR_LEN], + struct singleamsdu_params *param) +{ + wmi_send_singleamsdu_cmd *cmd; + wmi_buf_t buf; + int len = sizeof(wmi_send_singleamsdu_cmd); + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + qdf_print("%s: wmi_buf_alloc failed\n", __func__); + return QDF_STATUS_E_NOMEM; + } + + cmd = (wmi_send_singleamsdu_cmd *)wmi_buf_data(buf); + cmd->vdev_id = param->vdev_id; + WMI_CHAR_ARRAY_TO_MAC_ADDR(macaddr, &cmd->peer_macaddr); + cmd->tid = param->tidno; + + /* send the management frame buffer to the target */ + wmi_unified_cmd_send(wmi_handle, buf, len, WMI_SEND_SINGLEAMSDU_CMDID); + return QDF_STATUS_SUCCESS; +} + +/** + * send_set_qboost_param_cmd_non_tlv() - send set qboost command to fw + * @wmi_handle: wmi handle + * @param: pointer to qboost params + * @macaddr: vdev mac address + * Return: 0 for success or error code + */ +QDF_STATUS +send_set_qboost_param_cmd_non_tlv(wmi_unified_t wmi_handle, + uint8_t macaddr[IEEE80211_ADDR_LEN], + struct set_qboost_params *param) +{ + + WMI_QBOOST_CFG_CMD *cmd; + wmi_buf_t buf; + int ret; + + buf = wmi_buf_alloc(wmi_handle, sizeof(*cmd)); + if (!buf) { + qdf_print("%s: wmi_buf_alloc failed\n", __func__); + return QDF_STATUS_E_FAILURE; + } + + cmd = (WMI_QBOOST_CFG_CMD *)wmi_buf_data(buf); + cmd->vdev_id = param->vdev_id; + WMI_CHAR_ARRAY_TO_MAC_ADDR(macaddr, &cmd->peer_macaddr); + cmd->qb_enable = param->value; + + ret = wmi_unified_cmd_send(wmi_handle, buf, sizeof(*cmd), + WMI_QBOOST_CFG_CMDID); + return ret; +} + +/** + * send_mu_scan_cmd_non_tlv() - send mu scan command to fw + * @wmi_handle: wmi handle + * @param: pointer to mu scan params + * Return: 0 for success or error code + */ +QDF_STATUS +send_mu_scan_cmd_non_tlv(wmi_unified_t wmi_handle, + struct mu_scan_params *param) +{ + wmi_mu_start_cmd *cmd; + wmi_buf_t buf; + + buf = wmi_buf_alloc(wmi_handle, sizeof(wmi_mu_start_cmd)); + if (!buf) { + qdf_print("%s: wmi_buf_alloc failed\n", __func__); + return QDF_STATUS_E_FAILURE; + } + cmd = (wmi_mu_start_cmd *)wmi_buf_data(buf); + cmd->mu_request_id = param->id; + cmd->mu_duration = param->duration; + cmd->mu_type = param->type; + cmd->lteu_tx_power = param->lteu_tx_power; + return wmi_unified_cmd_send(wmi_handle, buf, + sizeof(wmi_mu_start_cmd), + WMI_MU_CAL_START_CMDID); +} + +/** + * send_lteu_config_cmd_non_tlv() - send lteu config command to fw + * @wmi_handle: wmi handle + * @param: pointer to lteu config params + * Return: 0 for success or error code + */ +QDF_STATUS +send_lteu_config_cmd_non_tlv(wmi_unified_t wmi_handle, + struct lteu_config_params *param) +{ + wmi_set_lteu_config *cmd; + wmi_buf_t buf; + int i; + + buf = wmi_buf_alloc(wmi_handle, sizeof(wmi_set_lteu_config)); + if (!buf) { + qdf_print("%s: wmi_buf_alloc failed\n", __func__); + return QDF_STATUS_E_FAILURE; + } + cmd = (wmi_set_lteu_config *)wmi_buf_data(buf); + cmd->gpio_enable = param->lteu_gpio_start; + cmd->num_lteu_bins = param->lteu_num_bins; + for (i = 0; i < cmd->num_lteu_bins; i++) { + cmd->mu_rssi_threshold[i] = param->lteu_thresh[i]; + cmd->mu_weight[i] = param->lteu_weight[i]; + cmd->mu_gamma[i] = param->lteu_gamma[i]; + } + cmd->mu_scan_timeout = param->lteu_scan_timeout; + cmd->alpha_num_bssid = param->alpha_num_bssid; + cmd->use_actual_nf = param->use_actual_nf; + cmd->wifi_tx_power = param->wifi_tx_power; + return wmi_unified_cmd_send(wmi_handle, buf, + sizeof(wmi_set_lteu_config), + WMI_SET_LTEU_CONFIG_CMDID); +} + +/** + * send_pdev_get_tpc_config_cmd_non_tlv() - send get tpc config command to fw + * @wmi_handle: wmi handle + * @param: pointer to get tpc config params + * + * Return: 0 for success or error code + */ +QDF_STATUS +send_pdev_get_tpc_config_cmd_non_tlv(wmi_unified_t wmi_handle, + uint32_t param) +{ + wmi_pdev_get_tpc_config_cmd *cmd; + wmi_buf_t buf; + int32_t len = sizeof(wmi_pdev_get_tpc_config_cmd); + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + qdf_print("%s:wmi_buf_alloc failed\n", __func__); + return QDF_STATUS_E_FAILURE; + } + cmd = (wmi_pdev_get_tpc_config_cmd *)wmi_buf_data(buf); + cmd->param = param; + return wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_PDEV_GET_TPC_CONFIG_CMDID); +} + +/** + * send_set_bwf_cmd_non_tlv() - send set bwf command to fw + * @wmi_handle: wmi handle + * @param: pointer to set bwf param + * + * Return: 0 for success or error code + */ +QDF_STATUS +send_set_bwf_cmd_non_tlv(wmi_unified_t wmi_handle, + struct set_bwf_params *param) +{ + struct wmi_bwf_peer_info *peer_info; + wmi_peer_bwf_request *cmd; + wmi_buf_t buf; + int len = sizeof(wmi_peer_bwf_request); + int i, retval = 0; + + len += param->num_peers * sizeof(struct wmi_bwf_peer_info); + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + qdf_print("%s:wmi_buf_alloc failed\n", __func__); + return QDF_STATUS_E_FAILURE; + } + cmd = (wmi_peer_bwf_request *)wmi_buf_data(buf); + qdf_mem_copy((void *)&(cmd->num_peers), + (void *)&(param->num_peers), + sizeof(u_int32_t)); + peer_info = (struct wmi_bwf_peer_info *)&(cmd->peer_info[0]); + for (i = 0; i < param->num_peers; i++) { + qdf_mem_copy((void *)&(peer_info[i]), + (void *)&(param->peer_info[i]), + sizeof(struct wmi_bwf_peer_info)); + } + + retval = wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_PEER_BWF_REQUEST_CMDID); + + if (retval) + wmi_buf_free(buf); + + return retval; +} + +/** + * send_set_atf_cmd_non_tlv() - send set atf command to fw + * @wmi_handle: wmi handle + * @param: pointer to set atf param + * + * Return: 0 for success or error code + */ +QDF_STATUS +send_set_atf_cmd_non_tlv(wmi_unified_t wmi_handle, + struct set_atf_params *param) +{ + struct wmi_atf_peer_info *peer_info; + wmi_peer_atf_request *cmd; + wmi_buf_t buf; + int len = sizeof(wmi_peer_atf_request); + int i, retval = 0; + + len += param->num_peers * sizeof(struct wmi_atf_peer_info); + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + qdf_print("%s:wmi_buf_alloc failed\n", __func__); + return QDF_STATUS_E_FAILURE; + } + + cmd = (wmi_peer_atf_request *)wmi_buf_data(buf); + qdf_mem_copy((void *)&(cmd->num_peers), (void *)&(param->num_peers), + sizeof(uint32_t)); + peer_info = (struct wmi_atf_peer_info *)&(cmd->peer_info[0]); + for (i = 0; i < param->num_peers; i++) { + qdf_mem_copy((void *)&(peer_info[i]), + (void *)&(param->peer_info[i]), + sizeof(struct wmi_atf_peer_info)); + } +/* qdf_print("wmi_unified_pdev_set_atf peer_num=%d\n", cmd->num_peers); */ + retval = wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_PEER_ATF_REQUEST_CMDID); + return retval; +} + +/** + * send_atf_peer_request_cmd_non_tlv() - send atf peer request command to fw + * @wmi_handle: wmi handle + * @param: pointer to atf peer request param + * + * Return: 0 for success or error code + */ +QDF_STATUS +send_atf_peer_request_cmd_non_tlv(wmi_unified_t wmi_handle, + struct atf_peer_request_params *param) +{ + struct wmi_atf_peer_ext_info *peer_ext_info; + wmi_peer_atf_ext_request *cmd; + wmi_buf_t buf; + int len = sizeof(wmi_peer_atf_ext_request); + int i, retval = 0; + + len += param->num_peers * sizeof(struct wmi_atf_peer_ext_info); + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + qdf_print("%s:wmi_buf_alloc failed\n", __func__); + return QDF_STATUS_E_FAILURE; + } + + cmd = (wmi_peer_atf_ext_request *)wmi_buf_data(buf); + qdf_mem_copy((void *)&(cmd->num_peers), (void *)&(param->num_peers), + sizeof(uint32_t)); + peer_ext_info = + (struct wmi_atf_peer_ext_info *)&(cmd->peer_ext_info[0]); + for (i = 0; i < param->num_peers; i++) { + qdf_mem_copy((void *)&(peer_ext_info[i]), + (void *)&(param->peer_ext_info[i]), + sizeof(struct wmi_atf_peer_ext_info)); + } + retval = wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_PEER_ATF_EXT_REQUEST_CMDID); + return retval; +} + +/** + * send_set_atf_grouping_cmd_non_tlv() - send set atf grouping command to fw + * @wmi_handle: wmi handle + * @param: pointer to set atf grouping param + * + * Return: 0 for success or error code + */ +QDF_STATUS +send_set_atf_grouping_cmd_non_tlv(wmi_unified_t wmi_handle, + struct atf_grouping_params *param) +{ + struct wmi_atf_group_info *group_info; + wmi_atf_ssid_grp_request *cmd; + wmi_buf_t buf; + int len = sizeof(wmi_atf_ssid_grp_request); + int i, retval = 0; + + len += param->num_groups * sizeof(struct wmi_atf_group_info); + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + qdf_print("%s:wmi_buf_alloc failed\n", __func__); + return QDF_STATUS_E_FAILURE; + } + + cmd = (wmi_atf_ssid_grp_request *)wmi_buf_data(buf); + qdf_mem_copy((void *)&(cmd->num_groups), (void *)&(param->num_groups), + sizeof(uint32_t)); + group_info = (struct wmi_atf_group_info *)&(cmd->group_info[0]); + for (i = 0; i < param->num_groups; i++) { + qdf_mem_copy((void *)&(group_info[i]), + (void *)&(param->group_info[i]), + sizeof(struct wmi_atf_group_info)); + } + retval = wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_ATF_SSID_GROUPING_REQUEST_CMDID); + return retval; +} + +/** + * send_wlan_profile_enable_cmd_non_tlv() - send wlan profile enable command + * to fw + * @wmi_handle: wmi handle + * @param: pointer to wlan profile param + * + * Return: 0 for success or error code + */ +QDF_STATUS +send_wlan_profile_enable_cmd_non_tlv(wmi_unified_t wmi_handle, + struct wlan_profile_params *param) +{ + wmi_buf_t buf; + uint16_t len; + wmi_wlan_profile_enable_profile_id_cmd *cmd; + + len = sizeof(wmi_wlan_profile_enable_profile_id_cmd); + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + qdf_print("%s:wmi_buf_alloc failed\n", __func__); + return QDF_STATUS_E_FAILURE; + } + cmd = (wmi_wlan_profile_enable_profile_id_cmd *)wmi_buf_data(buf); + cmd->profile_id = param->profile_id; + cmd->enable = param->enable; + return wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_WLAN_PROFILE_ENABLE_PROFILE_ID_CMDID); +} + +/** + * send_wlan_profile_trigger_cmd_non_tlv() - send wlan profile trigger command + * to fw + * @wmi_handle: wmi handle + * @param: pointer to wlan profile param + * + * Return: 0 for success or error code + */ +QDF_STATUS +send_wlan_profile_trigger_cmd_non_tlv(wmi_unified_t wmi_handle, + struct wlan_profile_params *param) +{ + wmi_buf_t buf; + uint16_t len; + wmi_wlan_profile_trigger_cmd *cmd; + + len = sizeof(wmi_wlan_profile_trigger_cmd); + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + qdf_print("%s:wmi_buf_alloc failed\n", __func__); + return QDF_STATUS_E_FAILURE; + } + cmd = (wmi_wlan_profile_trigger_cmd *)wmi_buf_data(buf); + cmd->enable = param->enable; + return wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_WLAN_PROFILE_TRIGGER_CMDID); +} + +#ifdef BIG_ENDIAN_HOST +void wmi_host_swap_bytes(void *pv, size_t n) +{ + int noWords; + int i; + A_UINT32 *wordPtr; + + noWords = n/sizeof(u_int32_t); + wordPtr = (u_int32_t *)pv; + for (i = 0; i < noWords; i++) + *(wordPtr + i) = __cpu_to_le32(*(wordPtr + i)); +} +#define WMI_HOST_SWAPME(x, len) wmi_host_swap_bytes(&x, len); +#endif + +/** + * send_set_ht_ie_cmd_non_tlv() - send ht ie command to fw + * @wmi_handle: wmi handle + * @param: pointer to ht ie param + * + * Return: 0 for success or error code + */ +QDF_STATUS +send_set_ht_ie_cmd_non_tlv(wmi_unified_t wmi_handle, + struct ht_ie_params *param) +{ + wmi_pdev_set_ht_ie_cmd *cmd; + wmi_buf_t buf; + /* adjust length to be next multiple of four */ + int len = (param->ie_len + (sizeof(uint32_t) - 1)) & + (~(sizeof(uint32_t) - 1)); + + /* to account for extra four bytes of ie data in the struct */ + len += (sizeof(wmi_pdev_set_ht_ie_cmd) - 4); + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + qdf_print("%s:wmi_buf_alloc failed\n", __func__); + return QDF_STATUS_E_FAILURE; + } + cmd = (wmi_pdev_set_ht_ie_cmd *)wmi_buf_data(buf); + cmd->ie_len = param->ie_len; + qdf_mem_copy(cmd->ie_data, param->ie_data, param->ie_len); +#ifdef BIG_ENDIAN_HOST + WMI_HOST_SWAPME(cmd->ie_data, len-(offsetof(wmi_pdev_set_ht_ie_cmd, + ie_data))); +#endif + return wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_PDEV_SET_HT_CAP_IE_CMDID); +} + +/** + * send_set_vht_ie_cmd_non_tlv() - send vht ie command to fw + * @wmi_handle: wmi handle + * @param: pointer to vht ie param + * + * Return: 0 for success or error code + */ +QDF_STATUS +send_set_vht_ie_cmd_non_tlv(wmi_unified_t wmi_handle, + struct vht_ie_params *param) +{ + wmi_pdev_set_vht_ie_cmd *cmd; + wmi_buf_t buf; + /* adjust length to be next multiple of four */ + int len = (param->ie_len + (sizeof(u_int32_t) - 1)) & + (~(sizeof(u_int32_t) - 1)); + + /* to account for extra four bytes of ie data in the struct */ + len += (sizeof(wmi_pdev_set_vht_ie_cmd) - 4); + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + qdf_print("%s:wmi_buf_alloc failed\n", __func__); + return QDF_STATUS_E_FAILURE; + } + cmd = (wmi_pdev_set_vht_ie_cmd *)wmi_buf_data(buf); + cmd->ie_len = param->ie_len; + qdf_mem_copy(cmd->ie_data, param->ie_data, param->ie_len); +#ifdef BIG_ENDIAN_HOST + WMI_HOST_SWAPME(cmd->ie_data, len-(offsetof(wmi_pdev_set_vht_ie_cmd, + ie_data))); +#endif + return wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_PDEV_SET_VHT_CAP_IE_CMDID); +} + +/** + * send_wmm_update_cmd_non_tlv() - send wmm update command to fw + * @wmi_handle: wmi handle + * @param: pointer to wmm update param + * + * Return: 0 for success or error code + */ +QDF_STATUS +send_wmm_update_cmd_non_tlv(wmi_unified_t wmi_handle, + struct wmm_update_params *param) +{ +#define ATH_EXPONENT_TO_VALUE(v) ((1<wmep_array[ac]; + switch (ac) { + case WME_AC_BE: + wmi_param = &cmd->wmm_params_ac_be; + break; + case WME_AC_BK: + wmi_param = &cmd->wmm_params_ac_bk; + break; + case WME_AC_VI: + wmi_param = &cmd->wmm_params_ac_vi; + break; + case WME_AC_VO: + wmi_param = &cmd->wmm_params_ac_vo; + break; + default: + break; + } + + wmi_param->aifs = wmep->wmep_aifsn; + wmi_param->cwmin = ATH_EXPONENT_TO_VALUE(wmep->wmep_logcwmin); + wmi_param->cwmax = ATH_EXPONENT_TO_VALUE(wmep->wmep_logcwmax); + wmi_param->txoplimit = ATH_TXOP_TO_US(wmep->wmep_txopLimit); + wmi_param->acm = wmep->wmep_acm; + wmi_param->no_ack = wmep->wmep_noackPolicy; + + } + + wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_PDEV_SET_WMM_PARAMS_CMDID); + return QDF_STATUS_SUCCESS; +} + +/** + * send_set_ant_switch_tbl_cmd_non_tlv() - send ant switch tbl cmd to fw + * @wmi_handle: wmi handle + * @param: pointer to hold ant switch tbl param + * + * Return: 0 for success or error code + */ +QDF_STATUS +send_set_ant_switch_tbl_cmd_non_tlv(wmi_unified_t wmi_handle, + struct ant_switch_tbl_params *param) +{ + uint8_t len; + wmi_buf_t buf; + wmi_pdev_set_ant_switch_tbl_cmd *cmd; + + len = sizeof(wmi_pdev_set_ant_switch_tbl_cmd); + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + qdf_print("%s:wmi_buf_alloc failed\n", __func__); + return QDF_STATUS_E_NOMEM; + } + cmd = (wmi_pdev_set_ant_switch_tbl_cmd *)wmi_buf_data(buf); + cmd->antCtrlCommon1 = param->ant_ctrl_common1; + cmd->antCtrlCommon2 = param->ant_ctrl_common2; + + if (wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_PDEV_SET_ANTENNA_SWITCH_TABLE_CMDID)) { + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * send_set_ratepwr_table_cmd_non_tlv() - send rate power table cmd to fw + * @wmi_handle: wmi handle + * @param: pointer to hold rate power table param + * + * Return: 0 for success or error code + */ +QDF_STATUS +send_set_ratepwr_table_cmd_non_tlv(wmi_unified_t wmi_handle, + struct ratepwr_table_params *param) +{ + uint16_t len; + wmi_buf_t buf; + wmi_pdev_ratepwr_table_cmd *cmd; + + if (!param->ratepwr_tbl) + return QDF_STATUS_E_FAILURE; + + len = sizeof(wmi_pdev_ratepwr_table_cmd); + len += roundup(param->ratepwr_len, sizeof(A_UINT32)) - sizeof(A_UINT32); + /* already 4 bytes in cmd structure */ + qdf_print("wmi buf len = %d\n", len); + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + qdf_print("%s:wmi_buf_alloc failed\n", __func__); + return QDF_STATUS_E_NOMEM; + } + cmd = (wmi_pdev_ratepwr_table_cmd *)wmi_buf_data(buf); + + cmd->op = RATEPWR_TABLE_OPS_SET; + cmd->ratepwr_len = param->ratepwr_len; + WMI_HOST_IF_MSG_COPY_CHAR_ARRAY(&cmd->ratepwr_tbl[0], + param->ratepwr_tbl, param->ratepwr_len); + + if (wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_PDEV_RATEPWR_TABLE_CMDID)) { + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * send_get_ratepwr_table_cmd_non_tlv() - send rate power table cmd to fw + * @wmi_handle: wmi handle + * + * Return: 0 for success or error code + */ +QDF_STATUS +send_get_ratepwr_table_cmd_non_tlv(wmi_unified_t wmi_handle) +{ + uint16_t len; + wmi_buf_t buf; + wmi_pdev_ratepwr_table_cmd *cmd; + + len = sizeof(wmi_pdev_ratepwr_table_cmd); + qdf_print("wmi buf len = %d\n", len); + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + qdf_print("%s:wmi_buf_alloc failed\n", __func__); + return QDF_STATUS_E_NOMEM; + } + cmd = (wmi_pdev_ratepwr_table_cmd *)wmi_buf_data(buf); + + cmd->op = RATEPWR_TABLE_OPS_GET; + cmd->ratepwr_len = 0; + cmd->ratepwr_tbl[0] = 0; + + if (wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_PDEV_RATEPWR_TABLE_CMDID)) { + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * send_set_ctl_table_cmd_non_tlv() - send ctl table cmd to fw + * @wmi_handle: wmi handle + * @param: pointer to hold ctl table param + * + * Return: 0 for success or error code + */ +QDF_STATUS +send_set_ctl_table_cmd_non_tlv(wmi_unified_t wmi_handle, + struct ctl_table_params *param) +{ +/* for QC98XX only */ +/*6 modes (A, HT20, HT40, VHT20, VHT40, VHT80) * 3 reg dommains + * TODO for 160/80+80 + */ +#define WHAL_NUM_CTLS_5G 18 +/*6 modes (B, G, HT20, HT40, VHT20, VHT40) * 3 reg domains */ +#define WHAL_NUM_CTLS_2G 18 +#define WHAL_NUM_BAND_EDGES_5G 8 +#define WHAL_NUM_BAND_EDGES_2G 4 + uint16_t len; + wmi_buf_t buf; + wmi_pdev_set_ctl_table_cmd *cmd; + + if (!param->ctl_array) + return QDF_STATUS_E_FAILURE; + + if (!param->is_acfg_ctl && param->ctl_len != + WHAL_NUM_CTLS_2G * WHAL_NUM_BAND_EDGES_2G * 2 + + WHAL_NUM_CTLS_5G * WHAL_NUM_BAND_EDGES_5G * 2) { + qdf_print("CTL array len not correct\n"); + return QDF_STATUS_E_FAILURE; + } + + len = sizeof(wmi_pdev_set_ctl_table_cmd); + len += roundup(param->ctl_len, sizeof(A_UINT32)) - sizeof(A_UINT32); + qdf_print("wmi buf len = %d\n", len); + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + qdf_print("%s:wmi_buf_alloc failed\n", __func__); + return QDF_STATUS_E_FAILURE; + } + cmd = (wmi_pdev_set_ctl_table_cmd *)wmi_buf_data(buf); + + cmd->ctl_len = param->ctl_len; + WMI_HOST_IF_MSG_COPY_CHAR_ARRAY(&cmd->ctl_info[0], param->ctl_array, + param->ctl_len); + + if (param->is_acfg_ctl) + len = param->ctl_len; + + if (wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_PDEV_SET_CTL_TABLE_CMDID)) { + qdf_print("%s:Failed to send command\n", __func__); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +#undef WHAL_NUM_CTLS_5G +#undef WHAL_NUM_CTLS_2G +#undef WHAL_NUM_BAND_EDGES_5G +#undef WHAL_NUM_BAND_EDGES_2G +} + +/** + * send_set_mimogain_table_cmd_non_tlv() - send mimogain table cmd to fw + * @wmi_handle: wmi handle + * @param: pointer to hold mimogain table param + * + * Return: 0 for success or error code + */ +QDF_STATUS +send_set_mimogain_table_cmd_non_tlv(wmi_unified_t wmi_handle, + struct mimogain_table_params *param) +{ +/* for QC98XX only */ +#define WHAL_TX_NUM_CHAIN 0x3 +#define WHAL_TPC_REGINDEX_MAX 4 +#define WHAL_ARRAY_GAIN_NUM_STREAMS 2 + + uint16_t len; + wmi_buf_t buf; + wmi_pdev_set_mimogain_table_cmd *cmd; + + if (!param->array_gain) + return QDF_STATUS_E_FAILURE; + + /* len must be multiple of a single array gain table */ + if (param->tbl_len % ((WHAL_TX_NUM_CHAIN-1) * WHAL_TPC_REGINDEX_MAX * + WHAL_ARRAY_GAIN_NUM_STREAMS) != 0) { + qdf_print("Array gain table len not correct\n"); + return QDF_STATUS_E_FAILURE; + } + + len = sizeof(wmi_pdev_set_mimogain_table_cmd); + len += roundup(param->tbl_len, sizeof(A_UINT32)) - sizeof(A_UINT32); + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + qdf_print("%s:wmi_buf_alloc failed\n", __func__); + return QDF_STATUS_E_FAILURE; + } + cmd = (wmi_pdev_set_mimogain_table_cmd *)wmi_buf_data(buf); + + WMI_MIMOGAIN_ARRAY_GAIN_LEN_SET(cmd->mimogain_info, param->tbl_len); + WMI_MIMOGAIN_MULTI_CHAIN_BYPASS_SET(cmd->mimogain_info, + param->multichain_gain_bypass); + WMI_HOST_IF_MSG_COPY_CHAR_ARRAY(&cmd->arraygain_tbl[0], + param->array_gain, + param->tbl_len); + + if (wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_PDEV_SET_MIMOGAIN_TABLE_CMDID)) { + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +#undef WHAL_TX_NUM_CHAIN +#undef WHAL_TPC_REGINDEX_MAX +#undef WHAL_ARRAY_GAIN_NUM_STREAMS +} + +/** + * send_set_ratepwr_chainmsk_cmd_non_tlv() - send ratepwr chainmask cmd to fw + * @wmi_handle: wmi handle + * @param: pointer to hold ratepwr chainmask param + * + * Return: 0 for success or error code + */ +QDF_STATUS +send_set_ratepwr_chainmsk_cmd_non_tlv(wmi_unified_t wmi_handle, + struct ratepwr_chainmsk_params *param) +{ +#define RC_CCK_OFDM_RATES 0 +#define RC_HT_RATES 1 +#define RC_VHT_RATES 2 + uint16_t len; + wmi_buf_t buf; + wmi_pdev_ratepwr_chainmsk_tbl_cmd *cmd; + + if (!param->ratepwr_chain_tbl) + return QDF_STATUS_E_FAILURE; + + len = sizeof(wmi_pdev_ratepwr_chainmsk_tbl_cmd); + len += roundup(param->num_rate*sizeof(uint32_t), sizeof(A_UINT32)); + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + qdf_print("%s:wmi_buf_alloc failed\n", __func__); + return QDF_STATUS_E_NOMEM; + } + cmd = (wmi_pdev_ratepwr_chainmsk_tbl_cmd *)wmi_buf_data(buf); + cmd->op = param->ops; + cmd->pream_type = param->pream_type; + cmd->rate_len = param->num_rate; + + if (param->ops == RATEPWR_CHAINMSK_TABLE_OPS_EN) { + qdf_mem_copy(&cmd->ratepwr_chaintbl[0], + param->ratepwr_chain_tbl, + param->num_rate*sizeof(u_int32_t)); + } + + wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_PDEV_RATEPWR_CHAINMSK_TABLE_CMDID); + return QDF_STATUS_SUCCESS; +} + +/** + * send_set_macaddr_cmd_non_tlv() - send set macaddr cmd to fw + * @wmi_handle: wmi handle + * @param: pointer to hold macaddr param + * + * Return: 0 for success or error code + */ +QDF_STATUS +send_set_macaddr_cmd_non_tlv(wmi_unified_t wmi_handle, + struct macaddr_params *param) +{ + uint8_t len; + wmi_buf_t buf; + wmi_pdev_set_base_macaddr_cmd *cmd; + + len = sizeof(wmi_pdev_set_base_macaddr_cmd); + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + qdf_print("%s:wmi_buf_alloc failed\n", __func__); + return QDF_STATUS_E_FAILURE; + } + cmd = (wmi_pdev_set_base_macaddr_cmd *)wmi_buf_data(buf); + WMI_CHAR_ARRAY_TO_MAC_ADDR(param->macaddr, &cmd->base_macaddr); + + if (wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_PDEV_SET_BASE_MACADDR_CMDID)) { + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * send_pdev_scan_start_cmd_non_tlv() - send pdev scan start cmd to fw + * @wmi_handle: wmi handle + * + * Return: 0 for success or error code + */ +QDF_STATUS +send_pdev_scan_start_cmd_non_tlv(wmi_unified_t wmi_handle) +{ + /* + * this command was added to support host scan egine which is + * deprecated. now the scan engine is in FW and host directly + * isssues a scan request to perform scan and provide results back + * to host + */ + wmi_buf_t buf; + wmi_pdev_scan_cmd *cmd; + int len = sizeof(wmi_pdev_scan_cmd); + + buf = wmi_buf_alloc(wmi_handle, len); + qdf_print("%s:\n", __func__); + if (!buf) { + qdf_print("%s:wmi_buf_alloc failed\n", __func__); + return QDF_STATUS_E_NOMEM; + } + cmd = (wmi_pdev_scan_cmd *)wmi_buf_data(buf); + cmd->scan_start = TRUE; +#if DEPRECATE_WMI + wmi_unified_cmd_send(wmi_handle, buf, len, WMI_PDEV_SCAN_CMDID); +#endif + return QDF_STATUS_SUCCESS; +} + +/** + * send_pdev_scan_end_cmd_non_tlv() - send pdev scan end cmd to fw + * @wmi_handle: wmi handle + * + * Return: 0 for success or error code + */ +QDF_STATUS +send_pdev_scan_end_cmd_non_tlv(wmi_unified_t wmi_handle) +{ + /* + * this command was added to support host scan egine which is + * deprecated. now the scan engine is in FW and host directly isssues + * a scan request to perform scan and provide results back to host + */ + wmi_pdev_scan_cmd *cmd; + wmi_buf_t buf; + int len = sizeof(wmi_pdev_scan_cmd); + + buf = wmi_buf_alloc(wmi_handle, len); + qdf_print("%s:\n", __func__); + if (!buf) { + qdf_print("%s:wmi_buf_alloc failed\n", __func__); + return QDF_STATUS_E_NOMEM; + } + cmd = (wmi_pdev_scan_cmd *)wmi_buf_data(buf); + cmd->scan_start = FALSE; +#if DEPRECATE_WMI + wmi_unified_cmd_send(wmi_handle, buf, len, WMI_PDEV_SCAN_CMDID); +#endif + return QDF_STATUS_SUCCESS; +} + +/** + * send_set_acparams_cmd_non_tlv() - send acparams cmd to fw + * @wmi_handle: wmi handle + * @param: pointer to hold acparams + * + * Return: 0 for success or error code + */ +QDF_STATUS +send_set_acparams_cmd_non_tlv(wmi_unified_t wmi_handle, + struct acparams_params *param) +{ + wmi_pdev_set_param_cmd *cmd; + wmi_buf_t buf; + uint32_t param_value = 0; + int len = sizeof(wmi_pdev_set_param_cmd); + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + qdf_print("%s:wmi_buf_alloc failed\n", __func__); + return QDF_STATUS_E_NOMEM; + } + + cmd = (wmi_pdev_set_param_cmd *)wmi_buf_data(buf); + cmd->param_id = WMI_PDEV_PARAM_AC_AGGRSIZE_SCALING; + param_value = param->ac; + param_value |= (param->aggrsize_scaling << 8); + cmd->param_value = param_value; + + wmi_unified_cmd_send(wmi_handle, buf, len, WMI_PDEV_SET_PARAM_CMDID); + return QDF_STATUS_SUCCESS; +} + +/** + * send_set_vap_dscp_tid_map_cmd_non_tlv() - send vap dscp tid map cmd to fw + * @wmi_handle: wmi handle + * @param: pointer to hold vap dscp tid map param + * + * Return: 0 for success or error code + */ +QDF_STATUS +send_set_vap_dscp_tid_map_cmd_non_tlv(wmi_unified_t wmi_handle, + struct vap_dscp_tid_map_params *param) +{ + wmi_buf_t buf; + wmi_vdev_set_dscp_tid_map_cmd *cmd_vdev; + int len_vdev = sizeof(wmi_vdev_set_dscp_tid_map_cmd); + + buf = wmi_buf_alloc(wmi_handle, len_vdev); + if (!buf) { + qdf_print("%s:wmi_buf_alloc failed\n", __func__); + return QDF_STATUS_E_FAILURE; + } + + cmd_vdev = (wmi_vdev_set_dscp_tid_map_cmd *)wmi_buf_data(buf); + qdf_mem_copy(cmd_vdev->dscp_to_tid_map, param->dscp_to_tid_map, + sizeof(A_UINT32) * WMI_DSCP_MAP_MAX); + + cmd_vdev->vdev_id = param->vdev_id; + + qdf_print("Setting dscp for vap id: %d\n", cmd_vdev->vdev_id); + return wmi_unified_cmd_send(wmi_handle, buf, len_vdev, + WMI_VDEV_SET_DSCP_TID_MAP_CMDID); +} + +/** + * send_proxy_ast_reserve_cmd_non_tlv() - send proxy ast reserve cmd to fw + * @wmi_handle: wmi handle + * @param: pointer to hold proxy ast reserve param + * + * Return: 0 for success or error code + */ +QDF_STATUS +send_proxy_ast_reserve_cmd_non_tlv(wmi_unified_t wmi_handle, + struct proxy_ast_reserve_params *param) +{ + wmi_pdev_reserve_ast_entry_cmd *cmd; + wmi_buf_t buf; + int len = sizeof(wmi_pdev_reserve_ast_entry_cmd); + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + qdf_print("%s:wmi_buf_alloc failed\n", __func__); + return QDF_STATUS_E_FAILURE; + } + cmd = (wmi_pdev_reserve_ast_entry_cmd *)wmi_buf_data(buf); + WMI_CHAR_ARRAY_TO_MAC_ADDR(param->macaddr, &cmd->mac_addr); + cmd->key_id = 0; + cmd->mcast = 0; + + qdf_print("%s macaddr=%s key_id=%d mcast=%d\n", __func__, + ether_sprintf(param->macaddr), cmd->key_id, cmd->mcast); + + return wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_PDEV_RESERVE_AST_ENTRY_CMDID); +} + +/** + * send_pdev_fips_cmd_non_tlv() - send pdev fips cmd to fw + * @wmi_handle: wmi handle + * @param: pointer to hold pdev fips param + * + * Return: 0 for success or error code + */ +QDF_STATUS +send_pdev_fips_cmd_non_tlv(wmi_unified_t wmi_handle, + struct fips_params *param) +{ + wmi_pdev_fips_cmd *cmd; + wmi_buf_t buf; + int len = sizeof(wmi_pdev_fips_cmd) + param->data_len; + int retval = 0; + + buf = wmi_buf_alloc(wmi_handle, len); + /* Data length must be multiples of 16 bytes - checked against 0xF - + * and must be less than WMI_SVC_MSG_SIZE - static size of + * wmi_pdev_fips_cmd structure + */ + /* do sanity on the input */ + if (!(((param->data_len & 0xF) == 0) && + ((param->data_len > 0) && + (param->data_len < (WMI_HOST_MAX_BUFFER_SIZE - + sizeof(wmi_pdev_fips_cmd)))))) { + wmi_buf_free(buf); + return QDF_STATUS_E_INVAL; + } + if (!buf) { + qdf_print("%s:wmi_buf_alloc failed\n", __func__); + return QDF_STATUS_E_FAILURE; + } + + cmd = (wmi_pdev_fips_cmd *)wmi_buf_data(buf); + if (param->key != NULL && param->data != NULL) { + cmd->key_len = param->key_len; + cmd->data_len = param->data_len; + cmd->fips_cmd = !!(param->op); + +#ifdef BIG_ENDIAN_HOST + { + /****************BE to LE conversion*****************/ + /* Assigning unaligned space to copy the key */ + unsigned char *key_unaligned = qdf_mem_malloc( + sizeof(u_int8_t)*param->key_len + FIPS_ALIGN); + + u_int8_t *key_aligned = NULL; + + unsigned char *data_unaligned = qdf_mem_malloc( + sizeof(u_int8_t)*param->data_len + FIPS_ALIGN); + u_int8_t *data_aligned = NULL; + + int c; + + /* Checking if kmalloc is succesful to allocate space */ + if (key_unaligned == NULL) + return QDF_STATUS_SUCCESS; + /* Checking if space is aligned */ + if (!FIPS_IS_ALIGNED(key_unaligned, FIPS_ALIGN)) { + /* align to 4 */ + key_aligned = + (u_int8_t *)FIPS_ALIGNTO(key_unaligned, + FIPS_ALIGN); + } else { + key_aligned = (u_int8_t *)key_unaligned; + } + + /* memset and copy content from key to key aligned */ + OS_MEMSET(key_aligned, 0, param->key_len); + OS_MEMCPY(key_aligned, param->key, param->key_len); + + /* print a hexdump for host debug */ + print_hex_dump(KERN_DEBUG, + "\t Aligned and Copied Key:@@@@ ", + DUMP_PREFIX_NONE, + 16, 1, key_aligned, param->key_len, true); + + /* Checking if kmalloc is succesful to allocate space */ + if (data_unaligned == NULL) + return QDF_STATUS_SUCCESS; + /* Checking of space is aligned */ + if (!FIPS_IS_ALIGNED(data_unaligned, FIPS_ALIGN)) { + /* align to 4 */ + data_aligned = + (u_int8_t *)FIPS_ALIGNTO(data_unaligned, + FIPS_ALIGN); + } else { + data_aligned = (u_int8_t *)data_unaligned; + } + + /* memset and copy content from data to data aligned */ + OS_MEMSET(data_aligned, 0, param->data_len); + OS_MEMCPY(data_aligned, param->data, param->data_len); + + /* print a hexdump for host debug */ + print_hex_dump(KERN_DEBUG, + "\t Properly Aligned and Copied Data:@@@@ ", + DUMP_PREFIX_NONE, + 16, 1, data_aligned, param->data_len, true); + + /* converting to little Endian both key_aligned and + * data_aligned*/ + for (c = 0; c < param->key_len/4; c++) { + *((u_int32_t *)key_aligned+c) = + qdf_cpu_to_le32(*((u_int32_t *)key_aligned+c)); + } + for (c = 0; c < param->data_len/4; c++) { + *((u_int32_t *)data_aligned+c) = + qdf_cpu_to_le32(*((u_int32_t *)data_aligned+c)); + } + + /* update endian data to key and data vectors */ + OS_MEMCPY(param->key, key_aligned, param->key_len); + OS_MEMCPY(param->data, data_aligned, param->data_len); + + /* clean up allocated spaces */ + qdf_mem_free(key_unaligned); + key_unaligned = NULL; + key_aligned = NULL; + + qdf_mem_free(data_unaligned); + data_unaligned = NULL; + data_aligned = NULL; + + /*****************************************************/ + } +#endif + qdf_mem_copy(cmd->key, param->key, param->key_len); + qdf_mem_copy(cmd->data, param->data, param->data_len); + + if (param->mode == FIPS_ENGINE_AES_CTR || + param->mode == FIPS_ENGINE_AES_MIC) { + cmd->mode = param->mode; + } else { + cmd->mode = FIPS_ENGINE_AES_CTR; + } + qdf_print(KERN_ERR "Key len = %d, Data len = %d\n", + cmd->key_len, cmd->data_len); + + print_hex_dump(KERN_DEBUG, "Key: ", DUMP_PREFIX_NONE, 16, 1, + cmd->key, cmd->key_len, true); + print_hex_dump(KERN_DEBUG, "Plain text: ", DUMP_PREFIX_NONE, + 16, 1, cmd->data, cmd->data_len, true); + + retval = wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_PDEV_FIPS_CMDID); + qdf_print("%s return value %d\n", __func__, retval); + } else { + qdf_print("\n%s:%d Key or Data is NULL\n", __func__, __LINE__); + retval = -EFAULT; + } + + return retval; +} + +/** + * send_pdev_set_chan_cmd_non_tlv() - send pdev set chan cmd to fw + * @wmi_handle: wmi handle + * @param: pointer to hold set chan param + * + * Return: 0 for success or error code + */ +QDF_STATUS +send_pdev_set_chan_cmd_non_tlv(wmi_unified_t wmi_handle, + struct channel_param *param) +{ + wmi_set_channel_cmd *cmd; + wmi_buf_t buf; + int len = sizeof(wmi_set_channel_cmd); + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + qdf_print("%s:wmi_buf_alloc failed\n", __func__); + return QDF_STATUS_E_FAILURE; + } + + cmd = (wmi_set_channel_cmd *)wmi_buf_data(buf); + + cmd->chan.mhz = param->mhz; + + WMI_SET_CHANNEL_MODE(&cmd->chan, param->phy_mode); + + cmd->chan.band_center_freq1 = param->cfreq1; + cmd->chan.band_center_freq2 = param->cfreq2; + + WMI_SET_CHANNEL_MIN_POWER(&cmd->chan, param->minpower); + WMI_SET_CHANNEL_MAX_POWER(&cmd->chan, param->maxpower); + WMI_SET_CHANNEL_REG_POWER(&cmd->chan, param->maxregpower); + WMI_SET_CHANNEL_ANTENNA_MAX(&cmd->chan, param->antennamax); + WMI_SET_CHANNEL_REG_CLASSID(&cmd->chan, param->reg_class_id); + + if (param->dfs_set) + WMI_SET_CHANNEL_FLAG(&cmd->chan, WMI_CHAN_FLAG_DFS); + + if (param->dfs_set_cfreq2) + WMI_SET_CHANNEL_FLAG(&cmd->chan, WMI_CHAN_FLAG_DFS_CFREQ2); + + if (param->half_rate) + WMI_SET_CHANNEL_FLAG(&cmd->chan, WMI_CHAN_FLAG_HALF); + + if (param->quarter_rate) + WMI_SET_CHANNEL_FLAG(&cmd->chan, WMI_CHAN_FLAG_QUARTER); + + if (param->phy_mode == MODE_11AC_VHT80_80) { + qdf_print( + "WMI channel freq=%d, mode=%x band_center_freq1=%d band_center_freq2=%d\n", + cmd->chan.mhz, + WMI_GET_CHANNEL_MODE(&cmd->chan), cmd->chan.band_center_freq1, + cmd->chan.band_center_freq2); + } else { + qdf_print("WMI channel freq=%d, mode=%x band_center_freq1=%d\n" + , cmd->chan.mhz, + WMI_GET_CHANNEL_MODE(&cmd->chan), + cmd->chan.band_center_freq1); + } + + return wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_PDEV_SET_CHANNEL_CMDID); +} + +/** + * send_mcast_group_update_cmd_non_tlv() - send mcast group update cmd to fw + * @wmi_handle: wmi handle + * @param: pointer to hold mcast update param + * + * Return: 0 for success or error code + */ +QDF_STATUS +send_mcast_group_update_cmd_non_tlv(wmi_unified_t wmi_handle, + struct mcast_group_update_params *param) +{ + wmi_peer_mcast_group_cmd *cmd; + wmi_buf_t buf; + int len; + int offset = 0; + char dummymask[4] = { 0xFF, 0xFF, 0xFF, 0xFF}; + + len = sizeof(wmi_peer_mcast_group_cmd); + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + qdf_print("%s: wmi_buf_alloc failed\n", __func__); + return QDF_STATUS_E_NOMEM; + } + cmd = (wmi_peer_mcast_group_cmd *) wmi_buf_data(buf); + /* confirm the buffer is 4-byte aligned */ + ASSERT((((size_t) cmd) & 0x3) == 0); + OS_MEMZERO(cmd, sizeof(wmi_peer_mcast_group_cmd)); + + /* construct the message assuming our endianness matches the target */ + cmd->flags |= WMI_PEER_MCAST_GROUP_FLAG_ACTION_M & + (param->action << WMI_PEER_MCAST_GROUP_FLAG_ACTION_S); + cmd->flags |= WMI_PEER_MCAST_GROUP_FLAG_WILDCARD_M & + (param->wildcard << WMI_PEER_MCAST_GROUP_FLAG_WILDCARD_S); + if (param->is_action_delete) + cmd->flags |= WMI_PEER_MCAST_GROUP_FLAG_DELETEALL_M; + + if (param->is_mcast_addr_len) + cmd->flags |= WMI_PEER_MCAST_GROUP_FLAG_IPV6_M; + + if (param->is_filter_mode_snoop) + cmd->flags |= WMI_PEER_MCAST_GROUP_FLAG_SRC_FILTER_EXCLUDE_M; + + /* unicast address spec only applies for non-wildcard cases */ + if (!param->wildcard && param->ucast_mac_addr) { + qdf_mem_copy( + &cmd->ucast_mac_addr, + param->ucast_mac_addr, + sizeof(cmd->ucast_mac_addr)); + } + if (param->mcast_ip_addr) { + ASSERT(param->mcast_ip_addr_bytes <= + sizeof(cmd->mcast_ip_addr)); + offset = sizeof(cmd->mcast_ip_addr) - + param->mcast_ip_addr_bytes; + qdf_mem_copy(((u_int8_t *) &cmd->mcast_ip_addr) + offset, + param->mcast_ip_addr, + param->mcast_ip_addr_bytes); + } + if (!param->mask) + param->mask = &dummymask[0]; + + qdf_mem_copy(((u_int8_t *) &cmd->mcast_ip_mask) + offset, param->mask, + param->mcast_ip_addr_bytes); + + if (param->srcs && param->nsrcs) { + cmd->num_filter_addr = param->nsrcs; + ASSERT((param->nsrcs * param->mcast_ip_addr_bytes) <= + sizeof(cmd->srcs)); + + qdf_mem_copy(((u_int8_t *) &cmd->filter_addr), param->srcs, + param->nsrcs * param->mcast_ip_addr_bytes); + } + /* now correct for endianness, if necessary */ + /* + * For Little Endian, N/w Stack gives packets in Network byte order and + * issue occurs if both Host and Target happens to be in Little Endian. + * Target when compares IP addresses in packet with MCAST_GROUP_CMDID + * given IP addresses, it fails. Hence swap only mcast_ip_addr + * (16 bytes) for now. + * TODO : filter + */ +/* TBD in OL Layer +#ifdef BIG_ENDIAN_HOST + ol_bytestream_endian_fix( + (u_int32_t *)&cmd->ucast_mac_addr, + (sizeof(*cmd)-4) / sizeof(u_int32_t)); +#else + ol_bytestream_endian_fix( + (u_int32_t *)&cmd->mcast_ip_addr, + (sizeof(cmd->mcast_ip_addr)) / sizeof(u_int32_t)); +#endif Little Endian */ + wmi_unified_cmd_send( + wmi_handle, buf, len, WMI_PEER_MCAST_GROUP_CMDID); + + return QDF_STATUS_SUCCESS; +} + +/** + * send_periodic_chan_stats_config_cmd_non_tlv() - send periodic chan stats cmd + * to fw + * @wmi_handle: wmi handle + * @param: pointer to hold periodic chan stats param + * + * Return: 0 for success or error code + */ +QDF_STATUS +send_periodic_chan_stats_config_cmd_non_tlv(wmi_unified_t wmi_handle, + struct periodic_chan_stats_params *param) +{ + wmi_buf_t buf = NULL; + wmi_set_periodic_channel_stats_config *cmd = NULL; + QDF_STATUS error = 0; + int32_t len = 0; + + len = sizeof(wmi_set_periodic_channel_stats_config); + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + qdf_print("%s: Unable to allocate merory\n", __func__); + return QDF_STATUS_E_NOMEM; + } + cmd = (wmi_set_periodic_channel_stats_config *) wmi_buf_data(buf); + cmd->enable = param->enable; + cmd->stats_period = param->stats_period; + + error = wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_SET_PERIODIC_CHANNEL_STATS_CONFIG); + + if (error) + qdf_print(" %s :WMI Failed\n", __func__); + + return error; +} + +/** + * send_nf_dbr_dbm_info_get_cmd_non_tlv() - send request to get nf to fw + * @wmi_handle: wmi handle + * + * Return: 0 for success or error code + */ +QDF_STATUS +send_nf_dbr_dbm_info_get_cmd_non_tlv(wmi_unified_t wmi_handle) +{ + wmi_buf_t wmibuf; + + wmibuf = wmi_buf_alloc(wmi_handle, 0); + if (wmibuf == NULL) + return QDF_STATUS_E_NOMEM; + + return wmi_unified_cmd_send(wmi_handle, wmibuf, 0, + WMI_PDEV_GET_NFCAL_POWER_CMDID); +} + +/** + * send_packet_power_info_get_cmd_non_tlv() - send request to get packet power + * info to fw + * @wmi_handle: wmi handle + * @param: pointer to hold packet power info param + * + * Return: 0 for success or error code + */ +QDF_STATUS +send_packet_power_info_get_cmd_non_tlv(wmi_unified_t wmi_handle, + struct packet_power_info_params *param) +{ + wmi_pdev_get_tpc_cmd *cmd; + wmi_buf_t wmibuf; + u_int32_t len = sizeof(wmi_pdev_get_tpc_cmd); + + wmibuf = wmi_buf_alloc(wmi_handle, len); + if (wmibuf == NULL) + return QDF_STATUS_E_NOMEM; + + cmd = (wmi_pdev_get_tpc_cmd *)wmi_buf_data(wmibuf); + cmd->rate_flags = param->rate_flags; + cmd->nss = param->nss; + cmd->preamble = param->preamble; + cmd->hw_rate = param->hw_rate; + cmd->rsvd = 0x0; + qdf_print("%s[%d] commandID %d, wmi_pdev_get_tpc_cmd=0x%x\n", __func__, + __LINE__, WMI_PDEV_GET_TPC_CMDID, *((u_int32_t *)cmd)); + return wmi_unified_cmd_send(wmi_handle, wmibuf, len, + WMI_PDEV_GET_TPC_CMDID); +} + +/** + * send_gpio_config_cmd_non_tlv() - send gpio config to fw + * @wmi_handle: wmi handle + * @param: pointer to hold gpio config param + * + * Return: 0 for success or error code + */ +QDF_STATUS +send_gpio_config_cmd_non_tlv(wmi_unified_t wmi_handle, + struct gpio_config_params *param) +{ + wmi_gpio_config_cmd *cmd; + wmi_buf_t wmibuf; + u_int32_t len = sizeof(wmi_gpio_config_cmd); + + /* Sanity Checks */ + if (param->pull_type > WMI_GPIO_PULL_DOWN || + param->intr_mode > WMI_GPIO_INTTYPE_LEVEL_HIGH) { + return QDF_STATUS_E_FAILURE; + } + + wmibuf = wmi_buf_alloc(wmi_handle, len); + if (wmibuf == NULL) + return QDF_STATUS_E_FAILURE; + + cmd = (wmi_gpio_config_cmd *)wmi_buf_data(wmibuf); + cmd->gpio_num = param->gpio_num; + cmd->input = param->input; + cmd->pull_type = param->pull_type; + cmd->intr_mode = param->intr_mode; + return wmi_unified_cmd_send(wmi_handle, wmibuf, len, + WMI_GPIO_CONFIG_CMDID); +} + +/** + * send_gpio_output_cmd_non_tlv() - send gpio output to fw + * @wmi_handle: wmi handle + * @param: pointer to hold gpio output param + * + * Return: 0 for success or error code + */ +QDF_STATUS +send_gpio_output_cmd_non_tlv(wmi_unified_t wmi_handle, + struct gpio_output_params *param) +{ + wmi_gpio_output_cmd *cmd; + wmi_buf_t wmibuf; + u_int32_t len = sizeof(wmi_gpio_output_cmd); + + wmibuf = wmi_buf_alloc(wmi_handle, len); + if (wmibuf == NULL) + return QDF_STATUS_E_FAILURE; + + cmd = (wmi_gpio_output_cmd *)wmi_buf_data(wmibuf); + cmd->gpio_num = param->gpio_num; + cmd->set = param->set; + return wmi_unified_cmd_send(wmi_handle, wmibuf, len, + WMI_GPIO_OUTPUT_CMDID); +} + +/* + * send_rtt_meas_req_test_cmd_non_tlv() - send rtt meas req test cmd to fw + * @wmi_handle: wmi handle + * @param: pointer to hold rtt meas req test param + * + * Return: 0 for success or error code + */ +QDF_STATUS +send_rtt_meas_req_test_cmd_non_tlv(wmi_unified_t wmi_handle, + struct rtt_meas_req_test_params *param) +{ + wmi_buf_t buf; + u_int8_t *p; + int ret; + u_int16_t len; + wmi_rtt_measreq_head *head; + wmi_rtt_measreq_body *body; + wmi_channel *w_chan; + + qdf_print("%s: The request ID is: %d\n", __func__, param->req_id); + + len = sizeof(wmi_rtt_measreq_head) + param->req_num_req * + sizeof(wmi_rtt_measreq_body); + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + qdf_print("No WMI resource!"); + return QDF_STATUS_E_NOMEM; + } + + p = (u_int8_t *) wmi_buf_data(buf); + qdf_mem_set(p, len, 0); + + head = (wmi_rtt_measreq_head *) p; + WMI_RTT_REQ_ID_SET(head->req_id, param->req_id); + WMI_RTT_SPS_SET(head->req_id, 1); + + WMI_RTT_NUM_STA_SET(head->sta_num, param->req_num_req); + if (param->req_report_type < WMI_RTT_AGGREAGET_REPORT_NON_CFR) { + /* In command line, 0 - FAC, 1 - CFR, need to revert here */ + param->req_report_type ^= 1; + } + + if (param->num_measurements == 0) + param->num_measurements = 25; + + body = &(head->body[0]); + WMI_RTT_VDEV_ID_SET(body->measure_info, 0); + WMI_RTT_TIMEOUT_SET(body->measure_info, 100); + WMI_RTT_REPORT_TYPE_SET(body->measure_info, param->req_report_type); + WMI_RTT_FRAME_TYPE_SET(body->control_flag, param->req_frame_type); + + WMI_RTT_TX_CHAIN_SET(body->control_flag, 001); + WMI_RTT_QCA_PEER_SET(body->control_flag, 1); + if (param->req_preamble == WMI_RTT_PREAM_LEGACY) + WMI_RTT_MCS_SET(body->control_flag, 3); + else + WMI_RTT_MCS_SET(body->control_flag, 0); + WMI_RTT_RETRIES_SET(body->control_flag, 1); + + /* + qdf_mem_copy(peer, param->mac_addr, 6); + + qdf_print("The mac_addr is" + " %.2x:%.2x:%.2x:%.2x:%.2x:%.2x extra=%d\n", + peer[0], peer[1], peer[2], + peer[3], peer[4], peer[5], param->extra); + */ + + /* start from here, embed the first req in each RTT measurement + * Command */ + /*peer[5] = 0x12; + peer[4] = 0x90; + peer[3] = 0x78; + peer[2] = 0x56; + peer[1] = 0x34; + peer[0] = 0x12; +>---*/ + head->channel.mhz = param->channel.mhz; + head->channel.band_center_freq1 = param->channel.cfreq1; + head->channel.band_center_freq2 = param->channel.cfreq2; + + + w_chan = (wmi_channel *)&head->channel; + WMI_SET_CHANNEL_MODE(w_chan, param->channel.phy_mode); + WMI_SET_CHANNEL_MIN_POWER(w_chan, param->channel.minpower); + WMI_SET_CHANNEL_MAX_POWER(w_chan, param->channel.maxpower); + WMI_SET_CHANNEL_REG_POWER(w_chan, param->channel.maxregpower); + WMI_SET_CHANNEL_ANTENNA_MAX(w_chan, param->channel.antennamax); + WMI_SET_CHANNEL_REG_CLASSID(w_chan, param->channel.reg_class_id); + + WMI_CHAR_ARRAY_TO_MAC_ADDR(((u_int8_t *)param->peer), &body->dest_mac); + WMI_CHAR_ARRAY_TO_MAC_ADDR(((u_int8_t *)param->peer), + &body->spoof_bssid); + + WMI_RTT_BW_SET(body->control_flag, param->req_bw); + WMI_RTT_PREAMBLE_SET(body->control_flag, param->req_preamble); + WMI_RTT_MEAS_NUM_SET(body->measure_info, param->num_measurements); + + body->measure_params_1 = 0; + body->measure_params_2 = 0; + + WMI_RTT_ASAP_MODE_SET(body->measure_params_1, param->asap_mode); + WMI_RTT_LCI_REQ_SET(body->measure_params_1, param->lci_requested); + WMI_RTT_LOC_CIV_REQ_SET(body->measure_params_1, + param->loc_civ_requested); + WMI_RTT_NUM_BURST_EXP_SET(body->measure_params_1, 0); + WMI_RTT_BURST_DUR_SET(body->measure_params_1, 15); + WMI_RTT_BURST_PERIOD_SET(body->measure_params_1, 0); + WMI_RTT_TSF_DELTA_VALID_SET(body->measure_params_1, 1); + WMI_RTT_TSF_DELTA_SET(body->measure_params_2, 0); + + /** other requests are same with first request */ + p = (u_int8_t *) body; + while (--param->req_num_req) { + body++; + qdf_mem_copy(body, p, sizeof(wmi_rtt_measreq_body)); + } + + ret = wmi_unified_cmd_send(wmi_handle, buf, len, WMI_RTT_MEASREQ_CMDID); + qdf_print("send rtt cmd to FW with length %d and return %d\n", + len, ret); + return QDF_STATUS_SUCCESS; +} + +/** + * send_rtt_meas_req_cmd_non_tlv() - send rtt meas req cmd to fw + * @wmi_handle: wmi handle + * @param: pointer to hold rtt meas req param + * + * Return: 0 for success or error code + */ +QDF_STATUS +send_rtt_meas_req_cmd_non_tlv(wmi_unified_t wmi_handle, + struct rtt_meas_req_params *param) +{ + wmi_buf_t buf; + uint8_t *p; + int ret; + uint16_t len; + uint8_t peer[6]; + uint8_t spoof[6]; + wmi_rtt_measreq_head *head; + wmi_rtt_measreq_body *body; + int req_frame_type, req_preamble; + wmi_channel *w_chan; + + /* Temporarily, hardcoding peer mac address for test purpose will be + * removed once RTT host has been developed for even req_id, like + * 0, 2, 4, there is no channel_swicth for odd req_id, like 1, 3 , 5, + * there is channel switch currently, for both cases, we have 3 req in + * each command please change here if you only have one (or just let + * it be). Even == HC, odd == OC. + */ + if (!(param->req_id & 0x1)) { + len = sizeof(wmi_rtt_measreq_head); + /* + 2 * sizeof(wmi_rtt_measreq_body);*/ + } else { + len = sizeof(wmi_rtt_measreq_head); + /* + 2 * sizeof(wmi_rtt_measreq_body);*/ + } + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + qdf_print("No WMI resource!"); + return QDF_STATUS_E_FAILURE; + } + + p = (uint8_t *) wmi_buf_data(buf); + qdf_mem_set(p, len, 0); + + /* encode header */ + head = (wmi_rtt_measreq_head *) p; + /* head->req_id = req_id;*/ + WMI_RTT_REQ_ID_SET(head->req_id, param->req_id); + /* WMI_RTT_SPS_SET(head->req_id, 1);*/ + + if (!(param->req_id & 0x1)) { /*even req id */ +#ifndef RTT_TEST + /* we actually only have 3 sta to measure + this is used to test over limit request protection + XIN:WMI_RTT_NUM_STA_SET(head->sta_num, 5);*/ +#else + /* XIN:WMI_RTT_NUM_STA_SET(head->sta_num, 2);*/ + WMI_RTT_NUM_STA_SET(head->sta_num, 1); +#endif + WMI_RTT_NUM_STA_SET(head->sta_num, 1); + } else { /* odd req id */ + /* XIN:WMI_RTT_NUM_STA_SET(head->sta_num, 3); */ + WMI_RTT_NUM_STA_SET(head->sta_num, 1); + + } + + req_frame_type = RTT_MEAS_FRAME_NULL; + /* MS(extra, RTT_REQ_FRAME_TYPE);*/ + /* req_bw = //MS(extra, RTT_REQ_BW);*/ + req_preamble = WMI_RTT_PREAM_LEGACY;/*MS(extra, RTT_REQ_PREAMBLE);*/ + + /*encode common parts for each RTT measurement command body + The value here can be overwrite in following each req hardcoding */ + body = &(head->body[0]); + WMI_RTT_VDEV_ID_SET(body->measure_info, param->vdev_id); + WMI_RTT_TIMEOUT_SET(body->measure_info, RTT_TIMEOUT_MS); + WMI_RTT_REPORT_TYPE_SET(body->measure_info, 1); + WMI_RTT_FRAME_TYPE_SET(body->control_flag, req_frame_type); + WMI_RTT_TX_CHAIN_SET(body->control_flag, 001); + WMI_RTT_QCA_PEER_SET(body->control_flag, 1); + if (req_preamble == WMI_RTT_PREAM_LEGACY) + WMI_RTT_MCS_SET(body->control_flag, 3); + else + WMI_RTT_MCS_SET(body->control_flag, 0); + WMI_RTT_RETRIES_SET(body->control_flag, 1); + + if (!(param->req_id & 0x1)) { /* even time */ + qdf_mem_copy(peer, param->sta_mac_addr, 6); + } else { /* odd time */ + qdf_mem_copy(peer, param->sta_mac_addr, 6); + } + head->channel.mhz = param->channel.mhz; + head->channel.band_center_freq1 = param->channel.cfreq1; + head->channel.band_center_freq2 = param->channel.cfreq2; + + w_chan = (wmi_channel *)&head->channel; + WMI_SET_CHANNEL_MAX_POWER(w_chan, param->channel.phy_mode); + WMI_SET_CHANNEL_MIN_POWER(w_chan, param->channel.minpower); + WMI_SET_CHANNEL_MAX_POWER(w_chan, param->channel.maxpower); + WMI_SET_CHANNEL_REG_POWER(w_chan, param->channel.maxregpower); + WMI_SET_CHANNEL_ANTENNA_MAX(w_chan, param->channel.antennamax); + WMI_SET_CHANNEL_REG_CLASSID(w_chan, param->channel.reg_class_id); + + if (param->is_mode_na) + WMI_SET_CHANNEL_MODE(w_chan, MODE_11NG_HT20); + else if (param->is_mode_ac) + WMI_SET_CHANNEL_MODE(w_chan, MODE_11NA_HT20); + + if (param->channel.dfs_set) + WMI_SET_CHANNEL_FLAG(w_chan, WMI_CHAN_FLAG_DFS); + + WMI_CHAR_ARRAY_TO_MAC_ADDR(((uint8_t *)peer), &body->dest_mac); + qdf_mem_set(spoof, IEEE80211_ADDR_LEN, 0); + WMI_CHAR_ARRAY_TO_MAC_ADDR(((uint8_t *)param->spoof_mac_addr), + &body->spoof_bssid); + + /** embedded varing part of each request + set Preamble, BW, measurement times */ + if (param->is_bw_20) + WMI_RTT_BW_SET(body->control_flag, WMI_RTT_BW_20); + else if (param->is_bw_40) + WMI_RTT_BW_SET(body->control_flag, WMI_RTT_BW_40); + else if (param->is_bw_80) + WMI_RTT_BW_SET(body->control_flag, WMI_RTT_BW_80); + else + WMI_RTT_BW_SET(body->control_flag, WMI_RTT_BW_20); + WMI_RTT_PREAMBLE_SET(body->control_flag, req_preamble); + WMI_RTT_MEAS_NUM_SET(body->measure_info, param->num_probe_rqst); + + + ret = wmi_unified_cmd_send(wmi_handle, buf, len, WMI_RTT_MEASREQ_CMDID); + qdf_print("send rtt cmd to FW with length %d and return %d\n", + len, ret); + return ret; +} +/** + * send_rtt_keepalive_req_cmd_non_tlv() - send rtt keepalive req cmd to fw + * @wmi_handle: wmi handle + * @param: pointer to hold rtt keepalive req param + * + * Return: 0 for success or error code + */ +QDF_STATUS +send_rtt_keepalive_req_cmd_non_tlv(wmi_unified_t wmi_handle, + struct rtt_keepalive_req_params *param) +{ + wmi_buf_t buf; + wmi_rtt_keepalive_cmd *cmd; + int ret; + uint16_t len; + uint8_t *ptr; + + len = sizeof(wmi_rtt_keepalive_cmd); + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + qdf_print("No WMI resource\n"); + return QDF_STATUS_E_FAILURE; + } + ptr = (uint8_t *)wmi_buf_data(buf); + OS_MEMSET(ptr, 0, len); + + cmd = (wmi_rtt_keepalive_cmd *)wmi_buf_data(buf); + + WMI_RTT_REQ_ID_SET(cmd->req_id, param->req_id); + WMI_RTT_KEEPALIVE_ACTION_SET(cmd->req_id, param->stop); + WMI_RTT_VDEV_ID_SET(cmd->probe_info, param->vdev_id); + /* 3ms probe interval by default */ + WMI_RTT_KEEPALIVE_PERIOD_SET(cmd->probe_info, 3); + /* max retry of 50 by default */ + WMI_RTT_TIMEOUT_SET(cmd->probe_info, 20); + /* set frame type */ + WMI_RTT_FRAME_TYPE_SET(cmd->control_flag, RTT_MEAS_FRAME_KEEPALIVE); + + WMI_CHAR_ARRAY_TO_MAC_ADDR(param->macaddr, &cmd->sta_mac); + + ret = wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_RTT_KEEPALIVE_CMDID); + qdf_print("send rtt keepalive cmd to FW with length %d and return %d\n" + , len, ret); + param->req_id++; + + return QDF_STATUS_SUCCESS; +} +/** + * send_lci_set_cmd_non_tlv() - send lci cmd to fw + * @wmi_handle: wmi handle + * @param: pointer to hold lci param + * + * Return: 0 for success or error code + */ +QDF_STATUS +send_lci_set_cmd_non_tlv(wmi_unified_t wmi_handle, + struct lci_set_params *param) +{ + wmi_buf_t buf; + uint8_t *p; + wmi_oem_measreq_head *head; + int len; + wmi_rtt_lci_cfg_head *rtt_req; + rtt_req = (wmi_rtt_lci_cfg_head *) param->lci_data; + + len = sizeof(wmi_oem_measreq_head)+sizeof(wmi_rtt_lci_cfg_head); + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + qdf_print("No WMI resource!"); + return QDF_STATUS_E_FAILURE; + } + + p = (uint8_t *) wmi_buf_data(buf); + qdf_mem_set(p, len, 0); + + head = (wmi_oem_measreq_head *)p; + head->sub_type = TARGET_OEM_CONFIGURE_LCI; + WMI_HOST_IF_MSG_COPY_CHAR_ARRAY(&(head->head), param->lci_data, + sizeof(wmi_rtt_lci_cfg_head)); + if (wmi_unified_cmd_send(wmi_handle, buf, len, WMI_OEM_REQ_CMDID)) + return QDF_STATUS_E_FAILURE; + + /* Save LCI data in host buffer */ + { + + param->latitude_unc = WMI_RTT_LCI_LAT_UNC_GET( + rtt_req->lci_cfg_param_info); + param->latitude_0_1 = ((uint32_t)(rtt_req->latitude & 0x3)); + param->latitude_2_33 = (uint32_t) + (((uint64_t)(rtt_req->latitude)) >> 2); + param->longitude_unc = + WMI_RTT_LCI_LON_UNC_GET(rtt_req->lci_cfg_param_info); + param->longitude_0_1 = ((uint32_t)(rtt_req->longitude & 0x3)); + param->longitude_2_33 = + (uint32_t)(((uint64_t)(rtt_req->longitude)) >> 2); + param->altitude_type = + WMI_RTT_LCI_ALT_TYPE_GET(rtt_req->altitude_info); + param->altitude_unc_0_3 = + (WMI_RTT_LCI_ALT_UNC_GET(rtt_req->altitude_info) & 0xF); + param->altitude_unc_4_5 = + ((WMI_RTT_LCI_ALT_UNC_GET(rtt_req->altitude_info) >> 4) & + 0x3); + param->altitude = (rtt_req->altitude & RTT_LCI_ALTITUDE_MASK); + param->datum = + WMI_RTT_LCI_DATUM_GET(rtt_req->lci_cfg_param_info); + param->reg_loc_agmt = + WMI_RTT_LCI_REG_LOC_AGMT_GET(rtt_req->lci_cfg_param_info); + param->reg_loc_dse = + WMI_RTT_LCI_REG_LOC_DSE_GET(rtt_req->lci_cfg_param_info); + param->dep_sta = + WMI_RTT_LCI_DEP_STA_GET(rtt_req->lci_cfg_param_info); + param->version = + WMI_RTT_LCI_VERSION_GET(rtt_req->lci_cfg_param_info); + + } + return QDF_STATUS_SUCCESS; +} + +/** + * send_lcr_set_cmd_non_tlv() - send lcr cmd to fw + * @wmi_handle: wmi handle + * @param: pointer to hold lcr param + * + * Return: 0 for success or error code + */ +QDF_STATUS +send_lcr_set_cmd_non_tlv(wmi_unified_t wmi_handle, + struct lcr_set_params *param) +{ + wmi_buf_t buf; + uint8_t *p; + wmi_oem_measreq_head *head; + int len; + + len = sizeof(wmi_oem_measreq_head)+sizeof(wmi_rtt_lcr_cfg_head); + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + qdf_print("No WMI resource!"); + return QDF_STATUS_E_FAILURE; + } + + p = (uint8_t *) wmi_buf_data(buf); + qdf_mem_set(p, len, 0); + + head = (wmi_oem_measreq_head *)p; + head->sub_type = TARGET_OEM_CONFIGURE_LCR; + WMI_HOST_IF_MSG_COPY_CHAR_ARRAY(&(head->head), param->lcr_data, + sizeof(wmi_rtt_lcr_cfg_head)); + + if (wmi_unified_cmd_send(wmi_handle, buf, len, WMI_OEM_REQ_CMDID)) + return QDF_STATUS_E_FAILURE; + + return QDF_STATUS_SUCCESS; +} + +/** + * wmi_copy_resource_config_non_tlv() - copy resource configuration function + * @param resource_cfg: pointer to resource configuration + * @param tgt_res_cfg: pointer to target resource configuration + * + * Return: None + */ +static void wmi_copy_resource_config_non_tlv(wmi_resource_config *resource_cfg, + target_resource_config *tgt_res_cfg) +{ + resource_cfg->num_vdevs = tgt_res_cfg->num_vdevs; + resource_cfg->num_peers = tgt_res_cfg->num_peers; + resource_cfg->num_active_peers = tgt_res_cfg->num_active_peers; + resource_cfg->num_offload_peers = tgt_res_cfg->num_offload_peers; + resource_cfg->num_offload_reorder_buffs = + tgt_res_cfg->num_offload_reorder_buffs; + resource_cfg->num_peer_keys = tgt_res_cfg->num_peer_keys; + resource_cfg->num_tids = tgt_res_cfg->num_tids; + resource_cfg->ast_skid_limit = tgt_res_cfg->ast_skid_limit; + resource_cfg->tx_chain_mask = tgt_res_cfg->tx_chain_mask; + resource_cfg->rx_chain_mask = tgt_res_cfg->rx_chain_mask; + resource_cfg->rx_timeout_pri[0] = tgt_res_cfg->rx_timeout_pri[0]; + resource_cfg->rx_timeout_pri[1] = tgt_res_cfg->rx_timeout_pri[1]; + resource_cfg->rx_timeout_pri[2] = tgt_res_cfg->rx_timeout_pri[2]; + resource_cfg->rx_timeout_pri[3] = tgt_res_cfg->rx_timeout_pri[3]; + resource_cfg->rx_decap_mode = tgt_res_cfg->rx_decap_mode; + resource_cfg->scan_max_pending_req = tgt_res_cfg->scan_max_pending_req; + resource_cfg->bmiss_offload_max_vdev = + tgt_res_cfg->bmiss_offload_max_vdev; + resource_cfg->roam_offload_max_vdev = + tgt_res_cfg->roam_offload_max_vdev; + resource_cfg->roam_offload_max_ap_profiles = + tgt_res_cfg->roam_offload_max_ap_profiles; + resource_cfg->num_mcast_groups = tgt_res_cfg->num_mcast_groups; + resource_cfg->num_mcast_table_elems = + tgt_res_cfg->num_mcast_table_elems; + resource_cfg->mcast2ucast_mode = tgt_res_cfg->mcast2ucast_mode; + resource_cfg->tx_dbg_log_size = tgt_res_cfg->tx_dbg_log_size; + resource_cfg->num_wds_entries = tgt_res_cfg->num_wds_entries; + resource_cfg->dma_burst_size = tgt_res_cfg->dma_burst_size; + resource_cfg->mac_aggr_delim = tgt_res_cfg->mac_aggr_delim; + resource_cfg->rx_skip_defrag_timeout_dup_detection_check = + tgt_res_cfg->rx_skip_defrag_timeout_dup_detection_check; + resource_cfg->vow_config = tgt_res_cfg->vow_config; + resource_cfg->gtk_offload_max_vdev = tgt_res_cfg->gtk_offload_max_vdev; + resource_cfg->num_msdu_desc = tgt_res_cfg->num_msdu_desc; + resource_cfg->max_frag_entries = tgt_res_cfg->max_frag_entries; + resource_cfg->max_peer_ext_stats = tgt_res_cfg->max_peer_ext_stats; + resource_cfg->smart_ant_cap = tgt_res_cfg->smart_ant_cap; + resource_cfg->BK_Minfree = tgt_res_cfg->BK_Minfree; + resource_cfg->BE_Minfree = tgt_res_cfg->BE_Minfree; + resource_cfg->VI_Minfree = tgt_res_cfg->VI_Minfree; + resource_cfg->VO_Minfree = tgt_res_cfg->VO_Minfree; + resource_cfg->rx_batchmode = tgt_res_cfg->rx_batchmode; + resource_cfg->tt_support = tgt_res_cfg->tt_support; + resource_cfg->atf_config = tgt_res_cfg->atf_config; + resource_cfg->iphdr_pad_config = tgt_res_cfg->iphdr_pad_config; + WMI_SET_QWRAP(resource_cfg, tgt_res_cfg->qwrap_config); + WMI_SET_ALLOC_FRAG(resource_cfg, + tgt_res_cfg->alloc_frag_desc_for_data_pkt); +} + +/** + * init_cmd_send_non_tlv() - send initialization cmd to fw + * @wmi_handle: wmi handle + * @param tgt_res_cfg: pointer to target resource configuration + * @param num_mem_chunks: Number of memory chunks + * @param mem_chunks: pointer to target memory chunks + * + * Return: 0 for success or error code + */ +static QDF_STATUS init_cmd_send_non_tlv(wmi_unified_t wmi_handle, + target_resource_config *tgt_res_cfg, + uint8_t num_mem_chunks, struct wmi_host_mem_chunk *mem_chunks) +{ + wmi_buf_t buf; + wmi_init_cmd *cmd; + wlan_host_memory_chunk *host_mem_chunks; + uint32_t mem_chunk_len = 0; + uint16_t idx; + int len; + + len = sizeof(*cmd); + mem_chunk_len = (sizeof(wlan_host_memory_chunk) * MAX_MEM_CHUNKS); + buf = wmi_buf_alloc(wmi_handle, len + mem_chunk_len); + if (!buf) { + qdf_print("%s: wmi_buf_alloc failed\n", __func__); + return QDF_STATUS_E_FAILURE; + } + + cmd = (wmi_init_cmd *) wmi_buf_data(buf); + + wmi_copy_resource_config_non_tlv(&cmd->resource_config, tgt_res_cfg); + + host_mem_chunks = cmd->host_mem_chunks; + for (idx = 0; idx < num_mem_chunks; ++idx) { + host_mem_chunks[idx].ptr = mem_chunks[idx].paddr; + host_mem_chunks[idx].size = mem_chunks[idx].len; + host_mem_chunks[idx].req_id = mem_chunks[idx].req_id; + qdf_print("chunk %d len %d requested , ptr 0x%x\n", + idx, cmd->host_mem_chunks[idx].size, + cmd->host_mem_chunks[idx].ptr); + } + cmd->num_host_mem_chunks = num_mem_chunks; + if (num_mem_chunks > 1) + len += ((num_mem_chunks-1) * sizeof(wlan_host_memory_chunk)); + + if (wmi_unified_cmd_send(wmi_handle, buf, len, WMI_INIT_CMDID) < 0) { + wmi_buf_free(buf); + return QDF_STATUS_E_FAILURE; + } + return QDF_STATUS_SUCCESS; +} + +/** + * send_ext_resource_config_non_tlv() - send extended resource configuration + * @wmi_handle: wmi handle + * @param ext_cfg: pointer to extended resource configuration + * + * Return: 0 for success or error code + */ +static QDF_STATUS send_ext_resource_config_non_tlv(wmi_unified_t wmi_handle, + wmi_host_ext_resource_config *ext_cfg) +{ + wmi_buf_t buf; + int len = 0; + wmi_ext_resource_config *cmd_cfg; + +#define PAD_LENGTH 100 + buf = wmi_buf_alloc(wmi_handle, + len + (sizeof(wmi_ext_resource_config) + PAD_LENGTH)); + if (!buf) { + qdf_print("%s:wmi_buf_alloc failed\n", __func__); + return QDF_STATUS_E_FAILURE; + } + + cmd_cfg = (wmi_ext_resource_config *)wmi_buf_data(buf); + qdf_mem_copy(cmd_cfg, ext_cfg, sizeof(wmi_ext_resource_config)); + qdf_print("\nSending Ext resource cfg: HOST PLATFORM as %d\n" + "fw_feature_bitmap as %x to TGT\n", + cmd_cfg->host_platform_config, + cmd_cfg->fw_feature_bitmap); + if (wmi_unified_cmd_send(wmi_handle, buf, + sizeof(wmi_ext_resource_config), + WMI_EXT_RESOURCE_CFG_CMDID) < 0) { + wmi_buf_free(buf); + return QDF_STATUS_E_FAILURE; + } + return QDF_STATUS_SUCCESS; +} + +/** + * save_service_bitmap_non_tlv() - save service bitmap + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * + * Return: None + */ +static void save_service_bitmap_non_tlv(wmi_unified_t wmi_handle, void *evt_buf) +{ + wmi_service_ready_event *ev; + + ev = (wmi_service_ready_event *) evt_buf; + + qdf_mem_copy(wmi_handle->wmi_service_bitmap, ev->wmi_service_bitmap, + (WMI_SERVICE_BM_SIZE * sizeof(uint32_t))); +} + +/** + * is_service_enabled_non_tlv() - Check if service enabled + * @param wmi_handle: wmi handle + * @param service_id: service identifier + * + * Return: 1 enabled, 0 disabled + */ +static bool is_service_enabled_non_tlv(wmi_unified_t wmi_handle, + uint32_t service_id) +{ + return WMI_SERVICE_IS_ENABLED(wmi_handle->wmi_service_bitmap, + service_id); +} + +/** + * extract_service_ready_non_tlv() - extract service ready event + * @wmi_handle: wmi handle + * @param evt_buf: pointer to received event buffer + * @param cap: pointer to hold target capability information extracted from even + * + * Return: 0 for success or error code + */ +static QDF_STATUS extract_service_ready_non_tlv(wmi_unified_t wmi_handle, + void *evt_buf, + target_capability_info *cap) +{ + wmi_service_ready_event *ev; + + ev = (wmi_service_ready_event *) evt_buf; + + cap->phy_capability = ev->phy_capability; + cap->max_frag_entry = ev->max_frag_entry; + cap->num_rf_chains = ev->num_rf_chains; + cap->ht_cap_info = ev->ht_cap_info; + cap->vht_cap_info = ev->vht_cap_info; + cap->vht_supp_mcs = ev->vht_supp_mcs; + cap->hw_min_tx_power = ev->hw_min_tx_power; + cap->hw_max_tx_power = ev->hw_max_tx_power; + cap->sys_cap_info = ev->sys_cap_info; + cap->min_pkt_size_enable = ev->min_pkt_size_enable; + cap->max_bcn_ie_size = ev->max_bcn_ie_size; + /* Following caps not recieved in older fw/hw + * Initialize it as zero(default). */ + cap->max_num_scan_channels = 0; + cap->max_supported_macs = 0; + cap->wmi_fw_sub_feat_caps = 0; + cap->txrx_chainmask = 0; + cap->default_dbs_hw_mode_index = 0; + cap->num_msdu_desc = 0; + + return QDF_STATUS_SUCCESS; +} + +/** + * extract_fw_version_non_tlv() - extract fw version + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * @param fw_ver: Pointer to hold fw version + * + * Return: 0 for success or error code + */ +QDF_STATUS extract_fw_version_non_tlv(wmi_unified_t wmi_handle, + void *evt_buf, struct wmi_host_fw_ver *fw_ver) +{ + wmi_service_ready_event *ev; + + ev = (wmi_service_ready_event *) evt_buf; + + fw_ver->sw_version = ev->sw_version; + fw_ver->sw_version_1 = ev->sw_version_1; + + return QDF_STATUS_SUCCESS; +} + +/** + * extract_fw_abi_version_non_tlv() - extract fw abi version + * @wmi_handle: wmi handle + * @param evt_buf: Pointer to event buffer + * @param fw_ver: Pointer to hold fw abi version + * + * Return: 0 for success or error code + */ +QDF_STATUS extract_fw_abi_version_non_tlv(wmi_unified_t wmi_handle, + void *evt_buf, struct wmi_host_fw_abi_ver *fw_ver) +{ + wmi_ready_event *ev; + + ev = (wmi_ready_event *) evt_buf; + + fw_ver->sw_version = ev->sw_version; + fw_ver->abi_version = ev->abi_version; + + return QDF_STATUS_SUCCESS; +} + +/** + * extract_hal_reg_cap_non_tlv() - extract HAL registered capabilities + * @wmi_handle: wmi handle + * @param evt_buf: Pointer to event buffer + * @param cap: pointer to hold HAL reg capabilities + * + * Return: 0 for success or error code + */ +static QDF_STATUS extract_hal_reg_cap_non_tlv(wmi_unified_t wmi_handle, + void *evt_buf, + TARGET_HAL_REG_CAPABILITIES *cap) +{ + wmi_service_ready_event *ev; + + ev = (wmi_service_ready_event *) evt_buf; + + qdf_mem_copy(cap, &ev->hal_reg_capabilities, + sizeof(TARGET_HAL_REG_CAPABILITIES)); + + return QDF_STATUS_SUCCESS; +} + +/** + * extract_host_mem_req_non_tlv() - Extract host memory request event + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * @param num_entries: pointer to hold number of entries requested + * + * Return: Number of entries requested + */ +static host_mem_req *extract_host_mem_req_non_tlv(wmi_unified_t wmi_handle, + void *evt_buf, uint8_t *num_entries) +{ + wmi_service_ready_event *ev; + + ev = (wmi_service_ready_event *) evt_buf; + + *num_entries = ev->num_mem_reqs; + return (host_mem_req *)ev->mem_reqs; +} + +/** + * save_fw_version_in_service_ready_non_tlv() - Save fw version in service + * ready function + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * + * Return: 0 for success or error code + */ +static QDF_STATUS save_fw_version_in_service_ready_non_tlv( + wmi_unified_t wmi_handle, + void *evt_buf) +{ + /* Version check and exchange is not present in non-tlv implementation*/ + return QDF_STATUS_SUCCESS; +} + +/** + * ready_check_and_update_fw_version_non_tlv() - Ready and fw version check + * function + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * + * Return: 0 for success or error code + */ +static QDF_STATUS ready_check_and_update_fw_version_non_tlv( + wmi_unified_t wmi_handle, + void *evt_buf) +{ + /* Version check and exchange is not present in non-tlv implementation*/ + return QDF_STATUS_SUCCESS; +} + +/** + * ready_extract_init_status_non_tlv() - Extract init status from ready event + * @wmi_handle: wmi handle + * @param evt_buf: Pointer to event buffer + * + * Return: ready status + */ +static uint32_t ready_extract_init_status_non_tlv(wmi_unified_t wmi_hdl, + void *evt_buf) +{ + wmi_ready_event *ev = (wmi_ready_event *) evt_buf; + qdf_print("Version = %d %d status = %d\n", ev->sw_version, + ev->abi_version, ev->status); + return ev->status; +} + +/** + * ready_extract_mac_addr_non_tlv() - extract mac address from ready event + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * @param macaddr: Pointer to hold MAC address + * + * Return: 0 for success or error code + */ +static QDF_STATUS ready_extract_mac_addr_non_tlv(wmi_unified_t wmi_hdl, + void *evt_buf, + uint8_t *macaddr) +{ + wmi_ready_event *ev = (wmi_ready_event *) evt_buf; + + WMI_MAC_ADDR_TO_CHAR_ARRAY(&ev->mac_addr, macaddr); + return QDF_STATUS_SUCCESS; +} + +/** + * extract_dbglog_data_len_non_tlv() - extract debuglog data length + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * + * Return: length + */ +static uint8_t *extract_dbglog_data_len_non_tlv(wmi_unified_t wmi_handle, + void *evt_buf, + uint16_t *len) +{ + /*Len is already valid from event. No need to change it */ + return evt_buf; +} + +/** + * extract_wds_addr_event_non_tlv() - extract wds address from event + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * @param wds_ev: Pointer to hold wds address + * + * Return: 0 for success or error code + */ +static QDF_STATUS extract_wds_addr_event_non_tlv(wmi_unified_t wmi_handle, + void *evt_buf, + uint16_t len, wds_addr_event_t *wds_ev) +{ + wmi_wds_addr_event_t *ev = (wmi_wds_addr_event_t *) evt_buf; + int i; + +#ifdef BIG_ENDIAN_HOST + { + uint8_t *datap = (uint8_t *) ev; + /*Skip swapping the first long word*/ + datap += sizeof(uint32_t); + for (i = 0; i < ((len / sizeof(uint32_t))-1); + i++, datap += sizeof(uint32_t)) + *(uint32_t *)datap = + qdf_le32_to_cpu(*(uint32_t *)datap); + } +#endif + + qdf_mem_copy(wds_ev->event_type, ev->event_type, + sizeof(wds_ev->event_type)); + for (i = 0; i < 4; i++) { + wds_ev->peer_mac[i] = + ((u_int8_t *)&(ev->peer_mac.mac_addr31to0))[i]; + wds_ev->dest_mac[i] = + ((u_int8_t *)&(ev->dest_mac.mac_addr31to0))[i]; + } + for (i = 0; i < 2; i++) { + wds_ev->peer_mac[4+i] = + ((u_int8_t *)&(ev->peer_mac.mac_addr47to32))[i]; + wds_ev->dest_mac[4+i] = + ((u_int8_t *)&(ev->dest_mac.mac_addr47to32))[i]; + } + return QDF_STATUS_SUCCESS; +} + +/** + * extract_dcs_interference_type_non_tlv() - extract dcs interference type + * from event + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * @param interference_type: Pointer to hold interference type + * + * Return: 0 for success or error code + */ +static QDF_STATUS extract_dcs_interference_type_non_tlv( + wmi_unified_t wmi_handle, + void *evt_buf, uint32_t *interference_type) +{ + wmi_dcs_interference_event_t *ev = + (wmi_dcs_interference_event_t *) evt_buf; + + *interference_type = ev->interference_type; + return QDF_STATUS_SUCCESS; +} + +/* + * extract_dcs_cw_int_non_tlv() - extract dcs cw interference from event + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * @param cw_int: Pointer to hold cw interference + * + * Return: 0 for success or error code + */ +static QDF_STATUS extract_dcs_cw_int_non_tlv(wmi_unified_t wmi_handle, + void *evt_buf, + wmi_host_ath_dcs_cw_int *cw_int) +{ + wmi_dcs_interference_event_t *ev = + (wmi_dcs_interference_event_t *) evt_buf; + + qdf_mem_copy(cw_int, &ev->int_event.cw_int, sizeof(*cw_int)); + return QDF_STATUS_SUCCESS; +} + +/** + * extract_dcs_im_tgt_stats_non_tlv() - extract dcs im target stats from event + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * @param wlan_stat: Pointer to hold wlan stats + * + * Return: 0 for success or error code + */ +static QDF_STATUS extract_dcs_im_tgt_stats_non_tlv(wmi_unified_t wmi_handle, + void *evt_buf, + wmi_host_dcs_im_tgt_stats_t *wlan_stat) +{ + wmi_dcs_interference_event_t *ev = + (wmi_dcs_interference_event_t *) evt_buf; + + qdf_mem_copy(wlan_stat, &ev->int_event.wlan_stat, + sizeof(wmi_host_dcs_im_tgt_stats_t)); + return QDF_STATUS_SUCCESS; +} + +/** + * extract_fips_event_error_status_non_tlv() - extract fips event error status + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * @param err_status: Pointer to hold error status + * + * Return: 0 for success or error code + */ +static QDF_STATUS extract_fips_event_error_status_non_tlv( + wmi_unified_t wmi_handle, void *evt_buf, + uint32_t *err_status) +{ + wmi_pdev_fips_event *event = (wmi_pdev_fips_event *)evt_buf; + + *err_status = event->error_status; + return QDF_STATUS_SUCCESS; +} + +/** + * extract_fips_event_data_non_tlv() - extract fips event data + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * @param data_len: Pointer to hold fips data length + * @param data: Double pointer to hold fips data + * + * Return: 0 for success or error code + */ +static QDF_STATUS extract_fips_event_data_non_tlv(wmi_unified_t wmi_handle, + void *evt_buf, + uint32_t *data_len, uint32_t **data) +{ + wmi_pdev_fips_event *event = (wmi_pdev_fips_event *)evt_buf; +#ifdef BIG_ENDIAN_HOST + { + /*****************LE to BE conversion*************************/ + + /* Assigning unaligned space to copy the data */ + unsigned char *data_unaligned = qdf_mem_malloc( + (sizeof(u_int8_t)*event->data_len + FIPS_ALIGN)); + + u_int8_t *data_aligned = NULL; + int c; + + /* Checking if kmalloc does succesful allocation */ + if (data_unaligned == NULL) + return QDF_STATUS_E_FAILURE; + + /* Checking if space is alligned */ + if (!FIPS_IS_ALIGNED(data_unaligned, FIPS_ALIGN)) { + /* align the data space */ + data_aligned = + (u_int8_t *)FIPS_ALIGNTO(data_unaligned, FIPS_ALIGN); + } else { + data_aligned = (u_int8_t *)data_unaligned; + } + + /* memset and copy content from data to data aligned */ + OS_MEMSET(data_aligned, 0, event->data_len); + OS_MEMCPY(data_aligned, event->data, event->data_len); + /* Endianness to LE */ + for (c = 0; c < event->data_len/4; c++) { + *((u_int32_t *)data_aligned+c) = + qdf_le32_to_cpu(*((u_int32_t *)data_aligned+c)); + } + + /* Copy content to event->data */ + OS_MEMCPY(event->data, data_aligned, event->data_len); + + /* clean up allocated space */ + qdf_mem_free(data_unaligned); + data_aligned = NULL; + data_unaligned = NULL; + + /*************************************************************/ + } +#endif + *data = event->data; + *data_len = event->data_len; + return QDF_STATUS_SUCCESS; +} + +/** + * extract_vdev_start_resp_non_tlv() - extract vdev start response + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * @param vdev_rsp: Pointer to hold vdev response + * + * Return: 0 for success or error code + */ +static QDF_STATUS extract_vdev_start_resp_non_tlv(wmi_unified_t wmi_handle, + void *evt_buf, + wmi_host_vdev_start_resp *vdev_rsp) +{ + wmi_vdev_start_response_event *ev = + (wmi_vdev_start_response_event *) evt_buf; + + qdf_mem_zero(vdev_rsp, sizeof(*vdev_rsp)); + + vdev_rsp->vdev_id = ev->vdev_id; + vdev_rsp->requestor_id = ev->requestor_id; + vdev_rsp->resp_type = ev->resp_type; + vdev_rsp->status = ev->status; + + return QDF_STATUS_SUCCESS; +} + +/** + * extract_tbttoffset_update_params_non_tlv() - extract tbtt offset update param + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * @param vdev_map: Pointer to hold vdev map + * @param tbttoffset_list: Pointer to tbtt offset list + * + * Return: 0 for success or error code + */ +QDF_STATUS extract_tbttoffset_update_params_non_tlv(void *wmi_hdl, + void *evt_buf, + uint32_t *vdev_map, uint32_t **tbttoffset_list) +{ + wmi_tbtt_offset_event *tbtt_offset_event = + (wmi_tbtt_offset_event *)evt_buf; + + *vdev_map = tbtt_offset_event->vdev_map; + *tbttoffset_list = tbtt_offset_event->tbttoffset_list; + + return QDF_STATUS_SUCCESS; +} + +/** + * extract_mgmt_rx_params_non_tlv() - extract management rx params from event + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * @param hdr: Pointer to hold header + * @param bufp: Pointer to hold pointer to rx param buffer + * + * Return: 0 for success or error code + */ +static QDF_STATUS extract_mgmt_rx_params_non_tlv(wmi_unified_t wmi_handle, + void *evt_buf, + wmi_host_mgmt_rx_hdr *hdr, uint8_t **bufp) +{ + wmi_mgmt_rx_event *ev = (wmi_mgmt_rx_event *)evt_buf; + + hdr->channel = ev->hdr.channel; + hdr->snr = ev->hdr.snr; + hdr->rate = ev->hdr.rate; + hdr->phy_mode = ev->hdr.phy_mode; + hdr->buf_len = ev->hdr.buf_len; + hdr->status = ev->hdr.status; + + *bufp = ev->bufp; + + return QDF_STATUS_SUCCESS; +} + +/** + * extract_vdev_stopped_param_non_tlv() - extract vdev stop param from event + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * @param vdev_id: Pointer to hold vdev identifier + * + * Return: 0 for success or error code + */ +static QDF_STATUS extract_vdev_stopped_param_non_tlv(wmi_unified_t wmi_handle, + void *evt_buf, + uint32_t *vdev_id) +{ + wmi_vdev_stopped_event *event = (wmi_vdev_stopped_event *)evt_buf; + + *vdev_id = event->vdev_id; + + return QDF_STATUS_SUCCESS; +} + +/** + * extract_vdev_roam_param_non_tlv() - extract vdev roam param from event + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * @param param: Pointer to hold roam param + * + * Return: 0 for success or error code + */ +static QDF_STATUS extract_vdev_roam_param_non_tlv(wmi_unified_t wmi_handle, + void *evt_buf, + wmi_host_roam_event *param) +{ + wmi_roam_event *evt = (wmi_roam_event *)evt_buf; + + qdf_mem_zero(param, sizeof(*param)); + param->vdev_id = evt->vdev_id; + param->reason = evt->reason; + return QDF_STATUS_SUCCESS; +} + +/** + * extract_vdev_scan_ev_param_non_tlv() - extract vdev scan param from event + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * @param param: Pointer to hold vdev scan param + * + * Return: 0 for success or error code + */ +static QDF_STATUS extract_vdev_scan_ev_param_non_tlv(wmi_unified_t wmi_handle, + void *evt_buf, + wmi_host_scan_event *param) +{ + wmi_scan_event *evt = (wmi_scan_event *)evt_buf; + + qdf_mem_zero(param, sizeof(*param)); + switch (evt->event) { + case WMI_SCAN_EVENT_STARTED: + param->event = WMI_HOST_SCAN_EVENT_STARTED; + break; + case WMI_SCAN_EVENT_COMPLETED: + param->event = WMI_HOST_SCAN_EVENT_COMPLETED; + break; + case WMI_SCAN_EVENT_BSS_CHANNEL: + param->event = WMI_HOST_SCAN_EVENT_BSS_CHANNEL; + break; + case WMI_SCAN_EVENT_FOREIGN_CHANNEL: + param->event = WMI_HOST_SCAN_EVENT_FOREIGN_CHANNEL; + break; + case WMI_SCAN_EVENT_DEQUEUED: + param->event = WMI_HOST_SCAN_EVENT_DEQUEUED; + break; + case WMI_SCAN_EVENT_PREEMPTED: + param->event = WMI_HOST_SCAN_EVENT_PREEMPTED; + break; + case WMI_SCAN_EVENT_START_FAILED: + param->event = WMI_HOST_SCAN_EVENT_START_FAILED; + break; + case WMI_SCAN_EVENT_RESTARTED: + param->event = WMI_HOST_SCAN_EVENT_RESTARTED; + break; + case WMI_HOST_SCAN_EVENT_FOREIGN_CHANNEL_EXIT: + param->event = WMI_HOST_SCAN_EVENT_FOREIGN_CHANNEL_EXIT; + break; + case WMI_SCAN_EVENT_INVALID: + param->event = WMI_HOST_SCAN_EVENT_INVALID; + break; + case WMI_SCAN_EVENT_MAX: + default: + param->event = WMI_HOST_SCAN_EVENT_MAX; + break; + }; + + switch (evt->reason) { + case WMI_SCAN_REASON_NONE: + param->reason = WMI_HOST_SCAN_REASON_NONE; + break; + case WMI_SCAN_REASON_COMPLETED: + param->reason = WMI_HOST_SCAN_REASON_COMPLETED; + break; + case WMI_SCAN_REASON_CANCELLED: + param->reason = WMI_HOST_SCAN_REASON_CANCELLED; + break; + case WMI_SCAN_REASON_PREEMPTED: + param->reason = WMI_HOST_SCAN_REASON_PREEMPTED; + break; + case WMI_SCAN_REASON_TIMEDOUT: + param->reason = WMI_HOST_SCAN_REASON_TIMEDOUT; + break; + case WMI_SCAN_REASON_INTERNAL_FAILURE: + param->reason = WMI_HOST_SCAN_REASON_INTERNAL_FAILURE; + break; + case WMI_SCAN_REASON_MAX: + default: + param->reason = WMI_HOST_SCAN_REASON_MAX; + break; + }; + + param->channel_freq = evt->channel_freq; + param->requestor = evt->requestor; + param->scan_id = evt->scan_id; + param->vdev_id = evt->vdev_id; + return QDF_STATUS_SUCCESS; +} + +/** + * extract_mu_ev_param_non_tlv() - extract mu param from event + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * @param param: Pointer to hold mu report + * + * Return: 0 for success or error code + */ +QDF_STATUS extract_mu_ev_param_non_tlv(wmi_unified_t wmi_handle, void *evt_buf, + wmi_host_mu_report_event *param) +{ + wmi_mu_report_event *event = (wmi_mu_report_event *)evt_buf; + + param->mu_request_id = event->mu_request_id; + param->status_reason = event->status_reason; + qdf_mem_copy(param->total_mu, event->total_mu, sizeof(param->total_mu)); + param->num_active_bssid = event->num_active_bssid; + + return QDF_STATUS_SUCCESS; +} + +/** + * extract_pdev_tpc_config_ev_param_non_tlv() - extract pdev tpc configuration + * param from event + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * @param param: Pointer to hold tpc configuration + * + * Return: 0 for success or error code + */ +QDF_STATUS extract_pdev_tpc_config_ev_param_non_tlv(wmi_unified_t wmi_handle, + void *evt_buf, + wmi_host_pdev_tpc_config_event *param) +{ + wmi_pdev_tpc_config_event *event = (wmi_pdev_tpc_config_event *)evt_buf; + + param->regDomain = event->regDomain; + param->chanFreq = event->chanFreq; + param->phyMode = event->phyMode; + param->twiceAntennaReduction = event->twiceAntennaReduction; + param->twiceMaxRDPower = event->twiceMaxRDPower; + param->powerLimit = event->powerLimit; + param->rateMax = event->rateMax; + param->numTxChain = event->numTxChain; + param->ctl = event->ctl; + param->flags = event->flags; + + qdf_mem_copy(param->maxRegAllowedPower, event->maxRegAllowedPower, + sizeof(param->maxRegAllowedPower)); + qdf_mem_copy(param->maxRegAllowedPowerAGCDD, + event->maxRegAllowedPowerAGCDD, + sizeof(param->maxRegAllowedPowerAGCDD)); + qdf_mem_copy(param->maxRegAllowedPowerAGSTBC, + event->maxRegAllowedPowerAGSTBC, + sizeof(param->maxRegAllowedPowerAGSTBC)); + qdf_mem_copy(param->maxRegAllowedPowerAGTXBF, + event->maxRegAllowedPowerAGTXBF, + sizeof(param->maxRegAllowedPowerAGTXBF)); + qdf_mem_copy(param->ratesArray, event->ratesArray, + sizeof(param->ratesArray)); + + return QDF_STATUS_SUCCESS; +} + +/** + * extract_nfcal_power_ev_param_non_tlv() - extract noise floor calibration + * power param from event + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * @param param: Pointer to hold nf cal power param + * + * Return: 0 for success or error code + */ +QDF_STATUS extract_nfcal_power_ev_param_non_tlv(wmi_unified_t wmi_handle, + void *evt_buf, + wmi_host_pdev_nfcal_power_all_channels_event *param) +{ + wmi_pdev_nfcal_power_all_channels_event *event = + (wmi_pdev_nfcal_power_all_channels_event *)evt_buf; + + qdf_mem_copy(param->nfdBr, event->nfdBr, sizeof(param->nfdBr)); + qdf_mem_copy(param->nfdBm, event->nfdBm, sizeof(param->nfdBm)); + qdf_mem_copy(param->freqNum, event->freqNum, sizeof(param->freqNum)); + + return QDF_STATUS_SUCCESS; +} + +/** + * extract_pdev_tpc_ev_param_non_tlv() - extract tpc param from event + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * @param param: Pointer to hold tpc param + * + * Return: 0 for success or error code + */ +QDF_STATUS extract_pdev_tpc_ev_param_non_tlv(wmi_unified_t wmi_handle, + void *evt_buf, + wmi_host_pdev_tpc_event *param) +{ + wmi_pdev_tpc_event *event = (wmi_pdev_tpc_event *)evt_buf; + + qdf_mem_copy(param->tpc, event->tpc, sizeof(param->tpc)); + + return QDF_STATUS_SUCCESS; +} + +/** + * extract_pdev_generic_buffer_ev_param_non_tlv() - extract pdev generic buffer + * from event + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * @param param: Pointer to generic buffer param + * + * Return: 0 for success or error code + */ +QDF_STATUS extract_pdev_generic_buffer_ev_param_non_tlv( + wmi_unified_t wmi_handle, void *evt_buf, + wmi_host_pdev_generic_buffer_event *param) +{ + wmi_pdev_generic_buffer_event *event = + (wmi_pdev_generic_buffer_event *)evt_buf; + + param->buf_type = event->buf_type; + param->frag_id = event->frag_id; + param->more_frag = event->more_frag; + param->buf_len = event->buf_len; + + qdf_mem_copy(param->buf_info, event->buf_info, event->buf_len); + + return QDF_STATUS_SUCCESS; +} + +/** + * extract_gpio_input_ev_param_non_tlv() - extract gpio input param from event + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * @param gpio_num: Pointer to hold gpio number + * + * Return: 0 for success or error code + */ +static QDF_STATUS extract_gpio_input_ev_param_non_tlv(wmi_unified_t wmi_handle, + void *evt_buf, uint32_t *gpio_num) +{ + wmi_gpio_input_event *ev = (wmi_gpio_input_event *) evt_buf; + + *gpio_num = ev->gpio_num; + return QDF_STATUS_SUCCESS; +} + +/** + * extract_pdev_reserve_ast_ev_param_non_tlv() - extract reserve ast entry + * param from event + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * @param result: Pointer to hold reserve ast entry param + * + * Return: 0 for success or error code + */ +static QDF_STATUS extract_pdev_reserve_ast_ev_param_non_tlv( + wmi_unified_t wmi_handle, + void *evt_buf, uint32_t *result) +{ + wmi_pdev_reserve_ast_entry_event *ev = + (wmi_pdev_reserve_ast_entry_event *) evt_buf; + + *result = ev->result; + return QDF_STATUS_SUCCESS; +} + +/** + * extract_swba_vdev_map_non_tlv() - extract swba vdev map from event + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * @param vdev_map: Pointer to hold vdev map + * + * Return: 0 for success or error code + */ +static QDF_STATUS extract_swba_vdev_map_non_tlv(wmi_unified_t wmi_handle, + void *evt_buf, + uint32_t *vdev_map) +{ + wmi_host_swba_event *swba_event = (wmi_host_swba_event *)evt_buf; + + *vdev_map = swba_event->vdev_map; + + return QDF_STATUS_SUCCESS; +} + +/** + * extract_swba_tim_info_non_tlv() - extract swba tim info from event + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * @param idx: Index to bcn info + * @param tim_info: Pointer to hold tim info + * + * Return: 0 for success or error code + */ +static QDF_STATUS extract_swba_tim_info_non_tlv(wmi_unified_t wmi_handle, + void *evt_buf, + uint32_t idx, wmi_host_tim_info *tim_info) +{ + wmi_host_swba_event *swba_event = (wmi_host_swba_event *)evt_buf; + wmi_bcn_info *bcn_info; + + bcn_info = &swba_event->bcn_info[idx]; + + tim_info->tim_len = bcn_info->tim_info.tim_len; + tim_info->tim_mcast = bcn_info->tim_info.tim_mcast; + qdf_mem_copy(tim_info->tim_bitmap, bcn_info->tim_info.tim_bitmap, + (sizeof(uint32_t) * WMI_TIM_BITMAP_ARRAY_SIZE)); + tim_info->tim_changed = bcn_info->tim_info.tim_changed; + tim_info->tim_num_ps_pending = bcn_info->tim_info.tim_num_ps_pending; + return QDF_STATUS_SUCCESS; +} + +/** + * extract_swba_noa_info_non_tlv() - extract swba NoA information from event + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * @param idx: Index to bcn info + * @param p2p_desc: Pointer to hold p2p NoA info + * + * Return: 0 for success or error code + */ +static QDF_STATUS extract_swba_noa_info_non_tlv(wmi_unified_t wmi_handle, + void *evt_buf, + uint32_t idx, wmi_host_p2p_noa_info *p2p_desc) +{ + wmi_host_swba_event *swba_event = (wmi_host_swba_event *)evt_buf; + wmi_p2p_noa_info *p2p_noa_info; + wmi_bcn_info *bcn_info; + uint8_t i = 0; + + bcn_info = &swba_event->bcn_info[idx]; + + p2p_noa_info = &bcn_info->p2p_noa_info; + + p2p_desc->modified = false; + p2p_desc->num_descriptors = 0; + if (WMI_UNIFIED_NOA_ATTR_IS_MODIFIED(p2p_noa_info)) { + p2p_desc->modified = true; + p2p_desc->index = + (uint8_t) WMI_UNIFIED_NOA_ATTR_INDEX_GET(p2p_noa_info); + p2p_desc->oppPS = + (uint8_t) WMI_UNIFIED_NOA_ATTR_OPP_PS_GET(p2p_noa_info); + p2p_desc->ctwindow = + (uint8_t) WMI_UNIFIED_NOA_ATTR_CTWIN_GET(p2p_noa_info); + p2p_desc->num_descriptors = + (uint8_t) WMI_UNIFIED_NOA_ATTR_NUM_DESC_GET(p2p_noa_info); + + for (i = 0; i < p2p_desc->num_descriptors; i++) { + p2p_desc->noa_descriptors[i].type_count = + (uint8_t) p2p_noa_info->noa_descriptors[i]. + type_count; + p2p_desc->noa_descriptors[i].duration = + p2p_noa_info->noa_descriptors[i].duration; + p2p_desc->noa_descriptors[i].interval = + p2p_noa_info->noa_descriptors[i].interval; + p2p_desc->noa_descriptors[i].start_time = + p2p_noa_info->noa_descriptors[i].start_time; + } + } + + return QDF_STATUS_SUCCESS; +} + +/** + * extract_peer_sta_ps_statechange_ev_non_tlv() - extract peer sta ps state + * from event + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * @param ev: Pointer to hold peer param and ps state + * + * Return: 0 for success or error code + */ +QDF_STATUS extract_peer_sta_ps_statechange_ev_non_tlv(wmi_unified_t wmi_handle, + void *evt_buf, wmi_host_peer_sta_ps_statechange_event *ev) +{ + wmi_peer_sta_ps_statechange_event *event = + (wmi_peer_sta_ps_statechange_event *)evt_buf; + + WMI_MAC_ADDR_TO_CHAR_ARRAY(&event->peer_macaddr, ev->peer_macaddr); + ev->peer_ps_state = event->peer_ps_state; + + return QDF_STATUS_SUCCESS; +} + +/** + * extract_peer_sta_kickout_ev_non_tlv() - extract peer sta kickout event + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * @param ev: Pointer to hold peer param + * + * Return: 0 for success or error code + */ +QDF_STATUS extract_peer_sta_kickout_ev_non_tlv(wmi_unified_t wmi_handle, + void *evt_buf, + wmi_host_peer_sta_kickout_event *ev) +{ + wmi_peer_sta_kickout_event *kickout_event = + (wmi_peer_sta_kickout_event *)evt_buf; + + WMI_MAC_ADDR_TO_CHAR_ARRAY(&kickout_event->peer_macaddr, + ev->peer_macaddr); + + /**Following not available in legacy wmi*/ + ev->reason = 0; + ev->rssi = 0; + return QDF_STATUS_SUCCESS; +} + +/** + * extract_peer_ratecode_list_ev_non_tlv() - extract peer ratecode from event + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * @param peer_mac: Pointer to hold peer mac address + * @param rate_cap: Pointer to hold ratecode + * + * Return: 0 for success or error code + */ +QDF_STATUS extract_peer_ratecode_list_ev_non_tlv(wmi_unified_t wmi_handle, + void *evt_buf, + uint8_t *peer_mac, wmi_sa_rate_cap *rate_cap) +{ + wmi_peer_ratecode_list_event_t *rate_event = + (wmi_peer_ratecode_list_event_t *)evt_buf; + int i, htindex, j; + uint8_t shift = 0; + + WMI_MAC_ADDR_TO_CHAR_ARRAY(&rate_event->peer_macaddr, peer_mac); + + htindex = 0; + rate_cap->ratecount[0] = + ((rate_event->peer_rate_info.ratecount) & SA_MASK_BYTE); + rate_cap->ratecount[1] = + ((rate_event->peer_rate_info.ratecount >> 8) & SA_MASK_BYTE); + rate_cap->ratecount[2] = + ((rate_event->peer_rate_info.ratecount >> 16) & SA_MASK_BYTE); + rate_cap->ratecount[3] = + ((rate_event->peer_rate_info.ratecount >> 24) & SA_MASK_BYTE); + + if (rate_cap->ratecount[0]) { + for (i = 0; i < SA_MAX_LEGACY_RATE_DWORDS; i++) { + for (j = 0; j < SA_BYTES_IN_DWORD; j++) { + rate_cap->ratecode_legacy[htindex] = + ((rate_event->peer_rate_info.ratecode_legacy[i] + >> (8*j)) & SA_MASK_BYTE); + htindex++; + } + } + } + + htindex = 0; + for (i = 0; i < SA_MAX_HT_RATE_DWORDS; i++) { + for (j = 0; j < SA_BYTES_IN_DWORD; j++) { + shift = (8*j); + rate_cap->ratecode_20[htindex] = + ((rate_event->peer_rate_info.ratecode_20[i] + >> (shift)) & SA_MASK_BYTE); + rate_cap->ratecode_40[htindex] = + ((rate_event->peer_rate_info.ratecode_40[i] + >> (shift)) & SA_MASK_BYTE); + rate_cap->ratecode_80[htindex] = + ((rate_event->peer_rate_info.ratecode_80[i] + >> (shift)) & SA_MASK_BYTE); + htindex++; + } + } + return QDF_STATUS_SUCCESS; +} + +/** + * extract_rtt_header_internal_non_tlv() - extract internal rtt header from + * event + * @param ev: pointer to internal rtt event header + * @param hdr: Pointer to received rtt event header + * + * Return: None + */ +static void extract_rtt_header_internal_non_tlv(wmi_host_rtt_event_hdr *ev, + wmi_rtt_event_hdr *hdr) +{ + ev->req_id = WMI_RTT_REQ_ID_GET(hdr->req_id); + ev->result = (hdr->req_id & 0xffff0000) >> 16; + ev->meas_type = WMI_RTT_REPORT_MEAS_TYPE_GET(hdr->req_id); + ev->report_type = WMI_RTT_REPORT_REPORT_TYPE_GET(hdr->req_id); + ev->v3_status = WMI_RTT_REPORT_V3_STATUS_GET(hdr->req_id); + ev->v3_finish = WMI_RTT_REPORT_V3_FINISH_GET(hdr->req_id); + ev->v3_tm_start = WMI_RTT_REPORT_V3_TM_START_GET(hdr->req_id); + ev->num_ap = WMI_RTT_REPORT_NUM_AP_GET(hdr->req_id); + + WMI_MAC_ADDR_TO_CHAR_ARRAY(&hdr->dest_mac, ev->dest_mac); +} + +/** + * extract_rtt_error_report_ev_non_tlv() - extract rtt error report from event + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * @param wds_ev: Pointer to hold rtt error report + * + * Return: 0 for success or error code + */ +static QDF_STATUS extract_rtt_error_report_ev_non_tlv(wmi_unified_t wmi_handle, + void *evt_buf, + wmi_host_rtt_error_report_event *ev) +{ + wmi_rtt_error_report_event *error_report = + (wmi_rtt_error_report_event *) evt_buf; + + extract_rtt_header_internal_non_tlv(&ev->hdr, &error_report->header); + ev->reject_reason = error_report->reject_reason; + + return QDF_STATUS_SUCCESS; +} + +/** + * extract_rtt_hdr_non_tlv() - extract rtt header from event + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * @param ev: Pointer to hold rtt header + * + * Return: 0 for success or error code + */ +QDF_STATUS extract_rtt_hdr_non_tlv(wmi_unified_t wmi_handle, void *evt_buf, + wmi_host_rtt_event_hdr *ev) +{ + wmi_rtt_event_hdr *hdr = (wmi_rtt_event_hdr *) evt_buf; + + extract_rtt_header_internal_non_tlv(ev, hdr); + + return QDF_STATUS_SUCCESS; +} + +/** + * copy_rtt_report_cfr + * @ev: pointer to destination event pointer + * @report_type: report type recieved in event + * @p: pointer to event data + * @hdump: pointer to destination buffer + * @hdump_len: length of dest buffer + * + * Return: Pointer to current offset in p + */ +static uint8_t *copy_rtt_report_cfr(wmi_host_rtt_meas_event *ev, + uint8_t report_type, uint8_t *p, + uint8_t *hdump, int16_t hdump_len) +{ + uint8_t index, i; + uint8_t *tmp, *temp1, *temp2; +#define TONE_LEGACY_20M 53 +#define TONE_VHT_20M 56 +#define TONE_VHT_40M 117 +#define TONE_VHT_80M 242 + int tone_number[4] = { + TONE_LEGACY_20M, TONE_VHT_20M, TONE_VHT_40M, TONE_VHT_80M}; +#define MEM_ALIGN(x) ((((x)<<1)+3) & 0xFFFC) + /* the buffer size of 1 chain for each BW 0-3 */ + u_int16_t bw_size[4] = { + MEM_ALIGN(TONE_LEGACY_20M), + MEM_ALIGN(TONE_VHT_20M), + MEM_ALIGN(TONE_VHT_40M), + MEM_ALIGN(TONE_VHT_80M) + }; + if (hdump == NULL) { + qdf_print("Destination buffer is NULL\n"); + return p; + } + temp1 = temp2 = hdump; + + for (index = 0; index < 4; index++) { + if (ev->chain_mask & (1 << index)) { + if (index == 0) + ev->rssi0 = *((u_int32_t *)p); + if (index == 1) + ev->rssi1 = *((u_int32_t *)p); + if (index == 2) + ev->rssi2 = *((u_int32_t *)p); + if (index == 3) + ev->rssi3 = *((u_int32_t *)p); + + p += sizeof(u_int32_t); + if (report_type == WMI_RTT_REPORT_CFR) { + tmp = p + bw_size[ev->bw]; + ev->txrxchain_mask = tone_number[ev->bw]; + temp2 = temp2 + bw_size[ev->bw]; + for (i = 0; (i < tone_number[ev->bw]); i++) { + qdf_mem_copy(temp1, p, 2); + temp1 += 2; + p += 2; + hdump_len -= 2; + if (hdump_len <= 0) + break; + } + temp1 = temp2; + p = tmp; + } + } + } + return p; +} +/** + * extract_rtt_ev_non_tlv() - extract rtt event + * @wmi_handle: wmi handle + * @param evt_buf: Pointer to event buffer + * @param ev: Pointer to hold rtt event + * @param hdump: Pointer to hold hex dump + * @param hdump_len: hex dump length + * + * Return: 0 for success or error code + */ +QDF_STATUS extract_rtt_ev_non_tlv(wmi_unified_t wmi_handle, void *evt_buf, + wmi_host_rtt_meas_event *ev, uint8_t *hdump, uint16_t h_len) +{ + wmi_rtt_meas_event *body = (wmi_rtt_meas_event *) evt_buf; + uint8_t meas_type, report_type; + uint8_t *p; + int16_t hdump_len = h_len; + + A_TIME64 *time; + + if (body) { + meas_type = WMI_RTT_REPORT_MEAS_TYPE_GET(body->header.req_id); + report_type = + WMI_RTT_REPORT_REPORT_TYPE_GET(body->header.req_id); + + ev->chain_mask = WMI_RTT_REPORT_RX_CHAIN_GET(body->rx_chain); + ev->bw = WMI_RTT_REPORT_RX_BW_GET(body->rx_chain); + + ev->tod = ((u_int64_t) body->tod.time32) << 32; + ev->tod |= body->tod.time0; /*tmp1 is the 64 bit tod*/ + ev->toa = ((u_int64_t) body->toa.time32) << 32; + ev->toa |= body->toa.time0; + + p = (u_int8_t *) (++body); + + /* if the measurement is TMR, we should have T3 and T4 */ + if (meas_type == RTT_MEAS_FRAME_TMR) { + time = (A_TIME64 *) body; + ev->t3 = (u_int64_t) (time->time32) << 32; + ev->t3 |= time->time0; + + time++; + ev->t4 = (u_int64_t)(time->time32) << 32; + ev->t4 |= time->time0; + + p = (u_int8_t *) (++time); + } else { + ev->t3 = 0; + ev->t4 = 0; + } + + ev->rssi0 = 0; + ev->rssi1 = 0; + ev->rssi2 = 0; + ev->rssi3 = 0; + p = copy_rtt_report_cfr(ev, report_type, p, hdump, hdump_len); + } else { + qdf_print("Error!body is NULL\n"); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * extract_thermal_stats_non_tlv() - extract thermal stats from event + * @wmi_handle: wmi handle + * @param evt_buf: Pointer to event buffer + * @param temp: Pointer to hold extracted temperature + * @param level: Pointer to hold extracted level + * + * Return: 0 for success or error code + */ +QDF_STATUS extract_thermal_stats_non_tlv(wmi_unified_t wmi_handle, + void *evt_buf, + uint32_t *temp, uint32_t *level) +{ + tt_stats_t *tt_stats_event = NULL; + + tt_stats_event = (tt_stats_t *) evt_buf; + + *temp = tt_stats_event->temp; + *level = tt_stats_event->level; + return QDF_STATUS_SUCCESS; +} + +/** + * extract_thermal_level_stats_non_tlv() - extract thermal level stats from + * event + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * @param idx: Index to level stats + * @param levelcount: Pointer to hold levelcount + * @param dccount: Pointer to hold dccount + * + * Return: 0 for success or error code + */ +QDF_STATUS extract_thermal_level_stats_non_tlv(wmi_unified_t wmi_handle, + void *evt_buf, + uint8_t idx, uint32_t *levelcount, uint32_t *dccount) +{ + tt_stats_t *tt_stats_event = NULL; + + tt_stats_event = (tt_stats_t *) evt_buf; + + if (idx < TT_LEVELS) { + *levelcount = tt_stats_event->levstats[idx].levelcount; + *dccount = tt_stats_event->levstats[idx].dccount; + return QDF_STATUS_SUCCESS; + } + return QDF_STATUS_E_FAILURE; +} + +/** + * extract_comb_phyerr_non_tlv() - extract comb phy error from event + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * @param datalen: data length of event buffer + * @param buf_offset: Pointer to hold value of current event buffer offset + * post extraction + * @param phyer: Pointer to hold phyerr + * + * Return: 0 for success or error code + */ +QDF_STATUS extract_comb_phyerr_non_tlv(wmi_unified_t wmi_handle, void *evt_buf, + uint16_t datalen, uint16_t *buf_offset, + wmi_host_phyerr_t *phyerr) +{ + wmi_comb_phyerr_rx_event *pe; +#if ATH_PHYERR_DEBUG + int i; +#endif /* ATH_PHYERR_DEBUG */ + uint8_t *data; + + data = (uint8_t *) evt_buf; + +#if ATH_PHYERR_DEBUG + qdf_print("%s: data=%p, datalen=%d\n", __func__, data, datalen); + /* XXX for now */ + + for (i = 0; i < datalen; i++) { + qdf_print("%02X ", data[i]); + if (i % 32 == 31) + qdf_print("\n"); + } + qdf_print("\n"); +#endif /* ATH_PHYERR_DEBUG */ + + /* Ensure it's at least the size of the header */ + if (datalen < sizeof(*pe)) { + return QDF_STATUS_E_FAILURE; + /* XXX what should errors be? */ + } + + pe = (wmi_comb_phyerr_rx_event *) data; +#if ATH_PHYERR_DEBUG + qdf_print("%s: pe->hdr.num_phyerr_events=%d\n", + __func__, + pe->hdr.num_phyerr_events); +#endif /* ATH_PHYERR_DEBUG */ + + /* + * Reconstruct the 64 bit event TSF. This isn't from the MAC, it's + * at the time the event was sent to us, the TSF value will be + * in the future. + */ + phyerr->tsf64 = pe->hdr.tsf_l32; + phyerr->tsf64 |= (((uint64_t) pe->hdr.tsf_u32) << 32); + + *buf_offset = sizeof(pe->hdr); + return QDF_STATUS_SUCCESS; +} + +/** + * extract_single_phyerr_non_tlv() - extract single phy error from event + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * @param datalen: data length of event buffer + * @param buf_offset: Pointer to hold value of current event buffer offset + * post extraction + * @param phyerr: Pointer to hold phyerr + * + * Return: 0 for success or error code + */ +QDF_STATUS extract_single_phyerr_non_tlv(wmi_unified_t wmi_handle, + void *evt_buf, + uint16_t datalen, uint16_t *buf_offset, + wmi_host_phyerr_t *phyerr) +{ + wmi_single_phyerr_rx_event *ev; +#if ATH_PHYERR_DEBUG + int i; +#endif /* ATH_PHYERR_DEBUG */ + int n = 0; + uint8_t *data; + + n = (int) *buf_offset; + data = (uint8_t *) evt_buf; + + /* Loop over the bufp, extracting out phyerrors */ + /* + * XXX wmi_unified_comb_phyerr_rx_event.bufp is a char pointer, + * which isn't correct here - what we have received here + * is an array of TLV-style PHY errors. + */ + if (n < datalen) { + /* ensure there's at least space for the header */ + if ((datalen - n) < sizeof(ev->hdr)) { + qdf_print( + "%s: not enough space? (datalen=%d, n=%d, hdr=%d bytes\n", + __func__, + datalen, + n, + sizeof(ev->hdr)); + return QDF_STATUS_SUCCESS; + } + + /* + * Obtain a pointer to the beginning of the current event. + * data[0] is the beginning of the WMI payload. + */ + ev = (wmi_single_phyerr_rx_event *) &data[n]; + + /* + * Sanity check the buffer length of the event against + * what we currently have. + * + * Since buf_len is 32 bits, we check if it overflows + * a large 32 bit value. It's not 0x7fffffff because + * we increase n by (buf_len + sizeof(hdr)), which would + * in itself cause n to overflow. + * + * If "int" is 64 bits then this becomes a moot point. + */ + if (ev->hdr.buf_len > 0x7f000000) { + qdf_print("%s: buf_len is garbage? (0x%x\n)\n", + __func__, + ev->hdr.buf_len); + return QDF_STATUS_SUCCESS; + } + if (n + ev->hdr.buf_len > datalen) { + qdf_print("%s: buf_len exceeds available space " + "(n=%d, buf_len=%d, datalen=%d\n", + __func__, + n, + ev->hdr.buf_len, + datalen); + return QDF_STATUS_SUCCESS; + } + + phyerr->phy_err_code = WMI_UNIFIED_PHYERRCODE_GET(&ev->hdr); + +#if ATH_PHYERR_DEBUG + qdf_print("%s: len=%d, tsf=0x%08x, rssi = 0x%x/0x%x/0x%x/0x%x, " + "comb rssi = 0x%x, phycode=%d\n", + __func__, + ev->hdr.buf_len, + ev->hdr.tsf_timestamp, + ev->hdr.rssi_chain0, + ev->hdr.rssi_chain1, + ev->hdr.rssi_chain2, + ev->hdr.rssi_chain3, + WMI_UNIFIED_RSSI_COMB_GET(&ev->hdr), + phyerr->phy_err_code); + + /* + * For now, unroll this loop - the chain 'value' field isn't + * a variable but glued together into a macro field definition. + * Grr. :-) + */ + qdf_print( + "%s: chain 0: raw=0x%08x; pri20=%d sec20=%d sec40=%d sec80=%d\n", + __func__, + ev->hdr.rssi_chain0, + WMI_UNIFIED_RSSI_CHAN_GET(&ev->hdr, 0, PRI20), + WMI_UNIFIED_RSSI_CHAN_GET(&ev->hdr, 0, SEC20), + WMI_UNIFIED_RSSI_CHAN_GET(&ev->hdr, 0, SEC40), + WMI_UNIFIED_RSSI_CHAN_GET(&ev->hdr, 0, SEC80)); + + qdf_print( + "%s: chain 1: raw=0x%08x: pri20=%d sec20=%d sec40=%d sec80=%d\n", + __func__, + ev->hdr.rssi_chain1, + WMI_UNIFIED_RSSI_CHAN_GET(&ev->hdr, 1, PRI20), + WMI_UNIFIED_RSSI_CHAN_GET(&ev->hdr, 1, SEC20), + WMI_UNIFIED_RSSI_CHAN_GET(&ev->hdr, 1, SEC40), + WMI_UNIFIED_RSSI_CHAN_GET(&ev->hdr, 1, SEC80)); + + qdf_print( + "%s: chain 2: raw=0x%08x: pri20=%d sec20=%d sec40=%d sec80=%d\n", + __func__, + ev->hdr.rssi_chain2, + WMI_UNIFIED_RSSI_CHAN_GET(&ev->hdr, 2, PRI20), + WMI_UNIFIED_RSSI_CHAN_GET(&ev->hdr, 2, SEC20), + WMI_UNIFIED_RSSI_CHAN_GET(&ev->hdr, 2, SEC40), + WMI_UNIFIED_RSSI_CHAN_GET(&ev->hdr, 2, SEC80)); + + qdf_print( + "%s: chain 3: raw=0x%08x: pri20=%d sec20=%d sec40=%d sec80=%d\n", + __func__, + ev->hdr.rssi_chain3, + WMI_UNIFIED_RSSI_CHAN_GET(&ev->hdr, 3, PRI20), + WMI_UNIFIED_RSSI_CHAN_GET(&ev->hdr, 3, SEC20), + WMI_UNIFIED_RSSI_CHAN_GET(&ev->hdr, 3, SEC40), + WMI_UNIFIED_RSSI_CHAN_GET(&ev->hdr, 3, SEC80)); + + + qdf_print( + "%s: freq_info_1=0x%08x, freq_info_2=0x%08x\n", + __func__, ev->hdr.freq_info_1, ev->hdr.freq_info_2); + + /* + * The NF chain values are signed and are negative - hence + * the cast evilness. + */ + qdf_print( + "%s: nfval[1]=0x%08x, nfval[2]=0x%08x, nf=%d/%d/%d/%d, " + "freq1=%d, freq2=%d, cw=%d\n", + __func__, + ev->hdr.nf_list_1, + ev->hdr.nf_list_2, + (int) WMI_UNIFIED_NF_CHAIN_GET(&ev->hdr, 0), + (int) WMI_UNIFIED_NF_CHAIN_GET(&ev->hdr, 1), + (int) WMI_UNIFIED_NF_CHAIN_GET(&ev->hdr, 2), + (int) WMI_UNIFIED_NF_CHAIN_GET(&ev->hdr, 3), + WMI_UNIFIED_FREQ_INFO_GET(&ev->hdr, 1), + WMI_UNIFIED_FREQ_INFO_GET(&ev->hdr, 2), + WMI_UNIFIED_CHWIDTH_GET(&ev->hdr)); +#endif /* ATH_PHYERR_DEBUG */ + +#if ATH_SUPPORT_DFS + /* + * If required, pass radar events to the dfs pattern matching + * code. + * + * Don't pass radar events with no buffer payload. + */ + phyerr->tsf_timestamp = ev->hdr.tsf_timestamp; + phyerr->bufp = &ev->bufp[0]; + phyerr->buf_len = ev->hdr.buf_len; +#endif /* ATH_SUPPORT_DFS */ + +#if ATH_SUPPORT_SPECTRAL + + /* + * If required, pass spectral events to the spectral module + * + */ + if (phyerr->phy_err_code == WMI_HOST_PHY_ERROR_FALSE_RADAR_EXT + || phyerr->phy_err_code == WMI_HOST_PHY_ERROR_SPECTRAL_SCAN) { + if (ev->hdr.buf_len > 0) { + + /* Initialize the NF values to Zero. */ + phyerr->rf_info.noise_floor[0] = + WMI_UNIFIED_NF_CHAIN_GET(&ev->hdr, 0); + phyerr->rf_info.noise_floor[1] = + WMI_UNIFIED_NF_CHAIN_GET(&ev->hdr, 1); + phyerr->rf_info.noise_floor[2] = + WMI_UNIFIED_NF_CHAIN_GET(&ev->hdr, 2); + phyerr->rf_info.noise_floor[3] = + WMI_UNIFIED_NF_CHAIN_GET(&ev->hdr, 3); + + /* populate the rf info */ + phyerr->rf_info.rssi_comb = + WMI_UNIFIED_RSSI_COMB_GET(&ev->hdr); + + /* Need to unroll loop due to macro + * constraints + * chain 0 */ + phyerr->rf_info.pc_rssi_info[0].rssi_pri20 = + WMI_UNIFIED_RSSI_CHAN_GET(&ev->hdr, 0, PRI20); + phyerr->rf_info.pc_rssi_info[0].rssi_sec20 = + WMI_UNIFIED_RSSI_CHAN_GET(&ev->hdr, 0, SEC20); + phyerr->rf_info.pc_rssi_info[0].rssi_sec40 = + WMI_UNIFIED_RSSI_CHAN_GET(&ev->hdr, 0, SEC40); + phyerr->rf_info.pc_rssi_info[0].rssi_sec80 = + WMI_UNIFIED_RSSI_CHAN_GET(&ev->hdr, 0, SEC80); + + /* chain 1 */ + phyerr->rf_info.pc_rssi_info[1].rssi_pri20 = + WMI_UNIFIED_RSSI_CHAN_GET(&ev->hdr, 1, PRI20); + phyerr->rf_info.pc_rssi_info[1].rssi_sec20 = + WMI_UNIFIED_RSSI_CHAN_GET(&ev->hdr, 1, SEC20); + phyerr->rf_info.pc_rssi_info[1].rssi_sec40 = + WMI_UNIFIED_RSSI_CHAN_GET(&ev->hdr, 1, SEC40); + phyerr->rf_info.pc_rssi_info[1].rssi_sec80 = + WMI_UNIFIED_RSSI_CHAN_GET(&ev->hdr, 1, SEC80); + + /* chain 2 */ + phyerr->rf_info.pc_rssi_info[2].rssi_pri20 = + WMI_UNIFIED_RSSI_CHAN_GET(&ev->hdr, 2, PRI20); + phyerr->rf_info.pc_rssi_info[2].rssi_sec20 = + WMI_UNIFIED_RSSI_CHAN_GET(&ev->hdr, 2, SEC20); + phyerr->rf_info.pc_rssi_info[2].rssi_sec40 = + WMI_UNIFIED_RSSI_CHAN_GET(&ev->hdr, 2, SEC40); + phyerr->rf_info.pc_rssi_info[2].rssi_sec80 = + WMI_UNIFIED_RSSI_CHAN_GET(&ev->hdr, 2, SEC80); + + /* chain 3 */ + phyerr->rf_info.pc_rssi_info[3].rssi_pri20 = + WMI_UNIFIED_RSSI_CHAN_GET(&ev->hdr, 3, PRI20); + phyerr->rf_info.pc_rssi_info[3].rssi_sec20 = + WMI_UNIFIED_RSSI_CHAN_GET(&ev->hdr, 3, SEC20); + phyerr->rf_info.pc_rssi_info[3].rssi_sec40 = + WMI_UNIFIED_RSSI_CHAN_GET(&ev->hdr, 3, SEC40); + phyerr->rf_info.pc_rssi_info[3].rssi_sec80 = + WMI_UNIFIED_RSSI_CHAN_GET(&ev->hdr, 3, SEC80); + + phyerr->chan_info.center_freq1 = + WMI_UNIFIED_FREQ_INFO_GET(&ev->hdr, 1); + phyerr->chan_info.center_freq2 = + WMI_UNIFIED_FREQ_INFO_GET(&ev->hdr, 2); + + } + } +#endif /* ATH_SUPPORT_SPECTRAL */ + + /* + * Advance the buffer pointer to the next PHY error. + * buflen is the length of this payload, so we need to + * advance past the current header _AND_ the payload. + */ + n += sizeof(*ev) + ev->hdr.buf_len; + } + *buf_offset = n; + + return QDF_STATUS_SUCCESS; +} + +/** + * extract_composite_phyerr_non_tlv() - extract composite phy error from event + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * @param datalen: Length of event buffer + * @param phyerr: Pointer to hold phy error + * + * Return: 0 for success or error code + */ +QDF_STATUS extract_composite_phyerr_non_tlv(wmi_unified_t wmi_handle, + void *evt_buf, + uint16_t datalen, wmi_host_phyerr_t *phyerr) +{ + wmi_composite_phyerr_rx_event *pe; + wmi_composite_phyerr_rx_hdr *ph; + + /* Ensure it's at least the size of the header */ + if (datalen < sizeof(*pe)) { + return QDF_STATUS_E_FAILURE; + /* XXX what should errors be? */ + } + + pe = (wmi_composite_phyerr_rx_event *) evt_buf; + ph = &pe->hdr; + + /* + * Reconstruct the 64 bit event TSF. This isn't from the MAC, it's + * at the time the event was sent to us, the TSF value will be + * in the future. + */ + phyerr->tsf64 = ph->tsf_l32; + phyerr->tsf64 |= (((uint64_t) ph->tsf_u32) << 32); + + phyerr->tsf_timestamp = ph->tsf_timestamp; + phyerr->bufp = &pe->bufp[0]; + phyerr->buf_len = ph->buf_len; + + phyerr->phy_err_mask0 = ph->phy_err_mask0; + phyerr->phy_err_mask1 = ph->phy_err_mask1; + + /* Handle Spectral PHY Error */ + if ((ph->phy_err_mask0 & WMI_HOST_AR900B_SPECTRAL_PHYERR_MASK)) { +#if ATH_SUPPORT_SPECTRAL + if (ph->buf_len > 0) { + + /* Initialize the NF values to Zero. */ + phyerr->rf_info.noise_floor[0] = + WMI_UNIFIED_NF_CHAIN_GET(ph, 0); + phyerr->rf_info.noise_floor[1] = + WMI_UNIFIED_NF_CHAIN_GET(ph, 1); + phyerr->rf_info.noise_floor[2] = + WMI_UNIFIED_NF_CHAIN_GET(ph, 2); + phyerr->rf_info.noise_floor[3] = + WMI_UNIFIED_NF_CHAIN_GET(ph, 3); + + /* populate the rf info */ + phyerr->rf_info.rssi_comb = + WMI_UNIFIED_RSSI_COMB_GET(ph); + + /* Need to unroll loop due to macro constraints */ + /* chain 0 */ + phyerr->rf_info.pc_rssi_info[0].rssi_pri20 = + WMI_UNIFIED_RSSI_CHAN_GET(ph, 0, PRI20); + phyerr->rf_info.pc_rssi_info[0].rssi_sec20 = + WMI_UNIFIED_RSSI_CHAN_GET(ph, 0, SEC20); + phyerr->rf_info.pc_rssi_info[0].rssi_sec40 = + WMI_UNIFIED_RSSI_CHAN_GET(ph, 0, SEC40); + phyerr->rf_info.pc_rssi_info[0].rssi_sec80 = + WMI_UNIFIED_RSSI_CHAN_GET(ph, 0, SEC80); + + /* chain 1 */ + phyerr->rf_info.pc_rssi_info[1].rssi_pri20 = + WMI_UNIFIED_RSSI_CHAN_GET(ph, 1, PRI20); + phyerr->rf_info.pc_rssi_info[1].rssi_sec20 = + WMI_UNIFIED_RSSI_CHAN_GET(ph, 1, SEC20); + phyerr->rf_info.pc_rssi_info[1].rssi_sec40 = + WMI_UNIFIED_RSSI_CHAN_GET(ph, 1, SEC40); + phyerr->rf_info.pc_rssi_info[1].rssi_sec80 = + WMI_UNIFIED_RSSI_CHAN_GET(ph, 1, SEC80); + + /* chain 2 */ + phyerr->rf_info.pc_rssi_info[2].rssi_pri20 = + WMI_UNIFIED_RSSI_CHAN_GET(ph, 2, PRI20); + phyerr->rf_info.pc_rssi_info[2].rssi_sec20 = + WMI_UNIFIED_RSSI_CHAN_GET(ph, 2, SEC20); + phyerr->rf_info.pc_rssi_info[2].rssi_sec40 = + WMI_UNIFIED_RSSI_CHAN_GET(ph, 2, SEC40); + phyerr->rf_info.pc_rssi_info[2].rssi_sec80 = + WMI_UNIFIED_RSSI_CHAN_GET(ph, 2, SEC80); + + /* chain 3 */ + phyerr->rf_info.pc_rssi_info[3].rssi_pri20 = + WMI_UNIFIED_RSSI_CHAN_GET(ph, 3, PRI20); + phyerr->rf_info.pc_rssi_info[3].rssi_sec20 = + WMI_UNIFIED_RSSI_CHAN_GET(ph, 3, SEC20); + phyerr->rf_info.pc_rssi_info[3].rssi_sec40 = + WMI_UNIFIED_RSSI_CHAN_GET(ph, 3, SEC40); + phyerr->rf_info.pc_rssi_info[3].rssi_sec80 = + WMI_UNIFIED_RSSI_CHAN_GET(ph, 3, SEC80); + + phyerr->chan_info.center_freq1 = + WMI_UNIFIED_FREQ_INFO_GET(ph, 1); + phyerr->chan_info.center_freq2 = + WMI_UNIFIED_FREQ_INFO_GET(ph, 2); + + } +#endif /* ATH_SUPPORT_SPECTRAL */ + + } + return QDF_STATUS_SUCCESS; +} + +/** + * extract_all_stats_counts_non_tlv() - extract all stats count from event + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * @param stats_param: Pointer to hold stats count + * + * Return: 0 for success or error code + */ +static QDF_STATUS extract_all_stats_counts_non_tlv(wmi_unified_t wmi_handle, + void *evt_buf, + wmi_host_stats_event *stats_param) +{ + wmi_stats_event *ev = (wmi_stats_event *) evt_buf; + + switch (ev->stats_id) { + case WMI_REQUEST_PEER_STAT: + stats_param->stats_id |= WMI_HOST_REQUEST_PEER_STAT; + break; + + case WMI_REQUEST_AP_STAT: + stats_param->stats_id |= WMI_HOST_REQUEST_AP_STAT; + break; + + case WMI_REQUEST_INST_STAT: + stats_param->stats_id |= WMI_HOST_REQUEST_INST_STAT; + break; + + case WMI_REQUEST_PEER_EXTD_STAT: + stats_param->stats_id |= WMI_HOST_REQUEST_PEER_EXTD_STAT; + break; + + case WMI_REQUEST_VDEV_EXTD_STAT: + stats_param->stats_id |= WMI_HOST_REQUEST_VDEV_EXTD_STAT; + break; + + default: + stats_param->stats_id = 0; + break; + + } + stats_param->num_pdev_stats = ev->num_pdev_stats; + stats_param->num_pdev_ext_stats = ev->num_pdev_ext_stats; + stats_param->num_vdev_stats = ev->num_vdev_stats; + stats_param->num_peer_stats = ev->num_peer_stats; + stats_param->num_bcnflt_stats = ev->num_bcnflt_stats; + stats_param->num_chan_stats = 0; + + return QDF_STATUS_SUCCESS; +} + +/** + * extract_pdev_stats_non_tlv() - extract pdev stats from event + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * @param index: Index into pdev stats + * @param pdev_stats: Pointer to hold pdev stats + * + * Return: 0 for success or error code + */ +static QDF_STATUS extract_pdev_stats_non_tlv(wmi_unified_t wmi_handle, + void *evt_buf, + uint32_t index, wmi_host_pdev_stats *pdev_stats) +{ + if (index < ((wmi_stats_event *)evt_buf)->num_pdev_stats) { + + wmi_pdev_stats *ev = + (wmi_pdev_stats *) ((((wmi_stats_event *)evt_buf)->data) + + (index * sizeof(wmi_pdev_stats))); + + /* direct copy possible since wmi_host_pdev_stats is same as + * wmi_pdev_stats for non-tlv */ + /* qdf_mem_copy(pdev_stats, ev, sizeof(wmi_pdev_stats));*/ + + pdev_stats->chan_nf = ev->chan_nf; + pdev_stats->tx_frame_count = ev->tx_frame_count; + pdev_stats->rx_frame_count = ev->rx_frame_count; + pdev_stats->rx_clear_count = ev->rx_clear_count; + pdev_stats->cycle_count = ev->cycle_count; + pdev_stats->phy_err_count = ev->phy_err_count; + pdev_stats->chan_tx_pwr = ev->chan_tx_pwr; + +#define tx_stats (pdev_stats->pdev_stats.tx) +#define ev_tx_stats (ev->pdev_stats.tx) + + /* Tx Stats */ + tx_stats.comp_queued = ev_tx_stats.comp_queued; + tx_stats.comp_delivered = ev_tx_stats.comp_delivered; + tx_stats.msdu_enqued = ev_tx_stats.msdu_enqued; + tx_stats.mpdu_enqued = ev_tx_stats.mpdu_enqued; + tx_stats.wmm_drop = ev_tx_stats.wmm_drop; + tx_stats.local_enqued = ev_tx_stats.local_enqued; + tx_stats.local_freed = ev_tx_stats.local_freed; + tx_stats.hw_queued = ev_tx_stats.hw_queued; + tx_stats.hw_reaped = ev_tx_stats.hw_reaped; + tx_stats.underrun = ev_tx_stats.underrun; + tx_stats.hw_paused = ev_tx_stats.hw_paused; + tx_stats.tx_abort = ev_tx_stats.tx_abort; + tx_stats.mpdus_requed = ev_tx_stats.mpdus_requed; + tx_stats.tx_xretry = ev_tx_stats.tx_xretry; + tx_stats.data_rc = ev_tx_stats.data_rc; + tx_stats.self_triggers = ev_tx_stats.self_triggers; + tx_stats.sw_retry_failure = ev_tx_stats.sw_retry_failure; + tx_stats.illgl_rate_phy_err = ev_tx_stats.illgl_rate_phy_err; + tx_stats.pdev_cont_xretry = ev_tx_stats.pdev_cont_xretry; + tx_stats.pdev_tx_timeout = ev_tx_stats.pdev_tx_timeout; + tx_stats.pdev_resets = ev_tx_stats.pdev_resets; + tx_stats.stateless_tid_alloc_failure = + ev_tx_stats.stateless_tid_alloc_failure; + tx_stats.phy_underrun = ev_tx_stats.phy_underrun; + tx_stats.txop_ovf = ev_tx_stats.txop_ovf; + tx_stats.seq_posted = ev_tx_stats.seq_posted; + tx_stats.seq_failed_queueing = ev_tx_stats.seq_failed_queueing; + tx_stats.seq_completed = ev_tx_stats.seq_completed; + tx_stats.seq_restarted = ev_tx_stats.seq_restarted; + tx_stats.mu_seq_posted = ev_tx_stats.mu_seq_posted; + tx_stats.mpdus_sw_flush = ev_tx_stats.mpdus_sw_flush; + tx_stats.mpdus_hw_filter = ev_tx_stats.mpdus_hw_filter; + tx_stats.mpdus_truncated = ev_tx_stats.mpdus_truncated; + tx_stats.mpdus_ack_failed = ev_tx_stats.mpdus_ack_failed; + tx_stats.mpdus_expired = ev_tx_stats.mpdus_expired; + /* Only NON-TLV */ + tx_stats.mc_drop = ev_tx_stats.mc_drop; + /* Only TLV */ + tx_stats.tx_ko = 0; + +#define rx_stats (pdev_stats->pdev_stats.rx) +#define ev_rx_stats (ev->pdev_stats.rx) + + /* Rx Stats */ + rx_stats.mid_ppdu_route_change = + ev_rx_stats.mid_ppdu_route_change; + rx_stats.status_rcvd = ev_rx_stats.status_rcvd; + rx_stats.r0_frags = ev_rx_stats.r0_frags; + rx_stats.r1_frags = ev_rx_stats.r1_frags; + rx_stats.r2_frags = ev_rx_stats.r2_frags; + /* Only TLV */ + rx_stats.r3_frags = 0; + rx_stats.htt_msdus = ev_rx_stats.htt_msdus; + rx_stats.htt_mpdus = ev_rx_stats.htt_mpdus; + rx_stats.loc_msdus = ev_rx_stats.loc_msdus; + rx_stats.loc_mpdus = ev_rx_stats.loc_mpdus; + rx_stats.oversize_amsdu = ev_rx_stats.oversize_amsdu; + rx_stats.phy_errs = ev_rx_stats.phy_errs; + rx_stats.phy_err_drop = ev_rx_stats.phy_err_drop; + rx_stats.mpdu_errs = ev_rx_stats.mpdu_errs; + rx_stats.pdev_rx_timeout = ev_rx_stats.pdev_rx_timeout; + rx_stats.rx_ovfl_errs = ev_rx_stats.rx_ovfl_errs; + + /* mem stats */ + pdev_stats->pdev_stats.mem.iram_free_size = + ev->pdev_stats.mem.iram_free_size; + pdev_stats->pdev_stats.mem.dram_free_size = + ev->pdev_stats.mem.dram_free_size; + /* Only Non-TLV */ + pdev_stats->pdev_stats.mem.sram_free_size = + ev->pdev_stats.mem.sram_free_size; + + /* Peer stats */ + /* Only TLV */ + pdev_stats->pdev_stats.peer.dummy = 0; + /* Only NON-TLV */ + pdev_stats->ackRcvBad = ev->ackRcvBad; + pdev_stats->rtsBad = ev->rtsBad; + pdev_stats->rtsGood = ev->rtsGood; + pdev_stats->fcsBad = ev->fcsBad; + pdev_stats->noBeacons = ev->noBeacons; + pdev_stats->mib_int_count = ev->mib_int_count; + + } + return QDF_STATUS_SUCCESS; +} + +/** + * extract_pdev_ext_stats_non_tlv() - extract extended pdev stats from event + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * @param index: Index into extended pdev stats + * @param pdev_ext_stats: Pointer to hold extended pdev stats + * + * Return: 0 for success or error code + */ +static QDF_STATUS extract_pdev_ext_stats_non_tlv(wmi_unified_t wmi_handle, + void *evt_buf, + uint32_t index, wmi_host_pdev_ext_stats *pdev_ext_stats) +{ + if (index < ((wmi_stats_event *)evt_buf)->num_pdev_ext_stats) { + wmi_pdev_ext_stats *ev = + (wmi_pdev_ext_stats *) ((((wmi_stats_event *)evt_buf)->data) + + ((((wmi_stats_event *)evt_buf)->num_pdev_stats) * + sizeof(wmi_pdev_stats)) + + (index * sizeof(wmi_pdev_ext_stats))); + /* Copy content to event->data */ + OS_MEMCPY(pdev_ext_stats, ev, sizeof(wmi_pdev_ext_stats)); + + } + return QDF_STATUS_SUCCESS; +} + +/** + * extract_vdev_stats_non_tlv() - extract vdev stats from event + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * @param index: Index into vdev stats + * @param vdev_stats: Pointer to hold vdev stats + * + * Return: 0 for success or error code + */ + +static QDF_STATUS extract_vdev_stats_non_tlv(wmi_unified_t wmi_handle, + void *evt_buf, uint32_t index, wmi_host_vdev_stats *vdev_stats) +{ + if (index < ((wmi_stats_event *)evt_buf)->num_vdev_stats) { + wmi_vdev_stats *ev = + (wmi_vdev_stats *) ((((wmi_stats_event *)evt_buf)->data) + + ((((wmi_stats_event *)evt_buf)->num_pdev_stats) * + sizeof(wmi_pdev_stats)) + + ((((wmi_stats_event *)evt_buf)->num_pdev_ext_stats) * + sizeof(wmi_pdev_ext_stats)) + + (index * sizeof(wmi_vdev_stats))); + + OS_MEMSET(vdev_stats, 0, sizeof(wmi_host_vdev_stats)); + vdev_stats->vdev_id = ev->vdev_id; + + } + return QDF_STATUS_SUCCESS; +} + +/** + * extract_peer_stats_non_tlv() - extract peer stats from event + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * @param index: Index into peer stats + * @param peer_stats: Pointer to hold peer stats + * + * Return: 0 for success or error code + */ +static QDF_STATUS extract_peer_stats_non_tlv(wmi_unified_t wmi_handle, + void *evt_buf, uint32_t index, wmi_host_peer_stats *peer_stats) +{ + if (index < ((wmi_stats_event *)evt_buf)->num_peer_stats) { + wmi_peer_stats *ev = + (wmi_peer_stats *) ((((wmi_stats_event *)evt_buf)->data) + + ((((wmi_stats_event *)evt_buf)->num_pdev_stats) * + sizeof(wmi_pdev_stats)) + + ((((wmi_stats_event *)evt_buf)->num_pdev_ext_stats) * + sizeof(wmi_pdev_ext_stats)) + + ((((wmi_stats_event *)evt_buf)->num_vdev_stats) * + sizeof(wmi_vdev_stats)) + + (index * sizeof(wmi_peer_stats))); + + OS_MEMCPY(&(peer_stats->peer_macaddr), &(ev->peer_macaddr), + sizeof(wmi_mac_addr)); + + peer_stats->peer_rssi = ev->peer_rssi; + peer_stats->peer_rssi_seq_num = ev->peer_rssi_seq_num; + peer_stats->peer_tx_rate = ev->peer_tx_rate; + peer_stats->peer_rx_rate = ev->peer_rx_rate; + peer_stats->currentper = ev->currentper; + peer_stats->retries = ev->retries; + peer_stats->txratecount = ev->txratecount; + peer_stats->max4msframelen = ev->max4msframelen; + peer_stats->totalsubframes = ev->totalsubframes; + peer_stats->txbytes = ev->txbytes; + + OS_MEMCPY(peer_stats->nobuffs, ev->nobuffs, + sizeof(peer_stats->nobuffs)); + OS_MEMCPY(peer_stats->excretries, ev->excretries, + sizeof(peer_stats->excretries)); + peer_stats->peer_rssi_changed = ev->peer_rssi_changed; + } + return QDF_STATUS_SUCCESS; +} + +/** + * extract_bcnflt_stats_non_tlv() - extract bcn fault stats from event + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * @param index: Index into bcn fault stats + * @param bcnflt_stats: Pointer to hold bcn fault stats + * + * Return: 0 for success or error code + */ +static QDF_STATUS extract_bcnflt_stats_non_tlv(wmi_unified_t wmi_handle, + void *evt_buf, uint32_t index, wmi_host_bcnflt_stats *bcnflt_stats) +{ + return QDF_STATUS_SUCCESS; +} + +/** + * extract_peer_extd_stats_non_tlv() - extract extended peer stats from event + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * @param index: Index into extended peer stats + * @param peer_extd_stats: Pointer to hold extended peer stats + * + * Return: 0 for success or error code + */ +static QDF_STATUS extract_peer_extd_stats_non_tlv(wmi_unified_t wmi_handle, + void *evt_buf, uint32_t index, + wmi_host_peer_extd_stats *peer_extd_stats) +{ + if (WMI_REQUEST_PEER_EXTD_STAT & + ((wmi_stats_event *)evt_buf)->stats_id) { + if (index < ((wmi_stats_event *)evt_buf)->num_peer_stats) { + wmi_peer_extd_stats *ev = (wmi_peer_extd_stats *) + ((((wmi_stats_event *)evt_buf)->data) + + ((((wmi_stats_event *)evt_buf)->num_pdev_stats) * + sizeof(wmi_pdev_stats)) + + ((((wmi_stats_event *)evt_buf)->num_pdev_ext_stats) * + sizeof(wmi_pdev_ext_stats)) + + ((((wmi_stats_event *)evt_buf)->num_vdev_stats) * + sizeof(wmi_vdev_stats)) + + ((((wmi_stats_event *)evt_buf)->num_peer_stats) * + sizeof(wmi_peer_stats)) + + (index * sizeof(wmi_peer_extd_stats))); + + OS_MEMCPY(peer_extd_stats, ev, + sizeof(wmi_host_peer_extd_stats)); + } + } + return QDF_STATUS_SUCCESS; +} + +/** + * extract_vdev_extd_stats_non_tlv() - extract extended vdev stats from event + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * @param index: Index into extended vdev stats + * @param vdev_extd_stats: Pointer to hold extended vdev stats + * + * Return: 0 for success or error code + */ +static QDF_STATUS extract_vdev_extd_stats_non_tlv(wmi_unified_t wmi_handle, + void *evt_buf, uint32_t index, + wmi_host_vdev_extd_stats *vdev_extd_stats) +{ + if (WMI_REQUEST_PEER_EXTD_STAT & + ((wmi_stats_event *)evt_buf)->stats_id) { + + if (index < ((wmi_stats_event *)evt_buf)->num_vdev_stats) { + + wmi_vdev_extd_stats *ev = (wmi_vdev_extd_stats *) + ((((wmi_stats_event *)evt_buf)->data) + + ((((wmi_stats_event *)evt_buf)->num_pdev_stats) * + sizeof(wmi_pdev_stats)) + + ((((wmi_stats_event *)evt_buf)->num_pdev_ext_stats) * + sizeof(wmi_pdev_ext_stats)) + + ((((wmi_stats_event *)evt_buf)->num_vdev_stats) * + sizeof(wmi_vdev_stats)) + + ((((wmi_stats_event *)evt_buf)->num_peer_stats) * + sizeof(wmi_peer_stats)) + + ((((wmi_stats_event *)evt_buf)->num_peer_stats) * + sizeof(wmi_peer_extd_stats)) + + (index * sizeof(wmi_vdev_extd_stats))); + + OS_MEMCPY(vdev_extd_stats, ev, + sizeof(wmi_host_vdev_extd_stats)); + } + } + return QDF_STATUS_SUCCESS; +} + +/** + * extract_chan_stats_non_tlv() - extract chan stats from event + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * @param index: Index into chan stats + * @param vdev_extd_stats: Pointer to hold chan stats + * + * Return: 0 for success or error code + */ +static QDF_STATUS extract_chan_stats_non_tlv(wmi_unified_t wmi_handle, + void *evt_buf, + uint32_t index, wmi_host_chan_stats *chan_stats) +{ + /* Non-TLV doesnt have num_chan_stats */ + return QDF_STATUS_SUCCESS; +} + +/** + * extract_profile_ctx_non_tlv() - extract profile context from event + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * @param profile_ctx: Pointer to hold profile context + * + * Return: 0 for success or error code + */ +static QDF_STATUS extract_profile_ctx_non_tlv(wmi_unified_t wmi_handle, + void *evt_buf, + wmi_host_wlan_profile_ctx_t *profile_ctx) +{ + wmi_profile_stats_event *profile_ev = + (wmi_profile_stats_event *)evt_buf; + + qdf_mem_copy(profile_ctx, &(profile_ev->profile_ctx), + sizeof(wmi_host_wlan_profile_ctx_t)); + + return QDF_STATUS_SUCCESS; +} + +/** + * extract_profile_data_non_tlv() - extract profile data from event + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * @param profile_data: Pointer to hold profile data + * + * Return: 0 for success or error code + */ +static QDF_STATUS extract_profile_data_non_tlv(wmi_unified_t wmi_handle, + void *evt_buf, uint8_t idx, + wmi_host_wlan_profile_t *profile_data) +{ + wmi_profile_stats_event *profile_ev = + (wmi_profile_stats_event *)evt_buf; + + if (idx > profile_ev->profile_ctx.bin_count) + return QDF_STATUS_E_INVAL; + + qdf_mem_copy(profile_data, &profile_ev->profile_data[idx], + sizeof(wmi_host_wlan_profile_t)); + + return QDF_STATUS_SUCCESS; +} + +/** + * extract_chan_info_event_non_tlv() - extract chan information from event + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * @param chan_info: Pointer to hold chan information + * + * Return: 0 for success or error code + */ +static QDF_STATUS extract_chan_info_event_non_tlv(wmi_unified_t wmi_handle, + void *evt_buf, + wmi_host_chan_info_event *chan_info) +{ + wmi_chan_info_event *chan_info_ev = (wmi_chan_info_event *)evt_buf; + + chan_info->err_code = chan_info_ev->err_code; + chan_info->freq = chan_info_ev->freq; + chan_info->cmd_flags = chan_info_ev->cmd_flags; + chan_info->noise_floor = chan_info_ev->noise_floor; + chan_info->rx_clear_count = chan_info_ev->rx_clear_count; + chan_info->cycle_count = chan_info_ev->cycle_count; + chan_info->rx_11b_mode_data_duration = + chan_info_ev->rx_11b_mode_data_duration; + /* ONLY NON-TLV */ + chan_info->chan_tx_pwr_range = chan_info_ev->chan_tx_pwr_range; + chan_info->chan_tx_pwr_tp = chan_info_ev->chan_tx_pwr_tp; + chan_info->rx_frame_count = chan_info_ev->rx_frame_count; + + return QDF_STATUS_SUCCESS; +} + +/** + * extract_channel_hopping_event_non_tlv() - extract channel hopping param + * from event + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * @param ch_hopping: Pointer to hold channel hopping param + * + * Return: 0 for success or error code + */ +static QDF_STATUS extract_channel_hopping_event_non_tlv( + wmi_unified_t wmi_handle, void *evt_buf, + wmi_host_pdev_channel_hopping_event *ch_hopping) +{ + wmi_pdev_channel_hopping_event *event = + (wmi_pdev_channel_hopping_event *)evt_buf; + + ch_hopping->noise_floor_report_iter = event->noise_floor_report_iter; + ch_hopping->noise_floor_total_iter = event->noise_floor_total_iter; + + return QDF_STATUS_SUCCESS; +} + +/** + * extract_bss_chan_info_event_non_tlv() - extract bss channel information + * from event + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * @param bss_chan_info: Pointer to hold bss channel information + * + * Return: 0 for success or error code + */ +static QDF_STATUS extract_bss_chan_info_event_non_tlv(wmi_unified_t wmi_handle, + void *evt_buf, wmi_host_pdev_bss_chan_info_event *bss_chan_info) +{ + wmi_pdev_bss_chan_info_event *event = + (wmi_pdev_bss_chan_info_event *)evt_buf; + + qdf_mem_copy(bss_chan_info, event, + sizeof(wmi_pdev_bss_chan_info_event)); + + return QDF_STATUS_SUCCESS; +} + +/** + * extract_inst_rssi_stats_event_non_tlv() - extract inst rssi stats from event + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * @param inst_rssi_resp: Pointer to hold inst rssi response + * + * Return: 0 for success or error code + */ +static QDF_STATUS extract_inst_rssi_stats_event_non_tlv( + wmi_unified_t wmi_handle, void *evt_buf, + wmi_host_inst_stats_resp *inst_rssi_resp) +{ + wmi_inst_stats_resp *event = (wmi_inst_stats_resp *)evt_buf; + + qdf_mem_copy(inst_rssi_resp, event, sizeof(wmi_inst_stats_resp)); + + return QDF_STATUS_SUCCESS; +} + +/** + * extract_tx_data_traffic_ctrl_ev_non_tlv() - extract tx data traffic control + * from event + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * @param index: Index into chan stats + * @param ev: Pointer to hold data traffic control + * + * Return: 0 for success or error code + */ +static QDF_STATUS extract_tx_data_traffic_ctrl_ev_non_tlv( + wmi_unified_t wmi_handle, void *evt_buf, + wmi_host_tx_data_traffic_ctrl_event *ev) +{ + wmi_tx_data_traffic_ctrl_event *evt = + (wmi_tx_data_traffic_ctrl_event *)evt_buf; + + ev->peer_ast_idx = evt->peer_ast_idx; + ev->vdev_id = evt->vdev_id; + ev->ctrl_cmd = evt->ctrl_cmd; + + return QDF_STATUS_SUCCESS; +} + +#ifdef WMI_INTERFACE_EVENT_LOGGING +static bool is_management_record_non_tlv(uint32_t cmd_id) +{ + if ((cmd_id == WMI_BCN_TX_CMDID) || + (cmd_id == WMI_PDEV_SEND_BCN_CMDID) || + (cmd_id == WMI_MGMT_TX_CMDID)) { + return true; + } + + return false; +} +#endif + +/** + * wmi_set_htc_tx_tag_non_tlv() - set HTC TX tag for WMI commands + * @wmi_handle: WMI handle + * @buf: WMI buffer + * @cmd_id: WMI command Id + * + * Return htc_tx_tag + */ +static uint16_t wmi_set_htc_tx_tag_non_tlv(wmi_unified_t wmi_handle, + wmi_buf_t buf, uint32_t cmd_id) +{ + return 0; +} + +struct wmi_ops non_tlv_ops = { + .send_vdev_create_cmd = send_vdev_create_cmd_non_tlv, + .send_vdev_delete_cmd = send_vdev_delete_cmd_non_tlv, + .send_vdev_down_cmd = send_vdev_down_cmd_non_tlv, + .send_peer_flush_tids_cmd = send_peer_flush_tids_cmd_non_tlv, + .send_peer_param_cmd = send_peer_param_cmd_non_tlv, + .send_vdev_up_cmd = send_vdev_up_cmd_non_tlv, + .send_peer_create_cmd = send_peer_create_cmd_non_tlv, + .send_peer_delete_cmd = send_peer_delete_cmd_non_tlv, + .send_green_ap_ps_cmd = send_green_ap_ps_cmd_non_tlv, + .send_pdev_utf_cmd = send_pdev_utf_cmd_non_tlv, + .send_pdev_param_cmd = send_pdev_param_cmd_non_tlv, + .send_suspend_cmd = send_suspend_cmd_non_tlv, + .send_resume_cmd = send_resume_cmd_non_tlv, + .send_wow_enable_cmd = send_wow_enable_cmd_non_tlv, + .send_set_ap_ps_param_cmd = send_set_ap_ps_param_cmd_non_tlv, + .send_set_sta_ps_param_cmd = send_set_sta_ps_param_cmd_non_tlv, + .send_crash_inject_cmd = send_crash_inject_cmd_non_tlv, + .send_dbglog_cmd = send_dbglog_cmd_non_tlv, + .send_vdev_set_param_cmd = send_vdev_set_param_cmd_non_tlv, + .send_stats_request_cmd = send_stats_request_cmd_non_tlv, + .send_packet_log_enable_cmd = send_packet_log_enable_cmd_non_tlv, + .send_packet_log_disable_cmd = send_packet_log_disable_cmd_non_tlv, + .send_beacon_send_cmd = send_beacon_send_cmd_non_tlv, + .send_peer_assoc_cmd = send_peer_assoc_cmd_non_tlv, + .send_scan_start_cmd = send_scan_start_cmd_non_tlv, + .send_scan_stop_cmd = send_scan_stop_cmd_non_tlv, + .send_scan_chan_list_cmd = send_scan_chan_list_cmd_non_tlv, + .send_pdev_get_tpc_config_cmd = send_pdev_get_tpc_config_cmd_non_tlv, + .send_set_atf_cmd = send_set_atf_cmd_non_tlv, + .send_set_bwf_cmd = send_set_bwf_cmd_non_tlv, + .send_pdev_fips_cmd = send_pdev_fips_cmd_non_tlv, + .send_wlan_profile_enable_cmd = send_wlan_profile_enable_cmd_non_tlv, + .send_wlan_profile_trigger_cmd = send_wlan_profile_trigger_cmd_non_tlv, + .send_pdev_set_chan_cmd = send_pdev_set_chan_cmd_non_tlv, + .send_set_ht_ie_cmd = send_set_ht_ie_cmd_non_tlv, + .send_set_vht_ie_cmd = send_set_vht_ie_cmd_non_tlv, + .send_wmm_update_cmd = send_wmm_update_cmd_non_tlv, + .send_set_ant_switch_tbl_cmd = send_set_ant_switch_tbl_cmd_non_tlv, + .send_set_ratepwr_table_cmd = send_set_ratepwr_table_cmd_non_tlv, + .send_get_ratepwr_table_cmd = send_get_ratepwr_table_cmd_non_tlv, + .send_set_ctl_table_cmd = send_set_ctl_table_cmd_non_tlv, + .send_set_mimogain_table_cmd = send_set_mimogain_table_cmd_non_tlv, + .send_set_ratepwr_chainmsk_cmd = send_set_ratepwr_chainmsk_cmd_non_tlv, + .send_set_macaddr_cmd = send_set_macaddr_cmd_non_tlv, + .send_pdev_scan_start_cmd = send_pdev_scan_start_cmd_non_tlv, + .send_pdev_scan_end_cmd = send_pdev_scan_end_cmd_non_tlv, + .send_set_acparams_cmd = send_set_acparams_cmd_non_tlv, + .send_set_vap_dscp_tid_map_cmd = send_set_vap_dscp_tid_map_cmd_non_tlv, + .send_proxy_ast_reserve_cmd = send_proxy_ast_reserve_cmd_non_tlv, + .send_pdev_qvit_cmd = send_pdev_qvit_cmd_non_tlv, + .send_mcast_group_update_cmd = send_mcast_group_update_cmd_non_tlv, + .send_peer_add_wds_entry_cmd = send_peer_add_wds_entry_cmd_non_tlv, + .send_peer_del_wds_entry_cmd = send_peer_del_wds_entry_cmd_non_tlv, + .send_peer_update_wds_entry_cmd = + send_peer_update_wds_entry_cmd_non_tlv, + .send_phyerr_enable_cmd = send_phyerr_enable_cmd_non_tlv, + .send_phyerr_disable_cmd = send_phyerr_disable_cmd_non_tlv, + .send_smart_ant_enable_cmd = send_smart_ant_enable_cmd_non_tlv, + .send_smart_ant_set_rx_ant_cmd = send_smart_ant_set_rx_ant_cmd_non_tlv, + .send_smart_ant_set_tx_ant_cmd = send_smart_ant_set_tx_ant_cmd_non_tlv, + .send_smart_ant_set_training_info_cmd = + send_smart_ant_set_training_info_cmd_non_tlv, + .send_smart_ant_set_node_config_cmd = + send_smart_ant_set_node_config_cmd_non_tlv, + .send_smart_ant_enable_tx_feedback_cmd = + send_smart_ant_enable_tx_feedback_cmd_non_tlv, + .send_vdev_spectral_configure_cmd = + send_vdev_spectral_configure_cmd_non_tlv, + .send_vdev_spectral_enable_cmd = + send_vdev_spectral_enable_cmd_non_tlv, + .send_bss_chan_info_request_cmd = + send_bss_chan_info_request_cmd_non_tlv, + .send_thermal_mitigation_param_cmd = + send_thermal_mitigation_param_cmd_non_tlv, + .send_vdev_start_cmd = send_vdev_start_cmd_non_tlv, + .send_vdev_stop_cmd = send_vdev_stop_cmd_non_tlv, + .send_vdev_set_neighbour_rx_cmd = + send_vdev_set_neighbour_rx_cmd_non_tlv, + .send_vdev_set_fwtest_param_cmd = + send_vdev_set_fwtest_param_cmd_non_tlv, + .send_vdev_config_ratemask_cmd = send_vdev_config_ratemask_cmd_non_tlv, + .send_vdev_install_key_cmd = send_vdev_install_key_cmd_non_tlv, + .send_wow_wakeup_cmd = send_wow_wakeup_cmd_non_tlv, + .send_wow_add_wakeup_event_cmd = send_wow_add_wakeup_event_cmd_non_tlv, + .send_wow_add_wakeup_pattern_cmd = + send_wow_add_wakeup_pattern_cmd_non_tlv, + .send_wow_remove_wakeup_pattern_cmd = + send_wow_remove_wakeup_pattern_cmd_non_tlv, + .send_pdev_set_regdomain_cmd = + send_pdev_set_regdomain_cmd_non_tlv, + .send_set_quiet_mode_cmd = send_set_quiet_mode_cmd_non_tlv, + .send_set_beacon_filter_cmd = send_set_beacon_filter_cmd_non_tlv, + .send_remove_beacon_filter_cmd = send_remove_beacon_filter_cmd_non_tlv, + .send_mgmt_cmd = send_mgmt_cmd_non_tlv, + .send_addba_clearresponse_cmd = send_addba_clearresponse_cmd_non_tlv, + .send_addba_send_cmd = send_addba_send_cmd_non_tlv, + .send_delba_send_cmd = send_delba_send_cmd_non_tlv, + .send_addba_setresponse_cmd = send_addba_setresponse_cmd_non_tlv, + .send_singleamsdu_cmd = send_singleamsdu_cmd_non_tlv, + .send_set_qboost_param_cmd = send_set_qboost_param_cmd_non_tlv, + .send_mu_scan_cmd = send_mu_scan_cmd_non_tlv, + .send_lteu_config_cmd = send_lteu_config_cmd_non_tlv, + .send_set_ps_mode_cmd = send_set_ps_mode_cmd_non_tlv, + .init_cmd_send = init_cmd_send_non_tlv, + .send_ext_resource_config = send_ext_resource_config_non_tlv, +#if 0 + .send_bcn_prb_template_cmd = send_bcn_prb_template_cmd_non_tlv, +#endif + .send_nf_dbr_dbm_info_get_cmd = send_nf_dbr_dbm_info_get_cmd_non_tlv, + .send_packet_power_info_get_cmd = + send_packet_power_info_get_cmd_non_tlv, + .send_gpio_config_cmd = send_gpio_config_cmd_non_tlv, + .send_gpio_output_cmd = send_gpio_output_cmd_non_tlv, + .send_rtt_meas_req_test_cmd = send_rtt_meas_req_test_cmd_non_tlv, + .send_rtt_meas_req_cmd = send_rtt_meas_req_cmd_non_tlv, + .send_lci_set_cmd = send_lci_set_cmd_non_tlv, + .send_rtt_keepalive_req_cmd = send_rtt_keepalive_req_cmd_non_tlv, + .send_periodic_chan_stats_config_cmd = + send_periodic_chan_stats_config_cmd_non_tlv, + + .get_target_cap_from_service_ready = extract_service_ready_non_tlv, + .extract_fw_version = extract_fw_version_non_tlv, + .extract_fw_abi_version = extract_fw_abi_version_non_tlv, + .extract_hal_reg_cap = extract_hal_reg_cap_non_tlv, + .extract_host_mem_req = extract_host_mem_req_non_tlv, + .save_service_bitmap = save_service_bitmap_non_tlv, + .is_service_enabled = is_service_enabled_non_tlv, + .save_fw_version = save_fw_version_in_service_ready_non_tlv, + .check_and_update_fw_version = + ready_check_and_update_fw_version_non_tlv, + .extract_dbglog_data_len = extract_dbglog_data_len_non_tlv, + .ready_extract_init_status = ready_extract_init_status_non_tlv, + .ready_extract_mac_addr = ready_extract_mac_addr_non_tlv, + .extract_wds_addr_event = extract_wds_addr_event_non_tlv, + .extract_dcs_interference_type = extract_dcs_interference_type_non_tlv, + .extract_dcs_cw_int = extract_dcs_cw_int_non_tlv, + .extract_dcs_im_tgt_stats = extract_dcs_im_tgt_stats_non_tlv, + .extract_vdev_start_resp = extract_vdev_start_resp_non_tlv, + .extract_tbttoffset_update_params = + extract_tbttoffset_update_params_non_tlv, + .extract_mgmt_rx_params = extract_mgmt_rx_params_non_tlv, + .extract_vdev_stopped_param = extract_vdev_stopped_param_non_tlv, + .extract_vdev_roam_param = extract_vdev_roam_param_non_tlv, + .extract_vdev_scan_ev_param = extract_vdev_scan_ev_param_non_tlv, + .extract_mu_ev_param = extract_mu_ev_param_non_tlv, + .extract_pdev_tpc_config_ev_param = + extract_pdev_tpc_config_ev_param_non_tlv, + .extract_nfcal_power_ev_param = extract_nfcal_power_ev_param_non_tlv, + .extract_pdev_tpc_ev_param = extract_pdev_tpc_ev_param_non_tlv, + .extract_pdev_generic_buffer_ev_param = + extract_pdev_generic_buffer_ev_param_non_tlv, + .extract_gpio_input_ev_param = extract_gpio_input_ev_param_non_tlv, + .extract_pdev_reserve_ast_ev_param = + extract_pdev_reserve_ast_ev_param_non_tlv, + .extract_swba_vdev_map = extract_swba_vdev_map_non_tlv, + .extract_swba_tim_info = extract_swba_tim_info_non_tlv, + .extract_swba_noa_info = extract_swba_noa_info_non_tlv, + .extract_peer_sta_ps_statechange_ev = + extract_peer_sta_ps_statechange_ev_non_tlv, + .extract_peer_sta_kickout_ev = extract_peer_sta_kickout_ev_non_tlv, + .extract_peer_ratecode_list_ev = extract_peer_ratecode_list_ev_non_tlv, + .extract_comb_phyerr = extract_comb_phyerr_non_tlv, + .extract_single_phyerr = extract_single_phyerr_non_tlv, + .extract_composite_phyerr = extract_composite_phyerr_non_tlv, + .extract_rtt_hdr = extract_rtt_hdr_non_tlv, + .extract_rtt_ev = extract_rtt_ev_non_tlv, + .extract_rtt_error_report_ev = extract_rtt_error_report_ev_non_tlv, + .extract_all_stats_count = extract_all_stats_counts_non_tlv, + .extract_pdev_stats = extract_pdev_stats_non_tlv, + .extract_pdev_ext_stats = extract_pdev_ext_stats_non_tlv, + .extract_vdev_stats = extract_vdev_stats_non_tlv, + .extract_peer_stats = extract_peer_stats_non_tlv, + .extract_bcnflt_stats = extract_bcnflt_stats_non_tlv, + .extract_peer_extd_stats = extract_peer_extd_stats_non_tlv, + .extract_chan_stats = extract_chan_stats_non_tlv, + .extract_thermal_stats = extract_thermal_stats_non_tlv, + .extract_thermal_level_stats = extract_thermal_level_stats_non_tlv, + .extract_profile_ctx = extract_profile_ctx_non_tlv, + .extract_profile_data = extract_profile_data_non_tlv, + .extract_chan_info_event = extract_chan_info_event_non_tlv, + .extract_channel_hopping_event = extract_channel_hopping_event_non_tlv, + .extract_bss_chan_info_event = extract_bss_chan_info_event_non_tlv, + .extract_inst_rssi_stats_event = extract_inst_rssi_stats_event_non_tlv, + .extract_tx_data_traffic_ctrl_ev = + extract_tx_data_traffic_ctrl_ev_non_tlv, + .extract_vdev_extd_stats = extract_vdev_extd_stats_non_tlv, + .extract_fips_event_data = extract_fips_event_data_non_tlv, + .extract_fips_event_error_status = + extract_fips_event_error_status_non_tlv, + .wmi_set_htc_tx_tag = wmi_set_htc_tx_tag_non_tlv, +}; + +/** + * populate_non_tlv_service() - populates wmi services + * + * @param wmi_service: Pointer to hold wmi_service + * Return: None + */ +static void populate_non_tlv_service(uint32_t *wmi_service) +{ + wmi_service[wmi_service_beacon_offload] = WMI_SERVICE_BEACON_OFFLOAD; + wmi_service[wmi_service_scan_offload] = WMI_SERVICE_SCAN_OFFLOAD; + wmi_service[wmi_service_roam_offload] = WMI_SERVICE_ROAM_OFFLOAD; + wmi_service[wmi_service_bcn_miss_offload] = + WMI_SERVICE_BCN_MISS_OFFLOAD; + wmi_service[wmi_service_sta_pwrsave] = WMI_SERVICE_STA_PWRSAVE; + wmi_service[wmi_service_sta_advanced_pwrsave] = + WMI_SERVICE_STA_ADVANCED_PWRSAVE; + wmi_service[wmi_service_ap_uapsd] = WMI_SERVICE_AP_UAPSD; + wmi_service[wmi_service_ap_dfs] = WMI_SERVICE_AP_DFS; + wmi_service[wmi_service_11ac] = WMI_SERVICE_11AC; + wmi_service[wmi_service_blockack] = WMI_SERVICE_BLOCKACK; + wmi_service[wmi_service_phyerr] = WMI_SERVICE_PHYERR; + wmi_service[wmi_service_bcn_filter] = WMI_SERVICE_BCN_FILTER; + wmi_service[wmi_service_rtt] = WMI_SERVICE_RTT; + wmi_service[wmi_service_ratectrl] = WMI_SERVICE_RATECTRL; + wmi_service[wmi_service_wow] = WMI_SERVICE_WOW; + wmi_service[wmi_service_ratectrl_cache] = WMI_SERVICE_RATECTRL_CACHE; + wmi_service[wmi_service_iram_tids] = WMI_SERVICE_IRAM_TIDS; + wmi_service[wmi_service_burst] = WMI_SERVICE_BURST; + wmi_service[wmi_service_smart_antenna_sw_support] = + WMI_SERVICE_SMART_ANTENNA_SW_SUPPORT; + wmi_service[wmi_service_gtk_offload] = WMI_SERVICE_GTK_OFFLOAD; + wmi_service[wmi_service_scan_sch] = WMI_SERVICE_SCAN_SCH; + wmi_service[wmi_service_csa_offload] = WMI_SERVICE_CSA_OFFLOAD; + wmi_service[wmi_service_chatter] = WMI_SERVICE_CHATTER; + wmi_service[wmi_service_coex_freqavoid] = WMI_SERVICE_COEX_FREQAVOID; + wmi_service[wmi_service_packet_power_save] = + WMI_SERVICE_PACKET_POWER_SAVE; + wmi_service[wmi_service_force_fw_hang] = WMI_SERVICE_FORCE_FW_HANG; + wmi_service[wmi_service_smart_antenna_hw_support] = + WMI_SERVICE_SMART_ANTENNA_HW_SUPPORT; + wmi_service[wmi_service_gpio] = WMI_SERVICE_GPIO; + wmi_service[wmi_sta_uapsd_basic_auto_trig] = + WMI_STA_UAPSD_BASIC_AUTO_TRIG; + wmi_service[wmi_sta_uapsd_var_auto_trig] = WMI_STA_UAPSD_VAR_AUTO_TRIG; + wmi_service[wmi_service_sta_keep_alive] = WMI_SERVICE_STA_KEEP_ALIVE; + wmi_service[wmi_service_tx_encap] = WMI_SERVICE_TX_ENCAP; + wmi_service[wmi_service_ap_ps_detect_out_of_sync] = + WMI_SERVICE_AP_PS_DETECT_OUT_OF_SYNC; + wmi_service[wmi_service_early_rx] = + WMI_SERVICE_EARLY_RX; + wmi_service[wmi_service_enhanced_proxy_sta] = + WMI_SERVICE_ENHANCED_PROXY_STA; + wmi_service[wmi_service_tt] = WMI_SERVICE_TT; + wmi_service[wmi_service_atf] = WMI_SERVICE_ATF; + wmi_service[wmi_service_peer_caching] = WMI_SERVICE_PEER_CACHING; + wmi_service[wmi_service_coex_gpio] = WMI_SERVICE_COEX_GPIO; + wmi_service[wmi_service_aux_spectral_intf] = + WMI_SERVICE_AUX_SPECTRAL_INTF; + wmi_service[wmi_service_aux_chan_load_intf] = + WMI_SERVICE_AUX_CHAN_LOAD_INTF; + wmi_service[wmi_service_bss_channel_info_64] = + WMI_SERVICE_BSS_CHANNEL_INFO_64; + wmi_service[wmi_service_ext_res_cfg_support] = + WMI_SERVICE_EXT_RES_CFG_SUPPORT; + wmi_service[wmi_service_mesh] = WMI_SERVICE_MESH; + wmi_service[wmi_service_restrt_chnl_support] = + WMI_SERVICE_RESTRT_CHNL_SUPPORT; + wmi_service[wmi_service_peer_stats] = WMI_SERVICE_PEER_STATS; + wmi_service[wmi_service_mesh_11s] = WMI_SERVICE_MESH_11S; + wmi_service[wmi_service_periodic_chan_stat_support] = + WMI_SERVICE_PERIODIC_CHAN_STAT_SUPPORT; + wmi_service[wmi_service_tx_mode_push_only] = + WMI_SERVICE_TX_MODE_PUSH_ONLY; + wmi_service[wmi_service_tx_mode_push_pull] = + WMI_SERVICE_TX_MODE_PUSH_PULL; + wmi_service[wmi_service_tx_mode_dynamic] = WMI_SERVICE_TX_MODE_DYNAMIC; + + wmi_service[wmi_service_roam_scan_offload] = WMI_SERVICE_UNAVAILABLE; + wmi_service[wmi_service_arpns_offload] = WMI_SERVICE_UNAVAILABLE; + wmi_service[wmi_service_nlo] = WMI_SERVICE_UNAVAILABLE; + wmi_service[wmi_service_sta_dtim_ps_modulated_dtim] = + WMI_SERVICE_UNAVAILABLE; + wmi_service[wmi_service_sta_smps] = WMI_SERVICE_UNAVAILABLE; + wmi_service[wmi_service_fwtest] = WMI_SERVICE_UNAVAILABLE; + wmi_service[wmi_service_sta_wmmac] = WMI_SERVICE_UNAVAILABLE; + wmi_service[wmi_service_tdls] = WMI_SERVICE_UNAVAILABLE; + wmi_service[wmi_service_mcc_bcn_interval_change] = + WMI_SERVICE_UNAVAILABLE; + wmi_service[wmi_service_adaptive_ocs] = WMI_SERVICE_UNAVAILABLE; + wmi_service[wmi_service_ba_ssn_support] = WMI_SERVICE_UNAVAILABLE; + wmi_service[wmi_service_filter_ipsec_natkeepalive] = + WMI_SERVICE_UNAVAILABLE; + wmi_service[wmi_service_wlan_hb] = WMI_SERVICE_UNAVAILABLE; + wmi_service[wmi_service_lte_ant_share_support] = + WMI_SERVICE_UNAVAILABLE; + wmi_service[wmi_service_batch_scan] = WMI_SERVICE_UNAVAILABLE; + wmi_service[wmi_service_qpower] = WMI_SERVICE_UNAVAILABLE; + wmi_service[wmi_service_plmreq] = WMI_SERVICE_UNAVAILABLE; + wmi_service[wmi_service_thermal_mgmt] = WMI_SERVICE_UNAVAILABLE; + wmi_service[wmi_service_rmc] = WMI_SERVICE_UNAVAILABLE; + wmi_service[wmi_service_mhf_offload] = WMI_SERVICE_UNAVAILABLE; + wmi_service[wmi_service_coex_sar] = WMI_SERVICE_UNAVAILABLE; + wmi_service[wmi_service_bcn_txrate_override] = WMI_SERVICE_UNAVAILABLE; + wmi_service[wmi_service_nan] = WMI_SERVICE_UNAVAILABLE; + wmi_service[wmi_service_l1ss_stat] = WMI_SERVICE_UNAVAILABLE; + wmi_service[wmi_service_estimate_linkspeed] = WMI_SERVICE_UNAVAILABLE; + wmi_service[wmi_service_obss_scan] = WMI_SERVICE_UNAVAILABLE; + wmi_service[wmi_service_tdls_offchan] = WMI_SERVICE_UNAVAILABLE; + wmi_service[wmi_service_tdls_uapsd_buffer_sta] = + WMI_SERVICE_UNAVAILABLE; + wmi_service[wmi_service_tdls_uapsd_sleep_sta] = WMI_SERVICE_UNAVAILABLE; + wmi_service[wmi_service_ibss_pwrsave] = WMI_SERVICE_UNAVAILABLE; + wmi_service[wmi_service_lpass] = WMI_SERVICE_UNAVAILABLE; + wmi_service[wmi_service_extscan] = WMI_SERVICE_UNAVAILABLE; + wmi_service[wmi_service_d0wow] = WMI_SERVICE_UNAVAILABLE; + wmi_service[wmi_service_hsoffload] = WMI_SERVICE_UNAVAILABLE; + wmi_service[wmi_service_roam_ho_offload] = WMI_SERVICE_UNAVAILABLE; + wmi_service[wmi_service_rx_full_reorder] = WMI_SERVICE_UNAVAILABLE; + wmi_service[wmi_service_dhcp_offload] = WMI_SERVICE_UNAVAILABLE; + wmi_service[wmi_service_sta_rx_ipa_offload_support] = + WMI_SERVICE_UNAVAILABLE; + wmi_service[wmi_service_mdns_offload] = WMI_SERVICE_UNAVAILABLE; + wmi_service[wmi_service_sap_auth_offload] = WMI_SERVICE_UNAVAILABLE; + wmi_service[wmi_service_dual_band_simultaneous_support] = + WMI_SERVICE_UNAVAILABLE; + wmi_service[wmi_service_ocb] = WMI_SERVICE_UNAVAILABLE; + wmi_service[wmi_service_ap_arpns_offload] = WMI_SERVICE_UNAVAILABLE; + wmi_service[wmi_service_per_band_chainmask_support] = + WMI_SERVICE_UNAVAILABLE; + wmi_service[wmi_service_packet_filter_offload] = + WMI_SERVICE_UNAVAILABLE; + wmi_service[wmi_service_mgmt_tx_htt] = WMI_SERVICE_UNAVAILABLE; + wmi_service[wmi_service_mgmt_tx_wmi] = WMI_SERVICE_UNAVAILABLE; + wmi_service[wmi_service_ext_msg] = WMI_SERVICE_UNAVAILABLE; + wmi_service[wmi_service_mawc] = WMI_SERVICE_UNAVAILABLE; + +} + +/** + * populate_non_tlv_event_id() - populates wmi event ids + * + * @param event_ids: Pointer to hold event ids + * Return: None + */ +static void populate_non_tlv_events_id(uint32_t *event_ids) +{ + event_ids[wmi_service_ready_event_id] = WMI_SERVICE_READY_EVENTID; + event_ids[wmi_ready_event_id] = WMI_READY_EVENTID; + event_ids[wmi_dbg_msg_event_id] = WMI_DEBUG_MESG_EVENTID; + event_ids[wmi_scan_event_id] = WMI_SCAN_EVENTID; + event_ids[wmi_echo_event_id] = WMI_ECHO_EVENTID; + event_ids[wmi_update_stats_event_id] = WMI_UPDATE_STATS_EVENTID; + event_ids[wmi_inst_rssi_stats_event_id] = WMI_INST_RSSI_STATS_EVENTID; + event_ids[wmi_vdev_start_resp_event_id] = WMI_VDEV_START_RESP_EVENTID; + event_ids[wmi_vdev_standby_req_event_id] = WMI_VDEV_STANDBY_REQ_EVENTID; + event_ids[wmi_vdev_resume_req_event_id] = WMI_VDEV_RESUME_REQ_EVENTID; + event_ids[wmi_vdev_stopped_event_id] = WMI_VDEV_STOPPED_EVENTID; + event_ids[wmi_peer_sta_kickout_event_id] = WMI_PEER_STA_KICKOUT_EVENTID; + event_ids[wmi_host_swba_event_id] = WMI_HOST_SWBA_EVENTID; + event_ids[wmi_tbttoffset_update_event_id] = + WMI_TBTTOFFSET_UPDATE_EVENTID; + event_ids[wmi_mgmt_rx_event_id] = WMI_MGMT_RX_EVENTID; + event_ids[wmi_chan_info_event_id] = WMI_CHAN_INFO_EVENTID; + event_ids[wmi_phyerr_event_id] = WMI_PHYERR_EVENTID; + event_ids[wmi_roam_event_id] = WMI_ROAM_EVENTID; + event_ids[wmi_profile_match] = WMI_PROFILE_MATCH; + event_ids[wmi_debug_print_event_id] = WMI_DEBUG_PRINT_EVENTID; + event_ids[wmi_pdev_qvit_event_id] = WMI_PDEV_QVIT_EVENTID; + event_ids[wmi_wlan_profile_data_event_id] = + WMI_WLAN_PROFILE_DATA_EVENTID; + event_ids[wmi_rtt_meas_report_event_id] = + WMI_RTT_MEASUREMENT_REPORT_EVENTID; + event_ids[wmi_tsf_meas_report_event_id] = + WMI_TSF_MEASUREMENT_REPORT_EVENTID; + event_ids[wmi_rtt_error_report_event_id] = WMI_RTT_ERROR_REPORT_EVENTID; + event_ids[wmi_rtt_keepalive_event_id] = WMI_RTT_KEEPALIVE_EVENTID; + event_ids[wmi_oem_cap_event_id] = WMI_OEM_CAPABILITY_EVENTID; + event_ids[wmi_oem_meas_report_event_id] = + WMI_OEM_MEASUREMENT_REPORT_EVENTID; + event_ids[wmi_oem_report_event_id] = WMI_OEM_ERROR_REPORT_EVENTID; + event_ids[wmi_nan_event_id] = WMI_NAN_EVENTID; + event_ids[wmi_wow_wakeup_host_event_id] = WMI_WOW_WAKEUP_HOST_EVENTID; + event_ids[wmi_gtk_offload_status_event_id] = + WMI_GTK_OFFLOAD_STATUS_EVENTID; + event_ids[wmi_gtk_rekey_fail_event_id] = WMI_GTK_REKEY_FAIL_EVENTID; + event_ids[wmi_dcs_interference_event_id] = WMI_DCS_INTERFERENCE_EVENTID; + event_ids[wmi_pdev_tpc_config_event_id] = WMI_PDEV_TPC_CONFIG_EVENTID; + event_ids[wmi_csa_handling_event_id] = WMI_CSA_HANDLING_EVENTID; + event_ids[wmi_gpio_input_event_id] = WMI_GPIO_INPUT_EVENTID; + event_ids[wmi_peer_ratecode_list_event_id] = + WMI_PEER_RATECODE_LIST_EVENTID; + event_ids[wmi_generic_buffer_event_id] = WMI_GENERIC_BUFFER_EVENTID; + event_ids[wmi_mcast_buf_release_event_id] = + WMI_MCAST_BUF_RELEASE_EVENTID; + event_ids[wmi_mcast_list_ageout_event_id] = + WMI_MCAST_LIST_AGEOUT_EVENTID; + event_ids[wmi_vdev_get_keepalive_event_id] = + WMI_VDEV_GET_KEEPALIVE_EVENTID; + event_ids[wmi_wds_peer_event_id] = WMI_WDS_PEER_EVENTID; + event_ids[wmi_peer_sta_ps_statechg_event_id] = + WMI_PEER_STA_PS_STATECHG_EVENTID; + event_ids[wmi_pdev_fips_event_id] = WMI_PDEV_FIPS_EVENTID; + event_ids[wmi_tt_stats_event_id] = WMI_TT_STATS_EVENTID; + event_ids[wmi_pdev_channel_hopping_event_id] = + WMI_PDEV_CHANNEL_HOPPING_EVENTID; + event_ids[wmi_pdev_ani_cck_level_event_id] = + WMI_PDEV_ANI_CCK_LEVEL_EVENTID; + event_ids[wmi_pdev_ani_ofdm_level_event_id] = + WMI_PDEV_ANI_OFDM_LEVEL_EVENTID; + event_ids[wmi_pdev_reserve_ast_entry_event_id] = + WMI_PDEV_RESERVE_AST_ENTRY_EVENTID; + event_ids[wmi_pdev_nfcal_power_event_id] = WMI_PDEV_NFCAL_POWER_EVENTID; + event_ids[wmi_pdev_tpc_event_id] = WMI_PDEV_TPC_EVENTID; + event_ids[wmi_pdev_get_ast_info_event_id] = + WMI_PDEV_GET_AST_INFO_EVENTID; + event_ids[wmi_pdev_temperature_event_id] = WMI_PDEV_TEMPERATURE_EVENTID; + event_ids[wmi_pdev_nfcal_power_all_channels_event_id] = + WMI_PDEV_NFCAL_POWER_ALL_CHANNELS_EVENTID; + event_ids[wmi_pdev_bss_chan_info_event_id] = + WMI_PDEV_BSS_CHAN_INFO_EVENTID; + event_ids[wmi_mu_report_event_id] = WMI_MU_REPORT_EVENTID; + event_ids[wmi_tx_data_traffic_ctrl_event_id] = + WMI_TX_DATA_TRAFFIC_CTRL_EVENTID; + event_ids[wmi_pdev_utf_event_id] = WMI_PDEV_UTF_EVENTID; + event_ids[wmi_update_rcpi_event_id] = WMI_UPDATE_RCPI_EVENTID; +} + +/** + * populate_pdev_param_non_tlv() - populates pdev params + * + * @param pdev_param: Pointer to hold pdev params + * Return: None + */ +static void populate_pdev_param_non_tlv(uint32_t *pdev_param) +{ + pdev_param[wmi_pdev_param_tx_chain_mask] = WMI_PDEV_PARAM_TX_CHAIN_MASK; + pdev_param[wmi_pdev_param_rx_chain_mask] = WMI_PDEV_PARAM_RX_CHAIN_MASK; + pdev_param[wmi_pdev_param_txpower_limit2g] = + WMI_PDEV_PARAM_TXPOWER_LIMIT2G; + pdev_param[wmi_pdev_param_txpower_limit5g] = + WMI_PDEV_PARAM_TXPOWER_LIMIT5G; + pdev_param[wmi_pdev_param_txpower_scale] = WMI_PDEV_PARAM_TXPOWER_SCALE; + pdev_param[wmi_pdev_param_beacon_gen_mode] = + WMI_PDEV_PARAM_BEACON_GEN_MODE; + pdev_param[wmi_pdev_param_beacon_tx_mode] = + WMI_PDEV_PARAM_BEACON_TX_MODE; + pdev_param[wmi_pdev_param_resmgr_offchan_mode] = + WMI_PDEV_PARAM_RESMGR_OFFCHAN_MODE; + pdev_param[wmi_pdev_param_protection_mode] = + WMI_PDEV_PARAM_PROTECTION_MODE; + pdev_param[wmi_pdev_param_dynamic_bw] = WMI_PDEV_PARAM_DYNAMIC_BW; + pdev_param[wmi_pdev_param_non_agg_sw_retry_th] = + WMI_PDEV_PARAM_NON_AGG_SW_RETRY_TH; + pdev_param[wmi_pdev_param_agg_sw_retry_th] = + WMI_PDEV_PARAM_AGG_SW_RETRY_TH; + pdev_param[wmi_pdev_param_sta_kickout_th] = + WMI_PDEV_PARAM_STA_KICKOUT_TH; + pdev_param[wmi_pdev_param_ac_aggrsize_scaling] = + WMI_PDEV_PARAM_AC_AGGRSIZE_SCALING; + pdev_param[wmi_pdev_param_ltr_enable] = WMI_PDEV_PARAM_LTR_ENABLE; + pdev_param[wmi_pdev_param_ltr_ac_latency_be] = + WMI_PDEV_PARAM_LTR_AC_LATENCY_BE; + pdev_param[wmi_pdev_param_ltr_ac_latency_bk] = + WMI_PDEV_PARAM_LTR_AC_LATENCY_BK; + pdev_param[wmi_pdev_param_ltr_ac_latency_vi] = + WMI_PDEV_PARAM_LTR_AC_LATENCY_VI; + pdev_param[wmi_pdev_param_ltr_ac_latency_vo] = + WMI_PDEV_PARAM_LTR_AC_LATENCY_VO; + pdev_param[wmi_pdev_param_ltr_ac_latency_timeout] = + WMI_PDEV_PARAM_LTR_AC_LATENCY_TIMEOUT; + pdev_param[wmi_pdev_param_ltr_sleep_override] = + WMI_PDEV_PARAM_LTR_SLEEP_OVERRIDE; + pdev_param[wmi_pdev_param_ltr_rx_override] = + WMI_PDEV_PARAM_LTR_RX_OVERRIDE; + pdev_param[wmi_pdev_param_ltr_tx_activity_timeout] = + WMI_PDEV_PARAM_LTR_TX_ACTIVITY_TIMEOUT; + pdev_param[wmi_pdev_param_l1ss_enable] = WMI_PDEV_PARAM_L1SS_ENABLE; + pdev_param[wmi_pdev_param_dsleep_enable] = WMI_PDEV_PARAM_DSLEEP_ENABLE; + pdev_param[wmi_pdev_param_pcielp_txbuf_flush] = + WMI_PDEV_PARAM_PCIELP_TXBUF_FLUSH; + pdev_param[wmi_pdev_param_pcielp_txbuf_watermark] = + WMI_PDEV_PARAM_PCIELP_TXBUF_WATERMARK; + pdev_param[wmi_pdev_param_pcielp_txbuf_tmo_en] = + WMI_PDEV_PARAM_PCIELP_TXBUF_TMO_EN; + pdev_param[wmi_pdev_param_pcielp_txbuf_tmo_value] = + WMI_PDEV_PARAM_PCIELP_TXBUF_TMO_VALUE; + pdev_param[wmi_pdev_param_pdev_stats_update_period] = + WMI_PDEV_PARAM_PDEV_STATS_UPDATE_PERIOD; + pdev_param[wmi_pdev_param_vdev_stats_update_period] = + WMI_PDEV_PARAM_VDEV_STATS_UPDATE_PERIOD; + pdev_param[wmi_pdev_param_peer_stats_update_period] = + WMI_PDEV_PARAM_PEER_STATS_UPDATE_PERIOD; + pdev_param[wmi_pdev_param_bcnflt_stats_update_period] = + WMI_PDEV_PARAM_BCNFLT_STATS_UPDATE_PERIOD; + pdev_param[wmi_pdev_param_pmf_qos] = + WMI_PDEV_PARAM_PMF_QOS; + pdev_param[wmi_pdev_param_arp_ac_override] = + WMI_PDEV_PARAM_ARP_AC_OVERRIDE; + pdev_param[wmi_pdev_param_dcs] = + WMI_PDEV_PARAM_DCS; + pdev_param[wmi_pdev_param_ani_enable] = WMI_PDEV_PARAM_ANI_ENABLE; + pdev_param[wmi_pdev_param_ani_poll_period] = + WMI_PDEV_PARAM_ANI_POLL_PERIOD; + pdev_param[wmi_pdev_param_ani_listen_period] = + WMI_PDEV_PARAM_ANI_LISTEN_PERIOD; + pdev_param[wmi_pdev_param_ani_ofdm_level] = + WMI_PDEV_PARAM_ANI_OFDM_LEVEL; + pdev_param[wmi_pdev_param_ani_cck_level] = WMI_PDEV_PARAM_ANI_CCK_LEVEL; + pdev_param[wmi_pdev_param_dyntxchain] = WMI_PDEV_PARAM_DYNTXCHAIN; + pdev_param[wmi_pdev_param_proxy_sta] = WMI_PDEV_PARAM_PROXY_STA; + pdev_param[wmi_pdev_param_idle_ps_config] = + WMI_PDEV_PARAM_IDLE_PS_CONFIG; + pdev_param[wmi_pdev_param_power_gating_sleep] = + WMI_PDEV_PARAM_POWER_GATING_SLEEP; + pdev_param[wmi_pdev_param_aggr_burst] = WMI_PDEV_PARAM_AGGR_BURST; + pdev_param[wmi_pdev_param_rx_decap_mode] = WMI_PDEV_PARAM_RX_DECAP_MODE; + pdev_param[wmi_pdev_param_fast_channel_reset] = + WMI_PDEV_PARAM_FAST_CHANNEL_RESET; + pdev_param[wmi_pdev_param_burst_dur] = WMI_PDEV_PARAM_BURST_DUR; + pdev_param[wmi_pdev_param_burst_enable] = WMI_PDEV_PARAM_BURST_ENABLE; + pdev_param[wmi_pdev_param_smart_antenna_default_antenna] = + WMI_PDEV_PARAM_SMART_ANTENNA_DEFAULT_ANTENNA; + pdev_param[wmi_pdev_param_igmpmld_override] = + WMI_PDEV_PARAM_IGMPMLD_OVERRIDE; + pdev_param[wmi_pdev_param_igmpmld_tid] = + WMI_PDEV_PARAM_IGMPMLD_TID; + pdev_param[wmi_pdev_param_antenna_gain] = WMI_PDEV_PARAM_ANTENNA_GAIN; + pdev_param[wmi_pdev_param_rx_filter] = WMI_PDEV_PARAM_RX_FILTER; + pdev_param[wmi_pdev_set_mcast_to_ucast_tid] = + WMI_PDEV_SET_MCAST_TO_UCAST_TID; + pdev_param[wmi_pdev_param_proxy_sta_mode] = + WMI_PDEV_PARAM_PROXY_STA_MODE; + pdev_param[wmi_pdev_param_set_mcast2ucast_mode] = + WMI_PDEV_PARAM_SET_MCAST2UCAST_MODE; + pdev_param[wmi_pdev_param_set_mcast2ucast_buffer] = + WMI_PDEV_PARAM_SET_MCAST2UCAST_BUFFER; + pdev_param[wmi_pdev_param_remove_mcast2ucast_buffer] = + WMI_PDEV_PARAM_REMOVE_MCAST2UCAST_BUFFER; + pdev_param[wmi_pdev_peer_sta_ps_statechg_enable] = + WMI_PDEV_PEER_STA_PS_STATECHG_ENABLE; + pdev_param[wmi_pdev_param_igmpmld_ac_override] = + WMI_PDEV_PARAM_IGMPMLD_AC_OVERRIDE; + pdev_param[wmi_pdev_param_block_interbss] = + WMI_PDEV_PARAM_BLOCK_INTERBSS; + pdev_param[wmi_pdev_param_set_disable_reset_cmdid] = + WMI_PDEV_PARAM_SET_DISABLE_RESET_CMDID; + pdev_param[wmi_pdev_param_set_msdu_ttl_cmdid] = + WMI_PDEV_PARAM_SET_MSDU_TTL_CMDID; + pdev_param[wmi_pdev_param_set_ppdu_duration_cmdid] = + WMI_PDEV_PARAM_SET_PPDU_DURATION_CMDID; + pdev_param[wmi_pdev_param_txbf_sound_period_cmdid] = + WMI_PDEV_PARAM_TXBF_SOUND_PERIOD_CMDID; + pdev_param[wmi_pdev_param_set_promisc_mode_cmdid] = + WMI_PDEV_PARAM_SET_PROMISC_MODE_CMDID; + pdev_param[wmi_pdev_param_set_burst_mode_cmdid] = + WMI_PDEV_PARAM_SET_BURST_MODE_CMDID; + pdev_param[wmi_pdev_param_en_stats] = WMI_PDEV_PARAM_EN_STATS; + pdev_param[wmi_pdev_param_mu_group_policy] = + WMI_PDEV_PARAM_MU_GROUP_POLICY; + pdev_param[wmi_pdev_param_noise_detection] = + WMI_PDEV_PARAM_NOISE_DETECTION; + pdev_param[wmi_pdev_param_noise_threshold] = + WMI_PDEV_PARAM_NOISE_THRESHOLD; + pdev_param[wmi_pdev_param_dpd_enable] = + WMI_PDEV_PARAM_DPD_ENABLE; + pdev_param[wmi_pdev_param_set_mcast_bcast_echo] = + WMI_PDEV_PARAM_SET_MCAST_BCAST_ECHO; + pdev_param[wmi_pdev_param_atf_strict_sch] = + WMI_PDEV_PARAM_ATF_STRICT_SCH; + pdev_param[wmi_pdev_param_atf_sched_duration] = + WMI_PDEV_PARAM_ATF_SCHED_DURATION; + pdev_param[wmi_pdev_param_ant_plzn] = WMI_PDEV_PARAM_ANT_PLZN; + pdev_param[wmi_pdev_param_mgmt_retry_limit] = + WMI_PDEV_PARAM_MGMT_RETRY_LIMIT; + pdev_param[wmi_pdev_param_sensitivity_level] = + WMI_PDEV_PARAM_SENSITIVITY_LEVEL; + pdev_param[wmi_pdev_param_signed_txpower_2g] = + WMI_PDEV_PARAM_SIGNED_TXPOWER_2G; + pdev_param[wmi_pdev_param_signed_txpower_5g] = + WMI_PDEV_PARAM_SIGNED_TXPOWER_5G; + pdev_param[wmi_pdev_param_enable_per_tid_amsdu] = + WMI_PDEV_PARAM_ENABLE_PER_TID_AMSDU; + pdev_param[wmi_pdev_param_enable_per_tid_ampdu] = + WMI_PDEV_PARAM_ENABLE_PER_TID_AMPDU; + pdev_param[wmi_pdev_param_cca_threshold] = WMI_PDEV_PARAM_CCA_THRESHOLD; + pdev_param[wmi_pdev_param_rts_fixed_rate] = + WMI_PDEV_PARAM_RTS_FIXED_RATE; + pdev_param[wmi_pdev_param_cal_period] = WMI_PDEV_PARAM_CAL_PERIOD; + pdev_param[wmi_pdev_param_pdev_reset] = WMI_PDEV_PARAM_PDEV_RESET; + pdev_param[wmi_pdev_param_wapi_mbssid_offset] = + WMI_PDEV_PARAM_WAPI_MBSSID_OFFSET; + pdev_param[wmi_pdev_param_arp_srcaddr] = WMI_PDEV_PARAM_ARP_SRCADDR; + pdev_param[wmi_pdev_param_arp_dstaddr] = WMI_PDEV_PARAM_ARP_DSTADDR; + pdev_param[wmi_pdev_param_txpower_decr_db] = + WMI_PDEV_PARAM_TXPOWER_DECR_DB; + pdev_param[wmi_pdev_param_rx_batchmode] = WMI_PDEV_PARAM_RX_BATCHMODE; + pdev_param[wmi_pdev_param_packet_aggr_delay] = + WMI_PDEV_PARAM_PACKET_AGGR_DELAY; + pdev_param[wmi_pdev_param_atf_obss_noise_sch] = + WMI_PDEV_PARAM_ATF_OBSS_NOISE_SCH; + pdev_param[wmi_pdev_param_atf_obss_noise_scaling_factor] = + WMI_PDEV_PARAM_ATF_OBSS_NOISE_SCALING_FACTOR; + pdev_param[wmi_pdev_param_cust_txpower_scale] = + WMI_PDEV_PARAM_CUST_TXPOWER_SCALE; + pdev_param[wmi_pdev_param_atf_dynamic_enable] = + WMI_PDEV_PARAM_ATF_DYNAMIC_ENABLE; + pdev_param[wmi_pdev_param_atf_ssid_group_policy] = + WMI_PDEV_PARAM_ATF_SSID_GROUP_POLICY; + pdev_param[wmi_pdev_param_rfkill_enable] = WMI_UNAVAILABLE_PARAM; + pdev_param[wmi_pdev_param_hw_rfkill_config] = WMI_UNAVAILABLE_PARAM; + pdev_param[wmi_pdev_param_low_power_rf_enable] = WMI_UNAVAILABLE_PARAM; + pdev_param[wmi_pdev_param_l1ss_track] = WMI_UNAVAILABLE_PARAM; + pdev_param[wmi_pdev_param_hyst_en] = WMI_UNAVAILABLE_PARAM; + pdev_param[wmi_pdev_param_power_collapse_enable] = + WMI_UNAVAILABLE_PARAM; + pdev_param[wmi_pdev_param_led_sys_state] = WMI_UNAVAILABLE_PARAM; + pdev_param[wmi_pdev_param_led_enable] = WMI_UNAVAILABLE_PARAM; + pdev_param[wmi_pdev_param_audio_over_wlan_latency] = + WMI_UNAVAILABLE_PARAM; + pdev_param[wmi_pdev_param_audio_over_wlan_enable] = + WMI_UNAVAILABLE_PARAM; + pdev_param[wmi_pdev_param_whal_mib_stats_update_enable] = + WMI_UNAVAILABLE_PARAM; + pdev_param[wmi_pdev_param_vdev_rate_stats_update_period] = + WMI_UNAVAILABLE_PARAM; + pdev_param[wmi_pdev_param_cts_cbw] = WMI_UNAVAILABLE_PARAM; + pdev_param[wmi_pdev_param_wnts_config] = WMI_UNAVAILABLE_PARAM; + pdev_param[wmi_pdev_param_adaptive_early_rx_enable] = + WMI_UNAVAILABLE_PARAM; + pdev_param[wmi_pdev_param_adaptive_early_rx_min_sleep_slop] = + WMI_UNAVAILABLE_PARAM; + pdev_param[wmi_pdev_param_adaptive_early_rx_inc_dec_step] = + WMI_UNAVAILABLE_PARAM; + pdev_param[wmi_pdev_param_early_rx_fix_sleep_slop] = + WMI_UNAVAILABLE_PARAM; + pdev_param[wmi_pdev_param_bmiss_based_adaptive_bto_enable] = + WMI_UNAVAILABLE_PARAM; + pdev_param[wmi_pdev_param_bmiss_bto_min_bcn_timeout] = + WMI_UNAVAILABLE_PARAM; + pdev_param[wmi_pdev_param_bmiss_bto_inc_dec_step] = + WMI_UNAVAILABLE_PARAM; + pdev_param[wmi_pdev_param_bto_fix_bcn_timeout] = + WMI_UNAVAILABLE_PARAM; + pdev_param[wmi_pdev_param_ce_based_adaptive_bto_enable] = + WMI_UNAVAILABLE_PARAM; + pdev_param[wmi_pdev_param_ce_bto_combo_ce_value] = + WMI_UNAVAILABLE_PARAM; + pdev_param[wmi_pdev_param_tx_chain_mask_2g] = WMI_UNAVAILABLE_PARAM; + pdev_param[wmi_pdev_param_rx_chain_mask_2g] = WMI_UNAVAILABLE_PARAM; + pdev_param[wmi_pdev_param_tx_chain_mask_5g] = WMI_UNAVAILABLE_PARAM; + pdev_param[wmi_pdev_param_rx_chain_mask_5g] = WMI_UNAVAILABLE_PARAM; + pdev_param[wmi_pdev_param_tx_chain_mask_cck] = WMI_UNAVAILABLE_PARAM; + pdev_param[wmi_pdev_param_tx_chain_mask_1ss] = WMI_UNAVAILABLE_PARAM; +} + +/** + * populate_vdev_param_non_tlv() - populates vdev params + * + * @param vdev_param: Pointer to hold vdev params + * Return: None + */ +static void populate_vdev_param_non_tlv(uint32_t *vdev_param) +{ + vdev_param[wmi_vdev_param_rts_threshold] = WMI_VDEV_PARAM_RTS_THRESHOLD; + vdev_param[wmi_vdev_param_fragmentation_threshold] = + WMI_VDEV_PARAM_FRAGMENTATION_THRESHOLD; + vdev_param[wmi_vdev_param_beacon_interval] = + WMI_VDEV_PARAM_BEACON_INTERVAL; + vdev_param[wmi_vdev_param_listen_interval] = + WMI_VDEV_PARAM_LISTEN_INTERVAL; + vdev_param[wmi_vdev_param_multicast_rate] = + WMI_VDEV_PARAM_MULTICAST_RATE; + vdev_param[wmi_vdev_param_mgmt_tx_rate] = + WMI_VDEV_PARAM_MGMT_TX_RATE; + vdev_param[wmi_vdev_param_slot_time] = WMI_VDEV_PARAM_SLOT_TIME; + vdev_param[wmi_vdev_param_preamble] = WMI_VDEV_PARAM_PREAMBLE; + vdev_param[wmi_vdev_param_swba_time] = WMI_VDEV_PARAM_SWBA_TIME; + vdev_param[wmi_vdev_stats_update_period] = WMI_VDEV_STATS_UPDATE_PERIOD; + vdev_param[wmi_vdev_pwrsave_ageout_time] = WMI_VDEV_PWRSAVE_AGEOUT_TIME; + vdev_param[wmi_vdev_host_swba_interval] = WMI_VDEV_HOST_SWBA_INTERVAL; + vdev_param[wmi_vdev_param_dtim_period] = WMI_VDEV_PARAM_DTIM_PERIOD; + vdev_param[wmi_vdev_oc_scheduler_air_time_limit] = + WMI_VDEV_OC_SCHEDULER_AIR_TIME_LIMIT; + vdev_param[wmi_vdev_param_wds] = WMI_VDEV_PARAM_WDS; + vdev_param[wmi_vdev_param_atim_window] = WMI_VDEV_PARAM_ATIM_WINDOW; + vdev_param[wmi_vdev_param_bmiss_count_max] = + WMI_VDEV_PARAM_BMISS_COUNT_MAX; + vdev_param[wmi_vdev_param_bmiss_first_bcnt] = + WMI_VDEV_PARAM_BMISS_FIRST_BCNT; + vdev_param[wmi_vdev_param_bmiss_final_bcnt] = + WMI_VDEV_PARAM_BMISS_FINAL_BCNT; + vdev_param[wmi_vdev_param_feature_wmm] = WMI_VDEV_PARAM_FEATURE_WMM; + vdev_param[wmi_vdev_param_chwidth] = WMI_VDEV_PARAM_CHWIDTH; + vdev_param[wmi_vdev_param_chextoffset] = WMI_VDEV_PARAM_CHEXTOFFSET; + vdev_param[wmi_vdev_param_disable_htprotection] = + WMI_VDEV_PARAM_DISABLE_HTPROTECTION; + vdev_param[wmi_vdev_param_sta_quickkickout] = + WMI_VDEV_PARAM_STA_QUICKKICKOUT; + vdev_param[wmi_vdev_param_mgmt_rate] = WMI_VDEV_PARAM_MGMT_RATE; + vdev_param[wmi_vdev_param_protection_mode] = + WMI_VDEV_PARAM_PROTECTION_MODE; + vdev_param[wmi_vdev_param_fixed_rate] = WMI_VDEV_PARAM_FIXED_RATE; + vdev_param[wmi_vdev_param_sgi] = WMI_VDEV_PARAM_SGI; + vdev_param[wmi_vdev_param_ldpc] = WMI_VDEV_PARAM_LDPC; + vdev_param[wmi_vdev_param_tx_stbc] = WMI_VDEV_PARAM_TX_STBC; + vdev_param[wmi_vdev_param_rx_stbc] = WMI_VDEV_PARAM_RX_STBC; + vdev_param[wmi_vdev_param_intra_bss_fwd] = WMI_VDEV_PARAM_INTRA_BSS_FWD; + vdev_param[wmi_vdev_param_def_keyid] = WMI_VDEV_PARAM_DEF_KEYID; + vdev_param[wmi_vdev_param_nss] = WMI_VDEV_PARAM_NSS; + vdev_param[wmi_vdev_param_bcast_data_rate] = + WMI_VDEV_PARAM_BCAST_DATA_RATE; + vdev_param[wmi_vdev_param_mcast_data_rate] = + WMI_VDEV_PARAM_MCAST_DATA_RATE; + vdev_param[wmi_vdev_param_mcast_indicate] = + WMI_VDEV_PARAM_MCAST_INDICATE; + vdev_param[wmi_vdev_param_dhcp_indicate] = WMI_VDEV_PARAM_DHCP_INDICATE; + vdev_param[wmi_vdev_param_unknown_dest_indicate] = + WMI_VDEV_PARAM_UNKNOWN_DEST_INDICATE; + vdev_param[wmi_vdev_param_ap_keepalive_min_idle_inactive_time_secs] = + WMI_VDEV_PARAM_AP_KEEPALIVE_MIN_IDLE_INACTIVE_TIME_SECS; + vdev_param[wmi_vdev_param_ap_keepalive_max_idle_inactive_time_secs] = + WMI_VDEV_PARAM_AP_KEEPALIVE_MAX_IDLE_INACTIVE_TIME_SECS; + vdev_param[wmi_vdev_param_ap_keepalive_max_unresponsive_time_secs] = + WMI_VDEV_PARAM_AP_KEEPALIVE_MAX_UNRESPONSIVE_TIME_SECS; + vdev_param[wmi_vdev_param_ap_enable_nawds] = + WMI_VDEV_PARAM_AP_ENABLE_NAWDS; + vdev_param[wmi_vdev_param_mcast2ucast_set] = + WMI_VDEV_PARAM_MCAST2UCAST_SET; + vdev_param[wmi_vdev_param_enable_rtscts] = WMI_VDEV_PARAM_ENABLE_RTSCTS; + vdev_param[wmi_vdev_param_rc_num_retries] = + WMI_VDEV_PARAM_RC_NUM_RETRIES; + vdev_param[wmi_vdev_param_txbf] = WMI_VDEV_PARAM_TXBF; + vdev_param[wmi_vdev_param_packet_powersave] = + WMI_VDEV_PARAM_PACKET_POWERSAVE; + vdev_param[wmi_vdev_param_drop_unencry] = WMI_VDEV_PARAM_DROP_UNENCRY; + vdev_param[wmi_vdev_param_tx_encap_type] = WMI_VDEV_PARAM_TX_ENCAP_TYPE; + vdev_param[wmi_vdev_param_ap_detect_out_of_sync_sleeping_sta_time_secs] + = WMI_VDEV_PARAM_AP_DETECT_OUT_OF_SYNC_SLEEPING_STA_TIME_SECS; + vdev_param[wmi_vdev_param_cabq_maxdur] = WMI_VDEV_PARAM_CABQ_MAXDUR; + vdev_param[wmi_vdev_param_mfptest_set] = WMI_VDEV_PARAM_MFPTEST_SET; + vdev_param[wmi_vdev_param_rts_fixed_rate] = + WMI_VDEV_PARAM_RTS_FIXED_RATE; + vdev_param[wmi_vdev_param_vht_sgimask] = WMI_VDEV_PARAM_VHT_SGIMASK; + vdev_param[wmi_vdev_param_vht80_ratemask] = + WMI_VDEV_PARAM_VHT80_RATEMASK; + vdev_param[wmi_vdev_param_early_rx_adjust_enable] = + WMI_VDEV_PARAM_EARLY_RX_ADJUST_ENABLE; + vdev_param[wmi_vdev_param_early_rx_tgt_bmiss_num] = + WMI_VDEV_PARAM_EARLY_RX_TGT_BMISS_NUM; + vdev_param[wmi_vdev_param_early_rx_bmiss_sample_cycle] = + WMI_VDEV_PARAM_EARLY_RX_BMISS_SAMPLE_CYCLE; + vdev_param[wmi_vdev_param_early_rx_slop_step] = + WMI_VDEV_PARAM_EARLY_RX_SLOP_STEP; + vdev_param[wmi_vdev_param_early_rx_init_slop] = + WMI_VDEV_PARAM_EARLY_RX_INIT_SLOP; + vdev_param[wmi_vdev_param_early_rx_adjust_pause] = + WMI_VDEV_PARAM_EARLY_RX_ADJUST_PAUSE; + vdev_param[wmi_vdev_param_proxy_sta] = WMI_VDEV_PARAM_PROXY_STA; + vdev_param[wmi_vdev_param_meru_vc] = WMI_VDEV_PARAM_MERU_VC; + vdev_param[wmi_vdev_param_rx_decap_type] = WMI_VDEV_PARAM_RX_DECAP_TYPE; + vdev_param[wmi_vdev_param_bw_nss_ratemask] = + WMI_VDEV_PARAM_BW_NSS_RATEMASK; + vdev_param[wmi_vdev_param_sensor_ap] = WMI_VDEV_PARAM_SENSOR_AP; + vdev_param[wmi_vdev_param_beacon_rate] = WMI_VDEV_PARAM_BEACON_RATE; + vdev_param[wmi_vdev_param_dtim_enable_cts] = + WMI_VDEV_PARAM_DTIM_ENABLE_CTS; + vdev_param[wmi_vdev_param_sta_kickout] = WMI_VDEV_PARAM_STA_KICKOUT; +} +#endif + +/** + * wmi_get_non_tlv_ops() - gives pointer to wmi tlv ops + * + * Return: pointer to wmi tlv ops + */ +void wmi_non_tlv_attach(struct wmi_unified *wmi_handle) +{ +#ifdef WMI_NON_TLV_SUPPORT + wmi_handle->ops = &non_tlv_ops; + populate_non_tlv_service(wmi_handle->services); + populate_non_tlv_events_id(wmi_handle->wmi_events); + populate_pdev_param_non_tlv(wmi_handle->pdev_param); + populate_vdev_param_non_tlv(wmi_handle->vdev_param); + +#ifdef WMI_INTERFACE_EVENT_LOGGING + wmi_handle->log_info.buf_offset_command = 0; + wmi_handle->log_info.buf_offset_event = 0; + wmi_handle->log_info.is_management_record = + is_management_record_non_tlv; + /*(uint8 *)(*wmi_id_to_name)(uint32_t cmd_id);*/ +#endif +#else + qdf_print("%s: Not supported\n", __func__); +#endif +} diff --git a/drivers/staging/qca-wifi-host-cmn/wmi/src/wmi_unified_tlv.c b/drivers/staging/qca-wifi-host-cmn/wmi/src/wmi_unified_tlv.c new file mode 100644 index 0000000000000000000000000000000000000000..694665b8c7ad10bb9bcf4e66bfa76ed681ccffb9 --- /dev/null +++ b/drivers/staging/qca-wifi-host-cmn/wmi/src/wmi_unified_tlv.c @@ -0,0 +1,13864 @@ +/* + * Copyright (c) 2016-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#include "wmi_unified_tlv.h" +#include "wmi_unified_api.h" +#include "wmi.h" +#include "wmi_version.h" +#include "wmi_unified_priv.h" +#include "wmi_version_whitelist.h" + +/** + * send_vdev_create_cmd_tlv() - send VDEV create command to fw + * @wmi_handle: wmi handle + * @param: pointer to hold vdev create parameter + * @macaddr: vdev mac address + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +QDF_STATUS send_vdev_create_cmd_tlv(wmi_unified_t wmi_handle, + uint8_t macaddr[IEEE80211_ADDR_LEN], + struct vdev_create_params *param) +{ + wmi_vdev_create_cmd_fixed_param *cmd; + wmi_buf_t buf; + int32_t len = sizeof(*cmd); + QDF_STATUS ret; + int num_bands = 2; + uint8_t *buf_ptr; + wmi_vdev_txrx_streams *txrx_streams; + + len += (num_bands * sizeof(*txrx_streams) + WMI_TLV_HDR_SIZE); + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMI_LOGP("%s:wmi_buf_alloc failed", __func__); + return QDF_STATUS_E_NOMEM; + } + cmd = (wmi_vdev_create_cmd_fixed_param *) wmi_buf_data(buf); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_vdev_create_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_vdev_create_cmd_fixed_param)); + cmd->vdev_id = param->if_id; + cmd->vdev_type = param->type; + cmd->vdev_subtype = param->subtype; + cmd->num_cfg_txrx_streams = num_bands; + cmd->pdev_id = WMI_PDEV_ID_SOC; + WMI_CHAR_ARRAY_TO_MAC_ADDR(macaddr, &cmd->vdev_macaddr); + WMI_LOGD("%s: ID = %d VAP Addr = %02x:%02x:%02x:%02x:%02x:%02x", + __func__, param->if_id, + macaddr[0], macaddr[1], macaddr[2], + macaddr[3], macaddr[4], macaddr[5]); + buf_ptr = (uint8_t *)cmd + sizeof(*cmd); + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, + (num_bands * sizeof(wmi_vdev_txrx_streams))); + buf_ptr += WMI_TLV_HDR_SIZE; + + WMI_LOGD("%s: type %d, subtype %d, nss_2g %d, nss_5g %d", __func__, + param->type, param->subtype, + param->nss_2g, param->nss_5g); + txrx_streams = (wmi_vdev_txrx_streams *)buf_ptr; + txrx_streams->band = WMI_TPC_CHAINMASK_CONFIG_BAND_2G; + txrx_streams->supported_tx_streams = param->nss_2g; + txrx_streams->supported_rx_streams = param->nss_2g; + WMITLV_SET_HDR(&txrx_streams->tlv_header, + WMITLV_TAG_STRUC_wmi_vdev_txrx_streams, + WMITLV_GET_STRUCT_TLVLEN(wmi_vdev_txrx_streams)); + + txrx_streams++; + txrx_streams->band = WMI_TPC_CHAINMASK_CONFIG_BAND_5G; + txrx_streams->supported_tx_streams = param->nss_5g; + txrx_streams->supported_rx_streams = param->nss_5g; + WMITLV_SET_HDR(&txrx_streams->tlv_header, + WMITLV_TAG_STRUC_wmi_vdev_txrx_streams, + WMITLV_GET_STRUCT_TLVLEN(wmi_vdev_txrx_streams)); + ret = wmi_unified_cmd_send(wmi_handle, buf, len, WMI_VDEV_CREATE_CMDID); + if (QDF_IS_STATUS_ERROR(ret)) { + WMI_LOGE("Failed to send WMI_VDEV_CREATE_CMDID"); + wmi_buf_free(buf); + } + + return ret; +} + +/** + * send_vdev_delete_cmd_tlv() - send VDEV delete command to fw + * @wmi_handle: wmi handle + * @if_id: vdev id + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +QDF_STATUS send_vdev_delete_cmd_tlv(wmi_unified_t wmi_handle, + uint8_t if_id) +{ + wmi_vdev_delete_cmd_fixed_param *cmd; + wmi_buf_t buf; + QDF_STATUS ret; + + buf = wmi_buf_alloc(wmi_handle, sizeof(*cmd)); + if (!buf) { + WMI_LOGP("%s:wmi_buf_alloc failed", __func__); + return QDF_STATUS_E_NOMEM; + } + + cmd = (wmi_vdev_delete_cmd_fixed_param *) wmi_buf_data(buf); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_vdev_delete_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_vdev_delete_cmd_fixed_param)); + cmd->vdev_id = if_id; + ret = wmi_unified_cmd_send(wmi_handle, buf, + sizeof(wmi_vdev_delete_cmd_fixed_param), + WMI_VDEV_DELETE_CMDID); + if (QDF_IS_STATUS_ERROR(ret)) { + WMI_LOGE("Failed to send WMI_VDEV_DELETE_CMDID"); + wmi_buf_free(buf); + } + WMI_LOGD("%s:vdev id = %d", __func__, if_id); + + return ret; +} + +/** + * send_vdev_stop_cmd_tlv() - send vdev stop command to fw + * @wmi: wmi handle + * @vdev_id: vdev id + * + * Return: QDF_STATUS_SUCCESS for success or erro code + */ +QDF_STATUS send_vdev_stop_cmd_tlv(wmi_unified_t wmi, + uint8_t vdev_id) +{ + wmi_vdev_stop_cmd_fixed_param *cmd; + wmi_buf_t buf; + int32_t len = sizeof(*cmd); + + buf = wmi_buf_alloc(wmi, len); + if (!buf) { + WMI_LOGP("%s : wmi_buf_alloc failed", __func__); + return QDF_STATUS_E_NOMEM; + } + cmd = (wmi_vdev_stop_cmd_fixed_param *) wmi_buf_data(buf); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_vdev_stop_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN(wmi_vdev_stop_cmd_fixed_param)); + cmd->vdev_id = vdev_id; + if (wmi_unified_cmd_send(wmi, buf, len, WMI_VDEV_STOP_CMDID)) { + WMI_LOGP("%s: Failed to send vdev stop command", __func__); + wmi_buf_free(buf); + return QDF_STATUS_E_FAILURE; + } + + return 0; +} + +/** + * send_vdev_down_cmd_tlv() - send vdev down command to fw + * @wmi: wmi handle + * @vdev_id: vdev id + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +QDF_STATUS send_vdev_down_cmd_tlv(wmi_unified_t wmi, uint8_t vdev_id) +{ + wmi_vdev_down_cmd_fixed_param *cmd; + wmi_buf_t buf; + int32_t len = sizeof(*cmd); + + buf = wmi_buf_alloc(wmi, len); + if (!buf) { + WMI_LOGP("%s : wmi_buf_alloc failed", __func__); + return QDF_STATUS_E_NOMEM; + } + cmd = (wmi_vdev_down_cmd_fixed_param *) wmi_buf_data(buf); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_vdev_down_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN(wmi_vdev_down_cmd_fixed_param)); + cmd->vdev_id = vdev_id; + if (wmi_unified_cmd_send(wmi, buf, len, WMI_VDEV_DOWN_CMDID)) { + WMI_LOGP("%s: Failed to send vdev down", __func__); + wmi_buf_free(buf); + return QDF_STATUS_E_FAILURE; + } + WMI_LOGD("%s: vdev_id %d", __func__, vdev_id); + + return 0; +} + +/** + * send_vdev_start_cmd_tlv() - send vdev start request to fw + * @wmi_handle: wmi handle + * @req: vdev start params + * + * Return: QDF status + */ +QDF_STATUS send_vdev_start_cmd_tlv(wmi_unified_t wmi_handle, + struct vdev_start_params *req) +{ + wmi_vdev_start_request_cmd_fixed_param *cmd; + wmi_buf_t buf; + wmi_channel *chan; + int32_t len, ret; + uint8_t *buf_ptr; + + len = sizeof(*cmd) + sizeof(wmi_channel) + WMI_TLV_HDR_SIZE; + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMI_LOGE("%s : wmi_buf_alloc failed", __func__); + return QDF_STATUS_E_NOMEM; + } + buf_ptr = (uint8_t *) wmi_buf_data(buf); + cmd = (wmi_vdev_start_request_cmd_fixed_param *) buf_ptr; + chan = (wmi_channel *) (buf_ptr + sizeof(*cmd)); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_vdev_start_request_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_vdev_start_request_cmd_fixed_param)); + WMITLV_SET_HDR(&chan->tlv_header, WMITLV_TAG_STRUC_wmi_channel, + WMITLV_GET_STRUCT_TLVLEN(wmi_channel)); + cmd->vdev_id = req->vdev_id; + + /* Fill channel info */ + chan->mhz = req->chan_freq; + + WMI_SET_CHANNEL_MODE(chan, req->chan_mode); + + chan->band_center_freq1 = req->band_center_freq1; + chan->band_center_freq2 = req->band_center_freq2; + + if (req->is_half_rate) + WMI_SET_CHANNEL_FLAG(chan, WMI_CHAN_FLAG_HALF_RATE); + else if (req->is_quarter_rate) + WMI_SET_CHANNEL_FLAG(chan, WMI_CHAN_FLAG_QUARTER_RATE); + + if (req->is_dfs && req->flag_dfs) { + WMI_SET_CHANNEL_FLAG(chan, req->flag_dfs); + cmd->disable_hw_ack = req->dis_hw_ack; + } + + cmd->beacon_interval = req->beacon_intval; + cmd->dtim_period = req->dtim_period; + /* FIXME: Find out min, max and regulatory power levels */ + WMI_SET_CHANNEL_REG_POWER(chan, req->max_txpow); + WMI_SET_CHANNEL_MAX_TX_POWER(chan, req->max_txpow); + + if (!req->is_restart) { + cmd->beacon_interval = req->beacon_intval; + cmd->dtim_period = req->dtim_period; + + /* Copy the SSID */ + if (req->ssid.length) { + if (req->ssid.length < sizeof(cmd->ssid.ssid)) + cmd->ssid.ssid_len = req->ssid.length; + else + cmd->ssid.ssid_len = sizeof(cmd->ssid.ssid); + qdf_mem_copy(cmd->ssid.ssid, req->ssid.mac_ssid, + cmd->ssid.ssid_len); + } + + if (req->hidden_ssid) + cmd->flags |= WMI_UNIFIED_VDEV_START_HIDDEN_SSID; + + if (req->pmf_enabled) + cmd->flags |= WMI_UNIFIED_VDEV_START_PMF_ENABLED; + } + + cmd->num_noa_descriptors = req->num_noa_descriptors; + cmd->preferred_rx_streams = req->preferred_rx_streams; + cmd->preferred_tx_streams = req->preferred_tx_streams; + + buf_ptr = (uint8_t *) (((uintptr_t) cmd) + sizeof(*cmd) + + sizeof(wmi_channel)); + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, + cmd->num_noa_descriptors * + sizeof(wmi_p2p_noa_descriptor)); + WMI_LOGA("%s: vdev_id %d freq %d chanmode %d ch_info: 0x%x is_dfs %d " + "beacon interval %d dtim %d center_chan %d center_freq2 %d " + "reg_info_1: 0x%x reg_info_2: 0x%x, req->max_txpow: 0x%x " + "Tx SS %d, Rx SS %d", + __func__, req->vdev_id, chan->mhz, req->chan_mode, chan->info, + req->is_dfs, req->beacon_intval, cmd->dtim_period, + chan->band_center_freq1, chan->band_center_freq2, + chan->reg_info_1, chan->reg_info_2, req->max_txpow, + req->preferred_tx_streams, req->preferred_rx_streams); + + if (req->is_restart) + ret = wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_VDEV_RESTART_REQUEST_CMDID); + else + ret = wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_VDEV_START_REQUEST_CMDID); + if (ret) { + WMI_LOGP("%s: Failed to send vdev start command", __func__); + wmi_buf_free(buf); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * send_hidden_ssid_vdev_restart_cmd_tlv() - restart vdev to set hidden ssid + * @wmi_handle: wmi handle + * @restart_params: vdev restart params + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +QDF_STATUS send_hidden_ssid_vdev_restart_cmd_tlv(wmi_unified_t wmi_handle, + struct hidden_ssid_vdev_restart_params *restart_params) +{ + wmi_vdev_start_request_cmd_fixed_param *cmd; + wmi_buf_t buf; + wmi_channel *chan; + int32_t len; + uint8_t *buf_ptr; + QDF_STATUS ret = 0; + + len = sizeof(*cmd) + sizeof(wmi_channel) + WMI_TLV_HDR_SIZE; + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMI_LOGE("%s : wmi_buf_alloc failed", __func__); + return QDF_STATUS_E_NOMEM; + } + buf_ptr = (uint8_t *) wmi_buf_data(buf); + cmd = (wmi_vdev_start_request_cmd_fixed_param *) buf_ptr; + chan = (wmi_channel *) (buf_ptr + sizeof(*cmd)); + + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_vdev_start_request_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_vdev_start_request_cmd_fixed_param)); + + WMITLV_SET_HDR(&chan->tlv_header, + WMITLV_TAG_STRUC_wmi_channel, + WMITLV_GET_STRUCT_TLVLEN(wmi_channel)); + + cmd->vdev_id = restart_params->session_id; + cmd->ssid.ssid_len = restart_params->ssid_len; + qdf_mem_copy(cmd->ssid.ssid, + restart_params->ssid, + cmd->ssid.ssid_len); + cmd->flags = restart_params->flags; + cmd->requestor_id = restart_params->requestor_id; + cmd->disable_hw_ack = restart_params->disable_hw_ack; + + chan->mhz = restart_params->mhz; + chan->band_center_freq1 = + restart_params->band_center_freq1; + chan->band_center_freq2 = + restart_params->band_center_freq2; + chan->info = restart_params->info; + chan->reg_info_1 = restart_params->reg_info_1; + chan->reg_info_2 = restart_params->reg_info_2; + + cmd->num_noa_descriptors = 0; + buf_ptr = (uint8_t *) (((uint8_t *) cmd) + sizeof(*cmd) + + sizeof(wmi_channel)); + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, + cmd->num_noa_descriptors * + sizeof(wmi_p2p_noa_descriptor)); + + ret = wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_VDEV_RESTART_REQUEST_CMDID); + if (QDF_IS_STATUS_ERROR(ret)) { + wmi_buf_free(buf); + return QDF_STATUS_E_FAILURE; + } + return QDF_STATUS_SUCCESS; +} + + +/** + * send_peer_flush_tids_cmd_tlv() - flush peer tids packets in fw + * @wmi: wmi handle + * @peer_addr: peer mac address + * @param: pointer to hold peer flush tid parameter + * + * Return: 0 for sucess or error code + */ +QDF_STATUS send_peer_flush_tids_cmd_tlv(wmi_unified_t wmi, + uint8_t peer_addr[IEEE80211_ADDR_LEN], + struct peer_flush_params *param) +{ + wmi_peer_flush_tids_cmd_fixed_param *cmd; + wmi_buf_t buf; + int32_t len = sizeof(*cmd); + + buf = wmi_buf_alloc(wmi, len); + if (!buf) { + WMI_LOGP("%s: wmi_buf_alloc failed", __func__); + return QDF_STATUS_E_NOMEM; + } + cmd = (wmi_peer_flush_tids_cmd_fixed_param *) wmi_buf_data(buf); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_peer_flush_tids_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_peer_flush_tids_cmd_fixed_param)); + WMI_CHAR_ARRAY_TO_MAC_ADDR(peer_addr, &cmd->peer_macaddr); + cmd->peer_tid_bitmap = param->peer_tid_bitmap; + cmd->vdev_id = param->vdev_id; + WMI_LOGD("%s: peer_addr %pM vdev_id %d and peer bitmap %d", __func__, + peer_addr, param->vdev_id, + param->peer_tid_bitmap); + if (wmi_unified_cmd_send(wmi, buf, len, WMI_PEER_FLUSH_TIDS_CMDID)) { + WMI_LOGP("%s: Failed to send flush tid command", __func__); + wmi_buf_free(buf); + return QDF_STATUS_E_FAILURE; + } + + return 0; +} + +/** + * send_peer_delete_cmd_tlv() - send PEER delete command to fw + * @wmi: wmi handle + * @peer_addr: peer mac addr + * @vdev_id: vdev id + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +QDF_STATUS send_peer_delete_cmd_tlv(wmi_unified_t wmi, + uint8_t peer_addr[IEEE80211_ADDR_LEN], + uint8_t vdev_id) +{ + wmi_peer_delete_cmd_fixed_param *cmd; + wmi_buf_t buf; + int32_t len = sizeof(*cmd); + buf = wmi_buf_alloc(wmi, len); + if (!buf) { + WMI_LOGP("%s: wmi_buf_alloc failed", __func__); + return QDF_STATUS_E_NOMEM; + } + cmd = (wmi_peer_delete_cmd_fixed_param *) wmi_buf_data(buf); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_peer_delete_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_peer_delete_cmd_fixed_param)); + WMI_CHAR_ARRAY_TO_MAC_ADDR(peer_addr, &cmd->peer_macaddr); + cmd->vdev_id = vdev_id; + + WMI_LOGD("%s: peer_addr %pM vdev_id %d", __func__, peer_addr, vdev_id); + if (wmi_unified_cmd_send(wmi, buf, len, WMI_PEER_DELETE_CMDID)) { + WMI_LOGP("%s: Failed to send peer delete command", __func__); + wmi_buf_free(buf); + return QDF_STATUS_E_FAILURE; + } + + return 0; +} + +/** + * send_peer_param_cmd_tlv() - set peer parameter in fw + * @wmi: wmi handle + * @peer_addr: peer mac address + * @param : pointer to hold peer set parameter + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +QDF_STATUS send_peer_param_cmd_tlv(wmi_unified_t wmi, + uint8_t peer_addr[IEEE80211_ADDR_LEN], + struct peer_set_params *param) +{ + wmi_peer_set_param_cmd_fixed_param *cmd; + wmi_buf_t buf; + int32_t err; + + buf = wmi_buf_alloc(wmi, sizeof(*cmd)); + if (!buf) { + WMI_LOGE("Failed to allocate buffer to send set_param cmd"); + return QDF_STATUS_E_NOMEM; + } + cmd = (wmi_peer_set_param_cmd_fixed_param *) wmi_buf_data(buf); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_peer_set_param_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_peer_set_param_cmd_fixed_param)); + cmd->vdev_id = param->vdev_id; + WMI_CHAR_ARRAY_TO_MAC_ADDR(peer_addr, &cmd->peer_macaddr); + cmd->param_id = param->param_id; + cmd->param_value = param->param_value; + err = wmi_unified_cmd_send(wmi, buf, + sizeof(wmi_peer_set_param_cmd_fixed_param), + WMI_PEER_SET_PARAM_CMDID); + if (err) { + WMI_LOGE("Failed to send set_param cmd"); + wmi_buf_free(buf); + return QDF_STATUS_E_FAILURE; + } + + return 0; +} + +/** + * send_vdev_up_cmd_tlv() - send vdev up command in fw + * @wmi: wmi handle + * @bssid: bssid + * @vdev_up_params: pointer to hold vdev up parameter + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +QDF_STATUS send_vdev_up_cmd_tlv(wmi_unified_t wmi, + uint8_t bssid[IEEE80211_ADDR_LEN], + struct vdev_up_params *params) +{ + wmi_vdev_up_cmd_fixed_param *cmd; + wmi_buf_t buf; + int32_t len = sizeof(*cmd); + + WMI_LOGD("%s: VDEV_UP", __func__); + WMI_LOGD("%s: vdev_id %d aid %d bssid %pM", __func__, + params->vdev_id, params->assoc_id, bssid); + buf = wmi_buf_alloc(wmi, len); + if (!buf) { + WMI_LOGP("%s: wmi_buf_alloc failed", __func__); + return QDF_STATUS_E_NOMEM; + } + cmd = (wmi_vdev_up_cmd_fixed_param *) wmi_buf_data(buf); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_vdev_up_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN(wmi_vdev_up_cmd_fixed_param)); + cmd->vdev_id = params->vdev_id; + cmd->vdev_assoc_id = params->assoc_id; + WMI_CHAR_ARRAY_TO_MAC_ADDR(bssid, &cmd->vdev_bssid); + if (wmi_unified_cmd_send(wmi, buf, len, WMI_VDEV_UP_CMDID)) { + WMI_LOGP("%s: Failed to send vdev up command", __func__); + wmi_buf_free(buf); + return QDF_STATUS_E_FAILURE; + } + + return 0; +} + +/** + * send_peer_create_cmd_tlv() - send peer create command to fw + * @wmi: wmi handle + * @peer_addr: peer mac address + * @peer_type: peer type + * @vdev_id: vdev id + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +QDF_STATUS send_peer_create_cmd_tlv(wmi_unified_t wmi, + struct peer_create_params *param) +{ + wmi_peer_create_cmd_fixed_param *cmd; + wmi_buf_t buf; + int32_t len = sizeof(*cmd); + + buf = wmi_buf_alloc(wmi, len); + if (!buf) { + WMI_LOGP("%s: wmi_buf_alloc failed", __func__); + return QDF_STATUS_E_NOMEM; + } + cmd = (wmi_peer_create_cmd_fixed_param *) wmi_buf_data(buf); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_peer_create_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_peer_create_cmd_fixed_param)); + WMI_CHAR_ARRAY_TO_MAC_ADDR(param->peer_addr, &cmd->peer_macaddr); + cmd->peer_type = param->peer_type; + cmd->vdev_id = param->vdev_id; + + if (wmi_unified_cmd_send(wmi, buf, len, WMI_PEER_CREATE_CMDID)) { + WMI_LOGP("%s: failed to send WMI_PEER_CREATE_CMDID", __func__); + wmi_buf_free(buf); + return QDF_STATUS_E_FAILURE; + } + WMI_LOGD("%s: peer_addr %pM vdev_id %d", __func__, param->peer_addr, + param->vdev_id); + + return 0; +} + +/** + * send_green_ap_ps_cmd_tlv() - enable green ap powersave command + * @wmi_handle: wmi handle + * @value: value + * @mac_id: mac id to have radio context + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +QDF_STATUS send_green_ap_ps_cmd_tlv(wmi_unified_t wmi_handle, + uint32_t value, uint8_t mac_id) +{ + wmi_pdev_green_ap_ps_enable_cmd_fixed_param *cmd; + wmi_buf_t buf; + int32_t len = sizeof(*cmd); + + WMI_LOGD("Set Green AP PS val %d", value); + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMI_LOGP("%s: Green AP PS Mem Alloc Failed", __func__); + return QDF_STATUS_E_NOMEM; + } + + cmd = (wmi_pdev_green_ap_ps_enable_cmd_fixed_param *) wmi_buf_data(buf); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_pdev_green_ap_ps_enable_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_pdev_green_ap_ps_enable_cmd_fixed_param)); + cmd->pdev_id = 0; + cmd->enable = value; + + if (wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_PDEV_GREEN_AP_PS_ENABLE_CMDID)) { + WMI_LOGE("Set Green AP PS param Failed val %d", value); + wmi_buf_free(buf); + return QDF_STATUS_E_FAILURE; + } + + return 0; +} + +/** + * send_pdev_utf_cmd_tlv() - send utf command to fw + * @wmi_handle: wmi handle + * @param: pointer to pdev_utf_params + * @mac_id: mac id to have radio context + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +QDF_STATUS +send_pdev_utf_cmd_tlv(wmi_unified_t wmi_handle, + struct pdev_utf_params *param, + uint8_t mac_id) +{ + wmi_buf_t buf; + uint8_t *cmd; + /* if param->len is 0 no data is sent, return error */ + QDF_STATUS ret = QDF_STATUS_E_INVAL; + static uint8_t msgref = 1; + uint8_t segNumber = 0, segInfo, numSegments; + uint16_t chunk_len, total_bytes; + uint8_t *bufpos; + struct seg_hdr_info segHdrInfo; + + bufpos = param->utf_payload; + total_bytes = param->len; + ASSERT(total_bytes / MAX_WMI_UTF_LEN == + (uint8_t) (total_bytes / MAX_WMI_UTF_LEN)); + numSegments = (uint8_t) (total_bytes / MAX_WMI_UTF_LEN); + + if (param->len - (numSegments * MAX_WMI_UTF_LEN)) + numSegments++; + + while (param->len) { + if (param->len > MAX_WMI_UTF_LEN) + chunk_len = MAX_WMI_UTF_LEN; /* MAX messsage */ + else + chunk_len = param->len; + + buf = wmi_buf_alloc(wmi_handle, + (chunk_len + sizeof(segHdrInfo) + + WMI_TLV_HDR_SIZE)); + if (!buf) { + WMI_LOGE("%s:wmi_buf_alloc failed", __func__); + return QDF_STATUS_E_NOMEM; + } + + cmd = (uint8_t *) wmi_buf_data(buf); + + segHdrInfo.len = total_bytes; + segHdrInfo.msgref = msgref; + segInfo = ((numSegments << 4) & 0xF0) | (segNumber & 0xF); + segHdrInfo.segmentInfo = segInfo; + segHdrInfo.pad = 0; + + WMI_LOGD("%s:segHdrInfo.len = %d, segHdrInfo.msgref = %d," + " segHdrInfo.segmentInfo = %d", + __func__, segHdrInfo.len, segHdrInfo.msgref, + segHdrInfo.segmentInfo); + + WMI_LOGD("%s:total_bytes %d segNumber %d totalSegments %d" + "chunk len %d", __func__, total_bytes, segNumber, + numSegments, chunk_len); + + segNumber++; + + WMITLV_SET_HDR(cmd, WMITLV_TAG_ARRAY_BYTE, + (chunk_len + sizeof(segHdrInfo))); + cmd += WMI_TLV_HDR_SIZE; + memcpy(cmd, &segHdrInfo, sizeof(segHdrInfo)); /* 4 bytes */ + memcpy(&cmd[sizeof(segHdrInfo)], bufpos, chunk_len); + + ret = wmi_unified_cmd_send(wmi_handle, buf, + (chunk_len + sizeof(segHdrInfo) + + WMI_TLV_HDR_SIZE), + WMI_PDEV_UTF_CMDID); + + if (QDF_IS_STATUS_ERROR(ret)) { + WMI_LOGE("Failed to send WMI_PDEV_UTF_CMDID command"); + wmi_buf_free(buf); + break; + } + + param->len -= chunk_len; + bufpos += chunk_len; + } + + msgref++; + + return ret; +} + +/** + * send_pdev_param_cmd_tlv() - set pdev parameters + * @wmi_handle: wmi handle + * @param: pointer to pdev parameter + * @mac_id: radio context + * + * Return: 0 on success, errno on failure + */ +QDF_STATUS +send_pdev_param_cmd_tlv(wmi_unified_t wmi_handle, + struct pdev_params *param, + uint8_t mac_id) +{ + QDF_STATUS ret; + wmi_pdev_set_param_cmd_fixed_param *cmd; + wmi_buf_t buf; + uint16_t len = sizeof(*cmd); + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMI_LOGE("%s:wmi_buf_alloc failed", __func__); + return QDF_STATUS_E_NOMEM; + } + cmd = (wmi_pdev_set_param_cmd_fixed_param *) wmi_buf_data(buf); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_pdev_set_param_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_pdev_set_param_cmd_fixed_param)); + cmd->pdev_id = 0; + cmd->param_id = param->param_id; + cmd->param_value = param->param_value; + WMI_LOGD("Setting pdev param = %x, value = %u", param->param_id, + param->param_value); + ret = wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_PDEV_SET_PARAM_CMDID); + if (QDF_IS_STATUS_ERROR(ret)) { + WMI_LOGE("Failed to send set param command ret = %d", ret); + wmi_buf_free(buf); + } + return ret; +} + +/** + * send_suspend_cmd_tlv() - WMI suspend function + * @param wmi_handle : handle to WMI. + * @param param : pointer to hold suspend parameter + * @mac_id: radio context + * + * Return 0 on success and -ve on failure. + */ +QDF_STATUS send_suspend_cmd_tlv(wmi_unified_t wmi_handle, + struct suspend_params *param, + uint8_t mac_id) +{ + wmi_pdev_suspend_cmd_fixed_param *cmd; + wmi_buf_t wmibuf; + uint32_t len = sizeof(*cmd); + int32_t ret; + + /* + * send the comand to Target to ignore the + * PCIE reset so as to ensure that Host and target + * states are in sync + */ + wmibuf = wmi_buf_alloc(wmi_handle, len); + if (wmibuf == NULL) + return QDF_STATUS_E_NOMEM; + + cmd = (wmi_pdev_suspend_cmd_fixed_param *) wmi_buf_data(wmibuf); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_pdev_suspend_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_pdev_suspend_cmd_fixed_param)); + if (param->disable_target_intr) + cmd->suspend_opt = WMI_PDEV_SUSPEND_AND_DISABLE_INTR; + else + cmd->suspend_opt = WMI_PDEV_SUSPEND; + ret = wmi_unified_cmd_send(wmi_handle, wmibuf, len, + WMI_PDEV_SUSPEND_CMDID); + if (ret) { + wmi_buf_free(wmibuf); + WMI_LOGE("Failed to send WMI_PDEV_SUSPEND_CMDID command"); + } + + return ret; +} + +/** + * send_resume_cmd_tlv() - WMI resume function + * @param wmi_handle : handle to WMI. + * @mac_id: radio context + * + * Return: 0 on success and -ve on failure. + */ +QDF_STATUS send_resume_cmd_tlv(wmi_unified_t wmi_handle, + uint8_t mac_id) +{ + wmi_buf_t wmibuf; + wmi_pdev_resume_cmd_fixed_param *cmd; + QDF_STATUS ret; + + wmibuf = wmi_buf_alloc(wmi_handle, sizeof(*cmd)); + if (wmibuf == NULL) + return QDF_STATUS_E_NOMEM; + cmd = (wmi_pdev_resume_cmd_fixed_param *) wmi_buf_data(wmibuf); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_pdev_resume_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_pdev_resume_cmd_fixed_param)); + cmd->pdev_id = WMI_PDEV_ID_SOC; + ret = wmi_unified_cmd_send(wmi_handle, wmibuf, sizeof(*cmd), + WMI_PDEV_RESUME_CMDID); + if (QDF_IS_STATUS_ERROR(ret)) { + WMI_LOGE("Failed to send WMI_PDEV_RESUME_CMDID command"); + wmi_buf_free(wmibuf); + } + + return ret; +} + +/** + * send_wow_enable_cmd_tlv() - WMI wow enable function + * @param wmi_handle : handle to WMI. + * @param param : pointer to hold wow enable parameter + * @mac_id: radio context + * + * Return: 0 on success and -ve on failure. + */ +QDF_STATUS send_wow_enable_cmd_tlv(wmi_unified_t wmi_handle, + struct wow_cmd_params *param, + uint8_t mac_id) +{ + wmi_wow_enable_cmd_fixed_param *cmd; + wmi_buf_t buf; + int32_t len; + int32_t ret; + + len = sizeof(wmi_wow_enable_cmd_fixed_param); + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMI_LOGE("%s: Failed allocate wmi buffer", __func__); + return QDF_STATUS_E_NOMEM; + } + cmd = (wmi_wow_enable_cmd_fixed_param *) wmi_buf_data(buf); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_wow_enable_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_wow_enable_cmd_fixed_param)); + cmd->enable = param->enable; + if (param->can_suspend_link) + cmd->pause_iface_config = WOW_IFACE_PAUSE_ENABLED; + else + cmd->pause_iface_config = WOW_IFACE_PAUSE_DISABLED; + cmd->flags = param->flags; + + WMI_LOGI("suspend type: %s", + cmd->pause_iface_config == WOW_IFACE_PAUSE_ENABLED ? + "WOW_IFACE_PAUSE_ENABLED" : "WOW_IFACE_PAUSE_DISABLED"); + + ret = wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_WOW_ENABLE_CMDID); + if (ret) + wmi_buf_free(buf); + + return ret; +} + +/** + * send_set_ap_ps_param_cmd_tlv() - set ap powersave parameters + * @wmi_handle: wmi handle + * @peer_addr: peer mac address + * @param: pointer to ap_ps parameter structure + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +QDF_STATUS send_set_ap_ps_param_cmd_tlv(wmi_unified_t wmi_handle, + uint8_t *peer_addr, + struct ap_ps_params *param) +{ + wmi_ap_ps_peer_cmd_fixed_param *cmd; + wmi_buf_t buf; + int32_t err; + + buf = wmi_buf_alloc(wmi_handle, sizeof(*cmd)); + if (!buf) { + WMI_LOGE("Failed to allocate buffer to send set_ap_ps_param cmd"); + return QDF_STATUS_E_NOMEM; + } + cmd = (wmi_ap_ps_peer_cmd_fixed_param *) wmi_buf_data(buf); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_ap_ps_peer_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_ap_ps_peer_cmd_fixed_param)); + cmd->vdev_id = param->vdev_id; + WMI_CHAR_ARRAY_TO_MAC_ADDR(peer_addr, &cmd->peer_macaddr); + cmd->param = param->param; + cmd->value = param->value; + err = wmi_unified_cmd_send(wmi_handle, buf, + sizeof(*cmd), WMI_AP_PS_PEER_PARAM_CMDID); + if (err) { + WMI_LOGE("Failed to send set_ap_ps_param cmd"); + wmi_buf_free(buf); + return QDF_STATUS_E_FAILURE; + } + + return 0; +} + +/** + * send_set_sta_ps_param_cmd_tlv() - set sta powersave parameters + * @wmi_handle: wmi handle + * @peer_addr: peer mac address + * @param: pointer to sta_ps parameter structure + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +QDF_STATUS send_set_sta_ps_param_cmd_tlv(wmi_unified_t wmi_handle, + struct sta_ps_params *param) +{ + wmi_sta_powersave_param_cmd_fixed_param *cmd; + wmi_buf_t buf; + int32_t len = sizeof(*cmd); + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMI_LOGP("%s: Set Sta Ps param Mem Alloc Failed", __func__); + return QDF_STATUS_E_NOMEM; + } + + cmd = (wmi_sta_powersave_param_cmd_fixed_param *) wmi_buf_data(buf); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_sta_powersave_param_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_sta_powersave_param_cmd_fixed_param)); + cmd->vdev_id = param->vdev_id; + cmd->param = param->param; + cmd->value = param->value; + + if (wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_STA_POWERSAVE_PARAM_CMDID)) { + WMI_LOGE("Set Sta Ps param Failed vdevId %d Param %d val %d", + param->vdev_id, param->param, param->value); + wmi_buf_free(buf); + return QDF_STATUS_E_FAILURE; + } + + return 0; +} + +/** + * send_crash_inject_cmd_tlv() - inject fw crash + * @wmi_handle: wmi handle + * @param: ponirt to crash inject paramter structure + * + * Return: QDF_STATUS_SUCCESS for success or return error + */ +QDF_STATUS send_crash_inject_cmd_tlv(wmi_unified_t wmi_handle, + struct crash_inject *param) +{ + int32_t ret = 0; + WMI_FORCE_FW_HANG_CMD_fixed_param *cmd; + uint16_t len = sizeof(*cmd); + wmi_buf_t buf; + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMI_LOGE("%s: wmi_buf_alloc failed!", __func__); + return QDF_STATUS_E_NOMEM; + } + + cmd = (WMI_FORCE_FW_HANG_CMD_fixed_param *) wmi_buf_data(buf); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_WMI_FORCE_FW_HANG_CMD_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (WMI_FORCE_FW_HANG_CMD_fixed_param)); + cmd->type = param->type; + cmd->delay_time_ms = param->delay_time_ms; + + ret = wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_FORCE_FW_HANG_CMDID); + if (ret) { + WMI_LOGE("%s: Failed to send set param command, ret = %d", + __func__, ret); + wmi_buf_free(buf); + } + + return ret; +} + +/** + * send_dbglog_cmd_tlv() - set debug log level + * @param wmi_handle : handle to WMI. + * @param param : pointer to hold dbglog level parameter + * + * Return: 0 on success and -ve on failure. + */ +QDF_STATUS +send_dbglog_cmd_tlv(wmi_unified_t wmi_handle, + struct dbglog_params *dbglog_param) +{ + wmi_buf_t buf; + wmi_debug_log_config_cmd_fixed_param *configmsg; + A_STATUS status = A_OK; + int32_t i; + int32_t len; + int8_t *buf_ptr; + int32_t *module_id_bitmap_array; /* Used to fomr the second tlv */ + + ASSERT(bitmap_len < MAX_MODULE_ID_BITMAP_WORDS); + + /* Allocate size for 2 tlvs - including tlv hdr space for second tlv */ + len = sizeof(wmi_debug_log_config_cmd_fixed_param) + WMI_TLV_HDR_SIZE + + (sizeof(int32_t) * MAX_MODULE_ID_BITMAP_WORDS); + buf = wmi_buf_alloc(wmi_handle, len); + if (buf == NULL) + return A_NO_MEMORY; + + configmsg = + (wmi_debug_log_config_cmd_fixed_param *) (wmi_buf_data(buf)); + buf_ptr = (int8_t *) configmsg; + WMITLV_SET_HDR(&configmsg->tlv_header, + WMITLV_TAG_STRUC_wmi_debug_log_config_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_debug_log_config_cmd_fixed_param)); + configmsg->dbg_log_param = dbglog_param->param; + configmsg->value = dbglog_param->val; + /* Filling in the data part of second tlv -- should + * follow first tlv _ WMI_TLV_HDR_SIZE */ + module_id_bitmap_array = (A_UINT32 *) (buf_ptr + + sizeof + (wmi_debug_log_config_cmd_fixed_param) + + WMI_TLV_HDR_SIZE); + WMITLV_SET_HDR(buf_ptr + sizeof(wmi_debug_log_config_cmd_fixed_param), + WMITLV_TAG_ARRAY_UINT32, + sizeof(A_UINT32) * MAX_MODULE_ID_BITMAP_WORDS); + if (dbglog_param->module_id_bitmap) { + for (i = 0; i < dbglog_param->bitmap_len; ++i) { + module_id_bitmap_array[i] = + dbglog_param->module_id_bitmap[i]; + } + } + + status = wmi_unified_cmd_send(wmi_handle, buf, + len, WMI_DBGLOG_CFG_CMDID); + + if (status != A_OK) + wmi_buf_free(buf); + + return status; +} + +/** + * send_vdev_set_param_cmd_tlv() - WMI vdev set parameter function + * @param wmi_handle : handle to WMI. + * @param macaddr : MAC address + * @param param : pointer to hold vdev set parameter + * + * Return: 0 on success and -ve on failure. + */ +QDF_STATUS send_vdev_set_param_cmd_tlv(wmi_unified_t wmi_handle, + struct vdev_set_params *param) +{ + QDF_STATUS ret; + wmi_vdev_set_param_cmd_fixed_param *cmd; + wmi_buf_t buf; + uint16_t len = sizeof(*cmd); + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMI_LOGE("%s:wmi_buf_alloc failed", __func__); + return QDF_STATUS_E_NOMEM; + } + cmd = (wmi_vdev_set_param_cmd_fixed_param *) wmi_buf_data(buf); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_vdev_set_param_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_vdev_set_param_cmd_fixed_param)); + cmd->vdev_id = param->if_id; + cmd->param_id = param->param_id; + cmd->param_value = param->param_value; + WMI_LOGD("Setting vdev %d param = %x, value = %u", + param->if_id, param->param_id, param->param_value); + ret = wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_VDEV_SET_PARAM_CMDID); + if (QDF_IS_STATUS_ERROR(ret)) { + WMI_LOGE("Failed to send set param command ret = %d", ret); + wmi_buf_free(buf); + } + + return ret; +} + +/** + * send_stats_request_cmd_tlv() - WMI request stats function + * @param wmi_handle : handle to WMI. + * @param macaddr : MAC address + * @param param : pointer to hold stats request parameter + * + * Return: 0 on success and -ve on failure. + */ +QDF_STATUS send_stats_request_cmd_tlv(wmi_unified_t wmi_handle, + uint8_t macaddr[IEEE80211_ADDR_LEN], + struct stats_request_params *param) +{ + int32_t ret; + wmi_request_stats_cmd_fixed_param *cmd; + wmi_buf_t buf; + uint16_t len = sizeof(wmi_request_stats_cmd_fixed_param); + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMI_LOGE("%s: wmi_buf_alloc failed", __func__); + return -QDF_STATUS_E_NOMEM; + } + + cmd = (wmi_request_stats_cmd_fixed_param *) wmi_buf_data(buf); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_request_stats_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_request_stats_cmd_fixed_param)); + cmd->stats_id = param->stats_id; + cmd->vdev_id = param->vdev_id; + ret = wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_REQUEST_STATS_CMDID); + if (ret) { + WMI_LOGE("Failed to send status request to fw =%d", ret); + wmi_buf_free(buf); + } + + return ret; +} + +#ifdef CONFIG_WIN +/** + * send_packet_log_enable_cmd_tlv() - WMI request stats function + * @param wmi_handle : handle to WMI. + * @param macaddr : MAC address + * @param param : pointer to hold stats request parameter + * + * Return: 0 on success and -ve on failure. + */ +QDF_STATUS send_packet_log_enable_cmd_tlv(wmi_unified_t wmi_handle, + WMI_HOST_PKTLOG_EVENT PKTLOG_EVENT) +{ + return 0; +} +#else +/** + * send_packet_log_enable_cmd_tlv() - WMI request stats function + * @param wmi_handle : handle to WMI. + * @param macaddr : MAC address + * @param param : pointer to hold stats request parameter + * + * Return: 0 on success and -ve on failure. + */ +QDF_STATUS send_packet_log_enable_cmd_tlv(wmi_unified_t wmi_handle, + uint8_t macaddr[IEEE80211_ADDR_LEN], + struct packet_enable_params *param) +{ + return 0; +} +#endif + +#ifdef CONFIG_MCL +/** + * send_beacon_send_cmd_tlv() - WMI beacon send function + * @param wmi_handle : handle to WMI. + * @param param : pointer to hold beacon send cmd parameter + * + * Return: 0 on success and -ve on failure. + */ +QDF_STATUS send_beacon_send_cmd_tlv(wmi_unified_t wmi_handle, + struct beacon_params *param) +{ + int32_t ret; + wmi_bcn_tmpl_cmd_fixed_param *cmd; + wmi_bcn_prb_info *bcn_prb_info; + wmi_buf_t wmi_buf; + uint8_t *buf_ptr; + uint32_t wmi_buf_len; + + wmi_buf_len = sizeof(wmi_bcn_tmpl_cmd_fixed_param) + + sizeof(wmi_bcn_prb_info) + WMI_TLV_HDR_SIZE + + param->tmpl_len_aligned; + wmi_buf = wmi_buf_alloc(wmi_handle, wmi_buf_len); + if (!wmi_buf) { + WMI_LOGE("%s : wmi_buf_alloc failed", __func__); + return QDF_STATUS_E_NOMEM; + } + buf_ptr = (uint8_t *) wmi_buf_data(wmi_buf); + cmd = (wmi_bcn_tmpl_cmd_fixed_param *) buf_ptr; + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_bcn_tmpl_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN(wmi_bcn_tmpl_cmd_fixed_param)); + cmd->vdev_id = param->vdev_id; + cmd->tim_ie_offset = param->tim_ie_offset; + cmd->buf_len = param->tmpl_len; + buf_ptr += sizeof(wmi_bcn_tmpl_cmd_fixed_param); + + bcn_prb_info = (wmi_bcn_prb_info *) buf_ptr; + WMITLV_SET_HDR(&bcn_prb_info->tlv_header, + WMITLV_TAG_STRUC_wmi_bcn_prb_info, + WMITLV_GET_STRUCT_TLVLEN(wmi_bcn_prb_info)); + bcn_prb_info->caps = 0; + bcn_prb_info->erp = 0; + buf_ptr += sizeof(wmi_bcn_prb_info); + + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE, param->tmpl_len_aligned); + buf_ptr += WMI_TLV_HDR_SIZE; + qdf_mem_copy(buf_ptr, param->frm, param->tmpl_len); + + ret = wmi_unified_cmd_send(wmi_handle, + wmi_buf, wmi_buf_len, WMI_BCN_TMPL_CMDID); + if (ret) { + WMI_LOGE("%s: Failed to send bcn tmpl: %d", __func__, ret); + wmi_buf_free(wmi_buf); + } + return 0; +} +#else +QDF_STATUS send_beacon_send_cmd_tlv(wmi_unified_t wmi_handle, + struct beacon_params *param) +{ + return 0; +} + +/** + * send_beacon_send_tmpl_cmd_tlv() - WMI beacon send function + * @param wmi_handle : handle to WMI. + * @param param : pointer to hold beacon send cmd parameter + * + * Return: 0 on success and -ve on failure. + */ +QDF_STATUS send_beacon_tmpl_send_cmd_tlv(wmi_unified_t wmi_handle, + struct beacon_tmpl_params *param) +{ + int32_t ret; + wmi_bcn_tmpl_cmd_fixed_param *cmd; + wmi_bcn_prb_info *bcn_prb_info; + wmi_buf_t wmi_buf; + uint8_t *buf_ptr; + uint32_t wmi_buf_len; + + wmi_buf_len = sizeof(wmi_bcn_tmpl_cmd_fixed_param) + + sizeof(wmi_bcn_prb_info) + WMI_TLV_HDR_SIZE + + param->tmpl_len_aligned; + wmi_buf = wmi_buf_alloc(wmi_handle, wmi_buf_len); + if (!wmi_buf) { + WMI_LOGE("%s : wmi_buf_alloc failed", __func__); + return QDF_STATUS_E_NOMEM; + } + buf_ptr = (uint8_t *) wmi_buf_data(wmi_buf); + cmd = (wmi_bcn_tmpl_cmd_fixed_param *) buf_ptr; + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_bcn_tmpl_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN(wmi_bcn_tmpl_cmd_fixed_param)); + cmd->vdev_id = param->vdev_id; + cmd->tim_ie_offset = param->tim_ie_offset; + cmd->buf_len = param->tmpl_len; + buf_ptr += sizeof(wmi_bcn_tmpl_cmd_fixed_param); + + bcn_prb_info = (wmi_bcn_prb_info *) buf_ptr; + WMITLV_SET_HDR(&bcn_prb_info->tlv_header, + WMITLV_TAG_STRUC_wmi_bcn_prb_info, + WMITLV_GET_STRUCT_TLVLEN(wmi_bcn_prb_info)); + bcn_prb_info->caps = 0; + bcn_prb_info->erp = 0; + buf_ptr += sizeof(wmi_bcn_prb_info); + + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE, param->tmpl_len_aligned); + buf_ptr += WMI_TLV_HDR_SIZE; + qdf_mem_copy(buf_ptr, param->frm, param->tmpl_len); + + ret = wmi_unified_cmd_send(wmi_handle, + wmi_buf, wmi_buf_len, WMI_BCN_TMPL_CMDID); + if (ret) { + WMI_LOGE("%s: Failed to send bcn tmpl: %d", __func__, ret); + wmi_buf_free(wmi_buf); + } + return 0; +} +#endif + +/** + * send_peer_assoc_cmd_tlv() - WMI peer assoc function + * @param wmi_handle : handle to WMI. + * @param param : pointer to peer assoc parameter + * + * Return: 0 on success and -ve on failure. + */ +QDF_STATUS send_peer_assoc_cmd_tlv(wmi_unified_t wmi_handle, + struct peer_assoc_params *param) +{ + wmi_peer_assoc_complete_cmd_fixed_param *cmd; + wmi_vht_rate_set *mcs; + wmi_buf_t buf; + int32_t len; + uint8_t *buf_ptr; + QDF_STATUS ret; + uint32_t peer_legacy_rates_align; + uint32_t peer_ht_rates_align; + + + peer_legacy_rates_align = wmi_align(param->peer_legacy_rates.num_rates); + peer_ht_rates_align = wmi_align(param->peer_ht_rates.num_rates); + + len = sizeof(*cmd) + WMI_TLV_HDR_SIZE + + (peer_legacy_rates_align * sizeof(uint8_t)) + + WMI_TLV_HDR_SIZE + + (peer_ht_rates_align * sizeof(uint8_t)) + + sizeof(wmi_vht_rate_set); + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMI_LOGE("%s: wmi_buf_alloc failed", __func__); + return QDF_STATUS_E_NOMEM; + } + + buf_ptr = (uint8_t *) wmi_buf_data(buf); + cmd = (wmi_peer_assoc_complete_cmd_fixed_param *) buf_ptr; + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_peer_assoc_complete_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_peer_assoc_complete_cmd_fixed_param)); + + cmd->vdev_id = param->vdev_id; + qdf_mem_copy(&cmd->peer_macaddr, ¶m->peer_macaddr, + sizeof(param->peer_macaddr)); + cmd->peer_new_assoc = param->peer_new_assoc; + cmd->peer_associd = param->peer_associd; + cmd->peer_flags = param->peer_flags; + cmd->peer_rate_caps = param->peer_rate_caps; + cmd->peer_caps = param->peer_caps; + cmd->peer_listen_intval = param->peer_listen_intval; + cmd->peer_ht_caps = param->peer_ht_caps; + cmd->peer_max_mpdu = param->peer_max_mpdu; + cmd->peer_mpdu_density = param->peer_mpdu_density; + cmd->peer_vht_caps = param->peer_vht_caps; + cmd->peer_phymode = param->peer_phymode; + + /* Update peer legacy rate information */ + buf_ptr += sizeof(*cmd); + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE, + peer_legacy_rates_align); + buf_ptr += WMI_TLV_HDR_SIZE; + cmd->num_peer_legacy_rates = param->peer_legacy_rates.num_rates; + qdf_mem_copy(buf_ptr, param->peer_legacy_rates.rates, + param->peer_legacy_rates.num_rates); + + /* Update peer HT rate information */ + buf_ptr += peer_legacy_rates_align; + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE, + peer_ht_rates_align); + buf_ptr += WMI_TLV_HDR_SIZE; + cmd->num_peer_ht_rates = param->peer_ht_rates.num_rates; + qdf_mem_copy(buf_ptr, param->peer_ht_rates.rates, + param->peer_ht_rates.num_rates); + + /* VHT Rates */ + buf_ptr += peer_ht_rates_align; + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_STRUC_wmi_vht_rate_set, + WMITLV_GET_STRUCT_TLVLEN(wmi_vht_rate_set)); + + cmd->peer_nss = param->peer_nss; + mcs = (wmi_vht_rate_set *) buf_ptr; + if (param->vht_capable) { + mcs->rx_max_rate = param->rx_max_rate; + mcs->rx_mcs_set = param->rx_mcs_set; + mcs->tx_max_rate = param->tx_max_rate; + mcs->tx_mcs_set = param->tx_mcs_set; + } + + WMI_LOGD("%s: vdev_id %d associd %d peer_flags %x rate_caps %x " + "peer_caps %x listen_intval %d ht_caps %x max_mpdu %d " + "nss %d phymode %d peer_mpdu_density %d " + "cmd->peer_vht_caps %x", __func__, + cmd->vdev_id, cmd->peer_associd, cmd->peer_flags, + cmd->peer_rate_caps, cmd->peer_caps, + cmd->peer_listen_intval, cmd->peer_ht_caps, + cmd->peer_max_mpdu, cmd->peer_nss, cmd->peer_phymode, + cmd->peer_mpdu_density, + cmd->peer_vht_caps); + + ret = wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_PEER_ASSOC_CMDID); + if (QDF_IS_STATUS_ERROR(ret)) { + WMI_LOGP("%s: Failed to send peer assoc command ret = %d", + __func__, ret); + wmi_buf_free(buf); + } + + return ret; +} + +/* + * wmi_fill_vendor_oui() - fill vendor OUIs + * @buf_ptr: pointer to wmi tlv buffer + * @num_vendor_oui: number of vendor OUIs to be filled + * @param_voui: pointer to OUI buffer + * + * This function populates the wmi tlv buffer when vendor specific OUIs are + * present. + * + * Return: None + */ +static void wmi_fill_vendor_oui(uint8_t *buf_ptr, uint32_t num_vendor_oui, + void *param_voui) +{ + wmi_vendor_oui *voui = NULL; + struct vendor_oui *pvoui = NULL; + uint32_t i; + + voui = (wmi_vendor_oui *)buf_ptr; + pvoui = (struct vendor_oui *)param_voui; + + for (i = 0; i < num_vendor_oui; i++) { + WMITLV_SET_HDR(&voui[i].tlv_header, + WMITLV_TAG_STRUC_wmi_vendor_oui, + WMITLV_GET_STRUCT_TLVLEN(wmi_vendor_oui)); + voui[i].oui_type_subtype = pvoui[i].oui_type | + (pvoui[i].oui_subtype << 24); + } +} + +/** + * send_scan_start_cmd_tlv() - WMI scan start function + * @param wmi_handle : handle to WMI. + * @param param : pointer to hold scan start cmd parameter + * + * Return: 0 on success and -ve on failure. + */ +QDF_STATUS send_scan_start_cmd_tlv(wmi_unified_t wmi_handle, + struct scan_start_params *params) +{ + int32_t ret = 0; + int32_t i; + wmi_buf_t wmi_buf; + wmi_start_scan_cmd_fixed_param *cmd; + uint8_t *buf_ptr; + uint32_t *tmp_ptr; + wmi_ssid *ssid = NULL; + wmi_mac_addr *bssid; + int len = sizeof(*cmd); + + /* Length TLV placeholder for array of uint32_t */ + len += WMI_TLV_HDR_SIZE; + /* calculate the length of buffer required */ + if (params->num_chan) + len += params->num_chan * sizeof(uint32_t); + + /* Length TLV placeholder for array of wmi_ssid structures */ + len += WMI_TLV_HDR_SIZE; + if (params->num_ssids) + len += params->num_ssids * sizeof(wmi_ssid); + + /* Length TLV placeholder for array of wmi_mac_addr structures */ + len += WMI_TLV_HDR_SIZE; + len += sizeof(wmi_mac_addr); + + /* Length TLV placeholder for array of bytes */ + len += WMI_TLV_HDR_SIZE; + if (params->ie_len) + len += roundup(params->ie_len, sizeof(uint32_t)); + + len += WMI_TLV_HDR_SIZE; /* Length of TLV for array of wmi_vendor_oui */ + if (params->num_vendor_oui) + len += params->num_vendor_oui * sizeof(wmi_vendor_oui); + + /* Allocate the memory */ + wmi_buf = wmi_buf_alloc(wmi_handle, len); + if (!wmi_buf) { + WMI_LOGP("%s: failed to allocate memory for start scan cmd", + __func__); + return QDF_STATUS_E_FAILURE; + } + buf_ptr = (uint8_t *) wmi_buf_data(wmi_buf); + cmd = (wmi_start_scan_cmd_fixed_param *) buf_ptr; + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_start_scan_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_start_scan_cmd_fixed_param)); + + cmd->scan_id = params->scan_id; + cmd->scan_req_id = params->scan_req_id; + cmd->vdev_id = params->vdev_id; + cmd->scan_priority = params->scan_priority; + cmd->notify_scan_events = params->notify_scan_events; + cmd->dwell_time_active = params->dwell_time_active; + cmd->dwell_time_passive = params->dwell_time_passive; + cmd->min_rest_time = params->min_rest_time; + cmd->max_rest_time = params->max_rest_time; + cmd->repeat_probe_time = params->repeat_probe_time; + cmd->probe_spacing_time = params->probe_spacing_time; + cmd->idle_time = params->idle_time; + cmd->max_scan_time = params->max_scan_time; + cmd->probe_delay = params->probe_delay; + cmd->scan_ctrl_flags = params->scan_ctrl_flags; + cmd->burst_duration = params->burst_duration; + cmd->num_chan = params->num_chan; + cmd->num_bssid = params->num_bssid; + cmd->num_ssids = params->num_ssids; + cmd->ie_len = params->ie_len; + cmd->n_probes = params->n_probes; + + /* mac randomization attributes */ + if (params->enable_scan_randomization) { + cmd->scan_ctrl_flags |= WMI_SCAN_ADD_SPOOFED_MAC_IN_PROBE_REQ | + WMI_SCAN_RANDOM_SEQ_NO_IN_PROBE_REQ; + WMI_CHAR_ARRAY_TO_MAC_ADDR(params->mac_addr, &cmd->mac_addr); + WMI_CHAR_ARRAY_TO_MAC_ADDR(params->mac_addr_mask, + &cmd->mac_mask); + } + + if (params->ie_whitelist) { + cmd->scan_ctrl_flags |= + WMI_SCAN_ENABLE_IE_WHTELIST_IN_PROBE_REQ; + for (i = 0; i < PROBE_REQ_BITMAP_LEN; i++) + cmd->ie_bitmap[i] = params->probe_req_ie_bitmap[i]; + + cmd->num_vendor_oui = params->num_vendor_oui; + } + + WMI_LOGI("scan_ctrl_flags = %x", cmd->scan_ctrl_flags); + + buf_ptr += sizeof(*cmd); + tmp_ptr = (uint32_t *) (buf_ptr + WMI_TLV_HDR_SIZE); + for (i = 0; i < params->num_chan; ++i) + tmp_ptr[i] = params->chan_list[i]; + + WMITLV_SET_HDR(buf_ptr, + WMITLV_TAG_ARRAY_UINT32, + (params->num_chan * sizeof(uint32_t))); + buf_ptr += WMI_TLV_HDR_SIZE + (params->num_chan * sizeof(uint32_t)); + if (params->num_ssids > WMI_SCAN_MAX_NUM_SSID) { + WMI_LOGE("Invalid value for numSsid"); + goto error; + } + + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_FIXED_STRUC, + (params->num_ssids * sizeof(wmi_ssid))); + + if (params->num_ssids) { + ssid = (wmi_ssid *) (buf_ptr + WMI_TLV_HDR_SIZE); + for (i = 0; i < params->num_ssids; ++i) { + ssid->ssid_len = params->ssid[i].length; + qdf_mem_copy(ssid->ssid, params->ssid[i].mac_ssid, + params->ssid[i].length); + ssid++; + } + } + buf_ptr += WMI_TLV_HDR_SIZE + (params->num_ssids * sizeof(wmi_ssid)); + + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_FIXED_STRUC, + (params->num_bssid * sizeof(wmi_mac_addr))); + bssid = (wmi_mac_addr *) (buf_ptr + WMI_TLV_HDR_SIZE); + WMI_CHAR_ARRAY_TO_MAC_ADDR(params->mac_add_bytes, bssid); + buf_ptr += WMI_TLV_HDR_SIZE + (params->num_bssid * sizeof(wmi_mac_addr)); + + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE, params->ie_len_with_pad); + if (params->ie_len) { + qdf_mem_copy(buf_ptr + WMI_TLV_HDR_SIZE, + (uint8_t *) params->ie_base + + (params->uie_fieldOffset), params->ie_len); + } + buf_ptr += WMI_TLV_HDR_SIZE + params->ie_len_with_pad; + + /* probe req ie whitelisting */ + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, + params->num_vendor_oui * sizeof(wmi_vendor_oui)); + + buf_ptr += WMI_TLV_HDR_SIZE; + + if (cmd->num_vendor_oui != 0) { + wmi_fill_vendor_oui(buf_ptr, cmd->num_vendor_oui, params->voui); + buf_ptr += cmd->num_vendor_oui * sizeof(wmi_vendor_oui); + } + + ret = wmi_unified_cmd_send(wmi_handle, wmi_buf, + len, WMI_START_SCAN_CMDID); + if (ret) { + WMI_LOGE("%s: Failed to start scan: %d", __func__, ret); + wmi_buf_free(wmi_buf); + } + return ret; +error: + wmi_buf_free(wmi_buf); + return QDF_STATUS_E_FAILURE; +} + +/** + * send_scan_stop_cmd_tlv() - WMI scan start function + * @param wmi_handle : handle to WMI. + * @param param : pointer to hold scan start cmd parameter + * + * Return: 0 on success and -ve on failure. + */ +QDF_STATUS send_scan_stop_cmd_tlv(wmi_unified_t wmi_handle, + struct scan_stop_params *param) +{ + wmi_stop_scan_cmd_fixed_param *cmd; + int ret; + int len = sizeof(*cmd); + wmi_buf_t wmi_buf; + + /* Allocate the memory */ + wmi_buf = wmi_buf_alloc(wmi_handle, len); + if (!wmi_buf) { + WMI_LOGP("%s: failed to allocate memory for stop scan cmd", + __func__); + ret = QDF_STATUS_E_NOMEM; + goto error; + } + + cmd = (wmi_stop_scan_cmd_fixed_param *) wmi_buf_data(wmi_buf); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_stop_scan_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN(wmi_stop_scan_cmd_fixed_param)); + cmd->vdev_id = param->vdev_id; + cmd->requestor = param->requestor; + cmd->scan_id = param->scan_id; + /* stop the scan with the corresponding scan_id */ + cmd->req_type = param->req_type; + ret = wmi_unified_cmd_send(wmi_handle, wmi_buf, + len, WMI_STOP_SCAN_CMDID); + if (ret) { + WMI_LOGE("%s: Failed to send stop scan: %d", __func__, ret); + wmi_buf_free(wmi_buf); + } + +error: + return ret; +} + +#ifdef CONFIG_MCL +/** + * send_scan_chan_list_cmd_tlv() - WMI scan channel list function + * @param wmi_handle : handle to WMI. + * @param param : pointer to hold scan channel list parameter + * + * Return: 0 on success and -ve on failure. + */ +QDF_STATUS send_scan_chan_list_cmd_tlv(wmi_unified_t wmi_handle, + struct scan_chan_list_params *chan_list) +{ + wmi_buf_t buf; + QDF_STATUS qdf_status; + wmi_scan_chan_list_cmd_fixed_param *cmd; + int i; + uint8_t *buf_ptr; + wmi_channel_param *chan_info, *tchan_info; + uint16_t len = sizeof(*cmd) + WMI_TLV_HDR_SIZE; + + len += sizeof(wmi_channel) * chan_list->num_scan_chans; + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMI_LOGE("Failed to allocate memory"); + qdf_status = QDF_STATUS_E_NOMEM; + goto end; + } + + buf_ptr = (uint8_t *) wmi_buf_data(buf); + cmd = (wmi_scan_chan_list_cmd_fixed_param *) buf_ptr; + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_scan_chan_list_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_scan_chan_list_cmd_fixed_param)); + + WMI_LOGD("no of channels = %d, len = %d", chan_list->num_scan_chans, len); + + cmd->num_scan_chans = chan_list->num_scan_chans; + WMITLV_SET_HDR((buf_ptr + sizeof(wmi_scan_chan_list_cmd_fixed_param)), + WMITLV_TAG_ARRAY_STRUC, + sizeof(wmi_channel) * chan_list->num_scan_chans); + chan_info = (wmi_channel_param *) + (buf_ptr + sizeof(*cmd) + WMI_TLV_HDR_SIZE); + tchan_info = chan_list->chan_info; + + for (i = 0; i < chan_list->num_scan_chans; ++i) { + WMITLV_SET_HDR(&chan_info->tlv_header, + WMITLV_TAG_STRUC_wmi_channel, + WMITLV_GET_STRUCT_TLVLEN(wmi_channel)); + chan_info->mhz = tchan_info->mhz; + chan_info->band_center_freq1 = + tchan_info->band_center_freq1; + chan_info->band_center_freq2 = + tchan_info->band_center_freq2; + chan_info->info = tchan_info->info; + chan_info->reg_info_1 = tchan_info->reg_info_1; + chan_info->reg_info_2 = tchan_info->reg_info_2; + WMI_LOGD("chan[%d] = %u", i, chan_info->mhz); + + /*TODO: Set WMI_SET_CHANNEL_MIN_POWER */ + /*TODO: Set WMI_SET_CHANNEL_ANTENNA_MAX */ + /*TODO: WMI_SET_CHANNEL_REG_CLASSID */ + tchan_info++; + chan_info++; + } + + qdf_status = wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_SCAN_CHAN_LIST_CMDID); + + if (QDF_IS_STATUS_ERROR(qdf_status)) { + WMI_LOGE("Failed to send WMI_SCAN_CHAN_LIST_CMDID"); + wmi_buf_free(buf); + } + +end: + return qdf_status; +} +#else +QDF_STATUS send_scan_chan_list_cmd_tlv(wmi_unified_t wmi_handle, + struct scan_chan_list_params *chan_list) +{ + wmi_buf_t buf; + QDF_STATUS qdf_status; + wmi_scan_chan_list_cmd_fixed_param *cmd; + int i; + uint8_t *buf_ptr; + wmi_channel *chan_info; + struct channel_param *tchan_info; + uint16_t len = sizeof(*cmd) + WMI_TLV_HDR_SIZE; + + len += sizeof(wmi_channel) * chan_list->num_chan; + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMI_LOGE("Failed to allocate memory"); + qdf_status = QDF_STATUS_E_NOMEM; + goto end; + } + + buf_ptr = (uint8_t *) wmi_buf_data(buf); + cmd = (wmi_scan_chan_list_cmd_fixed_param *) buf_ptr; + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_scan_chan_list_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_scan_chan_list_cmd_fixed_param)); + + WMI_LOGD("no of channels = %d, len = %d", chan_list->num_chan, len); + + cmd->num_scan_chans = chan_list->num_chan; + WMITLV_SET_HDR((buf_ptr + sizeof(wmi_scan_chan_list_cmd_fixed_param)), + WMITLV_TAG_ARRAY_STRUC, + sizeof(wmi_channel) * chan_list->num_chan); + chan_info = (wmi_channel *) (buf_ptr + sizeof(*cmd) + WMI_TLV_HDR_SIZE); + tchan_info = &(chan_list->ch_param[0]); + + for (i = 0; i < chan_list->num_chan; ++i) { + WMITLV_SET_HDR(&chan_info->tlv_header, + WMITLV_TAG_STRUC_wmi_channel, + WMITLV_GET_STRUCT_TLVLEN(wmi_channel)); + chan_info->mhz = tchan_info->mhz; + chan_info->band_center_freq1 = + tchan_info->cfreq1; + chan_info->band_center_freq2 = + tchan_info->cfreq2; + + WMI_LOGD("chan[%d] = %u", i, chan_info->mhz); + + /*TODO: Set WMI_SET_CHANNEL_MIN_POWER */ + /*TODO: Set WMI_SET_CHANNEL_ANTENNA_MAX */ + /*TODO: WMI_SET_CHANNEL_REG_CLASSID */ + tchan_info++; + chan_info++; + } + + qdf_status = wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_SCAN_CHAN_LIST_CMDID); + + if (QDF_IS_STATUS_ERROR(qdf_status)) { + WMI_LOGE("Failed to send WMI_SCAN_CHAN_LIST_CMDID"); + wmi_buf_free(buf); + } + +end: + return qdf_status; +} +#endif +/** + * send_mgmt_cmd_tlv() - WMI scan start function + * @wmi_handle : handle to WMI. + * @param : pointer to hold mgmt cmd parameter + * + * Return: 0 on success and -ve on failure. + */ +QDF_STATUS send_mgmt_cmd_tlv(wmi_unified_t wmi_handle, + struct wmi_mgmt_params *param) +{ + wmi_buf_t buf; + wmi_mgmt_tx_send_cmd_fixed_param *cmd; + int32_t cmd_len; + uint64_t dma_addr; + void *qdf_ctx = param->qdf_ctx; + uint8_t *bufp; + QDF_STATUS status; + int32_t bufp_len = (param->frm_len < mgmt_tx_dl_frm_len) ? param->frm_len : + mgmt_tx_dl_frm_len; + + cmd_len = sizeof(wmi_mgmt_tx_send_cmd_fixed_param) + + WMI_TLV_HDR_SIZE + roundup(bufp_len, sizeof(uint32_t)); + + buf = wmi_buf_alloc(wmi_handle, cmd_len); + if (!buf) { + WMI_LOGE("%s:wmi_buf_alloc failed", __func__); + return QDF_STATUS_E_NOMEM; + } + + cmd = (wmi_mgmt_tx_send_cmd_fixed_param *)wmi_buf_data(buf); + bufp = (uint8_t *) cmd; + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_mgmt_tx_send_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_mgmt_tx_send_cmd_fixed_param)); + + cmd->vdev_id = param->vdev_id; + + cmd->desc_id = param->desc_id; + cmd->chanfreq = param->chanfreq; + bufp += sizeof(wmi_mgmt_tx_send_cmd_fixed_param); + WMITLV_SET_HDR(bufp, WMITLV_TAG_ARRAY_BYTE, roundup(bufp_len, + sizeof(uint32_t))); + bufp += WMI_TLV_HDR_SIZE; + qdf_mem_copy(bufp, param->pdata, bufp_len); + + status = qdf_nbuf_map_single(qdf_ctx, param->tx_frame, + QDF_DMA_TO_DEVICE); + if (status != QDF_STATUS_SUCCESS) { + WMI_LOGE("%s: wmi buf map failed", __func__); + goto err1; + } + + dma_addr = qdf_nbuf_get_frag_paddr(param->tx_frame, 0); + cmd->paddr_lo = (uint32_t)(dma_addr & 0xffffffff); +#if defined(HTT_PADDR64) + cmd->paddr_hi = (uint32_t)((dma_addr >> 32) & 0x1F); +#endif + cmd->frame_len = param->frm_len; + cmd->buf_len = bufp_len; + + wmi_mgmt_cmd_record(wmi_handle, WMI_MGMT_TX_SEND_CMDID, + bufp, cmd->vdev_id, cmd->chanfreq); + + if (wmi_unified_cmd_send(wmi_handle, buf, cmd_len, + WMI_MGMT_TX_SEND_CMDID)) { + WMI_LOGE("%s: Failed to send mgmt Tx", __func__); + goto err1; + } + return QDF_STATUS_SUCCESS; + +err1: + wmi_buf_free(buf); + return QDF_STATUS_E_FAILURE; +} + +/** + * send_modem_power_state_cmd_tlv() - set modem power state to fw + * @wmi_handle: wmi handle + * @param_value: parameter value + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +QDF_STATUS send_modem_power_state_cmd_tlv(wmi_unified_t wmi_handle, + uint32_t param_value) +{ + QDF_STATUS ret; + wmi_modem_power_state_cmd_param *cmd; + wmi_buf_t buf; + uint16_t len = sizeof(*cmd); + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMI_LOGE("%s:wmi_buf_alloc failed", __func__); + return QDF_STATUS_E_NOMEM; + } + cmd = (wmi_modem_power_state_cmd_param *) wmi_buf_data(buf); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_modem_power_state_cmd_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_modem_power_state_cmd_param)); + cmd->modem_power_state = param_value; + WMI_LOGD("%s: Setting cmd->modem_power_state = %u", __func__, + param_value); + ret = wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_MODEM_POWER_STATE_CMDID); + if (QDF_IS_STATUS_ERROR(ret)) { + WMI_LOGE("Failed to send notify cmd ret = %d", ret); + wmi_buf_free(buf); + } + + return ret; +} + +/** + * send_set_sta_ps_mode_cmd_tlv() - set sta powersave mode in fw + * @wmi_handle: wmi handle + * @vdev_id: vdev id + * @val: value + * + * Return: QDF_STATUS_SUCCESS for success or error code. + */ +QDF_STATUS send_set_sta_ps_mode_cmd_tlv(wmi_unified_t wmi_handle, + uint32_t vdev_id, uint8_t val) +{ + wmi_sta_powersave_mode_cmd_fixed_param *cmd; + wmi_buf_t buf; + int32_t len = sizeof(*cmd); + + WMI_LOGD("Set Sta Mode Ps vdevId %d val %d", vdev_id, val); + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMI_LOGP("%s: Set Sta Mode Ps Mem Alloc Failed", __func__); + return QDF_STATUS_E_NOMEM; + } + cmd = (wmi_sta_powersave_mode_cmd_fixed_param *) wmi_buf_data(buf); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_sta_powersave_mode_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_sta_powersave_mode_cmd_fixed_param)); + cmd->vdev_id = vdev_id; + if (val) + cmd->sta_ps_mode = WMI_STA_PS_MODE_ENABLED; + else + cmd->sta_ps_mode = WMI_STA_PS_MODE_DISABLED; + + if (wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_STA_POWERSAVE_MODE_CMDID)) { + WMI_LOGE("Set Sta Mode Ps Failed vdevId %d val %d", + vdev_id, val); + wmi_buf_free(buf); + return QDF_STATUS_E_FAILURE; + } + return 0; +} + +/** + * send_set_mimops_cmd_tlv() - set MIMO powersave + * @wmi_handle: wmi handle + * @vdev_id: vdev id + * @value: value + * + * Return: QDF_STATUS_SUCCESS for success or error code. + */ +QDF_STATUS send_set_mimops_cmd_tlv(wmi_unified_t wmi_handle, + uint8_t vdev_id, int value) +{ + QDF_STATUS ret; + wmi_sta_smps_force_mode_cmd_fixed_param *cmd; + wmi_buf_t buf; + uint16_t len = sizeof(*cmd); + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMI_LOGE("%s:wmi_buf_alloc failed", __func__); + return QDF_STATUS_E_NOMEM; + } + cmd = (wmi_sta_smps_force_mode_cmd_fixed_param *) wmi_buf_data(buf); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_sta_smps_force_mode_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_sta_smps_force_mode_cmd_fixed_param)); + + cmd->vdev_id = vdev_id; + + /* WMI_SMPS_FORCED_MODE values do not directly map + * to SM power save values defined in the specification. + * Make sure to send the right mapping. + */ + switch (value) { + case 0: + cmd->forced_mode = WMI_SMPS_FORCED_MODE_NONE; + break; + case 1: + cmd->forced_mode = WMI_SMPS_FORCED_MODE_DISABLED; + break; + case 2: + cmd->forced_mode = WMI_SMPS_FORCED_MODE_STATIC; + break; + case 3: + cmd->forced_mode = WMI_SMPS_FORCED_MODE_DYNAMIC; + break; + default: + WMI_LOGE("%s:INVALID Mimo PS CONFIG", __func__); + return QDF_STATUS_E_FAILURE; + } + + WMI_LOGD("Setting vdev %d value = %u", vdev_id, value); + + ret = wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_STA_SMPS_FORCE_MODE_CMDID); + if (QDF_IS_STATUS_ERROR(ret)) { + WMI_LOGE("Failed to send set Mimo PS ret = %d", ret); + wmi_buf_free(buf); + } + + return ret; +} + +/** + * send_set_smps_params_cmd_tlv() - set smps params + * @wmi_handle: wmi handle + * @vdev_id: vdev id + * @value: value + * + * Return: QDF_STATUS_SUCCESS for success or error code. + */ +QDF_STATUS send_set_smps_params_cmd_tlv(wmi_unified_t wmi_handle, uint8_t vdev_id, + int value) +{ + QDF_STATUS ret; + wmi_sta_smps_param_cmd_fixed_param *cmd; + wmi_buf_t buf; + uint16_t len = sizeof(*cmd); + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMI_LOGE("%s:wmi_buf_alloc failed", __func__); + return QDF_STATUS_E_NOMEM; + } + cmd = (wmi_sta_smps_param_cmd_fixed_param *) wmi_buf_data(buf); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_sta_smps_param_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_sta_smps_param_cmd_fixed_param)); + + cmd->vdev_id = vdev_id; + cmd->value = value & WMI_SMPS_MASK_LOWER_16BITS; + cmd->param = + (value >> WMI_SMPS_PARAM_VALUE_S) & WMI_SMPS_MASK_UPPER_3BITS; + + WMI_LOGD("Setting vdev %d value = %x param %x", vdev_id, cmd->value, + cmd->param); + + ret = wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_STA_SMPS_PARAM_CMDID); + if (QDF_IS_STATUS_ERROR(ret)) { + WMI_LOGE("Failed to send set Mimo PS ret = %d", ret); + wmi_buf_free(buf); + } + + return ret; +} + +/** + * send_set_p2pgo_noa_req_cmd_tlv() - send p2p go noa request to fw + * @wmi_handle: wmi handle + * @noa: p2p power save parameters + * + * Return: CDF status + */ +QDF_STATUS send_set_p2pgo_noa_req_cmd_tlv(wmi_unified_t wmi_handle, + struct p2p_ps_params *noa) +{ + wmi_p2p_set_noa_cmd_fixed_param *cmd; + wmi_p2p_noa_descriptor *noa_discriptor; + wmi_buf_t buf; + uint8_t *buf_ptr; + uint16_t len; + QDF_STATUS status; + uint32_t duration; + + WMI_LOGD("%s: Enter", __func__); + len = sizeof(*cmd) + WMI_TLV_HDR_SIZE + sizeof(*noa_discriptor); + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMI_LOGE("Failed to allocate memory"); + status = QDF_STATUS_E_FAILURE; + goto end; + } + + buf_ptr = (uint8_t *) wmi_buf_data(buf); + cmd = (wmi_p2p_set_noa_cmd_fixed_param *) buf_ptr; + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_p2p_set_noa_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_p2p_set_noa_cmd_fixed_param)); + duration = (noa->count == 1) ? noa->single_noa_duration : noa->duration; + cmd->vdev_id = noa->session_id; + cmd->enable = (duration) ? true : false; + cmd->num_noa = 1; + + WMITLV_SET_HDR((buf_ptr + sizeof(wmi_p2p_set_noa_cmd_fixed_param)), + WMITLV_TAG_ARRAY_STRUC, sizeof(wmi_p2p_noa_descriptor)); + noa_discriptor = (wmi_p2p_noa_descriptor *) (buf_ptr + + sizeof + (wmi_p2p_set_noa_cmd_fixed_param) + + WMI_TLV_HDR_SIZE); + WMITLV_SET_HDR(&noa_discriptor->tlv_header, + WMITLV_TAG_STRUC_wmi_p2p_noa_descriptor, + WMITLV_GET_STRUCT_TLVLEN(wmi_p2p_noa_descriptor)); + noa_discriptor->type_count = noa->count; + noa_discriptor->duration = duration; + noa_discriptor->interval = noa->interval; + noa_discriptor->start_time = 0; + + WMI_LOGI("SET P2P GO NOA:vdev_id:%d count:%d duration:%d interval:%d", + cmd->vdev_id, noa->count, noa_discriptor->duration, + noa->interval); + status = wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_FWTEST_P2P_SET_NOA_PARAM_CMDID); + if (QDF_IS_STATUS_ERROR(status)) { + WMI_LOGE("Failed to send WMI_FWTEST_P2P_SET_NOA_PARAM_CMDID"); + wmi_buf_free(buf); + } + +end: + WMI_LOGD("%s: Exit", __func__); + return status; +} + + +/** + * send_set_p2pgo_oppps_req_cmd_tlv() - send p2p go opp power save request to fw + * @wmi_handle: wmi handle + * @noa: p2p opp power save parameters + * + * Return: CDF status + */ +QDF_STATUS send_set_p2pgo_oppps_req_cmd_tlv(wmi_unified_t wmi_handle, + struct p2p_ps_params *oppps) +{ + wmi_p2p_set_oppps_cmd_fixed_param *cmd; + wmi_buf_t buf; + QDF_STATUS status; + + WMI_LOGD("%s: Enter", __func__); + buf = wmi_buf_alloc(wmi_handle, sizeof(*cmd)); + if (!buf) { + WMI_LOGE("Failed to allocate memory"); + status = QDF_STATUS_E_FAILURE; + goto end; + } + + cmd = (wmi_p2p_set_oppps_cmd_fixed_param *) wmi_buf_data(buf); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_p2p_set_oppps_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_p2p_set_oppps_cmd_fixed_param)); + cmd->vdev_id = oppps->session_id; + if (oppps->ctwindow) + WMI_UNIFIED_OPPPS_ATTR_ENABLED_SET(cmd); + + WMI_UNIFIED_OPPPS_ATTR_CTWIN_SET(cmd, oppps->ctwindow); + WMI_LOGI("SET P2P GO OPPPS:vdev_id:%d ctwindow:%d", + cmd->vdev_id, oppps->ctwindow); + status = wmi_unified_cmd_send(wmi_handle, buf, sizeof(*cmd), + WMI_P2P_SET_OPPPS_PARAM_CMDID); + if (QDF_IS_STATUS_ERROR(status)) { + WMI_LOGE("Failed to send WMI_P2P_SET_OPPPS_PARAM_CMDID"); + wmi_buf_free(buf); + } + +end: + WMI_LOGD("%s: Exit", __func__); + return status; +} + +/** + * send_get_temperature_cmd_tlv() - get pdev temperature req + * @wmi_handle: wmi handle + * + * Return: QDF_STATUS_SUCCESS for success or error code. + */ +QDF_STATUS send_get_temperature_cmd_tlv(wmi_unified_t wmi_handle) +{ + wmi_pdev_get_temperature_cmd_fixed_param *cmd; + wmi_buf_t wmi_buf; + uint32_t len = sizeof(wmi_pdev_get_temperature_cmd_fixed_param); + uint8_t *buf_ptr; + + if (!wmi_handle) { + WMI_LOGE(FL("WMI is closed, can not issue cmd")); + return QDF_STATUS_E_INVAL; + } + + wmi_buf = wmi_buf_alloc(wmi_handle, len); + if (!wmi_buf) { + WMI_LOGE(FL("wmi_buf_alloc failed")); + return QDF_STATUS_E_NOMEM; + } + + buf_ptr = (uint8_t *) wmi_buf_data(wmi_buf); + + cmd = (wmi_pdev_get_temperature_cmd_fixed_param *) buf_ptr; + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_pdev_get_temperature_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_pdev_get_temperature_cmd_fixed_param)); + + if (wmi_unified_cmd_send(wmi_handle, wmi_buf, len, + WMI_PDEV_GET_TEMPERATURE_CMDID)) { + WMI_LOGE(FL("failed to send get temperature command")); + wmi_buf_free(wmi_buf); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * send_set_sta_uapsd_auto_trig_cmd_tlv() - set uapsd auto trigger command + * @wmi_handle: wmi handle + * @vdevid: vdev id + * @peer_addr: peer mac address + * @auto_triggerparam: auto trigger parameters + * @num_ac: number of access category + * + * This function sets the trigger + * uapsd params such as service interval, delay interval + * and suspend interval which will be used by the firmware + * to send trigger frames periodically when there is no + * traffic on the transmit side. + * + * Return: QDF_STATUS_SUCCESS for success or error code. + */ +QDF_STATUS send_set_sta_uapsd_auto_trig_cmd_tlv(wmi_unified_t wmi_handle, + struct sta_uapsd_trig_params *param) +{ + wmi_sta_uapsd_auto_trig_cmd_fixed_param *cmd; + QDF_STATUS ret; + uint32_t param_len = param->num_ac * sizeof(wmi_sta_uapsd_auto_trig_param); + uint32_t cmd_len = sizeof(*cmd) + param_len + WMI_TLV_HDR_SIZE; + uint32_t i; + wmi_buf_t buf; + uint8_t *buf_ptr; + + buf = wmi_buf_alloc(wmi_handle, cmd_len); + if (!buf) { + WMI_LOGE("%s:wmi_buf_alloc failed", __func__); + return QDF_STATUS_E_NOMEM; + } + + buf_ptr = (uint8_t *) wmi_buf_data(buf); + cmd = (wmi_sta_uapsd_auto_trig_cmd_fixed_param *) buf_ptr; + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_sta_uapsd_auto_trig_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_sta_uapsd_auto_trig_cmd_fixed_param)); + cmd->vdev_id = param->vdevid; + cmd->num_ac = param->num_ac; + WMI_CHAR_ARRAY_TO_MAC_ADDR(param->peer_addr, &cmd->peer_macaddr); + + /* TLV indicating array of structures to follow */ + buf_ptr += sizeof(*cmd); + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, param_len); + + buf_ptr += WMI_TLV_HDR_SIZE; + qdf_mem_copy(buf_ptr, param->auto_triggerparam, param_len); + + /* + * Update tag and length for uapsd auto trigger params (this will take + * care of updating tag and length if it is not pre-filled by caller). + */ + for (i = 0; i < param->num_ac; i++) { + WMITLV_SET_HDR((buf_ptr + + (i * sizeof(wmi_sta_uapsd_auto_trig_param))), + WMITLV_TAG_STRUC_wmi_sta_uapsd_auto_trig_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_sta_uapsd_auto_trig_param)); + } + + ret = wmi_unified_cmd_send(wmi_handle, buf, cmd_len, + WMI_STA_UAPSD_AUTO_TRIG_CMDID); + if (QDF_IS_STATUS_ERROR(ret)) { + WMI_LOGE("Failed to send set uapsd param ret = %d", ret); + wmi_buf_free(buf); + } + + return ret; +} + +/** + * send_ocb_set_utc_time_cmd() - send the UTC time to the firmware + * @wmi_handle: pointer to the wmi handle + * @utc: pointer to the UTC time struct + * + * Return: 0 on succes + */ +QDF_STATUS send_ocb_set_utc_time_cmd_tlv(wmi_unified_t wmi_handle, + struct ocb_utc_param *utc) +{ + QDF_STATUS ret; + wmi_ocb_set_utc_time_cmd_fixed_param *cmd; + uint8_t *buf_ptr; + uint32_t len, i; + wmi_buf_t buf; + + len = sizeof(*cmd); + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMI_LOGE(FL("wmi_buf_alloc failed")); + return QDF_STATUS_E_NOMEM; + } + + buf_ptr = (uint8_t *)wmi_buf_data(buf); + cmd = (wmi_ocb_set_utc_time_cmd_fixed_param *)buf_ptr; + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_ocb_set_utc_time_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN(wmi_ocb_set_utc_time_cmd_fixed_param)); + cmd->vdev_id = utc->vdev_id; + + for (i = 0; i < SIZE_UTC_TIME; i++) + WMI_UTC_TIME_SET(cmd, i, utc->utc_time[i]); + + for (i = 0; i < SIZE_UTC_TIME_ERROR; i++) + WMI_TIME_ERROR_SET(cmd, i, utc->time_error[i]); + + ret = wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_OCB_SET_UTC_TIME_CMDID); + if (QDF_IS_STATUS_ERROR(ret)) { + WMI_LOGE(FL("Failed to set OCB UTC time")); + wmi_buf_free(buf); + } + + return ret; +} + +/** + * send_ocb_start_timing_advert_cmd_tlv() - start sending the timing advertisement + * frames on a channel + * @wmi_handle: pointer to the wmi handle + * @timing_advert: pointer to the timing advertisement struct + * + * Return: 0 on succes + */ +QDF_STATUS send_ocb_start_timing_advert_cmd_tlv(wmi_unified_t wmi_handle, + struct ocb_timing_advert_param *timing_advert) +{ + QDF_STATUS ret; + wmi_ocb_start_timing_advert_cmd_fixed_param *cmd; + uint8_t *buf_ptr; + uint32_t len, len_template; + wmi_buf_t buf; + + len = sizeof(*cmd) + + WMI_TLV_HDR_SIZE; + + len_template = timing_advert->template_length; + /* Add padding to the template if needed */ + if (len_template % 4 != 0) + len_template += 4 - (len_template % 4); + len += len_template; + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMI_LOGE(FL("wmi_buf_alloc failed")); + return QDF_STATUS_E_NOMEM; + } + + buf_ptr = (uint8_t *)wmi_buf_data(buf); + cmd = (wmi_ocb_start_timing_advert_cmd_fixed_param *)buf_ptr; + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_ocb_start_timing_advert_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN( + wmi_ocb_start_timing_advert_cmd_fixed_param)); + cmd->vdev_id = timing_advert->vdev_id; + cmd->repeat_rate = timing_advert->repeat_rate; + cmd->channel_freq = timing_advert->chan_freq; + cmd->timestamp_offset = timing_advert->timestamp_offset; + cmd->time_value_offset = timing_advert->time_value_offset; + cmd->timing_advert_template_length = timing_advert->template_length; + buf_ptr += sizeof(*cmd); + + /* Add the timing advert template */ + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE, + len_template); + qdf_mem_copy(buf_ptr + WMI_TLV_HDR_SIZE, + (uint8_t *)timing_advert->template_value, + timing_advert->template_length); + + ret = wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_OCB_START_TIMING_ADVERT_CMDID); + if (QDF_IS_STATUS_ERROR(ret)) { + WMI_LOGE(FL("Failed to start OCB timing advert")); + wmi_buf_free(buf); + } + + return ret; +} + +/** + * send_ocb_stop_timing_advert_cmd_tlv() - stop sending the timing advertisement frames + * on a channel + * @wmi_handle: pointer to the wmi handle + * @timing_advert: pointer to the timing advertisement struct + * + * Return: 0 on succes + */ +QDF_STATUS send_ocb_stop_timing_advert_cmd_tlv(wmi_unified_t wmi_handle, + struct ocb_timing_advert_param *timing_advert) +{ + QDF_STATUS ret; + wmi_ocb_stop_timing_advert_cmd_fixed_param *cmd; + uint8_t *buf_ptr; + uint32_t len; + wmi_buf_t buf; + + len = sizeof(*cmd); + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMI_LOGE(FL("wmi_buf_alloc failed")); + return QDF_STATUS_E_NOMEM; + } + + buf_ptr = (uint8_t *)wmi_buf_data(buf); + cmd = (wmi_ocb_stop_timing_advert_cmd_fixed_param *)buf_ptr; + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_ocb_stop_timing_advert_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN( + wmi_ocb_stop_timing_advert_cmd_fixed_param)); + cmd->vdev_id = timing_advert->vdev_id; + cmd->channel_freq = timing_advert->chan_freq; + + ret = wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_OCB_STOP_TIMING_ADVERT_CMDID); + if (QDF_IS_STATUS_ERROR(ret)) { + WMI_LOGE(FL("Failed to stop OCB timing advert")); + wmi_buf_free(buf); + } + + return ret; +} + +/** + * send_ocb_get_tsf_timer_cmd_tlv() - get ocb tsf timer val + * @wmi_handle: pointer to the wmi handle + * @request: pointer to the request + * + * Return: 0 on succes + */ +QDF_STATUS send_ocb_get_tsf_timer_cmd_tlv(wmi_unified_t wmi_handle, + uint8_t vdev_id) +{ + QDF_STATUS ret; + wmi_ocb_get_tsf_timer_cmd_fixed_param *cmd; + uint8_t *buf_ptr; + wmi_buf_t buf; + int32_t len; + + len = sizeof(*cmd); + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMI_LOGE(FL("wmi_buf_alloc failed")); + return QDF_STATUS_E_NOMEM; + } + buf_ptr = (uint8_t *)wmi_buf_data(buf); + + cmd = (wmi_ocb_get_tsf_timer_cmd_fixed_param *)buf_ptr; + qdf_mem_zero(cmd, len); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_ocb_get_tsf_timer_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN( + wmi_ocb_get_tsf_timer_cmd_fixed_param)); + cmd->vdev_id = vdev_id; + + /* Send the WMI command */ + ret = wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_OCB_GET_TSF_TIMER_CMDID); + /* If there is an error, set the completion event */ + if (QDF_IS_STATUS_ERROR(ret)) { + WMI_LOGE(FL("Failed to send WMI message: %d"), ret); + wmi_buf_free(buf); + } + + return ret; +} + +/** + * send_dcc_get_stats_cmd_tlv() - get the DCC channel stats + * @wmi_handle: pointer to the wmi handle + * @get_stats_param: pointer to the dcc stats + * + * Return: 0 on succes + */ +QDF_STATUS send_dcc_get_stats_cmd_tlv(wmi_unified_t wmi_handle, + struct dcc_get_stats_param *get_stats_param) +{ + QDF_STATUS ret; + wmi_dcc_get_stats_cmd_fixed_param *cmd; + wmi_dcc_channel_stats_request *channel_stats_array; + wmi_buf_t buf; + uint8_t *buf_ptr; + uint32_t len; + uint32_t i; + + /* Validate the input */ + if (get_stats_param->request_array_len != + get_stats_param->channel_count * sizeof(*channel_stats_array)) { + WMI_LOGE(FL("Invalid parameter")); + return QDF_STATUS_E_INVAL; + } + + /* Allocate memory for the WMI command */ + len = sizeof(*cmd) + WMI_TLV_HDR_SIZE + + get_stats_param->request_array_len; + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMI_LOGE(FL("wmi_buf_alloc failed")); + return QDF_STATUS_E_NOMEM; + } + + buf_ptr = wmi_buf_data(buf); + qdf_mem_zero(buf_ptr, len); + + /* Populate the WMI command */ + cmd = (wmi_dcc_get_stats_cmd_fixed_param *)buf_ptr; + buf_ptr += sizeof(*cmd); + + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_dcc_get_stats_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN( + wmi_dcc_get_stats_cmd_fixed_param)); + cmd->vdev_id = get_stats_param->vdev_id; + cmd->num_channels = get_stats_param->channel_count; + + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, + get_stats_param->request_array_len); + buf_ptr += WMI_TLV_HDR_SIZE; + + channel_stats_array = (wmi_dcc_channel_stats_request *)buf_ptr; + qdf_mem_copy(channel_stats_array, get_stats_param->request_array, + get_stats_param->request_array_len); + for (i = 0; i < cmd->num_channels; i++) + WMITLV_SET_HDR(&channel_stats_array[i].tlv_header, + WMITLV_TAG_STRUC_wmi_dcc_channel_stats_request, + WMITLV_GET_STRUCT_TLVLEN( + wmi_dcc_channel_stats_request)); + + /* Send the WMI command */ + ret = wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_DCC_GET_STATS_CMDID); + + if (QDF_IS_STATUS_ERROR(ret)) { + WMI_LOGE(FL("Failed to send WMI message: %d"), ret); + wmi_buf_free(buf); + } + + return ret; +} + +/** + * send_dcc_clear_stats_cmd_tlv() - command to clear the DCC stats + * @wmi_handle: pointer to the wmi handle + * @vdev_id: vdev id + * @dcc_stats_bitmap: dcc status bitmap + * + * Return: 0 on succes + */ +QDF_STATUS send_dcc_clear_stats_cmd_tlv(wmi_unified_t wmi_handle, + uint32_t vdev_id, uint32_t dcc_stats_bitmap) +{ + QDF_STATUS ret; + wmi_dcc_clear_stats_cmd_fixed_param *cmd; + wmi_buf_t buf; + uint8_t *buf_ptr; + uint32_t len; + + /* Allocate memory for the WMI command */ + len = sizeof(*cmd); + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMI_LOGE(FL("wmi_buf_alloc failed")); + return QDF_STATUS_E_NOMEM; + } + + buf_ptr = wmi_buf_data(buf); + qdf_mem_zero(buf_ptr, len); + + /* Populate the WMI command */ + cmd = (wmi_dcc_clear_stats_cmd_fixed_param *)buf_ptr; + + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_dcc_clear_stats_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN( + wmi_dcc_clear_stats_cmd_fixed_param)); + cmd->vdev_id = vdev_id; + cmd->dcc_stats_bitmap = dcc_stats_bitmap; + + /* Send the WMI command */ + ret = wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_DCC_CLEAR_STATS_CMDID); + if (QDF_IS_STATUS_ERROR(ret)) { + WMI_LOGE(FL("Failed to send the WMI command")); + wmi_buf_free(buf); + } + + return ret; +} + +/** + * send_dcc_update_ndl_cmd_tlv() - command to update the NDL data + * @wmi_handle: pointer to the wmi handle + * @update_ndl_param: pointer to the request parameters + * + * Return: 0 on success + */ +QDF_STATUS send_dcc_update_ndl_cmd_tlv(wmi_unified_t wmi_handle, + struct dcc_update_ndl_param *update_ndl_param) +{ + QDF_STATUS qdf_status; + wmi_dcc_update_ndl_cmd_fixed_param *cmd; + wmi_dcc_ndl_chan *ndl_chan_array; + wmi_dcc_ndl_active_state_config *ndl_active_state_array; + uint32_t active_state_count; + wmi_buf_t buf; + uint8_t *buf_ptr; + uint32_t len; + uint32_t i; + + /* validate the input */ + if (update_ndl_param->dcc_ndl_chan_list_len != + update_ndl_param->channel_count * sizeof(*ndl_chan_array)) { + WMI_LOGE(FL("Invalid parameter")); + return QDF_STATUS_E_INVAL; + } + active_state_count = 0; + ndl_chan_array = update_ndl_param->dcc_ndl_chan_list; + for (i = 0; i < update_ndl_param->channel_count; i++) + active_state_count += + WMI_NDL_NUM_ACTIVE_STATE_GET(&ndl_chan_array[i]); + if (update_ndl_param->dcc_ndl_active_state_list_len != + active_state_count * sizeof(*ndl_active_state_array)) { + WMI_LOGE(FL("Invalid parameter")); + return QDF_STATUS_E_INVAL; + } + + /* Allocate memory for the WMI command */ + len = sizeof(*cmd) + + WMI_TLV_HDR_SIZE + update_ndl_param->dcc_ndl_chan_list_len + + WMI_TLV_HDR_SIZE + + update_ndl_param->dcc_ndl_active_state_list_len; + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMI_LOGE(FL("wmi_buf_alloc failed")); + return QDF_STATUS_E_NOMEM; + } + + buf_ptr = wmi_buf_data(buf); + qdf_mem_zero(buf_ptr, len); + + /* Populate the WMI command */ + cmd = (wmi_dcc_update_ndl_cmd_fixed_param *)buf_ptr; + buf_ptr += sizeof(*cmd); + + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_dcc_update_ndl_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN( + wmi_dcc_update_ndl_cmd_fixed_param)); + cmd->vdev_id = update_ndl_param->vdev_id; + cmd->num_channel = update_ndl_param->channel_count; + + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, + update_ndl_param->dcc_ndl_chan_list_len); + buf_ptr += WMI_TLV_HDR_SIZE; + + ndl_chan_array = (wmi_dcc_ndl_chan *)buf_ptr; + qdf_mem_copy(ndl_chan_array, update_ndl_param->dcc_ndl_chan_list, + update_ndl_param->dcc_ndl_chan_list_len); + for (i = 0; i < cmd->num_channel; i++) + WMITLV_SET_HDR(&ndl_chan_array[i].tlv_header, + WMITLV_TAG_STRUC_wmi_dcc_ndl_chan, + WMITLV_GET_STRUCT_TLVLEN( + wmi_dcc_ndl_chan)); + buf_ptr += update_ndl_param->dcc_ndl_chan_list_len; + + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, + update_ndl_param->dcc_ndl_active_state_list_len); + buf_ptr += WMI_TLV_HDR_SIZE; + + ndl_active_state_array = (wmi_dcc_ndl_active_state_config *) buf_ptr; + qdf_mem_copy(ndl_active_state_array, + update_ndl_param->dcc_ndl_active_state_list, + update_ndl_param->dcc_ndl_active_state_list_len); + for (i = 0; i < active_state_count; i++) { + WMITLV_SET_HDR(&ndl_active_state_array[i].tlv_header, + WMITLV_TAG_STRUC_wmi_dcc_ndl_active_state_config, + WMITLV_GET_STRUCT_TLVLEN( + wmi_dcc_ndl_active_state_config)); + } + buf_ptr += update_ndl_param->dcc_ndl_active_state_list_len; + + /* Send the WMI command */ + qdf_status = wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_DCC_UPDATE_NDL_CMDID); + /* If there is an error, set the completion event */ + if (QDF_IS_STATUS_ERROR(qdf_status)) { + WMI_LOGE(FL("Failed to send WMI message: %d"), qdf_status); + wmi_buf_free(buf); + } + + return qdf_status; +} + +/** + * send_ocb_set_config_cmd_tlv() - send the OCB config to the FW + * @wmi_handle: pointer to the wmi handle + * @config: the OCB configuration + * + * Return: 0 on success + */ +QDF_STATUS send_ocb_set_config_cmd_tlv(wmi_unified_t wmi_handle, + struct ocb_config_param *config, uint32_t *ch_mhz) +{ + QDF_STATUS ret; + wmi_ocb_set_config_cmd_fixed_param *cmd; + wmi_channel *chan; + wmi_ocb_channel *ocb_chan; + wmi_qos_parameter *qos_param; + wmi_dcc_ndl_chan *ndl_chan; + wmi_dcc_ndl_active_state_config *ndl_active_config; + wmi_ocb_schedule_element *sched_elem; + uint8_t *buf_ptr; + wmi_buf_t buf; + int32_t len; + int32_t i, j, active_state_count; + + /* + * Validate the dcc_ndl_chan_list_len and count the number of active + * states. Validate dcc_ndl_active_state_list_len. + */ + active_state_count = 0; + if (config->dcc_ndl_chan_list_len) { + if (!config->dcc_ndl_chan_list || + config->dcc_ndl_chan_list_len != + config->channel_count * sizeof(wmi_dcc_ndl_chan)) { + WMI_LOGE(FL("NDL channel is invalid. List len: %d"), + config->dcc_ndl_chan_list_len); + return QDF_STATUS_E_INVAL; + } + + for (i = 0, ndl_chan = config->dcc_ndl_chan_list; + i < config->channel_count; ++i, ++ndl_chan) + active_state_count += + WMI_NDL_NUM_ACTIVE_STATE_GET(ndl_chan); + + if (active_state_count) { + if (!config->dcc_ndl_active_state_list || + config->dcc_ndl_active_state_list_len != + active_state_count * + sizeof(wmi_dcc_ndl_active_state_config)) { + WMI_LOGE(FL("NDL active state is invalid.")); + return QDF_STATUS_E_INVAL; + } + } + } + + len = sizeof(*cmd) + + WMI_TLV_HDR_SIZE + config->channel_count * + sizeof(wmi_channel) + + WMI_TLV_HDR_SIZE + config->channel_count * + sizeof(wmi_ocb_channel) + + WMI_TLV_HDR_SIZE + config->channel_count * + sizeof(wmi_qos_parameter) * WMI_MAX_NUM_AC + + WMI_TLV_HDR_SIZE + config->dcc_ndl_chan_list_len + + WMI_TLV_HDR_SIZE + active_state_count * + sizeof(wmi_dcc_ndl_active_state_config) + + WMI_TLV_HDR_SIZE + config->schedule_size * + sizeof(wmi_ocb_schedule_element); + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMI_LOGE(FL("wmi_buf_alloc failed")); + return QDF_STATUS_E_NOMEM; + } + + buf_ptr = (uint8_t *)wmi_buf_data(buf); + cmd = (wmi_ocb_set_config_cmd_fixed_param *)buf_ptr; + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_ocb_set_config_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN(wmi_ocb_set_config_cmd_fixed_param)); + cmd->vdev_id = config->session_id; + cmd->channel_count = config->channel_count; + cmd->schedule_size = config->schedule_size; + cmd->flags = config->flags; + buf_ptr += sizeof(*cmd); + + /* Add the wmi_channel info */ + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, + config->channel_count*sizeof(wmi_channel)); + buf_ptr += WMI_TLV_HDR_SIZE; + for (i = 0; i < config->channel_count; i++) { + chan = (wmi_channel *)buf_ptr; + WMITLV_SET_HDR(&chan->tlv_header, + WMITLV_TAG_STRUC_wmi_channel, + WMITLV_GET_STRUCT_TLVLEN(wmi_channel)); + chan->mhz = config->channels[i].chan_freq; + chan->band_center_freq1 = config->channels[i].chan_freq; + chan->band_center_freq2 = 0; + chan->info = 0; + + WMI_SET_CHANNEL_MODE(chan, ch_mhz[i]); + WMI_SET_CHANNEL_MAX_POWER(chan, config->channels[i].max_pwr); + WMI_SET_CHANNEL_MIN_POWER(chan, config->channels[i].min_pwr); + WMI_SET_CHANNEL_MAX_TX_POWER(chan, config->channels[i].max_pwr); + WMI_SET_CHANNEL_REG_POWER(chan, config->channels[i].reg_pwr); + WMI_SET_CHANNEL_ANTENNA_MAX(chan, + config->channels[i].antenna_max); + + if (config->channels[i].bandwidth < 10) + WMI_SET_CHANNEL_FLAG(chan, WMI_CHAN_FLAG_QUARTER_RATE); + else if (config->channels[i].bandwidth < 20) + WMI_SET_CHANNEL_FLAG(chan, WMI_CHAN_FLAG_HALF_RATE); + buf_ptr += sizeof(*chan); + } + + /* Add the wmi_ocb_channel info */ + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, + config->channel_count*sizeof(wmi_ocb_channel)); + buf_ptr += WMI_TLV_HDR_SIZE; + for (i = 0; i < config->channel_count; i++) { + ocb_chan = (wmi_ocb_channel *)buf_ptr; + WMITLV_SET_HDR(&ocb_chan->tlv_header, + WMITLV_TAG_STRUC_wmi_ocb_channel, + WMITLV_GET_STRUCT_TLVLEN(wmi_ocb_channel)); + ocb_chan->bandwidth = config->channels[i].bandwidth; + WMI_CHAR_ARRAY_TO_MAC_ADDR( + config->channels[i].mac_address.bytes, + &ocb_chan->mac_address); + buf_ptr += sizeof(*ocb_chan); + } + + /* Add the wmi_qos_parameter info */ + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, + config->channel_count * sizeof(wmi_qos_parameter)*WMI_MAX_NUM_AC); + buf_ptr += WMI_TLV_HDR_SIZE; + /* WMI_MAX_NUM_AC parameters for each channel */ + for (i = 0; i < config->channel_count; i++) { + for (j = 0; j < WMI_MAX_NUM_AC; j++) { + qos_param = (wmi_qos_parameter *)buf_ptr; + WMITLV_SET_HDR(&qos_param->tlv_header, + WMITLV_TAG_STRUC_wmi_qos_parameter, + WMITLV_GET_STRUCT_TLVLEN(wmi_qos_parameter)); + qos_param->aifsn = + config->channels[i].qos_params[j].aifsn; + qos_param->cwmin = + config->channels[i].qos_params[j].cwmin; + qos_param->cwmax = + config->channels[i].qos_params[j].cwmax; + buf_ptr += sizeof(*qos_param); + } + } + + /* Add the wmi_dcc_ndl_chan (per channel) */ + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, + config->dcc_ndl_chan_list_len); + buf_ptr += WMI_TLV_HDR_SIZE; + if (config->dcc_ndl_chan_list_len) { + ndl_chan = (wmi_dcc_ndl_chan *)buf_ptr; + qdf_mem_copy(ndl_chan, config->dcc_ndl_chan_list, + config->dcc_ndl_chan_list_len); + for (i = 0; i < config->channel_count; i++) + WMITLV_SET_HDR(&(ndl_chan[i].tlv_header), + WMITLV_TAG_STRUC_wmi_dcc_ndl_chan, + WMITLV_GET_STRUCT_TLVLEN(wmi_dcc_ndl_chan)); + buf_ptr += config->dcc_ndl_chan_list_len; + } + + /* Add the wmi_dcc_ndl_active_state_config */ + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, active_state_count * + sizeof(wmi_dcc_ndl_active_state_config)); + buf_ptr += WMI_TLV_HDR_SIZE; + if (active_state_count) { + ndl_active_config = (wmi_dcc_ndl_active_state_config *)buf_ptr; + qdf_mem_copy(ndl_active_config, + config->dcc_ndl_active_state_list, + active_state_count * sizeof(*ndl_active_config)); + for (i = 0; i < active_state_count; ++i) + WMITLV_SET_HDR(&(ndl_active_config[i].tlv_header), + WMITLV_TAG_STRUC_wmi_dcc_ndl_active_state_config, + WMITLV_GET_STRUCT_TLVLEN( + wmi_dcc_ndl_active_state_config)); + buf_ptr += active_state_count * + sizeof(*ndl_active_config); + } + + /* Add the wmi_ocb_schedule_element info */ + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, + config->schedule_size * sizeof(wmi_ocb_schedule_element)); + buf_ptr += WMI_TLV_HDR_SIZE; + for (i = 0; i < config->schedule_size; i++) { + sched_elem = (wmi_ocb_schedule_element *)buf_ptr; + WMITLV_SET_HDR(&sched_elem->tlv_header, + WMITLV_TAG_STRUC_wmi_ocb_schedule_element, + WMITLV_GET_STRUCT_TLVLEN(wmi_ocb_schedule_element)); + sched_elem->channel_freq = config->schedule[i].chan_freq; + sched_elem->total_duration = config->schedule[i].total_duration; + sched_elem->guard_interval = config->schedule[i].guard_interval; + buf_ptr += sizeof(*sched_elem); + } + + + ret = wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_OCB_SET_CONFIG_CMDID); + if (QDF_IS_STATUS_ERROR(ret)) { + WMI_LOGE("Failed to set OCB config"); + wmi_buf_free(buf); + } + + return ret; +} + +/** + * send_set_enable_disable_mcc_adaptive_scheduler_cmd_tlv() -enable/disable mcc scheduler + * @wmi_handle: wmi handle + * @mcc_adaptive_scheduler: enable/disable + * + * This function enable/disable mcc adaptive scheduler in fw. + * + * Return: QDF_STATUS_SUCCESS for sucess or error code + */ +QDF_STATUS send_set_enable_disable_mcc_adaptive_scheduler_cmd_tlv( + wmi_unified_t wmi_handle, uint32_t mcc_adaptive_scheduler, + uint32_t pdev_id) +{ + QDF_STATUS ret; + wmi_buf_t buf = 0; + wmi_resmgr_adaptive_ocs_enable_disable_cmd_fixed_param *cmd = NULL; + uint16_t len = + sizeof(wmi_resmgr_adaptive_ocs_enable_disable_cmd_fixed_param); + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMI_LOGP("%s : wmi_buf_alloc failed", __func__); + return QDF_STATUS_E_NOMEM; + } + cmd = (wmi_resmgr_adaptive_ocs_enable_disable_cmd_fixed_param *) + wmi_buf_data(buf); + + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_resmgr_adaptive_ocs_enable_disable_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_resmgr_adaptive_ocs_enable_disable_cmd_fixed_param)); + cmd->enable = mcc_adaptive_scheduler; + cmd->pdev_id = pdev_id; + + ret = wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_RESMGR_ADAPTIVE_OCS_ENABLE_DISABLE_CMDID); + if (QDF_IS_STATUS_ERROR(ret)) { + WMI_LOGP("%s: Failed to send enable/disable MCC" + " adaptive scheduler command", __func__); + wmi_buf_free(buf); + } + + return ret; +} + +/** + * send_set_mcc_channel_time_latency_cmd_tlv() -set MCC channel time latency + * @wmi: wmi handle + * @mcc_channel: mcc channel + * @mcc_channel_time_latency: MCC channel time latency. + * + * Currently used to set time latency for an MCC vdev/adapter using operating + * channel of it and channel number. The info is provided run time using + * iwpriv command: iwpriv setMccLatency . + * + * Return: CDF status + */ +QDF_STATUS send_set_mcc_channel_time_latency_cmd_tlv(wmi_unified_t wmi_handle, + uint32_t mcc_channel_freq, uint32_t mcc_channel_time_latency) +{ + QDF_STATUS ret; + wmi_buf_t buf = 0; + wmi_resmgr_set_chan_latency_cmd_fixed_param *cmdTL = NULL; + uint16_t len = 0; + uint8_t *buf_ptr = NULL; + wmi_resmgr_chan_latency chan_latency; + /* Note: we only support MCC time latency for a single channel */ + uint32_t num_channels = 1; + uint32_t chan1_freq = mcc_channel_freq; + uint32_t latency_chan1 = mcc_channel_time_latency; + + + /* If 0ms latency is provided, then FW will set to a default. + * Otherwise, latency must be at least 30ms. + */ + if ((latency_chan1 > 0) && + (latency_chan1 < WMI_MCC_MIN_NON_ZERO_CHANNEL_LATENCY)) { + WMI_LOGE("%s: Invalid time latency for Channel #1 = %dms " + "Minimum is 30ms (or 0 to use default value by " + "firmware)", __func__, latency_chan1); + return QDF_STATUS_E_INVAL; + } + + /* Set WMI CMD for channel time latency here */ + len = sizeof(wmi_resmgr_set_chan_latency_cmd_fixed_param) + + WMI_TLV_HDR_SIZE + /*Place holder for chan_time_latency array */ + num_channels * sizeof(wmi_resmgr_chan_latency); + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMI_LOGE("%s : wmi_buf_alloc failed", __func__); + return QDF_STATUS_E_NOMEM; + } + buf_ptr = (uint8_t *) wmi_buf_data(buf); + cmdTL = (wmi_resmgr_set_chan_latency_cmd_fixed_param *) + wmi_buf_data(buf); + WMITLV_SET_HDR(&cmdTL->tlv_header, + WMITLV_TAG_STRUC_wmi_resmgr_set_chan_latency_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_resmgr_set_chan_latency_cmd_fixed_param)); + cmdTL->num_chans = num_channels; + /* Update channel time latency information for home channel(s) */ + buf_ptr += sizeof(*cmdTL); + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE, + num_channels * sizeof(wmi_resmgr_chan_latency)); + buf_ptr += WMI_TLV_HDR_SIZE; + chan_latency.chan_mhz = chan1_freq; + chan_latency.latency = latency_chan1; + qdf_mem_copy(buf_ptr, &chan_latency, sizeof(chan_latency)); + ret = wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_RESMGR_SET_CHAN_LATENCY_CMDID); + if (QDF_IS_STATUS_ERROR(ret)) { + WMI_LOGE("%s: Failed to send MCC Channel Time Latency command", + __func__); + wmi_buf_free(buf); + QDF_ASSERT(0); + } + + return ret; +} + +/** + * send_set_mcc_channel_time_quota_cmd_tlv() -set MCC channel time quota + * @wmi: wmi handle + * @adapter_1_chan_number: adapter 1 channel number + * @adapter_1_quota: adapter 1 quota + * @adapter_2_chan_number: adapter 2 channel number + * + * Return: CDF status + */ +QDF_STATUS send_set_mcc_channel_time_quota_cmd_tlv(wmi_unified_t wmi_handle, + uint32_t adapter_1_chan_freq, + uint32_t adapter_1_quota, uint32_t adapter_2_chan_freq) +{ + QDF_STATUS ret; + wmi_buf_t buf = 0; + uint16_t len = 0; + uint8_t *buf_ptr = NULL; + wmi_resmgr_set_chan_time_quota_cmd_fixed_param *cmdTQ = NULL; + wmi_resmgr_chan_time_quota chan_quota; + uint32_t quota_chan1 = adapter_1_quota; + /* Knowing quota of 1st chan., derive quota for 2nd chan. */ + uint32_t quota_chan2 = 100 - quota_chan1; + /* Note: setting time quota for MCC requires info for 2 channels */ + uint32_t num_channels = 2; + uint32_t chan1_freq = adapter_1_chan_freq; + uint32_t chan2_freq = adapter_2_chan_freq; + + WMI_LOGD("%s: freq1:%dMHz, Quota1:%dms, " + "freq2:%dMHz, Quota2:%dms", __func__, + chan1_freq, quota_chan1, chan2_freq, + quota_chan2); + + /* + * Perform sanity check on time quota values provided. + */ + if (quota_chan1 < WMI_MCC_MIN_CHANNEL_QUOTA || + quota_chan1 > WMI_MCC_MAX_CHANNEL_QUOTA) { + WMI_LOGE("%s: Invalid time quota for Channel #1=%dms. Minimum " + "is 20ms & maximum is 80ms", __func__, quota_chan1); + return QDF_STATUS_E_INVAL; + } + /* Set WMI CMD for channel time quota here */ + len = sizeof(wmi_resmgr_set_chan_time_quota_cmd_fixed_param) + + WMI_TLV_HDR_SIZE + /* Place holder for chan_time_quota array */ + num_channels * sizeof(wmi_resmgr_chan_time_quota); + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMI_LOGE("%s : wmi_buf_alloc failed", __func__); + QDF_ASSERT(0); + return QDF_STATUS_E_NOMEM; + } + buf_ptr = (uint8_t *) wmi_buf_data(buf); + cmdTQ = (wmi_resmgr_set_chan_time_quota_cmd_fixed_param *) + wmi_buf_data(buf); + WMITLV_SET_HDR(&cmdTQ->tlv_header, + WMITLV_TAG_STRUC_wmi_resmgr_set_chan_time_quota_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_resmgr_set_chan_time_quota_cmd_fixed_param)); + cmdTQ->num_chans = num_channels; + + /* Update channel time quota information for home channel(s) */ + buf_ptr += sizeof(*cmdTQ); + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE, + num_channels * sizeof(wmi_resmgr_chan_time_quota)); + buf_ptr += WMI_TLV_HDR_SIZE; + chan_quota.chan_mhz = chan1_freq; + chan_quota.channel_time_quota = quota_chan1; + qdf_mem_copy(buf_ptr, &chan_quota, sizeof(chan_quota)); + /* Construct channel and quota record for the 2nd MCC mode. */ + buf_ptr += sizeof(chan_quota); + chan_quota.chan_mhz = chan2_freq; + chan_quota.channel_time_quota = quota_chan2; + qdf_mem_copy(buf_ptr, &chan_quota, sizeof(chan_quota)); + + ret = wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_RESMGR_SET_CHAN_TIME_QUOTA_CMDID); + if (QDF_IS_STATUS_ERROR(ret)) { + WMI_LOGE("Failed to send MCC Channel Time Quota command"); + wmi_buf_free(buf); + QDF_ASSERT(0); + } + + return ret; +} + +/** + * send_set_thermal_mgmt_cmd_tlv() - set thermal mgmt command to fw + * @wmi_handle: Pointer to wmi handle + * @thermal_info: Thermal command information + * + * This function sends the thermal management command + * to the firmware + * + * Return: QDF_STATUS_SUCCESS for success otherwise failure + */ +QDF_STATUS send_set_thermal_mgmt_cmd_tlv(wmi_unified_t wmi_handle, + struct thermal_cmd_params *thermal_info) +{ + wmi_thermal_mgmt_cmd_fixed_param *cmd = NULL; + wmi_buf_t buf = NULL; + QDF_STATUS status; + uint32_t len = 0; + + len = sizeof(*cmd); + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMI_LOGE("Failed to allocate buffer to send set key cmd"); + return QDF_STATUS_E_FAILURE; + } + + cmd = (wmi_thermal_mgmt_cmd_fixed_param *) wmi_buf_data(buf); + + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_thermal_mgmt_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_thermal_mgmt_cmd_fixed_param)); + + cmd->lower_thresh_degreeC = thermal_info->min_temp; + cmd->upper_thresh_degreeC = thermal_info->max_temp; + cmd->enable = thermal_info->thermal_enable; + + WMI_LOGE("TM Sending thermal mgmt cmd: low temp %d, upper temp %d, enabled %d", + cmd->lower_thresh_degreeC, cmd->upper_thresh_degreeC, cmd->enable); + + status = wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_THERMAL_MGMT_CMDID); + if (QDF_IS_STATUS_ERROR(status)) { + wmi_buf_free(buf); + WMI_LOGE("%s:Failed to send thermal mgmt command", __func__); + } + + return status; +} + + +/** + * send_lro_config_cmd_tlv() - process the LRO config command + * @wmi_handle: Pointer to WMI handle + * @wmi_lro_cmd: Pointer to LRO configuration parameters + * + * This function sends down the LRO configuration parameters to + * the firmware to enable LRO, sets the TCP flags and sets the + * seed values for the toeplitz hash generation + * + * Return: QDF_STATUS_SUCCESS for success otherwise failure + */ +QDF_STATUS send_lro_config_cmd_tlv(wmi_unified_t wmi_handle, + struct wmi_lro_config_cmd_t *wmi_lro_cmd) +{ + wmi_lro_info_cmd_fixed_param *cmd; + wmi_buf_t buf; + QDF_STATUS status; + + + buf = wmi_buf_alloc(wmi_handle, sizeof(*cmd)); + if (!buf) { + WMI_LOGE("Failed to allocate buffer to send set key cmd"); + return QDF_STATUS_E_FAILURE; + } + + cmd = (wmi_lro_info_cmd_fixed_param *) wmi_buf_data(buf); + + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_lro_info_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN(wmi_lro_info_cmd_fixed_param)); + + cmd->lro_enable = wmi_lro_cmd->lro_enable; + WMI_LRO_INFO_TCP_FLAG_VALS_SET(cmd->tcp_flag_u32, + wmi_lro_cmd->tcp_flag); + WMI_LRO_INFO_TCP_FLAGS_MASK_SET(cmd->tcp_flag_u32, + wmi_lro_cmd->tcp_flag_mask); + cmd->toeplitz_hash_ipv4_0_3 = + wmi_lro_cmd->toeplitz_hash_ipv4[0]; + cmd->toeplitz_hash_ipv4_4_7 = + wmi_lro_cmd->toeplitz_hash_ipv4[1]; + cmd->toeplitz_hash_ipv4_8_11 = + wmi_lro_cmd->toeplitz_hash_ipv4[2]; + cmd->toeplitz_hash_ipv4_12_15 = + wmi_lro_cmd->toeplitz_hash_ipv4[3]; + cmd->toeplitz_hash_ipv4_16 = + wmi_lro_cmd->toeplitz_hash_ipv4[4]; + + cmd->toeplitz_hash_ipv6_0_3 = + wmi_lro_cmd->toeplitz_hash_ipv6[0]; + cmd->toeplitz_hash_ipv6_4_7 = + wmi_lro_cmd->toeplitz_hash_ipv6[1]; + cmd->toeplitz_hash_ipv6_8_11 = + wmi_lro_cmd->toeplitz_hash_ipv6[2]; + cmd->toeplitz_hash_ipv6_12_15 = + wmi_lro_cmd->toeplitz_hash_ipv6[3]; + cmd->toeplitz_hash_ipv6_16_19 = + wmi_lro_cmd->toeplitz_hash_ipv6[4]; + cmd->toeplitz_hash_ipv6_20_23 = + wmi_lro_cmd->toeplitz_hash_ipv6[5]; + cmd->toeplitz_hash_ipv6_24_27 = + wmi_lro_cmd->toeplitz_hash_ipv6[6]; + cmd->toeplitz_hash_ipv6_28_31 = + wmi_lro_cmd->toeplitz_hash_ipv6[7]; + cmd->toeplitz_hash_ipv6_32_35 = + wmi_lro_cmd->toeplitz_hash_ipv6[8]; + cmd->toeplitz_hash_ipv6_36_39 = + wmi_lro_cmd->toeplitz_hash_ipv6[9]; + cmd->toeplitz_hash_ipv6_40 = + wmi_lro_cmd->toeplitz_hash_ipv6[10]; + + WMI_LOGD("WMI_LRO_CONFIG: lro_enable %d, tcp_flag 0x%x", + cmd->lro_enable, cmd->tcp_flag_u32); + + status = wmi_unified_cmd_send(wmi_handle, buf, + sizeof(*cmd), WMI_LRO_CONFIG_CMDID); + if (QDF_IS_STATUS_ERROR(status)) { + wmi_buf_free(buf); + WMI_LOGE("%s:Failed to send WMI_LRO_CONFIG_CMDID", __func__); + } + + return status; +} + +/** + * send_peer_rate_report_cmd_tlv() - process the peer rate report command + * @wmi_handle: Pointer to wmi handle + * @rate_report_params: Pointer to peer rate report parameters + * + * + * Return: QDF_STATUS_SUCCESS for success otherwise failure + */ +QDF_STATUS send_peer_rate_report_cmd_tlv(wmi_unified_t wmi_handle, + struct wmi_peer_rate_report_params *rate_report_params) +{ + wmi_peer_set_rate_report_condition_fixed_param *cmd = NULL; + wmi_buf_t buf = NULL; + QDF_STATUS status = 0; + uint32_t len = 0; + uint32_t i, j; + + len = sizeof(*cmd); + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMI_LOGE("Failed to alloc buf to peer_set_condition cmd\n"); + return QDF_STATUS_E_FAILURE; + } + + cmd = (wmi_peer_set_rate_report_condition_fixed_param *) + wmi_buf_data(buf); + + WMITLV_SET_HDR( + &cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_peer_set_rate_report_condition_fixed_param, + WMITLV_GET_STRUCT_TLVLEN( + wmi_peer_set_rate_report_condition_fixed_param)); + + cmd->enable_rate_report = rate_report_params->rate_report_enable; + cmd->report_backoff_time = rate_report_params->backoff_time; + cmd->report_timer_period = rate_report_params->timer_period; + for (i = 0; i < PEER_RATE_REPORT_COND_MAX_NUM; i++) { + cmd->cond_per_phy[i].val_cond_flags = + rate_report_params->report_per_phy[i].cond_flags; + cmd->cond_per_phy[i].rate_delta.min_delta = + rate_report_params->report_per_phy[i].delta.delta_min; + cmd->cond_per_phy[i].rate_delta.percentage = + rate_report_params->report_per_phy[i].delta.percent; + for (j = 0; j < MAX_NUM_OF_RATE_THRESH; j++) { + cmd->cond_per_phy[i].rate_threshold[j] = + rate_report_params->report_per_phy[i]. + report_rate_threshold[j]; + } + } + + WMI_LOGE("%s enable %d backoff_time %d period %d\n", __func__, + cmd->enable_rate_report, + cmd->report_backoff_time, cmd->report_timer_period); + + status = wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_PEER_SET_RATE_REPORT_CONDITION_CMDID); + if (QDF_IS_STATUS_ERROR(status)) { + wmi_buf_free(buf); + WMI_LOGE("%s:Failed to send peer_set_report_cond command", + __func__); + } + return status; +} + +/** + * send_bcn_buf_ll_cmd_tlv() - prepare and send beacon buffer to fw for LL + * @wmi_handle: wmi handle + * @param: bcn ll cmd parameter + * + * Return: QDF_STATUS_SUCCESS for success otherwise failure + */ +QDF_STATUS send_bcn_buf_ll_cmd_tlv(wmi_unified_t wmi_handle, + wmi_bcn_send_from_host_cmd_fixed_param *param) +{ + wmi_bcn_send_from_host_cmd_fixed_param *cmd; + wmi_buf_t wmi_buf; + QDF_STATUS ret; + + wmi_buf = wmi_buf_alloc(wmi_handle, sizeof(*cmd)); + if (!wmi_buf) { + WMI_LOGE("%s: wmi_buf_alloc failed", __func__); + return QDF_STATUS_E_FAILURE; + } + + cmd = (wmi_bcn_send_from_host_cmd_fixed_param *) wmi_buf_data(wmi_buf); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_bcn_send_from_host_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_bcn_send_from_host_cmd_fixed_param)); + cmd->vdev_id = param->vdev_id; + cmd->data_len = param->data_len; + cmd->frame_ctrl = param->frame_ctrl; + cmd->frag_ptr = param->frag_ptr; + cmd->dtim_flag = param->dtim_flag; + + ret = wmi_unified_cmd_send(wmi_handle, wmi_buf, sizeof(*cmd), + WMI_PDEV_SEND_BCN_CMDID); + + if (QDF_IS_STATUS_ERROR(ret)) { + WMI_LOGE("Failed to send WMI_PDEV_SEND_BCN_CMDID command"); + wmi_buf_free(wmi_buf); + } + + return ret; +} + +/** + * send_set_sta_sa_query_param_cmd_tlv() - set sta sa query parameters + * @wmi_handle: wmi handle + * @vdev_id: vdev id + * @max_retries: max retries + * @retry_interval: retry interval + * This function sets sta query related parameters in fw. + * + * Return: QDF_STATUS_SUCCESS for success otherwise failure + */ + +QDF_STATUS send_set_sta_sa_query_param_cmd_tlv(wmi_unified_t wmi_handle, + uint8_t vdev_id, uint32_t max_retries, + uint32_t retry_interval) +{ + wmi_buf_t buf; + WMI_PMF_OFFLOAD_SET_SA_QUERY_CMD_fixed_param *cmd; + int len; + + len = sizeof(*cmd); + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMI_LOGE(FL("wmi_buf_alloc failed")); + return QDF_STATUS_E_FAILURE; + } + + cmd = (WMI_PMF_OFFLOAD_SET_SA_QUERY_CMD_fixed_param *)wmi_buf_data(buf); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_WMI_PMF_OFFLOAD_SET_SA_QUERY_CMD_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (WMI_PMF_OFFLOAD_SET_SA_QUERY_CMD_fixed_param)); + + + cmd->vdev_id = vdev_id; + cmd->sa_query_max_retry_count = max_retries; + cmd->sa_query_retry_interval = retry_interval; + + WMI_LOGD(FL("STA sa query: vdev_id:%d interval:%u retry count:%d"), + vdev_id, retry_interval, max_retries); + + if (wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_PMF_OFFLOAD_SET_SA_QUERY_CMDID)) { + WMI_LOGE(FL("Failed to offload STA SA Query")); + wmi_buf_free(buf); + return QDF_STATUS_E_FAILURE; + } + + WMI_LOGD(FL("Exit :")); + return 0; +} + +/** + * send_set_sta_keep_alive_cmd_tlv() - set sta keep alive parameters + * @wmi_handle: wmi handle + * @params: sta keep alive parameter + * + * This function sets keep alive related parameters in fw. + * + * Return: CDF status + */ +QDF_STATUS send_set_sta_keep_alive_cmd_tlv(wmi_unified_t wmi_handle, + struct sta_params *params) +{ + wmi_buf_t buf; + WMI_STA_KEEPALIVE_CMD_fixed_param *cmd; + WMI_STA_KEEPALVE_ARP_RESPONSE *arp_rsp; + uint8_t *buf_ptr; + int len; + QDF_STATUS ret; + + WMI_LOGD("%s: Enter", __func__); + + len = sizeof(*cmd) + sizeof(*arp_rsp); + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMI_LOGE("wmi_buf_alloc failed"); + return QDF_STATUS_E_FAILURE; + } + + cmd = (WMI_STA_KEEPALIVE_CMD_fixed_param *) wmi_buf_data(buf); + buf_ptr = (uint8_t *) cmd; + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_WMI_STA_KEEPALIVE_CMD_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (WMI_STA_KEEPALIVE_CMD_fixed_param)); + cmd->interval = params->timeperiod; + cmd->enable = (params->timeperiod) ? 1 : 0; + cmd->vdev_id = params->vdev_id; + WMI_LOGD("Keep Alive: vdev_id:%d interval:%u method:%d", params->vdev_id, + params->timeperiod, params->method); + arp_rsp = (WMI_STA_KEEPALVE_ARP_RESPONSE *) (buf_ptr + sizeof(*cmd)); + WMITLV_SET_HDR(&arp_rsp->tlv_header, + WMITLV_TAG_STRUC_WMI_STA_KEEPALVE_ARP_RESPONSE, + WMITLV_GET_STRUCT_TLVLEN(WMI_STA_KEEPALVE_ARP_RESPONSE)); + + if ((params->method == WMI_KEEP_ALIVE_UNSOLICIT_ARP_RSP) || + (params->method == + WMI_STA_KEEPALIVE_METHOD_GRATUITOUS_ARP_REQUEST)) { + if ((NULL == params->hostv4addr) || + (NULL == params->destv4addr) || + (NULL == params->destmac)) { + WMI_LOGE("%s: received null pointer, hostv4addr:%p " + "destv4addr:%p destmac:%p ", __func__, + params->hostv4addr, params->destv4addr, params->destmac); + wmi_buf_free(buf); + return QDF_STATUS_E_FAILURE; + } + cmd->method = params->method; + qdf_mem_copy(&arp_rsp->sender_prot_addr, params->hostv4addr, + WMI_IPV4_ADDR_LEN); + qdf_mem_copy(&arp_rsp->target_prot_addr, params->destv4addr, + WMI_IPV4_ADDR_LEN); + WMI_CHAR_ARRAY_TO_MAC_ADDR(params->destmac, &arp_rsp->dest_mac_addr); + } else { + cmd->method = WMI_STA_KEEPALIVE_METHOD_NULL_FRAME; + } + + ret = wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_STA_KEEPALIVE_CMDID); + if (QDF_IS_STATUS_ERROR(ret)) { + WMI_LOGE("Failed to set KeepAlive"); + wmi_buf_free(buf); + } + + WMI_LOGD("%s: Exit", __func__); + return ret; +} + +/** + * send_vdev_set_gtx_cfg_cmd_tlv() - set GTX params + * @wmi_handle: wmi handle + * @if_id: vdev id + * @gtx_info: GTX config params + * + * This function set GTX related params in firmware. + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +QDF_STATUS send_vdev_set_gtx_cfg_cmd_tlv(wmi_unified_t wmi_handle, uint32_t if_id, + struct wmi_gtx_config *gtx_info) +{ + wmi_vdev_set_gtx_params_cmd_fixed_param *cmd; + wmi_buf_t buf; + QDF_STATUS ret; + int len = sizeof(wmi_vdev_set_gtx_params_cmd_fixed_param); + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMI_LOGE("%s:wmi_buf_alloc failed", __func__); + return QDF_STATUS_E_NOMEM; + } + cmd = (wmi_vdev_set_gtx_params_cmd_fixed_param *) wmi_buf_data(buf); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_vdev_set_gtx_params_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_vdev_set_gtx_params_cmd_fixed_param)); + cmd->vdev_id = if_id; + + cmd->gtxRTMask[0] = gtx_info->gtx_rt_mask[0]; + cmd->gtxRTMask[1] = gtx_info->gtx_rt_mask[1]; + cmd->userGtxMask = gtx_info->gtx_usrcfg; + cmd->gtxPERThreshold = gtx_info->gtx_threshold; + cmd->gtxPERMargin = gtx_info->gtx_margin; + cmd->gtxTPCstep = gtx_info->gtx_tpcstep; + cmd->gtxTPCMin = gtx_info->gtx_tpcmin; + cmd->gtxBWMask = gtx_info->gtx_bwmask; + + WMI_LOGD("Setting vdev%d GTX values:htmcs 0x%x, vhtmcs 0x%x, usermask 0x%x, \ + gtxPERThreshold %d, gtxPERMargin %d, gtxTPCstep %d, gtxTPCMin %d, \ + gtxBWMask 0x%x.", if_id, cmd->gtxRTMask[0], cmd->gtxRTMask[1], + cmd->userGtxMask, cmd->gtxPERThreshold, cmd->gtxPERMargin, + cmd->gtxTPCstep, cmd->gtxTPCMin, cmd->gtxBWMask); + + ret = wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_VDEV_SET_GTX_PARAMS_CMDID); + if (QDF_IS_STATUS_ERROR(ret)) { + WMI_LOGE("Failed to set GTX PARAMS"); + wmi_buf_free(buf); + } + return ret; +} + +/** + * send_process_update_edca_param_cmd_tlv() - update EDCA params + * @wmi_handle: wmi handle + * @edca_params: edca parameters + * + * This function updates EDCA parameters to the target + * + * Return: CDF Status + */ +QDF_STATUS send_process_update_edca_param_cmd_tlv(wmi_unified_t wmi_handle, + uint8_t vdev_id, + wmi_wmm_vparams gwmm_param[WMI_MAX_NUM_AC]) +{ + uint8_t *buf_ptr; + wmi_buf_t buf; + wmi_vdev_set_wmm_params_cmd_fixed_param *cmd; + wmi_wmm_vparams *wmm_param, *twmm_param; + int len = sizeof(*cmd); + int ac; + + buf = wmi_buf_alloc(wmi_handle, len); + + if (!buf) { + WMI_LOGE("%s: wmi_buf_alloc failed", __func__); + return QDF_STATUS_E_NOMEM; + } + + buf_ptr = (uint8_t *) wmi_buf_data(buf); + cmd = (wmi_vdev_set_wmm_params_cmd_fixed_param *) buf_ptr; + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_vdev_set_wmm_params_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_vdev_set_wmm_params_cmd_fixed_param)); + cmd->vdev_id = vdev_id; + + for (ac = 0; ac < WMI_MAX_NUM_AC; ac++) { + wmm_param = (wmi_wmm_vparams *) (&cmd->wmm_params[ac]); + twmm_param = (wmi_wmm_vparams *) (&gwmm_param[ac]); + WMITLV_SET_HDR(&wmm_param->tlv_header, + WMITLV_TAG_STRUC_wmi_vdev_set_wmm_params_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN(wmi_wmm_vparams)); + wmm_param->cwmin = twmm_param->cwmin; + wmm_param->cwmax = twmm_param->cwmax; + wmm_param->aifs = twmm_param->aifs; + wmm_param->txoplimit = twmm_param->txoplimit; + wmm_param->acm = twmm_param->acm; + wmm_param->no_ack = twmm_param->no_ack; + } + + if (wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_VDEV_SET_WMM_PARAMS_CMDID)) + goto fail; + + return QDF_STATUS_SUCCESS; + +fail: + wmi_buf_free(buf); + WMI_LOGE("%s: Failed to set WMM Paremeters", __func__); + return QDF_STATUS_E_FAILURE; +} + +/** + * send_probe_rsp_tmpl_send_cmd_tlv() - send probe response template to fw + * @wmi_handle: wmi handle + * @vdev_id: vdev id + * @probe_rsp_info: probe response info + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +QDF_STATUS send_probe_rsp_tmpl_send_cmd_tlv(wmi_unified_t wmi_handle, + uint8_t vdev_id, + struct wmi_probe_resp_params *probe_rsp_info, + uint8_t *frm) +{ + wmi_prb_tmpl_cmd_fixed_param *cmd; + wmi_bcn_prb_info *bcn_prb_info; + wmi_buf_t wmi_buf; + uint32_t tmpl_len, tmpl_len_aligned, wmi_buf_len; + uint8_t *buf_ptr; + QDF_STATUS ret; + + WMI_LOGD(FL("Send probe response template for vdev %d"), vdev_id); + + tmpl_len = probe_rsp_info->probeRespTemplateLen; + tmpl_len_aligned = roundup(tmpl_len, sizeof(A_UINT32)); + + wmi_buf_len = sizeof(wmi_prb_tmpl_cmd_fixed_param) + + sizeof(wmi_bcn_prb_info) + WMI_TLV_HDR_SIZE + + tmpl_len_aligned; + + if (wmi_buf_len > WMI_BEACON_TX_BUFFER_SIZE) { + WMI_LOGE(FL("wmi_buf_len: %d > %d. Can't send wmi cmd"), + wmi_buf_len, WMI_BEACON_TX_BUFFER_SIZE); + return QDF_STATUS_E_INVAL; + } + + wmi_buf = wmi_buf_alloc(wmi_handle, wmi_buf_len); + if (!wmi_buf) { + WMI_LOGE(FL("wmi_buf_alloc failed")); + return QDF_STATUS_E_NOMEM; + } + + buf_ptr = (uint8_t *) wmi_buf_data(wmi_buf); + + cmd = (wmi_prb_tmpl_cmd_fixed_param *) buf_ptr; + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_prb_tmpl_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN(wmi_prb_tmpl_cmd_fixed_param)); + cmd->vdev_id = vdev_id; + cmd->buf_len = tmpl_len; + buf_ptr += sizeof(wmi_prb_tmpl_cmd_fixed_param); + + bcn_prb_info = (wmi_bcn_prb_info *) buf_ptr; + WMITLV_SET_HDR(&bcn_prb_info->tlv_header, + WMITLV_TAG_STRUC_wmi_bcn_prb_info, + WMITLV_GET_STRUCT_TLVLEN(wmi_bcn_prb_info)); + bcn_prb_info->caps = 0; + bcn_prb_info->erp = 0; + buf_ptr += sizeof(wmi_bcn_prb_info); + + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE, tmpl_len_aligned); + buf_ptr += WMI_TLV_HDR_SIZE; + qdf_mem_copy(buf_ptr, frm, tmpl_len); + + ret = wmi_unified_cmd_send(wmi_handle, + wmi_buf, wmi_buf_len, WMI_PRB_TMPL_CMDID); + if (QDF_IS_STATUS_ERROR(ret)) { + WMI_LOGE(FL("Failed to send PRB RSP tmpl: %d"), ret); + wmi_buf_free(wmi_buf); + } + + return ret; +} + +#ifdef FEATURE_WLAN_WAPI +#define WPI_IV_LEN 16 + +/** + * wmi_update_wpi_key_counter() - update WAPI tsc and rsc key counters + * + * @dest_tx: destination address of tsc key counter + * @src_tx: source address of tsc key counter + * @dest_rx: destination address of rsc key counter + * @src_rx: source address of rsc key counter + * + * This function copies WAPI tsc and rsc key counters in the wmi buffer. + * + * Return: None + * + */ +static void wmi_update_wpi_key_counter(uint8_t *dest_tx, uint8_t *src_tx, + uint8_t *dest_rx, uint8_t *src_rx) +{ + qdf_mem_copy(dest_tx, src_tx, WPI_IV_LEN); + qdf_mem_copy(dest_rx, src_rx, WPI_IV_LEN); +} +#else +static void wmi_update_wpi_key_counter(uint8_t *dest_tx, uint8_t *src_tx, + uint8_t *dest_rx, uint8_t *src_rx) +{ + return; +} +#endif + +/** + * send_setup_install_key_cmd_tlv() - set key parameters + * @wmi_handle: wmi handle + * @key_params: key parameters + * + * This function fills structure from information + * passed in key_params. + * + * Return: QDF_STATUS_SUCCESS - success + * QDF_STATUS_E_FAILURE - failure + * QDF_STATUS_E_NOMEM - not able to allocate buffer + */ +QDF_STATUS send_setup_install_key_cmd_tlv(wmi_unified_t wmi_handle, + struct set_key_params *key_params) +{ + wmi_vdev_install_key_cmd_fixed_param *cmd; + wmi_buf_t buf; + uint8_t *buf_ptr; + uint32_t len; + uint8_t *key_data; + QDF_STATUS status; + + len = sizeof(*cmd) + roundup(key_params->key_len, sizeof(uint32_t)) + + WMI_TLV_HDR_SIZE; + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMI_LOGE("Failed to allocate buffer to send set key cmd"); + return QDF_STATUS_E_NOMEM; + } + + buf_ptr = (uint8_t *) wmi_buf_data(buf); + cmd = (wmi_vdev_install_key_cmd_fixed_param *) buf_ptr; + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_vdev_install_key_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_vdev_install_key_cmd_fixed_param)); + cmd->vdev_id = key_params->vdev_id; + cmd->key_ix = key_params->key_idx; + WMI_CHAR_ARRAY_TO_MAC_ADDR(key_params->peer_mac, &cmd->peer_macaddr); + cmd->key_flags |= key_params->key_flags; + cmd->key_cipher = key_params->key_cipher; + if ((key_params->key_txmic_len) && + (key_params->key_rxmic_len)) { + cmd->key_txmic_len = key_params->key_txmic_len; + cmd->key_rxmic_len = key_params->key_rxmic_len; + } +#ifdef FEATURE_WLAN_WAPI + wmi_update_wpi_key_counter(cmd->wpi_key_tsc_counter, + key_params->tx_iv, + cmd->wpi_key_rsc_counter, + key_params->rx_iv); +#endif + buf_ptr += sizeof(wmi_vdev_install_key_cmd_fixed_param); + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE, + roundup(key_params->key_len, sizeof(uint32_t))); + key_data = (A_UINT8 *) (buf_ptr + WMI_TLV_HDR_SIZE); + qdf_mem_copy((void *)key_data, + (const void *)key_params->key_data, key_params->key_len); + cmd->key_len = key_params->key_len; + + status = wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_VDEV_INSTALL_KEY_CMDID); + if (QDF_IS_STATUS_ERROR(status)) + wmi_buf_free(buf); + + return status; +} + +/** + * send_sar_limit_cmd_tlv() - send sar limit cmd to fw + * @wmi_handle: wmi handle + * @params: sar limit params + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +static QDF_STATUS send_sar_limit_cmd_tlv(wmi_unified_t wmi_handle, + struct sar_limit_cmd_params *sar_limit_params) +{ + wmi_buf_t buf; + QDF_STATUS qdf_status; + wmi_sar_limits_cmd_fixed_param *cmd; + int i; + uint8_t *buf_ptr; + wmi_sar_limit_cmd_row *wmi_sar_rows_list; + struct sar_limit_cmd_row *sar_rows_list; + uint32_t len = sizeof(*cmd) + WMI_TLV_HDR_SIZE; + + len += sizeof(wmi_sar_limit_cmd_row) * sar_limit_params->num_limit_rows; + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMI_LOGE("Failed to allocate memory"); + qdf_status = QDF_STATUS_E_NOMEM; + goto end; + } + + buf_ptr = (uint8_t *) wmi_buf_data(buf); + cmd = (wmi_sar_limits_cmd_fixed_param *) buf_ptr; + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_sar_limits_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_sar_limits_cmd_fixed_param)); + cmd->sar_enable = sar_limit_params->sar_enable; + cmd->commit_limits = sar_limit_params->commit_limits; + cmd->num_limit_rows = sar_limit_params->num_limit_rows; + + WMI_LOGD("no of sar rows = %d, len = %d", + sar_limit_params->num_limit_rows, len); + buf_ptr += sizeof(*cmd); + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, + sizeof(wmi_sar_limit_cmd_row) * + sar_limit_params->num_limit_rows); + if (cmd->num_limit_rows == 0) + goto send_sar_limits; + + wmi_sar_rows_list = (wmi_sar_limit_cmd_row *) + (buf_ptr + WMI_TLV_HDR_SIZE); + sar_rows_list = sar_limit_params->sar_limit_row_list; + + for (i = 0; i < sar_limit_params->num_limit_rows; i++) { + WMITLV_SET_HDR(&wmi_sar_rows_list->tlv_header, + WMITLV_TAG_STRUC_wmi_sar_limit_cmd_row, + WMITLV_GET_STRUCT_TLVLEN(wmi_sar_limit_cmd_row)); + wmi_sar_rows_list->band_id = sar_rows_list->band_id; + wmi_sar_rows_list->chain_id = sar_rows_list->chain_id; + wmi_sar_rows_list->mod_id = sar_rows_list->mod_id; + wmi_sar_rows_list->limit_value = sar_rows_list->limit_value; + wmi_sar_rows_list->validity_bitmap = + sar_rows_list->validity_bitmap; + WMI_LOGD("row %d, band_id = %d, chain_id = %d, mod_id = %d, limit_value = %d, validity_bitmap = %d", + i, wmi_sar_rows_list->band_id, + wmi_sar_rows_list->chain_id, + wmi_sar_rows_list->mod_id, + wmi_sar_rows_list->limit_value, + wmi_sar_rows_list->validity_bitmap); + sar_rows_list++; + wmi_sar_rows_list++; + } +send_sar_limits: + qdf_status = wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_SAR_LIMITS_CMDID); + + if (QDF_IS_STATUS_ERROR(qdf_status)) { + WMI_LOGE("Failed to send WMI_SAR_LIMITS_CMDID"); + wmi_buf_free(buf); + } + +end: + return qdf_status; +} + +/** + * send_encrypt_decrypt_send_cmd() - send encrypt/decrypt cmd to fw + * @wmi_handle: wmi handle + * @params: encrypt/decrypt params + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +static +QDF_STATUS send_encrypt_decrypt_send_cmd_tlv(wmi_unified_t wmi_handle, + struct encrypt_decrypt_req_params *encrypt_decrypt_params) +{ + wmi_vdev_encrypt_decrypt_data_req_cmd_fixed_param *cmd; + wmi_buf_t wmi_buf; + uint8_t *buf_ptr; + QDF_STATUS ret; + uint32_t len; + + WMI_LOGD(FL("Send encrypt decrypt cmd")); + + len = sizeof(*cmd) + + roundup(encrypt_decrypt_params->data_len, sizeof(A_UINT32)) + + WMI_TLV_HDR_SIZE; + wmi_buf = wmi_buf_alloc(wmi_handle, len); + if (!wmi_buf) { + WMI_LOGP("%s: failed to allocate memory for encrypt/decrypt msg", + __func__); + return QDF_STATUS_E_NOMEM; + } + + buf_ptr = wmi_buf_data(wmi_buf); + cmd = (wmi_vdev_encrypt_decrypt_data_req_cmd_fixed_param *)buf_ptr; + + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_vdev_encrypt_decrypt_data_req_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN( + wmi_vdev_encrypt_decrypt_data_req_cmd_fixed_param)); + + cmd->vdev_id = encrypt_decrypt_params->vdev_id; + cmd->key_flag = encrypt_decrypt_params->key_flag; + cmd->key_idx = encrypt_decrypt_params->key_idx; + cmd->key_cipher = encrypt_decrypt_params->key_cipher; + cmd->key_len = encrypt_decrypt_params->key_len; + cmd->key_txmic_len = encrypt_decrypt_params->key_txmic_len; + cmd->key_rxmic_len = encrypt_decrypt_params->key_rxmic_len; + + qdf_mem_copy(cmd->key_data, encrypt_decrypt_params->key_data, + encrypt_decrypt_params->key_len); + + qdf_mem_copy(cmd->mac_hdr, encrypt_decrypt_params->mac_header, + MAX_MAC_HEADER_LEN); + + cmd->data_len = encrypt_decrypt_params->data_len; + + if (cmd->data_len) { + buf_ptr += sizeof(*cmd); + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE, + roundup(encrypt_decrypt_params->data_len, + sizeof(A_UINT32))); + buf_ptr += WMI_TLV_HDR_SIZE; + qdf_mem_copy(buf_ptr, encrypt_decrypt_params->data, + encrypt_decrypt_params->data_len); + } + + /* This conversion is to facilitate data to FW in little endian */ + cmd->pn[5] = encrypt_decrypt_params->pn[0]; + cmd->pn[4] = encrypt_decrypt_params->pn[1]; + cmd->pn[3] = encrypt_decrypt_params->pn[2]; + cmd->pn[2] = encrypt_decrypt_params->pn[3]; + cmd->pn[1] = encrypt_decrypt_params->pn[4]; + cmd->pn[0] = encrypt_decrypt_params->pn[5]; + + ret = wmi_unified_cmd_send(wmi_handle, + wmi_buf, len, + WMI_VDEV_ENCRYPT_DECRYPT_DATA_REQ_CMDID); + if (QDF_IS_STATUS_ERROR(ret)) { + WMI_LOGE("Failed to send ENCRYPT DECRYPT cmd: %d", ret); + wmi_buf_free(wmi_buf); + } + + return ret; +} + + + +/** + * send_p2p_go_set_beacon_ie_cmd_tlv() - set beacon IE for p2p go + * @wmi_handle: wmi handle + * @vdev_id: vdev id + * @p2p_ie: p2p IE + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +QDF_STATUS send_p2p_go_set_beacon_ie_cmd_tlv(wmi_unified_t wmi_handle, + A_UINT32 vdev_id, uint8_t *p2p_ie) +{ + QDF_STATUS ret; + wmi_p2p_go_set_beacon_ie_fixed_param *cmd; + wmi_buf_t wmi_buf; + uint32_t ie_len, ie_len_aligned, wmi_buf_len; + uint8_t *buf_ptr; + + ie_len = (uint32_t) (p2p_ie[1] + 2); + + /* More than one P2P IE may be included in a single frame. + If multiple P2P IEs are present, the complete P2P attribute + data consists of the concatenation of the P2P Attribute + fields of the P2P IEs. The P2P Attributes field of each + P2P IE may be any length up to the maximum (251 octets). + In this case host sends one P2P IE to firmware so the length + should not exceed more than 251 bytes + */ + if (ie_len > 251) { + WMI_LOGE("%s : invalid p2p ie length %u", __func__, ie_len); + return QDF_STATUS_E_INVAL; + } + + ie_len_aligned = roundup(ie_len, sizeof(A_UINT32)); + + wmi_buf_len = + sizeof(wmi_p2p_go_set_beacon_ie_fixed_param) + ie_len_aligned + + WMI_TLV_HDR_SIZE; + + wmi_buf = wmi_buf_alloc(wmi_handle, wmi_buf_len); + if (!wmi_buf) { + WMI_LOGE("%s : wmi_buf_alloc failed", __func__); + return QDF_STATUS_E_NOMEM; + } + + buf_ptr = (uint8_t *) wmi_buf_data(wmi_buf); + + cmd = (wmi_p2p_go_set_beacon_ie_fixed_param *) buf_ptr; + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_p2p_go_set_beacon_ie_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_p2p_go_set_beacon_ie_fixed_param)); + cmd->vdev_id = vdev_id; + cmd->ie_buf_len = ie_len; + + buf_ptr += sizeof(wmi_p2p_go_set_beacon_ie_fixed_param); + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE, ie_len_aligned); + buf_ptr += WMI_TLV_HDR_SIZE; + qdf_mem_copy(buf_ptr, p2p_ie, ie_len); + + WMI_LOGI("%s: Sending WMI_P2P_GO_SET_BEACON_IE", __func__); + + ret = wmi_unified_cmd_send(wmi_handle, + wmi_buf, wmi_buf_len, + WMI_P2P_GO_SET_BEACON_IE); + if (QDF_IS_STATUS_ERROR(ret)) { + WMI_LOGE("Failed to send bcn tmpl: %d", ret); + wmi_buf_free(wmi_buf); + } + + WMI_LOGI("%s: Successfully sent WMI_P2P_GO_SET_BEACON_IE", __func__); + return ret; +} + +/** + * send_set_gateway_params_cmd_tlv() - set gateway parameters + * @wmi_handle: wmi handle + * @req: gateway parameter update request structure + * + * This function reads the incoming @req and fill in the destination + * WMI structure and sends down the gateway configs down to the firmware + * + * Return: QDF_STATUS + */ +QDF_STATUS send_set_gateway_params_cmd_tlv(wmi_unified_t wmi_handle, + struct gateway_update_req_param *req) +{ + wmi_roam_subnet_change_config_fixed_param *cmd; + wmi_buf_t buf; + QDF_STATUS ret; + int len = sizeof(*cmd); + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMI_LOGP("%s: wmi_buf_alloc failed", __func__); + return QDF_STATUS_E_NOMEM; + } + + cmd = (wmi_roam_subnet_change_config_fixed_param *) wmi_buf_data(buf); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_roam_subnet_change_config_fixed_param, + WMITLV_GET_STRUCT_TLVLEN( + wmi_roam_subnet_change_config_fixed_param)); + + cmd->vdev_id = req->session_id; + qdf_mem_copy(&cmd->inet_gw_ip_v4_addr, req->ipv4_addr, + QDF_IPV4_ADDR_SIZE); + qdf_mem_copy(&cmd->inet_gw_ip_v6_addr, req->ipv6_addr, + QDF_IPV6_ADDR_SIZE); + WMI_CHAR_ARRAY_TO_MAC_ADDR(req->gw_mac_addr.bytes, + &cmd->inet_gw_mac_addr); + cmd->max_retries = req->max_retries; + cmd->timeout = req->timeout; + cmd->num_skip_subnet_change_detection_bssid_list = 0; + cmd->flag = 0; + if (req->ipv4_addr_type) + WMI_SET_ROAM_SUBNET_CHANGE_FLAG_IP4_ENABLED(cmd->flag); + + if (req->ipv6_addr_type) + WMI_SET_ROAM_SUBNET_CHANGE_FLAG_IP6_ENABLED(cmd->flag); + + ret = wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_ROAM_SUBNET_CHANGE_CONFIG_CMDID); + if (QDF_IS_STATUS_ERROR(ret)) { + WMI_LOGE("Failed to send gw config parameter to fw, ret: %d", + ret); + wmi_buf_free(buf); + } + + return ret; +} + +/** + * send_set_rssi_monitoring_cmd_tlv() - set rssi monitoring + * @wmi_handle: wmi handle + * @req: rssi monitoring request structure + * + * This function reads the incoming @req and fill in the destination + * WMI structure and send down the rssi monitoring configs down to the firmware + * + * Return: 0 on success; error number otherwise + */ +QDF_STATUS send_set_rssi_monitoring_cmd_tlv(wmi_unified_t wmi_handle, + struct rssi_monitor_param *req) +{ + wmi_rssi_breach_monitor_config_fixed_param *cmd; + wmi_buf_t buf; + QDF_STATUS ret; + uint32_t len = sizeof(*cmd); + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMI_LOGP("%s: wmi_buf_alloc failed", __func__); + return QDF_STATUS_E_NOMEM; + } + + cmd = (wmi_rssi_breach_monitor_config_fixed_param *) wmi_buf_data(buf); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_rssi_breach_monitor_config_fixed_param, + WMITLV_GET_STRUCT_TLVLEN( + wmi_rssi_breach_monitor_config_fixed_param)); + + cmd->vdev_id = req->session_id; + cmd->request_id = req->request_id; + cmd->lo_rssi_reenable_hysteresis = 0; + cmd->hi_rssi_reenable_histeresis = 0; + cmd->min_report_interval = 0; + cmd->max_num_report = 1; + if (req->control) { + /* enable one threshold for each min/max */ + cmd->enabled_bitmap = 0x09; + cmd->low_rssi_breach_threshold[0] = req->min_rssi; + cmd->hi_rssi_breach_threshold[0] = req->max_rssi; + } else { + cmd->enabled_bitmap = 0; + cmd->low_rssi_breach_threshold[0] = 0; + cmd->hi_rssi_breach_threshold[0] = 0; + } + + ret = wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_RSSI_BREACH_MONITOR_CONFIG_CMDID); + if (QDF_IS_STATUS_ERROR(ret)) { + WMI_LOGE("Failed to send WMI_RSSI_BREACH_MONITOR_CONFIG_CMDID"); + wmi_buf_free(buf); + } + + WMI_LOGI("Sent WMI_RSSI_BREACH_MONITOR_CONFIG_CMDID to FW"); + return ret; +} + +/** + * send_scan_probe_setoui_cmd_tlv() - set scan probe OUI + * @wmi_handle: wmi handle + * @psetoui: OUI parameters + * + * set scan probe OUI parameters in firmware + * + * Return: CDF status + */ +QDF_STATUS send_scan_probe_setoui_cmd_tlv(wmi_unified_t wmi_handle, + struct scan_mac_oui *psetoui) +{ + wmi_scan_prob_req_oui_cmd_fixed_param *cmd; + wmi_buf_t wmi_buf; + uint32_t len; + uint8_t *buf_ptr; + uint32_t *oui_buf; + uint32_t i = 0; + + len = sizeof(*cmd) + WMI_TLV_HDR_SIZE + + psetoui->num_vendor_oui * sizeof(wmi_vendor_oui); + + wmi_buf = wmi_buf_alloc(wmi_handle, len); + if (!wmi_buf) { + WMI_LOGE("%s: wmi_buf_alloc failed", __func__); + return QDF_STATUS_E_NOMEM; + } + buf_ptr = (uint8_t *) wmi_buf_data(wmi_buf); + cmd = (wmi_scan_prob_req_oui_cmd_fixed_param *) buf_ptr; + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_scan_prob_req_oui_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_scan_prob_req_oui_cmd_fixed_param)); + + oui_buf = &cmd->prob_req_oui; + qdf_mem_zero(oui_buf, sizeof(cmd->prob_req_oui)); + *oui_buf = psetoui->oui[0] << 16 | psetoui->oui[1] << 8 + | psetoui->oui[2]; + WMI_LOGD("%s: wmi:oui received from hdd %08x", __func__, + cmd->prob_req_oui); + + cmd->vdev_id = psetoui->vdev_id; + cmd->flags = WMI_SCAN_PROBE_OUI_SPOOFED_MAC_IN_PROBE_REQ; + if (psetoui->enb_probe_req_sno_randomization) + cmd->flags |= WMI_SCAN_PROBE_OUI_RANDOM_SEQ_NO_IN_PROBE_REQ; + + if (psetoui->ie_whitelist) { + cmd->flags |= + WMI_SCAN_PROBE_OUI_ENABLE_IE_WHITELIST_IN_PROBE_REQ; + cmd->num_vendor_oui = psetoui->num_vendor_oui; + for (i = 0; i < PROBE_REQ_BITMAP_LEN; i++) + cmd->ie_bitmap[i] = psetoui->probe_req_ie_bitmap[i]; + } + + WMI_LOGI(FL("vdev_id = %d, flags = %x"), cmd->vdev_id, cmd->flags); + + buf_ptr += sizeof(*cmd); + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, + psetoui->num_vendor_oui * sizeof(wmi_vendor_oui)); + buf_ptr += WMI_TLV_HDR_SIZE; + + if (cmd->num_vendor_oui != 0) { + wmi_fill_vendor_oui(buf_ptr, cmd->num_vendor_oui, + psetoui->voui); + buf_ptr += cmd->num_vendor_oui * sizeof(wmi_vendor_oui); + } + + if (wmi_unified_cmd_send(wmi_handle, wmi_buf, len, + WMI_SCAN_PROB_REQ_OUI_CMDID)) { + WMI_LOGE("%s: failed to send command", __func__); + wmi_buf_free(wmi_buf); + return QDF_STATUS_E_FAILURE; + } + return QDF_STATUS_SUCCESS; +} + +/** + * send_reset_passpoint_network_list_cmd_tlv() - reset passpoint network list + * @wmi_handle: wmi handle + * @req: passpoint network request structure + * + * This function sends down WMI command with network id set to wildcard id. + * firmware shall clear all the config entries + * + * Return: QDF_STATUS enumeration + */ +QDF_STATUS send_reset_passpoint_network_list_cmd_tlv(wmi_unified_t wmi_handle, + struct wifi_passpoint_req_param *req) +{ + wmi_passpoint_config_cmd_fixed_param *cmd; + wmi_buf_t buf; + uint32_t len; + int ret; + + len = sizeof(*cmd); + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMI_LOGE("%s: Failed allocate wmi buffer", __func__); + return QDF_STATUS_E_NOMEM; + } + + cmd = (wmi_passpoint_config_cmd_fixed_param *) wmi_buf_data(buf); + + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_passpoint_config_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN( + wmi_passpoint_config_cmd_fixed_param)); + cmd->id = WMI_PASSPOINT_NETWORK_ID_WILDCARD; + + ret = wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_PASSPOINT_LIST_CONFIG_CMDID); + if (ret) { + WMI_LOGE("%s: Failed to send reset passpoint network list wmi cmd", + __func__); + wmi_buf_free(buf); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * send_set_passpoint_network_list_cmd_tlv() - set passpoint network list + * @wmi_handle: wmi handle + * @req: passpoint network request structure + * + * This function reads the incoming @req and fill in the destination + * WMI structure and send down the passpoint configs down to the firmware + * + * Return: QDF_STATUS enumeration + */ +QDF_STATUS send_set_passpoint_network_list_cmd_tlv(wmi_unified_t wmi_handle, + struct wifi_passpoint_req_param *req) +{ + wmi_passpoint_config_cmd_fixed_param *cmd; + u_int8_t i, j, *bytes; + wmi_buf_t buf; + uint32_t len; + int ret; + + len = sizeof(*cmd); + for (i = 0; i < req->num_networks; i++) { + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMI_LOGE("%s: Failed allocate wmi buffer", __func__); + return QDF_STATUS_E_NOMEM; + } + + cmd = (wmi_passpoint_config_cmd_fixed_param *) + wmi_buf_data(buf); + + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_passpoint_config_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN( + wmi_passpoint_config_cmd_fixed_param)); + cmd->id = req->networks[i].id; + WMI_LOGD("%s: network id: %u", __func__, cmd->id); + qdf_mem_copy(cmd->realm, req->networks[i].realm, + strlen(req->networks[i].realm) + 1); + WMI_LOGD("%s: realm: %s", __func__, cmd->realm); + for (j = 0; j < PASSPOINT_ROAMING_CONSORTIUM_ID_NUM; j++) { + bytes = (uint8_t *) &req->networks[i].roaming_consortium_ids[j]; + WMI_LOGD("index: %d rcids: %02x %02x %02x %02x %02x %02x %02x %02x", + j, bytes[0], bytes[1], bytes[2], bytes[3], + bytes[4], bytes[5], bytes[6], bytes[7]); + + qdf_mem_copy(&cmd->roaming_consortium_ids[j], + &req->networks[i].roaming_consortium_ids[j], + PASSPOINT_ROAMING_CONSORTIUM_ID_LEN); + } + qdf_mem_copy(cmd->plmn, req->networks[i].plmn, + PASSPOINT_PLMN_ID_LEN); + WMI_LOGD("%s: plmn: %02x:%02x:%02x", __func__, + cmd->plmn[0], cmd->plmn[1], cmd->plmn[2]); + + ret = wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_PASSPOINT_LIST_CONFIG_CMDID); + if (ret) { + WMI_LOGE("%s: Failed to send set passpoint network list wmi cmd", + __func__); + wmi_buf_free(buf); + return QDF_STATUS_E_FAILURE; + } + } + + return QDF_STATUS_SUCCESS; +} + +/** + * send_roam_scan_offload_mode_cmd_tlv() - send roam scan mode request to fw + * @wmi_handle: wmi handle + * @scan_cmd_fp: start scan command ptr + * @roam_req: roam request param + * + * send WMI_ROAM_SCAN_MODE TLV to firmware. It has a piggyback + * of WMI_ROAM_SCAN_MODE. + * + * Return: QDF status + */ +QDF_STATUS send_roam_scan_offload_mode_cmd_tlv(wmi_unified_t wmi_handle, + wmi_start_scan_cmd_fixed_param * + scan_cmd_fp, + struct roam_offload_scan_params *roam_req) +{ + wmi_buf_t buf = NULL; + QDF_STATUS status; + int len; + uint8_t *buf_ptr; + wmi_roam_scan_mode_fixed_param *roam_scan_mode_fp; + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + int auth_mode = roam_req->auth_mode; + wmi_roam_offload_tlv_param *roam_offload_params; + wmi_roam_11i_offload_tlv_param *roam_offload_11i; + wmi_roam_11r_offload_tlv_param *roam_offload_11r; + wmi_roam_ese_offload_tlv_param *roam_offload_ese; + wmi_tlv_buf_len_param *assoc_ies; +#endif /* WLAN_FEATURE_ROAM_OFFLOAD */ + /* Need to create a buf with roam_scan command at + * front and piggyback with scan command */ + len = sizeof(wmi_roam_scan_mode_fixed_param) + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + (2 * WMI_TLV_HDR_SIZE) + +#endif /* WLAN_FEATURE_ROAM_OFFLOAD */ + sizeof(wmi_start_scan_cmd_fixed_param); +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + if (roam_req->is_roam_req_valid && + roam_req->roam_offload_enabled) { + len += sizeof(wmi_roam_offload_tlv_param); + len += WMI_TLV_HDR_SIZE; + if ((auth_mode != WMI_AUTH_NONE) && + ((auth_mode != WMI_AUTH_OPEN) || + (auth_mode == WMI_AUTH_OPEN && + roam_req->mdid.mdie_present) || + roam_req->is_ese_assoc)) { + len += WMI_TLV_HDR_SIZE; + if (roam_req->is_ese_assoc) + len += + sizeof(wmi_roam_ese_offload_tlv_param); + else if (auth_mode == WMI_AUTH_FT_RSNA || + auth_mode == WMI_AUTH_FT_RSNA_PSK || + (auth_mode == WMI_AUTH_OPEN && + roam_req->mdid.mdie_present)) + len += + sizeof(wmi_roam_11r_offload_tlv_param); + else + len += + sizeof(wmi_roam_11i_offload_tlv_param); + } else { + len += WMI_TLV_HDR_SIZE; + } + + len += (sizeof(*assoc_ies) + (2*WMI_TLV_HDR_SIZE) + + roundup(roam_req->assoc_ie_length, + sizeof(uint32_t))); + } else { + if (roam_req->is_roam_req_valid) + WMI_LOGD("%s : roam offload = %d", + __func__, roam_req->roam_offload_enabled); + else + WMI_LOGD("%s : roam_req is NULL", __func__); + len += (4 * WMI_TLV_HDR_SIZE); + } + if (roam_req->is_roam_req_valid && + roam_req->roam_offload_enabled) { + roam_req->mode = roam_req->mode | + WMI_ROAM_SCAN_MODE_ROAMOFFLOAD; + } +#endif /* WLAN_FEATURE_ROAM_OFFLOAD */ + + if (roam_req->mode == (WMI_ROAM_SCAN_MODE_NONE + |WMI_ROAM_SCAN_MODE_ROAMOFFLOAD)) + len = sizeof(wmi_roam_scan_mode_fixed_param); + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMI_LOGE("%s : wmi_buf_alloc failed", __func__); + return QDF_STATUS_E_NOMEM; + } + + buf_ptr = (uint8_t *) wmi_buf_data(buf); + + roam_scan_mode_fp = (wmi_roam_scan_mode_fixed_param *) buf_ptr; + WMITLV_SET_HDR(&roam_scan_mode_fp->tlv_header, + WMITLV_TAG_STRUC_wmi_roam_scan_mode_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_roam_scan_mode_fixed_param)); + + roam_scan_mode_fp->roam_scan_mode = roam_req->mode; + roam_scan_mode_fp->vdev_id = roam_req->vdev_id; + if (roam_req->mode == (WMI_ROAM_SCAN_MODE_NONE | + WMI_ROAM_SCAN_MODE_ROAMOFFLOAD)) { + roam_scan_mode_fp->flags |= + WMI_ROAM_SCAN_MODE_FLAG_REPORT_STATUS; + goto send_roam_scan_mode_cmd; + } + + /* Fill in scan parameters suitable for roaming scan */ + buf_ptr += sizeof(wmi_roam_scan_mode_fixed_param); + + qdf_mem_copy(buf_ptr, scan_cmd_fp, + sizeof(wmi_start_scan_cmd_fixed_param)); + /* Ensure there is no additional IEs */ + scan_cmd_fp->ie_len = 0; + WMITLV_SET_HDR(buf_ptr, + WMITLV_TAG_STRUC_wmi_start_scan_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_start_scan_cmd_fixed_param)); +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + buf_ptr += sizeof(wmi_start_scan_cmd_fixed_param); + if (roam_req->is_roam_req_valid && roam_req->roam_offload_enabled) { + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, + sizeof(wmi_roam_offload_tlv_param)); + buf_ptr += WMI_TLV_HDR_SIZE; + roam_offload_params = (wmi_roam_offload_tlv_param *) buf_ptr; + WMITLV_SET_HDR(buf_ptr, + WMITLV_TAG_STRUC_wmi_roam_offload_tlv_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_roam_offload_tlv_param)); + roam_offload_params->prefer_5g = roam_req->prefer_5ghz; + roam_offload_params->rssi_cat_gap = roam_req->roam_rssi_cat_gap; + roam_offload_params->select_5g_margin = + roam_req->select_5ghz_margin; + roam_offload_params->reassoc_failure_timeout = + roam_req->reassoc_failure_timeout; + + /* Fill the capabilities */ + roam_offload_params->capability = + roam_req->roam_offload_params.capability; + roam_offload_params->ht_caps_info = + roam_req->roam_offload_params.ht_caps_info; + roam_offload_params->ampdu_param = + roam_req->roam_offload_params.ampdu_param; + roam_offload_params->ht_ext_cap = + roam_req->roam_offload_params.ht_ext_cap; + roam_offload_params->ht_txbf = + roam_req->roam_offload_params.ht_txbf; + roam_offload_params->asel_cap = + roam_req->roam_offload_params.asel_cap; + roam_offload_params->qos_caps = + roam_req->roam_offload_params.qos_caps; + roam_offload_params->qos_enabled = + roam_req->roam_offload_params.qos_enabled; + roam_offload_params->wmm_caps = + roam_req->roam_offload_params.wmm_caps; + qdf_mem_copy((uint8_t *)roam_offload_params->mcsset, + (uint8_t *)roam_req->roam_offload_params.mcsset, + ROAM_OFFLOAD_NUM_MCS_SET); + + buf_ptr += sizeof(wmi_roam_offload_tlv_param); + /* The TLV's are in the order of 11i, 11R, ESE. Hence, + * they are filled in the same order.Depending on the + * authentication type, the other mode TLV's are nullified + * and only headers are filled.*/ + if ((auth_mode != WMI_AUTH_NONE) && + ((auth_mode != WMI_AUTH_OPEN) || + (auth_mode == WMI_AUTH_OPEN + && roam_req->mdid.mdie_present) || + roam_req->is_ese_assoc)) { + if (roam_req->is_ese_assoc) { + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, + WMITLV_GET_STRUCT_TLVLEN(0)); + buf_ptr += WMI_TLV_HDR_SIZE; + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, + WMITLV_GET_STRUCT_TLVLEN(0)); + buf_ptr += WMI_TLV_HDR_SIZE; + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, + sizeof(wmi_roam_ese_offload_tlv_param)); + buf_ptr += WMI_TLV_HDR_SIZE; + roam_offload_ese = + (wmi_roam_ese_offload_tlv_param *) buf_ptr; + qdf_mem_copy(roam_offload_ese->krk, + roam_req->krk, + sizeof(roam_req->krk)); + qdf_mem_copy(roam_offload_ese->btk, + roam_req->btk, + sizeof(roam_req->btk)); + WMITLV_SET_HDR(&roam_offload_ese->tlv_header, + WMITLV_TAG_STRUC_wmi_roam_ese_offload_tlv_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_roam_ese_offload_tlv_param)); + buf_ptr += + sizeof(wmi_roam_ese_offload_tlv_param); + } else if (auth_mode == WMI_AUTH_FT_RSNA + || auth_mode == WMI_AUTH_FT_RSNA_PSK + || (auth_mode == WMI_AUTH_OPEN + && roam_req->mdid.mdie_present)) { + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, + 0); + buf_ptr += WMI_TLV_HDR_SIZE; + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, + sizeof(wmi_roam_11r_offload_tlv_param)); + buf_ptr += WMI_TLV_HDR_SIZE; + roam_offload_11r = + (wmi_roam_11r_offload_tlv_param *) buf_ptr; + roam_offload_11r->r0kh_id_len = + roam_req->rokh_id_length; + qdf_mem_copy(roam_offload_11r->r0kh_id, + roam_req->rokh_id, + roam_offload_11r->r0kh_id_len); + qdf_mem_copy(roam_offload_11r->psk_msk, + roam_req->psk_pmk, + sizeof(roam_req->psk_pmk)); + roam_offload_11r->psk_msk_len = + roam_req->pmk_len; + roam_offload_11r->mdie_present = + roam_req->mdid.mdie_present; + roam_offload_11r->mdid = + roam_req->mdid.mobility_domain; + if (auth_mode == WMI_AUTH_OPEN) { + /* If FT-Open ensure pmk length + and r0khid len are zero */ + roam_offload_11r->r0kh_id_len = 0; + roam_offload_11r->psk_msk_len = 0; + } + WMITLV_SET_HDR(&roam_offload_11r->tlv_header, + WMITLV_TAG_STRUC_wmi_roam_11r_offload_tlv_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_roam_11r_offload_tlv_param)); + buf_ptr += + sizeof(wmi_roam_11r_offload_tlv_param); + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, + WMITLV_GET_STRUCT_TLVLEN(0)); + buf_ptr += WMI_TLV_HDR_SIZE; + } else { + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, + sizeof(wmi_roam_11i_offload_tlv_param)); + buf_ptr += WMI_TLV_HDR_SIZE; + roam_offload_11i = + (wmi_roam_11i_offload_tlv_param *) buf_ptr; + + if (roam_req->roam_key_mgmt_offload_enabled && + roam_req->fw_okc) { + WMI_SET_ROAM_OFFLOAD_OKC_ENABLED + (roam_offload_11i->flags); + WMI_LOGE("LFR3:OKC enabled"); + } else { + WMI_SET_ROAM_OFFLOAD_OKC_DISABLED + (roam_offload_11i->flags); + WMI_LOGE("LFR3:OKC disabled"); + } + if (roam_req->roam_key_mgmt_offload_enabled && + roam_req->fw_pmksa_cache) { + WMI_SET_ROAM_OFFLOAD_PMK_CACHE_ENABLED + (roam_offload_11i->flags); + WMI_LOGE("LFR3:PMKSA caching enabled"); + } else { + WMI_SET_ROAM_OFFLOAD_PMK_CACHE_DISABLED + (roam_offload_11i->flags); + WMI_LOGE("LFR3:PMKSA caching disabled"); + } + + qdf_mem_copy(roam_offload_11i->pmk, + roam_req->psk_pmk, + sizeof(roam_req->psk_pmk)); + roam_offload_11i->pmk_len = roam_req->pmk_len; + WMITLV_SET_HDR(&roam_offload_11i->tlv_header, + WMITLV_TAG_STRUC_wmi_roam_11i_offload_tlv_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_roam_11i_offload_tlv_param)); + buf_ptr += + sizeof(wmi_roam_11i_offload_tlv_param); + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, + 0); + buf_ptr += WMI_TLV_HDR_SIZE; + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, + 0); + buf_ptr += WMI_TLV_HDR_SIZE; + } + } else { + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, + WMITLV_GET_STRUCT_TLVLEN(0)); + buf_ptr += WMI_TLV_HDR_SIZE; + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, + WMITLV_GET_STRUCT_TLVLEN(0)); + buf_ptr += WMI_TLV_HDR_SIZE; + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, + WMITLV_GET_STRUCT_TLVLEN(0)); + buf_ptr += WMI_TLV_HDR_SIZE; + } + + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, + sizeof(*assoc_ies)); + buf_ptr += WMI_TLV_HDR_SIZE; + + assoc_ies = (wmi_tlv_buf_len_param *) buf_ptr; + WMITLV_SET_HDR(&assoc_ies->tlv_header, + WMITLV_TAG_STRUC_wmi_tlv_buf_len_param, + WMITLV_GET_STRUCT_TLVLEN(wmi_tlv_buf_len_param)); + assoc_ies->buf_len = roam_req->assoc_ie_length; + + buf_ptr += sizeof(*assoc_ies); + + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE, + roundup(assoc_ies->buf_len, sizeof(uint32_t))); + buf_ptr += WMI_TLV_HDR_SIZE; + + if (assoc_ies->buf_len != 0) { + qdf_mem_copy(buf_ptr, roam_req->assoc_ie, + assoc_ies->buf_len); + } + + } else { + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, + WMITLV_GET_STRUCT_TLVLEN(0)); + buf_ptr += WMI_TLV_HDR_SIZE; + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, + WMITLV_GET_STRUCT_TLVLEN(0)); + buf_ptr += WMI_TLV_HDR_SIZE; + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, + WMITLV_GET_STRUCT_TLVLEN(0)); + buf_ptr += WMI_TLV_HDR_SIZE; + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, + WMITLV_GET_STRUCT_TLVLEN(0)); + buf_ptr += WMI_TLV_HDR_SIZE; + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, + WMITLV_GET_STRUCT_TLVLEN(0)); + buf_ptr += WMI_TLV_HDR_SIZE; + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE, + WMITLV_GET_STRUCT_TLVLEN(0)); + } +#endif /* WLAN_FEATURE_ROAM_OFFLOAD */ + +send_roam_scan_mode_cmd: + status = wmi_unified_cmd_send(wmi_handle, buf, + len, WMI_ROAM_SCAN_MODE); + if (QDF_IS_STATUS_ERROR(status)) { + WMI_LOGE( + "wmi_unified_cmd_send WMI_ROAM_SCAN_MODE returned Error %d", + status); + wmi_buf_free(buf); + } + + return status; +} + + +/** + * send_roam_scan_offload_rssi_thresh_cmd_tlv() - set scan offload + * rssi threashold + * @wmi_handle: wmi handle + * @roam_req: Roaming request buffer + * + * Send WMI_ROAM_SCAN_RSSI_THRESHOLD TLV to firmware + * + * Return: QDF status + */ +QDF_STATUS send_roam_scan_offload_rssi_thresh_cmd_tlv(wmi_unified_t wmi_handle, + struct roam_offload_scan_rssi_params *roam_req) +{ + wmi_buf_t buf = NULL; + QDF_STATUS status; + int len; + uint8_t *buf_ptr; + wmi_roam_scan_rssi_threshold_fixed_param *rssi_threshold_fp; + wmi_roam_scan_extended_threshold_param *ext_thresholds = NULL; + wmi_roam_earlystop_rssi_thres_param *early_stop_thresholds = NULL; + wmi_roam_dense_thres_param *dense_thresholds = NULL; + + len = sizeof(wmi_roam_scan_rssi_threshold_fixed_param); + len += WMI_TLV_HDR_SIZE; /* TLV for ext_thresholds*/ + len += sizeof(wmi_roam_scan_extended_threshold_param); + len += WMI_TLV_HDR_SIZE; + len += sizeof(wmi_roam_earlystop_rssi_thres_param); + len += WMI_TLV_HDR_SIZE; /* TLV for dense thresholds*/ + len += sizeof(wmi_roam_dense_thres_param); + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMI_LOGE("%s : wmi_buf_alloc failed", __func__); + return QDF_STATUS_E_NOMEM; + } + + buf_ptr = (uint8_t *) wmi_buf_data(buf); + rssi_threshold_fp = + (wmi_roam_scan_rssi_threshold_fixed_param *) buf_ptr; + WMITLV_SET_HDR(&rssi_threshold_fp->tlv_header, + WMITLV_TAG_STRUC_wmi_roam_scan_rssi_threshold_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_roam_scan_rssi_threshold_fixed_param)); + /* fill in threshold values */ + rssi_threshold_fp->vdev_id = roam_req->session_id; + rssi_threshold_fp->roam_scan_rssi_thresh = roam_req->rssi_thresh; + rssi_threshold_fp->roam_rssi_thresh_diff = roam_req->rssi_thresh_diff; + rssi_threshold_fp->hirssi_scan_max_count = + roam_req->hi_rssi_scan_max_count; + rssi_threshold_fp->hirssi_scan_delta = + roam_req->hi_rssi_scan_rssi_delta; + rssi_threshold_fp->hirssi_upper_bound = roam_req->hi_rssi_scan_rssi_ub; + + buf_ptr += sizeof(wmi_roam_scan_rssi_threshold_fixed_param); + WMITLV_SET_HDR(buf_ptr, + WMITLV_TAG_ARRAY_STRUC, + sizeof(wmi_roam_scan_extended_threshold_param)); + buf_ptr += WMI_TLV_HDR_SIZE; + ext_thresholds = (wmi_roam_scan_extended_threshold_param *) buf_ptr; + + ext_thresholds->penalty_threshold_5g = roam_req->penalty_threshold_5g; + if (roam_req->raise_rssi_thresh_5g >= WMI_NOISE_FLOOR_DBM_DEFAULT) + ext_thresholds->boost_threshold_5g = + roam_req->boost_threshold_5g; + + ext_thresholds->boost_algorithm_5g = + WMI_ROAM_5G_BOOST_PENALIZE_ALGO_LINEAR; + ext_thresholds->boost_factor_5g = roam_req->raise_factor_5g; + ext_thresholds->penalty_algorithm_5g = + WMI_ROAM_5G_BOOST_PENALIZE_ALGO_LINEAR; + ext_thresholds->penalty_factor_5g = roam_req->drop_factor_5g; + ext_thresholds->max_boost_5g = roam_req->max_raise_rssi_5g; + ext_thresholds->max_penalty_5g = roam_req->max_drop_rssi_5g; + ext_thresholds->good_rssi_threshold = roam_req->good_rssi_threshold; + + WMITLV_SET_HDR(&ext_thresholds->tlv_header, + WMITLV_TAG_STRUC_wmi_roam_scan_extended_threshold_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_roam_scan_extended_threshold_param)); + buf_ptr += sizeof(wmi_roam_scan_extended_threshold_param); + WMITLV_SET_HDR(buf_ptr, + WMITLV_TAG_ARRAY_STRUC, + sizeof(wmi_roam_earlystop_rssi_thres_param)); + buf_ptr += WMI_TLV_HDR_SIZE; + early_stop_thresholds = (wmi_roam_earlystop_rssi_thres_param *) buf_ptr; + early_stop_thresholds->roam_earlystop_thres_min = + roam_req->roam_earlystop_thres_min; + early_stop_thresholds->roam_earlystop_thres_max = + roam_req->roam_earlystop_thres_max; + WMITLV_SET_HDR(&early_stop_thresholds->tlv_header, + WMITLV_TAG_STRUC_wmi_roam_earlystop_rssi_thres_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_roam_earlystop_rssi_thres_param)); + + buf_ptr += sizeof(wmi_roam_earlystop_rssi_thres_param); + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, + sizeof(wmi_roam_dense_thres_param)); + buf_ptr += WMI_TLV_HDR_SIZE; + dense_thresholds = (wmi_roam_dense_thres_param *) buf_ptr; + dense_thresholds->roam_dense_rssi_thres_offset = + roam_req->dense_rssi_thresh_offset; + dense_thresholds->roam_dense_min_aps = roam_req->dense_min_aps_cnt; + dense_thresholds->roam_dense_traffic_thres = + roam_req->traffic_threshold; + dense_thresholds->roam_dense_status = roam_req->initial_dense_status; + WMITLV_SET_HDR(&dense_thresholds->tlv_header, + WMITLV_TAG_STRUC_wmi_roam_dense_thres_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_roam_dense_thres_param)); + + status = wmi_unified_cmd_send(wmi_handle, buf, + len, WMI_ROAM_SCAN_RSSI_THRESHOLD); + if (QDF_IS_STATUS_ERROR(status)) { + WMI_LOGE("cmd WMI_ROAM_SCAN_RSSI_THRESHOLD returned Error %d", + status); + wmi_buf_free(buf); + } + + return status; +} + +/** + * send_adapt_dwelltime_params_cmd_tlv() - send wmi cmd of adaptive dwelltime + * configuration params + * @wma_handle: wma handler + * @dwelltime_params: pointer to dwelltime_params + * + * Return: QDF_STATUS_SUCCESS on success and QDF failure reason code for failure + */ +static +QDF_STATUS send_adapt_dwelltime_params_cmd_tlv(wmi_unified_t wmi_handle, + struct wmi_adaptive_dwelltime_params *dwelltime_params) +{ + wmi_scan_adaptive_dwell_config_fixed_param *dwell_param; + wmi_scan_adaptive_dwell_parameters_tlv *cmd; + wmi_buf_t buf; + uint8_t *buf_ptr; + int32_t err; + int len; + + len = sizeof(wmi_scan_adaptive_dwell_config_fixed_param); + len += WMI_TLV_HDR_SIZE; /* TLV for ext_thresholds*/ + len += sizeof(wmi_scan_adaptive_dwell_parameters_tlv); + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMI_LOGE("%s :Failed to allocate buffer to send cmd", + __func__); + return QDF_STATUS_E_NOMEM; + } + buf_ptr = (uint8_t *) wmi_buf_data(buf); + dwell_param = (wmi_scan_adaptive_dwell_config_fixed_param *) buf_ptr; + WMITLV_SET_HDR(&dwell_param->tlv_header, + WMITLV_TAG_STRUC_wmi_scan_adaptive_dwell_config_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_scan_adaptive_dwell_config_fixed_param)); + + dwell_param->enable = dwelltime_params->is_enabled; + buf_ptr += sizeof(wmi_scan_adaptive_dwell_config_fixed_param); + WMITLV_SET_HDR(buf_ptr, + WMITLV_TAG_ARRAY_STRUC, + sizeof(wmi_scan_adaptive_dwell_parameters_tlv)); + buf_ptr += WMI_TLV_HDR_SIZE; + + cmd = (wmi_scan_adaptive_dwell_parameters_tlv *) buf_ptr; + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_scan_adaptive_dwell_parameters_tlv, + WMITLV_GET_STRUCT_TLVLEN( + wmi_scan_adaptive_dwell_parameters_tlv)); + + cmd->default_adaptive_dwell_mode = dwelltime_params->dwelltime_mode; + cmd->adapative_lpf_weight = dwelltime_params->lpf_weight; + cmd->passive_monitor_interval_ms = dwelltime_params->passive_mon_intval; + cmd->wifi_activity_threshold_pct = dwelltime_params->wifi_act_threshold; + err = wmi_unified_cmd_send(wmi_handle, buf, + len, WMI_SCAN_ADAPTIVE_DWELL_CONFIG_CMDID); + if (err) { + WMI_LOGE("Failed to send adapt dwelltime cmd err=%d", err); + wmi_buf_free(buf); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + + +/** + * send_roam_scan_filter_cmd_tlv() - Filter to be applied while roaming + * @wmi_handle: wmi handle + * @roam_req: Request which contains the filters + * + * There are filters such as whitelist, blacklist and preferred + * list that need to be applied to the scan results to form the + * probable candidates for roaming. + * + * Return: Return success upon succesfully passing the + * parameters to the firmware, otherwise failure. + */ +QDF_STATUS send_roam_scan_filter_cmd_tlv(wmi_unified_t wmi_handle, + struct roam_scan_filter_params *roam_req) +{ + wmi_buf_t buf = NULL; + QDF_STATUS status; + uint32_t i; + uint32_t len; + uint8_t *buf_ptr; + wmi_roam_filter_fixed_param *roam_filter; + uint8_t *bssid_src_ptr = NULL; + wmi_mac_addr *bssid_dst_ptr = NULL; + wmi_ssid *ssid_ptr = NULL; + uint32_t *bssid_preferred_factor_ptr = NULL; + + len = sizeof(wmi_roam_filter_fixed_param); + + len += WMI_TLV_HDR_SIZE; + if (roam_req->num_bssid_black_list) + len += roam_req->num_bssid_black_list * sizeof(wmi_mac_addr); + len += WMI_TLV_HDR_SIZE; + if (roam_req->num_ssid_white_list) + len += roam_req->num_ssid_white_list * sizeof(wmi_ssid); + len += 2 * WMI_TLV_HDR_SIZE; + if (roam_req->num_bssid_preferred_list) { + len += roam_req->num_bssid_preferred_list * sizeof(wmi_mac_addr); + len += roam_req->num_bssid_preferred_list * sizeof(A_UINT32); + } + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMI_LOGE("%s : wmi_buf_alloc failed", __func__); + return QDF_STATUS_E_NOMEM; + } + + buf_ptr = (u_int8_t *) wmi_buf_data(buf); + roam_filter = (wmi_roam_filter_fixed_param *) buf_ptr; + WMITLV_SET_HDR(&roam_filter->tlv_header, + WMITLV_TAG_STRUC_wmi_roam_filter_fixed_param, + WMITLV_GET_STRUCT_TLVLEN(wmi_roam_filter_fixed_param)); + /* fill in fixed values */ + roam_filter->vdev_id = roam_req->session_id; + roam_filter->flags = 0; + roam_filter->op_bitmap = roam_req->op_bitmap; + roam_filter->num_bssid_black_list = roam_req->num_bssid_black_list; + roam_filter->num_ssid_white_list = roam_req->num_ssid_white_list; + roam_filter->num_bssid_preferred_list = + roam_req->num_bssid_preferred_list; + buf_ptr += sizeof(wmi_roam_filter_fixed_param); + + WMITLV_SET_HDR((buf_ptr), + WMITLV_TAG_ARRAY_FIXED_STRUC, + (roam_req->num_bssid_black_list * sizeof(wmi_mac_addr))); + bssid_src_ptr = (uint8_t *)&roam_req->bssid_avoid_list; + bssid_dst_ptr = (wmi_mac_addr *)(buf_ptr + WMI_TLV_HDR_SIZE); + for (i = 0; i < roam_req->num_bssid_black_list; i++) { + WMI_CHAR_ARRAY_TO_MAC_ADDR(bssid_src_ptr, bssid_dst_ptr); + bssid_src_ptr += ATH_MAC_LEN; + bssid_dst_ptr++; + } + buf_ptr += WMI_TLV_HDR_SIZE + + (roam_req->num_bssid_black_list * sizeof(wmi_mac_addr)); + WMITLV_SET_HDR((buf_ptr), + WMITLV_TAG_ARRAY_FIXED_STRUC, + (roam_req->num_ssid_white_list * sizeof(wmi_ssid))); + ssid_ptr = (wmi_ssid *)(buf_ptr + WMI_TLV_HDR_SIZE); + for (i = 0; i < roam_req->num_ssid_white_list; i++) { + qdf_mem_copy(&ssid_ptr->ssid, + &roam_req->ssid_allowed_list[i].mac_ssid, + roam_req->ssid_allowed_list[i].length); + ssid_ptr->ssid_len = roam_req->ssid_allowed_list[i].length; + ssid_ptr++; + } + buf_ptr += WMI_TLV_HDR_SIZE + (roam_req->num_ssid_white_list * + sizeof(wmi_ssid)); + WMITLV_SET_HDR((buf_ptr), + WMITLV_TAG_ARRAY_FIXED_STRUC, + (roam_req->num_bssid_preferred_list * sizeof(wmi_mac_addr))); + bssid_src_ptr = (uint8_t *)&roam_req->bssid_favored; + bssid_dst_ptr = (wmi_mac_addr *)(buf_ptr + WMI_TLV_HDR_SIZE); + for (i = 0; i < roam_req->num_bssid_preferred_list; i++) { + WMI_CHAR_ARRAY_TO_MAC_ADDR(bssid_src_ptr, + (wmi_mac_addr *)bssid_dst_ptr); + bssid_src_ptr += ATH_MAC_LEN; + bssid_dst_ptr++; + } + buf_ptr += WMI_TLV_HDR_SIZE + + (roam_req->num_bssid_preferred_list * sizeof(wmi_mac_addr)); + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_UINT32, + (roam_req->num_bssid_preferred_list * sizeof(uint32_t))); + bssid_preferred_factor_ptr = (uint32_t *)(buf_ptr + WMI_TLV_HDR_SIZE); + for (i = 0; i < roam_req->num_bssid_preferred_list; i++) { + *bssid_preferred_factor_ptr = + roam_req->bssid_favored_factor[i]; + bssid_preferred_factor_ptr++; + } + buf_ptr += WMI_TLV_HDR_SIZE + + (roam_req->num_bssid_preferred_list * sizeof(uint32_t)); + + status = wmi_unified_cmd_send(wmi_handle, buf, + len, WMI_ROAM_FILTER_CMDID); + if (QDF_IS_STATUS_ERROR(status)) { + WMI_LOGE("cmd WMI_ROAM_FILTER_CMDID returned Error %d", + status); + wmi_buf_free(buf); + } + + return status; +} + +/** send_set_epno_network_list_cmd_tlv() - set epno network list + * @wmi_handle: wmi handle + * @req: epno config params request structure + * + * This function reads the incoming epno config request structure + * and constructs the WMI message to the firmware. + * + * Returns: 0 on success, error number otherwise + */ +QDF_STATUS send_set_epno_network_list_cmd_tlv(wmi_unified_t wmi_handle, + struct wifi_enhanched_pno_params *req) +{ + wmi_nlo_config_cmd_fixed_param *cmd; + nlo_configured_parameters *nlo_list; + enlo_candidate_score_params *cand_score_params; + u_int8_t i, *buf_ptr; + wmi_buf_t buf; + uint32_t len; + QDF_STATUS ret; + + /* Fixed Params */ + len = sizeof(*cmd); + if (req->num_networks) { + /* TLV place holder for array of structures + * then each nlo_configured_parameters(nlo_list) TLV. + */ + len += WMI_TLV_HDR_SIZE; + len += (sizeof(nlo_configured_parameters) + * QDF_MIN(req->num_networks, WMI_NLO_MAX_SSIDS)); + /* TLV for array of uint32 channel_list */ + len += WMI_TLV_HDR_SIZE; + /* TLV for nlo_channel_prediction_cfg */ + len += WMI_TLV_HDR_SIZE; + /* TLV for candidate score params */ + len += sizeof(enlo_candidate_score_params); + } + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMI_LOGE("%s: Failed allocate wmi buffer", __func__); + return QDF_STATUS_E_NOMEM; + } + + cmd = (wmi_nlo_config_cmd_fixed_param *) wmi_buf_data(buf); + + buf_ptr = (u_int8_t *) cmd; + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_nlo_config_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN( + wmi_nlo_config_cmd_fixed_param)); + cmd->vdev_id = req->session_id; + + /* set flag to reset if num of networks are 0 */ + cmd->flags = (req->num_networks == 0 ? + WMI_NLO_CONFIG_ENLO_RESET : WMI_NLO_CONFIG_ENLO); + + buf_ptr += sizeof(wmi_nlo_config_cmd_fixed_param); + + cmd->no_of_ssids = QDF_MIN(req->num_networks, WMI_NLO_MAX_SSIDS); + WMI_LOGD("SSID count: %d flags: %d", + cmd->no_of_ssids, cmd->flags); + + /* Fill nlo_config only when num_networks are non zero */ + if (cmd->no_of_ssids) { + /* Fill networks */ + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, + cmd->no_of_ssids * sizeof(nlo_configured_parameters)); + buf_ptr += WMI_TLV_HDR_SIZE; + + nlo_list = (nlo_configured_parameters *) buf_ptr; + for (i = 0; i < cmd->no_of_ssids; i++) { + WMITLV_SET_HDR(&nlo_list[i].tlv_header, + WMITLV_TAG_ARRAY_BYTE, + WMITLV_GET_STRUCT_TLVLEN( + nlo_configured_parameters)); + /* Copy ssid and it's length */ + nlo_list[i].ssid.valid = true; + nlo_list[i].ssid.ssid.ssid_len = + req->networks[i].ssid.length; + qdf_mem_copy(nlo_list[i].ssid.ssid.ssid, + req->networks[i].ssid.mac_ssid, + nlo_list[i].ssid.ssid.ssid_len); + WMI_LOGD("index: %d ssid: %.*s len: %d", i, + nlo_list[i].ssid.ssid.ssid_len, + (char *) nlo_list[i].ssid.ssid.ssid, + nlo_list[i].ssid.ssid.ssid_len); + + /* Copy pno flags */ + nlo_list[i].bcast_nw_type.valid = true; + nlo_list[i].bcast_nw_type.bcast_nw_type = + req->networks[i].flags; + WMI_LOGD("PNO flags (%u)", + nlo_list[i].bcast_nw_type.bcast_nw_type); + + /* Copy auth bit field */ + nlo_list[i].auth_type.valid = true; + nlo_list[i].auth_type.auth_type = + req->networks[i].auth_bit_field; + WMI_LOGD("Auth bit field (%u)", + nlo_list[i].auth_type.auth_type); + } + + buf_ptr += cmd->no_of_ssids * sizeof(nlo_configured_parameters); + /* Fill the channel list */ + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_UINT32, 0); + buf_ptr += WMI_TLV_HDR_SIZE; + + /* Fill prediction_param */ + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, 0); + buf_ptr += WMI_TLV_HDR_SIZE; + + /* Fill epno candidate score params */ + cand_score_params = (enlo_candidate_score_params *) buf_ptr; + WMITLV_SET_HDR(buf_ptr, + WMITLV_TAG_STRUC_enlo_candidate_score_param, + WMITLV_GET_STRUCT_TLVLEN(enlo_candidate_score_params)); + cand_score_params->min5GHz_rssi = + req->min_5ghz_rssi; + cand_score_params->min24GHz_rssi = + req->min_24ghz_rssi; + cand_score_params->initial_score_max = + req->initial_score_max; + cand_score_params->current_connection_bonus = + req->current_connection_bonus; + cand_score_params->same_network_bonus = + req->same_network_bonus; + cand_score_params->secure_bonus = + req->secure_bonus; + cand_score_params->band5GHz_bonus = + req->band_5ghz_bonus; + buf_ptr += sizeof(enlo_candidate_score_params); + } + + ret = wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_NETWORK_LIST_OFFLOAD_CONFIG_CMDID); + if (QDF_IS_STATUS_ERROR(ret)) { + WMI_LOGE("%s: Failed to send nlo wmi cmd", __func__); + wmi_buf_free(buf); + return QDF_STATUS_E_INVAL; + } + + WMI_LOGD("set ePNO list request sent successfully for vdev %d", + req->session_id); + + return ret; +} + + +/** send_ipa_offload_control_cmd_tlv() - ipa offload control parameter + * @wmi_handle: wmi handle + * @ipa_offload: ipa offload control parameter + * + * Returns: 0 on success, error number otherwise + */ +QDF_STATUS send_ipa_offload_control_cmd_tlv(wmi_unified_t wmi_handle, + struct ipa_offload_control_params *ipa_offload) +{ + wmi_ipa_offload_enable_disable_cmd_fixed_param *cmd; + wmi_buf_t wmi_buf; + uint32_t len; + u_int8_t *buf_ptr; + + len = sizeof(*cmd); + wmi_buf = wmi_buf_alloc(wmi_handle, len); + if (!wmi_buf) { + WMI_LOGE("%s: wmi_buf_alloc failed (len=%d)", __func__, len); + return QDF_STATUS_E_NOMEM; + } + + WMI_LOGE("%s: offload_type=%d, enable=%d", __func__, + ipa_offload->offload_type, ipa_offload->enable); + + buf_ptr = (u_int8_t *)wmi_buf_data(wmi_buf); + + cmd = (wmi_ipa_offload_enable_disable_cmd_fixed_param *)buf_ptr; + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUCT_wmi_ipa_offload_enable_disable_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN( + wmi_ipa_offload_enable_disable_cmd_fixed_param)); + + cmd->offload_type = ipa_offload->offload_type; + cmd->vdev_id = ipa_offload->vdev_id; + cmd->enable = ipa_offload->enable; + + if (wmi_unified_cmd_send(wmi_handle, wmi_buf, len, + WMI_IPA_OFFLOAD_ENABLE_DISABLE_CMDID)) { + WMI_LOGE("%s: failed to command", __func__); + wmi_buf_free(wmi_buf); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * send_extscan_get_capabilities_cmd_tlv() - extscan get capabilities + * @wmi_handle: wmi handle + * @pgetcapab: get capabilities params + * + * This function send request to fw to get extscan capabilities. + * + * Return: CDF status + */ +QDF_STATUS send_extscan_get_capabilities_cmd_tlv(wmi_unified_t wmi_handle, + struct extscan_capabilities_params *pgetcapab) +{ + wmi_extscan_get_capabilities_cmd_fixed_param *cmd; + wmi_buf_t wmi_buf; + uint32_t len; + uint8_t *buf_ptr; + + len = sizeof(*cmd); + wmi_buf = wmi_buf_alloc(wmi_handle, len); + if (!wmi_buf) { + WMI_LOGE("%s: wmi_buf_alloc failed", __func__); + return QDF_STATUS_E_NOMEM; + } + buf_ptr = (uint8_t *) wmi_buf_data(wmi_buf); + + cmd = (wmi_extscan_get_capabilities_cmd_fixed_param *) buf_ptr; + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_extscan_get_capabilities_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_extscan_get_capabilities_cmd_fixed_param)); + + cmd->request_id = pgetcapab->request_id; + + if (wmi_unified_cmd_send(wmi_handle, wmi_buf, len, + WMI_EXTSCAN_GET_CAPABILITIES_CMDID)) { + WMI_LOGE("%s: failed to command", __func__); + wmi_buf_free(wmi_buf); + return QDF_STATUS_E_FAILURE; + } + return QDF_STATUS_SUCCESS; +} + +/** + * send_extscan_get_cached_results_cmd_tlv() - extscan get cached results + * @wmi_handle: wmi handle + * @pcached_results: cached results parameters + * + * This function send request to fw to get cached results. + * + * Return: CDF status + */ +QDF_STATUS send_extscan_get_cached_results_cmd_tlv(wmi_unified_t wmi_handle, + struct extscan_cached_result_params *pcached_results) +{ + wmi_extscan_get_cached_results_cmd_fixed_param *cmd; + wmi_buf_t wmi_buf; + uint32_t len; + uint8_t *buf_ptr; + + len = sizeof(*cmd); + wmi_buf = wmi_buf_alloc(wmi_handle, len); + if (!wmi_buf) { + WMI_LOGE("%s: wmi_buf_alloc failed", __func__); + return QDF_STATUS_E_NOMEM; + } + buf_ptr = (uint8_t *) wmi_buf_data(wmi_buf); + + cmd = (wmi_extscan_get_cached_results_cmd_fixed_param *) buf_ptr; + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_extscan_get_cached_results_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_extscan_get_cached_results_cmd_fixed_param)); + + cmd->request_id = pcached_results->request_id; + cmd->vdev_id = pcached_results->session_id; + cmd->control_flags = pcached_results->flush; + + if (wmi_unified_cmd_send(wmi_handle, wmi_buf, len, + WMI_EXTSCAN_GET_CACHED_RESULTS_CMDID)) { + WMI_LOGE("%s: failed to command", __func__); + wmi_buf_free(wmi_buf); + return QDF_STATUS_E_FAILURE; + } + return QDF_STATUS_SUCCESS; +} + +/** + * send_extscan_stop_change_monitor_cmd_tlv() - send stop change monitor cmd + * @wmi_handle: wmi handle + * @reset_req: Reset change request params + * + * This function sends stop change monitor request to fw. + * + * Return: CDF status + */ +QDF_STATUS send_extscan_stop_change_monitor_cmd_tlv(wmi_unified_t wmi_handle, + struct extscan_capabilities_reset_params *reset_req) +{ + wmi_extscan_configure_wlan_change_monitor_cmd_fixed_param *cmd; + wmi_buf_t wmi_buf; + uint32_t len; + uint8_t *buf_ptr; + int change_list = 0; + + len = sizeof(*cmd); + + /* reset significant change tlv is set to 0 */ + len += WMI_TLV_HDR_SIZE; + len += change_list * sizeof(wmi_extscan_wlan_change_bssid_param); + wmi_buf = wmi_buf_alloc(wmi_handle, len); + if (!wmi_buf) { + WMI_LOGE("%s: wmi_buf_alloc failed", __func__); + return QDF_STATUS_E_NOMEM; + } + buf_ptr = (uint8_t *) wmi_buf_data(wmi_buf); + + cmd = (wmi_extscan_configure_wlan_change_monitor_cmd_fixed_param *) + buf_ptr; + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_extscan_configure_wlan_change_monitor_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_extscan_configure_wlan_change_monitor_cmd_fixed_param)); + + cmd->request_id = reset_req->request_id; + cmd->vdev_id = reset_req->session_id; + cmd->mode = 0; + + buf_ptr += sizeof(*cmd); + WMITLV_SET_HDR(buf_ptr, + WMITLV_TAG_ARRAY_STRUC, + change_list * + sizeof(wmi_extscan_wlan_change_bssid_param)); + buf_ptr += WMI_TLV_HDR_SIZE + (change_list * + sizeof + (wmi_extscan_wlan_change_bssid_param)); + + if (wmi_unified_cmd_send(wmi_handle, wmi_buf, len, + WMI_EXTSCAN_CONFIGURE_WLAN_CHANGE_MONITOR_CMDID)) { + WMI_LOGE("%s: failed to command", __func__); + wmi_buf_free(wmi_buf); + return QDF_STATUS_E_FAILURE; + } + return QDF_STATUS_SUCCESS; +} + +/** + * wmi_get_buf_extscan_change_monitor_cmd() - fill change monitor request + * @wmi_handle: wmi handle + * @psigchange: change monitor request params + * @buf: wmi buffer + * @buf_len: buffer length + * + * This function fills elements of change monitor request buffer. + * + * Return: CDF status + */ +static QDF_STATUS wmi_get_buf_extscan_change_monitor_cmd(wmi_unified_t wmi_handle, + struct extscan_set_sig_changereq_params + *psigchange, wmi_buf_t *buf, int *buf_len) +{ + wmi_extscan_configure_wlan_change_monitor_cmd_fixed_param *cmd; + wmi_extscan_wlan_change_bssid_param *dest_chglist; + uint8_t *buf_ptr; + int j; + int len = sizeof(*cmd); + uint32_t numap = psigchange->num_ap; + struct ap_threshold_params *src_ap = psigchange->ap; + + if (!numap || (numap > WMI_WLAN_EXTSCAN_MAX_SIGNIFICANT_CHANGE_APS)) { + WMI_LOGE("%s: Invalid number of bssid's", __func__); + return QDF_STATUS_E_INVAL; + } + len += WMI_TLV_HDR_SIZE; + len += numap * sizeof(wmi_extscan_wlan_change_bssid_param); + + *buf = wmi_buf_alloc(wmi_handle, len); + if (!*buf) { + WMI_LOGP("%s: failed to allocate memory for change monitor cmd", + __func__); + return QDF_STATUS_E_FAILURE; + } + buf_ptr = (uint8_t *) wmi_buf_data(*buf); + cmd = + (wmi_extscan_configure_wlan_change_monitor_cmd_fixed_param *) + buf_ptr; + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_extscan_configure_wlan_change_monitor_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_extscan_configure_wlan_change_monitor_cmd_fixed_param)); + + cmd->request_id = psigchange->request_id; + cmd->vdev_id = psigchange->session_id; + cmd->total_entries = numap; + cmd->mode = 1; + cmd->num_entries_in_page = numap; + cmd->lost_ap_scan_count = psigchange->lostap_sample_size; + cmd->max_rssi_samples = psigchange->rssi_sample_size; + cmd->rssi_averaging_samples = psigchange->rssi_sample_size; + cmd->max_out_of_range_count = psigchange->min_breaching; + + buf_ptr += sizeof(*cmd); + WMITLV_SET_HDR(buf_ptr, + WMITLV_TAG_ARRAY_STRUC, + numap * sizeof(wmi_extscan_wlan_change_bssid_param)); + dest_chglist = (wmi_extscan_wlan_change_bssid_param *) + (buf_ptr + WMI_TLV_HDR_SIZE); + + for (j = 0; j < numap; j++) { + WMITLV_SET_HDR(dest_chglist, + WMITLV_TAG_STRUC_wmi_extscan_bucket_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_extscan_wlan_change_bssid_param)); + + dest_chglist->lower_rssi_limit = src_ap->low; + dest_chglist->upper_rssi_limit = src_ap->high; + WMI_CHAR_ARRAY_TO_MAC_ADDR(src_ap->bssid.bytes, + &dest_chglist->bssid); + + WMI_LOGD("%s: min_rssi %d", __func__, + dest_chglist->lower_rssi_limit); + dest_chglist++; + src_ap++; + } + buf_ptr += WMI_TLV_HDR_SIZE + + (numap * sizeof(wmi_extscan_wlan_change_bssid_param)); + *buf_len = len; + return QDF_STATUS_SUCCESS; +} + +/** + * send_extscan_start_change_monitor_cmd_tlv() - send start change monitor cmd + * @wmi_handle: wmi handle + * @psigchange: change monitor request params + * + * This function sends start change monitor request to fw. + * + * Return: CDF status + */ +QDF_STATUS send_extscan_start_change_monitor_cmd_tlv(wmi_unified_t wmi_handle, + struct extscan_set_sig_changereq_params * + psigchange) +{ + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + wmi_buf_t buf; + int len; + + + qdf_status = wmi_get_buf_extscan_change_monitor_cmd(wmi_handle, + psigchange, &buf, + &len); + if (qdf_status != QDF_STATUS_SUCCESS) { + WMI_LOGE("%s: Failed to get buffer for change monitor cmd", + __func__); + return QDF_STATUS_E_FAILURE; + } + if (!buf) { + WMI_LOGE("%s: Failed to get buffer", __func__); + return QDF_STATUS_E_FAILURE; + } + if (wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_EXTSCAN_CONFIGURE_WLAN_CHANGE_MONITOR_CMDID)) { + WMI_LOGE("%s: failed to send command", __func__); + wmi_buf_free(buf); + return QDF_STATUS_E_FAILURE; + } + return QDF_STATUS_SUCCESS; +} + +/** + * send_extscan_stop_hotlist_monitor_cmd_tlv() - stop hotlist monitor + * @wmi_handle: wmi handle + * @photlist_reset: hotlist reset params + * + * This function configures hotlist monitor to stop in fw. + * + * Return: CDF status + */ +QDF_STATUS send_extscan_stop_hotlist_monitor_cmd_tlv(wmi_unified_t wmi_handle, + struct extscan_bssid_hotlist_reset_params *photlist_reset) +{ + wmi_extscan_configure_hotlist_monitor_cmd_fixed_param *cmd; + wmi_buf_t wmi_buf; + uint32_t len; + uint8_t *buf_ptr; + int hotlist_entries = 0; + + len = sizeof(*cmd); + + /* reset bssid hotlist with tlv set to 0 */ + len += WMI_TLV_HDR_SIZE; + len += hotlist_entries * sizeof(wmi_extscan_hotlist_entry); + + wmi_buf = wmi_buf_alloc(wmi_handle, len); + if (!wmi_buf) { + WMI_LOGE("%s: wmi_buf_alloc failed", __func__); + return QDF_STATUS_E_NOMEM; + } + + buf_ptr = (uint8_t *) wmi_buf_data(wmi_buf); + cmd = (wmi_extscan_configure_hotlist_monitor_cmd_fixed_param *) + buf_ptr; + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_extscan_configure_hotlist_monitor_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_extscan_configure_hotlist_monitor_cmd_fixed_param)); + + cmd->request_id = photlist_reset->request_id; + cmd->vdev_id = photlist_reset->session_id; + cmd->mode = 0; + + buf_ptr += sizeof(*cmd); + WMITLV_SET_HDR(buf_ptr, + WMITLV_TAG_ARRAY_STRUC, + hotlist_entries * sizeof(wmi_extscan_hotlist_entry)); + buf_ptr += WMI_TLV_HDR_SIZE + + (hotlist_entries * sizeof(wmi_extscan_hotlist_entry)); + + if (wmi_unified_cmd_send(wmi_handle, wmi_buf, len, + WMI_EXTSCAN_CONFIGURE_HOTLIST_MONITOR_CMDID)) { + WMI_LOGE("%s: failed to command", __func__); + wmi_buf_free(wmi_buf); + return QDF_STATUS_E_FAILURE; + } + return QDF_STATUS_SUCCESS; +} + +/** + * send_stop_extscan_cmd_tlv() - stop extscan command to fw. + * @wmi_handle: wmi handle + * @pstopcmd: stop scan command request params + * + * This function sends stop extscan request to fw. + * + * Return: CDF Status. + */ +QDF_STATUS send_stop_extscan_cmd_tlv(wmi_unified_t wmi_handle, + struct extscan_stop_req_params *pstopcmd) +{ + wmi_extscan_stop_cmd_fixed_param *cmd; + wmi_buf_t wmi_buf; + uint32_t len; + uint8_t *buf_ptr; + + len = sizeof(*cmd); + wmi_buf = wmi_buf_alloc(wmi_handle, len); + if (!wmi_buf) { + WMI_LOGE("%s: wmi_buf_alloc failed", __func__); + return QDF_STATUS_E_NOMEM; + } + buf_ptr = (uint8_t *) wmi_buf_data(wmi_buf); + cmd = (wmi_extscan_stop_cmd_fixed_param *) buf_ptr; + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_extscan_stop_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_extscan_stop_cmd_fixed_param)); + + cmd->request_id = pstopcmd->request_id; + cmd->vdev_id = pstopcmd->session_id; + + if (wmi_unified_cmd_send(wmi_handle, wmi_buf, len, + WMI_EXTSCAN_STOP_CMDID)) { + WMI_LOGE("%s: failed to command", __func__); + wmi_buf_free(wmi_buf); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * wmi_get_buf_extscan_start_cmd() - Fill extscan start request + * @wmi_handle: wmi handle + * @pstart: scan command request params + * @buf: event buffer + * @buf_len: length of buffer + * + * This function fills individual elements of extscan request and + * TLV for buckets, channel list. + * + * Return: CDF Status. + */ +static +QDF_STATUS wmi_get_buf_extscan_start_cmd(wmi_unified_t wmi_handle, + struct wifi_scan_cmd_req_params *pstart, + wmi_buf_t *buf, int *buf_len) +{ + wmi_extscan_start_cmd_fixed_param *cmd; + wmi_extscan_bucket *dest_blist; + wmi_extscan_bucket_channel *dest_clist; + struct wifi_scan_bucket_params *src_bucket = pstart->buckets; + struct wifi_scan_channelspec_params *src_channel = src_bucket->channels; + struct wifi_scan_channelspec_params save_channel[WMI_WLAN_EXTSCAN_MAX_CHANNELS]; + + uint8_t *buf_ptr; + int i, k, count = 0; + int len = sizeof(*cmd); + int nbuckets = pstart->numBuckets; + int nchannels = 0; + + /* These TLV's are are NULL by default */ + uint32_t ie_len_with_pad = 0; + int num_ssid = 0; + int num_bssid = 0; + int ie_len = 0; + + uint32_t base_period = pstart->basePeriod; + + /* TLV placeholder for ssid_list (NULL) */ + len += WMI_TLV_HDR_SIZE; + len += num_ssid * sizeof(wmi_ssid); + + /* TLV placeholder for bssid_list (NULL) */ + len += WMI_TLV_HDR_SIZE; + len += num_bssid * sizeof(wmi_mac_addr); + + /* TLV placeholder for ie_data (NULL) */ + len += WMI_TLV_HDR_SIZE; + len += ie_len * sizeof(uint32_t); + + /* TLV placeholder for bucket */ + len += WMI_TLV_HDR_SIZE; + len += nbuckets * sizeof(wmi_extscan_bucket); + + /* TLV channel placeholder */ + len += WMI_TLV_HDR_SIZE; + for (i = 0; i < nbuckets; i++) { + nchannels += src_bucket->numChannels; + src_bucket++; + } + + WMI_LOGD("%s: Total buckets: %d total #of channels is %d", + __func__, nbuckets, nchannels); + len += nchannels * sizeof(wmi_extscan_bucket_channel); + /* Allocate the memory */ + *buf = wmi_buf_alloc(wmi_handle, len); + if (!*buf) { + WMI_LOGP("%s: failed to allocate memory" + " for start extscan cmd", __func__); + return QDF_STATUS_E_NOMEM; + } + buf_ptr = (uint8_t *) wmi_buf_data(*buf); + cmd = (wmi_extscan_start_cmd_fixed_param *) buf_ptr; + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_extscan_start_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_extscan_start_cmd_fixed_param)); + + cmd->request_id = pstart->requestId; + cmd->vdev_id = pstart->sessionId; + cmd->base_period = pstart->basePeriod; + cmd->num_buckets = nbuckets; + cmd->configuration_flags = 0; + if (pstart->configuration_flags & WMI_EXTSCAN_LP_EXTENDED_BATCHING) + cmd->configuration_flags |= WMI_EXTSCAN_EXTENDED_BATCHING_EN; + WMI_LOGI("%s: configuration_flags: 0x%x", __func__, + cmd->configuration_flags); +#ifdef FEATURE_WLAN_EXTSCAN + cmd->min_rest_time = WMI_EXTSCAN_REST_TIME; + cmd->max_rest_time = WMI_EXTSCAN_REST_TIME; + cmd->max_scan_time = WMI_EXTSCAN_MAX_SCAN_TIME; + cmd->burst_duration = WMI_EXTSCAN_BURST_DURATION; +#endif + cmd->max_bssids_per_scan_cycle = pstart->maxAPperScan; + + /* The max dwell time is retrieved from the first channel + * of the first bucket and kept common for all channels. + */ + cmd->min_dwell_time_active = pstart->min_dwell_time_active; + cmd->max_dwell_time_active = pstart->max_dwell_time_active; + cmd->min_dwell_time_passive = pstart->min_dwell_time_passive; + cmd->max_dwell_time_passive = pstart->max_dwell_time_passive; + cmd->max_bssids_per_scan_cycle = pstart->maxAPperScan; + cmd->max_table_usage = pstart->report_threshold_percent; + cmd->report_threshold_num_scans = pstart->report_threshold_num_scans; + + cmd->repeat_probe_time = cmd->max_dwell_time_active / + WMI_SCAN_NPROBES_DEFAULT; + cmd->probe_delay = 0; + cmd->probe_spacing_time = 0; + cmd->idle_time = 0; + cmd->scan_ctrl_flags = WMI_SCAN_ADD_BCAST_PROBE_REQ | + WMI_SCAN_ADD_CCK_RATES | + WMI_SCAN_ADD_OFDM_RATES | + WMI_SCAN_ADD_SPOOFED_MAC_IN_PROBE_REQ | + WMI_SCAN_ADD_DS_IE_IN_PROBE_REQ; + WMI_SCAN_SET_DWELL_MODE(cmd->scan_ctrl_flags, + pstart->extscan_adaptive_dwell_mode); + cmd->scan_priority = WMI_SCAN_PRIORITY_VERY_LOW; + cmd->num_ssids = 0; + cmd->num_bssid = 0; + cmd->ie_len = 0; + cmd->n_probes = (cmd->repeat_probe_time > 0) ? + cmd->max_dwell_time_active / cmd->repeat_probe_time : 0; + + buf_ptr += sizeof(*cmd); + WMITLV_SET_HDR(buf_ptr, + WMITLV_TAG_ARRAY_FIXED_STRUC, + num_ssid * sizeof(wmi_ssid)); + buf_ptr += WMI_TLV_HDR_SIZE + (num_ssid * sizeof(wmi_ssid)); + + WMITLV_SET_HDR(buf_ptr, + WMITLV_TAG_ARRAY_FIXED_STRUC, + num_bssid * sizeof(wmi_mac_addr)); + buf_ptr += WMI_TLV_HDR_SIZE + (num_bssid * sizeof(wmi_mac_addr)); + + ie_len_with_pad = 0; + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE, + ie_len_with_pad); + buf_ptr += WMI_TLV_HDR_SIZE + ie_len_with_pad; + + WMITLV_SET_HDR(buf_ptr, + WMITLV_TAG_ARRAY_STRUC, + nbuckets * sizeof(wmi_extscan_bucket)); + dest_blist = (wmi_extscan_bucket *) + (buf_ptr + WMI_TLV_HDR_SIZE); + src_bucket = pstart->buckets; + + /* Retrieve scanning information from each bucket and + * channels and send it to the target + */ + for (i = 0; i < nbuckets; i++) { + WMITLV_SET_HDR(dest_blist, + WMITLV_TAG_STRUC_wmi_extscan_bucket_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN(wmi_extscan_bucket)); + + dest_blist->bucket_id = src_bucket->bucket; + dest_blist->base_period_multiplier = + src_bucket->period / base_period; + dest_blist->min_period = src_bucket->period; + dest_blist->max_period = src_bucket->max_period; + dest_blist->exp_backoff = src_bucket->exponent; + dest_blist->exp_max_step_count = src_bucket->step_count; + dest_blist->channel_band = src_bucket->band; + dest_blist->num_channels = src_bucket->numChannels; + dest_blist->notify_extscan_events = 0; + + if (src_bucket->reportEvents & WMI_EXTSCAN_REPORT_EVENTS_EACH_SCAN) + dest_blist->notify_extscan_events = + WMI_EXTSCAN_CYCLE_COMPLETED_EVENT | + WMI_EXTSCAN_CYCLE_STARTED_EVENT; + + if (src_bucket->reportEvents & + WMI_EXTSCAN_REPORT_EVENTS_FULL_RESULTS) { + dest_blist->forwarding_flags = + WMI_EXTSCAN_FORWARD_FRAME_TO_HOST; + dest_blist->notify_extscan_events |= + WMI_EXTSCAN_BUCKET_COMPLETED_EVENT | + WMI_EXTSCAN_CYCLE_STARTED_EVENT | + WMI_EXTSCAN_CYCLE_COMPLETED_EVENT; + } else { + dest_blist->forwarding_flags = + WMI_EXTSCAN_NO_FORWARDING; + } + + if (src_bucket->reportEvents & WMI_EXTSCAN_REPORT_EVENTS_NO_BATCH) + dest_blist->configuration_flags = 0; + else + dest_blist->configuration_flags = + WMI_EXTSCAN_BUCKET_CACHE_RESULTS; + + WMI_LOGI("%s: ntfy_extscan_events:%u cfg_flags:%u fwd_flags:%u", + __func__, dest_blist->notify_extscan_events, + dest_blist->configuration_flags, + dest_blist->forwarding_flags); + + dest_blist->min_dwell_time_active = + src_bucket->min_dwell_time_active; + dest_blist->max_dwell_time_active = + src_bucket->max_dwell_time_active; + dest_blist->min_dwell_time_passive = + src_bucket->min_dwell_time_passive; + dest_blist->max_dwell_time_passive = + src_bucket->max_dwell_time_passive; + src_channel = src_bucket->channels; + + /* save the channel info to later populate + * the channel TLV + */ + for (k = 0; k < src_bucket->numChannels; k++) { + save_channel[count++].channel = src_channel->channel; + src_channel++; + } + dest_blist++; + src_bucket++; + } + buf_ptr += WMI_TLV_HDR_SIZE + (nbuckets * sizeof(wmi_extscan_bucket)); + WMITLV_SET_HDR(buf_ptr, + WMITLV_TAG_ARRAY_STRUC, + nchannels * sizeof(wmi_extscan_bucket_channel)); + dest_clist = (wmi_extscan_bucket_channel *) + (buf_ptr + WMI_TLV_HDR_SIZE); + + /* Active or passive scan is based on the bucket dwell time + * and channel specific active,passive scans are not + * supported yet + */ + for (i = 0; i < nchannels; i++) { + WMITLV_SET_HDR(dest_clist, + WMITLV_TAG_STRUC_wmi_extscan_bucket_channel_event_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_extscan_bucket_channel)); + dest_clist->channel = save_channel[i].channel; + dest_clist++; + } + buf_ptr += WMI_TLV_HDR_SIZE + + (nchannels * sizeof(wmi_extscan_bucket_channel)); + *buf_len = len; + return QDF_STATUS_SUCCESS; +} + +/** + * send_start_extscan_cmd_tlv() - start extscan command to fw. + * @wmi_handle: wmi handle + * @pstart: scan command request params + * + * This function sends start extscan request to fw. + * + * Return: CDF Status. + */ +QDF_STATUS send_start_extscan_cmd_tlv(wmi_unified_t wmi_handle, + struct wifi_scan_cmd_req_params *pstart) +{ + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + wmi_buf_t buf; + int len; + + /* Fill individual elements of extscan request and + * TLV for buckets, channel list. + */ + qdf_status = wmi_get_buf_extscan_start_cmd(wmi_handle, + pstart, &buf, &len); + if (qdf_status != QDF_STATUS_SUCCESS) { + WMI_LOGE("%s: Failed to get buffer for ext scan cmd", __func__); + return QDF_STATUS_E_FAILURE; + } + if (!buf) { + WMI_LOGE("%s:Failed to get buffer" + "for current extscan info", __func__); + return QDF_STATUS_E_FAILURE; + } + if (wmi_unified_cmd_send(wmi_handle, buf, + len, WMI_EXTSCAN_START_CMDID)) { + WMI_LOGE("%s: failed to send command", __func__); + wmi_buf_free(buf); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * send_plm_stop_cmd_tlv() - plm stop request + * @wmi_handle: wmi handle + * @plm: plm request parameters + * + * This function request FW to stop PLM. + * + * Return: CDF status + */ +QDF_STATUS send_plm_stop_cmd_tlv(wmi_unified_t wmi_handle, + const struct plm_req_params *plm) +{ + wmi_vdev_plmreq_stop_cmd_fixed_param *cmd; + int32_t len; + wmi_buf_t buf; + uint8_t *buf_ptr; + int ret; + + len = sizeof(*cmd); + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMI_LOGE("%s: Failed allocate wmi buffer", __func__); + return QDF_STATUS_E_NOMEM; + } + + cmd = (wmi_vdev_plmreq_stop_cmd_fixed_param *) wmi_buf_data(buf); + + buf_ptr = (uint8_t *) cmd; + + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_vdev_plmreq_stop_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_vdev_plmreq_stop_cmd_fixed_param)); + + cmd->vdev_id = plm->session_id; + + cmd->meas_token = plm->meas_token; + WMI_LOGD("vdev %d meas token %d", cmd->vdev_id, cmd->meas_token); + + ret = wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_VDEV_PLMREQ_STOP_CMDID); + if (ret) { + WMI_LOGE("%s: Failed to send plm stop wmi cmd", __func__); + wmi_buf_free(buf); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * send_plm_start_cmd_tlv() - plm start request + * @wmi_handle: wmi handle + * @plm: plm request parameters + * + * This function request FW to start PLM. + * + * Return: CDF status + */ +QDF_STATUS send_plm_start_cmd_tlv(wmi_unified_t wmi_handle, + const struct plm_req_params *plm, + uint32_t *gchannel_list) +{ + wmi_vdev_plmreq_start_cmd_fixed_param *cmd; + uint32_t *channel_list; + int32_t len; + wmi_buf_t buf; + uint8_t *buf_ptr; + uint8_t count; + int ret; + + /* TLV place holder for channel_list */ + len = sizeof(*cmd) + WMI_TLV_HDR_SIZE; + len += sizeof(uint32_t) * plm->plm_num_ch; + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMI_LOGE("%s: Failed allocate wmi buffer", __func__); + return QDF_STATUS_E_NOMEM; + } + cmd = (wmi_vdev_plmreq_start_cmd_fixed_param *) wmi_buf_data(buf); + + buf_ptr = (uint8_t *) cmd; + + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_vdev_plmreq_start_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_vdev_plmreq_start_cmd_fixed_param)); + + cmd->vdev_id = plm->session_id; + + cmd->meas_token = plm->meas_token; + cmd->dialog_token = plm->diag_token; + cmd->number_bursts = plm->num_bursts; + cmd->burst_interval = WMI_SEC_TO_MSEC(plm->burst_int); + cmd->off_duration = plm->meas_duration; + cmd->burst_cycle = plm->burst_len; + cmd->tx_power = plm->desired_tx_pwr; + WMI_CHAR_ARRAY_TO_MAC_ADDR(plm->mac_addr.bytes, &cmd->dest_mac); + cmd->num_chans = plm->plm_num_ch; + + buf_ptr += sizeof(wmi_vdev_plmreq_start_cmd_fixed_param); + + WMI_LOGD("vdev : %d measu token : %d", cmd->vdev_id, cmd->meas_token); + WMI_LOGD("dialog_token: %d", cmd->dialog_token); + WMI_LOGD("number_bursts: %d", cmd->number_bursts); + WMI_LOGD("burst_interval: %d", cmd->burst_interval); + WMI_LOGD("off_duration: %d", cmd->off_duration); + WMI_LOGD("burst_cycle: %d", cmd->burst_cycle); + WMI_LOGD("tx_power: %d", cmd->tx_power); + WMI_LOGD("Number of channels : %d", cmd->num_chans); + + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_UINT32, + (cmd->num_chans * sizeof(uint32_t))); + + buf_ptr += WMI_TLV_HDR_SIZE; + if (cmd->num_chans) { + channel_list = (uint32_t *) buf_ptr; + for (count = 0; count < cmd->num_chans; count++) { + channel_list[count] = plm->plm_ch_list[count]; + if (channel_list[count] < WMI_NLO_FREQ_THRESH) + channel_list[count] = + gchannel_list[count]; + WMI_LOGD("Ch[%d]: %d MHz", count, channel_list[count]); + } + buf_ptr += cmd->num_chans * sizeof(uint32_t); + } + + ret = wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_VDEV_PLMREQ_START_CMDID); + if (ret) { + WMI_LOGE("%s: Failed to send plm start wmi cmd", __func__); + wmi_buf_free(buf); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * send_pno_stop_cmd_tlv() - PNO stop request + * @wmi_handle: wmi handle + * @vdev_id: vdev id + * + * This function request FW to stop ongoing PNO operation. + * + * Return: CDF status + */ +QDF_STATUS send_pno_stop_cmd_tlv(wmi_unified_t wmi_handle, uint8_t vdev_id) +{ + wmi_nlo_config_cmd_fixed_param *cmd; + int32_t len = sizeof(*cmd); + wmi_buf_t buf; + uint8_t *buf_ptr; + int ret; + + /* + * TLV place holder for array of structures nlo_configured_parameters + * TLV place holder for array of uint32_t channel_list + * TLV place holder for chnl prediction cfg + */ + len += WMI_TLV_HDR_SIZE + WMI_TLV_HDR_SIZE + WMI_TLV_HDR_SIZE; + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMI_LOGE("%s: Failed allocate wmi buffer", __func__); + return QDF_STATUS_E_NOMEM; + } + + cmd = (wmi_nlo_config_cmd_fixed_param *) wmi_buf_data(buf); + buf_ptr = (uint8_t *) cmd; + + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_nlo_config_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_nlo_config_cmd_fixed_param)); + + cmd->vdev_id = vdev_id; + cmd->flags = WMI_NLO_CONFIG_STOP; + buf_ptr += sizeof(*cmd); + + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, 0); + buf_ptr += WMI_TLV_HDR_SIZE; + + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_UINT32, 0); + buf_ptr += WMI_TLV_HDR_SIZE; + + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, 0); + buf_ptr += WMI_TLV_HDR_SIZE; + + + ret = wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_NETWORK_LIST_OFFLOAD_CONFIG_CMDID); + if (ret) { + WMI_LOGE("%s: Failed to send nlo wmi cmd", __func__); + wmi_buf_free(buf); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * wmi_set_pno_channel_prediction() - Set PNO channel prediction + * @buf_ptr: Buffer passed by upper layers + * @pno: Buffer to be sent to the firmware + * + * Copy the PNO Channel prediction configuration parameters + * passed by the upper layers to a WMI format TLV and send it + * down to the firmware. + * + * Return: None + */ +static void wmi_set_pno_channel_prediction(uint8_t *buf_ptr, + struct pno_scan_req_params *pno) +{ + nlo_channel_prediction_cfg *channel_prediction_cfg = + (nlo_channel_prediction_cfg *) buf_ptr; + WMITLV_SET_HDR(&channel_prediction_cfg->tlv_header, + WMITLV_TAG_ARRAY_BYTE, + WMITLV_GET_STRUCT_TLVLEN(nlo_channel_prediction_cfg)); +#ifdef FEATURE_WLAN_SCAN_PNO + channel_prediction_cfg->enable = pno->pno_channel_prediction; + channel_prediction_cfg->top_k_num = pno->top_k_num_of_channels; + channel_prediction_cfg->stationary_threshold = pno->stationary_thresh; + channel_prediction_cfg->full_scan_period_ms = + pno->channel_prediction_full_scan; +#endif + buf_ptr += sizeof(nlo_channel_prediction_cfg); + WMI_LOGD("enable: %d, top_k_num: %d, stat_thresh: %d, full_scan: %d", + channel_prediction_cfg->enable, + channel_prediction_cfg->top_k_num, + channel_prediction_cfg->stationary_threshold, + channel_prediction_cfg->full_scan_period_ms); +} + +/** + * send_pno_start_cmd_tlv() - PNO start request + * @wmi_handle: wmi handle + * @pno: PNO request + * + * This function request FW to start PNO request. + * Request: CDF status + */ +QDF_STATUS send_pno_start_cmd_tlv(wmi_unified_t wmi_handle, + struct pno_scan_req_params *pno, + uint32_t *gchannel_freq_list) +{ + wmi_nlo_config_cmd_fixed_param *cmd; + nlo_configured_parameters *nlo_list; + uint32_t *channel_list; + int32_t len; + wmi_buf_t buf; + uint8_t *buf_ptr; + uint8_t i; + int ret; + + /* + * TLV place holder for array nlo_configured_parameters(nlo_list) + * TLV place holder for array of uint32_t channel_list + * TLV place holder for chnnl prediction cfg + * TLV place holder for array of wmi_vendor_oui + */ + len = sizeof(*cmd) + + WMI_TLV_HDR_SIZE + WMI_TLV_HDR_SIZE + WMI_TLV_HDR_SIZE + + WMI_TLV_HDR_SIZE; + + len += sizeof(uint32_t) * QDF_MIN(pno->aNetworks[0].ucChannelCount, + WMI_NLO_MAX_CHAN); + len += sizeof(nlo_configured_parameters) * + QDF_MIN(pno->ucNetworksCount, WMI_NLO_MAX_SSIDS); + len += sizeof(nlo_channel_prediction_cfg); + len += sizeof(enlo_candidate_score_params); + len += sizeof(wmi_vendor_oui) * pno->num_vendor_oui; + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMI_LOGE("%s: Failed allocate wmi buffer", __func__); + return QDF_STATUS_E_NOMEM; + } + + cmd = (wmi_nlo_config_cmd_fixed_param *) wmi_buf_data(buf); + + buf_ptr = (uint8_t *) cmd; + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_nlo_config_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_nlo_config_cmd_fixed_param)); + cmd->vdev_id = pno->sessionId; + cmd->flags = WMI_NLO_CONFIG_START | WMI_NLO_CONFIG_SSID_HIDE_EN; + +#ifdef FEATURE_WLAN_SCAN_PNO + WMI_SCAN_SET_DWELL_MODE(cmd->flags, + pno->pnoscan_adaptive_dwell_mode); +#endif + /* Current FW does not support min-max range for dwell time */ + cmd->active_dwell_time = pno->active_max_time; + cmd->passive_dwell_time = pno->passive_max_time; + + if (pno->do_passive_scan) + cmd->flags |= WMI_NLO_CONFIG_SCAN_PASSIVE; + /* Copy scan interval */ + cmd->fast_scan_period = pno->fast_scan_period; + cmd->slow_scan_period = pno->slow_scan_period; + cmd->delay_start_time = WMI_SEC_TO_MSEC(pno->delay_start_time); + cmd->fast_scan_max_cycles = pno->fast_scan_max_cycles; + WMI_LOGD("fast_scan_period: %d msec slow_scan_period: %d msec", + cmd->fast_scan_period, cmd->slow_scan_period); + WMI_LOGD("fast_scan_max_cycles: %d", cmd->fast_scan_max_cycles); + + buf_ptr += sizeof(wmi_nlo_config_cmd_fixed_param); + + cmd->no_of_ssids = QDF_MIN(pno->ucNetworksCount, WMI_NLO_MAX_SSIDS); + WMI_LOGD("SSID count : %d", cmd->no_of_ssids); + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, + cmd->no_of_ssids * sizeof(nlo_configured_parameters)); + buf_ptr += WMI_TLV_HDR_SIZE; + + nlo_list = (nlo_configured_parameters *) buf_ptr; + for (i = 0; i < cmd->no_of_ssids; i++) { + WMITLV_SET_HDR(&nlo_list[i].tlv_header, + WMITLV_TAG_ARRAY_BYTE, + WMITLV_GET_STRUCT_TLVLEN + (nlo_configured_parameters)); + /* Copy ssid and it's length */ + nlo_list[i].ssid.valid = true; + nlo_list[i].ssid.ssid.ssid_len = pno->aNetworks[i].ssid.length; + qdf_mem_copy(nlo_list[i].ssid.ssid.ssid, + pno->aNetworks[i].ssid.mac_ssid, + nlo_list[i].ssid.ssid.ssid_len); + WMI_LOGD("index: %d ssid: %.*s len: %d", i, + nlo_list[i].ssid.ssid.ssid_len, + (char *)nlo_list[i].ssid.ssid.ssid, + nlo_list[i].ssid.ssid.ssid_len); + + /* Copy rssi threshold */ + if (pno->aNetworks[i].rssiThreshold && + pno->aNetworks[i].rssiThreshold > WMI_RSSI_THOLD_DEFAULT) { + nlo_list[i].rssi_cond.valid = true; + nlo_list[i].rssi_cond.rssi = + pno->aNetworks[i].rssiThreshold; + WMI_LOGD("RSSI threshold : %d dBm", + nlo_list[i].rssi_cond.rssi); + } + nlo_list[i].bcast_nw_type.valid = true; + nlo_list[i].bcast_nw_type.bcast_nw_type = + pno->aNetworks[i].bcastNetwType; + WMI_LOGI("Broadcast NW type (%u)", + nlo_list[i].bcast_nw_type.bcast_nw_type); + } + buf_ptr += cmd->no_of_ssids * sizeof(nlo_configured_parameters); + + /* Copy channel info */ + cmd->num_of_channels = QDF_MIN(pno->aNetworks[0].ucChannelCount, + WMI_NLO_MAX_CHAN); + WMI_LOGD("Channel count: %d", cmd->num_of_channels); + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_UINT32, + (cmd->num_of_channels * sizeof(uint32_t))); + buf_ptr += WMI_TLV_HDR_SIZE; + + channel_list = (uint32_t *) buf_ptr; + for (i = 0; i < cmd->num_of_channels; i++) { + channel_list[i] = pno->aNetworks[0].aChannels[i]; + + if (channel_list[i] < WMI_NLO_FREQ_THRESH) + channel_list[i] = gchannel_freq_list[i]; + + WMI_LOGD("Ch[%d]: %d MHz", i, channel_list[i]); + } + buf_ptr += cmd->num_of_channels * sizeof(uint32_t); + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, + sizeof(nlo_channel_prediction_cfg)); + buf_ptr += WMI_TLV_HDR_SIZE; + wmi_set_pno_channel_prediction(buf_ptr, pno); + buf_ptr += sizeof(nlo_channel_prediction_cfg); + /** TODO: Discrete firmware doesn't have command/option to configure + * App IE which comes from wpa_supplicant as of part PNO start request. + */ + + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_STRUC_enlo_candidate_score_param, + WMITLV_GET_STRUCT_TLVLEN(enlo_candidate_score_params)); + buf_ptr += sizeof(enlo_candidate_score_params); + + /* mac randomization attributes */ + if (pno->enable_pno_scan_randomization) { + cmd->flags |= WMI_NLO_CONFIG_SPOOFED_MAC_IN_PROBE_REQ | + WMI_NLO_CONFIG_RANDOM_SEQ_NO_IN_PROBE_REQ; + WMI_CHAR_ARRAY_TO_MAC_ADDR(pno->mac_addr, &cmd->mac_addr); + WMI_CHAR_ARRAY_TO_MAC_ADDR(pno->mac_addr_mask, &cmd->mac_mask); + } + if (pno->ie_whitelist) { + cmd->flags |= WMI_NLO_CONFIG_ENABLE_IE_WHITELIST_IN_PROBE_REQ; + cmd->num_vendor_oui = pno->num_vendor_oui; + for (i = 0; i < PROBE_REQ_BITMAP_LEN; i++) + cmd->ie_bitmap[i] = pno->probe_req_ie_bitmap[i]; + } + WMI_LOGI("pno flags = %x", cmd->flags); + + /* ie white list */ + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, pno->num_vendor_oui * + sizeof(wmi_vendor_oui)); + + buf_ptr += WMI_TLV_HDR_SIZE; + + if (cmd->num_vendor_oui != 0) { + wmi_fill_vendor_oui(buf_ptr, cmd->num_vendor_oui, pno->voui); + buf_ptr += cmd->num_vendor_oui * sizeof(wmi_vendor_oui); + } + + ret = wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_NETWORK_LIST_OFFLOAD_CONFIG_CMDID); + if (ret) { + WMI_LOGE("%s: Failed to send nlo wmi cmd", __func__); + wmi_buf_free(buf); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/* send_set_ric_req_cmd_tlv() - set ric request element + * @wmi_handle: wmi handle + * @msg: message + * @is_add_ts: is addts required + * + * This function sets ric request element for 11r roaming. + * + * Return: CDF status + */ +QDF_STATUS send_set_ric_req_cmd_tlv(wmi_unified_t wmi_handle, + void *msg, uint8_t is_add_ts) +{ + wmi_ric_request_fixed_param *cmd; + wmi_ric_tspec *tspec_param; + wmi_buf_t buf; + uint8_t *buf_ptr; + struct mac_tspec_ie *ptspecIE = NULL; + int32_t len = sizeof(wmi_ric_request_fixed_param) + + WMI_TLV_HDR_SIZE + sizeof(wmi_ric_tspec); + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMI_LOGP("%s: wmi_buf_alloc failed", __func__); + return QDF_STATUS_E_NOMEM; + } + + buf_ptr = (uint8_t *) wmi_buf_data(buf); + + cmd = (wmi_ric_request_fixed_param *) buf_ptr; + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_ric_request_fixed_param, + WMITLV_GET_STRUCT_TLVLEN(wmi_ric_request_fixed_param)); + if (is_add_ts) + cmd->vdev_id = ((struct add_ts_param *) msg)->sessionId; + else + cmd->vdev_id = ((struct del_ts_params *) msg)->sessionId; + cmd->num_ric_request = 1; + cmd->is_add_ric = is_add_ts; + + buf_ptr += sizeof(wmi_ric_request_fixed_param); + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, sizeof(wmi_ric_tspec)); + + buf_ptr += WMI_TLV_HDR_SIZE; + tspec_param = (wmi_ric_tspec *) buf_ptr; + WMITLV_SET_HDR(&tspec_param->tlv_header, + WMITLV_TAG_STRUC_wmi_ric_tspec, + WMITLV_GET_STRUCT_TLVLEN(wmi_ric_tspec)); + + if (is_add_ts) + ptspecIE = &(((struct add_ts_param *) msg)->tspec); +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + else + ptspecIE = &(((struct del_ts_params *) msg)->delTsInfo.tspec); +#endif + if (ptspecIE) { + /* Fill the tsinfo in the format expected by firmware */ +#ifndef ANI_LITTLE_BIT_ENDIAN + qdf_mem_copy(((uint8_t *) &tspec_param->ts_info) + 1, + ((uint8_t *) &ptspecIE->tsinfo) + 1, 2); +#else + qdf_mem_copy(((uint8_t *) &tspec_param->ts_info), + ((uint8_t *) &ptspecIE->tsinfo) + 1, 2); +#endif /* ANI_LITTLE_BIT_ENDIAN */ + + tspec_param->nominal_msdu_size = ptspecIE->nomMsduSz; + tspec_param->maximum_msdu_size = ptspecIE->maxMsduSz; + tspec_param->min_service_interval = ptspecIE->minSvcInterval; + tspec_param->max_service_interval = ptspecIE->maxSvcInterval; + tspec_param->inactivity_interval = ptspecIE->inactInterval; + tspec_param->suspension_interval = ptspecIE->suspendInterval; + tspec_param->svc_start_time = ptspecIE->svcStartTime; + tspec_param->min_data_rate = ptspecIE->minDataRate; + tspec_param->mean_data_rate = ptspecIE->meanDataRate; + tspec_param->peak_data_rate = ptspecIE->peakDataRate; + tspec_param->max_burst_size = ptspecIE->maxBurstSz; + tspec_param->delay_bound = ptspecIE->delayBound; + tspec_param->min_phy_rate = ptspecIE->minPhyRate; + tspec_param->surplus_bw_allowance = ptspecIE->surplusBw; + tspec_param->medium_time = 0; + } + WMI_LOGI("%s: Set RIC Req is_add_ts:%d", __func__, is_add_ts); + + if (wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_ROAM_SET_RIC_REQUEST_CMDID)) { + WMI_LOGP("%s: Failed to send vdev Set RIC Req command", + __func__); + if (is_add_ts) + ((struct add_ts_param *) msg)->status = + QDF_STATUS_E_FAILURE; + wmi_buf_free(buf); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * send_process_ll_stats_clear_cmd_tlv() - clear link layer stats + * @wmi_handle: wmi handle + * @clear_req: ll stats clear request command params + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +QDF_STATUS send_process_ll_stats_clear_cmd_tlv(wmi_unified_t wmi_handle, + const struct ll_stats_clear_params *clear_req, + uint8_t addr[IEEE80211_ADDR_LEN]) +{ + wmi_clear_link_stats_cmd_fixed_param *cmd; + int32_t len; + wmi_buf_t buf; + uint8_t *buf_ptr; + int ret; + + len = sizeof(*cmd); + buf = wmi_buf_alloc(wmi_handle, len); + + if (!buf) { + WMI_LOGE("%s: Failed allocate wmi buffer", __func__); + return QDF_STATUS_E_NOMEM; + } + + buf_ptr = (uint8_t *) wmi_buf_data(buf); + qdf_mem_zero(buf_ptr, len); + cmd = (wmi_clear_link_stats_cmd_fixed_param *) buf_ptr; + + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_clear_link_stats_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_clear_link_stats_cmd_fixed_param)); + + cmd->stop_stats_collection_req = clear_req->stop_req; + cmd->vdev_id = clear_req->sta_id; + cmd->stats_clear_req_mask = clear_req->stats_clear_mask; + + WMI_CHAR_ARRAY_TO_MAC_ADDR(addr, + &cmd->peer_macaddr); + + WMI_LOGD("LINK_LAYER_STATS - Clear Request Params"); + WMI_LOGD("StopReq : %d", cmd->stop_stats_collection_req); + WMI_LOGD("Vdev Id : %d", cmd->vdev_id); + WMI_LOGD("Clear Stat Mask : %d", cmd->stats_clear_req_mask); + /* WMI_LOGD("Peer MAC Addr : %pM", + cmd->peer_macaddr); */ + + ret = wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_CLEAR_LINK_STATS_CMDID); + if (ret) { + WMI_LOGE("%s: Failed to send clear link stats req", __func__); + wmi_buf_free(buf); + return QDF_STATUS_E_FAILURE; + } + + WMI_LOGD("Clear Link Layer Stats request sent successfully"); + return QDF_STATUS_SUCCESS; +} + +/** + * send_process_ll_stats_set_cmd_tlv() - link layer stats set request + * @wmi_handle: wmi handle + * @setReq: ll stats set request command params + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +QDF_STATUS send_process_ll_stats_set_cmd_tlv(wmi_unified_t wmi_handle, + const struct ll_stats_set_params *set_req) +{ + wmi_start_link_stats_cmd_fixed_param *cmd; + int32_t len; + wmi_buf_t buf; + uint8_t *buf_ptr; + int ret; + + len = sizeof(*cmd); + buf = wmi_buf_alloc(wmi_handle, len); + + if (!buf) { + WMI_LOGE("%s: Failed allocate wmi buffer", __func__); + return QDF_STATUS_E_NOMEM; + } + + buf_ptr = (uint8_t *) wmi_buf_data(buf); + qdf_mem_zero(buf_ptr, len); + cmd = (wmi_start_link_stats_cmd_fixed_param *) buf_ptr; + + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_start_link_stats_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_start_link_stats_cmd_fixed_param)); + + cmd->mpdu_size_threshold = set_req->mpdu_size_threshold; + cmd->aggressive_statistics_gathering = + set_req->aggressive_statistics_gathering; + + WMI_LOGD("LINK_LAYER_STATS - Start/Set Request Params"); + WMI_LOGD("MPDU Size Thresh : %d", cmd->mpdu_size_threshold); + WMI_LOGD("Aggressive Gather: %d", cmd->aggressive_statistics_gathering); + + ret = wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_START_LINK_STATS_CMDID); + if (ret) { + WMI_LOGE("%s: Failed to send set link stats request", __func__); + wmi_buf_free(buf); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * send_process_ll_stats_get_cmd_tlv() - link layer stats get request + * @wmi_handle:wmi handle + * @get_req:ll stats get request command params + * @addr: mac address + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +QDF_STATUS send_process_ll_stats_get_cmd_tlv(wmi_unified_t wmi_handle, + const struct ll_stats_get_params *get_req, + uint8_t addr[IEEE80211_ADDR_LEN]) +{ + wmi_request_link_stats_cmd_fixed_param *cmd; + int32_t len; + wmi_buf_t buf; + uint8_t *buf_ptr; + int ret; + + len = sizeof(*cmd); + buf = wmi_buf_alloc(wmi_handle, len); + + if (!buf) { + WMI_LOGE("%s: buf allocation failed", __func__); + return QDF_STATUS_E_NOMEM; + } + + buf_ptr = (uint8_t *) wmi_buf_data(buf); + qdf_mem_zero(buf_ptr, len); + cmd = (wmi_request_link_stats_cmd_fixed_param *) buf_ptr; + + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_request_link_stats_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_request_link_stats_cmd_fixed_param)); + + cmd->request_id = get_req->req_id; + cmd->stats_type = get_req->param_id_mask; + cmd->vdev_id = get_req->sta_id; + + WMI_CHAR_ARRAY_TO_MAC_ADDR(addr, + &cmd->peer_macaddr); + + WMI_LOGD("LINK_LAYER_STATS - Get Request Params"); + WMI_LOGD("Request ID : %d", cmd->request_id); + WMI_LOGD("Stats Type : %d", cmd->stats_type); + WMI_LOGD("Vdev ID : %d", cmd->vdev_id); + WMI_LOGD("Peer MAC Addr : %pM", addr); + + ret = wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_REQUEST_LINK_STATS_CMDID); + if (ret) { + WMI_LOGE("%s: Failed to send get link stats request", __func__); + wmi_buf_free(buf); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * send_get_stats_cmd_tlv() - get stats request + * @wmi_handle: wmi handle + * @get_stats_param: stats params + * @addr: mac address + * + * Return: CDF status + */ +QDF_STATUS send_get_stats_cmd_tlv(wmi_unified_t wmi_handle, + struct pe_stats_req *get_stats_param, + uint8_t addr[IEEE80211_ADDR_LEN]) +{ + wmi_buf_t buf; + wmi_request_stats_cmd_fixed_param *cmd; + uint8_t len = sizeof(wmi_request_stats_cmd_fixed_param); + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMI_LOGE("%s: Failed to allocate wmi buffer", __func__); + return QDF_STATUS_E_FAILURE; + } + + + cmd = (wmi_request_stats_cmd_fixed_param *) wmi_buf_data(buf); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_request_stats_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_request_stats_cmd_fixed_param)); + cmd->stats_id = + WMI_REQUEST_PEER_STAT | WMI_REQUEST_PDEV_STAT | + WMI_REQUEST_VDEV_STAT | WMI_REQUEST_RSSI_PER_CHAIN_STAT; + cmd->vdev_id = get_stats_param->session_id; + WMI_CHAR_ARRAY_TO_MAC_ADDR(addr, &cmd->peer_macaddr); + WMI_LOGD("STATS REQ VDEV_ID:%d-->", cmd->vdev_id); + if (wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_REQUEST_STATS_CMDID)) { + + WMI_LOGE("%s: Failed to send WMI_REQUEST_STATS_CMDID", + __func__); + wmi_buf_free(buf); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; + +} + +/** + * send_congestion_cmd_tlv() - send request to fw to get CCA + * @wmi_handle: wmi handle + * @vdev_id: vdev id + * + * Return: CDF status + */ +QDF_STATUS send_congestion_cmd_tlv(wmi_unified_t wmi_handle, + A_UINT8 vdev_id) +{ + wmi_buf_t buf; + wmi_request_stats_cmd_fixed_param *cmd; + uint8_t len; + uint8_t *buf_ptr; + + len = sizeof(*cmd); + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMI_LOGE("%s: Failed to allocate wmi buffer", __func__); + return QDF_STATUS_E_FAILURE; + } + + buf_ptr = wmi_buf_data(buf); + cmd = (wmi_request_stats_cmd_fixed_param *)buf_ptr; + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_request_stats_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_request_stats_cmd_fixed_param)); + + cmd->stats_id = WMI_REQUEST_CONGESTION_STAT; + cmd->vdev_id = vdev_id; + WMI_LOGD("STATS REQ VDEV_ID:%d stats_id %d -->", + cmd->vdev_id, cmd->stats_id); + + if (wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_REQUEST_STATS_CMDID)) { + WMI_LOGE("%s: Failed to send WMI_REQUEST_STATS_CMDID", + __func__); + wmi_buf_free(buf); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * send_snr_request_cmd_tlv() - send request to fw to get RSSI stats + * @wmi_handle: wmi handle + * @rssi_req: get RSSI request + * + * Return: CDF status + */ +QDF_STATUS send_snr_request_cmd_tlv(wmi_unified_t wmi_handle) +{ + wmi_buf_t buf; + wmi_request_stats_cmd_fixed_param *cmd; + uint8_t len = sizeof(wmi_request_stats_cmd_fixed_param); + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMI_LOGE("%s: wmi_buf_alloc failed", __func__); + return QDF_STATUS_E_FAILURE; + } + + cmd = (wmi_request_stats_cmd_fixed_param *) wmi_buf_data(buf); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_request_stats_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_request_stats_cmd_fixed_param)); + cmd->stats_id = WMI_REQUEST_VDEV_STAT; + if (wmi_unified_cmd_send + (wmi_handle, buf, len, WMI_REQUEST_STATS_CMDID)) { + WMI_LOGE("Failed to send host stats request to fw"); + wmi_buf_free(buf); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * send_snr_cmd_tlv() - get RSSI from fw + * @wmi_handle: wmi handle + * @vdev_id: vdev id + * + * Return: CDF status + */ +QDF_STATUS send_snr_cmd_tlv(wmi_unified_t wmi_handle, uint8_t vdev_id) +{ + wmi_buf_t buf; + wmi_request_stats_cmd_fixed_param *cmd; + uint8_t len = sizeof(wmi_request_stats_cmd_fixed_param); + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMI_LOGE("%s: wmi_buf_alloc failed", __func__); + return QDF_STATUS_E_FAILURE; + } + + cmd = (wmi_request_stats_cmd_fixed_param *) wmi_buf_data(buf); + cmd->vdev_id = vdev_id; + + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_request_stats_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_request_stats_cmd_fixed_param)); + cmd->stats_id = WMI_REQUEST_VDEV_STAT; + if (wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_REQUEST_STATS_CMDID)) { + WMI_LOGE("Failed to send host stats request to fw"); + wmi_buf_free(buf); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * send_link_status_req_cmd_tlv() - process link status request from UMAC + * @wmi_handle: wmi handle + * @link_status: get link params + * + * Return: CDF status + */ +QDF_STATUS send_link_status_req_cmd_tlv(wmi_unified_t wmi_handle, + struct link_status_params *link_status) +{ + wmi_buf_t buf; + wmi_request_stats_cmd_fixed_param *cmd; + uint8_t len = sizeof(wmi_request_stats_cmd_fixed_param); + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMI_LOGE("%s: wmi_buf_alloc failed", __func__); + return QDF_STATUS_E_FAILURE; + } + + cmd = (wmi_request_stats_cmd_fixed_param *) wmi_buf_data(buf); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_request_stats_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_request_stats_cmd_fixed_param)); + cmd->stats_id = WMI_REQUEST_VDEV_RATE_STAT; + cmd->vdev_id = link_status->session_id; + if (wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_REQUEST_STATS_CMDID)) { + WMI_LOGE("Failed to send WMI link status request to fw"); + wmi_buf_free(buf); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +#ifdef FEATURE_WLAN_LPHB + +/** + * send_lphb_config_hbenable_cmd_tlv() - enable command of LPHB configuration + * @wmi_handle: wmi handle + * @lphb_conf_req: configuration info + * + * Return: CDF status + */ +QDF_STATUS send_lphb_config_hbenable_cmd_tlv(wmi_unified_t wmi_handle, + wmi_hb_set_enable_cmd_fixed_param *params) +{ + QDF_STATUS status; + wmi_buf_t buf = NULL; + uint8_t *buf_ptr; + wmi_hb_set_enable_cmd_fixed_param *hb_enable_fp; + int len = sizeof(wmi_hb_set_enable_cmd_fixed_param); + + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMI_LOGE("%s : wmi_buf_alloc failed", __func__); + return QDF_STATUS_E_NOMEM; + } + + buf_ptr = (uint8_t *) wmi_buf_data(buf); + hb_enable_fp = (wmi_hb_set_enable_cmd_fixed_param *) buf_ptr; + WMITLV_SET_HDR(&hb_enable_fp->tlv_header, + WMITLV_TAG_STRUC_wmi_hb_set_enable_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_hb_set_enable_cmd_fixed_param)); + + /* fill in values */ + hb_enable_fp->vdev_id = params->session; + hb_enable_fp->enable = params->enable; + hb_enable_fp->item = params->item; + hb_enable_fp->session = params->session; + + status = wmi_unified_cmd_send(wmi_handle, buf, + len, WMI_HB_SET_ENABLE_CMDID); + if (QDF_IS_STATUS_ERROR(status)) { + WMI_LOGE("wmi_unified_cmd_send WMI_HB_SET_ENABLE returned Error %d", + status); + wmi_buf_free(buf); + } + + return status; +} + +/** + * send_lphb_config_tcp_params_cmd_tlv() - set tcp params of LPHB configuration + * @wmi_handle: wmi handle + * @lphb_conf_req: lphb config request + * + * Return: CDF status + */ +QDF_STATUS send_lphb_config_tcp_params_cmd_tlv(wmi_unified_t wmi_handle, + wmi_hb_set_tcp_params_cmd_fixed_param *lphb_conf_req) +{ + QDF_STATUS status; + wmi_buf_t buf = NULL; + uint8_t *buf_ptr; + wmi_hb_set_tcp_params_cmd_fixed_param *hb_tcp_params_fp; + int len = sizeof(wmi_hb_set_tcp_params_cmd_fixed_param); + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMI_LOGE("%s : wmi_buf_alloc failed", __func__); + return QDF_STATUS_E_NOMEM; + } + + buf_ptr = (uint8_t *) wmi_buf_data(buf); + hb_tcp_params_fp = (wmi_hb_set_tcp_params_cmd_fixed_param *) buf_ptr; + WMITLV_SET_HDR(&hb_tcp_params_fp->tlv_header, + WMITLV_TAG_STRUC_wmi_hb_set_tcp_params_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_hb_set_tcp_params_cmd_fixed_param)); + + /* fill in values */ + hb_tcp_params_fp->vdev_id = lphb_conf_req->vdev_id; + hb_tcp_params_fp->srv_ip = lphb_conf_req->srv_ip; + hb_tcp_params_fp->dev_ip = lphb_conf_req->dev_ip; + hb_tcp_params_fp->seq = lphb_conf_req->seq; + hb_tcp_params_fp->src_port = lphb_conf_req->src_port; + hb_tcp_params_fp->dst_port = lphb_conf_req->dst_port; + hb_tcp_params_fp->interval = lphb_conf_req->interval; + hb_tcp_params_fp->timeout = lphb_conf_req->timeout; + hb_tcp_params_fp->session = lphb_conf_req->session; + qdf_mem_copy(&hb_tcp_params_fp->gateway_mac, + &lphb_conf_req->gateway_mac, + sizeof(hb_tcp_params_fp->gateway_mac)); + + status = wmi_unified_cmd_send(wmi_handle, buf, + len, WMI_HB_SET_TCP_PARAMS_CMDID); + if (QDF_IS_STATUS_ERROR(status)) { + WMI_LOGE("wmi_unified_cmd_send WMI_HB_SET_TCP_PARAMS returned Error %d", + status); + wmi_buf_free(buf); + } + + return status; +} + +/** + * send_lphb_config_tcp_pkt_filter_cmd_tlv() - configure tcp packet filter cmd + * @wmi_handle: wmi handle + * @lphb_conf_req: lphb config request + * + * Return: CDF status + */ +QDF_STATUS send_lphb_config_tcp_pkt_filter_cmd_tlv(wmi_unified_t wmi_handle, + wmi_hb_set_tcp_pkt_filter_cmd_fixed_param *g_hb_tcp_filter_fp) +{ + QDF_STATUS status; + wmi_buf_t buf = NULL; + uint8_t *buf_ptr; + wmi_hb_set_tcp_pkt_filter_cmd_fixed_param *hb_tcp_filter_fp; + int len = sizeof(wmi_hb_set_tcp_pkt_filter_cmd_fixed_param); + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMI_LOGE("%s : wmi_buf_alloc failed", __func__); + return QDF_STATUS_E_NOMEM; + } + + buf_ptr = (uint8_t *) wmi_buf_data(buf); + hb_tcp_filter_fp = + (wmi_hb_set_tcp_pkt_filter_cmd_fixed_param *) buf_ptr; + WMITLV_SET_HDR(&hb_tcp_filter_fp->tlv_header, + WMITLV_TAG_STRUC_wmi_hb_set_tcp_pkt_filter_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_hb_set_tcp_pkt_filter_cmd_fixed_param)); + + /* fill in values */ + hb_tcp_filter_fp->vdev_id = g_hb_tcp_filter_fp->vdev_id; + hb_tcp_filter_fp->length = g_hb_tcp_filter_fp->length; + hb_tcp_filter_fp->offset = g_hb_tcp_filter_fp->offset; + hb_tcp_filter_fp->session = g_hb_tcp_filter_fp->session; + memcpy((void *)&hb_tcp_filter_fp->filter, + (void *)&g_hb_tcp_filter_fp->filter, + WMI_WLAN_HB_MAX_FILTER_SIZE); + + status = wmi_unified_cmd_send(wmi_handle, buf, + len, WMI_HB_SET_TCP_PKT_FILTER_CMDID); + if (QDF_IS_STATUS_ERROR(status)) { + WMI_LOGE("wmi_unified_cmd_send WMI_HB_SET_TCP_PKT_FILTER returned Error %d", + status); + wmi_buf_free(buf); + } + + return status; +} + +/** + * send_lphb_config_udp_params_cmd_tlv() - configure udp param command of LPHB + * @wmi_handle: wmi handle + * @lphb_conf_req: lphb config request + * + * Return: CDF status + */ +QDF_STATUS send_lphb_config_udp_params_cmd_tlv(wmi_unified_t wmi_handle, + wmi_hb_set_udp_params_cmd_fixed_param *lphb_conf_req) +{ + QDF_STATUS status; + wmi_buf_t buf = NULL; + uint8_t *buf_ptr; + wmi_hb_set_udp_params_cmd_fixed_param *hb_udp_params_fp; + int len = sizeof(wmi_hb_set_udp_params_cmd_fixed_param); + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMI_LOGE("%s : wmi_buf_alloc failed", __func__); + return QDF_STATUS_E_NOMEM; + } + + buf_ptr = (uint8_t *) wmi_buf_data(buf); + hb_udp_params_fp = (wmi_hb_set_udp_params_cmd_fixed_param *) buf_ptr; + WMITLV_SET_HDR(&hb_udp_params_fp->tlv_header, + WMITLV_TAG_STRUC_wmi_hb_set_udp_params_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_hb_set_udp_params_cmd_fixed_param)); + + /* fill in values */ + hb_udp_params_fp->vdev_id = lphb_conf_req->vdev_id; + hb_udp_params_fp->srv_ip = lphb_conf_req->srv_ip; + hb_udp_params_fp->dev_ip = lphb_conf_req->dev_ip; + hb_udp_params_fp->src_port = lphb_conf_req->src_port; + hb_udp_params_fp->dst_port = lphb_conf_req->dst_port; + hb_udp_params_fp->interval = lphb_conf_req->interval; + hb_udp_params_fp->timeout = lphb_conf_req->timeout; + hb_udp_params_fp->session = lphb_conf_req->session; + qdf_mem_copy(&hb_udp_params_fp->gateway_mac, + &lphb_conf_req->gateway_mac, + sizeof(lphb_conf_req->gateway_mac)); + + status = wmi_unified_cmd_send(wmi_handle, buf, + len, WMI_HB_SET_UDP_PARAMS_CMDID); + if (QDF_IS_STATUS_ERROR(status)) { + WMI_LOGE("wmi_unified_cmd_send WMI_HB_SET_UDP_PARAMS returned Error %d", + status); + wmi_buf_free(buf); + } + + return status; +} + +/** + * send_lphb_config_udp_pkt_filter_cmd_tlv() - configure udp pkt filter command + * @wmi_handle: wmi handle + * @lphb_conf_req: lphb config request + * + * Return: CDF status + */ +QDF_STATUS send_lphb_config_udp_pkt_filter_cmd_tlv(wmi_unified_t wmi_handle, + wmi_hb_set_udp_pkt_filter_cmd_fixed_param *lphb_conf_req) +{ + QDF_STATUS status; + wmi_buf_t buf = NULL; + uint8_t *buf_ptr; + wmi_hb_set_udp_pkt_filter_cmd_fixed_param *hb_udp_filter_fp; + int len = sizeof(wmi_hb_set_udp_pkt_filter_cmd_fixed_param); + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMI_LOGE("%s : wmi_buf_alloc failed", __func__); + return QDF_STATUS_E_NOMEM; + } + + buf_ptr = (uint8_t *) wmi_buf_data(buf); + hb_udp_filter_fp = + (wmi_hb_set_udp_pkt_filter_cmd_fixed_param *) buf_ptr; + WMITLV_SET_HDR(&hb_udp_filter_fp->tlv_header, + WMITLV_TAG_STRUC_wmi_hb_set_udp_pkt_filter_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_hb_set_udp_pkt_filter_cmd_fixed_param)); + + /* fill in values */ + hb_udp_filter_fp->vdev_id = lphb_conf_req->vdev_id; + hb_udp_filter_fp->length = lphb_conf_req->length; + hb_udp_filter_fp->offset = lphb_conf_req->offset; + hb_udp_filter_fp->session = lphb_conf_req->session; + memcpy((void *)&hb_udp_filter_fp->filter, + (void *)&lphb_conf_req->filter, + WMI_WLAN_HB_MAX_FILTER_SIZE); + + status = wmi_unified_cmd_send(wmi_handle, buf, + len, WMI_HB_SET_UDP_PKT_FILTER_CMDID); + if (QDF_IS_STATUS_ERROR(status)) { + WMI_LOGE("wmi_unified_cmd_send WMI_HB_SET_UDP_PKT_FILTER returned Error %d", + status); + wmi_buf_free(buf); + } + + return status; +} +#endif /* FEATURE_WLAN_LPHB */ + +/** + * send_process_dhcp_ind_cmd_tlv() - process dhcp indication from SME + * @wmi_handle: wmi handle + * @ta_dhcp_ind: DHCP indication parameter + * + * Return: CDF Status + */ +QDF_STATUS send_process_dhcp_ind_cmd_tlv(wmi_unified_t wmi_handle, + wmi_peer_set_param_cmd_fixed_param *ta_dhcp_ind) +{ + QDF_STATUS status; + wmi_buf_t buf = NULL; + uint8_t *buf_ptr; + wmi_peer_set_param_cmd_fixed_param *peer_set_param_fp; + int len = sizeof(wmi_peer_set_param_cmd_fixed_param); + + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMI_LOGE("%s : wmi_buf_alloc failed", __func__); + return QDF_STATUS_E_NOMEM; + } + + buf_ptr = (uint8_t *) wmi_buf_data(buf); + peer_set_param_fp = (wmi_peer_set_param_cmd_fixed_param *) buf_ptr; + WMITLV_SET_HDR(&peer_set_param_fp->tlv_header, + WMITLV_TAG_STRUC_wmi_peer_set_param_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_peer_set_param_cmd_fixed_param)); + + /* fill in values */ + peer_set_param_fp->vdev_id = ta_dhcp_ind->vdev_id; + peer_set_param_fp->param_id = ta_dhcp_ind->param_id; + peer_set_param_fp->param_value = ta_dhcp_ind->param_value; + qdf_mem_copy(&peer_set_param_fp->peer_macaddr, + &ta_dhcp_ind->peer_macaddr, + sizeof(ta_dhcp_ind->peer_macaddr)); + + status = wmi_unified_cmd_send(wmi_handle, buf, + len, WMI_PEER_SET_PARAM_CMDID); + if (QDF_IS_STATUS_ERROR(status)) { + WMI_LOGE("%s: wmi_unified_cmd_send WMI_PEER_SET_PARAM_CMD" + " returned Error %d", __func__, status); + wmi_buf_free(buf); + } + + return status; +} + +/** + * send_get_link_speed_cmd_tlv() -send command to get linkspeed + * @wmi_handle: wmi handle + * @pLinkSpeed: link speed info + * + * Return: CDF status + */ +QDF_STATUS send_get_link_speed_cmd_tlv(wmi_unified_t wmi_handle, + wmi_mac_addr peer_macaddr) +{ + wmi_peer_get_estimated_linkspeed_cmd_fixed_param *cmd; + wmi_buf_t wmi_buf; + uint32_t len; + uint8_t *buf_ptr; + + len = sizeof(wmi_peer_get_estimated_linkspeed_cmd_fixed_param); + wmi_buf = wmi_buf_alloc(wmi_handle, len); + if (!wmi_buf) { + WMI_LOGE("%s: wmi_buf_alloc failed", __func__); + return QDF_STATUS_E_NOMEM; + } + buf_ptr = (uint8_t *) wmi_buf_data(wmi_buf); + + cmd = (wmi_peer_get_estimated_linkspeed_cmd_fixed_param *) buf_ptr; + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_peer_get_estimated_linkspeed_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_peer_get_estimated_linkspeed_cmd_fixed_param)); + + /* Copy the peer macaddress to the wma buffer */ + qdf_mem_copy(&cmd->peer_macaddr, + &peer_macaddr, + sizeof(peer_macaddr)); + + + if (wmi_unified_cmd_send(wmi_handle, wmi_buf, len, + WMI_PEER_GET_ESTIMATED_LINKSPEED_CMDID)) { + WMI_LOGE("%s: failed to send link speed command", __func__); + wmi_buf_free(wmi_buf); + return QDF_STATUS_E_FAILURE; + } + return QDF_STATUS_SUCCESS; +} + +/** + * send_egap_conf_params_cmd_tlv() - send wmi cmd of egap configuration params + * @wmi_handle: wmi handler + * @egap_params: pointer to egap_params + * + * Return: 0 for success, otherwise appropriate error code + */ +QDF_STATUS send_egap_conf_params_cmd_tlv(wmi_unified_t wmi_handle, + wmi_ap_ps_egap_param_cmd_fixed_param *egap_params) +{ + wmi_ap_ps_egap_param_cmd_fixed_param *cmd; + wmi_buf_t buf; + int32_t err; + + buf = wmi_buf_alloc(wmi_handle, sizeof(*cmd)); + if (!buf) { + WMI_LOGE("Failed to allocate buffer to send ap_ps_egap cmd"); + return QDF_STATUS_E_NOMEM; + } + cmd = (wmi_ap_ps_egap_param_cmd_fixed_param *) wmi_buf_data(buf); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_ap_ps_egap_param_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN( + wmi_ap_ps_egap_param_cmd_fixed_param)); + + cmd->enable = egap_params->enable; + cmd->inactivity_time = egap_params->inactivity_time; + cmd->wait_time = egap_params->wait_time; + cmd->flags = egap_params->flags; + err = wmi_unified_cmd_send(wmi_handle, buf, + sizeof(*cmd), WMI_AP_PS_EGAP_PARAM_CMDID); + if (err) { + WMI_LOGE("Failed to send ap_ps_egap cmd"); + wmi_buf_free(buf); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * send_action_frame_patterns_cmd_tlv() - send wmi cmd of action filter params + * @wmi_handle: wmi handler + * @action_params: pointer to action_params + * + * Return: 0 for success, otherwise appropriate error code + */ +QDF_STATUS send_action_frame_patterns_cmd_tlv(wmi_unified_t wmi_handle, + struct action_wakeup_set_param *action_params) +{ + WMI_WOW_SET_ACTION_WAKE_UP_CMD_fixed_param *cmd; + wmi_buf_t buf; + int i; + int32_t err; + + buf = wmi_buf_alloc(wmi_handle, sizeof(*cmd)); + if (!buf) { + WMI_LOGE("Failed to allocate buffer to send action filter cmd"); + return QDF_STATUS_E_NOMEM; + } + cmd = (WMI_WOW_SET_ACTION_WAKE_UP_CMD_fixed_param *) wmi_buf_data(buf); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_wow_set_action_wake_up_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN( + WMI_WOW_SET_ACTION_WAKE_UP_CMD_fixed_param)); + + cmd->vdev_id = action_params->vdev_id; + cmd->operation = action_params->operation; + + for (i = 0; i < MAX_SUPPORTED_ACTION_CATEGORY_ELE_LIST; i++) + cmd->action_category_map[i] = + action_params->action_category_map[i]; + + err = wmi_unified_cmd_send(wmi_handle, buf, + sizeof(*cmd), WMI_WOW_SET_ACTION_WAKE_UP_CMDID); + if (err) { + WMI_LOGE("Failed to send ap_ps_egap cmd"); + wmi_buf_free(buf); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * send_fw_profiling_cmd_tlv() - send FW profiling cmd to WLAN FW + * @wmi_handl: wmi handle + * @cmd: Profiling command index + * @value1: parameter1 value + * @value2: parameter2 value + * + * Return: QDF_STATUS_SUCCESS for success else error code + */ +QDF_STATUS send_fw_profiling_cmd_tlv(wmi_unified_t wmi_handle, + uint32_t cmd, uint32_t value1, uint32_t value2) +{ + wmi_buf_t buf; + int32_t len = 0; + int ret; + wmi_wlan_profile_trigger_cmd_fixed_param *prof_trig_cmd; + wmi_wlan_profile_set_hist_intvl_cmd_fixed_param *hist_intvl_cmd; + wmi_wlan_profile_enable_profile_id_cmd_fixed_param *profile_enable_cmd; + wmi_wlan_profile_get_prof_data_cmd_fixed_param *profile_getdata_cmd; + + switch (cmd) { + case WMI_WLAN_PROFILE_TRIGGER_CMDID: + len = sizeof(wmi_wlan_profile_trigger_cmd_fixed_param); + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMI_LOGP("%s: wmi_buf_alloc Failed", __func__); + return QDF_STATUS_E_NOMEM; + } + prof_trig_cmd = + (wmi_wlan_profile_trigger_cmd_fixed_param *) + wmi_buf_data(buf); + WMITLV_SET_HDR(&prof_trig_cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_wlan_profile_trigger_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_wlan_profile_trigger_cmd_fixed_param)); + prof_trig_cmd->enable = value1; + ret = wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_WLAN_PROFILE_TRIGGER_CMDID); + if (ret) { + WMI_LOGE("PROFILE_TRIGGER cmd Failed with value %d", + value1); + wmi_buf_free(buf); + return ret; + } + break; + + case WMI_WLAN_PROFILE_GET_PROFILE_DATA_CMDID: + len = sizeof(wmi_wlan_profile_get_prof_data_cmd_fixed_param); + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMI_LOGP("%s: wmi_buf_alloc Failed", __func__); + return QDF_STATUS_E_NOMEM; + } + profile_getdata_cmd = + (wmi_wlan_profile_get_prof_data_cmd_fixed_param *) + wmi_buf_data(buf); + WMITLV_SET_HDR(&profile_getdata_cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_wlan_profile_get_prof_data_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_wlan_profile_get_prof_data_cmd_fixed_param)); + ret = wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_WLAN_PROFILE_GET_PROFILE_DATA_CMDID); + if (ret) { + WMI_LOGE("PROFILE_DATA cmd Failed for id %d value %d", + value1, value2); + wmi_buf_free(buf); + return ret; + } + break; + + case WMI_WLAN_PROFILE_SET_HIST_INTVL_CMDID: + len = sizeof(wmi_wlan_profile_set_hist_intvl_cmd_fixed_param); + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMI_LOGP("%s: wmi_buf_alloc Failed", __func__); + return QDF_STATUS_E_NOMEM; + } + hist_intvl_cmd = + (wmi_wlan_profile_set_hist_intvl_cmd_fixed_param *) + wmi_buf_data(buf); + WMITLV_SET_HDR(&hist_intvl_cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_wlan_profile_set_hist_intvl_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_wlan_profile_set_hist_intvl_cmd_fixed_param)); + hist_intvl_cmd->profile_id = value1; + hist_intvl_cmd->value = value2; + ret = wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_WLAN_PROFILE_SET_HIST_INTVL_CMDID); + if (ret) { + WMI_LOGE("HIST_INTVL cmd Failed for id %d value %d", + value1, value2); + wmi_buf_free(buf); + return ret; + } + break; + + case WMI_WLAN_PROFILE_ENABLE_PROFILE_ID_CMDID: + len = + sizeof(wmi_wlan_profile_enable_profile_id_cmd_fixed_param); + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMI_LOGP("%s: wmi_buf_alloc Failed", __func__); + return QDF_STATUS_E_NOMEM; + } + profile_enable_cmd = + (wmi_wlan_profile_enable_profile_id_cmd_fixed_param *) + wmi_buf_data(buf); + WMITLV_SET_HDR(&profile_enable_cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_wlan_profile_enable_profile_id_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_wlan_profile_enable_profile_id_cmd_fixed_param)); + profile_enable_cmd->profile_id = value1; + profile_enable_cmd->enable = value2; + ret = wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_WLAN_PROFILE_ENABLE_PROFILE_ID_CMDID); + if (ret) { + WMI_LOGE("enable cmd Failed for id %d value %d", + value1, value2); + wmi_buf_free(buf); + return ret; + } + break; + + default: + WMI_LOGD("%s: invalid profiling command", __func__); + break; + } + + return 0; +} + +#ifdef FEATURE_WLAN_RA_FILTERING +/** + * send_wow_sta_ra_filter_cmd_tlv() - set RA filter pattern in fw + * @wmi_handle: wmi handle + * @vdev_id: vdev id + * + * Return: CDF status + */ +QDF_STATUS send_wow_sta_ra_filter_cmd_tlv(wmi_unified_t wmi_handle, + uint8_t vdev_id, uint8_t default_pattern, + uint16_t rate_limit_interval) +{ + + WMI_WOW_ADD_PATTERN_CMD_fixed_param *cmd; + wmi_buf_t buf; + uint8_t *buf_ptr; + int32_t len; + int ret; + + len = sizeof(WMI_WOW_ADD_PATTERN_CMD_fixed_param) + + WMI_TLV_HDR_SIZE + + 0 * sizeof(WOW_BITMAP_PATTERN_T) + + WMI_TLV_HDR_SIZE + + 0 * sizeof(WOW_IPV4_SYNC_PATTERN_T) + + WMI_TLV_HDR_SIZE + + 0 * sizeof(WOW_IPV6_SYNC_PATTERN_T) + + WMI_TLV_HDR_SIZE + + 0 * sizeof(WOW_MAGIC_PATTERN_CMD) + + WMI_TLV_HDR_SIZE + + 0 * sizeof(A_UINT32) + WMI_TLV_HDR_SIZE + 1 * sizeof(A_UINT32); + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMI_LOGE("%s: Failed allocate wmi buffer", __func__); + return QDF_STATUS_E_NOMEM; + } + + cmd = (WMI_WOW_ADD_PATTERN_CMD_fixed_param *) wmi_buf_data(buf); + buf_ptr = (uint8_t *) cmd; + + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_WMI_WOW_ADD_PATTERN_CMD_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (WMI_WOW_ADD_PATTERN_CMD_fixed_param)); + cmd->vdev_id = vdev_id; + cmd->pattern_id = default_pattern, + cmd->pattern_type = WOW_IPV6_RA_PATTERN; + buf_ptr += sizeof(WMI_WOW_ADD_PATTERN_CMD_fixed_param); + + /* Fill TLV for WMITLV_TAG_STRUC_WOW_BITMAP_PATTERN_T but no data. */ + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, 0); + buf_ptr += WMI_TLV_HDR_SIZE; + + /* Fill TLV for WMITLV_TAG_STRUC_WOW_IPV4_SYNC_PATTERN_T but no data. */ + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, 0); + buf_ptr += WMI_TLV_HDR_SIZE; + + /* Fill TLV for WMITLV_TAG_STRUC_WOW_IPV6_SYNC_PATTERN_T but no data. */ + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, 0); + buf_ptr += WMI_TLV_HDR_SIZE; + + /* Fill TLV for WMITLV_TAG_STRUC_WOW_MAGIC_PATTERN_CMD but no data. */ + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, 0); + buf_ptr += WMI_TLV_HDR_SIZE; + + /* Fill TLV for pattern_info_timeout but no data. */ + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_UINT32, 0); + buf_ptr += WMI_TLV_HDR_SIZE; + + /* Fill TLV for ra_ratelimit_interval. */ + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_UINT32, sizeof(A_UINT32)); + buf_ptr += WMI_TLV_HDR_SIZE; + + *((A_UINT32 *) buf_ptr) = rate_limit_interval; + + WMI_LOGD("%s: send RA rate limit [%d] to fw vdev = %d", __func__, + rate_limit_interval, vdev_id); + + ret = wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_WOW_ADD_WAKE_PATTERN_CMDID); + if (ret) { + WMI_LOGE("%s: Failed to send RA rate limit to fw", __func__); + wmi_buf_free(buf); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; + +} +#endif /* FEATURE_WLAN_RA_FILTERING */ + +/** + * send_nat_keepalive_en_cmd_tlv() - enable NAT keepalive filter + * @wmi_handle: wmi handle + * @vdev_id: vdev id + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +QDF_STATUS send_nat_keepalive_en_cmd_tlv(wmi_unified_t wmi_handle, uint8_t vdev_id) +{ + WMI_VDEV_IPSEC_NATKEEPALIVE_FILTER_CMD_fixed_param *cmd; + wmi_buf_t buf; + int32_t len = sizeof(*cmd); + + WMI_LOGD("%s: vdev_id %d", __func__, vdev_id); + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMI_LOGP("%s: wmi_buf_alloc failed", __func__); + return QDF_STATUS_E_NOMEM; + } + cmd = (WMI_VDEV_IPSEC_NATKEEPALIVE_FILTER_CMD_fixed_param *) + wmi_buf_data(buf); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_WMI_VDEV_IPSEC_NATKEEPALIVE_FILTER_CMD_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (WMI_VDEV_IPSEC_NATKEEPALIVE_FILTER_CMD_fixed_param)); + cmd->vdev_id = vdev_id; + cmd->action = IPSEC_NATKEEPALIVE_FILTER_ENABLE; + if (wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_VDEV_IPSEC_NATKEEPALIVE_FILTER_CMDID)) { + WMI_LOGP("%s: Failed to send NAT keepalive enable command", + __func__); + wmi_buf_free(buf); + return QDF_STATUS_E_FAILURE; + } + + return 0; +} + +/** + * wmi_unified_csa_offload_enable() - sen CSA offload enable command + * @wmi_handle: wmi handle + * @vdev_id: vdev id + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +QDF_STATUS send_csa_offload_enable_cmd_tlv(wmi_unified_t wmi_handle, + uint8_t vdev_id) +{ + wmi_csa_offload_enable_cmd_fixed_param *cmd; + wmi_buf_t buf; + int32_t len = sizeof(*cmd); + + WMI_LOGD("%s: vdev_id %d", __func__, vdev_id); + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMI_LOGP("%s: wmi_buf_alloc failed", __func__); + return QDF_STATUS_E_NOMEM; + } + cmd = (wmi_csa_offload_enable_cmd_fixed_param *) wmi_buf_data(buf); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_csa_offload_enable_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_csa_offload_enable_cmd_fixed_param)); + cmd->vdev_id = vdev_id; + cmd->csa_offload_enable = WMI_CSA_OFFLOAD_ENABLE; + if (wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_CSA_OFFLOAD_ENABLE_CMDID)) { + WMI_LOGP("%s: Failed to send CSA offload enable command", + __func__); + wmi_buf_free(buf); + return QDF_STATUS_E_FAILURE; + } + + return 0; +} + +/** + * send_start_oem_data_cmd_tlv() - start OEM data request to target + * @wmi_handle: wmi handle + * @startOemDataReq: start request params + * + * Return: CDF status + */ +QDF_STATUS send_start_oem_data_cmd_tlv(wmi_unified_t wmi_handle, + uint32_t data_len, + uint8_t *data) +{ + wmi_buf_t buf; + uint8_t *cmd; + QDF_STATUS ret; + + buf = wmi_buf_alloc(wmi_handle, + (data_len + WMI_TLV_HDR_SIZE)); + if (!buf) { + WMI_LOGE(FL("wmi_buf_alloc failed")); + return QDF_STATUS_E_FAILURE; + } + + cmd = (uint8_t *) wmi_buf_data(buf); + + WMITLV_SET_HDR(cmd, WMITLV_TAG_ARRAY_BYTE, data_len); + cmd += WMI_TLV_HDR_SIZE; + qdf_mem_copy(cmd, data, + data_len); + + WMI_LOGI(FL("Sending OEM Data Request to target, data len %d"), + data_len); + + ret = wmi_unified_cmd_send(wmi_handle, buf, + (data_len + + WMI_TLV_HDR_SIZE), WMI_OEM_REQ_CMDID); + + if (QDF_IS_STATUS_ERROR(ret)) { + WMI_LOGE(FL(":wmi cmd send failed")); + wmi_buf_free(buf); + } + + return ret; +} + +/** + * send_dfs_phyerr_filter_offload_en_cmd_tlv() - enable dfs phyerr filter + * @wmi_handle: wmi handle + * @dfs_phyerr_filter_offload: is dfs phyerr filter offload + * + * Send WMI_DFS_PHYERR_FILTER_ENA_CMDID or + * WMI_DFS_PHYERR_FILTER_DIS_CMDID command + * to firmware based on phyerr filtering + * offload status. + * + * Return: 1 success, 0 failure + */ +QDF_STATUS +send_dfs_phyerr_filter_offload_en_cmd_tlv(wmi_unified_t wmi_handle, + bool dfs_phyerr_filter_offload) +{ + wmi_dfs_phyerr_filter_ena_cmd_fixed_param *enable_phyerr_offload_cmd; + wmi_dfs_phyerr_filter_dis_cmd_fixed_param *disable_phyerr_offload_cmd; + wmi_buf_t buf; + uint16_t len; + QDF_STATUS ret; + + + if (false == dfs_phyerr_filter_offload) { + WMI_LOGD("%s:Phyerror Filtering offload is Disabled in ini", + __func__); + len = sizeof(*disable_phyerr_offload_cmd); + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMI_LOGE("%s:wmi_buf_alloc failed", __func__); + return 0; + } + disable_phyerr_offload_cmd = + (wmi_dfs_phyerr_filter_dis_cmd_fixed_param *) + wmi_buf_data(buf); + + WMITLV_SET_HDR(&disable_phyerr_offload_cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_dfs_phyerr_filter_dis_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_dfs_phyerr_filter_dis_cmd_fixed_param)); + + /* + * Send WMI_DFS_PHYERR_FILTER_DIS_CMDID + * to the firmware to disable the phyerror + * filtering offload. + */ + ret = wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_DFS_PHYERR_FILTER_DIS_CMDID); + if (QDF_IS_STATUS_ERROR(ret)) { + WMI_LOGE("%s: Failed to send WMI_DFS_PHYERR_FILTER_DIS_CMDID ret=%d", + __func__, ret); + wmi_buf_free(buf); + return QDF_STATUS_E_FAILURE; + } + WMI_LOGD("%s: WMI_DFS_PHYERR_FILTER_DIS_CMDID Send Success", + __func__); + } else { + WMI_LOGD("%s:Phyerror Filtering offload is Enabled in ini", + __func__); + + len = sizeof(*enable_phyerr_offload_cmd); + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMI_LOGE("%s:wmi_buf_alloc failed", __func__); + return QDF_STATUS_E_FAILURE; + } + + enable_phyerr_offload_cmd = + (wmi_dfs_phyerr_filter_ena_cmd_fixed_param *) + wmi_buf_data(buf); + + WMITLV_SET_HDR(&enable_phyerr_offload_cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_dfs_phyerr_filter_ena_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_dfs_phyerr_filter_ena_cmd_fixed_param)); + + /* + * Send a WMI_DFS_PHYERR_FILTER_ENA_CMDID + * to the firmware to enable the phyerror + * filtering offload. + */ + ret = wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_DFS_PHYERR_FILTER_ENA_CMDID); + + if (QDF_IS_STATUS_ERROR(ret)) { + WMI_LOGE("%s: Failed to send DFS PHYERR CMD ret=%d", + __func__, ret); + wmi_buf_free(buf); + return QDF_STATUS_E_FAILURE; + } + WMI_LOGD("%s: WMI_DFS_PHYERR_FILTER_ENA_CMDID Send Success", + __func__); + } + + return QDF_STATUS_SUCCESS; +} + +#if !defined(REMOVE_PKT_LOG) +/** + * send_pktlog_wmi_send_cmd_tlv() - send pktlog enable/disable command to target + * @wmi_handle: wmi handle + * @pktlog_event: pktlog event + * @cmd_id: pktlog cmd id + * + * Return: CDF status + */ +QDF_STATUS send_pktlog_wmi_send_cmd_tlv(wmi_unified_t wmi_handle, + WMI_PKTLOG_EVENT pktlog_event, + WMI_CMD_ID cmd_id, uint8_t user_triggered) +{ + WMI_PKTLOG_EVENT PKTLOG_EVENT; + WMI_CMD_ID CMD_ID; + wmi_pdev_pktlog_enable_cmd_fixed_param *cmd; + wmi_pdev_pktlog_disable_cmd_fixed_param *disable_cmd; + int len = 0; + wmi_buf_t buf; + + PKTLOG_EVENT = pktlog_event; + CMD_ID = cmd_id; + + switch (CMD_ID) { + case WMI_PDEV_PKTLOG_ENABLE_CMDID: + len = sizeof(*cmd); + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMI_LOGE("%s:wmi_buf_alloc failed", __func__); + return QDF_STATUS_E_NOMEM; + } + cmd = (wmi_pdev_pktlog_enable_cmd_fixed_param *) + wmi_buf_data(buf); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_pdev_pktlog_enable_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_pdev_pktlog_enable_cmd_fixed_param)); + cmd->evlist = PKTLOG_EVENT; + cmd->enable = user_triggered ? WMI_PKTLOG_ENABLE_FORCE + : WMI_PKTLOG_ENABLE_AUTO; + cmd->pdev_id = WMI_PDEV_ID_SOC; + if (wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_PDEV_PKTLOG_ENABLE_CMDID)) { + WMI_LOGE("failed to send pktlog enable cmdid"); + goto wmi_send_failed; + } + break; + case WMI_PDEV_PKTLOG_DISABLE_CMDID: + len = sizeof(*disable_cmd); + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMI_LOGE("%s:wmi_buf_alloc failed", __func__); + return QDF_STATUS_E_NOMEM; + } + disable_cmd = (wmi_pdev_pktlog_disable_cmd_fixed_param *) + wmi_buf_data(buf); + WMITLV_SET_HDR(&disable_cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_pdev_pktlog_disable_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_pdev_pktlog_disable_cmd_fixed_param)); + disable_cmd->pdev_id = WMI_PDEV_ID_SOC; + if (wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_PDEV_PKTLOG_DISABLE_CMDID)) { + WMI_LOGE("failed to send pktlog disable cmdid"); + goto wmi_send_failed; + } + break; + default: + WMI_LOGD("%s: invalid PKTLOG command", __func__); + break; + } + + return QDF_STATUS_SUCCESS; + +wmi_send_failed: + wmi_buf_free(buf); + return QDF_STATUS_E_FAILURE; +} +#endif /* REMOVE_PKT_LOG */ + +/** + * send_add_wow_wakeup_event_cmd_tlv() - Configures wow wakeup events. + * @wmi_handle: wmi handle + * @vdev_id: vdev id + * @bitmap: Event bitmap + * @enable: enable/disable + * + * Return: CDF status + */ +QDF_STATUS send_add_wow_wakeup_event_cmd_tlv(wmi_unified_t wmi_handle, + uint32_t vdev_id, + uint32_t *bitmap, + bool enable) +{ + WMI_WOW_ADD_DEL_EVT_CMD_fixed_param *cmd; + uint16_t len; + wmi_buf_t buf; + int ret; + + len = sizeof(WMI_WOW_ADD_DEL_EVT_CMD_fixed_param); + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMI_LOGE("%s: Failed allocate wmi buffer", __func__); + return QDF_STATUS_E_NOMEM; + } + cmd = (WMI_WOW_ADD_DEL_EVT_CMD_fixed_param *) wmi_buf_data(buf); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_WMI_WOW_ADD_DEL_EVT_CMD_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (WMI_WOW_ADD_DEL_EVT_CMD_fixed_param)); + cmd->vdev_id = vdev_id; + cmd->is_add = enable; + qdf_mem_copy(&(cmd->event_bitmaps[0]), bitmap, sizeof(uint32_t) * + WMI_WOW_MAX_EVENT_BM_LEN); + + WMI_LOGD("Wakeup pattern 0x%x%x%x%x %s in fw", cmd->event_bitmaps[0], + cmd->event_bitmaps[1], cmd->event_bitmaps[2], + cmd->event_bitmaps[3], enable ? "enabled" : "disabled"); + + ret = wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_WOW_ENABLE_DISABLE_WAKE_EVENT_CMDID); + if (ret) { + WMI_LOGE("Failed to config wow wakeup event"); + wmi_buf_free(buf); + return QDF_STATUS_E_FAILURE; + } + + /* Do not access buf or cmd data after this as WMI tx complete interrupt + * could have freed the buffer in different context + */ + + return QDF_STATUS_SUCCESS; +} + +/** + * send_wow_patterns_to_fw_cmd_tlv() - Sends WOW patterns to FW. + * @wmi_handle: wmi handle + * @vdev_id: vdev id + * @ptrn_id: pattern id + * @ptrn: pattern + * @ptrn_len: pattern length + * @ptrn_offset: pattern offset + * @mask: mask + * @mask_len: mask length + * @user: true for user configured pattern and false for default pattern + * @default_patterns: default patterns + * + * Return: CDF status + */ +QDF_STATUS send_wow_patterns_to_fw_cmd_tlv(wmi_unified_t wmi_handle, + uint8_t vdev_id, uint8_t ptrn_id, + const uint8_t *ptrn, uint8_t ptrn_len, + uint8_t ptrn_offset, const uint8_t *mask, + uint8_t mask_len, bool user, + uint8_t default_patterns) +{ + WMI_WOW_ADD_PATTERN_CMD_fixed_param *cmd; + WOW_BITMAP_PATTERN_T *bitmap_pattern; + wmi_buf_t buf; + uint8_t *buf_ptr; + int32_t len; + int ret; + + + len = sizeof(WMI_WOW_ADD_PATTERN_CMD_fixed_param) + + WMI_TLV_HDR_SIZE + + 1 * sizeof(WOW_BITMAP_PATTERN_T) + + WMI_TLV_HDR_SIZE + + 0 * sizeof(WOW_IPV4_SYNC_PATTERN_T) + + WMI_TLV_HDR_SIZE + + 0 * sizeof(WOW_IPV6_SYNC_PATTERN_T) + + WMI_TLV_HDR_SIZE + + 0 * sizeof(WOW_MAGIC_PATTERN_CMD) + + WMI_TLV_HDR_SIZE + + 0 * sizeof(A_UINT32) + WMI_TLV_HDR_SIZE + 1 * sizeof(A_UINT32); + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMI_LOGE("%s: Failed allocate wmi buffer", __func__); + return QDF_STATUS_E_NOMEM; + } + + cmd = (WMI_WOW_ADD_PATTERN_CMD_fixed_param *) wmi_buf_data(buf); + buf_ptr = (uint8_t *) cmd; + + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_WMI_WOW_ADD_PATTERN_CMD_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (WMI_WOW_ADD_PATTERN_CMD_fixed_param)); + cmd->vdev_id = vdev_id; + cmd->pattern_id = ptrn_id; + + cmd->pattern_type = WOW_BITMAP_PATTERN; + buf_ptr += sizeof(WMI_WOW_ADD_PATTERN_CMD_fixed_param); + + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, + sizeof(WOW_BITMAP_PATTERN_T)); + buf_ptr += WMI_TLV_HDR_SIZE; + bitmap_pattern = (WOW_BITMAP_PATTERN_T *) buf_ptr; + + WMITLV_SET_HDR(&bitmap_pattern->tlv_header, + WMITLV_TAG_STRUC_WOW_BITMAP_PATTERN_T, + WMITLV_GET_STRUCT_TLVLEN(WOW_BITMAP_PATTERN_T)); + + qdf_mem_copy(&bitmap_pattern->patternbuf[0], ptrn, ptrn_len); + qdf_mem_copy(&bitmap_pattern->bitmaskbuf[0], mask, mask_len); + + bitmap_pattern->pattern_offset = ptrn_offset; + bitmap_pattern->pattern_len = ptrn_len; + + if (bitmap_pattern->pattern_len > WOW_DEFAULT_BITMAP_PATTERN_SIZE) + bitmap_pattern->pattern_len = WOW_DEFAULT_BITMAP_PATTERN_SIZE; + + if (bitmap_pattern->pattern_len > WOW_DEFAULT_BITMASK_SIZE) + bitmap_pattern->pattern_len = WOW_DEFAULT_BITMASK_SIZE; + + bitmap_pattern->bitmask_len = bitmap_pattern->pattern_len; + bitmap_pattern->pattern_id = ptrn_id; + + WMI_LOGI("vdev id : %d, ptrn id: %d, ptrn len: %d, ptrn offset: %d user %d", + cmd->vdev_id, cmd->pattern_id, bitmap_pattern->pattern_len, + bitmap_pattern->pattern_offset, user); +#ifdef CONFIG_MCL + WMI_LOGI("Pattern : "); + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_WMI, QDF_TRACE_LEVEL_INFO, + &bitmap_pattern->patternbuf[0], bitmap_pattern->pattern_len); + + WMI_LOGI("Mask : "); + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_WMI, QDF_TRACE_LEVEL_INFO, + &bitmap_pattern->bitmaskbuf[0], bitmap_pattern->pattern_len); +#endif + + buf_ptr += sizeof(WOW_BITMAP_PATTERN_T); + + /* Fill TLV for WMITLV_TAG_STRUC_WOW_IPV4_SYNC_PATTERN_T but no data. */ + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, 0); + buf_ptr += WMI_TLV_HDR_SIZE; + + /* Fill TLV for WMITLV_TAG_STRUC_WOW_IPV6_SYNC_PATTERN_T but no data. */ + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, 0); + buf_ptr += WMI_TLV_HDR_SIZE; + + /* Fill TLV for WMITLV_TAG_STRUC_WOW_MAGIC_PATTERN_CMD but no data. */ + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, 0); + buf_ptr += WMI_TLV_HDR_SIZE; + + /* Fill TLV for pattern_info_timeout but no data. */ + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_UINT32, 0); + buf_ptr += WMI_TLV_HDR_SIZE; + + /* Fill TLV for ratelimit_interval with dummy data as this fix elem */ + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_UINT32, 1 * sizeof(A_UINT32)); + buf_ptr += WMI_TLV_HDR_SIZE; + *(A_UINT32 *) buf_ptr = 0; + + ret = wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_WOW_ADD_WAKE_PATTERN_CMDID); + if (ret) { + WMI_LOGE("%s: Failed to send wow ptrn to fw", __func__); + wmi_buf_free(buf); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * send_wow_delete_pattern_cmd_tlv() - delete wow pattern in target + * @wmi_handle: wmi handle + * @ptrn_id: pattern id + * @vdev_id: vdev id + * + * Return: CDF status + */ +QDF_STATUS send_wow_delete_pattern_cmd_tlv(wmi_unified_t wmi_handle, uint8_t ptrn_id, + uint8_t vdev_id) +{ + WMI_WOW_DEL_PATTERN_CMD_fixed_param *cmd; + wmi_buf_t buf; + int32_t len; + int ret; + + len = sizeof(WMI_WOW_DEL_PATTERN_CMD_fixed_param); + + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMI_LOGE("%s: Failed allocate wmi buffer", __func__); + return QDF_STATUS_E_NOMEM; + } + + cmd = (WMI_WOW_DEL_PATTERN_CMD_fixed_param *) wmi_buf_data(buf); + + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_WMI_WOW_DEL_PATTERN_CMD_fixed_param, + WMITLV_GET_STRUCT_TLVLEN( + WMI_WOW_DEL_PATTERN_CMD_fixed_param)); + cmd->vdev_id = vdev_id; + cmd->pattern_id = ptrn_id; + cmd->pattern_type = WOW_BITMAP_PATTERN; + + WMI_LOGI("Deleting pattern id: %d vdev id %d in fw", + cmd->pattern_id, vdev_id); + + ret = wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_WOW_DEL_WAKE_PATTERN_CMDID); + if (ret) { + WMI_LOGE("%s: Failed to delete wow ptrn from fw", __func__); + wmi_buf_free(buf); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * send_host_wakeup_ind_to_fw_cmd_tlv() - send wakeup ind to fw + * @wmi_handle: wmi handle + * + * Sends host wakeup indication to FW. On receiving this indication, + * FW will come out of WOW. + * + * Return: CDF status + */ +QDF_STATUS send_host_wakeup_ind_to_fw_cmd_tlv(wmi_unified_t wmi_handle) +{ + wmi_wow_hostwakeup_from_sleep_cmd_fixed_param *cmd; + wmi_buf_t buf; + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + int32_t len; + int ret; + + len = sizeof(wmi_wow_hostwakeup_from_sleep_cmd_fixed_param); + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMI_LOGE("%s: Failed allocate wmi buffer", __func__); + return QDF_STATUS_E_NOMEM; + } + + cmd = (wmi_wow_hostwakeup_from_sleep_cmd_fixed_param *) + wmi_buf_data(buf); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_wow_hostwakeup_from_sleep_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_wow_hostwakeup_from_sleep_cmd_fixed_param)); + + + ret = wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_WOW_HOSTWAKEUP_FROM_SLEEP_CMDID); + if (ret) { + WMI_LOGE("Failed to send host wakeup indication to fw"); + wmi_buf_free(buf); + return QDF_STATUS_E_FAILURE; + } + + return qdf_status; +} + +/** + * send_del_ts_cmd_tlv() - send DELTS request to fw + * @wmi_handle: wmi handle + * @msg: delts params + * + * Return: CDF status + */ +QDF_STATUS send_del_ts_cmd_tlv(wmi_unified_t wmi_handle, uint8_t vdev_id, + uint8_t ac) +{ + wmi_vdev_wmm_delts_cmd_fixed_param *cmd; + wmi_buf_t buf; + int32_t len = sizeof(*cmd); + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMI_LOGP("%s: wmi_buf_alloc failed", __func__); + return QDF_STATUS_E_NOMEM; + } + cmd = (wmi_vdev_wmm_delts_cmd_fixed_param *) wmi_buf_data(buf); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_vdev_wmm_delts_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_vdev_wmm_delts_cmd_fixed_param)); + cmd->vdev_id = vdev_id; + cmd->ac = ac; + + WMI_LOGD("Delts vdev:%d, ac:%d, %s:%d", + cmd->vdev_id, cmd->ac, __func__, __LINE__); + if (wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_VDEV_WMM_DELTS_CMDID)) { + WMI_LOGP("%s: Failed to send vdev DELTS command", __func__); + wmi_buf_free(buf); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * send_aggr_qos_cmd_tlv() - send aggr qos request to fw + * @wmi_handle: handle to wmi + * @aggr_qos_rsp_msg - combined struct for all ADD_TS requests. + * + * A function to handle WMI_AGGR_QOS_REQ. This will send out + * ADD_TS requestes to firmware in loop for all the ACs with + * active flow. + * + * Return: CDF status + */ +QDF_STATUS send_aggr_qos_cmd_tlv(wmi_unified_t wmi_handle, + struct aggr_add_ts_param *aggr_qos_rsp_msg) +{ + int i = 0; + wmi_vdev_wmm_addts_cmd_fixed_param *cmd; + wmi_buf_t buf; + int32_t len = sizeof(*cmd); + + for (i = 0; i < WMI_QOS_NUM_AC_MAX; i++) { + /* if flow in this AC is active */ + if (((1 << i) & aggr_qos_rsp_msg->tspecIdx)) { + /* + * as per implementation of wma_add_ts_req() we + * are not waiting any response from firmware so + * apart from sending ADDTS to firmware just send + * success to upper layers + */ + aggr_qos_rsp_msg->status[i] = QDF_STATUS_SUCCESS; + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMI_LOGP("%s: wmi_buf_alloc failed", __func__); + return QDF_STATUS_E_NOMEM; + } + cmd = (wmi_vdev_wmm_addts_cmd_fixed_param *) + wmi_buf_data(buf); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_vdev_wmm_addts_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_vdev_wmm_addts_cmd_fixed_param)); + cmd->vdev_id = aggr_qos_rsp_msg->sessionId; + cmd->ac = + WMI_TID_TO_AC(aggr_qos_rsp_msg->tspec[i].tsinfo. + traffic.userPrio); + cmd->medium_time_us = + aggr_qos_rsp_msg->tspec[i].mediumTime * 32; + cmd->downgrade_type = WMM_AC_DOWNGRADE_DEPRIO; + WMI_LOGD("%s:%d: Addts vdev:%d, ac:%d, mediumTime:%d downgrade_type:%d", + __func__, __LINE__, cmd->vdev_id, cmd->ac, + cmd->medium_time_us, cmd->downgrade_type); + if (wmi_unified_cmd_send + (wmi_handle, buf, len, + WMI_VDEV_WMM_ADDTS_CMDID)) { + WMI_LOGP("%s: Failed to send vdev ADDTS command", + __func__); + aggr_qos_rsp_msg->status[i] = + QDF_STATUS_E_FAILURE; + wmi_buf_free(buf); + return QDF_STATUS_E_FAILURE; + } + } + } + + return QDF_STATUS_SUCCESS; +} + +/** + * send_add_ts_cmd_tlv() - send ADDTS request to fw + * @wmi_handle: wmi handle + * @msg: ADDTS params + * + * Return: CDF status + */ +QDF_STATUS send_add_ts_cmd_tlv(wmi_unified_t wmi_handle, + struct add_ts_param *msg) +{ + wmi_vdev_wmm_addts_cmd_fixed_param *cmd; + wmi_buf_t buf; + int32_t len = sizeof(*cmd); + + msg->status = QDF_STATUS_SUCCESS; + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMI_LOGP("%s: wmi_buf_alloc failed", __func__); + return QDF_STATUS_E_NOMEM; + } + cmd = (wmi_vdev_wmm_addts_cmd_fixed_param *) wmi_buf_data(buf); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_vdev_wmm_addts_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_vdev_wmm_addts_cmd_fixed_param)); + cmd->vdev_id = msg->sme_session_id; + cmd->ac = msg->tspec.tsinfo.traffic.userPrio; + cmd->medium_time_us = msg->tspec.mediumTime * 32; + cmd->downgrade_type = WMM_AC_DOWNGRADE_DROP; + WMI_LOGD("Addts vdev:%d, ac:%d, mediumTime:%d, downgrade_type:%d %s:%d", + cmd->vdev_id, cmd->ac, cmd->medium_time_us, + cmd->downgrade_type, __func__, __LINE__); + if (wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_VDEV_WMM_ADDTS_CMDID)) { + WMI_LOGP("%s: Failed to send vdev ADDTS command", __func__); + msg->status = QDF_STATUS_E_FAILURE; + wmi_buf_free(buf); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * send_enable_disable_packet_filter_cmd_tlv() - enable/disable packet filter in target + * @wmi_handle: wmi handle + * @vdev_id: vdev id + * @enable: Flag to enable/disable packet filter + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +QDF_STATUS send_enable_disable_packet_filter_cmd_tlv(wmi_unified_t wmi_handle, + uint8_t vdev_id, bool enable) +{ + int32_t len; + int ret = 0; + wmi_buf_t buf; + WMI_PACKET_FILTER_ENABLE_CMD_fixed_param *cmd; + + len = sizeof(WMI_PACKET_FILTER_ENABLE_CMD_fixed_param); + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMI_LOGE("%s: Failed allocate wmi buffer", __func__); + return QDF_STATUS_E_NOMEM; + } + + cmd = (WMI_PACKET_FILTER_ENABLE_CMD_fixed_param *) wmi_buf_data(buf); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_packet_filter_enable_fixed_param, + WMITLV_GET_STRUCT_TLVLEN( + WMI_PACKET_FILTER_ENABLE_CMD_fixed_param)); + + cmd->vdev_id = vdev_id; + if (enable) + cmd->enable = PACKET_FILTER_SET_ENABLE; + else + cmd->enable = PACKET_FILTER_SET_DISABLE; + + WMI_LOGE("%s: Packet filter enable %d for vdev_id %d", + __func__, cmd->enable, vdev_id); + + ret = wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_PACKET_FILTER_ENABLE_CMDID); + if (ret) { + WMI_LOGE("Failed to send packet filter wmi cmd to fw"); + wmi_buf_free(buf); + } + + return ret; +} + +/** + * send_config_packet_filter_cmd_tlv() - configure packet filter in target + * @wmi_handle: wmi handle + * @vdev_id: vdev id + * @rcv_filter_param: Packet filter parameters + * @filter_id: Filter id + * @enable: Flag to add/delete packet filter configuration + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +QDF_STATUS send_config_packet_filter_cmd_tlv(wmi_unified_t wmi_handle, + uint8_t vdev_id, struct rcv_pkt_filter_config *rcv_filter_param, + uint8_t filter_id, bool enable) +{ + int len, i; + int err = 0; + wmi_buf_t buf; + WMI_PACKET_FILTER_CONFIG_CMD_fixed_param *cmd; + + + /* allocate the memory */ + len = sizeof(*cmd); + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMI_LOGE("Failed to allocate buffer to send set_param cmd"); + return QDF_STATUS_E_NOMEM; + } + + cmd = (WMI_PACKET_FILTER_CONFIG_CMD_fixed_param *)wmi_buf_data(buf); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_packet_filter_config_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (WMI_PACKET_FILTER_CONFIG_CMD_fixed_param)); + + cmd->vdev_id = vdev_id; + cmd->filter_id = filter_id; + if (enable) + cmd->filter_action = PACKET_FILTER_SET_ACTIVE; + else + cmd->filter_action = PACKET_FILTER_SET_INACTIVE; + + if (enable) { + cmd->num_params = QDF_MIN( + WMI_PACKET_FILTER_MAX_CMP_PER_PACKET_FILTER, + rcv_filter_param->numFieldParams); + cmd->filter_type = rcv_filter_param->filterType; + cmd->coalesce_time = rcv_filter_param->coalesceTime; + + for (i = 0; i < cmd->num_params; i++) { + cmd->paramsData[i].proto_type = + rcv_filter_param->paramsData[i].protocolLayer; + cmd->paramsData[i].cmp_type = + rcv_filter_param->paramsData[i].cmpFlag; + cmd->paramsData[i].data_length = + rcv_filter_param->paramsData[i].dataLength; + cmd->paramsData[i].data_offset = + rcv_filter_param->paramsData[i].dataOffset; + memcpy(&cmd->paramsData[i].compareData, + rcv_filter_param->paramsData[i].compareData, + sizeof(cmd->paramsData[i].compareData)); + memcpy(&cmd->paramsData[i].dataMask, + rcv_filter_param->paramsData[i].dataMask, + sizeof(cmd->paramsData[i].dataMask)); + } + } + + WMI_LOGE("Packet filter action %d filter with id: %d, num_params=%d", + cmd->filter_action, cmd->filter_id, cmd->num_params); + /* send the command along with data */ + err = wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_PACKET_FILTER_CONFIG_CMDID); + if (err) { + WMI_LOGE("Failed to send pkt_filter cmd"); + wmi_buf_free(buf); + return QDF_STATUS_E_FAILURE; + } + + + return 0; +} + +/** + * send_add_clear_mcbc_filter_cmd_tlv() - set mcast filter command to fw + * @wmi_handle: wmi handle + * @vdev_id: vdev id + * @multicastAddr: mcast address + * @clearList: clear list flag + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +QDF_STATUS send_add_clear_mcbc_filter_cmd_tlv(wmi_unified_t wmi_handle, + uint8_t vdev_id, + struct qdf_mac_addr multicast_addr, + bool clearList) +{ + WMI_SET_MCASTBCAST_FILTER_CMD_fixed_param *cmd; + wmi_buf_t buf; + int err; + + buf = wmi_buf_alloc(wmi_handle, sizeof(*cmd)); + if (!buf) { + WMI_LOGE("Failed to allocate buffer to send set_param cmd"); + return QDF_STATUS_E_NOMEM; + } + + cmd = (WMI_SET_MCASTBCAST_FILTER_CMD_fixed_param *) wmi_buf_data(buf); + qdf_mem_zero(cmd, sizeof(*cmd)); + + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_WMI_SET_MCASTBCAST_FILTER_CMD_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (WMI_SET_MCASTBCAST_FILTER_CMD_fixed_param)); + cmd->action = + (clearList ? WMI_MCAST_FILTER_DELETE : WMI_MCAST_FILTER_SET); + cmd->vdev_id = vdev_id; + WMI_CHAR_ARRAY_TO_MAC_ADDR(multicast_addr.bytes, &cmd->mcastbdcastaddr); + + WMI_LOGD("Action:%d; vdev_id:%d; clearList:%d; MCBC MAC Addr: %pM", + cmd->action, vdev_id, clearList, multicast_addr.bytes); + + err = wmi_unified_cmd_send(wmi_handle, buf, + sizeof(*cmd), + WMI_SET_MCASTBCAST_FILTER_CMDID); + if (err) { + WMI_LOGE("Failed to send set_param cmd"); + wmi_buf_free(buf); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * send_gtk_offload_cmd_tlv() - send GTK offload command to fw + * @wmi_handle: wmi handle + * @vdev_id: vdev id + * @params: GTK offload parameters + * + * Return: CDF status + */ +QDF_STATUS send_gtk_offload_cmd_tlv(wmi_unified_t wmi_handle, uint8_t vdev_id, + struct gtk_offload_params *params, + bool enable_offload, + uint32_t gtk_offload_opcode) +{ + int len; + wmi_buf_t buf; + WMI_GTK_OFFLOAD_CMD_fixed_param *cmd; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + WMI_LOGD("%s Enter", __func__); + + len = sizeof(*cmd); + + /* alloc wmi buffer */ + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMI_LOGE("wmi_buf_alloc failed for WMI_GTK_OFFLOAD_CMD"); + status = QDF_STATUS_E_NOMEM; + goto out; + } + + cmd = (WMI_GTK_OFFLOAD_CMD_fixed_param *) wmi_buf_data(buf); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_WMI_GTK_OFFLOAD_CMD_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (WMI_GTK_OFFLOAD_CMD_fixed_param)); + + cmd->vdev_id = vdev_id; + + /* Request target to enable GTK offload */ + if (enable_offload == WMI_GTK_OFFLOAD_ENABLE) { + cmd->flags = gtk_offload_opcode; + + /* Copy the keys and replay counter */ + qdf_mem_copy(cmd->KCK, params->aKCK, WMI_GTK_OFFLOAD_KCK_BYTES); + qdf_mem_copy(cmd->KEK, params->aKEK, WMI_GTK_OFFLOAD_KEK_BYTES); + qdf_mem_copy(cmd->replay_counter, ¶ms->ullKeyReplayCounter, + GTK_REPLAY_COUNTER_BYTES); + } else { + cmd->flags = gtk_offload_opcode; + } + + WMI_LOGD("VDEVID: %d, GTK_FLAGS: x%x", vdev_id, cmd->flags); + + /* send the wmi command */ + if (wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_GTK_OFFLOAD_CMDID)) { + WMI_LOGE("Failed to send WMI_GTK_OFFLOAD_CMDID"); + wmi_buf_free(buf); + status = QDF_STATUS_E_FAILURE; + } + +out: + WMI_LOGD("%s Exit", __func__); + return status; +} + +/** + * send_process_gtk_offload_getinfo_cmd_tlv() - send GTK offload cmd to fw + * @wmi_handle: wmi handle + * @params: GTK offload params + * + * Return: CDF status + */ +QDF_STATUS send_process_gtk_offload_getinfo_cmd_tlv(wmi_unified_t wmi_handle, + uint8_t vdev_id, + uint64_t offload_req_opcode) +{ + int len; + wmi_buf_t buf; + WMI_GTK_OFFLOAD_CMD_fixed_param *cmd; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + len = sizeof(*cmd); + + /* alloc wmi buffer */ + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMI_LOGE("wmi_buf_alloc failed for WMI_GTK_OFFLOAD_CMD"); + status = QDF_STATUS_E_NOMEM; + goto out; + } + + cmd = (WMI_GTK_OFFLOAD_CMD_fixed_param *) wmi_buf_data(buf); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_WMI_GTK_OFFLOAD_CMD_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (WMI_GTK_OFFLOAD_CMD_fixed_param)); + + /* Request for GTK offload status */ + cmd->flags = offload_req_opcode; + cmd->vdev_id = vdev_id; + + /* send the wmi command */ + if (wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_GTK_OFFLOAD_CMDID)) { + WMI_LOGE("Failed to send WMI_GTK_OFFLOAD_CMDID for req info"); + wmi_buf_free(buf); + status = QDF_STATUS_E_FAILURE; + } + +out: + return status; +} + +/** + * send_process_add_periodic_tx_ptrn_cmd_tlv - add periodic tx ptrn + * @wmi_handle: wmi handle + * @pAddPeriodicTxPtrnParams: tx ptrn params + * + * Retrun: CDF status + */ +QDF_STATUS send_process_add_periodic_tx_ptrn_cmd_tlv(wmi_unified_t wmi_handle, + struct periodic_tx_pattern * + pAddPeriodicTxPtrnParams, + uint8_t vdev_id) +{ + WMI_ADD_PROACTIVE_ARP_RSP_PATTERN_CMD_fixed_param *cmd; + wmi_buf_t wmi_buf; + uint32_t len; + uint8_t *buf_ptr; + uint32_t ptrn_len, ptrn_len_aligned; + int j; + + ptrn_len = pAddPeriodicTxPtrnParams->ucPtrnSize; + ptrn_len_aligned = roundup(ptrn_len, sizeof(uint32_t)); + len = sizeof(WMI_ADD_PROACTIVE_ARP_RSP_PATTERN_CMD_fixed_param) + + WMI_TLV_HDR_SIZE + ptrn_len_aligned; + + wmi_buf = wmi_buf_alloc(wmi_handle, len); + if (!wmi_buf) { + WMI_LOGE("%s: wmi_buf_alloc failed", __func__); + return QDF_STATUS_E_NOMEM; + } + + buf_ptr = (uint8_t *) wmi_buf_data(wmi_buf); + + cmd = (WMI_ADD_PROACTIVE_ARP_RSP_PATTERN_CMD_fixed_param *) buf_ptr; + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_WMI_ADD_PROACTIVE_ARP_RSP_PATTERN_CMD_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (WMI_ADD_PROACTIVE_ARP_RSP_PATTERN_CMD_fixed_param)); + + /* Pass the pattern id to delete for the corresponding vdev id */ + cmd->vdev_id = vdev_id; + cmd->pattern_id = pAddPeriodicTxPtrnParams->ucPtrnId; + cmd->timeout = pAddPeriodicTxPtrnParams->usPtrnIntervalMs; + cmd->length = pAddPeriodicTxPtrnParams->ucPtrnSize; + + /* Pattern info */ + buf_ptr += sizeof(WMI_ADD_PROACTIVE_ARP_RSP_PATTERN_CMD_fixed_param); + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE, ptrn_len_aligned); + buf_ptr += WMI_TLV_HDR_SIZE; + qdf_mem_copy(buf_ptr, pAddPeriodicTxPtrnParams->ucPattern, ptrn_len); + for (j = 0; j < pAddPeriodicTxPtrnParams->ucPtrnSize; j++) + WMI_LOGD("%s: Add Ptrn: %02x", __func__, buf_ptr[j] & 0xff); + + WMI_LOGD("%s: Add ptrn id: %d vdev_id: %d", + __func__, cmd->pattern_id, cmd->vdev_id); + + if (wmi_unified_cmd_send(wmi_handle, wmi_buf, len, + WMI_ADD_PROACTIVE_ARP_RSP_PATTERN_CMDID)) { + WMI_LOGE("%s: failed to add pattern set state command", + __func__); + wmi_buf_free(wmi_buf); + return QDF_STATUS_E_FAILURE; + } + return QDF_STATUS_SUCCESS; +} + +/** + * send_process_del_periodic_tx_ptrn_cmd_tlv - del periodic tx ptrn + * @wmi_handle: wmi handle + * @vdev_id: vdev id + * @pattern_id: pattern id + * + * Retrun: CDF status + */ +QDF_STATUS send_process_del_periodic_tx_ptrn_cmd_tlv(wmi_unified_t wmi_handle, + uint8_t vdev_id, + uint8_t pattern_id) +{ + WMI_DEL_PROACTIVE_ARP_RSP_PATTERN_CMD_fixed_param *cmd; + wmi_buf_t wmi_buf; + uint32_t len = + sizeof(WMI_DEL_PROACTIVE_ARP_RSP_PATTERN_CMD_fixed_param); + + wmi_buf = wmi_buf_alloc(wmi_handle, len); + if (!wmi_buf) { + WMI_LOGE("%s: wmi_buf_alloc failed", __func__); + return QDF_STATUS_E_NOMEM; + } + + cmd = (WMI_DEL_PROACTIVE_ARP_RSP_PATTERN_CMD_fixed_param *) + wmi_buf_data(wmi_buf); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_WMI_DEL_PROACTIVE_ARP_RSP_PATTERN_CMD_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (WMI_DEL_PROACTIVE_ARP_RSP_PATTERN_CMD_fixed_param)); + + /* Pass the pattern id to delete for the corresponding vdev id */ + cmd->vdev_id = vdev_id; + cmd->pattern_id = pattern_id; + WMI_LOGD("%s: Del ptrn id: %d vdev_id: %d", + __func__, cmd->pattern_id, cmd->vdev_id); + + if (wmi_unified_cmd_send(wmi_handle, wmi_buf, len, + WMI_DEL_PROACTIVE_ARP_RSP_PATTERN_CMDID)) { + WMI_LOGE("%s: failed to send del pattern command", __func__); + wmi_buf_free(wmi_buf); + return QDF_STATUS_E_FAILURE; + } + return QDF_STATUS_SUCCESS; +} + +/** + * send_stats_ext_req_cmd_tlv() - request ext stats from fw + * @wmi_handle: wmi handle + * @preq: stats ext params + * + * Return: CDF status + */ +QDF_STATUS send_stats_ext_req_cmd_tlv(wmi_unified_t wmi_handle, + struct stats_ext_params *preq) +{ + QDF_STATUS ret; + wmi_req_stats_ext_cmd_fixed_param *cmd; + wmi_buf_t buf; + uint16_t len; + uint8_t *buf_ptr; + + len = sizeof(*cmd) + WMI_TLV_HDR_SIZE + preq->request_data_len; + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMI_LOGE("%s:wmi_buf_alloc failed", __func__); + return QDF_STATUS_E_NOMEM; + } + + buf_ptr = (uint8_t *) wmi_buf_data(buf); + cmd = (wmi_req_stats_ext_cmd_fixed_param *) buf_ptr; + + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_req_stats_ext_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_req_stats_ext_cmd_fixed_param)); + cmd->vdev_id = preq->vdev_id; + cmd->data_len = preq->request_data_len; + + WMI_LOGD("%s: The data len value is %u and vdev id set is %u ", + __func__, preq->request_data_len, preq->vdev_id); + + buf_ptr += sizeof(wmi_req_stats_ext_cmd_fixed_param); + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE, cmd->data_len); + + buf_ptr += WMI_TLV_HDR_SIZE; + qdf_mem_copy(buf_ptr, preq->request_data, cmd->data_len); + + ret = wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_REQUEST_STATS_EXT_CMDID); + if (QDF_IS_STATUS_ERROR(ret)) { + WMI_LOGE("%s: Failed to send notify cmd ret = %d", __func__, + ret); + wmi_buf_free(buf); + } + + return ret; +} + +/** + * send_enable_ext_wow_cmd_tlv() - enable ext wow in fw + * @wmi_handle: wmi handle + * @params: ext wow params + * + * Return:0 for success or error code + */ +QDF_STATUS send_enable_ext_wow_cmd_tlv(wmi_unified_t wmi_handle, + struct ext_wow_params *params) +{ + wmi_extwow_enable_cmd_fixed_param *cmd; + wmi_buf_t buf; + int32_t len; + int ret; + + len = sizeof(wmi_extwow_enable_cmd_fixed_param); + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMI_LOGE("%s: Failed allocate wmi buffer", __func__); + return QDF_STATUS_E_NOMEM; + } + + cmd = (wmi_extwow_enable_cmd_fixed_param *) wmi_buf_data(buf); + + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_extwow_enable_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_extwow_enable_cmd_fixed_param)); + + cmd->vdev_id = params->vdev_id; + cmd->type = params->type; + cmd->wakeup_pin_num = params->wakeup_pin_num; + + WMI_LOGD("%s: vdev_id %d type %d Wakeup_pin_num %x", + __func__, cmd->vdev_id, cmd->type, cmd->wakeup_pin_num); + + ret = wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_EXTWOW_ENABLE_CMDID); + if (ret) { + WMI_LOGE("%s: Failed to set EXTWOW Enable", __func__); + wmi_buf_free(buf); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; + +} + +/** + * send_app_type1_params_in_fw_cmd_tlv() - set app type1 params in fw + * @wmi_handle: wmi handle + * @app_type1_params: app type1 params + * + * Return: CDF status + */ +QDF_STATUS send_app_type1_params_in_fw_cmd_tlv(wmi_unified_t wmi_handle, + struct app_type1_params *app_type1_params) +{ + wmi_extwow_set_app_type1_params_cmd_fixed_param *cmd; + wmi_buf_t buf; + int32_t len; + int ret; + + len = sizeof(wmi_extwow_set_app_type1_params_cmd_fixed_param); + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMI_LOGE("%s: Failed allocate wmi buffer", __func__); + return QDF_STATUS_E_NOMEM; + } + + cmd = (wmi_extwow_set_app_type1_params_cmd_fixed_param *) + wmi_buf_data(buf); + + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_extwow_set_app_type1_params_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_extwow_set_app_type1_params_cmd_fixed_param)); + + cmd->vdev_id = app_type1_params->vdev_id; + WMI_CHAR_ARRAY_TO_MAC_ADDR(app_type1_params->wakee_mac_addr.bytes, + &cmd->wakee_mac); + qdf_mem_copy(cmd->ident, app_type1_params->identification_id, 8); + cmd->ident_len = app_type1_params->id_length; + qdf_mem_copy(cmd->passwd, app_type1_params->password, 16); + cmd->passwd_len = app_type1_params->pass_length; + + WMI_LOGD("%s: vdev_id %d wakee_mac_addr %pM " + "identification_id %.8s id_length %u " + "password %.16s pass_length %u", + __func__, cmd->vdev_id, app_type1_params->wakee_mac_addr.bytes, + cmd->ident, cmd->ident_len, cmd->passwd, cmd->passwd_len); + + ret = wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_EXTWOW_SET_APP_TYPE1_PARAMS_CMDID); + if (ret) { + WMI_LOGE("%s: Failed to set APP TYPE1 PARAMS", __func__); + wmi_buf_free(buf); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * send_set_app_type2_params_in_fw_cmd_tlv() - set app type2 params in fw + * @wmi_handle: wmi handle + * @appType2Params: app type2 params + * + * Return: CDF status + */ +QDF_STATUS send_set_app_type2_params_in_fw_cmd_tlv(wmi_unified_t wmi_handle, + struct app_type2_params *appType2Params) +{ + wmi_extwow_set_app_type2_params_cmd_fixed_param *cmd; + wmi_buf_t buf; + int32_t len; + int ret; + + len = sizeof(wmi_extwow_set_app_type2_params_cmd_fixed_param); + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMI_LOGE("%s: Failed allocate wmi buffer", __func__); + return QDF_STATUS_E_NOMEM; + } + + cmd = (wmi_extwow_set_app_type2_params_cmd_fixed_param *) + wmi_buf_data(buf); + + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_extwow_set_app_type2_params_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_extwow_set_app_type2_params_cmd_fixed_param)); + + cmd->vdev_id = appType2Params->vdev_id; + + qdf_mem_copy(cmd->rc4_key, appType2Params->rc4_key, 16); + cmd->rc4_key_len = appType2Params->rc4_key_len; + + cmd->ip_id = appType2Params->ip_id; + cmd->ip_device_ip = appType2Params->ip_device_ip; + cmd->ip_server_ip = appType2Params->ip_server_ip; + + cmd->tcp_src_port = appType2Params->tcp_src_port; + cmd->tcp_dst_port = appType2Params->tcp_dst_port; + cmd->tcp_seq = appType2Params->tcp_seq; + cmd->tcp_ack_seq = appType2Params->tcp_ack_seq; + + cmd->keepalive_init = appType2Params->keepalive_init; + cmd->keepalive_min = appType2Params->keepalive_min; + cmd->keepalive_max = appType2Params->keepalive_max; + cmd->keepalive_inc = appType2Params->keepalive_inc; + + WMI_CHAR_ARRAY_TO_MAC_ADDR(appType2Params->gateway_mac.bytes, + &cmd->gateway_mac); + cmd->tcp_tx_timeout_val = appType2Params->tcp_tx_timeout_val; + cmd->tcp_rx_timeout_val = appType2Params->tcp_rx_timeout_val; + + WMI_LOGD("%s: vdev_id %d gateway_mac %pM " + "rc4_key %.16s rc4_key_len %u " + "ip_id %x ip_device_ip %x ip_server_ip %x " + "tcp_src_port %u tcp_dst_port %u tcp_seq %u " + "tcp_ack_seq %u keepalive_init %u keepalive_min %u " + "keepalive_max %u keepalive_inc %u " + "tcp_tx_timeout_val %u tcp_rx_timeout_val %u", + __func__, cmd->vdev_id, appType2Params->gateway_mac.bytes, + cmd->rc4_key, cmd->rc4_key_len, + cmd->ip_id, cmd->ip_device_ip, cmd->ip_server_ip, + cmd->tcp_src_port, cmd->tcp_dst_port, cmd->tcp_seq, + cmd->tcp_ack_seq, cmd->keepalive_init, cmd->keepalive_min, + cmd->keepalive_max, cmd->keepalive_inc, + cmd->tcp_tx_timeout_val, cmd->tcp_rx_timeout_val); + + ret = wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_EXTWOW_SET_APP_TYPE2_PARAMS_CMDID); + if (ret) { + WMI_LOGE("%s: Failed to set APP TYPE2 PARAMS", __func__); + wmi_buf_free(buf); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; + +} + +/** + * send_set_auto_shutdown_timer_cmd_tlv() - sets auto shutdown timer in firmware + * @wmi_handle: wmi handle + * @timer_val: auto shutdown timer value + * + * Return: CDF status + */ +QDF_STATUS send_set_auto_shutdown_timer_cmd_tlv(wmi_unified_t wmi_handle, + uint32_t timer_val) +{ + QDF_STATUS status; + wmi_buf_t buf = NULL; + uint8_t *buf_ptr; + wmi_host_auto_shutdown_cfg_cmd_fixed_param *wmi_auto_sh_cmd; + int len = sizeof(wmi_host_auto_shutdown_cfg_cmd_fixed_param); + + WMI_LOGD("%s: Set WMI_HOST_AUTO_SHUTDOWN_CFG_CMDID:TIMER_VAL=%d", + __func__, timer_val); + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMI_LOGE("%s : wmi_buf_alloc failed", __func__); + return QDF_STATUS_E_NOMEM; + } + + buf_ptr = (uint8_t *) wmi_buf_data(buf); + wmi_auto_sh_cmd = + (wmi_host_auto_shutdown_cfg_cmd_fixed_param *) buf_ptr; + wmi_auto_sh_cmd->timer_value = timer_val; + + WMITLV_SET_HDR(&wmi_auto_sh_cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_host_auto_shutdown_cfg_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_host_auto_shutdown_cfg_cmd_fixed_param)); + + status = wmi_unified_cmd_send(wmi_handle, buf, + len, WMI_HOST_AUTO_SHUTDOWN_CFG_CMDID); + if (QDF_IS_STATUS_ERROR(status)) { + WMI_LOGE("%s: WMI_HOST_AUTO_SHUTDOWN_CFG_CMDID Err %d", + __func__, status); + wmi_buf_free(buf); + } + + return status; +} + +/** + * send_nan_req_cmd_tlv() - to send nan request to target + * @wmi_handle: wmi handle + * @nan_req: request data which will be non-null + * + * Return: CDF status + */ +QDF_STATUS send_nan_req_cmd_tlv(wmi_unified_t wmi_handle, + struct nan_req_params *nan_req) +{ + QDF_STATUS ret; + wmi_nan_cmd_param *cmd; + wmi_buf_t buf; + uint16_t len = sizeof(*cmd); + uint16_t nan_data_len, nan_data_len_aligned; + uint8_t *buf_ptr; + + /* + * <----- cmd ------------><-- WMI_TLV_HDR_SIZE --><--- data ----> + * +------------+----------+-----------------------+--------------+ + * | tlv_header | data_len | WMITLV_TAG_ARRAY_BYTE | nan_req_data | + * +------------+----------+-----------------------+--------------+ + */ + if (!nan_req) { + WMI_LOGE("%s:nan req is not valid", __func__); + return QDF_STATUS_E_FAILURE; + } + nan_data_len = nan_req->request_data_len; + nan_data_len_aligned = roundup(nan_req->request_data_len, + sizeof(uint32_t)); + len += WMI_TLV_HDR_SIZE + nan_data_len_aligned; + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMI_LOGE("%s:wmi_buf_alloc failed", __func__); + return QDF_STATUS_E_NOMEM; + } + buf_ptr = (uint8_t *) wmi_buf_data(buf); + cmd = (wmi_nan_cmd_param *) buf_ptr; + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_nan_cmd_param, + WMITLV_GET_STRUCT_TLVLEN(wmi_nan_cmd_param)); + cmd->data_len = nan_req->request_data_len; + WMI_LOGD("%s: The data len value is %u", + __func__, nan_req->request_data_len); + buf_ptr += sizeof(wmi_nan_cmd_param); + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE, nan_data_len_aligned); + buf_ptr += WMI_TLV_HDR_SIZE; + qdf_mem_copy(buf_ptr, nan_req->request_data, cmd->data_len); + + ret = wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_NAN_CMDID); + if (QDF_IS_STATUS_ERROR(ret)) { + WMI_LOGE("%s Failed to send set param command ret = %d", + __func__, ret); + wmi_buf_free(buf); + } + + return ret; +} + +/** + * send_process_dhcpserver_offload_cmd_tlv() - enable DHCP server offload + * @wmi_handle: wmi handle + * @pDhcpSrvOffloadInfo: DHCP server offload info + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +QDF_STATUS send_process_dhcpserver_offload_cmd_tlv(wmi_unified_t wmi_handle, + struct dhcp_offload_info_params *pDhcpSrvOffloadInfo) +{ + wmi_set_dhcp_server_offload_cmd_fixed_param *cmd; + wmi_buf_t buf; + QDF_STATUS status; + + buf = wmi_buf_alloc(wmi_handle, sizeof(*cmd)); + if (!buf) { + WMI_LOGE("Failed to allocate buffer to send " + "set_dhcp_server_offload cmd"); + return QDF_STATUS_E_NOMEM; + } + + cmd = (wmi_set_dhcp_server_offload_cmd_fixed_param *) wmi_buf_data(buf); + qdf_mem_zero(cmd, sizeof(*cmd)); + + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_set_dhcp_server_offload_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_set_dhcp_server_offload_cmd_fixed_param)); + cmd->vdev_id = pDhcpSrvOffloadInfo->vdev_id; + cmd->enable = pDhcpSrvOffloadInfo->dhcpSrvOffloadEnabled; + cmd->num_client = pDhcpSrvOffloadInfo->dhcpClientNum; + cmd->srv_ipv4 = pDhcpSrvOffloadInfo->dhcpSrvIP; + cmd->start_lsb = 0; + status = wmi_unified_cmd_send(wmi_handle, buf, + sizeof(*cmd), + WMI_SET_DHCP_SERVER_OFFLOAD_CMDID); + if (QDF_IS_STATUS_ERROR(status)) { + WMI_LOGE("Failed to send set_dhcp_server_offload cmd"); + wmi_buf_free(buf); + return QDF_STATUS_E_FAILURE; + } + WMI_LOGD("Set dhcp server offload to vdevId %d", + pDhcpSrvOffloadInfo->vdev_id); + + return status; +} + +/** + * send_set_led_flashing_cmd_tlv() - set led flashing in fw + * @wmi_handle: wmi handle + * @flashing: flashing request + * + * Return: CDF status + */ +QDF_STATUS send_set_led_flashing_cmd_tlv(wmi_unified_t wmi_handle, + struct flashing_req_params *flashing) +{ + wmi_set_led_flashing_cmd_fixed_param *cmd; + QDF_STATUS status; + wmi_buf_t buf; + uint8_t *buf_ptr; + int32_t len = sizeof(wmi_set_led_flashing_cmd_fixed_param); + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMI_LOGP(FL("wmi_buf_alloc failed")); + return QDF_STATUS_E_NOMEM; + } + buf_ptr = (uint8_t *) wmi_buf_data(buf); + cmd = (wmi_set_led_flashing_cmd_fixed_param *) buf_ptr; + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_set_led_flashing_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_set_led_flashing_cmd_fixed_param)); + cmd->pattern_id = flashing->pattern_id; + cmd->led_x0 = flashing->led_x0; + cmd->led_x1 = flashing->led_x1; + + status = wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_PDEV_SET_LED_FLASHING_CMDID); + if (QDF_IS_STATUS_ERROR(status)) { + WMI_LOGE("%s: wmi_unified_cmd_send WMI_PEER_SET_PARAM_CMD" + " returned Error %d", __func__, status); + wmi_buf_free(buf); + } + + return status; +} + +/** + * send_process_ch_avoid_update_cmd_tlv() - handles channel avoid update request + * @wmi_handle: wmi handle + * @ch_avoid_update_req: channel avoid update params + * + * Return: CDF status + */ +QDF_STATUS send_process_ch_avoid_update_cmd_tlv(wmi_unified_t wmi_handle) +{ + QDF_STATUS status; + wmi_buf_t buf = NULL; + uint8_t *buf_ptr; + wmi_chan_avoid_update_cmd_param *ch_avoid_update_fp; + int len = sizeof(wmi_chan_avoid_update_cmd_param); + + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMI_LOGE("%s : wmi_buf_alloc failed", __func__); + return QDF_STATUS_E_NOMEM; + } + + buf_ptr = (uint8_t *) wmi_buf_data(buf); + ch_avoid_update_fp = (wmi_chan_avoid_update_cmd_param *) buf_ptr; + WMITLV_SET_HDR(&ch_avoid_update_fp->tlv_header, + WMITLV_TAG_STRUC_wmi_chan_avoid_update_cmd_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_chan_avoid_update_cmd_param)); + + status = wmi_unified_cmd_send(wmi_handle, buf, + len, WMI_CHAN_AVOID_UPDATE_CMDID); + if (QDF_IS_STATUS_ERROR(status)) { + WMI_LOGE("wmi_unified_cmd_send" + " WMITLV_TABLE_WMI_CHAN_AVOID_UPDATE" + " returned Error %d", status); + wmi_buf_free(buf); + } + + return status; +} + +/** + * send_regdomain_info_to_fw_cmd_tlv() - send regdomain info to fw + * @wmi_handle: wmi handle + * @reg_dmn: reg domain + * @regdmn2G: 2G reg domain + * @regdmn5G: 5G reg domain + * @ctl2G: 2G test limit + * @ctl5G: 5G test limit + * + * Return: none + */ +QDF_STATUS send_regdomain_info_to_fw_cmd_tlv(wmi_unified_t wmi_handle, + uint32_t reg_dmn, uint16_t regdmn2G, + uint16_t regdmn5G, int8_t ctl2G, + int8_t ctl5G) +{ + wmi_buf_t buf; + wmi_pdev_set_regdomain_cmd_fixed_param *cmd; + int32_t len = sizeof(*cmd); + + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMI_LOGP("%s: wmi_buf_alloc failed", __func__); + return QDF_STATUS_E_NOMEM; + } + cmd = (wmi_pdev_set_regdomain_cmd_fixed_param *) wmi_buf_data(buf); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_pdev_set_regdomain_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_pdev_set_regdomain_cmd_fixed_param)); + cmd->reg_domain = reg_dmn; + cmd->reg_domain_2G = regdmn2G; + cmd->reg_domain_5G = regdmn5G; + cmd->conformance_test_limit_2G = ctl2G; + cmd->conformance_test_limit_5G = ctl5G; + + if (wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_PDEV_SET_REGDOMAIN_CMDID)) { + WMI_LOGP("%s: Failed to send pdev set regdomain command", + __func__); + wmi_buf_free(buf); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + + +/** + * send_set_tdls_offchan_mode_cmd_tlv() - set tdls off channel mode + * @wmi_handle: wmi handle + * @chan_switch_params: Pointer to tdls channel switch parameter structure + * + * This function sets tdls off channel mode + * + * Return: 0 on success; Negative errno otherwise + */ +QDF_STATUS send_set_tdls_offchan_mode_cmd_tlv(wmi_unified_t wmi_handle, + struct tdls_channel_switch_params *chan_switch_params) +{ + wmi_tdls_set_offchan_mode_cmd_fixed_param *cmd; + wmi_buf_t wmi_buf; + u_int16_t len = sizeof(wmi_tdls_set_offchan_mode_cmd_fixed_param); + + wmi_buf = wmi_buf_alloc(wmi_handle, len); + if (!wmi_buf) { + WMI_LOGE(FL("wmi_buf_alloc failed")); + return QDF_STATUS_E_FAILURE; + } + cmd = (wmi_tdls_set_offchan_mode_cmd_fixed_param *) + wmi_buf_data(wmi_buf); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_tdls_set_offchan_mode_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN( + wmi_tdls_set_offchan_mode_cmd_fixed_param)); + + WMI_CHAR_ARRAY_TO_MAC_ADDR(chan_switch_params->peer_mac_addr, + &cmd->peer_macaddr); + cmd->vdev_id = chan_switch_params->vdev_id; + cmd->offchan_mode = chan_switch_params->tdls_sw_mode; + cmd->is_peer_responder = chan_switch_params->is_responder; + cmd->offchan_num = chan_switch_params->tdls_off_ch; + cmd->offchan_bw_bitmap = chan_switch_params->tdls_off_ch_bw_offset; + cmd->offchan_oper_class = chan_switch_params->oper_class; + + WMI_LOGD(FL("Peer MAC Addr mac_addr31to0: 0x%x, mac_addr47to32: 0x%x"), + cmd->peer_macaddr.mac_addr31to0, + cmd->peer_macaddr.mac_addr47to32); + + WMI_LOGD(FL( + "vdev_id: %d, off channel mode: %d, off channel Num: %d, " + "off channel offset: 0x%x, is_peer_responder: %d, operating class: %d" + ), + cmd->vdev_id, + cmd->offchan_mode, + cmd->offchan_num, + cmd->offchan_bw_bitmap, + cmd->is_peer_responder, + cmd->offchan_oper_class); + + if (wmi_unified_cmd_send(wmi_handle, wmi_buf, len, + WMI_TDLS_SET_OFFCHAN_MODE_CMDID)) { + WMI_LOGP(FL("failed to send tdls off chan command")); + wmi_buf_free(wmi_buf); + return QDF_STATUS_E_FAILURE; + } + + + return QDF_STATUS_SUCCESS; +} + +/** + * send_update_fw_tdls_state_cmd_tlv() - send enable/disable tdls for a vdev + * @wmi_handle: wmi handle + * @pwmaTdlsparams: TDLS params + * + * Return: 0 for sucess or error code + */ +QDF_STATUS send_update_fw_tdls_state_cmd_tlv(wmi_unified_t wmi_handle, + void *tdls_param, uint8_t tdls_state) +{ + wmi_tdls_set_state_cmd_fixed_param *cmd; + wmi_buf_t wmi_buf; + + struct wmi_tdls_params *wmi_tdls = (struct wmi_tdls_params *) tdls_param; + uint16_t len = sizeof(wmi_tdls_set_state_cmd_fixed_param); + + wmi_buf = wmi_buf_alloc(wmi_handle, len); + if (!wmi_buf) { + WMI_LOGE("%s: wmai_buf_alloc failed", __func__); + return QDF_STATUS_E_FAILURE; + } + cmd = (wmi_tdls_set_state_cmd_fixed_param *) wmi_buf_data(wmi_buf); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_tdls_set_state_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_tdls_set_state_cmd_fixed_param)); + cmd->vdev_id = wmi_tdls->vdev_id; + cmd->state = tdls_state; + cmd->notification_interval_ms = wmi_tdls->notification_interval_ms; + cmd->tx_discovery_threshold = wmi_tdls->tx_discovery_threshold; + cmd->tx_teardown_threshold = wmi_tdls->tx_teardown_threshold; + cmd->rssi_teardown_threshold = wmi_tdls->rssi_teardown_threshold; + cmd->rssi_delta = wmi_tdls->rssi_delta; + cmd->tdls_options = wmi_tdls->tdls_options; + cmd->tdls_peer_traffic_ind_window = wmi_tdls->peer_traffic_ind_window; + cmd->tdls_peer_traffic_response_timeout_ms = + wmi_tdls->peer_traffic_response_timeout; + cmd->tdls_puapsd_mask = wmi_tdls->puapsd_mask; + cmd->tdls_puapsd_inactivity_time_ms = wmi_tdls->puapsd_inactivity_time; + cmd->tdls_puapsd_rx_frame_threshold = + wmi_tdls->puapsd_rx_frame_threshold; + cmd->teardown_notification_ms = + wmi_tdls->teardown_notification_ms; + cmd->tdls_peer_kickout_threshold = + wmi_tdls->tdls_peer_kickout_threshold; + + WMI_LOGD("%s: tdls_state: %d, state: %d, " + "notification_interval_ms: %d, " + "tx_discovery_threshold: %d, " + "tx_teardown_threshold: %d, " + "rssi_teardown_threshold: %d, " + "rssi_delta: %d, " + "tdls_options: 0x%x, " + "tdls_peer_traffic_ind_window: %d, " + "tdls_peer_traffic_response_timeout: %d, " + "tdls_puapsd_mask: 0x%x, " + "tdls_puapsd_inactivity_time: %d, " + "tdls_puapsd_rx_frame_threshold: %d, " + "teardown_notification_ms: %d, " + "tdls_peer_kickout_threshold: %d", + __func__, tdls_state, cmd->state, + cmd->notification_interval_ms, + cmd->tx_discovery_threshold, + cmd->tx_teardown_threshold, + cmd->rssi_teardown_threshold, + cmd->rssi_delta, + cmd->tdls_options, + cmd->tdls_peer_traffic_ind_window, + cmd->tdls_peer_traffic_response_timeout_ms, + cmd->tdls_puapsd_mask, + cmd->tdls_puapsd_inactivity_time_ms, + cmd->tdls_puapsd_rx_frame_threshold, + cmd->teardown_notification_ms, + cmd->tdls_peer_kickout_threshold); + + if (wmi_unified_cmd_send(wmi_handle, wmi_buf, len, + WMI_TDLS_SET_STATE_CMDID)) { + WMI_LOGP("%s: failed to send tdls set state command", __func__); + wmi_buf_free(wmi_buf); + return QDF_STATUS_E_FAILURE; + } + WMI_LOGD("%s: vdev_id %d", __func__, wmi_tdls->vdev_id); + + return QDF_STATUS_SUCCESS; +} + +/** + * send_update_tdls_peer_state_cmd_tlv() - update TDLS peer state + * @wmi_handle: wmi handle + * @peerStateParams: TDLS peer state params + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +QDF_STATUS send_update_tdls_peer_state_cmd_tlv(wmi_unified_t wmi_handle, + struct tdls_peer_state_params *peerStateParams, + uint32_t *ch_mhz) +{ + wmi_tdls_peer_update_cmd_fixed_param *cmd; + wmi_tdls_peer_capabilities *peer_cap; + wmi_channel *chan_info; + wmi_buf_t wmi_buf; + uint8_t *buf_ptr; + uint32_t i; + int32_t len = sizeof(wmi_tdls_peer_update_cmd_fixed_param) + + sizeof(wmi_tdls_peer_capabilities); + + + len += WMI_TLV_HDR_SIZE + + sizeof(wmi_channel) * peerStateParams->peerCap.peerChanLen; + + wmi_buf = wmi_buf_alloc(wmi_handle, len); + if (!wmi_buf) { + WMI_LOGE("%s: wmi_buf_alloc failed", __func__); + return QDF_STATUS_E_FAILURE; + } + + buf_ptr = (uint8_t *) wmi_buf_data(wmi_buf); + cmd = (wmi_tdls_peer_update_cmd_fixed_param *) buf_ptr; + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_tdls_peer_update_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_tdls_peer_update_cmd_fixed_param)); + + cmd->vdev_id = peerStateParams->vdevId; + WMI_CHAR_ARRAY_TO_MAC_ADDR(peerStateParams->peerMacAddr, + &cmd->peer_macaddr); + + + cmd->peer_state = peerStateParams->peerState; + + WMI_LOGD("%s: vdev_id: %d, peerStateParams->peerMacAddr: %pM, " + "peer_macaddr.mac_addr31to0: 0x%x, " + "peer_macaddr.mac_addr47to32: 0x%x, peer_state: %d", + __func__, cmd->vdev_id, peerStateParams->peerMacAddr, + cmd->peer_macaddr.mac_addr31to0, + cmd->peer_macaddr.mac_addr47to32, cmd->peer_state); + + buf_ptr += sizeof(wmi_tdls_peer_update_cmd_fixed_param); + peer_cap = (wmi_tdls_peer_capabilities *) buf_ptr; + WMITLV_SET_HDR(&peer_cap->tlv_header, + WMITLV_TAG_STRUC_wmi_tdls_peer_capabilities, + WMITLV_GET_STRUCT_TLVLEN(wmi_tdls_peer_capabilities)); + + if ((peerStateParams->peerCap.peerUapsdQueue & 0x08) >> 3) + WMI_SET_TDLS_PEER_VO_UAPSD(peer_cap); + if ((peerStateParams->peerCap.peerUapsdQueue & 0x04) >> 2) + WMI_SET_TDLS_PEER_VI_UAPSD(peer_cap); + if ((peerStateParams->peerCap.peerUapsdQueue & 0x02) >> 1) + WMI_SET_TDLS_PEER_BK_UAPSD(peer_cap); + if (peerStateParams->peerCap.peerUapsdQueue & 0x01) + WMI_SET_TDLS_PEER_BE_UAPSD(peer_cap); + + /* Ack and More Data Ack are sent as 0, so no need to set + * but fill SP + */ + WMI_SET_TDLS_PEER_SP_UAPSD(peer_cap, + peerStateParams->peerCap.peerMaxSp); + + peer_cap->buff_sta_support = + peerStateParams->peerCap.peerBuffStaSupport; + peer_cap->off_chan_support = + peerStateParams->peerCap.peerOffChanSupport; + peer_cap->peer_curr_operclass = + peerStateParams->peerCap.peerCurrOperClass; + /* self curr operclass is not being used and so pass op class for + * preferred off chan in it. + */ + peer_cap->self_curr_operclass = + peerStateParams->peerCap.opClassForPrefOffChan; + peer_cap->peer_chan_len = peerStateParams->peerCap.peerChanLen; + peer_cap->peer_operclass_len = + peerStateParams->peerCap.peerOperClassLen; + + WMI_LOGD("%s: peer_operclass_len: %d", + __func__, peer_cap->peer_operclass_len); + for (i = 0; i < WMI_TDLS_MAX_SUPP_OPER_CLASSES; i++) { + peer_cap->peer_operclass[i] = + peerStateParams->peerCap.peerOperClass[i]; + WMI_LOGD("%s: peer_operclass[%d]: %d", + __func__, i, peer_cap->peer_operclass[i]); + } + + peer_cap->is_peer_responder = peerStateParams->peerCap.isPeerResponder; + peer_cap->pref_offchan_num = peerStateParams->peerCap.prefOffChanNum; + peer_cap->pref_offchan_bw = + peerStateParams->peerCap.prefOffChanBandwidth; + + WMI_LOGD + ("%s: peer_qos: 0x%x, buff_sta_support: %d, off_chan_support: %d, " + "peer_curr_operclass: %d, self_curr_operclass: %d, peer_chan_len: " + "%d, peer_operclass_len: %d, is_peer_responder: %d, pref_offchan_num:" + " %d, pref_offchan_bw: %d", + __func__, peer_cap->peer_qos, peer_cap->buff_sta_support, + peer_cap->off_chan_support, peer_cap->peer_curr_operclass, + peer_cap->self_curr_operclass, peer_cap->peer_chan_len, + peer_cap->peer_operclass_len, peer_cap->is_peer_responder, + peer_cap->pref_offchan_num, peer_cap->pref_offchan_bw); + + /* next fill variable size array of peer chan info */ + buf_ptr += sizeof(wmi_tdls_peer_capabilities); + WMITLV_SET_HDR(buf_ptr, + WMITLV_TAG_ARRAY_STRUC, + sizeof(wmi_channel) * + peerStateParams->peerCap.peerChanLen); + chan_info = (wmi_channel *) (buf_ptr + WMI_TLV_HDR_SIZE); + + for (i = 0; i < peerStateParams->peerCap.peerChanLen; ++i) { + WMITLV_SET_HDR(&chan_info->tlv_header, + WMITLV_TAG_STRUC_wmi_channel, + WMITLV_GET_STRUCT_TLVLEN(wmi_channel)); + chan_info->mhz = ch_mhz[i]; + chan_info->band_center_freq1 = chan_info->mhz; + chan_info->band_center_freq2 = 0; + + WMI_LOGD("%s: chan[%d] = %u", __func__, i, chan_info->mhz); + + if (peerStateParams->peerCap.peerChan[i].dfsSet) { + WMI_SET_CHANNEL_FLAG(chan_info, WMI_CHAN_FLAG_PASSIVE); + WMI_LOGI("chan[%d] DFS[%d]\n", + peerStateParams->peerCap.peerChan[i].chanId, + peerStateParams->peerCap.peerChan[i].dfsSet); + } + + if (chan_info->mhz < WMI_2_4_GHZ_MAX_FREQ) + WMI_SET_CHANNEL_MODE(chan_info, MODE_11G); + else + WMI_SET_CHANNEL_MODE(chan_info, MODE_11A); + + WMI_SET_CHANNEL_MAX_TX_POWER(chan_info, + peerStateParams->peerCap. + peerChan[i].pwr); + + WMI_SET_CHANNEL_REG_POWER(chan_info, + peerStateParams->peerCap.peerChan[i]. + pwr); + WMI_LOGD("Channel TX power[%d] = %u: %d", i, chan_info->mhz, + peerStateParams->peerCap.peerChan[i].pwr); + + chan_info++; + } + + if (wmi_unified_cmd_send(wmi_handle, wmi_buf, len, + WMI_TDLS_PEER_UPDATE_CMDID)) { + WMI_LOGE("%s: failed to send tdls peer update state command", + __func__); + wmi_buf_free(wmi_buf); + return QDF_STATUS_E_FAILURE; + } + + + return QDF_STATUS_SUCCESS; +} + +/* + * send_process_fw_mem_dump_cmd_tlv() - Function to request fw memory dump from + * firmware + * @wmi_handle: Pointer to wmi handle + * @mem_dump_req: Pointer for mem_dump_req + * + * This function sends memory dump request to firmware + * + * Return: QDF_STATUS_SUCCESS for success otherwise failure + * + */ +QDF_STATUS send_process_fw_mem_dump_cmd_tlv(wmi_unified_t wmi_handle, + struct fw_dump_req_param *mem_dump_req) +{ + wmi_get_fw_mem_dump_fixed_param *cmd; + wmi_fw_mem_dump *dump_params; + struct wmi_fw_dump_seg_req *seg_req; + int32_t len; + wmi_buf_t buf; + u_int8_t *buf_ptr; + int ret, loop; + + /* + * len = sizeof(fixed param) that includes tlv header + + * tlv header for array of struc + + * sizeof (each struct) + */ + len = sizeof(*cmd) + WMI_TLV_HDR_SIZE; + len += mem_dump_req->num_seg * sizeof(wmi_fw_mem_dump); + buf = wmi_buf_alloc(wmi_handle, len); + + if (!buf) { + WMI_LOGE(FL("Failed allocate wmi buffer")); + return QDF_STATUS_E_NOMEM; + } + + buf_ptr = (u_int8_t *) wmi_buf_data(buf); + qdf_mem_zero(buf_ptr, len); + cmd = (wmi_get_fw_mem_dump_fixed_param *) buf_ptr; + + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_get_fw_mem_dump_fixed_param, + WMITLV_GET_STRUCT_TLVLEN(wmi_get_fw_mem_dump_fixed_param)); + + cmd->request_id = mem_dump_req->request_id; + cmd->num_fw_mem_dump_segs = mem_dump_req->num_seg; + + /* TLV indicating array of structures to follow */ + buf_ptr += sizeof(wmi_get_fw_mem_dump_fixed_param); + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, + sizeof(wmi_fw_mem_dump) * + cmd->num_fw_mem_dump_segs); + + buf_ptr += WMI_TLV_HDR_SIZE; + dump_params = (wmi_fw_mem_dump *) buf_ptr; + + WMI_LOGI(FL("request_id:%d num_seg:%d"), + mem_dump_req->request_id, mem_dump_req->num_seg); + for (loop = 0; loop < cmd->num_fw_mem_dump_segs; loop++) { + seg_req = (struct wmi_fw_dump_seg_req *) + ((uint8_t *)(mem_dump_req->segment) + + loop * sizeof(*seg_req)); + WMITLV_SET_HDR(&dump_params->tlv_header, + WMITLV_TAG_STRUC_wmi_fw_mem_dump_params, + WMITLV_GET_STRUCT_TLVLEN(wmi_fw_mem_dump)); + dump_params->seg_id = seg_req->seg_id; + dump_params->seg_start_addr_lo = seg_req->seg_start_addr_lo; + dump_params->seg_start_addr_hi = seg_req->seg_start_addr_hi; + dump_params->seg_length = seg_req->seg_length; + dump_params->dest_addr_lo = seg_req->dst_addr_lo; + dump_params->dest_addr_hi = seg_req->dst_addr_hi; + WMI_LOGI(FL("seg_number:%d"), loop); + WMI_LOGI(FL("seg_id:%d start_addr_lo:0x%x start_addr_hi:0x%x"), + dump_params->seg_id, dump_params->seg_start_addr_lo, + dump_params->seg_start_addr_hi); + WMI_LOGI(FL("seg_length:%d dst_addr_lo:0x%x dst_addr_hi:0x%x"), + dump_params->seg_length, dump_params->dest_addr_lo, + dump_params->dest_addr_hi); + dump_params++; + } + + ret = wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_GET_FW_MEM_DUMP_CMDID); + if (ret) { + WMI_LOGE(FL("Failed to send get firmware mem dump request")); + wmi_buf_free(buf); + return QDF_STATUS_E_FAILURE; + } + + WMI_LOGI(FL("Get firmware mem dump request sent successfully")); + return QDF_STATUS_SUCCESS; +} + +/* + * send_process_set_ie_info_cmd_tlv() - Function to send IE info to firmware + * @wmi_handle: Pointer to WMi handle + * @ie_data: Pointer for ie data + * + * This function sends IE information to firmware + * + * Return: QDF_STATUS_SUCCESS for success otherwise failure + * + */ +QDF_STATUS send_process_set_ie_info_cmd_tlv(wmi_unified_t wmi_handle, + struct vdev_ie_info_param *ie_info) +{ + wmi_vdev_set_ie_cmd_fixed_param *cmd; + wmi_buf_t buf; + uint8_t *buf_ptr; + uint32_t len, ie_len_aligned; + QDF_STATUS ret; + + + ie_len_aligned = roundup(ie_info->length, sizeof(uint32_t)); + /* Allocate memory for the WMI command */ + len = sizeof(*cmd) + WMI_TLV_HDR_SIZE + ie_len_aligned; + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMI_LOGE(FL("wmi_buf_alloc failed")); + return QDF_STATUS_E_NOMEM; + } + + buf_ptr = wmi_buf_data(buf); + qdf_mem_zero(buf_ptr, len); + + /* Populate the WMI command */ + cmd = (wmi_vdev_set_ie_cmd_fixed_param *)buf_ptr; + + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_vdev_set_ie_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN( + wmi_vdev_set_ie_cmd_fixed_param)); + cmd->vdev_id = ie_info->vdev_id; + cmd->ie_id = ie_info->ie_id; + cmd->ie_len = ie_info->length; + cmd->band = ie_info->band; + + WMI_LOGD(FL("IE:%d of size:%d sent for vdev:%d"), ie_info->ie_id, + ie_info->length, ie_info->vdev_id); + + buf_ptr += sizeof(*cmd); + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE, ie_len_aligned); + buf_ptr += WMI_TLV_HDR_SIZE; + + qdf_mem_copy(buf_ptr, ie_info->data, cmd->ie_len); + + ret = wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_VDEV_SET_IE_CMDID); + if (QDF_IS_STATUS_ERROR(ret)) { + WMI_LOGE(FL("Failed to send set IE command ret = %d"), ret); + wmi_buf_free(buf); + } + + return ret; +} + +static +void wmi_copy_resource_config(wmi_resource_config *resource_cfg, + target_resource_config *tgt_res_cfg) +{ + resource_cfg->num_vdevs = tgt_res_cfg->num_vdevs; + resource_cfg->num_peers = tgt_res_cfg->num_peers; + resource_cfg->num_offload_peers = tgt_res_cfg->num_offload_peers; + resource_cfg->num_offload_reorder_buffs = + tgt_res_cfg->num_offload_reorder_buffs; + resource_cfg->num_peer_keys = tgt_res_cfg->num_peer_keys; + resource_cfg->num_tids = tgt_res_cfg->num_tids; + resource_cfg->ast_skid_limit = tgt_res_cfg->ast_skid_limit; + resource_cfg->tx_chain_mask = tgt_res_cfg->tx_chain_mask; + resource_cfg->rx_chain_mask = tgt_res_cfg->rx_chain_mask; + resource_cfg->rx_timeout_pri[0] = tgt_res_cfg->rx_timeout_pri[0]; + resource_cfg->rx_timeout_pri[1] = tgt_res_cfg->rx_timeout_pri[1]; + resource_cfg->rx_timeout_pri[2] = tgt_res_cfg->rx_timeout_pri[2]; + resource_cfg->rx_timeout_pri[3] = tgt_res_cfg->rx_timeout_pri[3]; + resource_cfg->rx_decap_mode = tgt_res_cfg->rx_decap_mode; + resource_cfg->scan_max_pending_req = + tgt_res_cfg->scan_max_pending_req; + resource_cfg->bmiss_offload_max_vdev = + tgt_res_cfg->bmiss_offload_max_vdev; + resource_cfg->roam_offload_max_vdev = + tgt_res_cfg->roam_offload_max_vdev; + resource_cfg->roam_offload_max_ap_profiles = + tgt_res_cfg->roam_offload_max_ap_profiles; + resource_cfg->num_mcast_groups = tgt_res_cfg->num_mcast_groups; + resource_cfg->num_mcast_table_elems = + tgt_res_cfg->num_mcast_table_elems; + resource_cfg->mcast2ucast_mode = tgt_res_cfg->mcast2ucast_mode; + resource_cfg->tx_dbg_log_size = tgt_res_cfg->tx_dbg_log_size; + resource_cfg->num_wds_entries = tgt_res_cfg->num_wds_entries; + resource_cfg->dma_burst_size = tgt_res_cfg->dma_burst_size; + resource_cfg->mac_aggr_delim = tgt_res_cfg->mac_aggr_delim; + resource_cfg->rx_skip_defrag_timeout_dup_detection_check = + tgt_res_cfg->rx_skip_defrag_timeout_dup_detection_check; + resource_cfg->vow_config = tgt_res_cfg->vow_config; + resource_cfg->gtk_offload_max_vdev = tgt_res_cfg->gtk_offload_max_vdev; + resource_cfg->num_msdu_desc = tgt_res_cfg->num_msdu_desc; + resource_cfg->max_frag_entries = tgt_res_cfg->max_frag_entries; + resource_cfg->num_tdls_vdevs = tgt_res_cfg->num_tdls_vdevs; + resource_cfg->num_tdls_conn_table_entries = + tgt_res_cfg->num_tdls_conn_table_entries; + resource_cfg->beacon_tx_offload_max_vdev = + tgt_res_cfg->beacon_tx_offload_max_vdev; + resource_cfg->num_multicast_filter_entries = + tgt_res_cfg->num_multicast_filter_entries; + resource_cfg->num_wow_filters = + tgt_res_cfg->num_wow_filters; + resource_cfg->num_keep_alive_pattern = + tgt_res_cfg->num_keep_alive_pattern; + resource_cfg->keep_alive_pattern_size = + tgt_res_cfg->keep_alive_pattern_size; + resource_cfg->max_tdls_concurrent_sleep_sta = + tgt_res_cfg->max_tdls_concurrent_sleep_sta; + resource_cfg->max_tdls_concurrent_buffer_sta = + tgt_res_cfg->max_tdls_concurrent_buffer_sta; + resource_cfg->wmi_send_separate = + tgt_res_cfg->wmi_send_separate; + resource_cfg->num_ocb_vdevs = + tgt_res_cfg->num_ocb_vdevs; + resource_cfg->num_ocb_channels = + tgt_res_cfg->num_ocb_channels; + resource_cfg->num_ocb_schedules = + tgt_res_cfg->num_ocb_schedules; + +} +#ifdef CONFIG_MCL +/** + * send_init_cmd_tlv() - wmi init command + * @wmi_handle: pointer to wmi handle + * @res_cfg: resource config + * @num_mem_chunks: no of mem chunck + * @mem_chunk: pointer to mem chunck structure + * + * This function sends IE information to firmware + * + * Return: QDF_STATUS_SUCCESS for success otherwise failure + * + */ +QDF_STATUS send_init_cmd_tlv(wmi_unified_t wmi_handle, + wmi_resource_config *tgt_res_cfg, + uint8_t num_mem_chunks, struct wmi_host_mem_chunk *mem_chunks, + bool action) +{ + wmi_buf_t buf; + wmi_init_cmd_fixed_param *cmd; + wmi_abi_version my_vers; + int num_whitelist; + uint8_t *buf_ptr; + wmi_resource_config *resource_cfg; + wlan_host_memory_chunk *host_mem_chunks; + uint32_t mem_chunk_len = 0; + uint16_t idx; + int len; + int ret; + + len = sizeof(*cmd) + sizeof(wmi_resource_config) + WMI_TLV_HDR_SIZE; + mem_chunk_len = (sizeof(wlan_host_memory_chunk) * MAX_MEM_CHUNKS); + buf = wmi_buf_alloc(wmi_handle, len + mem_chunk_len); + if (!buf) { + WMI_LOGD("%s: wmi_buf_alloc failed\n", __func__); + return QDF_STATUS_E_FAILURE; + } + + buf_ptr = (uint8_t *) wmi_buf_data(buf); + cmd = (wmi_init_cmd_fixed_param *) buf_ptr; + resource_cfg = (wmi_resource_config *) (buf_ptr + sizeof(*cmd)); + + host_mem_chunks = (wlan_host_memory_chunk *) + (buf_ptr + sizeof(*cmd) + sizeof(wmi_resource_config) + + WMI_TLV_HDR_SIZE); + + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_init_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN(wmi_init_cmd_fixed_param)); + + qdf_mem_copy(resource_cfg, tgt_res_cfg, sizeof(wmi_resource_config)); + WMITLV_SET_HDR(&resource_cfg->tlv_header, + WMITLV_TAG_STRUC_wmi_resource_config, + WMITLV_GET_STRUCT_TLVLEN(wmi_resource_config)); + + for (idx = 0; idx < num_mem_chunks; ++idx) { + WMITLV_SET_HDR(&(host_mem_chunks[idx].tlv_header), + WMITLV_TAG_STRUC_wlan_host_memory_chunk, + WMITLV_GET_STRUCT_TLVLEN + (wlan_host_memory_chunk)); + host_mem_chunks[idx].ptr = mem_chunks[idx].paddr; + host_mem_chunks[idx].size = mem_chunks[idx].len; + host_mem_chunks[idx].req_id = mem_chunks[idx].req_id; + WMI_LOGD("chunk %d len %d requested ,ptr 0x%x ", + idx, host_mem_chunks[idx].size, + host_mem_chunks[idx].ptr); + } + cmd->num_host_mem_chunks = num_mem_chunks; + len += (num_mem_chunks * sizeof(wlan_host_memory_chunk)); + WMITLV_SET_HDR((buf_ptr + sizeof(*cmd) + sizeof(wmi_resource_config)), + WMITLV_TAG_ARRAY_STRUC, + (sizeof(wlan_host_memory_chunk) * + num_mem_chunks)); + + num_whitelist = sizeof(version_whitelist) / + sizeof(wmi_whitelist_version_info); + my_vers.abi_version_0 = WMI_ABI_VERSION_0; + my_vers.abi_version_1 = WMI_ABI_VERSION_1; + my_vers.abi_version_ns_0 = WMI_ABI_VERSION_NS_0; + my_vers.abi_version_ns_1 = WMI_ABI_VERSION_NS_1; + my_vers.abi_version_ns_2 = WMI_ABI_VERSION_NS_2; + my_vers.abi_version_ns_3 = WMI_ABI_VERSION_NS_3; +#ifdef CONFIG_MCL + /* This needs to be enabled for WIN Lithium after removing dependency + * on wmi_unified.h from priv.h for using wmi_abi_version type */ + wmi_cmp_and_set_abi_version(num_whitelist, version_whitelist, + &my_vers, + &wmi_handle->fw_abi_version, + &cmd->host_abi_vers); +#endif + WMI_LOGD("%s: INIT_CMD version: %d, %d, 0x%x, 0x%x, 0x%x, 0x%x", + __func__, WMI_VER_GET_MAJOR(cmd->host_abi_vers.abi_version_0), + WMI_VER_GET_MINOR(cmd->host_abi_vers.abi_version_0), + cmd->host_abi_vers.abi_version_ns_0, + cmd->host_abi_vers.abi_version_ns_1, + cmd->host_abi_vers.abi_version_ns_2, + cmd->host_abi_vers.abi_version_ns_3); +#ifdef CONFIG_MCL + /* Save version sent from host - + * Will be used to check ready event + */ + qdf_mem_copy(&wmi_handle->final_abi_vers, &cmd->host_abi_vers, + sizeof(wmi_abi_version)); +#endif + if (action) { + ret = wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_INIT_CMDID); + if (ret) { + WMI_LOGE(FL("Failed to send set WMI INIT command ret = %d"), ret); + wmi_buf_free(buf); + return QDF_STATUS_E_FAILURE; + } + } else { + wmi_handle->saved_wmi_init_cmd.buf = buf; + wmi_handle->saved_wmi_init_cmd.buf_len = len; + } + + return QDF_STATUS_SUCCESS; + +} +#endif +/** + * send_saved_init_cmd_tlv() - wmi init command + * @wmi_handle: pointer to wmi handle + * + * This function sends IE information to firmware + * + * Return: QDF_STATUS_SUCCESS for success otherwise failure + * + */ +QDF_STATUS send_saved_init_cmd_tlv(wmi_unified_t wmi_handle) +{ + int status; + + if (!wmi_handle->saved_wmi_init_cmd.buf || + !wmi_handle->saved_wmi_init_cmd.buf_len) { + WMI_LOGP("Service ready ext event w/o WMI_SERVICE_EXT_MSG!"); + return QDF_STATUS_E_FAILURE; + } + status = wmi_unified_cmd_send(wmi_handle, + wmi_handle->saved_wmi_init_cmd.buf, + wmi_handle->saved_wmi_init_cmd.buf_len, + WMI_INIT_CMDID); + if (status) { + WMI_LOGE(FL("Failed to send set WMI INIT command ret = %d"), status); + wmi_buf_free(wmi_handle->saved_wmi_init_cmd.buf); + return QDF_STATUS_E_FAILURE; + } + wmi_handle->saved_wmi_init_cmd.buf = NULL; + wmi_handle->saved_wmi_init_cmd.buf_len = 0; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS save_fw_version_cmd_tlv(wmi_unified_t wmi_handle, void *evt_buf) +{ + WMI_SERVICE_READY_EVENTID_param_tlvs *param_buf; + wmi_service_ready_event_fixed_param *ev; + + + param_buf = (WMI_SERVICE_READY_EVENTID_param_tlvs *) evt_buf; + + ev = (wmi_service_ready_event_fixed_param *) param_buf->fixed_param; + if (!ev) + return QDF_STATUS_E_FAILURE; + +#ifdef CONFIG_MCL + /* TODO:This needs to be enabled for WIN Lithium after removing dependen + * on wmi_unified.h from priv.h for using wmi_abi_version type */ + /*Save fw version from service ready message */ + /*This will be used while sending INIT message */ + qdf_mem_copy(&wmi_handle->fw_abi_version, &ev->fw_abi_vers, + sizeof(wmi_handle->fw_abi_version)); +#endif + return QDF_STATUS_SUCCESS; +} + +/** + * wmi_unified_save_fw_version_cmd() - save fw version + * @wmi_handle: pointer to wmi handle + * @res_cfg: resource config + * @num_mem_chunks: no of mem chunck + * @mem_chunk: pointer to mem chunck structure + * + * This function sends IE information to firmware + * + * Return: QDF_STATUS_SUCCESS for success otherwise failure + * + */ +QDF_STATUS check_and_update_fw_version_cmd_tlv(wmi_unified_t wmi_handle, + void *evt_buf) +{ + WMI_READY_EVENTID_param_tlvs *param_buf = NULL; + wmi_ready_event_fixed_param *ev = NULL; + + param_buf = (WMI_READY_EVENTID_param_tlvs *) evt_buf; + ev = param_buf->fixed_param; +#ifdef CONFIG_MCL + /* TODO:This needs to be enabled for WIN Lithium after removing dependen + * on wmi_unified.h from priv.h for using wmi_abi_version type */ + if (!wmi_versions_are_compatible(&wmi_handle->final_abi_vers, + &ev->fw_abi_vers)) { + /* + * Error: Our host version and the given firmware version + * are incompatible. + **/ + WMI_LOGD("%s: Error: Incompatible WMI version." + "Host: %d,%d,0x%x 0x%x 0x%x 0x%x, FW: %d,%d,0x%x 0x%x 0x%x 0x%x\n", + __func__, + WMI_VER_GET_MAJOR(wmi_handle->final_abi_vers. + abi_version_0), + WMI_VER_GET_MINOR(wmi_handle->final_abi_vers. + abi_version_0), + wmi_handle->final_abi_vers.abi_version_ns_0, + wmi_handle->final_abi_vers.abi_version_ns_1, + wmi_handle->final_abi_vers.abi_version_ns_2, + wmi_handle->final_abi_vers.abi_version_ns_3, + WMI_VER_GET_MAJOR(ev->fw_abi_vers.abi_version_0), + WMI_VER_GET_MINOR(ev->fw_abi_vers.abi_version_0), + ev->fw_abi_vers.abi_version_ns_0, + ev->fw_abi_vers.abi_version_ns_1, + ev->fw_abi_vers.abi_version_ns_2, + ev->fw_abi_vers.abi_version_ns_3); + + return QDF_STATUS_E_FAILURE; + } + qdf_mem_copy(&wmi_handle->final_abi_vers, &ev->fw_abi_vers, + sizeof(wmi_abi_version)); + qdf_mem_copy(&wmi_handle->fw_abi_version, &ev->fw_abi_vers, + sizeof(wmi_abi_version)); +#endif + + return QDF_STATUS_SUCCESS; +} + +/** + * send_set_base_macaddr_indicate_cmd_tlv() - set base mac address in fw + * @wmi_handle: wmi handle + * @custom_addr: base mac address + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +QDF_STATUS send_set_base_macaddr_indicate_cmd_tlv(wmi_unified_t wmi_handle, + uint8_t *custom_addr) +{ + wmi_pdev_set_base_macaddr_cmd_fixed_param *cmd; + wmi_buf_t buf; + int err; + + buf = wmi_buf_alloc(wmi_handle, sizeof(*cmd)); + if (!buf) { + WMI_LOGE("Failed to allocate buffer to send base macaddr cmd"); + return QDF_STATUS_E_NOMEM; + } + + cmd = (wmi_pdev_set_base_macaddr_cmd_fixed_param *) wmi_buf_data(buf); + qdf_mem_zero(cmd, sizeof(*cmd)); + + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_pdev_set_base_macaddr_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_pdev_set_base_macaddr_cmd_fixed_param)); + WMI_CHAR_ARRAY_TO_MAC_ADDR(custom_addr, &cmd->base_macaddr); + cmd->pdev_id = WMI_PDEV_ID_SOC; + err = wmi_unified_cmd_send(wmi_handle, buf, + sizeof(*cmd), + WMI_PDEV_SET_BASE_MACADDR_CMDID); + if (err) { + WMI_LOGE("Failed to send set_base_macaddr cmd"); + wmi_buf_free(buf); + return QDF_STATUS_E_FAILURE; + } + + return 0; +} + +/** + * send_log_supported_evt_cmd_tlv() - Enable/Disable FW diag/log events + * @handle: wmi handle + * @event: Event received from FW + * @len: Length of the event + * + * Enables the low frequency events and disables the high frequency + * events. Bit 17 indicates if the event if low/high frequency. + * 1 - high frequency, 0 - low frequency + * + * Return: 0 on successfully enabling/disabling the events + */ +QDF_STATUS send_log_supported_evt_cmd_tlv(wmi_unified_t wmi_handle, + uint8_t *event, + uint32_t len) +{ + uint32_t num_of_diag_events_logs; + wmi_diag_event_log_config_fixed_param *cmd; + wmi_buf_t buf; + uint8_t *buf_ptr; + uint32_t *cmd_args, *evt_args; + uint32_t buf_len, i; + + WMI_DIAG_EVENT_LOG_SUPPORTED_EVENTID_param_tlvs *param_buf; + wmi_diag_event_log_supported_event_fixed_params *wmi_event; + + WMI_LOGI("Received WMI_DIAG_EVENT_LOG_SUPPORTED_EVENTID"); + + param_buf = (WMI_DIAG_EVENT_LOG_SUPPORTED_EVENTID_param_tlvs *) event; + if (!param_buf) { + WMI_LOGE("Invalid log supported event buffer"); + return QDF_STATUS_E_INVAL; + } + wmi_event = param_buf->fixed_param; + num_of_diag_events_logs = wmi_event->num_of_diag_events_logs; + evt_args = param_buf->diag_events_logs_list; + if (!evt_args) { + WMI_LOGE("%s: Event list is empty, num_of_diag_events_logs=%d", + __func__, num_of_diag_events_logs); + return QDF_STATUS_E_INVAL; + } + + WMI_LOGD("%s: num_of_diag_events_logs=%d", + __func__, num_of_diag_events_logs); + + /* Free any previous allocation */ + if (wmi_handle->events_logs_list) + qdf_mem_free(wmi_handle->events_logs_list); + + /* Store the event list for run time enable/disable */ + wmi_handle->events_logs_list = qdf_mem_malloc(num_of_diag_events_logs * + sizeof(uint32_t)); + if (!wmi_handle->events_logs_list) { + WMI_LOGE("%s: event log list memory allocation failed", + __func__); + return QDF_STATUS_E_NOMEM; + } + wmi_handle->num_of_diag_events_logs = num_of_diag_events_logs; + + /* Prepare the send buffer */ + buf_len = sizeof(*cmd) + WMI_TLV_HDR_SIZE + + (num_of_diag_events_logs * sizeof(uint32_t)); + + buf = wmi_buf_alloc(wmi_handle, buf_len); + if (!buf) { + WMI_LOGE("%s: wmi_buf_alloc failed", __func__); + qdf_mem_free(wmi_handle->events_logs_list); + wmi_handle->events_logs_list = NULL; + return QDF_STATUS_E_NOMEM; + } + + cmd = (wmi_diag_event_log_config_fixed_param *) wmi_buf_data(buf); + buf_ptr = (uint8_t *) cmd; + + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_diag_event_log_config_fixed_param, + WMITLV_GET_STRUCT_TLVLEN( + wmi_diag_event_log_config_fixed_param)); + + cmd->num_of_diag_events_logs = num_of_diag_events_logs; + + buf_ptr += sizeof(wmi_diag_event_log_config_fixed_param); + + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_UINT32, + (num_of_diag_events_logs * sizeof(uint32_t))); + + cmd_args = (uint32_t *) (buf_ptr + WMI_TLV_HDR_SIZE); + + /* Populate the events */ + for (i = 0; i < num_of_diag_events_logs; i++) { + /* Low freq (0) - Enable (1) the event + * High freq (1) - Disable (0) the event + */ + WMI_DIAG_ID_ENABLED_DISABLED_SET(cmd_args[i], + !(WMI_DIAG_FREQUENCY_GET(evt_args[i]))); + /* Set the event ID */ + WMI_DIAG_ID_SET(cmd_args[i], + WMI_DIAG_ID_GET(evt_args[i])); + /* Set the type */ + WMI_DIAG_TYPE_SET(cmd_args[i], + WMI_DIAG_TYPE_GET(evt_args[i])); + /* Storing the event/log list in WMI */ + wmi_handle->events_logs_list[i] = evt_args[i]; + } + + if (wmi_unified_cmd_send(wmi_handle, buf, buf_len, + WMI_DIAG_EVENT_LOG_CONFIG_CMDID)) { + WMI_LOGE("%s: WMI_DIAG_EVENT_LOG_CONFIG_CMDID failed", + __func__); + wmi_buf_free(buf); + /* Not clearing events_logs_list, though wmi cmd failed. + * Host can still have this list + */ + return QDF_STATUS_E_INVAL; + } + + return 0; +} + +/** + * send_enable_specific_fw_logs_cmd_tlv() - Start/Stop logging of diag log id + * @wmi_handle: wmi handle + * @start_log: Start logging related parameters + * + * Send the command to the FW based on which specific logging of diag + * event/log id can be started/stopped + * + * Return: None + */ +QDF_STATUS send_enable_specific_fw_logs_cmd_tlv(wmi_unified_t wmi_handle, + struct wmi_wifi_start_log *start_log) +{ + wmi_diag_event_log_config_fixed_param *cmd; + wmi_buf_t buf; + uint8_t *buf_ptr; + uint32_t len, count, log_level, i; + uint32_t *cmd_args; + uint32_t total_len; + count = 0; + + if (!wmi_handle->events_logs_list) { + WMI_LOGE("%s: Not received event/log list from FW, yet", + __func__); + return QDF_STATUS_E_NOMEM; + } + /* total_len stores the number of events where BITS 17 and 18 are set. + * i.e., events of high frequency (17) and for extended debugging (18) + */ + total_len = 0; + for (i = 0; i < wmi_handle->num_of_diag_events_logs; i++) { + if ((WMI_DIAG_FREQUENCY_GET(wmi_handle->events_logs_list[i])) && + (WMI_DIAG_EXT_FEATURE_GET(wmi_handle->events_logs_list[i]))) + total_len++; + } + + len = sizeof(*cmd) + WMI_TLV_HDR_SIZE + + (total_len * sizeof(uint32_t)); + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMI_LOGE("%s: wmi_buf_alloc failed", __func__); + return QDF_STATUS_E_NOMEM; + } + cmd = (wmi_diag_event_log_config_fixed_param *) wmi_buf_data(buf); + buf_ptr = (uint8_t *) cmd; + + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_diag_event_log_config_fixed_param, + WMITLV_GET_STRUCT_TLVLEN( + wmi_diag_event_log_config_fixed_param)); + + cmd->num_of_diag_events_logs = total_len; + + buf_ptr += sizeof(wmi_diag_event_log_config_fixed_param); + + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_UINT32, + (total_len * sizeof(uint32_t))); + + cmd_args = (uint32_t *) (buf_ptr + WMI_TLV_HDR_SIZE); + + if (start_log->verbose_level >= WMI_LOG_LEVEL_ACTIVE) + log_level = 1; + else + log_level = 0; + + WMI_LOGD("%s: Length:%d, Log_level:%d", __func__, total_len, log_level); + for (i = 0; i < wmi_handle->num_of_diag_events_logs; i++) { + uint32_t val = wmi_handle->events_logs_list[i]; + if ((WMI_DIAG_FREQUENCY_GET(val)) && + (WMI_DIAG_EXT_FEATURE_GET(val))) { + + WMI_DIAG_ID_SET(cmd_args[count], + WMI_DIAG_ID_GET(val)); + WMI_DIAG_TYPE_SET(cmd_args[count], + WMI_DIAG_TYPE_GET(val)); + WMI_DIAG_ID_ENABLED_DISABLED_SET(cmd_args[count], + log_level); + WMI_LOGD("%s: Idx:%d, val:%x", __func__, i, val); + count++; + } + } + + if (wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_DIAG_EVENT_LOG_CONFIG_CMDID)) { + WMI_LOGE("%s: WMI_DIAG_EVENT_LOG_CONFIG_CMDID failed", + __func__); + wmi_buf_free(buf); + return QDF_STATUS_E_INVAL; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * send_flush_logs_to_fw_cmd_tlv() - Send log flush command to FW + * @wmi_handle: WMI handle + * + * This function is used to send the flush command to the FW, + * that will flush the fw logs that are residue in the FW + * + * Return: None + */ +QDF_STATUS send_flush_logs_to_fw_cmd_tlv(wmi_unified_t wmi_handle) +{ + wmi_debug_mesg_flush_fixed_param *cmd; + wmi_buf_t buf; + int len = sizeof(*cmd); + QDF_STATUS ret; + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMI_LOGP("%s: wmi_buf_alloc failed", __func__); + return QDF_STATUS_E_NOMEM; + } + + cmd = (wmi_debug_mesg_flush_fixed_param *) wmi_buf_data(buf); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_debug_mesg_flush_fixed_param, + WMITLV_GET_STRUCT_TLVLEN( + wmi_debug_mesg_flush_fixed_param)); + cmd->reserved0 = 0; + + ret = wmi_unified_cmd_send(wmi_handle, + buf, + len, + WMI_DEBUG_MESG_FLUSH_CMDID); + if (QDF_IS_STATUS_ERROR(ret)) { + WMI_LOGE("Failed to send WMI_DEBUG_MESG_FLUSH_CMDID"); + wmi_buf_free(buf); + return QDF_STATUS_E_INVAL; + } + WMI_LOGI("Sent WMI_DEBUG_MESG_FLUSH_CMDID to FW"); + + return ret; +} + +/** + * send_pdev_set_pcl_cmd_tlv() - Send WMI_SOC_SET_PCL_CMDID to FW + * @wmi_handle: wmi handle + * @msg: PCL structure containing the PCL and the number of channels + * + * WMI_PDEV_SET_PCL_CMDID provides a Preferred Channel List (PCL) to the WLAN + * firmware. The DBS Manager is the consumer of this information in the WLAN + * firmware. The channel list will be used when a Virtual DEVice (VDEV) needs + * to migrate to a new channel without host driver involvement. An example of + * this behavior is Legacy Fast Roaming (LFR 3.0). Generally, the host will + * manage the channel selection without firmware involvement. + * + * WMI_PDEV_SET_PCL_CMDID will carry only the weight list and not the actual + * channel list. The weights corresponds to the channels sent in + * WMI_SCAN_CHAN_LIST_CMDID. The channels from PCL would be having a higher + * weightage compared to the non PCL channels. + * + * Return: Success if the cmd is sent successfully to the firmware + */ +QDF_STATUS send_pdev_set_pcl_cmd_tlv(wmi_unified_t wmi_handle, + struct wmi_pcl_chan_weights *msg) +{ + wmi_pdev_set_pcl_cmd_fixed_param *cmd; + wmi_buf_t buf; + uint8_t *buf_ptr; + uint32_t *cmd_args, i, len; + uint32_t chan_len; + + chan_len = msg->saved_num_chan; + + len = sizeof(*cmd) + + WMI_TLV_HDR_SIZE + (chan_len * sizeof(uint32_t)); + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMI_LOGE("%s: wmi_buf_alloc failed", __func__); + return QDF_STATUS_E_NOMEM; + } + + cmd = (wmi_pdev_set_pcl_cmd_fixed_param *) wmi_buf_data(buf); + buf_ptr = (uint8_t *) cmd; + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_pdev_set_pcl_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN(wmi_pdev_set_pcl_cmd_fixed_param)); + + cmd->pdev_id = WMI_PDEV_ID_SOC; + cmd->num_chan = chan_len; + WMI_LOGI("%s: Total chan (PCL) len:%d", __func__, cmd->num_chan); + + buf_ptr += sizeof(wmi_pdev_set_pcl_cmd_fixed_param); + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_UINT32, + (chan_len * sizeof(uint32_t))); + cmd_args = (uint32_t *) (buf_ptr + WMI_TLV_HDR_SIZE); + for (i = 0; i < chan_len ; i++) { + cmd_args[i] = msg->weighed_valid_list[i]; + WMI_LOGI("%s: chan:%d weight:%d", __func__, + msg->saved_chan_list[i], cmd_args[i]); + } + if (wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_PDEV_SET_PCL_CMDID)) { + WMI_LOGE("%s: Failed to send WMI_PDEV_SET_PCL_CMDID", __func__); + wmi_buf_free(buf); + return QDF_STATUS_E_FAILURE; + } + return QDF_STATUS_SUCCESS; +} + +/** + * send_pdev_set_hw_mode_cmd_tlv() - Send WMI_PDEV_SET_HW_MODE_CMDID to FW + * @wmi_handle: wmi handle + * @msg: Structure containing the following parameters + * + * - hw_mode_index: The HW_Mode field is a enumerated type that is selected + * from the HW_Mode table, which is returned in the WMI_SERVICE_READY_EVENTID. + * + * Provides notification to the WLAN firmware that host driver is requesting a + * HardWare (HW) Mode change. This command is needed to support iHelium in the + * configurations that include the Dual Band Simultaneous (DBS) feature. + * + * Return: Success if the cmd is sent successfully to the firmware + */ +QDF_STATUS send_pdev_set_hw_mode_cmd_tlv(wmi_unified_t wmi_handle, + uint32_t hw_mode_index) +{ + wmi_pdev_set_hw_mode_cmd_fixed_param *cmd; + wmi_buf_t buf; + uint32_t len; + + len = sizeof(*cmd); + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMI_LOGE("%s: wmi_buf_alloc failed", __func__); + return QDF_STATUS_E_NOMEM; + } + + cmd = (wmi_pdev_set_hw_mode_cmd_fixed_param *) wmi_buf_data(buf); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_pdev_set_hw_mode_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN(wmi_pdev_set_hw_mode_cmd_fixed_param)); + + cmd->pdev_id = WMI_PDEV_ID_SOC; + cmd->hw_mode_index = hw_mode_index; + WMI_LOGI("%s: HW mode index:%d", __func__, cmd->hw_mode_index); + + if (wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_PDEV_SET_HW_MODE_CMDID)) { + WMI_LOGE("%s: Failed to send WMI_PDEV_SET_HW_MODE_CMDID", + __func__); + wmi_buf_free(buf); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * send_pdev_set_dual_mac_config_cmd_tlv() - Set dual mac config to FW + * @wmi_handle: wmi handle + * @msg: Dual MAC config parameters + * + * Configures WLAN firmware with the dual MAC features + * + * Return: QDF_STATUS. 0 on success. + */ +static +QDF_STATUS send_pdev_set_dual_mac_config_cmd_tlv(wmi_unified_t wmi_handle, + struct wmi_dual_mac_config *msg) +{ + wmi_pdev_set_mac_config_cmd_fixed_param *cmd; + wmi_buf_t buf; + uint32_t len; + + len = sizeof(*cmd); + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMI_LOGE("%s: wmi_buf_alloc failed", __func__); + return QDF_STATUS_E_FAILURE; + } + + cmd = (wmi_pdev_set_mac_config_cmd_fixed_param *) wmi_buf_data(buf); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_pdev_set_mac_config_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN( + wmi_pdev_set_mac_config_cmd_fixed_param)); + + cmd->pdev_id = WMI_PDEV_ID_SOC; + cmd->concurrent_scan_config_bits = msg->scan_config; + cmd->fw_mode_config_bits = msg->fw_mode_config; + WMI_LOGI("%s: scan_config:%x fw_mode_config:%x", + __func__, msg->scan_config, msg->fw_mode_config); + + if (wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_PDEV_SET_MAC_CONFIG_CMDID)) { + WMI_LOGE("%s: Failed to send WMI_PDEV_SET_MAC_CONFIG_CMDID", + __func__); + wmi_buf_free(buf); + } + return QDF_STATUS_SUCCESS; +} + +/** + * fill_arp_offload_params_tlv() - Fill ARP offload data + * @wmi_handle: wmi handle + * @offload_req: offload request + * @buf_ptr: buffer pointer + * + * To fill ARP offload data to firmware + * when target goes to wow mode. + * + * Return: None + */ +static void fill_arp_offload_params_tlv(wmi_unified_t wmi_handle, + struct host_offload_req_param *offload_req, uint8_t **buf_ptr) +{ + + int i; + WMI_ARP_OFFLOAD_TUPLE *arp_tuple; + bool enable_or_disable = offload_req->enableOrDisable; + + WMITLV_SET_HDR(*buf_ptr, WMITLV_TAG_ARRAY_STRUC, + (WMI_MAX_ARP_OFFLOADS*sizeof(WMI_ARP_OFFLOAD_TUPLE))); + *buf_ptr += WMI_TLV_HDR_SIZE; + for (i = 0; i < WMI_MAX_ARP_OFFLOADS; i++) { + arp_tuple = (WMI_ARP_OFFLOAD_TUPLE *)*buf_ptr; + WMITLV_SET_HDR(&arp_tuple->tlv_header, + WMITLV_TAG_STRUC_WMI_ARP_OFFLOAD_TUPLE, + WMITLV_GET_STRUCT_TLVLEN(WMI_ARP_OFFLOAD_TUPLE)); + + /* Fill data for ARP and NS in the first tupple for LA */ + if ((enable_or_disable & WMI_OFFLOAD_ENABLE) && (i == 0)) { + /* Copy the target ip addr and flags */ + arp_tuple->flags = WMI_ARPOFF_FLAGS_VALID; + qdf_mem_copy(&arp_tuple->target_ipaddr, + offload_req->params.hostIpv4Addr, + WMI_IPV4_ADDR_LEN); + WMI_LOGD("ARPOffload IP4 address: %pI4", + offload_req->params.hostIpv4Addr); + } + *buf_ptr += sizeof(WMI_ARP_OFFLOAD_TUPLE); + } +} + +#ifdef WLAN_NS_OFFLOAD +/** + * fill_ns_offload_params_tlv() - Fill NS offload data + * @wmi|_handle: wmi handle + * @offload_req: offload request + * @buf_ptr: buffer pointer + * + * To fill NS offload data to firmware + * when target goes to wow mode. + * + * Return: None + */ +static void fill_ns_offload_params_tlv(wmi_unified_t wmi_handle, + struct host_offload_req_param *offload_req, uint8_t **buf_ptr) +{ + + int i; + WMI_NS_OFFLOAD_TUPLE *ns_tuple; + struct ns_offload_req_params ns_req; + + ns_req = offload_req->nsOffloadInfo; + WMITLV_SET_HDR(*buf_ptr, WMITLV_TAG_ARRAY_STRUC, + (WMI_MAX_NS_OFFLOADS * sizeof(WMI_NS_OFFLOAD_TUPLE))); + *buf_ptr += WMI_TLV_HDR_SIZE; + for (i = 0; i < WMI_MAX_NS_OFFLOADS; i++) { + ns_tuple = (WMI_NS_OFFLOAD_TUPLE *)*buf_ptr; + WMITLV_SET_HDR(&ns_tuple->tlv_header, + WMITLV_TAG_STRUC_WMI_NS_OFFLOAD_TUPLE, + (sizeof(WMI_NS_OFFLOAD_TUPLE) - WMI_TLV_HDR_SIZE)); + + /* + * Fill data only for NS offload in the first ARP tuple for LA + */ + if ((offload_req->enableOrDisable & WMI_OFFLOAD_ENABLE)) { + ns_tuple->flags |= WMI_NSOFF_FLAGS_VALID; + /* Copy the target/solicitation/remote ip addr */ + if (ns_req.targetIPv6AddrValid[i]) + qdf_mem_copy(&ns_tuple->target_ipaddr[0], + &ns_req.targetIPv6Addr[i], + sizeof(WMI_IPV6_ADDR)); + qdf_mem_copy(&ns_tuple->solicitation_ipaddr, + &ns_req.selfIPv6Addr[i], + sizeof(WMI_IPV6_ADDR)); + if (ns_req.target_ipv6_addr_ac_type[i]) { + ns_tuple->flags |= + WMI_NSOFF_FLAGS_IS_IPV6_ANYCAST; + } + WMI_LOGD("Index %d NS solicitedIp %pI6, targetIp %pI6", + i, &ns_req.selfIPv6Addr[i], + &ns_req.targetIPv6Addr[i]); + + /* target MAC is optional, check if it is valid, + * if this is not valid, the target will use the known + * local MAC address rather than the tuple + */ + WMI_CHAR_ARRAY_TO_MAC_ADDR( + ns_req.self_macaddr.bytes, + &ns_tuple->target_mac); + if ((ns_tuple->target_mac.mac_addr31to0 != 0) || + (ns_tuple->target_mac.mac_addr47to32 != 0)) { + ns_tuple->flags |= WMI_NSOFF_FLAGS_MAC_VALID; + } + } + *buf_ptr += sizeof(WMI_NS_OFFLOAD_TUPLE); + } +} + + +/** + * fill_nsoffload_ext_tlv() - Fill NS offload ext data + * @wmi: wmi handle + * @offload_req: offload request + * @buf_ptr: buffer pointer + * + * To fill extended NS offload extended data to firmware + * when target goes to wow mode. + * + * Return: None + */ +static void fill_nsoffload_ext_tlv(wmi_unified_t wmi_handle, + struct host_offload_req_param *offload_req, uint8_t **buf_ptr) +{ + int i; + WMI_NS_OFFLOAD_TUPLE *ns_tuple; + uint32_t count, num_ns_ext_tuples; + struct ns_offload_req_params ns_req; + + ns_req = offload_req->nsOffloadInfo; + count = offload_req->num_ns_offload_count; + num_ns_ext_tuples = offload_req->num_ns_offload_count - + WMI_MAX_NS_OFFLOADS; + + /* Populate extended NS offload tuples */ + WMITLV_SET_HDR(*buf_ptr, WMITLV_TAG_ARRAY_STRUC, + (num_ns_ext_tuples * sizeof(WMI_NS_OFFLOAD_TUPLE))); + *buf_ptr += WMI_TLV_HDR_SIZE; + for (i = WMI_MAX_NS_OFFLOADS; i < count; i++) { + ns_tuple = (WMI_NS_OFFLOAD_TUPLE *)*buf_ptr; + WMITLV_SET_HDR(&ns_tuple->tlv_header, + WMITLV_TAG_STRUC_WMI_NS_OFFLOAD_TUPLE, + (sizeof(WMI_NS_OFFLOAD_TUPLE)-WMI_TLV_HDR_SIZE)); + + /* + * Fill data only for NS offload in the first ARP tuple for LA + */ + if ((offload_req->enableOrDisable & WMI_OFFLOAD_ENABLE)) { + ns_tuple->flags |= WMI_NSOFF_FLAGS_VALID; + /* Copy the target/solicitation/remote ip addr */ + if (ns_req.targetIPv6AddrValid[i]) + qdf_mem_copy(&ns_tuple->target_ipaddr[0], + &ns_req.targetIPv6Addr[i], + sizeof(WMI_IPV6_ADDR)); + qdf_mem_copy(&ns_tuple->solicitation_ipaddr, + &ns_req.selfIPv6Addr[i], + sizeof(WMI_IPV6_ADDR)); + if (ns_req.target_ipv6_addr_ac_type[i]) { + ns_tuple->flags |= + WMI_NSOFF_FLAGS_IS_IPV6_ANYCAST; + } + WMI_LOGD("Index %d NS solicitedIp %pI6, targetIp %pI6", + i, &ns_req.selfIPv6Addr[i], + &ns_req.targetIPv6Addr[i]); + + /* target MAC is optional, check if it is valid, + * if this is not valid, the target will use the + * known local MAC address rather than the tuple + */ + WMI_CHAR_ARRAY_TO_MAC_ADDR( + ns_req.self_macaddr.bytes, + &ns_tuple->target_mac); + if ((ns_tuple->target_mac.mac_addr31to0 != 0) || + (ns_tuple->target_mac.mac_addr47to32 != 0)) { + ns_tuple->flags |= WMI_NSOFF_FLAGS_MAC_VALID; + } + } + *buf_ptr += sizeof(WMI_NS_OFFLOAD_TUPLE); + } +} +#else +static void fill_ns_offload_params_tlv(wmi_unified_t wmi_handle, + struct host_offload_req_param *offload_req, uint8_t **buf_ptr) +{ + return; +} + +static void fill_nsoffload_ext_tlv(wmi_unified_t wmi_handle, + struct host_offload_req_param *offload_req, uint8_t **buf_ptr) +{ + return; +} +#endif + +/** + * send_enable_arp_ns_offload_cmd_tlv() - enable ARP NS offload + * @wma: wmi handle + * @arp_offload_req: arp offload request + * @ns_offload_req: ns offload request + * @arp_only: flag + * + * To configure ARP NS off load data to firmware + * when target goes to wow mode. + * + * Return: QDF Status + */ +QDF_STATUS send_enable_arp_ns_offload_cmd_tlv(wmi_unified_t wmi_handle, + struct host_offload_req_param *arp_offload_req, + struct host_offload_req_param *ns_offload_req, + bool arp_only, + uint8_t vdev_id) +{ + int32_t res; + WMI_SET_ARP_NS_OFFLOAD_CMD_fixed_param *cmd; + A_UINT8 *buf_ptr; + wmi_buf_t buf; + int32_t len; + uint32_t count = 0, num_ns_ext_tuples = 0; + + count = ns_offload_req->num_ns_offload_count; + + /* + * TLV place holder size for array of NS tuples + * TLV place holder size for array of ARP tuples + */ + len = sizeof(WMI_SET_ARP_NS_OFFLOAD_CMD_fixed_param) + + WMI_TLV_HDR_SIZE + + WMI_MAX_NS_OFFLOADS * sizeof(WMI_NS_OFFLOAD_TUPLE) + + WMI_TLV_HDR_SIZE + + WMI_MAX_ARP_OFFLOADS * sizeof(WMI_ARP_OFFLOAD_TUPLE); + + /* + * If there are more than WMI_MAX_NS_OFFLOADS addresses then allocate + * extra length for extended NS offload tuples which follows ARP offload + * tuples. Host needs to fill this structure in following format: + * 2 NS ofload tuples + * 2 ARP offload tuples + * N numbers of extended NS offload tuples if HDD has given more than + * 2 NS offload addresses + */ + if (count > WMI_MAX_NS_OFFLOADS) { + num_ns_ext_tuples = count - WMI_MAX_NS_OFFLOADS; + len += WMI_TLV_HDR_SIZE + num_ns_ext_tuples + * sizeof(WMI_NS_OFFLOAD_TUPLE); + } + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMI_LOGE("%s: wmi_buf_alloc failed", __func__); + return QDF_STATUS_E_NOMEM; + } + + buf_ptr = (A_UINT8 *) wmi_buf_data(buf); + cmd = (WMI_SET_ARP_NS_OFFLOAD_CMD_fixed_param *) buf_ptr; + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_WMI_SET_ARP_NS_OFFLOAD_CMD_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (WMI_SET_ARP_NS_OFFLOAD_CMD_fixed_param)); + cmd->flags = 0; + cmd->vdev_id = vdev_id; + cmd->num_ns_ext_tuples = num_ns_ext_tuples; + + WMI_LOGD("ARP NS Offload vdev_id: %d", cmd->vdev_id); + + buf_ptr += sizeof(WMI_SET_ARP_NS_OFFLOAD_CMD_fixed_param); + fill_ns_offload_params_tlv(wmi_handle, ns_offload_req, &buf_ptr); + fill_arp_offload_params_tlv(wmi_handle, arp_offload_req, &buf_ptr); + if (num_ns_ext_tuples) + fill_nsoffload_ext_tlv(wmi_handle, ns_offload_req, &buf_ptr); + + res = wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_SET_ARP_NS_OFFLOAD_CMDID); + if (res) { + WMI_LOGE("Failed to enable ARP NDP/NSffload"); + wmi_buf_free(buf); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS send_conf_hw_filter_cmd_tlv(wmi_unified_t wmi, uint8_t vdev_id, + uint8_t mode_bitmap) +{ + QDF_STATUS status; + wmi_hw_data_filter_cmd_fixed_param *cmd; + wmi_buf_t wmi_buf; + + wmi_buf = wmi_buf_alloc(wmi, sizeof(*cmd)); + if (!wmi_buf) { + WMI_LOGE(FL("Out of memory")); + return QDF_STATUS_E_NOMEM; + } + + cmd = (wmi_hw_data_filter_cmd_fixed_param *)wmi_buf_data(wmi_buf); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_hw_data_filter_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN(wmi_hw_data_filter_cmd_fixed_param)); + cmd->vdev_id = vdev_id; + cmd->enable = mode_bitmap != 0; + cmd->hw_filter_bitmap = mode_bitmap; + + WMI_LOGD("conf hw filter vdev_id: %d, mode: %u", vdev_id, mode_bitmap); + status = wmi_unified_cmd_send(wmi, wmi_buf, sizeof(*cmd), + WMI_HW_DATA_FILTER_CMDID); + if (QDF_IS_STATUS_ERROR(status)) { + WMI_LOGE("Failed to configure hw filter"); + wmi_buf_free(wmi_buf); + } + + return status; +} + +/** + * send_set_ssid_hotlist_cmd_tlv() - Handle an SSID hotlist set request + * @wmi_handle: wmi handle + * @request: SSID hotlist set request + * + * Return: QDF_STATUS enumeration + */ +QDF_STATUS +send_set_ssid_hotlist_cmd_tlv(wmi_unified_t wmi_handle, + struct ssid_hotlist_request_params *request) +{ + wmi_extscan_configure_hotlist_ssid_monitor_cmd_fixed_param *cmd; + wmi_buf_t wmi_buf; + uint32_t len; + uint32_t array_size; + uint8_t *buf_ptr; + + /* length of fixed portion */ + len = sizeof(*cmd); + + /* length of variable portion */ + array_size = + request->ssid_count * sizeof(wmi_extscan_hotlist_ssid_entry); + len += WMI_TLV_HDR_SIZE + array_size; + + wmi_buf = wmi_buf_alloc(wmi_handle, len); + if (!wmi_buf) { + WMI_LOGE("%s: wmi_buf_alloc failed", __func__); + return QDF_STATUS_E_NOMEM; + } + + buf_ptr = (uint8_t *) wmi_buf_data(wmi_buf); + cmd = (wmi_extscan_configure_hotlist_ssid_monitor_cmd_fixed_param *) + buf_ptr; + WMITLV_SET_HDR + (&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_extscan_configure_hotlist_ssid_monitor_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_extscan_configure_hotlist_ssid_monitor_cmd_fixed_param)); + + cmd->request_id = request->request_id; + cmd->requestor_id = 0; + cmd->vdev_id = request->session_id; + cmd->table_id = 0; + cmd->lost_ap_scan_count = request->lost_ssid_sample_size; + cmd->total_entries = request->ssid_count; + cmd->num_entries_in_page = request->ssid_count; + cmd->first_entry_index = 0; + + buf_ptr += sizeof(*cmd); + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, array_size); + + if (request->ssid_count) { + wmi_extscan_hotlist_ssid_entry *entry; + int i; + + buf_ptr += WMI_TLV_HDR_SIZE; + entry = (wmi_extscan_hotlist_ssid_entry *)buf_ptr; + for (i = 0; i < request->ssid_count; i++) { + WMITLV_SET_HDR + (entry, + WMITLV_TAG_ARRAY_STRUC, + WMITLV_GET_STRUCT_TLVLEN + (wmi_extscan_hotlist_ssid_entry)); + entry->ssid.ssid_len = request->ssids[i].ssid.length; + qdf_mem_copy(entry->ssid.ssid, + request->ssids[i].ssid.mac_ssid, + request->ssids[i].ssid.length); + entry->band = request->ssids[i].band; + entry->min_rssi = request->ssids[i].rssi_low; + entry->max_rssi = request->ssids[i].rssi_high; + entry++; + } + cmd->mode = WMI_EXTSCAN_MODE_START; + } else { + cmd->mode = WMI_EXTSCAN_MODE_STOP; + } + + if (wmi_unified_cmd_send + (wmi_handle, wmi_buf, len, + WMI_EXTSCAN_CONFIGURE_HOTLIST_SSID_MONITOR_CMDID)) { + WMI_LOGE("%s: failed to send command", __func__); + wmi_buf_free(wmi_buf); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * send_process_roam_synch_complete_cmd_tlv() - roam synch complete command to fw. + * @wmi_handle: wmi handle + * @vdev_id: vdev id + * + * This function sends roam synch complete event to fw. + * + * Return: CDF STATUS + */ +QDF_STATUS send_process_roam_synch_complete_cmd_tlv(wmi_unified_t wmi_handle, + uint8_t vdev_id) +{ + wmi_roam_synch_complete_fixed_param *cmd; + wmi_buf_t wmi_buf; + uint8_t *buf_ptr; + uint16_t len; + len = sizeof(wmi_roam_synch_complete_fixed_param); + + wmi_buf = wmi_buf_alloc(wmi_handle, len); + if (!wmi_buf) { + WMI_LOGE("%s: wmi_buf_alloc failed", __func__); + return QDF_STATUS_E_NOMEM; + } + cmd = (wmi_roam_synch_complete_fixed_param *) wmi_buf_data(wmi_buf); + buf_ptr = (uint8_t *) cmd; + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_roam_synch_complete_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_roam_synch_complete_fixed_param)); + cmd->vdev_id = vdev_id; + if (wmi_unified_cmd_send(wmi_handle, wmi_buf, len, + WMI_ROAM_SYNCH_COMPLETE)) { + WMI_LOGP("%s: failed to send roam synch confirmation", + __func__); + wmi_buf_free(wmi_buf); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * send_fw_test_cmd_tlv() - send fw test command to fw. + * @wmi_handle: wmi handle + * @wmi_fwtest: fw test command + * + * This function sends fw test command to fw. + * + * Return: CDF STATUS + */ +static +QDF_STATUS send_fw_test_cmd_tlv(wmi_unified_t wmi_handle, + struct set_fwtest_params *wmi_fwtest) +{ + wmi_fwtest_set_param_cmd_fixed_param *cmd; + wmi_buf_t wmi_buf; + uint16_t len; + + len = sizeof(*cmd); + + wmi_buf = wmi_buf_alloc(wmi_handle, len); + if (!wmi_buf) { + WMI_LOGE("%s: wmai_buf_alloc failed", __func__); + return QDF_STATUS_E_NOMEM; + } + + cmd = (wmi_fwtest_set_param_cmd_fixed_param *) wmi_buf_data(wmi_buf); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_fwtest_set_param_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN( + wmi_fwtest_set_param_cmd_fixed_param)); + cmd->param_id = wmi_fwtest->arg; + cmd->param_value = wmi_fwtest->value; + + if (wmi_unified_cmd_send(wmi_handle, wmi_buf, len, + WMI_FWTEST_CMDID)) { + WMI_LOGP("%s: failed to send fw test command", __func__); + qdf_nbuf_free(wmi_buf); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * send_unit_test_cmd_tlv() - send unit test command to fw. + * @wmi_handle: wmi handle + * @wmi_utest: unit test command + * + * This function send unit test command to fw. + * + * Return: CDF STATUS + */ +QDF_STATUS send_unit_test_cmd_tlv(wmi_unified_t wmi_handle, + struct wmi_unit_test_cmd *wmi_utest) +{ + wmi_unit_test_cmd_fixed_param *cmd; + wmi_buf_t wmi_buf; + uint8_t *buf_ptr; + int i; + uint16_t len, args_tlv_len; + A_UINT32 *unit_test_cmd_args; + + args_tlv_len = + WMI_TLV_HDR_SIZE + wmi_utest->num_args * sizeof(A_UINT32); + len = sizeof(wmi_unit_test_cmd_fixed_param) + args_tlv_len; + + wmi_buf = wmi_buf_alloc(wmi_handle, len); + if (!wmi_buf) { + WMI_LOGE("%s: wmai_buf_alloc failed", __func__); + return QDF_STATUS_E_NOMEM; + } + + cmd = (wmi_unit_test_cmd_fixed_param *) wmi_buf_data(wmi_buf); + buf_ptr = (uint8_t *) cmd; + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_unit_test_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN(wmi_unit_test_cmd_fixed_param)); + cmd->vdev_id = wmi_utest->vdev_id; + cmd->module_id = wmi_utest->module_id; + cmd->num_args = wmi_utest->num_args; + buf_ptr += sizeof(wmi_unit_test_cmd_fixed_param); + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_UINT32, + (wmi_utest->num_args * sizeof(uint32_t))); + unit_test_cmd_args = (A_UINT32 *) (buf_ptr + WMI_TLV_HDR_SIZE); + WMI_LOGI("%s: %d num of args = ", __func__, wmi_utest->num_args); + for (i = 0; (i < wmi_utest->num_args && i < WMI_MAX_NUM_ARGS); i++) { + unit_test_cmd_args[i] = wmi_utest->args[i]; + WMI_LOGI("%d,", wmi_utest->args[i]); + } + if (wmi_unified_cmd_send(wmi_handle, wmi_buf, len, + WMI_UNIT_TEST_CMDID)) { + WMI_LOGP("%s: failed to send unit test command", __func__); + wmi_buf_free(wmi_buf); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * send_roam_invoke_cmd_tlv() - send roam invoke command to fw. + * @wmi_handle: wma handle + * @roaminvoke: roam invoke command + * + * Send roam invoke command to fw for fastreassoc. + * + * Return: CDF STATUS + */ +QDF_STATUS send_roam_invoke_cmd_tlv(wmi_unified_t wmi_handle, + struct wmi_roam_invoke_cmd *roaminvoke, + uint32_t ch_hz) +{ + wmi_roam_invoke_cmd_fixed_param *cmd; + wmi_buf_t wmi_buf; + u_int8_t *buf_ptr; + u_int16_t len, args_tlv_len; + A_UINT32 *channel_list; + wmi_mac_addr *bssid_list; + wmi_tlv_buf_len_param *buf_len_tlv; + + /* Host sends only one channel and one bssid */ + args_tlv_len = (4 * WMI_TLV_HDR_SIZE) + sizeof(A_UINT32) + + sizeof(wmi_mac_addr) + sizeof(wmi_tlv_buf_len_param) + + roundup(roaminvoke->frame_len, sizeof(uint32_t)); + len = sizeof(wmi_roam_invoke_cmd_fixed_param) + args_tlv_len; + wmi_buf = wmi_buf_alloc(wmi_handle, len); + if (!wmi_buf) { + WMI_LOGE("%s: wmai_buf_alloc failed", __func__); + return QDF_STATUS_E_NOMEM; + } + + cmd = (wmi_roam_invoke_cmd_fixed_param *)wmi_buf_data(wmi_buf); + buf_ptr = (u_int8_t *) cmd; + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_roam_invoke_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN(wmi_roam_invoke_cmd_fixed_param)); + cmd->vdev_id = roaminvoke->vdev_id; + cmd->flags |= (1 << WMI_ROAM_INVOKE_FLAG_REPORT_FAILURE); + + if (roaminvoke->frame_len) + cmd->roam_scan_mode = WMI_ROAM_INVOKE_SCAN_MODE_SKIP; + else + cmd->roam_scan_mode = WMI_ROAM_INVOKE_SCAN_MODE_FIXED_CH; + + cmd->roam_ap_sel_mode = 0; + cmd->roam_delay = 0; + cmd->num_chan = 1; + cmd->num_bssid = 1; + /* packing 1 beacon/probe_rsp frame with WMI cmd */ + cmd->num_buf = 1; + + buf_ptr += sizeof(wmi_roam_invoke_cmd_fixed_param); + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_UINT32, + (sizeof(u_int32_t))); + channel_list = (A_UINT32 *)(buf_ptr + WMI_TLV_HDR_SIZE); + *channel_list = ch_hz; + buf_ptr += sizeof(A_UINT32) + WMI_TLV_HDR_SIZE; + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_FIXED_STRUC, + (sizeof(wmi_mac_addr))); + bssid_list = (wmi_mac_addr *)(buf_ptr + WMI_TLV_HDR_SIZE); + WMI_CHAR_ARRAY_TO_MAC_ADDR(roaminvoke->bssid, bssid_list); + + /* move to next tlv i.e. bcn_prb_buf_list */ + buf_ptr += WMI_TLV_HDR_SIZE + sizeof(wmi_mac_addr); + + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_FIXED_STRUC, + sizeof(wmi_tlv_buf_len_param)); + + buf_len_tlv = (wmi_tlv_buf_len_param *)(buf_ptr + WMI_TLV_HDR_SIZE); + buf_len_tlv->buf_len = roaminvoke->frame_len; + + /* move to next tlv i.e. bcn_prb_frm */ + buf_ptr += WMI_TLV_HDR_SIZE + sizeof(wmi_tlv_buf_len_param); + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE, + roundup(roaminvoke->frame_len, sizeof(uint32_t))); + + /* copy frame after the header */ + qdf_mem_copy(buf_ptr + WMI_TLV_HDR_SIZE, + roaminvoke->frame_buf, + roaminvoke->frame_len); + + WMI_LOGD(FL("Hex dump of beacon/probe_rsp frame, length: %d"), + roaminvoke->frame_len); + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_WMA, QDF_TRACE_LEVEL_DEBUG, + buf_ptr + WMI_TLV_HDR_SIZE, + roaminvoke->frame_len); + + if (wmi_unified_cmd_send(wmi_handle, wmi_buf, len, + WMI_ROAM_INVOKE_CMDID)) { + WMI_LOGP("%s: failed to send roam invoke command", __func__); + wmi_buf_free(wmi_buf); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * send_roam_scan_offload_cmd_tlv() - set roam offload command + * @wmi_handle: wmi handle + * @command: command + * @vdev_id: vdev id + * + * This function set roam offload command to fw. + * + * Return: CDF status + */ +QDF_STATUS send_roam_scan_offload_cmd_tlv(wmi_unified_t wmi_handle, + uint32_t command, uint32_t vdev_id) +{ + QDF_STATUS status; + wmi_roam_scan_cmd_fixed_param *cmd_fp; + wmi_buf_t buf = NULL; + int len; + uint8_t *buf_ptr; + + len = sizeof(wmi_roam_scan_cmd_fixed_param); + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMI_LOGE("%s : wmi_buf_alloc failed", __func__); + return QDF_STATUS_E_NOMEM; + } + + buf_ptr = (uint8_t *) wmi_buf_data(buf); + + cmd_fp = (wmi_roam_scan_cmd_fixed_param *) buf_ptr; + WMITLV_SET_HDR(&cmd_fp->tlv_header, + WMITLV_TAG_STRUC_wmi_roam_scan_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN(wmi_roam_scan_cmd_fixed_param)); + cmd_fp->vdev_id = vdev_id; + cmd_fp->command_arg = command; + + status = wmi_unified_cmd_send(wmi_handle, buf, + len, WMI_ROAM_SCAN_CMD); + if (QDF_IS_STATUS_ERROR(status)) { + WMI_LOGE("wmi_unified_cmd_send WMI_ROAM_SCAN_CMD returned Error %d", + status); + goto error; + } + + WMI_LOGI("%s: WMI --> WMI_ROAM_SCAN_CMD", __func__); + return QDF_STATUS_SUCCESS; + +error: + wmi_buf_free(buf); + + return status; +} + +/** + * send_roam_scan_offload_ap_profile_cmd_tlv() - set roam ap profile in fw + * @wmi_handle: wmi handle + * @ap_profile_p: ap profile + * @vdev_id: vdev id + * + * Send WMI_ROAM_AP_PROFILE to firmware + * + * Return: CDF status + */ +QDF_STATUS send_roam_scan_offload_ap_profile_cmd_tlv(wmi_unified_t wmi_handle, + wmi_ap_profile *ap_profile_p, + uint32_t vdev_id) +{ + wmi_buf_t buf = NULL; + QDF_STATUS status; + int len; + uint8_t *buf_ptr; + wmi_roam_ap_profile_fixed_param *roam_ap_profile_fp; + + len = sizeof(wmi_roam_ap_profile_fixed_param) + sizeof(wmi_ap_profile); + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMI_LOGE("%s : wmi_buf_alloc failed", __func__); + return QDF_STATUS_E_NOMEM; + } + + buf_ptr = (uint8_t *) wmi_buf_data(buf); + roam_ap_profile_fp = (wmi_roam_ap_profile_fixed_param *) buf_ptr; + WMITLV_SET_HDR(&roam_ap_profile_fp->tlv_header, + WMITLV_TAG_STRUC_wmi_roam_ap_profile_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_roam_ap_profile_fixed_param)); + /* fill in threshold values */ + roam_ap_profile_fp->vdev_id = vdev_id; + roam_ap_profile_fp->id = 0; + buf_ptr += sizeof(wmi_roam_ap_profile_fixed_param); + + qdf_mem_copy(buf_ptr, ap_profile_p, sizeof(wmi_ap_profile)); + WMITLV_SET_HDR(buf_ptr, + WMITLV_TAG_STRUC_wmi_ap_profile, + WMITLV_GET_STRUCT_TLVLEN(wmi_ap_profile)); + status = wmi_unified_cmd_send(wmi_handle, buf, + len, WMI_ROAM_AP_PROFILE); + if (QDF_IS_STATUS_ERROR(status)) { + WMI_LOGE("wmi_unified_cmd_send WMI_ROAM_AP_PROFILE returned Error %d", + status); + wmi_buf_free(buf); + } + + WMI_LOGI("WMI --> WMI_ROAM_AP_PROFILE and other parameters"); + + return status; +} + +/** + * send_roam_scan_offload_scan_period_cmd_tlv() - set roam offload scan period + * @wmi_handle: wmi handle + * @scan_period: scan period + * @scan_age: scan age + * @vdev_id: vdev id + * + * Send WMI_ROAM_SCAN_PERIOD parameters to fw. + * + * Return: CDF status + */ +QDF_STATUS send_roam_scan_offload_scan_period_cmd_tlv(wmi_unified_t wmi_handle, + uint32_t scan_period, + uint32_t scan_age, + uint32_t vdev_id) +{ + QDF_STATUS status; + wmi_buf_t buf = NULL; + int len; + uint8_t *buf_ptr; + wmi_roam_scan_period_fixed_param *scan_period_fp; + + /* Send scan period values */ + len = sizeof(wmi_roam_scan_period_fixed_param); + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMI_LOGE("%s : wmi_buf_alloc failed", __func__); + return QDF_STATUS_E_NOMEM; + } + + buf_ptr = (uint8_t *) wmi_buf_data(buf); + scan_period_fp = (wmi_roam_scan_period_fixed_param *) buf_ptr; + WMITLV_SET_HDR(&scan_period_fp->tlv_header, + WMITLV_TAG_STRUC_wmi_roam_scan_period_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_roam_scan_period_fixed_param)); + /* fill in scan period values */ + scan_period_fp->vdev_id = vdev_id; + scan_period_fp->roam_scan_period = scan_period; /* 20 seconds */ + scan_period_fp->roam_scan_age = scan_age; + + status = wmi_unified_cmd_send(wmi_handle, buf, + len, WMI_ROAM_SCAN_PERIOD); + if (QDF_IS_STATUS_ERROR(status)) { + WMI_LOGE("wmi_unified_cmd_send WMI_ROAM_SCAN_PERIOD returned Error %d", + status); + goto error; + } + + WMI_LOGI("%s: WMI --> WMI_ROAM_SCAN_PERIOD roam_scan_period=%d, roam_scan_age=%d", + __func__, scan_period, scan_age); + return QDF_STATUS_SUCCESS; +error: + wmi_buf_free(buf); + + return status; +} + +/** + * send_roam_scan_offload_chan_list_cmd_tlv() - set roam offload channel list + * @wmi_handle: wmi handle + * @chan_count: channel count + * @chan_list: channel list + * @list_type: list type + * @vdev_id: vdev id + * + * Set roam offload channel list. + * + * Return: CDF status + */ +QDF_STATUS send_roam_scan_offload_chan_list_cmd_tlv(wmi_unified_t wmi_handle, + uint8_t chan_count, + uint32_t *chan_list, + uint8_t list_type, uint32_t vdev_id) +{ + wmi_buf_t buf = NULL; + QDF_STATUS status; + int len, list_tlv_len; + int i; + uint8_t *buf_ptr; + wmi_roam_chan_list_fixed_param *chan_list_fp; + A_UINT32 *roam_chan_list_array; + + if (chan_count == 0) { + WMI_LOGD("%s : invalid number of channels %d", __func__, + chan_count); + return QDF_STATUS_E_EMPTY; + } + /* Channel list is a table of 2 TLV's */ + list_tlv_len = WMI_TLV_HDR_SIZE + chan_count * sizeof(A_UINT32); + len = sizeof(wmi_roam_chan_list_fixed_param) + list_tlv_len; + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMI_LOGE("%s : wmi_buf_alloc failed", __func__); + return QDF_STATUS_E_NOMEM; + } + + buf_ptr = (uint8_t *) wmi_buf_data(buf); + chan_list_fp = (wmi_roam_chan_list_fixed_param *) buf_ptr; + WMITLV_SET_HDR(&chan_list_fp->tlv_header, + WMITLV_TAG_STRUC_wmi_roam_chan_list_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_roam_chan_list_fixed_param)); + chan_list_fp->vdev_id = vdev_id; + chan_list_fp->num_chan = chan_count; + if (chan_count > 0 && list_type == WMI_CHANNEL_LIST_STATIC) { + /* external app is controlling channel list */ + chan_list_fp->chan_list_type = + WMI_ROAM_SCAN_CHAN_LIST_TYPE_STATIC; + } else { + /* umac supplied occupied channel list in LFR */ + chan_list_fp->chan_list_type = + WMI_ROAM_SCAN_CHAN_LIST_TYPE_DYNAMIC; + } + + buf_ptr += sizeof(wmi_roam_chan_list_fixed_param); + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_UINT32, + (chan_list_fp->num_chan * sizeof(uint32_t))); + roam_chan_list_array = (A_UINT32 *) (buf_ptr + WMI_TLV_HDR_SIZE); + WMI_LOGI("%s: %d channels = ", __func__, chan_list_fp->num_chan); + for (i = 0; ((i < chan_list_fp->num_chan) && + (i < WMI_ROAM_MAX_CHANNELS)); i++) { + roam_chan_list_array[i] = chan_list[i]; + WMI_LOGI("%d,", roam_chan_list_array[i]); + } + + status = wmi_unified_cmd_send(wmi_handle, buf, + len, WMI_ROAM_CHAN_LIST); + if (QDF_IS_STATUS_ERROR(status)) { + WMI_LOGE("wmi_unified_cmd_send WMI_ROAM_CHAN_LIST returned Error %d", + status); + goto error; + } + + WMI_LOGI("%s: WMI --> WMI_ROAM_SCAN_CHAN_LIST", __func__); + return QDF_STATUS_SUCCESS; +error: + wmi_buf_free(buf); + + return status; +} +QDF_STATUS send_set_arp_stats_req_cmd_tlv(wmi_unified_t wmi_handle, + struct set_arp_stats *req_buf) +{ + wmi_buf_t buf = NULL; + QDF_STATUS status; + int len; + uint8_t *buf_ptr; + wmi_vdev_set_arp_stats_cmd_fixed_param *wmi_set_arp; + + len = sizeof(wmi_vdev_set_arp_stats_cmd_fixed_param); + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMI_LOGE("%s : wmi_buf_alloc failed", __func__); + return QDF_STATUS_E_NOMEM; + } + + buf_ptr = (uint8_t *) wmi_buf_data(buf); + wmi_set_arp = + (wmi_vdev_set_arp_stats_cmd_fixed_param *) buf_ptr; + WMITLV_SET_HDR(&wmi_set_arp->tlv_header, + WMITLV_TAG_STRUC_wmi_vdev_set_arp_stats_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_vdev_set_arp_stats_cmd_fixed_param)); + + /* fill in per roam config values */ + wmi_set_arp->vdev_id = req_buf->vdev_id; + + wmi_set_arp->set_clr = req_buf->flag; + wmi_set_arp->pkt_type = req_buf->pkt_type; + wmi_set_arp->ipv4 = req_buf->ip_addr; + + /* Send per roam config parameters */ + status = wmi_unified_cmd_send(wmi_handle, buf, + len, WMI_VDEV_SET_ARP_STAT_CMDID); + if (QDF_IS_STATUS_ERROR(status)) { + WMI_LOGE("WMI_SET_ARP_STATS_CMDID failed, Error %d", + status); + goto error; + } + + WMI_LOGI(FL("set arp stats flag=%d, vdev=%d"), + req_buf->flag, req_buf->vdev_id); + return QDF_STATUS_SUCCESS; +error: + wmi_buf_free(buf); + + return status; +} + +QDF_STATUS send_get_arp_stats_req_cmd_tlv(wmi_unified_t wmi_handle, + struct get_arp_stats *req_buf) +{ + wmi_buf_t buf = NULL; + QDF_STATUS status; + int len; + uint8_t *buf_ptr; + wmi_vdev_get_arp_stats_cmd_fixed_param *get_arp_stats; + + len = sizeof(wmi_vdev_get_arp_stats_cmd_fixed_param); + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMI_LOGE("%s : wmi_buf_alloc failed", __func__); + return QDF_STATUS_E_NOMEM; + } + + buf_ptr = (uint8_t *) wmi_buf_data(buf); + get_arp_stats = + (wmi_vdev_get_arp_stats_cmd_fixed_param *) buf_ptr; + WMITLV_SET_HDR(&get_arp_stats->tlv_header, + WMITLV_TAG_STRUC_wmi_vdev_get_arp_stats_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_vdev_get_arp_stats_cmd_fixed_param)); + + /* fill in arp stats req cmd values */ + get_arp_stats->vdev_id = req_buf->vdev_id; + + WMI_LOGI(FL("vdev=%d"), req_buf->vdev_id); + /* Send per roam config parameters */ + status = wmi_unified_cmd_send(wmi_handle, buf, + len, WMI_VDEV_GET_ARP_STAT_CMDID); + if (QDF_IS_STATUS_ERROR(status)) { + WMI_LOGE("WMI_GET_ARP_STATS_CMDID failed, Error %d", + status); + goto error; + } + + return QDF_STATUS_SUCCESS; +error: + wmi_buf_free(buf); + + return status; +} + +QDF_STATUS send_per_roam_config_cmd_tlv(wmi_unified_t wmi_handle, + struct wmi_per_roam_config_req *req_buf) +{ + wmi_buf_t buf = NULL; + QDF_STATUS status; + int len; + uint8_t *buf_ptr; + wmi_roam_per_config_fixed_param *wmi_per_config; + + len = sizeof(wmi_roam_per_config_fixed_param); + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMI_LOGE("%s : wmi_buf_alloc failed", __func__); + return QDF_STATUS_E_NOMEM; + } + + buf_ptr = (uint8_t *) wmi_buf_data(buf); + wmi_per_config = + (wmi_roam_per_config_fixed_param *) buf_ptr; + WMITLV_SET_HDR(&wmi_per_config->tlv_header, + WMITLV_TAG_STRUC_wmi_roam_per_config_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_roam_per_config_fixed_param)); + + /* fill in per roam config values */ + wmi_per_config->vdev_id = req_buf->vdev_id; + + wmi_per_config->enable = req_buf->per_config.enable; + wmi_per_config->high_rate_thresh = + (req_buf->per_config.tx_high_rate_thresh << 16) | + (req_buf->per_config.rx_high_rate_thresh & 0x0000ffff); + wmi_per_config->low_rate_thresh = + (req_buf->per_config.tx_low_rate_thresh << 16) | + (req_buf->per_config.rx_low_rate_thresh & 0x0000ffff); + wmi_per_config->pkt_err_rate_thresh_pct = + (req_buf->per_config.tx_rate_thresh_percnt << 16) | + (req_buf->per_config.rx_rate_thresh_percnt & 0x0000ffff); + wmi_per_config->per_rest_time = req_buf->per_config.per_rest_time; + wmi_per_config->pkt_err_rate_mon_time = + (req_buf->per_config.tx_per_mon_time << 16) | + (req_buf->per_config.rx_per_mon_time & 0x0000ffff); + wmi_per_config->min_candidate_rssi = + req_buf->per_config.min_candidate_rssi; + + /* Send per roam config parameters */ + status = wmi_unified_cmd_send(wmi_handle, buf, + len, WMI_ROAM_PER_CONFIG_CMDID); + if (QDF_IS_STATUS_ERROR(status)) { + WMI_LOGE("WMI_ROAM_PER_CONFIG_CMDID failed, Error %d", + status); + goto error; + } + + WMI_LOGI(FL("per roam enable=%d, vdev=%d"), + req_buf->per_config.enable, req_buf->vdev_id); + return QDF_STATUS_SUCCESS; +error: + wmi_buf_free(buf); + + return status; +} + +/** + * send_roam_scan_offload_rssi_change_cmd_tlv() - set roam offload RSSI th + * @wmi_handle: wmi handle + * @rssi_change_thresh: RSSI Change threshold + * @bcn_rssi_weight: beacon RSSI weight + * @vdev_id: vdev id + * + * Send WMI_ROAM_SCAN_RSSI_CHANGE_THRESHOLD parameters to fw. + * + * Return: CDF status + */ +QDF_STATUS send_roam_scan_offload_rssi_change_cmd_tlv(wmi_unified_t wmi_handle, + uint32_t vdev_id, + int32_t rssi_change_thresh, + uint32_t bcn_rssi_weight, + uint32_t hirssi_delay_btw_scans) +{ + wmi_buf_t buf = NULL; + QDF_STATUS status; + int len; + uint8_t *buf_ptr; + wmi_roam_scan_rssi_change_threshold_fixed_param *rssi_change_fp; + + /* Send rssi change parameters */ + len = sizeof(wmi_roam_scan_rssi_change_threshold_fixed_param); + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMI_LOGE("%s : wmi_buf_alloc failed", __func__); + return QDF_STATUS_E_NOMEM; + } + + buf_ptr = (uint8_t *) wmi_buf_data(buf); + rssi_change_fp = + (wmi_roam_scan_rssi_change_threshold_fixed_param *) buf_ptr; + WMITLV_SET_HDR(&rssi_change_fp->tlv_header, + WMITLV_TAG_STRUC_wmi_roam_scan_rssi_change_threshold_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_roam_scan_rssi_change_threshold_fixed_param)); + /* fill in rssi change threshold (hysteresis) values */ + rssi_change_fp->vdev_id = vdev_id; + rssi_change_fp->roam_scan_rssi_change_thresh = rssi_change_thresh; + rssi_change_fp->bcn_rssi_weight = bcn_rssi_weight; + rssi_change_fp->hirssi_delay_btw_scans = hirssi_delay_btw_scans; + + status = wmi_unified_cmd_send(wmi_handle, buf, + len, WMI_ROAM_SCAN_RSSI_CHANGE_THRESHOLD); + if (QDF_IS_STATUS_ERROR(status)) { + WMI_LOGE("wmi_unified_cmd_send WMI_ROAM_SCAN_RSSI_CHANGE_THRESHOLD returned Error %d", + status); + goto error; + } + + WMI_LOGI(FL("roam_scan_rssi_change_thresh=%d, bcn_rssi_weight=%d"), + rssi_change_thresh, bcn_rssi_weight); + WMI_LOGI(FL("hirssi_delay_btw_scans=%d"), hirssi_delay_btw_scans); + return QDF_STATUS_SUCCESS; +error: + wmi_buf_free(buf); + + return status; +} + +/** wmi_get_hotlist_entries_per_page() - hotlist entries per page + * @wmi_handle: wmi handle. + * @cmd: size of command structure. + * @per_entry_size: per entry size. + * + * This utility function calculates how many hotlist entries can + * fit in one page. + * + * Return: number of entries + */ +static inline int wmi_get_hotlist_entries_per_page(wmi_unified_t wmi_handle, + size_t cmd_size, + size_t per_entry_size) +{ + uint32_t avail_space = 0; + int num_entries = 0; + uint16_t max_msg_len = wmi_get_max_msg_len(wmi_handle); + + /* Calculate number of hotlist entries that can + * be passed in wma message request. + */ + avail_space = max_msg_len - cmd_size; + num_entries = avail_space / per_entry_size; + return num_entries; +} + +/** + * send_get_buf_extscan_hotlist_cmd_tlv() - prepare hotlist command + * @wmi_handle: wmi handle + * @photlist: hotlist command params + * @buf_len: buffer length + * + * This function fills individual elements for hotlist request and + * TLV for bssid entries + * + * Return: CDF Status. + */ +QDF_STATUS send_get_buf_extscan_hotlist_cmd_tlv(wmi_unified_t wmi_handle, + struct ext_scan_setbssi_hotlist_params * + photlist, int *buf_len) +{ + wmi_extscan_configure_hotlist_monitor_cmd_fixed_param *cmd = NULL; + wmi_extscan_hotlist_entry *dest_hotlist; + struct ap_threshold_params *src_ap = photlist->ap; + wmi_buf_t buf; + uint8_t *buf_ptr; + + int j, index = 0; + int cmd_len = 0; + int num_entries; + int min_entries = 0; + uint32_t numap = photlist->numAp; + int len = sizeof(*cmd); + + len += WMI_TLV_HDR_SIZE; + cmd_len = len; + + num_entries = wmi_get_hotlist_entries_per_page(wmi_handle, + cmd_len, + sizeof(*dest_hotlist)); + /* setbssid hotlist expects the bssid list + * to be non zero value + */ + if (!numap || (numap > WMI_WLAN_EXTSCAN_MAX_HOTLIST_APS)) { + WMI_LOGE("Invalid number of APs: %d", numap); + return QDF_STATUS_E_INVAL; + } + + /* Split the hot list entry pages and send multiple command + * requests if the buffer reaches the maximum request size + */ + while (index < numap) { + min_entries = QDF_MIN(num_entries, numap); + len += min_entries * sizeof(wmi_extscan_hotlist_entry); + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMI_LOGP("%s: wmi_buf_alloc failed", __func__); + return QDF_STATUS_E_FAILURE; + } + buf_ptr = (uint8_t *) wmi_buf_data(buf); + cmd = (wmi_extscan_configure_hotlist_monitor_cmd_fixed_param *) + buf_ptr; + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_extscan_configure_hotlist_monitor_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_extscan_configure_hotlist_monitor_cmd_fixed_param)); + + /* Multiple requests are sent until the num_entries_in_page + * matches the total_entries + */ + cmd->request_id = photlist->requestId; + cmd->vdev_id = photlist->sessionId; + cmd->total_entries = numap; + cmd->mode = 1; + cmd->num_entries_in_page = min_entries; + cmd->lost_ap_scan_count = photlist->lost_ap_sample_size; + cmd->first_entry_index = index; + + WMI_LOGD("%s: vdev id:%d total_entries: %d num_entries: %d lost_ap_sample_size: %d", + __func__, cmd->vdev_id, cmd->total_entries, + cmd->num_entries_in_page, + cmd->lost_ap_scan_count); + + buf_ptr += sizeof(*cmd); + WMITLV_SET_HDR(buf_ptr, + WMITLV_TAG_ARRAY_STRUC, + min_entries * sizeof(wmi_extscan_hotlist_entry)); + dest_hotlist = (wmi_extscan_hotlist_entry *) + (buf_ptr + WMI_TLV_HDR_SIZE); + + /* Populate bssid, channel info and rssi + * for the bssid's that are sent as hotlists. + */ + for (j = 0; j < min_entries; j++) { + WMITLV_SET_HDR(dest_hotlist, + WMITLV_TAG_STRUC_wmi_extscan_bucket_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_extscan_hotlist_entry)); + + dest_hotlist->min_rssi = src_ap->low; + WMI_CHAR_ARRAY_TO_MAC_ADDR(src_ap->bssid.bytes, + &dest_hotlist->bssid); + + WMI_LOGD("%s:channel:%d min_rssi %d", + __func__, dest_hotlist->channel, + dest_hotlist->min_rssi); + WMI_LOGD + ("%s: bssid mac_addr31to0: 0x%x, mac_addr47to32: 0x%x", + __func__, dest_hotlist->bssid.mac_addr31to0, + dest_hotlist->bssid.mac_addr47to32); + dest_hotlist++; + src_ap++; + } + buf_ptr += WMI_TLV_HDR_SIZE + + (min_entries * sizeof(wmi_extscan_hotlist_entry)); + + if (wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_EXTSCAN_CONFIGURE_HOTLIST_MONITOR_CMDID)) { + WMI_LOGE("%s: failed to send command", __func__); + wmi_buf_free(buf); + return QDF_STATUS_E_FAILURE; + } + index = index + min_entries; + num_entries = numap - min_entries; + len = cmd_len; + } + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS send_set_active_bpf_mode_cmd_tlv(wmi_unified_t wmi_handle, + uint8_t vdev_id, + FW_ACTIVE_BPF_MODE ucast_mode, + FW_ACTIVE_BPF_MODE mcast_bcast_mode) +{ + const WMITLV_TAG_ID tag_id = + WMITLV_TAG_STRUC_wmi_bpf_set_vdev_active_mode_cmd_fixed_param; + const uint32_t tlv_len = WMITLV_GET_STRUCT_TLVLEN( + wmi_bpf_set_vdev_active_mode_cmd_fixed_param); + QDF_STATUS status; + wmi_bpf_set_vdev_active_mode_cmd_fixed_param *cmd; + wmi_buf_t buf; + + WMI_LOGI("Sending WMI_BPF_SET_VDEV_ACTIVE_MODE_CMDID(%u, %d, %d)", + vdev_id, ucast_mode, mcast_bcast_mode); + + /* allocate command buffer */ + buf = wmi_buf_alloc(wmi_handle, sizeof(*cmd)); + if (!buf) { + WMI_LOGE("%s: wmi_buf_alloc failed", __func__); + return QDF_STATUS_E_NOMEM; + } + + /* set TLV header */ + cmd = (wmi_bpf_set_vdev_active_mode_cmd_fixed_param *)wmi_buf_data(buf); + WMITLV_SET_HDR(&cmd->tlv_header, tag_id, tlv_len); + + /* populate data */ + cmd->vdev_id = vdev_id; + cmd->uc_mode = ucast_mode; + cmd->mcbc_mode = mcast_bcast_mode; + + /* send to FW */ + status = wmi_unified_cmd_send(wmi_handle, buf, sizeof(*cmd), + WMI_BPF_SET_VDEV_ACTIVE_MODE_CMDID); + if (QDF_IS_STATUS_ERROR(status)) { + WMI_LOGE("Failed to send WMI_BPF_SET_VDEV_ACTIVE_MODE_CMDID:%d", + status); + wmi_buf_free(buf); + return status; + } + + WMI_LOGI("Sent WMI_BPF_SET_VDEV_ACTIVE_MODE_CMDID successfully"); + + return QDF_STATUS_SUCCESS; +} + +/** + * send_power_dbg_cmd_tlv() - send power debug commands + * @wmi_handle: wmi handle + * @param: wmi power debug parameter + * + * Send WMI_POWER_DEBUG_CMDID parameters to fw. + * + * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_** on error + */ +static +QDF_STATUS send_power_dbg_cmd_tlv(wmi_unified_t wmi_handle, + struct wmi_power_dbg_params *param) +{ + wmi_buf_t buf = NULL; + QDF_STATUS status; + int len, args_tlv_len; + uint8_t *buf_ptr; + uint8_t i; + wmi_pdev_wal_power_debug_cmd_fixed_param *cmd; + uint32_t *cmd_args; + + /* Prepare and send power debug cmd parameters */ + args_tlv_len = WMI_TLV_HDR_SIZE + param->num_args * sizeof(uint32_t); + len = sizeof(*cmd) + args_tlv_len; + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMI_LOGE("%s : wmi_buf_alloc failed", __func__); + return QDF_STATUS_E_NOMEM; + } + + buf_ptr = (uint8_t *) wmi_buf_data(buf); + cmd = (wmi_pdev_wal_power_debug_cmd_fixed_param *) buf_ptr; + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_pdev_wal_power_debug_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_pdev_wal_power_debug_cmd_fixed_param)); + + cmd->pdev_id = param->pdev_id; + cmd->module_id = param->module_id; + cmd->num_args = param->num_args; + buf_ptr += sizeof(*cmd); + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_UINT32, + (param->num_args * sizeof(uint32_t))); + cmd_args = (uint32_t *) (buf_ptr + WMI_TLV_HDR_SIZE); + WMI_LOGI("%s: %d num of args = ", __func__, param->num_args); + for (i = 0; (i < param->num_args && i < WMI_MAX_NUM_ARGS); i++) { + cmd_args[i] = param->args[i]; + WMI_LOGI("%d,", param->args[i]); + } + + status = wmi_unified_cmd_send(wmi_handle, buf, + len, WMI_PDEV_WAL_POWER_DEBUG_CMDID); + if (QDF_IS_STATUS_ERROR(status)) { + WMI_LOGE("wmi_unified_cmd_send WMI_PDEV_WAL_POWER_DEBUG_CMDID returned Error %d", + status); + goto error; + } + + return QDF_STATUS_SUCCESS; +error: + wmi_buf_free(buf); + + return status; +} + +/** + * init_cmd_send_tlv() - send initialization cmd to fw + * @wmi_handle: wmi handle + * @param tgt_res_cfg: pointer to target resource configuration + * @param num_mem_chunks: Number of memory chunks + * @param mem_chunks: pointer to target memory chunks + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +static QDF_STATUS init_cmd_send_tlv(wmi_unified_t wmi_handle, + target_resource_config *tgt_res_cfg, uint8_t num_mem_chunks, + struct wmi_host_mem_chunk *mem_chunks) +{ + wmi_buf_t buf; + wmi_init_cmd_fixed_param *cmd; + wmi_abi_version my_vers; + int num_whitelist; + uint8_t *buf_ptr; + wmi_resource_config *resource_cfg; + wlan_host_memory_chunk *host_mem_chunks; + uint32_t mem_chunk_len = 0; + uint16_t idx; + int len; + QDF_STATUS ret; + + len = sizeof(*cmd) + sizeof(wmi_resource_config) + WMI_TLV_HDR_SIZE; + mem_chunk_len = (sizeof(wlan_host_memory_chunk) * MAX_MEM_CHUNKS); + buf = wmi_buf_alloc(wmi_handle, len + mem_chunk_len); + if (!buf) { + qdf_print("%s: wmi_buf_alloc failed\n", __func__); + return QDF_STATUS_E_FAILURE; + } + + buf_ptr = (uint8_t *) wmi_buf_data(buf); + cmd = (wmi_init_cmd_fixed_param *) buf_ptr; + resource_cfg = (wmi_resource_config *) (buf_ptr + sizeof(*cmd)); + + host_mem_chunks = (wlan_host_memory_chunk *) + (buf_ptr + sizeof(*cmd) + sizeof(wmi_resource_config) + + WMI_TLV_HDR_SIZE); + + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_init_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN(wmi_init_cmd_fixed_param)); + + wmi_copy_resource_config(resource_cfg, tgt_res_cfg); + WMITLV_SET_HDR(&resource_cfg->tlv_header, + WMITLV_TAG_STRUC_wmi_resource_config, + WMITLV_GET_STRUCT_TLVLEN(wmi_resource_config)); + + for (idx = 0; idx < num_mem_chunks; ++idx) { + WMITLV_SET_HDR(&(host_mem_chunks[idx].tlv_header), + WMITLV_TAG_STRUC_wlan_host_memory_chunk, + WMITLV_GET_STRUCT_TLVLEN + (wlan_host_memory_chunk)); + host_mem_chunks[idx].ptr = mem_chunks[idx].paddr; + host_mem_chunks[idx].size = mem_chunks[idx].len; + host_mem_chunks[idx].req_id = mem_chunks[idx].req_id; + qdf_print("chunk %d len %d requested ,ptr 0x%x ", + idx, host_mem_chunks[idx].size, + host_mem_chunks[idx].ptr); + } + cmd->num_host_mem_chunks = num_mem_chunks; + len += (num_mem_chunks * sizeof(wlan_host_memory_chunk)); + WMITLV_SET_HDR((buf_ptr + sizeof(*cmd) + sizeof(wmi_resource_config)), + WMITLV_TAG_ARRAY_STRUC, + (sizeof(wlan_host_memory_chunk) * + num_mem_chunks)); + + num_whitelist = sizeof(version_whitelist) / + sizeof(wmi_whitelist_version_info); + my_vers.abi_version_0 = WMI_ABI_VERSION_0; + my_vers.abi_version_1 = WMI_ABI_VERSION_1; + my_vers.abi_version_ns_0 = WMI_ABI_VERSION_NS_0; + my_vers.abi_version_ns_1 = WMI_ABI_VERSION_NS_1; + my_vers.abi_version_ns_2 = WMI_ABI_VERSION_NS_2; + my_vers.abi_version_ns_3 = WMI_ABI_VERSION_NS_3; + +#ifdef CONFIG_MCL + wmi_cmp_and_set_abi_version(num_whitelist, version_whitelist, + &my_vers, + (struct _wmi_abi_version *)&wmi_handle->fw_abi_version, + &cmd->host_abi_vers); +#endif + qdf_print("%s: INIT_CMD version: %d, %d, 0x%x, 0x%x, 0x%x, 0x%x", + __func__, + WMI_VER_GET_MAJOR(cmd->host_abi_vers.abi_version_0), + WMI_VER_GET_MINOR(cmd->host_abi_vers.abi_version_0), + cmd->host_abi_vers.abi_version_ns_0, + cmd->host_abi_vers.abi_version_ns_1, + cmd->host_abi_vers.abi_version_ns_2, + cmd->host_abi_vers.abi_version_ns_3); + + /* Save version sent from host - + * Will be used to check ready event + */ +#ifdef CONFIG_MCL + qdf_mem_copy(&wmi_handle->final_abi_vers, &cmd->host_abi_vers, + sizeof(wmi_abi_version)); +#endif + ret = wmi_unified_cmd_send(wmi_handle, buf, len, WMI_INIT_CMDID); + if (QDF_IS_STATUS_ERROR(ret)) { + WMI_LOGE("wmi_unified_cmd_send WMI_INIT_CMDID returned Error %d", + ret); + wmi_buf_free(buf); + } + return ret; + +} + +/** + * save_service_bitmap_tlv() - save service bitmap + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * + * Return: None + */ +#ifdef WMI_TLV_AND_NON_TLV_SUPPORT +static +void save_service_bitmap_tlv(wmi_unified_t wmi_handle, void *evt_buf) +{ + WMI_SERVICE_READY_EVENTID_param_tlvs *param_buf; + param_buf = (WMI_SERVICE_READY_EVENTID_param_tlvs *) evt_buf; + + qdf_mem_copy(wmi_handle->wmi_service_bitmap, + param_buf->wmi_service_bitmap, + (WMI_SERVICE_BM_SIZE * sizeof(uint32_t))); +} +#else +static +void save_service_bitmap_tlv(wmi_unified_t wmi_handle, void *evt_buf) +{ + return; +} + +#endif + +/** + * is_service_enabled_tlv() - Check if service enabled + * @param wmi_handle: wmi handle + * @param service_id: service identifier + * + * Return: 1 enabled, 0 disabled + */ +#ifdef WMI_TLV_AND_NON_TLV_SUPPORT +static bool is_service_enabled_tlv(wmi_unified_t wmi_handle, + uint32_t service_id) +{ + return WMI_SERVICE_IS_ENABLED(wmi_handle->wmi_service_bitmap, + service_id); +} +#else +static bool is_service_enabled_tlv(wmi_unified_t wmi_handle, + uint32_t service_id) +{ + return false; +} +#endif + +/** + * extract_service_ready_tlv() - extract service ready event + * @wmi_handle: wmi handle + * @param evt_buf: pointer to received event buffer + * @param cap: pointer to hold target capability information extracted from even + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +static QDF_STATUS extract_service_ready_tlv(wmi_unified_t wmi_handle, + void *evt_buf, target_capability_info *cap) +{ + WMI_SERVICE_READY_EVENTID_param_tlvs *param_buf; + wmi_service_ready_event_fixed_param *ev; + + + param_buf = (WMI_SERVICE_READY_EVENTID_param_tlvs *) evt_buf; + + ev = (wmi_service_ready_event_fixed_param *) param_buf->fixed_param; + if (!ev) { + qdf_print("%s: wmi_buf_alloc failed\n", __func__); + return QDF_STATUS_E_FAILURE; + } + + cap->phy_capability = ev->phy_capability; + cap->max_frag_entry = ev->max_frag_entry; + cap->num_rf_chains = ev->num_rf_chains; + cap->ht_cap_info = ev->ht_cap_info; + cap->vht_cap_info = ev->vht_cap_info; + cap->vht_supp_mcs = ev->vht_supp_mcs; + cap->hw_min_tx_power = ev->hw_min_tx_power; + cap->hw_max_tx_power = ev->hw_max_tx_power; + cap->sys_cap_info = ev->sys_cap_info; + cap->min_pkt_size_enable = ev->min_pkt_size_enable; + cap->max_bcn_ie_size = ev->max_bcn_ie_size; + cap->max_num_scan_channels = ev->max_num_scan_channels; + cap->max_supported_macs = ev->max_supported_macs; + cap->wmi_fw_sub_feat_caps = ev->wmi_fw_sub_feat_caps; + cap->txrx_chainmask = ev->txrx_chainmask; + cap->default_dbs_hw_mode_index = ev->default_dbs_hw_mode_index; + cap->num_msdu_desc = ev->num_msdu_desc; + + return QDF_STATUS_SUCCESS; +} + +/** + * extract_hal_reg_cap_tlv() - extract HAL registered capabilities + * @wmi_handle: wmi handle + * @param evt_buf: Pointer to event buffer + * @param cap: pointer to hold HAL reg capabilities + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +static QDF_STATUS extract_hal_reg_cap_tlv(wmi_unified_t wmi_handle, + void *evt_buf, TARGET_HAL_REG_CAPABILITIES *cap) +{ + WMI_SERVICE_READY_EVENTID_param_tlvs *param_buf; + + param_buf = (WMI_SERVICE_READY_EVENTID_param_tlvs *) evt_buf; + + qdf_mem_copy(cap, (((uint8_t *)param_buf->hal_reg_capabilities) + + sizeof(uint32_t)), + sizeof(TARGET_HAL_REG_CAPABILITIES)); + + return QDF_STATUS_SUCCESS; +} + +/** + * extract_host_mem_req_tlv() - Extract host memory request event + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * @param num_entries: pointer to hold number of entries requested + * + * Return: Number of entries requested + */ +static host_mem_req *extract_host_mem_req_tlv(wmi_unified_t wmi_handle, + void *evt_buf, uint8_t *num_entries) +{ + WMI_SERVICE_READY_EVENTID_param_tlvs *param_buf; + wmi_service_ready_event_fixed_param *ev; + + param_buf = (WMI_SERVICE_READY_EVENTID_param_tlvs *) evt_buf; + + ev = (wmi_service_ready_event_fixed_param *) param_buf->fixed_param; + if (!ev) { + qdf_print("%s: wmi_buf_alloc failed\n", __func__); + return NULL; + } + + *num_entries = ev->num_mem_reqs; + + return (host_mem_req *)param_buf->mem_reqs; +} + +/** + * save_fw_version_in_service_ready_tlv() - Save fw version in service + * ready function + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +static QDF_STATUS +save_fw_version_in_service_ready_tlv(wmi_unified_t wmi_handle, void *evt_buf) +{ + WMI_SERVICE_READY_EVENTID_param_tlvs *param_buf; + wmi_service_ready_event_fixed_param *ev; + + + param_buf = (WMI_SERVICE_READY_EVENTID_param_tlvs *) evt_buf; + + ev = (wmi_service_ready_event_fixed_param *) param_buf->fixed_param; + if (!ev) { + qdf_print("%s: wmi_buf_alloc failed\n", __func__); + return QDF_STATUS_E_FAILURE; + } + +#ifdef CONFIG_MCL + /*Save fw version from service ready message */ + /*This will be used while sending INIT message */ + qdf_mem_copy(&wmi_handle->fw_abi_version, &ev->fw_abi_vers, + sizeof(wmi_handle->fw_abi_version)); +#endif + return QDF_STATUS_SUCCESS; +} + +/** + * ready_extract_init_status_tlv() - Extract init status from ready event + * @wmi_handle: wmi handle + * @param evt_buf: Pointer to event buffer + * + * Return: ready status + */ +static uint32_t ready_extract_init_status_tlv(wmi_unified_t wmi_handle, + void *evt_buf) +{ + WMI_READY_EVENTID_param_tlvs *param_buf = NULL; + wmi_ready_event_fixed_param *ev = NULL; + + + param_buf = (WMI_READY_EVENTID_param_tlvs *) evt_buf; + ev = param_buf->fixed_param; + + qdf_print("%s:%d\n", __func__, ev->status); + + return ev->status; +} + +/** + * ready_extract_mac_addr_tlv() - extract mac address from ready event + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * @param macaddr: Pointer to hold MAC address + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +static QDF_STATUS ready_extract_mac_addr_tlv(wmi_unified_t wmi_hamdle, + void *evt_buf, uint8_t *macaddr) +{ + WMI_READY_EVENTID_param_tlvs *param_buf = NULL; + wmi_ready_event_fixed_param *ev = NULL; + + + param_buf = (WMI_READY_EVENTID_param_tlvs *) evt_buf; + ev = param_buf->fixed_param; + + WMI_MAC_ADDR_TO_CHAR_ARRAY(&ev->mac_addr, macaddr); + + return QDF_STATUS_SUCCESS; +} + +/** + * extract_dbglog_data_len_tlv() - extract debuglog data length + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * + * Return: length + */ +static uint8_t *extract_dbglog_data_len_tlv(wmi_unified_t wmi_handle, + void *evt_buf, uint16_t *len) +{ + WMI_DEBUG_MESG_EVENTID_param_tlvs *param_buf; + + param_buf = (WMI_DEBUG_MESG_EVENTID_param_tlvs *) evt_buf; + + *len = param_buf->num_bufp; + + return param_buf->bufp; +} + +/** + * extract_vdev_start_resp_tlv() - extract vdev start response + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * @param vdev_rsp: Pointer to hold vdev response + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +static QDF_STATUS extract_vdev_start_resp_tlv(wmi_unified_t wmi_handle, + void *evt_buf, wmi_host_vdev_start_resp *vdev_rsp) +{ + WMI_VDEV_START_RESP_EVENTID_param_tlvs *param_buf; + wmi_vdev_start_response_event_fixed_param *ev; + + param_buf = (WMI_VDEV_START_RESP_EVENTID_param_tlvs *) evt_buf; + if (!param_buf) { + qdf_print("Invalid start response event buffer\n"); + return QDF_STATUS_E_INVAL; + } + + ev = param_buf->fixed_param; + if (!ev) { + qdf_print("Invalid start response event buffer\n"); + return QDF_STATUS_E_INVAL; + } + + qdf_mem_zero(vdev_rsp, sizeof(*vdev_rsp)); + + vdev_rsp->vdev_id = ev->vdev_id; + vdev_rsp->requestor_id = ev->requestor_id; + vdev_rsp->resp_type = ev->resp_type; + vdev_rsp->status = ev->status; + vdev_rsp->chain_mask = ev->chain_mask; + vdev_rsp->smps_mode = ev->smps_mode; + vdev_rsp->mac_id = ev->mac_id; + vdev_rsp->cfgd_tx_streams = ev->cfgd_tx_streams; + vdev_rsp->cfgd_rx_streams = ev->cfgd_rx_streams; + + return QDF_STATUS_SUCCESS; +} + +/** + * extract_tbttoffset_update_params_tlv() - extract tbtt offset update param + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * @param vdev_map: Pointer to hold vdev map + * @param tbttoffset_list: Pointer to tbtt offset list + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +static QDF_STATUS extract_tbttoffset_update_params_tlv(void *wmi_hdl, + void *evt_buf, uint32_t *vdev_map, uint32_t **tbttoffset_list) +{ + WMI_TBTTOFFSET_UPDATE_EVENTID_param_tlvs *param_buf; + wmi_tbtt_offset_event_fixed_param *tbtt_offset_event; + + param_buf = (WMI_TBTTOFFSET_UPDATE_EVENTID_param_tlvs *) evt_buf; + if (!param_buf) { + qdf_print("Invalid tbtt update event buffer\n"); + return QDF_STATUS_E_INVAL; + } + tbtt_offset_event = param_buf->fixed_param; + + *vdev_map = tbtt_offset_event->vdev_map; + *tbttoffset_list = param_buf->tbttoffset_list; + + return QDF_STATUS_SUCCESS; +} + +/** + * extract_mgmt_rx_params_tlv() - extract management rx params from event + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * @param hdr: Pointer to hold header + * @param bufp: Pointer to hold pointer to rx param buffer + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +static QDF_STATUS extract_mgmt_rx_params_tlv(wmi_unified_t wmi_handle, + void *evt_buf, wmi_host_mgmt_rx_hdr *hdr, uint8_t **bufp) +{ + WMI_MGMT_RX_EVENTID_param_tlvs *param_tlvs = NULL; + wmi_mgmt_rx_hdr *ev_hdr = NULL; + + param_tlvs = (WMI_MGMT_RX_EVENTID_param_tlvs *) evt_buf; + if (!param_tlvs) { + WMI_LOGE("Get NULL point message from FW"); + return QDF_STATUS_E_INVAL; + } + + ev_hdr = param_tlvs->hdr; + if (!hdr) { + WMI_LOGE("Rx event is NULL"); + return QDF_STATUS_E_INVAL; + } + + + hdr->channel = ev_hdr->channel; + hdr->snr = ev_hdr->snr; + hdr->rate = ev_hdr->rate; + hdr->phy_mode = ev_hdr->phy_mode; + hdr->buf_len = ev_hdr->buf_len; + hdr->status = ev_hdr->status; + hdr->flags = ev_hdr->flags; + hdr->rssi = ev_hdr->rssi; + hdr->tsf_delta = ev_hdr->tsf_delta; + qdf_mem_copy(hdr->rssi_ctl, ev_hdr->rssi_ctl, sizeof(hdr->rssi_ctl)); + + *bufp = param_tlvs->bufp; + + return QDF_STATUS_SUCCESS; +} + +/** + * extract_vdev_stopped_param_tlv() - extract vdev stop param from event + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * @param vdev_id: Pointer to hold vdev identifier + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +static QDF_STATUS extract_vdev_stopped_param_tlv(wmi_unified_t wmi_handle, + void *evt_buf, uint32_t *vdev_id) +{ + WMI_VDEV_STOPPED_EVENTID_param_tlvs *param_buf; + wmi_vdev_stopped_event_fixed_param *resp_event; + + param_buf = (WMI_VDEV_STOPPED_EVENTID_param_tlvs *) evt_buf; + if (!param_buf) { + WMI_LOGE("Invalid event buffer"); + return QDF_STATUS_E_INVAL; + } + resp_event = param_buf->fixed_param; + *vdev_id = resp_event->vdev_id; + + return QDF_STATUS_SUCCESS; +} + +/** + * extract_vdev_roam_param_tlv() - extract vdev roam param from event + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * @param param: Pointer to hold roam param + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +static QDF_STATUS extract_vdev_roam_param_tlv(wmi_unified_t wmi_handle, + void *evt_buf, wmi_host_roam_event *param) +{ + WMI_ROAM_EVENTID_param_tlvs *param_buf; + wmi_roam_event_fixed_param *evt; + + param_buf = (WMI_ROAM_EVENTID_param_tlvs *) evt_buf; + if (!param_buf) { + WMI_LOGE("Invalid roam event buffer"); + return QDF_STATUS_E_INVAL; + } + + evt = param_buf->fixed_param; + qdf_mem_zero(param, sizeof(*param)); + + param->vdev_id = evt->vdev_id; + param->reason = evt->reason; + param->rssi = evt->rssi; + + return QDF_STATUS_SUCCESS; +} + +/** + * extract_vdev_scan_ev_param_tlv() - extract vdev scan param from event + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * @param param: Pointer to hold vdev scan param + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +static QDF_STATUS extract_vdev_scan_ev_param_tlv(wmi_unified_t wmi_handle, + void *evt_buf, wmi_host_scan_event *param) +{ + WMI_SCAN_EVENTID_param_tlvs *param_buf = NULL; + wmi_scan_event_fixed_param *evt = NULL; + + param_buf = (WMI_SCAN_EVENTID_param_tlvs *) evt_buf; + evt = param_buf->fixed_param; + + qdf_mem_zero(param, sizeof(*param)); + switch (evt->event) { + case WMI_SCAN_EVENT_STARTED: + param->event = WMI_HOST_SCAN_EVENT_STARTED; + break; + case WMI_SCAN_EVENT_COMPLETED: + param->event = WMI_HOST_SCAN_EVENT_COMPLETED; + break; + case WMI_SCAN_EVENT_BSS_CHANNEL: + param->event = WMI_HOST_SCAN_EVENT_BSS_CHANNEL; + break; + case WMI_SCAN_EVENT_FOREIGN_CHANNEL: + param->event = WMI_HOST_SCAN_EVENT_FOREIGN_CHANNEL; + break; + case WMI_SCAN_EVENT_DEQUEUED: + param->event = WMI_HOST_SCAN_EVENT_DEQUEUED; + break; + case WMI_SCAN_EVENT_PREEMPTED: + param->event = WMI_HOST_SCAN_EVENT_PREEMPTED; + break; + case WMI_SCAN_EVENT_START_FAILED: + param->event = WMI_HOST_SCAN_EVENT_START_FAILED; + break; + case WMI_SCAN_EVENT_RESTARTED: + param->event = WMI_HOST_SCAN_EVENT_RESTARTED; + break; + case WMI_HOST_SCAN_EVENT_FOREIGN_CHANNEL_EXIT: + param->event = WMI_HOST_SCAN_EVENT_FOREIGN_CHANNEL_EXIT; + break; + case WMI_SCAN_EVENT_MAX: + default: + param->event = WMI_HOST_SCAN_EVENT_MAX; + break; + }; + + switch (evt->reason) { + case WMI_SCAN_REASON_NONE: + param->reason = WMI_HOST_SCAN_REASON_NONE; + break; + case WMI_SCAN_REASON_COMPLETED: + param->reason = WMI_HOST_SCAN_REASON_COMPLETED; + break; + case WMI_SCAN_REASON_CANCELLED: + param->reason = WMI_HOST_SCAN_REASON_CANCELLED; + break; + case WMI_SCAN_REASON_PREEMPTED: + param->reason = WMI_HOST_SCAN_REASON_PREEMPTED; + break; + case WMI_SCAN_REASON_TIMEDOUT: + param->reason = WMI_HOST_SCAN_REASON_TIMEDOUT; + break; + case WMI_SCAN_REASON_INTERNAL_FAILURE: + param->reason = WMI_HOST_SCAN_REASON_INTERNAL_FAILURE; + break; + case WMI_SCAN_REASON_MAX: + default: + param->reason = WMI_HOST_SCAN_REASON_MAX; + break; + }; + + param->channel_freq = evt->channel_freq; + param->requestor = evt->requestor; + param->scan_id = evt->scan_id; + param->vdev_id = evt->vdev_id; + + return QDF_STATUS_SUCCESS; +} + +/** + * extract_mgmt_tx_compl_param_tlv() - extract MGMT tx completion event params + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * @param param: Pointer to hold MGMT TX completion params + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +static QDF_STATUS extract_mgmt_tx_compl_param_tlv(wmi_unified_t wmi_handle, + void *evt_buf, wmi_host_mgmt_tx_compl_event *param) +{ + WMI_MGMT_TX_COMPLETION_EVENTID_param_tlvs *param_buf; + wmi_mgmt_tx_compl_event_fixed_param *cmpl_params; + + param_buf = (WMI_MGMT_TX_COMPLETION_EVENTID_param_tlvs *) + evt_buf; + if (!param_buf) { + WMI_LOGE("%s: Invalid mgmt Tx completion event", __func__); + return QDF_STATUS_E_INVAL; + } + cmpl_params = param_buf->fixed_param; + + param->desc_id = cmpl_params->desc_id; + param->status = cmpl_params->status; + + return QDF_STATUS_SUCCESS; +} + +/** + * extract_swba_vdev_map_tlv() - extract swba vdev map from event + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * @param vdev_map: Pointer to hold vdev map + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +static QDF_STATUS extract_swba_vdev_map_tlv(wmi_unified_t wmi_handle, + void *evt_buf, uint32_t *vdev_map) +{ + WMI_HOST_SWBA_EVENTID_param_tlvs *param_buf; + wmi_host_swba_event_fixed_param *swba_event; + + param_buf = (WMI_HOST_SWBA_EVENTID_param_tlvs *) evt_buf; + if (!param_buf) { + WMI_LOGE("Invalid swba event buffer"); + return QDF_STATUS_E_INVAL; + } + swba_event = param_buf->fixed_param; + *vdev_map = swba_event->vdev_map; + + return QDF_STATUS_SUCCESS; +} + +/** + * extract_swba_tim_info_tlv() - extract swba tim info from event + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * @param idx: Index to bcn info + * @param tim_info: Pointer to hold tim info + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +static QDF_STATUS extract_swba_tim_info_tlv(wmi_unified_t wmi_handle, + void *evt_buf, uint32_t idx, wmi_host_tim_info *tim_info) +{ + WMI_HOST_SWBA_EVENTID_param_tlvs *param_buf; + wmi_tim_info *tim_info_ev; + + param_buf = (WMI_HOST_SWBA_EVENTID_param_tlvs *) evt_buf; + if (!param_buf) { + WMI_LOGE("Invalid swba event buffer"); + return QDF_STATUS_E_INVAL; + } + + tim_info_ev = ¶m_buf->tim_info[idx]; + + tim_info->tim_len = tim_info_ev->tim_len; + tim_info->tim_mcast = tim_info_ev->tim_mcast; + qdf_mem_copy(tim_info->tim_bitmap, tim_info_ev->tim_bitmap, + (sizeof(uint32_t) * WMI_TIM_BITMAP_ARRAY_SIZE)); + tim_info->tim_changed = tim_info_ev->tim_changed; + tim_info->tim_num_ps_pending = tim_info_ev->tim_num_ps_pending; + + return QDF_STATUS_SUCCESS; +} + +/** + * extract_swba_noa_info_tlv() - extract swba NoA information from event + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * @param idx: Index to bcn info + * @param p2p_desc: Pointer to hold p2p NoA info + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +static QDF_STATUS extract_swba_noa_info_tlv(wmi_unified_t wmi_handle, + void *evt_buf, uint32_t idx, wmi_host_p2p_noa_info *p2p_desc) +{ + WMI_HOST_SWBA_EVENTID_param_tlvs *param_buf; + wmi_p2p_noa_info *p2p_noa_info; + uint8_t i = 0; + + param_buf = (WMI_HOST_SWBA_EVENTID_param_tlvs *) evt_buf; + if (!param_buf) { + WMI_LOGE("Invalid swba event buffer"); + return QDF_STATUS_E_INVAL; + } + + p2p_noa_info = ¶m_buf->p2p_noa_info[idx]; + + p2p_desc->modified = false; + p2p_desc->num_descriptors = 0; + if (WMI_UNIFIED_NOA_ATTR_IS_MODIFIED(p2p_noa_info)) { + p2p_desc->modified = true; + p2p_desc->index = + (uint8_t) WMI_UNIFIED_NOA_ATTR_INDEX_GET(p2p_noa_info); + p2p_desc->oppPS = + (uint8_t) WMI_UNIFIED_NOA_ATTR_OPP_PS_GET(p2p_noa_info); + p2p_desc->ctwindow = + (uint8_t) WMI_UNIFIED_NOA_ATTR_CTWIN_GET(p2p_noa_info); + p2p_desc->num_descriptors = + (uint8_t) WMI_UNIFIED_NOA_ATTR_NUM_DESC_GET + (p2p_noa_info); + for (i = 0; i < p2p_desc->num_descriptors; i++) { + p2p_desc->noa_descriptors[i].type_count = + (uint8_t) p2p_noa_info->noa_descriptors[i]. + type_count; + p2p_desc->noa_descriptors[i].duration = + p2p_noa_info->noa_descriptors[i].duration; + p2p_desc->noa_descriptors[i].interval = + p2p_noa_info->noa_descriptors[i].interval; + p2p_desc->noa_descriptors[i].start_time = + p2p_noa_info->noa_descriptors[i].start_time; + } + } + + return QDF_STATUS_SUCCESS; +} + +/** + * extract_peer_sta_kickout_ev_tlv() - extract peer sta kickout event + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * @param ev: Pointer to hold peer param + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +static QDF_STATUS extract_peer_sta_kickout_ev_tlv(wmi_unified_t wmi_handle, + void *evt_buf, wmi_host_peer_sta_kickout_event *ev) +{ + WMI_PEER_STA_KICKOUT_EVENTID_param_tlvs *param_buf = NULL; + wmi_peer_sta_kickout_event_fixed_param *kickout_event = NULL; + + param_buf = (WMI_PEER_STA_KICKOUT_EVENTID_param_tlvs *) evt_buf; + kickout_event = param_buf->fixed_param; + + WMI_MAC_ADDR_TO_CHAR_ARRAY(&kickout_event->peer_macaddr, + ev->peer_macaddr); + + ev->reason = kickout_event->reason; + ev->rssi = kickout_event->rssi; + + return QDF_STATUS_SUCCESS; +} + +/** + * extract_all_stats_counts_tlv() - extract all stats count from event + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * @param stats_param: Pointer to hold stats count + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +static QDF_STATUS extract_all_stats_counts_tlv(wmi_unified_t wmi_handle, + void *evt_buf, wmi_host_stats_event *stats_param) +{ + WMI_UPDATE_STATS_EVENTID_param_tlvs *param_buf; + wmi_stats_event_fixed_param *ev; + + param_buf = (WMI_UPDATE_STATS_EVENTID_param_tlvs *) evt_buf; + + ev = (wmi_stats_event_fixed_param *) param_buf->fixed_param; + if (!ev) { + WMI_LOGE("%s: Failed to alloc memory\n", __func__); + return QDF_STATUS_E_FAILURE; + } + + switch (ev->stats_id) { + case WMI_REQUEST_PEER_STAT: + stats_param->stats_id = WMI_HOST_REQUEST_PEER_STAT; + break; + + case WMI_REQUEST_AP_STAT: + stats_param->stats_id = WMI_HOST_REQUEST_AP_STAT; + break; + + case WMI_REQUEST_PDEV_STAT: + stats_param->stats_id = WMI_HOST_REQUEST_PDEV_STAT; + break; + + case WMI_REQUEST_VDEV_STAT: + stats_param->stats_id = WMI_HOST_REQUEST_VDEV_STAT; + break; + + case WMI_REQUEST_BCNFLT_STAT: + stats_param->stats_id = WMI_HOST_REQUEST_BCNFLT_STAT; + break; + + case WMI_REQUEST_VDEV_RATE_STAT: + stats_param->stats_id = WMI_HOST_REQUEST_VDEV_RATE_STAT; + break; + + default: + stats_param->stats_id = 0; + break; + + } + + stats_param->num_pdev_stats = ev->num_pdev_stats; + stats_param->num_pdev_ext_stats = 0; + stats_param->num_vdev_stats = ev->num_vdev_stats; + stats_param->num_peer_stats = ev->num_peer_stats; + stats_param->num_bcnflt_stats = ev->num_bcnflt_stats; + stats_param->num_chan_stats = ev->num_chan_stats; + + return QDF_STATUS_SUCCESS; +} + +/** + * extract_pdev_stats_tlv() - extract pdev stats from event + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * @param index: Index into pdev stats + * @param pdev_stats: Pointer to hold pdev stats + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +static QDF_STATUS extract_pdev_stats_tlv(wmi_unified_t wmi_handle, + void *evt_buf, uint32_t index, wmi_host_pdev_stats *pdev_stats) +{ + return QDF_STATUS_SUCCESS; +} + +/** + * extract_pdev_ext_stats_tlv() - extract extended pdev stats from event + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * @param index: Index into extended pdev stats + * @param pdev_ext_stats: Pointer to hold extended pdev stats + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +static QDF_STATUS extract_pdev_ext_stats_tlv(wmi_unified_t wmi_handle, + void *evt_buf, uint32_t index, wmi_host_pdev_ext_stats *pdev_ext_stats) +{ + return QDF_STATUS_SUCCESS; +} + +/** + * extract_vdev_stats_tlv() - extract vdev stats from event + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * @param index: Index into vdev stats + * @param vdev_stats: Pointer to hold vdev stats + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +static QDF_STATUS extract_vdev_stats_tlv(wmi_unified_t wmi_handle, + void *evt_buf, uint32_t index, wmi_host_vdev_stats *vdev_stats) +{ + WMI_UPDATE_STATS_EVENTID_param_tlvs *param_buf; + wmi_stats_event_fixed_param *ev_param; + uint8_t *data; + + param_buf = (WMI_UPDATE_STATS_EVENTID_param_tlvs *) evt_buf; + ev_param = (wmi_stats_event_fixed_param *) param_buf->fixed_param; + data = (uint8_t *) param_buf->data; + + if (index < ev_param->num_vdev_stats) { + wmi_vdev_stats *ev = (wmi_vdev_stats *) ((data) + + ((ev_param->num_pdev_stats) * + sizeof(wmi_pdev_stats)) + + (index * sizeof(wmi_vdev_stats))); + + vdev_stats->vdev_id = ev->vdev_id; + vdev_stats->vdev_snr.bcn_snr = ev->vdev_snr.bcn_snr; + vdev_stats->vdev_snr.dat_snr = ev->vdev_snr.dat_snr; + + OS_MEMCPY(vdev_stats->tx_frm_cnt, ev->tx_frm_cnt, + sizeof(ev->tx_frm_cnt)); + vdev_stats->rx_frm_cnt = ev->rx_frm_cnt; + OS_MEMCPY(vdev_stats->multiple_retry_cnt, + ev->multiple_retry_cnt, + sizeof(ev->multiple_retry_cnt)); + OS_MEMCPY(vdev_stats->fail_cnt, ev->fail_cnt, + sizeof(ev->fail_cnt)); + vdev_stats->rts_fail_cnt = ev->rts_fail_cnt; + vdev_stats->rts_succ_cnt = ev->rts_succ_cnt; + vdev_stats->rx_err_cnt = ev->rx_err_cnt; + vdev_stats->rx_discard_cnt = ev->rx_discard_cnt; + vdev_stats->ack_fail_cnt = ev->ack_fail_cnt; + OS_MEMCPY(vdev_stats->tx_rate_history, ev->tx_rate_history, + sizeof(ev->tx_rate_history)); + OS_MEMCPY(vdev_stats->bcn_rssi_history, ev->bcn_rssi_history, + sizeof(ev->bcn_rssi_history)); + + } + + return QDF_STATUS_SUCCESS; +} + +/** + * extract_peer_stats_tlv() - extract peer stats from event + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * @param index: Index into peer stats + * @param peer_stats: Pointer to hold peer stats + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +static QDF_STATUS extract_peer_stats_tlv(wmi_unified_t wmi_handle, + void *evt_buf, uint32_t index, wmi_host_peer_stats *peer_stats) +{ + WMI_UPDATE_STATS_EVENTID_param_tlvs *param_buf; + wmi_stats_event_fixed_param *ev_param; + uint8_t *data; + + param_buf = (WMI_UPDATE_STATS_EVENTID_param_tlvs *) evt_buf; + ev_param = (wmi_stats_event_fixed_param *) param_buf->fixed_param; + data = (uint8_t *) param_buf->data; + + if (index < ev_param->num_peer_stats) { + wmi_peer_stats *ev = (wmi_peer_stats *) ((data) + + ((ev_param->num_pdev_stats) * sizeof(wmi_pdev_stats)) + + ((ev_param->num_vdev_stats) * sizeof(wmi_vdev_stats)) + + (index * sizeof(wmi_peer_stats))); + + OS_MEMSET(peer_stats, 0, sizeof(wmi_host_peer_stats)); + + OS_MEMCPY(&(peer_stats->peer_macaddr), + &(ev->peer_macaddr), sizeof(wmi_mac_addr)); + + peer_stats->peer_rssi = ev->peer_rssi; + peer_stats->peer_tx_rate = ev->peer_tx_rate; + peer_stats->peer_rx_rate = ev->peer_rx_rate; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * extract_bcnflt_stats_tlv() - extract bcn fault stats from event + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * @param index: Index into bcn fault stats + * @param bcnflt_stats: Pointer to hold bcn fault stats + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +static QDF_STATUS extract_bcnflt_stats_tlv(wmi_unified_t wmi_handle, + void *evt_buf, uint32_t index, wmi_host_bcnflt_stats *peer_stats) +{ + return QDF_STATUS_SUCCESS; +} + +/** + * extract_peer_extd_stats_tlv() - extract extended peer stats from event + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * @param index: Index into extended peer stats + * @param peer_extd_stats: Pointer to hold extended peer stats + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +static QDF_STATUS extract_peer_extd_stats_tlv(wmi_unified_t wmi_handle, + void *evt_buf, uint32_t index, + wmi_host_peer_extd_stats *peer_extd_stats) +{ + return QDF_STATUS_SUCCESS; +} + +/** + * extract_chan_stats_tlv() - extract chan stats from event + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * @param index: Index into chan stats + * @param vdev_extd_stats: Pointer to hold chan stats + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +static QDF_STATUS extract_chan_stats_tlv(wmi_unified_t wmi_handle, + void *evt_buf, uint32_t index, wmi_host_chan_stats *chan_stats) +{ + WMI_UPDATE_STATS_EVENTID_param_tlvs *param_buf; + wmi_stats_event_fixed_param *ev_param; + uint8_t *data; + + param_buf = (WMI_UPDATE_STATS_EVENTID_param_tlvs *) evt_buf; + ev_param = (wmi_stats_event_fixed_param *) param_buf->fixed_param; + data = (uint8_t *) param_buf->data; + + if (index < ev_param->num_chan_stats) { + wmi_chan_stats *ev = (wmi_chan_stats *) ((data) + + ((ev_param->num_pdev_stats) * sizeof(wmi_pdev_stats)) + + ((ev_param->num_vdev_stats) * sizeof(wmi_vdev_stats)) + + ((ev_param->num_peer_stats) * sizeof(wmi_peer_stats)) + + (index * sizeof(wmi_chan_stats))); + + + /* Non-TLV doesnt have num_chan_stats */ + chan_stats->chan_mhz = ev->chan_mhz; + chan_stats->sampling_period_us = ev->sampling_period_us; + chan_stats->rx_clear_count = ev->rx_clear_count; + chan_stats->tx_duration_us = ev->tx_duration_us; + chan_stats->rx_duration_us = ev->rx_duration_us; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * extract_profile_ctx_tlv() - extract profile context from event + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * @idx: profile stats index to extract + * @param profile_ctx: Pointer to hold profile context + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +static QDF_STATUS extract_profile_ctx_tlv(wmi_unified_t wmi_handle, + void *evt_buf, wmi_host_wlan_profile_ctx_t *profile_ctx) +{ + return QDF_STATUS_SUCCESS; +} + +/** + * extract_profile_data_tlv() - extract profile data from event + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * @param profile_data: Pointer to hold profile data + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +static QDF_STATUS extract_profile_data_tlv(wmi_unified_t wmi_handle, + void *evt_buf, uint8_t idx, wmi_host_wlan_profile_t *profile_data) +{ + + return QDF_STATUS_SUCCESS; +} + +/** + * extract_chan_info_event_tlv() - extract chan information from event + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * @param chan_info: Pointer to hold chan information + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +static QDF_STATUS extract_chan_info_event_tlv(wmi_unified_t wmi_handle, + void *evt_buf, wmi_host_chan_info_event *chan_info) +{ + WMI_CHAN_INFO_EVENTID_param_tlvs *param_buf; + wmi_chan_info_event_fixed_param *ev; + + param_buf = (WMI_CHAN_INFO_EVENTID_param_tlvs *) evt_buf; + + ev = (wmi_chan_info_event_fixed_param *) param_buf->fixed_param; + if (!ev) { + WMI_LOGE("%s: Failed to allocmemory\n", __func__); + return QDF_STATUS_E_FAILURE; + } + + chan_info->err_code = ev->err_code; + chan_info->freq = ev->freq; + chan_info->cmd_flags = ev->cmd_flags; + chan_info->noise_floor = ev->noise_floor; + chan_info->rx_clear_count = ev->rx_clear_count; + chan_info->cycle_count = ev->cycle_count; + + return QDF_STATUS_SUCCESS; +} + +/** + * extract_channel_hopping_event_tlv() - extract channel hopping param + * from event + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * @param ch_hopping: Pointer to hold channel hopping param + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +static QDF_STATUS extract_channel_hopping_event_tlv(wmi_unified_t wmi_handle, + void *evt_buf, wmi_host_pdev_channel_hopping_event *chan_info) +{ + return QDF_STATUS_SUCCESS; +} + +#ifdef WMI_INTERFACE_EVENT_LOGGING +static bool is_management_record_tlv(uint32_t cmd_id) +{ + if ((cmd_id == WMI_MGMT_TX_SEND_CMDID) || + (cmd_id == WMI_MGMT_TX_COMPLETION_EVENTID)) + return true; + + return false; +} +#endif + +static uint16_t wmi_tag_vdev_set_cmd(wmi_unified_t wmi_hdl, wmi_buf_t buf) +{ + wmi_vdev_set_param_cmd_fixed_param *set_cmd; + + set_cmd = (wmi_vdev_set_param_cmd_fixed_param *)wmi_buf_data(buf); + + switch (set_cmd->param_id) { + case WMI_VDEV_PARAM_LISTEN_INTERVAL: + case WMI_VDEV_PARAM_DTIM_POLICY: + return HTC_TX_PACKET_TAG_AUTO_PM; + default: + break; + } + + return 0; +} + +static uint16_t wmi_tag_sta_powersave_cmd(wmi_unified_t wmi_hdl, wmi_buf_t buf) +{ + wmi_sta_powersave_param_cmd_fixed_param *ps_cmd; + + ps_cmd = (wmi_sta_powersave_param_cmd_fixed_param *)wmi_buf_data(buf); + + switch (ps_cmd->param) { + case WMI_STA_PS_PARAM_TX_WAKE_THRESHOLD: + case WMI_STA_PS_PARAM_INACTIVITY_TIME: + case WMI_STA_PS_ENABLE_QPOWER: + return HTC_TX_PACKET_TAG_AUTO_PM; + default: + break; + } + + return 0; +} + +static uint16_t wmi_tag_common_cmd(wmi_unified_t wmi_hdl, wmi_buf_t buf, + uint32_t cmd_id) +{ + if (qdf_atomic_read(&wmi_hdl->is_wow_bus_suspended)) + return 0; + + switch (cmd_id) { + case WMI_VDEV_SET_PARAM_CMDID: + return wmi_tag_vdev_set_cmd(wmi_hdl, buf); + case WMI_STA_POWERSAVE_PARAM_CMDID: + return wmi_tag_sta_powersave_cmd(wmi_hdl, buf); + default: + break; + } + + return 0; +} + +static uint16_t wmi_tag_fw_hang_cmd(wmi_unified_t wmi_handle) +{ + uint16_t tag = 0; + + if (qdf_atomic_read(&wmi_handle->is_target_suspended)) { + pr_err("%s: Target is already suspended, Ignore FW Hang Command\n", + __func__); + return tag; + } + + if (wmi_handle->tag_crash_inject) + tag = HTC_TX_PACKET_TAG_AUTO_PM; + + wmi_handle->tag_crash_inject = false; + return tag; +} + +/** + * wmi_set_htc_tx_tag() - set HTC TX tag for WMI commands + * @wmi_handle: WMI handle + * @buf: WMI buffer + * @cmd_id: WMI command Id + * + * Return htc_tx_tag + */ +static uint16_t wmi_set_htc_tx_tag_tlv(wmi_unified_t wmi_handle, + wmi_buf_t buf, + uint32_t cmd_id) +{ + uint16_t htc_tx_tag = 0; + + switch (cmd_id) { + case WMI_WOW_ENABLE_CMDID: + case WMI_PDEV_SUSPEND_CMDID: + case WMI_WOW_ENABLE_DISABLE_WAKE_EVENT_CMDID: + case WMI_WOW_ADD_WAKE_PATTERN_CMDID: + case WMI_WOW_HOSTWAKEUP_FROM_SLEEP_CMDID: + case WMI_PDEV_RESUME_CMDID: + case WMI_WOW_DEL_WAKE_PATTERN_CMDID: + case WMI_WOW_SET_ACTION_WAKE_UP_CMDID: +#ifdef FEATURE_WLAN_D0WOW + case WMI_D0_WOW_ENABLE_DISABLE_CMDID: +#endif + htc_tx_tag = HTC_TX_PACKET_TAG_AUTO_PM; + break; + case WMI_FORCE_FW_HANG_CMDID: + htc_tx_tag = wmi_tag_fw_hang_cmd(wmi_handle); + break; + case WMI_VDEV_SET_PARAM_CMDID: + case WMI_STA_POWERSAVE_PARAM_CMDID: + htc_tx_tag = wmi_tag_common_cmd(wmi_handle, buf, cmd_id); + default: + break; + } + + return htc_tx_tag; +} + +/** + * send_get_rcpi_cmd_tlv() - get rcpi request + * @wmi_handle: wmi handle + * @get_rcpi_param: rcpi params + * + * Return: CDF status + */ +static QDF_STATUS send_get_rcpi_cmd_tlv(wmi_unified_t wmi_handle, + struct rcpi_req *get_rcpi_param) +{ + wmi_buf_t buf; + wmi_request_rcpi_cmd_fixed_param *cmd; + uint8_t len = sizeof(wmi_request_rcpi_cmd_fixed_param); + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMI_LOGE("%s: Failed to allocate wmi buffer", __func__); + return QDF_STATUS_E_FAILURE; + } + + + cmd = (wmi_request_rcpi_cmd_fixed_param *) wmi_buf_data(buf); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_request_rcpi_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_request_rcpi_cmd_fixed_param)); + + cmd->vdev_id = get_rcpi_param->vdev_id; + WMI_CHAR_ARRAY_TO_MAC_ADDR(get_rcpi_param->mac_addr, + &cmd->peer_macaddr); + cmd->measurement_type = get_rcpi_param->measurement_type; + WMI_LOGD("RCPI REQ VDEV_ID:%d-->", cmd->vdev_id); + if (wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_REQUEST_RCPI_CMDID)) { + + WMI_LOGE("%s: Failed to send WMI_REQUEST_RCPI_CMDID", + __func__); + wmi_buf_free(buf); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +struct wmi_ops tlv_ops = { + .send_vdev_create_cmd = send_vdev_create_cmd_tlv, + .send_vdev_delete_cmd = send_vdev_delete_cmd_tlv, + .send_vdev_down_cmd = send_vdev_down_cmd_tlv, + .send_vdev_start_cmd = send_vdev_start_cmd_tlv, + .send_hidden_ssid_vdev_restart_cmd = + send_hidden_ssid_vdev_restart_cmd_tlv, + .send_peer_flush_tids_cmd = send_peer_flush_tids_cmd_tlv, + .send_peer_param_cmd = send_peer_param_cmd_tlv, + .send_vdev_up_cmd = send_vdev_up_cmd_tlv, + .send_vdev_stop_cmd = send_vdev_stop_cmd_tlv, + .send_peer_create_cmd = send_peer_create_cmd_tlv, + .send_peer_delete_cmd = send_peer_delete_cmd_tlv, + .send_green_ap_ps_cmd = send_green_ap_ps_cmd_tlv, + .send_pdev_utf_cmd = send_pdev_utf_cmd_tlv, + .send_pdev_param_cmd = send_pdev_param_cmd_tlv, + .send_suspend_cmd = send_suspend_cmd_tlv, + .send_resume_cmd = send_resume_cmd_tlv, + .send_wow_enable_cmd = send_wow_enable_cmd_tlv, + .send_set_ap_ps_param_cmd = send_set_ap_ps_param_cmd_tlv, + .send_set_sta_ps_param_cmd = send_set_sta_ps_param_cmd_tlv, + .send_crash_inject_cmd = send_crash_inject_cmd_tlv, + .send_dbglog_cmd = send_dbglog_cmd_tlv, + .send_vdev_set_param_cmd = send_vdev_set_param_cmd_tlv, + .send_stats_request_cmd = send_stats_request_cmd_tlv, + .send_packet_log_enable_cmd = send_packet_log_enable_cmd_tlv, + .send_beacon_send_cmd = send_beacon_send_cmd_tlv, +#ifndef CONFIG_MCL + .send_beacon_tmpl_send_cmd = send_beacon_tmpl_send_cmd_tlv, +#endif + .send_peer_assoc_cmd = send_peer_assoc_cmd_tlv, + .send_scan_start_cmd = send_scan_start_cmd_tlv, + .send_scan_stop_cmd = send_scan_stop_cmd_tlv, + .send_scan_chan_list_cmd = send_scan_chan_list_cmd_tlv, + .send_mgmt_cmd = send_mgmt_cmd_tlv, + .send_modem_power_state_cmd = send_modem_power_state_cmd_tlv, + .send_set_sta_ps_mode_cmd = send_set_sta_ps_mode_cmd_tlv, + .send_set_sta_uapsd_auto_trig_cmd = + send_set_sta_uapsd_auto_trig_cmd_tlv, + .send_get_temperature_cmd = send_get_temperature_cmd_tlv, + .send_set_p2pgo_oppps_req_cmd = send_set_p2pgo_oppps_req_cmd_tlv, + .send_set_p2pgo_noa_req_cmd = send_set_p2pgo_noa_req_cmd_tlv, + .send_set_smps_params_cmd = send_set_smps_params_cmd_tlv, + .send_set_mimops_cmd = send_set_mimops_cmd_tlv, + .send_ocb_set_utc_time_cmd = send_ocb_set_utc_time_cmd_tlv, + .send_ocb_get_tsf_timer_cmd = send_ocb_get_tsf_timer_cmd_tlv, + .send_dcc_clear_stats_cmd = send_dcc_clear_stats_cmd_tlv, + .send_dcc_get_stats_cmd = send_dcc_get_stats_cmd_tlv, + .send_dcc_update_ndl_cmd = send_dcc_update_ndl_cmd_tlv, + .send_ocb_set_config_cmd = send_ocb_set_config_cmd_tlv, + .send_ocb_stop_timing_advert_cmd = send_ocb_stop_timing_advert_cmd_tlv, + .send_ocb_start_timing_advert_cmd = + send_ocb_start_timing_advert_cmd_tlv, + .send_set_enable_disable_mcc_adaptive_scheduler_cmd = + send_set_enable_disable_mcc_adaptive_scheduler_cmd_tlv, + .send_set_mcc_channel_time_latency_cmd = + send_set_mcc_channel_time_latency_cmd_tlv, + .send_set_mcc_channel_time_quota_cmd = + send_set_mcc_channel_time_quota_cmd_tlv, + .send_set_thermal_mgmt_cmd = send_set_thermal_mgmt_cmd_tlv, + .send_lro_config_cmd = send_lro_config_cmd_tlv, + .send_peer_rate_report_cmd = send_peer_rate_report_cmd_tlv, + .send_set_sta_sa_query_param_cmd = send_set_sta_sa_query_param_cmd_tlv, + .send_set_sta_keep_alive_cmd = send_set_sta_keep_alive_cmd_tlv, + .send_vdev_set_gtx_cfg_cmd = send_vdev_set_gtx_cfg_cmd_tlv, + .send_probe_rsp_tmpl_send_cmd = + send_probe_rsp_tmpl_send_cmd_tlv, + .send_p2p_go_set_beacon_ie_cmd = + send_p2p_go_set_beacon_ie_cmd_tlv, + .send_setup_install_key_cmd = + send_setup_install_key_cmd_tlv, + .send_set_gateway_params_cmd = + send_set_gateway_params_cmd_tlv, + .send_set_rssi_monitoring_cmd = + send_set_rssi_monitoring_cmd_tlv, + .send_scan_probe_setoui_cmd = + send_scan_probe_setoui_cmd_tlv, + .send_reset_passpoint_network_list_cmd = + send_reset_passpoint_network_list_cmd_tlv, + .send_set_passpoint_network_list_cmd = + send_set_passpoint_network_list_cmd_tlv, + .send_roam_scan_offload_rssi_thresh_cmd = + send_roam_scan_offload_rssi_thresh_cmd_tlv, + .send_roam_scan_filter_cmd = + send_roam_scan_filter_cmd_tlv, + .send_set_epno_network_list_cmd = + send_set_epno_network_list_cmd_tlv, + .send_ipa_offload_control_cmd = + send_ipa_offload_control_cmd_tlv, + .send_extscan_get_capabilities_cmd = + send_extscan_get_capabilities_cmd_tlv, + .send_extscan_get_cached_results_cmd = + send_extscan_get_cached_results_cmd_tlv, + .send_extscan_stop_change_monitor_cmd = + send_extscan_stop_change_monitor_cmd_tlv, + .send_extscan_start_change_monitor_cmd = + send_extscan_start_change_monitor_cmd_tlv, + .send_extscan_stop_hotlist_monitor_cmd = + send_extscan_stop_hotlist_monitor_cmd_tlv, + .send_stop_extscan_cmd = send_stop_extscan_cmd_tlv, + .send_start_extscan_cmd = send_start_extscan_cmd_tlv, + .send_plm_stop_cmd = send_plm_stop_cmd_tlv, + .send_plm_start_cmd = send_plm_start_cmd_tlv, + .send_pno_stop_cmd = send_pno_stop_cmd_tlv, +#ifdef FEATURE_WLAN_SCAN_PNO + .send_pno_start_cmd = send_pno_start_cmd_tlv, +#endif + .send_set_ric_req_cmd = send_set_ric_req_cmd_tlv, + .send_process_ll_stats_clear_cmd = send_process_ll_stats_clear_cmd_tlv, + .send_process_ll_stats_set_cmd = send_process_ll_stats_set_cmd_tlv, + .send_process_ll_stats_get_cmd = send_process_ll_stats_get_cmd_tlv, + .send_get_stats_cmd = send_get_stats_cmd_tlv, + .send_congestion_cmd = send_congestion_cmd_tlv, + .send_snr_request_cmd = send_snr_request_cmd_tlv, + .send_snr_cmd = send_snr_cmd_tlv, + .send_link_status_req_cmd = send_link_status_req_cmd_tlv, +#ifdef CONFIG_MCL + .send_lphb_config_hbenable_cmd = send_lphb_config_hbenable_cmd_tlv, + .send_lphb_config_tcp_params_cmd = send_lphb_config_tcp_params_cmd_tlv, + .send_lphb_config_udp_params_cmd = send_lphb_config_udp_params_cmd_tlv, + .send_lphb_config_udp_pkt_filter_cmd = + send_lphb_config_udp_pkt_filter_cmd_tlv, + .send_process_dhcp_ind_cmd = send_process_dhcp_ind_cmd_tlv, + .send_get_link_speed_cmd = send_get_link_speed_cmd_tlv, + .send_egap_conf_params_cmd = send_egap_conf_params_cmd_tlv, + .send_action_frame_patterns_cmd = send_action_frame_patterns_cmd_tlv, + .send_bcn_buf_ll_cmd = send_bcn_buf_ll_cmd_tlv, + .send_process_update_edca_param_cmd = + send_process_update_edca_param_cmd_tlv, + .send_roam_scan_offload_mode_cmd = + send_roam_scan_offload_mode_cmd_tlv, + .send_pktlog_wmi_send_cmd = send_pktlog_wmi_send_cmd_tlv, + .send_roam_scan_offload_ap_profile_cmd = + send_roam_scan_offload_ap_profile_cmd_tlv, +#endif + .send_fw_profiling_cmd = send_fw_profiling_cmd_tlv, + .send_csa_offload_enable_cmd = send_csa_offload_enable_cmd_tlv, +#ifdef FEATURE_WLAN_RA_FILTERING + .send_wow_sta_ra_filter_cmd = send_wow_sta_ra_filter_cmd_tlv, +#endif + .send_nat_keepalive_en_cmd = send_nat_keepalive_en_cmd_tlv, + .send_start_oem_data_cmd = send_start_oem_data_cmd_tlv, + .send_dfs_phyerr_filter_offload_en_cmd = + send_dfs_phyerr_filter_offload_en_cmd_tlv, + .send_add_wow_wakeup_event_cmd = send_add_wow_wakeup_event_cmd_tlv, + .send_wow_patterns_to_fw_cmd = send_wow_patterns_to_fw_cmd_tlv, + .send_wow_delete_pattern_cmd = send_wow_delete_pattern_cmd_tlv, + .send_host_wakeup_ind_to_fw_cmd = send_host_wakeup_ind_to_fw_cmd_tlv, + .send_del_ts_cmd = send_del_ts_cmd_tlv, + .send_aggr_qos_cmd = send_aggr_qos_cmd_tlv, + .send_add_ts_cmd = send_add_ts_cmd_tlv, + .send_enable_disable_packet_filter_cmd = + send_enable_disable_packet_filter_cmd_tlv, + .send_config_packet_filter_cmd = send_config_packet_filter_cmd_tlv, + .send_add_clear_mcbc_filter_cmd = send_add_clear_mcbc_filter_cmd_tlv, + .send_gtk_offload_cmd = send_gtk_offload_cmd_tlv, + .send_process_gtk_offload_getinfo_cmd = + send_process_gtk_offload_getinfo_cmd_tlv, + .send_process_add_periodic_tx_ptrn_cmd = + send_process_add_periodic_tx_ptrn_cmd_tlv, + .send_process_del_periodic_tx_ptrn_cmd = + send_process_del_periodic_tx_ptrn_cmd_tlv, + .send_stats_ext_req_cmd = send_stats_ext_req_cmd_tlv, + .send_enable_ext_wow_cmd = send_enable_ext_wow_cmd_tlv, + .send_set_app_type2_params_in_fw_cmd = + send_set_app_type2_params_in_fw_cmd_tlv, + .send_set_auto_shutdown_timer_cmd = + send_set_auto_shutdown_timer_cmd_tlv, + .send_nan_req_cmd = send_nan_req_cmd_tlv, + .send_process_dhcpserver_offload_cmd = + send_process_dhcpserver_offload_cmd_tlv, + .send_set_led_flashing_cmd = send_set_led_flashing_cmd_tlv, + .send_process_ch_avoid_update_cmd = + send_process_ch_avoid_update_cmd_tlv, + .send_regdomain_info_to_fw_cmd = send_regdomain_info_to_fw_cmd_tlv, + .send_set_tdls_offchan_mode_cmd = send_set_tdls_offchan_mode_cmd_tlv, + .send_update_fw_tdls_state_cmd = send_update_fw_tdls_state_cmd_tlv, + .send_update_tdls_peer_state_cmd = send_update_tdls_peer_state_cmd_tlv, + .send_process_fw_mem_dump_cmd = send_process_fw_mem_dump_cmd_tlv, + .send_process_set_ie_info_cmd = send_process_set_ie_info_cmd_tlv, +#ifdef CONFIG_MCL + .send_init_cmd = send_init_cmd_tlv, +#endif + .save_fw_version_cmd = save_fw_version_cmd_tlv, + .check_and_update_fw_version = + check_and_update_fw_version_cmd_tlv, + .send_saved_init_cmd = send_saved_init_cmd_tlv, + .send_set_base_macaddr_indicate_cmd = + send_set_base_macaddr_indicate_cmd_tlv, + .send_log_supported_evt_cmd = send_log_supported_evt_cmd_tlv, + .send_enable_specific_fw_logs_cmd = + send_enable_specific_fw_logs_cmd_tlv, + .send_flush_logs_to_fw_cmd = send_flush_logs_to_fw_cmd_tlv, + .send_pdev_set_pcl_cmd = send_pdev_set_pcl_cmd_tlv, + .send_pdev_set_hw_mode_cmd = send_pdev_set_hw_mode_cmd_tlv, + .send_pdev_set_dual_mac_config_cmd = + send_pdev_set_dual_mac_config_cmd_tlv, + .send_enable_arp_ns_offload_cmd = + send_enable_arp_ns_offload_cmd_tlv, + .send_conf_hw_filter_mode_cmd = send_conf_hw_filter_cmd_tlv, + .send_app_type1_params_in_fw_cmd = + send_app_type1_params_in_fw_cmd_tlv, + .send_set_ssid_hotlist_cmd = send_set_ssid_hotlist_cmd_tlv, + .send_process_roam_synch_complete_cmd = + send_process_roam_synch_complete_cmd_tlv, + .send_unit_test_cmd = send_unit_test_cmd_tlv, + .send_roam_invoke_cmd = send_roam_invoke_cmd_tlv, + .send_roam_scan_offload_cmd = send_roam_scan_offload_cmd_tlv, + .send_roam_scan_offload_scan_period_cmd = + send_roam_scan_offload_scan_period_cmd_tlv, + .send_roam_scan_offload_chan_list_cmd = + send_roam_scan_offload_chan_list_cmd_tlv, + .send_roam_scan_offload_rssi_change_cmd = + send_roam_scan_offload_rssi_change_cmd_tlv, + .send_get_buf_extscan_hotlist_cmd = + send_get_buf_extscan_hotlist_cmd_tlv, + .send_set_active_bpf_mode_cmd = send_set_active_bpf_mode_cmd_tlv, + .send_adapt_dwelltime_params_cmd = + send_adapt_dwelltime_params_cmd_tlv, + .init_cmd_send = init_cmd_send_tlv, + .get_target_cap_from_service_ready = extract_service_ready_tlv, + .extract_hal_reg_cap = extract_hal_reg_cap_tlv, + .extract_host_mem_req = extract_host_mem_req_tlv, + .save_service_bitmap = save_service_bitmap_tlv, + .is_service_enabled = is_service_enabled_tlv, + .save_fw_version = save_fw_version_in_service_ready_tlv, + .ready_extract_init_status = ready_extract_init_status_tlv, + .ready_extract_mac_addr = ready_extract_mac_addr_tlv, + .extract_dbglog_data_len = extract_dbglog_data_len_tlv, + .extract_vdev_start_resp = extract_vdev_start_resp_tlv, + .extract_tbttoffset_update_params = + extract_tbttoffset_update_params_tlv, + .extract_mgmt_rx_params = extract_mgmt_rx_params_tlv, + .extract_vdev_stopped_param = extract_vdev_stopped_param_tlv, + .extract_vdev_roam_param = extract_vdev_roam_param_tlv, + .extract_vdev_scan_ev_param = extract_vdev_scan_ev_param_tlv, + .extract_mgmt_tx_compl_param = extract_mgmt_tx_compl_param_tlv, + .extract_swba_vdev_map = extract_swba_vdev_map_tlv, + .extract_swba_tim_info = extract_swba_tim_info_tlv, + .extract_swba_noa_info = extract_swba_noa_info_tlv, + .extract_peer_sta_kickout_ev = extract_peer_sta_kickout_ev_tlv, + .extract_all_stats_count = extract_all_stats_counts_tlv, + .extract_pdev_stats = extract_pdev_stats_tlv, + .extract_pdev_ext_stats = extract_pdev_ext_stats_tlv, + .extract_vdev_stats = extract_vdev_stats_tlv, + .extract_peer_stats = extract_peer_stats_tlv, + .extract_bcnflt_stats = extract_bcnflt_stats_tlv, + .extract_peer_extd_stats = extract_peer_extd_stats_tlv, + .extract_chan_stats = extract_chan_stats_tlv, + .extract_profile_ctx = extract_profile_ctx_tlv, + .extract_profile_data = extract_profile_data_tlv, + .extract_chan_info_event = extract_chan_info_event_tlv, + .extract_channel_hopping_event = extract_channel_hopping_event_tlv, + .send_fw_test_cmd = send_fw_test_cmd_tlv, + .send_power_dbg_cmd = send_power_dbg_cmd_tlv, + .send_encrypt_decrypt_send_cmd = + send_encrypt_decrypt_send_cmd_tlv, + .send_sar_limit_cmd = send_sar_limit_cmd_tlv, + .send_per_roam_config_cmd = send_per_roam_config_cmd_tlv, + .wmi_set_htc_tx_tag = wmi_set_htc_tx_tag_tlv, + .send_get_rcpi_cmd = send_get_rcpi_cmd_tlv, + .send_set_arp_stats_req_cmd = send_set_arp_stats_req_cmd_tlv, + .send_get_arp_stats_req_cmd = send_get_arp_stats_req_cmd_tlv, +}; + +#ifdef WMI_TLV_AND_NON_TLV_SUPPORT +/** + * populate_tlv_service() - populates wmi services + * + * @param wmi_service: Pointer to hold wmi_service + * Return: None + */ +static void populate_tlv_service(uint32_t *wmi_service) +{ + wmi_service[wmi_service_beacon_offload] = WMI_SERVICE_BEACON_OFFLOAD; + wmi_service[wmi_service_scan_offload] = WMI_SERVICE_SCAN_OFFLOAD; + wmi_service[wmi_service_roam_scan_offload] = + WMI_SERVICE_ROAM_SCAN_OFFLOAD; + wmi_service[wmi_service_bcn_miss_offload] = + WMI_SERVICE_BCN_MISS_OFFLOAD; + wmi_service[wmi_service_sta_pwrsave] = WMI_SERVICE_STA_PWRSAVE; + wmi_service[wmi_service_sta_advanced_pwrsave] = + WMI_SERVICE_STA_ADVANCED_PWRSAVE; + wmi_service[wmi_service_ap_uapsd] = WMI_SERVICE_AP_UAPSD; + wmi_service[wmi_service_ap_dfs] = WMI_SERVICE_AP_DFS; + wmi_service[wmi_service_11ac] = WMI_SERVICE_11AC; + wmi_service[wmi_service_blockack] = WMI_SERVICE_BLOCKACK; + wmi_service[wmi_service_phyerr] = WMI_SERVICE_PHYERR; + wmi_service[wmi_service_bcn_filter] = WMI_SERVICE_BCN_FILTER; + wmi_service[wmi_service_rtt] = WMI_SERVICE_RTT; + wmi_service[wmi_service_wow] = WMI_SERVICE_WOW; + wmi_service[wmi_service_ratectrl_cache] = WMI_SERVICE_RATECTRL_CACHE; + wmi_service[wmi_service_iram_tids] = WMI_SERVICE_IRAM_TIDS; + wmi_service[wmi_service_arpns_offload] = WMI_SERVICE_ARPNS_OFFLOAD; + wmi_service[wmi_service_nlo] = WMI_SERVICE_NLO; + wmi_service[wmi_service_gtk_offload] = WMI_SERVICE_GTK_OFFLOAD; + wmi_service[wmi_service_scan_sch] = WMI_SERVICE_SCAN_SCH; + wmi_service[wmi_service_csa_offload] = WMI_SERVICE_CSA_OFFLOAD; + wmi_service[wmi_service_chatter] = WMI_SERVICE_CHATTER; + wmi_service[wmi_service_coex_freqavoid] = WMI_SERVICE_COEX_FREQAVOID; + wmi_service[wmi_service_packet_power_save] = + WMI_SERVICE_PACKET_POWER_SAVE; + wmi_service[wmi_service_force_fw_hang] = WMI_SERVICE_FORCE_FW_HANG; + wmi_service[wmi_service_gpio] = WMI_SERVICE_GPIO; + wmi_service[wmi_service_sta_dtim_ps_modulated_dtim] = + WMI_SERVICE_STA_DTIM_PS_MODULATED_DTIM; + wmi_service[wmi_sta_uapsd_basic_auto_trig] = + WMI_STA_UAPSD_BASIC_AUTO_TRIG; + wmi_service[wmi_sta_uapsd_var_auto_trig] = WMI_STA_UAPSD_VAR_AUTO_TRIG; + wmi_service[wmi_service_sta_keep_alive] = WMI_SERVICE_STA_KEEP_ALIVE; + wmi_service[wmi_service_tx_encap] = WMI_SERVICE_TX_ENCAP; + wmi_service[wmi_service_ap_ps_detect_out_of_sync] = + WMI_SERVICE_AP_PS_DETECT_OUT_OF_SYNC; + wmi_service[wmi_service_early_rx] = WMI_SERVICE_EARLY_RX; + wmi_service[wmi_service_sta_smps] = WMI_SERVICE_STA_SMPS; + wmi_service[wmi_service_fwtest] = WMI_SERVICE_FWTEST; + wmi_service[wmi_service_sta_wmmac] = WMI_SERVICE_STA_WMMAC; + wmi_service[wmi_service_tdls] = WMI_SERVICE_TDLS; + wmi_service[wmi_service_burst] = WMI_SERVICE_BURST; + wmi_service[wmi_service_mcc_bcn_interval_change] = + WMI_SERVICE_MCC_BCN_INTERVAL_CHANGE; + wmi_service[wmi_service_adaptive_ocs] = WMI_SERVICE_ADAPTIVE_OCS; + wmi_service[wmi_service_ba_ssn_support] = WMI_SERVICE_BA_SSN_SUPPORT; + wmi_service[wmi_service_filter_ipsec_natkeepalive] = + WMI_SERVICE_FILTER_IPSEC_NATKEEPALIVE; + wmi_service[wmi_service_wlan_hb] = WMI_SERVICE_WLAN_HB; + wmi_service[wmi_service_lte_ant_share_support] = + WMI_SERVICE_LTE_ANT_SHARE_SUPPORT; + wmi_service[wmi_service_batch_scan] = WMI_SERVICE_BATCH_SCAN; + wmi_service[wmi_service_qpower] = WMI_SERVICE_QPOWER; + wmi_service[wmi_service_plmreq] = WMI_SERVICE_PLMREQ; + wmi_service[wmi_service_thermal_mgmt] = WMI_SERVICE_THERMAL_MGMT; + wmi_service[wmi_service_rmc] = WMI_SERVICE_RMC; + wmi_service[wmi_service_mhf_offload] = WMI_SERVICE_MHF_OFFLOAD; + wmi_service[wmi_service_coex_sar] = WMI_SERVICE_COEX_SAR; + wmi_service[wmi_service_bcn_txrate_override] = + WMI_SERVICE_BCN_TXRATE_OVERRIDE; + wmi_service[wmi_service_nan] = WMI_SERVICE_NAN; + wmi_service[wmi_service_l1ss_stat] = WMI_SERVICE_L1SS_STAT; + wmi_service[wmi_service_estimate_linkspeed] = + WMI_SERVICE_ESTIMATE_LINKSPEED; + wmi_service[wmi_service_obss_scan] = WMI_SERVICE_OBSS_SCAN; + wmi_service[wmi_service_tdls_offchan] = WMI_SERVICE_TDLS_OFFCHAN; + wmi_service[wmi_service_tdls_uapsd_buffer_sta] = + WMI_SERVICE_TDLS_UAPSD_BUFFER_STA; + wmi_service[wmi_service_tdls_uapsd_sleep_sta] = + WMI_SERVICE_TDLS_UAPSD_SLEEP_STA; + wmi_service[wmi_service_ibss_pwrsave] = WMI_SERVICE_IBSS_PWRSAVE; + wmi_service[wmi_service_lpass] = WMI_SERVICE_LPASS; + wmi_service[wmi_service_extscan] = WMI_SERVICE_EXTSCAN; + wmi_service[wmi_service_d0wow] = WMI_SERVICE_D0WOW; + wmi_service[wmi_service_hsoffload] = WMI_SERVICE_HSOFFLOAD; + wmi_service[wmi_service_roam_ho_offload] = WMI_SERVICE_ROAM_HO_OFFLOAD; + wmi_service[wmi_service_rx_full_reorder] = WMI_SERVICE_RX_FULL_REORDER; + wmi_service[wmi_service_dhcp_offload] = WMI_SERVICE_DHCP_OFFLOAD; + wmi_service[wmi_service_sta_rx_ipa_offload_support] = + WMI_SERVICE_STA_RX_IPA_OFFLOAD_SUPPORT; + wmi_service[wmi_service_mdns_offload] = WMI_SERVICE_MDNS_OFFLOAD; + wmi_service[wmi_service_sap_auth_offload] = + WMI_SERVICE_SAP_AUTH_OFFLOAD; + wmi_service[wmi_service_dual_band_simultaneous_support] = + WMI_SERVICE_DUAL_BAND_SIMULTANEOUS_SUPPORT; + wmi_service[wmi_service_ocb] = WMI_SERVICE_OCB; + wmi_service[wmi_service_ap_arpns_offload] = + WMI_SERVICE_AP_ARPNS_OFFLOAD; + wmi_service[wmi_service_per_band_chainmask_support] = + WMI_SERVICE_PER_BAND_CHAINMASK_SUPPORT; + wmi_service[wmi_service_packet_filter_offload] = + WMI_SERVICE_PACKET_FILTER_OFFLOAD; + wmi_service[wmi_service_mgmt_tx_htt] = WMI_SERVICE_MGMT_TX_HTT; + wmi_service[wmi_service_mgmt_tx_wmi] = WMI_SERVICE_MGMT_TX_WMI; + wmi_service[wmi_service_ext_msg] = WMI_SERVICE_EXT_MSG; + wmi_service[wmi_service_mawc] = WMI_SERVICE_MAWC; + + wmi_service[wmi_service_roam_offload] = WMI_SERVICE_UNAVAILABLE; + wmi_service[wmi_service_ratectrl] = WMI_SERVICE_UNAVAILABLE; + wmi_service[wmi_service_smart_antenna_sw_support] = + WMI_SERVICE_UNAVAILABLE; + wmi_service[wmi_service_smart_antenna_hw_support] = + WMI_SERVICE_UNAVAILABLE; + wmi_service[wmi_service_enhanced_proxy_sta] = WMI_SERVICE_UNAVAILABLE; + wmi_service[wmi_service_tt] = WMI_SERVICE_UNAVAILABLE; + wmi_service[wmi_service_atf] = WMI_SERVICE_UNAVAILABLE; + wmi_service[wmi_service_peer_caching] = WMI_SERVICE_UNAVAILABLE; + wmi_service[wmi_service_coex_gpio] = WMI_SERVICE_UNAVAILABLE; + wmi_service[wmi_service_aux_spectral_intf] = WMI_SERVICE_UNAVAILABLE; + wmi_service[wmi_service_aux_chan_load_intf] = WMI_SERVICE_UNAVAILABLE; + wmi_service[wmi_service_bss_channel_info_64] = WMI_SERVICE_UNAVAILABLE; + wmi_service[wmi_service_ext_res_cfg_support] = WMI_SERVICE_UNAVAILABLE; + wmi_service[wmi_service_mesh] = WMI_SERVICE_UNAVAILABLE; + wmi_service[wmi_service_restrt_chnl_support] = WMI_SERVICE_UNAVAILABLE; + + wmi_service[wmi_service_peer_stats] = WMI_SERVICE_UNAVAILABLE; + wmi_service[wmi_service_mesh_11s] = WMI_SERVICE_UNAVAILABLE; + wmi_service[wmi_service_periodic_chan_stat_support] = + WMI_SERVICE_UNAVAILABLE; + wmi_service[wmi_service_tx_mode_push_only] = WMI_SERVICE_UNAVAILABLE; + wmi_service[wmi_service_tx_mode_push_pull] = WMI_SERVICE_UNAVAILABLE; + wmi_service[wmi_service_tx_mode_dynamic] = WMI_SERVICE_UNAVAILABLE; +} + +/** + * populate_tlv_event_id() - populates wmi event ids + * + * @param event_ids: Pointer to hold event ids + * Return: None + */ +static void populate_tlv_events_id(uint32_t *event_ids) +{ + event_ids[wmi_service_ready_event_id] = WMI_SERVICE_READY_EVENTID; + event_ids[wmi_ready_event_id] = WMI_READY_EVENTID; + event_ids[wmi_scan_event_id] = WMI_SCAN_EVENTID; + event_ids[wmi_pdev_tpc_config_event_id] = WMI_PDEV_TPC_CONFIG_EVENTID; + event_ids[wmi_chan_info_event_id] = WMI_CHAN_INFO_EVENTID; + event_ids[wmi_phyerr_event_id] = WMI_PHYERR_EVENTID; + event_ids[wmi_pdev_dump_event_id] = WMI_PDEV_DUMP_EVENTID; + event_ids[wmi_tx_pause_event_id] = WMI_TX_PAUSE_EVENTID; + event_ids[wmi_dfs_radar_event_id] = WMI_DFS_RADAR_EVENTID; + event_ids[wmi_pdev_l1ss_track_event_id] = WMI_PDEV_L1SS_TRACK_EVENTID; + event_ids[wmi_pdev_temperature_event_id] = WMI_PDEV_TEMPERATURE_EVENTID; + event_ids[wmi_service_ready_ext_event_id] = + WMI_SERVICE_READY_EXT_EVENTID; + event_ids[wmi_vdev_start_resp_event_id] = WMI_VDEV_START_RESP_EVENTID; + event_ids[wmi_vdev_stopped_event_id] = WMI_VDEV_STOPPED_EVENTID; + event_ids[wmi_vdev_install_key_complete_event_id] = + WMI_VDEV_INSTALL_KEY_COMPLETE_EVENTID; + event_ids[wmi_vdev_mcc_bcn_intvl_change_req_event_id] = + WMI_VDEV_MCC_BCN_INTERVAL_CHANGE_REQ_EVENTID; + + event_ids[wmi_vdev_tsf_report_event_id] = WMI_VDEV_TSF_REPORT_EVENTID; + event_ids[wmi_peer_sta_kickout_event_id] = WMI_PEER_STA_KICKOUT_EVENTID; + event_ids[wmi_peer_info_event_id] = WMI_PEER_INFO_EVENTID; + event_ids[wmi_peer_tx_fail_cnt_thr_event_id] = + WMI_PEER_TX_FAIL_CNT_THR_EVENTID; + event_ids[wmi_peer_estimated_linkspeed_event_id] = + WMI_PEER_ESTIMATED_LINKSPEED_EVENTID; + event_ids[wmi_peer_state_event_id] = WMI_PEER_STATE_EVENTID; + event_ids[wmi_mgmt_rx_event_id] = WMI_MGMT_RX_EVENTID; + event_ids[wmi_host_swba_event_id] = WMI_HOST_SWBA_EVENTID; + event_ids[wmi_tbttoffset_update_event_id] = + WMI_TBTTOFFSET_UPDATE_EVENTID; + event_ids[wmi_offload_bcn_tx_status_event_id] = + WMI_OFFLOAD_BCN_TX_STATUS_EVENTID; + event_ids[wmi_offload_prob_resp_tx_status_event_id] = + WMI_OFFLOAD_PROB_RESP_TX_STATUS_EVENTID; + event_ids[wmi_mgmt_tx_completion_event_id] = + WMI_MGMT_TX_COMPLETION_EVENTID; + + event_ids[wmi_tx_delba_complete_event_id] = + WMI_TX_DELBA_COMPLETE_EVENTID; + event_ids[wmi_tx_addba_complete_event_id] = + WMI_TX_ADDBA_COMPLETE_EVENTID; + event_ids[wmi_ba_rsp_ssn_event_id] = WMI_BA_RSP_SSN_EVENTID; + + event_ids[wmi_aggr_state_trig_event_id] = WMI_AGGR_STATE_TRIG_EVENTID; + + event_ids[wmi_roam_event_id] = WMI_ROAM_EVENTID; + event_ids[wmi_profile_match] = WMI_PROFILE_MATCH; + + event_ids[wmi_roam_synch_event_id] = WMI_ROAM_SYNCH_EVENTID; + + event_ids[wmi_p2p_disc_event_id] = WMI_P2P_DISC_EVENTID; + + event_ids[wmi_p2p_noa_event_id] = WMI_P2P_NOA_EVENTID; + + event_ids[wmi_pdev_resume_event_id] = WMI_PDEV_RESUME_EVENTID; + event_ids[wmi_wow_wakeup_host_event_id] = WMI_WOW_WAKEUP_HOST_EVENTID; + event_ids[wmi_do_wow_disable_ack_event_id] = + WMI_D0_WOW_DISABLE_ACK_EVENTID; + event_ids[wmi_wow_initial_wakeup_event_id] = + WMI_WOW_INITIAL_WAKEUP_EVENTID; + + event_ids[wmi_rtt_meas_report_event_id] = + WMI_RTT_MEASUREMENT_REPORT_EVENTID; + event_ids[wmi_tsf_meas_report_event_id] = + WMI_TSF_MEASUREMENT_REPORT_EVENTID; + event_ids[wmi_rtt_error_report_event_id] = WMI_RTT_ERROR_REPORT_EVENTID; + event_ids[wmi_stats_ext_event_id] = WMI_STATS_EXT_EVENTID; + event_ids[wmi_iface_link_stats_event_id] = WMI_IFACE_LINK_STATS_EVENTID; + event_ids[wmi_peer_link_stats_event_id] = WMI_PEER_LINK_STATS_EVENTID; + event_ids[wmi_radio_link_stats_link] = WMI_RADIO_LINK_STATS_EVENTID; + event_ids[wmi_update_fw_mem_dump_event_id] = + WMI_UPDATE_FW_MEM_DUMP_EVENTID; + event_ids[wmi_diag_event_id_log_supported_event_id] = + WMI_DIAG_EVENT_LOG_SUPPORTED_EVENTID; + event_ids[wmi_nlo_match_event_id] = WMI_NLO_MATCH_EVENTID; + event_ids[wmi_nlo_scan_complete_event_id] = + WMI_NLO_SCAN_COMPLETE_EVENTID; + event_ids[wmi_apfind_event_id] = WMI_APFIND_EVENTID; + event_ids[wmi_passpoint_match_event_id] = WMI_PASSPOINT_MATCH_EVENTID; + + event_ids[wmi_gtk_offload_status_event_id] = + WMI_GTK_OFFLOAD_STATUS_EVENTID; + event_ids[wmi_gtk_rekey_fail_event_id] = WMI_GTK_REKEY_FAIL_EVENTID; + event_ids[wmi_csa_handling_event_id] = WMI_CSA_HANDLING_EVENTID; + event_ids[wmi_chatter_pc_query_event_id] = WMI_CHATTER_PC_QUERY_EVENTID; + + event_ids[wmi_echo_event_id] = WMI_ECHO_EVENTID; + + event_ids[wmi_pdev_utf_event_id] = WMI_PDEV_UTF_EVENTID; + + event_ids[wmi_dbg_msg_event_id] = WMI_DEBUG_MESG_EVENTID; + event_ids[wmi_update_stats_event_id] = WMI_UPDATE_STATS_EVENTID; + event_ids[wmi_debug_print_event_id] = WMI_DEBUG_PRINT_EVENTID; + event_ids[wmi_dcs_interference_event_id] = WMI_DCS_INTERFERENCE_EVENTID; + event_ids[wmi_pdev_qvit_event_id] = WMI_PDEV_QVIT_EVENTID; + event_ids[wmi_wlan_profile_data_event_id] = + WMI_WLAN_PROFILE_DATA_EVENTID; + event_ids[wmi_pdev_ftm_intg_event_id] = WMI_PDEV_FTM_INTG_EVENTID; + event_ids[wmi_wlan_freq_avoid_event_id] = WMI_WLAN_FREQ_AVOID_EVENTID; + event_ids[wmi_vdev_get_keepalive_event_id] = + WMI_VDEV_GET_KEEPALIVE_EVENTID; + event_ids[wmi_thermal_mgmt_event_id] = WMI_THERMAL_MGMT_EVENTID; + + event_ids[wmi_diag_container_event_id] = + WMI_DIAG_DATA_CONTAINER_EVENTID; + + event_ids[wmi_host_auto_shutdown_event_id] = + WMI_HOST_AUTO_SHUTDOWN_EVENTID; + + event_ids[wmi_update_whal_mib_stats_event_id] = + WMI_UPDATE_WHAL_MIB_STATS_EVENTID; + + /*update ht/vht info based on vdev (rx and tx NSS and preamble) */ + event_ids[wmi_update_vdev_rate_stats_event_id] = + WMI_UPDATE_VDEV_RATE_STATS_EVENTID; + + event_ids[wmi_diag_event_id] = WMI_DIAG_EVENTID; + + /** Set OCB Sched Response, deprecated */ + event_ids[wmi_ocb_set_sched_event_id] = WMI_OCB_SET_SCHED_EVENTID; + + event_ids[wmi_dbg_mesg_flush_complete_event_id] = + WMI_DEBUG_MESG_FLUSH_COMPLETE_EVENTID; + event_ids[wmi_rssi_breach_event_id] = WMI_RSSI_BREACH_EVENTID; + + /* GPIO Event */ + event_ids[wmi_gpio_input_event_id] = WMI_GPIO_INPUT_EVENTID; + event_ids[wmi_uploadh_event_id] = WMI_UPLOADH_EVENTID; + + event_ids[wmi_captureh_event_id] = WMI_CAPTUREH_EVENTID; + event_ids[wmi_rfkill_state_change_event_id] = + WMI_RFKILL_STATE_CHANGE_EVENTID; + + /* TDLS Event */ + event_ids[wmi_tdls_peer_event_id] = WMI_TDLS_PEER_EVENTID; + + event_ids[wmi_batch_scan_enabled_event_id] = + WMI_BATCH_SCAN_ENABLED_EVENTID; + event_ids[wmi_batch_scan_result_event_id] = + WMI_BATCH_SCAN_RESULT_EVENTID; + /* OEM Event */ + event_ids[wmi_oem_cap_event_id] = WMI_OEM_CAPABILITY_EVENTID; + event_ids[wmi_oem_meas_report_event_id] = + WMI_OEM_MEASUREMENT_REPORT_EVENTID; + event_ids[wmi_oem_report_event_id] = WMI_OEM_ERROR_REPORT_EVENTID; + + /* NAN Event */ + event_ids[wmi_nan_event_id] = WMI_NAN_EVENTID; + + /* LPI Event */ + event_ids[wmi_lpi_result_event_id] = WMI_LPI_RESULT_EVENTID; + event_ids[wmi_lpi_status_event_id] = WMI_LPI_STATUS_EVENTID; + event_ids[wmi_lpi_handoff_event_id] = WMI_LPI_HANDOFF_EVENTID; + + /* ExtScan events */ + event_ids[wmi_extscan_start_stop_event_id] = + WMI_EXTSCAN_START_STOP_EVENTID; + event_ids[wmi_extscan_operation_event_id] = + WMI_EXTSCAN_OPERATION_EVENTID; + event_ids[wmi_extscan_table_usage_event_id] = + WMI_EXTSCAN_TABLE_USAGE_EVENTID; + event_ids[wmi_extscan_cached_results_event_id] = + WMI_EXTSCAN_CACHED_RESULTS_EVENTID; + event_ids[wmi_extscan_wlan_change_results_event_id] = + WMI_EXTSCAN_WLAN_CHANGE_RESULTS_EVENTID; + event_ids[wmi_extscan_hotlist_match_event_id] = + WMI_EXTSCAN_HOTLIST_MATCH_EVENTID; + event_ids[wmi_extscan_capabilities_event_id] = + WMI_EXTSCAN_CAPABILITIES_EVENTID; + event_ids[wmi_extscan_hotlist_ssid_match_event_id] = + WMI_EXTSCAN_HOTLIST_SSID_MATCH_EVENTID; + + /* mDNS offload events */ + event_ids[wmi_mdns_stats_event_id] = WMI_MDNS_STATS_EVENTID; + + /* SAP Authentication offload events */ + event_ids[wmi_sap_ofl_add_sta_event_id] = WMI_SAP_OFL_ADD_STA_EVENTID; + event_ids[wmi_sap_ofl_del_sta_event_id] = WMI_SAP_OFL_DEL_STA_EVENTID; + + /** Out-of-context-of-bss (OCB) events */ + event_ids[wmi_ocb_set_config_resp_event_id] = + WMI_OCB_SET_CONFIG_RESP_EVENTID; + event_ids[wmi_ocb_get_tsf_timer_resp_event_id] = + WMI_OCB_GET_TSF_TIMER_RESP_EVENTID; + event_ids[wmi_dcc_get_stats_resp_event_id] = + WMI_DCC_GET_STATS_RESP_EVENTID; + event_ids[wmi_dcc_update_ndl_resp_event_id] = + WMI_DCC_UPDATE_NDL_RESP_EVENTID; + event_ids[wmi_dcc_stats_event_id] = WMI_DCC_STATS_EVENTID; + /* System-On-Chip events */ + event_ids[wmi_soc_set_hw_mode_resp_event_id] = + WMI_SOC_SET_HW_MODE_RESP_EVENTID; + event_ids[wmi_soc_hw_mode_transition_event_id] = + WMI_SOC_HW_MODE_TRANSITION_EVENTID; + event_ids[wmi_soc_set_dual_mac_config_resp_event_id] = + WMI_SOC_SET_DUAL_MAC_CONFIG_RESP_EVENTID; + event_ids[wmi_update_rcpi_event_id] = WMI_UPDATE_RCPI_EVENTID; +} + +/** + * populate_pdev_param_tlv() - populates pdev params + * + * @param pdev_param: Pointer to hold pdev params + * Return: None + */ +static void populate_pdev_param_tlv(uint32_t *pdev_param) +{ + pdev_param[wmi_pdev_param_tx_chain_mask] = WMI_PDEV_PARAM_TX_CHAIN_MASK; + pdev_param[wmi_pdev_param_rx_chain_mask] = WMI_PDEV_PARAM_RX_CHAIN_MASK; + pdev_param[wmi_pdev_param_txpower_limit2g] = + WMI_PDEV_PARAM_TXPOWER_LIMIT2G; + pdev_param[wmi_pdev_param_txpower_limit5g] = + WMI_PDEV_PARAM_TXPOWER_LIMIT5G; + pdev_param[wmi_pdev_param_txpower_scale] = WMI_PDEV_PARAM_TXPOWER_SCALE; + pdev_param[wmi_pdev_param_beacon_gen_mode] = + WMI_PDEV_PARAM_BEACON_GEN_MODE; + pdev_param[wmi_pdev_param_beacon_tx_mode] = + WMI_PDEV_PARAM_BEACON_TX_MODE; + pdev_param[wmi_pdev_param_resmgr_offchan_mode] = + WMI_PDEV_PARAM_RESMGR_OFFCHAN_MODE; + pdev_param[wmi_pdev_param_protection_mode] = + WMI_PDEV_PARAM_PROTECTION_MODE; + pdev_param[wmi_pdev_param_dynamic_bw] = WMI_PDEV_PARAM_DYNAMIC_BW; + pdev_param[wmi_pdev_param_non_agg_sw_retry_th] = + WMI_PDEV_PARAM_NON_AGG_SW_RETRY_TH; + pdev_param[wmi_pdev_param_agg_sw_retry_th] = + WMI_PDEV_PARAM_AGG_SW_RETRY_TH; + pdev_param[wmi_pdev_param_sta_kickout_th] = + WMI_PDEV_PARAM_STA_KICKOUT_TH; + pdev_param[wmi_pdev_param_ac_aggrsize_scaling] = + WMI_PDEV_PARAM_AC_AGGRSIZE_SCALING; + pdev_param[wmi_pdev_param_ltr_enable] = WMI_PDEV_PARAM_LTR_ENABLE; + pdev_param[wmi_pdev_param_ltr_ac_latency_be] = + WMI_PDEV_PARAM_LTR_AC_LATENCY_BE; + pdev_param[wmi_pdev_param_ltr_ac_latency_bk] = + WMI_PDEV_PARAM_LTR_AC_LATENCY_BK; + pdev_param[wmi_pdev_param_ltr_ac_latency_vi] = + WMI_PDEV_PARAM_LTR_AC_LATENCY_VI; + pdev_param[wmi_pdev_param_ltr_ac_latency_vo] = + WMI_PDEV_PARAM_LTR_AC_LATENCY_VO; + pdev_param[wmi_pdev_param_ltr_ac_latency_timeout] = + WMI_PDEV_PARAM_LTR_AC_LATENCY_TIMEOUT; + pdev_param[wmi_pdev_param_ltr_sleep_override] = + WMI_PDEV_PARAM_LTR_SLEEP_OVERRIDE; + pdev_param[wmi_pdev_param_ltr_rx_override] = + WMI_PDEV_PARAM_LTR_RX_OVERRIDE; + pdev_param[wmi_pdev_param_ltr_tx_activity_timeout] = + WMI_PDEV_PARAM_LTR_TX_ACTIVITY_TIMEOUT; + pdev_param[wmi_pdev_param_l1ss_enable] = WMI_PDEV_PARAM_L1SS_ENABLE; + pdev_param[wmi_pdev_param_dsleep_enable] = WMI_PDEV_PARAM_DSLEEP_ENABLE; + pdev_param[wmi_pdev_param_pcielp_txbuf_flush] = + WMI_PDEV_PARAM_PCIELP_TXBUF_FLUSH; + pdev_param[wmi_pdev_param_pcielp_txbuf_watermark] = + WMI_PDEV_PARAM_PCIELP_TXBUF_WATERMARK; + pdev_param[wmi_pdev_param_pcielp_txbuf_tmo_en] = + WMI_PDEV_PARAM_PCIELP_TXBUF_TMO_EN; + pdev_param[wmi_pdev_param_pcielp_txbuf_tmo_value] = + WMI_PDEV_PARAM_PCIELP_TXBUF_TMO_VALUE; + pdev_param[wmi_pdev_param_pdev_stats_update_period] = + WMI_PDEV_PARAM_PDEV_STATS_UPDATE_PERIOD; + pdev_param[wmi_pdev_param_vdev_stats_update_period] = + WMI_PDEV_PARAM_VDEV_STATS_UPDATE_PERIOD; + pdev_param[wmi_pdev_param_peer_stats_update_period] = + WMI_PDEV_PARAM_PEER_STATS_UPDATE_PERIOD; + pdev_param[wmi_pdev_param_bcnflt_stats_update_period] = + WMI_PDEV_PARAM_BCNFLT_STATS_UPDATE_PERIOD; + pdev_param[wmi_pdev_param_pmf_qos] = WMI_PDEV_PARAM_PMF_QOS; + pdev_param[wmi_pdev_param_arp_ac_override] = + WMI_PDEV_PARAM_ARP_AC_OVERRIDE; + pdev_param[wmi_pdev_param_dcs] = WMI_PDEV_PARAM_DCS; + pdev_param[wmi_pdev_param_ani_enable] = WMI_PDEV_PARAM_ANI_ENABLE; + pdev_param[wmi_pdev_param_ani_poll_period] = + WMI_PDEV_PARAM_ANI_POLL_PERIOD; + pdev_param[wmi_pdev_param_ani_listen_period] = + WMI_PDEV_PARAM_ANI_LISTEN_PERIOD; + pdev_param[wmi_pdev_param_ani_ofdm_level] = + WMI_PDEV_PARAM_ANI_OFDM_LEVEL; + pdev_param[wmi_pdev_param_ani_cck_level] = WMI_PDEV_PARAM_ANI_CCK_LEVEL; + pdev_param[wmi_pdev_param_dyntxchain] = WMI_PDEV_PARAM_DYNTXCHAIN; + pdev_param[wmi_pdev_param_proxy_sta] = WMI_PDEV_PARAM_PROXY_STA; + pdev_param[wmi_pdev_param_idle_ps_config] = + WMI_PDEV_PARAM_IDLE_PS_CONFIG; + pdev_param[wmi_pdev_param_power_gating_sleep] = + WMI_PDEV_PARAM_POWER_GATING_SLEEP; + pdev_param[wmi_pdev_param_rfkill_enable] = WMI_PDEV_PARAM_RFKILL_ENABLE; + pdev_param[wmi_pdev_param_burst_dur] = WMI_PDEV_PARAM_BURST_DUR; + pdev_param[wmi_pdev_param_burst_enable] = WMI_PDEV_PARAM_BURST_ENABLE; + pdev_param[wmi_pdev_param_hw_rfkill_config] = + WMI_PDEV_PARAM_HW_RFKILL_CONFIG; + pdev_param[wmi_pdev_param_low_power_rf_enable] = + WMI_PDEV_PARAM_LOW_POWER_RF_ENABLE; + pdev_param[wmi_pdev_param_l1ss_track] = WMI_PDEV_PARAM_L1SS_TRACK; + pdev_param[wmi_pdev_param_hyst_en] = WMI_PDEV_PARAM_HYST_EN; + pdev_param[wmi_pdev_param_power_collapse_enable] = + WMI_PDEV_PARAM_POWER_COLLAPSE_ENABLE; + pdev_param[wmi_pdev_param_led_sys_state] = WMI_PDEV_PARAM_LED_SYS_STATE; + pdev_param[wmi_pdev_param_led_enable] = WMI_PDEV_PARAM_LED_ENABLE; + pdev_param[wmi_pdev_param_audio_over_wlan_latency] = + WMI_PDEV_PARAM_AUDIO_OVER_WLAN_LATENCY; + pdev_param[wmi_pdev_param_audio_over_wlan_enable] = + WMI_PDEV_PARAM_AUDIO_OVER_WLAN_ENABLE; + pdev_param[wmi_pdev_param_whal_mib_stats_update_enable] = + WMI_PDEV_PARAM_WHAL_MIB_STATS_UPDATE_ENABLE; + pdev_param[wmi_pdev_param_vdev_rate_stats_update_period] = + WMI_PDEV_PARAM_VDEV_RATE_STATS_UPDATE_PERIOD; + pdev_param[wmi_pdev_param_cts_cbw] = WMI_PDEV_PARAM_CTS_CBW; + pdev_param[wmi_pdev_param_wnts_config] = WMI_PDEV_PARAM_WNTS_CONFIG; + pdev_param[wmi_pdev_param_adaptive_early_rx_enable] = + WMI_PDEV_PARAM_ADAPTIVE_EARLY_RX_ENABLE; + pdev_param[wmi_pdev_param_adaptive_early_rx_min_sleep_slop] = + WMI_PDEV_PARAM_ADAPTIVE_EARLY_RX_MIN_SLEEP_SLOP; + pdev_param[wmi_pdev_param_adaptive_early_rx_inc_dec_step] = + WMI_PDEV_PARAM_ADAPTIVE_EARLY_RX_INC_DEC_STEP; + pdev_param[wmi_pdev_param_early_rx_fix_sleep_slop] = + WMI_PDEV_PARAM_EARLY_RX_FIX_SLEEP_SLOP; + pdev_param[wmi_pdev_param_bmiss_based_adaptive_bto_enable] = + WMI_PDEV_PARAM_BMISS_BASED_ADAPTIVE_BTO_ENABLE; + pdev_param[wmi_pdev_param_bmiss_bto_min_bcn_timeout] = + WMI_PDEV_PARAM_BMISS_BTO_MIN_BCN_TIMEOUT; + pdev_param[wmi_pdev_param_bmiss_bto_inc_dec_step] = + WMI_PDEV_PARAM_BMISS_BTO_INC_DEC_STEP; + pdev_param[wmi_pdev_param_bto_fix_bcn_timeout] = + WMI_PDEV_PARAM_BTO_FIX_BCN_TIMEOUT; + pdev_param[wmi_pdev_param_ce_based_adaptive_bto_enable] = + WMI_PDEV_PARAM_CE_BASED_ADAPTIVE_BTO_ENABLE; + pdev_param[wmi_pdev_param_ce_bto_combo_ce_value] = + WMI_PDEV_PARAM_CE_BTO_COMBO_CE_VALUE; + pdev_param[wmi_pdev_param_tx_chain_mask_2g] = + WMI_PDEV_PARAM_TX_CHAIN_MASK_2G; + pdev_param[wmi_pdev_param_rx_chain_mask_2g] = + WMI_PDEV_PARAM_RX_CHAIN_MASK_2G; + pdev_param[wmi_pdev_param_tx_chain_mask_5g] = + WMI_PDEV_PARAM_TX_CHAIN_MASK_5G; + pdev_param[wmi_pdev_param_rx_chain_mask_5g] = + WMI_PDEV_PARAM_RX_CHAIN_MASK_5G; + pdev_param[wmi_pdev_param_tx_chain_mask_cck] = + WMI_PDEV_PARAM_TX_CHAIN_MASK_CCK; + pdev_param[wmi_pdev_param_tx_chain_mask_1ss] = + WMI_PDEV_PARAM_TX_CHAIN_MASK_1SS; + pdev_param[wmi_pdev_param_rx_filter] = WMI_UNAVAILABLE_PARAM; + pdev_param[wmi_pdev_set_mcast_to_ucast_tid] = WMI_UNAVAILABLE_PARAM; + pdev_param[wmi_pdev_param_mgmt_retry_limit] = WMI_UNAVAILABLE_PARAM; + pdev_param[wmi_pdev_param_aggr_burst] = WMI_UNAVAILABLE_PARAM; + pdev_param[wmi_pdev_peer_sta_ps_statechg_enable] = + WMI_UNAVAILABLE_PARAM; + pdev_param[wmi_pdev_param_proxy_sta_mode] = WMI_UNAVAILABLE_PARAM; + pdev_param[wmi_pdev_param_mu_group_policy] = WMI_UNAVAILABLE_PARAM; + pdev_param[wmi_pdev_param_noise_detection] = WMI_UNAVAILABLE_PARAM; + pdev_param[wmi_pdev_param_noise_threshold] = WMI_UNAVAILABLE_PARAM; + pdev_param[wmi_pdev_param_dpd_enable] = WMI_UNAVAILABLE_PARAM; + pdev_param[wmi_pdev_param_set_mcast_bcast_echo] = WMI_UNAVAILABLE_PARAM; + pdev_param[wmi_pdev_param_atf_strict_sch] = WMI_UNAVAILABLE_PARAM; + pdev_param[wmi_pdev_param_atf_sched_duration] = WMI_UNAVAILABLE_PARAM; + pdev_param[wmi_pdev_param_ant_plzn] = WMI_UNAVAILABLE_PARAM; + pdev_param[wmi_pdev_param_sensitivity_level] = WMI_UNAVAILABLE_PARAM; + pdev_param[wmi_pdev_param_signed_txpower_2g] = WMI_UNAVAILABLE_PARAM; + pdev_param[wmi_pdev_param_signed_txpower_5g] = WMI_UNAVAILABLE_PARAM; + pdev_param[wmi_pdev_param_enable_per_tid_amsdu] = WMI_UNAVAILABLE_PARAM; + pdev_param[wmi_pdev_param_enable_per_tid_ampdu] = WMI_UNAVAILABLE_PARAM; + pdev_param[wmi_pdev_param_cca_threshold] = WMI_UNAVAILABLE_PARAM; + pdev_param[wmi_pdev_param_rts_fixed_rate] = WMI_UNAVAILABLE_PARAM; + pdev_param[wmi_pdev_param_cal_period] = WMI_UNAVAILABLE_PARAM; + pdev_param[wmi_pdev_param_pdev_reset] = WMI_UNAVAILABLE_PARAM; + pdev_param[wmi_pdev_param_wapi_mbssid_offset] = WMI_UNAVAILABLE_PARAM; + pdev_param[wmi_pdev_param_arp_srcaddr] = WMI_UNAVAILABLE_PARAM; + pdev_param[wmi_pdev_param_arp_dstaddr] = WMI_UNAVAILABLE_PARAM; + pdev_param[wmi_pdev_param_txpower_decr_db] = WMI_UNAVAILABLE_PARAM; + pdev_param[wmi_pdev_param_rx_batchmode] = WMI_UNAVAILABLE_PARAM; + pdev_param[wmi_pdev_param_packet_aggr_delay] = WMI_UNAVAILABLE_PARAM; + pdev_param[wmi_pdev_param_atf_obss_noise_sch] = WMI_UNAVAILABLE_PARAM; + pdev_param[wmi_pdev_param_atf_obss_noise_scaling_factor] = + WMI_UNAVAILABLE_PARAM; + pdev_param[wmi_pdev_param_cust_txpower_scale] = WMI_UNAVAILABLE_PARAM; + pdev_param[wmi_pdev_param_atf_dynamic_enable] = WMI_UNAVAILABLE_PARAM; + pdev_param[wmi_pdev_param_atf_ssid_group_policy] = + WMI_UNAVAILABLE_PARAM; + pdev_param[wmi_pdev_param_igmpmld_override] = WMI_UNAVAILABLE_PARAM; + pdev_param[wmi_pdev_param_igmpmld_tid] = WMI_UNAVAILABLE_PARAM; + pdev_param[wmi_pdev_param_antenna_gain] = WMI_UNAVAILABLE_PARAM; + pdev_param[wmi_pdev_param_block_interbss] = WMI_UNAVAILABLE_PARAM; + pdev_param[wmi_pdev_param_set_disable_reset_cmdid] = + WMI_UNAVAILABLE_PARAM; + pdev_param[wmi_pdev_param_set_msdu_ttl_cmdid] = WMI_UNAVAILABLE_PARAM; + pdev_param[wmi_pdev_param_txbf_sound_period_cmdid] = + WMI_UNAVAILABLE_PARAM; + pdev_param[wmi_pdev_param_set_burst_mode_cmdid] = WMI_UNAVAILABLE_PARAM; + pdev_param[wmi_pdev_param_en_stats] = WMI_UNAVAILABLE_PARAM; +} + +/** + * populate_vdev_param_tlv() - populates vdev params + * + * @param vdev_param: Pointer to hold vdev params + * Return: None + */ +static void populate_vdev_param_tlv(uint32_t *vdev_param) +{ + vdev_param[wmi_vdev_param_rts_threshold] = WMI_VDEV_PARAM_RTS_THRESHOLD; + vdev_param[wmi_vdev_param_fragmentation_threshold] = + WMI_VDEV_PARAM_FRAGMENTATION_THRESHOLD; + vdev_param[wmi_vdev_param_beacon_interval] = + WMI_VDEV_PARAM_BEACON_INTERVAL; + vdev_param[wmi_vdev_param_listen_interval] = + WMI_VDEV_PARAM_LISTEN_INTERVAL; + vdev_param[wmi_vdev_param_multicast_rate] = + WMI_VDEV_PARAM_MULTICAST_RATE; + vdev_param[wmi_vdev_param_mgmt_tx_rate] = WMI_VDEV_PARAM_MGMT_TX_RATE; + vdev_param[wmi_vdev_param_slot_time] = WMI_VDEV_PARAM_SLOT_TIME; + vdev_param[wmi_vdev_param_preamble] = WMI_VDEV_PARAM_PREAMBLE; + vdev_param[wmi_vdev_param_swba_time] = WMI_VDEV_PARAM_SWBA_TIME; + vdev_param[wmi_vdev_stats_update_period] = WMI_VDEV_STATS_UPDATE_PERIOD; + vdev_param[wmi_vdev_pwrsave_ageout_time] = WMI_VDEV_PWRSAVE_AGEOUT_TIME; + vdev_param[wmi_vdev_host_swba_interval] = WMI_VDEV_HOST_SWBA_INTERVAL; + vdev_param[wmi_vdev_param_dtim_period] = WMI_VDEV_PARAM_DTIM_PERIOD; + vdev_param[wmi_vdev_oc_scheduler_air_time_limit] = + WMI_VDEV_OC_SCHEDULER_AIR_TIME_LIMIT; + vdev_param[wmi_vdev_param_wds] = WMI_VDEV_PARAM_WDS; + vdev_param[wmi_vdev_param_atim_window] = WMI_VDEV_PARAM_ATIM_WINDOW; + vdev_param[wmi_vdev_param_bmiss_count_max] = + WMI_VDEV_PARAM_BMISS_COUNT_MAX; + vdev_param[wmi_vdev_param_bmiss_first_bcnt] = + WMI_VDEV_PARAM_BMISS_FIRST_BCNT; + vdev_param[wmi_vdev_param_bmiss_final_bcnt] = + WMI_VDEV_PARAM_BMISS_FINAL_BCNT; + vdev_param[wmi_vdev_param_feature_wmm] = WMI_VDEV_PARAM_FEATURE_WMM; + vdev_param[wmi_vdev_param_chwidth] = WMI_VDEV_PARAM_CHWIDTH; + vdev_param[wmi_vdev_param_chextoffset] = WMI_VDEV_PARAM_CHEXTOFFSET; + vdev_param[wmi_vdev_param_disable_htprotection] = + WMI_VDEV_PARAM_DISABLE_HTPROTECTION; + vdev_param[wmi_vdev_param_sta_quickkickout] = + WMI_VDEV_PARAM_STA_QUICKKICKOUT; + vdev_param[wmi_vdev_param_mgmt_rate] = WMI_VDEV_PARAM_MGMT_RATE; + vdev_param[wmi_vdev_param_protection_mode] = + WMI_VDEV_PARAM_PROTECTION_MODE; + vdev_param[wmi_vdev_param_fixed_rate] = WMI_VDEV_PARAM_FIXED_RATE; + vdev_param[wmi_vdev_param_sgi] = WMI_VDEV_PARAM_SGI; + vdev_param[wmi_vdev_param_ldpc] = WMI_VDEV_PARAM_LDPC; + vdev_param[wmi_vdev_param_tx_stbc] = WMI_VDEV_PARAM_TX_STBC; + vdev_param[wmi_vdev_param_rx_stbc] = WMI_VDEV_PARAM_RX_STBC; + vdev_param[wmi_vdev_param_intra_bss_fwd] = WMI_VDEV_PARAM_INTRA_BSS_FWD; + vdev_param[wmi_vdev_param_def_keyid] = WMI_VDEV_PARAM_DEF_KEYID; + vdev_param[wmi_vdev_param_nss] = WMI_VDEV_PARAM_NSS; + vdev_param[wmi_vdev_param_bcast_data_rate] = + WMI_VDEV_PARAM_BCAST_DATA_RATE; + vdev_param[wmi_vdev_param_mcast_data_rate] = + WMI_VDEV_PARAM_MCAST_DATA_RATE; + vdev_param[wmi_vdev_param_mcast_indicate] = + WMI_VDEV_PARAM_MCAST_INDICATE; + vdev_param[wmi_vdev_param_dhcp_indicate] = + WMI_VDEV_PARAM_DHCP_INDICATE; + vdev_param[wmi_vdev_param_unknown_dest_indicate] = + WMI_VDEV_PARAM_UNKNOWN_DEST_INDICATE; + vdev_param[wmi_vdev_param_ap_keepalive_min_idle_inactive_time_secs] = + WMI_VDEV_PARAM_AP_KEEPALIVE_MIN_IDLE_INACTIVE_TIME_SECS; + vdev_param[wmi_vdev_param_ap_keepalive_max_idle_inactive_time_secs] = + WMI_VDEV_PARAM_AP_KEEPALIVE_MAX_IDLE_INACTIVE_TIME_SECS; + vdev_param[wmi_vdev_param_ap_keepalive_max_unresponsive_time_secs] = + WMI_VDEV_PARAM_AP_KEEPALIVE_MAX_UNRESPONSIVE_TIME_SECS; + vdev_param[wmi_vdev_param_ap_enable_nawds] = + WMI_VDEV_PARAM_AP_ENABLE_NAWDS; + vdev_param[wmi_vdev_param_enable_rtscts] = WMI_VDEV_PARAM_ENABLE_RTSCTS; + vdev_param[wmi_vdev_param_txbf] = WMI_VDEV_PARAM_TXBF; + vdev_param[wmi_vdev_param_packet_powersave] = + WMI_VDEV_PARAM_PACKET_POWERSAVE; + vdev_param[wmi_vdev_param_drop_unencry] = WMI_VDEV_PARAM_DROP_UNENCRY; + vdev_param[wmi_vdev_param_tx_encap_type] = WMI_VDEV_PARAM_TX_ENCAP_TYPE; + vdev_param[wmi_vdev_param_ap_detect_out_of_sync_sleeping_sta_time_secs] = + WMI_VDEV_PARAM_AP_DETECT_OUT_OF_SYNC_SLEEPING_STA_TIME_SECS; + vdev_param[wmi_vdev_param_early_rx_adjust_enable] = + WMI_VDEV_PARAM_EARLY_RX_ADJUST_ENABLE; + vdev_param[wmi_vdev_param_early_rx_tgt_bmiss_num] = + WMI_VDEV_PARAM_EARLY_RX_TGT_BMISS_NUM; + vdev_param[wmi_vdev_param_early_rx_bmiss_sample_cycle] = + WMI_VDEV_PARAM_EARLY_RX_BMISS_SAMPLE_CYCLE; + vdev_param[wmi_vdev_param_early_rx_slop_step] = + WMI_VDEV_PARAM_EARLY_RX_SLOP_STEP; + vdev_param[wmi_vdev_param_early_rx_init_slop] = + WMI_VDEV_PARAM_EARLY_RX_INIT_SLOP; + vdev_param[wmi_vdev_param_early_rx_adjust_pause] = + WMI_VDEV_PARAM_EARLY_RX_ADJUST_PAUSE; + vdev_param[wmi_vdev_param_tx_pwrlimit] = WMI_VDEV_PARAM_TX_PWRLIMIT; + vdev_param[wmi_vdev_param_snr_num_for_cal] = + WMI_VDEV_PARAM_SNR_NUM_FOR_CAL; + vdev_param[wmi_vdev_param_roam_fw_offload] = + WMI_VDEV_PARAM_ROAM_FW_OFFLOAD; + vdev_param[wmi_vdev_param_enable_rmc] = WMI_VDEV_PARAM_ENABLE_RMC; + vdev_param[wmi_vdev_param_ibss_max_bcn_lost_ms] = + WMI_VDEV_PARAM_IBSS_MAX_BCN_LOST_MS; + vdev_param[wmi_vdev_param_max_rate] = WMI_VDEV_PARAM_MAX_RATE; + vdev_param[wmi_vdev_param_early_rx_drift_sample] = + WMI_VDEV_PARAM_EARLY_RX_DRIFT_SAMPLE; + vdev_param[wmi_vdev_param_set_ibss_tx_fail_cnt_thr] = + WMI_VDEV_PARAM_SET_IBSS_TX_FAIL_CNT_THR; + vdev_param[wmi_vdev_param_ebt_resync_timeout] = + WMI_VDEV_PARAM_EBT_RESYNC_TIMEOUT; + vdev_param[wmi_vdev_param_aggr_trig_event_enable] = + WMI_VDEV_PARAM_AGGR_TRIG_EVENT_ENABLE; + vdev_param[wmi_vdev_param_is_ibss_power_save_allowed] = + WMI_VDEV_PARAM_IS_IBSS_POWER_SAVE_ALLOWED; + vdev_param[wmi_vdev_param_is_power_collapse_allowed] = + WMI_VDEV_PARAM_IS_POWER_COLLAPSE_ALLOWED; + vdev_param[wmi_vdev_param_is_awake_on_txrx_enabled] = + WMI_VDEV_PARAM_IS_AWAKE_ON_TXRX_ENABLED; + vdev_param[wmi_vdev_param_inactivity_cnt] = + WMI_VDEV_PARAM_INACTIVITY_CNT; + vdev_param[wmi_vdev_param_txsp_end_inactivity_time_ms] = + WMI_VDEV_PARAM_TXSP_END_INACTIVITY_TIME_MS; + vdev_param[wmi_vdev_param_dtim_policy] = WMI_VDEV_PARAM_DTIM_POLICY; + vdev_param[wmi_vdev_param_ibss_ps_warmup_time_secs] = + WMI_VDEV_PARAM_IBSS_PS_WARMUP_TIME_SECS; + vdev_param[wmi_vdev_param_ibss_ps_1rx_chain_in_atim_window_enable] = + WMI_VDEV_PARAM_IBSS_PS_1RX_CHAIN_IN_ATIM_WINDOW_ENABLE; + vdev_param[wmi_vdev_param_rx_leak_window] = + WMI_VDEV_PARAM_RX_LEAK_WINDOW; + vdev_param[wmi_vdev_param_stats_avg_factor] = + WMI_VDEV_PARAM_STATS_AVG_FACTOR; + vdev_param[wmi_vdev_param_disconnect_th] = WMI_VDEV_PARAM_DISCONNECT_TH; + vdev_param[wmi_vdev_param_rtscts_rate] = WMI_VDEV_PARAM_RTSCTS_RATE; + vdev_param[wmi_vdev_param_mcc_rtscts_protection_enable] = + WMI_VDEV_PARAM_MCC_RTSCTS_PROTECTION_ENABLE; + vdev_param[wmi_vdev_param_mcc_broadcast_probe_enable] = + WMI_VDEV_PARAM_MCC_BROADCAST_PROBE_ENABLE; +} +#endif + +/** + * wmi_tlv_attach() - Attach TLV APIs + * + * Return: None + */ +#ifdef WMI_TLV_AND_NON_TLV_SUPPORT +void wmi_tlv_attach(wmi_unified_t wmi_handle) +{ + wmi_handle->ops = &tlv_ops; +#ifdef WMI_INTERFACE_EVENT_LOGGING + wmi_handle->log_info.buf_offset_command = 2; + wmi_handle->log_info.buf_offset_event = 4; + wmi_handle->log_info.is_management_record = + is_management_record_tlv; +#endif + populate_tlv_service(wmi_handle->services); + populate_tlv_events_id(wmi_handle->wmi_events); + populate_pdev_param_tlv(wmi_handle->pdev_param); + populate_vdev_param_tlv(wmi_handle->vdev_param); +} +#else +void wmi_tlv_attach(wmi_unified_t wmi_handle) +{ + wmi_handle->ops = &tlv_ops; +#ifdef WMI_INTERFACE_EVENT_LOGGING + wmi_handle->log_info.buf_offset_command = 2; + wmi_handle->log_info.buf_offset_event = 4; + wmi_handle->log_info.is_management_record = + is_management_record_tlv; +#endif +} +#endif diff --git a/drivers/staging/qcacld-3.0/Kbuild b/drivers/staging/qcacld-3.0/Kbuild new file mode 100644 index 0000000000000000000000000000000000000000..38bc9893aaf3d6657c3729ee4a0d430c2d123be6 --- /dev/null +++ b/drivers/staging/qcacld-3.0/Kbuild @@ -0,0 +1,1669 @@ +# We can build either as part of a standalone Kernel build or as +# an external module. Determine which mechanism is being used +ifeq ($(MODNAME),) + KERNEL_BUILD := 1 +else + KERNEL_BUILD := 0 +endif + +ifeq ($(CONFIG_CLD_HL_SDIO_CORE), y) + CONFIG_QCA_WIFI_SDIO := 1 +endif + +ifeq ($(CONFIG_QCA_WIFI_SDIO), 1) + CONFIG_ROME_IF = sdio +endif + +ifdef CONFIG_ICNSS + CONFIG_ROME_IF = snoc +endif + +ifeq ($(CONFIG_CNSS), y) +ifndef CONFIG_ROME_IF + #use pci as default interface + CONFIG_ROME_IF = pci +endif +endif + +ifeq ($(KERNEL_BUILD),1) + # These are provided in external module based builds + # Need to explicitly define for Kernel-based builds + MODNAME := wlan + WLAN_ROOT := drivers/staging/qcacld-3.0 + WLAN_COMMON_ROOT := ../qca-wifi-host-cmn + WLAN_COMMON_INC := $(WLAN_ROOT)/$(WLAN_COMMON_ROOT) +endif + +# Make WLAN as open-source driver by default +WLAN_OPEN_SOURCE := 1 + +ifeq ($(KERNEL_BUILD), 0) + # These are configurable via Kconfig for kernel-based builds + # Need to explicitly configure for Android-based builds + + ifeq ($(CONFIG_ARCH_MDM9630), y) + CONFIG_MOBILE_ROUTER := y + endif + + ifeq ($(CONFIG_ARCH_MDM9640), y) + CONFIG_MOBILE_ROUTER := y + endif + + # As per target team, build is done as follows: + # Defconfig : build with default flags + # Slub : defconfig + CONFIG_SLUB_DEBUG=y + + # CONFIG_SLUB_DEBUG_ON=y + CONFIG_PAGE_POISONING=y + # Perf : Using appropriate msmXXXX-perf_defconfig + # + # Shipment builds (user variants) should not have any debug feature + # enabled. This is identified using 'TARGET_BUILD_VARIANT'. Slub builds + # are identified using the CONFIG_SLUB_DEBUG_ON configuration. Since + # there is no other way to identify defconfig builds, QCOMs internal + # representation of perf builds (identified using the string 'perf'), + # is used to identify if the build is a slub or defconfig one. This + # way no critical debug feature will be enabled for perf and shipment + # builds. Other OEMs are also protected using the TARGET_BUILD_VARIANT + # config. + ifneq ($(TARGET_BUILD_VARIANT),user) + CONFIG_FEATURE_PKTLOG := y + ifeq ($(CONFIG_SLUB_DEBUG_ON),y) + CONFIG_FEATURE_DP_TRACE := y + else + ifeq ($(findstring perf,$(KERNEL_DEFCONFIG)),) + CONFIG_FEATURE_DP_TRACE := y + endif + endif + endif + + #Flag to enable Legacy Fast Roaming2(LFR2) + CONFIG_QCACLD_WLAN_LFR2 := y + #Flag to enable Legacy Fast Roaming3(LFR3) + ifneq ($(CONFIG_ARCH_SDXHEDGEHOG), y) + CONFIG_QCACLD_WLAN_LFR3 := y + endif + + #Enable Power debugfs feature only if debug_fs is enabled + ifeq ($(CONFIG_DEBUG_FS), y) + CONFIG_WLAN_POWER_DEBUGFS := y + endif + + # JB kernel has CPU enablement patches, so enable + ifeq ($(CONFIG_ROME_IF),pci) + CONFIG_PRIMA_WLAN_11AC_HIGH_TP := y + endif + ifeq ($(CONFIG_ROME_IF),usb) + CONFIG_PRIMA_WLAN_11AC_HIGH_TP := n + endif + ifeq ($(CONFIG_ROME_IF),sdio) + CONFIG_PRIMA_WLAN_11AC_HIGH_TP := n + endif + + ifneq ($(CONFIG_MOBILE_ROUTER), y) + #Flag to enable TDLS feature + CONFIG_QCOM_TDLS := y + endif + + ifeq ($(CONFIG_MOBILE_ROUTER), y) + CONFIG_QCACLD_FEATURE_GREEN_AP := y + endif + ifeq ($(CONFIG_ARCH_MSM8998), y) + CONFIG_QCACLD_FEATURE_GREEN_AP := y + CONFIG_QCACLD_FEATURE_METERING := y + endif + + ifeq ($(CONFIG_ARCH_SDM660), y) + CONFIG_QCACLD_FEATURE_GREEN_AP := y + CONFIG_QCACLD_FEATURE_METERING := y + endif + + ifeq ($(CONFIG_ARCH_SDM630), y) + CONFIG_QCACLD_FEATURE_METERING := y + endif + + #Flag to enable Fast Transition (11r) feature + CONFIG_QCOM_VOWIFI_11R := y + + ifneq ($(CONFIG_QCA_CLD_WLAN),) + ifeq (y,$(findstring y,$(CONFIG_CNSS) $(CONFIG_ICNSS))) + #Flag to enable Protected Managment Frames (11w) feature + CONFIG_WLAN_FEATURE_11W := y + #Flag to enable LTE CoEx feature + CONFIG_QCOM_LTE_COEX := y + ifneq ($(CONFIG_MOBILE_ROUTER), y) + #Flag to enable LPSS feature + CONFIG_WLAN_FEATURE_LPSS := y + endif + endif + endif + + #Flag to enable Protected Managment Frames (11w) feature + ifeq ($(CONFIG_ROME_IF),usb) + CONFIG_WLAN_FEATURE_11W := y + endif + ifeq ($(CONFIG_ROME_IF),sdio) + CONFIG_WLAN_FEATURE_11W := y + endif + + #Flag to enable the tx desc sanity check + ifeq ($(CONFIG_ROME_IF),usb) + CONFIG_QCA_TXDESC_SANITY_CHECKS := y + endif + + ifneq ($(CONFIG_MOBILE_ROUTER), y) + #Flag to enable NAN + CONFIG_QCACLD_FEATURE_NAN := y + endif + + ifneq ($(CONFIG_MOBILE_ROUTER), y) + #Flag to enable NAN Data path + CONFIG_WLAN_FEATURE_NAN_DATAPATH := y + endif + + #Flag to enable Linux QCMBR feature as default feature + ifeq ($(CONFIG_ROME_IF),usb) + CONFIG_LINUX_QCMBR :=y + endif + + CONFIG_MPC_UT_FRAMEWORK := y + + #Flag to enable offload packets feature + CONFIG_WLAN_OFFLOAD_PACKETS := y + + #enable TSF get feature + CONFIG_WLAN_SYNC_TSF := y + #Enable DSRC feature + + ifeq ($(CONFIG_QCA_WIFI_SDIO), 1) + CONFIG_WLAN_FEATURE_DSRC := y + endif + +ifneq ($(CONFIG_ROME_IF),sdio) + #Flag to enable memdump feature + CONFIG_WLAN_FEATURE_MEMDUMP := y + + #Flag to enable DISA + CONFIG_WLAN_FEATURE_DISA := y + + #Flag to enable Fast Path feature + CONFIG_WLAN_FASTPATH := y + + # Flag to enable NAPI + CONFIG_WLAN_NAPI := y + CONFIG_WLAN_NAPI_DEBUG := n + + # Flag to enable FW based TX Flow control + ifeq ($(CONFIG_CNSS_EOS),y) + CONFIG_WLAN_TX_FLOW_CONTROL_V2 := y + else + CONFIG_WLAN_TX_FLOW_CONTROL_V2 := n + endif + + # Flag to enable LRO (Large Receive Offload) + ifeq ($(CONFIG_INET_LRO), y) + ifeq ($(VERSION), 4) + CONFIG_WLAN_LRO := y + else + CONFIG_WLAN_LRO := n + endif + endif +endif + +ifeq ($(CONFIG_ROME_IF), snoc) + CONFIG_WLAN_TX_FLOW_CONTROL_V2 := y +endif + + # Flag to enable LFR Subnet Detection + CONFIG_LFR_SUBNET_DETECTION := y + + # Flag to enable MCC to SCC switch feature + CONFIG_MCC_TO_SCC_SWITCH := y + +ifeq ($(CONFIG_DEBUG_FS), y) + # Flag to enable debugfs. Depends on CONFIG_DEBUG_FS in kernel + # configuration. + CONFIG_WLAN_DEBUGFS := y +endif + +endif + +# If not set, assume, Common driver is with in the build tree +WLAN_COMMON_ROOT ?= ../qca-wifi-host-cmn +WLAN_COMMON_INC ?= $(WLAN_ROOT)/$(WLAN_COMMON_ROOT) + +ifneq ($(CONFIG_MOBILE_ROUTER), y) +CONFIG_QCOM_ESE := y +endif + +# Feature flags which are not (currently) configurable via Kconfig + +#Whether to build debug version +BUILD_DEBUG_VERSION := 1 + +#Enable this flag to build driver in diag version +BUILD_DIAG_VERSION := 1 + +#Do we panic on bug? default is to warn +PANIC_ON_BUG := 1 + +#Enable OL debug and wmi unified functions +CONFIG_ATH_PERF_PWR_OFFLOAD := 1 + +#Disable packet log +CONFIG_REMOVE_PKT_LOG := 0 + +#Enable 11AC TX +ifeq ($(CONFIG_ROME_IF),pci) + CONFIG_ATH_11AC_TXCOMPACT := 1 +endif +ifeq ($(CONFIG_ROME_IF),usb) + CONFIG_ATH_11AC_TXCOMPACT := 0 +endif + +#Enable OS specific IRQ abstraction +CONFIG_ATH_SUPPORT_SHARED_IRQ := 1 + +#Enable message based HIF instead of RAW access in BMI +ifeq ($(CONFIG_QCA_WIFI_SDIO), 1) +CONFIG_HIF_MESSAGE_BASED := 0 +else +CONFIG_HIF_MESSAGE_BASED := 1 +endif + +#Enable PCI specific APIS (dma, etc) +ifeq ($(CONFIG_ROME_IF),pci) + CONFIG_HIF_PCI := 1 +endif + +#Enable USB specific APIS +ifeq ($(CONFIG_ROME_IF),usb) + CONFIG_HIF_USB := 1 + CONFIG_PLD_USB_CNSS := y +endif + +#Enable SDIO specific APIS +ifeq ($(CONFIG_ROME_IF),sdio) + CONFIG_HIF_SDIO := 1 +endif + +#Enable pci read/write config functions +ifeq ($(CONFIG_ROME_IF),pci) + CONFIG_ATH_PCI := 1 +endif + +ifeq ($(CONFIG_ROME_IF),snoc) + CONFIG_HIF_SNOC:= 1 +endif + +ifneq ($(CONFIG_MOBILE_ROUTER), y) +#Enable IBSS support on CLD +CONFIG_QCA_IBSS_SUPPORT := 1 +endif + +#Enable power management suspend/resume functionality to PCI +CONFIG_ATH_BUS_PM := 1 + +#Enable FLOWMAC module support +CONFIG_ATH_SUPPORT_FLOWMAC_MODULE := 0 + +#Enable spectral support +CONFIG_ATH_SUPPORT_SPECTRAL := 0 + +#Enable HOST statistics support +CONFIG_SUPPORT_HOST_STATISTICS := 0 + +#Enable WDI Event support +CONFIG_WDI_EVENT_ENABLE := 1 + +#Endianess selection +CONFIG_LITTLE_ENDIAN := 1 + +#Enable TX reclaim support +CONFIG_TX_CREDIT_RECLAIM_SUPPORT := 0 + +#Enable FTM support +CONFIG_QCA_WIFI_FTM := 1 + +#Enable Checksum Offload +CONFIG_CHECKSUM_OFFLOAD := 1 + +#Enable GTK offload +CONFIG_GTK_OFFLOAD := 1 + +#Enable EXT WOW +ifeq ($(CONFIG_ROME_IF),pci) + CONFIG_EXT_WOW := 1 +endif + +# Flag to enable bus auto suspend +ifeq ($(CONFIG_ROME_IF),pci) +ifeq ($(CONFIG_BUS_AUTO_SUSPEND), y) +CDEFINES += -DFEATURE_RUNTIME_PM +endif +endif + +#Set this to 1 to catch erroneous Target accesses during debug. +CONFIG_ATH_PCIE_ACCESS_DEBUG := 0 + +#Enable IPA offload +ifeq ($(CONFIG_IPA), y) +CONFIG_IPA_OFFLOAD := 1 +endif + +#Enable Signed firmware support for split binary format +CONFIG_QCA_SIGNED_SPLIT_BINARY_SUPPORT := 0 + +#Enable single firmware binary format +CONFIG_QCA_SINGLE_BINARY_SUPPORT := 0 + +#Enable collecting target RAM dump after kernel panic +CONFIG_TARGET_RAMDUMP_AFTER_KERNEL_PANIC := 1 + +#Flag to enable/disable secure firmware feature +CONFIG_FEATURE_SECURE_FIRMWARE := 0 + +#Flag to enable Stats Ext implementation +CONFIG_FEATURE_STATS_EXT := 1 + +ifeq ($(CONFIG_CFG80211),y) +HAVE_CFG80211 := 1 +else +ifeq ($(CONFIG_CFG80211),m) +HAVE_CFG80211 := 1 +else +HAVE_CFG80211 := 0 +endif +endif + +############ UAPI ############ +UAPI_DIR := uapi +UAPI_INC := -I$(WLAN_ROOT)/$(UAPI_DIR)/linux + +############ COMMON ############ +COMMON_DIR := core/common +COMMON_INC := -I$(WLAN_ROOT)/$(COMMON_DIR) + +############ HDD ############ +HDD_DIR := core/hdd +HDD_INC_DIR := $(HDD_DIR)/inc +HDD_SRC_DIR := $(HDD_DIR)/src + +HDD_INC := -I$(WLAN_ROOT)/$(HDD_INC_DIR) \ + -I$(WLAN_ROOT)/$(HDD_SRC_DIR) + +HDD_OBJS := $(HDD_SRC_DIR)/wlan_hdd_assoc.o \ + $(HDD_SRC_DIR)/wlan_hdd_cfg.o \ + $(HDD_SRC_DIR)/wlan_hdd_driver_ops.o \ + $(HDD_SRC_DIR)/wlan_hdd_ftm.o \ + $(HDD_SRC_DIR)/wlan_hdd_hostapd.o \ + $(HDD_SRC_DIR)/wlan_hdd_ioctl.o \ + $(HDD_SRC_DIR)/wlan_hdd_main.o \ + $(HDD_SRC_DIR)/wlan_hdd_oemdata.o \ + $(HDD_SRC_DIR)/wlan_hdd_power.o \ + $(HDD_SRC_DIR)/wlan_hdd_regulatory.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 \ + $(HDD_SRC_DIR)/wlan_hdd_trace.o \ + $(HDD_SRC_DIR)/wlan_hdd_wext.o \ + $(HDD_SRC_DIR)/wlan_hdd_wmm.o \ + $(HDD_SRC_DIR)/wlan_hdd_wowl.o \ + $(HDD_SRC_DIR)/wlan_hdd_packet_filter.o + +ifeq ($(CONFIG_WLAN_DEBUGFS), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_debugfs.o +endif + +ifeq ($(CONFIG_WLAN_FEATURE_DSRC), y) +HDD_OBJS+= $(HDD_SRC_DIR)/wlan_hdd_ocb.o +endif + +ifeq ($(CONFIG_WLAN_FEATURE_LPSS),y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_lpass.o +endif + +ifeq ($(CONFIG_WLAN_LRO), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_lro.o +endif + +ifeq ($(CONFIG_WLAN_NAPI), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_napi.o +endif + +ifeq ($(CONFIG_IPA_OFFLOAD), 1) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_ipa.o +endif + +ifeq ($(HAVE_CFG80211),1) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_cfg80211.o \ + $(HDD_SRC_DIR)/wlan_hdd_ext_scan.o \ + $(HDD_SRC_DIR)/wlan_hdd_stats.o \ + $(HDD_SRC_DIR)/wlan_hdd_p2p.o +endif + +ifeq ($(CONFIG_QCACLD_FEATURE_GREEN_AP),y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_green_ap.o +endif + +ifeq ($(CONFIG_QCACLD_FEATURE_NAN),y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_nan.o +endif + +ifeq ($(CONFIG_QCOM_TDLS),y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_tdls.o +endif + +ifeq ($(CONFIG_WLAN_SYNC_TSF),y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_tsf.o +endif + +ifeq ($(CONFIG_MPC_UT_FRAMEWORK),y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_conc_ut.o +endif + +ifeq ($(CONFIG_WLAN_FEATURE_MEMDUMP),y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_memdump.o +endif + +ifeq ($(CONFIG_WLAN_FEATURE_DISA),y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_disa.o +endif + +ifeq ($(CONFIG_LFR_SUBNET_DETECTION), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_subnet_detect.o +endif + +ifeq ($(CONFIG_WLAN_FEATURE_NAN_DATAPATH), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_nan_datapath.o +endif + +########### HOST DIAG LOG ########### +HOST_DIAG_LOG_DIR := core/utils/host_diag_log + +HOST_DIAG_LOG_INC_DIR := $(HOST_DIAG_LOG_DIR)/inc +HOST_DIAG_LOG_SRC_DIR := $(HOST_DIAG_LOG_DIR)/src + +HOST_DIAG_LOG_INC := -I$(WLAN_ROOT)/$(HOST_DIAG_LOG_INC_DIR) \ + -I$(WLAN_ROOT)/$(HOST_DIAG_LOG_SRC_DIR) + +HOST_DIAG_LOG_OBJS += $(HOST_DIAG_LOG_SRC_DIR)/host_diag_log.o + +############ EPPING ############ +EPPING_DIR := core/utils/epping +EPPING_INC_DIR := $(EPPING_DIR)/inc +EPPING_SRC_DIR := $(EPPING_DIR)/src + +EPPING_INC := -I$(WLAN_ROOT)/$(EPPING_INC_DIR) + +EPPING_OBJS := $(EPPING_SRC_DIR)/epping_main.o \ + $(EPPING_SRC_DIR)/epping_txrx.o \ + $(EPPING_SRC_DIR)/epping_tx.o \ + $(EPPING_SRC_DIR)/epping_rx.o \ + $(EPPING_SRC_DIR)/epping_helper.o \ + + +############ MAC ############ +MAC_DIR := core/mac +MAC_INC_DIR := $(MAC_DIR)/inc +MAC_SRC_DIR := $(MAC_DIR)/src + +MAC_INC := -I$(WLAN_ROOT)/$(MAC_INC_DIR) \ + -I$(WLAN_ROOT)/$(MAC_SRC_DIR)/dph \ + -I$(WLAN_ROOT)/$(MAC_SRC_DIR)/include \ + -I$(WLAN_ROOT)/$(MAC_SRC_DIR)/pe/include \ + -I$(WLAN_ROOT)/$(MAC_SRC_DIR)/pe/lim \ + -I$(WLAN_ROOT)/$(MAC_SRC_DIR)/pe/nan + +MAC_CFG_OBJS := $(MAC_SRC_DIR)/cfg/cfg_api.o \ + $(MAC_SRC_DIR)/cfg/cfg_debug.o \ + $(MAC_SRC_DIR)/cfg/cfg_param_name.o \ + $(MAC_SRC_DIR)/cfg/cfg_proc_msg.o \ + $(MAC_SRC_DIR)/cfg/cfg_send_msg.o + +MAC_DPH_OBJS := $(MAC_SRC_DIR)/dph/dph_hash_table.o + +MAC_LIM_OBJS := $(MAC_SRC_DIR)/pe/lim/lim_aid_mgmt.o \ + $(MAC_SRC_DIR)/pe/lim/lim_admit_control.o \ + $(MAC_SRC_DIR)/pe/lim/lim_api.o \ + $(MAC_SRC_DIR)/pe/lim/lim_assoc_utils.o \ + $(MAC_SRC_DIR)/pe/lim/lim_debug.o \ + $(MAC_SRC_DIR)/pe/lim/lim_ft.o \ + $(MAC_SRC_DIR)/pe/lim/lim_ibss_peer_mgmt.o \ + $(MAC_SRC_DIR)/pe/lim/lim_link_monitoring_algo.o \ + $(MAC_SRC_DIR)/pe/lim/lim_p2p.o \ + $(MAC_SRC_DIR)/pe/lim/lim_process_action_frame.o \ + $(MAC_SRC_DIR)/pe/lim/lim_process_assoc_req_frame.o \ + $(MAC_SRC_DIR)/pe/lim/lim_process_assoc_rsp_frame.o \ + $(MAC_SRC_DIR)/pe/lim/lim_process_auth_frame.o \ + $(MAC_SRC_DIR)/pe/lim/lim_process_beacon_frame.o \ + $(MAC_SRC_DIR)/pe/lim/lim_process_cfg_updates.o \ + $(MAC_SRC_DIR)/pe/lim/lim_process_deauth_frame.o \ + $(MAC_SRC_DIR)/pe/lim/lim_process_disassoc_frame.o \ + $(MAC_SRC_DIR)/pe/lim/lim_process_message_queue.o \ + $(MAC_SRC_DIR)/pe/lim/lim_process_mlm_req_messages.o \ + $(MAC_SRC_DIR)/pe/lim/lim_process_mlm_rsp_messages.o \ + $(MAC_SRC_DIR)/pe/lim/lim_process_probe_req_frame.o \ + $(MAC_SRC_DIR)/pe/lim/lim_process_probe_rsp_frame.o \ + $(MAC_SRC_DIR)/pe/lim/lim_process_sme_req_messages.o \ + $(MAC_SRC_DIR)/pe/lim/lim_prop_exts_utils.o \ + $(MAC_SRC_DIR)/pe/lim/lim_scan_result_utils.o \ + $(MAC_SRC_DIR)/pe/lim/lim_security_utils.o \ + $(MAC_SRC_DIR)/pe/lim/lim_send_management_frames.o \ + $(MAC_SRC_DIR)/pe/lim/lim_send_messages.o \ + $(MAC_SRC_DIR)/pe/lim/lim_send_sme_rsp_messages.o \ + $(MAC_SRC_DIR)/pe/lim/lim_ser_des_utils.o \ + $(MAC_SRC_DIR)/pe/lim/lim_session.o \ + $(MAC_SRC_DIR)/pe/lim/lim_session_utils.o \ + $(MAC_SRC_DIR)/pe/lim/lim_sme_req_utils.o \ + $(MAC_SRC_DIR)/pe/lim/lim_sta_hash_api.o \ + $(MAC_SRC_DIR)/pe/lim/lim_timer_utils.o \ + $(MAC_SRC_DIR)/pe/lim/lim_trace.o \ + $(MAC_SRC_DIR)/pe/lim/lim_utils.o + +ifeq ($(CONFIG_QCOM_TDLS),y) +MAC_LIM_OBJS += $(MAC_SRC_DIR)/pe/lim/lim_process_tdls.o +endif + +ifeq ($(CONFIG_WLAN_FEATURE_NAN_DATAPATH), y) +MAC_NDP_OBJS += $(MAC_SRC_DIR)/pe/nan/nan_datapath.o +endif + +ifeq ($(CONFIG_QCACLD_WLAN_LFR2),y) + MAC_LIM_OBJS += $(MAC_SRC_DIR)/pe/lim/lim_process_mlm_host_roam.o \ + $(MAC_SRC_DIR)/pe/lim/lim_send_frames_host_roam.o \ + $(MAC_SRC_DIR)/pe/lim/lim_roam_timer_utils.o \ + $(MAC_SRC_DIR)/pe/lim/lim_ft_preauth.o \ + $(MAC_SRC_DIR)/pe/lim/lim_reassoc_utils.o +endif + +MAC_SCH_OBJS := $(MAC_SRC_DIR)/pe/sch/sch_api.o \ + $(MAC_SRC_DIR)/pe/sch/sch_beacon_gen.o \ + $(MAC_SRC_DIR)/pe/sch/sch_beacon_process.o \ + $(MAC_SRC_DIR)/pe/sch/sch_debug.o \ + $(MAC_SRC_DIR)/pe/sch/sch_message.o + +MAC_RRM_OBJS := $(MAC_SRC_DIR)/pe/rrm/rrm_api.o + +MAC_OBJS := $(MAC_CFG_OBJS) \ + $(MAC_DPH_OBJS) \ + $(MAC_LIM_OBJS) \ + $(MAC_SCH_OBJS) \ + $(MAC_RRM_OBJS) \ + $(MAC_NDP_OBJS) + +############ SAP ############ +SAP_DIR := core/sap +SAP_INC_DIR := $(SAP_DIR)/inc +SAP_SRC_DIR := $(SAP_DIR)/src + +SAP_INC := -I$(WLAN_ROOT)/$(SAP_INC_DIR) \ + -I$(WLAN_ROOT)/$(SAP_SRC_DIR) + +SAP_OBJS := $(SAP_SRC_DIR)/sap_api_link_cntl.o \ + $(SAP_SRC_DIR)/sap_ch_select.o \ + $(SAP_SRC_DIR)/sap_fsm.o \ + $(SAP_SRC_DIR)/sap_module.o + +############ DFS ############ 350 +DFS_DIR := $(SAP_DIR)/dfs +DFS_INC_DIR := $(DFS_DIR)/inc +DFS_SRC_DIR := $(DFS_DIR)/src + +DFS_INC := -I$(WLAN_ROOT)/$(DFS_INC_DIR) \ + -I$(WLAN_ROOT)/$(DFS_SRC_DIR) + +DFS_OBJS := $(DFS_SRC_DIR)/dfs_bindetects.o \ + $(DFS_SRC_DIR)/dfs.o \ + $(DFS_SRC_DIR)/dfs_debug.o\ + $(DFS_SRC_DIR)/dfs_fcc_bin5.o\ + $(DFS_SRC_DIR)/dfs_init.o\ + $(DFS_SRC_DIR)/dfs_misc.o\ + $(DFS_SRC_DIR)/dfs_nol.o\ + $(DFS_SRC_DIR)/dfs_phyerr_tlv.o\ + $(DFS_SRC_DIR)/dfs_process_phyerr.o\ + $(DFS_SRC_DIR)/dfs_process_radarevent.o\ + $(DFS_SRC_DIR)/dfs_staggered.o + +############ SME ############ +SME_DIR := core/sme +SME_INC_DIR := $(SME_DIR)/inc +SME_SRC_DIR := $(SME_DIR)/src + +SME_INC := -I$(WLAN_ROOT)/$(SME_INC_DIR) \ + -I$(WLAN_ROOT)/$(SME_SRC_DIR)/csr + +SME_CSR_OBJS := $(SME_SRC_DIR)/csr/csr_api_roam.o \ + $(SME_SRC_DIR)/csr/csr_api_scan.o \ + $(SME_SRC_DIR)/csr/csr_cmd_process.o \ + $(SME_SRC_DIR)/csr/csr_link_list.o \ + $(SME_SRC_DIR)/csr/csr_neighbor_roam.o \ + $(SME_SRC_DIR)/csr/csr_util.o \ + + +ifeq ($(CONFIG_QCACLD_WLAN_LFR2),y) +SME_CSR_OBJS += $(SME_SRC_DIR)/csr/csr_roam_preauth.o \ + $(SME_SRC_DIR)/csr/csr_host_scan_roam.o +endif + + +ifeq ($(CONFIG_QCOM_TDLS),y) +SME_CSR_OBJS += $(SME_SRC_DIR)/csr/csr_tdls_process.o +endif + +SME_QOS_OBJS := $(SME_SRC_DIR)/qos/sme_qos.o + +SME_CMN_OBJS := $(SME_SRC_DIR)/common/sme_api.o \ + $(SME_SRC_DIR)/common/sme_ft_api.o \ + $(SME_SRC_DIR)/common/sme_power_save.o \ + $(SME_SRC_DIR)/common/sme_trace.o + +SME_P2P_OBJS = $(SME_SRC_DIR)/p2p/p2p_api.o + +SME_RRM_OBJS := $(SME_SRC_DIR)/rrm/sme_rrm.o + +ifeq ($(CONFIG_QCACLD_FEATURE_NAN),y) +SME_NAN_OBJS = $(SME_SRC_DIR)/nan/nan_api.o +endif + +ifeq ($(CONFIG_WLAN_FEATURE_NAN_DATAPATH), y) +SME_NDP_OBJS += $(SME_SRC_DIR)/nan/nan_datapath_api.o +endif + +SME_OBJS := $(SME_CMN_OBJS) \ + $(SME_CSR_OBJS) \ + $(SME_P2P_OBJS) \ + $(SME_QOS_OBJS) \ + $(SME_RRM_OBJS) \ + $(SME_NAN_OBJS) \ + $(SME_NDP_OBJS) + +############ NLINK ############ +NLINK_DIR := core/utils/nlink +NLINK_INC_DIR := $(NLINK_DIR)/inc +NLINK_SRC_DIR := $(NLINK_DIR)/src + +NLINK_INC := -I$(WLAN_ROOT)/$(NLINK_INC_DIR) +NLINK_OBJS := $(NLINK_SRC_DIR)/wlan_nlink_srv.o + +############ PTT ############ +PTT_DIR := core/utils/ptt +PTT_INC_DIR := $(PTT_DIR)/inc +PTT_SRC_DIR := $(PTT_DIR)/src + +PTT_INC := -I$(WLAN_ROOT)/$(PTT_INC_DIR) +PTT_OBJS := $(PTT_SRC_DIR)/wlan_ptt_sock_svc.o + +############ WLAN_LOGGING ############ +WLAN_LOGGING_DIR := core/utils/logging +WLAN_LOGGING_INC_DIR := $(WLAN_LOGGING_DIR)/inc +WLAN_LOGGING_SRC_DIR := $(WLAN_LOGGING_DIR)/src + +WLAN_LOGGING_INC := -I$(WLAN_ROOT)/$(WLAN_LOGGING_INC_DIR) +WLAN_LOGGING_OBJS := $(WLAN_LOGGING_SRC_DIR)/wlan_logging_sock_svc.o + +############ SYS ############ +SYS_DIR := core/mac/src/sys + +SYS_INC := -I$(WLAN_ROOT)/$(SYS_DIR)/common/inc \ + -I$(WLAN_ROOT)/$(SYS_DIR)/legacy/src/platform/inc \ + -I$(WLAN_ROOT)/$(SYS_DIR)/legacy/src/system/inc \ + -I$(WLAN_ROOT)/$(SYS_DIR)/legacy/src/utils/inc + +SYS_COMMON_SRC_DIR := $(SYS_DIR)/common/src +SYS_LEGACY_SRC_DIR := $(SYS_DIR)/legacy/src +SYS_OBJS := $(SYS_COMMON_SRC_DIR)/wlan_qct_sys.o \ + $(SYS_LEGACY_SRC_DIR)/platform/src/sys_wrapper.o \ + $(SYS_LEGACY_SRC_DIR)/system/src/mac_init_api.o \ + $(SYS_LEGACY_SRC_DIR)/system/src/sys_entry_func.o \ + $(SYS_LEGACY_SRC_DIR)/utils/src/dot11f.o \ + $(SYS_LEGACY_SRC_DIR)/utils/src/log_api.o \ + $(SYS_LEGACY_SRC_DIR)/utils/src/mac_trace.o \ + $(SYS_LEGACY_SRC_DIR)/utils/src/parser_api.o \ + $(SYS_LEGACY_SRC_DIR)/utils/src/utils_api.o \ + $(SYS_LEGACY_SRC_DIR)/utils/src/utils_parser.o + +############ Qca-wifi-host-cmn ############ +QDF_OS_DIR := qdf +QDF_OS_INC_DIR := $(QDF_OS_DIR)/inc +QDF_OS_SRC_DIR := $(QDF_OS_DIR)/linux/src +QDF_OBJ_DIR := $(WLAN_COMMON_ROOT)/$(QDF_OS_SRC_DIR) + +QDF_INC := -I$(WLAN_COMMON_INC)/$(QDF_OS_INC_DIR) \ + -I$(WLAN_COMMON_INC)/$(QDF_OS_SRC_DIR) + +QDF_OBJS := $(QDF_OBJ_DIR)/qdf_defer.o \ + $(QDF_OBJ_DIR)/qdf_event.o \ + $(QDF_OBJ_DIR)/qdf_list.o \ + $(QDF_OBJ_DIR)/qdf_lock.o \ + $(QDF_OBJ_DIR)/qdf_mc_timer.o \ + $(QDF_OBJ_DIR)/qdf_mem.o \ + $(QDF_OBJ_DIR)/qdf_nbuf.o \ + $(QDF_OBJ_DIR)/qdf_threads.o \ + $(QDF_OBJ_DIR)/qdf_trace.o + +ifeq ($(CONFIG_WLAN_DEBUGFS), y) +QDF_OBJS += $(QDF_OBJ_DIR)/qdf_debugfs.o +endif + +############ CDS (Connectivity driver services) ############ +CDS_DIR := core/cds +CDS_INC_DIR := $(CDS_DIR)/inc +CDS_SRC_DIR := $(CDS_DIR)/src + +CDS_INC := -I$(WLAN_ROOT)/$(CDS_INC_DIR) \ + -I$(WLAN_ROOT)/$(CDS_SRC_DIR) + +CDS_OBJS := $(CDS_SRC_DIR)/cds_api.o \ + $(CDS_SRC_DIR)/cds_reg_service.o \ + $(CDS_SRC_DIR)/cds_mq.o \ + $(CDS_SRC_DIR)/cds_packet.o \ + $(CDS_SRC_DIR)/cds_regdomain.o \ + $(CDS_SRC_DIR)/cds_sched.o \ + $(CDS_SRC_DIR)/cds_concurrency.o \ + $(CDS_SRC_DIR)/cds_utils.o \ + $(CDS_SRC_DIR)/cds_mc_timer.o + + +########### BMI ########### +BMI_DIR := core/bmi + +BMI_INC := -I$(WLAN_ROOT)/$(BMI_DIR)/inc + +BMI_OBJS := $(BMI_DIR)/src/bmi.o \ + $(BMI_DIR)/src/ol_fw.o \ + $(BMI_DIR)/src/ol_fw_common.o +BMI_OBJS += $(BMI_DIR)/src/bmi_1.o + +########### WMI ########### +WMI_ROOT_DIR := wmi + +WMI_SRC_DIR := $(WMI_ROOT_DIR)/src +WMI_INC_DIR := $(WMI_ROOT_DIR)/inc +WMI_OBJ_DIR := $(WLAN_COMMON_ROOT)/$(WMI_SRC_DIR) + +WMI_INC := -I$(WLAN_COMMON_INC)/$(WMI_INC_DIR) + +WMI_OBJS := $(WMI_OBJ_DIR)/wmi_unified.o \ + $(WMI_OBJ_DIR)/wmi_tlv_helper.o \ + $(WMI_OBJ_DIR)/wmi_unified_tlv.o \ + $(WMI_OBJ_DIR)/wmi_unified_api.o \ + $(WMI_OBJ_DIR)/wmi_unified_non_tlv.o + +########### FWLOG ########### +FWLOG_DIR := core/utils/fwlog + +FWLOG_INC := -I$(WLAN_ROOT)/$(FWLOG_DIR) + +FWLOG_OBJS := $(FWLOG_DIR)/dbglog_host.o + +############ TXRX ############ +TXRX_DIR := core/dp/txrx +TXRX_INC := -I$(WLAN_ROOT)/$(TXRX_DIR) + +TXRX_OBJS := $(TXRX_DIR)/ol_txrx.o \ + $(TXRX_DIR)/ol_cfg.o \ + $(TXRX_DIR)/ol_rx.o \ + $(TXRX_DIR)/ol_rx_fwd.o \ + $(TXRX_DIR)/ol_txrx.o \ + $(TXRX_DIR)/ol_rx_defrag.o \ + $(TXRX_DIR)/ol_tx_desc.o \ + $(TXRX_DIR)/ol_tx.o \ + $(TXRX_DIR)/ol_rx_reorder_timeout.o \ + $(TXRX_DIR)/ol_rx_reorder.o \ + $(TXRX_DIR)/ol_rx_pn.o \ + $(TXRX_DIR)/ol_tx_queue.o \ + $(TXRX_DIR)/ol_txrx_peer_find.o \ + $(TXRX_DIR)/ol_txrx_event.o \ + $(TXRX_DIR)/ol_txrx_encap.o \ + $(TXRX_DIR)/ol_tx_send.o \ + $(TXRX_DIR)/ol_tx_sched.o \ + $(TXRX_DIR)/ol_tx_classify.o + +ifeq ($(CONFIG_WLAN_TX_FLOW_CONTROL_V2), y) +TXRX_OBJS += $(TXRX_DIR)/ol_txrx_flow_control.o +endif + +############ OL ############ +OL_DIR := core/dp/ol +OL_INC := -I$(WLAN_ROOT)/$(OL_DIR)/inc + +############ CDP ############ +CDP_ROOT_DIR := dp +CDP_INC_DIR := $(CDP_ROOT_DIR)/inc +CDP_INC := -I$(WLAN_COMMON_INC)/$(CDP_INC_DIR) + +############ PKTLOG ############ +PKTLOG_DIR := core/utils/pktlog +PKTLOG_INC := -I$(WLAN_ROOT)/$(PKTLOG_DIR)/include + +PKTLOG_OBJS := $(PKTLOG_DIR)/pktlog_ac.o \ + $(PKTLOG_DIR)/pktlog_internal.o \ + $(PKTLOG_DIR)/linux_ac.o + +############ HTT ############ +HTT_DIR := core/dp/htt +HTT_INC := -I$(WLAN_ROOT)/$(HTT_DIR) + +HTT_OBJS := $(HTT_DIR)/htt_tx.o \ + $(HTT_DIR)/htt.o \ + $(HTT_DIR)/htt_t2h.o \ + $(HTT_DIR)/htt_h2t.o \ + $(HTT_DIR)/htt_fw_stats.o \ + $(HTT_DIR)/htt_rx.o + +############## HTC ########## +HTC_DIR := htc +HTC_INC := -I$(WLAN_COMMON_INC)/$(HTC_DIR) + +HTC_OBJS := $(WLAN_COMMON_ROOT)/$(HTC_DIR)/htc.o \ + $(WLAN_COMMON_ROOT)/$(HTC_DIR)/htc_send.o \ + $(WLAN_COMMON_ROOT)/$(HTC_DIR)/htc_recv.o \ + $(WLAN_COMMON_ROOT)/$(HTC_DIR)/htc_services.o + +########### HIF ########### +HIF_DIR := hif +HIF_CE_DIR := $(HIF_DIR)/src/ce + +HIF_DISPATCHER_DIR := $(HIF_DIR)/src/dispatcher + +HIF_PCIE_DIR := $(HIF_DIR)/src/pcie +HIF_SNOC_DIR := $(HIF_DIR)/src/snoc +HIF_USB_DIR := $(HIF_DIR)/src/usb +HIF_SDIO_DIR := $(HIF_DIR)/src/sdio + +HIF_SDIO_NATIVE_DIR := $(HIF_SDIO_DIR)/native_sdio +HIF_SDIO_NATIVE_INC_DIR := $(HIF_SDIO_NATIVE_DIR)/include +HIF_SDIO_NATIVE_SRC_DIR := $(HIF_SDIO_NATIVE_DIR)/src + +HIF_INC := -I$(WLAN_COMMON_INC)/$(HIF_DIR)/inc \ + -I$(WLAN_COMMON_INC)/$(HIF_DIR)/src \ + -I$(WLAN_COMMON_INC)/$(HIF_CE_DIR) + +ifeq ($(CONFIG_HIF_PCI), 1) +HIF_INC += -I$(WLAN_COMMON_INC)/$(HIF_DISPATCHER_DIR) +HIF_INC += -I$(WLAN_COMMON_INC)/$(HIF_PCIE_DIR) +endif + +ifeq ($(CONFIG_HIF_SNOC), 1) +HIF_INC += -I$(WLAN_COMMON_INC)/$(HIF_DISPATCHER_DIR) +HIF_INC += -I$(WLAN_COMMON_INC)/$(HIF_SNOC_DIR) +endif + +ifeq ($(CONFIG_HIF_USB), 1) +HIF_INC += -I$(WLAN_COMMON_INC)/$(HIF_DISPATCHER_DIR) +HIF_INC += -I$(WLAN_COMMON_INC)/$(HIF_USB_DIR) +endif + +ifeq ($(CONFIG_HIF_SDIO), 1) +HIF_INC += -I$(WLAN_COMMON_INC)/$(HIF_DISPATCHER_DIR) +HIF_INC += -I$(WLAN_COMMON_INC)/$(HIF_SDIO_DIR) +HIF_INC += -I$(WLAN_COMMON_INC)/$(HIF_SDIO_NATIVE_INC_DIR) +endif + +HIF_COMMON_OBJS := $(WLAN_COMMON_ROOT)/$(HIF_DIR)/src/ath_procfs.o \ + $(WLAN_COMMON_ROOT)/$(HIF_DIR)/src/hif_main.o \ + $(WLAN_COMMON_ROOT)/$(HIF_DIR)/src/mp_dev.o + +HIF_CE_OBJS := $(WLAN_COMMON_ROOT)/$(HIF_CE_DIR)/ce_bmi.o \ + $(WLAN_COMMON_ROOT)/$(HIF_CE_DIR)/ce_diag.o \ + $(WLAN_COMMON_ROOT)/$(HIF_CE_DIR)/ce_main.o \ + $(WLAN_COMMON_ROOT)/$(HIF_CE_DIR)/ce_service.o \ + $(WLAN_COMMON_ROOT)/$(HIF_CE_DIR)/ce_tasklet.o \ + $(WLAN_COMMON_ROOT)/$(HIF_DIR)/src/regtable.o + +HIF_USB_OBJS := $(WLAN_COMMON_ROOT)/$(HIF_USB_DIR)/usbdrv.o \ + $(WLAN_COMMON_ROOT)/$(HIF_USB_DIR)/hif_usb.o \ + $(WLAN_COMMON_ROOT)/$(HIF_USB_DIR)/if_usb.o \ + $(WLAN_COMMON_ROOT)/$(HIF_USB_DIR)/regtable_usb.o + +HIF_SDIO_OBJS := $(WLAN_COMMON_ROOT)/$(HIF_SDIO_DIR)/hif_sdio_send.o \ + $(WLAN_COMMON_ROOT)/$(HIF_SDIO_DIR)/hif_bmi_reg_access.o \ + $(WLAN_COMMON_ROOT)/$(HIF_SDIO_DIR)/hif_diag_reg_access.o \ + $(WLAN_COMMON_ROOT)/$(HIF_SDIO_DIR)/hif_sdio_dev.o \ + $(WLAN_COMMON_ROOT)/$(HIF_SDIO_DIR)/hif_sdio.o \ + $(WLAN_COMMON_ROOT)/$(HIF_SDIO_DIR)/hif_sdio_recv.o \ + $(WLAN_COMMON_ROOT)/$(HIF_SDIO_DIR)/regtable_sdio.o + +HIF_SDIO_NATIVE_OBJS := $(WLAN_COMMON_ROOT)/$(HIF_SDIO_NATIVE_SRC_DIR)/hif.o \ + $(WLAN_COMMON_ROOT)/$(HIF_SDIO_NATIVE_SRC_DIR)/hif_scatter.o + +ifeq ($(CONFIG_WLAN_NAPI), y) +HIF_OBJS += $(WLAN_COMMON_ROOT)/$(HIF_DIR)/src/hif_napi.o +endif + +HIF_PCIE_OBJS := $(WLAN_COMMON_ROOT)/$(HIF_PCIE_DIR)/if_pci.o +HIF_SNOC_OBJS := $(WLAN_COMMON_ROOT)/$(HIF_SNOC_DIR)/if_snoc.o +HIF_SDIO_OBJS += $(WLAN_COMMON_ROOT)/$(HIF_SDIO_DIR)/if_sdio.o + +HIF_OBJS += $(WLAN_COMMON_ROOT)/$(HIF_DISPATCHER_DIR)/multibus.o +HIF_OBJS += $(WLAN_COMMON_ROOT)/$(HIF_DISPATCHER_DIR)/dummy.o + +ifeq ($(CONFIG_HIF_PCI), 1) +HIF_OBJS += $(HIF_PCIE_OBJS) +HIF_OBJS += $(HIF_COMMON_OBJS) +HIF_OBJS += $(HIF_CE_OBJS) +HIF_OBJS += $(WLAN_COMMON_ROOT)/$(HIF_DISPATCHER_DIR)/multibus_pci.o +endif + +ifeq ($(CONFIG_HIF_SNOC), 1) +HIF_OBJS += $(HIF_SNOC_OBJS) +HIF_OBJS += $(HIF_COMMON_OBJS) +HIF_OBJS += $(HIF_CE_OBJS) +HIF_OBJS += $(WLAN_COMMON_ROOT)/$(HIF_DISPATCHER_DIR)/multibus_snoc.o +endif + +ifeq ($(CONFIG_HIF_SDIO), 1) +HIF_OBJS += $(HIF_SDIO_OBJS) +HIF_OBJS += $(HIF_SDIO_NATIVE_OBJS) +HIF_OBJS += $(HIF_COMMON_OBJS) +HIF_OBJS += $(WLAN_COMMON_ROOT)/$(HIF_DISPATCHER_DIR)/multibus_sdio.o +endif + +ifeq ($(CONFIG_HIF_USB), 1) +HIF_OBJS += $(HIF_USB_OBJS) +HIF_OBJS += $(HIF_COMMON_OBJS) +HIF_OBJS += $(WLAN_COMMON_ROOT)/$(HIF_DISPATCHER_DIR)/multibus_usb.o +endif + +############ WMA ############ +WMA_DIR := core/wma + +WMA_INC_DIR := $(WMA_DIR)/inc +WMA_SRC_DIR := $(WMA_DIR)/src + +WMA_INC := -I$(WLAN_ROOT)/$(WMA_INC_DIR) \ + -I$(WLAN_ROOT)/$(WMA_SRC_DIR) + +ifeq ($(CONFIG_WLAN_FEATURE_NAN_DATAPATH), y) +WMA_NDP_OBJS += $(WMA_SRC_DIR)/wma_nan_datapath.o +endif + +WMA_OBJS := $(WMA_SRC_DIR)/wma_main.o \ + $(WMA_SRC_DIR)/wma_scan_roam.o \ + $(WMA_SRC_DIR)/wma_dev_if.o \ + $(WMA_SRC_DIR)/wma_mgmt.o \ + $(WMA_SRC_DIR)/wma_power.o \ + $(WMA_SRC_DIR)/wma_data.o \ + $(WMA_SRC_DIR)/wma_utils.o \ + $(WMA_SRC_DIR)/wma_features.o \ + $(WMA_SRC_DIR)/wma_dfs_interface.o \ + $(WMA_SRC_DIR)/wlan_qct_wma_legacy.o\ + $(WMA_NDP_OBJS) + +ifeq ($(CONFIG_WLAN_FEATURE_DSRC), y) +WMA_OBJS+= $(WMA_SRC_DIR)/wma_ocb.o +endif +ifeq ($(CONFIG_MPC_UT_FRAMEWORK),y) +WMA_OBJS += $(WMA_SRC_DIR)/wma_utils_ut.o +endif + +############## PLD ########## +PLD_DIR := core/pld +PLD_INC_DIR := $(PLD_DIR)/inc +PLD_SRC_DIR := $(PLD_DIR)/src + +PLD_INC := -I$(WLAN_ROOT)/$(PLD_INC_DIR) \ + -I$(WLAN_ROOT)/$(PLD_SRC_DIR) + +PLD_OBJS := $(PLD_SRC_DIR)/pld_common.o + +ifeq ($(CONFIG_PCI), y) +PLD_OBJS += $(PLD_SRC_DIR)/pld_pcie.o +endif +ifeq ($(CONFIG_ICNSS),y) +PLD_OBJS += $(PLD_SRC_DIR)/pld_snoc.o +endif +ifeq ($(CONFIG_CNSS_SDIO),y) +PLD_OBJS += $(PLD_SRC_DIR)/pld_sdio.o +endif +ifeq ($(CONFIG_PLD_USB_CNSS), y) +PLD_OBJS += $(PLD_SRC_DIR)/pld_usb.o +endif + +TARGET_INC := -I$(WLAN_ROOT)/../fw-api/fw + +LINUX_INC := -Iinclude/linux + +INCS := $(HDD_INC) \ + $(EPPING_INC) \ + $(LINUX_INC) \ + $(MAC_INC) \ + $(SAP_INC) \ + $(SME_INC) \ + $(SYS_INC) \ + $(QDF_INC) \ + $(CDS_INC) \ + $(DFS_INC) + +INCS += $(WMA_INC) \ + $(UAPI_INC) \ + $(COMMON_INC) \ + $(WMI_INC) \ + $(FWLOG_INC) \ + $(TXRX_INC) \ + $(OL_INC) \ + $(CDP_INC) \ + $(PKTLOG_INC) \ + $(HTT_INC) \ + $(HTC_INC) \ + $(DFS_INC) + +INCS += $(HIF_INC) \ + $(BMI_INC) + +INCS += $(TARGET_INC) + +INCS += $(NLINK_INC) \ + $(PTT_INC) \ + $(WLAN_LOGGING_INC) + +INCS += $(PLD_INC) + +ifeq ($(CONFIG_REMOVE_PKT_LOG), 0) +INCS += $(PKTLOG_INC) +endif + +ifeq ($(BUILD_DIAG_VERSION), 1) +INCS += $(HOST_DIAG_LOG_INC) +endif + +OBJS := $(HDD_OBJS) \ + $(EPPING_OBJS) \ + $(MAC_OBJS) \ + $(SAP_OBJS) \ + $(SME_OBJS) \ + $(SYS_OBJS) \ + $(QDF_OBJS) \ + $(CDS_OBJS) \ + $(DFS_OBJS) + +OBJS += $(WMA_OBJS) \ + $(TXRX_OBJS) \ + $(WMI_OBJS) \ + $(FWLOG_OBJS) \ + $(HTC_OBJS) \ + $(DFS_OBJS) + +OBJS += $(HIF_OBJS) \ + $(BMI_OBJS) \ + $(HTT_OBJS) + +OBJS += $(WLAN_LOGGING_OBJS) +OBJS += $(NLINK_OBJS) +OBJS += $(PTT_OBJS) + +OBJS += $(PLD_OBJS) + +ifeq ($(CONFIG_REMOVE_PKT_LOG), 0) +OBJS += $(PKTLOG_OBJS) +endif + +ifeq ($(BUILD_DIAG_VERSION), 1) +OBJS += $(HOST_DIAG_LOG_OBJS) +endif + + +EXTRA_CFLAGS += $(INCS) + +CDEFINES := -DANI_LITTLE_BYTE_ENDIAN \ + -DANI_LITTLE_BIT_ENDIAN \ + -DDOT11F_LITTLE_ENDIAN_HOST \ + -DANI_COMPILER_TYPE_GCC \ + -DANI_OS_TYPE_ANDROID=6 \ + -DPTT_SOCK_SVC_ENABLE \ + -Wall\ + -Werror\ + -D__linux__ \ + -DHAL_SELF_STA_PER_BSS=1 \ + -DFEATURE_WLAN_WAPI \ + -DFEATURE_OEM_DATA_SUPPORT\ + -DSOFTAP_CHANNEL_RANGE \ + -DWLAN_AP_STA_CONCURRENCY \ + -DFEATURE_WLAN_SCAN_PNO \ + -DWLAN_FEATURE_PACKET_FILTERING \ + -DWLAN_FEATURE_P2P_DEBUG \ + -DWLAN_ENABLE_AGEIE_ON_SCAN_RESULTS \ + -DWLANTL_DEBUG\ + -DWLAN_NS_OFFLOAD \ + -DWLAN_SOFTAP_VSTA_FEATURE \ + -DWLAN_FEATURE_GTK_OFFLOAD \ + -DWLAN_WAKEUP_EVENTS \ + -DFEATURE_WLAN_RA_FILTERING\ + -DWLAN_NL80211_TESTMODE \ + -DFEATURE_WLAN_LPHB \ + -DQCA_SUPPORT_TX_THROTTLE \ + -DWMI_INTERFACE_EVENT_LOGGING \ + -DATH_SUPPORT_WAPI \ + -DWLAN_FEATURE_LINK_LAYER_STATS \ + -DFEATURE_WLAN_EXTSCAN \ + -DWLAN_FEATURE_MBSSID \ + -DCONFIG_160MHZ_SUPPORT \ + -DCONFIG_MCL \ + -DWMI_CMD_STRINGS \ + -DCONFIG_HDD_INIT_WITH_RTNL_LOCK + +ifneq ($(CONFIG_HIF_USB), 1) +CDEFINES += -DWLAN_LOGGING_SOCK_SVC_ENABLE +endif + +ifeq ($(CONFIG_CNSS), y) +ifeq ($(CONFIG_CNSS_SDIO), y) +CDEFINES += -DCONFIG_PLD_SDIO_CNSS +else +CDEFINES += -DCONFIG_PLD_PCIE_CNSS +endif +endif + +ifeq ($(CONFIG_ICNSS), y) +CDEFINES += -DCONFIG_PLD_SNOC_ICNSS +endif + +ifeq (y,$(filter y,$(CONFIG_CNSS_EOS) $(CONFIG_ICNSS))) +CDEFINES += -DQCA_WIFI_3_0 +endif + +ifeq (y,$(filter y,$(CONFIG_CNSS_ADRASTEA) $(CONFIG_ICNSS))) +CDEFINES += -DQCA_WIFI_3_0_ADRASTEA +CDEFINES += -DADRASTEA_SHADOW_REGISTERS +CDEFINES += -DADRASTEA_RRI_ON_DDR +endif + +ifeq ($(CONFIG_WLAN_FASTPATH), y) +CDEFINES += -DWLAN_FEATURE_FASTPATH +endif + +ifeq ($(CONFIG_FEATURE_PKTLOG), y) +CDEFINES += -DFEATURE_PKTLOG +endif + +ifeq ($(CONFIG_FEATURE_DP_TRACE), y) +CDEFINES += -DFEATURE_DP_TRACE +endif + +ifeq ($(CONFIG_WLAN_NAPI), y) +CDEFINES += -DFEATURE_NAPI +ifeq ($(CONFIG_WLAN_NAPI_DEBUG), y) +CDEFINES += -DFEATURE_NAPI_DEBUG +endif +endif + +ifeq (y,$(findstring y,$(CONFIG_ARCH_MSM) $(CONFIG_ARCH_QCOM))) +CDEFINES += -DMSM_PLATFORM +endif + +CDEFINES += -DQCA_SUPPORT_TXRX_LOCAL_PEER_ID + +ifeq ($(CONFIG_WLAN_TX_FLOW_CONTROL_V2), y) +CDEFINES += -DQCA_LL_TX_FLOW_CONTROL_V2 +CDEFINES += -DQCA_LL_TX_FLOW_GLOBAL_MGMT_POOL +else +ifeq ($(CONFIG_ROME_IF),pci) +CDEFINES += -DQCA_LL_LEGACY_TX_FLOW_CONTROL +endif +endif + +ifneq ($(CONFIG_QCA_CLD_WLAN),) +CDEFINES += -DWCN_PRONTO +CDEFINES += -DWCN_PRONTO_V1 +endif + +ifeq ($(BUILD_DEBUG_VERSION),1) +CDEFINES += -DWLAN_DEBUG \ + -DTRACE_RECORD \ + -DLIM_TRACE_RECORD \ + -DSME_TRACE_RECORD \ + -DHDD_TRACE_RECORD \ + -DPE_DEBUG_LOGW \ + -DPE_DEBUG_LOGE +endif + +ifeq ($(CONFIG_SLUB_DEBUG_ON),y) +CDEFINES += -DTIMER_MANAGER +CDEFINES += -DMEMORY_DEBUG +CDEFINES += -DWLAN_SUSPEND_RESUME_TEST +endif + +ifeq ($(HAVE_CFG80211),1) +CDEFINES += -DWLAN_FEATURE_P2P +CDEFINES += -DWLAN_FEATURE_WFD +ifeq ($(CONFIG_QCOM_VOWIFI_11R),y) +CDEFINES += -DKERNEL_SUPPORT_11R_CFG80211 +CDEFINES += -DUSE_80211_WMMTSPEC_FOR_RIC +endif +endif + +ifeq ($(CONFIG_QCOM_ESE),y) +CDEFINES += -DFEATURE_WLAN_ESE +CDEFINES += -DQCA_COMPUTE_TX_DELAY +CDEFINES += -DQCA_COMPUTE_TX_DELAY_PER_TID +endif + +#normally, TDLS negative behavior is not needed +ifeq ($(CONFIG_QCOM_TDLS),y) +CDEFINES += -DFEATURE_WLAN_TDLS +endif + +ifeq ($(CONFIG_QCACLD_WLAN_LFR3),y) +CDEFINES += -DWLAN_FEATURE_ROAM_OFFLOAD +endif + +ifeq ($(CONFIG_QCACLD_WLAN_LFR2),y) +CDEFINES += -DWLAN_FEATURE_HOST_ROAM +endif + +ifeq ($(CONFIG_WLAN_POWER_DEBUGFS), y) +CDEFINES += -DWLAN_POWER_DEBUGFS +endif + +ifeq ($(BUILD_DIAG_VERSION),1) +CDEFINES += -DFEATURE_WLAN_DIAG_SUPPORT +CDEFINES += -DFEATURE_WLAN_DIAG_SUPPORT_CSR +CDEFINES += -DFEATURE_WLAN_DIAG_SUPPORT_LIM +ifeq ($(CONFIG_HIF_PCI), 1) +CDEFINES += -DCONFIG_ATH_PROCFS_DIAG_SUPPORT +endif +endif + +ifeq ($(CONFIG_HIF_USB), 1) +CDEFINES += -DCONFIG_ATH_PROCFS_DIAG_SUPPORT +CDEFINES += -DQCA_SUPPORT_OL_RX_REORDER_TIMEOUT +CDEFINES += -DCONFIG_ATH_PCIE_MAX_PERF=0 -DCONFIG_ATH_PCIE_AWAKE_WHILE_DRIVER_LOAD=0 -DCONFIG_DISABLE_CDC_MAX_PERF_WAR=0 +endif + +ifeq ($(CONFIG_WLAN_FEATURE_11W),y) +CDEFINES += -DWLAN_FEATURE_11W +endif + +ifeq ($(CONFIG_QCA_TXDESC_SANITY_CHECKS), 1) +CDEFINES += -DQCA_SUPPORT_TXDESC_SANITY_CHECKS +endif + +ifeq ($(CONFIG_QCOM_LTE_COEX),y) +CDEFINES += -DFEATURE_WLAN_CH_AVOID +endif + +ifeq ($(CONFIG_WLAN_FEATURE_LPSS),y) +CDEFINES += -DWLAN_FEATURE_LPSS +endif + +ifneq ($(TARGET_BUILD_VARIANT),user) +CDEFINES += -DDESC_DUP_DETECT_DEBUG +CDEFINES += -DDEBUG_RX_RING_BUFFER +endif + +ifeq ($(PANIC_ON_BUG),1) +CDEFINES += -DPANIC_ON_BUG +endif + +ifeq ($(WLAN_OPEN_SOURCE), 1) +CDEFINES += -DWLAN_OPEN_SOURCE +endif + +ifeq ($(CONFIG_FEATURE_STATS_EXT), 1) +CDEFINES += -DWLAN_FEATURE_STATS_EXT +endif + +ifeq ($(CONFIG_QCACLD_FEATURE_NAN),y) +CDEFINES += -DWLAN_FEATURE_NAN +endif + +ifeq ($(CONFIG_QCA_IBSS_SUPPORT), 1) +CDEFINES += -DQCA_IBSS_SUPPORT +endif + +#Enable OL debug and wmi unified functions +ifeq ($(CONFIG_ATH_PERF_PWR_OFFLOAD), 1) +CDEFINES += -DATH_PERF_PWR_OFFLOAD +endif + +#Disable packet log +ifeq ($(CONFIG_REMOVE_PKT_LOG), 1) +CDEFINES += -DREMOVE_PKT_LOG +endif + +#Enable 11AC TX +ifeq ($(CONFIG_ATH_11AC_TXCOMPACT), 1) +CDEFINES += -DATH_11AC_TXCOMPACT +endif + +#Enable OS specific IRQ abstraction +ifeq ($(CONFIG_ATH_SUPPORT_SHARED_IRQ), 1) +CDEFINES += -DATH_SUPPORT_SHARED_IRQ +endif + +#Enable message based HIF instead of RAW access in BMI +ifeq ($(CONFIG_HIF_MESSAGE_BASED), 1) +CDEFINES += -DHIF_MESSAGE_BASED +endif + +#Enable PCI specific APIS (dma, etc) +ifeq ($(CONFIG_HIF_PCI), 1) +CDEFINES += -DHIF_PCI +endif + +ifeq ($(CONFIG_HIF_SNOC), 1) +CDEFINES += -DHIF_SNOC +endif + +#Enable High Latency related Flags +ifeq ($(CONFIG_QCA_WIFI_SDIO), 1) +CDEFINES += -DCONFIG_HL_SUPPORT \ + -DCONFIG_AR6320_SUPPORT \ + -DSDIO_3_0 \ + -DHIF_SDIO \ + -DCONFIG_DISABLE_CDC_MAX_PERF_WAR=0 \ + -DCONFIG_ATH_PROCFS_DIAG_SUPPORT \ + -DFEATURE_HL_GROUP_CREDIT_FLOW_CONTROL \ + -DHIF_MBOX_SLEEP_WAR \ + -DDEBUG_HL_LOGGING \ + -DQCA_BAD_PEER_TX_FLOW_CL \ + -DCONFIG_TX_DESC_HI_PRIO_RESERVE \ + -DCONFIG_PER_VDEV_TX_DESC_POOL \ + -DCONFIG_SDIO \ + -DFEATURE_WLAN_FORCE_SAP_SCC +endif + +ifeq ($(CONFIG_WLAN_FEATURE_DSRC), y) +CDEFINES += -DWLAN_FEATURE_DSRC +endif + +#Enable USB specific APIS +ifeq ($(CONFIG_HIF_USB), 1) +CDEFINES += -DHIF_USB \ + -DCONFIG_PLD_USB_CNSS \ + -DCONFIG_HL_SUPPORT +endif + +#Enable FW logs through ini +CDEFINES += -DCONFIG_FW_LOGS_BASED_ON_INI + +#Enable pci read/write config functions +ifeq ($(CONFIG_ATH_PCI), 1) +CDEFINES += -DATH_PCI +endif + +#Enable power management suspend/resume functionality +ifeq ($(CONFIG_ATH_BUS_PM), 1) +CDEFINES += -DATH_BUS_PM +endif + +#Enable FLOWMAC module support +ifeq ($(CONFIG_ATH_SUPPORT_FLOWMAC_MODULE), 1) +CDEFINES += -DATH_SUPPORT_FLOWMAC_MODULE +endif + +#Enable spectral support +ifeq ($(CONFIG_ATH_SUPPORT_SPECTRAL), 1) +CDEFINES += -DATH_SUPPORT_SPECTRAL +endif + +#Enable WDI Event support +ifeq ($(CONFIG_WDI_EVENT_ENABLE), 1) +CDEFINES += -DWDI_EVENT_ENABLE +endif + +#Endianess selection +ifeq ($(CONFIG_LITTLE_ENDIAN), 1) +AH_LITTLE_ENDIAN=1234 +CDEFINES += -DAH_BYTE_ORDER=$(AH_LITTLE_ENDIAN) +else +AH_BIG_ENDIAN=4321 +CDEFINES += -DAH_BYTE_ORDER=$(AH_BIG_ENDIAN) +CDEFINES += -DBIG_ENDIAN_HOST +endif + +#Enable TX reclaim support +ifeq ($(CONFIG_TX_CREDIT_RECLAIM_SUPPORT), 1) +CDEFINES += -DTX_CREDIT_RECLAIM_SUPPORT +endif + +#Enable FTM support +ifeq ($(CONFIG_QCA_WIFI_FTM), 1) +CDEFINES += -DQCA_WIFI_FTM +endif + +#Enable Checksum Offload support +ifeq ($(CONFIG_CHECKSUM_OFFLOAD), 1) +CDEFINES += -DCHECKSUM_OFFLOAD +endif + +#Enable Checksum Offload support +ifeq ($(CONFIG_IPA_OFFLOAD), 1) +CDEFINES += -DIPA_OFFLOAD +endif + +ifneq ($(CONFIG_ARCH_MDM9630), y) +ifeq ($(CONFIG_ARCH_MDM9640), y) +CDEFINES += -DQCA_CONFIG_SMP +endif +endif + +#Enable GTK Offload +ifeq ($(CONFIG_GTK_OFFLOAD), 1) +CDEFINES += -DWLAN_FEATURE_GTK_OFFLOAD +CDEFINES += -DIGTK_OFFLOAD +endif + +#Enable GTK Offload +ifeq ($(CONFIG_EXT_WOW), 1) +CDEFINES += -DWLAN_FEATURE_EXTWOW_SUPPORT +endif + +#Mark it as SMP Kernel +ifeq ($(CONFIG_SMP),y) +CDEFINES += -DQCA_CONFIG_SMP +endif + +#Enable Channel Matrix restriction for all Rome only targets +ifneq (y,$(filter y,$(CONFIG_CNSS_EOS) $(CONFIG_ICNSS))) +CDEFINES += -DWLAN_ENABLE_CHNL_MATRIX_RESTRICTION +endif + +#Enable OBSS feature +CDEFINES += -DQCA_HT_2040_COEX + +#features specific to mobile router use case +ifeq ($(CONFIG_MOBILE_ROUTER), y) + +#enable MCC TO SCC switch +CDEFINES += -DFEATURE_WLAN_MCC_TO_SCC_SWITCH + +#enable wlan auto shutdown feature +CDEFINES += -DFEATURE_WLAN_AUTO_SHUTDOWN + +#enable for MBSSID +CDEFINES += -DWLAN_FEATURE_MBSSID + +#enable AP-AP ACS Optimization +CDEFINES += -DFEATURE_WLAN_AP_AP_ACS_OPTIMIZE + +#Enable 4address scheme +CDEFINES += -DFEATURE_WLAN_STA_4ADDR_SCHEME + +#Disable STA-AP Mode DFS support +CDEFINES += -DFEATURE_WLAN_STA_AP_MODE_DFS_DISABLE + +else #CONFIG_MOBILE_ROUTER + +#Open P2P device interface only for non-Mobile router use cases +CDEFINES += -DWLAN_OPEN_P2P_INTERFACE + +#Enable 2.4 GHz social channels in 5 GHz only mode for p2p usage +CDEFINES += -DWLAN_ENABLE_SOCIAL_CHANNELS_5G_ONLY + +endif #CONFIG_MOBILE_ROUTER + +#Green AP feature +ifeq ($(CONFIG_QCACLD_FEATURE_GREEN_AP),y) +CDEFINES += -DFEATURE_GREEN_AP +endif + +#Stats & Quota Metering feature +ifeq ($(CONFIG_QCACLD_FEATURE_METERING),y) +CDEFINES += -DFEATURE_METERING +endif + +#Enable RX Full re-order OL feature only "LL and NON-MDM9630 platform" +ifneq ($(CONFIG_ARCH_MDM9630), y) +ifeq ($(CONFIG_HIF_PCI), 1) +CDEFINES += -DWLAN_FEATURE_RX_FULL_REORDER_OL +endif +endif + +#Enable Signed firmware support for split binary format +ifeq ($(CONFIG_QCA_SIGNED_SPLIT_BINARY_SUPPORT), 1) +CDEFINES += -DQCA_SIGNED_SPLIT_BINARY_SUPPORT +endif + +#Enable single firmware binary format +ifeq ($(CONFIG_QCA_SINGLE_BINARY_SUPPORT), 1) +CDEFINES += -DQCA_SINGLE_BINARY_SUPPORT +endif + +#Enable collecting target RAM dump after kernel panic +ifeq ($(CONFIG_TARGET_RAMDUMP_AFTER_KERNEL_PANIC), 1) +CDEFINES += -DTARGET_RAMDUMP_AFTER_KERNEL_PANIC +endif + +#Enable/disable secure firmware feature +ifeq ($(CONFIG_FEATURE_SECURE_FIRMWARE), 1) +CDEFINES += -DFEATURE_SECURE_FIRMWARE +endif + +ifeq ($(CONFIG_ATH_PCIE_ACCESS_DEBUG), 1) +CDEFINES += -DCONFIG_ATH_PCIE_ACCESS_DEBUG +endif + +# Enable feature support fo Linux version QCMBR +ifeq ($(CONFIG_LINUX_QCMBR),y) +CDEFINES += -DLINUX_QCMBR +endif + +# Enable featue sync tsf between multi devices +ifeq ($(CONFIG_WLAN_SYNC_TSF), y) +CDEFINES += -DWLAN_FEATURE_TSF +endif + +# Enable full rx re-order offload for adrastea +ifeq (y, $(filter y, $(CONFIG_CNSS_ADRASTEA) $(CONFIG_ICNSS))) +CDEFINES += -DWLAN_FEATURE_RX_FULL_REORDER_OL +endif + +# Enable athdiag procfs debug support for adrastea +ifeq (y, $(filter y, $(CONFIG_CNSS_ADRASTEA) $(CONFIG_ICNSS))) +CDEFINES += -DCONFIG_ATH_PROCFS_DIAG_SUPPORT +endif + +# Enable 11AC TX compact feature for adrastea +ifeq (y, $(filter y, $(CONFIG_CNSS_ADRASTEA) $(CONFIG_ICNSS))) +CDEFINES += -DATH_11AC_TXCOMPACT +endif + +# NOTE: CONFIG_64BIT_PADDR requires CONFIG_HELIUMPLUS +ifeq (y,$(filter y,$(CONFIG_CNSS_EOS) $(CONFIG_ICNSS))) +CONFIG_HELIUMPLUS := y +CONFIG_64BIT_PADDR := y +CONFIG_FEATURE_TSO := y +CONFIG_FEATURE_TSO_DEBUG := y +ifneq ($(CONFIG_FORCE_ALLOC_FROM_DMA_ZONE), y) +CONFIG_ENABLE_DEBUG_ADDRESS_MARKING := y +endif +ifeq ($(CONFIG_HELIUMPLUS),y) +CDEFINES += -DHELIUMPLUS +CDEFINES += -DAR900B +ifeq ($(CONFIG_64BIT_PADDR),y) +CDEFINES += -DHTT_PADDR64 +endif + +ifeq ($(CONFIG_SLUB_DEBUG_ON),y) +CDEFINES += -DOL_RX_INDICATION_RECORD +endif + +endif +endif + +ifeq ($(CONFIG_ENABLE_DEBUG_ADDRESS_MARKING),y) +CDEFINES += -DENABLE_DEBUG_ADDRESS_MARKING +endif +ifeq ($(CONFIG_FEATURE_TSO),y) +CDEFINES += -DFEATURE_TSO +endif +ifeq ($(CONFIG_FEATURE_TSO_DEBUG),y) +CDEFINES += -DFEATURE_TSO_DEBUG +endif + +ifeq ($(CONFIG_WLAN_LRO), y) +CDEFINES += -DFEATURE_LRO +endif + +ifeq ($(CONFIG_MOBILE_ROUTER), y) +CDEFINES += -DFEATURE_AP_MCC_CH_AVOIDANCE +endif + +ifeq ($(CONFIG_MPC_UT_FRAMEWORK), y) +CDEFINES += -DMPC_UT_FRAMEWORK +endif + +ifeq ($(CONFIG_WLAN_OFFLOAD_PACKETS),y) +CDEFINES += -DWLAN_FEATURE_OFFLOAD_PACKETS +endif + +ifeq ($(CONFIG_WLAN_FEATURE_MEMDUMP),y) +CDEFINES += -DWLAN_FEATURE_MEMDUMP +endif + +ifeq ($(CONFIG_WLAN_FEATURE_DISA),y) +CDEFINES += -DWLAN_FEATURE_DISA +endif + +ifeq ($(CONFIG_LFR_SUBNET_DETECTION), y) +CDEFINES += -DFEATURE_LFR_SUBNET_DETECTION +endif + +ifeq ($(CONFIG_MCC_TO_SCC_SWITCH), y) +CDEFINES += -DFEATURE_WLAN_MCC_TO_SCC_SWITCH +endif + +ifeq ($(CONFIG_WLAN_FEATURE_NAN_DATAPATH), y) +CDEFINES += -DWLAN_FEATURE_NAN_DATAPATH +endif + +ifeq ($(CONFIG_WLAN_DEBUGFS), y) +CDEFINES += -DWLAN_DEBUGFS +endif + +KBUILD_CPPFLAGS += $(CDEFINES) + +# Currently, for versions of gcc which support it, the kernel Makefile +# is disabling the maybe-uninitialized warning. Re-enable it for the +# WLAN driver. Note that we must use EXTRA_CFLAGS here so that it +# will override the kernel settings. +ifeq ($(call cc-option-yn, -Wmaybe-uninitialized),y) +EXTRA_CFLAGS += -Wmaybe-uninitialized +endif +EXTRA_CFLAGS += -Wmissing-prototypes + +ifeq ($(call cc-option-yn, -Wheader-guard),y) +EXTRA_CFLAGS += -Wheader-guard +endif + +# If the module name is not "wlan", then the define MULTI_IF_NAME to be the +# same a the module name. The host driver will then append MULTI_IF_NAME to +# any string that must be unique for all instances of the driver on the system. +# This allows multiple instances of the driver with different module names. +# If the module name is wlan, leave MULTI_IF_NAME undefined and the code will +# treat the driver as the primary driver. +ifneq ($(MODNAME), wlan) +CDEFINES += -DMULTI_IF_NAME=\"$(MODNAME)\" +endif + +# WLAN_HDD_ADAPTER_MAGIC must be unique for all instances of the driver on the +# system. If it is not defined, then the host driver will use the first 4 +# characters (including NULL) of MULTI_IF_NAME to construct +# WLAN_HDD_ADAPTER_MAGIC. +ifdef WLAN_HDD_ADAPTER_MAGIC +CDEFINES += -DWLAN_HDD_ADAPTER_MAGIC=$(WLAN_HDD_ADAPTER_MAGIC) +endif + +# Module information used by KBuild framework +obj-$(CONFIG_QCA_CLD_WLAN) += $(MODNAME).o +$(MODNAME)-y := $(OBJS) diff --git a/drivers/staging/qcacld-3.0/Kconfig b/drivers/staging/qcacld-3.0/Kconfig new file mode 100644 index 0000000000000000000000000000000000000000..379880839f5dc628a1c01e432e5dbe52ba51e716 --- /dev/null +++ b/drivers/staging/qcacld-3.0/Kconfig @@ -0,0 +1,135 @@ +comment "Qualcomm Atheros CLD WLAN module" + +config QCA_CLD_WLAN + + tristate "Qualcomm Atheros CLD WLAN module" + default n + help + Add support for the Qualcomm Atheros CLD WLAN module + +if QCA_CLD_WLAN != n + +config QCACLD_WLAN_LFR3 + bool "Enable the WLAN Legacy Fast Roaming feature Version 3" + default n + +config PRIMA_WLAN_OKC + bool "Enable the Prima WLAN Opportunistic Key Caching feature" + default n + +config PRIMA_WLAN_11AC_HIGH_TP + bool "Enable the Prima WLAN 802.11ac High Throughput option (depends upon kernel support)" + default n + +config WLAN_FEATURE_11W + bool "Enable the WLAN 802.11w Protected Management Frames feature" + default n + +config WLAN_FEATURE_LPSS + bool "Enable the WLAN LPSS feature" + default n + +config QCOM_VOWIFI_11R + bool "Enable Fast Transition (11r) feature" + default n + +config QCACLD_FEATURE_NAN + bool "Enable NAN feature" + default n + +config WLAN_FEATURE_NAN_DATAPATH + bool "Enable NaN Data Path feature" + depends on QCACLD_FEATURE_NAN + default n + +config QCACLD_FEATURE_GREEN_AP + bool "Enable Green AP feature" + default n + +config HELIUMPLUS + bool "Enable Beeliner based descriptor structures for Helium" + default n + +config 64BIT_PADDR + bool "Enable 37-bit physical/bus addresses" + depends on HELIUMPLUS + default n + +config QCOM_TDLS + bool "Enable TDLS feature" + default n + +config QCOM_LTE_COEX + bool "Enable QCOM LTE Coex feature" + default n + +config MPC_UT_FRAMEWORK + bool "Enable Unit test framework for multiport concurrency" + default n + +config WLAN_OFFLOAD_PACKETS + bool "Enable offload packets feature" + default n + +config WLAN_FEATURE_MEMDUMP + bool "Enable MEMDUMP feature" + default n + +config FEATURE_TSO + bool "Enable TCP Segmentation Offload" + depends on HELIUMPLUS + default n + +config FEATURE_TSO_DEBUG + bool "Enable TCP Segmentation Offload with debug" + depends on FEATURE_TSO + default n + +config WLAN_FASTPATH + bool "Enable fastpath for datapackets" + default n + +config WLAN_NAPI + bool "Enable NAPI - datapath rx" + default n + +config WLAN_NAPI_DEBUG + bool "Enable debug logging on NAPI" + depends on WLAN_NAPI + default n + +config WLAN_TX_FLOW_CONTROL_V2 + bool "Enable tx flow control version:2" + default n + +config WLAN_LRO + bool "Enable Large Receive Offload" + depends on HELIUMPLUS + depends on CONFIG_INET_LRO + default n + +config WLAN_SYNC_TSF + bool "Enable QCOM sync multi devices tsf feature" + default n + +config LFR_SUBNET_DETECTION + bool "Enable LFR Subnet Change Detection" + default n + +config MCC_TO_SCC_SWITCH + bool "Enable MCC to SCC Switch Logic" + default n + +config QCACLD_WLAN_LFR2 + bool "Enable the WLAN Legacy Fast Roaming feature Version 2" + default n + +config FEATURE_DP_TRACE + bool "Enable data path trace feature" + default n + +config WLAN_FEATURE_DISA + bool "Enable DISA certification feature" + default n + +endif # QCA_CLD_WLAN diff --git a/drivers/staging/qcacld-3.0/Makefile b/drivers/staging/qcacld-3.0/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..0e11ae6e7ae78707c490cb5ffbe20587d639d2cf --- /dev/null +++ b/drivers/staging/qcacld-3.0/Makefile @@ -0,0 +1,20 @@ +KERNEL_SRC ?= /lib/modules/$(shell uname -r)/build + +KBUILD_OPTIONS := WLAN_ROOT=$(PWD) +KBUILD_OPTIONS += MODNAME?=wlan + +#By default build for CLD +WLAN_SELECT := CONFIG_QCA_CLD_WLAN=m +KBUILD_OPTIONS += CONFIG_QCA_WIFI_ISOC=0 +KBUILD_OPTIONS += CONFIG_QCA_WIFI_2_0=1 +KBUILD_OPTIONS += $(WLAN_SELECT) +KBUILD_OPTIONS += $(KBUILD_EXTRA) # Extra config if any + +all: + $(MAKE) -C $(KERNEL_SRC) M=$(shell pwd) modules $(KBUILD_OPTIONS) + +modules_install: + $(MAKE) INSTALL_MOD_STRIP=1 -C $(KERNEL_SRC) M=$(shell pwd) modules_install + +clean: + $(MAKE) -C $(KERNEL_SRC) M=$(PWD) clean diff --git a/drivers/staging/qcacld-3.0/README.txt b/drivers/staging/qcacld-3.0/README.txt new file mode 100644 index 0000000000000000000000000000000000000000..bdf3e7a7adc4eaf2883ac235c8ad755f3552a88f --- /dev/null +++ b/drivers/staging/qcacld-3.0/README.txt @@ -0,0 +1 @@ +This is CNSS WLAN Host Driver for products starting from iHelium diff --git a/drivers/staging/qcacld-3.0/core/bmi/inc/bmi.h b/drivers/staging/qcacld-3.0/core/bmi/inc/bmi.h new file mode 100644 index 0000000000000000000000000000000000000000..2adae5d9d77a8a02477ec49d227a71d458e4a2e4 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/bmi/inc/bmi.h @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2013-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* ================================================================ */ +/* BMI declarations and prototypes */ +/* */ +/* ================================================================= */ + +#ifndef _BMI_H_ +#define _BMI_H_ +#include "bmi_msg.h" +#include "qdf_trace.h" +#include "ol_if_athvar.h" +#include "hif.h" + +struct ol_context; +QDF_STATUS ol_cds_init(qdf_device_t qdf_dev, void *hif_ctx); +void ol_cds_free(void); + +/** + * struct hif_config_info - Place Holder for hif confiruation + * @enable_uart_print: UART Print + * @enable_self_recovery: Self Recovery + * @enable_fw_log: To Enable FW LOG + * @enable_lpass_support: LPASS support + * @enable_ramdump_collection: Ramdump Collection + * + * Structure for holding ini parameters. + */ + +struct ol_config_info { + bool enable_uart_print; + bool enable_self_recovery; + uint8_t enable_fw_log; + bool enable_lpass_support; + bool enable_ramdump_collection; +}; + +void ol_init_ini_config(struct ol_context *ol_ctx, + struct ol_config_info *cfg); +void bmi_cleanup(struct ol_context *scn); +QDF_STATUS bmi_done(struct ol_context *ol_ctx); +void bmi_target_ready(struct hif_opaque_softc *scn, void *cfg_ctx); +QDF_STATUS bmi_download_firmware(struct ol_context *ol_ctx); +#endif /* _BMI_H_ */ diff --git a/drivers/staging/qcacld-3.0/core/bmi/inc/ol_fw.h b/drivers/staging/qcacld-3.0/core/bmi/inc/ol_fw.h new file mode 100644 index 0000000000000000000000000000000000000000..5243228970cf8c0557a18eea2dff5ab47382061d --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/bmi/inc/ol_fw.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2014-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef _OL_FW_H_ +#define _OL_FW_H_ + +#ifdef QCA_WIFI_FTM +#include "qdf_types.h" +#endif +#include "hif.h" +#include "hif_hw_version.h" +#include "bmi.h" + +#define AR6320_REV2_VERSION AR6320_REV1_1_VERSION +#define AR6320_REV4_VERSION AR6320_REV2_1_VERSION +#define SIGN_HEADER_MAGIC 0x454D4F52 +#define HI_ACS_FLAGS_SDIO_SWAP_MAILBOX_SET (1 << 0) +#define HI_ACS_FLAGS_SDIO_REDUCE_TX_COMPL_SET (1 << 1) +#define HI_ACS_FLAGS_ALT_DATA_CREDIT_SIZE (1 << 2) + +#define HI_ACS_FLAGS_SDIO_SWAP_MAILBOX_FW_ACK (1 << 16) +#define HI_ACS_FLAGS_SDIO_REDUCE_TX_COMPL_FW_ACK (1 << 17) + +void ol_target_failure(void *instance, QDF_STATUS status); + +void ol_target_ready(struct hif_opaque_softc *scn, void *cfg_ctx); +QDF_STATUS ol_get_fw_files(struct ol_context *ol_ctx); +QDF_STATUS ol_extra_initialization(struct ol_context *ol_ctx); +#endif /* _OL_FW_H_ */ diff --git a/drivers/staging/qcacld-3.0/core/bmi/inc/ol_if_athvar.h b/drivers/staging/qcacld-3.0/core/bmi/inc/ol_if_athvar.h new file mode 100644 index 0000000000000000000000000000000000000000..afd143899ec2a7d48e4934ad38a8a98ce3f96fc8 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/bmi/inc/ol_if_athvar.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2014-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * Defintions for the Atheros Wireless LAN controller driver. + */ +#ifndef _DEV_OL_ATH_ATHVAR_H +#define _DEV_OL_ATH_ATHVAR_H + +#include +#include "qdf_types.h" +#include "qdf_lock.h" +#include "wmi_unified_api.h" +#include "htc_api.h" +#include "bmi_msg.h" +#include "ol_params.h" +#include + +#include "ol_ctrl_addba_api.h" + +struct ol_version { + uint32_t host_ver; + uint32_t target_ver; + uint32_t wlan_ver; + uint32_t wlan_ver_1; + uint32_t abi_ver; +}; + +enum ol_ath_tx_ecodes { + TX_IN_PKT_INCR = 0, + TX_OUT_HDR_COMPL, + TX_OUT_PKT_COMPL, + PKT_ENCAP_FAIL, + TX_PKT_BAD, + RX_RCV_MSG_RX_IND, + RX_RCV_MSG_PEER_MAP, + RX_RCV_MSG_TYPE_TEST +}; + +/* + * structure to hold the packet error count for CE and hif layer + */ +struct ol_ath_stats { + int hif_pipe_no_resrc_count; + int ce_ring_delta_fail_count; +}; + +#endif /* _DEV_OL_ATH_ATHVAR_H */ diff --git a/drivers/staging/qcacld-3.0/core/bmi/src/bmi.c b/drivers/staging/qcacld-3.0/core/bmi/src/bmi.c new file mode 100644 index 0000000000000000000000000000000000000000..33f5986cca0d238aaf9dd579d55d9a16725bbd78 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/bmi/src/bmi.c @@ -0,0 +1,582 @@ +/* + * Copyright (c) 2014-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#include "i_bmi.h" +#include "cds_api.h" + +/* APIs visible to the driver */ + +QDF_STATUS bmi_init(struct ol_context *ol_ctx) +{ + struct bmi_info *info = GET_BMI_CONTEXT(ol_ctx); + struct hif_opaque_softc *scn = ol_ctx->scn; + qdf_device_t qdf_dev = ol_ctx->qdf_dev; + + if (!scn) { + BMI_ERR("Invalid scn Context"); + bmi_assert(0); + return QDF_STATUS_NOT_INITIALIZED; + } + + if (!qdf_dev->dev) { + BMI_ERR("%s: Invalid Device Pointer", __func__); + return QDF_STATUS_NOT_INITIALIZED; + } + + info->bmi_done = false; + + if (!info->bmi_cmd_buff) { + info->bmi_cmd_buff = + qdf_mem_alloc_consistent(qdf_dev, qdf_dev->dev, MAX_BMI_CMDBUF_SZ, + &info->bmi_cmd_da); + if (!info->bmi_cmd_buff) { + BMI_ERR("No Memory for BMI Command"); + return QDF_STATUS_E_NOMEM; + } + } + + if (!info->bmi_rsp_buff) { + info->bmi_rsp_buff = + qdf_mem_alloc_consistent(qdf_dev, qdf_dev->dev, MAX_BMI_CMDBUF_SZ, + &info->bmi_rsp_da); + if (!info->bmi_rsp_buff) { + BMI_ERR("No Memory for BMI Response"); + goto end; + } + } + return QDF_STATUS_SUCCESS; +end: + qdf_mem_free_consistent(qdf_dev, qdf_dev->dev, MAX_BMI_CMDBUF_SZ, + info->bmi_cmd_buff, info->bmi_cmd_da, 0); + info->bmi_cmd_buff = NULL; + return QDF_STATUS_E_NOMEM; +} + +void bmi_cleanup(struct ol_context *ol_ctx) +{ + struct bmi_info *info = GET_BMI_CONTEXT(ol_ctx); + qdf_device_t qdf_dev; + + if (!info || !ol_ctx) { + BMI_WARN("%s: no bmi to cleanup", __func__); + return; + } + + qdf_dev = ol_ctx->qdf_dev; + if (!qdf_dev || !qdf_dev->dev) { + BMI_ERR("%s: Invalid Device Pointer", __func__); + return; + } + + if (info->bmi_cmd_buff) { + qdf_mem_free_consistent(qdf_dev, qdf_dev->dev, + MAX_BMI_CMDBUF_SZ, + info->bmi_cmd_buff, info->bmi_cmd_da, 0); + info->bmi_cmd_buff = NULL; + info->bmi_cmd_da = 0; + } + + if (info->bmi_rsp_buff) { + qdf_mem_free_consistent(qdf_dev, qdf_dev->dev, + MAX_BMI_CMDBUF_SZ, + info->bmi_rsp_buff, info->bmi_rsp_da, 0); + info->bmi_rsp_buff = NULL; + info->bmi_rsp_da = 0; + } +} + +/** + * bmi_done() - finish the bmi opperation + * @ol_ctx: the bmi context + * + * does some sanity checking. + * exchanges one last message with firmware. + * frees some buffers. + * + * Return: QDF_STATUS_SUCCESS if bmi isn't needed. + * QDF_STATUS_SUCCESS if bmi finishes. + * otherwise returns failure. + */ +QDF_STATUS bmi_done(struct ol_context *ol_ctx) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + + if (NO_BMI) + return QDF_STATUS_SUCCESS; + + if (!ol_ctx) { + BMI_ERR("%s: null context", __func__); + return QDF_STATUS_E_NOMEM; + } + hif_claim_device(ol_ctx->scn); + + if (!hif_needs_bmi(ol_ctx->scn)) + return QDF_STATUS_SUCCESS; + + status = bmi_done_local(ol_ctx); + if (status != QDF_STATUS_SUCCESS) + BMI_ERR("BMI_DONE Failed status:%d", status); + + return status; +} + +void bmi_target_ready(struct hif_opaque_softc *scn, void *cfg_ctx) +{ + ol_target_ready(scn, cfg_ctx); +} + +static QDF_STATUS +bmi_get_target_info_message_based(struct bmi_target_info *targ_info, + struct ol_context *ol_ctx) +{ + int status = 0; + struct hif_opaque_softc *scn = ol_ctx->scn; + struct bmi_info *info = GET_BMI_CONTEXT(ol_ctx); + uint8_t *bmi_cmd_buff = info->bmi_cmd_buff; + uint8_t *bmi_rsp_buff = info->bmi_rsp_buff; + uint32_t cid, length; + qdf_dma_addr_t cmd = info->bmi_cmd_da; + qdf_dma_addr_t rsp = info->bmi_rsp_da; + + if (!bmi_cmd_buff || !bmi_rsp_buff) { + BMI_ERR("%s:BMI CMD/RSP Buffer is NULL", __func__); + return QDF_STATUS_NOT_INITIALIZED; + } + + cid = BMI_GET_TARGET_INFO; + + qdf_mem_copy(bmi_cmd_buff, &cid, sizeof(cid)); + length = sizeof(struct bmi_target_info); + + status = hif_exchange_bmi_msg(scn, cmd, rsp, bmi_cmd_buff, sizeof(cid), + (uint8_t *)bmi_rsp_buff, &length, + BMI_EXCHANGE_TIMEOUT_MS); + if (status) { + BMI_ERR("Failed to target info: status:%d", status); + return QDF_STATUS_E_FAILURE; + } + + qdf_mem_copy(targ_info, bmi_rsp_buff, length); + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +bmi_get_target_info(struct bmi_target_info *targ_info, + struct ol_context *ol_ctx) +{ + struct hif_opaque_softc *scn = ol_ctx->scn; + struct bmi_info *info = GET_BMI_CONTEXT(ol_ctx); + QDF_STATUS status; + + if (info->bmi_done) { + BMI_ERR("BMI Phase is Already Done"); + return QDF_STATUS_E_PERM; + } + + switch (hif_get_bus_type(scn)) { + case QDF_BUS_TYPE_PCI: + case QDF_BUS_TYPE_SNOC: + case QDF_BUS_TYPE_USB: + status = bmi_get_target_info_message_based(targ_info, ol_ctx); + break; +#ifdef HIF_SDIO + case QDF_BUS_TYPE_SDIO: + status = hif_reg_based_get_target_info(scn, targ_info); + break; +#endif + default: + status = QDF_STATUS_E_FAILURE; + break; + } + return status; +} + +QDF_STATUS bmi_download_firmware(struct ol_context *ol_ctx) +{ + struct hif_opaque_softc *scn; + + if (!ol_ctx) { + if (NO_BMI) { + /* ol_ctx is not allocated in NO_BMI case */ + return QDF_STATUS_SUCCESS; + } else { + BMI_ERR("ol_ctx is NULL"); + bmi_assert(0); + return QDF_STATUS_NOT_INITIALIZED; + } + } + + scn = ol_ctx->scn; + + if (!scn) { + BMI_ERR("Invalid scn context"); + bmi_assert(0); + return QDF_STATUS_NOT_INITIALIZED; + } + + if (!hif_needs_bmi(scn)) + return QDF_STATUS_SUCCESS; + + return bmi_firmware_download(ol_ctx); +} + +QDF_STATUS bmi_read_soc_register(uint32_t address, uint32_t *param, + struct ol_context *ol_ctx) +{ + struct hif_opaque_softc *scn = ol_ctx->scn; + uint32_t cid; + int status; + uint32_t offset, param_len; + struct bmi_info *info = GET_BMI_CONTEXT(ol_ctx); + uint8_t *bmi_cmd_buff = info->bmi_cmd_buff; + uint8_t *bmi_rsp_buff = info->bmi_rsp_buff; + qdf_dma_addr_t cmd = info->bmi_cmd_da; + qdf_dma_addr_t rsp = info->bmi_rsp_da; + + bmi_assert(BMI_COMMAND_FITS(sizeof(cid) + sizeof(address))); + qdf_mem_set(bmi_cmd_buff, 0, sizeof(cid) + sizeof(address)); + qdf_mem_set(bmi_rsp_buff, 0, sizeof(cid) + sizeof(address)); + + if (info->bmi_done) { + BMI_DBG("Command disallowed"); + return QDF_STATUS_E_PERM; + } + + BMI_DBG("BMI Read SOC Register:device: 0x%p, address: 0x%x", + scn, address); + + cid = BMI_READ_SOC_REGISTER; + + offset = 0; + qdf_mem_copy(&(bmi_cmd_buff[offset]), &cid, sizeof(cid)); + offset += sizeof(cid); + qdf_mem_copy(&(bmi_cmd_buff[offset]), &address, sizeof(address)); + offset += sizeof(address); + param_len = sizeof(*param); + status = hif_exchange_bmi_msg(scn, cmd, rsp, bmi_cmd_buff, offset, + bmi_rsp_buff, ¶m_len, BMI_EXCHANGE_TIMEOUT_MS); + if (status) { + BMI_DBG("Unable to read from the device; status:%d", status); + return QDF_STATUS_E_FAILURE; + } + qdf_mem_copy(param, bmi_rsp_buff, sizeof(*param)); + + BMI_DBG("BMI Read SOC Register: Exit value: %d", *param); + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS bmi_write_soc_register(uint32_t address, uint32_t param, + struct ol_context *ol_ctx) +{ + struct hif_opaque_softc *scn = ol_ctx->scn; + uint32_t cid; + int status; + uint32_t offset; + struct bmi_info *info = GET_BMI_CONTEXT(ol_ctx); + uint8_t *bmi_cmd_buff = info->bmi_cmd_buff; + uint32_t size = sizeof(cid) + sizeof(address) + sizeof(param); + qdf_dma_addr_t cmd = info->bmi_cmd_da; + qdf_dma_addr_t rsp = info->bmi_rsp_da; + + bmi_assert(BMI_COMMAND_FITS(size)); + qdf_mem_set(bmi_cmd_buff, 0, size); + + if (info->bmi_done) { + BMI_DBG("Command disallowed"); + return QDF_STATUS_E_FAILURE; + } + + BMI_DBG("SOC Register Write:device:0x%p, addr:0x%x, param:%d", + scn, address, param); + + cid = BMI_WRITE_SOC_REGISTER; + + offset = 0; + qdf_mem_copy(&(bmi_cmd_buff[offset]), &cid, sizeof(cid)); + offset += sizeof(cid); + qdf_mem_copy(&(bmi_cmd_buff[offset]), &address, sizeof(address)); + offset += sizeof(address); + qdf_mem_copy(&(bmi_cmd_buff[offset]), ¶m, sizeof(param)); + offset += sizeof(param); + status = hif_exchange_bmi_msg(scn, cmd, rsp, bmi_cmd_buff, offset, + NULL, NULL, 0); + if (status) { + BMI_ERR("Unable to write to the device: status:%d", status); + return QDF_STATUS_E_FAILURE; + } + + BMI_DBG("BMI Read SOC Register: Exit"); + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS +bmilz_data(uint8_t *buffer, uint32_t length, struct ol_context *ol_ctx) +{ + uint32_t cid; + int status; + uint32_t offset; + uint32_t remaining, txlen; + const uint32_t header = sizeof(cid) + sizeof(length); + struct hif_opaque_softc *scn = ol_ctx->scn; + struct bmi_info *info = GET_BMI_CONTEXT(ol_ctx); + uint8_t *bmi_cmd_buff = info->bmi_cmd_buff; + qdf_dma_addr_t cmd = info->bmi_cmd_da; + qdf_dma_addr_t rsp = info->bmi_rsp_da; + + bmi_assert(BMI_COMMAND_FITS(BMI_DATASZ_MAX + header)); + qdf_mem_set(bmi_cmd_buff, 0, BMI_DATASZ_MAX + header); + + if (info->bmi_done) { + BMI_ERR("Command disallowed"); + return QDF_STATUS_E_PERM; + } + + BMI_DBG("BMI Send LZ Data: device: 0x%p, length: %d", + scn, length); + + cid = BMI_LZ_DATA; + + remaining = length; + while (remaining) { + txlen = (remaining < (BMI_DATASZ_MAX - header)) ? + remaining : (BMI_DATASZ_MAX - header); + offset = 0; + qdf_mem_copy(&(bmi_cmd_buff[offset]), &cid, sizeof(cid)); + offset += sizeof(cid); + qdf_mem_copy(&(bmi_cmd_buff[offset]), &txlen, sizeof(txlen)); + offset += sizeof(txlen); + qdf_mem_copy(&(bmi_cmd_buff[offset]), + &buffer[length - remaining], txlen); + offset += txlen; + status = hif_exchange_bmi_msg(scn, cmd, rsp, + bmi_cmd_buff, offset, + NULL, NULL, 0); + if (status) { + BMI_ERR("Failed to write to the device: status:%d", + status); + return QDF_STATUS_E_FAILURE; + } + remaining -= txlen; + } + + BMI_DBG("BMI LZ Data: Exit"); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS bmi_sign_stream_start(uint32_t address, uint8_t *buffer, + uint32_t length, struct ol_context *ol_ctx) +{ + uint32_t cid; + int status; + uint32_t offset; + const uint32_t header = sizeof(cid) + sizeof(address) + sizeof(length); + uint8_t aligned_buf[BMI_DATASZ_MAX + 4]; + uint8_t *src; + struct hif_opaque_softc *scn = ol_ctx->scn; + struct bmi_info *info = GET_BMI_CONTEXT(ol_ctx); + uint8_t *bmi_cmd_buff = info->bmi_cmd_buff; + uint32_t remaining, txlen; + qdf_dma_addr_t cmd = info->bmi_cmd_da; + qdf_dma_addr_t rsp = info->bmi_rsp_da; + + bmi_assert(BMI_COMMAND_FITS(BMI_DATASZ_MAX + header)); + qdf_mem_set(bmi_cmd_buff, 0, BMI_DATASZ_MAX + header); + + if (info->bmi_done) { + BMI_ERR("Command disallowed"); + return QDF_STATUS_E_PERM; + } + + BMI_ERR("Sign Stream start:device:0x%p, addr:0x%x, length:%d", + scn, address, length); + + cid = BMI_SIGN_STREAM_START; + remaining = length; + while (remaining) { + src = &buffer[length - remaining]; + if (remaining < (BMI_DATASZ_MAX - header)) { + if (remaining & 0x3) { + remaining = remaining + (4 - (remaining & 0x3)); + memcpy(aligned_buf, src, remaining); + src = aligned_buf; + } + txlen = remaining; + } else { + txlen = (BMI_DATASZ_MAX - header); + } + + offset = 0; + qdf_mem_copy(&(bmi_cmd_buff[offset]), &cid, sizeof(cid)); + offset += sizeof(cid); + qdf_mem_copy(&(bmi_cmd_buff[offset]), &address, + sizeof(address)); + offset += sizeof(offset); + qdf_mem_copy(&(bmi_cmd_buff[offset]), &txlen, sizeof(txlen)); + offset += sizeof(txlen); + qdf_mem_copy(&(bmi_cmd_buff[offset]), src, txlen); + offset += txlen; + status = hif_exchange_bmi_msg(scn, cmd, rsp, + bmi_cmd_buff, offset, NULL, + NULL, BMI_EXCHANGE_TIMEOUT_MS); + if (status) { + BMI_ERR("Unable to write to the device: status:%d", + status); + return QDF_STATUS_E_FAILURE; + } + remaining -= txlen; + } + BMI_DBG("BMI SIGN Stream Start: Exit"); + + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS +bmilz_stream_start(uint32_t address, struct ol_context *ol_ctx) +{ + uint32_t cid; + int status; + uint32_t offset; + struct hif_opaque_softc *scn = ol_ctx->scn; + struct bmi_info *info = GET_BMI_CONTEXT(ol_ctx); + uint8_t *bmi_cmd_buff = info->bmi_cmd_buff; + qdf_dma_addr_t cmd = info->bmi_cmd_da; + qdf_dma_addr_t rsp = info->bmi_rsp_da; + + bmi_assert(BMI_COMMAND_FITS(sizeof(cid) + sizeof(address))); + qdf_mem_set(bmi_cmd_buff, 0, sizeof(cid) + sizeof(address)); + + if (info->bmi_done) { + BMI_DBG("Command disallowed"); + return QDF_STATUS_E_PERM; + } + BMI_DBG("BMI LZ Stream Start: (device: 0x%p, address: 0x%x)", + scn, address); + + cid = BMI_LZ_STREAM_START; + offset = 0; + qdf_mem_copy(&(bmi_cmd_buff[offset]), &cid, sizeof(cid)); + offset += sizeof(cid); + qdf_mem_copy(&(bmi_cmd_buff[offset]), &address, sizeof(address)); + offset += sizeof(address); + status = hif_exchange_bmi_msg(scn, cmd, rsp, bmi_cmd_buff, offset, + NULL, NULL, 0); + if (status) { + BMI_ERR("Unable to Start LZ Stream to the device status:%d", + status); + return QDF_STATUS_E_FAILURE; + } + BMI_DBG("BMI LZ Stream: Exit"); + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +bmi_fast_download(uint32_t address, uint8_t *buffer, + uint32_t length, struct ol_context *ol_ctx) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + uint32_t last_word = 0; + uint32_t last_word_offset = length & ~0x3; + uint32_t unaligned_bytes = length & 0x3; + + status = bmilz_stream_start(address, ol_ctx); + if (status != QDF_STATUS_SUCCESS) + goto end; + + /* copy the last word into a zero padded buffer */ + if (unaligned_bytes) + qdf_mem_copy(&last_word, &buffer[last_word_offset], + unaligned_bytes); + + status = bmilz_data(buffer, last_word_offset, ol_ctx); + + if (status != QDF_STATUS_SUCCESS) + goto end; + + if (unaligned_bytes) + status = bmilz_data((uint8_t *) &last_word, 4, ol_ctx); + + if (status != QDF_STATUS_SUCCESS) + /* + * Close compressed stream and open a new (fake) one. + * This serves mainly to flush Target caches. + */ + status = bmilz_stream_start(0x00, ol_ctx); +end: + return status; +} + +/** + * ol_cds_init() - API to initialize global CDS OL Context + * @qdf_dev: QDF Device + * @hif_ctx: HIF Context + * + * Return: Success/Failure + */ +QDF_STATUS ol_cds_init(qdf_device_t qdf_dev, void *hif_ctx) +{ + struct ol_context *ol_info; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + if (NO_BMI) + return QDF_STATUS_SUCCESS; /* no BMI for Q6 bring up */ + + status = cds_alloc_context(cds_get_global_context(), QDF_MODULE_ID_BMI, + (void **)&ol_info, sizeof(*ol_info)); + + if (status != QDF_STATUS_SUCCESS) { + BMI_ERR("%s: CDS Allocation failed for ol_bmi context", + __func__); + return status; + } + + ol_info->qdf_dev = qdf_dev; + ol_info->scn = hif_ctx; + ol_info->tgt_def.targetdef = hif_get_targetdef(hif_ctx); + + qdf_create_work(qdf_dev, &ol_info->ramdump_work, + ramdump_work_handler, ol_info); + qdf_create_work(qdf_dev, &ol_info->fw_indication_work, + fw_indication_work_handler, ol_info); + + return status; +} + +/** + * ol_cds_free() - API to free the global CDS OL Context + * + * Return: void + */ +void ol_cds_free(void) +{ + struct ol_context *ol_info = cds_get_context(QDF_MODULE_ID_BMI); + + if (NO_BMI) + return; + + cds_free_context(cds_get_global_context(), QDF_MODULE_ID_BMI, ol_info); +} diff --git a/drivers/staging/qcacld-3.0/core/bmi/src/bmi_1.c b/drivers/staging/qcacld-3.0/core/bmi/src/bmi_1.c new file mode 100644 index 0000000000000000000000000000000000000000..9033d9dc1686025612d306aa1589f7a4764bb2fc --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/bmi/src/bmi_1.c @@ -0,0 +1,341 @@ +/* + * Copyright (c) 2014-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#include "i_bmi.h" +#include "cds_api.h" + +/* APIs visible to the driver */ + +QDF_STATUS +bmi_read_memory(uint32_t address, + uint8_t *buffer, uint32_t length, struct ol_context *ol_ctx) +{ + struct hif_opaque_softc *scn = ol_ctx->scn; + uint32_t cid; + int status; + uint32_t offset; + uint32_t remaining, rxlen; + struct bmi_info *info = GET_BMI_CONTEXT(ol_ctx); + uint8_t *bmi_cmd_buff = info->bmi_cmd_buff; + uint8_t *bmi_rsp_buff = info->bmi_rsp_buff; + uint32_t align; + qdf_dma_addr_t cmd = info->bmi_cmd_da; + qdf_dma_addr_t rsp = info->bmi_rsp_da; + + if (info->bmi_done) { + BMI_DBG("command disallowed"); + return QDF_STATUS_E_PERM; + } + + if (!info->bmi_cmd_buff || !info->bmi_rsp_buff) { + BMI_ERR("BMI Initialization hasn't done"); + return QDF_STATUS_NOT_INITIALIZED; + } + + bmi_assert(BMI_COMMAND_FITS(BMI_DATASZ_MAX + sizeof(cid) + + sizeof(address) + sizeof(length))); + qdf_mem_set(bmi_cmd_buff, 0, BMI_DATASZ_MAX + sizeof(cid) + + sizeof(address) + sizeof(length)); + qdf_mem_set(bmi_rsp_buff, 0, BMI_DATASZ_MAX + sizeof(cid) + + sizeof(address) + sizeof(length)); + + cid = BMI_READ_MEMORY; + align = 0; + remaining = length; + + while (remaining) { + rxlen = (remaining < BMI_DATASZ_MAX) ? + remaining : BMI_DATASZ_MAX; + offset = 0; + qdf_mem_copy(&(bmi_cmd_buff[offset]), &cid, sizeof(cid)); + offset += sizeof(cid); + qdf_mem_copy(&(bmi_cmd_buff[offset]), &address, + sizeof(address)); + offset += sizeof(address); + qdf_mem_copy(&(bmi_cmd_buff[offset]), &rxlen, sizeof(rxlen)); + offset += sizeof(length); + + /* note we reuse the same buffer to receive on */ + status = hif_exchange_bmi_msg(scn, cmd, rsp, bmi_cmd_buff, + offset, bmi_rsp_buff, &rxlen, + BMI_EXCHANGE_TIMEOUT_MS); + if (status) { + BMI_ERR("Unable to read from the device"); + return QDF_STATUS_E_FAILURE; + } + if (remaining == rxlen) { + qdf_mem_copy(&buffer[length - remaining + align], + bmi_rsp_buff, rxlen - align); + /* last align bytes are invalid */ + } else { + qdf_mem_copy(&buffer[length - remaining + align], + bmi_rsp_buff, rxlen); + } + remaining -= rxlen; + address += rxlen; + } + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS bmi_write_memory(uint32_t address, uint8_t *buffer, uint32_t length, + struct ol_context *ol_ctx) +{ + struct hif_opaque_softc *scn = ol_ctx->scn; + uint32_t cid; + int status; + uint32_t offset; + uint32_t remaining, txlen; + const uint32_t header = sizeof(cid) + sizeof(address) + sizeof(length); + uint8_t aligned_buffer[BMI_DATASZ_MAX]; + uint8_t *src; + struct bmi_info *info = GET_BMI_CONTEXT(ol_ctx); + uint8_t *bmi_cmd_buff = info->bmi_cmd_buff; + qdf_dma_addr_t cmd = info->bmi_cmd_da; + qdf_dma_addr_t rsp = info->bmi_rsp_da; + + if (info->bmi_done) { + BMI_ERR("Command disallowed"); + return QDF_STATUS_E_PERM; + } + + if (!bmi_cmd_buff) { + BMI_ERR("BMI initialization hasn't done"); + return QDF_STATUS_E_PERM; + } + + bmi_assert(BMI_COMMAND_FITS(BMI_DATASZ_MAX + header)); + qdf_mem_set(bmi_cmd_buff, 0, BMI_DATASZ_MAX + header); + + cid = BMI_WRITE_MEMORY; + + remaining = length; + while (remaining) { + src = &buffer[length - remaining]; + if (remaining < (BMI_DATASZ_MAX - header)) { + if (remaining & 3) { + /* align it with 4 bytes */ + remaining = remaining + (4 - (remaining & 3)); + memcpy(aligned_buffer, src, remaining); + src = aligned_buffer; + } + txlen = remaining; + } else { + txlen = (BMI_DATASZ_MAX - header); + } + offset = 0; + qdf_mem_copy(&(bmi_cmd_buff[offset]), &cid, sizeof(cid)); + offset += sizeof(cid); + qdf_mem_copy(&(bmi_cmd_buff[offset]), &address, + sizeof(address)); + offset += sizeof(address); + qdf_mem_copy(&(bmi_cmd_buff[offset]), &txlen, sizeof(txlen)); + offset += sizeof(txlen); + qdf_mem_copy(&(bmi_cmd_buff[offset]), src, txlen); + offset += txlen; + status = hif_exchange_bmi_msg(scn, cmd, rsp, bmi_cmd_buff, + offset, NULL, NULL, + BMI_EXCHANGE_TIMEOUT_MS); + if (status) { + BMI_ERR("Unable to write to the device; status:%d", + status); + return QDF_STATUS_E_FAILURE; + } + remaining -= txlen; + address += txlen; + } + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +bmi_execute(uint32_t address, A_UINT32 *param, struct ol_context *ol_ctx) +{ + struct hif_opaque_softc *scn = ol_ctx->scn; + uint32_t cid; + int status; + uint32_t offset; + uint32_t param_len; + struct bmi_info *info = GET_BMI_CONTEXT(ol_ctx); + uint8_t *bmi_cmd_buff = info->bmi_cmd_buff; + uint8_t *bmi_rsp_buff = info->bmi_rsp_buff; + uint32_t size = sizeof(cid) + sizeof(address) + sizeof(param); + qdf_dma_addr_t cmd = info->bmi_cmd_da; + qdf_dma_addr_t rsp = info->bmi_rsp_da; + + if (info->bmi_done) { + BMI_ERR("Command disallowed"); + return QDF_STATUS_E_PERM; + } + + if (!bmi_cmd_buff || !bmi_rsp_buff) { + BMI_ERR("%s:BMI CMD/RSP Buffer is NULL", __func__); + return QDF_STATUS_NOT_INITIALIZED; + } + + bmi_assert(BMI_COMMAND_FITS(size)); + qdf_mem_set(bmi_cmd_buff, 0, size); + qdf_mem_set(bmi_rsp_buff, 0, size); + + + BMI_DBG("BMI Execute: device: 0x%p, address: 0x%x, param: %d", + scn, address, *param); + + cid = BMI_EXECUTE; + + offset = 0; + qdf_mem_copy(&(bmi_cmd_buff[offset]), &cid, sizeof(cid)); + offset += sizeof(cid); + qdf_mem_copy(&(bmi_cmd_buff[offset]), &address, sizeof(address)); + offset += sizeof(address); + qdf_mem_copy(&(bmi_cmd_buff[offset]), param, sizeof(*param)); + offset += sizeof(*param); + param_len = sizeof(*param); + status = hif_exchange_bmi_msg(scn, cmd, rsp, bmi_cmd_buff, offset, + bmi_rsp_buff, ¶m_len, 0); + if (status) { + BMI_ERR("Unable to read from the device status:%d", status); + return QDF_STATUS_E_FAILURE; + } + + qdf_mem_copy(param, bmi_rsp_buff, sizeof(*param)); + + BMI_DBG("BMI Execute: Exit (param: %d)", *param); + return QDF_STATUS_SUCCESS; +} + +inline QDF_STATUS +bmi_no_command(struct ol_context *ol_ctx) +{ + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +bmi_firmware_download(struct ol_context *ol_ctx) +{ + struct hif_opaque_softc *scn = ol_ctx->scn; + QDF_STATUS status; + struct bmi_target_info targ_info; + struct hif_target_info *tgt_info = hif_get_target_info_handle(scn); + + qdf_mem_zero(&targ_info, sizeof(targ_info)); + /* Initialize BMI */ + status = bmi_init(ol_ctx); + if (status != QDF_STATUS_SUCCESS) { + BMI_ERR("BMI Initialization Failed err:%d", status); + return status; + } + + /* Get target information */ + status = bmi_get_target_info(&targ_info, ol_ctx); + if (status != QDF_STATUS_SUCCESS) { + BMI_ERR("BMI Target Info get failed: status:%d", status); + return status; + } + + tgt_info->target_type = targ_info.target_type; + tgt_info->target_version = targ_info.target_ver; + /* Configure target */ + status = ol_configure_target(ol_ctx); + if (status != QDF_STATUS_SUCCESS) { + BMI_ERR("BMI Configure Target Failed status:%d", status); + return status; + } + status = ol_download_firmware(ol_ctx); + if (status != QDF_STATUS_SUCCESS) + BMI_ERR("BMI Download Firmware Failed Status:%d", status); + + return status; +} + +QDF_STATUS bmi_done_local(struct ol_context *ol_ctx) +{ + struct hif_opaque_softc *scn = ol_ctx->scn; + int status; + uint32_t cid; + struct bmi_info *info; + qdf_device_t qdf_dev = ol_ctx->qdf_dev; + qdf_dma_addr_t cmd, rsp; + + if (!scn) { + BMI_ERR("Invalid scn context"); + bmi_assert(0); + return QDF_STATUS_NOT_INITIALIZED; + } + + if (!qdf_dev->dev) { + BMI_ERR("%s: Invalid device pointer", __func__); + return QDF_STATUS_NOT_INITIALIZED; + } + + info = GET_BMI_CONTEXT(ol_ctx); + if (info->bmi_done) { + BMI_DBG("bmi_done_local skipped"); + return QDF_STATUS_E_PERM; + } + + cmd = info->bmi_cmd_da; + rsp = info->bmi_rsp_da; + + BMI_DBG("BMI Done: Enter (device: 0x%p)", scn); + + info->bmi_done = true; + cid = BMI_DONE; + + if (!info->bmi_cmd_buff) { + BMI_ERR("Invalid scn BMICmdBuff"); + bmi_assert(0); + return QDF_STATUS_NOT_INITIALIZED; + } + + qdf_mem_copy(info->bmi_cmd_buff, &cid, sizeof(cid)); + + status = hif_exchange_bmi_msg(scn, cmd, rsp, info->bmi_cmd_buff, + sizeof(cid), NULL, NULL, 0); + if (status) { + BMI_ERR("Failed to write to the device; status:%d", status); + return QDF_STATUS_E_FAILURE; + } + + if (info->bmi_cmd_buff) { + qdf_mem_free_consistent(qdf_dev, qdf_dev->dev, + MAX_BMI_CMDBUF_SZ, + info->bmi_cmd_buff, info->bmi_cmd_da, 0); + info->bmi_cmd_buff = NULL; + info->bmi_cmd_da = 0; + } + + if (info->bmi_rsp_buff) { + qdf_mem_free_consistent(qdf_dev, qdf_dev->dev, + MAX_BMI_CMDBUF_SZ, + info->bmi_rsp_buff, info->bmi_rsp_da, 0); + info->bmi_rsp_buff = NULL; + info->bmi_rsp_da = 0; + } + + return QDF_STATUS_SUCCESS; +} diff --git a/drivers/staging/qcacld-3.0/core/bmi/src/i_ar6320v2_regtable.h b/drivers/staging/qcacld-3.0/core/bmi/src/i_ar6320v2_regtable.h new file mode 100644 index 0000000000000000000000000000000000000000..7bfc1b6e767f258d93832cc17c3d455d0b0d7a07 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/bmi/src/i_ar6320v2_regtable.h @@ -0,0 +1,605 @@ +/* + * Copyright (c) 2014,2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef _AR6320V2_DBG_REGTABLE_H_ +#define _AR6320V2_DBG_REGTABLE_H_ + +#include "regtable.h" + +#define AR6320_REV2_1_REG_SIZE 0x0007F820 +#define AR6320_REV3_REG_SIZE 0x0007F820 + +/* + * Redefine the register list. To minimize the size of the array, the list must + * obey the below format. {start0, end0}, {start1, end1}, {start2, end2}....... + * The value below must obey to "start0 < end0 < start1 < end1 < start2 < ...", + * otherwise we may encouter error in the dump processing. + */ + +static const tgt_reg_section ar6320v2_reg_table[] = { + {0x800, 0x810}, + {0x820, 0x82C}, + {0x830, 0x8F4}, + {0x90C, 0x91C}, + {0xA14, 0xA18}, + {0xA84, 0xA94}, + {0xAA8, 0xAD4}, + {0xADC, 0xB40}, + {0x1000, 0x10A4}, + {0x10BC, 0x111C}, + {0x1134, 0x1138}, + {0x1144, 0x114C}, + {0x1150, 0x115C}, + {0x1160, 0x1178}, + {0x1240, 0x1260}, + {0x2000, 0x207C}, + {0x3000, 0x3014}, + {0x4000, 0x4014}, + {0x5000, 0x5124}, + {0x6000, 0x6040}, + {0x6080, 0x60CC}, + {0x6100, 0x611C}, + {0x6140, 0x61D8}, + {0x6200, 0x6238}, + {0x6240, 0x628C}, + {0x62C0, 0x62EC}, + {0x6380, 0x63E8}, + {0x6400, 0x6440}, + {0x6480, 0x64CC}, + {0x6500, 0x651C}, + {0x6540, 0x6580}, + {0x6600, 0x6638}, + {0x6640, 0x668C}, + {0x66C0, 0x66EC}, + {0x6780, 0x67E8}, + {0x7080, 0x708C}, + {0x70C0, 0x70C8}, + {0x7400, 0x741C}, + {0x7440, 0x7454}, + {0x7800, 0x7818}, + {0x8000, 0x8004}, + {0x8010, 0x8064}, + {0x8080, 0x8084}, + {0x80A0, 0x80A4}, + {0x80C0, 0x80C4}, + {0x80E0, 0x80F4}, + {0x8100, 0x8104}, + {0x8110, 0x812C}, + {0x9000, 0x9004}, + {0x9800, 0x982C}, + {0x9830, 0x9838}, + {0x9840, 0x986C}, + {0x9870, 0x9898}, + {0x9A00, 0x9C00}, + {0xD580, 0xD59C}, + {0xF000, 0xF0E0}, + {0xF140, 0xF190}, + {0xF250, 0xF25C}, + {0xF260, 0xF268}, + {0xF26C, 0xF2A8}, + {0x10008, 0x1000C}, + {0x10014, 0x10018}, + {0x1001C, 0x10020}, + {0x10024, 0x10028}, + {0x10030, 0x10034}, + {0x10040, 0x10054}, + {0x10058, 0x1007C}, + {0x10080, 0x100C4}, + {0x100C8, 0x10114}, + {0x1012C, 0x10130}, + {0x10138, 0x10144}, + {0x10200, 0x10220}, + {0x10230, 0x10250}, + {0x10260, 0x10280}, + {0x10290, 0x102B0}, + {0x102C0, 0x102DC}, + {0x102E0, 0x102F4}, + {0x102FC, 0x1037C}, + {0x10380, 0x10390}, + {0x10800, 0x10828}, + {0x10840, 0x10844}, + {0x10880, 0x10884}, + {0x108C0, 0x108E8}, + {0x10900, 0x10928}, + {0x10940, 0x10944}, + {0x10980, 0x10984}, + {0x109C0, 0x109E8}, + {0x10A00, 0x10A28}, + {0x10A40, 0x10A50}, + {0x11000, 0x11028}, + {0x11030, 0x11034}, + {0x11038, 0x11068}, + {0x11070, 0x11074}, + {0x11078, 0x110A8}, + {0x110B0, 0x110B4}, + {0x110B8, 0x110E8}, + {0x110F0, 0x110F4}, + {0x110F8, 0x11128}, + {0x11138, 0x11144}, + {0x11178, 0x11180}, + {0x111B8, 0x111C0}, + {0x111F8, 0x11200}, + {0x11238, 0x1123C}, + {0x11270, 0x11274}, + {0x11278, 0x1127C}, + {0x112B0, 0x112B4}, + {0x112B8, 0x112BC}, + {0x112F0, 0x112F4}, + {0x112F8, 0x112FC}, + {0x11338, 0x1133C}, + {0x11378, 0x1137C}, + {0x113B8, 0x113BC}, + {0x113F8, 0x113FC}, + {0x11438, 0x11440}, + {0x11478, 0x11480}, + {0x114B8, 0x114BC}, + {0x114F8, 0x114FC}, + {0x11538, 0x1153C}, + {0x11578, 0x1157C}, + {0x115B8, 0x115BC}, + {0x115F8, 0x115FC}, + {0x11638, 0x1163C}, + {0x11678, 0x1167C}, + {0x116B8, 0x116BC}, + {0x116F8, 0x116FC}, + {0x11738, 0x1173C}, + {0x11778, 0x1177C}, + {0x117B8, 0x117BC}, + {0x117F8, 0x117FC}, + {0x17000, 0x1701C}, + {0x17020, 0x170AC}, + {0x18000, 0x18050}, + {0x18054, 0x18074}, + {0x18080, 0x180D4}, + {0x180DC, 0x18104}, + {0x18108, 0x1813C}, + {0x18144, 0x18148}, + {0x18168, 0x18174}, + {0x18178, 0x18180}, + {0x181C8, 0x181E0}, + {0x181E4, 0x181E8}, + {0x181EC, 0x1820C}, + {0x1825C, 0x18280}, + {0x18284, 0x18290}, + {0x18294, 0x182A0}, + {0x18300, 0x18304}, + {0x18314, 0x18320}, + {0x18328, 0x18350}, + {0x1835C, 0x1836C}, + {0x18370, 0x18390}, + {0x18398, 0x183AC}, + {0x183BC, 0x183D8}, + {0x183DC, 0x183F4}, + {0x18400, 0x186F4}, + {0x186F8, 0x1871C}, + {0x18720, 0x18790}, + {0x19800, 0x19830}, + {0x19834, 0x19840}, + {0x19880, 0x1989C}, + {0x198A4, 0x198B0}, + {0x198BC, 0x19900}, + {0x19C00, 0x19C88}, + {0x19D00, 0x19D20}, + {0x19E00, 0x19E7C}, + {0x19E80, 0x19E94}, + {0x19E98, 0x19EAC}, + {0x19EB0, 0x19EBC}, + {0x19F70, 0x19F74}, + {0x19F80, 0x19F8C}, + {0x19FA0, 0x19FB4}, + {0x19FC0, 0x19FD8}, + {0x1A000, 0x1A200}, + {0x1A204, 0x1A210}, + {0x1A228, 0x1A22C}, + {0x1A230, 0x1A248}, + {0x1A250, 0x1A270}, + {0x1A280, 0x1A290}, + {0x1A2A0, 0x1A2A4}, + {0x1A2C0, 0x1A2EC}, + {0x1A300, 0x1A3BC}, + {0x1A3F0, 0x1A3F4}, + {0x1A3F8, 0x1A434}, + {0x1A438, 0x1A444}, + {0x1A448, 0x1A468}, + {0x1A580, 0x1A58C}, + {0x1A644, 0x1A654}, + {0x1A670, 0x1A698}, + {0x1A6AC, 0x1A6B0}, + {0x1A6D0, 0x1A6D4}, + {0x1A6EC, 0x1A70C}, + {0x1A710, 0x1A738}, + {0x1A7C0, 0x1A7D0}, + {0x1A7D4, 0x1A7D8}, + {0x1A7DC, 0x1A7E4}, + {0x1A7F0, 0x1A7F8}, + {0x1A888, 0x1A89C}, + {0x1A8A8, 0x1A8AC}, + {0x1A8C0, 0x1A8DC}, + {0x1A8F0, 0x1A8FC}, + {0x1AE04, 0x1AE08}, + {0x1AE18, 0x1AE24}, + {0x1AF80, 0x1AF8C}, + {0x1AFA0, 0x1AFB4}, + {0x1B000, 0x1B200}, + {0x1B284, 0x1B288}, + {0x1B2D0, 0x1B2D8}, + {0x1B2DC, 0x1B2EC}, + {0x1B300, 0x1B340}, + {0x1B374, 0x1B378}, + {0x1B380, 0x1B384}, + {0x1B388, 0x1B38C}, + {0x1B404, 0x1B408}, + {0x1B420, 0x1B428}, + {0x1B440, 0x1B444}, + {0x1B448, 0x1B44C}, + {0x1B450, 0x1B458}, + {0x1B45C, 0x1B468}, + {0x1B584, 0x1B58C}, + {0x1B68C, 0x1B690}, + {0x1B6AC, 0x1B6B0}, + {0x1B7F0, 0x1B7F8}, + {0x1C800, 0x1CC00}, + {0x1CE00, 0x1CE04}, + {0x1CF80, 0x1CF84}, + {0x1D200, 0x1D800}, + {0x1E000, 0x20014}, + {0x20100, 0x20124}, + {0x21400, 0x217A8}, + {0x21800, 0x21BA8}, + {0x21C00, 0x21FA8}, + {0x22000, 0x223A8}, + {0x22400, 0x227A8}, + {0x22800, 0x22BA8}, + {0x22C00, 0x22FA8}, + {0x23000, 0x233A8}, + {0x24000, 0x24034}, + + /* + * EFUSE0,1,2 is disabled here + * because it's state may be reset + * + * {0x24800, 0x24804}, + * {0x25000, 0x25004}, + * {0x25800, 0x25804}, + */ + + {0x26000, 0x26064}, + {0x27000, 0x27024}, + {0x34000, 0x3400C}, + {0x34400, 0x3445C}, + {0x34800, 0x3485C}, + {0x34C00, 0x34C5C}, + {0x35000, 0x3505C}, + {0x35400, 0x3545C}, + {0x35800, 0x3585C}, + {0x35C00, 0x35C5C}, + {0x36000, 0x3605C}, + {0x38000, 0x38064}, + {0x38070, 0x380E0}, + {0x3A000, 0x3A064}, + + /* DBI windows is skipped here, it can be only accessed when pcie + * is active (not in reset) and CORE_CTRL_PCIE_LTSSM_EN = 0 && + * PCIE_CTRL_APP_LTSSM_ENALBE=0. + * {0x3C000 , 0x3C004}, + */ + + {0x40000, 0x400A4}, + + /* + * SI register is skiped here. + * Because it will cause bus hang + * + * {0x50000, 0x50018}, + */ + + {0x80000, 0x8000C}, + {0x80010, 0x80020}, +}; + +static const tgt_reg_section ar6320v3_reg_table[] = { + {0x800, 0x810}, + {0x820, 0x82C}, + {0x830, 0x8F4}, + {0x90C, 0x91C}, + {0xA14, 0xA18}, + {0xA84, 0xA94}, + {0xAA8, 0xAD4}, + {0xADC, 0xB40}, + {0x1000, 0x10A4}, + {0x10BC, 0x111C}, + {0x1134, 0x1138}, + {0x1144, 0x114C}, + {0x1150, 0x115C}, + {0x1160, 0x1178}, + {0x1240, 0x1260}, + {0x2000, 0x207C}, + {0x3000, 0x3014}, + {0x4000, 0x4014}, + {0x5000, 0x5124}, + {0x6000, 0x6040}, + {0x6080, 0x60CC}, + {0x6100, 0x611C}, + {0x6140, 0x61D8}, + {0x6200, 0x6238}, + {0x6240, 0x628C}, + {0x62C0, 0x62EC}, + {0x6380, 0x63E8}, + {0x6400, 0x6440}, + {0x6480, 0x64CC}, + {0x6500, 0x651C}, + {0x6540, 0x6580}, + {0x6600, 0x6638}, + {0x6640, 0x668C}, + {0x66C0, 0x66EC}, + {0x6780, 0x67E8}, + {0x7080, 0x708C}, + {0x70C0, 0x70C8}, + {0x7400, 0x741C}, + {0x7440, 0x7454}, + {0x7800, 0x7818}, + {0x8000, 0x8004}, + {0x8010, 0x8064}, + {0x8080, 0x8084}, + {0x80A0, 0x80A4}, + {0x80C0, 0x80C4}, + {0x80E0, 0x80F4}, + {0x8100, 0x8104}, + {0x8110, 0x812C}, + {0x9000, 0x9004}, + {0x9800, 0x982C}, + {0x9830, 0x9838}, + {0x9840, 0x986C}, + {0x9870, 0x9898}, + {0x9A00, 0x9C00}, + {0xD580, 0xD59C}, + {0xF000, 0xF0E0}, + {0xF140, 0xF190}, + {0xF250, 0xF25C}, + {0xF260, 0xF268}, + {0xF26C, 0xF2A8}, + {0x10008, 0x1000C}, + {0x10014, 0x10018}, + {0x1001C, 0x10020}, + {0x10024, 0x10028}, + {0x10030, 0x10034}, + {0x10040, 0x10054}, + {0x10058, 0x1007C}, + {0x10080, 0x100C4}, + {0x100C8, 0x10114}, + {0x1012C, 0x10130}, + {0x10138, 0x10144}, + {0x10200, 0x10220}, + {0x10230, 0x10250}, + {0x10260, 0x10280}, + {0x10290, 0x102B0}, + {0x102C0, 0x102DC}, + {0x102E0, 0x102F4}, + {0x102FC, 0x1037C}, + {0x10380, 0x10390}, + {0x10800, 0x10828}, + {0x10840, 0x10844}, + {0x10880, 0x10884}, + {0x108C0, 0x108E8}, + {0x10900, 0x10928}, + {0x10940, 0x10944}, + {0x10980, 0x10984}, + {0x109C0, 0x109E8}, + {0x10A00, 0x10A28}, + {0x10A40, 0x10A50}, + {0x11000, 0x11028}, + {0x11030, 0x11034}, + {0x11038, 0x11068}, + {0x11070, 0x11074}, + {0x11078, 0x110A8}, + {0x110B0, 0x110B4}, + {0x110B8, 0x110E8}, + {0x110F0, 0x110F4}, + {0x110F8, 0x11128}, + {0x11138, 0x11144}, + {0x11178, 0x11180}, + {0x111B8, 0x111C0}, + {0x111F8, 0x11200}, + {0x11238, 0x1123C}, + {0x11270, 0x11274}, + {0x11278, 0x1127C}, + {0x112B0, 0x112B4}, + {0x112B8, 0x112BC}, + {0x112F0, 0x112F4}, + {0x112F8, 0x112FC}, + {0x11338, 0x1133C}, + {0x11378, 0x1137C}, + {0x113B8, 0x113BC}, + {0x113F8, 0x113FC}, + {0x11438, 0x11440}, + {0x11478, 0x11480}, + {0x114B8, 0x114BC}, + {0x114F8, 0x114FC}, + {0x11538, 0x1153C}, + {0x11578, 0x1157C}, + {0x115B8, 0x115BC}, + {0x115F8, 0x115FC}, + {0x11638, 0x1163C}, + {0x11678, 0x1167C}, + {0x116B8, 0x116BC}, + {0x116F8, 0x116FC}, + {0x11738, 0x1173C}, + {0x11778, 0x1177C}, + {0x117B8, 0x117BC}, + {0x117F8, 0x117FC}, + {0x17000, 0x1701C}, + {0x17020, 0x170AC}, + {0x18000, 0x18050}, + {0x18054, 0x18074}, + {0x18080, 0x180D4}, + {0x180DC, 0x18104}, + {0x18108, 0x1813C}, + {0x18144, 0x18148}, + {0x18168, 0x18174}, + {0x18178, 0x18180}, + {0x181C8, 0x181E0}, + {0x181E4, 0x181E8}, + {0x181EC, 0x1820C}, + {0x1825C, 0x18280}, + {0x18284, 0x18290}, + {0x18294, 0x182A0}, + {0x18300, 0x18304}, + {0x18314, 0x18320}, + {0x18328, 0x18350}, + {0x1835C, 0x1836C}, + {0x18370, 0x18390}, + {0x18398, 0x183AC}, + {0x183BC, 0x183D8}, + {0x183DC, 0x183F4}, + {0x18400, 0x186F4}, + {0x186F8, 0x1871C}, + {0x18720, 0x18790}, + {0x19800, 0x19830}, + {0x19834, 0x19840}, + {0x19880, 0x1989C}, + {0x198A4, 0x198B0}, + {0x198BC, 0x19900}, + {0x19C00, 0x19C88}, + {0x19D00, 0x19D20}, + {0x19E00, 0x19E7C}, + {0x19E80, 0x19E94}, + {0x19E98, 0x19EAC}, + {0x19EB0, 0x19EBC}, + {0x19F70, 0x19F74}, + {0x19F80, 0x19F8C}, + {0x19FA0, 0x19FB4}, + {0x19FC0, 0x19FD8}, + {0x1A000, 0x1A200}, + {0x1A204, 0x1A210}, + {0x1A228, 0x1A22C}, + {0x1A230, 0x1A248}, + {0x1A250, 0x1A270}, + {0x1A280, 0x1A290}, + {0x1A2A0, 0x1A2A4}, + {0x1A2C0, 0x1A2EC}, + {0x1A300, 0x1A3BC}, + {0x1A3F0, 0x1A3F4}, + {0x1A3F8, 0x1A434}, + {0x1A438, 0x1A444}, + {0x1A448, 0x1A468}, + {0x1A580, 0x1A58C}, + {0x1A644, 0x1A654}, + {0x1A670, 0x1A698}, + {0x1A6AC, 0x1A6B0}, + {0x1A6D0, 0x1A6D4}, + {0x1A6EC, 0x1A70C}, + {0x1A710, 0x1A738}, + {0x1A7C0, 0x1A7D0}, + {0x1A7D4, 0x1A7D8}, + {0x1A7DC, 0x1A7E4}, + {0x1A7F0, 0x1A7F8}, + {0x1A888, 0x1A89C}, + {0x1A8A8, 0x1A8AC}, + {0x1A8C0, 0x1A8DC}, + {0x1A8F0, 0x1A8FC}, + {0x1AE04, 0x1AE08}, + {0x1AE18, 0x1AE24}, + {0x1AF80, 0x1AF8C}, + {0x1AFA0, 0x1AFB4}, + {0x1B000, 0x1B200}, + {0x1B284, 0x1B288}, + {0x1B2D0, 0x1B2D8}, + {0x1B2DC, 0x1B2EC}, + {0x1B300, 0x1B340}, + {0x1B374, 0x1B378}, + {0x1B380, 0x1B384}, + {0x1B388, 0x1B38C}, + {0x1B404, 0x1B408}, + {0x1B420, 0x1B428}, + {0x1B440, 0x1B444}, + {0x1B448, 0x1B44C}, + {0x1B450, 0x1B458}, + {0x1B45C, 0x1B468}, + {0x1B584, 0x1B58C}, + {0x1B68C, 0x1B690}, + {0x1B6AC, 0x1B6B0}, + {0x1B7F0, 0x1B7F8}, + {0x1C800, 0x1CC00}, + {0x1CE00, 0x1CE04}, + {0x1CF80, 0x1CF84}, + {0x1D200, 0x1D800}, + {0x1E000, 0x20014}, + {0x20100, 0x20124}, + {0x21400, 0x217A8}, + {0x21800, 0x21BA8}, + {0x21C00, 0x21FA8}, + {0x22000, 0x223A8}, + {0x22400, 0x227A8}, + {0x22800, 0x22BA8}, + {0x22C00, 0x22FA8}, + {0x23000, 0x233A8}, + {0x24000, 0x24034}, + + /* + * EFUSE0,1,2 is disabled here + * because it's state may be reset + * + * {0x24800, 0x24804}, + * {0x25000, 0x25004}, + * {0x25800, 0x25804}, + */ + + {0x26000, 0x26064}, + {0x27000, 0x27024}, + {0x34000, 0x3400C}, + {0x34400, 0x3445C}, + {0x34800, 0x3485C}, + {0x34C00, 0x34C5C}, + {0x35000, 0x3505C}, + {0x35400, 0x3545C}, + {0x35800, 0x3585C}, + {0x35C00, 0x35C5C}, + {0x36000, 0x3605C}, + {0x38000, 0x38064}, + {0x38070, 0x380E0}, + {0x3A000, 0x3A074}, + + /* + * DBI windows is skipped here, it can be only accessed when pcie + * is active (not in reset) and CORE_CTRL_PCIE_LTSSM_EN = 0 && + * PCIE_CTRL_APP_LTSSM_ENALBE=0. + * {0x3C000 , 0x3C004}, + */ + + {0x40000, 0x400A4}, + + /* + * SI register is skiped here. + * Because it will cause bus hang + * + * {0x50000, 0x50018}, + */ + + {0x80000, 0x8000C}, + {0x80010, 0x80020}, +}; +#endif /* #ifndef _AR6320V2_DBG_REGTABLE_H_ */ diff --git a/drivers/staging/qcacld-3.0/core/bmi/src/i_bmi.h b/drivers/staging/qcacld-3.0/core/bmi/src/i_bmi.h new file mode 100644 index 0000000000000000000000000000000000000000..712bf9e30be553c0603191afae34d3e3fb3f596d --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/bmi/src/i_bmi.h @@ -0,0 +1,199 @@ +/* + * Copyright (c) 2014-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ +/* =================================================================== + * Internal BMI Header File + */ + +#ifndef _I_BMI_H_ +#define _I_BMI_H_ + +#include "hif.h" +#include "bmi_msg.h" +#include "bmi.h" +#include "ol_fw.h" +#include "pld_common.h" + +/* + * Note that not all the register locations are accessible. + * A list of accessible target registers are specified with + * their start and end addresses in a table for given target + * version. We should NOT access other locations as either + * they are invalid locations or host does not have read + * access to it or the value of the particular register + * read might change + */ +#define REGISTER_LOCATION 0x00000800 + +#define DRAM_LOCATION 0x00400000 +#define DRAM_SIZE 0x000a8000 +/* The local base addr is used to read the target dump using pcie I/O reads */ +#define DRAM_LOCAL_BASE_ADDR (0x100000) + +#define IRAM_LOCATION 0x00980000 +#define IRAM_SIZE 0x00038000 + +#define AXI_LOCATION 0x000a0000 +#define AXI_SIZE 0x00018000 + +#define TOTAL_DUMP_SIZE 0x00200000 +#define PCIE_READ_LIMIT 0x00005000 + +#define SHA256_DIGEST_SIZE 32 + +/* BMI LOGGING WRAPPERS */ + +#define BMI_LOG(level, args...) QDF_TRACE(QDF_MODULE_ID_BMI, \ + level, ##args) +#define BMI_ERR(args ...) BMI_LOG(QDF_TRACE_LEVEL_ERROR, args) +#define BMI_DBG(args ...) BMI_LOG(QDF_TRACE_LEVEL_DEBUG, args) +#define BMI_WARN(args ...) BMI_LOG(QDF_TRACE_LEVEL_WARN, args) +#define BMI_INFO(args ...) BMI_LOG(QDF_TRACE_LEVEL_INFO, args) +/* End of BMI Logging Wrappers */ + +/* BMI Assert Wrappers */ +#define bmi_assert QDF_BUG +/* + * Although we had envisioned BMI to run on top of HTC, this is not how the + * final implementation ended up. On the Target side, BMI is a part of the BSP + * and does not use the HTC protocol nor even DMA -- it is intentionally kept + * very simple. + */ + +#define MAX_BMI_CMDBUF_SZ (BMI_DATASZ_MAX + \ + sizeof(uint32_t) /* cmd */ + \ + sizeof(uint32_t) /* addr */ + \ + sizeof(uint32_t)) /* length */ +#define BMI_COMMAND_FITS(sz) ((sz) <= MAX_BMI_CMDBUF_SZ) +#define BMI_EXCHANGE_TIMEOUT_MS 1000 + +struct hash_fw { + u8 qwlan[SHA256_DIGEST_SIZE]; + u8 otp[SHA256_DIGEST_SIZE]; + u8 bdwlan[SHA256_DIGEST_SIZE]; + u8 utf[SHA256_DIGEST_SIZE]; +}; + +typedef enum _ATH_BIN_FILE { + ATH_OTP_FILE, + ATH_FIRMWARE_FILE, + ATH_PATCH_FILE, + ATH_BOARD_DATA_FILE, + ATH_FLASH_FILE, + ATH_SETUP_FILE, +} ATH_BIN_FILE; + +#if defined(QCA_WIFI_3_0_ADRASTEA) +#define NO_BMI 1 +#else +#define NO_BMI 0 +#endif + +/** + * struct bmi_info - Structure to hold BMI Specific information + * @bmi_cmd_buff - BMI Command Buffer + * @bmi_rsp_buff - BMI Response Buffer + * @bmi_cmd_da - BMI Command Physical address + * @bmi_rsp_da - BMI Response Physical address + * @bmi_done - Flag to check if BMI Phase is complete + * @fw_files - FW files + * + */ +struct bmi_info { + uint8_t *bmi_cmd_buff; + uint8_t *bmi_rsp_buff; + dma_addr_t bmi_cmd_da; + dma_addr_t bmi_rsp_da; + bool bmi_done; + struct pld_fw_files fw_files; +}; + +/** + * struct ol_context - Structure to hold OL context + * @bmi: BMI info + * @cal_in_flash: For Firmware Flash Download + * @qdf_dev: QDF Device + * @scn: HIF Context + * @ramdump_work: Work for Ramdump collection + * @fw_indication_work: Work for Fw inciation + * @tgt_def: Target Defnition pointer + * + * Structure to hold all ol BMI/Ramdump info + */ +struct ol_context { + struct bmi_info bmi; + struct ol_config_info cfg_info; + uint8_t *cal_in_flash; + qdf_device_t qdf_dev; + qdf_work_t ramdump_work; + qdf_work_t fw_indication_work; + struct hif_opaque_softc *scn; + struct targetdef_t { + struct targetdef_s *targetdef; + } tgt_def; +}; + +#define GET_BMI_CONTEXT(ol_ctx) ((struct bmi_info *)ol_ctx) + +QDF_STATUS bmi_execute(uint32_t address, uint32_t *param, + struct ol_context *ol_ctx); +QDF_STATUS bmi_init(struct ol_context *ol_ctx); +QDF_STATUS bmi_no_command(struct ol_context *ol_ctx); +QDF_STATUS bmi_read_memory(uint32_t address, uint8_t *buffer, uint32_t length, + struct ol_context *ol_ctx); +QDF_STATUS bmi_write_memory(uint32_t address, uint8_t *buffer, uint32_t length, + struct ol_context *ol_ctx); +QDF_STATUS bmi_fast_download(uint32_t address, uint8_t *buffer, uint32_t length, + struct ol_context *ol_ctx); +QDF_STATUS bmi_read_soc_register(uint32_t address, + uint32_t *param, struct ol_context *ol_ctx); +QDF_STATUS bmi_write_soc_register(uint32_t address, uint32_t param, + struct ol_context *ol_ctx); +QDF_STATUS bmi_get_target_info(struct bmi_target_info *targ_info, + struct ol_context *ol_ctx); +QDF_STATUS bmi_firmware_download(struct ol_context *ol_ctx); +QDF_STATUS bmi_done_local(struct ol_context *ol_ctx); +QDF_STATUS ol_download_firmware(struct ol_context *ol_ctx); +QDF_STATUS ol_configure_target(struct ol_context *ol_ctx); +QDF_STATUS bmi_sign_stream_start(uint32_t address, uint8_t *buffer, + uint32_t length, struct ol_context *ol_ctx); +void ramdump_work_handler(void *arg); +void fw_indication_work_handler(void *arg); +struct ol_config_info *ol_get_ini_handle(struct ol_context *ol_ctx); + +#ifdef HIF_SDIO +QDF_STATUS hif_reg_based_get_target_info(struct hif_opaque_softc *hif_ctx, + struct bmi_target_info *targ_info); +#endif +#if defined(HIF_PCI) || defined(SNOC) || defined(HIF_AHB) || defined(HIF_USB) +static inline QDF_STATUS +hif_reg_based_get_target_info(struct hif_opaque_softc *hif_ctx, + struct bmi_target_info *targ_info) +{ + return QDF_STATUS_SUCCESS; +} +#endif +#endif diff --git a/drivers/staging/qcacld-3.0/core/bmi/src/ol_fw.c b/drivers/staging/qcacld-3.0/core/bmi/src/ol_fw.c new file mode 100644 index 0000000000000000000000000000000000000000..4d21f8f994a8bf08c025a32cfae4e23f99e30d91 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/bmi/src/ol_fw.c @@ -0,0 +1,1706 @@ +/* + * Copyright (c) 2014-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#include +#include "ol_if_athvar.h" +#include "targaddrs.h" +#include "ol_cfg.h" +#include "cds_api.h" +#include "wma_api.h" +#include "wma.h" +#include "bin_sig.h" +#include "i_ar6320v2_regtable.h" +#include "epping_main.h" +#ifdef HIF_PCI +#include "ce_reg.h" +#endif +#if defined(HIF_SDIO) +#include "if_sdio.h" +#include "regtable_sdio.h" +#endif +#if defined(HIF_USB) +#include "if_usb.h" +#include "regtable_usb.h" +#endif +#include "pld_common.h" +#include "hif_main.h" + +#include "i_bmi.h" +#include "qwlan_version.h" +#include "cds_concurrency.h" +#include "dbglog_host.h" + +#ifdef FEATURE_SECURE_FIRMWARE +static struct hash_fw fw_hash; +#endif + +static uint32_t refclk_speed_to_hz[] = { + 48000000, /* SOC_REFCLK_48_MHZ */ + 19200000, /* SOC_REFCLK_19_2_MHZ */ + 24000000, /* SOC_REFCLK_24_MHZ */ + 26000000, /* SOC_REFCLK_26_MHZ */ + 37400000, /* SOC_REFCLK_37_4_MHZ */ + 38400000, /* SOC_REFCLK_38_4_MHZ */ + 40000000, /* SOC_REFCLK_40_MHZ */ + 52000000, /* SOC_REFCLK_52_MHZ */ +}; + +static int ol_target_coredump(void *inst, void *memory_block, + uint32_t block_len); + +#ifdef FEATURE_SECURE_FIRMWARE +static int ol_check_fw_hash(struct device *dev, + const u8 *data, u32 fw_size, ATH_BIN_FILE file) +{ + u8 *hash = NULL; + u8 *fw_mem = NULL; + u8 digest[SHA256_DIGEST_SIZE]; + u8 temp[SHA256_DIGEST_SIZE] = { }; + int ret = 0; + + switch (file) { + case ATH_BOARD_DATA_FILE: + hash = fw_hash.bdwlan; + break; + case ATH_OTP_FILE: + hash = fw_hash.otp; + break; + case ATH_FIRMWARE_FILE: +#ifdef QCA_WIFI_FTM + if (cds_get_conparam() == QDF_GLOBAL_FTM_MODE) { + hash = fw_hash.utf; + break; + } +#endif + hash = fw_hash.qwlan; + default: + break; + } + + if (!hash) { + BMI_INFO("No entry for file:%d Download FW in non-secure mode", + file); + goto end; + } + + if (qdf_mem_cmp(hash, temp, SHA256_DIGEST_SIZE)) { + BMI_INFO("Download FW in non-secure mode:%d", file); + goto end; + } + + fw_mem = pld_get_fw_ptr(dev); + if (!fw_mem || (fw_size > MAX_FIRMWARE_SIZE)) { + BMI_ERR("No Memory to copy FW data"); + ret = -1; + goto end; + } + qdf_mem_copy(fw_mem, data, fw_size); + + ret = pld_get_sha_hash(dev, fw_mem, fw_size, "sha256", digest); + + if (ret) { + BMI_ERR("Sha256 Hash computation failed err:%d", ret); + goto end; + } + + if (qdf_mem_cmp(hash, digest, SHA256_DIGEST_SIZE)) { + BMI_ERR("Hash Mismatch"); + qdf_trace_hex_dump(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_FATAL, + digest, SHA256_DIGEST_SIZE); + qdf_trace_hex_dump(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_FATAL, + hash, SHA256_DIGEST_SIZE); + ret = QDF_STATUS_E_FAILURE; + } +end: + return ret; +} +#endif + +#ifdef QCA_SIGNED_SPLIT_BINARY_SUPPORT +#define SIGNED_SPLIT_BINARY_VALUE true +#else +#define SIGNED_SPLIT_BINARY_VALUE false +#endif + +static int +__ol_transfer_bin_file(struct ol_context *ol_ctx, ATH_BIN_FILE file, + uint32_t address, bool compressed) +{ + struct hif_opaque_softc *scn = ol_ctx->scn; + int status = EOK; + const char *filename = NULL; + const struct firmware *fw_entry; + uint32_t fw_entry_size; + uint8_t *temp_eeprom; + uint32_t board_data_size; + bool bin_sign = false; + int bin_off, bin_len; + SIGN_HEADER_T *sign_header; + struct hif_target_info *tgt_info = hif_get_target_info_handle(scn); + uint32_t target_type = tgt_info->target_type; + struct bmi_info *bmi_ctx = GET_BMI_CONTEXT(ol_ctx); + qdf_device_t qdf_dev = ol_ctx->qdf_dev; + int ret = 0; + + switch (file) { + default: + BMI_ERR("%s: Unknown file type", __func__); + ret = -1; + return ret; + case ATH_OTP_FILE: + filename = bmi_ctx->fw_files.otp_data; + if (SIGNED_SPLIT_BINARY_VALUE) + bin_sign = true; + + break; + case ATH_FIRMWARE_FILE: + if (QDF_IS_EPPING_ENABLED(cds_get_conparam())) { + filename = bmi_ctx->fw_files.epping_file; + BMI_INFO("%s: Loading epping firmware file %s", + __func__, filename); + break; + } +#ifdef QCA_WIFI_FTM + if (cds_get_conparam() == QDF_GLOBAL_FTM_MODE) { + filename = bmi_ctx->fw_files.utf_file; + if (SIGNED_SPLIT_BINARY_VALUE) + bin_sign = true; + BMI_INFO("%s: Loading firmware file %s", + __func__, filename); + break; + } +#endif + if (cds_get_conparam() == QDF_GLOBAL_IBSS_MODE && + (bmi_ctx->fw_files.ibss_image_file[0] != '\0')) { + filename = bmi_ctx->fw_files.ibss_image_file; + } else { + filename = bmi_ctx->fw_files.image_file; + } + + if (SIGNED_SPLIT_BINARY_VALUE) + bin_sign = true; + break; + case ATH_PATCH_FILE: + BMI_INFO("%s: no Patch file defined", __func__); + return 0; + case ATH_BOARD_DATA_FILE: +#ifdef QCA_WIFI_FTM + if (cds_get_conparam() == QDF_GLOBAL_FTM_MODE) { + filename = bmi_ctx->fw_files.utf_board_data; + if (SIGNED_SPLIT_BINARY_VALUE) + bin_sign = true; + + BMI_INFO("%s: Loading board data file %s", + __func__, filename); + break; + } +#endif /* QCA_WIFI_FTM */ + filename = bmi_ctx->fw_files.board_data; + if (SIGNED_SPLIT_BINARY_VALUE) + bin_sign = false; + + break; + case ATH_SETUP_FILE: + if (cds_get_conparam() != QDF_GLOBAL_FTM_MODE && + !QDF_IS_EPPING_ENABLED(cds_get_conparam())) { + filename = bmi_ctx->fw_files.setup_file; + if (filename[0] == 0) { + BMI_INFO("%s: no Setup file defined", __func__); + ret = -1; + return ret; + } + + if (SIGNED_SPLIT_BINARY_VALUE) + bin_sign = true; + + BMI_INFO("%s: Loading setup file %s", + __func__, filename); + } else { + BMI_INFO("%s: no Setup file needed", __func__); + ret = -1; + return ret; + } + break; + } + + if (request_firmware(&fw_entry, filename, qdf_dev->dev) != 0) { + BMI_ERR("%s: Failed to get %s", __func__, filename); + + if (file == ATH_OTP_FILE) + return -ENOENT; + +#if defined(QCA_WIFI_FTM) + /* Try default board data file if FTM specific + * board data file is not present. */ + if (filename == bmi_ctx->fw_files.utf_board_data) { + filename = bmi_ctx->fw_files.board_data; + BMI_INFO("%s: Trying to load default %s", + __func__, filename); + if (request_firmware(&fw_entry, filename, + qdf_dev->dev) != 0) { + BMI_ERR("%s: Failed to get %s", + __func__, filename); + ret = -1; + return ret; + } + } else { + ret = -1; + return ret; + } +#else + ret = -1; + return ret; +#endif + } + + if (!fw_entry || !fw_entry->data) { + BMI_ERR("Invalid fw_entries"); + return QDF_STATUS_E_FAILURE; + } + + fw_entry_size = fw_entry->size; + temp_eeprom = NULL; + +#ifdef FEATURE_SECURE_FIRMWARE + + if (ol_check_fw_hash(qdf_dev->dev, fw_entry->data, fw_entry_size, file)) { + BMI_ERR("Hash Check failed for file:%s", filename); + status = QDF_STATUS_E_FAILURE; + goto end; + } +#endif + + if (file == ATH_BOARD_DATA_FILE) { + uint32_t board_ext_address = 0; + int32_t board_ext_data_size; + + temp_eeprom = qdf_mem_malloc(fw_entry_size); + if (!temp_eeprom) { + BMI_ERR("%s: Memory allocation failed", __func__); + release_firmware(fw_entry); + return QDF_STATUS_E_NOMEM; + } + + qdf_mem_copy(temp_eeprom, (uint8_t *) fw_entry->data, + fw_entry_size); + + switch (target_type) { + case TARGET_TYPE_AR6004: + board_data_size = AR6004_BOARD_DATA_SZ; + board_ext_data_size = AR6004_BOARD_EXT_DATA_SZ; + break; + case TARGET_TYPE_AR9888: + board_data_size = AR9888_BOARD_DATA_SZ; + board_ext_data_size = AR9888_BOARD_EXT_DATA_SZ; + break; + default: + board_data_size = 0; + board_ext_data_size = 0; + break; + } + + /* Determine where in Target RAM to write Board Data */ + bmi_read_memory(HOST_INTEREST_ITEM_ADDRESS(target_type, + hi_board_ext_data), + (uint8_t *) &board_ext_address, 4, ol_ctx); + BMI_INFO("Board extended Data download address: 0x%x", + board_ext_address); + + /* Check whether the target has allocated memory for extended + * board data and file contains extended board data + */ + + if ((board_ext_address) + && (fw_entry_size == + (board_data_size + board_ext_data_size))) { + uint32_t param; + + status = bmi_write_memory(board_ext_address, + (uint8_t *)(temp_eeprom + + board_data_size), + board_ext_data_size, ol_ctx); + + if (status != EOK) + goto end; + + /* Record extended board Data initialized */ + param = (board_ext_data_size << 16) | 1; + bmi_write_memory( + HOST_INTEREST_ITEM_ADDRESS(target_type, + hi_board_ext_data_config), + (uint8_t *)¶m, 4, ol_ctx); + + fw_entry_size = board_data_size; + } + } + + if (bin_sign && SIGNED_SPLIT_BINARY_VALUE) { + uint32_t chip_id; + + if (fw_entry_size < sizeof(SIGN_HEADER_T)) { + BMI_ERR("Invalid binary size %d", fw_entry_size); + status = QDF_STATUS_E_FAILURE; + goto end; + } + + sign_header = (SIGN_HEADER_T *) fw_entry->data; + chip_id = cpu_to_le32(sign_header->product_id); + if (sign_header->magic_num == SIGN_HEADER_MAGIC + && (chip_id == AR6320_REV1_1_VERSION + || chip_id == AR6320_REV1_3_VERSION + || chip_id == AR6320_REV2_1_VERSION)) { + + status = bmi_sign_stream_start(address, + (uint8_t *)fw_entry->data, + sizeof(SIGN_HEADER_T), ol_ctx); + if (status != EOK) { + BMI_ERR("unable to start sign stream"); + status = QDF_STATUS_E_FAILURE; + goto end; + } + + bin_off = sizeof(SIGN_HEADER_T); + bin_len = sign_header->rampatch_len + - sizeof(SIGN_HEADER_T); + } else { + bin_sign = false; + bin_off = 0; + bin_len = fw_entry_size; + } + } else { + bin_len = fw_entry_size; + bin_off = 0; + } + + if (compressed) { + status = bmi_fast_download(address, + (uint8_t *) fw_entry->data + bin_off, + bin_len, ol_ctx); + } else { + if (file == ATH_BOARD_DATA_FILE && fw_entry->data) { + status = bmi_write_memory(address, + (uint8_t *) temp_eeprom, + fw_entry_size, ol_ctx); + } else { + status = bmi_write_memory(address, + (uint8_t *) fw_entry->data + + bin_off, bin_len, ol_ctx); + } + } + + if (bin_sign && SIGNED_SPLIT_BINARY_VALUE) { + bin_off += bin_len; + bin_len = sign_header->total_len - sign_header->rampatch_len; + + if (bin_len > 0) { + status = bmi_sign_stream_start(0, + (uint8_t *)fw_entry->data + + bin_off, bin_len, ol_ctx); + if (status != EOK) + BMI_ERR("sign stream error"); + } + } + +end: + if (temp_eeprom) + qdf_mem_free(temp_eeprom); + + if (status != EOK) { + BMI_ERR("%s, BMI operation failed: %d", __func__, __LINE__); + release_firmware(fw_entry); + return QDF_STATUS_E_FAILURE; + } + + release_firmware(fw_entry); + + BMI_INFO("transferring file: %s size %d bytes done!", + (filename != NULL) ? filename : " ", fw_entry_size); + + return status; +} + +static int +ol_transfer_bin_file(struct ol_context *ol_ctx, ATH_BIN_FILE file, + uint32_t address, bool compressed) +{ + int ret; + qdf_device_t qdf_dev = ol_ctx->qdf_dev; + + /* Wait until suspend and resume are completed before loading FW */ + pld_lock_pm_sem(qdf_dev->dev); + + ret = __ol_transfer_bin_file(ol_ctx, file, address, compressed); + + pld_release_pm_sem(qdf_dev->dev); + + return ret; +} + +/** + * struct ramdump_info: Structure to hold ramdump information + * @base: Base address for Ramdump collection + * @size: Size of the dump + * + * Ramdump information. + */ +struct ramdump_info { + void *base; + unsigned long size; +}; + +#if !defined(QCA_WIFI_3_0) +static inline void ol_get_ramdump_mem(struct device *dev, + struct ramdump_info *info) +{ + info->base = pld_get_virt_ramdump_mem(dev, &info->size); +} +#else +static inline void ol_get_ramdump_mem(struct device *dev, + struct ramdump_info *info) { } +#endif + +int ol_copy_ramdump(struct hif_opaque_softc *scn) +{ + int ret = -1; + struct ramdump_info *info; + qdf_device_t qdf_dev = cds_get_context(QDF_MODULE_ID_QDF_DEVICE); + + if (!qdf_dev) { + BMI_ERR("%s qdf_dev is NULL", __func__); + return -EINVAL; + } + + if (hif_get_bus_type(scn) == QDF_BUS_TYPE_SDIO) + return 0; + + info = qdf_mem_malloc(sizeof(struct ramdump_info)); + if (!info) { + BMI_ERR("%s Memory for Ramdump Allocation failed", __func__); + return -ENOMEM; + } + + ol_get_ramdump_mem(qdf_dev->dev, info); + + if (!info->base || !info->size) { + BMI_ERR("%s:ramdump collection fail", __func__); + return -EACCES; + } + + ret = ol_target_coredump(scn, info->base, info->size); + + qdf_mem_free(info); + return ret; +} + +void ramdump_work_handler(void *data) +{ + int ret; + uint32_t host_interest_address; + uint32_t dram_dump_values[4]; + uint32_t target_type; + struct hif_target_info *tgt_info; + struct ol_context *ol_ctx = data; + struct hif_opaque_softc *ramdump_scn = ol_ctx->scn; + qdf_device_t qdf_dev = ol_ctx->qdf_dev; + struct ol_config_info *ini_cfg = ol_get_ini_handle(ol_ctx); + + if (!ramdump_scn) { + BMI_ERR("%s:Ramdump_scn is null:", __func__); + goto out_fail; + } + tgt_info = hif_get_target_info_handle(ramdump_scn); + target_type = tgt_info->target_type; +#ifdef WLAN_DEBUG + ret = hif_check_soc_status(ramdump_scn); + if (ret) + goto out_fail; + + ret = hif_dump_registers(ramdump_scn); + if (ret) + goto out_fail; + +#endif + + if (hif_diag_read_mem(ramdump_scn, + hif_hia_item_address(target_type, + offsetof(struct host_interest_s, hi_failure_state)), + (uint8_t *)&host_interest_address, + sizeof(uint32_t)) != QDF_STATUS_SUCCESS) { + BMI_ERR("HifDiagReadiMem FW Dump Area Pointer failed!"); + ol_copy_ramdump(ramdump_scn); + pld_device_crashed(qdf_dev->dev); + + return; + } + + BMI_ERR("Host interest item address: 0x%08x", host_interest_address); + + if (hif_diag_read_mem(ramdump_scn, host_interest_address, + (uint8_t *) &dram_dump_values[0], + 4 * sizeof(uint32_t)) != QDF_STATUS_SUCCESS) { + BMI_ERR("HifDiagReadiMem FW Dump Area failed!"); + goto out_fail; + } + BMI_ERR("FW Assertion at PC: 0x%08x BadVA: 0x%08x TargetID: 0x%08x", + dram_dump_values[2], dram_dump_values[3], dram_dump_values[0]); + + if (ol_copy_ramdump(ramdump_scn)) + goto out_fail; + + BMI_ERR("%s: RAM dump collecting completed!", __func__); + + /* notify SSR framework the target has crashed. */ + pld_device_crashed(qdf_dev->dev); + return; + +out_fail: + /* Silent SSR on dump failure */ + if (ini_cfg->enable_self_recovery) + pld_device_self_recovery(qdf_dev->dev); + else + pld_device_crashed(qdf_dev->dev); + return; +} + +void fw_indication_work_handler(void *data) +{ + struct ol_context *ol_ctx = data; + qdf_device_t qdf_dev = ol_ctx->qdf_dev; + + pld_device_self_recovery(qdf_dev->dev); +} + +void ol_target_failure(void *instance, QDF_STATUS status) +{ + struct ol_context *ol_ctx = instance; + struct hif_opaque_softc *scn = ol_ctx->scn; + tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA); + struct ol_config_info *ini_cfg = ol_get_ini_handle(ol_ctx); + qdf_device_t qdf_dev = ol_ctx->qdf_dev; + int ret; + enum hif_target_status target_status = hif_get_target_status(scn); + + if (hif_get_bus_type(scn) == QDF_BUS_TYPE_SNOC) { + BMI_ERR("SNOC doesn't suppor this code path!"); + return; + } + + qdf_event_set(&wma->recovery_event); + + if (TARGET_STATUS_RESET == target_status) { + BMI_ERR("Target is already asserted, ignore!"); + return; + } + + hif_set_target_status(scn, TARGET_STATUS_RESET); + + if (hif_get_bus_type(scn) == QDF_BUS_TYPE_USB) { + if (status == QDF_STATUS_E_USB_ERROR) + hif_ramdump_handler(scn); + return; + } + + if (cds_is_driver_recovering()) { + BMI_ERR("%s: Recovery in progress, ignore!\n", __func__); + return; + } + + if (cds_is_load_or_unload_in_progress()) { + BMI_ERR("%s: Loading/Unloading is in progress, ignore!", + __func__); + return; + } + cds_set_recovery_in_progress(true); + + ret = hif_check_fw_reg(scn); + if (0 == ret) { + if (ini_cfg->enable_self_recovery) { + qdf_sched_work(0, &ol_ctx->fw_indication_work); + return; + } + } else if (-1 == ret) { + return; + } + + BMI_ERR("XXX TARGET ASSERTED XXX"); + + cds_svc_fw_shutdown_ind(qdf_dev->dev); + /* Collect the RAM dump through a workqueue */ + if (ini_cfg->enable_ramdump_collection) + qdf_sched_work(0, &ol_ctx->ramdump_work); + else + pr_debug("%s: athdiag read for target reg\n", __func__); + + return; +} + +#ifdef CONFIG_DISABLE_CDC_MAX_PERF_WAR +static QDF_STATUS ol_disable_cdc_max_perf(struct ol_context *ol_ctx) +{ + uint32_t param; + struct hif_opaque_softc *scn = ol_ctx->scn; + struct hif_target_info *tgt_info = hif_get_target_info_handle(scn); + uint32_t target_type = tgt_info->target_type; + + /* set the firmware to disable CDC max perf WAR */ + if (bmi_read_memory(hif_hia_item_address(target_type, + offsetof(struct host_interest_s, hi_option_flag2)), + (uint8_t *) ¶m, 4, ol_ctx) != QDF_STATUS_SUCCESS) { + BMI_ERR("BMI READ for setting cdc max perf failed"); + return QDF_STATUS_E_FAILURE; + } + + param |= HI_OPTION_DISABLE_CDC_MAX_PERF_WAR; + if (bmi_write_memory( + hif_hia_item_address(target_type, + offsetof(struct host_interest_s, hi_option_flag2)), + (uint8_t *)¶m, 4, ol_ctx) != QDF_STATUS_SUCCESS) { + BMI_ERR("setting cdc max perf failed"); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +#else +static QDF_STATUS ol_disable_cdc_max_perf(struct ol_context *ol_ctx) +{ + return QDF_STATUS_SUCCESS; +} + +#endif + +#ifdef WLAN_FEATURE_LPSS +static QDF_STATUS ol_set_lpass_support(struct ol_context *ol_ctx) +{ + uint32_t param; + struct hif_opaque_softc *scn = ol_ctx->scn; + struct hif_target_info *tgt_info = hif_get_target_info_handle(scn); + struct ol_config_info *ini_cfg = ol_get_ini_handle(ol_ctx); + uint32_t target_type = tgt_info->target_type; + + if (ini_cfg->enable_lpass_support) { + if (bmi_read_memory(hif_hia_item_address(target_type, + offsetof(struct host_interest_s, hi_option_flag2)), + (uint8_t *) ¶m, 4, ol_ctx) != QDF_STATUS_SUCCESS) { + BMI_ERR("BMI READ:Setting LPASS Support failed"); + return QDF_STATUS_E_FAILURE; + } + + param |= HI_OPTION_DBUART_SUPPORT; + if (bmi_write_memory( + hif_hia_item_address(target_type, + offsetof(struct host_interest_s, hi_option_flag2)), + (uint8_t *)¶m, 4, ol_ctx) != QDF_STATUS_SUCCESS) { + BMI_ERR("BMI_READ for setting LPASS Support fail"); + return QDF_STATUS_E_FAILURE; + } + } + + return QDF_STATUS_SUCCESS; +} + +#else +static QDF_STATUS ol_set_lpass_support(struct ol_context *ol_ctx) +{ + return QDF_STATUS_SUCCESS; +} + +#endif + + +QDF_STATUS ol_configure_target(struct ol_context *ol_ctx) +{ + uint32_t param; + struct pld_platform_cap cap; + int ret; + struct hif_opaque_softc *scn = ol_ctx->scn; + struct hif_target_info *tgt_info = hif_get_target_info_handle(scn); + uint32_t target_type = tgt_info->target_type; + qdf_device_t qdf_dev = ol_ctx->qdf_dev; + + /* Tell target which HTC version it is used */ + param = HTC_PROTOCOL_VERSION; + if (bmi_write_memory( + hif_hia_item_address(target_type, + offsetof(struct host_interest_s, hi_app_host_interest)), + (uint8_t *) ¶m, 4, ol_ctx) != QDF_STATUS_SUCCESS) { + BMI_ERR("bmi_write_memory for htc version failed"); + return QDF_STATUS_E_FAILURE; + } + + /* set the firmware mode to STA/IBSS/AP */ + { + if (bmi_read_memory(hif_hia_item_address(target_type, + offsetof(struct host_interest_s, hi_option_flag)), + (uint8_t *)¶m, 4, ol_ctx) != QDF_STATUS_SUCCESS) { + BMI_ERR("bmi_read_memory for setting fwmode failed"); + return QDF_STATUS_E_FAILURE; + } + + /* TODO following parameters need to be re-visited. */ + param |= (1 << HI_OPTION_NUM_DEV_SHIFT); /* num_device */ + /* Firmware mode ?? */ + param |= (HI_OPTION_FW_MODE_AP << HI_OPTION_FW_MODE_SHIFT); + /* mac_addr_method */ + param |= (1 << HI_OPTION_MAC_ADDR_METHOD_SHIFT); + /* firmware_bridge */ + param |= (0 << HI_OPTION_FW_BRIDGE_SHIFT); + /* fwsubmode */ + param |= (0 << HI_OPTION_FW_SUBMODE_SHIFT); + + BMI_INFO("NUM_DEV=%d FWMODE=0x%x FWSUBMODE=0x%x FWBR_BUF %d", + 1, HI_OPTION_FW_MODE_AP, 0, 0); + + if (bmi_write_memory( + hif_hia_item_address(target_type, + offsetof(struct host_interest_s, hi_option_flag)), + (uint8_t *)¶m, 4, ol_ctx) != QDF_STATUS_SUCCESS) { + BMI_ERR("BMI WRITE for setting fwmode failed"); + return QDF_STATUS_E_FAILURE; + } + } + if (hif_get_bus_type(scn) == QDF_BUS_TYPE_PCI) { + if (ol_disable_cdc_max_perf(ol_ctx)) + return QDF_STATUS_E_FAILURE; + + ret = pld_get_platform_cap(qdf_dev->dev, &cap); + if (ret) + BMI_ERR("platform capability info not available"); + + if (!ret && cap.cap_flag & PLD_HAS_EXTERNAL_SWREG) { + if (bmi_read_memory(hif_hia_item_address(target_type, + offsetof(struct host_interest_s, + hi_option_flag2)), + (uint8_t *)¶m, 4, ol_ctx) != + QDF_STATUS_SUCCESS) { + BMI_ERR("bmi_read_memory for setting external SWREG failed"); + return QDF_STATUS_E_FAILURE; + } + + param |= HI_OPTION_USE_EXT_LDO; + if (bmi_write_memory( + hif_hia_item_address(target_type, + offsetof(struct host_interest_s, + hi_option_flag2)), + (uint8_t *)¶m, 4, ol_ctx) != + QDF_STATUS_SUCCESS) { + BMI_ERR("BMI WRITE for setting external SWREG fail"); + return QDF_STATUS_E_FAILURE; + } + } + + if (ol_set_lpass_support(ol_ctx)) + return QDF_STATUS_E_FAILURE; + } + + /* If host is running on a BE CPU, set the host interest area */ + { +#ifdef BIG_ENDIAN_HOST + param = 1; +#else + param = 0; +#endif + if (bmi_write_memory( + hif_hia_item_address(target_type, + offsetof(struct host_interest_s, hi_be)), + (uint8_t *) ¶m, 4, ol_ctx) != QDF_STATUS_SUCCESS) { + BMI_ERR("setting host CPU BE mode failed"); + return QDF_STATUS_E_FAILURE; + } + } + + /* FW descriptor/Data swap flags */ + param = 0; + if (bmi_write_memory( + hif_hia_item_address(target_type, + offsetof(struct host_interest_s, hi_fw_swap)), + (uint8_t *) ¶m, 4, ol_ctx) != QDF_STATUS_SUCCESS) { + BMI_ERR("BMI WRITE failed setting FW data/desc swap flags"); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +static int +ol_check_dataset_patch(struct hif_opaque_softc *scn, uint32_t *address) +{ + /* Check if patch file needed for this target type/version. */ + return 0; +} + + +static QDF_STATUS ol_fw_populate_clk_settings(A_refclk_speed_t refclk, + struct cmnos_clock_s *clock_s) +{ + if (!clock_s) + return QDF_STATUS_E_FAILURE; + + switch (refclk) { + case SOC_REFCLK_48_MHZ: + clock_s->wlan_pll.div = 0xE; + clock_s->wlan_pll.rnfrac = 0x2AAA8; + clock_s->pll_settling_time = 2400; + break; + case SOC_REFCLK_19_2_MHZ: + clock_s->wlan_pll.div = 0x24; + clock_s->wlan_pll.rnfrac = 0x2AAA8; + clock_s->pll_settling_time = 960; + break; + case SOC_REFCLK_24_MHZ: + clock_s->wlan_pll.div = 0x1D; + clock_s->wlan_pll.rnfrac = 0x15551; + clock_s->pll_settling_time = 1200; + break; + case SOC_REFCLK_26_MHZ: + clock_s->wlan_pll.div = 0x1B; + clock_s->wlan_pll.rnfrac = 0x4EC4; + clock_s->pll_settling_time = 1300; + break; + case SOC_REFCLK_37_4_MHZ: + clock_s->wlan_pll.div = 0x12; + clock_s->wlan_pll.rnfrac = 0x34B49; + clock_s->pll_settling_time = 1870; + break; + case SOC_REFCLK_38_4_MHZ: + clock_s->wlan_pll.div = 0x12; + clock_s->wlan_pll.rnfrac = 0x15551; + clock_s->pll_settling_time = 1920; + break; + case SOC_REFCLK_40_MHZ: + clock_s->wlan_pll.div = 0x11; + clock_s->wlan_pll.rnfrac = 0x26665; + clock_s->pll_settling_time = 2000; + break; + case SOC_REFCLK_52_MHZ: + clock_s->wlan_pll.div = 0x1B; + clock_s->wlan_pll.rnfrac = 0x4EC4; + clock_s->pll_settling_time = 2600; + break; + case SOC_REFCLK_UNKNOWN: + clock_s->wlan_pll.refdiv = 0; + clock_s->wlan_pll.div = 0; + clock_s->wlan_pll.rnfrac = 0; + clock_s->wlan_pll.outdiv = 0; + clock_s->pll_settling_time = 1024; + clock_s->refclk_hz = 0; + default: + return QDF_STATUS_E_FAILURE; + } + + clock_s->refclk_hz = refclk_speed_to_hz[refclk]; + clock_s->wlan_pll.refdiv = 0; + clock_s->wlan_pll.outdiv = 1; + + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS ol_patch_pll_switch(struct ol_context *ol_ctx) +{ + struct hif_opaque_softc *hif = ol_ctx->scn; + QDF_STATUS status = QDF_STATUS_SUCCESS; + uint32_t addr = 0; + uint32_t reg_val = 0; + uint32_t mem_val = 0; + struct cmnos_clock_s clock_s; + uint32_t cmnos_core_clk_div_addr = 0; + uint32_t cmnos_cpu_pll_init_done_addr = 0; + uint32_t cmnos_cpu_speed_addr = 0; + struct hif_target_info *tgt_info = hif_get_target_info_handle(hif); + uint32_t target_version = tgt_info->target_version; + struct targetdef_t *scn = &ol_ctx->tgt_def; + + switch (target_version) { + case AR6320_REV1_1_VERSION: + cmnos_core_clk_div_addr = AR6320_CORE_CLK_DIV_ADDR; + cmnos_cpu_pll_init_done_addr = AR6320_CPU_PLL_INIT_DONE_ADDR; + cmnos_cpu_speed_addr = AR6320_CPU_SPEED_ADDR; + break; + case AR6320_REV1_3_VERSION: + case AR6320_REV2_1_VERSION: + cmnos_core_clk_div_addr = AR6320V2_CORE_CLK_DIV_ADDR; + cmnos_cpu_pll_init_done_addr = AR6320V2_CPU_PLL_INIT_DONE_ADDR; + cmnos_cpu_speed_addr = AR6320V2_CPU_SPEED_ADDR; + break; + case AR6320_REV3_VERSION: + case AR6320_REV3_2_VERSION: + case QCA9379_REV1_VERSION: + case QCA9377_REV1_1_VERSION: + cmnos_core_clk_div_addr = AR6320V3_CORE_CLK_DIV_ADDR; + cmnos_cpu_pll_init_done_addr = AR6320V3_CPU_PLL_INIT_DONE_ADDR; + cmnos_cpu_speed_addr = AR6320V3_CPU_SPEED_ADDR; + break; + default: + BMI_ERR("%s: Unsupported target version %x", __func__, + target_version); + goto end; + } + + addr = (RTC_SOC_BASE_ADDRESS | EFUSE_OFFSET); + status = bmi_read_soc_register(addr, ®_val, ol_ctx); + if (status != QDF_STATUS_SUCCESS) { + BMI_ERR("Failed to read EFUSE Addr"); + goto end; + } + + status = ol_fw_populate_clk_settings(EFUSE_XTAL_SEL_GET(reg_val), + &clock_s); + if (status != QDF_STATUS_SUCCESS) { + BMI_ERR("Failed to set clock settings"); + goto end; + } + BMI_DBG("crystal_freq: %dHz", clock_s.refclk_hz); + + /* ------Step 1---- */ + reg_val = 0; + addr = (RTC_SOC_BASE_ADDRESS | BB_PLL_CONFIG_OFFSET); + status = bmi_read_soc_register(addr, ®_val, ol_ctx); + if (status != QDF_STATUS_SUCCESS) { + BMI_ERR("Failed to read PLL_CONFIG Addr"); + goto end; + } + BMI_DBG("Step 1a: %8X", reg_val); + + reg_val &= ~(BB_PLL_CONFIG_FRAC_MASK | BB_PLL_CONFIG_OUTDIV_MASK); + reg_val |= (BB_PLL_CONFIG_FRAC_SET(clock_s.wlan_pll.rnfrac) | + BB_PLL_CONFIG_OUTDIV_SET(clock_s.wlan_pll.outdiv)); + status = bmi_write_soc_register(addr, reg_val, ol_ctx); + if (status != QDF_STATUS_SUCCESS) { + BMI_ERR("Failed to write PLL_CONFIG Addr"); + goto end; + } + + reg_val = 0; + status = bmi_read_soc_register(addr, ®_val, ol_ctx); + if (status != QDF_STATUS_SUCCESS) { + BMI_ERR("Failed to read back PLL_CONFIG Addr"); + goto end; + } + BMI_DBG("Step 1b: %8X", reg_val); + + /* ------Step 2---- */ + reg_val = 0; + addr = (RTC_WMAC_BASE_ADDRESS | WLAN_PLL_SETTLE_OFFSET); + status = bmi_read_soc_register(addr, ®_val, ol_ctx); + if (status != QDF_STATUS_SUCCESS) { + BMI_ERR("Failed to read PLL_SETTLE Addr"); + goto end; + } + BMI_DBG("Step 2a: %8X", reg_val); + + reg_val &= ~WLAN_PLL_SETTLE_TIME_MASK; + reg_val |= WLAN_PLL_SETTLE_TIME_SET(clock_s.pll_settling_time); + status = bmi_write_soc_register(addr, reg_val, ol_ctx); + if (status != QDF_STATUS_SUCCESS) { + BMI_ERR("Failed to write PLL_SETTLE Addr"); + goto end; + } + + reg_val = 0; + status = bmi_read_soc_register(addr, ®_val, ol_ctx); + if (status != QDF_STATUS_SUCCESS) { + BMI_ERR("Failed to read back PLL_SETTLE Addr"); + goto end; + } + BMI_DBG("Step 2b: %8X", reg_val); + + /* ------Step 3---- */ + reg_val = 0; + addr = (RTC_SOC_BASE_ADDRESS | SOC_CORE_CLK_CTRL_OFFSET); + status = bmi_read_soc_register(addr, ®_val, ol_ctx); + if (status != QDF_STATUS_SUCCESS) { + BMI_ERR("Failed to read CLK_CTRL Addr"); + goto end; + } + BMI_DBG("Step 3a: %8X", reg_val); + + reg_val &= ~SOC_CORE_CLK_CTRL_DIV_MASK; + reg_val |= SOC_CORE_CLK_CTRL_DIV_SET(1); + status = bmi_write_soc_register(addr, reg_val, ol_ctx); + if (status != QDF_STATUS_SUCCESS) { + BMI_ERR("Failed to write CLK_CTRL Addr"); + goto end; + } + + reg_val = 0; + status = bmi_read_soc_register(addr, ®_val, ol_ctx); + if (status != QDF_STATUS_SUCCESS) { + BMI_ERR("Failed to read back CLK_CTRL Addr"); + goto end; + } + BMI_DBG("Step 3b: %8X", reg_val); + + /* ------Step 4----- */ + mem_val = 1; + status = bmi_write_memory(cmnos_core_clk_div_addr, + (uint8_t *) &mem_val, 4, ol_ctx); + if (status != QDF_STATUS_SUCCESS) { + BMI_ERR("Failed to write CLK_DIV Addr"); + goto end; + } + + /* ------Step 5----- */ + reg_val = 0; + addr = (RTC_WMAC_BASE_ADDRESS | WLAN_PLL_CONTROL_OFFSET); + status = bmi_read_soc_register(addr, ®_val, ol_ctx); + if (status != QDF_STATUS_SUCCESS) { + BMI_ERR("Failed to read PLL_CTRL Addr"); + goto end; + } + BMI_DBG("Step 5a: %8X", reg_val); + + reg_val &= ~(WLAN_PLL_CONTROL_REFDIV_MASK | WLAN_PLL_CONTROL_DIV_MASK | + WLAN_PLL_CONTROL_NOPWD_MASK); + reg_val |= (WLAN_PLL_CONTROL_REFDIV_SET(clock_s.wlan_pll.refdiv) | + WLAN_PLL_CONTROL_DIV_SET(clock_s.wlan_pll.div) | + WLAN_PLL_CONTROL_NOPWD_SET(1)); + status = bmi_write_soc_register(addr, reg_val, ol_ctx); + if (status != QDF_STATUS_SUCCESS) { + BMI_ERR("Failed to write PLL_CTRL Addr"); + goto end; + } + + reg_val = 0; + status = bmi_read_soc_register(addr, ®_val, ol_ctx); + if (status != QDF_STATUS_SUCCESS) { + BMI_ERR("Failed to read back PLL_CTRL Addr"); + goto end; + } + OS_DELAY(100); + BMI_DBG("Step 5b: %8X", reg_val); + + /* ------Step 6------- */ + do { + reg_val = 0; + status = bmi_read_soc_register((RTC_WMAC_BASE_ADDRESS | + RTC_SYNC_STATUS_OFFSET), ®_val, ol_ctx); + if (status != QDF_STATUS_SUCCESS) { + BMI_ERR("Failed to read RTC_SYNC_STATUS Addr"); + goto end; + } + } while (RTC_SYNC_STATUS_PLL_CHANGING_GET(reg_val)); + + /* ------Step 7------- */ + reg_val = 0; + addr = (RTC_WMAC_BASE_ADDRESS | WLAN_PLL_CONTROL_OFFSET); + status = bmi_read_soc_register(addr, ®_val, ol_ctx); + if (status != QDF_STATUS_SUCCESS) { + BMI_ERR("Failed to read PLL_CTRL Addr for CTRL_BYPASS"); + goto end; + } + BMI_DBG("Step 7a: %8X", reg_val); + + reg_val &= ~WLAN_PLL_CONTROL_BYPASS_MASK; + reg_val |= WLAN_PLL_CONTROL_BYPASS_SET(0); + status = bmi_write_soc_register(addr, reg_val, ol_ctx); + if (status != QDF_STATUS_SUCCESS) { + BMI_ERR("Failed to write PLL_CTRL Addr for CTRL_BYPASS"); + goto end; + } + + reg_val = 0; + status = bmi_read_soc_register(addr, ®_val, ol_ctx); + if (status != QDF_STATUS_SUCCESS) { + BMI_ERR("Failed to read back PLL_CTRL Addr for CTRL_BYPASS"); + goto end; + } + BMI_DBG("Step 7b: %8X", reg_val); + + /* ------Step 8-------- */ + do { + reg_val = 0; + status = bmi_read_soc_register((RTC_WMAC_BASE_ADDRESS | + RTC_SYNC_STATUS_OFFSET), ®_val, ol_ctx); + if (status != QDF_STATUS_SUCCESS) { + BMI_ERR("Failed to read SYNC_STATUS Addr"); + goto end; + } + } while (RTC_SYNC_STATUS_PLL_CHANGING_GET(reg_val)); + + /* ------Step 9-------- */ + reg_val = 0; + addr = (RTC_SOC_BASE_ADDRESS | SOC_CPU_CLOCK_OFFSET); + status = bmi_read_soc_register(addr, ®_val, ol_ctx); + if (status != QDF_STATUS_SUCCESS) { + BMI_ERR("Failed to read CPU_CLK Addr"); + goto end; + } + BMI_DBG("Step 9a: %8X", reg_val); + + reg_val &= ~SOC_CPU_CLOCK_STANDARD_MASK; + reg_val |= SOC_CPU_CLOCK_STANDARD_SET(1); + status = bmi_write_soc_register(addr, reg_val, ol_ctx); + if (status != QDF_STATUS_SUCCESS) { + BMI_ERR("Failed to write CPU_CLK Addr"); + goto end; + } + + reg_val = 0; + status = bmi_read_soc_register(addr, ®_val, ol_ctx); + if (status != QDF_STATUS_SUCCESS) { + BMI_ERR("Failed to read back CPU_CLK Addr"); + goto end; + } + BMI_DBG("Step 9b: %8X", reg_val); + + /* ------Step 10------- */ + reg_val = 0; + addr = (RTC_WMAC_BASE_ADDRESS | WLAN_PLL_CONTROL_OFFSET); + status = bmi_read_soc_register(addr, ®_val, ol_ctx); + if (status != QDF_STATUS_SUCCESS) { + BMI_ERR("Failed to read PLL_CTRL Addr for NOPWD"); + goto end; + } + BMI_DBG("Step 10a: %8X", reg_val); + + reg_val &= ~WLAN_PLL_CONTROL_NOPWD_MASK; + status = bmi_write_soc_register(addr, reg_val, ol_ctx); + if (status != QDF_STATUS_SUCCESS) { + BMI_ERR("Failed to write PLL_CTRL Addr for NOPWD"); + goto end; + } + reg_val = 0; + status = bmi_read_soc_register(addr, ®_val, ol_ctx); + if (status != QDF_STATUS_SUCCESS) { + BMI_ERR("Failed to read back PLL_CTRL Addr for NOPWD"); + goto end; + } + BMI_DBG("Step 10b: %8X", reg_val); + + /* ------Step 11------- */ + mem_val = 1; + status = bmi_write_memory(cmnos_cpu_pll_init_done_addr, + (uint8_t *) &mem_val, 4, ol_ctx); + if (status != QDF_STATUS_SUCCESS) { + BMI_ERR("Failed to write PLL_INIT Addr"); + goto end; + } + + mem_val = TARGET_CPU_FREQ; + status = bmi_write_memory(cmnos_cpu_speed_addr, + (uint8_t *) &mem_val, 4, ol_ctx); + if (status != QDF_STATUS_SUCCESS) { + BMI_ERR("Failed to write CPU_SPEED Addr"); + goto end; + } + +end: + return status; +} + +QDF_STATUS ol_download_firmware(struct ol_context *ol_ctx) +{ + struct hif_opaque_softc *scn = ol_ctx->scn; + uint32_t param, address = 0; + QDF_STATUS status = !QDF_STATUS_SUCCESS; + QDF_STATUS ret; + struct hif_target_info *tgt_info = hif_get_target_info_handle(scn); + struct ol_config_info *ini_cfg = ol_get_ini_handle(ol_ctx); + uint32_t target_type = tgt_info->target_type; + uint32_t target_version = tgt_info->target_version; + struct bmi_info *bmi_ctx = GET_BMI_CONTEXT(ol_ctx); + qdf_device_t qdf_dev = ol_ctx->qdf_dev; + + if (0 != pld_get_fw_files_for_target(qdf_dev->dev, + &bmi_ctx->fw_files, + target_type, + target_version)) { + BMI_ERR("%s: No FW files from platform driver", __func__); + return QDF_STATUS_E_FAILURE; + } + + /* Transfer Board Data from Target EEPROM to Target RAM */ + /* Determine where in Target RAM to write Board Data */ + bmi_read_memory(hif_hia_item_address(target_type, + offsetof(struct host_interest_s, hi_board_data)), + (uint8_t *)&address, 4, ol_ctx); + + if (!address) { + address = AR6004_REV5_BOARD_DATA_ADDRESS; + BMI_DBG("%s: Target address not known! Using 0x%x", + __func__, address); + } + + if (hif_get_bus_type(scn) != QDF_BUS_TYPE_USB) { + ret = ol_patch_pll_switch(ol_ctx); + if (ret != QDF_STATUS_SUCCESS) { + BMI_ERR("pll switch failed. status %d", ret); + return ret; + } + } + + if (ol_ctx->cal_in_flash) { + /* Write EEPROM or Flash data to Target RAM */ + status = ol_transfer_bin_file(ol_ctx, ATH_FLASH_FILE, + address, false); + } + + if (status == EOK) { + /* Record the fact that Board Data is initialized */ + param = 1; + bmi_write_memory( + hif_hia_item_address(target_type, + offsetof(struct host_interest_s, + hi_board_data_initialized)), + (uint8_t *) ¶m, 4, ol_ctx); + } else { + /* Flash is either not available or invalid */ + if (ol_transfer_bin_file(ol_ctx, ATH_BOARD_DATA_FILE, address, + false) != EOK) { + return -1; + } + + /* Record the fact that Board Data is initialized */ + param = 1; + bmi_write_memory( + hif_hia_item_address(target_type, + offsetof(struct host_interest_s, + hi_board_data_initialized)), + (uint8_t *) ¶m, 4, ol_ctx); + + /* Transfer One Time Programmable data */ + address = BMI_SEGMENTED_WRITE_ADDR; + BMI_INFO("%s: Using 0x%x for the remainder of init", + __func__, address); + + status = ol_transfer_bin_file(ol_ctx, ATH_OTP_FILE, + address, true); + /* Execute the OTP code only if entry found and downloaded */ + if (status == EOK) { + param = 0; + bmi_execute(address, ¶m, ol_ctx); + } else if (status < 0) { + return status; + } + } + + if (ol_transfer_bin_file(ol_ctx, ATH_SETUP_FILE, + BMI_SEGMENTED_WRITE_ADDR, true) == EOK) { + param = 0; + bmi_execute(address, ¶m, ol_ctx); + } + + /* Download Target firmware + * TODO point to target specific files in runtime + */ + address = BMI_SEGMENTED_WRITE_ADDR; + if (ol_transfer_bin_file(ol_ctx, ATH_FIRMWARE_FILE, + address, true) != EOK) { + return -1; + } + + /* Apply the patches */ + if (ol_check_dataset_patch(scn, &address)) { + if ((ol_transfer_bin_file(ol_ctx, ATH_PATCH_FILE, address, + false)) != EOK) { + return -1; + } + bmi_write_memory(hif_hia_item_address(target_type, + offsetof(struct host_interest_s, hi_dset_list_head)), + (uint8_t *) &address, 4, ol_ctx); + } + + if (ini_cfg->enable_uart_print) { + switch (target_version) { + case AR6004_VERSION_REV1_3: + param = 11; + break; + case AR6320_REV1_VERSION: + case AR6320_REV2_VERSION: + case AR6320_REV3_VERSION: + case AR6320_REV3_2_VERSION: + case QCA9379_REV1_VERSION: + case AR6320_REV4_VERSION: + case AR6320_DEV_VERSION: + if (hif_get_bus_type(scn) == QDF_BUS_TYPE_SDIO) + param = 19; + else + param = 6; + + break; + default: + /* Configure GPIO AR9888 UART */ + param = 7; + } + + bmi_write_memory(hif_hia_item_address(target_type, + offsetof(struct host_interest_s, hi_dbg_uart_txpin)), + (uint8_t *)¶m, 4, ol_ctx); + param = 1; + bmi_write_memory(hif_hia_item_address(target_type, + offsetof(struct host_interest_s, hi_serial_enable)), + (uint8_t *)¶m, 4, ol_ctx); + } else { + /* + * Explicitly setting UART prints to zero as target turns it on + * based on scratch registers. + */ + param = 0; + bmi_write_memory(hif_hia_item_address(target_type, + offsetof(struct host_interest_s, hi_serial_enable)), + (uint8_t *)¶m, 4, ol_ctx); + } + + if (ini_cfg->enable_fw_log) { + bmi_read_memory(hif_hia_item_address(target_type, + offsetof(struct host_interest_s, hi_option_flag)), + (uint8_t *)¶m, 4, ol_ctx); + + param &= ~(HI_OPTION_DISABLE_DBGLOG); + bmi_write_memory(hif_hia_item_address(target_type, + offsetof(struct host_interest_s, hi_option_flag)), + (uint8_t *)¶m, 4, ol_ctx); + } else { + /* + * Explicitly setting fwlog prints to zero as target turns it on + * based on scratch registers. + */ + bmi_read_memory(hif_hia_item_address(target_type, + offsetof(struct host_interest_s, hi_option_flag)), + (uint8_t *)¶m, 4, ol_ctx); + + param |= HI_OPTION_DISABLE_DBGLOG; + bmi_write_memory(hif_hia_item_address(target_type, + offsetof(struct host_interest_s, hi_option_flag)), + (uint8_t *) ¶m, 4, ol_ctx); + } + status = ol_extra_initialization(ol_ctx); + + return status; +} + +static int ol_diag_read(struct hif_opaque_softc *scn, uint8_t *buffer, + uint32_t pos, size_t count) +{ + int result = 0; + + if ((4 == count) && ((pos & 3) == 0)) { + result = hif_diag_read_access(scn, pos, + (uint32_t *) buffer); + } else { + size_t amount_read = 0; + size_t readSize = PCIE_READ_LIMIT; + size_t remainder = 0; + if (count > PCIE_READ_LIMIT) { + while ((amount_read < count) && (0 == result)) { + result = hif_diag_read_mem(scn, pos, + buffer, readSize); + if (0 == result) { + buffer += readSize; + pos += readSize; + amount_read += readSize; + remainder = count - amount_read; + if (remainder < PCIE_READ_LIMIT) + readSize = remainder; + } + } + } else { + result = hif_diag_read_mem(scn, pos, + buffer, count); + } + } + + if (!result) + return count; + else + return -EIO; +} + +static int ol_ath_get_reg_table(uint32_t target_version, + tgt_reg_table *reg_table) +{ + int section_len = 0; + + if (!reg_table) { + qdf_assert(0); + return section_len; + } + + switch (target_version) { + case AR6320_REV2_1_VERSION: + reg_table->section = + (tgt_reg_section *) &ar6320v2_reg_table[0]; + reg_table->section_size = sizeof(ar6320v2_reg_table) + / sizeof(ar6320v2_reg_table[0]); + section_len = AR6320_REV2_1_REG_SIZE; + break; + case AR6320_REV3_VERSION: + case AR6320_REV3_2_VERSION: + case QCA9379_REV1_VERSION: + reg_table->section = + (tgt_reg_section *) &ar6320v3_reg_table[0]; + reg_table->section_size = sizeof(ar6320v3_reg_table) + / sizeof(ar6320v3_reg_table[0]); + section_len = AR6320_REV3_REG_SIZE; + break; + default: + reg_table->section = (void *)NULL; + reg_table->section_size = 0; + section_len = 0; + } + + return section_len; +} + +static int ol_diag_read_reg_loc(struct hif_opaque_softc *scn, uint8_t *buffer, + uint32_t buffer_len) +{ + int i, len, section_len, fill_len; + int dump_len, result = 0; + tgt_reg_table reg_table; + tgt_reg_section *curr_sec, *next_sec; + struct hif_target_info *tgt_info = hif_get_target_info_handle(scn); + uint32_t target_version = tgt_info->target_version; + + section_len = ol_ath_get_reg_table(target_version, ®_table); + + if (!reg_table.section || !reg_table.section_size || !section_len) { + BMI_ERR("%s: failed to get reg table", __func__); + result = -EIO; + goto out; + } + + curr_sec = reg_table.section; + for (i = 0; i < reg_table.section_size; i++) { + + dump_len = curr_sec->end_addr - curr_sec->start_addr; + + if ((buffer_len - result) < dump_len) { + BMI_ERR("Not enough memory to dump the registers:" + " %d: 0x%08x-0x%08x", i, + curr_sec->start_addr, curr_sec->end_addr); + goto out; + } + + len = ol_diag_read(scn, buffer, curr_sec->start_addr, dump_len); + + if (len != -EIO) { + buffer += len; + result += len; + } else { + BMI_ERR("%s: can't read reg 0x%08x len = %d", + __func__, curr_sec->start_addr, dump_len); + result = -EIO; + goto out; + } + + if (result < section_len) { + next_sec = (tgt_reg_section *) ((uint8_t *) curr_sec + + sizeof(*curr_sec)); + fill_len = next_sec->start_addr - curr_sec->end_addr; + if ((buffer_len - result) < fill_len) { + BMI_ERR("Not enough memory to fill registers:" + " %d: 0x%08x-0x%08x", i, + curr_sec->end_addr, + next_sec->start_addr); + goto out; + } + + if (fill_len) { + buffer += fill_len; + result += fill_len; + } + } + curr_sec++; + } + +out: + return result; +} + +#ifdef CONFIG_HL_SUPPORT + +/** + * ol_dump_ce_register() - cannot read the section + * @scn: ol_softc handler + * @memory_block: non-NULL reserved memory location + * + * Return: -EACCES for LL and not apllicable for HL + */ +static inline int +ol_dump_ce_register(struct hif_opaque_softc *scn, void *memory_block) +{ + return 0; +} + +#else + +static +void ol_dump_target_memory(struct hif_opaque_softc *scn, void *memory_block) +{ + char *buffer_loc = memory_block; + u_int32_t section_count = 0; + u_int32_t address = 0; + u_int32_t size = 0; + + if (hif_get_bus_type(scn) == QDF_BUS_TYPE_SDIO || + hif_get_bus_type(scn) == QDF_BUS_TYPE_USB) + return; + + for (; section_count < 2; section_count++) { + switch (section_count) { + case 0: + address = DRAM_LOCAL_BASE_ADDR; + size = DRAM_SIZE; + break; + case 1: + address = AXI_LOCATION; + size = AXI_SIZE; + default: + break; + } + hif_dump_target_memory(scn, buffer_loc, address, size); + buffer_loc += size; + } +} + +static int +ol_dump_ce_register(struct hif_opaque_softc *scn, void *memory_block) +{ + int ret; + + BMI_ERR("Could not read dump section!"); + + if (hif_dump_registers(scn)) + BMI_ERR("Failed to dump bus registers"); + + ol_dump_target_memory(scn, memory_block); + ret = -EACCES; + + return ret; +} +#endif + +/** + * ol_target_coredump() - API to collect target ramdump + * @inst - private context + * @memory_block - non-NULL reserved memory location + * @block_len - size of the dump to collect + * + * Function to perform core dump for the target. + * + * Return: int + */ +static int ol_target_coredump(void *inst, void *memory_block, + uint32_t block_len) +{ + struct hif_opaque_softc *scn = (struct hif_opaque_softc *)inst; + int8_t *buffer_loc = memory_block; + int result = 0; + int ret = 0; + uint32_t amount_read = 0; + uint32_t section_count = 0; + uint32_t pos = 0; + uint32_t read_len = 0; + + /* + * SECTION = DRAM + * START = 0x00400000 + * LENGTH = 0x000a8000 + * + * SECTION = AXI + * START = 0x000a0000 + * LENGTH = 0x00018000 + * + * SECTION = REG + * START = 0x00000800 + * LENGTH = 0x0007F820 + */ + + while ((section_count < 3) && (amount_read < block_len)) { + switch (section_count) { + case 0: + /* DRAM SECTION */ + pos = DRAM_LOCATION; + read_len = DRAM_SIZE; + BMI_ERR("%s: Dumping DRAM section...", __func__); + break; + case 1: + /* AXI SECTION */ + pos = AXI_LOCATION; + read_len = AXI_SIZE; + BMI_ERR("%s: Dumping AXI section...", __func__); + break; + case 2: + /* REG SECTION */ + pos = REGISTER_LOCATION; + /* ol_diag_read_reg_loc checks for buffer overrun */ + read_len = 0; + BMI_ERR("%s: Dumping Register section...", __func__); + break; + } + + if ((block_len - amount_read) >= read_len) { + if ((hif_get_bus_type(scn) == QDF_BUS_TYPE_PCI) && + (pos == REGISTER_LOCATION)) { + result = ol_diag_read_reg_loc(scn, + buffer_loc, + block_len - amount_read); + } else { + result = ol_diag_read(scn, buffer_loc, + pos, read_len); + } + if (result != -EIO) { + amount_read += result; + buffer_loc += result; + section_count++; + } else { + ret = ol_dump_ce_register(scn, memory_block); + break; /* Could not read the section */ + } + } else { + BMI_ERR("Insufficient room in dump buffer!"); + break; /* Insufficient room in buffer */ + } + } + return ret; +} + +/** + * ol_get_ini_handle() - API to get Ol INI configuration + * @ol_ctx: OL Context + * + * Return: pointer to OL configuration + */ +struct ol_config_info *ol_get_ini_handle(struct ol_context *ol_ctx) +{ + return &ol_ctx->cfg_info; +} + +/** + * ol_init_ini_config() - API to initialize INI configuration + * @ol_ctx: OL Context + * @cfg: OL ini configuration + * + * Return: void + */ +void ol_init_ini_config(struct ol_context *ol_ctx, + struct ol_config_info *cfg) +{ + qdf_mem_copy(&ol_ctx->cfg_info, cfg, sizeof(struct ol_config_info)); +} diff --git a/drivers/staging/qcacld-3.0/core/bmi/src/ol_fw_common.c b/drivers/staging/qcacld-3.0/core/bmi/src/ol_fw_common.c new file mode 100644 index 0000000000000000000000000000000000000000..48e7fd0c1bf4ded97906f66e3d11b8435f05f9ec --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/bmi/src/ol_fw_common.c @@ -0,0 +1,223 @@ +/* + * Copyright (c) 2014-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#include "ol_if_athvar.h" +#include "targaddrs.h" +#include "ol_cfg.h" +#include "i_ar6320v2_regtable.h" +#include "ol_fw.h" +#ifdef HIF_PCI +#include "ce_reg.h" +#endif +#if defined(HIF_SDIO) +#include "regtable_sdio.h" +#endif +#if defined(HIF_USB) +#include "regtable_usb.h" +#endif +#if defined(CONFIG_CNSS) +#include +#endif +#include "i_bmi.h" + +#ifdef CONFIG_DISABLE_SLEEP_BMI_OPTION +static inline void ol_sdio_disable_sleep(struct ol_context *ol_ctx) +{ + uint32_t value; + + BMI_ERR("prevent ROME from sleeping"); + bmi_read_soc_register(MBOX_BASE_ADDRESS + LOCAL_SCRATCH_OFFSET, + /* this address should be 0x80C0 for ROME*/ + &value, + ol_ctx); + + value |= SOC_OPTION_SLEEP_DISABLE; + + bmi_write_soc_register(MBOX_BASE_ADDRESS + LOCAL_SCRATCH_OFFSET, + value, + ol_ctx); +} + +#else +static inline void ol_sdio_disable_sleep(struct ol_context *ol_ctx) +{ +} + +#endif + +/** + * ol_usb_extra_initialization() - USB extra initilization + * @ol_ctx: pointer to ol_context + * + * USB specific initialization after firmware download + * + * Return: QDF_STATUS_SUCCESS on success and error QDF status on failure + */ +static QDF_STATUS +ol_usb_extra_initialization(struct ol_context *ol_ctx) +{ + struct hif_opaque_softc *scn = ol_ctx->scn; + struct hif_target_info *tgt_info = + hif_get_target_info_handle(scn); + QDF_STATUS status = !QDF_STATUS_SUCCESS; + u_int32_t param = 0; + + param |= HI_ACS_FLAGS_ALT_DATA_CREDIT_SIZE; + status = bmi_write_memory( + hif_hia_item_address(tgt_info->target_type, + offsetof(struct host_interest_s, + hi_acs_flags)), + (u_int8_t *)¶m, 4, ol_ctx); + + return status; +} + +/*Setting SDIO block size, mbox ISR yield limit for SDIO based HIF*/ +static +QDF_STATUS ol_sdio_extra_initialization(struct ol_context *ol_ctx) +{ + + QDF_STATUS status; + uint32_t param; + uint32_t blocksizes[HTC_MAILBOX_NUM_MAX]; + uint32_t MboxIsrYieldValue = 99; + struct hif_opaque_softc *scn = ol_ctx->scn; + struct hif_target_info *tgt_info = hif_get_target_info_handle(scn); + uint32_t target_type = tgt_info->target_type; + + /* get the block sizes */ + status = hif_get_config_item(scn, + HIF_DEVICE_GET_MBOX_BLOCK_SIZE, + blocksizes, sizeof(blocksizes)); + if (status != EOK) { + BMI_ERR("Failed to get block size info from HIF layer"); + goto exit; + } + /* note: we actually get the block size for mailbox 1, + * for SDIO the block size on mailbox 0 is artificially + * set to 1 must be a power of 2 */ + qdf_assert((blocksizes[1] & (blocksizes[1] - 1)) == 0); + + /* set the host interest area for the block size */ + status = bmi_write_memory(hif_hia_item_address(target_type, + offsetof(struct host_interest_s, + hi_mbox_io_block_sz)), + (uint8_t *)&blocksizes[1], + 4, + ol_ctx); + + if (status != EOK) { + BMI_ERR("BMIWriteMemory for IO block size failed"); + goto exit; + } + + if (MboxIsrYieldValue != 0) { + /* set the host for the mbox ISR yield limit */ + status = + bmi_write_memory(hif_hia_item_address(target_type, + offsetof(struct host_interest_s, + hi_mbox_isr_yield_limit)), + (uint8_t *)&MboxIsrYieldValue, + 4, + ol_ctx); + + if (status != EOK) { + BMI_ERR("BMI write for yield limit failed\n"); + goto exit; + } + } + ol_sdio_disable_sleep(ol_ctx); + status = bmi_read_memory(hif_hia_item_address(target_type, + offsetof(struct host_interest_s, + hi_acs_flags)), + (uint8_t *)¶m, + 4, + ol_ctx); + if (status != EOK) { + BMI_ERR("BMIReadMemory for hi_acs_flags failed"); + goto exit; + } + + param |= (HI_ACS_FLAGS_SDIO_SWAP_MAILBOX_SET| + HI_ACS_FLAGS_SDIO_REDUCE_TX_COMPL_SET| + HI_ACS_FLAGS_ALT_DATA_CREDIT_SIZE); + + bmi_write_memory(hif_hia_item_address(target_type, + offsetof(struct host_interest_s, + hi_acs_flags)), + (uint8_t *)¶m, 4, ol_ctx); +exit: + return status; +} + +/** +* ol_extra_initialization() - OL extra initilization +* @ol_ctx: pointer to ol_context +* +* Bus specific initialization after firmware download +* +* Return: QDF_STATUS_SUCCESS on success and error QDF status on failure +*/ +QDF_STATUS ol_extra_initialization(struct ol_context *ol_ctx) +{ + struct hif_opaque_softc *scn = ol_ctx->scn; + + if (hif_get_bus_type(scn) == QDF_BUS_TYPE_SDIO) + return ol_sdio_extra_initialization(ol_ctx); + else if (hif_get_bus_type(scn) == QDF_BUS_TYPE_USB) + return ol_usb_extra_initialization(ol_ctx); + + return QDF_STATUS_SUCCESS; +} + +void ol_target_ready(struct hif_opaque_softc *scn, void *cfg_ctx) +{ + uint32_t value = 0; + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct hif_target_info *tgt_info = hif_get_target_info_handle(scn); + uint32_t target_type = tgt_info->target_type; + + if (hif_get_bus_type(scn) != QDF_BUS_TYPE_SDIO) + return; + status = hif_diag_read_mem(scn, + hif_hia_item_address(target_type, + offsetof(struct host_interest_s, hi_acs_flags)), + (uint8_t *)&value, sizeof(u_int32_t)); + + if (status != QDF_STATUS_SUCCESS) { + BMI_ERR("HIFDiagReadMem failed"); + return; + } + + if (value & HI_ACS_FLAGS_SDIO_SWAP_MAILBOX_FW_ACK) { + BMI_ERR("MAILBOX SWAP Service is enabled!"); + hif_set_mailbox_swap(scn); + } + + if (value & HI_ACS_FLAGS_SDIO_REDUCE_TX_COMPL_FW_ACK) + BMI_ERR("Reduced Tx Complete service is enabled!"); +} diff --git a/drivers/staging/qcacld-3.0/core/cds/inc/cds_api.h b/drivers/staging/qcacld-3.0/core/cds/inc/cds_api.h new file mode 100644 index 0000000000000000000000000000000000000000..92b289c698f987414b44b0a966e7d97ae15e3894 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/cds/inc/cds_api.h @@ -0,0 +1,323 @@ +/* + * Copyright (c) 2014-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ +#if !defined(__CDS_API_H) +#define __CDS_API_H + +/** + * DOC: cds_api.h + * + * Connectivity driver services public API + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Amount of time to wait for WMA to perform an asynchronous activity. + * This value should be larger than the timeout used by WMI to wait for + * a response from target + */ +#define CDS_WMA_TIMEOUT (15000) + +/** + * enum cds_driver_state - Driver state + * @CDS_DRIVER_STATE_UNINITIALIZED: Driver is in uninitialized state. + * CDS_DRIVER_STATE_LOADED: Driver is loaded and functional. + * CDS_DRIVER_STATE_LOADING: Driver probe is in progress. + * CDS_DRIVER_STATE_UNLOADING: Driver remove is in progress. + * CDS_DRIVER_STATE_RECOVERING: Recovery in progress. + */ +enum cds_driver_state { + CDS_DRIVER_STATE_UNINITIALIZED = 0, + CDS_DRIVER_STATE_LOADED = BIT(0), + CDS_DRIVER_STATE_LOADING = BIT(1), + CDS_DRIVER_STATE_UNLOADING = BIT(2), + CDS_DRIVER_STATE_RECOVERING = BIT(3), +}; + +#define __CDS_IS_DRIVER_STATE(_state, _mask) (((_state) & (_mask)) == (_mask)) + +/** + * struct cds_sme_cbacks - list of sme functions registered with + * CDS + * @sme_get_valid_channels: gets the valid channel list for + * current reg domain + * @sme_get_nss_for_vdev: gets the nss allowed for the vdev type + */ +struct cds_sme_cbacks { + QDF_STATUS (*sme_get_valid_channels)(void*, uint8_t *, uint32_t *); + void (*sme_get_nss_for_vdev)(void*, enum tQDF_ADAPTER_MODE, + uint8_t *, uint8_t *); +}; + +/** + * struct cds_dp_cbacks - list of datapath functions registered with CDS + * @ol_txrx_update_mac_id_cb: updates mac_id for vdev + * @hdd_en_lro_in_cc_cb: enables LRO if concurrency is not active + * @hdd_disble_lro_in_cc_cb: disables LRO due to concurrency + * @hdd_set_rx_mode_rps_cb: enable/disable RPS in SAP mode + */ +struct cds_dp_cbacks { + void (*ol_txrx_update_mac_id_cb)(uint8_t , uint8_t); + void (*hdd_en_lro_in_cc_cb)(struct hdd_context_s *); + void (*hdd_disble_lro_in_cc_cb)(struct hdd_context_s *); + void (*hdd_set_rx_mode_rps_cb)(struct hdd_context_s *, void *, bool); +}; + +void cds_set_driver_state(enum cds_driver_state); +void cds_clear_driver_state(enum cds_driver_state); +enum cds_driver_state cds_get_driver_state(void); + +/** + * cds_is_driver_loading() - Is driver load in progress + * + * Return: true if driver is loading and false otherwise. + */ +static inline bool cds_is_driver_loading(void) +{ + enum cds_driver_state state = cds_get_driver_state(); + + return __CDS_IS_DRIVER_STATE(state, CDS_DRIVER_STATE_LOADING); +} + +/** + * cds_is_driver_unloading() - Is driver unload in progress + * + * Return: true if driver is unloading and false otherwise. + */ +static inline bool cds_is_driver_unloading(void) +{ + enum cds_driver_state state = cds_get_driver_state(); + + return __CDS_IS_DRIVER_STATE(state, CDS_DRIVER_STATE_UNLOADING); +} + +/** + * cds_is_driver_recovering() - Is recovery in progress + * + * Return: true if recovery in progress and false otherwise. + */ +static inline bool cds_is_driver_recovering(void) +{ + enum cds_driver_state state = cds_get_driver_state(); + + return __CDS_IS_DRIVER_STATE(state, CDS_DRIVER_STATE_RECOVERING); +} + +/** + * cds_is_load_or_unload_in_progress() - Is driver load OR unload in progress + * + * Return: true if driver is loading OR unloading and false otherwise. + */ +static inline bool cds_is_load_or_unload_in_progress(void) +{ + enum cds_driver_state state = cds_get_driver_state(); + + return __CDS_IS_DRIVER_STATE(state, CDS_DRIVER_STATE_LOADING) || + __CDS_IS_DRIVER_STATE(state, CDS_DRIVER_STATE_UNLOADING); +} + +/** + * cds_set_recovery_in_progress() - Set recovery in progress + * @value: value to set + * + * Return: none + */ +static inline void cds_set_recovery_in_progress(uint8_t value) +{ + if (value) + cds_set_driver_state(CDS_DRIVER_STATE_RECOVERING); + else + cds_clear_driver_state(CDS_DRIVER_STATE_RECOVERING); +} + +/** + * cds_set_load_in_progress() - Set load in progress + * @value: value to set + * + * Return: none + */ +static inline void cds_set_load_in_progress(uint8_t value) +{ + if (value) + cds_set_driver_state(CDS_DRIVER_STATE_LOADING); + else + cds_clear_driver_state(CDS_DRIVER_STATE_LOADING); +} + +/** + * cds_set_driver_loaded() - Set load completed + * @value: value to set + * + * Return: none + */ +static inline void cds_set_driver_loaded(uint8_t value) +{ + if (value) + cds_set_driver_state(CDS_DRIVER_STATE_LOADED); + else + cds_clear_driver_state(CDS_DRIVER_STATE_LOADED); +} + +/** + * cds_set_unload_in_progress() - Set unload in progress + * @value: value to set + * + * Return: none + */ +static inline void cds_set_unload_in_progress(uint8_t value) +{ + if (value) + cds_set_driver_state(CDS_DRIVER_STATE_UNLOADING); + else + cds_clear_driver_state(CDS_DRIVER_STATE_UNLOADING); +} + +/** + * cds_is_driver_loaded() - Is driver loaded + * + * Return: true if driver is loaded or false otherwise. + */ +static inline bool cds_is_driver_loaded(void) +{ + enum cds_driver_state state = cds_get_driver_state(); + + return __CDS_IS_DRIVER_STATE(state, CDS_DRIVER_STATE_LOADED); +} + +v_CONTEXT_t cds_init(void); +void cds_deinit(void); + +QDF_STATUS cds_pre_enable(v_CONTEXT_t cds_context); + +QDF_STATUS cds_open(void); + +QDF_STATUS cds_enable(v_CONTEXT_t cds_context); + +QDF_STATUS cds_disable(v_CONTEXT_t cds_context); + +QDF_STATUS cds_post_disable(void); + +QDF_STATUS cds_close(v_CONTEXT_t cds_context); + +void cds_core_return_msg(void *pVContext, p_cds_msg_wrapper pMsgWrapper); + +void *cds_get_context(QDF_MODULE_ID moduleId); + +v_CONTEXT_t cds_get_global_context(void); + +QDF_STATUS cds_alloc_context(void *p_cds_context, QDF_MODULE_ID moduleID, + void **ppModuleContext, uint32_t size); + +QDF_STATUS cds_free_context(void *p_cds_context, QDF_MODULE_ID moduleID, + void *pModuleContext); + +QDF_STATUS cds_set_context(QDF_MODULE_ID module_id, void *context); + +QDF_STATUS cds_get_vdev_types(enum tQDF_ADAPTER_MODE mode, uint32_t *type, + uint32_t *subType); + +void cds_flush_work(void *work); +void cds_flush_delayed_work(void *dwork); + +bool cds_is_packet_log_enabled(void); + +uint64_t cds_get_monotonic_boottime(void); + +void cds_trigger_recovery(bool); + +void cds_set_wakelock_logging(bool value); +bool cds_is_wakelock_enabled(void); +void cds_set_ring_log_level(uint32_t ring_id, uint32_t log_level); +enum wifi_driver_log_level cds_get_ring_log_level(uint32_t ring_id); +void cds_set_multicast_logging(uint8_t value); +uint8_t cds_is_multicast_logging(void); +QDF_STATUS cds_set_log_completion(uint32_t is_fatal, + uint32_t type, + uint32_t sub_type, + bool recovery_needed); +void cds_get_and_reset_log_completion(uint32_t *is_fatal, + uint32_t *type, + uint32_t *sub_type, + bool *recovery_needed); +bool cds_is_log_report_in_progress(void); +bool cds_is_fatal_event_enabled(void); +uint32_t cds_get_log_indicator(void); +void cds_set_fatal_event(bool value); +void cds_wlan_flush_host_logs_for_fatal(void); + +void cds_init_log_completion(void); +QDF_STATUS cds_flush_logs(uint32_t is_fatal, + uint32_t indicator, + uint32_t reason_code, + bool dump_mac_trace, + bool recovery_needed); +void cds_logging_set_fw_flush_complete(void); +void cds_svc_fw_shutdown_ind(struct device *dev); +#ifdef FEATURE_WLAN_DIAG_SUPPORT +void cds_tdls_tx_rx_mgmt_event(uint8_t event_id, uint8_t tx_rx, + uint8_t type, uint8_t sub_type, uint8_t *peer_mac); +#else +static inline +void cds_tdls_tx_rx_mgmt_event(uint8_t event_id, uint8_t tx_rx, + uint8_t type, uint8_t sub_type, uint8_t *peer_mac) + +{ +} +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + +int cds_get_radio_index(void); +QDF_STATUS cds_set_radio_index(int radio_index); +void cds_init_ini_config(struct cds_config_info *cds_cfg); +void cds_deinit_ini_config(void); +struct cds_config_info *cds_get_ini_config(void); + +bool cds_is_5_mhz_enabled(void); +bool cds_is_10_mhz_enabled(void); +bool cds_is_sub_20_mhz_enabled(void); +bool cds_is_self_recovery_enabled(void); +void cds_pkt_stats_to_logger_thread(void *pl_hdr, void *pkt_dump, void *data); +QDF_STATUS cds_register_dp_cb(struct cds_dp_cbacks *dp_cbs); +QDF_STATUS cds_deregister_dp_cb(void); + +uint32_t cds_get_arp_stats_gw_ip(void); +void cds_incr_arp_stats_tx_tgt_delivered(void); +void cds_incr_arp_stats_tx_tgt_acked(void); +#endif /* if !defined __CDS_API_H */ diff --git a/drivers/staging/qcacld-3.0/core/cds/inc/cds_concurrency.h b/drivers/staging/qcacld-3.0/core/cds/inc/cds_concurrency.h new file mode 100644 index 0000000000000000000000000000000000000000..238659ffcab6fb64e29ab8744ae756bd24e54756 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/cds/inc/cds_concurrency.h @@ -0,0 +1,915 @@ +/* + * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef __CDS_CONCURRENCY_H +#define __CDS_CONCURRENCY_H + +/** + * DOC: cds_concurrency.h + * + * CDS Concurrenct Connection Management entity + */ + +/* Include files */ + +#include "wlan_hdd_main.h" + +#define MAX_NUMBER_OF_CONC_CONNECTIONS 3 +#define DBS_OPPORTUNISTIC_TIME 10 +#ifdef QCA_WIFI_3_0_EMU +#define CONNECTION_UPDATE_TIMEOUT 3000 +#else +#define CONNECTION_UPDATE_TIMEOUT 1000 +#endif + +/* Some max value greater than the max length of the channel list */ +#define MAX_WEIGHT_OF_PCL_CHANNELS 255 +/* Some fixed weight difference between the groups */ +#define PCL_GROUPS_WEIGHT_DIFFERENCE 20 +#define CDS_INVALID_VDEV_ID 255 + +/* Currently max, only 3 groups are possible as per 'enum cds_pcl_type'. + * i.e., in a PCL only 3 groups of channels can be present + * e.g., SCC channel on 2.4 Ghz, SCC channel on 5 Ghz & 5 Ghz channels. + * Group 1 has highest priority, group 2 has the next higher priority + * and so on. + */ +#define WEIGHT_OF_GROUP1_PCL_CHANNELS MAX_WEIGHT_OF_PCL_CHANNELS +#define WEIGHT_OF_GROUP2_PCL_CHANNELS \ + (WEIGHT_OF_GROUP1_PCL_CHANNELS - PCL_GROUPS_WEIGHT_DIFFERENCE) +#define WEIGHT_OF_GROUP3_PCL_CHANNELS \ + (WEIGHT_OF_GROUP2_PCL_CHANNELS - PCL_GROUPS_WEIGHT_DIFFERENCE) + +#define WEIGHT_OF_NON_PCL_CHANNELS 1 +#define WEIGHT_OF_DISALLOWED_CHANNELS 0 + +/** + * enum hw_mode_ss_config - Possible spatial stream configuration + * @SS_0x0: Unused Tx and Rx of MAC + * @SS_1x1: 1 Tx SS and 1 Rx SS + * @SS_2x2: 2 Tx SS and 2 Rx SS + * @SS_3x3: 3 Tx SS and 3 Rx SS + * @SS_4x4: 4 Tx SS and 4 Rx SS + * + * Note: Right now only 1x1 and 2x2 are being supported. Other modes should + * be added when supported. Asymmetric configuration like 1x2, 2x1 are also + * not supported now. But, they are still valid. Right now, Tx/Rx SS support is + * 4 bits long. So, we can go upto 15x15 + */ +enum hw_mode_ss_config { + HW_MODE_SS_0x0, + HW_MODE_SS_1x1, + HW_MODE_SS_2x2, + HW_MODE_SS_3x3, + HW_MODE_SS_4x4, +}; + +/** + * enum hw_mode_dbs_capab - DBS HW mode capability + * @HW_MODE_DBS_NONE: Non DBS capable + * @HW_MODE_DBS: DBS capable + */ +enum hw_mode_dbs_capab { + HW_MODE_DBS_NONE, + HW_MODE_DBS, +}; + +/** + * enum hw_mode_agile_dfs_capab - Agile DFS HW mode capability + * @HW_MODE_AGILE_DFS_NONE: Non Agile DFS capable + * @HW_MODE_AGILE_DFS: Agile DFS capable + */ +enum hw_mode_agile_dfs_capab { + HW_MODE_AGILE_DFS_NONE, + HW_MODE_AGILE_DFS, +}; + +/** + * enum hw_mode_sbs_capab - SBS HW mode capability + * @HW_MODE_SBS_NONE: Non SBS capable + * @HW_MODE_SBS: SBS capable + */ +enum hw_mode_sbs_capab { + HW_MODE_SBS_NONE, + HW_MODE_SBS, +}; + +/** + * enum cds_pcl_group_id - Identifies the pcl groups to be used + * @CDS_PCL_GROUP_ID1_ID2: Use weights of group1 and group2 + * @CDS_PCL_GROUP_ID2_ID2: Use weights of group2 and group3 + * + * Since maximum of three groups are possible, this will indicate which + * PCL group needs to be used. + */ +enum cds_pcl_group_id { + CDS_PCL_GROUP_ID1_ID2, + CDS_PCL_GROUP_ID2_ID3, +}; + +/** + * cds_pcl_channel_order - Order in which the PCL is requested + * @CDS_PCL_ORDER_NONE: no order + * @CDS_PCL_ORDER_24G_THEN_5G: 2.4 Ghz channel followed by 5 Ghz channel + * @CDS_PCL_ORDER_5G_THEN_2G: 5 Ghz channel followed by 2.4 Ghz channel + * + * Order in which the PCL is requested + */ +enum cds_pcl_channel_order { + CDS_PCL_ORDER_NONE, + CDS_PCL_ORDER_24G_THEN_5G, + CDS_PCL_ORDER_5G_THEN_2G, +}; + +/** + * enum cds_max_rx_ss - Maximum number of receive spatial streams + * @CDS_RX_NSS_1: Receive Nss = 1 + * @CDS_RX_NSS_2: Receive Nss = 2 + * @CDS_RX_NSS_3: Receive Nss = 3 + * @CDS_RX_NSS_4: Receive Nss = 4 + * @CDS_RX_NSS_5: Receive Nss = 5 + * @CDS_RX_NSS_6: Receive Nss = 6 + * @CDS_RX_NSS_7: Receive Nss = 7 + * @CDS_RX_NSS_8: Receive Nss = 8 + * + * Indicates the maximum number of spatial streams that the STA can receive + */ +enum cds_max_rx_ss { + CDS_RX_NSS_1 = 0, + CDS_RX_NSS_2 = 1, + CDS_RX_NSS_3 = 2, + CDS_RX_NSS_4 = 3, + CDS_RX_NSS_5 = 4, + CDS_RX_NSS_6 = 5, + CDS_RX_NSS_7 = 6, + CDS_RX_NSS_8 = 7, + CDS_RX_NSS_MAX, +}; + +/** + * enum cds_chain_mode - Chain Mask tx & rx combination. + * + * @CDS_ONE_ONE: One for Tx, One for Rx + * @CDS_TWO_TWO: Two for Tx, Two for Rx + * @CDS_MAX_NO_OF_CHAIN_MODE: Max place holder + * + * These are generic IDs that identify the various roles + * in the software system + */ +enum cds_chain_mode { + CDS_ONE_ONE = 0, + CDS_TWO_TWO, + CDS_MAX_NO_OF_CHAIN_MODE +}; + +/** + * enum cds_conc_priority_mode - t/p, powersave, latency. + * + * @CDS_THROUGHPUT: t/p is the priority + * @CDS_POWERSAVE: powersave is the priority + * @CDS_LATENCY: latency is the priority + * @CDS_MAX_CONC_PRIORITY_MODE: Max place holder + * + * These are generic IDs that identify the various roles + * in the software system + */ +enum cds_conc_priority_mode { + CDS_THROUGHPUT = 0, + CDS_POWERSAVE, + CDS_LATENCY, + CDS_MAX_CONC_PRIORITY_MODE +}; + +/** + * enum cds_con_mode - concurrency mode for PCL table + * + * @CDS_STA_MODE: station mode + * @CDS_SAP_MODE: SAP mode + * @CDS_P2P_CLIENT_MODE: P2P client mode + * @CDS_P2P_GO_MODE: P2P Go mode + * @CDS_IBSS_MODE: IBSS mode + * @CDS_MAX_NUM_OF_MODE: max value place holder + */ +enum cds_con_mode { + CDS_STA_MODE = 0, + CDS_SAP_MODE, + CDS_P2P_CLIENT_MODE, + CDS_P2P_GO_MODE, + CDS_IBSS_MODE, + CDS_MAX_NUM_OF_MODE +}; + +/** + * enum cds_mac_use - MACs that are used + * @CDS_MAC0: Only MAC0 is used + * @CDS_MAC1: Only MAC1 is used + * @CDS_MAC0_AND_MAC1: Both MAC0 and MAC1 are used + */ +enum cds_mac_use { + CDS_MAC0 = 1, + CDS_MAC1 = 2, + CDS_MAC0_AND_MAC1 = 3 +}; + +/** + * enum cds_pcl_type - Various types of Preferred channel list (PCL). + * + * @CDS_NONE: No channel preference + * @CDS_24G: 2.4 Ghz channels only + * @CDS_5G: 5 Ghz channels only + * @CDS_SCC_CH: SCC channel only + * @CDS_MCC_CH: MCC channels only + * @CDS_SCC_CH_24G: SCC channel & 2.4 Ghz channels + * @CDS_SCC_CH_5G: SCC channel & 5 Ghz channels + * @CDS_24G_SCC_CH: 2.4 Ghz channels & SCC channel + * @CDS_5G_SCC_CH: 5 Ghz channels & SCC channel + * @CDS_SCC_ON_5_SCC_ON_24_24G: SCC channel on 5 Ghz, SCC + * channel on 2.4 Ghz & 2.4 Ghz channels + * @CDS_SCC_ON_5_SCC_ON_24_5G: SCC channel on 5 Ghz, SCC channel + * on 2.4 Ghz & 5 Ghz channels + * @CDS_SCC_ON_24_SCC_ON_5_24G: SCC channel on 2.4 Ghz, SCC + * channel on 5 Ghz & 2.4 Ghz channels + * @CDS_SCC_ON_24_SCC_ON_5_5G: SCC channel on 2.4 Ghz, SCC + * channel on 5 Ghz & 5 Ghz channels + * @CDS_SCC_ON_5_SCC_ON_24: SCC channel on 5 Ghz, SCC channel on + * 2.4 Ghz + * @CDS_SCC_ON_24_SCC_ON_5: SCC channel on 2.4 Ghz, SCC channel + * on 5 Ghz + * @CDS_MCC_CH_24G: MCC channels & 2.4 Ghz channels + * @CDS_MCC_CH_5G: MCC channels & 5 Ghz channels + * @CDS_24G_MCC_CH: 2.4 Ghz channels & MCC channels + * @CDS_5G_MCC_CH: 5 Ghz channels & MCC channels + * @CDS_MAX_PCL_TYPE: Max place holder + * + * These are generic IDs that identify the various roles + * in the software system + */ +enum cds_pcl_type { + CDS_NONE = 0, + CDS_24G, + CDS_5G, + CDS_SCC_CH, + CDS_MCC_CH, + CDS_SCC_CH_24G, + CDS_SCC_CH_5G, + CDS_24G_SCC_CH, + CDS_5G_SCC_CH, + CDS_SCC_ON_5_SCC_ON_24_24G, + CDS_SCC_ON_5_SCC_ON_24_5G, + CDS_SCC_ON_24_SCC_ON_5_24G, + CDS_SCC_ON_24_SCC_ON_5_5G, + CDS_SCC_ON_5_SCC_ON_24, + CDS_SCC_ON_24_SCC_ON_5, + CDS_MCC_CH_24G, + CDS_MCC_CH_5G, + CDS_24G_MCC_CH, + CDS_5G_MCC_CH, + + CDS_MAX_PCL_TYPE +}; + +/** + * enum cds_one_connection_mode - Combination of first connection + * type, band & spatial stream used. + * + * @CDS_STA_24_1x1: STA connection using 1x1@2.4 Ghz + * @CDS_STA_24_2x2: STA connection using 2x2@2.4 Ghz + * @CDS_STA_5_1x1: STA connection using 1x1@5 Ghz + * @CDS_STA_5_2x2: STA connection using 2x2@5 Ghz + * @CDS_P2P_CLI_24_1x1: P2P Client connection using 1x1@2.4 Ghz + * @CDS_P2P_CLI_24_2x2: P2P Client connection using 2x2@2.4 Ghz + * @CDS_P2P_CLI_5_1x1: P2P Client connection using 1x1@5 Ghz + * @CDS_P2P_CLI_5_2x2: P2P Client connection using 2x2@5 Ghz + * @CDS_P2P_GO_24_1x1: P2P GO connection using 1x1@2.4 Ghz + * @CDS_P2P_GO_24_2x2: P2P GO connection using 2x2@2.4 Ghz + * @CDS_P2P_GO_5_1x1: P2P GO connection using 1x1@5 Ghz + * @CDS_P2P_GO_5_2x2: P2P GO connection using 2x2@5 Ghz + * @CDS_SAP_24_1x1: SAP connection using 1x1@2.4 Ghz + * @CDS_SAP_24_2x2: SAP connection using 2x2@2.4 Ghz + * @CDS_SAP_5_1x1: SAP connection using 1x1@5 Ghz + * @CDS_SAP_5_1x1: SAP connection using 2x2@5 Ghz + * @CDS_IBSS_24_1x1: IBSS connection using 1x1@2.4 Ghz + * @CDS_IBSS_24_2x2: IBSS connection using 2x2@2.4 Ghz + * @CDS_IBSS_5_1x1: IBSS connection using 1x1@5 Ghz + * @CDS_IBSS_5_2x2: IBSS connection using 2x2@5 Ghz + * @CDS_MAX_ONE_CONNECTION_MODE: Max place holder + * + * These are generic IDs that identify the various roles + * in the software system + */ +enum cds_one_connection_mode { + CDS_STA_24_1x1 = 0, + CDS_STA_24_2x2, + CDS_STA_5_1x1, + CDS_STA_5_2x2, + CDS_P2P_CLI_24_1x1, + CDS_P2P_CLI_24_2x2, + CDS_P2P_CLI_5_1x1, + CDS_P2P_CLI_5_2x2, + CDS_P2P_GO_24_1x1, + CDS_P2P_GO_24_2x2, + CDS_P2P_GO_5_1x1, + CDS_P2P_GO_5_2x2, + CDS_SAP_24_1x1, + CDS_SAP_24_2x2, + CDS_SAP_5_1x1, + CDS_SAP_5_2x2, + CDS_IBSS_24_1x1, + CDS_IBSS_24_2x2, + CDS_IBSS_5_1x1, + CDS_IBSS_5_2x2, + + CDS_MAX_ONE_CONNECTION_MODE +}; + +/** + * enum cds_two_connection_mode - Combination of first two + * connections type, concurrency state, band & spatial stream + * used. + * + * @CDS_STA_SAP_SCC_24_1x1: STA & SAP connection on SCC using + * 1x1@2.4 Ghz + * @CDS_STA_SAP_SCC_24_2x2: STA & SAP connection on SCC using + * 2x2@2.4 Ghz + * @CDS_STA_SAP_MCC_24_1x1: STA & SAP connection on MCC using + * 1x1@2.4 Ghz + * @CDS_STA_SAP_MCC_24_2x2: STA & SAP connection on MCC using + * 2x2@2.4 Ghz + * @CDS_STA_SAP_SCC_5_1x1: STA & SAP connection on SCC using + * 1x1@5 Ghz + * @CDS_STA_SAP_SCC_5_2x2: STA & SAP connection on SCC using + * 2x2@5 Ghz + * @CDS_STA_SAP_MCC_5_1x1: STA & SAP connection on MCC using + * 1x1@5 Ghz + * @CDS_STA_SAP_MCC_5_2x2: STA & SAP connection on MCC using + * 2x2@5 Ghz + * @CDS_STA_SAP_DBS_1x1,: STA & SAP connection on DBS using 1x1 + * @CDS_STA_P2P_GO_SCC_24_1x1: STA & P2P GO connection on SCC + * using 1x1@2.4 Ghz + * @CDS_STA_P2P_GO_SCC_24_2x2: STA & P2P GO connection on SCC + * using 2x2@2.4 Ghz + * @CDS_STA_P2P_GO_MCC_24_1x1: STA & P2P GO connection on MCC + * using 1x1@2.4 Ghz + * @CDS_STA_P2P_GO_MCC_24_2x2: STA & P2P GO connection on MCC + * using 2x2@2.4 Ghz + * @CDS_STA_P2P_GO_SCC_5_1x1: STA & P2P GO connection on SCC + * using 1x1@5 Ghz + * @CDS_STA_P2P_GO_SCC_5_2x2: STA & P2P GO connection on SCC + * using 2x2@5 Ghz + * @CDS_STA_P2P_GO_MCC_5_1x1: STA & P2P GO connection on MCC + * using 1x1@5 Ghz + * @CDS_STA_P2P_GO_MCC_5_2x2: STA & P2P GO connection on MCC + * using 2x2@5 Ghz + * @CDS_STA_P2P_GO_DBS_1x1: STA & P2P GO connection on DBS using + * 1x1 + * @CDS_STA_P2P_CLI_SCC_24_1x1: STA & P2P CLI connection on SCC + * using 1x1@2.4 Ghz + * @CDS_STA_P2P_CLI_SCC_24_2x2: STA & P2P CLI connection on SCC + * using 2x2@2.4 Ghz + * @CDS_STA_P2P_CLI_MCC_24_1x1: STA & P2P CLI connection on MCC + * using 1x1@2.4 Ghz + * @CDS_STA_P2P_CLI_MCC_24_2x2: STA & P2P CLI connection on MCC + * using 2x2@2.4 Ghz + * @CDS_STA_P2P_CLI_SCC_5_1x1: STA & P2P CLI connection on SCC + * using 1x1@5 Ghz + * @CDS_STA_P2P_CLI_SCC_5_2x2: STA & P2P CLI connection on SCC + * using 2x2@5 Ghz + * @CDS_STA_P2P_CLI_MCC_5_1x1: STA & P2P CLI connection on MCC + * using 1x1@5 Ghz + * @CDS_STA_P2P_CLI_MCC_5_2x2: STA & P2P CLI connection on MCC + * using 2x2@5 Ghz + * @CDS_STA_P2P_CLI_DBS_1x1: STA & P2P CLI connection on DBS + * using 1x1 + * @CDS_P2P_GO_P2P_CLI_SCC_24_1x1: P2P GO & CLI connection on + * SCC using 1x1@2.4 Ghz + * @CDS_P2P_GO_P2P_CLI_SCC_24_2x2: P2P GO & CLI connection on + * SCC using 2x2@2.4 Ghz + * @CDS_P2P_GO_P2P_CLI_MCC_24_1x1: P2P GO & CLI connection on + * MCC using 1x1@2.4 Ghz + * @CDS_P2P_GO_P2P_CLI_MCC_24_2x2: P2P GO & CLI connection on + * MCC using 2x2@2.4 Ghz + * @CDS_P2P_GO_P2P_CLI_SCC_5_1x1: P2P GO & CLI connection on + * SCC using 1x1@5 Ghz + * @CDS_P2P_GO_P2P_CLI_SCC_5_2x2: P2P GO & CLI connection on + * SCC using 2x2@5 Ghz + * @CDS_P2P_GO_P2P_CLI_MCC_5_1x1: P2P GO & CLI connection on + * MCC using 1x1@5 Ghz + * @CDS_P2P_GO_P2P_CLI_MCC_5_2x2: P2P GO & CLI connection on + * MCC using 2x2@5 Ghz + * @CDS_P2P_GO_P2P_CLI_DBS_1x1: P2P GO & CLI connection on DBS + * using 1x1 + * @CDS_P2P_GO_SAP_SCC_24_1x1: P2P GO & SAP connection on + * SCC using 1x1@2.4 Ghz + * @CDS_P2P_GO_SAP_SCC_24_2x2: P2P GO & SAP connection on + * SCC using 2x2@2.4 Ghz + * @CDS_P2P_GO_SAP_MCC_24_1x1: P2P GO & SAP connection on + * MCC using 1x1@2.4 Ghz + * @CDS_P2P_GO_SAP_MCC_24_2x2: P2P GO & SAP connection on + * MCC using 2x2@2.4 Ghz + * @CDS_P2P_GO_SAP_SCC_5_1x1: P2P GO & SAP connection on + * SCC using 1x1@5 Ghz + * @CDS_P2P_GO_SAP_SCC_5_2x2: P2P GO & SAP connection on + * SCC using 2x2@5 Ghz + * @CDS_P2P_GO_SAP_MCC_5_1x1: P2P GO & SAP connection on + * MCC using 1x1@5 Ghz + * @CDS_P2P_GO_SAP_MCC_5_2x2: P2P GO & SAP connection on + * MCC using 2x2@5 Ghz + * @CDS_P2P_GO_SAP_DBS_1x1: P2P GO & SAP connection on DBS using + * 1x1 + * @CDS_P2P_CLI_SAP_SCC_24_1x1: CLI & SAP connection on SCC using + * 1x1@2.4 Ghz + * @CDS_P2P_CLI_SAP_SCC_24_2x2: CLI & SAP connection on SCC using + * 2x2@2.4 Ghz + * @CDS_P2P_CLI_SAP_MCC_24_1x1: CLI & SAP connection on MCC using + * 1x1@2.4 Ghz + * @CDS_P2P_CLI_SAP_MCC_24_2x2: CLI & SAP connection on MCC using + * 2x2@2.4 Ghz + * @CDS_P2P_CLI_SAP_SCC_5_1x1: CLI & SAP connection on SCC using + * 1x1@5 Ghz + * @CDS_P2P_CLI_SAP_SCC_5_2x2: CLI & SAP connection on SCC using + * 2x2@5 Ghz + * @CDS_P2P_CLI_SAP_MCC_5_1x1: CLI & SAP connection on MCC using + * 1x1@5 Ghz + * @CDS_P2P_CLI_SAP_MCC_5_2x2: CLI & SAP connection on MCC using + * 2x2@5 Ghz + * @CDS_P2P_STA_SAP_MCC_24_5_1x1: CLI and SAP connecting on MCC + * in 2.4 and 5GHz 1x1 + * @CDS_P2P_STA_SAP_MCC_24_5_2x2: CLI and SAP connecting on MCC + in 2.4 and 5GHz 2x2 + * @CDS_P2P_CLI_SAP_DBS_1x1,: CLI & SAP connection on DBS using 1x1 + + * @CDS_MAX_TWO_CONNECTION_MODE: Max place holder + * + * These are generic IDs that identify the various roles + * in the software system + */ +enum cds_two_connection_mode { + CDS_STA_SAP_SCC_24_1x1 = 0, + CDS_STA_SAP_SCC_24_2x2, + CDS_STA_SAP_MCC_24_1x1, + CDS_STA_SAP_MCC_24_2x2, + CDS_STA_SAP_SCC_5_1x1, + CDS_STA_SAP_SCC_5_2x2, + CDS_STA_SAP_MCC_5_1x1, + CDS_STA_SAP_MCC_5_2x2, + CDS_STA_SAP_MCC_24_5_1x1, + CDS_STA_SAP_MCC_24_5_2x2, + CDS_STA_SAP_DBS_1x1, + CDS_STA_P2P_GO_SCC_24_1x1, + CDS_STA_P2P_GO_SCC_24_2x2, + CDS_STA_P2P_GO_MCC_24_1x1, + CDS_STA_P2P_GO_MCC_24_2x2, + CDS_STA_P2P_GO_SCC_5_1x1, + CDS_STA_P2P_GO_SCC_5_2x2, + CDS_STA_P2P_GO_MCC_5_1x1, + CDS_STA_P2P_GO_MCC_5_2x2, + CDS_STA_P2P_GO_MCC_24_5_1x1, + CDS_STA_P2P_GO_MCC_24_5_2x2, + CDS_STA_P2P_GO_DBS_1x1, + CDS_STA_P2P_CLI_SCC_24_1x1, + CDS_STA_P2P_CLI_SCC_24_2x2, + CDS_STA_P2P_CLI_MCC_24_1x1, + CDS_STA_P2P_CLI_MCC_24_2x2, + CDS_STA_P2P_CLI_SCC_5_1x1, + CDS_STA_P2P_CLI_SCC_5_2x2, + CDS_STA_P2P_CLI_MCC_5_1x1, + CDS_STA_P2P_CLI_MCC_5_2x2, + CDS_STA_P2P_CLI_MCC_24_5_1x1, + CDS_STA_P2P_CLI_MCC_24_5_2x2, + CDS_STA_P2P_CLI_DBS_1x1, + CDS_P2P_GO_P2P_CLI_SCC_24_1x1, + CDS_P2P_GO_P2P_CLI_SCC_24_2x2, + CDS_P2P_GO_P2P_CLI_MCC_24_1x1, + CDS_P2P_GO_P2P_CLI_MCC_24_2x2, + CDS_P2P_GO_P2P_CLI_SCC_5_1x1, + CDS_P2P_GO_P2P_CLI_SCC_5_2x2, + CDS_P2P_GO_P2P_CLI_MCC_5_1x1, + CDS_P2P_GO_P2P_CLI_MCC_5_2x2, + CDS_P2P_GO_P2P_CLI_MCC_24_5_1x1, + CDS_P2P_GO_P2P_CLI_MCC_24_5_2x2, + CDS_P2P_GO_P2P_CLI_DBS_1x1, + CDS_P2P_GO_SAP_SCC_24_1x1, + CDS_P2P_GO_SAP_SCC_24_2x2, + CDS_P2P_GO_SAP_MCC_24_1x1, + CDS_P2P_GO_SAP_MCC_24_2x2, + CDS_P2P_GO_SAP_SCC_5_1x1, + CDS_P2P_GO_SAP_SCC_5_2x2, + CDS_P2P_GO_SAP_MCC_5_1x1, + CDS_P2P_GO_SAP_MCC_5_2x2, + CDS_P2P_GO_SAP_MCC_24_5_1x1, + CDS_P2P_GO_SAP_MCC_24_5_2x2, + CDS_P2P_GO_SAP_DBS_1x1, + CDS_P2P_CLI_SAP_SCC_24_1x1, + CDS_P2P_CLI_SAP_SCC_24_2x2, + CDS_P2P_CLI_SAP_MCC_24_1x1, + CDS_P2P_CLI_SAP_MCC_24_2x2, + CDS_P2P_CLI_SAP_SCC_5_1x1, + CDS_P2P_CLI_SAP_SCC_5_2x2, + CDS_P2P_CLI_SAP_MCC_5_1x1, + CDS_P2P_CLI_SAP_MCC_5_2x2, + CDS_P2P_CLI_SAP_MCC_24_5_1x1, + CDS_P2P_CLI_SAP_MCC_24_5_2x2, + CDS_P2P_CLI_SAP_DBS_1x1, + + CDS_MAX_TWO_CONNECTION_MODE +}; + +/** + * enum cds_conc_next_action - actions to be taken on old + * connections. + * + * @CDS_NOP: No action + * @CDS_DBS: switch to DBS mode + * @CDS_DBS_DOWNGRADE: switch to DBS mode & downgrade to 1x1 + * @CDS_SINGLE_MAC: switch to MCC/SCC mode + * @CDS_SINGLE_MAC_UPGRADE: switch to MCC/SCC mode & upgrade to 2x2 + * @CDS_MAX_CONC_PRIORITY_MODE: Max place holder + * + * These are generic IDs that identify the various roles + * in the software system + */ +enum cds_conc_next_action { + CDS_NOP = 0, + CDS_DBS, + CDS_DBS_DOWNGRADE, + CDS_SINGLE_MAC, + CDS_SINGLE_MAC_UPGRADE, + CDS_MAX_CONC_NEXT_ACTION +}; + +/** + * enum cds_band - wifi band. + * + * @CDS_BAND_24: 2.4 Ghz band + * @CDS_BAND_5: 5 Ghz band + * @CDS_MAX_BAND: Max place holder + * + * These are generic IDs that identify the various roles + * in the software system + */ +enum cds_band { + CDS_BAND_24 = 0, + CDS_BAND_5, + CDS_MAX_BAND +}; + +/** + * enum cds_hw_mode_change - identify the HW mode switching to. + * + * @CDS_HW_MODE_NOT_IN_PROGRESS: HW mode change not in progress + * @CDS_SMM_IN_PROGRESS: switching to SMM mode + * @CDS_DBS_IN_PROGRESS: switching to DBS mode + * @CDS_SBS_IN_PROGRESS: switching to SBS mode + * + * These are generic IDs that identify the various roles + * in the software system + */ +enum cds_hw_mode_change { + CDS_HW_MODE_NOT_IN_PROGRESS = 0, + CDS_SMM_IN_PROGRESS, + CDS_DBS_IN_PROGRESS, + CDS_SBS_IN_PROGRESS +}; + +/** + * struct cds_conc_connection_info - information of all existing + * connections in the wlan system + * + * @mode: connection type + * @chan: channel of the connection + * @bw: channel bandwidth used for the connection + * @mac: The HW mac it is running + * @chain_mask: The original capability advertised by HW + * @original_nss: nss negotiated at connection time + * @vdev_id: vdev id of the connection + * @in_use: if the table entry is active + */ +struct cds_conc_connection_info { + enum cds_con_mode mode; + uint8_t chan; + enum hw_mode_bandwidth bw; + uint8_t mac; + enum cds_chain_mode chain_mask; + uint32_t original_nss; + uint32_t vdev_id; + bool in_use; +}; + +bool cds_is_connection_in_progress(uint8_t *session_id, + scan_reject_states *reason); +void cds_dump_concurrency_info(void); + +#ifdef FEATURE_WLAN_TDLS +bool cds_check_is_tdls_allowed(enum tQDF_ADAPTER_MODE device_mode); +void cds_set_tdls_ct_mode(hdd_context_t *hdd_ctx); +#else +static inline bool cds_check_is_tdls_allowed(enum tQDF_ADAPTER_MODE device_mode) +{ + return false; +} + +static inline void cds_set_tdls_ct_mode(hdd_context_t *hdd_ctx) +{ + +} +#endif + +void cds_set_concurrency_mode(enum tQDF_ADAPTER_MODE mode); +void cds_clear_concurrency_mode(enum tQDF_ADAPTER_MODE mode); +uint32_t cds_get_connection_count(void); +bool cds_is_sta_connection_pending(void); +void cds_change_sta_conn_pending_status(bool value); +void cds_change_sap_restart_required_status(bool value); +bool cds_set_connection_in_progress(bool value); +uint32_t cds_get_concurrency_mode(void); +QDF_STATUS cds_check_and_restart_sap(eCsrRoamResult roam_result, + hdd_station_ctx_t *hdd_sta_ctx); +void cds_handle_conc_rule1(hdd_adapter_t *adapter, + tCsrRoamProfile *roam_profile); +#ifdef FEATURE_WLAN_CH_AVOID +bool cds_handle_conc_rule2(hdd_adapter_t *adapter, + tCsrRoamProfile *roam_profile, + uint32_t *roam_id); +#else +static inline bool cds_handle_conc_rule2(hdd_adapter_t *adapter, + tCsrRoamProfile *roam_profile, + uint32_t *roam_id) +{ + return true; +} +#endif /* FEATURE_WLAN_CH_AVOID */ +uint8_t cds_search_and_check_for_session_conc(uint8_t session_id, + tCsrRoamProfile *roam_profile); +bool cds_check_for_session_conc(uint8_t session_id, uint8_t channel); +QDF_STATUS cds_handle_conc_multiport(uint8_t session_id, uint8_t channel); + +#ifdef FEATURE_WLAN_FORCE_SAP_SCC +void cds_force_sap_on_scc(eCsrRoamResult roam_result, + uint8_t channel_id); +#else +static inline void cds_force_sap_on_scc(eCsrRoamResult roam_result, + uint8_t channel_id) +{ + +} +#endif /* FEATURE_WLAN_FORCE_SAP_SCC */ + +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH +void cds_check_concurrent_intf_and_restart_sap(hdd_adapter_t *adapter); +#else +static inline void cds_check_concurrent_intf_and_restart_sap( + hdd_adapter_t *adapter) +{ + +} +#endif /* FEATURE_WLAN_MCC_TO_SCC_SWITCH */ +uint8_t cds_is_mcc_in_24G(void); +int32_t cds_set_mas(hdd_adapter_t *adapter, uint8_t mas_value); +int cds_set_mcc_p2p_quota(hdd_adapter_t *hostapd_adapter, + uint32_t set_value); +QDF_STATUS cds_change_mcc_go_beacon_interval(hdd_adapter_t *pHostapdAdapter); +int cds_go_set_mcc_p2p_quota(hdd_adapter_t *hostapd_adapter, + uint32_t set_value); +void cds_set_mcc_latency(hdd_adapter_t *adapter, int set_value); +#if defined(FEATURE_WLAN_MCC_TO_SCC_SWITCH) +void cds_change_sap_channel_with_csa(hdd_adapter_t *adapter, + hdd_ap_ctx_t *hdd_ap_ctx); +#else +static inline void cds_change_sap_channel_with_csa(hdd_adapter_t *adapter, + hdd_ap_ctx_t *hdd_ap_ctx) +{ + +} +#endif + +#if defined(FEATURE_WLAN_MCC_TO_SCC_SWITCH) || \ + defined(FEATURE_WLAN_STA_AP_MODE_DFS_DISABLE) +void cds_restart_sap(hdd_adapter_t *ap_adapter); +#else +static inline void cds_restart_sap(hdd_adapter_t *ap_adapter) +{ + +} +#endif /* FEATURE_WLAN_MCC_TO_SCC_SWITCH || + * FEATURE_WLAN_STA_AP_MODE_DFS_DISABLE + */ + +#ifdef FEATURE_WLAN_STA_AP_MODE_DFS_DISABLE +void cds_check_and_restart_sap_with_non_dfs_acs(void); +#else +static inline void cds_check_and_restart_sap_with_non_dfs_acs(void) +{ + +} +#endif /* FEATURE_WLAN_STA_AP_MODE_DFS_DISABLE */ +void cds_incr_active_session(enum tQDF_ADAPTER_MODE mode, + uint8_t sessionId); +QDF_STATUS cds_decr_active_session(enum tQDF_ADAPTER_MODE mode, + uint8_t sessionId); +void cds_decr_session_set_pcl(enum tQDF_ADAPTER_MODE mode, + uint8_t session_id); +QDF_STATUS cds_init_policy_mgr(struct cds_sme_cbacks *sme_cbacks); +QDF_STATUS cds_deinit_policy_mgr(void); +uint8_t cds_get_channel(enum cds_con_mode mode, uint32_t *vdev_id); +QDF_STATUS cds_get_pcl(enum cds_con_mode mode, + uint8_t *pcl_channels, uint32_t *len, + uint8_t *pcl_weight, uint32_t weight_len); +void cds_update_with_safe_channel_list(uint8_t *pcl_channels, uint32_t *len, + uint8_t *weight_list, uint32_t weight_len); +uint8_t cds_get_nondfs_preferred_channel(enum cds_con_mode mode, + bool for_existing_conn); +bool cds_is_any_nondfs_chnl_present(uint8_t *channel); +bool cds_is_any_dfs_beaconing_session_present(uint8_t *channel); +bool cds_allow_concurrency(enum cds_con_mode mode, + uint8_t channel, enum hw_mode_bandwidth bw); +enum cds_conc_priority_mode cds_get_first_connection_pcl_table_index(void); +enum cds_one_connection_mode cds_get_second_connection_pcl_table_index(void); +enum cds_two_connection_mode cds_get_third_connection_pcl_table_index(void); +QDF_STATUS cds_incr_connection_count(uint32_t vdev_id); +QDF_STATUS cds_update_connection_info(uint32_t vdev_id); +QDF_STATUS cds_decr_connection_count(uint32_t vdev_id); +QDF_STATUS cds_current_connections_update(uint32_t session_id, + uint8_t channel, + enum sir_conn_update_reason); +bool cds_is_ibss_conn_exist(uint8_t *ibss_channel); +struct cds_conc_connection_info *cds_get_conn_info(uint32_t *len); +#ifdef MPC_UT_FRAMEWORK +QDF_STATUS cds_incr_connection_count_utfw( + uint32_t vdev_id, uint32_t tx_streams, uint32_t rx_streams, + uint32_t chain_mask, uint32_t type, uint32_t sub_type, + uint32_t channelid, uint32_t mac_id); +QDF_STATUS cds_update_connection_info_utfw( + uint32_t vdev_id, uint32_t tx_streams, uint32_t rx_streams, + uint32_t chain_mask, uint32_t type, uint32_t sub_type, + uint32_t channelid, uint32_t mac_id); +QDF_STATUS cds_decr_connection_count_utfw( + uint32_t del_all, uint32_t vdev_id); +enum cds_pcl_type get_pcl_from_first_conn_table(enum cds_con_mode type, + enum cds_conc_priority_mode sys_pref); +enum cds_pcl_type get_pcl_from_second_conn_table( + enum cds_one_connection_mode idx, enum cds_con_mode type, + enum cds_conc_priority_mode sys_pref, uint8_t dbs_capable); +enum cds_pcl_type get_pcl_from_third_conn_table( + enum cds_two_connection_mode idx, enum cds_con_mode type, + enum cds_conc_priority_mode sys_pref, uint8_t dbs_capable); +#else +static inline QDF_STATUS cds_incr_connection_count_utfw(uint32_t vdev_id, + uint32_t tx_streams, uint32_t rx_streams, + uint32_t chain_mask, uint32_t type, uint32_t sub_type, + uint32_t channelid, uint32_t mac_id) +{ + return QDF_STATUS_SUCCESS; +} +static inline QDF_STATUS cds_update_connection_info_utfw(uint32_t vdev_id, + uint32_t tx_streams, uint32_t rx_streams, + uint32_t chain_mask, uint32_t type, uint32_t sub_type, + uint32_t channelid, uint32_t mac_id) +{ + return QDF_STATUS_SUCCESS; +} +static inline QDF_STATUS cds_decr_connection_count_utfw(uint32_t del_all, + uint32_t vdev_id) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +enum cds_con_mode cds_convert_device_mode_to_qdf_type( + enum tQDF_ADAPTER_MODE device_mode); +QDF_STATUS cds_pdev_set_hw_mode(uint32_t session_id, + enum hw_mode_ss_config mac0_ss, + enum hw_mode_bandwidth mac0_bw, + enum hw_mode_ss_config mac1_ss, + enum hw_mode_bandwidth mac1_bw, + enum hw_mode_dbs_capab dbs, + enum hw_mode_agile_dfs_capab dfs, + enum hw_mode_sbs_capab sbs, + enum sir_conn_update_reason reason); +enum cds_conc_next_action cds_need_opportunistic_upgrade(void); +QDF_STATUS cds_next_actions(uint32_t session_id, + enum cds_conc_next_action action, + enum sir_conn_update_reason reason); +void cds_set_dual_mac_scan_config(uint8_t dbs_val, + uint8_t dbs_plus_agile_scan_val, + uint8_t single_mac_scan_with_dbs_val); +void cds_set_dual_mac_fw_mode_config(uint8_t dbs, + uint8_t dfs); +void cds_soc_set_dual_mac_cfg_cb(enum set_hw_mode_status status, + uint32_t scan_config, + uint32_t fw_mode_config); +bool cds_map_concurrency_mode(enum tQDF_ADAPTER_MODE *old_mode, + enum cds_con_mode *new_mode); +QDF_STATUS cds_get_channel_from_scan_result(hdd_adapter_t *adapter, + tCsrRoamProfile *roam_profile, uint8_t *channel); + +enum tQDF_GLOBAL_CON_MODE cds_get_conparam(void); +bool cds_concurrent_open_sessions_running(void); +bool cds_max_concurrent_connections_reached(void); +void cds_clear_concurrent_session_count(void); +bool cds_is_multiple_active_sta_sessions(void); +bool cds_is_sta_active_connection_exists(void); +bool cds_concurrent_beaconing_sessions_running(void); +QDF_STATUS qdf_wait_for_connection_update(void); +QDF_STATUS qdf_reset_connection_update(void); +QDF_STATUS qdf_set_connection_update(void); +QDF_STATUS qdf_init_connection_update(void); +QDF_STATUS cds_restart_opportunistic_timer(bool check_state); +QDF_STATUS cds_modify_sap_pcl_based_on_mandatory_channel(uint8_t *pcl_list_org, + uint8_t *weight_list_org, + uint32_t *pcl_len_org); +QDF_STATUS cds_update_and_wait_for_connection_update(uint8_t session_id, + uint8_t channel, enum sir_conn_update_reason reason); +bool cds_is_sap_mandatory_channel_set(void); +bool cds_list_has_24GHz_channel(uint8_t *channel_list, uint32_t list_len); +QDF_STATUS cds_get_valid_chans(uint8_t *chan_list, uint32_t *list_len); +QDF_STATUS cds_get_nss_for_vdev(enum cds_con_mode mode, + uint8_t *nss_2g, uint8_t *nss_5g); +QDF_STATUS cds_get_sap_mandatory_channel(uint32_t *chan); +QDF_STATUS cds_set_sap_mandatory_channels(uint8_t *channels, uint32_t len); +QDF_STATUS cds_reset_sap_mandatory_channels(void); +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH +QDF_STATUS cds_register_sap_restart_channel_switch_cb( + void (*sap_restart_chan_switch_cb)(void *, uint32_t, uint32_t)); +QDF_STATUS cds_deregister_sap_restart_channel_switch_cb(void); +#endif +bool cds_is_any_mode_active_on_band_along_with_session(uint8_t session_id, + enum cds_band band); +QDF_STATUS cds_get_chan_by_session_id(uint8_t session_id, uint8_t *chan); +QDF_STATUS cds_get_mac_id_by_session_id(uint8_t session_id, uint8_t *mac_id); +QDF_STATUS cds_get_mcc_session_id_on_mac(uint8_t mac_id, uint8_t session_id, + uint8_t *mcc_session_id); +uint8_t cds_get_mcc_operating_channel(uint8_t session_id); +QDF_STATUS cds_get_pcl_for_existing_conn(enum cds_con_mode mode, + uint8_t *pcl_ch, uint32_t *len, + uint8_t *weight_list, uint32_t weight_len); +QDF_STATUS cds_get_valid_chan_weights(struct sir_pcl_chan_weights *weight); +QDF_STATUS cds_set_hw_mode_on_channel_switch(uint8_t session_id); +void cds_set_do_hw_mode_change_flag(bool flag); +bool cds_is_hw_mode_change_after_vdev_up(void); +void cds_checkn_update_hw_mode_single_mac_mode(uint8_t channel); +void cds_dump_connection_status_info(void); +/** + * cds_mode_specific_vdev_id() - provides the + * vdev id of specific mode + * @mode: type of connection + * + * This function provides the vdev id of specific mode + * + * Note: This gives the first vdev id of the mode type in a + * sta+sta or sap+sap or p2p + p2p case + * + * Return: vdev id of specific type + */ +uint32_t cds_mode_specific_vdev_id(enum cds_con_mode mode); +uint32_t cds_mode_specific_connection_count(enum cds_con_mode mode, + uint32_t *list); +/** + * cds_check_conn_with_mode_and_vdev_id() - checks if any active + * session with specific mode and vdev_id + * @mode: type of connection + * @vdev_id: vdev_id of the connection + * + * This function checks if any active session with specific mode and vdev_id + * is present + * + * Return: QDF STATUS with success if active session is found, else failure + */ +QDF_STATUS cds_check_conn_with_mode_and_vdev_id(enum cds_con_mode mode, + uint32_t vdev_id); +void cds_hw_mode_transition_cb(uint32_t old_hw_mode_index, + uint32_t new_hw_mode_index, + uint32_t num_vdev_mac_entries, + struct sir_vdev_mac_map *vdev_mac_map); +void cds_set_hw_mode_change_in_progress(enum cds_hw_mode_change value); +enum cds_hw_mode_change cds_is_hw_mode_change_in_progress(void); +void cds_enable_disable_sap_mandatory_chan_list(bool val); +void cds_add_sap_mandatory_chan(uint8_t chan); +void cds_remove_sap_mandatory_chan(uint8_t chan); +bool cds_is_sap_mandatory_chan_list_enabled(void); +void cds_init_sap_mandatory_2g_chan(void); +uint32_t cds_get_sap_mandatory_chan_list_len(void); +#endif /* __CDS_CONCURRENCY_H */ diff --git a/drivers/staging/qcacld-3.0/core/cds/inc/cds_config.h b/drivers/staging/qcacld-3.0/core/cds/inc/cds_config.h new file mode 100644 index 0000000000000000000000000000000000000000..3d805d05a64bc281c909160bf19f93aed0c9142d --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/cds/inc/cds_config.h @@ -0,0 +1,181 @@ +/* + * Copyright (c) 2016-2017 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. + */ + +/** + * DOC: cds_config.h + * + * Defines the configuration Information for various modules. Default values + * are read from the INI file and saved into cds_config_info which are passed + * to various modules for the initialization. + */ + +#if !defined(__CDS_CONFIG_H) +#define __CDS_CONFIG_H + +#include "cdp_txrx_cmn.h" +#include "cdp_txrx_cfg.h" + +/** + * enum driver_type - Indicate the driver type to the cds, and based on this + * do appropriate initialization. + * + * @DRIVER_TYPE_PRODUCTION: Driver used in the production + * @DRIVER_TYPE_MFG: Driver used in the Factory + * + */ +enum driver_type { + DRIVER_TYPE_PRODUCTION = 0, + DRIVER_TYPE_MFG = 1, +}; + +/** + * enum cfg_sub_20_channel_width: ini values for su 20 mhz channel width + * @WLAN_SUB_20_CH_WIDTH_5: Use 5 mhz channel width + * @WLAN_SUB_20_CH_WIDTH_10: Use 10 mhz channel width + */ +enum cfg_sub_20_channel_width { + WLAN_SUB_20_CH_WIDTH_NONE = 0, + WLAN_SUB_20_CH_WIDTH_5 = 1, + WLAN_SUB_20_CH_WIDTH_10 = 2, +}; + +/** + * enum active_bpf_mode - the modes active BPF can operate in + * @ACTIVE_BPF_DISABLED: BPF is disabled in active mode + * @ACTIVE_BPF_ENABLED: BPF is enabled for all packets + * @ACTIVE_BPF_ADAPTIVE: BPF is enabled for packets up to some threshold + * @ACTIVE_BPF_MODE_COUNT: The number of active BPF modes + */ +enum active_bpf_mode { + ACTIVE_BPF_DISABLED = 0, + ACTIVE_BPF_ENABLED, + ACTIVE_BPF_ADAPTIVE, + ACTIVE_BPF_MODE_COUNT +}; + +/** + * struct cds_config_info - Place Holder for cds configuration + * @max_station: Max station supported + * @max_bssid: Max Bssid Supported + * @powersave_offload_enabled: Indicate if powersave offload is enabled + * @sta_maxlimod_dtim: station max listen interval + * @sta_mod_dtim: station mode DTIM + * @sta_dynamic_dtim: station dynamic DTIM + * @driver_type: Enumeration of Driver Type whether FTM or Mission mode + * @max_wow_filters: Max wow filters to be configured to fw + * @wow_enable: Indicate whether wow is enabled or not + * @ol_ini_info: Status of offload enabled from ini 1st bit for arm,2nd for NS + * currently rest of bits are not used + * @ssdp: Indicate ssdp is enabled or not + * @enable_mc_list : To Check if Multicast list filtering is enabled in FW + * @dfs_phyerr_filter_offload: DFS Phyerror Filtering offload status from ini + * Indicates whether support is enabled or not + * @ap_disable_intrabss_fwd: pass intra-bss-fwd info to txrx module + * @ap_maxoffload_peers: max offload peer + * @ap_maxoffload_reorderbuffs: max offload reorder buffs + * @ra_ratelimit_interval: RA rate limit value + * @is_ra_ratelimit_enabled: Indicate RA rate limit enabled or not + * @reorder_offload: is RX re-ordering offloaded to the fw + * @dfs_pri_multiplier: dfs radar pri multiplier + * @uc_offload_enabled: IPA Micro controller data path offload enable flag + * @uc_txbuf_count: IPA Micro controller data path offload TX buffer count + * @uc_txbuf_size: IPA Micro controller data path offload TX buffer size + * @uc_rxind_ringcount: IPA Micro controller data path offload RX indication + * ring count + * @uc_tx_partition_base: IPA Micro controller datapath offload TX partition + * base + * @enable_rxthread: Rx processing in thread from TXRX + * @ip_tcp_udp_checksum_offload: checksum offload enabled or not + * @ce_classify_enabled: CE based classification enabled + * @max_scan: Maximum number of parallel scans + * @tx_flow_stop_queue_th: Threshold to stop queue in percentage + * @tx_flow_start_queue_offset: Start queue offset in percentage + * @is_lpass_enabled: Indicate whether LPASS is enabled or not + * @is_nan_enabled: Indicate whether NAN is enabled or not + * @bool bpf_packet_filter_enable; Indicate bpf filter enabled or not + * @tx_chain_mask_cck: Tx chain mask enabled or not + * @self_gen_frm_pwr: Self gen from power + * @sub_20_channel_width: Sub 20 MHz ch width, ini intersected with fw cap + * @flow_steering_enabled: Receive flow steering. + * @is_fw_timeout: Indicate whether crash host when fw timesout or not + * @force_target_assert_enabled: Indicate whether target assert enabled or not + * @active_bpf_mode: Setting that determines how BPF is applied in active mode + * @rps_enabled: RPS enabled in SAP mode + * @ito_repeat_count: Indicates ito repeated count + * Structure for holding cds ini parameters. + */ + +struct cds_config_info { + uint16_t max_station; + uint16_t max_bssid; + uint8_t powersave_offload_enabled; + uint8_t sta_maxlimod_dtim; + uint8_t sta_mod_dtim; + uint8_t sta_dynamic_dtim; + enum driver_type driver_type; + uint8_t max_wow_filters; + uint8_t wow_enable; + uint8_t ol_ini_info; + bool ssdp; + bool enable_mc_list; + uint8_t dfs_phyerr_filter_offload; + uint8_t ap_disable_intrabss_fwd; + uint8_t ap_maxoffload_peers; + uint8_t ap_maxoffload_reorderbuffs; +#ifdef FEATURE_WLAN_RA_FILTERING + uint16_t ra_ratelimit_interval; + bool is_ra_ratelimit_enabled; +#endif + uint8_t reorder_offload; + int32_t dfs_pri_multiplier; + uint8_t uc_offload_enabled; + uint32_t uc_txbuf_count; + uint32_t uc_txbuf_size; + uint32_t uc_rxind_ringcount; + uint32_t uc_tx_partition_base; + bool enable_rxthread; + bool ip_tcp_udp_checksum_offload; + bool ce_classify_enabled; + uint8_t max_scan; +#ifdef QCA_LL_TX_FLOW_CONTROL_V2 + uint32_t tx_flow_stop_queue_th; + uint32_t tx_flow_start_queue_offset; +#endif +#ifdef WLAN_FEATURE_LPSS + bool is_lpass_enabled; +#endif +#ifdef WLAN_FEATURE_NAN + bool is_nan_enabled; +#endif + bool bpf_packet_filter_enable; + bool tx_chain_mask_cck; + uint16_t self_gen_frm_pwr; + enum cfg_sub_20_channel_width sub_20_channel_width; + bool flow_steering_enabled; + bool self_recovery_enabled; + bool fw_timeout_crash; + + struct ol_tx_sched_wrr_ac_specs_t ac_specs[TX_WMM_AC_NUM]; + + bool force_target_assert_enabled; + enum active_bpf_mode active_bpf_mode; + bool rps_enabled; + bool auto_power_save_fail_mode; + uint8_t ito_repeat_count; +}; +#endif /* !defined( __CDS_CONFIG_H ) */ diff --git a/drivers/staging/qcacld-3.0/core/cds/inc/cds_crypto.h b/drivers/staging/qcacld-3.0/core/cds/inc/cds_crypto.h new file mode 100644 index 0000000000000000000000000000000000000000..c3da63bca211605dadc268a7ef791d685b9c1694 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/cds/inc/cds_crypto.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2014-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ +#if !defined(__CDS_CRYPTO_H) +#define __CDS_CRYPTO_H + +/** + * DOC: cds_crypto.h + * + * Crypto APIs + * + */ + +#include + +static inline struct crypto_cipher * +cds_crypto_alloc_cipher(const char *alg_name, u32 type, u32 mask) +{ + return crypto_alloc_cipher(alg_name, type, mask); +} + +static inline void cds_crypto_free_cipher(struct crypto_cipher *tfm) +{ + crypto_free_cipher(tfm); +} + +#endif /* if !defined __CDS_CRYPTO_H */ diff --git a/drivers/staging/qcacld-3.0/core/cds/inc/cds_ieee80211_common.h b/drivers/staging/qcacld-3.0/core/cds/inc/cds_ieee80211_common.h new file mode 100644 index 0000000000000000000000000000000000000000..9b8faf7575c64d68996db25a4b1b42f124d43f3c --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/cds/inc/cds_ieee80211_common.h @@ -0,0 +1,2105 @@ +/* + * Copyright (c) 2011,2014-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef EXTERNAL_USE_ONLY +#include "osdep.h" +#endif /* EXTERNAL_USE_ONLY */ +#include "cds_ieee80211_common_i.h" + +#ifndef CDS_COMMON_IEEE80211_H_ +#define CDS_COMMON_IEEE80211_H_ + +/* + * 802.11 protocol definitions. + */ + +/* is 802.11 address multicast/broadcast? */ +#define IEEE80211_IS_MULTICAST(_a) (*(_a) & 0x01) + +#define IEEE80211_IS_IPV4_MULTICAST(_a) (*(_a) == 0x01) + +#define IEEE80211_IS_IPV6_MULTICAST(_a) \ + ((_a)[0] == 0x33 && \ + (_a)[1] == 0x33) + +#define IEEE80211_IS_BROADCAST(_a) \ + ((_a)[0] == 0xff && \ + (_a)[1] == 0xff && \ + (_a)[2] == 0xff && \ + (_a)[3] == 0xff && \ + (_a)[4] == 0xff && \ + (_a)[5] == 0xff) + +/* IEEE 802.11 PLCP header */ +struct ieee80211_plcp_hdr { + uint16_t i_sfd; + uint8_t i_signal; + uint8_t i_service; + uint16_t i_length; + uint16_t i_crc; +} __packed; + +#define IEEE80211_PLCP_SFD 0xF3A0 +#define IEEE80211_PLCP_SERVICE 0x00 + +/* + * generic definitions for IEEE 802.11 frames + */ +struct ieee80211_frame { + uint8_t i_fc[2]; + uint8_t i_dur[2]; + union { + struct { + uint8_t i_addr1[IEEE80211_ADDR_LEN]; + uint8_t i_addr2[IEEE80211_ADDR_LEN]; + uint8_t i_addr3[IEEE80211_ADDR_LEN]; + }; + uint8_t i_addr_all[3 * IEEE80211_ADDR_LEN]; + }; + uint8_t i_seq[2]; + /* possibly followed by addr4[IEEE80211_ADDR_LEN]; */ + /* see below */ +} __packed; + +struct ieee80211_qosframe { + uint8_t i_fc[2]; + uint8_t i_dur[2]; + uint8_t i_addr1[IEEE80211_ADDR_LEN]; + uint8_t i_addr2[IEEE80211_ADDR_LEN]; + uint8_t i_addr3[IEEE80211_ADDR_LEN]; + uint8_t i_seq[2]; + uint8_t i_qos[2]; + /* possibly followed by addr4[IEEE80211_ADDR_LEN]; */ + /* see below */ +} __packed; + +struct ieee80211_qoscntl { + uint8_t i_qos[2]; +}; + +struct ieee80211_frame_addr4 { + uint8_t i_fc[2]; + uint8_t i_dur[2]; + uint8_t i_addr1[IEEE80211_ADDR_LEN]; + uint8_t i_addr2[IEEE80211_ADDR_LEN]; + uint8_t i_addr3[IEEE80211_ADDR_LEN]; + uint8_t i_seq[2]; + uint8_t i_addr4[IEEE80211_ADDR_LEN]; +} __packed; + +struct ieee80211_qosframe_addr4 { + uint8_t i_fc[2]; + uint8_t i_dur[2]; + uint8_t i_addr1[IEEE80211_ADDR_LEN]; + uint8_t i_addr2[IEEE80211_ADDR_LEN]; + uint8_t i_addr3[IEEE80211_ADDR_LEN]; + uint8_t i_seq[2]; + uint8_t i_addr4[IEEE80211_ADDR_LEN]; + uint8_t i_qos[2]; +} __packed; + +/* HTC frame for TxBF*/ +/* for TxBF RC */ +struct ieee80211_frame_min_one { + uint8_t i_fc[2]; + uint8_t i_dur[2]; + uint8_t i_addr1[IEEE80211_ADDR_LEN]; + +} __packed; /* For TxBF RC */ + +struct ieee80211_qosframe_htc { + uint8_t i_fc[2]; + uint8_t i_dur[2]; + uint8_t i_addr1[IEEE80211_ADDR_LEN]; + uint8_t i_addr2[IEEE80211_ADDR_LEN]; + uint8_t i_addr3[IEEE80211_ADDR_LEN]; + uint8_t i_seq[2]; + uint8_t i_qos[2]; + uint8_t i_htc[4]; + /* possibly followed by addr4[IEEE80211_ADDR_LEN]; */ + /* see below */ +} __packed; +struct ieee80211_qosframe_htc_addr4 { + uint8_t i_fc[2]; + uint8_t i_dur[2]; + uint8_t i_addr1[IEEE80211_ADDR_LEN]; + uint8_t i_addr2[IEEE80211_ADDR_LEN]; + uint8_t i_addr3[IEEE80211_ADDR_LEN]; + uint8_t i_seq[2]; + uint8_t i_addr4[IEEE80211_ADDR_LEN]; + uint8_t i_qos[2]; + uint8_t i_htc[4]; +} __packed; +struct ieee80211_htc { + uint8_t i_htc[4]; +}; +/*HTC frame for TxBF*/ + +struct ieee80211_ctlframe_addr2 { + uint8_t i_fc[2]; + uint8_t i_aidordur[2]; /* AID or duration */ + uint8_t i_addr1[IEEE80211_ADDR_LEN]; + uint8_t i_addr2[IEEE80211_ADDR_LEN]; +} __packed; + +#define IEEE80211_WHQ(wh) ((struct ieee80211_qosframe *)(wh)) +#define IEEE80211_WH4(wh) ((struct ieee80211_frame_addr4 *)(wh)) +#define IEEE80211_WHQ4(wh) ((struct ieee80211_qosframe_addr4 *)(wh)) + +#define IEEE80211_FC0_VERSION_MASK 0x03 +#define IEEE80211_FC0_VERSION_SHIFT 0 +#define IEEE80211_FC0_VERSION_0 0x00 +#define IEEE80211_FC0_TYPE_MASK 0x0c +#define IEEE80211_FC0_TYPE_SHIFT 2 +#define IEEE80211_FC0_TYPE_MGT 0x00 +#define IEEE80211_FC0_TYPE_CTL 0x04 +#define IEEE80211_FC0_TYPE_DATA 0x08 + +#define IEEE80211_FC0_SUBTYPE_MASK 0xf0 +#define IEEE80211_FC0_SUBTYPE_SHIFT 4 +/* for TYPE_MGT */ +#define IEEE80211_FC0_SUBTYPE_ASSOC_REQ 0x00 +#define IEEE80211_FC0_SUBTYPE_ASSOC_RESP 0x10 +#define IEEE80211_FC0_SUBTYPE_REASSOC_REQ 0x20 +#define IEEE80211_FC0_SUBTYPE_REASSOC_RESP 0x30 +#define IEEE80211_FC0_SUBTYPE_PROBE_REQ 0x40 +#define IEEE80211_FC0_SUBTYPE_PROBE_RESP 0x50 +#define IEEE80211_FC0_SUBTYPE_BEACON 0x80 +#define IEEE80211_FC0_SUBTYPE_ATIM 0x90 +#define IEEE80211_FC0_SUBTYPE_DISASSOC 0xa0 +#define IEEE80211_FC0_SUBTYPE_AUTH 0xb0 +#define IEEE80211_FC0_SUBTYPE_DEAUTH 0xc0 +#define IEEE80211_FC0_SUBTYPE_ACTION 0xd0 +#define IEEE80211_FCO_SUBTYPE_ACTION_NO_ACK 0xe0 +/* for TYPE_CTL */ +#define IEEE80211_FCO_SUBTYPE_Control_Wrapper 0x70 /* For TxBF RC */ +#define IEEE80211_FC0_SUBTYPE_BAR 0x80 +#define IEEE80211_FC0_SUBTYPE_PS_POLL 0xa0 +#define IEEE80211_FC0_SUBTYPE_RTS 0xb0 +#define IEEE80211_FC0_SUBTYPE_CTS 0xc0 +#define IEEE80211_FC0_SUBTYPE_ACK 0xd0 +#define IEEE80211_FC0_SUBTYPE_CF_END 0xe0 +#define IEEE80211_FC0_SUBTYPE_CF_END_ACK 0xf0 +/* for TYPE_DATA (bit combination) */ +#define IEEE80211_FC0_SUBTYPE_DATA 0x00 +#define IEEE80211_FC0_SUBTYPE_CF_ACK 0x10 +#define IEEE80211_FC0_SUBTYPE_CF_POLL 0x20 +#define IEEE80211_FC0_SUBTYPE_CF_ACPL 0x30 +#define IEEE80211_FC0_SUBTYPE_NODATA 0x40 +#define IEEE80211_FC0_SUBTYPE_CFACK 0x50 +#define IEEE80211_FC0_SUBTYPE_CFPOLL 0x60 +#define IEEE80211_FC0_SUBTYPE_CF_ACK_CF_ACK 0x70 +#define IEEE80211_FC0_SUBTYPE_QOS 0x80 +#define IEEE80211_FC0_SUBTYPE_QOS_NULL 0xc0 + +#define IEEE80211_FC1_DIR_MASK 0x03 +#define IEEE80211_FC1_DIR_NODS 0x00 /* STA->STA */ +#define IEEE80211_FC1_DIR_TODS 0x01 /* STA->AP */ +#define IEEE80211_FC1_DIR_FROMDS 0x02 /* AP ->STA */ +#define IEEE80211_FC1_DIR_DSTODS 0x03 /* AP ->AP */ + +#define IEEE80211_FC1_MORE_FRAG 0x04 +#define IEEE80211_FC1_RETRY 0x08 +#define IEEE80211_FC1_PWR_MGT 0x10 +#define IEEE80211_FC1_MORE_DATA 0x20 +#define IEEE80211_FC1_WEP 0x40 +#define IEEE80211_FC1_ORDER 0x80 + +#define IEEE80211_SEQ_FRAG_MASK 0x000f +#define IEEE80211_SEQ_FRAG_SHIFT 0 +#define IEEE80211_SEQ_SEQ_MASK 0xfff0 +#define IEEE80211_SEQ_SEQ_SHIFT 4 +#define IEEE80211_SEQ_MAX 4096 + +#define IEEE80211_SEQ_LEQ(a,b) ((int)((a)-(b)) <= 0) + +#define IEEE80211_QOS_TXOP 0x00ff + +#define IEEE80211_QOS_AMSDU 0x80 +#define IEEE80211_QOS_AMSDU_S 7 +#define IEEE80211_QOS_ACKPOLICY 0x60 +#define IEEE80211_QOS_ACKPOLICY_S 5 +#define IEEE80211_QOS_EOSP 0x10 +#define IEEE80211_QOS_EOSP_S 4 +#define IEEE80211_QOS_TID 0x0f +#define IEEE80211_MFP_TID 0xff + +#define IEEE80211_HTC0_TRQ 0x02 +#define IEEE80211_HTC2_CalPos 0x03 +#define IEEE80211_HTC2_CalSeq 0x0C +#define IEEE80211_HTC2_CSI_NONCOMP_BF 0x80 +#define IEEE80211_HTC2_CSI_COMP_BF 0xc0 + +/* Set bits 14 and 15 to 1 when duration field carries Association ID */ +#define IEEE80211_FIELD_TYPE_AID 0xC000 + +#define IEEE80211_IS_BEACON(_frame) ((((_frame)->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_MGT) && \ + (((_frame)->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) == IEEE80211_FC0_SUBTYPE_BEACON)) +#define IEEE80211_IS_DATA(_frame) (((_frame)->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_DATA) + +#define IEEE80211_IS_MFP_FRAME(_frame) ((((_frame)->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_MGT) && \ + ((_frame)->i_fc[1] & IEEE80211_FC1_WEP) && \ + ((((_frame)->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) == IEEE80211_FC0_SUBTYPE_DEAUTH) || \ + (((_frame)->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) == IEEE80211_FC0_SUBTYPE_DISASSOC) || \ + (((_frame)->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) == IEEE80211_FC0_SUBTYPE_ACTION))) +#define IEEE80211_IS_AUTH(_frame) ((((_frame)->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_MGT) && \ + (((_frame)->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) == IEEE80211_FC0_SUBTYPE_AUTH)) + +/* MCS Set */ +#define IEEE80211_RX_MCS_1_STREAM_BYTE_OFFSET 0 +#define IEEE80211_RX_MCS_2_STREAM_BYTE_OFFSET 1 +#define IEEE80211_RX_MCS_3_STREAM_BYTE_OFFSET 2 +#define IEEE80211_RX_MCS_ALL_NSTREAM_RATES 0xff +#define IEEE80211_TX_MCS_OFFSET 12 + +#define IEEE80211_TX_MCS_SET_DEFINED 0x80 +#define IEEE80211_TX_RX_MCS_SET_NOT_EQUAL 0x40 +#define IEEE80211_TX_1_SPATIAL_STREAMS 0x0 +#define IEEE80211_TX_2_SPATIAL_STREAMS 0x10 +#define IEEE80211_TX_3_SPATIAL_STREAMS 0x20 +#define IEEE80211_TX_4_SPATIAL_STREAMS 0x30 + +#define IEEE80211_TX_MCS_SET 0xf8 + +/* + * Subtype data: If bit 6 is set then the data frame contains no actual data. + */ +#define IEEE80211_FC0_SUBTYPE_NO_DATA_MASK 0x40 +#define IEEE80211_CONTAIN_DATA(_subtype) \ + (!((_subtype) & IEEE80211_FC0_SUBTYPE_NO_DATA_MASK)) + +#define IEEE8023_MAX_LEN 0x600 /* 1536 - larger is Ethernet II */ +#define RFC1042_SNAP_ORGCODE_0 0x00 +#define RFC1042_SNAP_ORGCODE_1 0x00 +#define RFC1042_SNAP_ORGCODE_2 0x00 + +#define BTEP_SNAP_ORGCODE_0 0x00 +#define BTEP_SNAP_ORGCODE_1 0x00 +#define BTEP_SNAP_ORGCODE_2 0xf8 + +/* BT 3.0 */ +#define BTAMP_SNAP_ORGCODE_0 0x00 +#define BTAMP_SNAP_ORGCODE_1 0x19 +#define BTAMP_SNAP_ORGCODE_2 0x58 + +/* Aironet OUI Codes */ +#define AIRONET_SNAP_CODE_0 0x00 +#define AIRONET_SNAP_CODE_1 0x40 +#define AIRONET_SNAP_CODE_2 0x96 + +#define IEEE80211_LSIG_LEN 3 +#define IEEE80211_HTSIG_LEN 6 +#define IEEE80211_SB_LEN 2 + +/* + * Information element header format + */ +struct ieee80211_ie_header { + uint8_t element_id; /* Element Id */ + uint8_t length; /* IE Length */ +} __packed; + +/* + * Country information element. + */ +#define IEEE80211_COUNTRY_MAX_TRIPLETS (83) +struct ieee80211_ie_country { + uint8_t country_id; + uint8_t country_len; + uint8_t country_str[3]; + uint8_t country_triplet[IEEE80211_COUNTRY_MAX_TRIPLETS * 3]; +} __packed; + +/* does frame have QoS sequence control data */ +#define IEEE80211_QOS_HAS_SEQ(wh) \ + (((wh)->i_fc[0] & \ + (IEEE80211_FC0_TYPE_MASK | IEEE80211_FC0_SUBTYPE_QOS)) == \ + (IEEE80211_FC0_TYPE_DATA | IEEE80211_FC0_SUBTYPE_QOS)) + +#define WME_QOSINFO_UAPSD 0x80 /* Mask for U-APSD field */ +#define WME_QOSINFO_COUNT 0x0f /* Mask for Param Set Count field */ +/* + * WME/802.11e information element. + */ +struct ieee80211_ie_wme { + uint8_t wme_id; /* IEEE80211_ELEMID_VENDOR */ + uint8_t wme_len; /* length in bytes */ + uint8_t wme_oui[3]; /* 0x00, 0x50, 0xf2 */ + uint8_t wme_type; /* OUI type */ + uint8_t wme_subtype; /* OUI subtype */ + uint8_t wme_version; /* spec revision */ + uint8_t wme_info; /* QoS info */ +} __packed; + +/* + * TS INFO part of the tspec element is a collection of bit flags + */ +#if _BYTE_ORDER == _BIG_ENDIAN +struct ieee80211_tsinfo_bitmap { + uint8_t one : 1, direction : 2, tid : 4, reserved1 : 1; + uint8_t reserved2 : 2, dot1Dtag : 3, psb : 1, reserved3 : 1, zero : 1; + uint8_t reserved5 : 7, reserved4 : 1; +} __packed; +#else +struct ieee80211_tsinfo_bitmap { + uint8_t reserved1 : 1, tid : 4, direction : 2, one : 1; + uint8_t zero : 1, reserved3 : 1, psb : 1, dot1Dtag : 3, reserved2 : 2; + uint8_t reserved4 : 1, reserved5 : 7; +} __packed; +#endif + +/* + * WME/802.11e Tspec Element + */ +struct ieee80211_wme_tspec { + uint8_t ts_id; + uint8_t ts_len; + uint8_t ts_oui[3]; + uint8_t ts_oui_type; + uint8_t ts_oui_subtype; + uint8_t ts_version; + uint8_t ts_tsinfo[3]; + uint8_t ts_nom_msdu[2]; + uint8_t ts_max_msdu[2]; + uint8_t ts_min_svc[4]; + uint8_t ts_max_svc[4]; + uint8_t ts_inactv_intv[4]; + uint8_t ts_susp_intv[4]; + uint8_t ts_start_svc[4]; + uint8_t ts_min_rate[4]; + uint8_t ts_mean_rate[4]; + uint8_t ts_peak_rate[4]; + uint8_t ts_max_burst[4]; + uint8_t ts_delay[4]; + uint8_t ts_min_phy[4]; + uint8_t ts_surplus[2]; + uint8_t ts_medium_time[2]; +} __packed; + +/* + * WME AC parameter field + */ +struct ieee80211_wme_acparams { + uint8_t acp_aci_aifsn; + uint8_t acp_logcwminmax; + uint16_t acp_txop; +} __packed; + +#define IEEE80211_WME_PARAM_LEN 24 +#define WME_NUM_AC 4 /* 4 AC categories */ + +#define WME_PARAM_ACI 0x60 /* Mask for ACI field */ +#define WME_PARAM_ACI_S 5 /* Shift for ACI field */ +#define WME_PARAM_ACM 0x10 /* Mask for ACM bit */ +#define WME_PARAM_ACM_S 4 /* Shift for ACM bit */ +#define WME_PARAM_AIFSN 0x0f /* Mask for aifsn field */ +#define WME_PARAM_AIFSN_S 0 /* Shift for aifsn field */ +#define WME_PARAM_LOGCWMIN 0x0f /* Mask for CwMin field (in log) */ +#define WME_PARAM_LOGCWMIN_S 0 /* Shift for CwMin field */ +#define WME_PARAM_LOGCWMAX 0xf0 /* Mask for CwMax field (in log) */ +#define WME_PARAM_LOGCWMAX_S 4 /* Shift for CwMax field */ + +#define WME_AC_TO_TID(_ac) ( \ + ((_ac) == WME_AC_VO) ? 6 : \ + ((_ac) == WME_AC_VI) ? 5 : \ + ((_ac) == WME_AC_BK) ? 1 : \ + 0) + +#define TID_TO_WME_AC(_tid) ( \ + (((_tid) == 0) || ((_tid) == 3)) ? WME_AC_BE : \ + (((_tid) == 1) || ((_tid) == 2)) ? WME_AC_BK : \ + (((_tid) == 4) || ((_tid) == 5)) ? WME_AC_VI : \ + WME_AC_VO) + +/* + * WME Parameter Element + */ +struct ieee80211_wme_param { + uint8_t param_id; + uint8_t param_len; + uint8_t param_oui[3]; + uint8_t param_oui_type; + uint8_t param_oui_sybtype; + uint8_t param_version; + uint8_t param_qosInfo; + uint8_t param_reserved; + struct ieee80211_wme_acparams params_acParams[WME_NUM_AC]; +} __packed; + +/* + * WME U-APSD qos info field defines + */ +#define WME_CAPINFO_UAPSD_EN 0x00000080 +#define WME_CAPINFO_UAPSD_VO 0x00000001 +#define WME_CAPINFO_UAPSD_VI 0x00000002 +#define WME_CAPINFO_UAPSD_BK 0x00000004 +#define WME_CAPINFO_UAPSD_BE 0x00000008 +#define WME_CAPINFO_UAPSD_ACFLAGS_SHIFT 0 +#define WME_CAPINFO_UAPSD_ACFLAGS_MASK 0xF +#define WME_CAPINFO_UAPSD_MAXSP_SHIFT 5 +#define WME_CAPINFO_UAPSD_MAXSP_MASK 0x3 +#define WME_CAPINFO_IE_OFFSET 8 +#define WME_UAPSD_MAXSP(_qosinfo) (((_qosinfo) >> WME_CAPINFO_UAPSD_MAXSP_SHIFT) & WME_CAPINFO_UAPSD_MAXSP_MASK) +#define WME_UAPSD_AC_ENABLED(_ac, _qosinfo) ( (1<<(3 - (_ac))) & \ + (((_qosinfo) >> WME_CAPINFO_UAPSD_ACFLAGS_SHIFT) & WME_CAPINFO_UAPSD_ACFLAGS_MASK) ) + +/* Mask used to determined whether all queues are UAPSD-enabled */ +#define WME_CAPINFO_UAPSD_ALL (WME_CAPINFO_UAPSD_VO | \ + WME_CAPINFO_UAPSD_VI | \ + WME_CAPINFO_UAPSD_BK | \ + WME_CAPINFO_UAPSD_BE) +#define WME_CAPINFO_UAPSD_NONE 0 + +#define WME_UAPSD_AC_MAX_VAL 1 +#define WME_UAPSD_AC_INVAL WME_UAPSD_AC_MAX_VAL+1 + +/* + * Atheros Advanced Capability information element. + */ +struct ieee80211_ie_athAdvCap { + uint8_t athAdvCap_id; /* IEEE80211_ELEMID_VENDOR */ + uint8_t athAdvCap_len; /* length in bytes */ + uint8_t athAdvCap_oui[3]; /* 0x00, 0x03, 0x7f */ + uint8_t athAdvCap_type; /* OUI type */ + uint16_t athAdvCap_version; /* spec revision */ + uint8_t athAdvCap_capability; /* Capability info */ + uint16_t athAdvCap_defKeyIndex; +} __packed; + +/* + * Atheros Extended Capability information element. + */ +struct ieee80211_ie_ath_extcap { + uint8_t ath_extcap_id; /* IEEE80211_ELEMID_VENDOR */ + uint8_t ath_extcap_len; /* length in bytes */ + uint8_t ath_extcap_oui[3]; /* 0x00, 0x03, 0x7f */ + uint8_t ath_extcap_type; /* OUI type */ + uint8_t ath_extcap_subtype; /* OUI subtype */ + uint8_t ath_extcap_version; /* spec revision */ + uint32_t ath_extcap_extcap : 16, /* B0-15 extended capabilities */ + ath_extcap_weptkipaggr_rxdelim : 8, /* B16-23 num delimiters for receiving WEP/TKIP aggregates */ + ath_extcap_reserved : 8; /* B24-31 reserved */ +} __packed; + +/* + * Atheros XR information element. + */ +struct ieee80211_xr_param { + uint8_t param_id; + uint8_t param_len; + uint8_t param_oui[3]; + uint8_t param_oui_type; + uint8_t param_oui_sybtype; + uint8_t param_version; + uint8_t param_Info; + uint8_t param_base_bssid[IEEE80211_ADDR_LEN]; + uint8_t param_xr_bssid[IEEE80211_ADDR_LEN]; + uint16_t param_xr_beacon_interval; + uint8_t param_base_ath_capability; + uint8_t param_xr_ath_capability; +} __packed; + +/* + * SFA information element. + */ +struct ieee80211_ie_sfa { + uint8_t sfa_id; /* IEEE80211_ELEMID_VENDOR */ + uint8_t sfa_len; /* length in bytes */ + uint8_t sfa_oui[3]; /* 0x00, 0x40, 0x96 */ + uint8_t sfa_type; /* OUI type */ + uint8_t sfa_caps; /* Capabilities */ +} __packed; + +/* Atheros capabilities */ +#define IEEE80211_ATHC_TURBOP 0x0001 /* Turbo Prime */ +#define IEEE80211_ATHC_COMP 0x0002 /* Compression */ +#define IEEE80211_ATHC_FF 0x0004 /* Fast Frames */ +#define IEEE80211_ATHC_XR 0x0008 /* Xtended Range support */ +#define IEEE80211_ATHC_AR 0x0010 /* Advanced Radar support */ +#define IEEE80211_ATHC_BURST 0x0020 /* Bursting - not negotiated */ +#define IEEE80211_ATHC_WME 0x0040 /* CWMin tuning */ +#define IEEE80211_ATHC_BOOST 0x0080 /* Boost */ +#define IEEE80211_ATHC_TDLS 0x0100 /* TDLS */ + +/* Atheros extended capabilities */ +/* OWL device capable of WDS workaround */ +#define IEEE80211_ATHEC_OWLWDSWAR 0x0001 +#define IEEE80211_ATHEC_WEPTKIPAGGR 0x0002 +#define IEEE80211_ATHEC_EXTRADELIMWAR 0x0004 +/* + * Management Frames + */ + +/* + * *** Platform-specific code?? *** + * In Vista one must use bit fields of type (unsigned short = uint16_t) to + * ensure data structure is of the correct size. ANSI C used to specify only + * "int" bit fields, which led to a larger structure size in Windows (32 bits). + * + * We must make sure the following construction is valid in all OS's. + */ +union ieee80211_capability { + struct { + uint16_t ess : 1; + uint16_t ibss : 1; + uint16_t cf_pollable : 1; + uint16_t cf_poll_request : 1; + uint16_t privacy : 1; + uint16_t short_preamble : 1; + uint16_t pbcc : 1; + uint16_t channel_agility : 1; + uint16_t spectrum_management : 1; + uint16_t qos : 1; + uint16_t short_slot_time : 1; + uint16_t apsd : 1; + uint16_t reserved2 : 1; + uint16_t dsss_ofdm : 1; + uint16_t del_block_ack : 1; + uint16_t immed_block_ack : 1; + }; + + uint16_t value; +} __packed; + +struct ieee80211_beacon_frame { + uint8_t timestamp[8]; /* the value of sender's TSFTIMER */ + uint16_t beacon_interval; /* the number of time units between target beacon transmission times */ + union ieee80211_capability capability; +/* Value of capability for every bit + #define IEEE80211_CAPINFO_ESS 0x0001 + #define IEEE80211_CAPINFO_IBSS 0x0002 + #define IEEE80211_CAPINFO_CF_POLLABLE 0x0004 + #define IEEE80211_CAPINFO_CF_POLLREQ 0x0008 + #define IEEE80211_CAPINFO_PRIVACY 0x0010 + #define IEEE80211_CAPINFO_SHORT_PREAMBLE 0x0020 + #define IEEE80211_CAPINFO_PBCC 0x0040 + #define IEEE80211_CAPINFO_CHNL_AGILITY 0x0080 + #define IEEE80211_CAPINFO_SPECTRUM_MGMT 0x0100 + #define IEEE80211_CAPINFO_QOS 0x0200 + #define IEEE80211_CAPINFO_SHORT_SLOTTIME 0x0400 + #define IEEE80211_CAPINFO_APSD 0x0800 + #define IEEE80211_CAPINFO_RADIOMEAS 0x1000 + #define IEEE80211_CAPINFO_DSSSOFDM 0x2000 + bits 14-15 are reserved + */ + struct ieee80211_ie_header info_elements; +} __packed; + +/* + * Management Action Frames + */ + +/* generic frame format */ +struct ieee80211_action { + uint8_t ia_category; + uint8_t ia_action; +} __packed; + +/* spectrum action frame header */ +struct ieee80211_action_measrep_header { + struct ieee80211_action action_header; + uint8_t dialog_token; +} __packed; + +/* categories */ +#define IEEE80211_ACTION_CAT_SPECTRUM 0 /* Spectrum management */ +#define IEEE80211_ACTION_CAT_QOS 1 /* IEEE QoS */ +#define IEEE80211_ACTION_CAT_DLS 2 /* DLS */ +#define IEEE80211_ACTION_CAT_BA 3 /* BA */ +#define IEEE80211_ACTION_CAT_PUBLIC 4 /* Public Action Frame */ +#define IEEE80211_ACTION_CAT_HT 7 /* HT per IEEE802.11n-D1.06 */ +#define IEEE80211_ACTION_CAT_SA_QUERY 8 /* SA Query per IEEE802.11w, PMF */ +#define IEEE80211_ACTION_CAT_WMM_QOS 17 /* QoS from WMM specification */ +#define IEEE80211_ACTION_CAT_VHT 21 /* VHT Action */ + +/* Spectrum Management actions */ +#define IEEE80211_ACTION_MEAS_REQUEST 0 /* Measure channels */ +#define IEEE80211_ACTION_MEAS_REPORT 1 +#define IEEE80211_ACTION_TPC_REQUEST 2 /* Transmit Power control */ +#define IEEE80211_ACTION_TPC_REPORT 3 +#define IEEE80211_ACTION_CHAN_SWITCH 4 /* 802.11h Channel Switch Announcement */ + +/* HT actions */ +#define IEEE80211_ACTION_HT_TXCHWIDTH 0 /* recommended transmission channel width */ +#define IEEE80211_ACTION_HT_SMPOWERSAVE 1 /* Spatial Multiplexing (SM) Power Save */ +#define IEEE80211_ACTION_HT_CSI 4 /* CSI Frame */ +#define IEEE80211_ACTION_HT_NONCOMP_BF 5 /* Non-compressed Beamforming */ +#define IEEE80211_ACTION_HT_COMP_BF 6 /* Compressed Beamforming */ + +/* VHT actions */ +#define IEEE80211_ACTION_VHT_OPMODE 2 /* Operating mode notification */ + +/* Spectrum channel switch action frame after IE*/ +/* Public Actions*/ +#define IEEE80211_ACTION_TDLS_DISCRESP 14 /* TDLS Discovery Response frame */ + +/* HT - recommended transmission channel width */ +struct ieee80211_action_ht_txchwidth { + struct ieee80211_action at_header; + uint8_t at_chwidth; +} __packed; + +#define IEEE80211_A_HT_TXCHWIDTH_20 0 +#define IEEE80211_A_HT_TXCHWIDTH_2040 1 + +/* HT - Spatial Multiplexing (SM) Power Save */ +struct ieee80211_action_ht_smpowersave { + struct ieee80211_action as_header; + uint8_t as_control; +} __packed; + +/*HT - CSI Frame */ /* for TxBF RC */ +#define MIMO_CONTROL_LEN 6 +struct ieee80211_action_ht_CSI { + struct ieee80211_action as_header; + uint8_t mimo_control[MIMO_CONTROL_LEN]; +} __packed; + +/*HT - V/CV report frame*/ +struct ieee80211_action_ht_txbf_rpt { + struct ieee80211_action as_header; + uint8_t mimo_control[MIMO_CONTROL_LEN]; +} __packed; + +/* + * 802.11ac Operating Mode Notification + */ +struct ieee80211_ie_op_mode { +#if _BYTE_ORDER == _BIG_ENDIAN + uint8_t rx_nss_type : 1, rx_nss : 3, reserved : 2, ch_width : 2; +#else + uint8_t ch_width : 2, reserved : 2, rx_nss : 3, rx_nss_type : 1; +#endif +} __packed; + +struct ieee80211_ie_op_mode_ntfy { + uint8_t elem_id; + uint8_t elem_len; + struct ieee80211_ie_op_mode opmode; +} __packed; + +/* VHT - recommended Channel width and Nss */ +struct ieee80211_action_vht_opmode { + struct ieee80211_action at_header; + struct ieee80211_ie_op_mode at_op_mode; +} __packed; + +/* values defined for 'as_control' field per 802.11n-D1.06 */ +#define IEEE80211_A_HT_SMPOWERSAVE_DISABLED 0x00 /* SM Power Save Disabled, SM packets ok */ +#define IEEE80211_A_HT_SMPOWERSAVE_ENABLED 0x01 /* SM Power Save Enabled bit */ +#define IEEE80211_A_HT_SMPOWERSAVE_MODE 0x02 /* SM Power Save Mode bit */ +#define IEEE80211_A_HT_SMPOWERSAVE_RESERVED 0xFC /* SM Power Save Reserved bits */ + +/* values defined for SM Power Save Mode bit */ +#define IEEE80211_A_HT_SMPOWERSAVE_STATIC 0x00 /* Static, SM packets not ok */ +#define IEEE80211_A_HT_SMPOWERSAVE_DYNAMIC 0x02 /* Dynamic, SM packets ok if preceded by RTS */ + +/* DLS actions */ +#define IEEE80211_ACTION_DLS_REQUEST 0 +#define IEEE80211_ACTION_DLS_RESPONSE 1 +#define IEEE80211_ACTION_DLS_TEARDOWN 2 + +struct ieee80211_dls_request { + struct ieee80211_action hdr; + uint8_t dst_addr[IEEE80211_ADDR_LEN]; + uint8_t src_addr[IEEE80211_ADDR_LEN]; + uint16_t capa_info; + uint16_t timeout; +} __packed; + +struct ieee80211_dls_response { + struct ieee80211_action hdr; + uint16_t statuscode; + uint8_t dst_addr[IEEE80211_ADDR_LEN]; + uint8_t src_addr[IEEE80211_ADDR_LEN]; +} __packed; + +/* BA actions */ +#define IEEE80211_ACTION_BA_ADDBA_REQUEST 0 /* ADDBA request */ +#define IEEE80211_ACTION_BA_ADDBA_RESPONSE 1 /* ADDBA response */ +#define IEEE80211_ACTION_BA_DELBA 2 /* DELBA */ + +struct ieee80211_ba_parameterset { +#if _BYTE_ORDER == _BIG_ENDIAN + uint16_t buffersize : 10, /* B6-15 buffer size */ + tid : 4, /* B2-5 TID */ + bapolicy : 1, /* B1 block ack policy */ + amsdusupported : 1; /* B0 amsdu supported */ +#else + uint16_t amsdusupported : 1, /* B0 amsdu supported */ + bapolicy : 1, /* B1 block ack policy */ + tid : 4, /* B2-5 TID */ + buffersize : 10; /* B6-15 buffer size */ +#endif +} __packed; + +#define IEEE80211_BA_POLICY_DELAYED 0 +#define IEEE80211_BA_POLICY_IMMEDIATE 1 +#define IEEE80211_BA_AMSDU_SUPPORTED 1 + +struct ieee80211_ba_seqctrl { +#if _BYTE_ORDER == _BIG_ENDIAN + uint16_t startseqnum : 12, /* B4-15 starting sequence number */ + fragnum : 4; /* B0-3 fragment number */ +#else + uint16_t fragnum : 4, /* B0-3 fragment number */ + startseqnum : 12; /* B4-15 starting sequence number */ +#endif +} __packed; + +struct ieee80211_delba_parameterset { +#if _BYTE_ORDER == _BIG_ENDIAN + uint16_t tid : 4, /* B12-15 tid */ + initiator : 1, /* B11 initiator */ + reserved0 : 11; /* B0-10 reserved */ +#else + uint16_t reserved0 : 11, /* B0-10 reserved */ + initiator : 1, /* B11 initiator */ + tid : 4; /* B12-15 tid */ +#endif +} __packed; + +/* BA - ADDBA request */ +struct ieee80211_action_ba_addbarequest { + struct ieee80211_action rq_header; + uint8_t rq_dialogtoken; + struct ieee80211_ba_parameterset rq_baparamset; + uint16_t rq_batimeout; /* in TUs */ + struct ieee80211_ba_seqctrl rq_basequencectrl; +} __packed; + +/* BA - ADDBA response */ +struct ieee80211_action_ba_addbaresponse { + struct ieee80211_action rs_header; + uint8_t rs_dialogtoken; + uint16_t rs_statuscode; + struct ieee80211_ba_parameterset rs_baparamset; + uint16_t rs_batimeout; /* in TUs */ +} __packed; + +/* BA - DELBA */ +struct ieee80211_action_ba_delba { + struct ieee80211_action dl_header; + struct ieee80211_delba_parameterset dl_delbaparamset; + uint16_t dl_reasoncode; +} __packed; + +/* MGT Notif actions */ +#define IEEE80211_WMM_QOS_ACTION_SETUP_REQ 0 +#define IEEE80211_WMM_QOS_ACTION_SETUP_RESP 1 +#define IEEE80211_WMM_QOS_ACTION_TEARDOWN 2 + +#define IEEE80211_WMM_QOS_DIALOG_TEARDOWN 0 +#define IEEE80211_WMM_QOS_DIALOG_SETUP 1 + +#define IEEE80211_WMM_QOS_TSID_DATA_TSPEC 6 +#define IEEE80211_WMM_QOS_TSID_SIG_TSPEC 7 + +struct ieee80211_action_wmm_qos { + struct ieee80211_action ts_header; + uint8_t ts_dialogtoken; + uint8_t ts_statuscode; + struct ieee80211_wme_tspec ts_tspecie; +} __packed; + +/* + * Control frames. + */ +struct ieee80211_frame_min { + uint8_t i_fc[2]; + uint8_t i_dur[2]; + uint8_t i_addr1[IEEE80211_ADDR_LEN]; + uint8_t i_addr2[IEEE80211_ADDR_LEN]; + /* FCS */ +} __packed; + +/* + * BAR frame format + */ +#define IEEE80211_BAR_CTL_TID_M 0xF000 /* tid mask */ +#define IEEE80211_BAR_CTL_TID_S 12 /* tid shift */ +#define IEEE80211_BAR_CTL_NOACK 0x0001 /* no-ack policy */ +#define IEEE80211_BAR_CTL_COMBA 0x0004 /* compressed block-ack */ + +/* + * SA Query Action mgmt Frame + */ +struct ieee80211_action_sa_query { + struct ieee80211_action sa_header; + uint16_t sa_transId; +}; + +typedef enum ieee80211_action_sa_query_type { + IEEE80211_ACTION_SA_QUERY_REQUEST, + IEEE80211_ACTION_SA_QUERY_RESPONSE +} ieee80211_action_sa_query_type_t; + +struct ieee80211_frame_bar { + uint8_t i_fc[2]; + uint8_t i_dur[2]; + uint8_t i_ra[IEEE80211_ADDR_LEN]; + uint8_t i_ta[IEEE80211_ADDR_LEN]; + uint16_t i_ctl; + uint16_t i_seq; + /* FCS */ +} __packed; + +struct ieee80211_frame_rts { + uint8_t i_fc[2]; + uint8_t i_dur[2]; + uint8_t i_ra[IEEE80211_ADDR_LEN]; + uint8_t i_ta[IEEE80211_ADDR_LEN]; + /* FCS */ +} __packed; + +struct ieee80211_frame_cts { + uint8_t i_fc[2]; + uint8_t i_dur[2]; + uint8_t i_ra[IEEE80211_ADDR_LEN]; + /* FCS */ +} __packed; + +struct ieee80211_frame_ack { + uint8_t i_fc[2]; + uint8_t i_dur[2]; + uint8_t i_ra[IEEE80211_ADDR_LEN]; + /* FCS */ +} __packed; + +struct ieee80211_frame_pspoll { + uint8_t i_fc[2]; + uint8_t i_aid[2]; + uint8_t i_bssid[IEEE80211_ADDR_LEN]; + uint8_t i_ta[IEEE80211_ADDR_LEN]; + /* FCS */ +} __packed; + +struct ieee80211_frame_cfend { /* NB: also CF-End+CF-Ack */ + uint8_t i_fc[2]; + uint8_t i_dur[2]; /* should be zero */ + uint8_t i_ra[IEEE80211_ADDR_LEN]; + uint8_t i_bssid[IEEE80211_ADDR_LEN]; + /* FCS */ +} __packed; + +/* + * BEACON management packets + * + * octet timestamp[8] + * octet beacon interval[2] + * octet capability information[2] + * information element + * octet elemid + * octet length + * octet information[length] + */ + +typedef uint8_t *ieee80211_mgt_beacon_t; + +#define IEEE80211_BEACON_INTERVAL(beacon) \ + ((beacon)[8] | ((beacon)[9] << 8)) +#define IEEE80211_BEACON_CAPABILITY(beacon) \ + ((beacon)[10] | ((beacon)[11] << 8)) + +#define IEEE80211_CAPINFO_ESS 0x0001 +#define IEEE80211_CAPINFO_IBSS 0x0002 +#define IEEE80211_CAPINFO_CF_POLLABLE 0x0004 +#define IEEE80211_CAPINFO_CF_POLLREQ 0x0008 +#define IEEE80211_CAPINFO_PRIVACY 0x0010 +#define IEEE80211_CAPINFO_SHORT_PREAMBLE 0x0020 +#define IEEE80211_CAPINFO_PBCC 0x0040 +#define IEEE80211_CAPINFO_CHNL_AGILITY 0x0080 +#define IEEE80211_CAPINFO_SPECTRUM_MGMT 0x0100 +#define IEEE80211_CAPINFO_QOS 0x0200 +#define IEEE80211_CAPINFO_SHORT_SLOTTIME 0x0400 +#define IEEE80211_CAPINFO_APSD 0x0800 +#define IEEE80211_CAPINFO_RADIOMEAS 0x1000 +#define IEEE80211_CAPINFO_DSSSOFDM 0x2000 +/* bits 14-15 are reserved */ + +/* + * 802.11i/WPA information element (maximally sized). + */ +struct ieee80211_ie_wpa { + uint8_t wpa_id; /* IEEE80211_ELEMID_VENDOR */ + uint8_t wpa_len; /* length in bytes */ + uint8_t wpa_oui[3]; /* 0x00, 0x50, 0xf2 */ + uint8_t wpa_type; /* OUI type */ + uint16_t wpa_version; /* spec revision */ + uint32_t wpa_mcipher[1]; /* multicast/group key cipher */ + uint16_t wpa_uciphercnt; /* # pairwise key ciphers */ + uint32_t wpa_uciphers[8]; /* ciphers */ + uint16_t wpa_authselcnt; /* authentication selector cnt */ + uint32_t wpa_authsels[8]; /* selectors */ + uint16_t wpa_caps; /* 802.11i capabilities */ + uint16_t wpa_pmkidcnt; /* 802.11i pmkid count */ + uint16_t wpa_pmkids[8]; /* 802.11i pmkids */ +} __packed; + +#ifndef _BYTE_ORDER +#error "Don't know native byte order" +#endif + +#ifndef IEEE80211N_IE +/* Temporary vendor specific IE for 11n pre-standard interoperability */ +#define VENDOR_HT_OUI 0x00904c +#define VENDOR_HT_CAP_ID 51 +#define VENDOR_HT_INFO_ID 52 +#endif + +#ifdef ATH_SUPPORT_TxBF +union ieee80211_hc_txbf { + struct { +#if _BYTE_ORDER == _BIG_ENDIAN + uint32_t reserved : 3, + channel_estimation_cap : 2, + csi_max_rows_bfer : 2, + comp_bfer_antennas : 2, + noncomp_bfer_antennas : 2, + csi_bfer_antennas : 2, + minimal_grouping : 2, + explicit_comp_bf : 2, + explicit_noncomp_bf : 2, + explicit_csi_feedback : 2, + explicit_comp_steering : 1, + explicit_noncomp_steering : 1, + explicit_csi_txbf_capable : 1, + calibration : 2, + implicit_txbf_capable : 1, + tx_ndp_capable : 1, + rx_ndp_capable : 1, + tx_staggered_sounding : 1, + rx_staggered_sounding : 1, implicit_rx_capable : 1; +#else + uint32_t implicit_rx_capable : 1, + rx_staggered_sounding : 1, + tx_staggered_sounding : 1, + rx_ndp_capable : 1, + tx_ndp_capable : 1, + implicit_txbf_capable : 1, + calibration : 2, + explicit_csi_txbf_capable : 1, + explicit_noncomp_steering : 1, + explicit_comp_steering : 1, + explicit_csi_feedback : 2, + explicit_noncomp_bf : 2, + explicit_comp_bf : 2, + minimal_grouping : 2, + csi_bfer_antennas : 2, + noncomp_bfer_antennas : 2, + comp_bfer_antennas : 2, + csi_max_rows_bfer : 2, channel_estimation_cap : 2, reserved : 3; +#endif + }; + + uint32_t value; +} __packed; +#endif + +struct ieee80211_ie_htcap_cmn { + uint16_t hc_cap; /* HT capabilities */ +#if _BYTE_ORDER == _BIG_ENDIAN + uint8_t hc_reserved : 3, /* B5-7 reserved */ + hc_mpdudensity : 3, /* B2-4 MPDU density (aka Minimum MPDU Start Spacing) */ + hc_maxampdu : 2; /* B0-1 maximum rx A-MPDU factor */ +#else + uint8_t hc_maxampdu : 2, /* B0-1 maximum rx A-MPDU factor */ + hc_mpdudensity : 3, /* B2-4 MPDU density (aka Minimum MPDU Start Spacing) */ + hc_reserved : 3; /* B5-7 reserved */ +#endif + uint8_t hc_mcsset[16]; /* supported MCS set */ + uint16_t hc_extcap; /* extended HT capabilities */ +#ifdef ATH_SUPPORT_TxBF + union ieee80211_hc_txbf hc_txbf; /* txbf capabilities */ +#else + uint32_t hc_txbf; /* txbf capabilities */ +#endif + uint8_t hc_antenna; /* antenna capabilities */ +} __packed; + +/* + * 802.11n HT Capability IE + */ +struct ieee80211_ie_htcap { + uint8_t hc_id; /* element ID */ + uint8_t hc_len; /* length in bytes */ + struct ieee80211_ie_htcap_cmn hc_ie; +} __packed; + +/* + * Temporary vendor private HT Capability IE + */ +struct vendor_ie_htcap { + uint8_t hc_id; /* element ID */ + uint8_t hc_len; /* length in bytes */ + uint8_t hc_oui[3]; + uint8_t hc_ouitype; + struct ieee80211_ie_htcap_cmn hc_ie; +} __packed; + +/* HT capability flags */ +#define IEEE80211_HTCAP_C_ADVCODING 0x0001 +#define IEEE80211_HTCAP_C_CHWIDTH40 0x0002 +#define IEEE80211_HTCAP_C_SMPOWERSAVE_STATIC 0x0000 /* Capable of SM Power Save (Static) */ +#define IEEE80211_HTCAP_C_SMPOWERSAVE_DYNAMIC 0x0004 /* Capable of SM Power Save (Dynamic) */ +#define IEEE80211_HTCAP_C_SM_RESERVED 0x0008 /* Reserved */ +#define IEEE80211_HTCAP_C_SM_ENABLED 0x000c /* SM enabled, no SM Power Save */ +#define IEEE80211_HTCAP_C_GREENFIELD 0x0010 +#define IEEE80211_HTCAP_C_SHORTGI20 0x0020 +#define IEEE80211_HTCAP_C_SHORTGI40 0x0040 +#define IEEE80211_HTCAP_C_TXSTBC 0x0080 +#define IEEE80211_HTCAP_C_TXSTBC_S 7 +#define IEEE80211_HTCAP_C_RXSTBC 0x0300 /* 2 bits */ +#define IEEE80211_HTCAP_C_RXSTBC_S 8 +#define IEEE80211_HTCAP_C_DELAYEDBLKACK 0x0400 +#define IEEE80211_HTCAP_C_MAXAMSDUSIZE 0x0800 /* 1 = 8K, 0 = 3839B */ +#define IEEE80211_HTCAP_C_DSSSCCK40 0x1000 +#define IEEE80211_HTCAP_C_PSMP 0x2000 +#define IEEE80211_HTCAP_C_INTOLERANT40 0x4000 +#define IEEE80211_HTCAP_C_LSIGTXOPPROT 0x8000 + +#define IEEE80211_HTCAP_C_SM_MASK 0x000c /* Spatial Multiplexing (SM) capabitlity bitmask */ + +/* B0-1 maximum rx A-MPDU factor 2^(13+Max Rx A-MPDU Factor) */ +enum { + IEEE80211_HTCAP_MAXRXAMPDU_8192, /* 2 ^ 13 */ + IEEE80211_HTCAP_MAXRXAMPDU_16384, /* 2 ^ 14 */ + IEEE80211_HTCAP_MAXRXAMPDU_32768, /* 2 ^ 15 */ + IEEE80211_HTCAP_MAXRXAMPDU_65536, /* 2 ^ 16 */ +}; +#define IEEE80211_HTCAP_MAXRXAMPDU_FACTOR 13 + +/* B2-4 MPDU density (usec) */ +enum { + IEEE80211_HTCAP_MPDUDENSITY_NA, /* No time restriction */ + IEEE80211_HTCAP_MPDUDENSITY_0_25, /* 1/4 usec */ + IEEE80211_HTCAP_MPDUDENSITY_0_5, /* 1/2 usec */ + IEEE80211_HTCAP_MPDUDENSITY_1, /* 1 usec */ + IEEE80211_HTCAP_MPDUDENSITY_2, /* 2 usec */ + IEEE80211_HTCAP_MPDUDENSITY_4, /* 4 usec */ + IEEE80211_HTCAP_MPDUDENSITY_8, /* 8 usec */ + IEEE80211_HTCAP_MPDUDENSITY_16, /* 16 usec */ +}; + +/* HT extended capability flags */ +#define IEEE80211_HTCAP_EXTC_PCO 0x0001 +#define IEEE80211_HTCAP_EXTC_TRANS_TIME_RSVD 0x0000 +#define IEEE80211_HTCAP_EXTC_TRANS_TIME_400 0x0002 /* 20-40 switch time */ +#define IEEE80211_HTCAP_EXTC_TRANS_TIME_1500 0x0004 /* in us */ +#define IEEE80211_HTCAP_EXTC_TRANS_TIME_5000 0x0006 +#define IEEE80211_HTCAP_EXTC_RSVD_1 0x00f8 +#define IEEE80211_HTCAP_EXTC_MCS_FEEDBACK_NONE 0x0000 +#define IEEE80211_HTCAP_EXTC_MCS_FEEDBACK_RSVD 0x0100 +#define IEEE80211_HTCAP_EXTC_MCS_FEEDBACK_UNSOL 0x0200 +#define IEEE80211_HTCAP_EXTC_MCS_FEEDBACK_FULL 0x0300 +#define IEEE80211_HTCAP_EXTC_RSVD_2 0xfc00 +#ifdef ATH_SUPPORT_TxBF +#define IEEE80211_HTCAP_EXTC_HTC_SUPPORT 0x0400 +#endif + +struct ieee80211_ie_htinfo_cmn { + uint8_t hi_ctrlchannel; /* control channel */ +#if _BYTE_ORDER == _BIG_ENDIAN + uint8_t hi_serviceinterval : 3, /* B5-7 svc interval granularity */ + hi_ctrlaccess : 1, /* B4 controlled access only */ + hi_rifsmode : 1, /* B3 rifs mode */ + hi_txchwidth : 1, /* B2 recommended xmiss width set */ + hi_extchoff : 2; /* B0-1 extension channel offset */ + +/* + + * The following 2 consecutive bytes are defined in word in 80211n spec. + + * Some processors store MSB byte into lower memory address which causes wrong + + * wrong byte sequence in beacon. Thus we break into byte definition which should + + * avoid the problem for all processors + + */ + + uint8_t hi_reserved3 : 3, /* B5-7 reserved */ + hi_obssnonhtpresent : 1, /* B4 OBSS non-HT STA present */ + hi_txburstlimit : 1, /* B3 transmit burst limit */ + hi_nongfpresent : 1, /* B2 non greenfield devices present */ + hi_opmode : 2; /* B0-1 operating mode */ + + uint8_t hi_reserved0; /* B0-7 (B8-15 in 11n) reserved */ + +/* The following 2 consecutive bytes are defined in word in 80211n spec. */ + + uint8_t hi_dualctsprot : 1, /* B7 dual CTS protection */ + hi_dualbeacon : 1, /* B6 dual beacon */ + hi_reserved2 : 6; /* B0-5 reserved */ + uint8_t hi_reserved1 : 4, /* B4-7 (B12-15 in 11n) reserved */ + hi_pcophase : 1, /* B3 (B11 in 11n) pco phase */ + hi_pcoactive : 1, /* B2 (B10 in 11n) pco active */ + hi_lsigtxopprot : 1, /* B1 (B9 in 11n) l-sig txop protection full support */ + hi_stbcbeacon : 1; /* B0 (B8 in 11n) STBC beacon */ +#else + uint8_t hi_extchoff : 2, /* B0-1 extension channel offset */ + hi_txchwidth : 1, /* B2 recommended xmiss width set */ + hi_rifsmode : 1, /* B3 rifs mode */ + hi_ctrlaccess : 1, /* B4 controlled access only */ + hi_serviceinterval : 3; /* B5-7 svc interval granularity */ + uint16_t hi_opmode : 2, /* B0-1 operating mode */ + hi_nongfpresent : 1, /* B2 non greenfield devices present */ + hi_txburstlimit : 1, /* B3 transmit burst limit */ + hi_obssnonhtpresent : 1, /* B4 OBSS non-HT STA present */ + hi_reserved0 : 11; /* B5-15 reserved */ + uint16_t hi_reserved2 : 6, /* B0-5 reserved */ + hi_dualbeacon : 1, /* B6 dual beacon */ + hi_dualctsprot : 1, /* B7 dual CTS protection */ + hi_stbcbeacon : 1, /* B8 STBC beacon */ + hi_lsigtxopprot : 1, /* B9 l-sig txop protection full support */ + hi_pcoactive : 1, /* B10 pco active */ + hi_pcophase : 1, /* B11 pco phase */ + hi_reserved1 : 4; /* B12-15 reserved */ +#endif + uint8_t hi_basicmcsset[16]; /* basic MCS set */ +} __packed; + +/* + * 802.11n HT Information IE + */ +struct ieee80211_ie_htinfo { + uint8_t hi_id; /* element ID */ + uint8_t hi_len; /* length in bytes */ + struct ieee80211_ie_htinfo_cmn hi_ie; +} __packed; + +/* + * Temporary vendor private HT Information IE + */ +struct vendor_ie_htinfo { + uint8_t hi_id; /* element ID */ + uint8_t hi_len; /* length in bytes */ + uint8_t hi_oui[3]; + uint8_t hi_ouitype; + struct ieee80211_ie_htinfo_cmn hi_ie; +} __packed; + +/* extension channel offset (2 bit signed number) */ +enum { + IEEE80211_HTINFO_EXTOFFSET_NA = 0, /* 0 no extension channel is present */ + IEEE80211_HTINFO_EXTOFFSET_ABOVE = 1, /* +1 extension channel above control channel */ + IEEE80211_HTINFO_EXTOFFSET_UNDEF = 2, /* -2 undefined */ + IEEE80211_HTINFO_EXTOFFSET_BELOW = 3 /* -1 extension channel below control channel */ +}; + +/* recommended transmission width set */ +enum { + IEEE80211_HTINFO_TXWIDTH_20, + IEEE80211_HTINFO_TXWIDTH_2040 +}; + +/* operating flags */ +#define IEEE80211_HTINFO_OPMODE_PURE 0x00 /* no protection */ +#define IEEE80211_HTINFO_OPMODE_MIXED_PROT_OPT 0x01 /* prot optional (legacy device maybe present) */ +#define IEEE80211_HTINFO_OPMODE_MIXED_PROT_40 0x02 /* prot required (20 MHz) */ +#define IEEE80211_HTINFO_OPMODE_MIXED_PROT_ALL 0x03 /* prot required (legacy devices present) */ +#define IEEE80211_HTINFO_OPMODE_NON_GF_PRESENT 0x04 /* non-greenfield devices present */ + +#define IEEE80211_HTINFO_OPMODE_MASK 0x03 /* For protection 0x00-0x03 */ + +/* Non-greenfield STAs present */ +enum { + IEEE80211_HTINFO_NON_GF_NOT_PRESENT, /* Non-greenfield STAs not present */ + IEEE80211_HTINFO_NON_GF_PRESENT, /* Non-greenfield STAs present */ +}; + +/* Transmit Burst Limit */ +enum { + IEEE80211_HTINFO_TXBURST_UNLIMITED, /* Transmit Burst is unlimited */ + IEEE80211_HTINFO_TXBURST_LIMITED, /* Transmit Burst is limited */ +}; + +/* OBSS Non-HT STAs present */ +enum { + IEEE80211_HTINFO_OBSS_NONHT_NOT_PRESENT, /* OBSS Non-HT STAs not present */ + IEEE80211_HTINFO_OBSS_NONHT_PRESENT, /* OBSS Non-HT STAs present */ +}; + +/* misc flags */ +#define IEEE80211_HTINFO_DUALBEACON 0x0040 /* B6 dual beacon */ +#define IEEE80211_HTINFO_DUALCTSPROT 0x0080 /* B7 dual stbc protection */ +#define IEEE80211_HTINFO_STBCBEACON 0x0100 /* B8 secondary beacon */ +#define IEEE80211_HTINFO_LSIGTXOPPROT 0x0200 /* B9 lsig txop prot full support */ +#define IEEE80211_HTINFO_PCOACTIVE 0x0400 /* B10 pco active */ +#define IEEE80211_HTINFO_PCOPHASE 0x0800 /* B11 pco phase */ + +/* Secondary Channel offset for for 40MHz direct link */ +#define IEEE80211_SECONDARY_CHANNEL_ABOVE 1 +#define IEEE80211_SECONDARY_CHANNEL_BELOW 3 + +#define IEEE80211_TDLS_CHAN_SX_PROHIBIT 0x00000002 /* bit-2 TDLS Channel Switch Prohibit */ + +/* RIFS mode */ +enum { + IEEE80211_HTINFO_RIFSMODE_PROHIBITED, /* use of rifs prohibited */ + IEEE80211_HTINFO_RIFSMODE_ALLOWED, /* use of rifs permitted */ +}; + +/* + * Management information element payloads. + */ +enum { + IEEE80211_ELEMID_SSID = 0, + IEEE80211_ELEMID_RATES = 1, + IEEE80211_ELEMID_FHPARMS = 2, + IEEE80211_ELEMID_DSPARMS = 3, + IEEE80211_ELEMID_CFPARMS = 4, + IEEE80211_ELEMID_TIM = 5, + IEEE80211_ELEMID_IBSSPARMS = 6, + IEEE80211_ELEMID_COUNTRY = 7, + IEEE80211_ELEMID_REQINFO = 10, + IEEE80211_ELEMID_QBSS_LOAD = 11, + IEEE80211_ELEMID_TCLAS = 14, + IEEE80211_ELEMID_CHALLENGE = 16, + /* 17-31 reserved for challenge text extension */ + IEEE80211_ELEMID_PWRCNSTR = 32, + IEEE80211_ELEMID_PWRCAP = 33, + IEEE80211_ELEMID_TPCREQ = 34, + IEEE80211_ELEMID_TPCREP = 35, + IEEE80211_ELEMID_SUPPCHAN = 36, + IEEE80211_ELEMID_CHANSWITCHANN = 37, + IEEE80211_ELEMID_MEASREQ = 38, + IEEE80211_ELEMID_MEASREP = 39, + IEEE80211_ELEMID_QUIET = 40, + IEEE80211_ELEMID_IBSSDFS = 41, + IEEE80211_ELEMID_ERP = 42, + IEEE80211_ELEMID_TCLAS_PROCESS = 44, + IEEE80211_ELEMID_HTCAP_ANA = 45, + IEEE80211_ELEMID_RESERVED_47 = 47, + IEEE80211_ELEMID_RSN = 48, + IEEE80211_ELEMID_XRATES = 50, + IEEE80211_ELEMID_HTCAP = 51, + IEEE80211_ELEMID_HTINFO = 52, + IEEE80211_ELEMID_MOBILITY_DOMAIN = 54, + IEEE80211_ELEMID_FT = 55, + IEEE80211_ELEMID_TIMEOUT_INTERVAL = 56, + IEEE80211_ELEMID_EXTCHANSWITCHANN = 60, + IEEE80211_ELEMID_HTINFO_ANA = 61, + IEEE80211_ELEMID_SECCHANOFFSET = 62, + IEEE80211_ELEMID_WAPI = 68, /*IE for WAPI */ + IEEE80211_ELEMID_TIME_ADVERTISEMENT = 69, + IEEE80211_ELEMID_RRM = 70, /* Radio resource measurement */ + IEEE80211_ELEMID_2040_COEXT = 72, + IEEE80211_ELEMID_2040_INTOL = 73, + IEEE80211_ELEMID_OBSS_SCAN = 74, + IEEE80211_ELEMID_MMIE = 76, /* 802.11w Management MIC IE */ + IEEE80211_ELEMID_FMS_DESCRIPTOR = 86, /* 802.11v FMS descriptor IE */ + IEEE80211_ELEMID_FMS_REQUEST = 87, /* 802.11v FMS request IE */ + IEEE80211_ELEMID_FMS_RESPONSE = 88, /* 802.11v FMS response IE */ + IEEE80211_ELEMID_BSSMAX_IDLE_PERIOD = 90, /* BSS MAX IDLE PERIOD */ + IEEE80211_ELEMID_TFS_REQUEST = 91, + IEEE80211_ELEMID_TFS_RESPONSE = 92, + IEEE80211_ELEMID_TIM_BCAST_REQUEST = 94, + IEEE80211_ELEMID_TIM_BCAST_RESPONSE = 95, + IEEE80211_ELEMID_INTERWORKING = 107, + IEEE80211_ELEMID_XCAPS = 127, + IEEE80211_ELEMID_RESERVED_133 = 133, + IEEE80211_ELEMID_TPC = 150, + IEEE80211_ELEMID_CCKM = 156, + IEEE80211_ELEMID_VHTCAP = 191, /* VHT Capabilities */ + IEEE80211_ELEMID_VHTOP = 192, /* VHT Operation */ + IEEE80211_ELEMID_EXT_BSS_LOAD = 193, /* Extended BSS Load */ + IEEE80211_ELEMID_WIDE_BAND_CHAN_SWITCH = 194, /* Wide Band Channel Switch */ + IEEE80211_ELEMID_VHT_TX_PWR_ENVLP = 195, /* VHT Transmit Power Envelope */ + IEEE80211_ELEMID_CHAN_SWITCH_WRAP = 196, /* Channel Switch Wrapper */ + IEEE80211_ELEMID_AID = 197, /* AID */ + IEEE80211_ELEMID_QUIET_CHANNEL = 198, /* Quiet Channel */ + IEEE80211_ELEMID_OP_MODE_NOTIFY = 199, /* Operating Mode Notification */ + IEEE80211_ELEMID_VENDOR = 221, /* vendor private */ +}; + +#define IEEE80211_MAX_IE_LEN 255 +#define IEEE80211_RSN_IE_LEN 22 + +#define IEEE80211_CHANSWITCHANN_BYTES 5 +#define IEEE80211_EXTCHANSWITCHANN_BYTES 6 + +/* TODO -> Need to Check Redefinition Error used in only UMAC */ +#if 0 +struct ieee80211_tim_ie { + uint8_t tim_ie; /* IEEE80211_ELEMID_TIM */ + uint8_t tim_len; + uint8_t tim_count; /* DTIM count */ + uint8_t tim_period; /* DTIM period */ + uint8_t tim_bitctl; /* bitmap control */ + uint8_t tim_bitmap[1]; /* variable-length bitmap */ +} __packed; +#endif + +/* Country IE channel triplet */ +struct country_ie_triplet { + union { + uint8_t schan; /* starting channel */ + uint8_t regextid; /* Regulatory Extension Identifier */ + }; + union { + uint8_t nchan; /* number of channels */ + uint8_t regclass; /* Regulatory Class */ + }; + union { + uint8_t maxtxpwr; /* tx power */ + uint8_t coverageclass; /* Coverage Class */ + }; +} __packed; + +struct ieee80211_country_ie { + uint8_t ie; /* IEEE80211_ELEMID_COUNTRY */ + uint8_t len; + uint8_t cc[3]; /* ISO CC+(I)ndoor/(O)utdoor */ + struct country_ie_triplet triplet[1]; +} __packed; + +struct ieee80211_fh_ie { + uint8_t ie; /* IEEE80211_ELEMID_FHPARMS */ + uint8_t len; + uint16_t dwell_time; /* endianess?? */ + uint8_t hop_set; + uint8_t hop_pattern; + uint8_t hop_index; +} __packed; + +struct ieee80211_ds_ie { + uint8_t ie; /* IEEE80211_ELEMID_DSPARMS */ + uint8_t len; + uint8_t current_channel; +} __packed; + +struct ieee80211_erp_ie { + uint8_t ie; /* IEEE80211_ELEMID_ERP */ + uint8_t len; + uint8_t value; +} __packed; + +/* TODO -> Need to Check Redefinition Error used in only UMAC */ +#if 0 +struct ieee80211_quiet_ie { + uint8_t ie; /* IEEE80211_ELEMID_QUIET */ + uint8_t len; + uint8_t tbttcount; /* quiet start */ + uint8_t period; /* beacon intervals between quiets */ + uint16_t duration; /* TUs of each quiet */ + uint16_t offset; /* TUs of from TBTT of quiet start */ +} __packed; +#endif + +struct ieee80211_channelswitch_ie { + uint8_t ie; /* IEEE80211_ELEMID_CHANSWITCHANN */ + uint8_t len; + uint8_t switchmode; + uint8_t newchannel; + uint8_t tbttcount; +} __packed; + +/* channel switch action frame format definition */ +struct ieee80211_action_spectrum_channel_switch { + struct ieee80211_action csa_header; + struct ieee80211_channelswitch_ie csa_element; +} __packed; + +struct ieee80211_extendedchannelswitch_ie { + uint8_t ie; /* IEEE80211_ELEMID_EXTCHANSWITCHANN */ + uint8_t len; + uint8_t switchmode; + uint8_t newClass; + uint8_t newchannel; + uint8_t tbttcount; +} __packed; + +struct ieee80211_tpc_ie { + uint8_t ie; + uint8_t len; + uint8_t pwrlimit; +} __packed; + +/* + * MHDRIE included in TKIP MFP protected management frames + */ +struct ieee80211_ese_mhdr_ie { + uint8_t mhdr_id; + uint8_t mhdr_len; + uint8_t mhdr_oui[3]; + uint8_t mhdr_oui_type; + uint8_t mhdr_fc[2]; + uint8_t mhdr_bssid[IEEE80211_ADDR_LEN]; +} __packed; + +/* + * SSID IE + */ +struct ieee80211_ie_ssid { + uint8_t ssid_id; + uint8_t ssid_len; + uint8_t ssid[32]; +} __packed; + +/* + * Supported rates + */ +#define IEEE80211_MAX_SUPPORTED_RATES 8 + +struct ieee80211_ie_rates { + uint8_t rate_id; /* Element Id */ + uint8_t rate_len; /* IE Length */ + uint8_t rate[IEEE80211_MAX_SUPPORTED_RATES]; /* IE Length */ +} __packed; + +/* + * Extended rates + */ +#define IEEE80211_MAX_EXTENDED_RATES 256 + +struct ieee80211_ie_xrates { + uint8_t xrate_id; /* Element Id */ + uint8_t xrate_len; /* IE Length */ + uint8_t xrate[IEEE80211_MAX_EXTENDED_RATES]; /* IE Length */ +} __packed; + +/* + * WPS SSID list information element (maximally sized). + */ +struct ieee80211_ie_ssidl { + uint8_t ssidl_id; /* IEEE80211_ELEMID_VENDOR */ + uint8_t ssidl_len; /* length in bytes */ + uint8_t ssidl_oui[3]; /* 0x00, 0x50, 0xf2 */ + uint8_t ssidl_type; /* OUI type */ + uint8_t ssidl_prim_cap; /* Primary capabilities */ + uint8_t ssidl_count; /* # of secondary SSIDs */ + uint16_t ssidl_value[248]; +} __packed; + +#if _BYTE_ORDER == _BIG_ENDIAN +struct ieee80211_sec_ssid_cap { + uint32_t reserved0 : 1, + akmlist : 6, reserved1 : 4, reeserved2 : 2, ucipher : 15, mcipher : 4; +}; +#else +struct ieee80211_sec_ssid_cap { + uint32_t mcipher : 4, + ucipher : 15, reserved2 : 2, reserved1 : 4, akmlist : 6, reserved0 : 1; +}; +#endif + +struct ieee80211_ie_qbssload { + uint8_t elem_id; /* IEEE80211_ELEMID_QBSS_LOAD */ + uint8_t length; /* length in bytes */ + uint16_t station_count; /* number of station associated */ + uint8_t channel_utilization; /* channel busy time in 0-255 scale */ + uint16_t aac; /* available admission capacity */ +} __packed; + +#define SEC_SSID_HEADER_LEN 6 +#define SSIDL_IE_HEADER_LEN 6 + +struct ieee80211_sec_ssid { + uint8_t sec_ext_cap; + struct ieee80211_sec_ssid_cap sec_cap; + uint8_t sec_ssid_len; + uint8_t sec_ssid[32]; +} __packed; + +/* Definitions of SSIDL IE */ +enum { + CAP_MCIPHER_ENUM_NONE = 0, + CAP_MCIPHER_ENUM_WEP40, + CAP_MCIPHER_ENUM_WEP104, + CAP_MCIPHER_ENUM_TKIP, + CAP_MCIPHER_ENUM_CCMP, + CAP_MCIPHER_ENUM_CKIP_CMIC, + CAP_MCIPHER_ENUM_CKIP, + CAP_MCIPHER_ENUM_CMIC +}; + +#define CAP_UCIPHER_BIT_NONE 0x0001 +#define CAP_UCIPHER_BIT_WEP40 0x0002 +#define CAP_UCIPHER_BIT_WEP104 0x0004 +#define CAP_UCIPHER_BIT_TKIP 0x0008 +#define CAP_UCIPHER_BIT_CCMP 0x0010 +#define CAP_UCIPHER_BIT_CKIP_CMIC 0x0020 +#define CAP_UCIPHER_BIT_CKIP 0x0040 +#define CAP_UCIPHER_BIT_CMIC 0x0080 +#define CAP_UCIPHER_BIT_WPA2_WEP40 0x0100 +#define CAP_UCIPHER_BIT_WPA2_WEP104 0x0200 +#define CAP_UCIPHER_BIT_WPA2_TKIP 0x0400 +#define CAP_UCIPHER_BIT_WPA2_CCMP 0x0800 +#define CAP_UCIPHER_BIT_WPA2_CKIP_CMIC 0x1000 +#define CAP_UCIPHER_BIT_WPA2_CKIP 0x2000 +#define CAP_UCIPHER_BIT_WPA2_CMIC 0x4000 + +#define CAP_AKM_BIT_WPA1_1X 0x01 +#define CAP_AKM_BIT_WPA1_PSK 0x02 +#define CAP_AKM_BIT_WPA2_1X 0x04 +#define CAP_AKM_BIT_WPA2_PSK 0x08 +#define CAP_AKM_BIT_WPA1_CCKM 0x10 +#define CAP_AKM_BIT_WPA2_CCKM 0x20 + +#define IEEE80211_CHALLENGE_LEN 128 + +#define IEEE80211_SUPPCHAN_LEN 26 + +#define IEEE80211_RATE_BASIC 0x80 +#define IEEE80211_RATE_VAL 0x7f + +/* EPR information element flags */ +#define IEEE80211_ERP_NON_ERP_PRESENT 0x01 +#define IEEE80211_ERP_USE_PROTECTION 0x02 +#define IEEE80211_ERP_LONG_PREAMBLE 0x04 + +/* Atheros private advanced capabilities info */ +#define ATHEROS_CAP_TURBO_PRIME 0x01 +#define ATHEROS_CAP_COMPRESSION 0x02 +#define ATHEROS_CAP_FAST_FRAME 0x04 +/* bits 3-6 reserved */ +#define ATHEROS_CAP_BOOST 0x80 + +#define ATH_OUI 0x7f0300 /* Atheros OUI */ +#define ATH_OUI_TYPE 0x01 +#define ATH_OUI_SUBTYPE 0x01 +#define ATH_OUI_VERSION 0x00 +#define ATH_OUI_TYPE_XR 0x03 +#define ATH_OUI_VER_XR 0x01 +#define ATH_OUI_EXTCAP_TYPE 0x04 /* Atheros Extended Cap Type */ +#define ATH_OUI_EXTCAP_SUBTYPE 0x01 /* Atheros Extended Cap Sub-type */ +#define ATH_OUI_EXTCAP_VERSION 0x00 /* Atheros Extended Cap Version */ + +#define WPA_OUI 0xf25000 +#define WPA_VERSION 1 /* current supported version */ +#define CSCO_OUI 0x964000 /* Cisco OUI */ +#define AOW_OUI 0x4a0100 /* AoW OUI, workaround */ +#define AOW_OUI_TYPE 0x01 +#define AOW_OUI_VERSION 0x01 + +#define WSC_OUI 0x0050f204 + +#define WPA_CSE_NULL 0x00 +#define WPA_CSE_WEP40 0x01 +#define WPA_CSE_TKIP 0x02 +#define WPA_CSE_CCMP 0x04 +#define WPA_CSE_WEP104 0x05 + +#define WPA_ASE_NONE 0x00 +#define WPA_ASE_8021X_UNSPEC 0x01 +#define WPA_ASE_8021X_PSK 0x02 +#define WPA_ASE_FT_IEEE8021X 0x20 +#define WPA_ASE_FT_PSK 0x40 +#define WPA_ASE_SHA256_IEEE8021X 0x80 +#define WPA_ASE_SHA256_PSK 0x100 +#define WPA_ASE_WPS 0x200 + +#define RSN_OUI 0xac0f00 +#define RSN_VERSION 1 /* current supported version */ + +#define RSN_CSE_NULL 0x00 +#define RSN_CSE_WEP40 0x01 +#define RSN_CSE_TKIP 0x02 +#define RSN_CSE_WRAP 0x03 +#define RSN_CSE_CCMP 0x04 +#define RSN_CSE_WEP104 0x05 +#define RSN_CSE_AES_CMAC 0x06 + +#define RSN_ASE_NONE 0x00 +#define RSN_ASE_8021X_UNSPEC 0x01 +#define RSN_ASE_8021X_PSK 0x02 +#define RSN_ASE_FT_IEEE8021X 0x20 +#define RSN_ASE_FT_PSK 0x40 +#define RSN_ASE_SHA256_IEEE8021X 0x80 +#define RSN_ASE_SHA256_PSK 0x100 +#define RSN_ASE_WPS 0x200 + +#define AKM_SUITE_TYPE_IEEE8021X 0x01 +#define AKM_SUITE_TYPE_PSK 0x02 +#define AKM_SUITE_TYPE_FT_IEEE8021X 0x03 +#define AKM_SUITE_TYPE_FT_PSK 0x04 +#define AKM_SUITE_TYPE_SHA256_IEEE8021X 0x05 +#define AKM_SUITE_TYPE_SHA256_PSK 0x06 + +#define RSN_CAP_PREAUTH 0x01 +#define RSN_CAP_PTKSA_REPLAYCOUNTER 0x0c +#define RSN_CAP_GTKSA_REPLAYCOUNTER 0x30 +#define RSN_CAP_MFP_REQUIRED 0x40 +#define RSN_CAP_MFP_ENABLED 0x80 + +#define CCKM_OUI 0x964000 +#define CCKM_ASE_UNSPEC 0 +#define WPA_CCKM_AKM 0x00964000 +#define RSN_CCKM_AKM 0x00964000 + +#define WME_OUI 0xf25000 +#define WME_OUI_TYPE 0x02 +#define WME_INFO_OUI_SUBTYPE 0x00 +#define WME_PARAM_OUI_SUBTYPE 0x01 +#define WME_TSPEC_OUI_SUBTYPE 0x02 + +#define WME_PARAM_OUI_VERSION 1 +#define WME_TSPEC_OUI_VERSION 1 +#define WME_VERSION 1 + +/* WME stream classes */ +#define WME_AC_BE 0 /* best effort */ +#define WME_AC_BK 1 /* background */ +#define WME_AC_VI 2 /* video */ +#define WME_AC_VO 3 /* voice */ + +/* WCN IE */ +#define WCN_OUI 0xf25000 /* Microsoft OUI */ +#define WCN_OUI_TYPE 0x04 /* WCN */ + +/* Atheros htoui for ht vender ie; use Epigram OUI for compatibility with pre11n devices */ +#define ATH_HTOUI 0x00904c + +#define SFA_OUI 0x964000 +#define SFA_OUI_TYPE 0x14 +#define SFA_IE_CAP_MFP 0x01 +#define SFA_IE_CAP_DIAG_CHANNEL 0x02 +#define SFA_IE_CAP_LOCATION_SVCS 0x04 +#define SFA_IE_CAP_EXP_BANDWIDTH 0x08 + +#define WPA_OUI_BYTES 0x00, 0x50, 0xf2 +#define RSN_OUI_BYTES 0x00, 0x0f, 0xac +#define WME_OUI_BYTES 0x00, 0x50, 0xf2 +#define ATH_OUI_BYTES 0x00, 0x03, 0x7f +#define SFA_OUI_BYTES 0x00, 0x40, 0x96 +#define CCKM_OUI_BYTES 0x00, 0x40, 0x96 +#define WPA_SEL(x) (((x)<<24)|WPA_OUI) +#define RSN_SEL(x) (((x)<<24)|RSN_OUI) +#define SFA_SEL(x) (((x)<<24)|SFA_OUI) +#define CCKM_SEL(x) (((x)<<24)|CCKM_OUI) + +#define IEEE80211_RV(v) ((v) & IEEE80211_RATE_VAL) + +/* + * AUTH management packets + * + * octet algo[2] + * octet seq[2] + * octet status[2] + * octet chal.id + * octet chal.length + * octet chal.text[253] + */ + +typedef uint8_t *ieee80211_mgt_auth_t; + +#define IEEE80211_AUTH_ALGORITHM(auth) \ + ((auth)[0] | ((auth)[1] << 8)) +#define IEEE80211_AUTH_TRANSACTION(auth) \ + ((auth)[2] | ((auth)[3] << 8)) +#define IEEE80211_AUTH_STATUS(auth) \ + ((auth)[4] | ((auth)[5] << 8)) + +#define IEEE80211_AUTH_ALG_OPEN 0x0000 +#define IEEE80211_AUTH_ALG_SHARED 0x0001 +#define IEEE80211_AUTH_ALG_FT 0x0002 +#define IEEE80211_AUTH_ALG_LEAP 0x0080 + +enum { + IEEE80211_AUTH_OPEN_REQUEST = 1, + IEEE80211_AUTH_OPEN_RESPONSE = 2, +}; + +enum { + IEEE80211_AUTH_SHARED_REQUEST = 1, + IEEE80211_AUTH_SHARED_CHALLENGE = 2, + IEEE80211_AUTH_SHARED_RESPONSE = 3, + IEEE80211_AUTH_SHARED_PASS = 4, +}; + +/* + * Reason codes + * + * Unlisted codes are reserved + */ + +enum { + IEEE80211_REASON_UNSPECIFIED = 1, + IEEE80211_REASON_AUTH_EXPIRE = 2, + IEEE80211_REASON_AUTH_LEAVE = 3, + IEEE80211_REASON_ASSOC_EXPIRE = 4, + IEEE80211_REASON_ASSOC_TOOMANY = 5, + IEEE80211_REASON_NOT_AUTHED = 6, + IEEE80211_REASON_NOT_ASSOCED = 7, + IEEE80211_REASON_ASSOC_LEAVE = 8, + IEEE80211_REASON_ASSOC_NOT_AUTHED = 9, + + IEEE80211_REASON_RSN_REQUIRED = 11, + IEEE80211_REASON_RSN_INCONSISTENT = 12, + IEEE80211_REASON_IE_INVALID = 13, + IEEE80211_REASON_MIC_FAILURE = 14, + + IEEE80211_REASON_QOS = 32, + IEEE80211_REASON_QOS_BANDWITDH = 33, + IEEE80211_REASON_QOS_CH_CONDITIONS = 34, + IEEE80211_REASON_QOS_TXOP = 35, + IEEE80211_REASON_QOS_LEAVE = 36, + IEEE80211_REASON_QOS_DECLINED = 37, + IEEE80211_REASON_QOS_SETUP_REQUIRED = 38, + IEEE80211_REASON_QOS_TIMEOUT = 39, + IEEE80211_REASON_QOS_CIPHER = 45, + + IEEE80211_STATUS_SUCCESS = 0, + IEEE80211_STATUS_UNSPECIFIED = 1, + IEEE80211_STATUS_CAPINFO = 10, + IEEE80211_STATUS_NOT_ASSOCED = 11, + IEEE80211_STATUS_OTHER = 12, + IEEE80211_STATUS_ALG = 13, + IEEE80211_STATUS_SEQUENCE = 14, + IEEE80211_STATUS_CHALLENGE = 15, + IEEE80211_STATUS_TIMEOUT = 16, + IEEE80211_STATUS_TOOMANY = 17, + IEEE80211_STATUS_BASIC_RATE = 18, + IEEE80211_STATUS_SP_REQUIRED = 19, + IEEE80211_STATUS_PBCC_REQUIRED = 20, + IEEE80211_STATUS_CA_REQUIRED = 21, + IEEE80211_STATUS_TOO_MANY_STATIONS = 22, + IEEE80211_STATUS_RATES = 23, + IEEE80211_STATUS_SHORTSLOT_REQUIRED = 25, + IEEE80211_STATUS_DSSSOFDM_REQUIRED = 26, + IEEE80211_STATUS_NO_HT = 27, + IEEE80211_STATUS_REJECT_TEMP = 30, + IEEE80211_STATUS_MFP_VIOLATION = 31, + IEEE80211_STATUS_REFUSED = 37, + IEEE80211_STATUS_INVALID_PARAM = 38, + + IEEE80211_STATUS_DLS_NOT_ALLOWED = 48, +}; + +/* private IEEE80211_STATUS */ +#define IEEE80211_STATUS_CANCEL -1 +#define IEEE80211_STATUS_INVALID_IE -2 +#define IEEE80211_STATUS_INVALID_CHANNEL -3 + +#define IEEE80211_WEP_KEYLEN 5 /* 40bit */ +#define IEEE80211_WEP_IVLEN 3 /* 24bit */ +#define IEEE80211_WEP_KIDLEN 1 /* 1 octet */ +#define IEEE80211_WEP_CRCLEN 4 /* CRC-32 */ +#define IEEE80211_WEP_NKID 4 /* number of key ids */ + +/* + * 802.11i defines an extended IV for use with non-WEP ciphers. + * When the EXTIV bit is set in the key id byte an additional + * 4 bytes immediately follow the IV for TKIP. For CCMP the + * EXTIV bit is likewise set but the 8 bytes represent the + * CCMP header rather than IV+extended-IV. + */ +#define IEEE80211_WEP_EXTIV 0x20 +#define IEEE80211_WEP_EXTIVLEN 4 /* extended IV length */ +#define IEEE80211_WEP_MICLEN 8 /* trailing MIC */ + +#define IEEE80211_CCMP_HEADERLEN 8 +#define IEEE80211_CCMP_MICLEN 8 + +/* + * 802.11w defines a MMIE chunk to be attached at the end of + * any outgoing broadcast or multicast robust management frame. + * MMIE field is total 18 bytes in size. Following the diagram of MMIE + * + * <------------ 18 Bytes MMIE -----------------------> + * +--------+---------+---------+-----------+---------+ + * |Element | Length | Key id | IPN | MIC | + * | id | | | | | + * +--------+---------+---------+-----------+---------+ + * bytes 1 1 2 6 8 + * + */ +#define IEEE80211_MMIE_LEN 18 +#define IEEE80211_MMIE_ELEMENTIDLEN 1 +#define IEEE80211_MMIE_LENGTHLEN 1 +#define IEEE80211_MMIE_KEYIDLEN 2 +#define IEEE80211_MMIE_IPNLEN 6 +#define IEEE80211_MMIE_MICLEN 8 + +#define IEEE80211_CRC_LEN 4 + +#define IEEE80211_8021Q_HEADER_LEN 4 +/* + * Maximum acceptable MTU is: + * IEEE80211_MAX_LEN - WEP overhead - CRC - + * QoS overhead - RSN/WPA overhead + * Min is arbitrarily chosen > IEEE80211_MIN_LEN. The default + * mtu is Ethernet-compatible; it's set by ether_ifattach. + */ +#define IEEE80211_MTU_MAX 2290 +#define IEEE80211_MTU_MIN 32 + +/* Rather than using this default value, customer platforms can provide a custom value for this constant. + Coustomer platform will use the different define value by themself */ +#ifndef IEEE80211_MAX_MPDU_LEN +#define IEEE80211_MAX_MPDU_LEN (3840 + IEEE80211_CRC_LEN + \ + (IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN + IEEE80211_WEP_CRCLEN)) +#endif +#define IEEE80211_ACK_LEN \ + (sizeof(struct ieee80211_frame_ack) + IEEE80211_CRC_LEN) +#define IEEE80211_MIN_LEN \ + (sizeof(struct ieee80211_frame_min) + IEEE80211_CRC_LEN) + +/* An 802.11 data frame can be one of three types: + 1. An unaggregated frame: The maximum length of an unaggregated data frame is 2324 bytes + headers. + 2. A data frame that is part of an AMPDU: The maximum length of an AMPDU may be upto 65535 bytes, but data frame is limited to 2324 bytes + header. + 3. An AMSDU: The maximum length of an AMSDU is eihther 3839 or 7095 bytes. + The maximum frame length supported by hardware is 4095 bytes. + A length of 3839 bytes is chosen here to support unaggregated data frames, any size AMPDUs and 3839 byte AMSDUs. + */ +#define IEEE80211N_MAX_FRAMELEN 3839 +#define IEEE80211N_MAX_LEN (IEEE80211N_MAX_FRAMELEN + IEEE80211_CRC_LEN + \ + (IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN + IEEE80211_WEP_CRCLEN)) + +#define IEEE80211_TX_CHAINMASK_MIN 1 +#define IEEE80211_TX_CHAINMASK_MAX 7 + +#define IEEE80211_RX_CHAINMASK_MIN 1 +#define IEEE80211_RX_CHAINMASK_MAX 7 + +/* + * The 802.11 spec says at most 2007 stations may be + * associated at once. For most AP's this is way more + * than is feasible so we use a default of 128. This + * number may be overridden by the driver and/or by + * user configuration. + */ +#define IEEE80211_AID_MAX 2007 +#define IEEE80211_AID_DEF 128 + +#define IEEE80211_AID(b) ((b) &~0xc000) + +/* + * RTS frame length parameters. The default is specified in + * the 802.11 spec. The max may be wrong for jumbo frames. + */ +#define IEEE80211_RTS_DEFAULT 512 +#define IEEE80211_RTS_MIN 0 +#define IEEE80211_RTS_MAX 2347 + +/* + * Fragmentation limits + */ +#define IEEE80211_FRAGMT_THRESHOLD_MIN 540 /* min frag threshold */ +#define IEEE80211_FRAGMT_THRESHOLD_MAX 2346 /* max frag threshold */ + +/* + * Regulatory extention identifier for country IE. + */ +#define IEEE80211_REG_EXT_ID 201 + +/* + * overlapping BSS + */ +#define IEEE80211_OBSS_SCAN_PASSIVE_DWELL_DEF 20 +#define IEEE80211_OBSS_SCAN_ACTIVE_DWELL_DEF 10 +#define IEEE80211_OBSS_SCAN_INTERVAL_DEF 300 +#define IEEE80211_OBSS_SCAN_PASSIVE_TOTAL_DEF 200 +#define IEEE80211_OBSS_SCAN_ACTIVE_TOTAL_DEF 20 +#define IEEE80211_OBSS_SCAN_THRESH_DEF 25 +#define IEEE80211_OBSS_SCAN_DELAY_DEF 5 + +/* + * overlapping BSS scan ie + */ +struct ieee80211_ie_obss_scan { + uint8_t elem_id; + uint8_t elem_len; + uint16_t scan_passive_dwell; + uint16_t scan_active_dwell; + uint16_t scan_interval; + uint16_t scan_passive_total; + uint16_t scan_active_total; + uint16_t scan_delay; + uint16_t scan_thresh; +} __packed; + +/* + * Extended capability ie + */ +struct ieee80211_ie_ext_cap { + uint8_t elem_id; + uint8_t elem_len; + uint32_t ext_capflags; + uint32_t ext_capflags2; +} __packed; + +/* Extended capability IE flags */ +#define IEEE80211_EXTCAPIE_2040COEXTMGMT 0x00000001 +#define IEEE80211_EXTCAPIE_TFS 0x00010000 +#define IEEE80211_EXTCAPIE_FMS 0x00000800 +#define IEEE80211_EXTCAPIE_WNMSLEEPMODE 0x00020000 +#define IEEE80211_EXTCAPIE_TIMBROADCAST 0x00040000 +#define IEEE80211_EXTCAPIE_PROXYARP 0x00001000 +#define IEEE80211_EXTCAPIE_BSSTRANSITION 0x00080000 +/* Tunneled Direct Link Setup (TDLS) extended capability bits */ +#define IEEE80211_EXTCAPIE_PEER_UAPSD_BUF_STA 0x10000000 +#define IEEE80211_EXTCAPIE_TDLS_PEER_PSM 0x20000000 +#define IEEE80211_EXTCAPIE_TDLS_CHAN_SX 0x40000000 +/* 2nd Extended capability IE flags bit32-bit63*/ +#define IEEE80211_EXTCAPIE_TDLSSUPPORT 0x00000020 /* bit-37 TDLS Support */ +#define IEEE80211_EXTCAPIE_TDLSPROHIBIT 0x00000040 /* bit-38 TDLS Prohibit Support */ +#define IEEE80211_EXTCAPIE_TDLSCHANSXPROHIBIT 0x00000080 /* bit-39 TDLS Channel Switch Prohibit */ +#define IEEE80211_EXTCAPIE_TDLS_WIDE_BAND 0x20000080 /* bit-61 TDLS Wide Bandwidth support */ +#define IEEE80211_EXTCAPIE_OP_MODE_NOTIFY 0x40000000 /* bit-62 Operating Mode notification */ + +/* + * These caps are populated when we recieve beacon/probe response + * This is used to maintain local TDLS cap bit masks + */ + +#define IEEE80211_TDLS_PROHIBIT 0x00000001 /* bit-1 TDLS Prohibit Support */ + +/* + * 20/40 BSS coexistence ie + */ +struct ieee80211_ie_bss_coex { + uint8_t elem_id; + uint8_t elem_len; +#if _BYTE_ORDER == _BIG_ENDIAN + uint8_t reserved1 : 1, + reserved2 : 1, + reserved3 : 1, + obss_exempt_grant : 1, + obss_exempt_req : 1, + ht20_width_req : 1, ht40_intolerant : 1, inf_request : 1; +#else + uint8_t inf_request : 1, + ht40_intolerant : 1, + ht20_width_req : 1, + obss_exempt_req : 1, + obss_exempt_grant : 1, reserved3 : 1, reserved2 : 1, reserved1 : 1; +#endif +} __packed; + +/* + * 20/40 BSS intolerant channel report ie + */ +struct ieee80211_ie_intolerant_report { + uint8_t elem_id; + uint8_t elem_len; + uint8_t reg_class; + uint8_t chan_list[1]; /* variable-length channel list */ +} __packed; + +/* + * 20/40 coext management action frame + */ +struct ieee80211_action_bss_coex_frame { + struct ieee80211_action ac_header; + struct ieee80211_ie_bss_coex coex; + struct ieee80211_ie_intolerant_report chan_report; +} __packed; + +typedef enum ieee80211_tie_interval_type { + IEEE80211_TIE_INTERVAL_TYPE_RESERVED = 0, + IEEE80211_TIE_INTERVAL_TYPE_REASSOC_DEADLINE_INTERVAL = 1, + IEEE80211_TIE_INTERVAL_TYPE_KEY_LIFETIME_INTERVAL = 2, + IEEE80211_TIE_INTERVAL_TYPE_ASSOC_COMEBACK_TIME = 3, +} ieee80211_tie_interval_type_t; + +struct ieee80211_ie_timeout_interval { + uint8_t elem_id; + uint8_t elem_len; + uint8_t interval_type; + uint32_t value; +} __packed; + +/* TODO -> Need to Check Redefinition Error used in only UMAC */ +#if 0 +/* Management MIC information element (IEEE 802.11w) */ +struct ieee80211_mmie { + uint8_t element_id; + uint8_t length; + uint16_t key_id; + uint8_t sequence_number[6]; + uint8_t mic[8]; +} __packed; +#endif + +/* + * 802.11n Secondary Channel Offset element + */ +#define IEEE80211_SEC_CHAN_OFFSET_SCN 0 /* no secondary channel */ +#define IEEE80211_SEC_CHAN_OFFSET_SCA 1 /* secondary channel above */ +#define IEEE80211_SEC_CHAN_OFFSET_SCB 3 /* secondary channel below */ + +struct ieee80211_ie_sec_chan_offset { + uint8_t elem_id; + uint8_t len; + uint8_t sec_chan_offset; +} __packed; + +/* + * 802.11ac Transmit Power Envelope element + */ +#define IEEE80211_VHT_TXPWR_IS_SUB_ELEMENT 1 /* It checks whether its sub element */ +#define IEEE80211_VHT_TXPWR_MAX_POWER_COUNT 4 /* Max TX power elements valid */ +#define IEEE80211_VHT_TXPWR_NUM_POWER_SUPPORTED 3 /* Max TX power elements supported */ +#define IEEE80211_VHT_TXPWR_LCL_MAX_PWR_UNITS_SHFT 3 /* B3-B5 Local Max transmit power units */ + +struct ieee80211_ie_vht_txpwr_env { + uint8_t elem_id; + uint8_t elem_len; + uint8_t txpwr_info; /* Transmit Power Information */ + uint8_t local_max_txpwr[4]; /* Local Max TxPower for 20,40,80,160MHz */ +} __packed; + +/* + * 802.11ac Wide Bandwidth Channel Switch Element + */ + +#define IEEE80211_VHT_EXTCH_SWITCH 1 /* For extension channel switch */ +#define CHWIDTH_VHT20 20 /* Channel width 20 */ +#define CHWIDTH_VHT40 40 /* Channel width 40 */ +#define CHWIDTH_VHT80 80 /* Channel width 80 */ +#define CHWIDTH_VHT160 160 /* Channel width 160 */ + +struct ieee80211_ie_wide_bw_switch { + uint8_t elem_id; + uint8_t elem_len; + uint8_t new_ch_width; /* New channel width */ + uint8_t new_ch_freq_seg1; /* Channel Center frequency 1 */ + uint8_t new_ch_freq_seg2; /* Channel Center frequency 2 */ +} __packed; + +#define IEEE80211_RSSI_RX 0x00000001 +#define IEEE80211_RSSI_TX 0x00000002 +#define IEEE80211_RSSI_EXTCHAN 0x00000004 +#define IEEE80211_RSSI_BEACON 0x00000008 +#define IEEE80211_RSSI_RXDATA 0x00000010 + +#define IEEE80211_RATE_TX 0 +#define IEEE80211_RATE_RX 1 +#define IEEE80211_LASTRATE_TX 2 +#define IEEE80211_LASTRATE_RX 3 +#define IEEE80211_RATECODE_TX 4 +#define IEEE80211_RATECODE_RX 5 + +#define IEEE80211_MAX_RATE_PER_CLIENT 8 +/* Define for the P2P Wildcard SSID */ +#define IEEE80211_P2P_WILDCARD_SSID "DIRECT-" + +#define IEEE80211_P2P_WILDCARD_SSID_LEN (sizeof(IEEE80211_P2P_WILDCARD_SSID) - 1) + +#endif /* CDS_COMMON_IEEE80211_H_ */ diff --git a/drivers/staging/qcacld-3.0/core/cds/inc/cds_ieee80211_defines.h b/drivers/staging/qcacld-3.0/core/cds/inc/cds_ieee80211_defines.h new file mode 100644 index 0000000000000000000000000000000000000000..037ad42950507aa7bda19f9ded7ee2854bf5cc00 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/cds/inc/cds_ieee80211_defines.h @@ -0,0 +1,1374 @@ +/* + * Copyright (c) 2011, 2014-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef CDS_IEEE80211_DEFINES_H_ +#define CDS_IEEE80211_DEFINES_H_ + +#include "cds_ieee80211_common.h" + +/* + * Public defines for Atheros Upper MAC Layer + */ + +/** + * @brief Opaque handle of 802.11 protocal layer. + */ +struct ieee80211com; +typedef struct ieee80211com *wlan_dev_t; + +/** + * @brief Opaque handle to App IE module. + */ +struct wlan_mlme_app_ie; +typedef struct wlan_mlme_app_ie *wlan_mlme_app_ie_t; + +/** + * @brief Opaque handle of network instance (vap) in 802.11 protocal layer. + */ +struct ieee80211vap; +typedef struct ieee80211vap *wlan_if_t; + +struct ieee80211vapprofile; +typedef struct ieee80211vapprofile *wlan_if_info_t; + +/** + * @brief Opaque handle of a node in the wifi network. + */ +struct ieee80211_node; +typedef struct ieee80211_node *wlan_node_t; + +/** + * @brief Opaque handle of OS interface (ifp in the case of unix ). + */ +struct _os_if_t; +typedef struct _os_if_t *os_if_t; + +/** + * + * @brief Opaque handle. + */ +typedef void *os_handle_t; + +/** + * @brief Opaque handle of a channel. + */ +struct ieee80211_channel; +typedef struct ieee80211_channel *wlan_chan_t; + +/** + * @brief Opaque handle scan_entry. + */ +struct ieee80211_scan_entry; +typedef struct ieee80211_scan_entry *wlan_scan_entry_t; + +/* AoW related defines */ +#define AOW_MAX_RECEIVER_COUNT 10 + +#define IEEE80211_NWID_LEN 32 +#define IEEE80211_ISO_COUNTRY_LENGTH 3 /* length of 11d ISO country string */ + +typedef struct _ieee80211_ssid { + int len; + uint8_t ssid[IEEE80211_NWID_LEN]; +} ieee80211_ssid; + +typedef struct ieee80211_tx_status { + int ts_flags; +#define IEEE80211_TX_ERROR 0x01 +#define IEEE80211_TX_XRETRY 0x02 + + int ts_retries; /* number of retries to successfully transmit this frame */ +#ifdef ATH_SUPPORT_TxBF + uint8_t ts_txbfstatus; +#define AR_BW_Mismatch 0x1 +#define AR_Stream_Miss 0x2 +#define AR_CV_Missed 0x4 +#define AR_Dest_Miss 0x8 +#define AR_Expired 0x10 +#define AR_TxBF_Valid_HW_Status (AR_BW_Mismatch|AR_Stream_Miss|AR_CV_Missed|AR_Dest_Miss|AR_Expired) +#define TxBF_STATUS_Sounding_Complete 0x20 +#define TxBF_STATUS_Sounding_Request 0x40 +#define TxBF_Valid_SW_Status (TxBF_STATUS_Sounding_Complete | TxBF_STATUS_Sounding_Request) +#define TxBF_Valid_Status (AR_TxBF_Valid_HW_Status | TxBF_Valid_SW_Status) + uint32_t ts_tstamp; /* tx time stamp */ +#endif +#ifdef ATH_SUPPORT_FLOWMAC_MODULE + uint8_t ts_flowmac_flags; +#define IEEE80211_TX_FLOWMAC_DONE 0x01 +#endif + uint32_t ts_rateKbps; +} ieee80211_xmit_status; + +#ifndef EXTERNAL_USE_ONLY +typedef struct ieee80211_rx_status { + int rs_numchains; + int rs_flags; +#define IEEE80211_RX_FCS_ERROR 0x01 +#define IEEE80211_RX_MIC_ERROR 0x02 +#define IEEE80211_RX_DECRYPT_ERROR 0x04 +/* holes in flags here between, ATH_RX_XXXX to IEEE80211_RX_XXX */ +#define IEEE80211_RX_KEYMISS 0x200 + int rs_rssi; /* RSSI (noise floor ajusted) */ + int rs_abs_rssi; /* absolute RSSI */ + int rs_datarate; /* data rate received */ + int rs_rateieee; + int rs_ratephy; + +#define IEEE80211_MAX_ANTENNA 3 /* Keep the same as ATH_MAX_ANTENNA */ + uint8_t rs_rssictl[IEEE80211_MAX_ANTENNA]; /* RSSI (noise floor ajusted) */ + uint8_t rs_rssiextn[IEEE80211_MAX_ANTENNA]; /* RSSI (noise floor ajusted) */ + uint8_t rs_isvalidrssi; /* rs_rssi is valid or not */ + + enum ieee80211_phymode rs_phymode; + int rs_freq; + + union { + uint8_t data[8]; + uint64_t tsf; + } rs_tstamp; + + /* + * Detail channel structure of recv frame. + * It could be NULL if not available + */ + struct ieee80211_channel *rs_full_chan; + + uint8_t rs_isaggr; + uint8_t rs_isapsd; + int16_t rs_noisefloor; + uint16_t rs_channel; +#ifdef ATH_SUPPORT_TxBF + uint32_t rs_rpttstamp; /* txbf report time stamp */ +#endif + + /* The following counts are meant to assist in stats calculation. + These variables are incremented only in specific situations, and + should not be relied upon for any purpose other than the original + stats related purpose they have been introduced for. */ + + uint16_t rs_cryptodecapcount; /* Crypto bytes decapped/demic'ed. */ + uint8_t rs_padspace; /* No. of padding bytes present after header + in wbuf. */ + uint8_t rs_qosdecapcount; /* QoS/HTC bytes decapped. */ + + /* End of stats calculation related counts. */ + + uint8_t rs_lsig[IEEE80211_LSIG_LEN]; + uint8_t rs_htsig[IEEE80211_HTSIG_LEN]; + uint8_t rs_servicebytes[IEEE80211_SB_LEN]; + +} ieee80211_recv_status; +#endif /* EXTERNAL_USE_ONLY */ + +/* + * flags to be passed to ieee80211_vap_create function . + */ +#define IEEE80211_CLONE_BSSID 0x0001 /* allocate unique mac/bssid */ +#define IEEE80211_CLONE_NOBEACONS 0x0002 /* don't setup beacon timers */ +#define IEEE80211_CLONE_WDS 0x0004 /* enable WDS processing */ +#define IEEE80211_CLONE_WDSLEGACY 0x0008 /* legacy WDS operation */ +#define IEEE80211_PRIMARY_VAP 0x0010 /* primary vap */ +#define IEEE80211_P2PDEV_VAP 0x0020 /* p2pdev vap */ +#define IEEE80211_P2PGO_VAP 0x0040 /* p2p-go vap */ +#define IEEE80211_P2PCLI_VAP 0x0080 /* p2p-client vap */ +#define IEEE80211_CLONE_MACADDR 0x0100 /* create vap w/ specified mac/bssid */ +#define IEEE80211_CLONE_MATADDR 0x0200 /* create vap w/ specified MAT addr */ +#define IEEE80211_WRAP_VAP 0x0400 /* wireless repeater ap vap */ + +/* + * For the new multi-vap scan feature, there is a set of default priority tables + * for each OpMode. + * The following are the default list of the VAP Scan Priority Mapping based on OpModes. + * NOTE: the following are only used when "#if ATH_SUPPORT_MULTIPLE_SCANS" is true. + */ +/* For IBSS opmode */ +#define DEF_VAP_SCAN_PRI_MAP_OPMODE_IBSS_BASE 0 +/* For STA opmode */ +#define DEF_VAP_SCAN_PRI_MAP_OPMODE_STA_BASE 0 +#define DEF_VAP_SCAN_PRI_MAP_OPMODE_STA_P2P_CLIENT 1 +/* For HostAp opmode */ +#define DEF_VAP_SCAN_PRI_MAP_OPMODE_AP_BASE 0 +#define DEF_VAP_SCAN_PRI_MAP_OPMODE_AP_P2P_GO 1 +#define DEF_VAP_SCAN_PRI_MAP_OPMODE_AP_P2P_DEVICE 2 +/* For BTAmp opmode */ +#define DEF_VAP_SCAN_PRI_MAP_OPMODE_BTAMP_BASE 0 + +typedef enum _ieee80211_dev_vap_event { + IEEE80211_VAP_CREATED = 1, + IEEE80211_VAP_STOPPED, + IEEE80211_VAP_DELETED +} ieee80211_dev_vap_event; + +typedef struct _wlan_dev_event_handler_table { + void (*wlan_dev_vap_event)(void *event_arg, wlan_dev_t, os_if_t, ieee80211_dev_vap_event); /* callback to receive vap events */ +#ifdef ATH_SUPPORT_SPECTRAL + void (*wlan_dev_spectral_indicate)(void *, void *, uint32_t); +#endif +} wlan_dev_event_handler_table; + +typedef enum _ieee80211_ap_stopped_reason { + IEEE80211_AP_STOPPED_REASON_DUMMY = 0, /* Dummy placeholder. Should not use */ + IEEE80211_AP_STOPPED_REASON_CHANNEL_DFS = 1, +} ieee80211_ap_stopped_reason; + +typedef int IEEE80211_REASON_CODE; +typedef int IEEE80211_STATUS; + +/* + * scan API related structs. + */ +typedef enum _ieee80211_scan_type { + IEEE80211_SCAN_BACKGROUND, + IEEE80211_SCAN_FOREGROUND, + IEEE80211_SCAN_SPECTRAL, + IEEE80211_SCAN_REPEATER_BACKGROUND, + IEEE80211_SCAN_REPEATER_EXT_BACKGROUND, + IEEE80211_SCAN_RADIO_MEASUREMENTS, +} ieee80211_scan_type; + +/* + * Priority numbers must be sequential, starting with 0. + */ +typedef enum ieee80211_scan_priority_t { + IEEE80211_SCAN_PRIORITY_VERY_LOW = 0, + IEEE80211_SCAN_PRIORITY_LOW, + IEEE80211_SCAN_PRIORITY_MEDIUM, + IEEE80211_SCAN_PRIORITY_HIGH, + IEEE80211_SCAN_PRIORITY_VERY_HIGH, + + IEEE80211_SCAN_PRIORITY_COUNT /* number of priorities supported */ +} IEEE80211_SCAN_PRIORITY; + +typedef uint16_t IEEE80211_SCAN_REQUESTOR; +typedef uint32_t IEEE80211_SCAN_ID; + +#define IEEE80211_SCAN_ID_NONE 0 + +/* All P2P scans currently use medium priority */ +#define IEEE80211_P2P_DEFAULT_SCAN_PRIORITY IEEE80211_SCAN_PRIORITY_MEDIUM +#define IEEE80211_P2P_SCAN_PRIORITY_HIGH IEEE80211_SCAN_PRIORITY_HIGH + +/* Masks identifying types/ID of scans */ +#define IEEE80211_SPECIFIC_SCAN 0x00000000 +#define IEEE80211_VAP_SCAN 0x01000000 +#define IEEE80211_ALL_SCANS 0x04000000 + +/** + * host scan bit. only relevant for host/target architecture. + * do not reuse this bit definition. target uses this . + * + */ +#define IEEE80211_HOST_SCAN 0x80000000 +#define IEEE80211_SCAN_CLASS_MASK 0xFF000000 + +#define IEEE80211_SCAN_PASSIVE 0x0001 /* passively scan all the channels */ +#define IEEE80211_SCAN_ACTIVE 0x0002 /* actively scan all the channels (regdomain rules still apply) */ +#define IEEE80211_SCAN_2GHZ 0x0004 /* scan 2GHz band */ +#define IEEE80211_SCAN_5GHZ 0x0008 /* scan 5GHz band */ +#define IEEE80211_SCAN_ALLBANDS (IEEE80211_SCAN_5GHZ | IEEE80211_SCAN_2GHZ) +#define IEEE80211_SCAN_CONTINUOUS 0x0010 /* keep scanning until maxscantime expires */ +#define IEEE80211_SCAN_FORCED 0x0020 /* forced scan (OS request) - should proceed even in the presence of data traffic */ +#define IEEE80211_SCAN_NOW 0x0040 /* scan now (User request) - should proceed even in the presence of data traffic */ +#define IEEE80211_SCAN_ADD_BCAST_PROBE 0x0080 /* add wildcard ssid and broadcast probe request if there is none */ +#define IEEE80211_SCAN_EXTERNAL 0x0100 /* scan requested by OS */ +#define IEEE80211_SCAN_BURST 0x0200 /* scan multiple channels before returning to BSS channel */ +#define IEEE80211_SCAN_CHAN_EVENT 0x0400 /* scan chan event for offload architectures */ +#define IEEE80211_SCAN_FILTER_PROBE_REQ 0x0800 /* Filter probe requests- applicable only for offload architectures */ + +#define IEEE80211_SCAN_PARAMS_MAX_SSID 10 +#define IEEE80211_SCAN_PARAMS_MAX_BSSID 10 + +/* flag definitions passed to scan_cancel API */ + +#define IEEE80211_SCAN_CANCEL_ASYNC 0x0 /* asynchronouly wait for scan SM to complete cancel */ +#define IEEE80211_SCAN_CANCEL_WAIT 0x1 /* wait for scan SM to complete cancel */ +#define IEEE80211_SCAN_CANCEL_SYNC 0x2 /* synchronously execute cancel scan */ + +#ifndef EXTERNAL_USE_ONLY +typedef bool (*ieee80211_scan_termination_check)(void *arg); + +typedef struct _ieee80211_scan_params { + ieee80211_scan_type type; + int min_dwell_time_active; /* min time in msec on active channels */ + int max_dwell_time_active; /* max time in msec on active channels (if no response) */ + int min_dwell_time_passive; /* min time in msec on passive channels */ + int max_dwell_time_passive; /* max time in msec on passive channels (if no response) */ + int min_rest_time; /* min time in msec on the BSS channel, only valid for BG scan */ + int max_rest_time; /* max time in msec on the BSS channel, only valid for BG scan */ + int max_offchannel_time; /* max time away from BSS channel, in ms */ + int repeat_probe_time; /* time before sending second probe request */ + int idle_time; /* time in msec on bss channel before switching channel */ + int max_scan_time; /* maximum time in msec allowed for scan */ + int probe_delay; /* delay in msec before sending probe request */ + int offchan_retry_delay; /* delay in msec before retrying off-channel switch */ + int min_beacon_count; /* number of home AP beacons to receive before leaving the home channel */ + int max_offchan_retries; /* maximum number of times to retry off-channel switch */ + int beacon_timeout; /* maximum time to wait for beacons */ + int flags; /* scan flags */ + int num_channels; /* number of channels to scan */ + bool multiple_ports_active; /* driver has multiple ports active in the home channel */ + bool restricted_scan; /* Perform restricted scan */ + bool chan_list_allocated; + IEEE80211_SCAN_PRIORITY p2p_scan_priority; /* indicates the scan priority if this is a P2P-related scan */ + uint32_t *chan_list; /* array of ieee channels (or) frequencies to scan */ + int num_ssid; /* number of desired ssids */ + ieee80211_ssid ssid_list[IEEE80211_SCAN_PARAMS_MAX_SSID]; + int num_bssid; /* number of desired bssids */ + uint8_t bssid_list[IEEE80211_SCAN_PARAMS_MAX_BSSID][IEEE80211_ADDR_LEN]; + struct ieee80211_node *bss_node; /* BSS node */ + int ie_len; /* length of the ie data to be added to probe req */ + uint8_t *ie_data; /* pointer to ie data */ + ieee80211_scan_termination_check check_termination_function; /* function checking for termination condition */ + void *check_termination_context; /* context passed to function above */ +} ieee80211_scan_params; + +/* Data types used to specify scan priorities */ +typedef uint32_t IEEE80211_PRIORITY_MAPPING[IEEE80211_SCAN_PRIORITY_COUNT]; + +/************************************** + * Called before attempting to roam. Modifies the rssiAdder of a BSS + * based on the preferred status of a BSS. + * + * According to CCX spec, AP in the neighbor list is not meant for giving extra + * weightage in roaming. By doing so, roaming becomes sticky. See bug 21220. + * Change the weightage to 0. Cisco may ask in future for a user control of + * this weightage. + */ +#define PREFERRED_BSS_RANK 20 +#define NEIGHBOR_BSS_RANK 0 /* must be less than preferred BSS rank */ + +/* + * The utility of the BSS is the metric used in the selection + * of a BSS. The Utility of the BSS is reduced if we just left the BSS. + * The Utility of the BSS is not reduced if we have left the + * BSS for 8 seconds (8000ms) or more. + * 2^13 milliseconds is a close approximation to avoid expensive division + */ +#define LAST_ASSOC_TIME_DELTA_REQUIREMENT (1 << 13) /* 8192 */ + +#define QBSS_SCALE_MAX 255 /* Qbss channel load Max value */ +#define QBSS_SCALE_DOWN_FACTOR 2 /* scale factor to reduce Qbss channel load */ +#define QBSS_HYST_ADJ 60 /* Qbss Weightage factor for the current AP */ + +/* + * Flags used to set field APState + */ +#define AP_STATE_GOOD 0x00 +#define AP_STATE_BAD 0x01 +#define AP_STATE_RETRY 0x10 +#define BAD_AP_TIMEOUT 6000 /* In milli seconds */ +/* + * To disable BAD_AP status check on any scan entry + */ +#define BAD_AP_TIMEOUT_DISABLED 0 + +/* + * BAD_AP timeout specified in seconds + */ +#define BAD_AP_TIMEOUT_IN_SECONDS 10 + +/* + * State values used to represent our assoc_state with ap (discrete, not bitmasks) + */ +#define AP_ASSOC_STATE_NONE 0 +#define AP_ASSOC_STATE_AUTH 1 +#define AP_ASSOC_STATE_ASSOC 2 + +/* + * Entries in the scan list are considered obsolete after 75 seconds. + */ +#define IEEE80211_SCAN_ENTRY_EXPIRE_TIME 75000 + +/* + * idle time is only valid for scan type IEEE80211_SCAN_BACKGROUND. + * if idle time is set then the scanner would change channel from BSS + * channel to foreign channel only if both resttime is expired and + * the theres was not traffic for idletime msec on the bss channel. + * value of 0 for idletime would cause the channel to switch from BSS + * channel to foreign channel as soon as the resttime is expired. + * + * if maxscantime is nonzero and if the scanner can not complete the + * scan in maxscantime msec then the scanner will cancel the scan and + * post IEEE80211_SCAN_COMPLETED event with reason SCAN_TIMEDOUT. + * + */ + +/* + * chanlist can be either ieee channels (or) frequencies. + * if a value is less than 1000 implementation assumes it + * as ieee channel # otherwise implementation assumes it + * as frequency in Mhz. + */ + +typedef enum _ieee80211_scan_event_type { + IEEE80211_SCAN_STARTED, + IEEE80211_SCAN_COMPLETED, + IEEE80211_SCAN_RADIO_MEASUREMENT_START, + IEEE80211_SCAN_RADIO_MEASUREMENT_END, + IEEE80211_SCAN_RESTARTED, + IEEE80211_SCAN_HOME_CHANNEL, + IEEE80211_SCAN_FOREIGN_CHANNEL, + IEEE80211_SCAN_BSSID_MATCH, + IEEE80211_SCAN_FOREIGN_CHANNEL_GET_NF, + IEEE80211_SCAN_DEQUEUED, + IEEE80211_SCAN_PREEMPTED, + + IEEE80211_SCAN_EVENT_COUNT +} ieee80211_scan_event_type; + +typedef enum ieee80211_scan_completion_reason { + IEEE80211_REASON_NONE, + IEEE80211_REASON_COMPLETED, + IEEE80211_REASON_CANCELLED, + IEEE80211_REASON_TIMEDOUT, + IEEE80211_REASON_TERMINATION_FUNCTION, + IEEE80211_REASON_MAX_OFFCHAN_RETRIES, + IEEE80211_REASON_PREEMPTED, + IEEE80211_REASON_RUN_FAILED, + IEEE80211_REASON_INTERNAL_STOP, + + IEEE80211_REASON_COUNT +} ieee80211_scan_completion_reason; + +typedef struct _ieee80211_scan_event { + ieee80211_scan_event_type type; + ieee80211_scan_completion_reason reason; + wlan_chan_t chan; + IEEE80211_SCAN_REQUESTOR requestor; /* Requestor ID passed to the scan_start function */ + IEEE80211_SCAN_ID scan_id; /* Specific ID of the scan reporting the event */ +} ieee80211_scan_event; + +typedef enum _ieee80211_scan_request_status { + IEEE80211_SCAN_STATUS_QUEUED, + IEEE80211_SCAN_STATUS_RUNNING, + IEEE80211_SCAN_STATUS_PREEMPTED, + IEEE80211_SCAN_STATUS_COMPLETED +} ieee80211_scan_request_status; + +/* + * the sentry field of tht ieee80211_scan_event is only valid if the + * event type is IEEE80211_SCAN_BSSID_MATCH. + */ + +typedef void (*ieee80211_scan_event_handler)(wlan_if_t vaphandle, + ieee80211_scan_event *event, + void *arg); + +typedef struct _ieee80211_scan_info { + ieee80211_scan_type type; + IEEE80211_SCAN_REQUESTOR requestor; /* Originator ID passed to the scan_start function */ + IEEE80211_SCAN_ID scan_id; /* Specific ID of the scan reporting the event */ + IEEE80211_SCAN_PRIORITY priority; /* Requested priority level (low/medium/high) */ + ieee80211_scan_request_status scheduling_status; /* Queued/running/preempted/completed */ + int min_dwell_time_active; /* min time in msec on active channels */ + int max_dwell_time_active; /* max time in msec on active channel (if no response) */ + int min_dwell_time_passive; /* min time in msec on passive channels */ + int max_dwell_time_passive; /* max time in msec on passive channel */ + int min_rest_time; /* min time in msec on the BSS channel, only valid for BG scan */ + int max_rest_time; /* max time in msec on the BSS channel, only valid for BG scan */ + int max_offchannel_time; /* max time away from BSS channel, in ms */ + int repeat_probe_time; /* time before sending second probe request */ + int min_beacon_count; /* number of home AP beacons to receive before leaving the home channel */ + int flags; /* scan flags */ + systime_t scan_start_time; /* system time when last scani started */ + int scanned_channels; /* number of scanned channels */ + int default_channel_list_length; /* number of channels in the default channel list */ + int channel_list_length; /* number of channels in the channel list used for the current scan */ + uint8_t in_progress : 1, /* if the scan is in progress */ + cancelled : 1, /* if the scan is cancelled */ + preempted : 1, /* if the scan is preempted */ + restricted : 1; /* if the scan is restricted */ +} ieee80211_scan_info; + +typedef struct _ieee80211_scan_request_info { + wlan_if_t vaphandle; + IEEE80211_SCAN_REQUESTOR requestor; + IEEE80211_SCAN_PRIORITY requested_priority; + IEEE80211_SCAN_PRIORITY absolute_priority; + IEEE80211_SCAN_ID scan_id; + ieee80211_scan_request_status scheduling_status; + ieee80211_scan_params params; + systime_t request_timestamp; + uint32_t maximum_duration; +} ieee80211_scan_request_info; + +#endif /* EXTERNAL_USE_ONLY */ + +#ifndef EXTERNAL_USE_ONLY +typedef void (*ieee80211_acs_event_handler)(void *arg, wlan_chan_t channel); +#endif /* EXTERNAL_USE_ONLY */ + +#define MAX_CHAINS 3 + +typedef struct _wlan_rssi_info { + int8_t avg_rssi; /* average rssi */ + uint8_t valid_mask; /* bitmap of valid elements in rssi_ctrl/ext array */ + int8_t rssi_ctrl[MAX_CHAINS]; + int8_t rssi_ext[MAX_CHAINS]; +} wlan_rssi_info; + +typedef enum _wlan_rssi_type { + WLAN_RSSI_TX, + WLAN_RSSI_RX, + WLAN_RSSI_BEACON, /* rssi of the beacon, only valid for STA/IBSS vap */ + WLAN_RSSI_RX_DATA +} wlan_rssi_type; + +typedef enum _ieee80211_rate_type { + IEEE80211_RATE_TYPE_LEGACY, + IEEE80211_RATE_TYPE_MCS, +} ieee80211_rate_type; + +typedef struct _ieee80211_rate_info { + ieee80211_rate_type type; + uint32_t rate; /* average rate in kbps */ + uint32_t lastrate; /* last packet rate in kbps */ + uint8_t mcs; /* mcs index . is valid if rate type is MCS20 or MCS40 */ + uint8_t maxrate_per_client; +} ieee80211_rate_info; + +typedef enum _ieee80211_node_param_type { + IEEE80211_NODE_PARAM_TX_POWER, + IEEE80211_NODE_PARAM_ASSOCID, + IEEE80211_NODE_PARAM_INACT, /* inactivity timer value */ + IEEE80211_NODE_PARAM_AUTH_MODE, /* auth mode */ + IEEE80211_NODE_PARAM_CAP_INFO, /* auth mode */ +} ieee80211_node_param_type; + +/* + * Per/node (station) statistics available when operating as an AP. + */ +struct ieee80211_nodestats { + uint32_t ns_rx_data; /* rx data frames */ + uint32_t ns_rx_mgmt; /* rx management frames */ + uint32_t ns_rx_ctrl; /* rx control frames */ + uint32_t ns_rx_ucast; /* rx unicast frames */ + uint32_t ns_rx_mcast; /* rx multi/broadcast frames */ + uint64_t ns_rx_bytes; /* rx data count (bytes) */ + uint64_t ns_rx_beacons; /* rx beacon frames */ + uint32_t ns_rx_proberesp; /* rx probe response frames */ + + uint32_t ns_rx_dup; /* rx discard 'cuz dup */ + uint32_t ns_rx_noprivacy; /* rx w/ wep but privacy off */ + uint32_t ns_rx_wepfail; /* rx wep processing failed */ + uint32_t ns_rx_demicfail; /* rx demic failed */ + + /* We log MIC and decryption failures against Transmitter STA stats. + Though the frames may not actually be sent by STAs corresponding + to TA, the stats are still valuable for some customers as a sort + of rough indication. + Also note that the mapping from TA to STA may fail sometimes. */ + uint32_t ns_rx_tkipmic; /* rx TKIP MIC failure */ + uint32_t ns_rx_ccmpmic; /* rx CCMP MIC failure */ + uint32_t ns_rx_wpimic; /* rx WAPI MIC failure */ + uint32_t ns_rx_tkipicv; /* rx ICV check failed (TKIP) */ + uint32_t ns_rx_decap; /* rx decapsulation failed */ + uint32_t ns_rx_defrag; /* rx defragmentation failed */ + uint32_t ns_rx_disassoc; /* rx disassociation */ + uint32_t ns_rx_deauth; /* rx deauthentication */ + uint32_t ns_rx_action; /* rx action */ + uint32_t ns_rx_decryptcrc; /* rx decrypt failed on crc */ + uint32_t ns_rx_unauth; /* rx on unauthorized port */ + uint32_t ns_rx_unencrypted; /* rx unecrypted w/ privacy */ + + uint32_t ns_tx_data; /* tx data frames */ + uint32_t ns_tx_data_success; /* tx data frames successfully + transmitted (unicast only) */ + uint32_t ns_tx_mgmt; /* tx management frames */ + uint32_t ns_tx_ucast; /* tx unicast frames */ + uint32_t ns_tx_mcast; /* tx multi/broadcast frames */ + uint64_t ns_tx_bytes; /* tx data count (bytes) */ + uint64_t ns_tx_bytes_success; /* tx success data count - unicast only + (bytes) */ + uint32_t ns_tx_probereq; /* tx probe request frames */ + uint32_t ns_tx_uapsd; /* tx on uapsd queue */ + uint32_t ns_tx_discard; /* tx dropped by NIC */ + + uint32_t ns_tx_novlantag; /* tx discard 'cuz no tag */ + uint32_t ns_tx_vlanmismatch; /* tx discard 'cuz bad tag */ + + uint32_t ns_tx_eosplost; /* uapsd EOSP retried out */ + + uint32_t ns_ps_discard; /* ps discard 'cuz of age */ + + uint32_t ns_uapsd_triggers; /* uapsd triggers */ + uint32_t ns_uapsd_duptriggers; /* uapsd duplicate triggers */ + uint32_t ns_uapsd_ignoretriggers; /* uapsd duplicate triggers */ + uint32_t ns_uapsd_active; /* uapsd duplicate triggers */ + uint32_t ns_uapsd_triggerenabled; /* uapsd duplicate triggers */ + + /* MIB-related state */ + uint32_t ns_tx_assoc; /* [re]associations */ + uint32_t ns_tx_assoc_fail; /* [re]association failures */ + uint32_t ns_tx_auth; /* [re]authentications */ + uint32_t ns_tx_auth_fail; /* [re]authentication failures */ + uint32_t ns_tx_deauth; /* deauthentications */ + uint32_t ns_tx_deauth_code; /* last deauth reason */ + uint32_t ns_tx_disassoc; /* disassociations */ + uint32_t ns_tx_disassoc_code; /* last disassociation reason */ + uint32_t ns_psq_drops; /* power save queue drops */ +}; + +/* + * station power save mode. + */ +typedef enum ieee80211_psmode { + IEEE80211_PWRSAVE_NONE = 0, /* no power save */ + IEEE80211_PWRSAVE_LOW, + IEEE80211_PWRSAVE_NORMAL, + IEEE80211_PWRSAVE_MAXIMUM, + IEEE80211_PWRSAVE_WNM /* WNM-Sleep Mode */ +} ieee80211_pwrsave_mode; + +/* station power save pspoll handling */ +typedef enum { + IEEE80211_CONTINUE_PSPOLL_FOR_MORE_DATA, + IEEE80211_WAKEUP_FOR_MORE_DATA, +} ieee80211_pspoll_moredata_handling; + +/* + * apps power save state. + */ +typedef enum { + APPS_AWAKE = 0, + APPS_PENDING_SLEEP, + APPS_SLEEP, + APPS_FAKE_SLEEP, /* Pending blocking sleep */ + APPS_FAKING_SLEEP, /* Blocking sleep */ + APPS_UNKNOWN_PWRSAVE, +} ieee80211_apps_pwrsave_state; + +typedef enum _iee80211_mimo_powersave_mode { + IEEE80211_MIMO_POWERSAVE_NONE, /* no mimo power save */ + IEEE80211_MIMO_POWERSAVE_STATIC, /* static mimo power save */ + IEEE80211_MIMO_POWERSAVE_DYNAMIC /* dynamic mimo powersave */ +} ieee80211_mimo_powersave_mode; + +#ifdef ATH_COALESCING +typedef enum _ieee80211_coalescing_state { + IEEE80211_COALESCING_DISABLED = 0, /* Coalescing is disabled */ + IEEE80211_COALESCING_DYNAMIC = 1, /* Dynamically move to Enabled state based on Uruns */ + IEEE80211_COALESCING_ENABLED = 2, /* Coalescing is enabled */ +} ieee80211_coalescing_state; + +#define IEEE80211_TX_COALESCING_THRESHOLD 5 /* Number of underrun errors to trigger coalescing */ +#endif + +typedef enum _ieee80211_cap { + IEEE80211_CAP_SHSLOT, /* CAPABILITY: short slot */ + IEEE80211_CAP_SHPREAMBLE, /* CAPABILITY: short premable */ + IEEE80211_CAP_MULTI_DOMAIN, /* CAPABILITY: multiple domain */ + IEEE80211_CAP_WMM, /* CAPABILITY: WMM */ + IEEE80211_CAP_HT, /* CAPABILITY: HT */ + IEEE80211_CAP_PERF_PWR_OFLD, /* CAPABILITY: power performance offload support */ + IEEE80211_CAP_11AC, /* CAPABILITY: 11ac support */ +} ieee80211_cap; + +typedef enum _ieee80211_device_param { + IEEE80211_DEVICE_RSSI_CTL, + IEEE80211_DEVICE_NUM_TX_CHAIN, + IEEE80211_DEVICE_NUM_RX_CHAIN, + IEEE80211_DEVICE_TX_CHAIN_MASK, + IEEE80211_DEVICE_RX_CHAIN_MASK, + IEEE80211_DEVICE_TX_CHAIN_MASK_LEGACY, + IEEE80211_DEVICE_RX_CHAIN_MASK_LEGACY, + IEEE80211_DEVICE_BMISS_LIMIT, /* # of beacon misses for HW to generate BMISS intr */ + IEEE80211_DEVICE_PROTECTION_MODE, /* protection mode */ + IEEE80211_DEVICE_BLKDFSCHAN, /* block the use of DFS channels */ + IEEE80211_DEVICE_GREEN_AP_PS_ENABLE, + IEEE80211_DEVICE_GREEN_AP_PS_TIMEOUT, + IEEE80211_DEVICE_GREEN_AP_PS_ON_TIME, + IEEE80211_DEVICE_CWM_EXTPROTMODE, + IEEE80211_DEVICE_CWM_EXTPROTSPACING, + IEEE80211_DEVICE_CWM_ENABLE, + IEEE80211_DEVICE_CWM_EXTBUSYTHRESHOLD, + IEEE80211_DEVICE_DOTH, + IEEE80211_DEVICE_ADDBA_MODE, + IEEE80211_DEVICE_COUNTRYCODE, + IEEE80211_DEVICE_MULTI_CHANNEL, /* turn on/off off channel support */ + IEEE80211_DEVICE_MAX_AMSDU_SIZE, /* Size of AMSDU to be sent on the air */ + IEEE80211_DEVICE_P2P, /* Enable or Disable P2P */ + IEEE80211_DEVICE_OVERRIDE_SCAN_PROBERESPONSE_IE, /* Override scan Probe response IE, 0: Don't over-ride */ + IEEE80211_DEVICE_2G_CSA, + IEEE80211_DEVICE_PWRTARGET, + IEEE80211_DEVICE_OFF_CHANNEL_SUPPORT, +} ieee80211_device_param; + +typedef enum _ieee80211_param { + IEEE80211_BEACON_INTVAL, /* in TUs */ + IEEE80211_LISTEN_INTVAL, /* number of beacons */ + IEEE80211_DTIM_INTVAL, /* number of beacons */ + IEEE80211_BMISS_COUNT_RESET, /* number of beacon miss intrs before reset */ + IEEE80211_BMISS_COUNT_MAX, /* number of beacon miss intrs for bmiss notificationst */ + IEEE80211_ATIM_WINDOW, /* ATIM window */ + IEEE80211_SHORT_SLOT, /* short slot on/off */ + IEEE80211_SHORT_PREAMBLE, /* short preamble on/off */ + IEEE80211_RTS_THRESHOLD, /* rts threshold, 0 means no rts threshold */ + IEEE80211_FRAG_THRESHOLD, /* fragmentation threshold, 0 means no rts threshold */ + IEEE80211_FIXED_RATE, /* + * rate code series(0: auto rate, 32 bit value: rate + * codes for 4 rate series. each byte for one rate series) + */ + IEEE80211_MCAST_RATE, /* rate in Kbps */ + IEEE80211_TXPOWER, /* in 0.5db units */ + IEEE80211_AMPDU_DENCITY, /* AMPDU dencity */ + IEEE80211_AMPDU_LIMIT, /* AMPDU limit */ + IEEE80211_MAX_AMPDU, /* Max AMPDU Exp */ + IEEE80211_VHT_MAX_AMPDU, /* VHT Max AMPDU Exp */ + IEEE80211_WPS_MODE, /* WPS mode */ + IEEE80211_TSN_MODE, /* TSN mode */ + IEEE80211_MULTI_DOMAIN, /* Multiple domain */ + IEEE80211_SAFE_MODE, /* Safe mode */ + IEEE80211_NOBRIDGE_MODE, /* No bridging done, all frames sent up the stack */ + IEEE80211_PERSTA_KEYTABLE_SIZE, /* IBSS-only, read-only: persta key table size */ + IEEE80211_RECEIVE_80211, /* deliver std 802.11 frames 802.11 instead of ethernet frames on the rx */ + IEEE80211_SEND_80211, /* OS sends std 802.11 frames 802.11 instead of ethernet frames on tx side */ + IEEE80211_MIN_BEACON_COUNT, /* minumum number beacons to tx/rx before vap can pause */ + IEEE80211_IDLE_TIME, /* minimun no activity time before vap can pause */ + IEEE80211_MIN_FRAMESIZE, /* smallest frame size we are allowed to receive */ + /* features. 0:feature is off. 1:feature is on. */ + IEEE80211_FEATURE_WMM, /* WMM */ + IEEE80211_FEATURE_WMM_PWRSAVE, /* WMM Power Save */ + IEEE80211_FEATURE_UAPSD, /* UAPSD setting (BE/BK/VI/VO) */ + IEEE80211_FEATURE_WDS, /* dynamic WDS feature */ + IEEE80211_FEATURE_PRIVACY, /* encryption */ + IEEE80211_FEATURE_DROP_UNENC, /* drop un encrypted frames */ + IEEE80211_FEATURE_COUNTER_MEASURES, /* turn on couter measures */ + IEEE80211_FEATURE_HIDE_SSID, /* turn on hide ssid feature */ + IEEE80211_FEATURE_APBRIDGE, /* turn on internal mcast traffic bridging for AP */ + IEEE80211_FEATURE_PUREB, /* turn on pure B mode for AP */ + IEEE80211_FEATURE_PUREG, /* turn on pure G mode for AP */ + IEEE80211_FEATURE_REGCLASS, /* add regulatory class IE in AP */ + IEEE80211_FEATURE_COUNTRY_IE, /* add country IE for vap in AP */ + IEEE80211_FEATURE_IC_COUNTRY_IE, /* add country IE for ic in AP */ + IEEE80211_FEATURE_DOTH, /* enable 802.11h */ + IEEE80211_FEATURE_PURE11N, /* enable pure 11n mode */ + IEEE80211_FEATURE_PRIVATE_RSNIE, /* enable OS shim to setup RSN IE */ + IEEE80211_FEATURE_COPY_BEACON, /* keep a copy of beacon */ + IEEE80211_FEATURE_PSPOLL, /* enable/disable pspoll mode in power save SM */ + IEEE80211_FEATURE_CONTINUE_PSPOLL_FOR_MOREDATA, /* enable/disable option to contunue sending ps polls when there is more data */ + IEEE80211_FEATURE_AMPDU, /* Enable or Disable Aggregation */ +#ifdef ATH_COALESCING + IEEE80211_FEATURE_TX_COALESCING, /* enable tx coalescing */ +#endif + IEEE80211_FEATURE_VAP_IND, /* Repeater independant VAP */ + IEEE80211_FIXED_RETRIES, /* fixed retries 0-4 */ + IEEE80211_SHORT_GI, /* short gi on/off */ + IEEE80211_HT40_INTOLERANT, + IEEE80211_CHWIDTH, + IEEE80211_CHEXTOFFSET, + IEEE80211_DISABLE_2040COEXIST, + IEEE80211_DISABLE_HTPROTECTION, + IEEE80211_STA_QUICKKICKOUT, + IEEE80211_CHSCANINIT, + IEEE80211_FEATURE_STAFWD, /* dynamic AP Client feature */ + IEEE80211_DRIVER_CAPS, + IEEE80211_UAPSD_MAXSP, /* UAPSD service period setting (0:unlimited, 2,4,6) */ + IEEE80211_WEP_MBSSID, + IEEE80211_MGMT_RATE, /* ieee rate to be used for management */ + IEEE80211_RESMGR_VAP_AIR_TIME_LIMIT, /* When multi-channel enabled, restrict air-time allocated to a VAP */ + IEEE80211_TDLS_MACADDR1, /* Upper 4 bytes of device's MAC address */ + IEEE80211_TDLS_MACADDR2, /* Lower 2 bytes of device's MAC address */ + IEEE80211_TDLS_ACTION, /* TDLS action requested */ + IEEE80211_AUTO_ASSOC, + IEEE80211_PROTECTION_MODE, /* per VAP protection mode */ + IEEE80211_AUTH_INACT_TIMEOUT, /* inactivity time while waiting for 802.11x auth to complete */ + IEEE80211_INIT_INACT_TIMEOUT, /* inactivity time while waiting for 802.11 auth/assoc to complete */ + IEEE80211_RUN_INACT_TIMEOUT, /* inactivity time when fully authed */ + IEEE80211_PROBE_INACT_TIMEOUT, /* inactivity counter value below which starts probing */ + IEEE80211_QBSS_LOAD, + IEEE80211_WNM_CAP, + IEEE80211_WNM_BSS_CAP, + IEEE80211_WNM_TFS_CAP, + IEEE80211_WNM_TIM_CAP, + IEEE80211_WNM_SLEEP_CAP, + IEEE80211_WNM_FMS_CAP, + IEEE80211_AP_REJECT_DFS_CHAN, /* AP to reject resuming on DFS Channel */ + IEEE80211_ABOLT, + IEEE80211_COMP, + IEEE80211_FF, + IEEE80211_TURBO, + IEEE80211_BURST, + IEEE80211_AR, + IEEE80211_SLEEP, + IEEE80211_EOSPDROP, + IEEE80211_MARKDFS, + IEEE80211_WDS_AUTODETECT, + IEEE80211_WEP_TKIP_HT, + IEEE80211_ATH_RADIO, + IEEE80211_IGNORE_11DBEACON, + /* Video debug feature */ + IEEE80211_VI_DBG_CFG, /* Video debug configuration - Bit0- enable dbg, Bit1 - enable stats log */ + IEEE80211_VI_DBG_NUM_STREAMS, /* Total number of receive streams */ + IEEE80211_VI_STREAM_NUM, /* the stream number whose marker parameters are being set */ + IEEE80211_VI_DBG_NUM_MARKERS, /* total number of markers used to filter pkts */ + IEEE80211_VI_MARKER_NUM, /* the marker number whose parameters (offset, size & match) are being set */ + IEEE80211_VI_MARKER_OFFSET_SIZE, /* byte offset from skb start (upper 16 bits) & size in bytes(lower 16 bits) */ + IEEE80211_VI_MARKER_MATCH, /* marker pattern match used in filtering */ + IEEE80211_VI_RXSEQ_OFFSET_SIZE, /* Rx Seq num offset skb start (upper 16 bits) & size in bytes(lower 16 bits) */ + IEEE80211_VI_RX_SEQ_RSHIFT, /* right-shift value in case field is not word aligned */ + IEEE80211_VI_RX_SEQ_MAX, /* maximum Rx Seq number (to check wrap around) */ + IEEE80211_VI_RX_SEQ_DROP, /* Indicator to the debug app that a particular seq num has been dropped */ + IEEE80211_VI_TIME_OFFSET_SIZE, /* Timestamp offset skb start (upper 16 bits) & size in bytes(lower 16 bits) */ + IEEE80211_VI_RESTART, /* If set to 1 resets all internal variables/counters & restarts debug tool */ + IEEE80211_VI_RXDROP_STATUS, /* Total RX drops in wireless */ + IEEE80211_TRIGGER_MLME_RESP, /* Option for App to trigger mlme response */ +#ifdef ATH_SUPPORT_TxBF + IEEE80211_TXBF_AUTO_CVUPDATE, /* auto CV update enable */ + IEEE80211_TXBF_CVUPDATE_PER, /* per threshold to initial CV update */ +#endif + IEEE80211_MAX_CLIENT_NUMBERS, + IEEE80211_SMARTNET, + IEEE80211_FEATURE_MFP_TEST, /* MFP test */ + IEEE80211_WEATHER_RADAR, /* weather radar channel skip */ + IEEE80211_WEP_KEYCACHE, /* WEP KEYCACHE is enable */ + IEEE80211_SEND_DEAUTH, /* send deauth instead of disassoc while doing interface down */ + IEEE80211_SET_TXPWRADJUST, + IEEE80211_RRM_CAP, + IEEE80211_RRM_DEBUG, + IEEE80211_RRM_STATS, + IEEE80211_RRM_SLWINDOW, + IEEE80211_FEATURE_OFF_CHANNEL_SUPPORT, + IEEE80211_FIXED_VHT_MCS, /* VHT mcs index */ + IEEE80211_FIXED_NSS, /* Spatial Streams count */ + IEEE80211_SUPPORT_LDPC, /* LDPC Support */ + IEEE80211_SUPPORT_TX_STBC, /* TX STBC enable/disable */ + IEEE80211_SUPPORT_RX_STBC, /* RX STBC enable/disable */ + IEEE80211_DEFAULT_KEYID, /* XMIT default key */ + IEEE80211_OPMODE_NOTIFY_ENABLE, /* Op mode notification enable/disable */ + IEEE80211_ENABLE_RTSCTS, /* Enable/Disable RTS-CTS */ + IEEE80211_VHT_MCSMAP, /* VHT MCS Map */ + IEEE80211_GET_ACS_STATE, /* get acs state */ + IEEE80211_GET_CAC_STATE, /* get cac state */ +} ieee80211_param; + +#define IEEE80211_PROTECTION_NONE 0 +#define IEEE80211_PROTECTION_CTSTOSELF 1 +#define IEEE80211_PROTECTION_RTS_CTS 2 + +typedef enum _ieee80211_privacy_filter { + IEEE80211_PRIVACY_FILTER_ALLWAYS, + IEEE80211_PRIVACY_FILTER_KEY_UNAVAILABLE, +} ieee80211_privacy_filter; + +typedef enum _ieee80211_privacy_filter_packet_type { + IEEE80211_PRIVACY_FILTER_PACKET_UNICAST, + IEEE80211_PRIVACY_FILTER_PACKET_MULTICAST, + IEEE80211_PRIVACY_FILTER_PACKET_BOTH +} ieee80211_privacy_filter_packet_type; + +typedef struct _ieee80211_privacy_excemption_filter { + uint16_t ether_type; /* type of ethernet to apply this filter, in host byte order */ + ieee80211_privacy_filter filter_type; + ieee80211_privacy_filter_packet_type packet_type; +} ieee80211_privacy_exemption; + +/* + * Authentication mode. + * NB: the usage of auth modes NONE, AUTO are deprecated, + * they are implemented through combinations of other auth modes + * and cipher types. The deprecated values are preserved here to + * maintain binary compatibility with applications like + * wpa_supplicant and hostapd. + */ +typedef enum _ieee80211_auth_mode { + IEEE80211_AUTH_NONE = 0, /* deprecated */ + IEEE80211_AUTH_OPEN = 1, /* open */ + IEEE80211_AUTH_SHARED = 2, /* shared-key */ + IEEE80211_AUTH_8021X = 3, /* 802.1x */ + IEEE80211_AUTH_AUTO = 4, /* deprecated */ + IEEE80211_AUTH_WPA = 5, /* WPA */ + IEEE80211_AUTH_RSNA = 6, /* WPA2/RSNA */ + IEEE80211_AUTH_CCKM = 7, /* CCK */ + IEEE80211_AUTH_WAPI = 8, /* WAPI */ +} ieee80211_auth_mode; + +#define IEEE80211_AUTH_MAX (IEEE80211_AUTH_WAPI+1) + +/* + * Cipher types. + * NB: The values are preserved here to maintain binary compatibility + * with applications like wpa_supplicant and hostapd. + */ +typedef enum _ieee80211_cipher_type { + IEEE80211_CIPHER_WEP = 0, + IEEE80211_CIPHER_TKIP = 1, + IEEE80211_CIPHER_AES_OCB = 2, + IEEE80211_CIPHER_AES_CCM = 3, + IEEE80211_CIPHER_WAPI = 4, + IEEE80211_CIPHER_CKIP = 5, + IEEE80211_CIPHER_AES_CMAC = 6, + IEEE80211_CIPHER_NONE = 7, +} ieee80211_cipher_type; + +#define IEEE80211_CIPHER_MAX (IEEE80211_CIPHER_NONE+1) + +/* key direction */ +typedef enum _ieee80211_key_direction { + IEEE80211_KEY_DIR_TX, + IEEE80211_KEY_DIR_RX, + IEEE80211_KEY_DIR_BOTH +} ieee80211_key_direction; + +#define IEEE80211_KEYIX_NONE ((uint16_t) -1) + +typedef struct _ieee80211_keyval { + ieee80211_cipher_type keytype; + ieee80211_key_direction keydir; + u_int persistent : 1, /* persistent key */ + mfp : 1; /* management frame protection */ + uint16_t keylen; /* length of the key data fields */ + uint8_t *macaddr; /* mac address of length IEEE80211_ADDR_LEN . all bytes are 0xff for multicast key */ + uint64_t keyrsc; + uint64_t keytsc; + uint16_t txmic_offset; /* TKIP/SMS4 only: offset to tx mic key */ + uint16_t rxmic_offset; /* TKIP/SMS4 only: offset to rx mic key */ + uint8_t *keydata; +#ifdef ATH_SUPPORT_WAPI + uint8_t key_used; /*index for WAPI rekey labeling */ +#endif +} ieee80211_keyval; + +#define IEEE80211_AES_CMAC_LEN 128 +typedef enum _ieee80211_rsn_param { + IEEE80211_UCAST_CIPHER_LEN, + IEEE80211_MCAST_CIPHER_LEN, + IEEE80211_MCASTMGMT_CIPHER_LEN, + IEEE80211_KEYMGT_ALGS, + IEEE80211_RSN_CAPS +} ieee80211_rsn_param; + +#define IEEE80211_PMKID_LEN 16 + +typedef struct _ieee80211_pmkid_entry { + uint8_t bssid[IEEE80211_ADDR_LEN]; + uint8_t pmkid[IEEE80211_PMKID_LEN]; +} ieee80211_pmkid_entry; + +typedef enum _wlan_wme_param { + WLAN_WME_CWMIN, + WLAN_WME_CWMAX, + WLAN_WME_AIFS, + WLAN_WME_TXOPLIMIT, + WLAN_WME_ACM, /*bss only */ + WLAN_WME_ACKPOLICY /*bss only */ +} wlan_wme_param; + +typedef enum _ieee80211_frame_type { + IEEE80211_FRAME_TYPE_PROBEREQ, + IEEE80211_FRAME_TYPE_BEACON, + IEEE80211_FRAME_TYPE_PROBERESP, + IEEE80211_FRAME_TYPE_ASSOCREQ, + IEEE80211_FRAME_TYPE_ASSOCRESP, + IEEE80211_FRAME_TYPE_AUTH +} ieee80211_frame_type; + +#define IEEE80211_FRAME_TYPE_MAX (IEEE80211_FRAME_TYPE_AUTH+1) + +typedef enum _ieee80211_ampdu_mode { + IEEE80211_AMPDU_MODE_OFF, /* disable AMPDU */ + IEEE80211_AMPDU_MODE_ON, /* enable AMPDU */ + IEEE80211_AMPDU_MODE_WDSVAR /* enable AMPDU with 4addr WAR */ +} ieee80211_ampdu_mode; + +typedef enum _ieee80211_reset_type { + IEEE80211_RESET_TYPE_DEVICE = 0, /* device reset on error: tx timeout and etc. */ + IEEE80211_RESET_TYPE_DOT11_INTF, /* dot11 reset: only reset one network interface (vap) */ + IEEE80211_RESET_TYPE_INTERNAL, /* internal reset */ +} ieee80211_reset_type; + +typedef struct _ieee80211_reset_request { + ieee80211_reset_type type; + + u_int reset_hw : 1, /* reset the actual H/W */ + /* + * The following fields are only valid for DOT11 reset, i.e., + * IEEE80211_RESET_TYPE_DOT11_INTF + */ + reset_phy : 1, /* reset PHY */ + reset_mac : 1, /* reset MAC */ + set_default_mib : 1, /* set default MIB variables */ + no_flush : 1; + uint8_t macaddr[IEEE80211_ADDR_LEN]; + enum ieee80211_phymode phy_mode; +} ieee80211_reset_request; + +#define IEEE80211_MSG_MAX 63 +#define IEEE80211_MSG_SMARTANT 7 /* Bit 7 (0x80)for Smart Antenna debug */ +enum { + /* IEEE80211_PARAM_DBG_LVL */ + IEEE80211_MSG_TDLS = 0, /* TDLS */ + IEEE80211_MSG_ACS, /* auto channel selection */ + IEEE80211_MSG_SCAN_SM, /* scan state machine */ + IEEE80211_MSG_SCANENTRY, /* scan entry */ + IEEE80211_MSG_WDS, /* WDS handling */ + IEEE80211_MSG_ACTION, /* action management frames */ + IEEE80211_MSG_ROAM, /* sta-mode roaming */ + IEEE80211_MSG_INACT, /* inactivity handling */ + IEEE80211_MSG_DOTH = 8, /* 11.h */ + IEEE80211_MSG_IQUE, /* IQUE features */ + IEEE80211_MSG_WME, /* WME protocol */ + IEEE80211_MSG_ACL, /* ACL handling */ + IEEE80211_MSG_WPA, /* WPA/RSN protocol */ + IEEE80211_MSG_RADKEYS, /* dump 802.1x keys */ + IEEE80211_MSG_RADDUMP, /* dump 802.1x radius packets */ + IEEE80211_MSG_RADIUS, /* 802.1x radius client */ + IEEE80211_MSG_DOT1XSM = 16, /* 802.1x state machine */ + IEEE80211_MSG_DOT1X, /* 802.1x authenticator */ + IEEE80211_MSG_POWER, /* power save handling */ + IEEE80211_MSG_STATE, /* state machine */ + IEEE80211_MSG_OUTPUT, /* output handling */ + IEEE80211_MSG_SCAN, /* scanning */ + IEEE80211_MSG_AUTH, /* authentication handling */ + IEEE80211_MSG_ASSOC, /* association handling */ + IEEE80211_MSG_NODE = 24, /* node handling */ + IEEE80211_MSG_ELEMID, /* element id parsing */ + IEEE80211_MSG_XRATE, /* rate set handling */ + IEEE80211_MSG_INPUT, /* input handling */ + IEEE80211_MSG_CRYPTO, /* crypto work */ + IEEE80211_MSG_DUMPPKTS, /* IFF_LINK2 equivalant */ + IEEE80211_MSG_DEBUG, /* IFF_DEBUG equivalent */ + IEEE80211_MSG_MLME, /* MLME */ + /* IEEE80211_PARAM_DBG_LVL_HIGH */ + IEEE80211_MSG_RRM = 32, /* Radio resource measurement */ + IEEE80211_MSG_WNM, /* Wireless Network Management */ + IEEE80211_MSG_P2P_PROT, /* P2P Protocol driver */ + IEEE80211_MSG_PROXYARP, /* 11v Proxy ARP */ + IEEE80211_MSG_L2TIF, /* Hotspot 2.0 L2 TIF */ + IEEE80211_MSG_WIFIPOS, /* WifiPositioning Feature */ + IEEE80211_MSG_WRAP, /* WRAP or Wireless ProxySTA */ + IEEE80211_MSG_DFS, /* DFS debug mesg */ + + IEEE80211_MSG_NUM_CATEGORIES, /* total ieee80211 messages */ + IEEE80211_MSG_UNMASKABLE = IEEE80211_MSG_MAX, /* anything */ + IEEE80211_MSG_ANY = IEEE80211_MSG_MAX, /* anything */ +}; + +/* verbosity levels */ +#define IEEE80211_VERBOSE_OFF 100 +#define IEEE80211_VERBOSE_FORCE 1 +#define IEEE80211_VERBOSE_SERIOUS 2 +#define IEEE80211_VERBOSE_NORMAL 3 +#define IEEE80211_VERBOSE_LOUD 4 +#define IEEE80211_VERBOSE_DETAILED 5 +#define IEEE80211_VERBOSE_COMPLEX 6 +#define IEEE80211_VERBOSE_FUNCTION 7 +#define IEEE80211_VERBOSE_TRACE 8 + +#define IEEE80211_DEBUG_DEFAULT IEEE80211_MSG_DEBUG + +/* + * the lower 4 bits of the msg flags are used for extending the + * debug flags. + */ + +/* + * flag defintions for wlan_mlme_stop_bss(vap) API. + */ +#define WLAN_MLME_STOP_BSS_F_SEND_DEAUTH 0x01 +#define WLAN_MLME_STOP_BSS_F_CLEAR_ASSOC_STATE 0x02 +#define WLAN_MLME_STOP_BSS_F_FORCE_STOP_RESET 0x04 +#define WLAN_MLME_STOP_BSS_F_WAIT_RX_DONE 0x08 +#define WLAN_MLME_STOP_BSS_F_NO_RESET 0x10 +#define WLAN_MLME_STOP_BSS_F_STANDBY 0x20 + +/* + * WAPI commands to authenticator + */ +#define WAPI_WAI_REQUEST (uint16_t)0x00F1 +#define WAPI_UNICAST_REKEY (uint16_t)0x00F2 +#define WAPI_STA_AGING (uint16_t)0x00F3 +#define WAPI_MULTI_REKEY (uint16_t)0x00F4 +#define WAPI_STA_STATS (uint16_t)0x00F5 + +/* + * IEEE80211 PHY Statistics. + */ +struct ieee80211_phy_stats { + uint64_t ips_tx_packets; /* frames successfully transmitted */ + uint64_t ips_tx_multicast; /* multicast/broadcast frames successfully transmitted */ + uint64_t ips_tx_fragments; /* fragments successfully transmitted */ + uint64_t ips_tx_xretries; /* frames that are xretried. NB: not number of retries */ + uint64_t ips_tx_retries; /* frames transmitted after retries. NB: not number of retries */ + uint64_t ips_tx_multiretries; /* frames transmitted after more than one retry. */ + uint64_t ips_tx_timeout; /* frames that expire the dot11MaxTransmitMSDULifetime */ + uint64_t ips_rx_packets; /* frames successfully received */ + uint64_t ips_rx_multicast; /* multicast/broadcast frames successfully received */ + uint64_t ips_rx_fragments; /* fragments successfully received */ + uint64_t ips_rx_timeout; /* frmaes that expired the dot11MaxReceiveLifetime */ + uint64_t ips_rx_dup; /* duplicated fragments */ + uint64_t ips_rx_mdup; /* multiple duplicated fragments */ + uint64_t ips_rx_promiscuous; /* frames that are received only because promiscuous filter is on */ + uint64_t ips_rx_promiscuous_fragments; /* fragments that are received only because promiscuous filter is on */ + uint64_t ips_tx_rts; /* RTS success count */ + uint64_t ips_tx_shortretry; /* tx on-chip retries (short). RTSFailCnt */ + uint64_t ips_tx_longretry; /* tx on-chip retries (long). DataFailCnt */ + uint64_t ips_rx_crcerr; /* rx failed 'cuz of bad CRC */ + uint64_t ips_rx_fifoerr; /* rx failed 'cuz of FIFO overrun */ + uint64_t ips_rx_decrypterr; /* rx decryption error */ +}; + +struct ieee80211_chan_stats { + uint32_t chan_clr_cnt; + uint32_t cycle_cnt; + uint32_t phy_err_cnt; +}; + +struct ieee80211_mac_stats { + uint64_t ims_tx_packets; /* frames successfully transmitted */ + uint64_t ims_rx_packets; /* frames successfully received */ + uint64_t ims_tx_bytes; /* bytes successfully transmitted */ + uint64_t ims_rx_bytes; /* bytes successfully received */ + + /* TODO: For the byte counts below, we need to handle some scenarios + such as encryption related decaps, etc */ + uint64_t ims_tx_data_packets; /* data frames successfully transmitted */ + uint64_t ims_rx_data_packets; /* data frames successfully received */ + uint64_t ims_tx_data_bytes; /* data bytes successfully transmitted, + inclusive of FCS. */ + uint64_t ims_rx_data_bytes; /* data bytes successfully received, + inclusive of FCS. */ + + uint64_t ims_tx_datapyld_bytes; /* data payload bytes successfully + transmitted */ + uint64_t ims_rx_datapyld_bytes; /* data payload successfully + received */ + + /* Decryption errors */ + uint64_t ims_rx_unencrypted; /* rx w/o wep and privacy on */ + uint64_t ims_rx_badkeyid; /* rx w/ incorrect keyid */ + uint64_t ims_rx_decryptok; /* rx decrypt okay */ + uint64_t ims_rx_decryptcrc; /* rx decrypt failed on crc */ + uint64_t ims_rx_wepfail; /* rx wep processing failed */ + uint64_t ims_rx_tkipreplay; /* rx seq# violation (TKIP) */ + uint64_t ims_rx_tkipformat; /* rx format bad (TKIP) */ + uint64_t ims_rx_tkipmic; /* rx MIC check failed (TKIP) */ + uint64_t ims_rx_tkipicv; /* rx ICV check failed (TKIP) */ + uint64_t ims_rx_ccmpreplay; /* rx seq# violation (CCMP) */ + uint64_t ims_rx_ccmpformat; /* rx format bad (CCMP) */ + uint64_t ims_rx_ccmpmic; /* rx MIC check failed (CCMP) */ +/*this file can be included by applications as 80211stats that has no such MACRO definition*/ +/* #if ATH_SUPPORT_WAPI */ + uint64_t ims_rx_wpireplay; /* rx seq# violation (WPI) */ + uint64_t ims_rx_wpimic; /* rx MIC check failed (WPI) */ +/* #endif */ + /* Other Tx/Rx errors */ + uint64_t ims_tx_discard; /* tx dropped by NIC */ + uint64_t ims_rx_discard; /* rx dropped by NIC */ + + uint64_t ims_rx_countermeasure; /* rx TKIP countermeasure activation count */ +}; + +/* + * Summary statistics. + */ +struct ieee80211_stats { + uint32_t is_rx_badversion; /* rx frame with bad version */ + uint32_t is_rx_tooshort; /* rx frame too short */ + uint32_t is_rx_wrongbss; /* rx from wrong bssid */ + uint32_t is_rx_wrongdir; /* rx w/ wrong direction */ + uint32_t is_rx_mcastecho; /* rx discard 'cuz mcast echo */ + uint32_t is_rx_notassoc; /* rx discard 'cuz sta !assoc */ + uint32_t is_rx_noprivacy; /* rx w/ wep but privacy off */ + uint32_t is_rx_decap; /* rx decapsulation failed */ + uint32_t is_rx_mgtdiscard; /* rx discard mgt frames */ + uint32_t is_rx_ctl; /* rx discard ctrl frames */ + uint32_t is_rx_beacon; /* rx beacon frames */ + uint32_t is_rx_rstoobig; /* rx rate set truncated */ + uint32_t is_rx_elem_missing; /* rx required element missing */ + uint32_t is_rx_elem_toobig; /* rx element too big */ + uint32_t is_rx_elem_toosmall; /* rx element too small */ + uint32_t is_rx_elem_unknown; /* rx element unknown */ + uint32_t is_rx_badchan; /* rx frame w/ invalid chan */ + uint32_t is_rx_chanmismatch; /* rx frame chan mismatch */ + uint32_t is_rx_nodealloc; /* rx frame dropped */ + uint32_t is_rx_ssidmismatch; /* rx frame ssid mismatch */ + uint32_t is_rx_auth_unsupported; /* rx w/ unsupported auth alg */ + uint32_t is_rx_auth_fail; /* rx sta auth failure */ + uint32_t is_rx_auth_countermeasures; /* rx auth discard 'cuz CM */ + uint32_t is_rx_assoc_bss; /* rx assoc from wrong bssid */ + uint32_t is_rx_assoc_notauth; /* rx assoc w/o auth */ + uint32_t is_rx_assoc_capmismatch; /* rx assoc w/ cap mismatch */ + uint32_t is_rx_assoc_norate; /* rx assoc w/ no rate match */ + uint32_t is_rx_assoc_badwpaie; /* rx assoc w/ bad WPA IE */ + uint32_t is_rx_deauth; /* rx deauthentication */ + uint32_t is_rx_disassoc; /* rx disassociation */ + uint32_t is_rx_action; /* rx action mgt */ + uint32_t is_rx_badsubtype; /* rx frame w/ unknown subtype */ + uint32_t is_rx_nobuf; /* rx failed for lack of buf */ + uint32_t is_rx_ahdemo_mgt; /* rx discard ahdemo mgt frame */ + uint32_t is_rx_bad_auth; /* rx bad auth request */ + uint32_t is_rx_unauth; /* rx on unauthorized port */ + uint32_t is_rx_badcipher; /* rx failed 'cuz key type */ + uint32_t is_tx_nodefkey; /* tx failed 'cuz no defkey */ + uint32_t is_tx_noheadroom; /* tx failed 'cuz no space */ + uint32_t is_rx_nocipherctx; /* rx failed 'cuz key !setup */ + uint32_t is_rx_acl; /* rx discard 'cuz acl policy */ + uint32_t is_rx_ffcnt; /* rx fast frames */ + uint32_t is_rx_badathtnl; /* driver key alloc failed */ + uint32_t is_rx_nowds; /* 4-addr packets received with no wds enabled */ + uint32_t is_tx_nobuf; /* tx failed for lack of buf */ + uint32_t is_tx_nonode; /* tx failed for no node */ + uint32_t is_tx_unknownmgt; /* tx of unknown mgt frame */ + uint32_t is_tx_badcipher; /* tx failed 'cuz key type */ + uint32_t is_tx_ffokcnt; /* tx fast frames sent success */ + uint32_t is_tx_fferrcnt; /* tx fast frames sent success */ + uint32_t is_scan_active; /* active scans started */ + uint32_t is_scan_passive; /* passive scans started */ + uint32_t is_node_timeout; /* nodes timed out inactivity */ + uint32_t is_crypto_nomem; /* no memory for crypto ctx */ + uint32_t is_crypto_tkip; /* tkip crypto done in s/w */ + uint32_t is_crypto_tkipenmic; /* tkip en-MIC done in s/w */ + uint32_t is_crypto_tkipdemic; /* tkip de-MIC done in s/w */ + uint32_t is_crypto_tkipcm; /* tkip counter measures */ + uint32_t is_crypto_ccmp; /* ccmp crypto done in s/w */ + uint32_t is_crypto_wep; /* wep crypto done in s/w */ + uint32_t is_crypto_setkey_cipher; /* cipher rejected key */ + uint32_t is_crypto_setkey_nokey; /* no key index for setkey */ + uint32_t is_crypto_delkey; /* driver key delete failed */ + uint32_t is_crypto_badcipher; /* unknown cipher */ + uint32_t is_crypto_nocipher; /* cipher not available */ + uint32_t is_crypto_attachfail; /* cipher attach failed */ + uint32_t is_crypto_swfallback; /* cipher fallback to s/w */ + uint32_t is_crypto_keyfail; /* driver key alloc failed */ + uint32_t is_crypto_enmicfail; /* en-MIC failed */ + uint32_t is_ibss_capmismatch; /* merge failed-cap mismatch */ + uint32_t is_ibss_norate; /* merge failed-rate mismatch */ + uint32_t is_ps_unassoc; /* ps-poll for unassoc. sta */ + uint32_t is_ps_badaid; /* ps-poll w/ incorrect aid */ + uint32_t is_ps_qempty; /* ps-poll w/ nothing to send */ +}; + +typedef enum _ieee80211_send_frame_type { + IEEE80211_SEND_NULL, + IEEE80211_SEND_QOSNULL, +} ieee80211_send_frame_type; + +typedef struct _ieee80211_tspec_info { + uint8_t traffic_type; + uint8_t direction; + uint8_t dot1Dtag; + uint8_t tid; + uint8_t acc_policy_edca; + uint8_t acc_policy_hcca; + uint8_t aggregation; + uint8_t psb; + uint8_t ack_policy; + uint16_t norminal_msdu_size; + uint16_t max_msdu_size; + uint32_t min_srv_interval; + uint32_t max_srv_interval; + uint32_t inactivity_interval; + uint32_t suspension_interval; + uint32_t srv_start_time; + uint32_t min_data_rate; + uint32_t mean_data_rate; + uint32_t peak_data_rate; + uint32_t max_burst_size; + uint32_t delay_bound; + uint32_t min_phy_rate; + uint16_t surplus_bw; + uint16_t medium_time; +} ieee80211_tspec_info; + +#ifndef EXTERNAL_USE_ONLY +/* + * Manual ADDBA support + */ +enum { + ADDBA_SEND = 0, + ADDBA_STATUS = 1, + DELBA_SEND = 2, + ADDBA_RESP = 3, + ADDBA_CLR_RESP = 4, + SINGLE_AMSDU = 5, +}; + +enum { + ADDBA_MODE_AUTO = 0, + ADDBA_MODE_MANUAL = 1, +}; + +struct ieee80211_addba_delba_request { + wlan_dev_t ic; + uint8_t action; + uint8_t tid; + uint16_t status; + uint16_t aid; + uint32_t arg1; + uint32_t arg2; +}; +#endif /* EXTERNAL_USE_ONLY */ + +#ifdef ATH_BT_COEX +typedef enum _ieee80211_bt_coex_info_type { + IEEE80211_BT_COEX_INFO_SCHEME = 0, + IEEE80211_BT_COEX_INFO_BTBUSY = 1, +} ieee80211_bt_coex_info_type; +#endif + +struct tkip_countermeasure { + uint16_t mic_count_in_60s; + uint32_t timestamp; +}; + +enum _ieee80211_qos_frame_direction { + IEEE80211_RX_QOS_FRAME = 0, + IEEE80211_TX_QOS_FRAME = 1, + IEEE80211_TX_COMPLETE_QOS_FRAME = 2 +}; + +typedef struct ieee80211_vap_opmode_count { + int total_vaps; + int ibss_count; + int sta_count; + int wds_count; + int ahdemo_count; + int ap_count; + int monitor_count; + int btamp_count; + int unknown_count; +} ieee80211_vap_opmode_count; + +struct ieee80211_app_ie_t { + uint32_t length; + uint8_t *ie; +}; + +/* + * MAC ACL operations. + */ +enum { + IEEE80211_MACCMD_POLICY_OPEN = 0, /* set policy: no ACL's */ + IEEE80211_MACCMD_POLICY_ALLOW = 1, /* set policy: allow traffic */ + IEEE80211_MACCMD_POLICY_DENY = 2, /* set policy: deny traffic */ + IEEE80211_MACCMD_FLUSH = 3, /* flush ACL database */ + IEEE80211_MACCMD_DETACH = 4, /* detach ACL policy */ + IEEE80211_MACCMD_POLICY_RADIUS = 5, /* set policy: RADIUS managed ACLs */ +}; + +#endif diff --git a/drivers/staging/qcacld-3.0/core/cds/inc/cds_if_upperproto.h b/drivers/staging/qcacld-3.0/core/cds/inc/cds_if_upperproto.h new file mode 100644 index 0000000000000000000000000000000000000000..072c6bca2edbfc22dd320b155dd1d3c6985d22c0 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/cds/inc/cds_if_upperproto.h @@ -0,0 +1,238 @@ +/* + * Copyright (c) 2011, 2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* #ifndef _NET_IF_ETHERSUBR_H_ */ +/* #define _NET_IF_ETHERSUBR_H_ */ +#ifndef _NET_IF_UPPERPROTO_H_ +#define _NET_IF_UPPERPROTO_H_ + +#define ETHER_ADDR_LEN 6 /* length of an Ethernet address */ +#define ETHER_TYPE_LEN 2 /* length of the Ethernet type field */ +#define ETHER_CRC_LEN 4 /* length of the Ethernet CRC */ +#define ETHER_HDR_LEN (ETHER_ADDR_LEN*2+ETHER_TYPE_LEN) +#define ETHER_MAX_LEN 1518 + +#define ETHERMTU (ETHER_MAX_LEN-ETHER_HDR_LEN-ETHER_CRC_LEN) + +/* + * Structure of a 10Mb/s Ethernet header. + */ +#ifndef _NET_ETHERNET_H_ +struct ether_header { + uint8_t ether_dhost[ETHER_ADDR_LEN]; + uint8_t ether_shost[ETHER_ADDR_LEN]; + uint16_t ether_type; +} __packed; +#endif + +#ifndef ETHERTYPE_PAE +#define ETHERTYPE_PAE 0x888e /* EAPOL PAE/802.1x */ +#endif +#ifndef ETHERTYPE_IP +#define ETHERTYPE_IP 0x0800 /* IP protocol */ +#endif +#ifndef ETHERTYPE_AARP +#define ETHERTYPE_AARP 0x80f3 /* Appletalk AARP protocol */ +#endif +#ifndef ETHERTYPE_IPX +#define ETHERTYPE_IPX 0x8137 /* IPX over DIX protocol */ +#endif +#ifndef ETHERTYPE_ARP +#define ETHERTYPE_ARP 0x0806 /* ARP protocol */ +#endif +#ifndef ETHERTYPE_IPV6 +#define ETHERTYPE_IPV6 0x86dd /* IPv6 */ +#endif +#ifndef ETHERTYPE_8021Q +#define ETHERTYPE_8021Q 0x8100 /* 802.1Q vlan protocol */ +#endif +#ifndef ETHERTYPE_VLAN +#define ETHERTYPE_VLAN 0x8100 /* VLAN TAG protocol */ +#endif +#ifndef TX_QUEUE_FOR_EAPOL_FRAME +#define TX_QUEUE_FOR_EAPOL_FRAME 0x7 /* queue eapol frame to queue 7 to avoid aggregation disorder */ +#endif + +/* + * define WAI ethertype + */ +#ifndef ETHERTYPE_WAI +#define ETHERTYPE_WAI 0x88b4 /* WAI/WAPI */ +#endif + +#define ETHERTYPE_OCB_TX 0x8151 +#define ETHERTYPE_OCB_RX 0x8152 + +/* + * Structure of a 48-bit Ethernet address. + */ +#if 0 +#ifndef _NET_ETHERNET_H_ +struct ether_addr { + uint8_t octet[ETHER_ADDR_LEN]; +} __packed; +#endif +#endif + +#define ETHER_IS_MULTICAST(addr) (*(addr) & 0x01) /* is address mcast/bcast? */ + +#define VLAN_PRI_SHIFT 13 /* Shift to find VLAN user priority */ +#define VLAN_PRI_MASK 7 /* Mask for user priority bits in VLAN */ + +/* + * Structure of the IP frame + */ +struct ip_header { + uint8_t version_ihl; + uint8_t tos; + uint16_t tot_len; + uint16_t id; + uint16_t frag_off; + uint8_t ttl; + uint8_t protocol; + uint16_t check; + uint32_t saddr; + uint32_t daddr; + /*The options start here. */ +}; +#ifndef IP_PROTO_TCP +#define IP_PROTO_TCP 0x6 /* TCP protocol */ +#endif +#ifndef IP_PROTO_UDP +#define IP_PROTO_UDP 17 +#endif + +/* + * IGMP protocol structures + */ + +/* IGMP record type */ +#define IGMP_QUERY_TYPE 0x11 +#define IGMPV1_REPORT_TYPE 0x12 +#define IGMPV2_REPORT_TYPE 0x16 +#define IGMPV2_LEAVE_TYPE 0x17 +#define IGMPV3_REPORT_TYPE 0x22 + +/* Is packet type is either leave or report */ +#define IS_IGMP_REPORT_LEAVE_PACKET(type) ( \ + (IGMPV1_REPORT_TYPE == type) \ + || (IGMPV2_REPORT_TYPE == type) \ + || (IGMPV2_LEAVE_TYPE == type) \ + || (IGMPV3_REPORT_TYPE == type) \ + ) +/* + * Header in on cable format + */ + +struct igmp_header { + uint8_t type; + uint8_t code; /* For newer IGMP */ + uint16_t csum; + uint32_t group; +}; + +/* V3 group record types [grec_type] */ +#define IGMPV3_MODE_IS_INCLUDE 1 +#define IGMPV3_MODE_IS_EXCLUDE 2 +#define IGMPV3_CHANGE_TO_INCLUDE 3 +#define IGMPV3_CHANGE_TO_EXCLUDE 4 +#define IGMPV3_ALLOW_NEW_SOURCES 5 +#define IGMPV3_BLOCK_OLD_SOURCES 6 + +/* Group record format + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Record Type | Aux Data Len | Number of Sources (N) | + ||+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Multicast Address | + ||+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Source Address [1] | + ||+- -+ + | Source Address [2] | + ||+- -+ + . . . + . . . + . . . + ||+- -+ + | Source Address [N] | + ||+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | | + . . + . Auxiliary Data . + . . + | | + ||+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ +struct igmp_v3_grec { + uint8_t grec_type; + uint8_t grec_auxwords; + uint16_t grec_nsrcs; + uint32_t grec_mca; +}; + +/* IGMPv3 report format + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Type = 0x22 | Reserved | Checksum | + ||+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Reserved | Number of Group Records (M) | + ||+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | | + . . + . Group Record [1] . + . . + | | + ||+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | | + . . + . Group Record [2] . + . . + | | + ||+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | . | + . . . + | . | + ||+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | | + . . + . Group Record [M] . + . . + | | + ||+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ +struct igmp_v3_report { + uint8_t type; + uint8_t resv1; + uint16_t csum; + uint16_t resv2; + uint16_t ngrec; +}; + +/* Calculate the group record length*/ +#define IGMPV3_GRP_REC_LEN(x) (8 + (4 * x->grec_nsrcs) + (4 * x->grec_auxwords) ) + +#endif /* _NET_IF_ETHERSUBR_H_ */ diff --git a/drivers/staging/qcacld-3.0/core/cds/inc/cds_mc_timer.h b/drivers/staging/qcacld-3.0/core/cds/inc/cds_mc_timer.h new file mode 100644 index 0000000000000000000000000000000000000000..e01937ab16527da3757ad1435f6e645c4a9fac60 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/cds/inc/cds_mc_timer.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2014-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: cds_mc_timer.h + * + * Connectivity driver services public API + * + */ + +#if !defined(__CDS_MC_TIMER_H) +#define __CDS_MC_TIMER_H + +void cds_linux_timer_callback(unsigned long data); + +#endif /* __CDS_MC_TIMER_H */ diff --git a/drivers/staging/qcacld-3.0/core/cds/inc/cds_mq.h b/drivers/staging/qcacld-3.0/core/cds/inc/cds_mq.h new file mode 100644 index 0000000000000000000000000000000000000000..d114e0809240de215750956310127f0f9fe95e1f --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/cds/inc/cds_mq.h @@ -0,0 +1,155 @@ +/* + * Copyright (c) 2014-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#if !defined(__CDS_MQ_H) +#define __CDS_MQ_H + +/**========================================================================= + + \file cds_mq.h + + \brief virtual Operating System Services (QDF) message queue APIs + + Message Queue Definitions and API + + ========================================================================*/ + +/*-------------------------------------------------------------------------- + Include Files + ------------------------------------------------------------------------*/ +#include +#include + +/*-------------------------------------------------------------------------- + Preprocessor definitions and constants + ------------------------------------------------------------------------*/ + +/*-------------------------------------------------------------------------- + Type declarations + ------------------------------------------------------------------------*/ + +/* cds Message Type. + This represnets a message that can be posted to another module through + the cds Message Queues. + \note This is mapped directly to the tSirMsgQ for backward + compatibility with the legacy MAC code */ + +typedef struct cds_msg_s { + uint16_t type; + /* + * This field can be used as sequence number/dialog token for matching + * requests and responses. + */ + uint16_t reserved; + /** + * Based on the type either a bodyptr pointer into + * memory or bodyval as a 32 bit data is used. + * bodyptr: is always a freeable pointer, one should always + * make sure that bodyptr is always freeable. + * + * Messages should use either bodyptr or bodyval; not both !!!. + */ + void *bodyptr; + + uint32_t bodyval; + + /* + * Some messages provide a callback function. The function signature + * must be agreed upon between the two entities exchanging the message + */ + void *callback; + +} cds_msg_t; + +/*------------------------------------------------------------------------- + Function declarations and documenation + ------------------------------------------------------------------------*/ + +/* Message Queue IDs */ +typedef enum { + /* Message Queue ID for messages bound for SME */ + CDS_MQ_ID_SME = QDF_MODULE_ID_SME, + + /* Message Queue ID for messages bound for PE */ + CDS_MQ_ID_PE = QDF_MODULE_ID_PE, + + /* Message Queue ID for messages bound for WMA */ + CDS_MQ_ID_WMA = QDF_MODULE_ID_WMA, + + /* Message Queue ID for messages bound for the SYS module */ + CDS_MQ_ID_SYS = QDF_MODULE_ID_SYS, + +} CDS_MQ_ID; + +#define HIGH_PRIORITY 1 +#define LOW_PRIORITY 0 +QDF_STATUS cds_mq_post_message_by_priority(CDS_MQ_ID msg_queue_id, + cds_msg_t *message, + int is_high_priority); + +/** + * cds_mq_post_message() - posts a message to a message queue + * @msg_queue_id: Identifies the message queue upon which the message + * will be posted. + * @message: A pointer to a message buffer. Memory for this message + * buffer is allocated by the caller and free'd by the QDF after the + * message is posted to the message queue. If the consumer of the + * message needs anything in this message, it needs to copy the contents + * before returning from the message queue handler. + * + * Return: QDF_STATUS_SUCCESS for successful posting + * QDF_STATUS_E_INVAL for invalid message queue id + * QDF_STATUS_E_FAULT for invalid message pointer + * QDF_STATUS_E_FAILURE for unknown failure reported by + * message queue handler + */ +static inline QDF_STATUS cds_mq_post_message(CDS_MQ_ID msg_queue_id, + cds_msg_t *message) +{ + return cds_mq_post_message_by_priority(msg_queue_id, message, + LOW_PRIORITY); +} + +/**--------------------------------------------------------------------------- + + \brief cds_send_mb_message_to_mac() - post a message to a message queue + + \param pBuf is a buffer allocated by caller. The actual structure varies + base on message type + + \return QDF_STATUS_SUCCESS - the message has been successfully posted + to the message queue. + + QDF_STATUS_E_FAILURE - the message queue handler has reported + an unknown failure. + + \sa + --------------------------------------------------------------------------*/ + +QDF_STATUS cds_send_mb_message_to_mac(void *pBuf); + +#endif /* if !defined __CDS_MQ_H */ diff --git a/drivers/staging/qcacld-3.0/core/cds/inc/cds_pack_align.h b/drivers/staging/qcacld-3.0/core/cds/inc/cds_pack_align.h new file mode 100644 index 0000000000000000000000000000000000000000..f213115d2c0b9e7611e23efeab835cb7f1c67c54 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/cds/inc/cds_pack_align.h @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#if !defined( __CDS_PACK_ALIGN_H ) +#define __CDS_PACK_ALIGN_H + +/**========================================================================= + + \file cds_pack_align.h + + \brief Connectivity driver services (CDS) pack and align primitives + + Definitions for platform independent means of packing and aligning + data structures + + ========================================================================*/ + +/* + + Place the macro CDS_PACK_START above a structure declaration to pack. We + are not going to allow modifying the pack size because pack size cannot be + specified in AMSS and GNU. Place the macro CDS_PACK_END below a structure + declaration to stop the pack. This requirement is necessitated by Windows + which need pragma based prolog and epilog. + + Pack-size > 1-byte is not supported since gcc and arm do not support that. + + Here are some examples + + 1. Pack-size 1-byte foo_t across all platforms + + CDS_PACK_START + typedef CDS_PACK_PRE struct foo_s { ... } CDS_PACK_POST foo_t; + CDS_PACK_END + + 2. 2-byte alignment for foo_t across all platforms + + typedef CDS_ALIGN_PRE(2) struct foo_s { ... } CDS_ALIGN_POST(2) foo_t; + + 3. Pack-size 1-byte and 2-byte alignment for foo_t across all platforms + + CDS_PACK_START + typedef CDS_PACK_PRE CDS_ALIGN_PRE(2) struct foo_s { ... } CDS_ALIGN_POST(2) CDS_PACK_POST foo_t; + CDS_PACK_END + + */ + +#if defined __GNUC__ + +#define CDS_PACK_START +#define CDS_PACK_END + +#define CDS_PACK_PRE +#define CDS_PACK_POST __attribute__((__packed__)) + +#define CDS_ALIGN_PRE(__value) +#define CDS_ALIGN_POST(__value) __attribute__((__aligned__(__value))) + +#elif defined __arm + +#define CDS_PACK_START +#define CDS_PACK_END + +#define CDS_PACK_PRE __packed +#define CDS_PACK_POST + +#define CDS_ALIGN_PRE(__value) __align(__value) +#define CDS_ALIGN_POST(__value) + +#elif defined _MSC_VER + +#define CDS_PACK_START __pragma(pack(push,1)) +#define CDS_PACK_END __pragma(pack(pop)) + +#define CDS_PACK_PRE +#define CDS_PACK_POST + +#define CDS_ALIGN_PRE(__value) __declspec(align(__value)) +#define CDS_ALIGN_POST(__value) + +#else + +#error Unsupported compiler!!! + +#endif + +#endif /* __CDS_PACK_ALIGN_H */ diff --git a/drivers/staging/qcacld-3.0/core/cds/inc/cds_packet.h b/drivers/staging/qcacld-3.0/core/cds/inc/cds_packet.h new file mode 100644 index 0000000000000000000000000000000000000000..87a2a7b3941af5390c93021694a3731ca6bdeb61 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/cds/inc/cds_packet.h @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2014-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#if !defined(__CDS_PKT_H) +#define __CDS_PKT_H + +/**========================================================================= + + \file cds_packet.h + + \brief Connectivity driver services (CDS) network Packet APIs + + Network Protocol packet/buffer support interfaces + + ========================================================================*/ + +/*-------------------------------------------------------------------------- + Include Files + ------------------------------------------------------------------------*/ +#include +#include + +/*-------------------------------------------------------------------------- + Preprocessor definitions and constants + ------------------------------------------------------------------------*/ + +/*-------------------------------------------------------------------------- + Type declarations + ------------------------------------------------------------------------*/ +struct cds_pkt_t; +typedef struct cds_pkt_t cds_pkt_t; + +#include "qdf_nbuf.h" + +/** + * cds_pkt_return_packet Free the cds Packet + * @ cds Packet + */ +QDF_STATUS cds_pkt_return_packet(cds_pkt_t *packet); + +/** + * cds_pkt_get_packet_length Returns the packet length + * @ cds Packet + */ +QDF_STATUS cds_pkt_get_packet_length(cds_pkt_t *pPacket, + uint16_t *pPacketSize); + +/* + * TODO: Remove later + * All the below difinitions are not + * required for Host Driver 2.0 + * once corresponding references are removed + * from HDD and other layers + * below code will be removed + */ +/* The size of AMSDU frame per spec can be a max of 3839 bytes + in BD/PDUs that means 30 (one BD = 128 bytes) + we must add the size of the 802.11 header to that */ +#define CDS_PKT_SIZE_BUFFER ((30 * 128) + 32) + +/* cds Packet Types */ +typedef enum { + /* cds Packet is used to transmit 802.11 Management frames. */ + CDS_PKT_TYPE_TX_802_11_MGMT, + + /* cds Packet is used to transmit 802.11 Data frames. */ + CDS_PKT_TYPE_TX_802_11_DATA, + + /* cds Packet is used to transmit 802.3 Data frames. */ + CDS_PKT_TYPE_TX_802_3_DATA, + + /* cds Packet contains Received data of an unknown frame type */ + CDS_PKT_TYPE_RX_RAW, + + /* Invalid sentinel value */ + CDS_PKT_TYPE_MAXIMUM +} CDS_PKT_TYPE; + +/* user IDs. These IDs are needed on the cds_pkt_get/set_user_data_ptr() + to identify the user area in the cds Packet. */ +typedef enum { + CDS_PKT_USER_DATA_ID_TL = 0, + CDS_PKT_USER_DATA_ID_BAL, + CDS_PKT_USER_DATA_ID_WMA, + CDS_PKT_USER_DATA_ID_HDD, + CDS_PKT_USER_DATA_ID_BSL, + + CDS_PKT_USER_DATA_ID_MAX +} CDS_PKT_USER_DATA_ID; + +#ifdef MEMORY_DEBUG +#define cds_packet_alloc(s, d, p) \ + cds_packet_alloc_debug(s, d, p, __FILE__, __LINE__) + +QDF_STATUS cds_packet_alloc_debug(uint16_t size, void **data, void **ppPacket, + uint8_t *file_name, uint32_t line_num); +#else +QDF_STATUS cds_packet_alloc(uint16_t size, void **data, void **ppPacket); +#endif + +void cds_packet_free(void *pPacket); + +typedef QDF_STATUS (*cds_pkt_get_packet_callback)(cds_pkt_t *pPacket, + void *userData); + +#endif /* !defined( __CDS_PKT_H ) */ diff --git a/drivers/staging/qcacld-3.0/core/cds/inc/cds_queue.h b/drivers/staging/qcacld-3.0/core/cds/inc/cds_queue.h new file mode 100644 index 0000000000000000000000000000000000000000..030ff2536dde48aae9db8e8a27db4b4ef5979e80 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/cds/inc/cds_queue.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2013-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef _CDS_QUEUE_H +#define _CDS_QUEUE_H + +#include /* include BSD queue */ + +#endif /* end of _CDS_QUEUE_H */ diff --git a/drivers/staging/qcacld-3.0/core/cds/inc/cds_reg_service.h b/drivers/staging/qcacld-3.0/core/cds/inc/cds_reg_service.h new file mode 100644 index 0000000000000000000000000000000000000000..137e8512d98043210e62ccace3259091e4841c40 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/cds/inc/cds_reg_service.h @@ -0,0 +1,417 @@ +/* + * Copyright (c) 2014-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#if !defined __CDS_REG_SERVICE_H +#define __CDS_REG_SERVICE_H + +/**========================================================================= + + \file cds_reg_service.h + + \brief Connectivity driver services (CDS): Non-Volatile storage API + + ========================================================================*/ + +#include "qdf_status.h" + +#define CDS_COUNTRY_CODE_LEN 2 +#define CDS_MAC_ADDRESS_LEN 6 + +#define CDS_CHANNEL_STATE(chan_enum) reg_channels[chan_enum].state +#define CDS_CHANNEL_NUM(chan_enum) chan_mapping[chan_enum].chan_num +#define CDS_CHANNEL_FREQ(chan_enum) chan_mapping[chan_enum].center_freq +#define CDS_IS_DFS_CH(chan_num) (cds_get_channel_state((chan_num)) == \ + CHANNEL_STATE_DFS) + +#define CDS_IS_PASSIVE_OR_DISABLE_CH(chan_num) \ + (cds_get_channel_state(chan_num) != CHANNEL_STATE_ENABLE) + +#define CDS_MIN_24GHZ_CHANNEL_NUMBER chan_mapping[MIN_24GHZ_CHANNEL].chan_num +#define CDS_MAX_24GHZ_CHANNEL_NUMBER chan_mapping[MAX_24GHZ_CHANNEL].chan_num +#define CDS_MIN_59GHZ_CHANNEL_NUMBER chan_mapping[MIN_59GHZ_CHANNEL].chan_num +#define CDS_MAX_59GHZ_CHANNEL_NUMBER chan_mapping[MAX_59GHZ_CHANNEL].chan_num +#define CDS_MIN_5GHZ_CHANNEL_NUMBER chan_mapping[MIN_5GHZ_CHANNEL].chan_num +#define CDS_MAX_5GHZ_CHANNEL_NUMBER chan_mapping[MAX_5GHZ_CHANNEL].chan_num + +#define CDS_IS_CHANNEL_DSRC(chan_num) \ + ((chan_num >= CDS_MIN_59GHZ_CHANNEL_NUMBER) && \ + (chan_num <= CDS_MAX_59GHZ_CHANNEL_NUMBER)) + +#define CDS_IS_CHANNEL_5GHZ(chan_num) \ + ((chan_num >= CDS_MIN_5GHZ_CHANNEL_NUMBER) && \ + (chan_num <= CDS_MAX_5GHZ_CHANNEL_NUMBER)) + +#define CDS_IS_CHANNEL_24GHZ(chan_num) \ + ((chan_num >= CDS_MIN_24GHZ_CHANNEL_NUMBER) && \ + (chan_num <= CDS_MAX_24GHZ_CHANNEL_NUMBER)) + +#define CDS_IS_SAME_BAND_CHANNELS(chan_num1, chan_num2) \ + (chan_num1 && chan_num2 && \ + (CDS_IS_CHANNEL_5GHZ(chan_num1) == CDS_IS_CHANNEL_5GHZ(chan_num2))) + +#define CDS_MIN_11P_CHANNEL chan_mapping[MIN_59GHZ_CHANNEL].chan_num + +typedef enum { + REGDOMAIN_FCC, + REGDOMAIN_ETSI, + REGDOMAIN_JAPAN, + REGDOMAIN_WORLD, + REGDOMAIN_COUNT +} v_REGDOMAIN_t; + + +/** + * enum channel_enum: channel enumeration + * @CHAN_ENUM_1: channel number 1 + * @CHAN_ENUM_2: channel number 2 + * @CHAN_ENUM_3: channel number 3 + * @CHAN_ENUM_4: channel number 4 + * @CHAN_ENUM_5: channel number 5 + * @CHAN_ENUM_6: channel number 6 + * @CHAN_ENUM_7: channel number 7 + * @CHAN_ENUM_8: channel number 8 + * @CHAN_ENUM_9: channel number 9 + * @CHAN_ENUM_10: channel number 10 + * @CHAN_ENUM_11: channel number 11 + * @CHAN_ENUM_12: channel number 12 + * @CHAN_ENUM_13: channel number 13 + * @CHAN_ENUM_14: channel number 14 + * @CHAN_ENUM_36: channel number 36 + * @CHAN_ENUM_40: channel number 40 + * @CHAN_ENUM_44: channel number 44 + * @CHAN_ENUM_48: channel number 48 + * @CHAN_ENUM_52: channel number 52 + * @CHAN_ENUM_56: channel number 56 + * @CHAN_ENUM_60: channel number 60 + * @CHAN_ENUM_64: channel number 64 + * @CHAN_ENUM_100: channel number 100 + * @CHAN_ENUM_104: channel number 104 + * @CHAN_ENUM_108: channel number 108 + * @CHAN_ENUM_112: channel number 112 + * @CHAN_ENUM_116: channel number 116 + * @CHAN_ENUM_120: channel number 120 + * @CHAN_ENUM_124: channel number 124 + * @CHAN_ENUM_128: channel number 128 + * @CHAN_ENUM_132: channel number 132 + * @CHAN_ENUM_136: channel number 136 + * @CHAN_ENUM_140: channel number 140 + * @CHAN_ENUM_144: channel number 144 + * @CHAN_ENUM_149: channel number 149 + * @CHAN_ENUM_153: channel number 153 + * @CHAN_ENUM_157: channel number 157 + * @CHAN_ENUM_161: channel number 161 + * @CHAN_ENUM_165: channel number 165 + * @CHAN_ENUM_170: channel number 108 + * @CHAN_ENUM_171: channel number 112 + * @CHAN_ENUM_172: channel number 116 + * @CHAN_ENUM_173: channel number 120 + * @CHAN_ENUM_174: channel number 124 + * @CHAN_ENUM_175: channel number 128 + * @CHAN_ENUM_176: channel number 132 + * @CHAN_ENUM_177: channel number 136 + * @CHAN_ENUM_178: channel number 140 + * @CHAN_ENUM_179: channel number 144 + * @CHAN_ENUM_180: channel number 149 + * @CHAN_ENUM_181: channel number 153 + * @CHAN_ENUM_182: channel number 157 + * @CHAN_ENUM_183: channel number 161 + * @CHAN_ENUM_184: channel number 165 + */ +enum channel_enum { + CHAN_ENUM_1 = 0, + CHAN_ENUM_2, + CHAN_ENUM_3, + CHAN_ENUM_4, + CHAN_ENUM_5, + CHAN_ENUM_6, + CHAN_ENUM_7, + CHAN_ENUM_8, + CHAN_ENUM_9, + CHAN_ENUM_10, + CHAN_ENUM_11, + CHAN_ENUM_12, + CHAN_ENUM_13, + CHAN_ENUM_14, + + CHAN_ENUM_36, + CHAN_ENUM_40, + CHAN_ENUM_44, + CHAN_ENUM_48, + CHAN_ENUM_52, + CHAN_ENUM_56, + CHAN_ENUM_60, + CHAN_ENUM_64, + + CHAN_ENUM_100, + CHAN_ENUM_104, + CHAN_ENUM_108, + CHAN_ENUM_112, + CHAN_ENUM_116, + CHAN_ENUM_120, + CHAN_ENUM_124, + CHAN_ENUM_128, + CHAN_ENUM_132, + CHAN_ENUM_136, + CHAN_ENUM_140, + CHAN_ENUM_144, + + CHAN_ENUM_149, + CHAN_ENUM_153, + CHAN_ENUM_157, + CHAN_ENUM_161, + CHAN_ENUM_165, + + CHAN_ENUM_170, + CHAN_ENUM_171, + CHAN_ENUM_172, + CHAN_ENUM_173, + CHAN_ENUM_174, + CHAN_ENUM_175, + CHAN_ENUM_176, + CHAN_ENUM_177, + CHAN_ENUM_178, + CHAN_ENUM_179, + CHAN_ENUM_180, + CHAN_ENUM_181, + CHAN_ENUM_182, + CHAN_ENUM_183, + CHAN_ENUM_184, + + NUM_CHANNELS, + + MIN_24GHZ_CHANNEL = CHAN_ENUM_1, + MAX_24GHZ_CHANNEL = CHAN_ENUM_14, + NUM_24GHZ_CHANNELS = (MAX_24GHZ_CHANNEL - MIN_24GHZ_CHANNEL + 1), + + MIN_5GHZ_CHANNEL = CHAN_ENUM_36, + MAX_5GHZ_CHANNEL = CHAN_ENUM_184, + NUM_5GHZ_CHANNELS = (MAX_5GHZ_CHANNEL - MIN_5GHZ_CHANNEL + 1), + + MIN_59GHZ_CHANNEL = CHAN_ENUM_170, + MAX_59GHZ_CHANNEL = CHAN_ENUM_184, + + INVALID_CHANNEL = 0xBAD, +}; + +/** + * enum channel_state: channel state + * @CHANNEL_STATE_DISABLE: channel disabled + * @CHANNEL_STATE_DFS: rx enabled, tx DFS + * @CHANNEL_STATE_ENABLE: tx/rx enabled + * @CHANNEL_STATE_INVALID: not a valid channel + */ +enum channel_state { + CHANNEL_STATE_DISABLE, + CHANNEL_STATE_DFS, + CHANNEL_STATE_ENABLE, + CHANNEL_STATE_INVALID, +}; + +/** + * struct regulatory_channel: regulatory channel + * @state: channel state + * @flags: channel flags + * @pwr_limit: channel tx power limit + */ +struct regulatory_channel { + uint32_t state:4; + uint32_t flags:28; + int8_t pwr_limit; +}; + +/** + * struct chan_map: channel mapping + * @center_freq: channel center freq + * @chan_num: channel number + */ +struct chan_map { + uint16_t center_freq; + uint16_t chan_num; +}; + +/** + * struct channel_power: channel power + * @chan_num: channel number + * @power: tx power + */ +struct channel_power { + uint8_t chan_num; + int8_t power; +}; + +/** + * enum country_src: country source + * @SOURCE_QUERY: source query + * @SOURCE_CORE: source regulatory core + * @SOURCE_DRIVER: source driver + * @SOURCE_USERSPACE: source userspace + * @SOURCE_11D: source 11D + */ +enum country_src { + SOURCE_UNKNOWN, + SOURCE_QUERY, + SOURCE_CORE, + SOURCE_DRIVER, + SOURCE_USERSPACE, + SOURCE_11D +}; + +/** + * struct regulatory: regulatory information + * @reg_domain: regulatory domain pair + * @eeprom_rd_ext: eeprom value + * @country_code: current country in integer + * @alpha2: current alpha2 + * @def_country: default country alpha2 + * @def_region: DFS region + * @ctl_2g: 2G CTL value + * @ctl_5g: 5G CTL value + * @reg_pair: pointer to regulatory pair + * @cc_src: country code src + * @reg_flags: kernel regulatory flags + */ +struct regulatory { + uint32_t reg_domain; + uint32_t eeprom_rd_ext; + uint16_t country_code; + uint8_t alpha2[CDS_COUNTRY_CODE_LEN + 1]; + uint8_t ctl_2g; + uint8_t ctl_5g; + const void *regpair; + enum country_src cc_src; + uint32_t reg_flags; +}; + +/** + * enum phy_ch_width - physical layer channel width + * @CH_WIDTH_20MHZ: channel width 20 mhz + * @CH_WIDTH_40MHZ: channel width 40 mhz + * @CH_WIDTH_80MHZ: channel width 80 mhz + * @CH_WIDTH_160MHZ: channel width 160 mhz + * @CH_WIDTH_80P80MHZ: channel width 80+80 mhz + * @CH_WIDTH_5MHZ: channel width 5 mhz + * @CH_WIDTH_10MHZ: channel width 10 mhz + * @CH_WIDTH_INVALID: invalid channel width + * @CH_WIDTH_MAX: maximum channel width + */ +enum phy_ch_width { + CH_WIDTH_20MHZ = 0, + CH_WIDTH_40MHZ, + CH_WIDTH_80MHZ, + CH_WIDTH_160MHZ, + CH_WIDTH_80P80MHZ, + CH_WIDTH_5MHZ, + CH_WIDTH_10MHZ, + CH_WIDTH_INVALID, + CH_WIDTH_MAX +}; + +#define HT40PLUS_2G_FCC_CH_END 7 +#define HT40PLUS_2G_EURJAP_CH_END 9 +#define HT40MINUS_2G_CH_START 5 +#define HT40MINUS_2G_CH_END 13 + +/** + * struct ch_params_s + * @ch_width: channel width + * @sec_ch_offset: secondary channel offset + * @center_freq_seg0: center freq for segment 0 + * @center_freq_seg1: center freq for segment 1 + */ +struct ch_params_s { + enum phy_ch_width ch_width; + uint8_t sec_ch_offset; + uint8_t center_freq_seg0; + uint8_t center_freq_seg1; +}; + +/** + * enum dfs_region - DFS region + * @DFS_UNINIT_REGION: un-initialized region + * @DFS_FCC_REGION: FCC region + * @DFS_ETSI_REGION: ETSI region + * @DFS_MKK_REGION: MKK region + * @DFS_CN_REGION: China region + * @DFS_KR_REGION: Korea region + * @DFS_UNDEF_REGION: Undefined region + */ +enum dfs_region { + DFS_UNINIT_REGION = 0, + DFS_FCC_REGION = 1, + DFS_ETSI_REGION = 2, + DFS_MKK_REGION = 3, + DFS_CN_REGION = 4, + DFS_KR_REGION = 5, + DFS_UNDEF_REGION +}; + +extern const struct chan_map chan_mapping[NUM_CHANNELS]; +extern struct regulatory_channel reg_channels[NUM_CHANNELS]; + +QDF_STATUS cds_get_reg_domain_from_country_code(v_REGDOMAIN_t *pRegDomain, + const uint8_t *country_alpha2, + enum country_src source); +/** + * cds_is_fcc_regdomian() - is the regdomain FCC + * + * Return: true on FCC regdomain, false otherwise + */ +bool cds_is_fcc_regdomain(void); + +QDF_STATUS cds_read_default_country(uint8_t *default_country); + +QDF_STATUS cds_get_channel_list_with_power(struct channel_power + *base_channels, + uint8_t *num_base_channels); + +enum channel_state cds_get_channel_state(uint32_t chan_num); +QDF_STATUS cds_get_dfs_region(enum dfs_region *dfs_reg); +QDF_STATUS cds_put_dfs_region(enum dfs_region dfs_reg); + +bool cds_is_dsrc_channel(uint16_t center_freq); +enum channel_state cds_get_5g_bonded_channel_state(uint16_t chan_num, + enum phy_ch_width chan_width); + +enum channel_state cds_get_2g_bonded_channel_state(uint16_t chan_num, + enum phy_ch_width chan_width, + uint16_t sec_ch); + +void cds_set_channel_params(uint16_t oper_ch, uint16_t ht_offset_2g, + struct ch_params_s *ch_params); + +QDF_STATUS cds_set_reg_domain(void *client_ctxt, v_REGDOMAIN_t reg_domain); +QDF_STATUS cds_put_default_country(uint8_t *def_country); +uint16_t cds_bw_value(enum phy_ch_width bw); +uint8_t cds_skip_dfs_and_2g(uint32_t rf_channel); +/** + * cds_get_channel_enum() - get the channel enumeration + * @chan_num: channel number + * + * Return: enum for the channel + */ +enum channel_enum cds_get_channel_enum(uint32_t chan_num); +#endif /* __CDS_REG_SERVICE_H */ diff --git a/drivers/staging/qcacld-3.0/core/cds/inc/cds_regdomain.h b/drivers/staging/qcacld-3.0/core/cds/inc/cds_regdomain.h new file mode 100644 index 0000000000000000000000000000000000000000..5c3d831515e637eedb0d53d918b26aaa703daf0b --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/cds/inc/cds_regdomain.h @@ -0,0 +1,591 @@ +/* + * Copyright (c) 2011, 2014-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * Notifications and licenses are retained for attribution purposes only. + */ +/* + * Copyright (c) 2002-2006 Sam Leffler, Errno Consulting + * Copyright (c) 2005-2006 Atheros Communications, Inc. + * Copyright (c) 2010, Atheros Communications Inc. + * + * Redistribution and use in source and binary forms are permitted + * provided that the following conditions are met: + * 1. The materials contained herein are unmodified and are used + * unmodified. + * 2. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following NO + * ''WARRANTY'' disclaimer below (''Disclaimer''), without + * modification. + * 3. Redistributions in binary form must reproduce at minimum a + * disclaimer similar to the Disclaimer below and any redistribution + * must be conditioned upon including a substantially similar + * Disclaimer requirement for further binary redistribution. + * 4. Neither the names of the above-listed copyright holders nor the + * names of any contributors may be used to endorse or promote + * product derived from this software without specific prior written + * permission. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, + * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE + * FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGES. + * + * This module contains the regulatory domain private structure definitions . + * + */ + +#ifndef __CDS_REGDOMAIN_H +#define __CDS_REGDOMAIN_H + +#define MAX_CHANNELS_PER_OPERATING_CLASS 25 +#define CDS_MAX_SUPP_OPER_CLASSES 32 +#define MIN_TX_PWR_CAP 8 +#define MAX_TX_PWR_CAP 22 + +#define CTRY_DEFAULT 0 +#define CTRY_FLAG 0x8000 +#define WORLD_ROAMING_FLAG 0x4000 +#define WORLD_ROAMING_MASK 0x00F0 +#define WORLD_ROAMING_PREFIX 0x0060 + +enum country_code { + CTRY_AFGHANISTAN = 4, + CTRY_ALBANIA = 8, + CTRY_ALGERIA = 12, + CTRY_AMERICAN_SAMOA = 16, + CTRY_ANGUILLA = 660, + CTRY_ARGENTINA = 32, + CTRY_ARGENTINA_AP = 5003, + CTRY_ARMENIA = 51, + CTRY_ARUBA = 533, + CTRY_AUSTRALIA = 36, + CTRY_AUSTRALIA_AP = 5000, + CTRY_AUSTRIA = 40, + CTRY_AZERBAIJAN = 31, + CTRY_BAHAMAS = 44, + CTRY_BAHRAIN = 48, + CTRY_BANGLADESH = 50, + CTRY_BARBADOS = 52, + CTRY_BELARUS = 112, + CTRY_BELGIUM = 56, + CTRY_BELIZE = 84, + CTRY_BERMUDA = 60, + CTRY_BHUTAN = 64, + CTRY_BOLIVIA = 68, + CTRY_BOSNIA_HERZ = 70, + CTRY_BRAZIL = 76, + CTRY_BRUNEI_DARUSSALAM = 96, + CTRY_BULGARIA = 100, + CTRY_BURKINA_FASO = 854, + CTRY_CAMBODIA = 116, + CTRY_CANADA = 124, + CTRY_CANADA_AP = 5001, + CTRY_CAYMAN_ISLANDS = 136, + CTRY_CENTRAL_AFRICA_REPUBLIC = 140, + CTRY_CHAD = 148, + CTRY_CHILE = 152, + CTRY_CHINA = 156, + CTRY_CHRISTMAS_ISLAND = 162, + CTRY_COLOMBIA = 170, + CTRY_COSTA_RICA = 188, + CTRY_COTE_DIVOIRE = 384, + CTRY_CROATIA = 191, + CTRY_CYPRUS = 196, + CTRY_CZECH = 203, + CTRY_DENMARK = 208, + CTRY_DOMINICA = 212, + CTRY_DOMINICAN_REPUBLIC = 214, + CTRY_ECUADOR = 218, + CTRY_EGYPT = 818, + CTRY_EL_SALVADOR = 222, + CTRY_ESTONIA = 233, + CTRY_ETHIOPIA = 231, + CTRY_FINLAND = 246, + CTRY_FRANCE = 250, + CTRY_FRENCH_GUIANA = 254, + CTRY_FRENCH_POLYNESIA = 258, + CTRY_GEORGIA = 268, + CTRY_GERMANY = 276, + CTRY_GHANA = 288, + CTRY_GREECE = 300, + CTRY_GREENLAND = 304, + CTRY_GRENADA = 308, + CTRY_GUADELOUPE = 312, + CTRY_GUAM = 316, + CTRY_GUATEMALA = 320, + CTRY_GUYANA = 328, + CTRY_HAITI = 332, + CTRY_HONDURAS = 340, + CTRY_HONG_KONG = 344, + CTRY_HUNGARY = 348, + CTRY_ICELAND = 352, + CTRY_INDIA = 356, + CTRY_INDONESIA = 360, + CTRY_IRAN = 364, + CTRY_IRELAND = 372, + CTRY_ISRAEL = 376, + CTRY_ITALY = 380, + CTRY_JAMAICA = 388, + CTRY_JORDAN = 400, + CTRY_KAZAKHSTAN = 398, + CTRY_KENYA = 404, + CTRY_KOREA_NORTH = 408, + CTRY_KOREA_ROC = 410, + CTRY_KOREA_ROC_AP = 412, + CTRY_KUWAIT = 414, + CTRY_LATVIA = 428, + CTRY_LEBANON = 422, + CTRY_LESOTHO = 426, + CTRY_LIBYA = 434, + CTRY_LIECHTENSTEIN = 438, + CTRY_LITHUANIA = 440, + CTRY_LUXEMBOURG = 442, + CTRY_MACAU = 446, + CTRY_MACEDONIA = 807, + CTRY_MALAWI = 454, + CTRY_MALAYSIA = 458, + CTRY_MALDIVES = 462, + CTRY_MALTA = 470, + CTRY_MARSHALL_ISLANDS = 584, + CTRY_MARTINIQUE = 474, + CTRY_MAURITANIA = 478, + CTRY_MAURITIUS = 480, + CTRY_MAYOTTE = 175, + CTRY_MEXICO = 484, + CTRY_MICRONESIA = 583, + CTRY_MOLDOVA = 498, + CTRY_MONACO = 492, + CTRY_MONGOLIA = 496, + CTRY_MONTENEGRO = 499, + CTRY_MOROCCO = 504, + CTRY_NAMIBIA = 516, + CTRY_NEPAL = 524, + CTRY_NETHERLANDS = 528, + CTRY_NETHERLANDS_ANTILLES = 530, + CTRY_NEW_ZEALAND = 554, + CTRY_NIGERIA = 566, + CTRY_NORTHERN_MARIANA_ISLANDS = 580, + CTRY_NICARAGUA = 558, + CTRY_NORWAY = 578, + CTRY_OMAN = 512, + CTRY_PAKISTAN = 586, + CTRY_PALAU = 585, + CTRY_PANAMA = 591, + CTRY_PAPUA_NEW_GUINEA = 598, + CTRY_PARAGUAY = 600, + CTRY_PERU = 604, + CTRY_PHILIPPINES = 608, + CTRY_POLAND = 616, + CTRY_PORTUGAL = 620, + CTRY_PUERTO_RICO = 630, + CTRY_QATAR = 634, + CTRY_REUNION = 638, + CTRY_ROMANIA = 642, + CTRY_RUSSIA = 643, + CTRY_RWANDA = 646, + CTRY_SAINT_BARTHELEMY = 652, + CTRY_SAINT_KITTS_AND_NEVIS = 659, + CTRY_SAINT_LUCIA = 662, + CTRY_SAINT_MARTIN = 663, + CTRY_SAINT_PIERRE_AND_MIQUELON = 666, + CTRY_SAINT_VINCENT_AND_THE_GRENADIENS = 670, + CTRY_SAMOA = 882, + CTRY_SAUDI_ARABIA = 682, + CTRY_SENEGAL = 686, + CTRY_SERBIA = 688, + CTRY_SINGAPORE = 702, + CTRY_SLOVAKIA = 703, + CTRY_SLOVENIA = 705, + CTRY_SOUTH_AFRICA = 710, + CTRY_SPAIN = 724, + CTRY_SURINAME = 740, + CTRY_SRI_LANKA = 144, + CTRY_SWEDEN = 752, + CTRY_SWITZERLAND = 756, + CTRY_SYRIA = 760, + CTRY_TAIWAN = 158, + CTRY_TANZANIA = 834, + CTRY_THAILAND = 764, + CTRY_TOGO = 768, + CTRY_TRINIDAD_Y_TOBAGO = 780, + CTRY_TUNISIA = 788, + CTRY_TURKEY = 792, + CTRY_TURKS_AND_CAICOS = 796, + CTRY_UGANDA = 800, + CTRY_UKRAINE = 804, + CTRY_UAE = 784, + CTRY_UNITED_KINGDOM = 826, + CTRY_UNITED_STATES = 840, + CTRY_UNITED_STATES_AP = 841, + CTRY_UNITED_STATES_AP2 = 843, + CTRY_UNITED_STATES_PS = 842, + CTRY_URUGUAY = 858, + CTRY_UZBEKISTAN = 860, + CTRY_VANUATU = 548, + CTRY_VENEZUELA = 862, + CTRY_VIET_NAM = 704, + CTRY_VIRGIN_ISLANDS = 850, + CTRY_WALLIS_AND_FUTUNA = 876, + CTRY_YEMEN = 887, + CTRY_ZIMBABWE = 716, + CTRY_JAPAN7 = 4007, + CTRY_JAPAN8 = 4008, + CTRY_JAPAN9 = 4009, + CTRY_JAPAN10 = 4010, + CTRY_JAPAN11 = 4011, + CTRY_JAPAN12 = 4012, + CTRY_JAPAN13 = 4013, + CTRY_JAPAN14 = 4014, + CTRY_JAPAN15 = 4015, + CTRY_JAPAN25 = 4025, + CTRY_JAPAN26 = 4026, + CTRY_JAPAN27 = 4027, + CTRY_JAPAN28 = 4028, + CTRY_JAPAN29 = 4029, + CTRY_JAPAN34 = 4034, + CTRY_JAPAN35 = 4035, + CTRY_JAPAN36 = 4036, + CTRY_JAPAN37 = 4037, + CTRY_JAPAN38 = 4038, + CTRY_JAPAN39 = 4039, + CTRY_JAPAN40 = 4040, + CTRY_JAPAN41 = 4041, + CTRY_JAPAN42 = 4042, + CTRY_JAPAN43 = 4043, + CTRY_JAPAN44 = 4044, + CTRY_JAPAN45 = 4045, + CTRY_JAPAN46 = 4046, + CTRY_JAPAN47 = 4047, + CTRY_JAPAN48 = 4048, + CTRY_JAPAN49 = 4049, + CTRY_JAPAN55 = 4055, + CTRY_JAPAN56 = 4056, + CTRY_XA = 4100, +}; + +enum reg_domain { + NO_ENUMRD = 0x00, + NULL1_WORLD = 0x03, + NULL1_ETSIB = 0x07, + NULL1_ETSIC = 0x08, + + FCC1_FCCA = 0x10, + FCC1_WORLD = 0x11, + FCC2_FCCA = 0x20, + FCC2_WORLD = 0x21, + FCC2_ETSIC = 0x22, + FCC3_FCCA = 0x3A, + FCC3_WORLD = 0x3B, + FCC3_ETSIC = 0x3F, + FCC4_FCCA = 0x12, + FCC5_FCCA = 0x13, + FCC6_FCCA = 0x14, + FCC7_FCCA = 0x15, + FCC8_FCCA = 0x16, + FCC6_WORLD = 0x23, + FCC9_FCCA = 0x17, + FCC10_FCCA = 0x18, + FCC11_WORLD = 0x19, + + ETSI1_WORLD = 0x37, + ETSI3_ETSIA = 0x32, + ETSI2_WORLD = 0x35, + ETSI3_WORLD = 0x36, + ETSI4_WORLD = 0x30, + ETSI4_ETSIC = 0x38, + ETSI5_WORLD = 0x39, + ETSI6_WORLD = 0x34, + ETSI_RESERVED = 0x33, + FRANCE_RES = 0x31, + ETSI7_WORLD = 0x3C, + ETSI8_WORLD = 0x3D, + ETSI9_WORLD = 0x3E, + ETSI10_WORLD = 0x24, + ETSI11_WORLD = 0x26, + + APL4_WORLD = 0x42, + APL3_FCCA = 0x50, + APL_RESERVED = 0x44, + APL2_WORLD = 0x45, + APL2_FCCA = 0x4D, + APL2_APLC = 0x46, + APL3_WORLD = 0x47, + APL2_APLD = 0x49, + APL1_WORLD = 0x52, + APL1_FCCA = 0x53, + APL1_APLA = 0x54, + APL1_ETSIC = 0x55, + APL2_ETSIC = 0x56, + APL5_WORLD = 0x58, + APL6_WORLD = 0x5B, + APL7_FCCA = 0x5C, + APL8_WORLD = 0x5D, + APL9_WORLD = 0x5E, + APL10_WORLD = 0x5F, + APL11_FCCA = 0x4F, + APL12_WORLD = 0x51, + APL13_WORLD = 0x5A, + APL14_WORLD = 0x57, + APL15_WORLD = 0x59, + APL16_WORLD = 0x70, + + WOR0_WORLD = 0x60, + WOR1_WORLD = 0x61, + WOR2_WORLD = 0x62, + WOR3_WORLD = 0x63, + WOR4_FCCA = 0x64, + WOR5_ETSIC = 0x65, + WOR01_WORLD = 0x66, + WOR02_WORLD = 0x67, + EU1_WORLD = 0x68, + WOR9_WORLD = 0x69, + WORA_WORLD = 0x6A, + WORB_WORLD = 0x6B, + WORC_WORLD = 0x6C, + + MKK3_MKKB = 0x80, + MKK3_MKKA2 = 0x81, + MKK3_MKKC = 0x82, + MKK4_MKKB = 0x83, + MKK4_MKKA2 = 0x84, + MKK4_MKKC = 0x85, + MKK5_MKKA = 0x99, + MKK5_FCCA = 0x9A, + MKK5_MKKB = 0x86, + MKK5_MKKA2 = 0x87, + MKK5_MKKC = 0x88, + MKK3_MKKA = 0xF0, + MKK3_MKKA1 = 0xF1, + MKK3_FCCA = 0xF2, + MKK4_MKKA = 0xF3, + MKK4_MKKA1 = 0xF4, + MKK4_FCCA = 0xF5, + MKK9_MKKA = 0xF6, + MKK9_FCCA = 0xFC, + MKK9_MKKA1 = 0xFD, + MKK9_MKKC = 0xFE, + MKK9_MKKA2 = 0xFF, + MKK10_MKKA = 0xF7, + MKK10_FCCA = 0xD0, + MKK10_MKKA1 = 0xD1, + MKK10_MKKC = 0xD2, + MKK10_MKKA2 = 0xD3, + MKK11_MKKA = 0xD4, + MKK11_FCCA = 0xD5, + MKK11_MKKA1 = 0xD6, + MKK11_MKKC = 0xD7, + MKK11_MKKA2 = 0xD8, + + FCC1 = 0x0110, + FCC2 = 0x0120, + FCC3 = 0x0160, + FCC4 = 0x0165, + FCC5 = 0x0510, + FCC6 = 0x0610, + FCC7 = 0x0710, + FCC8 = 0x0810, + FCC9 = 0x0910, + FCC10 = 0x0B10, + FCC11 = 0x0B20, + + ETSI1 = 0x0130, + ETSI2 = 0x0230, + ETSI3 = 0x0330, + ETSI4 = 0x0430, + ETSI5 = 0x0530, + ETSI6 = 0x0630, + ETSI8 = 0x0830, + ETSI9 = 0x0930, + ETSI10 = 0x0D30, + ETSI11 = 0x0E30, + + APL1 = 0x0150, + APL2 = 0x0250, + APL3 = 0x0350, + APL4 = 0x0450, + APL5 = 0x0550, + APL6 = 0x0650, + APL7 = 0x0750, + APL8 = 0x0850, + APL9 = 0x0950, + APL10 = 0x1050, + APL11 = 0x1150, + APL12 = 0x1160, + APL13 = 0x1170, + APL14 = 0x1180, + APL15 = 0x1190, + APL16 = 0x1200, + + NULL1 = 0x0198, + MKK3 = 0x0340, + MKK4 = 0x0440, + MKK5 = 0x0540, + MKK9 = 0x0940, + MKK10 = 0x1040, + MKK11 = 0x1140, + + WORLD = 0x0199, + FCCA = 0x0A10, + MKKA = 0x0A40, + MKKC = 0x0A50, + ETSIC = 0x0C30, +}; + +/** + * enum ctl_val - CTL value + * @FCC: FCC + * @MKK: MKK + * @ETSI: ETSI + * @NO_CTL: no CTL + */ +enum ctl_val { + FCC = 0x10, + MKK = 0x40, + ETSI = 0x30, + NO_CTL = 0xff +}; + +/** + * enum offset_t: channel offset + * @BW20: 20 mhz channel + * @BW40_LOW_PRIMARY: lower channel in 40 mhz + * @BW40_HIGH_PRIMARY: higher channel in 40 mhz + * @BW80: 80 mhz channel + * @BWALL: unknown bandwidth + */ +enum offset_t { + BW20 = 0, + BW40_LOW_PRIMARY = 1, + BW40_HIGH_PRIMARY = 3, + BW80, + BWALL +}; + +/** + * struct reg_dmn_pair: regulatory domain pair + * @reg_dmn_pair: reg domain pair + * @reg_dmn_5ghz: 5G reg domain + * @reg_dmn_2ghz: 2G reg domain + * @single_cc: country with this reg domain + */ +struct reg_dmn_pair { + uint16_t reg_dmn_pair; + uint16_t reg_dmn_5ghz; + uint16_t reg_dmn_2ghz; + uint16_t single_cc; +}; + +/** + * struct country_code_to_reg_dmn: country code to reg domain mapping + * @country_code: country code + * @reg_dmn_pair: regulatory domain pair + * @alpha2: country alpha2 + * @name: country name + */ +struct country_code_to_reg_dmn { + uint16_t country_code; + uint16_t reg_dmn_pair; + const char *alpha2; + const char *name; +}; + +/** + * struct reg_dmn: regulatory domain structure + * @reg_dmn: regulatory domain + * @conformance_test_limit: CTL limit + */ +struct reg_dmn { + uint16_t reg_dmn; + uint8_t conformance_test_limit; +}; + +/** + * struct reg_dmn_op_class_map_t: operating class + * @op_class: operating class number + * @ch_spacing: channel spacing + * @offset: offset + * @channels: channel set + */ +struct reg_dmn_op_class_map_t { + uint8_t op_class; + uint8_t ch_spacing; + enum offset_t offset; + uint8_t channels[MAX_CHANNELS_PER_OPERATING_CLASS]; +}; + +/** + * struct reg_dmn_supp_op_classes: operating classes + * @num_classes: number of classes + * @classes: classes + */ +struct reg_dmn_supp_op_classes { + uint8_t num_classes; + uint8_t classes[CDS_MAX_SUPP_OPER_CLASSES]; +}; + +/** + * struct reg_dmn_tables: reg domain table + * @reg_dmn_pairs: list of reg domain pairs + * @all_countries: list of countries + * @reg_dmns: list of reg domains + * @reg_dmn_pairs_cnt: count of reg domain pairs + * @all_countries_cnt: count of countries + * @reg_dmns_cnt: count of reg domains + */ +struct reg_dmn_tables { + const struct reg_dmn_pair *reg_dmn_pairs; + const struct country_code_to_reg_dmn *all_countries; + const struct reg_dmn *reg_dmns; + uint16_t reg_dmn_pairs_cnt; + uint16_t all_countries_cnt; + uint16_t reg_dmns_cnt; +}; + +int32_t cds_fill_some_regulatory_info(struct regulatory *reg); +int32_t cds_get_country_from_alpha2(uint8_t *alpha2); +void cds_fill_and_send_ctl_to_fw(struct regulatory *reg); +void cds_set_wma_dfs_region(uint8_t dfs_region); +uint16_t cds_reg_dmn_get_opclass_from_channel(uint8_t *country, + uint8_t channel, + uint8_t offset); +uint16_t cds_reg_dmn_get_chanwidth_from_opclass(uint8_t *country, + uint8_t channel, + uint8_t opclass); +uint16_t cds_reg_dmn_set_curr_opclasses(uint8_t num_classes, uint8_t *class); +uint16_t cds_reg_dmn_get_curr_opclasses(uint8_t *num_classes, uint8_t *class); + +#endif /* __CDS_REGDOMAIN_H */ diff --git a/drivers/staging/qcacld-3.0/core/cds/inc/cds_sched.h b/drivers/staging/qcacld-3.0/core/cds/inc/cds_sched.h new file mode 100644 index 0000000000000000000000000000000000000000..af8a9111867987c0f14d00bfd04876bf60a6c1f5 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/cds/inc/cds_sched.h @@ -0,0 +1,601 @@ +/* + * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#if !defined(__CDS_SCHED_H) +#define __CDS_SCHED_H + +/**========================================================================= + + \file cds_sched.h + + \brief Connectivity driver services scheduler + + ========================================================================*/ + +/*-------------------------------------------------------------------------- + Include Files + ------------------------------------------------------------------------*/ +#include +#include +#include +#if defined(WLAN_OPEN_SOURCE) && defined(CONFIG_HAS_WAKELOCK) +#include +#endif +#include +#include +#include "qdf_lock.h" +#include "qdf_mc_timer.h" +#include "cds_config.h" + +#define TX_POST_EVENT 0x001 +#define TX_SUSPEND_EVENT 0x002 +#define MC_POST_EVENT 0x001 +#define MC_SUSPEND_EVENT 0x002 +#define RX_POST_EVENT 0x001 +#define RX_SUSPEND_EVENT 0x002 +#define TX_SHUTDOWN_EVENT 0x010 +#define MC_SHUTDOWN_EVENT 0x010 +#define RX_SHUTDOWN_EVENT 0x010 +#define WD_POST_EVENT 0x001 +#define WD_SHUTDOWN_EVENT 0x002 +#define WD_CHIP_RESET_EVENT 0x004 +#define WD_WLAN_SHUTDOWN_EVENT 0x008 +#define WD_WLAN_REINIT_EVENT 0x010 + +/* + * Maximum number of messages in the system + * These are buffers to account for all current messages + * with some accounting of what we think is a + * worst-case scenario. Must be able to handle all + * incoming frames, as well as overhead for internal + * messaging + * + * Increased to 8000 to handle more RX frames + */ +#define CDS_CORE_MAX_MESSAGES 8000 + +#ifdef QCA_CONFIG_SMP +/* +** Maximum number of cds messages to be allocated for +** OL Rx thread. +*/ +#define CDS_MAX_OL_RX_PKT 4000 + +typedef void (*cds_ol_rx_thread_cb)(void *context, void *rxpkt, uint16_t staid); +#endif + +/* +** QDF Message queue definition. +*/ +typedef struct _cds_mq_type { + /* Lock use to synchronize access to this message queue */ + spinlock_t mqLock; + + /* List of vOS Messages waiting on this queue */ + struct list_head mqList; + +} cds_mq_type, *p_cds_mq_type; + +#ifdef QCA_CONFIG_SMP +/* +** CDS message wrapper for data rx from TXRX +*/ +struct cds_ol_rx_pkt { + struct list_head list; + void *context; + + /* Rx skb */ + void *Rxpkt; + + /* Station id to which this packet is destined */ + uint16_t staId; + + /* Call back to further send this packet to txrx layer */ + cds_ol_rx_thread_cb callback; + +}; +#endif + +/* +** CDS Scheduler context +** The scheduler context contains the following: +** ** the messages queues +** ** the handle to the tread +** ** pointer to the events that gracefully shutdown the MC and Tx threads +** +*/ +typedef struct _cds_sched_context { + /* Place holder to the CDS Context */ + void *pVContext; + /* WMA Message queue on the Main thread */ + cds_mq_type wmaMcMq; + + /* PE Message queue on the Main thread */ + cds_mq_type peMcMq; + + /* SME Message queue on the Main thread */ + cds_mq_type smeMcMq; + + /* SYS Message queue on the Main thread */ + cds_mq_type sysMcMq; + + /* Handle of Event for MC thread to signal startup */ + struct completion McStartEvent; + + struct task_struct *McThread; + + /* completion object for MC thread shutdown */ + struct completion McShutdown; + + /* Wait queue for MC thread */ + wait_queue_head_t mcWaitQueue; + + unsigned long mcEventFlag; + + /* Completion object to resume Mc thread */ + struct completion ResumeMcEvent; + + /* lock to make sure that McThread suspend/resume mechanism is in sync */ + spinlock_t McThreadLock; +#ifdef QCA_CONFIG_SMP + spinlock_t ol_rx_thread_lock; + + /* OL Rx thread handle */ + struct task_struct *ol_rx_thread; + + /* Handle of Event for Rx thread to signal startup */ + struct completion ol_rx_start_event; + + /* Completion object to suspend OL rx thread */ + struct completion ol_suspend_rx_event; + + /* Completion objext to resume OL rx thread */ + struct completion ol_resume_rx_event; + + /* Completion object for OL Rxthread shutdown */ + struct completion ol_rx_shutdown; + + /* Waitq for OL Rx thread */ + wait_queue_head_t ol_rx_wait_queue; + + unsigned long ol_rx_event_flag; + + /* Rx buffer queue */ + struct list_head ol_rx_thread_queue; + + /* Spinlock to synchronize between tasklet and thread */ + spinlock_t ol_rx_queue_lock; + + /* Rx queue length */ + unsigned int ol_rx_queue_len; + + /* Lock to synchronize free buffer queue access */ + spinlock_t cds_ol_rx_pkt_freeq_lock; + + /* Free message queue for OL Rx processing */ + struct list_head cds_ol_rx_pkt_freeq; + + /* cpu hotplug notifier */ + struct notifier_block *cpu_hot_plug_notifier; + + /* affinity lock */ + struct mutex affinity_lock; + + /* rx thread affinity cpu */ + unsigned long rx_thread_cpu; + + /* high throughput required */ + bool high_throughput_required; +#endif +} cds_sched_context, *p_cds_sched_context; + +/** + * struct cds_log_complete - Log completion internal structure + * @is_fatal: Type is fatal or not + * @indicator: Source of bug report + * @reason_code: Reason code for bug report + * @is_report_in_progress: If bug report is in progress + * @recovery_needed: if recovery is needed after report completion + * + * This structure internally stores the log related params + */ +struct cds_log_complete { + uint32_t is_fatal; + uint32_t indicator; + uint32_t reason_code; + bool is_report_in_progress; + bool recovery_needed; +}; + +/* +** CDS Sched Msg Wrapper +** Wrapper messages so that they can be chained to their respective queue +** in the scheduler. +*/ +typedef struct _cds_msg_wrapper { + /* Message node */ + struct list_head msgNode; + + /* the Vos message it is associated to */ + cds_msg_t *pVosMsg; + +} cds_msg_wrapper, *p_cds_msg_wrapper; + +/* forward-declare hdd_context_s as it is used ina function type */ +struct hdd_context_s; +typedef struct _cds_context_type { + /* Messages buffers */ + cds_msg_t aMsgBuffers[CDS_CORE_MAX_MESSAGES]; + + cds_msg_wrapper aMsgWrappers[CDS_CORE_MAX_MESSAGES]; + + /* Free Message queue */ + cds_mq_type freeVosMq; + + /* Scheduler Context */ + cds_sched_context qdf_sched; + + /* HDD Module Context */ + void *pHDDContext; + + /* MAC Module Context */ + void *pMACContext; + + qdf_event_t ProbeEvent; + + uint32_t driver_state; + + qdf_event_t wmaCompleteEvent; + + /* WMA Context */ + void *pWMAContext; + + void *pHIFContext; + + void *htc_ctx; + + void *g_ol_context; + /* + * qdf_ctx will be used by qdf + * while allocating dma memory + * to access dev information. + */ + qdf_device_t qdf_ctx; + + void *pdev_txrx_ctx; + + /* Configuration handle used to get system configuration */ + void *cfg_ctx; + + /* radio index per driver */ + int radio_index; + + bool is_wakelock_log_enabled; + uint32_t wakelock_log_level; + uint32_t connectivity_log_level; + uint32_t packet_stats_log_level; + uint32_t driver_debug_log_level; + uint32_t fw_debug_log_level; + struct cds_log_complete log_complete; + qdf_spinlock_t bug_report_lock; + qdf_event_t connection_update_done_evt; + qdf_mutex_t qdf_conc_list_lock; + qdf_mc_timer_t dbs_opportunistic_timer; +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH + void (*sap_restart_chan_switch_cb)(void *, uint32_t, uint32_t); +#endif + QDF_STATUS (*sme_get_valid_channels)(void*, uint8_t *, uint32_t *); + void (*sme_get_nss_for_vdev)(void*, enum tQDF_ADAPTER_MODE, + uint8_t *, uint8_t *); + + /* Datapath callback functions */ + void (*ol_txrx_update_mac_id_cb)(uint8_t , uint8_t); + void (*hdd_en_lro_in_cc_cb)(struct hdd_context_s *); + void (*hdd_disable_lro_in_cc_cb)(struct hdd_context_s *); + void (*hdd_set_rx_mode_rps_cb)(struct hdd_context_s *, void *, bool); + + /* This list is not sessionized. This mandatory channel list would be + * as per OEMs preference as per the regulatory/other considerations. + * So, this would remain same for all the interfaces. + */ + uint8_t sap_mandatory_channels[QDF_MAX_NUM_CHAN]; + uint32_t sap_mandatory_channels_len; + bool enable_sap_mandatory_chan_list; + bool do_hw_mode_change; + bool enable_fatal_event; + struct cds_config_info *cds_cfg; + + /* This is to track if HW mode change is in progress */ + uint32_t hw_mode_change_in_progress; +} cds_context_type, *p_cds_contextType; + +extern struct _cds_sched_context *gp_cds_sched_context; + +/*--------------------------------------------------------------------------- + Function declarations and documenation + ---------------------------------------------------------------------------*/ +#ifdef QCA_CONFIG_SMP +int cds_sched_handle_cpu_hot_plug(void); +int cds_sched_handle_throughput_req(bool high_tput_required); + +/*--------------------------------------------------------------------------- + \brief cds_drop_rxpkt_by_staid() - API to drop pending Rx packets for a sta + The \a cds_drop_rxpkt_by_staid() drops queued packets for a station, to drop + all the pending packets the caller has to send WLAN_MAX_STA_COUNT as staId. + \param pSchedContext - pointer to the global CDS Sched Context + \param staId - Station Id + + \return Nothing + \sa cds_drop_rxpkt_by_staid() + -------------------------------------------------------------------------*/ +void cds_drop_rxpkt_by_staid(p_cds_sched_context pSchedContext, uint16_t staId); + +/*--------------------------------------------------------------------------- + \brief cds_indicate_rxpkt() - API to Indicate rx data packet + The \a cds_indicate_rxpkt() enqueues the rx packet onto ol_rx_thread_queue + and notifies cds_ol_rx_thread(). + \param Arg - pointer to the global CDS Sched Context + \param pkt - Vos data message buffer + + \return Nothing + \sa cds_indicate_rxpkt() + -------------------------------------------------------------------------*/ +void cds_indicate_rxpkt(p_cds_sched_context pSchedContext, + struct cds_ol_rx_pkt *pkt); + +/*--------------------------------------------------------------------------- + \brief cds_alloc_ol_rx_pkt() - API to return next available cds message + The \a cds_alloc_ol_rx_pkt() returns next available cds message buffer + used for Rx Data processing. + \param pSchedContext - pointer to the global CDS Sched Context + + \return pointer to cds message buffer + \sa cds_alloc_ol_rx_pkt() + -------------------------------------------------------------------------*/ +struct cds_ol_rx_pkt *cds_alloc_ol_rx_pkt(p_cds_sched_context pSchedContext); + +/*--------------------------------------------------------------------------- + \brief cds_free_ol_rx_pkt() - API to release cds message to the freeq + The \a cds_free_ol_rx_pkt() returns the cds message used for Rx data + to the free queue. + \param pSchedContext - pointer to the global CDS Sched Context + \param pkt - Vos message buffer to be returned to free queue. + + \return Nothing + \sa cds_free_ol_rx_pkt() + -------------------------------------------------------------------------*/ +void cds_free_ol_rx_pkt(p_cds_sched_context pSchedContext, + struct cds_ol_rx_pkt *pkt); +/*--------------------------------------------------------------------------- + \brief cds_free_ol_rx_pkt_freeq() - Free cdss buffer free queue + The \a cds_free_ol_rx_pkt_freeq() does mem free of the buffers + available in free cds buffer queue which is used for Data rx processing + from Tlshim. + \param pSchedContext - pointer to the global CDS Sched Context + + \return Nothing + \sa cds_free_ol_rx_pkt_freeq() + -------------------------------------------------------------------------*/ +void cds_free_ol_rx_pkt_freeq(p_cds_sched_context pSchedContext); +#else +/** + * cds_drop_rxpkt_by_staid() - api to drop pending rx packets for a sta + * @pSchedContext: Pointer to the global CDS Sched Context + * @staId: Station Id + * + * This api drops queued packets for a station, to drop all the pending + * packets the caller has to send WLAN_MAX_STA_COUNT as staId. + * + * Return: none + */ +static inline +void cds_drop_rxpkt_by_staid(p_cds_sched_context pSchedContext, uint16_t staId) +{ +} + +/** + * cds_indicate_rxpkt() - API to Indicate rx data packet + * @pSchedContext: pointer to CDS Sched Context + * @pkt: CDS OL RX pkt pointer containing to RX data message buffer + * + * Return: none + */ +static inline +void cds_indicate_rxpkt(p_cds_sched_context pSchedContext, + struct cds_ol_rx_pkt *pkt) +{ +} + +/** + * cds_alloc_ol_rx_pkt() - API to return next available cds message + * @pSchedContext: pointer to CDS Sched Context + * + * Return: none + */ +static inline +struct cds_ol_rx_pkt *cds_alloc_ol_rx_pkt(p_cds_sched_context pSchedContext) +{ +} + +/** + * cds_free_ol_rx_pkt() - API to release cds message to the freeq + * @pSchedContext: pointer to CDS Sched Context + * @pkt: CDS message buffer to be returned to free queue + * + * Return: none + */ +static inline +void cds_free_ol_rx_pkt(p_cds_sched_context pSchedContext, + struct cds_ol_rx_pkt *pkt) +{ +} + +/** + * cds_free_ol_rx_pkt_freeq() - Free cds buffer free queue + * @pSchedContext: pointer to CDS Sched Context + * @pkt: CDS message buffer to be returned to free queue + * + * Return: none + */ +static inline +void cds_free_ol_rx_pkt_freeq(p_cds_sched_context pSchedContext) +{ +} + +static inline int cds_sched_handle_throughput_req( + bool high_tput_required) +{ + return 0; +} + +#endif + +/*--------------------------------------------------------------------------- + + \brief cds_sched_open() - initialize the CDS Scheduler + + The \a cds_sched_open() function initializes the CDS Scheduler + Upon successful initialization: + + - All the message queues are initialized + + - The Main Controller thread is created and ready to receive and + dispatch messages. + + - The Tx thread is created and ready to receive and dispatch messages + + \param p_cds_context - pointer to the global QDF Context + + \param p_cds_sched_context - pointer to a previously allocated buffer big + enough to hold a scheduler context. + + \return QDF_STATUS_SUCCESS - Scheduler was successfully initialized and + is ready to be used. + + QDF_STATUS_E_RESOURCES - System resources (other than memory) + are unavailable to initilize the scheduler + + QDF_STATUS_E_NOMEM - insufficient memory exists to initialize + the scheduler + + QDF_STATUS_E_INVAL - Invalid parameter passed to the scheduler Open + function + + QDF_STATUS_E_FAILURE - Failure to initialize the scheduler/ + + \sa cds_sched_open() + + -------------------------------------------------------------------------*/ +QDF_STATUS cds_sched_open(void *p_cds_context, + p_cds_sched_context pSchedCxt, uint32_t SchedCtxSize); + +/*--------------------------------------------------------------------------- + + \brief cds_sched_close() - Close the CDS Scheduler + + The \a cds_sched_closes() function closes the CDS Scheduler + Upon successful closing: + + - All the message queues are flushed + + - The Main Controller thread is closed + + - The Tx thread is closed + + \param p_cds_context - pointer to the global QDF Context + + \return QDF_STATUS_SUCCESS - Scheduler was successfully initialized and + is ready to be used. + + QDF_STATUS_E_INVAL - Invalid parameter passed to the scheduler Open + function + + QDF_STATUS_E_FAILURE - Failure to initialize the scheduler/ + + \sa cds_sched_close() + + ---------------------------------------------------------------------------*/ +QDF_STATUS cds_sched_close(void *p_cds_context); + +/* Helper routines provided to other CDS API's */ +QDF_STATUS cds_mq_init(p_cds_mq_type pMq); +void cds_mq_deinit(p_cds_mq_type pMq); +void cds_mq_put(p_cds_mq_type pMq, p_cds_msg_wrapper pMsgWrapper); +void cds_mq_put_front(p_cds_mq_type mq, p_cds_msg_wrapper msg_wrapper); +p_cds_msg_wrapper cds_mq_get(p_cds_mq_type pMq); +bool cds_is_mq_empty(p_cds_mq_type pMq); +p_cds_sched_context get_cds_sched_ctxt(void); +QDF_STATUS cds_sched_init_mqs(p_cds_sched_context pSchedContext); +void cds_sched_deinit_mqs(p_cds_sched_context pSchedContext); +void cds_sched_flush_mc_mqs(p_cds_sched_context pSchedContext); + +void qdf_timer_module_init(void); +void qdf_timer_module_deinit(void); +void cds_ssr_protect_init(void); +void cds_ssr_protect(const char *caller_func); +void cds_ssr_unprotect(const char *caller_func); +bool cds_wait_for_external_threads_completion(const char *caller_func); +void cds_print_external_threads(void); +int cds_get_gfp_flags(void); + +/** + * cds_return_external_threads_count() - return active external thread calls + * + * Return: total number of active extrenal threads in driver + */ +int cds_return_external_threads_count(void); + +/** + * cds_shutdown_notifier_register() - Register for shutdown notification + * @cb : Call back to be called + * @priv : Private pointer to be passed back to call back + * + * During driver remove or shutdown (recovery), external threads might be stuck + * waiting on some event from firmware at lower layers. Remove or shutdown can't + * proceed till the thread completes to avoid any race condition. Call backs can + * be registered here to get early notification of remove or shutdown so that + * waiting thread can be unblocked and hence remove or shutdown can proceed + * further as waiting there may not make sense when FW may already have been + * down. + * + * Return: CDS status + */ +QDF_STATUS cds_shutdown_notifier_register(void (*cb)(void *priv), void *priv); + +/** + * cds_shutdown_notifier_purge() - Purge all the notifiers + * + * Shutdown notifiers are added to provide the early notification of remove or + * shutdown being initiated. Adding this API to purge all the registered call + * backs as they are not useful any more while all the lower layers are being + * shutdown. + * + * Return: None + */ +void cds_shutdown_notifier_purge(void); + +#endif /* #if !defined __CDS_SCHED_H */ diff --git a/drivers/staging/qcacld-3.0/core/cds/inc/cds_utils.h b/drivers/staging/qcacld-3.0/core/cds/inc/cds_utils.h new file mode 100644 index 0000000000000000000000000000000000000000..63699f0dddccae6fa76c7733295c9e8fe0f18942 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/cds/inc/cds_utils.h @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2014-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#if !defined(__CDS_UTILS_H) +#define __CDS_UTILS_H + +/**========================================================================= + + \file cds_utils.h + + \brief Connectivity driver services (CDS) utility APIs + + Various utility functions + + ========================================================================*/ + +/*-------------------------------------------------------------------------- + Include Files + ------------------------------------------------------------------------*/ +#include +#include +#include +#include +#include "ani_global.h" + +/*-------------------------------------------------------------------------- + Preprocessor definitions and constants + ------------------------------------------------------------------------*/ +#define CDS_DIGEST_SHA1_SIZE (20) +#define CDS_DIGEST_MD5_SIZE (16) + +#define CDS_24_GHZ_BASE_FREQ (2407) +#define CDS_5_GHZ_BASE_FREQ (5000) +#define CDS_24_GHZ_CHANNEL_6 (6) +#define CDS_24_GHZ_CHANNEL_14 (14) +#define CDS_24_GHZ_CHANNEL_15 (15) +#define CDS_24_GHZ_CHANNEL_27 (27) +#define CDS_5_GHZ_CHANNEL_170 (170) +#define CDS_CHAN_SPACING_5MHZ (5) +#define CDS_CHAN_SPACING_20MHZ (20) +#define CDS_CHAN_14_FREQ (2484) +#define CDS_CHAN_15_FREQ (2512) +#define CDS_CHAN_170_FREQ (5852) + +#define INVALID_SCAN_ID 0xFFFFFFFF + +#define cds_log(level, args...) QDF_TRACE(QDF_MODULE_ID_QDF, level, ## args) +#define cds_logfl(level, format, args...) cds_log(level, FL(format), ## args) + +#define cds_alert(format, args...) \ + cds_logfl(QDF_TRACE_LEVEL_FATAL, format, ## args) +#define cds_err(format, args...) \ + cds_logfl(QDF_TRACE_LEVEL_ERROR, format, ## args) +#define cds_warn(format, args...) \ + cds_logfl(QDF_TRACE_LEVEL_WARN, format, ## args) +#define cds_notice(format, args...) \ + cds_logfl(QDF_TRACE_LEVEL_INFO, format, ## args) +#define cds_info(format, args...) \ + cds_logfl(QDF_TRACE_LEVEL_INFO_HIGH, format, ## args) +#define cds_debug(format, args...) \ + cds_logfl(QDF_TRACE_LEVEL_DEBUG, format, ## args) + +/** + * enum cds_band_type - Band type - 2g, 5g or all + * CDS_BAND_ALL: Both 2G and 5G are valid. + * CDS_BAND_2GHZ: only 2G is valid. + * CDS_BAND_5GHZ: only 5G is valid. + */ +enum cds_band_type { + CDS_BAND_ALL = 0, + CDS_BAND_2GHZ = 1, + CDS_BAND_5GHZ = 2 +}; + +/*------------------------------------------------------------------------- + Function declarations and documenation + ------------------------------------------------------------------------*/ + +QDF_STATUS cds_crypto_init(uint32_t *phCryptProv); + +QDF_STATUS cds_crypto_deinit(uint32_t hCryptProv); + +/** + * cds_rand_get_bytes + + * FUNCTION: + * Returns cryptographically secure pseudo-random bytes. + * + * + * @param pbBuf - the caller allocated location where the bytes should be copied + * @param numBytes the number of bytes that should be generated and + * copied + * + * @return QDF_STATUS_SUCCSS if the operation succeeds + */ +QDF_STATUS cds_rand_get_bytes(uint32_t handle, uint8_t *pbBuf, + uint32_t numBytes); + +uint32_t cds_chan_to_freq(uint8_t chan); +uint8_t cds_freq_to_chan(uint32_t freq); +enum cds_band_type cds_chan_to_band(uint32_t chan); +#ifdef WLAN_FEATURE_11W +bool cds_is_mmie_valid(uint8_t *key, uint8_t *ipn, + uint8_t *frm, uint8_t *efrm); +bool cds_attach_mmie(uint8_t *igtk, uint8_t *ipn, uint16_t key_id, + uint8_t *frm, uint8_t *efrm, uint16_t frmLen); +uint8_t cds_get_mmie_size(void); +#endif /* WLAN_FEATURE_11W */ +QDF_STATUS sme_send_flush_logs_cmd_to_fw(tpAniSirGlobal pMac); +static inline void cds_host_diag_log_work(qdf_wake_lock_t *lock, uint32_t msec, + uint32_t reason) { + if (((cds_get_ring_log_level(RING_ID_WAKELOCK) >= WLAN_LOG_LEVEL_ACTIVE) + && (WIFI_POWER_EVENT_WAKELOCK_HOLD_RX == reason)) || + (WIFI_POWER_EVENT_WAKELOCK_HOLD_RX != reason)) { + host_diag_log_wlock(reason, qdf_wake_lock_name(lock), + msec, WIFI_POWER_EVENT_WAKELOCK_TAKEN); + } +} +#endif /* #if !defined __CDS_UTILS_H */ diff --git a/drivers/staging/qcacld-3.0/core/cds/src/cds_api.c b/drivers/staging/qcacld-3.0/core/cds/src/cds_api.c new file mode 100644 index 0000000000000000000000000000000000000000..64a12d0f93847ee6d4b937e720c9f38c43849143 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/cds/src/cds_api.c @@ -0,0 +1,2623 @@ +/* + * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: cds_api.c + * + * Connectivity driver services APIs + */ + +#include +#include "cds_sched.h" +#include +#include "sir_types.h" +#include "sir_api.h" +#include "sir_mac_prot_def.h" +#include "sme_api.h" +#include "mac_init_api.h" +#include "wlan_qct_sys.h" +#include "i_cds_packet.h" +#include "cds_reg_service.h" +#include "wma_types.h" +#include "wlan_hdd_main.h" +#include + +#include "pld_common.h" +#include "sap_api.h" +#include "qdf_trace.h" +#include "bmi.h" +#include "ol_fw.h" +#include "ol_if_athvar.h" +#include "hif.h" +#include "cds_concurrency.h" +#include "cds_utils.h" +#include "wlan_logging_sock_svc.h" +#include "wma.h" +#include "ol_txrx.h" +#include "pktlog_ac.h" +#include "wlan_hdd_ipa.h" +/* Preprocessor Definitions and Constants */ + +/* Maximum number of cds message queue get wrapper failures to cause panic */ +#define CDS_WRAPPER_MAX_FAIL_COUNT (CDS_CORE_MAX_MESSAGES * 3) + +/* Data definitions */ +static cds_context_type g_cds_context; +static p_cds_contextType gp_cds_context; +static struct __qdf_device g_qdf_ctx; + +/* Debug variable to detect MC thread stuck */ +static atomic_t cds_wrapper_empty_count; + +static uint8_t cds_multicast_logging; + +void cds_sys_probe_thread_cback(void *pUserData); + +/** + * cds_init() - Initialize CDS + * + * This function allocates the resource required for CDS, but does not + * initialize all the members. This overall initialization will happen at + * cds_open(). + * + * Return: Global context on success and NULL on failure. + */ +v_CONTEXT_t cds_init(void) +{ + qdf_debugfs_init(); + qdf_lock_stats_init(); + qdf_mem_init(); + qdf_mc_timer_manager_init(); + + gp_cds_context = &g_cds_context; + + gp_cds_context->qdf_ctx = &g_qdf_ctx; + qdf_mem_zero(&g_qdf_ctx, sizeof(g_qdf_ctx)); + + qdf_trace_spin_lock_init(); + +#if defined(TRACE_RECORD) + qdf_trace_init(); +#endif + qdf_register_debugcb_init(); + + cds_ssr_protect_init(); + + return gp_cds_context; +} + +/** + * cds_deinit() - Deinitialize CDS + * + * This function frees the CDS resources + */ +void cds_deinit(void) +{ + if (gp_cds_context == NULL) + return; + + qdf_mc_timer_manager_exit(); + qdf_mem_exit(); + qdf_lock_stats_deinit(); + qdf_debugfs_exit(); + + gp_cds_context->qdf_ctx = NULL; + gp_cds_context = NULL; + + qdf_mem_zero(&g_cds_context, sizeof(g_cds_context)); + return; +} + +#ifdef FEATURE_WLAN_DIAG_SUPPORT +/** + * cds_tdls_tx_rx_mgmt_event()- send tdls mgmt rx tx event + * @event_id: event id + * @tx_rx: tx or rx + * @type: type of frame + * @action_sub_type: action frame type + * @peer_mac: peer mac + * + * This Function sends tdls mgmt rx tx diag event + * + * Return: void. + */ +void cds_tdls_tx_rx_mgmt_event(uint8_t event_id, uint8_t tx_rx, + uint8_t type, uint8_t action_sub_type, uint8_t *peer_mac) +{ + WLAN_HOST_DIAG_EVENT_DEF(tdls_tx_rx_mgmt, + struct host_event_tdls_tx_rx_mgmt); + + tdls_tx_rx_mgmt.event_id = event_id; + tdls_tx_rx_mgmt.tx_rx = tx_rx; + tdls_tx_rx_mgmt.type = type; + tdls_tx_rx_mgmt.action_sub_type = action_sub_type; + qdf_mem_copy(tdls_tx_rx_mgmt.peer_mac, + peer_mac, CDS_MAC_ADDRESS_LEN); + WLAN_HOST_DIAG_EVENT_REPORT(&tdls_tx_rx_mgmt, + EVENT_WLAN_TDLS_TX_RX_MGMT); +} +#endif + +/** + * vos_set_ac_specs_params() - set ac_specs params in mac open param + * @param: Pointer to mac open param + * @hdd_ctx: Pointer to hdd context + * + * Return: none + */ +static void cds_set_ac_specs_params(struct cds_config_info *cds_cfg, + hdd_context_t *hdd_ctx) +{ + uint8_t num_entries = 0; + uint8_t tx_sched_wrr_param[TX_SCHED_WRR_PARAMS_NUM]; + uint8_t *tx_sched_wrr_ac; + int i; + + if (NULL == hdd_ctx) + return; + + if (NULL == cds_cfg) + return; + + if (NULL == hdd_ctx->config) { + /* Do nothing if hdd_ctx is invalid */ + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: Warning: hdd_ctx->cfg_ini is NULL", __func__); + return; + } + + for (i = 0; i < OL_TX_NUM_WMM_AC; i++) { + switch (i) { + case OL_TX_WMM_AC_BE: + tx_sched_wrr_ac = hdd_ctx->config->tx_sched_wrr_be; + break; + case OL_TX_WMM_AC_BK: + tx_sched_wrr_ac = hdd_ctx->config->tx_sched_wrr_bk; + break; + case OL_TX_WMM_AC_VI: + tx_sched_wrr_ac = hdd_ctx->config->tx_sched_wrr_vi; + break; + case OL_TX_WMM_AC_VO: + tx_sched_wrr_ac = hdd_ctx->config->tx_sched_wrr_vo; + break; + default: + tx_sched_wrr_ac = NULL; + break; + } + + hdd_string_to_u8_array(tx_sched_wrr_ac, + tx_sched_wrr_param, + &num_entries, + sizeof(tx_sched_wrr_param)); + + if (num_entries == TX_SCHED_WRR_PARAMS_NUM) { + cds_cfg->ac_specs[i].wrr_skip_weight = + tx_sched_wrr_param[0]; + cds_cfg->ac_specs[i].credit_threshold = + tx_sched_wrr_param[1]; + cds_cfg->ac_specs[i].send_limit = + tx_sched_wrr_param[2]; + cds_cfg->ac_specs[i].credit_reserve = + tx_sched_wrr_param[3]; + cds_cfg->ac_specs[i].discard_weight = + tx_sched_wrr_param[4]; + } + + num_entries = 0; + } +} + +/** + * cds_open() - open the CDS Module + * + * cds_open() function opens the CDS Scheduler + * Upon successful initialization: + * - All CDS submodules should have been initialized + * + * - The CDS scheduler should have opened + * + * - All the WLAN SW components should have been opened. This includes + * SYS, MAC, SME, WMA and TL. + * + * Return: QDF status + */ +QDF_STATUS cds_open(void) +{ + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + int iter = 0; + tSirRetStatus sirStatus = eSIR_SUCCESS; + struct cds_config_info *cds_cfg; + qdf_device_t qdf_ctx; + HTC_INIT_INFO htcInfo; + struct ol_context *ol_ctx; + struct hif_opaque_softc *scn; + void *HTCHandle; + hdd_context_t *pHddCtx; + cds_context_type *cds_ctx; + + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: Opening CDS", __func__); + + cds_ctx = cds_get_context(QDF_MODULE_ID_QDF); + if (!cds_ctx) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_FATAL, + "%s: Trying to open CDS without a PreOpen", __func__); + QDF_ASSERT(0); + return QDF_STATUS_E_FAILURE; + } + + /* Initialize the timer module */ + qdf_timer_module_init(); + + /* Initialize bug reporting structure */ + cds_init_log_completion(); + + /* Initialize the probe event */ + if (qdf_event_create(&gp_cds_context->ProbeEvent) != QDF_STATUS_SUCCESS) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_FATAL, + "%s: Unable to init probeEvent", __func__); + QDF_ASSERT(0); + return QDF_STATUS_E_FAILURE; + } + if (qdf_event_create(&(gp_cds_context->wmaCompleteEvent)) != + QDF_STATUS_SUCCESS) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_FATAL, + "%s: Unable to init wmaCompleteEvent", __func__); + QDF_ASSERT(0); + goto err_probe_event; + } + + /* Initialize the free message queue */ + qdf_status = cds_mq_init(&gp_cds_context->freeVosMq); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + /* Critical Error ... Cannot proceed further */ + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_FATAL, + "%s: Failed to initialize CDS free message queue", + __func__); + QDF_ASSERT(0); + goto err_wma_complete_event; + } + + for (iter = 0; iter < CDS_CORE_MAX_MESSAGES; iter++) { + (gp_cds_context->aMsgWrappers[iter]).pVosMsg = + &(gp_cds_context->aMsgBuffers[iter]); + INIT_LIST_HEAD(&gp_cds_context->aMsgWrappers[iter].msgNode); + cds_mq_put(&gp_cds_context->freeVosMq, + &(gp_cds_context->aMsgWrappers[iter])); + } + + pHddCtx = (hdd_context_t *) (gp_cds_context->pHDDContext); + if ((NULL == pHddCtx) || (NULL == pHddCtx->config)) { + /* Critical Error ... Cannot proceed further */ + cds_err("Hdd Context is Null"); + QDF_ASSERT(0); + goto err_msg_queue; + } + + if (!QDF_IS_STATUS_SUCCESS(qdf_mutex_create( + &cds_ctx->qdf_conc_list_lock))) { + cds_err("Failed to init qdf_conc_list_lock"); + QDF_ASSERT(0); + goto err_msg_queue; + } + + /* Now Open the CDS Scheduler */ + + if (pHddCtx->driver_status == DRIVER_MODULES_UNINITIALIZED || + cds_is_driver_recovering()) { + qdf_status = cds_sched_open(gp_cds_context, + &gp_cds_context->qdf_sched, + sizeof(cds_sched_context)); + + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + /* Critical Error ... Cannot proceed further */ + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_FATAL, + "%s: Failed to open CDS Scheduler", __func__); + QDF_ASSERT(0); + goto err_concurrency_lock; + } + } + + scn = cds_get_context(QDF_MODULE_ID_HIF); + if (!scn) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_FATAL, + "%s: scn is null!", __func__); + goto err_sched_close; + } + + cds_cfg = cds_get_ini_config(); + if (!cds_cfg) { + cds_err("Cds config is NULL"); + QDF_ASSERT(0); + goto err_sched_close; + } + hdd_enable_fastpath(pHddCtx->config, scn); + hdd_wlan_update_target_info(pHddCtx, scn); + + ol_ctx = cds_get_context(QDF_MODULE_ID_BMI); + /* Initialize BMI and Download firmware */ + qdf_status = bmi_download_firmware(ol_ctx); + if (qdf_status != QDF_STATUS_SUCCESS) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_FATAL, + "BMI FIALED status:%d", qdf_status); + goto err_bmi_close; + } + htcInfo.pContext = ol_ctx; + htcInfo.TargetFailure = ol_target_failure; + htcInfo.TargetSendSuspendComplete = wma_target_suspend_acknowledge; + htcInfo.target_initial_wakeup_cb = wma_handle_initial_wake_up; + qdf_ctx = cds_get_context(QDF_MODULE_ID_QDF_DEVICE); + + /* Create HTC */ + gp_cds_context->htc_ctx = + htc_create(scn, &htcInfo, qdf_ctx, cds_get_conparam()); + if (!gp_cds_context->htc_ctx) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_FATAL, + "%s: Failed to Create HTC", __func__); + goto err_bmi_close; + } + + if (bmi_done(ol_ctx)) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_FATAL, + "%s: Failed to complete BMI phase", __func__); + goto err_htc_close; + } + + cds_set_ac_specs_params(cds_cfg, pHddCtx); + + /*Open the WMA module */ + qdf_status = wma_open(gp_cds_context, + hdd_update_tgt_cfg, + hdd_dfs_indicate_radar, cds_cfg); + + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + /* Critical Error ... Cannot proceed further */ + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_FATAL, + "%s: Failed to open WMA module", __func__); + QDF_ASSERT(0); + goto err_htc_close; + } + + /* Number of peers limit differs in each chip version. If peer max + * limit configured in ini exceeds more than supported, WMA adjusts + * and keeps correct limit in cds_cfg.max_station. So, make sure + * config entry pHddCtx->config->maxNumberOfPeers has adjusted value + */ + /* In FTM mode cds_cfg->max_stations will be zero. On updating same + * into hdd context config entry, leads to pe_open() to fail, if + * con_mode change happens from FTM mode to any other mode. + */ + if (DRIVER_TYPE_PRODUCTION == cds_cfg->driver_type) + pHddCtx->config->maxNumberOfPeers = cds_cfg->max_station; + + HTCHandle = cds_get_context(QDF_MODULE_ID_HTC); + if (!HTCHandle) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_FATAL, + "%s: HTCHandle is null!", __func__); + goto err_wma_close; + } + if (htc_wait_target(HTCHandle)) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_FATAL, + "%s: Failed to complete BMI phase", __func__); + goto err_wma_close; + } + bmi_target_ready(scn, gp_cds_context->cfg_ctx); + + /* Now proceed to open the MAC */ + sirStatus = + mac_open(&(gp_cds_context->pMACContext), + gp_cds_context->pHDDContext, cds_cfg); + + if (eSIR_SUCCESS != sirStatus) { + /* Critical Error ... Cannot proceed further */ + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_FATAL, + "%s: Failed to open MAC", __func__); + QDF_ASSERT(0); + goto err_wma_close; + } + + /* Now proceed to open the SME */ + qdf_status = sme_open(gp_cds_context->pMACContext); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + /* Critical Error ... Cannot proceed further */ + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_FATAL, + "%s: Failed to open SME", __func__); + QDF_ASSERT(0); + goto err_mac_close; + } + + gp_cds_context->pdev_txrx_ctx = + ol_txrx_pdev_attach(gp_cds_context->cfg_ctx, + gp_cds_context->htc_ctx, + gp_cds_context->qdf_ctx); + if (!gp_cds_context->pdev_txrx_ctx) { + /* Critical Error ... Cannot proceed further */ + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_FATAL, + "%s: Failed to open TXRX", __func__); + QDF_ASSERT(0); + goto err_sme_close; + } + + hdd_lro_create(); + + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: CDS successfully Opened", __func__); + + return QDF_STATUS_SUCCESS; + +err_sme_close: + sme_close(gp_cds_context->pMACContext); + +err_mac_close: + mac_close(gp_cds_context->pMACContext); + +err_wma_close: + cds_shutdown_notifier_purge(); + wma_close(gp_cds_context); + + wma_wmi_service_close(gp_cds_context); + +err_htc_close: + if (gp_cds_context->htc_ctx) { + htc_destroy(gp_cds_context->htc_ctx); + gp_cds_context->htc_ctx = NULL; + } + +err_bmi_close: + bmi_cleanup(ol_ctx); + +err_sched_close: + if (pHddCtx->driver_status == DRIVER_MODULES_UNINITIALIZED || + cds_is_driver_recovering()) { + qdf_status = cds_sched_close(gp_cds_context); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + hdd_err("Failed to close CDS Scheduler"); + QDF_ASSERT(false); + } + } + +err_concurrency_lock: + qdf_mutex_destroy(&cds_ctx->qdf_conc_list_lock); + +err_msg_queue: + cds_mq_deinit(&gp_cds_context->freeVosMq); + +err_wma_complete_event: + qdf_event_destroy(&gp_cds_context->wmaCompleteEvent); + +err_probe_event: + qdf_event_destroy(&gp_cds_context->ProbeEvent); + + return QDF_STATUS_E_FAILURE; +} /* cds_open() */ + +/** + * cds_pre_enable() - pre enable cds + * @cds_context: CDS context + * + * Return: QDF status + */ +QDF_STATUS cds_pre_enable(v_CONTEXT_t cds_context) +{ + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + p_cds_contextType p_cds_context = (p_cds_contextType) cds_context; + void *scn; + QDF_TRACE(QDF_MODULE_ID_SYS, QDF_TRACE_LEVEL_INFO, "cds prestart"); + + if (gp_cds_context != p_cds_context) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: Context mismatch", __func__); + QDF_ASSERT(0); + return QDF_STATUS_E_INVAL; + } + + if (p_cds_context->pMACContext == NULL) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: MAC NULL context", __func__); + QDF_ASSERT(0); + return QDF_STATUS_E_INVAL; + } + + if (p_cds_context->pWMAContext == NULL) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: WMA NULL context", __func__); + QDF_ASSERT(0); + return QDF_STATUS_E_INVAL; + } + + scn = cds_get_context(QDF_MODULE_ID_HIF); + if (!scn) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_FATAL, + "%s: scn is null!", __func__); + return QDF_STATUS_E_FAILURE; + } + + /* call Packetlog connect service */ + if (QDF_GLOBAL_FTM_MODE != cds_get_conparam() && + QDF_GLOBAL_EPPING_MODE != cds_get_conparam()) { + htt_pkt_log_init(gp_cds_context->pdev_txrx_ctx, scn); + pktlog_htc_attach(); + } + + /* Reset wma wait event */ + qdf_event_reset(&gp_cds_context->wmaCompleteEvent); + + /*call WMA pre start */ + qdf_status = wma_pre_start(gp_cds_context); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + QDF_TRACE(QDF_MODULE_ID_SYS, QDF_TRACE_LEVEL_FATAL, + "Failed to WMA prestart"); + QDF_ASSERT(0); + return QDF_STATUS_E_FAILURE; + } + + /* Need to update time out of complete */ + qdf_status = qdf_wait_single_event(&gp_cds_context->wmaCompleteEvent, + CDS_WMA_TIMEOUT); + if (qdf_status != QDF_STATUS_SUCCESS) { + if (qdf_status == QDF_STATUS_E_TIMEOUT) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: Timeout occurred before WMA complete", + __func__); + } else { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: wma_pre_start reporting other error", + __func__); + } + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: Test MC thread by posting a probe message to SYS", + __func__); + wlan_sys_probe(); + + QDF_ASSERT(0); + return QDF_STATUS_E_FAILURE; + } + + qdf_status = htc_start(gp_cds_context->htc_ctx); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + QDF_TRACE(QDF_MODULE_ID_SYS, QDF_TRACE_LEVEL_FATAL, + "Failed to Start HTC"); + QDF_ASSERT(0); + return QDF_STATUS_E_FAILURE; + } + qdf_status = wma_wait_for_ready_event(gp_cds_context->pWMAContext); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_FATAL, + "Failed to get ready event from target firmware"); + /* + * Panic only if recovery is disabled, else return failure so + * that driver load can fail gracefully. We cannot trigger self + * recovery here because driver is not fully loaded yet. + */ + if (!cds_is_self_recovery_enabled()) + QDF_BUG(0); + + htc_stop(gp_cds_context->htc_ctx); + return QDF_STATUS_E_FAILURE; + } + + if (ol_txrx_pdev_post_attach(gp_cds_context->pdev_txrx_ctx)) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_FATAL, + "Failed to attach pdev"); + htc_stop(gp_cds_context->htc_ctx); + QDF_ASSERT(0); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * cds_enable() - start/enable cds module + * @cds_context: CDS context + * + * Return: QDF status + */ +QDF_STATUS cds_enable(v_CONTEXT_t cds_context) +{ + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + tSirRetStatus sirStatus = eSIR_SUCCESS; + p_cds_contextType p_cds_context = (p_cds_contextType) cds_context; + tHalMacStartParameters halStartParams; + + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO, + "%s: Starting Libra SW", __func__); + + /* We support only one instance for now ... */ + if (gp_cds_context != p_cds_context) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: mismatch in context", __func__); + return QDF_STATUS_E_FAILURE; + } + + if ((p_cds_context->pWMAContext == NULL) || + (p_cds_context->pMACContext == NULL)) { + if (p_cds_context->pWMAContext == NULL) + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: WMA NULL context", __func__); + else + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: MAC NULL context", __func__); + + return QDF_STATUS_E_FAILURE; + } + + /* Start the wma */ + qdf_status = wma_start(p_cds_context); + if (qdf_status != QDF_STATUS_SUCCESS) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: Failed to start wma", __func__); + return QDF_STATUS_E_FAILURE; + } + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO, + "%s: wma correctly started", __func__); + + /* Start the MAC */ + qdf_mem_zero(&halStartParams, + sizeof(tHalMacStartParameters)); + + /* Start the MAC */ + sirStatus = + mac_start(p_cds_context->pMACContext, &halStartParams); + + if (eSIR_SUCCESS != sirStatus) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_FATAL, + "%s: Failed to start MAC", __func__); + goto err_wma_stop; + } + + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO, + "%s: MAC correctly started", __func__); + + /* START SME */ + qdf_status = sme_start(p_cds_context->pMACContext); + + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_FATAL, + "%s: Failed to start SME", __func__); + goto err_mac_stop; + } + + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO, + "%s: SME correctly started", __func__); + + if (ol_txrx_pdev_attach_target + (p_cds_context->pdev_txrx_ctx)) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_FATAL, + "%s: Failed attach target", __func__); + goto err_sme_stop; + } + + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO, + "TL correctly started"); + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO, + "%s: CDS Start is successful!!", __func__); + + return QDF_STATUS_SUCCESS; + +err_sme_stop: + sme_stop(p_cds_context->pMACContext, HAL_STOP_TYPE_SYS_RESET); + +err_mac_stop: + mac_stop(p_cds_context->pMACContext, HAL_STOP_TYPE_SYS_RESET); + +err_wma_stop: + qdf_event_reset(&(gp_cds_context->wmaCompleteEvent)); + qdf_status = wma_stop(p_cds_context, HAL_STOP_TYPE_RF_KILL); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: Failed to stop wma", __func__); + QDF_ASSERT(QDF_IS_STATUS_SUCCESS(qdf_status)); + wma_setneedshutdown(cds_context); + } else { + qdf_status = + qdf_wait_single_event(&(gp_cds_context->wmaCompleteEvent), + CDS_WMA_TIMEOUT); + if (qdf_status != QDF_STATUS_SUCCESS) { + if (qdf_status == QDF_STATUS_E_TIMEOUT) { + QDF_TRACE(QDF_MODULE_ID_QDF, + QDF_TRACE_LEVEL_FATAL, + "%s: Timeout occurred before WMA_stop complete", + __func__); + } else { + QDF_TRACE(QDF_MODULE_ID_QDF, + QDF_TRACE_LEVEL_FATAL, + "%s: WMA_stop reporting other error", + __func__); + } + QDF_ASSERT(0); + wma_setneedshutdown(cds_context); + } + } + + return QDF_STATUS_E_FAILURE; +} /* cds_enable() */ + +/** + * cds_disable() - stop/disable cds module + * @cds_context: CDS context + * + * Return: QDF status + */ +QDF_STATUS cds_disable(v_CONTEXT_t cds_context) +{ + QDF_STATUS qdf_status; + void *handle; + + qdf_status = wma_stop(cds_context, HAL_STOP_TYPE_RF_KILL); + + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + cds_err("Failed to stop wma"); + QDF_ASSERT(QDF_IS_STATUS_SUCCESS(qdf_status)); + wma_setneedshutdown(cds_context); + } + + handle = cds_get_context(QDF_MODULE_ID_PE); + if (!handle) { + cds_err("Invalid PE context return!"); + return QDF_STATUS_E_INVAL; + } + qdf_status = sme_stop(handle, HAL_STOP_TYPE_SYS_DEEP_SLEEP); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + cds_err("Failed to stop SME: %d", qdf_status); + QDF_ASSERT(QDF_IS_STATUS_SUCCESS(qdf_status)); + } + qdf_status = mac_stop(handle, HAL_STOP_TYPE_SYS_DEEP_SLEEP); + + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + cds_err("Failed to stop MAC"); + QDF_ASSERT(QDF_IS_STATUS_SUCCESS(qdf_status)); + } + + return qdf_status; +} + +#ifdef HIF_USB +static inline void cds_suspend_target(tp_wma_handle wma_handle) +{ + QDF_STATUS status; + /* Suspend the target and disable interrupt */ + status = wma_suspend_target(wma_handle, 0); + if (status) + cds_err("Failed to suspend target, status = %d", status); +} +#else +static inline void cds_suspend_target(tp_wma_handle wma_handle) +{ + QDF_STATUS status; + /* Suspend the target and disable interrupt */ + status = wma_suspend_target(wma_handle, 1); + if (status) + cds_err("Failed to suspend target, status = %d", status); +} +#endif /* HIF_USB */ + +/** + * cds_post_disable() - post disable cds module + * + * Return: QDF status + */ +QDF_STATUS cds_post_disable(void) +{ + tp_wma_handle wma_handle; + struct hif_opaque_softc *hif_ctx; + ol_txrx_pdev_handle txrx_pdev; + + wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma_handle) { + cds_err("Failed to get wma_handle!"); + return QDF_STATUS_E_INVAL; + } + + hif_ctx = cds_get_context(QDF_MODULE_ID_HIF); + if (!hif_ctx) { + cds_err("Failed to get hif_handle!"); + return QDF_STATUS_E_INVAL; + } + + txrx_pdev = cds_get_context(QDF_MODULE_ID_TXRX); + if (!txrx_pdev) { + cds_err("Failed to get txrx pdev!"); + return QDF_STATUS_E_INVAL; + } + + /* + * With new state machine changes cds_close can be invoked without + * cds_disable. So, send the following clean up prerequisites to fw, + * So Fw and host are in sync for cleanup indication: + * - Send PDEV_SUSPEND indication to firmware + * - Disable HIF Interrupts. + * - Clean up CE tasklets. + */ + + cds_info("send denint sequence to firmware"); + if (!cds_is_driver_recovering()) + cds_suspend_target(wma_handle); + hif_disable_isr(hif_ctx); + hif_reset_soc(hif_ctx); + + ol_txrx_pdev_pre_detach(txrx_pdev, 1); + + return QDF_STATUS_SUCCESS; +} + +/** + * cds_close() - close cds module + * @cds_context: CDS context + * + * This API allows user to close modules registered + * with connectivity device services. + * + * Return: QDF status + */ +QDF_STATUS cds_close(v_CONTEXT_t cds_context) +{ + QDF_STATUS qdf_status; + + qdf_status = wma_wmi_work_close(cds_context); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: Failed to close wma_wmi_work", __func__); + QDF_ASSERT(0); + } + + hdd_lro_destroy(); + + if (gp_cds_context->htc_ctx) { + htc_stop(gp_cds_context->htc_ctx); + htc_destroy(gp_cds_context->htc_ctx); + gp_cds_context->htc_ctx = NULL; + } + + ol_txrx_pdev_detach(gp_cds_context->pdev_txrx_ctx); + cds_free_context(cds_context, QDF_MODULE_ID_TXRX, + gp_cds_context->pdev_txrx_ctx); + + qdf_status = sme_close(((p_cds_contextType) cds_context)->pMACContext); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: Failed to close SME", __func__); + QDF_ASSERT(QDF_IS_STATUS_SUCCESS(qdf_status)); + } + + qdf_status = mac_close(((p_cds_contextType) cds_context)->pMACContext); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: Failed to close MAC", __func__); + QDF_ASSERT(QDF_IS_STATUS_SUCCESS(qdf_status)); + } + + ((p_cds_contextType) cds_context)->pMACContext = NULL; + + cds_shutdown_notifier_purge(); + + if (true == wma_needshutdown(cds_context)) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: Failed to shutdown wma", __func__); + } else { + qdf_status = wma_close(cds_context); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: Failed to close wma", __func__); + QDF_ASSERT(QDF_IS_STATUS_SUCCESS(qdf_status)); + } + } + + qdf_status = wma_wmi_service_close(cds_context); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: Failed to close wma_wmi_service", __func__); + QDF_ASSERT(QDF_IS_STATUS_SUCCESS(qdf_status)); + } + + cds_mq_deinit(&((p_cds_contextType) cds_context)->freeVosMq); + + qdf_status = qdf_event_destroy(&gp_cds_context->wmaCompleteEvent); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: failed to destroy wmaCompleteEvent", __func__); + QDF_ASSERT(QDF_IS_STATUS_SUCCESS(qdf_status)); + } + + qdf_status = qdf_event_destroy(&gp_cds_context->ProbeEvent); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: failed to destroy ProbeEvent", __func__); + QDF_ASSERT(QDF_IS_STATUS_SUCCESS(qdf_status)); + } + + if (!QDF_IS_STATUS_SUCCESS(qdf_mutex_destroy( + &gp_cds_context->qdf_conc_list_lock))) { + cds_err("Failed to destroy qdf_conc_list_lock"); + QDF_ASSERT(QDF_IS_STATUS_SUCCESS(qdf_status)); + } + + cds_deinit_ini_config(); + qdf_timer_module_deinit(); + + return QDF_STATUS_SUCCESS; +} + +/** + * cds_get_context() - get context data area + * + * @moduleId: ID of the module who's context data is being retrived. + * + * Each module in the system has a context / data area that is allocated + * and managed by CDS. This API allows any user to get a pointer to its + * allocated context data area from the CDS global context. + * + * Return: pointer to the context data area of the module ID + * specified, or NULL if the context data is not allocated for + * the module ID specified + */ +void *cds_get_context(QDF_MODULE_ID moduleId) +{ + void *pModContext = NULL; + + if (gp_cds_context == NULL) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: cds context pointer is null", __func__); + return NULL; + } + + switch (moduleId) { + case QDF_MODULE_ID_HDD: + { + pModContext = gp_cds_context->pHDDContext; + break; + } + + case QDF_MODULE_ID_SME: + case QDF_MODULE_ID_PE: + { + /* In all these cases, we just return the MAC Context */ + pModContext = gp_cds_context->pMACContext; + break; + } + + case QDF_MODULE_ID_WMA: + { + /* For wma module */ + pModContext = gp_cds_context->pWMAContext; + break; + } + + case QDF_MODULE_ID_QDF: + { + /* For SYS this is CDS itself */ + pModContext = gp_cds_context; + break; + } + + case QDF_MODULE_ID_HIF: + { + pModContext = gp_cds_context->pHIFContext; + break; + } + + case QDF_MODULE_ID_HTC: + { + pModContext = gp_cds_context->htc_ctx; + break; + } + + case QDF_MODULE_ID_QDF_DEVICE: + { + pModContext = gp_cds_context->qdf_ctx; + break; + } + + case QDF_MODULE_ID_BMI: + { + pModContext = gp_cds_context->g_ol_context; + break; + } + + case QDF_MODULE_ID_TXRX: + { + pModContext = gp_cds_context->pdev_txrx_ctx; + break; + } + + case QDF_MODULE_ID_CFG: + { + pModContext = gp_cds_context->cfg_ctx; + break; + } + + default: + { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: Module ID %i does not have its context maintained by CDS", + __func__, moduleId); + QDF_ASSERT(0); + return NULL; + } + } + + if (pModContext == NULL) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: Module ID %i context is Null", __func__, + moduleId); + } + + return pModContext; +} /* cds_get_context() */ + +/** + * cds_get_global_context() - get CDS global Context + * + * This API allows any user to get the CDS Global Context pointer from a + * module context data area. + * + * Return: pointer to the CDS global context, NULL if the function is + * unable to retreive the CDS context. + */ +v_CONTEXT_t cds_get_global_context(void) +{ + if (gp_cds_context == NULL) { + /* + * To avoid recursive call, this should not change to + * QDF_TRACE(). + */ + pr_err("%s: global cds context is NULL", __func__); + } + + return gp_cds_context; +} /* cds_get_global_context() */ + +/** + * cds_get_driver_state() - Get current driver state + * + * This API returns current driver state stored in global context. + * + * Return: Driver state enum + */ +enum cds_driver_state cds_get_driver_state(void) +{ + if (gp_cds_context == NULL) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: global cds context is NULL", __func__); + + return CDS_DRIVER_STATE_UNINITIALIZED; + } + + return gp_cds_context->driver_state; +} + +/** + * cds_set_driver_state() - Set current driver state + * @state: Driver state to be set to. + * + * This API sets driver state to state. This API only sets the state and doesn't + * clear states, please make sure to use cds_clear_driver_state to clear any + * state if required. + * + * Return: None + */ +void cds_set_driver_state(enum cds_driver_state state) +{ + if (gp_cds_context == NULL) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: global cds context is NULL: %x", __func__, + state); + + return; + } + + gp_cds_context->driver_state |= state; +} + +/** + * cds_clear_driver_state() - Clear current driver state + * @state: Driver state to be cleared. + * + * This API clears driver state. This API only clears the state, please make + * sure to use cds_set_driver_state to set any new states. + * + * Return: None + */ +void cds_clear_driver_state(enum cds_driver_state state) +{ + if (gp_cds_context == NULL) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: global cds context is NULL: %x", __func__, + state); + + return; + } + + gp_cds_context->driver_state &= ~state; +} + +/** + * cds_alloc_context() - allocate a context within the CDS global Context + * @p_cds_context: pointer to the global Vos context + * @moduleId: module ID who's context area is being allocated. + * @ppModuleContext: pointer to location where the pointer to the + * allocated context is returned. Note this output pointer + * is valid only if the API returns QDF_STATUS_SUCCESS + * @param size: size of the context area to be allocated. + * + * This API allows any user to allocate a user context area within the + * CDS Global Context. + * + * Return: QDF status + */ +QDF_STATUS cds_alloc_context(void *p_cds_context, QDF_MODULE_ID moduleID, + void **ppModuleContext, uint32_t size) +{ + void **pGpModContext = NULL; + + if (p_cds_context == NULL) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: cds context is null", __func__); + return QDF_STATUS_E_FAILURE; + } + + if ((gp_cds_context != p_cds_context) || (ppModuleContext == NULL)) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: context mismatch or null param passed", + __func__); + return QDF_STATUS_E_FAILURE; + } + + switch (moduleID) { + case QDF_MODULE_ID_WMA: + { + pGpModContext = &(gp_cds_context->pWMAContext); + break; + } + + case QDF_MODULE_ID_HIF: + { + pGpModContext = &(gp_cds_context->pHIFContext); + break; + } + + case QDF_MODULE_ID_BMI: + { + pGpModContext = &(gp_cds_context->g_ol_context); + break; + } + + case QDF_MODULE_ID_EPPING: + case QDF_MODULE_ID_SME: + case QDF_MODULE_ID_PE: + case QDF_MODULE_ID_HDD: + case QDF_MODULE_ID_HDD_SOFTAP: + default: + { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: Module ID %i " + "does not have its context allocated by CDS", + __func__, moduleID); + QDF_ASSERT(0); + return QDF_STATUS_E_INVAL; + } + } + + if (NULL != *pGpModContext) { + /* Context has already been allocated! + * Prevent double allocation + */ + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: Module ID %i context has already been allocated", + __func__, moduleID); + return QDF_STATUS_E_EXISTS; + } + + /* Dynamically allocate the context for module */ + + *ppModuleContext = qdf_mem_malloc(size); + + if (*ppModuleContext == NULL) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: Failed to " "allocate Context for module ID %i", + __func__, moduleID); + QDF_ASSERT(0); + return QDF_STATUS_E_NOMEM; + } + + *pGpModContext = *ppModuleContext; + + return QDF_STATUS_SUCCESS; +} /* cds_alloc_context() */ + +/** + * cds_set_context() - API to set context in global CDS Context + * @module_id: Module ID + * @context: Pointer to the Module Context + * + * API to set a MODULE Context in global CDS Context + * + * Return: QDF_STATUS + */ +QDF_STATUS cds_set_context(QDF_MODULE_ID module_id, void *context) +{ + p_cds_contextType p_cds_context = cds_get_global_context(); + + if (!p_cds_context) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "cds context is Invalid"); + return QDF_STATUS_NOT_INITIALIZED; + } + + switch (module_id) { + case QDF_MODULE_ID_HIF: + p_cds_context->pHIFContext = context; + break; + default: + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: Module ID %i does not have its context managed by CDS", + __func__, module_id); + QDF_ASSERT(0); + return QDF_STATUS_E_INVAL; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * cds_free_context() - free an allocated context within the + * CDS global Context + * @p_cds_context: pointer to the global Vos context + * @moduleId: module ID who's context area is being free + * @pModuleContext: pointer to module context area to be free'd. + * + * This API allows a user to free the user context area within the + * CDS Global Context. + * + * Return: QDF status + */ +QDF_STATUS cds_free_context(void *p_cds_context, QDF_MODULE_ID moduleID, + void *pModuleContext) +{ + void **pGpModContext = NULL; + + if ((p_cds_context == NULL) || (gp_cds_context != p_cds_context) || + (pModuleContext == NULL)) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: Null params or context mismatch", __func__); + return QDF_STATUS_E_FAILURE; + } + + switch (moduleID) { + case QDF_MODULE_ID_WMA: + { + pGpModContext = &(gp_cds_context->pWMAContext); + break; + } + + case QDF_MODULE_ID_HIF: + { + pGpModContext = &(gp_cds_context->pHIFContext); + break; + } + + case QDF_MODULE_ID_TXRX: + { + pGpModContext = &(gp_cds_context->pdev_txrx_ctx); + break; + } + + case QDF_MODULE_ID_BMI: + { + pGpModContext = &(gp_cds_context->g_ol_context); + break; + } + + case QDF_MODULE_ID_EPPING: + case QDF_MODULE_ID_HDD: + case QDF_MODULE_ID_SME: + case QDF_MODULE_ID_PE: + case QDF_MODULE_ID_HDD_SOFTAP: + default: + { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: Module ID %i " + "does not have its context allocated by CDS", + __func__, moduleID); + QDF_ASSERT(0); + return QDF_STATUS_E_INVAL; + } + } + + if (NULL == *pGpModContext) { + /* Context has not been allocated or freed already! */ + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: Module ID %i " + "context has not been allocated or freed already", + __func__, moduleID); + return QDF_STATUS_E_FAILURE; + } + + if (*pGpModContext != pModuleContext) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: pGpModContext != pModuleContext", __func__); + return QDF_STATUS_E_FAILURE; + } + + if (pModuleContext != NULL) + qdf_mem_free(pModuleContext); + + *pGpModContext = NULL; + + return QDF_STATUS_SUCCESS; +} /* cds_free_context() */ + +/** + * cds_mq_post_message_by_priority() - posts message using priority + * to message queue + * @msgQueueId: message queue id + * @pMsg: message to be posted + * @is_high_priority: wheather message is high priority + * + * This function is used to post high priority message to message queue + * + * Return: QDF_STATUS_SUCCESS on success + * QDF_STATUS_E_FAILURE on failure + * QDF_STATUS_E_RESOURCES on resource allocation failure + */ +QDF_STATUS cds_mq_post_message_by_priority(CDS_MQ_ID msgQueueId, + cds_msg_t *pMsg, + int is_high_priority) +{ + p_cds_mq_type pTargetMq = NULL; + p_cds_msg_wrapper pMsgWrapper = NULL; + uint32_t debug_count = 0; + + if (!pMsg) { + cds_err("pMsg is null"); + return QDF_STATUS_E_INVAL; + } + + if (!gp_cds_context) { + cds_err("gp_cds_context is null"); + return QDF_STATUS_E_INVAL; + } + + if (!gp_cds_sched_context) { + cds_err("gp_cds_sched_context is null"); + return QDF_STATUS_E_INVAL; + } + + if (!gp_cds_sched_context->McThread) { + cds_err("Cannot post message because MC thread is stopped"); + return QDF_STATUS_E_FAILURE; + } + + switch (msgQueueId) { + /* Message Queue ID for messages bound for SME */ + case CDS_MQ_ID_SME: + { + pTargetMq = &(gp_cds_context->qdf_sched.smeMcMq); + break; + } + + /* Message Queue ID for messages bound for PE */ + case CDS_MQ_ID_PE: + { + pTargetMq = &(gp_cds_context->qdf_sched.peMcMq); + break; + } + + /* Message Queue ID for messages bound for wma */ + case CDS_MQ_ID_WMA: + { + pTargetMq = &(gp_cds_context->qdf_sched.wmaMcMq); + break; + } + + /* Message Queue ID for messages bound for the SYS module */ + case CDS_MQ_ID_SYS: + { + pTargetMq = &(gp_cds_context->qdf_sched.sysMcMq); + break; + } + + default: + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + ("%s: Trying to queue msg into unknown MC Msg queue ID %d"), + __func__, msgQueueId); + + return QDF_STATUS_E_FAILURE; + } + + QDF_ASSERT(NULL != pTargetMq); + if (pTargetMq == NULL) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: pTargetMq == NULL", __func__); + return QDF_STATUS_E_FAILURE; + } + + /* Try and get a free Msg wrapper */ + pMsgWrapper = cds_mq_get(&gp_cds_context->freeVosMq); + + if (NULL == pMsgWrapper) { + debug_count = atomic_inc_return(&cds_wrapper_empty_count); + if (1 == debug_count) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: CDS Core run out of message wrapper %d", + __func__, debug_count); + cds_flush_logs(WLAN_LOG_TYPE_FATAL, + WLAN_LOG_INDICATOR_HOST_ONLY, + WLAN_LOG_REASON_VOS_MSG_UNDER_RUN, + true, false); + } + if (CDS_WRAPPER_MAX_FAIL_COUNT == debug_count) + QDF_BUG(0); + + return QDF_STATUS_E_RESOURCES; + } + + atomic_set(&cds_wrapper_empty_count, 0); + + /* Copy the message now */ + qdf_mem_copy((void *)pMsgWrapper->pVosMsg, + (void *)pMsg, sizeof(cds_msg_t)); + + if (is_high_priority) + cds_mq_put_front(pTargetMq, pMsgWrapper); + else + cds_mq_put(pTargetMq, pMsgWrapper); + + set_bit(MC_POST_EVENT, &gp_cds_context->qdf_sched.mcEventFlag); + wake_up_interruptible(&gp_cds_context->qdf_sched.mcWaitQueue); + + return QDF_STATUS_SUCCESS; +} /* cds_mq_post_message() */ + +/** + * cds_sys_probe_thread_cback() - probe mc thread callback + * @pUserData: pointer to user data + * + * Return: none + */ +void cds_sys_probe_thread_cback(void *pUserData) +{ + if (gp_cds_context != pUserData) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: gp_cds_context != pUserData", __func__); + return; + } + + if (qdf_event_set(&gp_cds_context->ProbeEvent) != QDF_STATUS_SUCCESS) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: qdf_event_set failed", __func__); + return; + } +} /* cds_sys_probe_thread_cback() */ + +/** + * cds_wma_complete_cback() - wma complete callback + * @pUserData: pointer to user data + * + * Return: none + */ +void cds_wma_complete_cback(void *pUserData) +{ + if (gp_cds_context != pUserData) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: gp_cds_context != pUserData", __func__); + return; + } + + if (qdf_event_set(&gp_cds_context->wmaCompleteEvent) != + QDF_STATUS_SUCCESS) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: qdf_event_set failed", __func__); + return; + } +} /* cds_wma_complete_cback() */ + +/** + * cds_core_return_msg() - return core message + * @pVContext: pointer to cds context + * @pMsgWrapper: pointer to message wrapper + * + * Return: none + */ +void cds_core_return_msg(void *pVContext, p_cds_msg_wrapper pMsgWrapper) +{ + p_cds_contextType p_cds_context = (p_cds_contextType) pVContext; + + QDF_ASSERT(gp_cds_context == p_cds_context); + + if (gp_cds_context != p_cds_context) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: gp_cds_context != p_cds_context", __func__); + return; + } + + QDF_ASSERT(NULL != pMsgWrapper); + + if (pMsgWrapper == NULL) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: pMsgWrapper == NULL in function", __func__); + return; + } + + /* + ** Return the message on the free message queue + */ + INIT_LIST_HEAD(&pMsgWrapper->msgNode); + cds_mq_put(&p_cds_context->freeVosMq, pMsgWrapper); +} /* cds_core_return_msg() */ + +/** + * cds_get_vdev_types() - get vdev type + * @mode: mode + * @type: type + * @sub_type: sub_type + * + * Return: WMI vdev type + */ +QDF_STATUS cds_get_vdev_types(enum tQDF_ADAPTER_MODE mode, uint32_t *type, + uint32_t *sub_type) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + *type = 0; + *sub_type = 0; + + switch (mode) { + case QDF_STA_MODE: + *type = WMI_VDEV_TYPE_STA; + break; + case QDF_SAP_MODE: + *type = WMI_VDEV_TYPE_AP; + break; + case QDF_P2P_DEVICE_MODE: + *type = WMI_VDEV_TYPE_AP; + *sub_type = WMI_UNIFIED_VDEV_SUBTYPE_P2P_DEVICE; + break; + case QDF_P2P_CLIENT_MODE: + *type = WMI_VDEV_TYPE_STA; + *sub_type = WMI_UNIFIED_VDEV_SUBTYPE_P2P_CLIENT; + break; + case QDF_P2P_GO_MODE: + *type = WMI_VDEV_TYPE_AP; + *sub_type = WMI_UNIFIED_VDEV_SUBTYPE_P2P_GO; + break; + case QDF_OCB_MODE: + *type = WMI_VDEV_TYPE_OCB; + break; + case QDF_IBSS_MODE: + *type = WMI_VDEV_TYPE_IBSS; + break; + case QDF_MONITOR_MODE: + *type = WMI_VDEV_TYPE_MONITOR; + break; + case QDF_NDI_MODE: + *type = WMI_VDEV_TYPE_NDI; + break; + default: + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "Invalid device mode %d", mode); + status = QDF_STATUS_E_INVAL; + break; + } + return status; +} + +/** + * cds_flush_work() - flush pending works + * @work: pointer to work + * + * Return: none + */ +void cds_flush_work(void *work) +{ + cancel_work_sync(work); +} + +/** + * cds_flush_delayed_work() - flush delayed works + * @dwork: pointer to delayed work + * + * Return: none + */ +void cds_flush_delayed_work(void *dwork) +{ + cancel_delayed_work_sync(dwork); +} + +/** + * cds_is_packet_log_enabled() - check if packet log is enabled + * + * Return: true if packet log is enabled else false + */ +bool cds_is_packet_log_enabled(void) +{ + hdd_context_t *pHddCtx; + + pHddCtx = (hdd_context_t *) (gp_cds_context->pHDDContext); + if ((NULL == pHddCtx) || (NULL == pHddCtx->config)) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_FATAL, + "%s: Hdd Context is Null", __func__); + return false; + } + + return pHddCtx->config->enablePacketLog; +} + +#ifdef QCA_WIFI_3_0_ADRASTEA +/** + * cds_force_assert_target() - Force target assert via platform + * driver + * @qdf_ctx: pointer of qdf context + * + * For ADRASTREA chipsets target assert is supported via platform driver, + * for ROME chipsets control of self-recovery is with the hostdriver. + * + * Return: QDF_STATUS_SUCCESS if target assert through firmware is supported + * QDF_STATUS_E_INVAL if targer assert through firmware failed + * QDF_STATUS_E_NOSUPPORT if not supported for target + */ +static QDF_STATUS cds_force_assert_target(qdf_device_t qdf_ctx) +{ + + cds_set_recovery_in_progress(true); + /* + * If force assert thru platform is available, trigger that interface. + * That should generate recovery by going thru the normal FW + * assert recovery model. + */ + if (!pld_force_assert_target(qdf_ctx->dev)) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO_HIGH, + "Force assert triggered"); + return QDF_STATUS_SUCCESS; + } + + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "Self Recovery not supported via Platform driver assert"); + + cds_set_recovery_in_progress(false); + QDF_BUG(0); + + return QDF_STATUS_E_INVAL; +} + +#else +static QDF_STATUS cds_force_assert_target(qdf_device_t qdf_ctx) +{ + return QDF_STATUS_E_NOSUPPORT; +} +#endif + +/** + * cds_config_recovery_work() - configure self recovery + * @qdf_ctx: pointer of qdf context + * + * Return: none + */ + +static void cds_config_recovery_work(qdf_device_t qdf_ctx) +{ + if (cds_is_driver_recovering()) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "Recovery is in progress, ignore!"); + } else { + cds_set_recovery_in_progress(true); + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "schedule recovery work!"); + pld_schedule_recovery_work(qdf_ctx->dev); + } +} + +/** + * cds_trigger_recovery() - trigger self recovery + * @skip_crash_inject: Boolean value to skip to send crash inject cmd + * + * Return: none + */ +void cds_trigger_recovery(bool skip_crash_inject) +{ + tp_wma_handle wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + QDF_STATUS status = QDF_STATUS_SUCCESS; + qdf_runtime_lock_t recovery_lock; + qdf_device_t qdf_ctx = cds_get_context(QDF_MODULE_ID_QDF_DEVICE); + + if (!wma_handle) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "WMA context is invalid!"); + return; + } + if (!qdf_ctx) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "QDF context is invalid!"); + return; + } + + status = qdf_runtime_lock_init(&recovery_lock); + if (QDF_STATUS_SUCCESS != status) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "Could not acquire runtime pm lock: %d!", status); + return; + } + + qdf_runtime_pm_prevent_suspend(&recovery_lock); + + if (QDF_STATUS_E_NOSUPPORT != cds_force_assert_target(qdf_ctx)) + goto out; + + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO_HIGH, + "Force assert not available at platform"); + + if (!skip_crash_inject) { + + wma_crash_inject(wma_handle, RECOVERY_SIM_SELF_RECOVERY, 0); + status = qdf_wait_single_event(&wma_handle->recovery_event, + WMA_CRASH_INJECT_TIMEOUT); + + if (QDF_STATUS_SUCCESS != status) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "CRASH_INJECT command is timed out!"); + cds_config_recovery_work(qdf_ctx); + } + } else { + cds_config_recovery_work(qdf_ctx); + } + +out: + qdf_runtime_pm_allow_suspend(&recovery_lock); + qdf_runtime_lock_deinit(&recovery_lock); +} + +/** + * cds_get_monotonic_boottime() - Get kernel boot time. + * + * Return: Time in microseconds + */ + +uint64_t cds_get_monotonic_boottime(void) +{ + struct timespec ts; + + get_monotonic_boottime(&ts); + return ((uint64_t) ts.tv_sec * 1000000) + (ts.tv_nsec / 1000); +} + +/** + * cds_set_wakelock_logging() - Logging of wakelock enabled/disabled + * @value: Boolean value + * + * This function is used to set the flag which will indicate whether + * logging of wakelock is enabled or not + * + * Return: None + */ +void cds_set_wakelock_logging(bool value) +{ + p_cds_contextType p_cds_context; + + p_cds_context = cds_get_global_context(); + if (!p_cds_context) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "cds context is Invald"); + return; + } + p_cds_context->is_wakelock_log_enabled = value; +} + +/** + * cds_is_wakelock_enabled() - Check if logging of wakelock is enabled/disabled + * @value: Boolean value + * + * This function is used to check whether logging of wakelock is enabled or not + * + * Return: true if logging of wakelock is enabled + */ +bool cds_is_wakelock_enabled(void) +{ + p_cds_contextType p_cds_context; + + p_cds_context = cds_get_global_context(); + if (!p_cds_context) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "cds context is Invald"); + return false; + } + return p_cds_context->is_wakelock_log_enabled; +} + +/** + * cds_set_ring_log_level() - Sets the log level of a particular ring + * @ring_id: ring_id + * @log_levelvalue: Log level specificed + * + * This function converts HLOS values to driver log levels and sets the log + * level of a particular ring accordingly. + * + * Return: None + */ +void cds_set_ring_log_level(uint32_t ring_id, uint32_t log_level) +{ + p_cds_contextType p_cds_context; + uint32_t log_val; + + p_cds_context = cds_get_global_context(); + if (!p_cds_context) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: cds context is Invald", __func__); + return; + } + + switch (log_level) { + case LOG_LEVEL_NO_COLLECTION: + log_val = WLAN_LOG_LEVEL_OFF; + break; + case LOG_LEVEL_NORMAL_COLLECT: + log_val = WLAN_LOG_LEVEL_NORMAL; + break; + case LOG_LEVEL_ISSUE_REPRO: + log_val = WLAN_LOG_LEVEL_REPRO; + break; + case LOG_LEVEL_ACTIVE: + default: + log_val = WLAN_LOG_LEVEL_ACTIVE; + break; + } + + if (ring_id == RING_ID_WAKELOCK) { + p_cds_context->wakelock_log_level = log_val; + return; + } else if (ring_id == RING_ID_CONNECTIVITY) { + p_cds_context->connectivity_log_level = log_val; + return; + } else if (ring_id == RING_ID_PER_PACKET_STATS) { + p_cds_context->packet_stats_log_level = log_val; + return; + } else if (ring_id == RING_ID_DRIVER_DEBUG) { + p_cds_context->driver_debug_log_level = log_val; + return; + } else if (ring_id == RING_ID_FIRMWARE_DEBUG) { + p_cds_context->fw_debug_log_level = log_val; + return; + } +} + +/** + * cds_get_ring_log_level() - Get the a ring id's log level + * @ring_id: Ring id + * + * Fetch and return the log level corresponding to a ring id + * + * Return: Log level corresponding to the ring ID + */ +enum wifi_driver_log_level cds_get_ring_log_level(uint32_t ring_id) +{ + p_cds_contextType p_cds_context; + + p_cds_context = cds_get_global_context(); + if (!p_cds_context) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: cds context is Invald", __func__); + return WLAN_LOG_LEVEL_OFF; + } + + if (ring_id == RING_ID_WAKELOCK) + return p_cds_context->wakelock_log_level; + else if (ring_id == RING_ID_CONNECTIVITY) + return p_cds_context->connectivity_log_level; + else if (ring_id == RING_ID_PER_PACKET_STATS) + return p_cds_context->packet_stats_log_level; + else if (ring_id == RING_ID_DRIVER_DEBUG) + return p_cds_context->driver_debug_log_level; + else if (ring_id == RING_ID_FIRMWARE_DEBUG) + return p_cds_context->fw_debug_log_level; + + return WLAN_LOG_LEVEL_OFF; +} + +/** + * cds_set_multicast_logging() - Set mutlicast logging value + * @value: Value of multicast logging + * + * Set the multicast logging value which will indicate + * whether to multicast host and fw messages even + * without any registration by userspace entity + * + * Return: None + */ +void cds_set_multicast_logging(uint8_t value) +{ + cds_multicast_logging = value; +} + +/** + * cds_is_multicast_logging() - Get multicast logging value + * + * Get the multicast logging value which will indicate + * whether to multicast host and fw messages even + * without any registration by userspace entity + * + * Return: 0 - Multicast logging disabled, 1 - Multicast logging enabled + */ +uint8_t cds_is_multicast_logging(void) +{ + return cds_multicast_logging; +} + +static void cds_reset_log_completion(p_cds_contextType p_cds_context) +{ + /* reset */ + p_cds_context->log_complete.indicator = WLAN_LOG_INDICATOR_UNUSED; + p_cds_context->log_complete.is_fatal = WLAN_LOG_TYPE_NON_FATAL; + p_cds_context->log_complete.is_report_in_progress = false; + p_cds_context->log_complete.reason_code = WLAN_LOG_REASON_CODE_UNUSED; + p_cds_context->log_complete.recovery_needed = false; + +} +/* + * cds_init_log_completion() - Initialize log param structure + * + * This function is used to initialize the logging related + * parameters + * + * Return: None + */ +void cds_init_log_completion(void) +{ + p_cds_contextType p_cds_context; + + p_cds_context = cds_get_global_context(); + if (!p_cds_context) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: cds context is Invalid", __func__); + return; + } + + p_cds_context->log_complete.is_fatal = WLAN_LOG_TYPE_NON_FATAL; + p_cds_context->log_complete.indicator = WLAN_LOG_INDICATOR_UNUSED; + p_cds_context->log_complete.reason_code = WLAN_LOG_REASON_CODE_UNUSED; + p_cds_context->log_complete.is_report_in_progress = false; +} + +/** + * cds_set_log_completion() - Store the logging params + * @is_fatal: Indicates if the event triggering bug report is fatal or not + * @indicator: Source which trigerred the bug report + * @reason_code: Reason for triggering bug report + * @recovery_needed: If recovery is needed after bug report + * + * This function is used to set the logging parameters based on the + * caller + * + * Return: 0 if setting of params is successful + */ +QDF_STATUS cds_set_log_completion(uint32_t is_fatal, + uint32_t indicator, + uint32_t reason_code, + bool recovery_needed) +{ + p_cds_contextType p_cds_context; + + p_cds_context = cds_get_global_context(); + if (!p_cds_context) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: cds context is Invalid", __func__); + return QDF_STATUS_E_FAILURE; + } + + qdf_spinlock_acquire(&p_cds_context->bug_report_lock); + p_cds_context->log_complete.is_fatal = is_fatal; + p_cds_context->log_complete.indicator = indicator; + p_cds_context->log_complete.reason_code = reason_code; + p_cds_context->log_complete.recovery_needed = recovery_needed; + p_cds_context->log_complete.is_report_in_progress = true; + qdf_spinlock_release(&p_cds_context->bug_report_lock); + return QDF_STATUS_SUCCESS; +} + +/** + * cds_get_and_reset_log_completion() - Get and reset logging related params + * @is_fatal: Indicates if the event triggering bug report is fatal or not + * @indicator: Source which trigerred the bug report + * @reason_code: Reason for triggering bug report + * @recovery_needed: If recovery is needed after bug report + * + * This function is used to get the logging related parameters + * + * Return: None + */ +void cds_get_and_reset_log_completion(uint32_t *is_fatal, + uint32_t *indicator, + uint32_t *reason_code, + bool *recovery_needed) +{ + p_cds_contextType p_cds_context; + + p_cds_context = cds_get_global_context(); + if (!p_cds_context) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: cds context is Invalid", __func__); + return; + } + + qdf_spinlock_acquire(&p_cds_context->bug_report_lock); + *is_fatal = p_cds_context->log_complete.is_fatal; + *indicator = p_cds_context->log_complete.indicator; + *reason_code = p_cds_context->log_complete.reason_code; + *recovery_needed = p_cds_context->log_complete.recovery_needed; + cds_reset_log_completion(p_cds_context); + qdf_spinlock_release(&p_cds_context->bug_report_lock); + +} + +/** + * cds_is_log_report_in_progress() - Check if bug reporting is in progress + * + * This function is used to check if the bug reporting is already in progress + * + * Return: true if the bug reporting is in progress + */ +bool cds_is_log_report_in_progress(void) +{ + p_cds_contextType p_cds_context; + + p_cds_context = cds_get_global_context(); + if (!p_cds_context) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: cds context is Invalid", __func__); + return true; + } + return p_cds_context->log_complete.is_report_in_progress; +} + +/** + * cds_is_fatal_event_enabled() - Return if fatal event is enabled + * + * Return true if fatal event is enabled. + */ +bool cds_is_fatal_event_enabled(void) +{ + p_cds_contextType p_cds_context; + + p_cds_context = cds_get_global_context(); + if (!p_cds_context) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: cds context is Invalid", __func__); + return false; + } + + + return p_cds_context->enable_fatal_event; +} + +/** + * cds_get_log_indicator() - Get the log flush indicator + * + * This function is used to get the log flush indicator + * + * Return: log indicator + */ +uint32_t cds_get_log_indicator(void) +{ + p_cds_contextType p_cds_context; + uint32_t indicator; + + p_cds_context = cds_get_global_context(); + if (!p_cds_context) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: cds context is Invalid", __func__); + return WLAN_LOG_INDICATOR_UNUSED; + } + + if (cds_is_load_or_unload_in_progress() || + cds_is_driver_recovering()) { + return WLAN_LOG_INDICATOR_UNUSED; + } + + qdf_spinlock_acquire(&p_cds_context->bug_report_lock); + indicator = p_cds_context->log_complete.indicator; + qdf_spinlock_release(&p_cds_context->bug_report_lock); + return indicator; +} + +/** + * cds_wlan_flush_host_logs_for_fatal() - Wrapper to flush host logs + * + * This function is used to send signal to the logger thread to + * flush the host logs. + * + * Return: None + * + */ +void cds_wlan_flush_host_logs_for_fatal(void) +{ + wlan_flush_host_logs_for_fatal(); +} + +/** + * cds_flush_logs() - Report fatal event to userspace + * @is_fatal: Indicates if the event triggering bug report is fatal or not + * @indicator: Source which trigerred the bug report + * @reason_code: Reason for triggering bug report + * @dump_mac_trace: If mac trace are needed in logs. + * @recovery_needed: If recovery is needed after bug report + * + * This function sets the log related params and send the WMI command to the + * FW to flush its logs. On receiving the flush completion event from the FW + * the same will be conveyed to userspace + * + * Return: 0 on success + */ +QDF_STATUS cds_flush_logs(uint32_t is_fatal, + uint32_t indicator, + uint32_t reason_code, + bool dump_mac_trace, + bool recovery_needed) +{ + uint32_t ret; + QDF_STATUS status; + + p_cds_contextType p_cds_context; + + p_cds_context = cds_get_global_context(); + if (!p_cds_context) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: cds context is Invalid", __func__); + return QDF_STATUS_E_FAILURE; + } + if (!p_cds_context->enable_fatal_event) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: Fatal event not enabled", __func__); + return QDF_STATUS_E_FAILURE; + } + if (cds_is_load_or_unload_in_progress() || + cds_is_driver_recovering()) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: un/Load/SSR in progress", __func__); + return QDF_STATUS_E_FAILURE; + } + + if (cds_is_log_report_in_progress() == true) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: Bug report already in progress - dropping! type:%d, indicator=%d reason_code=%d", + __func__, is_fatal, indicator, reason_code); + return QDF_STATUS_E_FAILURE; + } + + status = cds_set_log_completion(is_fatal, indicator, + reason_code, recovery_needed); + if (QDF_STATUS_SUCCESS != status) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: Failed to set log trigger params", __func__); + return QDF_STATUS_E_FAILURE; + } + + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: Triggering bug report: type:%d, indicator=%d reason_code=%d", + __func__, is_fatal, indicator, reason_code); + + if (dump_mac_trace) + qdf_trace_dump_all(p_cds_context->pMACContext, 0, 0, 500, 0); + + if (WLAN_LOG_INDICATOR_HOST_ONLY == indicator) { + cds_wlan_flush_host_logs_for_fatal(); + return QDF_STATUS_SUCCESS; + } + + ret = sme_send_flush_logs_cmd_to_fw(p_cds_context->pMACContext); + if (0 != ret) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: Failed to send flush FW log", __func__); + cds_reset_log_completion(p_cds_context); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * cds_logging_set_fw_flush_complete() - Wrapper for FW log flush completion + * + * This function is used to send signal to the logger thread to indicate + * that the flushing of FW logs is complete by the FW + * + * Return: None + * + */ +void cds_logging_set_fw_flush_complete(void) +{ + wlan_logging_set_fw_flush_complete(); +} + +/** + * cds_set_fatal_event() - set fatal event status + * @value: pending statue to set + * + * Return: None + */ +void cds_set_fatal_event(bool value) +{ + p_cds_contextType p_cds_context; + + p_cds_context = cds_get_global_context(); + if (!p_cds_context) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: cds context is Invalid", __func__); + return; + } + p_cds_context->enable_fatal_event = value; +} + +/** + * cds_get_radio_index() - get radio index + * + * Return: radio index otherwise, -EINVAL + */ +int cds_get_radio_index(void) +{ + p_cds_contextType p_cds_context; + + p_cds_context = cds_get_global_context(); + if (!p_cds_context) { + /* + * To avoid recursive call, this should not change to + * QDF_TRACE(). + */ + pr_err("%s: cds context is invalid\n", __func__); + return -EINVAL; + } + + return p_cds_context->radio_index; +} + +/** + * cds_set_radio_index() - set radio index + * @radio_index: the radio index to set + * + * Return: QDF status + */ +QDF_STATUS cds_set_radio_index(int radio_index) +{ + p_cds_contextType p_cds_context; + + p_cds_context = cds_get_global_context(); + if (!p_cds_context) { + pr_err("%s: cds context is invalid\n", __func__); + return QDF_STATUS_E_FAILURE; + } + + p_cds_context->radio_index = radio_index; + + return QDF_STATUS_SUCCESS; +} + +/** + * cds_init_ini_config() - API to initialize CDS configuration parameters + * @cfg: CDS Configuration + * + * Return: void + */ + +void cds_init_ini_config(struct cds_config_info *cfg) +{ + cds_context_type *cds_ctx; + + cds_ctx = cds_get_context(QDF_MODULE_ID_QDF); + if (!cds_ctx) { + cds_err("Invalid CDS Context"); + return; + } + + cds_ctx->cds_cfg = cfg; +} + +/** + * cds_deinit_ini_config() - API to free CDS configuration parameters + * + * Return: void + */ +void cds_deinit_ini_config(void) +{ + cds_context_type *cds_ctx; + + cds_ctx = cds_get_context(QDF_MODULE_ID_QDF); + if (!cds_ctx) { + cds_err("Invalid CDS Context"); + return; + } + + if (cds_ctx->cds_cfg) + qdf_mem_free(cds_ctx->cds_cfg); + + cds_ctx->cds_cfg = NULL; +} + +/** + * cds_get_ini_config() - API to get CDS configuration parameters + * + * Return: cds config structure + */ +struct cds_config_info *cds_get_ini_config(void) +{ + cds_context_type *cds_ctx; + + cds_ctx = cds_get_context(QDF_MODULE_ID_QDF); + if (!cds_ctx) { + cds_err("Invalid CDS Context"); + return NULL; + } + + return cds_ctx->cds_cfg; +} + +/** + * cds_is_5_mhz_enabled() - API to get 5MHZ enabled + * + * Return: true if 5 mhz is enabled, false otherwise + */ +bool cds_is_5_mhz_enabled(void) +{ + p_cds_contextType p_cds_context; + + p_cds_context = cds_get_context(QDF_MODULE_ID_QDF); + if (!p_cds_context) { + cds_err("%s: cds context is invalid", __func__); + return false; + } + + if (p_cds_context->cds_cfg) + return (p_cds_context->cds_cfg->sub_20_channel_width == + WLAN_SUB_20_CH_WIDTH_5); + + return false; +} + +/** + * cds_is_10_mhz_enabled() - API to get 10-MHZ enabled + * + * Return: true if 10 mhz is enabled, false otherwise + */ +bool cds_is_10_mhz_enabled(void) +{ + p_cds_contextType p_cds_context; + + p_cds_context = cds_get_context(QDF_MODULE_ID_QDF); + if (!p_cds_context) { + cds_err("%s: cds context is invalid", __func__); + return false; + } + + if (p_cds_context->cds_cfg) + return (p_cds_context->cds_cfg->sub_20_channel_width == + WLAN_SUB_20_CH_WIDTH_10); + + return false; +} + +/** + * cds_is_sub_20_mhz_enabled() - API to get sub 20-MHZ enabled + * + * Return: true if 5 or 10 mhz is enabled, false otherwise + */ +bool cds_is_sub_20_mhz_enabled(void) +{ + p_cds_contextType p_cds_context; + + p_cds_context = cds_get_context(QDF_MODULE_ID_QDF); + if (!p_cds_context) { + cds_err("%s: cds context is invalid", __func__); + return false; + } + + if (p_cds_context->cds_cfg) + return p_cds_context->cds_cfg->sub_20_channel_width; + + return false; +} + +/** + * cds_is_self_recovery_enabled() - API to get self recovery enabled + * + * Return: true if self recovery enabled, false otherwise + */ +bool cds_is_self_recovery_enabled(void) +{ + p_cds_contextType p_cds_context; + + p_cds_context = cds_get_context(QDF_MODULE_ID_QDF); + if (!p_cds_context) { + cds_err("%s: cds context is invalid", __func__); + return false; + } + + if (p_cds_context->cds_cfg) + return p_cds_context->cds_cfg->self_recovery_enabled; + + return false; +} + +/** + * cds_svc_fw_shutdown_ind() - API to send userspace about FW crash + * + * @dev: Device Pointer + * + * Return: None + */ +void cds_svc_fw_shutdown_ind(struct device *dev) +{ + hdd_svc_fw_shutdown_ind(dev); +} + +/* + * cds_pkt_stats_to_logger_thread() - send pktstats to user + * @pl_hdr: Pointer to pl_hdr + * @pkt_dump: Pointer to pkt_dump data structure. + * @data: Pointer to data + * + * This function is used to send the pkt stats to SVC module. + * + * Return: None + */ +inline void cds_pkt_stats_to_logger_thread(void *pl_hdr, void *pkt_dump, + void *data) +{ + if (cds_get_ring_log_level(RING_ID_PER_PACKET_STATS) != + WLAN_LOG_LEVEL_ACTIVE) + return; + + wlan_pkt_stats_to_logger_thread(pl_hdr, pkt_dump, data); +} + +/** + * cds_register_dp_cb() - Register datapath callbacks with CDS + * @dp_cbs: pointer to cds_dp_cbacks structure + * + * Return: QDF_STATUS + */ +QDF_STATUS cds_register_dp_cb(struct cds_dp_cbacks *dp_cbs) +{ + p_cds_contextType cds_ctx; + + cds_ctx = cds_get_global_context(); + if (!cds_ctx) { + cds_err("Invalid CDS context"); + return QDF_STATUS_E_FAILURE; + } + + cds_ctx->ol_txrx_update_mac_id_cb = dp_cbs->ol_txrx_update_mac_id_cb; + cds_ctx->hdd_en_lro_in_cc_cb = dp_cbs->hdd_en_lro_in_cc_cb; + cds_ctx->hdd_disable_lro_in_cc_cb = dp_cbs->hdd_disble_lro_in_cc_cb; + cds_ctx->hdd_set_rx_mode_rps_cb = dp_cbs->hdd_set_rx_mode_rps_cb; + return QDF_STATUS_SUCCESS; +} + +/** + * cds_deregister_dp_cb() - Deregister datapath callbacks with CDS + * @dp_cbs: pointer to cds_dp_cbacks structure + * + * Return: QDF_STATUS + */ +QDF_STATUS cds_deregister_dp_cb(void) + +{ + p_cds_contextType cds_ctx; + + cds_ctx = cds_get_global_context(); + if (!cds_ctx) { + cds_err("Invalid CDS context"); + return QDF_STATUS_E_FAILURE; + } + + cds_ctx->ol_txrx_update_mac_id_cb = NULL; + cds_ctx->hdd_en_lro_in_cc_cb = NULL; + cds_ctx->hdd_disable_lro_in_cc_cb = NULL; + cds_ctx->hdd_set_rx_mode_rps_cb = NULL; + + return QDF_STATUS_SUCCESS; +} + +/** + * cds_get_arp_stats_gw_ip() - get arp stats track IP + * + * Return: ARP stats IP to track + */ +uint32_t cds_get_arp_stats_gw_ip(void) +{ + hdd_context_t *hdd_ctx; + + hdd_ctx = (hdd_context_t *) (gp_cds_context->pHDDContext); + if (!hdd_ctx) { + cds_err("Hdd Context is Null"); + return 0; + } + + return hdd_ctx->track_arp_ip; +} + +/** + * cds_incr_arp_stats_tx_tgt_delivered() - increment ARP stats + * + * Return: none + */ +void cds_incr_arp_stats_tx_tgt_delivered(void) +{ + hdd_context_t *hdd_ctx; + hdd_adapter_list_node_t *adapter_node = NULL, *next = NULL; + hdd_adapter_t *adapter = NULL; + QDF_STATUS status; + + hdd_ctx = (hdd_context_t *) (gp_cds_context->pHDDContext); + if (!hdd_ctx) { + cds_err("Hdd Context is Null"); + return; + } + + status = hdd_get_front_adapter(hdd_ctx, &adapter_node); + + while (NULL != adapter_node && QDF_STATUS_SUCCESS == status) { + adapter = adapter_node->pAdapter; + + if (QDF_STA_MODE == adapter->device_mode) + break; + + status = hdd_get_next_adapter(hdd_ctx, adapter_node, &next); + adapter_node = next; + } + + if (adapter) + adapter->hdd_stats.hdd_arp_stats.tx_host_fw_sent++; +} + +/** + * cds_incr_arp_stats_tx_tgt_acked() - increment ARP stats + * + * Return: none + */ +void cds_incr_arp_stats_tx_tgt_acked(void) +{ + hdd_context_t *hdd_ctx; + hdd_adapter_list_node_t *adapter_node = NULL, *next = NULL; + hdd_adapter_t *adapter = NULL; + QDF_STATUS status; + + hdd_ctx = (hdd_context_t *) (gp_cds_context->pHDDContext); + if (!hdd_ctx) { + cds_err("Hdd Context is Null"); + return; + } + + status = hdd_get_front_adapter(hdd_ctx, &adapter_node); + + while (NULL != adapter_node && QDF_STATUS_SUCCESS == status) { + adapter = adapter_node->pAdapter; + + if (QDF_STA_MODE == adapter->device_mode) + break; + + status = hdd_get_next_adapter(hdd_ctx, adapter_node, &next); + adapter_node = next; + } + + if (adapter) + adapter->hdd_stats.hdd_arp_stats.tx_ack_cnt++; +} diff --git a/drivers/staging/qcacld-3.0/core/cds/src/cds_concurrency.c b/drivers/staging/qcacld-3.0/core/cds/src/cds_concurrency.c new file mode 100644 index 0000000000000000000000000000000000000000..53eb5e7ff48fd7e18f210c6b1b037be15ef2bd43 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/cds/src/cds_concurrency.c @@ -0,0 +1,9947 @@ +/* + * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: cds_concurrency.c + * + * WLAN Concurrenct Connection Management functions + * + */ + +/* Include files */ + +#include +#include +#include +#include +#include +#include +#include "wlan_hdd_trace.h" +#include "wlan_hdd_hostapd.h" +#include "cds_concurrency.h" +#include "qdf_types.h" +#include "qdf_trace.h" + +#include +#include +#include +#include +#include +#include +#include "sap_api.h" +#include +#include +#include +#include "cfg_api.h" +#include "qwlan_version.h" +#include "wma_types.h" +#include "wma.h" +#include "wma_api.h" +#include "cds_utils.h" +#include "cds_reg_service.h" +#include "wlan_hdd_ipa.h" +#include "cdp_txrx_flow_ctrl_legacy.h" +#include "pld_common.h" +#include "wlan_hdd_green_ap.h" + +static struct cds_conc_connection_info + conc_connection_list[MAX_NUMBER_OF_CONC_CONNECTIONS]; + +#define CONC_CONNECTION_LIST_VALID_INDEX(index) \ + ((MAX_NUMBER_OF_CONC_CONNECTIONS > index) && \ + (conc_connection_list[index].in_use)) + +#define CDS_MAX_CON_STRING_LEN 100 +/** + * first_connection_pcl_table - table which provides PCL for the + * very first connection in the system + */ +static const enum cds_pcl_type +first_connection_pcl_table[CDS_MAX_NUM_OF_MODE] + [CDS_MAX_CONC_PRIORITY_MODE] = { + [CDS_STA_MODE] = {CDS_NONE, CDS_NONE, CDS_NONE}, + [CDS_SAP_MODE] = {CDS_5G, CDS_5G, CDS_5G }, + [CDS_P2P_CLIENT_MODE] = {CDS_5G, CDS_5G, CDS_5G }, + [CDS_P2P_GO_MODE] = {CDS_5G, CDS_5G, CDS_5G }, + [CDS_IBSS_MODE] = {CDS_NONE, CDS_NONE, CDS_NONE}, +}; + +/** + * second_connection_pcl_dbs_table - table which provides PCL + * for the 2nd connection, when we have a connection already in + * the system (with DBS supported by HW) + */ +static const enum cds_pcl_type +second_connection_pcl_dbs_table[CDS_MAX_ONE_CONNECTION_MODE] + [CDS_MAX_NUM_OF_MODE][CDS_MAX_CONC_PRIORITY_MODE] = { + [CDS_STA_24_1x1] = { + [CDS_STA_MODE] = {CDS_5G_SCC_CH, CDS_5G_SCC_CH, CDS_5G_SCC_CH}, + [CDS_SAP_MODE] = {CDS_5G_SCC_CH, CDS_5G_SCC_CH, CDS_5G_SCC_CH}, + [CDS_P2P_CLIENT_MODE] = {CDS_5G_SCC_CH, CDS_5G_SCC_CH, CDS_5G_SCC_CH}, + [CDS_P2P_GO_MODE] = {CDS_5G_SCC_CH, CDS_5G_SCC_CH, CDS_5G_SCC_CH}, + [CDS_IBSS_MODE] = {CDS_5G, CDS_5G, CDS_5G } }, + + [CDS_STA_24_2x2] = { + [CDS_STA_MODE] = {CDS_5G_SCC_CH, CDS_5G_SCC_CH, CDS_5G_SCC_CH}, + [CDS_SAP_MODE] = {CDS_5G_SCC_CH, CDS_5G_SCC_CH, CDS_5G_SCC_CH}, + [CDS_P2P_CLIENT_MODE] = {CDS_5G_SCC_CH, CDS_5G_SCC_CH, CDS_5G_SCC_CH}, + [CDS_P2P_GO_MODE] = {CDS_5G_SCC_CH, CDS_5G_SCC_CH, CDS_5G_SCC_CH}, + [CDS_IBSS_MODE] = {CDS_5G, CDS_5G, CDS_5G } }, + + [CDS_STA_5_1x1] = { + [CDS_STA_MODE] = {CDS_SCC_CH_24G, CDS_24G_SCC_CH, CDS_SCC_CH_24G}, + [CDS_SAP_MODE] = {CDS_SCC_CH_24G, CDS_24G_SCC_CH, CDS_SCC_CH_24G}, + [CDS_P2P_CLIENT_MODE] = { + CDS_SCC_CH_24G, CDS_24G_SCC_CH, CDS_SCC_CH_24G}, + [CDS_P2P_GO_MODE] = {CDS_SCC_CH_24G, CDS_24G_SCC_CH, CDS_SCC_CH_24G}, + [CDS_IBSS_MODE] = {CDS_24G, CDS_24G, CDS_24G } }, + + [CDS_STA_5_2x2] = { + [CDS_STA_MODE] = {CDS_SCC_CH_24G, CDS_24G_SCC_CH, CDS_SCC_CH_24G}, + [CDS_SAP_MODE] = {CDS_SCC_CH_24G, CDS_24G_SCC_CH, CDS_SCC_CH_24G}, + [CDS_P2P_CLIENT_MODE] = { + CDS_SCC_CH_24G, CDS_24G_SCC_CH, CDS_SCC_CH_24G}, + [CDS_P2P_GO_MODE] = {CDS_SCC_CH_24G, CDS_24G_SCC_CH, CDS_SCC_CH_24G}, + [CDS_IBSS_MODE] = {CDS_24G, CDS_24G, CDS_24G } }, + + [CDS_P2P_CLI_24_1x1] = { + [CDS_STA_MODE] = {CDS_5G_SCC_CH, CDS_5G_SCC_CH, CDS_5G_SCC_CH}, + [CDS_SAP_MODE] = {CDS_5G_SCC_CH, CDS_5G_SCC_CH, CDS_5G_SCC_CH}, + [CDS_P2P_CLIENT_MODE] = {CDS_5G_SCC_CH, CDS_5G_SCC_CH, CDS_5G_SCC_CH}, + [CDS_P2P_GO_MODE] = {CDS_5G_SCC_CH, CDS_5G_SCC_CH, CDS_5G_SCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_CLI_24_2x2] = { + [CDS_STA_MODE] = {CDS_5G_SCC_CH, CDS_5G_SCC_CH, CDS_5G_SCC_CH}, + [CDS_SAP_MODE] = {CDS_5G_SCC_CH, CDS_5G_SCC_CH, CDS_5G_SCC_CH}, + [CDS_P2P_CLIENT_MODE] = {CDS_5G_SCC_CH, CDS_5G_SCC_CH, CDS_5G_SCC_CH}, + [CDS_P2P_GO_MODE] = {CDS_5G_SCC_CH, CDS_5G_SCC_CH, CDS_5G_SCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_CLI_5_1x1] = { + [CDS_STA_MODE] = {CDS_SCC_CH_24G, CDS_24G_SCC_CH, CDS_SCC_CH_24G}, + [CDS_SAP_MODE] = {CDS_SCC_CH_24G, CDS_24G_SCC_CH, CDS_SCC_CH_24G}, + [CDS_P2P_CLIENT_MODE] = { + CDS_SCC_CH_24G, CDS_24G_SCC_CH, CDS_SCC_CH_24G}, + [CDS_P2P_GO_MODE] = {CDS_SCC_CH_24G, CDS_24G_SCC_CH, CDS_SCC_CH_24G}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_CLI_5_2x2] = { + [CDS_STA_MODE] = {CDS_SCC_CH_24G, CDS_24G_SCC_CH, CDS_SCC_CH_24G}, + [CDS_SAP_MODE] = {CDS_SCC_CH_24G, CDS_24G_SCC_CH, CDS_SCC_CH_24G}, + [CDS_P2P_CLIENT_MODE] = { + CDS_SCC_CH_24G, CDS_24G_SCC_CH, CDS_SCC_CH_24G}, + [CDS_P2P_GO_MODE] = {CDS_SCC_CH_24G, CDS_24G_SCC_CH, CDS_SCC_CH_24G}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_GO_24_1x1] = { + [CDS_STA_MODE] = {CDS_5G_SCC_CH, CDS_5G_SCC_CH, CDS_5G_SCC_CH}, + [CDS_SAP_MODE] = {CDS_5G_SCC_CH, CDS_5G_SCC_CH, CDS_5G_SCC_CH}, + [CDS_P2P_CLIENT_MODE] = {CDS_5G_SCC_CH, CDS_5G_SCC_CH, CDS_5G_SCC_CH}, + [CDS_P2P_GO_MODE] = {CDS_5G, CDS_5G, CDS_5G}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_GO_24_2x2] = { + [CDS_STA_MODE] = {CDS_5G_SCC_CH, CDS_5G_SCC_CH, CDS_5G_SCC_CH}, + [CDS_SAP_MODE] = {CDS_5G_SCC_CH, CDS_5G_SCC_CH, CDS_5G_SCC_CH}, + [CDS_P2P_CLIENT_MODE] = {CDS_5G_SCC_CH, CDS_5G_SCC_CH, CDS_5G_SCC_CH}, + [CDS_P2P_GO_MODE] = {CDS_5G, CDS_5G, CDS_5G}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_GO_5_1x1] = { + [CDS_STA_MODE] = {CDS_SCC_CH_24G, CDS_SCC_CH_24G, CDS_SCC_CH_24G}, + [CDS_SAP_MODE] = {CDS_SCC_CH_24G, CDS_SCC_CH_24G, CDS_SCC_CH_24G}, + [CDS_P2P_CLIENT_MODE] = { + CDS_SCC_CH_24G, CDS_24G_SCC_CH, CDS_SCC_CH_24G}, + [CDS_P2P_GO_MODE] = {CDS_24G, CDS_24G, CDS_24G}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_GO_5_2x2] = { + [CDS_STA_MODE] = {CDS_SCC_CH_24G, CDS_SCC_CH_24G, CDS_SCC_CH_24G}, + [CDS_SAP_MODE] = {CDS_SCC_CH_24G, CDS_SCC_CH_24G, CDS_SCC_CH_24G}, + [CDS_P2P_CLIENT_MODE] = { + CDS_SCC_CH_24G, CDS_24G_SCC_CH, CDS_SCC_CH_24G}, + [CDS_P2P_GO_MODE] = {CDS_24G, CDS_24G, CDS_24G}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_SAP_24_1x1] = { + [CDS_STA_MODE] = {CDS_5G_SCC_CH, CDS_5G_SCC_CH, CDS_5G_SCC_CH}, + [CDS_SAP_MODE] = {CDS_5G_SCC_CH, CDS_5G_SCC_CH, CDS_5G_SCC_CH}, + [CDS_P2P_CLIENT_MODE] = {CDS_5G_SCC_CH, CDS_5G_SCC_CH, CDS_5G_SCC_CH}, + [CDS_P2P_GO_MODE] = {CDS_5G_SCC_CH, CDS_5G_SCC_CH, CDS_5G_SCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_SAP_24_2x2] = { + [CDS_STA_MODE] = {CDS_5G_SCC_CH, CDS_5G_SCC_CH, CDS_5G_SCC_CH}, + [CDS_SAP_MODE] = {CDS_5G_SCC_CH, CDS_5G_SCC_CH, CDS_5G_SCC_CH}, + [CDS_P2P_CLIENT_MODE] = {CDS_5G_SCC_CH, CDS_5G_SCC_CH, CDS_5G_SCC_CH}, + [CDS_P2P_GO_MODE] = {CDS_5G_SCC_CH, CDS_5G_SCC_CH, CDS_5G_SCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_SAP_5_1x1] = { + [CDS_STA_MODE] = {CDS_SCC_CH_24G, CDS_SCC_CH_24G, CDS_SCC_CH_24G}, + [CDS_SAP_MODE] = {CDS_SCC_CH_24G, CDS_SCC_CH_24G, CDS_SCC_CH_24G}, + [CDS_P2P_CLIENT_MODE] = { + CDS_SCC_CH_24G, CDS_24G_SCC_CH, CDS_SCC_CH_24G}, + [CDS_P2P_GO_MODE] = {CDS_SCC_CH_24G, CDS_SCC_CH_24G, CDS_SCC_CH_24G}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_SAP_5_2x2] = { + [CDS_STA_MODE] = {CDS_SCC_CH_24G, CDS_SCC_CH_24G, CDS_SCC_CH_24G}, + [CDS_SAP_MODE] = {CDS_SCC_CH_24G, CDS_SCC_CH_24G, CDS_SCC_CH_24G}, + [CDS_P2P_CLIENT_MODE] = { + CDS_SCC_CH_24G, CDS_24G_SCC_CH, CDS_SCC_CH_24G}, + [CDS_P2P_GO_MODE] = {CDS_SCC_CH_24G, CDS_SCC_CH_24G, CDS_SCC_CH_24G}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_IBSS_24_1x1] = { + [CDS_STA_MODE] = {CDS_5G_SCC_CH, CDS_5G_SCC_CH, CDS_5G_SCC_CH}, + [CDS_SAP_MODE] = {CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_GO_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_IBSS_24_2x2] = { + [CDS_STA_MODE] = {CDS_5G_SCC_CH, CDS_5G_SCC_CH, CDS_5G_SCC_CH}, + [CDS_SAP_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_GO_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_IBSS_5_1x1] = { + [CDS_STA_MODE] = {CDS_24G_SCC_CH, CDS_24G_SCC_CH, CDS_24G_SCC_CH}, + [CDS_SAP_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_GO_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_IBSS_5_2x2] = { + [CDS_STA_MODE] = {CDS_24G_SCC_CH, CDS_24G_SCC_CH, CDS_24G_SCC_CH}, + [CDS_SAP_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_GO_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, +}; + +/** + * second_connection_pcl_nodbs_table - table which provides PCL + * for the 2nd connection, when we have a connection already in + * the system (with DBS not supported by HW) + */ +static const enum cds_pcl_type +second_connection_pcl_nodbs_table[CDS_MAX_ONE_CONNECTION_MODE] + [CDS_MAX_NUM_OF_MODE][CDS_MAX_CONC_PRIORITY_MODE] = { + [CDS_STA_24_1x1] = { + [CDS_STA_MODE] = {CDS_5G, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_SAP_MODE] = {CDS_5G, CDS_SCC_CH, CDS_SCC_CH_5G}, + [CDS_P2P_CLIENT_MODE] = {CDS_5G, CDS_SCC_CH, CDS_SCC_CH_5G}, + [CDS_P2P_GO_MODE] = {CDS_5G, CDS_SCC_CH, CDS_SCC_CH_5G}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_STA_24_2x2] = { + [CDS_STA_MODE] = {CDS_5G, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_SAP_MODE] = {CDS_5G, CDS_SCC_CH, CDS_SCC_CH_5G}, + [CDS_P2P_CLIENT_MODE] = {CDS_5G, CDS_SCC_CH, CDS_SCC_CH_5G}, + [CDS_P2P_GO_MODE] = {CDS_5G, CDS_SCC_CH, CDS_SCC_CH_5G}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_STA_5_1x1] = { + [CDS_STA_MODE] = {CDS_SCC_CH_5G, CDS_SCC_CH, CDS_SCC_CH_5G}, + [CDS_SAP_MODE] = {CDS_SCC_CH_5G, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_P2P_CLIENT_MODE] = {CDS_SCC_CH_5G, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_P2P_GO_MODE] = {CDS_SCC_CH_5G, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_STA_5_2x2] = { + [CDS_STA_MODE] = {CDS_SCC_CH_5G, CDS_SCC_CH, CDS_SCC_CH_5G}, + [CDS_SAP_MODE] = {CDS_SCC_CH_5G, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_P2P_CLIENT_MODE] = {CDS_SCC_CH_5G, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_P2P_GO_MODE] = {CDS_SCC_CH_5G, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_CLI_24_1x1] = { + [CDS_STA_MODE] = {CDS_5G, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_SAP_MODE] = {CDS_5G, CDS_SCC_CH, CDS_SCC_CH_5G}, + [CDS_P2P_CLIENT_MODE] = {CDS_5G, CDS_SCC_CH, CDS_SCC_CH_5G}, + [CDS_P2P_GO_MODE] = {CDS_5G, CDS_SCC_CH, CDS_SCC_CH_5G}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_CLI_24_2x2] = { + [CDS_STA_MODE] = {CDS_5G, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_SAP_MODE] = {CDS_5G, CDS_SCC_CH, CDS_SCC_CH_5G}, + [CDS_P2P_CLIENT_MODE] = {CDS_5G, CDS_SCC_CH, CDS_SCC_CH_5G}, + [CDS_P2P_GO_MODE] = {CDS_5G, CDS_SCC_CH, CDS_SCC_CH_5G}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_CLI_5_1x1] = { + [CDS_STA_MODE] = {CDS_SCC_CH_5G, CDS_SCC_CH, CDS_SCC_CH_5G}, + [CDS_SAP_MODE] = {CDS_SCC_CH_5G, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_P2P_CLIENT_MODE] = {CDS_SCC_CH_5G, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_P2P_GO_MODE] = {CDS_SCC_CH_5G, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_CLI_5_2x2] = { + [CDS_STA_MODE] = {CDS_SCC_CH_5G, CDS_SCC_CH, CDS_SCC_CH_5G}, + [CDS_SAP_MODE] = {CDS_SCC_CH_5G, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_P2P_CLIENT_MODE] = {CDS_SCC_CH_5G, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_P2P_GO_MODE] = {CDS_SCC_CH_5G, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_GO_24_1x1] = { + [CDS_STA_MODE] = {CDS_SCC_CH, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_SAP_MODE] = {CDS_SCC_CH, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_P2P_CLIENT_MODE] = {CDS_SCC_CH, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_P2P_GO_MODE] = {CDS_SCC_CH, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_GO_24_2x2] = { + [CDS_STA_MODE] = {CDS_SCC_CH, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_SAP_MODE] = {CDS_SCC_CH, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_P2P_CLIENT_MODE] = {CDS_SCC_CH, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_P2P_GO_MODE] = {CDS_SCC_CH, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_GO_5_1x1] = { + [CDS_STA_MODE] = {CDS_SCC_CH_5G, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_SAP_MODE] = {CDS_SCC_CH, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_P2P_CLIENT_MODE] = {CDS_SCC_CH, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_P2P_GO_MODE] = {CDS_SCC_CH, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_GO_5_2x2] = { + [CDS_STA_MODE] = {CDS_SCC_CH_5G, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_SAP_MODE] = {CDS_SCC_CH, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_P2P_CLIENT_MODE] = {CDS_SCC_CH, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_P2P_GO_MODE] = {CDS_SCC_CH, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_SAP_24_1x1] = { + [CDS_STA_MODE] = {CDS_SCC_CH, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_SAP_MODE] = {CDS_SCC_CH, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_P2P_CLIENT_MODE] = {CDS_SCC_CH, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_P2P_GO_MODE] = {CDS_SCC_CH, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_SAP_24_2x2] = { + [CDS_STA_MODE] = {CDS_SCC_CH, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_SAP_MODE] = {CDS_SCC_CH, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_P2P_CLIENT_MODE] = {CDS_SCC_CH, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_P2P_GO_MODE] = {CDS_SCC_CH, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_SAP_5_1x1] = { + [CDS_STA_MODE] = {CDS_SCC_CH_5G, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_SAP_MODE] = {CDS_SCC_CH, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_P2P_CLIENT_MODE] = {CDS_SCC_CH, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_P2P_GO_MODE] = {CDS_SCC_CH, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_SAP_5_2x2] = { + [CDS_STA_MODE] = {CDS_SCC_CH_5G, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_SAP_MODE] = {CDS_SCC_CH, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_P2P_CLIENT_MODE] = {CDS_SCC_CH, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_P2P_GO_MODE] = {CDS_SCC_CH, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_IBSS_24_1x1] = { + [CDS_STA_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_SAP_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_GO_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_IBSS_24_2x2] = { + [CDS_STA_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_SAP_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_GO_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_IBSS_5_1x1] = { + [CDS_STA_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_SAP_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_GO_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_IBSS_5_2x2] = { + [CDS_STA_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_SAP_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_GO_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, +}; + +/** + * third_connection_pcl_dbs_table - table which provides PCL for + * the 3rd connection, when we have two connections already in + * the system (with DBS supported by HW) + */ +static const enum cds_pcl_type +third_connection_pcl_dbs_table[CDS_MAX_TWO_CONNECTION_MODE] + [CDS_MAX_NUM_OF_MODE][CDS_MAX_CONC_PRIORITY_MODE] = { + [CDS_STA_SAP_SCC_24_1x1] = { + [CDS_STA_MODE] = {CDS_5G_SCC_CH, CDS_5G_SCC_CH, CDS_5G_SCC_CH}, + [CDS_SAP_MODE] = {CDS_5G_SCC_CH, CDS_5G_SCC_CH, CDS_5G_SCC_CH}, + [CDS_P2P_CLIENT_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_GO_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_STA_SAP_SCC_24_2x2] = { + [CDS_STA_MODE] = {CDS_5G_SCC_CH, CDS_5G_SCC_CH, CDS_5G_SCC_CH}, + [CDS_SAP_MODE] = {CDS_5G_SCC_CH, CDS_5G_SCC_CH, CDS_5G_SCC_CH}, + [CDS_P2P_CLIENT_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_GO_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_STA_SAP_MCC_24_1x1] = { + [CDS_STA_MODE] = {CDS_5G_MCC_CH, CDS_5G, CDS_5G_MCC_CH}, + [CDS_SAP_MODE] = {CDS_5G_MCC_CH, CDS_5G, CDS_5G_MCC_CH}, + [CDS_P2P_CLIENT_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_GO_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_STA_SAP_MCC_24_2x2] = { + [CDS_STA_MODE] = {CDS_5G_MCC_CH, CDS_5G, CDS_5G_MCC_CH}, + [CDS_SAP_MODE] = {CDS_5G_MCC_CH, CDS_5G, CDS_5G_MCC_CH}, + [CDS_P2P_CLIENT_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_GO_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_STA_SAP_SCC_5_1x1] = { + [CDS_STA_MODE] = {CDS_SCC_CH_24G, CDS_24G_SCC_CH, CDS_SCC_CH_24G}, + [CDS_SAP_MODE] = {CDS_SCC_CH_24G, CDS_24G_SCC_CH, CDS_SCC_CH_24G}, + [CDS_P2P_CLIENT_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_GO_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_STA_SAP_SCC_5_2x2] = { + [CDS_STA_MODE] = {CDS_SCC_CH_24G, CDS_24G_SCC_CH, CDS_SCC_CH_24G}, + [CDS_SAP_MODE] = {CDS_SCC_CH_24G, CDS_24G_SCC_CH, CDS_SCC_CH_24G}, + [CDS_P2P_CLIENT_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_GO_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_STA_SAP_MCC_5_1x1] = { + [CDS_STA_MODE] = {CDS_MCC_CH_24G, CDS_24G, CDS_24G}, + [CDS_SAP_MODE] = {CDS_24G, CDS_24G, CDS_24G}, + [CDS_P2P_CLIENT_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_GO_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_STA_SAP_MCC_5_2x2] = { + [CDS_STA_MODE] = {CDS_MCC_CH_24G, CDS_24G, CDS_24G}, + [CDS_SAP_MODE] = {CDS_24G, CDS_24G, CDS_24G}, + [CDS_P2P_CLIENT_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_GO_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_STA_SAP_MCC_24_5_1x1] = { + [CDS_STA_MODE] = {CDS_MCC_CH_5G, CDS_5G, CDS_5G}, + [CDS_SAP_MODE] = {CDS_24G, CDS_24G, CDS_24G}, + [CDS_P2P_CLIENT_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_GO_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_STA_SAP_MCC_24_5_2x2] = { + [CDS_STA_MODE] = {CDS_MCC_CH_5G, CDS_5G, CDS_5G}, + [CDS_SAP_MODE] = {CDS_24G, CDS_24G, CDS_24G}, + [CDS_P2P_CLIENT_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_GO_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_STA_SAP_DBS_1x1] = { + [CDS_STA_MODE] = { + CDS_SCC_ON_5_SCC_ON_24_5G, CDS_NONE, CDS_SCC_ON_5_SCC_ON_24}, + [CDS_SAP_MODE] = { + CDS_SCC_ON_5_SCC_ON_24_5G, CDS_NONE, CDS_SCC_ON_5_SCC_ON_24}, + [CDS_P2P_CLIENT_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_GO_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_STA_P2P_GO_SCC_24_1x1] = { + [CDS_STA_MODE] = {CDS_5G_SCC_CH, CDS_5G_SCC_CH, CDS_5G_SCC_CH}, + [CDS_SAP_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = {CDS_5G_SCC_CH, CDS_5G_SCC_CH, CDS_5G_SCC_CH}, + [CDS_P2P_GO_MODE] = {CDS_5G_SCC_CH, CDS_5G_SCC_CH, CDS_5G_SCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_STA_P2P_GO_SCC_24_2x2] = { + [CDS_STA_MODE] = {CDS_5G_SCC_CH, CDS_5G_SCC_CH, CDS_5G_SCC_CH}, + [CDS_SAP_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = {CDS_5G_SCC_CH, CDS_5G_SCC_CH, CDS_5G_SCC_CH}, + [CDS_P2P_GO_MODE] = {CDS_5G_SCC_CH, CDS_5G_SCC_CH, CDS_5G_SCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_STA_P2P_GO_MCC_24_1x1] = { + [CDS_STA_MODE] = {CDS_5G_MCC_CH, CDS_5G, CDS_5G_MCC_CH}, + [CDS_SAP_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = {CDS_5G_MCC_CH, CDS_5G, CDS_5G_MCC_CH}, + [CDS_P2P_GO_MODE] = {CDS_5G_MCC_CH, CDS_5G, CDS_5G_MCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_STA_P2P_GO_MCC_24_2x2] = { + [CDS_STA_MODE] = {CDS_5G_MCC_CH, CDS_5G, CDS_5G_MCC_CH}, + [CDS_SAP_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = {CDS_5G_MCC_CH, CDS_5G, CDS_5G_MCC_CH}, + [CDS_P2P_GO_MODE] = {CDS_5G_MCC_CH, CDS_5G, CDS_5G_MCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_STA_P2P_GO_SCC_5_1x1] = { + [CDS_STA_MODE] = {CDS_SCC_CH_24G, CDS_24G_SCC_CH, CDS_SCC_CH_24G}, + [CDS_SAP_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = { + CDS_SCC_CH_24G, CDS_24G_SCC_CH, CDS_SCC_CH_24G}, + [CDS_P2P_GO_MODE] = {CDS_SCC_CH_24G, CDS_24G_SCC_CH, CDS_SCC_CH_24G}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_STA_P2P_GO_SCC_5_2x2] = { + [CDS_STA_MODE] = {CDS_SCC_CH_24G, CDS_24G_SCC_CH, CDS_SCC_CH_24G}, + [CDS_SAP_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = { + CDS_SCC_CH_24G, CDS_24G_SCC_CH, CDS_SCC_CH_24G}, + [CDS_P2P_GO_MODE] = {CDS_SCC_CH_24G, CDS_24G_SCC_CH, CDS_SCC_CH_24G}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_STA_P2P_GO_MCC_5_1x1] = { + [CDS_STA_MODE] = {CDS_MCC_CH_24G, CDS_24G, CDS_24G}, + [CDS_SAP_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = {CDS_MCC_CH_24G, CDS_24G, CDS_24G}, + [CDS_P2P_GO_MODE] = {CDS_MCC_CH_24G, CDS_24G, CDS_24G}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_STA_P2P_GO_MCC_5_2x2] = { + [CDS_STA_MODE] = {CDS_MCC_CH_24G, CDS_24G, CDS_24G}, + [CDS_SAP_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = {CDS_MCC_CH_24G, CDS_24G, CDS_24G}, + [CDS_P2P_GO_MODE] = {CDS_MCC_CH_24G, CDS_24G, CDS_24G}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_STA_P2P_GO_MCC_24_5_1x1] = { + [CDS_STA_MODE] = {CDS_MCC_CH_5G, CDS_5G, CDS_5G}, + [CDS_SAP_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = {CDS_MCC_CH_24G, CDS_24G, CDS_24G}, + [CDS_P2P_GO_MODE] = {CDS_MCC_CH_24G, CDS_24G, CDS_24G}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_STA_P2P_GO_MCC_24_5_2x2] = { + [CDS_STA_MODE] = {CDS_MCC_CH_5G, CDS_5G, CDS_5G}, + [CDS_SAP_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = {CDS_MCC_CH_24G, CDS_24G, CDS_24G}, + [CDS_P2P_GO_MODE] = {CDS_MCC_CH_24G, CDS_24G, CDS_24G}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_STA_P2P_GO_DBS_1x1] = { + [CDS_STA_MODE] = { + CDS_SCC_ON_5_SCC_ON_24_5G, CDS_NONE, CDS_SCC_ON_5_SCC_ON_24}, + [CDS_SAP_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = { + CDS_SCC_ON_5_SCC_ON_24_5G, CDS_NONE, CDS_SCC_ON_5_SCC_ON_24}, + [CDS_P2P_GO_MODE] = { + CDS_SCC_ON_5_SCC_ON_24_5G, CDS_NONE, CDS_SCC_ON_5_SCC_ON_24}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_STA_P2P_CLI_SCC_24_1x1] = { + [CDS_STA_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_SAP_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = {CDS_5G_SCC_CH, CDS_5G_SCC_CH, CDS_5G_SCC_CH}, + [CDS_P2P_GO_MODE] = {CDS_5G_SCC_CH, CDS_5G_SCC_CH, CDS_5G_SCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_STA_P2P_CLI_SCC_24_2x2] = { + [CDS_STA_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_SAP_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = {CDS_5G_SCC_CH, CDS_5G_SCC_CH, CDS_5G_SCC_CH}, + [CDS_P2P_GO_MODE] = {CDS_5G_SCC_CH, CDS_5G_SCC_CH, CDS_5G_SCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_STA_P2P_CLI_MCC_24_1x1] = { + [CDS_STA_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_SAP_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = {CDS_5G_MCC_CH, CDS_5G, CDS_5G_MCC_CH}, + [CDS_P2P_GO_MODE] = {CDS_5G_MCC_CH, CDS_5G, CDS_5G_MCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_STA_P2P_CLI_MCC_24_2x2] = { + [CDS_STA_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_SAP_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = {CDS_5G_MCC_CH, CDS_5G, CDS_5G_MCC_CH}, + [CDS_P2P_GO_MODE] = {CDS_5G_MCC_CH, CDS_5G, CDS_5G_MCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_STA_P2P_CLI_SCC_5_1x1] = { + [CDS_STA_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_SAP_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = { + CDS_SCC_CH_24G, CDS_24G_SCC_CH, CDS_SCC_CH_24G}, + [CDS_P2P_GO_MODE] = {CDS_SCC_CH_24G, CDS_24G_SCC_CH, CDS_SCC_CH_24G}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_STA_P2P_CLI_SCC_5_2x2] = { + [CDS_STA_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_SAP_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = { + CDS_SCC_CH_24G, CDS_24G_SCC_CH, CDS_SCC_CH_24G}, + [CDS_P2P_GO_MODE] = {CDS_SCC_CH_24G, CDS_24G_SCC_CH, CDS_SCC_CH_24G}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_STA_P2P_CLI_MCC_5_1x1] = { + [CDS_STA_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_SAP_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = {CDS_MCC_CH_24G, CDS_24G, CDS_MCC_CH_24G}, + [CDS_P2P_GO_MODE] = {CDS_MCC_CH_24G, CDS_24G, CDS_MCC_CH_24G}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_STA_P2P_CLI_MCC_5_2x2] = { + [CDS_STA_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_SAP_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = {CDS_MCC_CH_24G, CDS_24G, CDS_MCC_CH_24G}, + [CDS_P2P_GO_MODE] = {CDS_MCC_CH_24G, CDS_24G, CDS_MCC_CH_24G}, + [CDS_IBSS_MODE] = {CDS_NONE, CDS_NONE, CDS_NONE} }, + + [CDS_STA_P2P_CLI_MCC_24_5_1x1] = { + [CDS_STA_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_SAP_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = {CDS_MCC_CH_24G, CDS_24G, CDS_MCC_CH_24G}, + [CDS_P2P_GO_MODE] = {CDS_MCC_CH_24G, CDS_24G, CDS_MCC_CH_24G}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_STA_P2P_CLI_MCC_24_5_2x2] = { + [CDS_STA_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_SAP_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = {CDS_MCC_CH_24G, CDS_24G, CDS_MCC_CH_24G}, + [CDS_P2P_GO_MODE] = {CDS_MCC_CH_24G, CDS_24G, CDS_MCC_CH_24G}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_STA_P2P_CLI_DBS_1x1] = { + [CDS_STA_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_SAP_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = { + CDS_SCC_ON_5_SCC_ON_24_5G, CDS_NONE, CDS_SCC_ON_5_SCC_ON_24}, + [CDS_P2P_GO_MODE] = { + CDS_SCC_ON_5_SCC_ON_24_5G, CDS_NONE, CDS_SCC_ON_5_SCC_ON_24}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_GO_P2P_CLI_SCC_24_1x1] = { + [CDS_STA_MODE] = {CDS_5G_SCC_CH, CDS_5G_SCC_CH, CDS_5G_SCC_CH}, + [CDS_SAP_MODE] = {CDS_5G_SCC_CH, CDS_5G_SCC_CH, CDS_5G_SCC_CH}, + [CDS_P2P_CLIENT_MODE] = {CDS_5G_SCC_CH, CDS_5G_SCC_CH, CDS_5G_SCC_CH}, + [CDS_P2P_GO_MODE] = {CDS_5G_SCC_CH, CDS_5G_SCC_CH, CDS_5G_SCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_GO_P2P_CLI_SCC_24_2x2] = { + [CDS_STA_MODE] = {CDS_5G_SCC_CH, CDS_5G_SCC_CH, CDS_5G_SCC_CH}, + [CDS_SAP_MODE] = {CDS_5G_SCC_CH, CDS_5G_SCC_CH, CDS_5G_SCC_CH}, + [CDS_P2P_CLIENT_MODE] = {CDS_5G_SCC_CH, CDS_5G_SCC_CH, CDS_5G_SCC_CH}, + [CDS_P2P_GO_MODE] = {CDS_5G_SCC_CH, CDS_5G_SCC_CH, CDS_5G_SCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_GO_P2P_CLI_MCC_24_1x1] = { + [CDS_STA_MODE] = {CDS_5G_MCC_CH, CDS_5G, CDS_5G_MCC_CH}, + [CDS_SAP_MODE] = {CDS_5G_MCC_CH, CDS_5G, CDS_5G_MCC_CH}, + [CDS_P2P_CLIENT_MODE] = {CDS_5G_MCC_CH, CDS_5G, CDS_5G_MCC_CH}, + [CDS_P2P_GO_MODE] = {CDS_5G_MCC_CH, CDS_5G, CDS_5G_MCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_GO_P2P_CLI_MCC_24_2x2] = { + [CDS_STA_MODE] = {CDS_5G_MCC_CH, CDS_5G, CDS_5G_MCC_CH}, + [CDS_SAP_MODE] = {CDS_5G_MCC_CH, CDS_5G, CDS_5G_MCC_CH}, + [CDS_P2P_CLIENT_MODE] = {CDS_5G_MCC_CH, CDS_5G, CDS_5G_MCC_CH}, + [CDS_P2P_GO_MODE] = {CDS_5G_MCC_CH, CDS_5G, CDS_5G_MCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_GO_P2P_CLI_SCC_5_1x1] = { + [CDS_STA_MODE] = {CDS_SCC_CH_24G, CDS_24G_SCC_CH, CDS_SCC_CH_24G}, + [CDS_SAP_MODE] = {CDS_SCC_CH_24G, CDS_24G_SCC_CH, CDS_SCC_CH_24G}, + [CDS_P2P_CLIENT_MODE] = { + CDS_SCC_CH_24G, CDS_24G_SCC_CH, CDS_SCC_CH_24G}, + [CDS_P2P_GO_MODE] = {CDS_SCC_CH_24G, CDS_24G_SCC_CH, CDS_SCC_CH_24G}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_GO_P2P_CLI_SCC_5_2x2] = { + [CDS_STA_MODE] = {CDS_SCC_CH_24G, CDS_24G_SCC_CH, CDS_SCC_CH_24G}, + [CDS_SAP_MODE] = {CDS_SCC_CH_24G, CDS_24G_SCC_CH, CDS_SCC_CH_24G}, + [CDS_P2P_CLIENT_MODE] = { + CDS_SCC_CH_24G, CDS_24G_SCC_CH, CDS_SCC_CH_24G}, + [CDS_P2P_GO_MODE] = {CDS_SCC_CH_24G, CDS_24G_SCC_CH, CDS_SCC_CH_24G}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_GO_P2P_CLI_MCC_5_1x1] = { + [CDS_STA_MODE] = {CDS_MCC_CH_24G, CDS_24G, CDS_24G}, + [CDS_SAP_MODE] = {CDS_24G, CDS_24G, CDS_24G}, + [CDS_P2P_CLIENT_MODE] = {CDS_MCC_CH_24G, CDS_24G, CDS_24G}, + [CDS_P2P_GO_MODE] = {CDS_MCC_CH_24G, CDS_24G, CDS_24G}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_GO_P2P_CLI_MCC_5_2x2] = { + [CDS_STA_MODE] = {CDS_MCC_CH_24G, CDS_24G, CDS_24G}, + [CDS_SAP_MODE] = {CDS_24G, CDS_24G, CDS_24G}, + [CDS_P2P_CLIENT_MODE] = {CDS_MCC_CH_24G, CDS_24G, CDS_24G}, + [CDS_P2P_GO_MODE] = {CDS_MCC_CH_24G, CDS_24G, CDS_24G}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_GO_P2P_CLI_MCC_24_5_1x1] = { + [CDS_STA_MODE] = {CDS_MCC_CH_5G, CDS_5G, CDS_5G}, + [CDS_SAP_MODE] = {CDS_24G, CDS_24G, CDS_24G}, + [CDS_P2P_CLIENT_MODE] = {CDS_MCC_CH_24G, CDS_24G, CDS_24G}, + [CDS_P2P_GO_MODE] = {CDS_MCC_CH_24G, CDS_24G, CDS_24G}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_GO_P2P_CLI_MCC_24_5_2x2] = { + [CDS_STA_MODE] = {CDS_MCC_CH_5G, CDS_5G, CDS_5G}, + [CDS_SAP_MODE] = {CDS_24G, CDS_24G, CDS_24G}, + [CDS_P2P_CLIENT_MODE] = {CDS_MCC_CH_24G, CDS_24G, CDS_24G}, + [CDS_P2P_GO_MODE] = {CDS_MCC_CH_24G, CDS_24G, CDS_24G}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_GO_P2P_CLI_DBS_1x1] = { + [CDS_STA_MODE] = { + CDS_SCC_ON_5_SCC_ON_24_5G, CDS_NONE, CDS_SCC_ON_5_SCC_ON_24}, + [CDS_SAP_MODE] = { + CDS_SCC_ON_5_SCC_ON_24_5G, CDS_NONE, CDS_SCC_ON_5_SCC_ON_24}, + [CDS_P2P_CLIENT_MODE] = { + CDS_SCC_ON_5_SCC_ON_24_5G, CDS_NONE, CDS_SCC_ON_5_SCC_ON_24}, + [CDS_P2P_GO_MODE] = { + CDS_SCC_ON_5_SCC_ON_24_5G, CDS_NONE, CDS_SCC_ON_5_SCC_ON_24}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_GO_SAP_SCC_24_1x1] = { + [CDS_STA_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_SAP_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_GO_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_GO_SAP_SCC_24_2x2] = { + [CDS_STA_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_SAP_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_GO_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_GO_SAP_MCC_24_1x1] = { + [CDS_STA_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_SAP_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_GO_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_GO_SAP_MCC_24_2x2] = { + [CDS_STA_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_SAP_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_GO_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_GO_SAP_SCC_5_1x1] = { + [CDS_STA_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_SAP_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_GO_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_GO_SAP_SCC_5_2x2] = { + [CDS_STA_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_SAP_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_GO_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_GO_SAP_MCC_5_1x1] = { + [CDS_STA_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_SAP_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_GO_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_GO_SAP_MCC_5_2x2] = { + [CDS_STA_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_SAP_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_GO_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_GO_SAP_MCC_24_5_1x1] = { + [CDS_STA_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_SAP_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_GO_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_GO_SAP_MCC_24_5_2x2] = { + [CDS_STA_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_SAP_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_GO_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_GO_SAP_DBS_1x1] = { + [CDS_STA_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_SAP_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_GO_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_CLI_SAP_SCC_24_1x1] = { + [CDS_STA_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_SAP_MODE] = {CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_GO_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_CLI_SAP_SCC_24_2x2] = { + [CDS_STA_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_SAP_MODE] = {CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_GO_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_CLI_SAP_MCC_24_1x1] = { + [CDS_STA_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_SAP_MODE] = {CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_GO_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_CLI_SAP_MCC_24_2x2] = { + [CDS_STA_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_SAP_MODE] = {CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_GO_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_CLI_SAP_SCC_5_1x1] = { + [CDS_STA_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_SAP_MODE] = {CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_GO_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_CLI_SAP_SCC_5_2x2] = { + [CDS_STA_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_SAP_MODE] = {CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_GO_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_CLI_SAP_MCC_5_1x1] = { + [CDS_STA_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_SAP_MODE] = {CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_GO_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_CLI_SAP_MCC_5_2x2] = { + [CDS_STA_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_SAP_MODE] = {CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_GO_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_CLI_SAP_MCC_24_5_1x1] = { + [CDS_STA_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_SAP_MODE] = {CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_GO_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_CLI_SAP_MCC_24_5_2x2] = { + [CDS_STA_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_SAP_MODE] = {CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_GO_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_CLI_SAP_DBS_1x1] = { + [CDS_STA_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_SAP_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_GO_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + +}; + +/** + * third_connection_pcl_nodbs_table - table which provides PCL + * for the 3rd connection, when we have two connections already + * in the system (with DBS not supported by HW) + */ +static const enum cds_pcl_type +third_connection_pcl_nodbs_table[CDS_MAX_TWO_CONNECTION_MODE] + [CDS_MAX_NUM_OF_MODE][CDS_MAX_CONC_PRIORITY_MODE] = { + [CDS_STA_SAP_SCC_24_1x1] = { + [CDS_STA_MODE] = {CDS_5G, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_SAP_MODE] = {CDS_SCC_CH_5G, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_P2P_CLIENT_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_GO_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_STA_SAP_SCC_24_2x2] = { + [CDS_STA_MODE] = {CDS_5G, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_SAP_MODE] = {CDS_SCC_CH_5G, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_P2P_CLIENT_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_GO_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_STA_SAP_MCC_24_1x1] = { + [CDS_STA_MODE] = {CDS_5G_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_SAP_MODE] = {CDS_5G_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_P2P_CLIENT_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_GO_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_STA_SAP_MCC_24_2x2] = { + [CDS_STA_MODE] = {CDS_5G_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_SAP_MODE] = {CDS_5G_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_P2P_CLIENT_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_GO_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_STA_SAP_SCC_5_1x1] = { + [CDS_STA_MODE] = {CDS_SCC_CH, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_SAP_MODE] = {CDS_SCC_CH, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_P2P_CLIENT_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_GO_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_STA_SAP_SCC_5_2x2] = { + [CDS_STA_MODE] = {CDS_SCC_CH, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_SAP_MODE] = {CDS_SCC_CH, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_P2P_CLIENT_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_GO_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_STA_SAP_MCC_5_1x1] = { + [CDS_STA_MODE] = {CDS_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_SAP_MODE] = {CDS_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_P2P_CLIENT_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_GO_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_STA_SAP_MCC_5_2x2] = { + [CDS_STA_MODE] = {CDS_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_SAP_MODE] = {CDS_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_P2P_CLIENT_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_GO_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_STA_SAP_MCC_24_5_1x1] = { + [CDS_STA_MODE] = {CDS_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_SAP_MODE] = {CDS_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_P2P_CLIENT_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_GO_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_STA_SAP_MCC_24_5_2x2] = { + [CDS_STA_MODE] = {CDS_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_SAP_MODE] = {CDS_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_P2P_CLIENT_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_GO_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_STA_SAP_DBS_1x1] = { + [CDS_STA_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_SAP_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_GO_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_STA_P2P_GO_SCC_24_1x1] = { + [CDS_STA_MODE] = {CDS_5G, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_SAP_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = {CDS_5G, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_P2P_GO_MODE] = {CDS_5G_SCC_CH, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_STA_P2P_GO_SCC_24_2x2] = { + [CDS_STA_MODE] = {CDS_5G, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_SAP_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = {CDS_5G, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_P2P_GO_MODE] = {CDS_5G_SCC_CH, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_STA_P2P_GO_MCC_24_1x1] = { + [CDS_STA_MODE] = {CDS_5G_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_SAP_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = { + CDS_5G_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_P2P_GO_MODE] = { + CDS_5G_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_STA_P2P_GO_MCC_24_2x2] = { + [CDS_STA_MODE] = {CDS_5G_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_SAP_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = { + CDS_5G_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_P2P_GO_MODE] = { + CDS_5G_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_STA_P2P_GO_SCC_5_1x1] = { + [CDS_STA_MODE] = {CDS_SCC_CH, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_SAP_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = {CDS_SCC_CH, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_P2P_GO_MODE] = {CDS_SCC_CH, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_STA_P2P_GO_SCC_5_2x2] = { + [CDS_STA_MODE] = {CDS_SCC_CH, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_SAP_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = {CDS_SCC_CH, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_P2P_GO_MODE] = {CDS_SCC_CH, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_STA_P2P_GO_MCC_5_1x1] = { + [CDS_STA_MODE] = {CDS_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_SAP_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = {CDS_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_P2P_GO_MODE] = {CDS_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_STA_P2P_GO_MCC_5_2x2] = { + [CDS_STA_MODE] = {CDS_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_SAP_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = {CDS_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_P2P_GO_MODE] = {CDS_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_STA_P2P_GO_MCC_24_5_1x1] = { + [CDS_STA_MODE] = {CDS_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_SAP_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = {CDS_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_P2P_GO_MODE] = {CDS_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_STA_P2P_GO_MCC_24_5_2x2] = { + [CDS_STA_MODE] = {CDS_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_SAP_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = {CDS_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_P2P_GO_MODE] = {CDS_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_STA_P2P_GO_DBS_1x1] = { + [CDS_STA_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_SAP_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_GO_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_STA_P2P_CLI_SCC_24_1x1] = { + [CDS_STA_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_SAP_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = {CDS_5G_SCC_CH, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_P2P_GO_MODE] = {CDS_5G_SCC_CH, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_STA_P2P_CLI_SCC_24_2x2] = { + [CDS_STA_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_SAP_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = {CDS_5G_SCC_CH, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_P2P_GO_MODE] = {CDS_5G_SCC_CH, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_STA_P2P_CLI_MCC_24_1x1] = { + [CDS_STA_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_SAP_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = {CDS_5G_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_P2P_GO_MODE] = {CDS_5G_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_STA_P2P_CLI_MCC_24_2x2] = { + [CDS_STA_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_SAP_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = {CDS_5G_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_P2P_GO_MODE] = {CDS_5G_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_STA_P2P_CLI_SCC_5_1x1] = { + [CDS_STA_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_SAP_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = {CDS_SCC_CH, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_P2P_GO_MODE] = {CDS_SCC_CH, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_STA_P2P_CLI_SCC_5_2x2] = { + [CDS_STA_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_SAP_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = {CDS_SCC_CH, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_P2P_GO_MODE] = {CDS_SCC_CH, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_STA_P2P_CLI_MCC_5_1x1] = { + [CDS_STA_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_SAP_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = {CDS_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_P2P_GO_MODE] = {CDS_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_STA_P2P_CLI_MCC_5_2x2] = { + [CDS_STA_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_SAP_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = {CDS_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_P2P_GO_MODE] = {CDS_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_STA_P2P_CLI_MCC_24_5_1x1] = { + [CDS_STA_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_SAP_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = {CDS_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_P2P_GO_MODE] = {CDS_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_STA_P2P_CLI_MCC_24_5_2x2] = { + [CDS_STA_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_SAP_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = {CDS_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_P2P_GO_MODE] = {CDS_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_STA_P2P_CLI_DBS_1x1] = { + [CDS_STA_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_SAP_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_GO_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_GO_P2P_CLI_SCC_24_1x1] = { + [CDS_STA_MODE] = {CDS_5G, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_SAP_MODE] = {CDS_SCC_CH_5G, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_P2P_CLIENT_MODE] = {CDS_5G, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_P2P_GO_MODE] = {CDS_5G_SCC_CH, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_GO_P2P_CLI_SCC_24_2x2] = { + [CDS_STA_MODE] = {CDS_5G, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_SAP_MODE] = {CDS_SCC_CH_5G, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_P2P_CLIENT_MODE] = {CDS_5G, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_P2P_GO_MODE] = {CDS_5G_SCC_CH, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_GO_P2P_CLI_MCC_24_1x1] = { + [CDS_STA_MODE] = {CDS_5G_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_SAP_MODE] = {CDS_5G_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_P2P_CLIENT_MODE] = { + CDS_5G_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_P2P_GO_MODE] = { + CDS_5G_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_GO_P2P_CLI_MCC_24_2x2] = { + [CDS_STA_MODE] = {CDS_5G_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_SAP_MODE] = {CDS_5G_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_P2P_CLIENT_MODE] = { + CDS_5G_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_P2P_GO_MODE] = { + CDS_5G_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_GO_P2P_CLI_SCC_5_1x1] = { + [CDS_STA_MODE] = {CDS_SCC_CH, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_SAP_MODE] = {CDS_SCC_CH, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_P2P_CLIENT_MODE] = {CDS_SCC_CH, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_P2P_GO_MODE] = {CDS_SCC_CH, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_GO_P2P_CLI_SCC_5_2x2] = { + [CDS_STA_MODE] = {CDS_SCC_CH, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_SAP_MODE] = {CDS_SCC_CH, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_P2P_CLIENT_MODE] = {CDS_SCC_CH, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_P2P_GO_MODE] = {CDS_SCC_CH, CDS_SCC_CH, CDS_SCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_GO_P2P_CLI_MCC_5_1x1] = { + [CDS_STA_MODE] = {CDS_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_SAP_MODE] = {CDS_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_P2P_CLIENT_MODE] = {CDS_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_P2P_GO_MODE] = {CDS_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_GO_P2P_CLI_MCC_5_2x2] = { + [CDS_STA_MODE] = {CDS_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_SAP_MODE] = {CDS_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_P2P_CLIENT_MODE] = {CDS_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_P2P_GO_MODE] = {CDS_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_GO_P2P_CLI_MCC_24_5_1x1] = { + [CDS_STA_MODE] = {CDS_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_SAP_MODE] = {CDS_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_P2P_CLIENT_MODE] = {CDS_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_P2P_GO_MODE] = {CDS_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_GO_P2P_CLI_MCC_24_5_2x2] = { + [CDS_STA_MODE] = {CDS_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_SAP_MODE] = {CDS_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_P2P_CLIENT_MODE] = {CDS_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_P2P_GO_MODE] = {CDS_MCC_CH, CDS_MCC_CH, CDS_MCC_CH}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_GO_P2P_CLI_DBS_1x1] = { + [CDS_STA_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_SAP_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_GO_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_GO_SAP_SCC_24_1x1] = { + [CDS_STA_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_SAP_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_GO_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_GO_SAP_SCC_24_2x2] = { + [CDS_STA_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_SAP_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_GO_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_GO_SAP_MCC_24_1x1] = { + [CDS_STA_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_SAP_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_GO_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_GO_SAP_MCC_24_2x2] = { + [CDS_STA_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_SAP_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_GO_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_GO_SAP_SCC_5_1x1] = { + [CDS_STA_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_SAP_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_GO_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_GO_SAP_SCC_5_2x2] = { + [CDS_STA_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_SAP_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_GO_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_GO_SAP_MCC_5_1x1] = { + [CDS_STA_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_SAP_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_GO_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_GO_SAP_MCC_5_2x2] = { + [CDS_STA_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_SAP_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_GO_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_GO_SAP_MCC_24_5_1x1] = { + [CDS_STA_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_SAP_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_GO_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_GO_SAP_MCC_24_5_2x2] = { + [CDS_STA_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_SAP_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_GO_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_GO_SAP_DBS_1x1] = { + [CDS_STA_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_SAP_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_GO_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + + [CDS_P2P_CLI_SAP_SCC_24_1x1] = { + [CDS_STA_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_SAP_MODE] = {CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_GO_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_CLI_SAP_SCC_24_2x2] = { + [CDS_STA_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_SAP_MODE] = {CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_GO_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_CLI_SAP_MCC_24_1x1] = { + [CDS_STA_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_SAP_MODE] = {CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_GO_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_CLI_SAP_MCC_24_2x2] = { + [CDS_STA_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_SAP_MODE] = {CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_GO_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_CLI_SAP_SCC_5_1x1] = { + [CDS_STA_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_SAP_MODE] = {CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_GO_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_CLI_SAP_SCC_5_2x2] = { + [CDS_STA_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_SAP_MODE] = {CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_GO_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_CLI_SAP_MCC_5_1x1] = { + [CDS_STA_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_SAP_MODE] = {CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_GO_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_CLI_SAP_MCC_5_2x2] = { + [CDS_STA_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_SAP_MODE] = {CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_GO_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_CLI_SAP_MCC_24_5_1x1] = { + [CDS_STA_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_SAP_MODE] = {CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_GO_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_CLI_SAP_MCC_24_5_2x2] = { + [CDS_STA_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_SAP_MODE] = {CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_GO_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + + [CDS_P2P_CLI_SAP_DBS_1x1] = { + [CDS_STA_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_SAP_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_CLIENT_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_P2P_GO_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE}, + [CDS_IBSS_MODE] = { + CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE, CDS_MAX_PCL_TYPE} }, + +}; + +/** + * next_action_two_connection_table - table which provides next + * action while a new connection is coming up, with one + * connection already in the system + */ +static const enum cds_conc_next_action +next_action_two_connection_table[CDS_MAX_ONE_CONNECTION_MODE][CDS_MAX_BAND] = { + [CDS_STA_24_1x1] = {CDS_NOP, CDS_DBS}, + [CDS_STA_24_2x2] = {CDS_NOP, CDS_DBS_DOWNGRADE}, + [CDS_STA_5_1x1] = {CDS_DBS, CDS_NOP}, + [CDS_STA_5_2x2] = {CDS_DBS_DOWNGRADE, CDS_NOP}, + [CDS_P2P_CLI_24_1x1] = {CDS_NOP, CDS_DBS}, + [CDS_P2P_CLI_24_2x2] = {CDS_NOP, CDS_DBS_DOWNGRADE}, + [CDS_P2P_CLI_5_1x1] = {CDS_DBS, CDS_NOP}, + [CDS_P2P_CLI_5_2x2] = {CDS_DBS_DOWNGRADE, CDS_NOP}, + [CDS_P2P_GO_24_1x1] = {CDS_NOP, CDS_DBS}, + [CDS_P2P_GO_24_2x2] = {CDS_NOP, CDS_DBS_DOWNGRADE}, + [CDS_P2P_GO_5_1x1] = {CDS_DBS, CDS_NOP}, + [CDS_P2P_GO_5_2x2] = {CDS_DBS_DOWNGRADE, CDS_NOP}, + [CDS_SAP_24_1x1] = {CDS_NOP, CDS_DBS}, + [CDS_SAP_24_2x2] = {CDS_NOP, CDS_DBS_DOWNGRADE}, + [CDS_SAP_5_1x1] = {CDS_DBS, CDS_NOP}, + [CDS_SAP_5_2x2] = {CDS_DBS_DOWNGRADE, CDS_NOP}, + [CDS_IBSS_24_1x1] = {CDS_NOP, CDS_DBS}, + [CDS_IBSS_24_2x2] = {CDS_NOP, CDS_DBS_DOWNGRADE}, + [CDS_IBSS_5_1x1] = {CDS_DBS, CDS_NOP}, + [CDS_IBSS_5_2x2] = {CDS_DBS_DOWNGRADE, CDS_NOP}, +}; + +/** + * next_action_three_connection_table - table which provides next + * action while a new connection is coming up, with two + * connections already in the system + */ +static const enum cds_conc_next_action +next_action_three_connection_table[CDS_MAX_TWO_CONNECTION_MODE] + [CDS_MAX_BAND] = { + [CDS_STA_SAP_SCC_24_1x1] = {CDS_NOP, CDS_DBS}, + [CDS_STA_SAP_SCC_24_2x2] = {CDS_NOP, CDS_DBS_DOWNGRADE}, + [CDS_STA_SAP_MCC_24_1x1] = {CDS_NOP, CDS_DBS}, + [CDS_STA_SAP_MCC_24_2x2] = {CDS_NOP, CDS_DBS_DOWNGRADE}, + [CDS_STA_SAP_SCC_5_1x1] = {CDS_DBS, CDS_NOP}, + [CDS_STA_SAP_SCC_5_2x2] = {CDS_DBS_DOWNGRADE, CDS_NOP}, + [CDS_STA_SAP_MCC_5_1x1] = {CDS_DBS, CDS_NOP}, + [CDS_STA_SAP_MCC_5_2x2] = {CDS_DBS_DOWNGRADE, CDS_NOP}, + [CDS_STA_SAP_MCC_24_5_1x1] = {CDS_DBS, CDS_DBS}, + [CDS_STA_SAP_MCC_24_5_2x2] = {CDS_DBS_DOWNGRADE, CDS_DBS_DOWNGRADE}, + [CDS_STA_SAP_DBS_1x1] = {CDS_NOP, CDS_NOP}, + [CDS_STA_P2P_GO_SCC_24_1x1] = {CDS_NOP, CDS_DBS}, + [CDS_STA_P2P_GO_SCC_24_2x2] = {CDS_NOP, CDS_DBS_DOWNGRADE}, + [CDS_STA_P2P_GO_MCC_24_1x1] = {CDS_NOP, CDS_DBS}, + [CDS_STA_P2P_GO_MCC_24_2x2] = {CDS_NOP, CDS_DBS_DOWNGRADE}, + [CDS_STA_P2P_GO_SCC_5_1x1] = {CDS_DBS, CDS_NOP}, + [CDS_STA_P2P_GO_SCC_5_2x2] = {CDS_DBS_DOWNGRADE, CDS_NOP}, + [CDS_STA_P2P_GO_MCC_5_1x1] = {CDS_DBS, CDS_NOP}, + [CDS_STA_P2P_GO_MCC_5_2x2] = {CDS_DBS_DOWNGRADE, CDS_NOP}, + [CDS_STA_P2P_GO_MCC_24_5_1x1] = {CDS_DBS, CDS_DBS}, + [CDS_STA_P2P_GO_MCC_24_5_2x2] = { + CDS_DBS_DOWNGRADE, CDS_DBS_DOWNGRADE}, + [CDS_STA_P2P_GO_DBS_1x1] = {CDS_NOP, CDS_NOP}, + [CDS_STA_P2P_CLI_SCC_24_1x1] = {CDS_NOP, CDS_DBS}, + [CDS_STA_P2P_CLI_SCC_24_2x2] = { + CDS_NOP, CDS_DBS_DOWNGRADE}, + [CDS_STA_P2P_CLI_MCC_24_1x1] = {CDS_NOP, CDS_DBS}, + [CDS_STA_P2P_CLI_MCC_24_2x2] = { + CDS_NOP, CDS_DBS_DOWNGRADE}, + [CDS_STA_P2P_CLI_SCC_5_1x1] = {CDS_DBS, CDS_NOP}, + [CDS_STA_P2P_CLI_SCC_5_2x2] = {CDS_DBS_DOWNGRADE, CDS_NOP}, + [CDS_STA_P2P_CLI_MCC_5_1x1] = {CDS_DBS, CDS_NOP}, + [CDS_STA_P2P_CLI_MCC_5_2x2] = {CDS_DBS_DOWNGRADE, CDS_NOP}, + [CDS_STA_P2P_CLI_MCC_24_5_1x1] = {CDS_DBS, CDS_DBS}, + [CDS_STA_P2P_CLI_MCC_24_5_2x2] = { + CDS_DBS_DOWNGRADE, CDS_DBS_DOWNGRADE}, + [CDS_STA_P2P_CLI_DBS_1x1] = {CDS_NOP, CDS_NOP}, + [CDS_P2P_GO_P2P_CLI_SCC_24_1x1] = {CDS_NOP, CDS_DBS}, + [CDS_P2P_GO_P2P_CLI_SCC_24_2x2] = { + CDS_NOP, CDS_DBS_DOWNGRADE}, + [CDS_P2P_GO_P2P_CLI_MCC_24_1x1] = {CDS_NOP, CDS_DBS}, + [CDS_P2P_GO_P2P_CLI_MCC_24_2x2] = { + CDS_NOP, CDS_DBS_DOWNGRADE}, + [CDS_P2P_GO_P2P_CLI_SCC_5_1x1] = {CDS_DBS, CDS_NOP}, + [CDS_P2P_GO_P2P_CLI_SCC_5_2x2] = {CDS_DBS_DOWNGRADE, CDS_NOP}, + [CDS_P2P_GO_P2P_CLI_MCC_5_1x1] = {CDS_DBS, CDS_NOP}, + [CDS_P2P_GO_P2P_CLI_MCC_5_2x2] = {CDS_DBS_DOWNGRADE, CDS_NOP}, + [CDS_P2P_GO_P2P_CLI_MCC_24_5_1x1] = {CDS_DBS, CDS_DBS}, + [CDS_P2P_GO_P2P_CLI_MCC_24_5_2x2] = { + CDS_DBS_DOWNGRADE, CDS_DBS_DOWNGRADE}, + [CDS_P2P_GO_P2P_CLI_DBS_1x1] = {CDS_NOP, CDS_NOP}, + [CDS_P2P_GO_SAP_SCC_24_1x1] = {CDS_NOP, CDS_DBS}, + [CDS_P2P_GO_SAP_SCC_24_2x2] = {CDS_NOP, CDS_DBS_DOWNGRADE}, + [CDS_P2P_GO_SAP_MCC_24_1x1] = {CDS_NOP, CDS_DBS}, + [CDS_P2P_GO_SAP_MCC_24_2x2] = {CDS_NOP, CDS_DBS_DOWNGRADE}, + [CDS_P2P_GO_SAP_SCC_5_1x1] = {CDS_DBS, CDS_NOP}, + [CDS_P2P_GO_SAP_SCC_5_2x2] = {CDS_DBS_DOWNGRADE, CDS_NOP}, + [CDS_P2P_GO_SAP_MCC_5_1x1] = {CDS_DBS, CDS_NOP}, + [CDS_P2P_GO_SAP_MCC_5_2x2] = {CDS_DBS_DOWNGRADE, CDS_NOP}, + [CDS_P2P_GO_SAP_MCC_24_5_1x1] = {CDS_DBS, CDS_DBS}, + [CDS_P2P_GO_SAP_MCC_24_5_2x2] = { + CDS_DBS_DOWNGRADE, CDS_DBS_DOWNGRADE}, + [CDS_P2P_GO_SAP_DBS_1x1] = {CDS_NOP, CDS_NOP}, + [CDS_P2P_CLI_SAP_SCC_24_1x1] = {CDS_NOP, CDS_DBS}, + [CDS_P2P_CLI_SAP_SCC_24_2x2] = {CDS_NOP, CDS_DBS_DOWNGRADE}, + [CDS_P2P_CLI_SAP_MCC_24_1x1] = {CDS_NOP, CDS_DBS}, + [CDS_P2P_CLI_SAP_MCC_24_2x2] = {CDS_NOP, CDS_DBS_DOWNGRADE}, + [CDS_P2P_CLI_SAP_SCC_5_1x1] = {CDS_DBS, CDS_NOP}, + [CDS_P2P_CLI_SAP_SCC_5_2x2] = {CDS_DBS_DOWNGRADE, CDS_NOP}, + [CDS_P2P_CLI_SAP_MCC_5_1x1] = {CDS_DBS, CDS_NOP}, + [CDS_P2P_CLI_SAP_MCC_5_2x2] = {CDS_DBS_DOWNGRADE, CDS_NOP}, + [CDS_P2P_CLI_SAP_MCC_24_5_1x1] = {CDS_DBS, CDS_DBS}, + [CDS_P2P_CLI_SAP_MCC_24_5_2x2] = {CDS_DBS_DOWNGRADE, CDS_DBS_DOWNGRADE}, + [CDS_P2P_CLI_SAP_DBS_1x1] = {CDS_NOP, CDS_NOP}, + +}; + +/** + * cds_get_connection_count() - provides the count of + * current connections + * + * This function provides the count of current connections + * + * Return: connection count + */ +uint32_t cds_get_connection_count(void) +{ + uint32_t conn_index, count = 0; + cds_context_type *cds_ctx; + + cds_ctx = cds_get_context(QDF_MODULE_ID_QDF); + if (!cds_ctx) { + cds_err("Invalid CDS Context"); + return count; + } + + qdf_mutex_acquire(&cds_ctx->qdf_conc_list_lock); + for (conn_index = 0; conn_index < MAX_NUMBER_OF_CONC_CONNECTIONS; + conn_index++) { + if (conc_connection_list[conn_index].in_use) + count++; + } + qdf_mutex_release(&cds_ctx->qdf_conc_list_lock); + + return count; +} + +/** + * cds_is_sta_connection_pending() - This function will check if sta connection + * is pending or not. + * + * This function will return the status of flag is_sta_connection_pending + * + * Return: true or false + */ +bool cds_is_sta_connection_pending(void) +{ + bool status; + hdd_context_t *hdd_ctx; + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (!hdd_ctx) { + cds_err("HDD context is NULL"); + return false; + } + + qdf_spin_lock(&hdd_ctx->sta_update_info_lock); + status = hdd_ctx->is_sta_connection_pending; + qdf_spin_unlock(&hdd_ctx->sta_update_info_lock); + return status; +} + +/** + * cds_change_sta_conn_pending_status() - This function will change the value + * of is_sta_connection_pending + * @value: value to set + * + * This function will change the value of is_sta_connection_pending + * + * Return: none + */ +void cds_change_sta_conn_pending_status(bool value) +{ + hdd_context_t *hdd_ctx; + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (!hdd_ctx) { + cds_err("HDD context is NULL"); + return; + } + + qdf_spin_lock(&hdd_ctx->sta_update_info_lock); + hdd_ctx->is_sta_connection_pending = value; + qdf_spin_unlock(&hdd_ctx->sta_update_info_lock); +} + +/** + * cds_is_sap_restart_required() - This function will check if sap restart + * is pending or not. + * + * This function will return the status of flag is_sap_restart_required. + * + * Return: true or false + */ +static bool cds_is_sap_restart_required(void) +{ + bool status; + hdd_context_t *hdd_ctx; + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (!hdd_ctx) { + cds_err("HDD context is NULL"); + return false; + } + + qdf_spin_lock(&hdd_ctx->sap_update_info_lock); + status = hdd_ctx->is_sap_restart_required; + qdf_spin_unlock(&hdd_ctx->sap_update_info_lock); + return status; +} + +/** + * cds_change_sap_restart_required_status() - This function will change the + * value of is_sap_restart_required + * @value: value to set + * + * This function will change the value of is_sap_restart_required + * + * Return: none + */ +void cds_change_sap_restart_required_status(bool value) +{ + hdd_context_t *hdd_ctx; + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (!hdd_ctx) { + cds_err("HDD context is NULL"); + return; + } + + qdf_spin_lock(&hdd_ctx->sap_update_info_lock); + hdd_ctx->is_sap_restart_required = value; + qdf_spin_unlock(&hdd_ctx->sap_update_info_lock); +} + +/** + * cds_set_connection_in_progress() - to set the connection in progress flag + * @value: value to set + * + * This function will set the passed value to connection in progress flag. + * If value is previously being set to true then no need to set it again. + * + * Return: true if value is being set correctly and false otherwise. + */ +bool cds_set_connection_in_progress(bool value) +{ + bool status = true; + hdd_context_t *hdd_ctx; + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (!hdd_ctx) { + cds_err("HDD context is NULL"); + return false; + } + + qdf_spin_lock(&hdd_ctx->connection_status_lock); + /* + * if the value is set to true previously and if someone is + * trying to make it true again then it could be some race + * condition being triggered. Avoid this situation by returning + * false + */ + if (hdd_ctx->connection_in_progress && value) + status = false; + else + hdd_ctx->connection_in_progress = value; + qdf_spin_unlock(&hdd_ctx->connection_status_lock); + return status; +} + +/** + * cds_update_conc_list() - Update the concurrent connection list + * @conn_index: Connection index + * @mode: Mode + * @chan: Channel + * @bw: Bandwidth + * @mac: Mac id + * @chain_mask: Chain mask + * @vdev_id: vdev id + * @in_use: Flag to indicate if the index is in use or not + * + * Updates the index value of the concurrent connection list + * + * Return: None + */ +static void cds_update_conc_list(uint32_t conn_index, + enum cds_con_mode mode, + uint8_t chan, + enum hw_mode_bandwidth bw, + uint8_t mac, + enum cds_chain_mode chain_mask, + uint32_t original_nss, + uint32_t vdev_id, + bool in_use) +{ + cds_context_type *cds_ctx; + + cds_ctx = cds_get_context(QDF_MODULE_ID_QDF); + if (!cds_ctx) { + cds_err("Invalid CDS Context"); + return; + } + + if (conn_index >= MAX_NUMBER_OF_CONC_CONNECTIONS) { + cds_err("Number of connections exceeded conn_index: %d", + conn_index); + return; + } + conc_connection_list[conn_index].mode = mode; + conc_connection_list[conn_index].chan = chan; + conc_connection_list[conn_index].bw = bw; + conc_connection_list[conn_index].mac = mac; + conc_connection_list[conn_index].chain_mask = chain_mask; + conc_connection_list[conn_index].original_nss = original_nss; + conc_connection_list[conn_index].vdev_id = vdev_id; + conc_connection_list[conn_index].in_use = in_use; + + cds_dump_connection_status_info(); + if (cds_ctx->ol_txrx_update_mac_id_cb) + cds_ctx->ol_txrx_update_mac_id_cb(vdev_id, mac); + +} + +/** + * cds_mode_specific_vdev_id() - provides the + * vdev id of specific mode + * @mode: type of connection + * + * This function provides the vdev id of specific mode + * + * Note: This gives the first vdev id of the mode type in a + * sta+sta or sap+sap or p2p + p2p case + * + * Return: vdev id of specific type or CDS_INVALID_VDEV_ID if no vdev + * found for the given mode + */ +uint32_t cds_mode_specific_vdev_id(enum cds_con_mode mode) +{ + uint32_t conn_index; + uint32_t vdev_id = CDS_INVALID_VDEV_ID; + cds_context_type *cds_ctx; + + cds_ctx = cds_get_context(QDF_MODULE_ID_QDF); + if (!cds_ctx) { + cds_err("Invalid CDS Context"); + return vdev_id; + } + qdf_mutex_acquire(&cds_ctx->qdf_conc_list_lock); + for (conn_index = 0; conn_index < MAX_NUMBER_OF_CONC_CONNECTIONS; + conn_index++) { + if ((conc_connection_list[conn_index].mode == mode) && + conc_connection_list[conn_index].in_use) { + vdev_id = conc_connection_list[conn_index].vdev_id; + break; + } + } + qdf_mutex_release(&cds_ctx->qdf_conc_list_lock); + return vdev_id; +} + +/** + * cds_mode_specific_connection_count() - provides the + * count of connections of specific mode + * @mode: type of connection + * @list: To provide the indices on conc_connection_list + * (optional) + * + * This function provides the count of current connections + * + * Return: connection count of specific type + */ +uint32_t cds_mode_specific_connection_count(enum cds_con_mode mode, + uint32_t *list) +{ + uint32_t conn_index = 0, count = 0; + cds_context_type *cds_ctx; + + cds_ctx = cds_get_context(QDF_MODULE_ID_QDF); + if (!cds_ctx) { + cds_err("Invalid CDS Context"); + return count; + } + qdf_mutex_acquire(&cds_ctx->qdf_conc_list_lock); + for (conn_index = 0; conn_index < MAX_NUMBER_OF_CONC_CONNECTIONS; + conn_index++) { + if ((conc_connection_list[conn_index].mode == mode) && + conc_connection_list[conn_index].in_use) { + if (list != NULL) + list[count] = conn_index; + count++; + } + } + qdf_mutex_release(&cds_ctx->qdf_conc_list_lock); + return count; +} + +QDF_STATUS cds_check_conn_with_mode_and_vdev_id(enum cds_con_mode mode, + uint32_t vdev_id) +{ + QDF_STATUS qdf_status = QDF_STATUS_E_FAILURE; + uint32_t conn_index = 0; + cds_context_type *cds_ctx; + + cds_ctx = cds_get_context(QDF_MODULE_ID_QDF); + if (!cds_ctx) { + cds_err("Invalid CDS Context"); + return qdf_status; + } + qdf_mutex_acquire(&cds_ctx->qdf_conc_list_lock); + while (CONC_CONNECTION_LIST_VALID_INDEX(conn_index)) { + if ((conc_connection_list[conn_index].mode == mode) && + (conc_connection_list[conn_index].vdev_id == vdev_id)) { + qdf_status = QDF_STATUS_SUCCESS; + break; + } + conn_index++; + } + qdf_mutex_release(&cds_ctx->qdf_conc_list_lock); + return qdf_status; +} + +/** + * cds_store_and_del_conn_info() - Store and del a connection info + * @mode: Mode whose entry has to be deleted + * @info: Struture pointer where the connection info will be saved + * + * Saves the connection info corresponding to the provided mode + * and deleted that corresponding entry based on vdev from the + * connection info structure + * + * Return: None + */ +static void cds_store_and_del_conn_info(enum cds_con_mode mode, + struct cds_conc_connection_info *info) +{ + uint32_t conn_index = 0; + bool found = false; + cds_context_type *cds_ctx; + + qdf_mem_zero(info, sizeof(*info)); + cds_ctx = cds_get_context(QDF_MODULE_ID_QDF); + if (!cds_ctx) { + cds_err("Invalid CDS Context"); + return; + } + + qdf_mutex_acquire(&cds_ctx->qdf_conc_list_lock); + while (CONC_CONNECTION_LIST_VALID_INDEX(conn_index)) { + if (mode == conc_connection_list[conn_index].mode) { + found = true; + break; + } + conn_index++; + } + + if (!found) { + qdf_mutex_release(&cds_ctx->qdf_conc_list_lock); + cds_err("Mode:%d not available in the conn info", mode); + return; + } + + /* Storing the STA entry which will be temporarily deleted */ + *info = conc_connection_list[conn_index]; + qdf_mutex_release(&cds_ctx->qdf_conc_list_lock); + + /* Deleting the STA entry */ + cds_decr_connection_count(info->vdev_id); + + cds_info("Stored %d (%d), deleted STA entry with vdev id %d, index %d", + info->vdev_id, info->mode, info->vdev_id, conn_index); + + /* Caller should set the PCL and restore the STA entry in conn info */ +} + +/** + * cds_restore_deleted_conn_info() - Restore connection info + * @info: Saved connection info that is to be restored + * + * Restores the connection info of STA that was saved before + * updating the PCL to the FW + * + * Return: None + */ +static void cds_restore_deleted_conn_info( + struct cds_conc_connection_info *info) +{ + uint32_t conn_index; + cds_context_type *cds_ctx; + + cds_ctx = cds_get_context(QDF_MODULE_ID_QDF); + if (!cds_ctx) { + cds_err("Invalid CDS Context"); + return; + } + + conn_index = cds_get_connection_count(); + if (MAX_NUMBER_OF_CONC_CONNECTIONS <= conn_index) { + cds_err("Failed to restore the deleted information %d/%d", + conn_index, MAX_NUMBER_OF_CONC_CONNECTIONS); + return; + } + + qdf_mutex_acquire(&cds_ctx->qdf_conc_list_lock); + conc_connection_list[conn_index] = *info; + qdf_mutex_release(&cds_ctx->qdf_conc_list_lock); + + cds_info("Restored the deleleted conn info, vdev:%d, index:%d", + info->vdev_id, conn_index); +} + +/** + * cds_update_hw_mode_conn_info() - Update connection info based on HW mode + * @num_vdev_mac_entries: Number of vdev-mac id entries that follow + * @vdev_mac_map: Mapping of vdev-mac id + * @hw_mode: HW mode + * + * Updates the connection info parameters based on the new HW mode + * + * Return: None + */ +static void cds_update_hw_mode_conn_info(uint32_t num_vdev_mac_entries, + struct sir_vdev_mac_map *vdev_mac_map, + struct sir_hw_mode_params hw_mode) +{ + uint32_t i, conn_index, found; + cds_context_type *cds_ctx; + + cds_ctx = cds_get_context(QDF_MODULE_ID_QDF); + if (!cds_ctx) { + cds_err("Invalid CDS Context"); + return; + } + + qdf_mutex_acquire(&cds_ctx->qdf_conc_list_lock); + for (i = 0; i < num_vdev_mac_entries; i++) { + conn_index = 0; + found = 0; + while (CONC_CONNECTION_LIST_VALID_INDEX(conn_index)) { + if (vdev_mac_map[i].vdev_id == + conc_connection_list[conn_index].vdev_id) { + found = 1; + break; + } + conn_index++; + } + if (found) { + conc_connection_list[conn_index].mac = + vdev_mac_map[i].mac_id; + cds_info("vdev:%d, mac:%d", + conc_connection_list[conn_index].vdev_id, + conc_connection_list[conn_index].mac); + if (cds_ctx->ol_txrx_update_mac_id_cb) + cds_ctx->ol_txrx_update_mac_id_cb( + vdev_mac_map[i].vdev_id, + vdev_mac_map[i].mac_id); + } + } + qdf_mutex_release(&cds_ctx->qdf_conc_list_lock); + cds_dump_connection_status_info(); +} + +/** + * cds_soc_set_dual_mac_cfg_cb() - Callback for set dual mac config + * @status: Status of set dual mac config + * @scan_config: Current scan config whose status is the first param + * @fw_mode_config: Current FW mode config whose status is the first param + * + * Callback on setting the dual mac configuration + * + * Return: None + */ +void cds_soc_set_dual_mac_cfg_cb(enum set_hw_mode_status status, + uint32_t scan_config, + uint32_t fw_mode_config) +{ + cds_info("Status:%d for scan_config:%x fw_mode_config:%x", + status, scan_config, fw_mode_config); +} + +/** + * cds_set_dual_mac_scan_config() - Set the dual MAC scan config + * @dbs_val: Value of DBS bit + * @dbs_plus_agile_scan_val: Value of DBS plus agile scan bit + * @single_mac_scan_with_dbs_val: Value of Single MAC scan with DBS + * + * Set the values of scan config. For FW mode config, the existing values + * will be retained + * + * Return: None + */ +void cds_set_dual_mac_scan_config(uint8_t dbs_val, + uint8_t dbs_plus_agile_scan_val, + uint8_t single_mac_scan_with_dbs_val) +{ + struct sir_dual_mac_config cfg; + QDF_STATUS status; + hdd_context_t *hdd_ctx; + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (!hdd_ctx) { + cds_err("HDD context is NULL"); + return; + } + + /* Any non-zero positive value is treated as 1 */ + if (dbs_val != 0) + dbs_val = 1; + if (dbs_plus_agile_scan_val != 0) + dbs_plus_agile_scan_val = 1; + if (single_mac_scan_with_dbs_val != 0) + single_mac_scan_with_dbs_val = 1; + + status = wma_get_updated_scan_config(&cfg.scan_config, + dbs_val, + dbs_plus_agile_scan_val, + single_mac_scan_with_dbs_val); + if (status != QDF_STATUS_SUCCESS) { + cds_err("wma_get_updated_scan_config failed %d", status); + return; + } + + status = wma_get_updated_fw_mode_config(&cfg.fw_mode_config, + wma_get_dbs_config(), + wma_get_agile_dfs_config()); + if (status != QDF_STATUS_SUCCESS) { + cds_err("wma_get_updated_fw_mode_config failed %d", status); + return; + } + + cfg.set_dual_mac_cb = (void *)cds_soc_set_dual_mac_cfg_cb; + + cds_info("scan_config:%x fw_mode_config:%x", + cfg.scan_config, cfg.fw_mode_config); + + status = sme_soc_set_dual_mac_config(hdd_ctx->hHal, cfg); + if (status != QDF_STATUS_SUCCESS) { + cds_err("sme_soc_set_dual_mac_config failed %d", status); + return; + } +} + +/** + * cds_set_dual_mac_fw_mode_config() - Set the dual mac FW mode config + * @dbs: DBS bit + * @dfs: Agile DFS bit + * + * Set the values of fw mode config. For scan config, the existing values + * will be retain. + * + * Return: None + */ +void cds_set_dual_mac_fw_mode_config(uint8_t dbs, uint8_t dfs) +{ + struct sir_dual_mac_config cfg; + QDF_STATUS status; + hdd_context_t *hdd_ctx; + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (!hdd_ctx) { + cds_err("HDD context is NULL"); + return; + } + + /* Any non-zero positive value is treated as 1 */ + if (dbs != 0) + dbs = 1; + if (dfs != 0) + dfs = 1; + + status = wma_get_updated_scan_config(&cfg.scan_config, + wma_get_dbs_scan_config(), + wma_get_dbs_plus_agile_scan_config(), + wma_get_single_mac_scan_with_dfs_config()); + if (status != QDF_STATUS_SUCCESS) { + cds_err("wma_get_updated_scan_config failed %d", status); + return; + } + + status = wma_get_updated_fw_mode_config(&cfg.fw_mode_config, + dbs, dfs); + if (status != QDF_STATUS_SUCCESS) { + cds_err("wma_get_updated_fw_mode_config failed %d", status); + return; + } + + cfg.set_dual_mac_cb = (void *)cds_soc_set_dual_mac_cfg_cb; + + cds_info("scan_config:%x fw_mode_config:%x", + cfg.scan_config, cfg.fw_mode_config); + + status = sme_soc_set_dual_mac_config(hdd_ctx->hHal, cfg); + if (status != QDF_STATUS_SUCCESS) { + cds_err("sme_soc_set_dual_mac_config failed %d", status); + return; + } +} + +/** + * cds_pdev_set_hw_mode_cb() - Callback for set hw mode + * @status: Status + * @cfgd_hw_mode_index: Configured HW mode index + * @num_vdev_mac_entries: Number of vdev-mac id mapping that follows + * @vdev_mac_map: vdev-mac id map. This memory will be freed by the caller. + * So, make local copy if needed. + * + * Provides the status and configured hw mode index set + * by the FW + * + * Return: None + */ +static void cds_pdev_set_hw_mode_cb(uint32_t status, + uint32_t cfgd_hw_mode_index, + uint32_t num_vdev_mac_entries, + struct sir_vdev_mac_map *vdev_mac_map) +{ + QDF_STATUS ret; + struct sir_hw_mode_params hw_mode; + uint32_t i; + + cds_set_hw_mode_change_in_progress(CDS_HW_MODE_NOT_IN_PROGRESS); + + if (status != SET_HW_MODE_STATUS_OK) { + cds_err("Set HW mode failed with status %d", status); + return; + } + + if (!vdev_mac_map) { + cds_err("vdev_mac_map is NULL"); + return; + } + + cds_info("cfgd_hw_mode_index=%d", cfgd_hw_mode_index); + + for (i = 0; i < num_vdev_mac_entries; i++) + cds_info("vdev_id:%d mac_id:%d", + vdev_mac_map[i].vdev_id, + vdev_mac_map[i].mac_id); + + ret = wma_get_hw_mode_from_idx(cfgd_hw_mode_index, &hw_mode); + if (ret != QDF_STATUS_SUCCESS) { + cds_err("Get HW mode failed: %d", ret); + return; + } + + cds_info("MAC0: TxSS:%d, RxSS:%d, Bw:%d", + hw_mode.mac0_tx_ss, hw_mode.mac0_rx_ss, hw_mode.mac0_bw); + cds_info("MAC1: TxSS:%d, RxSS:%d, Bw:%d", + hw_mode.mac1_tx_ss, hw_mode.mac1_rx_ss, hw_mode.mac1_bw); + cds_info("DBS:%d, Agile DFS:%d, SBS:%d", + hw_mode.dbs_cap, hw_mode.agile_dfs_cap, hw_mode.sbs_cap); + + /* update conc_connection_list */ + cds_update_hw_mode_conn_info(num_vdev_mac_entries, + vdev_mac_map, + hw_mode); + + ret = qdf_set_connection_update(); + if (!QDF_IS_STATUS_SUCCESS(ret)) + cds_err("ERROR: set connection_update_done event failed"); + + return; +} + +/** + * cds_hw_mode_transition_cb() - Callback for HW mode transition from FW + * @old_hw_mode_index: Old HW mode index + * @new_hw_mode_index: New HW mode index + * @num_vdev_mac_entries: Number of vdev-mac id mapping that follows + * @vdev_mac_map: vdev-mac id map. This memory will be freed by the caller. + * So, make local copy if needed. + * + * Provides the old and new HW mode index set by the FW + * + * Return: None + */ +void cds_hw_mode_transition_cb(uint32_t old_hw_mode_index, + uint32_t new_hw_mode_index, + uint32_t num_vdev_mac_entries, + struct sir_vdev_mac_map *vdev_mac_map) +{ + QDF_STATUS status; + struct sir_hw_mode_params hw_mode; + uint32_t i; + + if (!vdev_mac_map) { + cds_err("vdev_mac_map is NULL"); + return; + } + + cds_info("old_hw_mode_index=%d, new_hw_mode_index=%d", + old_hw_mode_index, new_hw_mode_index); + + for (i = 0; i < num_vdev_mac_entries; i++) + cds_info("vdev_id:%d mac_id:%d", + vdev_mac_map[i].vdev_id, + vdev_mac_map[i].mac_id); + + status = wma_get_hw_mode_from_idx(new_hw_mode_index, &hw_mode); + if (status != QDF_STATUS_SUCCESS) { + cds_err("Get HW mode failed: %d", status); + return; + } + + cds_info("MAC0: TxSS:%d, RxSS:%d, Bw:%d", + hw_mode.mac0_tx_ss, hw_mode.mac0_rx_ss, hw_mode.mac0_bw); + cds_info("MAC1: TxSS:%d, RxSS:%d, Bw:%d", + hw_mode.mac1_tx_ss, hw_mode.mac1_rx_ss, hw_mode.mac1_bw); + cds_info("DBS:%d, Agile DFS:%d, SBS:%d", + hw_mode.dbs_cap, hw_mode.agile_dfs_cap, hw_mode.sbs_cap); + + /* update conc_connection_list */ + cds_update_hw_mode_conn_info(num_vdev_mac_entries, + vdev_mac_map, + hw_mode); + + return; +} + +/** + * cds_pdev_set_hw_mode() - Set HW mode command to SME + * @session_id: Session ID + * @mac0_ss: MAC0 spatial stream configuration + * @mac0_bw: MAC0 bandwidth configuration + * @mac1_ss: MAC1 spatial stream configuration + * @mac1_bw: MAC1 bandwidth configuration + * @dbs: HW DBS capability + * @dfs: HW Agile DFS capability + * @sbs: HW SBS capability + * @reason: Reason for connection update + * + * Sends the set hw mode to the SME module which will pass on + * this message to WMA layer + * + * e.g.: To configure 2x2_80 + * mac0_ss = HW_MODE_SS_2x2, mac0_bw = HW_MODE_80_MHZ + * mac1_ss = HW_MODE_SS_0x0, mac1_bw = HW_MODE_BW_NONE + * dbs = HW_MODE_DBS_NONE, dfs = HW_MODE_AGILE_DFS_NONE, + * sbs = HW_MODE_SBS_NONE + * e.g.: To configure 1x1_80_1x1_40 (DBS) + * mac0_ss = HW_MODE_SS_1x1, mac0_bw = HW_MODE_80_MHZ + * mac1_ss = HW_MODE_SS_1x1, mac1_bw = HW_MODE_40_MHZ + * dbs = HW_MODE_DBS, dfs = HW_MODE_AGILE_DFS_NONE, + * sbs = HW_MODE_SBS_NONE + * e.g.: To configure 1x1_80_1x1_40 (Agile DFS) + * mac0_ss = HW_MODE_SS_1x1, mac0_bw = HW_MODE_80_MHZ + * mac1_ss = HW_MODE_SS_1x1, mac1_bw = HW_MODE_40_MHZ + * dbs = HW_MODE_DBS, dfs = HW_MODE_AGILE_DFS, + * sbs = HW_MODE_SBS_NONE + * + * Return: Success if the message made it down to the next layer + */ +QDF_STATUS cds_pdev_set_hw_mode(uint32_t session_id, + enum hw_mode_ss_config mac0_ss, + enum hw_mode_bandwidth mac0_bw, + enum hw_mode_ss_config mac1_ss, + enum hw_mode_bandwidth mac1_bw, + enum hw_mode_dbs_capab dbs, + enum hw_mode_agile_dfs_capab dfs, + enum hw_mode_sbs_capab sbs, + enum sir_conn_update_reason reason) +{ + int8_t hw_mode_index; + struct sir_hw_mode msg; + QDF_STATUS status; + hdd_context_t *hdd_ctx; + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (!hdd_ctx) { + cds_err("Invalid HDD context"); + return QDF_STATUS_E_FAILURE; + } + + /* + * if HW is not capable of doing 2x2 or ini config disabled 2x2, don't + * allow to request FW for 2x2 + */ + if ((HW_MODE_SS_2x2 == mac0_ss) && (!hdd_ctx->config->enable2x2)) { + cds_info("2x2 is not allowed downgrading to 1x1 for mac0"); + mac0_ss = HW_MODE_SS_1x1; + } + if ((HW_MODE_SS_2x2 == mac1_ss) && (!hdd_ctx->config->enable2x2)) { + cds_info("2x2 is not allowed downgrading to 1x1 for mac1"); + mac1_ss = HW_MODE_SS_1x1; + } + + hw_mode_index = wma_get_hw_mode_idx_from_dbs_hw_list(mac0_ss, + mac0_bw, mac1_ss, mac1_bw, dbs, dfs, sbs); + if (hw_mode_index < 0) { + cds_err("Invalid HW mode index obtained"); + return QDF_STATUS_E_FAILURE; + } + + msg.hw_mode_index = hw_mode_index; + msg.set_hw_mode_cb = (void *)cds_pdev_set_hw_mode_cb; + msg.reason = reason; + msg.session_id = session_id; + + cds_info("set hw mode to sme: hw_mode_index: %d session:%d reason:%d", + msg.hw_mode_index, msg.session_id, msg.reason); + + status = sme_pdev_set_hw_mode(hdd_ctx->hHal, msg); + if (status != QDF_STATUS_SUCCESS) { + cds_err("Failed to set hw mode to SME"); + return status; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * cds_is_connection_in_progress() - check if connection is in progress + * @session_id: session id + * @reason: scan reject reason + * + * Go through each adapter and check if Connection is in progress + * + * Return: true if connection is in progress else false + */ +bool cds_is_connection_in_progress(uint8_t *session_id, + scan_reject_states *reason) +{ + hdd_adapter_list_node_t *adapter_node = NULL, *next = NULL; + hdd_station_ctx_t *hdd_sta_ctx = NULL; + hdd_adapter_t *adapter = NULL; + QDF_STATUS status = 0; + uint8_t sta_id = 0; + uint8_t *sta_mac = NULL; + hdd_context_t *hdd_ctx; + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (!hdd_ctx) { + cds_err("HDD context is NULL"); + return false; + } + + status = hdd_get_front_adapter(hdd_ctx, &adapter_node); + while (NULL != adapter_node && QDF_STATUS_SUCCESS == status) { + adapter = adapter_node->pAdapter; + if (!adapter) + goto end; + + cds_info("Adapter with device mode %s(%d) exists", + hdd_device_mode_to_string(adapter->device_mode), + adapter->device_mode); + if (((QDF_STA_MODE == adapter->device_mode) + || (QDF_P2P_CLIENT_MODE == adapter->device_mode) + || (QDF_P2P_DEVICE_MODE == adapter->device_mode)) + && (eConnectionState_Connecting == + (WLAN_HDD_GET_STATION_CTX_PTR(adapter))-> + conn_info.connState)) { + cds_err("%p(%d) Connection is in progress", + WLAN_HDD_GET_STATION_CTX_PTR(adapter), + adapter->sessionId); + if (session_id && reason) { + *session_id = adapter->sessionId; + *reason = eHDD_CONNECTION_IN_PROGRESS; + } + return true; + } + /* + * sme_neighbor_middle_of_roaming is for LFR2 + * hdd_is_roaming_in_progress is for LFR3 + */ + if (((QDF_STA_MODE == adapter->device_mode) && + sme_neighbor_middle_of_roaming( + WLAN_HDD_GET_HAL_CTX(adapter), + adapter->sessionId)) || + hdd_is_roaming_in_progress(adapter)) { + cds_err("%p(%d) Reassociation in progress", + WLAN_HDD_GET_STATION_CTX_PTR(adapter), + adapter->sessionId); + if (session_id && reason) { + *session_id = adapter->sessionId; + *reason = eHDD_REASSOC_IN_PROGRESS; + } + return true; + } + if ((QDF_STA_MODE == adapter->device_mode) || + (QDF_P2P_CLIENT_MODE == adapter->device_mode) || + (QDF_P2P_DEVICE_MODE == adapter->device_mode)) { + hdd_sta_ctx = + WLAN_HDD_GET_STATION_CTX_PTR(adapter); + if ((eConnectionState_Associated == + hdd_sta_ctx->conn_info.connState) + && (false == + hdd_sta_ctx->conn_info.uIsAuthenticated)) { + sta_mac = (uint8_t *) + &(adapter->macAddressCurrent.bytes[0]); + cds_err("client " MAC_ADDRESS_STR + " is in middle of WPS/EAPOL exchange.", + MAC_ADDR_ARRAY(sta_mac)); + if (session_id && reason) { + *session_id = adapter->sessionId; + *reason = eHDD_EAPOL_IN_PROGRESS; + } + return true; + } + } else if ((QDF_SAP_MODE == adapter->device_mode) || + (QDF_P2P_GO_MODE == adapter->device_mode)) { + for (sta_id = 0; sta_id < WLAN_MAX_STA_COUNT; + sta_id++) { + if (!((adapter->aStaInfo[sta_id].isUsed) + && (OL_TXRX_PEER_STATE_CONN == + adapter->aStaInfo[sta_id].tlSTAState))) + continue; + + sta_mac = (uint8_t *) + &(adapter->aStaInfo[sta_id]. + macAddrSTA.bytes[0]); + cds_err("client " MAC_ADDRESS_STR + " of SAP/GO is in middle of WPS/EAPOL exchange", + MAC_ADDR_ARRAY(sta_mac)); + if (session_id && reason) { + *session_id = adapter->sessionId; + *reason = eHDD_SAP_EAPOL_IN_PROGRESS; + } + return true; + } + if (hdd_ctx->connection_in_progress) { + cds_err("AP/GO: connection is in progress"); + return true; + } + } +end: + status = hdd_get_next_adapter(hdd_ctx, adapter_node, &next); + adapter_node = next; + } + return false; +} + +/** + * cds_dump_current_concurrency_one_connection() - To dump the + * current concurrency info with one connection + * @cc_mode: connection string + * @length: Maximum size of the string + * + * This routine is called to dump the concurrency info + * + * Return: length of the string + */ +static uint32_t cds_dump_current_concurrency_one_connection(char *cc_mode, + uint32_t length) +{ + uint32_t count = 0; + enum cds_con_mode mode; + cds_context_type *cds_ctx; + + cds_ctx = cds_get_context(QDF_MODULE_ID_QDF); + if (!cds_ctx) { + cds_err("Invalid CDS Context"); + return count; + } + + mode = conc_connection_list[0].mode; + + switch (mode) { + case CDS_STA_MODE: + count = strlcat(cc_mode, "STA", + length); + break; + case CDS_SAP_MODE: + count = strlcat(cc_mode, "SAP", + length); + break; + case CDS_P2P_CLIENT_MODE: + count = strlcat(cc_mode, "P2P CLI", + length); + break; + case CDS_P2P_GO_MODE: + count = strlcat(cc_mode, "P2P GO", + length); + break; + case CDS_IBSS_MODE: + count = strlcat(cc_mode, "IBSS", + length); + break; + default: + cds_err("unexpected mode %d", mode); + break; + } + return count; +} + +/** + * cds_dump_current_concurrency_two_connection() - To dump the + * current concurrency info with two connections + * @cc_mode: connection string + * @length: Maximum size of the string + * + * This routine is called to dump the concurrency info + * + * Return: length of the string + */ +static uint32_t cds_dump_current_concurrency_two_connection(char *cc_mode, + uint32_t length) +{ + uint32_t count = 0; + enum cds_con_mode mode; + cds_context_type *cds_ctx; + + cds_ctx = cds_get_context(QDF_MODULE_ID_QDF); + if (!cds_ctx) { + cds_err("Invalid CDS Context"); + return count; + } + + mode = conc_connection_list[1].mode; + + switch (mode) { + case CDS_STA_MODE: + count = cds_dump_current_concurrency_one_connection( + cc_mode, length); + count += strlcat(cc_mode, "+STA", + length); + break; + case CDS_SAP_MODE: + count = cds_dump_current_concurrency_one_connection( + cc_mode, length); + count += strlcat(cc_mode, "+SAP", + length); + break; + case CDS_P2P_CLIENT_MODE: + count = cds_dump_current_concurrency_one_connection( + cc_mode, length); + count += strlcat(cc_mode, "+P2P CLI", + length); + break; + case CDS_P2P_GO_MODE: + count = cds_dump_current_concurrency_one_connection( + cc_mode, length); + count += strlcat(cc_mode, "+P2P GO", + length); + break; + case CDS_IBSS_MODE: + count = cds_dump_current_concurrency_one_connection( + cc_mode, length); + count += strlcat(cc_mode, "+IBSS", + length); + break; + default: + cds_err("unexpected mode %d", mode); + break; + } + return count; +} + +/** + * cds_dump_current_concurrency_three_connection() - To dump the + * current concurrency info with three connections + * @cc_mode: connection string + * @length: Maximum size of the string + * + * This routine is called to dump the concurrency info + * + * Return: length of the string + */ +static uint32_t cds_dump_current_concurrency_three_connection(char *cc_mode, + uint32_t length) +{ + uint32_t count = 0; + enum cds_con_mode mode; + cds_context_type *cds_ctx; + + cds_ctx = cds_get_context(QDF_MODULE_ID_QDF); + if (!cds_ctx) { + cds_err("Invalid CDS Context"); + return count; + } + + mode = conc_connection_list[2].mode; + + switch (mode) { + case CDS_STA_MODE: + count = cds_dump_current_concurrency_two_connection( + cc_mode, length); + count += strlcat(cc_mode, "+STA", + length); + break; + case CDS_SAP_MODE: + count = cds_dump_current_concurrency_two_connection( + cc_mode, length); + count += strlcat(cc_mode, "+SAP", + length); + break; + case CDS_P2P_CLIENT_MODE: + count = cds_dump_current_concurrency_two_connection( + cc_mode, length); + count += strlcat(cc_mode, "+P2P CLI", + length); + break; + case CDS_P2P_GO_MODE: + count = cds_dump_current_concurrency_two_connection( + cc_mode, length); + count += strlcat(cc_mode, "+P2P GO", + length); + break; + case CDS_IBSS_MODE: + count = cds_dump_current_concurrency_two_connection( + cc_mode, length); + count += strlcat(cc_mode, "+IBSS", + length); + break; + default: + cds_err("unexpected mode %d", mode); + break; + } + return count; +} + +/** + * cds_dump_dbs_concurrency() - To dump the dbs concurrency + * combination + * @cc_mode: connection string + * + * This routine is called to dump the concurrency info + * + * Return: None + */ +static void cds_dump_dbs_concurrency(char *cc_mode, uint32_t length) +{ + char buf[4] = {0}; + uint8_t mac = 0; + cds_context_type *cds_ctx; + + cds_ctx = cds_get_context(QDF_MODULE_ID_QDF); + if (!cds_ctx) { + cds_err("Invalid CDS Context"); + return; + } + + strlcat(cc_mode, " DBS", length); + qdf_mutex_acquire(&cds_ctx->qdf_conc_list_lock); + if (conc_connection_list[0].mac == + conc_connection_list[1].mac) { + if (conc_connection_list[0].chan == + conc_connection_list[1].chan) + strlcat(cc_mode, + " with SCC for 1st two connections on mac ", + length); + else + strlcat(cc_mode, + " with MCC for 1st two connections on mac ", + length); + mac = conc_connection_list[0].mac; + } + if (conc_connection_list[0].mac == conc_connection_list[2].mac) { + if (conc_connection_list[0].chan == + conc_connection_list[2].chan) + strlcat(cc_mode, + " with SCC for 1st & 3rd connections on mac ", + length); + else + strlcat(cc_mode, + " with MCC for 1st & 3rd connections on mac ", + length); + mac = conc_connection_list[0].mac; + } + if (conc_connection_list[1].mac == conc_connection_list[2].mac) { + if (conc_connection_list[1].chan == + conc_connection_list[2].chan) + strlcat(cc_mode, + " with SCC for 2nd & 3rd connections on mac ", + length); + else + strlcat(cc_mode, + " with MCC for 2nd & 3rd connections on mac ", + length); + mac = conc_connection_list[1].mac; + } + qdf_mutex_release(&cds_ctx->qdf_conc_list_lock); + snprintf(buf, sizeof(buf), "%d ", mac); + strlcat(cc_mode, buf, length); +} + +/** + * cds_dump_current_concurrency() - To dump the current + * concurrency combination + * + * This routine is called to dump the concurrency info + * + * Return: None + */ +static void cds_dump_current_concurrency(void) +{ + uint32_t num_connections = 0; + char cc_mode[CDS_MAX_CON_STRING_LEN] = {0}; + uint32_t count = 0; + cds_context_type *cds_ctx; + + cds_ctx = cds_get_context(QDF_MODULE_ID_QDF); + if (!cds_ctx) { + cds_err("Invalid CDS Context"); + return; + } + + num_connections = cds_get_connection_count(); + + switch (num_connections) { + case 1: + cds_dump_current_concurrency_one_connection(cc_mode, + sizeof(cc_mode)); + cds_err("%s Standalone", cc_mode); + break; + case 2: + count = cds_dump_current_concurrency_two_connection( + cc_mode, sizeof(cc_mode)); + qdf_mutex_acquire(&cds_ctx->qdf_conc_list_lock); + if (conc_connection_list[0].chan == + conc_connection_list[1].chan) { + strlcat(cc_mode, " SCC", sizeof(cc_mode)); + } else if (conc_connection_list[0].mac == + conc_connection_list[1].mac) { + strlcat(cc_mode, " MCC", sizeof(cc_mode)); + } else + strlcat(cc_mode, " DBS", sizeof(cc_mode)); + qdf_mutex_release(&cds_ctx->qdf_conc_list_lock); + cds_err("%s", cc_mode); + break; + case 3: + count = cds_dump_current_concurrency_three_connection( + cc_mode, sizeof(cc_mode)); + qdf_mutex_acquire(&cds_ctx->qdf_conc_list_lock); + if ((conc_connection_list[0].chan == + conc_connection_list[1].chan) && + (conc_connection_list[0].chan == + conc_connection_list[2].chan)){ + qdf_mutex_release(&cds_ctx->qdf_conc_list_lock); + strlcat(cc_mode, " SCC", + sizeof(cc_mode)); + } else if ((conc_connection_list[0].mac == + conc_connection_list[1].mac) + && (conc_connection_list[0].mac == + conc_connection_list[2].mac)) { + qdf_mutex_release(&cds_ctx->qdf_conc_list_lock); + strlcat(cc_mode, " MCC on single MAC", + sizeof(cc_mode)); + } else { + qdf_mutex_release(&cds_ctx->qdf_conc_list_lock); + cds_dump_dbs_concurrency(cc_mode, sizeof(cc_mode)); + } + cds_err("%s", cc_mode); + break; + default: + cds_err("unexpected num_connections value %d", + num_connections); + break; + } + + return; +} + +/** + * cds_current_concurrency_is_mcc() - To check the current + * concurrency combination if it is doing MCC + * + * This routine is called to check if it is doing MCC + * + * Return: True - MCC, False - Otherwise + */ +static bool cds_current_concurrency_is_mcc(void) +{ + uint32_t num_connections = 0; + bool is_mcc = false; + + num_connections = cds_get_connection_count(); + + switch (num_connections) { + case 1: + break; + case 2: + if ((conc_connection_list[0].chan != + conc_connection_list[1].chan) && + (conc_connection_list[0].mac == + conc_connection_list[1].mac)) { + is_mcc = true; + } + break; + case 3: + if ((conc_connection_list[0].chan != + conc_connection_list[1].chan) || + (conc_connection_list[0].chan != + conc_connection_list[2].chan) || + (conc_connection_list[1].chan != + conc_connection_list[2].chan)){ + is_mcc = true; + } + break; + default: + cds_err("unexpected num_connections value %d", + num_connections); + break; + } + + return is_mcc; +} + +/** + * cds_dump_concurrency_info() - To dump concurrency info + * + * This routine is called to dump the concurrency info + * + * Return: None + */ +void cds_dump_concurrency_info(void) +{ + hdd_adapter_list_node_t *adapterNode = NULL, *pNext = NULL; + QDF_STATUS status; + hdd_adapter_t *adapter; + hdd_station_ctx_t *pHddStaCtx; + hdd_ap_ctx_t *hdd_ap_ctx; + hdd_hostapd_state_t *hostapd_state; + struct qdf_mac_addr staBssid = QDF_MAC_ADDR_ZERO_INITIALIZER; + struct qdf_mac_addr p2pBssid = QDF_MAC_ADDR_ZERO_INITIALIZER; + struct qdf_mac_addr apBssid = QDF_MAC_ADDR_ZERO_INITIALIZER; + uint8_t staChannel = 0, p2pChannel = 0, apChannel = 0; + const char *p2pMode = "DEV"; + hdd_context_t *hdd_ctx; + cds_context_type *cds_ctx; +#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL + uint8_t targetChannel = 0; + uint8_t preAdapterChannel = 0; + uint8_t channel24; + uint8_t channel5; + hdd_adapter_t *preAdapterContext = NULL; + hdd_adapter_t *adapter2_4 = NULL; + hdd_adapter_t *adapter5 = NULL; +#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */ + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (!hdd_ctx) { + cds_err("HDD context is NULL"); + return; + } + + cds_ctx = cds_get_context(QDF_MODULE_ID_QDF); + if (!cds_ctx) { + cds_err("Invalid CDS Context"); + return; + } + + status = hdd_get_front_adapter(hdd_ctx, &adapterNode); + while (NULL != adapterNode && QDF_STATUS_SUCCESS == status) { + adapter = adapterNode->pAdapter; + switch (adapter->device_mode) { + case QDF_STA_MODE: + pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + if (eConnectionState_Associated == + pHddStaCtx->conn_info.connState) { + staChannel = + pHddStaCtx->conn_info.operationChannel; + qdf_copy_macaddr(&staBssid, + &pHddStaCtx->conn_info.bssId); +#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL + targetChannel = staChannel; +#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */ + } + break; + case QDF_P2P_CLIENT_MODE: + pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + if (eConnectionState_Associated == + pHddStaCtx->conn_info.connState) { + p2pChannel = + pHddStaCtx->conn_info.operationChannel; + qdf_copy_macaddr(&p2pBssid, + &pHddStaCtx->conn_info.bssId); + p2pMode = "CLI"; +#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL + targetChannel = p2pChannel; +#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */ + } + break; + case QDF_P2P_GO_MODE: + hdd_ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(adapter); + hostapd_state = WLAN_HDD_GET_HOSTAP_STATE_PTR(adapter); + if (hostapd_state->bssState == BSS_START + && hostapd_state->qdf_status == + QDF_STATUS_SUCCESS) { + p2pChannel = hdd_ap_ctx->operatingChannel; + qdf_copy_macaddr(&p2pBssid, + &adapter->macAddressCurrent); +#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL + targetChannel = p2pChannel; +#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */ + } + p2pMode = "GO"; + break; + case QDF_SAP_MODE: + hdd_ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(adapter); + hostapd_state = WLAN_HDD_GET_HOSTAP_STATE_PTR(adapter); + if (hostapd_state->bssState == BSS_START + && hostapd_state->qdf_status == + QDF_STATUS_SUCCESS) { + apChannel = hdd_ap_ctx->operatingChannel; + qdf_copy_macaddr(&apBssid, + &adapter->macAddressCurrent); +#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL + targetChannel = apChannel; +#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */ + } + break; + case QDF_IBSS_MODE: + default: + break; + } +#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL + if (targetChannel) { + /* + * This is first adapter detected as active + * set as default for none concurrency case + */ + if (!preAdapterChannel) { + /* If IPA UC data path is enabled, + * target should reserve extra tx descriptors + * for IPA data path. + * Then host data path should allow less TX + * packet pumping in case IPA + * data path enabled + */ + if (hdd_ipa_uc_is_enabled(hdd_ctx) && + (QDF_SAP_MODE == adapter->device_mode)) { + adapter->tx_flow_low_watermark = + hdd_ctx->config->TxFlowLowWaterMark + + WLAN_TFC_IPAUC_TX_DESC_RESERVE; + } else { + adapter->tx_flow_low_watermark = + hdd_ctx->config-> + TxFlowLowWaterMark; + } + adapter->tx_flow_high_watermark_offset = + hdd_ctx->config->TxFlowHighWaterMarkOffset; + ol_txrx_ll_set_tx_pause_q_depth( + adapter->sessionId, + hdd_ctx->config->TxFlowMaxQueueDepth); + cds_info("MODE %d,CH %d,LWM %d,HWM %d,TXQDEP %d", + adapter->device_mode, + targetChannel, + adapter->tx_flow_low_watermark, + adapter->tx_flow_low_watermark + + adapter->tx_flow_high_watermark_offset, + hdd_ctx->config->TxFlowMaxQueueDepth); + preAdapterChannel = targetChannel; + preAdapterContext = adapter; + } else { + /* + * SCC, disable TX flow control for both + * SCC each adapter cannot reserve dedicated + * channel resource, as a result, if any adapter + * blocked OS Q by flow control, + * blocked adapter will lost chance to recover + */ + if (preAdapterChannel == targetChannel) { + /* Current adapter */ + adapter->tx_flow_low_watermark = 0; + adapter-> + tx_flow_high_watermark_offset = 0; + ol_txrx_ll_set_tx_pause_q_depth( + adapter->sessionId, + hdd_ctx->config-> + TxHbwFlowMaxQueueDepth); + cds_info("SCC: MODE %s(%d), CH %d, LWM %d, HWM %d, TXQDEP %d", + hdd_device_mode_to_string( + adapter->device_mode), + adapter->device_mode, + targetChannel, + adapter->tx_flow_low_watermark, + adapter->tx_flow_low_watermark + + adapter-> + tx_flow_high_watermark_offset, + hdd_ctx->config-> + TxHbwFlowMaxQueueDepth); + + if (!preAdapterContext) { + cds_err("SCC: Previous adapter context NULL"); + continue; + } + + /* Previous adapter */ + preAdapterContext-> + tx_flow_low_watermark = 0; + preAdapterContext-> + tx_flow_high_watermark_offset = 0; + ol_txrx_ll_set_tx_pause_q_depth( + preAdapterContext->sessionId, + hdd_ctx->config-> + TxHbwFlowMaxQueueDepth); + cds_info("SCC: MODE %s(%d), CH %d, LWM %d, HWM %d, TXQDEP %d", + hdd_device_mode_to_string( + preAdapterContext->device_mode + ), + preAdapterContext->device_mode, + targetChannel, + preAdapterContext-> + tx_flow_low_watermark, + preAdapterContext-> + tx_flow_low_watermark + + preAdapterContext-> + tx_flow_high_watermark_offset, + hdd_ctx->config-> + TxHbwFlowMaxQueueDepth); + } + /* + * MCC, each adapter will have dedicated + * resource + */ + else { + /* current channel is 2.4 */ + if (targetChannel <= + WLAN_HDD_TX_FLOW_CONTROL_MAX_24BAND_CH) { + channel24 = targetChannel; + channel5 = preAdapterChannel; + adapter2_4 = adapter; + adapter5 = preAdapterContext; + } else { + /* Current channel is 5 */ + channel24 = preAdapterChannel; + channel5 = targetChannel; + adapter2_4 = preAdapterContext; + adapter5 = adapter; + } + + if (!adapter5) { + cds_err("MCC: 5GHz adapter context NULL"); + continue; + } + adapter5->tx_flow_low_watermark = + hdd_ctx->config-> + TxHbwFlowLowWaterMark; + adapter5-> + tx_flow_high_watermark_offset = + hdd_ctx->config-> + TxHbwFlowHighWaterMarkOffset; + ol_txrx_ll_set_tx_pause_q_depth( + adapter5->sessionId, + hdd_ctx->config-> + TxHbwFlowMaxQueueDepth); + cds_info("MCC: MODE %s(%d), CH %d, LWM %d, HWM %d, TXQDEP %d", + hdd_device_mode_to_string( + adapter5->device_mode), + adapter5->device_mode, + channel5, + adapter5->tx_flow_low_watermark, + adapter5-> + tx_flow_low_watermark + + adapter5-> + tx_flow_high_watermark_offset, + hdd_ctx->config-> + TxHbwFlowMaxQueueDepth); + + if (!adapter2_4) { + cds_err("MCC: 2.4GHz adapter context NULL"); + continue; + } + adapter2_4->tx_flow_low_watermark = + hdd_ctx->config-> + TxLbwFlowLowWaterMark; + adapter2_4-> + tx_flow_high_watermark_offset = + hdd_ctx->config-> + TxLbwFlowHighWaterMarkOffset; + ol_txrx_ll_set_tx_pause_q_depth( + adapter2_4->sessionId, + hdd_ctx->config-> + TxLbwFlowMaxQueueDepth); + cds_info("MCC: MODE %s(%d), CH %d, LWM %d, HWM %d, TXQDEP %d", + hdd_device_mode_to_string( + adapter2_4->device_mode), + adapter2_4->device_mode, + channel24, + adapter2_4-> + tx_flow_low_watermark, + adapter2_4-> + tx_flow_low_watermark + + adapter2_4-> + tx_flow_high_watermark_offset, + hdd_ctx->config-> + TxLbwFlowMaxQueueDepth); + + } + } + } + targetChannel = 0; +#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */ + status = hdd_get_next_adapter(hdd_ctx, adapterNode, &pNext); + adapterNode = pNext; + } + qdf_mutex_acquire(&cds_ctx->qdf_conc_list_lock); + hdd_ctx->mcc_mode = cds_current_concurrency_is_mcc(); + qdf_mutex_release(&cds_ctx->qdf_conc_list_lock); +} + +#ifdef FEATURE_WLAN_TDLS +/* + * cds_check_is_tdls_allowed() - check is tdls allowed or not + * @adapter: pointer to adapter + * + * Function determines the whether TDLS allowed in the system + * + * Return: true or false + */ +bool cds_check_is_tdls_allowed(enum tQDF_ADAPTER_MODE device_mode) +{ + bool state = false; + uint32_t count; + + count = cds_get_connection_count(); + + if (count > 1) + state = false; + else if (device_mode == QDF_STA_MODE || + device_mode == QDF_P2P_CLIENT_MODE) + state = true; + + /* If any concurrency is detected */ + if (!state) + cds_dump_concurrency_info(); + + return state; +} + +/** + * cds_set_tdls_ct_mode() - Set the tdls connection tracker mode + * @hdd_ctx: hdd context + * + * This routine is called to set the tdls connection tracker operation status + * + * Return: NONE + */ +void cds_set_tdls_ct_mode(hdd_context_t *hdd_ctx) +{ + bool state = false; + + /* If any concurrency is detected, skip tdls pkt tracker */ + if (cds_get_connection_count() > 1) { + state = false; + goto set_state; + } + + if (eTDLS_SUPPORT_DISABLED == hdd_ctx->tdls_mode || + eTDLS_SUPPORT_NOT_ENABLED == hdd_ctx->tdls_mode || + (!hdd_ctx->config->fEnableTDLSImplicitTrigger)) { + state = false; + goto set_state; + } else if (cds_mode_specific_connection_count(QDF_STA_MODE, + NULL) == 1) { + state = true; + } else if (cds_mode_specific_connection_count(QDF_P2P_CLIENT_MODE, + NULL) == 1){ + state = true; + } else { + state = false; + goto set_state; + } + + /* In case of TDLS external control, peer should be added + * by the user space to start connection tracker. + */ + if (hdd_ctx->config->fTDLSExternalControl) { + if (hdd_ctx->tdls_external_peer_count) + state = true; + else + state = false; + } + +set_state: + mutex_lock(&hdd_ctx->tdls_lock); + hdd_ctx->enable_tdls_connection_tracker = state; + mutex_unlock(&hdd_ctx->tdls_lock); + + cds_info("enable_tdls_connection_tracker %d", + hdd_ctx->enable_tdls_connection_tracker); +} +#endif + +/** + * cds_set_concurrency_mode() - To set concurrency mode + * @mode: adapter mode + * + * This routine is called to set the concurrency mode + * + * Return: NONE + */ +void cds_set_concurrency_mode(enum tQDF_ADAPTER_MODE mode) +{ + hdd_context_t *hdd_ctx; + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (!hdd_ctx) { + cds_err("HDD context is NULL"); + return; + } + + switch (mode) { + case QDF_STA_MODE: + case QDF_P2P_CLIENT_MODE: + case QDF_P2P_GO_MODE: + case QDF_SAP_MODE: + case QDF_IBSS_MODE: + case QDF_MONITOR_MODE: + hdd_ctx->concurrency_mode |= (1 << mode); + hdd_ctx->no_of_open_sessions[mode]++; + break; + default: + break; + } + + cds_info("concurrency_mode = 0x%x Number of open sessions for mode %d = %d", + hdd_ctx->concurrency_mode, mode, + hdd_ctx->no_of_open_sessions[mode]); + + hdd_green_ap_start_bss(hdd_ctx); +} + +/** + * cds_clear_concurrency_mode() - To clear concurrency mode + * @mode: adapter mode + * + * This routine is called to clear the concurrency mode + * + * Return: NONE + */ +void cds_clear_concurrency_mode(enum tQDF_ADAPTER_MODE mode) +{ + hdd_context_t *hdd_ctx; + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (!hdd_ctx) { + cds_err("HDD context is NULL"); + return; + } + + switch (mode) { + case QDF_STA_MODE: + case QDF_P2P_CLIENT_MODE: + case QDF_P2P_GO_MODE: + case QDF_SAP_MODE: + case QDF_MONITOR_MODE: + hdd_ctx->no_of_open_sessions[mode]--; + if (!(hdd_ctx->no_of_open_sessions[mode])) + hdd_ctx->concurrency_mode &= (~(1 << mode)); + break; + default: + break; + } + + cds_info("concurrency_mode = 0x%x Number of open sessions for mode %d = %d", + hdd_ctx->concurrency_mode, mode, + hdd_ctx->no_of_open_sessions[mode]); + + hdd_green_ap_start_bss(hdd_ctx); +} + +/** + * cds_pdev_set_pcl() - Sets PCL to FW + * @mode: adapter mode + * + * Fetches the PCL and sends the PCL to SME + * module which in turn will send the WMI + * command WMI_PDEV_SET_PCL_CMDID to the fw + * + * Return: None + */ +static void cds_pdev_set_pcl(enum tQDF_ADAPTER_MODE mode) +{ + QDF_STATUS status; + enum cds_con_mode con_mode; + struct sir_pcl_list pcl; + hdd_context_t *hdd_ctx; + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (!hdd_ctx) { + cds_err("HDD context is NULL"); + return; + } + pcl.pcl_len = 0; + + switch (mode) { + case QDF_STA_MODE: + con_mode = CDS_STA_MODE; + break; + case QDF_P2P_CLIENT_MODE: + con_mode = CDS_P2P_CLIENT_MODE; + break; + case QDF_P2P_GO_MODE: + con_mode = CDS_P2P_GO_MODE; + break; + case QDF_SAP_MODE: + con_mode = CDS_SAP_MODE; + break; + case QDF_IBSS_MODE: + con_mode = CDS_IBSS_MODE; + break; + default: + cds_err("Unable to set PCL to FW: %d", mode); + return; + } + + cds_debug("get pcl to set it to the FW"); + + status = cds_get_pcl(con_mode, + pcl.pcl_list, &pcl.pcl_len, + pcl.weight_list, QDF_ARRAY_SIZE(pcl.weight_list)); + if (status != QDF_STATUS_SUCCESS) { + cds_err("Unable to set PCL to FW, Get PCL failed"); + return; + } + + status = sme_pdev_set_pcl(hdd_ctx->hHal, pcl); + if (status != QDF_STATUS_SUCCESS) + cds_err("Send soc set PCL to SME failed"); + else + cds_info("Set PCL to FW for mode:%d", mode); +} + + +/** + * cds_set_pcl_for_existing_combo() - Set PCL for existing connection + * @mode: Connection mode of type 'cds_con_mode' + * + * Set the PCL for an existing connection + * + * Return: None + */ +static void cds_set_pcl_for_existing_combo(enum cds_con_mode mode) +{ + struct cds_conc_connection_info info; + enum tQDF_ADAPTER_MODE pcl_mode; + cds_context_type *cds_ctx; + + cds_ctx = cds_get_context(QDF_MODULE_ID_QDF); + if (!cds_ctx) { + cds_err("Invalid CDS Context"); + return; + } + switch (mode) { + case CDS_STA_MODE: + pcl_mode = QDF_STA_MODE; + break; + case CDS_SAP_MODE: + pcl_mode = QDF_SAP_MODE; + break; + case CDS_P2P_CLIENT_MODE: + pcl_mode = QDF_P2P_CLIENT_MODE; + break; + case CDS_P2P_GO_MODE: + pcl_mode = QDF_P2P_GO_MODE; + break; + case CDS_IBSS_MODE: + pcl_mode = QDF_IBSS_MODE; + break; + default: + cds_err("Invalid mode to set PCL"); + return; + }; + qdf_mutex_acquire(&cds_ctx->qdf_conc_list_lock); + if (cds_mode_specific_connection_count(mode, NULL) > 0) { + /* Check, store and temp delete the mode's parameter */ + cds_store_and_del_conn_info(mode, &info); + qdf_mutex_release(&cds_ctx->qdf_conc_list_lock); + /* Set the PCL to the FW since connection got updated */ + cds_pdev_set_pcl(pcl_mode); + cds_info("Set PCL to FW for mode:%d", mode); + /* Restore the connection info */ + qdf_mutex_acquire(&cds_ctx->qdf_conc_list_lock); + cds_restore_deleted_conn_info(&info); + } + qdf_mutex_release(&cds_ctx->qdf_conc_list_lock); +} + +/** + * cds_incr_active_session() - increments the number of active sessions + * @mode: Adapter mode + * @session_id: session ID for the connection session + * + * This function increments the number of active sessions maintained per device + * mode. In the case of STA/P2P CLI/IBSS upon connection indication it is + * incremented; In the case of SAP/P2P GO upon bss start it is incremented + * + * Return: None + */ +void cds_incr_active_session(enum tQDF_ADAPTER_MODE mode, + uint8_t session_id) +{ + hdd_context_t *hdd_ctx; + cds_context_type *cds_ctx; + hdd_adapter_t *sap_adapter; + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (!hdd_ctx) { + cds_err("HDD context is NULL"); + return; + } + + cds_ctx = cds_get_context(QDF_MODULE_ID_QDF); + if (!cds_ctx) { + cds_err("Invalid CDS Context"); + return; + } + + /* + * Need to aquire mutex as entire functionality in this function + * is in critical section + */ + qdf_mutex_acquire(&cds_ctx->qdf_conc_list_lock); + switch (mode) { + case QDF_STA_MODE: + case QDF_P2P_CLIENT_MODE: + case QDF_P2P_GO_MODE: + case QDF_SAP_MODE: + case QDF_IBSS_MODE: + hdd_ctx->no_of_active_sessions[mode]++; + break; + default: + break; + } + + + cds_info("No.# of active sessions for mode %d = %d", + mode, hdd_ctx->no_of_active_sessions[mode]); + /* + * Get PCL logic makes use of the connection info structure. + * Let us set the PCL to the FW before updating the connection + * info structure about the new connection. + */ + if (mode == QDF_STA_MODE) { + qdf_mutex_release(&cds_ctx->qdf_conc_list_lock); + /* Set PCL of STA to the FW */ + cds_pdev_set_pcl(mode); + qdf_mutex_acquire(&cds_ctx->qdf_conc_list_lock); + cds_info("Set PCL of STA to FW"); + } + cds_incr_connection_count(session_id); + if ((cds_mode_specific_connection_count(CDS_STA_MODE, NULL) > 0) && + (mode != QDF_STA_MODE)) { + qdf_mutex_release(&cds_ctx->qdf_conc_list_lock); + cds_set_pcl_for_existing_combo(CDS_STA_MODE); + qdf_mutex_acquire(&cds_ctx->qdf_conc_list_lock); + } + + /** + * Disable LRO if P2P or IBSS or SAP connection has come up or + * there are more than one STA connections + */ + if ((cds_mode_specific_connection_count(CDS_STA_MODE, NULL) > 1) || + (cds_mode_specific_connection_count(CDS_SAP_MODE, NULL) > 0) || + (cds_mode_specific_connection_count(CDS_P2P_CLIENT_MODE, NULL) > + 0) || + (cds_mode_specific_connection_count(CDS_P2P_GO_MODE, NULL) > 0) || + (cds_mode_specific_connection_count(CDS_IBSS_MODE, NULL) > 0)) { + if (cds_ctx->hdd_disable_lro_in_cc_cb != NULL) + cds_ctx->hdd_disable_lro_in_cc_cb(hdd_ctx); + else + cds_warn("hdd_disable_lro_in_cc_cb NULL!"); + }; + + /* Enable RPS if SAP interface has come up */ + if (cds_mode_specific_connection_count(CDS_SAP_MODE, NULL) == 1) { + if (cds_ctx->hdd_set_rx_mode_rps_cb != NULL) { + sap_adapter = hdd_get_adapter(hdd_ctx, QDF_SAP_MODE); + if (sap_adapter != NULL) + cds_ctx->hdd_set_rx_mode_rps_cb(hdd_ctx, + sap_adapter, + true); + } else { + cds_warn("hdd_set_rx_mode_rps_cb NULL!"); + } + }; + + hdd_update_tdls_ct_and_teardown_links(hdd_ctx); + cds_dump_current_concurrency(); + + qdf_mutex_release(&cds_ctx->qdf_conc_list_lock); +} + +/** + * cds_need_opportunistic_upgrade() - Tells us if we really + * need an upgrade to 2x2 + * + * This function returns if updrade to 2x2 is needed + * + * Return: CDS_NOP = upgrade is not needed, otherwise upgrade is + * needed + */ +enum cds_conc_next_action cds_need_opportunistic_upgrade(void) +{ + uint32_t conn_index; + enum cds_conc_next_action upgrade = CDS_NOP; + uint8_t mac = 0; + struct sir_hw_mode_params hw_mode; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + cds_context_type *cds_ctx; + + cds_ctx = cds_get_context(QDF_MODULE_ID_QDF); + if (!cds_ctx) { + cds_err("Invalid CDS Context"); + goto done; + } + + if (wma_is_hw_dbs_capable() == false) { + cds_err("driver isn't dbs capable, no further action needed"); + goto done; + } + + status = wma_get_current_hw_mode(&hw_mode); + if (!QDF_IS_STATUS_SUCCESS(status)) { + cds_err("wma_get_current_hw_mode failed"); + goto done; + } + if (!hw_mode.dbs_cap) { + cds_info("current HW mode is non-DBS capable"); + goto done; + } + + qdf_mutex_acquire(&cds_ctx->qdf_conc_list_lock); + /* Are both mac's still in use */ + for (conn_index = 0; conn_index < MAX_NUMBER_OF_CONC_CONNECTIONS; + conn_index++) { + cds_debug("index:%d mac:%d in_use:%d chan:%d org_nss:%d", + conn_index, + conc_connection_list[conn_index].mac, + conc_connection_list[conn_index].in_use, + conc_connection_list[conn_index].chan, + conc_connection_list[conn_index].original_nss); + if ((conc_connection_list[conn_index].mac == 0) && + conc_connection_list[conn_index].in_use) { + mac |= CDS_MAC0; + if (CDS_MAC0_AND_MAC1 == mac) { + qdf_mutex_release(&cds_ctx->qdf_conc_list_lock); + goto done; + } + } else if ((conc_connection_list[conn_index].mac == 1) && + conc_connection_list[conn_index].in_use) { + mac |= CDS_MAC1; + if (CDS_MAC0_AND_MAC1 == mac) { + qdf_mutex_release(&cds_ctx->qdf_conc_list_lock); + goto done; + } + } + } + /* Let's request for single MAC mode */ + upgrade = CDS_SINGLE_MAC; + /* Is there any connection had an initial connection with 2x2 */ + for (conn_index = 0; conn_index < MAX_NUMBER_OF_CONC_CONNECTIONS; + conn_index++) { + if ((conc_connection_list[conn_index].original_nss == 2) && + conc_connection_list[conn_index].in_use) { + upgrade = CDS_SINGLE_MAC_UPGRADE; + qdf_mutex_release(&cds_ctx->qdf_conc_list_lock); + goto done; + } + } + qdf_mutex_release(&cds_ctx->qdf_conc_list_lock); + +done: + return upgrade; +} + +/** + * cds_get_pcl_for_existing_conn() - Get PCL for existing connection + * @mode: Connection mode of type 'cds_con_mode' + * @pcl_ch: Pointer to the PCL + * @len: Pointer to the length of the PCL + * @pcl_weight: Pointer to the weights of the PCL + * @weight_len: Max length of the weights list + * + * Get the PCL for an existing connection + * + * Return: None + */ +QDF_STATUS cds_get_pcl_for_existing_conn(enum cds_con_mode mode, + uint8_t *pcl_ch, uint32_t *len, + uint8_t *pcl_weight, uint32_t weight_len) +{ + struct cds_conc_connection_info info; + + cds_context_type *cds_ctx; + QDF_STATUS status = QDF_STATUS_SUCCESS; + cds_ctx = cds_get_context(QDF_MODULE_ID_QDF); + if (!cds_ctx) { + cds_err("Invalid CDS Context"); + return QDF_STATUS_E_INVAL; + } + + cds_info("get pcl for existing conn:%d", mode); + qdf_mutex_acquire(&cds_ctx->qdf_conc_list_lock); + if (cds_mode_specific_connection_count(mode, NULL) > 0) { + /* Check, store and temp delete the mode's parameter */ + cds_store_and_del_conn_info(mode, &info); + qdf_mutex_release(&cds_ctx->qdf_conc_list_lock); + /* Get the PCL */ + status = cds_get_pcl(mode, pcl_ch, len, pcl_weight, weight_len); + cds_info("Get PCL to FW for mode:%d", mode); + /* Restore the connection info */ + qdf_mutex_acquire(&cds_ctx->qdf_conc_list_lock); + cds_restore_deleted_conn_info(&info); + } + qdf_mutex_release(&cds_ctx->qdf_conc_list_lock); + return status; +} + +/** + * cds_decr_session_set_pcl() - Decrement session count and set PCL + * @mode: Adapter mode + * @session_id: Session id + * + * Decrements the active session count and sets the PCL if a STA connection + * exists + * + * Return: None + */ +void cds_decr_session_set_pcl(enum tQDF_ADAPTER_MODE mode, + uint8_t session_id) +{ + QDF_STATUS qdf_status; + cds_context_type *cds_ctx; + + cds_ctx = cds_get_context(QDF_MODULE_ID_QDF); + if (!cds_ctx) { + cds_err("Invalid CDS Context"); + return; + } + + qdf_status = cds_decr_active_session(mode, session_id); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + cds_err("Invalid active session"); + return; + } + + /* + * After the removal of this connection, we need to check if + * a STA connection still exists. The reason for this is that + * if one or more STA exists, we need to provide the updated + * PCL to the FW for cases like LFR. + * + * Since cds_get_pcl provides PCL list based on the new + * connection that is going to come up, we will find the + * existing STA entry, save it and delete it temporarily. + * After this we will get PCL as though as new STA connection + * is coming up. This will give the exact PCL that needs to be + * given to the FW. After setting the PCL, we need to restore + * the entry that we have saved before. + */ + cds_set_pcl_for_existing_combo(CDS_STA_MODE); + /* do we need to change the HW mode */ + if (cds_need_opportunistic_upgrade()) { + /* let's start the timer */ + qdf_mc_timer_stop(&cds_ctx->dbs_opportunistic_timer); + qdf_status = qdf_mc_timer_start( + &cds_ctx->dbs_opportunistic_timer, + DBS_OPPORTUNISTIC_TIME * + 1000); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) + cds_err("Failed to start dbs opportunistic timer"); + } + + return; +} + + +/** + * cds_decr_active_session() - decrements the number of active sessions + * @mode: Adapter mode + * @session_id: session ID for the connection session + * + * This function decrements the number of active sessions maintained per device + * mode. In the case of STA/P2P CLI/IBSS upon disconnection it is decremented + * In the case of SAP/P2P GO upon bss stop it is decremented + * + * Return: QDF_STATUS + */ +QDF_STATUS cds_decr_active_session(enum tQDF_ADAPTER_MODE mode, + uint8_t session_id) +{ + hdd_context_t *hdd_ctx; + cds_context_type *cds_ctx; + hdd_adapter_t *sap_adapter; + QDF_STATUS qdf_status; + + cds_ctx = cds_get_context(QDF_MODULE_ID_QDF); + if (!cds_ctx) { + cds_err("Invalid CDS Context"); + return QDF_STATUS_E_INVAL; + } + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (!hdd_ctx) { + cds_err("HDD context is NULL"); + return QDF_STATUS_E_EMPTY; + } + + qdf_status = cds_check_conn_with_mode_and_vdev_id( + cds_convert_device_mode_to_qdf_type(mode), + session_id); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + cds_err("No connection with mode:%d vdev_id:%d", + cds_convert_device_mode_to_qdf_type(mode), session_id); + return qdf_status; + } + + switch (mode) { + case QDF_STA_MODE: + case QDF_P2P_CLIENT_MODE: + case QDF_P2P_GO_MODE: + case QDF_SAP_MODE: + case QDF_IBSS_MODE: + if (hdd_ctx->no_of_active_sessions[mode]) + hdd_ctx->no_of_active_sessions[mode]--; + break; + default: + break; + } + + cds_info("No.# of active sessions for mode %d = %d", + mode, hdd_ctx->no_of_active_sessions[mode]); + + cds_decr_connection_count(session_id); + + /* Enable LRO if there no concurrency */ + if ((cds_mode_specific_connection_count(CDS_STA_MODE, NULL) == 1) && + (cds_mode_specific_connection_count(CDS_SAP_MODE, NULL) == 0) && + (cds_mode_specific_connection_count(CDS_P2P_CLIENT_MODE, NULL) == + 0) && + (cds_mode_specific_connection_count(CDS_P2P_GO_MODE, NULL) == 0) && + (cds_mode_specific_connection_count(CDS_IBSS_MODE, NULL) == 0)) { + if (cds_ctx->hdd_en_lro_in_cc_cb != NULL) + cds_ctx->hdd_en_lro_in_cc_cb(hdd_ctx); + else + cds_warn("hdd_enable_lro_in_concurrency NULL!"); + } + + /* Disable RPS if SAP interface has come up */ + if (cds_mode_specific_connection_count(CDS_SAP_MODE, NULL) == 0) { + if (cds_ctx->hdd_set_rx_mode_rps_cb != NULL) { + sap_adapter = hdd_get_adapter(hdd_ctx, QDF_SAP_MODE); + if (sap_adapter != NULL) + cds_ctx->hdd_set_rx_mode_rps_cb(hdd_ctx, + sap_adapter, + false); + } else { + cds_warn("hdd_set_rx_mode_rps_cb NULL!"); + } + } + + /* set tdls connection tracker state */ + cds_set_tdls_ct_mode(hdd_ctx); + + cds_dump_current_concurrency(); + + return qdf_status; +} + +/** + * cds_dbs_opportunistic_timer_handler() - handler of + * dbs_opportunistic_timer + * @data: CDS context + * + * handler for dbs_opportunistic_timer + * + * Return: None + */ +static void cds_dbs_opportunistic_timer_handler(void *data) +{ + enum cds_conc_next_action action = CDS_NOP; + cds_context_type *cds_ctx = (cds_context_type *)data; + + if (!cds_ctx) { + cds_err("Invalid CDS Context"); + return; + } + + /* if we still need it */ + action = cds_need_opportunistic_upgrade(); + cds_info("action:%d", action); + if (action) { + /* lets call for action */ + /* session id is being used only + * in hidden ssid case for now. + * So, session id 0 is ok here. + */ + cds_next_actions(0, action, + SIR_UPDATE_REASON_OPPORTUNISTIC); + } + +} + +/** + * cds_deinit_policy_mgr() - Deinitialize the policy manager + * related data structures + * + * Deinitialize the policy manager related data structures + * + * Return: Success if the policy manager is deinitialized completely + */ +QDF_STATUS cds_deinit_policy_mgr(void) +{ + cds_context_type *cds_ctx; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + cds_ctx = cds_get_context(QDF_MODULE_ID_QDF); + if (!cds_ctx) { + cds_err("Invalid CDS Context"); + return QDF_STATUS_E_FAILURE; + } + + if (!QDF_IS_STATUS_SUCCESS(qdf_event_destroy + (&cds_ctx->connection_update_done_evt))) { + cds_err("Failed to destroy connection_update_done_evt"); + status = QDF_STATUS_E_FAILURE; + QDF_ASSERT(0); + } + + if (QDF_TIMER_STATE_RUNNING == + qdf_mc_timer_get_current_state( + &cds_ctx->dbs_opportunistic_timer)) { + qdf_mc_timer_stop(&cds_ctx->dbs_opportunistic_timer); + } + + if (!QDF_IS_STATUS_SUCCESS(qdf_mc_timer_destroy( + &cds_ctx->dbs_opportunistic_timer))) { + cds_err("Cannot deallocate dbs opportunistic timer"); + status = QDF_STATUS_E_FAILURE; + QDF_ASSERT(0); + } + + cds_ctx->sme_get_valid_channels = NULL; + cds_ctx->sme_get_nss_for_vdev = NULL; + + if (QDF_IS_STATUS_ERROR(cds_reset_sap_mandatory_channels())) { + cds_err("failed to reset sap mandatory channels"); + status = QDF_STATUS_E_FAILURE; + QDF_ASSERT(0); + } + + return status; +} + +/** + * cds_init_policy_mgr() - Initialize the policy manager + * related data structures + * + * Initialize the policy manager related data structures + * + * Return: Success if the policy manager is initialized completely + */ +QDF_STATUS cds_init_policy_mgr(struct cds_sme_cbacks *sme_cbacks) +{ + QDF_STATUS status; + hdd_context_t *hdd_ctx; + cds_context_type *cds_ctx; + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (!hdd_ctx) { + cds_err("HDD context is NULL"); + return QDF_STATUS_E_FAILURE; + } + + cds_ctx = cds_get_context(QDF_MODULE_ID_QDF); + if (!cds_ctx) { + cds_err("Invalid CDS Context"); + return QDF_STATUS_E_FAILURE; + } + + cds_debug("Initializing the policy manager"); + + /* init conc_connection_list */ + qdf_mem_zero(conc_connection_list, sizeof(conc_connection_list)); + + sme_register_hw_mode_trans_cb(hdd_ctx->hHal, + cds_hw_mode_transition_cb); + status = qdf_mc_timer_init(&cds_ctx->dbs_opportunistic_timer, + QDF_TIMER_TYPE_SW, + cds_dbs_opportunistic_timer_handler, + (void *)cds_ctx); + if (!QDF_IS_STATUS_SUCCESS(status)) { + cds_err("Failed to init DBS opportunistic timer"); + return status; + } + + status = qdf_init_connection_update(); + if (!QDF_IS_STATUS_SUCCESS(status)) { + cds_err("connection_update_done_evt init failed"); + return status; + } + + cds_ctx->do_hw_mode_change = false; + cds_ctx->hw_mode_change_in_progress = CDS_HW_MODE_NOT_IN_PROGRESS; + cds_ctx->sme_get_valid_channels = sme_cbacks->sme_get_valid_channels; + cds_ctx->sme_get_nss_for_vdev = sme_cbacks->sme_get_nss_for_vdev; + + status = cds_reset_sap_mandatory_channels(); + if (QDF_IS_STATUS_ERROR(status)) { + cds_err("failed to reset mandatory channels"); + return status; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * cds_get_connection_for_vdev_id() - provides the + * perticular connection with the requested vdev id + * @vdev_id: vdev id of the connection + * + * This function provides the specific connection with the + * requested vdev id + * + * Return: index in the connection table + */ +static uint32_t cds_get_connection_for_vdev_id(uint32_t vdev_id) +{ + uint32_t conn_index = 0; + cds_context_type *cds_ctx; + + cds_ctx = cds_get_context(QDF_MODULE_ID_QDF); + if (!cds_ctx) { + cds_err("Invalid CDS Context"); + return conn_index; + } + qdf_mutex_acquire(&cds_ctx->qdf_conc_list_lock); + for (conn_index = 0; conn_index < MAX_NUMBER_OF_CONC_CONNECTIONS; + conn_index++) { + if ((conc_connection_list[conn_index].vdev_id == vdev_id) && + conc_connection_list[conn_index].in_use) { + break; + } + } + qdf_mutex_release(&cds_ctx->qdf_conc_list_lock); + return conn_index; +} + +/** + * cds_get_mode() - Get mode from type and subtype + * @type: type + * @subtype: subtype + * + * Get the concurrency mode from the type and subtype + * of the interface + * + * Return: cds_con_mode + */ +static enum cds_con_mode cds_get_mode(uint8_t type, uint8_t subtype) +{ + enum cds_con_mode mode = CDS_MAX_NUM_OF_MODE; + + if (type == WMI_VDEV_TYPE_AP) { + switch (subtype) { + case 0: + mode = CDS_SAP_MODE; + break; + case WMI_UNIFIED_VDEV_SUBTYPE_P2P_GO: + mode = CDS_P2P_GO_MODE; + break; + default: + cds_err("Unknown subtype %d for type %d", + subtype, type); + break; + } + } else if (type == WMI_VDEV_TYPE_STA) { + switch (subtype) { + case 0: + mode = CDS_STA_MODE; + break; + case WMI_UNIFIED_VDEV_SUBTYPE_P2P_CLIENT: + mode = CDS_P2P_CLIENT_MODE; + break; + default: + cds_err("Unknown subtype %d for type %d", + subtype, type); + break; + } + } else if (type == WMI_VDEV_TYPE_IBSS) { + mode = CDS_IBSS_MODE; + } else { + cds_err("Unknown type %d", type); + } + + return mode; +} + +/** + * cds_get_bw() - Get channel bandwidth type used by WMI + * @chan_width: channel bandwidth type defined by host + * + * Get the channel bandwidth type used by WMI + * + * Return: hw_mode_bandwidth + */ +static enum hw_mode_bandwidth cds_get_bw(enum phy_ch_width chan_width) +{ + enum hw_mode_bandwidth bw = HW_MODE_BW_NONE; + + switch (chan_width) { + case CH_WIDTH_20MHZ: + bw = HW_MODE_20_MHZ; + break; + case CH_WIDTH_40MHZ: + bw = HW_MODE_40_MHZ; + break; + case CH_WIDTH_80MHZ: + bw = HW_MODE_80_MHZ; + break; + case CH_WIDTH_160MHZ: + bw = HW_MODE_160_MHZ; + break; + case CH_WIDTH_80P80MHZ: + bw = HW_MODE_80_PLUS_80_MHZ; + break; + case CH_WIDTH_5MHZ: + bw = HW_MODE_5_MHZ; + break; + case CH_WIDTH_10MHZ: + bw = HW_MODE_10_MHZ; + break; + default: + cds_err("Unknown channel BW type %d", chan_width); + break; + } + + return bw; +} + +/** + * cds_incr_connection_count() - adds the new connection to + * the current connections list + * @vdev_id: vdev id + * + * + * This function adds the new connection to the current + * connections list + * + * Return: QDF_STATUS + */ +QDF_STATUS cds_incr_connection_count(uint32_t vdev_id) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + uint32_t conn_index; + struct wma_txrx_node *wma_conn_table_entry; + hdd_context_t *hdd_ctx; + cds_context_type *cds_ctx; + enum cds_chain_mode chain_mask = CDS_ONE_ONE; + uint8_t nss_2g, nss_5g; + enum cds_con_mode mode; + uint8_t chan; + uint32_t nss = 0; + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (!hdd_ctx) { + cds_err("HDD context is NULL"); + return status; + } + + cds_ctx = cds_get_context(QDF_MODULE_ID_QDF); + if (!cds_ctx) { + cds_err("Invalid CDS Context"); + return status; + } + + conn_index = cds_get_connection_count(); + if (hdd_ctx->config->gMaxConcurrentActiveSessions < conn_index) { + cds_err("exceeded max connection limit %d", + hdd_ctx->config->gMaxConcurrentActiveSessions); + return status; + } + + wma_conn_table_entry = wma_get_interface_by_vdev_id(vdev_id); + + if (NULL == wma_conn_table_entry) { + cds_err("can't find vdev_id %d in WMA table", vdev_id); + return status; + } + mode = cds_get_mode(wma_conn_table_entry->type, + wma_conn_table_entry->sub_type); + chan = cds_freq_to_chan(wma_conn_table_entry->mhz); + status = cds_get_nss_for_vdev(mode, &nss_2g, &nss_5g); + if (QDF_IS_STATUS_SUCCESS(status)) { + if ((CDS_IS_CHANNEL_24GHZ(chan) && (nss_2g > 1)) || + (CDS_IS_CHANNEL_5GHZ(chan) && (nss_5g > 1))) + chain_mask = CDS_TWO_TWO; + else + chain_mask = CDS_ONE_ONE; + nss = (CDS_IS_CHANNEL_24GHZ(chan)) ? nss_2g : nss_5g; + } else { + cds_err("Error in getting nss"); + } + + + /* add the entry */ + cds_update_conc_list(conn_index, + mode, + chan, + cds_get_bw(wma_conn_table_entry->chan_width), + wma_conn_table_entry->mac_id, + chain_mask, + nss, vdev_id, true); + cds_info("Add at idx:%d vdev %d mac=%d", + conn_index, vdev_id, + wma_conn_table_entry->mac_id); + + return QDF_STATUS_SUCCESS; +} + +/** + * cds_update_connection_info() - updates the existing + * connection in the current connections list + * @vdev_id: vdev id + * + * + * This function adds the new connection to the current + * connections list + * + * Return: QDF_STATUS + */ +QDF_STATUS cds_update_connection_info(uint32_t vdev_id) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + uint32_t conn_index = 0; + bool found = false; + struct wma_txrx_node *wma_conn_table_entry; + cds_context_type *cds_ctx; + enum cds_chain_mode chain_mask = CDS_ONE_ONE; + uint8_t nss_2g, nss_5g; + enum cds_con_mode mode; + uint8_t chan; + uint32_t nss = 0; + + cds_ctx = cds_get_context(QDF_MODULE_ID_QDF); + if (!cds_ctx) { + cds_err("Invalid CDS Context"); + return status; + } + + qdf_mutex_acquire(&cds_ctx->qdf_conc_list_lock); + while (CONC_CONNECTION_LIST_VALID_INDEX(conn_index)) { + if (vdev_id == conc_connection_list[conn_index].vdev_id) { + /* debug msg */ + found = true; + break; + } + conn_index++; + } + qdf_mutex_release(&cds_ctx->qdf_conc_list_lock); + if (!found) { + /* err msg */ + cds_err("can't find vdev_id %d in conc_connection_list", + vdev_id); + return status; + } + + wma_conn_table_entry = wma_get_interface_by_vdev_id(vdev_id); + + if (NULL == wma_conn_table_entry) { + /* err msg*/ + cds_err("can't find vdev_id %d in WMA table", vdev_id); + return status; + } + mode = cds_get_mode(wma_conn_table_entry->type, + wma_conn_table_entry->sub_type); + chan = cds_freq_to_chan(wma_conn_table_entry->mhz); + status = cds_get_nss_for_vdev(mode, &nss_2g, &nss_5g); + if (QDF_IS_STATUS_SUCCESS(status)) { + if ((CDS_IS_CHANNEL_24GHZ(chan) && (nss_2g > 1)) || + (CDS_IS_CHANNEL_5GHZ(chan) && (nss_5g > 1))) + chain_mask = CDS_TWO_TWO; + else + chain_mask = CDS_ONE_ONE; + nss = (CDS_IS_CHANNEL_24GHZ(chan)) ? nss_2g : nss_5g; + } else { + cds_err("Error in getting nss"); + } + + cds_debug("update PM connection table for vdev:%d", vdev_id); + + /* add the entry */ + cds_update_conc_list(conn_index, + mode, + chan, + cds_get_bw(wma_conn_table_entry->chan_width), + wma_conn_table_entry->mac_id, + chain_mask, + nss, vdev_id, true); + return QDF_STATUS_SUCCESS; +} + +/** + * cds_decr_connection_count() - remove the old connection + * from the current connections list + * @vdev_id: vdev id of the old connection + * + * + * This function removes the old connection from the current + * connections list + * + * Return: QDF_STATUS + */ +QDF_STATUS cds_decr_connection_count(uint32_t vdev_id) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + uint32_t conn_index = 0, next_conn_index = 0; + bool found = false; + cds_context_type *cds_ctx; + + cds_ctx = cds_get_context(QDF_MODULE_ID_QDF); + if (!cds_ctx) { + cds_err("Invalid CDS Context"); + return status; + } + + qdf_mutex_acquire(&cds_ctx->qdf_conc_list_lock); + while (CONC_CONNECTION_LIST_VALID_INDEX(conn_index)) { + if (vdev_id == conc_connection_list[conn_index].vdev_id) { + /* debug msg */ + found = true; + break; + } + conn_index++; + } + if (!found) { + cds_err("can't find vdev_id %d in conc_connection_list", + vdev_id); + qdf_mutex_release(&cds_ctx->qdf_conc_list_lock); + return status; + } + next_conn_index = conn_index + 1; + while (CONC_CONNECTION_LIST_VALID_INDEX(next_conn_index)) { + conc_connection_list[conn_index].vdev_id = + conc_connection_list[next_conn_index].vdev_id; + conc_connection_list[conn_index].mode = + conc_connection_list[next_conn_index].mode; + conc_connection_list[conn_index].mac = + conc_connection_list[next_conn_index].mac; + conc_connection_list[conn_index].chan = + conc_connection_list[next_conn_index].chan; + conc_connection_list[conn_index].bw = + conc_connection_list[next_conn_index].bw; + conc_connection_list[conn_index].chain_mask = + conc_connection_list[next_conn_index].chain_mask; + conc_connection_list[conn_index].original_nss = + conc_connection_list[next_conn_index].original_nss; + conc_connection_list[conn_index].in_use = + conc_connection_list[next_conn_index].in_use; + conn_index++; + next_conn_index++; + } + + /* clean up the entry */ + qdf_mem_zero(&conc_connection_list[next_conn_index - 1], + sizeof(*conc_connection_list)); + qdf_mutex_release(&cds_ctx->qdf_conc_list_lock); + return QDF_STATUS_SUCCESS; +} + +/** + * cds_get_connection_channels() - provides the channel(s) + * on which current connection(s) is + * @channels: the channel(s) on which current connection(s) is + * @len: Number of channels + * @order: no order OR 2.4 Ghz channel followed by 5 Ghz + * channel OR 5 Ghz channel followed by 2.4 Ghz channel + * @skip_dfs_channel: if this flag is true then skip the dfs channel + * @pcl_weight: Pointer to the weights of PCL + * @weight_len: Max length of the weight list + * @index: Index from which the weight list needs to be populated + * @group_id: Next available groups for weight assignment + * + * + * This function provides the channel(s) on which current + * connection(s) is/are + * + * Return: QDF_STATUS + */ +static +QDF_STATUS cds_get_connection_channels(uint8_t *channels, + uint32_t *len, enum cds_pcl_channel_order order, + bool skip_dfs_channel, + uint8_t *pcl_weight, uint32_t weight_len, + uint32_t *index, enum cds_pcl_group_id group_id) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + uint32_t conn_index = 0, num_channels = 0; + uint32_t weight1, weight2; + cds_context_type *cds_ctx; + + cds_ctx = cds_get_context(QDF_MODULE_ID_QDF); + if (!cds_ctx) { + cds_err("Invalid CDS Context"); + return status; + } + + if ((NULL == channels) || (NULL == len)) { + cds_err("channels or len is NULL"); + status = QDF_STATUS_E_FAILURE; + return status; + } + + /* CDS_PCL_GROUP_ID1_ID2 indicates that all three weights are + * available for assignment. i.e., WEIGHT_OF_GROUP1_PCL_CHANNELS, + * WEIGHT_OF_GROUP2_PCL_CHANNELS and WEIGHT_OF_GROUP3_PCL_CHANNELS + * are all available. Since in this function only two weights are + * assigned at max, only group1 and group2 weights are considered. + * + * The other possible group id CDS_PCL_GROUP_ID2_ID3 indicates that + * group1 was assigned the weight WEIGHT_OF_GROUP1_PCL_CHANNELS and + * only weights WEIGHT_OF_GROUP2_PCL_CHANNELS and + * WEIGHT_OF_GROUP3_PCL_CHANNELS are available for further weight + * assignments. + * + * e.g., when order is CDS_PCL_ORDER_24G_THEN_5G and group id is + * CDS_PCL_GROUP_ID2_ID3, WEIGHT_OF_GROUP2_PCL_CHANNELS is assigned to + * 2.4GHz channels and the weight WEIGHT_OF_GROUP3_PCL_CHANNELS is + * assigned to the 5GHz channels. + */ + if (group_id == CDS_PCL_GROUP_ID1_ID2) { + weight1 = WEIGHT_OF_GROUP1_PCL_CHANNELS; + weight2 = WEIGHT_OF_GROUP2_PCL_CHANNELS; + } else { + weight1 = WEIGHT_OF_GROUP2_PCL_CHANNELS; + weight2 = WEIGHT_OF_GROUP3_PCL_CHANNELS; + } + + qdf_mutex_acquire(&cds_ctx->qdf_conc_list_lock); + if (CDS_PCL_ORDER_NONE == order) { + while (CONC_CONNECTION_LIST_VALID_INDEX(conn_index)) { + if (skip_dfs_channel && CDS_IS_DFS_CH( + conc_connection_list[conn_index].chan)) { + conn_index++; + } else if (*index < weight_len) { + channels[num_channels++] = + conc_connection_list[conn_index++].chan; + pcl_weight[(*index)++] = weight1; + } else { + conn_index++; + } + } + *len = num_channels; + } else if (CDS_PCL_ORDER_24G_THEN_5G == order) { + while (CONC_CONNECTION_LIST_VALID_INDEX(conn_index)) { + if (CDS_IS_CHANNEL_24GHZ( + conc_connection_list[conn_index].chan) + && (*index < weight_len)) { + channels[num_channels++] = + conc_connection_list[conn_index++].chan; + pcl_weight[(*index)++] = weight1; + } else { + conn_index++; + } + } + conn_index = 0; + while (CONC_CONNECTION_LIST_VALID_INDEX(conn_index)) { + if (skip_dfs_channel && CDS_IS_DFS_CH( + conc_connection_list[conn_index].chan)) { + conn_index++; + } else if (CDS_IS_CHANNEL_5GHZ( + conc_connection_list[conn_index].chan) + && (*index < weight_len)) { + channels[num_channels++] = + conc_connection_list[conn_index++].chan; + pcl_weight[(*index)++] = weight2; + } else { + conn_index++; + } + } + *len = num_channels; + } else if (CDS_PCL_ORDER_5G_THEN_2G == order) { + while (CONC_CONNECTION_LIST_VALID_INDEX(conn_index)) { + if (skip_dfs_channel && CDS_IS_DFS_CH( + conc_connection_list[conn_index].chan)) { + conn_index++; + } else if (CDS_IS_CHANNEL_5GHZ( + conc_connection_list[conn_index].chan) + && (*index < weight_len)) { + channels[num_channels++] = + conc_connection_list[conn_index++].chan; + pcl_weight[(*index)++] = weight1; + } else { + conn_index++; + } + } + conn_index = 0; + while (CONC_CONNECTION_LIST_VALID_INDEX(conn_index)) { + if (CDS_IS_CHANNEL_24GHZ( + conc_connection_list[conn_index].chan) + && (*index < weight_len)) { + channels[num_channels++] = + conc_connection_list[conn_index++].chan; + pcl_weight[(*index)++] = weight2; + + } else { + conn_index++; + } + } + *len = num_channels; + } else { + cds_err("unknown order %d", order); + status = QDF_STATUS_E_FAILURE; + } + qdf_mutex_release(&cds_ctx->qdf_conc_list_lock); + + return status; +} + +/** + * cds_update_with_safe_channel_list() - provides the safe + * channel list + * @pcl_channels: channel list + * @len: length of the list + * @weight_list: Weights of the PCL + * @weight_len: Max length of the weights list + * + * This function provides the safe channel list from the list + * provided after consulting the channel avoidance list + * + * Return: None + */ +void cds_update_with_safe_channel_list(uint8_t *pcl_channels, uint32_t *len, + uint8_t *weight_list, uint32_t weight_len) +{ + uint16_t unsafe_channel_list[QDF_MAX_NUM_CHAN]; + uint8_t current_channel_list[QDF_MAX_NUM_CHAN]; + uint8_t org_weight_list[QDF_MAX_NUM_CHAN]; + uint16_t unsafe_channel_count = 0; + uint8_t is_unsafe = 1; + uint8_t i, j; + uint32_t safe_channel_count = 0, current_channel_count = 0; + qdf_device_t qdf_ctx = cds_get_context(QDF_MODULE_ID_QDF_DEVICE); + + if (!qdf_ctx) { + cds_err("qdf_ctx is NULL"); + return; + } + + if (len) { + current_channel_count = QDF_MIN(*len, QDF_MAX_NUM_CHAN); + } else { + cds_err("invalid number of channel length"); + return; + } + + pld_get_wlan_unsafe_channel(qdf_ctx->dev, + unsafe_channel_list, + &unsafe_channel_count, + sizeof(unsafe_channel_list)); + + if (unsafe_channel_count == 0) + cds_notice("There are no unsafe channels"); + + if (unsafe_channel_count) { + qdf_mem_copy(current_channel_list, pcl_channels, + current_channel_count); + qdf_mem_zero(pcl_channels, + sizeof(*pcl_channels)*current_channel_count); + + qdf_mem_copy(org_weight_list, weight_list, QDF_MAX_NUM_CHAN); + qdf_mem_zero(weight_list, weight_len); + + for (i = 0; i < current_channel_count; i++) { + is_unsafe = 0; + for (j = 0; j < unsafe_channel_count; j++) { + if (current_channel_list[i] == + unsafe_channel_list[j]) { + /* Found unsafe channel, update it */ + is_unsafe = 1; + cds_warn("CH %d is not safe", + current_channel_list[i]); + break; + } + } + if (!is_unsafe) { + pcl_channels[safe_channel_count] = + current_channel_list[i]; + if (safe_channel_count < weight_len) + weight_list[safe_channel_count] = + org_weight_list[i]; + safe_channel_count++; + } + } + *len = safe_channel_count; + } + return; +} + +/** + * cds_get_channel_list() - provides the channel list + * suggestion for new connection + * @pcl: The preferred channel list enum + * @pcl_channels: PCL channels + * @len: length of the PCL + * @mode: concurrency mode for which channel list is requested + * @pcl_weights: Weights of the PCL + * @weight_len: Max length of the weight list + * + * This function provides the actual channel list based on the + * current regulatory domain derived using preferred channel + * list enum obtained from one of the pcl_table + * + * Return: Channel List + */ +static QDF_STATUS cds_get_channel_list(enum cds_pcl_type pcl, + uint8_t *pcl_channels, uint32_t *len, + enum cds_con_mode mode, + uint8_t *pcl_weights, + uint32_t weight_len) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + uint32_t num_channels = 0; + uint32_t chan_index = 0, chan_index_24 = 0, chan_index_5 = 0; + uint8_t channel_list[QDF_MAX_NUM_CHAN] = {0}; + uint8_t channel_list_24[QDF_MAX_NUM_CHAN] = {0}; + uint8_t channel_list_5[QDF_MAX_NUM_CHAN] = {0}; + bool skip_dfs_channel = false; + hdd_context_t *hdd_ctx; + uint32_t i = 0, j = 0; + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (!hdd_ctx) { + cds_err("HDD context is NULL"); + return status; + } + + if ((NULL == pcl_channels) || (NULL == len)) { + cds_err("pcl_channels or len is NULL"); + return status; + } + + if (CDS_MAX_PCL_TYPE == pcl) { + /* msg */ + cds_err("pcl is invalid"); + return status; + } + + if (CDS_NONE == pcl) { + /* msg */ + cds_info("pcl is 0"); + return QDF_STATUS_SUCCESS; + } + /* get the channel list for current domain */ + status = cds_get_valid_chans(channel_list, &num_channels); + if (QDF_IS_STATUS_ERROR(status)) { + cds_err("Error in getting valid channels"); + return status; + } + + /* + * if you have atleast one STA connection then don't fill DFS channels + * in the preferred channel list + */ + if (((mode == CDS_SAP_MODE) || (mode == CDS_P2P_GO_MODE)) && + (cds_mode_specific_connection_count(CDS_STA_MODE, NULL) > 0)) { + cds_info("STA present, skip DFS channels from pcl for SAP/Go"); + skip_dfs_channel = true; + } + + /* Let's divide the list in 2.4 & 5 Ghz lists */ + while ((chan_index < QDF_MAX_NUM_CHAN) && + (channel_list[chan_index] <= 11) && + (chan_index_24 < QDF_MAX_NUM_CHAN)) + channel_list_24[chan_index_24++] = channel_list[chan_index++]; + if ((chan_index < QDF_MAX_NUM_CHAN) && + (channel_list[chan_index] == 12) && + (chan_index_24 < QDF_MAX_NUM_CHAN)) { + channel_list_24[chan_index_24++] = channel_list[chan_index++]; + if ((chan_index < QDF_MAX_NUM_CHAN) && + (channel_list[chan_index] == 13) && + (chan_index_24 < QDF_MAX_NUM_CHAN)) { + channel_list_24[chan_index_24++] = + channel_list[chan_index++]; + if ((chan_index < QDF_MAX_NUM_CHAN) && + (channel_list[chan_index] == 14) && + (chan_index_24 < QDF_MAX_NUM_CHAN)) + channel_list_24[chan_index_24++] = + channel_list[chan_index++]; + } + } + + while ((chan_index < num_channels) && + (chan_index_5 < QDF_MAX_NUM_CHAN)) { + if ((true == skip_dfs_channel) && + CDS_IS_DFS_CH(channel_list[chan_index])) { + chan_index++; + continue; + } + channel_list_5[chan_index_5++] = channel_list[chan_index++]; + } + + num_channels = 0; + /* In the below switch case, the channel list is populated based on the + * pcl. e.g., if the pcl is CDS_SCC_CH_24G, the SCC channel group is + * populated first followed by the 2.4GHz channel group. Along with + * this, the weights are also populated in the same order for each of + * these groups. There are three weight groups: + * WEIGHT_OF_GROUP1_PCL_CHANNELS, WEIGHT_OF_GROUP2_PCL_CHANNELS and + * WEIGHT_OF_GROUP3_PCL_CHANNELS. + * + * e.g., if pcl is CDS_SCC_ON_5_SCC_ON_24_24G: scc on 5GHz (group1) + * channels take the weight WEIGHT_OF_GROUP1_PCL_CHANNELS, scc on 2.4GHz + * (group2) channels take the weight WEIGHT_OF_GROUP2_PCL_CHANNELS and + * 2.4GHz (group3) channels take the weight + * WEIGHT_OF_GROUP3_PCL_CHANNELS. + * + * When the weight to be assigned to the group is known along with the + * number of channels, the weights are directly assigned to the + * pcl_weights list. But, the channel list is populated using + * cds_get_connection_channels(), the order of weights to be used is + * passed as an argument to the function cds_get_connection_channels() + * using 'enum cds_pcl_group_id' which indicates the next available + * weights to be used and cds_get_connection_channels() will take care + * of the weight assignments. + * + * e.g., 'enum cds_pcl_group_id' value of CDS_PCL_GROUP_ID2_ID3 + * indicates that the next available groups for weight assignment are + * WEIGHT_OF_GROUP2_PCL_CHANNELS and WEIGHT_OF_GROUP3_PCL_CHANNELS and + * that the weight WEIGHT_OF_GROUP1_PCL_CHANNELS was already allocated. + * So, in the same example, when order is CDS_PCL_ORDER_24G_THEN_5G, + * cds_get_connection_channels() will assign the weight + * WEIGHT_OF_GROUP2_PCL_CHANNELS to 2.4GHz channels and assign the + * weight WEIGHT_OF_GROUP3_PCL_CHANNELS to 5GHz channels. + */ + switch (pcl) { + case CDS_24G: + chan_index_24 = QDF_MIN(chan_index_24, weight_len); + qdf_mem_copy(pcl_channels, channel_list_24, + chan_index_24); + *len = chan_index_24; + for (i = 0; i < *len; i++) + pcl_weights[i] = WEIGHT_OF_GROUP1_PCL_CHANNELS; + status = QDF_STATUS_SUCCESS; + break; + case CDS_5G: + chan_index_5 = QDF_MIN(chan_index_5, weight_len); + qdf_mem_copy(pcl_channels, channel_list_5, + chan_index_5); + *len = chan_index_5; + for (i = 0; i < *len; i++) + pcl_weights[i] = WEIGHT_OF_GROUP1_PCL_CHANNELS; + status = QDF_STATUS_SUCCESS; + break; + case CDS_SCC_CH: + case CDS_MCC_CH: + cds_get_connection_channels( + channel_list, &num_channels, CDS_PCL_ORDER_NONE, + skip_dfs_channel, pcl_weights, weight_len, &i, + CDS_PCL_GROUP_ID1_ID2); + qdf_mem_copy(pcl_channels, channel_list, num_channels); + *len = num_channels; + status = QDF_STATUS_SUCCESS; + break; + case CDS_SCC_CH_24G: + case CDS_MCC_CH_24G: + cds_get_connection_channels( + channel_list, &num_channels, CDS_PCL_ORDER_NONE, + skip_dfs_channel, pcl_weights, weight_len, &i, + CDS_PCL_GROUP_ID1_ID2); + qdf_mem_copy(pcl_channels, channel_list, num_channels); + *len = num_channels; + chan_index_24 = QDF_MIN((num_channels + chan_index_24), + weight_len) - num_channels; + qdf_mem_copy(&pcl_channels[num_channels], + channel_list_24, chan_index_24); + *len += chan_index_24; + for (j = 0; j < chan_index_24; i++, j++) + pcl_weights[i] = WEIGHT_OF_GROUP2_PCL_CHANNELS; + + status = QDF_STATUS_SUCCESS; + break; + case CDS_SCC_CH_5G: + case CDS_MCC_CH_5G: + cds_get_connection_channels( + channel_list, &num_channels, CDS_PCL_ORDER_NONE, + skip_dfs_channel, pcl_weights, weight_len, &i, + CDS_PCL_GROUP_ID1_ID2); + qdf_mem_copy(pcl_channels, channel_list, + num_channels); + *len = num_channels; + chan_index_5 = QDF_MIN((num_channels + chan_index_5), + weight_len) - num_channels; + qdf_mem_copy(&pcl_channels[num_channels], + channel_list_5, chan_index_5); + *len += chan_index_5; + for (j = 0; j < chan_index_5; i++, j++) + pcl_weights[i] = WEIGHT_OF_GROUP2_PCL_CHANNELS; + status = QDF_STATUS_SUCCESS; + break; + case CDS_24G_SCC_CH: + case CDS_24G_MCC_CH: + chan_index_24 = QDF_MIN(chan_index_24, weight_len); + qdf_mem_copy(pcl_channels, channel_list_24, + chan_index_24); + *len = chan_index_24; + for (i = 0; i < chan_index_24; i++) + pcl_weights[i] = WEIGHT_OF_GROUP1_PCL_CHANNELS; + cds_get_connection_channels( + channel_list, &num_channels, CDS_PCL_ORDER_NONE, + skip_dfs_channel, pcl_weights, weight_len, &i, + CDS_PCL_GROUP_ID2_ID3); + qdf_mem_copy(&pcl_channels[chan_index_24], + channel_list, num_channels); + *len += num_channels; + status = QDF_STATUS_SUCCESS; + break; + case CDS_5G_SCC_CH: + case CDS_5G_MCC_CH: + chan_index_5 = QDF_MIN(chan_index_5, weight_len); + qdf_mem_copy(pcl_channels, channel_list_5, + chan_index_5); + *len = chan_index_5; + for (i = 0; i < chan_index_5; i++) + pcl_weights[i] = WEIGHT_OF_GROUP1_PCL_CHANNELS; + cds_get_connection_channels( + channel_list, &num_channels, CDS_PCL_ORDER_NONE, + skip_dfs_channel, pcl_weights, weight_len, &i, + CDS_PCL_GROUP_ID2_ID3); + qdf_mem_copy(&pcl_channels[chan_index_5], + channel_list, num_channels); + *len += num_channels; + status = QDF_STATUS_SUCCESS; + break; + case CDS_SCC_ON_24_SCC_ON_5: + cds_get_connection_channels( + channel_list, &num_channels, CDS_PCL_ORDER_24G_THEN_5G, + skip_dfs_channel, pcl_weights, weight_len, &i, + CDS_PCL_GROUP_ID1_ID2); + qdf_mem_copy(pcl_channels, channel_list, + num_channels); + *len = num_channels; + status = QDF_STATUS_SUCCESS; + break; + case CDS_SCC_ON_5_SCC_ON_24: + cds_get_connection_channels( + channel_list, &num_channels, CDS_PCL_ORDER_5G_THEN_2G, + skip_dfs_channel, pcl_weights, weight_len, &i, + CDS_PCL_GROUP_ID1_ID2); + qdf_mem_copy(pcl_channels, channel_list, num_channels); + *len = num_channels; + status = QDF_STATUS_SUCCESS; + break; + case CDS_SCC_ON_24_SCC_ON_5_24G: + cds_get_connection_channels( + channel_list, &num_channels, CDS_PCL_ORDER_24G_THEN_5G, + skip_dfs_channel, pcl_weights, weight_len, &i, + CDS_PCL_GROUP_ID1_ID2); + qdf_mem_copy(pcl_channels, channel_list, num_channels); + *len = num_channels; + chan_index_24 = QDF_MIN((num_channels + chan_index_24), + weight_len) - num_channels; + qdf_mem_copy(&pcl_channels[num_channels], + channel_list_24, chan_index_24); + *len += chan_index_24; + for (j = 0; j < chan_index_24; i++, j++) + pcl_weights[i] = WEIGHT_OF_GROUP3_PCL_CHANNELS; + status = QDF_STATUS_SUCCESS; + break; + case CDS_SCC_ON_24_SCC_ON_5_5G: + cds_get_connection_channels( + channel_list, &num_channels, CDS_PCL_ORDER_24G_THEN_5G, + skip_dfs_channel, pcl_weights, weight_len, &i, + CDS_PCL_GROUP_ID1_ID2); + qdf_mem_copy(pcl_channels, channel_list, num_channels); + *len = num_channels; + chan_index_5 = QDF_MIN((num_channels + chan_index_5), + weight_len) - num_channels; + qdf_mem_copy(&pcl_channels[num_channels], + channel_list_5, chan_index_5); + *len += chan_index_5; + for (j = 0; j < chan_index_5; i++, j++) + pcl_weights[i] = WEIGHT_OF_GROUP3_PCL_CHANNELS; + status = QDF_STATUS_SUCCESS; + break; + case CDS_SCC_ON_5_SCC_ON_24_24G: + cds_get_connection_channels( + channel_list, &num_channels, CDS_PCL_ORDER_5G_THEN_2G, + skip_dfs_channel, pcl_weights, weight_len, &i, + CDS_PCL_GROUP_ID1_ID2); + qdf_mem_copy(pcl_channels, channel_list, num_channels); + *len = num_channels; + chan_index_24 = QDF_MIN((num_channels + chan_index_24), + weight_len) - num_channels; + qdf_mem_copy(&pcl_channels[num_channels], + channel_list_24, chan_index_24); + *len += chan_index_24; + for (j = 0; j < chan_index_24; i++, j++) + pcl_weights[i] = WEIGHT_OF_GROUP3_PCL_CHANNELS; + status = QDF_STATUS_SUCCESS; + break; + case CDS_SCC_ON_5_SCC_ON_24_5G: + cds_get_connection_channels( + channel_list, &num_channels, CDS_PCL_ORDER_5G_THEN_2G, + skip_dfs_channel, pcl_weights, weight_len, &i, + CDS_PCL_GROUP_ID1_ID2); + qdf_mem_copy(pcl_channels, channel_list, num_channels); + *len = num_channels; + chan_index_5 = QDF_MIN((num_channels + chan_index_5), + weight_len) - num_channels; + qdf_mem_copy(&pcl_channels[num_channels], + channel_list_5, chan_index_5); + *len += chan_index_5; + for (j = 0; j < chan_index_5; i++, j++) + pcl_weights[i] = WEIGHT_OF_GROUP3_PCL_CHANNELS; + status = QDF_STATUS_SUCCESS; + break; + default: + cds_err("unknown pcl value %d", pcl); + break; + } + + if ((*len != 0) && (*len != i)) + cds_info("pcl len (%d) and weight list len mismatch (%d)", + *len, i); + + /* check the channel avoidance list */ + cds_update_with_safe_channel_list(pcl_channels, len, + pcl_weights, weight_len); + + return status; +} + +/** + * cds_map_concurrency_mode() - to map concurrency mode between sme and hdd + * @old_mode: sme provided adapter mode + * @new_mode: hdd provided concurrency mode + * + * This routine will map concurrency mode between sme and hdd + * + * Return: true or false + */ +bool cds_map_concurrency_mode(enum tQDF_ADAPTER_MODE *old_mode, + enum cds_con_mode *new_mode) +{ + bool status = true; + + switch (*old_mode) { + + case QDF_STA_MODE: + *new_mode = CDS_STA_MODE; + break; + case QDF_SAP_MODE: + *new_mode = CDS_SAP_MODE; + break; + case QDF_P2P_CLIENT_MODE: + *new_mode = CDS_P2P_CLIENT_MODE; + break; + case QDF_P2P_GO_MODE: + *new_mode = CDS_P2P_GO_MODE; + break; + case QDF_IBSS_MODE: + *new_mode = CDS_IBSS_MODE; + break; + default: + *new_mode = CDS_MAX_NUM_OF_MODE; + status = false; + break; + } + return status; +} + +static QDF_STATUS cds_modify_pcl_based_on_enabled_channels( + uint8_t *pcl_list_org, + uint8_t *weight_list_org, + uint32_t *pcl_len_org) +{ + cds_context_type *cds_ctx; + uint32_t i, pcl_len = 0; + uint8_t pcl_list[QDF_MAX_NUM_CHAN]; + uint8_t weight_list[QDF_MAX_NUM_CHAN]; + + cds_ctx = cds_get_context(QDF_MODULE_ID_QDF); + if (!cds_ctx) { + cds_err("Invalid CDS Context"); + return QDF_STATUS_E_FAILURE; + } + + for (i = 0; i < *pcl_len_org; i++) { + if (!CDS_IS_PASSIVE_OR_DISABLE_CH(pcl_list_org[i])) { + pcl_list[pcl_len] = pcl_list_org[i]; + weight_list[pcl_len++] = weight_list_org[i]; + } + } + + qdf_mem_zero(pcl_list_org, QDF_ARRAY_SIZE(pcl_list_org)); + qdf_mem_zero(weight_list_org, QDF_ARRAY_SIZE(weight_list_org)); + qdf_mem_copy(pcl_list_org, pcl_list, pcl_len); + qdf_mem_copy(weight_list_org, weight_list, pcl_len); + *pcl_len_org = pcl_len; + + return QDF_STATUS_SUCCESS; +} + +/** + * cds_get_channel() - provide channel number of given mode and vdevid + * @mode: given CDS mode + * @vdev_id: pointer to vdev_id + * + * This API will provide channel number of matching mode and vdevid. + * If vdev_id is NULL then it will match only mode + * If vdev_id is not NULL the it will match both mode and vdev_id + * + * Return: channel number + */ +uint8_t cds_get_channel(enum cds_con_mode mode, uint32_t *vdev_id) +{ + uint32_t idx = 0; + uint8_t chan; + cds_context_type *cds_ctx; + + cds_ctx = cds_get_context(QDF_MODULE_ID_QDF); + if (!cds_ctx) { + cds_err("Invalid CDS Context"); + return 0; + } + + if (mode >= CDS_MAX_NUM_OF_MODE) { + cds_err("incorrect mode"); + return 0; + } + + for (idx = 0; idx < MAX_NUMBER_OF_CONC_CONNECTIONS; idx++) { + qdf_mutex_acquire(&cds_ctx->qdf_conc_list_lock); + if ((conc_connection_list[idx].mode == mode) && + (!vdev_id || (*vdev_id == + conc_connection_list[idx].vdev_id)) + && conc_connection_list[idx].in_use) { + chan = conc_connection_list[idx].chan; + qdf_mutex_release(&cds_ctx->qdf_conc_list_lock); + return chan; + } + qdf_mutex_release(&cds_ctx->qdf_conc_list_lock); + } + return 0; +} + +/** + * cds_get_pcl() - provides the preferred channel list for + * new connection + * @mode: Device mode + * @pcl_channels: PCL channels + * @len: lenght of the PCL + * @pcl_weight: Weights of the PCL + * @weight_len: Max length of the weights list + * + * This function provides the preferred channel list on which + * policy manager wants the new connection to come up. Various + * connection decision making entities will using this function + * to query the PCL info + * + * Return: QDF_STATUS + */ +QDF_STATUS cds_get_pcl(enum cds_con_mode mode, + uint8_t *pcl_channels, uint32_t *len, + uint8_t *pcl_weight, uint32_t weight_len) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + uint32_t num_connections = 0, i; + enum cds_conc_priority_mode first_index = 0; + enum cds_one_connection_mode second_index = 0; + enum cds_two_connection_mode third_index = 0; + enum cds_pcl_type pcl = CDS_NONE; + enum cds_conc_priority_mode conc_system_pref = 0; + hdd_context_t *hdd_ctx; + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (!hdd_ctx) { + cds_err("HDD context is NULL"); + return status; + } + + /* find the current connection state from conc_connection_list*/ + num_connections = cds_get_connection_count(); + cds_debug("connections:%d pref:%d requested mode:%d", + num_connections, hdd_ctx->config->conc_system_pref, mode); + + switch (hdd_ctx->config->conc_system_pref) { + case 0: + conc_system_pref = CDS_THROUGHPUT; + break; + case 1: + conc_system_pref = CDS_POWERSAVE; + break; + case 2: + conc_system_pref = CDS_LATENCY; + break; + default: + cds_err("unknown conc_system_pref value %d", + hdd_ctx->config->conc_system_pref); + break; + } + + switch (num_connections) { + case 0: + first_index = + cds_get_first_connection_pcl_table_index(); + pcl = first_connection_pcl_table[mode][first_index]; + break; + case 1: + second_index = + cds_get_second_connection_pcl_table_index(); + if (CDS_MAX_ONE_CONNECTION_MODE == second_index) { + cds_err("couldn't find index for 2nd connection pcl table"); + return status; + } + if (wma_is_hw_dbs_capable() == true) { + pcl = second_connection_pcl_dbs_table + [second_index][mode][conc_system_pref]; + } else { + pcl = second_connection_pcl_nodbs_table + [second_index][mode][conc_system_pref]; + } + + break; + case 2: + third_index = + cds_get_third_connection_pcl_table_index(); + if (CDS_MAX_TWO_CONNECTION_MODE == third_index) { + cds_err("couldn't find index for 3rd connection pcl table"); + return status; + } + if (wma_is_hw_dbs_capable() == true) { + pcl = third_connection_pcl_dbs_table + [third_index][mode][conc_system_pref]; + } else { + pcl = third_connection_pcl_nodbs_table + [third_index][mode][conc_system_pref]; + } + break; + default: + cds_err("unexpected num_connections value %d", + num_connections); + break; + } + + cds_debug("index1:%d index2:%d index3:%d pcl:%d dbs:%d", + first_index, second_index, third_index, + pcl, wma_is_hw_dbs_capable()); + + /* once the PCL enum is obtained find out the exact channel list with + * help from sme_get_cfg_valid_channels + */ + status = cds_get_channel_list(pcl, pcl_channels, len, mode, + pcl_weight, weight_len); + if (QDF_IS_STATUS_ERROR(status)) { + cds_err("failed to get channel list:%d", status); + return status; + } + + cds_debug("pcl len:%d", *len); + for (i = 0; i < *len; i++) { + cds_debug("chan:%d weight:%d", + pcl_channels[i], pcl_weight[i]); + } + + if ((mode == CDS_SAP_MODE) && cds_is_sap_mandatory_channel_set()) { + status = cds_modify_sap_pcl_based_on_mandatory_channel( + pcl_channels, pcl_weight, len); + if (QDF_IS_STATUS_ERROR(status)) { + cds_err("failed to get modified pcl for SAP"); + return status; + } + cds_debug("modified pcl len:%d", *len); + for (i = 0; i < *len; i++) + cds_debug("chan:%d weight:%d", + pcl_channels[i], pcl_weight[i]); + + } + + if (mode == CDS_P2P_GO_MODE) { + status = cds_modify_pcl_based_on_enabled_channels( + pcl_channels, pcl_weight, len); + if (QDF_IS_STATUS_ERROR(status)) { + cds_err("failed to get modified pcl for GO"); + return status; + } + cds_debug("modified pcl len:%d", *len); + for (i = 0; i < *len; i++) + cds_debug("chan:%d weight:%d", + pcl_channels[i], pcl_weight[i]); + } + + return QDF_STATUS_SUCCESS; +} + +/** + * cds_disallow_mcc() - Check for mcc + * + * @channel: channel on which new connection is coming up + * + * When a new connection is about to come up check if current + * concurrency combination including the new connection is + * causing MCC + * + * Return: True/False + */ +static bool cds_disallow_mcc(uint8_t channel) +{ + uint32_t index = 0; + bool match = false; + cds_context_type *cds_ctx; + + cds_ctx = cds_get_context(QDF_MODULE_ID_QDF); + if (!cds_ctx) { + cds_err("Invalid CDS Context"); + return match; + } + qdf_mutex_acquire(&cds_ctx->qdf_conc_list_lock); + while (CONC_CONNECTION_LIST_VALID_INDEX(index)) { + if (wma_is_hw_dbs_capable() == false) { + if (conc_connection_list[index].chan != + channel) { + match = true; + break; + } + } else if (CDS_IS_CHANNEL_5GHZ + (conc_connection_list[index].chan)) { + if (conc_connection_list[index].chan != channel) { + match = true; + break; + } + } + index++; + } + qdf_mutex_release(&cds_ctx->qdf_conc_list_lock); + return match; +} + +/** + * cds_allow_new_home_channel() - Check for allowed number of + * home channels + * @channel: channel on which new connection is coming up + * @num_connections: number of current connections + * + * When a new connection is about to come up check if current + * concurrency combination including the new connection is + * allowed or not based on the HW capability + * + * Return: True/False + */ +static bool cds_allow_new_home_channel(uint8_t channel, + uint32_t num_connections) +{ + bool status = true; + cds_context_type *cds_ctx; + + cds_ctx = cds_get_context(QDF_MODULE_ID_QDF); + if (!cds_ctx) { + cds_err("Invalid CDS Context"); + return false; + } + + qdf_mutex_acquire(&cds_ctx->qdf_conc_list_lock); + if ((num_connections == 2) && + (conc_connection_list[0].chan != conc_connection_list[1].chan) + && + (conc_connection_list[0].mac == conc_connection_list[1].mac)) { + if (wma_is_hw_dbs_capable() == false) { + if ((channel != conc_connection_list[0].chan) && + (channel != conc_connection_list[1].chan)) { + cds_err("don't allow 3rd home channel on same MAC"); + status = false; + } + } else if (((CDS_IS_CHANNEL_24GHZ(channel)) && + (CDS_IS_CHANNEL_24GHZ + (conc_connection_list[0].chan)) && + (CDS_IS_CHANNEL_24GHZ + (conc_connection_list[1].chan))) || + ((CDS_IS_CHANNEL_5GHZ(channel)) && + (CDS_IS_CHANNEL_5GHZ + (conc_connection_list[0].chan)) && + (CDS_IS_CHANNEL_5GHZ + (conc_connection_list[1].chan)))) { + cds_err("don't allow 3rd home channel on same MAC"); + status = false; + } + } + qdf_mutex_release(&cds_ctx->qdf_conc_list_lock); + return status; +} + +/** + * cds_is_ibss_conn_exist() - to check if IBSS connection already present + * @hdd_ctx: pointer to hdd context + * @ibss_channel: pointer to ibss channel which needs to be filled + * + * this routine will check if IBSS connection already exist or no. If it + * exist then this routine will return true and fill the ibss_channel value. + * + * Return: true if ibss connection exist else false + */ +bool cds_is_ibss_conn_exist(uint8_t *ibss_channel) +{ + uint32_t count = 0, index = 0; + uint32_t list[MAX_NUMBER_OF_CONC_CONNECTIONS]; + bool status = false; + + cds_context_type *cds_ctx; + + cds_ctx = cds_get_context(QDF_MODULE_ID_QDF); + if (!cds_ctx) { + cds_err("Invalid CDS Context"); + return status; + } + if (NULL == ibss_channel) { + cds_err("Null pointer error"); + return false; + } + count = cds_mode_specific_connection_count(CDS_IBSS_MODE, list); + qdf_mutex_acquire(&cds_ctx->qdf_conc_list_lock); + if (count == 0) { + /* No IBSS connection */ + status = false; + } else if (count == 1) { + *ibss_channel = conc_connection_list[list[index]].chan; + status = true; + } else { + *ibss_channel = conc_connection_list[list[index]].chan; + cds_notice("Multiple IBSS connections, picking first one"); + status = true; + } + qdf_mutex_release(&cds_ctx->qdf_conc_list_lock); + return status; +} + +/** + * cds_is_5g_channel_allowed() - check if 5g channel is allowed + * @channel: channel number which needs to be validated + * @list: list of existing connections. + * @mode: mode against which channel needs to be validated + * + * This API takes the channel as input and compares with existing + * connection channels. If existing connection's channel is DFS channel + * and provided channel is 5G channel then don't allow concurrency to + * happen as MCC with DFS channel is not yet supported + * + * Return: true if 5G channel is allowed, false if not allowed + * + */ +static bool cds_is_5g_channel_allowed(uint8_t channel, uint32_t *list, + enum cds_con_mode mode) +{ + uint32_t index = 0, count = 0; + cds_context_type *cds_ctx; + + cds_ctx = cds_get_context(QDF_MODULE_ID_QDF); + if (!cds_ctx) { + cds_err("Invalid CDS Context"); + return false; + } + + count = cds_mode_specific_connection_count(mode, list); + qdf_mutex_acquire(&cds_ctx->qdf_conc_list_lock); + while (index < count) { + if (CDS_IS_DFS_CH(conc_connection_list[list[index]].chan) && + CDS_IS_CHANNEL_5GHZ(channel) && + (channel != conc_connection_list[list[index]].chan)) { + qdf_mutex_release(&cds_ctx->qdf_conc_list_lock); + cds_err("don't allow MCC if SAP/GO on DFS channel"); + return false; + } + index++; + } + qdf_mutex_release(&cds_ctx->qdf_conc_list_lock); + return true; + +} + +/** + * cds_allow_concurrency() - Check for allowed concurrency + * combination + * @mode: new connection mode + * @channel: channel on which new connection is coming up + * @bw: Bandwidth requested by the connection (optional) + * + * When a new connection is about to come up check if current + * concurrency combination including the new connection is + * allowed or not based on the HW capability + * + * Return: True/False + */ +bool cds_allow_concurrency(enum cds_con_mode mode, + uint8_t channel, enum hw_mode_bandwidth bw) +{ + uint32_t num_connections = 0, count = 0, index = 0; + bool status = false, match = false; + uint32_t list[MAX_NUMBER_OF_CONC_CONNECTIONS]; + hdd_context_t *hdd_ctx; + cds_context_type *cds_ctx; + QDF_STATUS ret; + struct sir_pcl_list pcl; + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (!hdd_ctx) { + cds_err("HDD context is NULL"); + return status; + } + + cds_ctx = cds_get_context(QDF_MODULE_ID_QDF); + if (!cds_ctx) { + cds_err("Invalid CDS Context"); + return status; + } + + + qdf_mem_zero(&pcl, sizeof(pcl)); + ret = cds_get_pcl(mode, pcl.pcl_list, &pcl.pcl_len, + pcl.weight_list, QDF_ARRAY_SIZE(pcl.weight_list)); + if (QDF_IS_STATUS_ERROR(ret)) { + cds_err("disallow connection:%d", ret); + goto done; + } + + /* find the current connection state from conc_connection_list*/ + num_connections = cds_get_connection_count(); + + if (num_connections && cds_is_sub_20_mhz_enabled()) { + cds_err("dont allow concurrency if Sub 20 MHz is enabled"); + status = false; + goto done; + } + + if (cds_max_concurrent_connections_reached()) { + cds_err("Reached max concurrent connections: %d", + hdd_ctx->config->gMaxConcurrentActiveSessions); + goto done; + } + + if (channel) { + /* don't allow 3rd home channel on same MAC */ + if (!cds_allow_new_home_channel(channel, num_connections)) + goto done; + + /* + * 1) DFS MCC is not yet supported + * 2) If you already have STA connection on 5G channel then + * don't allow any other persona to make connection on DFS + * channel because STA 5G + DFS MCC is not allowed. + * 3) If STA is on 2G channel and SAP is coming up on + * DFS channel then allow concurrency but make sure it is + * going to DBS and send PCL to firmware indicating that + * don't allow STA to roam to 5G channels. + */ + if (!cds_is_5g_channel_allowed(channel, list, CDS_P2P_GO_MODE)) + goto done; + if (!cds_is_5g_channel_allowed(channel, list, CDS_SAP_MODE)) + goto done; + + if ((CDS_P2P_GO_MODE == mode) || (CDS_SAP_MODE == mode)) { + if (CDS_IS_DFS_CH(channel)) + match = cds_disallow_mcc(channel); + } + if (true == match) { + cds_err("No MCC, SAP/GO about to come up on DFS channel"); + goto done; + } + } + + /* + * Check all IBSS+STA concurrencies + * + * don't allow IBSS + STA MCC + * don't allow IBSS + STA SCC if IBSS is on DFS channel + */ + count = cds_mode_specific_connection_count(CDS_STA_MODE, list); + if ((CDS_IBSS_MODE == mode) && + (cds_mode_specific_connection_count( + CDS_IBSS_MODE, list)) && count) { + cds_err("No 2nd IBSS, we already have STA + IBSS"); + goto done; + } + if ((CDS_IBSS_MODE == mode) && + (CDS_IS_DFS_CH(channel)) && count) { + cds_err("No IBSS + STA SCC/MCC, IBSS is on DFS channel"); + goto done; + } + if (CDS_IBSS_MODE == mode) { + if (wma_is_hw_dbs_capable() == true) { + if (num_connections > 1) { + cds_err("No IBSS, we have concurrent connections already"); + goto done; + } + qdf_mutex_acquire(&cds_ctx->qdf_conc_list_lock); + if (CDS_STA_MODE != conc_connection_list[0].mode) { + cds_err("No IBSS, we've a non-STA connection"); + qdf_mutex_release(&cds_ctx->qdf_conc_list_lock); + goto done; + } + /* + * This logic protects STA and IBSS to come up on same + * band. If requirement changes then this condition + * needs to be removed + */ + if (channel && + (conc_connection_list[0].chan != channel) && + CDS_IS_SAME_BAND_CHANNELS( + conc_connection_list[0].chan, channel)) { + qdf_mutex_release(&cds_ctx->qdf_conc_list_lock); + cds_err("No IBSS + STA MCC"); + goto done; + } + qdf_mutex_release(&cds_ctx->qdf_conc_list_lock); + } else if (num_connections) { + cds_err("No IBSS, we have one connection already"); + goto done; + } + } + + if ((CDS_STA_MODE == mode) && + (cds_mode_specific_connection_count( + CDS_IBSS_MODE, list)) && count) { + cds_err("No 2nd STA, we already have STA + IBSS"); + goto done; + } + + if ((CDS_STA_MODE == mode) && + (cds_mode_specific_connection_count(CDS_IBSS_MODE, list))) { + if (wma_is_hw_dbs_capable() == true) { + if (num_connections > 1) { + cds_err("No 2nd STA, we already have IBSS concurrency"); + goto done; + } + qdf_mutex_acquire(&cds_ctx->qdf_conc_list_lock); + if (channel && + (CDS_IS_DFS_CH(conc_connection_list[0].chan)) + && (CDS_IS_CHANNEL_5GHZ(channel))) { + qdf_mutex_release(&cds_ctx->qdf_conc_list_lock); + cds_err("No IBSS + STA SCC/MCC, IBSS is on DFS channel"); + goto done; + } + /* + * This logic protects STA and IBSS to come up on same + * band. If requirement changes then this condition + * needs to be removed + */ + if ((conc_connection_list[0].chan != channel) && + CDS_IS_SAME_BAND_CHANNELS( + conc_connection_list[0].chan, channel)) { + cds_err("No IBSS + STA MCC"); + qdf_mutex_release(&cds_ctx->qdf_conc_list_lock); + goto done; + } + qdf_mutex_release(&cds_ctx->qdf_conc_list_lock); + } else { + cds_err("No STA, we have IBSS connection already"); + goto done; + } + } + + /* don't allow two P2P GO on same band */ + if (channel && (mode == CDS_P2P_GO_MODE) && num_connections) { + index = 0; + count = cds_mode_specific_connection_count( + CDS_P2P_GO_MODE, list); + qdf_mutex_acquire(&cds_ctx->qdf_conc_list_lock); + while (index < count) { + if (CDS_IS_SAME_BAND_CHANNELS(channel, + conc_connection_list[list[index]].chan)) { + cds_err("Don't allow P2P GO on same band"); + qdf_mutex_release(&cds_ctx->qdf_conc_list_lock); + goto done; + } + index++; + } + qdf_mutex_release(&cds_ctx->qdf_conc_list_lock); + } + + status = true; + +done: + return status; +} + +/** + * cds_get_first_connection_pcl_table_index() - provides the + * row index to firstConnectionPclTable to get to the correct + * pcl + * + * This function provides the row index to + * firstConnectionPclTable. The index is the preference config. + * + * Return: table index + */ +enum cds_conc_priority_mode cds_get_first_connection_pcl_table_index(void) +{ + hdd_context_t *hdd_ctx; + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (!hdd_ctx) { + cds_err("HDD context is NULL"); + return CDS_THROUGHPUT; + } + + if (hdd_ctx->config->conc_system_pref >= CDS_MAX_CONC_PRIORITY_MODE) + return CDS_THROUGHPUT; + return hdd_ctx->config->conc_system_pref; +} + +/** + * cds_get_second_connection_pcl_table_index() - provides the + * row index to secondConnectionPclTable to get to the correct + * pcl + * + * This function provides the row index to + * secondConnectionPclTable. The index is derived based on + * current connection, band on which it is on & chain mask it is + * using, as obtained from conc_connection_list. + * + * Return: table index + */ +enum cds_one_connection_mode cds_get_second_connection_pcl_table_index(void) +{ + enum cds_one_connection_mode index = CDS_MAX_ONE_CONNECTION_MODE; + cds_context_type *cds_ctx; + + cds_ctx = cds_get_context(QDF_MODULE_ID_QDF); + if (!cds_ctx) { + cds_err("Invalid CDS Context"); + return index; + } + + qdf_mutex_acquire(&cds_ctx->qdf_conc_list_lock); + if (CDS_STA_MODE == conc_connection_list[0].mode) { + if (CDS_IS_CHANNEL_24GHZ(conc_connection_list[0].chan)) { + if (CDS_ONE_ONE == conc_connection_list[0].chain_mask) + index = CDS_STA_24_1x1; + else + index = CDS_STA_24_2x2; + } else { + if (CDS_ONE_ONE == conc_connection_list[0].chain_mask) + index = CDS_STA_5_1x1; + else + index = CDS_STA_5_2x2; + } + } else if (CDS_SAP_MODE == conc_connection_list[0].mode) { + if (CDS_IS_CHANNEL_24GHZ(conc_connection_list[0].chan)) { + if (CDS_ONE_ONE == conc_connection_list[0].chain_mask) + index = CDS_SAP_24_1x1; + else + index = CDS_SAP_24_2x2; + } else { + if (CDS_ONE_ONE == conc_connection_list[0].chain_mask) + index = CDS_SAP_5_1x1; + else + index = CDS_SAP_5_2x2; + } + } else if (CDS_P2P_CLIENT_MODE == conc_connection_list[0].mode) { + if (CDS_IS_CHANNEL_24GHZ(conc_connection_list[0].chan)) { + if (CDS_ONE_ONE == conc_connection_list[0].chain_mask) + index = CDS_P2P_CLI_24_1x1; + else + index = CDS_P2P_CLI_24_2x2; + } else { + if (CDS_ONE_ONE == conc_connection_list[0].chain_mask) + index = CDS_P2P_CLI_5_1x1; + else + index = CDS_P2P_CLI_5_2x2; + } + } else if (CDS_P2P_GO_MODE == conc_connection_list[0].mode) { + if (CDS_IS_CHANNEL_24GHZ(conc_connection_list[0].chan)) { + if (CDS_ONE_ONE == conc_connection_list[0].chain_mask) + index = CDS_P2P_GO_24_1x1; + else + index = CDS_P2P_GO_24_2x2; + } else { + if (CDS_ONE_ONE == conc_connection_list[0].chain_mask) + index = CDS_P2P_GO_5_1x1; + else + index = CDS_P2P_GO_5_2x2; + } + } else if (CDS_IBSS_MODE == conc_connection_list[0].mode) { + if (CDS_IS_CHANNEL_24GHZ(conc_connection_list[0].chan)) { + if (CDS_ONE_ONE == conc_connection_list[0].chain_mask) + index = CDS_IBSS_24_1x1; + else + index = CDS_IBSS_24_2x2; + } else { + if (CDS_ONE_ONE == conc_connection_list[0].chain_mask) + index = CDS_IBSS_5_1x1; + else + index = CDS_IBSS_5_2x2; + } + } + + cds_debug("mode:%d chan:%d chain:%d index:%d", + conc_connection_list[0].mode, conc_connection_list[0].chan, + conc_connection_list[0].chain_mask, index); + + qdf_mutex_release(&cds_ctx->qdf_conc_list_lock); + return index; +} + +/** + * cds_get_third_connection_pcl_table_index() - provides the + * row index to thirdConnectionPclTable to get to the correct + * pcl + * + * This function provides the row index to + * thirdConnectionPclTable. The index is derived based on + * current connection, band on which it is on & chain mask it is + * using, as obtained from conc_connection_list. + * + * Return: table index + */ +enum cds_two_connection_mode cds_get_third_connection_pcl_table_index(void) +{ + enum cds_one_connection_mode index = CDS_MAX_TWO_CONNECTION_MODE; + cds_context_type *cds_ctx; + + cds_ctx = cds_get_context(QDF_MODULE_ID_QDF); + if (!cds_ctx) { + cds_err("Invalid CDS Context"); + return index; + } + + qdf_mutex_acquire(&cds_ctx->qdf_conc_list_lock); + /* P2P Client + SAP */ + if (((CDS_P2P_CLIENT_MODE == conc_connection_list[0].mode) && + (CDS_SAP_MODE == conc_connection_list[1].mode)) || + ((CDS_SAP_MODE == conc_connection_list[0].mode) && + (CDS_P2P_CLIENT_MODE == conc_connection_list[1].mode))) { + /* SCC */ + if (conc_connection_list[0].chan == + conc_connection_list[1].chan) { + if (CDS_IS_CHANNEL_24GHZ( + conc_connection_list[0].chan)) { + if (CDS_ONE_ONE == + conc_connection_list[0].chain_mask) + index = CDS_P2P_CLI_SAP_SCC_24_1x1; + else + index = CDS_P2P_CLI_SAP_SCC_24_2x2; + } else { + if (CDS_ONE_ONE == + conc_connection_list[0].chain_mask) + index = CDS_P2P_CLI_SAP_SCC_5_1x1; + else + index = CDS_P2P_CLI_SAP_SCC_5_2x2; + } + /* MCC */ + } else if (conc_connection_list[0].mac == + conc_connection_list[1].mac) { + if ((CDS_IS_CHANNEL_24GHZ + (conc_connection_list[0].chan)) && + (CDS_IS_CHANNEL_24GHZ + (conc_connection_list[1].chan))) { + if (CDS_ONE_ONE == + conc_connection_list[0].chain_mask) + index = CDS_P2P_CLI_SAP_MCC_24_1x1; + else + index = CDS_P2P_CLI_SAP_MCC_24_2x2; + } else if ((CDS_IS_CHANNEL_5GHZ( + conc_connection_list[0].chan)) && + (CDS_IS_CHANNEL_5GHZ( + conc_connection_list[1].chan))) { + if (CDS_ONE_ONE == + conc_connection_list[0].chain_mask) + index = CDS_P2P_CLI_SAP_MCC_5_1x1; + else + index = CDS_P2P_CLI_SAP_MCC_5_2x2; + } else { + if (CDS_ONE_ONE == + conc_connection_list[0].chain_mask) + index = CDS_P2P_CLI_SAP_MCC_24_5_1x1; + else + index = CDS_P2P_CLI_SAP_MCC_24_5_2x2; + } + /* DBS */ + } else + index = CDS_P2P_CLI_SAP_DBS_1x1; + } else + /* STA + SAP */ + if (((CDS_STA_MODE == conc_connection_list[0].mode) && + (CDS_SAP_MODE == conc_connection_list[1].mode)) || + ((CDS_SAP_MODE == conc_connection_list[0].mode) && + (CDS_STA_MODE == conc_connection_list[1].mode))) { + /* SCC */ + if (conc_connection_list[0].chan == + conc_connection_list[1].chan) { + if (CDS_IS_CHANNEL_24GHZ( + conc_connection_list[0].chan)) { + if (CDS_ONE_ONE == + conc_connection_list[0].chain_mask) + index = CDS_STA_SAP_SCC_24_1x1; + else + index = CDS_STA_SAP_SCC_24_2x2; + } else { + if (CDS_ONE_ONE == + conc_connection_list[0].chain_mask) + index = CDS_STA_SAP_SCC_5_1x1; + else + index = CDS_STA_SAP_SCC_5_2x2; + } + /* MCC */ + } else if (conc_connection_list[0].mac == + conc_connection_list[1].mac) { + if ((CDS_IS_CHANNEL_24GHZ + (conc_connection_list[0].chan)) && + (CDS_IS_CHANNEL_24GHZ + (conc_connection_list[1].chan))) { + if (CDS_ONE_ONE == + conc_connection_list[0].chain_mask) + index = CDS_STA_SAP_MCC_24_1x1; + else + index = CDS_STA_SAP_MCC_24_2x2; + } else if ((CDS_IS_CHANNEL_5GHZ( + conc_connection_list[0].chan)) && + (CDS_IS_CHANNEL_5GHZ( + conc_connection_list[1].chan))) { + if (CDS_ONE_ONE == + conc_connection_list[0].chain_mask) + index = CDS_STA_SAP_MCC_5_1x1; + else + index = CDS_STA_SAP_MCC_5_2x2; + } else { + if (CDS_ONE_ONE == + conc_connection_list[0].chain_mask) + index = CDS_STA_SAP_MCC_24_5_1x1; + else + index = CDS_STA_SAP_MCC_24_5_2x2; + } + /* DBS */ + } else + index = CDS_STA_SAP_DBS_1x1; + } else /* STA + P2P GO */ + if (((CDS_STA_MODE == conc_connection_list[0].mode) && + (CDS_P2P_GO_MODE == conc_connection_list[1].mode)) || + ((CDS_P2P_GO_MODE == conc_connection_list[0].mode) && + (CDS_STA_MODE == conc_connection_list[1].mode))) { + /* SCC */ + if (conc_connection_list[0].chan == + conc_connection_list[1].chan) { + if (CDS_IS_CHANNEL_24GHZ + (conc_connection_list[0].chan)) { + if (CDS_ONE_ONE == + conc_connection_list[0].chain_mask) + index = CDS_STA_P2P_GO_SCC_24_1x1; + else + index = CDS_STA_P2P_GO_SCC_24_2x2; + } else { + if (CDS_ONE_ONE == + conc_connection_list[0].chain_mask) + index = CDS_STA_P2P_GO_SCC_5_1x1; + else + index = CDS_STA_P2P_GO_SCC_5_2x2; + } + /* MCC */ + } else if (conc_connection_list[0].mac == + conc_connection_list[1].mac) { + if ((CDS_IS_CHANNEL_24GHZ( + conc_connection_list[0].chan)) && + (CDS_IS_CHANNEL_24GHZ + (conc_connection_list[1].chan))) { + if (CDS_ONE_ONE == + conc_connection_list[0].chain_mask) + index = CDS_STA_P2P_GO_MCC_24_1x1; + else + index = CDS_STA_P2P_GO_MCC_24_2x2; + } else if ((CDS_IS_CHANNEL_5GHZ( + conc_connection_list[0].chan)) && + (CDS_IS_CHANNEL_5GHZ( + conc_connection_list[1].chan))) { + if (CDS_ONE_ONE == + conc_connection_list[0].chain_mask) + index = CDS_STA_P2P_GO_MCC_5_1x1; + else + index = CDS_STA_P2P_GO_MCC_5_2x2; + } else { + if (CDS_ONE_ONE == + conc_connection_list[0].chain_mask) + index = CDS_STA_P2P_GO_MCC_24_5_1x1; + else + index = CDS_STA_P2P_GO_MCC_24_5_2x2; + } + /* DBS */ + } else + index = CDS_STA_P2P_GO_DBS_1x1; + } else /* STA + P2P CLI */ + if (((CDS_STA_MODE == conc_connection_list[0].mode) && + (CDS_P2P_CLIENT_MODE == conc_connection_list[1].mode)) || + ((CDS_P2P_CLIENT_MODE == conc_connection_list[0].mode) && + (CDS_STA_MODE == conc_connection_list[1].mode))) { + /* SCC */ + if (conc_connection_list[0].chan == + conc_connection_list[1].chan) { + if (CDS_IS_CHANNEL_24GHZ + (conc_connection_list[0].chan)) { + if (CDS_ONE_ONE == + conc_connection_list[0].chain_mask) + index = CDS_STA_P2P_CLI_SCC_24_1x1; + else + index = CDS_STA_P2P_CLI_SCC_24_2x2; + } else { + if (CDS_ONE_ONE == + conc_connection_list[0].chain_mask) + index = CDS_STA_P2P_CLI_SCC_5_1x1; + else + index = CDS_STA_P2P_CLI_SCC_5_2x2; + } + /* MCC */ + } else if (conc_connection_list[0].mac == + conc_connection_list[1].mac) { + if ((CDS_IS_CHANNEL_24GHZ( + conc_connection_list[0].chan)) && + (CDS_IS_CHANNEL_24GHZ( + conc_connection_list[1].chan))) { + if (CDS_ONE_ONE == + conc_connection_list[0].chain_mask) + index = CDS_STA_P2P_CLI_MCC_24_1x1; + else + index = CDS_STA_P2P_CLI_MCC_24_2x2; + } else if ((CDS_IS_CHANNEL_5GHZ( + conc_connection_list[0].chan)) && + (CDS_IS_CHANNEL_5GHZ( + conc_connection_list[1].chan))) { + if (CDS_ONE_ONE == + conc_connection_list[0].chain_mask) + index = CDS_STA_P2P_CLI_MCC_5_1x1; + else + index = CDS_STA_P2P_CLI_MCC_5_2x2; + } else { + if (CDS_ONE_ONE == + conc_connection_list[0].chain_mask) + index = CDS_STA_P2P_CLI_MCC_24_5_1x1; + else + index = CDS_STA_P2P_CLI_MCC_24_5_2x2; + } + /* DBS */ + } else + index = CDS_STA_P2P_CLI_DBS_1x1; + } else /* P2P GO + P2P CLI */ + if (((CDS_P2P_GO_MODE == conc_connection_list[0].mode) && + (CDS_P2P_CLIENT_MODE == conc_connection_list[1].mode)) || + ((CDS_P2P_CLIENT_MODE == conc_connection_list[0].mode) && + (CDS_P2P_GO_MODE == conc_connection_list[1].mode))) { + /* SCC */ + if (conc_connection_list[0].chan == + conc_connection_list[1].chan) { + if (CDS_IS_CHANNEL_24GHZ( + conc_connection_list[0].chan)) { + if (CDS_ONE_ONE == + conc_connection_list[0].chain_mask) + index = CDS_P2P_GO_P2P_CLI_SCC_24_1x1; + else + index = CDS_P2P_GO_P2P_CLI_SCC_24_2x2; + } else { + if (CDS_ONE_ONE == + conc_connection_list[0].chain_mask) + index = CDS_P2P_GO_P2P_CLI_SCC_5_1x1; + else + index = CDS_P2P_GO_P2P_CLI_SCC_5_2x2; + } + /* MCC */ + } else if (conc_connection_list[0].mac == + conc_connection_list[1].mac) { + if ((CDS_IS_CHANNEL_24GHZ( + conc_connection_list[0].chan)) && + (CDS_IS_CHANNEL_24GHZ( + conc_connection_list[1].chan))) { + if (CDS_ONE_ONE == + conc_connection_list[0].chain_mask) + index = CDS_P2P_GO_P2P_CLI_MCC_24_1x1; + else + index = CDS_P2P_GO_P2P_CLI_MCC_24_2x2; + } else if ((CDS_IS_CHANNEL_5GHZ( + conc_connection_list[0].chan)) && + (CDS_IS_CHANNEL_5GHZ( + conc_connection_list[1].chan))) { + if (CDS_ONE_ONE == + conc_connection_list[0].chain_mask) + index = CDS_P2P_GO_P2P_CLI_MCC_5_1x1; + else + index = CDS_P2P_GO_P2P_CLI_MCC_5_2x2; + } else { + if (CDS_ONE_ONE == + conc_connection_list[0].chain_mask) + index = CDS_P2P_GO_P2P_CLI_MCC_24_5_1x1; + else + index = CDS_P2P_GO_P2P_CLI_MCC_24_5_2x2; + } + /* DBS */ + } else + index = CDS_P2P_GO_P2P_CLI_DBS_1x1; + } else /* STA + P2P CLI */ + if (((CDS_SAP_MODE == conc_connection_list[0].mode) && + (CDS_P2P_GO_MODE == conc_connection_list[1].mode)) || + ((CDS_P2P_GO_MODE == conc_connection_list[0].mode) && + (CDS_SAP_MODE == conc_connection_list[1].mode))) { + /* SCC */ + if (conc_connection_list[0].chan == + conc_connection_list[1].chan) { + if (CDS_IS_CHANNEL_24GHZ( + conc_connection_list[0].chan)) { + if (CDS_ONE_ONE == + conc_connection_list[0].chain_mask) + index = CDS_P2P_GO_SAP_SCC_24_1x1; + else + index = CDS_P2P_GO_SAP_SCC_24_2x2; + } else { + if (CDS_ONE_ONE == + conc_connection_list[0].chain_mask) + index = CDS_P2P_GO_SAP_SCC_5_1x1; + else + index = CDS_P2P_GO_SAP_SCC_5_2x2; + } + /* MCC */ + } else if (conc_connection_list[0].mac == + conc_connection_list[1].mac) { + if ((CDS_IS_CHANNEL_24GHZ( + conc_connection_list[0].chan)) && + (CDS_IS_CHANNEL_24GHZ( + conc_connection_list[1].chan))) { + if (CDS_ONE_ONE == + conc_connection_list[0].chain_mask) + index = CDS_P2P_GO_SAP_MCC_24_1x1; + else + index = CDS_P2P_GO_SAP_MCC_24_2x2; + } else if ((CDS_IS_CHANNEL_5GHZ( + conc_connection_list[0].chan)) && + (CDS_IS_CHANNEL_5GHZ( + conc_connection_list[1].chan))) { + if (CDS_ONE_ONE == + conc_connection_list[0].chain_mask) + index = CDS_P2P_GO_SAP_MCC_5_1x1; + else + index = CDS_P2P_GO_SAP_MCC_5_2x2; + } else { + if (CDS_ONE_ONE == + conc_connection_list[0].chain_mask) + index = CDS_P2P_GO_SAP_MCC_24_5_1x1; + else + index = CDS_P2P_GO_SAP_MCC_24_5_2x2; + } + /* DBS */ + } else + index = CDS_P2P_GO_SAP_DBS_1x1; + } + + cds_debug("mode0:%d mode1:%d chan0:%d chan1:%d chain:%d index:%d", + conc_connection_list[0].mode, conc_connection_list[1].mode, + conc_connection_list[0].chan, conc_connection_list[1].chan, + conc_connection_list[0].chain_mask, index); + + qdf_mutex_release(&cds_ctx->qdf_conc_list_lock); + return index; +} + +/** + * cds_update_and_wait_for_connection_update() - Update and wait for + * connection update + * @session_id: Session id + * @channel: Channel number + * @reason: Reason for connection update + * + * Update the connection to either single MAC or dual MAC and wait for the + * update to complete + * + * Return: QDF_STATUS + */ +QDF_STATUS cds_update_and_wait_for_connection_update(uint8_t session_id, + uint8_t channel, + enum sir_conn_update_reason reason) +{ + QDF_STATUS status; + + cds_debug("session:%d channel:%d reason:%d", + session_id, channel, reason); + + status = qdf_reset_connection_update(); + if (QDF_IS_STATUS_ERROR(status)) + cds_err("clearing event failed"); + + status = cds_current_connections_update(session_id, channel, reason); + if (QDF_STATUS_E_FAILURE == status) { + cds_err("connections update failed"); + return QDF_STATUS_E_FAILURE; + } + + /* Wait only when status is success */ + if (QDF_IS_STATUS_SUCCESS(status)) { + status = qdf_wait_for_connection_update(); + if (QDF_IS_STATUS_ERROR(status)) { + cds_err("qdf wait for event failed"); + return QDF_STATUS_E_FAILURE; + } + } + + return QDF_STATUS_SUCCESS; +} + +/** + * cds_current_connections_update() - initiates actions + * needed on current connections once channel has been decided + * for the new connection + * @session_id: Session id + * @channel: Channel on which new connection will be + * @reason: Reason for which connection update is required + * + * This function initiates initiates actions + * needed on current connections once channel has been decided + * for the new connection. Notifies UMAC & FW as well + * + * Return: QDF_STATUS enum + */ +QDF_STATUS cds_current_connections_update(uint32_t session_id, + uint8_t channel, + enum sir_conn_update_reason reason) +{ + enum cds_conc_next_action next_action = CDS_NOP; + uint32_t num_connections = 0; + enum cds_one_connection_mode second_index = 0; + enum cds_two_connection_mode third_index = 0; + enum cds_band band; + cds_context_type *cds_ctx; + hdd_context_t *hdd_ctx; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + + cds_ctx = cds_get_context(QDF_MODULE_ID_QDF); + if (!cds_ctx) { + cds_err("Invalid CDS Context"); + return status; + } + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (!hdd_ctx) { + cds_err("Invalid HDD context"); + return QDF_STATUS_E_FAILURE; + } + + if (wma_is_hw_dbs_capable() == false) { + cds_err("driver isn't dbs capable, no further action needed"); + return QDF_STATUS_E_NOSUPPORT; + } + if (CDS_IS_CHANNEL_24GHZ(channel)) + band = CDS_BAND_24; + else + band = CDS_BAND_5; + + num_connections = cds_get_connection_count(); + + cds_debug("num_connections=%d channel=%d", + num_connections, channel); + + switch (num_connections) { + case 0: + next_action = CDS_NOP; + break; + case 1: + second_index = + cds_get_second_connection_pcl_table_index(); + if (CDS_MAX_ONE_CONNECTION_MODE == second_index) { + cds_err("couldn't find index for 2nd connection next action table"); + goto done; + } + next_action = + next_action_two_connection_table[second_index][band]; + break; + case 2: + third_index = + cds_get_third_connection_pcl_table_index(); + if (CDS_MAX_TWO_CONNECTION_MODE == third_index) { + cds_err("couldn't find index for 3rd connection next action table"); + goto done; + } + next_action = + next_action_three_connection_table[third_index][band]; + break; + default: + cds_err("unexpected num_connections value %d", num_connections); + break; + } + + if (CDS_NOP != next_action) + status = cds_next_actions(session_id, + next_action, reason); + else + status = QDF_STATUS_E_NOSUPPORT; + + cds_debug("index2=%d index3=%d next_action=%d, band=%d status=%d reason=%d session_id=%d", + second_index, third_index, next_action, band, status, + reason, session_id); + +done: + return status; +} + +/** + * cds_nss_update_cb() - callback from SME confirming nss + * update + * @hdd_ctx: HDD Context + * @tx_status: tx completion status for updated beacon with new + * nss value + * @vdev_id: vdev id for the specific connection + * @next_action: next action to happen at policy mgr after + * beacon update + * @reason: Reason for nss update + * + * This function is the callback registered with SME at nss + * update request time + * + * Return: None + */ +static void cds_nss_update_cb(void *context, uint8_t tx_status, uint8_t vdev_id, + uint8_t next_action, + enum sir_conn_update_reason reason) +{ + cds_context_type *cds_ctx; + uint32_t conn_index = 0; + + if (QDF_STATUS_SUCCESS != tx_status) + cds_err("nss update failed(%d) for vdev %d", tx_status, vdev_id); + + cds_ctx = cds_get_context(QDF_MODULE_ID_QDF); + if (!cds_ctx) { + cds_err("Invalid CDS Context"); + return; + } + + /* + * Check if we are ok to request for HW mode change now + */ + conn_index = cds_get_connection_for_vdev_id(vdev_id); + if (MAX_NUMBER_OF_CONC_CONNECTIONS == conn_index) { + cds_err("connection not found for vdev %d", vdev_id); + return; + } + + cds_debug("nss update successful for vdev:%d", vdev_id); + cds_next_actions(vdev_id, next_action, reason); + return; +} + +/** + * cds_complete_action() - initiates actions needed on + * current connections once channel has been decided for the new + * connection + * @new_nss: the new nss value + * @next_action: next action to happen at policy mgr after + * beacon update + * @reason: Reason for connection update + * @session_id: Session id + * + * This function initiates initiates actions + * needed on current connections once channel has been decided + * for the new connection. Notifies UMAC & FW as well + * + * Return: QDF_STATUS enum + */ +static QDF_STATUS cds_complete_action(uint8_t new_nss, uint8_t next_action, + enum sir_conn_update_reason reason, + uint32_t session_id) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + uint32_t index, count; + uint32_t list[MAX_NUMBER_OF_CONC_CONNECTIONS]; + uint32_t conn_index = 0; + hdd_context_t *hdd_ctx; + uint32_t vdev_id; + uint32_t original_nss; + cds_context_type *cds_ctx; + + cds_ctx = cds_get_context(QDF_MODULE_ID_QDF); + if (!cds_ctx) { + cds_err("Invalid CDS Context"); + return status; + } + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (!hdd_ctx) { + cds_err("HDD context is NULL"); + return status; + } + + if (wma_is_hw_dbs_capable() == false) { + cds_err("driver isn't dbs capable, no further action needed"); + return QDF_STATUS_E_NOSUPPORT; + } + + /* cds_complete_action() is called by cds_next_actions(). + * All other callers of cds_next_actions() have taken mutex + * protection. So, not taking any lock inside cds_complete_action() + * during conc_connection_list access. + */ + count = cds_mode_specific_connection_count( + CDS_P2P_GO_MODE, list); + for (index = 0; index < count; index++) { + qdf_mutex_acquire(&cds_ctx->qdf_conc_list_lock); + vdev_id = conc_connection_list[list[index]].vdev_id; + original_nss = conc_connection_list[list[index]].original_nss; + qdf_mutex_release(&cds_ctx->qdf_conc_list_lock); + conn_index = cds_get_connection_for_vdev_id(vdev_id); + if (MAX_NUMBER_OF_CONC_CONNECTIONS == conn_index) { + cds_err("connection not found for vdev %d", + vdev_id); + continue; + } + + if (2 == original_nss) { + status = sme_nss_update_request(hdd_ctx->hHal, + vdev_id, new_nss, + cds_nss_update_cb, + next_action, hdd_ctx, reason); + if (!QDF_IS_STATUS_SUCCESS(status)) { + cds_err("sme_nss_update_request() failed for vdev %d", + vdev_id); + } + } + } + + count = cds_mode_specific_connection_count( + CDS_SAP_MODE, list); + for (index = 0; index < count; index++) { + qdf_mutex_acquire(&cds_ctx->qdf_conc_list_lock); + vdev_id = conc_connection_list[list[index]].vdev_id; + original_nss = conc_connection_list[list[index]].original_nss; + qdf_mutex_release(&cds_ctx->qdf_conc_list_lock); + conn_index = cds_get_connection_for_vdev_id(vdev_id); + if (MAX_NUMBER_OF_CONC_CONNECTIONS == conn_index) { + cds_err("connection not found for vdev %d", + vdev_id); + continue; + } + if (2 == original_nss) { + status = sme_nss_update_request(hdd_ctx->hHal, + vdev_id, new_nss, + cds_nss_update_cb, + next_action, hdd_ctx, reason); + if (!QDF_IS_STATUS_SUCCESS(status)) { + cds_err("sme_nss_update_request() failed for vdev %d", + vdev_id); + } + } + } + if (!QDF_IS_STATUS_SUCCESS(status)) + status = cds_next_actions(session_id, + next_action, reason); + + return status; +} + +/** + * cds_next_actions() - initiates actions needed on current + * connections once channel has been decided for the new + * connection + * @session_id: Session id + * @action: action to be executed + * @reason: Reason for connection update + * + * This function initiates initiates actions + * needed on current connections once channel has been decided + * for the new connection. Notifies UMAC & FW as well + * + * Return: QDF_STATUS enum + */ +QDF_STATUS cds_next_actions(uint32_t session_id, + enum cds_conc_next_action action, + enum sir_conn_update_reason reason) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + struct sir_hw_mode_params hw_mode; + + if (wma_is_hw_dbs_capable() == false) { + cds_err("driver isn't dbs capable, no further action needed"); + return QDF_STATUS_E_NOSUPPORT; + } + + /* check for the current HW index to see if really need any action */ + status = wma_get_current_hw_mode(&hw_mode); + if (!QDF_IS_STATUS_SUCCESS(status)) { + cds_err("wma_get_current_hw_mode failed"); + return status; + } + /** + * if already in DBS no need to request DBS. Might be needed + * to extend the logic when multiple dbs HW mode is available + */ + if ((((CDS_DBS_DOWNGRADE == action) || (CDS_DBS == action)) + && hw_mode.dbs_cap)) { + cds_err("driver is already in %s mode, no further action needed", + (hw_mode.dbs_cap) ? "dbs" : "non dbs"); + return QDF_STATUS_E_ALREADY; + } + + switch (action) { + case CDS_DBS_DOWNGRADE: + /* + * check if we have a beaconing entity that is using 2x2. If yes, + * update the beacon template & notify FW. Once FW confirms + * beacon updated, send down the HW mode change req + */ + status = cds_complete_action(CDS_RX_NSS_1, CDS_DBS, reason, + session_id); + break; + case CDS_DBS: + status = cds_pdev_set_hw_mode(session_id, + HW_MODE_SS_1x1, + HW_MODE_80_MHZ, + HW_MODE_SS_1x1, HW_MODE_40_MHZ, + HW_MODE_DBS, + HW_MODE_AGILE_DFS_NONE, + HW_MODE_SBS_NONE, + reason); + break; + case CDS_SINGLE_MAC_UPGRADE: + /* + * change the HW mode first before the NSS upgrade + */ + status = cds_pdev_set_hw_mode(session_id, + HW_MODE_SS_2x2, + HW_MODE_80_MHZ, + HW_MODE_SS_0x0, HW_MODE_BW_NONE, + HW_MODE_DBS_NONE, + HW_MODE_AGILE_DFS_NONE, + HW_MODE_SBS_NONE, + reason); + /* + * check if we have a beaconing entity that advertised 2x2 + * intially. If yes, update the beacon template & notify FW. + * Once FW confirms beacon updated, send the HW mode change req + */ + status = cds_complete_action(CDS_RX_NSS_2, CDS_SINGLE_MAC, + reason, session_id); + break; + case CDS_SINGLE_MAC: + status = cds_pdev_set_hw_mode(session_id, + HW_MODE_SS_2x2, + HW_MODE_80_MHZ, + HW_MODE_SS_0x0, HW_MODE_BW_NONE, + HW_MODE_DBS_NONE, + HW_MODE_AGILE_DFS_NONE, + HW_MODE_SBS_NONE, + reason); + break; + default: + cds_err("unexpected action value %d", action); + status = QDF_STATUS_E_FAILURE; + break; + } + + return status; +} + +/** + * cds_get_concurrency_mode() - return concurrency mode + * + * This routine is used to retrieve concurrency mode + * + * Return: uint32_t value of concurrency mask + */ +uint32_t cds_get_concurrency_mode(void) +{ + hdd_context_t *hdd_ctx; + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (NULL != hdd_ctx) { + cds_info("concurrency_mode = 0x%x", + hdd_ctx->concurrency_mode); + return hdd_ctx->concurrency_mode; + } + + /* we are in an invalid state :( */ + cds_err("Invalid context"); + return QDF_STA_MASK; +} + +/** + * cds_sap_restart_handle() - to handle restarting of SAP + * @work: name of the work + * + * Purpose of this function is to trigger sap start. this function + * will be called from workqueue. + * + * Return: void. + */ +static void cds_sap_restart_handle(struct work_struct *work) +{ + hdd_adapter_t *sap_adapter; + hdd_context_t *hdd_ctx = container_of(work, hdd_context_t, + sap_start_work); + cds_ssr_protect(__func__); + if (0 != wlan_hdd_validate_context(hdd_ctx)) { + cds_ssr_unprotect(__func__); + return; + } + sap_adapter = hdd_get_adapter(hdd_ctx, QDF_SAP_MODE); + if (sap_adapter == NULL) { + cds_err("sap_adapter is NULL"); + cds_ssr_unprotect(__func__); + return; + } + wlan_hdd_start_sap(sap_adapter, false); + + cds_change_sap_restart_required_status(false); + cds_ssr_unprotect(__func__); +} + +/** + * cds_check_and_restart_sap() - Check and restart sap if required + * @roam_result: Roam result + * @hdd_sta_ctx: HDD station context + * + * This routine will restart the SAP if restart is pending + * + * Return: QDF_STATUS + */ +QDF_STATUS cds_check_and_restart_sap(eCsrRoamResult roam_result, + hdd_station_ctx_t *hdd_sta_ctx) +{ + hdd_adapter_t *sap_adapter = NULL; + hdd_ap_ctx_t *hdd_ap_ctx = NULL; + uint8_t default_sap_channel = 6; + hdd_context_t *hdd_ctx; + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (!hdd_ctx) { + cds_err("HDD context is NULL"); + return QDF_STATUS_E_FAILURE; + } + + if (!(hdd_ctx->config->conc_custom_rule1 && + (true == cds_is_sap_restart_required()))) + return QDF_STATUS_SUCCESS; + + sap_adapter = hdd_get_adapter(hdd_ctx, QDF_SAP_MODE); + if (sap_adapter == NULL) { + cds_err("sap_adapter is NULL"); + return QDF_STATUS_E_FAILURE; + } + + if (test_bit(SOFTAP_BSS_STARTED, &sap_adapter->event_flags)) { + cds_err("SAP is already in started state"); + return QDF_STATUS_E_FAILURE; + } + + hdd_ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(sap_adapter); + if (hdd_ap_ctx == NULL) { + cds_err("HDD sap context is NULL"); + return QDF_STATUS_E_FAILURE; + } + if ((eCSR_ROAM_RESULT_ASSOCIATED == roam_result) && + hdd_sta_ctx->conn_info.operationChannel < + SIR_11A_CHANNEL_BEGIN) { + cds_err("Starting SAP on chnl [%d] after STA assoc complete", + hdd_sta_ctx->conn_info.operationChannel); + hdd_ap_ctx->operatingChannel = + hdd_sta_ctx->conn_info.operationChannel; + } else { + /* start on default SAP channel */ + hdd_ap_ctx->operatingChannel = + default_sap_channel; + cds_err("Starting SAP on channel [%d] after STA assoc failed", + default_sap_channel); + } + hdd_ap_ctx->sapConfig.ch_params.ch_width = + hdd_ap_ctx->sapConfig.ch_width_orig; + + cds_set_channel_params(hdd_ap_ctx->operatingChannel, + hdd_ap_ctx->sapConfig.sec_ch, + &hdd_ap_ctx->sapConfig.ch_params); + /* + * Create a workqueue and let the workqueue handle the restart + * of sap task. if we directly call sap restart function without + * creating workqueue then our main thread might go to sleep + * which is not acceptable. + */ + INIT_WORK(&hdd_ctx->sap_start_work, + cds_sap_restart_handle); + schedule_work(&hdd_ctx->sap_start_work); + return QDF_STATUS_SUCCESS; +} + +/** + * cds_sta_sap_concur_handle() - This function will handle Station and sap + * concurrency. + * @sta_adapter: pointer to station adapter. + * @roam_profile: pointer to station's roam profile. + * + * This function will find the AP to which station is likely to make the + * the connection, if that AP's channel happens to be different than + * SAP's channel then this function will stop the SAP. + * + * Return: true or false based on function's overall success. + */ +static bool cds_sta_sap_concur_handle(hdd_adapter_t *sta_adapter, + tCsrRoamProfile *roam_profile) +{ + hdd_adapter_t *ap_adapter; + bool are_cc_channels_same = false; + tScanResultHandle scan_cache = NULL; + QDF_STATUS status; + hdd_context_t *hdd_ctx; + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (!hdd_ctx) { + cds_err("HDD context is NULL"); + return are_cc_channels_same; + } + + ap_adapter = hdd_get_adapter(hdd_ctx, QDF_SAP_MODE); + if ((ap_adapter != NULL) && + test_bit(SOFTAP_BSS_STARTED, &ap_adapter->event_flags)) { + status = + wlan_hdd_check_custom_con_channel_rules(sta_adapter, + ap_adapter, roam_profile, &scan_cache, + &are_cc_channels_same); + if (QDF_STATUS_SUCCESS != status) { + cds_err("wlan_hdd_check_custom_con_channel_rules failed!"); + /* Not returning */ + } + status = sme_scan_result_purge( + WLAN_HDD_GET_HAL_CTX(sta_adapter), + scan_cache); + if (QDF_STATUS_SUCCESS != status) { + cds_err("sme_scan_result_purge failed!"); + /* Not returning */ + } + /* + * are_cc_channels_same will be false incase if SAP and STA + * channel is different or STA channel is zero. + * incase if STA channel is zero then lets stop the AP and + * restart flag set, so later whenever STA channel is defined + * we can restart our SAP in that channel. + */ + if (false == are_cc_channels_same) { + cds_info("Stop AP due to mismatch with STA channel"); + wlan_hdd_stop_sap(ap_adapter); + cds_change_sap_restart_required_status(true); + return false; + } else { + cds_info("sap channels are same"); + } + } + return true; +} + +#ifdef FEATURE_WLAN_CH_AVOID +/** + * cds_sta_p2pgo_concur_handle() - This function will handle Station and GO + * concurrency. + * @sta_adapter: pointer to station adapter. + * @roam_profile: pointer to station's roam profile. + * @roam_id: reference to roam_id variable being passed. + * + * This function will find the AP to which station is likely to make the + * the connection, if that AP's channel happens to be different than our + * P2PGO's channel then this function will send avoid frequency event to + * framework to make P2PGO stop and also caches station's connect request. + * + * Return: true or false based on function's overall success. + */ +static bool cds_sta_p2pgo_concur_handle(hdd_adapter_t *sta_adapter, + tCsrRoamProfile *roam_profile, + uint32_t *roam_id) +{ + hdd_adapter_t *p2pgo_adapter; + bool are_cc_channels_same = false; + tScanResultHandle scan_cache = NULL; + uint32_t p2pgo_channel_num, freq; + tHddAvoidFreqList hdd_avoid_freq_list; + QDF_STATUS status; + bool ret; + hdd_context_t *hdd_ctx; + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (!hdd_ctx) { + cds_err("HDD context is NULL"); + return are_cc_channels_same; + } + p2pgo_adapter = hdd_get_adapter(hdd_ctx, QDF_P2P_GO_MODE); + if ((p2pgo_adapter != NULL) && + test_bit(SOFTAP_BSS_STARTED, &p2pgo_adapter->event_flags)) { + status = + wlan_hdd_check_custom_con_channel_rules(sta_adapter, + p2pgo_adapter, roam_profile, + &scan_cache, &are_cc_channels_same); + if (QDF_STATUS_SUCCESS != status) { + cds_err("wlan_hdd_check_custom_con_channel_rules failed"); + /* Not returning */ + } + /* + * are_cc_channels_same will be false incase if P2PGO and STA + * channel is different or STA channel is zero. + */ + if (false == are_cc_channels_same) { + if (true == cds_is_sta_connection_pending()) { + MTRACE(qdf_trace(QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_CLEAR_JOIN_REQ, + sta_adapter->sessionId, *roam_id)); + ret = sme_clear_joinreq_param( + WLAN_HDD_GET_HAL_CTX(sta_adapter), + sta_adapter->sessionId); + if (true != ret) { + cds_err("sme_clear_joinreq_param failed"); + /* Not returning */ + } + cds_change_sta_conn_pending_status(false); + cds_info("===>Clear pending join req"); + } + MTRACE(qdf_trace(QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_STORE_JOIN_REQ, + sta_adapter->sessionId, *roam_id)); + /* store the scan cache here */ + ret = sme_store_joinreq_param( + WLAN_HDD_GET_HAL_CTX(sta_adapter), + roam_profile, + scan_cache, + roam_id, + sta_adapter->sessionId); + if (true != ret) { + cds_err("sme_store_joinreq_param failed"); + status = sme_scan_result_purge( + WLAN_HDD_GET_HAL_CTX( + sta_adapter), + scan_cache); + if (QDF_STATUS_SUCCESS != status) { + cds_err("sme_scan_result_purge failed"); + /* Not returning */ + } + /* Not returning */ + } + cds_change_sta_conn_pending_status(true); + /* + * fill frequency avoidance event and send it up, so + * p2pgo stop event should get trigger from upper layer + */ + p2pgo_channel_num = + WLAN_HDD_GET_AP_CTX_PTR(p2pgo_adapter)-> + operatingChannel; + if (p2pgo_channel_num <= 14) { + freq = ieee80211_channel_to_frequency( + p2pgo_channel_num, + NL80211_BAND_2GHZ); + } else { + freq = ieee80211_channel_to_frequency( + p2pgo_channel_num, + NL80211_BAND_5GHZ); + } + qdf_mem_zero(&hdd_avoid_freq_list, + sizeof(hdd_avoid_freq_list)); + hdd_avoid_freq_list.avoidFreqRangeCount = 1; + hdd_avoid_freq_list.avoidFreqRange[0].startFreq = freq; + hdd_avoid_freq_list.avoidFreqRange[0].endFreq = freq; + wlan_hdd_send_avoid_freq_event(hdd_ctx, + &hdd_avoid_freq_list); + cds_info("===>Sending chnl_avoid ch[%d] freq[%d]", + p2pgo_channel_num, freq); + cds_info("=>Stop GO due to mismatch with STA channel"); + return false; + } else { + cds_info("===>p2pgo channels are same"); + status = sme_scan_result_purge( + WLAN_HDD_GET_HAL_CTX(sta_adapter), + scan_cache); + if (QDF_STATUS_SUCCESS != status) { + cds_err("sme_scan_result_purge failed"); + /* Not returning */ + } + } + } + return true; +} +#endif + +/** + * cds_handle_conc_rule1() - Check if concurrency rule1 is enabled + * @adapter: HDD adpater + * @roam_profile: Profile for connection + * + * Check if concurrency rule1 is enabled. As per rule1, if station is trying to + * connect to some AP in 2.4Ghz and SAP is already in started state then SAP + * should restart in station's + * + * Return: None + */ +void cds_handle_conc_rule1(hdd_adapter_t *adapter, + tCsrRoamProfile *roam_profile) +{ + bool ret; + hdd_context_t *hdd_ctx; + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (!hdd_ctx) { + cds_err("HDD context is NULL"); + return; + } + + /* + * Custom concurrency rule1: As per this rule if station is + * trying to connect to some AP in 2.4Ghz and SAP is already + * in started state then SAP should restart in station's + * channel. + */ + if (hdd_ctx->config->conc_custom_rule1 && + (QDF_STA_MODE == adapter->device_mode)) { + ret = cds_sta_sap_concur_handle(adapter, + roam_profile); + if (true != ret) { + cds_err("cds_sta_sap_concur_handle failed"); + /* Nothing to do for now */ + } + } +} + +#ifdef FEATURE_WLAN_CH_AVOID +/** + * cds_handle_conc_rule2() - Check if concurrency rule2 is enabled + * @adapter: HDD adpater + * @roam_profile: Profile for connection + * + * Check if concurrency rule1 is enabled. As per rule1, if station is trying to + * connect to some AP in 5Ghz and P2PGO is already in started state then P2PGO + * should restart in station's channel + * + * Return: None + */ +bool cds_handle_conc_rule2(hdd_adapter_t *adapter, + tCsrRoamProfile *roam_profile, + uint32_t *roam_id) +{ + hdd_context_t *hdd_ctx; + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (!hdd_ctx) { + cds_err("HDD context is NULL"); + return false; + } + + /* + * Custom concurrency rule2: As per this rule if station is + * trying to connect to some AP in 5Ghz and P2PGO is already in + * started state then P2PGO should restart in station's channel. + */ + if (hdd_ctx->config->conc_custom_rule2 && + (QDF_STA_MODE == adapter->device_mode)) { + if (false == cds_sta_p2pgo_concur_handle( + adapter, roam_profile, roam_id)) { + cds_err("P2PGO-STA chnl diff, cache join req"); + return false; + } + } + return true; +} +#endif + +/** + * cds_get_channel_from_scan_result() - to get channel from scan result + * @adapter: station adapter + * @roam_profile: pointer to roam profile + * @channel: channel to be filled + * + * This routine gets channel which most likely a candidate to which STA + * will make connection. + * + * Return: QDF_STATUS + */ +QDF_STATUS cds_get_channel_from_scan_result(hdd_adapter_t *adapter, + tCsrRoamProfile *roam_profile, uint8_t *channel) +{ + QDF_STATUS status; + tScanResultHandle scan_cache = NULL; + + status = sme_get_ap_channel_from_scan_cache( + WLAN_HDD_GET_HAL_CTX(adapter), + roam_profile, &scan_cache, + channel); + sme_scan_result_purge(WLAN_HDD_GET_HAL_CTX(adapter), scan_cache); + return status; +} + +/** + * cds_search_and_check_for_session_conc() - Checks if concurrecy is allowed + * @session_id: Session id + * @roam_profile: Pointer to the roam profile + * + * Searches and gets the channel number from the scan results and checks if + * concurrency is allowed for the given session ID + * + * Non zero channel number if concurrency is allowed, zero otherwise + */ +uint8_t cds_search_and_check_for_session_conc(uint8_t session_id, + tCsrRoamProfile *roam_profile) +{ + uint8_t channel = 0; + QDF_STATUS status; + hdd_context_t *hdd_ctx; + hdd_adapter_t *adapter; + bool ret; + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (!hdd_ctx) { + cds_err("Invalid HDD context"); + return channel; + } + + adapter = hdd_get_adapter_by_vdev(hdd_ctx, session_id); + if (!adapter) { + cds_err("Invalid HDD adapter"); + return channel; + } + + status = cds_get_channel_from_scan_result(adapter, + roam_profile, &channel); + if ((QDF_STATUS_SUCCESS != status) || (channel == 0)) { + cds_err("%s error %d %d", + __func__, status, channel); + return 0; + } + + /* Take care of 160MHz and 80+80Mhz later */ + ret = cds_allow_concurrency( + cds_convert_device_mode_to_qdf_type( + adapter->device_mode), + channel, HW_MODE_20_MHZ); + if (false == ret) { + cds_err("Connection failed due to conc check fail"); + return 0; + } + + return channel; +} + +/** + * cds_check_for_session_conc() - Check if concurrency is allowed for a session + * @session_id: Session ID + * @channel: Channel number + * + * Checks if connection is allowed for a given session_id + * + * True if the concurrency is allowed, false otherwise + */ +bool cds_check_for_session_conc(uint8_t session_id, uint8_t channel) +{ + hdd_context_t *hdd_ctx; + hdd_adapter_t *adapter; + bool ret; + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (!hdd_ctx) { + cds_err("Invalid HDD context"); + return false; + } + + adapter = hdd_get_adapter_by_vdev(hdd_ctx, session_id); + if (!adapter) { + cds_err("Invalid HDD adapter"); + return false; + } + + if (channel == 0) { + cds_err("Invalid channel number 0"); + return false; + } + + /* Take care of 160MHz and 80+80Mhz later */ + ret = cds_allow_concurrency( + cds_convert_device_mode_to_qdf_type( + adapter->device_mode), + channel, HW_MODE_20_MHZ); + if (false == ret) { + cds_err("Connection failed due to conc check fail"); + return 0; + } + + return true; +} + +/** + * cds_handle_conc_multiport() - to handle multiport concurrency + * @session_id: Session ID + * @channel: Channel number + * + * This routine will handle STA side concurrency when policy manager + * is enabled. + * + * Return: QDF_STATUS + */ +QDF_STATUS cds_handle_conc_multiport(uint8_t session_id, uint8_t channel) +{ + QDF_STATUS status; + + if (!cds_check_for_session_conc(session_id, channel)) { + cds_err("Conc not allowed for the session %d", session_id); + return QDF_STATUS_E_FAILURE; + } + + status = qdf_reset_connection_update(); + if (!QDF_IS_STATUS_SUCCESS(status)) + cds_err("clearing event failed"); + + status = cds_current_connections_update(session_id, + channel, + SIR_UPDATE_REASON_NORMAL_STA); + if (QDF_STATUS_E_FAILURE == status) { + cds_err("connections update failed"); + return status; + } + + return status; +} + +#ifdef FEATURE_WLAN_FORCE_SAP_SCC +/** + * cds_restart_softap() - restart SAP on STA channel to support + * STA + SAP concurrency. + * + * @pHostapdAdapter: pointer to hdd adapter + * + * Return: None + */ +void cds_restart_softap(hdd_adapter_t *pHostapdAdapter) +{ + tHddAvoidFreqList hdd_avoid_freq_list; + hdd_context_t *hdd_ctx; + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (!hdd_ctx) { + cds_err("HDD context is NULL"); + return; + } + + /* generate vendor specific event */ + qdf_mem_zero((void *)&hdd_avoid_freq_list, sizeof(tHddAvoidFreqList)); + hdd_avoid_freq_list.avoidFreqRange[0].startFreq = + cds_chan_to_freq(pHostapdAdapter->sessionCtx.ap. + operatingChannel); + hdd_avoid_freq_list.avoidFreqRange[0].endFreq = + cds_chan_to_freq(pHostapdAdapter->sessionCtx.ap. + operatingChannel); + hdd_avoid_freq_list.avoidFreqRangeCount = 1; + wlan_hdd_send_avoid_freq_event(hdd_ctx, &hdd_avoid_freq_list); +} + +/** + * cds_force_sap_on_scc() - Force SAP on SCC + * @roam_result: Roam result + * @channel_id: STA channel id + * + * Restarts SAP on SCC if its operating channel is different from that of the + * STA-AP interface + * + * Return: None + */ +void cds_force_sap_on_scc(eCsrRoamResult roam_result, + uint8_t channel_id) +{ + hdd_adapter_t *hostapd_adapter; + hdd_context_t *hdd_ctx; + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (!hdd_ctx) { + cds_err("HDD context is NULL"); + return; + } + + if (!(eCSR_ROAM_RESULT_ASSOCIATED == roam_result && + hdd_ctx->config->SapSccChanAvoidance)) { + cds_err("Not able to force SAP on SCC"); + return; + } + hostapd_adapter = hdd_get_adapter(hdd_ctx, QDF_SAP_MODE); + if (hostapd_adapter != NULL) { + /* Restart SAP if its operating channel is different + * from AP channel. + */ + if (hostapd_adapter->sessionCtx.ap.operatingChannel != + channel_id) { + cds_err("Restart SAP: SAP channel-%d, STA channel-%d", + hostapd_adapter->sessionCtx.ap.operatingChannel, + channel_id); + cds_restart_softap(hostapd_adapter); + } + } +} +#endif /* FEATURE_WLAN_FORCE_SAP_SCC */ + +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH +/** + * cds_check_sta_ap_concurrent_ch_intf() - Restart SAP in STA-AP case + * @data: Pointer to STA adapter + * + * Restarts the SAP interface in STA-AP concurrency scenario + * + * Restart: None + */ +static void cds_check_sta_ap_concurrent_ch_intf(void *data) +{ + hdd_adapter_t *ap_adapter = NULL, *sta_adapter = (hdd_adapter_t *) data; + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(sta_adapter); + tHalHandle *hal_handle; + hdd_ap_ctx_t *hdd_ap_ctx; + uint16_t intf_ch = 0; + p_cds_contextType cds_ctx; + + cds_ctx = cds_get_global_context(); + if (!cds_ctx) { + cds_err("Invalid CDS context"); + return; + } + + cds_info("cds_concurrent_open_sessions_running: %d", + cds_concurrent_open_sessions_running()); + + if ((hdd_ctx->config->WlanMccToSccSwitchMode == + QDF_MCC_TO_SCC_SWITCH_DISABLE) + || !(cds_concurrent_open_sessions_running() + || !(cds_get_concurrency_mode() == + (QDF_STA_MASK | QDF_SAP_MASK)))) + return; + + ap_adapter = hdd_get_adapter(hdd_ctx, QDF_SAP_MODE); + if (ap_adapter == NULL) + return; + + if (!test_bit(SOFTAP_BSS_STARTED, &ap_adapter->event_flags)) + return; + + hdd_ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(ap_adapter); + hal_handle = WLAN_HDD_GET_HAL_CTX(ap_adapter); + + if (hal_handle == NULL) + return; + + qdf_mutex_acquire(&cds_ctx->qdf_conc_list_lock); + intf_ch = wlansap_check_cc_intf(hdd_ap_ctx->sapContext); + cds_info("intf_ch:%d", intf_ch); + + if (intf_ch == 0) { + qdf_mutex_release(&cds_ctx->qdf_conc_list_lock); + return; + } + + cds_info("SAP restarts due to MCC->SCC switch, orig chan: %d, new chan: %d", + hdd_ap_ctx->sapConfig.channel, intf_ch); + + hdd_ap_ctx->sapConfig.channel = intf_ch; + hdd_ap_ctx->sapConfig.ch_params.ch_width = + hdd_ap_ctx->sapConfig.ch_width_orig; + hdd_ap_ctx->bss_stop_reason = BSS_STOP_DUE_TO_MCC_SCC_SWITCH; + cds_set_channel_params(hdd_ap_ctx->sapConfig.channel, + hdd_ap_ctx->sapConfig.sec_ch, + &hdd_ap_ctx->sapConfig.ch_params); + + if (((hdd_ctx->config->WlanMccToSccSwitchMode == + QDF_MCC_TO_SCC_SWITCH_FORCE_WITHOUT_DISCONNECTION) || + (hdd_ctx->config->WlanMccToSccSwitchMode == + QDF_MCC_TO_SCC_SWITCH_WITH_FAVORITE_CHANNEL)) && + (cds_ctx->sap_restart_chan_switch_cb)) { + cds_info("SAP chan change without restart"); + cds_ctx->sap_restart_chan_switch_cb(ap_adapter, + hdd_ap_ctx->sapConfig.channel, + hdd_ap_ctx->sapConfig.ch_params.ch_width); + } else { + cds_restart_sap(ap_adapter); + } + qdf_mutex_release(&cds_ctx->qdf_conc_list_lock); +} + +/** + * cds_check_concurrent_intf_and_restart_sap() - Check concurrent change intf + * @adapter: Pointer to HDD adapter + * + * Checks the concurrent change interface and restarts SAP + * Return: None + */ +void cds_check_concurrent_intf_and_restart_sap(hdd_adapter_t *adapter) +{ + hdd_context_t *hdd_ctx; + hdd_station_ctx_t *hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (!hdd_ctx) { + cds_err("HDD context is NULL"); + return; + } + + cds_info("mode:%d rule1:%d rule2:%d chan:%d", + hdd_ctx->config->WlanMccToSccSwitchMode, + hdd_ctx->config->conc_custom_rule1, + hdd_ctx->config->conc_custom_rule2, + hdd_sta_ctx->conn_info.operationChannel); + + if ((hdd_ctx->config->WlanMccToSccSwitchMode + != QDF_MCC_TO_SCC_SWITCH_DISABLE) && + ((0 == hdd_ctx->config->conc_custom_rule1) && + (0 == hdd_ctx->config->conc_custom_rule2)) +#ifdef FEATURE_WLAN_STA_AP_MODE_DFS_DISABLE + && !CDS_IS_DFS_CH(hdd_sta_ctx->conn_info. + operationChannel) +#endif + ) { + qdf_create_work(0, &hdd_ctx->sta_ap_intf_check_work, + cds_check_sta_ap_concurrent_ch_intf, + (void *)adapter); + qdf_sched_work(0, &hdd_ctx->sta_ap_intf_check_work); + cds_info("Checking for Concurrent Change interference"); + } +} +#endif /* FEATURE_WLAN_MCC_TO_SCC_SWITCH */ + +/** + * cds_is_mcc_in_24G() - Function to check for MCC in 2.4GHz + * + * This function is used to check for MCC operation in 2.4GHz band. + * STA, P2P and SAP adapters are only considered. + * + * Return: Non zero value if MCC is detected in 2.4GHz band + * + */ +uint8_t cds_is_mcc_in_24G(void) +{ + QDF_STATUS status; + hdd_adapter_t *hdd_adapter = NULL; + hdd_adapter_list_node_t *adapter_node = NULL, *next = NULL; + uint8_t ret = 0; + hdd_station_ctx_t *sta_ctx; + hdd_ap_ctx_t *ap_ctx; + uint8_t ch1 = 0, ch2 = 0; + uint8_t channel = 0; + hdd_hostapd_state_t *hostapd_state; + hdd_context_t *hdd_ctx; + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (!hdd_ctx) { + cds_err("HDD context is NULL"); + return 1; + } + + status = hdd_get_front_adapter(hdd_ctx, &adapter_node); + + /* loop through all adapters and check MCC for STA,P2P,SAP adapters */ + while (NULL != adapter_node && QDF_STATUS_SUCCESS == status) { + hdd_adapter = adapter_node->pAdapter; + + if (!((hdd_adapter->device_mode >= QDF_STA_MODE) + || (hdd_adapter->device_mode + <= QDF_P2P_GO_MODE))) { + /* skip for other adapters */ + status = hdd_get_next_adapter(hdd_ctx, + adapter_node, &next); + adapter_node = next; + continue; + } + if (QDF_STA_MODE == + hdd_adapter->device_mode || + QDF_P2P_CLIENT_MODE == + hdd_adapter->device_mode) { + sta_ctx = + WLAN_HDD_GET_STATION_CTX_PTR( + hdd_adapter); + if (eConnectionState_Associated == + sta_ctx->conn_info.connState) + channel = + sta_ctx->conn_info. + operationChannel; + } else if (QDF_P2P_GO_MODE == + hdd_adapter->device_mode || + QDF_SAP_MODE == + hdd_adapter->device_mode) { + ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(hdd_adapter); + hostapd_state = + WLAN_HDD_GET_HOSTAP_STATE_PTR( + hdd_adapter); + if (hostapd_state->bssState == BSS_START && + hostapd_state->qdf_status == + QDF_STATUS_SUCCESS) + channel = ap_ctx->operatingChannel; + } + + if ((ch1 == 0) || + ((ch2 != 0) && (ch2 != channel))) { + ch1 = channel; + } else if ((ch2 == 0) || + ((ch1 != 0) && (ch1 != channel))) { + ch2 = channel; + } + + if ((ch1 != 0 && ch2 != 0) && (ch1 != ch2) && + ((ch1 <= SIR_11B_CHANNEL_END) && + (ch2 <= SIR_11B_CHANNEL_END))) { + cds_err("MCC in 2.4Ghz on channels %d and %d", + ch1, ch2); + return 1; + } + status = hdd_get_next_adapter(hdd_ctx, + adapter_node, &next); + adapter_node = next; + } + return ret; +} + +/** + * cds_set_mas() - Function to set MAS value to UMAC + * @adapter: Pointer to HDD adapter + * @mas_value: 0-Disable, 1-Enable MAS + * + * This function passes down the value of MAS to UMAC + * + * Return: Configuration message posting status, SUCCESS or Fail + * + */ +int32_t cds_set_mas(hdd_adapter_t *adapter, uint8_t mas_value) +{ + hdd_context_t *hdd_ctx = NULL; + QDF_STATUS ret_status; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + if (!hdd_ctx) + return -EFAULT; + + if (mas_value) { + /* Miracast is ON. Disable MAS and configure P2P quota */ + if (hdd_ctx->config->enableMCCAdaptiveScheduler) { + if (cfg_set_int(hdd_ctx->hHal, + WNI_CFG_ENABLE_MCC_ADAPTIVE_SCHED, 0) + != eSIR_SUCCESS) { + cds_err("Could not pass on WNI_CFG_ENABLE_MCC_ADAPTIVE_SCHED to CCM"); + } + ret_status = sme_set_mas(false); + if (QDF_STATUS_SUCCESS != ret_status) { + cds_err("Failed to disable MAS"); + return -EBUSY; + } + } + + /* Config p2p quota */ + if (adapter->device_mode == QDF_STA_MODE) + cds_set_mcc_p2p_quota(adapter, + 100 - HDD_DEFAULT_MCC_P2P_QUOTA); + else if (adapter->device_mode == QDF_P2P_GO_MODE) + cds_go_set_mcc_p2p_quota(adapter, + HDD_DEFAULT_MCC_P2P_QUOTA); + else + cds_set_mcc_p2p_quota(adapter, + HDD_DEFAULT_MCC_P2P_QUOTA); + } else { + /* Reset p2p quota */ + if (adapter->device_mode == QDF_P2P_GO_MODE) + cds_go_set_mcc_p2p_quota(adapter, + HDD_RESET_MCC_P2P_QUOTA); + else + cds_set_mcc_p2p_quota(adapter, + HDD_RESET_MCC_P2P_QUOTA); + + /* Miracast is OFF. Enable MAS and reset P2P quota */ + if (hdd_ctx->config->enableMCCAdaptiveScheduler) { + if (cfg_set_int(hdd_ctx->hHal, + WNI_CFG_ENABLE_MCC_ADAPTIVE_SCHED, 1) + != eSIR_SUCCESS) { + cds_err("Could not pass on WNI_CFG_ENABLE_MCC_ADAPTIVE_SCHED to CCM"); + } + + /* Enable MAS */ + ret_status = sme_set_mas(true); + if (QDF_STATUS_SUCCESS != ret_status) { + cds_err("Unable to enable MAS"); + return -EBUSY; + } + } + } + + return 0; +} + +/** + * cds_set_mcc_p2p_quota() - Function to set quota for P2P + * @hostapd_adapter: Pointer to HDD adapter + * @set_value: Qouta value for the interface + * + * This function is used to set the quota for P2P cases + * + * Return: Configuration message posting status, SUCCESS or Fail + * + */ +int32_t cds_set_mcc_p2p_quota(hdd_adapter_t *hostapd_adapater, + uint32_t set_value) +{ + uint8_t first_adapter_operating_channel = 0; + uint8_t second_adapter_operating_channel = 0; + int32_t ret = 0; /* success */ + + uint32_t concurrent_state = cds_get_concurrency_mode(); + + /* + * Check if concurrency mode is active. + * Need to modify this code to support MCC modes other than STA/P2P + */ + if ((concurrent_state == (QDF_STA_MASK | QDF_P2P_CLIENT_MASK)) || + (concurrent_state == (QDF_STA_MASK | QDF_P2P_GO_MASK))) { + cds_info("STA & P2P are both enabled"); + /* + * The channel numbers for both adapters and the time + * quota for the 1st adapter, i.e., one specified in cmd + * are formatted as a bit vector then passed on to WMA + * +***********************************************************+ + * |bit 31-24 | bit 23-16 | bits 15-8 | bits 7-0 | + * | Unused | Quota for | chan. # for | chan. # for | + * | | 1st chan. | 1st chan. | 2nd chan. | + * +***********************************************************+ + */ + /* Get the operating channel of the specified vdev */ + first_adapter_operating_channel = + hdd_get_operating_channel + ( + hostapd_adapater->pHddCtx, + hostapd_adapater->device_mode + ); + cds_info("1st channel No.:%d and quota:%dms", + first_adapter_operating_channel, set_value); + /* Move the time quota for first channel to bits 15-8 */ + set_value = set_value << 8; + /* + * Store the channel number of 1st channel at bits 7-0 + * of the bit vector + */ + set_value = set_value | first_adapter_operating_channel; + /* Find out the 2nd MCC adapter and its operating channel */ + second_adapter_operating_channel = + cds_get_mcc_operating_channel( + hostapd_adapater->sessionId); + + cds_info("2nd vdev channel No. is:%d", + second_adapter_operating_channel); + + if (second_adapter_operating_channel == 0 || + first_adapter_operating_channel == 0) { + cds_err("Invalid channel"); + return -EINVAL; + } + /* + * Now move the time quota and channel number of the + * 1st adapter to bits 23-16 and bits 15-8 of the bit + * vector, respectively. + */ + set_value = set_value << 8; + /* + * Store the channel number for 2nd MCC vdev at bits + * 7-0 of set_value + */ + set_value = set_value | second_adapter_operating_channel; + ret = wma_cli_set_command(hostapd_adapater->sessionId, + WMA_VDEV_MCC_SET_TIME_QUOTA, + set_value, VDEV_CMD); + } else { + cds_info("MCC is not active. Exit w/o setting latency"); + } + return ret; +} + +/** + * cds_change_mcc_go_beacon_interval() - Change MCC beacon interval + * @pHostapdAdapter: HDD adapter + * + * Updates the beacon parameters of the GO in MCC scenario + * + * Return: Success or Failure depending on the overall function behavior + */ +QDF_STATUS cds_change_mcc_go_beacon_interval(hdd_adapter_t *pHostapdAdapter) +{ + QDF_STATUS qdf_ret_status = QDF_STATUS_E_FAILURE; + void *hHal; + + cds_info("UPDATE Beacon Params"); + + if (QDF_SAP_MODE == pHostapdAdapter->device_mode) { + hHal = WLAN_HDD_GET_HAL_CTX(pHostapdAdapter); + if (NULL == hHal) { + cds_err("Hal ctx is null"); + return QDF_STATUS_E_FAULT; + } + qdf_ret_status = + sme_change_mcc_beacon_interval(hHal, + pHostapdAdapter-> + sessionId); + if (qdf_ret_status == QDF_STATUS_E_FAILURE) { + cds_err("Failed to update Beacon Params"); + return QDF_STATUS_E_FAILURE; + } + } + return QDF_STATUS_SUCCESS; +} + +/** + * cds_go_set_mcc_p2p_quota() - Function to set quota for P2P GO + * @hostapd_adapter: Pointer to HDD adapter + * @set_value: Qouta value for the interface + * + * This function is used to set the quota for P2P GO cases + * + * Return: Configuration message posting status, SUCCESS or Fail + * + */ +int32_t cds_go_set_mcc_p2p_quota(hdd_adapter_t *hostapd_adapter, + uint32_t set_value) +{ + uint8_t first_adapter_operating_channel = 0; + uint8_t second_adapter_operating_channel = 0; + uint32_t concurrent_state = 0; + int32_t ret = 0; /* success */ + + /* + * Check if concurrency mode is active. + * Need to modify this code to support MCC modes other than + * STA/P2P GO + */ + + concurrent_state = cds_get_concurrency_mode(); + if (concurrent_state == (QDF_STA_MASK | QDF_P2P_GO_MASK)) { + cds_info("STA & P2P are both enabled"); + + /* + * The channel numbers for both adapters and the time + * quota for the 1st adapter, i.e., one specified in cmd + * are formatted as a bit vector then passed on to WMA + * +************************************************+ + * |bit 31-24 |bit 23-16 | bits 15-8 |bits 7-0 | + * | Unused | Quota for| chan. # for |chan. # for| + * | | 1st chan.| 1st chan. |2nd chan. | + * +************************************************+ + */ + + /* Get the operating channel of the specified vdev */ + first_adapter_operating_channel = + hdd_get_operating_channel(hostapd_adapter->pHddCtx, + hostapd_adapter->device_mode); + + cds_info("1st channel No.:%d and quota:%dms", + first_adapter_operating_channel, set_value); + + /* Move the time quota for first adapter to bits 15-8 */ + set_value = set_value << 8; + /* + * Store the operating channel number of 1st adapter at + * the lower 8-bits of bit vector. + */ + set_value = set_value | first_adapter_operating_channel; + + /* Find out the 2nd MCC adapter and its operating channel */ + second_adapter_operating_channel = + cds_get_mcc_operating_channel( + hostapd_adapter->sessionId); + + cds_info("2nd vdev channel No. is:%d", + second_adapter_operating_channel); + + if (second_adapter_operating_channel == 0 || + first_adapter_operating_channel == 0) { + cds_err("Invalid channel"); + return -EINVAL; + } + + /* + * Move the time quota and operating channel number + * for the first adapter to bits 23-16 & bits 15-8 + * of set_value vector, respectively. + */ + set_value = set_value << 8; + /* + * Store the channel number for 2nd MCC vdev at bits + * 7-0 of set_value vector as per the bit format above. + */ + set_value = set_value | + second_adapter_operating_channel; + ret = wma_cli_set_command(hostapd_adapter->sessionId, + WMA_VDEV_MCC_SET_TIME_QUOTA, + set_value, VDEV_CMD); + } else { + cds_info("MCC is not active. Exit w/o setting latency"); + } + return ret; +} + +/** + * cds_set_mcc_latency() - Set MCC latency + * @adapter: Pointer to HDD adapter + * @set_value: Latency value + * + * Sets the MCC latency value during STA-P2P concurrency + * + * Return: None + */ +void cds_set_mcc_latency(hdd_adapter_t *adapter, int set_value) +{ + uint32_t concurrent_state = 0; + uint8_t first_adapter_operating_channel = 0; + int ret = 0; /* success */ + + cds_info("iwpriv cmd to set MCC latency with val %dms", + set_value); + /** + * Check if concurrency mode is active. + * Need to modify this code to support MCC modes other than STA/P2P + */ + concurrent_state = cds_get_concurrency_mode(); + if ((concurrent_state == (QDF_STA_MASK | QDF_P2P_CLIENT_MASK)) || + (concurrent_state == (QDF_STA_MASK | QDF_P2P_GO_MASK))) { + cds_info("STA & P2P are both enabled"); + /* + * The channel number and latency are formatted in + * a bit vector then passed on to WMA layer. + * +**********************************************+ + * |bits 31-16 | bits 15-8 | bits 7-0 | + * | Unused | latency - Chan. 1 | channel no. | + * +**********************************************+ + */ + /* Get the operating channel of the designated vdev */ + first_adapter_operating_channel = + hdd_get_operating_channel + (adapter->pHddCtx, adapter->device_mode); + /* Move the time latency for the adapter to bits 15-8 */ + set_value = set_value << 8; + /* Store the channel number at bits 7-0 of the bit vector */ + set_value = + set_value | first_adapter_operating_channel; + /* Send command to WMA */ + ret = wma_cli_set_command(adapter->sessionId, + WMA_VDEV_MCC_SET_TIME_LATENCY, + set_value, VDEV_CMD); + } else { + cds_info("%s: MCC is not active. Exit w/o setting latency", + __func__); + } +} + +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH +/** + * cds_change_sap_channel_with_csa() - Move SAP channel using (E)CSA + * @adapter: AP adapter + * @hdd_ap_ctx: AP context + * + * Invoke the callback function to change SAP channel using (E)CSA + * + * Return: None + */ +void cds_change_sap_channel_with_csa(hdd_adapter_t *adapter, + hdd_ap_ctx_t *hdd_ap_ctx) +{ + p_cds_contextType cds_ctx; + + cds_ctx = cds_get_global_context(); + if (!cds_ctx) { + cds_err("Invalid CDS context"); + return; + } + + if (cds_ctx->sap_restart_chan_switch_cb) { + cds_info("SAP change change without restart"); + cds_ctx->sap_restart_chan_switch_cb(adapter, + hdd_ap_ctx->sapConfig.channel, + hdd_ap_ctx->sapConfig.ch_params.ch_width); + } +} +#endif + +#if defined(FEATURE_WLAN_MCC_TO_SCC_SWITCH) || \ + defined(FEATURE_WLAN_STA_AP_MODE_DFS_DISABLE) +/** + * cds_restart_sap() - to restart SAP in driver internally + * @ap_adapter: Pointer to SAP hdd_adapter_t structure + * + * Return: None + */ +void cds_restart_sap(hdd_adapter_t *ap_adapter) +{ + hdd_ap_ctx_t *hdd_ap_ctx; + hdd_hostapd_state_t *hostapd_state; + QDF_STATUS qdf_status; + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(ap_adapter); + tsap_Config_t *sap_config; + void *sap_ctx; + + hdd_ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(ap_adapter); + sap_config = &hdd_ap_ctx->sapConfig; + sap_ctx = hdd_ap_ctx->sapContext; + + mutex_lock(&hdd_ctx->sap_lock); + if (test_bit(SOFTAP_BSS_STARTED, &ap_adapter->event_flags)) { + wlan_hdd_del_station(ap_adapter); + hdd_cleanup_actionframe(hdd_ctx, ap_adapter); + hostapd_state = WLAN_HDD_GET_HOSTAP_STATE_PTR(ap_adapter); + qdf_event_reset(&hostapd_state->qdf_stop_bss_event); + if (QDF_STATUS_SUCCESS == wlansap_stop_bss(sap_ctx)) { + qdf_status = + qdf_wait_single_event(&hostapd_state-> + qdf_stop_bss_event, + SME_CMD_TIMEOUT_VALUE); + + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + cds_err("SAP Stop Failed"); + goto end; + } + } + clear_bit(SOFTAP_BSS_STARTED, &ap_adapter->event_flags); + cds_decr_session_set_pcl( + ap_adapter->device_mode, ap_adapter->sessionId); + cds_err("SAP Stop Success"); + + if (0 != wlan_hdd_cfg80211_update_apies(ap_adapter)) { + cds_err("SAP Not able to set AP IEs"); + wlansap_reset_sap_config_add_ie(sap_config, + eUPDATE_IE_ALL); + goto end; + } + + qdf_event_reset(&hostapd_state->qdf_event); + if (wlansap_start_bss(sap_ctx, hdd_hostapd_sap_event_cb, + sap_config, + ap_adapter->dev) != QDF_STATUS_SUCCESS) { + cds_err("SAP Start Bss fail"); + wlansap_reset_sap_config_add_ie(sap_config, + eUPDATE_IE_ALL); + goto end; + } + + cds_info("Waiting for SAP to start"); + qdf_status = + qdf_wait_single_event(&hostapd_state->qdf_event, + SME_CMD_TIMEOUT_VALUE); + wlansap_reset_sap_config_add_ie(sap_config, + eUPDATE_IE_ALL); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + cds_err("SAP Start failed"); + goto end; + } + cds_err("SAP Start Success"); + set_bit(SOFTAP_BSS_STARTED, &ap_adapter->event_flags); + if (hostapd_state->bssState == BSS_START) + cds_incr_active_session(ap_adapter->device_mode, + ap_adapter->sessionId); + hostapd_state->bCommit = true; + } +end: + mutex_unlock(&hdd_ctx->sap_lock); + return; +} +#endif + +#ifdef FEATURE_WLAN_STA_AP_MODE_DFS_DISABLE +/** + * cds_check_and_restart_sap_with_non_dfs_acs() - Restart SAP with non dfs acs + * + * Restarts SAP in non-DFS ACS mode when STA-AP mode DFS is not supported + * + * Return: None + */ +void cds_check_and_restart_sap_with_non_dfs_acs(void) +{ + hdd_adapter_t *ap_adapter; + hdd_context_t *hdd_ctx; + cds_context_type *cds_ctx; + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (!hdd_ctx) { + cds_err("HDD context is NULL"); + return; + } + + cds_ctx = cds_get_context(QDF_MODULE_ID_QDF); + if (!cds_ctx) { + cds_err("Invalid CDS Context"); + return; + } + + if (cds_get_concurrency_mode() != (QDF_STA_MASK | QDF_SAP_MASK)) { + cds_info("Concurrency mode is not SAP"); + return; + } + + ap_adapter = hdd_get_adapter(hdd_ctx, QDF_SAP_MODE); + if (ap_adapter != NULL && + test_bit(SOFTAP_BSS_STARTED, + &ap_adapter->event_flags) + && CDS_IS_DFS_CH(ap_adapter->sessionCtx.ap. + operatingChannel)) { + + cds_warn("STA-AP Mode DFS not supported. Restart SAP with Non DFS ACS"); + ap_adapter->sessionCtx.ap.sapConfig.channel = + AUTO_CHANNEL_SELECT; + ap_adapter->sessionCtx.ap.sapConfig. + acs_cfg.acs_mode = true; + + cds_restart_sap(ap_adapter); + } +} +#endif + +struct cds_conc_connection_info *cds_get_conn_info(uint32_t *len) +{ + struct cds_conc_connection_info *conn_ptr = &conc_connection_list[0]; + *len = MAX_NUMBER_OF_CONC_CONNECTIONS; + + return conn_ptr; +} + +#ifdef MPC_UT_FRAMEWORK +QDF_STATUS cds_update_connection_info_utfw( + uint32_t vdev_id, uint32_t tx_streams, uint32_t rx_streams, + uint32_t chain_mask, uint32_t type, uint32_t sub_type, + uint32_t channelid, uint32_t mac_id) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + uint32_t conn_index = 0, found = 0; + cds_context_type *cds_ctx; + + cds_ctx = cds_get_context(QDF_MODULE_ID_QDF); + if (!cds_ctx) { + cds_err("Invalid CDS Context"); + return status; + } + + qdf_mutex_acquire(&cds_ctx->qdf_conc_list_lock); + while (CONC_CONNECTION_LIST_VALID_INDEX(conn_index)) { + if (vdev_id == conc_connection_list[conn_index].vdev_id) { + /* debug msg */ + found = 1; + break; + } + conn_index++; + } + qdf_mutex_release(&cds_ctx->qdf_conc_list_lock); + if (!found) { + /* err msg */ + cds_err("can't find vdev_id %d in conc_connection_list", + vdev_id); + return status; + } + cds_info("--> updating entry at index[%d]", conn_index); + + cds_update_conc_list(conn_index, + cds_get_mode(type, sub_type), + channelid, HW_MODE_20_MHZ, + mac_id, chain_mask, 0, vdev_id, true); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS cds_incr_connection_count_utfw( + uint32_t vdev_id, uint32_t tx_streams, uint32_t rx_streams, + uint32_t chain_mask, uint32_t type, uint32_t sub_type, + uint32_t channelid, uint32_t mac_id) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + uint32_t conn_index = 0; + hdd_context_t *hdd_ctx; + cds_context_type *cds_ctx; + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (!hdd_ctx) { + cds_err("HDD context is NULL"); + return status; + } + + cds_ctx = cds_get_context(QDF_MODULE_ID_QDF); + if (!cds_ctx) { + cds_err("Invalid CDS Context"); + return status; + } + + conn_index = cds_get_connection_count(); + if (MAX_NUMBER_OF_CONC_CONNECTIONS <= conn_index) { + /* err msg */ + cds_err("exceeded max connection limit %d", + MAX_NUMBER_OF_CONC_CONNECTIONS); + return status; + } + cds_info("--> filling entry at index[%d]", conn_index); + + cds_update_conc_list(conn_index, + cds_get_mode(type, sub_type), + channelid, HW_MODE_20_MHZ, + mac_id, chain_mask, 0, vdev_id, true); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS cds_decr_connection_count_utfw(uint32_t del_all, + uint32_t vdev_id) +{ + QDF_STATUS status; + cds_context_type *cds_ctx; + struct cds_sme_cbacks sme_cbacks; + + cds_ctx = cds_get_context(QDF_MODULE_ID_QDF); + if (!cds_ctx) { + cds_err("Invalid CDS Context"); + return QDF_STATUS_E_FAILURE; + } + + sme_cbacks.sme_get_valid_channels = sme_get_cfg_valid_channels; + sme_cbacks.sme_get_nss_for_vdev = sme_get_vdev_type_nss; + if (del_all) { + status = cds_init_policy_mgr(&sme_cbacks); + if (!QDF_IS_STATUS_SUCCESS(status)) { + cds_err("Policy manager initialization failed"); + return QDF_STATUS_E_FAILURE; + } + } else { + cds_decr_connection_count(vdev_id); + } + + return QDF_STATUS_SUCCESS; +} + +enum cds_pcl_type get_pcl_from_first_conn_table(enum cds_con_mode type, + enum cds_conc_priority_mode sys_pref) +{ + if ((sys_pref >= CDS_MAX_CONC_PRIORITY_MODE) || + (type >= CDS_MAX_NUM_OF_MODE)) + return CDS_MAX_PCL_TYPE; + return first_connection_pcl_table[type][sys_pref]; +} + +enum cds_pcl_type get_pcl_from_second_conn_table( + enum cds_one_connection_mode idx, enum cds_con_mode type, + enum cds_conc_priority_mode sys_pref, uint8_t dbs_capable) +{ + if ((idx >= CDS_MAX_ONE_CONNECTION_MODE) || + (sys_pref >= CDS_MAX_CONC_PRIORITY_MODE) || + (type >= CDS_MAX_NUM_OF_MODE)) + return CDS_MAX_PCL_TYPE; + if (dbs_capable) + return second_connection_pcl_dbs_table[idx][type][sys_pref]; + else + return second_connection_pcl_nodbs_table[idx][type][sys_pref]; +} + +enum cds_pcl_type get_pcl_from_third_conn_table( + enum cds_two_connection_mode idx, enum cds_con_mode type, + enum cds_conc_priority_mode sys_pref, uint8_t dbs_capable) +{ + if ((idx >= CDS_MAX_TWO_CONNECTION_MODE) || + (sys_pref >= CDS_MAX_CONC_PRIORITY_MODE) || + (type >= CDS_MAX_NUM_OF_MODE)) + return CDS_MAX_PCL_TYPE; + if (dbs_capable) + return third_connection_pcl_dbs_table[idx][type][sys_pref]; + else + return third_connection_pcl_nodbs_table[idx][type][sys_pref]; +} +#endif + +/** + * cds_convert_device_mode_to_qdf_type() - provides the + * type translation from HDD to policy manager type + * @device_mode: Generic connection mode type + * + * + * This function provides the type translation + * + * Return: cds_con_mode enum + */ +enum cds_con_mode cds_convert_device_mode_to_qdf_type( + enum tQDF_ADAPTER_MODE device_mode) +{ + enum cds_con_mode mode = CDS_MAX_NUM_OF_MODE; + switch (device_mode) { + case QDF_STA_MODE: + mode = CDS_STA_MODE; + break; + case QDF_P2P_CLIENT_MODE: + mode = CDS_P2P_CLIENT_MODE; + break; + case QDF_P2P_GO_MODE: + mode = CDS_P2P_GO_MODE; + break; + case QDF_SAP_MODE: + mode = CDS_SAP_MODE; + break; + case QDF_IBSS_MODE: + mode = CDS_IBSS_MODE; + break; + default: + cds_err("Unsupported mode (%d)", + device_mode); + } + return mode; +} + +/** + * cds_get_conparam() - Get the connection mode parameters + * + * Return the connection mode parameter set by insmod or set during statically + * linked driver + * + * Return: enum tQDF_GLOBAL_CON_MODE + */ +enum tQDF_GLOBAL_CON_MODE cds_get_conparam(void) +{ + enum tQDF_GLOBAL_CON_MODE con_mode; + con_mode = hdd_get_conparam(); + return con_mode; +} + +/** + * cds_concurrent_open_sessions_running() - Checks for concurrent open session + * + * Checks if more than one open session is running for all the allowed modes + * in the driver + * + * Return: True if more than one open session exists, False otherwise + */ +bool cds_concurrent_open_sessions_running(void) +{ + uint8_t i = 0; + uint8_t j = 0; + hdd_context_t *pHddCtx; + + pHddCtx = cds_get_context(QDF_MODULE_ID_HDD); + if (NULL != pHddCtx) { + for (i = 0; i < QDF_MAX_NO_OF_MODE; i++) + j += pHddCtx->no_of_open_sessions[i]; + } + + return j > 1; +} + +/** + * cds_concurrent_beaconing_sessions_running() - Checks for concurrent beaconing + * entities + * + * Checks if multiple beaconing sessions are running i.e., if SAP or GO or IBSS + * are beaconing together + * + * Return: True if multiple entities are beaconing together, False otherwise + */ +bool cds_concurrent_beaconing_sessions_running(void) +{ + uint8_t i = 0; + hdd_context_t *pHddCtx; + + pHddCtx = cds_get_context(QDF_MODULE_ID_HDD); + if (NULL != pHddCtx) { + i = pHddCtx->no_of_open_sessions[QDF_SAP_MODE] + + pHddCtx->no_of_open_sessions[QDF_P2P_GO_MODE] + + pHddCtx->no_of_open_sessions[QDF_IBSS_MODE]; + } + return i > 1; +} + + +/** + * cds_max_concurrent_connections_reached() - Check if max conccurrency is + * reached + * + * Checks for presence of concurrency where more than one connection exists + * + * Return: True if the max concurrency is reached, False otherwise + * + * Example: + * STA + STA (wlan0 and wlan1 are connected) - returns true + * STA + STA (wlan0 connected and wlan1 disconnected) - returns false + * DUT with P2P-GO + P2P-CLIENT connection) - returns true + * + */ +bool cds_max_concurrent_connections_reached(void) +{ + uint8_t i = 0, j = 0; + hdd_context_t *pHddCtx; + + pHddCtx = cds_get_context(QDF_MODULE_ID_HDD); + if (NULL != pHddCtx) { + for (i = 0; i < QDF_MAX_NO_OF_MODE; i++) + j += pHddCtx->no_of_active_sessions[i]; + return j > + (pHddCtx->config-> + gMaxConcurrentActiveSessions - 1); + } + + return false; +} + +/** + * cds_clear_concurrent_session_count() - Clear active session count + * + * Clears the active session count for all modes + * + * Return: None + */ +void cds_clear_concurrent_session_count(void) +{ + uint8_t i = 0; + hdd_context_t *pHddCtx; + + pHddCtx = cds_get_context(QDF_MODULE_ID_HDD); + if (NULL != pHddCtx) { + for (i = 0; i < QDF_MAX_NO_OF_MODE; i++) + pHddCtx->no_of_active_sessions[i] = 0; + } +} + +/** + * cds_is_multiple_active_sta_sessions() - Check for multiple STA connections + * + * Checks if multiple active STA connection are in the driver + * + * Return: True if multiple STA sessions are present, False otherwise + * + */ +bool cds_is_multiple_active_sta_sessions(void) +{ + hdd_context_t *pHddCtx; + uint8_t j = 0; + + pHddCtx = cds_get_context(QDF_MODULE_ID_HDD); + if (NULL != pHddCtx) + j = pHddCtx->no_of_active_sessions[QDF_STA_MODE]; + + return j > 1; +} + +/** + * cds_is_sta_active_connection_exists() - Check if a STA connection is active + * + * Checks if there is atleast one active STA connection in the driver + * + * Return: True if an active STA session is present, False otherwise + */ +bool cds_is_sta_active_connection_exists(void) +{ + hdd_context_t *pHddCtx; + uint8_t j = 0; + + pHddCtx = cds_get_context(QDF_MODULE_ID_HDD); + if (NULL != pHddCtx) + j = pHddCtx->no_of_active_sessions[QDF_STA_MODE]; + + return j ? true : false; +} + +/** + * qdf_wait_for_connection_update() - Wait for hw mode command to get processed + * + * Waits for CONNECTION_UPDATE_TIMEOUT duration until the set hw mode + * response sets the event connection_update_done_evt + * + * Return: QDF_STATUS + */ +QDF_STATUS qdf_wait_for_connection_update(void) +{ + QDF_STATUS status; + p_cds_contextType cds_context; + + cds_context = cds_get_global_context(); + if (!cds_context) { + cds_err("Invalid CDS context"); + return QDF_STATUS_E_FAILURE; + } + + status = qdf_wait_single_event( + &cds_context->connection_update_done_evt, + CONNECTION_UPDATE_TIMEOUT); + + if (!QDF_IS_STATUS_SUCCESS(status)) { + cds_err("wait for event failed"); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * qdf_reset_connection_update() - Reset connection update event + * + * Resets the concurrent connection update event + * + * Return: QDF_STATUS + */ +QDF_STATUS qdf_reset_connection_update(void) +{ + QDF_STATUS status; + p_cds_contextType cds_context; + + cds_context = cds_get_global_context(); + if (!cds_context) { + cds_err("Invalid CDS context"); + return QDF_STATUS_E_FAILURE; + } + + status = qdf_event_reset(&cds_context->connection_update_done_evt); + + if (!QDF_IS_STATUS_SUCCESS(status)) { + cds_err("clear event failed"); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * qdf_set_connection_update() - Set connection update event + * + * Sets the concurrent connection update event + * + * Return: QDF_STATUS + */ +QDF_STATUS qdf_set_connection_update(void) +{ + QDF_STATUS status; + p_cds_contextType cds_context; + + cds_context = cds_get_global_context(); + if (!cds_context) { + cds_err("Invalid CDS context"); + return QDF_STATUS_E_FAILURE; + } + + status = qdf_event_set(&cds_context->connection_update_done_evt); + + if (!QDF_IS_STATUS_SUCCESS(status)) { + cds_err("set event failed"); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * qdf_init_connection_update() - Initialize connection update event + * + * Initializes the concurrent connection update event + * + * Return: QDF_STATUS + */ +QDF_STATUS qdf_init_connection_update(void) +{ + QDF_STATUS qdf_status; + p_cds_contextType cds_context; + + cds_context = cds_get_global_context(); + if (!cds_context) { + cds_err("Invalid CDS context"); + return QDF_STATUS_E_FAILURE; + } + + qdf_status = qdf_event_create(&cds_context->connection_update_done_evt); + + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + cds_err("init event failed"); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * cds_get_current_pref_hw_mode() - Get the current preferred hw mode + * + * Get the preferred hw mode based on the current connection combinations + * + * Return: No change (CDS_NOP), MCC (CDS_SINGLE_MAC_UPGRADE), + * DBS (CDS_DBS_DOWNGRADE) + */ +static enum cds_conc_next_action cds_get_current_pref_hw_mode(void) +{ + uint32_t num_connections; + uint8_t band1, band2, band3; + struct sir_hw_mode_params hw_mode; + QDF_STATUS status; + hdd_context_t *hdd_ctx; + enum cds_conc_next_action next_action; + cds_context_type *cds_ctx; + + cds_ctx = cds_get_context(QDF_MODULE_ID_QDF); + if (!cds_ctx) { + cds_err("Invalid CDS Context"); + return CDS_NOP; + } + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (!hdd_ctx) { + cds_err("HDD context is NULL"); + return CDS_NOP; + } + + status = wma_get_current_hw_mode(&hw_mode); + if (!QDF_IS_STATUS_SUCCESS(status)) { + cds_err("wma_get_current_hw_mode failed"); + return CDS_NOP; + } + + num_connections = cds_get_connection_count(); + + qdf_mutex_acquire(&cds_ctx->qdf_conc_list_lock); + cds_debug("chan[0]:%d chan[1]:%d chan[2]:%d num_connections:%d dbs:%d", + conc_connection_list[0].chan, conc_connection_list[1].chan, + conc_connection_list[2].chan, num_connections, hw_mode.dbs_cap); + + /* If the band of operation of both the MACs is the same, + * single MAC is preferred, otherwise DBS is preferred. + */ + switch (num_connections) { + case 1: + /* The driver would already be in the required hw mode */ + next_action = CDS_NOP; + break; + case 2: + band1 = cds_chan_to_band(conc_connection_list[0].chan); + band2 = cds_chan_to_band(conc_connection_list[1].chan); + if ((band1 == band2) && (hw_mode.dbs_cap)) + next_action = CDS_SINGLE_MAC_UPGRADE; + else if ((band1 != band2) && (!hw_mode.dbs_cap)) + next_action = CDS_DBS_DOWNGRADE; + else + next_action = CDS_NOP; + + break; + + case 3: + band1 = cds_chan_to_band(conc_connection_list[0].chan); + band2 = cds_chan_to_band(conc_connection_list[1].chan); + band3 = cds_chan_to_band(conc_connection_list[2].chan); + if (((band1 == band2) && (band2 == band3)) && + (hw_mode.dbs_cap)) { + next_action = CDS_SINGLE_MAC_UPGRADE; + } else if (((band1 != band2) || (band2 != band3) || + (band1 != band3)) && + (!hw_mode.dbs_cap)) { + next_action = CDS_DBS_DOWNGRADE; + } else { + next_action = CDS_NOP; + } + break; + default: + cds_err("unexpected num_connections value %d", + num_connections); + next_action = CDS_NOP; + break; + } + + qdf_mutex_release(&cds_ctx->qdf_conc_list_lock); + return next_action; + +} + +/** + * cds_restart_opportunistic_timer() - Restarts opportunistic timer + * @check_state: check timer state if this flag is set, else restart + * irrespective of state + * + * Restarts opportunistic timer for DBS_OPPORTUNISTIC_TIME seconds. + * Check if current state is RUNNING if check_state is set, else + * restart the timer irrespective of state. + * + * Return: QDF_STATUS + */ +QDF_STATUS cds_restart_opportunistic_timer(bool check_state) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + p_cds_contextType cds_ctx; + + cds_ctx = cds_get_global_context(); + if (!cds_ctx) { + cds_err("Invalid CDS context"); + return status; + } + + if (check_state && + QDF_TIMER_STATE_RUNNING != + cds_ctx->dbs_opportunistic_timer.state) + return status; + + qdf_mc_timer_stop(&cds_ctx->dbs_opportunistic_timer); + + status = qdf_mc_timer_start( + &cds_ctx->dbs_opportunistic_timer, + DBS_OPPORTUNISTIC_TIME * 1000); + + if (!QDF_IS_STATUS_SUCCESS(status)) { + cds_err("failed to start opportunistic timer"); + return status; + } + + return status; +} + +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH +/** + * cds_register_sap_restart_channel_switch_cb() - Register callback for SAP + * channel switch without restart + * @sap_restart_chan_switch_cb: Callback to perform channel switch + * + * Registers callback to perform channel switch without having to actually + * restart the beaconing entity + * + * Return: QDF_STATUS + */ +QDF_STATUS cds_register_sap_restart_channel_switch_cb( + void (*sap_restart_chan_switch_cb)(void *, uint32_t, uint32_t)) +{ + p_cds_contextType cds_ctx; + + cds_ctx = cds_get_global_context(); + if (!cds_ctx) { + cds_err("Invalid CDS context"); + return QDF_STATUS_E_FAILURE; + } + + cds_ctx->sap_restart_chan_switch_cb = sap_restart_chan_switch_cb; + return QDF_STATUS_SUCCESS; +} + +/** + * cds_deregister_sap_restart_channel_switch_cb() - De-Register callback for SAP + * channel switch without restart + * + * De Registers callback to perform channel switch + * + * Return: QDF_STATUS Enumeration + */ +QDF_STATUS cds_deregister_sap_restart_channel_switch_cb(void) +{ + p_cds_contextType cds_ctx; + + cds_ctx = cds_get_global_context(); + if (!cds_ctx) { + cds_err("Invalid CDS context"); + return QDF_STATUS_E_FAILURE; + } + + cds_ctx->sap_restart_chan_switch_cb = NULL; + return QDF_STATUS_SUCCESS; +} + +#endif + + + +/** + * cds_get_nondfs_preferred_channel() - to get non-dfs preferred channel + * for given mode + * @mode: mode for which preferred non-dfs channel is requested + * @for_existing_conn: flag to indicate if preferred channel is requested + * for existing connection + * + * this routine will return non-dfs channel + * 1) for getting non-dfs preferred channel, first we check if there are any + * other connection exist whose channel is non-dfs. if yes then return that + * channel so that we can accommodate upto 3 mode concurrency. + * 2) if there no any other connection present then query concurrency module + * to give preferred channel list. once we get preferred channel list, loop + * through list to find first non-dfs channel from ascending order. + * + * Return: uint8_t non-dfs channel + */ +uint8_t +cds_get_nondfs_preferred_channel(enum cds_con_mode mode, + bool for_existing_conn) +{ + uint8_t pcl_channels[QDF_MAX_NUM_CHAN]; + uint8_t pcl_weight[QDF_MAX_NUM_CHAN]; + + /* + * in worst case if we can't find any channel at all + * then return 2.4G channel, so atleast we won't fall + * under 5G MCC scenario + */ + uint8_t channel = CDS_24_GHZ_CHANNEL_6; + uint32_t i, pcl_len; + + if (true == for_existing_conn) { + /* + * First try to see if there is any non-dfs channel already + * present in current connection table. If yes then return + * that channel + */ + if (true == cds_is_any_nondfs_chnl_present(&channel)) + return channel; + + if (QDF_STATUS_SUCCESS != cds_get_pcl_for_existing_conn(mode, + &pcl_channels[0], &pcl_len, + pcl_weight, QDF_ARRAY_SIZE(pcl_weight))) + return channel; + } else { + if (QDF_STATUS_SUCCESS != cds_get_pcl(mode, + &pcl_channels[0], &pcl_len, + pcl_weight, QDF_ARRAY_SIZE(pcl_weight))) + return channel; + } + + for (i = 0; i < pcl_len; i++) { + if (CDS_IS_DFS_CH(pcl_channels[i])) { + continue; + } else { + channel = pcl_channels[i]; + break; + } + } + return channel; +} + + +/** + * cds_is_any_nondfs_chnl_present() - Find any non-dfs channel from conc table + * @channel: pointer to channel which needs to be filled + * + * In-case if any connection is already present whose channel is none dfs then + * return that channel + * + * Return: true up-on finding non-dfs channel else false + */ +bool cds_is_any_nondfs_chnl_present(uint8_t *channel) +{ + cds_context_type *cds_ctx; + bool status = false; + uint32_t conn_index = 0; + cds_ctx = cds_get_context(QDF_MODULE_ID_QDF); + + if (!cds_ctx) { + cds_err("Invalid CDS Context"); + return false; + } + qdf_mutex_acquire(&cds_ctx->qdf_conc_list_lock); + for (conn_index = 0; conn_index < MAX_NUMBER_OF_CONC_CONNECTIONS; + conn_index++) { + if (conc_connection_list[conn_index].in_use && + !CDS_IS_DFS_CH(conc_connection_list[conn_index].chan)) { + *channel = conc_connection_list[conn_index].chan; + status = true; + } + } + qdf_mutex_release(&cds_ctx->qdf_conc_list_lock); + return status; +} + +/** + * cds_is_any_dfs_beaconing_session_present() - to find if any DFS session + * @channel: pointer to channel number that needs to filled + * + * If any beaconing session such as SAP or GO present and it is on DFS channel + * then this function will return true + * + * Return: true if session is on DFS or false if session is on non-dfs channel + */ +bool cds_is_any_dfs_beaconing_session_present(uint8_t *channel) +{ + cds_context_type *cds_ctx; + struct cds_conc_connection_info *conn_info; + bool status = false; + uint32_t conn_index = 0; + cds_ctx = cds_get_context(QDF_MODULE_ID_QDF); + + if (!cds_ctx) { + cds_err("Invalid CDS Context"); + return false; + } + qdf_mutex_acquire(&cds_ctx->qdf_conc_list_lock); + for (conn_index = 0; conn_index < MAX_NUMBER_OF_CONC_CONNECTIONS; + conn_index++) { + conn_info = &conc_connection_list[conn_index]; + if (conn_info->in_use && CDS_IS_DFS_CH(conn_info->chan) && + (CDS_SAP_MODE == conn_info->mode || + CDS_P2P_GO_MODE == conn_info->mode)) { + *channel = conc_connection_list[conn_index].chan; + status = true; + } + } + qdf_mutex_release(&cds_ctx->qdf_conc_list_lock); + return status; +} + +/** + * cds_get_valid_chans() - Get the valid channel list + * @chan_list: Pointer to the valid channel list + * @list_len: Pointer to the length of the valid channel list + * + * Gets the valid channel list filtered by band + * + * Return: QDF_STATUS + */ +QDF_STATUS cds_get_valid_chans(uint8_t *chan_list, uint32_t *list_len) +{ + QDF_STATUS status; + hdd_context_t *hdd_ctx; + cds_context_type *cds_ctx; + + *list_len = 0; + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (!hdd_ctx) { + cds_err("HDD context is NULL"); + return QDF_STATUS_E_FAILURE; + } + + cds_ctx = cds_get_context(QDF_MODULE_ID_QDF); + if (!cds_ctx) { + cds_err("Invalid CDS Context"); + return QDF_STATUS_E_FAILURE; + } + + if (!cds_ctx->sme_get_valid_channels) { + cds_err("sme_get_valid_chans callback is NULL"); + return QDF_STATUS_E_FAILURE; + } + + *list_len = QDF_MAX_NUM_CHAN; + status = cds_ctx->sme_get_valid_channels(hdd_ctx->hHal, + chan_list, list_len); + if (QDF_IS_STATUS_ERROR(status)) { + cds_err("Error in getting valid channels"); + *list_len = 0; + return status; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * cds_get_nss_for_vdev() - Get the allowed nss value for the + * vdev + * @dev_mode: connection type. + * @nss2g: Pointer to the 2G Nss parameter. + * @nss5g: Pointer to the 5G Nss parameter. + * + * Fills the 2G and 5G Nss values based on connection type. + * + * Return: QDF_STATUS + */ +QDF_STATUS cds_get_nss_for_vdev(enum cds_con_mode mode, + uint8_t *nss_2g, uint8_t *nss_5g) +{ + hdd_context_t *hdd_ctx; + cds_context_type *cds_ctx; + enum tQDF_ADAPTER_MODE dev_mode; + + switch (mode) { + case CDS_STA_MODE: + dev_mode = QDF_STA_MODE; + break; + case CDS_SAP_MODE: + dev_mode = QDF_SAP_MODE; + break; + case CDS_P2P_CLIENT_MODE: + dev_mode = QDF_P2P_CLIENT_MODE; + break; + case CDS_P2P_GO_MODE: + dev_mode = QDF_P2P_GO_MODE; + break; + case CDS_IBSS_MODE: + dev_mode = QDF_IBSS_MODE; + break; + default: + cds_err("Invalid mode to get allowed NSS value"); + return QDF_STATUS_E_FAILURE; + }; + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (!hdd_ctx) { + cds_err("HDD context is NULL"); + return QDF_STATUS_E_FAILURE; + } + + cds_ctx = cds_get_context(QDF_MODULE_ID_QDF); + if (!cds_ctx) { + cds_err("Invalid CDS Context"); + return QDF_STATUS_E_FAILURE; + } + + if (!cds_ctx->sme_get_nss_for_vdev) { + cds_err("sme_get_nss_for_vdev callback is NULL"); + return QDF_STATUS_E_FAILURE; + } + + cds_ctx->sme_get_nss_for_vdev(hdd_ctx->hHal, + dev_mode, nss_2g, nss_5g); + + return QDF_STATUS_SUCCESS; +} + +/** + * cds_list_has_24GHz_channel() - Check if list contains 2.4GHz channels + * @channel_list: Channel list + * @list_len: Length of the channel list + * + * Checks if the channel list contains atleast one 2.4GHz channel + * + * Return: True if 2.4GHz channel is present, false otherwise + */ +bool cds_list_has_24GHz_channel(uint8_t *channel_list, + uint32_t list_len) +{ + uint32_t i; + + for (i = 0; i < list_len; i++) { + if (CDS_IS_CHANNEL_24GHZ(channel_list[i])) + return true; + } + + return false; +} + +/** + * cds_set_sap_mandatory_channels() - Set the mandatory channel for SAP + * @channels: Channel list to be set + * @len: Length of the channel list + * + * Sets the channels for the mandatory channel list along with the length of + * of the channel list. + * + * Return: QDF_STATUS + */ +QDF_STATUS cds_set_sap_mandatory_channels(uint8_t *channels, uint32_t len) +{ + cds_context_type *cds_ctx; + uint32_t i; + + cds_ctx = cds_get_context(QDF_MODULE_ID_QDF); + if (!cds_ctx) { + cds_err("Invalid CDS Context"); + return QDF_STATUS_E_FAILURE; + } + + if (!len) { + cds_err("No mandatory freq/chan configured"); + return QDF_STATUS_E_FAILURE; + } + + if (!cds_list_has_24GHz_channel(channels, len)) { + cds_err("2.4GHz channels missing, this is not expected"); + return QDF_STATUS_E_FAILURE; + } + + cds_debug("mandatory chan length:%d", + cds_ctx->sap_mandatory_channels_len); + + for (i = 0; i < len; i++) { + cds_ctx->sap_mandatory_channels[i] = channels[i]; + cds_debug("chan:%d", cds_ctx->sap_mandatory_channels[i]); + } + + cds_ctx->sap_mandatory_channels_len = len; + + return QDF_STATUS_SUCCESS; +} + +/** + * cds_reset_sap_mandatory_channels() - Reset the SAP mandatory channels + * + * Resets the SAP mandatory channel list and the length of the list + * + * Return: QDF_STATUS + */ +QDF_STATUS cds_reset_sap_mandatory_channels(void) +{ + cds_context_type *cds_ctx; + + cds_ctx = cds_get_context(QDF_MODULE_ID_QDF); + if (!cds_ctx) { + cds_err("Invalid CDS Context"); + return QDF_STATUS_E_FAILURE; + } + + cds_ctx->sap_mandatory_channels_len = 0; + qdf_mem_zero(cds_ctx->sap_mandatory_channels, + QDF_ARRAY_SIZE(cds_ctx->sap_mandatory_channels)); + + return QDF_STATUS_SUCCESS; +} + +/** + * cds_enable_disable_sap_mandatory_chan_list() - enable/disable SAP mandatory + * channel list + * @val: Enable or Disable sap mandatory chan list + * + * enable/disable the SAP mandatory channel list + * + * Return: None + */ +void cds_enable_disable_sap_mandatory_chan_list(bool val) +{ + cds_context_type *cds_ctx; + + cds_ctx = cds_get_context(QDF_MODULE_ID_QDF); + if (!cds_ctx) { + cds_err("Invalid CDS Context"); + return; + } + + cds_debug("enable_sap_mandatory_chan_list %d", val); + cds_ctx->enable_sap_mandatory_chan_list = val; +} + +/** + * cds_add_sap_mandatory_chan() - Add chan to SAP mandatory chan + * list + * @chan: Channel to be added + * + * Add chan to SAP mandatory channel list + * + * Return: None + */ +void cds_add_sap_mandatory_chan(uint8_t chan) +{ + cds_context_type *cds_ctx; + int i; + + cds_ctx = cds_get_context(QDF_MODULE_ID_QDF); + if (!cds_ctx) { + cds_err("Invalid CDS Context"); + return; + } + for (i = 0; i < cds_ctx->sap_mandatory_channels_len; i++) { + if (chan == cds_ctx->sap_mandatory_channels[i]) + return; + } + + cds_debug("chan %hu", chan); + cds_ctx->sap_mandatory_channels[cds_ctx->sap_mandatory_channels_len++] + = chan; +} + +/** + * cds_is_sap_mandatory_chan_list_enabled() - Return the SAP mandatory chan + * list enabled status + * + * Get the SAP mandatory chan list enabled status + * + * Return: Enable or Disable + */ +bool cds_is_sap_mandatory_chan_list_enabled(void) +{ + cds_context_type *cds_ctx; + cds_ctx = cds_get_context(QDF_MODULE_ID_QDF); + + if (!cds_ctx) { + cds_err("Invalid CDS Context"); + return false; + } + + return cds_ctx->enable_sap_mandatory_chan_list; +} + +/** + * cds_get_sap_mandatory_chan_list_len() - Return the SAP mandatory chan list + * len + * + * Get the SAP mandatory chan list len + * + * Return: Channel list length + */ +uint32_t cds_get_sap_mandatory_chan_list_len(void) +{ + cds_context_type *cds_ctx; + cds_ctx = cds_get_context(QDF_MODULE_ID_QDF); + + if (!cds_ctx) { + cds_err("Invalid CDS Context"); + return false; + } + + return cds_ctx->sap_mandatory_channels_len; +} + +/** + * cds_init_sap_mandatory_2g_chan() - Init 2.4G SAP mandatory chan list + * + * Initialize the 2.4G SAP mandatory channels + * + * Return: Success or Failure + */ +void cds_init_sap_mandatory_2g_chan(void) +{ + cds_context_type *cds_ctx; + uint8_t chan_list[QDF_MAX_NUM_CHAN] = {0}; + uint32_t len = 0; + int i; + QDF_STATUS status; + + cds_ctx = cds_get_context(QDF_MODULE_ID_QDF); + if (!cds_ctx) { + cds_err("Invalid CDS Context"); + return; + } + + status = cds_get_valid_chans(chan_list, &len); + if (QDF_IS_STATUS_ERROR(status)) { + cds_err("Error in getting valid channels"); + return; + } + for (i = 0; i < len; i++) { + if (CDS_IS_CHANNEL_24GHZ(chan_list[i])) { + cds_err("Add chan %hu to mandatory list", chan_list[i]); + cds_ctx->sap_mandatory_channels[ + cds_ctx->sap_mandatory_channels_len++] = chan_list[i]; + } + } + return; +} + +/** + * cds_remove_sap_mandatory_chan() - Remove chan from SAP mandatory chan list + * + * Remove chan from SAP mandatory chan list + * + * Return: Success or Failure + */ +void cds_remove_sap_mandatory_chan(uint8_t chan) +{ + cds_context_type *cds_ctx; + uint8_t chan_list[QDF_MAX_NUM_CHAN] = {0}; + uint32_t num_chan = 0; + int i; + + cds_ctx = cds_get_context(QDF_MODULE_ID_QDF); + if (!cds_ctx) { + cds_err("Invalid CDS Context"); + return; + } + + for (i = 0; i < cds_ctx->sap_mandatory_channels_len; i++) { + if (chan == cds_ctx->sap_mandatory_channels[i]) + continue; + chan_list[num_chan++] = cds_ctx->sap_mandatory_channels[i]; + } + + qdf_mem_zero(cds_ctx->sap_mandatory_channels, + cds_ctx->sap_mandatory_channels_len); + qdf_mem_copy(cds_ctx->sap_mandatory_channels, chan_list, num_chan); + cds_ctx->sap_mandatory_channels_len = num_chan; + + return; +} +/** + * cds_is_sap_mandatory_channel_set() - Checks if SAP mandatory channel is set + * + * Checks if any mandatory channel is set for SAP operation + * + * Return: True if mandatory channel is set, false otherwise + */ +bool cds_is_sap_mandatory_channel_set(void) +{ + cds_context_type *cds_ctx; + + cds_ctx = cds_get_context(QDF_MODULE_ID_QDF); + if (!cds_ctx) { + cds_err("Invalid CDS Context"); + return false; + } + + if (cds_ctx->sap_mandatory_channels_len) + return true; + else + return false; +} + +/** + * cds_modify_sap_pcl_based_on_mandatory_channel() - Modify SAPs PCL based on + * mandatory channel list + * @pcl_list_org: Pointer to the preferred channel list to be trimmed + * @weight_list_org: Pointer to the weights of the preferred channel list + * @pcl_len_org: Pointer to the length of the preferred chanel list + * + * Modifies the preferred channel list of SAP based on the mandatory channel + * + * Return: QDF_STATUS + */ +QDF_STATUS cds_modify_sap_pcl_based_on_mandatory_channel(uint8_t *pcl_list_org, + uint8_t *weight_list_org, + uint32_t *pcl_len_org) +{ + cds_context_type *cds_ctx; + uint32_t i, j, pcl_len = 0; + uint8_t pcl_list[QDF_MAX_NUM_CHAN]; + uint8_t weight_list[QDF_MAX_NUM_CHAN]; + bool found; + + cds_ctx = cds_get_context(QDF_MODULE_ID_QDF); + if (!cds_ctx) { + cds_err("Invalid CDS Context"); + return QDF_STATUS_E_FAILURE; + } + + if (!cds_ctx->sap_mandatory_channels_len) + return QDF_STATUS_SUCCESS; + + if (!cds_list_has_24GHz_channel(cds_ctx->sap_mandatory_channels, + cds_ctx->sap_mandatory_channels_len)) { + cds_err("fav channel list is missing 2.4GHz channels"); + return QDF_STATUS_E_FAILURE; + } + + for (i = 0; i < cds_ctx->sap_mandatory_channels_len; i++) + cds_debug("fav chan:%d", cds_ctx->sap_mandatory_channels[i]); + + for (i = 0; i < *pcl_len_org; i++) { + found = false; + for (j = 0; j < cds_ctx->sap_mandatory_channels_len; j++) { + if (pcl_list_org[i] == + cds_ctx->sap_mandatory_channels[j]) { + found = true; + break; + } + } + if (found) { + pcl_list[pcl_len] = pcl_list_org[i]; + weight_list[pcl_len++] = weight_list_org[i]; + } + } + + qdf_mem_zero(pcl_list_org, QDF_ARRAY_SIZE(pcl_list_org)); + qdf_mem_zero(weight_list_org, QDF_ARRAY_SIZE(weight_list_org)); + qdf_mem_copy(pcl_list_org, pcl_list, pcl_len); + qdf_mem_copy(weight_list_org, weight_list, pcl_len); + *pcl_len_org = pcl_len; + + return QDF_STATUS_SUCCESS; +} + +/** + * cds_get_sap_mandatory_channel() - Get the mandatory channel for SAP + * @chan: Pointer to the SAP mandatory channel + * + * Gets the mandatory channel for SAP operation + * + * Return: QDF_STATUS + */ +QDF_STATUS cds_get_sap_mandatory_channel(uint32_t *chan) +{ + QDF_STATUS status; + struct sir_pcl_list pcl; + + qdf_mem_zero(&pcl, sizeof(pcl)); + + status = cds_get_pcl_for_existing_conn(CDS_SAP_MODE, + pcl.pcl_list, &pcl.pcl_len, + pcl.weight_list, QDF_ARRAY_SIZE(pcl.weight_list)); + if (QDF_IS_STATUS_ERROR(status)) { + cds_err("Unable to get PCL for SAP"); + return status; + } + + /* No existing SAP connection and hence a new SAP connection might be + * coming up. + */ + if (!pcl.pcl_len) { + cds_info("cds_get_pcl_for_existing_conn returned no pcl"); + status = cds_get_pcl(CDS_SAP_MODE, + pcl.pcl_list, &pcl.pcl_len, + pcl.weight_list, + QDF_ARRAY_SIZE(pcl.weight_list)); + if (QDF_IS_STATUS_ERROR(status)) { + cds_err("Unable to get PCL for SAP: cds_get_pcl"); + return status; + } + } + + status = cds_modify_sap_pcl_based_on_mandatory_channel(pcl.pcl_list, + pcl.weight_list, + &pcl.pcl_len); + if (QDF_IS_STATUS_ERROR(status)) { + cds_err("Unable to modify SAP PCL"); + return status; + } + + *chan = pcl.pcl_list[0]; + cds_info("mandatory channel:%d", *chan); + return QDF_STATUS_SUCCESS; +} + +/** + * cds_get_valid_chan_weights() - Get the weightage for all valid channels + * @weight: Pointer to the structure containing pcl, saved channel list and + * weighed channel list + * + * Provides the weightage for all valid channels. This compares the PCL list + * with the valid channel list. The channels present in the PCL get their + * corresponding weightage and the non-PCL channels get the default weightage + * of WEIGHT_OF_NON_PCL_CHANNELS. + * + * Return: QDF_STATUS + */ +QDF_STATUS cds_get_valid_chan_weights(struct sir_pcl_chan_weights *weight) +{ + uint32_t i, j; + cds_context_type *cds_ctx; + struct cds_conc_connection_info info; + + cds_ctx = cds_get_context(QDF_MODULE_ID_QDF); + if (!cds_ctx) { + cds_err("Invalid CDS Context"); + return QDF_STATUS_E_FAILURE; + } + + if (!weight->pcl_list) { + cds_err("Invalid pcl"); + return QDF_STATUS_E_FAILURE; + } + + if (!weight->saved_chan_list) { + cds_err("Invalid valid channel list"); + return QDF_STATUS_E_FAILURE; + } + + if (!weight->weighed_valid_list) { + cds_err("Invalid weighed valid channel list"); + return QDF_STATUS_E_FAILURE; + } + + qdf_mem_set(weight->weighed_valid_list, QDF_MAX_NUM_CHAN, + WEIGHT_OF_DISALLOWED_CHANNELS); + qdf_mutex_acquire(&cds_ctx->qdf_conc_list_lock); + if (cds_mode_specific_connection_count(CDS_STA_MODE, NULL) > 0) { + /* + * Store the STA mode's parameter and temporarily delete it + * from the concurrency table. This way the allow concurrency + * check can be used as though a new connection is coming up, + * allowing to detect the disallowed channels. + */ + cds_store_and_del_conn_info(CDS_STA_MODE, &info); + /* + * There is a small window between releasing the above lock + * and acquiring the same in cds_allow_concurrency, below! + */ + qdf_mutex_release(&cds_ctx->qdf_conc_list_lock); + for (i = 0; i < weight->saved_num_chan; i++) { + if (cds_allow_concurrency(CDS_STA_MODE, + weight->saved_chan_list[i], + HW_MODE_20_MHZ)) { + weight->weighed_valid_list[i] = + WEIGHT_OF_NON_PCL_CHANNELS; + } + } + qdf_mutex_acquire(&cds_ctx->qdf_conc_list_lock); + /* Restore the connection info */ + cds_restore_deleted_conn_info(&info); + } + qdf_mutex_release(&cds_ctx->qdf_conc_list_lock); + + for (i = 0; i < weight->saved_num_chan; i++) { + for (j = 0; j < weight->pcl_len; j++) { + if (weight->saved_chan_list[i] == weight->pcl_list[j]) { + weight->weighed_valid_list[i] = + weight->weight_list[j]; + break; + } + } + } + + return QDF_STATUS_SUCCESS; +} + +/** + * cds_set_hw_mode_on_channel_switch() - Set hw mode after channel switch + * @session_id: Session ID + * + * Sets hw mode after doing a channel switch + * + * Return: QDF_STATUS + */ +QDF_STATUS cds_set_hw_mode_on_channel_switch(uint8_t session_id) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE, qdf_status; + cds_context_type *cds_ctx; + enum cds_conc_next_action action; + hdd_context_t *hdd_ctx; + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (!hdd_ctx) { + cds_err("HDD context is NULL"); + return status; + } + + if (!wma_is_hw_dbs_capable()) { + cds_err("PM/DBS is disabled"); + return status; + } + + cds_ctx = cds_get_context(QDF_MODULE_ID_QDF); + if (!cds_ctx) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("Invalid CDS Context")); + return status; + } + + action = cds_get_current_pref_hw_mode(); + + if ((action != CDS_DBS_DOWNGRADE) && + (action != CDS_SINGLE_MAC_UPGRADE)) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("Invalid action: %d"), action); + status = QDF_STATUS_SUCCESS; + goto done; + } + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO, + FL("action:%d session id:%d"), + action, session_id); + + /* Opportunistic timer is started, PM will check if MCC upgrade can be + * done on timer expiry. This avoids any possible ping pong effect + * as well. + */ + if (action == CDS_SINGLE_MAC_UPGRADE) { + qdf_status = cds_restart_opportunistic_timer(false); + if (QDF_IS_STATUS_SUCCESS(qdf_status)) + cds_info("opportunistic timer for MCC upgrade"); + goto done; + } + + /* For DBS, we want to move right away to DBS mode */ + status = cds_next_actions(session_id, action, + SIR_UPDATE_REASON_CHANNEL_SWITCH); + if (!QDF_IS_STATUS_SUCCESS(status)) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("no set hw mode command was issued")); + goto done; + } +done: + /* success must be returned only when a set hw mode was done */ + return status; +} + +/** + * cds_dump_connection_status_info() - Dump the concurrency information + * + * Prints the concurrency information such as tx/rx spatial stream, chainmask, + * etc. + * + * Return: None + */ +void cds_dump_connection_status_info(void) +{ + cds_context_type *cds_ctx; + uint32_t i; + + cds_ctx = cds_get_context(QDF_MODULE_ID_QDF); + if (!cds_ctx) { + cds_err("Invalid CDS Context"); + return; + } + + qdf_mutex_acquire(&cds_ctx->qdf_conc_list_lock); + for (i = 0; i < MAX_NUMBER_OF_CONC_CONNECTIONS; i++) { + cds_debug("%d: use:%d vdev:%d mode:%d mac:%d chan:%d orig chainmask:%d orig nss:%d bw:%d", + i, conc_connection_list[i].in_use, + conc_connection_list[i].vdev_id, + conc_connection_list[i].mode, + conc_connection_list[i].mac, + conc_connection_list[i].chan, + conc_connection_list[i].chain_mask, + conc_connection_list[i].original_nss, + conc_connection_list[i].bw); + } + qdf_mutex_release(&cds_ctx->qdf_conc_list_lock); +} + +/** + * cds_is_any_mode_active_on_band_along_with_session() - Check if any connection + * mode is active on a band along with the given session + * @session_id: Session along which active sessions are looked for + * @band: Operating frequency band of the connection + * CDS_BAND_24: Looks for active connection on 2.4 GHz only + * CDS_BAND_5: Looks for active connection on 5 GHz only + * + * Checks if any of the connection mode is active on a given frequency band + * + * Return: True if any connection is active on a given band, false otherwise + */ +bool cds_is_any_mode_active_on_band_along_with_session(uint8_t session_id, + enum cds_band band) +{ + cds_context_type *cds_ctx; + uint32_t i; + bool status = false; + + cds_ctx = cds_get_context(QDF_MODULE_ID_QDF); + if (!cds_ctx) { + cds_err("Invalid CDS Context"); + status = false; + goto send_status; + } + + qdf_mutex_acquire(&cds_ctx->qdf_conc_list_lock); + for (i = 0; i < MAX_NUMBER_OF_CONC_CONNECTIONS; i++) { + switch (band) { + case CDS_BAND_24: + if ((conc_connection_list[i].vdev_id != session_id) && + (conc_connection_list[i].in_use) && + (CDS_IS_CHANNEL_24GHZ( + conc_connection_list[i].chan))) { + status = true; + goto release_mutex_and_send_status; + } + break; + case CDS_BAND_5: + if ((conc_connection_list[i].vdev_id != session_id) && + (conc_connection_list[i].in_use) && + (CDS_IS_CHANNEL_5GHZ( + conc_connection_list[i].chan))) { + status = true; + goto release_mutex_and_send_status; + } + break; + default: + cds_err("Invalid band option:%d", band); + status = false; + goto release_mutex_and_send_status; + } + } +release_mutex_and_send_status: + qdf_mutex_release(&cds_ctx->qdf_conc_list_lock); +send_status: + return status; +} + +/** + * cds_get_chan_by_session_id() - Get channel for a given session ID + * @session_id: Session ID + * @chan: Pointer to the channel + * + * Gets the channel for a given session ID + * + * Return: QDF_STATUS + */ +QDF_STATUS cds_get_chan_by_session_id(uint8_t session_id, uint8_t *chan) +{ + cds_context_type *cds_ctx; + uint32_t i; + + cds_ctx = cds_get_context(QDF_MODULE_ID_QDF); + if (!cds_ctx) { + cds_err("Invalid CDS Context"); + return QDF_STATUS_E_FAILURE; + } + + qdf_mutex_acquire(&cds_ctx->qdf_conc_list_lock); + for (i = 0; i < MAX_NUMBER_OF_CONC_CONNECTIONS; i++) { + if ((conc_connection_list[i].vdev_id == session_id) && + (conc_connection_list[i].in_use)) { + *chan = conc_connection_list[i].chan; + qdf_mutex_release(&cds_ctx->qdf_conc_list_lock); + return QDF_STATUS_SUCCESS; + } + } + qdf_mutex_release(&cds_ctx->qdf_conc_list_lock); + return QDF_STATUS_E_FAILURE; +} + +/** + * cds_get_mac_id_by_session_id() - Get MAC ID for a given session ID + * @session_id: Session ID + * @mac_id: Pointer to the MAC ID + * + * Gets the MAC ID for a given session ID + * + * Return: QDF_STATUS + */ +QDF_STATUS cds_get_mac_id_by_session_id(uint8_t session_id, uint8_t *mac_id) +{ + cds_context_type *cds_ctx; + uint32_t i; + + cds_ctx = cds_get_context(QDF_MODULE_ID_QDF); + if (!cds_ctx) { + cds_err("Invalid CDS Context"); + return QDF_STATUS_E_FAILURE; + } + + qdf_mutex_acquire(&cds_ctx->qdf_conc_list_lock); + for (i = 0; i < MAX_NUMBER_OF_CONC_CONNECTIONS; i++) { + if ((conc_connection_list[i].vdev_id == session_id) && + (conc_connection_list[i].in_use)) { + *mac_id = conc_connection_list[i].mac; + qdf_mutex_release(&cds_ctx->qdf_conc_list_lock); + return QDF_STATUS_SUCCESS; + } + } + qdf_mutex_release(&cds_ctx->qdf_conc_list_lock); + return QDF_STATUS_E_FAILURE; +} + +/** + * cds_get_mcc_session_id_on_mac() - Get MCC session's ID + * @mac_id: MAC ID on which MCC session needs to be found + * @session_id: Session with which MCC combination needs to be found + * @mcc_session_id: Pointer to the MCC session ID + * + * Get the session ID of the MCC interface + * + * Return: QDF_STATUS + */ +QDF_STATUS cds_get_mcc_session_id_on_mac(uint8_t mac_id, uint8_t session_id, + uint8_t *mcc_session_id) +{ + cds_context_type *cds_ctx; + uint32_t i; + QDF_STATUS status; + uint8_t chan; + + cds_ctx = cds_get_context(QDF_MODULE_ID_QDF); + if (!cds_ctx) { + cds_err("Invalid CDS Context"); + return QDF_STATUS_E_FAILURE; + } + + status = cds_get_chan_by_session_id(session_id, &chan); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to get channel for session id:%d", session_id); + return QDF_STATUS_E_FAILURE; + } + + qdf_mutex_acquire(&cds_ctx->qdf_conc_list_lock); + for (i = 0; i < MAX_NUMBER_OF_CONC_CONNECTIONS; i++) { + if (conc_connection_list[i].mac != mac_id) + continue; + if (conc_connection_list[i].vdev_id == session_id) + continue; + /* Inter band or intra band MCC */ + if ((conc_connection_list[i].chan != chan) && + (conc_connection_list[i].in_use)) { + *mcc_session_id = conc_connection_list[i].vdev_id; + qdf_mutex_release(&cds_ctx->qdf_conc_list_lock); + return QDF_STATUS_SUCCESS; + } + } + qdf_mutex_release(&cds_ctx->qdf_conc_list_lock); + return QDF_STATUS_E_FAILURE; +} + +/** + * cds_get_mcc_operating_channel() - Get the MCC channel + * @session_id: Session ID with which MCC is being done + * + * Gets the MCC channel for a given session ID. + * + * Return: '0' (INVALID_CHANNEL_ID) or valid channel number + */ +uint8_t cds_get_mcc_operating_channel(uint8_t session_id) +{ + uint8_t mac_id, mcc_session_id; + QDF_STATUS status; + uint8_t chan; + cds_context_type *cds_ctx; + + cds_ctx = cds_get_context(QDF_MODULE_ID_QDF); + if (!cds_ctx) { + cds_err("Invalid CDS Context"); + return INVALID_CHANNEL_ID; + } + + status = cds_get_mac_id_by_session_id(session_id, &mac_id); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("failed to get MAC ID"); + return INVALID_CHANNEL_ID; + } + + status = cds_get_mcc_session_id_on_mac(mac_id, session_id, + &mcc_session_id); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("failed to get MCC session ID"); + return INVALID_CHANNEL_ID; + } + + status = cds_get_chan_by_session_id(mcc_session_id, &chan); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to get channel for MCC session ID:%d", + mcc_session_id); + return INVALID_CHANNEL_ID; + } + + return chan; +} + +/** + * cds_checkn_update_hw_mode_single_mac_mode() - Set hw_mode to SMM + * if required + * @channel: channel number for the new STA connection + * + * After the STA disconnection, if the hw_mode is in DBS and the new STA + * connection is coming in the band in which existing connections are + * present, then this function stops the dbs opportunistic timer and sets + * the hw_mode to Single MAC mode (SMM). + * + * Return: None + */ +void cds_checkn_update_hw_mode_single_mac_mode(uint8_t channel) +{ + uint8_t i; + cds_context_type *cds_ctx; + + cds_ctx = cds_get_context(QDF_MODULE_ID_QDF); + if (!cds_ctx) { + cds_err("Invalid CDS Context"); + return; + } + + qdf_mutex_acquire(&cds_ctx->qdf_conc_list_lock); + for (i = 0; i < MAX_NUMBER_OF_CONC_CONNECTIONS; i++) { + if (conc_connection_list[i].in_use) + if (!CDS_IS_SAME_BAND_CHANNELS(channel, + conc_connection_list[i].chan)) { + qdf_mutex_release(&cds_ctx->qdf_conc_list_lock); + cds_info("DBS required"); + return; + } + } + qdf_mutex_release(&cds_ctx->qdf_conc_list_lock); + + if (QDF_TIMER_STATE_RUNNING == + cds_ctx->dbs_opportunistic_timer.state) + qdf_mc_timer_stop(&cds_ctx->dbs_opportunistic_timer); + + cds_dbs_opportunistic_timer_handler((void *)cds_ctx); +} + +/** + * cds_set_do_hw_mode_change_flag() - Set flag to indicate hw mode change + * @flag: Indicate if hw mode change is required or not + * + * Set the flag to indicate whether a hw mode change is required after a + * vdev up or not. Flag value of true indicates that a hw mode change is + * required after vdev up. + * + * Return: None + */ +void cds_set_do_hw_mode_change_flag(bool flag) +{ + cds_context_type *cds_ctx; + cds_ctx = cds_get_context(QDF_MODULE_ID_QDF); + + if (!cds_ctx) { + cds_err("Invalid CDS Context"); + return; + } + + qdf_mutex_acquire(&cds_ctx->qdf_conc_list_lock); + cds_ctx->do_hw_mode_change = flag; + qdf_mutex_release(&cds_ctx->qdf_conc_list_lock); + + cds_debug("hw_mode_change_channel:%d", flag); +} + +/** + * cds_is_hw_mode_change_after_vdev_up() - Check if hw mode change is needed + * + * Returns the flag which indicates if a hw mode change is required after + * vdev up. + * + * Return: True if hw mode change is required, false otherwise + */ +bool cds_is_hw_mode_change_after_vdev_up(void) +{ + cds_context_type *cds_ctx; + bool flag; + + cds_ctx = cds_get_context(QDF_MODULE_ID_QDF); + + if (!cds_ctx) { + cds_err("Invalid CDS Context"); + return INVALID_CHANNEL_ID; + } + + qdf_mutex_acquire(&cds_ctx->qdf_conc_list_lock); + flag = cds_ctx->do_hw_mode_change; + qdf_mutex_release(&cds_ctx->qdf_conc_list_lock); + + return flag; +} + +/** + * cds_set_hw_mode_change_in_progress() - Set value corresponding to + * cds_hw_mode_change that indicate if HW mode change is in progress + * @value: Indicate if hw mode change is in progress + * + * Set the value corresponding to cds_hw_mode_change that + * indicated if hw mode change is in progress. + * + * Return: None + */ +void cds_set_hw_mode_change_in_progress(enum cds_hw_mode_change value) +{ + cds_context_type *cds_ctx; + cds_ctx = cds_get_context(QDF_MODULE_ID_QDF); + + if (!cds_ctx) { + cds_err("Invalid CDS Context"); + return; + } + + qdf_mutex_acquire(&cds_ctx->qdf_conc_list_lock); + cds_ctx->hw_mode_change_in_progress = value; + qdf_mutex_release(&cds_ctx->qdf_conc_list_lock); + + cds_debug("hw_mode_change_in_progress:%d", value); +} + +/** + * cds_is_hw_mode_change_in_progress() - Check if HW mode change is in + * progress. + * + * Returns the corresponding cds_hw_mode_change value. + * + * Return: cds_hw_mode_change value. + */ +enum cds_hw_mode_change cds_is_hw_mode_change_in_progress(void) +{ + cds_context_type *cds_ctx; + enum cds_hw_mode_change value; + value = CDS_HW_MODE_NOT_IN_PROGRESS; + + cds_ctx = cds_get_context(QDF_MODULE_ID_QDF); + + if (!cds_ctx) { + cds_err("Invalid CDS Context"); + return value; + } + + qdf_mutex_acquire(&cds_ctx->qdf_conc_list_lock); + value = cds_ctx->hw_mode_change_in_progress; + qdf_mutex_release(&cds_ctx->qdf_conc_list_lock); + + return value; +} diff --git a/drivers/staging/qcacld-3.0/core/cds/src/cds_ieee80211_common_i.h b/drivers/staging/qcacld-3.0/core/cds/src/cds_ieee80211_common_i.h new file mode 100644 index 0000000000000000000000000000000000000000..cccbdeb1b3793f42f359f2aa362a8e108d5956c7 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/cds/src/cds_ieee80211_common_i.h @@ -0,0 +1,565 @@ +/* + * Copyright (c) 2013-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef CDS_COMMON__IEEE80211_I_H_ +#define CDS_COMMON__IEEE80211_I_H_ + +/** + * enum ieee80211_phymode - not really a mode; there are really multiple PHY's + * @IEEE80211_MODE_AUTO - autoselect + * @IEEE80211_MODE_11A - 5GHz, OFDM + * @IEEE80211_MODE_11B - 2GHz, CCK + * @IEEE80211_MODE_11G - 2GHz, OFDM + * @IEEE80211_MODE_FH - 2GHz, GFSK + * @IEEE80211_MODE_TURBO_A - 5GHz, OFDM, 2x clock dynamic turbo + * @IEEE80211_MODE_TURBO_G - 2GHz, OFDM, 2x clock dynamic turbo + * @IEEE80211_MODE_11NA_HT20 - 5Ghz, HT20 + * @IEEE80211_MODE_11NG_HT20 - 2Ghz, HT20 + * @IEEE80211_MODE_11NA_HT40PLUS - 5Ghz, HT40 (ext ch +1) + * @IEEE80211_MODE_11NA_HT40MINUS - 5Ghz, HT40 (ext ch -1) + * @IEEE80211_MODE_11NG_HT40PLUS - 2Ghz, HT40 (ext ch +1) + * @IEEE80211_MODE_11NG_HT40MINUS - 2Ghz, HT40 (ext ch -1) + * @IEEE80211_MODE_11NG_HT40 - 2Ghz, Auto HT40 + * @IEEE80211_MODE_11NA_HT40 - 2Ghz, Auto HT40 + * @IEEE80211_MODE_11AC_VHT20 - 5Ghz, VHT20 + * @IEEE80211_MODE_11AC_VHT40PLUS - 5Ghz, VHT40 (Ext ch +1) + * @IEEE80211_MODE_11AC_VHT40MINUS - 5Ghz VHT40 (Ext ch -1) + * @IEEE80211_MODE_11AC_VHT40 - 5Ghz, VHT40 + * @IEEE80211_MODE_11AC_VHT80 - 5Ghz, VHT80 + * @IEEE80211_MODE_2G_AUTO - 2G 11 b/g/n autoselect + * @IEEE80211_MODE_5G_AUTO - 5G 11 a/n/ac autoselect + * @IEEE80211_MODE_11AGN - Support 11N in both 2G and 5G + * @IEEE80211_MODE_MAX - Maximum possible value + */ +enum ieee80211_phymode { + IEEE80211_MODE_AUTO = 0, + IEEE80211_MODE_11A = 1, + IEEE80211_MODE_11B = 2, + IEEE80211_MODE_11G = 3, + IEEE80211_MODE_FH = 4, + IEEE80211_MODE_TURBO_A = 5, + IEEE80211_MODE_TURBO_G = 6, + IEEE80211_MODE_11NA_HT20 = 7, + IEEE80211_MODE_11NG_HT20 = 8, + IEEE80211_MODE_11NA_HT40PLUS = 9, + IEEE80211_MODE_11NA_HT40MINUS = 10, + IEEE80211_MODE_11NG_HT40PLUS = 11, + IEEE80211_MODE_11NG_HT40MINUS = 12, + IEEE80211_MODE_11NG_HT40 = 13, + IEEE80211_MODE_11NA_HT40 = 14, + IEEE80211_MODE_11AC_VHT20 = 15, + IEEE80211_MODE_11AC_VHT40PLUS = 16, + IEEE80211_MODE_11AC_VHT40MINUS = 17, + IEEE80211_MODE_11AC_VHT40 = 18, + IEEE80211_MODE_11AC_VHT80 = 19, + IEEE80211_MODE_2G_AUTO = 20, + IEEE80211_MODE_5G_AUTO = 21, + IEEE80211_MODE_11AGN = 22, + + /* Do not add after this line */ + IEEE80211_MODE_MAX = IEEE80211_MODE_11AGN, +}; + +/** + * enum ieee80211_opmode - operating mode + * @IEEE80211_M_IBSS - IBSS (adhoc) station + * @IEEE80211_M_HOSTAP - Software Access Point + * @IEEE80211_OPMODE_MAX = Highest numbered opmode in the list + * @IEEE80211_M_ANY - Any of the above; used by NDIS 6.x + * +*/ +enum ieee80211_opmode { + IEEE80211_M_IBSS = 0, + IEEE80211_M_HOSTAP = 6, + + /* Do not add after this line */ + IEEE80211_OPMODE_MAX = IEEE80211_M_HOSTAP, + + IEEE80211_M_ANY = 0xFF, +}; + +/* + * 802.11n + */ +#define IEEE80211_CWM_EXTCH_BUSY_THRESHOLD 30 + +enum ieee80211_cwm_mode { + IEEE80211_CWM_MODE20, + IEEE80211_CWM_MODE2040, + IEEE80211_CWM_MODE40, + IEEE80211_CWM_MODEMAX +}; + +enum ieee80211_cwm_extprotspacing { + IEEE80211_CWM_EXTPROTSPACING20, + IEEE80211_CWM_EXTPROTSPACING25, + IEEE80211_CWM_EXTPROTSPACINGMAX +}; + +enum ieee80211_cwm_width { + IEEE80211_CWM_WIDTH20, + IEEE80211_CWM_WIDTH40, + IEEE80211_CWM_WIDTH80, + IEEE80211_CWM_WIDTHINVALID = 0xff /* user invalid value */ +}; + +enum ieee80211_cwm_extprotmode { + IEEE80211_CWM_EXTPROTNONE, /* no protection */ + IEEE80211_CWM_EXTPROTCTSONLY, /* CTS to self */ + IEEE80211_CWM_EXTPROTRTSCTS, /* RTS-CTS */ + IEEE80211_CWM_EXTPROTMAX +}; + +enum ieee80211_fixed_rate_mode { + IEEE80211_FIXED_RATE_NONE = 0, + IEEE80211_FIXED_RATE_MCS = 1, /* HT rates */ + IEEE80211_FIXED_RATE_LEGACY = 2, /* legacy rates */ + IEEE80211_FIXED_RATE_VHT = 3 /* VHT rates */ +}; + +/* Holds the fixed rate information for each VAP */ +struct ieee80211_fixed_rate { + enum ieee80211_fixed_rate_mode mode; + uint32_t series; + uint32_t retries; +}; + +/* + * 802.11g protection mode. + */ +enum ieee80211_protmode { + IEEE80211_PROT_NONE = 0, /* no protection */ + IEEE80211_PROT_CTSONLY = 1, /* CTS to self */ + IEEE80211_PROT_RTSCTS = 2, /* RTS-CTS */ +}; + +/* + * Roaming mode is effectively who controls the operation + * of the 802.11 state machine when operating as a station. + * State transitions are controlled either by the driver + * (typically when management frames are processed by the + * hardware/firmware), the host (auto/normal operation of + * the 802.11 layer), or explicitly through ioctl requests + * when applications like wpa_supplicant want control. + */ +enum ieee80211_roamingmode { + IEEE80211_ROAMING_DEVICE = 0, /* driver/hardware control */ + IEEE80211_ROAMING_AUTO = 1, /* 802.11 layer control */ + IEEE80211_ROAMING_MANUAL = 2, /* application control */ +}; + +/* + * Scanning mode controls station scanning work; this is + * used only when roaming mode permits the host to select + * the bss to join/channel to use. + */ +enum ieee80211_scanmode { + IEEE80211_SCAN_DEVICE = 0, /* driver/hardware control */ + IEEE80211_SCAN_BEST = 1, /* 802.11 layer selects best */ + IEEE80211_SCAN_FIRST = 2, /* take first suitable candidate */ +}; + +#define IEEE80211_NWID_LEN 32 +#define IEEE80211_CHAN_MAX 255 +#define IEEE80211_CHAN_BYTES 32 /* howmany(IEEE80211_CHAN_MAX, NBBY) */ +#define IEEE80211_CHAN_ANY (-1) /* token for ``any channel'' */ +#define IEEE80211_CHAN_ANYC \ + ((struct ieee80211_channel *) IEEE80211_CHAN_ANY) + +#define IEEE80211_CHAN_DEFAULT 11 +#define IEEE80211_CHAN_DEFAULT_11A 52 +#define IEEE80211_CHAN_ADHOC_DEFAULT1 10 +#define IEEE80211_CHAN_ADHOC_DEFAULT2 11 + +#define IEEE80211_RADAR_11HCOUNT 5 +#define IEEE80211_RADAR_TEST_MUTE_CHAN_11A 36 /* Move to channel 36 for mute test */ +#define IEEE80211_RADAR_TEST_MUTE_CHAN_11NHT20 36 +#define IEEE80211_RADAR_TEST_MUTE_CHAN_11NHT40U 36 +#define IEEE80211_RADAR_TEST_MUTE_CHAN_11NHT40D 40 /* Move to channel 40 for HT40D mute test */ +#define IEEE80211_RADAR_DETECT_DEFAULT_DELAY 60000 /* STA ignore AP beacons during this period in millisecond */ + +#define IEEE80211_2GCSA_TBTTCOUNT 3 + +/* bits 0-3 are for private use by drivers */ +/* channel attributes */ +#define IEEE80211_CHAN_TURBO 0x00000010 /* Turbo channel */ +#define IEEE80211_CHAN_CCK 0x00000020 /* CCK channel */ +#define IEEE80211_CHAN_OFDM 0x00000040 /* OFDM channel */ +#define IEEE80211_CHAN_2GHZ 0x00000080 /* 2 GHz spectrum channel. */ +#define IEEE80211_CHAN_5GHZ 0x00000100 /* 5 GHz spectrum channel */ +#define IEEE80211_CHAN_PASSIVE 0x00000200 /* Only passive scan allowed */ +#define IEEE80211_CHAN_DYN 0x00000400 /* Dynamic CCK-OFDM channel */ +#define IEEE80211_CHAN_GFSK 0x00000800 /* GFSK channel (FHSS PHY) */ +#define IEEE80211_CHAN_RADAR_DFS 0x00001000 /* Radar found on channel */ +#define IEEE80211_CHAN_STURBO 0x00002000 /* 11a static turbo channel only */ +#define IEEE80211_CHAN_HALF 0x00004000 /* Half rate channel */ +#define IEEE80211_CHAN_QUARTER 0x00008000 /* Quarter rate channel */ +#define IEEE80211_CHAN_HT20 0x00010000 /* HT 20 channel */ +#define IEEE80211_CHAN_HT40PLUS 0x00020000 /* HT 40 with extension channel above */ +#define IEEE80211_CHAN_HT40MINUS 0x00040000 /* HT 40 with extension channel below */ +#define IEEE80211_CHAN_HT40INTOL 0x00080000 /* HT 40 Intolerant */ +#define IEEE80211_CHAN_VHT20 0x00100000 /* VHT 20 channel */ +#define IEEE80211_CHAN_VHT40PLUS 0x00200000 /* VHT 40 with extension channel above */ +#define IEEE80211_CHAN_VHT40MINUS 0x00400000 /* VHT 40 with extension channel below */ +#define IEEE80211_CHAN_VHT80 0x00800000 /* VHT 80 channel */ + +/* flagext */ +#define IEEE80211_CHAN_RADAR_FOUND 0x01 +#define IEEE80211_CHAN_DFS 0x0002 /* DFS required on channel */ +#define IEEE80211_CHAN_DFS_CLEAR 0x0008 /* if channel has been checked for DFS */ +#define IEEE80211_CHAN_11D_EXCLUDED 0x0010 /* excluded in 11D */ +#define IEEE80211_CHAN_CSA_RECEIVED 0x0020 /* Channel Switch Announcement received on this channel */ +#define IEEE80211_CHAN_DISALLOW_ADHOC 0x0040 /* ad-hoc is not allowed */ +#define IEEE80211_CHAN_DISALLOW_HOSTAP 0x0080 /* Station only channel */ + +/* + * Useful combinations of channel characteristics. + */ +#define IEEE80211_CHAN_FHSS \ + (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_GFSK) +#define IEEE80211_CHAN_A \ + (IEEE80211_CHAN_5GHZ | IEEE80211_CHAN_OFDM) +#define IEEE80211_CHAN_B \ + (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_CCK) +#define IEEE80211_CHAN_PUREG \ + (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_OFDM) +#define IEEE80211_CHAN_G \ + (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_DYN) +#define IEEE80211_CHAN_108A \ + (IEEE80211_CHAN_5GHZ | IEEE80211_CHAN_OFDM | IEEE80211_CHAN_TURBO) +#define IEEE80211_CHAN_108G \ + (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_OFDM | IEEE80211_CHAN_TURBO) +#define IEEE80211_CHAN_ST \ + (IEEE80211_CHAN_108A | IEEE80211_CHAN_STURBO) + +#define IEEE80211_IS_CHAN_11AC_2G(_c) \ + (IEEE80211_IS_CHAN_2GHZ((_c)) && IEEE80211_IS_CHAN_VHT((_c))) +#define IEEE80211_CHAN_11AC_VHT20_2G \ + (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_VHT20) +#define IEEE80211_CHAN_11AC_VHT40_2G \ + (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_VHT40PLUS | IEEE80211_CHAN_VHT40MINUS) +#define IEEE80211_CHAN_11AC_VHT80_2G \ + (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_VHT80) + +#define IEEE80211_IS_CHAN_11AC_VHT20_2G(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_11AC_VHT20_2G) == IEEE80211_CHAN_11AC_VHT20_2G) +#define IEEE80211_IS_CHAN_11AC_VHT40_2G(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_11AC_VHT40_2G) != 0) +#define IEEE80211_IS_CHAN_11AC_VHT80_2G(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_11AC_VHT80_2G) == IEEE80211_CHAN_11AC_VHT80_2G) + +#define IEEE80211_CHAN_11NG_HT20 \ + (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_HT20) +#define IEEE80211_CHAN_11NA_HT20 \ + (IEEE80211_CHAN_5GHZ | IEEE80211_CHAN_HT20) +#define IEEE80211_CHAN_11NG_HT40PLUS \ + (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_HT40PLUS) +#define IEEE80211_CHAN_11NG_HT40MINUS \ + (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_HT40MINUS) +#define IEEE80211_CHAN_11NA_HT40PLUS \ + (IEEE80211_CHAN_5GHZ | IEEE80211_CHAN_HT40PLUS) +#define IEEE80211_CHAN_11NA_HT40MINUS \ + (IEEE80211_CHAN_5GHZ | IEEE80211_CHAN_HT40MINUS) + +#define IEEE80211_CHAN_ALL \ + (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_5GHZ | IEEE80211_CHAN_GFSK | \ + IEEE80211_CHAN_CCK | IEEE80211_CHAN_OFDM | IEEE80211_CHAN_DYN | \ + IEEE80211_CHAN_HT20 | IEEE80211_CHAN_HT40PLUS | IEEE80211_CHAN_HT40MINUS | \ + IEEE80211_CHAN_VHT20 | IEEE80211_CHAN_VHT40PLUS | IEEE80211_CHAN_VHT40MINUS | IEEE80211_CHAN_VHT80 | \ + IEEE80211_CHAN_HALF | IEEE80211_CHAN_QUARTER) +#define IEEE80211_CHAN_ALLTURBO \ + (IEEE80211_CHAN_ALL | IEEE80211_CHAN_TURBO | IEEE80211_CHAN_STURBO) + +#define IEEE80211_IS_CHAN_FHSS(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_FHSS) == IEEE80211_CHAN_FHSS) +#define IEEE80211_IS_CHAN_A(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_A) == IEEE80211_CHAN_A) +#define IEEE80211_IS_CHAN_B(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_B) == IEEE80211_CHAN_B) +#define IEEE80211_IS_CHAN_PUREG(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_PUREG) == IEEE80211_CHAN_PUREG) +#define IEEE80211_IS_CHAN_G(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_G) == IEEE80211_CHAN_G) +#define IEEE80211_IS_CHAN_ANYG(_c) \ + (IEEE80211_IS_CHAN_PUREG(_c) || IEEE80211_IS_CHAN_G(_c)) +#define IEEE80211_IS_CHAN_ST(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_ST) == IEEE80211_CHAN_ST) +#define IEEE80211_IS_CHAN_108A(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_108A) == IEEE80211_CHAN_108A) +#define IEEE80211_IS_CHAN_108G(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_108G) == IEEE80211_CHAN_108G) + +#define IEEE80211_IS_CHAN_2GHZ(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_2GHZ) != 0) +#define IEEE80211_IS_CHAN_5GHZ(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_5GHZ) != 0) +#define IEEE80211_IS_CHAN_OFDM(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_OFDM) != 0) +#define IEEE80211_IS_CHAN_CCK(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_CCK) != 0) +#define IEEE80211_IS_CHAN_GFSK(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_GFSK) != 0) +#define IEEE80211_IS_CHAN_TURBO(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_TURBO) != 0) +#define IEEE80211_IS_CHAN_WEATHER_RADAR(_c) \ + ((((_c)->ic_freq >= 5600) && ((_c)->ic_freq <= 5650)) \ + || (((_c)->ic_flags & IEEE80211_CHAN_HT40PLUS) && (5580 == (_c)->ic_freq))) +#define IEEE80211_IS_CHAN_STURBO(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_STURBO) != 0) +#define IEEE80211_IS_CHAN_DTURBO(_c) \ + (((_c)->ic_flags & \ + (IEEE80211_CHAN_TURBO | IEEE80211_CHAN_STURBO)) == IEEE80211_CHAN_TURBO) +#define IEEE80211_IS_CHAN_HALF(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_HALF) != 0) +#define IEEE80211_IS_CHAN_QUARTER(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_QUARTER) != 0) +#define IEEE80211_IS_CHAN_PASSIVE(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_PASSIVE) != 0) + +#define IEEE80211_IS_CHAN_DFS(_c) \ + (((_c)->ic_flagext & (IEEE80211_CHAN_DFS|IEEE80211_CHAN_DFS_CLEAR)) == IEEE80211_CHAN_DFS) +#define IEEE80211_IS_CHAN_DFSFLAG(_c) \ + (((_c)->ic_flagext & IEEE80211_CHAN_DFS) == IEEE80211_CHAN_DFS) +#define IEEE80211_IS_CHAN_DISALLOW_ADHOC(_c) \ + (((_c)->ic_flagext & IEEE80211_CHAN_DISALLOW_ADHOC) != 0) +#define IEEE80211_IS_CHAN_11D_EXCLUDED(_c) \ + (((_c)->ic_flagext & IEEE80211_CHAN_11D_EXCLUDED) != 0) +#define IEEE80211_IS_CHAN_CSA(_c) \ + (((_c)->ic_flagext & IEEE80211_CHAN_CSA_RECEIVED) != 0) +#define IEEE80211_IS_CHAN_ODD(_c) \ + (((_c)->ic_freq == 5170) || ((_c)->ic_freq == 5190) || \ + ((_c)->ic_freq == 5210) || ((_c)->ic_freq == 5230)) +#define IEEE80211_IS_CHAN_DISALLOW_HOSTAP(_c) \ + (((_c)->ic_flagext & IEEE80211_CHAN_DISALLOW_HOSTAP) != 0) + +#define IEEE80211_IS_CHAN_11NG_HT20(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_11NG_HT20) == IEEE80211_CHAN_11NG_HT20) +#define IEEE80211_IS_CHAN_11NA_HT20(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_11NA_HT20) == IEEE80211_CHAN_11NA_HT20) +#define IEEE80211_IS_CHAN_11NG_HT40PLUS(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_11NG_HT40PLUS) == IEEE80211_CHAN_11NG_HT40PLUS) +#define IEEE80211_IS_CHAN_11NG_HT40MINUS(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_11NG_HT40MINUS) == IEEE80211_CHAN_11NG_HT40MINUS) +#define IEEE80211_IS_CHAN_11NA_HT40PLUS(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_11NA_HT40PLUS) == IEEE80211_CHAN_11NA_HT40PLUS) +#define IEEE80211_IS_CHAN_11NA_HT40MINUS(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_11NA_HT40MINUS) == IEEE80211_CHAN_11NA_HT40MINUS) + +#define IEEE80211_IS_CHAN_11N(_c) \ + (((_c)->ic_flags & (IEEE80211_CHAN_HT20 | IEEE80211_CHAN_HT40PLUS | IEEE80211_CHAN_HT40MINUS)) != 0) +#define IEEE80211_IS_CHAN_11N_HT20(_c) \ + (((_c)->ic_flags & (IEEE80211_CHAN_HT20)) != 0) +#define IEEE80211_IS_CHAN_11N_HT40(_c) \ + (((_c)->ic_flags & (IEEE80211_CHAN_HT40PLUS | IEEE80211_CHAN_HT40MINUS)) != 0) +#define IEEE80211_IS_CHAN_11NG(_c) \ + (IEEE80211_IS_CHAN_2GHZ((_c)) && IEEE80211_IS_CHAN_11N((_c))) +#define IEEE80211_IS_CHAN_11NA(_c) \ + (IEEE80211_IS_CHAN_5GHZ((_c)) && IEEE80211_IS_CHAN_11N((_c))) +#define IEEE80211_IS_CHAN_11N_HT40PLUS(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_HT40PLUS) != 0) +#define IEEE80211_IS_CHAN_11N_HT40MINUS(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_HT40MINUS) != 0) + +#define IEEE80211_IS_CHAN_HT20_CAPABLE(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_HT20) == IEEE80211_CHAN_HT20) +#define IEEE80211_IS_CHAN_HT40PLUS_CAPABLE(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_HT40PLUS) == IEEE80211_CHAN_HT40PLUS) +#define IEEE80211_IS_CHAN_HT40MINUS_CAPABLE(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_HT40MINUS) == IEEE80211_CHAN_HT40MINUS) +#define IEEE80211_IS_CHAN_HT40_CAPABLE(_c) \ + (IEEE80211_IS_CHAN_HT40PLUS_CAPABLE(_c) || IEEE80211_IS_CHAN_HT40MINUS_CAPABLE(_c)) +#define IEEE80211_IS_CHAN_HT_CAPABLE(_c) \ + (IEEE80211_IS_CHAN_HT20_CAPABLE(_c) || IEEE80211_IS_CHAN_HT40_CAPABLE(_c)) +#define IEEE80211_IS_CHAN_11N_CTL_CAPABLE(_c) IEEE80211_IS_CHAN_HT20_CAPABLE(_c) +#define IEEE80211_IS_CHAN_11N_CTL_U_CAPABLE(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_HT40PLUS) == IEEE80211_CHAN_HT40PLUS) +#define IEEE80211_IS_CHAN_11N_CTL_L_CAPABLE(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_HT40MINUS) == IEEE80211_CHAN_HT40MINUS) +#define IEEE80211_IS_CHAN_11N_CTL_40_CAPABLE(_c) \ + (IEEE80211_IS_CHAN_11N_CTL_U_CAPABLE((_c)) || IEEE80211_IS_CHAN_11N_CTL_L_CAPABLE((_c))) + +#define IEEE80211_IS_CHAN_VHT(_c) \ + (((_c)->ic_flags & (IEEE80211_CHAN_VHT20 | \ + IEEE80211_CHAN_VHT40PLUS | IEEE80211_CHAN_VHT40MINUS | IEEE80211_CHAN_VHT80)) != 0) +#define IEEE80211_IS_CHAN_11AC(_c) \ + ( IEEE80211_IS_CHAN_5GHZ((_c)) && IEEE80211_IS_CHAN_VHT((_c)) ) +#define IEEE80211_CHAN_11AC_VHT20 \ + (IEEE80211_CHAN_5GHZ | IEEE80211_CHAN_VHT20) +#define IEEE80211_CHAN_11AC_VHT40 \ + (IEEE80211_CHAN_5GHZ | IEEE80211_CHAN_VHT40PLUS | IEEE80211_CHAN_VHT40MINUS ) +#define IEEE80211_CHAN_11AC_VHT40PLUS \ + (IEEE80211_CHAN_5GHZ | IEEE80211_CHAN_VHT40PLUS) +#define IEEE80211_CHAN_11AC_VHT40MINUS \ + (IEEE80211_CHAN_5GHZ | IEEE80211_CHAN_VHT40MINUS) +#define IEEE80211_CHAN_11AC_VHT80 \ + (IEEE80211_CHAN_5GHZ | IEEE80211_CHAN_VHT80) +#define IEEE80211_IS_CHAN_11AC_VHT20(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_11AC_VHT20) == IEEE80211_CHAN_11AC_VHT20) + +#define IEEE80211_IS_CHAN_11AC_VHT40(_c) \ + (((_c)->ic_flags & (IEEE80211_CHAN_VHT40PLUS | IEEE80211_CHAN_VHT40MINUS)) !=0) +#define IEEE80211_IS_CHAN_11AC_VHT40PLUS(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_11AC_VHT40PLUS) == IEEE80211_CHAN_11AC_VHT40PLUS) +#define IEEE80211_IS_CHAN_11AC_VHT40MINUS(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_11AC_VHT40MINUS) == IEEE80211_CHAN_11AC_VHT40MINUS) +#define IEEE80211_IS_CHAN_11AC_VHT80(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_11AC_VHT80) == IEEE80211_CHAN_11AC_VHT80) + +#define IEEE80211_IS_CHAN_RADAR(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_RADAR_DFS) == IEEE80211_CHAN_RADAR_DFS) +#define IEEE80211_CHAN_SET_RADAR(_c) \ + ((_c)->ic_flags |= IEEE80211_CHAN_RADAR_DFS) +#define IEEE80211_CHAN_CLR_RADAR(_c) \ + ((_c)->ic_flags &= ~IEEE80211_CHAN_RADAR_DFS) +#define IEEE80211_CHAN_SET_DISALLOW_ADHOC(_c) \ + ((_c)->ic_flagext |= IEEE80211_CHAN_DISALLOW_ADHOC) +#define IEEE80211_CHAN_SET_DISALLOW_HOSTAP(_c) \ + ((_c)->ic_flagext |= IEEE80211_CHAN_DISALLOW_HOSTAP) +#define IEEE80211_CHAN_SET_DFS(_c) \ + ((_c)->ic_flagext |= IEEE80211_CHAN_DFS) +#define IEEE80211_CHAN_SET_DFS_CLEAR(_c) \ + ((_c)->ic_flagext |= IEEE80211_CHAN_DFS_CLEAR) +#define IEEE80211_CHAN_EXCLUDE_11D(_c) \ + ((_c)->ic_flagext |= IEEE80211_CHAN_11D_EXCLUDED) + +/* channel encoding for FH phy */ +#define IEEE80211_FH_CHANMOD 80 +#define IEEE80211_FH_CHAN(set,pat) (((set)-1)*IEEE80211_FH_CHANMOD+(pat)) +#define IEEE80211_FH_CHANSET(chan) ((chan)/IEEE80211_FH_CHANMOD+1) +#define IEEE80211_FH_CHANPAT(chan) ((chan)%IEEE80211_FH_CHANMOD) + +/* + * 802.11 rate set. + */ +#define IEEE80211_RATE_SIZE 8 /* 802.11 standard */ +#define IEEE80211_RATE_MAXSIZE 36 /* max rates we'll handle */ +#define IEEE80211_HT_RATE_SIZE 128 +#define IEEE80211_RATE_SINGLE_STREAM_MCS_MAX 7 /* MCS7 */ + +#define IEEE80211_RATE_MCS 0x8000 +#define IEEE80211_RATE_MCS_VAL 0x7FFF + +#define IEEE80211_RATE_IDX_ENTRY(val, idx) (((val&(0xff<<(idx*8)))>>(idx*8))) + +/* + * RSSI range + */ +#define IEEE80211_RSSI_MAX -10 /* in db */ +#define IEEE80211_RSSI_MIN -200 + +/* + * 11n A-MPDU & A-MSDU limits + */ +#define IEEE80211_AMPDU_LIMIT_MIN (1 * 1024) +#define IEEE80211_AMPDU_LIMIT_MAX (64 * 1024 - 1) +#define IEEE80211_AMPDU_LIMIT_DEFAULT IEEE80211_AMPDU_LIMIT_MAX +#define IEEE80211_AMPDU_SUBFRAME_MIN 2 +#define IEEE80211_AMPDU_SUBFRAME_MAX 64 +#define IEEE80211_AMPDU_SUBFRAME_DEFAULT 32 +#define IEEE80211_AMSDU_LIMIT_MAX 4096 +#define IEEE80211_RIFS_AGGR_DIV 10 +#define IEEE80211_MAX_AMPDU_MIN 0 +#define IEEE80211_MAX_AMPDU_MAX 3 + +/* + * 11ac A-MPDU limits + */ +#define IEEE80211_VHT_MAX_AMPDU_MIN 0 +#define IEEE80211_VHT_MAX_AMPDU_MAX 7 + +struct ieee80211_rateset { + uint8_t rs_nrates; + uint8_t rs_rates[IEEE80211_RATE_MAXSIZE]; +}; + +struct ieee80211_beacon_info { + uint8_t essid[IEEE80211_NWID_LEN + 1]; + uint8_t esslen; + uint8_t rssi_ctl_0; + uint8_t rssi_ctl_1; + uint8_t rssi_ctl_2; + int numchains; +}; + +#define IEEE80211_ADDR_LEN 6 /* size of 802.11 address */ + +struct ieee80211_ibss_peer_list { + uint8_t bssid[IEEE80211_ADDR_LEN]; +}; + +struct ieee80211_roam { + int8_t rssi11a; /* rssi thresh for 11a bss */ + int8_t rssi11b; /* for 11g sta in 11b bss */ + int8_t rssi11bOnly; /* for 11b sta */ + uint8_t pad1; + uint8_t rate11a; /* rate thresh for 11a bss */ + uint8_t rate11b; /* for 11g sta in 11b bss */ + uint8_t rate11bOnly; /* for 11b sta */ + uint8_t pad2; +}; + +#define IEEE80211_TID_SIZE 17 /* total number of TIDs */ +#define IEEE80211_NON_QOS_SEQ 16 /* index for non-QoS (including management) sequence number space */ +#define IEEE80211_SEQ_MASK 0xfff /* sequence generator mask */ +#define MIN_SW_SEQ 0x100 /* minimum sequence for SW generate packect */ + +/* crypto related defines*/ +#define IEEE80211_KEYBUF_SIZE 16 +#define IEEE80211_MICBUF_SIZE (8+8) /* space for both tx+rx keys */ + +enum ieee80211_clist_cmd { + CLIST_UPDATE, + CLIST_DFS_UPDATE, + CLIST_NEW_COUNTRY, + CLIST_NOL_UPDATE +}; + +enum ieee80211_nawds_param { + IEEE80211_NAWDS_PARAM_NUM = 0, + IEEE80211_NAWDS_PARAM_MODE, + IEEE80211_NAWDS_PARAM_DEFCAPS, + IEEE80211_NAWDS_PARAM_OVERRIDE, +}; + +struct ieee80211_mib_cycle_cnts { + uint32_t tx_frame_count; + uint32_t rx_frame_count; + uint32_t rx_clear_count; + uint32_t cycle_count; + uint8_t is_rx_active; + uint8_t is_tx_active; +}; + +struct ieee80211_chanutil_info { + uint32_t rx_clear_count; + uint32_t cycle_count; + uint8_t value; + uint32_t beacon_count; + uint8_t beacon_intervals; +}; + +#endif /* CDS_COMMON__IEEE80211_I_H_ */ diff --git a/drivers/staging/qcacld-3.0/core/cds/src/cds_mc_timer.c b/drivers/staging/qcacld-3.0/core/cds/src/cds_mc_timer.c new file mode 100644 index 0000000000000000000000000000000000000000..f46b95e4b298ed07e3ca62577fa820e6bcfe92a7 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/cds/src/cds_mc_timer.c @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2014-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: cds_mc_timer.c + * Connectivity driver services timer APIs + */ + +#include +#include "cds_mc_timer.h" +#include +#include +#include "cds_mq.h" + +/** + * cds_linux_timer_callback() - timer callback, gets called at time out. + * @data: unsigned long, holds the timer object. + * + * Return: None + */ +void cds_linux_timer_callback(unsigned long data) +{ + qdf_mc_timer_t *timer = (qdf_mc_timer_t *)data; + cds_msg_t msg; + QDF_STATUS status; + + qdf_mc_timer_callback_t callback = NULL; + void *user_data = NULL; + QDF_TIMER_TYPE type = QDF_TIMER_TYPE_SW; + + QDF_ASSERT(timer); + + if (timer == NULL) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s Null pointer passed in!", __func__); + return; + } + + qdf_spin_lock_irqsave(&timer->platform_info.spinlock); + + switch (timer->state) { + case QDF_TIMER_STATE_STARTING: + /* we are in this state because someone just started the timer, + * MC timer got started and expired, but the time content have + * not been updated this is a rare race condition! + */ + timer->state = QDF_TIMER_STATE_STOPPED; + status = QDF_STATUS_E_ALREADY; + break; + + case QDF_TIMER_STATE_STOPPED: + status = QDF_STATUS_E_ALREADY; + break; + + case QDF_TIMER_STATE_UNUSED: + status = QDF_STATUS_E_EXISTS; + break; + + case QDF_TIMER_STATE_RUNNING: + /* need to go to stop state here because the call-back function + * may restart timer (to emulate periodic timer) + */ + timer->state = QDF_TIMER_STATE_STOPPED; + /* copy the relevant timer information to local variables; + * once we exits from this critical section, the timer content + * may be modified by other tasks + */ + callback = timer->callback; + user_data = timer->user_data; + type = timer->type; + status = QDF_STATUS_SUCCESS; + break; + + default: + QDF_ASSERT(0); + status = QDF_STATUS_E_FAULT; + break; + } + + qdf_spin_unlock_irqrestore(&timer->platform_info.spinlock); + + if (QDF_STATUS_SUCCESS != status) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "TIMER callback called in a wrong state=%d", + timer->state); + return; + } + + qdf_try_allowing_sleep(type); + + if (callback == NULL) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: No TIMER callback, Could not enqueue timer to any queue", + __func__); + QDF_ASSERT(0); + return; + } + + /* serialize to the MC thread */ + sys_build_message_header(SYS_MSG_ID_MC_TIMER, &msg); + msg.callback = callback; + msg.bodyptr = user_data; + msg.bodyval = 0; + + if (cds_mq_post_message(CDS_MQ_ID_SYS, &msg) == QDF_STATUS_SUCCESS) + return; + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: Could not enqueue timer to any queue", __func__); + QDF_ASSERT(0); +} diff --git a/drivers/staging/qcacld-3.0/core/cds/src/cds_mq.c b/drivers/staging/qcacld-3.0/core/cds/src/cds_mq.c new file mode 100644 index 0000000000000000000000000000000000000000..44ead61444066885e76e9948d87f2c1e60a43c02 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/cds/src/cds_mq.c @@ -0,0 +1,239 @@ +/* + * Copyright (c) 2014-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: cds_mq.c + * + * Connectivity driver services (CDS) message queue APIs + * + * Message Queue Definitions and API + */ + +/* Include Files */ +#include +#include "cds_sched.h" +#include +#include "sir_types.h" + +/* Preprocessor definitions and constants */ + +/* Type declarations */ + +/* Function declarations and documenation */ + +tSirRetStatus u_mac_post_ctrl_msg(void *pSirGlobal, void *pMb); + +/** + * cds_mq_init() - initialize cds message queue + * @pMq: Pointer to the message queue + * + * This function initializes the Message queue. + * + * Return: qdf status + */ +inline QDF_STATUS cds_mq_init(p_cds_mq_type pMq) +{ + + if (pMq == NULL) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: NULL pointer passed", __func__); + return QDF_STATUS_E_FAILURE; + } + + /* Now initialize the lock */ + spin_lock_init(&pMq->mqLock); + + /* Now initialize the List data structure */ + INIT_LIST_HEAD(&pMq->mqList); + + return QDF_STATUS_SUCCESS; +} /* cds_mq_init() */ + +/** + * cds_mq_deinit() - de-initialize cds message queue + * @pMq: Pointer to the message queue + * + * This function de-initializes cds message queue + * + * Return: none + */ +inline void cds_mq_deinit(p_cds_mq_type pMq) +{ + if (pMq == NULL) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: NULL pointer passed", __func__); + return; + } + + /* we don't have to do anything with the embedded list or spinlock */ +} /* cds_mq_deinit() */ + +/** + * cds_mq_put() - add a message to the message queue + * @pMq: Pointer to the message queue + * @pMsgWrapper: Msg wrapper containing the message + * + * Return: none + */ +inline void cds_mq_put(p_cds_mq_type pMq, p_cds_msg_wrapper pMsgWrapper) +{ + unsigned long flags; + + if ((pMq == NULL) || (pMsgWrapper == NULL)) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: NULL pointer passed", __func__); + return; + } + + spin_lock_irqsave(&pMq->mqLock, flags); + + list_add_tail(&pMsgWrapper->msgNode, &pMq->mqList); + + spin_unlock_irqrestore(&pMq->mqLock, flags); + +} /* cds_mq_put() */ + +/** + * cds_mq_put_front() - adds a message to the head of message queue + * @mq: message queue + * @msg_wrapper: message wrapper + * + * This function is used to add a message to the head of message queue + * + * Return: None + */ +void cds_mq_put_front(p_cds_mq_type mq, p_cds_msg_wrapper msg_wrapper) +{ + unsigned long flags; + + if ((mq == NULL) || (msg_wrapper == NULL)) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: NULL pointer passed", __func__); + return; + } + + spin_lock_irqsave(&mq->mqLock, flags); + list_add(&msg_wrapper->msgNode, &mq->mqList); + spin_unlock_irqrestore(&mq->mqLock, flags); +} + +/** + * cds_mq_get() - get a message with its wrapper from a message queue + * @pMq: Pointer to the message queue + * + * Return: pointer to the message wrapper + */ +inline p_cds_msg_wrapper cds_mq_get(p_cds_mq_type pMq) +{ + p_cds_msg_wrapper pMsgWrapper = NULL; + + struct list_head *listptr; + unsigned long flags; + + if (pMq == NULL) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: NULL pointer passed", __func__); + return NULL; + } + + spin_lock_irqsave(&pMq->mqLock, flags); + + if (list_empty(&pMq->mqList)) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_WARN, + "%s: CDS Message Queue is empty", __func__); + } else { + listptr = pMq->mqList.next; + pMsgWrapper = + (p_cds_msg_wrapper) list_entry(listptr, cds_msg_wrapper, + msgNode); + list_del(pMq->mqList.next); + } + + spin_unlock_irqrestore(&pMq->mqLock, flags); + + return pMsgWrapper; + +} /* cds_mq_get() */ + +/** + * cds_is_mq_empty() - check if the message queue is empty + * @pMq: Pointer to the message queue + * + * Return: true if message queue is emtpy + * false otherwise + */ +inline bool cds_is_mq_empty(p_cds_mq_type pMq) +{ + bool state = false; + unsigned long flags; + + if (pMq == NULL) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: NULL pointer passed", __func__); + return QDF_STATUS_E_FAILURE; + } + + spin_lock_irqsave(&pMq->mqLock, flags); + state = list_empty(&pMq->mqList) ? true : false; + spin_unlock_irqrestore(&pMq->mqLock, flags); + + return state; +} /* cds_mq_get() */ + +/** + * cds_send_mb_message_to_mac() - post a message to a message queue + * @pBuf: Pointer to buffer allocated by caller + * + * Return: qdf status + */ +QDF_STATUS cds_send_mb_message_to_mac(void *pBuf) +{ + QDF_STATUS qdf_ret_status = QDF_STATUS_E_FAILURE; + tSirRetStatus sirStatus; + v_CONTEXT_t cds_context; + void *hHal; + + cds_context = cds_get_global_context(); + if (NULL == cds_context) { + QDF_TRACE(QDF_MODULE_ID_SYS, QDF_TRACE_LEVEL_ERROR, + "%s: invalid cds_context", __func__); + qdf_mem_free(pBuf); + } else { + hHal = cds_get_context(QDF_MODULE_ID_SME); + if (NULL == hHal) { + QDF_TRACE(QDF_MODULE_ID_SYS, QDF_TRACE_LEVEL_ERROR, + "%s: invalid hHal", __func__); + qdf_mem_free(pBuf); + } else { + sirStatus = u_mac_post_ctrl_msg(hHal, pBuf); + if (eSIR_SUCCESS == sirStatus) + qdf_ret_status = QDF_STATUS_SUCCESS; + } + } + + return qdf_ret_status; +} diff --git a/drivers/staging/qcacld-3.0/core/cds/src/cds_packet.c b/drivers/staging/qcacld-3.0/core/cds/src/cds_packet.c new file mode 100644 index 0000000000000000000000000000000000000000..b1d1191e513f6b1ded8c11907288b39ca9bf1613 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/cds/src/cds_packet.c @@ -0,0 +1,169 @@ +/* + * Copyright (c) 2014-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/**========================================================================= + + \file cds_packet.c + + \brief Connectivity driver services (CDS) network Packet APIs + + Network Protocol packet/buffer support interfaces + + ========================================================================*/ + +/*-------------------------------------------------------------------------- + Include Files + ------------------------------------------------------------------------*/ +#include +#include +#include +#include +#include +#include "qdf_nbuf.h" +#include "qdf_mem.h" + +#define TX_PKT_MIN_HEADROOM (64) + +/* Protocol specific packet tracking feature */ +#define CDS_PKT_TRAC_ETH_TYPE_OFFSET (12) +#define CDS_PKT_TRAC_IP_OFFSET (14) +#define CDS_PKT_TRAC_IP_HEADER_SIZE (20) +#define CDS_PKT_TRAC_DHCP_SRV_PORT (67) +#define CDS_PKT_TRAC_DHCP_CLI_PORT (68) +#define CDS_PKT_TRAC_EAPOL_ETH_TYPE (0x888E) + +/** + * cds_pkt_return_packet Free the cds Packet + * @ cds Packet + */ +QDF_STATUS cds_pkt_return_packet(cds_pkt_t *packet) +{ + /* Validate the input parameter pointer */ + if (unlikely(packet == NULL)) { + return QDF_STATUS_E_INVAL; + } + + /* Free up the qdf nbuf */ + qdf_nbuf_free(packet->pkt_buf); + + packet->pkt_buf = NULL; + + /* Free up the Rx packet */ + qdf_mem_free(packet); + + return QDF_STATUS_SUCCESS; +} + +/**-------------------------------------------------------------------------- + + \brief cds_pkt_get_packet_length() - Get packet length for a cds Packet + + This API returns the total length of the data in a cds Packet. + + \param pPacket - the cds Packet to get the packet length from. + + \param pPacketSize - location to return the total size of the data contained + in the cds Packet. + \return + + \sa + + ---------------------------------------------------------------------------*/ +QDF_STATUS +cds_pkt_get_packet_length(cds_pkt_t *pPacket, uint16_t *pPacketSize) +{ + /* Validate the parameter pointers */ + if (unlikely((pPacket == NULL) || (pPacketSize == NULL)) || + (pPacket->pkt_buf == NULL)) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_FATAL, + "VPKT [%d]: NULL pointer", __LINE__); + return QDF_STATUS_E_INVAL; + } + /* return the requested information */ + *pPacketSize = qdf_nbuf_len(pPacket->pkt_buf); + return QDF_STATUS_SUCCESS; +} + +#ifdef MEMORY_DEBUG +/*--------------------------------------------------------------------------- +* @brief cds_packet_alloc_debug() - + Allocate a network buffer for TX + ---------------------------------------------------------------------------*/ +QDF_STATUS cds_packet_alloc_debug(uint16_t size, void **data, void **ppPacket, + uint8_t *file_name, uint32_t line_num) +{ + QDF_STATUS qdf_ret_status = QDF_STATUS_E_FAILURE; + qdf_nbuf_t nbuf; + + nbuf = qdf_nbuf_alloc_debug(NULL, + roundup(size + TX_PKT_MIN_HEADROOM, 4), + TX_PKT_MIN_HEADROOM, sizeof(uint32_t), false, + file_name, line_num); + + if (nbuf != NULL) { + qdf_nbuf_put_tail(nbuf, size); + qdf_nbuf_set_protocol(nbuf, ETH_P_CONTROL); + *ppPacket = nbuf; + *data = qdf_nbuf_data(nbuf); + qdf_ret_status = QDF_STATUS_SUCCESS; + } + + return qdf_ret_status; +} +#else +/*--------------------------------------------------------------------------- +* @brief cds_packet_alloc() - + Allocate a network buffer for TX + ---------------------------------------------------------------------------*/ +QDF_STATUS cds_packet_alloc(uint16_t size, void **data, void **ppPacket) +{ + QDF_STATUS qdf_ret_status = QDF_STATUS_E_FAILURE; + qdf_nbuf_t nbuf; + + nbuf = qdf_nbuf_alloc(NULL, roundup(size + TX_PKT_MIN_HEADROOM, 4), + TX_PKT_MIN_HEADROOM, sizeof(uint32_t), false); + + if (nbuf != NULL) { + qdf_nbuf_put_tail(nbuf, size); + qdf_nbuf_set_protocol(nbuf, ETH_P_CONTROL); + *ppPacket = nbuf; + *data = qdf_nbuf_data(nbuf); + qdf_ret_status = QDF_STATUS_SUCCESS; + } + + return qdf_ret_status; +} + +#endif +/*--------------------------------------------------------------------------- +* @brief cds_packet_free() - + Free input network buffer + ---------------------------------------------------------------------------*/ +void cds_packet_free(void *pPacket) +{ + qdf_nbuf_free((qdf_nbuf_t) pPacket); +} diff --git a/drivers/staging/qcacld-3.0/core/cds/src/cds_reg_service.c b/drivers/staging/qcacld-3.0/core/cds/src/cds_reg_service.c new file mode 100644 index 0000000000000000000000000000000000000000..087764346801e398f1330c0088cdd2f625bd6e41 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/cds/src/cds_reg_service.c @@ -0,0 +1,769 @@ +/* + * Copyright (c) 2014-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/*============================================================================ + FILE: cds_reg_service.c + OVERVIEW: This source file contains definitions for CDS regulatory APIs + DEPENDENCIES: None + ============================================================================*/ + +#include +#include "qdf_types.h" +#include "qdf_trace.h" +#include "cds_api.h" +#include "cds_reg_service.h" +#include "cds_regdomain.h" +#include "sme_api.h" +#include "wlan_hdd_main.h" + +const struct chan_map chan_mapping[NUM_CHANNELS] = { + [CHAN_ENUM_1] = {2412, 1}, + [CHAN_ENUM_2] = {2417, 2}, + [CHAN_ENUM_3] = {2422, 3}, + [CHAN_ENUM_4] = {2427, 4}, + [CHAN_ENUM_5] = {2432, 5}, + [CHAN_ENUM_6] = {2437, 6}, + [CHAN_ENUM_7] = {2442, 7}, + [CHAN_ENUM_8] = {2447, 8}, + [CHAN_ENUM_9] = {2452, 9}, + [CHAN_ENUM_10] = {2457, 10}, + [CHAN_ENUM_11] = {2462, 11}, + [CHAN_ENUM_12] = {2467, 12}, + [CHAN_ENUM_13] = {2472, 13}, + [CHAN_ENUM_14] = {2484, 14}, + + [CHAN_ENUM_36] = {5180, 36}, + [CHAN_ENUM_40] = {5200, 40}, + [CHAN_ENUM_44] = {5220, 44}, + [CHAN_ENUM_48] = {5240, 48}, + [CHAN_ENUM_52] = {5260, 52}, + [CHAN_ENUM_56] = {5280, 56}, + [CHAN_ENUM_60] = {5300, 60}, + [CHAN_ENUM_64] = {5320, 64}, + + [CHAN_ENUM_100] = {5500, 100}, + [CHAN_ENUM_104] = {5520, 104}, + [CHAN_ENUM_108] = {5540, 108}, + [CHAN_ENUM_112] = {5560, 112}, + [CHAN_ENUM_116] = {5580, 116}, + [CHAN_ENUM_120] = {5600, 120}, + [CHAN_ENUM_124] = {5620, 124}, + [CHAN_ENUM_128] = {5640, 128}, + [CHAN_ENUM_132] = {5660, 132}, + [CHAN_ENUM_136] = {5680, 136}, + [CHAN_ENUM_140] = {5700, 140}, + [CHAN_ENUM_144] = {5720, 144}, + + [CHAN_ENUM_149] = {5745, 149}, + [CHAN_ENUM_153] = {5765, 153}, + [CHAN_ENUM_157] = {5785, 157}, + [CHAN_ENUM_161] = {5805, 161}, + [CHAN_ENUM_165] = {5825, 165}, + + [CHAN_ENUM_170] = {5852, 170}, + [CHAN_ENUM_171] = {5855, 171}, + [CHAN_ENUM_172] = {5860, 172}, + [CHAN_ENUM_173] = {5865, 173}, + [CHAN_ENUM_174] = {5870, 174}, + [CHAN_ENUM_175] = {5875, 175}, + [CHAN_ENUM_176] = {5880, 176}, + [CHAN_ENUM_177] = {5885, 177}, + [CHAN_ENUM_178] = {5890, 178}, + [CHAN_ENUM_179] = {5895, 179}, + [CHAN_ENUM_180] = {5900, 180}, + [CHAN_ENUM_181] = {5905, 181}, + [CHAN_ENUM_182] = {5910, 182}, + [CHAN_ENUM_183] = {5915, 183}, + [CHAN_ENUM_184] = {5920, 184}, +}; + +/** + * struct bonded_chan + * @start_ch: start channel + * @end_ch: end channel + */ +struct bonded_chan { + uint16_t start_ch; + uint16_t end_ch; +}; + +static const struct bonded_chan bonded_chan_40mhz_array[] = { + {36, 40}, + {44, 48}, + {52, 56}, + {60, 64}, + {100, 104}, + {108, 112}, + {116, 120}, + {124, 128}, + {132, 136}, + {140, 144}, + {149, 153}, + {157, 161} +}; + +static const struct bonded_chan bonded_chan_80mhz_array[] = { + {36, 48}, + {52, 64}, + {100, 112}, + {116, 128}, + {132, 144}, + {149, 161} +}; + +static const struct bonded_chan bonded_chan_160mhz_array[] = { + {36, 64}, + {100, 128} +}; + +static const enum phy_ch_width next_lower_bw[] = { + [CH_WIDTH_80P80MHZ] = CH_WIDTH_160MHZ, + [CH_WIDTH_160MHZ] = CH_WIDTH_80MHZ, + [CH_WIDTH_80MHZ] = CH_WIDTH_40MHZ, + [CH_WIDTH_40MHZ] = CH_WIDTH_20MHZ, + [CH_WIDTH_20MHZ] = CH_WIDTH_10MHZ, + [CH_WIDTH_10MHZ] = CH_WIDTH_5MHZ, + [CH_WIDTH_5MHZ] = CH_WIDTH_INVALID +}; + +struct regulatory_channel reg_channels[NUM_CHANNELS]; +static uint8_t default_country[CDS_COUNTRY_CODE_LEN + 1]; +static enum dfs_region dfs_region; + +/** + * cds_get_channel_list_with_power() - retrieve channel list with power + * @base_channels: base channels + * @num_base_channels: number of base channels + * + * Return: QDF_STATUS_SUCCESS + */ +QDF_STATUS cds_get_channel_list_with_power(struct channel_power + *base_channels, + uint8_t *num_base_channels) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + int i, count; + + if (base_channels && num_base_channels) { + count = 0; + for (i = 0; i < NUM_CHANNELS; i++) { + if (reg_channels[i].state) { + base_channels[count].chan_num = + chan_mapping[i].chan_num; + base_channels[count++].power = + reg_channels[i].pwr_limit; + } + } + *num_base_channels = count; + } + + return status; +} + +/** + * cds_read_default_country() - set the default country + * @def_ctry: default country + * + * Return: QDF_STATUS + */ +QDF_STATUS cds_read_default_country(uint8_t *def_ctry) +{ + memcpy(def_ctry, + default_country, + CDS_COUNTRY_CODE_LEN + 1); + + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO, + "default country is %c%c\n", + def_ctry[0], + def_ctry[1]); + + return QDF_STATUS_SUCCESS; +} + +enum channel_enum cds_get_channel_enum(uint32_t chan_num) +{ + uint32_t loop; + + for (loop = 0; loop <= CHAN_ENUM_184; loop++) + if (chan_mapping[loop].chan_num == chan_num) + return loop; + + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "invalid channel number %d", chan_num); + + return INVALID_CHANNEL; +} + + +/** + * cds_get_channel_state() - get the channel state + * @chan_num: channel number + * + * Return: channel state + */ +enum channel_state cds_get_channel_state(uint32_t chan_num) +{ + enum channel_enum chan_enum; + + chan_enum = cds_get_channel_enum(chan_num); + if (INVALID_CHANNEL == chan_enum) + return CHANNEL_STATE_INVALID; + else + return reg_channels[chan_enum].state; +} + + +/** + * cds_search_5g_bonded_chan_array() - get ptr to bonded channel + * @oper_ch: operating channel number + * @bonded_chan_ar: bonded channel array + * @bonded_chan_ptr_ptr: bonded channel ptr ptr + * + * Return: bonded channel state + */ +static enum channel_state cds_search_5g_bonded_chan_array(uint32_t oper_chan, + const struct bonded_chan + bonded_chan_ar[], + uint16_t array_size, + const struct bonded_chan + **bonded_chan_ptr_ptr) +{ + int i; + uint8_t chan_num; + const struct bonded_chan *bonded_chan_ptr = NULL; + enum channel_state chan_state = CHANNEL_STATE_INVALID; + enum channel_state temp_chan_state; + + for (i = 0; i < array_size; i++) { + if ((oper_chan >= bonded_chan_ar[i].start_ch) && + (oper_chan <= bonded_chan_ar[i].end_ch)) { + bonded_chan_ptr = &(bonded_chan_ar[i]); + break; + } + } + + if (NULL == bonded_chan_ptr) + return chan_state; + + *bonded_chan_ptr_ptr = bonded_chan_ptr; + chan_num = bonded_chan_ptr->start_ch; + while (chan_num <= bonded_chan_ptr->end_ch) { + temp_chan_state = cds_get_channel_state(chan_num); + if (temp_chan_state < chan_state) + chan_state = temp_chan_state; + chan_num = chan_num + 4; + } + + return chan_state; +} + +/** + * cds_search_5g_bonded_channel() - get the 5G bonded channel state + * @chan_num: channel number + * @ch_width: channel width + * @bonded_chan_ptr_ptr: bonded channel ptr ptr + * + * Return: channel state + */ +static enum channel_state cds_search_5g_bonded_channel(uint32_t chan_num, + enum phy_ch_width ch_width, + const struct bonded_chan + **bonded_chan_ptr_ptr) +{ + + if (CH_WIDTH_80P80MHZ == ch_width) + return cds_search_5g_bonded_chan_array(chan_num, + bonded_chan_80mhz_array, + QDF_ARRAY_SIZE(bonded_chan_80mhz_array), + bonded_chan_ptr_ptr); + else if (CH_WIDTH_160MHZ == ch_width) + return cds_search_5g_bonded_chan_array(chan_num, + bonded_chan_160mhz_array, + QDF_ARRAY_SIZE(bonded_chan_160mhz_array), + bonded_chan_ptr_ptr); + else if (CH_WIDTH_80MHZ == ch_width) + return cds_search_5g_bonded_chan_array(chan_num, + bonded_chan_80mhz_array, + QDF_ARRAY_SIZE(bonded_chan_80mhz_array), + bonded_chan_ptr_ptr); + else if (CH_WIDTH_40MHZ == ch_width) + return cds_search_5g_bonded_chan_array(chan_num, + bonded_chan_40mhz_array, + QDF_ARRAY_SIZE(bonded_chan_40mhz_array), + bonded_chan_ptr_ptr); + else + return cds_get_channel_state(chan_num); +} + +/** + * cds_get_2g_bonded_channel_state() - get the 2G bonded channel state + * @oper_ch: operating channel + * @ch_width: channel width + * @sec_ch: secondary channel + * + * Return: channel state + */ +enum channel_state cds_get_2g_bonded_channel_state(uint16_t oper_ch, + enum phy_ch_width ch_width, + uint16_t sec_ch) +{ + enum channel_enum chan_enum; + enum channel_state chan_state; + bool bw_enabled = false; + enum channel_state chan_state2 = CHANNEL_STATE_INVALID; + + if (CH_WIDTH_40MHZ < ch_width) + return CHANNEL_STATE_INVALID; + + if (CH_WIDTH_40MHZ == ch_width) { + if ((sec_ch + 4 != oper_ch) && + (oper_ch + 4 != sec_ch)) + return CHANNEL_STATE_INVALID; + chan_state2 = cds_get_channel_state(sec_ch); + if (CHANNEL_STATE_INVALID == chan_state2) + return chan_state2; + } + + chan_state = cds_get_channel_state(oper_ch); + if (chan_state2 < chan_state) + chan_state = chan_state2; + + if ((CHANNEL_STATE_INVALID == chan_state) || + (CHANNEL_STATE_DISABLE == chan_state)) + return chan_state; + + chan_enum = cds_get_channel_enum(oper_ch); + if (CH_WIDTH_5MHZ == ch_width) + bw_enabled = true; + else if (CH_WIDTH_10MHZ == ch_width) + bw_enabled = !(reg_channels[chan_enum].flags & + IEEE80211_CHAN_NO_10MHZ); + else if (CH_WIDTH_20MHZ == ch_width) + bw_enabled = !(reg_channels[chan_enum].flags & + IEEE80211_CHAN_NO_20MHZ); + else if (CH_WIDTH_40MHZ == ch_width) + bw_enabled = !((reg_channels[chan_enum].flags & + IEEE80211_CHAN_NO_HT40) == IEEE80211_CHAN_NO_HT40); + + if (bw_enabled) + return chan_state; + else + return CHANNEL_STATE_DISABLE; +} + +/** + * cds_get_5g_bonded_channel_state() - get the 5G bonded channel state + * @chan_num: channel number + * @ch_width: channel width + * + * Return: channel state + */ +enum channel_state cds_get_5g_bonded_channel_state( + uint16_t chan_num, + enum phy_ch_width ch_width) +{ + enum channel_enum chan_enum; + enum channel_state chan_state; + bool bw_enabled = false; + const struct bonded_chan *bonded_chan_ptr = NULL; + + if (CH_WIDTH_80P80MHZ < ch_width) + return CHANNEL_STATE_INVALID; + + chan_state = cds_search_5g_bonded_channel(chan_num, ch_width, + &bonded_chan_ptr); + + if ((CHANNEL_STATE_INVALID == chan_state) || + (CHANNEL_STATE_DISABLE == chan_state)) + return chan_state; + + chan_enum = cds_get_channel_enum(chan_num); + if (CH_WIDTH_5MHZ == ch_width) + bw_enabled = true; + else if (CH_WIDTH_10MHZ == ch_width) + bw_enabled = !(reg_channels[chan_enum].flags & + IEEE80211_CHAN_NO_10MHZ); + else if (CH_WIDTH_20MHZ == ch_width) + bw_enabled = !(reg_channels[chan_enum].flags & + IEEE80211_CHAN_NO_20MHZ); + else if (CH_WIDTH_40MHZ == ch_width) + bw_enabled = !((reg_channels[chan_enum].flags & + IEEE80211_CHAN_NO_HT40) == IEEE80211_CHAN_NO_HT40); + else if (CH_WIDTH_80MHZ == ch_width) + bw_enabled = !(reg_channels[chan_enum].flags & + IEEE80211_CHAN_NO_80MHZ); + else if (CH_WIDTH_160MHZ == ch_width) + bw_enabled = !(reg_channels[chan_enum].flags & + IEEE80211_CHAN_NO_160MHZ); + else if (CH_WIDTH_80P80MHZ == ch_width) + bw_enabled = !(reg_channels[chan_enum].flags & + IEEE80211_CHAN_NO_80MHZ); + + if (bw_enabled) + return chan_state; + else + return CHANNEL_STATE_DISABLE; +} + +/** + * cds_combine_channel_states() - combine channel states + * @chan_state1: channel state1 + * @chan_state2: channel state2 + * + * Return: enum channel_state + */ + static enum channel_state cds_combine_channel_states( + enum channel_state chan_state1, + enum channel_state chan_state2) +{ + if ((CHANNEL_STATE_INVALID == chan_state1) || + (CHANNEL_STATE_INVALID == chan_state2)) + return CHANNEL_STATE_INVALID; + else + return min(chan_state1, chan_state2); +} + +/** + * cds_set_5g_channel_params() - set the 5G bonded channel parameters + * @oper_ch: opetrating channel + * @ch_params: channel parameters + * + * Return: void + */ +static void cds_set_5g_channel_params(uint16_t oper_ch, + struct ch_params_s *ch_params) +{ + enum channel_state chan_state = CHANNEL_STATE_ENABLE; + enum channel_state chan_state2 = CHANNEL_STATE_ENABLE; + const struct bonded_chan *bonded_chan_ptr = NULL; + const struct bonded_chan *bonded_chan_ptr2 = NULL; + + if (CH_WIDTH_MAX <= ch_params->ch_width) { + if (0 != ch_params->center_freq_seg1) + ch_params->ch_width = CH_WIDTH_80P80MHZ; + else + ch_params->ch_width = CH_WIDTH_160MHZ; + } + + while (ch_params->ch_width != CH_WIDTH_INVALID) { + bonded_chan_ptr = NULL; + bonded_chan_ptr2 = NULL; + chan_state = cds_search_5g_bonded_channel(oper_ch, + ch_params->ch_width, + &bonded_chan_ptr); + + chan_state = cds_get_5g_bonded_channel_state(oper_ch, + ch_params->ch_width); + + if (CH_WIDTH_80P80MHZ == ch_params->ch_width) { + chan_state2 = cds_get_5g_bonded_channel_state( + ch_params->center_freq_seg1 - 2, + CH_WIDTH_80MHZ); + + chan_state = cds_combine_channel_states(chan_state, + chan_state2); + } + + if ((CHANNEL_STATE_ENABLE == chan_state) || + (CHANNEL_STATE_DFS == chan_state)) { + if (CH_WIDTH_20MHZ >= ch_params->ch_width) { + ch_params->sec_ch_offset + = PHY_SINGLE_CHANNEL_CENTERED; + ch_params->center_freq_seg0 = oper_ch; + break; + } else if (CH_WIDTH_40MHZ <= ch_params->ch_width) { + cds_search_5g_bonded_chan_array(oper_ch, + bonded_chan_40mhz_array, + QDF_ARRAY_SIZE(bonded_chan_40mhz_array), + &bonded_chan_ptr2); + if (bonded_chan_ptr && bonded_chan_ptr2) { + if (oper_ch == + bonded_chan_ptr2->start_ch) + ch_params->sec_ch_offset = + PHY_DOUBLE_CHANNEL_LOW_PRIMARY; + else + ch_params->sec_ch_offset = + PHY_DOUBLE_CHANNEL_HIGH_PRIMARY; + + ch_params->center_freq_seg0 = + (bonded_chan_ptr->start_ch + + bonded_chan_ptr->end_ch)/2; + break; + } + } + } + ch_params->ch_width = next_lower_bw[ch_params->ch_width]; + } + if (CH_WIDTH_160MHZ == ch_params->ch_width) { + ch_params->center_freq_seg1 = ch_params->center_freq_seg0; + chan_state = cds_search_5g_bonded_channel(oper_ch, + CH_WIDTH_80MHZ, + &bonded_chan_ptr); + if (bonded_chan_ptr) + ch_params->center_freq_seg0 = + (bonded_chan_ptr->start_ch + + bonded_chan_ptr->end_ch)/2; + } + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO, + "ch %d ch_wd %d freq0 %d freq1 %d", oper_ch, + ch_params->ch_width, ch_params->center_freq_seg0, + ch_params->center_freq_seg1); +} + +/** + * cds_set_2g_channel_params() - set the 2.4G bonded channel parameters + * @oper_ch: operating channel + * @ch_params: channel parameters + * @sec_ch_2g: 2.4G secondary channel + * + * Return: void + */ +static void cds_set_2g_channel_params(uint16_t oper_ch, + struct ch_params_s *ch_params, + uint16_t sec_ch_2g) +{ + enum channel_state chan_state = CHANNEL_STATE_ENABLE; + + if (CH_WIDTH_MAX <= ch_params->ch_width) + ch_params->ch_width = CH_WIDTH_40MHZ; + + if ((cds_bw_value(ch_params->ch_width) > 20) && !sec_ch_2g) { + if (oper_ch >= 1 && oper_ch <= 5) + sec_ch_2g = oper_ch + 4; + else if (oper_ch >= 6 && oper_ch <= 13) + sec_ch_2g = oper_ch - 4; + } + + while (ch_params->ch_width != CH_WIDTH_INVALID) { + chan_state = cds_get_2g_bonded_channel_state(oper_ch, + ch_params->ch_width, + sec_ch_2g); + if (CHANNEL_STATE_ENABLE == chan_state) { + if (CH_WIDTH_40MHZ == ch_params->ch_width) { + if (oper_ch < sec_ch_2g) + ch_params->sec_ch_offset = + PHY_DOUBLE_CHANNEL_LOW_PRIMARY; + else + ch_params->sec_ch_offset = + PHY_DOUBLE_CHANNEL_HIGH_PRIMARY; + ch_params->center_freq_seg0 = + (oper_ch + sec_ch_2g)/2; + } else + ch_params->sec_ch_offset = + PHY_SINGLE_CHANNEL_CENTERED; + break; + } + + ch_params->ch_width = next_lower_bw[ch_params->ch_width]; + } +} + +/** + * cds_set_channel_params() - set the bonded channel parameters + * @oper_ch: operating channel + * @sec_ch_2g: 2.4G secondary channel + * @ch_params: chanel parameters + * + * Return: void + */ +void cds_set_channel_params(uint16_t oper_ch, uint16_t sec_ch_2g, + struct ch_params_s *ch_params) +{ + if (CDS_IS_CHANNEL_5GHZ(oper_ch)) + cds_set_5g_channel_params(oper_ch, ch_params); + else if (CDS_IS_CHANNEL_24GHZ(oper_ch)) + cds_set_2g_channel_params(oper_ch, ch_params, sec_ch_2g); +} + +/** + * cds_get_dfs_region() - get the dfs_region + * @dfs_region: the dfs_region to return + * + * Return: QDF_STATUS + */ +QDF_STATUS cds_get_dfs_region(enum dfs_region *dfs_reg) +{ + *dfs_reg = dfs_region; + + return QDF_STATUS_SUCCESS; +} + +/** + * cds_get_reg_domain_from_country_code() - get the regulatory domain + * @reg_domain_ptr: ptr to store regulatory domain + * + * Return: QDF_STATUS_SUCCESS on success + * QDF_STATUS_E_FAULT on error + * QDF_STATUS_E_EMPTY country table empty + */ +QDF_STATUS cds_get_reg_domain_from_country_code(v_REGDOMAIN_t *reg_domain_ptr, + const uint8_t *country_alpha2, + enum country_src source) +{ + if (NULL == reg_domain_ptr) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "Invalid reg domain pointer"); + return QDF_STATUS_E_FAULT; + } + + *reg_domain_ptr = 0; + + if (SOURCE_QUERY == source) + return QDF_STATUS_SUCCESS; + + if (NULL == country_alpha2) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "Country code array is NULL"); + return QDF_STATUS_E_FAULT; + } + + if (cds_is_driver_recovering()) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "SSR in progress, return"); + return QDF_STATUS_SUCCESS; + } + + if (SOURCE_11D == source || SOURCE_USERSPACE == source) + regulatory_hint_user(country_alpha2, + NL80211_USER_REG_HINT_USER); + + return QDF_STATUS_SUCCESS; +} + +/** + * cds_is_fcc_regdomian() - is the regdomain FCC + * + * Return: true on FCC regdomain, false otherwise + */ +bool cds_is_fcc_regdomain(void) +{ + v_REGDOMAIN_t domainId; + hdd_context_t *hdd_ctx; + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (wlan_hdd_validate_context(hdd_ctx)) + return false; + cds_get_reg_domain_from_country_code(&domainId, + hdd_ctx->reg.alpha2, SOURCE_QUERY); + if (REGDOMAIN_FCC == domainId) + return true; + return false; +} + +/* + * cds_is_dsrc_channel() - is the channel DSRC + * @center_freq: center freq of the channel + * + * Return: true if dsrc channel + * false otherwise + */ +bool cds_is_dsrc_channel(uint16_t center_freq) +{ + if (center_freq >= 5852 && + center_freq <= 5920) + return true; + + return false; +} + +/** + * cds_set_reg_domain() - set regulatory domain + * @client_ctxt: client context + * @reg_domain: regulatory domain + * + * Return: QDF_STATUS + */ +QDF_STATUS cds_set_reg_domain(void *client_ctxt, v_REGDOMAIN_t reg_domain) +{ + if (reg_domain >= REGDOMAIN_COUNT) { + QDF_TRACE(QDF_MODULE_ID_QDF_DEVICE, QDF_TRACE_LEVEL_ERROR, + "CDS set reg domain, invalid REG domain ID %d", + reg_domain); + return QDF_STATUS_E_INVAL; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * cds_put_dfs_region() - save dfs region + * @dfs_reg: dfs region + * + * Return: QDF_STATUS + */ +QDF_STATUS cds_put_dfs_region(enum dfs_region dfs_reg) +{ + dfs_region = dfs_reg; + + return QDF_STATUS_SUCCESS; +} + +/** + * cds_put_default_country() - save the default country + * @dfs_country: default country + * + * Return: QDF_STATUS + */ +QDF_STATUS cds_put_default_country(uint8_t *def_country) +{ + default_country[0] = def_country[0]; + default_country[1] = def_country[1]; + + return QDF_STATUS_SUCCESS; +} + +/** + * cds_bw_value() - give bandwidth value + * bw: bandwidth enum + * + * Return: uint16_t + */ +uint16_t cds_bw_value(enum phy_ch_width bw) +{ + switch (bw) { + case CH_WIDTH_20MHZ: + return 20; + case CH_WIDTH_40MHZ: + return 40; + case CH_WIDTH_80MHZ: + return 80; + case CH_WIDTH_160MHZ: + return 160; + case CH_WIDTH_80P80MHZ: + return 160; + case CH_WIDTH_INVALID: + return 0; + case CH_WIDTH_5MHZ: + return 10; + case CH_WIDTH_10MHZ: + return 5; + case CH_WIDTH_MAX: + return 160; + default: + return 0; + } +} diff --git a/drivers/staging/qcacld-3.0/core/cds/src/cds_regdomain.c b/drivers/staging/qcacld-3.0/core/cds/src/cds_regdomain.c new file mode 100644 index 0000000000000000000000000000000000000000..b109790df84bd29d2d2a2c79e4172af4b58e172f --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/cds/src/cds_regdomain.c @@ -0,0 +1,901 @@ +/* + * Copyright (c) 2011,2013-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * Notifications and licenses are retained for attribution purposes only. + */ +/* + * Copyright (c) 2002-2006 Sam Leffler, Errno Consulting + * Copyright (c) 2005-2006 Atheros Communications, Inc. + * Copyright (c) 2010, Atheros Communications Inc. + * + * Redistribution and use in source and binary forms are permitted + * provided that the following conditions are met: + * 1. The materials contained herein are unmodified and are used + * unmodified. + * 2. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following NO + * ''WARRANTY'' disclaimer below (''Disclaimer''), without + * modification. + * 3. Redistributions in binary form must reproduce at minimum a + * disclaimer similar to the Disclaimer below and any redistribution + * must be conditioned upon including a substantially similar + * Disclaimer requirement for further binary redistribution. + * 4. Neither the names of the above-listed copyright holders nor the + * names of any contributors may be used to endorse or promote + * product derived from this software without specific prior written + * permission. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, + * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE + * FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGES. + */ + +#include "qdf_types.h" +#include "wma.h" +#include "cds_regdomain.h" + +static struct reg_dmn_supp_op_classes reg_dmn_curr_supp_opp_classes = { 0 }; + +static const struct reg_dmn_op_class_map_t global_op_class[] = { + {81, 25, BW20, {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13} }, + {82, 25, BW20, {14} }, + {83, 40, BW40_LOW_PRIMARY, {1, 2, 3, 4, 5, 6, 7, 8, 9} }, + {84, 40, BW40_HIGH_PRIMARY, {5, 6, 7, 8, 9, 10, 11, 12, 13} }, + {115, 20, BW20, {36, 40, 44, 48} }, + {116, 40, BW40_LOW_PRIMARY, {36, 44} }, + {117, 40, BW40_HIGH_PRIMARY, {40, 48} }, + {118, 20, BW20, {52, 56, 60, 64} }, + {119, 40, BW40_LOW_PRIMARY, {52, 60} }, + {120, 40, BW40_HIGH_PRIMARY, {56, 64} }, + {121, 20, BW20, + {100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140} }, + {122, 40, BW40_LOW_PRIMARY, {100, 108, 116, 124, 132} }, + {123, 40, BW40_HIGH_PRIMARY, {104, 112, 120, 128, 136} }, + {125, 20, BW20, {149, 153, 157, 161, 165, 169} }, + {126, 40, BW40_LOW_PRIMARY, {149, 157} }, + {127, 40, BW40_HIGH_PRIMARY, {153, 161} }, + {128, 80, BW80, {36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, + 112, 116, 120, 124, 128, 132, 136, 140, 144, + 149, 153, 157, 161} }, + {0, 0, 0, {0} }, +}; + +static const struct reg_dmn_op_class_map_t us_op_class[] = { + {1, 20, BW20, {36, 40, 44, 48} }, + {2, 20, BW20, {52, 56, 60, 64} }, + {4, 20, BW20, {100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, + 144} }, + {5, 20, BW20, {149, 153, 157, 161, 165} }, + {12, 25, BW20, {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11} }, + {22, 40, BW40_LOW_PRIMARY, {36, 44} }, + {23, 40, BW40_LOW_PRIMARY, {52, 60} }, + {24, 40, BW40_LOW_PRIMARY, {100, 108, 116, 124, 132} }, + {26, 40, BW40_LOW_PRIMARY, {149, 157} }, + {27, 40, BW40_HIGH_PRIMARY, {40, 48} }, + {28, 40, BW40_HIGH_PRIMARY, {56, 64} }, + {29, 40, BW40_HIGH_PRIMARY, {104, 112, 120, 128, 136} }, + {31, 40, BW40_HIGH_PRIMARY, {153, 161} }, + {32, 40, BW40_LOW_PRIMARY, {1, 2, 3, 4, 5, 6, 7} }, + {33, 40, BW40_HIGH_PRIMARY, {5, 6, 7, 8, 9, 10, 11} }, + {128, 80, BW80, {36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, + 112, 116, 120, 124, 128, 132, 136, 140, 144, + 149, 153, 157, 161} }, + {0, 0, 0, {0} }, +}; + +static const struct reg_dmn_op_class_map_t euro_op_class[] = { + {1, 20, BW20, {36, 40, 44, 48} }, + {2, 20, BW20, {52, 56, 60, 64} }, + {3, 20, BW20, {100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140} }, + {4, 25, BW20, {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13} }, + {5, 40, BW40_LOW_PRIMARY, {36, 44} }, + {6, 40, BW40_LOW_PRIMARY, {52, 60} }, + {7, 40, BW40_LOW_PRIMARY, {100, 108, 116, 124, 132} }, + {8, 40, BW40_HIGH_PRIMARY, {40, 48} }, + {9, 40, BW40_HIGH_PRIMARY, {56, 64} }, + {10, 40, BW40_HIGH_PRIMARY, {104, 112, 120, 128, 136} }, + {11, 40, BW40_LOW_PRIMARY, {1, 2, 3, 4, 5, 6, 7, 8, 9} }, + {12, 40, BW40_HIGH_PRIMARY, {5, 6, 7, 8, 9, 10, 11, 12, 13} }, + {17, 20, BW20, {149, 153, 157, 161, 165, 169} }, + {128, 80, BW80, {36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, + 116, 120, 124, 128} }, + {0, 0, 0, {0} }, +}; + +static const struct reg_dmn_op_class_map_t japan_op_class[] = { + {1, 20, BW20, {36, 40, 44, 48} }, + {30, 25, BW20, {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13} }, + {31, 25, BW20, {14} }, + {32, 20, BW20, {52, 56, 60, 64} }, + {34, 20, BW20, + {100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140} }, + {36, 40, BW40_LOW_PRIMARY, {36, 44} }, + {37, 40, BW40_LOW_PRIMARY, {52, 60} }, + {39, 40, BW40_LOW_PRIMARY, {100, 108, 116, 124, 132} }, + {41, 40, BW40_HIGH_PRIMARY, {40, 48} }, + {42, 40, BW40_HIGH_PRIMARY, {56, 64} }, + {44, 40, BW40_HIGH_PRIMARY, {104, 112, 120, 128, 136} }, + {128, 80, BW80, {36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, + 116, 120, 124, 128} }, + {0, 0, 0, {0} }, +}; + +static const struct reg_dmn_pair g_reg_dmn_pairs[] = { + {NO_ENUMRD, FCC8, FCCA, CTRY_DEFAULT}, + {NULL1_WORLD, NULL1, WORLD, CTRY_DEFAULT}, + {FCC1_FCCA, FCC1, FCCA, CTRY_DEFAULT}, + {FCC1_WORLD, FCC1, WORLD, CTRY_DEFAULT}, + {FCC2_WORLD, FCC2, WORLD, CTRY_DEFAULT}, + {FCC2_ETSIC, FCC2, ETSIC, CTRY_DEFAULT}, + {FCC3_FCCA, FCC3, FCCA, CTRY_DEFAULT}, + {FCC3_WORLD, FCC3, WORLD, CTRY_DEFAULT}, + {FCC3_ETSIC, FCC3, ETSIC, CTRY_DEFAULT}, + {FCC4_FCCA, FCC4, FCCA, CTRY_DEFAULT}, + {FCC5_FCCA, FCC5, FCCA, CTRY_DEFAULT}, + {FCC6_FCCA, FCC6, FCCA, CTRY_DEFAULT}, + {FCC7_FCCA, FCC7, FCCA, CTRY_DEFAULT}, + {FCC8_FCCA, FCC8, FCCA, CTRY_DEFAULT}, + {FCC6_WORLD, FCC6, WORLD, CTRY_DEFAULT}, + {FCC9_FCCA, FCC9, FCCA, CTRY_DEFAULT}, + {FCC10_FCCA, FCC10, FCCA, CTRY_DEFAULT}, + {FCC11_WORLD, FCC11, WORLD, CTRY_DEFAULT}, + {ETSI1_WORLD, ETSI1, WORLD, CTRY_DEFAULT}, + {ETSI3_WORLD, ETSI3, WORLD, CTRY_DEFAULT}, + {ETSI4_WORLD, ETSI4, WORLD, CTRY_DEFAULT}, + {ETSI7_WORLD, ETSI4, WORLD, CTRY_DEFAULT}, + {ETSI8_WORLD, ETSI8, WORLD, CTRY_DEFAULT}, + {ETSI9_WORLD, ETSI9, WORLD, CTRY_DEFAULT}, + {APL4_WORLD, APL4, WORLD, CTRY_DEFAULT}, + {APL2_WORLD, APL2, WORLD, CTRY_DEFAULT}, + {APL2_FCCA, APL2, FCCA, CTRY_DEFAULT}, + {APL2_ETSIC, APL2, ETSIC, CTRY_DEFAULT}, + {APL1_WORLD, APL1, WORLD, CTRY_DEFAULT}, + {APL1_ETSIC, APL1, ETSIC, CTRY_DEFAULT}, + {APL6_WORLD, APL6, WORLD, CTRY_DEFAULT}, + {APL7_FCCA, APL7, FCCA, CTRY_DEFAULT}, + {APL8_WORLD, APL8, WORLD, CTRY_DEFAULT}, + {APL9_WORLD, APL9, WORLD, CTRY_DEFAULT}, + {APL10_WORLD, APL10, WORLD, CTRY_DEFAULT}, + {APL12_WORLD, APL12, WORLD, CTRY_DEFAULT}, + {APL13_WORLD, APL13, WORLD, CTRY_DEFAULT}, + {APL14_WORLD, APL14, WORLD, CTRY_DEFAULT}, + {APL15_WORLD, APL15, WORLD, CTRY_DEFAULT}, + {APL16_WORLD, APL16, WORLD, CTRY_DEFAULT}, + {WOR0_WORLD, WOR0_WORLD, WOR0_WORLD, CTRY_DEFAULT}, + {WOR1_WORLD, WOR1_WORLD, WOR1_WORLD, CTRY_DEFAULT}, + {WOR2_WORLD, WOR2_WORLD, WOR2_WORLD, CTRY_DEFAULT}, + {WOR3_WORLD, WOR3_WORLD, WOR3_WORLD, CTRY_DEFAULT}, + {WOR4_FCCA, WOR4_FCCA, WOR4_FCCA, CTRY_DEFAULT}, + {WOR5_ETSIC, WOR5_ETSIC, WOR5_ETSIC, CTRY_DEFAULT}, + {WOR01_WORLD, WOR01_WORLD, WOR01_WORLD, CTRY_DEFAULT}, + {WOR02_WORLD, WOR02_WORLD, WOR02_WORLD, CTRY_DEFAULT}, + {EU1_WORLD, EU1_WORLD, EU1_WORLD, CTRY_DEFAULT}, + {WOR9_WORLD, WOR9_WORLD, WOR9_WORLD, CTRY_DEFAULT}, + {WORA_WORLD, WORA_WORLD, WORA_WORLD, CTRY_DEFAULT}, + {WORB_WORLD, WORB_WORLD, WORB_WORLD, CTRY_DEFAULT}, + {WORC_WORLD, WORC_WORLD, WORC_WORLD, CTRY_DEFAULT}, + {MKK5_MKKA2, MKK5, MKKA, CTRY_JAPAN14}, +}; + +static const struct country_code_to_reg_dmn g_all_countries[] = { + {CTRY_AFGHANISTAN, ETSI1_WORLD, "AF", "AFGHANISTAN"}, + {CTRY_ALBANIA, ETSI1_WORLD, "AL", "ALBANIA"}, + {CTRY_ALGERIA, APL13_WORLD, "DZ", "ALGERIA"}, + {CTRY_AMERICAN_SAMOA, FCC3_FCCA, "AS", "AMERICAN SAMOA"}, + {CTRY_ANGUILLA, ETSI1_WORLD, "AI", "ANGUILLA"}, + {CTRY_ARGENTINA, APL16_WORLD, "AR", "ARGENTINA"}, + {CTRY_ARMENIA, ETSI4_WORLD, "AM", "ARMENIA"}, + {CTRY_ARUBA, ETSI1_WORLD, "AW", "ARUBA"}, + {CTRY_AUSTRALIA, FCC6_WORLD, "AU", "AUSTRALIA"}, + {CTRY_AUSTRIA, ETSI1_WORLD, "AT", "AUSTRIA"}, + {CTRY_AZERBAIJAN, ETSI4_WORLD, "AZ", "AZERBAIJAN"}, + {CTRY_BAHAMAS, FCC3_WORLD, "BS", "BAHAMAS"}, + {CTRY_BAHRAIN, APL15_WORLD, "BH", "BAHRAIN"}, + {CTRY_BANGLADESH, APL1_WORLD, "BD", "BANGLADESH"}, + {CTRY_BARBADOS, FCC2_WORLD, "BB", "BARBADOS"}, + {CTRY_BELARUS, ETSI1_WORLD, "BY", "BELARUS"}, + {CTRY_BELGIUM, ETSI1_WORLD, "BE", "BELGIUM"}, + {CTRY_BELIZE, FCC3_ETSIC, "BZ", "BELIZE"}, + {CTRY_BERMUDA, FCC3_FCCA, "BM", "BERMUDA"}, + {CTRY_BHUTAN, ETSI1_WORLD, "BT", "BHUTAN"}, + {CTRY_BOLIVIA, APL8_WORLD, "BO", "BOLIVIA"}, + {CTRY_BOSNIA_HERZ, ETSI1_WORLD, "BA", "BOSNIA AND HERZEGOVINA"}, + {CTRY_BRAZIL, FCC3_ETSIC, "BR", "BRAZIL"}, + {CTRY_BRUNEI_DARUSSALAM, APL6_WORLD, "BN", "BRUNEI DARUSSALAM"}, + {CTRY_BULGARIA, ETSI1_WORLD, "BG", "BULGARIA"}, + {CTRY_BURKINA_FASO, FCC3_WORLD, "BF", "BURKINA-FASO"}, + {CTRY_CAMBODIA, ETSI1_WORLD, "KH", "CAMBODIA"}, + {CTRY_CANADA, FCC6_FCCA, "CA", "CANADA"}, + {CTRY_CAYMAN_ISLANDS, FCC3_WORLD, "KY", "CAYMAN ISLANDS"}, + {CTRY_CENTRAL_AFRICA_REPUBLIC, FCC3_WORLD, "CF", "AFRICA REPUBLIC"}, + {CTRY_CHAD, ETSI1_WORLD, "TD", "CHAD"}, + {CTRY_CHILE, APL6_WORLD, "CL", "CHILE"}, + {CTRY_CHINA, APL14_WORLD, "CN", "CHINA"}, + {CTRY_CHRISTMAS_ISLAND, FCC3_WORLD, "CX", "CHRISTMAS ISLAND"}, + {CTRY_COLOMBIA, FCC3_WORLD, "CO", "COLOMBIA"}, + {CTRY_COSTA_RICA, FCC3_WORLD, "CR", "COSTA RICA"}, + {CTRY_COTE_DIVOIRE, FCC3_WORLD, "CI", "COTE DIVOIRE"}, + {CTRY_CROATIA, ETSI1_WORLD, "HR", "CROATIA"}, + {CTRY_CYPRUS, ETSI1_WORLD, "CY", "CYPRUS"}, + {CTRY_CZECH, ETSI1_WORLD, "CZ", "CZECH REPUBLIC"}, + {CTRY_DENMARK, ETSI1_WORLD, "DK", "DENMARK"}, + {CTRY_DOMINICA, FCC1_FCCA, "DM", "DOMINICA"}, + {CTRY_DOMINICAN_REPUBLIC, FCC1_FCCA, "DO", "DOMINICAN REPUBLIC"}, + {CTRY_ECUADOR, FCC3_WORLD, "EC", "ECUADOR"}, + {CTRY_EGYPT, ETSI3_WORLD, "EG", "EGYPT"}, + {CTRY_EL_SALVADOR, FCC1_WORLD, "SV", "EL SALVADOR"}, + {CTRY_ESTONIA, ETSI1_WORLD, "EE", "ESTONIA"}, + {CTRY_ETHIOPIA, ETSI1_WORLD, "ET", "ETHIOPIA"}, + {CTRY_FINLAND, ETSI1_WORLD, "FI", "FINLAND"}, + {CTRY_FRANCE, ETSI1_WORLD, "FR", "FRANCE"}, + {CTRY_FRENCH_GUIANA, ETSI1_WORLD, "GF", "FRENCH GUIANA"}, + {CTRY_FRENCH_POLYNESIA, ETSI1_WORLD, "PF", "FRENCH POLYNESIA"}, + {CTRY_GEORGIA, ETSI4_WORLD, "GE", "GEORGIA"}, + {CTRY_GERMANY, ETSI1_WORLD, "DE", "GERMANY"}, + {CTRY_GHANA, FCC3_WORLD, "GH", "GHANA"}, + {CTRY_GREECE, ETSI1_WORLD, "GR", "GREECE"}, + {CTRY_GREENLAND, ETSI1_WORLD, "GL", "GREENLAND"}, + {CTRY_GRENADA, FCC3_FCCA, "GD", "GRENADA"}, + {CTRY_GUADELOUPE, ETSI1_WORLD, "GP", "GUADELOUPE"}, + {CTRY_GUAM, FCC3_FCCA, "GU", "GUAM"}, + {CTRY_GUATEMALA, ETSI1_WORLD, "GT", "GUATEMALA"}, + {CTRY_GUYANA, APL1_ETSIC, "GY", "GUYANA"}, + {CTRY_HAITI, FCC3_FCCA, "HT", "HAITI"}, + {CTRY_HONDURAS, FCC3_WORLD, "HN", "HONDURAS"}, + {CTRY_HONG_KONG, FCC3_WORLD, "HK", "HONG KONG"}, + {CTRY_HUNGARY, ETSI1_WORLD, "HU", "HUNGARY"}, + {CTRY_ICELAND, ETSI1_WORLD, "IS", "ICELAND"}, + {CTRY_INDIA, APL15_WORLD, "IN", "INDIA"}, + {CTRY_INDONESIA, APL2_ETSIC, "ID", "INDONESIA"}, + {CTRY_IRAN, APL1_WORLD, "IR", "IRAN"}, + {CTRY_IRELAND, ETSI1_WORLD, "IE", "IRELAND"}, + {CTRY_ISRAEL, ETSI3_WORLD, "IL", "ISRAEL"}, + {CTRY_ITALY, ETSI1_WORLD, "IT", "ITALY"}, + {CTRY_JAMAICA, FCC3_WORLD, "JM", "JAMAICA"}, + {CTRY_JORDAN, APL4_WORLD, "JO", "JORDAN"}, + {CTRY_KAZAKHSTAN, NULL1_WORLD, "KZ", "KAZAKHSTAN"}, + {CTRY_KENYA, APL12_WORLD, "KE", "KENYA"}, + {CTRY_KOREA_NORTH, APL9_WORLD, "KP", "NORTH KOREA"}, + {CTRY_KOREA_ROC, APL9_WORLD, "KR", "KOREA REPUBLIC"}, + {CTRY_KUWAIT, ETSI3_WORLD, "KW", "KUWAIT"}, + {CTRY_LATVIA, ETSI1_WORLD, "LV", "LATVIA"}, + {CTRY_LEBANON, FCC3_WORLD, "LB", "LEBANON"}, + {CTRY_LESOTHO, ETSI1_WORLD, "LS", "LESOTHO"}, + {CTRY_LIECHTENSTEIN, ETSI1_WORLD, "LI", "LIECHTENSTEIN"}, + {CTRY_LITHUANIA, ETSI1_WORLD, "LT", "LITHUANIA"}, + {CTRY_LUXEMBOURG, ETSI1_WORLD, "LU", "LUXEMBOURG"}, + {CTRY_MACAU, FCC3_WORLD, "MO", "MACAU SAR"}, + {CTRY_MACEDONIA, ETSI1_WORLD, "MK", "MACEDONIA, FYRO"}, + {CTRY_MALAWI, ETSI1_WORLD, "MW", "MALAWI"}, + {CTRY_MALAYSIA, FCC11_WORLD, "MY", "MALAYSIA"}, + {CTRY_MALDIVES, APL6_WORLD, "MV", "MALDIVES"}, + {CTRY_MALTA, ETSI1_WORLD, "MT", "MALTA"}, + {CTRY_MARSHALL_ISLANDS, FCC3_FCCA, "MH", "MARSHALL ISLANDS"}, + {CTRY_MARTINIQUE, ETSI1_WORLD, "MQ", "MARTINIQUE"}, + {CTRY_MAURITANIA, ETSI1_WORLD, "MR", "MAURITANA"}, + {CTRY_MAURITIUS, FCC3_WORLD, "MU", "MAURITIUS"}, + {CTRY_MAYOTTE, ETSI1_WORLD, "YT", "MAYOTTE"}, + {CTRY_MEXICO, FCC3_ETSIC, "MX", "MEXICO"}, + {CTRY_MICRONESIA, FCC3_FCCA, "FM", "MICRONESIA"}, + {CTRY_MOLDOVA, ETSI1_WORLD, "MD", "MOLDOVA"}, + {CTRY_MONACO, ETSI1_WORLD, "MC", "MONACO"}, + {CTRY_MONGOLIA, FCC3_WORLD, "MN", "MONGOLIA"}, + {CTRY_MONTENEGRO, ETSI1_WORLD, "ME", "MONTENEGRO"}, + {CTRY_MOROCCO, ETSI3_WORLD, "MA", "MOROCCO"}, + {CTRY_NAMIBIA, APL9_WORLD, "NA", "NAMIBIA"}, + {CTRY_NEPAL, APL6_WORLD, "NP", "NEPAL"}, + {CTRY_NETHERLANDS, ETSI1_WORLD, "NL", "NETHERLANDS"}, + {CTRY_NETHERLANDS_ANTILLES, ETSI1_WORLD, "AN", "NETHERLANDS ANTILLES"}, + {CTRY_NEW_ZEALAND, FCC3_ETSIC, "NZ", "NEW ZEALAND"}, + {CTRY_NIGERIA, APL8_WORLD, "NG", "NIGERIA"}, + {CTRY_NORTHERN_MARIANA_ISLANDS, FCC3_FCCA, "MP", "MARIANA ISLANDS"}, + {CTRY_NICARAGUA, FCC3_FCCA, "NI", "NICARAGUA"}, + {CTRY_NORWAY, ETSI1_WORLD, "NO", "NORWAY"}, + {CTRY_OMAN, ETSI1_WORLD, "OM", "OMAN"}, + {CTRY_PAKISTAN, APL1_ETSIC, "PK", "PAKISTAN"}, + {CTRY_PALAU, FCC3_FCCA, "PW", "PALAU"}, + {CTRY_PANAMA, FCC1_FCCA, "PA", "PANAMA"}, + {CTRY_PAPUA_NEW_GUINEA, FCC3_WORLD, "PG", "PAPUA NEW GUINEA"}, + {CTRY_PARAGUAY, FCC3_WORLD, "PY", "PARAGUAY"}, + {CTRY_PERU, FCC3_WORLD, "PE", "PERU"}, + {CTRY_PHILIPPINES, FCC3_WORLD, "PH", "PHILIPPINES"}, + {CTRY_POLAND, ETSI1_WORLD, "PL", "POLAND"}, + {CTRY_PORTUGAL, ETSI1_WORLD, "PT", "PORTUGAL"}, + {CTRY_PUERTO_RICO, FCC3_FCCA, "PR", "PUERTO RICO"}, + {CTRY_QATAR, APL1_WORLD, "QA", "QATAR"}, + {CTRY_REUNION, ETSI1_WORLD, "RE", "REUNION"}, + {CTRY_ROMANIA, ETSI1_WORLD, "RO", "ROMANIA"}, + {CTRY_RUSSIA, ETSI8_WORLD, "RU", "RUSSIA"}, + {CTRY_RWANDA, FCC3_WORLD, "RW", "RWANDA"}, + {CTRY_SAINT_BARTHELEMY, ETSI1_WORLD, "BL", "SAINT BARTHELEMY"}, + {CTRY_SAINT_KITTS_AND_NEVIS, APL10_WORLD, "KN", "SAINT KITTS"}, + {CTRY_SAINT_LUCIA, APL10_WORLD, "LC", "SAINT LUCIA"}, + {CTRY_SAINT_MARTIN, ETSI1_WORLD, "MF", "SAINT MARTIN"}, + {CTRY_SAINT_PIERRE_AND_MIQUELON, ETSI1_WORLD, "PM", "SAINT PIERRE"}, + {CTRY_SAINT_VINCENT_AND_THE_GRENADIENS, ETSI1_WORLD, "VC", "VINCENT"}, + {CTRY_SAMOA, ETSI1_WORLD, "WS", "SAMOA"}, + {CTRY_SAUDI_ARABIA, ETSI1_WORLD, "SA", "SAUDI ARABIA"}, + {CTRY_SENEGAL, FCC3_WORLD, "SN", "SENEGAL"}, + {CTRY_SERBIA, ETSI1_WORLD, "RS", "REPUBLIC OF SERBIA"}, + {CTRY_SINGAPORE, FCC3_WORLD, "SG", "SINGAPORE"}, + {CTRY_SLOVAKIA, ETSI1_WORLD, "SK", "SLOVAKIA"}, + {CTRY_SLOVENIA, ETSI1_WORLD, "SI", "SLOVENIA"}, + {CTRY_SOUTH_AFRICA, FCC3_WORLD, "ZA", "SOUTH AFRICA"}, + {CTRY_SPAIN, ETSI1_WORLD, "ES", "SPAIN"}, + {CTRY_SURINAME, ETSI1_WORLD, "SR", "SURINAME"}, + {CTRY_SRI_LANKA, FCC3_WORLD, "LK", "SRI LANKA"}, + {CTRY_SWEDEN, ETSI1_WORLD, "SE", "SWEDEN"}, + {CTRY_SWITZERLAND, ETSI1_WORLD, "CH", "SWITZERLAND"}, + {CTRY_SYRIA, NULL1_WORLD, "SY", "SYRIAN ARAB REPUBLIC"}, + {CTRY_TAIWAN, FCC3_FCCA, "TW", "TAIWAN"}, + {CTRY_TANZANIA, APL1_WORLD, "TZ", "TANZANIA"}, + {CTRY_THAILAND, FCC3_WORLD, "TH", "THAILAND"}, + {CTRY_TOGO, ETSI1_WORLD, "TG", "TOGO"}, + {CTRY_TRINIDAD_Y_TOBAGO, FCC3_WORLD, "TT", "TRINIDAD AND TOBAGO"}, + {CTRY_TUNISIA, ETSI3_WORLD, "TN", "TUNISIA"}, + {CTRY_TURKEY, ETSI1_WORLD, "TR", "TURKEY"}, + {CTRY_TURKS_AND_CAICOS, FCC3_WORLD, "TC" "TURKS AND CAICOS"}, + {CTRY_UGANDA, FCC3_WORLD, "UG", "UGANDA"}, + {CTRY_UKRAINE, ETSI9_WORLD, "UA", "UKRAINE"}, + {CTRY_UAE, FCC3_WORLD, "AE", "UNITED ARAB EMIRATES"}, + {CTRY_UNITED_KINGDOM, ETSI1_WORLD, "GB", "UNITED KINGDOM"}, + {CTRY_UNITED_STATES, FCC3_FCCA, "US", "UNITED STATES"}, + {CTRY_UNITED_STATES_PS, FCC4_FCCA, "PS", "US PUBLIC SAFETY"}, + {CTRY_URUGUAY, FCC2_WORLD, "UY", "URUGUAY"}, + {CTRY_UZBEKISTAN, ETSI3_WORLD, "UZ", "UZBEKISTAN"}, + {CTRY_VANUATU, FCC3_WORLD, "VU", "VANUATU"}, + {CTRY_VENEZUELA, FCC2_ETSIC, "VE", "VENEZUELA"}, + {CTRY_VIET_NAM, FCC3_WORLD, "VN", "VIETNAM"}, + {CTRY_VIRGIN_ISLANDS, FCC3_FCCA, "VI", "VIRGIN ISLANDS"}, + {CTRY_WALLIS_AND_FUTUNA, ETSI1_WORLD, "WF" "WALLIS"}, + {CTRY_YEMEN, NULL1_WORLD, "YE", "YEMEN"}, + {CTRY_ZIMBABWE, ETSI1_WORLD, "ZW", "ZIMBABWE"}, + {CTRY_JAPAN14, MKK5_MKKA2, "JP", "JAPAN"}, + {CTRY_XA, MKK5_MKKA2, "XA", "JAPAN PASSIVE"} +}; + +static const struct reg_dmn g_reg_dmns[] = { + {FCC1, FCC}, + {FCC2, FCC}, + {FCC3, FCC}, + {FCC4, FCC}, + {FCC5, FCC}, + {FCC6, FCC}, + {FCC7, FCC}, + {FCC8, FCC}, + {FCC9, FCC}, + {FCC10, FCC}, + {FCC11, FCC}, + {ETSI1, ETSI}, + {ETSI2, ETSI}, + {ETSI3, ETSI}, + {ETSI4, ETSI}, + {ETSI5, ETSI}, + {ETSI6, ETSI}, + {ETSI8, ETSI}, + {ETSI9, ETSI}, + {ETSI10, ETSI}, + {ETSI11, ETSI}, + {APL1, ETSI}, + {APL2, ETSI}, + {APL3, ETSI}, + {APL4, ETSI}, + {APL5, ETSI}, + {APL6, ETSI}, + {APL7, ETSI}, + {APL8, ETSI}, + {APL9, ETSI}, + {APL10, ETSI}, + {APL11, ETSI}, + {APL12, ETSI}, + {APL13, ETSI}, + {APL14, FCC}, + {APL15, FCC}, + {APL16, FCC}, + {NULL1, NO_CTL}, + {MKK3, MKK}, + {MKK4, MKK}, + {MKK5, MKK}, + {MKK9, MKK}, + {MKK10, MKK}, + {MKK11, MKK}, + {WORLD, ETSI}, + {FCCA, FCC}, + {MKKA, MKK}, + {MKKC, MKK}, + {ETSIC, ETSI}, + {WOR0_WORLD, NO_CTL}, + {WOR1_WORLD, NO_CTL}, + {WOR2_WORLD, NO_CTL}, + {WOR3_WORLD, NO_CTL}, + {WOR4_FCCA, NO_CTL}, + {WOR5_ETSIC, NO_CTL}, + {WOR01_WORLD, NO_CTL}, + {WOR02_WORLD, NO_CTL}, + {EU1_WORLD, NO_CTL}, + {WOR9_WORLD, NO_CTL}, + {WORA_WORLD, NO_CTL}, + {WORB_WORLD, NO_CTL}, + {WORC_WORLD, NO_CTL}, +}; + + +struct reg_dmn_tables g_reg_dmn_tbl = { + g_reg_dmn_pairs, + g_all_countries, + g_reg_dmns, + QDF_ARRAY_SIZE(g_reg_dmn_pairs), + QDF_ARRAY_SIZE(g_all_countries), + QDF_ARRAY_SIZE(g_reg_dmns), +}; + +/** + * get_bdf_reg_dmn() - get regulatory domain from BDF + * @reg_dmn: BDF regulatory domain + * + * Return: regulatory domain + */ +static uint16_t get_bdf_reg_dmn(uint16_t reg_dmn) +{ + return reg_dmn & ~WORLD_ROAMING_FLAG; +} + +/** + * is_reg_dmn_valid() - is regulatory domain valid + * @reg_dmn: regulatory domain + * + * Return: true or false + */ +static bool is_reg_dmn_valid(uint16_t reg_dmn) +{ + int32_t i; + + if (reg_dmn & CTRY_FLAG) { + uint16_t cc = reg_dmn & ~CTRY_FLAG; + for (i = 0; i < g_reg_dmn_tbl.all_countries_cnt; i++) + if (g_reg_dmn_tbl.all_countries[i].country_code == cc) + return true; + } else { + for (i = 0; i < g_reg_dmn_tbl.reg_dmn_pairs_cnt; i++) + if (g_reg_dmn_tbl.reg_dmn_pairs[i].reg_dmn_pair + == reg_dmn) + return true; + } + + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "invalid regulatory domain/country code 0x%x", reg_dmn); + + return false; +} + +/** + * find_country() - find country data + * @country_code: country code + * + * Return: country code data pointer + */ +static const struct country_code_to_reg_dmn *find_country(uint16_t country_code) +{ + int32_t i; + + for (i = 0; i < g_reg_dmn_tbl.all_countries_cnt; i++) { + if (g_reg_dmn_tbl.all_countries[i].country_code == country_code) + return &g_reg_dmn_tbl.all_countries[i]; + } + + return NULL; +} + +/** + * cds_get_country_from_alpha2() - get country from alpha2 + * @alpha2: country code alpha2 + * + * Return: country code + */ +int32_t cds_get_country_from_alpha2(uint8_t *alpha2) +{ + int32_t i; + + for (i = 0; i < g_reg_dmn_tbl.all_countries_cnt; i++) { + if (g_reg_dmn_tbl.all_countries[i].alpha2[0] == alpha2[0] && + g_reg_dmn_tbl.all_countries[i].alpha2[1] == alpha2[1]) + return g_reg_dmn_tbl.all_countries[i].country_code; + } + + return CTRY_DEFAULT; +} + +/** + * reg_dmn_get_default_country() - get default country for regulatory domain + * @reg_dmn: regulatory domain + * + * Return: default country + */ +static uint16_t reg_dmn_get_default_country(uint16_t reg_dmn) +{ + int32_t i; + const struct country_code_to_reg_dmn *country = NULL; + uint16_t cc = reg_dmn & ~CTRY_FLAG; + + if (reg_dmn & CTRY_FLAG) { + country = find_country(cc); + if (country) + return cc; + } + + for (i = 0; i < g_reg_dmn_tbl.reg_dmn_pairs_cnt; i++) { + if (g_reg_dmn_tbl.reg_dmn_pairs[i].reg_dmn_pair == reg_dmn) { + if (g_reg_dmn_tbl.reg_dmn_pairs[i].single_cc != 0) + return g_reg_dmn_tbl.reg_dmn_pairs[i].single_cc; + else + i = g_reg_dmn_tbl.reg_dmn_pairs_cnt; + } + } + + return CTRY_DEFAULT; +} + +/** + * get_reg_dmn_pair() - get regulatory domain pair pointer + * @reg_dmn: regulatory domain + * + * Return: pointer to regulatory domain pair data + */ +static const struct reg_dmn_pair *get_reg_dmn_pair(uint16_t reg_dmn) +{ + int32_t i; + + for (i = 0; i < g_reg_dmn_tbl.reg_dmn_pairs_cnt; i++) { + if (g_reg_dmn_tbl.reg_dmn_pairs[i].reg_dmn_pair == reg_dmn) + return &g_reg_dmn_tbl.reg_dmn_pairs[i]; + } + + return NULL; +} + +/** + * get_reg_dmn() - get regulatory domain pointer + * @reg_dmn: regulatory domain + * + * Return: pointer to regulatory domain data + */ +static const struct reg_dmn *get_reg_dmn(uint16_t reg_dmn) +{ + int32_t i; + + for (i = 0; i < g_reg_dmn_tbl.reg_dmns_cnt; i++) { + if (g_reg_dmn_tbl.reg_dmns[i].reg_dmn == reg_dmn) + return &g_reg_dmn_tbl.reg_dmns[i]; + } + + return NULL; +} + +/** + * get_country_from_rd() - get country from regulatory domain + * @reg_dmn: regulatory domain + * + * Return: country code enum + */ +static const struct country_code_to_reg_dmn *get_country_from_rd( + uint16_t reg_dmn) +{ + int32_t i; + + for (i = 0; i < g_reg_dmn_tbl.all_countries_cnt; i++) { + if (g_reg_dmn_tbl.all_countries[i].reg_dmn_pair == reg_dmn) + return &g_reg_dmn_tbl.all_countries[i]; + } + + return NULL; +} + +/** + * reg_dmn_sanitize() - sanitize regulatory domain + * @reg: regulatory data structure + * + * Return: none + */ +static void reg_dmn_sanitize(struct regulatory *reg) +{ + if (reg->reg_domain != CTRY_FLAG) + return; + + reg->reg_domain = WOR0_WORLD; +} + +/** + * cds_fill_some_regulatory_info() - fill regulatory information + * @reg: regulatory data structure + * + * Return: error code + */ +int32_t cds_fill_some_regulatory_info(struct regulatory *reg) +{ + uint16_t country_code; + uint16_t reg_dmn, rd; + const struct country_code_to_reg_dmn *country = NULL; + + reg_dmn_sanitize(reg); + rd = reg->reg_domain; + + if (!is_reg_dmn_valid(rd)) + return -EINVAL; + + reg_dmn = get_bdf_reg_dmn(rd); + + country_code = reg_dmn_get_default_country(reg_dmn); + if (country_code == CTRY_DEFAULT && reg_dmn == CTRY_DEFAULT) + country_code = CTRY_UNITED_STATES; + + if (country_code != CTRY_DEFAULT) { + country = find_country(country_code); + if (!country) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "not a valid country code"); + return -EINVAL; + } + + reg_dmn = country->reg_dmn_pair; + } + + reg->regpair = get_reg_dmn_pair(reg_dmn); + if (!reg->regpair) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "no regpair is found, can not proceeed"); + return -EINVAL; + } + + reg->country_code = country_code; + + if (!country) + country = get_country_from_rd(reg_dmn); + + if (country) { + reg->alpha2[0] = country->alpha2[0]; + reg->alpha2[1] = country->alpha2[1]; + } else { + reg->alpha2[0] = '0'; + reg->alpha2[1] = '0'; + } + + return 0; +} + +/** + * cds_fill_and_send_ctl_to_fw() - fill and send ctl to firmware + * @reg: the regulatory handle + * + * Return: none + */ +void cds_fill_and_send_ctl_to_fw(struct regulatory *reg) +{ + const struct reg_dmn *reg_dmn_2g = NULL; + const struct reg_dmn *reg_dmn_5g = NULL; + int8_t ctl_2g, ctl_5g; + const struct reg_dmn_pair *regpair; + tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA); + + if (!wma) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "unable to get WMA handle"); + return; + } + + regpair = reg->regpair; + reg_dmn_2g = get_reg_dmn(regpair->reg_dmn_2ghz); + if (!reg_dmn_2g) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "failed to get regdmn 2G"); + return; + } + + reg_dmn_5g = get_reg_dmn(regpair->reg_dmn_5ghz); + if (!reg_dmn_5g) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "failed to get regdmn 5G"); + return; + } + + ctl_2g = reg_dmn_2g->conformance_test_limit; + ctl_5g = reg_dmn_5g->conformance_test_limit; + + + reg->ctl_5g = ctl_5g; + reg->ctl_2g = ctl_2g; + + wma_send_regdomain_info_to_fw(reg->reg_domain, regpair->reg_dmn_2ghz, + regpair->reg_dmn_5ghz, ctl_2g, ctl_5g); +} + +/** + * cds_set_wma_dfs_region() - to set the dfs region to wma + * @reg: the regulatory handle + * + * Return: none + */ +void cds_set_wma_dfs_region(uint8_t dfs_region) +{ + tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA); + + if (!wma) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "unable to get WMA handle"); + return; + } + + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO, + "dfs_region: %d", dfs_region); + + wma_set_dfs_region(wma, dfs_region); +} + +/** + * cds_reg_dmn_get_chanwidth_from_opclass() - return chan width based on opclass + * @country: country name + * @channel: operating channel + * @opclass: operating class + * + * Given a value of country, channel and opclass this API will return value of + * channel width. + * + * Return: channel width + * + */ +uint16_t cds_reg_dmn_get_chanwidth_from_opclass(uint8_t *country, + uint8_t channel, + uint8_t opclass) +{ + const struct reg_dmn_op_class_map_t *class; + uint16_t i; + + if (!qdf_mem_cmp(country, "US", 2)) + class = us_op_class; + else if (!qdf_mem_cmp(country, "EU", 2)) + class = euro_op_class; + else if (!qdf_mem_cmp(country, "JP", 2)) + class = japan_op_class; + else + class = global_op_class; + + while (class->op_class) { + if (opclass == class->op_class) { + for (i = 0; + (i < MAX_CHANNELS_PER_OPERATING_CLASS && + class->channels[i]); + i++) { + if (channel == class->channels[i]) + return class->ch_spacing; + } + } + class++; + } + + return 0; +} + + +/** + * cds_reg_dmn_get_opclass_from_channel() - get operating class from channel + * @country: the complete reg domain + * @channel: channel number + * @offset: the value of offset + * + * Return: operating class + */ +uint16_t cds_reg_dmn_get_opclass_from_channel(uint8_t *country, uint8_t channel, + uint8_t offset) +{ + const struct reg_dmn_op_class_map_t *class = NULL; + uint16_t i = 0; + + if (!qdf_mem_cmp(country, "US", 2)) { + class = us_op_class; + } else if (!qdf_mem_cmp(country, "EU", 2)) { + class = euro_op_class; + } else if (!qdf_mem_cmp(country, "JP", 2)) { + class = japan_op_class; + } else { + class = global_op_class; + } + + while (class->op_class) { + if ((offset == class->offset) || (offset == BWALL)) { + for (i = 0; + (i < MAX_CHANNELS_PER_OPERATING_CLASS && + class->channels[i]); i++) { + if (channel == class->channels[i]) + return class->op_class; + } + } + class++; + } + + return 0; +} + +/** + * cds_reg_dmn_set_curr_opclasses() - set the current operating class + * @num_classes: number of classes + * @class: operating class + * + * Return: error code + */ +uint16_t cds_reg_dmn_set_curr_opclasses(uint8_t num_classes, uint8_t *class) +{ + uint8_t i; + + if (CDS_MAX_SUPP_OPER_CLASSES < num_classes) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "invalid num classes %d", num_classes); + return -1; + } + + for (i = 0; i < num_classes; i++) { + reg_dmn_curr_supp_opp_classes.classes[i] = class[i]; + } + + reg_dmn_curr_supp_opp_classes.num_classes = num_classes; + + return 0; +} + +/** + * cds_reg_dmn_get_curr_opclasses() - get the current operating class + * @num_classes: number of classes + * @class: operating class + * + * Return: error code + */ +uint16_t cds_reg_dmn_get_curr_opclasses(uint8_t *num_classes, uint8_t *class) +{ + uint8_t i; + + if (!num_classes || !class) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "either num_classes or class is null"); + return -1; + } + + for (i = 0; i < reg_dmn_curr_supp_opp_classes.num_classes; i++) + class[i] = reg_dmn_curr_supp_opp_classes.classes[i]; + + *num_classes = reg_dmn_curr_supp_opp_classes.num_classes; + + return 0; +} diff --git a/drivers/staging/qcacld-3.0/core/cds/src/cds_sched.c b/drivers/staging/qcacld-3.0/core/cds/src/cds_sched.c new file mode 100644 index 0000000000000000000000000000000000000000..8090685b67ddc8b7dbdca3609da098c1b794d42e --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/cds/src/cds_sched.c @@ -0,0 +1,1737 @@ +/* + * Copyright (c) 2014-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * File: cds_sched.c + * + * DOC: CDS Scheduler Implementation + */ + + /* Include Files */ +#include +#include +#include +#include +#include +#include +#include +#include +#include "cds_sched.h" +#include +#include "wma_types.h" +#include +#include +#include +/* Preprocessor Definitions and Constants */ +#define CDS_SCHED_THREAD_HEART_BEAT INFINITE +/* Milli seconds to delay SSR thread when an Entry point is Active */ +#define SSR_WAIT_SLEEP_TIME 200 +/* MAX iteration count to wait for Entry point to exit before + * we proceed with SSR in WD Thread + */ +#define MAX_SSR_WAIT_ITERATIONS 100 +#define MAX_SSR_PROTECT_LOG (16) + +static atomic_t ssr_protect_entry_count; + +/** + * struct ssr_protect - sub system restart(ssr) protection tracking table + * @func: Function which needs ssr protection + * @free: Flag to tell whether entry is free in table or not + * @pid: Process id which needs ssr protection + */ +struct ssr_protect { + const char *func; + bool free; + uint32_t pid; +}; + +static spinlock_t ssr_protect_lock; +static struct ssr_protect ssr_protect_log[MAX_SSR_PROTECT_LOG]; + +struct shutdown_notifier { + struct list_head list; + void (*cb)(void *priv); + void *priv; +}; + +struct list_head shutdown_notifier_head; + +enum notifier_state { + NOTIFIER_STATE_NONE, + NOTIFIER_STATE_NOTIFYING, +} notifier_state; + +struct _cds_sched_context *gp_cds_sched_context; +static int cds_mc_thread(void *Arg); +#ifdef QCA_CONFIG_SMP +static int cds_ol_rx_thread(void *arg); +static unsigned long affine_cpu; +static QDF_STATUS cds_alloc_ol_rx_pkt_freeq(p_cds_sched_context pSchedContext); +#endif + +#ifdef QCA_CONFIG_SMP +#define CDS_CORE_PER_CLUSTER (4) +/*Maximum 2 clusters supported*/ +#define CDS_MAX_CPU_CLUSTERS 2 + +#define CDS_CPU_CLUSTER_TYPE_LITTLE 0 +#define CDS_CPU_CLUSTER_TYPE_PERF 1 + +static inline +int cds_set_cpus_allowed_ptr(struct task_struct *task, unsigned long cpu) +{ + return set_cpus_allowed_ptr(task, cpumask_of(cpu)); +} + + +/** + * cds_sched_find_attach_cpu - find available cores and attach to required core + * @pSchedContext: wlan scheduler context + * @high_throughput: high throughput is required or not + * + * Find current online cores. + * high troughput required and PERF core online, then attach to last PERF core + * low throughput required or only little cores online, the attach any little + * core + * + * Return: 0 success + * 1 fail + */ +static int cds_sched_find_attach_cpu(p_cds_sched_context pSchedContext, + bool high_throughput) +{ + unsigned long *online_perf_cpu = NULL; + unsigned long *online_litl_cpu = NULL; + unsigned char perf_core_count = 0; + unsigned char litl_core_count = 0; + int cds_max_cluster_id = 0; +#ifdef WLAN_OPEN_SOURCE + struct cpumask litl_mask; + unsigned long cpus; + int i; +#endif + + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO_LOW, + "%s: num possible cpu %d", + __func__, num_possible_cpus()); + + online_perf_cpu = qdf_mem_malloc( + num_possible_cpus() * sizeof(unsigned long)); + if (!online_perf_cpu) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: perf cpu cache alloc fail", __func__); + return 1; + } + + online_litl_cpu = qdf_mem_malloc( + num_possible_cpus() * sizeof(unsigned long)); + if (!online_litl_cpu) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: lttl cpu cache alloc fail", __func__); + qdf_mem_free(online_perf_cpu); + return 1; + } + + /* Get Online perf CPU count */ +#if defined(WLAN_OPEN_SOURCE) && \ + (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)) + for_each_online_cpu(cpus) { + if (topology_physical_package_id(cpus) > CDS_MAX_CPU_CLUSTERS) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: can handle max %d clusters, returning...", + __func__, CDS_MAX_CPU_CLUSTERS); + goto err; + } + + if (topology_physical_package_id(cpus) == + CDS_CPU_CLUSTER_TYPE_PERF) { + online_perf_cpu[perf_core_count] = cpus; + perf_core_count++; + } else { + online_litl_cpu[litl_core_count] = cpus; + litl_core_count++; + } + cds_max_cluster_id = topology_physical_package_id(cpus); + } +#else + cds_max_cluster_id = 0; +#endif + + /* Single cluster system, not need to handle this */ + if (0 == cds_max_cluster_id) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO_LOW, + "%s: single cluster system. returning", __func__); + goto success; + } + + if ((!litl_core_count) && (!perf_core_count)) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: Both Cluster off, do nothing", __func__); + goto success; + } + + if ((high_throughput && perf_core_count) || (!litl_core_count)) { + /* Attach RX thread to PERF CPU */ + if (pSchedContext->rx_thread_cpu != + online_perf_cpu[perf_core_count - 1]) { + if (cds_set_cpus_allowed_ptr( + pSchedContext->ol_rx_thread, + online_perf_cpu[perf_core_count - 1])) { + QDF_TRACE(QDF_MODULE_ID_QDF, + QDF_TRACE_LEVEL_ERROR, + "%s: rx thread perf core set fail", + __func__); + goto err; + } + pSchedContext->rx_thread_cpu = + online_perf_cpu[perf_core_count - 1]; + } + } else { +#if defined(WLAN_OPEN_SOURCE) && \ + (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)) + /* Attach to any little core + * Final decision should made by scheduler */ + + cpumask_clear(&litl_mask); + for (i = 0; i < litl_core_count; i++) + cpumask_set_cpu(online_litl_cpu[i], &litl_mask); + + set_cpus_allowed_ptr(pSchedContext->ol_rx_thread, &litl_mask); + pSchedContext->rx_thread_cpu = 0; +#else + + /* Attach RX thread to last little core CPU */ + if (pSchedContext->rx_thread_cpu != + online_perf_cpu[litl_core_count - 1]) { + if (cds_set_cpus_allowed_ptr( + pSchedContext->ol_rx_thread, + online_perf_cpu[litl_core_count - 1])) { + QDF_TRACE(QDF_MODULE_ID_QDF, + QDF_TRACE_LEVEL_ERROR, + "%s: rx thread litl core set fail", + __func__); + goto err; + } + pSchedContext->rx_thread_cpu = + online_perf_cpu[litl_core_count - 1]; + } +#endif /* WLAN_OPEN_SOURCE */ + } + + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO_LOW, + "%s: NUM PERF CORE %d, HIGH TPUTR REQ %d, RX THRE CPU %lu", + __func__, perf_core_count, + (int)pSchedContext->high_throughput_required, + pSchedContext->rx_thread_cpu); + +success: + qdf_mem_free(online_perf_cpu); + qdf_mem_free(online_litl_cpu); + return 0; + +err: + qdf_mem_free(online_perf_cpu); + qdf_mem_free(online_litl_cpu); + return 1; +} + +/** + * cds_sched_handle_cpu_hot_plug - cpu hotplug event handler + * + * cpu hotplug indication handler + * will find online cores and will assign proper core based on perf requirement + * + * Return: 0 success + * 1 fail + */ +int cds_sched_handle_cpu_hot_plug(void) +{ + p_cds_sched_context pSchedContext = get_cds_sched_ctxt(); + + if (!pSchedContext) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: invalid context", __func__); + return 1; + } + + if (cds_is_load_or_unload_in_progress()) + return 0; + + mutex_lock(&pSchedContext->affinity_lock); + if (cds_sched_find_attach_cpu(pSchedContext, + pSchedContext->high_throughput_required)) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: handle hot plug fail", __func__); + mutex_unlock(&pSchedContext->affinity_lock); + return 1; + } + mutex_unlock(&pSchedContext->affinity_lock); + return 0; +} + +/** + * cds_sched_handle_throughput_req - cpu throughput requirement handler + * @high_tput_required: high throughput is required or not + * + * high or low throughput indication ahndler + * will find online cores and will assign proper core based on perf requirement + * + * Return: 0 success + * 1 fail + */ +int cds_sched_handle_throughput_req(bool high_tput_required) +{ + p_cds_sched_context pSchedContext = get_cds_sched_ctxt(); + + if (!pSchedContext) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: invalid context", __func__); + return 1; + } + + if (cds_is_load_or_unload_in_progress()) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: load or unload in progress", __func__); + return 0; + } + + mutex_lock(&pSchedContext->affinity_lock); + pSchedContext->high_throughput_required = high_tput_required; + if (cds_sched_find_attach_cpu(pSchedContext, high_tput_required)) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: handle throughput req fail", __func__); + mutex_unlock(&pSchedContext->affinity_lock); + return 1; + } + mutex_unlock(&pSchedContext->affinity_lock); + return 0; +} + +/** + * cds_cpu_hotplug_notify() - hot plug notify + * @block: Pointer to block + * @state: State + * @hcpu: Pointer to hotplug cpu + * + * Return: NOTIFY_OK + */ +static int +__cds_cpu_hotplug_notify(struct notifier_block *block, + unsigned long state, void *hcpu) +{ + unsigned long cpu = (unsigned long)hcpu; + unsigned long pref_cpu = 0; + p_cds_sched_context pSchedContext = get_cds_sched_ctxt(); + int i; + unsigned int multi_cluster; + unsigned int num_cpus; +#if defined(WLAN_OPEN_SOURCE) && \ + (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)) + int cpus; +#endif + + + if ((NULL == pSchedContext) || (NULL == pSchedContext->ol_rx_thread)) + return NOTIFY_OK; + + if (cds_is_load_or_unload_in_progress()) + return NOTIFY_OK; + + num_cpus = num_possible_cpus(); + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO_LOW, + "%s: RX CORE %d, STATE %d, NUM CPUS %d", + __func__, (int)affine_cpu, (int)state, num_cpus); + multi_cluster = 0; + +#if defined(WLAN_OPEN_SOURCE) && \ + (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0)) + + for_each_online_cpu(cpus) { + multi_cluster = topology_physical_package_id(cpus); + } +#endif + + if ((multi_cluster) && + ((CPU_ONLINE == state) || (CPU_DEAD == state))) { + cds_sched_handle_cpu_hot_plug(); + return NOTIFY_OK; + } + + switch (state) { + case CPU_ONLINE: + if (affine_cpu != 0) + return NOTIFY_OK; + + for_each_online_cpu(i) { + if (i == 0) + continue; + pref_cpu = i; + break; + } + break; + case CPU_DEAD: + if (cpu != affine_cpu) + return NOTIFY_OK; + + affine_cpu = 0; + for_each_online_cpu(i) { + if (i == 0) + continue; + pref_cpu = i; + break; + } + } + + if (pref_cpu == 0) + return NOTIFY_OK; + + if (!cds_set_cpus_allowed_ptr(pSchedContext->ol_rx_thread, pref_cpu)) + affine_cpu = pref_cpu; + + return NOTIFY_OK; +} + +/** + * vos_cpu_hotplug_notify - cpu core on-off notification handler wrapper + * @block: notifier block + * @state: state of core + * @hcpu: target cpu core + * + * pre-registered core status change notify callback function + * will handle only ONLINE, OFFLINE notification + * based on cpu architecture, rx thread affinity will be different + * wrapper function + * + * Return: 0 success + * 1 fail + */ +static int cds_cpu_hotplug_notify(struct notifier_block *block, + unsigned long state, void *hcpu) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __cds_cpu_hotplug_notify(block, state, hcpu); + cds_ssr_unprotect(__func__); + + return ret; +} + +static struct notifier_block cds_cpu_hotplug_notifier = { + .notifier_call = cds_cpu_hotplug_notify, +}; +#endif + +/** + * cds_sched_open() - initialize the CDS Scheduler + * @p_cds_context: Pointer to the global CDS Context + * @pSchedContext: Pointer to a previously allocated buffer big + * enough to hold a scheduler context. + * @SchedCtxSize: CDS scheduler context size + * + * This function initializes the CDS Scheduler + * Upon successful initialization: + * - All the message queues are initialized + * - The Main Controller thread is created and ready to receive and + * dispatch messages. + * + * + * Return: QDF status + */ +QDF_STATUS cds_sched_open(void *p_cds_context, + p_cds_sched_context pSchedContext, + uint32_t SchedCtxSize) +{ + QDF_STATUS vStatus = QDF_STATUS_SUCCESS; + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: Opening the CDS Scheduler", __func__); + /* Sanity checks */ + if ((p_cds_context == NULL) || (pSchedContext == NULL)) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: Null params being passed", __func__); + return QDF_STATUS_E_FAILURE; + } + if (sizeof(cds_sched_context) != SchedCtxSize) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: Incorrect CDS Sched Context size passed", + __func__); + return QDF_STATUS_E_INVAL; + } + qdf_mem_zero(pSchedContext, sizeof(cds_sched_context)); + pSchedContext->pVContext = p_cds_context; + vStatus = cds_sched_init_mqs(pSchedContext); + if (!QDF_IS_STATUS_SUCCESS(vStatus)) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: Failed to initialize CDS Scheduler MQs", + __func__); + return vStatus; + } + /* Initialize the helper events and event queues */ + init_completion(&pSchedContext->McStartEvent); + init_completion(&pSchedContext->McShutdown); + init_completion(&pSchedContext->ResumeMcEvent); + + spin_lock_init(&pSchedContext->McThreadLock); +#ifdef QCA_CONFIG_SMP + spin_lock_init(&pSchedContext->ol_rx_thread_lock); +#endif + + init_waitqueue_head(&pSchedContext->mcWaitQueue); + pSchedContext->mcEventFlag = 0; + +#ifdef QCA_CONFIG_SMP + init_waitqueue_head(&pSchedContext->ol_rx_wait_queue); + init_completion(&pSchedContext->ol_rx_start_event); + init_completion(&pSchedContext->ol_suspend_rx_event); + init_completion(&pSchedContext->ol_resume_rx_event); + init_completion(&pSchedContext->ol_rx_shutdown); + pSchedContext->ol_rx_event_flag = 0; + spin_lock_init(&pSchedContext->ol_rx_queue_lock); + spin_lock_init(&pSchedContext->cds_ol_rx_pkt_freeq_lock); + INIT_LIST_HEAD(&pSchedContext->ol_rx_thread_queue); + spin_lock_bh(&pSchedContext->cds_ol_rx_pkt_freeq_lock); + INIT_LIST_HEAD(&pSchedContext->cds_ol_rx_pkt_freeq); + spin_unlock_bh(&pSchedContext->cds_ol_rx_pkt_freeq_lock); + if (cds_alloc_ol_rx_pkt_freeq(pSchedContext) != QDF_STATUS_SUCCESS) + goto pkt_freeqalloc_failure; + register_hotcpu_notifier(&cds_cpu_hotplug_notifier); + pSchedContext->cpu_hot_plug_notifier = &cds_cpu_hotplug_notifier; + mutex_init(&pSchedContext->affinity_lock); + pSchedContext->high_throughput_required = false; +#endif + gp_cds_sched_context = pSchedContext; + + /* Create the CDS Main Controller thread */ + pSchedContext->McThread = kthread_create(cds_mc_thread, pSchedContext, + "cds_mc_thread"); + if (IS_ERR(pSchedContext->McThread)) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_FATAL, + "%s: Could not Create CDS Main Thread Controller", + __func__); + goto MC_THREAD_START_FAILURE; + } + wake_up_process(pSchedContext->McThread); + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: CDS Main Controller thread Created", __func__); + +#ifdef QCA_CONFIG_SMP + pSchedContext->ol_rx_thread = kthread_create(cds_ol_rx_thread, + pSchedContext, + "cds_ol_rx_thread"); + if (IS_ERR(pSchedContext->ol_rx_thread)) { + + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_FATAL, + "%s: Could not Create CDS OL RX Thread", + __func__); + goto OL_RX_THREAD_START_FAILURE; + + } + wake_up_process(pSchedContext->ol_rx_thread); + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO_HIGH, + ("CDS OL RX thread Created")); +#endif + /* + * Now make sure all threads have started before we exit. + * Each thread should normally ACK back when it starts. + */ + wait_for_completion_interruptible(&pSchedContext->McStartEvent); + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: CDS MC Thread has started", __func__); +#ifdef QCA_CONFIG_SMP + wait_for_completion_interruptible(&pSchedContext->ol_rx_start_event); + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: CDS OL Rx Thread has started", __func__); +#endif + /* We're good now: Let's get the ball rolling!!! */ + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: CDS Scheduler successfully Opened", __func__); + return QDF_STATUS_SUCCESS; + +#ifdef QCA_CONFIG_SMP +OL_RX_THREAD_START_FAILURE: + /* Try and force the Main thread controller to exit */ + set_bit(MC_SHUTDOWN_EVENT, &pSchedContext->mcEventFlag); + set_bit(MC_POST_EVENT, &pSchedContext->mcEventFlag); + wake_up_interruptible(&pSchedContext->mcWaitQueue); + /* Wait for MC to exit */ + wait_for_completion_interruptible(&pSchedContext->McShutdown); +#endif + +MC_THREAD_START_FAILURE: + +#ifdef QCA_CONFIG_SMP + unregister_hotcpu_notifier(&cds_cpu_hotplug_notifier); + cds_free_ol_rx_pkt_freeq(gp_cds_sched_context); +pkt_freeqalloc_failure: +#endif + /* De-initialize all the message queues */ + cds_sched_deinit_mqs(pSchedContext); + gp_cds_sched_context = NULL; + + return QDF_STATUS_E_RESOURCES; + +} /* cds_sched_open() */ + +#define MC_THRD_WD_TIMEOUT (60 * 1000) /* 60s */ + +static inline void cds_mc_thread_watchdog_warn(uint16_t msg_type_id) +{ + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: Message type %x has exceeded its alloted time of %ds", + __func__, msg_type_id, MC_THRD_WD_TIMEOUT / 1000); +} + +#ifdef CONFIG_SLUB_DEBUG_ON +static void cds_mc_thread_watchdog_bite(void *arg) +{ + cds_mc_thread_watchdog_warn(*(uint16_t *)arg); + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: Going down for MC Thread Watchdog Bite!", __func__); + QDF_BUG(0); +} +#else +static inline void cds_mc_thread_watchdog_bite(void *arg) +{ + cds_mc_thread_watchdog_warn(*(uint16_t *)arg); +} +#endif + +/** + * cds_mc_thread() - cds main controller thread execution handler + * @Arg: Pointer to the global CDS Sched Context + * + * Return: thread exit code + */ +static int cds_mc_thread(void *Arg) +{ + p_cds_sched_context pSchedContext = (p_cds_sched_context) Arg; + p_cds_msg_wrapper pMsgWrapper = NULL; + tpAniSirGlobal pMacContext = NULL; + tSirRetStatus macStatus = eSIR_SUCCESS; + QDF_STATUS vStatus = QDF_STATUS_SUCCESS; + int retWaitStatus = 0; + bool shutdown = false; + hdd_context_t *pHddCtx = NULL; + v_CONTEXT_t p_cds_context = NULL; + qdf_timer_t wd_timer; + uint16_t wd_msg_type_id; + + if (Arg == NULL) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: Bad Args passed", __func__); + return 0; + } + set_user_nice(current, -2); + + /* Ack back to the context from which the main controller thread + * has been created + */ + complete(&pSchedContext->McStartEvent); + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO, + "%s: MC Thread %d (%s) starting up", __func__, current->pid, + current->comm); + + /* Get the Global CDS Context */ + p_cds_context = cds_get_global_context(); + if (!p_cds_context) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_FATAL, + "%s: Global CDS context is Null", __func__); + return 0; + } + + pHddCtx = cds_get_context(QDF_MODULE_ID_HDD); + if (!pHddCtx) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_FATAL, + "%s: HDD context is Null", __func__); + return 0; + } + + /* initialize MC thread watchdog timer */ + qdf_timer_init(NULL, &wd_timer, &cds_mc_thread_watchdog_bite, + &wd_msg_type_id, QDF_TIMER_TYPE_SW); + + while (!shutdown) { + /* This implements the execution model algorithm */ + retWaitStatus = + wait_event_interruptible(pSchedContext->mcWaitQueue, + test_bit(MC_POST_EVENT, + &pSchedContext->mcEventFlag) + || test_bit(MC_SUSPEND_EVENT, + &pSchedContext->mcEventFlag)); + + if (retWaitStatus == -ERESTARTSYS) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: wait_event_interruptible returned -ERESTARTSYS", + __func__); + QDF_BUG(0); + } + clear_bit(MC_POST_EVENT, &pSchedContext->mcEventFlag); + + while (1) { + /* Check if MC needs to shutdown */ + if (test_bit + (MC_SHUTDOWN_EVENT, + &pSchedContext->mcEventFlag)) { + QDF_TRACE(QDF_MODULE_ID_QDF, + QDF_TRACE_LEVEL_INFO, + "%s: MC thread signaled to shutdown", + __func__); + shutdown = true; + /* Check for any Suspend Indication */ + if (test_bit + (MC_SUSPEND_EVENT, + &pSchedContext->mcEventFlag)) { + clear_bit(MC_SUSPEND_EVENT, + &pSchedContext->mcEventFlag); + + /* Unblock anyone waiting on suspend */ + complete(&pHddCtx->mc_sus_event_var); + } + break; + } + /* Check the SYS queue first */ + if (!cds_is_mq_empty(&pSchedContext->sysMcMq)) { + /* Service the SYS message queue */ + pMsgWrapper = + cds_mq_get(&pSchedContext->sysMcMq); + if (pMsgWrapper == NULL) { + QDF_TRACE(QDF_MODULE_ID_QDF, + QDF_TRACE_LEVEL_ERROR, + "%s: pMsgWrapper is NULL", + __func__); + QDF_ASSERT(0); + break; + } + + qdf_timer_start(&wd_timer, MC_THRD_WD_TIMEOUT); + wd_msg_type_id = pMsgWrapper->pVosMsg->type; + vStatus = + sys_mc_process_msg(pSchedContext->pVContext, + pMsgWrapper->pVosMsg); + qdf_timer_stop(&wd_timer); + + if (!QDF_IS_STATUS_SUCCESS(vStatus)) { + QDF_TRACE(QDF_MODULE_ID_QDF, + QDF_TRACE_LEVEL_ERROR, + "%s: Issue Processing SYS message", + __func__); + } + /* return message to the Core */ + cds_core_return_msg(pSchedContext->pVContext, + pMsgWrapper); + continue; + } + /* Check the WMA queue */ + if (!cds_is_mq_empty(&pSchedContext->wmaMcMq)) { + /* Service the WMA message queue */ + pMsgWrapper = + cds_mq_get(&pSchedContext->wmaMcMq); + if (pMsgWrapper == NULL) { + QDF_TRACE(QDF_MODULE_ID_QDF, + QDF_TRACE_LEVEL_ERROR, + "%s: pMsgWrapper is NULL", + __func__); + QDF_ASSERT(0); + break; + } + + qdf_timer_start(&wd_timer, MC_THRD_WD_TIMEOUT); + wd_msg_type_id = pMsgWrapper->pVosMsg->type; + vStatus = + wma_mc_process_msg(pSchedContext->pVContext, + pMsgWrapper->pVosMsg); + qdf_timer_stop(&wd_timer); + + if (!QDF_IS_STATUS_SUCCESS(vStatus)) { + QDF_TRACE(QDF_MODULE_ID_QDF, + QDF_TRACE_LEVEL_ERROR, + "%s: Issue Processing WMA message", + __func__); + } + /* return message to the Core */ + cds_core_return_msg(pSchedContext->pVContext, + pMsgWrapper); + continue; + } + /* Check the PE queue */ + if (!cds_is_mq_empty(&pSchedContext->peMcMq)) { + /* Service the PE message queue */ + pMsgWrapper = + cds_mq_get(&pSchedContext->peMcMq); + if (NULL == pMsgWrapper) { + QDF_TRACE(QDF_MODULE_ID_QDF, + QDF_TRACE_LEVEL_ERROR, + "%s: pMsgWrapper is NULL", + __func__); + QDF_ASSERT(0); + break; + } + /* Need some optimization */ + pMacContext = + cds_get_context(QDF_MODULE_ID_PE); + if (NULL == pMacContext) { + QDF_TRACE(QDF_MODULE_ID_QDF, + QDF_TRACE_LEVEL_INFO, + "MAC Context not ready yet"); + cds_core_return_msg + (pSchedContext->pVContext, + pMsgWrapper); + continue; + } + + qdf_timer_start(&wd_timer, MC_THRD_WD_TIMEOUT); + wd_msg_type_id = pMsgWrapper->pVosMsg->type; + macStatus = + pe_process_messages(pMacContext, + (tSirMsgQ *) + pMsgWrapper->pVosMsg); + qdf_timer_stop(&wd_timer); + + if (eSIR_SUCCESS != macStatus) { + QDF_TRACE(QDF_MODULE_ID_QDF, + QDF_TRACE_LEVEL_ERROR, + "%s: Issue Processing PE message", + __func__); + } + /* return message to the Core */ + cds_core_return_msg(pSchedContext->pVContext, + pMsgWrapper); + continue; + } + /** Check the SME queue **/ + if (!cds_is_mq_empty(&pSchedContext->smeMcMq)) { + /* Service the SME message queue */ + pMsgWrapper = + cds_mq_get(&pSchedContext->smeMcMq); + if (NULL == pMsgWrapper) { + QDF_TRACE(QDF_MODULE_ID_QDF, + QDF_TRACE_LEVEL_ERROR, + "%s: pMsgWrapper is NULL", + __func__); + QDF_ASSERT(0); + break; + } + /* Need some optimization */ + pMacContext = + cds_get_context(QDF_MODULE_ID_SME); + if (NULL == pMacContext) { + QDF_TRACE(QDF_MODULE_ID_QDF, + QDF_TRACE_LEVEL_INFO, + "MAC Context not ready yet"); + cds_core_return_msg + (pSchedContext->pVContext, + pMsgWrapper); + continue; + } + + qdf_timer_start(&wd_timer, MC_THRD_WD_TIMEOUT); + wd_msg_type_id = pMsgWrapper->pVosMsg->type; + vStatus = + sme_process_msg((tHalHandle)pMacContext, + pMsgWrapper->pVosMsg); + qdf_timer_stop(&wd_timer); + + if (!QDF_IS_STATUS_SUCCESS(vStatus)) { + QDF_TRACE(QDF_MODULE_ID_QDF, + QDF_TRACE_LEVEL_ERROR, + "%s: Issue Processing SME message", + __func__); + } + /* return message to the Core */ + cds_core_return_msg(pSchedContext->pVContext, + pMsgWrapper); + continue; + } + /* Check for any Suspend Indication */ + if (test_bit + (MC_SUSPEND_EVENT, + &pSchedContext->mcEventFlag)) { + clear_bit(MC_SUSPEND_EVENT, + &pSchedContext->mcEventFlag); + spin_lock(&pSchedContext->McThreadLock); + INIT_COMPLETION(pSchedContext->ResumeMcEvent); + /* Mc Thread Suspended */ + complete(&pHddCtx->mc_sus_event_var); + + spin_unlock(&pSchedContext->McThreadLock); + + /* Wait foe Resume Indication */ + wait_for_completion_interruptible + (&pSchedContext->ResumeMcEvent); + } + break; /* All queues are empty now */ + } /* while message loop processing */ + } /* while true */ + + /* If we get here the MC thread must exit */ + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO, + "%s: MC Thread exiting!!!!", __func__); + + qdf_timer_free(&wd_timer); + + complete_and_exit(&pSchedContext->McShutdown, 0); +} /* cds_mc_thread() */ + +#ifdef QCA_CONFIG_SMP +/** + * cds_free_ol_rx_pkt_freeq() - free cds buffer free queue + * @pSchedContext - pointer to the global CDS Sched Context + * + * This API does mem free of the buffers available in free cds buffer + * queue which is used for Data rx processing. + * + * Return: none + */ +void cds_free_ol_rx_pkt_freeq(p_cds_sched_context pSchedContext) +{ + struct cds_ol_rx_pkt *pkt; + + spin_lock_bh(&pSchedContext->cds_ol_rx_pkt_freeq_lock); + while (!list_empty(&pSchedContext->cds_ol_rx_pkt_freeq)) { + pkt = list_entry((&pSchedContext->cds_ol_rx_pkt_freeq)->next, + typeof(*pkt), list); + list_del(&pkt->list); + spin_unlock_bh(&pSchedContext->cds_ol_rx_pkt_freeq_lock); + qdf_mem_free(pkt); + spin_lock_bh(&pSchedContext->cds_ol_rx_pkt_freeq_lock); + } + spin_unlock_bh(&pSchedContext->cds_ol_rx_pkt_freeq_lock); +} + +/** + * cds_alloc_ol_rx_pkt_freeq() - Function to allocate free buffer queue + * @pSchedContext - pointer to the global CDS Sched Context + * + * This API allocates CDS_MAX_OL_RX_PKT number of cds message buffers + * which are used for Rx data processing. + * + * Return: status of memory allocation + */ +static QDF_STATUS cds_alloc_ol_rx_pkt_freeq(p_cds_sched_context pSchedContext) +{ + struct cds_ol_rx_pkt *pkt, *tmp; + int i; + + for (i = 0; i < CDS_MAX_OL_RX_PKT; i++) { + pkt = qdf_mem_malloc(sizeof(*pkt)); + if (!pkt) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s Vos packet allocation for ol rx thread failed", + __func__); + goto free; + } + spin_lock_bh(&pSchedContext->cds_ol_rx_pkt_freeq_lock); + list_add_tail(&pkt->list, &pSchedContext->cds_ol_rx_pkt_freeq); + spin_unlock_bh(&pSchedContext->cds_ol_rx_pkt_freeq_lock); + } + + return QDF_STATUS_SUCCESS; + +free: + spin_lock_bh(&pSchedContext->cds_ol_rx_pkt_freeq_lock); + list_for_each_entry_safe(pkt, tmp, &pSchedContext->cds_ol_rx_pkt_freeq, + list) { + list_del(&pkt->list); + spin_unlock_bh(&pSchedContext->cds_ol_rx_pkt_freeq_lock); + qdf_mem_free(pkt); + spin_lock_bh(&pSchedContext->cds_ol_rx_pkt_freeq_lock); + } + spin_unlock_bh(&pSchedContext->cds_ol_rx_pkt_freeq_lock); + return QDF_STATUS_E_NOMEM; +} + +/** + * cds_free_ol_rx_pkt() - api to release cds message to the freeq + * This api returns the cds message used for Rx data to the free queue + * @pSchedContext: Pointer to the global CDS Sched Context + * @pkt: CDS message buffer to be returned to free queue. + * + * Return: none + */ +void +cds_free_ol_rx_pkt(p_cds_sched_context pSchedContext, + struct cds_ol_rx_pkt *pkt) +{ + memset(pkt, 0, sizeof(*pkt)); + spin_lock_bh(&pSchedContext->cds_ol_rx_pkt_freeq_lock); + list_add_tail(&pkt->list, &pSchedContext->cds_ol_rx_pkt_freeq); + spin_unlock_bh(&pSchedContext->cds_ol_rx_pkt_freeq_lock); +} + +/** + * cds_alloc_ol_rx_pkt() - API to return next available cds message + * @pSchedContext: Pointer to the global CDS Sched Context + * + * This api returns next available cds message buffer used for rx data + * processing + * + * Return: Pointer to cds message buffer + */ +struct cds_ol_rx_pkt *cds_alloc_ol_rx_pkt(p_cds_sched_context pSchedContext) +{ + struct cds_ol_rx_pkt *pkt; + + spin_lock_bh(&pSchedContext->cds_ol_rx_pkt_freeq_lock); + if (list_empty(&pSchedContext->cds_ol_rx_pkt_freeq)) { + spin_unlock_bh(&pSchedContext->cds_ol_rx_pkt_freeq_lock); + return NULL; + } + pkt = list_first_entry(&pSchedContext->cds_ol_rx_pkt_freeq, + struct cds_ol_rx_pkt, list); + list_del(&pkt->list); + spin_unlock_bh(&pSchedContext->cds_ol_rx_pkt_freeq_lock); + return pkt; +} + +/** + * cds_indicate_rxpkt() - indicate rx data packet + * @Arg: Pointer to the global CDS Sched Context + * @pkt: CDS data message buffer + * + * This api enqueues the rx packet into ol_rx_thread_queue and notifies + * cds_ol_rx_thread() + * + * Return: none + */ +void +cds_indicate_rxpkt(p_cds_sched_context pSchedContext, + struct cds_ol_rx_pkt *pkt) +{ + spin_lock_bh(&pSchedContext->ol_rx_queue_lock); + list_add_tail(&pkt->list, &pSchedContext->ol_rx_thread_queue); + spin_unlock_bh(&pSchedContext->ol_rx_queue_lock); + set_bit(RX_POST_EVENT, &pSchedContext->ol_rx_event_flag); + wake_up_interruptible(&pSchedContext->ol_rx_wait_queue); +} + +/** + * cds_drop_rxpkt_by_staid() - api to drop pending rx packets for a sta + * @pSchedContext: Pointer to the global CDS Sched Context + * @staId: Station Id + * + * This api drops queued packets for a station, to drop all the pending + * packets the caller has to send WLAN_MAX_STA_COUNT as staId. + * + * Return: none + */ +void cds_drop_rxpkt_by_staid(p_cds_sched_context pSchedContext, uint16_t staId) +{ + struct list_head local_list; + struct cds_ol_rx_pkt *pkt, *tmp; + qdf_nbuf_t buf, next_buf; + + INIT_LIST_HEAD(&local_list); + spin_lock_bh(&pSchedContext->ol_rx_queue_lock); + if (list_empty(&pSchedContext->ol_rx_thread_queue)) { + spin_unlock_bh(&pSchedContext->ol_rx_queue_lock); + return; + } + list_for_each_entry_safe(pkt, tmp, &pSchedContext->ol_rx_thread_queue, + list) { + if (pkt->staId == staId || staId == WLAN_MAX_STA_COUNT) + list_move_tail(&pkt->list, &local_list); + } + spin_unlock_bh(&pSchedContext->ol_rx_queue_lock); + + list_for_each_entry_safe(pkt, tmp, &local_list, list) { + list_del(&pkt->list); + buf = pkt->Rxpkt; + while (buf) { + next_buf = qdf_nbuf_queue_next(buf); + qdf_nbuf_free(buf); + buf = next_buf; + } + cds_free_ol_rx_pkt(pSchedContext, pkt); + } +} + +/** + * cds_rx_from_queue() - function to process pending Rx packets + * @pSchedContext: Pointer to the global CDS Sched Context + * + * This api traverses the pending buffer list and calling the callback. + * This callback would essentially send the packet to HDD. + * + * Return: none + */ +static void cds_rx_from_queue(p_cds_sched_context pSchedContext) +{ + struct cds_ol_rx_pkt *pkt; + uint16_t sta_id; + + spin_lock_bh(&pSchedContext->ol_rx_queue_lock); + while (!list_empty(&pSchedContext->ol_rx_thread_queue)) { + pkt = list_first_entry(&pSchedContext->ol_rx_thread_queue, + struct cds_ol_rx_pkt, list); + list_del(&pkt->list); + spin_unlock_bh(&pSchedContext->ol_rx_queue_lock); + sta_id = pkt->staId; + pkt->callback(pkt->context, pkt->Rxpkt, sta_id); + cds_free_ol_rx_pkt(pSchedContext, pkt); + spin_lock_bh(&pSchedContext->ol_rx_queue_lock); + } + spin_unlock_bh(&pSchedContext->ol_rx_queue_lock); +} + +/** + * cds_ol_rx_thread() - cds main tlshim rx thread + * @Arg: pointer to the global CDS Sched Context + * + * This api is the thread handler for Tlshim Data packet processing. + * + * Return: thread exit code + */ +static int cds_ol_rx_thread(void *arg) +{ + p_cds_sched_context pSchedContext = (p_cds_sched_context) arg; + unsigned long pref_cpu = 0; + bool shutdown = false; + int status, i; + + set_user_nice(current, -1); +#ifdef MSM_PLATFORM + set_wake_up_idle(true); +#endif + + /* Find the available cpu core other than cpu 0 and + * bind the thread + */ + /* Find the available cpu core other than cpu 0 and + * bind the thread */ + for_each_online_cpu(i) { + if (i == 0) + continue; + pref_cpu = i; + break; + } + + if (pref_cpu != 0 && (!cds_set_cpus_allowed_ptr(current, pref_cpu))) + affine_cpu = pref_cpu; + + if (!arg) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: Bad Args passed", __func__); + return 0; + } + + complete(&pSchedContext->ol_rx_start_event); + + while (!shutdown) { + status = + wait_event_interruptible(pSchedContext->ol_rx_wait_queue, + test_bit(RX_POST_EVENT, + &pSchedContext->ol_rx_event_flag) + || test_bit(RX_SUSPEND_EVENT, + &pSchedContext->ol_rx_event_flag)); + if (status == -ERESTARTSYS) + break; + + clear_bit(RX_POST_EVENT, &pSchedContext->ol_rx_event_flag); + while (true) { + if (test_bit(RX_SHUTDOWN_EVENT, + &pSchedContext->ol_rx_event_flag)) { + clear_bit(RX_SHUTDOWN_EVENT, + &pSchedContext->ol_rx_event_flag); + if (test_bit(RX_SUSPEND_EVENT, + &pSchedContext->ol_rx_event_flag)) { + clear_bit(RX_SUSPEND_EVENT, + &pSchedContext->ol_rx_event_flag); + complete + (&pSchedContext->ol_suspend_rx_event); + } + QDF_TRACE(QDF_MODULE_ID_QDF, + QDF_TRACE_LEVEL_INFO, + "%s: Shutting down OL RX Thread", + __func__); + shutdown = true; + break; + } + cds_rx_from_queue(pSchedContext); + + if (test_bit(RX_SUSPEND_EVENT, + &pSchedContext->ol_rx_event_flag)) { + clear_bit(RX_SUSPEND_EVENT, + &pSchedContext->ol_rx_event_flag); + spin_lock(&pSchedContext->ol_rx_thread_lock); + INIT_COMPLETION + (pSchedContext->ol_resume_rx_event); + complete(&pSchedContext->ol_suspend_rx_event); + spin_unlock(&pSchedContext->ol_rx_thread_lock); + wait_for_completion_interruptible + (&pSchedContext->ol_resume_rx_event); + } + break; + } + } + + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO, + "%s: Exiting CDS OL rx thread", __func__); + complete_and_exit(&pSchedContext->ol_rx_shutdown, 0); +} +#endif + +/** + * cds_sched_close() - close the cds scheduler + * @p_cds_context: Pointer to the global CDS Context + * + * This api closes the CDS Scheduler upon successful closing: + * - All the message queues are flushed + * - The Main Controller thread is closed + * - The Tx thread is closed + * + * + * Return: qdf status + */ +QDF_STATUS cds_sched_close(void *p_cds_context) +{ + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: invoked", __func__); + + if (gp_cds_sched_context == NULL) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: gp_cds_sched_context == NULL", __func__); + return QDF_STATUS_E_FAILURE; + } + + if (gp_cds_sched_context->McThread == 0) + return QDF_STATUS_SUCCESS; + + /* shut down MC Thread */ + set_bit(MC_SHUTDOWN_EVENT, &gp_cds_sched_context->mcEventFlag); + set_bit(MC_POST_EVENT, &gp_cds_sched_context->mcEventFlag); + wake_up_interruptible(&gp_cds_sched_context->mcWaitQueue); + /* Wait for MC to exit */ + wait_for_completion(&gp_cds_sched_context->McShutdown); + gp_cds_sched_context->McThread = 0; + + /* Clean up message queues of MC thread */ + cds_sched_flush_mc_mqs(gp_cds_sched_context); + + /* Deinit all the queues */ + cds_sched_deinit_mqs(gp_cds_sched_context); + +#ifdef QCA_CONFIG_SMP + /* Shut down Tlshim Rx thread */ + set_bit(RX_SHUTDOWN_EVENT, &gp_cds_sched_context->ol_rx_event_flag); + set_bit(RX_POST_EVENT, &gp_cds_sched_context->ol_rx_event_flag); + wake_up_interruptible(&gp_cds_sched_context->ol_rx_wait_queue); + wait_for_completion(&gp_cds_sched_context->ol_rx_shutdown); + gp_cds_sched_context->ol_rx_thread = NULL; + cds_drop_rxpkt_by_staid(gp_cds_sched_context, WLAN_MAX_STA_COUNT); + cds_free_ol_rx_pkt_freeq(gp_cds_sched_context); + unregister_hotcpu_notifier(&cds_cpu_hotplug_notifier); + gp_cds_sched_context->cpu_hot_plug_notifier = NULL; +#endif + gp_cds_sched_context = NULL; + return QDF_STATUS_SUCCESS; +} /* cds_sched_close() */ + +/** + * cds_sched_init_mqs() - initialize the cds scheduler message queues + * @p_cds_sched_context: Pointer to the Scheduler Context. + * + * This api initializes the cds scheduler message queues. + * + * Return: QDF status + */ +QDF_STATUS cds_sched_init_mqs(p_cds_sched_context pSchedContext) +{ + QDF_STATUS vStatus = QDF_STATUS_SUCCESS; + /* Now intialize all the message queues */ + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: Initializing the WMA MC Message queue", __func__); + vStatus = cds_mq_init(&pSchedContext->wmaMcMq); + if (!QDF_IS_STATUS_SUCCESS(vStatus)) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: Failed to init WMA MC Message queue", __func__); + QDF_ASSERT(0); + return vStatus; + } + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: Initializing the PE MC Message queue", __func__); + vStatus = cds_mq_init(&pSchedContext->peMcMq); + if (!QDF_IS_STATUS_SUCCESS(vStatus)) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: Failed to init PE MC Message queue", __func__); + QDF_ASSERT(0); + return vStatus; + } + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: Initializing the SME MC Message queue", __func__); + vStatus = cds_mq_init(&pSchedContext->smeMcMq); + if (!QDF_IS_STATUS_SUCCESS(vStatus)) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: Failed to init SME MC Message queue", __func__); + QDF_ASSERT(0); + return vStatus; + } + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: Initializing the SYS MC Message queue", __func__); + vStatus = cds_mq_init(&pSchedContext->sysMcMq); + if (!QDF_IS_STATUS_SUCCESS(vStatus)) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: Failed to init SYS MC Message queue", __func__); + QDF_ASSERT(0); + return vStatus; + } + + return QDF_STATUS_SUCCESS; +} /* cds_sched_init_mqs() */ + +/** + * cds_sched_deinit_mqs() - Deinitialize the cds scheduler message queues + * @p_cds_sched_context: Pointer to the Scheduler Context. + * + * Return: none + */ +void cds_sched_deinit_mqs(p_cds_sched_context pSchedContext) +{ + /* Now de-intialize all message queues */ + + /* MC WMA */ + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO_HIGH, + "%s De-Initializing the WMA MC Message queue", __func__); + cds_mq_deinit(&pSchedContext->wmaMcMq); + /* MC PE */ + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO_HIGH, + "%s De-Initializing the PE MC Message queue", __func__); + cds_mq_deinit(&pSchedContext->peMcMq); + /* MC SME */ + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO_HIGH, + "%s De-Initializing the SME MC Message queue", __func__); + cds_mq_deinit(&pSchedContext->smeMcMq); + /* MC SYS */ + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO_HIGH, + "%s De-Initializing the SYS MC Message queue", __func__); + cds_mq_deinit(&pSchedContext->sysMcMq); + +} /* cds_sched_deinit_mqs() */ + +/** + * cds_sched_flush_mc_mqs() - flush all the MC thread message queues + * @pSchedContext: Pointer to global cds context + * + * Return: none + */ +void cds_sched_flush_mc_mqs(p_cds_sched_context pSchedContext) +{ + p_cds_msg_wrapper pMsgWrapper = NULL; + p_cds_contextType cds_ctx; + + /* Here each of the MC thread MQ shall be drained and returned to the + * Core. Before returning a wrapper to the Core, the CDS message shall + * be freed first + */ + QDF_TRACE(QDF_MODULE_ID_QDF, + QDF_TRACE_LEVEL_INFO, + ("Flushing the MC Thread message queue")); + + if (NULL == pSchedContext) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: pSchedContext is NULL", __func__); + return; + } + + cds_ctx = (p_cds_contextType) (pSchedContext->pVContext); + if (NULL == cds_ctx) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: cds_ctx is NULL", __func__); + return; + } + + /* Flush the SYS Mq */ + while (NULL != (pMsgWrapper = cds_mq_get(&pSchedContext->sysMcMq))) { + QDF_TRACE(QDF_MODULE_ID_QDF, + QDF_TRACE_LEVEL_INFO, + "%s: Freeing MC SYS message type %d ", __func__, + pMsgWrapper->pVosMsg->type); + cds_core_return_msg(pSchedContext->pVContext, pMsgWrapper); + } + /* Flush the WMA Mq */ + while (NULL != (pMsgWrapper = cds_mq_get(&pSchedContext->wmaMcMq))) { + if (pMsgWrapper->pVosMsg != NULL) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO, + "%s: Freeing MC WMA MSG message type %d", + __func__, pMsgWrapper->pVosMsg->type); + + wma_mc_discard_msg(pMsgWrapper->pVosMsg); + } + cds_core_return_msg(pSchedContext->pVContext, pMsgWrapper); + } + + /* Flush the PE Mq */ + while (NULL != (pMsgWrapper = cds_mq_get(&pSchedContext->peMcMq))) { + QDF_TRACE(QDF_MODULE_ID_QDF, + QDF_TRACE_LEVEL_INFO, + "%s: Freeing MC PE MSG message type %d", __func__, + pMsgWrapper->pVosMsg->type); + pe_free_msg(cds_ctx->pMACContext, + (tSirMsgQ *) pMsgWrapper->pVosMsg); + cds_core_return_msg(pSchedContext->pVContext, pMsgWrapper); + } + /* Flush the SME Mq */ + while (NULL != (pMsgWrapper = cds_mq_get(&pSchedContext->smeMcMq))) { + QDF_TRACE(QDF_MODULE_ID_QDF, + QDF_TRACE_LEVEL_INFO, + "%s: Freeing MC SME MSG message type %d", __func__, + pMsgWrapper->pVosMsg->type); + sme_free_msg(cds_ctx->pMACContext, pMsgWrapper->pVosMsg); + cds_core_return_msg(pSchedContext->pVContext, pMsgWrapper); + } +} /* cds_sched_flush_mc_mqs() */ + +/** + * get_cds_sched_ctxt() - get cds scheduler context + * + * Return: none + */ +p_cds_sched_context get_cds_sched_ctxt(void) +{ + /* Make sure that Vos Scheduler context has been initialized */ + if (gp_cds_sched_context == NULL) + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: gp_cds_sched_context == NULL", __func__); + + return gp_cds_sched_context; +} + +/** + * cds_ssr_protect_init() - initialize ssr protection debug functionality + * + * Return: + * void + */ +void cds_ssr_protect_init(void) +{ + int i = 0; + + spin_lock_init(&ssr_protect_lock); + + while (i < MAX_SSR_PROTECT_LOG) { + ssr_protect_log[i].func = NULL; + ssr_protect_log[i].free = true; + ssr_protect_log[i].pid = 0; + i++; + } + + INIT_LIST_HEAD(&shutdown_notifier_head); +} + +/** + * cds_print_external_threads() - print external threads stuck in driver + * + * Return: + * void + */ +void cds_print_external_threads(void) +{ + int i = 0; + unsigned long irq_flags; + + spin_lock_irqsave(&ssr_protect_lock, irq_flags); + + while (i < MAX_SSR_PROTECT_LOG) { + if (!ssr_protect_log[i].free) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "PID %d is executing %s", + ssr_protect_log[i].pid, + ssr_protect_log[i].func); + } + i++; + } + + spin_unlock_irqrestore(&ssr_protect_lock, irq_flags); +} + +/** + * cds_ssr_protect() - start ssr protection + * @caller_func: name of calling function. + * + * This function is called to keep track of active driver entry points + * + * Return: none + */ +void cds_ssr_protect(const char *caller_func) +{ + int count; + int i = 0; + bool status = false; + unsigned long irq_flags; + + count = atomic_inc_return(&ssr_protect_entry_count); + + spin_lock_irqsave(&ssr_protect_lock, irq_flags); + + while (i < MAX_SSR_PROTECT_LOG) { + if (ssr_protect_log[i].free) { + ssr_protect_log[i].func = caller_func; + ssr_protect_log[i].free = false; + ssr_protect_log[i].pid = current->pid; + status = true; + break; + } + i++; + } + + spin_unlock_irqrestore(&ssr_protect_lock, irq_flags); + + /* + * Dump the protect log at intervals if count is consistently growing. + * Long running functions should tend to dominate the protect log, so + * hopefully, dumping at multiples of log size will prevent spamming the + * logs while telling us which calls are taking a long time to finish. + */ + if (count >= MAX_SSR_PROTECT_LOG && count % MAX_SSR_PROTECT_LOG == 0) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "Protect Log overflow; Dumping contents:"); + cds_print_external_threads(); + } + + if (!status) + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s can not be protected; PID:%d, entry_count:%d", + caller_func, current->pid, count); +} + +/** + * cds_ssr_unprotect() - stop ssr protection + * @caller_func: name of calling function. + * + * Return: none + */ +void cds_ssr_unprotect(const char *caller_func) +{ + int count; + int i = 0; + bool status = false; + unsigned long irq_flags; + + count = atomic_dec_return(&ssr_protect_entry_count); + + spin_lock_irqsave(&ssr_protect_lock, irq_flags); + + while (i < MAX_SSR_PROTECT_LOG) { + if (!ssr_protect_log[i].free) { + if ((ssr_protect_log[i].pid == current->pid) && + !strcmp(ssr_protect_log[i].func, caller_func)) { + ssr_protect_log[i].func = NULL; + ssr_protect_log[i].free = true; + ssr_protect_log[i].pid = 0; + status = true; + break; + } + } + i++; + } + + spin_unlock_irqrestore(&ssr_protect_lock, irq_flags); + + if (!status) + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s was not protected; PID:%d, entry_count:%d", + caller_func, current->pid, count); +} + +/** + * cds_shutdown_notifier_register() - Register for shutdown notification + * @cb : Call back to be called + * @priv : Private pointer to be passed back to call back + * + * During driver remove or shutdown (recovery), external threads might be stuck + * waiting on some event from firmware at lower layers. Remove or shutdown can't + * proceed till the thread completes to avoid any race condition. Call backs can + * be registered here to get early notification of remove or shutdown so that + * waiting thread can be unblocked and hence remove or shutdown can proceed + * further as waiting there may not make sense when FW may already have been + * down. + * + * This is intended for early notification of remove() or shutdown() only so + * that lower layers can take care of stuffs like external waiting thread. + * + * Return: CDS status + */ +QDF_STATUS cds_shutdown_notifier_register(void (*cb)(void *priv), void *priv) +{ + struct shutdown_notifier *notifier; + unsigned long irq_flags; + + notifier = qdf_mem_malloc(sizeof(*notifier)); + + if (notifier == NULL) + return QDF_STATUS_E_NOMEM; + + /* + * This logic can be simpilfied if there is separate state maintained + * for shutdown and reinit. Right now there is only recovery in progress + * state and it doesn't help to check against it as during reinit some + * of the modules may need to register the call backs. + * For now this logic added to avoid notifier registration happen while + * this function is trying to call the call back with the notification. + */ + spin_lock_irqsave(&ssr_protect_lock, irq_flags); + if (notifier_state == NOTIFIER_STATE_NOTIFYING) { + spin_unlock_irqrestore(&ssr_protect_lock, irq_flags); + qdf_mem_free(notifier); + return -EINVAL; + } + + notifier->cb = cb; + notifier->priv = priv; + + list_add_tail(¬ifier->list, &shutdown_notifier_head); + spin_unlock_irqrestore(&ssr_protect_lock, irq_flags); + + return 0; +} + +/** + * cds_shutdown_notifier_purge() - Purge all the notifiers + * + * Shutdown notifiers are added to provide the early notification of remove or + * shutdown being initiated. Adding this API to purge all the registered call + * backs as they are not useful any more while all the lower layers are being + * shutdown. + * + * Return: None + */ +void cds_shutdown_notifier_purge(void) +{ + struct shutdown_notifier *notifier, *temp; + unsigned long irq_flags; + + spin_lock_irqsave(&ssr_protect_lock, irq_flags); + list_for_each_entry_safe(notifier, temp, + &shutdown_notifier_head, list) { + list_del(¬ifier->list); + spin_unlock_irqrestore(&ssr_protect_lock, irq_flags); + + qdf_mem_free(notifier); + + spin_lock_irqsave(&ssr_protect_lock, irq_flags); + } + + spin_unlock_irqrestore(&ssr_protect_lock, irq_flags); +} + +/** + * cds_shutdown_notifier_call() - Call shutdown notifier call back + * + * Call registered shutdown notifier call back to indicate about remove or + * shutdown. + */ +static void cds_shutdown_notifier_call(void) +{ + struct shutdown_notifier *notifier; + unsigned long irq_flags; + + spin_lock_irqsave(&ssr_protect_lock, irq_flags); + notifier_state = NOTIFIER_STATE_NOTIFYING; + + list_for_each_entry(notifier, &shutdown_notifier_head, list) { + spin_unlock_irqrestore(&ssr_protect_lock, irq_flags); + + notifier->cb(notifier->priv); + + spin_lock_irqsave(&ssr_protect_lock, irq_flags); + } + + notifier_state = NOTIFIER_STATE_NONE; + spin_unlock_irqrestore(&ssr_protect_lock, irq_flags); +} + +/** + * cds_wait_for_external_threads_completion() - wait for external threads + * completion before proceeding further + * @caller_func: name of calling function. + * + * Return: true if there is no active entry points in driver + * false if there is at least one active entry in driver + */ +bool cds_wait_for_external_threads_completion(const char *caller_func) +{ + int count = MAX_SSR_WAIT_ITERATIONS; + int r; + + cds_shutdown_notifier_call(); + + while (count) { + + r = atomic_read(&ssr_protect_entry_count); + + if (!r) + break; + + if (--count) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: Waiting for %d active entry points to exit", + __func__, r); + msleep(SSR_WAIT_SLEEP_TIME); + if (count == (MAX_SSR_WAIT_ITERATIONS/2)) { + QDF_TRACE(QDF_MODULE_ID_QDF, + QDF_TRACE_LEVEL_ERROR, + "%s: in middle of waiting for active entry points:", + __func__); + cds_print_external_threads(); + } + } + } + + /* at least one external thread is executing */ + if (!count) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "Timed-out waiting for active entry points:"); + cds_print_external_threads(); + return false; + } + + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO, + "Allowing SSR/Driver unload for %s", caller_func); + + return true; +} + +int cds_return_external_threads_count(void) +{ + return atomic_read(&ssr_protect_entry_count); +} + +/** + * cds_get_gfp_flags(): get GFP flags + * + * Based on the scheduled context, return GFP flags + * Return: gfp flags + */ +int cds_get_gfp_flags(void) +{ + int flags = GFP_KERNEL; + + if (in_interrupt() || in_atomic() || irqs_disabled()) + flags = GFP_ATOMIC; + + return flags; +} diff --git a/drivers/staging/qcacld-3.0/core/cds/src/cds_utils.c b/drivers/staging/qcacld-3.0/core/cds/src/cds_utils.c new file mode 100644 index 0000000000000000000000000000000000000000..8eaa2f501d4acf0ed0b4f4423a0e22f6aa3b5f92 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/cds/src/cds_utils.c @@ -0,0 +1,606 @@ +/* + * Copyright (c) 2014-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/*============================================================================ + FILE: cds_utils.c + + OVERVIEW: This source file contains definitions for CDS crypto APIs + The four APIs mentioned in this file are used for + initializing, and de-initializing a crypto context, and + obtaining truly random data (for keys), as well as + SHA1 HMAC, and AES encrypt and decrypt routines. + + The routines include: + cds_crypto_init() - Initializes Crypto module + cds_crypto_deinit() - De-initializes Crypto module + cds_rand_get_bytes() - Generates random byte + + DEPENDENCIES: + ============================================================================*/ + +/*---------------------------------------------------------------------------- + * Include Files + * -------------------------------------------------------------------------*/ + +#include "qdf_trace.h" +#include "cds_utils.h" +#include "qdf_mem.h" +#include "cds_crypto.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cds_ieee80211_common.h" +/*---------------------------------------------------------------------------- + * Preprocessor Definitions and Constants + * -------------------------------------------------------------------------*/ +#define AAD_LEN 20 +#define IV_SIZE_AES_128 16 +#define CMAC_IPN_LEN 6 +#define CMAC_TLEN 8 /* CMAC TLen = 64 bits (8 octets) */ + +/*---------------------------------------------------------------------------- + * Type Declarations + * -------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------- + * Global Data Definitions + * -------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------- + * Static Variable Definitions + * -------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------- + Function Definitions and Documentation + * -------------------------------------------------------------------------*/ +#ifdef WLAN_FEATURE_11W +static inline void xor_128(const u8 *a, const u8 *b, u8 *out) +{ + u8 i; + + for (i = 0; i < AES_BLOCK_SIZE; i++) + out[i] = a[i] ^ b[i]; +} + +static inline void leftshift_onebit(const u8 *input, u8 *output) +{ + int i, overflow = 0; + + for (i = (AES_BLOCK_SIZE - 1); i >= 0; i--) { + output[i] = input[i] << 1; + output[i] |= overflow; + overflow = (input[i] & 0x80) ? 1 : 0; + } + return; +} + +static void generate_subkey(struct crypto_cipher *tfm, u8 *k1, u8 *k2) +{ + u8 l[AES_BLOCK_SIZE], tmp[AES_BLOCK_SIZE]; + u8 const_rb[AES_BLOCK_SIZE] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x87 + }; + u8 const_zero[AES_BLOCK_SIZE] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + + crypto_cipher_encrypt_one(tfm, l, const_zero); + + if ((l[0] & 0x80) == 0) { /* If MSB(l) = 0, then k1 = l << 1 */ + leftshift_onebit(l, k1); + } else { /* Else k1 = ( l << 1 ) (+) Rb */ + leftshift_onebit(l, tmp); + xor_128(tmp, const_rb, k1); + } + + if ((k1[0] & 0x80) == 0) { + leftshift_onebit(k1, k2); + } else { + leftshift_onebit(k1, tmp); + xor_128(tmp, const_rb, k2); + } +} + +static inline void padding(u8 *lastb, u8 *pad, u16 length) +{ + u8 j; + + /* original last block */ + for (j = 0; j < AES_BLOCK_SIZE; j++) { + if (j < length) + pad[j] = lastb[j]; + else if (j == length) + pad[j] = 0x80; + else + pad[j] = 0x00; + } +} + +static void cds_cmac_calc_mic(struct crypto_cipher *tfm, + u8 *m, u16 length, u8 *mac) +{ + u8 x[AES_BLOCK_SIZE], y[AES_BLOCK_SIZE]; + u8 m_last[AES_BLOCK_SIZE], padded[AES_BLOCK_SIZE]; + u8 k1[AES_KEYSIZE_128], k2[AES_KEYSIZE_128]; + int cmpBlk; + int i, nBlocks = (length + 15) / AES_BLOCK_SIZE; + + generate_subkey(tfm, k1, k2); + + if (nBlocks == 0) { + nBlocks = 1; + cmpBlk = 0; + } else { + cmpBlk = ((length % AES_BLOCK_SIZE) == 0) ? 1 : 0; + } + + if (cmpBlk) { /* Last block is complete block */ + xor_128(&m[AES_BLOCK_SIZE * (nBlocks - 1)], k1, m_last); + } else { /* Last block is not complete block */ + padding(&m[AES_BLOCK_SIZE * (nBlocks - 1)], padded, + length % AES_BLOCK_SIZE); + xor_128(padded, k2, m_last); + } + + for (i = 0; i < AES_BLOCK_SIZE; i++) + x[i] = 0; + + for (i = 0; i < (nBlocks - 1); i++) { + xor_128(x, &m[AES_BLOCK_SIZE * i], y); /* y = Mi (+) x */ + crypto_cipher_encrypt_one(tfm, x, y); /* x = AES-128(KEY, y) */ + } + + xor_128(x, m_last, y); + crypto_cipher_encrypt_one(tfm, x, y); + + memcpy(mac, x, CMAC_TLEN); +} +#endif + +/*-------------------------------------------------------------------------- + + \brief cds_crypto_init() - Initializes Crypto module + + The cds_crypto_init() function initializes Crypto module. + + \param phCryptProv - pointer to the Crypt handle + + \return QDF_STATUS_SUCCESS - Successfully generated random memory. + + QDF_STATUS_E_FAULT - pbBuf is an invalid pointer. + + QDF_STATUS_E_FAILURE - default return value if it fails due to + unknown reasons + + ***QDF_STATUS_E_RESOURCES - System resources (other than memory) + are unavailable + \sa + + ( *** return value not considered yet ) + --------------------------------------------------------------------------*/ +QDF_STATUS cds_crypto_init(uint32_t *phCryptProv) +{ + QDF_STATUS uResult = QDF_STATUS_E_FAILURE; + + /* This implementation doesn't require a crypto context */ + *phCryptProv = 0; + uResult = QDF_STATUS_SUCCESS; + return uResult; +} + +QDF_STATUS cds_crypto_deinit(uint32_t hCryptProv) +{ + QDF_STATUS uResult = QDF_STATUS_E_FAILURE; + + /* CryptReleaseContext succeeded */ + uResult = QDF_STATUS_SUCCESS; + + return uResult; +} + +/*-------------------------------------------------------------------------- + + \brief cds_rand_get_bytes() - Generates random byte + + The cds_rand_get_bytes() function generate random bytes. + + Buffer should be allocated before calling cds_rand_get_bytes(). + + Attempting to initialize an already initialized lock results in + a failure. + + \param lock - pointer to the opaque lock object to initialize + + \return QDF_STATUS_SUCCESS - Successfully generated random memory. + + QDF_STATUS_E_FAULT - pbBuf is an invalid pointer. + + QDF_STATUS_E_FAILURE - default return value if it fails due to + unknown reasons + + ***QDF_STATUS_E_RESOURCES - System resources (other than memory) + are unavailable + \sa + + ( *** return value not considered yet ) + --------------------------------------------------------------------------*/ +QDF_STATUS +cds_rand_get_bytes(uint32_t cryptHandle, uint8_t *pbBuf, uint32_t numBytes) +{ + QDF_STATUS uResult = QDF_STATUS_E_FAILURE; + + /* check for invalid pointer */ + if (NULL == pbBuf) { + uResult = QDF_STATUS_E_FAULT; + return uResult; + } + + get_random_bytes(pbBuf, numBytes); + /* "Random sequence generated." */ + uResult = QDF_STATUS_SUCCESS; + return uResult; +} + +#ifdef WLAN_FEATURE_11W +uint8_t cds_get_mmie_size(void) +{ + return sizeof(struct ieee80211_mmie); +} + +/*-------------------------------------------------------------------------- + + \brief cds_increase_seq() - Increase the IPN aka Sequence number by one unit + + The cds_increase_seq() function increases the IPN by one unit. + + \param ipn - pointer to the IPN aka Sequence number [6 bytes] + + --------------------------------------------------------------------------*/ +static void cds_increase_seq(uint8_t *ipn) +{ + uint64_t value = 0; + if (ipn) { + value = (0xffffffffffff) & (*((uint64_t *) ipn)); + value = value + 1; + qdf_mem_copy(ipn, &value, IEEE80211_MMIE_IPNLEN); + } +} + +/*-------------------------------------------------------------------------- + + \brief cds_attach_mmie() - attches the complete MMIE at the end of frame + + The cds_attach_mmie() calculates the entire MMIE and attaches at the end + of Broadcast/Multicast robust management frames. + + \param igtk - pointer group key which will be used to calculate + the 8 byte MIC. + \param ipn - pointer ipn, it is also known as sequence number + \param key_id - key identication number + \param frm - pointer to the start of the frame. + \param efrm - pointer to the end of the frame. + \param frmLen - size of the entire frame. + + \return - this function will return true on success and false on + failure. + + --------------------------------------------------------------------------*/ + +bool +cds_attach_mmie(uint8_t *igtk, uint8_t *ipn, uint16_t key_id, + uint8_t *frm, uint8_t *efrm, uint16_t frmLen) +{ + struct ieee80211_mmie *mmie; + struct ieee80211_frame *wh; + uint8_t aad[AAD_LEN], mic[CMAC_TLEN], *input = NULL; + uint8_t previous_ipn[IEEE80211_MMIE_IPNLEN] = { 0 }; + uint16_t nBytes = 0; + int ret = 0; + struct crypto_cipher *tfm; + + /* This is how received frame look like + * + * <------------frmLen----------------------------> + * + * +---------------+----------------------+-------+ + * | 802.11 HEADER | Management framebody | MMIE | + * +---------------+----------------------+-------+ + * ^ + * | + * efrm + * This is how MMIE from above frame look like + * + * + * <------------ 18 Bytes-----------------------------> + * +--------+---------+---------+-----------+---------+ + * |Element | Length | Key id | IPN | MIC | + * | id | | | | | + * +--------+---------+---------+-----------+---------+ + * Octet 1 1 2 6 8 + * + */ + + /* Check if frame is invalid length */ + if (((efrm - frm) != frmLen) || (frmLen < sizeof(*wh))) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid frame length", __func__); + return false; + } + mmie = (struct ieee80211_mmie *)(efrm - sizeof(*mmie)); + + /* Copy Element id */ + mmie->element_id = IEEE80211_ELEMID_MMIE; + + /* Copy Length */ + mmie->length = sizeof(*mmie) - 2; + + /* Copy Key id */ + mmie->key_id = key_id; + + /* + * In case of error, revert back to original IPN + * to do that copy the original IPN into previous_ipn + */ + qdf_mem_copy(&previous_ipn[0], ipn, IEEE80211_MMIE_IPNLEN); + cds_increase_seq(ipn); + qdf_mem_copy(mmie->sequence_number, ipn, IEEE80211_MMIE_IPNLEN); + + /* + * Calculate MIC and then copy + */ + tfm = cds_crypto_alloc_cipher("aes", 0, CRYPTO_ALG_ASYNC); + if (IS_ERR(tfm)) { + ret = PTR_ERR(tfm); + tfm = NULL; + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: crypto_alloc_cipher failed (%d)", __func__, ret); + goto err_tfm; + } + + ret = crypto_cipher_setkey(tfm, igtk, AES_KEYSIZE_128); + if (ret) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: crypto_cipher_setkey failed (%d)", __func__, + ret); + goto err_tfm; + } + + /* Construct AAD */ + wh = (struct ieee80211_frame *)frm; + + /* Generate BIP AAD: FC(masked) || A1 || A2 || A3 */ + + /* FC type/subtype */ + aad[0] = wh->i_fc[0]; + /* Mask FC Retry, PwrMgt, MoreData flags to zero */ + aad[1] = wh->i_fc[1] & ~(IEEE80211_FC1_RETRY | IEEE80211_FC1_PWR_MGT | + IEEE80211_FC1_MORE_DATA); + /* A1 || A2 || A3 */ + qdf_mem_copy(aad + 2, wh->i_addr_all, 3 * IEEE80211_ADDR_LEN); + + /* MIC = AES-128-CMAC(IGTK, AAD || Management Frame Body || MMIE, 64) */ + nBytes = AAD_LEN + (frmLen - sizeof(struct ieee80211_frame)); + input = (uint8_t *) qdf_mem_malloc(nBytes); + if (NULL == input) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s: Memory allocation failed", __func__); + ret = QDF_STATUS_E_NOMEM; + goto err_tfm; + } + + /* + * Copy the AAD, Management frame body, and + * MMIE with 8 bit MIC zeroed out + */ + qdf_mem_copy(input, aad, AAD_LEN); + /* Copy Management Frame Body and MMIE without MIC */ + qdf_mem_copy(input + AAD_LEN, + (uint8_t *) (efrm - + (frmLen - sizeof(struct ieee80211_frame))), + nBytes - AAD_LEN - CMAC_TLEN); + + cds_cmac_calc_mic(tfm, input, nBytes, mic); + qdf_mem_free(input); + + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO_HIGH, + "CMAC(T)= %02X %02X %02X %02X %02X %02X %02X %02X", + mic[0], mic[1], mic[2], mic[3], + mic[4], mic[5], mic[6], mic[7]); + qdf_mem_copy(mmie->mic, mic, IEEE80211_MMIE_MICLEN); + +err_tfm: + if (ret) { + qdf_mem_copy(ipn, previous_ipn, IEEE80211_MMIE_IPNLEN); + } + + if (tfm) + cds_crypto_free_cipher(tfm); + return !ret ? true : false; +} + +bool +cds_is_mmie_valid(uint8_t *igtk, uint8_t *ipn, uint8_t *frm, uint8_t *efrm) +{ + struct ieee80211_mmie *mmie; + struct ieee80211_frame *wh; + uint8_t *rx_ipn, aad[AAD_LEN], mic[CMAC_TLEN], *input; + uint16_t nBytes = 0; + int ret = 0; + struct crypto_cipher *tfm; + + /* Check if frame is invalid length */ + if ((efrm < frm) || ((efrm - frm) < sizeof(*wh))) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "Invalid frame length"); + return false; + } + + mmie = (struct ieee80211_mmie *)(efrm - sizeof(*mmie)); + + /* Check Element ID */ + if ((mmie->element_id != IEEE80211_ELEMID_MMIE) || + (mmie->length != (sizeof(*mmie) - 2))) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "IE is not Mgmt MIC IE or Invalid length"); + /* IE is not Mgmt MIC IE or invalid length */ + return false; + } + + /* Validate IPN */ + rx_ipn = mmie->sequence_number; + if (OS_MEMCMP(rx_ipn, ipn, CMAC_IPN_LEN) <= 0) { + /* Replay error */ + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "Replay error mmie ipn %02X %02X %02X %02X %02X %02X" + " drvr ipn %02X %02X %02X %02X %02X %02X", + rx_ipn[0], rx_ipn[1], rx_ipn[2], rx_ipn[3], rx_ipn[4], + rx_ipn[5], ipn[0], ipn[1], ipn[2], ipn[3], ipn[4], + ipn[5]); + return false; + } + tfm = cds_crypto_alloc_cipher("aes", 0, CRYPTO_ALG_ASYNC); + if (IS_ERR(tfm)) { + ret = PTR_ERR(tfm); + tfm = NULL; + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "crypto_alloc_cipher failed (%d)", ret); + goto err_tfm; + } + + ret = crypto_cipher_setkey(tfm, igtk, AES_KEYSIZE_128); + if (ret) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "crypto_cipher_setkey failed (%d)", ret); + goto err_tfm; + } + + /* Construct AAD */ + wh = (struct ieee80211_frame *)frm; + + /* Generate BIP AAD: FC(masked) || A1 || A2 || A3 */ + + /* FC type/subtype */ + aad[0] = wh->i_fc[0]; + /* Mask FC Retry, PwrMgt, MoreData flags to zero */ + aad[1] = wh->i_fc[1] & ~(IEEE80211_FC1_RETRY | IEEE80211_FC1_PWR_MGT | + IEEE80211_FC1_MORE_DATA); + /* A1 || A2 || A3 */ + qdf_mem_copy(aad + 2, wh->i_addr_all, 3 * IEEE80211_ADDR_LEN); + + /* MIC = AES-128-CMAC(IGTK, AAD || Management Frame Body || MMIE, 64) */ + nBytes = AAD_LEN + (efrm - (uint8_t *) (wh + 1)); + input = (uint8_t *) qdf_mem_malloc(nBytes); + if (NULL == input) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "Memory allocation failed"); + ret = QDF_STATUS_E_NOMEM; + goto err_tfm; + } + + /* Copy the AAD, MMIE with 8 bit MIC zeroed out */ + qdf_mem_copy(input, aad, AAD_LEN); + qdf_mem_copy(input + AAD_LEN, (uint8_t *) (wh + 1), + nBytes - AAD_LEN - CMAC_TLEN); + + cds_cmac_calc_mic(tfm, input, nBytes, mic); + qdf_mem_free(input); + + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "CMAC(T)= %02X %02X %02X %02X %02X %02X %02X %02X", + mic[0], mic[1], mic[2], mic[3], + mic[4], mic[5], mic[6], mic[7]); + + if (OS_MEMCMP(mic, mmie->mic, CMAC_TLEN) != 0) { + /* MMIE MIC mismatch */ + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "BC/MC MGMT frame MMIE MIC check Failed" + " rmic %02X %02X %02X %02X %02X %02X %02X %02X" + " cmic %02X %02X %02X %02X %02X %02X %02X %02X", + mmie->mic[0], mmie->mic[1], mmie->mic[2], + mmie->mic[3], mmie->mic[4], mmie->mic[5], + mmie->mic[6], mmie->mic[7], mic[0], mic[1], mic[2], + mic[3], mic[4], mic[5], mic[6], mic[7]); + return false; + } + + /* Update IPN */ + qdf_mem_copy(ipn, rx_ipn, CMAC_IPN_LEN); + +err_tfm: + if (tfm) + cds_crypto_free_cipher(tfm); + + return !ret ? true : false; +} + +#endif /* WLAN_FEATURE_11W */ + +uint32_t cds_chan_to_freq(uint8_t chan) +{ + if (chan < CDS_24_GHZ_CHANNEL_14) /* ch 0 - ch 13 */ + return CDS_24_GHZ_BASE_FREQ + chan * CDS_CHAN_SPACING_5MHZ; + else if (chan == CDS_24_GHZ_CHANNEL_14) /* ch 14 */ + return CDS_CHAN_14_FREQ; + else if (chan < CDS_24_GHZ_CHANNEL_27) /* ch 15 - ch 26 */ + return CDS_CHAN_15_FREQ + + (chan - CDS_24_GHZ_CHANNEL_15) * CDS_CHAN_SPACING_20MHZ; + else if (chan == CDS_5_GHZ_CHANNEL_170) + return CDS_CHAN_170_FREQ; + else + return CDS_5_GHZ_BASE_FREQ + chan * CDS_CHAN_SPACING_5MHZ; +} + +uint8_t cds_freq_to_chan(uint32_t freq) +{ + uint8_t chan; + + if (freq > CDS_24_GHZ_BASE_FREQ && freq < CDS_CHAN_14_FREQ) + chan = ((freq - CDS_24_GHZ_BASE_FREQ) / CDS_CHAN_SPACING_5MHZ); + else if (freq == CDS_CHAN_14_FREQ) + chan = CDS_24_GHZ_CHANNEL_14; + else if ((freq > CDS_24_GHZ_BASE_FREQ) && (freq < CDS_5_GHZ_BASE_FREQ)) + chan = (((freq - CDS_CHAN_15_FREQ) / CDS_CHAN_SPACING_20MHZ) + + CDS_24_GHZ_CHANNEL_15); + else + chan = (freq - CDS_5_GHZ_BASE_FREQ) / CDS_CHAN_SPACING_5MHZ; + return chan; +} + +enum cds_band_type cds_chan_to_band(uint32_t chan) +{ + if (chan <= CDS_24_GHZ_CHANNEL_14) + return CDS_BAND_2GHZ; + + return CDS_BAND_5GHZ; +} diff --git a/drivers/staging/qcacld-3.0/core/cds/src/i_cds_packet.h b/drivers/staging/qcacld-3.0/core/cds/src/i_cds_packet.h new file mode 100644 index 0000000000000000000000000000000000000000..c21c70ac5bacf4058870d6ebcfc3c7b6cfe6755a --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/cds/src/i_cds_packet.h @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2014-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#if !defined(__I_CDS_PACKET_H) +#define __I_CDS_PACKET_H + +/**========================================================================= + + \file i_cds_packet.h + + \brief Connectivity driver services network packet APIs + + Network Protocol packet/buffer internal include file + + ========================================================================*/ + +/*-------------------------------------------------------------------------- + Include Files + ------------------------------------------------------------------------*/ +#include "qdf_types.h" +/** + * Rx Packet Struct + * Buffer for the packet received from WMA has pointers to 802.11 + * frame fields and additional information based on the type of frame. + * @channel: Channel number + * @snr: Signal to noise ratio + * @rssi: Received signal strength indicator, normalized to -96 dBm as + * normal noise floor by adding -96 to snr. All the configured + * thresholds in the driver assume that noise floor is -96 dBm. + * @timestamp: System timestamp when frame was received. Set to jiffies. + * @mpdu_hdr_ptr: Pointer to beginning of 802.11 MPDU + * @mpdu_data_ptr: Pointer to beginning of payload + * @mpdu_len: Length of 802.11 MPDU + * @mpdu_hdr_len: Length of 802.11 MPDU header + * @mpdu_data_len: Length of 802.11 MPDU payload + * @offloadScanLearn: Bit set to 1 for beacons received during roaming scan + * @roamCandidateInd: Bit set to 1 when roaming candidate is found by fw + * @scan: Bit set to 1 if packet received during scanning + * @scan_src: Source of scan + * @dpuFeedback: DPU feedback for frame + * @sessionId: PE session + * @tsf_delta: Delta between tsf in frame and local value of tsf + * @rssi_raw: rssi based on actual noise floor in hardware. + */ +typedef struct { + uint8_t channel; + uint8_t snr; + uint32_t rssi; + uint32_t timestamp; + uint8_t *mpdu_hdr_ptr; + uint8_t *mpdu_data_ptr; + uint32_t mpdu_len; + uint32_t mpdu_hdr_len; + uint32_t mpdu_data_len; + uint8_t offloadScanLearn:1; + uint8_t roamCandidateInd:1; + uint8_t scan:1; + uint8_t scan_src; + uint8_t dpuFeedback; + uint8_t sessionId; + uint32_t tsf_delta; + uint32_t rssi_raw; +} t_packetmeta, *tp_packetmeta; + +/* implementation specific cds packet type */ +struct cds_pkt_t { + /* Packet Meta Information */ + t_packetmeta pkt_meta; + + /* Pointer to Packet */ + void *pkt_buf; +}; + +#endif /* !defined( __I_CDS_PACKET_H ) */ diff --git a/drivers/staging/qcacld-3.0/core/cds/src/queue.h b/drivers/staging/qcacld-3.0/core/cds/src/queue.h new file mode 100644 index 0000000000000000000000000000000000000000..73200429eaf77516184b1179a3533efede432dca --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/cds/src/queue.h @@ -0,0 +1,571 @@ +/* + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)queue.h 8.5 (Berkeley) 8/20/94 + * $FreeBSD: src/sys/sys/queue.h,v 1.58 2004/04/07 04:19:49 imp Exp $ + */ + +#if !defined(__NetBSD__) +#ifndef _SYS_QUEUE_H_ +#define _SYS_QUEUE_H_ + +/* + * This file defines four types of data structures: singly-linked lists, + * singly-linked tail queues, lists and tail queues. + * + * A singly-linked list is headed by a single forward pointer. The elements + * are singly linked for minimum space and pointer manipulation overhead at + * the expense of O(n) removal for arbitrary elements. New elements can be + * added to the list after an existing element or at the head of the list. + * Elements being removed from the head of the list should use the explicit + * macro for this purpose for optimum efficiency. A singly-linked list may + * only be traversed in the forward direction. Singly-linked lists are ideal + * for applications with large datasets and few or no removals or for + * implementing a LIFO queue. + * + * A singly-linked tail queue is headed by a pair of pointers, one to the + * head of the list and the other to the tail of the list. The elements are + * singly linked for minimum space and pointer manipulation overhead at the + * expense of O(n) removal for arbitrary elements. New elements can be added + * to the list after an existing element, at the head of the list, or at the + * end of the list. Elements being removed from the head of the tail queue + * should use the explicit macro for this purpose for optimum efficiency. + * A singly-linked tail queue may only be traversed in the forward direction. + * Singly-linked tail queues are ideal for applications with large datasets + * and few or no removals or for implementing a FIFO queue. + * + * A list is headed by a single forward pointer (or an array of forward + * pointers for a hash table header). The elements are doubly linked + * so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before + * or after an existing element or at the head of the list. A list + * may only be traversed in the forward direction. + * + * A tail queue is headed by a pair of pointers, one to the head of the + * list and the other to the tail of the list. The elements are doubly + * linked so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before or + * after an existing element, at the head of the list, or at the end of + * the list. A tail queue may be traversed in either direction. + * + * For details on the use of these macros, see the queue(3) manual page. + * + * + * SLIST LIST STAILQ TAILQ + * _HEAD + + + + + * _HEAD_INITIALIZER + + + + + * _ENTRY + + + + + * _INIT + + + + + * _EMPTY + + + + + * _FIRST + + + + + * _NEXT + + + + + * _PREV - - - + + * _LAST - - + + + * _FOREACH + + + + + * _FOREACH_SAFE + + + + + * _FOREACH_REVERSE - - - + + * _FOREACH_REVERSE_SAFE - - - + + * _INSERT_HEAD + + + + + * _INSERT_BEFORE - + - + + * _INSERT_AFTER + + + + + * _INSERT_TAIL - - + + + * _CONCAT - - + + + * _REMOVE_HEAD + - + - + * _REMOVE + + + + + * + */ +#define QUEUE_MACRO_DEBUG 0 +#if QUEUE_MACRO_DEBUG +/* Store the last 2 places the queue element or head was altered */ +struct qm_trace { + char *lastfile; + int lastline; + char *prevfile; + int prevline; +}; + +#define TRACEBUF struct qm_trace trace; +#define TRASHIT(x) do {(x) = (void *)NULL; } while (0) + +#define QMD_TRACE_HEAD(head) do { \ + (head)->trace.prevline = (head)->trace.lastline; \ + (head)->trace.prevfile = (head)->trace.lastfile; \ + (head)->trace.lastline = __LINE__; \ + (head)->trace.lastfile = __FILE__; \ +} while (0) + +#define QMD_TRACE_ELEM(elem) do { \ + (elem)->trace.prevline = (elem)->trace.lastline; \ + (elem)->trace.prevfile = (elem)->trace.lastfile; \ + (elem)->trace.lastline = __LINE__; \ + (elem)->trace.lastfile = __FILE__; \ +} while (0) + +#else +#define QMD_TRACE_ELEM(elem) +#define QMD_TRACE_HEAD(head) +#define TRACEBUF +#define TRASHIT(x) do {(x) = (void *)0; } while (0) +#endif /* QUEUE_MACRO_DEBUG */ + +#ifdef ATHR_RNWF +/* NDIS contains a defn for SLIST_ENTRY and SINGLE_LIST_ENTRY */ +#endif + +/* + * Singly-linked List declarations. + */ +#define SLIST_HEAD(name, type) \ + struct name { \ + struct type *slh_first; /* first element */ \ + } + +#define SLIST_HEAD_INITIALIZER(head) \ + { NULL } + +#define SING_LIST_ENTRY(type) \ + struct { \ + struct type *sle_next; /* next element */ \ + } + +/* + * Singly-linked List functions. + */ +#define SLIST_EMPTY(head) ((head)->slh_first == NULL) + +#define SLIST_FIRST(head) ((head)->slh_first) + +#define SLIST_FOREACH(var, head, field) \ + for ((var) = SLIST_FIRST((head)); \ + (var); \ + (var) = SLIST_NEXT((var), field)) + +#define SLIST_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = SLIST_FIRST((head)); \ + (var) && ((tvar) = SLIST_NEXT((var), field), 1); \ + (var) = (tvar)) + +#define SLIST_FOREACH_PREVPTR(var, varp, head, field) \ + for ((varp) = &SLIST_FIRST((head)); \ + ((var) = *(varp)) != NULL; \ + (varp) = &SLIST_NEXT((var), field)) + +#define SLIST_INIT(head) do { \ + SLIST_FIRST((head)) = NULL; \ +} while (0) + +#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \ + SLIST_NEXT((elm), field) = SLIST_NEXT((slistelm), field); \ + SLIST_NEXT((slistelm), field) = (elm); \ +} while (0) + +#define SLIST_INSERT_HEAD(head, elm, field) do { \ + SLIST_NEXT((elm), field) = SLIST_FIRST((head)); \ + SLIST_FIRST((head)) = (elm); \ +} while (0) + +#define SLIST_NEXT(elm, field) ((elm)->field.sle_next) + +#define SLIST_REMOVE(head, elm, type, field) do { \ + if (SLIST_FIRST((head)) == (elm)) { \ + SLIST_REMOVE_HEAD((head), field); \ + } \ + else { \ + struct type *curelm = SLIST_FIRST((head)); \ + while (SLIST_NEXT(curelm, field) != (elm)) \ + curelm = SLIST_NEXT(curelm, field); \ + SLIST_NEXT(curelm, field) = \ + SLIST_NEXT(SLIST_NEXT(curelm, field), field); \ + } \ +} while (0) + +#define SLIST_REMOVE_HEAD(head, field) do { \ + SLIST_FIRST((head)) = SLIST_NEXT(SLIST_FIRST((head)), field); \ +} while (0) + +/* + * Singly-linked Tail queue declarations. + */ +#define STAILQ_HEAD(name, type) \ + struct name { \ + struct type *stqh_first; /* first element */ \ + struct type **stqh_last; /* addr of last next element */ \ + } + +#define STAILQ_HEAD_INITIALIZER(head) \ + { NULL, &(head).stqh_first } + +#define STAILQ_ENTRY(type) \ + struct { \ + struct type *stqe_next; /* next element */ \ + } + +/* + * Singly-linked Tail queue functions. + */ +#define STAILQ_CONCAT(head1, head2) do { \ + if (!STAILQ_EMPTY((head2))) { \ + *(head1)->stqh_last = (head2)->stqh_first; \ + (head1)->stqh_last = (head2)->stqh_last; \ + STAILQ_INIT((head2)); \ + } \ +} while (0) + +#define STAILQ_EMPTY(head) ((head)->stqh_first == NULL) + +#define STAILQ_FIRST(head) ((head)->stqh_first) + +#define STAILQ_FOREACH(var, head, field) \ + for((var) = STAILQ_FIRST((head)); \ + (var); \ + (var) = STAILQ_NEXT((var), field)) + +#define STAILQ_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = STAILQ_FIRST((head)); \ + (var) && ((tvar) = STAILQ_NEXT((var), field), 1); \ + (var) = (tvar)) + +#define STAILQ_INIT(head) do { \ + STAILQ_FIRST((head)) = NULL; \ + (head)->stqh_last = &STAILQ_FIRST((head)); \ +} while (0) + +#define STAILQ_INSERT_AFTER(head, tqelm, elm, field) do { \ + if ((STAILQ_NEXT((elm), field) = STAILQ_NEXT((tqelm), field)) == NULL) \ + (head)->stqh_last = &STAILQ_NEXT((elm), field); \ + STAILQ_NEXT((tqelm), field) = (elm); \ +} while (0) + +#define STAILQ_INSERT_HEAD(head, elm, field) do { \ + if ((STAILQ_NEXT((elm), field) = STAILQ_FIRST((head))) == NULL) \ + (head)->stqh_last = &STAILQ_NEXT((elm), field); \ + STAILQ_FIRST((head)) = (elm); \ +} while (0) + +#define STAILQ_INSERT_TAIL(head, elm, field) do { \ + STAILQ_NEXT((elm), field) = NULL; \ + *(head)->stqh_last = (elm); \ + (head)->stqh_last = &STAILQ_NEXT((elm), field); \ +} while (0) + +#define STAILQ_LAST(head, type, field) \ + (STAILQ_EMPTY((head)) ? \ + NULL : \ + ((struct type *) \ + ((char *)((head)->stqh_last) - __offsetof(struct type, field)))) + +#define STAILQ_NEXT(elm, field) ((elm)->field.stqe_next) + +#define STAILQ_REMOVE(head, elm, type, field) do { \ + if (STAILQ_FIRST((head)) == (elm)) { \ + STAILQ_REMOVE_HEAD((head), field); \ + } \ + else { \ + struct type *curelm = STAILQ_FIRST((head)); \ + while (STAILQ_NEXT(curelm, field) != (elm)) \ + curelm = STAILQ_NEXT(curelm, field); \ + if ((STAILQ_NEXT(curelm, field) = \ + STAILQ_NEXT(STAILQ_NEXT(curelm, field), field)) == NULL) \ + (head)->stqh_last = &STAILQ_NEXT((curelm), field); \ + } \ +} while (0) + +#define STAILQ_REMOVE_AFTER(head, elm, field) do { \ + if (STAILQ_NEXT(elm, field)) { \ + if ((STAILQ_NEXT(elm, field) = \ + STAILQ_NEXT(STAILQ_NEXT(elm, field), field)) == NULL) \ + (head)->stqh_last = &STAILQ_NEXT((elm), field); \ + } \ +} while (0) + +#define STAILQ_REMOVE_HEAD(head, field) do { \ + if ((STAILQ_FIRST((head)) = \ + STAILQ_NEXT(STAILQ_FIRST((head)), field)) == NULL) \ + (head)->stqh_last = &STAILQ_FIRST((head)); \ +} while (0) + +#define STAILQ_REMOVE_HEAD_UNTIL(head, elm, field) do { \ + if ((STAILQ_FIRST((head)) = STAILQ_NEXT((elm), field)) == NULL) \ + (head)->stqh_last = &STAILQ_FIRST((head)); \ +} while (0) + +/* + * List declarations. + */ +#define ATH_LIST_HEAD(name, type) \ + struct name { \ + struct type *lh_first; /* first element */ \ + } + +#ifndef LIST_HEAD +#define LIST_HEAD ATH_LIST_HEAD +#endif + +#define LIST_HEAD_INITIALIZER(head) \ + { NULL } + +#define LIST_ENTRY(type) \ + struct { \ + struct type *le_next; /* next element */ \ + struct type **le_prev; /* address of previous next element */ \ + } + +/* + * List functions. + */ + +#define LIST_EMPTY(head) ((head)->lh_first == NULL) + +#define LIST_FIRST(head) ((head)->lh_first) + +#define LIST_FOREACH(var, head, field) \ + for ((var) = LIST_FIRST((head)); \ + (var); \ + (var) = LIST_NEXT((var), field)) + +#define LIST_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = LIST_FIRST((head)); \ + (var) && ((tvar) = LIST_NEXT((var), field), 1); \ + (var) = (tvar)) + +#define LIST_INIT(head) do { \ + LIST_FIRST((head)) = NULL; \ +} while (0) + +#define LIST_INSERT_AFTER(listelm, elm, field) do { \ + if ((LIST_NEXT((elm), field) = LIST_NEXT((listelm), field)) != NULL) \ + LIST_NEXT((listelm), field)->field.le_prev = \ + &LIST_NEXT((elm), field); \ + LIST_NEXT((listelm), field) = (elm); \ + (elm)->field.le_prev = &LIST_NEXT((listelm), field); \ +} while (0) + +#define LIST_INSERT_BEFORE(listelm, elm, field) do { \ + (elm)->field.le_prev = (listelm)->field.le_prev; \ + LIST_NEXT((elm), field) = (listelm); \ + *(listelm)->field.le_prev = (elm); \ + (listelm)->field.le_prev = &LIST_NEXT((elm), field); \ +} while (0) + +#define LIST_INSERT_HEAD(head, elm, field) do { \ + if ((LIST_NEXT((elm), field) = LIST_FIRST((head))) != NULL) \ + LIST_FIRST((head))->field.le_prev = &LIST_NEXT((elm), field); \ + LIST_FIRST((head)) = (elm); \ + (elm)->field.le_prev = &LIST_FIRST((head)); \ +} while (0) + +#define LIST_NEXT(elm, field) ((elm)->field.le_next) + +#define LIST_REMOVE(elm, field) do { \ + if (LIST_NEXT((elm), field) != NULL) \ + LIST_NEXT((elm), field)->field.le_prev = \ + (elm)->field.le_prev; \ + *(elm)->field.le_prev = LIST_NEXT((elm), field); \ +} while (0) + +/* + * Tail queue declarations. + */ +#define HEADNAME +#define COPY_HEADNAME(head) + +#define TAILQ_HEAD(name, type) \ + struct name { \ + struct type *tqh_first; /* first element */ \ + struct type **tqh_last; /* addr of last next element */ \ + HEADNAME \ + TRACEBUF \ + } + +#define TAILQ_HEAD_INITIALIZER(head) \ + { NULL, &(head).tqh_first } + +#define TAILQ_ENTRY(type) \ + struct { \ + struct type *tqe_next; /* next element */ \ + struct type **tqe_prev; /* address of previous next element */ \ + TRACEBUF \ + } + +/* + * Tail queue functions. + */ + +#define TAILQ_EMPTY(head) ((head)->tqh_first == NULL) + +#define TAILQ_FIRST(head) ((head)->tqh_first) + +#define TAILQ_FOREACH(var, head, field) \ + for ((var) = TAILQ_FIRST((head)); \ + (var); \ + (var) = TAILQ_NEXT((var), field)) + +#define TAILQ_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = TAILQ_FIRST((head)); \ + (var) && ((tvar) = TAILQ_NEXT((var), field), 1); \ + (var) = (tvar)) + +#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \ + for ((var) = TAILQ_LAST((head), headname); \ + (var); \ + (var) = TAILQ_PREV((var), headname, field)) + +#define TAILQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar) \ + for ((var) = TAILQ_LAST((head), headname); \ + (var) && ((tvar) = TAILQ_PREV((var), headname, field), 1); \ + (var) = (tvar)) + +#define TAILQ_INIT(head) do { \ + TAILQ_FIRST((head)) = NULL; \ + (head)->tqh_last = &TAILQ_FIRST((head)); \ + COPY_HEADNAME(head); \ + QMD_TRACE_HEAD(head); \ +} while (0) + +#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \ + if ((TAILQ_NEXT((elm), field) = TAILQ_NEXT((listelm), field)) != NULL) \ + TAILQ_NEXT((elm), field)->field.tqe_prev = \ + &TAILQ_NEXT((elm), field); \ + else { \ + (head)->tqh_last = &TAILQ_NEXT((elm), field); \ + QMD_TRACE_HEAD(head); \ + } \ + TAILQ_NEXT((listelm), field) = (elm); \ + (elm)->field.tqe_prev = &TAILQ_NEXT((listelm), field); \ + QMD_TRACE_ELEM(&(elm)->field); \ + QMD_TRACE_ELEM(&listelm->field); \ +} while (0) + +#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \ + (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \ + TAILQ_NEXT((elm), field) = (listelm); \ + *(listelm)->field.tqe_prev = (elm); \ + (listelm)->field.tqe_prev = &TAILQ_NEXT((elm), field); \ + QMD_TRACE_ELEM(&(elm)->field); \ + QMD_TRACE_ELEM(&listelm->field); \ +} while (0) + +#define TAILQ_INSERT_HEAD(head, elm, field) do { \ + if ((TAILQ_NEXT((elm), field) = TAILQ_FIRST((head))) != NULL) \ + TAILQ_FIRST((head))->field.tqe_prev = \ + &TAILQ_NEXT((elm), field); \ + else \ + (head)->tqh_last = &TAILQ_NEXT((elm), field); \ + TAILQ_FIRST((head)) = (elm); \ + (elm)->field.tqe_prev = &TAILQ_FIRST((head)); \ + QMD_TRACE_HEAD(head); \ + QMD_TRACE_ELEM(&(elm)->field); \ +} while (0) + +#define TAILQ_INSERT_TAIL(head, elm, field) do { \ + TAILQ_NEXT((elm), field) = NULL; \ + (elm)->field.tqe_prev = (head)->tqh_last; \ + *(head)->tqh_last = (elm); \ + (head)->tqh_last = &TAILQ_NEXT((elm), field); \ + QMD_TRACE_HEAD(head); \ + QMD_TRACE_ELEM(&(elm)->field); \ +} while (0) + +#define TAILQ_LAST(head, headname) \ + (*(((struct headname *)((head)->tqh_last))->tqh_last)) + +#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) + +#define TAILQ_PREV(elm, headname, field) \ + (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last)) + +#define TAILQ_REMOVE(head, elm, field) do { \ + if ((TAILQ_NEXT((elm), field)) != NULL) \ + TAILQ_NEXT((elm), field)->field.tqe_prev = \ + (elm)->field.tqe_prev; \ + else { \ + (head)->tqh_last = (elm)->field.tqe_prev; \ + QMD_TRACE_HEAD(head); \ + } \ + *(elm)->field.tqe_prev = TAILQ_NEXT((elm), field); \ + TRASHIT((elm)->field.tqe_next); \ + TRASHIT((elm)->field.tqe_prev); \ + QMD_TRACE_ELEM(&(elm)->field); \ +} while (0) + +#define TAILQ_CONCAT(head1, head2, field) do { \ + if (!TAILQ_EMPTY(head2)) { \ + *(head1)->tqh_last = (head2)->tqh_first; \ + (head2)->tqh_first->field.tqe_prev = (head1)->tqh_last; \ + (head1)->tqh_last = (head2)->tqh_last; \ + TAILQ_INIT((head2)); \ + } \ +} while (0) + +#ifdef _KERNEL + +/* + * XXX insque() and remque() are an old way of handling certain queues. + * They bogusly assumes that all queue heads look alike. + */ + +struct quehead { + struct quehead *qh_link; + struct quehead *qh_rlink; +}; + +#if defined(__GNUC__) || defined(__INTEL_COMPILER) + +static __inline void insque(void *a, void *b) +{ + struct quehead *element = (struct quehead *)a, + *head = (struct quehead *)b; + + element->qh_link = head->qh_link; + element->qh_rlink = head; + head->qh_link = element; + element->qh_link->qh_rlink = element; +} + +static __inline void remque(void *a) +{ + struct quehead *element = (struct quehead *)a; + + element->qh_link->qh_rlink = element->qh_rlink; + element->qh_rlink->qh_link = element->qh_link; + element->qh_rlink = 0; +} + +#else /* !(__GNUC__ || __INTEL_COMPILER) */ + +void insque(void *a, void *b); +void remque(void *a); + +#endif /* __GNUC__ || __INTEL_COMPILER */ + +#endif /* _KERNEL */ + +#endif /* !_SYS_QUEUE_H_ */ +#else /* !__NetBSD__ */ +#include_next +#endif /* __NetBSD__ */ diff --git a/drivers/staging/qcacld-3.0/core/dp/htt/htt.c b/drivers/staging/qcacld-3.0/core/dp/htt/htt.c new file mode 100644 index 0000000000000000000000000000000000000000..aad0f5a6c03f6eb09e111e625b892cb1ae970a42 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/dp/htt/htt.c @@ -0,0 +1,891 @@ +/* + * Copyright (c) 2011, 2014-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * @file htt.c + * @brief Provide functions to create+init and destroy a HTT instance. + * @details + * This file contains functions for creating a HTT instance; initializing + * the HTT instance, e.g. by allocating a pool of HTT tx descriptors and + * connecting the HTT service with HTC; and deleting a HTT instance. + */ + +#include /* qdf_mem_malloc */ +#include /* qdf_device_t, qdf_print */ + +#include /* htt_tx_msdu_desc_t */ +#include +#include /* ol_tx_dowload_done_ll, etc. */ +#include + +#include +#include +#include +#include "hif.h" + +#define HTT_HTC_PKT_POOL_INIT_SIZE 100 /* enough for a large A-MPDU */ + +QDF_STATUS(*htt_h2t_rx_ring_cfg_msg)(struct htt_pdev_t *pdev); +QDF_STATUS(*htt_h2t_rx_ring_rfs_cfg_msg)(struct htt_pdev_t *pdev); + +#ifdef IPA_OFFLOAD +static A_STATUS htt_ipa_config(htt_pdev_handle pdev, A_STATUS status) +{ + if ((A_OK == status) && + ol_cfg_ipa_uc_offload_enabled(pdev->ctrl_pdev)) + status = htt_h2t_ipa_uc_rsc_cfg_msg(pdev); + return status; +} + +#define HTT_IPA_CONFIG htt_ipa_config +#else +#define HTT_IPA_CONFIG(pdev, status) status /* no-op */ +#endif /* IPA_OFFLOAD */ + +struct htt_htc_pkt *htt_htc_pkt_alloc(struct htt_pdev_t *pdev) +{ + struct htt_htc_pkt_union *pkt = NULL; + + HTT_TX_MUTEX_ACQUIRE(&pdev->htt_tx_mutex); + if (pdev->htt_htc_pkt_freelist) { + pkt = pdev->htt_htc_pkt_freelist; + pdev->htt_htc_pkt_freelist = pdev->htt_htc_pkt_freelist->u.next; + } + HTT_TX_MUTEX_RELEASE(&pdev->htt_tx_mutex); + + if (pkt == NULL) + pkt = qdf_mem_malloc(sizeof(*pkt)); + + if (!pkt) { + qdf_print("%s: HTC packet allocation failed\n", __func__); + return NULL; + } + htc_packet_set_magic_cookie(&(pkt->u.pkt.htc_pkt), 0); + return &pkt->u.pkt; /* not actually a dereference */ +} + +void htt_htc_pkt_free(struct htt_pdev_t *pdev, struct htt_htc_pkt *pkt) +{ + struct htt_htc_pkt_union *u_pkt = (struct htt_htc_pkt_union *)pkt; + + if (!u_pkt) { + qdf_print("%s: HTC packet is NULL\n", __func__); + return; + } + + HTT_TX_MUTEX_ACQUIRE(&pdev->htt_tx_mutex); + htc_packet_set_magic_cookie(&(u_pkt->u.pkt.htc_pkt), 0); + u_pkt->u.next = pdev->htt_htc_pkt_freelist; + pdev->htt_htc_pkt_freelist = u_pkt; + HTT_TX_MUTEX_RELEASE(&pdev->htt_tx_mutex); +} + +void htt_htc_pkt_pool_free(struct htt_pdev_t *pdev) +{ + struct htt_htc_pkt_union *pkt, *next; + pkt = pdev->htt_htc_pkt_freelist; + while (pkt) { + next = pkt->u.next; + qdf_mem_free(pkt); + pkt = next; + } + pdev->htt_htc_pkt_freelist = NULL; +} + +#ifdef ATH_11AC_TXCOMPACT + +void +htt_htc_misc_pkt_list_trim(struct htt_pdev_t *pdev, int level) +{ + struct htt_htc_pkt_union *pkt, *next, *prev = NULL; + int i = 0; + qdf_nbuf_t netbuf; + + HTT_TX_MUTEX_ACQUIRE(&pdev->htt_tx_mutex); + pkt = pdev->htt_htc_pkt_misclist; + while (pkt) { + next = pkt->u.next; + /* trim the out grown list*/ + if (++i > level) { + netbuf = (qdf_nbuf_t)(pkt->u.pkt.htc_pkt.pNetBufContext); + qdf_nbuf_unmap(pdev->osdev, netbuf, QDF_DMA_TO_DEVICE); + qdf_nbuf_free(netbuf); + qdf_mem_free(pkt); + pkt = NULL; + if (prev) + prev->u.next = NULL; + } + prev = pkt; + pkt = next; + } + HTT_TX_MUTEX_RELEASE(&pdev->htt_tx_mutex); +} + +void htt_htc_misc_pkt_list_add(struct htt_pdev_t *pdev, struct htt_htc_pkt *pkt) +{ + struct htt_htc_pkt_union *u_pkt = (struct htt_htc_pkt_union *)pkt; + int misclist_trim_level = htc_get_tx_queue_depth(pdev->htc_pdev, + pkt->htc_pkt.Endpoint) + + HTT_HTC_PKT_MISCLIST_SIZE; + + HTT_TX_MUTEX_ACQUIRE(&pdev->htt_tx_mutex); + if (pdev->htt_htc_pkt_misclist) { + u_pkt->u.next = pdev->htt_htc_pkt_misclist; + pdev->htt_htc_pkt_misclist = u_pkt; + } else { + pdev->htt_htc_pkt_misclist = u_pkt; + } + HTT_TX_MUTEX_RELEASE(&pdev->htt_tx_mutex); + + /* only ce pipe size + tx_queue_depth could possibly be in use + * free older packets in the msiclist + */ + htt_htc_misc_pkt_list_trim(pdev, misclist_trim_level); +} + +void htt_htc_misc_pkt_pool_free(struct htt_pdev_t *pdev) +{ + struct htt_htc_pkt_union *pkt, *next; + qdf_nbuf_t netbuf; + pkt = pdev->htt_htc_pkt_misclist; + + while (pkt) { + next = pkt->u.next; + if (htc_packet_get_magic_cookie(&(pkt->u.pkt.htc_pkt)) != + HTC_PACKET_MAGIC_COOKIE) { + pkt = next; + continue; + } + + netbuf = (qdf_nbuf_t) (pkt->u.pkt.htc_pkt.pNetBufContext); + qdf_nbuf_unmap(pdev->osdev, netbuf, QDF_DMA_TO_DEVICE); + qdf_nbuf_free(netbuf); + qdf_mem_free(pkt); + pkt = next; + } + pdev->htt_htc_pkt_misclist = NULL; +} +#endif + + +/* AR6004 don't need HTT layer. */ +#ifdef AR6004_HW +#define NO_HTT_NEEDED true +#else +#define NO_HTT_NEEDED false +#endif + +#if defined(QCA_TX_HTT2_SUPPORT) && defined(CONFIG_HL_SUPPORT) + +/** + * htt_htc_tx_htt2_service_start() - Start TX HTT2 service + * + * @pdev: pointer to htt device. + * @connect_req: pointer to service connection request information + * @connect_resp: pointer to service connection response information + * + * + * Return: None + */ +static void +htt_htc_tx_htt2_service_start(struct htt_pdev_t *pdev, + HTC_SERVICE_CONNECT_REQ *connect_req, + HTC_SERVICE_CONNECT_RESP *connect_resp) +{ + A_STATUS status; + + qdf_mem_set(connect_req, 0, sizeof(HTC_SERVICE_CONNECT_REQ)); + qdf_mem_set(connect_resp, 0, sizeof(HTC_SERVICE_CONNECT_RESP)); + + /* The same as HTT service but no RX. */ + connect_req->EpCallbacks.pContext = pdev; + connect_req->EpCallbacks.EpTxComplete = htt_h2t_send_complete; + connect_req->EpCallbacks.EpSendFull = htt_h2t_full; + connect_req->MaxSendQueueDepth = HTT_MAX_SEND_QUEUE_DEPTH; + /* Should NOT support credit flow control. */ + connect_req->ConnectionFlags |= + HTC_CONNECT_FLAGS_DISABLE_CREDIT_FLOW_CTRL; + /* Enable HTC schedule mechanism for TX HTT2 service. */ + connect_req->ConnectionFlags |= HTC_CONNECT_FLAGS_ENABLE_HTC_SCHEDULE; + + connect_req->service_id = HTT_DATA2_MSG_SVC; + + status = htc_connect_service(pdev->htc_pdev, connect_req, connect_resp); + + if (status != A_OK) { + pdev->htc_tx_htt2_endpoint = ENDPOINT_UNUSED; + pdev->htc_tx_htt2_max_size = 0; + } else { + pdev->htc_tx_htt2_endpoint = connect_resp->Endpoint; + pdev->htc_tx_htt2_max_size = HTC_TX_HTT2_MAX_SIZE; + } + + qdf_print("TX HTT %s, ep %d size %d\n", + (status == A_OK ? "ON" : "OFF"), + pdev->htc_tx_htt2_endpoint, + pdev->htc_tx_htt2_max_size); +} +#else + +static inline void +htt_htc_tx_htt2_service_start(struct htt_pdev_t *pdev, + HTC_SERVICE_CONNECT_REQ *connect_req, + HTC_SERVICE_CONNECT_RESP *connect_resp) +{ + return; +} +#endif + +/** + * htt_htc_credit_flow_disable() - disable flow control for + * HTT data message service + * + * @pdev: pointer to htt device. + * @connect_req: pointer to service connection request information + * + * HTC Credit mechanism is disabled based on + * default_tx_comp_req as throughput will be lower + * if we disable htc credit mechanism with default_tx_comp_req + * set since txrx download packet will be limited by ota + * completion. + * + * Return: None + */ +static +void htt_htc_credit_flow_disable(struct htt_pdev_t *pdev, + HTC_SERVICE_CONNECT_REQ *connect_req) +{ + if (pdev->osdev->bus_type == QDF_BUS_TYPE_SDIO) { + /* + * TODO:Conditional disabling will be removed once firmware + * with reduced tx completion is pushed into release builds. + */ + if (!pdev->cfg.default_tx_comp_req) + connect_req->ConnectionFlags |= + HTC_CONNECT_FLAGS_DISABLE_CREDIT_FLOW_CTRL; + } else { + connect_req->ConnectionFlags |= + HTC_CONNECT_FLAGS_DISABLE_CREDIT_FLOW_CTRL; + } +} + +#if defined(DEBUG_HL_LOGGING) && defined(CONFIG_HL_SUPPORT) + +/** + * htt_dump_bundle_stats() - dump wlan stats + * @pdev: handle to the HTT instance + * + * Return: None + */ +void htt_dump_bundle_stats(htt_pdev_handle pdev) +{ + htc_dump_bundle_stats(pdev->htc_pdev); +} + +/** + * htt_clear_bundle_stats() - clear wlan stats + * @pdev: handle to the HTT instance + * + * Return: None + */ +void htt_clear_bundle_stats(htt_pdev_handle pdev) +{ + htc_clear_bundle_stats(pdev->htc_pdev); +} +#endif + +/** + * htt_pdev_alloc() - allocate HTT pdev + * @txrx_pdev: txrx pdev + * @ctrl_pdev: cfg pdev + * @htc_pdev: HTC pdev + * @osdev: os device + * + * Return: HTT pdev handle + */ +htt_pdev_handle +htt_pdev_alloc(ol_txrx_pdev_handle txrx_pdev, + ol_pdev_handle ctrl_pdev, + HTC_HANDLE htc_pdev, qdf_device_t osdev) +{ + struct htt_pdev_t *pdev; + struct hif_opaque_softc *osc = cds_get_context(QDF_MODULE_ID_HIF); + + if (!osc) + goto fail1; + + pdev = qdf_mem_malloc(sizeof(*pdev)); + if (!pdev) + goto fail1; + + pdev->osdev = osdev; + pdev->ctrl_pdev = ctrl_pdev; + pdev->txrx_pdev = txrx_pdev; + pdev->htc_pdev = htc_pdev; + + pdev->htt_htc_pkt_freelist = NULL; +#ifdef ATH_11AC_TXCOMPACT + pdev->htt_htc_pkt_misclist = NULL; +#endif + + /* for efficiency, store a local copy of the is_high_latency flag */ + pdev->cfg.is_high_latency = ol_cfg_is_high_latency(pdev->ctrl_pdev); + pdev->cfg.default_tx_comp_req = + !ol_cfg_tx_free_at_download(pdev->ctrl_pdev); + + pdev->cfg.is_full_reorder_offload = + ol_cfg_is_full_reorder_offload(pdev->ctrl_pdev); + qdf_print("is_full_reorder_offloaded? %d\n", + (int)pdev->cfg.is_full_reorder_offload); + + pdev->cfg.ce_classify_enabled = + ol_cfg_is_ce_classify_enabled(ctrl_pdev); + qdf_print("ce_classify_enabled %d\n", + pdev->cfg.ce_classify_enabled); + + if (pdev->cfg.is_high_latency) { + qdf_atomic_init(&pdev->htt_tx_credit.target_delta); + qdf_atomic_init(&pdev->htt_tx_credit.bus_delta); + qdf_atomic_add(HTT_MAX_BUS_CREDIT, + &pdev->htt_tx_credit.bus_delta); + } + + pdev->targetdef = htc_get_targetdef(htc_pdev); +#if defined(HELIUMPLUS) + HTT_SET_WIFI_IP(pdev, 2, 0); +#endif /* defined(HELIUMPLUS) */ + + if (NO_HTT_NEEDED) + goto success; + /* + * Connect to HTC service. + * This has to be done before calling htt_rx_attach, + * since htt_rx_attach involves sending a rx ring configure + * message to the target. + */ + if (htt_htc_attach(pdev, HTT_DATA_MSG_SVC)) + goto fail2; + if (htt_htc_attach(pdev, HTT_DATA2_MSG_SVC)) + ; + /* TODO: enable the following line once FW is ready */ + /* goto fail2; */ + if (htt_htc_attach(pdev, HTT_DATA3_MSG_SVC)) + ; + /* TODO: enable the following line once FW is ready */ + /* goto fail2; */ + if (hif_ce_fastpath_cb_register(osc, htt_t2h_msg_handler_fast, pdev)) + qdf_print("failed to register fastpath callback\n"); + +success: + return pdev; + +fail2: + qdf_mem_free(pdev); + +fail1: + return NULL; + +} + +/** + * htt_attach() - Allocate and setup HTT TX/RX descriptors + * @pdev: pdev ptr + * @desc_pool_size: size of tx descriptors + * + * Return: 0 for success or error code. + */ +int +htt_attach(struct htt_pdev_t *pdev, int desc_pool_size) +{ + int i; + int ret = 0; + + ret = htt_tx_attach(pdev, desc_pool_size); + if (ret) + goto fail1; + + ret = htt_rx_attach(pdev); + if (ret) + goto fail2; + + HTT_TX_MUTEX_INIT(&pdev->htt_tx_mutex); + HTT_TX_NBUF_QUEUE_MUTEX_INIT(pdev); + + /* pre-allocate some HTC_PACKET objects */ + for (i = 0; i < HTT_HTC_PKT_POOL_INIT_SIZE; i++) { + struct htt_htc_pkt_union *pkt; + pkt = qdf_mem_malloc(sizeof(*pkt)); + if (!pkt) + break; + htt_htc_pkt_free(pdev, &pkt->u.pkt); + } + + if (pdev->cfg.is_high_latency) { + /* + * HL - download the whole frame. + * Specify a download length greater than the max MSDU size, + * so the downloads will be limited by the actual frame sizes. + */ + pdev->download_len = 5000; + + if (ol_cfg_tx_free_at_download(pdev->ctrl_pdev)) + pdev->tx_send_complete_part2 = + ol_tx_download_done_hl_free; + else + pdev->tx_send_complete_part2 = + ol_tx_download_done_hl_retain; + + /* + * CHECK THIS LATER: does the HL HTT version of + * htt_rx_mpdu_desc_list_next + * (which is not currently implemented) present the + * adf_nbuf_data(rx_ind_msg) + * as the abstract rx descriptor? + * If not, the rx_fw_desc_offset initialization + * here will have to be adjusted accordingly. + * NOTE: for HL, because fw rx desc is in ind msg, + * not in rx desc, so the + * offset should be negtive value + */ + pdev->rx_fw_desc_offset = + HTT_ENDIAN_BYTE_IDX_SWAP( + HTT_RX_IND_FW_RX_DESC_BYTE_OFFSET + - HTT_RX_IND_HL_BYTES); + + htt_h2t_rx_ring_cfg_msg = htt_h2t_rx_ring_cfg_msg_hl; + htt_h2t_rx_ring_rfs_cfg_msg = htt_h2t_rx_ring_rfs_cfg_msg_hl; + + /* initialize the txrx credit count */ + ol_tx_target_credit_update( + pdev->txrx_pdev, ol_cfg_target_tx_credit( + pdev->ctrl_pdev)); + } else { + enum wlan_frm_fmt frm_type; + + /* + * LL - download just the initial portion of the frame. + * Download enough to cover the encapsulation headers checked + * by the target's tx classification descriptor engine. + * + * For LL, the FW rx desc directly referenced at its location + * inside the rx indication message. + */ + + /* account for the 802.3 or 802.11 header */ + frm_type = ol_cfg_frame_type(pdev->ctrl_pdev); + + if (frm_type == wlan_frm_fmt_native_wifi) { + pdev->download_len = HTT_TX_HDR_SIZE_NATIVE_WIFI; + } else if (frm_type == wlan_frm_fmt_802_3) { + pdev->download_len = HTT_TX_HDR_SIZE_ETHERNET; + } else { + qdf_print("Unexpected frame type spec: %d\n", frm_type); + HTT_ASSERT0(0); + } + + /* + * Account for the optional L2 / ethernet header fields: + * 802.1Q, LLC/SNAP + */ + pdev->download_len += + HTT_TX_HDR_SIZE_802_1Q + HTT_TX_HDR_SIZE_LLC_SNAP; + + /* + * Account for the portion of the L3 (IP) payload that the + * target needs for its tx classification. + */ + pdev->download_len += ol_cfg_tx_download_size(pdev->ctrl_pdev); + + /* + * Account for the HTT tx descriptor, including the + * HTC header + alignment padding. + */ + pdev->download_len += sizeof(struct htt_host_tx_desc_t); + + /* + * The TXCOMPACT htt_tx_sched function uses pdev->download_len + * to apply for all requeued tx frames. Thus, + * pdev->download_len has to be the largest download length of + * any tx frame that will be downloaded. + * This maximum download length is for management tx frames, + * which have an 802.11 header. + */ +#ifdef ATH_11AC_TXCOMPACT + pdev->download_len = sizeof(struct htt_host_tx_desc_t) + + HTT_TX_HDR_SIZE_OUTER_HDR_MAX /* worst case */ + + HTT_TX_HDR_SIZE_802_1Q + + HTT_TX_HDR_SIZE_LLC_SNAP + + ol_cfg_tx_download_size(pdev->ctrl_pdev); +#endif + pdev->tx_send_complete_part2 = ol_tx_download_done_ll; + + /* + * For LL, the FW rx desc is alongside the HW rx desc fields in + * the htt_host_rx_desc_base struct/. + */ + pdev->rx_fw_desc_offset = RX_STD_DESC_FW_MSDU_OFFSET; + + htt_h2t_rx_ring_cfg_msg = htt_h2t_rx_ring_cfg_msg_ll; + htt_h2t_rx_ring_rfs_cfg_msg = htt_h2t_rx_ring_rfs_cfg_msg_ll; + } + + return 0; + +fail2: + htt_tx_detach(pdev); + +fail1: + return ret; +} + +A_STATUS htt_attach_target(htt_pdev_handle pdev) +{ + A_STATUS status; + + status = htt_h2t_ver_req_msg(pdev); + if (status != A_OK) + return status; + +#if defined(HELIUMPLUS) + /* + * Send the frag_desc info to target. + */ + htt_h2t_frag_desc_bank_cfg_msg(pdev); +#endif /* defined(HELIUMPLUS) */ + + + /* + * If applicable, send the rx ring config message to the target. + * The host could wait for the HTT version number confirmation message + * from the target before sending any further HTT messages, but it's + * reasonable to assume that the host and target HTT version numbers + * match, and proceed immediately with the remaining configuration + * handshaking. + */ + + status = htt_h2t_rx_ring_rfs_cfg_msg(pdev); + status = htt_h2t_rx_ring_cfg_msg(pdev); + status = HTT_IPA_CONFIG(pdev, status); + + return status; +} + +void htt_detach(htt_pdev_handle pdev) +{ + htt_rx_detach(pdev); + htt_tx_detach(pdev); + htt_htc_pkt_pool_free(pdev); +#ifdef ATH_11AC_TXCOMPACT + htt_htc_misc_pkt_pool_free(pdev); +#endif + HTT_TX_MUTEX_DESTROY(&pdev->htt_tx_mutex); + HTT_TX_NBUF_QUEUE_MUTEX_DESTROY(pdev); + htt_rx_dbg_rxbuf_deinit(pdev); +} + +/** + * htt_pdev_free() - Free HTT pdev + * @pdev: htt pdev + * + * Return: none + */ +void htt_pdev_free(htt_pdev_handle pdev) +{ + qdf_mem_free(pdev); +} + +void htt_detach_target(htt_pdev_handle pdev) +{ +} + +static inline +int htt_update_endpoint(struct htt_pdev_t *pdev, + uint16_t service_id, HTC_ENDPOINT_ID ep) +{ + struct hif_opaque_softc *hif_ctx; + uint8_t ul = 0xff, dl = 0xff; + int ul_polled, dl_polled; + int tx_service = 0; + int rc = 0; + + hif_ctx = cds_get_context(QDF_MODULE_ID_HIF); + if (qdf_unlikely(NULL == hif_ctx)) { + QDF_ASSERT(NULL != hif_ctx); + qdf_print("%s:%d: assuming non-tx service.", + __func__, __LINE__); + } else { + ul = dl = 0xff; + if (QDF_STATUS_SUCCESS != + hif_map_service_to_pipe(hif_ctx, service_id, + &ul, &dl, + &ul_polled, &dl_polled)) + qdf_print("%s:%d: assuming non-tx srv.", + __func__, __LINE__); + else + tx_service = (ul != 0xff); + } + if (tx_service) { + /* currently we have only one OUT htt tx service */ + QDF_BUG(service_id == HTT_DATA_MSG_SVC); + + pdev->htc_tx_endpoint = ep; + hif_save_htc_htt_config_endpoint(hif_ctx, ep); + rc = 1; + } + return rc; +} + +int htt_htc_attach(struct htt_pdev_t *pdev, uint16_t service_id) +{ + HTC_SERVICE_CONNECT_REQ connect; + HTC_SERVICE_CONNECT_RESP response; + A_STATUS status; + + qdf_mem_set(&connect, sizeof(connect), 0); + qdf_mem_set(&response, sizeof(response), 0); + + connect.pMetaData = NULL; + connect.MetaDataLength = 0; + connect.EpCallbacks.pContext = pdev; + connect.EpCallbacks.EpTxComplete = htt_h2t_send_complete; + connect.EpCallbacks.EpTxCompleteMultiple = NULL; + connect.EpCallbacks.EpRecv = htt_t2h_msg_handler; + connect.EpCallbacks.ep_resume_tx_queue = htt_tx_resume_handler; + + /* rx buffers currently are provided by HIF, not by EpRecvRefill */ + connect.EpCallbacks.EpRecvRefill = NULL; + connect.EpCallbacks.RecvRefillWaterMark = 1; + /* N/A, fill is done by HIF */ + + connect.EpCallbacks.EpSendFull = htt_h2t_full; + /* + * Specify how deep to let a queue get before htc_send_pkt will + * call the EpSendFull function due to excessive send queue depth. + */ + connect.MaxSendQueueDepth = HTT_MAX_SEND_QUEUE_DEPTH; + + /* disable flow control for HTT data message service */ + htt_htc_credit_flow_disable(pdev, &connect); + + /* connect to control service */ + connect.service_id = service_id; + + status = htc_connect_service(pdev->htc_pdev, &connect, &response); + + if (status != A_OK) + return -EIO; /* failure */ + + htt_update_endpoint(pdev, service_id, response.Endpoint); + + /* Start TX HTT2 service if the target support it. */ + htt_htc_tx_htt2_service_start(pdev, &connect, &response); + + return 0; /* success */ +} + +#if HTT_DEBUG_LEVEL > 5 +void htt_display(htt_pdev_handle pdev, int indent) +{ + qdf_print("%*s%s:\n", indent, " ", "HTT"); + qdf_print("%*stx desc pool: %d elems of %d bytes, %d allocated\n", + indent + 4, " ", + pdev->tx_descs.pool_elems, + pdev->tx_descs.size, pdev->tx_descs.alloc_cnt); + qdf_print("%*srx ring: space for %d elems, filled with %d buffers\n", + indent + 4, " ", + pdev->rx_ring.size, pdev->rx_ring.fill_level); + qdf_print("%*sat %p (%llx paddr)\n", indent + 8, " ", + pdev->rx_ring.buf.paddrs_ring, + (unsigned long long)pdev->rx_ring.base_paddr); + qdf_print("%*snetbuf ring @ %p\n", indent + 8, " ", + pdev->rx_ring.buf.netbufs_ring); + qdf_print("%*sFW_IDX shadow register: vaddr = %p, paddr = %llx\n", + indent + 8, " ", + pdev->rx_ring.alloc_idx.vaddr, + (unsigned long long)pdev->rx_ring.alloc_idx.paddr); + qdf_print("%*sSW enqueue idx= %d, SW dequeue idx: desc= %d, buf= %d\n", + indent + 8, " ", *pdev->rx_ring.alloc_idx.vaddr, + pdev->rx_ring.sw_rd_idx.msdu_desc, + pdev->rx_ring.sw_rd_idx.msdu_payld); +} +#endif + +#ifdef IPA_OFFLOAD +/** + * htt_ipa_uc_attach() - Allocate UC data path resources + * @pdev: handle to the HTT instance + * + * Return: 0 success + * none 0 fail + */ +int htt_ipa_uc_attach(struct htt_pdev_t *pdev) +{ + int error; + + /* TX resource attach */ + error = htt_tx_ipa_uc_attach( + pdev, + ol_cfg_ipa_uc_tx_buf_size(pdev->ctrl_pdev), + ol_cfg_ipa_uc_tx_max_buf_cnt(pdev->ctrl_pdev), + ol_cfg_ipa_uc_tx_partition_base(pdev->ctrl_pdev)); + if (error) { + qdf_print("HTT IPA UC TX attach fail code %d\n", error); + HTT_ASSERT0(0); + return error; + } + + /* RX resource attach */ + error = htt_rx_ipa_uc_attach( + pdev, qdf_get_pwr2(pdev->rx_ring.fill_level)); + if (error) { + qdf_print("HTT IPA UC RX attach fail code %d\n", error); + htt_tx_ipa_uc_detach(pdev); + HTT_ASSERT0(0); + return error; + } + + return 0; /* success */ +} + +/** + * htt_ipa_uc_attach() - Remove UC data path resources + * @pdev: handle to the HTT instance + * + * Return: None + */ +void htt_ipa_uc_detach(struct htt_pdev_t *pdev) +{ + /* TX IPA micro controller detach */ + htt_tx_ipa_uc_detach(pdev); + + /* RX IPA micro controller detach */ + htt_rx_ipa_uc_detach(pdev); +} + +/** + * htt_ipa_uc_get_resource() - Get uc resource from htt and lower layer + * @pdev: handle to the HTT instance + * @ce_sr_base_paddr: copy engine source ring base physical address + * @ce_sr_ring_size: copy engine source ring size + * @ce_reg_paddr: copy engine register physical address + * @tx_comp_ring_base_paddr: tx comp ring base physical address + * @tx_comp_ring_size: tx comp ring size + * @tx_num_alloc_buffer: number of allocated tx buffer + * @rx_rdy_ring_base_paddr: rx ready ring base physical address + * @rx_rdy_ring_size: rx ready ring size + * @rx_proc_done_idx_paddr: rx process done index physical address + * @rx_proc_done_idx_vaddr: rx process done index virtual address + * @rx2_rdy_ring_base_paddr: rx done ring base physical address + * @rx2_rdy_ring_size: rx done ring size + * @rx2_proc_done_idx_paddr: rx done index physical address + * @rx2_proc_done_idx_vaddr: rx done index virtual address + * + * Return: 0 success + */ +int +htt_ipa_uc_get_resource(htt_pdev_handle pdev, + qdf_dma_addr_t *ce_sr_base_paddr, + uint32_t *ce_sr_ring_size, + qdf_dma_addr_t *ce_reg_paddr, + qdf_dma_addr_t *tx_comp_ring_base_paddr, + uint32_t *tx_comp_ring_size, + uint32_t *tx_num_alloc_buffer, + qdf_dma_addr_t *rx_rdy_ring_base_paddr, + uint32_t *rx_rdy_ring_size, + qdf_dma_addr_t *rx_proc_done_idx_paddr, + void **rx_proc_done_idx_vaddr, + qdf_dma_addr_t *rx2_rdy_ring_base_paddr, + uint32_t *rx2_rdy_ring_size, + qdf_dma_addr_t *rx2_proc_done_idx_paddr, + void **rx2_proc_done_idx_vaddr) +{ + /* Release allocated resource to client */ + *tx_comp_ring_base_paddr = + pdev->ipa_uc_tx_rsc.tx_comp_base.paddr; + *tx_comp_ring_size = + (uint32_t) ol_cfg_ipa_uc_tx_max_buf_cnt(pdev->ctrl_pdev); + *tx_num_alloc_buffer = (uint32_t) pdev->ipa_uc_tx_rsc.alloc_tx_buf_cnt; + *rx_rdy_ring_base_paddr = + pdev->ipa_uc_rx_rsc.rx_ind_ring_base.paddr; + *rx_rdy_ring_size = (uint32_t) pdev->ipa_uc_rx_rsc.rx_ind_ring_size; + *rx_proc_done_idx_paddr = + pdev->ipa_uc_rx_rsc.rx_ipa_prc_done_idx.paddr; + *rx_proc_done_idx_vaddr = + (void *)pdev->ipa_uc_rx_rsc.rx_ipa_prc_done_idx.vaddr; + *rx2_rdy_ring_base_paddr = + pdev->ipa_uc_rx_rsc.rx2_ind_ring_base.paddr; + *rx2_rdy_ring_size = (uint32_t) pdev->ipa_uc_rx_rsc.rx2_ind_ring_size; + *rx2_proc_done_idx_paddr = + pdev->ipa_uc_rx_rsc.rx2_ipa_prc_done_idx.paddr; + *rx2_proc_done_idx_vaddr = + (void *)pdev->ipa_uc_rx_rsc.rx2_ipa_prc_done_idx.vaddr; + + /* Get copy engine, bus resource */ + htc_ipa_get_ce_resource(pdev->htc_pdev, + ce_sr_base_paddr, + ce_sr_ring_size, ce_reg_paddr); + + return 0; +} + +/** + * htt_ipa_uc_set_doorbell_paddr() - Propagate IPA doorbell address + * @pdev: handle to the HTT instance + * @ipa_uc_tx_doorbell_paddr: TX doorbell base physical address + * @ipa_uc_rx_doorbell_paddr: RX doorbell base physical address + * + * Return: 0 success + */ +int +htt_ipa_uc_set_doorbell_paddr(htt_pdev_handle pdev, + qdf_dma_addr_t ipa_uc_tx_doorbell_paddr, + qdf_dma_addr_t ipa_uc_rx_doorbell_paddr) +{ + pdev->ipa_uc_tx_rsc.tx_comp_idx_paddr = ipa_uc_tx_doorbell_paddr; + pdev->ipa_uc_rx_rsc.rx_rdy_idx_paddr = ipa_uc_rx_doorbell_paddr; + return 0; +} +#endif /* IPA_OFFLOAD */ + +/** + * htt_mark_first_wakeup_packet() - set flag to indicate that + * fw is compatible for marking first packet after wow wakeup + * @pdev: pointer to htt pdev + * @value: 1 for enabled/ 0 for disabled + * + * Return: None + */ +void htt_mark_first_wakeup_packet(htt_pdev_handle pdev, + uint8_t value) +{ + if (!pdev) { + qdf_print("%s: htt pdev is NULL", __func__); + return; + } + + pdev->cfg.is_first_wakeup_packet = value; +} diff --git a/drivers/staging/qcacld-3.0/core/dp/htt/htt_fw_stats.c b/drivers/staging/qcacld-3.0/core/dp/htt/htt_fw_stats.c new file mode 100644 index 0000000000000000000000000000000000000000..772c12e69fcb66d347b12a12cbabd508215ed0db --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/dp/htt/htt_fw_stats.c @@ -0,0 +1,1290 @@ +/* + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * @file htt_fw_stats.c + * @brief Provide functions to process FW status retrieved from FW. + */ + +#include /* HTC_PACKET */ +#include /* HTT_T2H_MSG_TYPE, etc. */ +#include /* qdf_nbuf_t */ +#include /* qdf_mem_set */ +#include /* ol_fw_tx_dbg_ppdu_base */ + +#include +#include /* htt_tx_status */ + +#include + +#include + +#define ROUND_UP_TO_4(val) (((val) + 3) & ~0x3) + + +static char *bw_str_arr[] = {"20MHz", "40MHz", "80MHz", "160MHz"}; + +/* + * Defined the macro tx_rate_stats_print_cmn() + * so that this could be used in both + * htt_t2h_stats_tx_rate_stats_print() & + * htt_t2h_stats_tx_rate_stats_print_v2(). + * Each of these functions take a different structure as argument, + * but with common fields in the structures--so using a macro + * to bypass the strong type-checking of a function seems a simple + * trick to use to avoid the code duplication. + */ +#define tx_rate_stats_print_cmn(_tx_rate_info, _concise) \ +{ \ + qdf_print("TX Rate Info:"); \ + \ + /* MCS */ \ + qdf_print("MCS counts (0..9): %d, %d, %d, %d, %d, %d, %d, %d, %d, %d",\ + _tx_rate_info->mcs[0], \ + _tx_rate_info->mcs[1], \ + _tx_rate_info->mcs[2], \ + _tx_rate_info->mcs[3], \ + _tx_rate_info->mcs[4], \ + _tx_rate_info->mcs[5], \ + _tx_rate_info->mcs[6], \ + _tx_rate_info->mcs[7], \ + _tx_rate_info->mcs[8], \ + _tx_rate_info->mcs[9]); \ + \ + /* SGI */ \ + qdf_print("SGI counts (0..9): %d, %d, %d, %d, %d, %d, %d, %d, %d, %d",\ + _tx_rate_info->sgi[0], \ + _tx_rate_info->sgi[1], \ + _tx_rate_info->sgi[2], \ + _tx_rate_info->sgi[3], \ + _tx_rate_info->sgi[4], \ + _tx_rate_info->sgi[5], \ + _tx_rate_info->sgi[6], \ + _tx_rate_info->sgi[7], \ + _tx_rate_info->sgi[8], \ + _tx_rate_info->sgi[9]); \ + \ + /* NSS */ \ + qdf_print("NSS counts: 1x1 %d, 2x2 %d, 3x3 %d", \ + _tx_rate_info->nss[0], \ + _tx_rate_info->nss[1], _tx_rate_info->nss[2]);\ + \ + /* BW */ \ + if (sizeof(_tx_rate_info->bw) / sizeof(_tx_rate_info->bw[0]) == 3)\ + qdf_print("BW counts: %s %d, %s %d, %s %d", \ + bw_str_arr[0], _tx_rate_info->bw[0], \ + bw_str_arr[1], _tx_rate_info->bw[1], \ + bw_str_arr[2], _tx_rate_info->bw[2]); \ + else if (sizeof(_tx_rate_info->bw) / sizeof(_tx_rate_info->bw[0]) == 4)\ + qdf_print("BW counts: %s %d, %s %d, %s %d, %s %d", \ + bw_str_arr[0], _tx_rate_info->bw[0], \ + bw_str_arr[1], _tx_rate_info->bw[1], \ + bw_str_arr[2], _tx_rate_info->bw[2], \ + bw_str_arr[3], _tx_rate_info->bw[3]); \ + \ + \ + /* Preamble */ \ + qdf_print("Preamble (O C H V) counts: %d, %d, %d, %d",\ + _tx_rate_info->pream[0], \ + _tx_rate_info->pream[1], \ + _tx_rate_info->pream[2], \ + _tx_rate_info->pream[3]); \ + \ + /* STBC rate counts */ \ + qdf_print("STBC rate counts (0..9): %d, %d, %d, %d, %d, %d, %d, %d, %d, %d",\ + _tx_rate_info->stbc[0], \ + _tx_rate_info->stbc[1], \ + _tx_rate_info->stbc[2], \ + _tx_rate_info->stbc[3], \ + _tx_rate_info->stbc[4], \ + _tx_rate_info->stbc[5], \ + _tx_rate_info->stbc[6], \ + _tx_rate_info->stbc[7], \ + _tx_rate_info->stbc[8], \ + _tx_rate_info->stbc[9]); \ + \ + /* LDPC and TxBF counts */ \ + qdf_print("LDPC Counts: %d", _tx_rate_info->ldpc);\ + qdf_print("RTS Counts: %d", _tx_rate_info->rts_cnt);\ + /* RSSI Values for last ack frames */ \ + qdf_print("Ack RSSI: %d", _tx_rate_info->ack_rssi);\ +} + +static void htt_t2h_stats_tx_rate_stats_print(wlan_dbg_tx_rate_info_t * + tx_rate_info, int concise) +{ + tx_rate_stats_print_cmn(tx_rate_info, concise); +} + +static void htt_t2h_stats_tx_rate_stats_print_v2(wlan_dbg_tx_rate_info_v2_t * + tx_rate_info, int concise) +{ + tx_rate_stats_print_cmn(tx_rate_info, concise); +} + +/* + * Defined the macro rx_rate_stats_print_cmn() + * so that this could be used in both + * htt_t2h_stats_rx_rate_stats_print() & + * htt_t2h_stats_rx_rate_stats_print_v2(). + * Each of these functions take a different structure as argument, + * but with common fields in the structures -- so using a macro + * to bypass the strong type-checking of a function seems a simple + * trick to use to avoid the code duplication. + */ +#define rx_rate_stats_print_cmn(_rx_phy_info, _concise) \ +{ \ + qdf_print("RX Rate Info:"); \ + \ + /* MCS */ \ + qdf_print("MCS counts (0..9): %d, %d, %d, %d, %d, %d, %d, %d, %d, %d",\ + _rx_phy_info->mcs[0], \ + _rx_phy_info->mcs[1], \ + _rx_phy_info->mcs[2], \ + _rx_phy_info->mcs[3], \ + _rx_phy_info->mcs[4], \ + _rx_phy_info->mcs[5], \ + _rx_phy_info->mcs[6], \ + _rx_phy_info->mcs[7], \ + _rx_phy_info->mcs[8], \ + _rx_phy_info->mcs[9]); \ + \ + /* SGI */ \ + qdf_print("SGI counts (0..9): %d, %d, %d, %d, %d, %d, %d, %d, %d, %d",\ + _rx_phy_info->sgi[0], \ + _rx_phy_info->sgi[1], \ + _rx_phy_info->sgi[2], \ + _rx_phy_info->sgi[3], \ + _rx_phy_info->sgi[4], \ + _rx_phy_info->sgi[5], \ + _rx_phy_info->sgi[6], \ + _rx_phy_info->sgi[7], \ + _rx_phy_info->sgi[8], \ + _rx_phy_info->sgi[9]); \ + \ + /* NSS */ \ + /* nss[0] just holds the count of non-stbc frames that were sent at 1x1 \ + * rates and nsts holds the count of frames sent with stbc. \ + * It was decided to not include PPDUs sent w/ STBC in nss[0]\ + * since it would be easier to change the value that needs to be\ + * printed (from "stbc+non-stbc count to only non-stbc count")\ + * if needed in the future. Hence the addition in the host code\ + * at this line. */ \ + qdf_print("NSS counts: 1x1 %d, 2x2 %d, 3x3 %d, 4x4 %d",\ + _rx_phy_info->nss[0] + _rx_phy_info->nsts, \ + _rx_phy_info->nss[1], \ + _rx_phy_info->nss[2], \ + _rx_phy_info->nss[3]); \ + \ + /* NSTS */ \ + qdf_print("NSTS count: %d", _rx_phy_info->nsts); \ + \ + /* BW */ \ + if (sizeof(_rx_phy_info->bw) / sizeof(_rx_phy_info->bw[0]) == 3)\ + qdf_print("BW counts: %s %d, %s %d, %s %d", \ + bw_str_arr[0], _rx_phy_info->bw[0], \ + bw_str_arr[1], _rx_phy_info->bw[1], \ + bw_str_arr[2], _rx_phy_info->bw[2]); \ + else if (sizeof(_rx_phy_info->bw) / sizeof(_rx_phy_info->bw[0]) == 4) \ + qdf_print("BW counts: %s %d, %s %d, %s %d, %s %d", \ + bw_str_arr[0], _rx_phy_info->bw[0], \ + bw_str_arr[1], _rx_phy_info->bw[1], \ + bw_str_arr[2], _rx_phy_info->bw[2], \ + bw_str_arr[3], _rx_phy_info->bw[3]); \ + \ + /* Preamble */ \ + qdf_print("Preamble counts: %d, %d, %d, %d, %d, %d",\ + _rx_phy_info->pream[0], \ + _rx_phy_info->pream[1], \ + _rx_phy_info->pream[2], \ + _rx_phy_info->pream[3], \ + _rx_phy_info->pream[4], \ + _rx_phy_info->pream[5]); \ + \ + /* STBC rate counts */ \ + qdf_print("STBC rate counts (0..9): %d, %d, %d, %d, %d, %d, %d, %d, %d, %d",\ + _rx_phy_info->stbc[0], \ + _rx_phy_info->stbc[1], \ + _rx_phy_info->stbc[2], \ + _rx_phy_info->stbc[3], \ + _rx_phy_info->stbc[4], \ + _rx_phy_info->stbc[5], \ + _rx_phy_info->stbc[6], \ + _rx_phy_info->stbc[7], \ + _rx_phy_info->stbc[8], \ + _rx_phy_info->stbc[9]); \ + \ + /* LDPC and TxBF counts */ \ + qdf_print("LDPC TXBF Counts: %d, %d", \ + _rx_phy_info->ldpc, _rx_phy_info->txbf);\ + /* RSSI Values for last received frames */ \ + qdf_print("RSSI (data, mgmt): %d, %d", _rx_phy_info->data_rssi,\ + _rx_phy_info->mgmt_rssi); \ + \ + qdf_print("RSSI Chain 0 (0x%02x 0x%02x 0x%02x 0x%02x)",\ + ((_rx_phy_info->rssi_chain0 >> 24) & 0xff), \ + ((_rx_phy_info->rssi_chain0 >> 16) & 0xff), \ + ((_rx_phy_info->rssi_chain0 >> 8) & 0xff), \ + ((_rx_phy_info->rssi_chain0 >> 0) & 0xff)); \ + \ + qdf_print("RSSI Chain 1 (0x%02x 0x%02x 0x%02x 0x%02x)",\ + ((_rx_phy_info->rssi_chain1 >> 24) & 0xff), \ + ((_rx_phy_info->rssi_chain1 >> 16) & 0xff), \ + ((_rx_phy_info->rssi_chain1 >> 8) & 0xff), \ + ((_rx_phy_info->rssi_chain1 >> 0) & 0xff)); \ + \ + qdf_print("RSSI Chain 2 (0x%02x 0x%02x 0x%02x 0x%02x)",\ + ((_rx_phy_info->rssi_chain2 >> 24) & 0xff), \ + ((_rx_phy_info->rssi_chain2 >> 16) & 0xff), \ + ((_rx_phy_info->rssi_chain2 >> 8) & 0xff), \ + ((_rx_phy_info->rssi_chain2 >> 0) & 0xff)); \ +} + +static void htt_t2h_stats_rx_rate_stats_print(wlan_dbg_rx_rate_info_t * + rx_phy_info, int concise) +{ + rx_rate_stats_print_cmn(rx_phy_info, concise); +} + +static void htt_t2h_stats_rx_rate_stats_print_v2(wlan_dbg_rx_rate_info_v2_t * + rx_phy_info, int concise) +{ + rx_rate_stats_print_cmn(rx_phy_info, concise); +} + +static void +htt_t2h_stats_pdev_stats_print(struct wlan_dbg_stats *wlan_pdev_stats, + int concise) +{ + struct wlan_dbg_tx_stats *tx = &wlan_pdev_stats->tx; + struct wlan_dbg_rx_stats *rx = &wlan_pdev_stats->rx; + + qdf_print("WAL Pdev stats:"); + qdf_print("\n### Tx ###"); + + /* Num HTT cookies queued to dispatch list */ + qdf_print("comp_queued :\t%d", tx->comp_queued); + /* Num HTT cookies dispatched */ + qdf_print("comp_delivered :\t%d", tx->comp_delivered); + /* Num MSDU queued to WAL */ + qdf_print("msdu_enqued :\t%d", tx->msdu_enqued); + /* Num MPDU queued to WAL */ + qdf_print("mpdu_enqued :\t%d", tx->mpdu_enqued); + /* Num MSDUs dropped by WMM limit */ + qdf_print("wmm_drop :\t%d", tx->wmm_drop); + /* Num Local frames queued */ + qdf_print("local_enqued :\t%d", tx->local_enqued); + /* Num Local frames done */ + qdf_print("local_freed :\t%d", tx->local_freed); + /* Num queued to HW */ + qdf_print("hw_queued :\t%d", tx->hw_queued); + /* Num PPDU reaped from HW */ + qdf_print("hw_reaped :\t%d", tx->hw_reaped); + /* Num underruns */ + qdf_print("mac underrun :\t%d", tx->underrun); + /* Num underruns */ + qdf_print("phy underrun :\t%d", tx->phy_underrun); + /* Num PPDUs cleaned up in TX abort */ + qdf_print("tx_abort :\t%d", tx->tx_abort); + /* Num MPDUs requed by SW */ + qdf_print("mpdus_requed :\t%d", tx->mpdus_requed); + /* Excessive retries */ + qdf_print("excess retries :\t%d", tx->tx_ko); + /* last data rate */ + qdf_print("last rc :\t%d", tx->data_rc); + /* scheduler self triggers */ + qdf_print("sched self trig :\t%d", tx->self_triggers); + /* SW retry failures */ + qdf_print("ampdu retry failed:\t%d", tx->sw_retry_failure); + /* ilegal phy rate errirs */ + qdf_print("illegal rate errs :\t%d", tx->illgl_rate_phy_err); + /* pdev continous excessive retries */ + qdf_print("pdev cont xretry :\t%d", tx->pdev_cont_xretry); + /* pdev continous excessive retries */ + qdf_print("pdev tx timeout :\t%d", tx->pdev_tx_timeout); + /* pdev resets */ + qdf_print("pdev resets :\t%d", tx->pdev_resets); + /* PPDU > txop duration */ + qdf_print("ppdu txop ovf :\t%d", tx->txop_ovf); + + qdf_print("\n### Rx ###\n"); + /* Cnts any change in ring routing mid-ppdu */ + qdf_print("ppdu_route_change :\t%d", rx->mid_ppdu_route_change); + /* Total number of statuses processed */ + qdf_print("status_rcvd :\t%d", rx->status_rcvd); + /* Extra frags on rings 0-3 */ + qdf_print("r0_frags :\t%d", rx->r0_frags); + qdf_print("r1_frags :\t%d", rx->r1_frags); + qdf_print("r2_frags :\t%d", rx->r2_frags); + qdf_print("r3_frags :\t%d", rx->r3_frags); + /* MSDUs / MPDUs delivered to HTT */ + qdf_print("htt_msdus :\t%d", rx->htt_msdus); + qdf_print("htt_mpdus :\t%d", rx->htt_mpdus); + /* MSDUs / MPDUs delivered to local stack */ + qdf_print("loc_msdus :\t%d", rx->loc_msdus); + qdf_print("loc_mpdus :\t%d", rx->loc_mpdus); + /* AMSDUs that have more MSDUs than the status ring size */ + qdf_print("oversize_amsdu :\t%d", rx->oversize_amsdu); + /* Number of PHY errors */ + qdf_print("phy_errs :\t%d", rx->phy_errs); + /* Number of PHY errors dropped */ + qdf_print("phy_errs dropped :\t%d", rx->phy_err_drop); + /* Number of mpdu errors - FCS, MIC, ENC etc. */ + qdf_print("mpdu_errs :\t%d", rx->mpdu_errs); + +} + +static void +htt_t2h_stats_rx_reorder_stats_print(struct rx_reorder_stats *stats_ptr, + int concise) +{ + qdf_print("Rx reorder statistics:"); + qdf_print(" %u non-QoS frames received", stats_ptr->deliver_non_qos); + qdf_print(" %u frames received in-order", + stats_ptr->deliver_in_order); + qdf_print(" %u frames flushed due to timeout", + stats_ptr->deliver_flush_timeout); + qdf_print(" %u frames flushed due to moving out of window", + stats_ptr->deliver_flush_oow); + qdf_print(" %u frames flushed due to receiving DELBA", + stats_ptr->deliver_flush_delba); + qdf_print(" %u frames discarded due to FCS error", + stats_ptr->fcs_error); + qdf_print(" %u frames discarded due to invalid peer", + stats_ptr->invalid_peer); + qdf_print + (" %u frames discarded due to duplication (non aggregation)", + stats_ptr->dup_non_aggr); + qdf_print(" %u frames discarded due to duplication in reorder queue", + stats_ptr->dup_in_reorder); + qdf_print(" %u frames discarded due to processed before", + stats_ptr->dup_past); + qdf_print(" %u times reorder timeout happened", + stats_ptr->reorder_timeout); + qdf_print(" %u times incorrect bar received", + stats_ptr->invalid_bar_ssn); + qdf_print(" %u times bar ssn reset happened", + stats_ptr->ssn_reset); + qdf_print(" %u times flushed due to peer delete", + stats_ptr->deliver_flush_delpeer); + qdf_print(" %u times flushed due to offload", + stats_ptr->deliver_flush_offload); + qdf_print(" %u times flushed due to ouf of buffer", + stats_ptr->deliver_flush_oob); + qdf_print(" %u MPDU's dropped due to PN check fail", + stats_ptr->pn_fail); + qdf_print(" %u MPDU's dropped due to lack of memory", + stats_ptr->store_fail); + qdf_print(" %u times tid pool alloc succeeded", + stats_ptr->tid_pool_alloc_succ); + qdf_print(" %u times MPDU pool alloc succeeded", + stats_ptr->mpdu_pool_alloc_succ); + qdf_print(" %u times MSDU pool alloc succeeded", + stats_ptr->msdu_pool_alloc_succ); + qdf_print(" %u times tid pool alloc failed", + stats_ptr->tid_pool_alloc_fail); + qdf_print(" %u times MPDU pool alloc failed", + stats_ptr->mpdu_pool_alloc_fail); + qdf_print(" %u times MSDU pool alloc failed", + stats_ptr->msdu_pool_alloc_fail); + qdf_print(" %u times tid pool freed", + stats_ptr->tid_pool_free); + qdf_print(" %u times MPDU pool freed", + stats_ptr->mpdu_pool_free); + qdf_print(" %u times MSDU pool freed", + stats_ptr->msdu_pool_free); + qdf_print(" %u MSDUs undelivered to HTT, queued to Rx MSDU free list", + stats_ptr->msdu_queued); + qdf_print(" %u MSDUs released from Rx MSDU list to MAC ring", + stats_ptr->msdu_recycled); + qdf_print(" %u MPDUs with invalid peer but A2 found in AST", + stats_ptr->invalid_peer_a2_in_ast); + qdf_print(" %u MPDUs with invalid peer but A3 found in AST", + stats_ptr->invalid_peer_a3_in_ast); + qdf_print(" %u MPDUs with invalid peer, Broadcast or Mulitcast frame", + stats_ptr->invalid_peer_bmc_mpdus); + qdf_print(" %u MSDUs with err attention word", + stats_ptr->rxdesc_err_att); + qdf_print(" %u MSDUs with flag of peer_idx_invalid", + stats_ptr->rxdesc_err_peer_idx_inv); + qdf_print(" %u MSDUs with flag of peer_idx_timeout", + stats_ptr->rxdesc_err_peer_idx_to); + qdf_print(" %u MSDUs with flag of overflow", + stats_ptr->rxdesc_err_ov); + qdf_print(" %u MSDUs with flag of msdu_length_err", + stats_ptr->rxdesc_err_msdu_len); + qdf_print(" %u MSDUs with flag of mpdu_length_err", + stats_ptr->rxdesc_err_mpdu_len); + qdf_print(" %u MSDUs with flag of tkip_mic_err", + stats_ptr->rxdesc_err_tkip_mic); + qdf_print(" %u MSDUs with flag of decrypt_err", + stats_ptr->rxdesc_err_decrypt); + qdf_print(" %u MSDUs with flag of fcs_err", + stats_ptr->rxdesc_err_fcs); + qdf_print(" %u Unicast frames with invalid peer handler", + stats_ptr->rxdesc_uc_msdus_inv_peer); + qdf_print(" %u unicast frame directly to DUT with invalid peer handler", + stats_ptr->rxdesc_direct_msdus_inv_peer); + qdf_print(" %u Broadcast/Multicast frames with invalid peer handler", + stats_ptr->rxdesc_bmc_msdus_inv_peer); + qdf_print(" %u MSDUs dropped due to no first MSDU flag", + stats_ptr->rxdesc_no_1st_msdu); + qdf_print(" %u MSDUs dropped due to ring overflow", + stats_ptr->msdu_drop_ring_ov); + qdf_print(" %u MSDUs dropped due to FC mismatch", + stats_ptr->msdu_drop_fc_mismatch); + qdf_print(" %u MSDUs dropped due to mgt frame in Remote ring", + stats_ptr->msdu_drop_mgmt_remote_ring); + qdf_print(" %u MSDUs dropped due to misc non error", + stats_ptr->msdu_drop_misc); + qdf_print(" %u MSDUs go to offload before reorder", + stats_ptr->offload_msdu_wal); + qdf_print(" %u data frame dropped by offload after reorder", + stats_ptr->offload_msdu_reorder); + qdf_print(" %u MPDUs with SN in the past & within BA window", + stats_ptr->dup_past_within_window); + qdf_print(" %u MPDUs with SN in the past & outside BA window", + stats_ptr->dup_past_outside_window); +} + +static void +htt_t2h_stats_rx_rem_buf_stats_print( + struct rx_remote_buffer_mgmt_stats *stats_ptr, int concise) +{ + qdf_print("Rx Remote Buffer Statistics:"); + qdf_print(" %u MSDU's reaped for Rx processing", + stats_ptr->remote_reaped); + qdf_print(" %u MSDU's recycled within firmware", + stats_ptr->remote_recycled); + qdf_print(" %u MSDU's stored by Data Rx", + stats_ptr->data_rx_msdus_stored); + qdf_print(" %u HTT indications from WAL Rx MSDU", + stats_ptr->wal_rx_ind); + qdf_print(" %u HTT indications unconsumed from WAL Rx MSDU", + stats_ptr->wal_rx_ind_unconsumed); + qdf_print(" %u HTT indications from Data Rx MSDU", + stats_ptr->data_rx_ind); + qdf_print(" %u HTT indications unconsumed from Data Rx MSDU", + stats_ptr->data_rx_ind_unconsumed); + qdf_print(" %u HTT indications from ATHBUF", + stats_ptr->athbuf_rx_ind); + qdf_print(" %u Remote buffers requested for refill", + stats_ptr->refill_buf_req); + qdf_print(" %u Remote buffers filled by host", + stats_ptr->refill_buf_rsp); + qdf_print(" %u times MAC has no buffers", + stats_ptr->mac_no_bufs); + qdf_print(" %u times f/w write & read indices on MAC ring are equal", + stats_ptr->fw_indices_equal); + qdf_print(" %u times f/w has no remote buffers to post to MAC", + stats_ptr->host_no_bufs); +} + +static void +htt_t2h_stats_txbf_info_buf_stats_print( + struct wlan_dbg_txbf_data_stats *stats_ptr) +{ + qdf_print("TXBF data Statistics:"); + qdf_print("tx_txbf_vht (0..9): %u, %u, %u, %u, %u, %u, %u, %u, %u, %d", + stats_ptr->tx_txbf_vht[0], + stats_ptr->tx_txbf_vht[1], + stats_ptr->tx_txbf_vht[2], + stats_ptr->tx_txbf_vht[3], + stats_ptr->tx_txbf_vht[4], + stats_ptr->tx_txbf_vht[5], + stats_ptr->tx_txbf_vht[6], + stats_ptr->tx_txbf_vht[7], + stats_ptr->tx_txbf_vht[8], + stats_ptr->tx_txbf_vht[9]); + qdf_print("rx_txbf_vht (0..9): %u, %u, %u, %u, %u, %u, %u, %u, %u, %u", + stats_ptr->rx_txbf_vht[0], + stats_ptr->rx_txbf_vht[1], + stats_ptr->rx_txbf_vht[2], + stats_ptr->rx_txbf_vht[3], + stats_ptr->rx_txbf_vht[4], + stats_ptr->rx_txbf_vht[5], + stats_ptr->rx_txbf_vht[6], + stats_ptr->rx_txbf_vht[7], + stats_ptr->rx_txbf_vht[8], + stats_ptr->rx_txbf_vht[9]); + qdf_print("tx_txbf_ht (0..7): %u, %u, %u, %u, %u, %u, %u, %u", + stats_ptr->tx_txbf_ht[0], + stats_ptr->tx_txbf_ht[1], + stats_ptr->tx_txbf_ht[2], + stats_ptr->tx_txbf_ht[3], + stats_ptr->tx_txbf_ht[4], + stats_ptr->tx_txbf_ht[5], + stats_ptr->tx_txbf_ht[6], + stats_ptr->tx_txbf_ht[7]); + qdf_print("tx_txbf_ofdm (0..7): %u, %u, %u, %u, %u, %u, %u, %u", + stats_ptr->tx_txbf_ofdm[0], + stats_ptr->tx_txbf_ofdm[1], + stats_ptr->tx_txbf_ofdm[2], + stats_ptr->tx_txbf_ofdm[3], + stats_ptr->tx_txbf_ofdm[4], + stats_ptr->tx_txbf_ofdm[5], + stats_ptr->tx_txbf_ofdm[6], + stats_ptr->tx_txbf_ofdm[7]); + qdf_print("tx_txbf_cck (0..6): %u, %u, %u, %u, %u, %u, %u", + stats_ptr->tx_txbf_cck[0], + stats_ptr->tx_txbf_cck[1], + stats_ptr->tx_txbf_cck[2], + stats_ptr->tx_txbf_cck[3], + stats_ptr->tx_txbf_cck[4], + stats_ptr->tx_txbf_cck[5], + stats_ptr->tx_txbf_cck[6]); +} + +static void +htt_t2h_stats_txbf_snd_buf_stats_print( + struct wlan_dbg_txbf_snd_stats *stats_ptr) +{ + qdf_print("TXBF snd Buffer Statistics:"); + qdf_print("cbf_20: %u, %u, %u, %u", + stats_ptr->cbf_20[0], + stats_ptr->cbf_20[1], + stats_ptr->cbf_20[2], + stats_ptr->cbf_20[3]); + qdf_print("cbf_40: %u, %u, %u, %u", + stats_ptr->cbf_40[0], + stats_ptr->cbf_40[1], + stats_ptr->cbf_40[2], + stats_ptr->cbf_40[3]); + qdf_print("cbf_80: %u, %u, %u, %u", + stats_ptr->cbf_80[0], + stats_ptr->cbf_80[1], + stats_ptr->cbf_80[2], + stats_ptr->cbf_80[3]); + qdf_print("sounding: %u, %u, %u, %u, %u, %u, %u, %u, %u", + stats_ptr->sounding[0], + stats_ptr->sounding[1], + stats_ptr->sounding[2], + stats_ptr->sounding[3], + stats_ptr->sounding[4], + stats_ptr->sounding[5], + stats_ptr->sounding[6], + stats_ptr->sounding[7], + stats_ptr->sounding[8]); +} + +static void +htt_t2h_stats_tx_selfgen_buf_stats_print( + struct wlan_dbg_tx_selfgen_stats *stats_ptr) +{ + qdf_print("Tx selfgen Buffer Statistics:"); + qdf_print(" %u su_ndpa", + stats_ptr->su_ndpa); + qdf_print(" %u mu_ndp", + stats_ptr->mu_ndp); + qdf_print(" %u mu_ndpa", + stats_ptr->mu_ndpa); + qdf_print(" %u mu_ndp", + stats_ptr->mu_ndp); + qdf_print(" %u mu_brpoll_1", + stats_ptr->mu_brpoll_1); + qdf_print(" %u mu_brpoll_2", + stats_ptr->mu_brpoll_2); + qdf_print(" %u mu_bar_1", + stats_ptr->mu_bar_1); + qdf_print(" %u mu_bar_2", + stats_ptr->mu_bar_2); + qdf_print(" %u cts_burst", + stats_ptr->cts_burst); + qdf_print(" %u su_ndp_err", + stats_ptr->su_ndp_err); + qdf_print(" %u su_ndpa_err", + stats_ptr->su_ndpa_err); + qdf_print(" %u mu_ndp_err", + stats_ptr->mu_ndp_err); + qdf_print(" %u mu_brp1_err", + stats_ptr->mu_brp1_err); + qdf_print(" %u mu_brp2_err", + stats_ptr->mu_brp2_err); +} + +static void +htt_t2h_stats_wifi2_error_stats_print( + struct wlan_dbg_wifi2_error_stats *stats_ptr) +{ + int i; + + qdf_print("Scheduler error Statistics:"); + qdf_print("urrn_stats: "); + qdf_print("urrn_stats: %d, %d, %d", + stats_ptr->urrn_stats[0], + stats_ptr->urrn_stats[1], + stats_ptr->urrn_stats[2]); + qdf_print("flush_errs (0..%d): ", + WHAL_DBG_FLUSH_REASON_MAXCNT); + for (i = 0; i < WHAL_DBG_FLUSH_REASON_MAXCNT; i++) + qdf_print(" %u", stats_ptr->flush_errs[i]); + qdf_print("\n"); + qdf_print("schd_stall_errs (0..3): "); + qdf_print("%d, %d, %d, %d", + stats_ptr->schd_stall_errs[0], + stats_ptr->schd_stall_errs[1], + stats_ptr->schd_stall_errs[2], + stats_ptr->schd_stall_errs[3]); + qdf_print("schd_cmd_result (0..%d): ", + WHAL_DBG_CMD_RESULT_MAXCNT); + for (i = 0; i < WHAL_DBG_CMD_RESULT_MAXCNT; i++) + qdf_print(" %u", stats_ptr->schd_cmd_result[i]); + qdf_print("\n"); + qdf_print("sifs_status (0..%d): ", + WHAL_DBG_SIFS_STATUS_MAXCNT); + for (i = 0; i < WHAL_DBG_SIFS_STATUS_MAXCNT; i++) + qdf_print(" %u", stats_ptr->sifs_status[i]); + qdf_print("\n"); + qdf_print("phy_errs (0..%d): ", + WHAL_DBG_PHY_ERR_MAXCNT); + for (i = 0; i < WHAL_DBG_PHY_ERR_MAXCNT; i++) + qdf_print(" %u", stats_ptr->phy_errs[i]); + qdf_print("\n"); + qdf_print(" %u rx_rate_inval", + stats_ptr->rx_rate_inval); +} + +static void +htt_t2h_rx_musu_ndpa_pkts_stats_print( + struct rx_txbf_musu_ndpa_pkts_stats *stats_ptr) +{ + qdf_print("Rx TXBF MU/SU Packets and NDPA Statistics:"); + qdf_print(" %u Number of TXBF MU packets received", + stats_ptr->number_mu_pkts); + qdf_print(" %u Number of TXBF SU packets received", + stats_ptr->number_su_pkts); + qdf_print(" %u Number of TXBF directed NDPA", + stats_ptr->txbf_directed_ndpa_count); + qdf_print(" %u Number of TXBF retried NDPA", + stats_ptr->txbf_ndpa_retry_count); + qdf_print(" %u Total number of TXBF NDPA", + stats_ptr->txbf_total_ndpa_count); +} + +#define HTT_TICK_TO_USEC(ticks, microsec_per_tick) (ticks * microsec_per_tick) +static inline int htt_rate_flags_to_mhz(uint8_t rate_flags) +{ + if (rate_flags & 0x20) + return 40; /* WHAL_RC_FLAG_40MHZ */ + if (rate_flags & 0x40) + return 80; /* WHAL_RC_FLAG_80MHZ */ + if (rate_flags & 0x80) + return 160; /* WHAL_RC_FLAG_160MHZ */ + return 20; +} + +#define HTT_FW_STATS_MAX_BLOCK_ACK_WINDOW 64 + +static void +htt_t2h_tx_ppdu_bitmaps_pr(uint32_t *queued_ptr, uint32_t *acked_ptr) +{ + char queued_str[HTT_FW_STATS_MAX_BLOCK_ACK_WINDOW + 1]; + char acked_str[HTT_FW_STATS_MAX_BLOCK_ACK_WINDOW + 1]; + int i, j, word; + + qdf_mem_set(queued_str, HTT_FW_STATS_MAX_BLOCK_ACK_WINDOW, '0'); + qdf_mem_set(acked_str, HTT_FW_STATS_MAX_BLOCK_ACK_WINDOW, '-'); + i = 0; + for (word = 0; word < 2; word++) { + uint32_t queued = *(queued_ptr + word); + uint32_t acked = *(acked_ptr + word); + for (j = 0; j < 32; j++, i++) { + if (queued & (1 << j)) { + queued_str[i] = '1'; + acked_str[i] = (acked & (1 << j)) ? 'y' : 'N'; + } + } + } + queued_str[HTT_FW_STATS_MAX_BLOCK_ACK_WINDOW] = '\0'; + acked_str[HTT_FW_STATS_MAX_BLOCK_ACK_WINDOW] = '\0'; + qdf_print("%s\n", queued_str); + qdf_print("%s\n", acked_str); +} + +static inline uint16_t htt_msg_read16(uint16_t *p16) +{ +#ifdef BIG_ENDIAN_HOST + /* + * During upload, the bytes within each uint32_t word were + * swapped by the HIF HW. This results in the lower and upper bytes + * of each uint16_t to be in the correct big-endian order with + * respect to each other, but for each even-index uint16_t to + * have its position switched with its successor neighbor uint16_t. + * Undo this uint16_t position swapping. + */ + return (((size_t) p16) & 0x2) ? *(p16 - 1) : *(p16 + 1); +#else + return *p16; +#endif +} + +static inline uint8_t htt_msg_read8(uint8_t *p8) +{ +#ifdef BIG_ENDIAN_HOST + /* + * During upload, the bytes within each uint32_t word were + * swapped by the HIF HW. + * Undo this byte swapping. + */ + switch (((size_t) p8) & 0x3) { + case 0: + return *(p8 + 3); + case 1: + return *(p8 + 1); + case 2: + return *(p8 - 1); + default /* 3 */: + return *(p8 - 3); + } +#else + return *p8; +#endif +} + +static void htt_make_u8_list_str(uint32_t *aligned_data, + char *buffer, int space, int max_elems) +{ + uint8_t *p8 = (uint8_t *) aligned_data; + char *buf_p = buffer; + while (max_elems-- > 0) { + int bytes; + uint8_t val; + + val = htt_msg_read8(p8); + if (val == 0) + /* not enough data to fill the reserved msg buffer*/ + break; + + bytes = qdf_snprint(buf_p, space, "%d,", val); + space -= bytes; + if (space > 0) + buf_p += bytes; + else /* not enough print buffer space for all the data */ + break; + p8++; + } + if (buf_p == buffer) + *buf_p = '\0'; /* nothing was written */ + else + *(buf_p - 1) = '\0'; /* erase the final comma */ + +} + +static void htt_make_u16_list_str(uint32_t *aligned_data, + char *buffer, int space, int max_elems) +{ + uint16_t *p16 = (uint16_t *) aligned_data; + char *buf_p = buffer; + while (max_elems-- > 0) { + int bytes; + uint16_t val; + + val = htt_msg_read16(p16); + if (val == 0) + /* not enough data to fill the reserved msg buffer */ + break; + bytes = qdf_snprint(buf_p, space, "%d,", val); + space -= bytes; + if (space > 0) + buf_p += bytes; + else /* not enough print buffer space for all the data */ + break; + + p16++; + } + if (buf_p == buffer) + *buf_p = '\0'; /* nothing was written */ + else + *(buf_p - 1) = '\0'; /* erase the final comma */ +} + +static void +htt_t2h_tx_ppdu_log_print(struct ol_fw_tx_dbg_ppdu_msg_hdr *hdr, + struct ol_fw_tx_dbg_ppdu_base *record, + int length, int concise) +{ + int i; + int record_size; + int num_records; + + record_size = + sizeof(*record) + + hdr->mpdu_bytes_array_len * sizeof(uint16_t) + + hdr->mpdu_msdus_array_len * sizeof(uint8_t) + + hdr->msdu_bytes_array_len * sizeof(uint16_t); + num_records = (length - sizeof(*hdr)) / record_size; + qdf_print("Tx PPDU log elements: num_records %d", num_records); + + for (i = 0; i < num_records; i++) { + uint16_t start_seq_num; + uint16_t start_pn_lsbs; + uint8_t num_mpdus; + uint16_t peer_id; + uint8_t ext_tid; + uint8_t rate_code; + uint8_t rate_flags; + uint8_t tries; + uint8_t complete; + uint32_t time_enqueue_us; + uint32_t time_completion_us; + uint32_t *msg_word = (uint32_t *) record; + + /* fields used for both concise and complete printouts */ + start_seq_num = + ((*(msg_word + OL_FW_TX_DBG_PPDU_START_SEQ_NUM_WORD)) & + OL_FW_TX_DBG_PPDU_START_SEQ_NUM_M) >> + OL_FW_TX_DBG_PPDU_START_SEQ_NUM_S; + complete = + ((*(msg_word + OL_FW_TX_DBG_PPDU_COMPLETE_WORD)) & + OL_FW_TX_DBG_PPDU_COMPLETE_M) >> + OL_FW_TX_DBG_PPDU_COMPLETE_S; + + /* fields used only for complete printouts */ + if (!concise) { +#define BUF_SIZE 80 + char buf[BUF_SIZE]; + uint8_t *p8; + time_enqueue_us = + HTT_TICK_TO_USEC(record->timestamp_enqueue, + hdr->microsec_per_tick); + time_completion_us = + HTT_TICK_TO_USEC(record->timestamp_completion, + hdr->microsec_per_tick); + + start_pn_lsbs = + ((* + (msg_word + + OL_FW_TX_DBG_PPDU_START_PN_LSBS_WORD)) & + OL_FW_TX_DBG_PPDU_START_PN_LSBS_M) >> + OL_FW_TX_DBG_PPDU_START_PN_LSBS_S; + num_mpdus = + ((*(msg_word + OL_FW_TX_DBG_PPDU_NUM_MPDUS_WORD))& + OL_FW_TX_DBG_PPDU_NUM_MPDUS_M) >> + OL_FW_TX_DBG_PPDU_NUM_MPDUS_S; + peer_id = + ((*(msg_word + OL_FW_TX_DBG_PPDU_PEER_ID_WORD)) & + OL_FW_TX_DBG_PPDU_PEER_ID_M) >> + OL_FW_TX_DBG_PPDU_PEER_ID_S; + ext_tid = + ((*(msg_word + OL_FW_TX_DBG_PPDU_EXT_TID_WORD)) & + OL_FW_TX_DBG_PPDU_EXT_TID_M) >> + OL_FW_TX_DBG_PPDU_EXT_TID_S; + rate_code = + ((*(msg_word + OL_FW_TX_DBG_PPDU_RATE_CODE_WORD))& + OL_FW_TX_DBG_PPDU_RATE_CODE_M) >> + OL_FW_TX_DBG_PPDU_RATE_CODE_S; + rate_flags = + ((*(msg_word + OL_FW_TX_DBG_PPDU_RATE_FLAGS_WORD))& + OL_FW_TX_DBG_PPDU_RATE_FLAGS_M) >> + OL_FW_TX_DBG_PPDU_RATE_FLAGS_S; + tries = + ((*(msg_word + OL_FW_TX_DBG_PPDU_TRIES_WORD)) & + OL_FW_TX_DBG_PPDU_TRIES_M) >> + OL_FW_TX_DBG_PPDU_TRIES_S; + + qdf_print(" - PPDU tx to peer %d, TID %d", peer_id, + ext_tid); + qdf_print + (" start seq num= %u, start PN LSBs= %#04x", + start_seq_num, start_pn_lsbs); + qdf_print + (" PPDU: %d MPDUs, (?) MSDUs, %d bytes", + num_mpdus, + /* num_msdus - not yet computed in target */ + record->num_bytes); + if (complete) { + qdf_print + (" enqueued: %u, completed: %u usec)", + time_enqueue_us, time_completion_us); + qdf_print + (" %d tries, last tx used rate %d ", + tries, rate_code); + qdf_print("on %d MHz chan (flags = %#x)", + htt_rate_flags_to_mhz + (rate_flags), rate_flags); + qdf_print + (" enqueued and acked MPDU bitmaps:"); + htt_t2h_tx_ppdu_bitmaps_pr(msg_word + + OL_FW_TX_DBG_PPDU_ENQUEUED_LSBS_WORD, + msg_word + + OL_FW_TX_DBG_PPDU_BLOCK_ACK_LSBS_WORD); + } else { + qdf_print + (" enqueued: %d us, not yet completed", + time_enqueue_us); + } + /* skip the regular msg fields to reach the tail area */ + p8 = (uint8_t *) record; + p8 += sizeof(struct ol_fw_tx_dbg_ppdu_base); + if (hdr->mpdu_bytes_array_len) { + htt_make_u16_list_str((uint32_t *) p8, buf, + BUF_SIZE, + hdr-> + mpdu_bytes_array_len); + qdf_print(" MPDU bytes: %s", buf); + } + p8 += hdr->mpdu_bytes_array_len * sizeof(uint16_t); + if (hdr->mpdu_msdus_array_len) { + htt_make_u8_list_str((uint32_t *) p8, buf, + BUF_SIZE, + hdr->mpdu_msdus_array_len); + qdf_print(" MPDU MSDUs: %s", buf); + } + p8 += hdr->mpdu_msdus_array_len * sizeof(uint8_t); + if (hdr->msdu_bytes_array_len) { + htt_make_u16_list_str((uint32_t *) p8, buf, + BUF_SIZE, + hdr-> + msdu_bytes_array_len); + qdf_print(" MSDU bytes: %s", buf); + } + } else { + /* concise */ + qdf_print("start seq num = %u ", start_seq_num); + qdf_print("enqueued and acked MPDU bitmaps:"); + if (complete) { + htt_t2h_tx_ppdu_bitmaps_pr(msg_word + + OL_FW_TX_DBG_PPDU_ENQUEUED_LSBS_WORD, + msg_word + + OL_FW_TX_DBG_PPDU_BLOCK_ACK_LSBS_WORD); + } else { + qdf_print("(not completed)"); + } + } + record = (struct ol_fw_tx_dbg_ppdu_base *) + (((uint8_t *) record) + record_size); + } +} + +static void htt_t2h_stats_tidq_stats_print( + struct wlan_dbg_tidq_stats *tidq_stats, int concise) +{ + qdf_print("TID QUEUE STATS:"); + qdf_print("tid_txq_stats: %u", tidq_stats->wlan_dbg_tid_txq_status); + qdf_print("num_pkts_queued(0..9):"); + qdf_print("%u, %u, %u, %u, %u, %u, %u, %u, %u, %u", + tidq_stats->txq_st.num_pkts_queued[0], + tidq_stats->txq_st.num_pkts_queued[1], + tidq_stats->txq_st.num_pkts_queued[2], + tidq_stats->txq_st.num_pkts_queued[3], + tidq_stats->txq_st.num_pkts_queued[4], + tidq_stats->txq_st.num_pkts_queued[5], + tidq_stats->txq_st.num_pkts_queued[6], + tidq_stats->txq_st.num_pkts_queued[7], + tidq_stats->txq_st.num_pkts_queued[8], + tidq_stats->txq_st.num_pkts_queued[9]); + qdf_print("tid_hw_qdepth(0..19):"); + qdf_print("%u, %u, %u, %u, %u, %u, %u, %u, %u, %u", + tidq_stats->txq_st.tid_hw_qdepth[0], + tidq_stats->txq_st.tid_hw_qdepth[1], + tidq_stats->txq_st.tid_hw_qdepth[2], + tidq_stats->txq_st.tid_hw_qdepth[3], + tidq_stats->txq_st.tid_hw_qdepth[4], + tidq_stats->txq_st.tid_hw_qdepth[5], + tidq_stats->txq_st.tid_hw_qdepth[6], + tidq_stats->txq_st.tid_hw_qdepth[7], + tidq_stats->txq_st.tid_hw_qdepth[8], + tidq_stats->txq_st.tid_hw_qdepth[9]); + qdf_print("%u, %u, %u, %u, %u, %u, %u, %u, %u, %u", + tidq_stats->txq_st.tid_hw_qdepth[10], + tidq_stats->txq_st.tid_hw_qdepth[11], + tidq_stats->txq_st.tid_hw_qdepth[12], + tidq_stats->txq_st.tid_hw_qdepth[13], + tidq_stats->txq_st.tid_hw_qdepth[14], + tidq_stats->txq_st.tid_hw_qdepth[15], + tidq_stats->txq_st.tid_hw_qdepth[16], + tidq_stats->txq_st.tid_hw_qdepth[17], + tidq_stats->txq_st.tid_hw_qdepth[18], + tidq_stats->txq_st.tid_hw_qdepth[19]); + qdf_print("tid_sw_qdepth(0..19):"); + qdf_print("%u, %u, %u, %u, %u, %u, %u, %u, %u, %u", + tidq_stats->txq_st.tid_sw_qdepth[0], + tidq_stats->txq_st.tid_sw_qdepth[1], + tidq_stats->txq_st.tid_sw_qdepth[2], + tidq_stats->txq_st.tid_sw_qdepth[3], + tidq_stats->txq_st.tid_sw_qdepth[4], + tidq_stats->txq_st.tid_sw_qdepth[5], + tidq_stats->txq_st.tid_sw_qdepth[6], + tidq_stats->txq_st.tid_sw_qdepth[7], + tidq_stats->txq_st.tid_sw_qdepth[8], + tidq_stats->txq_st.tid_sw_qdepth[9]); + qdf_print("%u, %u, %u, %u, %u, %u, %u, %u, %u, %u", + tidq_stats->txq_st.tid_sw_qdepth[10], + tidq_stats->txq_st.tid_sw_qdepth[11], + tidq_stats->txq_st.tid_sw_qdepth[12], + tidq_stats->txq_st.tid_sw_qdepth[13], + tidq_stats->txq_st.tid_sw_qdepth[14], + tidq_stats->txq_st.tid_sw_qdepth[15], + tidq_stats->txq_st.tid_sw_qdepth[16], + tidq_stats->txq_st.tid_sw_qdepth[17], + tidq_stats->txq_st.tid_sw_qdepth[18], + tidq_stats->txq_st.tid_sw_qdepth[19]); +} + +static void htt_t2h_stats_tx_mu_stats_print( + struct wlan_dbg_tx_mu_stats *tx_mu_stats, int concise) +{ + qdf_print("TX MU STATS:"); + qdf_print("mu_sch_nusers_2: %u", tx_mu_stats->mu_sch_nusers_2); + qdf_print("mu_sch_nusers_3: %u", tx_mu_stats->mu_sch_nusers_3); + qdf_print("mu_mpdus_queued_usr: %u, %u, %u, %u", + tx_mu_stats->mu_mpdus_queued_usr[0], + tx_mu_stats->mu_mpdus_queued_usr[1], + tx_mu_stats->mu_mpdus_queued_usr[2], + tx_mu_stats->mu_mpdus_queued_usr[3]); + qdf_print("mu_mpdus_tried_usr: %u, %u, %u, %u", + tx_mu_stats->mu_mpdus_tried_usr[0], + tx_mu_stats->mu_mpdus_tried_usr[1], + tx_mu_stats->mu_mpdus_tried_usr[2], + tx_mu_stats->mu_mpdus_tried_usr[3]); + qdf_print("mu_mpdus_failed_usr: %u, %u, %u, %u", + tx_mu_stats->mu_mpdus_failed_usr[0], + tx_mu_stats->mu_mpdus_failed_usr[1], + tx_mu_stats->mu_mpdus_failed_usr[2], + tx_mu_stats->mu_mpdus_failed_usr[3]); + qdf_print("mu_mpdus_requeued_usr: %u, %u, %u, %u", + tx_mu_stats->mu_mpdus_requeued_usr[0], + tx_mu_stats->mu_mpdus_requeued_usr[1], + tx_mu_stats->mu_mpdus_requeued_usr[2], + tx_mu_stats->mu_mpdus_requeued_usr[3]); + qdf_print("mu_err_no_ba_usr: %u, %u, %u, %u", + tx_mu_stats->mu_err_no_ba_usr[0], + tx_mu_stats->mu_err_no_ba_usr[1], + tx_mu_stats->mu_err_no_ba_usr[2], + tx_mu_stats->mu_err_no_ba_usr[3]); + qdf_print("mu_mpdu_underrun_usr: %u, %u, %u, %u", + tx_mu_stats->mu_mpdu_underrun_usr[0], + tx_mu_stats->mu_mpdu_underrun_usr[1], + tx_mu_stats->mu_mpdu_underrun_usr[2], + tx_mu_stats->mu_mpdu_underrun_usr[3]); + qdf_print("mu_ampdu_underrun_usr: %u, %u, %u, %u", + tx_mu_stats->mu_ampdu_underrun_usr[0], + tx_mu_stats->mu_ampdu_underrun_usr[1], + tx_mu_stats->mu_ampdu_underrun_usr[2], + tx_mu_stats->mu_ampdu_underrun_usr[3]); + +} + +static void htt_t2h_stats_sifs_resp_stats_print( + struct wlan_dbg_sifs_resp_stats *sifs_stats, int concise) +{ + qdf_print("SIFS RESP STATS:"); + qdf_print("num of ps-poll trigger frames: %u", + sifs_stats->ps_poll_trigger); + qdf_print("num of uapsd trigger frames: %u", + sifs_stats->uapsd_trigger); + qdf_print("num of data trigger frames: %u, %u", + sifs_stats->qb_data_trigger[0], + sifs_stats->qb_data_trigger[1]); + qdf_print("num of bar trigger frames: %u, %u", + sifs_stats->qb_bar_trigger[0], + sifs_stats->qb_bar_trigger[1]); + qdf_print("num of ppdu transmitted at SIFS interval: %u", + sifs_stats->sifs_resp_data); + qdf_print("num of ppdu failed to meet SIFS resp timing: %u", + sifs_stats->sifs_resp_err); +} + +void htt_t2h_stats_print(uint8_t *stats_data, int concise) +{ + uint32_t *msg_word = (uint32_t *) stats_data; + enum htt_dbg_stats_type type; + enum htt_dbg_stats_status status; + int length; + + type = HTT_T2H_STATS_CONF_TLV_TYPE_GET(*msg_word); + status = HTT_T2H_STATS_CONF_TLV_STATUS_GET(*msg_word); + length = HTT_T2H_STATS_CONF_TLV_LENGTH_GET(*msg_word); + + /* check that we've been given a valid stats type */ + if (status == HTT_DBG_STATS_STATUS_SERIES_DONE) { + return; + } else if (status == HTT_DBG_STATS_STATUS_INVALID) { + qdf_print("Target doesn't support stats type %d", type); + return; + } else if (status == HTT_DBG_STATS_STATUS_ERROR) { + qdf_print("Target couldn't upload stats type %d (no mem?)", + type); + return; + } + /* got valid (though perhaps partial) stats - process them */ + switch (type) { + case HTT_DBG_STATS_WAL_PDEV_TXRX: + { + struct wlan_dbg_stats *wlan_dbg_stats_ptr; + + wlan_dbg_stats_ptr = + (struct wlan_dbg_stats *)(msg_word + 1); + htt_t2h_stats_pdev_stats_print(wlan_dbg_stats_ptr, + concise); + break; + } + case HTT_DBG_STATS_RX_REORDER: + { + struct rx_reorder_stats *rx_reorder_stats_ptr; + + rx_reorder_stats_ptr = + (struct rx_reorder_stats *)(msg_word + 1); + htt_t2h_stats_rx_reorder_stats_print + (rx_reorder_stats_ptr, concise); + break; + } + + case HTT_DBG_STATS_RX_RATE_INFO: + { + wlan_dbg_rx_rate_info_t *rx_phy_info; + rx_phy_info = + (wlan_dbg_rx_rate_info_t *) (msg_word + 1); + + htt_t2h_stats_rx_rate_stats_print(rx_phy_info, concise); + + break; + } + case HTT_DBG_STATS_RX_RATE_INFO_V2: + { + wlan_dbg_rx_rate_info_v2_t *rx_phy_info; + rx_phy_info = + (wlan_dbg_rx_rate_info_v2_t *) (msg_word + 1); + htt_t2h_stats_rx_rate_stats_print_v2(rx_phy_info, concise); + break; + } + case HTT_DBG_STATS_TX_PPDU_LOG: + { + struct ol_fw_tx_dbg_ppdu_msg_hdr *hdr; + struct ol_fw_tx_dbg_ppdu_base *record; + + if (status == HTT_DBG_STATS_STATUS_PARTIAL + && length == 0) { + qdf_print + ("HTT_DBG_STATS_TX_PPDU_LOG -- length = 0!"); + break; + } + hdr = + (struct ol_fw_tx_dbg_ppdu_msg_hdr *)(msg_word + 1); + record = (struct ol_fw_tx_dbg_ppdu_base *)(hdr + 1); + htt_t2h_tx_ppdu_log_print(hdr, record, length, concise); + } + break; + case HTT_DBG_STATS_TX_RATE_INFO: + { + wlan_dbg_tx_rate_info_t *tx_rate_info; + tx_rate_info = + (wlan_dbg_tx_rate_info_t *) (msg_word + 1); + + htt_t2h_stats_tx_rate_stats_print(tx_rate_info, concise); + + break; + } + case HTT_DBG_STATS_TX_RATE_INFO_V2: + { + wlan_dbg_tx_rate_info_v2_t *tx_rate_info; + tx_rate_info = + (wlan_dbg_tx_rate_info_v2_t *) (msg_word + 1); + htt_t2h_stats_tx_rate_stats_print_v2(tx_rate_info, concise); + break; + } + case HTT_DBG_STATS_RX_REMOTE_RING_BUFFER_INFO: + { + struct rx_remote_buffer_mgmt_stats *rx_rem_buf; + + rx_rem_buf = (struct rx_remote_buffer_mgmt_stats *)(msg_word + 1); + htt_t2h_stats_rx_rem_buf_stats_print(rx_rem_buf, concise); + break; + } + case HTT_DBG_STATS_TXBF_INFO: + { + struct wlan_dbg_txbf_data_stats *txbf_info_buf; + + txbf_info_buf = + (struct wlan_dbg_txbf_data_stats *)(msg_word + 1); + htt_t2h_stats_txbf_info_buf_stats_print(txbf_info_buf); + break; + } + case HTT_DBG_STATS_SND_INFO: + { + struct wlan_dbg_txbf_snd_stats *txbf_snd_buf; + + txbf_snd_buf = + (struct wlan_dbg_txbf_snd_stats *)(msg_word + 1); + htt_t2h_stats_txbf_snd_buf_stats_print(txbf_snd_buf); + break; + } + case HTT_DBG_STATS_TX_SELFGEN_INFO: + { + struct wlan_dbg_tx_selfgen_stats *tx_selfgen_buf; + + tx_selfgen_buf = + (struct wlan_dbg_tx_selfgen_stats *)(msg_word + 1); + htt_t2h_stats_tx_selfgen_buf_stats_print(tx_selfgen_buf); + break; + } + case HTT_DBG_STATS_ERROR_INFO: + { + struct wlan_dbg_wifi2_error_stats *wifi2_error_buf; + + wifi2_error_buf = + (struct wlan_dbg_wifi2_error_stats *)(msg_word + 1); + htt_t2h_stats_wifi2_error_stats_print(wifi2_error_buf); + break; + } + case HTT_DBG_STATS_TXBF_MUSU_NDPA_PKT: + { + struct rx_txbf_musu_ndpa_pkts_stats *rx_musu_ndpa_stats; + + rx_musu_ndpa_stats = (struct rx_txbf_musu_ndpa_pkts_stats *) + (msg_word + 1); + htt_t2h_rx_musu_ndpa_pkts_stats_print(rx_musu_ndpa_stats); + break; + } + case HTT_DBG_STATS_TIDQ: + { + struct wlan_dbg_tidq_stats *tidq_stats; + tidq_stats = (struct wlan_dbg_tidq_stats *)(msg_word + 1); + + htt_t2h_stats_tidq_stats_print(tidq_stats, concise); + break; + } + case HTT_DBG_STATS_TX_MU_INFO: + { + struct wlan_dbg_tx_mu_stats *tx_mu_stats; + tx_mu_stats = (struct wlan_dbg_tx_mu_stats *)(msg_word + 1); + + htt_t2h_stats_tx_mu_stats_print(tx_mu_stats, concise); + break; + } + case HTT_DBG_STATS_SIFS_RESP_INFO: + { + struct wlan_dbg_sifs_resp_stats *sifs_stats; + sifs_stats = (struct wlan_dbg_sifs_resp_stats *)(msg_word + 1); + + htt_t2h_stats_sifs_resp_stats_print(sifs_stats, concise); + break; + } + default: + break; + } +} diff --git a/drivers/staging/qcacld-3.0/core/dp/htt/htt_h2t.c b/drivers/staging/qcacld-3.0/core/dp/htt/htt_h2t.c new file mode 100644 index 0000000000000000000000000000000000000000..7e2197d2f99935847a1c56d408829468cdb0e0a1 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/dp/htt/htt_h2t.c @@ -0,0 +1,1466 @@ +/* + * Copyright (c) 2011-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * @file htt_h2t.c + * @brief Provide functions to send host->target HTT messages. + * @details + * This file contains functions related to host->target HTT messages. + * There are a couple aspects of this host->target messaging: + * 1. This file contains the function that is called by HTC when + * a host->target send completes. + * This send-completion callback is primarily relevant to HL, + * to invoke the download scheduler to set up a new download, + * and optionally free the tx frame whose download is completed. + * For both HL and LL, this completion callback frees up the + * HTC_PACKET object used to specify the download. + * 2. This file contains functions for creating messages to send + * from the host to the target. + */ + +#include /* qdf_mem_copy */ +#include /* qdf_nbuf_map_single */ +#include /* HTC_PACKET */ +#include /* HTC_HDR_ALIGNMENT_PADDING */ +#include /* HTT host->target msg defs */ +#include /* ol_tx_completion_handler, htt_tx_status */ +#include + +#include +#include + +#define HTT_MSG_BUF_SIZE(msg_bytes) \ + ((msg_bytes) + HTC_HEADER_LEN + HTC_HDR_ALIGNMENT_PADDING) + +#ifndef container_of +#define container_of(ptr, type, member) \ + ((type *)((char *)(ptr) - (char *)(&((type *)0)->member))) +#endif + +#ifdef ATH_11AC_TXCOMPACT +#define HTT_SEND_HTC_PKT(pdev, pkt) \ +do { \ + if (htc_send_pkt(pdev->htc_pdev, &pkt->htc_pkt) == A_OK) \ + htt_htc_misc_pkt_list_add(pdev, pkt); \ +} while (0) +#else +#define HTT_SEND_HTC_PKT(pdev, ppkt) htc_send_pkt(pdev->htc_pdev, &pkt->htc_pkt); +#endif + + +static void +htt_h2t_send_complete_free_netbuf(void *pdev, A_STATUS status, + qdf_nbuf_t netbuf, uint16_t msdu_id) +{ + qdf_nbuf_free(netbuf); +} + +void htt_h2t_send_complete(void *context, HTC_PACKET *htc_pkt) +{ + void (*send_complete_part2)(void *pdev, A_STATUS status, + qdf_nbuf_t msdu, uint16_t msdu_id); + struct htt_pdev_t *pdev = (struct htt_pdev_t *)context; + struct htt_htc_pkt *htt_pkt; + qdf_nbuf_t netbuf; + + send_complete_part2 = htc_pkt->pPktContext; + + htt_pkt = container_of(htc_pkt, struct htt_htc_pkt, htc_pkt); + + /* process (free or keep) the netbuf that held the message */ + netbuf = (qdf_nbuf_t) htc_pkt->pNetBufContext; + if (send_complete_part2 != NULL) { + send_complete_part2(htt_pkt->pdev_ctxt, htc_pkt->Status, netbuf, + htt_pkt->msdu_id); + } + + if (pdev->cfg.is_high_latency && !pdev->cfg.default_tx_comp_req) { + int32_t credit_delta; + + qdf_atomic_add(1, &pdev->htt_tx_credit.bus_delta); + credit_delta = htt_tx_credit_update(pdev); + + if (credit_delta) + ol_tx_credit_completion_handler(pdev->txrx_pdev, + credit_delta); + } + + /* free the htt_htc_pkt / HTC_PACKET object */ + htt_htc_pkt_free(pdev, htt_pkt); +} + +HTC_SEND_FULL_ACTION htt_h2t_full(void *context, HTC_PACKET *pkt) +{ +/* FIX THIS */ + return HTC_SEND_FULL_KEEP; +} + +#if defined(HELIUMPLUS) +A_STATUS htt_h2t_frag_desc_bank_cfg_msg(struct htt_pdev_t *pdev) +{ + A_STATUS rc = A_OK; + + struct htt_htc_pkt *pkt; + qdf_nbuf_t msg; + u_int32_t *msg_word; + struct htt_tx_frag_desc_bank_cfg_t *bank_cfg; + + pkt = htt_htc_pkt_alloc(pdev); + if (!pkt) + return A_ERROR; /* failure */ + + /* show that this is not a tx frame download + * (not required, but helpful) + */ + pkt->msdu_id = HTT_TX_COMPL_INV_MSDU_ID; + pkt->pdev_ctxt = NULL; /* not used during send-done callback */ + + msg = qdf_nbuf_alloc( + pdev->osdev, + HTT_MSG_BUF_SIZE(sizeof(struct htt_tx_frag_desc_bank_cfg_t)), + /* reserve room for the HTC header */ + HTC_HEADER_LEN + HTC_HDR_ALIGNMENT_PADDING, 4, true); + if (!msg) { + htt_htc_pkt_free(pdev, pkt); + return A_ERROR; /* failure */ + } + + /* + * Set the length of the message. + * The contribution from the HTC_HDR_ALIGNMENT_PADDING is added + * separately during the below call to adf_nbuf_push_head. + * The contribution from the HTC header is added separately inside HTC. + */ + qdf_nbuf_put_tail(msg, sizeof(struct htt_tx_frag_desc_bank_cfg_t)); + + /* fill in the message contents */ + msg_word = (u_int32_t *) qdf_nbuf_data(msg); + + memset(msg_word, 0, sizeof(struct htt_tx_frag_desc_bank_cfg_t)); + /* rewind beyond alignment pad to get to the HTC header reserved area */ + qdf_nbuf_push_head(msg, HTC_HDR_ALIGNMENT_PADDING); + + *msg_word = 0; + HTT_H2T_MSG_TYPE_SET(*msg_word, HTT_H2T_MSG_TYPE_FRAG_DESC_BANK_CFG); + + bank_cfg = (struct htt_tx_frag_desc_bank_cfg_t *)msg_word; + + /** @note @todo Hard coded to 0 Assuming just one pdev for now.*/ + HTT_H2T_FRAG_DESC_BANK_PDEVID_SET(*msg_word, 0); + /** @note Hard coded to 1.*/ + HTT_H2T_FRAG_DESC_BANK_NUM_BANKS_SET(*msg_word, 1); + HTT_H2T_FRAG_DESC_BANK_DESC_SIZE_SET(*msg_word, pdev->frag_descs.size); + HTT_H2T_FRAG_DESC_BANK_SWAP_SET(*msg_word, 0); + + /** Bank specific data structure.*/ +#if HTT_PADDR64 + bank_cfg->bank_base_address[0].lo = qdf_get_lower_32_bits( + pdev->frag_descs.desc_pages.dma_pages->page_p_addr); + bank_cfg->bank_base_address[0].hi = qdf_get_upper_32_bits( + pdev->frag_descs.desc_pages.dma_pages->page_p_addr); +#else /* ! HTT_PADDR64 */ + bank_cfg->bank_base_address[0] = + pdev->frag_descs.desc_pages.dma_pages->page_p_addr; +#endif /* HTT_PADDR64 */ + /* Logical Min index */ + HTT_H2T_FRAG_DESC_BANK_MIN_IDX_SET(bank_cfg->bank_info[0], 0); + /* Logical Max index */ + HTT_H2T_FRAG_DESC_BANK_MAX_IDX_SET(bank_cfg->bank_info[0], + pdev->frag_descs.pool_elems-1); + + SET_HTC_PACKET_INFO_TX( + &pkt->htc_pkt, + htt_h2t_send_complete_free_netbuf, + qdf_nbuf_data(msg), + qdf_nbuf_len(msg), + pdev->htc_tx_endpoint, + 1); /* tag - not relevant here */ + + SET_HTC_PACKET_NET_BUF_CONTEXT(&pkt->htc_pkt, msg); + + rc = htc_send_pkt(pdev->htc_pdev, &pkt->htc_pkt); +#ifdef ATH_11AC_TXCOMPACT + if (rc == A_OK) + htt_htc_misc_pkt_list_add(pdev, pkt); +#endif + + return rc; +} + +#endif /* defined(HELIUMPLUS) */ + +A_STATUS htt_h2t_ver_req_msg(struct htt_pdev_t *pdev) +{ + struct htt_htc_pkt *pkt; + qdf_nbuf_t msg; + uint32_t *msg_word; + uint32_t msg_size; + uint32_t max_tx_group; + + pkt = htt_htc_pkt_alloc(pdev); + if (!pkt) + return A_ERROR; /* failure */ + + max_tx_group = ol_tx_get_max_tx_groups_supported(pdev->txrx_pdev); + + if (max_tx_group) + msg_size = HTT_VER_REQ_BYTES + + sizeof(struct htt_option_tlv_mac_tx_queue_groups_t); + else + msg_size = HTT_VER_REQ_BYTES; + + /* show that this is not a tx frame download + * (not required, but helpful) + */ + pkt->msdu_id = HTT_TX_COMPL_INV_MSDU_ID; + pkt->pdev_ctxt = NULL; /* not used during send-done callback */ + + /* reserve room for the HTC header */ + msg = qdf_nbuf_alloc(pdev->osdev, HTT_MSG_BUF_SIZE(msg_size), + HTC_HEADER_LEN + HTC_HDR_ALIGNMENT_PADDING, 4, + true); + if (!msg) { + htt_htc_pkt_free(pdev, pkt); + return A_ERROR; /* failure */ + } + + /* + * Set the length of the message. + * The contribution from the HTC_HDR_ALIGNMENT_PADDING is added + * separately during the below call to qdf_nbuf_push_head. + * The contribution from the HTC header is added separately inside HTC. + */ + qdf_nbuf_put_tail(msg, msg_size); + + /* fill in the message contents */ + msg_word = (uint32_t *) qdf_nbuf_data(msg); + + /* rewind beyond alignment pad to get to the HTC header reserved area */ + qdf_nbuf_push_head(msg, HTC_HDR_ALIGNMENT_PADDING); + + *msg_word = 0; + HTT_H2T_MSG_TYPE_SET(*msg_word, HTT_H2T_MSG_TYPE_VERSION_REQ); + + if (max_tx_group) { + *(msg_word + 1) = 0; + + /* Fill Group Info */ + HTT_OPTION_TLV_TAG_SET(*(msg_word+1), + HTT_OPTION_TLV_TAG_MAX_TX_QUEUE_GROUPS); + HTT_OPTION_TLV_LENGTH_SET(*(msg_word+1), + (sizeof(struct htt_option_tlv_mac_tx_queue_groups_t)/ + sizeof(uint32_t))); + HTT_OPTION_TLV_VALUE0_SET(*(msg_word+1), max_tx_group); + } + + SET_HTC_PACKET_INFO_TX(&pkt->htc_pkt, + htt_h2t_send_complete_free_netbuf, + qdf_nbuf_data(msg), qdf_nbuf_len(msg), + pdev->htc_tx_endpoint, + 1); /* tag - not relevant here */ + + SET_HTC_PACKET_NET_BUF_CONTEXT(&pkt->htc_pkt, msg); + HTT_SEND_HTC_PKT(pdev, pkt); + + if ((pdev->cfg.is_high_latency) && + (!pdev->cfg.default_tx_comp_req)) + ol_tx_target_credit_update(pdev->txrx_pdev, -1); + + return A_OK; +} + +#if defined(HELIUMPLUS) +/** + * htt_h2t_rx_ring_rfs_cfg_msg_ll() - Configure receive flow steering + * @pdev: handle to the HTT instance + * + * Return: QDF_STATUS_SUCCESS on success + * A_NO_MEMORY No memory fail + */ +QDF_STATUS htt_h2t_rx_ring_rfs_cfg_msg_ll(struct htt_pdev_t *pdev) +{ + struct htt_htc_pkt *pkt; + qdf_nbuf_t msg; + uint32_t *msg_word; + + qdf_print("Receive flow steering configuration, disable gEnableFlowSteering(=0) in ini if FW doesnot support it\n"); + pkt = htt_htc_pkt_alloc(pdev); + if (!pkt) + return QDF_STATUS_E_NOMEM; /* failure */ + + pkt->msdu_id = HTT_TX_COMPL_INV_MSDU_ID; + pkt->pdev_ctxt = NULL; /* not used during send-done callback */ + + /* reserve room for the HTC header */ + msg = qdf_nbuf_alloc(pdev->osdev, + HTT_MSG_BUF_SIZE(HTT_RFS_CFG_REQ_BYTES), + HTC_HEADER_LEN + HTC_HDR_ALIGNMENT_PADDING, 4, + true); + if (!msg) { + htt_htc_pkt_free(pdev, pkt); + return QDF_STATUS_E_NOMEM; /* failure */ + } + /* + * Set the length of the message. + * The contribution from the HTC_HDR_ALIGNMENT_PADDING is added + * separately during the below call to qdf_nbuf_push_head. + * The contribution from the HTC header is added separately inside HTC. + */ + qdf_nbuf_put_tail(msg, HTT_RFS_CFG_REQ_BYTES); + + /* fill in the message contents */ + msg_word = (uint32_t *) qdf_nbuf_data(msg); + + /* rewind beyond alignment pad to get to the HTC header reserved area */ + qdf_nbuf_push_head(msg, HTC_HDR_ALIGNMENT_PADDING); + + *msg_word = 0; + HTT_H2T_MSG_TYPE_SET(*msg_word, HTT_H2T_MSG_TYPE_RFS_CONFIG); + if (ol_cfg_is_flow_steering_enabled(pdev->ctrl_pdev)) { + HTT_RX_RFS_CONFIG_SET(*msg_word, 1); + qdf_print("Enable Rx flow steering\n"); + } else { + qdf_print("Disable Rx flow steering\n"); + } + + SET_HTC_PACKET_INFO_TX(&pkt->htc_pkt, + htt_h2t_send_complete_free_netbuf, + qdf_nbuf_data(msg), qdf_nbuf_len(msg), + pdev->htc_tx_endpoint, + 1); /* tag - not relevant here */ + + SET_HTC_PACKET_NET_BUF_CONTEXT(&pkt->htc_pkt, msg); + HTT_SEND_HTC_PKT(pdev, pkt); + return QDF_STATUS_SUCCESS; +} +#else +/** + * htt_h2t_rx_ring_rfs_cfg_msg_ll() - Configure receive flow steering + * @pdev: handle to the HTT instance + * + * Return: QDF_STATUS_SUCCESS on success + * A_NO_MEMORY No memory fail + */ +QDF_STATUS htt_h2t_rx_ring_rfs_cfg_msg_ll(struct htt_pdev_t *pdev) +{ + qdf_print("Doesnot support receive flow steering configuration\n"); + return QDF_STATUS_SUCCESS; +} +#endif /* HELIUMPLUS */ + +QDF_STATUS htt_h2t_rx_ring_cfg_msg_ll(struct htt_pdev_t *pdev) +{ + struct htt_htc_pkt *pkt; + qdf_nbuf_t msg; + uint32_t *msg_word; + int enable_ctrl_data, enable_mgmt_data, + enable_null_data, enable_phy_data, enable_hdr, + enable_ppdu_start, enable_ppdu_end; + + pkt = htt_htc_pkt_alloc(pdev); + if (!pkt) + return A_ERROR; /* failure */ + + /* show that this is not a tx frame download + (not required, but helpful) + */ + pkt->msdu_id = HTT_TX_COMPL_INV_MSDU_ID; + pkt->pdev_ctxt = NULL; /* not used during send-done callback */ + + /* reserve room for the HTC header */ + msg = qdf_nbuf_alloc(pdev->osdev, + HTT_MSG_BUF_SIZE(HTT_RX_RING_CFG_BYTES(1)), + HTC_HEADER_LEN + HTC_HDR_ALIGNMENT_PADDING, 4, + true); + if (!msg) { + htt_htc_pkt_free(pdev, pkt); + return A_ERROR; /* failure */ + } + /* + * Set the length of the message. + * The contribution from the HTC_HDR_ALIGNMENT_PADDING is added + * separately during the below call to qdf_nbuf_push_head. + * The contribution from the HTC header is added separately inside HTC. + */ + qdf_nbuf_put_tail(msg, HTT_RX_RING_CFG_BYTES(1)); + + /* fill in the message contents */ + msg_word = (uint32_t *) qdf_nbuf_data(msg); + + /* rewind beyond alignment pad to get to the HTC header reserved area */ + qdf_nbuf_push_head(msg, HTC_HDR_ALIGNMENT_PADDING); + + *msg_word = 0; + HTT_H2T_MSG_TYPE_SET(*msg_word, HTT_H2T_MSG_TYPE_RX_RING_CFG); + HTT_RX_RING_CFG_NUM_RINGS_SET(*msg_word, 1); + + msg_word++; + *msg_word = 0; +#if HTT_PADDR64 + HTT_RX_RING_CFG_IDX_SHADOW_REG_PADDR_LO_SET( + *msg_word, + qdf_get_lower_32_bits(pdev->rx_ring.alloc_idx.paddr)); + msg_word++; + HTT_RX_RING_CFG_IDX_SHADOW_REG_PADDR_HI_SET( + *msg_word, + qdf_get_upper_32_bits(pdev->rx_ring.alloc_idx.paddr)); +#else /* ! HTT_PADDR64 */ + HTT_RX_RING_CFG_IDX_SHADOW_REG_PADDR_SET(*msg_word, + pdev->rx_ring.alloc_idx.paddr); +#endif /* HTT_PADDR64 */ + + msg_word++; + *msg_word = 0; +#if HTT_PADDR64 + HTT_RX_RING_CFG_BASE_PADDR_LO_SET(*msg_word, + pdev->rx_ring.base_paddr); + { + uint32_t tmp; + + tmp = qdf_get_upper_32_bits(pdev->rx_ring.base_paddr); + if (tmp & 0xfffffe0) { + qdf_print("%s:%d paddr > 37 bits!. Trimmed.", + __func__, __LINE__); + tmp &= 0x01f; + } + + + msg_word++; + HTT_RX_RING_CFG_BASE_PADDR_HI_SET(*msg_word, tmp); + } +#else /* ! HTT_PADDR64 */ + HTT_RX_RING_CFG_BASE_PADDR_SET(*msg_word, pdev->rx_ring.base_paddr); +#endif /* HTT_PADDR64 */ + + msg_word++; + *msg_word = 0; + HTT_RX_RING_CFG_LEN_SET(*msg_word, pdev->rx_ring.size); + HTT_RX_RING_CFG_BUF_SZ_SET(*msg_word, HTT_RX_BUF_SIZE); + +/* FIX THIS: if the FW creates a complete translated rx descriptor, + * then the MAC DMA of the HW rx descriptor should be disabled. + */ + msg_word++; + *msg_word = 0; +#ifndef REMOVE_PKT_LOG + if (ol_cfg_is_packet_log_enabled(pdev->ctrl_pdev)) { + enable_ctrl_data = 1; + enable_mgmt_data = 1; + enable_null_data = 1; + enable_phy_data = 1; + enable_hdr = 1; + enable_ppdu_start = 1; + enable_ppdu_end = 1; + qdf_print("Pkt log is enabled\n"); + } else { + qdf_print("Pkt log is disabled\n"); + enable_ctrl_data = 0; + enable_mgmt_data = 0; + enable_null_data = 0; + enable_phy_data = 0; + enable_hdr = 0; + enable_ppdu_start = 0; + enable_ppdu_end = 0; + } +#else + enable_ctrl_data = 0; + enable_mgmt_data = 0; + enable_null_data = 0; + enable_phy_data = 0; + enable_hdr = 0; + enable_ppdu_start = 0; + enable_ppdu_end = 0; +#endif + if (QDF_GLOBAL_MONITOR_MODE == cds_get_conparam()) { + enable_ctrl_data = 1; + enable_mgmt_data = 1; + enable_null_data = 1; + enable_phy_data = 1; + enable_hdr = 1; + enable_ppdu_start = 1; + enable_ppdu_end = 1; + /* Disable ASPM for monitor mode */ + qdf_print("Monitor mode is enabled\n"); + } + + HTT_RX_RING_CFG_ENABLED_802_11_HDR_SET(*msg_word, enable_hdr); + HTT_RX_RING_CFG_ENABLED_MSDU_PAYLD_SET(*msg_word, 1); + HTT_RX_RING_CFG_ENABLED_PPDU_START_SET(*msg_word, enable_ppdu_start); + HTT_RX_RING_CFG_ENABLED_PPDU_END_SET(*msg_word, enable_ppdu_end); + HTT_RX_RING_CFG_ENABLED_MPDU_START_SET(*msg_word, 1); + HTT_RX_RING_CFG_ENABLED_MPDU_END_SET(*msg_word, 1); + HTT_RX_RING_CFG_ENABLED_MSDU_START_SET(*msg_word, 1); + HTT_RX_RING_CFG_ENABLED_MSDU_END_SET(*msg_word, 1); + HTT_RX_RING_CFG_ENABLED_RX_ATTN_SET(*msg_word, 1); + /* always present? */ + HTT_RX_RING_CFG_ENABLED_FRAG_INFO_SET(*msg_word, 1); + HTT_RX_RING_CFG_ENABLED_UCAST_SET(*msg_word, 1); + HTT_RX_RING_CFG_ENABLED_MCAST_SET(*msg_word, 1); + /* Must change to dynamic enable at run time + * rather than at compile time + */ + HTT_RX_RING_CFG_ENABLED_CTRL_SET(*msg_word, enable_ctrl_data); + HTT_RX_RING_CFG_ENABLED_MGMT_SET(*msg_word, enable_mgmt_data); + HTT_RX_RING_CFG_ENABLED_NULL_SET(*msg_word, enable_null_data); + HTT_RX_RING_CFG_ENABLED_PHY_SET(*msg_word, enable_phy_data); + HTT_RX_RING_CFG_IDX_INIT_VAL_SET(*msg_word, + *pdev->rx_ring.alloc_idx.vaddr); + + msg_word++; + *msg_word = 0; + HTT_RX_RING_CFG_OFFSET_802_11_HDR_SET(*msg_word, + RX_DESC_HDR_STATUS_OFFSET32); + HTT_RX_RING_CFG_OFFSET_MSDU_PAYLD_SET(*msg_word, + HTT_RX_DESC_RESERVATION32); + + msg_word++; + *msg_word = 0; + HTT_RX_RING_CFG_OFFSET_PPDU_START_SET(*msg_word, + RX_DESC_PPDU_START_OFFSET32); + HTT_RX_RING_CFG_OFFSET_PPDU_END_SET(*msg_word, + RX_DESC_PPDU_END_OFFSET32); + + msg_word++; + *msg_word = 0; + HTT_RX_RING_CFG_OFFSET_MPDU_START_SET(*msg_word, + RX_DESC_MPDU_START_OFFSET32); + HTT_RX_RING_CFG_OFFSET_MPDU_END_SET(*msg_word, + RX_DESC_MPDU_END_OFFSET32); + + msg_word++; + *msg_word = 0; + HTT_RX_RING_CFG_OFFSET_MSDU_START_SET(*msg_word, + RX_DESC_MSDU_START_OFFSET32); + HTT_RX_RING_CFG_OFFSET_MSDU_END_SET(*msg_word, + RX_DESC_MSDU_END_OFFSET32); + + msg_word++; + *msg_word = 0; + HTT_RX_RING_CFG_OFFSET_RX_ATTN_SET(*msg_word, + RX_DESC_ATTN_OFFSET32); + HTT_RX_RING_CFG_OFFSET_FRAG_INFO_SET(*msg_word, + RX_DESC_FRAG_INFO_OFFSET32); + + SET_HTC_PACKET_INFO_TX(&pkt->htc_pkt, + htt_h2t_send_complete_free_netbuf, + qdf_nbuf_data(msg), + qdf_nbuf_len(msg), + pdev->htc_tx_endpoint, + HTC_TX_PACKET_TAG_RUNTIME_PUT); + + SET_HTC_PACKET_NET_BUF_CONTEXT(&pkt->htc_pkt, msg); + HTT_SEND_HTC_PKT(pdev, pkt); + return A_OK; +} + +QDF_STATUS +htt_h2t_rx_ring_cfg_msg_hl(struct htt_pdev_t *pdev) +{ + struct htt_htc_pkt *pkt; + qdf_nbuf_t msg; + u_int32_t *msg_word; + + pkt = htt_htc_pkt_alloc(pdev); + if (!pkt) + return A_ERROR; /* failure */ + + /* show that this is not a tx frame download + * (not required, but helpful) */ + pkt->msdu_id = HTT_TX_COMPL_INV_MSDU_ID; + pkt->pdev_ctxt = NULL; /* not used during send-done callback */ + + msg = qdf_nbuf_alloc( + pdev->osdev, + HTT_MSG_BUF_SIZE(HTT_RX_RING_CFG_BYTES(1)), + /* reserve room for the HTC header */ + HTC_HEADER_LEN + HTC_HDR_ALIGNMENT_PADDING, 4, true); + if (!msg) { + htt_htc_pkt_free(pdev, pkt); + return A_ERROR; /* failure */ + } + /* + * Set the length of the message. + * The contribution from the HTC_HDR_ALIGNMENT_PADDING is added + * separately during the below call to adf_nbuf_push_head. + * The contribution from the HTC header is added separately inside HTC. + */ + qdf_nbuf_put_tail(msg, HTT_RX_RING_CFG_BYTES(1)); + + /* fill in the message contents */ + msg_word = (u_int32_t *)qdf_nbuf_data(msg); + + /* rewind beyond alignment pad to get to the HTC header reserved area */ + qdf_nbuf_push_head(msg, HTC_HDR_ALIGNMENT_PADDING); + + *msg_word = 0; + HTT_H2T_MSG_TYPE_SET(*msg_word, HTT_H2T_MSG_TYPE_RX_RING_CFG); + HTT_RX_RING_CFG_NUM_RINGS_SET(*msg_word, 1); + + msg_word++; + *msg_word = 0; + HTT_RX_RING_CFG_IDX_SHADOW_REG_PADDR_SET( + *msg_word, pdev->rx_ring.alloc_idx.paddr); + + msg_word++; + *msg_word = 0; + HTT_RX_RING_CFG_BASE_PADDR_SET(*msg_word, pdev->rx_ring.base_paddr); + + msg_word++; + *msg_word = 0; + HTT_RX_RING_CFG_LEN_SET(*msg_word, pdev->rx_ring.size); + HTT_RX_RING_CFG_BUF_SZ_SET(*msg_word, HTT_RX_BUF_SIZE); + + /* FIX THIS: if the FW creates a complete translated rx descriptor, + * then the MAC DMA of the HW rx descriptor should be disabled. */ + msg_word++; + *msg_word = 0; + + HTT_RX_RING_CFG_ENABLED_802_11_HDR_SET(*msg_word, 0); + HTT_RX_RING_CFG_ENABLED_MSDU_PAYLD_SET(*msg_word, 1); + HTT_RX_RING_CFG_ENABLED_PPDU_START_SET(*msg_word, 0); + HTT_RX_RING_CFG_ENABLED_PPDU_END_SET(*msg_word, 0); + HTT_RX_RING_CFG_ENABLED_MPDU_START_SET(*msg_word, 0); + HTT_RX_RING_CFG_ENABLED_MPDU_END_SET(*msg_word, 0); + HTT_RX_RING_CFG_ENABLED_MSDU_START_SET(*msg_word, 0); + HTT_RX_RING_CFG_ENABLED_MSDU_END_SET(*msg_word, 0); + HTT_RX_RING_CFG_ENABLED_RX_ATTN_SET(*msg_word, 0); + /* always present? */ + HTT_RX_RING_CFG_ENABLED_FRAG_INFO_SET(*msg_word, 0); + HTT_RX_RING_CFG_ENABLED_UCAST_SET(*msg_word, 1); + HTT_RX_RING_CFG_ENABLED_MCAST_SET(*msg_word, 1); + /* Must change to dynamic enable at run time + * rather than at compile time + */ + HTT_RX_RING_CFG_ENABLED_CTRL_SET(*msg_word, 0); + HTT_RX_RING_CFG_ENABLED_MGMT_SET(*msg_word, 0); + HTT_RX_RING_CFG_ENABLED_NULL_SET(*msg_word, 0); + HTT_RX_RING_CFG_ENABLED_PHY_SET(*msg_word, 0); + + msg_word++; + *msg_word = 0; + HTT_RX_RING_CFG_OFFSET_802_11_HDR_SET(*msg_word, + 0); + HTT_RX_RING_CFG_OFFSET_MSDU_PAYLD_SET(*msg_word, + 0); + + msg_word++; + *msg_word = 0; + HTT_RX_RING_CFG_OFFSET_PPDU_START_SET(*msg_word, + 0); + HTT_RX_RING_CFG_OFFSET_PPDU_END_SET(*msg_word, + 0); + + msg_word++; + *msg_word = 0; + HTT_RX_RING_CFG_OFFSET_MPDU_START_SET(*msg_word, + 0); + HTT_RX_RING_CFG_OFFSET_MPDU_END_SET(*msg_word, + 0); + + msg_word++; + *msg_word = 0; + HTT_RX_RING_CFG_OFFSET_MSDU_START_SET(*msg_word, + 0); + HTT_RX_RING_CFG_OFFSET_MSDU_END_SET(*msg_word, + 0); + + msg_word++; + *msg_word = 0; + HTT_RX_RING_CFG_OFFSET_RX_ATTN_SET(*msg_word, + 0); + HTT_RX_RING_CFG_OFFSET_FRAG_INFO_SET(*msg_word, + 0); + + SET_HTC_PACKET_INFO_TX( + &pkt->htc_pkt, + htt_h2t_send_complete_free_netbuf, + qdf_nbuf_data(msg), + qdf_nbuf_len(msg), + pdev->htc_tx_endpoint, + 1); /* tag - not relevant here */ + + SET_HTC_PACKET_NET_BUF_CONTEXT(&pkt->htc_pkt, msg); + +#ifdef ATH_11AC_TXCOMPACT + if (htc_send_pkt(pdev->htc_pdev, &pkt->htc_pkt) == A_OK) + htt_htc_misc_pkt_list_add(pdev, pkt); +#else + htc_send_pkt(pdev->htc_pdev, &pkt->htc_pkt); +#endif + + if ((pdev->cfg.is_high_latency) && + (!pdev->cfg.default_tx_comp_req)) + ol_tx_target_credit_update(pdev->txrx_pdev, -1); + + return QDF_STATUS_SUCCESS; +} + +/** + * htt_h2t_rx_ring_rfs_cfg_msg_hl() - Configure receive flow steering + * @pdev: handle to the HTT instance + * + * Return: QDF_STATUS_SUCCESS on success + * A_NO_MEMORY No memory fail + */ +QDF_STATUS htt_h2t_rx_ring_rfs_cfg_msg_hl(struct htt_pdev_t *pdev) +{ + qdf_print("Doesnot support Receive flow steering configuration\n"); + return QDF_STATUS_SUCCESS; +} + +int +htt_h2t_dbg_stats_get(struct htt_pdev_t *pdev, + uint32_t stats_type_upload_mask, + uint32_t stats_type_reset_mask, + uint8_t cfg_stat_type, uint32_t cfg_val, uint64_t cookie) +{ + struct htt_htc_pkt *pkt; + qdf_nbuf_t msg; + uint32_t *msg_word; + uint16_t htc_tag = 1; + + pkt = htt_htc_pkt_alloc(pdev); + if (!pkt) + return -EINVAL; /* failure */ + + if (stats_type_upload_mask >= 1 << HTT_DBG_NUM_STATS || + stats_type_reset_mask >= 1 << HTT_DBG_NUM_STATS) { + /* FIX THIS - add more details? */ + qdf_print("%#x %#x stats not supported\n", + stats_type_upload_mask, stats_type_reset_mask); + htt_htc_pkt_free(pdev, pkt); + return -EINVAL; /* failure */ + } + + if (stats_type_reset_mask) + htc_tag = HTC_TX_PACKET_TAG_RUNTIME_PUT; + + /* show that this is not a tx frame download + * (not required, but helpful) + */ + pkt->msdu_id = HTT_TX_COMPL_INV_MSDU_ID; + pkt->pdev_ctxt = NULL; /* not used during send-done callback */ + + + msg = qdf_nbuf_alloc(pdev->osdev, + HTT_MSG_BUF_SIZE(HTT_H2T_STATS_REQ_MSG_SZ), + /* reserve room for HTC header */ + HTC_HEADER_LEN + HTC_HDR_ALIGNMENT_PADDING, 4, + false); + if (!msg) { + htt_htc_pkt_free(pdev, pkt); + return -EINVAL; /* failure */ + } + /* set the length of the message */ + qdf_nbuf_put_tail(msg, HTT_H2T_STATS_REQ_MSG_SZ); + + /* fill in the message contents */ + msg_word = (uint32_t *) qdf_nbuf_data(msg); + + /* rewind beyond alignment pad to get to the HTC header reserved area */ + qdf_nbuf_push_head(msg, HTC_HDR_ALIGNMENT_PADDING); + + *msg_word = 0; + HTT_H2T_MSG_TYPE_SET(*msg_word, HTT_H2T_MSG_TYPE_STATS_REQ); + HTT_H2T_STATS_REQ_UPLOAD_TYPES_SET(*msg_word, stats_type_upload_mask); + + msg_word++; + *msg_word = 0; + HTT_H2T_STATS_REQ_RESET_TYPES_SET(*msg_word, stats_type_reset_mask); + + msg_word++; + *msg_word = 0; + HTT_H2T_STATS_REQ_CFG_VAL_SET(*msg_word, cfg_val); + HTT_H2T_STATS_REQ_CFG_STAT_TYPE_SET(*msg_word, cfg_stat_type); + + /* cookie LSBs */ + msg_word++; + *msg_word = cookie & 0xffffffff; + + /* cookie MSBs */ + msg_word++; + *msg_word = cookie >> 32; + + SET_HTC_PACKET_INFO_TX(&pkt->htc_pkt, + htt_h2t_send_complete_free_netbuf, + qdf_nbuf_data(msg), + qdf_nbuf_len(msg), + pdev->htc_tx_endpoint, + htc_tag); /* tag - not relevant here */ + + SET_HTC_PACKET_NET_BUF_CONTEXT(&pkt->htc_pkt, msg); + +#ifdef ATH_11AC_TXCOMPACT + if (htc_send_pkt(pdev->htc_pdev, &pkt->htc_pkt) == A_OK) + htt_htc_misc_pkt_list_add(pdev, pkt); +#else + htc_send_pkt(pdev->htc_pdev, &pkt->htc_pkt); +#endif + + if ((pdev->cfg.is_high_latency) && + (!pdev->cfg.default_tx_comp_req)) + ol_tx_target_credit_update(pdev->txrx_pdev, -1); + + return 0; +} + +A_STATUS htt_h2t_sync_msg(struct htt_pdev_t *pdev, uint8_t sync_cnt) +{ + struct htt_htc_pkt *pkt; + qdf_nbuf_t msg; + uint32_t *msg_word; + + pkt = htt_htc_pkt_alloc(pdev); + if (!pkt) + return A_NO_MEMORY; + + /* show that this is not a tx frame download + (not required, but helpful) + */ + pkt->msdu_id = HTT_TX_COMPL_INV_MSDU_ID; + pkt->pdev_ctxt = NULL; /* not used during send-done callback */ + + /* reserve room for HTC header */ + msg = qdf_nbuf_alloc(pdev->osdev, HTT_MSG_BUF_SIZE(HTT_H2T_SYNC_MSG_SZ), + HTC_HEADER_LEN + HTC_HDR_ALIGNMENT_PADDING, 4, + false); + if (!msg) { + htt_htc_pkt_free(pdev, pkt); + return A_NO_MEMORY; + } + /* set the length of the message */ + qdf_nbuf_put_tail(msg, HTT_H2T_SYNC_MSG_SZ); + + /* fill in the message contents */ + msg_word = (uint32_t *) qdf_nbuf_data(msg); + + /* rewind beyond alignment pad to get to the HTC header reserved area */ + qdf_nbuf_push_head(msg, HTC_HDR_ALIGNMENT_PADDING); + + *msg_word = 0; + HTT_H2T_MSG_TYPE_SET(*msg_word, HTT_H2T_MSG_TYPE_SYNC); + HTT_H2T_SYNC_COUNT_SET(*msg_word, sync_cnt); + + SET_HTC_PACKET_INFO_TX(&pkt->htc_pkt, + htt_h2t_send_complete_free_netbuf, + qdf_nbuf_data(msg), + qdf_nbuf_len(msg), + pdev->htc_tx_endpoint, + HTC_TX_PACKET_TAG_RUNTIME_PUT); + + SET_HTC_PACKET_NET_BUF_CONTEXT(&pkt->htc_pkt, msg); + HTT_SEND_HTC_PKT(pdev, pkt); + + if ((pdev->cfg.is_high_latency) && + (!pdev->cfg.default_tx_comp_req)) + ol_tx_target_credit_update(pdev->txrx_pdev, -1); + + return A_OK; +} + +int +htt_h2t_aggr_cfg_msg(struct htt_pdev_t *pdev, + int max_subfrms_ampdu, int max_subfrms_amsdu) +{ + struct htt_htc_pkt *pkt; + qdf_nbuf_t msg; + uint32_t *msg_word; + + pkt = htt_htc_pkt_alloc(pdev); + if (!pkt) + return -EINVAL; /* failure */ + + /* show that this is not a tx frame download + * (not required, but helpful) + */ + pkt->msdu_id = HTT_TX_COMPL_INV_MSDU_ID; + pkt->pdev_ctxt = NULL; /* not used during send-done callback */ + + /* reserve room for HTC header */ + msg = qdf_nbuf_alloc(pdev->osdev, HTT_MSG_BUF_SIZE(HTT_AGGR_CFG_MSG_SZ), + HTC_HEADER_LEN + HTC_HDR_ALIGNMENT_PADDING, 4, + false); + if (!msg) { + htt_htc_pkt_free(pdev, pkt); + return -EINVAL; /* failure */ + } + /* set the length of the message */ + qdf_nbuf_put_tail(msg, HTT_AGGR_CFG_MSG_SZ); + + /* fill in the message contents */ + msg_word = (uint32_t *) qdf_nbuf_data(msg); + + /* rewind beyond alignment pad to get to the HTC header reserved area */ + qdf_nbuf_push_head(msg, HTC_HDR_ALIGNMENT_PADDING); + + *msg_word = 0; + HTT_H2T_MSG_TYPE_SET(*msg_word, HTT_H2T_MSG_TYPE_AGGR_CFG); + + if (max_subfrms_ampdu && (max_subfrms_ampdu <= 64)) { + HTT_AGGR_CFG_MAX_NUM_AMPDU_SUBFRM_SET(*msg_word, + max_subfrms_ampdu); + } + + if (max_subfrms_amsdu && (max_subfrms_amsdu < 32)) { + HTT_AGGR_CFG_MAX_NUM_AMSDU_SUBFRM_SET(*msg_word, + max_subfrms_amsdu); + } + + SET_HTC_PACKET_INFO_TX(&pkt->htc_pkt, + htt_h2t_send_complete_free_netbuf, + qdf_nbuf_data(msg), + qdf_nbuf_len(msg), + pdev->htc_tx_endpoint, + HTC_TX_PACKET_TAG_RUNTIME_PUT); + + SET_HTC_PACKET_NET_BUF_CONTEXT(&pkt->htc_pkt, msg); + +#ifdef ATH_11AC_TXCOMPACT + if (htc_send_pkt(pdev->htc_pdev, &pkt->htc_pkt) == A_OK) + htt_htc_misc_pkt_list_add(pdev, pkt); +#else + htc_send_pkt(pdev->htc_pdev, &pkt->htc_pkt); +#endif + + if ((pdev->cfg.is_high_latency) && + (!pdev->cfg.default_tx_comp_req)) + ol_tx_target_credit_update(pdev->txrx_pdev, -1); + + return 0; +} + +#ifdef IPA_OFFLOAD +/** + * htt_h2t_ipa_uc_rsc_cfg_msg() - Send WDI IPA config message to firmware + * @pdev: handle to the HTT instance + * + * Return: 0 success + * A_NO_MEMORY No memory fail + */ +#ifdef QCA_WIFI_3_0 +int htt_h2t_ipa_uc_rsc_cfg_msg(struct htt_pdev_t *pdev) +{ + struct htt_htc_pkt *pkt; + qdf_nbuf_t msg; + uint32_t *msg_word; + + pkt = htt_htc_pkt_alloc(pdev); + if (!pkt) + return -A_NO_MEMORY; + + /* show that this is not a tx frame download + * (not required, but helpful) + */ + pkt->msdu_id = HTT_TX_COMPL_INV_MSDU_ID; + pkt->pdev_ctxt = NULL; /* not used during send-done callback */ + + /* reserve room for HTC header */ + msg = qdf_nbuf_alloc(pdev->osdev, HTT_MSG_BUF_SIZE(HTT_WDI_IPA_CFG_SZ), + HTC_HEADER_LEN + HTC_HDR_ALIGNMENT_PADDING, 4, + false); + if (!msg) { + htt_htc_pkt_free(pdev, pkt); + return -A_NO_MEMORY; + } + /* set the length of the message */ + qdf_nbuf_put_tail(msg, HTT_WDI_IPA_CFG_SZ); + + /* fill in the message contents */ + msg_word = (uint32_t *) qdf_nbuf_data(msg); + + /* rewind beyond alignment pad to get to the HTC header reserved area */ + qdf_nbuf_push_head(msg, HTC_HDR_ALIGNMENT_PADDING); + + *msg_word = 0; + HTT_WDI_IPA_CFG_TX_PKT_POOL_SIZE_SET(*msg_word, + pdev->ipa_uc_tx_rsc.alloc_tx_buf_cnt); + HTT_H2T_MSG_TYPE_SET(*msg_word, HTT_H2T_MSG_TYPE_WDI_IPA_CFG); + + msg_word++; + *msg_word = 0; + /* TX COMP RING BASE LO */ + HTT_WDI_IPA_CFG_TX_COMP_RING_BASE_ADDR_LO_SET(*msg_word, + (unsigned int)pdev->ipa_uc_tx_rsc.tx_comp_base.paddr); + msg_word++; + *msg_word = 0; + /* TX COMP RING BASE HI, NONE */ + + msg_word++; + *msg_word = 0; + HTT_WDI_IPA_CFG_TX_COMP_RING_SIZE_SET(*msg_word, + (unsigned int)ol_cfg_ipa_uc_tx_max_buf_cnt(pdev->ctrl_pdev)); + + msg_word++; + *msg_word = 0; + HTT_WDI_IPA_CFG_TX_COMP_WR_IDX_ADDR_LO_SET(*msg_word, + (unsigned int)pdev->ipa_uc_tx_rsc.tx_comp_idx_paddr); + msg_word++; + *msg_word = 0; + + msg_word++; + *msg_word = 0; + HTT_WDI_IPA_CFG_TX_CE_WR_IDX_ADDR_LO_SET(*msg_word, + (unsigned int)pdev->ipa_uc_tx_rsc.tx_ce_idx.paddr); + msg_word++; + *msg_word = 0; + + msg_word++; + *msg_word = 0; + HTT_WDI_IPA_CFG_RX_IND_RING_BASE_ADDR_LO_SET(*msg_word, + (unsigned int)pdev->ipa_uc_rx_rsc.rx_ind_ring_base.paddr); + msg_word++; + *msg_word = 0; + HTT_WDI_IPA_CFG_RX_IND_RING_BASE_ADDR_HI_SET(*msg_word, + 0); + + msg_word++; + *msg_word = 0; + HTT_WDI_IPA_CFG_RX_IND_RING_SIZE_SET(*msg_word, + (unsigned int)qdf_get_pwr2(pdev->rx_ring.fill_level)); + + msg_word++; + *msg_word = 0; + HTT_WDI_IPA_CFG_RX_IND_RD_IDX_ADDR_LO_SET(*msg_word, + (unsigned int)pdev->ipa_uc_rx_rsc.rx_ipa_prc_done_idx.paddr); + msg_word++; + *msg_word = 0; + HTT_WDI_IPA_CFG_RX_IND_RD_IDX_ADDR_HI_SET(*msg_word, + 0); + + msg_word++; + *msg_word = 0; + HTT_WDI_IPA_CFG_RX_IND_WR_IDX_ADDR_LO_SET(*msg_word, + (unsigned int)pdev->ipa_uc_rx_rsc.rx_rdy_idx_paddr); + msg_word++; + *msg_word = 0; + HTT_WDI_IPA_CFG_RX_IND_WR_IDX_ADDR_HI_SET(*msg_word, + 0); + + msg_word++; + *msg_word = 0; + HTT_WDI_IPA_CFG_RX_RING2_BASE_ADDR_LO_SET(*msg_word, + (unsigned int)pdev->ipa_uc_rx_rsc.rx2_ind_ring_base.paddr); + msg_word++; + *msg_word = 0; + HTT_WDI_IPA_CFG_RX_RING2_BASE_ADDR_HI_SET(*msg_word, + 0); + + msg_word++; + *msg_word = 0; + HTT_WDI_IPA_CFG_RX_RING2_SIZE_SET(*msg_word, + (unsigned int)qdf_get_pwr2(pdev->rx_ring.fill_level)); + + msg_word++; + *msg_word = 0; + HTT_WDI_IPA_CFG_RX_RING2_RD_IDX_ADDR_LO_SET(*msg_word, + (unsigned int)pdev->ipa_uc_rx_rsc.rx2_ipa_prc_done_idx.paddr); + msg_word++; + *msg_word = 0; + HTT_WDI_IPA_CFG_RX_RING2_RD_IDX_ADDR_HI_SET(*msg_word, + 0); + + msg_word++; + *msg_word = 0; + HTT_WDI_IPA_CFG_RX_RING2_WR_IDX_ADDR_LO_SET(*msg_word, + (unsigned int)pdev->ipa_uc_rx_rsc.rx2_ipa_prc_done_idx.paddr); + msg_word++; + *msg_word = 0; + HTT_WDI_IPA_CFG_RX_RING2_WR_IDX_ADDR_HI_SET(*msg_word, + 0); + + SET_HTC_PACKET_INFO_TX(&pkt->htc_pkt, + htt_h2t_send_complete_free_netbuf, + qdf_nbuf_data(msg), + qdf_nbuf_len(msg), + pdev->htc_tx_endpoint, + HTC_TX_PACKET_TAG_RUNTIME_PUT); + + SET_HTC_PACKET_NET_BUF_CONTEXT(&pkt->htc_pkt, msg); + HTT_SEND_HTC_PKT(pdev, pkt); + return A_OK; +} +#else +/* Rome Support only WDI 1.0 */ +int htt_h2t_ipa_uc_rsc_cfg_msg(struct htt_pdev_t *pdev) +{ + struct htt_htc_pkt *pkt; + qdf_nbuf_t msg; + uint32_t *msg_word; + + pkt = htt_htc_pkt_alloc(pdev); + if (!pkt) + return A_NO_MEMORY; + + /* show that this is not a tx frame download + * (not required, but helpful) + */ + pkt->msdu_id = HTT_TX_COMPL_INV_MSDU_ID; + pkt->pdev_ctxt = NULL; /* not used during send-done callback */ + + /* reserve room for HTC header */ + msg = qdf_nbuf_alloc(pdev->osdev, HTT_MSG_BUF_SIZE(HTT_WDI_IPA_CFG_SZ), + HTC_HEADER_LEN + HTC_HDR_ALIGNMENT_PADDING, 4, + false); + if (!msg) { + htt_htc_pkt_free(pdev, pkt); + return A_NO_MEMORY; + } + /* set the length of the message */ + qdf_nbuf_put_tail(msg, HTT_WDI_IPA_CFG_SZ); + + /* fill in the message contents */ + msg_word = (uint32_t *) qdf_nbuf_data(msg); + + /* rewind beyond alignment pad to get to the HTC header reserved area */ + qdf_nbuf_push_head(msg, HTC_HDR_ALIGNMENT_PADDING); + + *msg_word = 0; + HTT_WDI_IPA_CFG_TX_PKT_POOL_SIZE_SET(*msg_word, + pdev->ipa_uc_tx_rsc.alloc_tx_buf_cnt); + HTT_H2T_MSG_TYPE_SET(*msg_word, HTT_H2T_MSG_TYPE_WDI_IPA_CFG); + + msg_word++; + *msg_word = 0; + HTT_WDI_IPA_CFG_TX_COMP_RING_BASE_ADDR_SET(*msg_word, + (unsigned int)pdev->ipa_uc_tx_rsc.tx_comp_base.paddr); + + msg_word++; + *msg_word = 0; + HTT_WDI_IPA_CFG_TX_COMP_RING_SIZE_SET( + *msg_word, + (unsigned int)ol_cfg_ipa_uc_tx_max_buf_cnt(pdev->ctrl_pdev)); + + msg_word++; + *msg_word = 0; + HTT_WDI_IPA_CFG_TX_COMP_WR_IDX_ADDR_SET(*msg_word, + (unsigned int)pdev->ipa_uc_tx_rsc.tx_comp_idx_paddr); + + msg_word++; + *msg_word = 0; + HTT_WDI_IPA_CFG_TX_CE_WR_IDX_ADDR_SET(*msg_word, + (unsigned int)pdev->ipa_uc_tx_rsc.tx_ce_idx.paddr); + + msg_word++; + *msg_word = 0; + HTT_WDI_IPA_CFG_RX_IND_RING_BASE_ADDR_SET(*msg_word, + (unsigned int)pdev->ipa_uc_rx_rsc.rx_ind_ring_base.paddr); + + msg_word++; + *msg_word = 0; + HTT_WDI_IPA_CFG_RX_IND_RING_SIZE_SET(*msg_word, + (unsigned int)qdf_get_pwr2(pdev->rx_ring.fill_level)); + + msg_word++; + *msg_word = 0; + HTT_WDI_IPA_CFG_RX_IND_RD_IDX_ADDR_SET(*msg_word, + (unsigned int)pdev->ipa_uc_rx_rsc.rx_ipa_prc_done_idx.paddr); + + msg_word++; + *msg_word = 0; + HTT_WDI_IPA_CFG_RX_IND_WR_IDX_ADDR_SET(*msg_word, + (unsigned int)pdev->ipa_uc_rx_rsc.rx_rdy_idx_paddr); + + SET_HTC_PACKET_INFO_TX(&pkt->htc_pkt, + htt_h2t_send_complete_free_netbuf, + qdf_nbuf_data(msg), + qdf_nbuf_len(msg), + pdev->htc_tx_endpoint, + HTC_TX_PACKET_TAG_RUNTIME_PUT); + + SET_HTC_PACKET_NET_BUF_CONTEXT(&pkt->htc_pkt, msg); + HTT_SEND_HTC_PKT(pdev, pkt); + return A_OK; +} +#endif + +/** + * htt_h2t_ipa_uc_set_active() - Propagate WDI path enable/disable to firmware + * @pdev: handle to the HTT instance + * @uc_active: WDI UC path enable or not + * @is_tx: TX path or RX path + * + * Return: 0 success + * A_NO_MEMORY No memory fail + */ +int htt_h2t_ipa_uc_set_active(struct htt_pdev_t *pdev, + bool uc_active, bool is_tx) +{ + struct htt_htc_pkt *pkt; + qdf_nbuf_t msg; + uint32_t *msg_word; + uint8_t active_target = 0; + + pkt = htt_htc_pkt_alloc(pdev); + if (!pkt) + return -A_NO_MEMORY; + + /* show that this is not a tx frame download + * (not required, but helpful) + */ + pkt->msdu_id = HTT_TX_COMPL_INV_MSDU_ID; + pkt->pdev_ctxt = NULL; /* not used during send-done callback */ + + /* reserve room for HTC header */ + msg = qdf_nbuf_alloc(pdev->osdev, + HTT_MSG_BUF_SIZE(HTT_WDI_IPA_OP_REQUEST_SZ), + HTC_HEADER_LEN + HTC_HDR_ALIGNMENT_PADDING, 4, + false); + if (!msg) { + htt_htc_pkt_free(pdev, pkt); + return -A_NO_MEMORY; + } + /* set the length of the message */ + qdf_nbuf_put_tail(msg, HTT_WDI_IPA_OP_REQUEST_SZ); + + /* fill in the message contents */ + msg_word = (uint32_t *) qdf_nbuf_data(msg); + + /* rewind beyond alignment pad to get to the HTC header reserved area */ + qdf_nbuf_push_head(msg, HTC_HDR_ALIGNMENT_PADDING); + + *msg_word = 0; + if (uc_active && is_tx) + active_target = HTT_WDI_IPA_OPCODE_TX_RESUME; + else if (!uc_active && is_tx) + active_target = HTT_WDI_IPA_OPCODE_TX_SUSPEND; + else if (uc_active && !is_tx) + active_target = HTT_WDI_IPA_OPCODE_RX_RESUME; + else if (!uc_active && !is_tx) + active_target = HTT_WDI_IPA_OPCODE_RX_SUSPEND; + + HTT_WDI_IPA_OP_REQUEST_OP_CODE_SET(*msg_word, active_target); + HTT_H2T_MSG_TYPE_SET(*msg_word, HTT_H2T_MSG_TYPE_WDI_IPA_OP_REQ); + + SET_HTC_PACKET_INFO_TX(&pkt->htc_pkt, + htt_h2t_send_complete_free_netbuf, + qdf_nbuf_data(msg), + qdf_nbuf_len(msg), + pdev->htc_tx_endpoint, + 1); /* tag - not relevant here */ + + SET_HTC_PACKET_NET_BUF_CONTEXT(&pkt->htc_pkt, msg); + HTT_SEND_HTC_PKT(pdev, pkt); + return A_OK; +} + +/** + * htt_h2t_ipa_uc_get_stats() - WDI UC state query request to firmware + * @pdev: handle to the HTT instance + * + * Return: 0 success + * A_NO_MEMORY No memory fail + */ +int htt_h2t_ipa_uc_get_stats(struct htt_pdev_t *pdev) +{ + struct htt_htc_pkt *pkt; + qdf_nbuf_t msg; + uint32_t *msg_word; + + pkt = htt_htc_pkt_alloc(pdev); + if (!pkt) + return -A_NO_MEMORY; + + /* show that this is not a tx frame download + * (not required, but helpful) + */ + pkt->msdu_id = HTT_TX_COMPL_INV_MSDU_ID; + pkt->pdev_ctxt = NULL; /* not used during send-done callback */ + + /* reserve room for HTC header */ + msg = qdf_nbuf_alloc(pdev->osdev, + HTT_MSG_BUF_SIZE(HTT_WDI_IPA_OP_REQUEST_SZ), + HTC_HEADER_LEN + HTC_HDR_ALIGNMENT_PADDING, 4, + false); + if (!msg) { + htt_htc_pkt_free(pdev, pkt); + return -A_NO_MEMORY; + } + /* set the length of the message */ + qdf_nbuf_put_tail(msg, HTT_WDI_IPA_OP_REQUEST_SZ); + + /* fill in the message contents */ + msg_word = (uint32_t *) qdf_nbuf_data(msg); + + /* rewind beyond alignment pad to get to the HTC header reserved area */ + qdf_nbuf_push_head(msg, HTC_HDR_ALIGNMENT_PADDING); + + *msg_word = 0; + HTT_WDI_IPA_OP_REQUEST_OP_CODE_SET(*msg_word, + HTT_WDI_IPA_OPCODE_DBG_STATS); + HTT_H2T_MSG_TYPE_SET(*msg_word, HTT_H2T_MSG_TYPE_WDI_IPA_OP_REQ); + + SET_HTC_PACKET_INFO_TX(&pkt->htc_pkt, + htt_h2t_send_complete_free_netbuf, + qdf_nbuf_data(msg), + qdf_nbuf_len(msg), + pdev->htc_tx_endpoint, + 1); /* tag - not relevant here */ + + SET_HTC_PACKET_NET_BUF_CONTEXT(&pkt->htc_pkt, msg); + HTT_SEND_HTC_PKT(pdev, pkt); + return A_OK; +} + +/** + * htt_h2t_ipa_uc_get_share_stats() - WDI UC wifi sharing state request to FW + * @pdev: handle to the HTT instance + * + * Return: A_OK success + * A_NO_MEMORY No memory fail + */ +int htt_h2t_ipa_uc_get_share_stats(struct htt_pdev_t *pdev, uint8_t reset_stats) +{ + struct htt_htc_pkt *pkt; + qdf_nbuf_t msg; + uint32_t *msg_word; + + pkt = htt_htc_pkt_alloc(pdev); + if (!pkt) + return -A_NO_MEMORY; + + /* show that this is not a tx frame download + * (not required, but helpful) + */ + pkt->msdu_id = HTT_TX_COMPL_INV_MSDU_ID; + pkt->pdev_ctxt = NULL; /* not used during send-done callback */ + + /* reserve room for HTC header */ + msg = qdf_nbuf_alloc(pdev->osdev, + HTT_MSG_BUF_SIZE(HTT_WDI_IPA_OP_REQUEST_SZ)+ + HTT_MSG_BUF_SIZE(HTT_WDI_IPA_OP_REQ_GET_SHARING_STATS_SZ), + HTC_HEADER_LEN + HTC_HDR_ALIGNMENT_PADDING, 4, false); + if (!msg) { + htt_htc_pkt_free(pdev, pkt); + return -A_NO_MEMORY; + } + /* set the length of the message */ + qdf_nbuf_put_tail(msg, HTT_WDI_IPA_OP_REQUEST_SZ+ + HTT_WDI_IPA_OP_REQ_GET_SHARING_STATS_SZ); + + /* fill in the message contents */ + msg_word = (uint32_t *) qdf_nbuf_data(msg); + + /* rewind beyond alignment pad to get to the HTC header reserved area */ + qdf_nbuf_push_head(msg, HTC_HDR_ALIGNMENT_PADDING); + + *msg_word = 0; + HTT_WDI_IPA_OP_REQUEST_OP_CODE_SET(*msg_word, + HTT_WDI_IPA_OPCODE_GET_SHARING_STATS); + HTT_H2T_MSG_TYPE_SET(*msg_word, HTT_H2T_MSG_TYPE_WDI_IPA_OP_REQ); + + msg_word++; + *msg_word = 0; + HTT_WDI_IPA_OP_REQ_GET_SHARING_STATS_RESET_STATS_SET(*msg_word, + reset_stats); + + SET_HTC_PACKET_INFO_TX(&pkt->htc_pkt, + htt_h2t_send_complete_free_netbuf, + qdf_nbuf_data(msg), + qdf_nbuf_len(msg), + pdev->htc_tx_endpoint, + 1); /* tag - not relevant here */ + + SET_HTC_PACKET_NET_BUF_CONTEXT(&pkt->htc_pkt, msg); + HTT_SEND_HTC_PKT(pdev, pkt); + return A_OK; +} + +/** + * htt_h2t_ipa_uc_set_quota() - WDI UC state query request to firmware + * @pdev: handle to the HTT instance + * + * Return: A_OK success + * A_NO_MEMORY No memory fail + */ +int htt_h2t_ipa_uc_set_quota(struct htt_pdev_t *pdev, uint64_t quota_bytes) +{ + struct htt_htc_pkt *pkt; + qdf_nbuf_t msg; + uint32_t *msg_word; + + pkt = htt_htc_pkt_alloc(pdev); + if (!pkt) + return -A_NO_MEMORY; + + /* show that this is not a tx frame download + * (not required, but helpful) + */ + pkt->msdu_id = HTT_TX_COMPL_INV_MSDU_ID; + pkt->pdev_ctxt = NULL; /* not used during send-done callback */ + + /* reserve room for HTC header */ + msg = qdf_nbuf_alloc(pdev->osdev, + HTT_MSG_BUF_SIZE(HTT_WDI_IPA_OP_REQUEST_SZ)+ + HTT_MSG_BUF_SIZE(HTT_WDI_IPA_OP_REQ_SET_QUOTA_SZ), + HTC_HEADER_LEN + HTC_HDR_ALIGNMENT_PADDING, 4, false); + if (!msg) { + htt_htc_pkt_free(pdev, pkt); + return -A_NO_MEMORY; + } + /* set the length of the message */ + qdf_nbuf_put_tail(msg, HTT_WDI_IPA_OP_REQUEST_SZ+ + HTT_WDI_IPA_OP_REQ_SET_QUOTA_SZ); + + /* fill in the message contents */ + msg_word = (uint32_t *) qdf_nbuf_data(msg); + + /* rewind beyond alignment pad to get to the HTC header reserved area */ + qdf_nbuf_push_head(msg, HTC_HDR_ALIGNMENT_PADDING); + + *msg_word = 0; + HTT_WDI_IPA_OP_REQUEST_OP_CODE_SET(*msg_word, + HTT_WDI_IPA_OPCODE_SET_QUOTA); + HTT_H2T_MSG_TYPE_SET(*msg_word, HTT_H2T_MSG_TYPE_WDI_IPA_OP_REQ); + + msg_word++; + *msg_word = 0; + HTT_WDI_IPA_OP_REQ_SET_QUOTA_SET_QUOTA_SET(*msg_word, quota_bytes > 0); + + msg_word++; + *msg_word = 0; + HTT_WDI_IPA_OP_REQ_SET_QUOTA_QUOTA_LO_SET(*msg_word, + (uint32_t)(quota_bytes & + HTT_WDI_IPA_OP_REQ_SET_QUOTA_QUOTA_LO_M)); + + msg_word++; + *msg_word = 0; + HTT_WDI_IPA_OP_REQ_SET_QUOTA_QUOTA_HI_SET(*msg_word, + (uint32_t)(quota_bytes>>32 & + HTT_WDI_IPA_OP_REQ_SET_QUOTA_QUOTA_HI_M)); + + SET_HTC_PACKET_INFO_TX(&pkt->htc_pkt, + htt_h2t_send_complete_free_netbuf, + qdf_nbuf_data(msg), + qdf_nbuf_len(msg), + pdev->htc_tx_endpoint, + 1); /* tag - not relevant here */ + + SET_HTC_PACKET_NET_BUF_CONTEXT(&pkt->htc_pkt, msg); + HTT_SEND_HTC_PKT(pdev, pkt); + return A_OK; +} +#endif /* IPA_OFFLOAD */ diff --git a/drivers/staging/qcacld-3.0/core/dp/htt/htt_internal.h b/drivers/staging/qcacld-3.0/core/dp/htt/htt_internal.h new file mode 100644 index 0000000000000000000000000000000000000000..229725ddb2bad4a253b158cc00838a83f1d84299 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/dp/htt/htt_internal.h @@ -0,0 +1,885 @@ +/* + * Copyright (c) 2011, 2014-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef _HTT_INTERNAL__H_ +#define _HTT_INTERNAL__H_ + +#include /* A_STATUS */ +#include /* qdf_nbuf_t */ +#include /* qdf_assert */ +#include /* HTC_PACKET */ + +#include + +#ifndef offsetof +#define offsetof(type, field) ((size_t)(&((type *)0)->field)) +#endif + +#undef MS +#define MS(_v, _f) (((_v) & _f ## _MASK) >> _f ## _LSB) +#undef SM +#define SM(_v, _f) (((_v) << _f ## _LSB) & _f ## _MASK) +#undef WO +#define WO(_f) ((_f ## _OFFSET) >> 2) + +#define GET_FIELD(_addr, _f) MS(*((A_UINT32 *)(_addr) + WO(_f)), _f) + +#include +#include /* struct rx_attention, etc */ + +struct htt_host_fw_desc_base { + union { + struct fw_rx_desc_base val; + A_UINT32 dummy_pad; /* make sure it is DOWRD aligned */ + } u; +}; + + +/* + * This struct defines the basic descriptor information used by host, + * which is written either by the 11ac HW MAC into the host Rx data + * buffer ring directly or generated by FW and copied from Rx indication + */ +#define RX_HTT_HDR_STATUS_LEN 64 +struct htt_host_rx_desc_base { + struct htt_host_fw_desc_base fw_desc; + struct rx_attention attention; + struct rx_frag_info frag_info; + struct rx_mpdu_start mpdu_start; + struct rx_msdu_start msdu_start; + struct rx_msdu_end msdu_end; + struct rx_mpdu_end mpdu_end; + struct rx_ppdu_start ppdu_start; + struct rx_ppdu_end ppdu_end; + char rx_hdr_status[RX_HTT_HDR_STATUS_LEN]; +}; + +#define RX_DESC_ATTN_MPDU_LEN_ERR_BIT 0x08000000 + +#define RX_STD_DESC_ATTN_OFFSET \ + (offsetof(struct htt_host_rx_desc_base, attention)) +#define RX_STD_DESC_FRAG_INFO_OFFSET \ + (offsetof(struct htt_host_rx_desc_base, frag_info)) +#define RX_STD_DESC_MPDU_START_OFFSET \ + (offsetof(struct htt_host_rx_desc_base, mpdu_start)) +#define RX_STD_DESC_MSDU_START_OFFSET \ + (offsetof(struct htt_host_rx_desc_base, msdu_start)) +#define RX_STD_DESC_MSDU_END_OFFSET \ + (offsetof(struct htt_host_rx_desc_base, msdu_end)) +#define RX_STD_DESC_MPDU_END_OFFSET \ + (offsetof(struct htt_host_rx_desc_base, mpdu_end)) +#define RX_STD_DESC_PPDU_START_OFFSET \ + (offsetof(struct htt_host_rx_desc_base, ppdu_start)) +#define RX_STD_DESC_PPDU_END_OFFSET \ + (offsetof(struct htt_host_rx_desc_base, ppdu_end)) +#define RX_STD_DESC_HDR_STATUS_OFFSET \ + (offsetof(struct htt_host_rx_desc_base, rx_hdr_status)) + +#define RX_STD_DESC_FW_MSDU_OFFSET \ + (offsetof(struct htt_host_rx_desc_base, fw_desc)) + +#define RX_STD_DESC_SIZE (sizeof(struct htt_host_rx_desc_base)) + +#define RX_DESC_ATTN_OFFSET32 (RX_STD_DESC_ATTN_OFFSET >> 2) +#define RX_DESC_FRAG_INFO_OFFSET32 (RX_STD_DESC_FRAG_INFO_OFFSET >> 2) +#define RX_DESC_MPDU_START_OFFSET32 (RX_STD_DESC_MPDU_START_OFFSET >> 2) +#define RX_DESC_MSDU_START_OFFSET32 (RX_STD_DESC_MSDU_START_OFFSET >> 2) +#define RX_DESC_MSDU_END_OFFSET32 (RX_STD_DESC_MSDU_END_OFFSET >> 2) +#define RX_DESC_MPDU_END_OFFSET32 (RX_STD_DESC_MPDU_END_OFFSET >> 2) +#define RX_DESC_PPDU_START_OFFSET32 (RX_STD_DESC_PPDU_START_OFFSET >> 2) +#define RX_DESC_PPDU_END_OFFSET32 (RX_STD_DESC_PPDU_END_OFFSET >> 2) +#define RX_DESC_HDR_STATUS_OFFSET32 (RX_STD_DESC_HDR_STATUS_OFFSET >> 2) + +#define RX_STD_DESC_SIZE_DWORD (RX_STD_DESC_SIZE >> 2) + +/* + * Make sure there is a minimum headroom provided in the rx netbufs + * for use by the OS shim and OS and rx data consumers. + */ +#define HTT_RX_BUF_OS_MIN_HEADROOM 32 +#define HTT_RX_STD_DESC_RESERVATION \ + ((HTT_RX_BUF_OS_MIN_HEADROOM > RX_STD_DESC_SIZE) ? \ + HTT_RX_BUF_OS_MIN_HEADROOM : RX_STD_DESC_SIZE) +#define HTT_RX_DESC_RESERVATION32 \ + (HTT_RX_STD_DESC_RESERVATION >> 2) + +#define HTT_RX_DESC_ALIGN_MASK 7 /* 8-byte alignment */ + +#ifdef DEBUG_RX_RING_BUFFER +#define NBUF_MAP_ID(skb) \ + (((struct qdf_nbuf_cb *)((skb)->cb))->u.rx.map_index) + +/** + * rx_buf_debug: rx_ring history + * + * There are three types of entries in history: + * 1) rx-descriptors posted (and received) + * Both of these events are stored on the same entry + * @paddr : physical address posted on the ring + * @nbuf : virtual address of nbuf containing data + * @ndata : virual address of data (corresponds to physical address) + * @posted: time-stamp when the buffer is posted to the ring + * @recved: time-stamp when the buffer is received (rx_in_order_ind) + * : or 0, if the buffer has not been received yet + * 2) ring alloc-index (fill-index) updates + * @paddr : = 0 + * @nbuf : = 0 + * @ndata : = 0 + * posted : time-stamp when alloc index was updated + * recved : value of alloc index + * 3) htt_rx_in_order_indication reception + * @paddr : = 0 + * @nbuf : = 0 + * @ndata : msdu_cnt + * @posted: time-stamp when HTT message is recived + * @recvd : 0x48545452584D5367 ('HTTRXMSG') +*/ +#define HTT_RX_RING_BUFF_DBG_LIST (2 * 1024) +struct rx_buf_debug { + qdf_dma_addr_t paddr; + qdf_nbuf_t nbuf; + void *nbuf_data; + uint64_t posted; /* timetamp */ + uint64_t recved; /* timestamp */ + int cpu; + +}; +#endif + +static inline struct htt_host_rx_desc_base *htt_rx_desc(qdf_nbuf_t msdu) +{ + return (struct htt_host_rx_desc_base *) + (((size_t) (qdf_nbuf_head(msdu) + HTT_RX_DESC_ALIGN_MASK)) & + ~HTT_RX_DESC_ALIGN_MASK); +} + +#if defined(FEATURE_LRO) +/** + * htt_print_rx_desc_lro() - print LRO information in the rx + * descriptor + * @rx_desc: HTT rx descriptor + * + * Prints the LRO related fields in the HTT rx descriptor + * + * Return: none + */ +static inline void htt_print_rx_desc_lro(struct htt_host_rx_desc_base *rx_desc) +{ + qdf_print + ("----------------------RX DESC LRO----------------------\n"); + qdf_print("msdu_end.lro_eligible:0x%x\n", + rx_desc->msdu_end.lro_eligible); + qdf_print("msdu_start.tcp_only_ack:0x%x\n", + rx_desc->msdu_start.tcp_only_ack); + qdf_print("msdu_end.tcp_udp_chksum:0x%x\n", + rx_desc->msdu_end.tcp_udp_chksum); + qdf_print("msdu_end.tcp_seq_number:0x%x\n", + rx_desc->msdu_end.tcp_seq_number); + qdf_print("msdu_end.tcp_ack_number:0x%x\n", + rx_desc->msdu_end.tcp_ack_number); + qdf_print("msdu_start.tcp_proto:0x%x\n", + rx_desc->msdu_start.tcp_proto); + qdf_print("msdu_start.ipv6_proto:0x%x\n", + rx_desc->msdu_start.ipv6_proto); + qdf_print("msdu_start.ipv4_proto:0x%x\n", + rx_desc->msdu_start.ipv4_proto); + qdf_print("msdu_start.l3_offset:0x%x\n", + rx_desc->msdu_start.l3_offset); + qdf_print("msdu_start.l4_offset:0x%x\n", + rx_desc->msdu_start.l4_offset); + qdf_print("msdu_start.flow_id_toeplitz:0x%x\n", + rx_desc->msdu_start.flow_id_toeplitz); + qdf_print + ("---------------------------------------------------------\n"); +} + +/** + * htt_print_rx_desc_lro() - extract LRO information from the rx + * descriptor + * @msdu: network buffer + * @rx_desc: HTT rx descriptor + * + * Extracts the LRO related fields from the HTT rx descriptor + * and stores them in the network buffer's control block + * + * Return: none + */ +static inline void htt_rx_extract_lro_info(qdf_nbuf_t msdu, + struct htt_host_rx_desc_base *rx_desc) +{ + if (rx_desc->attention.tcp_udp_chksum_fail) + QDF_NBUF_CB_RX_LRO_ELIGIBLE(msdu) = 0; + else + QDF_NBUF_CB_RX_LRO_ELIGIBLE(msdu) = + rx_desc->msdu_end.lro_eligible; + + if (QDF_NBUF_CB_RX_LRO_ELIGIBLE(msdu)) { + QDF_NBUF_CB_RX_TCP_PURE_ACK(msdu) = rx_desc->msdu_start.tcp_only_ack; + QDF_NBUF_CB_RX_TCP_CHKSUM(msdu) = rx_desc->msdu_end.tcp_udp_chksum; + QDF_NBUF_CB_RX_TCP_SEQ_NUM(msdu) = rx_desc->msdu_end.tcp_seq_number; + QDF_NBUF_CB_RX_TCP_ACK_NUM(msdu) = rx_desc->msdu_end.tcp_ack_number; + QDF_NBUF_CB_RX_TCP_WIN(msdu) = rx_desc->msdu_end.window_size; + QDF_NBUF_CB_RX_TCP_PROTO(msdu) = rx_desc->msdu_start.tcp_proto; + QDF_NBUF_CB_RX_IPV6_PROTO(msdu) = rx_desc->msdu_start.ipv6_proto; + QDF_NBUF_CB_RX_IP_OFFSET(msdu) = rx_desc->msdu_start.l3_offset; + QDF_NBUF_CB_RX_TCP_OFFSET(msdu) = rx_desc->msdu_start.l4_offset; + QDF_NBUF_CB_RX_FLOW_ID_TOEPLITZ(msdu) = + rx_desc->msdu_start.flow_id_toeplitz; + } +} +#else +static inline void htt_print_rx_desc_lro(struct htt_host_rx_desc_base *rx_desc) +{} +static inline void htt_rx_extract_lro_info(qdf_nbuf_t msdu, + struct htt_host_rx_desc_base *rx_desc) {} +#endif /* FEATURE_LRO */ + +static inline void htt_print_rx_desc(struct htt_host_rx_desc_base *rx_desc) +{ + qdf_print + ("----------------------RX DESC----------------------------\n"); + qdf_print("attention: %#010x\n", + (unsigned int)(*(uint32_t *) &rx_desc->attention)); + qdf_print("frag_info: %#010x\n", + (unsigned int)(*(uint32_t *) &rx_desc->frag_info)); + qdf_print("mpdu_start: %#010x %#010x %#010x\n", + (unsigned int)(((uint32_t *) &rx_desc->mpdu_start)[0]), + (unsigned int)(((uint32_t *) &rx_desc->mpdu_start)[1]), + (unsigned int)(((uint32_t *) &rx_desc->mpdu_start)[2])); + qdf_print("msdu_start: %#010x %#010x %#010x\n", + (unsigned int)(((uint32_t *) &rx_desc->msdu_start)[0]), + (unsigned int)(((uint32_t *) &rx_desc->msdu_start)[1]), + (unsigned int)(((uint32_t *) &rx_desc->msdu_start)[2])); + qdf_print("msdu_end: %#010x %#010x %#010x %#010x %#010x\n", + (unsigned int)(((uint32_t *) &rx_desc->msdu_end)[0]), + (unsigned int)(((uint32_t *) &rx_desc->msdu_end)[1]), + (unsigned int)(((uint32_t *) &rx_desc->msdu_end)[2]), + (unsigned int)(((uint32_t *) &rx_desc->msdu_end)[3]), + (unsigned int)(((uint32_t *) &rx_desc->msdu_end)[4])); + qdf_print("mpdu_end: %#010x\n", + (unsigned int)(*(uint32_t *) &rx_desc->mpdu_end)); + qdf_print("ppdu_start: " "%#010x %#010x %#010x %#010x %#010x\n" + "%#010x %#010x %#010x %#010x %#010x\n", + (unsigned int)(((uint32_t *) &rx_desc->ppdu_start)[0]), + (unsigned int)(((uint32_t *) &rx_desc->ppdu_start)[1]), + (unsigned int)(((uint32_t *) &rx_desc->ppdu_start)[2]), + (unsigned int)(((uint32_t *) &rx_desc->ppdu_start)[3]), + (unsigned int)(((uint32_t *) &rx_desc->ppdu_start)[4]), + (unsigned int)(((uint32_t *) &rx_desc->ppdu_start)[5]), + (unsigned int)(((uint32_t *) &rx_desc->ppdu_start)[6]), + (unsigned int)(((uint32_t *) &rx_desc->ppdu_start)[7]), + (unsigned int)(((uint32_t *) &rx_desc->ppdu_start)[8]), + (unsigned int)(((uint32_t *) &rx_desc->ppdu_start)[9])); + qdf_print("ppdu_end:" "%#010x %#010x %#010x %#010x %#010x\n" + "%#010x %#010x %#010x %#010x %#010x\n" + "%#010x,%#010x %#010x %#010x %#010x\n" + "%#010x %#010x %#010x %#010x %#010x\n" "%#010x %#010x\n", + (unsigned int)(((uint32_t *) &rx_desc->ppdu_end)[0]), + (unsigned int)(((uint32_t *) &rx_desc->ppdu_end)[1]), + (unsigned int)(((uint32_t *) &rx_desc->ppdu_end)[2]), + (unsigned int)(((uint32_t *) &rx_desc->ppdu_end)[3]), + (unsigned int)(((uint32_t *) &rx_desc->ppdu_end)[4]), + (unsigned int)(((uint32_t *) &rx_desc->ppdu_end)[5]), + (unsigned int)(((uint32_t *) &rx_desc->ppdu_end)[6]), + (unsigned int)(((uint32_t *) &rx_desc->ppdu_end)[7]), + (unsigned int)(((uint32_t *) &rx_desc->ppdu_end)[8]), + (unsigned int)(((uint32_t *) &rx_desc->ppdu_end)[9]), + (unsigned int)(((uint32_t *) &rx_desc->ppdu_end)[10]), + (unsigned int)(((uint32_t *) &rx_desc->ppdu_end)[11]), + (unsigned int)(((uint32_t *) &rx_desc->ppdu_end)[12]), + (unsigned int)(((uint32_t *) &rx_desc->ppdu_end)[13]), + (unsigned int)(((uint32_t *) &rx_desc->ppdu_end)[14]), + (unsigned int)(((uint32_t *) &rx_desc->ppdu_end)[15]), + (unsigned int)(((uint32_t *) &rx_desc->ppdu_end)[16]), + (unsigned int)(((uint32_t *) &rx_desc->ppdu_end)[17]), + (unsigned int)(((uint32_t *) &rx_desc->ppdu_end)[18]), + (unsigned int)(((uint32_t *) &rx_desc->ppdu_end)[19]), + (unsigned int)(((uint32_t *) &rx_desc->ppdu_end)[20]), + (unsigned int)(((uint32_t *) &rx_desc->ppdu_end)[21])); + qdf_print + ("---------------------------------------------------------\n"); +} + +#ifndef HTT_ASSERT_LEVEL +#define HTT_ASSERT_LEVEL 3 +#endif + +#define HTT_ASSERT_ALWAYS(condition) qdf_assert_always((condition)) + +#define HTT_ASSERT0(condition) qdf_assert((condition)) +#if HTT_ASSERT_LEVEL > 0 +#define HTT_ASSERT1(condition) qdf_assert((condition)) +#else +#define HTT_ASSERT1(condition) +#endif + +#if HTT_ASSERT_LEVEL > 1 +#define HTT_ASSERT2(condition) qdf_assert((condition)) +#else +#define HTT_ASSERT2(condition) +#endif + +#if HTT_ASSERT_LEVEL > 2 +#define HTT_ASSERT3(condition) qdf_assert((condition)) +#else +#define HTT_ASSERT3(condition) +#endif + +#define HTT_MAC_ADDR_LEN 6 + +/* + * HTT_MAX_SEND_QUEUE_DEPTH - + * How many packets HTC should allow to accumulate in a send queue + * before calling the EpSendFull callback to see whether to retain + * or drop packets. + * This is not relevant for LL, where tx descriptors should be immediately + * downloaded to the target. + * This is not very relevant for HL either, since it is anticipated that + * the HL tx download scheduler will not work this far in advance - rather, + * it will make its decisions just-in-time, so it can be responsive to + * changing conditions. + * Hence, this queue depth threshold spec is mostly just a formality. + */ +#define HTT_MAX_SEND_QUEUE_DEPTH 64 + +#define IS_PWR2(value) (((value) ^ ((value)-1)) == ((value) << 1) - 1) + +/* FIX THIS + * Should be: sizeof(struct htt_host_rx_desc) + max rx MSDU size, + * rounded up to a cache line size. + */ +#define HTT_RX_BUF_SIZE 1920 +#define MAX_RX_PAYLOAD_SZ (HTT_RX_BUF_SIZE - RX_STD_DESC_SIZE) +/* + * DMA_MAP expects the buffer to be an integral number of cache lines. + * Rather than checking the actual cache line size, this code makes a + * conservative estimate of what the cache line size could be. + */ +#define HTT_LOG2_MAX_CACHE_LINE_SIZE 7 /* 2^7 = 128 */ +#define HTT_MAX_CACHE_LINE_SIZE_MASK ((1 << HTT_LOG2_MAX_CACHE_LINE_SIZE) - 1) + +#ifdef BIG_ENDIAN_HOST +/* + * big-endian: bytes within a 4-byte "word" are swapped: + * pre-swap post-swap + * index index + * 0 3 + * 1 2 + * 2 1 + * 3 0 + * 4 7 + * 5 6 + * etc. + * To compute the post-swap index from the pre-swap index, compute + * the byte offset for the start of the word (index & ~0x3) and add + * the swapped byte offset within the word (3 - (index & 0x3)). + */ +#define HTT_ENDIAN_BYTE_IDX_SWAP(idx) (((idx) & ~0x3) + (3 - ((idx) & 0x3))) +#else +/* little-endian: no adjustment needed */ +#define HTT_ENDIAN_BYTE_IDX_SWAP(idx) idx +#endif + +#define HTT_TX_MUTEX_INIT(_mutex) \ + qdf_spinlock_create(_mutex) + +#define HTT_TX_MUTEX_ACQUIRE(_mutex) \ + qdf_spin_lock_bh(_mutex) + +#define HTT_TX_MUTEX_RELEASE(_mutex) \ + qdf_spin_unlock_bh(_mutex) + +#define HTT_TX_MUTEX_DESTROY(_mutex) \ + qdf_spinlock_destroy(_mutex) + +#define HTT_TX_DESC_PADDR(_pdev, _tx_desc_vaddr) \ + ((_pdev)->tx_descs.pool_paddr + (uint32_t) \ + ((char *)(_tx_desc_vaddr) - \ + (char *)((_pdev)->tx_descs.pool_vaddr))) + +#ifdef ATH_11AC_TXCOMPACT + +#define HTT_TX_NBUF_QUEUE_MUTEX_INIT(_pdev) \ + qdf_spinlock_create(&_pdev->txnbufq_mutex) + +#define HTT_TX_NBUF_QUEUE_MUTEX_DESTROY(_pdev) \ + HTT_TX_MUTEX_DESTROY(&_pdev->txnbufq_mutex) + +#define HTT_TX_NBUF_QUEUE_REMOVE(_pdev, _msdu) do { \ + HTT_TX_MUTEX_ACQUIRE(&_pdev->txnbufq_mutex); \ + _msdu = qdf_nbuf_queue_remove(&_pdev->txnbufq);\ + HTT_TX_MUTEX_RELEASE(&_pdev->txnbufq_mutex); \ + } while (0) + +#define HTT_TX_NBUF_QUEUE_ADD(_pdev, _msdu) do { \ + HTT_TX_MUTEX_ACQUIRE(&_pdev->txnbufq_mutex); \ + qdf_nbuf_queue_add(&_pdev->txnbufq, _msdu); \ + HTT_TX_MUTEX_RELEASE(&_pdev->txnbufq_mutex); \ + } while (0) + +#define HTT_TX_NBUF_QUEUE_INSERT_HEAD(_pdev, _msdu) do { \ + HTT_TX_MUTEX_ACQUIRE(&_pdev->txnbufq_mutex); \ + qdf_nbuf_queue_insert_head(&_pdev->txnbufq, _msdu);\ + HTT_TX_MUTEX_RELEASE(&_pdev->txnbufq_mutex); \ + } while (0) +#else + +#define HTT_TX_NBUF_QUEUE_MUTEX_INIT(_pdev) +#define HTT_TX_NBUF_QUEUE_REMOVE(_pdev, _msdu) +#define HTT_TX_NBUF_QUEUE_ADD(_pdev, _msdu) +#define HTT_TX_NBUF_QUEUE_INSERT_HEAD(_pdev, _msdu) +#define HTT_TX_NBUF_QUEUE_MUTEX_DESTROY(_pdev) + +#endif + +#ifdef CONFIG_HL_SUPPORT + +static inline void htt_tx_resume_handler(void *context) +{ + return; +} +#else + +void htt_tx_resume_handler(void *); +#endif + +#ifdef ATH_11AC_TXCOMPACT +#define HTT_TX_SCHED htt_tx_sched +#else +#define HTT_TX_SCHED(pdev) /* no-op */ +#endif + +int htt_tx_attach(struct htt_pdev_t *pdev, int desc_pool_elems); + +void htt_tx_detach(struct htt_pdev_t *pdev); + +int htt_rx_attach(struct htt_pdev_t *pdev); + +#if defined(CONFIG_HL_SUPPORT) + +static inline void htt_rx_detach(struct htt_pdev_t *pdev) +{ + return; +} +#else + +void htt_rx_detach(struct htt_pdev_t *pdev); +#endif + +int htt_htc_attach(struct htt_pdev_t *pdev, uint16_t service_id); + +void htt_t2h_msg_handler(void *context, HTC_PACKET *pkt); +#ifdef WLAN_FEATURE_FASTPATH +void htt_t2h_msg_handler_fast(void *htt_pdev, qdf_nbuf_t *cmpl_msdus, + uint32_t num_cmpls); +#else +static inline void htt_t2h_msg_handler_fast(void *htt_pdev, + qdf_nbuf_t *cmpl_msdus, + uint32_t num_cmpls) +{ +} +#endif + +void htt_h2t_send_complete(void *context, HTC_PACKET *pkt); + +A_STATUS htt_h2t_ver_req_msg(struct htt_pdev_t *pdev); + +#if defined(HELIUMPLUS) +A_STATUS +htt_h2t_frag_desc_bank_cfg_msg(struct htt_pdev_t *pdev); +#endif /* defined(HELIUMPLUS) */ + +extern QDF_STATUS htt_h2t_rx_ring_cfg_msg_ll(struct htt_pdev_t *pdev); + +extern QDF_STATUS htt_h2t_rx_ring_rfs_cfg_msg_ll(struct htt_pdev_t *pdev); + +extern QDF_STATUS htt_h2t_rx_ring_rfs_cfg_msg_hl(struct htt_pdev_t *pdev); + +extern QDF_STATUS htt_h2t_rx_ring_cfg_msg_hl(struct htt_pdev_t *pdev); + +extern QDF_STATUS (*htt_h2t_rx_ring_cfg_msg)(struct htt_pdev_t *pdev); + +HTC_SEND_FULL_ACTION htt_h2t_full(void *context, HTC_PACKET *pkt); + +struct htt_htc_pkt *htt_htc_pkt_alloc(struct htt_pdev_t *pdev); + +void htt_htc_pkt_free(struct htt_pdev_t *pdev, struct htt_htc_pkt *pkt); + +void htt_htc_pkt_pool_free(struct htt_pdev_t *pdev); + +#ifdef ATH_11AC_TXCOMPACT +void htt_htc_misc_pkt_list_trim(struct htt_pdev_t *pdev, int level); + +void +htt_htc_misc_pkt_list_add(struct htt_pdev_t *pdev, struct htt_htc_pkt *pkt); + +void htt_htc_misc_pkt_pool_free(struct htt_pdev_t *pdev); +#endif + +int +htt_rx_hash_list_insert(struct htt_pdev_t *pdev, + qdf_dma_addr_t paddr, + qdf_nbuf_t netbuf); + +qdf_nbuf_t +htt_rx_hash_list_lookup(struct htt_pdev_t *pdev, qdf_dma_addr_t paddr); + +#ifdef IPA_OFFLOAD +int +htt_tx_ipa_uc_attach(struct htt_pdev_t *pdev, + unsigned int uc_tx_buf_sz, + unsigned int uc_tx_buf_cnt, + unsigned int uc_tx_partition_base); + +int +htt_rx_ipa_uc_attach(struct htt_pdev_t *pdev, unsigned int rx_ind_ring_size); + +int htt_tx_ipa_uc_detach(struct htt_pdev_t *pdev); + +int htt_rx_ipa_uc_detach(struct htt_pdev_t *pdev); +#else +/** + * htt_tx_ipa_uc_attach() - attach htt ipa uc tx resource + * @pdev: htt context + * @uc_tx_buf_sz: single tx buffer size + * @uc_tx_buf_cnt: total tx buffer count + * @uc_tx_partition_base: tx buffer partition start + * + * Return: 0 success + */ +static inline int +htt_tx_ipa_uc_attach(struct htt_pdev_t *pdev, + unsigned int uc_tx_buf_sz, + unsigned int uc_tx_buf_cnt, + unsigned int uc_tx_partition_base) +{ + return 0; +} + +/** + * htt_rx_ipa_uc_attach() - attach htt ipa uc rx resource + * @pdev: htt context + * @rx_ind_ring_size: rx ring size + * + * Return: 0 success + */ +static inline int +htt_rx_ipa_uc_attach(struct htt_pdev_t *pdev, unsigned int rx_ind_ring_size) +{ + return 0; +} + +static inline int htt_tx_ipa_uc_detach(struct htt_pdev_t *pdev) +{ + return 0; +} + +static inline int htt_rx_ipa_uc_detach(struct htt_pdev_t *pdev) +{ + return 0; +} +#endif /* IPA_OFFLOAD */ + +/* Maximum Outstanding Bus Download */ +#define HTT_MAX_BUS_CREDIT 33 + +#ifdef CONFIG_HL_SUPPORT + +/** + * htt_tx_credit_update() - check for diff in bus delta and target delta + * @pdev: pointer to htt device. + * + * Return: min of bus delta and target delta + */ +int +htt_tx_credit_update(struct htt_pdev_t *pdev); +#else + +static inline int +htt_tx_credit_update(struct htt_pdev_t *pdev) +{ + return 0; +} +#endif + + +#ifdef FEATURE_HL_GROUP_CREDIT_FLOW_CONTROL + +#define HTT_TX_GROUP_INDEX_OFFSET \ +(sizeof(struct htt_txq_group) / sizeof(u_int32_t)) + +void htt_tx_group_credit_process(struct htt_pdev_t *pdev, u_int32_t *msg_word); +#else + +static inline +void htt_tx_group_credit_process(struct htt_pdev_t *pdev, u_int32_t *msg_word) +{ + return; +} +#endif + +#ifdef DEBUG_RX_RING_BUFFER +/** + * htt_rx_dbg_rxbuf_init() - init debug rx buff list + * @pdev: pdev handle + * + * Allocation is done from bss segment. This uses vmalloc and has a bit + * of an overhead compared to kmalloc (which qdf_mem_alloc wraps). The impact + * of the overhead to performance will need to be quantified. + * + * Return: none + */ +static struct rx_buf_debug rx_buff_list_bss[HTT_RX_RING_BUFF_DBG_LIST]; +static inline +void htt_rx_dbg_rxbuf_init(struct htt_pdev_t *pdev) +{ + pdev->rx_buff_list = rx_buff_list_bss; + qdf_spinlock_create(&(pdev->rx_buff_list_lock)); + pdev->rx_buff_index = 0; + pdev->rx_buff_posted_cum = 0; + pdev->rx_buff_recvd_cum = 0; + pdev->rx_buff_recvd_err = 0; + pdev->refill_retry_timer_starts = 0; + pdev->refill_retry_timer_calls = 0; + pdev->refill_retry_timer_doubles = 0; +} + +/** + * htt_display_rx_buf_debug() - display debug rx buff list and some counters + * @pdev: pdev handle + * + * Return: Success + */ +static inline int htt_display_rx_buf_debug(struct htt_pdev_t *pdev) +{ + int i; + struct rx_buf_debug *buf; + + if ((pdev != NULL) && + (pdev->rx_buff_list != NULL)) { + buf = pdev->rx_buff_list; + for (i = 0; i < HTT_RX_RING_BUFF_DBG_LIST; i++) { + if (buf[i].posted != 0) + QDF_TRACE(QDF_MODULE_ID_TXRX, + QDF_TRACE_LEVEL_ERROR, + "[%d][0x%x] %p %lu %p %llu %llu", + i, buf[i].cpu, + buf[i].nbuf_data, + (unsigned long)buf[i].paddr, + buf[i].nbuf, + buf[i].posted, + buf[i].recved); + } + + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "rxbuf_idx %d all_posted: %d all_recvd: %d recv_err: %d", + pdev->rx_buff_index, + pdev->rx_buff_posted_cum, + pdev->rx_buff_recvd_cum, + pdev->rx_buff_recvd_err); + + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "timer kicks :%d actual :%d restarts:%d debtors: %d fill_n: %d", + pdev->refill_retry_timer_starts, + pdev->refill_retry_timer_calls, + pdev->refill_retry_timer_doubles, + pdev->rx_buff_debt_invoked, + pdev->rx_buff_fill_n_invoked); + } else + return -EINVAL; + return 0; +} + +/** + * htt_rx_dbg_rxbuf_set() - set element of rx buff list + * @pdev: pdev handle + * @paddr: physical address of netbuf + * @rx_netbuf: received netbuf + * + * Return: none + */ +static inline +void htt_rx_dbg_rxbuf_set(struct htt_pdev_t *pdev, qdf_dma_addr_t paddr, + qdf_nbuf_t rx_netbuf) +{ + if (pdev->rx_buff_list) { + qdf_spin_lock_bh(&(pdev->rx_buff_list_lock)); + pdev->rx_buff_list[pdev->rx_buff_index].paddr = paddr; + pdev->rx_buff_list[pdev->rx_buff_index].nbuf = rx_netbuf; + pdev->rx_buff_list[pdev->rx_buff_index].nbuf_data = + rx_netbuf->data; + pdev->rx_buff_list[pdev->rx_buff_index].posted = + qdf_get_log_timestamp(); + pdev->rx_buff_posted_cum++; + pdev->rx_buff_list[pdev->rx_buff_index].recved = 0; + pdev->rx_buff_list[pdev->rx_buff_index].cpu = + (1 << qdf_get_cpu()); + NBUF_MAP_ID(rx_netbuf) = pdev->rx_buff_index; + if (++pdev->rx_buff_index >= + HTT_RX_RING_BUFF_DBG_LIST) + pdev->rx_buff_index = 0; + qdf_spin_unlock_bh(&(pdev->rx_buff_list_lock)); + } +} + +/** + * htt_rx_dbg_rxbuf_set() - reset element of rx buff list + * @pdev: pdev handle + * @netbuf: rx sk_buff + * Return: none + */ +static inline +void htt_rx_dbg_rxbuf_reset(struct htt_pdev_t *pdev, + qdf_nbuf_t netbuf) +{ + uint32_t index; + + if (pdev->rx_buff_list) { + qdf_spin_lock_bh(&(pdev->rx_buff_list_lock)); + index = NBUF_MAP_ID(netbuf); + if (index < HTT_RX_RING_BUFF_DBG_LIST) { + pdev->rx_buff_list[index].recved = + qdf_get_log_timestamp(); + pdev->rx_buff_recvd_cum++; + } else { + pdev->rx_buff_recvd_err++; + } + pdev->rx_buff_list[pdev->rx_buff_index].cpu |= + (1 << qdf_get_cpu()); + qdf_spin_unlock_bh(&(pdev->rx_buff_list_lock)); + } +} +/** + * htt_rx_dbg_rxbuf_indupd() - add a record for alloc index update + * @pdev: pdev handle + * @idx : value of the index + * + * Return: none + */ +static inline +void htt_rx_dbg_rxbuf_indupd(struct htt_pdev_t *pdev, int alloc_index) +{ + if (pdev->rx_buff_list) { + qdf_spin_lock_bh(&(pdev->rx_buff_list_lock)); + pdev->rx_buff_list[pdev->rx_buff_index].paddr = 0; + pdev->rx_buff_list[pdev->rx_buff_index].nbuf = 0; + pdev->rx_buff_list[pdev->rx_buff_index].nbuf_data = 0; + pdev->rx_buff_list[pdev->rx_buff_index].posted = + qdf_get_log_timestamp(); + pdev->rx_buff_list[pdev->rx_buff_index].recved = + (uint64_t)alloc_index; + pdev->rx_buff_list[pdev->rx_buff_index].cpu = + (1 << qdf_get_cpu()); + if (++pdev->rx_buff_index >= + HTT_RX_RING_BUFF_DBG_LIST) + pdev->rx_buff_index = 0; + qdf_spin_unlock_bh(&(pdev->rx_buff_list_lock)); + } +} +/** + * htt_rx_dbg_rxbuf_httrxind() - add a record for recipt of htt rx_ind msg + * @pdev: pdev handle + * + * Return: none + */ +static inline +void htt_rx_dbg_rxbuf_httrxind(struct htt_pdev_t *pdev, unsigned int msdu_cnt) +{ + if (pdev->rx_buff_list) { + qdf_spin_lock_bh(&(pdev->rx_buff_list_lock)); + pdev->rx_buff_list[pdev->rx_buff_index].paddr = msdu_cnt; + pdev->rx_buff_list[pdev->rx_buff_index].nbuf = 0; + pdev->rx_buff_list[pdev->rx_buff_index].nbuf_data = 0; + pdev->rx_buff_list[pdev->rx_buff_index].posted = + qdf_get_log_timestamp(); + pdev->rx_buff_list[pdev->rx_buff_index].recved = + (uint64_t)0x48545452584D5347; /* 'HTTRXMSG' */ + pdev->rx_buff_list[pdev->rx_buff_index].cpu = + (1 << qdf_get_cpu()); + if (++pdev->rx_buff_index >= + HTT_RX_RING_BUFF_DBG_LIST) + pdev->rx_buff_index = 0; + qdf_spin_unlock_bh(&(pdev->rx_buff_list_lock)); + } +} + +/** + * htt_rx_dbg_rxbuf_deinit() - deinit debug rx buff list + * @pdev: pdev handle + * + * Return: none + */ +static inline +void htt_rx_dbg_rxbuf_deinit(struct htt_pdev_t *pdev) +{ + if (pdev->rx_buff_list) + pdev->rx_buff_list = NULL; + qdf_spinlock_destroy(&(pdev->rx_buff_list_lock)); +} +#else +static inline +void htt_rx_dbg_rxbuf_init(struct htt_pdev_t *pdev) +{ + return; +} +static inline int htt_display_rx_buf_debug(struct htt_pdev_t *pdev) +{ + return 0; +} + +static inline +void htt_rx_dbg_rxbuf_set(struct htt_pdev_t *pdev, + uint32_t paddr, + qdf_nbuf_t rx_netbuf) +{ + return; +} +static inline +void htt_rx_dbg_rxbuf_reset(struct htt_pdev_t *pdev, + qdf_nbuf_t netbuf) +{ + return; +} +static inline +void htt_rx_dbg_rxbuf_indupd(struct htt_pdev_t *pdev, + int alloc_index) +{ + return; +} +static inline +void htt_rx_dbg_rxbuf_httrxind(struct htt_pdev_t *pdev, + unsigned int msdu_cnt) +{ + return; +} +static inline +void htt_rx_dbg_rxbuf_deinit(struct htt_pdev_t *pdev) +{ + return; +} +#endif +#endif /* _HTT_INTERNAL__H_ */ diff --git a/drivers/staging/qcacld-3.0/core/dp/htt/htt_rx.c b/drivers/staging/qcacld-3.0/core/dp/htt/htt_rx.c new file mode 100644 index 0000000000000000000000000000000000000000..51ce3f7ce083b3d6d23a9357ec0f2ec61cc10bf6 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/dp/htt/htt_rx.c @@ -0,0 +1,3778 @@ +/* + * Copyright (c) 2011-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * @file htt_rx.c + * @brief Implement receive aspects of HTT. + * @details + * This file contains three categories of HTT rx code: + * 1. An abstraction of the rx descriptor, to hide the + * differences between the HL vs. LL rx descriptor. + * 2. Functions for providing access to the (series of) + * rx descriptor(s) and rx frame(s) associated with + * an rx indication message. + * 3. Functions for setting up and using the MAC DMA + * rx ring (applies to LL only). + */ + +#include /* qdf_mem_malloc,free, etc. */ +#include /* qdf_print, bool */ +#include /* qdf_nbuf_t, etc. */ +#include /* qdf_timer_free */ + +#include /* HTT_HL_RX_DESC_SIZE */ +#include +#include +#include +#include /* HTT_ASSERT, htt_pdev_t, HTT_RX_BUF_SIZE */ +#include "regtable.h" + +#include /* ieee80211_frame, ieee80211_qoscntl */ +#include /* ieee80211_rx_status */ +#include +#include +#include "ol_txrx_types.h" +#ifdef DEBUG_DMA_DONE +#include +#include +#endif +#include + +#ifdef HTT_DEBUG_DATA +#define HTT_PKT_DUMP(x) x +#else +#define HTT_PKT_DUMP(x) /* no-op */ +#endif + +/* AR9888v1 WORKAROUND for EV#112367 */ +/* FIX THIS - remove this WAR when the bug is fixed */ +#define PEREGRINE_1_0_ZERO_LEN_PHY_ERR_WAR + +/*--- setup / tear-down functions -------------------------------------------*/ + +#ifndef HTT_RX_RING_SIZE_MIN +#define HTT_RX_RING_SIZE_MIN 128 /* slightly > than one large A-MPDU */ +#endif + +#ifndef HTT_RX_RING_SIZE_MAX +#define HTT_RX_RING_SIZE_MAX 2048 /* ~20 ms @ 1 Gbps of 1500B MSDUs */ +#endif + +#ifndef HTT_RX_AVG_FRM_BYTES +#define HTT_RX_AVG_FRM_BYTES 1000 +#endif + +#ifndef HTT_RX_HOST_LATENCY_MAX_MS +#define HTT_RX_HOST_LATENCY_MAX_MS 20 /* ms */ /* very conservative */ +#endif + + /* very conservative to ensure enough buffers are allocated */ +#ifndef HTT_RX_HOST_LATENCY_WORST_LIKELY_MS +#define HTT_RX_HOST_LATENCY_WORST_LIKELY_MS 20 +#endif + +#ifndef HTT_RX_RING_REFILL_RETRY_TIME_MS +#define HTT_RX_RING_REFILL_RETRY_TIME_MS 50 +#endif + +/*--- RX In Order Definitions ------------------------------------------------*/ + +/* Number of buckets in the hash table */ +#define RX_NUM_HASH_BUCKETS 1024 /* This should always be a power of 2 */ +#define RX_NUM_HASH_BUCKETS_MASK (RX_NUM_HASH_BUCKETS - 1) + +/* Number of hash entries allocated per bucket */ +#define RX_ENTRIES_SIZE 10 + +#define RX_HASH_FUNCTION(a) (((a >> 14) ^ (a >> 4)) & RX_NUM_HASH_BUCKETS_MASK) + +#ifdef RX_HASH_DEBUG_LOG +#define RX_HASH_LOG(x) x +#else +#define RX_HASH_LOG(x) /* no-op */ +#endif + +#ifndef CONFIG_HL_SUPPORT +/* De -initialization function of the rx buffer hash table. This function will + * free up the hash table which includes freeing all the pending rx buffers + */ +static void htt_rx_hash_deinit(struct htt_pdev_t *pdev) +{ + + uint32_t i; + struct htt_rx_hash_entry *hash_entry; + struct htt_rx_hash_bucket **hash_table; + struct htt_list_node *list_iter = NULL; + + if (NULL == pdev->rx_ring.hash_table) + return; + + qdf_spin_lock_bh(&(pdev->rx_ring.rx_hash_lock)); + hash_table = pdev->rx_ring.hash_table; + pdev->rx_ring.hash_table = NULL; + qdf_spin_unlock_bh(&(pdev->rx_ring.rx_hash_lock)); + + for (i = 0; i < RX_NUM_HASH_BUCKETS; i++) { + /* Free the hash entries in hash bucket i */ + list_iter = hash_table[i]->listhead.next; + while (list_iter != &hash_table[i]->listhead) { + hash_entry = + (struct htt_rx_hash_entry *)((char *)list_iter - + pdev->rx_ring. + listnode_offset); + if (hash_entry->netbuf) { +#ifdef DEBUG_DMA_DONE + qdf_nbuf_unmap(pdev->osdev, hash_entry->netbuf, + QDF_DMA_BIDIRECTIONAL); +#else + qdf_nbuf_unmap(pdev->osdev, hash_entry->netbuf, + QDF_DMA_FROM_DEVICE); +#endif + qdf_nbuf_free(hash_entry->netbuf); + hash_entry->paddr = 0; + } + list_iter = list_iter->next; + + if (!hash_entry->fromlist) + qdf_mem_free(hash_entry); + } + + qdf_mem_free(hash_table[i]); + + } + qdf_mem_free(hash_table); + + qdf_spinlock_destroy(&(pdev->rx_ring.rx_hash_lock)); + +} +#endif + +/* + * This function is used both below within this file (which the compiler + * will hopefully inline), and out-line from other files via the + * htt_rx_msdu_first_msdu_flag function pointer. + */ + +static inline bool +htt_rx_msdu_first_msdu_flag_hl(htt_pdev_handle pdev, void *msdu_desc) +{ + return ((u_int8_t *)msdu_desc - sizeof(struct hl_htt_rx_ind_base)) + [HTT_ENDIAN_BYTE_IDX_SWAP(HTT_RX_IND_HL_FLAG_OFFSET)] & + HTT_RX_IND_HL_FLAG_FIRST_MSDU ? true : false; +} + +u_int16_t +htt_rx_msdu_rx_desc_size_hl( + htt_pdev_handle pdev, + void *msdu_desc + ) +{ + return ((u_int8_t *)(msdu_desc) - HTT_RX_IND_HL_BYTES) + [HTT_ENDIAN_BYTE_IDX_SWAP(HTT_RX_IND_HL_RX_DESC_LEN_OFFSET)]; +} + +/** + * htt_rx_mpdu_desc_retry_hl() - Returns the retry bit from the Rx descriptor + * for the High Latency driver + * @pdev: Handle (pointer) to HTT pdev. + * @mpdu_desc: Void pointer to the Rx descriptor for MPDU + * before the beginning of the payload. + * + * This function returns the retry bit of the 802.11 header for the + * provided rx MPDU descriptor. For the high latency driver, this function + * pretends as if the retry bit is never set so that the mcast duplicate + * detection never fails. + * + * Return: boolean -- false always for HL + */ +static inline bool +htt_rx_mpdu_desc_retry_hl(htt_pdev_handle pdev, void *mpdu_desc) +{ + return false; +} + +#ifdef CONFIG_HL_SUPPORT +static u_int16_t +htt_rx_mpdu_desc_seq_num_hl(htt_pdev_handle pdev, void *mpdu_desc) +{ + if (pdev->rx_desc_size_hl) { + return pdev->cur_seq_num_hl = + (u_int16_t)(HTT_WORD_GET(*(u_int32_t *)mpdu_desc, + HTT_HL_RX_DESC_MPDU_SEQ_NUM)); + } else { + return (u_int16_t)(pdev->cur_seq_num_hl); + } +} + +static void +htt_rx_mpdu_desc_pn_hl( + htt_pdev_handle pdev, + void *mpdu_desc, + union htt_rx_pn_t *pn, + int pn_len_bits) +{ + if (htt_rx_msdu_first_msdu_flag_hl(pdev, mpdu_desc) == true) { + /* Fix Me: only for little endian */ + struct hl_htt_rx_desc_base *rx_desc = + (struct hl_htt_rx_desc_base *)mpdu_desc; + u_int32_t *word_ptr = (u_int32_t *)pn->pn128; + + /* TODO: for Host of big endian */ + switch (pn_len_bits) { + case 128: + /* bits 128:64 */ + *(word_ptr + 3) = rx_desc->pn_127_96; + /* bits 63:0 */ + *(word_ptr + 2) = rx_desc->pn_95_64; + case 48: + /* bits 48:0 + * copy 64 bits + */ + *(word_ptr + 1) = rx_desc->u0.pn_63_32; + case 24: + /* bits 23:0 + * copy 32 bits + */ + *(word_ptr + 0) = rx_desc->pn_31_0; + break; + default: + qdf_print( + "Error: invalid length spec (%d bits) for PN\n", + pn_len_bits); + qdf_assert(0); + break; + }; + } else { + /* not first msdu, no pn info */ + qdf_print( + "Error: get pn from a not-first msdu.\n"); + qdf_assert(0); + } +} +#endif + +/** + * htt_rx_mpdu_desc_tid_hl() - Returns the TID value from the Rx descriptor + * for High Latency driver + * @pdev: Handle (pointer) to HTT pdev. + * @mpdu_desc: Void pointer to the Rx descriptor for the MPDU + * before the beginning of the payload. + * + * This function returns the TID set in the 802.11 QoS Control for the MPDU + * in the packet header, by looking at the mpdu_start of the Rx descriptor. + * Rx descriptor gets a copy of the TID from the MAC. + * For the HL driver, this is currently uimplemented and always returns + * an invalid tid. It is the responsibility of the caller to make + * sure that return value is checked for valid range. + * + * Return: Invalid TID value (0xff) for HL driver. + */ +static inline uint8_t +htt_rx_mpdu_desc_tid_hl(htt_pdev_handle pdev, void *mpdu_desc) +{ + return 0xff; /* Invalid TID */ +} + +static inline bool +htt_rx_msdu_desc_completes_mpdu_hl(htt_pdev_handle pdev, void *msdu_desc) +{ + return ( + ((u_int8_t *)(msdu_desc) - sizeof(struct hl_htt_rx_ind_base)) + [HTT_ENDIAN_BYTE_IDX_SWAP(HTT_RX_IND_HL_FLAG_OFFSET)] + & HTT_RX_IND_HL_FLAG_LAST_MSDU) + ? true : false; +} + +static inline int +htt_rx_msdu_has_wlan_mcast_flag_hl(htt_pdev_handle pdev, void *msdu_desc) +{ + /* currently, only first msdu has hl rx_desc */ + return htt_rx_msdu_first_msdu_flag_hl(pdev, msdu_desc) == true; +} + +static inline bool +htt_rx_msdu_is_wlan_mcast_hl(htt_pdev_handle pdev, void *msdu_desc) +{ + struct hl_htt_rx_desc_base *rx_desc = + (struct hl_htt_rx_desc_base *)msdu_desc; + + return + HTT_WORD_GET(*(u_int32_t *)rx_desc, HTT_HL_RX_DESC_MCAST_BCAST); +} + +static inline int +htt_rx_msdu_is_frag_hl(htt_pdev_handle pdev, void *msdu_desc) +{ + struct hl_htt_rx_desc_base *rx_desc = + (struct hl_htt_rx_desc_base *)msdu_desc; + + return + HTT_WORD_GET(*(u_int32_t *)rx_desc, HTT_HL_RX_DESC_MCAST_BCAST); +} + +#ifndef CONFIG_HL_SUPPORT +static bool +htt_rx_msdu_first_msdu_flag_ll(htt_pdev_handle pdev, void *msdu_desc) +{ + struct htt_host_rx_desc_base *rx_desc = + (struct htt_host_rx_desc_base *)msdu_desc; + return (bool) + (((*(((uint32_t *) &rx_desc->msdu_end) + 4)) & + RX_MSDU_END_4_FIRST_MSDU_MASK) >> + RX_MSDU_END_4_FIRST_MSDU_LSB); +} + +#define RX_PADDR_MAGIC_PATTERN 0xDEAD0000 +static qdf_dma_addr_t +htt_rx_paddr_mark_high_bits(qdf_dma_addr_t paddr) +{ +#ifdef ENABLE_DEBUG_ADDRESS_MARKING + if (sizeof(qdf_dma_addr_t) > 4) { + /* clear high bits, leave lower 37 bits (paddr) */ + paddr &= 0x01FFFFFFFFF; + /* mark upper 16 bits of paddr */ + paddr |= (((uint64_t)RX_PADDR_MAGIC_PATTERN) << 32); + } +#endif + return paddr; +} + +#ifdef HTT_PADDR64 +static inline qdf_dma_addr_t htt_paddr_trim_to_37(qdf_dma_addr_t paddr) +{ + qdf_dma_addr_t ret = paddr; + + if (sizeof(paddr) > 4) + ret &= 0x1fffffffff; + return ret; +} +#else /* not 64 bits */ +static inline qdf_dma_addr_t htt_paddr_trim_to_37(qdf_dma_addr_t paddr) +{ + return paddr; +} +#endif /* HTT_PADDR64 */ + +#ifdef ENABLE_DEBUG_ADDRESS_MARKING +static qdf_dma_addr_t +htt_rx_paddr_unmark_high_bits(qdf_dma_addr_t paddr) +{ + uint32_t markings; + + if (sizeof(qdf_dma_addr_t) > 4) { + markings = (uint32_t)((paddr >> 16) >> 16); + /* + * check if it is marked correctly: + * See the mark_high_bits function above for the expected + * pattern. + * the LS 5 bits are the high bits of physical address + * padded (with 0b0) to 8 bits + */ + if ((markings & 0xFFFF0000) != RX_PADDR_MAGIC_PATTERN) { + qdf_print("%s: paddr not marked correctly: 0x%p!\n", + __func__, (void *)paddr); + HTT_ASSERT_ALWAYS(0); + } + + /* clear markings for further use */ + paddr = htt_paddr_trim_to_37(paddr); + } + return paddr; +} + +static qdf_dma_addr_t +htt_rx_in_ord_paddr_get(uint32_t *u32p) +{ + qdf_dma_addr_t paddr = 0; + + paddr = (qdf_dma_addr_t)HTT_RX_IN_ORD_PADDR_IND_PADDR_GET(*u32p); + if (sizeof(qdf_dma_addr_t) > 4) { + u32p++; + /* 32 bit architectures dont like <<32 */ + paddr |= (((qdf_dma_addr_t) + HTT_RX_IN_ORD_PADDR_IND_PADDR_GET(*u32p)) + << 16 << 16); + } + paddr = htt_rx_paddr_unmark_high_bits(paddr); + + return paddr; +} +#else +static inline qdf_dma_addr_t +htt_rx_in_ord_paddr_get(uint32_t *u32p) +{ + return HTT_RX_IN_ORD_PADDR_IND_PADDR_GET(*u32p); +} +#endif /* ENABLE_DEBUG_ADDRESS_MARKING */ + +/* full_reorder_offload case: this function is called with lock held */ +static int htt_rx_ring_fill_n(struct htt_pdev_t *pdev, int num) +{ + int idx; + QDF_STATUS status; + struct htt_host_rx_desc_base *rx_desc; + int filled = 0; + int debt_served = 0; + + idx = *(pdev->rx_ring.alloc_idx.vaddr); + +moretofill: + while (num > 0) { + qdf_dma_addr_t paddr; + qdf_nbuf_t rx_netbuf; + int headroom; + + rx_netbuf = + qdf_nbuf_alloc(pdev->osdev, HTT_RX_BUF_SIZE, + 0, 4, false); + if (!rx_netbuf) { + qdf_timer_stop(&pdev->rx_ring. + refill_retry_timer); + /* + * Failed to fill it to the desired level - + * we'll start a timer and try again next time. + * As long as enough buffers are left in the ring for + * another A-MPDU rx, no special recovery is needed. + */ +#ifdef DEBUG_DMA_DONE + pdev->rx_ring.dbg_refill_cnt++; +#endif + pdev->refill_retry_timer_starts++; + qdf_timer_start( + &pdev->rx_ring.refill_retry_timer, + HTT_RX_RING_REFILL_RETRY_TIME_MS); + goto fail; + } + + /* Clear rx_desc attention word before posting to Rx ring */ + rx_desc = htt_rx_desc(rx_netbuf); + *(uint32_t *) &rx_desc->attention = 0; + +#ifdef DEBUG_DMA_DONE + *(uint32_t *) &rx_desc->msdu_end = 1; + +#define MAGIC_PATTERN 0xDEADBEEF + *(uint32_t *) &rx_desc->msdu_start = MAGIC_PATTERN; + + /* To ensure that attention bit is reset and msdu_end is set + before calling dma_map */ + smp_mb(); +#endif + /* + * Adjust qdf_nbuf_data to point to the location in the buffer + * where the rx descriptor will be filled in. + */ + headroom = qdf_nbuf_data(rx_netbuf) - (uint8_t *) rx_desc; + qdf_nbuf_push_head(rx_netbuf, headroom); + +#ifdef DEBUG_DMA_DONE + status = + qdf_nbuf_map(pdev->osdev, rx_netbuf, + QDF_DMA_BIDIRECTIONAL); +#else + status = + qdf_nbuf_map(pdev->osdev, rx_netbuf, + QDF_DMA_FROM_DEVICE); +#endif + if (status != QDF_STATUS_SUCCESS) { + qdf_nbuf_free(rx_netbuf); + goto fail; + } + paddr = qdf_nbuf_get_frag_paddr(rx_netbuf, 0); + paddr = htt_rx_paddr_mark_high_bits(paddr); + if (pdev->cfg.is_full_reorder_offload) { + if (qdf_unlikely(htt_rx_hash_list_insert( + pdev, paddr, rx_netbuf))) { + qdf_print("%s: hash insert failed!\n", + __func__); +#ifdef DEBUG_DMA_DONE + qdf_nbuf_unmap(pdev->osdev, rx_netbuf, + QDF_DMA_BIDIRECTIONAL); +#else + qdf_nbuf_unmap(pdev->osdev, rx_netbuf, + QDF_DMA_FROM_DEVICE); +#endif + qdf_nbuf_free(rx_netbuf); + goto fail; + } + htt_rx_dbg_rxbuf_set(pdev, paddr, rx_netbuf); + } else { + pdev->rx_ring.buf.netbufs_ring[idx] = rx_netbuf; + } + pdev->rx_ring.buf.paddrs_ring[idx] = paddr; + pdev->rx_ring.fill_cnt++; + + num--; + idx++; + filled++; + idx &= pdev->rx_ring.size_mask; + } + if (debt_served < qdf_atomic_read(&pdev->rx_ring.refill_debt)) { + num = qdf_atomic_read(&pdev->rx_ring.refill_debt); + debt_served += num; + goto moretofill; + } + +fail: + *(pdev->rx_ring.alloc_idx.vaddr) = idx; + htt_rx_dbg_rxbuf_indupd(pdev, idx); + + return filled; +} + +static int htt_rx_ring_size(struct htt_pdev_t *pdev) +{ + int size; + + /* + * It is expected that the host CPU will typically be able to service + * the rx indication from one A-MPDU before the rx indication from + * the subsequent A-MPDU happens, roughly 1-2 ms later. + * However, the rx ring should be sized very conservatively, to + * accommodate the worst reasonable delay before the host CPU services + * a rx indication interrupt. + * The rx ring need not be kept full of empty buffers. In theory, + * the htt host SW can dynamically track the low-water mark in the + * rx ring, and dynamically adjust the level to which the rx ring + * is filled with empty buffers, to dynamically meet the desired + * low-water mark. + * In contrast, it's difficult to resize the rx ring itself, once + * it's in use. + * Thus, the ring itself should be sized very conservatively, while + * the degree to which the ring is filled with empty buffers should + * be sized moderately conservatively. + */ + size = + ol_cfg_max_thruput_mbps(pdev->ctrl_pdev) * + 1000 /* 1e6 bps/mbps / 1e3 ms per sec = 1000 */ / + (8 * HTT_RX_AVG_FRM_BYTES) * HTT_RX_HOST_LATENCY_MAX_MS; + + if (size < HTT_RX_RING_SIZE_MIN) + size = HTT_RX_RING_SIZE_MIN; + else if (size > HTT_RX_RING_SIZE_MAX) + size = HTT_RX_RING_SIZE_MAX; + + size = qdf_get_pwr2(size); + return size; +} + +static int htt_rx_ring_fill_level(struct htt_pdev_t *pdev) +{ + int size; + + size = ol_cfg_max_thruput_mbps(pdev->ctrl_pdev) * + 1000 /* 1e6 bps/mbps / 1e3 ms per sec = 1000 */ / + (8 * HTT_RX_AVG_FRM_BYTES) * + HTT_RX_HOST_LATENCY_WORST_LIKELY_MS; + + size = qdf_get_pwr2(size); + /* + * Make sure the fill level is at least 1 less than the ring size. + * Leaving 1 element empty allows the SW to easily distinguish + * between a full ring vs. an empty ring. + */ + if (size >= pdev->rx_ring.size) + size = pdev->rx_ring.size - 1; + + return size; +} + +static void htt_rx_ring_refill_retry(void *arg) +{ + htt_pdev_handle pdev = (htt_pdev_handle) arg; + int filled = 0; + int num; + + pdev->refill_retry_timer_calls++; + qdf_spin_lock_bh(&(pdev->rx_ring.refill_lock)); + + num = qdf_atomic_read(&pdev->rx_ring.refill_debt); + qdf_atomic_sub(num, &pdev->rx_ring.refill_debt); + filled = htt_rx_ring_fill_n(pdev, num); + + qdf_spin_unlock_bh(&(pdev->rx_ring.refill_lock)); + + if (filled > num) { + /* we served ourselves and some other debt */ + /* sub is safer than = 0 */ + qdf_atomic_sub(filled - num, &pdev->rx_ring.refill_debt); + } else if (num == filled) { /* nothing to be done */ + } else { + /* we could not fill all, timer must have been started */ + pdev->refill_retry_timer_doubles++; + } + +} +#endif + +static inline unsigned htt_rx_ring_elems(struct htt_pdev_t *pdev) +{ + return + (*pdev->rx_ring.alloc_idx.vaddr - + pdev->rx_ring.sw_rd_idx.msdu_payld) & pdev->rx_ring.size_mask; +} + +static inline unsigned int htt_rx_in_order_ring_elems(struct htt_pdev_t *pdev) +{ + return + (*pdev->rx_ring.alloc_idx.vaddr - + *pdev->rx_ring.target_idx.vaddr) & + pdev->rx_ring.size_mask; +} + +#ifndef CONFIG_HL_SUPPORT + +void htt_rx_detach(struct htt_pdev_t *pdev) +{ + qdf_timer_stop(&pdev->rx_ring.refill_retry_timer); + qdf_timer_free(&pdev->rx_ring.refill_retry_timer); + + if (pdev->cfg.is_full_reorder_offload) { + qdf_mem_free_consistent(pdev->osdev, pdev->osdev->dev, + sizeof(uint32_t), + pdev->rx_ring.target_idx.vaddr, + pdev->rx_ring.target_idx.paddr, + qdf_get_dma_mem_context((&pdev-> + rx_ring. + target_idx), + memctx)); + htt_rx_hash_deinit(pdev); + } else { + int sw_rd_idx = pdev->rx_ring.sw_rd_idx.msdu_payld; + + while (sw_rd_idx != *(pdev->rx_ring.alloc_idx.vaddr)) { +#ifdef DEBUG_DMA_DONE + qdf_nbuf_unmap(pdev->osdev, + pdev->rx_ring.buf. + netbufs_ring[sw_rd_idx], + QDF_DMA_BIDIRECTIONAL); +#else + qdf_nbuf_unmap(pdev->osdev, + pdev->rx_ring.buf. + netbufs_ring[sw_rd_idx], + QDF_DMA_FROM_DEVICE); +#endif + qdf_nbuf_free(pdev->rx_ring.buf. + netbufs_ring[sw_rd_idx]); + sw_rd_idx++; + sw_rd_idx &= pdev->rx_ring.size_mask; + } + qdf_mem_free(pdev->rx_ring.buf.netbufs_ring); + } + + qdf_mem_free_consistent(pdev->osdev, pdev->osdev->dev, + sizeof(uint32_t), + pdev->rx_ring.alloc_idx.vaddr, + pdev->rx_ring.alloc_idx.paddr, + qdf_get_dma_mem_context((&pdev->rx_ring. + alloc_idx), + memctx)); + + qdf_mem_free_consistent(pdev->osdev, pdev->osdev->dev, + pdev->rx_ring.size * sizeof(qdf_dma_addr_t), + pdev->rx_ring.buf.paddrs_ring, + pdev->rx_ring.base_paddr, + qdf_get_dma_mem_context((&pdev->rx_ring.buf), + memctx)); + + /* destroy the rx-parallelization refill spinlock */ + qdf_spinlock_destroy(&(pdev->rx_ring.refill_lock)); +} + +/*--- rx descriptor field access functions ----------------------------------*/ +/* + * These functions need to use bit masks and shifts to extract fields + * from the rx descriptors, rather than directly using the bitfields. + * For example, use + * (desc & FIELD_MASK) >> FIELD_LSB + * rather than + * desc.field + * This allows the functions to work correctly on either little-endian + * machines (no endianness conversion needed) or big-endian machines + * (endianness conversion provided automatically by the HW DMA's + * byte-swizzling). + */ +/* FIX THIS: APPLIES TO LL ONLY */ + +/** + * htt_rx_mpdu_desc_retry_ll() - Returns the retry bit from the Rx descriptor + * for the Low Latency driver + * @pdev: Handle (pointer) to HTT pdev. + * @mpdu_desc: Void pointer to the Rx descriptor for MPDU + * before the beginning of the payload. + * + * This function returns the retry bit of the 802.11 header for the + * provided rx MPDU descriptor. + * + * Return: boolean -- true if retry is set, false otherwise + */ +static bool +htt_rx_mpdu_desc_retry_ll(htt_pdev_handle pdev, void *mpdu_desc) +{ + struct htt_host_rx_desc_base *rx_desc = + (struct htt_host_rx_desc_base *) mpdu_desc; + + return + (bool)(((*((uint32_t *) &rx_desc->mpdu_start)) & + RX_MPDU_START_0_RETRY_MASK) >> + RX_MPDU_START_0_RETRY_LSB); +} + +static uint16_t htt_rx_mpdu_desc_seq_num_ll(htt_pdev_handle pdev, + void *mpdu_desc) +{ + struct htt_host_rx_desc_base *rx_desc = + (struct htt_host_rx_desc_base *)mpdu_desc; + + return + (uint16_t) (((*((uint32_t *) &rx_desc->mpdu_start)) & + RX_MPDU_START_0_SEQ_NUM_MASK) >> + RX_MPDU_START_0_SEQ_NUM_LSB); +} + +/* FIX THIS: APPLIES TO LL ONLY */ +static void +htt_rx_mpdu_desc_pn_ll(htt_pdev_handle pdev, + void *mpdu_desc, union htt_rx_pn_t *pn, int pn_len_bits) +{ + struct htt_host_rx_desc_base *rx_desc = + (struct htt_host_rx_desc_base *)mpdu_desc; + + switch (pn_len_bits) { + case 24: + /* bits 23:0 */ + pn->pn24 = rx_desc->mpdu_start.pn_31_0 & 0xffffff; + break; + case 48: + /* bits 31:0 */ + pn->pn48 = rx_desc->mpdu_start.pn_31_0; + /* bits 47:32 */ + pn->pn48 |= ((uint64_t) + ((*(((uint32_t *) &rx_desc->mpdu_start) + 2)) + & RX_MPDU_START_2_PN_47_32_MASK)) + << (32 - RX_MPDU_START_2_PN_47_32_LSB); + break; + case 128: + /* bits 31:0 */ + pn->pn128[0] = rx_desc->mpdu_start.pn_31_0; + /* bits 47:32 */ + pn->pn128[0] |= + ((uint64_t) ((*(((uint32_t *)&rx_desc->mpdu_start) + 2)) + & RX_MPDU_START_2_PN_47_32_MASK)) + << (32 - RX_MPDU_START_2_PN_47_32_LSB); + /* bits 63:48 */ + pn->pn128[0] |= + ((uint64_t) ((*(((uint32_t *) &rx_desc->msdu_end) + 2)) + & RX_MSDU_END_1_EXT_WAPI_PN_63_48_MASK)) + << (48 - RX_MSDU_END_1_EXT_WAPI_PN_63_48_LSB); + /* bits 95:64 */ + pn->pn128[1] = rx_desc->msdu_end.ext_wapi_pn_95_64; + /* bits 127:96 */ + pn->pn128[1] |= + ((uint64_t) rx_desc->msdu_end.ext_wapi_pn_127_96) << 32; + break; + default: + qdf_print("Error: invalid length spec (%d bits) for PN\n", + pn_len_bits); + }; +} + +/** + * htt_rx_mpdu_desc_tid_ll() - Returns the TID value from the Rx descriptor + * for Low Latency driver + * @pdev: Handle (pointer) to HTT pdev. + * @mpdu_desc: Void pointer to the Rx descriptor for the MPDU + * before the beginning of the payload. + * + * This function returns the TID set in the 802.11 QoS Control for the MPDU + * in the packet header, by looking at the mpdu_start of the Rx descriptor. + * Rx descriptor gets a copy of the TID from the MAC. + * + * Return: Actual TID set in the packet header. + */ +static uint8_t +htt_rx_mpdu_desc_tid_ll(htt_pdev_handle pdev, void *mpdu_desc) +{ + struct htt_host_rx_desc_base *rx_desc = + (struct htt_host_rx_desc_base *) mpdu_desc; + + return + (uint8_t)(((*(((uint32_t *) &rx_desc->mpdu_start) + 2)) & + RX_MPDU_START_2_TID_MASK) >> + RX_MPDU_START_2_TID_LSB); +} + +/* FIX THIS: APPLIES TO LL ONLY */ +static bool htt_rx_msdu_desc_completes_mpdu_ll(htt_pdev_handle pdev, + void *msdu_desc) +{ + struct htt_host_rx_desc_base *rx_desc = + (struct htt_host_rx_desc_base *)msdu_desc; + return (bool) + (((*(((uint32_t *) &rx_desc->msdu_end) + 4)) & + RX_MSDU_END_4_LAST_MSDU_MASK) >> RX_MSDU_END_4_LAST_MSDU_LSB); +} + +/* FIX THIS: APPLIES TO LL ONLY */ +static int htt_rx_msdu_has_wlan_mcast_flag_ll(htt_pdev_handle pdev, + void *msdu_desc) +{ + struct htt_host_rx_desc_base *rx_desc = + (struct htt_host_rx_desc_base *)msdu_desc; + /* HW rx desc: the mcast_bcast flag is only valid + if first_msdu is set */ + return + ((*(((uint32_t *) &rx_desc->msdu_end) + 4)) & + RX_MSDU_END_4_FIRST_MSDU_MASK) >> RX_MSDU_END_4_FIRST_MSDU_LSB; +} + +/* FIX THIS: APPLIES TO LL ONLY */ +static bool htt_rx_msdu_is_wlan_mcast_ll(htt_pdev_handle pdev, void *msdu_desc) +{ + struct htt_host_rx_desc_base *rx_desc = + (struct htt_host_rx_desc_base *)msdu_desc; + return + ((*((uint32_t *) &rx_desc->attention)) & + RX_ATTENTION_0_MCAST_BCAST_MASK) + >> RX_ATTENTION_0_MCAST_BCAST_LSB; +} + +/* FIX THIS: APPLIES TO LL ONLY */ +static int htt_rx_msdu_is_frag_ll(htt_pdev_handle pdev, void *msdu_desc) +{ + struct htt_host_rx_desc_base *rx_desc = + (struct htt_host_rx_desc_base *)msdu_desc; + return + ((*((uint32_t *) &rx_desc->attention)) & + RX_ATTENTION_0_FRAGMENT_MASK) >> RX_ATTENTION_0_FRAGMENT_LSB; +} +#endif + +uint32_t htt_rx_mpdu_desc_tsf32(htt_pdev_handle pdev, void *mpdu_desc) +{ +/* FIX THIS */ + return 0; +} + +/* FIX THIS: APPLIES TO LL ONLY */ +char *htt_rx_mpdu_wifi_hdr_retrieve(htt_pdev_handle pdev, void *mpdu_desc) +{ + struct htt_host_rx_desc_base *rx_desc = + (struct htt_host_rx_desc_base *)mpdu_desc; + return rx_desc->rx_hdr_status; +} + +static inline +uint8_t htt_rx_msdu_fw_desc_get(htt_pdev_handle pdev, void *msdu_desc) +{ + /* + * HL and LL use the same format for FW rx desc, but have the FW rx desc + * in different locations. + * In LL, the FW rx descriptor has been copied into the same + * htt_host_rx_desc_base struct that holds the HW rx desc. + * In HL, the FW rx descriptor, along with the MSDU payload, + * is in the same buffer as the rx indication message. + * + * Use the FW rx desc offset configured during startup to account for + * this difference between HL vs. LL. + * + * An optimization would be to define the LL and HL msdu_desc pointer + * in such a way that they both use the same offset to the FW rx desc. + * Then the following functions could be converted to macros, without + * needing to expose the htt_pdev_t definition outside HTT. + */ + return *(((uint8_t *) msdu_desc) + pdev->rx_fw_desc_offset); +} + +int htt_rx_msdu_discard(htt_pdev_handle pdev, void *msdu_desc) +{ + return htt_rx_msdu_fw_desc_get(pdev, msdu_desc) & FW_RX_DESC_DISCARD_M; +} + +int htt_rx_msdu_forward(htt_pdev_handle pdev, void *msdu_desc) +{ + return htt_rx_msdu_fw_desc_get(pdev, msdu_desc) & FW_RX_DESC_FORWARD_M; +} + +int htt_rx_msdu_inspect(htt_pdev_handle pdev, void *msdu_desc) +{ + return htt_rx_msdu_fw_desc_get(pdev, msdu_desc) & FW_RX_DESC_INSPECT_M; +} + +void +htt_rx_msdu_actions(htt_pdev_handle pdev, + void *msdu_desc, int *discard, int *forward, int *inspect) +{ + uint8_t rx_msdu_fw_desc = htt_rx_msdu_fw_desc_get(pdev, msdu_desc); +#ifdef HTT_DEBUG_DATA + HTT_PRINT("act:0x%x ", rx_msdu_fw_desc); +#endif + *discard = rx_msdu_fw_desc & FW_RX_DESC_DISCARD_M; + *forward = rx_msdu_fw_desc & FW_RX_DESC_FORWARD_M; + *inspect = rx_msdu_fw_desc & FW_RX_DESC_INSPECT_M; +} + +static inline qdf_nbuf_t htt_rx_netbuf_pop(htt_pdev_handle pdev) +{ + int idx; + qdf_nbuf_t msdu; + + HTT_ASSERT1(htt_rx_ring_elems(pdev) != 0); + +#ifdef DEBUG_DMA_DONE + pdev->rx_ring.dbg_ring_idx++; + pdev->rx_ring.dbg_ring_idx &= pdev->rx_ring.size_mask; +#endif + + idx = pdev->rx_ring.sw_rd_idx.msdu_payld; + msdu = pdev->rx_ring.buf.netbufs_ring[idx]; + idx++; + idx &= pdev->rx_ring.size_mask; + pdev->rx_ring.sw_rd_idx.msdu_payld = idx; + pdev->rx_ring.fill_cnt--; + return msdu; +} + +static inline qdf_nbuf_t +htt_rx_in_order_netbuf_pop(htt_pdev_handle pdev, qdf_dma_addr_t paddr) +{ + HTT_ASSERT1(htt_rx_in_order_ring_elems(pdev) != 0); + pdev->rx_ring.fill_cnt--; + paddr = htt_paddr_trim_to_37(paddr); + return htt_rx_hash_list_lookup(pdev, paddr); +} + +/* FIX ME: this function applies only to LL rx descs. + An equivalent for HL rx descs is needed. */ +#ifdef CHECKSUM_OFFLOAD +static inline +void +htt_set_checksum_result_ll(htt_pdev_handle pdev, qdf_nbuf_t msdu, + struct htt_host_rx_desc_base *rx_desc) +{ +#define MAX_IP_VER 2 +#define MAX_PROTO_VAL 4 + struct rx_msdu_start *rx_msdu = &rx_desc->msdu_start; + unsigned int proto = (rx_msdu->tcp_proto) | (rx_msdu->udp_proto << 1); + + /* + * HW supports TCP & UDP checksum offload for ipv4 and ipv6 + */ + static const qdf_nbuf_l4_rx_cksum_type_t + cksum_table[][MAX_PROTO_VAL][MAX_IP_VER] = { + { + /* non-fragmented IP packet */ + /* non TCP/UDP packet */ + {QDF_NBUF_RX_CKSUM_NONE, QDF_NBUF_RX_CKSUM_NONE}, + /* TCP packet */ + {QDF_NBUF_RX_CKSUM_TCP, QDF_NBUF_RX_CKSUM_TCPIPV6}, + /* UDP packet */ + {QDF_NBUF_RX_CKSUM_UDP, QDF_NBUF_RX_CKSUM_UDPIPV6}, + /* invalid packet type */ + {QDF_NBUF_RX_CKSUM_NONE, QDF_NBUF_RX_CKSUM_NONE}, + }, + { + /* fragmented IP packet */ + {QDF_NBUF_RX_CKSUM_NONE, QDF_NBUF_RX_CKSUM_NONE}, + {QDF_NBUF_RX_CKSUM_NONE, QDF_NBUF_RX_CKSUM_NONE}, + {QDF_NBUF_RX_CKSUM_NONE, QDF_NBUF_RX_CKSUM_NONE}, + {QDF_NBUF_RX_CKSUM_NONE, QDF_NBUF_RX_CKSUM_NONE}, + } + }; + + qdf_nbuf_rx_cksum_t cksum = { + cksum_table[rx_msdu->ip_frag][proto][rx_msdu->ipv6_proto], + QDF_NBUF_RX_CKSUM_NONE, + 0 + }; + + if (cksum.l4_type != + (qdf_nbuf_l4_rx_cksum_type_t) QDF_NBUF_RX_CKSUM_NONE) { + cksum.l4_result = + ((*(uint32_t *) &rx_desc->attention) & + RX_ATTENTION_0_TCP_UDP_CHKSUM_FAIL_MASK) ? + QDF_NBUF_RX_CKSUM_NONE : + QDF_NBUF_RX_CKSUM_TCP_UDP_UNNECESSARY; + } + qdf_nbuf_set_rx_cksum(msdu, &cksum); +#undef MAX_IP_VER +#undef MAX_PROTO_VAL +} + +#if defined(CONFIG_HL_SUPPORT) + +static void +htt_set_checksum_result_hl(qdf_nbuf_t msdu, + struct htt_host_rx_desc_base *rx_desc) +{ + u_int8_t flag = ((u_int8_t *)rx_desc - + sizeof(struct hl_htt_rx_ind_base))[ + HTT_ENDIAN_BYTE_IDX_SWAP( + HTT_RX_IND_HL_FLAG_OFFSET)]; + + int is_ipv6 = flag & HTT_RX_IND_HL_FLAG_IPV6 ? 1 : 0; + int is_tcp = flag & HTT_RX_IND_HL_FLAG_TCP ? 1 : 0; + int is_udp = flag & HTT_RX_IND_HL_FLAG_UDP ? 1 : 0; + + qdf_nbuf_rx_cksum_t cksum = { + QDF_NBUF_RX_CKSUM_NONE, + QDF_NBUF_RX_CKSUM_NONE, + 0 + }; + + switch ((is_udp << 2) | (is_tcp << 1) | (is_ipv6 << 0)) { + case 0x4: + cksum.l4_type = QDF_NBUF_RX_CKSUM_UDP; + break; + case 0x2: + cksum.l4_type = QDF_NBUF_RX_CKSUM_TCP; + break; + case 0x5: + cksum.l4_type = QDF_NBUF_RX_CKSUM_UDPIPV6; + break; + case 0x3: + cksum.l4_type = QDF_NBUF_RX_CKSUM_TCPIPV6; + break; + default: + cksum.l4_type = QDF_NBUF_RX_CKSUM_NONE; + break; + } + if (cksum.l4_type != (qdf_nbuf_l4_rx_cksum_type_t) + QDF_NBUF_RX_CKSUM_NONE) { + cksum.l4_result = flag & HTT_RX_IND_HL_FLAG_C4_FAILED ? + QDF_NBUF_RX_CKSUM_NONE : + QDF_NBUF_RX_CKSUM_TCP_UDP_UNNECESSARY; + } + qdf_nbuf_set_rx_cksum(msdu, &cksum); +} +#endif + +#else + +static inline +void htt_set_checksum_result_ll(htt_pdev_handle pdev, qdf_nbuf_t msdu, + struct htt_host_rx_desc_base *rx_desc) +{ + return; +} + +#if defined(CONFIG_HL_SUPPORT) + +static inline +void htt_set_checksum_result_hl(qdf_nbuf_t msdu, + struct htt_host_rx_desc_base *rx_desc) +{ + return; +} +#endif + +#endif + +#ifdef DEBUG_DMA_DONE +#define MAX_DONE_BIT_CHECK_ITER 5 +#endif + +#ifndef CONFIG_HL_SUPPORT +static int +htt_rx_amsdu_pop_ll(htt_pdev_handle pdev, + qdf_nbuf_t rx_ind_msg, + qdf_nbuf_t *head_msdu, qdf_nbuf_t *tail_msdu, + uint32_t *msdu_count) +{ + int msdu_len, msdu_chaining = 0; + qdf_nbuf_t msdu; + struct htt_host_rx_desc_base *rx_desc; + uint8_t *rx_ind_data; + uint32_t *msg_word, num_msdu_bytes; + enum htt_t2h_msg_type msg_type; + uint8_t pad_bytes = 0; + + HTT_ASSERT1(htt_rx_ring_elems(pdev) != 0); + rx_ind_data = qdf_nbuf_data(rx_ind_msg); + msg_word = (uint32_t *) rx_ind_data; + + msg_type = HTT_T2H_MSG_TYPE_GET(*msg_word); + + if (qdf_unlikely(HTT_T2H_MSG_TYPE_RX_FRAG_IND == msg_type)) { + num_msdu_bytes = HTT_RX_FRAG_IND_FW_RX_DESC_BYTES_GET( + *(msg_word + HTT_RX_FRAG_IND_HDR_PREFIX_SIZE32)); + } else { + num_msdu_bytes = HTT_RX_IND_FW_RX_DESC_BYTES_GET( + *(msg_word + + HTT_RX_IND_HDR_PREFIX_SIZE32 + + HTT_RX_PPDU_DESC_SIZE32)); + } + msdu = *head_msdu = htt_rx_netbuf_pop(pdev); + while (1) { + int last_msdu, msdu_len_invalid, msdu_chained; + int byte_offset; + + /* + * Set the netbuf length to be the entire buffer length + * initially, so the unmap will unmap the entire buffer. + */ + qdf_nbuf_set_pktlen(msdu, HTT_RX_BUF_SIZE); +#ifdef DEBUG_DMA_DONE + qdf_nbuf_unmap(pdev->osdev, msdu, QDF_DMA_BIDIRECTIONAL); +#else + qdf_nbuf_unmap(pdev->osdev, msdu, QDF_DMA_FROM_DEVICE); +#endif + + /* cache consistency has been taken care of by qdf_nbuf_unmap */ + + /* + * Now read the rx descriptor. + * Set the length to the appropriate value. + * Check if this MSDU completes a MPDU. + */ + rx_desc = htt_rx_desc(msdu); +#if defined(HELIUMPLUS) + if (HTT_WIFI_IP(pdev, 2, 0)) + pad_bytes = rx_desc->msdu_end.l3_header_padding; +#endif /* defined(HELIUMPLUS) */ + /* + * Make the netbuf's data pointer point to the payload rather + * than the descriptor. + */ + + qdf_nbuf_pull_head(msdu, + HTT_RX_STD_DESC_RESERVATION + pad_bytes); + + /* + * Sanity check - confirm the HW is finished filling in + * the rx data. + * If the HW and SW are working correctly, then it's guaranteed + * that the HW's MAC DMA is done before this point in the SW. + * To prevent the case that we handle a stale Rx descriptor, + * just assert for now until we have a way to recover. + */ + +#ifdef DEBUG_DMA_DONE + if (qdf_unlikely(!((*(uint32_t *) &rx_desc->attention) + & RX_ATTENTION_0_MSDU_DONE_MASK))) { + + int dbg_iter = MAX_DONE_BIT_CHECK_ITER; + + qdf_print("malformed frame\n"); + + while (dbg_iter && + (!((*(uint32_t *) &rx_desc->attention) & + RX_ATTENTION_0_MSDU_DONE_MASK))) { + qdf_mdelay(1); + + qdf_invalidate_range((void *)rx_desc, + (void *)((char *)rx_desc + + HTT_RX_STD_DESC_RESERVATION)); + + qdf_print("debug iter %d success %d\n", + dbg_iter, + pdev->rx_ring.dbg_sync_success); + + dbg_iter--; + } + + if (qdf_unlikely(!((*(uint32_t *) &rx_desc->attention) + & RX_ATTENTION_0_MSDU_DONE_MASK))) { + +#ifdef HTT_RX_RESTORE + qdf_print("RX done bit error detected!\n"); + qdf_nbuf_set_next(msdu, NULL); + *tail_msdu = msdu; + pdev->rx_ring.rx_reset = 1; + return msdu_chaining; +#else + wma_cli_set_command(0, GEN_PARAM_CRASH_INJECT, + 0, GEN_CMD); + HTT_ASSERT_ALWAYS(0); +#endif + } + pdev->rx_ring.dbg_sync_success++; + qdf_print("debug iter %d success %d\n", dbg_iter, + pdev->rx_ring.dbg_sync_success); + } +#else + HTT_ASSERT_ALWAYS((*(uint32_t *) &rx_desc->attention) & + RX_ATTENTION_0_MSDU_DONE_MASK); +#endif + /* + * Copy the FW rx descriptor for this MSDU from the rx + * indication message into the MSDU's netbuf. + * HL uses the same rx indication message definition as LL, and + * simply appends new info (fields from the HW rx desc, and the + * MSDU payload itself). + * So, the offset into the rx indication message only has to + * account for the standard offset of the per-MSDU FW rx + * desc info within the message, and how many bytes of the + * per-MSDU FW rx desc info have already been consumed. + * (And the endianness of the host, + * since for a big-endian host, the rx ind message contents, + * including the per-MSDU rx desc bytes, were byteswapped during + * upload.) + */ + if (pdev->rx_ind_msdu_byte_idx < num_msdu_bytes) { + if (qdf_unlikely + (HTT_T2H_MSG_TYPE_RX_FRAG_IND == msg_type)) + byte_offset = + HTT_ENDIAN_BYTE_IDX_SWAP + (HTT_RX_FRAG_IND_FW_DESC_BYTE_OFFSET); + else + byte_offset = + HTT_ENDIAN_BYTE_IDX_SWAP + (HTT_RX_IND_FW_RX_DESC_BYTE_OFFSET + + pdev->rx_ind_msdu_byte_idx); + + *((uint8_t *) &rx_desc->fw_desc.u.val) = + rx_ind_data[byte_offset]; + /* + * The target is expected to only provide the basic + * per-MSDU rx descriptors. Just to be sure, + * verify that the target has not attached + * extension data (e.g. LRO flow ID). + */ + /* + * The assertion below currently doesn't work for + * RX_FRAG_IND messages, since their format differs + * from the RX_IND format (no FW rx PPDU desc in + * the current RX_FRAG_IND message). + * If the RX_FRAG_IND message format is updated to match + * the RX_IND message format, then the following + * assertion can be restored. + */ + /* qdf_assert((rx_ind_data[byte_offset] & + FW_RX_DESC_EXT_M) == 0); */ + pdev->rx_ind_msdu_byte_idx += 1; + /* or more, if there's ext data */ + } else { + /* + * When an oversized AMSDU happened, FW will lost some + * of MSDU status - in this case, the FW descriptors + * provided will be less than the actual MSDUs + * inside this MPDU. + * Mark the FW descriptors so that it will still + * deliver to upper stack, if no CRC error for the MPDU. + * + * FIX THIS - the FW descriptors are actually for MSDUs + * in the end of this A-MSDU instead of the beginning. + */ + *((uint8_t *) &rx_desc->fw_desc.u.val) = 0; + } + + /* + * TCP/UDP checksum offload support + */ + htt_set_checksum_result_ll(pdev, msdu, rx_desc); + + msdu_len_invalid = (*(uint32_t *) &rx_desc->attention) & + RX_ATTENTION_0_MPDU_LENGTH_ERR_MASK; + msdu_chained = (((*(uint32_t *) &rx_desc->frag_info) & + RX_FRAG_INFO_0_RING2_MORE_COUNT_MASK) >> + RX_FRAG_INFO_0_RING2_MORE_COUNT_LSB); + msdu_len = + ((*((uint32_t *) &rx_desc->msdu_start)) & + RX_MSDU_START_0_MSDU_LENGTH_MASK) >> + RX_MSDU_START_0_MSDU_LENGTH_LSB; + + do { + if (!msdu_len_invalid && !msdu_chained) { +#if defined(PEREGRINE_1_0_ZERO_LEN_PHY_ERR_WAR) + if (msdu_len > 0x3000) + break; +#endif + qdf_nbuf_trim_tail(msdu, + HTT_RX_BUF_SIZE - + (RX_STD_DESC_SIZE + + msdu_len)); + } + } while (0); + + while (msdu_chained--) { + qdf_nbuf_t next = htt_rx_netbuf_pop(pdev); + qdf_nbuf_set_pktlen(next, HTT_RX_BUF_SIZE); + msdu_len -= HTT_RX_BUF_SIZE; + qdf_nbuf_set_next(msdu, next); + msdu = next; + msdu_chaining = 1; + + if (msdu_chained == 0) { + /* Trim the last one to the correct size - + * accounting for inconsistent HW lengths + * causing length overflows and underflows + */ + if (((unsigned)msdu_len) > + ((unsigned) + (HTT_RX_BUF_SIZE - RX_STD_DESC_SIZE))) { + msdu_len = + (HTT_RX_BUF_SIZE - + RX_STD_DESC_SIZE); + } + + qdf_nbuf_trim_tail(next, + HTT_RX_BUF_SIZE - + (RX_STD_DESC_SIZE + + msdu_len)); + } + } + + last_msdu = + ((*(((uint32_t *) &rx_desc->msdu_end) + 4)) & + RX_MSDU_END_4_LAST_MSDU_MASK) >> + RX_MSDU_END_4_LAST_MSDU_LSB; + + if (last_msdu) { + qdf_nbuf_set_next(msdu, NULL); + break; + } else { + qdf_nbuf_t next = htt_rx_netbuf_pop(pdev); + qdf_nbuf_set_next(msdu, next); + msdu = next; + } + } + *tail_msdu = msdu; + + /* + * Don't refill the ring yet. + * First, the elements popped here are still in use - it is + * not safe to overwrite them until the matching call to + * mpdu_desc_list_next. + * Second, for efficiency it is preferable to refill the rx ring + * with 1 PPDU's worth of rx buffers (something like 32 x 3 buffers), + * rather than one MPDU's worth of rx buffers (sth like 3 buffers). + * Consequently, we'll rely on the txrx SW to tell us when it is done + * pulling all the PPDU's rx buffers out of the rx ring, and then + * refill it just once. + */ + return msdu_chaining; +} +#endif + +#if defined(CONFIG_HL_SUPPORT) + +static int +htt_rx_amsdu_pop_hl( + htt_pdev_handle pdev, + qdf_nbuf_t rx_ind_msg, + qdf_nbuf_t *head_msdu, + qdf_nbuf_t *tail_msdu, + uint32_t *msdu_count) +{ + pdev->rx_desc_size_hl = + (qdf_nbuf_data(rx_ind_msg)) + [HTT_ENDIAN_BYTE_IDX_SWAP( + HTT_RX_IND_HL_RX_DESC_LEN_OFFSET)]; + + /* point to the rx desc */ + qdf_nbuf_pull_head(rx_ind_msg, + sizeof(struct hl_htt_rx_ind_base)); + *head_msdu = *tail_msdu = rx_ind_msg; + + htt_set_checksum_result_hl(rx_ind_msg, + (struct htt_host_rx_desc_base *) + (qdf_nbuf_data(rx_ind_msg))); + + qdf_nbuf_set_next(*tail_msdu, NULL); + return 0; +} + +static int +htt_rx_frag_pop_hl( + htt_pdev_handle pdev, + qdf_nbuf_t frag_msg, + qdf_nbuf_t *head_msdu, + qdf_nbuf_t *tail_msdu, + uint32_t *msdu_count) +{ + qdf_nbuf_pull_head(frag_msg, HTT_RX_FRAG_IND_BYTES); + pdev->rx_desc_size_hl = + (qdf_nbuf_data(frag_msg)) + [HTT_ENDIAN_BYTE_IDX_SWAP( + HTT_RX_IND_HL_RX_DESC_LEN_OFFSET)]; + + /* point to the rx desc */ + qdf_nbuf_pull_head(frag_msg, + sizeof(struct hl_htt_rx_ind_base)); + *head_msdu = *tail_msdu = frag_msg; + + qdf_nbuf_set_next(*tail_msdu, NULL); + return 0; +} + +static inline int +htt_rx_offload_msdu_pop_hl(htt_pdev_handle pdev, + qdf_nbuf_t offload_deliver_msg, + int *vdev_id, + int *peer_id, + int *tid, + u_int8_t *fw_desc, + qdf_nbuf_t *head_buf, + qdf_nbuf_t *tail_buf) +{ + qdf_nbuf_t buf; + u_int32_t *msdu_hdr, msdu_len; + int ret = 0; + + *head_buf = *tail_buf = buf = offload_deliver_msg; + msdu_hdr = (u_int32_t *)qdf_nbuf_data(buf); + /* First dword */ + + /* Second dword */ + msdu_hdr++; + msdu_len = HTT_RX_OFFLOAD_DELIVER_IND_MSDU_LEN_GET(*msdu_hdr); + *peer_id = HTT_RX_OFFLOAD_DELIVER_IND_MSDU_PEER_ID_GET(*msdu_hdr); + + /* Third dword */ + msdu_hdr++; + *vdev_id = HTT_RX_OFFLOAD_DELIVER_IND_MSDU_VDEV_ID_GET(*msdu_hdr); + *tid = HTT_RX_OFFLOAD_DELIVER_IND_MSDU_TID_GET(*msdu_hdr); + *fw_desc = HTT_RX_OFFLOAD_DELIVER_IND_MSDU_DESC_GET(*msdu_hdr); + + qdf_nbuf_pull_head(buf, HTT_RX_OFFLOAD_DELIVER_IND_MSDU_HDR_BYTES \ + + HTT_RX_OFFLOAD_DELIVER_IND_HDR_BYTES); + + if (msdu_len <= qdf_nbuf_len(buf)) { + qdf_nbuf_set_pktlen(buf, msdu_len); + } else { + qdf_print("%s: drop frame with invalid msdu len %d %d\n", + __FUNCTION__, msdu_len, (int)qdf_nbuf_len(buf)); + qdf_nbuf_free(offload_deliver_msg); + ret = -1; + } + + return ret; +} +#endif + +#ifndef CONFIG_HL_SUPPORT +static int +htt_rx_offload_msdu_pop_ll(htt_pdev_handle pdev, + qdf_nbuf_t offload_deliver_msg, + int *vdev_id, + int *peer_id, + int *tid, + uint8_t *fw_desc, + qdf_nbuf_t *head_buf, qdf_nbuf_t *tail_buf) +{ + qdf_nbuf_t buf; + uint32_t *msdu_hdr, msdu_len; + + *head_buf = *tail_buf = buf = htt_rx_netbuf_pop(pdev); + /* Fake read mpdu_desc to keep desc ptr in sync */ + htt_rx_mpdu_desc_list_next(pdev, NULL); + qdf_nbuf_set_pktlen(buf, HTT_RX_BUF_SIZE); +#ifdef DEBUG_DMA_DONE + qdf_nbuf_unmap(pdev->osdev, buf, QDF_DMA_BIDIRECTIONAL); +#else + qdf_nbuf_unmap(pdev->osdev, buf, QDF_DMA_FROM_DEVICE); +#endif + msdu_hdr = (uint32_t *) qdf_nbuf_data(buf); + + /* First dword */ + msdu_len = HTT_RX_OFFLOAD_DELIVER_IND_MSDU_LEN_GET(*msdu_hdr); + *peer_id = HTT_RX_OFFLOAD_DELIVER_IND_MSDU_PEER_ID_GET(*msdu_hdr); + + /* Second dword */ + msdu_hdr++; + *vdev_id = HTT_RX_OFFLOAD_DELIVER_IND_MSDU_VDEV_ID_GET(*msdu_hdr); + *tid = HTT_RX_OFFLOAD_DELIVER_IND_MSDU_TID_GET(*msdu_hdr); + *fw_desc = HTT_RX_OFFLOAD_DELIVER_IND_MSDU_DESC_GET(*msdu_hdr); + + qdf_nbuf_pull_head(buf, HTT_RX_OFFLOAD_DELIVER_IND_MSDU_HDR_BYTES); + qdf_nbuf_set_pktlen(buf, msdu_len); + return 0; +} + +int +htt_rx_offload_paddr_msdu_pop_ll(htt_pdev_handle pdev, + uint32_t *msg_word, + int msdu_iter, + int *vdev_id, + int *peer_id, + int *tid, + uint8_t *fw_desc, + qdf_nbuf_t *head_buf, qdf_nbuf_t *tail_buf) +{ + qdf_nbuf_t buf; + uint32_t *msdu_hdr, msdu_len; + uint32_t *curr_msdu; + qdf_dma_addr_t paddr; + + curr_msdu = + msg_word + (msdu_iter * HTT_RX_IN_ORD_PADDR_IND_MSDU_DWORDS); + paddr = htt_rx_in_ord_paddr_get(curr_msdu); + *head_buf = *tail_buf = buf = htt_rx_in_order_netbuf_pop(pdev, paddr); + + if (qdf_unlikely(NULL == buf)) { + qdf_print("%s: netbuf pop failed!\n", __func__); + return 0; + } + qdf_nbuf_set_pktlen(buf, HTT_RX_BUF_SIZE); +#ifdef DEBUG_DMA_DONE + qdf_nbuf_unmap(pdev->osdev, buf, QDF_DMA_BIDIRECTIONAL); +#else + qdf_nbuf_unmap(pdev->osdev, buf, QDF_DMA_FROM_DEVICE); +#endif + + if (pdev->cfg.is_first_wakeup_packet) { + if (HTT_RX_IN_ORD_PADDR_IND_MSDU_INFO_GET(*(curr_msdu + 1)) & + FW_MSDU_INFO_FIRST_WAKEUP_M) { + qdf_nbuf_mark_wakeup_frame(buf); + qdf_print("%s: First packet after WOW Wakeup rcvd\n", + __func__); + } + } + + msdu_hdr = (uint32_t *) qdf_nbuf_data(buf); + + /* First dword */ + msdu_len = HTT_RX_OFFLOAD_DELIVER_IND_MSDU_LEN_GET(*msdu_hdr); + *peer_id = HTT_RX_OFFLOAD_DELIVER_IND_MSDU_PEER_ID_GET(*msdu_hdr); + + /* Second dword */ + msdu_hdr++; + *vdev_id = HTT_RX_OFFLOAD_DELIVER_IND_MSDU_VDEV_ID_GET(*msdu_hdr); + *tid = HTT_RX_OFFLOAD_DELIVER_IND_MSDU_TID_GET(*msdu_hdr); + *fw_desc = HTT_RX_OFFLOAD_DELIVER_IND_MSDU_DESC_GET(*msdu_hdr); + + qdf_nbuf_pull_head(buf, HTT_RX_OFFLOAD_DELIVER_IND_MSDU_HDR_BYTES); + qdf_nbuf_set_pktlen(buf, msdu_len); + return 0; +} +#endif + +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) +#if HTT_PADDR64 +#define NEXT_FIELD_OFFSET_IN32 2 +#else /* ! HTT_PADDR64 */ +#define NEXT_FIELD_OFFSET_IN32 1 +#endif /* HTT_PADDR64 */ + +#ifndef CONFIG_HL_SUPPORT +/** + * htt_mon_rx_handle_amsdu_packet() - Handle consecutive fragments of amsdu + * @msdu: pointer to first msdu of amsdu + * @pdev: Handle to htt_pdev_handle + * @msg_word: Input and output variable, so pointer to HTT msg pointer + * @amsdu_len: remaining length of all N-1 msdu msdu's + * @frag_cnt: number of frags handled + * + * This function handles the (N-1) msdu's of amsdu, N'th msdu is already + * handled by calling function. N-1 msdu's are tied using frags_list. + * msdu_info field updated by FW indicates if this is last msdu. All the + * msdu's before last msdu will be of MAX payload. + * + * Return: 1 on success and 0 on failure. + */ +static +int htt_mon_rx_handle_amsdu_packet(qdf_nbuf_t msdu, htt_pdev_handle pdev, + uint32_t **msg_word, uint32_t amsdu_len, + uint32_t *frag_cnt) +{ + qdf_nbuf_t frag_nbuf; + qdf_nbuf_t prev_frag_nbuf; + uint32_t len; + uint32_t last_frag; + qdf_dma_addr_t paddr; + + *msg_word += HTT_RX_IN_ORD_PADDR_IND_MSDU_DWORDS; + paddr = htt_rx_in_ord_paddr_get(*msg_word); + frag_nbuf = htt_rx_in_order_netbuf_pop(pdev, paddr); + if (qdf_unlikely(NULL == frag_nbuf)) { + qdf_print("%s: netbuf pop failed!\n", __func__); + return 0; + } + *frag_cnt = *frag_cnt + 1; + last_frag = ((struct htt_rx_in_ord_paddr_ind_msdu_t *)*msg_word)-> + msdu_info; + qdf_nbuf_append_ext_list(msdu, frag_nbuf, amsdu_len); + qdf_nbuf_set_pktlen(frag_nbuf, HTT_RX_BUF_SIZE); + qdf_nbuf_unmap(pdev->osdev, frag_nbuf, QDF_DMA_FROM_DEVICE); + /* For msdu's other than parent will not have htt_host_rx_desc_base */ + len = MIN(amsdu_len, HTT_RX_BUF_SIZE); + amsdu_len -= len; + qdf_nbuf_trim_tail(frag_nbuf, HTT_RX_BUF_SIZE - len); + + HTT_PKT_DUMP(qdf_trace_hex_dump(QDF_MODULE_ID_TXRX, + QDF_TRACE_LEVEL_FATAL, + qdf_nbuf_data(frag_nbuf), + qdf_nbuf_len(frag_nbuf))); + prev_frag_nbuf = frag_nbuf; + while (!last_frag) { + *msg_word += HTT_RX_IN_ORD_PADDR_IND_MSDU_DWORDS; + paddr = htt_rx_in_ord_paddr_get(*msg_word); + frag_nbuf = htt_rx_in_order_netbuf_pop(pdev, paddr); + last_frag = ((struct htt_rx_in_ord_paddr_ind_msdu_t *) + *msg_word)->msdu_info; + + if (qdf_unlikely(NULL == frag_nbuf)) { + qdf_print("%s: netbuf pop failed!\n", __func__); + prev_frag_nbuf->next = NULL; + return 0; + } + *frag_cnt = *frag_cnt + 1; + qdf_nbuf_set_pktlen(frag_nbuf, HTT_RX_BUF_SIZE); + qdf_nbuf_unmap(pdev->osdev, frag_nbuf, QDF_DMA_FROM_DEVICE); + + len = MIN(amsdu_len, HTT_RX_BUF_SIZE); + amsdu_len -= len; + qdf_nbuf_trim_tail(frag_nbuf, HTT_RX_BUF_SIZE - len); + HTT_PKT_DUMP(qdf_trace_hex_dump(QDF_MODULE_ID_TXRX, + QDF_TRACE_LEVEL_FATAL, + qdf_nbuf_data(frag_nbuf), + qdf_nbuf_len(frag_nbuf))); + + qdf_nbuf_set_next(prev_frag_nbuf, frag_nbuf); + prev_frag_nbuf = frag_nbuf; + } + qdf_nbuf_set_next(prev_frag_nbuf, NULL); + return 1; +} + +/** + * htt_mon_rx_get_phy_info() - Get rate interms of 500Kbps. + * @rx_desc: Pointer to struct htt_host_rx_desc_base + * @rx_status: Return variable updated with phy_info in rx_status + * + * If l_sig_rate_select is 0: + * 0x8: OFDM 48 Mbps + * 0x9: OFDM 24 Mbps + * 0xA: OFDM 12 Mbps + * 0xB: OFDM 6 Mbps + * 0xC: OFDM 54 Mbps + * 0xD: OFDM 36 Mbps + * 0xE: OFDM 18 Mbps + * 0xF: OFDM 9 Mbps + * If l_sig_rate_select is 1: + * 0x8: CCK 11 Mbps long preamble + * 0x9: CCK 5.5 Mbps long preamble + * 0xA: CCK 2 Mbps long preamble + * 0xB: CCK 1 Mbps long preamble + * 0xC: CCK 11 Mbps short preamble + * 0xD: CCK 5.5 Mbps short preamble + * 0xE: CCK 2 Mbps short preamble + * + * Return: None + */ +static void htt_mon_rx_get_phy_info(struct htt_host_rx_desc_base *rx_desc, + struct mon_rx_status *rx_status) +{ +#define SHORT_PREAMBLE 1 +#define LONG_PREAMBLE 0 + char rate = 0x0; + uint8_t preamble = SHORT_PREAMBLE; + uint8_t preamble_type = rx_desc->ppdu_start.preamble_type; + uint8_t mcs = 0, nss = 0, sgi = 0, bw = 0, beamformed = 0; + uint16_t vht_flags = 0, ht_flags = 0; + uint32_t l_sig_rate_select = rx_desc->ppdu_start.l_sig_rate_select; + uint32_t l_sig_rate = rx_desc->ppdu_start.l_sig_rate; + bool is_stbc = 0, ldpc = 0; + + if (l_sig_rate_select == 0) { + switch (l_sig_rate) { + case 0x8: + rate = 0x60; + break; + case 0x9: + rate = 0x30; + break; + case 0xA: + rate = 0x18; + break; + case 0xB: + rate = 0x0c; + break; + case 0xC: + rate = 0x6c; + break; + case 0xD: + rate = 0x48; + break; + case 0xE: + rate = 0x24; + break; + case 0xF: + rate = 0x12; + break; + default: + break; + } + } else if (l_sig_rate_select == 1) { + switch (l_sig_rate) { + case 0x8: + rate = 0x16; + preamble = LONG_PREAMBLE; + break; + case 0x9: + rate = 0x0B; + preamble = LONG_PREAMBLE; + break; + case 0xA: + rate = 0x04; + preamble = LONG_PREAMBLE; + break; + case 0xB: + rate = 0x02; + preamble = LONG_PREAMBLE; + break; + case 0xC: + rate = 0x16; + break; + case 0xD: + rate = 0x0B; + break; + case 0xE: + rate = 0x04; + break; + default: + break; + } + } else { + qdf_print("Invalid rate info\n"); + } + + switch (preamble_type) { + case 8: + is_stbc = ((VHT_SIG_A_2(rx_desc) >> 4) & 3); + /* fallthrough */ + case 9: + ht_flags = 1; + sgi = (VHT_SIG_A_2(rx_desc) >> 7) & 0x01; + bw = (VHT_SIG_A_1(rx_desc) >> 7) & 0x01; + mcs = (VHT_SIG_A_1(rx_desc) & 0x7f); + nss = mcs>>3; + beamformed = + (VHT_SIG_A_2(rx_desc) >> 8) & 0x1; + break; + case 0x0c: + is_stbc = (VHT_SIG_A_2(rx_desc) >> 3) & 1; + ldpc = (VHT_SIG_A_2(rx_desc) >> 2) & 1; + /* fallthrough */ + case 0x0d: + { + uint8_t gid_in_sig = ((VHT_SIG_A_1(rx_desc) >> 4) & 0x3f); + + vht_flags = 1; + sgi = VHT_SIG_A_2(rx_desc) & 0x01; + bw = (VHT_SIG_A_1(rx_desc) & 0x03); + if (gid_in_sig == 0 || gid_in_sig == 63) { + /* SU case */ + mcs = (VHT_SIG_A_2(rx_desc) >> 4) & + 0xf; + nss = (VHT_SIG_A_1(rx_desc) >> 10) & + 0x7; + } else { + /* MU case */ + uint8_t sta_user_pos = + (uint8_t)((rx_desc->ppdu_start.reserved_4a >> 8) + & 0x3); + mcs = (rx_desc->ppdu_start.vht_sig_b >> 16); + if (bw >= 2) + mcs >>= 3; + else if (bw > 0) + mcs >>= 1; + mcs &= 0xf; + nss = (((VHT_SIG_A_1(rx_desc) >> 10) + + sta_user_pos * 3) & 0x7); + } + beamformed = (VHT_SIG_A_2(rx_desc) >> 8) & 0x1; + } + /* fallthrough */ + default: + break; + } + + rx_status->mcs = mcs; + rx_status->bw = bw; + rx_status->nr_ant = nss; + rx_status->is_stbc = is_stbc; + rx_status->sgi = sgi; + rx_status->ldpc = ldpc; + rx_status->beamformed = beamformed; + rx_status->vht_flag_values3[0] = mcs << 0x4 | (nss + 1); + rx_status->rate = rate; + rx_status->ht_flags = ht_flags; + rx_status->vht_flags = vht_flags; + rx_status->rtap_flags |= ((preamble == SHORT_PREAMBLE) ? BIT(1) : 0); + if (bw == 0) + rx_status->vht_flag_values2 = 0; + else if (bw == 1) + rx_status->vht_flag_values2 = 1; + else if (bw == 2) + rx_status->vht_flag_values2 = 4; +} + +/** + * htt_mon_rx_get_rtap_flags() - Get radiotap flags + * @rx_desc: Pointer to struct htt_host_rx_desc_base + * + * Return: Bitmapped radiotap flags. + */ +static uint8_t htt_mon_rx_get_rtap_flags(struct htt_host_rx_desc_base *rx_desc) +{ + uint8_t rtap_flags = 0; + + /* WEP40 || WEP104 || WEP128 */ + if (rx_desc->mpdu_start.encrypt_type == 0 || + rx_desc->mpdu_start.encrypt_type == 1 || + rx_desc->mpdu_start.encrypt_type == 3) + rtap_flags |= BIT(2); + + /* IEEE80211_RADIOTAP_F_FRAG */ + if (rx_desc->attention.fragment) + rtap_flags |= BIT(3); + + /* IEEE80211_RADIOTAP_F_FCS */ + rtap_flags |= BIT(4); + + /* IEEE80211_RADIOTAP_F_BADFCS */ + if (rx_desc->mpdu_end.fcs_err) + rtap_flags |= BIT(6); + + return rtap_flags; +} + +/** + * htt_rx_mon_get_rx_status() - Update information about the rx status, + * which is used later for radiotap updation. + * @rx_desc: Pointer to struct htt_host_rx_desc_base + * @rx_status: Return variable updated with rx_status + * + * Return: None + */ +static void htt_rx_mon_get_rx_status(htt_pdev_handle pdev, + struct htt_host_rx_desc_base *rx_desc, + struct mon_rx_status *rx_status) +{ + uint16_t channel_flags = 0; + struct mon_channel *ch_info = &pdev->mon_ch_info; + + rx_status->tsft = (u_int64_t)TSF_TIMESTAMP(rx_desc); + rx_status->chan_freq = ch_info->ch_freq; + rx_status->chan_num = ch_info->ch_num; + htt_mon_rx_get_phy_info(rx_desc, rx_status); + rx_status->rtap_flags |= htt_mon_rx_get_rtap_flags(rx_desc); + channel_flags |= rx_desc->ppdu_start.l_sig_rate_select ? + IEEE80211_CHAN_CCK : IEEE80211_CHAN_OFDM; + channel_flags |= + (cds_chan_to_band(ch_info->ch_num) == CDS_BAND_2GHZ ? + IEEE80211_CHAN_2GHZ : IEEE80211_CHAN_5GHZ); + + rx_status->chan_flags = channel_flags; + rx_status->ant_signal_db = rx_desc->ppdu_start.rssi_comb; +} +#endif + +#ifdef RX_HASH_DEBUG +#define HTT_RX_CHECK_MSDU_COUNT(msdu_count) HTT_ASSERT_ALWAYS(msdu_count) +#else +#define HTT_RX_CHECK_MSDU_COUNT(msdu_count) /* no-op */ +#endif + +#ifndef CONFIG_HL_SUPPORT +/** + * htt_rx_mon_amsdu_rx_in_order_pop_ll() - Monitor mode HTT Rx in order pop + * function + * @pdev: Handle to htt_pdev_handle + * @rx_ind_msg: In order indication message. + * @head_msdu: Return variable pointing to head msdu. + * @tail_msdu: Return variable pointing to tail msdu. + * + * This function pops the msdu based on paddr:length of inorder indication + * message. + * + * Return: 1 for success, 0 on failure. + */ +static int htt_rx_mon_amsdu_rx_in_order_pop_ll(htt_pdev_handle pdev, + qdf_nbuf_t rx_ind_msg, + qdf_nbuf_t *head_msdu, + qdf_nbuf_t *tail_msdu, + uint32_t *replenish_cnt) +{ + qdf_nbuf_t msdu, next, prev = NULL; + uint8_t *rx_ind_data; + uint32_t *msg_word; + uint32_t msdu_count; + struct htt_host_rx_desc_base *rx_desc; + struct mon_rx_status rx_status = {0}; + uint32_t amsdu_len; + uint32_t len; + uint32_t last_frag; + qdf_dma_addr_t paddr; + + HTT_ASSERT1(htt_rx_in_order_ring_elems(pdev) != 0); + + rx_ind_data = qdf_nbuf_data(rx_ind_msg); + msg_word = (uint32_t *)rx_ind_data; + + *replenish_cnt = 0; + HTT_PKT_DUMP(qdf_trace_hex_dump(QDF_MODULE_ID_TXRX, + QDF_TRACE_LEVEL_FATAL, + (void *)rx_ind_data, + (int)qdf_nbuf_len(rx_ind_msg))); + + /* Get the total number of MSDUs */ + msdu_count = HTT_RX_IN_ORD_PADDR_IND_MSDU_CNT_GET(*(msg_word + 1)); + HTT_RX_CHECK_MSDU_COUNT(msdu_count); + + msg_word = (uint32_t *)(rx_ind_data + + HTT_RX_IN_ORD_PADDR_IND_HDR_BYTES); + paddr = htt_rx_in_ord_paddr_get(msg_word); + msdu = htt_rx_in_order_netbuf_pop(pdev, paddr); + + if (qdf_unlikely(NULL == msdu)) { + qdf_print("%s: netbuf pop failed!\n", __func__); + *tail_msdu = NULL; + return 0; + } + *replenish_cnt = *replenish_cnt + 1; + + while (msdu_count > 0) { + + msdu_count--; + /* + * Set the netbuf length to be the entire buffer length + * initially, so the unmap will unmap the entire buffer. + */ + qdf_nbuf_set_pktlen(msdu, HTT_RX_BUF_SIZE); + qdf_nbuf_unmap(pdev->osdev, msdu, QDF_DMA_FROM_DEVICE); + + /* + * cache consistency has been taken care of by the + * qdf_nbuf_unmap + */ + rx_desc = htt_rx_desc(msdu); + if ((unsigned int)(*(uint32_t *)&rx_desc->attention) & + RX_DESC_ATTN_MPDU_LEN_ERR_BIT) { + qdf_nbuf_free(msdu); + last_frag = ((struct htt_rx_in_ord_paddr_ind_msdu_t *) + msg_word)->msdu_info; + while (!last_frag) { + msg_word += HTT_RX_IN_ORD_PADDR_IND_MSDU_DWORDS; + paddr = htt_rx_in_ord_paddr_get(msg_word); + msdu = htt_rx_in_order_netbuf_pop(pdev, paddr); + last_frag = ((struct + htt_rx_in_ord_paddr_ind_msdu_t *) + msg_word)->msdu_info; + if (qdf_unlikely(!msdu)) { + qdf_print("%s: netbuf pop failed!\n", + __func__); + return 0; + } + *replenish_cnt = *replenish_cnt + 1; + qdf_nbuf_unmap(pdev->osdev, msdu, + QDF_DMA_FROM_DEVICE); + qdf_nbuf_free(msdu); + } + msdu = prev; + goto next_pop; + } + + if (!prev) + (*head_msdu) = msdu; + prev = msdu; + + HTT_PKT_DUMP(htt_print_rx_desc(rx_desc)); + /* + * Make the netbuf's data pointer point to the payload rather + * than the descriptor. + */ + htt_rx_mon_get_rx_status(pdev, rx_desc, &rx_status); + /* + * 350 bytes of RX_STD_DESC size should be sufficient for + * radiotap. + */ + qdf_nbuf_update_radiotap(&rx_status, msdu, + HTT_RX_STD_DESC_RESERVATION); + amsdu_len = HTT_RX_IN_ORD_PADDR_IND_MSDU_LEN_GET(*(msg_word + + NEXT_FIELD_OFFSET_IN32)); + + /* + * MAX_RX_PAYLOAD_SZ when we have AMSDU packet. amsdu_len in + * which case is the total length of sum of all AMSDU's + */ + len = MIN(amsdu_len, MAX_RX_PAYLOAD_SZ); + amsdu_len -= len; + qdf_nbuf_trim_tail(msdu, + HTT_RX_BUF_SIZE - + (RX_STD_DESC_SIZE + len)); + + + HTT_PKT_DUMP(qdf_trace_hex_dump(QDF_MODULE_ID_TXRX, + QDF_TRACE_LEVEL_FATAL, + qdf_nbuf_data(msdu), + qdf_nbuf_len(msdu))); + last_frag = ((struct htt_rx_in_ord_paddr_ind_msdu_t *) + msg_word)->msdu_info; + +#undef NEXT_FIELD_OFFSET_IN32 + /* Handle amsdu packet */ + if (!last_frag) { + /* + * For AMSDU packet msdu->len is sum of all the msdu's + * length, msdu->data_len is sum of length's of + * remaining msdu's other than parent. + */ + if (!htt_mon_rx_handle_amsdu_packet(msdu, pdev, + &msg_word, + amsdu_len, + replenish_cnt)) { + qdf_print("%s: failed to handle amsdu packet\n", + __func__); + return 0; + } + } + +next_pop: + /* check if this is the last msdu */ + if (msdu_count) { + msg_word += HTT_RX_IN_ORD_PADDR_IND_MSDU_DWORDS; + paddr = htt_rx_in_ord_paddr_get(msg_word); + next = htt_rx_in_order_netbuf_pop(pdev, paddr); + if (qdf_unlikely(NULL == next)) { + qdf_print("%s: netbuf pop failed!\n", + __func__); + *tail_msdu = NULL; + return 0; + } + *replenish_cnt = *replenish_cnt + 1; + if (msdu) + qdf_nbuf_set_next(msdu, next); + msdu = next; + } else { + *tail_msdu = msdu; + if (msdu) + qdf_nbuf_set_next(msdu, NULL); + } + } + + return 1; +} +#endif + +/** + * htt_rx_mon_note_capture_channel() - Make note of channel to update in + * radiotap + * @pdev: handle to htt_pdev + * @mon_ch: capture channel number. + * + * Return: None + */ +void htt_rx_mon_note_capture_channel(htt_pdev_handle pdev, int mon_ch) +{ + struct mon_channel *ch_info = &pdev->mon_ch_info; + + ch_info->ch_num = mon_ch; + ch_info->ch_freq = cds_chan_to_freq(mon_ch); +} + +uint32_t htt_rx_amsdu_rx_in_order_get_pktlog(qdf_nbuf_t rx_ind_msg) +{ + uint32_t *msg_word; + + msg_word = (uint32_t *) qdf_nbuf_data(rx_ind_msg); + return HTT_RX_IN_ORD_PADDR_IND_PKTLOG_GET(*msg_word); +} + +#ifndef CONFIG_HL_SUPPORT +/* Return values: 1 - success, 0 - failure */ +static int +htt_rx_amsdu_rx_in_order_pop_ll(htt_pdev_handle pdev, + qdf_nbuf_t rx_ind_msg, + qdf_nbuf_t *head_msdu, qdf_nbuf_t *tail_msdu, + uint32_t *replenish_cnt) +{ + qdf_nbuf_t msdu, next, prev = NULL; + uint8_t *rx_ind_data; + uint32_t *msg_word; + uint32_t rx_ctx_id; + unsigned int msdu_count = 0; + uint8_t offload_ind, frag_ind; + uint8_t peer_id; + struct htt_host_rx_desc_base *rx_desc; + enum rx_pkt_fate status = RX_PKT_FATE_SUCCESS; + qdf_dma_addr_t paddr; + + HTT_ASSERT1(htt_rx_in_order_ring_elems(pdev) != 0); + + rx_ind_data = qdf_nbuf_data(rx_ind_msg); + rx_ctx_id = QDF_NBUF_CB_RX_CTX_ID(rx_ind_msg); + msg_word = (uint32_t *) rx_ind_data; + peer_id = HTT_RX_IN_ORD_PADDR_IND_PEER_ID_GET( + *(u_int32_t *)rx_ind_data); + + offload_ind = HTT_RX_IN_ORD_PADDR_IND_OFFLOAD_GET(*msg_word); + frag_ind = HTT_RX_IN_ORD_PADDR_IND_FRAG_GET(*msg_word); + + /* Get the total number of MSDUs */ + msdu_count = HTT_RX_IN_ORD_PADDR_IND_MSDU_CNT_GET(*(msg_word + 1)); + HTT_RX_CHECK_MSDU_COUNT(msdu_count); + ol_rx_update_histogram_stats(msdu_count, frag_ind, offload_ind); + htt_rx_dbg_rxbuf_httrxind(pdev, msdu_count); + + + msg_word = + (uint32_t *) (rx_ind_data + HTT_RX_IN_ORD_PADDR_IND_HDR_BYTES); + if (offload_ind) { + ol_rx_offload_paddr_deliver_ind_handler(pdev, msdu_count, + msg_word); + *head_msdu = *tail_msdu = NULL; + return 0; + } + + paddr = htt_rx_in_ord_paddr_get(msg_word); + (*head_msdu) = msdu = htt_rx_in_order_netbuf_pop(pdev, paddr); + + if (qdf_unlikely(NULL == msdu)) { + qdf_print("%s: netbuf pop failed!\n", __func__); + *tail_msdu = NULL; + return 0; + } + + while (msdu_count > 0) { + + /* + * Set the netbuf length to be the entire buffer length + * initially, so the unmap will unmap the entire buffer. + */ + qdf_nbuf_set_pktlen(msdu, HTT_RX_BUF_SIZE); +#ifdef DEBUG_DMA_DONE + qdf_nbuf_unmap(pdev->osdev, msdu, QDF_DMA_BIDIRECTIONAL); +#else + qdf_nbuf_unmap(pdev->osdev, msdu, QDF_DMA_FROM_DEVICE); +#endif + + /* cache consistency has been taken care of by qdf_nbuf_unmap */ + rx_desc = htt_rx_desc(msdu); + htt_rx_extract_lro_info(msdu, rx_desc); + + /* + * Make the netbuf's data pointer point to the payload rather + * than the descriptor. + */ + qdf_nbuf_pull_head(msdu, HTT_RX_STD_DESC_RESERVATION); + + QDF_NBUF_CB_DP_TRACE_PRINT(msdu) = false; + qdf_dp_trace_set_track(msdu, QDF_RX); + QDF_NBUF_CB_TX_PACKET_TRACK(msdu) = QDF_NBUF_TX_PKT_DATA_TRACK; + QDF_NBUF_CB_RX_CTX_ID(msdu) = rx_ctx_id; + ol_rx_log_packet(pdev, peer_id, msdu); + if (qdf_nbuf_is_ipv4_arp_pkt(msdu)) + QDF_NBUF_CB_GET_PACKET_TYPE(msdu) = + QDF_NBUF_CB_PACKET_TYPE_ARP; + DPTRACE(qdf_dp_trace(msdu, + QDF_DP_TRACE_RX_HTT_PACKET_PTR_RECORD, + qdf_nbuf_data_addr(msdu), + sizeof(qdf_nbuf_data(msdu)), QDF_RX)); + +#if HTT_PADDR64 +#define NEXT_FIELD_OFFSET_IN32 2 +#else /* ! HTT_PADDR64 */ +#define NEXT_FIELD_OFFSET_IN32 1 +#endif /* HTT_PADDR64 */ + qdf_nbuf_trim_tail(msdu, + HTT_RX_BUF_SIZE - + (RX_STD_DESC_SIZE + + HTT_RX_IN_ORD_PADDR_IND_MSDU_LEN_GET( + *(msg_word + NEXT_FIELD_OFFSET_IN32)))); +#if defined(HELIUMPLUS_DEBUG) + ol_txrx_dump_pkt(msdu, 0, 64); +#endif + *((uint8_t *) &rx_desc->fw_desc.u.val) = + HTT_RX_IN_ORD_PADDR_IND_FW_DESC_GET(*(msg_word + NEXT_FIELD_OFFSET_IN32)); +#undef NEXT_FIELD_OFFSET_IN32 + + msdu_count--; + + /* calling callback function for packet logging */ + if (pdev->rx_pkt_dump_cb) { + if (qdf_unlikely((*((u_int8_t *) + &rx_desc->fw_desc.u.val)) & + FW_RX_DESC_ANY_ERR_M)) + status = RX_PKT_FATE_FW_DROP_INVALID; + pdev->rx_pkt_dump_cb(msdu, peer_id, status); + } + + if (qdf_unlikely((*((u_int8_t *) &rx_desc->fw_desc.u.val)) & + FW_RX_DESC_ANY_ERR_M)) { + uint8_t tid = + HTT_RX_IN_ORD_PADDR_IND_EXT_TID_GET( + *(u_int32_t *)rx_ind_data); + ol_rx_mic_error_handler(pdev->txrx_pdev, tid, peer_id, + rx_desc, msdu); + + htt_rx_desc_frame_free(pdev, msdu); + /* if this is the last msdu */ + if (!msdu_count) { + /* if this is the only msdu */ + if (!prev) { + *head_msdu = *tail_msdu = NULL; + return 0; + } else { + *tail_msdu = prev; + qdf_nbuf_set_next(prev, NULL); + return 1; + } + } else { /* if this is not the last msdu */ + /* get the next msdu */ + msg_word += HTT_RX_IN_ORD_PADDR_IND_MSDU_DWORDS; + paddr = htt_rx_in_ord_paddr_get(msg_word); + next = htt_rx_in_order_netbuf_pop(pdev, paddr); + if (qdf_unlikely(NULL == next)) { + qdf_print("%s: netbuf pop failed!\n", + __func__); + *tail_msdu = NULL; + return 0; + } + + /* if this is not the first msdu, update the + * next pointer of the preceding msdu + */ + if (prev) { + qdf_nbuf_set_next(prev, next); + } else { + /* if this is the first msdu, update the + * head pointer + */ + *head_msdu = next; + } + msdu = next; + continue; + } + } + + /* Update checksum result */ + htt_set_checksum_result_ll(pdev, msdu, rx_desc); + + /* check if this is the last msdu */ + if (msdu_count) { + msg_word += HTT_RX_IN_ORD_PADDR_IND_MSDU_DWORDS; + paddr = htt_rx_in_ord_paddr_get(msg_word); + next = htt_rx_in_order_netbuf_pop(pdev, paddr); + if (qdf_unlikely(NULL == next)) { + qdf_print("%s: netbuf pop failed!\n", + __func__); + *tail_msdu = NULL; + return 0; + } + qdf_nbuf_set_next(msdu, next); + prev = msdu; + msdu = next; + } else { + *tail_msdu = msdu; + qdf_nbuf_set_next(msdu, NULL); + } + } + + return 1; +} +#endif + +/* Util fake function that has same prototype as qdf_nbuf_clone that just + * retures the same nbuf + */ +static qdf_nbuf_t htt_rx_qdf_noclone_buf(qdf_nbuf_t buf) +{ + return buf; +} + +/* FIXME: This is a HW definition not provded by HW, where does it go ? */ +enum { + HW_RX_DECAP_FORMAT_RAW = 0, + HW_RX_DECAP_FORMAT_NWIFI, + HW_RX_DECAP_FORMAT_8023, + HW_RX_DECAP_FORMAT_ETH2, +}; + +#define HTT_FCS_LEN (4) + +static void +htt_rx_parse_ppdu_start_status(struct htt_host_rx_desc_base *rx_desc, + struct ieee80211_rx_status *rs) +{ + + struct rx_ppdu_start *ppdu_start = &rx_desc->ppdu_start; + + /* RSSI */ + rs->rs_rssi = ppdu_start->rssi_comb; + + /* PHY rate */ + /* rs_ratephy coding + [b3 - b0] + 0 -> OFDM + 1 -> CCK + 2 -> HT + 3 -> VHT + OFDM / CCK + [b7 - b4 ] => LSIG rate + [b23 - b8 ] => service field + (b'12 static/dynamic, + b'14..b'13 BW for VHT) + [b31 - b24 ] => Reserved + HT / VHT + [b15 - b4 ] => SIG A_2 12 LSBs + [b31 - b16] => SIG A_1 16 LSBs + + */ + if (ppdu_start->preamble_type == 0x4) { + rs->rs_ratephy = ppdu_start->l_sig_rate_select; + rs->rs_ratephy |= ppdu_start->l_sig_rate << 4; + rs->rs_ratephy |= ppdu_start->service << 8; + } else { + rs->rs_ratephy = (ppdu_start->preamble_type & 0x4) ? 3 : 2; +#ifdef HELIUMPLUS + rs->rs_ratephy |= + (ppdu_start->ht_sig_vht_sig_ah_sig_a_2 & 0xFFF) << 4; + rs->rs_ratephy |= + (ppdu_start->ht_sig_vht_sig_ah_sig_a_1 & 0xFFFF) << 16; +#else + rs->rs_ratephy |= (ppdu_start->ht_sig_vht_sig_a_2 & 0xFFF) << 4; + rs->rs_ratephy |= + (ppdu_start->ht_sig_vht_sig_a_1 & 0xFFFF) << 16; +#endif + } + + return; +} + +/* This function is used by montior mode code to restitch an MSDU list + * corresponding to an MPDU back into an MPDU by linking up the skbs. + */ +qdf_nbuf_t +htt_rx_restitch_mpdu_from_msdus(htt_pdev_handle pdev, + qdf_nbuf_t head_msdu, + struct ieee80211_rx_status *rx_status, + unsigned clone_not_reqd) +{ + + qdf_nbuf_t msdu, mpdu_buf, prev_buf, msdu_orig, head_frag_list_cloned; + unsigned decap_format, wifi_hdr_len, sec_hdr_len, msdu_llc_len, + mpdu_buf_len, decap_hdr_pull_bytes, frag_list_sum_len, dir, + is_amsdu, is_first_frag, amsdu_pad, msdu_len; + struct htt_host_rx_desc_base *rx_desc; + char *hdr_desc; + unsigned char *dest; + struct ieee80211_frame *wh; + struct ieee80211_qoscntl *qos; + + /* The nbuf has been pulled just beyond the status and points to the + * payload + */ + msdu_orig = head_msdu; + rx_desc = htt_rx_desc(msdu_orig); + + /* Fill out the rx_status from the PPDU start and end fields */ + if (rx_desc->attention.first_mpdu) { + htt_rx_parse_ppdu_start_status(rx_desc, rx_status); + + /* The timestamp is no longer valid - It will be valid only for + * the last MPDU + */ + rx_status->rs_tstamp.tsf = ~0; + } + + decap_format = + GET_FIELD(&rx_desc->msdu_start, RX_MSDU_START_2_DECAP_FORMAT); + + head_frag_list_cloned = NULL; + + /* Easy case - The MSDU status indicates that this is a non-decapped + * packet in RAW mode. + * return + */ + if (decap_format == HW_RX_DECAP_FORMAT_RAW) { + /* Note that this path might suffer from headroom unavailabilty, + * but the RX status is usually enough + */ + if (clone_not_reqd) + mpdu_buf = htt_rx_qdf_noclone_buf(head_msdu); + else + mpdu_buf = qdf_nbuf_clone(head_msdu); + + if (!mpdu_buf) + goto mpdu_stitch_fail; + + if (!mpdu_buf) + goto mpdu_stitch_fail; + + prev_buf = mpdu_buf; + + frag_list_sum_len = 0; + is_first_frag = 1; + msdu_len = qdf_nbuf_len(mpdu_buf); + + /* Drop the zero-length msdu */ + if (!msdu_len) + goto mpdu_stitch_fail; + + msdu_orig = qdf_nbuf_next(head_msdu); + + while (msdu_orig) { + + /* TODO: intra AMSDU padding - do we need it ??? */ + if (clone_not_reqd) + msdu = htt_rx_qdf_noclone_buf(msdu_orig); + else + msdu = qdf_nbuf_clone(msdu_orig); + + if (!msdu) + goto mpdu_stitch_fail; + + if (is_first_frag) { + is_first_frag = 0; + head_frag_list_cloned = msdu; + } + + msdu_len = qdf_nbuf_len(msdu); + /* Drop the zero-length msdu */ + if (!msdu_len) + goto mpdu_stitch_fail; + + frag_list_sum_len += msdu_len; + + /* Maintain the linking of the cloned MSDUS */ + qdf_nbuf_set_next_ext(prev_buf, msdu); + + /* Move to the next */ + prev_buf = msdu; + msdu_orig = qdf_nbuf_next(msdu_orig); + } + + /* The last msdu length need be larger than HTT_FCS_LEN */ + if (msdu_len < HTT_FCS_LEN) + goto mpdu_stitch_fail; + + qdf_nbuf_trim_tail(prev_buf, HTT_FCS_LEN); + + /* If there were more fragments to this RAW frame */ + if (head_frag_list_cloned) { + qdf_nbuf_append_ext_list(mpdu_buf, + head_frag_list_cloned, + frag_list_sum_len); + } + + goto mpdu_stitch_done; + } + + /* Decap mode: + * Calculate the amount of header in decapped packet to knock off based + * on the decap type and the corresponding number of raw bytes to copy + * status header + */ + + hdr_desc = &rx_desc->rx_hdr_status[0]; + + /* Base size */ + wifi_hdr_len = sizeof(struct ieee80211_frame); + wh = (struct ieee80211_frame *)hdr_desc; + + dir = wh->i_fc[1] & IEEE80211_FC1_DIR_MASK; + if (dir == IEEE80211_FC1_DIR_DSTODS) + wifi_hdr_len += 6; + + is_amsdu = 0; + if (wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_QOS) { + qos = (struct ieee80211_qoscntl *) + (hdr_desc + wifi_hdr_len); + wifi_hdr_len += 2; + + is_amsdu = (qos->i_qos[0] & IEEE80211_QOS_AMSDU); + } + + /* TODO: Any security headers associated with MPDU */ + sec_hdr_len = 0; + + /* MSDU related stuff LLC - AMSDU subframe header etc */ + msdu_llc_len = is_amsdu ? (14 + 8) : 8; + + mpdu_buf_len = wifi_hdr_len + sec_hdr_len + msdu_llc_len; + + /* "Decap" header to remove from MSDU buffer */ + decap_hdr_pull_bytes = 14; + + /* Allocate a new nbuf for holding the 802.11 header retrieved from the + * status of the now decapped first msdu. Leave enough headroom for + * accomodating any radio-tap /prism like PHY header + */ +#define HTT_MAX_MONITOR_HEADER (512) + mpdu_buf = qdf_nbuf_alloc(pdev->osdev, + HTT_MAX_MONITOR_HEADER + mpdu_buf_len, + HTT_MAX_MONITOR_HEADER, 4, false); + + if (!mpdu_buf) + goto mpdu_stitch_fail; + + /* Copy the MPDU related header and enc headers into the first buffer + * - Note that there can be a 2 byte pad between heaader and enc header + */ + + prev_buf = mpdu_buf; + dest = qdf_nbuf_put_tail(prev_buf, wifi_hdr_len); + if (!dest) + goto mpdu_stitch_fail; + qdf_mem_copy(dest, hdr_desc, wifi_hdr_len); + hdr_desc += wifi_hdr_len; + + /* NOTE - This padding is present only in the RAW header status - not + * when the MSDU data payload is in RAW format. + */ + /* Skip the "IV pad" */ + if (wifi_hdr_len & 0x3) + hdr_desc += 2; + + /* The first LLC len is copied into the MPDU buffer */ + frag_list_sum_len = 0; + frag_list_sum_len -= msdu_llc_len; + + msdu_orig = head_msdu; + is_first_frag = 1; + amsdu_pad = 0; + + while (msdu_orig) { + + /* TODO: intra AMSDU padding - do we need it ??? */ + + if (clone_not_reqd) + msdu = htt_rx_qdf_noclone_buf(msdu_orig); + else + msdu = qdf_nbuf_clone(msdu_orig); + + if (!msdu) + goto mpdu_stitch_fail; + + if (is_first_frag) { + is_first_frag = 0; + head_frag_list_cloned = msdu; + } else { + + /* Maintain the linking of the cloned MSDUS */ + qdf_nbuf_set_next_ext(prev_buf, msdu); + + /* Reload the hdr ptr only on non-first MSDUs */ + rx_desc = htt_rx_desc(msdu_orig); + hdr_desc = &rx_desc->rx_hdr_status[0]; + + } + + /* Copy this buffers MSDU related status into the prev buffer */ + dest = qdf_nbuf_put_tail(prev_buf, msdu_llc_len + amsdu_pad); + dest += amsdu_pad; + qdf_mem_copy(dest, hdr_desc, msdu_llc_len); + + /* Push the MSDU buffer beyond the decap header */ + qdf_nbuf_pull_head(msdu, decap_hdr_pull_bytes); + frag_list_sum_len += + msdu_llc_len + qdf_nbuf_len(msdu) + amsdu_pad; + + /* Set up intra-AMSDU pad to be added to start of next buffer - + * AMSDU pad is 4 byte pad on AMSDU subframe */ + amsdu_pad = (msdu_llc_len + qdf_nbuf_len(msdu)) & 0x3; + amsdu_pad = amsdu_pad ? (4 - amsdu_pad) : 0; + + /* TODO FIXME How do we handle MSDUs that have fraglist - Should + * probably iterate all the frags cloning them along the way and + * and also updating the prev_buf pointer + */ + + /* Move to the next */ + prev_buf = msdu; + msdu_orig = qdf_nbuf_next(msdu_orig); + + } + + /* TODO: Convert this to suitable qdf routines */ + qdf_nbuf_append_ext_list(mpdu_buf, head_frag_list_cloned, + frag_list_sum_len); + +mpdu_stitch_done: + /* Check if this buffer contains the PPDU end status for TSF */ + if (rx_desc->attention.last_mpdu) +#ifdef HELIUMPLUS + rx_status->rs_tstamp.tsf = + rx_desc->ppdu_end.rx_pkt_end.phy_timestamp_1_lower_32; +#else + rx_status->rs_tstamp.tsf = rx_desc->ppdu_end.tsf_timestamp; +#endif + /* All the nbufs have been linked into the ext list and + then unlink the nbuf list */ + if (clone_not_reqd) { + msdu = head_msdu; + while (msdu) { + msdu_orig = msdu; + msdu = qdf_nbuf_next(msdu); + qdf_nbuf_set_next(msdu_orig, NULL); + } + } + + return mpdu_buf; + +mpdu_stitch_fail: + /* Free these alloced buffers and the orig buffers in non-clone case */ + if (!clone_not_reqd) { + /* Free the head buffer */ + if (mpdu_buf) + qdf_nbuf_free(mpdu_buf); + + /* Free the partial list */ + while (head_frag_list_cloned) { + msdu = head_frag_list_cloned; + head_frag_list_cloned = + qdf_nbuf_next_ext(head_frag_list_cloned); + qdf_nbuf_free(msdu); + } + } else { + /* Free the alloced head buffer */ + if (decap_format != HW_RX_DECAP_FORMAT_RAW) + if (mpdu_buf) + qdf_nbuf_free(mpdu_buf); + + /* Free the orig buffers */ + msdu = head_msdu; + while (msdu) { + msdu_orig = msdu; + msdu = qdf_nbuf_next(msdu); + qdf_nbuf_free(msdu_orig); + } + } + + return NULL; +} + +int16_t htt_rx_mpdu_desc_rssi_dbm(htt_pdev_handle pdev, void *mpdu_desc) +{ + /* + * Currently the RSSI is provided only as a field in the + * HTT_T2H_RX_IND message, rather than in each rx descriptor. + */ + return HTT_RSSI_INVALID; +} + +/* + * htt_rx_amsdu_pop - + * global function pointer that is programmed during attach to point + * to either htt_rx_amsdu_pop_ll or htt_rx_amsdu_rx_in_order_pop_ll. + */ +int (*htt_rx_amsdu_pop)(htt_pdev_handle pdev, + qdf_nbuf_t rx_ind_msg, + qdf_nbuf_t *head_msdu, qdf_nbuf_t *tail_msdu, + uint32_t *msdu_count); + +/* + * htt_rx_frag_pop - + * global function pointer that is programmed during attach to point + * to either htt_rx_amsdu_pop_ll + */ +int (*htt_rx_frag_pop)(htt_pdev_handle pdev, + qdf_nbuf_t rx_ind_msg, + qdf_nbuf_t *head_msdu, qdf_nbuf_t *tail_msdu, + uint32_t *msdu_count); + +int +(*htt_rx_offload_msdu_pop)(htt_pdev_handle pdev, + qdf_nbuf_t offload_deliver_msg, + int *vdev_id, + int *peer_id, + int *tid, + uint8_t *fw_desc, + qdf_nbuf_t *head_buf, qdf_nbuf_t *tail_buf); + +void * (*htt_rx_mpdu_desc_list_next)(htt_pdev_handle pdev, + qdf_nbuf_t rx_ind_msg); + +bool (*htt_rx_mpdu_desc_retry)( + htt_pdev_handle pdev, void *mpdu_desc); + +uint16_t (*htt_rx_mpdu_desc_seq_num)(htt_pdev_handle pdev, void *mpdu_desc); + +void (*htt_rx_mpdu_desc_pn)(htt_pdev_handle pdev, + void *mpdu_desc, + union htt_rx_pn_t *pn, int pn_len_bits); + +uint8_t (*htt_rx_mpdu_desc_tid)( + htt_pdev_handle pdev, void *mpdu_desc); + +bool (*htt_rx_msdu_desc_completes_mpdu)(htt_pdev_handle pdev, void *msdu_desc); + +bool (*htt_rx_msdu_first_msdu_flag)(htt_pdev_handle pdev, void *msdu_desc); + +int (*htt_rx_msdu_has_wlan_mcast_flag)(htt_pdev_handle pdev, void *msdu_desc); + +bool (*htt_rx_msdu_is_wlan_mcast)(htt_pdev_handle pdev, void *msdu_desc); + +int (*htt_rx_msdu_is_frag)(htt_pdev_handle pdev, void *msdu_desc); + +void * (*htt_rx_msdu_desc_retrieve)(htt_pdev_handle pdev, qdf_nbuf_t msdu); + +bool (*htt_rx_mpdu_is_encrypted)(htt_pdev_handle pdev, void *mpdu_desc); + +bool (*htt_rx_msdu_desc_key_id)(htt_pdev_handle pdev, + void *mpdu_desc, uint8_t *key_id); + +#ifndef CONFIG_HL_SUPPORT +static +void *htt_rx_mpdu_desc_list_next_ll(htt_pdev_handle pdev, qdf_nbuf_t rx_ind_msg) +{ + int idx = pdev->rx_ring.sw_rd_idx.msdu_desc; + qdf_nbuf_t netbuf = pdev->rx_ring.buf.netbufs_ring[idx]; + pdev->rx_ring.sw_rd_idx.msdu_desc = pdev->rx_ring.sw_rd_idx.msdu_payld; + return (void *)htt_rx_desc(netbuf); +} +#endif + +bool (*htt_rx_msdu_chan_info_present)( + htt_pdev_handle pdev, + void *mpdu_desc); + +bool (*htt_rx_msdu_center_freq)( + htt_pdev_handle pdev, + struct ol_txrx_peer_t *peer, + void *mpdu_desc, + uint16_t *primary_chan_center_freq_mhz, + uint16_t *contig_chan1_center_freq_mhz, + uint16_t *contig_chan2_center_freq_mhz, + uint8_t *phy_mode); + +#ifndef CONFIG_HL_SUPPORT +static void *htt_rx_in_ord_mpdu_desc_list_next_ll(htt_pdev_handle pdev, + qdf_nbuf_t netbuf) +{ + return (void *)htt_rx_desc(netbuf); +} +#endif + +#if defined(CONFIG_HL_SUPPORT) + +/** + * htt_rx_mpdu_desc_list_next_hl() - provides an abstract way to obtain + * the next MPDU descriptor + * @pdev: the HTT instance the rx data was received on + * @rx_ind_msg: the netbuf containing the rx indication message + * + * for HL, the returned value is not mpdu_desc, + * it's translated hl_rx_desc just after the hl_ind_msg + * for HL AMSDU, we can't point to payload now, because + * hl rx desc is not fixed, we can't retrive the desc + * by minus rx_desc_size when release. keep point to hl rx desc + * now + * + * Return: next abstract rx descriptor from the series of MPDUs + * referenced by an rx ind msg + */ +static inline void * +htt_rx_mpdu_desc_list_next_hl(htt_pdev_handle pdev, qdf_nbuf_t rx_ind_msg) +{ + void *mpdu_desc = (void *)qdf_nbuf_data(rx_ind_msg); + return mpdu_desc; +} + +/** + * htt_rx_msdu_desc_retrieve_hl() - Retrieve a previously-stored rx descriptor + * from a MSDU buffer + * @pdev: the HTT instance the rx data was received on + * @msdu - the buffer containing the MSDU payload + * + * currently for HL AMSDU, we don't point to payload. + * we shift to payload in ol_rx_deliver later + * + * Return: the corresponding abstract rx MSDU descriptor + */ +static inline void * +htt_rx_msdu_desc_retrieve_hl(htt_pdev_handle pdev, qdf_nbuf_t msdu) +{ + return qdf_nbuf_data(msdu); +} + +static +bool htt_rx_mpdu_is_encrypted_hl(htt_pdev_handle pdev, void *mpdu_desc) +{ + if (htt_rx_msdu_first_msdu_flag_hl(pdev, mpdu_desc) == true) { + /* Fix Me: only for little endian */ + struct hl_htt_rx_desc_base *rx_desc = + (struct hl_htt_rx_desc_base *)mpdu_desc; + + return HTT_WORD_GET(*(u_int32_t *)rx_desc, + HTT_HL_RX_DESC_MPDU_ENC); + } else { + /* not first msdu, no encrypt info for hl */ + qdf_print( + "Error: get encrypted from a not-first msdu.\n"); + qdf_assert(0); + return false; + } +} + +static inline bool +htt_rx_msdu_chan_info_present_hl(htt_pdev_handle pdev, void *mpdu_desc) +{ + if (htt_rx_msdu_first_msdu_flag_hl(pdev, mpdu_desc) == true && + HTT_WORD_GET(*(u_int32_t *)mpdu_desc, + HTT_HL_RX_DESC_CHAN_INFO_PRESENT)) + return true; + + return false; +} + +static bool +htt_rx_msdu_center_freq_hl(htt_pdev_handle pdev, + struct ol_txrx_peer_t *peer, + void *mpdu_desc, + uint16_t *primary_chan_center_freq_mhz, + uint16_t *contig_chan1_center_freq_mhz, + uint16_t *contig_chan2_center_freq_mhz, + uint8_t *phy_mode) +{ + int pn_len, index; + uint32_t *chan_info; + + index = htt_rx_msdu_is_wlan_mcast(pdev, mpdu_desc) ? + txrx_sec_mcast : txrx_sec_ucast; + + pn_len = (peer ? + pdev->txrx_pdev->rx_pn[peer->security[index].sec_type]. + len : 0); + chan_info = (uint32_t *)((uint8_t *)mpdu_desc + + HTT_HL_RX_DESC_PN_OFFSET + pn_len); + + if (htt_rx_msdu_chan_info_present_hl(pdev, mpdu_desc)) { + if (primary_chan_center_freq_mhz) + *primary_chan_center_freq_mhz = + HTT_WORD_GET( + *chan_info, + HTT_CHAN_INFO_PRIMARY_CHAN_CENTER_FREQ); + if (contig_chan1_center_freq_mhz) + *contig_chan1_center_freq_mhz = + HTT_WORD_GET( + *chan_info, + HTT_CHAN_INFO_CONTIG_CHAN1_CENTER_FREQ); + chan_info++; + if (contig_chan2_center_freq_mhz) + *contig_chan2_center_freq_mhz = + HTT_WORD_GET( + *chan_info, + HTT_CHAN_INFO_CONTIG_CHAN2_CENTER_FREQ); + if (phy_mode) + *phy_mode = + HTT_WORD_GET(*chan_info, + HTT_CHAN_INFO_PHY_MODE); + return true; + } + + if (primary_chan_center_freq_mhz) + *primary_chan_center_freq_mhz = 0; + if (contig_chan1_center_freq_mhz) + *contig_chan1_center_freq_mhz = 0; + if (contig_chan2_center_freq_mhz) + *contig_chan2_center_freq_mhz = 0; + if (phy_mode) + *phy_mode = 0; + return false; +} + +static bool +htt_rx_msdu_desc_key_id_hl(htt_pdev_handle htt_pdev, + void *mpdu_desc, u_int8_t *key_id) +{ + if (htt_rx_msdu_first_msdu_flag_hl(htt_pdev, mpdu_desc) == true) { + /* Fix Me: only for little endian */ + struct hl_htt_rx_desc_base *rx_desc = + (struct hl_htt_rx_desc_base *)mpdu_desc; + + *key_id = rx_desc->key_id_oct; + return true; + } + + return false; +} + +#endif + +#ifndef CONFIG_HL_SUPPORT +static void *htt_rx_msdu_desc_retrieve_ll(htt_pdev_handle pdev, qdf_nbuf_t msdu) +{ + return htt_rx_desc(msdu); +} + +static bool htt_rx_mpdu_is_encrypted_ll(htt_pdev_handle pdev, void *mpdu_desc) +{ + struct htt_host_rx_desc_base *rx_desc = + (struct htt_host_rx_desc_base *)mpdu_desc; + + return (((*((uint32_t *) &rx_desc->mpdu_start)) & + RX_MPDU_START_0_ENCRYPTED_MASK) >> + RX_MPDU_START_0_ENCRYPTED_LSB) ? true : false; +} + +static +bool htt_rx_msdu_chan_info_present_ll(htt_pdev_handle pdev, void *mpdu_desc) +{ + return false; +} + +static bool htt_rx_msdu_center_freq_ll(htt_pdev_handle pdev, + struct ol_txrx_peer_t *peer, + void *mpdu_desc, + uint16_t *primary_chan_center_freq_mhz, + uint16_t *contig_chan1_center_freq_mhz, + uint16_t *contig_chan2_center_freq_mhz, + uint8_t *phy_mode) +{ + if (primary_chan_center_freq_mhz) + *primary_chan_center_freq_mhz = 0; + if (contig_chan1_center_freq_mhz) + *contig_chan1_center_freq_mhz = 0; + if (contig_chan2_center_freq_mhz) + *contig_chan2_center_freq_mhz = 0; + if (phy_mode) + *phy_mode = 0; + return false; +} + +static bool +htt_rx_msdu_desc_key_id_ll(htt_pdev_handle pdev, void *mpdu_desc, + uint8_t *key_id) +{ + struct htt_host_rx_desc_base *rx_desc = (struct htt_host_rx_desc_base *) + mpdu_desc; + + if (!htt_rx_msdu_first_msdu_flag_ll(pdev, mpdu_desc)) + return false; + + *key_id = ((*(((uint32_t *) &rx_desc->msdu_end) + 1)) & + (RX_MSDU_END_1_KEY_ID_OCT_MASK >> + RX_MSDU_END_1_KEY_ID_OCT_LSB)); + + return true; +} +#endif + +void htt_rx_desc_frame_free(htt_pdev_handle htt_pdev, qdf_nbuf_t msdu) +{ + qdf_nbuf_free(msdu); +} + +void htt_rx_msdu_desc_free(htt_pdev_handle htt_pdev, qdf_nbuf_t msdu) +{ + /* + * The rx descriptor is in the same buffer as the rx MSDU payload, + * and does not need to be freed separately. + */ +} + +#if defined(CONFIG_HL_SUPPORT) + +/** + * htt_rx_fill_ring_count() - replenish rx msdu buffer + * @pdev: Handle (pointer) to HTT pdev. + * + * This funciton will replenish the rx buffer to the max number + * that can be kept in the ring + * + * Return: None + */ +static inline void htt_rx_fill_ring_count(htt_pdev_handle pdev) +{ + return; +} +#else + +static void htt_rx_fill_ring_count(htt_pdev_handle pdev) +{ + int num_to_fill; + num_to_fill = pdev->rx_ring.fill_level - pdev->rx_ring.fill_cnt; + htt_rx_ring_fill_n(pdev, num_to_fill /* okay if <= 0 */); +} +#endif + +void htt_rx_msdu_buff_replenish(htt_pdev_handle pdev) +{ + if (qdf_atomic_dec_and_test(&pdev->rx_ring.refill_ref_cnt)) + htt_rx_fill_ring_count(pdev); + + qdf_atomic_inc(&pdev->rx_ring.refill_ref_cnt); +} + +#ifndef CONFIG_HL_SUPPORT +#define RX_RING_REFILL_DEBT_MAX 128 +int htt_rx_msdu_buff_in_order_replenish(htt_pdev_handle pdev, uint32_t num) +{ + int filled = 0; + + if (!qdf_spin_trylock_bh(&(pdev->rx_ring.refill_lock))) { + if (qdf_atomic_read(&pdev->rx_ring.refill_debt) + < RX_RING_REFILL_DEBT_MAX) { + qdf_atomic_add(num, &pdev->rx_ring.refill_debt); + pdev->rx_buff_debt_invoked++; + return filled; /* 0 */ + } + /* + * else: + * If we have quite a debt, then it is better for the lock + * holder to finish its work and then acquire the lock and + * fill our own part. + */ + qdf_spin_lock_bh(&(pdev->rx_ring.refill_lock)); + } + pdev->rx_buff_fill_n_invoked++; + filled = htt_rx_ring_fill_n(pdev, num); + + qdf_spin_unlock_bh(&(pdev->rx_ring.refill_lock)); + + if (filled > num) { + /* we served ourselves and some other debt */ + /* sub is safer than = 0 */ + qdf_atomic_sub(filled - num, &pdev->rx_ring.refill_debt); + } + + return filled; +} +#endif + +#define AR600P_ASSEMBLE_HW_RATECODE(_rate, _nss, _pream) \ + (((_pream) << 6) | ((_nss) << 4) | (_rate)) + +enum AR600P_HW_RATECODE_PREAM_TYPE { + AR600P_HW_RATECODE_PREAM_OFDM, + AR600P_HW_RATECODE_PREAM_CCK, + AR600P_HW_RATECODE_PREAM_HT, + AR600P_HW_RATECODE_PREAM_VHT, +}; + +/*--- RX In Order Hash Code --------------------------------------------------*/ + +/* Initializes the circular linked list */ +static inline void htt_list_init(struct htt_list_node *head) +{ + head->prev = head; + head->next = head; +} + +/* Adds entry to the end of the linked list */ +static inline void htt_list_add_tail(struct htt_list_node *head, + struct htt_list_node *node) +{ + head->prev->next = node; + node->prev = head->prev; + node->next = head; + head->prev = node; +} + +/* Removes the entry corresponding to the input node from the linked list */ +static inline void htt_list_remove(struct htt_list_node *node) +{ + node->prev->next = node->next; + node->next->prev = node->prev; +} + +/* Helper macro to iterate through the linked list */ +#define HTT_LIST_ITER_FWD(iter, head) for (iter = (head)->next; \ + (iter) != (head); \ + (iter) = (iter)->next) \ + +#ifdef RX_HASH_DEBUG +/* Hash cookie related macros */ +#define HTT_RX_HASH_COOKIE 0xDEED + +#define HTT_RX_HASH_COOKIE_SET(hash_element) \ + ((hash_element)->cookie = HTT_RX_HASH_COOKIE) + +#define HTT_RX_HASH_COOKIE_CHECK(hash_element) \ + HTT_ASSERT_ALWAYS((hash_element)->cookie == HTT_RX_HASH_COOKIE) + +/* Hash count related macros */ +#define HTT_RX_HASH_COUNT_INCR(hash_bucket) \ + ((hash_bucket)->count++) + +#define HTT_RX_HASH_COUNT_DECR(hash_bucket) \ + ((hash_bucket)->count--) + +#define HTT_RX_HASH_COUNT_RESET(hash_bucket) ((hash_bucket)->count = 0) + +#define HTT_RX_HASH_COUNT_PRINT(hash_bucket) \ + RX_HASH_LOG(qdf_print(" count %d\n", (hash_bucket)->count)) +#else /* RX_HASH_DEBUG */ +/* Hash cookie related macros */ +#define HTT_RX_HASH_COOKIE_SET(hash_element) /* no-op */ +#define HTT_RX_HASH_COOKIE_CHECK(hash_element) /* no-op */ +/* Hash count related macros */ +#define HTT_RX_HASH_COUNT_INCR(hash_bucket) /* no-op */ +#define HTT_RX_HASH_COUNT_DECR(hash_bucket) /* no-op */ +#define HTT_RX_HASH_COUNT_PRINT(hash_bucket) /* no-op */ +#define HTT_RX_HASH_COUNT_RESET(hash_bucket) /* no-op */ +#endif /* RX_HASH_DEBUG */ + +/* Inserts the given "physical address - network buffer" pair into the + hash table for the given pdev. This function will do the following: + 1. Determine which bucket to insert the pair into + 2. First try to allocate the hash entry for this pair from the pre-allocated + entries list + 3. If there are no more entries in the pre-allocated entries list, allocate + the hash entry from the hash memory pool + Note: this function is not thread-safe + Returns 0 - success, 1 - failure */ +int +htt_rx_hash_list_insert(struct htt_pdev_t *pdev, + qdf_dma_addr_t paddr, + qdf_nbuf_t netbuf) +{ + int i; + int rc = 0; + struct htt_rx_hash_entry *hash_element = NULL; + + qdf_spin_lock_bh(&(pdev->rx_ring.rx_hash_lock)); + + /* get rid of the marking bits if they are available */ + paddr = htt_paddr_trim_to_37(paddr); + + i = RX_HASH_FUNCTION(paddr); + + /* Check if there are any entries in the pre-allocated free list */ + if (pdev->rx_ring.hash_table[i]->freepool.next != + &pdev->rx_ring.hash_table[i]->freepool) { + + hash_element = + (struct htt_rx_hash_entry *)( + (char *) + pdev->rx_ring.hash_table[i]->freepool.next - + pdev->rx_ring.listnode_offset); + if (qdf_unlikely(NULL == hash_element)) { + HTT_ASSERT_ALWAYS(0); + rc = 1; + goto hli_end; + } + + htt_list_remove(pdev->rx_ring.hash_table[i]->freepool.next); + } else { + hash_element = qdf_mem_malloc(sizeof(struct htt_rx_hash_entry)); + if (qdf_unlikely(NULL == hash_element)) { + HTT_ASSERT_ALWAYS(0); + rc = 1; + goto hli_end; + } + hash_element->fromlist = 0; + } + + hash_element->netbuf = netbuf; + hash_element->paddr = paddr; + HTT_RX_HASH_COOKIE_SET(hash_element); + + htt_list_add_tail(&pdev->rx_ring.hash_table[i]->listhead, + &hash_element->listnode); + + RX_HASH_LOG(qdf_print("rx hash: %s: paddr 0x%x netbuf %p bucket %d\n", + __func__, paddr, netbuf, (int)i)); + + HTT_RX_HASH_COUNT_INCR(pdev->rx_ring.hash_table[i]); + HTT_RX_HASH_COUNT_PRINT(pdev->rx_ring.hash_table[i]); + +hli_end: + qdf_spin_unlock_bh(&(pdev->rx_ring.rx_hash_lock)); + return rc; +} + +/* + * Given a physical address this function will find the corresponding network + * buffer from the hash table. + * paddr is already stripped off of higher marking bits. + */ +qdf_nbuf_t htt_rx_hash_list_lookup(struct htt_pdev_t *pdev, + qdf_dma_addr_t paddr) +{ + uint32_t i; + struct htt_list_node *list_iter = NULL; + qdf_nbuf_t netbuf = NULL; + struct htt_rx_hash_entry *hash_entry; + + qdf_spin_lock_bh(&(pdev->rx_ring.rx_hash_lock)); + + if (!pdev->rx_ring.hash_table) + return NULL; + + i = RX_HASH_FUNCTION(paddr); + + HTT_LIST_ITER_FWD(list_iter, &pdev->rx_ring.hash_table[i]->listhead) { + hash_entry = (struct htt_rx_hash_entry *) + ((char *)list_iter - + pdev->rx_ring.listnode_offset); + + HTT_RX_HASH_COOKIE_CHECK(hash_entry); + + if (hash_entry->paddr == paddr) { + /* Found the entry corresponding to paddr */ + netbuf = hash_entry->netbuf; + /* set netbuf to NULL to trace if freed entry + * is getting unmapped in hash deinit. + */ + hash_entry->netbuf = NULL; + htt_list_remove(&hash_entry->listnode); + HTT_RX_HASH_COUNT_DECR(pdev->rx_ring.hash_table[i]); + /* if the rx entry is from the pre-allocated list, + return it */ + if (hash_entry->fromlist) + htt_list_add_tail(&pdev->rx_ring.hash_table[i]->freepool, + &hash_entry->listnode); + else + qdf_mem_free(hash_entry); + + htt_rx_dbg_rxbuf_reset(pdev, netbuf); + break; + } + } + + RX_HASH_LOG(qdf_print("rx hash: %s: paddr 0x%x, netbuf %p, bucket %d\n", + __func__, paddr, netbuf, (int)i)); + HTT_RX_HASH_COUNT_PRINT(pdev->rx_ring.hash_table[i]); + + qdf_spin_unlock_bh(&(pdev->rx_ring.rx_hash_lock)); + + if (netbuf == NULL) { + qdf_print("rx hash: %s: no entry found for %p!\n", + __func__, (void *)paddr); + HTT_ASSERT_ALWAYS(0); + } + + return netbuf; +} + +#ifndef CONFIG_HL_SUPPORT +/* Initialization function of the rx buffer hash table. This function will + allocate a hash table of a certain pre-determined size and initialize all + the elements */ +static int htt_rx_hash_init(struct htt_pdev_t *pdev) +{ + int i, j; + int rc = 0; + void *allocation; + + HTT_ASSERT2(QDF_IS_PWR2(RX_NUM_HASH_BUCKETS)); + + /* hash table is array of bucket pointers */ + pdev->rx_ring.hash_table = + qdf_mem_malloc(RX_NUM_HASH_BUCKETS * + sizeof(struct htt_rx_hash_bucket *)); + + if (NULL == pdev->rx_ring.hash_table) { + qdf_print("rx hash table allocation failed!\n"); + return 1; + } + + qdf_spinlock_create(&(pdev->rx_ring.rx_hash_lock)); + qdf_spin_lock_bh(&(pdev->rx_ring.rx_hash_lock)); + + for (i = 0; i < RX_NUM_HASH_BUCKETS; i++) { + + qdf_spin_unlock_bh(&(pdev->rx_ring.rx_hash_lock)); + /* pre-allocate bucket and pool of entries for this bucket */ + allocation = qdf_mem_malloc((sizeof(struct htt_rx_hash_bucket) + + (RX_ENTRIES_SIZE * sizeof(struct htt_rx_hash_entry)))); + qdf_spin_lock_bh(&(pdev->rx_ring.rx_hash_lock)); + pdev->rx_ring.hash_table[i] = allocation; + + + HTT_RX_HASH_COUNT_RESET(pdev->rx_ring.hash_table[i]); + + /* initialize the hash table buckets */ + htt_list_init(&pdev->rx_ring.hash_table[i]->listhead); + + /* initialize the hash table free pool per bucket */ + htt_list_init(&pdev->rx_ring.hash_table[i]->freepool); + + /* pre-allocate a pool of entries for this bucket */ + pdev->rx_ring.hash_table[i]->entries = + (struct htt_rx_hash_entry *) + ((uint8_t *)pdev->rx_ring.hash_table[i] + + sizeof(struct htt_rx_hash_bucket)); + + if (NULL == pdev->rx_ring.hash_table[i]->entries) { + qdf_print("rx hash bucket %d entries alloc failed\n", + (int)i); + while (i) { + i--; + qdf_mem_free(pdev->rx_ring.hash_table[i]); + } + qdf_mem_free(pdev->rx_ring.hash_table); + pdev->rx_ring.hash_table = NULL; + rc = 1; + goto hi_end; + } + + /* initialize the free list with pre-allocated entries */ + for (j = 0; j < RX_ENTRIES_SIZE; j++) { + pdev->rx_ring.hash_table[i]->entries[j].fromlist = 1; + htt_list_add_tail(&pdev->rx_ring.hash_table[i]->freepool, + &pdev->rx_ring.hash_table[i]-> + entries[j].listnode); + } + } + + pdev->rx_ring.listnode_offset = + qdf_offsetof(struct htt_rx_hash_entry, listnode); +hi_end: + qdf_spin_unlock_bh(&(pdev->rx_ring.rx_hash_lock)); + + return rc; +} +#endif + +/*--- RX In Order Hash Code --------------------------------------------------*/ + +/* move the function to the end of file + * to omit ll/hl pre-declaration + */ + +#if defined(CONFIG_HL_SUPPORT) + +int htt_rx_attach(struct htt_pdev_t *pdev) +{ + pdev->rx_ring.size = HTT_RX_RING_SIZE_MIN; + HTT_ASSERT2(IS_PWR2(pdev->rx_ring.size)); + pdev->rx_ring.size_mask = pdev->rx_ring.size - 1; + /* host can force ring base address if it wish to do so */ + pdev->rx_ring.base_paddr = 0; + htt_rx_amsdu_pop = htt_rx_amsdu_pop_hl; + htt_rx_frag_pop = htt_rx_frag_pop_hl; + htt_rx_offload_msdu_pop = htt_rx_offload_msdu_pop_hl; + htt_rx_mpdu_desc_list_next = htt_rx_mpdu_desc_list_next_hl; + htt_rx_mpdu_desc_retry = htt_rx_mpdu_desc_retry_hl; + htt_rx_mpdu_desc_seq_num = htt_rx_mpdu_desc_seq_num_hl; + htt_rx_mpdu_desc_pn = htt_rx_mpdu_desc_pn_hl; + htt_rx_mpdu_desc_tid = htt_rx_mpdu_desc_tid_hl; + htt_rx_msdu_desc_completes_mpdu = htt_rx_msdu_desc_completes_mpdu_hl; + htt_rx_msdu_first_msdu_flag = htt_rx_msdu_first_msdu_flag_hl; + htt_rx_msdu_has_wlan_mcast_flag = htt_rx_msdu_has_wlan_mcast_flag_hl; + htt_rx_msdu_is_wlan_mcast = htt_rx_msdu_is_wlan_mcast_hl; + htt_rx_msdu_is_frag = htt_rx_msdu_is_frag_hl; + htt_rx_msdu_desc_retrieve = htt_rx_msdu_desc_retrieve_hl; + htt_rx_mpdu_is_encrypted = htt_rx_mpdu_is_encrypted_hl; + htt_rx_msdu_desc_key_id = htt_rx_msdu_desc_key_id_hl; + htt_rx_msdu_chan_info_present = htt_rx_msdu_chan_info_present_hl; + htt_rx_msdu_center_freq = htt_rx_msdu_center_freq_hl; + + /* + * HL case, the rx descriptor can be different sizes for + * different sub-types of RX_IND messages, e.g. for the + * initial vs. interior vs. final MSDUs within a PPDU. + * The size of each RX_IND message's rx desc is read from + * a field within the RX_IND message itself. + * In the meantime, until the rx_desc_size_hl variable is + * set to its real value based on the RX_IND message, + * initialize it to a reasonable value (zero). + */ + pdev->rx_desc_size_hl = 0; + return 0; /* success */ +} + +#else + +int htt_rx_attach(struct htt_pdev_t *pdev) +{ + qdf_dma_addr_t paddr; + uint32_t ring_elem_size = sizeof(target_paddr_t); + + pdev->rx_ring.size = htt_rx_ring_size(pdev); + HTT_ASSERT2(QDF_IS_PWR2(pdev->rx_ring.size)); + pdev->rx_ring.size_mask = pdev->rx_ring.size - 1; + + /* + * Set the initial value for the level to which the rx ring + * should be filled, based on the max throughput and the worst + * likely latency for the host to fill the rx ring. + * In theory, this fill level can be dynamically adjusted from + * the initial value set here to reflect the actual host latency + * rather than a conservative assumption. + */ + pdev->rx_ring.fill_level = htt_rx_ring_fill_level(pdev); + + if (pdev->cfg.is_full_reorder_offload) { + if (htt_rx_hash_init(pdev)) + goto fail1; + + /* allocate the target index */ + pdev->rx_ring.target_idx.vaddr = + qdf_mem_alloc_consistent(pdev->osdev, pdev->osdev->dev, + sizeof(uint32_t), + &paddr); + + if (!pdev->rx_ring.target_idx.vaddr) + goto fail2; + + pdev->rx_ring.target_idx.paddr = paddr; + *pdev->rx_ring.target_idx.vaddr = 0; + } else { + pdev->rx_ring.buf.netbufs_ring = + qdf_mem_malloc(pdev->rx_ring.size * sizeof(qdf_nbuf_t)); + if (!pdev->rx_ring.buf.netbufs_ring) + goto fail1; + + pdev->rx_ring.sw_rd_idx.msdu_payld = 0; + pdev->rx_ring.sw_rd_idx.msdu_desc = 0; + } + + pdev->rx_ring.buf.paddrs_ring = + qdf_mem_alloc_consistent( + pdev->osdev, pdev->osdev->dev, + pdev->rx_ring.size * ring_elem_size, + &paddr); + if (!pdev->rx_ring.buf.paddrs_ring) + goto fail3; + + pdev->rx_ring.base_paddr = paddr; + pdev->rx_ring.alloc_idx.vaddr = + qdf_mem_alloc_consistent( + pdev->osdev, pdev->osdev->dev, + sizeof(uint32_t), &paddr); + + if (!pdev->rx_ring.alloc_idx.vaddr) + goto fail4; + + pdev->rx_ring.alloc_idx.paddr = paddr; + *pdev->rx_ring.alloc_idx.vaddr = 0; + + /* + * Initialize the Rx refill reference counter to be one so that + * only one thread is allowed to refill the Rx ring. + */ + qdf_atomic_init(&pdev->rx_ring.refill_ref_cnt); + qdf_atomic_inc(&pdev->rx_ring.refill_ref_cnt); + + /* Initialize the refill_lock and debt (for rx-parallelization) */ + qdf_spinlock_create(&(pdev->rx_ring.refill_lock)); + qdf_atomic_init(&pdev->rx_ring.refill_debt); + + + /* Initialize the Rx refill retry timer */ + qdf_timer_init(pdev->osdev, + &pdev->rx_ring.refill_retry_timer, + htt_rx_ring_refill_retry, (void *)pdev, + QDF_TIMER_TYPE_SW); + + pdev->rx_ring.fill_cnt = 0; +#ifdef DEBUG_DMA_DONE + pdev->rx_ring.dbg_ring_idx = 0; + pdev->rx_ring.dbg_refill_cnt = 0; + pdev->rx_ring.dbg_sync_success = 0; +#endif +#ifdef HTT_RX_RESTORE + pdev->rx_ring.rx_reset = 0; + pdev->rx_ring.htt_rx_restore = 0; +#endif + htt_rx_dbg_rxbuf_init(pdev); + htt_rx_ring_fill_n(pdev, pdev->rx_ring.fill_level); + + if (pdev->cfg.is_full_reorder_offload) { + qdf_print("HTT: full reorder offload enabled\n"); + htt_rx_amsdu_pop = htt_rx_amsdu_rx_in_order_pop_ll; + htt_rx_frag_pop = htt_rx_amsdu_rx_in_order_pop_ll; + htt_rx_mpdu_desc_list_next = + htt_rx_in_ord_mpdu_desc_list_next_ll; + } else { + htt_rx_amsdu_pop = htt_rx_amsdu_pop_ll; + htt_rx_frag_pop = htt_rx_amsdu_pop_ll; + htt_rx_mpdu_desc_list_next = htt_rx_mpdu_desc_list_next_ll; + } + + if (cds_get_conparam() == QDF_GLOBAL_MONITOR_MODE) + htt_rx_amsdu_pop = htt_rx_mon_amsdu_rx_in_order_pop_ll; + + htt_rx_offload_msdu_pop = htt_rx_offload_msdu_pop_ll; + htt_rx_mpdu_desc_retry = htt_rx_mpdu_desc_retry_ll; + htt_rx_mpdu_desc_seq_num = htt_rx_mpdu_desc_seq_num_ll; + htt_rx_mpdu_desc_pn = htt_rx_mpdu_desc_pn_ll; + htt_rx_mpdu_desc_tid = htt_rx_mpdu_desc_tid_ll; + htt_rx_msdu_desc_completes_mpdu = htt_rx_msdu_desc_completes_mpdu_ll; + htt_rx_msdu_first_msdu_flag = htt_rx_msdu_first_msdu_flag_ll; + htt_rx_msdu_has_wlan_mcast_flag = htt_rx_msdu_has_wlan_mcast_flag_ll; + htt_rx_msdu_is_wlan_mcast = htt_rx_msdu_is_wlan_mcast_ll; + htt_rx_msdu_is_frag = htt_rx_msdu_is_frag_ll; + htt_rx_msdu_desc_retrieve = htt_rx_msdu_desc_retrieve_ll; + htt_rx_mpdu_is_encrypted = htt_rx_mpdu_is_encrypted_ll; + htt_rx_msdu_desc_key_id = htt_rx_msdu_desc_key_id_ll; + htt_rx_msdu_chan_info_present = htt_rx_msdu_chan_info_present_ll; + htt_rx_msdu_center_freq = htt_rx_msdu_center_freq_ll; + + return 0; /* success */ + +fail4: + qdf_mem_free_consistent(pdev->osdev, pdev->osdev->dev, + pdev->rx_ring.size * sizeof(target_paddr_t), + pdev->rx_ring.buf.paddrs_ring, + pdev->rx_ring.base_paddr, + qdf_get_dma_mem_context((&pdev->rx_ring.buf), + memctx)); + +fail3: + if (pdev->cfg.is_full_reorder_offload) + qdf_mem_free_consistent(pdev->osdev, pdev->osdev->dev, + sizeof(uint32_t), + pdev->rx_ring.target_idx.vaddr, + pdev->rx_ring.target_idx.paddr, + qdf_get_dma_mem_context((&pdev-> + rx_ring. + target_idx), + memctx)); + else + qdf_mem_free(pdev->rx_ring.buf.netbufs_ring); + +fail2: + if (pdev->cfg.is_full_reorder_offload) + htt_rx_hash_deinit(pdev); + +fail1: + return 1; /* failure */ +} +#endif + +#ifdef IPA_OFFLOAD +#ifdef QCA_WIFI_3_0 +/** + * htt_rx_ipa_uc_alloc_wdi2_rsc() - Allocate WDI2.0 resources + * @pdev: htt context + * @rx_ind_ring_elements: rx ring elements + * + * Return: 0 success + */ +static int htt_rx_ipa_uc_alloc_wdi2_rsc(struct htt_pdev_t *pdev, + unsigned int rx_ind_ring_elements) +{ + /* Allocate RX2 indication ring */ + /* RX2 IND ring element + * 4bytes: pointer + * 2bytes: VDEV ID + * 2bytes: length */ + /* RX indication ring size, by bytes */ + pdev->ipa_uc_rx_rsc.rx2_ind_ring_size = + rx_ind_ring_elements * sizeof(target_paddr_t); + pdev->ipa_uc_rx_rsc.rx2_ind_ring_base.vaddr = + qdf_mem_alloc_consistent( + pdev->osdev, pdev->osdev->dev, + pdev->ipa_uc_rx_rsc.rx2_ind_ring_size, + &pdev->ipa_uc_rx_rsc.rx2_ind_ring_base.paddr); + if (!pdev->ipa_uc_rx_rsc.rx2_ind_ring_base.vaddr) { + qdf_print("%s: RX IND RING alloc fail", __func__); + return -ENOBUFS; + } + + qdf_mem_zero(pdev->ipa_uc_rx_rsc.rx2_ind_ring_base.vaddr, + pdev->ipa_uc_rx_rsc.rx2_ind_ring_size); + + /* Allocate RX process done index */ + pdev->ipa_uc_rx_rsc.rx2_ipa_prc_done_idx.vaddr = + qdf_mem_alloc_consistent( + pdev->osdev, pdev->osdev->dev, 4, + &pdev->ipa_uc_rx_rsc.rx2_ipa_prc_done_idx.paddr); + if (!pdev->ipa_uc_rx_rsc.rx2_ipa_prc_done_idx.vaddr) { + qdf_print("%s: RX PROC DONE IND alloc fail", __func__); + qdf_mem_free_consistent( + pdev->osdev, pdev->osdev->dev, + pdev->ipa_uc_rx_rsc.rx2_ind_ring_size, + pdev->ipa_uc_rx_rsc.rx2_ind_ring_base.vaddr, + pdev->ipa_uc_rx_rsc.rx2_ind_ring_base.paddr, + qdf_get_dma_mem_context((&pdev->ipa_uc_rx_rsc. + rx2_ind_ring_base), + memctx)); + return -ENOBUFS; + } + qdf_mem_zero(pdev->ipa_uc_rx_rsc.rx2_ipa_prc_done_idx.vaddr, 4); + return 0; +} +#else +static int htt_rx_ipa_uc_alloc_wdi2_rsc(struct htt_pdev_t *pdev, + unsigned int rx_ind_ring_elements) +{ + return 0; +} +#endif + +/** + * htt_rx_ipa_uc_attach() - attach htt ipa uc rx resource + * @pdev: htt context + * @rx_ind_ring_size: rx ring size + * + * Return: 0 success + */ +int htt_rx_ipa_uc_attach(struct htt_pdev_t *pdev, + unsigned int rx_ind_ring_elements) +{ + int ret = 0; + + /* Allocate RX indication ring */ + /* RX IND ring element + * 4bytes: pointer + * 2bytes: VDEV ID + * 2bytes: length */ + pdev->ipa_uc_rx_rsc.rx_ind_ring_base.vaddr = + qdf_mem_alloc_consistent( + pdev->osdev, + pdev->osdev->dev, + rx_ind_ring_elements * + sizeof(struct ipa_uc_rx_ring_elem_t), + &pdev->ipa_uc_rx_rsc.rx_ind_ring_base.paddr); + if (!pdev->ipa_uc_rx_rsc.rx_ind_ring_base.vaddr) { + qdf_print("%s: RX IND RING alloc fail", __func__); + return -ENOBUFS; + } + + /* RX indication ring size, by bytes */ + pdev->ipa_uc_rx_rsc.rx_ind_ring_size = + rx_ind_ring_elements * sizeof(struct ipa_uc_rx_ring_elem_t); + qdf_mem_zero(pdev->ipa_uc_rx_rsc.rx_ind_ring_base.vaddr, + pdev->ipa_uc_rx_rsc.rx_ind_ring_size); + + /* Allocate RX process done index */ + pdev->ipa_uc_rx_rsc.rx_ipa_prc_done_idx.vaddr = + qdf_mem_alloc_consistent( + pdev->osdev, pdev->osdev->dev, 4, + &pdev->ipa_uc_rx_rsc.rx_ipa_prc_done_idx.paddr); + if (!pdev->ipa_uc_rx_rsc.rx_ipa_prc_done_idx.vaddr) { + qdf_print("%s: RX PROC DONE IND alloc fail", __func__); + qdf_mem_free_consistent( + pdev->osdev, pdev->osdev->dev, + pdev->ipa_uc_rx_rsc.rx_ind_ring_size, + pdev->ipa_uc_rx_rsc.rx_ind_ring_base.vaddr, + pdev->ipa_uc_rx_rsc.rx_ind_ring_base.paddr, + qdf_get_dma_mem_context((&pdev->ipa_uc_rx_rsc. + rx_ind_ring_base), + memctx)); + return -ENOBUFS; + } + qdf_mem_zero(pdev->ipa_uc_rx_rsc.rx_ipa_prc_done_idx.vaddr, 4); + + ret = htt_rx_ipa_uc_alloc_wdi2_rsc(pdev, rx_ind_ring_elements); + return ret; +} + +#ifdef QCA_WIFI_3_0 +/** + * htt_rx_ipa_uc_free_wdi2_rsc() - Free WDI2.0 resources + * @pdev: htt context + * + * Return: None + */ +static void htt_rx_ipa_uc_free_wdi2_rsc(struct htt_pdev_t *pdev) +{ + if (pdev->ipa_uc_rx_rsc.rx2_ind_ring_base.vaddr) { + qdf_mem_free_consistent( + pdev->osdev, pdev->osdev->dev, + pdev->ipa_uc_rx_rsc.rx2_ind_ring_size, + pdev->ipa_uc_rx_rsc.rx2_ind_ring_base.vaddr, + pdev->ipa_uc_rx_rsc.rx2_ind_ring_base.paddr, + qdf_get_dma_mem_context((&pdev->ipa_uc_rx_rsc. + rx2_ind_ring_base), + memctx)); + } + + if (pdev->ipa_uc_rx_rsc.rx2_ipa_prc_done_idx.vaddr) { + qdf_mem_free_consistent( + pdev->osdev, pdev->osdev->dev, + 4, + pdev->ipa_uc_rx_rsc. + rx2_ipa_prc_done_idx.vaddr, + pdev->ipa_uc_rx_rsc.rx2_ipa_prc_done_idx.paddr, + qdf_get_dma_mem_context((&pdev->ipa_uc_rx_rsc. + rx2_ipa_prc_done_idx), + memctx)); + } +} +#else +static void htt_rx_ipa_uc_free_wdi2_rsc(struct htt_pdev_t *pdev) +{ + return; +} +#endif + +int htt_rx_ipa_uc_detach(struct htt_pdev_t *pdev) +{ + if (pdev->ipa_uc_rx_rsc.rx_ind_ring_base.vaddr) { + qdf_mem_free_consistent( + pdev->osdev, pdev->osdev->dev, + pdev->ipa_uc_rx_rsc.rx_ind_ring_size, + pdev->ipa_uc_rx_rsc.rx_ind_ring_base.vaddr, + pdev->ipa_uc_rx_rsc.rx_ind_ring_base.paddr, + qdf_get_dma_mem_context((&pdev->ipa_uc_rx_rsc. + rx_ind_ring_base), + memctx)); + } + + if (pdev->ipa_uc_rx_rsc.rx_ipa_prc_done_idx.vaddr) { + qdf_mem_free_consistent( + pdev->osdev, pdev->osdev->dev, + 4, + pdev->ipa_uc_rx_rsc. + rx_ipa_prc_done_idx.vaddr, + pdev->ipa_uc_rx_rsc.rx_ipa_prc_done_idx.paddr, + qdf_get_dma_mem_context((&pdev->ipa_uc_rx_rsc. + rx2_ipa_prc_done_idx), + memctx)); + } + + htt_rx_ipa_uc_free_wdi2_rsc(pdev); + return 0; +} +#endif /* IPA_OFFLOAD */ + +/** + * htt_register_rx_pkt_dump_callback() - registers callback to + * get rx pkt status and call callback to do rx packet dump + * + * @pdev: htt pdev handle + * @callback: callback to get rx pkt status and + * call callback to do rx packet dump + * + * This function is used to register the callback to get + * rx pkt status and call callback to do rx packet dump + * + * Return: None + * + */ +void htt_register_rx_pkt_dump_callback(struct htt_pdev_t *pdev, + tp_rx_pkt_dump_cb callback) +{ + if (!pdev) { + qdf_print("%s: htt pdev is NULL, rx packet status callback register unsuccessful\n", + __func__); + return; + } + pdev->rx_pkt_dump_cb = callback; +} + +/** + * htt_deregister_rx_pkt_dump_callback() - deregisters callback to + * get rx pkt status and call callback to do rx packet dump + * + * @pdev: htt pdev handle + * + * This function is used to deregister the callback to get + * rx pkt status and call callback to do rx packet dump + * + * Return: None + * + */ +void htt_deregister_rx_pkt_dump_callback(struct htt_pdev_t *pdev) +{ + if (!pdev) { + qdf_print("%s: htt pdev is NULL, rx packet status callback deregister unsuccessful\n", + __func__); + return; + } + pdev->rx_pkt_dump_cb = NULL; +} diff --git a/drivers/staging/qcacld-3.0/core/dp/htt/htt_t2h.c b/drivers/staging/qcacld-3.0/core/dp/htt/htt_t2h.c new file mode 100644 index 0000000000000000000000000000000000000000..ab1293ea80e5026f1addb356252832670943f786 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/dp/htt/htt_t2h.c @@ -0,0 +1,1320 @@ +/* + * Copyright (c) 2011-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * @file htt_t2h.c + * @brief Provide functions to process target->host HTT messages. + * @details + * This file contains functions related to target->host HTT messages. + * There are two categories of functions: + * 1. A function that receives a HTT message from HTC, and dispatches it + * based on the HTT message type. + * 2. functions that provide the info elements from specific HTT messages. + */ +#include +#include /* HTC_PACKET */ +#include /* HTT_T2H_MSG_TYPE, etc. */ +#include /* qdf_nbuf_t */ + +#include +#include +#include /* htt_tx_status */ + +#include /* HTT_TX_SCHED, etc. */ +#include +#include +#include +#include +#include +#include "pktlog_ac.h" + +/*--- target->host HTT message dispatch function ----------------------------*/ + +#ifndef DEBUG_CREDIT +#define DEBUG_CREDIT 0 +#endif + +#if defined(CONFIG_HL_SUPPORT) + + + +/** + * htt_rx_frag_set_last_msdu() - set last msdu bit in rx descriptor + * for recieved frames + * @pdev: Handle (pointer) to HTT pdev. + * @msg: htt recieved msg + * + * Return: None + */ +static inline +void htt_rx_frag_set_last_msdu(struct htt_pdev_t *pdev, qdf_nbuf_t msg) +{ + return; +} +#else + +static void htt_rx_frag_set_last_msdu(struct htt_pdev_t *pdev, qdf_nbuf_t msg) +{ + uint32_t *msg_word; + unsigned num_msdu_bytes; + qdf_nbuf_t msdu; + struct htt_host_rx_desc_base *rx_desc; + int start_idx; + uint8_t *p_fw_msdu_rx_desc = 0; + + msg_word = (uint32_t *) qdf_nbuf_data(msg); + num_msdu_bytes = HTT_RX_FRAG_IND_FW_RX_DESC_BYTES_GET( + *(msg_word + HTT_RX_FRAG_IND_HDR_PREFIX_SIZE32)); + /* + * 1 word for the message header, + * 1 word to specify the number of MSDU bytes, + * 1 word for every 4 MSDU bytes (round up), + * 1 word for the MPDU range header + */ + pdev->rx_mpdu_range_offset_words = 3 + ((num_msdu_bytes + 3) >> 2); + pdev->rx_ind_msdu_byte_idx = 0; + + p_fw_msdu_rx_desc = ((uint8_t *) (msg_word) + + HTT_ENDIAN_BYTE_IDX_SWAP + (HTT_RX_FRAG_IND_FW_DESC_BYTE_OFFSET)); + + /* + * Fix for EV126710, in which BSOD occurs due to last_msdu bit + * not set while the next pointer is deliberately set to NULL + * before calling ol_rx_pn_check_base() + * + * For fragment frames, the HW may not have set the last_msdu bit + * in the rx descriptor, but the SW expects this flag to be set, + * since each fragment is in a separate MPDU. Thus, set the flag here, + * just in case the HW didn't. + */ + start_idx = pdev->rx_ring.sw_rd_idx.msdu_payld; + msdu = pdev->rx_ring.buf.netbufs_ring[start_idx]; + qdf_nbuf_set_pktlen(msdu, HTT_RX_BUF_SIZE); + qdf_nbuf_unmap(pdev->osdev, msdu, QDF_DMA_FROM_DEVICE); + rx_desc = htt_rx_desc(msdu); + *((uint8_t *) &rx_desc->fw_desc.u.val) = *p_fw_msdu_rx_desc; + rx_desc->msdu_end.last_msdu = 1; + qdf_nbuf_map(pdev->osdev, msdu, QDF_DMA_FROM_DEVICE); +} +#endif + +static uint8_t *htt_t2h_mac_addr_deswizzle(uint8_t *tgt_mac_addr, + uint8_t *buffer) +{ +#ifdef BIG_ENDIAN_HOST + /* + * The host endianness is opposite of the target endianness. + * To make uint32_t elements come out correctly, the target->host + * upload has swizzled the bytes in each uint32_t element of the + * message. + * For byte-array message fields like the MAC address, this + * upload swizzling puts the bytes in the wrong order, and needs + * to be undone. + */ + buffer[0] = tgt_mac_addr[3]; + buffer[1] = tgt_mac_addr[2]; + buffer[2] = tgt_mac_addr[1]; + buffer[3] = tgt_mac_addr[0]; + buffer[4] = tgt_mac_addr[7]; + buffer[5] = tgt_mac_addr[6]; + return buffer; +#else + /* + * The host endianness matches the target endianness - + * we can use the mac addr directly from the message buffer. + */ + return tgt_mac_addr; +#endif +} + +/* Target to host Msg/event handler for low priority messages*/ +static void htt_t2h_lp_msg_handler(void *context, qdf_nbuf_t htt_t2h_msg, + bool free_msg_buf) +{ + struct htt_pdev_t *pdev = (struct htt_pdev_t *)context; + uint32_t *msg_word; + enum htt_t2h_msg_type msg_type; + + msg_word = (uint32_t *) qdf_nbuf_data(htt_t2h_msg); + msg_type = HTT_T2H_MSG_TYPE_GET(*msg_word); + switch (msg_type) { + case HTT_T2H_MSG_TYPE_VERSION_CONF: + { + htc_pm_runtime_put(pdev->htc_pdev); + pdev->tgt_ver.major = HTT_VER_CONF_MAJOR_GET(*msg_word); + pdev->tgt_ver.minor = HTT_VER_CONF_MINOR_GET(*msg_word); + qdf_print + ("target uses HTT version %d.%d; host uses %d.%d", + pdev->tgt_ver.major, pdev->tgt_ver.minor, + HTT_CURRENT_VERSION_MAJOR, + HTT_CURRENT_VERSION_MINOR); + if (pdev->tgt_ver.major != HTT_CURRENT_VERSION_MAJOR) + qdf_print + ("*** Incompatible host/target HTT versions!"); + /* abort if the target is incompatible with the host */ + qdf_assert(pdev->tgt_ver.major == + HTT_CURRENT_VERSION_MAJOR); + if (pdev->tgt_ver.minor != HTT_CURRENT_VERSION_MINOR) { + qdf_print("*** Warning: host/target HTT versions are "); + qdf_print(" different, though compatible!"); + } + break; + } + case HTT_T2H_MSG_TYPE_RX_FLUSH: + { + uint16_t peer_id; + uint8_t tid; + int seq_num_start, seq_num_end; + enum htt_rx_flush_action action; + + peer_id = HTT_RX_FLUSH_PEER_ID_GET(*msg_word); + tid = HTT_RX_FLUSH_TID_GET(*msg_word); + seq_num_start = + HTT_RX_FLUSH_SEQ_NUM_START_GET(*(msg_word + 1)); + seq_num_end = + HTT_RX_FLUSH_SEQ_NUM_END_GET(*(msg_word + 1)); + action = + HTT_RX_FLUSH_MPDU_STATUS_GET(*(msg_word + 1)) == + 1 ? htt_rx_flush_release : htt_rx_flush_discard; + ol_rx_flush_handler(pdev->txrx_pdev, peer_id, tid, + seq_num_start, seq_num_end, action); + break; + } + case HTT_T2H_MSG_TYPE_RX_OFFLOAD_DELIVER_IND: + { + int msdu_cnt; + msdu_cnt = + HTT_RX_OFFLOAD_DELIVER_IND_MSDU_CNT_GET(*msg_word); + ol_rx_offload_deliver_ind_handler(pdev->txrx_pdev, + htt_t2h_msg, + msdu_cnt); + if (pdev->cfg.is_high_latency) { + /* + * return here for HL to avoid double free on + * htt_t2h_msg + */ + return; + } else { + break; + } + } + case HTT_T2H_MSG_TYPE_RX_FRAG_IND: + { + uint16_t peer_id; + uint8_t tid; + + peer_id = HTT_RX_FRAG_IND_PEER_ID_GET(*msg_word); + tid = HTT_RX_FRAG_IND_EXT_TID_GET(*msg_word); + htt_rx_frag_set_last_msdu(pdev, htt_t2h_msg); + + /* If packet len is invalid, will discard this frame. */ + if (pdev->cfg.is_high_latency) { + u_int32_t rx_pkt_len = 0; + + rx_pkt_len = qdf_nbuf_len(htt_t2h_msg); + + if (rx_pkt_len < (HTT_RX_FRAG_IND_BYTES + + sizeof(struct hl_htt_rx_ind_base)+ + sizeof(struct ieee80211_frame))) { + + qdf_print("%s: invalid packet len, %u\n", + __func__, + rx_pkt_len); + /* + * This buf will be freed before + * exiting this function. + */ + break; + } + } + + ol_rx_frag_indication_handler(pdev->txrx_pdev, + htt_t2h_msg, + peer_id, tid); + + if (pdev->cfg.is_high_latency) { + /* + * For high latency solution, + * HTT_T2H_MSG_TYPE_RX_FRAG_IND message and RX packet + * share the same buffer. All buffer will be freed by + * ol_rx_frag_indication_handler or upper layer to + * avoid double free issue. + * + */ + return; + } + + break; + } + case HTT_T2H_MSG_TYPE_RX_ADDBA: + { + uint16_t peer_id; + uint8_t tid; + uint8_t win_sz; + uint16_t start_seq_num; + + /* + * FOR NOW, the host doesn't need to know the initial + * sequence number for rx aggregation. + * Thus, any value will do - specify 0. + */ + start_seq_num = 0; + peer_id = HTT_RX_ADDBA_PEER_ID_GET(*msg_word); + tid = HTT_RX_ADDBA_TID_GET(*msg_word); + win_sz = HTT_RX_ADDBA_WIN_SIZE_GET(*msg_word); + ol_rx_addba_handler(pdev->txrx_pdev, peer_id, tid, + win_sz, start_seq_num, + 0 /* success */); + break; + } + case HTT_T2H_MSG_TYPE_RX_DELBA: + { + uint16_t peer_id; + uint8_t tid; + + peer_id = HTT_RX_DELBA_PEER_ID_GET(*msg_word); + tid = HTT_RX_DELBA_TID_GET(*msg_word); + ol_rx_delba_handler(pdev->txrx_pdev, peer_id, tid); + break; + } + case HTT_T2H_MSG_TYPE_PEER_MAP: + { + uint8_t mac_addr_deswizzle_buf[HTT_MAC_ADDR_LEN]; + uint8_t *peer_mac_addr; + uint16_t peer_id; + uint8_t vdev_id; + + peer_id = HTT_RX_PEER_MAP_PEER_ID_GET(*msg_word); + vdev_id = HTT_RX_PEER_MAP_VDEV_ID_GET(*msg_word); + peer_mac_addr = htt_t2h_mac_addr_deswizzle( + (uint8_t *) (msg_word + 1), + &mac_addr_deswizzle_buf[0]); + + ol_rx_peer_map_handler(pdev->txrx_pdev, peer_id, + vdev_id, peer_mac_addr, + 1 /*can tx */); + break; + } + case HTT_T2H_MSG_TYPE_PEER_UNMAP: + { + uint16_t peer_id; + peer_id = HTT_RX_PEER_UNMAP_PEER_ID_GET(*msg_word); + + ol_rx_peer_unmap_handler(pdev->txrx_pdev, peer_id); + break; + } + case HTT_T2H_MSG_TYPE_SEC_IND: + { + uint16_t peer_id; + enum htt_sec_type sec_type; + int is_unicast; + + peer_id = HTT_SEC_IND_PEER_ID_GET(*msg_word); + sec_type = HTT_SEC_IND_SEC_TYPE_GET(*msg_word); + is_unicast = HTT_SEC_IND_UNICAST_GET(*msg_word); + msg_word++; /* point to the first part of the Michael key */ + ol_rx_sec_ind_handler(pdev->txrx_pdev, peer_id, + sec_type, is_unicast, msg_word, + msg_word + 2); + break; + } + case HTT_T2H_MSG_TYPE_MGMT_TX_COMPL_IND: + { + struct htt_mgmt_tx_compl_ind *compl_msg; + int32_t credit_delta = 1; + + compl_msg = + (struct htt_mgmt_tx_compl_ind *)(msg_word + 1); + + if (pdev->cfg.is_high_latency) { + if (!pdev->cfg.default_tx_comp_req) { + qdf_atomic_add(credit_delta, + &pdev->htt_tx_credit. + target_delta); + credit_delta = htt_tx_credit_update(pdev); + } + if (credit_delta) + ol_tx_target_credit_update( + pdev->txrx_pdev, credit_delta); + } + ol_tx_desc_update_group_credit( + pdev->txrx_pdev, compl_msg->desc_id, 1, + 0, compl_msg->status); + + if (!ol_tx_get_is_mgmt_over_wmi_enabled()) { + ol_tx_single_completion_handler(pdev->txrx_pdev, + compl_msg->status, + compl_msg->desc_id); + htc_pm_runtime_put(pdev->htc_pdev); + HTT_TX_SCHED(pdev); + } else { + qdf_print("Ignoring HTT_T2H_MSG_TYPE_MGMT_TX_COMPL_IND indication"); + } + break; + } + case HTT_T2H_MSG_TYPE_STATS_CONF: + { + uint64_t cookie; + uint8_t *stats_info_list; + + cookie = *(msg_word + 1); + cookie |= ((uint64_t) (*(msg_word + 2))) << 32; + + stats_info_list = (uint8_t *) (msg_word + 3); + htc_pm_runtime_put(pdev->htc_pdev); + ol_txrx_fw_stats_handler(pdev->txrx_pdev, cookie, + stats_info_list); + break; + } +#ifndef REMOVE_PKT_LOG + case HTT_T2H_MSG_TYPE_PKTLOG: + { + pktlog_process_fw_msg(msg_word + 1); + break; + } +#endif + case HTT_T2H_MSG_TYPE_TX_CREDIT_UPDATE_IND: + { + uint32_t htt_credit_delta_abs; + int32_t htt_credit_delta; + int sign; + + htt_credit_delta_abs = + HTT_TX_CREDIT_DELTA_ABS_GET(*msg_word); + sign = HTT_TX_CREDIT_SIGN_BIT_GET(*msg_word) ? -1 : 1; + htt_credit_delta = sign * htt_credit_delta_abs; + + if (pdev->cfg.is_high_latency && + !pdev->cfg.default_tx_comp_req) { + qdf_atomic_add(htt_credit_delta, + &pdev->htt_tx_credit.target_delta); + htt_credit_delta = htt_tx_credit_update(pdev); + } + + htt_tx_group_credit_process(pdev, msg_word); + ol_tx_credit_completion_handler(pdev->txrx_pdev, + htt_credit_delta); + break; + } + + case HTT_T2H_MSG_TYPE_WDI_IPA_OP_RESPONSE: + { + uint8_t op_code; + uint16_t len; + uint8_t *op_msg_buffer; + uint8_t *msg_start_ptr; + + htc_pm_runtime_put(pdev->htc_pdev); + msg_start_ptr = (uint8_t *) msg_word; + op_code = + HTT_WDI_IPA_OP_RESPONSE_OP_CODE_GET(*msg_word); + msg_word++; + len = HTT_WDI_IPA_OP_RESPONSE_RSP_LEN_GET(*msg_word); + + op_msg_buffer = + qdf_mem_malloc(sizeof + (struct htt_wdi_ipa_op_response_t) + + len); + if (!op_msg_buffer) { + qdf_print("OPCODE messsage buffer alloc fail"); + break; + } + qdf_mem_copy(op_msg_buffer, + msg_start_ptr, + sizeof(struct htt_wdi_ipa_op_response_t) + + len); + ol_txrx_ipa_uc_op_response(pdev->txrx_pdev, + op_msg_buffer); + break; + } + + case HTT_T2H_MSG_TYPE_FLOW_POOL_MAP: + { + uint8_t num_flows; + struct htt_flow_pool_map_payload_t *pool_map_payoad; + + num_flows = HTT_FLOW_POOL_MAP_NUM_FLOWS_GET(*msg_word); + + msg_word++; + while (num_flows) { + pool_map_payoad = (struct htt_flow_pool_map_payload_t *) + msg_word; + ol_tx_flow_pool_map_handler(pool_map_payoad->flow_id, + pool_map_payoad->flow_type, + pool_map_payoad->flow_pool_id, + pool_map_payoad->flow_pool_size); + + msg_word += (HTT_FLOW_POOL_MAP_PAYLOAD_SZ / + HTT_FLOW_POOL_MAP_HEADER_SZ); + num_flows--; + } + break; + } + + case HTT_T2H_MSG_TYPE_FLOW_POOL_UNMAP: + { + struct htt_flow_pool_unmap_t *pool_numap_payload; + + pool_numap_payload = (struct htt_flow_pool_unmap_t *)msg_word; + ol_tx_flow_pool_unmap_handler(pool_numap_payload->flow_id, + pool_numap_payload->flow_type, + pool_numap_payload->flow_pool_id); + break; + } + + case HTT_T2H_MSG_TYPE_RX_OFLD_PKT_ERR: + { + switch (HTT_RX_OFLD_PKT_ERR_MSG_SUB_TYPE_GET(*msg_word)) { + case HTT_RX_OFLD_PKT_ERR_TYPE_MIC_ERR: + { + struct ol_error_info err_info; + struct ol_txrx_vdev_t *vdev; + struct ol_txrx_peer_t *peer; + uint16_t peer_id = + HTT_RX_OFLD_PKT_ERR_MIC_ERR_PEER_ID_GET + (*(msg_word + 1)); + + peer = ol_txrx_peer_find_by_id(pdev->txrx_pdev, + peer_id); + if (!peer) { + qdf_print("%s: invalid peer id %d\n", + __func__, peer_id); + qdf_assert(0); + break; + } + vdev = peer->vdev; + err_info.u.mic_err.vdev_id = vdev->vdev_id; + err_info.u.mic_err.key_id = + HTT_RX_OFLD_PKT_ERR_MIC_ERR_KEYID_GET + (*(msg_word + 1)); + qdf_mem_copy(err_info.u.mic_err.da, + (uint8_t *)(msg_word + 2), + OL_TXRX_MAC_ADDR_LEN); + qdf_mem_copy(err_info.u.mic_err.sa, + (uint8_t *)(msg_word + 4), + OL_TXRX_MAC_ADDR_LEN); + qdf_mem_copy(&err_info.u.mic_err.pn, + (uint8_t *)(msg_word + 6), 6); + qdf_mem_copy(err_info.u.mic_err.ta, + peer->mac_addr.raw, OL_TXRX_MAC_ADDR_LEN); + + wma_indicate_err(OL_RX_ERR_TKIP_MIC, &err_info); + break; + } + default: + { + qdf_print("%s: unhandled error type %d\n", + __func__, + HTT_RX_OFLD_PKT_ERR_MSG_SUB_TYPE_GET(*msg_word)); + break; + } + } + } + + default: + break; + }; + /* Free the indication buffer */ + if (free_msg_buf) + qdf_nbuf_free(htt_t2h_msg); +} + +#if defined(CONFIG_HL_SUPPORT) +static inline void htt_t2h_rx_in_order_indication_handler( + ol_txrx_pdev_handle pdev, + qdf_nbuf_t htt_t2h_msg, uint32_t msg_word) +{ +} +#else +static void htt_t2h_rx_in_order_indication_handler( + ol_txrx_pdev_handle pdev, + qdf_nbuf_t htt_t2h_msg, uint32_t msg_word) +{ + u_int16_t peer_id; + u_int8_t tid; + u_int8_t offload_ind, frag_ind; + + peer_id = HTT_RX_IN_ORD_PADDR_IND_PEER_ID_GET(msg_word); + tid = HTT_RX_IN_ORD_PADDR_IND_EXT_TID_GET(msg_word); + offload_ind = HTT_RX_IN_ORD_PADDR_IND_OFFLOAD_GET(msg_word); + frag_ind = HTT_RX_IN_ORD_PADDR_IND_FRAG_GET(msg_word); + +#if defined(HELIUMPLUS_DEBUG) + qdf_print("%s %d: peerid %d tid %d offloadind %d fragind %d\n", + __func__, __LINE__, peer_id, tid, offload_ind, + frag_ind); +#endif + if (qdf_unlikely(frag_ind)) { + ol_rx_frag_indication_handler(pdev, + htt_t2h_msg, + peer_id, tid); + return; + } + + ol_rx_in_order_indication_handler(pdev, + htt_t2h_msg, peer_id, + tid, offload_ind); +} +#endif + +/* Generic Target to host Msg/event handler for low priority messages + Low priority message are handler in a different handler called from + this function . So that the most likely succes path like Rx and + Tx comp has little code foot print + */ +void htt_t2h_msg_handler(void *context, HTC_PACKET *pkt) +{ + struct htt_pdev_t *pdev = (struct htt_pdev_t *)context; + qdf_nbuf_t htt_t2h_msg = (qdf_nbuf_t) pkt->pPktContext; + uint32_t *msg_word; + enum htt_t2h_msg_type msg_type; + + /* check for successful message reception */ + if (pkt->Status != A_OK) { + if (pkt->Status != A_ECANCELED) + pdev->stats.htc_err_cnt++; + qdf_nbuf_free(htt_t2h_msg); + return; + } +#ifdef HTT_RX_RESTORE + if (qdf_unlikely(pdev->rx_ring.rx_reset)) { + qdf_print("rx restore ..\n"); + qdf_nbuf_free(htt_t2h_msg); + return; + } +#endif + + /* confirm alignment */ + HTT_ASSERT3((((unsigned long)qdf_nbuf_data(htt_t2h_msg)) & 0x3) == 0); + + msg_word = (uint32_t *) qdf_nbuf_data(htt_t2h_msg); + msg_type = HTT_T2H_MSG_TYPE_GET(*msg_word); + +#if defined(HELIUMPLUS_DEBUG) + qdf_print("%s %d: msg_word 0x%x msg_type %d", + __func__, __LINE__, *msg_word, msg_type); +#endif + + switch (msg_type) { + case HTT_T2H_MSG_TYPE_RX_IND: + { + unsigned num_mpdu_ranges; + unsigned num_msdu_bytes; + uint16_t peer_id; + uint8_t tid; + + if (qdf_unlikely(pdev->cfg.is_full_reorder_offload)) { + qdf_print("HTT_T2H_MSG_TYPE_RX_IND not supported "); + qdf_print("with full reorder offload\n"); + break; + } + peer_id = HTT_RX_IND_PEER_ID_GET(*msg_word); + tid = HTT_RX_IND_EXT_TID_GET(*msg_word); + + if (tid >= OL_TXRX_NUM_EXT_TIDS) { + qdf_print("HTT_T2H_MSG_TYPE_RX_IND, invalid tid %d\n", + tid); + break; + } + num_msdu_bytes = + HTT_RX_IND_FW_RX_DESC_BYTES_GET( + *(msg_word + 2 + HTT_RX_PPDU_DESC_SIZE32)); + /* + * 1 word for the message header, + * HTT_RX_PPDU_DESC_SIZE32 words for the FW rx PPDU desc + * 1 word to specify the number of MSDU bytes, + * 1 word for every 4 MSDU bytes (round up), + * 1 word for the MPDU range header + */ + pdev->rx_mpdu_range_offset_words = + (HTT_RX_IND_HDR_BYTES + num_msdu_bytes + 3) >> 2; + num_mpdu_ranges = + HTT_RX_IND_NUM_MPDU_RANGES_GET(*(msg_word + 1)); + pdev->rx_ind_msdu_byte_idx = 0; + + ol_rx_indication_handler(pdev->txrx_pdev, + htt_t2h_msg, peer_id, + tid, num_mpdu_ranges); + + if (pdev->cfg.is_high_latency) + return; + + break; + } + case HTT_T2H_MSG_TYPE_TX_COMPL_IND: + { + int num_msdus; + enum htt_tx_status status; + + /* status - no enum translation needed */ + status = HTT_TX_COMPL_IND_STATUS_GET(*msg_word); + num_msdus = HTT_TX_COMPL_IND_NUM_GET(*msg_word); + if (num_msdus & 0x1) { + struct htt_tx_compl_ind_base *compl = + (void *)msg_word; + + /* + * Host CPU endianness can be different from FW CPU. + * This can result in even and odd MSDU IDs being + * switched. If this happens, copy the switched final + * odd MSDU ID from location payload[size], to + * location payload[size-1], where the message + * handler function expects to find it + */ + if (compl->payload[num_msdus] != + HTT_TX_COMPL_INV_MSDU_ID) { + compl->payload[num_msdus - 1] = + compl->payload[num_msdus]; + } + } + + if (pdev->cfg.is_high_latency) { + if (!pdev->cfg.default_tx_comp_req) { + int credit_delta; + + qdf_atomic_add(num_msdus, + &pdev->htt_tx_credit. + target_delta); + credit_delta = htt_tx_credit_update(pdev); + + if (credit_delta) { + ol_tx_target_credit_update( + pdev->txrx_pdev, + credit_delta); + } + } else { + ol_tx_target_credit_update(pdev->txrx_pdev, + num_msdus); + } + } + + ol_tx_completion_handler(pdev->txrx_pdev, num_msdus, + status, msg_word + 1); + HTT_TX_SCHED(pdev); + break; + } + case HTT_T2H_MSG_TYPE_RX_PN_IND: + { + uint16_t peer_id; + uint8_t tid, pn_ie_cnt, *pn_ie = NULL; + int seq_num_start, seq_num_end; + + /*First dword */ + peer_id = HTT_RX_PN_IND_PEER_ID_GET(*msg_word); + tid = HTT_RX_PN_IND_EXT_TID_GET(*msg_word); + + msg_word++; + /*Second dword */ + seq_num_start = + HTT_RX_PN_IND_SEQ_NUM_START_GET(*msg_word); + seq_num_end = HTT_RX_PN_IND_SEQ_NUM_END_GET(*msg_word); + pn_ie_cnt = HTT_RX_PN_IND_PN_IE_CNT_GET(*msg_word); + + msg_word++; + /*Third dword */ + if (pn_ie_cnt) + pn_ie = (uint8_t *) msg_word; + + ol_rx_pn_ind_handler(pdev->txrx_pdev, peer_id, tid, + seq_num_start, seq_num_end, + pn_ie_cnt, pn_ie); + + break; + } + case HTT_T2H_MSG_TYPE_TX_INSPECT_IND: + { + int num_msdus; + + num_msdus = HTT_TX_COMPL_IND_NUM_GET(*msg_word); + if (num_msdus & 0x1) { + struct htt_tx_compl_ind_base *compl = + (void *)msg_word; + + /* + * Host CPU endianness can be different from FW CPU. + * This can result in even and odd MSDU IDs being + * switched. If this happens, copy the switched final + * odd MSDU ID from location payload[size], to + * location payload[size-1], where the message handler + * function expects to find it + */ + if (compl->payload[num_msdus] != + HTT_TX_COMPL_INV_MSDU_ID) { + compl->payload[num_msdus - 1] = + compl->payload[num_msdus]; + } + } + ol_tx_inspect_handler(pdev->txrx_pdev, num_msdus, + msg_word + 1); + HTT_TX_SCHED(pdev); + break; + } + case HTT_T2H_MSG_TYPE_RX_IN_ORD_PADDR_IND: + { + if (qdf_unlikely(!pdev->cfg.is_full_reorder_offload)) { + qdf_print("HTT_T2H_MSG_TYPE_RX_IN_ORD_PADDR_IND not "); + qdf_print("supported when full reorder offload is "); + qdf_print("disabled in the configuration.\n"); + break; + } + + if (qdf_unlikely(pdev->cfg.is_high_latency)) { + qdf_print("HTT_T2H_MSG_TYPE_RX_IN_ORD_PADDR_IND "); + qdf_print("not supported on high latency.\n"); + break; + } + + htt_t2h_rx_in_order_indication_handler( + pdev->txrx_pdev, + htt_t2h_msg, *msg_word); + break; + } + + default: + htt_t2h_lp_msg_handler(context, htt_t2h_msg, true); + return; + + }; + + /* Free the indication buffer */ + qdf_nbuf_free(htt_t2h_msg); +} + +#ifdef WLAN_FEATURE_FASTPATH +#define HTT_T2H_MSG_BUF_REINIT(_buf, dev) \ + do { \ + QDF_NBUF_CB_PADDR(_buf) -= (HTC_HEADER_LEN + \ + HTC_HDR_ALIGNMENT_PADDING); \ + qdf_nbuf_init_fast((_buf)); \ + qdf_mem_dma_sync_single_for_device(dev, \ + (QDF_NBUF_CB_PADDR(_buf)), \ + (skb_end_pointer(_buf) - \ + (_buf)->data) , \ + PCI_DMA_FROMDEVICE); \ + } while (0) + +/** + * htt_t2h_msg_handler_fast() - Fastpath specific message handler + * @context: HTT context + * @cmpl_msdus: netbuf completions + * @num_cmpls: number of completions to be handled + * + * Return: None + */ +void htt_t2h_msg_handler_fast(void *context, qdf_nbuf_t *cmpl_msdus, + uint32_t num_cmpls) +{ + struct htt_pdev_t *pdev = (struct htt_pdev_t *)context; + qdf_nbuf_t htt_t2h_msg; + uint32_t *msg_word; + uint32_t i; + enum htt_t2h_msg_type msg_type; + uint32_t msg_len; + + for (i = 0; i < num_cmpls; i++) { + htt_t2h_msg = cmpl_msdus[i]; + msg_len = qdf_nbuf_len(htt_t2h_msg); + + /* + * Move the data pointer to point to HTT header + * past the HTC header + HTC header alignment padding + */ + qdf_nbuf_pull_head(htt_t2h_msg, HTC_HEADER_LEN + + HTC_HDR_ALIGNMENT_PADDING); + + /* confirm alignment */ + HTT_ASSERT3((((unsigned long) qdf_nbuf_data(htt_t2h_msg)) & 0x3) + == 0); + + msg_word = (u_int32_t *) qdf_nbuf_data(htt_t2h_msg); + msg_type = HTT_T2H_MSG_TYPE_GET(*msg_word); + + switch (msg_type) { + case HTT_T2H_MSG_TYPE_RX_IND: + { + unsigned int num_mpdu_ranges; + unsigned int num_msdu_bytes; + u_int16_t peer_id; + u_int8_t tid; + + peer_id = HTT_RX_IND_PEER_ID_GET(*msg_word); + tid = HTT_RX_IND_EXT_TID_GET(*msg_word); + + num_msdu_bytes = + HTT_RX_IND_FW_RX_DESC_BYTES_GET( + *(msg_word + 2 + + HTT_RX_PPDU_DESC_SIZE32)); + /* + * 1 word for the message header, + * HTT_RX_PPDU_DESC_SIZE32 words for the FW + * rx PPDU desc. + * 1 word to specify the number of MSDU bytes, + * 1 word for every 4 MSDU bytes (round up), + * 1 word for the MPDU range header + */ + pdev->rx_mpdu_range_offset_words = + (HTT_RX_IND_HDR_BYTES + num_msdu_bytes + 3) >> + 2; + num_mpdu_ranges = + HTT_RX_IND_NUM_MPDU_RANGES_GET(*(msg_word + + 1)); + pdev->rx_ind_msdu_byte_idx = 0; + ol_rx_indication_handler(pdev->txrx_pdev, htt_t2h_msg, + peer_id, tid, num_mpdu_ranges); + break; + } + case HTT_T2H_MSG_TYPE_TX_COMPL_IND: + { + int num_msdus; + enum htt_tx_status status; + + /* status - no enum translation needed */ + status = HTT_TX_COMPL_IND_STATUS_GET(*msg_word); + num_msdus = HTT_TX_COMPL_IND_NUM_GET(*msg_word); + if (num_msdus & 0x1) { + struct htt_tx_compl_ind_base *compl = + (void *)msg_word; + + /* + * Host CPU endianness can be different + * from FW CPU. This can result in even + * and odd MSDU IDs being switched. If + * this happens, copy the switched final + * odd MSDU ID from location + * payload[size], to location + * payload[size-1],where the message + * handler function expects to find it + */ + if (compl->payload[num_msdus] != + HTT_TX_COMPL_INV_MSDU_ID) { + compl->payload[num_msdus - 1] = + compl->payload[num_msdus]; + } + } + ol_tx_completion_handler(pdev->txrx_pdev, num_msdus, + status, msg_word + 1); + + break; + } + case HTT_T2H_MSG_TYPE_RX_PN_IND: + { + u_int16_t peer_id; + u_int8_t tid, pn_ie_cnt, *pn_ie = NULL; + int seq_num_start, seq_num_end; + + /*First dword */ + peer_id = HTT_RX_PN_IND_PEER_ID_GET(*msg_word); + tid = HTT_RX_PN_IND_EXT_TID_GET(*msg_word); + + msg_word++; + /*Second dword */ + seq_num_start = + HTT_RX_PN_IND_SEQ_NUM_START_GET(*msg_word); + seq_num_end = + HTT_RX_PN_IND_SEQ_NUM_END_GET(*msg_word); + pn_ie_cnt = + HTT_RX_PN_IND_PN_IE_CNT_GET(*msg_word); + + msg_word++; + /*Third dword*/ + if (pn_ie_cnt) + pn_ie = (u_int8_t *)msg_word; + + ol_rx_pn_ind_handler(pdev->txrx_pdev, peer_id, tid, + seq_num_start, seq_num_end, pn_ie_cnt, pn_ie); + + break; + } + case HTT_T2H_MSG_TYPE_TX_INSPECT_IND: + { + int num_msdus; + + num_msdus = HTT_TX_COMPL_IND_NUM_GET(*msg_word); + if (num_msdus & 0x1) { + struct htt_tx_compl_ind_base *compl = + (void *)msg_word; + + /* + * Host CPU endianness can be different + * from FW CPU. This * can result in + * even and odd MSDU IDs being switched. + * If this happens, copy the switched + * final odd MSDU ID from location + * payload[size], to location + * payload[size-1], where the message + * handler function expects to find it + */ + if (compl->payload[num_msdus] != + HTT_TX_COMPL_INV_MSDU_ID) { + compl->payload[num_msdus - 1] = + compl->payload[num_msdus]; + } + } + ol_tx_inspect_handler(pdev->txrx_pdev, + num_msdus, msg_word + 1); + break; + } + case HTT_T2H_MSG_TYPE_RX_IN_ORD_PADDR_IND: + { + if (qdf_unlikely( + !pdev->cfg.is_full_reorder_offload)) { + qdf_print("HTT_T2H_MSG_TYPE_RX_IN_ORD_PADDR_IND not supported when full reorder offload is disabled\n"); + break; + } + + if (qdf_unlikely( + pdev->txrx_pdev->cfg.is_high_latency)) { + qdf_print("HTT_T2H_MSG_TYPE_RX_IN_ORD_PADDR_IND not supported on high latency\n"); + break; + } + + htt_t2h_rx_in_order_indication_handler( + pdev->txrx_pdev, + htt_t2h_msg, *msg_word); + break; + } + default: + htt_t2h_lp_msg_handler(context, htt_t2h_msg, false); + break; + }; + + /* Re-initialize the indication buffer */ + HTT_T2H_MSG_BUF_REINIT(htt_t2h_msg, pdev->osdev); + qdf_nbuf_set_pktlen(htt_t2h_msg, 0); + } +} +#endif /* WLAN_FEATURE_FASTPATH */ + +/*--- target->host HTT message Info Element access methods ------------------*/ + +/*--- tx completion message ---*/ + +uint16_t htt_tx_compl_desc_id(void *iterator, int num) +{ + /* + * The MSDU IDs are packed , 2 per 32-bit word. + * Iterate on them as an array of 16-bit elements. + * This will work fine if the host endianness matches + * the target endianness. + * If the host endianness is opposite of the target's, + * this iterator will produce descriptor IDs in a different + * order than the target inserted them into the message - + * if the target puts in [0, 1, 2, 3, ...] the host will + * put out [1, 0, 3, 2, ...]. + * This is fine, except for the last ID if there are an + * odd number of IDs. But the TX_COMPL_IND handling code + * in the htt_t2h_msg_handler already added a duplicate + * of the final ID, if there were an odd number of IDs, + * so this function can safely treat the IDs as an array + * of 16-bit elements. + */ + return *(((uint16_t *) iterator) + num); +} + +/*--- rx indication message ---*/ + +int htt_rx_ind_flush(htt_pdev_handle pdev, qdf_nbuf_t rx_ind_msg) +{ + uint32_t *msg_word; + + msg_word = (uint32_t *) qdf_nbuf_data(rx_ind_msg); + return HTT_RX_IND_FLUSH_VALID_GET(*msg_word); +} + +void +htt_rx_ind_flush_seq_num_range(htt_pdev_handle pdev, + qdf_nbuf_t rx_ind_msg, + unsigned *seq_num_start, unsigned *seq_num_end) +{ + uint32_t *msg_word; + + msg_word = (uint32_t *) qdf_nbuf_data(rx_ind_msg); + msg_word++; + *seq_num_start = HTT_RX_IND_FLUSH_SEQ_NUM_START_GET(*msg_word); + *seq_num_end = HTT_RX_IND_FLUSH_SEQ_NUM_END_GET(*msg_word); +} + +int htt_rx_ind_release(htt_pdev_handle pdev, qdf_nbuf_t rx_ind_msg) +{ + uint32_t *msg_word; + + msg_word = (uint32_t *) qdf_nbuf_data(rx_ind_msg); + return HTT_RX_IND_REL_VALID_GET(*msg_word); +} + +void +htt_rx_ind_release_seq_num_range(htt_pdev_handle pdev, + qdf_nbuf_t rx_ind_msg, + unsigned *seq_num_start, unsigned *seq_num_end) +{ + uint32_t *msg_word; + + msg_word = (uint32_t *) qdf_nbuf_data(rx_ind_msg); + msg_word++; + *seq_num_start = HTT_RX_IND_REL_SEQ_NUM_START_GET(*msg_word); + *seq_num_end = HTT_RX_IND_REL_SEQ_NUM_END_GET(*msg_word); +} + +void +htt_rx_ind_mpdu_range_info(struct htt_pdev_t *pdev, + qdf_nbuf_t rx_ind_msg, + int mpdu_range_num, + enum htt_rx_status *status, int *mpdu_count) +{ + uint32_t *msg_word; + + msg_word = (uint32_t *) qdf_nbuf_data(rx_ind_msg); + msg_word += pdev->rx_mpdu_range_offset_words + mpdu_range_num; + *status = HTT_RX_IND_MPDU_STATUS_GET(*msg_word); + *mpdu_count = HTT_RX_IND_MPDU_COUNT_GET(*msg_word); +} + +/** + * htt_rx_ind_rssi_dbm() - Return the RSSI provided in a rx indication message. + * + * @pdev: the HTT instance the rx data was received on + * @rx_ind_msg: the netbuf containing the rx indication message + * + * Return the RSSI from an rx indication message, in dBm units. + * + * Return: RSSI in dBm, or HTT_INVALID_RSSI + */ +int16_t htt_rx_ind_rssi_dbm(htt_pdev_handle pdev, qdf_nbuf_t rx_ind_msg) +{ + int8_t rssi; + uint32_t *msg_word; + + msg_word = (uint32_t *) + (qdf_nbuf_data(rx_ind_msg) + + HTT_RX_IND_FW_RX_PPDU_DESC_BYTE_OFFSET); + + /* check if the RX_IND message contains valid rx PPDU start info */ + if (!HTT_RX_IND_START_VALID_GET(*msg_word)) + return HTT_RSSI_INVALID; + + rssi = HTT_RX_IND_RSSI_CMB_GET(*msg_word); + return (HTT_TGT_RSSI_INVALID == rssi) ? + HTT_RSSI_INVALID : rssi; +} + +/** + * htt_rx_ind_rssi_dbm_chain() - Return the RSSI for a chain provided in a rx + * indication message. + * @pdev: the HTT instance the rx data was received on + * @rx_ind_msg: the netbuf containing the rx indication message + * @chain: the index of the chain (0-4) + * + * Return the RSSI for a chain from an rx indication message, in dBm units. + * + * Return: RSSI, or HTT_INVALID_RSSI + */ +int16_t +htt_rx_ind_rssi_dbm_chain(htt_pdev_handle pdev, qdf_nbuf_t rx_ind_msg, + int8_t chain) +{ + int8_t rssi; + uint32_t *msg_word; + + if (chain < 0 || chain > 3) + return HTT_RSSI_INVALID; + + msg_word = (uint32_t *) + (qdf_nbuf_data(rx_ind_msg) + + HTT_RX_IND_FW_RX_PPDU_DESC_BYTE_OFFSET); + + /* check if the RX_IND message contains valid rx PPDU start info */ + if (!HTT_RX_IND_START_VALID_GET(*msg_word)) + return HTT_RSSI_INVALID; + + msg_word += 1 + chain; + + rssi = HTT_RX_IND_RSSI_PRI20_GET(*msg_word); + return (HTT_TGT_RSSI_INVALID == rssi) ? + HTT_RSSI_INVALID : + rssi; +} + +/** + * htt_rx_ind_legacy_rate() - Return the data rate + * @pdev: the HTT instance the rx data was received on + * @rx_ind_msg: the netbuf containing the rx indication message + * @legacy_rate: (output) the data rate + * The legacy_rate parameter's value depends on the + * legacy_rate_sel value. + * If legacy_rate_sel is 0: + * 0x8: OFDM 48 Mbps + * 0x9: OFDM 24 Mbps + * 0xA: OFDM 12 Mbps + * 0xB: OFDM 6 Mbps + * 0xC: OFDM 54 Mbps + * 0xD: OFDM 36 Mbps + * 0xE: OFDM 18 Mbps + * 0xF: OFDM 9 Mbps + * If legacy_rate_sel is 1: + * 0x8: CCK 11 Mbps long preamble + * 0x9: CCK 5.5 Mbps long preamble + * 0xA: CCK 2 Mbps long preamble + * 0xB: CCK 1 Mbps long preamble + * 0xC: CCK 11 Mbps short preamble + * 0xD: CCK 5.5 Mbps short preamble + * 0xE: CCK 2 Mbps short preamble + * -1 on error. + * @legacy_rate_sel: (output) 0 to indicate OFDM, 1 to indicate CCK. + * -1 on error. + * + * Return the data rate provided in a rx indication message. + */ +void +htt_rx_ind_legacy_rate(htt_pdev_handle pdev, qdf_nbuf_t rx_ind_msg, + uint8_t *legacy_rate, uint8_t *legacy_rate_sel) +{ + uint32_t *msg_word; + + msg_word = (uint32_t *) + (qdf_nbuf_data(rx_ind_msg) + + HTT_RX_IND_FW_RX_PPDU_DESC_BYTE_OFFSET); + + /* check if the RX_IND message contains valid rx PPDU start info */ + if (!HTT_RX_IND_START_VALID_GET(*msg_word)) { + *legacy_rate = -1; + *legacy_rate_sel = -1; + return; + } + + *legacy_rate = HTT_RX_IND_LEGACY_RATE_GET(*msg_word); + *legacy_rate_sel = HTT_RX_IND_LEGACY_RATE_SEL_GET(*msg_word); +} + +/** + * htt_rx_ind_timestamp() - Return the timestamp + * @pdev: the HTT instance the rx data was received on + * @rx_ind_msg: the netbuf containing the rx indication message + * @timestamp_microsec: (output) the timestamp to microsecond resolution. + * -1 on error. + * @timestamp_submicrosec: the submicrosecond portion of the + * timestamp. -1 on error. + * + * Return the timestamp provided in a rx indication message. + */ +void +htt_rx_ind_timestamp(htt_pdev_handle pdev, qdf_nbuf_t rx_ind_msg, + uint32_t *timestamp_microsec, + uint8_t *timestamp_submicrosec) +{ + uint32_t *msg_word; + + msg_word = (uint32_t *) + (qdf_nbuf_data(rx_ind_msg) + + HTT_RX_IND_FW_RX_PPDU_DESC_BYTE_OFFSET); + + /* check if the RX_IND message contains valid rx PPDU start info */ + if (!HTT_RX_IND_END_VALID_GET(*msg_word)) { + *timestamp_microsec = -1; + *timestamp_submicrosec = -1; + return; + } + + *timestamp_microsec = *(msg_word + 6); + *timestamp_submicrosec = + HTT_RX_IND_TIMESTAMP_SUBMICROSEC_GET(*msg_word); +} + +#define INVALID_TSF -1 +/** + * htt_rx_ind_tsf32() - Return the TSF timestamp + * @pdev: the HTT instance the rx data was received on + * @rx_ind_msg: the netbuf containing the rx indication message + * + * Return the TSF timestamp provided in a rx indication message. + * + * Return: TSF timestamp + */ +uint32_t +htt_rx_ind_tsf32(htt_pdev_handle pdev, qdf_nbuf_t rx_ind_msg) +{ + uint32_t *msg_word; + + msg_word = (uint32_t *) + (qdf_nbuf_data(rx_ind_msg) + + HTT_RX_IND_FW_RX_PPDU_DESC_BYTE_OFFSET); + + /* check if the RX_IND message contains valid rx PPDU start info */ + if (!HTT_RX_IND_END_VALID_GET(*msg_word)) + return INVALID_TSF; + + return *(msg_word + 5); +} + +/** + * htt_rx_ind_ext_tid() - Return the extended traffic ID provided in a rx indication message. + * @pdev: the HTT instance the rx data was received on + * @rx_ind_msg: the netbuf containing the rx indication message + * + * Return the extended traffic ID in a rx indication message. + * + * Return: Extended TID + */ +uint8_t +htt_rx_ind_ext_tid(htt_pdev_handle pdev, qdf_nbuf_t rx_ind_msg) +{ + uint32_t *msg_word; + + msg_word = (uint32_t *) + (qdf_nbuf_data(rx_ind_msg)); + + return HTT_RX_IND_EXT_TID_GET(*msg_word); +} + +/*--- stats confirmation message ---*/ + +void +htt_t2h_dbg_stats_hdr_parse(uint8_t *stats_info_list, + enum htt_dbg_stats_type *type, + enum htt_dbg_stats_status *status, + int *length, uint8_t **stats_data) +{ + uint32_t *msg_word = (uint32_t *) stats_info_list; + *type = HTT_T2H_STATS_CONF_TLV_TYPE_GET(*msg_word); + *status = HTT_T2H_STATS_CONF_TLV_STATUS_GET(*msg_word); + *length = HTT_T2H_STATS_CONF_TLV_HDR_SIZE + /* header length */ + HTT_T2H_STATS_CONF_TLV_LENGTH_GET(*msg_word); /* data len */ + *stats_data = stats_info_list + HTT_T2H_STATS_CONF_TLV_HDR_SIZE; +} + +void +htt_rx_frag_ind_flush_seq_num_range(htt_pdev_handle pdev, + qdf_nbuf_t rx_frag_ind_msg, + int *seq_num_start, int *seq_num_end) +{ + uint32_t *msg_word; + + msg_word = (uint32_t *) qdf_nbuf_data(rx_frag_ind_msg); + msg_word++; + *seq_num_start = HTT_RX_FRAG_IND_FLUSH_SEQ_NUM_START_GET(*msg_word); + *seq_num_end = HTT_RX_FRAG_IND_FLUSH_SEQ_NUM_END_GET(*msg_word); +} diff --git a/drivers/staging/qcacld-3.0/core/dp/htt/htt_tx.c b/drivers/staging/qcacld-3.0/core/dp/htt/htt_tx.c new file mode 100644 index 0000000000000000000000000000000000000000..722af89dfca46bb9854aa60521bc2edf48e281ba --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/dp/htt/htt_tx.c @@ -0,0 +1,1877 @@ +/* + * Copyright (c) 2011, 2014-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * @file htt_tx.c + * @brief Implement transmit aspects of HTT. + * @details + * This file contains three categories of HTT tx code: + * 1. An abstraction of the tx descriptor, to hide the + * differences between the HL vs. LL tx descriptor. + * 2. Functions for allocating and freeing HTT tx descriptors. + * 3. The function that accepts a tx frame from txrx and sends the + * tx frame to HTC. + */ +#include /* uint32_t, offsetof, etc. */ +#include /* qdf_dma_addr_t */ +#include /* qdf_mem_alloc_consistent et al */ +#include /* qdf_nbuf_t, etc. */ +#include /* qdf_mdelay */ + +#include /* htt_tx_msdu_desc_t */ +#include /* HTC_HDR_LENGTH */ +#include /* htc_flush_surprise_remove */ +#include /* ol_cfg_netbuf_frags_max, etc. */ +#include /* HTT_TX_DESC_VADDR_OFFSET */ +#include /* ol_tx_msdu_id_storage */ +#include +#include + +#include + +/* IPA Micro controler TX data packet HTT Header Preset */ +/* 31 | 30 29 | 28 | 27 | 26 22 | 21 16 | 15 13 | 12 8 | 7 0 + *---------------------------------------------------------------------------- + * R | CS OL | R | PP | ext TID | vdev ID | pkt type | pkt subtyp | msg type + * 0 | 0 | 0 | | 0x1F | 0 | 2 | 0 | 0x01 + ***---------------------------------------------------------------------------- + * pkt ID | pkt length + ***---------------------------------------------------------------------------- + * frag_desc_ptr + ***---------------------------------------------------------------------------- + * peer_id + ***---------------------------------------------------------------------------- + */ +#define HTT_IPA_UC_OFFLOAD_TX_HEADER_DEFAULT 0x07C04001 + +#ifdef QCA_WIFI_3_0 +#define IPA_UC_TX_BUF_FRAG_DESC_OFFSET 20 +#define IPA_UC_TX_BUF_FRAG_HDR_OFFSET 64 +#define IPA_UC_TX_BUF_TSO_HDR_SIZE 6 +#define IPA_UC_TX_BUF_PADDR_HI_MASK 0x0000001F +#define IPA_UC_TX_BUF_PADDR_HI_OFFSET 32 +#else +#define IPA_UC_TX_BUF_FRAG_DESC_OFFSET 16 +#define IPA_UC_TX_BUF_FRAG_HDR_OFFSET 32 +#endif /* QCA_WIFI_3_0 */ + +#if HTT_PADDR64 +#define HTT_TX_DESC_FRAG_FIELD_HI_UPDATE(frag_filed_ptr) \ +do { \ + frag_filed_ptr++; \ + /* frags_desc_ptr.hi */ \ + *frag_filed_ptr = 0; \ +} while (0) +#else +#define HTT_TX_DESC_FRAG_FIELD_HI_UPDATE(frag_filed_ptr) {} +#endif + +/*--- setup / tear-down functions -------------------------------------------*/ + +static qdf_dma_addr_t htt_tx_get_paddr(htt_pdev_handle pdev, + char *target_vaddr); + +#ifdef HELIUMPLUS +/** + * htt_tx_desc_get_size() - get tx descripotrs size + * @pdev: htt device instance pointer + * + * This function will get HTT TX descriptor size and fragment descriptor size + * + * Return: None + */ +static void htt_tx_desc_get_size(struct htt_pdev_t *pdev) +{ + pdev->tx_descs.size = sizeof(struct htt_host_tx_desc_t); + if (HTT_WIFI_IP_VERSION(pdev->wifi_ip_ver.major, 0x2)) { + /* + * sizeof MSDU_EXT/Fragmentation descriptor. + */ + pdev->frag_descs.size = sizeof(struct msdu_ext_desc_t); + } else { + /* + * Add the fragmentation descriptor elements. + * Add the most that the OS may deliver, plus one more + * in case the txrx code adds a prefix fragment (for + * TSO or audio interworking SNAP header) + */ + pdev->frag_descs.size = + (ol_cfg_netbuf_frags_max(pdev->ctrl_pdev)+1) * 8 + + 4; + } +} + +/** + * htt_tx_frag_desc_field_update() - Update fragment descriptor field + * @pdev: htt device instance pointer + * @fptr: Fragment descriptor field pointer + * @index: Descriptor index to find page and offset + * @desc_v_ptr: descriptor virtual pointot to find offset + * + * This function will update fragment descriptor field with actual fragment + * descriptor stating physical pointer + * + * Return: None + */ +static void htt_tx_frag_desc_field_update(struct htt_pdev_t *pdev, + uint32_t *fptr, unsigned int index, + struct htt_tx_msdu_desc_t *desc_v_ptr) +{ + unsigned int target_page; + unsigned int offset; + struct qdf_mem_dma_page_t *dma_page; + + target_page = index / pdev->frag_descs.desc_pages.num_element_per_page; + offset = index % pdev->frag_descs.desc_pages.num_element_per_page; + dma_page = &pdev->frag_descs.desc_pages.dma_pages[target_page]; + *fptr = (uint32_t)(dma_page->page_p_addr + + offset * pdev->frag_descs.size); + HTT_TX_DESC_FRAG_FIELD_HI_UPDATE(fptr); + return; +} + +/** + * htt_tx_frag_desc_attach() - Attach fragment descriptor + * @pdev: htt device instance pointer + * @desc_pool_elems: Number of fragment descriptor + * + * This function will allocate fragment descriptor + * + * Return: 0 success + */ +static int htt_tx_frag_desc_attach(struct htt_pdev_t *pdev, + uint16_t desc_pool_elems) +{ + pdev->frag_descs.pool_elems = desc_pool_elems; + qdf_mem_multi_pages_alloc(pdev->osdev, &pdev->frag_descs.desc_pages, + pdev->frag_descs.size, desc_pool_elems, + qdf_get_dma_mem_context((&pdev->frag_descs), memctx), false); + if ((0 == pdev->frag_descs.desc_pages.num_pages) || + (NULL == pdev->frag_descs.desc_pages.dma_pages)) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "FRAG descriptor alloc fail"); + return -ENOBUFS; + } + return 0; +} + +/** + * htt_tx_frag_desc_detach() - Detach fragment descriptor + * @pdev: htt device instance pointer + * + * This function will free fragment descriptor + * + * Return: None + */ +static void htt_tx_frag_desc_detach(struct htt_pdev_t *pdev) +{ + qdf_mem_multi_pages_free(pdev->osdev, &pdev->frag_descs.desc_pages, + qdf_get_dma_mem_context((&pdev->frag_descs), memctx), false); +} + +/** + * htt_tx_frag_alloc() - Allocate single fragment descriptor from the pool + * @pdev: htt device instance pointer + * @index: Descriptor index + * @frag_paddr: Fragment descriptor physical address + * @frag_ptr: Fragment descriptor virtual address + * + * This function will free fragment descriptor + * + * Return: None + */ +int htt_tx_frag_alloc(htt_pdev_handle pdev, + u_int16_t index, qdf_dma_addr_t *frag_paddr, void **frag_ptr) +{ + uint16_t frag_page_index; + uint16_t frag_elem_index; + struct qdf_mem_dma_page_t *dma_page; + + /** Index should never be 0, since its used by the hardware + to terminate the link. */ + if (index >= pdev->tx_descs.pool_elems) { + *frag_ptr = NULL; + return 1; + } + + frag_page_index = index / + pdev->frag_descs.desc_pages.num_element_per_page; + frag_elem_index = index % + pdev->frag_descs.desc_pages.num_element_per_page; + dma_page = &pdev->frag_descs.desc_pages.dma_pages[frag_page_index]; + + *frag_ptr = dma_page->page_v_addr_start + + frag_elem_index * pdev->frag_descs.size; + if (((char *)(*frag_ptr) < dma_page->page_v_addr_start) || + ((char *)(*frag_ptr) > dma_page->page_v_addr_end)) { + *frag_ptr = NULL; + return 1; + } + + *frag_paddr = dma_page->page_p_addr + + frag_elem_index * pdev->frag_descs.size; + return 0; +} +#else + +/** + * htt_tx_desc_get_size() - get tx descripotrs size + * @pdev: htt device instance pointer + * + * This function will get HTT TX descriptor size and fragment descriptor size + * + * Return: None + */ +static inline void htt_tx_desc_get_size(struct htt_pdev_t *pdev) +{ + if (pdev->cfg.is_high_latency) { + pdev->tx_descs.size = sizeof(struct htt_host_tx_desc_t); + } else { + /* + * Start with the size of the base struct + * that actually gets downloaded. + * + * Add the fragmentation descriptor elements. + * Add the most that the OS may deliver, plus one more + * in case the txrx code adds a prefix fragment (for + * TSO or audio interworking SNAP header) + */ + pdev->tx_descs.size = + sizeof(struct htt_host_tx_desc_t) + + (ol_cfg_netbuf_frags_max(pdev->ctrl_pdev) + 1) * 8 + /* 2x uint32_t */ + + 4; /* uint32_t fragmentation list terminator */ + } +} + +#ifndef CONFIG_HL_SUPPORT + +/** + * htt_tx_frag_desc_field_update() - Update fragment descriptor field + * @pdev: htt device instance pointer + * @fptr: Fragment descriptor field pointer + * @index: Descriptor index to find page and offset + * @desc_v_ptr: descriptor virtual pointot to find offset + * + * This function will update fragment descriptor field with actual fragment + * descriptor stating physical pointer + * + * Return: None + */ +static void htt_tx_frag_desc_field_update(struct htt_pdev_t *pdev, + uint32_t *fptr, unsigned int index, + struct htt_tx_msdu_desc_t *desc_v_ptr) +{ + *fptr = (uint32_t)htt_tx_get_paddr(pdev, (char *)desc_v_ptr) + + HTT_TX_DESC_LEN; +} +#endif + +/** + * htt_tx_frag_desc_attach() - Attach fragment descriptor + * @pdev: htt device instance pointer + * @desc_pool_elems: Number of fragment descriptor + * + * This function will allocate fragment descriptor + * + * Return: 0 success + */ +static inline int htt_tx_frag_desc_attach(struct htt_pdev_t *pdev, + int desc_pool_elems) +{ + return 0; +} + +/** + * htt_tx_frag_desc_detach() - Detach fragment descriptor + * @pdev: htt device instance pointer + * + * This function will free fragment descriptor + * + * Return: None + */ +static void htt_tx_frag_desc_detach(struct htt_pdev_t *pdev) {} +#endif /* HELIUMPLUS */ + +#ifdef CONFIG_HL_SUPPORT + +/** + * htt_tx_attach() - Attach HTT device instance + * @pdev: htt device instance pointer + * @desc_pool_elems: Number of TX descriptors + * + * This function will allocate HTT TX resources + * + * Return: 0 Success + */ +int htt_tx_attach(struct htt_pdev_t *pdev, int desc_pool_elems) +{ + int i, i_int, pool_size; + uint32_t **p; + uint32_t num_link = 0; + uint16_t num_page, num_desc_per_page; + void **cacheable_pages = NULL; + + htt_tx_desc_get_size(pdev); + + /* + * Make sure tx_descs.size is a multiple of 4-bytes. + * It should be, but round up just to be sure. + */ + pdev->tx_descs.size = (pdev->tx_descs.size + 3) & (~0x3); + + pdev->tx_descs.pool_elems = desc_pool_elems; + pdev->tx_descs.alloc_cnt = 0; + pool_size = pdev->tx_descs.pool_elems * pdev->tx_descs.size; + qdf_mem_multi_pages_alloc(pdev->osdev, &pdev->tx_descs.desc_pages, + pdev->tx_descs.size, + pdev->tx_descs.pool_elems, + qdf_get_dma_mem_context((&pdev->tx_descs), + memctx), true); + if ((0 == pdev->tx_descs.desc_pages.num_pages) || + (NULL == pdev->tx_descs.desc_pages.cacheable_pages)) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "HTT desc alloc fail"); + goto out_fail; + } + num_page = pdev->tx_descs.desc_pages.num_pages; + num_desc_per_page = pdev->tx_descs.desc_pages.num_element_per_page; + + /* link tx descriptors into a freelist */ + cacheable_pages = pdev->tx_descs.desc_pages.cacheable_pages; + + pdev->tx_descs.freelist = (uint32_t *)cacheable_pages[0]; + p = (uint32_t **)pdev->tx_descs.freelist; + for (i = 0; i < num_page; i++) { + for (i_int = 0; i_int < num_desc_per_page; i_int++) { + if (i_int == (num_desc_per_page - 1)) { + /* + * Last element on this page, + * should point next page + */ + if (!cacheable_pages[i + 1]) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "over flow num link %d\n", + num_link); + goto free_htt_desc; + } + *p = (uint32_t *)cacheable_pages[i + 1]; + } else { + *p = (uint32_t *) + (((char *)p) + pdev->tx_descs.size); + } + num_link++; + p = (uint32_t **) *p; + /* Last link established exit */ + if (num_link == (pdev->tx_descs.pool_elems - 1)) + break; + } + } + *p = NULL; + + if (htt_tx_frag_desc_attach(pdev, desc_pool_elems)) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "HTT Frag descriptor alloc fail"); + goto free_htt_desc; + } + + /* success */ + return 0; + +free_htt_desc: + qdf_mem_multi_pages_free(pdev->osdev, &pdev->tx_descs.desc_pages, + qdf_get_dma_mem_context((&pdev->tx_descs), + memctx), true); +out_fail: + return -ENOBUFS; +} + +void htt_tx_detach(struct htt_pdev_t *pdev) +{ + if (!pdev) { + qdf_print("htt tx detach invalid instance"); + return; + } + + htt_tx_frag_desc_detach(pdev); + qdf_mem_multi_pages_free(pdev->osdev, &pdev->tx_descs.desc_pages, + qdf_get_dma_mem_context((&pdev->tx_descs), + memctx), true); +} + +/** + * htt_tx_set_frag_desc_addr() - set up the fragmentation descriptor address + * @pdev: pointer to the HTT instance making the allocation + * @htt_tx_desc: Host tx decriptor that does not include HTC hdr + * @index: index to alloc htt tx desc + * + * + * Return: None + */ +static inline void +htt_tx_set_frag_desc_addr(struct htt_pdev_t *pdev, + struct htt_tx_msdu_desc_t *htt_tx_desc, + uint16_t index) +{ + return; +} + +/** + * htt_tx_desc_frags_table_set() - set up the descriptor and payload + * to correspondinf fragments + * @pdev: pointer to the HTT instance making the allocation + * @htt_tx_desc: Host tx decriptor that does not include HTC hdr + * @paddr: fragment physical address + * @frag_desc_paddr_lo: frag descriptor address + * @reset: reset + * + * Return: None + */ +void htt_tx_desc_frags_table_set(htt_pdev_handle pdev, + void *desc, + qdf_dma_addr_t paddr, + qdf_dma_addr_t frag_desc_paddr, + int reset) +{ + /* fragments table only applies to LL systems */ + return; +} + +/** + * htt_tx_credit_update() - get the number of credits by which the amount of + * target credits needs to be updated + * @pdev: htt context + * + * Return: number of credits + */ +int htt_tx_credit_update(struct htt_pdev_t *pdev) +{ + int credit_delta; + credit_delta = QDF_MIN(qdf_atomic_read( + &pdev->htt_tx_credit.target_delta), + qdf_atomic_read(&pdev->htt_tx_credit.bus_delta)); + if (credit_delta) { + qdf_atomic_add(-credit_delta, + &pdev->htt_tx_credit.target_delta); + qdf_atomic_add(-credit_delta, + &pdev->htt_tx_credit.bus_delta); + } + return credit_delta; +} + +/** + * htt_tx_get_paddr() - get physical address for htt desc + * + * Get HTT descriptor physical address from virtaul address + * Find page first and find offset + * Not required for HL systems + * + * Return: Physical address of descriptor + */ +static inline +qdf_dma_addr_t htt_tx_get_paddr(htt_pdev_handle pdev, + char *target_vaddr) +{ + return 0; +} + + +#else + +int htt_tx_attach(struct htt_pdev_t *pdev, int desc_pool_elems) +{ + int i, i_int, pool_size; + uint32_t **p; + struct qdf_mem_dma_page_t *page_info; + uint32_t num_link = 0; + uint16_t num_page, num_desc_per_page; + + htt_tx_desc_get_size(pdev); + + /* + * Make sure tx_descs.size is a multiple of 4-bytes. + * It should be, but round up just to be sure. + */ + pdev->tx_descs.size = (pdev->tx_descs.size + 3) & (~0x3); + + pdev->tx_descs.pool_elems = desc_pool_elems; + pdev->tx_descs.alloc_cnt = 0; + pool_size = pdev->tx_descs.pool_elems * pdev->tx_descs.size; + qdf_mem_multi_pages_alloc(pdev->osdev, &pdev->tx_descs.desc_pages, + pdev->tx_descs.size, pdev->tx_descs.pool_elems, + qdf_get_dma_mem_context((&pdev->tx_descs), memctx), false); + if ((0 == pdev->tx_descs.desc_pages.num_pages) || + (NULL == pdev->tx_descs.desc_pages.dma_pages)) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "HTT desc alloc fail"); + goto out_fail; + } + num_page = pdev->tx_descs.desc_pages.num_pages; + num_desc_per_page = pdev->tx_descs.desc_pages.num_element_per_page; + + /* link tx descriptors into a freelist */ + page_info = pdev->tx_descs.desc_pages.dma_pages; + pdev->tx_descs.freelist = (uint32_t *)page_info->page_v_addr_start; + p = (uint32_t **) pdev->tx_descs.freelist; + for (i = 0; i < num_page; i++) { + for (i_int = 0; i_int < num_desc_per_page; i_int++) { + if (i_int == (num_desc_per_page - 1)) { + /* + * Last element on this page, + * should pint next page */ + if (!page_info->page_v_addr_start) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "over flow num link %d\n", + num_link); + goto free_htt_desc; + } + page_info++; + *p = (uint32_t *)page_info->page_v_addr_start; + } else { + *p = (uint32_t *) + (((char *) p) + pdev->tx_descs.size); + } + num_link++; + p = (uint32_t **) *p; + /* Last link established exit */ + if (num_link == (pdev->tx_descs.pool_elems - 1)) + break; + } + } + *p = NULL; + + if (htt_tx_frag_desc_attach(pdev, desc_pool_elems)) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "HTT Frag descriptor alloc fail"); + goto free_htt_desc; + } + + /* success */ + return 0; + +free_htt_desc: + qdf_mem_multi_pages_free(pdev->osdev, &pdev->tx_descs.desc_pages, + qdf_get_dma_mem_context((&pdev->tx_descs), memctx), false); +out_fail: + return -ENOBUFS; +} + +void htt_tx_detach(struct htt_pdev_t *pdev) +{ + if (!pdev) { + qdf_print("htt tx detach invalid instance"); + return; + } + + htt_tx_frag_desc_detach(pdev); + qdf_mem_multi_pages_free(pdev->osdev, &pdev->tx_descs.desc_pages, + qdf_get_dma_mem_context((&pdev->tx_descs), memctx), false); +} + +static void +htt_tx_set_frag_desc_addr(struct htt_pdev_t *pdev, + struct htt_tx_msdu_desc_t *htt_tx_desc, + uint16_t index) +{ + uint32_t *fragmentation_descr_field_ptr; + fragmentation_descr_field_ptr = (uint32_t *) + ((uint32_t *)htt_tx_desc) + + HTT_TX_DESC_FRAGS_DESC_PADDR_OFFSET_DWORD; + /* + * The fragmentation descriptor is allocated from consistent + * memory. Therefore, we can use the address directly rather + * than having to map it from a virtual/CPU address to a + * physical/bus address. + */ + htt_tx_frag_desc_field_update(pdev, fragmentation_descr_field_ptr, + index, htt_tx_desc); + + return; +} + +void htt_tx_desc_frags_table_set(htt_pdev_handle pdev, + void *htt_tx_desc, + qdf_dma_addr_t paddr, + qdf_dma_addr_t frag_desc_paddr, + int reset) +{ + uint32_t *fragmentation_descr_field_ptr; + + fragmentation_descr_field_ptr = (uint32_t *) + ((uint32_t *) htt_tx_desc) + + HTT_TX_DESC_FRAGS_DESC_PADDR_OFFSET_DWORD; + if (reset) { +#if defined(HELIUMPLUS) + *fragmentation_descr_field_ptr = frag_desc_paddr; +#else + *fragmentation_descr_field_ptr = + htt_tx_get_paddr(pdev, htt_tx_desc) + HTT_TX_DESC_LEN; +#endif + } else { + *fragmentation_descr_field_ptr = paddr; + } +} + +void htt_tx_pending_discard(htt_pdev_handle pdev) +{ + htc_flush_surprise_remove(pdev->htc_pdev); +} + +static qdf_dma_addr_t htt_tx_get_paddr(htt_pdev_handle pdev, + char *target_vaddr) +{ + uint16_t i; + struct qdf_mem_dma_page_t *page_info = NULL; + uint64_t offset; + + for (i = 0; i < pdev->tx_descs.desc_pages.num_pages; i++) { + page_info = pdev->tx_descs.desc_pages.dma_pages + i; + if (!page_info->page_v_addr_start) { + qdf_assert(0); + return 0; + } + if ((target_vaddr >= page_info->page_v_addr_start) && + (target_vaddr <= page_info->page_v_addr_end)) + break; + } + + if (!page_info) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, "invalid page_info"); + return 0; + } + + offset = (uint64_t)(target_vaddr - page_info->page_v_addr_start); + return page_info->page_p_addr + offset; +} + +#endif + +/*--- descriptor allocation functions ---------------------------------------*/ + +void *htt_tx_desc_alloc(htt_pdev_handle pdev, qdf_dma_addr_t *paddr, + uint16_t index) +{ + struct htt_host_tx_desc_t *htt_host_tx_desc; /* includes HTC hdr */ + struct htt_tx_msdu_desc_t *htt_tx_desc; /* doesn't include HTC hdr */ + + htt_host_tx_desc = (struct htt_host_tx_desc_t *)pdev->tx_descs.freelist; + if (!htt_host_tx_desc) + return NULL; /* pool is exhausted */ + + htt_tx_desc = &htt_host_tx_desc->align32.tx_desc; + + if (pdev->tx_descs.freelist) { + pdev->tx_descs.freelist = + *((uint32_t **) pdev->tx_descs.freelist); + pdev->tx_descs.alloc_cnt++; + } + /* + * For LL, set up the fragmentation descriptor address. + * Currently, this HTT tx desc allocation is performed once up front. + * If this is changed to have the allocation done during tx, then it + * would be helpful to have separate htt_tx_desc_alloc functions for + * HL vs. LL, to remove the below conditional branch. + */ + htt_tx_set_frag_desc_addr(pdev, htt_tx_desc, index); + + /* + * Include the headroom for the HTC frame header when specifying the + * physical address for the HTT tx descriptor. + */ + *paddr = (qdf_dma_addr_t)htt_tx_get_paddr(pdev, (char *)htt_host_tx_desc); + /* + * The allocated tx descriptor space includes headroom for a + * HTC frame header. Hide this headroom, so that we don't have + * to jump past the headroom each time we program a field within + * the tx desc, but only once when we download the tx desc (and + * the headroom) to the target via HTC. + * Skip past the headroom and return the address of the HTT tx desc. + */ + return (void *)htt_tx_desc; +} + +void htt_tx_desc_free(htt_pdev_handle pdev, void *tx_desc) +{ + char *htt_host_tx_desc = tx_desc; + /* rewind over the HTC frame header space */ + htt_host_tx_desc -= + offsetof(struct htt_host_tx_desc_t, align32.tx_desc); + *((uint32_t **) htt_host_tx_desc) = pdev->tx_descs.freelist; + pdev->tx_descs.freelist = (uint32_t *) htt_host_tx_desc; + pdev->tx_descs.alloc_cnt--; +} + +/*--- descriptor field access methods ---------------------------------------*/ + +/* PUT THESE AS inline IN ol_htt_tx_api.h */ + +void htt_tx_desc_flag_postponed(htt_pdev_handle pdev, void *desc) +{ +} + +void htt_tx_desc_flag_batch_more(htt_pdev_handle pdev, void *desc) +{ +} + +/*--- tx send function ------------------------------------------------------*/ + +#ifdef ATH_11AC_TXCOMPACT + +/* Scheduling the Queued packets in HTT which could not be sent out + because of No CE desc*/ +void htt_tx_sched(htt_pdev_handle pdev) +{ + qdf_nbuf_t msdu; + int download_len = pdev->download_len; + int packet_len; + + HTT_TX_NBUF_QUEUE_REMOVE(pdev, msdu); + while (msdu != NULL) { + int not_accepted; + /* packet length includes HTT tx desc frag added above */ + packet_len = qdf_nbuf_len(msdu); + if (packet_len < download_len) { + /* + * This case of packet length being less than the + * nominal download length can happen for a couple + * of reasons: + * In HL, the nominal download length is a large + * artificial value. + * In LL, the frame may not have the optional header + * fields accounted for in the nominal download size + * (LLC/SNAP header, IPv4 or IPv6 header). + */ + download_len = packet_len; + } + + not_accepted = + htc_send_data_pkt(pdev->htc_pdev, msdu, + pdev->htc_tx_endpoint, + download_len); + if (not_accepted) { + HTT_TX_NBUF_QUEUE_INSERT_HEAD(pdev, msdu); + return; + } + HTT_TX_NBUF_QUEUE_REMOVE(pdev, msdu); + } +} + +int htt_tx_send_std(htt_pdev_handle pdev, qdf_nbuf_t msdu, uint16_t msdu_id) +{ + + int download_len = pdev->download_len; + + int packet_len; + + /* packet length includes HTT tx desc frag added above */ + packet_len = qdf_nbuf_len(msdu); + if (packet_len < download_len) { + /* + * This case of packet length being less than the nominal + * download length can happen for a couple of reasons: + * In HL, the nominal download length is a large artificial + * value. + * In LL, the frame may not have the optional header fields + * accounted for in the nominal download size (LLC/SNAP header, + * IPv4 or IPv6 header). + */ + download_len = packet_len; + } + + if (QDF_NBUF_CB_TX_EXTRA_FRAG_FLAGS_EXT_HEADER(msdu)) + download_len += sizeof(struct htt_tx_msdu_desc_ext_t); + + + QDF_NBUF_UPDATE_TX_PKT_COUNT(msdu, QDF_NBUF_TX_PKT_HTT); + DPTRACE(qdf_dp_trace(msdu, QDF_DP_TRACE_HTT_PACKET_PTR_RECORD, + qdf_nbuf_data_addr(msdu), + sizeof(qdf_nbuf_data(msdu)), QDF_TX)); + if (qdf_nbuf_queue_len(&pdev->txnbufq) > 0) { + HTT_TX_NBUF_QUEUE_ADD(pdev, msdu); + htt_tx_sched(pdev); + return 0; + } + + if (htc_send_data_pkt(pdev->htc_pdev, msdu, + pdev->htc_tx_endpoint, download_len)) { + HTT_TX_NBUF_QUEUE_ADD(pdev, msdu); + } + + return 0; /* success */ + +} + +#ifndef CONFIG_HL_SUPPORT +#ifdef FEATURE_RUNTIME_PM +/** + * htt_tx_resume_handler() - resume callback for the htt endpoint + * @context: a pointer to the htt context + * + * runs htt_tx_sched. + */ +void htt_tx_resume_handler(void *context) +{ + struct htt_pdev_t *pdev = (struct htt_pdev_t *) context; + + htt_tx_sched(pdev); +} +#else +void +htt_tx_resume_handler(void *context) { } +#endif +#endif + +qdf_nbuf_t +htt_tx_send_batch(htt_pdev_handle pdev, qdf_nbuf_t head_msdu, int num_msdus) +{ + qdf_print("*** %s curently only applies for HL systems\n", __func__); + qdf_assert(0); + return head_msdu; + +} + +int +htt_tx_send_nonstd(htt_pdev_handle pdev, + qdf_nbuf_t msdu, + uint16_t msdu_id, enum htt_pkt_type pkt_type) +{ + int download_len; + + /* + * The pkt_type could be checked to see what L2 header type is present, + * and then the L2 header could be examined to determine its length. + * But for simplicity, just use the maximum possible header size, + * rather than computing the actual header size. + */ + download_len = sizeof(struct htt_host_tx_desc_t) + + HTT_TX_HDR_SIZE_OUTER_HDR_MAX /* worst case */ + + HTT_TX_HDR_SIZE_802_1Q + + HTT_TX_HDR_SIZE_LLC_SNAP + + ol_cfg_tx_download_size(pdev->ctrl_pdev); + qdf_assert(download_len <= pdev->download_len); + return htt_tx_send_std(pdev, msdu, msdu_id); +} + +#else /*ATH_11AC_TXCOMPACT */ + +#ifdef QCA_TX_HTT2_SUPPORT +static inline HTC_ENDPOINT_ID +htt_tx_htt2_get_ep_id(htt_pdev_handle pdev, qdf_nbuf_t msdu) +{ + /* + * TX HTT2 service mainly for small sized frame and check if + * this candidate frame allow or not. + */ + if ((pdev->htc_tx_htt2_endpoint != ENDPOINT_UNUSED) && + qdf_nbuf_get_tx_parallel_dnload_frm(msdu) && + (qdf_nbuf_len(msdu) < pdev->htc_tx_htt2_max_size)) + return pdev->htc_tx_htt2_endpoint; + else + return pdev->htc_tx_endpoint; +} +#else +#define htt_tx_htt2_get_ep_id(pdev, msdu) (pdev->htc_tx_endpoint) +#endif /* QCA_TX_HTT2_SUPPORT */ + +static inline int +htt_tx_send_base(htt_pdev_handle pdev, + qdf_nbuf_t msdu, + uint16_t msdu_id, int download_len, uint8_t more_data) +{ + struct htt_host_tx_desc_t *htt_host_tx_desc; + struct htt_htc_pkt *pkt; + int packet_len; + HTC_ENDPOINT_ID ep_id; + + /* + * The HTT tx descriptor was attached as the prefix fragment to the + * msdu netbuf during the call to htt_tx_desc_init. + * Retrieve it so we can provide its HTC header space to HTC. + */ + htt_host_tx_desc = (struct htt_host_tx_desc_t *) + qdf_nbuf_get_frag_vaddr(msdu, 0); + + pkt = htt_htc_pkt_alloc(pdev); + if (!pkt) + return -ENOBUFS; /* failure */ + + pkt->msdu_id = msdu_id; + pkt->pdev_ctxt = pdev->txrx_pdev; + + /* packet length includes HTT tx desc frag added above */ + packet_len = qdf_nbuf_len(msdu); + if (packet_len < download_len) { + /* + * This case of packet length being less than the nominal + * download length can happen for a couple reasons: + * In HL, the nominal download length is a large artificial + * value. + * In LL, the frame may not have the optional header fields + * accounted for in the nominal download size (LLC/SNAP header, + * IPv4 or IPv6 header). + */ + download_len = packet_len; + } + + ep_id = htt_tx_htt2_get_ep_id(pdev, msdu); + + SET_HTC_PACKET_INFO_TX(&pkt->htc_pkt, + pdev->tx_send_complete_part2, + (unsigned char *)htt_host_tx_desc, + download_len - HTC_HDR_LENGTH, + ep_id, + 1); /* tag - not relevant here */ + + SET_HTC_PACKET_NET_BUF_CONTEXT(&pkt->htc_pkt, msdu); + + QDF_NBUF_UPDATE_TX_PKT_COUNT(msdu, QDF_NBUF_TX_PKT_HTT); + DPTRACE(qdf_dp_trace(msdu, QDF_DP_TRACE_HTT_PACKET_PTR_RECORD, + qdf_nbuf_data_addr(msdu), + sizeof(qdf_nbuf_data(msdu)), QDF_TX)); + htc_send_data_pkt(pdev->htc_pdev, &pkt->htc_pkt, more_data); + + return 0; /* success */ +} + +qdf_nbuf_t +htt_tx_send_batch(htt_pdev_handle pdev, qdf_nbuf_t head_msdu, int num_msdus) +{ + qdf_nbuf_t rejected = NULL; + uint16_t *msdu_id_storage; + uint16_t msdu_id; + qdf_nbuf_t msdu; + /* + * FOR NOW, iterate through the batch, sending the frames singly. + * Eventually HTC and HIF should be able to accept a batch of + * data frames rather than singles. + */ + msdu = head_msdu; + while (num_msdus--) { + qdf_nbuf_t next_msdu = qdf_nbuf_next(msdu); + msdu_id_storage = ol_tx_msdu_id_storage(msdu); + msdu_id = *msdu_id_storage; + + /* htt_tx_send_base returns 0 as success and 1 as failure */ + if (htt_tx_send_base(pdev, msdu, msdu_id, pdev->download_len, + num_msdus)) { + qdf_nbuf_set_next(msdu, rejected); + rejected = msdu; + } + msdu = next_msdu; + } + return rejected; +} + +int +htt_tx_send_nonstd(htt_pdev_handle pdev, + qdf_nbuf_t msdu, + uint16_t msdu_id, enum htt_pkt_type pkt_type) +{ + int download_len; + + /* + * The pkt_type could be checked to see what L2 header type is present, + * and then the L2 header could be examined to determine its length. + * But for simplicity, just use the maximum possible header size, + * rather than computing the actual header size. + */ + download_len = sizeof(struct htt_host_tx_desc_t) + + HTT_TX_HDR_SIZE_OUTER_HDR_MAX /* worst case */ + + HTT_TX_HDR_SIZE_802_1Q + + HTT_TX_HDR_SIZE_LLC_SNAP + + ol_cfg_tx_download_size(pdev->ctrl_pdev); + return htt_tx_send_base(pdev, msdu, msdu_id, download_len, 0); +} + +int htt_tx_send_std(htt_pdev_handle pdev, qdf_nbuf_t msdu, uint16_t msdu_id) +{ + return htt_tx_send_base(pdev, msdu, msdu_id, pdev->download_len, 0); +} + +#endif /*ATH_11AC_TXCOMPACT */ + +#if defined(HTT_DBG) +void htt_tx_desc_display(void *tx_desc) +{ + struct htt_tx_msdu_desc_t *htt_tx_desc; + + htt_tx_desc = (struct htt_tx_msdu_desc_t *)tx_desc; + + /* only works for little-endian */ + qdf_print("HTT tx desc (@ %p):", htt_tx_desc); + qdf_print(" msg type = %d", htt_tx_desc->msg_type); + qdf_print(" pkt subtype = %d", htt_tx_desc->pkt_subtype); + qdf_print(" pkt type = %d", htt_tx_desc->pkt_type); + qdf_print(" vdev ID = %d", htt_tx_desc->vdev_id); + qdf_print(" ext TID = %d", htt_tx_desc->ext_tid); + qdf_print(" postponed = %d", htt_tx_desc->postponed); + qdf_print(" extension = %d", htt_tx_desc->extension); + qdf_print(" cksum_offload = %d", htt_tx_desc->cksum_offload); + qdf_print(" tx_compl_req= %d", htt_tx_desc->tx_compl_req); + qdf_print(" length = %d", htt_tx_desc->len); + qdf_print(" id = %d", htt_tx_desc->id); +#if HTT_PADDR64 + qdf_print(" frag desc addr.lo = %#x", + htt_tx_desc->frags_desc_ptr.lo); + qdf_print(" frag desc addr.hi = %#x", + htt_tx_desc->frags_desc_ptr.hi); +#else /* ! HTT_PADDR64 */ + qdf_print(" frag desc addr = %#x", htt_tx_desc->frags_desc_ptr); +#endif /* HTT_PADDR64 */ + qdf_print(" peerid = %d", htt_tx_desc->peerid); + qdf_print(" chanfreq = %d", htt_tx_desc->chanfreq); +} +#endif + +#ifdef IPA_OFFLOAD +#ifdef QCA_WIFI_3_0 +/** + * htt_tx_ipa_uc_wdi_tx_buf_alloc() - Alloc WDI TX buffers + * @pdev: htt context + * @uc_tx_buf_sz: TX buffer size + * @uc_tx_buf_cnt: TX Buffer count + * @uc_tx_partition_base: IPA UC TX partition base value + * + * Allocate WDI TX buffers. Also note Rome supports only WDI 1.0. + * + * Return: 0 success + */ + +static int htt_tx_ipa_uc_wdi_tx_buf_alloc(struct htt_pdev_t *pdev, + unsigned int uc_tx_buf_sz, + unsigned int uc_tx_buf_cnt, + unsigned int uc_tx_partition_base) +{ + unsigned int tx_buffer_count; + unsigned int tx_buffer_count_pwr2; + void *buffer_vaddr; + qdf_dma_addr_t buffer_paddr; + uint32_t *header_ptr; + qdf_dma_addr_t *ring_vaddr; + uint16_t idx; + + ring_vaddr = (qdf_dma_addr_t *)pdev->ipa_uc_tx_rsc.tx_comp_base.vaddr; + /* Allocate TX buffers as many as possible */ + for (tx_buffer_count = 0; + tx_buffer_count < (uc_tx_buf_cnt - 1); tx_buffer_count++) { + + buffer_vaddr = qdf_mem_alloc_consistent(pdev->osdev, + pdev->osdev->dev, uc_tx_buf_sz, &buffer_paddr); + if (!buffer_vaddr) { + qdf_print("IPA WDI TX buffer alloc fail %d allocated\n", + tx_buffer_count); + return tx_buffer_count; + } + + header_ptr = buffer_vaddr; + + /* HTT control header */ + *header_ptr = HTT_IPA_UC_OFFLOAD_TX_HEADER_DEFAULT; + header_ptr++; + + /* PKT ID */ + *header_ptr |= ((uint16_t) uc_tx_partition_base + + tx_buffer_count) << 16; + + header_ptr++; + + /* Frag Desc Pointer */ + /* 64bits descriptor, Low 32bits */ + *header_ptr = qdf_get_lower_32_bits(buffer_paddr + + IPA_UC_TX_BUF_FRAG_DESC_OFFSET); + header_ptr++; + + /* 64bits descriptor, high 32bits */ + *header_ptr = qdf_get_upper_32_bits(buffer_paddr) & + IPA_UC_TX_BUF_PADDR_HI_MASK; + header_ptr++; + + /* chanreq, peerid */ + *header_ptr = 0xFFFFFFFF; + header_ptr++; + + /* FRAG Header */ + /* 6 words TSO header */ + header_ptr += IPA_UC_TX_BUF_TSO_HDR_SIZE; + *header_ptr = buffer_paddr + IPA_UC_TX_BUF_FRAG_HDR_OFFSET; + + *ring_vaddr = buffer_paddr; + pdev->ipa_uc_tx_rsc.tx_buf_pool_vaddr_strg[tx_buffer_count] = + buffer_vaddr; + pdev->ipa_uc_tx_rsc.paddr_strg[tx_buffer_count] = + buffer_paddr; + /* Memory barrier to ensure actual value updated */ + + ring_vaddr++; + } + + /* + * Tx complete ring buffer count should be power of 2. + * So, allocated Tx buffer count should be one less than ring buffer + * size. + */ + tx_buffer_count_pwr2 = qdf_rounddown_pow_of_two(tx_buffer_count + 1) + - 1; + if (tx_buffer_count > tx_buffer_count_pwr2) { + qdf_print( + "%s: Allocated Tx buffer count %d is rounded down to %d", + __func__, tx_buffer_count, tx_buffer_count_pwr2); + + /* Free over allocated buffers below power of 2 */ + for (idx = tx_buffer_count_pwr2; idx < tx_buffer_count; idx++) { + if (pdev->ipa_uc_tx_rsc.tx_buf_pool_vaddr_strg[idx]) { + qdf_mem_free_consistent( + pdev->osdev, pdev->osdev->dev, + ol_cfg_ipa_uc_tx_buf_size(pdev->ctrl_pdev), + pdev->ipa_uc_tx_rsc.tx_buf_pool_vaddr_strg[idx], + pdev->ipa_uc_tx_rsc.paddr_strg[idx], 0); + } + } + } + + if (tx_buffer_count_pwr2 < 0) { + qdf_print("%s: Failed to round down Tx buffer count %d", + __func__, tx_buffer_count_pwr2); + tx_buffer_count_pwr2 = 0; + } + + return tx_buffer_count_pwr2; +} +#else +static int htt_tx_ipa_uc_wdi_tx_buf_alloc(struct htt_pdev_t *pdev, + unsigned int uc_tx_buf_sz, + unsigned int uc_tx_buf_cnt, + unsigned int uc_tx_partition_base) +{ + unsigned int tx_buffer_count; + unsigned int tx_buffer_count_pwr2; + qdf_nbuf_t buffer_vaddr; + qdf_dma_addr_t buffer_paddr; + uint32_t *header_ptr; + uint32_t *ring_vaddr; + uint16_t idx; + QDF_STATUS status; + + ring_vaddr = pdev->ipa_uc_tx_rsc.tx_comp_base.vaddr; + /* Allocate TX buffers as many as possible */ + for (tx_buffer_count = 0; + tx_buffer_count < (uc_tx_buf_cnt - 1); tx_buffer_count++) { + buffer_vaddr = qdf_nbuf_alloc(pdev->osdev, + uc_tx_buf_sz, 0, 4, false); + if (!buffer_vaddr) { + qdf_print("%s: TX BUF alloc fail, loop index: %d", + __func__, tx_buffer_count); + return tx_buffer_count; + } + + /* Init buffer */ + qdf_mem_zero(qdf_nbuf_data(buffer_vaddr), uc_tx_buf_sz); + header_ptr = (uint32_t *) qdf_nbuf_data(buffer_vaddr); + + /* HTT control header */ + *header_ptr = HTT_IPA_UC_OFFLOAD_TX_HEADER_DEFAULT; + header_ptr++; + + /* PKT ID */ + *header_ptr |= ((uint16_t) uc_tx_partition_base + + tx_buffer_count) << 16; + + status = qdf_nbuf_map(pdev->osdev, buffer_vaddr, + QDF_DMA_BIDIRECTIONAL); + if (status != QDF_STATUS_SUCCESS) { + QDF_TRACE(QDF_MODULE_ID_HTT, QDF_TRACE_LEVEL_ERROR, + "%s: nbuf map failed, loop index: %d", + __func__, tx_buffer_count); + qdf_nbuf_free(buffer_vaddr); + return tx_buffer_count; + } + + buffer_paddr = qdf_nbuf_get_frag_paddr(buffer_vaddr, 0); + header_ptr++; + *header_ptr = (uint32_t) (buffer_paddr + + IPA_UC_TX_BUF_FRAG_DESC_OFFSET); + header_ptr++; + *header_ptr = 0xFFFFFFFF; + + /* FRAG Header */ + header_ptr++; + *header_ptr = buffer_paddr + IPA_UC_TX_BUF_FRAG_HDR_OFFSET; + + *ring_vaddr = buffer_paddr; + pdev->ipa_uc_tx_rsc.tx_buf_pool_vaddr_strg[tx_buffer_count] = + buffer_vaddr; + /* Memory barrier to ensure actual value updated */ + + ring_vaddr++; + } + + /* + * Tx complete ring buffer count should be power of 2. + * So, allocated Tx buffer count should be one less than ring buffer + * size. + */ + tx_buffer_count_pwr2 = qdf_rounddown_pow_of_two(tx_buffer_count + 1) + - 1; + if (tx_buffer_count > tx_buffer_count_pwr2) { + qdf_print( + "%s: Allocated Tx buffer count %d is rounded down to %d", + __func__, tx_buffer_count, tx_buffer_count_pwr2); + + /* Free over allocated buffers below power of 2 */ + for (idx = tx_buffer_count_pwr2; idx < tx_buffer_count; idx++) { + if (pdev->ipa_uc_tx_rsc.tx_buf_pool_vaddr_strg[idx]) { + qdf_mem_free_consistent( + pdev->osdev, pdev->osdev->dev, + ol_cfg_ipa_uc_tx_buf_size(pdev->ctrl_pdev), + pdev->ipa_uc_tx_rsc.tx_buf_pool_vaddr_strg[idx], + pdev->ipa_uc_tx_rsc.paddr_strg[idx], 0); + } + } + } + + if (tx_buffer_count_pwr2 < 0) { + qdf_print("%s: Failed to round down Tx buffer count %d", + __func__, tx_buffer_count_pwr2); + tx_buffer_count_pwr2 = 0; + } + + return tx_buffer_count_pwr2; +} +#endif + +/** + * htt_tx_ipa_uc_attach() - attach htt ipa uc tx resource + * @pdev: htt context + * @uc_tx_buf_sz: single tx buffer size + * @uc_tx_buf_cnt: total tx buffer count + * @uc_tx_partition_base: tx buffer partition start + * + * Return: 0 success + * ENOBUFS No memory fail + */ +int htt_tx_ipa_uc_attach(struct htt_pdev_t *pdev, + unsigned int uc_tx_buf_sz, + unsigned int uc_tx_buf_cnt, + unsigned int uc_tx_partition_base) +{ + int return_code = 0; + unsigned int tx_comp_ring_size; + + /* Allocate CE Write Index WORD */ + pdev->ipa_uc_tx_rsc.tx_ce_idx.vaddr = + qdf_mem_alloc_consistent( + pdev->osdev, pdev->osdev->dev, + 4, &pdev->ipa_uc_tx_rsc.tx_ce_idx.paddr); + if (!pdev->ipa_uc_tx_rsc.tx_ce_idx.vaddr) { + qdf_print("%s: CE Write Index WORD alloc fail", __func__); + return -ENOBUFS; + } + + /* Allocate TX COMP Ring */ + tx_comp_ring_size = uc_tx_buf_cnt * sizeof(target_paddr_t); + pdev->ipa_uc_tx_rsc.tx_comp_base.vaddr = + qdf_mem_alloc_consistent( + pdev->osdev, pdev->osdev->dev, + tx_comp_ring_size, + &pdev->ipa_uc_tx_rsc.tx_comp_base.paddr); + if (!pdev->ipa_uc_tx_rsc.tx_comp_base.vaddr) { + qdf_print("%s: TX COMP ring alloc fail", __func__); + return_code = -ENOBUFS; + goto free_tx_ce_idx; + } + + qdf_mem_zero(pdev->ipa_uc_tx_rsc.tx_comp_base.vaddr, tx_comp_ring_size); + + /* Allocate TX BUF vAddress Storage */ + pdev->ipa_uc_tx_rsc.tx_buf_pool_vaddr_strg = + qdf_mem_malloc(uc_tx_buf_cnt * + sizeof(*pdev->ipa_uc_tx_rsc.tx_buf_pool_vaddr_strg)); + if (!pdev->ipa_uc_tx_rsc.tx_buf_pool_vaddr_strg) { + qdf_print("%s: TX BUF POOL vaddr storage alloc fail", __func__); + return_code = -ENOBUFS; + goto free_tx_comp_base; + } + + pdev->ipa_uc_tx_rsc.paddr_strg = + qdf_mem_malloc(uc_tx_buf_cnt * + sizeof(pdev->ipa_uc_tx_rsc.paddr_strg)); + if (!pdev->ipa_uc_tx_rsc.paddr_strg) { + qdf_print("%s: TX BUF POOL paddr storage alloc fail", __func__); + return_code = -ENOBUFS; + goto free_tx_buf_pool_vaddr_strg; + } + + pdev->ipa_uc_tx_rsc.alloc_tx_buf_cnt = htt_tx_ipa_uc_wdi_tx_buf_alloc( + pdev, uc_tx_buf_sz, uc_tx_buf_cnt, uc_tx_partition_base); + + + return 0; + +free_tx_buf_pool_vaddr_strg: + qdf_mem_free(pdev->ipa_uc_tx_rsc.tx_buf_pool_vaddr_strg); +free_tx_comp_base: + qdf_mem_free_consistent(pdev->osdev, pdev->osdev->dev, + tx_comp_ring_size, + pdev->ipa_uc_tx_rsc.tx_comp_base.vaddr, + pdev->ipa_uc_tx_rsc.tx_comp_base.paddr, + qdf_get_dma_mem_context((&pdev-> + ipa_uc_tx_rsc. + tx_comp_base), + memctx)); +free_tx_ce_idx: + qdf_mem_free_consistent(pdev->osdev, pdev->osdev->dev, + 4, + pdev->ipa_uc_tx_rsc.tx_ce_idx.vaddr, + pdev->ipa_uc_tx_rsc.tx_ce_idx.paddr, + qdf_get_dma_mem_context((&pdev-> + ipa_uc_tx_rsc. + tx_ce_idx), + memctx)); + return return_code; +} + +/** + * htt_tx_ipa_uc_detach() - Free WDI TX resources + * @pdev: htt context + * + * Remove IPA WDI TX resources during device detach + * Free all of allocated resources + * + * Return: 0 success + */ +int htt_tx_ipa_uc_detach(struct htt_pdev_t *pdev) +{ + uint16_t idx; + + if (pdev->ipa_uc_tx_rsc.tx_ce_idx.vaddr) { + qdf_mem_free_consistent( + pdev->osdev, pdev->osdev->dev, + 4, + pdev->ipa_uc_tx_rsc.tx_ce_idx.vaddr, + pdev->ipa_uc_tx_rsc.tx_ce_idx.paddr, + qdf_get_dma_mem_context( + (&pdev->ipa_uc_tx_rsc.tx_ce_idx), + memctx)); + } + + if (pdev->ipa_uc_tx_rsc.tx_comp_base.vaddr) { + qdf_mem_free_consistent( + pdev->osdev, pdev->osdev->dev, + ol_cfg_ipa_uc_tx_max_buf_cnt(pdev->ctrl_pdev) * + sizeof(qdf_nbuf_t), + pdev->ipa_uc_tx_rsc.tx_comp_base.vaddr, + pdev->ipa_uc_tx_rsc.tx_comp_base.paddr, + qdf_get_dma_mem_context((&pdev->ipa_uc_tx_rsc. + tx_comp_base), + memctx)); + } + + /* Free each single buffer */ + for (idx = 0; idx < pdev->ipa_uc_tx_rsc.alloc_tx_buf_cnt; idx++) { + if (pdev->ipa_uc_tx_rsc.tx_buf_pool_vaddr_strg[idx]) { + qdf_mem_free_consistent( + pdev->osdev, pdev->osdev->dev, + ol_cfg_ipa_uc_tx_buf_size(pdev->ctrl_pdev), + pdev->ipa_uc_tx_rsc.tx_buf_pool_vaddr_strg[idx], + pdev->ipa_uc_tx_rsc.paddr_strg[idx], 0); + } + } + + /* Free storage */ + qdf_mem_free(pdev->ipa_uc_tx_rsc.tx_buf_pool_vaddr_strg); + qdf_mem_free(pdev->ipa_uc_tx_rsc.paddr_strg); + + return 0; +} +#endif /* IPA_OFFLOAD */ + +#if defined(FEATURE_TSO) +void +htt_tx_desc_fill_tso_info(htt_pdev_handle pdev, void *desc, + struct qdf_tso_info_t *tso_info) +{ + u_int32_t *word; + int i; + struct qdf_tso_seg_elem_t *tso_seg = tso_info->curr_seg; + struct msdu_ext_desc_t *msdu_ext_desc = (struct msdu_ext_desc_t *)desc; + + word = (u_int32_t *)(desc); + + /* Initialize the TSO flags per MSDU */ + ((struct msdu_ext_desc_t *)msdu_ext_desc)->tso_flags = + tso_seg->seg.tso_flags; + + /* First 24 bytes (6*4) contain the TSO flags */ + TSO_DEBUG("%s seq# %u l2 len %d, ip len %d flags 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", + __func__, + tso_seg->seg.tso_flags.tcp_seq_num, + tso_seg->seg.tso_flags.l2_len, + tso_seg->seg.tso_flags.ip_len, + *word, + *(word + 1), + *(word + 2), + *(word + 3), + *(word + 4), + *(word + 5)); + + word += 6; + + for (i = 0; i < tso_seg->seg.num_frags; i++) { + uint32_t lo = 0; + uint32_t hi = 0; + qdf_dmaaddr_to_32s(tso_seg->seg.tso_frags[i].paddr, + &lo, &hi); + /* [31:0] first 32 bits of the buffer pointer */ + *word = lo; + word++; + /* [15:0] the upper 16 bits of the first buffer pointer */ + /* [31:16] length of the first buffer */ + *word = (tso_seg->seg.tso_frags[i].length << 16) | hi; + word++; + TSO_DEBUG("%s frag[%d] ptr_low 0x%x ptr_hi 0x%x len %u\n", + __func__, i, + msdu_ext_desc->frags[i].u.frag32.ptr_low, + msdu_ext_desc->frags[i].u.frag32.ptr_hi, + msdu_ext_desc->frags[i].u.frag32.len); + + } + + if (tso_seg->seg.num_frags < FRAG_NUM_MAX) { + *word = 0; + } +} +#endif /* FEATURE_TSO */ + +/** + * htt_get_ext_tid() - get ext_tid value + * @type: extension header type + * @ext_header_data: header data + * @msdu_info: msdu info + * + * Return: ext_tid value + */ +static inline +int htt_get_ext_tid(enum extension_header_type type, + void *ext_header_data, struct htt_msdu_info_t *msdu_info) +{ + if (type == OCB_MODE_EXT_HEADER && ext_header_data) + return ((struct ocb_tx_ctrl_hdr_t *)ext_header_data)->ext_tid; + else + return msdu_info->info.ext_tid; +} + +/** + * htt_get_channel_freq() - get channel frequency + * @type: extension header type + * @ext_header_data: header data + * + * Return: channel frequency number + */ +static inline +int htt_get_channel_freq(enum extension_header_type type, + void *ext_header_data) +{ + if (type == OCB_MODE_EXT_HEADER && ext_header_data) + return ((struct ocb_tx_ctrl_hdr_t *)ext_header_data) + ->channel_freq; + else + return HTT_INVALID_CHANNEL; +} + +/** + * htt_fill_ocb_ext_header() - fill OCB extension header + * @msdu: network buffer + * @local_desc_ext: extension descriptor + * @type: extension header type + * @ext_header_data: header data + * @is_dsrc: is dsrc is eenabled or not + * + * Return: none + */ +static +void htt_fill_ocb_ext_header(qdf_nbuf_t msdu, + struct htt_tx_msdu_desc_ext_t *local_desc_ext, + enum extension_header_type type, void *ext_header_data) +{ + struct ocb_tx_ctrl_hdr_t *tx_ctrl = + (struct ocb_tx_ctrl_hdr_t *)ext_header_data; + + if (tx_ctrl->all_flags == 0) + return; + /* + * Copy the info that was read from TX control header from the + * user application to the extended HTT header. + * First copy everything + * to a local temp structure, and then copy everything to the + * actual uncached structure in one go to save memory writes. + */ + local_desc_ext->valid_pwr = tx_ctrl->valid_pwr; + local_desc_ext->valid_mcs_mask = tx_ctrl->valid_datarate; + local_desc_ext->valid_retries = tx_ctrl->valid_retries; + local_desc_ext->valid_expire_tsf = tx_ctrl->valid_expire_tsf; + local_desc_ext->valid_chainmask = tx_ctrl->valid_chain_mask; + + local_desc_ext->pwr = tx_ctrl->pwr; + if (tx_ctrl->valid_datarate && + tx_ctrl->datarate <= htt_ofdm_datarate_max) + local_desc_ext->mcs_mask = + (1 << (tx_ctrl->datarate + 4)); + local_desc_ext->retry_limit = tx_ctrl->retry_limit; + local_desc_ext->expire_tsf_lo = tx_ctrl->expire_tsf_lo; + local_desc_ext->expire_tsf_hi = tx_ctrl->expire_tsf_hi; + local_desc_ext->chain_mask = tx_ctrl->chain_mask; + local_desc_ext->is_dsrc = 1; + qdf_nbuf_push_head(msdu, sizeof(struct htt_tx_msdu_desc_ext_t)); + qdf_mem_copy(qdf_nbuf_data(msdu), local_desc_ext, + sizeof(struct htt_tx_msdu_desc_ext_t)); + QDF_NBUF_CB_TX_EXTRA_FRAG_FLAGS_EXT_HEADER(msdu) = 1; +} + +/** + * htt_fill_wisa_ext_header() - fill WiSA extension header + * @msdu: network buffer + * @local_desc_ext: extension descriptor + * @type: extension header type + * @ext_header_data: header data + * + * Return: none + */ +static +void htt_fill_wisa_ext_header(qdf_nbuf_t msdu, + struct htt_tx_msdu_desc_ext_t *local_desc_ext, + enum extension_header_type type, void *ext_header_data) +{ + void *qdf_ctx = cds_get_context(QDF_MODULE_ID_QDF_DEVICE); + QDF_STATUS status; + + if (!qdf_ctx) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "%s: qdf_ctx is NULL", __func__); + return; + } + + local_desc_ext->valid_mcs_mask = 1; + if (WISA_MODE_EXT_HEADER_6MBPS == type) + local_desc_ext->mcs_mask = htt_ofdm_datarate_6_mbps; + else + local_desc_ext->mcs_mask = htt_ofdm_datarate_24_mbps; + local_desc_ext->valid_nss_mask = 1; + local_desc_ext->nss_mask = 1; + local_desc_ext->valid_bandwidth = 1; + local_desc_ext->bandwidth_mask = htt_tx_bandwidth_20MHz; + local_desc_ext->valid_guard_interval = 1; + local_desc_ext->guard_interval = htt_tx_guard_interval_regular; + + /* + * Do dma_unmap and dma_map again if already mapped + * as adding extra bytes in skb + */ + if (QDF_NBUF_CB_PADDR(msdu) != 0) + qdf_nbuf_unmap_single(qdf_ctx, msdu, QDF_DMA_TO_DEVICE); + + qdf_nbuf_push_head(msdu, sizeof(struct htt_tx_msdu_desc_ext_t)); + qdf_mem_copy(qdf_nbuf_data(msdu), local_desc_ext, + sizeof(struct htt_tx_msdu_desc_ext_t)); + + if (QDF_NBUF_CB_PADDR(msdu) != 0) { + status = qdf_nbuf_map_single(qdf_ctx, msdu, QDF_DMA_TO_DEVICE); + if (qdf_unlikely(status != QDF_STATUS_SUCCESS)) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_WARN, + "%s: nbuf map failed", __func__); + return; + } + } + QDF_NBUF_CB_TX_EXTRA_FRAG_FLAGS_EXT_HEADER(msdu) = 1; +} + +/** + * htt_push_ext_header() - fill extension header + * @msdu: network buffer + * @local_desc_ext: extension descriptor + * @type: extension header type + * @ext_header_data: header data + * @is_dsrc: is dsrc is eenabled or not + * + * Return: none + */ +static +void htt_push_ext_header(qdf_nbuf_t msdu, + struct htt_tx_msdu_desc_ext_t *local_desc_ext, + enum extension_header_type type, void *ext_header_data) +{ + switch (type) { + case OCB_MODE_EXT_HEADER: + htt_fill_ocb_ext_header(msdu, local_desc_ext, + type, ext_header_data); + break; + case WISA_MODE_EXT_HEADER_6MBPS: + case WISA_MODE_EXT_HEADER_24MBPS: + htt_fill_wisa_ext_header(msdu, local_desc_ext, + type, ext_header_data); + break; + default: + QDF_TRACE(QDF_MODULE_ID_HTT, QDF_TRACE_LEVEL_INFO, + "Invalid EXT header type %d\n", type); + break; + } +} + +QDF_STATUS +htt_tx_desc_init(htt_pdev_handle pdev, + void *htt_tx_desc, + qdf_dma_addr_t htt_tx_desc_paddr, + uint16_t msdu_id, + qdf_nbuf_t msdu, struct htt_msdu_info_t *msdu_info, + struct qdf_tso_info_t *tso_info, + void *ext_header_data, + enum extension_header_type type) +{ + uint8_t pkt_type, pkt_subtype = 0, ce_pkt_type = 0; + uint32_t hw_classify = 0, data_attr = 0; + uint32_t *word0, *word1, local_word3; +#if HTT_PADDR64 + uint32_t *word4; +#else /* ! HTT_PADDR64 */ + uint32_t *word3; +#endif /* HTT_PADDR64 */ + uint32_t local_word0, local_word1; + struct htt_host_tx_desc_t *htt_host_tx_desc = + (struct htt_host_tx_desc_t *) + (((char *)htt_tx_desc) - HTT_TX_DESC_VADDR_OFFSET); + bool desc_ext_required = (type != EXT_HEADER_NOT_PRESENT); + uint16_t channel_freq; + void *qdf_ctx = cds_get_context(QDF_MODULE_ID_QDF_DEVICE); + QDF_STATUS status; + + if (qdf_unlikely(!qdf_ctx)) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "%s: qdf_ctx is NULL", __func__); + return QDF_STATUS_E_FAILURE; + } + if (qdf_unlikely(!msdu_info)) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "%s: bad arg: msdu_info is NULL", __func__); + return QDF_STATUS_E_FAILURE; + } + if (qdf_unlikely(!tso_info)) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "%s: bad arg: tso_info is NULL", __func__); + return QDF_STATUS_E_FAILURE; + } + + word0 = (uint32_t *) htt_tx_desc; + word1 = word0 + 1; + /* + * word2 is frag desc pointer + * word3 or 4 is peer_id + */ +#if HTT_PADDR64 + word4 = word0 + 4; /* Dword 3 */ +#else /* ! HTT_PADDR64 */ + word3 = word0 + 3; /* Dword 3 */ +#endif /* HTT_PADDR64 */ + + pkt_type = msdu_info->info.l2_hdr_type; + + if (qdf_likely(pdev->cfg.ce_classify_enabled)) { + if (qdf_likely(pkt_type == htt_pkt_type_eth2 || + pkt_type == htt_pkt_type_ethernet)) + qdf_nbuf_tx_info_get(msdu, pkt_type, pkt_subtype, + hw_classify); + + ce_pkt_type = htt_to_ce_pkt_type[pkt_type]; + if (0xffffffff == ce_pkt_type) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_DEBUG, + "Invalid HTT pkt type %d\n", pkt_type); + return QDF_STATUS_E_INVAL; + } + } + + /* + * HTT Tx Desc is in uncached memory. Used cached writes per word, to + * reduce unnecessary memory access. + */ + + local_word0 = 0; + + HTT_H2T_MSG_TYPE_SET(local_word0, HTT_H2T_MSG_TYPE_TX_FRM); + HTT_TX_DESC_PKT_TYPE_SET(local_word0, pkt_type); + HTT_TX_DESC_PKT_SUBTYPE_SET(local_word0, pkt_subtype); + HTT_TX_DESC_VDEV_ID_SET(local_word0, msdu_info->info.vdev_id); + HTT_TX_DESC_EXT_TID_SET(local_word0, htt_get_ext_tid(type, + ext_header_data, msdu_info)); + HTT_TX_DESC_EXTENSION_SET(local_word0, desc_ext_required); + HTT_TX_DESC_EXT_TID_SET(local_word0, msdu_info->info.ext_tid); + HTT_TX_DESC_CKSUM_OFFLOAD_SET(local_word0, + msdu_info->action.cksum_offload); + if (pdev->cfg.is_high_latency) + HTT_TX_DESC_TX_COMP_SET(local_word0, msdu_info->action. + tx_comp_req); + HTT_TX_DESC_NO_ENCRYPT_SET(local_word0, + msdu_info->action.do_encrypt ? + 0 : 1); + + *word0 = local_word0; + + local_word1 = 0; + + if (tso_info->is_tso) { + uint32_t total_len = tso_info->curr_seg->seg.total_len; + + HTT_TX_DESC_FRM_LEN_SET(local_word1, total_len); + TSO_DEBUG("%s setting HTT TX DESC Len = curr_seg->seg.total_len %d\n", + __func__, total_len); + } else { + HTT_TX_DESC_FRM_LEN_SET(local_word1, qdf_nbuf_len(msdu)); + } + + HTT_TX_DESC_FRM_ID_SET(local_word1, msdu_id); + *word1 = local_word1; + + /* Initialize peer_id to INVALID_PEER because + this is NOT Reinjection path */ + local_word3 = HTT_INVALID_PEER; + channel_freq = htt_get_channel_freq(type, ext_header_data); + if (channel_freq != HTT_INVALID_CHANNEL) + HTT_TX_DESC_CHAN_FREQ_SET(local_word3, channel_freq); +#if HTT_PADDR64 + *word4 = local_word3; +#else /* ! HTT_PADDR64 */ + *word3 = local_word3; +#endif /* HTT_PADDR64 */ + + /* + * If any of the tx control flags are set, then we need the extended + * HTT header. + */ + if (desc_ext_required) { + struct htt_tx_msdu_desc_ext_t local_desc_ext = {0}; + + htt_push_ext_header(msdu, &local_desc_ext, + type, ext_header_data); + } + + /* + * Specify that the data provided by the OS is a bytestream, + * and thus should not be byte-swapped during the HIF download + * even if the host is big-endian. + * There could be extra fragments added before the OS's fragments, + * e.g. for TSO, so it's incorrect to clear the frag 0 wordstream flag. + * Instead, clear the wordstream flag for the final fragment, which + * is certain to be (one of the) fragment(s) provided by the OS. + * Setting the flag for this final fragment suffices for specifying + * all fragments provided by the OS rather than added by the driver. + */ + qdf_nbuf_set_frag_is_wordstream(msdu, qdf_nbuf_get_num_frags(msdu) - 1, + 0); + + if (QDF_NBUF_CB_PADDR(msdu) == 0) { + status = qdf_nbuf_map_single(qdf_ctx, msdu, QDF_DMA_TO_DEVICE); + if (qdf_unlikely(status != QDF_STATUS_SUCCESS)) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "%s: nbuf map failed", __func__); + return QDF_STATUS_E_NOMEM; + } + } + + /* store a link to the HTT tx descriptor within the netbuf */ + qdf_nbuf_frag_push_head(msdu, sizeof(struct htt_host_tx_desc_t), + (char *)htt_host_tx_desc, /* virtual addr */ + htt_tx_desc_paddr); + + /* + * Indicate that the HTT header (and HTC header) is a meta-data + * "wordstream", i.e. series of uint32_t, rather than a data + * bytestream. + * This allows the HIF download to byteswap the HTT + HTC headers if + * the host is big-endian, to convert to the target's little-endian + * format. + */ + qdf_nbuf_set_frag_is_wordstream(msdu, 0, 1); + + if (qdf_likely(pdev->cfg.ce_classify_enabled && + (msdu_info->info.l2_hdr_type != htt_pkt_type_mgmt))) { + uint32_t pkt_offset = qdf_nbuf_get_frag_len(msdu, 0); + + data_attr = hw_classify << QDF_CE_TX_CLASSIFY_BIT_S; + data_attr |= ce_pkt_type << QDF_CE_TX_PKT_TYPE_BIT_S; + data_attr |= pkt_offset << QDF_CE_TX_PKT_OFFSET_BIT_S; + } + + qdf_nbuf_data_attr_set(msdu, data_attr); + return QDF_STATUS_SUCCESS; +} + +#ifdef FEATURE_HL_GROUP_CREDIT_FLOW_CONTROL + +/** + * htt_tx_group_credit_process() - process group data for + * credit update indication + * @pdev: pointer to htt device. + * @msg_word: htt msg + * + * Return: None + */ +void htt_tx_group_credit_process(struct htt_pdev_t *pdev, u_int32_t *msg_word) +{ + int group_credit_sign; + int32_t group_credit; + u_int32_t group_credit_abs, vdev_id_mask, ac_mask; + u_int8_t group_abs, group_id; + u_int8_t group_offset = 0, more_group_present = 0; + more_group_present = HTT_TX_CREDIT_TXQ_GRP_GET(*msg_word); + + while (more_group_present) { + /* Parse the Group Data */ + group_id = HTT_TXQ_GROUP_ID_GET(*(msg_word+1 + +group_offset)); + group_credit_abs = + HTT_TXQ_GROUP_CREDIT_COUNT_GET(*(msg_word+1 + +group_offset)); + group_credit_sign = + HTT_TXQ_GROUP_SIGN_GET(*(msg_word+1 + +group_offset)) ? -1 : 1; + group_credit = group_credit_sign * group_credit_abs; + group_abs = HTT_TXQ_GROUP_ABS_GET(*(msg_word+1 + +group_offset)); + + vdev_id_mask = + HTT_TXQ_GROUP_VDEV_ID_MASK_GET(*(msg_word+2 + +group_offset)); + ac_mask = HTT_TXQ_GROUP_AC_MASK_GET(*(msg_word+2 + +group_offset)); + + ol_txrx_update_tx_queue_groups(pdev->txrx_pdev, group_id, + group_credit, group_abs, + vdev_id_mask, ac_mask); + more_group_present = HTT_TXQ_GROUP_EXT_GET(*(msg_word+1 + +group_offset)); + group_offset += HTT_TX_GROUP_INDEX_OFFSET; + } + ol_tx_update_group_credit_stats(pdev->txrx_pdev); +} +#endif diff --git a/drivers/staging/qcacld-3.0/core/dp/htt/htt_types.h b/drivers/staging/qcacld-3.0/core/dp/htt/htt_types.h new file mode 100644 index 0000000000000000000000000000000000000000..24116769fb2b13f5ede6ad787718e41dbd5a70ff --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/dp/htt/htt_types.h @@ -0,0 +1,454 @@ +/* + * Copyright (c) 2011, 2014-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef _HTT_TYPES__H_ +#define _HTT_TYPES__H_ + +#include /* uint16_t, dma_addr_t */ +#include /* qdf_device_t */ +#include /* qdf_spinlock_t */ +#include /* qdf_timer_t */ +#include /* qdf_atomic_inc */ +#include /* qdf_nbuf_t */ +#include /* HTC_PACKET */ +#include + +#define DEBUG_DMA_DONE + +#define HTT_TX_MUTEX_TYPE qdf_spinlock_t + +#ifdef QCA_TX_HTT2_SUPPORT +#ifndef HTC_TX_HTT2_MAX_SIZE +/* Should sync to the target's implementation. */ +#define HTC_TX_HTT2_MAX_SIZE (120) +#endif +#endif /* QCA_TX_HTT2_SUPPORT */ + +/* Set the base misclist size to the size of the htt tx copy engine + * to guarantee that a packet on the misclist wont be freed while it + * is sitting in the copy engine. + */ +#define HTT_HTC_PKT_MISCLIST_SIZE 2048 + +struct htt_htc_pkt { + void *pdev_ctxt; + target_paddr_t nbuf_paddr; + HTC_PACKET htc_pkt; + uint16_t msdu_id; +}; + +struct htt_htc_pkt_union { + union { + struct htt_htc_pkt pkt; + struct htt_htc_pkt_union *next; + } u; +}; + +/* + * HTT host descriptor: + * Include the htt_tx_msdu_desc that gets downloaded to the target, + * but also include the HTC_FRAME_HDR and alignment padding that + * precede the htt_tx_msdu_desc. + * htc_send_data_pkt expects this header space at the front of the + * initial fragment (i.e. tx descriptor) that is downloaded. + */ +struct htt_host_tx_desc_t { + uint8_t htc_header[HTC_HEADER_LEN]; + /* force the tx_desc field to begin on a 4-byte boundary */ + union { + uint32_t dummy_force_align; + struct htt_tx_msdu_desc_t tx_desc; + } align32; +}; + +struct htt_tx_mgmt_desc_buf { + qdf_nbuf_t msg_buf; + A_BOOL is_inuse; + qdf_nbuf_t mgmt_frm; +}; + +struct htt_tx_mgmt_desc_ctxt { + struct htt_tx_mgmt_desc_buf *pool; + A_UINT32 pending_cnt; +}; + +struct htt_list_node { + struct htt_list_node *prev; + struct htt_list_node *next; +}; + +struct htt_rx_hash_entry { + qdf_dma_addr_t paddr; + qdf_nbuf_t netbuf; + A_UINT8 fromlist; + struct htt_list_node listnode; +#ifdef RX_HASH_DEBUG + A_UINT32 cookie; +#endif +}; + +struct htt_rx_hash_bucket { + struct htt_list_node listhead; + struct htt_rx_hash_entry *entries; + struct htt_list_node freepool; +#ifdef RX_HASH_DEBUG + A_UINT32 count; +#endif +}; + +/* IPA micro controller + wlan host driver + firmware shared memory structure */ +struct uc_shared_mem_t { + uint32_t *vaddr; + qdf_dma_addr_t paddr; + qdf_dma_mem_context(memctx); +}; + +/* Micro controller datapath offload + * WLAN TX resources */ +struct htt_ipa_uc_tx_resource_t { + struct uc_shared_mem_t tx_ce_idx; + struct uc_shared_mem_t tx_comp_base; + + uint32_t tx_comp_idx_paddr; + void **tx_buf_pool_vaddr_strg; + qdf_dma_addr_t *paddr_strg; + uint32_t alloc_tx_buf_cnt; +}; + +/** + * struct htt_ipa_uc_rx_resource_t + * @rx_rdy_idx_paddr: rx ready index physical address + * @rx_ind_ring_base: rx indication ring base memory info + * @rx_ipa_prc_done_idx: rx process done index memory info + * @rx_ind_ring_size: rx process done ring size + * @rx2_rdy_idx_paddr: rx process done index physical address + * @rx2_ind_ring_base: rx process done indication ring base memory info + * @rx2_ipa_prc_done_idx: rx process done index memory info + * @rx2_ind_ring_size: rx process done ring size + */ +struct htt_ipa_uc_rx_resource_t { + qdf_dma_addr_t rx_rdy_idx_paddr; + struct uc_shared_mem_t rx_ind_ring_base; + struct uc_shared_mem_t rx_ipa_prc_done_idx; + uint32_t rx_ind_ring_size; + + /* 2nd RX ring */ + qdf_dma_addr_t rx2_rdy_idx_paddr; + struct uc_shared_mem_t rx2_ind_ring_base; + struct uc_shared_mem_t rx2_ipa_prc_done_idx; + uint32_t rx2_ind_ring_size; +}; + +/** + * struct ipa_uc_rx_ring_elem_t + * @rx_packet_paddr: rx packet physical address + * @vdev_id: virtual interface id + * @rx_packet_leng: packet length + */ +struct ipa_uc_rx_ring_elem_t { + target_paddr_t rx_packet_paddr; + uint32_t vdev_id; + uint32_t rx_packet_leng; +}; + +struct htt_tx_credit_t { + qdf_atomic_t bus_delta; + qdf_atomic_t target_delta; +}; + +#if defined(HELIUMPLUS) +/** + * msdu_ext_frag_desc: + * semantically, this is an array of 6 of 2-tuples of + * a 48-bit physical address and a 16 bit len field + * with the following layout: + * 31 16 8 0 + * | p t r - l o w 3 2 | + * | len | ptr-7/16 | + */ +struct msdu_ext_frag_desc { + union { + uint64_t desc64; + struct { + uint32_t ptr_low; + uint32_t ptr_hi:16, + len:16; + } frag32; + } u; +}; + +struct msdu_ext_desc_t { + struct qdf_tso_flags_t tso_flags; + struct msdu_ext_frag_desc frags[6]; +/* + u_int32_t frag_ptr0; + u_int32_t frag_len0; + u_int32_t frag_ptr1; + u_int32_t frag_len1; + u_int32_t frag_ptr2; + u_int32_t frag_len2; + u_int32_t frag_ptr3; + u_int32_t frag_len3; + u_int32_t frag_ptr4; + u_int32_t frag_len4; + u_int32_t frag_ptr5; + u_int32_t frag_len5; +*/ +}; +#endif /* defined(HELIUMPLUS) */ + +/** + * struct mon_channel + * @ch_num: Monitor mode capture channel number + * @ch_freq: channel frequency. + */ +struct mon_channel { + uint32_t ch_num; + uint32_t ch_freq; +}; + +struct htt_pdev_t { + ol_pdev_handle ctrl_pdev; + ol_txrx_pdev_handle txrx_pdev; + HTC_HANDLE htc_pdev; + qdf_device_t osdev; + + HTC_ENDPOINT_ID htc_tx_endpoint; + +#ifdef QCA_TX_HTT2_SUPPORT + HTC_ENDPOINT_ID htc_tx_htt2_endpoint; + uint16_t htc_tx_htt2_max_size; +#endif /* QCA_TX_HTT2_SUPPORT */ + +#ifdef ATH_11AC_TXCOMPACT + HTT_TX_MUTEX_TYPE txnbufq_mutex; + qdf_nbuf_queue_t txnbufq; + struct htt_htc_pkt_union *htt_htc_pkt_misclist; +#endif + + struct htt_htc_pkt_union *htt_htc_pkt_freelist; + struct { + int is_high_latency; + int is_full_reorder_offload; + int default_tx_comp_req; + int ce_classify_enabled; + uint8_t is_first_wakeup_packet; + } cfg; + struct { + uint8_t major; + uint8_t minor; + } tgt_ver; +#if defined(HELIUMPLUS) + struct { + u_int8_t major; + u_int8_t minor; + } wifi_ip_ver; +#endif /* defined(HELIUMPLUS) */ + struct { + struct { + /* + * Ring of network buffer objects - + * This ring is used exclusively by the host SW. + * This ring mirrors the dev_addrs_ring that is shared + * between the host SW and the MAC HW. + * The host SW uses this netbufs ring to locate the nw + * buffer objects whose data buffers the HW has filled. + */ + qdf_nbuf_t *netbufs_ring; + /* + * Ring of buffer addresses - + * This ring holds the "physical" device address of the + * rx buffers the host SW provides for MAC HW to fill. + */ +#if HTT_PADDR64 + uint64_t *paddrs_ring; +#else /* ! HTT_PADDR64 */ + uint32_t *paddrs_ring; +#endif + qdf_dma_mem_context(memctx); + } buf; + /* + * Base address of ring, as a "physical" device address rather + * than a CPU address. + */ + qdf_dma_addr_t base_paddr; + int32_t size; /* how many elems in the ring (power of 2) */ + uint32_t size_mask; /* size - 1, at least 16 bits long */ + + int fill_level; /* how many rx buffers to keep in the ring */ + int fill_cnt; /* # of rx buffers (full+empty) in the ring */ + + /* + * target_idx - + * Without reorder offload: + * not used + * With reorder offload: + * points to the location in the rx ring from which rx buffers + * are available to copy into the MAC DMA ring + */ + struct { + uint32_t *vaddr; + qdf_dma_addr_t paddr; + qdf_dma_mem_context(memctx); + } target_idx; + + /* + * alloc_idx/host_idx - + * Without reorder offload: + * where HTT SW has deposited empty buffers + * This is allocated in consistent mem, so that the FW can read + * this variable, and program the HW's FW_IDX reg with the value + * of this shadow register + * With reorder offload: + * points to the end of the available free rx buffers + */ + struct { + uint32_t *vaddr; + qdf_dma_addr_t paddr; + qdf_dma_mem_context(memctx); + } alloc_idx; + + /* sw_rd_idx - + * where HTT SW has processed bufs filled by rx MAC DMA */ + struct { + unsigned msdu_desc; + unsigned msdu_payld; + } sw_rd_idx; + + /* + * refill_retry_timer - timer triggered when the ring is not + * refilled to the level expected + */ + qdf_timer_t refill_retry_timer; + + /* + * refill_ref_cnt - ref cnt for Rx buffer replenishment - this + * variable is used to guarantee that only one thread tries + * to replenish Rx ring. + */ + qdf_atomic_t refill_ref_cnt; + qdf_spinlock_t refill_lock; + qdf_atomic_t refill_debt; +#ifdef DEBUG_DMA_DONE + uint32_t dbg_initial_msdu_payld; + uint32_t dbg_mpdu_range; + uint32_t dbg_mpdu_count; + uint32_t dbg_ring_idx; + uint32_t dbg_refill_cnt; + uint32_t dbg_sync_success; +#endif +#ifdef HTT_RX_RESTORE + int rx_reset; + uint8_t htt_rx_restore; +#endif + qdf_spinlock_t rx_hash_lock; + struct htt_rx_hash_bucket **hash_table; + uint32_t listnode_offset; + } rx_ring; +#ifdef CONFIG_HL_SUPPORT + int rx_desc_size_hl; +#endif + long rx_fw_desc_offset; + int rx_mpdu_range_offset_words; + int rx_ind_msdu_byte_idx; + + struct { + int size; /* of each HTT tx desc */ + uint16_t pool_elems; + uint16_t alloc_cnt; + struct qdf_mem_multi_page_t desc_pages; + uint32_t *freelist; + qdf_dma_mem_context(memctx); + } tx_descs; +#if defined(HELIUMPLUS) + struct { + int size; /* of each Fragment/MSDU-Ext descriptor */ + int pool_elems; + struct qdf_mem_multi_page_t desc_pages; + qdf_dma_mem_context(memctx); + } frag_descs; +#endif /* defined(HELIUMPLUS) */ + + int download_len; + void (*tx_send_complete_part2)(void *pdev, A_STATUS status, + qdf_nbuf_t msdu, uint16_t msdu_id); + + HTT_TX_MUTEX_TYPE htt_tx_mutex; + + struct { + int htc_err_cnt; + } stats; +#ifdef CONFIG_HL_SUPPORT + int cur_seq_num_hl; +#endif + struct htt_tx_mgmt_desc_ctxt tx_mgmt_desc_ctxt; + struct targetdef_s *targetdef; + struct ce_reg_def *target_ce_def; + + struct htt_ipa_uc_tx_resource_t ipa_uc_tx_rsc; + struct htt_ipa_uc_rx_resource_t ipa_uc_rx_rsc; + + struct htt_tx_credit_t htt_tx_credit; + +#ifdef DEBUG_RX_RING_BUFFER + struct rx_buf_debug *rx_buff_list; + qdf_spinlock_t rx_buff_list_lock; + int rx_buff_index; + int rx_buff_posted_cum; + int rx_buff_recvd_cum; + int rx_buff_recvd_err; +#endif + /* + * Counters below are being invoked from functions defined outside of + * DEBUG_RX_RING_BUFFER + */ + int rx_buff_debt_invoked; + int rx_buff_fill_n_invoked; + int refill_retry_timer_starts; + int refill_retry_timer_calls; + int refill_retry_timer_doubles; + + /* callback function for packetdump */ + tp_rx_pkt_dump_cb rx_pkt_dump_cb; + + struct mon_channel mon_ch_info; +}; + +#define HTT_EPID_GET(_htt_pdev_hdl) \ + (((struct htt_pdev_t *)(_htt_pdev_hdl))->htc_tx_endpoint) + +#if defined(HELIUMPLUS) +#define HTT_WIFI_IP(pdev, x, y) (((pdev)->wifi_ip_ver.major == (x)) && \ + ((pdev)->wifi_ip_ver.minor == (y))) + +#define HTT_SET_WIFI_IP(pdev, x, y) (((pdev)->wifi_ip_ver.major = (x)) && \ + ((pdev)->wifi_ip_ver.minor = (y))) +#endif /* defined(HELIUMPLUS) */ + +#endif /* _HTT_TYPES__H_ */ diff --git a/drivers/staging/qcacld-3.0/core/dp/htt/rx_desc.h b/drivers/staging/qcacld-3.0/core/dp/htt/rx_desc.h new file mode 100644 index 0000000000000000000000000000000000000000..faf103dc2ca6be14004b16ea19948ef5b8c8ea1c --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/dp/htt/rx_desc.h @@ -0,0 +1,543 @@ +/* + * Copyright (c) 2011-2015, 2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef _RX_DESC_H_ +#define _RX_DESC_H_ + +/* + * REMIND: Copy one of rx_desc related structures here for export, + * hopes they are always the same between Peregrine and Rome in future + */ +struct rx_attention { + volatile + uint32_t first_mpdu:1, /* [0] */ + last_mpdu:1, /* [1] */ + mcast_bcast:1, /* [2] */ + peer_idx_invalid:1, /* [3] */ + peer_idx_timeout:1, /* [4] */ + power_mgmt:1, /* [5] */ + non_qos:1, /* [6] */ + null_data:1, /* [7] */ + mgmt_type:1, /* [8] */ + ctrl_type:1, /* [9] */ + more_data:1, /* [10] */ + eosp:1, /* [11] */ + u_apsd_trigger:1, /* [12] */ + fragment:1, /* [13] */ + order:1, /* [14] */ + classification:1, /* [15] */ + overflow_err:1, /* [16] */ + msdu_length_err:1, /* [17] */ + tcp_udp_chksum_fail:1, /* [18] */ + ip_chksum_fail:1, /* [19] */ + sa_idx_invalid:1, /* [20] */ + da_idx_invalid:1, /* [21] */ + sa_idx_timeout:1, /* [22] */ + da_idx_timeout:1, /* [23] */ + encrypt_required:1, /* [24] */ + directed:1, /* [25] */ + buffer_fragment:1, /* [26] */ + mpdu_length_err:1, /* [27] */ + tkip_mic_err:1, /* [28] */ + decrypt_err:1, /* [29] */ + fcs_err:1, /* [30] */ + msdu_done:1; /* [31] */ +}; + +struct rx_frag_info { + volatile + uint32_t ring0_more_count:8, /* [7:0] */ + ring1_more_count:8, /* [15:8] */ + ring2_more_count:8, /* [23:16] */ + ring3_more_count:8; /* [31:24] */ + volatile + uint32_t ring4_more_count:8, /* [7:0] */ + ring5_more_count:8, /* [15:8] */ + ring6_more_count:8, /* [23:16] */ + ring7_more_count:8; /* [31:24] */ +}; + +struct rx_msdu_start { + volatile + uint32_t msdu_length:14, /* [13:0] */ +#if defined(HELIUMPLUS) + l3_offset:7, /* [20:14] */ + ipsec_ah:1, /* [21] */ + reserved_0a:2, /* [23:22] */ + l4_offset:7, /* [30:24] */ + ipsec_esp:1; /* [31] */ +#else + ip_offset:6, /* [19:14] */ + ring_mask:4, /* [23:20] */ + tcp_udp_offset:7, /* [30:24] */ + reserved_0c:1; /* [31] */ +#endif /* defined(HELIUMPLUS) */ +#if defined(HELIUMPLUS) + volatile uint32_t flow_id_toeplitz:32; /* [31:0] */ +#else + volatile uint32_t flow_id_crc:32; /* [31:0] */ +#endif /* defined(HELIUMPLUS) */ + volatile + uint32_t msdu_number:8, /* [7:0] */ + decap_format:2, /* [9:8] */ + ipv4_proto:1, /* [10] */ + ipv6_proto:1, /* [11] */ + tcp_proto:1, /* [12] */ + udp_proto:1, /* [13] */ + ip_frag:1, /* [14] */ + tcp_only_ack:1, /* [15] */ + sa_idx:11, /* [26:16] */ + reserved_2b:5; /* [31:27] */ +#if defined(HELIUMPLUS) + volatile + uint32_t da_idx:11, /* [10:0] */ + da_is_bcast_mcast:1, /* [11] */ + reserved_3a:4, /* [15:12] */ + ip4_protocol_ip6_next_header:8, /* [23:16] */ + ring_mask:8; /* [31:24] */ + volatile uint32_t toeplitz_hash_2_or_4:32; /* [31:0] */ +#endif /* defined(HELIUMPLUS) */ +}; + +struct rx_msdu_end { + volatile + uint32_t ip_hdr_chksum:16, /* [15:0] */ + tcp_udp_chksum:16; /* [31:16] */ + volatile + uint32_t key_id_octet:8, /* [7:0] */ +#if defined(HELIUMPLUS) + classification_rule:6, /* [13:8] */ + classify_not_done_truncate:1, /* [14] */ + classify_not_done_cce_dis:1, /* [15] */ +#else + classification_filter:8, /* [15:8] */ +#endif /* defined(HELIUMPLUS) */ + ext_wapi_pn_63_48:16; /* [31:16] */ + volatile uint32_t ext_wapi_pn_95_64:32; /* [31:0] */ + volatile uint32_t ext_wapi_pn_127_96:32; /* [31:0] */ + volatile + uint32_t reported_mpdu_length:14, /* [13:0] */ + first_msdu:1, /* [14] */ + last_msdu:1, /* [15] */ +#if defined(HELIUMPLUS) + sa_idx_timeout:1, /* [16] */ + da_idx_timeout:1, /* [17] */ + msdu_limit_error:1, /* [18] */ + classify_ring_mask:8, /* [26:19] */ +#endif /* defined(HELIUMPLUS) */ + reserved_3a:3, /* [29:27] */ + pre_delim_err:1, /* [30] */ + reserved_3b:1; /* [31] */ +#if defined(HELIUMPLUS) + volatile uint32_t ipv6_options_crc:32; + volatile uint32_t tcp_seq_number:32; + volatile uint32_t tcp_ack_number:32; + volatile + uint32_t tcp_flag:9, /* [8:0] */ + lro_eligible:1, /* [9] */ + l3_header_padding:3, /* [12:10] */ + reserved_8a:3, /* [15:13] */ + window_size:16; /* [31:16] */ + volatile + uint32_t da_offset:6, /* [5:0] */ + sa_offset:6, /* [11:6] */ + da_offset_valid:1, /* [12] */ + sa_offset_valid:1, /* [13] */ + type_offset:7, /* [20:14] */ + reserved_9a:11; /* [31:21] */ + volatile uint32_t rule_indication_31_0:32; + volatile uint32_t rule_indication_63_32:32; + volatile uint32_t rule_indication_95_64:32; + volatile uint32_t rule_indication_127_96:32; +#endif /* defined(HELIUMPLUS) */ +}; + +struct rx_mpdu_end { + volatile + uint32_t reserved_0:13, /* [12:0] */ + overflow_err:1, /* [13] */ + last_mpdu:1, /* [14] */ + post_delim_err:1, /* [15] */ + post_delim_cnt:12, /* [27:16] */ + mpdu_length_err:1, /* [28] */ + tkip_mic_err:1, /* [29] */ + decrypt_err:1, /* [30] */ + fcs_err:1; /* [31] */ +}; + + +#if defined(HELIUMPLUS) + +struct rx_mpdu_start { + volatile + uint32_t peer_idx:11, /* [10:0] */ + fr_ds:1, /* [11] */ + to_ds:1, /* [12] */ + encrypted:1, /* [13] */ + retry:1, /* [14] */ + reserved:1, /* [15] */ + seq_num:12, /* [27:16] */ + encrypt_type:4; /* [31:28] */ + volatile uint32_t pn_31_0:32; /* [31:0] */ + volatile + uint32_t pn_47_32:16, /* [15:0] */ + toeplitz_hash:2, /* [17:16] */ + reserved_2:10, /* [27:18] */ + tid:4; /* [31:28] */ +}; + + +struct rx_ppdu_start { + volatile + uint32_t rssi_pri_chain0:8, /* [7:0] */ + rssi_sec20_chain0:8, /* [15:8] */ + rssi_sec40_chain0:8, /* [23:16] */ + rssi_sec80_chain0:8; /* [31:24] */ + volatile + uint32_t rssi_pri_chain1:8, /* [7:0] */ + rssi_sec20_chain1:8, /* [15:8] */ + rssi_sec40_chain1:8, /* [23:16] */ + rssi_sec80_chain1:8; /* [31:24] */ + volatile + uint32_t rssi_pri_chain2:8, /* [7:0] */ + rssi_sec20_chain2:8, /* [15:8] */ + rssi_sec40_chain2:8, /* [23:16] */ + rssi_sec80_chain2:8; /* [31:24] */ + volatile + uint32_t rssi_pri_chain3:8, /* [7:0] */ + rssi_sec20_chain3:8, /* [15:8] */ + rssi_sec40_chain3:8, /* [23:16] */ + rssi_sec80_chain3:8; /* [31:24] */ + volatile + uint32_t rssi_comb:8, /* [7:0] */ + bandwidth:3, /* [10:8] */ + reserved_4a:5, /* [15:11] */ + rssi_comb_ht:8, /* [23:16] */ + reserved_4b:8; /* [31:24] */ + volatile + uint32_t l_sig_rate:4, /*[3:0] */ + l_sig_rate_select:1, /* [4] */ + l_sig_length:12, /* [16:5] */ + l_sig_parity:1, /* [17] */ + l_sig_tail:6, /* [23:18] */ + preamble_type:8; /* [31:24] */ + volatile + uint32_t ht_sig_vht_sig_ah_sig_a_1:24, /* [23:0] */ + captured_implicit_sounding:1, /* [24] */ + reserved_6:7; /* [31:25] */ + volatile + uint32_t ht_sig_vht_sig_ah_sig_a_2:24, /* [23:0] */ + reserved_7:8; /* [31:24] */ + volatile uint32_t vht_sig_b:32; /* [31:0] */ + volatile + uint32_t service:16, /* [15:0] */ + reserved_9:16; /* [31:16] */ +}; + +#define VHT_SIG_A_1(rx_desc) ((rx_desc)->ppdu_start.ht_sig_vht_sig_ah_sig_a_1) +#define VHT_SIG_A_2(rx_desc) ((rx_desc)->ppdu_start.ht_sig_vht_sig_ah_sig_a_2) +#define TSF_TIMESTAMP(rx_desc) \ +((rx_desc)->ppdu_end.rx_pkt_end.phy_timestamp_1_lower_32) + +struct rx_location_info { + volatile + uint32_t rtt_fac_legacy:14, /* [13:0] */ + rtt_fac_legacy_status:1, /* [14] */ + rtt_fac_vht:14, /* [28:15] */ + rtt_fac_vht_status:1, /* [29] */ + rtt_cfr_status:1, /* [30] */ + rtt_cir_status:1; /* [31] */ + volatile + uint32_t rtt_fac_sifs:10, /* [9:0] */ + rtt_fac_sifs_status:2, /* [11:10] */ + rtt_channel_dump_size:11, /* [22:12] */ + rtt_mac_phy_phase:2, /* [24:23] */ + rtt_hw_ifft_mode:1, /* [25] */ + rtt_btcf_status:1, /* [26] */ + rtt_preamble_type:2, /* [28:27] */ + rtt_pkt_bw:2, /* [30:29] */ + rtt_gi_type:1; /* [31] */ + volatile + uint32_t rtt_mcs_rate:4, /* [3:0] */ + rtt_strongest_chain:2, /* [5:4] */ + rtt_phase_jump:7, /* [12:6] */ + rtt_rx_chain_mask:4, /* [16:13] */ + rtt_tx_data_start_x_phase:1, /* [17] */ + reserved_2:13, /* [30:18] */ + rx_location_info_valid:1; /* [31] */ +}; + +struct rx_pkt_end { + volatile + uint32_t rx_success:1, /* [0] */ + reserved_0a:2, /* [2:1] */ + error_tx_interrupt_rx:1, /* [3] */ + error_ofdm_power_drop:1, /* [4] */ + error_ofdm_restart:1, /* [5] */ + error_cck_power_drop:1, /* [6] */ + error_cck_restart:1, /* [7] */ + reserved_0b:24; /* [31:8] */ + volatile uint32_t phy_timestamp_1_lower_32:32; /* [31:0] */ + volatile uint32_t phy_timestamp_1_upper_32:32; /* [31:0] */ + volatile uint32_t phy_timestamp_2_lower_32:32; /* [31:0] */ + volatile uint32_t phy_timestamp_2_upper_32:32; /* [31:0] */ + struct rx_location_info rx_location_info; +}; + +struct rx_phy_ppdu_end { + volatile + uint32_t reserved_0a:2, /* [1:0] */ + error_radar:1, /* [2] */ + error_rx_abort:1, /* [3] */ + error_rx_nap:1, /* [4] */ + error_ofdm_timing:1, /* [5] */ + error_ofdm_signal_parity:1, /* [6] */ + error_ofdm_rate_illegal:1, /* [7] */ + error_ofdm_length_illegal:1, /* [8] */ + error_ppdu_ofdm_restart:1, /* [9] */ + error_ofdm_service:1, /* [10] */ + error_ppdu_ofdm_power_drop:1, /* [11] */ + error_cck_blocker:1, /* [12] */ + error_cck_timing:1, /* [13] */ + error_cck_header_crc:1, /* [14] */ + error_cck_rate_illegal:1, /* [15] */ + error_cck_length_illegal:1, /* [16] */ + error_ppdu_cck_restart:1, /* [17] */ + error_cck_service:1, /* [18] */ + error_ppdu_cck_power_drop:1, /* [19] */ + error_ht_crc_err:1, /* [20] */ + error_ht_length_illegal:1, /* [21] */ + error_ht_rate_illegal:1, /* [22] */ + error_ht_zlf:1, /* [23] */ + error_false_radar_ext:1, /* [24] */ + error_green_field:1, /* [25] */ + error_spectral_scan:1, /* [26] */ + error_rx_bw_gt_dyn_bw:1, /* [27] */ + error_leg_ht_mismatch:1, /* [28] */ + error_vht_crc_error:1, /* [29] */ + error_vht_siga_unsupported:1, /* [30] */ + error_vht_lsig_len_invalid:1; /* [31] */ + volatile + uint32_t error_vht_ndp_or_zlf:1, /* [0] */ + error_vht_nsym_lt_zero:1, /* [1] */ + error_vht_rx_extra_symbol_mismatch:1, /* [2] */ + error_vht_rx_skip_group_id0:1, /* [3] */ + error_vht_rx_skip_group_id1to62:1, /* [4] */ + error_vht_rx_skip_group_id63:1, /* [5] */ + error_ofdm_ldpc_decoder_disabled:1, /* [6] */ + error_defer_nap:1, /* [7] */ + error_fdomain_timeout:1, /* [8] */ + error_lsig_rel_check:1, /* [9] */ + error_bt_collision:1, /* [10] */ + error_unsupported_mu_feedback:1, /* [11] */ + error_ppdu_tx_interrupt_rx:1, /* [12] */ + error_rx_unsupported_cbf:1, /* [13] */ + reserved_1:18; /* [31:14] */ +}; + +struct rx_timing_offset { + volatile + uint32_t timing_offset:12, /* [11:0] */ + reserved:20; /* [31:12] */ +}; + +struct rx_ppdu_end { + volatile uint32_t evm_p0:32; + volatile uint32_t evm_p1:32; + volatile uint32_t evm_p2:32; + volatile uint32_t evm_p3:32; + volatile uint32_t evm_p4:32; + volatile uint32_t evm_p5:32; + volatile uint32_t evm_p6:32; + volatile uint32_t evm_p7:32; + volatile uint32_t evm_p8:32; + volatile uint32_t evm_p9:32; + volatile uint32_t evm_p10:32; + volatile uint32_t evm_p11:32; + volatile uint32_t evm_p12:32; + volatile uint32_t evm_p13:32; + volatile uint32_t evm_p14:32; + volatile uint32_t evm_p15:32; + volatile uint32_t reserved_16:32; + volatile uint32_t reserved_17:32; + volatile uint32_t wb_timestamp_lower_32:32; + volatile uint32_t wb_timestamp_upper_32:32; + struct rx_pkt_end rx_pkt_end; + struct rx_phy_ppdu_end rx_phy_ppdu_end; + struct rx_timing_offset rx_timing_offset; + volatile + uint32_t rx_antenna:24, /* [23:0] */ + tx_ht_vht_ack:1, /* [24] */ + rx_pkt_end_valid:1, /* [25] */ + rx_phy_ppdu_end_valid:1, /* [26] */ + rx_timing_offset_valid:1, /* [27] */ + bb_captured_channel:1, /* [28] */ + unsupported_mu_nc:1, /* [29] */ + otp_txbf_disable:1, /* [30] */ + reserved_31:1; /* [31] */ + volatile + uint32_t coex_bt_tx_from_start_of_rx:1, /* [0] */ + coex_bt_tx_after_start_of_rx:1, /* [1] */ + coex_wan_tx_from_start_of_rx:1, /* [2] */ + coex_wan_tx_after_start_of_rx:1, /* [3] */ + coex_wlan_tx_from_start_of_rx:1, /* [4] */ + coex_wlan_tx_after_start_of_rx:1, /* [5] */ + mpdu_delimiter_errors_seen:1, /* [6] */ + ftm:1, /* [7] */ + ftm_dialog_token:8, /* [15:8] */ + ftm_follow_up_dialog_token:8, /* [23:16] */ + reserved_32:8; /* [31:24] */ + volatile + uint32_t before_mpdu_cnt_passing_fcs:8, /* [7:0] */ + before_mpdu_cnt_failing_fcs:8, /* [15:8] */ + after_mpdu_cnt_passing_fcs:8, /* [23:16] */ + after_mpdu_cnt_failing_fcs:8; /* [31:24] */ + volatile uint32_t phy_timestamp_tx_lower_32:32; /* [31:0] */ + volatile uint32_t phy_timestamp_tx_upper_32:32; /* [31:0] */ + volatile + uint32_t bb_length:16, /* [15:0] */ + bb_data:1, /* [16] */ + peer_idx_valid:1, /* [17] */ + peer_idx:11, /* [28:18] */ + reserved_26:2, /* [30:29] */ + ppdu_done:1; /* [31] */ +}; +#else +struct rx_ppdu_start { + volatile + uint32_t rssi_chain0_pri20:8, /* [7:0] */ + rssi_chain0_sec20:8, /* [15:8] */ + rssi_chain0_sec40:8, /* [23:16] */ + rssi_chain0_sec80:8; /* [31:24] */ + volatile + uint32_t rssi_chain1_pri20:8, /* [7:0] */ + rssi_chain1_sec20:8, /* [15:8] */ + rssi_chain1_sec40:8, /* [23:16] */ + rssi_chain1_sec80:8; /* [31:24] */ + volatile + uint32_t rssi_chain2_pri20:8, /* [7:0] */ + rssi_chain2_sec20:8, /* [15:8] */ + rssi_chain2_sec40:8, /* [23:16] */ + rssi_chain2_sec80:8; /* [31:24] */ + volatile + uint32_t rssi_chain3_pri20:8, /* [7:0] */ + rssi_chain3_sec20:8, /* [15:8] */ + rssi_chain3_sec40:8, /* [23:16] */ + rssi_chain3_sec80:8; /* [31:24] */ + volatile + uint32_t rssi_comb:8, /* [7:0] */ + reserved_4a:16, /* [23:8] */ + is_greenfield:1, /* [24] */ + reserved_4b:7; /* [31:25] */ + volatile + uint32_t l_sig_rate:4, /* [3:0] */ + l_sig_rate_select:1, /* [4] */ + l_sig_length:12, /* [16:5] */ + l_sig_parity:1, /* [17] */ + l_sig_tail:6, /* [23:18] */ + preamble_type:8; /* [31:24] */ + volatile + uint32_t ht_sig_vht_sig_a_1:24, /* [23:0] */ + reserved_6:8; /* [31:24] */ + volatile + uint32_t ht_sig_vht_sig_a_2:24, /* [23:0] */ + txbf_h_info:1, /* [24] */ + reserved_7:7; /* [31:25] */ + volatile + uint32_t vht_sig_b:29, /* [28:0] */ + reserved_8:3; /* [31:29] */ + volatile + uint32_t service:16, /* [15:0] */ + reserved_9:16; /* [31:16] */ +}; + +#define VHT_SIG_A_1(rx_desc) ((rx_desc)->ppdu_start.ht_sig_vht_sig_a_1) +#define VHT_SIG_A_2(rx_desc) ((rx_desc)->ppdu_start.ht_sig_vht_sig_a_2) + +#define TSF_TIMESTAMP(rx_desc) ((rx_desc)->ppdu_end.tsf_timestamp) + +struct rx_mpdu_start { + volatile + uint32_t peer_idx:11, /* [10:0] */ + fr_ds:1, /* [11] */ + to_ds:1, /* [12] */ + encrypted:1, /* [13] */ + retry:1, /* [14] */ + txbf_h_info:1, /* [15] */ + seq_num:12, /* [27:16] */ + encrypt_type:4; /* [31:28] */ + volatile uint32_t pn_31_0:32; /* [31:0] */ + volatile + uint32_t pn_47_32:16, /* [15:0] */ + directed:1, /* [16] */ + reserved_2:11, /* [27:17] */ + tid:4; /* [31:28] */ +}; + +struct rx_ppdu_end { + volatile uint32_t evm_p0:32; /* [31:0] */ + volatile uint32_t evm_p1:32; /* [31:0] */ + volatile uint32_t evm_p2:32; /* [31:0] */ + volatile uint32_t evm_p3:32; /* [31:0] */ + volatile uint32_t evm_p4:32; /* [31:0] */ + volatile uint32_t evm_p5:32; /* [31:0] */ + volatile uint32_t evm_p6:32; /* [31:0] */ + volatile uint32_t evm_p7:32; /* [31:0] */ + volatile uint32_t evm_p8:32; /* [31:0] */ + volatile uint32_t evm_p9:32; /* [31:0] */ + volatile uint32_t evm_p10:32; /* [31:0] */ + volatile uint32_t evm_p11:32; /* [31:0] */ + volatile uint32_t evm_p12:32; /* [31:0] */ + volatile uint32_t evm_p13:32; /* [31:0] */ + volatile uint32_t evm_p14:32; /* [31:0] */ + volatile uint32_t evm_p15:32; /* [31:0] */ + volatile uint32_t tsf_timestamp:32; /* [31:0] */ + volatile uint32_t wb_timestamp:32; /* [31:0] */ + volatile + uint32_t locationing_timestamp:8, /* [7:0] */ + phy_err_code:8, /* [15:8] */ + phy_err:1, /* [16] */ + rx_location:1, /* [17] */ + txbf_h_info:1, /* [18] */ + reserved_18:13; /* [31:19] */ + volatile + uint32_t rx_antenna:24, /* [23:0] */ + tx_ht_vht_ack:1, /* [24] */ + bb_captured_channel:1, /* [25] */ + reserved_19:6; /* [31:26] */ + volatile + uint32_t rtt_correction_value:24, /* [23:0] */ + reserved_20:7, /* [30:24] */ + rtt_normal_mode:1; /* [31] */ + volatile + uint32_t bb_length:16, /* [15:0] */ + reserved_21:15, /* [30:16] */ + ppdu_done:1; /* [31] */ +}; +#endif /* defined(HELIUMPLUS) */ + +#endif /*_RX_DESC_H_*/ diff --git a/drivers/staging/qcacld-3.0/core/dp/ol/inc/ol_cfg.h b/drivers/staging/qcacld-3.0/core/dp/ol/inc/ol_cfg.h new file mode 100644 index 0000000000000000000000000000000000000000..34ac3ce17070ac98b9a168ef1ee122f3dfc27f5c --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/dp/ol/inc/ol_cfg.h @@ -0,0 +1,600 @@ +/* + * Copyright (c) 2011-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef _OL_CFG__H_ +#define _OL_CFG__H_ + +#include /* uint32_t */ +#include /* ol_pdev_handle */ +#include /* ieee80211_qosframe_htc_addr4 */ +#include /* LLC_SNAP_HDR_LEN */ +#if defined(CONFIG_HL_SUPPORT) +#include "wlan_tgt_def_config_hl.h" +#else +#include "wlan_tgt_def_config.h" +#endif +#include "ol_txrx_ctrl_api.h" /* txrx_pdev_cfg_param_t */ + + +/** + * @brief format of data frames delivered to/from the WLAN driver by/to the OS + */ +enum wlan_frm_fmt { + wlan_frm_fmt_unknown, + wlan_frm_fmt_raw, + wlan_frm_fmt_native_wifi, + wlan_frm_fmt_802_3, +}; + +/* Throttle period Different level Duty Cycle values*/ +#define THROTTLE_DUTY_CYCLE_LEVEL0 (0) +#define THROTTLE_DUTY_CYCLE_LEVEL1 (50) +#define THROTTLE_DUTY_CYCLE_LEVEL2 (75) +#define THROTTLE_DUTY_CYCLE_LEVEL3 (94) + +struct wlan_ipa_uc_rsc_t { + u8 uc_offload_enabled; + u32 tx_max_buf_cnt; + u32 tx_buf_size; + u32 rx_ind_ring_size; + u32 tx_partition_base; +}; + +/* Config parameters for txrx_pdev */ +struct txrx_pdev_cfg_t { + u8 is_high_latency; + u8 defrag_timeout_check; + u8 rx_pn_check; + u8 pn_rx_fwd_check; + u8 host_addba; + u8 tx_free_at_download; + u8 rx_fwd_inter_bss; + u32 max_thruput_mbps; + u32 target_tx_credit; + u32 vow_config; + u32 tx_download_size; + u32 max_peer_id; + u32 max_vdev; + u32 max_nbuf_frags; + u32 throttle_period_ms; + u8 dutycycle_level[4]; + enum wlan_frm_fmt frame_type; + u8 rx_fwd_disabled; + u8 is_packet_log_enabled; + u8 is_full_reorder_offload; + struct wlan_ipa_uc_rsc_t ipa_uc_rsc; + bool ip_tcp_udp_checksum_offload; + bool enable_rxthread; + bool ce_classify_enabled; +#ifdef QCA_LL_TX_FLOW_CONTROL_V2 + uint32_t tx_flow_stop_queue_th; + uint32_t tx_flow_start_queue_offset; +#endif + bool flow_steering_enabled; + + struct ol_tx_sched_wrr_ac_specs_t ac_specs[TX_WMM_AC_NUM]; +}; + +/** + * @brief Specify whether the system is high-latency or low-latency. + * @details + * Indicate whether the system is operating in high-latency (message + * based, e.g. USB) mode or low-latency (memory-mapped, e.g. PCIe) mode. + * Some chips support just one type of host / target interface. + * Other chips support both LL and HL interfaces (e.g. PCIe and USB), + * so the selection will be made based on which bus HW is present, or + * which is preferred if both are present. + * + * @param pdev - handle to the physical device + * @return 1 -> high-latency -OR- 0 -> low-latency + */ +int ol_cfg_is_high_latency(ol_pdev_handle pdev); + +/** + * @brief Specify the range of peer IDs. + * @details + * Specify the maximum peer ID. This is the maximum number of peers, + * minus one. + * This is used by the host to determine the size of arrays indexed by + * peer ID. + * + * @param pdev - handle to the physical device + * @return maximum peer ID + */ +int ol_cfg_max_peer_id(ol_pdev_handle pdev); + +/** + * @brief Specify the max number of virtual devices within a physical device. + * @details + * Specify how many virtual devices may exist within a physical device. + * + * @param pdev - handle to the physical device + * @return maximum number of virtual devices + */ +int ol_cfg_max_vdevs(ol_pdev_handle pdev); + +/** + * @brief Check whether host-side rx PN check is enabled or disabled. + * @details + * Choose whether to allocate rx PN state information and perform + * rx PN checks (if applicable, based on security type) on the host. + * If the rx PN check is specified to be done on the host, the host SW + * will determine which peers are using a security type (e.g. CCMP) that + * requires a PN check. + * + * @param pdev - handle to the physical device + * @return 1 -> host performs rx PN check -OR- 0 -> no host-side rx PN check + */ +int ol_cfg_rx_pn_check(ol_pdev_handle pdev); + +/** + * @brief Check whether host-side rx forwarding is enabled or disabled. + * @details + * Choose whether to check whether to forward rx frames to tx on the host. + * For LL systems, this rx -> tx host-side forwarding check is typically + * enabled. + * For HL systems, the rx -> tx forwarding check is typically done on the + * target. However, even in HL systems, the host-side rx -> tx forwarding + * will typically be enabled, as a second-tier safety net in case the + * target doesn't have enough memory to store all rx -> tx forwarded frames. + * + * @param pdev - handle to the physical device + * @return 1 -> host does rx->tx forward -OR- 0 -> no host-side rx->tx forward + */ +int ol_cfg_rx_fwd_check(ol_pdev_handle pdev); + +/** + * @brief Check whether rx forwarding is enabled or disabled. + * @details + * Choose whether to forward rx frames to tx (where applicable) within the + * WLAN driver, or to leave all forwarding up to the operating system. + * + * @param pdev - handle to the physical device + * @return 1 -> no rx->tx forward -OR- 0 -> rx->tx forward (in host or target) + */ +int ol_cfg_rx_fwd_disabled(ol_pdev_handle pdev); + +/** + * @brief Check whether to perform inter-BSS or intra-BSS rx->tx forwarding. + * @details + * Check whether data received by an AP on one virtual device destined + * to a STA associated with a different virtual device within the same + * physical device should be forwarded within the driver, or whether + * forwarding should only be done within a virtual device. + * + * @param pdev - handle to the physical device + * @return + * 1 -> forward both within and between vdevs + * -OR- + * 0 -> forward only within a vdev + */ +int ol_cfg_rx_fwd_inter_bss(ol_pdev_handle pdev); + +/** + * @brief Specify data frame format used by the OS. + * @details + * Specify what type of frame (802.3 or native WiFi) the host data SW + * should expect from and provide to the OS shim. + * + * @param pdev - handle to the physical device + * @return enumerated data frame format + */ +enum wlan_frm_fmt ol_cfg_frame_type(ol_pdev_handle pdev); + +/** + * @brief Specify the peak throughput. + * @details + * Specify the peak throughput that a system is expected to support. + * The data SW uses this configuration to help choose the size for its + * tx descriptor pool and rx buffer ring. + * The data SW assumes that the peak throughput applies to either rx or tx, + * rather than having separate specs of the rx max throughput vs. the tx + * max throughput. + * + * @param pdev - handle to the physical device + * @return maximum supported throughput in Mbps (not MBps) + */ +int ol_cfg_max_thruput_mbps(ol_pdev_handle pdev); + +/** + * @brief Specify the maximum number of fragments per tx network buffer. + * @details + * Specify the maximum number of fragments that a tx frame provided to + * the WLAN driver by the OS may contain. + * In LL systems, the host data SW uses this maximum fragment count to + * determine how many elements to allocate in the fragmentation descriptor + * it creates to specify to the tx MAC DMA where to locate the tx frame's + * data. + * This maximum fragments count is only for regular frames, not TSO frames, + * since TSO frames are sent in segments with a limited number of fragments + * per segment. + * + * @param pdev - handle to the physical device + * @return maximum number of fragments that can occur in a regular tx frame + */ +int ol_cfg_netbuf_frags_max(ol_pdev_handle pdev); + +/** + * @brief For HL systems, specify when to free tx frames. + * @details + * In LL systems, the host's tx frame is referenced by the MAC DMA, and + * thus cannot be freed until the target indicates that it is finished + * transmitting the frame. + * In HL systems, the entire tx frame is downloaded to the target. + * Consequently, the target has its own copy of the tx frame, and the + * host can free the tx frame as soon as the download completes. + * Alternatively, the HL host can keep the frame allocated until the + * target explicitly tells the HL host it is done transmitting the frame. + * This gives the target the option of discarding its copy of the tx + * frame, and then later getting a new copy from the host. + * This function tells the host whether it should retain its copy of the + * transmit frames until the target explicitly indicates it is finished + * transmitting them, or if it should free its copy as soon as the + * tx frame is downloaded to the target. + * + * @param pdev - handle to the physical device + * @return + * 0 -> retain the tx frame until the target indicates it is done + * transmitting the frame + * -OR- + * 1 -> free the tx frame as soon as the download completes + */ +int ol_cfg_tx_free_at_download(ol_pdev_handle pdev); +void ol_cfg_set_tx_free_at_download(ol_pdev_handle pdev); + +/** + * @brief Low water mark for target tx credit. + * Tx completion handler is invoked to reap the buffers when the target tx + * credit goes below Low Water Mark. + */ +#define OL_CFG_NUM_MSDU_REAP 512 +#define ol_cfg_tx_credit_lwm(pdev) \ + ((CFG_TGT_NUM_MSDU_DESC > OL_CFG_NUM_MSDU_REAP) ? \ + (CFG_TGT_NUM_MSDU_DESC - OL_CFG_NUM_MSDU_REAP) : 0) + +/** + * @brief In a HL system, specify the target initial credit count. + * @details + * The HL host tx data SW includes a module for determining which tx frames + * to download to the target at a given time. + * To make this judgement, the HL tx download scheduler has to know + * how many buffers the HL target has available to hold tx frames. + * Due to the possibility that a single target buffer pool can be shared + * between rx and tx frames, the host may not be able to obtain a precise + * specification of the tx buffer space available in the target, but it + * uses the best estimate, as provided by this configuration function, + * to determine how best to schedule the tx frame downloads. + * + * @param pdev - handle to the physical device + * @return the number of tx buffers available in a HL target + */ +uint16_t ol_cfg_target_tx_credit(ol_pdev_handle pdev); + +/** + * @brief Specify the LL tx MSDU header download size. + * @details + * In LL systems, determine how many bytes from a tx frame to download, + * in order to provide the target FW's Descriptor Engine with enough of + * the packet's payload to interpret what kind of traffic this is, + * and who it is for. + * This download size specification does not include the 802.3 / 802.11 + * frame encapsulation headers; it starts with the encapsulated IP packet + * (or whatever ethertype is carried within the ethernet-ish frame). + * The LL host data SW will determine how many bytes of the MSDU header to + * download by adding this download size specification to the size of the + * frame header format specified by the ol_cfg_frame_type configuration + * function. + * + * @param pdev - handle to the physical device + * @return the number of bytes beyond the 802.3 or native WiFi header to + * download to the target for tx classification + */ +int ol_cfg_tx_download_size(ol_pdev_handle pdev); + +/** + * brief Specify where defrag timeout and duplicate detection is handled + * @details + * non-aggregate duplicate detection and timing out stale fragments + * requires additional target memory. To reach max client + * configurations (128+), non-aggregate duplicate detection and the + * logic to time out stale fragments is moved to the host. + * + * @param pdev - handle to the physical device + * @return + * 0 -> target is responsible non-aggregate duplicate detection and + * timing out stale fragments. + * + * 1 -> host is responsible non-aggregate duplicate detection and + * timing out stale fragments. + */ +int ol_cfg_rx_host_defrag_timeout_duplicate_check(ol_pdev_handle pdev); + +/** + * brief Query for the period in ms used for throttling for + * thermal mitigation + * @details + * In LL systems, transmit data throttling is used for thermal + * mitigation where data is paused and resumed during the + * throttle period i.e. the throttle period consists of an + * "on" phase when transmit is allowed and an "off" phase when + * transmit is suspended. This function returns the total + * period used for throttling. + * + * @param pdev - handle to the physical device + * @return the total throttle period in ms + */ +int ol_cfg_throttle_period_ms(ol_pdev_handle pdev); + +/** + * brief Query for the duty cycle in percentage used for throttling for + * thermal mitigation + * + * @param pdev - handle to the physical device + * @param level - duty cycle level + * @return the duty cycle level in percentage + */ +int ol_cfg_throttle_duty_cycle_level(ol_pdev_handle pdev, int level); + +/** + * brief Check whether full reorder offload is + * enabled/disable by the host + * @details + * If the host does not support receive reorder (i.e. the + * target performs full receive re-ordering) this will return + * "enabled" + * + * @param pdev - handle to the physical device + * @return 1 - enable, 0 - disable + */ +int ol_cfg_is_full_reorder_offload(ol_pdev_handle pdev); + +int ol_cfg_is_rx_thread_enabled(ol_pdev_handle pdev); + +/** + * ol_cfg_is_ip_tcp_udp_checksum_offload_enabled() - return + * ip_tcp_udp_checksum_offload is enable/disable + * @pdev : handle to the physical device + * + * Return: 1 - enable, 0 - disable + */ +static inline +int ol_cfg_is_ip_tcp_udp_checksum_offload_enabled(ol_pdev_handle pdev) +{ + struct txrx_pdev_cfg_t *cfg = (struct txrx_pdev_cfg_t *)pdev; + return cfg->ip_tcp_udp_checksum_offload; +} + + +#ifdef QCA_LL_TX_FLOW_CONTROL_V2 +int ol_cfg_get_tx_flow_stop_queue_th(ol_pdev_handle pdev); + +int ol_cfg_get_tx_flow_start_queue_offset(ol_pdev_handle pdev); +#endif + +bool ol_cfg_is_ce_classify_enabled(ol_pdev_handle pdev); + +enum wlan_target_fmt_translation_caps { + wlan_frm_tran_cap_raw = 0x01, + wlan_frm_tran_cap_native_wifi = 0x02, + wlan_frm_tran_cap_8023 = 0x04, +}; + +/** + * @brief Specify the maximum header size added by SW tx encapsulation + * @details + * This function returns the maximum size of the new L2 header, not the + * difference between the new and old L2 headers. + * Thus, this function returns the maximum 802.11 header size that the + * tx SW may need to add to tx data frames. + * + * @param pdev - handle to the physical device + */ +static inline int ol_cfg_sw_encap_hdr_max_size(ol_pdev_handle pdev) +{ + /* + * 24 byte basic 802.11 header + * + 6 byte 4th addr + * + 2 byte QoS control + * + 4 byte HT control + * + 8 byte LLC/SNAP + */ + return sizeof(struct ieee80211_qosframe_htc_addr4) + LLC_SNAP_HDR_LEN; +} + +static inline uint8_t ol_cfg_tx_encap(ol_pdev_handle pdev) +{ + /* tx encap done in HW */ + return 0; +} + +static inline int ol_cfg_host_addba(ol_pdev_handle pdev) +{ + /* + * ADDBA negotiation is handled by the target FW for Peregrine + Rome. + */ + return 0; +} + +/** + * @brief If the host SW's ADDBA negotiation fails, should it be retried? + * + * @param pdev - handle to the physical device + */ +static inline int ol_cfg_addba_retry(ol_pdev_handle pdev) +{ + return 0; /* disabled for now */ +} + +/** + * @brief How many frames to hold in a paused vdev's tx queue in LL systems + */ +static inline int ol_tx_cfg_max_tx_queue_depth_ll(ol_pdev_handle pdev) +{ + /* + * Store up to 1500 frames for a paused vdev. + * For example, if the vdev is sending 300 Mbps of traffic, and the + * PHY is capable of 600 Mbps, then it will take 56 ms for the PHY to + * drain both the 700 frames that are queued initially, plus the next + * 700 frames that come in while the PHY is catching up. + * So in this example scenario, the PHY will remain fully utilized + * in a MCC system that has a channel-switching period of 56 ms or less. + * 700 frames calculation was correct when FW drain packet without + * any overhead. Actual situation drain overhead will slowdown drain + * speed. And channel period is less than 56 msec + * Worst scenario, 1500 frames should be stored in host. + */ + return 1500; +} + +/** + * @brief Get packet log config from HTT config + */ +uint8_t ol_cfg_is_packet_log_enabled(ol_pdev_handle pdev); + +#ifdef IPA_OFFLOAD +/** + * @brief IPA micro controller data path offload enable or not + * @detail + * This function returns IPA micro controller data path offload + * feature enabled or not + * + * @param pdev - handle to the physical device + */ +unsigned int ol_cfg_ipa_uc_offload_enabled(ol_pdev_handle pdev); +/** + * @brief IPA micro controller data path TX buffer size + * @detail + * This function returns IPA micro controller data path offload + * TX buffer size which should be pre-allocated by driver. + * Default buffer size is 2K + * + * @param pdev - handle to the physical device + */ +unsigned int ol_cfg_ipa_uc_tx_buf_size(ol_pdev_handle pdev); +/** + * @brief IPA micro controller data path TX buffer size + * @detail + * This function returns IPA micro controller data path offload + * TX buffer count which should be pre-allocated by driver. + * + * @param pdev - handle to the physical device + */ +unsigned int ol_cfg_ipa_uc_tx_max_buf_cnt(ol_pdev_handle pdev); +/** + * @brief IPA micro controller data path TX buffer size + * @detail + * This function returns IPA micro controller data path offload + * RX indication ring size which will notified by WLAN FW to IPA + * micro controller + * + * @param pdev - handle to the physical device + */ +unsigned int ol_cfg_ipa_uc_rx_ind_ring_size(ol_pdev_handle pdev); +/** + * @brief IPA micro controller data path TX buffer size + * @param pdev - handle to the physical device + */ +unsigned int ol_cfg_ipa_uc_tx_partition_base(ol_pdev_handle pdev); +void ol_cfg_set_ipa_uc_tx_partition_base(ol_pdev_handle pdev, uint32_t value); +#else +static inline unsigned int ol_cfg_ipa_uc_offload_enabled( + ol_pdev_handle pdev) +{ + return 0; +} + +static inline unsigned int ol_cfg_ipa_uc_tx_buf_size( + ol_pdev_handle pdev) +{ + return 0; +} + +static inline unsigned int ol_cfg_ipa_uc_tx_max_buf_cnt( + ol_pdev_handle pdev) +{ + return 0; +} + +static inline unsigned int ol_cfg_ipa_uc_rx_ind_ring_size( + ol_pdev_handle pdev) +{ + return 0; +} + +static inline unsigned int ol_cfg_ipa_uc_tx_partition_base( + ol_pdev_handle pdev) +{ + return 0; +} + +static inline void ol_cfg_set_ipa_uc_tx_partition_base( + ol_pdev_handle pdev, uint32_t value) +{ + return; +} +#endif /* IPA_OFFLOAD */ + +/** + * ol_set_cfg_flow_steering - Set Rx flow steering config based on CFG ini + * config. + * + * @pdev - handle to the physical device + * @val - 0 - disable, 1 - enable + * + * Return: None + */ +static inline void ol_set_cfg_flow_steering(ol_pdev_handle pdev, uint8_t val) +{ + struct txrx_pdev_cfg_t *cfg = (struct txrx_pdev_cfg_t *)pdev; + + cfg->flow_steering_enabled = val; +} + +/** + * ol_cfg_is_flow_steering_enabled - Return Rx flow steering config. + * + * @pdev - handle to the physical device + * + * Return: value of configured flow steering value. + */ +static inline uint8_t ol_cfg_is_flow_steering_enabled(ol_pdev_handle pdev) +{ + struct txrx_pdev_cfg_t *cfg = (struct txrx_pdev_cfg_t *)pdev; + + return cfg->flow_steering_enabled; +} + +int ol_cfg_get_wrr_skip_weight(ol_pdev_handle pdev, int ac); + +uint32_t ol_cfg_get_credit_threshold(ol_pdev_handle pdev, int ac); + +uint16_t ol_cfg_get_send_limit(ol_pdev_handle pdev, int ac); + +int ol_cfg_get_credit_reserve(ol_pdev_handle pdev, int ac); + +int ol_cfg_get_discard_weight(ol_pdev_handle pdev, int ac); +#endif /* _OL_CFG__H_ */ diff --git a/drivers/staging/qcacld-3.0/core/dp/ol/inc/ol_ctrl_addba_api.h b/drivers/staging/qcacld-3.0/core/dp/ol/inc/ol_ctrl_addba_api.h new file mode 100644 index 0000000000000000000000000000000000000000..31854e61086dc80c5258997d7c41c8b0886b30a8 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/dp/ol/inc/ol_ctrl_addba_api.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2013-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef _OL_CTRL_ADDBA_API_H_ +#define _OL_CTRL_ADDBA_API_H_ +#define ol_ctrl_addba_attach(a, b, c, d, e) 0 +#define ol_ctrl_addba_detach(a) 0 +#define ol_ctrl_addba_init(a, b, c, d, e) 0 +#define ol_ctrl_addba_cleanup(a) 0 +#define ol_ctrl_addba_request_setup(a, b, c, d, e, f) 0 +#define ol_ctrl_addba_response_setup(a, b, c, d, e, f) 0 +#define ol_ctrl_addba_request_process(a, b, c, d, e) 0 +#define ol_ctrl_addba_response_process(a, b, c, d) 0 +#define ol_ctrl_addba_clear(a) 0 +#define ol_ctrl_delba_process(a, b, c) 0 +#define ol_ctrl_addba_get_status(a, b) 0 +#define ol_ctrl_addba_set_response(a, b, c) 0 +#define ol_ctrl_addba_clear_response(a) 0 +#endif diff --git a/drivers/staging/qcacld-3.0/core/dp/ol/inc/ol_defines.h b/drivers/staging/qcacld-3.0/core/dp/ol/inc/ol_defines.h new file mode 100644 index 0000000000000000000000000000000000000000..8b83adb85f9140c02a9790d4fd621d3ddb78b184 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/dp/ol/inc/ol_defines.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2013-2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * Offload specific Opaque Data types. + */ +#ifndef _DEV_OL_DEFINES_H +#define _DEV_OL_DEFINES_H + +/** + * @brief Opaque handle of wmi structure + */ +struct wmi_unified; +typedef struct wmi_unified *wmi_unified_t; + +typedef void *ol_scn_t; +/** + * @wmi_event_handler function prototype + */ +typedef int (*wmi_unified_event_handler)(ol_scn_t scn_handle, + uint8_t *event_buf, uint32_t len); + +#endif /* _DEV_OL_DEFINES_H */ diff --git a/drivers/staging/qcacld-3.0/core/dp/ol/inc/ol_htt_api.h b/drivers/staging/qcacld-3.0/core/dp/ol/inc/ol_htt_api.h new file mode 100644 index 0000000000000000000000000000000000000000..7adbf244206c6993479c2a53c9ed521ad86b79b9 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/dp/ol/inc/ol_htt_api.h @@ -0,0 +1,423 @@ +/* + * Copyright (c) 2011, 2014-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * @file ol_htt_api.h + * @brief Specify the general HTT API functions called by the host data SW. + * @details + * This file declares the HTT API functions that are not specific to + * either tx nor rx. + */ +#ifndef _OL_HTT_API__H_ +#define _OL_HTT_API__H_ + +#include /* qdf_device_t */ +#include /* qdf_nbuf_t */ +#include /* A_STATUS */ +#include /* HTC_HANDLE */ +#include "htt.h" /* htt_dbg_stats_type, etc. */ +#include /* ol_pdev_handle */ + +/* TID */ +#define OL_HTT_TID_NON_QOS_UNICAST 16 +#define OL_HTT_TID_NON_QOS_MCAST_BCAST 18 + +struct htt_pdev_t; +typedef struct htt_pdev_t *htt_pdev_handle; + +htt_pdev_handle +htt_pdev_alloc(ol_txrx_pdev_handle txrx_pdev, + ol_pdev_handle ctrl_pdev, + HTC_HANDLE htc_pdev, qdf_device_t osdev); + +/** + * @brief Allocate and initialize a HTT instance. + * @details + * This function allocates and initializes an HTT instance. + * This involves allocating a pool of HTT tx descriptors in + * consistent memory, allocating and filling a rx ring (LL only), + * and connecting the HTC's HTT_DATA_MSG service. + * The HTC service connect call will block, so this function + * needs to be called in passive context. + * Because HTC setup has not been completed at the time this function + * is called, this function cannot send any HTC messages to the target. + * Messages to configure the target are instead sent in the + * htc_attach_target function. + * + * @param pdev - data SW's physical device handle + * (used as context pointer during HTT -> txrx calls) + * @param desc_pool_size - number of HTT descriptors to (pre)allocate + * @return success -> HTT pdev handle; failure -> NULL + */ +int +htt_attach(struct htt_pdev_t *pdev, int desc_pool_size); + +/** + * @brief Send HTT configuration messages to the target. + * @details + * For LL only, this function sends a rx ring configuration message to the + * target. For HL, this function is a no-op. + * + * @param htt_pdev - handle to the HTT instance being initialized + */ +A_STATUS htt_attach_target(htt_pdev_handle htt_pdev); + +/** + * enum htt_op_mode - Virtual device operation mode + * + * @htt_op_mode_unknown: Unknown mode + * @htt_op_mode_ap: AP mode + * @htt_op_mode_ibss: IBSS mode + * @htt_op_mode_sta: STA (client) mode + * @htt_op_mode_monitor: Monitor mode + * @htt_op_mode_ocb: OCB mode + */ +enum htt_op_mode { + htt_op_mode_unknown, + htt_op_mode_ap, + htt_op_mode_ibss, + htt_op_mode_sta, + htt_op_mode_monitor, + htt_op_mode_ocb, +}; + +/* no-ops */ +#define htt_vdev_attach(htt_pdev, vdev_id, op_mode) +#define htt_vdev_detach(htt_pdev, vdev_id) +#define htt_peer_qos_update(htt_pdev, peer_id, qos_capable) +#define htt_peer_uapsdmask_update(htt_pdev, peer_id, uapsd_mask) + +void htt_pdev_free(htt_pdev_handle pdev); + +/** + * @brief Deallocate a HTT instance. + * + * @param htt_pdev - handle to the HTT instance being torn down + */ +void htt_detach(htt_pdev_handle htt_pdev); + +/** + * @brief Stop the communication between HTT and target + * @details + * For ISOC solution, this function stop the communication between HTT and + * target. + * For Peregrine/Rome, it's already stopped by ol_ath_disconnect_htc + * before ol_txrx_pdev_detach called in ol_ath_detach. So this function is + * a no-op. + * Peregrine/Rome HTT layer is on top of HTC while ISOC solution HTT layer is + * on top of DXE layer. + * + * @param htt_pdev - handle to the HTT instance being initialized + */ +void htt_detach_target(htt_pdev_handle htt_pdev); + +/* + * @brief Tell the target side of HTT to suspend H2T processing until synced + * @param htt_pdev - the host HTT object + * @param sync_cnt - what sync count value the target HTT FW should wait for + * before resuming H2T processing + */ +A_STATUS htt_h2t_sync_msg(htt_pdev_handle htt_pdev, uint8_t sync_cnt); + +int +htt_h2t_aggr_cfg_msg(htt_pdev_handle htt_pdev, + int max_subfrms_ampdu, int max_subfrms_amsdu); + +/** + * @brief Get the FW status + * @details + * Trigger FW HTT to retrieve FW status. + * A separate HTT message will come back with the statistics we want. + * + * @param pdev - handle to the HTT instance + * @param stats_type_upload_mask - bitmask identifying which stats to upload + * @param stats_type_reset_mask - bitmask identifying which stats to reset + * @param cookie - unique value to distinguish and identify stats requests + * @return 0 - succeed to send the request to FW; otherwise, failed to do so. + */ +int +htt_h2t_dbg_stats_get(struct htt_pdev_t *pdev, + uint32_t stats_type_upload_mask, + uint32_t stats_type_reset_mask, + uint8_t cfg_stats_type, + uint32_t cfg_val, uint64_t cookie); + +/** + * @brief Get the fields from HTT T2H stats upload message's stats info header + * @details + * Parse the a HTT T2H message's stats info tag-length-value header, + * to obtain the stats type, status, data lenght, and data address. + * + * @param stats_info_list - address of stats record's header + * @param[out] type - which type of FW stats are contained in the record + * @param[out] status - whether the stats are (fully) present in the record + * @param[out] length - how large the data portion of the stats record is + * @param[out] stats_data - where the data portion of the stats record is + */ +void +htt_t2h_dbg_stats_hdr_parse(uint8_t *stats_info_list, + enum htt_dbg_stats_type *type, + enum htt_dbg_stats_status *status, + int *length, uint8_t **stats_data); + +/** + * @brief Display a stats record from the HTT T2H STATS_CONF message. + * @details + * Parse the stats type and status, and invoke a type-specified printout + * to display the stats values. + * + * @param stats_data - buffer holding the stats record from the STATS_CONF msg + * @param concise - whether to do a verbose or concise printout + */ +void htt_t2h_stats_print(uint8_t *stats_data, int concise); + +#ifndef HTT_DEBUG_LEVEL +#if defined(DEBUG) +#define HTT_DEBUG_LEVEL 10 +#else +#define HTT_DEBUG_LEVEL 0 +#endif +#endif + +#if HTT_DEBUG_LEVEL > 5 +void htt_display(htt_pdev_handle pdev, int indent); +#else +#define htt_display(pdev, indent) +#endif + +#define HTT_DXE_RX_LOG 0 +#define htt_rx_reorder_log_print(pdev) + +#ifdef IPA_OFFLOAD +int htt_h2t_ipa_uc_rsc_cfg_msg(struct htt_pdev_t *pdev); + +int +htt_ipa_uc_get_resource(htt_pdev_handle pdev, + qdf_dma_addr_t *ce_sr_base_paddr, + uint32_t *ce_sr_ring_size, + qdf_dma_addr_t *ce_reg_paddr, + qdf_dma_addr_t *tx_comp_ring_base_paddr, + uint32_t *tx_comp_ring_size, + uint32_t *tx_num_alloc_buffer, + qdf_dma_addr_t *rx_rdy_ring_base_paddr, + uint32_t *rx_rdy_ring_size, + qdf_dma_addr_t *rx_proc_done_idx_paddr, + void **rx_proc_done_idx_vaddr, + qdf_dma_addr_t *rx2_rdy_ring_base_paddr, + uint32_t *rx2_rdy_ring_size, + qdf_dma_addr_t *rx2_proc_done_idx_paddr, + void **rx2_proc_done_idx_vaddr); + +int +htt_ipa_uc_set_doorbell_paddr(htt_pdev_handle pdev, + qdf_dma_addr_t ipa_uc_tx_doorbell_paddr, + qdf_dma_addr_t ipa_uc_rx_doorbell_paddr); + +int +htt_h2t_ipa_uc_set_active(struct htt_pdev_t *pdev, bool uc_active, bool is_tx); + +int htt_h2t_ipa_uc_get_stats(struct htt_pdev_t *pdev); + +int htt_h2t_ipa_uc_get_share_stats(struct htt_pdev_t *pdev, + uint8_t reset_stats); + +int htt_h2t_ipa_uc_set_quota(struct htt_pdev_t *pdev, uint64_t quota_bytes); + +int htt_ipa_uc_attach(struct htt_pdev_t *pdev); + +void htt_ipa_uc_detach(struct htt_pdev_t *pdev); +#else +/** + * htt_h2t_ipa_uc_rsc_cfg_msg() - Send WDI IPA config message to firmware + * @pdev: handle to the HTT instance + * + * Return: 0 success + */ +static inline int htt_h2t_ipa_uc_rsc_cfg_msg(struct htt_pdev_t *pdev) +{ + return 0; +} + +/** + * htt_ipa_uc_get_resource() - Get uc resource from htt and lower layer + * @pdev: handle to the HTT instance + * @ce_sr_base_paddr: copy engine source ring base physical address + * @ce_sr_ring_size: copy engine source ring size + * @ce_reg_paddr: copy engine register physical address + * @tx_comp_ring_base_paddr: tx comp ring base physical address + * @tx_comp_ring_size: tx comp ring size + * @tx_num_alloc_buffer: number of allocated tx buffer + * @rx_rdy_ring_base_paddr: rx ready ring base physical address + * @rx_rdy_ring_size: rx ready ring size + * @rx_proc_done_idx_paddr: rx process done index physical address + * @rx_proc_done_idx_vaddr: rx process done index virtual address + * @rx2_rdy_ring_base_paddr: rx done ring base physical address + * @rx2_rdy_ring_size: rx done ring size + * @rx2_proc_done_idx_paddr: rx done index physical address + * @rx2_proc_done_idx_vaddr: rx done index virtual address + * + * Return: 0 success + */ +static inline int +htt_ipa_uc_get_resource(htt_pdev_handle pdev, + qdf_dma_addr_t *ce_sr_base_paddr, + uint32_t *ce_sr_ring_size, + qdf_dma_addr_t *ce_reg_paddr, + qdf_dma_addr_t *tx_comp_ring_base_paddr, + uint32_t *tx_comp_ring_size, + uint32_t *tx_num_alloc_buffer, + qdf_dma_addr_t *rx_rdy_ring_base_paddr, + uint32_t *rx_rdy_ring_size, + qdf_dma_addr_t *rx_proc_done_idx_paddr, + void **rx_proc_done_idx_vaddr, + qdf_dma_addr_t *rx2_rdy_ring_base_paddr, + uint32_t *rx2_rdy_ring_size, + qdf_dma_addr_t *rx2_proc_done_idx_paddr, + void **rx2_proc_done_idx_vaddr) +{ + return 0; +} + +/** + * htt_ipa_uc_set_doorbell_paddr() - Propagate IPA doorbell address + * @pdev: handle to the HTT instance + * @ipa_uc_tx_doorbell_paddr: TX doorbell base physical address + * @ipa_uc_rx_doorbell_paddr: RX doorbell base physical address + * + * Return: 0 success + */ +static inline int +htt_ipa_uc_set_doorbell_paddr(htt_pdev_handle pdev, + uint32_t ipa_uc_tx_doorbell_paddr, + uint32_t ipa_uc_rx_doorbell_paddr) +{ + return 0; +} + +/** + * htt_h2t_ipa_uc_set_active() - Propagate WDI path enable/disable to firmware + * @pdev: handle to the HTT instance + * @uc_active: WDI UC path enable or not + * @is_tx: TX path or RX path + * + * Return: 0 success + */ +static inline int +htt_h2t_ipa_uc_set_active(struct htt_pdev_t *pdev, bool uc_active, + bool is_tx) +{ + return 0; +} + +/** + * htt_h2t_ipa_uc_get_stats() - WDI UC state query request to firmware + * @pdev: handle to the HTT instance + * + * Return: 0 success + */ +static inline int htt_h2t_ipa_uc_get_stats(struct htt_pdev_t *pdev) +{ + return 0; +} + +/** + * htt_h2t_ipa_uc_get_share_stats() - WDI UC wifi sharing state request to FW + * @pdev: handle to the HTT instance + * + * Return: 0 success + */ +static inline int htt_h2t_ipa_uc_get_share_stats(struct htt_pdev_t *pdev, + uint8_t reset_stats) +{ + return 0; +} + +/** + * htt_h2t_ipa_uc_set_quota() - WDI UC set quota request to firmware + * @pdev: handle to the HTT instance + * + * Return: 0 success + */ +static inline int htt_h2t_ipa_uc_set_quota(struct htt_pdev_t *pdev, + uint64_t quota_bytes) +{ + return 0; +} + +/** + * htt_ipa_uc_attach() - Allocate UC data path resources + * @pdev: handle to the HTT instance + * + * Return: 0 success + */ +static inline int htt_ipa_uc_attach(struct htt_pdev_t *pdev) +{ + return 0; +} + +/** + * htt_ipa_uc_attach() - Remove UC data path resources + * @pdev: handle to the HTT instance + * + * Return: 0 success + */ +static inline void htt_ipa_uc_detach(struct htt_pdev_t *pdev) +{ + return; +} +#endif /* IPA_OFFLOAD */ + +void htt_rx_mon_note_capture_channel(htt_pdev_handle pdev, int mon_ch); + +void ol_htt_mon_note_chan(ol_txrx_pdev_handle pdev, int mon_ch); + +#if defined(DEBUG_HL_LOGGING) && defined(CONFIG_HL_SUPPORT) + +void htt_dump_bundle_stats(struct htt_pdev_t *pdev); +void htt_clear_bundle_stats(struct htt_pdev_t *pdev); +#else + +static inline void htt_dump_bundle_stats(struct htt_pdev_t *pdev) +{ + return; +} + +static inline void htt_clear_bundle_stats(struct htt_pdev_t *pdev) +{ + return; +} +#endif + +void htt_mark_first_wakeup_packet(htt_pdev_handle pdev, uint8_t value); +typedef void (*tp_rx_pkt_dump_cb)(qdf_nbuf_t msdu, uint8_t peer_id, + uint8_t status); +void htt_register_rx_pkt_dump_callback(struct htt_pdev_t *pdev, + tp_rx_pkt_dump_cb ol_rx_pkt_dump_call); +void htt_deregister_rx_pkt_dump_callback(struct htt_pdev_t *pdev); +void ol_rx_pkt_dump_call(qdf_nbuf_t msdu, uint8_t peer_id, uint8_t status); + +#endif /* _OL_HTT_API__H_ */ diff --git a/drivers/staging/qcacld-3.0/core/dp/ol/inc/ol_htt_rx_api.h b/drivers/staging/qcacld-3.0/core/dp/ol/inc/ol_htt_rx_api.h new file mode 100644 index 0000000000000000000000000000000000000000..746f25e41f5994b11dafa67b3c709cbfc8e16ddc --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/dp/ol/inc/ol_htt_rx_api.h @@ -0,0 +1,891 @@ +/* + * Copyright (c) 2011-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * @file ol_htt_rx_api.h + * @brief Specify the rx HTT API functions called by the host data SW. + * @details + * This file declares the HTT API functions that are specifically + * related to receive processing. + * In particular, this file specifies methods of the abstract HTT rx + * descriptor, and functions to iterate though a series of rx descriptors + * and rx MSDU buffers. + */ +#ifndef _OL_HTT_RX_API__H_ +#define _OL_HTT_RX_API__H_ + +/* #include / * uint16_t, etc. * / */ +#include /* uint16_t, etc. */ +#include /* qdf_nbuf_t */ +#include /* bool */ + +#include /* HTT_RX_IND_MPDU_STATUS */ +#include /* htt_pdev_handle */ + +#include /* ieee80211_rx_status */ +#include + +/*================ constants and types used in the rx API ===================*/ + +#define HTT_RSSI_INVALID 0x7fff + +/** + * struct ocb_rx_stats_hdr_t - RX stats header + * @version: The version must be 1. + * @length: The length of this structure + * @channel_freq: The center frequency for the packet + * @rssi_cmb: combined RSSI from all chains + * @rssi[4]: rssi for chains 0 through 3 (for 20 MHz bandwidth) + * @tsf32: timestamp in TSF units + * @timestamp_microsec: timestamp in microseconds + * @datarate: MCS index + * @timestamp_submicrosec: submicrosecond portion of the timestamp + * @ext_tid: Extended TID + * @reserved: Ensure the size of the structure is a multiple of 4. + * Must be 0. + * + * When receiving an OCB packet, the RX stats is sent to the user application + * so that the user application can do processing based on the RX stats. + * This structure will be preceded by an ethernet header with + * the proto field set to 0x8152. This struct includes various RX + * paramaters including RSSI, data rate, and center frequency. + */ +PREPACK struct ocb_rx_stats_hdr_t { + uint16_t version; + uint16_t length; + uint16_t channel_freq; + int16_t rssi_cmb; + int16_t rssi[4]; + uint32_t tsf32; + uint32_t timestamp_microsec; + uint8_t datarate; + uint8_t timestamp_submicrosec; + uint8_t ext_tid; + uint8_t reserved; +}; + +/*================ rx indication message field access methods ===============*/ + +/** + * @brief Check if a rx indication message has a rx reorder flush command. + * @details + * Space is reserved in each rx indication message for a rx reorder flush + * command, to release specified MPDUs from the rx reorder holding array + * before processing the new MPDUs referenced by the rx indication message. + * This rx reorder flush command contains a flag to show whether the command + * is valid within a given rx indication message. + * This function checks the validity flag from the rx indication + * flush command IE within the rx indication message. + * + * @param pdev - the HTT instance the rx data was received on + * @param rx_ind_msg - the netbuf containing the rx indication message + * @return + * 1 - the message's rx flush command is valid and should be processed + * before processing new rx MPDUs, + * -OR- + * 0 - the message's rx flush command is invalid and should be ignored + */ +int htt_rx_ind_flush(htt_pdev_handle pdev, qdf_nbuf_t rx_ind_msg); + +/** + * @brief Return the sequence number starting the range of MPDUs to flush. + * @details + * Read the fields of the rx indication message that identify the start + * and end of the range of MPDUs to flush from the rx reorder holding array + * and send on to subsequent stages of rx processing. + * These sequence numbers are the 6 LSBs of the 12-bit 802.11 sequence + * number. These sequence numbers are masked with the block ack window size, + * rounded up to a power of two (minus one, to create a bitmask) to obtain + * the corresponding index into the rx reorder holding array. + * The series of MPDUs to flush includes the one specified by the start + * sequence number. + * The series of MPDUs to flush excludes the one specified by the end + * sequence number; the MPDUs up to but not including the end sequence number + * are to be flushed. + * These start and end seq num fields are only valid if the "flush valid" + * flag is set. + * + * @param pdev - the HTT instance the rx data was received on + * @param rx_ind_msg - the netbuf containing the rx indication message + * @param seq_num_start - (call-by-reference output) sequence number + * for the start of the range of MPDUs to flush + * @param seq_num_end - (call-by-reference output) sequence number + * for the end of the range of MPDUs to flush + */ +void +htt_rx_ind_flush_seq_num_range(htt_pdev_handle pdev, + qdf_nbuf_t rx_ind_msg, + unsigned *seq_num_start, unsigned *seq_num_end); + +/** + * @brief Check if a rx indication message has a rx reorder release command. + * @details + * Space is reserved in each rx indication message for a rx reorder release + * command, to release specified MPDUs from the rx reorder holding array + * after processing the new MPDUs referenced by the rx indication message. + * This rx reorder release command contains a flag to show whether the command + * is valid within a given rx indication message. + * This function checks the validity flag from the rx indication + * release command IE within the rx indication message. + * + * @param pdev - the HTT instance the rx data was received on + * @param rx_ind_msg - the netbuf containing the rx indication message + * @return + * 1 - the message's rx release command is valid and should be processed + * after processing new rx MPDUs, + * -OR- + * 0 - the message's rx release command is invalid and should be ignored + */ +int htt_rx_ind_release(htt_pdev_handle pdev, qdf_nbuf_t rx_ind_msg); + +/** + * @brief Return the sequence number starting the range of MPDUs to release. + * @details + * Read the fields of the rx indication message that identify the start + * and end of the range of MPDUs to release from the rx reorder holding + * array and send on to subsequent stages of rx processing. + * These sequence numbers are the 6 LSBs of the 12-bit 802.11 sequence + * number. These sequence numbers are masked with the block ack window size, + * rounded up to a power of two (minus one, to create a bitmask) to obtain + * the corresponding index into the rx reorder holding array. + * The series of MPDUs to release includes the one specified by the start + * sequence number. + * The series of MPDUs to release excludes the one specified by the end + * sequence number; the MPDUs up to but not including the end sequence number + * are to be released. + * These start and end seq num fields are only valid if the "release valid" + * flag is set. + * + * @param pdev - the HTT instance the rx data was received on + * @param rx_ind_msg - the netbuf containing the rx indication message + * @param seq_num_start - (call-by-reference output) sequence number + * for the start of the range of MPDUs to release + * @param seq_num_end - (call-by-reference output) sequence number + * for the end of the range of MPDUs to release + */ +void +htt_rx_ind_release_seq_num_range(htt_pdev_handle pdev, + qdf_nbuf_t rx_ind_msg, + unsigned *seq_num_start, + unsigned *seq_num_end); + +/* + * For now, the host HTT -> host data rx status enum + * exactly matches the target HTT -> host HTT rx status enum; + * no translation is required. + * However, the host data SW should only use the htt_rx_status, + * so that in the future a translation from target HTT rx status + * to host HTT rx status can be added, if the need ever arises. + */ +enum htt_rx_status { + htt_rx_status_unknown = HTT_RX_IND_MPDU_STATUS_UNKNOWN, + htt_rx_status_ok = HTT_RX_IND_MPDU_STATUS_OK, + htt_rx_status_err_fcs = HTT_RX_IND_MPDU_STATUS_ERR_FCS, + htt_rx_status_err_dup = HTT_RX_IND_MPDU_STATUS_ERR_DUP, + htt_rx_status_err_replay = HTT_RX_IND_MPDU_STATUS_ERR_REPLAY, + htt_rx_status_err_inv_peer = HTT_RX_IND_MPDU_STATUS_ERR_INV_PEER, + htt_rx_status_ctrl_mgmt_null = HTT_RX_IND_MPDU_STATUS_MGMT_CTRL, + htt_rx_status_tkip_mic_err = HTT_RX_IND_MPDU_STATUS_TKIP_MIC_ERR, + + htt_rx_status_err_misc = HTT_RX_IND_MPDU_STATUS_ERR_MISC +}; + +/** + * @brief Check the status MPDU range referenced by a rx indication message. + * @details + * Check the status of a range of MPDUs referenced by a rx indication message. + * This status determines whether the MPDUs should be processed or discarded. + * If the status is OK, then the MPDUs within the range should be processed + * as usual. + * Otherwise (FCS error, duplicate error, replay error, unknown sender error, + * etc.) the MPDUs within the range should be discarded. + * + * @param pdev - the HTT instance the rx data was received on + * @param rx_ind_msg - the netbuf containing the rx indication message + * @param mpdu_range_num - which MPDU range within the rx ind msg to check, + * starting from 0 + * @param status - (call-by-reference output) MPDU status + * @param mpdu_count - (call-by-reference output) count of MPDUs comprising + * the specified MPDU range + */ +void +htt_rx_ind_mpdu_range_info(htt_pdev_handle pdev, + qdf_nbuf_t rx_ind_msg, + int mpdu_range_num, + enum htt_rx_status *status, int *mpdu_count); + +/** + * @brief Return the RSSI provided in a rx indication message. + * @details + * Return the RSSI from an rx indication message, converted to dBm units. + * + * @param pdev - the HTT instance the rx data was received on + * @param rx_ind_msg - the netbuf containing the rx indication message + * @return RSSI in dBm, or HTT_INVALID_RSSI + */ +int16_t +htt_rx_ind_rssi_dbm(htt_pdev_handle pdev, qdf_nbuf_t rx_ind_msg); + +int16_t +htt_rx_ind_rssi_dbm_chain(htt_pdev_handle pdev, qdf_nbuf_t rx_ind_msg, + int8_t chain); + +void +htt_rx_ind_legacy_rate(htt_pdev_handle pdev, qdf_nbuf_t rx_ind_msg, + uint8_t *legacy_rate, uint8_t *legacy_rate_sel); + + +void +htt_rx_ind_timestamp(htt_pdev_handle pdev, qdf_nbuf_t rx_ind_msg, + uint32_t *timestamp_microsec, + uint8_t *timestamp_submicrosec); + +uint32_t +htt_rx_ind_tsf32(htt_pdev_handle pdev, qdf_nbuf_t rx_ind_msg); + +uint8_t +htt_rx_ind_ext_tid(htt_pdev_handle pdev, qdf_nbuf_t rx_ind_msg); + + +/*==================== rx MPDU descriptor access methods ====================*/ + +/** + * @brief Check if the retry bit is set in Rx-descriptor + * @details + * This function returns the retry bit of the 802.11 header for the + * provided rx MPDU descriptor. + * + * @param pdev - the handle of the physical device the rx data was received on + * @param msdu_desc - the abstract descriptor for the MSDU in question + * @return boolean -- true if retry is set, false otherwise + */ +extern +bool (*htt_rx_mpdu_desc_retry)( + htt_pdev_handle pdev, void *mpdu_desc); + +/** + * @brief Return a rx MPDU's sequence number. + * @details + * This function returns the LSBs of the 802.11 sequence number for the + * provided rx MPDU descriptor. + * Depending on the system, 6-12 LSBs from the 802.11 sequence number are + * returned. (Typically, either the 8 or 12 LSBs are returned.) + * This sequence number is masked with the block ack window size, + * rounded up to a power of two (minus one, to create a bitmask) to obtain + * the corresponding index into the rx reorder holding array. + * + * @param pdev - the HTT instance the rx data was received on + * @param mpdu_desc - the abstract descriptor for the MPDU in question + * @return the LSBs of the sequence number for the MPDU + */ +extern uint16_t +(*htt_rx_mpdu_desc_seq_num)(htt_pdev_handle pdev, void *mpdu_desc); + +/** + * @brief Return a rx MPDU's rx reorder array index, based on sequence number. + * @details + * This function returns a sequence-number based index into the rx + * reorder array for the specified MPDU. + * In some systems, this rx reorder array is simply the LSBs of the + * sequence number, or possibly even the full sequence number. + * To support such systems, the returned index has to be masked with + * the power-of-two array size before using the value to index the + * rx reorder array. + * In other systems, this rx reorder array index is + * (sequence number) % (block ack window size) + * + * @param pdev - the HTT instance the rx data was received on + * @param mpdu_desc - the abstract descriptor for the MPDU in question + * @return the rx reorder array index the MPDU goes into + */ +/* use sequence number (or LSBs thereof) as rx reorder array index */ +#define htt_rx_mpdu_desc_reorder_idx htt_rx_mpdu_desc_seq_num + +union htt_rx_pn_t { + /* WEP: 24-bit PN */ + uint32_t pn24; + + /* TKIP or CCMP: 48-bit PN */ + uint64_t pn48; + + /* WAPI: 128-bit PN */ + uint64_t pn128[2]; +}; + +/** + * @brief Find the packet number (PN) for a MPDU. + * @details + * This function only applies when the rx PN check is configured to be + * performed in the host rather than the target, and on peers using a + * security type for which a PN check applies. + * The pn_len_bits argument is used to determine which element of the + * htt_rx_pn_t union to deposit the PN value read from the MPDU descriptor + * into. + * A 24-bit PN is deposited into pn->pn24. + * A 48-bit PN is deposited into pn->pn48. + * A 128-bit PN is deposited in little-endian order into pn->pn128. + * Specifically, bits 63:0 of the PN are copied into pn->pn128[0], while + * bits 127:64 of the PN are copied into pn->pn128[1]. + * + * @param pdev - the HTT instance the rx data was received on + * @param mpdu_desc - the abstract descriptor for the MPDU in question + * @param pn - the location to copy the packet number into + * @param pn_len_bits - the PN size, in bits + */ +extern void (*htt_rx_mpdu_desc_pn)(htt_pdev_handle pdev, + void *mpdu_desc, + union htt_rx_pn_t *pn, int pn_len_bits); + +/** + * @brief This function Returns the TID value from the Rx descriptor + * for Low Latency driver + * @details + * This function returns the TID set in the 802.11 QoS Control for the MPDU + * in the packet header, by looking at the mpdu_start of the Rx descriptor. + * Rx descriptor gets a copy of the TID from the MAC. + * @pdev: Handle (pointer) to HTT pdev. + * @param mpdu_desc - the abstract descriptor for the MPDU in question + * @return: Actual TID set in the packet header. + */ +extern +uint8_t (*htt_rx_mpdu_desc_tid)( + htt_pdev_handle pdev, void *mpdu_desc); + +/** + * @brief Return the TSF timestamp indicating when a MPDU was received. + * @details + * This function provides the timestamp indicating when the PPDU that + * the specified MPDU belongs to was received. + * + * @param pdev - the HTT instance the rx data was received on + * @param mpdu_desc - the abstract descriptor for the MPDU in question + * @return 32 LSBs of TSF time at which the MPDU's PPDU was received + */ +uint32_t htt_rx_mpdu_desc_tsf32(htt_pdev_handle pdev, void *mpdu_desc); + +/** + * @brief Return the 802.11 header of the MPDU + * @details + * This function provides a pointer to the start of the 802.11 header + * of the Rx MPDU + * + * @param pdev - the HTT instance the rx data was received on + * @param mpdu_desc - the abstract descriptor for the MPDU in question + * @return pointer to 802.11 header of the received MPDU + */ +char *htt_rx_mpdu_wifi_hdr_retrieve(htt_pdev_handle pdev, void *mpdu_desc); + +/** + * @brief Return the RSSI provided in a rx descriptor. + * @details + * Return the RSSI from a rx descriptor, converted to dBm units. + * + * @param pdev - the HTT instance the rx data was received on + * @param mpdu_desc - the abstract descriptor for the MPDU in question + * @return RSSI in dBm, or HTT_INVALID_RSSI + */ +int16_t htt_rx_mpdu_desc_rssi_dbm(htt_pdev_handle pdev, void *mpdu_desc); + +/*==================== rx MSDU descriptor access methods ====================*/ + +/** + * @brief Check if a MSDU completes a MPDU. + * @details + * When A-MSDU aggregation is used, a single MPDU will consist of + * multiple MSDUs. This function checks a MSDU's rx descriptor to + * see whether the MSDU is the final MSDU within a MPDU. + * + * @param pdev - the handle of the physical device the rx data was received on + * @param msdu_desc - the abstract descriptor for the MSDU in question + * @return + * 0 - there are subsequent MSDUs within the A-MSDU / MPDU + * -OR- + * 1 - this is the last MSDU within its MPDU + */ +extern bool (*htt_rx_msdu_desc_completes_mpdu)(htt_pdev_handle pdev, + void *msdu_desc); + +/** + * @brief Check if a MSDU is first msdu of MPDU. + * @details + * When A-MSDU aggregation is used, a single MPDU will consist of + * multiple MSDUs. This function checks a MSDU's rx descriptor to + * see whether the MSDU is the first MSDU within a MPDU. + * + * @param pdev - the handle of the physical device the rx data was received on + * @param msdu_desc - the abstract descriptor for the MSDU in question + * @return + * 0 - this is interior MSDU in the A-MSDU / MPDU + * -OR- + * 1 - this is the first MSDU within its MPDU + */ +extern bool (*htt_rx_msdu_first_msdu_flag)(htt_pdev_handle pdev, + void *msdu_desc); + +/** + * @brief Retrieve encrypt bit from a mpdu desc. + * @details + * Fw will pass all the frame to the host whether encrypted or not, and will + * indicate the encrypt flag in the desc, this function is to get the info + * and used to make a judge whether should make pn check, because + * non-encrypted frames always get the same pn number 0. + * + * @param pdev - the HTT instance the rx data was received on + * @param mpdu_desc - the abstract descriptor for the MPDU in question + * @return 0 - the frame was not encrypted + * 1 - the frame was encrypted + */ +extern bool (*htt_rx_mpdu_is_encrypted)(htt_pdev_handle pdev, void *mpdu_desc); + +/** + * @brief Indicate whether a rx desc has a WLAN unicast vs. mcast/bcast flag. + * @details + * A flag indicating whether a MPDU was delivered over WLAN as unicast or + * multicast/broadcast may be only valid once per MPDU (LL), or within each + * rx descriptor for the MSDUs within the MPDU (HL). (In practice, it is + * unlikely that A-MSDU aggregation will be used in HL, so typically HL will + * only have one MSDU per MPDU anyway.) + * This function indicates whether the specified rx descriptor contains + * a WLAN ucast vs. mcast/bcast flag. + * + * @param pdev - the HTT instance the rx data was received on + * @param msdu_desc - the abstract descriptor for the MSDU in question + * @return + * 0 - The rx descriptor does not contain a WLAN ucast vs. mcast flag. + * -OR- + * 1 - The rx descriptor has a valid WLAN ucast vs. mcast flag. + */ +extern int (*htt_rx_msdu_has_wlan_mcast_flag)(htt_pdev_handle pdev, + void *msdu_desc); + +/** + * @brief Indicate whether a MSDU was received as unicast or mcast/bcast + * @details + * Indicate whether the MPDU that the specified MSDU belonged to was + * delivered over the WLAN as unicast, or as multicast/broadcast. + * This query can only be performed on rx descriptors for which + * htt_rx_msdu_has_wlan_mcast_flag is true. + * + * @param pdev - the HTT instance the rx data was received on + * @param msdu_desc - the abstract descriptor for the MSDU in question + * @return + * 0 - The MSDU was delivered over the WLAN as unicast. + * -OR- + * 1 - The MSDU was delivered over the WLAN as broadcast or multicast. + */ +extern bool (*htt_rx_msdu_is_wlan_mcast)(htt_pdev_handle pdev, void *msdu_desc); + +/** + * @brief Indicate whether a MSDU was received as a fragmented frame + * @details + * This query can only be performed on LL system. + * + * @param pdev - the HTT instance the rx data was received on + * @param msdu_desc - the abstract descriptor for the MSDU in question + * @return + * 0 - The MSDU was a non-fragmented frame. + * -OR- + * 1 - The MSDU was fragmented frame. + */ +extern int (*htt_rx_msdu_is_frag)(htt_pdev_handle pdev, void *msdu_desc); + +/** + * @brief Indicate if a MSDU should be delivered to the OS shim or discarded. + * @details + * Indicate whether a MSDU should be discarded or delivered to the OS shim. + * + * @param pdev - the HTT instance the rx data was received on + * @param msdu_desc - the abstract descriptor for the MSDU in question + * @return + * 0 - The MSDU should be delivered to the OS + * -OR- + * non-zero - The MSDU should not be delivered to the OS. + * If the "forward" flag is set, it should be forwarded to tx. + * Else, it should be discarded. + */ +int htt_rx_msdu_discard(htt_pdev_handle pdev, void *msdu_desc); + +/** + * @brief Indicate whether a MSDU should be forwarded to tx. + * @details + * Indicate whether a MSDU should be forwarded to tx, e.g. for intra-BSS + * STA-to-STA forwarding in an AP, or for multicast echo in an AP. + * + * @param pdev - the HTT instance the rx data was received on + * @param msdu_desc - the abstract descriptor for the MSDU in question + * @return + * 0 - The MSDU should not be forwarded + * -OR- + * non-zero - The MSDU should be forwarded. + * If the "discard" flag is set, then the original MSDU can be + * directly forwarded into the tx path. + * Else, a copy (clone?) of the rx MSDU needs to be created to + * send to the tx path. + */ +int htt_rx_msdu_forward(htt_pdev_handle pdev, void *msdu_desc); + +/** + * @brief Indicate whether a MSDU's contents need to be inspected. + * @details + * Indicate whether the host data SW needs to examine the contents of the + * received MSDU, and based on the packet type infer what special handling + * to provide for the MSDU. + * + * @param pdev - the HTT instance the rx data was received on + * @param msdu_desc - the abstract descriptor for the MSDU in question + * @return + * 0 - No inspection + special handling is required. + * -OR- + * non-zero - Inspect the MSDU contents to infer what special handling + * to apply to the MSDU. + */ +int htt_rx_msdu_inspect(htt_pdev_handle pdev, void *msdu_desc); + +/** + * @brief Provide all action specifications for a rx MSDU + * @details + * Provide all action specifications together. This provides the same + * information in a single function call as would be provided by calling + * the functions htt_rx_msdu_discard, htt_rx_msdu_forward, and + * htt_rx_msdu_inspect. + * + * @param pdev - the HTT instance the rx data was received on + * @param msdu_desc - the abstract descriptor for the MSDU in question + * @param[out] discard - 1: discard the MSDU, 0: deliver the MSDU to the OS + * @param[out] forward - 1: forward the rx MSDU to tx, 0: no rx->tx forward + * @param[out] inspect - 1: process according to MSDU contents, 0: no inspect + */ +void +htt_rx_msdu_actions(htt_pdev_handle pdev, + void *msdu_desc, int *discard, int *forward, int *inspect); + +/** + * @brief Get the key id sent in IV of the frame + * @details + * Provide the key index octet which is taken from IV. + * This is valid only for the first MSDU. + * + * @param pdev - the HTT instance the rx data was received on + * @param msdu_desc - the abstract descriptor for the MSDU in question + * @key_id - Key id octet + * @return indication of whether key id access is successful + * true - Success + * false - if this is not first msdu + */ +extern bool +(*htt_rx_msdu_desc_key_id)(htt_pdev_handle pdev, + void *mpdu_desc, uint8_t *key_id); + +extern bool +(*htt_rx_msdu_chan_info_present)( + htt_pdev_handle pdev, + void *mpdu_desc); + +extern bool +(*htt_rx_msdu_center_freq)( + htt_pdev_handle pdev, + struct ol_txrx_peer_t *peer, + void *mpdu_desc, + uint16_t *primary_chan_center_freq_mhz, + uint16_t *contig_chan1_center_freq_mhz, + uint16_t *contig_chan2_center_freq_mhz, + uint8_t *phy_mode); + +/*====================== rx MSDU + descriptor delivery ======================*/ + +/** + * @brief Return a linked-list of network buffer holding the next rx A-MSDU. + * @details + * In some systems, the rx MSDUs are uploaded along with the rx + * indication message, while in other systems the rx MSDUs are uploaded + * out of band, via MAC DMA. + * This function provides an abstract way to obtain a linked-list of the + * next MSDUs, regardless of whether the MSDU was delivered in-band with + * the rx indication message, or out of band through MAC DMA. + * In a LL system, this function returns a linked list of the one or more + * MSDUs that together comprise an A-MSDU. + * In a HL system, this function returns a degenerate linked list consisting + * of a single MSDU (head_msdu == tail_msdu). + * This function also makes sure each MSDU's rx descriptor can be found + * through the MSDU's network buffer. + * In most systems, this is trivial - a single network buffer stores both + * the MSDU rx descriptor and the MSDU payload. + * In systems where the rx descriptor is in a separate buffer from the + * network buffer holding the MSDU payload, a pointer to the rx descriptor + * has to be stored in the network buffer. + * After this function call, the descriptor for a given MSDU can be + * obtained via the htt_rx_msdu_desc_retrieve function. + * + * @param pdev - the HTT instance the rx data was received on + * @param rx_ind_msg - the netbuf containing the rx indication message + * @param head_msdu - call-by-reference network buffer handle, which gets set + * in this function to point to the head MSDU of the A-MSDU + * @param tail_msdu - call-by-reference network buffer handle, which gets set + * in this function to point to the tail MSDU of the A-MSDU, or the + * same MSDU that the head_msdu points to if only a single MSDU is + * delivered at a time. + * @return indication of whether any MSDUs in the AMSDU use chaining: + * 0 - no buffer chaining + * 1 - buffers are chained + */ +extern int +(*htt_rx_amsdu_pop)(htt_pdev_handle pdev, + qdf_nbuf_t rx_ind_msg, + qdf_nbuf_t *head_msdu, qdf_nbuf_t *tail_msdu, + uint32_t *msdu_count); + +extern int +(*htt_rx_frag_pop)(htt_pdev_handle pdev, + qdf_nbuf_t rx_ind_msg, + qdf_nbuf_t *head_msdu, qdf_nbuf_t *tail_msdu, + uint32_t *msdu_count); + +/** + * @brief Return a linked list of buffers holding one MSDU + * In some systems the buffers are delivered along with offload delivery + * indication message itself, while in other systems the buffers are uploaded + * out of band, via MAC DMA. + * @details + * This function provides an abstract way to obtain a linked-list of the + * buffers corresponding to an msdu, regardless of whether the MSDU was + * delivered in-band with the rx indication message, or out of band through + * MAC DMA. + * In a LL system, this function returns a linked list of one or more + * buffers corresponding to an MSDU + * In a HL system , TODO + * + * @param pdev - the HTT instance the rx data was received on + * @param offload_deliver_msg - the nebuf containing the offload deliver message + * @param head_msdu - call-by-reference network buffer handle, which gets set in this + * function to the head buffer of this MSDU + * @param tail_msdu - call-by-reference network buffer handle, which gets set in this + * function to the tail buffer of this MSDU + */ +extern int +(*htt_rx_offload_msdu_pop)(htt_pdev_handle pdev, + qdf_nbuf_t offload_deliver_msg, + int *vdev_id, + int *peer_id, + int *tid, + uint8_t *fw_desc, + qdf_nbuf_t *head_buf, qdf_nbuf_t *tail_buf); + +/** + * @brief Return the rx descriptor for the next rx MPDU. + * @details + * The rx MSDU descriptors may be uploaded as part of the rx indication + * message, or delivered separately out of band. + * This function provides an abstract way to obtain the next MPDU descriptor, + * regardless of whether the MPDU descriptors are delivered in-band with + * the rx indication message, or out of band. + * This is used to iterate through the series of MPDU descriptors referenced + * by a rx indication message. + * The htt_rx_amsdu_pop function should be called before this function + * (or at least before using the returned rx descriptor handle), so that + * the cache location for the rx descriptor will be flushed before the + * rx descriptor gets used. + * + * @param pdev - the HTT instance the rx data was received on + * @param rx_ind_msg - the netbuf containing the rx indication message + * @return next abstract rx descriptor from the series of MPDUs referenced + * by an rx ind msg + */ +extern void * +(*htt_rx_mpdu_desc_list_next)(htt_pdev_handle pdev, qdf_nbuf_t rx_ind_msg); + +/** + * @brief Retrieve a previously-stored rx descriptor from a MSDU buffer. + * @details + * The data SW will call the htt_rx_msdu_desc_link macro/function to + * link a MSDU's rx descriptor with the buffer holding the MSDU payload. + * This function retrieves the rx MSDU descriptor. + * + * @param pdev - the HTT instance the rx data was received on + * @param msdu - the buffer containing the MSDU payload + * @return the corresponding abstract rx MSDU descriptor + */ +extern void * +(*htt_rx_msdu_desc_retrieve)(htt_pdev_handle pdev, qdf_nbuf_t msdu); + +/** + * @brief Free both an rx MSDU descriptor and the associated MSDU buffer. + * @details + * Usually the WLAN driver does not free rx MSDU buffers, but needs to + * do so when an invalid frame (e.g. FCS error) was deposited into the + * queue of rx buffers. + * This function frees both the rx descriptor and the rx frame. + * On some systems, the rx descriptor and rx frame are stored in the + * same buffer, and thus one free suffices for both objects. + * On other systems, the rx descriptor and rx frame are stored + * separately, so distinct frees are internally needed. + * However, in either case, the rx descriptor has been associated with + * the MSDU buffer, and can be retrieved by htt_rx_msdu_desc_retrieve. + * Hence, it is only necessary to provide the MSDU buffer; the HTT SW + * internally finds the corresponding MSDU rx descriptor. + * + * @param htt_pdev - the HTT instance the rx data was received on + * @param rx_msdu_desc - rx descriptor for the MSDU being freed + * @param msdu - rx frame buffer for the MSDU being freed + */ +void htt_rx_desc_frame_free(htt_pdev_handle htt_pdev, qdf_nbuf_t msdu); + +/** + * @brief Look up and free the rx descriptor for a MSDU. + * @details + * When the driver delivers rx frames to the OS, it first needs + * to free the associated rx descriptors. + * In some systems the rx descriptors are allocated in the same + * buffer as the rx frames, so this operation is a no-op. + * In other systems, the rx descriptors are stored separately + * from the rx frames, so the rx descriptor has to be freed. + * The descriptor is located from the MSDU buffer with the + * htt_rx_desc_frame_free macro/function. + * + * @param htt_pdev - the HTT instance the rx data was received on + * @param msdu - rx frame buffer for the rx MSDU descriptor being freed + */ +void htt_rx_msdu_desc_free(htt_pdev_handle htt_pdev, qdf_nbuf_t msdu); + +/** + * @brief Add new MSDU buffers for the target to fill. + * @details + * In some systems, the underlying upload mechanism (HIF) allocates new rx + * buffers itself. In other systems, the underlying upload mechanism + * (MAC DMA) needs to be provided with new rx buffers. + * This function is used as an abstract method to indicate to the underlying + * data upload mechanism when it is an appropriate time to allocate new rx + * buffers. + * If the allocation is automatically handled, a la HIF, then this function + * call is ignored. + * If the allocation has to be done explicitly, a la MAC DMA, then this + * function provides the context and timing for such replenishment + * allocations. + * + * @param pdev - the HTT instance the rx data will be received on + */ +void htt_rx_msdu_buff_replenish(htt_pdev_handle pdev); + +#ifndef CONFIG_HL_SUPPORT +/** + * @brief Add new MSDU buffers for the target to fill. + * @details + * This is full_reorder_offload version of the replenish function. + * In full_reorder, FW sends HTT_T2H_MSG_TYPE_RX_IN_ORD_PADDR_IND + * msg to host. It includes the number of MSDUs. Thgis will be fed + * into htt_rx_msdu_buff_in_order_replenish function. + * The reason for creating yet another function is to avoid checks + * in real-time. + * + * @param pdev - the HTT instance the rx data will be received on + * @num - number of buffers to replenish + * + * Return: number of buffers actually replenished + */ +int htt_rx_msdu_buff_in_order_replenish(htt_pdev_handle pdev, uint32_t num); +#endif + +/** + * @brief Links list of MSDUs into an single MPDU. Updates RX stats + * @details + * When HW MSDU splitting is turned on each MSDU in an AMSDU MPDU occupies + * a separate wbuf for delivery to the network stack. For delivery to the + * monitor mode interface they need to be restitched into an MPDU. This + * function does this. Also updates the RX status if the MPDU starts + * a new PPDU + * + * @param pdev - the HTT instance the rx data was received on + * @param head_msdu - network buffer handle, which points to the first MSDU + * in the list. This is a NULL terminated list + * @param rx_staus - pointer to the status associated with this MPDU. + * Updated only if there is a new PPDU and new status associated with it + * @param clone_not_reqd - If set the MPDU linking destroys the passed in + * list, else operates on a cloned nbuf + * @return network buffer handle to the MPDU + */ +qdf_nbuf_t +htt_rx_restitch_mpdu_from_msdus(htt_pdev_handle pdev, + qdf_nbuf_t head_msdu, + struct ieee80211_rx_status *rx_status, + unsigned clone_not_reqd); + +/** + * @brief Return the sequence number of MPDUs to flush. + * @param pdev - the HTT instance the rx data was received on + * @param rx_frag_ind_msg - the netbuf containing the rx fragment indication message + * @param seq_num_start - (call-by-reference output) sequence number + * for the start of the range of MPDUs to flush + * @param seq_num_end - (call-by-reference output) sequence number + * for the end of the range of MPDUs to flush + */ +void +htt_rx_frag_ind_flush_seq_num_range(htt_pdev_handle pdev, + qdf_nbuf_t rx_frag_ind_msg, + int *seq_num_start, int *seq_num_end); + +/** + * htt_rx_msdu_rx_desc_size_hl() - Return the HL rx desc size + * @pdev: the HTT instance the rx data was received on. + * @msdu_desc: the hl rx desc pointer + * + * Return: HL rx desc size + */ +uint16_t htt_rx_msdu_rx_desc_size_hl(htt_pdev_handle pdev, void *msdu_desc); + +/** + * @brief populates vowext stats by processing RX desc. + * @param msdu - network buffer handle + * @param vowstats - handle to vow ext stats. + */ +void htt_rx_get_vowext_stats(qdf_nbuf_t msdu, struct vow_extstats *vowstats); + +#ifndef CONFIG_HL_SUPPORT +/** + * @brief parses the offload message passed by the target. + * @param pdev - pdev handle + * @param paddr - physical address of the rx buffer + * @param vdev_id - reference to vdev id to be filled + * @param peer_id - reference to the peer id to be filled + * @param tid - reference to the tid to be filled + * @param fw_desc - reference to the fw descriptor to be filled + * @param peer_id - reference to the peer id to be filled + * @param head_buf - reference to the head buffer + * @param tail_buf - reference to the tail buffer + */ +int +htt_rx_offload_paddr_msdu_pop_ll(htt_pdev_handle pdev, + uint32_t *msg_word, + int msdu_iter, + int *vdev_id, + int *peer_id, + int *tid, + uint8_t *fw_desc, + qdf_nbuf_t *head_buf, qdf_nbuf_t *tail_buf); +#endif + +uint32_t htt_rx_amsdu_rx_in_order_get_pktlog(qdf_nbuf_t rx_ind_msg); + +#endif /* _OL_HTT_RX_API__H_ */ diff --git a/drivers/staging/qcacld-3.0/core/dp/ol/inc/ol_htt_tx_api.h b/drivers/staging/qcacld-3.0/core/dp/ol/inc/ol_htt_tx_api.h new file mode 100644 index 0000000000000000000000000000000000000000..ccd17db45d6e482ab20a04f9625ddfb1ccf34ba6 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/dp/ol/inc/ol_htt_tx_api.h @@ -0,0 +1,848 @@ +/* + * Copyright (c) 2011-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * @file ol_htt_tx_api.h + * @brief Specify the tx HTT API functions called by the host data SW. + * @details + * This file declares the HTT API functions that are specifically + * related to transmit processing. + * In particular, the methods of the abstract HTT tx descriptor are + * specified. + */ +#ifndef _OL_HTT_TX_API__H_ +#define _OL_HTT_TX_API__H_ + +/* #include / * uint16_t, etc. * / */ +#include /* uint16_t, etc. */ +#include /* qdf_nbuf_t */ +#include /* wlan_frm_fmt */ + +#include /* needed by inline functions */ +#include +#include /* htt_pdev_handle */ +#include +#include +#include + +#define HTT_INVALID_CHANNEL -1 + +/* Remove these macros when they get added to htt.h. */ +#ifndef HTT_TX_DESC_EXTENSION_GET +#define HTT_TX_DESC_EXTENSION_OFFSET_BYTES 0 +#define HTT_TX_DESC_EXTENSION_OFFSET_DWORD 0 +#define HTT_TX_DESC_EXTENSION_M 0x10000000 +#define HTT_TX_DESC_EXTENSION_S 28 + +#define HTT_TX_DESC_EXTENSION_GET(_var) \ + (((_var) & HTT_TX_DESC_EXTENSION_M) >> HTT_TX_DESC_EXTENSION_S) +#define HTT_TX_DESC_EXTENSION_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_TX_DESC_EXTENSION, _val); \ + ((_var) |= ((_val) << HTT_TX_DESC_EXTENSION_S)); \ + } while (0) +#endif + +/*================ meta-info about tx MSDUs =================================*/ + +/* + * For simplicity, use the IEEE 802.11 frame type values. + */ +enum htt_frm_type { + htt_frm_type_mgmt = 0, + htt_frm_type_ctrl = 1, + htt_frm_type_data = 2 +}; + +/* + * For simplicity, use the IEEE 802.11 frame sub-type values. + */ +enum htt_frm_subtype { + htt_frm_subtype_mgmt_assoc_req = 0, + htt_frm_subtype_mgmt_assoc_resp = 1, + htt_frm_subtype_mgmt_reassoc_req = 2, + htt_frm_subtype_mgmt_reassoc_resp = 3, + htt_frm_subtype_mgmt_probe_req = 4, + htt_frm_subtype_mgmt_probe_resp = 5, + htt_frm_subtype_mgmt_timing_adv = 6, + htt_frm_subtype_mgmt_beacon = 8, + htt_frm_subtype_mgmt_atim = 9, + htt_frm_subtype_mgmt_disassoc = 10, + htt_frm_subtype_mgmt_auth = 11, + htt_frm_subtype_mgmt_deauth = 12, + htt_frm_subtype_mgmt_action = 13, + htt_frm_subtype_mgmt_action_no_ack = 14, + + htt_frm_subtype_data_data = 0, + htt_frm_subtype_data_data_cf_ack = 1, + htt_frm_subtype_data_data_cf_poll = 2, + htt_frm_subtype_data_data_cf_ack_cf_poll = 3, + htt_frm_subtype_data_null = 4, + htt_frm_subtype_data_cf_ack = 5, + htt_frm_subtype_data_cf_poll = 6, + htt_frm_subtype_data_cf_ack_cf_poll = 7, + htt_frm_subtype_data_QoS_data = 8, + htt_frm_subtype_data_QoS_data_cf_ack = 9, + htt_frm_subtype_data_QoS_data_cf_poll = 10, + htt_frm_subtype_data_QoS_data_cf_ack_cf_poll = 11, + htt_frm_subtype_data_QoS_null = 12, + htt_frm_subtype_data_QoS_cf_poll = 14, + htt_frm_subtype_data_QoS_cf_ack_cf_poll = 15, +}; + +enum htt_ofdm_datarate { /* Value MBPS Modulation Coding*/ + htt_ofdm_datarate_6_mbps = 0, /* 0 6 BPSK 1/2 */ + htt_ofdm_datarate_9_mbps = 1, /* 1 9 BPSK 3/4 */ + htt_ofdm_datarate_12_mbps = 2, /* 2 12 QPSK 1/2 */ + htt_ofdm_datarate_18_mbps = 3, /* 3 18 QPSK 3/4 */ + htt_ofdm_datarate_24_mbps = 4, /* 4 24 16-QAM 1/2 */ + htt_ofdm_datarate_36_mbps = 5, /* 5 36 16-QAM 3/4 */ + htt_ofdm_datarate_48_mbps = 6, /* 6 48 64-QAM 1/2 */ + htt_ofdm_datarate_54_mbps = 7, /* 7 54 64-QAM 3/4 */ + htt_ofdm_datarate_max = 7, +}; + +/** + * struct ocb_tx_ctrl_hdr_t - TX control header + * @version: must be 1 + * @length: length of this structure + * @channel_freq: channel on which to transmit the packet + * @valid_pwr: bit 0: if set, tx pwr spec is valid + * @valid_datarate: bit 1: if set, tx MCS mask spec is valid + * @valid_retries: bit 2: if set, tx retries spec is valid + * @valid_chain_mask: bit 3: if set, chain mask is valid + * @valid_expire_tsf: bit 4: if set, tx expire TSF spec is valid + * @valid_tid: bit 5: if set, TID is valid + * @reserved0_15_6: bits 15:6 - unused, set to 0x0 + * @all_flags: union of all the flags + * @expire_tsf_lo: TX expiry time (TSF) LSBs + * @expire_tsf_hi: TX expiry time (TSF) MSBs + * @pwr: Specify what power the tx frame needs to be transmitted + * at. The power a signed (two's complement) value is in + * units of 0.5 dBm. The value needs to be appropriately + * sign-extended when extracting the value from the message + * and storing it in a variable that is larger than A_INT8. + * If the transmission uses multiple tx chains, this power + * spec is the total transmit power, assuming incoherent + * combination of per-chain power to produce the total + * power. + * @datarate: The desired modulation and coding scheme. + * VALUE DATA RATE MODULATION CODING RATE + * @ 20 MHz + * (MBPS) + * 0 6 BPSK 1/2 + * 1 9 BPSK 3/4 + * 2 12 QPSK 1/2 + * 3 18 QPSK 3/4 + * 4 24 16-QAM 1/2 + * 5 36 16-QAM 3/4 + * 6 48 64-QAM 1/2 + * 7 54 64-QAM 3/4 + * @retry_limit: Specify the maximum number of transmissions, including + * the initial transmission, to attempt before giving up if + * no ack is received. + * If the tx rate is specified, then all retries shall use + * the same rate as the initial transmission. + * If no tx rate is specified, the target can choose + * whether to retain the original rate during the + * retransmissions, or to fall back to a more robust rate. + * @chain_mask: specify which chains to transmit from + * @ext_tid: Extended Traffic ID (0-15) + * @reserved: Ensure that the size of the structure is a multiple of + * 4. Must be 0. + * + * When sending an OCB packet, the user application has + * the option of including the following struct following an ethernet header + * with the proto field set to 0x8151. This struct includes various TX + * paramaters including the TX power and MCS. + */ +PREPACK struct ocb_tx_ctrl_hdr_t { + uint16_t version; + uint16_t length; + uint16_t channel_freq; + + union { + struct { + uint16_t + valid_pwr:1, + valid_datarate:1, + valid_retries:1, + valid_chain_mask:1, + valid_expire_tsf:1, + valid_tid:1, + reserved0_15_6:10; + }; + uint16_t all_flags; + }; + + uint32_t expire_tsf_lo; + uint32_t expire_tsf_hi; + int8_t pwr; + uint8_t datarate; + uint8_t retry_limit; + uint8_t chain_mask; + uint8_t ext_tid; + uint8_t reserved[3]; +} POSTPACK; + +/** + * @brief tx MSDU meta-data that HTT may use to program the FW/HW tx descriptor + */ +struct htt_msdu_info_t { + /* the info sub-struct specifies the characteristics of the MSDU */ + struct { + uint16_t ethertype; +#define HTT_INVALID_PEER_ID 0xffff + uint16_t peer_id; + uint8_t vdev_id; + uint8_t ext_tid; + /* + * l2_hdr_type - L2 format (802.3, native WiFi 802.11, + * or raw 802.11) + * Based on attach-time configuration, the tx frames provided + * by the OS to the tx data SW are expected to be either + * 802.3 format or the "native WiFi" variant of 802.11 format. + * Internally, the driver may also inject tx frames into the tx + * datapath, and these frames may be either 802.3 format or + * 802.11 "raw" format, with no further 802.11 encapsulation + * needed. + * The tx frames are tagged with their frame format, so target + * FW/HW will know how to interpret the packet's encapsulation + * headers when doing tx classification, and what form of 802.11 + * header encapsulation is needed, if any. + */ + uint8_t l2_hdr_type; /* enum htt_pkt_type */ + /* + * frame_type - is the tx frame management or data? + * Just to avoid confusion, the enum values for this frame type + * field use the 802.11 frame type values, although it is + * unexpected for control frames to be sent through the host + * data path. + */ + uint8_t frame_type; /* enum htt_frm_type */ + /* + * frame subtype - this field specifies the sub-type of + * management frames + * Just to avoid confusion, the enum values for this frame + * subtype field use the 802.11 management frame subtype values. + */ + uint8_t frame_subtype; /* enum htt_frm_subtype */ + uint8_t is_unicast; + + /* dest_addr is not currently used. + * It could be used as an input to a Tx BD (Riva tx descriptor) + * signature computation. + uint8_t *dest_addr; + */ + + uint8_t l3_hdr_offset; /* wrt qdf_nbuf_data(msdu), in bytes */ + + /* l4_hdr_offset is not currently used. + * It could be used to specify to a TCP/UDP checksum computation + * engine where the TCP/UDP header starts. + */ + /* uint8_t l4_hdr_offset; - wrt qdf_nbuf_data(msdu), in bytes */ + } info; + /* the action sub-struct specifies how to process the MSDU */ + struct { + uint8_t use_6mbps; /* mgmt frames: option to force + 6 Mbps rate */ + uint8_t do_encrypt; + uint8_t do_tx_complete; + uint8_t tx_comp_req; + + /* + * cksum_offload - Specify whether checksum offload is + * enabled or not + * Target FW uses this flag to turn on HW checksumming + * 0x0 - No checksum offload + * 0x1 - L3 header checksum only + * 0x2 - L4 checksum only + * 0x3 - L3 header checksum + L4 checksum + */ + qdf_nbuf_tx_cksum_t cksum_offload; + } action; +}; + +static inline void htt_msdu_info_dump(struct htt_msdu_info_t *msdu_info) +{ + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_LOW, + "HTT MSDU info object (%p)\n", msdu_info); + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_LOW, + " ethertype: %#x\n", msdu_info->info.ethertype); + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_LOW, + " peer_id: %d\n", msdu_info->info.peer_id); + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_LOW, + " vdev_id: %d\n", msdu_info->info.vdev_id); + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_LOW, + " ext_tid: %d\n", msdu_info->info.ext_tid); + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_LOW, + " l2_hdr_type: %d\n", msdu_info->info.l2_hdr_type); + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_LOW, + " frame_type: %d\n", msdu_info->info.frame_type); + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_LOW, + " frame_subtype: %d\n", msdu_info->info.frame_subtype); + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_LOW, + " is_unicast: %u\n", msdu_info->info.is_unicast); + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_LOW, + " l3_hdr_offset: %u\n", msdu_info->info.l3_hdr_offset); + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_LOW, + " use 6 Mbps: %d\n", msdu_info->action.use_6mbps); + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_LOW, + " do_encrypt: %d\n", msdu_info->action.do_encrypt); + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_LOW, + " do_tx_complete: %d\n", msdu_info->action.do_tx_complete); + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_LOW, + " is_unicast: %u\n", msdu_info->info.is_unicast); + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_LOW, + " is_unicast: %u\n", msdu_info->info.is_unicast); +} + +/*================ tx completion message field access methods ===============*/ + +/** + * @brief Look up the descriptor ID of the nth MSDU from a tx completion msg. + * @details + * A tx completion message tells the host that the target is done + * transmitting a series of MSDUs. The message uses a descriptor ID + * to identify each such MSDU. This function/macro is used to + * find the ID of one such MSDU referenced by the tx completion message. + * + * @param iterator - tx completion message context provided by HTT to the + * tx completion message handler. This abstract reference to the + * HTT tx completion message's payload allows the data SW's tx + * completion handler to not care about the format of the HTT + * tx completion message. + * @param num - (zero-based) index to specify a single MSDU within the + * series of MSDUs referenced by the tx completion message + * @return descriptor ID for the specified MSDU + */ +uint16_t htt_tx_compl_desc_id(void *iterator, int num); + +/*========================= tx descriptor operations ========================*/ + +/** + * @brief Allocate a HTT abstract tx descriptor. + * @details + * Allocate a HTT abstract tx descriptor from a pool within "consistent" + * memory, which is accessible by HIF and/or MAC DMA as well as by the + * host CPU. + * It is expected that the tx datapath will allocate HTT tx descriptors + * and link them with datapath SW tx descriptors up front as the driver + * is loaded. Thereafter, the link from datapath SW tx descriptor to + * HTT tx descriptor will be maintained until the driver is unloaded. + * + * @param htt_pdev - handle to the HTT instance making the allocation + * @param[OUT] paddr_lo - physical address of the HTT descriptor + * @return success -> descriptor handle, -OR- failure -> NULL + */ +void *htt_tx_desc_alloc(htt_pdev_handle pdev, qdf_dma_addr_t *paddr, + uint16_t index); + +/** + * @brief Free a HTT abstract tx descriptor. + * + * @param htt_pdev - handle to the HTT instance that made the allocation + * @param htt_tx_desc - the descriptor to free + */ +void htt_tx_desc_free(htt_pdev_handle htt_pdev, void *htt_tx_desc); + +#if defined(HELIUMPLUS) +/** + * @brief Allocate TX frag descriptor + * @details + * Allocate TX frag descriptor + * + * @param pdev - handle to the HTT instance that made the allocation + * @param index - tx descriptor index + * @param frag_paddr_lo - fragment descriptor physical address lower 32bits + * @param frag_ptr - fragment descriptor hlos pointe + * @return success 0 + */ +int htt_tx_frag_alloc(htt_pdev_handle pdev, + u_int16_t index, qdf_dma_addr_t *frag_paddr, void **frag_ptr); +#else +static inline int htt_tx_frag_alloc(htt_pdev_handle pdev, + u_int16_t index, qdf_dma_addr_t *frag_paddr, void **frag_ptr) +{ + *frag_ptr = NULL; + return 0; +} +#endif /* defined(HELIUMPLUS) */ + +#if defined(CONFIG_HL_SUPPORT) + +/** + * @brief Discard all tx frames in the process of being downloaded. + * @details + * This function dicards any tx frames queued in HTT or the layers + * under HTT. + * The download completion callback is invoked on these frames. + * + * @param htt_pdev - handle to the HTT instance + * @param[OUT] frag_paddr_lo - physical address of the fragment descriptor + * (MSDU Link Extension Descriptor) + */ +static inline void htt_tx_pending_discard(htt_pdev_handle pdev) +{ + return; +} +#else + +void htt_tx_pending_discard(htt_pdev_handle pdev); +#endif + +/** + * @brief Download a MSDU descriptor and (a portion of) the MSDU payload. + * @details + * This function is used within LL systems to download a tx descriptor and + * the initial portion of the tx MSDU payload, and within HL systems to + * download the tx descriptor and the entire tx MSDU payload. + * The HTT layer determines internally how much of the tx descriptor + * actually needs to be downloaded. In particular, the HTT layer does not + * download the fragmentation descriptor, and only for the LL case downloads + * the physical address of the fragmentation descriptor. + * In HL systems, the tx descriptor and the entire frame are downloaded. + * In LL systems, only the tx descriptor and the header of the frame are + * downloaded. To determine how much of the tx frame to download, this + * function assumes the tx frame is the default frame type, as specified + * by ol_cfg_frame_type. "Raw" frames need to be transmitted through the + * alternate htt_tx_send_nonstd function. + * The tx descriptor has already been attached to the qdf_nbuf object during + * a preceding call to htt_tx_desc_init. + * + * @param htt_pdev - the handle of the physical device sending the tx data + * @param msdu - the frame being transmitted + * @param msdu_id - unique ID for the frame being transmitted + * @return 0 -> success, -OR- 1 -> failure + */ +int +htt_tx_send_std(htt_pdev_handle htt_pdev, qdf_nbuf_t msdu, uint16_t msdu_id); + +/** + * @brief Download a Batch Of Tx MSDUs + * @details + * Each MSDU already has the MSDU ID stored in the headroom of the + * netbuf data buffer, and has the HTT tx descriptor already attached + * as a prefix fragment to the netbuf. + * + * @param htt_pdev - the handle of the physical device sending the tx data + * @param head_msdu - the MSDU Head for Tx batch being transmitted + * @param num_msdus - The total Number of MSDU's provided for batch tx + * @return null-terminated linked-list of unaccepted frames + */ +qdf_nbuf_t +htt_tx_send_batch(htt_pdev_handle htt_pdev, + qdf_nbuf_t head_msdu, int num_msdus); + +/* The htt scheduler for queued packets in htt + * htt when unable to send to HTC because of lack of resource + * forms a nbuf queue which is flushed when tx completion event from + * target is recieved + */ + +void htt_tx_sched(htt_pdev_handle pdev); + +/** + * @brief Same as htt_tx_send_std, but can handle raw frames. + */ +int +htt_tx_send_nonstd(htt_pdev_handle htt_pdev, + qdf_nbuf_t msdu, + uint16_t msdu_id, enum htt_pkt_type pkt_type); + +/** + * htt_pkt_dl_len_get() Gets the HTT PKT download length. + * @pdev: pointer to struct htt_pdev_t + * + * Return: size of HTT packet download length. + */ +int +htt_pkt_dl_len_get(struct htt_pdev_t *pdev); + +#define HTT_TX_CLASSIFY_BIT_S 4 /* Used to set + * classify bit in HTT desc.*/ + +/** + * enum htt_ce_tx_pkt_type - enum of packet types to be set in CE + * descriptor + * @tx_pkt_type_raw: Value set for RAW frames + * @tx_pkt_type_native_wifi: Value set for NATIVE WIFI frames + * @tx_pkt_type_eth2: Value set for Ethernet II frames (mostly default) + * @tx_pkt_type_802_3: Value set for 802.3 / original ethernet frames + * @tx_pkt_type_mgmt: Value set for MGMT frames over HTT + * + */ +enum htt_ce_tx_pkt_type { + tx_pkt_type_raw = 0, + tx_pkt_type_native_wifi = 1, + tx_pkt_type_eth2 = 2, + tx_pkt_type_802_3 = 3, + tx_pkt_type_mgmt = 4 +}; + +/** + * enum extension_header_type - extension header type + * @EXT_HEADER_NOT_PRESENT: extension header not present + * @OCB_MODE_EXT_HEADER: Extension header for OCB mode + * @WISA_MODE_EXT_HEADER_6MBPS: WISA mode 6Mbps header + * @WISA_MODE_EXT_HEADER_24MBPS: WISA mode 24Mbps header + */ +enum extension_header_type { + EXT_HEADER_NOT_PRESENT, + OCB_MODE_EXT_HEADER, + WISA_MODE_EXT_HEADER_6MBPS, + WISA_MODE_EXT_HEADER_24MBPS, +}; + +extern const uint32_t htt_to_ce_pkt_type[]; + +/** + * Provide a constant to specify the offset of the HTT portion of the + * HTT tx descriptor, to avoid having to export the descriptor defintion. + * The htt module checks internally that this exported offset is consistent + * with the private tx descriptor definition. + * + * Similarly, export a definition of the HTT tx descriptor size, and then + * check internally that this exported constant matches the private tx + * descriptor definition. + */ +#define HTT_TX_DESC_VADDR_OFFSET 8 + +/** + * htt_tx_desc_init() - Initialize the per packet HTT Tx descriptor + * @pdev: The handle of the physical device sending the + * tx data + * @htt_tx_desc: Abstract handle to the tx descriptor + * @htt_tx_desc_paddr_lo: Physical address of the HTT tx descriptor + * @msdu_id: ID to tag the descriptor with. + * The FW sends this ID back to host as a cookie + * during Tx completion, which the host uses to + * identify the MSDU. + * This ID is an index into the OL Tx desc. array. + * @msdu: The MSDU that is being prepared for transmission + * @msdu_info: Tx MSDU meta-data + * @tso_info: Storage for TSO meta-data + * @ext_header_data: extension header data + * @type: extension header type + * + * This function initializes the HTT tx descriptor. + * HTT Tx descriptor is a host-f/w interface structure, and meta-data + * accompanying every packet downloaded to f/w via the HTT interface. + * + * Return QDF_STATUS_SUCCESS for success, otherwise error. + */ +QDF_STATUS +htt_tx_desc_init(htt_pdev_handle pdev, + void *htt_tx_desc, + qdf_dma_addr_t htt_tx_desc_paddr, + uint16_t msdu_id, + qdf_nbuf_t msdu, struct htt_msdu_info_t *msdu_info, + struct qdf_tso_info_t *tso_info, + void *ext_header_data, + enum extension_header_type type); + +/** + * @brief Set a flag to indicate that the MSDU in question was postponed. + * @details + * In systems in which the host retains its tx frame until the target sends + * a tx completion, the target has the option of discarding it's copy of + * the tx descriptor (and frame, for HL) and sending a "postpone" message + * to the host, to inform the host that it must eventually download the + * tx descriptor (and frame, for HL). + * Before the host downloads the postponed tx desc/frame again, it will use + * this function to set a flag in the HTT tx descriptor indicating that this + * is a re-send of a postponed frame, rather than a new frame. The target + * uses this flag to keep the correct order between re-sent and new tx frames. + * This function is relevant for LL systems. + * + * @param pdev - the handle of the physical device sending the tx data + * @param desc - abstract handle to the tx descriptor + */ +void htt_tx_desc_flag_postponed(htt_pdev_handle pdev, void *desc); + +/** + * @brief Set a flag to tell the target that more tx downloads are en route. + * @details + * At times, particularly in response to a U-APSD trigger in a HL system, the + * host will download multiple tx descriptors (+ frames, in HL) in a batch. + * The host will use this function to set a "more" flag in the initial + * and interior frames of the batch, to tell the target that more tx frame + * downloads within the batch are imminent. + * + * @param pdev - the handle of the physical device sending the tx data + * @param desc - abstract handle to the tx descriptor + */ +void htt_tx_desc_flag_batch_more(htt_pdev_handle pdev, void *desc); + +/** + * @brief Specify the number of fragments in the fragmentation descriptor. + * @details + * Specify the number of fragments within the MSDU, i.e. the number of + * elements within the fragmentation descriptor. + * For LL, this is used to terminate the list of fragments used by the + * HW's tx MAC DMA. + * For HL, this is used to terminate the list of fragments provided to + * HTC for download. + * + * @param pdev - the handle of the physical device sending the tx data + * @param desc - abstract handle to the tx descriptor + * @param num_frags - the number of fragments comprising the MSDU + */ +static inline +void +htt_tx_desc_num_frags(htt_pdev_handle pdev, void *desc, uint32_t num_frags) +{ + /* + * Set the element after the valid frag elems to 0x0, + * to terminate the list of fragments. + */ +#if defined(HELIUMPLUS) + if (HTT_WIFI_IP(pdev, 2, 0)) { + struct msdu_ext_frag_desc *fdesc; + + /** Skip TSO related 4 dwords WIFI2.0*/ + fdesc = (struct msdu_ext_frag_desc *) + &(((struct msdu_ext_desc_t *)desc)->frags[0]); + fdesc[num_frags].u.desc64 = 0; + } else { + /* This piece of code should never be executed on HELIUMPLUS */ + *((u_int32_t *) + (((char *) desc) + HTT_TX_DESC_LEN + num_frags * 8)) = 0; + } +#else /* ! HELIUMPLUS */ + *((uint32_t *) + (((char *)desc) + HTT_TX_DESC_LEN + num_frags * 8)) = 0; +#endif /* HELIUMPLUS */ +} + +/* checksum offload flags for hw */ +#define IPV4_CSUM_EN 0x00010000 +#define UDP_IPV4_CSUM_EN 0x00020000 +#define UDP_IPV6_CSUM_EN 0x00040000 +#define TCP_IPV4_CSUM_EN 0x00080000 +#define TCP_IPV6_CSUM_EN 0x00100000 +#define PARTIAL_CSUM_EN 0x00200000 + +/** + * @brief Specify the location and size of a fragment of a tx MSDU. + * @details + * In LL systems, the tx MAC DMA needs to know how the MSDU is constructed + * from fragments. + * In LL and HL systems, the HIF's download DMA to the target (LL: tx desc + * + header of tx payload; HL: tx desc + entire tx payload) needs to know + * where to find the fragments to download. + * The tx data SW uses this function to specify the location and size of + * each of the MSDU's fragments. + * + * @param pdev - the handle of the physical device sending the tx data + * @param desc - abstract handle to the HTT tx descriptor + * @param frag_num - which fragment is being specified (zero-based indexing) + * @param frag_phys_addr - DMA/physical address of the fragment + * @param frag_len - number of bytes within the fragment + */ +static inline +void +htt_tx_desc_frag(htt_pdev_handle pdev, + void *desc, + int frag_num, qdf_dma_addr_t frag_phys_addr, uint16_t frag_len) +{ + uint32_t *word32; +#if defined(HELIUMPLUS) + uint64_t *word64; + + if (HTT_WIFI_IP(pdev, 2, 0)) { + word32 = (u_int32_t *)(desc); + /* Initialize top 6 words of TSO flags per packet */ + *word32++ = 0; + *word32++ = 0; + *word32++ = 0; + if (((struct txrx_pdev_cfg_t *)(pdev->ctrl_pdev)) + ->ip_tcp_udp_checksum_offload) + *word32 |= (IPV4_CSUM_EN | TCP_IPV4_CSUM_EN | + TCP_IPV6_CSUM_EN | UDP_IPV4_CSUM_EN | + UDP_IPV6_CSUM_EN); + else + *word32 = 0; + word32++; + *word32++ = 0; + *word32++ = 0; + + qdf_assert_always(word32 == (uint32_t *) + &(((struct msdu_ext_desc_t *)desc)->frags[0])); + + /* Each fragment consumes 2 DWORDS */ + word32 += (frag_num << 1); + word64 = (uint64_t *)word32; + *word64 = frag_phys_addr; + /* The frag_phys address is 37 bits. So, the higher 16 bits will be + for len */ + word32++; + *word32 &= 0x0000ffff; + *word32 |= (frag_len << 16); + } else { + /* For Helium+, this block cannot exist */ + QDF_ASSERT(0); + } +#else /* !defined(HELIUMPLUS) */ + { + uint64_t u64 = (uint64_t)frag_phys_addr; + uint32_t u32l = (u64 & 0xffffffff); + uint32_t u32h = (uint32_t)((u64 >> 32) & 0x1f); + uint64_t *word64; + + word32 = (uint32_t *) (((char *)desc) + HTT_TX_DESC_LEN + frag_num * 8); + word64 = (uint64_t *)word32; + *word32 = u32l; + word32++; + *word32 = (u32h << 16) | frag_len; + } +#endif /* defined(HELIUMPLUS) */ +} + +void htt_tx_desc_frags_table_set(htt_pdev_handle pdev, + void *desc, + qdf_dma_addr_t paddr, + qdf_dma_addr_t frag_desc_paddr, + int reset); + +/** + * @brief Specify the type and subtype of a tx frame. + * + * @param pdev - the handle of the physical device sending the tx data + * @param type - format of the MSDU (802.3, native WiFi, raw, or mgmt) + * @param sub_type - sub_type (relevant for raw frames) + */ +static inline +void +htt_tx_desc_type(htt_pdev_handle pdev, + void *htt_tx_desc, enum wlan_frm_fmt type, uint8_t sub_type) +{ + uint32_t *word0; + + word0 = (uint32_t *) htt_tx_desc; + /* clear old values */ + *word0 &= ~(HTT_TX_DESC_PKT_TYPE_M | HTT_TX_DESC_PKT_SUBTYPE_M); + /* write new values */ + HTT_TX_DESC_PKT_TYPE_SET(*word0, type); + HTT_TX_DESC_PKT_SUBTYPE_SET(*word0, sub_type); +} + +/***** TX MGMT DESC management APIs ****/ + +/* Number of mgmt descriptors in the pool */ +#define HTT_MAX_NUM_MGMT_DESCS 32 + +/** htt_tx_mgmt_desc_pool_alloc + * @description - allocates the memory for mgmt frame descriptors + * @param - htt pdev object + * @param - num of descriptors to be allocated in the pool + */ +void htt_tx_mgmt_desc_pool_alloc(struct htt_pdev_t *pdev, A_UINT32 num_elems); + +/** htt_tx_mgmt_desc_alloc + * @description - reserves a mgmt descriptor from the pool + * @param - htt pdev object + * @param - pointer to variable to hold the allocated desc id + * @param - pointer to the mamangement from UMAC + * @return - pointer the allocated mgmt descriptor + */ +qdf_nbuf_t +htt_tx_mgmt_desc_alloc(struct htt_pdev_t *pdev, A_UINT32 *desc_id, + qdf_nbuf_t mgmt_frm); + +/** htt_tx_mgmt_desc_free + * @description - releases the management descriptor back to the pool + * @param - htt pdev object + * @param - descriptor ID + */ +void +htt_tx_mgmt_desc_free(struct htt_pdev_t *pdev, A_UINT8 desc_id, + A_UINT32 status); + +/** htt_tx_mgmt_desc_pool_free + * @description - releases all the resources allocated for mgmt desc pool + * @param - htt pdev object + */ +void htt_tx_mgmt_desc_pool_free(struct htt_pdev_t *pdev); + +/** + * @brief Provide a buffer to store a 802.11 header added by SW tx encap + * + * @param htt_tx_desc - which frame the 802.11 header is being added to + * @param new_l2_hdr_size - how large the buffer needs to be + */ +#define htt_tx_desc_mpdu_header(htt_tx_desc, new_l2_hdr_size) /*NULL*/ +/** + * @brief How many tx credits would be consumed by the specified tx frame. + * + * @param msdu - the tx frame in question + * @return number of credits used for this tx frame + */ +#define htt_tx_msdu_credit(msdu) 1 /* 1 credit per buffer */ +#ifdef HTT_DBG +void htt_tx_desc_display(void *tx_desc); +#else +#define htt_tx_desc_display(tx_desc) +#endif + +static inline void htt_tx_desc_set_peer_id(void *htt_tx_desc, uint16_t peer_id) +{ + uint16_t *peer_id_field_ptr; + + peer_id_field_ptr = (uint16_t *) + (htt_tx_desc + + HTT_TX_DESC_PEERID_DESC_PADDR_OFFSET_BYTES); + + *peer_id_field_ptr = peer_id; +} + +static inline +void htt_tx_desc_set_chanfreq(void *htt_tx_desc, uint16_t chanfreq) +{ + uint16_t *chanfreq_field_ptr; + + /* The reason we dont use CHAN_FREQ_OFFSET_BYTES is because + it uses DWORD as unit */ + /* The reason we dont use the SET macro in htt.h is because + htt_tx_desc is incomplete type */ + chanfreq_field_ptr = (uint16_t *) + (htt_tx_desc + + HTT_TX_DESC_PEERID_DESC_PADDR_OFFSET_BYTES + + sizeof(A_UINT16)); + + *chanfreq_field_ptr = chanfreq; +} + +#if defined(FEATURE_TSO) +void +htt_tx_desc_fill_tso_info(htt_pdev_handle pdev, void *desc, + struct qdf_tso_info_t *tso_info); +#else +#define htt_tx_desc_fill_tso_info(pdev, desc, tso_info) +#endif +#endif /* _OL_HTT_TX_API__H_ */ diff --git a/drivers/staging/qcacld-3.0/core/dp/ol/inc/ol_params.h b/drivers/staging/qcacld-3.0/core/dp/ol/inc/ol_params.h new file mode 100644 index 0000000000000000000000000000000000000000..89eff22faad1d6dde0e1ad9b49bd79d3aa8b5d29 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/dp/ol/inc/ol_params.h @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2013-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * Defintions for the Atheros Wireless LAN controller driver. + */ +#ifndef _DEV_OL_PARAMS_H +#define _DEV_OL_PARAMS_H +#include "ol_txrx_stats.h" +#include "wlan_defs.h" /* for wlan statst definitions */ +/* +** Enumeration of PDEV Configuration parameter +*/ + +enum ol_ath_param_t { + OL_ATH_PARAM_TXCHAINMASK = 0, + OL_ATH_PARAM_RXCHAINMASK, + OL_ATH_PARAM_TXCHAINMASKLEGACY, + OL_ATH_PARAM_RXCHAINMASKLEGACY, + OL_ATH_PARAM_CHAINMASK_SEL, + OL_ATH_PARAM_AMPDU, + OL_ATH_PARAM_AMPDU_LIMIT, + OL_ATH_PARAM_AMPDU_SUBFRAMES, + OL_ATH_PARAM_LDPC, + OL_ATH_PARAM_NON_AGG_SW_RETRY_TH, + OL_ATH_PARAM_AGG_SW_RETRY_TH, + OL_ATH_PARAM_STA_KICKOUT_TH, + OL_ATH_PARAM_WLAN_PROF_ENABLE, + OL_ATH_PARAM_LTR_ENABLE, + OL_ATH_PARAM_LTR_AC_LATENCY_BE, + OL_ATH_PARAM_LTR_AC_LATENCY_BK, + OL_ATH_PARAM_LTR_AC_LATENCY_VI, + OL_ATH_PARAM_LTR_AC_LATENCY_VO, + OL_ATH_PARAM_LTR_AC_LATENCY_TIMEOUT, + OL_ATH_PARAM_LTR_TX_ACTIVITY_TIMEOUT, + OL_ATH_PARAM_LTR_SLEEP_OVERRIDE, + OL_ATH_PARAM_LTR_RX_OVERRIDE, + OL_ATH_PARAM_L1SS_ENABLE, + OL_ATH_PARAM_DSLEEP_ENABLE, + OL_ATH_PARAM_PCIELP_TXBUF_FLUSH, + OL_ATH_PARAM_PCIELP_TXBUF_WATERMARK, + OL_ATH_PARAM_PCIELP_TXBUF_TMO_EN, + OL_ATH_PARAM_PCIELP_TXBUF_TMO_VALUE, + OL_ATH_PARAM_BCN_BURST, + OL_ATH_PARAM_ARP_AC_OVERRIDE, + OL_ATH_PARAM_TXPOWER_LIMIT2G, + OL_ATH_PARAM_TXPOWER_LIMIT5G, + OL_ATH_PARAM_TXPOWER_SCALE, + OL_ATH_PARAM_DCS, + OL_ATH_PARAM_ANI_ENABLE, + OL_ATH_PARAM_ANI_POLL_PERIOD, + OL_ATH_PARAM_ANI_LISTEN_PERIOD, + OL_ATH_PARAM_ANI_OFDM_LEVEL, + OL_ATH_PARAM_ANI_CCK_LEVEL, + OL_ATH_PARAM_PROXYSTA, + OL_ATH_PARAM_DYN_TX_CHAINMASK, + OL_ATH_PARAM_VOW_EXT_STATS, + OL_ATH_PARAM_PWR_GATING_ENABLE, + OL_ATH_PARAM_CHATTER, +}; + +/* +** Enumeration of PDEV Configuration parameter +*/ + +enum ol_hal_param_t { + OL_HAL_CONFIG_DMA_BEACON_RESPONSE_TIME = 0 +}; + +/* +** structure to hold all stats information +** for offload device interface +*/ +struct ol_stats { + int txrx_stats_level; + struct ol_txrx_stats txrx_stats; + struct wlan_dbg_stats stats; +}; +#endif /* _DEV_OL_PARAMS_H */ diff --git a/drivers/staging/qcacld-3.0/core/dp/ol/inc/ol_txrx_api.h b/drivers/staging/qcacld-3.0/core/dp/ol/inc/ol_txrx_api.h new file mode 100644 index 0000000000000000000000000000000000000000..b0d56ee1df623b415264d75da3b453bc31872c32 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/dp/ol/inc/ol_txrx_api.h @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2011-2014, 2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * @file ol_txrx_api.h + * @brief Definitions used in multiple external interfaces to the txrx SW. + */ +#ifndef _OL_TXRX_API__H_ +#define _OL_TXRX_API__H_ + +/** + * @brief ADDBA negotiation status, used both during requests and confirmations + */ +enum ol_addba_status { + /* status: negotiation started or completed successfully */ + ol_addba_success, + + /* reject: aggregation is not applicable - don't try again */ + ol_addba_reject, + + /* busy: ADDBA negotiation couldn't be performed - try again later */ + ol_addba_busy, +}; + +enum ol_sec_type { + ol_sec_type_none, + ol_sec_type_wep128, + ol_sec_type_wep104, + ol_sec_type_wep40, + ol_sec_type_tkip, + ol_sec_type_tkip_nomic, + ol_sec_type_aes_ccmp, + ol_sec_type_wapi, + + /* keep this last! */ + ol_sec_type_types +}; + +typedef void (*tp_ol_packetdump_cb)(qdf_nbuf_t netbuf, + uint8_t status, uint8_t vdev_id, uint8_t type); +void ol_register_packetdump_callback(tp_ol_packetdump_cb ol_tx_packetdump_cb, + tp_ol_packetdump_cb ol_rx_packetdump_cb); +void ol_deregister_packetdump_callback(void); + +#endif /* _OL_TXRX_API__H_ */ diff --git a/drivers/staging/qcacld-3.0/core/dp/ol/inc/ol_txrx_ctrl_api.h b/drivers/staging/qcacld-3.0/core/dp/ol/inc/ol_txrx_ctrl_api.h new file mode 100644 index 0000000000000000000000000000000000000000..ab55ac39dc22a96774f56f2713afd506a0a4a9ec --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/dp/ol/inc/ol_txrx_ctrl_api.h @@ -0,0 +1,719 @@ +/* + * Copyright (c) 2011-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * @file ol_txrx_ctrl_api.h + * @brief Define the host data API functions called by the host control SW. + */ +#ifndef _OL_TXRX_CTRL_API__H_ +#define _OL_TXRX_CTRL_API__H_ + +#include /* A_STATUS */ +#include /* qdf_nbuf_t */ +#include /* qdf_device_t */ +#include /* HTC_HANDLE */ + +#include /* ol_sec_type */ +#include /* MAX_SPATIAL_STREAM */ +#include /* ol_pdev_handle, ol_vdev_handle, etc */ +#include + +#define OL_ATH_TX_DRAIN_WAIT_DELAY 50 + +/* Maximum number of station supported by data path, including BC. */ +#define WLAN_MAX_STA_COUNT (HAL_NUM_STA) + +/* The symbolic station ID return to HDD to specify the packet is bc/mc */ +#define WLAN_RX_BCMC_STA_ID (WLAN_MAX_STA_COUNT + 1) + +/* The symbolic station ID return to HDD to specify the packet is + to soft-AP itself */ +#define WLAN_RX_SAP_SELF_STA_ID (WLAN_MAX_STA_COUNT + 2) + +#define OL_TXQ_PAUSE_REASON_FW (1 << 0) +#define OL_TXQ_PAUSE_REASON_PEER_UNAUTHORIZED (1 << 1) +#define OL_TXQ_PAUSE_REASON_TX_ABORT (1 << 2) +#define OL_TXQ_PAUSE_REASON_VDEV_STOP (1 << 3) +#define OL_TXQ_PAUSE_REASON_THERMAL_MITIGATION (1 << 4) + +/* command options for dumpStats*/ +#define WLAN_HDD_STATS 0 +#define WLAN_TXRX_STATS 1 +#define WLAN_TXRX_HIST_STATS 2 +#define WLAN_TXRX_TSO_STATS 3 +#define WLAN_HDD_NETIF_OPER_HISTORY 4 +#define WLAN_DUMP_TX_FLOW_POOL_INFO 5 +#define WLAN_TXRX_DESC_STATS 6 +#define WLAN_HIF_STATS 7 +#define WLAN_LRO_STATS 8 +#define WLAN_NAPI_STATS 9 +#define WLAN_RX_BUF_DEBUG_STATS 10 +#define WLAN_SCHEDULER_STATS 21 +#define WLAN_TX_QUEUE_STATS 22 +#define WLAN_BUNDLE_STATS 23 +#define WLAN_CREDIT_STATS 24 + +/** + * @brief Set up the data SW subsystem. + * @details + * As part of the WLAN device attach, the data SW subsystem has + * to be attached as a component within the WLAN device. + * This attach allocates and initializes the physical device object + * used by the data SW. + * The data SW subsystem attach needs to happen after the target has + * be started, and host / target parameter negotiation has completed, + * since the host data SW uses some of these host/target negotiated + * parameters (e.g. peer ID range) during the initializations within + * its attach function. + * However, the host data SW is not allowed to send HTC messages to the + * target within this pdev_attach function call, since the HTC setup + * has not complete at this stage of initializations. Any messaging + * to the target has to be done in the separate pdev_attach_target call + * that is invoked after HTC setup is complete. + * + * @param pdev - txrx_pdev handle + * @return 0 for success or error code + */ +int +ol_txrx_pdev_post_attach(ol_txrx_pdev_handle pdev); + +/** + * @brief Parameter type to be input to ol_txrx_peer_update + * @details + * This struct is union,to be used to specify various informations to update + * txrx peer object. + */ +union ol_txrx_peer_update_param_t { + uint8_t qos_capable; + uint8_t uapsd_mask; + enum ol_sec_type sec_type; +}; + +/** + * @brief Parameter type to be input to ol_txrx_peer_update + * @details + * This enum is used to specify what exact information in + * ol_txrx_peer_update_param_t + * is used to update the txrx peer object. + */ +enum ol_txrx_peer_update_select_t { + ol_txrx_peer_update_qos_capable = 1, + ol_txrx_peer_update_uapsdMask, + ol_txrx_peer_update_peer_security, +}; + +/** + * @brief Update the data peer object as some informaiton changed in node. + * @details + * Only a single prarameter can be changed for each call to this func. + * + * @param peer - pointer to the node's object + * @param param - new param to be upated in peer object. + * @param select - specify what's parameter needed to be update + */ +void +ol_txrx_peer_update(ol_txrx_vdev_handle data_vdev, uint8_t *peer_mac, + union ol_txrx_peer_update_param_t *param, + enum ol_txrx_peer_update_select_t select); + +enum { + OL_TX_WMM_AC_BE, + OL_TX_WMM_AC_BK, + OL_TX_WMM_AC_VI, + OL_TX_WMM_AC_VO, + + OL_TX_NUM_WMM_AC +}; + +/** + * @brief Parameter type to pass WMM setting to ol_txrx_set_wmm_param + * @details + * The struct is used to specify informaiton to update TX WMM scheduler. + */ +struct ol_tx_ac_param_t { + uint32_t aifs; + uint32_t cwmin; + uint32_t cwmax; +}; + +struct ol_tx_wmm_param_t { + struct ol_tx_ac_param_t ac[OL_TX_NUM_WMM_AC]; +}; + +#if defined(CONFIG_HL_SUPPORT) +/** + * @brief Set paramters of WMM scheduler per AC settings. . + * @details + * This function applies only to HL systems. + * + * @param data_pdev - the physical device being paused + * @param wmm_param - the wmm parameters + */ +void +ol_txrx_set_wmm_param(ol_txrx_pdev_handle data_pdev, + struct ol_tx_wmm_param_t wmm_param); + +/** + * @brief notify tx data SW that a peer-TID is ready to transmit to. + * @details + * This function applies only to HL systems - in LL systems, tx flow control + * is handled entirely within the target FW. + * If a peer-TID has tx paused, then the tx datapath will end up queuing + * any tx frames that arrive from the OS shim for that peer-TID. + * In a HL system, the host tx data SW itself will classify the tx frame, + * and determine that it needs to be queued rather than downloaded to the + * target for transmission. + * Once the peer-TID is ready to accept data, the host control SW will call + * this function to notify the host data SW that the queued frames can be + * enabled for transmission, or specifically to download the tx frames + * to the target to transmit. + * The TID parameter is an extended version of the QoS TID. Values 0-15 + * indicate a regular QoS TID, and the value 16 indicates either non-QoS + * data, multicast data, or broadcast data. + * + * @param data_peer - which peer is being unpaused + * @param tid - which TID within the peer is being unpaused, or -1 as a + * wildcard to unpause all TIDs within the peer + */ +void +ol_txrx_peer_tid_unpause(ol_txrx_peer_handle data_peer, int tid); + + +/** + * @brief Tell a paused peer to release a specified number of tx frames. + * @details + * This function applies only to HL systems - in LL systems, tx flow control + * is handled entirely within the target FW. + * Download up to a specified maximum number of tx frames from the tx + * queues of the specified TIDs within the specified paused peer, usually + * in response to a U-APSD trigger from the peer. + * It is up to the host data SW to determine how to choose frames from the + * tx queues of the specified TIDs. However, the host data SW does need to + * provide long-term fairness across the U-APSD enabled TIDs. + * The host data SW will notify the target data FW when it is done downloading + * the batch of U-APSD triggered tx frames, so the target data FW can + * differentiate between an in-progress download versus a case when there are + * fewer tx frames available than the specified limit. + * This function is relevant primarily to HL U-APSD, where the frames are + * held in the host. + * + * @param peer - which peer sent the U-APSD trigger + * @param tid_mask - bitmask of U-APSD enabled TIDs from whose tx queues + * tx frames can be released + * @param max_frms - limit on the number of tx frames to release from the + * specified TID's queues within the specified peer + */ +void ol_txrx_tx_release(ol_txrx_peer_handle peer, + u_int32_t tid_mask, + int max_frms); + +/** + * @brief Suspend all tx data per thermal event/timer for the + * specified physical device + * @details + * This function applies only to HL systerms, and it makes pause and + * unpause operations happen in pairs. + */ +void +ol_txrx_throttle_pause(ol_txrx_pdev_handle data_pdev); + + +/** + * @brief Resume all tx data per thermal event/timer for the + * specified physical device + * @details + * This function applies only to HL systerms, and it makes pause and + * unpause operations happen in pairs. + */ +void +ol_txrx_throttle_unpause(ol_txrx_pdev_handle data_pdev); + +#else + +static inline +void ol_txrx_set_wmm_param(ol_txrx_pdev_handle data_pdev, + struct ol_tx_wmm_param_t wmm_param) +{ + return; +} + +static inline void +ol_txrx_peer_tid_unpause(ol_txrx_peer_handle data_peer, int tid) +{ + return; +} + +static inline void +ol_txrx_tx_release(ol_txrx_peer_handle peer, + u_int32_t tid_mask, + int max_frms) +{ + return; +} + +static inline void +ol_txrx_throttle_pause(ol_txrx_pdev_handle data_pdev) +{ + return; +} + +static inline void +ol_txrx_throttle_unpause(ol_txrx_pdev_handle data_pdev) +{ + return; +} + +#endif /* CONFIG_HL_SUPPORT */ + +/** + * @brief notify tx data SW that a peer's transmissions are suspended. + * @details + * This function applies only to HL systems - in LL systems, tx flow control + * is handled entirely within the target FW. + * The HL host tx data SW is doing tx classification and tx download + * scheduling, and therefore also needs to actively participate in tx + * flow control. Specifically, the HL tx data SW needs to check whether a + * given peer is available to transmit to, or is paused. + * This function is used to tell the HL tx data SW when a peer is paused, + * so the host tx data SW can hold the tx frames for that SW. + * + * @param data_peer - which peer is being paused + */ +static inline void ol_txrx_peer_pause(struct ol_txrx_peer_t *data_peer) +{ + return; +} + +/** + * @brief Suspend all tx data for the specified physical device. + * @details + * This function applies only to HL systems - in LL systems, tx flow control + * is handled entirely within the target FW. + * In some systems it is necessary to be able to temporarily + * suspend all WLAN traffic, e.g. to allow another device such as bluetooth + * to temporarily have exclusive access to shared RF chain resources. + * This function suspends tx traffic within the specified physical device. + * + * @param data_pdev - the physical device being paused + */ +#if defined(QCA_LL_LEGACY_TX_FLOW_CONTROL) || \ + defined(QCA_LL_TX_FLOW_CONTROL_V2) || defined(CONFIG_HL_SUPPORT) + +void ol_txrx_pdev_pause(struct ol_txrx_pdev_t *data_pdev, uint32_t reason); +#else +static inline +void ol_txrx_pdev_pause(struct ol_txrx_pdev_t *data_pdev, uint32_t reason) +{ + return; +} +#endif + +/** + * @brief Resume tx for the specified physical device. + * @details + * This function applies only to HL systems - in LL systems, tx flow control + * is handled entirely within the target FW. + * + * @param data_pdev - the physical device being unpaused + */ +#if defined(QCA_LL_LEGACY_TX_FLOW_CONTROL) || \ + defined(QCA_LL_TX_FLOW_CONTROL_V2) || defined(CONFIG_HL_SUPPORT) + +void ol_txrx_pdev_unpause(struct ol_txrx_pdev_t *pdev, uint32_t reason); +#else +static inline +void ol_txrx_pdev_unpause(struct ol_txrx_pdev_t *pdev, uint32_t reason) +{ + return; +} +#endif + +/** + * @brief Synchronize the data-path tx with a control-path target download + * @dtails + * @param data_pdev - the data-path physical device object + * @param sync_cnt - after the host data-path SW downloads this sync request + * to the target data-path FW, the target tx data-path will hold itself + * in suspension until it is given an out-of-band sync counter value that + * is equal to or greater than this counter value + */ +void ol_txrx_tx_sync(ol_txrx_pdev_handle data_pdev, uint8_t sync_cnt); + +typedef void (*ol_txrx_vdev_delete_cb)(void *context); + + +typedef void +(*ol_txrx_data_tx_cb)(void *ctxt, qdf_nbuf_t tx_frm, int had_error); + +/** + * @brief Store a delivery notification callback for specific data frames. + * @details + * Through a non-std tx function, the txrx SW can be given tx data frames + * that are specially marked to not be unmapped and freed by the tx SW + * when transmission completes. Rather, these specially-marked frames + * are provided to the callback registered with this function. + * + * @param data_vdev - which vdev the callback is being registered with + * (Currently the callback is stored in the pdev rather than the vdev.) + * @param callback - the function to call when tx frames marked as "no free" + * are done being transmitted + * @param ctxt - the context argument provided to the callback function + */ +void +ol_txrx_data_tx_cb_set(ol_txrx_vdev_handle data_vdev, + ol_txrx_data_tx_cb callback, void *ctxt); + +#ifdef FEATURE_RUNTIME_PM +QDF_STATUS ol_txrx_runtime_suspend(ol_txrx_pdev_handle txrx_pdev); +QDF_STATUS ol_txrx_runtime_resume(ol_txrx_pdev_handle txrx_pdev); +#endif + +QDF_STATUS ol_txrx_wait_for_pending_tx(int timeout); + +/** + * @brief Discard all tx frames that are pending in txrx. + * @details + * Mainly used in clean up path to make sure all pending tx packets + * held by txrx are returned back to OS shim immediately. + * + * @param pdev - the data physical device object + * @return - void + */ +void ol_txrx_discard_tx_pending(ol_txrx_pdev_handle pdev); + +/** + * @brief set the safemode of the device + * @details + * This flag is used to bypass the encrypt and decrypt processes when send and + * receive packets. It works like open AUTH mode, HW will treate all packets + * as non-encrypt frames because no key installed. For rx fragmented frames, + * it bypasses all the rx defragmentaion. + * + * @param vdev - the data virtual device object + * @param val - the safemode state + * @return - void + */ +void ol_txrx_set_safemode(ol_txrx_vdev_handle vdev, uint32_t val); + +/** + * @brief configure the drop unencrypted frame flag + * @details + * Rx related. When set this flag, all the unencrypted frames + * received over a secure connection will be discarded + * + * @param vdev - the data virtual device object + * @param val - flag + * @return - void + */ +void ol_txrx_set_drop_unenc(ol_txrx_vdev_handle vdev, uint32_t val); + +void +ol_txrx_peer_keyinstalled_state_update(ol_txrx_peer_handle data_peer, + uint8_t val); + +#define ol_tx_addba_conf(data_peer, tid, status) /* no-op */ + +/** + * @brief Find a txrx peer handle from the peer's MAC address + * @details + * The control SW typically uses the txrx peer handle to refer to the peer. + * In unusual circumstances, if it is infeasible for the control SW maintain + * the txrx peer handle but it can maintain the peer's MAC address, + * this function allows the peer handled to be retrieved, based on the peer's + * MAC address. + * In cases where there are multiple peer objects with the same MAC address, + * it is undefined which such object is returned. + * This function does not increment the peer's reference count. Thus, it is + * only suitable for use as long as the control SW has assurance that it has + * not deleted the peer object, by calling ol_txrx_peer_detach. + * + * @param pdev - the data physical device object + * @param peer_mac_addr - MAC address of the peer in question + * @return handle to the txrx peer object + */ +ol_txrx_peer_handle +ol_txrx_peer_find_by_addr(ol_txrx_pdev_handle pdev, uint8_t *peer_mac_addr); + +struct ol_txrx_peer_stats_t { + struct { + struct { + uint32_t ucast; + uint32_t mcast; + uint32_t bcast; + } frms; + struct { + uint32_t ucast; + uint32_t mcast; + uint32_t bcast; + } bytes; + } tx; + struct { + struct { + uint32_t ucast; + uint32_t mcast; + uint32_t bcast; + } frms; + struct { + uint32_t ucast; + uint32_t mcast; + uint32_t bcast; + } bytes; + } rx; +}; + +/** + * @brief Provide a snapshot of the txrx counters for the specified peer + * @details + * The txrx layer optionally maintains per-peer stats counters. + * This function provides the caller with a consistent snapshot of the + * txrx stats counters for the specified peer. + * + * @param pdev - the data physical device object + * @param peer - which peer's stats counters are requested + * @param stats - buffer for holding the stats counters snapshot + * @return success / failure status + */ +#ifdef QCA_ENABLE_OL_TXRX_PEER_STATS +A_STATUS +ol_txrx_peer_stats_copy(ol_txrx_pdev_handle pdev, + ol_txrx_peer_handle peer, ol_txrx_peer_stats_t *stats); +#else +#define ol_txrx_peer_stats_copy(pdev, peer, stats) A_ERROR /* failure */ +#endif /* QCA_ENABLE_OL_TXRX_PEER_STATS */ + +QDF_STATUS ol_txrx_get_vdevid(struct ol_txrx_peer_t *peer, uint8_t *vdev_id); + +void *ol_txrx_get_vdev_by_sta_id(uint8_t sta_id); + +#define OL_TXRX_INVALID_LOCAL_PEER_ID 0xffff + +#define OL_TXRX_RSSI_INVALID 0xffff +/** + * @brief Provide the current RSSI average from data frames sent by a peer. + * @details + * If a peer has sent data frames, the data SW will optionally keep + * a running average of the RSSI observed for those data frames. + * This function returns that time-average RSSI if is it available, + * or OL_TXRX_RSSI_INVALID if either RSSI tracking is disabled or if + * no data frame indications with valid RSSI meta-data have been received. + * The RSSI is in approximate dBm units, and is normalized with respect + * to a 20 MHz channel. For example, if a data frame is received on a + * 40 MHz channel, wherein both the primary 20 MHz channel and the + * secondary 20 MHz channel have an RSSI of -77 dBm, the reported RSSI + * will be -77 dBm, rather than the actual -74 dBm RSSI from the + * combination of the primary + extension 20 MHz channels. + * Alternatively, the RSSI may be evaluated only on the primary 20 MHz + * channel. + * + * @param peer - which peer's RSSI is desired + * @return RSSI evaluted from frames sent by the specified peer + */ +#ifdef QCA_SUPPORT_PEER_DATA_RX_RSSI +int16_t ol_txrx_peer_rssi(ol_txrx_peer_handle peer); +#else +#define ol_txrx_peer_rssi(peer) OL_TXRX_RSSI_INVALID +#endif /* QCA_SUPPORT_PEER_DATA_RX_RSSI */ + +/* + * Bins used for reporting delay histogram: + * bin 0: 0 - 10 ms delay + * bin 1: 10 - 20 ms delay + * bin 2: 20 - 40 ms delay + * bin 3: 40 - 80 ms delay + * bin 4: 80 - 160 ms delay + * bin 5: > 160 ms delay + */ +#define QCA_TX_DELAY_HIST_REPORT_BINS 6 + +#if defined(CONFIG_HL_SUPPORT) && defined(QCA_BAD_PEER_TX_FLOW_CL) + +/** + * @brief Configure the bad peer tx limit setting. + * @details + * + * @param pdev - the physics device + */ +void +ol_txrx_bad_peer_txctl_set_setting( + struct ol_txrx_pdev_t *pdev, + int enable, + int period, + int txq_limit); + +/** + * @brief Configure the bad peer tx threshold limit + * @details + * + * @param pdev - the physics device + */ +void +ol_txrx_bad_peer_txctl_update_threshold( + struct ol_txrx_pdev_t *pdev, + int level, + int tput_thresh, + int tx_limit); + +#else + +static inline void +ol_txrx_bad_peer_txctl_set_setting( + struct ol_txrx_pdev_t *pdev, + int enable, + int period, + int txq_limit) +{ + return; +} + +static inline void +ol_txrx_bad_peer_txctl_update_threshold( + struct ol_txrx_pdev_t *pdev, + int level, + int tput_thresh, + int tx_limit) +{ + return; +} +#endif /* defined(CONFIG_HL_SUPPORT) && defined(QCA_BAD_PEER_TX_FLOW_CL) */ + + +void ol_txrx_set_ocb_peer(struct ol_txrx_pdev_t *pdev, + struct ol_txrx_peer_t *peer); + +bool ol_txrx_get_ocb_peer(struct ol_txrx_pdev_t *pdev, + struct ol_txrx_peer_t **peer); +/** + * ol_txrx_set_ocb_def_tx_param() - Set the default OCB TX parameters + * @vdev: The OCB vdev that will use these defaults. + * @_def_tx_param: The default TX parameters. + * @def_tx_param_size: The size of the _def_tx_param buffer. + * + * Return: true if the default parameters were set correctly, false if there + * is an error, for example an invalid parameter. In the case that false is + * returned, see the kernel log for the error description. + */ +bool ol_txrx_set_ocb_def_tx_param(ol_txrx_vdev_handle vdev, + void *def_tx_param, uint32_t def_tx_param_size); + +void ol_tx_set_is_mgmt_over_wmi_enabled(uint8_t value); +uint8_t ol_tx_get_is_mgmt_over_wmi_enabled(void); + +/* TX FLOW Control related functions */ +#ifdef QCA_LL_TX_FLOW_CONTROL_V2 +#define TX_FLOW_MGMT_POOL_ID 0xEF + +#ifdef QCA_LL_TX_FLOW_GLOBAL_MGMT_POOL +#define TX_FLOW_MGMT_POOL_SIZE 32 +#else +#define TX_FLOW_MGMT_POOL_SIZE 0 +#endif + +void ol_tx_register_flow_control(struct ol_txrx_pdev_t *pdev); +void ol_tx_deregister_flow_control(struct ol_txrx_pdev_t *pdev); +void ol_tx_dump_flow_pool_info(void); +void ol_tx_clear_flow_pool_stats(void); +void ol_tx_flow_pool_map_handler(uint8_t flow_id, uint8_t flow_type, + uint8_t flow_pool_id, uint16_t flow_pool_size); +void ol_tx_flow_pool_unmap_handler(uint8_t flow_id, uint8_t flow_type, + uint8_t flow_pool_id); +struct ol_tx_flow_pool_t *ol_tx_create_flow_pool(uint8_t flow_pool_id, + uint16_t flow_pool_size); + +/** + * ol_tx_inc_pool_ref() - increment pool ref count + * @pool: flow pool pointer + * + * Increments pool's ref count, used to make sure that no one is using + * pool when it is being deleted. + * As this function is taking pool->flow_pool_lock inside it, it should + * always be called outside this spinlock. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS ol_tx_inc_pool_ref(struct ol_tx_flow_pool_t *pool); + +/** + * ol_tx_dec_pool_ref() - decrement pool ref count + * @pool: flow pool pointer + * @force: free pool forcefully + * + * Decrements pool's ref count and deletes the pool if ref count gets 0. + * As this function is taking pdev->tx_desc.flow_pool_list_lock and + * pool->flow_pool_lock inside it, it should always be called outside + * these two spinlocks. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS ol_tx_dec_pool_ref(struct ol_tx_flow_pool_t *pool, bool force); +#else + +static inline void ol_tx_register_flow_control(struct ol_txrx_pdev_t *pdev) +{ + return; +} +static inline void ol_tx_deregister_flow_control(struct ol_txrx_pdev_t *pdev) +{ + return; +} +static inline void ol_tx_dump_flow_pool_info(void) +{ + return; +} +static inline void ol_tx_clear_flow_pool_stats(void) +{ + return; +} +static inline void ol_tx_flow_pool_map_handler(uint8_t flow_id, + uint8_t flow_type, uint8_t flow_pool_id, uint16_t flow_pool_size) +{ + return; +} +static inline void ol_tx_flow_pool_unmap_handler(uint8_t flow_id, + uint8_t flow_type, uint8_t flow_pool_id) +{ + return; +} +static inline struct ol_tx_flow_pool_t *ol_tx_create_flow_pool( + uint8_t flow_pool_id, uint16_t flow_pool_size) +{ + return NULL; +} +static inline QDF_STATUS +ol_tx_inc_pool_ref(struct ol_tx_flow_pool_t *pool) +{ + return QDF_STATUS_SUCCESS; +} +static inline QDF_STATUS +ol_tx_dec_pool_ref(struct ol_tx_flow_pool_t *pool, bool force) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +void ol_tx_mark_first_wakeup_packet(uint8_t value); + +#endif /* _OL_TXRX_CTRL_API__H_ */ diff --git a/drivers/staging/qcacld-3.0/core/dp/ol/inc/ol_txrx_dbg.h b/drivers/staging/qcacld-3.0/core/dp/ol/inc/ol_txrx_dbg.h new file mode 100644 index 0000000000000000000000000000000000000000..8e5470344b19327be21a9f14acd76e5bf380efa6 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/dp/ol/inc/ol_txrx_dbg.h @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2011, 2014-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * @file ol_txrx_dbg.h + * @brief Functions provided for visibility and debugging. + */ +#ifndef _OL_TXRX_DBG__H_ +#define _OL_TXRX_DBG__H_ + +#include /* A_STATUS, uint64_t */ +#include /* qdf_semaphore_t */ +#include /* htt_dbg_stats_type */ +#include /* ol_txrx_stats */ + +#ifndef TXRX_DEBUG_LEVEL +#define TXRX_DEBUG_LEVEL 0 /* no debug info */ +#endif + +enum { + TXRX_DBG_MASK_OBJS = 0x01, + TXRX_DBG_MASK_STATS = 0x02, + TXRX_DBG_MASK_PROT_ANALYZE = 0x04, + TXRX_DBG_MASK_RX_REORDER_TRACE = 0x08, + TXRX_DBG_MASK_RX_PN_TRACE = 0x10 +}; + +/*--- txrx printouts ---*/ + +/* + * Uncomment this to enable txrx printouts with dynamically adjustable + * verbosity. These printouts should not impact performance. + */ +#define TXRX_PRINT_ENABLE 1 +/* uncomment this for verbose txrx printouts (may impact performance) */ +/* #define TXRX_PRINT_VERBOSE_ENABLE 1 */ + +/*--- txrx object (pdev, vdev, peer) display debug functions ---*/ + +#if TXRX_DEBUG_LEVEL > 5 +void ol_txrx_pdev_display(ol_txrx_pdev_handle pdev, int indent); +void ol_txrx_vdev_display(ol_txrx_vdev_handle vdev, int indent); +void ol_txrx_peer_display(ol_txrx_peer_handle peer, int indent); +#else +#define ol_txrx_pdev_display(pdev, indent) +#define ol_txrx_vdev_display(vdev, indent) +#define ol_txrx_peer_display(peer, indent) +#endif + +/*--- txrx stats display debug functions ---*/ + + +void ol_txrx_stats_display(ol_txrx_pdev_handle pdev); + +void ol_txrx_stats_clear(ol_txrx_pdev_handle pdev); + + +/*--- txrx protocol analyzer debug feature ---*/ + +/* uncomment this to enable the protocol analzyer feature */ +/* #define ENABLE_TXRX_PROT_ANALYZE 1 */ + +#if defined(ENABLE_TXRX_PROT_ANALYZE) + +void ol_txrx_prot_ans_display(ol_txrx_pdev_handle pdev); + +#else + +#define ol_txrx_prot_ans_display(pdev) + +#endif /* ENABLE_TXRX_PROT_ANALYZE */ + +/*--- txrx sequence number trace debug feature ---*/ + +/* uncomment this to enable the rx reorder trace feature */ +/* #define ENABLE_RX_REORDER_TRACE 1 */ + +#define ol_txrx_seq_num_trace_display(pdev) \ + ol_rx_reorder_trace_display(pdev, 0, 0) + +#if defined(ENABLE_RX_REORDER_TRACE) + +void +ol_rx_reorder_trace_display(ol_txrx_pdev_handle pdev, int just_once, int limit); + +#else + +#define ol_rx_reorder_trace_display(pdev, just_once, limit) + +#endif /* ENABLE_RX_REORDER_TRACE */ + +/*--- txrx packet number trace debug feature ---*/ + +/* uncomment this to enable the rx PN trace feature */ +/* #define ENABLE_RX_PN_TRACE 1 */ + +#define ol_txrx_pn_trace_display(pdev) ol_rx_pn_trace_display(pdev, 0) + +#if defined(ENABLE_RX_PN_TRACE) + +void ol_rx_pn_trace_display(ol_txrx_pdev_handle pdev, int just_once); + +#else + +#define ol_rx_pn_trace_display(pdev, just_once) + +#endif /* ENABLE_RX_PN_TRACE */ + +/*--- tx queue log debug feature ---*/ +/* uncomment this to enable the tx queue log feature */ +/* #define ENABLE_TX_QUEUE_LOG 1 */ + +#if defined(DEBUG_HL_LOGGING) && defined(CONFIG_HL_SUPPORT) + +void +ol_tx_queue_log_display(ol_txrx_pdev_handle pdev); +void ol_tx_queue_log_clear(ol_txrx_pdev_handle pdev); +#else + +static inline void +ol_tx_queue_log_display(ol_txrx_pdev_handle pdev) +{ + return; +} + +static inline +void ol_tx_queue_log_clear(ol_txrx_pdev_handle pdev) +{ + return; +} +#endif /* defined(DEBUG_HL_LOGGING) && defined(CONFIG_HL_SUPPORT) */ + + +/*----------------------------------------*/ + +#endif /* _OL_TXRX_DBG__H_ */ diff --git a/drivers/staging/qcacld-3.0/core/dp/ol/inc/ol_txrx_htt_api.h b/drivers/staging/qcacld-3.0/core/dp/ol/inc/ol_txrx_htt_api.h new file mode 100644 index 0000000000000000000000000000000000000000..64b4c5870b5b87cb93caca3e74bc4337ad1912b7 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/dp/ol/inc/ol_txrx_htt_api.h @@ -0,0 +1,747 @@ +/* + * Copyright (c) 2011-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * @file ol_txrx_htt_api.h + * @brief Define the host data API functions called by the host HTT SW. + */ +#ifndef _OL_TXRX_HTT_API__H_ +#define _OL_TXRX_HTT_API__H_ + +#include /* HTT_TX_COMPL_IND_STAT */ +#include /* A_STATUS */ +#include /* qdf_nbuf_t */ + +#include /* ol_txrx_pdev_handle */ + +#ifdef CONFIG_HL_SUPPORT +static inline uint16_t *ol_tx_msdu_id_storage(qdf_nbuf_t msdu) +{ + return (uint16_t *) (&QDF_NBUF_CB_TX_DESC_ID(msdu)); + +} +#else +static inline uint16_t *ol_tx_msdu_id_storage(qdf_nbuf_t msdu) +{ + qdf_assert(qdf_nbuf_headroom(msdu) >= (sizeof(uint16_t) * 2 - 1)); + return (uint16_t *) (((qdf_size_t) (qdf_nbuf_head(msdu) + 1)) & ~0x1); +} +#endif +/** + * @brief Tx MSDU download completion for a LL system + * @details + * Release the reference to the downloaded tx descriptor. + * In the unlikely event that the reference count is zero, free + * the tx descriptor and tx frame. + * + * @param pdev - (abstract) pointer to the txrx physical device + * @param status - indication of whether the download succeeded + * @param msdu - the downloaded tx frame + * @param msdu_id - the txrx ID of the tx frame - this is used for + * locating the frame's tx descriptor + */ +void +ol_tx_download_done_ll(void *pdev, + A_STATUS status, qdf_nbuf_t msdu, uint16_t msdu_id); + +/** + * @brief Tx MSDU download completion for HL system without tx completion msgs + * @details + * Free the tx descriptor and tx frame. + * Invoke the HL tx download scheduler. + * + * @param pdev - (abstract) pointer to the txrx physical device + * @param status - indication of whether the download succeeded + * @param msdu - the downloaded tx frame + * @param msdu_id - the txrx ID of the tx frame - this is used for + * locating the frame's tx descriptor + */ +void +ol_tx_download_done_hl_free(void *pdev, + A_STATUS status, qdf_nbuf_t msdu, uint16_t msdu_id); + +/** + * @brief Tx MSDU download completion for HL system with tx completion msgs + * @details + * Release the reference to the downloaded tx descriptor. + * In the unlikely event that the reference count is zero, free + * the tx descriptor and tx frame. + * Optionally, invoke the HL tx download scheduler. (It is probable that + * the HL tx download scheduler would operate in response to tx completion + * messages rather than download completion events.) + * + * @param pdev - (abstract) pointer to the txrx physical device + * @param status - indication of whether the download succeeded + * @param msdu - the downloaded tx frame + * @param msdu_id - the txrx ID of the tx frame - this is used for + * locating the frame's tx descriptor + */ +void +ol_tx_download_done_hl_retain(void *pdev, + A_STATUS status, + qdf_nbuf_t msdu, uint16_t msdu_id); + +/* + * For now, make the host HTT -> host txrx tx completion status + * match the target HTT -> host HTT tx completion status, so no + * translation is needed. + */ +/* + * host-only statuses use a different part of the number space + * than host-target statuses + */ +#define HTT_HOST_ONLY_STATUS_CODE_START 128 +enum htt_tx_status { + /* ok - successfully sent + acked */ + htt_tx_status_ok = HTT_TX_COMPL_IND_STAT_OK, + + /* discard - not sent (congestion control) */ + htt_tx_status_discard = HTT_TX_COMPL_IND_STAT_DISCARD, + + /* no_ack - sent, but no ack */ + htt_tx_status_no_ack = HTT_TX_COMPL_IND_STAT_NO_ACK, + + /* download_fail - host could not deliver the tx frame to target */ + htt_tx_status_download_fail = HTT_HOST_ONLY_STATUS_CODE_START, +}; + +/** + * @brief Process a tx completion message sent by the target. + * @details + * When the target is done transmitting a tx frame (either because + * the frame was sent + acknowledged, or because the target gave up) + * it sends a tx completion message to the host. + * This notification function is used regardless of whether the + * transmission succeeded or not; the status argument indicates whether + * the transmission succeeded. + * This tx completion message indicates via the descriptor ID which + * tx frames were completed, and indicates via the status whether the + * frames were transmitted successfully. + * The host frees the completed descriptors / frames (updating stats + * in the process). + * + * @param pdev - the data physical device that sent the tx frames + * (registered with HTT as a context pointer during attach time) + * @param num_msdus - how many MSDUs are referenced by the tx completion + * message + * @param status - whether transmission was successful + * @param tx_msdu_id_iterator - abstract method of finding the IDs for the + * individual MSDUs referenced by the tx completion message, via the + * htt_tx_compl_desc_id API function + */ +void +ol_tx_completion_handler(ol_txrx_pdev_handle pdev, + int num_msdus, + enum htt_tx_status status, void *tx_msdu_id_iterator); + +void ol_tx_credit_completion_handler(ol_txrx_pdev_handle pdev, int credits); + +struct rate_report_t { + u_int16_t id; + u_int16_t phy:4; + u_int32_t rate; +}; + +#if defined(CONFIG_HL_SUPPORT) && defined(QCA_BAD_PEER_TX_FLOW_CL) + +/** + * @brief Process a link status report for all peers. + * @details + * The ol_txrx_peer_link_status_handler function performs basic peer link + * status analysis + * + * According to the design, there are 3 kinds of peers which will be + * treated differently: + * 1) normal: not do any flow control for the peer + * 2) limited: will apply flow control for the peer, but frames are allowed + * to send + * 3) paused: will apply flow control for the peer, no frame is allowed + * to send + * + * @param pdev - the data physical device that sent the tx frames + * @param status - the number of peers need to be handled + * @param peer_link_report - the link status dedail message + */ +void +ol_txrx_peer_link_status_handler( + ol_txrx_pdev_handle pdev, + u_int16_t peer_num, + struct rate_report_t *peer_link_status); + + +#else +static inline void ol_txrx_peer_link_status_handler( + ol_txrx_pdev_handle pdev, + u_int16_t peer_num, + struct rate_report_t *peer_link_status) +{ + return; +} +#endif + + +#ifdef FEATURE_HL_GROUP_CREDIT_FLOW_CONTROL + +/** + * ol_txrx_update_tx_queue_groups() - update vdev tx queue group if + * vdev id mask and ac mask is not matching + * @pdev: the data physical device + * @group_id: TXQ group id + * @credit: TXQ group credit count + * @absolute: TXQ group absolute + * @vdev_id_mask: TXQ vdev group id mask + * @ac_mask: TQX access category mask + * + * Return: None + */ +void +ol_txrx_update_tx_queue_groups( + ol_txrx_pdev_handle pdev, + u_int8_t group_id, + int32_t credit, + u_int8_t absolute, + u_int32_t vdev_id_mask, + u_int32_t ac_mask +); + +/** + * ol_tx_desc_update_group_credit() - update group credits for txq group + * @pdev: the data physical device + * @tx_desc_id: desc id of tx completion message + * @credit: number of credits to update + * @absolute: absolute value + * @status: tx completion message status + * + * Return: None + */ +void +ol_tx_desc_update_group_credit( + ol_txrx_pdev_handle pdev, + u_int16_t tx_desc_id, + int credit, u_int8_t absolute, enum htt_tx_status status); + +#ifdef DEBUG_HL_LOGGING + +/** + * ol_tx_update_group_credit_stats() - update group credits stats for txq groups + * @pdev: the data physical device + * + * Return: None + */ +void +ol_tx_update_group_credit_stats(ol_txrx_pdev_handle pdev); + +/** + * ol_tx_dump_group_credit_stats() - dump group credits stats for txq groups + * @pdev: the data physical device + * + * Return: None + */ +void +ol_tx_dump_group_credit_stats(ol_txrx_pdev_handle pdev); + +/** + * ol_tx_clear_group_credit_stats() - clear group credits stats for txq groups + * @pdev: the data physical device + * + * Return: None + */ +void +ol_tx_clear_group_credit_stats(ol_txrx_pdev_handle pdev); +#else + +static inline void ol_tx_update_group_credit_stats(ol_txrx_pdev_handle pdev) +{ + return; +} + +static inline void ol_tx_dump_group_credit_stats(ol_txrx_pdev_handle pdev) +{ + return; +} + +static inline void ol_tx_clear_group_credit_stats(ol_txrx_pdev_handle pdev) +{ + return; +} +#endif + +#else +static inline void +ol_tx_desc_update_group_credit( + ol_txrx_pdev_handle pdev, + u_int16_t tx_desc_id, + int credit, u_int8_t absolute, enum htt_tx_status status) +{ + return; +} +#endif + +/** + * @brief Init the total amount of target credit. + * @details + * + * @param pdev - the data physical device that sent the tx frames + * @param credit_delta - how much to increment the target's tx credit by + */ +void ol_tx_target_credit_init(struct ol_txrx_pdev_t *pdev, int credit_delta); + +/** + * @brief Process a tx completion message for a single MSDU. + * @details + * The ol_tx_single_completion_handler function performs the same tx + * completion processing as the ol_tx_completion_handler, but for a + * single frame. + * ol_tx_completion_handler is optimized to handle batch completions + * as efficiently as possible; in contrast ol_tx_single_completion_handler + * handles single frames as simply and generally as possible. + * Thus, this ol_tx_single_completion_handler function is suitable for + * intermittent usage, such as for tx mgmt frames. + * + * @param pdev - the data physical device that sent the tx frames + * @param status - whether transmission was successful + * @param tx_msdu_id - ID of the frame which completed transmission + */ +void +ol_tx_single_completion_handler(ol_txrx_pdev_handle pdev, + enum htt_tx_status status, uint16_t tx_desc_id); + +/** + * @brief Update the amount of target credit. + * @details + * When the target finishes with an old transmit frame, it can use the + * space that was occupied by the old tx frame to store a new tx frame. + * This function is used to inform the txrx layer, where the HL tx download + * scheduler resides, about such updates to the target's tx credit. + * This credit update is done explicitly, rather than having the txrx layer + * update the credit count itself inside the ol_tx_completion handler + * function. This provides HTT with the flexibility to limit the rate of + * downloads from the TXRX layer's download scheduler, by controlling how + * much credit the download scheduler gets, and also provides the flexibility + * to account for a change in the tx memory pool size within the target. + * This function is only used for HL systems; in LL systems, each tx frame + * is assumed to use exactly one credit (for its target-side tx descriptor), + * and any rate limiting is managed within the target. + * + * @param pdev - the data physical device that sent the tx frames + * @param credit_delta - how much to increment the target's tx credit by + */ +void ol_tx_target_credit_update(struct ol_txrx_pdev_t *pdev, int credit_delta); + +/** + * @brief Process an rx indication message sent by the target. + * @details + * The target sends a rx indication message to the host as a + * notification that there are new rx frames available for the + * host to process. + * The HTT host layer locates the rx descriptors and rx frames + * associated with the indication, and calls this function to + * invoke the rx data processing on the new frames. + * (For LL, the rx descriptors and frames are delivered directly + * to the host via MAC DMA, while for HL the rx descriptor and + * frame for individual frames are combined with the rx indication + * message.) + * All MPDUs referenced by a rx indication message belong to the + * same peer-TID. + * + * @param pdev - the data physical device that received the frames + * (registered with HTT as a context pointer during attach time) + * @param rx_ind_msg - the network buffer holding the rx indication message + * (For HL, this netbuf also holds the rx desc and rx payload, but + * the data SW is agnostic to whether the desc and payload are + * piggybacked with the rx indication message.) + * @param peer_id - which peer sent this rx data + * @param tid - what (extended) traffic type the rx data is + * @param num_mpdu_ranges - how many ranges of MPDUs does the message describe. + * Each MPDU within the range has the same rx status. + */ +void +ol_rx_indication_handler(ol_txrx_pdev_handle pdev, + qdf_nbuf_t rx_ind_msg, + uint16_t peer_id, uint8_t tid, int num_mpdu_ranges); + +/** + * @brief Process an rx fragment indication message sent by the target. + * @details + * The target sends a rx fragment indication message to the host as a + * notification that there are new rx fragment available for the + * host to process. + * The HTT host layer locates the rx descriptors and rx fragment + * associated with the indication, and calls this function to + * invoke the rx fragment data processing on the new fragment. + * + * @param pdev - the data physical device that received the frames + * (registered with HTT as a context pointer during attach time) + * @param rx_frag_ind_msg - the network buffer holding the rx fragment indication message + * @param peer_id - which peer sent this rx data + * @param tid - what (extended) traffic type the rx data is + */ +void ol_rx_frag_indication_handler(ol_txrx_pdev_handle pdev, + qdf_nbuf_t rx_frag_ind_msg, + uint16_t peer_id, uint8_t tid); + +/** + * @brief Process rx offload deliver indication message sent by the target. + * @details + * When the target exits offload mode, target delivers packets that it has + * held in its memory to the host using this message. + * Low latency case: + * The message contains the number of MSDUs that are being delivered by the + * target to the host. The packet itself resides in host ring along with some + * metadata describing the peer id, vdev id, tid, FW desc and length of + * the packet being delivered. + * Hight letency case: + * The message itself contains the payload of the MSDU being delivered by + * the target to the host. The message also contains meta data describing + * the packet such as peer id, vdev id, tid, FW desc and length of the packet + * being delivered. Refer to htt.h for the exact structure of the message. + * @param pdev - the data physical device that received the frame. + * @param msg - offload deliver indication message + * @param msdu_cnt - number of MSDUs being delivred. + */ +void +ol_rx_offload_deliver_ind_handler(ol_txrx_pdev_handle pdev, + qdf_nbuf_t msg, int msdu_cnt); + +/** + * @brief Process a peer map message sent by the target. + * @details + * Each time the target allocates a new peer ID, it will inform the + * host via the "peer map" message. This function processes that + * message. The host data SW looks for a peer object whose MAC address + * matches the MAC address specified in the peer map message, and then + * sets up a mapping between the peer ID specified in the message and + * the peer object that was found. + * + * @param pdev - data physical device handle + * (registered with HTT as a context pointer during attach time) + * @param peer_id - ID generated by the target to refer to the peer in question + * The target may create multiple IDs for a single peer. + * @param vdev_id - Reference to the virtual device the peer is associated with + * @param peer_mac_addr - MAC address of the peer in question + * @param tx_ready - whether transmits to this peer can be done already, or + * need to wait for a call to peer_tx_ready (only applies to HL systems) + */ +void +ol_rx_peer_map_handler(ol_txrx_pdev_handle pdev, + uint16_t peer_id, + uint8_t vdev_id, uint8_t *peer_mac_addr, int tx_ready); + +/** + * @brief notify the host that the target is ready to transmit to a new peer. + * @details + * Some targets can immediately accept tx frames for a new peer, as soon as + * the peer's association completes. Other target need a short setup time + * before they are ready to accept tx frames for the new peer. + * If the target needs time for setup, it will provide a peer_tx_ready + * message when it is done with the setup. This function forwards this + * notification from the target to the host's tx queue manager. + * This function only applies for HL systems, in which the host determines + * which peer a given tx frame is for, and stores the tx frames in queues. + * + * @param pdev - data physical device handle + * (registered with HTT as a context pointer during attach time) + * @param peer_id - ID for the new peer which can now accept tx frames + */ +void ol_txrx_peer_tx_ready_handler(ol_txrx_pdev_handle pdev, uint16_t peer_id); + +/** + * @brief Process a peer unmap message sent by the target. + * @details + * Each time the target frees a peer ID, it will inform the host via the + * "peer unmap" message. This function processes that message. + * The host data SW uses the peer ID from the message to find the peer + * object from peer_map[peer_id], then invalidates peer_map[peer_id] + * (by setting it to NULL), and checks whether there are any remaining + * references to the peer object. If not, the function deletes the + * peer object. + * + * @param pdev - data physical device handle + * (registered with HTT as a context pointer during attach time) + * @param peer_id - ID that is being freed. + * The target may create multiple IDs for a single peer. + */ +void ol_rx_peer_unmap_handler(ol_txrx_pdev_handle pdev, uint16_t peer_id); + +/** + * @brief Process a security indication message sent by the target. + * @details + * When a key is assigned to a peer, the target will inform the host + * with a security indication message. + * The host remembers the security type, and infers whether a rx PN + * check is needed. + * + * @param pdev - data physical device handle + * @param peer_id - which peer the security info is for + * @param sec_type - which type of security / key the peer is using + * @param is_unicast - whether security spec is for a unicast or multicast key + * @param michael_key - key used for TKIP MIC (if sec_type == TKIP) + * @param rx_pn - RSC used for WAPI PN replay check (if sec_type == WAPI) + */ +void +ol_rx_sec_ind_handler(ol_txrx_pdev_handle pdev, + uint16_t peer_id, + enum htt_sec_type sec_type, + int is_unicast, uint32_t *michael_key, uint32_t *rx_pn); + +/** + * @brief Process an ADDBA message sent by the target. + * @details + * When the target notifies the host of an ADDBA event for a specified + * peer-TID, the host will set up the rx reordering state for the peer-TID. + * Specifically, the host will create a rx reordering array whose length + * is based on the window size specified in the ADDBA. + * + * @param pdev - data physical device handle + * (registered with HTT as a context pointer during attach time) + * @param peer_id - which peer the ADDBA event is for + * @param tid - which traffic ID within the peer the ADDBA event is for + * @param win_sz - how many sequence numbers are in the ARQ block ack window + * set up by the ADDBA event + * @param start_seq_num - the initial value of the sequence number during the + * block ack agreement, as specified by the ADDBA request. + * @param failed - indicate whether the target's ADDBA setup succeeded: + * 0 -> success, 1 -> fail + */ +void +ol_rx_addba_handler(ol_txrx_pdev_handle pdev, + uint16_t peer_id, + uint8_t tid, + uint8_t win_sz, uint16_t start_seq_num, uint8_t failed); + +/** + * @brief Process a DELBA message sent by the target. + * @details + * When the target notifies the host of a DELBA event for a specified + * peer-TID, the host will clean up the rx reordering state for the peer-TID. + * Specifically, the host will remove the rx reordering array, and will + * set the reorder window size to be 1 (stop and go ARQ). + * + * @param pdev - data physical device handle + * (registered with HTT as a context pointer during attach time) + * @param peer_id - which peer the ADDBA event is for + * @param tid - which traffic ID within the peer the ADDBA event is for + */ +void +ol_rx_delba_handler(ol_txrx_pdev_handle pdev, uint16_t peer_id, uint8_t tid); + +enum htt_rx_flush_action { + htt_rx_flush_release, + htt_rx_flush_discard, +}; + +/** + * @brief Process a rx reorder flush message sent by the target. + * @details + * The target's rx reorder logic can send a flush indication to the + * host's rx reorder buffering either as a flush IE within a rx + * indication message, or as a standalone rx reorder flush message. + * This ol_rx_flush_handler function processes the standalone rx + * reorder flush message from the target. + * The flush message specifies a range of sequence numbers whose + * rx frames are flushed. + * Some sequence numbers within the specified range may not have + * rx frames; the host needs to check for each sequence number in + * the specified range whether there are rx frames held for that + * sequence number. + * + * @param pdev - data physical device handle + * (registered with HTT as a context pointer during attach time) + * @param peer_id - which peer's rx data is being flushed + * @param tid - which traffic ID within the peer has the rx data being flushed + * @param seq_num_start - Which sequence number within the rx reordering + * buffer the flushing should start with. + * This is the LSBs of the 802.11 sequence number. + * This sequence number is masked with the rounded-to-power-of-two + * window size to generate a reorder buffer index. + * The flush includes this initial sequence number. + * @param seq_num_end - Which sequence number within the rx reordering + * buffer the flushing should stop at. + * This is the LSBs of the 802.11 sequence number. + * This sequence number is masked with the rounded-to-power-of-two + * window size to generate a reorder buffer index. + * The flush excludes this final sequence number. + * @param action - whether to release or discard the rx frames + */ +void +ol_rx_flush_handler(ol_txrx_pdev_handle pdev, + uint16_t peer_id, + uint8_t tid, + uint16_t seq_num_start, + uint16_t seq_num_end, enum htt_rx_flush_action action); + +/** + * @brief Process a rx pn indication message + * @details + * When the peer is configured to get PN checking done in target, + * the target instead of sending reorder flush/release messages + * sends PN indication messages which contain the start and end + * sequence numbers to be flushed/released along with the sequence + * numbers of MPDUs that failed the PN check in target. + * + * @param pdev - data physical device handle + * (registered with HTT as a context pointer during attach time) + * @param peer_id - which peer's rx data is being flushed + * @param tid - which traffic ID within the peer + * @param seq_num_start - Which sequence number within the rx reordering + * buffer to start with. + * This is the LSBs of the 802.11 sequence number. + * This sequence number is masked with the rounded-to-power-of-two + * window size to generate a reorder buffer index. + * This is the initial sequence number. + * @param seq_num_end - Which sequence number within the rx reordering + * buffer to stop at. + * This is the LSBs of the 802.11 sequence number. + * This sequence number is masked with the rounded-to-power-of-two + * window size to generate a reorder buffer index. + * The processing stops right before this sequence number + * @param pn_ie_cnt - Indicates the number of PN information elements. + * @param pn_ie - Pointer to the array of PN information elements. Each + * PN information element contains the LSBs of the 802.11 sequence number + * of the MPDU that failed the PN checking in target. + */ +void +ol_rx_pn_ind_handler(ol_txrx_pdev_handle pdev, + uint16_t peer_id, + uint8_t tid, + int seq_num_start, + int seq_num_end, uint8_t pn_ie_cnt, uint8_t *pn_ie); + +/** + * @brief Process a stats message sent by the target. + * @details + * The host can request target for stats. + * The target sends the stats to the host via a confirmation message. + * This ol_txrx_fw_stats_handler function processes the confirmation message. + * Currently, this processing consists of copying the stats from the message + * buffer into the txrx pdev object, and waking the sleeping host context + * that requested the stats. + * + * @param pdev - data physical device handle + * (registered with HTT as a context pointer during attach time) + * @param cookie - Value echoed from the cookie in the stats request + * message. This allows the host SW to find the stats request object. + * (Currently, this cookie is unused.) + * @param stats_info_list - stats confirmation message contents, containing + * a list of the stats requested from the target + */ +void +ol_txrx_fw_stats_handler(ol_txrx_pdev_handle pdev, + uint64_t cookie, uint8_t *stats_info_list); + +/** + * @brief Process a tx inspect message sent by the target. + * @details: + * TODO: update + * This tx inspect message indicates via the descriptor ID + * which tx frames are to be inspected by host. The host + * re-injects the packet back to the host for a number of + * cases. + * + * @param pdev - the data physical device that sent the tx frames + * (registered with HTT as a context pointer during attach time) + * @param num_msdus - how many MSDUs are referenced by the tx completion + * message + * @param tx_msdu_id_iterator - abstract method of finding the IDs for the + * individual MSDUs referenced by the tx completion message, via the + * htt_tx_compl_desc_id API function + */ +void +ol_tx_inspect_handler(ol_txrx_pdev_handle pdev, + int num_msdus, void *tx_desc_id_iterator); + +/** + * @brief Get the UAPSD mask. + * @details + * This function will return the UAPSD TID mask. + * + * @param txrx_pdev - pointer to the txrx pdev object + * @param peer_id - PeerID. + * @return uapsd mask value + */ +uint8_t +ol_txrx_peer_uapsdmask_get(struct ol_txrx_pdev_t *txrx_pdev, uint16_t peer_id); + +/** + * @brief Get the Qos Capable. + * @details + * This function will return the txrx_peer qos_capable. + * + * @param txrx_pdev - pointer to the txrx pdev object + * @param peer_id - PeerID. + * @return qos_capable value + */ +uint8_t +ol_txrx_peer_qoscapable_get(struct ol_txrx_pdev_t *txrx_pdev, uint16_t peer_id); + +#ifndef CONFIG_HL_SUPPORT +/** + * @brief Process an rx indication message sent by the target. + * @details + * The target sends a rx indication message to the host as a + * notification that there are new rx frames available for the + * host to process. + * The HTT host layer locates the rx descriptors and rx frames + * associated with the indication, and calls this function to + * invoke the rx data processing on the new frames. + * All MPDUs referenced by a rx indication message belong to the + * same peer-TID. The frames indicated have been re-ordered by + * the target. + * + * @param pdev - the data physical device that received the frames + * (registered with HTT as a context pointer during attach time) + * @param rx_ind_msg - the network buffer holding the rx indication message + * @param peer_id - which peer sent this rx data + * @param tid - what (extended) traffic type the rx data is + * @param is_offload - is this an offload indication? + */ +void +ol_rx_in_order_indication_handler(ol_txrx_pdev_handle pdev, + qdf_nbuf_t rx_ind_msg, + uint16_t peer_id, + uint8_t tid, uint8_t is_offload); +#endif + +#ifdef FEATURE_HL_GROUP_CREDIT_FLOW_CONTROL + +/** + * ol_tx_get_max_tx_groups_supported() - get max TCQ groups supported + * @pdev: the data physical device that received the frames + * + * Return: number of max groups supported + */ +u_int32_t ol_tx_get_max_tx_groups_supported(struct ol_txrx_pdev_t *pdev); +#else + +static inline u_int32_t +ol_tx_get_max_tx_groups_supported(struct ol_txrx_pdev_t *pdev) +{ + return 0; +} +#endif + +#endif /* _OL_TXRX_HTT_API__H_ */ diff --git a/drivers/staging/qcacld-3.0/core/dp/ol/inc/ol_txrx_osif_api.h b/drivers/staging/qcacld-3.0/core/dp/ol/inc/ol_txrx_osif_api.h new file mode 100644 index 0000000000000000000000000000000000000000..b999b5e03fbdea1d4a6bd581a7a6b16561edafe0 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/dp/ol/inc/ol_txrx_osif_api.h @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2012, 2014-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * @file ol_txrx_osif_api.h + * @brief Define the host data API functions called by the host OS shim SW. + */ +#ifndef _OL_TXRX_OSIF_API__H_ +#define _OL_TXRX_OSIF_API__H_ + +#include /* qdf_nbuf_t */ +#include "cds_sched.h" +#include "ol_txrx_ctrl_api.h" +#include + +/** + * struct ol_rx_cached_buf - rx cached buffer + * @list: linked list + * @buf: skb buffer + */ +struct ol_rx_cached_buf { + struct list_head list; + qdf_nbuf_t buf; +}; + +struct txrx_rx_metainfo; + +typedef QDF_STATUS (*ol_rx_callback_fp)(void *p_cds_gctx, + qdf_nbuf_t pDataBuff, + uint8_t ucSTAId); + +/** + * @brief Divide a jumbo TCP frame into smaller segments. + * @details + * For efficiency, the protocol stack above the WLAN driver may operate + * on jumbo tx frames, which are larger than the 802.11 MTU. + * The OSIF SW uses this txrx API function to divide the jumbo tx TCP frame + * into a series of segment frames. + * The segments are created as clones of the input jumbo frame. + * The txrx SW generates a new encapsulation header (ethernet + IP + TCP) + * for each of the output segment frames. The exact format of this header, + * e.g. 802.3 vs. Ethernet II, and IPv4 vs. IPv6, is chosen to match the + * header format of the input jumbo frame. + * The input jumbo frame is not modified. + * After the ol_txrx_osif_tso_segment returns, the OSIF SW needs to perform + * DMA mapping on each of the segment network buffers, and also needs to + * + * @param txrx_vdev - which virtual device will transmit the TSO segments + * @param max_seg_payload_bytes - the maximum size for the TCP payload of + * each segment frame. + * This does not include the ethernet + IP + TCP header sizes. + * @param jumbo_tcp_frame - jumbo frame which needs to be cloned+segmented + * @return + * NULL if the segmentation fails, - OR - + * a NULL-terminated list of segment network buffers + */ +qdf_nbuf_t ol_txrx_osif_tso_segment(ol_txrx_vdev_handle txrx_vdev, + int max_seg_payload_bytes, + qdf_nbuf_t jumbo_tcp_frame); + +qdf_nbuf_t ol_tx_data(ol_txrx_vdev_handle data_vdev, qdf_nbuf_t skb); + +void ol_rx_data_process(struct ol_txrx_peer_t *peer, + qdf_nbuf_t rx_buf_list); + +void ol_txrx_flush_rx_frames(struct ol_txrx_peer_t *peer, + bool drop); +/** + * ol_txrx_flush_cache_rx_queue() - flush cache rx queue frame + * + * Return: None + */ +void ol_txrx_flush_cache_rx_queue(void); + +#endif /* _OL_TXRX_OSIF_API__H_ */ diff --git a/drivers/staging/qcacld-3.0/core/dp/ol/inc/ol_txrx_stats.h b/drivers/staging/qcacld-3.0/core/dp/ol/inc/ol_txrx_stats.h new file mode 100644 index 0000000000000000000000000000000000000000..c143ae34f9b4711b639ddaf47be9c7dbfab6ff2c --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/dp/ol/inc/ol_txrx_stats.h @@ -0,0 +1,182 @@ +/* + * Copyright (c) 2012, 2014-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * @file ol_txrx_status.h + * @brief Functions provided for visibility and debugging. + * NOTE: This file is used by both kernel driver SW and userspace SW. + * Thus, do not reference use any kernel header files or defs in this file! + */ +#ifndef _OL_TXRX_STATS__H_ +#define _OL_TXRX_STATS__H_ + +#include /* uint64_t */ + + + +struct ol_txrx_stats_elem { + uint64_t pkts; + uint64_t bytes; +}; + +#define NUM_MAX_TSO_SEGS 4 +#define NUM_MAX_TSO_SEGS_MASK (NUM_MAX_TSO_SEGS - 1) + +#define NUM_MAX_TSO_MSDUS 32 +#define NUM_MAX_TSO_MSDUS_MASK (NUM_MAX_TSO_MSDUS - 1) + +struct ol_txrx_stats_tso_msdu { + struct qdf_tso_seg_t tso_segs[NUM_MAX_TSO_SEGS]; + uint8_t num_seg; + uint8_t tso_seg_idx; + uint32_t total_len; + uint32_t gso_size; + uint8_t nr_frags; +}; + +struct ol_txrx_stats_tso_info { + struct ol_txrx_stats_tso_msdu tso_msdu_info[NUM_MAX_TSO_MSDUS]; + uint32_t tso_msdu_idx; +}; + +/** + * @brief data stats published by the host txrx layer + * + * ------------------------- + * + * TX + * + */ +struct ol_txrx_stats_tx_dropped { + /* MSDUs that the host did not accept */ + struct ol_txrx_stats_elem host_reject; + /* MSDUs which could not be downloaded to the target */ + struct ol_txrx_stats_elem download_fail; + /* MSDUs which the target discarded + (lack of memory or old age) */ + struct ol_txrx_stats_elem target_discard; + /* MSDUs which the target sent but + couldn't get an ack for */ + struct ol_txrx_stats_elem no_ack; +}; + +struct ol_txrx_tso_histogram { + uint32_t pkts_1; + uint32_t pkts_2_5; + uint32_t pkts_6_10; + uint32_t pkts_11_15; + uint32_t pkts_16_20; + uint32_t pkts_20_plus; +}; + +struct ol_txrx_stats_tx_histogram { + uint32_t pkts_1; + uint32_t pkts_2_10; + uint32_t pkts_11_20; + uint32_t pkts_21_30; + uint32_t pkts_31_40; + uint32_t pkts_41_50; + uint32_t pkts_51_60; + uint32_t pkts_61_plus; +}; +struct ol_txrx_stats_tx_tso { + struct ol_txrx_stats_elem tso_pkts; +#if defined(FEATURE_TSO) + struct ol_txrx_stats_tso_info tso_info; + struct ol_txrx_tso_histogram tso_hist; + qdf_spinlock_t tso_stats_lock; +#endif +}; + +struct ol_txrx_stats_tx { + /* MSDUs given to the txrx layer by the management stack */ + struct ol_txrx_stats_elem mgmt; + /* MSDUs received from the stack */ + struct ol_txrx_stats_elem from_stack; + /* MSDUs successfully sent across the WLAN */ + struct ol_txrx_stats_elem delivered; + struct ol_txrx_stats_tx_dropped dropped; + /* contains information of packets recevied per tx completion*/ + struct ol_txrx_stats_tx_histogram comp_histogram; + /* TSO (TCP segmentation offload) information */ + struct ol_txrx_stats_tx_tso tso; +}; + +/* + * RX + */ +struct ol_txrx_stats_rx_histogram { + uint32_t pkts_1; + uint32_t pkts_2_10; + uint32_t pkts_11_20; + uint32_t pkts_21_30; + uint32_t pkts_31_40; + uint32_t pkts_41_50; + uint32_t pkts_51_60; + uint32_t pkts_61_plus; +}; +struct ol_txrx_stats_rx_ibss_fwd { + /* MSDUs forwarded to network stack */ + u_int32_t packets_stack; + /* MSDUs forwarded from the rx path to the tx path */ + u_int32_t packets_fwd; + /* MSDUs forwarded to stack and tx path */ + u_int32_t packets_stack_n_fwd; +}; +struct ol_txrx_stats_rx { + /* MSDUs given to the OS shim */ + struct ol_txrx_stats_elem delivered; + struct ol_txrx_stats_elem dropped_err; + struct ol_txrx_stats_elem dropped_mic_err; + struct ol_txrx_stats_elem dropped_peer_invalid; + struct ol_txrx_stats_rx_ibss_fwd intra_bss_fwd; + struct ol_txrx_stats_rx_histogram rx_ind_histogram; + uint32_t msdus_with_frag_ind; + uint32_t msdus_with_offload_ind; +}; +struct ol_txrx_stats { + struct ol_txrx_stats_tx tx; + struct ol_txrx_stats_rx rx; +}; + +/* + * Structure to consolidate host stats + */ +struct ieee80211req_ol_ath_host_stats { + struct ol_txrx_stats txrx_stats; + struct { + int pkt_q_fail_count; + int pkt_q_empty_count; + int send_q_empty_count; + } htc; + struct { + int pipe_no_resrc_count; + int ce_ring_delta_fail_count; + } hif; +}; + +#endif /* _OL_TXRX_STATS__H_ */ diff --git a/drivers/staging/qcacld-3.0/core/dp/ol/inc/ol_vowext_dbg_defs.h b/drivers/staging/qcacld-3.0/core/dp/ol/inc/ol_vowext_dbg_defs.h new file mode 100644 index 0000000000000000000000000000000000000000..4a9d3db50014baf14fe2582d9d5f3d28f6623800 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/dp/ol/inc/ol_vowext_dbg_defs.h @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2012, 2014-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef _VOW_DEFINES__H_ +#define _VOW_DEFINES__H_ + +#define UDP_CKSUM_OFFSET 40 /* UDP check sum offset in network buffer */ +#define RTP_HDR_OFFSET 42 /* RTP header offset in network buffer */ +#define EXT_HDR_OFFSET 54 /* Extension header offset in network buffer */ +#define UDP_PDU_RTP_EXT 0x90 /* ((2 << 6) | (1 << 4)) RTP V2 + X bit */ +#define IP_VER4_N_NO_EXTRA_HEADERS 0x45 +#define IPERF3_DATA_OFFSET 12 /* iperf3 data offset from EXT_HDR_OFFSET */ +#define HAL_RX_40 0x08 /* 40 Mhz */ +#define HAL_RX_GI 0x04 /* full gi */ + +struct vow_extstats { + uint8_t rx_rssi_ctl0; /* control channel chain0 rssi */ + uint8_t rx_rssi_ctl1; /* control channel chain1 rssi */ + uint8_t rx_rssi_ctl2; /* control channel chain2 rssi */ + uint8_t rx_rssi_ext0; /* extention channel chain0 rssi */ + uint8_t rx_rssi_ext1; /* extention channel chain1 rssi */ + uint8_t rx_rssi_ext2; /* extention channel chain2 rssi */ + uint8_t rx_rssi_comb; /* combined RSSI value */ + uint8_t rx_bw; /* Band width 0-20, 1-40, 2-80 */ + uint8_t rx_sgi; /* Guard interval, 0-Long GI, 1-Short GI */ + uint8_t rx_nss; /* Number of spatial streams */ + uint8_t rx_mcs; /* Rate MCS value */ + uint8_t rx_ratecode; /* Hardware rate code */ + uint8_t rx_rs_flags; /* Recieve misc flags */ + uint8_t rx_moreaggr; /* 0 - non aggr frame */ + uint32_t rx_macTs; /* Time stamp */ + uint16_t rx_seqno; /* rx sequence number */ +}; + +/** + * @brief populates vow ext stats in given network buffer. + * @param msdu - network buffer handle + * @param pdev - handle to htt dev. + */ +void ol_ath_add_vow_extstats(htt_pdev_handle pdev, qdf_nbuf_t msdu); + +#endif /* _VOW_DEFINES__H_ */ diff --git a/drivers/staging/qcacld-3.0/core/dp/txrx/ipv6_defs.h b/drivers/staging/qcacld-3.0/core/dp/txrx/ipv6_defs.h new file mode 100644 index 0000000000000000000000000000000000000000..c1c52babe485b495c7697f9783477c83bcdda02e --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/dp/txrx/ipv6_defs.h @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2012-2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef _IPV6__H_ +#define _IPV6__H_ + +#if defined(ATH_TARGET) +#include /* A_UINT8 */ +#else +#include /* A_UINT8 */ +#endif + +/* utilities for converting between network byte order and native endianness */ +#ifndef BYTESWAP32 +#define BYTESWAP32(x) \ + ((((x) & 0x000000ff) << 24) /* byte 0 -> byte 3 */ | \ + (((x) & 0x0000ff00) << 8) /* byte 1 -> byte 2 */ | \ + (((x) & 0x00ff0000) >> 8) /* byte 2 -> byte 1 */ | \ + (((x) & 0xff000000) >> 24) /* byte 3 -> byte 0 */) +#endif /* BYTESWAP32 */ + +#ifndef BE_TO_CPU32 +#if defined(ATH_TARGET) +/* assume target is little-endian */ +#define BE_TO_CPU32(x) BYTESWAP32(x) +#else +#ifdef BIG_ENDIAN_HOST +#define BE_TO_CPU32(x) (x) +#else +#define BE_TO_CPU32(x) BYTESWAP32(x) +#endif +#endif +#endif /* BE_TO_CPU32 */ + +/* IPv6 header definition */ + +#define IPV6_ADDR_LEN 4 /* bytes */ +struct ipv6_hdr_t { + A_UINT32 ver_tclass_flowlabel; /* version, traffic class, and flow label */ + A_UINT8 pyld_len[2]; /* payload length */ + A_UINT8 next_hdr; + A_UINT8 hop_limit; + A_UINT8 src_addr[IPV6_ADDR_LEN]; + A_UINT8 dst_addr[IPV6_ADDR_LEN]; +}; + +#define IPV6_HDR_LEN (sizeof(struct ipv6_hdr_t)) +#define IPV6_HDR_OFFSET_NEXT_HDR (offsetof(struct ipv6_hdr_t, next_hdr)) +#define IPV6_HDR_OFFSET_DST_ADDR (offsetof(struct ipv6_hdr_t, dst_addr[0])) + +/* IPv6 header field access macros */ + +#define IPV6_HDR_VERSION_M 0xF0000000 +#define IPV6_HDR_VERSION_S 28 + +#define IPV6_HDR_TRAFFIC_CLASS_M 0x0FF00000 +#define IPV6_HDR_TRAFFIC_CLASS_S 20 + +#define IPV6_HDR_FLOW_LABEL_M 0x000FFFFF +#define IPV6_HDR_FLOW_LABEL_S 0 + +static inline A_UINT8 ipv6_version(struct ipv6_hdr_t *ipv6_hdr) +{ + return + (BE_TO_CPU32(ipv6_hdr->ver_tclass_flowlabel) & + IPV6_HDR_VERSION_M) >> IPV6_HDR_VERSION_S; +} + +static inline A_UINT8 ipv6_traffic_class(struct ipv6_hdr_t *ipv6_hdr) +{ + return + (A_UINT8) ((BE_TO_CPU32(ipv6_hdr->ver_tclass_flowlabel) & + IPV6_HDR_TRAFFIC_CLASS_M) >> IPV6_HDR_TRAFFIC_CLASS_S); +} + +static inline A_UINT32 ipv6_flow_label(struct ipv6_hdr_t *ipv6_hdr) +{ + return + (BE_TO_CPU32(ipv6_hdr->ver_tclass_flowlabel) & + IPV6_HDR_FLOW_LABEL_M) >> IPV6_HDR_FLOW_LABEL_S; +} + +#endif /* _IPV6__H_ */ diff --git a/drivers/staging/qcacld-3.0/core/dp/txrx/ol_cfg.c b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_cfg.c new file mode 100644 index 0000000000000000000000000000000000000000..87ab86ca5f46288e604488379f417106cc021ddf --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_cfg.c @@ -0,0 +1,525 @@ +/* + * Copyright (c) 2011-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#include +#include +#include + +unsigned int vow_config = 0; + +#ifdef QCA_LL_TX_FLOW_CONTROL_V2 +/** + * ol_tx_set_flow_control_parameters() - set flow control parameters + * @cfg_ctx: cfg context + * @cfg_param: cfg parameters + * + * Return: none + */ +static +void ol_tx_set_flow_control_parameters(struct txrx_pdev_cfg_t *cfg_ctx, + struct txrx_pdev_cfg_param_t cfg_param) +{ + cfg_ctx->tx_flow_start_queue_offset = + cfg_param.tx_flow_start_queue_offset; + cfg_ctx->tx_flow_stop_queue_th = + cfg_param.tx_flow_stop_queue_th; +} +#else +static +void ol_tx_set_flow_control_parameters(struct txrx_pdev_cfg_t *cfg_ctx, + struct txrx_pdev_cfg_param_t cfg_param) +{ + return; +} +#endif + +#ifdef CONFIG_HL_SUPPORT + +/** + * ol_pdev_cfg_param_update() - assign download size of tx frame for txrx + * pdev that will be used across datapath + * @cfg_ctx: ptr to config parameter for txrx pdev + * + * Return: None + */ +static inline +void ol_pdev_cfg_param_update(struct txrx_pdev_cfg_t *cfg_ctx) +{ + cfg_ctx->is_high_latency = 1; + /* 802.1Q and SNAP / LLC headers are accounted for elsewhere */ + cfg_ctx->tx_download_size = 1500; + cfg_ctx->tx_free_at_download = 0; +} +#else + +static inline +void ol_pdev_cfg_param_update(struct txrx_pdev_cfg_t *cfg_ctx) +{ + /* + * Need to change HTT_LL_TX_HDR_SIZE_IP accordingly. + * Include payload, up to the end of UDP header for IPv4 case + */ + cfg_ctx->tx_download_size = 16; +} +#endif + +#if CFG_TGT_DEFAULT_RX_SKIP_DEFRAG_TIMEOUT_DUP_DETECTION_CHECK +static inline +uint8_t ol_defrag_timeout_check(void) +{ + return 1; +} +#else +static inline +uint8_t ol_defrag_timeout_check(void) +{ + return 0; +} +#endif + +/* FIX THIS - + * For now, all these configuration parameters are hardcoded. + * Many of these should actually be determined dynamically instead. + */ + +/** + * ol_pdev_cfg_attach - setup configuration parameters + * + *@osdev - OS handle needed as an argument for some OS primitives + *@cfg_param - configuration parameters + * + * Allocation configuration context that will be used across data path + * + * Return: the control device object + */ + +ol_pdev_handle ol_pdev_cfg_attach(qdf_device_t osdev, + struct txrx_pdev_cfg_param_t cfg_param) +{ + struct txrx_pdev_cfg_t *cfg_ctx; + int i; + + cfg_ctx = qdf_mem_malloc(sizeof(*cfg_ctx)); + if (!cfg_ctx) { + printk(KERN_ERR "cfg ctx allocation failed\n"); + return NULL; + } + + ol_pdev_cfg_param_update(cfg_ctx); + + /* temporarily diabled PN check for Riva/Pronto */ + cfg_ctx->rx_pn_check = 1; + cfg_ctx->defrag_timeout_check = ol_defrag_timeout_check(); + cfg_ctx->max_peer_id = 511; + cfg_ctx->max_vdev = CFG_TGT_NUM_VDEV; + cfg_ctx->pn_rx_fwd_check = 1; + cfg_ctx->frame_type = wlan_frm_fmt_802_3; + cfg_ctx->max_thruput_mbps = 800; + cfg_ctx->max_nbuf_frags = 1; + cfg_ctx->vow_config = vow_config; + cfg_ctx->target_tx_credit = CFG_TGT_NUM_MSDU_DESC; + cfg_ctx->throttle_period_ms = 40; + cfg_ctx->dutycycle_level[0] = THROTTLE_DUTY_CYCLE_LEVEL0; + cfg_ctx->dutycycle_level[1] = THROTTLE_DUTY_CYCLE_LEVEL1; + cfg_ctx->dutycycle_level[2] = THROTTLE_DUTY_CYCLE_LEVEL2; + cfg_ctx->dutycycle_level[3] = THROTTLE_DUTY_CYCLE_LEVEL3; + cfg_ctx->rx_fwd_disabled = 0; + cfg_ctx->is_packet_log_enabled = 0; + cfg_ctx->is_full_reorder_offload = cfg_param.is_full_reorder_offload; + cfg_ctx->ipa_uc_rsc.uc_offload_enabled = + cfg_param.is_uc_offload_enabled; + cfg_ctx->ipa_uc_rsc.tx_max_buf_cnt = cfg_param.uc_tx_buffer_count; + cfg_ctx->ipa_uc_rsc.tx_buf_size = cfg_param.uc_tx_buffer_size; + cfg_ctx->ipa_uc_rsc.rx_ind_ring_size = + cfg_param.uc_rx_indication_ring_count; + cfg_ctx->ipa_uc_rsc.tx_partition_base = cfg_param.uc_tx_partition_base; + cfg_ctx->enable_rxthread = cfg_param.enable_rxthread; + cfg_ctx->ip_tcp_udp_checksum_offload = + cfg_param.ip_tcp_udp_checksum_offload; + cfg_ctx->ce_classify_enabled = cfg_param.ce_classify_enabled; + + ol_tx_set_flow_control_parameters(cfg_ctx, cfg_param); + + for (i = 0; i < OL_TX_NUM_WMM_AC; i++) { + cfg_ctx->ac_specs[i].wrr_skip_weight = + cfg_param.ac_specs[i].wrr_skip_weight; + cfg_ctx->ac_specs[i].credit_threshold = + cfg_param.ac_specs[i].credit_threshold; + cfg_ctx->ac_specs[i].send_limit = + cfg_param.ac_specs[i].send_limit; + cfg_ctx->ac_specs[i].credit_reserve = + cfg_param.ac_specs[i].credit_reserve; + cfg_ctx->ac_specs[i].discard_weight = + cfg_param.ac_specs[i].discard_weight; + } + + return (ol_pdev_handle) cfg_ctx; +} + +int ol_cfg_is_high_latency(ol_pdev_handle pdev) +{ + struct txrx_pdev_cfg_t *cfg = (struct txrx_pdev_cfg_t *)pdev; + return cfg->is_high_latency; +} + +int ol_cfg_max_peer_id(ol_pdev_handle pdev) +{ + struct txrx_pdev_cfg_t *cfg = (struct txrx_pdev_cfg_t *)pdev; + /* + * TBDXXX - this value must match the peer table + * size allocated in FW + */ + return cfg->max_peer_id; +} + +int ol_cfg_max_vdevs(ol_pdev_handle pdev) +{ + struct txrx_pdev_cfg_t *cfg = (struct txrx_pdev_cfg_t *)pdev; + return cfg->max_vdev; +} + +int ol_cfg_rx_pn_check(ol_pdev_handle pdev) +{ + struct txrx_pdev_cfg_t *cfg = (struct txrx_pdev_cfg_t *)pdev; + return cfg->rx_pn_check; +} + +int ol_cfg_rx_fwd_check(ol_pdev_handle pdev) +{ + struct txrx_pdev_cfg_t *cfg = (struct txrx_pdev_cfg_t *)pdev; + return cfg->pn_rx_fwd_check; +} + +/** + * ol_set_cfg_rx_fwd_disabled - set rx fwd disable/enable + * + * @pdev - handle to the physical device + * @disable_rx_fwd 1 -> no rx->tx forward -> rx->tx forward + * + * Choose whether to forward rx frames to tx (where applicable) within the + * WLAN driver, or to leave all forwarding up to the operating system. + * Currently only intra-bss fwd is supported. + * + */ +void ol_set_cfg_rx_fwd_disabled(ol_pdev_handle pdev, uint8_t disable_rx_fwd) +{ + struct txrx_pdev_cfg_t *cfg = (struct txrx_pdev_cfg_t *)pdev; + cfg->rx_fwd_disabled = disable_rx_fwd; +} + +/** + * ol_set_cfg_packet_log_enabled - Set packet log config in HTT + * config based on CFG ini configuration + * + * @pdev - handle to the physical device + * @val - 0 - disable, 1 - enable + */ +void ol_set_cfg_packet_log_enabled(ol_pdev_handle pdev, uint8_t val) +{ + struct txrx_pdev_cfg_t *cfg = (struct txrx_pdev_cfg_t *)pdev; + cfg->is_packet_log_enabled = val; +} + +uint8_t ol_cfg_is_packet_log_enabled(ol_pdev_handle pdev) +{ + struct txrx_pdev_cfg_t *cfg = (struct txrx_pdev_cfg_t *)pdev; + return cfg->is_packet_log_enabled; +} + +int ol_cfg_rx_fwd_disabled(ol_pdev_handle pdev) +{ +#if defined(ATHR_WIN_NWF) + /* for Windows, let the OS handle the forwarding */ + return 1; +#else + struct txrx_pdev_cfg_t *cfg = (struct txrx_pdev_cfg_t *)pdev; + return cfg->rx_fwd_disabled; +#endif +} + +int ol_cfg_rx_fwd_inter_bss(ol_pdev_handle pdev) +{ + struct txrx_pdev_cfg_t *cfg = (struct txrx_pdev_cfg_t *)pdev; + return cfg->rx_fwd_inter_bss; +} + +enum wlan_frm_fmt ol_cfg_frame_type(ol_pdev_handle pdev) +{ + struct txrx_pdev_cfg_t *cfg = (struct txrx_pdev_cfg_t *)pdev; + return cfg->frame_type; +} + +int ol_cfg_max_thruput_mbps(ol_pdev_handle pdev) +{ + struct txrx_pdev_cfg_t *cfg = (struct txrx_pdev_cfg_t *)pdev; + return cfg->max_thruput_mbps; +} + +int ol_cfg_netbuf_frags_max(ol_pdev_handle pdev) +{ + struct txrx_pdev_cfg_t *cfg = (struct txrx_pdev_cfg_t *)pdev; + return cfg->max_nbuf_frags; +} + +int ol_cfg_tx_free_at_download(ol_pdev_handle pdev) +{ + struct txrx_pdev_cfg_t *cfg = (struct txrx_pdev_cfg_t *)pdev; + return cfg->tx_free_at_download; +} + +void ol_cfg_set_tx_free_at_download(ol_pdev_handle pdev) +{ + struct txrx_pdev_cfg_t *cfg = (struct txrx_pdev_cfg_t *)pdev; + cfg->tx_free_at_download = 1; +} + + +#ifdef CONFIG_HL_SUPPORT +uint16_t ol_cfg_target_tx_credit(ol_pdev_handle pdev) +{ + struct txrx_pdev_cfg_t *cfg = (struct txrx_pdev_cfg_t *)pdev; + return cfg->target_tx_credit; +} +#else + +uint16_t ol_cfg_target_tx_credit(ol_pdev_handle pdev) +{ + struct txrx_pdev_cfg_t *cfg = (struct txrx_pdev_cfg_t *)pdev; + uint16_t rc; + uint16_t vow_max_sta = (cfg->vow_config & 0xffff0000) >> 16; + uint16_t vow_max_desc_persta = cfg->vow_config & 0x0000ffff; + + rc = (cfg->target_tx_credit + (vow_max_sta * vow_max_desc_persta)); + + return rc; +} +#endif + +int ol_cfg_tx_download_size(ol_pdev_handle pdev) +{ + struct txrx_pdev_cfg_t *cfg = (struct txrx_pdev_cfg_t *)pdev; + return cfg->tx_download_size; +} + +int ol_cfg_rx_host_defrag_timeout_duplicate_check(ol_pdev_handle pdev) +{ + struct txrx_pdev_cfg_t *cfg = (struct txrx_pdev_cfg_t *)pdev; + return cfg->defrag_timeout_check; +} + +int ol_cfg_throttle_period_ms(ol_pdev_handle pdev) +{ + struct txrx_pdev_cfg_t *cfg = (struct txrx_pdev_cfg_t *)pdev; + return cfg->throttle_period_ms; +} + +int ol_cfg_throttle_duty_cycle_level(ol_pdev_handle pdev, int level) +{ + struct txrx_pdev_cfg_t *cfg = (struct txrx_pdev_cfg_t *)pdev; + return cfg->dutycycle_level[level]; +} + +int ol_cfg_is_full_reorder_offload(ol_pdev_handle pdev) +{ + struct txrx_pdev_cfg_t *cfg = (struct txrx_pdev_cfg_t *)pdev; + return cfg->is_full_reorder_offload; +} + +/** + * ol_cfg_is_rx_thread_enabled() - return rx_thread is enable/disable + * @pdev : handle to the physical device + * + * Return: 1 - enable, 0 - disable + */ +int ol_cfg_is_rx_thread_enabled(ol_pdev_handle pdev) +{ + struct txrx_pdev_cfg_t *cfg = (struct txrx_pdev_cfg_t *)pdev; + return cfg->enable_rxthread; +} + +#ifdef QCA_LL_TX_FLOW_CONTROL_V2 +/** + * ol_cfg_get_tx_flow_stop_queue_th() - return stop queue threshold + * @pdev : handle to the physical device + * + * Return: stop queue threshold + */ +int ol_cfg_get_tx_flow_stop_queue_th(ol_pdev_handle pdev) +{ + struct txrx_pdev_cfg_t *cfg = (struct txrx_pdev_cfg_t *)pdev; + return cfg->tx_flow_stop_queue_th; +} + +/** + * ol_cfg_get_tx_flow_start_queue_offset() - return start queue offset + * @pdev : handle to the physical device + * + * Return: start queue offset + */ +int ol_cfg_get_tx_flow_start_queue_offset(ol_pdev_handle pdev) +{ + struct txrx_pdev_cfg_t *cfg = (struct txrx_pdev_cfg_t *)pdev; + return cfg->tx_flow_start_queue_offset; +} + +#endif + +#ifdef IPA_OFFLOAD +unsigned int ol_cfg_ipa_uc_offload_enabled(ol_pdev_handle pdev) +{ + struct txrx_pdev_cfg_t *cfg = (struct txrx_pdev_cfg_t *)pdev; + return (unsigned int)cfg->ipa_uc_rsc.uc_offload_enabled; +} + +unsigned int ol_cfg_ipa_uc_tx_buf_size(ol_pdev_handle pdev) +{ + struct txrx_pdev_cfg_t *cfg = (struct txrx_pdev_cfg_t *)pdev; + return cfg->ipa_uc_rsc.tx_buf_size; +} + +unsigned int ol_cfg_ipa_uc_tx_max_buf_cnt(ol_pdev_handle pdev) +{ + struct txrx_pdev_cfg_t *cfg = (struct txrx_pdev_cfg_t *)pdev; + return cfg->ipa_uc_rsc.tx_max_buf_cnt; +} + +unsigned int ol_cfg_ipa_uc_rx_ind_ring_size(ol_pdev_handle pdev) +{ + struct txrx_pdev_cfg_t *cfg = (struct txrx_pdev_cfg_t *)pdev; + return cfg->ipa_uc_rsc.rx_ind_ring_size; +} + +unsigned int ol_cfg_ipa_uc_tx_partition_base(ol_pdev_handle pdev) +{ + struct txrx_pdev_cfg_t *cfg = (struct txrx_pdev_cfg_t *)pdev; + return cfg->ipa_uc_rsc.tx_partition_base; +} + +void ol_cfg_set_ipa_uc_tx_partition_base(ol_pdev_handle pdev, uint32_t val) +{ + struct txrx_pdev_cfg_t *cfg = (struct txrx_pdev_cfg_t *)pdev; + cfg->ipa_uc_rsc.tx_partition_base = val; +} +#endif /* IPA_OFFLOAD */ + +/** + * ol_cfg_is_ce_classify_enabled() - Return if CE classification is enabled + * or disabled + * @pdev : handle to the physical device + * + * Return: 1 - enabled, 0 - disabled + */ +bool ol_cfg_is_ce_classify_enabled(ol_pdev_handle pdev) +{ + struct txrx_pdev_cfg_t *cfg = (struct txrx_pdev_cfg_t *)pdev; + return cfg->ce_classify_enabled; +} + +/** + * ol_cfg_get_wrr_skip_weight() - brief Query for the param of wrr_skip_weight + * @pdev: handle to the physical device. + * @ac: access control, it will be BE, BK, VI, VO + * + * Return: wrr_skip_weight for specified ac. + */ +int ol_cfg_get_wrr_skip_weight(ol_pdev_handle pdev, int ac) +{ + struct txrx_pdev_cfg_t *cfg = (struct txrx_pdev_cfg_t *)pdev; + + if (ac >= OL_TX_WMM_AC_BE && ac <= OL_TX_WMM_AC_VO) + return cfg->ac_specs[ac].wrr_skip_weight; + else + return 0; +} + +/** + * ol_cfg_get_credit_threshold() - Query for the param of credit_threshold + * @pdev: handle to the physical device. + * @ac: access control, it will be BE, BK, VI, VO + * + * Return: credit_threshold for specified ac. + */ +uint32_t ol_cfg_get_credit_threshold(ol_pdev_handle pdev, int ac) +{ + struct txrx_pdev_cfg_t *cfg = (struct txrx_pdev_cfg_t *)pdev; + + if (ac >= OL_TX_WMM_AC_BE && ac <= OL_TX_WMM_AC_VO) + return cfg->ac_specs[ac].credit_threshold; + else + return 0; +} + +/** + * ol_cfg_get_send_limit() - Query for the param of send_limit + * @pdev: handle to the physical device. + * @ac: access control, it will be BE, BK, VI, VO + * + * Return: send_limit for specified ac. + */ +uint16_t ol_cfg_get_send_limit(ol_pdev_handle pdev, int ac) +{ + struct txrx_pdev_cfg_t *cfg = (struct txrx_pdev_cfg_t *)pdev; + + if (ac >= OL_TX_WMM_AC_BE && ac <= OL_TX_WMM_AC_VO) + return cfg->ac_specs[ac].send_limit; + else + return 0; +} + +/** + * ol_cfg_get_credit_reserve() - Query for the param of credit_reserve + * @pdev: handle to the physical device. + * @ac: access control, it will be BE, BK, VI, VO + * + * Return: credit_reserve for specified ac. + */ +int ol_cfg_get_credit_reserve(ol_pdev_handle pdev, int ac) +{ + struct txrx_pdev_cfg_t *cfg = (struct txrx_pdev_cfg_t *)pdev; + + if (ac >= OL_TX_WMM_AC_BE && ac <= OL_TX_WMM_AC_VO) + return cfg->ac_specs[ac].credit_reserve; + else + return 0; +} + +/** + * ol_cfg_get_discard_weight() - Query for the param of discard_weight + * @pdev: handle to the physical device. + * @ac: access control, it will be BE, BK, VI, VO + * + * Return: discard_weight for specified ac. + */ +int ol_cfg_get_discard_weight(ol_pdev_handle pdev, int ac) +{ + struct txrx_pdev_cfg_t *cfg = (struct txrx_pdev_cfg_t *)pdev; + + if (ac >= OL_TX_WMM_AC_BE && ac <= OL_TX_WMM_AC_VO) + return cfg->ac_specs[ac].discard_weight; + else + return 0; +} diff --git a/drivers/staging/qcacld-3.0/core/dp/txrx/ol_ctrl_txrx_api.h b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_ctrl_txrx_api.h new file mode 100644 index 0000000000000000000000000000000000000000..544ea956147666eaacbc2220720db648c63a7760 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_ctrl_txrx_api.h @@ -0,0 +1,145 @@ +/* + * Copyright (c) 2011-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * @file ol_ctrl_txrx_api.h + * @brief Define the host control API functions called by the host data SW. + */ +#ifndef _OL_CTRL_TXRX_API__H_ +#define _OL_CTRL_TXRX_API__H_ + +/* #include / * uint8_t * / */ +#include /* uint8_t */ +#include /* qdf_nbuf_t */ + +#include /* ol_txrx_pdev_handle */ +#include /* OL_TXRX_MAC_ADDR_LEN */ +#include /* ieee80211_frame */ + +#ifdef SUPPORT_HOST_STATISTICS +/** * @brief Update tx statistics + * @details + * Update tx statistics after tx complete. + * + * @param pdev - ol_pdev_handle instance + * @param vdev_id - ID of the virtual device that tx frame + * @param had_error - whether there is error when tx + */ +void ol_tx_statistics(ol_pdev_handle pdev, uint16_t vdev_id, int had_error); +#else +#define ol_tx_statistics(pdev, vdev_id, had_error) +#endif + +/** * @brief Count on received packets for invalid peer case + * + * @param pdev - txrx pdev handle + * @param wh - received frame + * @param err_type - what kind of error occurred + */ +void ol_rx_err_inv_peer_statistics(ol_pdev_handle pdev, + struct ieee80211_frame *wh, + enum ol_rx_err_type err_type); + +/** + * @brief Count on received packets, both success and failed + * + * @param pdev - ol_pdev_handle handle + * @param vdev_id - ID of the virtual device received the erroneous rx frame + * @param err_type - what kind of error occurred + * @param sec_type - The cipher type the peer is using + * @param is_mcast - whether this is one multi cast frame + */ +void ol_rx_err_statistics(ol_pdev_handle pdev, + uint8_t vdev_id, + enum ol_rx_err_type err_type, + enum ol_sec_type sec_type, int is_mcast); + +/** + * @brief Provide notification of failure during host rx processing + * @details + * Indicate an error during host rx data processing, including what + * kind of error happened, when it happened, which peer and TID the + * erroneous rx frame is from, and what the erroneous rx frame itself + * is. + * + * @param pdev - handle to the ctrl SW's physical device object + * @param vdev_id - ID of the virtual device received the erroneous rx frame + * @param peer_mac_addr - MAC address of the peer that sent the erroneous + * rx frame + * @param tid - which TID within the peer sent the erroneous rx frame + * @param tsf32 - the timstamp in TSF units of the erroneous rx frame, or + * one of the fragments that when reassembled, constitute the rx frame + * @param err_type - what kind of error occurred + * @param rx_frame - the rx frame that had an error + * @pn - Packet sequence number + * @key_id - Key index octet received in IV of the frame + */ +void +ol_rx_err(ol_pdev_handle pdev, + uint8_t vdev_id, + uint8_t *peer_mac_addr, + int tid, + uint32_t tsf32, + enum ol_rx_err_type err_type, + qdf_nbuf_t rx_frame, uint64_t *pn, uint8_t key_id); + +enum ol_rx_notify_type { + OL_RX_NOTIFY_IPV4_IGMP, +}; + +/** + * @brief Provide notification of reception of data of special interest. + * @details + * Indicate when "special" data has been received. The nature of the + * data that results in it being considered special is specified in the + * notify_type argument. + * This function is currently used by the data-path SW to notify the + * control path SW when the following types of rx data are received: + * + IPv4 IGMP frames + * The control SW can use these to learn about multicast group + * membership, if it so chooses. + * + * @param pdev - handle to the ctrl SW's physical device object + * @param vdev_id - ID of the virtual device received the special data + * @param peer_mac_addr - MAC address of the peer that sent the special data + * @param tid - which TID within the peer sent the special data + * @param tsf32 - the timstamp in TSF units of the special data + * @param notify_type - what kind of special data was received + * @param rx_frame - the rx frame containing the special data + */ +void +ol_rx_notify(ol_pdev_handle pdev, + uint8_t vdev_id, + uint8_t *peer_mac_addr, + int tid, + uint32_t tsf32, + enum ol_rx_notify_type notify_type, qdf_nbuf_t rx_frame); + +#define ol_ctrl_addba_req(pdev, peer_mac_addr, tid) ol_addba_req_reject +#define ol_ctrl_rx_addba_complete(pdev, peer_mac_addr, tid, failed) /* no-op */ + +#endif /* _OL_CTRL_TXRX_API__H_ */ diff --git a/drivers/staging/qcacld-3.0/core/dp/txrx/ol_osif_txrx_api.h b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_osif_txrx_api.h new file mode 100644 index 0000000000000000000000000000000000000000..979b258c0a4325c5ccaa0a13baf997565e92cddc --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_osif_txrx_api.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2011, 2014-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * @file ol_osif_txrx_api.h + * @brief Define the OS specific API functions called by txrx SW. + */ +#ifndef _OL_OSIF_TXRX_API_H_ +#define _OL_OSIF_TXRX_API_H_ + +#include /* qdf_nbuf_t */ + +/** + * @brief Call tx completion handler to release the buffers + * @details + * + * Invoke tx completion handler when the tx credit goes below low water mark. + * This eliminate the packet drop in the host driver due to send routine not + * yielding the cpu when the amount of traffic pumped from the network layer + * is very high. + * + * @param osdev + */ + +void ol_osif_ath_tasklet(qdf_device_t osdev); + +#endif /* _OL_OSIF_TXRX_API_H_ */ diff --git a/drivers/staging/qcacld-3.0/core/dp/txrx/ol_rx.c b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_rx.c new file mode 100644 index 0000000000000000000000000000000000000000..c2096af516b95e91735a1b1e2ccaf810a06449c5 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_rx.c @@ -0,0 +1,1788 @@ +/* + * Copyright (c) 2011-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#include /* qdf_nbuf_t, etc. */ +#include /* qdf_cpu_to_le64 */ +#include /* bool */ +#include /* ieee80211_frame */ + +/* external API header files */ +#include /* ol_rx_notify */ +#include /* ol_txrx_pdev_handle */ +#include /* ol_rx_indication_handler */ +#include /* htt_rx_peer_id, etc. */ + +/* internal API header files */ +#include /* ol_txrx_peer_find_by_id */ +#include /* ol_rx_reorder_store, etc. */ +#include /* OL_RX_REORDER_TIMEOUT_UPDATE */ +#include /* ol_rx_defrag_waitlist_flush */ +#include +#include +#ifdef QCA_SUPPORT_SW_TXRX_ENCAP +#include /* ol_rx_decap_info_t, etc */ +#endif +#include + +/* FIX THIS: txrx should not include private header files of other modules */ +#include +#include +#include /* ethernet + SNAP/LLC header defs and + ethertype values */ +#include /* IP protocol values */ +#include /* IPv4 header defs */ +#include /* IPv6 header defs */ +#include +#include +#include +#include "pktlog_ac_fmt.h" + +#include + + +#define OL_RX_INDICATION_MAX_RECORDS 2048 + +/** + * enum ol_rx_ind_record_type - OL rx indication events + * @OL_RX_INDICATION_POP_START: event recorded before netbuf pop + * @OL_RX_INDICATION_POP_END: event recorded after netbuf pop + * @OL_RX_INDICATION_BUF_REPLENISH: event recorded after buffer replenishment + */ +enum ol_rx_ind_record_type { + OL_RX_INDICATION_POP_START, + OL_RX_INDICATION_POP_END, + OL_RX_INDICATION_BUF_REPLENISH, +}; + +/** + * struct ol_rx_ind_record - structure for detailing ol txrx rx ind. event + * @value: info corresponding to rx indication event + * @type: what the event was + * @time: when it happened + */ +struct ol_rx_ind_record { + uint16_t value; + enum ol_rx_ind_record_type type; + uint64_t time; +}; + +#ifdef OL_RX_INDICATION_RECORD +static uint32_t ol_rx_ind_record_index; +static struct ol_rx_ind_record + ol_rx_indication_record_history[OL_RX_INDICATION_MAX_RECORDS]; + +/** + * ol_rx_ind_record_event() - record ol rx indication events + * @value: contains rx ind. event related info + * @type: ol rx indication message type + * + * This API record the ol rx indiation event in a rx indication + * record buffer. + * + * Return: None + */ +static void ol_rx_ind_record_event(uint32_t value, + enum ol_rx_ind_record_type type) +{ + ol_rx_indication_record_history[ol_rx_ind_record_index].value = value; + ol_rx_indication_record_history[ol_rx_ind_record_index].type = type; + ol_rx_indication_record_history[ol_rx_ind_record_index].time = + qdf_get_log_timestamp(); + + ol_rx_ind_record_index++; + if (ol_rx_ind_record_index >= OL_RX_INDICATION_MAX_RECORDS) + ol_rx_ind_record_index = 0; +} +#else +static inline +void ol_rx_ind_record_event(uint32_t value, enum ol_rx_ind_record_type type) +{ +} + +#endif /* OL_RX_INDICATION_RECORD */ + +void ol_rx_data_process(struct ol_txrx_peer_t *peer, + qdf_nbuf_t rx_buf_list); + +/** + * ol_rx_send_pktlog_event() - send rx packetlog event + * @pdev: pdev handle + * @peer: peer handle + * @msdu: skb list + * @pktlog_bit: packetlog bit from firmware + * + * Return: none + */ +#ifdef HELIUMPLUS +void ol_rx_send_pktlog_event(struct ol_txrx_pdev_t *pdev, + struct ol_txrx_peer_t *peer, qdf_nbuf_t msdu, uint8_t pktlog_bit) +{ + struct ol_rx_remote_data data; + + if (!pktlog_bit) + return; + + data.msdu = msdu; + if (peer) + data.mac_id = peer->vdev->mac_id; + else + data.mac_id = 0; + + wdi_event_handler(WDI_EVENT_RX_DESC_REMOTE, pdev, &data); +} +#else +void ol_rx_send_pktlog_event(struct ol_txrx_pdev_t *pdev, + struct ol_txrx_peer_t *peer, qdf_nbuf_t msdu, uint8_t pktlog_bit) +{ + struct ol_rx_remote_data data; + + data.msdu = msdu; + if (peer) + data.mac_id = peer->vdev->mac_id; + else + data.mac_id = 0; + + wdi_event_handler(WDI_EVENT_RX_DESC_REMOTE, pdev, &data); +} +#endif + +#ifdef HTT_RX_RESTORE + +static void ol_rx_restore_handler(struct work_struct *htt_rx) +{ + qdf_device_t qdf_ctx = cds_get_context(QDF_MODULE_ID_QDF_DEVICE); + + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO, + "Enter: %s", __func__); + pld_device_self_recovery(qdf_ctx->dev); + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO, + "Exit: %s", __func__); +} + +static DECLARE_WORK(ol_rx_restore_work, ol_rx_restore_handler); + +void ol_rx_trigger_restore(htt_pdev_handle htt_pdev, qdf_nbuf_t head_msdu, + qdf_nbuf_t tail_msdu) +{ + qdf_nbuf_t next; + + while (head_msdu) { + next = qdf_nbuf_next(head_msdu); + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO, + "freeing %p\n", head_msdu); + qdf_nbuf_free(head_msdu); + head_msdu = next; + } + + if (!htt_pdev->rx_ring.htt_rx_restore) { + cds_set_recovery_in_progress(true); + htt_pdev->rx_ring.htt_rx_restore = 1; + schedule_work(&ol_rx_restore_work); + } +} +#endif + +/** + * ol_rx_update_histogram_stats() - update rx histogram statistics + * @msdu_count: msdu count + * @frag_ind: fragment indication set + * @offload_ind: offload indication set + * + * Return: none + */ +void ol_rx_update_histogram_stats(uint32_t msdu_count, uint8_t frag_ind, + uint8_t offload_ind) +{ + struct ol_txrx_pdev_t *pdev = cds_get_context(QDF_MODULE_ID_TXRX); + + if (!pdev) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "%s pdev is NULL\n", __func__); + return; + } + + if (msdu_count > 60) { + TXRX_STATS_ADD(pdev, pub.rx.rx_ind_histogram.pkts_61_plus, 1); + } else if (msdu_count > 50) { + TXRX_STATS_ADD(pdev, pub.rx.rx_ind_histogram.pkts_51_60, 1); + } else if (msdu_count > 40) { + TXRX_STATS_ADD(pdev, pub.rx.rx_ind_histogram.pkts_41_50, 1); + } else if (msdu_count > 30) { + TXRX_STATS_ADD(pdev, pub.rx.rx_ind_histogram.pkts_31_40, 1); + } else if (msdu_count > 20) { + TXRX_STATS_ADD(pdev, pub.rx.rx_ind_histogram.pkts_21_30, 1); + } else if (msdu_count > 10) { + TXRX_STATS_ADD(pdev, pub.rx.rx_ind_histogram.pkts_11_20, 1); + } else if (msdu_count > 1) { + TXRX_STATS_ADD(pdev, pub.rx.rx_ind_histogram.pkts_2_10, 1); + } else if (msdu_count == 1) { + TXRX_STATS_ADD(pdev, pub.rx.rx_ind_histogram.pkts_1, 1); + } + + if (frag_ind) + TXRX_STATS_ADD(pdev, pub.rx.msdus_with_frag_ind, msdu_count); + + if (offload_ind) + TXRX_STATS_ADD(pdev, pub.rx.msdus_with_offload_ind, msdu_count); + +} + +static void ol_rx_process_inv_peer(ol_txrx_pdev_handle pdev, + void *rx_mpdu_desc, qdf_nbuf_t msdu) +{ + uint8_t a1[IEEE80211_ADDR_LEN]; + htt_pdev_handle htt_pdev = pdev->htt_pdev; + struct ol_txrx_vdev_t *vdev = NULL; + struct ieee80211_frame *wh; + struct wdi_event_rx_peer_invalid_msg msg; + + wh = (struct ieee80211_frame *) + htt_rx_mpdu_wifi_hdr_retrieve(htt_pdev, rx_mpdu_desc); + /* + * Klocwork issue #6152 + * All targets that send a "INVALID_PEER" rx status provide a + * 802.11 header for each rx MPDU, so it is certain that + * htt_rx_mpdu_wifi_hdr_retrieve will succeed. + * However, both for robustness, e.g. if this function is given a + * MSDU descriptor rather than a MPDU descriptor, and to make it + * clear to static analysis that this code is safe, add an explicit + * check that htt_rx_mpdu_wifi_hdr_retrieve provides a non-NULL value. + */ + if (wh == NULL || !IEEE80211_IS_DATA(wh)) + return; + + /* ignore frames for non-existent bssids */ + qdf_mem_copy(a1, wh->i_addr1, IEEE80211_ADDR_LEN); + TAILQ_FOREACH(vdev, &pdev->vdev_list, vdev_list_elem) { + if (qdf_mem_cmp(a1, vdev->mac_addr.raw, IEEE80211_ADDR_LEN)) + break; + } + if (!vdev) + return; + + msg.wh = wh; + msg.msdu = msdu; + msg.vdev_id = vdev->vdev_id; +#ifdef WDI_EVENT_ENABLE + wdi_event_handler(WDI_EVENT_RX_PEER_INVALID, pdev, &msg); +#endif +} + +#ifdef QCA_SUPPORT_PEER_DATA_RX_RSSI +static inline int16_t +ol_rx_rssi_avg(struct ol_txrx_pdev_t *pdev, int16_t rssi_old, int16_t rssi_new) +{ + int rssi_old_weight; + + if (rssi_new == HTT_RSSI_INVALID) + return rssi_old; + if (rssi_old == HTT_RSSI_INVALID) + return rssi_new; + + rssi_old_weight = + (1 << pdev->rssi_update_shift) - pdev->rssi_new_weight; + return (rssi_new * pdev->rssi_new_weight + + rssi_old * rssi_old_weight) >> pdev->rssi_update_shift; +} + +static void +ol_rx_ind_rssi_update(struct ol_txrx_peer_t *peer, qdf_nbuf_t rx_ind_msg) +{ + struct ol_txrx_pdev_t *pdev = peer->vdev->pdev; + peer->rssi_dbm = ol_rx_rssi_avg(pdev, peer->rssi_dbm, + htt_rx_ind_rssi_dbm(pdev->htt_pdev, + rx_ind_msg)); +} + +static void +ol_rx_mpdu_rssi_update(struct ol_txrx_peer_t *peer, void *rx_mpdu_desc) +{ + struct ol_txrx_pdev_t *pdev = peer->vdev->pdev; + if (!peer) + return; + peer->rssi_dbm = ol_rx_rssi_avg(pdev, peer->rssi_dbm, + htt_rx_mpdu_desc_rssi_dbm( + pdev->htt_pdev, + rx_mpdu_desc)); +} + +#else +#define ol_rx_ind_rssi_update(peer, rx_ind_msg) /* no-op */ +#define ol_rx_mpdu_rssi_update(peer, rx_mpdu_desc) /* no-op */ +#endif /* QCA_SUPPORT_PEER_DATA_RX_RSSI */ + +static void discard_msdus(htt_pdev_handle htt_pdev, + qdf_nbuf_t head_msdu, + qdf_nbuf_t tail_msdu) +{ + while (1) { + qdf_nbuf_t next; + next = qdf_nbuf_next( + head_msdu); + htt_rx_desc_frame_free + (htt_pdev, + head_msdu); + if (head_msdu == + tail_msdu) { + break; + } + head_msdu = next; + } + return; +} + +static void chain_msdus(htt_pdev_handle htt_pdev, + qdf_nbuf_t head_msdu, + qdf_nbuf_t tail_msdu) +{ + while (1) { + qdf_nbuf_t next; + next = qdf_nbuf_next(head_msdu); + htt_rx_desc_frame_free( + htt_pdev, + head_msdu); + if (head_msdu == tail_msdu) + break; + head_msdu = next; + } + return; +} + +static void process_reorder(ol_txrx_pdev_handle pdev, + void *rx_mpdu_desc, + uint8_t tid, + struct ol_txrx_peer_t *peer, + qdf_nbuf_t head_msdu, + qdf_nbuf_t tail_msdu, + int num_mpdu_ranges, + int num_pdus, + bool rx_ind_release) +{ + htt_pdev_handle htt_pdev = pdev->htt_pdev; + enum htt_rx_status mpdu_status; + int reorder_idx; + reorder_idx = htt_rx_mpdu_desc_reorder_idx(htt_pdev, rx_mpdu_desc); + OL_RX_REORDER_TRACE_ADD(pdev, tid, + reorder_idx, + htt_rx_mpdu_desc_seq_num(htt_pdev, + rx_mpdu_desc), + 1); + ol_rx_mpdu_rssi_update(peer, rx_mpdu_desc); + /* + * In most cases, out-of-bounds and duplicate sequence number detection + * is performed by the target, but in some cases it is done by the host. + * Specifically, the host does rx out-of-bounds sequence number + * detection for: + * 1. Peregrine or Rome target + * for peer-TIDs that do not have aggregation enabled, if the + * RX_SKIP_DEFRAG_TIMEOUT_DUP_DETECTION_CHECK flag + * is set during the driver build. + * 2. Riva-family targets, which have rx reorder timeouts handled by + * the host rather than the target. + * (The target already does duplicate detection, but the host + * may have given up waiting for a particular sequence number before + * it arrives. In this case, the out-of-bounds sequence number + * of the late frame allows the host to discard it, rather than + * sending it out of order. + */ + mpdu_status = OL_RX_SEQ_NUM_CHECK(pdev, + peer, + tid, + rx_mpdu_desc); + if (mpdu_status != htt_rx_status_ok) { + /* + * If the sequence number was out of bounds, the MPDU needs + * to be discarded. + */ + discard_msdus(htt_pdev, head_msdu, tail_msdu); + /* + * For Peregrine and Rome, + * OL_RX_REORDER_SEQ_NUM_CHECK should only fail for the case + * of (duplicate) non-aggregates. + * + * For Riva, Pronto and Northstar, + * there should be only one MPDU delivered at a time. + * Thus, there are no further MPDUs that need to be + * processed here. + * Just to be sure this is true, check the assumption + * that this was the only MPDU referenced by the rx + * indication. + */ + TXRX_ASSERT2((num_mpdu_ranges == 1) && num_mpdus == 1); + + /* + * The MPDU was not stored in the rx reorder array, so + * there's nothing to release. + */ + rx_ind_release = false; + } else { + ol_rx_reorder_store(pdev, peer, tid, + reorder_idx, head_msdu, tail_msdu); + if (peer->tids_rx_reorder[tid].win_sz_mask == 0) { + peer->tids_last_seq[tid] = htt_rx_mpdu_desc_seq_num( + htt_pdev, + rx_mpdu_desc); + } + } + return; +} /* process_reorder */ + +void +ol_rx_indication_handler(ol_txrx_pdev_handle pdev, + qdf_nbuf_t rx_ind_msg, + uint16_t peer_id, uint8_t tid, int num_mpdu_ranges) +{ + int mpdu_range, i; + unsigned seq_num_start = 0, seq_num_end = 0; + bool rx_ind_release = false; + struct ol_txrx_vdev_t *vdev = NULL; + struct ol_txrx_peer_t *peer; + htt_pdev_handle htt_pdev; + uint16_t center_freq; + uint16_t chan1; + uint16_t chan2; + uint8_t phymode; + bool ret; + uint32_t msdu_count = 0; + + htt_pdev = pdev->htt_pdev; + peer = ol_txrx_peer_find_by_id(pdev, peer_id); + if (!peer) { + /* + * If we can't find a peer send this packet to OCB interface + * using OCB self peer + */ + if (!ol_txrx_get_ocb_peer(pdev, &peer)) + peer = NULL; + } + + if (peer) { + vdev = peer->vdev; + ol_rx_ind_rssi_update(peer, rx_ind_msg); + + if (vdev->opmode == wlan_op_mode_ocb) { + htt_rx_ind_legacy_rate(pdev->htt_pdev, rx_ind_msg, + &peer->last_pkt_legacy_rate, + &peer->last_pkt_legacy_rate_sel); + peer->last_pkt_rssi_cmb = htt_rx_ind_rssi_dbm( + pdev->htt_pdev, rx_ind_msg); + for (i = 0; i < 4; i++) + peer->last_pkt_rssi[i] = + htt_rx_ind_rssi_dbm_chain( + pdev->htt_pdev, rx_ind_msg, i); + htt_rx_ind_timestamp(pdev->htt_pdev, rx_ind_msg, + &peer->last_pkt_timestamp_microsec, + &peer->last_pkt_timestamp_submicrosec); + peer->last_pkt_tsf = htt_rx_ind_tsf32(pdev->htt_pdev, + rx_ind_msg); + peer->last_pkt_tid = htt_rx_ind_ext_tid(pdev->htt_pdev, + rx_ind_msg); + } + } + + TXRX_STATS_INCR(pdev, priv.rx.normal.ppdus); + + OL_RX_REORDER_TIMEOUT_MUTEX_LOCK(pdev); + + if (htt_rx_ind_flush(pdev->htt_pdev, rx_ind_msg) && peer) { + htt_rx_ind_flush_seq_num_range(pdev->htt_pdev, rx_ind_msg, + &seq_num_start, &seq_num_end); + if (tid == HTT_INVALID_TID) { + /* + * host/FW reorder state went out-of sync + * for a while because FW ran out of Rx indication + * buffer. We have to discard all the buffers in + * reorder queue. + */ + ol_rx_reorder_peer_cleanup(vdev, peer); + } else { + ol_rx_reorder_flush(vdev, peer, tid, seq_num_start, + seq_num_end, htt_rx_flush_release); + } + } + + if (htt_rx_ind_release(pdev->htt_pdev, rx_ind_msg)) { + /* the ind info of release is saved here and do release at the + * end. This is for the reason of in HL case, the qdf_nbuf_t + * for msg and payload are the same buf. And the buf will be + * changed during processing */ + rx_ind_release = true; + htt_rx_ind_release_seq_num_range(pdev->htt_pdev, rx_ind_msg, + &seq_num_start, &seq_num_end); + } +#ifdef DEBUG_DMA_DONE + pdev->htt_pdev->rx_ring.dbg_initial_msdu_payld = + pdev->htt_pdev->rx_ring.sw_rd_idx.msdu_payld; +#endif + + for (mpdu_range = 0; mpdu_range < num_mpdu_ranges; mpdu_range++) { + enum htt_rx_status status; + int i, num_mpdus; + qdf_nbuf_t head_msdu, tail_msdu, msdu; + void *rx_mpdu_desc; + +#ifdef DEBUG_DMA_DONE + pdev->htt_pdev->rx_ring.dbg_mpdu_range = mpdu_range; +#endif + + htt_rx_ind_mpdu_range_info(pdev->htt_pdev, rx_ind_msg, + mpdu_range, &status, &num_mpdus); + if ((status == htt_rx_status_ok) && peer) { + TXRX_STATS_ADD(pdev, priv.rx.normal.mpdus, num_mpdus); + /* valid frame - deposit it into rx reordering buffer */ + for (i = 0; i < num_mpdus; i++) { + int msdu_chaining; + /* + * Get a linked list of the MSDUs that comprise + * this MPDU. + * This also attaches each rx MSDU descriptor to + * the corresponding rx MSDU network buffer. + * (In some systems, the rx MSDU desc is already + * in the same buffer as the MSDU payload; in + * other systems they are separate, so a pointer + * needs to be set in the netbuf to locate the + * corresponding rx descriptor.) + * + * It is neccessary to call htt_rx_amsdu_pop + * before htt_rx_mpdu_desc_list_next, because + * the (MPDU) rx descriptor has DMA unmapping + * done during the htt_rx_amsdu_pop call. + * The rx desc should not be accessed until this + * DMA unmapping has been done, since the DMA + * unmapping involves making sure the cache area + * for the mapped buffer is flushed, so the data + * written by the MAC DMA into memory will be + * fetched, rather than garbage from the cache. + */ + +#ifdef DEBUG_DMA_DONE + pdev->htt_pdev->rx_ring.dbg_mpdu_count = i; +#endif + + msdu_chaining = + htt_rx_amsdu_pop(htt_pdev, + rx_ind_msg, + &head_msdu, + &tail_msdu, + &msdu_count); +#ifdef HTT_RX_RESTORE + if (htt_pdev->rx_ring.rx_reset) { + ol_rx_trigger_restore(htt_pdev, + head_msdu, + tail_msdu); + return; + } +#endif + rx_mpdu_desc = + htt_rx_mpdu_desc_list_next(htt_pdev, + rx_ind_msg); + ret = htt_rx_msdu_center_freq(htt_pdev, peer, + rx_mpdu_desc, ¢er_freq, &chan1, + &chan2, &phymode); + if (ret == true) { + peer->last_pkt_center_freq = + center_freq; + } else { + peer->last_pkt_center_freq = 0; + } + + /* Pktlog */ +#ifdef WDI_EVENT_ENABLE + ol_rx_send_pktlog_event(pdev, peer, head_msdu, 1); +#endif + + if (msdu_chaining) { + /* + * TBDXXX - to deliver SDU with + * chaining, we need to stitch those + * scattered buffers into one single + * buffer. + * Just discard it now. + */ + chain_msdus(htt_pdev, + head_msdu, + tail_msdu); + } else { + process_reorder(pdev, rx_mpdu_desc, + tid, peer, + head_msdu, tail_msdu, + num_mpdu_ranges, + num_mpdus, + rx_ind_release); + } + + } + } else { + /* invalid frames - discard them */ + OL_RX_REORDER_TRACE_ADD(pdev, tid, + TXRX_SEQ_NUM_ERR(status), + TXRX_SEQ_NUM_ERR(status), + num_mpdus); + TXRX_STATS_ADD(pdev, priv.rx.err.mpdu_bad, num_mpdus); + for (i = 0; i < num_mpdus; i++) { + /* pull the MPDU's MSDUs off the buffer queue */ + htt_rx_amsdu_pop(htt_pdev, rx_ind_msg, &msdu, + &tail_msdu, &msdu_count); +#ifdef HTT_RX_RESTORE + if (htt_pdev->rx_ring.rx_reset) { + ol_rx_trigger_restore(htt_pdev, msdu, + tail_msdu); + return; + } +#endif + /* pull the MPDU desc off the desc queue */ + rx_mpdu_desc = + htt_rx_mpdu_desc_list_next(htt_pdev, + rx_ind_msg); + OL_RX_ERR_STATISTICS_2(pdev, vdev, peer, + rx_mpdu_desc, msdu, + status); + + if (status == htt_rx_status_tkip_mic_err && + vdev != NULL && peer != NULL) { + union htt_rx_pn_t pn; + uint8_t key_id; + htt_rx_mpdu_desc_pn( + pdev->htt_pdev, + htt_rx_msdu_desc_retrieve( + pdev->htt_pdev, + msdu), &pn, 48); + if (htt_rx_msdu_desc_key_id( + pdev->htt_pdev, + htt_rx_msdu_desc_retrieve( + pdev->htt_pdev, + msdu), + &key_id) == true) { + ol_rx_err(pdev->ctrl_pdev, + vdev->vdev_id, + peer->mac_addr.raw, + tid, 0, + OL_RX_ERR_TKIP_MIC, + msdu, &pn.pn48, + key_id); + } + } +#ifdef WDI_EVENT_ENABLE + if (status != htt_rx_status_ctrl_mgmt_null) { + /* Pktlog */ + ol_rx_send_pktlog_event(pdev, + peer, msdu, 1); + } +#endif + if (status == htt_rx_status_err_inv_peer) { + /* once per mpdu */ + ol_rx_process_inv_peer(pdev, + rx_mpdu_desc, + msdu); + } + while (1) { + /* Free the nbuf */ + qdf_nbuf_t next; + next = qdf_nbuf_next(msdu); + htt_rx_desc_frame_free(htt_pdev, msdu); + if (msdu == tail_msdu) + break; + msdu = next; + } + } + } + } + /* + * Now that a whole batch of MSDUs have been pulled out of HTT + * and put into the rx reorder array, it is an appropriate time + * to request HTT to provide new rx MSDU buffers for the target + * to fill. + * This could be done after the end of this function, but it's + * better to do it now, rather than waiting until after the driver + * and OS finish processing the batch of rx MSDUs. + */ + htt_rx_msdu_buff_replenish(htt_pdev); + + if ((true == rx_ind_release) && peer && vdev) { + ol_rx_reorder_release(vdev, peer, tid, seq_num_start, + seq_num_end); + } + OL_RX_REORDER_TIMEOUT_UPDATE(peer, tid); + OL_RX_REORDER_TIMEOUT_MUTEX_UNLOCK(pdev); + + if (pdev->rx.flags.defrag_timeout_check) + ol_rx_defrag_waitlist_flush(pdev); +} + +void +ol_rx_sec_ind_handler(ol_txrx_pdev_handle pdev, + uint16_t peer_id, + enum htt_sec_type sec_type, + int is_unicast, uint32_t *michael_key, uint32_t *rx_pn) +{ + struct ol_txrx_peer_t *peer; + int sec_index, i; + + peer = ol_txrx_peer_find_by_id(pdev, peer_id); + if (!peer) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "Couldn't find peer from ID %d - skipping security inits\n", + peer_id); + return; + } + TXRX_PRINT(TXRX_PRINT_LEVEL_INFO1, + "sec spec for peer %p (%02x:%02x:%02x:%02x:%02x:%02x): " + "%s key of type %d\n", + peer, + peer->mac_addr.raw[0], peer->mac_addr.raw[1], + peer->mac_addr.raw[2], peer->mac_addr.raw[3], + peer->mac_addr.raw[4], peer->mac_addr.raw[5], + is_unicast ? "ucast" : "mcast", sec_type); + sec_index = is_unicast ? txrx_sec_ucast : txrx_sec_mcast; + peer->security[sec_index].sec_type = sec_type; + /* michael key only valid for TKIP + but for simplicity, copy it anyway */ + qdf_mem_copy(&peer->security[sec_index].michael_key[0], + michael_key, + sizeof(peer->security[sec_index].michael_key)); + + if (sec_type != htt_sec_type_wapi) { + qdf_mem_set(peer->tids_last_pn_valid, + OL_TXRX_NUM_EXT_TIDS, 0x00); + } else if (sec_index == txrx_sec_mcast || peer->tids_last_pn_valid[0]) { + for (i = 0; i < OL_TXRX_NUM_EXT_TIDS; i++) { + /* + * Setting PN valid bit for WAPI sec_type, + * since WAPI PN has to be started with predefined value + */ + peer->tids_last_pn_valid[i] = 1; + qdf_mem_copy((uint8_t *) &peer->tids_last_pn[i], + (uint8_t *) rx_pn, + sizeof(union htt_rx_pn_t)); + peer->tids_last_pn[i].pn128[1] = + qdf_cpu_to_le64( + peer->tids_last_pn[i].pn128[1]); + peer->tids_last_pn[i].pn128[0] = + qdf_cpu_to_le64( + peer->tids_last_pn[i].pn128[0]); + } + } +} + +#if defined(PERE_IP_HDR_ALIGNMENT_WAR) + +#include + +static void transcap_nwifi_to_8023(qdf_nbuf_t msdu) +{ + struct ieee80211_frame *wh; + uint32_t hdrsize; + struct llc *llchdr; + struct ether_header *eth_hdr; + uint16_t ether_type = 0; + uint8_t a1[IEEE80211_ADDR_LEN]; + uint8_t a2[IEEE80211_ADDR_LEN]; + uint8_t a3[IEEE80211_ADDR_LEN]; + uint8_t fc1; + + wh = (struct ieee80211_frame *)qdf_nbuf_data(msdu); + qdf_mem_copy(a1, wh->i_addr1, IEEE80211_ADDR_LEN); + qdf_mem_copy(a2, wh->i_addr2, IEEE80211_ADDR_LEN); + qdf_mem_copy(a3, wh->i_addr3, IEEE80211_ADDR_LEN); + fc1 = wh->i_fc[1] & IEEE80211_FC1_DIR_MASK; + /* Native Wifi header is 80211 non-QoS header */ + hdrsize = sizeof(struct ieee80211_frame); + + llchdr = (struct llc *)(((uint8_t *) qdf_nbuf_data(msdu)) + hdrsize); + ether_type = llchdr->llc_un.type_snap.ether_type; + + /* + * Now move the data pointer to the beginning of the mac header : + * new-header = old-hdr + (wifhdrsize + llchdrsize - ethhdrsize) + */ + qdf_nbuf_pull_head(msdu, + (hdrsize + sizeof(struct llc) - + sizeof(struct ether_header))); + eth_hdr = (struct ether_header *)(qdf_nbuf_data(msdu)); + switch (fc1) { + case IEEE80211_FC1_DIR_NODS: + qdf_mem_copy(eth_hdr->ether_dhost, a1, IEEE80211_ADDR_LEN); + qdf_mem_copy(eth_hdr->ether_shost, a2, IEEE80211_ADDR_LEN); + break; + case IEEE80211_FC1_DIR_TODS: + qdf_mem_copy(eth_hdr->ether_dhost, a3, IEEE80211_ADDR_LEN); + qdf_mem_copy(eth_hdr->ether_shost, a2, IEEE80211_ADDR_LEN); + break; + case IEEE80211_FC1_DIR_FROMDS: + qdf_mem_copy(eth_hdr->ether_dhost, a1, IEEE80211_ADDR_LEN); + qdf_mem_copy(eth_hdr->ether_shost, a3, IEEE80211_ADDR_LEN); + break; + case IEEE80211_FC1_DIR_DSTODS: + break; + } + eth_hdr->ether_type = ether_type; +} +#endif + +void ol_rx_notify(ol_pdev_handle pdev, + uint8_t vdev_id, + uint8_t *peer_mac_addr, + int tid, + uint32_t tsf32, + enum ol_rx_notify_type notify_type, qdf_nbuf_t rx_frame) +{ + /* + * NOTE: This is used in qca_main for AP mode to handle IGMP + * packets specially. Umac has a corresponding handler for this + * not sure if we need to have this for CLD as well. + */ +} + +/** + * @brief Look into a rx MSDU to see what kind of special handling it requires + * @details + * This function is called when the host rx SW sees that the target + * rx FW has marked a rx MSDU as needing inspection. + * Based on the results of the inspection, the host rx SW will infer + * what special handling to perform on the rx frame. + * Currently, the only type of frames that require special handling + * are IGMP frames. The rx data-path SW checks if the frame is IGMP + * (it should be, since the target would not have set the inspect flag + * otherwise), and then calls the ol_rx_notify function so the + * control-path SW can perform multicast group membership learning + * by sniffing the IGMP frame. + */ +#define SIZEOF_80211_HDR (sizeof(struct ieee80211_frame)) +static void +ol_rx_inspect(struct ol_txrx_vdev_t *vdev, + struct ol_txrx_peer_t *peer, + unsigned tid, qdf_nbuf_t msdu, void *rx_desc) +{ + ol_txrx_pdev_handle pdev = vdev->pdev; + uint8_t *data, *l3_hdr; + uint16_t ethertype; + int offset; + + data = qdf_nbuf_data(msdu); + if (pdev->frame_format == wlan_frm_fmt_native_wifi) { + offset = SIZEOF_80211_HDR + LLC_SNAP_HDR_OFFSET_ETHERTYPE; + l3_hdr = data + SIZEOF_80211_HDR + LLC_SNAP_HDR_LEN; + } else { + offset = ETHERNET_ADDR_LEN * 2; + l3_hdr = data + ETHERNET_HDR_LEN; + } + ethertype = (data[offset] << 8) | data[offset + 1]; + if (ethertype == ETHERTYPE_IPV4) { + offset = IPV4_HDR_OFFSET_PROTOCOL; + if (l3_hdr[offset] == IP_PROTOCOL_IGMP) { + ol_rx_notify(pdev->ctrl_pdev, + vdev->vdev_id, + peer->mac_addr.raw, + tid, + htt_rx_mpdu_desc_tsf32(pdev->htt_pdev, + rx_desc), + OL_RX_NOTIFY_IPV4_IGMP, msdu); + } + } +} + +void +ol_rx_offload_deliver_ind_handler(ol_txrx_pdev_handle pdev, + qdf_nbuf_t msg, int msdu_cnt) +{ + int vdev_id, peer_id, tid; + qdf_nbuf_t head_buf, tail_buf, buf; + struct ol_txrx_peer_t *peer; + uint8_t fw_desc; + htt_pdev_handle htt_pdev = pdev->htt_pdev; + + while (msdu_cnt) { + if (!htt_rx_offload_msdu_pop(htt_pdev, msg, &vdev_id, &peer_id, + &tid, &fw_desc, &head_buf, &tail_buf)) { + peer = ol_txrx_peer_find_by_id(pdev, peer_id); + if (peer) { + ol_rx_data_process(peer, head_buf); + } else { + buf = head_buf; + while (1) { + qdf_nbuf_t next; + next = qdf_nbuf_next(buf); + htt_rx_desc_frame_free(htt_pdev, buf); + if (buf == tail_buf) + break; + buf = next; + } + } + } + msdu_cnt--; + } + htt_rx_msdu_buff_replenish(htt_pdev); +} + +#ifdef WDI_EVENT_ENABLE +static inline +void ol_rx_mic_error_send_pktlog_event(struct ol_txrx_pdev_t *pdev, + struct ol_txrx_peer_t *peer, qdf_nbuf_t msdu, uint8_t pktlog_bit) +{ + ol_rx_send_pktlog_event(pdev, peer, msdu, pktlog_bit); +} + +#else +static inline +void ol_rx_mic_error_send_pktlog_event(struct ol_txrx_pdev_t *pdev, + struct ol_txrx_peer_t *peer, qdf_nbuf_t msdu, uint8_t pktlog_bit) +{ +} + +#endif + + +void +ol_rx_mic_error_handler( + ol_txrx_pdev_handle pdev, + u_int8_t tid, + u_int16_t peer_id, + void *msdu_desc, + qdf_nbuf_t msdu) +{ + union htt_rx_pn_t pn = {0}; + u_int8_t key_id = 0; + + struct ol_txrx_peer_t *peer = NULL; + struct ol_txrx_vdev_t *vdev = NULL; + + if (pdev) { + TXRX_STATS_MSDU_INCR(pdev, rx.dropped_mic_err, msdu); + peer = ol_txrx_peer_find_by_id(pdev, peer_id); + if (peer) { + vdev = peer->vdev; + if (vdev) { + htt_rx_mpdu_desc_pn(vdev->pdev->htt_pdev, + msdu_desc, &pn, 48); + + if (htt_rx_msdu_desc_key_id( + vdev->pdev->htt_pdev, msdu_desc, + &key_id) == true) { + ol_rx_err(vdev->pdev->ctrl_pdev, + vdev->vdev_id, + peer->mac_addr.raw, tid, 0, + OL_RX_ERR_TKIP_MIC, msdu, + &pn.pn48, key_id); + } + } + } + /* Pktlog */ + ol_rx_mic_error_send_pktlog_event(pdev, peer, msdu, 1); + } +} + +/** + * @brief Check the first msdu to decide whether the a-msdu should be accepted. + */ +static bool +ol_rx_filter(struct ol_txrx_vdev_t *vdev, + struct ol_txrx_peer_t *peer, qdf_nbuf_t msdu, void *rx_desc) +{ +#define FILTER_STATUS_REJECT 1 +#define FILTER_STATUS_ACCEPT 0 + uint8_t *wh; + uint32_t offset = 0; + uint16_t ether_type = 0; + bool is_encrypted = false, is_mcast = false; + uint8_t i; + enum privacy_filter_packet_type packet_type = + PRIVACY_FILTER_PACKET_UNICAST; + ol_txrx_pdev_handle pdev = vdev->pdev; + htt_pdev_handle htt_pdev = pdev->htt_pdev; + int sec_idx; + + /* + * Safemode must avoid the PrivacyExemptionList and + * ExcludeUnencrypted checking + */ + if (vdev->safemode) + return FILTER_STATUS_ACCEPT; + + is_mcast = htt_rx_msdu_is_wlan_mcast(htt_pdev, rx_desc); + if (vdev->num_filters > 0) { + if (pdev->frame_format == wlan_frm_fmt_native_wifi) { + offset = SIZEOF_80211_HDR + + LLC_SNAP_HDR_OFFSET_ETHERTYPE; + } else { + offset = ETHERNET_ADDR_LEN * 2; + } + /* get header info from msdu */ + wh = qdf_nbuf_data(msdu); + + /* get ether type */ + ether_type = (wh[offset] << 8) | wh[offset + 1]; + /* get packet type */ + if (true == is_mcast) + packet_type = PRIVACY_FILTER_PACKET_MULTICAST; + else + packet_type = PRIVACY_FILTER_PACKET_UNICAST; + } + /* get encrypt info */ + is_encrypted = htt_rx_mpdu_is_encrypted(htt_pdev, rx_desc); +#ifdef ATH_SUPPORT_WAPI + if ((true == is_encrypted) && (ETHERTYPE_WAI == ether_type)) { + /* We expect the WAI frames to be always unencrypted when + the UMAC gets it.*/ + return FILTER_STATUS_REJECT; + } +#endif /* ATH_SUPPORT_WAPI */ + + for (i = 0; i < vdev->num_filters; i++) { + enum privacy_filter filter_type; + enum privacy_filter_packet_type filter_packet_type; + + /* skip if the ether type does not match */ + if (vdev->privacy_filters[i].ether_type != ether_type) + continue; + + /* skip if the packet type does not match */ + filter_packet_type = vdev->privacy_filters[i].packet_type; + if (filter_packet_type != packet_type && + filter_packet_type != PRIVACY_FILTER_PACKET_BOTH) { + continue; + } + + filter_type = vdev->privacy_filters[i].filter_type; + if (filter_type == PRIVACY_FILTER_ALWAYS) { + /* + * In this case, we accept the frame if and only if + * it was originally NOT encrypted. + */ + if (true == is_encrypted) + return FILTER_STATUS_REJECT; + else + return FILTER_STATUS_ACCEPT; + + } else if (filter_type == PRIVACY_FILTER_KEY_UNAVAILABLE) { + /* + * In this case, we reject the frame if it was + * originally NOT encrypted but we have the key mapping + * key for this frame. + */ + if (!is_encrypted && + !is_mcast && + (peer->security[txrx_sec_ucast].sec_type != + htt_sec_type_none) && + (peer->keyinstalled || !ETHERTYPE_IS_EAPOL_WAPI( + ether_type))) { + return FILTER_STATUS_REJECT; + } else { + return FILTER_STATUS_ACCEPT; + } + } else { + /* + * The privacy exemption does not apply to this frame. + */ + break; + } + } + + /* + * If the privacy exemption list does not apply to the frame, + * check ExcludeUnencrypted. + * If ExcludeUnencrypted is not set, or if this was oringially + * an encrypted frame, it will be accepted. + */ + if (!vdev->drop_unenc || (true == is_encrypted)) + return FILTER_STATUS_ACCEPT; + + /* + * If this is a open connection, it will be accepted. + */ + sec_idx = (true == is_mcast) ? txrx_sec_mcast : txrx_sec_ucast; + if (peer->security[sec_idx].sec_type == htt_sec_type_none) + return FILTER_STATUS_ACCEPT; + + if ((false == is_encrypted) && vdev->drop_unenc) { + OL_RX_ERR_STATISTICS(pdev, vdev, OL_RX_ERR_PRIVACY, + pdev->sec_types[htt_sec_type_none], + is_mcast); + } + return FILTER_STATUS_REJECT; +} + +void +ol_rx_deliver(struct ol_txrx_vdev_t *vdev, + struct ol_txrx_peer_t *peer, unsigned tid, qdf_nbuf_t msdu_list) +{ + ol_txrx_pdev_handle pdev = vdev->pdev; + htt_pdev_handle htt_pdev = pdev->htt_pdev; + qdf_nbuf_t deliver_list_head = NULL; + qdf_nbuf_t deliver_list_tail = NULL; + qdf_nbuf_t msdu; + bool filter = false; +#ifdef QCA_SUPPORT_SW_TXRX_ENCAP + struct ol_rx_decap_info_t info; + qdf_mem_set(&info, sizeof(info), 0); +#endif + + msdu = msdu_list; + /* + * Check each MSDU to see whether it requires special handling, + * and free each MSDU's rx descriptor + */ + while (msdu) { + void *rx_desc; + int discard, inspect, dummy_fwd; + qdf_nbuf_t next = qdf_nbuf_next(msdu); + + rx_desc = htt_rx_msdu_desc_retrieve(pdev->htt_pdev, msdu); + /* for HL, point to payload right now*/ + if (pdev->cfg.is_high_latency) + qdf_nbuf_pull_head(msdu, + htt_rx_msdu_rx_desc_size_hl(htt_pdev, rx_desc)); + +#ifdef QCA_SUPPORT_SW_TXRX_ENCAP + info.is_msdu_cmpl_mpdu = + htt_rx_msdu_desc_completes_mpdu(htt_pdev, rx_desc); + info.is_first_subfrm = + htt_rx_msdu_first_msdu_flag(htt_pdev, rx_desc); + if (OL_RX_DECAP(vdev, peer, msdu, &info) != A_OK) { + discard = 1; + TXRX_PRINT(TXRX_PRINT_LEVEL_WARN, + "decap error %p from peer %p " + "(%02x:%02x:%02x:%02x:%02x:%02x) len %d\n", + msdu, peer, + peer->mac_addr.raw[0], peer->mac_addr.raw[1], + peer->mac_addr.raw[2], peer->mac_addr.raw[3], + peer->mac_addr.raw[4], peer->mac_addr.raw[5], + qdf_nbuf_len(msdu)); + goto DONE; + } +#endif + htt_rx_msdu_actions(pdev->htt_pdev, rx_desc, &discard, + &dummy_fwd, &inspect); + if (inspect) + ol_rx_inspect(vdev, peer, tid, msdu, rx_desc); + + /* + * Check the first msdu in the mpdu, if it will be filtered out, + * then discard the entire mpdu. + */ + if (htt_rx_msdu_first_msdu_flag(htt_pdev, rx_desc)) + filter = ol_rx_filter(vdev, peer, msdu, rx_desc); + +#ifdef QCA_SUPPORT_SW_TXRX_ENCAP +DONE: +#endif + htt_rx_msdu_desc_free(htt_pdev, msdu); + if (discard || (true == filter)) { + ol_txrx_frms_dump("rx discarding:", + pdev, deliver_list_head, + ol_txrx_frm_dump_tcp_seq | + ol_txrx_frm_dump_contents, + 0 /* don't print contents */); + qdf_nbuf_free(msdu); + /* If discarding packet is last packet of the delivery + list, NULL terminator should be added + for delivery list. */ + if (next == NULL && deliver_list_head) { + /* add NULL terminator */ + qdf_nbuf_set_next(deliver_list_tail, NULL); + } + } else { + /* + * If this is for OCB, + * then prepend the RX stats header. + */ + if (vdev->opmode == wlan_op_mode_ocb) { + int i; + struct ol_txrx_ocb_chan_info *chan_info = 0; + int packet_freq = peer->last_pkt_center_freq; + for (i = 0; i < vdev->ocb_channel_count; i++) { + if (vdev->ocb_channel_info[i]. + chan_freq == packet_freq) { + chan_info = &vdev-> + ocb_channel_info[i]; + break; + } + } + if (!chan_info || !chan_info-> + disable_rx_stats_hdr) { + struct ether_header eth_header = { + {0} }; + struct ocb_rx_stats_hdr_t rx_header = { + 0}; + + /* + * Construct the RX stats header and + * push that to the frontof the packet. + */ + rx_header.version = 1; + rx_header.length = sizeof(rx_header); + rx_header.channel_freq = + peer->last_pkt_center_freq; + rx_header.rssi_cmb = + peer->last_pkt_rssi_cmb; + qdf_mem_copy(rx_header.rssi, + peer->last_pkt_rssi, + sizeof(rx_header.rssi)); + if (peer->last_pkt_legacy_rate_sel == + 0) { + switch (peer-> + last_pkt_legacy_rate) { + case 0x8: + rx_header.datarate = 6; + break; + case 0x9: + rx_header.datarate = 4; + break; + case 0xA: + rx_header.datarate = 2; + break; + case 0xB: + rx_header.datarate = 0; + break; + case 0xC: + rx_header.datarate = 7; + break; + case 0xD: + rx_header.datarate = 5; + break; + case 0xE: + rx_header.datarate = 3; + break; + case 0xF: + rx_header.datarate = 1; + break; + default: + rx_header.datarate = + 0xFF; + break; + } + } else { + rx_header.datarate = 0xFF; + } + + rx_header.timestamp_microsec = peer-> + last_pkt_timestamp_microsec; + rx_header.timestamp_submicrosec = peer-> + last_pkt_timestamp_submicrosec; + rx_header.tsf32 = peer->last_pkt_tsf; + rx_header.ext_tid = peer->last_pkt_tid; + + qdf_nbuf_push_head(msdu, + sizeof(rx_header)); + qdf_mem_copy(qdf_nbuf_data(msdu), + &rx_header, sizeof(rx_header)); + + /* Construct the ethernet header with + type 0x8152 and push that to the + front of the packet to indicate the + RX stats header. */ + eth_header.ether_type = QDF_SWAP_U16( + ETHERTYPE_OCB_RX); + qdf_nbuf_push_head(msdu, + sizeof(eth_header)); + qdf_mem_copy(qdf_nbuf_data(msdu), + ð_header, + sizeof(eth_header)); + } + } + OL_RX_PEER_STATS_UPDATE(peer, msdu); + OL_RX_ERR_STATISTICS_1(pdev, vdev, peer, rx_desc, + OL_RX_ERR_NONE); + TXRX_STATS_MSDU_INCR(vdev->pdev, rx.delivered, msdu); + OL_TXRX_LIST_APPEND(deliver_list_head, + deliver_list_tail, msdu); + } + msdu = next; + } + /* sanity check - are there any frames left to give to the OS shim? */ + if (!deliver_list_head) + return; + +#if defined(PERE_IP_HDR_ALIGNMENT_WAR) + if (pdev->host_80211_enable) + for (msdu = deliver_list_head; msdu; msdu = qdf_nbuf_next(msdu)) + transcap_nwifi_to_8023(msdu); +#endif + + ol_txrx_frms_dump("rx delivering:", + pdev, deliver_list_head, + ol_txrx_frm_dump_tcp_seq | ol_txrx_frm_dump_contents, + 0 /* don't print contents */); + + ol_rx_data_process(peer, deliver_list_head); +} + +void +ol_rx_discard(struct ol_txrx_vdev_t *vdev, + struct ol_txrx_peer_t *peer, unsigned tid, qdf_nbuf_t msdu_list) +{ + ol_txrx_pdev_handle pdev = vdev->pdev; + htt_pdev_handle htt_pdev = pdev->htt_pdev; + + while (msdu_list) { + qdf_nbuf_t msdu = msdu_list; + + msdu_list = qdf_nbuf_next(msdu_list); + TXRX_PRINT(TXRX_PRINT_LEVEL_INFO1, + "discard rx %p from partly-deleted peer %p " + "(%02x:%02x:%02x:%02x:%02x:%02x)\n", + msdu, peer, + peer->mac_addr.raw[0], peer->mac_addr.raw[1], + peer->mac_addr.raw[2], peer->mac_addr.raw[3], + peer->mac_addr.raw[4], peer->mac_addr.raw[5]); + htt_rx_desc_frame_free(htt_pdev, msdu); + } +} + +void ol_rx_peer_init(struct ol_txrx_pdev_t *pdev, struct ol_txrx_peer_t *peer) +{ + uint8_t tid; + for (tid = 0; tid < OL_TXRX_NUM_EXT_TIDS; tid++) { + ol_rx_reorder_init(&peer->tids_rx_reorder[tid], tid); + + /* invalid sequence number */ + peer->tids_last_seq[tid] = IEEE80211_SEQ_MAX; + } + /* + * Set security defaults: no PN check, no security. + * The target may send a HTT SEC_IND message to overwrite + * these defaults. + */ + peer->security[txrx_sec_ucast].sec_type = + peer->security[txrx_sec_mcast].sec_type = htt_sec_type_none; + peer->keyinstalled = 0; + + peer->last_assoc_rcvd = 0; + peer->last_disassoc_rcvd = 0; + peer->last_deauth_rcvd = 0; + + qdf_atomic_init(&peer->fw_pn_check); +} + +void +ol_rx_peer_cleanup(struct ol_txrx_vdev_t *vdev, struct ol_txrx_peer_t *peer) +{ + peer->keyinstalled = 0; + peer->last_assoc_rcvd = 0; + peer->last_disassoc_rcvd = 0; + peer->last_deauth_rcvd = 0; + ol_rx_reorder_peer_cleanup(vdev, peer); +} + +/* + * Free frames including both rx descriptors and buffers + */ +void ol_rx_frames_free(htt_pdev_handle htt_pdev, qdf_nbuf_t frames) +{ + qdf_nbuf_t next, frag = frames; + + while (frag) { + next = qdf_nbuf_next(frag); + htt_rx_desc_frame_free(htt_pdev, frag); + frag = next; + } +} + +#ifndef CONFIG_HL_SUPPORT +void +ol_rx_in_order_indication_handler(ol_txrx_pdev_handle pdev, + qdf_nbuf_t rx_ind_msg, + uint16_t peer_id, + uint8_t tid, uint8_t is_offload) +{ + struct ol_txrx_vdev_t *vdev = NULL; + struct ol_txrx_peer_t *peer = NULL; + htt_pdev_handle htt_pdev = NULL; + int status; + qdf_nbuf_t head_msdu = NULL, tail_msdu = NULL; + uint8_t *rx_ind_data; + uint32_t *msg_word; + uint32_t msdu_count; +#ifdef WDI_EVENT_ENABLE + uint8_t pktlog_bit; +#endif + uint32_t filled = 0; + + if (pdev) { + if (qdf_unlikely(QDF_GLOBAL_MONITOR_MODE == cds_get_conparam())) + peer = pdev->self_peer; + else + peer = ol_txrx_peer_find_by_id(pdev, peer_id); + htt_pdev = pdev->htt_pdev; + } else { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "%s: Invalid pdev passed!\n", __func__); + qdf_assert_always(pdev); + return; + } + +#if defined(HELIUMPLUS_DEBUG) + qdf_print("%s %d: rx_ind_msg 0x%p peer_id %d tid %d is_offload %d\n", + __func__, __LINE__, rx_ind_msg, peer_id, tid, is_offload); +#endif + +#ifdef WDI_EVENT_ENABLE + pktlog_bit = (htt_rx_amsdu_rx_in_order_get_pktlog(rx_ind_msg) == 0x01); +#endif + + rx_ind_data = qdf_nbuf_data(rx_ind_msg); + msg_word = (uint32_t *)rx_ind_data; + /* Get the total number of MSDUs */ + msdu_count = HTT_RX_IN_ORD_PADDR_IND_MSDU_CNT_GET(*(msg_word + 1)); + + ol_rx_ind_record_event(msdu_count, OL_RX_INDICATION_POP_START); + + /* + * Get a linked list of the MSDUs in the rx in order indication. + * This also attaches each rx MSDU descriptor to the + * corresponding rx MSDU network buffer. + */ + status = htt_rx_amsdu_pop(htt_pdev, rx_ind_msg, &head_msdu, + &tail_msdu, &msdu_count); + ol_rx_ind_record_event(status, OL_RX_INDICATION_POP_END); + + if (qdf_unlikely(0 == status)) { + TXRX_PRINT(TXRX_PRINT_LEVEL_WARN, + "%s: Pop status is 0, returning here\n", __func__); + return; + } + + /* Replenish the rx buffer ring first to provide buffers to the target + rather than waiting for the indeterminate time taken by the OS + to consume the rx frames */ + filled = htt_rx_msdu_buff_in_order_replenish(htt_pdev, msdu_count); + ol_rx_ind_record_event(filled, OL_RX_INDICATION_BUF_REPLENISH); + + if (!head_msdu) { + TXRX_PRINT(TXRX_PRINT_LEVEL_WARN, + "%s: No packet to send to HDD\n", __func__); + return; + } + + /* Send the chain of MSDUs to the OS */ + /* rx_opt_proc takes a NULL-terminated list of msdu netbufs */ + qdf_nbuf_set_next(tail_msdu, NULL); + + /* Pktlog */ +#ifdef WDI_EVENT_ENABLE + ol_rx_send_pktlog_event(pdev, peer, head_msdu, pktlog_bit); +#endif + + /* if this is an offload indication, peer id is carried in the + rx buffer */ + if (peer) { + vdev = peer->vdev; + } else { + TXRX_PRINT(TXRX_PRINT_LEVEL_INFO2, + "%s: Couldn't find peer from ID 0x%x\n", + __func__, peer_id); + while (head_msdu) { + qdf_nbuf_t msdu = head_msdu; + head_msdu = qdf_nbuf_next(head_msdu); + TXRX_STATS_MSDU_INCR(pdev, + rx.dropped_peer_invalid, msdu); + htt_rx_desc_frame_free(htt_pdev, msdu); + } + return; + } + + peer->rx_opt_proc(vdev, peer, tid, head_msdu); +} +#endif + +/** + * ol_rx_pkt_dump_call() - updates status and + * calls packetdump callback to log rx packet + * + * @msdu: rx packet + * @peer_id: peer id + * @status: status of rx packet + * + * This function is used to update the status of rx packet + * and then calls packetdump callback to log that packet. + * + * Return: None + * + */ +void ol_rx_pkt_dump_call( + qdf_nbuf_t msdu, + uint8_t peer_id, + uint8_t status) +{ + v_CONTEXT_t vos_context; + ol_txrx_pdev_handle pdev; + struct ol_txrx_peer_t *peer = NULL; + tp_ol_packetdump_cb packetdump_cb; + + vos_context = cds_get_global_context(); + pdev = cds_get_context(QDF_MODULE_ID_TXRX); + + if (!pdev) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "%s: pdev is NULL", __func__); + return; + } + + peer = ol_txrx_peer_find_by_id(pdev, peer_id); + if (!peer) { + TXRX_PRINT(TXRX_PRINT_LEVEL_INFO1, + "%s: peer with peer id %d is NULL", __func__, + peer_id); + return; + } + + packetdump_cb = pdev->ol_rx_packetdump_cb; + if (packetdump_cb) + packetdump_cb(msdu, status, peer->vdev->vdev_id, RX_DATA_PKT); +} + +/* the msdu_list passed here must be NULL terminated */ +void +ol_rx_in_order_deliver(struct ol_txrx_vdev_t *vdev, + struct ol_txrx_peer_t *peer, + unsigned tid, qdf_nbuf_t msdu_list) +{ + qdf_nbuf_t msdu; + + msdu = msdu_list; + /* + * Currently, this does not check each MSDU to see whether it requires + * special handling. MSDUs that need special handling (example: IGMP + * frames) should be sent via a seperate HTT message. Also, this does + * not do rx->tx forwarding or filtering. + */ + + while (msdu) { + qdf_nbuf_t next = qdf_nbuf_next(msdu); + + DPTRACE(qdf_dp_trace(msdu, + QDF_DP_TRACE_RX_TXRX_PACKET_PTR_RECORD, + qdf_nbuf_data_addr(msdu), + sizeof(qdf_nbuf_data(msdu)), QDF_RX)); + + OL_RX_PEER_STATS_UPDATE(peer, msdu); + OL_RX_ERR_STATISTICS_1(vdev->pdev, vdev, peer, rx_desc, + OL_RX_ERR_NONE); + TXRX_STATS_MSDU_INCR(vdev->pdev, rx.delivered, msdu); + + msdu = next; + } + + ol_txrx_frms_dump("rx delivering:", + pdev, deliver_list_head, + ol_txrx_frm_dump_tcp_seq | ol_txrx_frm_dump_contents, + 0 /* don't print contents */); + + ol_rx_data_process(peer, msdu_list); +} + +void ol_rx_log_packet(htt_pdev_handle htt_pdev, + uint8_t peer_id, qdf_nbuf_t msdu) +{ + struct ol_txrx_peer_t *peer; + + peer = ol_txrx_peer_find_by_id(htt_pdev->txrx_pdev, peer_id); + if (peer) + qdf_dp_trace_log_pkt(peer->vdev->vdev_id, msdu, QDF_RX); +} + +#ifndef CONFIG_HL_SUPPORT +void +ol_rx_offload_paddr_deliver_ind_handler(htt_pdev_handle htt_pdev, + uint32_t msdu_count, + uint32_t *msg_word) +{ + int vdev_id, peer_id, tid; + qdf_nbuf_t head_buf, tail_buf, buf; + struct ol_txrx_peer_t *peer; + uint8_t fw_desc; + int msdu_iter = 0; + + while (msdu_count) { + htt_rx_offload_paddr_msdu_pop_ll(htt_pdev, msg_word, msdu_iter, + &vdev_id, &peer_id, &tid, + &fw_desc, &head_buf, + &tail_buf); + + peer = ol_txrx_peer_find_by_id(htt_pdev->txrx_pdev, peer_id); + if (peer) { + QDF_NBUF_CB_DP_TRACE_PRINT(head_buf) = false; + qdf_dp_trace_set_track(head_buf, QDF_RX); + QDF_NBUF_CB_TX_PACKET_TRACK(head_buf) = + QDF_NBUF_TX_PKT_DATA_TRACK; + qdf_dp_trace_log_pkt(peer->vdev->vdev_id, + head_buf, QDF_RX); + DPTRACE(qdf_dp_trace(head_buf, + QDF_DP_TRACE_RX_OFFLOAD_HTT_PACKET_PTR_RECORD, + qdf_nbuf_data_addr(head_buf), + sizeof(qdf_nbuf_data(head_buf)), QDF_RX)); + ol_rx_data_process(peer, head_buf); + } else { + buf = head_buf; + while (1) { + qdf_nbuf_t next; + next = qdf_nbuf_next(buf); + htt_rx_desc_frame_free(htt_pdev, buf); + if (buf == tail_buf) + break; + buf = next; + } + } + msdu_iter++; + msdu_count--; + } + htt_rx_msdu_buff_replenish(htt_pdev); +} +#endif + +/** + * ol_htt_mon_note_chan() - Update monitor channel information + * @pdev: handle to the physical device + * @mon_ch: Monitor channel + * + * Return: None + */ +void ol_htt_mon_note_chan(ol_txrx_pdev_handle pdev, int mon_ch) +{ + htt_rx_mon_note_capture_channel(pdev->htt_pdev, mon_ch); +} + +#ifdef NEVERDEFINED +/** + * @brief populates vow ext stats in given network buffer. + * @param msdu - network buffer handle + * @param pdev - handle to htt dev. + */ +void ol_ath_add_vow_extstats(htt_pdev_handle pdev, qdf_nbuf_t msdu) +{ + /* FIX THIS: + * txrx should not be directly using data types (scn) + * that are internal to other modules. + */ + struct ol_ath_softc_net80211 *scn = + (struct ol_ath_softc_net80211 *)pdev->ctrl_pdev; + + if (scn->vow_extstats == 0) { + return; + } else { + uint8_t *data, *l3_hdr, *bp; + uint16_t ethertype; + int offset; + struct vow_extstats vowstats; + + data = qdf_nbuf_data(msdu); + + offset = ETHERNET_ADDR_LEN * 2; + l3_hdr = data + ETHERNET_HDR_LEN; + ethertype = (data[offset] << 8) | data[offset + 1]; + if (ethertype == ETHERTYPE_IPV4) { + offset = IPV4_HDR_OFFSET_PROTOCOL; + if ((l3_hdr[offset] == IP_PROTOCOL_UDP) && + (l3_hdr[0] == IP_VER4_N_NO_EXTRA_HEADERS)) { + bp = data + EXT_HDR_OFFSET; + + if ((data[RTP_HDR_OFFSET] == UDP_PDU_RTP_EXT) && + (bp[0] == 0x12) && + (bp[1] == 0x34) && + (bp[2] == 0x00) && (bp[3] == 0x08)) { + /* + * Clear UDP checksum so we do not have + * to recalculate it + * after filling in status fields. + */ + data[UDP_CKSUM_OFFSET] = 0; + data[(UDP_CKSUM_OFFSET + 1)] = 0; + + bp += IPERF3_DATA_OFFSET; + + htt_rx_get_vowext_stats(msdu, + &vowstats); + + /* control channel RSSI */ + *bp++ = vowstats.rx_rssi_ctl0; + *bp++ = vowstats.rx_rssi_ctl1; + *bp++ = vowstats.rx_rssi_ctl2; + + /* rx rate info */ + *bp++ = vowstats.rx_bw; + *bp++ = vowstats.rx_sgi; + *bp++ = vowstats.rx_nss; + + *bp++ = vowstats.rx_rssi_comb; + /* rsflags */ + *bp++ = vowstats.rx_rs_flags; + + /* Time stamp Lo */ + *bp++ = (uint8_t) + ((vowstats. + rx_macTs & 0x0000ff00) >> 8); + *bp++ = (uint8_t) + (vowstats.rx_macTs & 0x0000ff); + /* rx phy errors */ + *bp++ = (uint8_t) + ((scn->chan_stats. + phy_err_cnt >> 8) & 0xff); + *bp++ = + (uint8_t) (scn->chan_stats. + phy_err_cnt & 0xff); + /* rx clear count */ + *bp++ = (uint8_t) + ((scn->mib_cycle_cnts. + rx_clear_count >> 24) & 0xff); + *bp++ = (uint8_t) + ((scn->mib_cycle_cnts. + rx_clear_count >> 16) & 0xff); + *bp++ = (uint8_t) + ((scn->mib_cycle_cnts. + rx_clear_count >> 8) & 0xff); + *bp++ = (uint8_t) + (scn->mib_cycle_cnts. + rx_clear_count & 0xff); + /* rx cycle count */ + *bp++ = (uint8_t) + ((scn->mib_cycle_cnts. + cycle_count >> 24) & 0xff); + *bp++ = (uint8_t) + ((scn->mib_cycle_cnts. + cycle_count >> 16) & 0xff); + *bp++ = (uint8_t) + ((scn->mib_cycle_cnts. + cycle_count >> 8) & 0xff); + *bp++ = (uint8_t) + (scn->mib_cycle_cnts. + cycle_count & 0xff); + + *bp++ = vowstats.rx_ratecode; + *bp++ = vowstats.rx_moreaggr; + + /* sequence number */ + *bp++ = (uint8_t) + ((vowstats.rx_seqno >> 8) & + 0xff); + *bp++ = (uint8_t) + (vowstats.rx_seqno & 0xff); + } + } + } + } +} + +#endif diff --git a/drivers/staging/qcacld-3.0/core/dp/txrx/ol_rx.h b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_rx.h new file mode 100644 index 0000000000000000000000000000000000000000..09a5401a75f40a795eda1b0a63fa6a2b5c7ff8bb --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_rx.h @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2011, 2014-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef _OL_RX__H_ +#define _OL_RX__H_ + +#include /* qdf_nbuf_t */ +#include /* htt_pdev_handle */ +#include /* ol_txrx_vdev_t */ + +void +ol_rx_deliver(struct ol_txrx_vdev_t *vdev, + struct ol_txrx_peer_t *peer, unsigned tid, qdf_nbuf_t head_msdu); + +void +ol_rx_discard(struct ol_txrx_vdev_t *vdev, + struct ol_txrx_peer_t *peer, unsigned tid, qdf_nbuf_t head_msdu); + +void ol_rx_frames_free(htt_pdev_handle htt_pdev, qdf_nbuf_t frames); + +void ol_rx_peer_init(struct ol_txrx_pdev_t *pdev, struct ol_txrx_peer_t *peer); + +void +ol_rx_peer_cleanup(struct ol_txrx_vdev_t *vdev, struct ol_txrx_peer_t *peer); + +void ol_rx_send_pktlog_event(struct ol_txrx_pdev_t *pdev, + struct ol_txrx_peer_t *peer, qdf_nbuf_t msdu, uint8_t pktlog_bit); + + +void +ol_rx_in_order_deliver(struct ol_txrx_vdev_t *vdev, + struct ol_txrx_peer_t *peer, + unsigned tid, qdf_nbuf_t head_msdu); + +void ol_rx_log_packet(htt_pdev_handle htt_pdev, + uint8_t peer_id, qdf_nbuf_t msdu); + +#ifndef CONFIG_HL_SUPPORT +void +ol_rx_offload_paddr_deliver_ind_handler(htt_pdev_handle htt_pdev, + uint32_t msdu_count, + uint32_t *msg_word); +#endif + +void ol_rx_update_histogram_stats(uint32_t msdu_count, + uint8_t frag_ind, uint8_t offload_ind); + +void +ol_rx_mic_error_handler( + ol_txrx_pdev_handle pdev, + u_int8_t tid, + u_int16_t peer_id, + void *msdu_desc, + qdf_nbuf_t msdu); + +#endif /* _OL_RX__H_ */ diff --git a/drivers/staging/qcacld-3.0/core/dp/txrx/ol_rx_defrag.c b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_rx_defrag.c new file mode 100644 index 0000000000000000000000000000000000000000..0da09609cd922433e4026e5f73a38016a34c7e7e --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_rx_defrag.c @@ -0,0 +1,1287 @@ +/* + * Copyright (c) 2011-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/*- + * Copyright (c) 2002-2007 Sam Leffler, Errno Consulting + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* qdf_system_time */ + +#define DEFRAG_IEEE80211_ADDR_EQ(a1, a2) \ + (!qdf_mem_cmp(a1, a2, IEEE80211_ADDR_LEN)) + +#define DEFRAG_IEEE80211_ADDR_COPY(dst, src) \ + qdf_mem_copy(dst, src, IEEE80211_ADDR_LEN) + +#define DEFRAG_IEEE80211_QOS_HAS_SEQ(wh) \ + (((wh)->i_fc[0] & \ + (IEEE80211_FC0_TYPE_MASK | IEEE80211_FC0_SUBTYPE_QOS)) == \ + (IEEE80211_FC0_TYPE_DATA | IEEE80211_FC0_SUBTYPE_QOS)) + +#define DEFRAG_IEEE80211_QOS_GET_TID(_x) \ + ((_x)->i_qos[0] & IEEE80211_QOS_TID) + +const struct ol_rx_defrag_cipher f_ccmp = { + "AES-CCM", + IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN + IEEE80211_WEP_EXTIVLEN, + IEEE80211_WEP_MICLEN, + 0, +}; + +const struct ol_rx_defrag_cipher f_tkip = { + "TKIP", + IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN + IEEE80211_WEP_EXTIVLEN, + IEEE80211_WEP_CRCLEN, + IEEE80211_WEP_MICLEN, +}; + +const struct ol_rx_defrag_cipher f_wep = { + "WEP", + IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN, + IEEE80211_WEP_CRCLEN, + 0, +}; + +#if defined(CONFIG_HL_SUPPORT) + +/** + * ol_rx_frag_get_mac_hdr() - retrieve mac header + * @htt_pdev: pointer to htt pdev handle + * @frag: rx fragment + * + * Return: pointer to ieee mac header of frag + */ +static struct ieee80211_frame *ol_rx_frag_get_mac_hdr( + htt_pdev_handle htt_pdev, qdf_nbuf_t frag) +{ + void *rx_desc; + int rx_desc_len; + + rx_desc = htt_rx_msdu_desc_retrieve(htt_pdev, frag); + rx_desc_len = htt_rx_msdu_rx_desc_size_hl(htt_pdev, rx_desc); + return (struct ieee80211_frame *)(qdf_nbuf_data(frag) + rx_desc_len); +} + +/** + * ol_rx_frag_pull_hdr() - point to payload of rx frag + * @htt_pdev: pointer to htt pdev handle + * @frag: rx fragment + * @hdrsize: header size + * + * Return: None + */ +static void ol_rx_frag_pull_hdr(htt_pdev_handle htt_pdev, + qdf_nbuf_t frag, int hdrsize) +{ + void *rx_desc; + int rx_desc_len; + + rx_desc = htt_rx_msdu_desc_retrieve(htt_pdev, frag); + rx_desc_len = htt_rx_msdu_rx_desc_size_hl(htt_pdev, rx_desc); + qdf_nbuf_pull_head(frag, rx_desc_len + hdrsize); +} + +/** + * ol_rx_frag_desc_adjust() - adjust rx frag descriptor position + * @pdev: pointer to txrx handle + * @msdu: msdu + * @rx_desc_old_position: rx descriptor old position + * @ind_old_position:index of old position + * @rx_desc_len: rx desciptor length + * + * Return: None + */ +static void +ol_rx_frag_desc_adjust(ol_txrx_pdev_handle pdev, + qdf_nbuf_t msdu, + void **rx_desc_old_position, + void **ind_old_position, int *rx_desc_len) +{ + *rx_desc_old_position = htt_rx_msdu_desc_retrieve(pdev->htt_pdev, + msdu); + *ind_old_position = *rx_desc_old_position - HTT_RX_IND_HL_BYTES; + *rx_desc_len = htt_rx_msdu_rx_desc_size_hl(pdev->htt_pdev, + *rx_desc_old_position); +} + +/** + * ol_rx_frag_restructure() - point to payload for HL + * @pdev: physical device object + * @msdu: the buffer containing the MSDU payload + * @rx_desc_old_position: rx MSDU descriptor + * @ind_old_position: rx msdu indication + * @f_type: pointing to rx defrag cipher + * @rx_desc_len: length by which rx descriptor to move + * + * Return: None + */ +static void +ol_rx_frag_restructure( + ol_txrx_pdev_handle pdev, + qdf_nbuf_t msdu, + void *rx_desc_old_position, + void *ind_old_position, + const struct ol_rx_defrag_cipher *f_type, + int rx_desc_len) +{ + if ((ind_old_position == NULL) || (rx_desc_old_position == NULL)) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "ind_old_position,rx_desc_old_position is NULL\n"); + ASSERT(0); + return; + } + /* move rx description*/ + qdf_mem_move(rx_desc_old_position + f_type->ic_header, + rx_desc_old_position, rx_desc_len); + /* move rx indication*/ + qdf_mem_move(ind_old_position + f_type->ic_header, ind_old_position, + HTT_RX_IND_HL_BYTES); +} + +/** + * ol_rx_get_desc_len() - point to payload for HL + * @htt_pdev: the HTT instance the rx data was received on + * @wbuf: buffer containing the MSDU payload + * @rx_desc_old_position: rx MSDU descriptor + * + * Return: Return the HL rx desc size + */ +static +int ol_rx_get_desc_len(htt_pdev_handle htt_pdev, + qdf_nbuf_t wbuf, + void **rx_desc_old_position) +{ + int rx_desc_len = 0; + *rx_desc_old_position = htt_rx_msdu_desc_retrieve(htt_pdev, wbuf); + rx_desc_len = htt_rx_msdu_rx_desc_size_hl(htt_pdev, + *rx_desc_old_position); + + return rx_desc_len; +} + +/** + * ol_rx_defrag_push_rx_desc() - point to payload for HL + * @nbuf: buffer containing the MSDU payload + * @rx_desc_old_position: rx MSDU descriptor + * @ind_old_position: rx msdu indication + * @rx_desc_len: HL rx desc size + * + * Return: Return the HL rx desc size + */ +static +void ol_rx_defrag_push_rx_desc(qdf_nbuf_t nbuf, + void *rx_desc_old_position, + void *ind_old_position, + int rx_desc_len) +{ + qdf_nbuf_push_head(nbuf, rx_desc_len); + qdf_mem_move( + qdf_nbuf_data(nbuf), rx_desc_old_position, rx_desc_len); + qdf_mem_move( + qdf_nbuf_data(nbuf) - HTT_RX_IND_HL_BYTES, ind_old_position, + HTT_RX_IND_HL_BYTES); +} +#else + +static inline struct ieee80211_frame *ol_rx_frag_get_mac_hdr( + htt_pdev_handle htt_pdev, + qdf_nbuf_t frag) +{ + return + (struct ieee80211_frame *) qdf_nbuf_data(frag); +} + +static inline void ol_rx_frag_pull_hdr(htt_pdev_handle htt_pdev, + qdf_nbuf_t frag, int hdrsize) +{ + qdf_nbuf_pull_head(frag, hdrsize); +} + +static inline void +ol_rx_frag_desc_adjust(ol_txrx_pdev_handle pdev, + qdf_nbuf_t msdu, + void **rx_desc_old_position, + void **ind_old_position, int *rx_desc_len) +{ + *rx_desc_old_position = NULL; + *ind_old_position = NULL; + *rx_desc_len = 0; +} + +static inline void +ol_rx_frag_restructure( + ol_txrx_pdev_handle pdev, + qdf_nbuf_t msdu, + void *rx_desc_old_position, + void *ind_old_position, + const struct ol_rx_defrag_cipher *f_type, + int rx_desc_len) +{ + /* no op */ + return; +} + +static inline +int ol_rx_get_desc_len(htt_pdev_handle htt_pdev, + qdf_nbuf_t wbuf, + void **rx_desc_old_position) +{ + return 0; +} + +static inline +void ol_rx_defrag_push_rx_desc(qdf_nbuf_t nbuf, + void *rx_desc_old_position, + void *ind_old_position, + int rx_desc_len) +{ + return; +} +#endif /* CONFIG_HL_SUPPORT */ + +#ifdef WDI_EVENT_ENABLE +static inline +void ol_rx_frag_send_pktlog_event(struct ol_txrx_pdev_t *pdev, + struct ol_txrx_peer_t *peer, qdf_nbuf_t msdu, uint8_t pktlog_bit) +{ + ol_rx_send_pktlog_event(pdev, peer, msdu, pktlog_bit); +} + +#else +static inline +void ol_rx_frag_send_pktlog_event(struct ol_txrx_pdev_t *pdev, + struct ol_txrx_peer_t *peer, qdf_nbuf_t msdu, uint8_t pktlog_bit) +{ +} + +#endif + +/* + * Process incoming fragments + */ +void +ol_rx_frag_indication_handler(ol_txrx_pdev_handle pdev, + qdf_nbuf_t rx_frag_ind_msg, + uint16_t peer_id, uint8_t tid) +{ + uint16_t seq_num; + int seq_num_start, seq_num_end; + struct ol_txrx_peer_t *peer; + htt_pdev_handle htt_pdev; + qdf_nbuf_t head_msdu, tail_msdu; + void *rx_mpdu_desc; + uint8_t pktlog_bit; + uint32_t msdu_count = 0; + + htt_pdev = pdev->htt_pdev; + peer = ol_txrx_peer_find_by_id(pdev, peer_id); + + if (!ol_cfg_is_full_reorder_offload(pdev->ctrl_pdev) && + htt_rx_ind_flush(pdev->htt_pdev, rx_frag_ind_msg) && peer) { + htt_rx_frag_ind_flush_seq_num_range(pdev->htt_pdev, + rx_frag_ind_msg, + &seq_num_start, + &seq_num_end); + /* + * Assuming flush indication for frags sent from target is + * separate from normal frames + */ + ol_rx_reorder_flush_frag(htt_pdev, peer, tid, seq_num_start); + } + pktlog_bit = + (htt_rx_amsdu_rx_in_order_get_pktlog(rx_frag_ind_msg) == 0x01); + if (peer) { + htt_rx_frag_pop(htt_pdev, rx_frag_ind_msg, &head_msdu, + &tail_msdu, &msdu_count); + qdf_assert(head_msdu == tail_msdu); + if (ol_cfg_is_full_reorder_offload(pdev->ctrl_pdev)) { + rx_mpdu_desc = + htt_rx_mpdu_desc_list_next(htt_pdev, head_msdu); + } else { + rx_mpdu_desc = + htt_rx_mpdu_desc_list_next(htt_pdev, + rx_frag_ind_msg); + } + seq_num = htt_rx_mpdu_desc_seq_num(htt_pdev, rx_mpdu_desc); + OL_RX_ERR_STATISTICS_1(pdev, peer->vdev, peer, rx_mpdu_desc, + OL_RX_ERR_NONE_FRAG); + ol_rx_frag_send_pktlog_event(pdev, peer, head_msdu, pktlog_bit); + ol_rx_reorder_store_frag(pdev, peer, tid, seq_num, head_msdu); + } else { + /* invalid frame - discard it */ + htt_rx_frag_pop(htt_pdev, rx_frag_ind_msg, &head_msdu, + &tail_msdu, &msdu_count); + if (ol_cfg_is_full_reorder_offload(pdev->ctrl_pdev)) + htt_rx_msdu_desc_retrieve(htt_pdev, head_msdu); + else + htt_rx_mpdu_desc_list_next(htt_pdev, rx_frag_ind_msg); + + ol_rx_frag_send_pktlog_event(pdev, peer, head_msdu, pktlog_bit); + htt_rx_desc_frame_free(htt_pdev, head_msdu); + } + /* request HTT to provide new rx MSDU buffers for the target to fill. */ + htt_rx_msdu_buff_replenish(htt_pdev); +} + +/* + * Flushing fragments + */ +void +ol_rx_reorder_flush_frag(htt_pdev_handle htt_pdev, + struct ol_txrx_peer_t *peer, unsigned tid, int seq_num) +{ + struct ol_rx_reorder_array_elem_t *rx_reorder_array_elem; + int seq; + + seq = seq_num & peer->tids_rx_reorder[tid].win_sz_mask; + rx_reorder_array_elem = &peer->tids_rx_reorder[tid].array[seq]; + if (rx_reorder_array_elem->head) { + ol_rx_frames_free(htt_pdev, rx_reorder_array_elem->head); + rx_reorder_array_elem->head = NULL; + rx_reorder_array_elem->tail = NULL; + } +} + +/* + * Reorder and store fragments + */ +void +ol_rx_reorder_store_frag(ol_txrx_pdev_handle pdev, + struct ol_txrx_peer_t *peer, + unsigned tid, uint16_t seq_num, qdf_nbuf_t frag) +{ + struct ieee80211_frame *fmac_hdr, *mac_hdr; + uint8_t fragno, more_frag, all_frag_present = 0; + struct ol_rx_reorder_array_elem_t *rx_reorder_array_elem; + uint16_t frxseq, rxseq, seq; + htt_pdev_handle htt_pdev = pdev->htt_pdev; + + seq = seq_num & peer->tids_rx_reorder[tid].win_sz_mask; + qdf_assert(seq == 0); + rx_reorder_array_elem = &peer->tids_rx_reorder[tid].array[seq]; + + mac_hdr = (struct ieee80211_frame *) + ol_rx_frag_get_mac_hdr(htt_pdev, frag); + rxseq = qdf_le16_to_cpu(*(uint16_t *) mac_hdr->i_seq) >> + IEEE80211_SEQ_SEQ_SHIFT; + fragno = qdf_le16_to_cpu(*(uint16_t *) mac_hdr->i_seq) & + IEEE80211_SEQ_FRAG_MASK; + more_frag = mac_hdr->i_fc[1] & IEEE80211_FC1_MORE_FRAG; + + if ((!more_frag) && (!fragno) && (!rx_reorder_array_elem->head)) { + ol_rx_fraglist_insert(htt_pdev, &rx_reorder_array_elem->head, + &rx_reorder_array_elem->tail, frag, &all_frag_present); + qdf_nbuf_set_next(frag, NULL); + ol_rx_defrag(pdev, peer, tid, rx_reorder_array_elem->head); + rx_reorder_array_elem->head = NULL; + rx_reorder_array_elem->tail = NULL; + return; + } + if (rx_reorder_array_elem->head) { + fmac_hdr = (struct ieee80211_frame *) + ol_rx_frag_get_mac_hdr(htt_pdev, + rx_reorder_array_elem->head); + frxseq = qdf_le16_to_cpu(*(uint16_t *) fmac_hdr->i_seq) >> + IEEE80211_SEQ_SEQ_SHIFT; + if (rxseq != frxseq + || !DEFRAG_IEEE80211_ADDR_EQ(mac_hdr->i_addr1, + fmac_hdr->i_addr1) + || !DEFRAG_IEEE80211_ADDR_EQ(mac_hdr->i_addr2, + fmac_hdr->i_addr2)) { + ol_rx_frames_free(htt_pdev, + rx_reorder_array_elem->head); + rx_reorder_array_elem->head = NULL; + rx_reorder_array_elem->tail = NULL; + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "\n ol_rx_reorder_store: %s mismatch \n", + (rxseq == frxseq) + ? "address" + : "seq number"); + } + } + + ol_rx_fraglist_insert(htt_pdev, &rx_reorder_array_elem->head, + &rx_reorder_array_elem->tail, frag, + &all_frag_present); + + if (pdev->rx.flags.defrag_timeout_check) + ol_rx_defrag_waitlist_remove(peer, tid); + + if (all_frag_present) { + ol_rx_defrag(pdev, peer, tid, rx_reorder_array_elem->head); + rx_reorder_array_elem->head = NULL; + rx_reorder_array_elem->tail = NULL; + peer->tids_rx_reorder[tid].defrag_timeout_ms = 0; + peer->tids_last_seq[tid] = seq_num; + } else if (pdev->rx.flags.defrag_timeout_check) { + uint32_t now_ms = qdf_system_ticks_to_msecs(qdf_system_ticks()); + + peer->tids_rx_reorder[tid].defrag_timeout_ms = + now_ms + pdev->rx.defrag.timeout_ms; + ol_rx_defrag_waitlist_add(peer, tid); + } +} + +/* + * Insert and store fragments + */ +void +ol_rx_fraglist_insert(htt_pdev_handle htt_pdev, + qdf_nbuf_t *head_addr, + qdf_nbuf_t *tail_addr, + qdf_nbuf_t frag, uint8_t *all_frag_present) +{ + qdf_nbuf_t next, prev = NULL, cur = *head_addr; + struct ieee80211_frame *mac_hdr, *cmac_hdr, *next_hdr, *lmac_hdr; + uint8_t fragno, cur_fragno, lfragno, next_fragno; + uint8_t last_morefrag = 1, count = 0; + + qdf_assert(frag); + + mac_hdr = (struct ieee80211_frame *) + ol_rx_frag_get_mac_hdr(htt_pdev, frag); + fragno = qdf_le16_to_cpu(*(uint16_t *) mac_hdr->i_seq) & + IEEE80211_SEQ_FRAG_MASK; + + if (!(*head_addr)) { + *head_addr = frag; + *tail_addr = frag; + qdf_nbuf_set_next(*tail_addr, NULL); + return; + } + /* For efficiency, compare with tail first */ + lmac_hdr = (struct ieee80211_frame *) + ol_rx_frag_get_mac_hdr(htt_pdev, *tail_addr); + lfragno = qdf_le16_to_cpu(*(uint16_t *) lmac_hdr->i_seq) & + IEEE80211_SEQ_FRAG_MASK; + if (fragno > lfragno) { + qdf_nbuf_set_next(*tail_addr, frag); + *tail_addr = frag; + qdf_nbuf_set_next(*tail_addr, NULL); + } else { + do { + cmac_hdr = (struct ieee80211_frame *) + ol_rx_frag_get_mac_hdr(htt_pdev, cur); + cur_fragno = + qdf_le16_to_cpu(*(uint16_t *) cmac_hdr->i_seq) & + IEEE80211_SEQ_FRAG_MASK; + prev = cur; + cur = qdf_nbuf_next(cur); + } while (fragno > cur_fragno); + + if (fragno == cur_fragno) { + htt_rx_desc_frame_free(htt_pdev, frag); + *all_frag_present = 0; + return; + } else { + qdf_nbuf_set_next(prev, frag); + qdf_nbuf_set_next(frag, cur); + } + } + next = qdf_nbuf_next(*head_addr); + lmac_hdr = (struct ieee80211_frame *)ol_rx_frag_get_mac_hdr(htt_pdev, + *tail_addr); + last_morefrag = lmac_hdr->i_fc[1] & IEEE80211_FC1_MORE_FRAG; + if (!last_morefrag) { + do { + next_hdr = + (struct ieee80211_frame *) + ol_rx_frag_get_mac_hdr(htt_pdev, next); + next_fragno = + qdf_le16_to_cpu(*(uint16_t *) next_hdr->i_seq) & + IEEE80211_SEQ_FRAG_MASK; + count++; + if (next_fragno != count) + break; + + next = qdf_nbuf_next(next); + } while (next); + + if (!next) { + *all_frag_present = 1; + return; + } + } + *all_frag_present = 0; +} + +/* + * add tid to pending fragment wait list + */ +void ol_rx_defrag_waitlist_add(struct ol_txrx_peer_t *peer, unsigned tid) +{ + struct ol_txrx_pdev_t *pdev = peer->vdev->pdev; + struct ol_rx_reorder_t *rx_reorder = &peer->tids_rx_reorder[tid]; + + TAILQ_INSERT_TAIL(&pdev->rx.defrag.waitlist, rx_reorder, + defrag_waitlist_elem); +} + +/* + * remove tid from pending fragment wait list + */ +void ol_rx_defrag_waitlist_remove(struct ol_txrx_peer_t *peer, unsigned tid) +{ + struct ol_txrx_pdev_t *pdev = peer->vdev->pdev; + struct ol_rx_reorder_t *rx_reorder = &peer->tids_rx_reorder[tid]; + + if (rx_reorder->defrag_waitlist_elem.tqe_next != NULL) { + + TAILQ_REMOVE(&pdev->rx.defrag.waitlist, rx_reorder, + defrag_waitlist_elem); + + rx_reorder->defrag_waitlist_elem.tqe_next = NULL; + rx_reorder->defrag_waitlist_elem.tqe_prev = NULL; + } else if (rx_reorder->defrag_waitlist_elem.tqe_next != NULL) { + TXRX_PRINT(TXRX_PRINT_LEVEL_FATAL_ERR, + "waitlist->tqe_prv = NULL\n"); + QDF_ASSERT(0); + rx_reorder->defrag_waitlist_elem.tqe_next = NULL; + } +} + +#ifndef container_of +#define container_of(ptr, type, member) \ + ((type *)((char *)(ptr) - (char *)(&((type *)0)->member))) +#endif + +/* + * flush stale fragments from the waitlist + */ +void ol_rx_defrag_waitlist_flush(struct ol_txrx_pdev_t *pdev) +{ + struct ol_rx_reorder_t *rx_reorder, *tmp; + uint32_t now_ms = qdf_system_ticks_to_msecs(qdf_system_ticks()); + + TAILQ_FOREACH_SAFE(rx_reorder, &pdev->rx.defrag.waitlist, + defrag_waitlist_elem, tmp) { + struct ol_txrx_peer_t *peer; + struct ol_rx_reorder_t *rx_reorder_base; + unsigned tid; + + if (rx_reorder->defrag_timeout_ms > now_ms) + break; + + tid = rx_reorder->tid; + /* 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]); + + ol_rx_defrag_waitlist_remove(peer, tid); + ol_rx_reorder_flush_frag(pdev->htt_pdev, peer, tid, + 0 /* frags always stored at seq 0 */); + } +} + +/* + * Handling security checking and processing fragments + */ +void +ol_rx_defrag(ol_txrx_pdev_handle pdev, + struct ol_txrx_peer_t *peer, unsigned tid, qdf_nbuf_t frag_list) +{ + struct ol_txrx_vdev_t *vdev = NULL; + qdf_nbuf_t tmp_next, msdu, prev = NULL, cur = frag_list; + uint8_t index, tkip_demic = 0; + uint16_t hdr_space; + void *rx_desc; + struct ieee80211_frame *wh; + uint8_t key[DEFRAG_IEEE80211_KEY_LEN]; + + htt_pdev_handle htt_pdev = pdev->htt_pdev; + vdev = peer->vdev; + + /* bypass defrag for safe mode */ + if (vdev->safemode) { + if (ol_cfg_is_full_reorder_offload(pdev->ctrl_pdev)) + ol_rx_in_order_deliver(vdev, peer, tid, frag_list); + else + ol_rx_deliver(vdev, peer, tid, frag_list); + return; + } + + while (cur) { + tmp_next = qdf_nbuf_next(cur); + qdf_nbuf_set_next(cur, NULL); + if (!ol_rx_pn_check_base(vdev, peer, tid, cur)) { + /* PN check failed,discard frags */ + if (prev) { + qdf_nbuf_set_next(prev, NULL); + ol_rx_frames_free(htt_pdev, frag_list); + } + ol_rx_frames_free(htt_pdev, tmp_next); + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "ol_rx_defrag: PN Check failed\n"); + return; + } + /* remove FCS from each fragment */ + qdf_nbuf_trim_tail(cur, DEFRAG_IEEE80211_FCS_LEN); + prev = cur; + qdf_nbuf_set_next(cur, tmp_next); + cur = tmp_next; + } + cur = frag_list; + wh = (struct ieee80211_frame *)ol_rx_frag_get_mac_hdr(htt_pdev, cur); + hdr_space = ol_rx_frag_hdrsize(wh); + rx_desc = htt_rx_msdu_desc_retrieve(htt_pdev, frag_list); + qdf_assert(htt_rx_msdu_has_wlan_mcast_flag(htt_pdev, rx_desc)); + index = htt_rx_msdu_is_wlan_mcast(htt_pdev, rx_desc) ? + txrx_sec_mcast : txrx_sec_ucast; + + switch (peer->security[index].sec_type) { + case htt_sec_type_tkip: + tkip_demic = 1; + /* fall-through to rest of tkip ops */ + case htt_sec_type_tkip_nomic: + while (cur) { + tmp_next = qdf_nbuf_next(cur); + if (!ol_rx_frag_tkip_decap(pdev, cur, hdr_space)) { + /* TKIP decap failed, discard frags */ + ol_rx_frames_free(htt_pdev, frag_list); + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "\n ol_rx_defrag: TKIP decap failed\n"); + return; + } + cur = tmp_next; + } + break; + + case htt_sec_type_aes_ccmp: + while (cur) { + tmp_next = qdf_nbuf_next(cur); + if (!ol_rx_frag_ccmp_demic(pdev, cur, hdr_space)) { + /* CCMP demic failed, discard frags */ + ol_rx_frames_free(htt_pdev, frag_list); + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "\n ol_rx_defrag: CCMP demic failed\n"); + return; + } + if (!ol_rx_frag_ccmp_decap(pdev, cur, hdr_space)) { + /* CCMP decap failed, discard frags */ + ol_rx_frames_free(htt_pdev, frag_list); + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "\n ol_rx_defrag: CCMP decap failed\n"); + return; + } + cur = tmp_next; + } + break; + + case htt_sec_type_wep40: + case htt_sec_type_wep104: + case htt_sec_type_wep128: + while (cur) { + tmp_next = qdf_nbuf_next(cur); + if (!ol_rx_frag_wep_decap(pdev, cur, hdr_space)) { + /* wep decap failed, discard frags */ + ol_rx_frames_free(htt_pdev, frag_list); + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "\n ol_rx_defrag: wep decap failed\n"); + return; + } + cur = tmp_next; + } + break; + + default: + break; + } + + msdu = ol_rx_defrag_decap_recombine(htt_pdev, frag_list, hdr_space); + if (!msdu) + return; + + if (tkip_demic) { + qdf_mem_copy(key, + peer->security[index].michael_key, + sizeof(peer->security[index].michael_key)); + if (!ol_rx_frag_tkip_demic(pdev, key, msdu, hdr_space)) { + htt_rx_desc_frame_free(htt_pdev, msdu); + ol_rx_err(pdev->ctrl_pdev, + vdev->vdev_id, peer->mac_addr.raw, tid, 0, + OL_RX_DEFRAG_ERR, msdu, NULL, 0); + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "\n ol_rx_defrag: TKIP demic failed\n"); + return; + } + } + wh = (struct ieee80211_frame *)ol_rx_frag_get_mac_hdr(htt_pdev, msdu); + if (DEFRAG_IEEE80211_QOS_HAS_SEQ(wh)) + ol_rx_defrag_qos_decap(pdev, msdu, hdr_space); + if (ol_cfg_frame_type(pdev->ctrl_pdev) == wlan_frm_fmt_802_3) + ol_rx_defrag_nwifi_to_8023(pdev, msdu); + + ol_rx_fwd_check(vdev, peer, tid, msdu); +} + +/* + * Handling TKIP processing for defragmentation + */ +int +ol_rx_frag_tkip_decap(ol_txrx_pdev_handle pdev, + qdf_nbuf_t msdu, uint16_t hdrlen) +{ + uint8_t *ivp, *origHdr; + + void *rx_desc_old_position = NULL; + void *ind_old_position = NULL; + int rx_desc_len = 0; + + ol_rx_frag_desc_adjust(pdev, + msdu, + &rx_desc_old_position, + &ind_old_position, &rx_desc_len); + /* Header should have extended IV */ + origHdr = (uint8_t *) (qdf_nbuf_data(msdu) + rx_desc_len); + + ivp = origHdr + hdrlen; + if (!(ivp[IEEE80211_WEP_IVLEN] & IEEE80211_WEP_EXTIV)) + return OL_RX_DEFRAG_ERR; + + qdf_mem_move(origHdr + f_tkip.ic_header, origHdr, hdrlen); + ol_rx_frag_restructure( + pdev, + msdu, + rx_desc_old_position, + ind_old_position, + &f_tkip, + rx_desc_len); + qdf_nbuf_pull_head(msdu, f_tkip.ic_header); + qdf_nbuf_trim_tail(msdu, f_tkip.ic_trailer); + return OL_RX_DEFRAG_OK; +} + +/* + * Handling WEP processing for defragmentation + */ +int +ol_rx_frag_wep_decap(ol_txrx_pdev_handle pdev, qdf_nbuf_t msdu, uint16_t hdrlen) +{ + uint8_t *origHdr; + void *rx_desc_old_position = NULL; + void *ind_old_position = NULL; + int rx_desc_len = 0; + + ol_rx_frag_desc_adjust(pdev, + msdu, + &rx_desc_old_position, + &ind_old_position, &rx_desc_len); + origHdr = (uint8_t *) (qdf_nbuf_data(msdu) + rx_desc_len); + qdf_mem_move(origHdr + f_wep.ic_header, origHdr, hdrlen); + ol_rx_frag_restructure( + pdev, + msdu, + rx_desc_old_position, + ind_old_position, + &f_wep, + rx_desc_len); + qdf_nbuf_pull_head(msdu, f_wep.ic_header); + qdf_nbuf_trim_tail(msdu, f_wep.ic_trailer); + return OL_RX_DEFRAG_OK; +} + +/* + * Verify and strip MIC from the frame. + */ +int +ol_rx_frag_tkip_demic(ol_txrx_pdev_handle pdev, const uint8_t *key, + qdf_nbuf_t msdu, uint16_t hdrlen) +{ + int status; + uint32_t pktlen; + uint8_t mic[IEEE80211_WEP_MICLEN]; + uint8_t mic0[IEEE80211_WEP_MICLEN]; + void *rx_desc_old_position = NULL; + void *ind_old_position = NULL; + int rx_desc_len = 0; + + ol_rx_frag_desc_adjust(pdev, + msdu, + &rx_desc_old_position, + &ind_old_position, &rx_desc_len); + + pktlen = ol_rx_defrag_len(msdu) - rx_desc_len; + + status = ol_rx_defrag_mic(pdev, key, msdu, hdrlen, + pktlen - (hdrlen + f_tkip.ic_miclen), mic); + if (status != OL_RX_DEFRAG_OK) + return OL_RX_DEFRAG_ERR; + + ol_rx_defrag_copydata(msdu, pktlen - f_tkip.ic_miclen + rx_desc_len, + f_tkip.ic_miclen, (caddr_t) mic0); + if (!qdf_mem_cmp(mic, mic0, f_tkip.ic_miclen)) + return OL_RX_DEFRAG_ERR; + + qdf_nbuf_trim_tail(msdu, f_tkip.ic_miclen); + return OL_RX_DEFRAG_OK; +} + +/* + * Handling CCMP processing for defragmentation + */ +int +ol_rx_frag_ccmp_decap(ol_txrx_pdev_handle pdev, + qdf_nbuf_t nbuf, uint16_t hdrlen) +{ + uint8_t *ivp, *origHdr; + void *rx_desc_old_position = NULL; + void *ind_old_position = NULL; + int rx_desc_len = 0; + + ol_rx_frag_desc_adjust(pdev, + nbuf, + &rx_desc_old_position, + &ind_old_position, &rx_desc_len); + + origHdr = (uint8_t *) (qdf_nbuf_data(nbuf) + rx_desc_len); + ivp = origHdr + hdrlen; + if (!(ivp[IEEE80211_WEP_IVLEN] & IEEE80211_WEP_EXTIV)) + return OL_RX_DEFRAG_ERR; + + qdf_mem_move(origHdr + f_ccmp.ic_header, origHdr, hdrlen); + ol_rx_frag_restructure( + pdev, + nbuf, + rx_desc_old_position, + ind_old_position, + &f_ccmp, + rx_desc_len); + qdf_nbuf_pull_head(nbuf, f_ccmp.ic_header); + + return OL_RX_DEFRAG_OK; +} + +/* + * Verify and strip MIC from the frame. + */ +int +ol_rx_frag_ccmp_demic(ol_txrx_pdev_handle pdev, + qdf_nbuf_t wbuf, uint16_t hdrlen) +{ + uint8_t *ivp, *origHdr; + void *rx_desc_old_position = NULL; + void *ind_old_position = NULL; + int rx_desc_len = 0; + + ol_rx_frag_desc_adjust(pdev, + wbuf, + &rx_desc_old_position, + &ind_old_position, &rx_desc_len); + + origHdr = (uint8_t *) (qdf_nbuf_data(wbuf) + rx_desc_len); + + ivp = origHdr + hdrlen; + if (!(ivp[IEEE80211_WEP_IVLEN] & IEEE80211_WEP_EXTIV)) + return OL_RX_DEFRAG_ERR; + + qdf_nbuf_trim_tail(wbuf, f_ccmp.ic_trailer); + + return OL_RX_DEFRAG_OK; +} + +/* + * Craft pseudo header used to calculate the MIC. + */ +void ol_rx_defrag_michdr(const struct ieee80211_frame *wh0, uint8_t hdr[]) +{ + const struct ieee80211_frame_addr4 *wh = + (const struct ieee80211_frame_addr4 *)wh0; + + switch (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) { + case IEEE80211_FC1_DIR_NODS: + DEFRAG_IEEE80211_ADDR_COPY(hdr, wh->i_addr1); /* DA */ + DEFRAG_IEEE80211_ADDR_COPY(hdr + IEEE80211_ADDR_LEN, + wh->i_addr2); + break; + case IEEE80211_FC1_DIR_TODS: + DEFRAG_IEEE80211_ADDR_COPY(hdr, wh->i_addr3); /* DA */ + DEFRAG_IEEE80211_ADDR_COPY(hdr + IEEE80211_ADDR_LEN, + wh->i_addr2); + break; + case IEEE80211_FC1_DIR_FROMDS: + DEFRAG_IEEE80211_ADDR_COPY(hdr, wh->i_addr1); /* DA */ + DEFRAG_IEEE80211_ADDR_COPY(hdr + IEEE80211_ADDR_LEN, + wh->i_addr3); + break; + case IEEE80211_FC1_DIR_DSTODS: + DEFRAG_IEEE80211_ADDR_COPY(hdr, wh->i_addr3); /* DA */ + DEFRAG_IEEE80211_ADDR_COPY(hdr + IEEE80211_ADDR_LEN, + wh->i_addr4); + break; + } + /* + * Bit 7 is IEEE80211_FC0_SUBTYPE_QOS for data frame, but + * it could also be set for deauth, disassoc, action, etc. for + * a mgt type frame. It comes into picture for MFP. + */ + if (wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_QOS) { + const struct ieee80211_qosframe *qwh = + (const struct ieee80211_qosframe *)wh; + hdr[12] = qwh->i_qos[0] & IEEE80211_QOS_TID; + } else { + hdr[12] = 0; + } + hdr[13] = hdr[14] = hdr[15] = 0; /* reserved */ +} + +/* + * Michael_mic for defragmentation + */ +int +ol_rx_defrag_mic(ol_txrx_pdev_handle pdev, + const uint8_t *key, + qdf_nbuf_t wbuf, + uint16_t off, uint16_t data_len, uint8_t mic[]) +{ + uint8_t hdr[16] = { 0, }; + uint32_t l, r; + const uint8_t *data; + uint32_t space; + void *rx_desc_old_position = NULL; + void *ind_old_position = NULL; + int rx_desc_len = 0; + htt_pdev_handle htt_pdev = pdev->htt_pdev; + + ol_rx_frag_desc_adjust(pdev, + wbuf, + &rx_desc_old_position, + &ind_old_position, &rx_desc_len); + + ol_rx_defrag_michdr((struct ieee80211_frame *)(qdf_nbuf_data(wbuf) + + rx_desc_len), hdr); + l = get_le32(key); + r = get_le32(key + 4); + + /* Michael MIC pseudo header: DA, SA, 3 x 0, Priority */ + l ^= get_le32(hdr); + michael_block(l, r); + l ^= get_le32(&hdr[4]); + michael_block(l, r); + l ^= get_le32(&hdr[8]); + michael_block(l, r); + l ^= get_le32(&hdr[12]); + michael_block(l, r); + + /* first buffer has special handling */ + data = (uint8_t *) qdf_nbuf_data(wbuf) + rx_desc_len + off; + space = ol_rx_defrag_len(wbuf) - rx_desc_len - off; + for (;; ) { + if (space > data_len) + space = data_len; + + /* collect 32-bit blocks from current buffer */ + while (space >= sizeof(uint32_t)) { + l ^= get_le32(data); + michael_block(l, r); + data += sizeof(uint32_t); + space -= sizeof(uint32_t); + data_len -= sizeof(uint32_t); + } + if (data_len < sizeof(uint32_t)) + break; + + wbuf = qdf_nbuf_next(wbuf); + if (wbuf == NULL) + return OL_RX_DEFRAG_ERR; + + rx_desc_len = ol_rx_get_desc_len(htt_pdev, wbuf, + &rx_desc_old_position); + + if (space != 0) { + const uint8_t *data_next; + /* + * Block straddles buffers, split references. + */ + data_next = + (uint8_t *) qdf_nbuf_data(wbuf) + rx_desc_len; + if ((ol_rx_defrag_len(wbuf) - rx_desc_len) < + sizeof(uint32_t) - space) { + return OL_RX_DEFRAG_ERR; + } + switch (space) { + case 1: + l ^= get_le32_split(data[0], data_next[0], + data_next[1], data_next[2]); + data = data_next + 3; + space = (ol_rx_defrag_len(wbuf) - rx_desc_len) + - 3; + break; + case 2: + l ^= get_le32_split(data[0], data[1], + data_next[0], data_next[1]); + data = data_next + 2; + space = (ol_rx_defrag_len(wbuf) - rx_desc_len) + - 2; + break; + case 3: + l ^= get_le32_split(data[0], data[1], data[2], + data_next[0]); + data = data_next + 1; + space = (ol_rx_defrag_len(wbuf) - rx_desc_len) + - 1; + break; + } + michael_block(l, r); + data_len -= sizeof(uint32_t); + } else { + /* + * Setup for next buffer. + */ + data = (uint8_t *) qdf_nbuf_data(wbuf) + rx_desc_len; + space = ol_rx_defrag_len(wbuf) - rx_desc_len; + } + } + /* Last block and padding (0x5a, 4..7 x 0) */ + switch (data_len) { + case 0: + l ^= get_le32_split(0x5a, 0, 0, 0); + break; + case 1: + l ^= get_le32_split(data[0], 0x5a, 0, 0); + break; + case 2: + l ^= get_le32_split(data[0], data[1], 0x5a, 0); + break; + case 3: + l ^= get_le32_split(data[0], data[1], data[2], 0x5a); + break; + } + michael_block(l, r); + michael_block(l, r); + put_le32(mic, l); + put_le32(mic + 4, r); + + return OL_RX_DEFRAG_OK; +} + +/* + * Calculate headersize + */ +uint16_t ol_rx_frag_hdrsize(const void *data) +{ + const struct ieee80211_frame *wh = (const struct ieee80211_frame *)data; + uint16_t size = sizeof(struct ieee80211_frame); + + if ((wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) == IEEE80211_FC1_DIR_DSTODS) + size += IEEE80211_ADDR_LEN; + + if (DEFRAG_IEEE80211_QOS_HAS_SEQ(wh)) { + size += sizeof(uint16_t); + if (wh->i_fc[1] & IEEE80211_FC1_ORDER) + size += sizeof(struct ieee80211_htc); + } + return size; +} + +/* + * Recombine and decap fragments + */ +qdf_nbuf_t +ol_rx_defrag_decap_recombine(htt_pdev_handle htt_pdev, + qdf_nbuf_t frag_list, uint16_t hdrsize) +{ + qdf_nbuf_t tmp; + qdf_nbuf_t msdu = frag_list; + qdf_nbuf_t rx_nbuf = frag_list; + struct ieee80211_frame *wh; + + msdu = qdf_nbuf_next(msdu); + qdf_nbuf_set_next(rx_nbuf, NULL); + while (msdu) { + htt_rx_msdu_desc_free(htt_pdev, msdu); + qdf_net_buf_debug_release_skb(msdu); + tmp = qdf_nbuf_next(msdu); + qdf_nbuf_set_next(msdu, NULL); + ol_rx_frag_pull_hdr(htt_pdev, msdu, hdrsize); + if (!ol_rx_defrag_concat(rx_nbuf, msdu)) { + ol_rx_frames_free(htt_pdev, tmp); + htt_rx_desc_frame_free(htt_pdev, rx_nbuf); + qdf_nbuf_free(msdu); + /* msdu rx desc already freed above */ + return NULL; + } + msdu = tmp; + } + wh = (struct ieee80211_frame *)ol_rx_frag_get_mac_hdr(htt_pdev, + rx_nbuf); + wh->i_fc[1] &= ~IEEE80211_FC1_MORE_FRAG; + *(uint16_t *) wh->i_seq &= ~IEEE80211_SEQ_FRAG_MASK; + + return rx_nbuf; +} + +void ol_rx_defrag_nwifi_to_8023(ol_txrx_pdev_handle pdev, qdf_nbuf_t msdu) +{ + struct ieee80211_frame wh; + uint32_t hdrsize; + struct llc_snap_hdr_t llchdr; + struct ethernet_hdr_t *eth_hdr; + void *rx_desc_old_position = NULL; + void *ind_old_position = NULL; + int rx_desc_len = 0; + struct ieee80211_frame *wh_ptr; + + ol_rx_frag_desc_adjust(pdev, + msdu, + &rx_desc_old_position, + &ind_old_position, &rx_desc_len); + + wh_ptr = (struct ieee80211_frame *)(qdf_nbuf_data(msdu) + rx_desc_len); + qdf_mem_copy(&wh, wh_ptr, sizeof(wh)); + hdrsize = sizeof(struct ieee80211_frame); + qdf_mem_copy(&llchdr, ((uint8_t *) (qdf_nbuf_data(msdu) + + rx_desc_len)) + hdrsize, + sizeof(struct llc_snap_hdr_t)); + + /* + * Now move the data pointer to the beginning of the mac header : + * new-header = old-hdr + (wifhdrsize + llchdrsize - ethhdrsize) + */ + qdf_nbuf_pull_head(msdu, (rx_desc_len + hdrsize + + sizeof(struct llc_snap_hdr_t) - + sizeof(struct ethernet_hdr_t))); + eth_hdr = (struct ethernet_hdr_t *)(qdf_nbuf_data(msdu)); + switch (wh.i_fc[1] & IEEE80211_FC1_DIR_MASK) { + case IEEE80211_FC1_DIR_NODS: + qdf_mem_copy(eth_hdr->dest_addr, wh.i_addr1, + IEEE80211_ADDR_LEN); + qdf_mem_copy(eth_hdr->src_addr, wh.i_addr2, IEEE80211_ADDR_LEN); + break; + case IEEE80211_FC1_DIR_TODS: + qdf_mem_copy(eth_hdr->dest_addr, wh.i_addr3, + IEEE80211_ADDR_LEN); + qdf_mem_copy(eth_hdr->src_addr, wh.i_addr2, IEEE80211_ADDR_LEN); + break; + case IEEE80211_FC1_DIR_FROMDS: + qdf_mem_copy(eth_hdr->dest_addr, wh.i_addr1, + IEEE80211_ADDR_LEN); + qdf_mem_copy(eth_hdr->src_addr, wh.i_addr3, IEEE80211_ADDR_LEN); + break; + case IEEE80211_FC1_DIR_DSTODS: + break; + } + + qdf_mem_copy(eth_hdr->ethertype, llchdr.ethertype, + sizeof(llchdr.ethertype)); + + ol_rx_defrag_push_rx_desc(msdu, rx_desc_old_position, + ind_old_position, rx_desc_len); +} + +/* + * Handling QOS for defragmentation + */ +void +ol_rx_defrag_qos_decap(ol_txrx_pdev_handle pdev, + qdf_nbuf_t nbuf, uint16_t hdrlen) +{ + struct ieee80211_frame *wh; + uint16_t qoslen; + void *rx_desc_old_position = NULL; + void *ind_old_position = NULL; + int rx_desc_len = 0; + + ol_rx_frag_desc_adjust(pdev, + nbuf, + &rx_desc_old_position, + &ind_old_position, &rx_desc_len); + + wh = (struct ieee80211_frame *)(qdf_nbuf_data(nbuf) + rx_desc_len); + if (DEFRAG_IEEE80211_QOS_HAS_SEQ(wh)) { + qoslen = sizeof(struct ieee80211_qoscntl); + /* Qos frame with Order bit set indicates a HTC frame */ + if (wh->i_fc[1] & IEEE80211_FC1_ORDER) + qoslen += sizeof(struct ieee80211_htc); + + /* remove QoS filed from header */ + hdrlen -= qoslen; + qdf_mem_move((uint8_t *) wh + qoslen, wh, hdrlen); + wh = (struct ieee80211_frame *)qdf_nbuf_pull_head(nbuf, + rx_desc_len + + qoslen); + /* clear QoS bit */ + /* + * KW# 6154 'qdf_nbuf_pull_head' in turn calls + * __qdf_nbuf_pull_head, + * which returns NULL if there is not sufficient data to pull. + * It's guaranteed that qdf_nbuf_pull_head will succeed rather + * than returning NULL, since the entire rx frame is already + * present in the rx buffer. + * However, to make it obvious to static analyzers that this + * code is safe, add an explicit check that qdf_nbuf_pull_head + * returns a non-NULL value. + * Since this part of the code is not performance-critical, + * adding this explicit check is okay. + */ + if (wh) + wh->i_fc[0] &= ~IEEE80211_FC0_SUBTYPE_QOS; + + ol_rx_defrag_push_rx_desc(nbuf, rx_desc_old_position, + ind_old_position, rx_desc_len); + + } +} diff --git a/drivers/staging/qcacld-3.0/core/dp/txrx/ol_rx_defrag.h b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_rx_defrag.h new file mode 100644 index 0000000000000000000000000000000000000000..595d83a1d7b4fe00a6390ce6993832131797e8fd --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_rx_defrag.h @@ -0,0 +1,197 @@ +/* + * Copyright (c) 2011-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef _OL_RX_DEFRAG_H_ +#define _OL_RX_DEFRAG_H_ + +#include +#include +#include +#include +#include +#include +#include + +#define DEFRAG_IEEE80211_ADDR_LEN 6 +#define DEFRAG_IEEE80211_KEY_LEN 8 +#define DEFRAG_IEEE80211_FCS_LEN 4 + +struct ol_rx_defrag_cipher { + const char *ic_name; + uint16_t ic_header; + uint8_t ic_trailer; + uint8_t ic_miclen; +}; + +enum { + OL_RX_DEFRAG_ERR, + OL_RX_DEFRAG_OK, + OL_RX_DEFRAG_PN_ERR +}; + +#define ol_rx_defrag_copydata(buf, offset, len, _to) \ + qdf_nbuf_copy_bits(buf, offset, len, _to) + +#define ol_rx_defrag_len(buf) \ + qdf_nbuf_len(buf) + +void +ol_rx_fraglist_insert(htt_pdev_handle htt_pdev, + qdf_nbuf_t *head_addr, + qdf_nbuf_t *tail_addr, + qdf_nbuf_t frag, uint8_t *all_frag_present); + +void ol_rx_defrag_waitlist_add(struct ol_txrx_peer_t *peer, unsigned tid); + +void ol_rx_defrag_waitlist_remove(struct ol_txrx_peer_t *peer, unsigned tid); + +void ol_rx_defrag_waitlist_flush(struct ol_txrx_pdev_t *pdev); + +void +ol_rx_defrag(ol_txrx_pdev_handle pdev, + struct ol_txrx_peer_t *peer, unsigned tid, qdf_nbuf_t frag_list); + +int +ol_rx_frag_tkip_decap(ol_txrx_pdev_handle pdev, + qdf_nbuf_t msdu, uint16_t hdrlen); + +int +ol_rx_frag_wep_decap(ol_txrx_pdev_handle pdev, + qdf_nbuf_t nbuf, uint16_t hdrlen); + +void ol_rx_defrag_nwifi_to_8023(ol_txrx_pdev_handle pdev, qdf_nbuf_t msdu); + +void +ol_rx_defrag_qos_decap(ol_txrx_pdev_handle pdev, + qdf_nbuf_t nbuf, uint16_t hdrlen); + +int +ol_rx_frag_tkip_demic(ol_txrx_pdev_handle pdev, + const uint8_t *key, qdf_nbuf_t msdu, uint16_t hdrlen); + +int +ol_rx_frag_ccmp_decap(ol_txrx_pdev_handle pdev, + qdf_nbuf_t nbuf, uint16_t hdrlen); + +int +ol_rx_frag_ccmp_demic(ol_txrx_pdev_handle pdev, + qdf_nbuf_t wbuf, uint16_t hdrlen); + +uint16_t ol_rx_frag_hdrsize(const void *data); + +void ol_rx_defrag_michdr(const struct ieee80211_frame *wh0, uint8_t hdr[]); + +void +ol_rx_reorder_store_frag(ol_txrx_pdev_handle pdev, + struct ol_txrx_peer_t *peer, + unsigned tid, uint16_t seq_num, qdf_nbuf_t frag); + +qdf_nbuf_t +ol_rx_defrag_decap_recombine(htt_pdev_handle htt_pdev, + qdf_nbuf_t frag_list, uint16_t hdrsize); + +int +ol_rx_defrag_mic(ol_txrx_pdev_handle pdev, + const uint8_t *key, + qdf_nbuf_t wbuf, + uint16_t off, uint16_t data_len, uint8_t mic[]); + +void +ol_rx_reorder_flush_frag(htt_pdev_handle htt_pdev, + struct ol_txrx_peer_t *peer, + unsigned tid, int seq_num); + +static inline void xor_block(uint8_t *b, const uint8_t *a, qdf_size_t len) +{ + qdf_size_t i; + + for (i = 0; i < len; i++) + b[i] ^= a[i]; +} + +static inline uint32_t rotl(uint32_t val, int bits) +{ + return (val << bits) | (val >> (32 - bits)); +} + +static inline uint32_t rotr(uint32_t val, int bits) +{ + return (val >> bits) | (val << (32 - bits)); +} + +static inline uint32_t xswap(uint32_t val) +{ + return ((val & 0x00ff00ff) << 8) | ((val & 0xff00ff00) >> 8); +} + +static inline uint32_t +get_le32_split(uint8_t b0, uint8_t b1, uint8_t b2, uint8_t b3) +{ + return b0 | (b1 << 8) | (b2 << 16) | (b3 << 24); +} + +static inline uint32_t get_le32(const uint8_t *p) +{ + return get_le32_split(p[0], p[1], p[2], p[3]); +} + +static inline void put_le32(uint8_t *p, uint32_t v) +{ + p[0] = (v) & 0xff; + p[1] = (v >> 8) & 0xff; + p[2] = (v >> 16) & 0xff; + p[3] = (v >> 24) & 0xff; +} + +static inline uint8_t ol_rx_defrag_concat(qdf_nbuf_t dst, qdf_nbuf_t src) +{ + /* + * Inside qdf_nbuf_cat, if it is necessary to reallocate dst + * to provide space for src, the headroom portion is copied from + * the original dst buffer to the larger new dst buffer. + * (This is needed, because the headroom of the dst buffer + * contains the rx desc.) + */ + if (qdf_nbuf_cat(dst, src)) + return OL_RX_DEFRAG_ERR; + + return OL_RX_DEFRAG_OK; +} + +#define michael_block(l, r) \ + do { \ + r ^= rotl(l, 17); \ + l += r; \ + r ^= xswap(l); \ + l += r; \ + r ^= rotl(l, 3); \ + l += r; \ + r ^= rotr(l, 2); \ + l += r; \ + } while (0) + +#endif diff --git a/drivers/staging/qcacld-3.0/core/dp/txrx/ol_rx_fwd.c b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_rx_fwd.c new file mode 100644 index 0000000000000000000000000000000000000000..256ca5f155ea0a77d4ddccf8f1932819d8f6c830 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_rx_fwd.c @@ -0,0 +1,298 @@ +/* + * Copyright (c) 2011, 2014-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* standard header files */ +#include /* qdf_nbuf_map */ +#include /* qdf_mem_cmp */ + +/* external header files */ +#include /* wlan_op_mode_ap, etc. */ +#include /* htt_rx_msdu_desc_retrieve */ +#include /* ieee80211_frame, etc. */ + +/* internal header files */ +#include /* our own defs */ +#include /* ol_rx_deliver */ +#include /* TXRX_ASSERT1 */ +#include +#include + +/* + * Porting from Ap11PrepareForwardedPacket. + * This routine is called when a RX data frame from an associated station is + * to be forwarded to another associated station. We will prepare the + * received packet so that it is suitable for transmission again. + * Check that this Packet is suitable for forwarding. If yes, then + * prepare the new 802.11 header. + */ +static inline void ol_ap_fwd_check(struct ol_txrx_vdev_t *vdev, qdf_nbuf_t msdu) +{ + struct ieee80211_frame *mac_header; + unsigned char tmp_addr[IEEE80211_ADDR_LEN]; + unsigned char type; + unsigned char subtype; + unsigned char fromds; + unsigned char tods; + + mac_header = (struct ieee80211_frame *)(qdf_nbuf_data(msdu)); + TXRX_ASSERT1(mac_header); + + type = mac_header->i_fc[0] & IEEE80211_FC0_TYPE_MASK; + subtype = mac_header->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK; + tods = mac_header->i_fc[1] & IEEE80211_FC1_DIR_TODS; + fromds = mac_header->i_fc[1] & IEEE80211_FC1_DIR_FROMDS; + + /* + * Make sure no QOS or any other non-data subtype + * Should be a ToDs data frame. + * Make sure that this frame is unicast and not for us. + * These packets should come up through the normal rx path and + * not forwarded. + */ + if (type != IEEE80211_FC0_TYPE_DATA || + subtype != 0x0 || + ((tods != 1) || (fromds != 0)) || + qdf_mem_cmp + (mac_header->i_addr3, vdev->mac_addr.raw, + IEEE80211_ADDR_LEN)) { +#ifdef DEBUG_HOST_RC + TXRX_PRINT(TXRX_PRINT_LEVEL_INFO1, + "Exit: %s | Unnecessary to adjust mac header\n", + __func__); +#endif + } else { + /* Flip the ToDs bit to FromDs */ + mac_header->i_fc[1] &= 0xfe; + mac_header->i_fc[1] |= 0x2; + + /* + * Flip the addresses + * (ToDs, addr1, RA=BSSID) move to (FrDs, addr2, TA=BSSID) + * (ToDs, addr2, SA) move to (FrDs, addr3, SA) + * (ToDs, addr3, DA) move to (FrDs, addr1, DA) + */ + + memcpy(tmp_addr, mac_header->i_addr2, sizeof(tmp_addr)); + + memcpy(mac_header->i_addr2, + mac_header->i_addr1, sizeof(tmp_addr)); + + memcpy(mac_header->i_addr1, + mac_header->i_addr3, sizeof(tmp_addr)); + + memcpy(mac_header->i_addr3, tmp_addr, sizeof(tmp_addr)); + } +} + +static inline void ol_rx_fwd_to_tx(struct ol_txrx_vdev_t *vdev, qdf_nbuf_t msdu) +{ + struct ol_txrx_pdev_t *pdev = vdev->pdev; + + if (pdev->frame_format == wlan_frm_fmt_native_wifi) + ol_ap_fwd_check(vdev, msdu); + + /* + * Map the netbuf, so it's accessible to the DMA that + * sends it to the target. + */ + qdf_nbuf_set_next(msdu, NULL); /* add NULL terminator */ + + /* for HL, point to payload before send to tx again.*/ + if (pdev->cfg.is_high_latency) { + void *rx_desc; + + rx_desc = htt_rx_msdu_desc_retrieve(pdev->htt_pdev, + msdu); + qdf_nbuf_pull_head(msdu, + htt_rx_msdu_rx_desc_size_hl(pdev->htt_pdev, + rx_desc)); + } + + /* Clear the msdu control block as it will be re-interpreted */ + qdf_mem_set(msdu->cb, sizeof(msdu->cb), 0); + /* update any cb field expected by OL_TX_SEND */ + + msdu = OL_TX_SEND(vdev, msdu); + + if (msdu) { + /* + * The frame was not accepted by the tx. + * We could store the frame and try again later, + * but the simplest solution is to discard the frames. + */ + qdf_nbuf_tx_free(msdu, QDF_NBUF_PKT_ERROR); + } + return; +} + +void +ol_rx_fwd_check(struct ol_txrx_vdev_t *vdev, + struct ol_txrx_peer_t *peer, unsigned tid, qdf_nbuf_t msdu_list) +{ + struct ol_txrx_pdev_t *pdev = vdev->pdev; + qdf_nbuf_t deliver_list_head = NULL; + qdf_nbuf_t deliver_list_tail = NULL; + qdf_nbuf_t msdu; + + msdu = msdu_list; + while (msdu) { + struct ol_txrx_vdev_t *tx_vdev; + void *rx_desc; + /* + * Remember the next list elem, because our processing + * may cause the MSDU to get linked into a different list. + */ + msdu_list = qdf_nbuf_next(msdu); + + rx_desc = htt_rx_msdu_desc_retrieve(pdev->htt_pdev, msdu); + + if (!vdev->disable_intrabss_fwd && + htt_rx_msdu_forward(pdev->htt_pdev, rx_desc)) { + /* + * Use the same vdev that received the frame to + * transmit the frame. + * This is exactly what we want for intra-BSS + * forwarding, like STA-to-STA forwarding and + * multicast echo. + * If this is a intra-BSS forwarding case (which is not + * currently supported), then the tx vdev is different + * from the rx vdev. + * On the LL host the vdevs are not actually used + * for tx, so it would still work to use the rx vdev + * rather than the tx vdev. + * For HL, the tx classification searches for the DA + * within the given vdev, so we would want to get the DA + * peer ID from the target, so we can locate + * the tx vdev. + */ + tx_vdev = vdev; + /* + * Copying TID value of RX packet to forwarded + * packet if the tid is other than non qos tid. + * But for non qos tid fill invalid tid so that + * Fw will take care of filling proper tid. + */ + if (tid != HTT_NON_QOS_TID) { + qdf_nbuf_set_tid(msdu, tid); + } else { + qdf_nbuf_set_tid(msdu, + QDF_NBUF_TX_EXT_TID_INVALID); + } + + if (!ol_txrx_fwd_desc_thresh_check(vdev)) { + /* Drop the packet*/ + htt_rx_msdu_desc_free(pdev->htt_pdev, msdu); + qdf_net_buf_debug_release_skb(msdu); + TXRX_STATS_MSDU_LIST_INCR( + pdev, tx.dropped.host_reject, msdu); + /* add NULL terminator */ + qdf_nbuf_set_next(msdu, NULL); + qdf_nbuf_tx_free(msdu, + QDF_NBUF_PKT_ERROR); + msdu = msdu_list; + continue; + } + + /* + * This MSDU needs to be forwarded to the tx path. + * Check whether it also needs to be sent to the OS + * shim, in which case we need to make a copy + * (or clone?). + */ + if (htt_rx_msdu_discard(pdev->htt_pdev, rx_desc)) { + htt_rx_msdu_desc_free(pdev->htt_pdev, msdu); + qdf_net_buf_debug_release_skb(msdu); + ol_rx_fwd_to_tx(tx_vdev, msdu); + msdu = NULL; /* already handled this MSDU */ + tx_vdev->fwd_tx_packets++; + vdev->fwd_rx_packets++; + TXRX_STATS_ADD(pdev, + pub.rx.intra_bss_fwd.packets_fwd, 1); + } else { + qdf_nbuf_t copy; + + copy = qdf_nbuf_copy(msdu); + if (copy) { + /* Since this is a private copy of skb + * and part of skb tracking table, so + * mark it to make sure that this skb + * is getting deleted from tracking + * table on receiving tx completion. + */ + QDF_NBUF_CB_TX_IS_PACKET_PRIV(copy) = 1; + ol_rx_fwd_to_tx(tx_vdev, copy); + tx_vdev->fwd_tx_packets++; + } + TXRX_STATS_ADD(pdev, + pub.rx.intra_bss_fwd.packets_stack_n_fwd, 1); + } + } else { + TXRX_STATS_ADD(pdev, + pub.rx.intra_bss_fwd.packets_stack, 1); + } + if (msdu) { + /* send this frame to the OS */ + OL_TXRX_LIST_APPEND(deliver_list_head, + deliver_list_tail, msdu); + } + msdu = msdu_list; + } + if (deliver_list_head) { + /* add NULL terminator */ + qdf_nbuf_set_next(deliver_list_tail, NULL); + if (ol_cfg_is_full_reorder_offload(pdev->ctrl_pdev)) { + ol_rx_in_order_deliver(vdev, peer, tid, + deliver_list_head); + } else { + ol_rx_deliver(vdev, peer, tid, deliver_list_head); + } + } + return; +} + +/* + * ol_get_intra_bss_fwd_pkts_count() - to get the total tx and rx packets + * that has been forwarded from txrx layer without going to upper layers. + * @vdev_id: vdev id + * @fwd_tx_packets: pointer to forwarded tx packets count parameter + * @fwd_rx_packets: pointer to forwarded rx packets count parameter + * + * Return: status -> A_OK - success, A_ERROR - failure + */ +A_STATUS ol_get_intra_bss_fwd_pkts_count(uint8_t vdev_id, + uint64_t *fwd_tx_packets, uint64_t *fwd_rx_packets) +{ + struct ol_txrx_vdev_t *vdev = NULL; + + vdev = (struct ol_txrx_vdev_t *)ol_txrx_get_vdev_from_vdev_id(vdev_id); + if (!vdev) + return A_ERROR; + + *fwd_tx_packets = vdev->fwd_tx_packets; + *fwd_rx_packets = vdev->fwd_rx_packets; + return A_OK; +} diff --git a/drivers/staging/qcacld-3.0/core/dp/txrx/ol_rx_fwd.h b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_rx_fwd.h new file mode 100644 index 0000000000000000000000000000000000000000..e82130ffd13e210a31fa293f0f5519b3ffee680d --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_rx_fwd.h @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2011, 2014-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef _OL_RX_FWD_H_ +#define _OL_RX_FWD_H_ + +#include /* qdf_nbuf_t, etc. */ + +#include /* ol_txrx_peer_t, etc. */ + +qdf_nbuf_t +ol_rx_fwd_mcast_check_sta(struct ol_txrx_vdev_t *vdev, + struct ol_txrx_peer_t *peer, + qdf_nbuf_t msdu, void *rx_desc, int is_wlan_mcast); + +qdf_nbuf_t +ol_rx_fwd_mcast_check_ap(struct ol_txrx_vdev_t *vdev, + struct ol_txrx_peer_t *peer, + qdf_nbuf_t msdu, void *rx_desc, int is_wlan_mcast); + +/** + * @brief Check if rx frames should be transmitted over WLAN. + * @details + * Check if rx frames should be transmitted back over WLAN, instead of + * or in addition to delivering the rx frames to the OS. + * Rx frames will be forwarded to the transmit path under the following + * conditions: + * 1. If the destination is a STA associated to the same virtual device + * within this physical device, the rx frame will be forwarded to the + * tx path rather than being sent to the OS. If the destination is a + * STA associated to a different virtual device within this physical + * device, then the rx frame will optionally be forwarded to the tx path. + * 2. If the frame is received by an AP, but the destination is for another + * AP that the current AP is associated with for WDS forwarding, the + * intermediate AP will forward the rx frame to the tx path to transmit + * to send to the destination AP, rather than sending it to the OS. + * 3. If the AP receives a multicast frame, it will retransmit the frame + * within the BSS, in addition to sending the frame to the OS. + * + * @param vdev - which virtual device the frames were addressed to + * @param peer - which peer the rx frames belong to + * @param tid - which TID within the peer the rx frames belong to + * @param msdu_list - NULL-terminated list of MSDUs to perform the rx->tx + * forwarding check on + */ +void +ol_rx_fwd_check(struct ol_txrx_vdev_t *vdev, + struct ol_txrx_peer_t *peer, + unsigned tid, qdf_nbuf_t msdu_list); + +A_STATUS +ol_get_intra_bss_fwd_pkts_count( + uint8_t vdev_id, + uint64_t *fwd_tx_packets, + uint64_t *fwd_rx_packets); + +#endif /* _OL_RX_FWD_H_ */ diff --git a/drivers/staging/qcacld-3.0/core/dp/txrx/ol_rx_pn.c b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_rx_pn.c new file mode 100644 index 0000000000000000000000000000000000000000..9ecb4eab6d1b24d8e712ff84183b0ff3897d2ce6 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_rx_pn.c @@ -0,0 +1,349 @@ +/* + * Copyright (c) 2011, 2013-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#include /* qdf_nbuf_t */ + +#include /* htt_rx_pn_t, etc. */ +#include /* ol_rx_err */ + +#include /* ol_rx_mpdu_list_next */ +#include /* our own defs */ +#include /* ol_rx_fwd_check */ +#include /* ol_rx_deliver */ + +/* add the MSDUs from this MPDU to the list of good frames */ +#define ADD_MPDU_TO_LIST(head, tail, mpdu, mpdu_tail) do { \ + if (!head) { \ + head = mpdu; \ + } else { \ + qdf_nbuf_set_next(tail, mpdu); \ + } \ + tail = mpdu_tail; \ + } while (0) + +int ol_rx_pn_cmp24(union htt_rx_pn_t *new_pn, + union htt_rx_pn_t *old_pn, int is_unicast, int opmode) +{ + int rc = ((new_pn->pn24 & 0xffffff) <= (old_pn->pn24 & 0xffffff)); + return rc; +} + +int ol_rx_pn_cmp48(union htt_rx_pn_t *new_pn, + union htt_rx_pn_t *old_pn, int is_unicast, int opmode) +{ + int rc = ((new_pn->pn48 & 0xffffffffffffULL) <= + (old_pn->pn48 & 0xffffffffffffULL)); + return rc; +} + +int ol_rx_pn_wapi_cmp(union htt_rx_pn_t *new_pn, + union htt_rx_pn_t *old_pn, int is_unicast, int opmode) +{ + int pn_is_replay = 0; + + if (new_pn->pn128[1] == old_pn->pn128[1]) + pn_is_replay = (new_pn->pn128[0] <= old_pn->pn128[0]); + else + pn_is_replay = (new_pn->pn128[1] < old_pn->pn128[1]); + + if (is_unicast) { + if (opmode == wlan_op_mode_ap) + pn_is_replay |= ((new_pn->pn128[0] & 0x1ULL) != 0); + else + pn_is_replay |= ((new_pn->pn128[0] & 0x1ULL) != 1); + } + return pn_is_replay; +} + +qdf_nbuf_t +ol_rx_pn_check_base(struct ol_txrx_vdev_t *vdev, + struct ol_txrx_peer_t *peer, + unsigned tid, qdf_nbuf_t msdu_list) +{ + struct ol_txrx_pdev_t *pdev = vdev->pdev; + union htt_rx_pn_t *last_pn; + qdf_nbuf_t out_list_head = NULL; + qdf_nbuf_t out_list_tail = NULL; + qdf_nbuf_t mpdu; + int index; /* unicast vs. multicast */ + int pn_len; + void *rx_desc; + int last_pn_valid; + + /* Make sure host pn check is not redundant */ + if ((qdf_atomic_read(&peer->fw_pn_check)) || + (vdev->opmode == wlan_op_mode_ibss)) { + return msdu_list; + } + + /* First, check whether the PN check applies */ + rx_desc = htt_rx_msdu_desc_retrieve(pdev->htt_pdev, msdu_list); + qdf_assert(htt_rx_msdu_has_wlan_mcast_flag(pdev->htt_pdev, rx_desc)); + index = htt_rx_msdu_is_wlan_mcast(pdev->htt_pdev, rx_desc) ? + txrx_sec_mcast : txrx_sec_ucast; + pn_len = pdev->rx_pn[peer->security[index].sec_type].len; + if (pn_len == 0) + return msdu_list; + + last_pn_valid = peer->tids_last_pn_valid[tid]; + last_pn = &peer->tids_last_pn[tid]; + mpdu = msdu_list; + while (mpdu) { + qdf_nbuf_t mpdu_tail, next_mpdu; + union htt_rx_pn_t new_pn; + int pn_is_replay = 0; + + rx_desc = htt_rx_msdu_desc_retrieve(pdev->htt_pdev, mpdu); + + /* + * Find the last MSDU within this MPDU, and + * the find the first MSDU within the next MPDU. + */ + ol_rx_mpdu_list_next(pdev, mpdu, &mpdu_tail, &next_mpdu); + + /* Don't check the PN replay for non-encrypted frames */ + if (!htt_rx_mpdu_is_encrypted(pdev->htt_pdev, rx_desc)) { + ADD_MPDU_TO_LIST(out_list_head, out_list_tail, mpdu, + mpdu_tail); + mpdu = next_mpdu; + continue; + } + + /* retrieve PN from rx descriptor */ + htt_rx_mpdu_desc_pn(pdev->htt_pdev, rx_desc, &new_pn, pn_len); + + /* if there was no prior PN, there's nothing to check */ + if (last_pn_valid) { + pn_is_replay = + pdev->rx_pn[peer->security[index].sec_type]. + cmp(&new_pn, last_pn, index == txrx_sec_ucast, + vdev->opmode); + } else { + last_pn_valid = peer->tids_last_pn_valid[tid] = 1; + } + + if (pn_is_replay) { + qdf_nbuf_t msdu; + static uint32_t last_pncheck_print_time /* = 0 */; + int log_level; + uint32_t current_time_ms; + + /* + * This MPDU failed the PN check: + * 1. notify the control SW of the PN failure + * (so countermeasures can be taken, if necessary) + * 2. Discard all the MSDUs from this MPDU. + */ + msdu = mpdu; + current_time_ms = + qdf_system_ticks_to_msecs(qdf_system_ticks()); + if (TXRX_PN_CHECK_FAILURE_PRINT_PERIOD_MS < + (current_time_ms - last_pncheck_print_time)) { + last_pncheck_print_time = current_time_ms; + log_level = TXRX_PRINT_LEVEL_WARN; + } else { + log_level = TXRX_PRINT_LEVEL_INFO2; + } + + TXRX_PRINT(log_level, + "PN check failed - TID %d, peer %p " + "(%02x:%02x:%02x:%02x:%02x:%02x) %s\n" + " old PN (u64 x2)= 0x%08llx %08llx (LSBs = %lld)\n" + " new PN (u64 x2)= 0x%08llx %08llx (LSBs = %lld)\n" + " new seq num = %d\n", + tid, peer, + peer->mac_addr.raw[0], peer->mac_addr.raw[1], + peer->mac_addr.raw[2], peer->mac_addr.raw[3], + peer->mac_addr.raw[4], peer->mac_addr.raw[5], + (index == + txrx_sec_ucast) ? "ucast" : "mcast", + last_pn->pn128[1], last_pn->pn128[0], + last_pn->pn128[0] & 0xffffffffffffULL, + new_pn.pn128[1], new_pn.pn128[0], + new_pn.pn128[0] & 0xffffffffffffULL, + htt_rx_mpdu_desc_seq_num(pdev->htt_pdev, + rx_desc)); +#if defined(ENABLE_RX_PN_TRACE) + ol_rx_pn_trace_display(pdev, 1); +#endif /* ENABLE_RX_PN_TRACE */ + ol_rx_err(pdev->ctrl_pdev, + vdev->vdev_id, peer->mac_addr.raw, tid, + htt_rx_mpdu_desc_tsf32(pdev->htt_pdev, + rx_desc), OL_RX_ERR_PN, + mpdu, NULL, 0); + /* free all MSDUs within this MPDU */ + do { + qdf_nbuf_t next_msdu; + OL_RX_ERR_STATISTICS_1(pdev, vdev, peer, + rx_desc, OL_RX_ERR_PN); + next_msdu = qdf_nbuf_next(msdu); + htt_rx_desc_frame_free(pdev->htt_pdev, msdu); + if (msdu == mpdu_tail) + break; + else + msdu = next_msdu; + } while (1); + } else { + ADD_MPDU_TO_LIST(out_list_head, out_list_tail, mpdu, + mpdu_tail); + /* + * Remember the new PN. + * For simplicity, just do 2 64-bit word copies to + * cover the worst case (WAPI), regardless of the length + * of the PN. + * This is more efficient than doing a conditional + * branch to copy only the relevant portion. + */ + last_pn->pn128[0] = new_pn.pn128[0]; + last_pn->pn128[1] = new_pn.pn128[1]; + OL_RX_PN_TRACE_ADD(pdev, peer, tid, rx_desc); + } + + mpdu = next_mpdu; + } + /* make sure the list is null-terminated */ + if (out_list_tail) + qdf_nbuf_set_next(out_list_tail, NULL); + + return out_list_head; +} + +void +ol_rx_pn_check(struct ol_txrx_vdev_t *vdev, + struct ol_txrx_peer_t *peer, unsigned tid, qdf_nbuf_t msdu_list) +{ + msdu_list = ol_rx_pn_check_base(vdev, peer, tid, msdu_list); + ol_rx_fwd_check(vdev, peer, tid, msdu_list); +} + +void +ol_rx_pn_check_only(struct ol_txrx_vdev_t *vdev, + struct ol_txrx_peer_t *peer, + unsigned tid, qdf_nbuf_t msdu_list) +{ + msdu_list = ol_rx_pn_check_base(vdev, peer, tid, msdu_list); + ol_rx_deliver(vdev, peer, tid, msdu_list); +} + +#if defined(ENABLE_RX_PN_TRACE) + +A_STATUS ol_rx_pn_trace_attach(ol_txrx_pdev_handle pdev) +{ + int num_elems; + + num_elems = 1 << TXRX_RX_PN_TRACE_SIZE_LOG2; + pdev->rx_pn_trace.idx = 0; + pdev->rx_pn_trace.cnt = 0; + pdev->rx_pn_trace.mask = num_elems - 1; + pdev->rx_pn_trace.data = + qdf_mem_malloc(sizeof(*pdev->rx_pn_trace.data) * num_elems); + if (!pdev->rx_pn_trace.data) + return A_NO_MEMORY; + return A_OK; +} + +void ol_rx_pn_trace_detach(ol_txrx_pdev_handle pdev) +{ + qdf_mem_free(pdev->rx_pn_trace.data); +} + +void +ol_rx_pn_trace_add(struct ol_txrx_pdev_t *pdev, + struct ol_txrx_peer_t *peer, uint16_t tid, void *rx_desc) +{ + uint32_t idx = pdev->rx_pn_trace.idx; + union htt_rx_pn_t pn; + uint32_t pn32; + uint16_t seq_num; + uint8_t unicast; + + htt_rx_mpdu_desc_pn(pdev->htt_pdev, rx_desc, &pn, 48); + pn32 = pn.pn48 & 0xffffffff; + seq_num = htt_rx_mpdu_desc_seq_num(pdev->htt_pdev, rx_desc); + unicast = !htt_rx_msdu_is_wlan_mcast(pdev->htt_pdev, rx_desc); + + pdev->rx_pn_trace.data[idx].peer = peer; + pdev->rx_pn_trace.data[idx].tid = tid; + pdev->rx_pn_trace.data[idx].seq_num = seq_num; + pdev->rx_pn_trace.data[idx].unicast = unicast; + pdev->rx_pn_trace.data[idx].pn32 = pn32; + pdev->rx_pn_trace.cnt++; + idx++; + pdev->rx_pn_trace.idx = idx & pdev->rx_pn_trace.mask; +} + +void ol_rx_pn_trace_display(ol_txrx_pdev_handle pdev, int just_once) +{ + static int print_count /* = 0 */; + uint32_t i, start, end; + uint64_t cnt; + int elems; + int limit = 0; /* move this to the arg list? */ + + if (print_count != 0 && just_once) + return; + + print_count++; + + end = pdev->rx_pn_trace.idx; + if (pdev->rx_pn_trace.cnt <= pdev->rx_pn_trace.mask) { + /* trace log has not yet wrapped around - start at the top */ + start = 0; + cnt = 0; + } else { + start = end; + cnt = pdev->rx_pn_trace.cnt - (pdev->rx_pn_trace.mask + 1); + } + elems = (end - 1 - start) & pdev->rx_pn_trace.mask; + if (limit > 0 && elems > limit) { + int delta; + delta = elems - limit; + start += delta; + start &= pdev->rx_pn_trace.mask; + cnt += delta; + } + + i = start; + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO, + " seq PN"); + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO, + " count idx peer tid uni num LSBs"); + do { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO, + " %6lld %4d %p %2d %d %4d %8d", + cnt, i, + pdev->rx_pn_trace.data[i].peer, + pdev->rx_pn_trace.data[i].tid, + pdev->rx_pn_trace.data[i].unicast, + pdev->rx_pn_trace.data[i].seq_num, + pdev->rx_pn_trace.data[i].pn32); + cnt++; + i++; + i &= pdev->rx_pn_trace.mask; + } while (i != end); +} +#endif /* ENABLE_RX_PN_TRACE */ diff --git a/drivers/staging/qcacld-3.0/core/dp/txrx/ol_rx_pn.h b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_rx_pn.h new file mode 100644 index 0000000000000000000000000000000000000000..0b132f8fbb5ccdd8a0658ef42138708afa9ea34d --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_rx_pn.h @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2011, 2014-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef _OL_RX_PN_H_ +#define _OL_RX_PN_H_ + +#include /* qdf_nbuf_t, etc. */ + +#include /* ol_txrx_peer_t, etc. */ + +int ol_rx_pn_cmp24(union htt_rx_pn_t *new_pn, + union htt_rx_pn_t *old_pn, int is_unicast, int opmode); + +int ol_rx_pn_cmp48(union htt_rx_pn_t *new_pn, + union htt_rx_pn_t *old_pn, int is_unicast, int opmode); + +int ol_rx_pn_wapi_cmp(union htt_rx_pn_t *new_pn, + union htt_rx_pn_t *old_pn, int is_unicast, int opmode); + +/** + * @brief If applicable, check the Packet Number to detect replays. + * @details + * Determine whether a PN check is needed, and if so, what the PN size is. + * (A PN size of 0 is used to indirectly bypass the PN check for security + * methods that don't involve a PN check.) + * This function produces event notifications for any PN failures, via the + * ol_rx_err function. + * After the PN check, call the next stage of rx processing (rx --> tx + * forwarding check). + * + * @param vdev - which virtual device the frames were addressed to + * @param peer - which peer the rx frames belong to + * @param tid - which TID within the peer the rx frames belong to + * @param msdu_list - NULL-terminated list of MSDUs to perform PN check on + * (if PN check is applicable, i.e. PN length > 0) + */ +void +ol_rx_pn_check(struct ol_txrx_vdev_t *vdev, + struct ol_txrx_peer_t *peer, unsigned tid, qdf_nbuf_t msdu_list); + +/** + * @brief If applicable, check the Packet Number to detect replays. + * @details + * Determine whether a PN check is needed, and if so, what the PN size is. + * (A PN size of 0 is used to indirectly bypass the PN check for security + * methods that don't involve a PN check.) + * This function produces event notifications for any PN failures, via the + * ol_rx_err function. + * After the PN check, deliver the valid rx frames to the OS shim. + * (Don't perform a rx --> tx forwarding check.) + * + * @param vdev - which virtual device the frames were addressed to + * @param peer - which peer the rx frames belong to + * @param tid - which TID within the peer the rx frames belong to + * @param msdu_list - NULL-terminated list of MSDUs to perform PN check on + * (if PN check is applicable, i.e. PN length > 0) + */ +void +ol_rx_pn_check_only(struct ol_txrx_vdev_t *vdev, + struct ol_txrx_peer_t *peer, + unsigned tid, qdf_nbuf_t msdu_list); + +/** + * @brief If applicable, check the Packet Number to detect replays. + * @details + * Same as ol_rx_pn_check but return valid rx netbufs + * rather than invoking the rx --> tx forwarding check. + * + * @param vdev - which virtual device the frames were addressed to + * @param peer - which peer the rx frames belong to + * @param tid - which TID within the peer the rx frames belong to + * @param msdu_list - NULL-terminated list of MSDUs to perform PN check on + * (if PN check is applicable, i.e. PN length > 0) + * @return list of netbufs that didn't fail the PN check + */ +qdf_nbuf_t +ol_rx_pn_check_base(struct ol_txrx_vdev_t *vdev, + struct ol_txrx_peer_t *peer, + unsigned tid, qdf_nbuf_t msdu_list); + +#endif /* _OL_RX_PN_H_ */ diff --git a/drivers/staging/qcacld-3.0/core/dp/txrx/ol_rx_reorder.c b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_rx_reorder.c new file mode 100644 index 0000000000000000000000000000000000000000..5116cf0c0a6fe217720e8871257f2a31ad5808cc --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_rx_reorder.c @@ -0,0 +1,824 @@ +/* + * Copyright (c) 2011-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/*=== header file includes ===*/ +/* generic utilities */ +#include /* qdf_nbuf_t, etc. */ +#include /* qdf_mem_malloc */ + +#include /* IEEE80211_SEQ_MAX */ + +/* external interfaces */ +#include /* ol_txrx_pdev_handle */ +#include /* ol_rx_addba_handler, etc. */ +#include /* ol_ctrl_rx_addba_complete */ +#include /* htt_rx_desc_frame_free */ +#include /* ol_rx_err */ + +/* datapath internal interfaces */ +#include /* ol_txrx_peer_find_by_id */ +#include /* TXRX_ASSERT */ +#include /* OL_RX_REORDER_TIMEOUT_REMOVE, etc. */ +#include +#include + +/*=== data types and defines ===*/ +#define OL_RX_REORDER_ROUND_PWR2(value) g_log2ceil[value] + +/*=== global variables ===*/ + +static char g_log2ceil[] = { + 1, /* 0 -> 1 */ + 1, /* 1 -> 1 */ + 2, /* 2 -> 2 */ + 4, 4, /* 3-4 -> 4 */ + 8, 8, 8, 8, /* 5-8 -> 8 */ + 16, 16, 16, 16, 16, 16, 16, 16, /* 9-16 -> 16 */ + 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, /* 17-32 -> 32 */ + 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, /* 33-64 -> 64 */ +}; + +/*=== function definitions ===*/ + +/*---*/ + +#define QCA_SUPPORT_RX_REORDER_RELEASE_CHECK 0 +#define OL_RX_REORDER_IDX_START_SELF_SELECT(peer, tid, idx_start) /* no-op */ +#define OL_RX_REORDER_IDX_WRAP(idx, win_sz, win_sz_mask) { idx &= win_sz_mask; } +#define OL_RX_REORDER_IDX_MAX(win_sz, win_sz_mask) win_sz_mask +#define OL_RX_REORDER_IDX_INIT(seq_num, win_sz, win_sz_mask) 0 /* n/a */ +#define OL_RX_REORDER_NO_HOLES(rx_reorder) 0 +#define OL_RX_REORDER_MPDU_CNT_INCR(rx_reorder, incr) /* n/a */ +#define OL_RX_REORDER_MPDU_CNT_DECR(rx_reorder, decr) /* n/a */ + +/*---*/ + +/* reorder array elements are known to be non-NULL */ +#define OL_RX_REORDER_LIST_APPEND(head_msdu, tail_msdu, rx_reorder_array_elem) \ + do { \ + if (tail_msdu) { \ + qdf_nbuf_set_next(tail_msdu, \ + rx_reorder_array_elem->head); \ + } \ + } while (0) + +/* functions called by txrx components */ + +void ol_rx_reorder_init(struct ol_rx_reorder_t *rx_reorder, uint8_t tid) +{ + rx_reorder->win_sz = 1; + rx_reorder->win_sz_mask = 0; + rx_reorder->array = &rx_reorder->base; + rx_reorder->base.head = rx_reorder->base.tail = NULL; + rx_reorder->tid = tid; + rx_reorder->defrag_timeout_ms = 0; + + rx_reorder->defrag_waitlist_elem.tqe_next = NULL; + rx_reorder->defrag_waitlist_elem.tqe_prev = NULL; +} + +static enum htt_rx_status +ol_rx_reorder_seq_num_check( + struct ol_txrx_pdev_t *pdev, + struct ol_txrx_peer_t *peer, + unsigned tid, unsigned seq_num) +{ + unsigned seq_num_delta; + + /* don't check the new seq_num against last_seq + if last_seq is not valid */ + if (peer->tids_last_seq[tid] == IEEE80211_SEQ_MAX) + return htt_rx_status_ok; + + /* + * For duplicate detection, it might be helpful to also check + * whether the retry bit is set or not - a strict duplicate packet + * should be the one with retry bit set. + * However, since many implementations do not set the retry bit, + * and since this same function is also used for filtering out + * late-arriving frames (frames that arive after their rx reorder + * timeout has expired) which are not retries, don't bother checking + * the retry bit for now. + */ + /* note: if new seq_num == old seq_num, seq_num_delta = 4095 */ + seq_num_delta = (seq_num - 1 - peer->tids_last_seq[tid]) & + (IEEE80211_SEQ_MAX - 1); /* account for wraparound */ + + if (seq_num_delta > (IEEE80211_SEQ_MAX >> 1)) { + return htt_rx_status_err_replay; + /* or maybe htt_rx_status_err_dup */ + } + return htt_rx_status_ok; +} + +/** + * ol_rx_seq_num_check() - Does duplicate detection for mcast packets and + * duplicate detection & check for out-of-order + * packets for unicast packets. + * @pdev: Pointer to pdev maintained by OL + * @peer: Pointer to peer structure maintained by OL + * @tid: TID value passed as part of HTT msg by f/w + * @rx_mpdu_desc: Pointer to Rx Descriptor for the given MPDU + * + * This function + * 1) For Multicast Frames -- does duplicate detection + * A frame is considered duplicate & dropped if it has a seq.number + * which is received twice in succession and with the retry bit set + * in the second case. + * A frame which is older than the last sequence number received + * is not considered duplicate but out-of-order. This function does + * perform out-of-order check for multicast frames, which is in + * keeping with the 802.11 2012 spec section 9.3.2.10 + * 2) For Unicast Frames -- does duplicate detection & out-of-order check + * only for non-aggregation tids. + * + * Return: Returns htt_rx_status_err_replay, if packet needs to be + * dropped, htt_rx_status_ok otherwise. + */ +enum htt_rx_status +ol_rx_seq_num_check(struct ol_txrx_pdev_t *pdev, + struct ol_txrx_peer_t *peer, + uint8_t tid, + void *rx_mpdu_desc) +{ + uint16_t pkt_tid = 0xffff; + uint16_t seq_num = IEEE80211_SEQ_MAX; + bool retry = 0; + + seq_num = htt_rx_mpdu_desc_seq_num(pdev->htt_pdev, rx_mpdu_desc); + + /* For mcast packets, we only the dup-detection, not re-order check */ + + if (qdf_unlikely(OL_RX_MCAST_TID == tid)) { + + pkt_tid = htt_rx_mpdu_desc_tid(pdev->htt_pdev, rx_mpdu_desc); + + /* Invalid packet TID, expected only for HL */ + /* Pass the packet on */ + if (qdf_unlikely(pkt_tid >= OL_TXRX_NUM_EXT_TIDS)) + return htt_rx_status_ok; + + retry = htt_rx_mpdu_desc_retry(pdev->htt_pdev, rx_mpdu_desc); + + /* + * At this point, we define frames to be duplicate if they arrive + * "ONLY" in succession with the same sequence number and the last + * one has the retry bit set. For an older frame, we consider that + * as an out of order frame, and hence do not perform the dup-detection + * or out-of-order check for multicast frames as per discussions & spec + * Hence "seq_num <= last_seq_num" check is not necessary. + */ + if (qdf_unlikely(retry && + (seq_num == peer->tids_mcast_last_seq[pkt_tid]))) {/* drop mcast */ + TXRX_STATS_INCR(pdev, priv.rx.err.msdu_mc_dup_drop); + return htt_rx_status_err_replay; + } else { + /* + * This is a multicast packet likely to be passed on... + * Set the mcast last seq number here + * This is fairly accurate since: + * a) f/w sends multicast as separate PPDU/HTT messages + * b) Mcast packets are not aggregated & hence single + * c) Result of b) is that, flush / release bit is set always + * on the mcast packets, so likely to be immediatedly released. + */ + peer->tids_mcast_last_seq[pkt_tid] = seq_num; + return htt_rx_status_ok; + } + } else + return ol_rx_reorder_seq_num_check(pdev, peer, tid, seq_num); +} + + +void +ol_rx_reorder_store(struct ol_txrx_pdev_t *pdev, + struct ol_txrx_peer_t *peer, + unsigned tid, + unsigned idx, qdf_nbuf_t head_msdu, qdf_nbuf_t tail_msdu) +{ + struct ol_rx_reorder_array_elem_t *rx_reorder_array_elem; + + idx &= peer->tids_rx_reorder[tid].win_sz_mask; + rx_reorder_array_elem = &peer->tids_rx_reorder[tid].array[idx]; + if (rx_reorder_array_elem->head) { + qdf_nbuf_set_next(rx_reorder_array_elem->tail, head_msdu); + } else { + rx_reorder_array_elem->head = head_msdu; + OL_RX_REORDER_MPDU_CNT_INCR(&peer->tids_rx_reorder[tid], 1); + } + rx_reorder_array_elem->tail = tail_msdu; +} + +void +ol_rx_reorder_release(struct ol_txrx_vdev_t *vdev, + struct ol_txrx_peer_t *peer, + unsigned tid, unsigned idx_start, unsigned idx_end) +{ + unsigned idx; + unsigned win_sz, win_sz_mask; + struct ol_rx_reorder_array_elem_t *rx_reorder_array_elem; + qdf_nbuf_t head_msdu; + qdf_nbuf_t tail_msdu; + + OL_RX_REORDER_IDX_START_SELF_SELECT(peer, tid, &idx_start); + /* may get reset below */ + peer->tids_next_rel_idx[tid] = (uint16_t) idx_end; + + win_sz = peer->tids_rx_reorder[tid].win_sz; + win_sz_mask = peer->tids_rx_reorder[tid].win_sz_mask; + idx_start &= win_sz_mask; + idx_end &= win_sz_mask; + rx_reorder_array_elem = &peer->tids_rx_reorder[tid].array[idx_start]; + + head_msdu = rx_reorder_array_elem->head; + tail_msdu = rx_reorder_array_elem->tail; + rx_reorder_array_elem->head = rx_reorder_array_elem->tail = NULL; + if (head_msdu) + OL_RX_REORDER_MPDU_CNT_DECR(&peer->tids_rx_reorder[tid], 1); + + idx = (idx_start + 1); + OL_RX_REORDER_IDX_WRAP(idx, win_sz, win_sz_mask); + while (idx != idx_end) { + rx_reorder_array_elem = &peer->tids_rx_reorder[tid].array[idx]; + if (rx_reorder_array_elem->head) { + OL_RX_REORDER_MPDU_CNT_DECR(&peer->tids_rx_reorder[tid], + 1); + OL_RX_REORDER_LIST_APPEND(head_msdu, tail_msdu, + rx_reorder_array_elem); + tail_msdu = rx_reorder_array_elem->tail; + } + rx_reorder_array_elem->head = rx_reorder_array_elem->tail = + NULL; + idx++; + OL_RX_REORDER_IDX_WRAP(idx, win_sz, win_sz_mask); + } + if (head_msdu) { + uint16_t seq_num; + htt_pdev_handle htt_pdev = vdev->pdev->htt_pdev; + + /* + * This logic is not quite correct - the last_seq value should + * be the sequence number of the final MPDU released rather than + * the initial MPDU released. + * However, tracking the sequence number of the first MPDU in + * the released batch works well enough: + * For Peregrine and Rome, the last_seq is checked only for + * non-aggregate cases, where only one MPDU at a time is + * released. + * For Riva, Pronto, and Northstar, the last_seq is checked to + * filter out late-arriving rx frames, whose sequence number + * will be less than the first MPDU in this release batch. + */ + seq_num = htt_rx_mpdu_desc_seq_num( + htt_pdev, + htt_rx_msdu_desc_retrieve(htt_pdev, + head_msdu)); + peer->tids_last_seq[tid] = seq_num; + /* rx_opt_proc takes a NULL-terminated list of msdu netbufs */ + qdf_nbuf_set_next(tail_msdu, NULL); + peer->rx_opt_proc(vdev, peer, tid, head_msdu); + } + /* + * If the rx reorder timeout is handled by host SW rather than the + * target's rx reorder logic, then stop the timer here. + * (If there are remaining rx holes, then the timer will be restarted.) + */ + OL_RX_REORDER_TIMEOUT_REMOVE(peer, tid); +} + +void +ol_rx_reorder_flush(struct ol_txrx_vdev_t *vdev, + struct ol_txrx_peer_t *peer, + unsigned tid, + unsigned idx_start, + unsigned idx_end, enum htt_rx_flush_action action) +{ + struct ol_txrx_pdev_t *pdev; + unsigned win_sz; + uint8_t win_sz_mask; + struct ol_rx_reorder_array_elem_t *rx_reorder_array_elem; + qdf_nbuf_t head_msdu = NULL; + qdf_nbuf_t tail_msdu = NULL; + + pdev = vdev->pdev; + win_sz = peer->tids_rx_reorder[tid].win_sz; + win_sz_mask = peer->tids_rx_reorder[tid].win_sz_mask; + + OL_RX_REORDER_IDX_START_SELF_SELECT(peer, tid, &idx_start); + /* a idx_end value of 0xffff means to flush the entire array */ + if (idx_end == 0xffff) { + idx_end = idx_start; + /* + * The array is being flushed in entirety because the block + * ack window has been shifted to a new position that does not + * overlap with the old position. (Or due to reception of a + * DELBA.) + * Thus, since the block ack window is essentially being reset, + * reset the "next release index". + */ + peer->tids_next_rel_idx[tid] = + OL_RX_REORDER_IDX_INIT(0 /*n/a */, win_sz, win_sz_mask); + } else { + peer->tids_next_rel_idx[tid] = (uint16_t) idx_end; + } + + idx_start &= win_sz_mask; + idx_end &= win_sz_mask; + + do { + rx_reorder_array_elem = + &peer->tids_rx_reorder[tid].array[idx_start]; + idx_start = (idx_start + 1); + OL_RX_REORDER_IDX_WRAP(idx_start, win_sz, win_sz_mask); + + if (rx_reorder_array_elem->head) { + OL_RX_REORDER_MPDU_CNT_DECR(&peer->tids_rx_reorder[tid], + 1); + if (head_msdu == NULL) { + head_msdu = rx_reorder_array_elem->head; + tail_msdu = rx_reorder_array_elem->tail; + rx_reorder_array_elem->head = NULL; + rx_reorder_array_elem->tail = NULL; + continue; + } + qdf_nbuf_set_next(tail_msdu, + rx_reorder_array_elem->head); + tail_msdu = rx_reorder_array_elem->tail; + rx_reorder_array_elem->head = + rx_reorder_array_elem->tail = NULL; + } + } while (idx_start != idx_end); + + ol_rx_defrag_waitlist_remove(peer, tid); + + if (head_msdu) { + uint16_t seq_num; + htt_pdev_handle htt_pdev = vdev->pdev->htt_pdev; + + seq_num = htt_rx_mpdu_desc_seq_num( + htt_pdev, + htt_rx_msdu_desc_retrieve(htt_pdev, head_msdu)); + peer->tids_last_seq[tid] = seq_num; + /* rx_opt_proc takes a NULL-terminated list of msdu netbufs */ + qdf_nbuf_set_next(tail_msdu, NULL); + if (action == htt_rx_flush_release) { + peer->rx_opt_proc(vdev, peer, tid, head_msdu); + } else { + do { + qdf_nbuf_t next; + next = qdf_nbuf_next(head_msdu); + htt_rx_desc_frame_free(pdev->htt_pdev, + head_msdu); + head_msdu = next; + } while (head_msdu); + } + } + /* + * If the rx reorder array is empty, then reset the last_seq value - + * it is likely that a BAR or a sequence number shift caused the + * sequence number to jump, so the old last_seq value is not relevant. + */ + if (OL_RX_REORDER_NO_HOLES(&peer->tids_rx_reorder[tid])) + peer->tids_last_seq[tid] = IEEE80211_SEQ_MAX; /* invalid */ + + OL_RX_REORDER_TIMEOUT_REMOVE(peer, tid); +} + +void +ol_rx_reorder_first_hole(struct ol_txrx_peer_t *peer, + unsigned tid, unsigned *idx_end) +{ + unsigned win_sz, win_sz_mask; + unsigned idx_start = 0, tmp_idx = 0; + + win_sz = peer->tids_rx_reorder[tid].win_sz; + win_sz_mask = peer->tids_rx_reorder[tid].win_sz_mask; + + OL_RX_REORDER_IDX_START_SELF_SELECT(peer, tid, &idx_start); + tmp_idx++; + OL_RX_REORDER_IDX_WRAP(tmp_idx, win_sz, win_sz_mask); + /* bypass the initial hole */ + while (tmp_idx != idx_start && + !peer->tids_rx_reorder[tid].array[tmp_idx].head) { + tmp_idx++; + OL_RX_REORDER_IDX_WRAP(tmp_idx, win_sz, win_sz_mask); + } + /* bypass the present frames following the initial hole */ + while (tmp_idx != idx_start && + peer->tids_rx_reorder[tid].array[tmp_idx].head) { + tmp_idx++; + OL_RX_REORDER_IDX_WRAP(tmp_idx, win_sz, win_sz_mask); + } + /* + * idx_end is exclusive rather than inclusive. + * In other words, it is the index of the first slot of the second + * hole, rather than the index of the final present frame following + * the first hole. + */ + *idx_end = tmp_idx; +} + +void +ol_rx_reorder_peer_cleanup(struct ol_txrx_vdev_t *vdev, + struct ol_txrx_peer_t *peer) +{ + int tid; + for (tid = 0; tid < OL_TXRX_NUM_EXT_TIDS; tid++) { + ol_rx_reorder_flush(vdev, peer, tid, 0, 0, + htt_rx_flush_discard); + } + OL_RX_REORDER_TIMEOUT_PEER_CLEANUP(peer); +} + +/* functions called by HTT */ + +void +ol_rx_addba_handler(ol_txrx_pdev_handle pdev, + uint16_t peer_id, + uint8_t tid, + uint8_t win_sz, uint16_t start_seq_num, uint8_t failed) +{ + uint8_t round_pwr2_win_sz; + unsigned array_size; + struct ol_txrx_peer_t *peer; + struct ol_rx_reorder_t *rx_reorder; + + peer = ol_txrx_peer_find_by_id(pdev, peer_id); + if (peer == NULL) + return; + + if (pdev->cfg.host_addba) { + ol_ctrl_rx_addba_complete(pdev->ctrl_pdev, + &peer->mac_addr.raw[0], tid, failed); + } + if (failed) + return; + + peer->tids_last_seq[tid] = IEEE80211_SEQ_MAX; /* invalid */ + rx_reorder = &peer->tids_rx_reorder[tid]; + + TXRX_ASSERT2(win_sz <= 64); + rx_reorder->win_sz = win_sz; + round_pwr2_win_sz = OL_RX_REORDER_ROUND_PWR2(win_sz); + array_size = + round_pwr2_win_sz * sizeof(struct ol_rx_reorder_array_elem_t); + rx_reorder->array = qdf_mem_malloc(array_size); + TXRX_ASSERT1(rx_reorder->array); + + rx_reorder->win_sz_mask = round_pwr2_win_sz - 1; + rx_reorder->num_mpdus = 0; + + peer->tids_next_rel_idx[tid] = + OL_RX_REORDER_IDX_INIT(start_seq_num, rx_reorder->win_sz, + rx_reorder->win_sz_mask); +} + +void +ol_rx_delba_handler(ol_txrx_pdev_handle pdev, uint16_t peer_id, uint8_t tid) +{ + struct ol_txrx_peer_t *peer; + struct ol_rx_reorder_t *rx_reorder; + + peer = ol_txrx_peer_find_by_id(pdev, peer_id); + if (peer == NULL) + return; + + peer->tids_next_rel_idx[tid] = 0xffff; /* invalid value */ + rx_reorder = &peer->tids_rx_reorder[tid]; + + /* check that there really was a block ack agreement */ + TXRX_ASSERT1(rx_reorder->win_sz_mask != 0); + /* + * Deallocate the old rx reorder array. + * The call to ol_rx_reorder_init below + * will reset rx_reorder->array to point to + * the single-element statically-allocated reorder array + * used for non block-ack cases. + */ + if (rx_reorder->array != &rx_reorder->base) { + TXRX_PRINT(TXRX_PRINT_LEVEL_INFO1, + "%s, delete reorder array, tid:%d\n", __func__, tid); + qdf_mem_free(rx_reorder->array); + } + + /* set up the TID with default parameters (ARQ window size = 1) */ + ol_rx_reorder_init(rx_reorder, tid); +} + +void +ol_rx_flush_handler(ol_txrx_pdev_handle pdev, + uint16_t peer_id, + uint8_t tid, + uint16_t idx_start, + uint16_t idx_end, enum htt_rx_flush_action action) +{ + struct ol_txrx_vdev_t *vdev = NULL; + void *rx_desc; + struct ol_txrx_peer_t *peer; + int idx; + struct ol_rx_reorder_array_elem_t *rx_reorder_array_elem; + htt_pdev_handle htt_pdev = pdev->htt_pdev; + + peer = ol_txrx_peer_find_by_id(pdev, peer_id); + if (peer) + vdev = peer->vdev; + else + return; + + OL_RX_REORDER_TIMEOUT_MUTEX_LOCK(pdev); + + idx = idx_start & peer->tids_rx_reorder[tid].win_sz_mask; + rx_reorder_array_elem = &peer->tids_rx_reorder[tid].array[idx]; + if (rx_reorder_array_elem->head) { + rx_desc = + htt_rx_msdu_desc_retrieve(htt_pdev, + rx_reorder_array_elem->head); + if (htt_rx_msdu_is_frag(htt_pdev, rx_desc)) { + ol_rx_reorder_flush_frag(htt_pdev, peer, tid, + idx_start); + /* + * Assuming flush message sent seperately for frags + * and for normal frames + */ + OL_RX_REORDER_TIMEOUT_MUTEX_UNLOCK(pdev); + return; + } + } + ol_rx_reorder_flush(vdev, peer, tid, idx_start, idx_end, action); + /* + * If the rx reorder timeout is handled by host SW, see if there are + * remaining rx holes that require the timer to be restarted. + */ + OL_RX_REORDER_TIMEOUT_UPDATE(peer, tid); + OL_RX_REORDER_TIMEOUT_MUTEX_UNLOCK(pdev); +} + +void +ol_rx_pn_ind_handler(ol_txrx_pdev_handle pdev, + uint16_t peer_id, + uint8_t tid, + int seq_num_start, + int seq_num_end, uint8_t pn_ie_cnt, uint8_t *pn_ie) +{ + struct ol_txrx_vdev_t *vdev = NULL; + void *rx_desc; + struct ol_txrx_peer_t *peer; + struct ol_rx_reorder_array_elem_t *rx_reorder_array_elem; + unsigned win_sz_mask; + qdf_nbuf_t head_msdu = NULL; + qdf_nbuf_t tail_msdu = NULL; + htt_pdev_handle htt_pdev = pdev->htt_pdev; + int seq_num, i = 0; + + peer = ol_txrx_peer_find_by_id(pdev, peer_id); + + if (!peer) { + /* + * If we can't find a peer send this packet to OCB interface + * using OCB self peer + */ + if (!ol_txrx_get_ocb_peer(pdev, &peer)) + peer = NULL; + } + + if (peer) + vdev = peer->vdev; + else + return; + + qdf_atomic_set(&peer->fw_pn_check, 1); + /*TODO: Fragmentation case */ + win_sz_mask = peer->tids_rx_reorder[tid].win_sz_mask; + seq_num_start &= win_sz_mask; + seq_num_end &= win_sz_mask; + seq_num = seq_num_start; + + do { + rx_reorder_array_elem = + &peer->tids_rx_reorder[tid].array[seq_num]; + + if (rx_reorder_array_elem->head) { + if (pn_ie_cnt && seq_num == (int)(pn_ie[i])) { + qdf_nbuf_t msdu, next_msdu, mpdu_head, + mpdu_tail; + static uint32_t last_pncheck_print_time; + /* Do not need to initialize as C does it */ + + int log_level; + uint32_t current_time_ms; + union htt_rx_pn_t pn = { 0 }; + int index, pn_len; + + mpdu_head = msdu = rx_reorder_array_elem->head; + mpdu_tail = rx_reorder_array_elem->tail; + + pn_ie_cnt--; + i++; + rx_desc = htt_rx_msdu_desc_retrieve(htt_pdev, + msdu); + index = htt_rx_msdu_is_wlan_mcast( + pdev->htt_pdev, rx_desc) + ? txrx_sec_mcast + : txrx_sec_ucast; + pn_len = pdev->rx_pn[peer->security[index]. + sec_type].len; + htt_rx_mpdu_desc_pn(htt_pdev, rx_desc, &pn, + pn_len); + + current_time_ms = qdf_system_ticks_to_msecs( + qdf_system_ticks()); + if (TXRX_PN_CHECK_FAILURE_PRINT_PERIOD_MS < + (current_time_ms - + last_pncheck_print_time)) { + last_pncheck_print_time = + current_time_ms; + log_level = TXRX_PRINT_LEVEL_WARN; + } else { + log_level = TXRX_PRINT_LEVEL_INFO2; + } + TXRX_PRINT(log_level, + "Tgt PN check failed - TID %d, peer %p " + "(%02x:%02x:%02x:%02x:%02x:%02x)\n" + " PN (u64 x2)= 0x%08llx %08llx (LSBs = %lld)\n" + " new seq num = %d\n", + tid, peer, + peer->mac_addr.raw[0], + peer->mac_addr.raw[1], + peer->mac_addr.raw[2], + peer->mac_addr.raw[3], + peer->mac_addr.raw[4], + peer->mac_addr.raw[5], pn.pn128[1], + pn.pn128[0], + pn.pn128[0] & 0xffffffffffffULL, + htt_rx_mpdu_desc_seq_num(htt_pdev, + rx_desc)); + ol_rx_err(pdev->ctrl_pdev, vdev->vdev_id, + peer->mac_addr.raw, tid, + htt_rx_mpdu_desc_tsf32(htt_pdev, + rx_desc), + OL_RX_ERR_PN, mpdu_head, NULL, 0); + + /* free all MSDUs within this MPDU */ + do { + next_msdu = qdf_nbuf_next(msdu); + htt_rx_desc_frame_free(htt_pdev, msdu); + if (msdu == mpdu_tail) + break; + else + msdu = next_msdu; + } while (1); + + } else { + if (head_msdu == NULL) { + head_msdu = rx_reorder_array_elem->head; + tail_msdu = rx_reorder_array_elem->tail; + } else { + qdf_nbuf_set_next( + tail_msdu, + rx_reorder_array_elem->head); + tail_msdu = rx_reorder_array_elem->tail; + } + } + rx_reorder_array_elem->head = NULL; + rx_reorder_array_elem->tail = NULL; + } + seq_num = (seq_num + 1) & win_sz_mask; + } while (seq_num != seq_num_end); + + if (head_msdu) { + /* rx_opt_proc takes a NULL-terminated list of msdu netbufs */ + qdf_nbuf_set_next(tail_msdu, NULL); + peer->rx_opt_proc(vdev, peer, tid, head_msdu); + } +} + +#if defined(ENABLE_RX_REORDER_TRACE) + +A_STATUS ol_rx_reorder_trace_attach(ol_txrx_pdev_handle pdev) +{ + int num_elems; + + num_elems = 1 << TXRX_RX_REORDER_TRACE_SIZE_LOG2; + pdev->rx_reorder_trace.idx = 0; + pdev->rx_reorder_trace.cnt = 0; + pdev->rx_reorder_trace.mask = num_elems - 1; + pdev->rx_reorder_trace.data = qdf_mem_malloc( + sizeof(*pdev->rx_reorder_trace.data) * num_elems); + if (!pdev->rx_reorder_trace.data) + return A_NO_MEMORY; + + while (--num_elems >= 0) + pdev->rx_reorder_trace.data[num_elems].seq_num = 0xffff; + + return A_OK; +} + +void ol_rx_reorder_trace_detach(ol_txrx_pdev_handle pdev) +{ + qdf_mem_free(pdev->rx_reorder_trace.data); +} + +void +ol_rx_reorder_trace_add(ol_txrx_pdev_handle pdev, + uint8_t tid, + uint16_t reorder_idx, uint16_t seq_num, int num_mpdus) +{ + uint32_t idx = pdev->rx_reorder_trace.idx; + + pdev->rx_reorder_trace.data[idx].tid = tid; + pdev->rx_reorder_trace.data[idx].reorder_idx = reorder_idx; + pdev->rx_reorder_trace.data[idx].seq_num = seq_num; + pdev->rx_reorder_trace.data[idx].num_mpdus = num_mpdus; + pdev->rx_reorder_trace.cnt++; + idx++; + pdev->rx_reorder_trace.idx = idx & pdev->rx_reorder_trace.mask; +} + +void +ol_rx_reorder_trace_display(ol_txrx_pdev_handle pdev, int just_once, int limit) +{ + static int print_count; + uint32_t i, start, end; + uint64_t cnt; + int elems; + + if (print_count != 0 && just_once) + return; + + print_count++; + + end = pdev->rx_reorder_trace.idx; + if (pdev->rx_reorder_trace.data[end].seq_num == 0xffff) { + /* trace log has not yet wrapped around - start at the top */ + start = 0; + cnt = 0; + } else { + start = end; + cnt = pdev->rx_reorder_trace.cnt - + (pdev->rx_reorder_trace.mask + 1); + } + elems = (end - 1 - start) & pdev->rx_reorder_trace.mask; + if (limit > 0 && elems > limit) { + int delta; + delta = elems - limit; + start += delta; + start &= pdev->rx_reorder_trace.mask; + cnt += delta; + } + + i = start; + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO, + " log array seq"); + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO, + " count idx tid idx num (LSBs)"); + do { + uint16_t seq_num, reorder_idx; + seq_num = pdev->rx_reorder_trace.data[i].seq_num; + reorder_idx = pdev->rx_reorder_trace.data[i].reorder_idx; + if (seq_num < (1 << 14)) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO, + " %6lld %4d %3d %4d %4d (%d)", + cnt, i, pdev->rx_reorder_trace.data[i].tid, + reorder_idx, seq_num, seq_num & 63); + } else { + int err = TXRX_SEQ_NUM_ERR(seq_num); + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO, + " %6lld %4d err %d (%d MPDUs)", + cnt, i, err, + pdev->rx_reorder_trace.data[i].num_mpdus); + } + cnt++; + i++; + i &= pdev->rx_reorder_trace.mask; + } while (i != end); +} + +#endif /* ENABLE_RX_REORDER_TRACE */ diff --git a/drivers/staging/qcacld-3.0/core/dp/txrx/ol_rx_reorder.h b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_rx_reorder.h new file mode 100644 index 0000000000000000000000000000000000000000..701715423152596d75bd6aa9b7d2f7a8034a2173 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_rx_reorder.h @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2011, 2014-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef _OL_RX_REORDER__H_ +#define _OL_RX_REORDER__H_ + +#include /* qdf_nbuf_t, etc. */ + +#include /* ol_txrx_peer_t, etc. */ + +#include /* ol_rx_reorder_t */ + +void +ol_rx_reorder_store(struct ol_txrx_pdev_t *pdev, + struct ol_txrx_peer_t *peer, + unsigned tid, + unsigned reorder_array_index, + qdf_nbuf_t head_msdu, qdf_nbuf_t tail_msdu); + +void +ol_rx_reorder_release(struct ol_txrx_vdev_t *vdev, + struct ol_txrx_peer_t *peer, + unsigned tid, + unsigned seq_num_start, unsigned seq_num_end); + +void +ol_rx_reorder_flush(struct ol_txrx_vdev_t *vdev, + struct ol_txrx_peer_t *peer, + unsigned tid, + unsigned seq_num_start, + unsigned seq_num_end, enum htt_rx_flush_action action); + +/** + * @brief - find end of first range of present MPDUs after the initial rx hole + * @param[in] peer - which sender's data is being checked + * @param[in] tid - which type of data is being checked + * @param[out] idx_end - the reorder array index holding the last MPDU in the + * range of in-order MPDUs that following the initial hole. + * Note that this is the index of the last in-order MPDU following the + * first hole, rather than the starting index of the second hole. + */ +void +ol_rx_reorder_first_hole(struct ol_txrx_peer_t *peer, + unsigned tid, unsigned *idx_end); + +void +ol_rx_reorder_peer_cleanup(struct ol_txrx_vdev_t *vdev, + struct ol_txrx_peer_t *peer); + +void ol_rx_reorder_init(struct ol_rx_reorder_t *rx_reorder, uint8_t tid); + +enum htt_rx_status +ol_rx_seq_num_check(struct ol_txrx_pdev_t *pdev, + struct ol_txrx_peer_t *peer, + uint8_t tid, void *rx_mpdu_desc); + +/* + * Peregrine and Rome: do sequence number checking in the host + * for peer-TIDs without aggregation enabled + */ + +#define OL_RX_SEQ_NUM_CHECK(pdev, peer, tid, rx_mpdu_desc) \ + (pdev->rx.flags.dup_check && peer->tids_rx_reorder[tid].win_sz_mask == 0) ? \ + ol_rx_seq_num_check( \ + pdev, peer, tid, \ + rx_mpdu_desc) : \ + htt_rx_status_ok + +#endif /* _OL_RX_REORDER__H_ */ diff --git a/drivers/staging/qcacld-3.0/core/dp/txrx/ol_rx_reorder_timeout.c b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_rx_reorder_timeout.c new file mode 100644 index 0000000000000000000000000000000000000000..d2a9f8a17a15dba8735496b6ab4d052c742f7f78 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_rx_reorder_timeout.c @@ -0,0 +1,219 @@ +/* + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/*=== header file includes ===*/ +/* generic utilities */ +#include /* qdf_nbuf_t, etc. */ +#include +#include + +/* datapath internal interfaces */ +#include /* TXRX_ASSERT, etc. */ +#include /* ol_rx_reorder_flush, etc. */ + +#ifdef QCA_SUPPORT_OL_RX_REORDER_TIMEOUT + +void ol_rx_reorder_timeout_remove(struct ol_txrx_peer_t *peer, unsigned tid) +{ + struct ol_txrx_pdev_t *pdev; + struct ol_tx_reorder_cat_timeout_t *rx_reorder_timeout_ac; + struct ol_rx_reorder_timeout_list_elem_t *list_elem; + int ac; + + pdev = peer->vdev->pdev; + ac = TXRX_TID_TO_WMM_AC(tid); + rx_reorder_timeout_ac = &pdev->rx.reorder_timeout.access_cats[ac]; + list_elem = &peer->tids_rx_reorder[tid].timeout; + if (!list_elem->active) { + /* this element has already been removed */ + return; + } + list_elem->active = 0; + TAILQ_REMOVE(&rx_reorder_timeout_ac->virtual_timer_list, list_elem, + reorder_timeout_list_elem); +} + +static void +ol_rx_reorder_timeout_start(struct ol_tx_reorder_cat_timeout_t + *rx_reorder_timeout_ac, uint32_t time_now_ms) +{ + uint32_t duration_ms; + struct ol_rx_reorder_timeout_list_elem_t *list_elem; + + list_elem = TAILQ_FIRST(&rx_reorder_timeout_ac->virtual_timer_list); + + duration_ms = list_elem->timestamp_ms - time_now_ms; + qdf_timer_start(&rx_reorder_timeout_ac->timer, duration_ms); +} + +static inline void +ol_rx_reorder_timeout_add(struct ol_txrx_peer_t *peer, uint8_t tid) +{ + uint32_t time_now_ms; + struct ol_txrx_pdev_t *pdev; + struct ol_tx_reorder_cat_timeout_t *rx_reorder_timeout_ac; + struct ol_rx_reorder_timeout_list_elem_t *list_elem; + int ac; + int start; + + pdev = peer->vdev->pdev; + ac = TXRX_TID_TO_WMM_AC(tid); + rx_reorder_timeout_ac = &pdev->rx.reorder_timeout.access_cats[ac]; + list_elem = &peer->tids_rx_reorder[tid].timeout; + + list_elem->active = 1; + list_elem->peer = peer; + list_elem->tid = tid; + + /* set the expiration timestamp */ + time_now_ms = qdf_system_ticks_to_msecs(qdf_system_ticks()); + list_elem->timestamp_ms = + time_now_ms + rx_reorder_timeout_ac->duration_ms; + + /* add to the queue */ + start = TAILQ_EMPTY(&rx_reorder_timeout_ac->virtual_timer_list); + TAILQ_INSERT_TAIL(&rx_reorder_timeout_ac->virtual_timer_list, + list_elem, reorder_timeout_list_elem); + if (start) + ol_rx_reorder_timeout_start(rx_reorder_timeout_ac, time_now_ms); +} + +void ol_rx_reorder_timeout_update(struct ol_txrx_peer_t *peer, uint8_t tid) +{ + if (!peer) + return; + + /* + * If there are no holes, i.e. no queued frames, + * then timeout doesn't apply. + */ + if (peer->tids_rx_reorder[tid].num_mpdus == 0) + return; + + /* + * If the virtual timer for this peer-TID is already running, + * then leave it. + */ + if (peer->tids_rx_reorder[tid].timeout.active) + return; + + ol_rx_reorder_timeout_add(peer, tid); +} + +static void ol_rx_reorder_timeout(void *arg) +{ + struct ol_txrx_pdev_t *pdev; + struct ol_rx_reorder_timeout_list_elem_t *list_elem, *tmp; + uint32_t time_now_ms; + struct ol_tx_reorder_cat_timeout_t *rx_reorder_timeout_ac; + + rx_reorder_timeout_ac = (struct ol_tx_reorder_cat_timeout_t *)arg; + time_now_ms = qdf_system_ticks_to_msecs(qdf_system_ticks()); + + pdev = rx_reorder_timeout_ac->pdev; + qdf_spin_lock(&pdev->rx.mutex); +/* TODO: conditionally take mutex lock during regular rx */ + TAILQ_FOREACH_SAFE(list_elem, + &rx_reorder_timeout_ac->virtual_timer_list, + reorder_timeout_list_elem, tmp) { + unsigned idx_start, idx_end; + struct ol_txrx_peer_t *peer; + + if (list_elem->timestamp_ms > time_now_ms) + break; /* time has not expired yet for this element */ + + list_elem->active = 0; + /* remove the expired element from the list */ + TAILQ_REMOVE(&rx_reorder_timeout_ac->virtual_timer_list, + list_elem, reorder_timeout_list_elem); + + peer = list_elem->peer; + + idx_start = 0xffff; /* start from next_rel_idx */ + ol_rx_reorder_first_hole(peer, list_elem->tid, &idx_end); + ol_rx_reorder_flush(peer->vdev, + peer, + list_elem->tid, + idx_start, idx_end, htt_rx_flush_release); + } + /* restart the timer if unexpired elements are left in the list */ + if (!TAILQ_EMPTY(&rx_reorder_timeout_ac->virtual_timer_list)) + ol_rx_reorder_timeout_start(rx_reorder_timeout_ac, time_now_ms); + + qdf_spin_unlock(&pdev->rx.mutex); +} + +void ol_rx_reorder_timeout_init(struct ol_txrx_pdev_t *pdev) +{ + int i; + + for (i = 0; i < QDF_ARRAY_SIZE(pdev->rx.reorder_timeout.access_cats); + i++) { + struct ol_tx_reorder_cat_timeout_t *rx_reorder_timeout_ac; + rx_reorder_timeout_ac = + &pdev->rx.reorder_timeout.access_cats[i]; + /* init the per-AC timers */ + qdf_timer_init(pdev->osdev, + &rx_reorder_timeout_ac->timer, + ol_rx_reorder_timeout, + rx_reorder_timeout_ac, + QDF_TIMER_TYPE_SW); + /* init the virtual timer list */ + TAILQ_INIT(&rx_reorder_timeout_ac->virtual_timer_list); + rx_reorder_timeout_ac->pdev = pdev; + } + pdev->rx.reorder_timeout.access_cats[TXRX_WMM_AC_VO].duration_ms = 40; + pdev->rx.reorder_timeout.access_cats[TXRX_WMM_AC_VI].duration_ms = 100; + pdev->rx.reorder_timeout.access_cats[TXRX_WMM_AC_BE].duration_ms = 100; + pdev->rx.reorder_timeout.access_cats[TXRX_WMM_AC_BK].duration_ms = 100; +} + +void ol_rx_reorder_timeout_peer_cleanup(struct ol_txrx_peer_t *peer) +{ + int tid; + + for (tid = 0; tid < OL_TXRX_NUM_EXT_TIDS; tid++) { + if (peer->tids_rx_reorder[tid].timeout.active) + ol_rx_reorder_timeout_remove(peer, tid); + } +} + +void ol_rx_reorder_timeout_cleanup(struct ol_txrx_pdev_t *pdev) +{ + int i; + + for (i = 0; i < QDF_ARRAY_SIZE(pdev->rx.reorder_timeout.access_cats); + i++) { + struct ol_tx_reorder_cat_timeout_t *rx_reorder_timeout_ac; + rx_reorder_timeout_ac = + &pdev->rx.reorder_timeout.access_cats[i]; + qdf_timer_stop(&rx_reorder_timeout_ac->timer); + qdf_timer_free(&rx_reorder_timeout_ac->timer); + } +} + +#endif /* QCA_SUPPORT_OL_RX_REORDER_TIMEOUT */ diff --git a/drivers/staging/qcacld-3.0/core/dp/txrx/ol_rx_reorder_timeout.h b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_rx_reorder_timeout.h new file mode 100644 index 0000000000000000000000000000000000000000..950e3843ab5754f415cdb9507c3d9201e7cd76f9 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_rx_reorder_timeout.h @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2012, 2014, 2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef _OL_RX_REORDER_TIMEOUT__H_ +#define _OL_RX_REORDER_TIMEOUT__H_ + +#include /* ol_txrx_vdev_t, etc. */ +#ifdef QCA_SUPPORT_OL_RX_REORDER_TIMEOUT + +void ol_rx_reorder_timeout_init(struct ol_txrx_pdev_t *pdev); +void ol_rx_reorder_timeout_cleanup(struct ol_txrx_pdev_t *pdev); +void ol_rx_reorder_timeout_remove(struct ol_txrx_peer_t *peer, unsigned tid); +void ol_rx_reorder_timeout_update(struct ol_txrx_peer_t *peer, uint8_t tid); +void ol_rx_reorder_timeout_peer_cleanup(struct ol_txrx_peer_t *peer); + +#define OL_RX_REORDER_TIMEOUT_INIT ol_rx_reorder_timeout_init +#define OL_RX_REORDER_TIMEOUT_PEER_CLEANUP ol_rx_reorder_timeout_peer_cleanup +#define OL_RX_REORDER_TIMEOUT_CLEANUP ol_rx_reorder_timeout_cleanup +#define OL_RX_REORDER_TIMEOUT_REMOVE ol_rx_reorder_timeout_remove +#define OL_RX_REORDER_TIMEOUT_UPDATE ol_rx_reorder_timeout_update +#define OL_RX_REORDER_TIMEOUT_PEER_TID_INIT(peer, tid) \ + (peer)->tids_rx_reorder[(tid)].timeout.active = 0 +#define OL_RX_REORDER_TIMEOUT_MUTEX_LOCK(pdev) \ + qdf_spin_lock(&(pdev)->rx.mutex) +#define OL_RX_REORDER_TIMEOUT_MUTEX_UNLOCK(pdev) \ + qdf_spin_unlock(&(pdev)->rx.mutex) + +#else + +#define OL_RX_REORDER_TIMEOUT_INIT(pdev) /* no-op */ +#define OL_RX_REORDER_TIMEOUT_PEER_CLEANUP(peer) /* no-op */ +#define OL_RX_REORDER_TIMEOUT_CLEANUP(pdev) /* no-op */ +#define OL_RX_REORDER_TIMEOUT_REMOVE(peer, tid) /* no-op */ +#define OL_RX_REORDER_TIMEOUT_UPDATE(peer, tid) /* no-op */ +#define OL_RX_REORDER_TIMEOUT_PEER_TID_INIT(peer, tid) /* no-op */ +#define OL_RX_REORDER_TIMEOUT_MUTEX_LOCK(pdev) /* no-op */ +#define OL_RX_REORDER_TIMEOUT_MUTEX_UNLOCK(pdev) /* no-op */ + +#endif /* QCA_SUPPORT_OL_RX_REORDER_TIMEOUT */ + +#endif /* _OL_RX_REORDER_TIMEOUT__H_ */ diff --git a/drivers/staging/qcacld-3.0/core/dp/txrx/ol_tx.c b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_tx.c new file mode 100644 index 0000000000000000000000000000000000000000..28816379514979d39b019759a72c8ccabe5e8705 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_tx.c @@ -0,0 +1,2328 @@ +/* + * Copyright (c) 2011-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* OS abstraction libraries */ +#include /* qdf_nbuf_t, etc. */ +#include /* qdf_atomic_read, etc. */ +#include /* qdf_unlikely */ + +/* APIs for other modules */ +#include /* HTT_TX_EXT_TID_MGMT */ +#include /* htt_tx_desc_tid */ + +/* internal header files relevant for all systems */ +#include /* TXRX_ASSERT1 */ +#include /* ol_tx_desc */ +#include /* ol_tx_send */ +#include + +/* internal header files relevant only for HL systems */ +#include /* ol_tx_classify, ol_tx_classify_mgmt */ +#include /* ol_tx_enqueue */ +#include /* ol_tx_sched */ + + +/* internal header files relevant only for specific systems (Pronto) */ +#include /* OL_TX_ENCAP, etc */ +#include + +#ifdef WLAN_FEATURE_FASTPATH +#include /* HIF_DEVICE */ +#include /* Layering violation, but required for fast path */ +#include +#include /* htc_endpoint */ +#include +#include + +int ce_send_fast(struct CE_handle *copyeng, qdf_nbuf_t msdu, + unsigned int transfer_id, uint32_t download_len); +#endif /* WLAN_FEATURE_FASTPATH */ + +/* + * The TXRX module doesn't accept tx frames unless the target has + * enough descriptors for them. + * For LL, the TXRX descriptor pool is sized to match the target's + * descriptor pool. Hence, if the descriptor allocation in TXRX + * succeeds, that guarantees that the target has room to accept + * the new tx frame. + */ +#define ol_tx_prepare_ll(tx_desc, vdev, msdu, msdu_info) \ + do { \ + struct ol_txrx_pdev_t *pdev = vdev->pdev; \ + (msdu_info)->htt.info.frame_type = pdev->htt_pkt_type; \ + tx_desc = ol_tx_desc_ll(pdev, vdev, msdu, msdu_info); \ + if (qdf_unlikely(!tx_desc)) { \ + /* \ + * If TSO packet, free associated \ + * remaining TSO segment descriptors \ + */ \ + if (qdf_nbuf_is_tso(msdu)) \ + ol_free_remaining_tso_segs( \ + vdev, msdu_info, true); \ + TXRX_STATS_MSDU_LIST_INCR( \ + pdev, tx.dropped.host_reject, msdu); \ + return msdu; /* the list of unaccepted MSDUs */ \ + } \ + } while (0) + +#if defined(FEATURE_TSO) +void ol_free_remaining_tso_segs(ol_txrx_vdev_handle vdev, + struct ol_txrx_msdu_info_t *msdu_info, + bool is_tso_seg_mapping_done) +{ + struct qdf_tso_seg_elem_t *next_seg; + struct qdf_tso_seg_elem_t *free_seg = msdu_info->tso_info.curr_seg; + struct ol_txrx_pdev_t *pdev; + bool is_last_seg = false; + + if (qdf_unlikely(!vdev)) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "%s:vdev is null", __func__); + return; + } else { + pdev = vdev->pdev; + if (qdf_unlikely(!pdev)) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "%s:pdev is null", __func__); + return; + } + } + + if (is_tso_seg_mapping_done) { + /* + * TSO segment are mapped already, therefore, + * 1. unmap the tso segments, + * 2. free tso num segment if it is a last segment, and + * 3. free the tso segments. + */ + struct qdf_tso_num_seg_elem_t *tso_num_desc = + msdu_info->tso_info.tso_num_seg_list; + + if (qdf_unlikely(tso_num_desc == NULL)) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "%s %d TSO common info is NULL!", + __func__, __LINE__); + return; + } + + while (free_seg) { + qdf_spin_lock_bh(&pdev->tso_seg_pool.tso_mutex); + tso_num_desc->num_seg.tso_cmn_num_seg--; + + is_last_seg = (tso_num_desc->num_seg.tso_cmn_num_seg == + 0) ? true : false; + qdf_nbuf_unmap_tso_segment(pdev->osdev, free_seg, + is_last_seg); + qdf_spin_unlock_bh(&pdev->tso_seg_pool.tso_mutex); + + if (is_last_seg) { + ol_tso_num_seg_free(pdev, + msdu_info->tso_info.tso_num_seg_list); + msdu_info->tso_info.tso_num_seg_list = NULL; + } + + next_seg = free_seg->next; + ol_tso_free_segment(pdev, free_seg); + free_seg = next_seg; + } + } else { + /* + * TSO segment are not mapped therefore, + * free the tso segments only. + */ + while (free_seg) { + next_seg = free_seg->next; + ol_tso_free_segment(pdev, free_seg); + free_seg = next_seg; + } + } +} + +/** + * ol_tx_prepare_tso() - Given a jumbo msdu, prepare the TSO + * related information in the msdu_info meta data + * @vdev: virtual device handle + * @msdu: network buffer + * @msdu_info: meta data associated with the msdu + * + * Return: 0 - success, >0 - error + */ +static inline uint8_t ol_tx_prepare_tso(ol_txrx_vdev_handle vdev, + qdf_nbuf_t msdu, struct ol_txrx_msdu_info_t *msdu_info) +{ + msdu_info->tso_info.curr_seg = NULL; + if (qdf_nbuf_is_tso(msdu)) { + int num_seg = qdf_nbuf_get_tso_num_seg(msdu); + struct qdf_tso_num_seg_elem_t *tso_num_seg; + + msdu_info->tso_info.tso_num_seg_list = NULL; + msdu_info->tso_info.tso_seg_list = NULL; + msdu_info->tso_info.num_segs = num_seg; + while (num_seg) { + struct qdf_tso_seg_elem_t *tso_seg = + ol_tso_alloc_segment(vdev->pdev); + if (tso_seg) { + qdf_tso_seg_dbg_record(tso_seg, + TSOSEG_LOC_PREPARETSO); + tso_seg->next = + msdu_info->tso_info.tso_seg_list; + msdu_info->tso_info.tso_seg_list + = tso_seg; + num_seg--; + } else { + /* Free above alocated TSO segements till now */ + msdu_info->tso_info.curr_seg = + msdu_info->tso_info.tso_seg_list; + ol_free_remaining_tso_segs(vdev, msdu_info, + false); + return 1; + } + } + tso_num_seg = ol_tso_num_seg_alloc(vdev->pdev); + if (tso_num_seg) { + tso_num_seg->next = msdu_info->tso_info. + tso_num_seg_list; + msdu_info->tso_info.tso_num_seg_list = tso_num_seg; + } else { + /* Free the already allocated num of segments */ + msdu_info->tso_info.curr_seg = + msdu_info->tso_info.tso_seg_list; + ol_free_remaining_tso_segs(vdev, msdu_info, false); + return 1; + } + + if (qdf_unlikely(!qdf_nbuf_get_tso_info(vdev->pdev->osdev, + msdu, &(msdu_info->tso_info)))) { + /* Free the already allocated num of segments */ + msdu_info->tso_info.curr_seg = + msdu_info->tso_info.tso_seg_list; + ol_free_remaining_tso_segs(vdev, msdu_info, false); + return 1; + } + + msdu_info->tso_info.curr_seg = + msdu_info->tso_info.tso_seg_list; + num_seg = msdu_info->tso_info.num_segs; + } else { + msdu_info->tso_info.is_tso = 0; + msdu_info->tso_info.num_segs = 1; + } + return 0; +} +#endif + +/** + * ol_tx_data() - send data frame + * @vdev: virtual device handle + * @skb: skb + * + * Return: skb/NULL for success + */ +qdf_nbuf_t ol_tx_data(ol_txrx_vdev_handle vdev, qdf_nbuf_t skb) +{ + struct ol_txrx_pdev_t *pdev; + qdf_nbuf_t ret; + + if (qdf_unlikely(!vdev)) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_WARN, + "%s:vdev is null", __func__); + return skb; + } else { + pdev = vdev->pdev; + } + + if (qdf_unlikely(!pdev)) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_WARN, + "%s:pdev is null", __func__); + return skb; + } + + if ((ol_cfg_is_ip_tcp_udp_checksum_offload_enabled(pdev->ctrl_pdev)) + && (qdf_nbuf_get_protocol(skb) == htons(ETH_P_IP)) + && (qdf_nbuf_get_ip_summed(skb) == CHECKSUM_PARTIAL)) + qdf_nbuf_set_ip_summed(skb, CHECKSUM_COMPLETE); + + /* Terminate the (single-element) list of tx frames */ + qdf_nbuf_set_next(skb, NULL); + ret = OL_TX_SEND(vdev, skb); + if (ret) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_WARN, + "%s: Failed to tx", __func__); + return ret; + } + + return NULL; +} + +#ifdef IPA_OFFLOAD +/** + * ol_tx_send_ipa_data_frame() - send IPA data frame + * @vdev: vdev + * @skb: skb + * + * Return: skb/ NULL is for success + */ +qdf_nbuf_t ol_tx_send_ipa_data_frame(void *vdev, + qdf_nbuf_t skb) +{ + ol_txrx_pdev_handle pdev = cds_get_context(QDF_MODULE_ID_TXRX); + qdf_nbuf_t ret; + + if (qdf_unlikely(!pdev)) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "%s: pdev is NULL", __func__); + return skb; + } + + if ((ol_cfg_is_ip_tcp_udp_checksum_offload_enabled(pdev->ctrl_pdev)) + && (qdf_nbuf_get_protocol(skb) == htons(ETH_P_IP)) + && (qdf_nbuf_get_ip_summed(skb) == CHECKSUM_PARTIAL)) + qdf_nbuf_set_ip_summed(skb, CHECKSUM_COMPLETE); + + /* Terminate the (single-element) list of tx frames */ + qdf_nbuf_set_next(skb, NULL); + ret = OL_TX_SEND((struct ol_txrx_vdev_t *)vdev, skb); + if (ret) { + TXRX_PRINT(TXRX_PRINT_LEVEL_WARN, + "%s: Failed to tx", __func__); + return ret; + } + + return NULL; +} +#endif + +#if defined(FEATURE_TSO) +/** + * ol_tx_tso_update_stats() - update TSO stats + * @pdev: pointer to ol_txrx_pdev_t structure + * @msdu_info: tso msdu_info for the msdu + * @msdu: tso mdsu for which stats are updated + * @tso_msdu_idx: stats index in the global TSO stats array where stats will be + * updated + * + * Return: None + */ +static inline void ol_tx_tso_update_stats(struct ol_txrx_pdev_t *pdev , + struct qdf_tso_info_t *tso_info, + qdf_nbuf_t msdu, + uint32_t tso_msdu_idx) +{ + TXRX_STATS_TSO_HISTOGRAM(pdev, tso_info->num_segs); + TXRX_STATS_TSO_GSO_SIZE_UPDATE(pdev, tso_msdu_idx, + qdf_nbuf_tcp_tso_size(msdu)); + TXRX_STATS_TSO_TOTAL_LEN_UPDATE(pdev, + tso_msdu_idx, qdf_nbuf_len(msdu)); + TXRX_STATS_TSO_NUM_FRAGS_UPDATE(pdev, tso_msdu_idx, + qdf_nbuf_get_nr_frags(msdu)); +} + +/** + * ol_tx_tso_get_stats_idx() - retrieve global TSO stats index and increment it + * @pdev: pointer to ol_txrx_pdev_t structure + * + * Retreive the current value of the global variable and increment it. This is + * done in a spinlock as the global TSO stats may be accessed in parallel by + * multiple TX streams. + * + * Return: The current value of TSO stats index. + */ +static uint32_t ol_tx_tso_get_stats_idx(struct ol_txrx_pdev_t *pdev) +{ + uint32_t msdu_stats_idx = 0; + + qdf_spin_lock_bh(&pdev->stats.pub.tx.tso.tso_stats_lock); + msdu_stats_idx = pdev->stats.pub.tx.tso.tso_info.tso_msdu_idx; + pdev->stats.pub.tx.tso.tso_info.tso_msdu_idx++; + pdev->stats.pub.tx.tso.tso_info.tso_msdu_idx &= + NUM_MAX_TSO_MSDUS_MASK; + qdf_spin_unlock_bh(&pdev->stats.pub.tx.tso.tso_stats_lock); + + TXRX_STATS_TSO_RESET_MSDU(pdev, msdu_stats_idx); + + return msdu_stats_idx; +} +#endif + +#if defined(FEATURE_TSO) +qdf_nbuf_t ol_tx_ll(ol_txrx_vdev_handle vdev, qdf_nbuf_t msdu_list) +{ + qdf_nbuf_t msdu = msdu_list; + struct ol_txrx_msdu_info_t msdu_info; + uint32_t tso_msdu_stats_idx = 0; + + msdu_info.htt.info.l2_hdr_type = vdev->pdev->htt_pkt_type; + msdu_info.htt.action.tx_comp_req = 0; + /* + * The msdu_list variable could be used instead of the msdu var, + * but just to clarify which operations are done on a single MSDU + * vs. a list of MSDUs, use a distinct variable for single MSDUs + * within the list. + */ + while (msdu) { + qdf_nbuf_t next; + struct ol_tx_desc_t *tx_desc; + int segments = 1; + + msdu_info.htt.info.ext_tid = qdf_nbuf_get_tid(msdu); + msdu_info.peer = NULL; + + if (qdf_unlikely(ol_tx_prepare_tso(vdev, msdu, &msdu_info))) { + qdf_print("ol_tx_prepare_tso failed\n"); + TXRX_STATS_MSDU_LIST_INCR(vdev->pdev, + tx.dropped.host_reject, msdu); + return msdu; + } + + segments = msdu_info.tso_info.num_segs; + + if (msdu_info.tso_info.is_tso) { + tso_msdu_stats_idx = + ol_tx_tso_get_stats_idx(vdev->pdev); + msdu_info.tso_info.msdu_stats_idx = tso_msdu_stats_idx; + ol_tx_tso_update_stats(vdev->pdev, + &(msdu_info.tso_info), + msdu, tso_msdu_stats_idx); + } + + /* + * The netbuf may get linked into a different list inside the + * ol_tx_send function, so store the next pointer before the + * tx_send call. + */ + next = qdf_nbuf_next(msdu); + /* init the current segment to the 1st segment in the list */ + while (segments) { + + if (msdu_info.tso_info.curr_seg) + QDF_NBUF_CB_PADDR(msdu) = + msdu_info.tso_info.curr_seg-> + seg.tso_frags[0].paddr; + + segments--; + + ol_tx_prepare_ll(tx_desc, vdev, msdu, &msdu_info); + + /** + * if this is a jumbo nbuf, then increment the number + * of nbuf users for each additional segment of the msdu. + * This will ensure that the skb is freed only after + * receiving tx completion for all segments of an nbuf + */ + if (segments) + qdf_nbuf_inc_users(msdu); + + TXRX_STATS_MSDU_INCR(vdev->pdev, tx.from_stack, msdu); + + /* + * If debug display is enabled, show the meta-data being + * downloaded to the target via the HTT tx descriptor. + */ + htt_tx_desc_display(tx_desc->htt_tx_desc); + + ol_tx_send(vdev->pdev, tx_desc, msdu, vdev->vdev_id); + + if (msdu_info.tso_info.curr_seg) { + msdu_info.tso_info.curr_seg = + msdu_info.tso_info.curr_seg->next; + } + + qdf_nbuf_reset_num_frags(msdu); + + if (msdu_info.tso_info.is_tso) { + TXRX_STATS_TSO_INC_SEG(vdev->pdev, + tso_msdu_stats_idx); + TXRX_STATS_TSO_INC_SEG_IDX(vdev->pdev, + tso_msdu_stats_idx); + } + } /* while segments */ + + msdu = next; + } /* while msdus */ + return NULL; /* all MSDUs were accepted */ +} +#else /* TSO */ + +qdf_nbuf_t ol_tx_ll(ol_txrx_vdev_handle vdev, qdf_nbuf_t msdu_list) +{ + qdf_nbuf_t msdu = msdu_list; + struct ol_txrx_msdu_info_t msdu_info; + + msdu_info.htt.info.l2_hdr_type = vdev->pdev->htt_pkt_type; + msdu_info.htt.action.tx_comp_req = 0; + msdu_info.tso_info.is_tso = 0; + /* + * The msdu_list variable could be used instead of the msdu var, + * but just to clarify which operations are done on a single MSDU + * vs. a list of MSDUs, use a distinct variable for single MSDUs + * within the list. + */ + while (msdu) { + qdf_nbuf_t next; + struct ol_tx_desc_t *tx_desc; + + msdu_info.htt.info.ext_tid = qdf_nbuf_get_tid(msdu); + msdu_info.peer = NULL; + ol_tx_prepare_ll(tx_desc, vdev, msdu, &msdu_info); + + TXRX_STATS_MSDU_INCR(vdev->pdev, tx.from_stack, msdu); + + /* + * If debug display is enabled, show the meta-data being + * downloaded to the target via the HTT tx descriptor. + */ + htt_tx_desc_display(tx_desc->htt_tx_desc); + /* + * The netbuf may get linked into a different list inside the + * ol_tx_send function, so store the next pointer before the + * tx_send call. + */ + next = qdf_nbuf_next(msdu); + ol_tx_send(vdev->pdev, tx_desc, msdu, vdev->vdev_id); + msdu = next; + } + return NULL; /* all MSDUs were accepted */ +} +#endif /* TSO */ + +#ifdef WLAN_FEATURE_FASTPATH +/** + * ol_tx_prepare_ll_fast() Alloc and prepare Tx descriptor + * + * Allocate and prepare Tx descriptor with msdu and fragment descritor + * inforamtion. + * + * @pdev: pointer to ol pdev handle + * @vdev: pointer to ol vdev handle + * @msdu: linked list of msdu packets + * @pkt_download_len: packet download length + * @ep_id: endpoint ID + * @msdu_info: Handle to msdu_info + * + * Return: Pointer to Tx descriptor + */ +static inline struct ol_tx_desc_t * +ol_tx_prepare_ll_fast(struct ol_txrx_pdev_t *pdev, + ol_txrx_vdev_handle vdev, qdf_nbuf_t msdu, + uint32_t pkt_download_len, uint32_t ep_id, + struct ol_txrx_msdu_info_t *msdu_info) +{ + struct ol_tx_desc_t *tx_desc = NULL; + uint32_t *htt_tx_desc; + void *htc_hdr_vaddr; + u_int32_t num_frags, i; + enum extension_header_type type; + + tx_desc = ol_tx_desc_alloc_wrapper(pdev, vdev, msdu_info); + if (qdf_unlikely(!tx_desc)) + return NULL; + + tx_desc->netbuf = msdu; + if (msdu_info->tso_info.is_tso) { + tx_desc->tso_desc = msdu_info->tso_info.curr_seg; + qdf_tso_seg_dbg_setowner(tx_desc->tso_desc, tx_desc); + qdf_tso_seg_dbg_record(tx_desc->tso_desc, + TSOSEG_LOC_TXPREPLLFAST); + tx_desc->tso_num_desc = msdu_info->tso_info.tso_num_seg_list; + tx_desc->pkt_type = OL_TX_FRM_TSO; + TXRX_STATS_MSDU_INCR(pdev, tx.tso.tso_pkts, msdu); + } else { + tx_desc->pkt_type = OL_TX_FRM_STD; + } + + htt_tx_desc = tx_desc->htt_tx_desc; + + /* Make sure frags num is set to 0 */ + /* + * Do this here rather than in hardstart, so + * that we can hopefully take only one cache-miss while + * accessing skb->cb. + */ + + /* HTT Header */ + /* TODO : Take care of multiple fragments */ + + type = ol_tx_get_ext_header_type(vdev, msdu); + + /* TODO: Precompute and store paddr in ol_tx_desc_t */ + /* Virtual address of the HTT/HTC header, added by driver */ + htc_hdr_vaddr = (char *)htt_tx_desc - HTC_HEADER_LEN; + if (qdf_unlikely(htt_tx_desc_init(pdev->htt_pdev, htt_tx_desc, + tx_desc->htt_tx_desc_paddr, tx_desc->id, msdu, + &msdu_info->htt, &msdu_info->tso_info, + NULL, type))) { + /* + * HTT Tx descriptor initialization failed. + * therefore, free the tx desc + */ + ol_tx_desc_free(pdev, tx_desc); + return NULL; + } + + num_frags = qdf_nbuf_get_num_frags(msdu); + /* num_frags are expected to be 2 max */ + num_frags = (num_frags > QDF_NBUF_CB_TX_MAX_EXTRA_FRAGS) + ? QDF_NBUF_CB_TX_MAX_EXTRA_FRAGS + : num_frags; +#if defined(HELIUMPLUS) + /* + * Use num_frags - 1, since 1 frag is used to store + * the HTT/HTC descriptor + * Refer to htt_tx_desc_init() + */ + htt_tx_desc_num_frags(pdev->htt_pdev, tx_desc->htt_frag_desc, + num_frags - 1); +#else /* ! defined(HELIUMPLUS) */ + htt_tx_desc_num_frags(pdev->htt_pdev, tx_desc->htt_tx_desc, + num_frags-1); +#endif /* defined(HELIUMPLUS) */ + if (msdu_info->tso_info.is_tso) { + htt_tx_desc_fill_tso_info(pdev->htt_pdev, + tx_desc->htt_frag_desc, &msdu_info->tso_info); + TXRX_STATS_TSO_SEG_UPDATE(pdev, + msdu_info->tso_info.msdu_stats_idx, + msdu_info->tso_info.curr_seg->seg); + } else { + for (i = 1; i < num_frags; i++) { + qdf_size_t frag_len; + qdf_dma_addr_t frag_paddr; + + frag_len = qdf_nbuf_get_frag_len(msdu, i); + frag_paddr = qdf_nbuf_get_frag_paddr(msdu, i); + if (type != EXT_HEADER_NOT_PRESENT) { + frag_paddr += + sizeof(struct htt_tx_msdu_desc_ext_t); + frag_len -= + sizeof(struct htt_tx_msdu_desc_ext_t); + } +#if defined(HELIUMPLUS) + htt_tx_desc_frag(pdev->htt_pdev, tx_desc->htt_frag_desc, + i - 1, frag_paddr, frag_len); +#if defined(HELIUMPLUS_DEBUG) + qdf_print("%s:%d: htt_fdesc=%p frag=%d frag_paddr=0x%0llx len=%zu", + __func__, __LINE__, tx_desc->htt_frag_desc, + i-1, frag_paddr, frag_len); + ol_txrx_dump_pkt(netbuf, frag_paddr, 64); +#endif /* HELIUMPLUS_DEBUG */ +#else /* ! defined(HELIUMPLUS) */ + htt_tx_desc_frag(pdev->htt_pdev, tx_desc->htt_tx_desc, + i - 1, frag_paddr, frag_len); +#endif /* defined(HELIUMPLUS) */ + } + } + + /* + * Do we want to turn on word_stream bit-map here ? For linux, non-TSO + * this is not required. We still have to mark the swap bit correctly, + * when posting to the ring + */ + /* Check to make sure, data download length is correct */ + + /* + * TODO : Can we remove this check and always download a fixed length ? + * */ + + + if (QDF_NBUF_CB_TX_EXTRA_FRAG_FLAGS_EXT_HEADER(msdu)) + pkt_download_len += sizeof(struct htt_tx_msdu_desc_ext_t); + + if (qdf_unlikely(qdf_nbuf_len(msdu) < pkt_download_len)) + pkt_download_len = qdf_nbuf_len(msdu); + + /* Fill the HTC header information */ + /* + * Passing 0 as the seq_no field, we can probably get away + * with it for the time being, since this is not checked in f/w + */ + /* TODO : Prefill this, look at multi-fragment case */ + HTC_TX_DESC_FILL(htc_hdr_vaddr, pkt_download_len, ep_id, 0); + + return tx_desc; +} +#if defined(FEATURE_TSO) +/** + * ol_tx_ll_fast() Update metadata information and send msdu to HIF/CE + * + * @vdev: handle to ol_txrx_vdev_t + * @msdu_list: msdu list to be sent out. + * + * Return: on success return NULL, pointer to nbuf when it fails to send. + */ +qdf_nbuf_t +ol_tx_ll_fast(ol_txrx_vdev_handle vdev, qdf_nbuf_t msdu_list) +{ + qdf_nbuf_t msdu = msdu_list; + struct ol_txrx_pdev_t *pdev = vdev->pdev; + uint32_t pkt_download_len = + ((struct htt_pdev_t *)(pdev->htt_pdev))->download_len; + uint32_t ep_id = HTT_EPID_GET(pdev->htt_pdev); + struct ol_txrx_msdu_info_t msdu_info; + uint32_t tso_msdu_stats_idx = 0; + + msdu_info.htt.info.l2_hdr_type = vdev->pdev->htt_pkt_type; + msdu_info.htt.action.tx_comp_req = 0; + /* + * The msdu_list variable could be used instead of the msdu var, + * but just to clarify which operations are done on a single MSDU + * vs. a list of MSDUs, use a distinct variable for single MSDUs + * within the list. + */ + while (msdu) { + qdf_nbuf_t next; + struct ol_tx_desc_t *tx_desc; + int segments = 1; + + msdu_info.htt.info.ext_tid = qdf_nbuf_get_tid(msdu); + msdu_info.peer = NULL; + + if (qdf_unlikely(ol_tx_prepare_tso(vdev, msdu, &msdu_info))) { + qdf_print("ol_tx_prepare_tso failed\n"); + TXRX_STATS_MSDU_LIST_INCR(vdev->pdev, + tx.dropped.host_reject, msdu); + return msdu; + } + + segments = msdu_info.tso_info.num_segs; + + if (msdu_info.tso_info.is_tso) { + tso_msdu_stats_idx = + ol_tx_tso_get_stats_idx(vdev->pdev); + msdu_info.tso_info.msdu_stats_idx = tso_msdu_stats_idx; + ol_tx_tso_update_stats(vdev->pdev, + &(msdu_info.tso_info), + msdu, tso_msdu_stats_idx); + } + + /* + * The netbuf may get linked into a different list + * inside the ce_send_fast function, so store the next + * pointer before the ce_send call. + */ + next = qdf_nbuf_next(msdu); + /* init the current segment to the 1st segment in the list */ + while (segments) { + + if (msdu_info.tso_info.curr_seg) + QDF_NBUF_CB_PADDR(msdu) = msdu_info.tso_info. + curr_seg->seg.tso_frags[0].paddr; + + segments--; + + msdu_info.htt.info.frame_type = pdev->htt_pkt_type; + msdu_info.htt.info.vdev_id = vdev->vdev_id; + msdu_info.htt.action.cksum_offload = + qdf_nbuf_get_tx_cksum(msdu); + switch (qdf_nbuf_get_exemption_type(msdu)) { + case QDF_NBUF_EXEMPT_NO_EXEMPTION: + case QDF_NBUF_EXEMPT_ON_KEY_MAPPING_KEY_UNAVAILABLE: + /* We want to encrypt this frame */ + msdu_info.htt.action.do_encrypt = 1; + break; + case QDF_NBUF_EXEMPT_ALWAYS: + /* We don't want to encrypt this frame */ + msdu_info.htt.action.do_encrypt = 0; + break; + default: + msdu_info.htt.action.do_encrypt = 1; + qdf_assert(0); + break; + } + + tx_desc = ol_tx_prepare_ll_fast(pdev, vdev, msdu, + pkt_download_len, ep_id, + &msdu_info); + + TXRX_STATS_MSDU_INCR(pdev, tx.from_stack, msdu); + + if (qdf_likely(tx_desc)) { + + /* + * if this is a jumbo nbuf, then increment the + * number of nbuf users for each additional + * segment of the msdu. This will ensure that + * the skb is freed only after receiving tx + * completion for all segments of an nbuf. + */ + if (segments) + qdf_nbuf_inc_users(msdu); + + DPTRACE(qdf_dp_trace_ptr(msdu, + QDF_DP_TRACE_TXRX_FAST_PACKET_PTR_RECORD, + qdf_nbuf_data_addr(msdu), + sizeof(qdf_nbuf_data(msdu)), + tx_desc->id, vdev->vdev_id)); + /* + * If debug display is enabled, show the meta + * data being downloaded to the target via the + * HTT tx descriptor. + */ + if (QDF_NBUF_CB_TX_EXTRA_FRAG_FLAGS_EXT_HEADER + (msdu)) + pkt_download_len += + sizeof(struct htt_tx_msdu_desc_ext_t); + + htt_tx_desc_display(tx_desc->htt_tx_desc); + if ((0 == ce_send_fast(pdev->ce_tx_hdl, msdu, + ep_id, pkt_download_len))) { + struct qdf_tso_info_t *tso_info = + &msdu_info.tso_info; + /* + * If TSO packet, free associated + * remaining TSO segment descriptors + */ + if (tx_desc->pkt_type == + OL_TX_FRM_TSO) { + tso_info->curr_seg = + tso_info->curr_seg->next; + ol_free_remaining_tso_segs(vdev, + &msdu_info, true); + } + + /* + * The packet could not be sent. + * Free the descriptor, return the + * packet to the caller. + */ + ol_tx_desc_frame_free_nonstd(pdev, + tx_desc, + htt_tx_status_download_fail); + return msdu; + } + if (msdu_info.tso_info.curr_seg) { + msdu_info.tso_info.curr_seg = + msdu_info.tso_info.curr_seg->next; + } + + if (msdu_info.tso_info.is_tso) { + qdf_nbuf_reset_num_frags(msdu); + TXRX_STATS_TSO_INC_SEG(vdev->pdev, + tso_msdu_stats_idx); + TXRX_STATS_TSO_INC_SEG_IDX(vdev->pdev, + tso_msdu_stats_idx); + } + } else { + /* + * If TSO packet, free associated + * remaining TSO segment descriptors + */ + if (qdf_nbuf_is_tso(msdu)) + ol_free_remaining_tso_segs(vdev, + &msdu_info, true); + + TXRX_STATS_MSDU_LIST_INCR( + pdev, tx.dropped.host_reject, msdu); + /* the list of unaccepted MSDUs */ + return msdu; + } + } /* while segments */ + + msdu = next; + } /* while msdus */ + return NULL; /* all MSDUs were accepted */ +} +#else +qdf_nbuf_t +ol_tx_ll_fast(ol_txrx_vdev_handle vdev, qdf_nbuf_t msdu_list) +{ + qdf_nbuf_t msdu = msdu_list; + struct ol_txrx_pdev_t *pdev = vdev->pdev; + uint32_t pkt_download_len = + ((struct htt_pdev_t *)(pdev->htt_pdev))->download_len; + uint32_t ep_id = HTT_EPID_GET(pdev->htt_pdev); + struct ol_txrx_msdu_info_t msdu_info; + + msdu_info.htt.info.l2_hdr_type = vdev->pdev->htt_pkt_type; + msdu_info.htt.action.tx_comp_req = 0; + msdu_info.tso_info.is_tso = 0; + /* + * The msdu_list variable could be used instead of the msdu var, + * but just to clarify which operations are done on a single MSDU + * vs. a list of MSDUs, use a distinct variable for single MSDUs + * within the list. + */ + while (msdu) { + qdf_nbuf_t next; + struct ol_tx_desc_t *tx_desc; + + msdu_info.htt.info.ext_tid = qdf_nbuf_get_tid(msdu); + msdu_info.peer = NULL; + + msdu_info.htt.info.frame_type = pdev->htt_pkt_type; + msdu_info.htt.info.vdev_id = vdev->vdev_id; + msdu_info.htt.action.cksum_offload = + qdf_nbuf_get_tx_cksum(msdu); + switch (qdf_nbuf_get_exemption_type(msdu)) { + case QDF_NBUF_EXEMPT_NO_EXEMPTION: + case QDF_NBUF_EXEMPT_ON_KEY_MAPPING_KEY_UNAVAILABLE: + /* We want to encrypt this frame */ + msdu_info.htt.action.do_encrypt = 1; + break; + case QDF_NBUF_EXEMPT_ALWAYS: + /* We don't want to encrypt this frame */ + msdu_info.htt.action.do_encrypt = 0; + break; + default: + msdu_info.htt.action.do_encrypt = 1; + qdf_assert(0); + break; + } + + tx_desc = ol_tx_prepare_ll_fast(pdev, vdev, msdu, + pkt_download_len, ep_id, + &msdu_info); + + TXRX_STATS_MSDU_INCR(pdev, tx.from_stack, msdu); + + if (qdf_likely(tx_desc)) { + DPTRACE(qdf_dp_trace_ptr(msdu, + QDF_DP_TRACE_TXRX_FAST_PACKET_PTR_RECORD, + qdf_nbuf_data_addr(msdu), + sizeof(qdf_nbuf_data(msdu)), tx_desc->id, + vdev->vdev_id)); + /* + * If debug display is enabled, show the meta-data being + * downloaded to the target via the HTT tx descriptor. + */ + if (QDF_NBUF_CB_TX_EXTRA_FRAG_FLAGS_EXT_HEADER(msdu)) + pkt_download_len += + sizeof(struct htt_tx_msdu_desc_ext_t); + + htt_tx_desc_display(tx_desc->htt_tx_desc); + /* + * The netbuf may get linked into a different list + * inside the ce_send_fast function, so store the next + * pointer before the ce_send call. + */ + next = qdf_nbuf_next(msdu); + if ((0 == ce_send_fast(pdev->ce_tx_hdl, msdu, + ep_id, pkt_download_len))) { + /* The packet could not be sent */ + /* Free the descriptor, return the packet to the + * caller */ + ol_tx_desc_free(pdev, tx_desc); + return msdu; + } + msdu = next; + } else { + TXRX_STATS_MSDU_LIST_INCR( + pdev, tx.dropped.host_reject, msdu); + return msdu; /* the list of unaccepted MSDUs */ + } + } + + return NULL; /* all MSDUs were accepted */ +} +#endif /* FEATURE_TSO */ +#endif /* WLAN_FEATURE_FASTPATH */ + +#ifdef WLAN_FEATURE_FASTPATH +/** + * ol_tx_ll_wrapper() wrapper to ol_tx_ll + * + */ +qdf_nbuf_t +ol_tx_ll_wrapper(ol_txrx_vdev_handle vdev, qdf_nbuf_t msdu_list) +{ + struct hif_opaque_softc *hif_device = + (struct hif_opaque_softc *)cds_get_context(QDF_MODULE_ID_HIF); + + if (qdf_likely(hif_device && hif_is_fastpath_mode_enabled(hif_device))) + msdu_list = ol_tx_ll_fast(vdev, msdu_list); + else + msdu_list = ol_tx_ll(vdev, msdu_list); + + return msdu_list; +} +#else +qdf_nbuf_t +ol_tx_ll_wrapper(ol_txrx_vdev_handle vdev, qdf_nbuf_t msdu_list) +{ + return ol_tx_ll(vdev, msdu_list); +} +#endif /* WLAN_FEATURE_FASTPATH */ + +#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL + +#define OL_TX_VDEV_PAUSE_QUEUE_SEND_MARGIN 400 +#define OL_TX_VDEV_PAUSE_QUEUE_SEND_PERIOD_MS 5 +static void ol_tx_vdev_ll_pause_queue_send_base(struct ol_txrx_vdev_t *vdev) +{ + int max_to_accept; + + qdf_spin_lock_bh(&vdev->ll_pause.mutex); + if (vdev->ll_pause.paused_reason) { + qdf_spin_unlock_bh(&vdev->ll_pause.mutex); + return; + } + + /* + * Send as much of the backlog as possible, but leave some margin + * of unallocated tx descriptors that can be used for new frames + * being transmitted by other vdevs. + * Ideally there would be a scheduler, which would not only leave + * some margin for new frames for other vdevs, but also would + * fairly apportion the tx descriptors between multiple vdevs that + * have backlogs in their pause queues. + * However, the fairness benefit of having a scheduler for frames + * from multiple vdev's pause queues is not sufficient to outweigh + * the extra complexity. + */ + max_to_accept = vdev->pdev->tx_desc.num_free - + OL_TX_VDEV_PAUSE_QUEUE_SEND_MARGIN; + while (max_to_accept > 0 && vdev->ll_pause.txq.depth) { + qdf_nbuf_t tx_msdu; + max_to_accept--; + vdev->ll_pause.txq.depth--; + tx_msdu = vdev->ll_pause.txq.head; + if (tx_msdu) { + vdev->ll_pause.txq.head = qdf_nbuf_next(tx_msdu); + if (NULL == vdev->ll_pause.txq.head) + vdev->ll_pause.txq.tail = NULL; + qdf_nbuf_set_next(tx_msdu, NULL); + QDF_NBUF_UPDATE_TX_PKT_COUNT(tx_msdu, + QDF_NBUF_TX_PKT_TXRX_DEQUEUE); + tx_msdu = ol_tx_ll_wrapper(vdev, tx_msdu); + /* + * It is unexpected that ol_tx_ll would reject the frame + * since we checked that there's room for it, though + * there's an infinitesimal possibility that between the + * time we checked the room available and now, a + * concurrent batch of tx frames used up all the room. + * For simplicity, just drop the frame. + */ + if (tx_msdu) { + qdf_nbuf_unmap(vdev->pdev->osdev, tx_msdu, + QDF_DMA_TO_DEVICE); + qdf_nbuf_tx_free(tx_msdu, QDF_NBUF_PKT_ERROR); + } + } + } + if (vdev->ll_pause.txq.depth) { + qdf_timer_stop(&vdev->ll_pause.timer); + qdf_timer_start(&vdev->ll_pause.timer, + OL_TX_VDEV_PAUSE_QUEUE_SEND_PERIOD_MS); + vdev->ll_pause.is_q_timer_on = true; + if (vdev->ll_pause.txq.depth >= vdev->ll_pause.max_q_depth) + vdev->ll_pause.q_overflow_cnt++; + } + + qdf_spin_unlock_bh(&vdev->ll_pause.mutex); +} + +static qdf_nbuf_t +ol_tx_vdev_pause_queue_append(struct ol_txrx_vdev_t *vdev, + qdf_nbuf_t msdu_list, uint8_t start_timer) +{ + qdf_spin_lock_bh(&vdev->ll_pause.mutex); + while (msdu_list && + vdev->ll_pause.txq.depth < vdev->ll_pause.max_q_depth) { + qdf_nbuf_t next = qdf_nbuf_next(msdu_list); + QDF_NBUF_UPDATE_TX_PKT_COUNT(msdu_list, + QDF_NBUF_TX_PKT_TXRX_ENQUEUE); + DPTRACE(qdf_dp_trace(msdu_list, + QDF_DP_TRACE_TXRX_QUEUE_PACKET_PTR_RECORD, + qdf_nbuf_data_addr(msdu_list), + sizeof(qdf_nbuf_data(msdu_list)), QDF_TX)); + + vdev->ll_pause.txq.depth++; + if (!vdev->ll_pause.txq.head) { + vdev->ll_pause.txq.head = msdu_list; + vdev->ll_pause.txq.tail = msdu_list; + } else { + qdf_nbuf_set_next(vdev->ll_pause.txq.tail, msdu_list); + } + vdev->ll_pause.txq.tail = msdu_list; + + msdu_list = next; + } + if (vdev->ll_pause.txq.tail) + qdf_nbuf_set_next(vdev->ll_pause.txq.tail, NULL); + + if (start_timer) { + qdf_timer_stop(&vdev->ll_pause.timer); + qdf_timer_start(&vdev->ll_pause.timer, + OL_TX_VDEV_PAUSE_QUEUE_SEND_PERIOD_MS); + vdev->ll_pause.is_q_timer_on = true; + } + qdf_spin_unlock_bh(&vdev->ll_pause.mutex); + + return msdu_list; +} + +/* + * Store up the tx frame in the vdev's tx queue if the vdev is paused. + * If there are too many frames in the tx queue, reject it. + */ +qdf_nbuf_t ol_tx_ll_queue(ol_txrx_vdev_handle vdev, qdf_nbuf_t msdu_list) +{ + uint16_t eth_type; + uint32_t paused_reason; + + if (msdu_list == NULL) + return NULL; + + paused_reason = vdev->ll_pause.paused_reason; + if (paused_reason) { + if (qdf_unlikely((paused_reason & + OL_TXQ_PAUSE_REASON_PEER_UNAUTHORIZED) == + paused_reason)) { + eth_type = (((struct ethernet_hdr_t *) + qdf_nbuf_data(msdu_list))-> + ethertype[0] << 8) | + (((struct ethernet_hdr_t *) + qdf_nbuf_data(msdu_list))->ethertype[1]); + if (ETHERTYPE_IS_EAPOL_WAPI(eth_type)) { + msdu_list = ol_tx_ll_wrapper(vdev, msdu_list); + return msdu_list; + } + } + msdu_list = ol_tx_vdev_pause_queue_append(vdev, msdu_list, 1); + } else { + if (vdev->ll_pause.txq.depth > 0 || + vdev->pdev->tx_throttle.current_throttle_level != + THROTTLE_LEVEL_0) { + /* not paused, but there is a backlog of frms + from a prior pause or throttle off phase */ + msdu_list = ol_tx_vdev_pause_queue_append( + vdev, msdu_list, 0); + /* if throttle is disabled or phase is "on", + send the frame */ + if (vdev->pdev->tx_throttle.current_throttle_level == + THROTTLE_LEVEL_0 || + vdev->pdev->tx_throttle.current_throttle_phase == + THROTTLE_PHASE_ON) { + /* send as many frames as possible + from the vdevs backlog */ + ol_tx_vdev_ll_pause_queue_send_base(vdev); + } + } else { + /* not paused, no throttle and no backlog - + send the new frames */ + msdu_list = ol_tx_ll_wrapper(vdev, msdu_list); + } + } + return msdu_list; +} + +/* + * Run through the transmit queues for all the vdevs and + * send the pending frames + */ +void ol_tx_pdev_ll_pause_queue_send_all(struct ol_txrx_pdev_t *pdev) +{ + int max_to_send; /* tracks how many frames have been sent */ + qdf_nbuf_t tx_msdu; + struct ol_txrx_vdev_t *vdev = NULL; + uint8_t more; + + if (NULL == pdev) + return; + + if (pdev->tx_throttle.current_throttle_phase == THROTTLE_PHASE_OFF) + return; + + /* ensure that we send no more than tx_threshold frames at once */ + max_to_send = pdev->tx_throttle.tx_threshold; + + /* round robin through the vdev queues for the given pdev */ + + /* Potential improvement: download several frames from the same vdev + at a time, since it is more likely that those frames could be + aggregated together, remember which vdev was serviced last, + so the next call this function can resume the round-robin + traversing where the current invocation left off */ + do { + more = 0; + TAILQ_FOREACH(vdev, &pdev->vdev_list, vdev_list_elem) { + + qdf_spin_lock_bh(&vdev->ll_pause.mutex); + if (vdev->ll_pause.txq.depth) { + if (vdev->ll_pause.paused_reason) { + qdf_spin_unlock_bh(&vdev->ll_pause. + mutex); + continue; + } + + tx_msdu = vdev->ll_pause.txq.head; + if (NULL == tx_msdu) { + qdf_spin_unlock_bh(&vdev->ll_pause. + mutex); + continue; + } + + max_to_send--; + vdev->ll_pause.txq.depth--; + + vdev->ll_pause.txq.head = + qdf_nbuf_next(tx_msdu); + + if (NULL == vdev->ll_pause.txq.head) + vdev->ll_pause.txq.tail = NULL; + + qdf_nbuf_set_next(tx_msdu, NULL); + tx_msdu = ol_tx_ll_wrapper(vdev, tx_msdu); + /* + * It is unexpected that ol_tx_ll would reject + * the frame, since we checked that there's + * room for it, though there's an infinitesimal + * possibility that between the time we checked + * the room available and now, a concurrent + * batch of tx frames used up all the room. + * For simplicity, just drop the frame. + */ + if (tx_msdu) { + qdf_nbuf_unmap(pdev->osdev, tx_msdu, + QDF_DMA_TO_DEVICE); + qdf_nbuf_tx_free(tx_msdu, + QDF_NBUF_PKT_ERROR); + } + } + /*check if there are more msdus to transmit */ + if (vdev->ll_pause.txq.depth) + more = 1; + qdf_spin_unlock_bh(&vdev->ll_pause.mutex); + } + } while (more && max_to_send); + + vdev = NULL; + TAILQ_FOREACH(vdev, &pdev->vdev_list, vdev_list_elem) { + qdf_spin_lock_bh(&vdev->ll_pause.mutex); + if (vdev->ll_pause.txq.depth) { + qdf_timer_stop(&pdev->tx_throttle.tx_timer); + qdf_timer_start( + &pdev->tx_throttle.tx_timer, + OL_TX_VDEV_PAUSE_QUEUE_SEND_PERIOD_MS); + qdf_spin_unlock_bh(&vdev->ll_pause.mutex); + return; + } + qdf_spin_unlock_bh(&vdev->ll_pause.mutex); + } +} + +void ol_tx_vdev_ll_pause_queue_send(void *context) +{ + struct ol_txrx_vdev_t *vdev = (struct ol_txrx_vdev_t *)context; + struct ol_txrx_pdev_t *pdev = vdev->pdev; + + if (pdev->tx_throttle.current_throttle_level != THROTTLE_LEVEL_0 && + pdev->tx_throttle.current_throttle_phase == THROTTLE_PHASE_OFF) + return; + ol_tx_vdev_ll_pause_queue_send_base(vdev); +} +#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */ + +static inline int ol_txrx_tx_is_raw(enum ol_tx_spec tx_spec) +{ + return + tx_spec & + (OL_TX_SPEC_RAW | OL_TX_SPEC_NO_AGGR | OL_TX_SPEC_NO_ENCRYPT); +} + +static inline uint8_t ol_txrx_tx_raw_subtype(enum ol_tx_spec tx_spec) +{ + uint8_t sub_type = 0x1; /* 802.11 MAC header present */ + + if (tx_spec & OL_TX_SPEC_NO_AGGR) + sub_type |= 0x1 << HTT_TX_MSDU_DESC_RAW_SUBTYPE_NO_AGGR_S; + if (tx_spec & OL_TX_SPEC_NO_ENCRYPT) + sub_type |= 0x1 << HTT_TX_MSDU_DESC_RAW_SUBTYPE_NO_ENCRYPT_S; + if (tx_spec & OL_TX_SPEC_NWIFI_NO_ENCRYPT) + sub_type |= 0x1 << HTT_TX_MSDU_DESC_RAW_SUBTYPE_NO_ENCRYPT_S; + return sub_type; +} + +qdf_nbuf_t +ol_tx_non_std_ll(ol_txrx_vdev_handle vdev, + enum ol_tx_spec tx_spec, + qdf_nbuf_t msdu_list) +{ + qdf_nbuf_t msdu = msdu_list; + htt_pdev_handle htt_pdev = vdev->pdev->htt_pdev; + struct ol_txrx_msdu_info_t msdu_info; + + msdu_info.htt.info.l2_hdr_type = vdev->pdev->htt_pkt_type; + msdu_info.htt.action.tx_comp_req = 0; + + /* + * The msdu_list variable could be used instead of the msdu var, + * but just to clarify which operations are done on a single MSDU + * vs. a list of MSDUs, use a distinct variable for single MSDUs + * within the list. + */ + while (msdu) { + qdf_nbuf_t next; + struct ol_tx_desc_t *tx_desc; + + msdu_info.htt.info.ext_tid = qdf_nbuf_get_tid(msdu); + msdu_info.peer = NULL; + msdu_info.tso_info.is_tso = 0; + + ol_tx_prepare_ll(tx_desc, vdev, msdu, &msdu_info); + + /* + * The netbuf may get linked into a different list inside the + * ol_tx_send function, so store the next pointer before the + * tx_send call. + */ + next = qdf_nbuf_next(msdu); + + if (tx_spec != OL_TX_SPEC_STD) { + if (tx_spec & OL_TX_SPEC_NO_FREE) { + tx_desc->pkt_type = OL_TX_FRM_NO_FREE; + } else if (tx_spec & OL_TX_SPEC_TSO) { + tx_desc->pkt_type = OL_TX_FRM_TSO; + } else if (tx_spec & OL_TX_SPEC_NWIFI_NO_ENCRYPT) { + uint8_t sub_type = + ol_txrx_tx_raw_subtype(tx_spec); + htt_tx_desc_type(htt_pdev, tx_desc->htt_tx_desc, + htt_pkt_type_native_wifi, + sub_type); + } else if (ol_txrx_tx_is_raw(tx_spec)) { + /* different types of raw frames */ + uint8_t sub_type = + ol_txrx_tx_raw_subtype(tx_spec); + htt_tx_desc_type(htt_pdev, tx_desc->htt_tx_desc, + htt_pkt_type_raw, sub_type); + } + } + /* + * If debug display is enabled, show the meta-data being + * downloaded to the target via the HTT tx descriptor. + */ + htt_tx_desc_display(tx_desc->htt_tx_desc); + ol_tx_send(vdev->pdev, tx_desc, msdu, vdev->vdev_id); + msdu = next; + } + return NULL; /* all MSDUs were accepted */ +} + +#ifdef QCA_SUPPORT_SW_TXRX_ENCAP +#define OL_TX_ENCAP_WRAPPER(pdev, vdev, tx_desc, msdu, tx_msdu_info) \ + do { \ + if (OL_TX_ENCAP(vdev, tx_desc, msdu, &tx_msdu_info) != A_OK) { \ + qdf_atomic_inc(&pdev->tx_queue.rsrc_cnt); \ + ol_tx_desc_frame_free_nonstd(pdev, tx_desc, 1); \ + if (tx_msdu_info.peer) { \ + /* remove the peer reference added above */ \ + OL_TXRX_PEER_UNREF_DELETE(tx_msdu_info.peer); \ + } \ + goto MSDU_LOOP_BOTTOM; \ + } \ + } while (0) +#else +#define OL_TX_ENCAP_WRAPPER(pdev, vdev, tx_desc, msdu, tx_msdu_info) /* no-op */ +#endif + +/* tx filtering is handled within the target FW */ +#define TX_FILTER_CHECK(tx_msdu_info) 0 /* don't filter */ + +/** + * parse_ocb_tx_header() - Function to check for OCB + * @msdu: Pointer to OS packet (qdf_nbuf_t) + * @tx_ctrl: TX control header on a packet and extract it if present + * + * Return: true if ocb parsing is successful + */ +#define OCB_HEADER_VERSION 1 +static bool parse_ocb_tx_header(qdf_nbuf_t msdu, + struct ocb_tx_ctrl_hdr_t *tx_ctrl, + bool *tx_ctrl_header_found) +{ + struct ether_header *eth_hdr_p; + struct ocb_tx_ctrl_hdr_t *tx_ctrl_hdr; + *tx_ctrl_header_found = false; + + /* Check if TX control header is present */ + eth_hdr_p = (struct ether_header *)qdf_nbuf_data(msdu); + if (eth_hdr_p->ether_type != QDF_SWAP_U16(ETHERTYPE_OCB_TX)) + /* TX control header is not present. Nothing to do.. */ + return true; + + /* Remove the ethernet header */ + qdf_nbuf_pull_head(msdu, sizeof(struct ether_header)); + + /* Parse the TX control header */ + tx_ctrl_hdr = (struct ocb_tx_ctrl_hdr_t *)qdf_nbuf_data(msdu); + + if (tx_ctrl_hdr->version == OCB_HEADER_VERSION) { + *tx_ctrl_header_found = true; + if (tx_ctrl) + qdf_mem_copy(tx_ctrl, tx_ctrl_hdr, + sizeof(*tx_ctrl_hdr)); + } else { + /* The TX control header is invalid. */ + return false; + } + + /* Remove the TX control header */ + qdf_nbuf_pull_head(msdu, tx_ctrl_hdr->length); + return true; +} + +/** + * merge_ocb_tx_ctrl_hdr() - merge the default TX ctrl parameters into + * @tx_ctrl: The destination TX control header. + * @def_ctrl_hdr: The default TX control header. + * + * For each parameter in tx_ctrl, if the parameter is unspecified, the + * equivalent parameter in def_ctrl_hdr will be copied to tx_ctrl. + */ +static void merge_ocb_tx_ctrl_hdr(struct ocb_tx_ctrl_hdr_t *tx_ctrl, + struct ocb_tx_ctrl_hdr_t *def_ctrl_hdr) +{ + if (!tx_ctrl || !def_ctrl_hdr) + return; + + if (!tx_ctrl->channel_freq && def_ctrl_hdr->channel_freq) + tx_ctrl->channel_freq = def_ctrl_hdr->channel_freq; + if (!tx_ctrl->valid_pwr && def_ctrl_hdr->valid_pwr) { + tx_ctrl->pwr = def_ctrl_hdr->pwr; + tx_ctrl->valid_pwr = 1; + } + if (!tx_ctrl->valid_datarate && def_ctrl_hdr->valid_datarate) { + tx_ctrl->datarate = def_ctrl_hdr->datarate; + tx_ctrl->valid_datarate = 1; + } + if (!tx_ctrl->valid_retries && def_ctrl_hdr->valid_retries) { + tx_ctrl->retry_limit = def_ctrl_hdr->retry_limit; + tx_ctrl->valid_retries = 1; + } + if (!tx_ctrl->valid_chain_mask && def_ctrl_hdr->valid_chain_mask) { + tx_ctrl->chain_mask = def_ctrl_hdr->chain_mask; + tx_ctrl->valid_chain_mask = 1; + } + if (!tx_ctrl->valid_expire_tsf && def_ctrl_hdr->valid_expire_tsf) { + tx_ctrl->expire_tsf_hi = def_ctrl_hdr->expire_tsf_hi; + tx_ctrl->expire_tsf_lo = def_ctrl_hdr->expire_tsf_lo; + tx_ctrl->valid_expire_tsf = 1; + } + if (!tx_ctrl->valid_tid && def_ctrl_hdr->valid_tid) { + tx_ctrl->ext_tid = def_ctrl_hdr->ext_tid; + tx_ctrl->valid_tid = 1; + } +} + + + +#if defined(CONFIG_HL_SUPPORT) && defined(CONFIG_TX_DESC_HI_PRIO_RESERVE) + +/** + * ol_tx_hl_desc_alloc() - Allocate and initialize a tx descriptor + * for a HL system. + * @pdev: the data physical device sending the data + * @vdev: the virtual device sending the data + * @msdu: the tx frame + * @msdu_info: the tx meta data + * + * Return: the tx decriptor + */ +static inline +struct ol_tx_desc_t *ol_tx_hl_desc_alloc(struct ol_txrx_pdev_t *pdev, + struct ol_txrx_vdev_t *vdev, + qdf_nbuf_t msdu, + struct ol_txrx_msdu_info_t *msdu_info) +{ + struct ol_tx_desc_t *tx_desc = NULL; + + if (qdf_atomic_read(&pdev->tx_queue.rsrc_cnt) > + TXRX_HL_TX_DESC_HI_PRIO_RESERVED) { + tx_desc = ol_tx_desc_hl(pdev, vdev, msdu, msdu_info); + } else if (qdf_nbuf_is_ipv4_pkt(msdu) == true) { + if ((QDF_NBUF_CB_GET_PACKET_TYPE(msdu) == + QDF_NBUF_CB_PACKET_TYPE_DHCP) || + (QDF_NBUF_CB_GET_PACKET_TYPE(msdu) == + QDF_NBUF_CB_PACKET_TYPE_EAPOL)) { + tx_desc = ol_tx_desc_hl(pdev, vdev, msdu, msdu_info); + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "Provided tx descriptor from reserve pool for DHCP/EAPOL\n"); + } + } + return tx_desc; +} +#else + +static inline +struct ol_tx_desc_t *ol_tx_hl_desc_alloc(struct ol_txrx_pdev_t *pdev, + struct ol_txrx_vdev_t *vdev, + qdf_nbuf_t msdu, + struct ol_txrx_msdu_info_t *msdu_info) +{ + struct ol_tx_desc_t *tx_desc = NULL; + tx_desc = ol_tx_desc_hl(pdev, vdev, msdu, msdu_info); + return tx_desc; +} +#endif + +#if defined(CONFIG_HL_SUPPORT) + +/** + * ol_txrx_mgmt_tx_desc_alloc() - Allocate and initialize a tx descriptor + * for management frame + * @pdev: the data physical device sending the data + * @vdev: the virtual device sending the data + * @tx_mgmt_frm: the tx managment frame + * @tx_msdu_info: the tx meta data + * + * Return: the tx decriptor + */ +static inline +struct ol_tx_desc_t * +ol_txrx_mgmt_tx_desc_alloc( + struct ol_txrx_pdev_t *pdev, + struct ol_txrx_vdev_t *vdev, + qdf_nbuf_t tx_mgmt_frm, + struct ol_txrx_msdu_info_t *tx_msdu_info) +{ + struct ol_tx_desc_t *tx_desc; + tx_msdu_info->htt.action.tx_comp_req = 1; + tx_desc = ol_tx_desc_hl(pdev, vdev, tx_mgmt_frm, tx_msdu_info); + return tx_desc; +} + +/** + * ol_txrx_mgmt_send_frame() - send a management frame + * @vdev: virtual device sending the frame + * @tx_desc: tx desc + * @tx_mgmt_frm: management frame to send + * @tx_msdu_info: the tx meta data + * @chanfreq: download change frequency + * + * Return: + * 0 -> the frame is accepted for transmission, -OR- + * 1 -> the frame was not accepted + */ +static inline +int ol_txrx_mgmt_send_frame( + struct ol_txrx_vdev_t *vdev, + struct ol_tx_desc_t *tx_desc, + qdf_nbuf_t tx_mgmt_frm, + struct ol_txrx_msdu_info_t *tx_msdu_info, + uint16_t chanfreq) +{ + struct ol_txrx_pdev_t *pdev = vdev->pdev; + struct ol_tx_frms_queue_t *txq; + /* + * 1. Look up the peer and queue the frame in the peer's mgmt queue. + * 2. Invoke the download scheduler. + */ + txq = ol_tx_classify_mgmt(vdev, tx_desc, tx_mgmt_frm, tx_msdu_info); + if (!txq) { + /*TXRX_STATS_MSDU_LIST_INCR(vdev->pdev, tx.dropped.no_txq, + msdu);*/ + qdf_atomic_inc(&pdev->tx_queue.rsrc_cnt); + ol_tx_desc_frame_free_nonstd(vdev->pdev, tx_desc, + 1 /* error */); + if (tx_msdu_info->peer) { + /* remove the peer reference added above */ + OL_TXRX_PEER_UNREF_DELETE(tx_msdu_info->peer); + } + return 1; /* can't accept the tx mgmt frame */ + } + /* Initialize the HTT tx desc l2 header offset field. + * Even though tx encap does not apply to mgmt frames, + * htt_tx_desc_mpdu_header still needs to be called, + * to specifiy that there was no L2 header added by tx encap, + * so the frame's length does not need to be adjusted to account for + * an added L2 header. + */ + htt_tx_desc_mpdu_header(tx_desc->htt_tx_desc, 0); + if (qdf_unlikely(htt_tx_desc_init( + pdev->htt_pdev, tx_desc->htt_tx_desc, + tx_desc->htt_tx_desc_paddr, + ol_tx_desc_id(pdev, tx_desc), + tx_mgmt_frm, + &tx_msdu_info->htt, &tx_msdu_info->tso_info, NULL, 0))) + return 1; + htt_tx_desc_display(tx_desc->htt_tx_desc); + htt_tx_desc_set_chanfreq(tx_desc->htt_tx_desc, chanfreq); + + ol_tx_enqueue(vdev->pdev, txq, tx_desc, tx_msdu_info); + if (tx_msdu_info->peer) { + /* remove the peer reference added above */ + OL_TXRX_PEER_UNREF_DELETE(tx_msdu_info->peer); + } + ol_tx_sched(vdev->pdev); + + return 0; +} + +#else + +static inline +struct ol_tx_desc_t * +ol_txrx_mgmt_tx_desc_alloc( + struct ol_txrx_pdev_t *pdev, + struct ol_txrx_vdev_t *vdev, + qdf_nbuf_t tx_mgmt_frm, + struct ol_txrx_msdu_info_t *tx_msdu_info) +{ + struct ol_tx_desc_t *tx_desc; + /* For LL tx_comp_req is not used so initialized to 0 */ + tx_msdu_info->htt.action.tx_comp_req = 0; + tx_desc = ol_tx_desc_ll(pdev, vdev, tx_mgmt_frm, tx_msdu_info); + /* FIX THIS - + * The FW currently has trouble using the host's fragments table + * for management frames. Until this is fixed, rather than + * specifying the fragment table to the FW, specify just the + * address of the initial fragment. + */ +#if defined(HELIUMPLUS) + /* ol_txrx_dump_frag_desc("ol_txrx_mgmt_send(): after ol_tx_desc_ll", + tx_desc); */ +#endif /* defined(HELIUMPLUS) */ + if (tx_desc) { + /* + * Following the call to ol_tx_desc_ll, frag 0 is the + * HTT tx HW descriptor, and the frame payload is in + * frag 1. + */ + htt_tx_desc_frags_table_set( + pdev->htt_pdev, + tx_desc->htt_tx_desc, + qdf_nbuf_get_frag_paddr(tx_mgmt_frm, 1), + 0, 0); +#if defined(HELIUMPLUS) && defined(HELIUMPLUS_DEBUG) + ol_txrx_dump_frag_desc( + "after htt_tx_desc_frags_table_set", + tx_desc); +#endif /* defined(HELIUMPLUS) */ + } + + return tx_desc; +} + +static inline +int ol_txrx_mgmt_send_frame( + struct ol_txrx_vdev_t *vdev, + struct ol_tx_desc_t *tx_desc, + qdf_nbuf_t tx_mgmt_frm, + struct ol_txrx_msdu_info_t *tx_msdu_info, + uint16_t chanfreq) +{ + struct ol_txrx_pdev_t *pdev = vdev->pdev; + htt_tx_desc_set_chanfreq(tx_desc->htt_tx_desc, chanfreq); + QDF_NBUF_CB_TX_PACKET_TRACK(tx_desc->netbuf) = + QDF_NBUF_TX_PKT_MGMT_TRACK; + ol_tx_send_nonstd(pdev, tx_desc, tx_mgmt_frm, + htt_pkt_type_mgmt); + + return 0; +} +#endif + +/** + * ol_tx_hl_base() - send tx frames for a HL system. + * @vdev: the virtual device sending the data + * @tx_spec: indicate what non-standard transmission actions to apply + * @msdu_list: the tx frames to send + * @tx_comp_req: tx completion req + * + * Return: NULL if all MSDUs are accepted + */ +static inline qdf_nbuf_t +ol_tx_hl_base( + ol_txrx_vdev_handle vdev, + enum ol_tx_spec tx_spec, + qdf_nbuf_t msdu_list, + int tx_comp_req) +{ + struct ol_txrx_pdev_t *pdev = vdev->pdev; + qdf_nbuf_t msdu = msdu_list; + struct ol_txrx_msdu_info_t tx_msdu_info; + struct ocb_tx_ctrl_hdr_t tx_ctrl; + + htt_pdev_handle htt_pdev = pdev->htt_pdev; + tx_msdu_info.peer = NULL; + tx_msdu_info.tso_info.is_tso = 0; + + /* + * The msdu_list variable could be used instead of the msdu var, + * but just to clarify which operations are done on a single MSDU + * vs. a list of MSDUs, use a distinct variable for single MSDUs + * within the list. + */ + while (msdu) { + qdf_nbuf_t next; + struct ol_tx_frms_queue_t *txq; + struct ol_tx_desc_t *tx_desc = NULL; + + qdf_mem_zero(&tx_ctrl, sizeof(tx_ctrl)); + + /* + * The netbuf will get stored into a (peer-TID) tx queue list + * inside the ol_tx_classify_store function or else dropped, + * so store the next pointer immediately. + */ + next = qdf_nbuf_next(msdu); + + tx_desc = ol_tx_hl_desc_alloc(pdev, vdev, msdu, &tx_msdu_info); + + if (!tx_desc) { + /* + * If we're out of tx descs, there's no need to try + * to allocate tx descs for the remaining MSDUs. + */ + TXRX_STATS_MSDU_LIST_INCR(pdev, tx.dropped.host_reject, + msdu); + return msdu; /* the list of unaccepted MSDUs */ + } + + /* OL_TXRX_PROT_AN_LOG(pdev->prot_an_tx_sent, msdu);*/ + + if (tx_spec != OL_TX_SPEC_STD) { +#if defined(FEATURE_WLAN_TDLS) + if (tx_spec & OL_TX_SPEC_NO_FREE) { + tx_desc->pkt_type = OL_TX_FRM_NO_FREE; + } else if (tx_spec & OL_TX_SPEC_TSO) { +#else + if (tx_spec & OL_TX_SPEC_TSO) { +#endif + tx_desc->pkt_type = OL_TX_FRM_TSO; + } + if (ol_txrx_tx_is_raw(tx_spec)) { + /* CHECK THIS: does this need + * to happen after htt_tx_desc_init? + */ + /* different types of raw frames */ + u_int8_t sub_type = + ol_txrx_tx_raw_subtype( + tx_spec); + htt_tx_desc_type(htt_pdev, + tx_desc->htt_tx_desc, + htt_pkt_type_raw, + sub_type); + } + } + + tx_msdu_info.htt.info.ext_tid = qdf_nbuf_get_tid(msdu); + tx_msdu_info.htt.info.vdev_id = vdev->vdev_id; + tx_msdu_info.htt.info.frame_type = htt_frm_type_data; + tx_msdu_info.htt.info.l2_hdr_type = pdev->htt_pkt_type; + tx_msdu_info.htt.action.tx_comp_req = tx_comp_req; + + /* If the vdev is in OCB mode, + * parse the tx control header. + */ + if (vdev->opmode == wlan_op_mode_ocb) { + bool tx_ctrl_header_found = false; + + if (!parse_ocb_tx_header(msdu, &tx_ctrl, + &tx_ctrl_header_found)) { + /* There was an error parsing + * the header.Skip this packet. + */ + goto MSDU_LOOP_BOTTOM; + } + /* If the TX control header was not found, + just use the defaults */ + if (!tx_ctrl_header_found && vdev->ocb_def_tx_param) + qdf_mem_copy(&tx_ctrl, vdev->ocb_def_tx_param, + sizeof(tx_ctrl)); + /* If the TX control header was found, merge the + defaults into it */ + else if (tx_ctrl_header_found && vdev->ocb_def_tx_param) + merge_ocb_tx_ctrl_hdr(&tx_ctrl, + vdev->ocb_def_tx_param); + + } + + txq = ol_tx_classify(vdev, tx_desc, msdu, + &tx_msdu_info); + + if ((!txq) || TX_FILTER_CHECK(&tx_msdu_info)) { + /* drop this frame, + * but try sending subsequent frames + */ + /*TXRX_STATS_MSDU_LIST_INCR(pdev, + tx.dropped.no_txq, + msdu);*/ + qdf_atomic_inc(&pdev->tx_queue.rsrc_cnt); + ol_tx_desc_frame_free_nonstd(pdev, tx_desc, 1); + if (tx_msdu_info.peer) { + /* remove the peer reference + * added above */ + OL_TXRX_PEER_UNREF_DELETE( + tx_msdu_info.peer); + } + goto MSDU_LOOP_BOTTOM; + } + + if (tx_msdu_info.peer) { + /*If the state is not associated then drop all + *the data packets received for that peer*/ + if (tx_msdu_info.peer->state == + OL_TXRX_PEER_STATE_DISC) { + qdf_atomic_inc( + &pdev->tx_queue.rsrc_cnt); + ol_tx_desc_frame_free_nonstd(pdev, + tx_desc, + 1); + OL_TXRX_PEER_UNREF_DELETE( + tx_msdu_info.peer); + msdu = next; + continue; + } else if (tx_msdu_info.peer->state != + OL_TXRX_PEER_STATE_AUTH) { + if (tx_msdu_info.htt.info.ethertype != + ETHERTYPE_PAE && + tx_msdu_info.htt.info.ethertype + != ETHERTYPE_WAI) { + qdf_atomic_inc( + &pdev->tx_queue. + rsrc_cnt); + ol_tx_desc_frame_free_nonstd( + pdev, + tx_desc, 1); + OL_TXRX_PEER_UNREF_DELETE( + tx_msdu_info.peer); + msdu = next; + continue; + } + } + } + /* + * Initialize the HTT tx desc l2 header offset field. + * htt_tx_desc_mpdu_header needs to be called to + * make sure, the l2 header size is initialized + * correctly to handle cases where TX ENCAP is disabled + * or Tx Encap fails to perform Encap + */ + htt_tx_desc_mpdu_header(tx_desc->htt_tx_desc, 0); + + /* + * Note: when the driver is built without support for + * SW tx encap,the following macro is a no-op. + * When the driver is built with support for SW tx + * encap, it performs encap, and if an error is + * encountered, jumps to the MSDU_LOOP_BOTTOM label. + */ + OL_TX_ENCAP_WRAPPER(pdev, vdev, tx_desc, msdu, + tx_msdu_info); + + /* initialize the HW tx descriptor */ + htt_tx_desc_init( + pdev->htt_pdev, tx_desc->htt_tx_desc, + tx_desc->htt_tx_desc_paddr, + ol_tx_desc_id(pdev, tx_desc), + msdu, + &tx_msdu_info.htt, + &tx_msdu_info.tso_info, + &tx_ctrl, + vdev->opmode == wlan_op_mode_ocb); + /* + * If debug display is enabled, show the meta-data + * being downloaded to the target via the + * HTT tx descriptor. + */ + htt_tx_desc_display(tx_desc->htt_tx_desc); + + ol_tx_enqueue(pdev, txq, tx_desc, &tx_msdu_info); + if (tx_msdu_info.peer) { + OL_TX_PEER_STATS_UPDATE(tx_msdu_info.peer, + msdu); + /* remove the peer reference added above */ + OL_TXRX_PEER_UNREF_DELETE(tx_msdu_info.peer); + } +MSDU_LOOP_BOTTOM: + msdu = next; + } + ol_tx_sched(pdev); + return NULL; /* all MSDUs were accepted */ +} + +qdf_nbuf_t +ol_tx_hl(ol_txrx_vdev_handle vdev, qdf_nbuf_t msdu_list) +{ + struct ol_txrx_pdev_t *pdev = vdev->pdev; + int tx_comp_req = pdev->cfg.default_tx_comp_req; + return ol_tx_hl_base(vdev, OL_TX_SPEC_STD, msdu_list, tx_comp_req); +} + +qdf_nbuf_t +ol_tx_non_std_hl(ol_txrx_vdev_handle vdev, + enum ol_tx_spec tx_spec, + qdf_nbuf_t msdu_list) +{ + struct ol_txrx_pdev_t *pdev = vdev->pdev; + int tx_comp_req = pdev->cfg.default_tx_comp_req; + + if (!tx_comp_req) { + if ((tx_spec == OL_TX_SPEC_NO_FREE) && + (pdev->tx_data_callback.func)) + tx_comp_req = 1; + } + return ol_tx_hl_base(vdev, tx_spec, msdu_list, tx_comp_req); +} + +/** + * ol_tx_non_std - Allow the control-path SW to send data frames + * + * @data_vdev - which vdev should transmit the tx data frames + * @tx_spec - what non-standard handling to apply to the tx data frames + * @msdu_list - NULL-terminated list of tx MSDUs + * + * Generally, all tx data frames come from the OS shim into the txrx layer. + * However, there are rare cases such as TDLS messaging where the UMAC + * control-path SW creates tx data frames. + * This UMAC SW can call this function to provide the tx data frames to + * the txrx layer. + * The UMAC SW can request a callback for these data frames after their + * transmission completes, by using the ol_txrx_data_tx_cb_set function + * to register a tx completion callback, and by specifying + * ol_tx_spec_no_free as the tx_spec arg when giving the frames to + * ol_tx_non_std. + * The MSDUs need to have the appropriate L2 header type (802.3 vs. 802.11), + * as specified by ol_cfg_frame_type(). + * + * Return: null - success, skb - failure + */ +qdf_nbuf_t +ol_tx_non_std(ol_txrx_vdev_handle vdev, + enum ol_tx_spec tx_spec, qdf_nbuf_t msdu_list) +{ + if (vdev->pdev->cfg.is_high_latency) + return ol_tx_non_std_hl(vdev, tx_spec, msdu_list); + else + return ol_tx_non_std_ll(vdev, tx_spec, msdu_list); +} + +void +ol_txrx_data_tx_cb_set(ol_txrx_vdev_handle vdev, + ol_txrx_data_tx_cb callback, void *ctxt) +{ + struct ol_txrx_pdev_t *pdev = vdev->pdev; + pdev->tx_data_callback.func = callback; + pdev->tx_data_callback.ctxt = ctxt; +} + +/** + * ol_txrx_mgmt_tx_cb_set() - Store a callback for delivery + * notifications for management frames. + * + * @pdev - the data physical device object + * @type - the type of mgmt frame the callback is used for + * @download_cb - the callback for notification of delivery to the target + * @ota_ack_cb - the callback for notification of delivery to the peer + * @ctxt - context to use with the callback + * + * When the txrx SW receives notifications from the target that a tx frame + * has been delivered to its recipient, it will check if the tx frame + * is a management frame. If so, the txrx SW will check the management + * frame type specified when the frame was submitted for transmission. + * If there is a callback function registered for the type of managment + * frame in question, the txrx code will invoke the callback to inform + * the management + control SW that the mgmt frame was delivered. + * This function is used by the control SW to store a callback pointer + * for a given type of management frame. + */ +void +ol_txrx_mgmt_tx_cb_set(ol_txrx_pdev_handle pdev, + uint8_t type, + ol_txrx_mgmt_tx_cb download_cb, + ol_txrx_mgmt_tx_cb ota_ack_cb, void *ctxt) +{ + TXRX_ASSERT1(type < OL_TXRX_MGMT_NUM_TYPES); + pdev->tx_mgmt.callbacks[type].download_cb = download_cb; + pdev->tx_mgmt.callbacks[type].ota_ack_cb = ota_ack_cb; + pdev->tx_mgmt.callbacks[type].ctxt = ctxt; +} + +#if defined(HELIUMPLUS) +void ol_txrx_dump_frag_desc(char *msg, struct ol_tx_desc_t *tx_desc) +{ + uint32_t *frag_ptr_i_p; + int i; + + qdf_print("OL TX Descriptor 0x%p msdu_id %d\n", + tx_desc, tx_desc->id); + qdf_print("HTT TX Descriptor vaddr: 0x%p paddr: %pad", + tx_desc->htt_tx_desc, &tx_desc->htt_tx_desc_paddr); + qdf_print("%s %d: Fragment Descriptor 0x%p (paddr=%pad)", + __func__, __LINE__, tx_desc->htt_frag_desc, + &tx_desc->htt_frag_desc_paddr); + + /* it looks from htt_tx_desc_frag() that tx_desc->htt_frag_desc + is already de-referrable (=> in virtual address space) */ + frag_ptr_i_p = tx_desc->htt_frag_desc; + + /* Dump 6 words of TSO flags */ + print_hex_dump(KERN_DEBUG, "MLE Desc:TSO Flags: ", + DUMP_PREFIX_NONE, 8, 4, + frag_ptr_i_p, 24, true); + + frag_ptr_i_p += 6; /* Skip 6 words of TSO flags */ + + i = 0; + while (*frag_ptr_i_p) { + print_hex_dump(KERN_DEBUG, "MLE Desc:Frag Ptr: ", + DUMP_PREFIX_NONE, 8, 4, + frag_ptr_i_p, 8, true); + i++; + if (i > 5) /* max 6 times: frag_ptr0 to frag_ptr5 */ + break; + else /* jump to next pointer - skip length */ + frag_ptr_i_p += 2; + } + return; +} +#endif /* HELIUMPLUS */ + +/** + * ol_txrx_mgmt_send_ext() - Transmit a management frame + * + * @vdev - virtual device transmitting the frame + * @tx_mgmt_frm - management frame to transmit + * @type - the type of managment frame (determines what callback to use) + * @use_6mbps - specify whether management frame to transmit should + * use 6 Mbps rather than 1 Mbps min rate(for 5GHz band or P2P) + * @chanfreq - channel to transmit the frame on + * + * Send the specified management frame from the specified virtual device. + * The type is used for determining whether to invoke a callback to inform + * the sender that the tx mgmt frame was delivered, and if so, which + * callback to use. + * + * Return: 0 - the frame is accepted for transmission + * 1 - the frame was not accepted + */ +int +ol_txrx_mgmt_send_ext(ol_txrx_vdev_handle vdev, + qdf_nbuf_t tx_mgmt_frm, + uint8_t type, uint8_t use_6mbps, uint16_t chanfreq) +{ + struct ol_txrx_pdev_t *pdev = vdev->pdev; + struct ol_tx_desc_t *tx_desc; + struct ol_txrx_msdu_info_t tx_msdu_info; + int result = 0; + tx_msdu_info.tso_info.is_tso = 0; + + tx_msdu_info.htt.action.use_6mbps = use_6mbps; + tx_msdu_info.htt.info.ext_tid = HTT_TX_EXT_TID_MGMT; + tx_msdu_info.htt.info.vdev_id = vdev->vdev_id; + tx_msdu_info.htt.action.do_tx_complete = + pdev->tx_mgmt.callbacks[type].ota_ack_cb ? 1 : 0; + + /* + * FIX THIS: l2_hdr_type should only specify L2 header type + * The Peregrine/Rome HTT layer provides the FW with a "pkt type" + * that is a combination of L2 header type and 802.11 frame type. + * If the 802.11 frame type is "mgmt", then the HTT pkt type is "mgmt". + * But if the 802.11 frame type is "data", then the HTT pkt type is + * the L2 header type (more or less): 802.3 vs. Native WiFi + * (basic 802.11). + * (Or the header type can be "raw", which is any version of the 802.11 + * header, and also implies that some of the offloaded tx data + * processing steps may not apply.) + * For efficiency, the Peregrine/Rome HTT uses the msdu_info's + * l2_hdr_type field to program the HTT pkt type. Thus, this txrx SW + * needs to overload the l2_hdr_type to indicate whether the frame is + * data vs. mgmt, as well as 802.3 L2 header vs. 802.11 L2 header. + * To fix this, the msdu_info's l2_hdr_type should be left specifying + * just the L2 header type. For mgmt frames, there should be a + * separate function to patch the HTT pkt type to store a "mgmt" value + * rather than the L2 header type. Then the HTT pkt type can be + * programmed efficiently for data frames, and the msdu_info's + * l2_hdr_type field won't be confusingly overloaded to hold the 802.11 + * frame type rather than the L2 header type. + */ + /* + * FIX THIS: remove duplication of htt_frm_type_mgmt and + * htt_pkt_type_mgmt + * The htt module expects a "enum htt_pkt_type" value. + * The htt_dxe module expects a "enum htt_frm_type" value. + * This needs to be cleaned up, so both versions of htt use a + * consistent method of specifying the frame type. + */ +#ifdef QCA_SUPPORT_INTEGRATED_SOC + /* tx mgmt frames always come with a 802.11 header */ + tx_msdu_info.htt.info.l2_hdr_type = htt_pkt_type_native_wifi; + tx_msdu_info.htt.info.frame_type = htt_frm_type_mgmt; +#else + tx_msdu_info.htt.info.l2_hdr_type = htt_pkt_type_mgmt; + tx_msdu_info.htt.info.frame_type = htt_pkt_type_mgmt; +#endif + + tx_msdu_info.peer = NULL; + + tx_desc = ol_txrx_mgmt_tx_desc_alloc(pdev, vdev, tx_mgmt_frm, + &tx_msdu_info); + if (!tx_desc) + return -EINVAL; /* can't accept the tx mgmt frame */ + + TXRX_STATS_MSDU_INCR(pdev, tx.mgmt, tx_mgmt_frm); + TXRX_ASSERT1(type < OL_TXRX_MGMT_NUM_TYPES); + tx_desc->pkt_type = type + OL_TXRX_MGMT_TYPE_BASE; + + result = ol_txrx_mgmt_send_frame(vdev, tx_desc, tx_mgmt_frm, + &tx_msdu_info, chanfreq); + + return 0; /* accepted the tx mgmt frame */ +} + +qdf_nbuf_t ol_tx_reinject(struct ol_txrx_vdev_t *vdev, + qdf_nbuf_t msdu, uint16_t peer_id) +{ + struct ol_tx_desc_t *tx_desc; + struct ol_txrx_msdu_info_t msdu_info; + + msdu_info.htt.info.l2_hdr_type = vdev->pdev->htt_pkt_type; + msdu_info.htt.info.ext_tid = HTT_TX_EXT_TID_INVALID; + msdu_info.peer = NULL; + msdu_info.htt.action.tx_comp_req = 0; + msdu_info.tso_info.is_tso = 0; + + ol_tx_prepare_ll(tx_desc, vdev, msdu, &msdu_info); + HTT_TX_DESC_POSTPONED_SET(*((uint32_t *) (tx_desc->htt_tx_desc)), true); + + htt_tx_desc_set_peer_id(tx_desc->htt_tx_desc, peer_id); + + ol_tx_send(vdev->pdev, tx_desc, msdu, vdev->vdev_id); + + return NULL; +} + +#if defined(FEATURE_TSO) +/** + * ol_tso_seg_list_init() - function to initialise the tso seg freelist + * @pdev: the data physical device sending the data + * @num_seg: number of segments needs to be intialised + * + * Return: none + */ +void ol_tso_seg_list_init(struct ol_txrx_pdev_t *pdev, uint32_t num_seg) +{ + int i = 0; + struct qdf_tso_seg_elem_t *c_element; + + /* Host should not allocate any c_element. */ + if (num_seg <= 0) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "%s: ERROR: Pool size passed is 0", + __func__); + QDF_BUG(0); + pdev->tso_seg_pool.pool_size = i; + qdf_spinlock_create(&pdev->tso_seg_pool.tso_mutex); + return; + } + + c_element = qdf_mem_malloc(sizeof(struct qdf_tso_seg_elem_t)); + pdev->tso_seg_pool.freelist = c_element; + for (i = 0; i < (num_seg - 1); i++) { + if (qdf_unlikely(!c_element)) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "%s: ERROR: c_element NULL for seg %d", + __func__, i); + QDF_BUG(0); + pdev->tso_seg_pool.pool_size = i; + pdev->tso_seg_pool.num_free = i; + qdf_spinlock_create(&pdev->tso_seg_pool.tso_mutex); + return; + } + /* set the freelist bit and magic cookie*/ + c_element->on_freelist = 1; + c_element->cookie = TSO_SEG_MAGIC_COOKIE; +#ifdef TSOSEG_DEBUG + c_element->dbg.txdesc = NULL; + c_element->dbg.cur = -1; /* history empty */ + qdf_tso_seg_dbg_record(c_element, TSOSEG_LOC_INIT1); +#endif /* TSOSEG_DEBUG */ + c_element->next = + qdf_mem_malloc(sizeof(struct qdf_tso_seg_elem_t)); + c_element = c_element->next; + } + /* + * NULL check for the last c_element of the list or + * first c_element if num_seg is equal to 1. + */ + if (qdf_unlikely(!c_element)) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "%s: ERROR: c_element NULL for seg %d", + __func__, i); + QDF_BUG(0); + pdev->tso_seg_pool.pool_size = i; + pdev->tso_seg_pool.num_free = i; + qdf_spinlock_create(&pdev->tso_seg_pool.tso_mutex); + return; + } + c_element->on_freelist = 1; + c_element->cookie = TSO_SEG_MAGIC_COOKIE; +#ifdef TSOSEG_DEBUG + c_element->dbg.txdesc = NULL; + c_element->dbg.cur = -1; /* history empty */ + qdf_tso_seg_dbg_record(c_element, TSOSEG_LOC_INIT2); +#endif /* TSOSEG_DEBUG */ + c_element->next = NULL; + pdev->tso_seg_pool.pool_size = num_seg; + pdev->tso_seg_pool.num_free = num_seg; + qdf_spinlock_create(&pdev->tso_seg_pool.tso_mutex); +} + +/** + * ol_tso_seg_list_deinit() - function to de-initialise the tso seg freelist + * @pdev: the data physical device sending the data + * + * Return: none + */ +void ol_tso_seg_list_deinit(struct ol_txrx_pdev_t *pdev) +{ + int i; + struct qdf_tso_seg_elem_t *c_element; + struct qdf_tso_seg_elem_t *temp; + + /* pool size 0 implies that tso seg list is not initialised*/ + if (pdev->tso_seg_pool.freelist == NULL && + pdev->tso_seg_pool.pool_size == 0) + return; + + qdf_spin_lock_bh(&pdev->tso_seg_pool.tso_mutex); + c_element = pdev->tso_seg_pool.freelist; + i = pdev->tso_seg_pool.pool_size; + + pdev->tso_seg_pool.freelist = NULL; + pdev->tso_seg_pool.num_free = 0; + pdev->tso_seg_pool.pool_size = 0; + + qdf_spin_unlock_bh(&pdev->tso_seg_pool.tso_mutex); + qdf_spinlock_destroy(&pdev->tso_seg_pool.tso_mutex); + + while (i-- > 0 && c_element) { + temp = c_element->next; + if (c_element->on_freelist != 1) { + qdf_tso_seg_dbg_bug("this seg already freed (double?)"); + return; + } else if (c_element->cookie != TSO_SEG_MAGIC_COOKIE) { + qdf_print("this seg cookie is bad (memory corruption?)"); + QDF_BUG(0); + return; + } + /* free this seg, so reset the cookie value*/ + c_element->cookie = 0; + qdf_mem_free(c_element); + c_element = temp; + } +} + +/** + * ol_tso_num_seg_list_init() - function to initialise the freelist of elements + * use to count the num of tso segments in jumbo + * skb packet freelist + * @pdev: the data physical device sending the data + * @num_seg: number of elements needs to be intialised + * + * Return: none + */ +void ol_tso_num_seg_list_init(struct ol_txrx_pdev_t *pdev, uint32_t num_seg) +{ + int i = 0; + struct qdf_tso_num_seg_elem_t *c_element; + + /* Host should not allocate any c_element. */ + if (num_seg <= 0) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "%s: ERROR: Pool size passed is 0", + __func__); + QDF_BUG(0); + pdev->tso_num_seg_pool.num_seg_pool_size = i; + qdf_spinlock_create(&pdev->tso_num_seg_pool.tso_num_seg_mutex); + return; + } + + c_element = qdf_mem_malloc(sizeof(struct qdf_tso_num_seg_elem_t)); + pdev->tso_num_seg_pool.freelist = c_element; + for (i = 0; i < (num_seg - 1); i++) { + if (qdf_unlikely(!c_element)) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "%s: ERROR: c_element NULL for num of seg %d", + __func__, i); + QDF_BUG(0); + pdev->tso_num_seg_pool.num_seg_pool_size = i; + pdev->tso_num_seg_pool.num_free = i; + qdf_spinlock_create(&pdev->tso_num_seg_pool. + tso_num_seg_mutex); + return; + } + c_element->next = + qdf_mem_malloc(sizeof(struct qdf_tso_num_seg_elem_t)); + c_element = c_element->next; + } + /* + * NULL check for the last c_element of the list or + * first c_element if num_seg is equal to 1. + */ + if (qdf_unlikely(!c_element)) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "%s: ERROR: c_element NULL for num of seg %d", + __func__, i); + QDF_BUG(0); + pdev->tso_num_seg_pool.num_seg_pool_size = i; + pdev->tso_num_seg_pool.num_free = i; + qdf_spinlock_create(&pdev->tso_num_seg_pool.tso_num_seg_mutex); + return; + } + c_element->next = NULL; + pdev->tso_num_seg_pool.num_seg_pool_size = num_seg; + pdev->tso_num_seg_pool.num_free = num_seg; + qdf_spinlock_create(&pdev->tso_num_seg_pool.tso_num_seg_mutex); +} + +/** + * ol_tso_num_seg_list_deinit() - function to de-initialise the freelist of + * elements use to count the num of tso segment + * in a jumbo skb packet freelist + * @pdev: the data physical device sending the data + * + * Return: none + */ +void ol_tso_num_seg_list_deinit(struct ol_txrx_pdev_t *pdev) +{ + int i; + struct qdf_tso_num_seg_elem_t *c_element; + struct qdf_tso_num_seg_elem_t *temp; + + /* pool size 0 implies that tso num seg list is not initialised*/ + if (pdev->tso_num_seg_pool.freelist == NULL && + pdev->tso_num_seg_pool.num_seg_pool_size == 0) + return; + + qdf_spin_lock_bh(&pdev->tso_num_seg_pool.tso_num_seg_mutex); + c_element = pdev->tso_num_seg_pool.freelist; + i = pdev->tso_num_seg_pool.num_seg_pool_size; + + pdev->tso_num_seg_pool.freelist = NULL; + pdev->tso_num_seg_pool.num_free = 0; + pdev->tso_num_seg_pool.num_seg_pool_size = 0; + + qdf_spin_unlock_bh(&pdev->tso_num_seg_pool.tso_num_seg_mutex); + qdf_spinlock_destroy(&pdev->tso_num_seg_pool.tso_num_seg_mutex); + + while (i-- > 0 && c_element) { + temp = c_element->next; + qdf_mem_free(c_element); + c_element = temp; + } +} +#endif /* FEATURE_TSO */ diff --git a/drivers/staging/qcacld-3.0/core/dp/txrx/ol_tx.h b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_tx.h new file mode 100644 index 0000000000000000000000000000000000000000..9c60dae6a34610587a70de96d25df952add61ff5 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_tx.h @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2011-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * @file ol_tx.h + * @brief Internal definitions for the high-level tx module. + */ +#ifndef _OL_TX__H_ +#define _OL_TX__H_ + +#include /* qdf_nbuf_t */ +#include +#include /* ol_txrx_vdev_t, etc. */ +#include /* ol_tx_spec */ + +#include /* ol_tx_desc_t, ol_txrx_msdu_info_t */ + +qdf_nbuf_t ol_tx_ll(ol_txrx_vdev_handle vdev, qdf_nbuf_t msdu_list); +qdf_nbuf_t ol_tx_ll_wrapper(ol_txrx_vdev_handle vdev, qdf_nbuf_t msdu_list); +#ifdef WLAN_FEATURE_FASTPATH +qdf_nbuf_t ol_tx_ll_fast(ol_txrx_vdev_handle vdev, qdf_nbuf_t msdu_list); +#endif + +qdf_nbuf_t ol_tx_ll_queue(ol_txrx_vdev_handle vdev, qdf_nbuf_t msdu_list); + +#ifdef CONFIG_HL_SUPPORT +#define OL_TX_SEND ol_tx_hl +#else +#define OL_TX_SEND OL_TX_LL +#endif + +#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL +#define OL_TX_LL ol_tx_ll_queue +#else +#define OL_TX_LL ol_tx_ll_wrapper +#endif + +#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL +void ol_tx_vdev_ll_pause_queue_send(void *context); +void ol_tx_pdev_ll_pause_queue_send_all(struct ol_txrx_pdev_t *pdev); +#else +static inline void ol_tx_vdev_ll_pause_queue_send(void *context) +{ + return; +} +static inline +void ol_tx_pdev_ll_pause_queue_send_all(struct ol_txrx_pdev_t *pdev) +{ + return; +} +#endif + +/** + * ol_tx_non_std_hl() - send non std tx frame. + * @vdev: the virtual device sending the data + * @tx_spec: indicate what non-standard transmission actions to apply + * @msdu_list: the tx frames to send + * + * Return: NULL if all MSDUs are accepted + */ +qdf_nbuf_t +ol_tx_non_std_hl(ol_txrx_vdev_handle data_vdev, + enum ol_tx_spec tx_spec, qdf_nbuf_t msdu_list); + +/** + * ol_tx_hl() - transmit tx frames for a HL system. + * @vdev: the virtual device transmit the data + * @msdu_list: the tx frames to send + * + * Return: NULL if all MSDUs are accepted + */ +qdf_nbuf_t +ol_tx_hl(ol_txrx_vdev_handle vdev, qdf_nbuf_t msdu_list); + +qdf_nbuf_t +ol_tx_non_std_ll(ol_txrx_vdev_handle data_vdev, + enum ol_tx_spec tx_spec, qdf_nbuf_t msdu_list); + +qdf_nbuf_t +ol_tx_reinject(struct ol_txrx_vdev_t *vdev, qdf_nbuf_t msdu, uint16_t peer_id); + +void ol_txrx_mgmt_tx_complete(void *ctxt, qdf_nbuf_t netbuf, int err); + + +#if defined(FEATURE_TSO) +void ol_tso_seg_list_init(struct ol_txrx_pdev_t *pdev, uint32_t num_seg); +void ol_tso_seg_list_deinit(struct ol_txrx_pdev_t *pdev); +void ol_tso_num_seg_list_init(struct ol_txrx_pdev_t *pdev, uint32_t num_seg); +void ol_tso_num_seg_list_deinit(struct ol_txrx_pdev_t *pdev); +#else +static inline void ol_tso_seg_list_init(struct ol_txrx_pdev_t *pdev, + uint32_t num_seg) +{ + return; +} +static inline void ol_tso_seg_list_deinit(struct ol_txrx_pdev_t *pdev) +{ + return; +} +static inline void ol_tso_num_seg_list_init(struct ol_txrx_pdev_t *pdev, + uint32_t num_seg) +{ +} +static inline void ol_tso_num_seg_list_deinit(struct ol_txrx_pdev_t *pdev) +{ +} +#endif + +#if defined(HELIUMPLUS) +void ol_txrx_dump_frag_desc(char *msg, struct ol_tx_desc_t *tx_desc); +#else +static inline +void ol_txrx_dump_frag_desc(char *msg, struct ol_tx_desc_t *tx_desc) +{ +} +#endif + +#endif /* _OL_TX__H_ */ diff --git a/drivers/staging/qcacld-3.0/core/dp/txrx/ol_tx_classify.c b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_tx_classify.c new file mode 100644 index 0000000000000000000000000000000000000000..bc7a8536619a63e3f5aac32f2322ca824bc5958f --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_tx_classify.c @@ -0,0 +1,887 @@ +/* + * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#include /* qdf_nbuf_t, etc. */ +#include /* HTT_TX_EXT_TID_MGMT */ +#include /* htt_tx_desc_tid */ +#include /* ol_txrx_vdev_handle */ +#include /* ol_txrx_sync */ +#include +#include /* TXRX_ASSERT1 */ +#include /* pdev stats */ +#include /* ol_tx_desc */ +#include /* ol_tx_send */ +#include +#include +#include +#include +#include +#include +#include /* ETHERTYPE_VLAN, etc. */ +#include /* ieee80211_frame */ + +/* + * In theory, this tx classify code could be used on the host or in the target. + * Thus, this code uses generic OS primitives, that can be aliased to either + * the host's OS primitives or the target's OS primitives. + * For now, the following #defines set up these host-specific or + * target-specific aliases. + */ + +#if defined(CONFIG_HL_SUPPORT) + +#define OL_TX_CLASSIFY_EXTENSION(vdev, tx_desc, netbuf, msdu_info, txq) +#define OL_TX_CLASSIFY_MGMT_EXTENSION(vdev, tx_desc, netbuf, msdu_info, txq) + +#ifdef QCA_TX_HTT2_SUPPORT +static void +ol_tx_classify_htt2_frm( + struct ol_txrx_vdev_t *vdev, + qdf_nbuf_t tx_nbuf, + struct ol_txrx_msdu_info_t *tx_msdu_info) +{ + struct htt_msdu_info_t *htt = &tx_msdu_info->htt; + A_UINT8 candi_frm = 0; + + /* + * Offload the frame re-order to L3 protocol and ONLY support + * TCP protocol now. + */ + if ((htt->info.l2_hdr_type == htt_pkt_type_ethernet) && + (htt->info.frame_type == htt_frm_type_data) && + htt->info.is_unicast && + (htt->info.ethertype == ETHERTYPE_IPV4)) { + struct ipv4_hdr_t *ipHdr; + + ipHdr = (struct ipv4_hdr_t *)(qdf_nbuf_data(tx_nbuf) + + htt->info.l3_hdr_offset); + if (ipHdr->protocol == IP_PROTOCOL_TCP) + candi_frm = 1; + } + + qdf_nbuf_set_tx_parallel_dnload_frm(tx_nbuf, candi_frm); +} + +#define OL_TX_CLASSIFY_HTT2_EXTENSION(vdev, netbuf, msdu_info) \ + ol_tx_classify_htt2_frm(vdev, netbuf, msdu_info); +#else +#define OL_TX_CLASSIFY_HTT2_EXTENSION(vdev, netbuf, msdu_info) /* no-op */ +#endif /* QCA_TX_HTT2_SUPPORT */ +/* DHCP go with voice priority; WMM_AC_VO_TID1();*/ +#define TX_DHCP_TID 6 + +#if defined(QCA_BAD_PEER_TX_FLOW_CL) +static inline A_BOOL +ol_if_tx_bad_peer_txq_overflow( + struct ol_txrx_pdev_t *pdev, + struct ol_txrx_peer_t *peer, + struct ol_tx_frms_queue_t *txq) +{ + if (peer && pdev && txq && (peer->tx_limit_flag) && + (txq->frms >= pdev->tx_peer_bal.peer_bal_txq_limit)) + return true; + else + return false; +} +#else +static inline A_BOOL ol_if_tx_bad_peer_txq_overflow( + struct ol_txrx_pdev_t *pdev, + struct ol_txrx_peer_t *peer, + struct ol_tx_frms_queue_t *txq) +{ + return false; +} +#endif + +/* EAPOL go with voice priority: WMM_AC_TO_TID1(WMM_AC_VO);*/ +#define TX_EAPOL_TID 6 + +/* ARP go with voice priority: WMM_AC_TO_TID1(pdev->arp_ac_override)*/ +#define TX_ARP_TID 6 + +/* For non-IP case, use default TID */ +#define TX_DEFAULT_TID 0 + +/* + * Determine IP TOS priority + * IP Tos format : + * (Refer Pg 57 WMM-test-plan-v1.2) + * IP-TOS - 8bits + * : DSCP(6-bits) ECN(2-bits) + * : DSCP - P2 P1 P0 X X X + * where (P2 P1 P0) form 802.1D + */ +static inline A_UINT8 +ol_tx_tid_by_ipv4(A_UINT8 *pkt) +{ + A_UINT8 ipPri, tid; + struct ipv4_hdr_t *ipHdr = (struct ipv4_hdr_t *)pkt; + + ipPri = ipHdr->tos >> 5; + tid = ipPri & 0x7; + + return tid; +} + +static inline A_UINT8 +ol_tx_tid_by_ipv6(A_UINT8 *pkt) +{ + return (ipv6_traffic_class((struct ipv6_hdr_t *)pkt) >> 5) & 0x7; +} + +static inline void +ol_tx_set_ether_type( + A_UINT8 *datap, + struct ol_txrx_msdu_info_t *tx_msdu_info) +{ + A_UINT16 typeorlength; + A_UINT8 *ptr; + A_UINT8 *l3_data_ptr; + + if (tx_msdu_info->htt.info.l2_hdr_type == htt_pkt_type_raw) { + /* adjust hdr_ptr to RA */ + struct ieee80211_frame *wh = (struct ieee80211_frame *)datap; + + if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == + IEEE80211_FC0_TYPE_DATA) { + struct llc_snap_hdr_t *llc; + /* dot11 encapsulated frame */ + struct ieee80211_qosframe *whqos = + (struct ieee80211_qosframe *)datap; + if (whqos->i_fc[0] & IEEE80211_FC0_SUBTYPE_QOS) { + tx_msdu_info->htt.info.l3_hdr_offset = + sizeof(struct ieee80211_qosframe); + } else { + tx_msdu_info->htt.info.l3_hdr_offset = + sizeof(struct ieee80211_frame); + } + llc = (struct llc_snap_hdr_t *) + (datap + tx_msdu_info->htt.info.l3_hdr_offset); + tx_msdu_info->htt.info.ethertype = + (llc->ethertype[0] << 8) | llc->ethertype[1]; + /* + * l3_hdr_offset refers to the end of the 802.3 or + * 802.11 header, which may be a LLC/SNAP header rather + * than the IP header. + * Thus, don't increment l3_hdr_offset += sizeof(*llc); + * rather,leave it as is. + */ + } else { + /* + * This function should only be applied to data frames. + * For management frames, we already know to use + * HTT_TX_EXT_TID_MGMT. + */ + TXRX_ASSERT2(0); + } + } else if (tx_msdu_info->htt.info.l2_hdr_type == + htt_pkt_type_ethernet) { + ptr = (datap + ETHERNET_ADDR_LEN * 2); + typeorlength = (ptr[0] << 8) | ptr[1]; + /*ETHERNET_HDR_LEN;*/ + l3_data_ptr = datap + sizeof(struct ethernet_hdr_t); + + if (typeorlength == ETHERTYPE_VLAN) { + ptr = (datap + ETHERNET_ADDR_LEN * 2 + + ETHERTYPE_VLAN_LEN); + typeorlength = (ptr[0] << 8) | ptr[1]; + l3_data_ptr += ETHERTYPE_VLAN_LEN; + } + + if (!IS_ETHERTYPE(typeorlength)) { + /* 802.3 header*/ + struct llc_snap_hdr_t *llc_hdr = + (struct llc_snap_hdr_t *)l3_data_ptr; + typeorlength = (llc_hdr->ethertype[0] << 8) | + llc_hdr->ethertype[1]; + l3_data_ptr += sizeof(struct llc_snap_hdr_t); + } + + tx_msdu_info->htt.info.l3_hdr_offset = (A_UINT8)(l3_data_ptr - + datap); + tx_msdu_info->htt.info.ethertype = typeorlength; + } +} + +static inline A_UINT8 +ol_tx_tid_by_ether_type( + A_UINT8 *datap, + struct ol_txrx_msdu_info_t *tx_msdu_info) +{ + A_UINT8 tid; + A_UINT8 *l3_data_ptr; + A_UINT16 typeorlength; + + l3_data_ptr = datap + tx_msdu_info->htt.info.l3_hdr_offset; + typeorlength = tx_msdu_info->htt.info.ethertype; + + /* IP packet, do packet inspection for TID */ + if (typeorlength == ETHERTYPE_IPV4) { + tid = ol_tx_tid_by_ipv4(l3_data_ptr); + } else if (typeorlength == ETHERTYPE_IPV6) { + tid = ol_tx_tid_by_ipv6(l3_data_ptr); + } else if (ETHERTYPE_IS_EAPOL_WAPI(typeorlength)) { + /* EAPOL go with voice priority*/ + tid = TX_EAPOL_TID; + } else if (typeorlength == ETHERTYPE_ARP) { + tid = TX_ARP_TID; + } else { + /* For non-IP case, use default TID */ + tid = TX_DEFAULT_TID; + } + return tid; +} + +static inline A_UINT8 +ol_tx_tid_by_raw_type( + A_UINT8 *datap, + struct ol_txrx_msdu_info_t *tx_msdu_info) +{ + A_UINT8 tid = HTT_TX_EXT_TID_NON_QOS_MCAST_BCAST; + + /* adjust hdr_ptr to RA */ + struct ieee80211_frame *wh = (struct ieee80211_frame *)datap; + + /* FIXME: This code does not handle 4 address formats. The QOS field + * is not at usual location. + */ + if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == + IEEE80211_FC0_TYPE_DATA) { + /* dot11 encapsulated frame */ + struct ieee80211_qosframe *whqos = + (struct ieee80211_qosframe *)datap; + if (whqos->i_fc[0] & IEEE80211_FC0_SUBTYPE_QOS) + tid = whqos->i_qos[0] & IEEE80211_QOS_TID; + else + tid = HTT_NON_QOS_TID; + } else { + /* + * This function should only be applied to data frames. + * For management frames, we already know to use + * HTT_TX_EXT_TID_MGMT. + */ + qdf_assert(0); + } + return tid; +} + +static A_UINT8 +ol_tx_tid( + struct ol_txrx_pdev_t *pdev, + qdf_nbuf_t tx_nbuf, + struct ol_txrx_msdu_info_t *tx_msdu_info) +{ + A_UINT8 *datap = qdf_nbuf_data(tx_nbuf); + A_UINT8 tid; + + if (pdev->frame_format == wlan_frm_fmt_raw) { + tx_msdu_info->htt.info.l2_hdr_type = htt_pkt_type_raw; + + ol_tx_set_ether_type(datap, tx_msdu_info); + tid = tx_msdu_info->htt.info.ext_tid == + QDF_NBUF_TX_EXT_TID_INVALID ? + ol_tx_tid_by_raw_type(datap, tx_msdu_info) : + tx_msdu_info->htt.info.ext_tid; + } else if (pdev->frame_format == wlan_frm_fmt_802_3) { + tx_msdu_info->htt.info.l2_hdr_type = htt_pkt_type_ethernet; + + ol_tx_set_ether_type(datap, tx_msdu_info); + tid = + tx_msdu_info->htt.info.ext_tid == + QDF_NBUF_TX_EXT_TID_INVALID ? + ol_tx_tid_by_ether_type(datap, tx_msdu_info) : + tx_msdu_info->htt.info.ext_tid; + } else if (pdev->frame_format == wlan_frm_fmt_native_wifi) { + struct llc_snap_hdr_t *llc; + + tx_msdu_info->htt.info.l2_hdr_type = htt_pkt_type_native_wifi; + tx_msdu_info->htt.info.l3_hdr_offset = + sizeof(struct ieee80211_frame); + llc = (struct llc_snap_hdr_t *) + (datap + tx_msdu_info->htt.info.l3_hdr_offset); + tx_msdu_info->htt.info.ethertype = + (llc->ethertype[0] << 8) | llc->ethertype[1]; + /* + * Native WiFi is a special case of "raw" 802.11 header format. + * However, we expect that for all cases that use native WiFi, + * the TID will be directly specified out of band. + */ + tid = tx_msdu_info->htt.info.ext_tid; + } else { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_FATAL, + "Invalid standard frame type: %d\n", + pdev->frame_format); + qdf_assert(0); + tid = HTT_TX_EXT_TID_INVALID; + } + return tid; +} + +#if defined(CONFIG_HL_SUPPORT) && defined(FEATURE_WLAN_TDLS) +static inline +struct ol_txrx_peer_t *ol_tx_tdls_peer_find(struct ol_txrx_pdev_t *pdev, + struct ol_txrx_vdev_t *vdev, + uint8_t *peer_id) +{ + struct ol_txrx_peer_t *peer = NULL; + + if (vdev->hlTdlsFlag) { + peer = ol_txrx_find_peer_by_addr(pdev, + vdev->hl_tdls_ap_mac_addr.raw, + peer_id); + if (peer && (peer->peer_ids[0] == HTT_INVALID_PEER_ID)) { + peer = NULL; + } else { + if (peer) + OL_TXRX_PEER_INC_REF_CNT(peer); + } + } + if (!peer) + peer = ol_txrx_assoc_peer_find(vdev); + + return peer; +} + +#else +struct ol_txrx_peer_t *ol_tx_tdls_peer_find(struct ol_txrx_pdev_t *pdev, + struct ol_txrx_vdev_t *vdev, + uint8_t *peer_id) +{ + struct ol_txrx_peer_t *peer = NULL; + peer = ol_txrx_assoc_peer_find(vdev); + + return peer; +} + + +#endif + +struct ol_tx_frms_queue_t * +ol_tx_classify( + struct ol_txrx_vdev_t *vdev, + struct ol_tx_desc_t *tx_desc, + qdf_nbuf_t tx_nbuf, + struct ol_txrx_msdu_info_t *tx_msdu_info) +{ + struct ol_txrx_pdev_t *pdev = vdev->pdev; + struct ol_txrx_peer_t *peer = NULL; + struct ol_tx_frms_queue_t *txq = NULL; + A_UINT8 *dest_addr; + A_UINT8 tid; + u_int8_t peer_id; + + TX_SCHED_DEBUG_PRINT("Enter %s\n", __func__); + dest_addr = ol_tx_dest_addr_find(pdev, tx_nbuf); + if ((IEEE80211_IS_MULTICAST(dest_addr)) || + (vdev->opmode == wlan_op_mode_ocb)) { + txq = &vdev->txqs[OL_TX_VDEV_MCAST_BCAST]; + tx_msdu_info->htt.info.ext_tid = + HTT_TX_EXT_TID_NON_QOS_MCAST_BCAST; + if (vdev->opmode == wlan_op_mode_sta) { + /* + * The STA sends a frame with a broadcast + * dest addr (DA) as a + * unicast frame to the AP's receive addr (RA). + * Find the peer object that represents the AP + * that the STA is associated with. + */ + peer = ol_txrx_assoc_peer_find(vdev); + if (!peer) { + QDF_TRACE(QDF_MODULE_ID_TXRX, + QDF_TRACE_LEVEL_ERROR, + "Error: STA %p (%02x:%02x:%02x:%02x:%02x:%02x) trying to send bcast DA tx data frame w/o association\n", + vdev, + vdev->mac_addr.raw[0], + vdev->mac_addr.raw[1], + vdev->mac_addr.raw[2], + vdev->mac_addr.raw[3], + vdev->mac_addr.raw[4], + vdev->mac_addr.raw[5]); + return NULL; /* error */ + } else if ((peer->security[ + OL_TXRX_PEER_SECURITY_MULTICAST].sec_type + != htt_sec_type_wapi) && + (qdf_nbuf_is_ipv4_pkt(tx_nbuf) == true)) { + if (QDF_NBUF_CB_PACKET_TYPE_DHCP == + QDF_NBUF_CB_GET_PACKET_TYPE( + tx_nbuf)) { + /* DHCP frame to go with + * voice priority + */ + txq = &peer->txqs[TX_DHCP_TID]; + tx_msdu_info->htt.info.ext_tid = + TX_DHCP_TID; + } + } + /* + * The following line assumes each peer object has a + * single ID. This is currently true, and is expected + * to remain true. + */ + tx_msdu_info->htt.info.peer_id = peer->peer_ids[0]; + } else if (vdev->opmode == wlan_op_mode_ocb) { + tx_msdu_info->htt.info.peer_id = HTT_INVALID_PEER_ID; + /* In OCB mode, don't worry about the peer. + *We don't need it. */ + peer = NULL; + } else { + tx_msdu_info->htt.info.peer_id = HTT_INVALID_PEER_ID; + /* + * Look up the vdev's BSS peer, so that the + * classify_extension function can check whether to + * encrypt multicast / broadcast frames. + */ + peer = ol_txrx_peer_find_hash_find_inc_ref(pdev, + vdev->mac_addr.raw, + 0, 1); + if (!peer) { + QDF_TRACE(QDF_MODULE_ID_TXRX, + QDF_TRACE_LEVEL_ERROR, + "Error: vdev %p (%02x:%02x:%02x:%02x:%02x:%02x) trying to send bcast/mcast, but no self-peer found\n", + vdev, + vdev->mac_addr.raw[0], + vdev->mac_addr.raw[1], + vdev->mac_addr.raw[2], + vdev->mac_addr.raw[3], + vdev->mac_addr.raw[4], + vdev->mac_addr.raw[5]); + return NULL; /* error */ + } + } + tx_msdu_info->htt.info.is_unicast = false; + } else { + /* tid would be overwritten for non QoS case*/ + tid = ol_tx_tid(pdev, tx_nbuf, tx_msdu_info); + if ((HTT_TX_EXT_TID_INVALID == tid) || + (tid >= OL_TX_NUM_TIDS)) { + QDF_TRACE(QDF_MODULE_ID_TXRX, + QDF_TRACE_LEVEL_ERROR, + "%s Error: could not classify packet into valid TID(%d).\n", + __func__, tid); + return NULL; + } +#ifdef ATH_SUPPORT_WAPI + /* Check to see if a frame is a WAI frame */ + if (tx_msdu_info->htt.info.ethertype == ETHERTYPE_WAI) { + /* WAI frames should not be encrypted */ + tx_msdu_info->htt.action.do_encrypt = 0; + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO, + "Tx Frame is a WAI frame\n"); + } +#endif /* ATH_SUPPORT_WAPI */ + + /* + * Find the peer and increment its reference count. + * If this vdev is an AP, use the dest addr (DA) to determine + * which peer STA this unicast data frame is for. + * If this vdev is a STA, the unicast data frame is for the + * AP the STA is associated with. + */ + if (vdev->opmode == wlan_op_mode_sta) { + /* + * TO DO: + * To support TDLS, first check if there is a TDLS + * peer STA, + * and if so, check if the DA matches the TDLS peer + * STA's MAC address. If there is no peer TDLS STA, + * or if the DA is not the TDLS STA's address, + * then the frame is either for the AP itself, or is + * supposed to be sent to the AP for forwarding. + */ +#if 0 + if (vdev->num_tdls_peers > 0) { + peer = NULL; + for (i = 0; i < vdev->num_tdls_peers; i++) { + int differs = adf_os_mem_cmp( + vdev->tdls_peers[i]-> + mac_addr.raw, + dest_addr, + OL_TXRX_MAC_ADDR_LEN); + if (!differs) { + peer = vdev->tdls_peers[i]; + break; + } + } + } else { + /* send to AP */ + peer = ol_txrx_assoc_peer_find(vdev); + } +#endif + peer = ol_tx_tdls_peer_find(pdev, vdev, &peer_id); + } else { + peer = ol_txrx_peer_find_hash_find_inc_ref(pdev, + dest_addr, + 0, 1); + } + tx_msdu_info->htt.info.is_unicast = true; + if (!peer) { + /* + * Unicast data xfer can only happen to an + * associated peer. It is illegitimate to send unicast + * data if there is no peer to send it to. + */ + QDF_TRACE(QDF_MODULE_ID_TXRX, + QDF_TRACE_LEVEL_ERROR, + "Error: vdev %p (%02x:%02x:%02x:%02x:%02x:%02x) trying to send unicast tx data frame to an unknown peer\n", + vdev, + vdev->mac_addr.raw[0], vdev->mac_addr.raw[1], + vdev->mac_addr.raw[2], vdev->mac_addr.raw[3], + vdev->mac_addr.raw[4], vdev->mac_addr.raw[5]); + return NULL; /* error */ + } + TX_SCHED_DEBUG_PRINT("Peer found\n"); + if (!peer->qos_capable) { + tid = OL_TX_NON_QOS_TID; + } else if ((peer->security[ + OL_TXRX_PEER_SECURITY_UNICAST].sec_type + != htt_sec_type_wapi) && + (qdf_nbuf_is_ipv4_pkt(tx_nbuf) == true)) { + if (QDF_NBUF_CB_PACKET_TYPE_DHCP == + QDF_NBUF_CB_GET_PACKET_TYPE(tx_nbuf)) + /* DHCP frame to go with voice priority */ + tid = TX_DHCP_TID; + } + + /* Only allow encryption when in authenticated state */ + if (OL_TXRX_PEER_STATE_AUTH != peer->state) + tx_msdu_info->htt.action.do_encrypt = 0; + + txq = &peer->txqs[tid]; + tx_msdu_info->htt.info.ext_tid = tid; + /* + * The following line assumes each peer object has a single ID. + * This is currently true, and is expected to remain true. + */ + tx_msdu_info->htt.info.peer_id = peer->peer_ids[0]; + /* + * WORKAROUND - check that the peer ID is valid. + * If tx data is provided before ol_rx_peer_map_handler is + * called to record the peer ID specified by the target, + * then we could end up here with an invalid peer ID. + * TO DO: rather than dropping the tx frame, pause the txq it + * goes into, then fill in the peer ID for the entries in the + * txq when the peer_map event provides the peer ID, and then + * unpause the txq. + */ + if (tx_msdu_info->htt.info.peer_id == HTT_INVALID_PEER_ID) { + if (peer) { + /* remove the peer reference added above */ + OL_TXRX_PEER_UNREF_DELETE(peer); + tx_msdu_info->peer = NULL; + } + return NULL; + } + } + tx_msdu_info->peer = peer; + if (ol_if_tx_bad_peer_txq_overflow(pdev, peer, txq)) + return NULL; + /* + * If relevant, do a deeper inspection to determine additional + * characteristics of the tx frame. + * If the frame is invalid, then the txq will be set to NULL to + * indicate an error. + */ + OL_TX_CLASSIFY_EXTENSION(vdev, tx_desc, tx_nbuf, tx_msdu_info, txq); + if (IEEE80211_IS_MULTICAST(dest_addr) && vdev->opmode != + wlan_op_mode_sta && tx_msdu_info->peer != + NULL) { + TXRX_PRINT(TXRX_PRINT_LEVEL_INFO1, + "%s: remove the peer reference %p\n", + __func__, peer); + /* remove the peer reference added above */ + OL_TXRX_PEER_UNREF_DELETE(tx_msdu_info->peer); + /* Making peer NULL in case if multicast non STA mode */ + tx_msdu_info->peer = NULL; + } + + /* Whether this frame can download though HTT2 data pipe or not. */ + OL_TX_CLASSIFY_HTT2_EXTENSION(vdev, tx_nbuf, tx_msdu_info); + + /* Update Tx Queue info */ + tx_desc->txq = txq; + + TX_SCHED_DEBUG_PRINT("Leave %s\n", __func__); + return txq; +} + +struct ol_tx_frms_queue_t * +ol_tx_classify_mgmt( + struct ol_txrx_vdev_t *vdev, + struct ol_tx_desc_t *tx_desc, + qdf_nbuf_t tx_nbuf, + struct ol_txrx_msdu_info_t *tx_msdu_info) +{ + struct ol_txrx_pdev_t *pdev = vdev->pdev; + struct ol_txrx_peer_t *peer = NULL; + struct ol_tx_frms_queue_t *txq = NULL; + A_UINT8 *dest_addr; + union ol_txrx_align_mac_addr_t local_mac_addr_aligned, *mac_addr; + + TX_SCHED_DEBUG_PRINT("Enter %s\n", __func__); + dest_addr = ol_tx_dest_addr_find(pdev, tx_nbuf); + if (IEEE80211_IS_MULTICAST(dest_addr)) { + /* + * AP: beacons are broadcast, + * public action frames (e.g. extended channel + * switch announce) may be broadcast + * STA: probe requests can be either broadcast or unicast + */ + txq = &vdev->txqs[OL_TX_VDEV_DEFAULT_MGMT]; + tx_msdu_info->htt.info.peer_id = HTT_INVALID_PEER_ID; + tx_msdu_info->peer = NULL; + tx_msdu_info->htt.info.is_unicast = 0; + } else { + /* + * Find the peer and increment its reference count. + * If this vdev is an AP, use the receiver addr (RA) to + * determine which peer STA this unicast mgmt frame is for. + * If this vdev is a STA, the unicast mgmt frame is for the + * AP the STA is associated with. + * Probe request / response and Assoc request / response are + * sent before the peer exists - in this case, use the + * vdev's default tx queue. + */ + if (vdev->opmode == wlan_op_mode_sta) { + /* + * TO DO: + * To support TDLS, first check if there is a TDLS + * peer STA, and if so, check if the DA matches + * the TDLS peer STA's MAC address. + */ + peer = ol_txrx_assoc_peer_find(vdev); + /* + * Some special case(preauth for example) needs to send + * unicast mgmt frame to unassociated AP. In such case, + * we need to check if dest addr match the associated + * peer addr. If not, we set peer as NULL to queue this + * frame to vdev queue. + */ + if (peer) { + int rcnt; + + qdf_mem_copy( + &local_mac_addr_aligned.raw[0], + dest_addr, OL_TXRX_MAC_ADDR_LEN); + mac_addr = &local_mac_addr_aligned; + if (ol_txrx_peer_find_mac_addr_cmp( + mac_addr, + &peer->mac_addr) != 0) { + rcnt = OL_TXRX_PEER_UNREF_DELETE(peer); + peer = NULL; + } + } + } else { + /* find the peer and increment its reference count */ + peer = ol_txrx_peer_find_hash_find_inc_ref(pdev, dest_addr, + 0, 1); + } + tx_msdu_info->peer = peer; + if (!peer) { + txq = &vdev->txqs[OL_TX_VDEV_DEFAULT_MGMT]; + tx_msdu_info->htt.info.peer_id = HTT_INVALID_PEER_ID; + } else { + txq = &peer->txqs[HTT_TX_EXT_TID_MGMT]; + tx_msdu_info->htt.info.ext_tid = HTT_TX_EXT_TID_MGMT; + /* + * The following line assumes each peer object has a + * single ID. This is currently true, and is expected + * to remain true. + */ + tx_msdu_info->htt.info.peer_id = peer->peer_ids[0]; + } + tx_msdu_info->htt.info.is_unicast = 1; + } + /* + * If relevant, do a deeper inspection to determine additional + * characteristics of the tx frame. + * If the frame is invalid, then the txq will be set to NULL to + * indicate an error. + */ + OL_TX_CLASSIFY_MGMT_EXTENSION(vdev, tx_desc, tx_nbuf, + tx_msdu_info, txq); + + /* Whether this frame can download though HTT2 data pipe or not. */ + OL_TX_CLASSIFY_HTT2_EXTENSION(vdev, tx_nbuf, tx_msdu_info); + + /* Update Tx Queue info */ + tx_desc->txq = txq; + + TX_SCHED_DEBUG_PRINT("Leave %s\n", __func__); + return txq; +} + +A_STATUS +ol_tx_classify_extension( + struct ol_txrx_vdev_t *vdev, + struct ol_tx_desc_t *tx_desc, + qdf_nbuf_t tx_msdu, + struct ol_txrx_msdu_info_t *msdu_info) +{ + A_UINT8 *datap = qdf_nbuf_data(tx_msdu); + struct ol_txrx_peer_t *peer; + int which_key; + + /* + * The following msdu_info fields were already filled in by the + * ol_tx entry function or the regular ol_tx_classify function: + * htt.info.vdev_id (ol_tx_hl or ol_tx_non_std_hl) + * htt.info.ext_tid (ol_tx_non_std_hl or ol_tx_classify) + * htt.info.frame_type (ol_tx_hl or ol_tx_non_std_hl) + * htt.info.l2_hdr_type (ol_tx_hl or ol_tx_non_std_hl) + * htt.info.is_unicast (ol_tx_classify) + * htt.info.peer_id (ol_tx_classify) + * peer (ol_tx_classify) + * if (is_unicast) { + * htt.info.ethertype (ol_tx_classify) + * htt.info.l3_hdr_offset (ol_tx_classify) + * } + * The following fields need to be filled in by this function: + * if (!is_unicast) { + * htt.info.ethertype + * htt.info.l3_hdr_offset + * } + * htt.action.band (NOT CURRENTLY USED) + * htt.action.do_encrypt + * htt.action.do_tx_complete + * The following fields are not needed for data frames, and can + * be left uninitialized: + * htt.info.frame_subtype + */ + + if (!msdu_info->htt.info.is_unicast) { + int l2_hdr_size; + A_UINT16 ethertype; + + if (msdu_info->htt.info.l2_hdr_type == htt_pkt_type_ethernet) { + struct ethernet_hdr_t *eh; + + eh = (struct ethernet_hdr_t *)datap; + l2_hdr_size = sizeof(*eh); + ethertype = (eh->ethertype[0] << 8) | eh->ethertype[1]; + + if (ethertype == ETHERTYPE_VLAN) { + struct ethernet_vlan_hdr_t *evh; + + evh = (struct ethernet_vlan_hdr_t *)datap; + l2_hdr_size = sizeof(*evh); + ethertype = (evh->ethertype[0] << 8) | + evh->ethertype[1]; + } + + if (!IS_ETHERTYPE(ethertype)) { + /* 802.3 header*/ + struct llc_snap_hdr_t *llc = + (struct llc_snap_hdr_t *)(datap + + l2_hdr_size); + ethertype = (llc->ethertype[0] << 8) | + llc->ethertype[1]; + l2_hdr_size += sizeof(*llc); + } + msdu_info->htt.info.l3_hdr_offset = l2_hdr_size; + msdu_info->htt.info.ethertype = ethertype; + } else { /* 802.11 */ + struct llc_snap_hdr_t *llc; + l2_hdr_size = ol_txrx_ieee80211_hdrsize(datap); + llc = (struct llc_snap_hdr_t *)(datap + l2_hdr_size); + ethertype = (llc->ethertype[0] << 8) | + llc->ethertype[1]; + /* + * Don't include the LLC/SNAP header in l2_hdr_size, + * because l3_hdr_offset is actually supposed to refer + * to the header after the 802.3 or 802.11 header, + * which could be a LLC/SNAP header rather + * than the L3 header. + */ + } + msdu_info->htt.info.l3_hdr_offset = l2_hdr_size; + msdu_info->htt.info.ethertype = ethertype; + which_key = txrx_sec_mcast; + } else { + which_key = txrx_sec_ucast; + } + peer = msdu_info->peer; + /* + * msdu_info->htt.action.do_encrypt is initially set in ol_tx_desc_hl. + * Add more check here. + */ + msdu_info->htt.action.do_encrypt = (!peer) ? 0 : + (peer->security[which_key].sec_type == htt_sec_type_none) ? 0 : + msdu_info->htt.action.do_encrypt; + /* + * For systems that have a frame by frame spec for whether to receive + * a tx completion notification, use the tx completion notification + * only for certain management frames, not for data frames. + * (In the future, this may be changed slightly, e.g. to request a + * tx completion notification for the final EAPOL message sent by a + * STA during the key delivery handshake.) + */ + msdu_info->htt.action.do_tx_complete = 0; + + return A_OK; +} + +A_STATUS +ol_tx_classify_mgmt_extension( + struct ol_txrx_vdev_t *vdev, + struct ol_tx_desc_t *tx_desc, + qdf_nbuf_t tx_msdu, + struct ol_txrx_msdu_info_t *msdu_info) +{ + struct ieee80211_frame *wh; + + /* + * The following msdu_info fields were already filled in by the + * ol_tx entry function or the regular ol_tx_classify_mgmt function: + * htt.info.vdev_id (ol_txrx_mgmt_send) + * htt.info.frame_type (ol_txrx_mgmt_send) + * htt.info.l2_hdr_type (ol_txrx_mgmt_send) + * htt.action.do_tx_complete (ol_txrx_mgmt_send) + * htt.info.peer_id (ol_tx_classify_mgmt) + * htt.info.ext_tid (ol_tx_classify_mgmt) + * htt.info.is_unicast (ol_tx_classify_mgmt) + * peer (ol_tx_classify_mgmt) + * The following fields need to be filled in by this function: + * htt.info.frame_subtype + * htt.info.l3_hdr_offset + * htt.action.band (NOT CURRENTLY USED) + * The following fields are not needed for mgmt frames, and can + * be left uninitialized: + * htt.info.ethertype + * htt.action.do_encrypt + * (This will be filled in by other SW, which knows whether + * the peer has robust-managment-frames enabled.) + */ + wh = (struct ieee80211_frame *)qdf_nbuf_data(tx_msdu); + msdu_info->htt.info.frame_subtype = + (wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) >> + IEEE80211_FC0_SUBTYPE_SHIFT; + msdu_info->htt.info.l3_hdr_offset = sizeof(struct ieee80211_frame); + + return A_OK; +} + +#endif /* defined(CONFIG_HL_SUPPORT) */ diff --git a/drivers/staging/qcacld-3.0/core/dp/txrx/ol_tx_classify.h b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_tx_classify.h new file mode 100644 index 0000000000000000000000000000000000000000..159897ae5c423f773cd3e8cad3843eed1dce96ad --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_tx_classify.h @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2012, 2014, 2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * @file ol_tx_classify.h + * @brief API definitions for the tx classify module within the data SW. + */ +#ifndef _OL_TX_CLASSIFY__H_ +#define _OL_TX_CLASSIFY__H_ + +#include /* qdf_nbuf_t */ +#include /* ol_txrx_vdev_t, etc. */ + +static inline u_int8_t * +ol_tx_dest_addr_find( + struct ol_txrx_pdev_t *pdev, + qdf_nbuf_t tx_nbuf) +{ + u_int8_t *hdr_ptr; + void *datap = qdf_nbuf_data(tx_nbuf); + + if (pdev->frame_format == wlan_frm_fmt_raw) { + /* adjust hdr_ptr to RA */ + struct ieee80211_frame *wh = + (struct ieee80211_frame *)datap; + hdr_ptr = wh->i_addr1; + } else if (pdev->frame_format == + wlan_frm_fmt_native_wifi) { + /* adjust hdr_ptr to RA */ + struct ieee80211_frame *wh = ( + struct ieee80211_frame *)datap; + hdr_ptr = wh->i_addr1; + } else if (pdev->frame_format == wlan_frm_fmt_802_3) { + hdr_ptr = datap; + } else { + QDF_TRACE(QDF_MODULE_ID_TXRX, + QDF_TRACE_LEVEL_ERROR, + "Invalid standard frame type: %d\n", + pdev->frame_format); + qdf_assert(0); + hdr_ptr = NULL; + } + return hdr_ptr; +} + +#if defined(CONFIG_HL_SUPPORT) + +/** + * @brief Classify a tx frame to which tid queue. + * + * @param vdev - the virtual device sending the data + * (for specifying the transmitter address for multicast / broadcast data) + * @param tx_desc - descriptor object with meta-data about the tx frame + * @param netbuf - the tx frame + * @param tx_msdu_info - characteristics of the tx frame + */ +struct ol_tx_frms_queue_t * +ol_tx_classify( + struct ol_txrx_vdev_t *vdev, + struct ol_tx_desc_t *tx_desc, + qdf_nbuf_t netbuf, + struct ol_txrx_msdu_info_t *tx_msdu_info); + +struct ol_tx_frms_queue_t * +ol_tx_classify_mgmt( + struct ol_txrx_vdev_t *vdev, + struct ol_tx_desc_t *tx_desc, + qdf_nbuf_t netbuf, + struct ol_txrx_msdu_info_t *tx_msdu_info); + +#else + +#define ol_tx_classify(vdev, tx_desc, netbuf, tx_msdu_info) NULL +#define ol_tx_classify_mgmt(vdev, tx_desc, netbuf, tx_msdu_info) NULL + +#endif /* defined(CONFIG_HL_SUPPORT) */ + + +#endif /* _OL_TX_CLASSIFY__H_ */ diff --git a/drivers/staging/qcacld-3.0/core/dp/txrx/ol_tx_desc.c b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_tx_desc.c new file mode 100644 index 0000000000000000000000000000000000000000..50b73921c9c92bd63af63b28a4ca9a49e1eb0066 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_tx_desc.c @@ -0,0 +1,968 @@ +/* + * Copyright (c) 2011, 2014-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#include /* QDF_NBUF_EXEMPT_NO_EXEMPTION, etc. */ +#include /* qdf_nbuf_t, etc. */ +#include /* qdf_assert */ +#include /* qdf_spinlock */ +#include /* qdf_tso_seg_dbg stuff */ +#ifdef QCA_COMPUTE_TX_DELAY +#include /* qdf_system_ticks */ +#endif + +#include /* htt_tx_desc_id */ + +#include +#include +#ifdef QCA_SUPPORT_SW_TXRX_ENCAP +#include /* OL_TX_RESTORE_HDR, etc */ +#endif +#include + +#ifdef QCA_SUPPORT_TXDESC_SANITY_CHECKS +static inline void ol_tx_desc_sanity_checks(struct ol_txrx_pdev_t *pdev, + struct ol_tx_desc_t *tx_desc) +{ + if (tx_desc->pkt_type != ol_tx_frm_freed) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "%s Potential tx_desc corruption pkt_type:0x%x pdev:0x%p", + __func__, tx_desc->pkt_type, pdev); + qdf_assert(0); + } +} +static inline void ol_tx_desc_reset_pkt_type(struct ol_tx_desc_t *tx_desc) +{ + tx_desc->pkt_type = ol_tx_frm_freed; +} +#ifdef QCA_COMPUTE_TX_DELAY +static inline void ol_tx_desc_compute_delay(struct ol_tx_desc_t *tx_desc) +{ + if (tx_desc->entry_timestamp_ticks != 0xffffffff) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, "%s Timestamp:0x%x\n", + __func__, tx_desc->entry_timestamp_ticks); + qdf_assert(0); + } + tx_desc->entry_timestamp_ticks = qdf_system_ticks(); +} +static inline void ol_tx_desc_reset_timestamp(struct ol_tx_desc_t *tx_desc) +{ + tx_desc->entry_timestamp_ticks = 0xffffffff; +} +#endif +#else +static inline void ol_tx_desc_sanity_checks(struct ol_txrx_pdev_t *pdev, + struct ol_tx_desc_t *tx_desc) +{ + return; +} +static inline void ol_tx_desc_reset_pkt_type(struct ol_tx_desc_t *tx_desc) +{ + return; +} +static inline void ol_tx_desc_compute_delay(struct ol_tx_desc_t *tx_desc) +{ + return; +} +static inline void ol_tx_desc_reset_timestamp(struct ol_tx_desc_t *tx_desc) +{ + return; +} +#endif + +/** + * ol_tx_desc_vdev_update() - vedv assign. + * @tx_desc: tx descriptor pointer + * @vdev: vdev handle + * + * Return: None + */ +static inline void +ol_tx_desc_vdev_update(struct ol_tx_desc_t *tx_desc, + struct ol_txrx_vdev_t *vdev) +{ + tx_desc->vdev = vdev; + tx_desc->vdev_id = vdev->vdev_id; +} + +#ifdef CONFIG_PER_VDEV_TX_DESC_POOL + +/** + * ol_tx_desc_count_inc() - tx desc count increment for desc allocation. + * @vdev: vdev handle + * + * Return: None + */ +static inline void +ol_tx_desc_count_inc(struct ol_txrx_vdev_t *vdev) +{ + qdf_atomic_inc(&vdev->tx_desc_count); +} +#else + +static inline void +ol_tx_desc_count_inc(struct ol_txrx_vdev_t *vdev) +{ + return; +} + +#endif + +#ifndef QCA_LL_TX_FLOW_CONTROL_V2 + +/** + * ol_tx_desc_alloc() - allocate descriptor from freelist + * @pdev: pdev handle + * @vdev: vdev handle + * + * Return: tx descriptor pointer/ NULL in case of error + */ +static +struct ol_tx_desc_t *ol_tx_desc_alloc(struct ol_txrx_pdev_t *pdev, + struct ol_txrx_vdev_t *vdev) +{ + struct ol_tx_desc_t *tx_desc = NULL; + + qdf_spin_lock_bh(&pdev->tx_mutex); + if (pdev->tx_desc.freelist) { + tx_desc = ol_tx_get_desc_global_pool(pdev); + ol_tx_desc_dup_detect_set(pdev, tx_desc); + ol_tx_desc_sanity_checks(pdev, tx_desc); + ol_tx_desc_compute_delay(tx_desc); + } + qdf_spin_unlock_bh(&pdev->tx_mutex); + + if (!tx_desc) + return NULL; + + ol_tx_desc_vdev_update(tx_desc, vdev); + ol_tx_desc_count_inc(vdev); + qdf_atomic_inc(&tx_desc->ref_cnt); + + return tx_desc; +} + +/** + * ol_tx_desc_alloc_wrapper() -allocate tx descriptor + * @pdev: pdev handler + * @vdev: vdev handler + * @msdu_info: msdu handler + * + * Return: tx descriptor or NULL + */ +struct ol_tx_desc_t * +ol_tx_desc_alloc_wrapper(struct ol_txrx_pdev_t *pdev, + struct ol_txrx_vdev_t *vdev, + struct ol_txrx_msdu_info_t *msdu_info) +{ + return ol_tx_desc_alloc(pdev, vdev); +} + +#else +/** + * ol_tx_desc_alloc() -allocate tx descriptor + * @pdev: pdev handler + * @vdev: vdev handler + * @pool: flow pool + * + * Return: tx descriptor or NULL + */ +static +struct ol_tx_desc_t *ol_tx_desc_alloc(struct ol_txrx_pdev_t *pdev, + struct ol_txrx_vdev_t *vdev, + struct ol_tx_flow_pool_t *pool) +{ + struct ol_tx_desc_t *tx_desc = NULL; + + if (pool) { + qdf_spin_lock_bh(&pool->flow_pool_lock); + if (pool->avail_desc) { + tx_desc = ol_tx_get_desc_flow_pool(pool); + ol_tx_desc_dup_detect_set(pdev, tx_desc); + if (qdf_unlikely(pool->avail_desc < pool->stop_th)) { + pool->status = FLOW_POOL_ACTIVE_PAUSED; + qdf_spin_unlock_bh(&pool->flow_pool_lock); + /* pause network queues */ + pdev->pause_cb(vdev->vdev_id, + WLAN_STOP_ALL_NETIF_QUEUE, + WLAN_DATA_FLOW_CONTROL); + } else { + qdf_spin_unlock_bh(&pool->flow_pool_lock); + } + ol_tx_desc_sanity_checks(pdev, tx_desc); + ol_tx_desc_compute_delay(tx_desc); + ol_tx_desc_vdev_update(tx_desc, vdev); + qdf_atomic_inc(&tx_desc->ref_cnt); + } else { + pool->pkt_drop_no_desc++; + qdf_spin_unlock_bh(&pool->flow_pool_lock); + } + } else { + pdev->pool_stats.pkt_drop_no_pool++; + } + + return tx_desc; +} + +/** + * ol_tx_desc_alloc_wrapper() -allocate tx descriptor + * @pdev: pdev handler + * @vdev: vdev handler + * @msdu_info: msdu handler + * + * Return: tx descriptor or NULL + */ +#ifdef QCA_LL_TX_FLOW_GLOBAL_MGMT_POOL +struct ol_tx_desc_t * +ol_tx_desc_alloc_wrapper(struct ol_txrx_pdev_t *pdev, + struct ol_txrx_vdev_t *vdev, + struct ol_txrx_msdu_info_t *msdu_info) +{ + if (qdf_unlikely(msdu_info->htt.info.frame_type == htt_pkt_type_mgmt)) + return ol_tx_desc_alloc(pdev, vdev, pdev->mgmt_pool); + else + return ol_tx_desc_alloc(pdev, vdev, vdev->pool); +} +#else +struct ol_tx_desc_t * +ol_tx_desc_alloc_wrapper(struct ol_txrx_pdev_t *pdev, + struct ol_txrx_vdev_t *vdev, + struct ol_txrx_msdu_info_t *msdu_info) +{ + return ol_tx_desc_alloc(pdev, vdev, vdev->pool); +} +#endif +#endif + +/** + * ol_tx_desc_alloc_hl() - allocate tx descriptor + * @pdev: pdev handle + * @vdev: vdev handle + * @msdu_info: tx msdu info + * + * Return: tx descriptor pointer/ NULL in case of error + */ +static struct ol_tx_desc_t * +ol_tx_desc_alloc_hl(struct ol_txrx_pdev_t *pdev, + struct ol_txrx_vdev_t *vdev, + struct ol_txrx_msdu_info_t *msdu_info) +{ + struct ol_tx_desc_t *tx_desc; + + tx_desc = ol_tx_desc_alloc_wrapper(pdev, vdev, msdu_info); + if (!tx_desc) + return NULL; + + qdf_atomic_dec(&pdev->tx_queue.rsrc_cnt); + + return tx_desc; +} + +#if defined(CONFIG_PER_VDEV_TX_DESC_POOL) && defined(CONFIG_HL_SUPPORT) + +/** + * ol_tx_desc_vdev_rm() - decrement the tx desc count for vdev. + * @tx_desc: tx desc + * + * Return: None + */ +static inline void +ol_tx_desc_vdev_rm(struct ol_tx_desc_t *tx_desc) +{ + qdf_atomic_dec(&tx_desc->vdev->tx_desc_count); + tx_desc->vdev = NULL; +} +#else + +static inline void +ol_tx_desc_vdev_rm(struct ol_tx_desc_t *tx_desc) +{ + return; +} +#endif + +#ifdef FEATURE_TSO +/** + * ol_tso_unmap_tso_segment() - Unmap TSO segment + * @pdev: pointer to ol_txrx_pdev_t structure + * @tx_desc: pointer to ol_tx_desc_t containing the TSO segment + * + * Unmap TSO segment (frag[1]). If it is the last TSO segment corresponding the + * nbuf, also unmap the EIT header(frag[0]). + * + * Return: None + */ +static void ol_tso_unmap_tso_segment(struct ol_txrx_pdev_t *pdev, struct ol_tx_desc_t *tx_desc) +{ + bool is_last_seg = false; + struct qdf_tso_num_seg_elem_t *tso_num_desc = NULL; + + if (qdf_unlikely(tx_desc->tso_desc == NULL)) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "%s %d TSO desc is NULL!", + __func__, __LINE__); + qdf_assert(0); + return; + } else if (qdf_unlikely(tx_desc->tso_num_desc == NULL)) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "%s %d TSO common info is NULL!", + __func__, __LINE__); + qdf_assert(0); + return; + } + + tso_num_desc = tx_desc->tso_num_desc; + + qdf_spin_lock_bh(&pdev->tso_seg_pool.tso_mutex); + + tso_num_desc->num_seg.tso_cmn_num_seg--; + is_last_seg = (tso_num_desc->num_seg.tso_cmn_num_seg == 0) ? + true : false; + qdf_nbuf_unmap_tso_segment(pdev->osdev, tx_desc->tso_desc, is_last_seg); + + qdf_spin_unlock_bh(&pdev->tso_seg_pool.tso_mutex); + +} + +/** + * ol_tx_tso_desc_free() - Add TSO TX descs back to the freelist + * @pdev: pointer to ol_txrx_pdev_t structure + * @tx_desc: pointer to ol_tx_desc_t containing the TSO segment + * + * Add qdf_tso_seg_elem_t corresponding to the TSO seg back to freelist. + * If it is the last segment of the jumbo skb, also add the + * qdf_tso_num_seg_elem_t to the free list. + * + * Return: None + */ +static void ol_tx_tso_desc_free(struct ol_txrx_pdev_t *pdev, + struct ol_tx_desc_t *tx_desc) +{ + bool is_last_seg; + struct qdf_tso_num_seg_elem_t *tso_num_desc = tx_desc->tso_num_desc; + + is_last_seg = (tso_num_desc->num_seg.tso_cmn_num_seg == 0) ? + true : false; + if (is_last_seg) { + ol_tso_num_seg_free(pdev, tx_desc->tso_num_desc); + tx_desc->tso_num_desc = NULL; + } + + ol_tso_free_segment(pdev, tx_desc->tso_desc); + tx_desc->tso_desc = NULL; +} + +#else +static void ol_tso_unmap_tso_segment(struct ol_txrx_pdev_t *pdev, struct ol_tx_desc_t *tx_desc) +{ +} + +static inline void ol_tx_tso_desc_free(struct ol_txrx_pdev_t *pdev, + struct ol_tx_desc_t *tx_desc) +{ +} + +#endif + +/** + * ol_tx_desc_free_common() - common funcs to free tx_desc for all flow ctl vers + * @pdev: pdev handle + * @tx_desc: tx descriptor + * + * Set of common functions needed for QCA_LL_TX_FLOW_CONTROL_V2 and older + * versions of flow control. Needs to be called from within a spinlock. + * + * Return: None + */ +static void ol_tx_desc_free_common(struct ol_txrx_pdev_t *pdev, struct ol_tx_desc_t *tx_desc) +{ + ol_tx_desc_dup_detect_reset(pdev, tx_desc); + + if (tx_desc->pkt_type == OL_TX_FRM_TSO) + ol_tx_tso_desc_free(pdev, tx_desc); + + ol_tx_desc_reset_pkt_type(tx_desc); + ol_tx_desc_reset_timestamp(tx_desc); + /* clear the ref cnt */ + qdf_atomic_init(&tx_desc->ref_cnt); + tx_desc->vdev_id = OL_TXRX_INVALID_VDEV_ID; +} + +#ifndef QCA_LL_TX_FLOW_CONTROL_V2 +/** + * ol_tx_desc_free() - put descriptor to freelist + * @pdev: pdev handle + * @tx_desc: tx descriptor + * + * Return: None + */ +void ol_tx_desc_free(struct ol_txrx_pdev_t *pdev, struct ol_tx_desc_t *tx_desc) +{ + qdf_spin_lock_bh(&pdev->tx_mutex); + + ol_tx_desc_free_common(pdev, tx_desc); + + ol_tx_put_desc_global_pool(pdev, tx_desc); + ol_tx_desc_vdev_rm(tx_desc); + tx_desc->vdev_id = OL_TXRX_INVALID_VDEV_ID; + + qdf_spin_unlock_bh(&pdev->tx_mutex); +} + +#else +/** + * ol_tx_desc_free() - put descriptor to pool freelist + * @pdev: pdev handle + * @tx_desc: tx descriptor + * + * Return: None + */ +void ol_tx_desc_free(struct ol_txrx_pdev_t *pdev, struct ol_tx_desc_t *tx_desc) +{ + struct ol_tx_flow_pool_t *pool = tx_desc->pool; + + qdf_spin_lock_bh(&pool->flow_pool_lock); + + ol_tx_desc_free_common(pdev, tx_desc); + ol_tx_put_desc_flow_pool(pool, tx_desc); + switch (pool->status) { + case FLOW_POOL_ACTIVE_PAUSED: + if (pool->avail_desc > pool->start_th) { + pdev->pause_cb(pool->member_flow_id, + WLAN_WAKE_ALL_NETIF_QUEUE, + WLAN_DATA_FLOW_CONTROL); + pool->status = FLOW_POOL_ACTIVE_UNPAUSED; + } + break; + case FLOW_POOL_INVALID: + if (pool->avail_desc == pool->flow_pool_size) { + qdf_spin_unlock_bh(&pool->flow_pool_lock); + ol_tx_free_invalid_flow_pool(pool); + qdf_print("%s %d pool is INVALID State!!\n", + __func__, __LINE__); + return; + } + break; + case FLOW_POOL_ACTIVE_UNPAUSED: + break; + default: + qdf_print("%s %d pool is INACTIVE State!!\n", + __func__, __LINE__); + break; + }; + + qdf_spin_unlock_bh(&pool->flow_pool_lock); + +} +#endif + +const uint32_t htt_to_ce_pkt_type[] = { + [htt_pkt_type_raw] = tx_pkt_type_raw, + [htt_pkt_type_native_wifi] = tx_pkt_type_native_wifi, + [htt_pkt_type_ethernet] = tx_pkt_type_802_3, + [htt_pkt_type_mgmt] = tx_pkt_type_mgmt, + [htt_pkt_type_eth2] = tx_pkt_type_eth2, + [htt_pkt_num_types] = 0xffffffff +}; + +#define WISA_DEST_PORT_6MBPS 50000 +#define WISA_DEST_PORT_24MBPS 50001 + +/** + * ol_tx_get_wisa_ext_hdr_type() - get header type for WiSA mode + * @netbuf: network buffer + * + * Return: extension header type + */ +static enum extension_header_type +ol_tx_get_wisa_ext_hdr_type(qdf_nbuf_t netbuf) +{ + uint8_t *buf = qdf_nbuf_data(netbuf); + uint16_t dport; + + if (qdf_is_macaddr_group( + (struct qdf_mac_addr *)(buf + QDF_NBUF_DEST_MAC_OFFSET))) { + + dport = (uint16_t)(*(uint16_t *)(buf + + QDF_NBUF_TRAC_IPV4_OFFSET + + QDF_NBUF_TRAC_IPV4_HEADER_SIZE + sizeof(uint16_t))); + + if (dport == QDF_SWAP_U16(WISA_DEST_PORT_6MBPS)) + return WISA_MODE_EXT_HEADER_6MBPS; + else if (dport == QDF_SWAP_U16(WISA_DEST_PORT_24MBPS)) + return WISA_MODE_EXT_HEADER_24MBPS; + else + return EXT_HEADER_NOT_PRESENT; + } else { + return EXT_HEADER_NOT_PRESENT; + } +} + +/** + * ol_tx_get_ext_header_type() - extension header is required or not + * @vdev: vdev pointer + * @netbuf: network buffer + * + * This function returns header type and if extension header is + * not required than returns EXT_HEADER_NOT_PRESENT. + * + * Return: extension header type + */ +enum extension_header_type +ol_tx_get_ext_header_type(struct ol_txrx_vdev_t *vdev, + qdf_nbuf_t netbuf) +{ + if (vdev->is_wisa_mode_enable == true) + return ol_tx_get_wisa_ext_hdr_type(netbuf); + else + return EXT_HEADER_NOT_PRESENT; +} + +struct ol_tx_desc_t *ol_tx_desc_ll(struct ol_txrx_pdev_t *pdev, + struct ol_txrx_vdev_t *vdev, + qdf_nbuf_t netbuf, + struct ol_txrx_msdu_info_t *msdu_info) +{ + struct ol_tx_desc_t *tx_desc; + unsigned int i; + uint32_t num_frags; + enum extension_header_type type; + + msdu_info->htt.info.vdev_id = vdev->vdev_id; + msdu_info->htt.action.cksum_offload = qdf_nbuf_get_tx_cksum(netbuf); + switch (qdf_nbuf_get_exemption_type(netbuf)) { + case QDF_NBUF_EXEMPT_NO_EXEMPTION: + case QDF_NBUF_EXEMPT_ON_KEY_MAPPING_KEY_UNAVAILABLE: + /* We want to encrypt this frame */ + msdu_info->htt.action.do_encrypt = 1; + break; + case QDF_NBUF_EXEMPT_ALWAYS: + /* We don't want to encrypt this frame */ + msdu_info->htt.action.do_encrypt = 0; + break; + default: + qdf_assert(0); + break; + } + + /* allocate the descriptor */ + tx_desc = ol_tx_desc_alloc_wrapper(pdev, vdev, msdu_info); + if (!tx_desc) + return NULL; + + /* initialize the SW tx descriptor */ + tx_desc->netbuf = netbuf; + + if (msdu_info->tso_info.is_tso) { + tx_desc->tso_desc = msdu_info->tso_info.curr_seg; + tx_desc->tso_num_desc = msdu_info->tso_info.tso_num_seg_list; + tx_desc->pkt_type = OL_TX_FRM_TSO; + TXRX_STATS_MSDU_INCR(pdev, tx.tso.tso_pkts, netbuf); + } else { + tx_desc->pkt_type = OL_TX_FRM_STD; + } + + type = ol_tx_get_ext_header_type(vdev, netbuf); + + /* initialize the HW tx descriptor */ + if (qdf_unlikely(htt_tx_desc_init(pdev->htt_pdev, tx_desc->htt_tx_desc, + tx_desc->htt_tx_desc_paddr, + ol_tx_desc_id(pdev, tx_desc), netbuf, &msdu_info->htt, + &msdu_info->tso_info, NULL, type))) { + /* + * HTT Tx descriptor initialization failed. + * therefore, free the tx desc + */ + ol_tx_desc_free(pdev, tx_desc); + return NULL; + } + + /* + * Initialize the fragmentation descriptor. + * Skip the prefix fragment (HTT tx descriptor) that was added + * during the call to htt_tx_desc_init above. + */ + num_frags = qdf_nbuf_get_num_frags(netbuf); + /* num_frags are expected to be 2 max */ + num_frags = (num_frags > QDF_NBUF_CB_TX_MAX_EXTRA_FRAGS) + ? QDF_NBUF_CB_TX_MAX_EXTRA_FRAGS + : num_frags; +#if defined(HELIUMPLUS) + /* + * Use num_frags - 1, since 1 frag is used to store + * the HTT/HTC descriptor + * Refer to htt_tx_desc_init() + */ + htt_tx_desc_num_frags(pdev->htt_pdev, tx_desc->htt_frag_desc, + num_frags - 1); +#else /* ! defined(HELIUMPLUS) */ + htt_tx_desc_num_frags(pdev->htt_pdev, tx_desc->htt_tx_desc, + num_frags - 1); +#endif /* defined(HELIUMPLUS) */ + + if (msdu_info->tso_info.is_tso) { + htt_tx_desc_fill_tso_info(pdev->htt_pdev, + tx_desc->htt_frag_desc, &msdu_info->tso_info); + TXRX_STATS_TSO_SEG_UPDATE(pdev, + msdu_info->tso_info.msdu_stats_idx, + msdu_info->tso_info.curr_seg->seg); + } else { + for (i = 1; i < num_frags; i++) { + qdf_size_t frag_len; + qdf_dma_addr_t frag_paddr; +#ifdef HELIUMPLUS_DEBUG + void *frag_vaddr; + frag_vaddr = qdf_nbuf_get_frag_vaddr(netbuf, i); +#endif + frag_len = qdf_nbuf_get_frag_len(netbuf, i); + frag_paddr = qdf_nbuf_get_frag_paddr(netbuf, i); +#if defined(HELIUMPLUS) + htt_tx_desc_frag(pdev->htt_pdev, tx_desc->htt_frag_desc, i - 1, + frag_paddr, frag_len); +#if defined(HELIUMPLUS_DEBUG) + qdf_print("%s:%d: htt_fdesc=%p frag=%d frag_vaddr=0x%p frag_paddr=0x%llx len=%zu\n", + __func__, __LINE__, tx_desc->htt_frag_desc, + i-1, frag_vaddr, frag_paddr, frag_len); + ol_txrx_dump_pkt(netbuf, frag_paddr, 64); +#endif /* HELIUMPLUS_DEBUG */ +#else /* ! defined(HELIUMPLUS) */ + htt_tx_desc_frag(pdev->htt_pdev, tx_desc->htt_tx_desc, i - 1, + frag_paddr, frag_len); +#endif /* defined(HELIUMPLUS) */ + } + } + +#if defined(HELIUMPLUS_DEBUG) + ol_txrx_dump_frag_desc("ol_tx_desc_ll()", tx_desc); +#endif + return tx_desc; +} + +struct ol_tx_desc_t * +ol_tx_desc_hl( + struct ol_txrx_pdev_t *pdev, + struct ol_txrx_vdev_t *vdev, + qdf_nbuf_t netbuf, + struct ol_txrx_msdu_info_t *msdu_info) +{ + struct ol_tx_desc_t *tx_desc; + + /* FIX THIS: these inits should probably be done by tx classify */ + msdu_info->htt.info.vdev_id = vdev->vdev_id; + msdu_info->htt.info.frame_type = pdev->htt_pkt_type; + msdu_info->htt.action.cksum_offload = qdf_nbuf_get_tx_cksum(netbuf); + switch (qdf_nbuf_get_exemption_type(netbuf)) { + case QDF_NBUF_EXEMPT_NO_EXEMPTION: + case QDF_NBUF_EXEMPT_ON_KEY_MAPPING_KEY_UNAVAILABLE: + /* We want to encrypt this frame */ + msdu_info->htt.action.do_encrypt = 1; + break; + case QDF_NBUF_EXEMPT_ALWAYS: + /* We don't want to encrypt this frame */ + msdu_info->htt.action.do_encrypt = 0; + break; + default: + qdf_assert(0); + break; + } + + /* allocate the descriptor */ + tx_desc = ol_tx_desc_alloc_hl(pdev, vdev, msdu_info); + if (!tx_desc) + return NULL; + + /* initialize the SW tx descriptor */ + tx_desc->netbuf = netbuf; + /* fix this - get pkt_type from msdu_info */ + tx_desc->pkt_type = OL_TX_FRM_STD; + +#ifdef QCA_SUPPORT_SW_TXRX_ENCAP + tx_desc->orig_l2_hdr_bytes = 0; +#endif + /* the HW tx descriptor will be initialized later by the caller */ + + return tx_desc; +} + +void ol_tx_desc_frame_list_free(struct ol_txrx_pdev_t *pdev, + ol_tx_desc_list *tx_descs, int had_error) +{ + struct ol_tx_desc_t *tx_desc, *tmp; + qdf_nbuf_t msdus = NULL; + + TAILQ_FOREACH_SAFE(tx_desc, tx_descs, tx_desc_list_elem, tmp) { + qdf_nbuf_t msdu = tx_desc->netbuf; + + qdf_atomic_init(&tx_desc->ref_cnt); /* clear the ref cnt */ +#ifdef QCA_SUPPORT_SW_TXRX_ENCAP + /* restore original hdr offset */ + OL_TX_RESTORE_HDR(tx_desc, msdu); +#endif + if (qdf_nbuf_get_users(msdu) <= 1) + qdf_nbuf_unmap(pdev->osdev, msdu, QDF_DMA_TO_DEVICE); + + /* free the tx desc */ + ol_tx_desc_free(pdev, tx_desc); + /* link the netbuf into a list to free as a batch */ + qdf_nbuf_set_next(msdu, msdus); + msdus = msdu; + } + /* free the netbufs as a batch */ + qdf_nbuf_tx_free(msdus, had_error); +} + +void ol_tx_desc_frame_free_nonstd(struct ol_txrx_pdev_t *pdev, + struct ol_tx_desc_t *tx_desc, int had_error) +{ + int mgmt_type; + ol_txrx_mgmt_tx_cb ota_ack_cb; + + qdf_atomic_init(&tx_desc->ref_cnt); /* clear the ref cnt */ +#ifdef QCA_SUPPORT_SW_TXRX_ENCAP + /* restore original hdr offset */ + OL_TX_RESTORE_HDR(tx_desc, (tx_desc->netbuf)); +#endif + if (tx_desc->pkt_type == OL_TX_FRM_NO_FREE) { + /* free the tx desc but don't unmap or free the frame */ + if (pdev->tx_data_callback.func) { + qdf_nbuf_set_next(tx_desc->netbuf, NULL); + pdev->tx_data_callback.func(pdev->tx_data_callback.ctxt, + tx_desc->netbuf, had_error); + goto free_tx_desc; + } + /* let the code below unmap and free the frame */ + } + if (tx_desc->pkt_type == OL_TX_FRM_TSO) + ol_tso_unmap_tso_segment(pdev, tx_desc); + else + qdf_nbuf_unmap(pdev->osdev, tx_desc->netbuf, QDF_DMA_TO_DEVICE); + /* check the frame type to see what kind of special steps are needed */ + if ((tx_desc->pkt_type >= OL_TXRX_MGMT_TYPE_BASE) && + (tx_desc->pkt_type != ol_tx_frm_freed)) { + qdf_dma_addr_t frag_desc_paddr = 0; + +#if defined(HELIUMPLUS) + frag_desc_paddr = tx_desc->htt_frag_desc_paddr; + /* FIX THIS - + * The FW currently has trouble using the host's fragments + * table for management frames. Until this is fixed, + * rather than specifying the fragment table to the FW, + * the host SW will specify just the address of the initial + * fragment. + * Now that the mgmt frame is done, the HTT tx desc's frags + * table pointer needs to be reset. + */ +#if defined(HELIUMPLUS_DEBUG) + qdf_print("%s %d: Frag Descriptor Reset [%d] to 0x%x\n", + __func__, __LINE__, tx_desc->id, + frag_desc_paddr); +#endif /* HELIUMPLUS_DEBUG */ +#endif /* HELIUMPLUS */ + htt_tx_desc_frags_table_set(pdev->htt_pdev, + tx_desc->htt_tx_desc, 0, + frag_desc_paddr, 1); + + mgmt_type = tx_desc->pkt_type - OL_TXRX_MGMT_TYPE_BASE; + /* + * we already checked the value when the mgmt frame was + * provided to the txrx layer. + * no need to check it a 2nd time. + */ + ota_ack_cb = pdev->tx_mgmt.callbacks[mgmt_type].ota_ack_cb; + if (ota_ack_cb) { + void *ctxt; + ctxt = pdev->tx_mgmt.callbacks[mgmt_type].ctxt; + ota_ack_cb(ctxt, tx_desc->netbuf, had_error); + } + /* free the netbuf */ + qdf_nbuf_free(tx_desc->netbuf); + } else if (had_error == htt_tx_status_download_fail) { + /* Failed to send to target */ + + /* This is to decrement skb->users count for TSO segment */ + if (tx_desc->pkt_type == OL_TX_FRM_TSO) + qdf_nbuf_tx_free(tx_desc->netbuf, had_error); + goto free_tx_desc; + } else { + /* single regular frame, called from completion path */ + qdf_nbuf_set_next(tx_desc->netbuf, NULL); + qdf_nbuf_tx_free(tx_desc->netbuf, had_error); + } +free_tx_desc: + /* free the tx desc */ + ol_tx_desc_free(pdev, tx_desc); +} + +#ifdef TSOSEG_DEBUG +static int +ol_tso_seg_dbg_sanitize(struct qdf_tso_seg_elem_t *tsoseg) +{ + int rc = -1; + struct ol_tx_desc_t *txdesc; + + if (tsoseg != NULL) { + txdesc = tsoseg->dbg.txdesc; + if (txdesc->tso_desc != tsoseg) + qdf_tso_seg_dbg_bug("Owner sanity failed"); + else + rc = 0; + } + return rc; + +}; +#else +static int +ol_tso_seg_dbg_sanitize(struct qdf_tso_seg_elem_t *tsoseg) +{ + return 0; +} +#endif /* TSOSEG_DEBUG */ + +#if defined(FEATURE_TSO) +/** + * ol_tso_alloc_segment() - function to allocate a TSO segment + * element + * @pdev: the data physical device sending the data + * + * Allocates a TSO segment element from the free list held in + * the pdev + * + * Return: tso_seg + */ +struct qdf_tso_seg_elem_t *ol_tso_alloc_segment(struct ol_txrx_pdev_t *pdev) +{ + struct qdf_tso_seg_elem_t *tso_seg = NULL; + + qdf_spin_lock_bh(&pdev->tso_seg_pool.tso_mutex); + if (pdev->tso_seg_pool.freelist) { + pdev->tso_seg_pool.num_free--; + tso_seg = pdev->tso_seg_pool.freelist; + if (tso_seg->on_freelist != 1) { + qdf_print("Do not alloc tso seg as this seg is not in freelist\n"); + qdf_spin_unlock_bh(&pdev->tso_seg_pool.tso_mutex); + QDF_BUG(0); + return NULL; + } else if (tso_seg->cookie != TSO_SEG_MAGIC_COOKIE) { + qdf_print("Do not alloc tso seg as cookie is not good\n"); + qdf_spin_unlock_bh(&pdev->tso_seg_pool.tso_mutex); + QDF_BUG(0); + return NULL; + } + /*this tso seg is not a part of freelist now.*/ + tso_seg->on_freelist = 0; + qdf_tso_seg_dbg_record(tso_seg, TSOSEG_LOC_ALLOC); + pdev->tso_seg_pool.freelist = pdev->tso_seg_pool.freelist->next; + } + qdf_spin_unlock_bh(&pdev->tso_seg_pool.tso_mutex); + + return tso_seg; +} + +/** + * ol_tso_free_segment() - function to free a TSO segment + * element + * @pdev: the data physical device sending the data + * @tso_seg: The TSO segment element to be freed + * + * Returns a TSO segment element to the free list held in the + * pdev + * + * Return: none + */ +void ol_tso_free_segment(struct ol_txrx_pdev_t *pdev, + struct qdf_tso_seg_elem_t *tso_seg) +{ + qdf_spin_lock_bh(&pdev->tso_seg_pool.tso_mutex); + if (tso_seg->on_freelist != 0) { + qdf_spin_unlock_bh(&pdev->tso_seg_pool.tso_mutex); + qdf_tso_seg_dbg_bug("Do not free tso seg, already freed"); + return; + } else if (tso_seg->cookie != TSO_SEG_MAGIC_COOKIE) { + qdf_print("Do not free the tso seg as cookie is not good. Looks like memory corruption"); + qdf_spin_unlock_bh(&pdev->tso_seg_pool.tso_mutex); + QDF_BUG(0); + return; + } + /* sanitize before free */ + ol_tso_seg_dbg_sanitize(tso_seg); + /*this tso seg is now a part of freelist*/ + /* retain segment history, if debug is enabled */ + qdf_tso_seg_dbg_zero(tso_seg); + tso_seg->next = pdev->tso_seg_pool.freelist; + tso_seg->on_freelist = 1; + tso_seg->cookie = TSO_SEG_MAGIC_COOKIE; + qdf_tso_seg_dbg_record(tso_seg, TSOSEG_LOC_FREE); + pdev->tso_seg_pool.freelist = tso_seg; + pdev->tso_seg_pool.num_free++; + qdf_spin_unlock_bh(&pdev->tso_seg_pool.tso_mutex); +} + +/** + * ol_tso_num_seg_alloc() - function to allocate a element to count TSO segments + * in a jumbo skb packet. + * @pdev: the data physical device sending the data + * + * Allocates a element to count TSO segments from the free list held in + * the pdev + * + * Return: tso_num_seg + */ +struct qdf_tso_num_seg_elem_t *ol_tso_num_seg_alloc(struct ol_txrx_pdev_t *pdev) +{ + struct qdf_tso_num_seg_elem_t *tso_num_seg = NULL; + + qdf_spin_lock_bh(&pdev->tso_num_seg_pool.tso_num_seg_mutex); + if (pdev->tso_num_seg_pool.freelist) { + pdev->tso_num_seg_pool.num_free--; + tso_num_seg = pdev->tso_num_seg_pool.freelist; + pdev->tso_num_seg_pool.freelist = + pdev->tso_num_seg_pool.freelist->next; + } + qdf_spin_unlock_bh(&pdev->tso_num_seg_pool.tso_num_seg_mutex); + + return tso_num_seg; +} + +/** + * ol_tso_num_seg_free() - function to free a TSO segment + * element + * @pdev: the data physical device sending the data + * @tso_seg: The TSO segment element to be freed + * + * Returns a element to the free list held in the pdev + * + * Return: none + */ +void ol_tso_num_seg_free(struct ol_txrx_pdev_t *pdev, + struct qdf_tso_num_seg_elem_t *tso_num_seg) +{ + qdf_spin_lock_bh(&pdev->tso_num_seg_pool.tso_num_seg_mutex); + tso_num_seg->next = pdev->tso_num_seg_pool.freelist; + pdev->tso_num_seg_pool.freelist = tso_num_seg; + pdev->tso_num_seg_pool.num_free++; + qdf_spin_unlock_bh(&pdev->tso_num_seg_pool.tso_num_seg_mutex); +} +#endif diff --git a/drivers/staging/qcacld-3.0/core/dp/txrx/ol_tx_desc.h b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_tx_desc.h new file mode 100644 index 0000000000000000000000000000000000000000..5cf71326f385a3d332a7e6fccb186bf869d03773 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_tx_desc.h @@ -0,0 +1,465 @@ +/* + * Copyright (c) 2011, 2014-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * @file ol_tx_desc.h + * @brief API definitions for the tx descriptor module within the data SW. + */ +#ifndef _OL_TX_DESC__H_ +#define _OL_TX_DESC__H_ + +#include /* TAILQ_HEAD */ +#include /* qdf_nbuf_t */ +#include /* ol_txrx_vdev_t, etc. */ +#include /*TXRX_ASSERT2 */ +#include + +#define DIV_BY_8 3 +#define DIV_BY_32 5 +#define MOD_BY_8 0x7 +#define MOD_BY_32 0x1F + +struct ol_tx_desc_t * +ol_tx_desc_alloc_wrapper(struct ol_txrx_pdev_t *pdev, + struct ol_txrx_vdev_t *vdev, + struct ol_txrx_msdu_info_t *msdu_info); + + +/** + * @brief Allocate and initialize a tx descriptor for a LL system. + * @details + * Allocate a tx descriptor pair for a new tx frame - a SW tx descriptor + * for private use within the host data SW, and a HTT tx descriptor for + * downloading tx meta-data to the target FW/HW. + * Fill in the fields of this pair of tx descriptors based on the + * information in the netbuf. + * For LL, this includes filling in a fragmentation descriptor to + * specify to the MAC HW where to find the tx frame's fragments. + * + * @param pdev - the data physical device sending the data + * (for accessing the tx desc pool) + * @param vdev - the virtual device sending the data + * (for specifying the transmitter address for multicast / broadcast data) + * @param netbuf - the tx frame + * @param msdu_info - tx meta-data + */ +struct ol_tx_desc_t *ol_tx_desc_ll(struct ol_txrx_pdev_t *pdev, + struct ol_txrx_vdev_t *vdev, + qdf_nbuf_t netbuf, + struct ol_txrx_msdu_info_t *msdu_info); + + +/** + * @brief Allocate and initialize a tx descriptor for a HL system. + * @details + * Allocate a tx descriptor pair for a new tx frame - a SW tx descriptor + * for private use within the host data SW, and a HTT tx descriptor for + * downloading tx meta-data to the target FW/HW. + * Fill in the fields of this pair of tx descriptors based on the + * information in the netbuf. + * + * @param pdev - the data physical device sending the data + * (for accessing the tx desc pool) + * @param vdev - the virtual device sending the data + * (for specifying the transmitter address for multicast / broadcast data) + * @param netbuf - the tx frame + * @param msdu_info - tx meta-data + */ +struct ol_tx_desc_t * +ol_tx_desc_hl( + struct ol_txrx_pdev_t *pdev, + struct ol_txrx_vdev_t *vdev, + qdf_nbuf_t netbuf, + struct ol_txrx_msdu_info_t *msdu_info); + + +/** + * @brief Use a tx descriptor ID to find the corresponding desriptor object. + * + * @param pdev - the data physical device sending the data + * @param tx_desc_id - the ID of the descriptor in question + * @return the descriptor object that has the specified ID + */ +static inline struct ol_tx_desc_t *ol_tx_desc_find( + struct ol_txrx_pdev_t *pdev, uint16_t tx_desc_id) +{ + void **td_base = (void **)pdev->tx_desc.desc_pages.cacheable_pages; + + return &((union ol_tx_desc_list_elem_t *) + (td_base[tx_desc_id >> pdev->tx_desc.page_divider] + + (pdev->tx_desc.desc_reserved_size * + (tx_desc_id & pdev->tx_desc.offset_filter))))->tx_desc; +} + +/** + * @brief Use a tx descriptor ID to find the corresponding desriptor object + * and add sanity check. + * + * @param pdev - the data physical device sending the data + * @param tx_desc_id - the ID of the descriptor in question + * @return the descriptor object that has the specified ID, + * if failure, will return NULL. + */ + +#ifdef QCA_SUPPORT_TXDESC_SANITY_CHECKS +static inline struct ol_tx_desc_t * +ol_tx_desc_find_check(struct ol_txrx_pdev_t *pdev, u_int16_t tx_desc_id) +{ + struct ol_tx_desc_t *tx_desc; + + tx_desc = ol_tx_desc_find(pdev, tx_desc_id); + + if (tx_desc->pkt_type == ol_tx_frm_freed) { + return NULL; + } + + return tx_desc; +} + +#else + +static inline struct ol_tx_desc_t * +ol_tx_desc_find_check(struct ol_txrx_pdev_t *pdev, u_int16_t tx_desc_id) +{ + return ol_tx_desc_find(pdev, tx_desc_id); +} +#endif + +/** + * @brief Free a list of tx descriptors and the tx frames they refer to. + * @details + * Free a batch of "standard" tx descriptors and their tx frames. + * Free each tx descriptor, by returning it to the freelist. + * Unmap each netbuf, and free the netbufs as a batch. + * Irregular tx frames like TSO or managment frames that require + * special handling are processed by the ol_tx_desc_frame_free_nonstd + * function rather than this function. + * + * @param pdev - the data physical device that sent the data + * @param tx_descs - a list of SW tx descriptors for the tx frames + * @param had_error - bool indication of whether the transmission failed. + * This is provided to callback functions that get notified of + * the tx frame completion. + */ +void ol_tx_desc_frame_list_free(struct ol_txrx_pdev_t *pdev, + ol_tx_desc_list *tx_descs, int had_error); + +/** + * @brief Free a non-standard tx frame and its tx descriptor. + * @details + * Check the tx frame type (e.g. TSO vs. management) to determine what + * special steps, if any, need to be performed prior to freeing the + * tx frame and its tx descriptor. + * This function can also be used to free single standard tx frames. + * After performing any special steps based on tx frame type, free the + * tx descriptor, i.e. return it to the freelist, and unmap and + * free the netbuf referenced by the tx descriptor. + * + * @param pdev - the data physical device that sent the data + * @param tx_desc - the SW tx descriptor for the tx frame that was sent + * @param had_error - bool indication of whether the transmission failed. + * This is provided to callback functions that get notified of + * the tx frame completion. + */ +void ol_tx_desc_frame_free_nonstd(struct ol_txrx_pdev_t *pdev, + struct ol_tx_desc_t *tx_desc, int had_error); + +/* + * @brief Determine the ID of a tx descriptor. + * + * @param pdev - the physical device that is sending the data + * @param tx_desc - the descriptor whose ID is being determined + * @return numeric ID that uniquely identifies the tx descriptor + */ +static inline uint16_t +ol_tx_desc_id(struct ol_txrx_pdev_t *pdev, struct ol_tx_desc_t *tx_desc) +{ + TXRX_ASSERT2(tx_desc->id < pdev->tx_desc.pool_size); + return tx_desc->id; +} + +/* + * @brief Retrieves the beacon headr for the vdev + * @param pdev - opaque pointe to scn + * @param vdevid - vdev id + * @return void pointer to the beacon header for the given vdev + */ + +void *ol_ath_get_bcn_header(ol_pdev_handle pdev, A_UINT32 vdev_id); + +/* + * @brief Free a tx descriptor, without freeing the matching frame. + * @details + * This function is using during the function call that submits tx frames + * into the txrx layer, for cases where a tx descriptor is successfully + * allocated, but for other reasons the frame could not be accepted. + * + * @param pdev - the data physical device that is sending the data + * @param tx_desc - the descriptor being freed + */ +void ol_tx_desc_free(struct ol_txrx_pdev_t *pdev, struct ol_tx_desc_t *tx_desc); + +#if defined(FEATURE_TSO) +struct qdf_tso_seg_elem_t *ol_tso_alloc_segment(struct ol_txrx_pdev_t *pdev); + +void ol_tso_free_segment(struct ol_txrx_pdev_t *pdev, + struct qdf_tso_seg_elem_t *tso_seg); +struct qdf_tso_num_seg_elem_t *ol_tso_num_seg_alloc( + struct ol_txrx_pdev_t *pdev); +void ol_tso_num_seg_free(struct ol_txrx_pdev_t *pdev, + struct qdf_tso_num_seg_elem_t *tso_num_seg); +void ol_free_remaining_tso_segs(ol_txrx_vdev_handle vdev, + struct ol_txrx_msdu_info_t *msdu_info, + bool is_tso_seg_mapping_done); + +#else +#define ol_tso_alloc_segment(pdev) /*no-op*/ +#define ol_tso_free_segment(pdev, tso_seg) /*no-op*/ +#define ol_tso_num_seg_alloc(pdev) /*no-op*/ +#define ol_tso_num_seg_free(pdev, tso_num_seg) /*no-op*/ +/*no-op*/ +#define ol_free_remaining_tso_segs(vdev, msdu_info, is_tso_seg_mapping_done) +#endif + +/** + * ol_tx_get_desc_global_pool() - get descriptor from global pool + * @pdev: pdev handler + * + * Caller needs to take lock and do sanity checks. + * + * Return: tx descriptor + */ +static inline +struct ol_tx_desc_t *ol_tx_get_desc_global_pool(struct ol_txrx_pdev_t *pdev) +{ + struct ol_tx_desc_t *tx_desc = &pdev->tx_desc.freelist->tx_desc; + pdev->tx_desc.freelist = pdev->tx_desc.freelist->next; + pdev->tx_desc.num_free--; + return tx_desc; +} + +/** + * ol_tx_put_desc_global_pool() - put descriptor to global pool freelist + * @pdev: pdev handle + * @tx_desc: tx descriptor + * + * Caller needs to take lock and do sanity checks. + * + * Return: none + */ +static inline +void ol_tx_put_desc_global_pool(struct ol_txrx_pdev_t *pdev, + struct ol_tx_desc_t *tx_desc) +{ + ((union ol_tx_desc_list_elem_t *)tx_desc)->next = + pdev->tx_desc.freelist; + pdev->tx_desc.freelist = + (union ol_tx_desc_list_elem_t *)tx_desc; + pdev->tx_desc.num_free++; + return; +} + + +#ifdef QCA_LL_TX_FLOW_CONTROL_V2 +int ol_tx_free_invalid_flow_pool(struct ol_tx_flow_pool_t *pool); +/** + * ol_tx_get_desc_flow_pool() - get descriptor from flow pool + * @pool: flow pool + * + * Caller needs to take lock and do sanity checks. + * + * Return: tx descriptor + */ +static inline +struct ol_tx_desc_t *ol_tx_get_desc_flow_pool(struct ol_tx_flow_pool_t *pool) +{ + struct ol_tx_desc_t *tx_desc = &pool->freelist->tx_desc; + pool->freelist = pool->freelist->next; + pool->avail_desc--; + return tx_desc; +} + +/** + * ol_tx_put_desc_flow_pool() - put descriptor to flow pool freelist + * @pool: flow pool + * @tx_desc: tx descriptor + * + * Caller needs to take lock and do sanity checks. + * + * Return: none + */ +static inline +void ol_tx_put_desc_flow_pool(struct ol_tx_flow_pool_t *pool, + struct ol_tx_desc_t *tx_desc) +{ + tx_desc->pool = pool; + ((union ol_tx_desc_list_elem_t *)tx_desc)->next = pool->freelist; + pool->freelist = (union ol_tx_desc_list_elem_t *)tx_desc; + pool->avail_desc++; + return; +} + +#else +static inline int ol_tx_free_invalid_flow_pool(void *pool) +{ + return 0; +} +#endif + +#ifdef DESC_DUP_DETECT_DEBUG +/** + * ol_tx_desc_dup_detect_init() - initialize descriptor duplication logic + * @pdev: pdev handle + * @pool_size: global pool size + * + * Return: none + */ +static inline +void ol_tx_desc_dup_detect_init(struct ol_txrx_pdev_t *pdev, uint16_t pool_size) +{ + uint16_t size = (pool_size >> DIV_BY_8) + + sizeof(*pdev->tx_desc.free_list_bitmap); + pdev->tx_desc.free_list_bitmap = qdf_mem_malloc(size); + if (!pdev->tx_desc.free_list_bitmap) + qdf_print("%s: malloc failed", __func__); +} + +/** + * ol_tx_desc_dup_detect_deinit() - deinit descriptor duplication logic + * @pdev: pdev handle + * + * Return: none + */ +static inline +void ol_tx_desc_dup_detect_deinit(struct ol_txrx_pdev_t *pdev) +{ + qdf_print("%s: pool_size %d num_free %d\n", __func__, + pdev->tx_desc.pool_size, pdev->tx_desc.num_free); + if (pdev->tx_desc.free_list_bitmap) + qdf_mem_free(pdev->tx_desc.free_list_bitmap); +} + +/** + * ol_tx_desc_dup_detect_set() - set bit for msdu_id + * @pdev: pdev handle + * @tx_desc: tx descriptor + * + * Return: none + */ +static inline +void ol_tx_desc_dup_detect_set(struct ol_txrx_pdev_t *pdev, + struct ol_tx_desc_t *tx_desc) +{ + uint16_t msdu_id = ol_tx_desc_id(pdev, tx_desc); + bool test; + + if (!pdev->tx_desc.free_list_bitmap) + return; + + if (qdf_unlikely(msdu_id > pdev->tx_desc.pool_size)) { + qdf_print("%s: msdu_id %d > pool_size %d", + __func__, msdu_id, pdev->tx_desc.pool_size); + QDF_BUG(0); + } + + test = test_and_set_bit(msdu_id, pdev->tx_desc.free_list_bitmap); + if (qdf_unlikely(test)) { + uint16_t size = (pdev->tx_desc.pool_size >> DIV_BY_8) + + ((pdev->tx_desc.pool_size & MOD_BY_8) ? 1 : 0); + qdf_print("duplicate msdu_id %d detected !!\n", msdu_id); + qdf_trace_hex_dump(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + (void *)pdev->tx_desc.free_list_bitmap, size); + QDF_BUG(0); + } +} + +/** + * ol_tx_desc_dup_detect_reset() - reset bit for msdu_id + * @pdev: pdev handle + * @tx_desc: tx descriptor + * + * Return: none + */ +static inline +void ol_tx_desc_dup_detect_reset(struct ol_txrx_pdev_t *pdev, + struct ol_tx_desc_t *tx_desc) +{ + uint16_t msdu_id = ol_tx_desc_id(pdev, tx_desc); + bool test; + + if (!pdev->tx_desc.free_list_bitmap) + return; + + if (qdf_unlikely(msdu_id > pdev->tx_desc.pool_size)) { + qdf_print("%s: msdu_id %d > pool_size %d", + __func__, msdu_id, pdev->tx_desc.pool_size); + QDF_BUG(0); + } + + test = !test_and_clear_bit(msdu_id, pdev->tx_desc.free_list_bitmap); + if (qdf_unlikely(test)) { + uint16_t size = (pdev->tx_desc.pool_size >> DIV_BY_8) + + ((pdev->tx_desc.pool_size & MOD_BY_8) ? 1 : 0); + qdf_print("duplicate free msg received for msdu_id %d!!\n", + msdu_id); + qdf_trace_hex_dump(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + (void *)pdev->tx_desc.free_list_bitmap, size); + QDF_BUG(0); + } +} +#else +static inline +void ol_tx_desc_dup_detect_init(struct ol_txrx_pdev_t *pdev, uint16_t size) +{ +} + +static inline +void ol_tx_desc_dup_detect_deinit(struct ol_txrx_pdev_t *pdev) +{ +} + +static inline +void ol_tx_desc_dup_detect_set(struct ol_txrx_pdev_t *pdev, + struct ol_tx_desc_t *tx_desc) +{ +} + +static inline +void ol_tx_desc_dup_detect_reset(struct ol_txrx_pdev_t *pdev, + struct ol_tx_desc_t *tx_desc) +{ +} +#endif + +enum extension_header_type +ol_tx_get_ext_header_type(struct ol_txrx_vdev_t *vdev, + qdf_nbuf_t netbuf); +enum extension_header_type +ol_tx_get_wisa_ext_type(qdf_nbuf_t netbuf); + + +#endif /* _OL_TX_DESC__H_ */ diff --git a/drivers/staging/qcacld-3.0/core/dp/txrx/ol_tx_queue.c b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_tx_queue.c new file mode 100644 index 0000000000000000000000000000000000000000..f72fe878941f286cb3689a3221522cfb7c7e50fc --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_tx_queue.c @@ -0,0 +1,2305 @@ +/* + * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#include /* qdf_nbuf_t, etc. */ +#include /* qdf_atomic_read, etc. */ +#include /* ol_cfg_addba_retry */ +#include /* HTT_TX_EXT_TID_MGMT */ +#include /* htt_tx_desc_tid */ +#include /* ol_txrx_vdev_handle */ +#include /* ol_txrx_sync, ol_tx_addba_conf */ +#include +#include /* ol_ctrl_addba_req */ +#include /* TXRX_ASSERT1, etc. */ +#include /* ol_tx_desc, ol_tx_desc_frame_list_free */ +#include /* ol_tx_vdev_ll_pause_queue_send */ +#include /* ol_tx_sched_notify, etc. */ +#include +#include /* ol_tx_desc_pool_size_hl */ +#include /* ENABLE_TX_QUEUE_LOG */ +#include /* bool */ +#include "cdp_txrx_flow_ctrl_legacy.h" +#include + +#if defined(CONFIG_HL_SUPPORT) + +#ifndef offsetof +#define offsetof(type, field) ((qdf_size_t)(&((type *)0)->field)) +#endif + +/*--- function prototypes for optional host ADDBA negotiation ---------------*/ + +#define OL_TX_QUEUE_ADDBA_CHECK(pdev, txq, tx_msdu_info) /* no-op */ + +#ifndef container_of +#define container_of(ptr, type, member) ((type *)( \ + (char *)(ptr) - (char *)(&((type *)0)->member))) +#endif +/*--- function definitions --------------------------------------------------*/ + +/** + * ol_tx_queue_vdev_flush() - try to flush pending frames in the tx queues + * no matter it's queued in the TX scheduler or not + * @pdev: the physical device object + * @vdev: the virtual device object + * + * Return: None + */ +static void +ol_tx_queue_vdev_flush(struct ol_txrx_pdev_t *pdev, struct ol_txrx_vdev_t *vdev) +{ +#define PEER_ARRAY_COUNT 10 + struct ol_tx_frms_queue_t *txq; + struct ol_txrx_peer_t *peer, *peers[PEER_ARRAY_COUNT]; + int i, j, peer_count; + + /* flush VDEV TX queues */ + for (i = 0; i < OL_TX_VDEV_NUM_QUEUES; i++) { + txq = &vdev->txqs[i]; + /* + * currently txqs of MCAST_BCAST/DEFAULT_MGMT packet are using + * tid HTT_TX_EXT_TID_NON_QOS_MCAST_BCAST/HTT_TX_EXT_TID_MGMT + * when inserted into scheduler, so use same tid when we flush + * them + */ + if (i == OL_TX_VDEV_MCAST_BCAST) + ol_tx_queue_free(pdev, + txq, + HTT_TX_EXT_TID_NON_QOS_MCAST_BCAST, + false); + else if (i == OL_TX_VDEV_DEFAULT_MGMT) + ol_tx_queue_free(pdev, + txq, + HTT_TX_EXT_TID_MGMT, + false); + else + ol_tx_queue_free(pdev, + txq, + (i + OL_TX_NUM_TIDS), + false); + } + /* flush PEER TX queues */ + do { + peer_count = 0; + /* select candidate peers */ + qdf_spin_lock_bh(&pdev->peer_ref_mutex); + TAILQ_FOREACH(peer, &vdev->peer_list, peer_list_elem) { + for (i = 0; i < OL_TX_NUM_TIDS; i++) { + txq = &peer->txqs[i]; + if (txq->frms) { + OL_TXRX_PEER_INC_REF_CNT(peer); + peers[peer_count++] = peer; + break; + } + } + if (peer_count >= PEER_ARRAY_COUNT) + break; + } + qdf_spin_unlock_bh(&pdev->peer_ref_mutex); + /* flush TX queues of candidate peers */ + for (i = 0; i < peer_count; i++) { + for (j = 0; j < OL_TX_NUM_TIDS; j++) { + txq = &peers[i]->txqs[j]; + if (txq->frms) + ol_tx_queue_free(pdev, txq, j, true); + } + OL_TXRX_PEER_UNREF_DELETE(peers[i]); + } + } while (peer_count >= PEER_ARRAY_COUNT); +} + +/** + * ol_tx_queue_flush() - try to flush pending frames in the tx queues + * no matter it's queued in the TX scheduler or not + * @pdev: the physical device object + * + * Return: None + */ +static inline void +ol_tx_queue_flush(struct ol_txrx_pdev_t *pdev) +{ + struct ol_txrx_vdev_t *vdev; + + TAILQ_FOREACH(vdev, &pdev->vdev_list, vdev_list_elem) { + ol_tx_queue_vdev_flush(pdev, vdev); + } +} + +void +ol_tx_queue_discard( + struct ol_txrx_pdev_t *pdev, + bool flush_all, + ol_tx_desc_list *tx_descs) +{ + u_int16_t num; + u_int16_t discarded, actual_discarded = 0; + + qdf_spin_lock_bh(&pdev->tx_queue_spinlock); + + if (flush_all == true) + /* flush all the pending tx queues in the scheduler */ + num = ol_tx_desc_pool_size_hl(pdev->ctrl_pdev) - + qdf_atomic_read(&pdev->tx_queue.rsrc_cnt); + else + num = pdev->tx_queue.rsrc_threshold_hi - + pdev->tx_queue.rsrc_threshold_lo; + + TX_SCHED_DEBUG_PRINT("+%s : %u\n,", __func__, + qdf_atomic_read(&pdev->tx_queue.rsrc_cnt)); + while (num > 0) { + discarded = ol_tx_sched_discard_select( + pdev, (u_int16_t)num, tx_descs, flush_all); + if (discarded == 0) + /* + * No more packets could be discarded. + * Probably tx queues are empty. + */ + break; + + num -= discarded; + actual_discarded += discarded; + } + qdf_atomic_add(actual_discarded, &pdev->tx_queue.rsrc_cnt); + TX_SCHED_DEBUG_PRINT("-%s\n", __func__); + + qdf_spin_unlock_bh(&pdev->tx_queue_spinlock); + + if (flush_all == true && num > 0) + /* + * try to flush pending frames in the tx queues + * which are not queued in the TX scheduler. + */ + ol_tx_queue_flush(pdev); +} + +#ifdef CONFIG_PER_VDEV_TX_DESC_POOL + +/** + * is_ol_tx_discard_frames_success() - check whether currently queued tx frames + * can be discarded or not + * @pdev: the physical device object + * @tx_desc: tx desciptor ptr + * + * Return: Success if available tx descriptors are too few + */ +static bool +is_ol_tx_discard_frames_success(struct ol_txrx_pdev_t *pdev, + struct ol_tx_desc_t *tx_desc) +{ + ol_txrx_vdev_handle vdev; + vdev = tx_desc->vdev; + return qdf_atomic_read(&vdev->tx_desc_count) > + ((ol_tx_desc_pool_size_hl(pdev->ctrl_pdev) >> 1) + - TXRX_HL_TX_FLOW_CTRL_MGMT_RESERVED); +} +#else + +static inline bool +is_ol_tx_discard_frames_success(struct ol_txrx_pdev_t *pdev, + struct ol_tx_desc_t *tx_desc) +{ + return qdf_atomic_read(&pdev->tx_queue.rsrc_cnt) <= + pdev->tx_queue.rsrc_threshold_lo; +} +#endif + +void +ol_tx_enqueue( + struct ol_txrx_pdev_t *pdev, + struct ol_tx_frms_queue_t *txq, + struct ol_tx_desc_t *tx_desc, + struct ol_txrx_msdu_info_t *tx_msdu_info) +{ + int bytes; + struct ol_tx_sched_notify_ctx_t notify_ctx; + + TX_SCHED_DEBUG_PRINT("Enter %s\n", __func__); + + /* + * If too few tx descriptors are available, drop some currently-queued + * tx frames, to provide enough tx descriptors for new frames, which + * may be higher priority than the current frames. + */ + if (is_ol_tx_discard_frames_success(pdev, tx_desc)) { + ol_tx_desc_list tx_descs; + TAILQ_INIT(&tx_descs); + ol_tx_queue_discard(pdev, false, &tx_descs); + /*Discard Frames in Discard List*/ + ol_tx_desc_frame_list_free(pdev, &tx_descs, 1 /* error */); + } + + qdf_spin_lock_bh(&pdev->tx_queue_spinlock); + TAILQ_INSERT_TAIL(&txq->head, tx_desc, tx_desc_list_elem); + + bytes = qdf_nbuf_len(tx_desc->netbuf); + txq->frms++; + txq->bytes += bytes; + ol_tx_queue_log_enqueue(pdev, tx_msdu_info, 1, bytes); + + if (txq->flag != ol_tx_queue_paused) { + notify_ctx.event = OL_TX_ENQUEUE_FRAME; + notify_ctx.frames = 1; + notify_ctx.bytes = qdf_nbuf_len(tx_desc->netbuf); + notify_ctx.txq = txq; + notify_ctx.info.tx_msdu_info = tx_msdu_info; + ol_tx_sched_notify(pdev, ¬ify_ctx); + txq->flag = ol_tx_queue_active; + } + + if (!ETHERTYPE_IS_EAPOL_WAPI(tx_msdu_info->htt.info.ethertype)) + OL_TX_QUEUE_ADDBA_CHECK(pdev, txq, tx_msdu_info); + + qdf_spin_unlock_bh(&pdev->tx_queue_spinlock); + TX_SCHED_DEBUG_PRINT("Leave %s\n", __func__); +} + +u_int16_t +ol_tx_dequeue( + struct ol_txrx_pdev_t *pdev, + struct ol_tx_frms_queue_t *txq, + ol_tx_desc_list *head, + u_int16_t max_frames, + u_int32_t *credit, + int *bytes) +{ + u_int16_t num_frames; + int bytes_sum; + unsigned credit_sum; + + TXRX_ASSERT2(txq->flag != ol_tx_queue_paused); + TX_SCHED_DEBUG_PRINT("Enter %s\n", __func__); + + if (txq->frms < max_frames) + max_frames = txq->frms; + + bytes_sum = 0; + credit_sum = 0; + for (num_frames = 0; num_frames < max_frames; num_frames++) { + unsigned frame_credit; + struct ol_tx_desc_t *tx_desc; + tx_desc = TAILQ_FIRST(&txq->head); + + frame_credit = htt_tx_msdu_credit(tx_desc->netbuf); + if (credit_sum + frame_credit > *credit) + break; + + credit_sum += frame_credit; + bytes_sum += qdf_nbuf_len(tx_desc->netbuf); + TAILQ_REMOVE(&txq->head, tx_desc, tx_desc_list_elem); + TAILQ_INSERT_TAIL(head, tx_desc, tx_desc_list_elem); + } + txq->frms -= num_frames; + txq->bytes -= bytes_sum; + /* a paused queue remains paused, regardless of whether it has frames */ + if (txq->frms == 0 && txq->flag == ol_tx_queue_active) + txq->flag = ol_tx_queue_empty; + + ol_tx_queue_log_dequeue(pdev, txq, num_frames, bytes_sum); + TX_SCHED_DEBUG_PRINT("Leave %s\n", __func__); + + *bytes = bytes_sum; + *credit = credit_sum; + return num_frames; +} + +void +ol_tx_queue_free( + struct ol_txrx_pdev_t *pdev, + struct ol_tx_frms_queue_t *txq, + int tid, bool is_peer_txq) +{ + int frms = 0, bytes = 0; + struct ol_tx_desc_t *tx_desc; + struct ol_tx_sched_notify_ctx_t notify_ctx; + ol_tx_desc_list tx_tmp_list; + + TAILQ_INIT(&tx_tmp_list); + TX_SCHED_DEBUG_PRINT("Enter %s\n", __func__); + qdf_spin_lock_bh(&pdev->tx_queue_spinlock); + + notify_ctx.event = OL_TX_DELETE_QUEUE; + notify_ctx.txq = txq; + notify_ctx.info.ext_tid = tid; + ol_tx_sched_notify(pdev, ¬ify_ctx); + + frms = txq->frms; + tx_desc = TAILQ_FIRST(&txq->head); + while (txq->frms) { + bytes += qdf_nbuf_len(tx_desc->netbuf); + txq->frms--; + tx_desc = TAILQ_NEXT(tx_desc, tx_desc_list_elem); + } + ol_tx_queue_log_free(pdev, txq, tid, frms, bytes, is_peer_txq); + txq->bytes -= bytes; + ol_tx_queue_log_free(pdev, txq, tid, frms, bytes, is_peer_txq); + txq->flag = ol_tx_queue_empty; + /* txq->head gets reset during the TAILQ_CONCAT call */ + TAILQ_CONCAT(&tx_tmp_list, &txq->head, tx_desc_list_elem); + + qdf_spin_unlock_bh(&pdev->tx_queue_spinlock); + /* free tx frames without holding tx_queue_spinlock */ + qdf_atomic_add(frms, &pdev->tx_queue.rsrc_cnt); + while (frms) { + tx_desc = TAILQ_FIRST(&tx_tmp_list); + TAILQ_REMOVE(&tx_tmp_list, tx_desc, tx_desc_list_elem); + ol_tx_desc_frame_free_nonstd(pdev, tx_desc, 0); + frms--; + } + TX_SCHED_DEBUG_PRINT("Leave %s\n", __func__); +} + + +/*--- queue pause / unpause functions ---------------------------------------*/ + +/** + * ol_txrx_peer_tid_pause_base() - suspend/pause txq for a given tid given peer + * @pdev: the physical device object + * @peer: peer device object + * @tid: tid for which queue needs to be paused + * + * Return: None + */ +static void +ol_txrx_peer_tid_pause_base( + struct ol_txrx_pdev_t *pdev, + struct ol_txrx_peer_t *peer, + int tid) +{ + struct ol_tx_frms_queue_t *txq = &peer->txqs[tid]; + + if (txq->paused_count.total++ == 0) { + struct ol_tx_sched_notify_ctx_t notify_ctx; + + notify_ctx.event = OL_TX_PAUSE_QUEUE; + notify_ctx.txq = txq; + notify_ctx.info.ext_tid = tid; + ol_tx_sched_notify(pdev, ¬ify_ctx); + txq->flag = ol_tx_queue_paused; + } +} +#ifdef QCA_BAD_PEER_TX_FLOW_CL + +/** + * ol_txrx_peer_pause_but_no_mgmt_q_base() - suspend/pause all txqs except + * management queue for a given peer + * @pdev: the physical device object + * @peer: peer device object + * + * Return: None + */ +static void +ol_txrx_peer_pause_but_no_mgmt_q_base( + struct ol_txrx_pdev_t *pdev, + struct ol_txrx_peer_t *peer) +{ + int i; + for (i = 0; i < OL_TX_MGMT_TID; i++) + ol_txrx_peer_tid_pause_base(pdev, peer, i); +} +#endif + + +/** + * ol_txrx_peer_pause_base() - suspend/pause all txqs for a given peer + * @pdev: the physical device object + * @peer: peer device object + * + * Return: None + */ +static void +ol_txrx_peer_pause_base( + struct ol_txrx_pdev_t *pdev, + struct ol_txrx_peer_t *peer) +{ + int i; + for (i = 0; i < QDF_ARRAY_SIZE(peer->txqs); i++) + ol_txrx_peer_tid_pause_base(pdev, peer, i); +} + +/** + * ol_txrx_peer_tid_unpause_base() - unpause txq for a given tid given peer + * @pdev: the physical device object + * @peer: peer device object + * @tid: tid for which queue needs to be unpaused + * + * Return: None + */ +static void +ol_txrx_peer_tid_unpause_base( + struct ol_txrx_pdev_t *pdev, + struct ol_txrx_peer_t *peer, + int tid) +{ + struct ol_tx_frms_queue_t *txq = &peer->txqs[tid]; + /* + * Don't actually unpause the tx queue until all pause requests + * have been removed. + */ + TXRX_ASSERT2(txq->paused_count.total > 0); + /* return, if not already paused */ + if (txq->paused_count.total == 0) + return; + + if (--txq->paused_count.total == 0) { + struct ol_tx_sched_notify_ctx_t notify_ctx; + + notify_ctx.event = OL_TX_UNPAUSE_QUEUE; + notify_ctx.txq = txq; + notify_ctx.info.ext_tid = tid; + ol_tx_sched_notify(pdev, ¬ify_ctx); + + if (txq->frms == 0) { + txq->flag = ol_tx_queue_empty; + } else { + txq->flag = ol_tx_queue_active; + /* + * Now that the are new tx frames available to download, + * invoke the scheduling function, to see if it wants to + * download the new frames. + * Since the queue lock is currently held, and since + * the scheduler function takes the lock, temporarily + * release the lock. + */ + qdf_spin_unlock_bh(&pdev->tx_queue_spinlock); + ol_tx_sched(pdev); + qdf_spin_lock_bh(&pdev->tx_queue_spinlock); + } + } +} +#ifdef QCA_BAD_PEER_TX_FLOW_CL +/** + * ol_txrx_peer_unpause_but_no_mgmt_q_base() - unpause all txqs except + * management queue for a given peer + * @pdev: the physical device object + * @peer: peer device object + * + * Return: None + */ +static void +ol_txrx_peer_unpause_but_no_mgmt_q_base( + struct ol_txrx_pdev_t *pdev, + struct ol_txrx_peer_t *peer) +{ + int i; + for (i = 0; i < OL_TX_MGMT_TID; i++) + ol_txrx_peer_tid_unpause_base(pdev, peer, i); +} +#endif + +void +ol_txrx_peer_tid_unpause(ol_txrx_peer_handle peer, int tid) +{ + struct ol_txrx_pdev_t *pdev = peer->vdev->pdev; + + /* TO DO: log the queue unpause */ + + /* acquire the mutex lock, since we'll be modifying the queues */ + TX_SCHED_DEBUG_PRINT("Enter %s\n", __func__); + qdf_spin_lock_bh(&pdev->tx_queue_spinlock); + + if (tid == -1) { + int i; + for (i = 0; i < QDF_ARRAY_SIZE(peer->txqs); i++) + ol_txrx_peer_tid_unpause_base(pdev, peer, i); + + } else { + ol_txrx_peer_tid_unpause_base(pdev, peer, tid); + } + + qdf_spin_unlock_bh(&pdev->tx_queue_spinlock); + TX_SCHED_DEBUG_PRINT("Leave %s\n", __func__); +} + +void +ol_txrx_throttle_pause(ol_txrx_pdev_handle pdev) +{ +#if defined(QCA_SUPPORT_TX_THROTTLE) + qdf_spin_lock_bh(&pdev->tx_throttle.mutex); + + if (pdev->tx_throttle.is_paused == true) { + qdf_spin_unlock_bh(&pdev->tx_throttle.mutex); + return; + } + + pdev->tx_throttle.is_paused = true; + qdf_spin_unlock_bh(&pdev->tx_throttle.mutex); +#endif + ol_txrx_pdev_pause(pdev, 0); +} + +void +ol_txrx_throttle_unpause(ol_txrx_pdev_handle pdev) +{ +#if defined(QCA_SUPPORT_TX_THROTTLE) + qdf_spin_lock_bh(&pdev->tx_throttle.mutex); + + if (pdev->tx_throttle.is_paused == false) { + qdf_spin_unlock_bh(&pdev->tx_throttle.mutex); + return; + } + + pdev->tx_throttle.is_paused = false; + qdf_spin_unlock_bh(&pdev->tx_throttle.mutex); +#endif + ol_txrx_pdev_unpause(pdev, 0); +} + +void +ol_txrx_vdev_pause(ol_txrx_vdev_handle vdev, uint32_t reason) +{ + struct ol_txrx_pdev_t *pdev = vdev->pdev; + struct ol_txrx_peer_t *peer; + /* TO DO: log the queue pause */ + /* acquire the mutex lock, since we'll be modifying the queues */ + TX_SCHED_DEBUG_PRINT("Enter %s\n", __func__); + + + /* use peer_ref_mutex before accessing peer_list */ + qdf_spin_lock_bh(&pdev->peer_ref_mutex); + qdf_spin_lock_bh(&pdev->tx_queue_spinlock); + TAILQ_FOREACH(peer, &vdev->peer_list, peer_list_elem) { + ol_txrx_peer_pause_base(pdev, peer); + } + qdf_spin_unlock_bh(&pdev->tx_queue_spinlock); + qdf_spin_unlock_bh(&pdev->peer_ref_mutex); + + TX_SCHED_DEBUG_PRINT("Leave %s\n", __func__); +} + + +void ol_txrx_vdev_unpause(ol_txrx_vdev_handle vdev, uint32_t reason) +{ + struct ol_txrx_pdev_t *pdev = vdev->pdev; + struct ol_txrx_peer_t *peer; + /* TO DO: log the queue unpause */ + /* acquire the mutex lock, since we'll be modifying the queues */ + TX_SCHED_DEBUG_PRINT("Enter %s\n", __func__); + + + + /* take peer_ref_mutex before accessing peer_list */ + qdf_spin_lock_bh(&pdev->peer_ref_mutex); + qdf_spin_lock_bh(&pdev->tx_queue_spinlock); + + TAILQ_FOREACH(peer, &vdev->peer_list, peer_list_elem) { + int i; + for (i = 0; i < QDF_ARRAY_SIZE(peer->txqs); i++) + ol_txrx_peer_tid_unpause_base(pdev, peer, i); + } + qdf_spin_unlock_bh(&pdev->tx_queue_spinlock); + qdf_spin_unlock_bh(&pdev->peer_ref_mutex); + + TX_SCHED_DEBUG_PRINT("Leave %s\n", __func__); +} + +void ol_txrx_vdev_flush(ol_txrx_vdev_handle vdev) +{ + ol_tx_queue_vdev_flush(vdev->pdev, vdev); +} + +#ifdef QCA_BAD_PEER_TX_FLOW_CL + +/** + * ol_txrx_peer_bal_add_limit_peer() - add one peer into limit list + * @pdev: Pointer to PDEV structure. + * @peer_id: Peer Identifier. + * @peer_limit Peer limit threshold + * + * Add one peer into the limit list of pdev + * Note that the peer limit info will be also updated + * If it is the first time, start the timer + * + * Return: None + */ +void +ol_txrx_peer_bal_add_limit_peer(struct ol_txrx_pdev_t *pdev, + u_int16_t peer_id, u_int16_t peer_limit) +{ + u_int16_t i, existed = 0; + struct ol_txrx_peer_t *peer = NULL; + + for (i = 0; i < pdev->tx_peer_bal.peer_num; i++) { + if (pdev->tx_peer_bal.limit_list[i].peer_id == peer_id) { + existed = 1; + break; + } + } + + if (!existed) { + u_int32_t peer_num = pdev->tx_peer_bal.peer_num; + /* Check if peer_num has reached the capabilit */ + if (peer_num >= MAX_NO_PEERS_IN_LIMIT) { + TX_SCHED_DEBUG_PRINT_ALWAYS( + "reach the maxinum peer num %d\n", + peer_num); + return; + } + pdev->tx_peer_bal.limit_list[peer_num].peer_id = peer_id; + pdev->tx_peer_bal.limit_list[peer_num].limit_flag = true; + pdev->tx_peer_bal.limit_list[peer_num].limit = peer_limit; + pdev->tx_peer_bal.peer_num++; + + peer = ol_txrx_peer_find_by_id(pdev, peer_id); + if (peer) { + peer->tx_limit_flag = true; + peer->tx_limit = peer_limit; + } + + TX_SCHED_DEBUG_PRINT_ALWAYS( + "Add one peer into limit queue, peer_id %d, cur peer num %d\n", + peer_id, + pdev->tx_peer_bal.peer_num); + } + + /* Only start the timer once */ + if (pdev->tx_peer_bal.peer_bal_timer_state == + ol_tx_peer_bal_timer_inactive) { + qdf_timer_start(&pdev->tx_peer_bal.peer_bal_timer, + pdev->tx_peer_bal.peer_bal_period_ms); + pdev->tx_peer_bal.peer_bal_timer_state = + ol_tx_peer_bal_timer_active; + } +} + +/** + * ol_txrx_peer_bal_remove_limit_peer() - remove one peer from limit list + * @pdev: Pointer to PDEV structure. + * @peer_id: Peer Identifier. + * + * Remove one peer from the limit list of pdev + * Note that Only stop the timer if no peer in limit state + * + * Return: NULL + */ +void +ol_txrx_peer_bal_remove_limit_peer(struct ol_txrx_pdev_t *pdev, + u_int16_t peer_id) +{ + u_int16_t i; + struct ol_txrx_peer_t *peer = NULL; + + for (i = 0; i < pdev->tx_peer_bal.peer_num; i++) { + if (pdev->tx_peer_bal.limit_list[i].peer_id == peer_id) { + pdev->tx_peer_bal.limit_list[i] = + pdev->tx_peer_bal.limit_list[ + pdev->tx_peer_bal.peer_num - 1]; + pdev->tx_peer_bal.peer_num--; + + peer = ol_txrx_peer_find_by_id(pdev, peer_id); + if (peer) + peer->tx_limit_flag = false; + + + TX_SCHED_DEBUG_PRINT( + "Remove one peer from limitq, peer_id %d, cur peer num %d\n", + peer_id, + pdev->tx_peer_bal.peer_num); + break; + } + } + + /* Only stop the timer if no peer in limit state */ + if (pdev->tx_peer_bal.peer_num == 0) { + qdf_timer_stop(&pdev->tx_peer_bal.peer_bal_timer); + pdev->tx_peer_bal.peer_bal_timer_state = + ol_tx_peer_bal_timer_inactive; + } +} + +void +ol_txrx_peer_pause_but_no_mgmt_q(ol_txrx_peer_handle peer) +{ + struct ol_txrx_pdev_t *pdev = peer->vdev->pdev; + + /* TO DO: log the queue pause */ + + /* acquire the mutex lock, since we'll be modifying the queues */ + TX_SCHED_DEBUG_PRINT("Enter %s\n", __func__); + qdf_spin_lock_bh(&pdev->tx_queue_spinlock); + + ol_txrx_peer_pause_but_no_mgmt_q_base(pdev, peer); + + qdf_spin_unlock_bh(&pdev->tx_queue_spinlock); + TX_SCHED_DEBUG_PRINT("Leave %s\n", __func__); +} + +void +ol_txrx_peer_unpause_but_no_mgmt_q(ol_txrx_peer_handle peer) +{ + struct ol_txrx_pdev_t *pdev = peer->vdev->pdev; + + /* TO DO: log the queue pause */ + + /* acquire the mutex lock, since we'll be modifying the queues */ + TX_SCHED_DEBUG_PRINT("Enter %s\n", __func__); + qdf_spin_lock_bh(&pdev->tx_queue_spinlock); + + ol_txrx_peer_unpause_but_no_mgmt_q_base(pdev, peer); + + qdf_spin_unlock_bh(&pdev->tx_queue_spinlock); + TX_SCHED_DEBUG_PRINT("Leave %s\n", __func__); +} + +u_int16_t +ol_tx_bad_peer_dequeue_check(struct ol_tx_frms_queue_t *txq, + u_int16_t max_frames, + u_int16_t *tx_limit_flag) +{ + if (txq && (txq->peer) && (txq->peer->tx_limit_flag) && + (txq->peer->tx_limit < max_frames)) { + TX_SCHED_DEBUG_PRINT( + "Peer ID %d goes to limit, threshold is %d\n", + txq->peer->peer_ids[0], txq->peer->tx_limit); + *tx_limit_flag = 1; + return txq->peer->tx_limit; + } else { + return max_frames; + } +} + +void +ol_tx_bad_peer_update_tx_limit(struct ol_txrx_pdev_t *pdev, + struct ol_tx_frms_queue_t *txq, + u_int16_t frames, + u_int16_t tx_limit_flag) +{ + qdf_spin_lock_bh(&pdev->tx_peer_bal.mutex); + if (txq && tx_limit_flag && (txq->peer) && + (txq->peer->tx_limit_flag)) { + if (txq->peer->tx_limit < frames) + txq->peer->tx_limit = 0; + else + txq->peer->tx_limit -= frames; + + TX_SCHED_DEBUG_PRINT_ALWAYS( + "Peer ID %d in limit, deque %d frms\n", + txq->peer->peer_ids[0], frames); + } else if (txq->peer) { + TX_SCHED_DEBUG_PRINT("Download peer_id %d, num_frames %d\n", + txq->peer->peer_ids[0], frames); + } + qdf_spin_unlock_bh(&pdev->tx_peer_bal.mutex); +} + +void +ol_txrx_bad_peer_txctl_set_setting(struct ol_txrx_pdev_t *pdev, + int enable, int period, int txq_limit) +{ + if (enable) + pdev->tx_peer_bal.enabled = ol_tx_peer_bal_enable; + else + pdev->tx_peer_bal.enabled = ol_tx_peer_bal_disable; + + /* Set the current settingl */ + pdev->tx_peer_bal.peer_bal_period_ms = period; + pdev->tx_peer_bal.peer_bal_txq_limit = txq_limit; +} + +void +ol_txrx_bad_peer_txctl_update_threshold(struct ol_txrx_pdev_t *pdev, + int level, int tput_thresh, + int tx_limit) +{ + /* Set the current settingl */ + pdev->tx_peer_bal.ctl_thresh[level].tput_thresh = + tput_thresh; + pdev->tx_peer_bal.ctl_thresh[level].tx_limit = + tx_limit; +} + +/** + * ol_tx_pdev_peer_bal_timer() - timer function + * @context: context of timer function + * + * Return: None + */ +void +ol_tx_pdev_peer_bal_timer(void *context) +{ + int i; + struct ol_txrx_pdev_t *pdev = (struct ol_txrx_pdev_t *)context; + + qdf_spin_lock_bh(&pdev->tx_peer_bal.mutex); + + for (i = 0; i < pdev->tx_peer_bal.peer_num; i++) { + if (pdev->tx_peer_bal.limit_list[i].limit_flag) { + u_int16_t peer_id = + pdev->tx_peer_bal.limit_list[i].peer_id; + u_int16_t tx_limit = + pdev->tx_peer_bal.limit_list[i].limit; + + struct ol_txrx_peer_t *peer = NULL; + peer = ol_txrx_peer_find_by_id(pdev, peer_id); + TX_SCHED_DEBUG_PRINT( + "%s peer_id %d peer = 0x%x tx limit %d\n", + __func__, peer_id, + (int)peer, tx_limit); + + /* It is possible the peer limit is still not 0, + but it is the scenario should not be cared */ + if (peer) { + peer->tx_limit = tx_limit; + } else { + ol_txrx_peer_bal_remove_limit_peer(pdev, + peer_id); + TX_SCHED_DEBUG_PRINT_ALWAYS( + "No such a peer, peer id = %d\n", + peer_id); + } + } + } + + qdf_spin_unlock_bh(&pdev->tx_peer_bal.mutex); + + if (pdev->tx_peer_bal.peer_num) { + ol_tx_sched(pdev); + qdf_timer_start(&pdev->tx_peer_bal.peer_bal_timer, + pdev->tx_peer_bal.peer_bal_period_ms); + } +} + +void +ol_txrx_set_txq_peer( + struct ol_tx_frms_queue_t *txq, + struct ol_txrx_peer_t *peer) +{ + if (txq) + txq->peer = peer; +} + +void ol_tx_badpeer_flow_cl_init(struct ol_txrx_pdev_t *pdev) +{ + u_int32_t timer_period; + + qdf_spinlock_create(&pdev->tx_peer_bal.mutex); + pdev->tx_peer_bal.peer_num = 0; + pdev->tx_peer_bal.peer_bal_timer_state + = ol_tx_peer_bal_timer_inactive; + + timer_period = 2000; + pdev->tx_peer_bal.peer_bal_period_ms = timer_period; + + qdf_timer_init( + pdev->osdev, + &pdev->tx_peer_bal.peer_bal_timer, + ol_tx_pdev_peer_bal_timer, + pdev, QDF_TIMER_TYPE_SW); +} + +void ol_tx_badpeer_flow_cl_deinit(struct ol_txrx_pdev_t *pdev) +{ + qdf_timer_stop(&pdev->tx_peer_bal.peer_bal_timer); + pdev->tx_peer_bal.peer_bal_timer_state = + ol_tx_peer_bal_timer_inactive; + qdf_timer_free(&pdev->tx_peer_bal.peer_bal_timer); + qdf_spinlock_destroy(&pdev->tx_peer_bal.mutex); +} + +void +ol_txrx_peer_link_status_handler( + ol_txrx_pdev_handle pdev, + u_int16_t peer_num, + struct rate_report_t *peer_link_status) +{ + u_int16_t i = 0; + struct ol_txrx_peer_t *peer = NULL; + + if (NULL == pdev) { + TX_SCHED_DEBUG_PRINT_ALWAYS("Error: NULL pdev handler\n"); + return; + } + + if (NULL == peer_link_status) { + TX_SCHED_DEBUG_PRINT_ALWAYS( + "Error:NULL link report message. peer num %d\n", + peer_num); + return; + } + + /* Check if bad peer tx flow CL is enabled */ + if (pdev->tx_peer_bal.enabled != ol_tx_peer_bal_enable) { + TX_SCHED_DEBUG_PRINT_ALWAYS( + "Bad peer tx flow CL is not enabled, ignore it\n"); + return; + } + + /* Check peer_num is reasonable */ + if (peer_num > MAX_NO_PEERS_IN_LIMIT) { + TX_SCHED_DEBUG_PRINT_ALWAYS( + "%s: Bad peer_num %d\n", __func__, peer_num); + return; + } + + TX_SCHED_DEBUG_PRINT_ALWAYS("%s: peer_num %d\n", __func__, peer_num); + + for (i = 0; i < peer_num; i++) { + u_int16_t peer_limit, peer_id; + u_int16_t pause_flag, unpause_flag; + u_int32_t peer_phy, peer_tput; + + peer_id = peer_link_status->id; + peer_phy = peer_link_status->phy; + peer_tput = peer_link_status->rate; + + TX_SCHED_DEBUG_PRINT("%s: peer id %d tput %d phy %d\n", + __func__, peer_id, peer_tput, peer_phy); + + /* Sanity check for the PHY mode value */ + if (peer_phy > TXRX_IEEE11_AC) { + TX_SCHED_DEBUG_PRINT_ALWAYS( + "%s: PHY value is illegal: %d, and the peer_id %d\n", + __func__, peer_link_status->phy, peer_id); + continue; + } + pause_flag = false; + unpause_flag = false; + peer_limit = 0; + + /* From now on, PHY, PER info should be all fine */ + qdf_spin_lock_bh(&pdev->tx_peer_bal.mutex); + + /* Update link status analysis for each peer */ + peer = ol_txrx_peer_find_by_id(pdev, peer_id); + if (peer) { + u_int32_t thresh, limit, phy; + phy = peer_link_status->phy; + thresh = pdev->tx_peer_bal.ctl_thresh[phy].tput_thresh; + limit = pdev->tx_peer_bal.ctl_thresh[phy].tx_limit; + + if (((peer->tx_pause_flag) || (peer->tx_limit_flag)) && + (peer_tput) && (peer_tput < thresh)) + peer_limit = limit; + + if (peer_limit) { + ol_txrx_peer_bal_add_limit_peer(pdev, peer_id, + peer_limit); + } else if (pdev->tx_peer_bal.peer_num) { + TX_SCHED_DEBUG_PRINT( + "%s: Check if peer_id %d exit limit\n", + __func__, peer_id); + ol_txrx_peer_bal_remove_limit_peer(pdev, + peer_id); + } + if ((peer_tput == 0) && + (peer->tx_pause_flag == false)) { + peer->tx_pause_flag = true; + pause_flag = true; + } else if (peer->tx_pause_flag) { + unpause_flag = true; + peer->tx_pause_flag = false; + } + } else { + TX_SCHED_DEBUG_PRINT( + "%s: Remove peer_id %d from limit list\n", + __func__, peer_id); + ol_txrx_peer_bal_remove_limit_peer(pdev, peer_id); + } + + peer_link_status++; + qdf_spin_unlock_bh(&pdev->tx_peer_bal.mutex); + if (pause_flag) + ol_txrx_peer_pause_but_no_mgmt_q(peer); + else if (unpause_flag) + ol_txrx_peer_unpause_but_no_mgmt_q(peer); + } +} +#endif /* QCA_BAD_PEER_TX_FLOW_CL */ + +/*--- ADDBA triggering functions --------------------------------------------*/ + + +/*=== debug functions =======================================================*/ + +/*--- queue event log -------------------------------------------------------*/ + +#if defined(DEBUG_HL_LOGGING) + +#define negative_sign -1 + +/** + * ol_tx_queue_log_entry_type_info() - log queues entry info + * @type: log entry type + * @size: size + * @align: alignment + * @var_size: variable size record + * + * Return: None + */ +static void +ol_tx_queue_log_entry_type_info( + u_int8_t *type, int *size, int *align, int var_size) +{ + switch (*type) { + case ol_tx_log_entry_type_enqueue: + case ol_tx_log_entry_type_dequeue: + case ol_tx_log_entry_type_queue_free: + *size = sizeof(struct ol_tx_log_queue_add_t); + *align = 2; + break; + + case ol_tx_log_entry_type_queue_state: + *size = offsetof(struct ol_tx_log_queue_state_var_sz_t, data); + *align = 4; + if (var_size) { + /* read the variable-sized record, + * to see how large it is + */ + int align_pad; + struct ol_tx_log_queue_state_var_sz_t *record; + + align_pad = + (*align - ((((u_int32_t) *type) + 1))) + & (*align - 1); + record = (struct ol_tx_log_queue_state_var_sz_t *) + (type + 1 + align_pad); + *size += record->num_cats_active * + (sizeof(u_int32_t) /* bytes */ + + sizeof(u_int16_t) /* frms */); + } + break; + + /*case ol_tx_log_entry_type_drop:*/ + default: + *size = 0; + *align = 0; + }; +} + +/** + * ol_tx_queue_log_oldest_update() - log oldest record + * @pdev: pointer to txrx handle + * @offset: offset value + * + * Return: None + */ +static void +ol_tx_queue_log_oldest_update(struct ol_txrx_pdev_t *pdev, int offset) +{ + int oldest_record_offset; + + /* + * If the offset of the oldest record is between the current and + * new values of the offset of the newest record, then the oldest + * record has to be dropped from the log to provide room for the + * newest record. + * Advance the offset of the oldest record until it points to a + * record that is beyond the new value of the offset of the newest + * record. + */ + if (!pdev->txq_log.wrapped) + /* + * The log has not even filled up yet - no need to remove + * the oldest record to make room for a new record. + */ + return; + + + if (offset > pdev->txq_log.offset) { + /* + * not wraparound - + * The oldest record offset may have already wrapped around, + * even if the newest record has not. In this case, then + * the oldest record offset is fine where it is. + */ + if (pdev->txq_log.oldest_record_offset == 0) + return; + + oldest_record_offset = pdev->txq_log.oldest_record_offset; + } else + /* wraparound */ + oldest_record_offset = 0; + + + while (oldest_record_offset < offset) { + int size, align, align_pad; + u_int8_t type; + + type = pdev->txq_log.data[oldest_record_offset]; + if (type == ol_tx_log_entry_type_wrap) { + oldest_record_offset = 0; + break; + } + ol_tx_queue_log_entry_type_info( + &pdev->txq_log.data[oldest_record_offset], + &size, &align, 1); + align_pad = + (align - ((oldest_record_offset + 1/*type*/))) + & (align - 1); + /* + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_LOW, + "TXQ LOG old alloc: offset %d, type %d, size %d (%d)\n", + oldest_record_offset, type, size, size + 1 + align_pad); + */ + oldest_record_offset += size + 1 + align_pad; + } + if (oldest_record_offset >= pdev->txq_log.size) + oldest_record_offset = 0; + + pdev->txq_log.oldest_record_offset = oldest_record_offset; +} + +/** + * ol_tx_queue_log_alloc() - log data allocation + * @pdev: physical device object + * @type: ol_tx_log_entry_type + * @extra_bytes: extra bytes + * + * + * Return: log element + */ +void* +ol_tx_queue_log_alloc( + struct ol_txrx_pdev_t *pdev, + u_int8_t type /* ol_tx_log_entry_type */, + int extra_bytes) +{ + int size, align, align_pad; + int offset; + + ol_tx_queue_log_entry_type_info(&type, &size, &align, 0); + size += extra_bytes; + + offset = pdev->txq_log.offset; + align_pad = (align - ((offset + 1/*type*/))) & (align - 1); + + if (pdev->txq_log.size - offset >= size + 1 + align_pad) + /* no need to wrap around */ + goto alloc_found; + + if (!pdev->txq_log.allow_wrap) + return NULL; /* log is full and can't wrap */ + + /* handle wrap-around */ + pdev->txq_log.wrapped = 1; + offset = 0; + align_pad = (align - ((offset + 1/*type*/))) & (align - 1); + /* sanity check that the log is large enough to hold this entry */ + if (pdev->txq_log.size <= size + 1 + align_pad) + return NULL; + + +alloc_found: + ol_tx_queue_log_oldest_update(pdev, offset + size + 1 + align_pad); + if (offset == 0) + pdev->txq_log.data[pdev->txq_log.offset] = + ol_tx_log_entry_type_wrap; + + /* + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_LOW, + "TXQ LOG new alloc: offset %d, type %d, size %d (%d)\n", + offset, type, size, size + 1 + align_pad); + */ + pdev->txq_log.data[offset] = type; + pdev->txq_log.offset = offset + size + 1 + align_pad; + if (pdev->txq_log.offset >= pdev->txq_log.size) { + pdev->txq_log.offset = 0; + pdev->txq_log.wrapped = 1; + } + return &pdev->txq_log.data[offset + 1 + align_pad]; +} + +/** + * ol_tx_queue_log_record_display() - show log record of tx queue + * @pdev: pointer to txrx handle + * @offset: offset value + * + * Return: size of record + */ +static int +ol_tx_queue_log_record_display(struct ol_txrx_pdev_t *pdev, int offset) +{ + int size, align, align_pad; + u_int8_t type; + struct ol_txrx_peer_t *peer; + + qdf_spin_lock_bh(&pdev->txq_log_spinlock); + type = pdev->txq_log.data[offset]; + ol_tx_queue_log_entry_type_info( + &pdev->txq_log.data[offset], &size, &align, 1); + align_pad = (align - ((offset + 1/*type*/))) & (align - 1); + + switch (type) { + case ol_tx_log_entry_type_enqueue: + { + struct ol_tx_log_queue_add_t record; + qdf_mem_copy(&record, + &pdev->txq_log.data[offset + 1 + align_pad], + sizeof(struct ol_tx_log_queue_add_t)); + qdf_spin_unlock_bh(&pdev->txq_log_spinlock); + + if (record.peer_id != 0xffff) { + peer = ol_txrx_peer_find_by_id(pdev, + record.peer_id); + if (peer != NULL) + QDF_TRACE(QDF_MODULE_ID_TXRX, + QDF_TRACE_LEVEL_ERROR, + "Q: %6d %5d %3d %4d (%02x:%02x:%02x:%02x:%02x:%02x)", + record.num_frms, record.num_bytes, + record.tid, + record.peer_id, + peer->mac_addr.raw[0], + peer->mac_addr.raw[1], + peer->mac_addr.raw[2], + peer->mac_addr.raw[3], + peer->mac_addr.raw[4], + peer->mac_addr.raw[5]); + else + QDF_TRACE(QDF_MODULE_ID_TXRX, + QDF_TRACE_LEVEL_ERROR, + "Q: %6d %5d %3d %4d", + record.num_frms, record.num_bytes, + record.tid, record.peer_id); + } else { + QDF_TRACE(QDF_MODULE_ID_TXRX, + QDF_TRACE_LEVEL_INFO, + "Q: %6d %5d %3d from vdev", + record.num_frms, record.num_bytes, + record.tid); + } + break; + } + case ol_tx_log_entry_type_dequeue: + { + struct ol_tx_log_queue_add_t record; + qdf_mem_copy(&record, + &pdev->txq_log.data[offset + 1 + align_pad], + sizeof(struct ol_tx_log_queue_add_t)); + qdf_spin_unlock_bh(&pdev->txq_log_spinlock); + + if (record.peer_id != 0xffff) { + peer = ol_txrx_peer_find_by_id(pdev, record.peer_id); + if (peer != NULL) + QDF_TRACE(QDF_MODULE_ID_TXRX, + QDF_TRACE_LEVEL_ERROR, + "DQ: %6d %5d %3d %4d (%02x:%02x:%02x:%02x:%02x:%02x)", + record.num_frms, record.num_bytes, + record.tid, + record.peer_id, + peer->mac_addr.raw[0], + peer->mac_addr.raw[1], + peer->mac_addr.raw[2], + peer->mac_addr.raw[3], + peer->mac_addr.raw[4], + peer->mac_addr.raw[5]); + else + QDF_TRACE(QDF_MODULE_ID_TXRX, + QDF_TRACE_LEVEL_ERROR, + "DQ: %6d %5d %3d %4d", + record.num_frms, record.num_bytes, + record.tid, record.peer_id); + } else { + QDF_TRACE(QDF_MODULE_ID_TXRX, + QDF_TRACE_LEVEL_INFO, + "DQ: %6d %5d %3d from vdev", + record.num_frms, record.num_bytes, + record.tid); + } + break; + } + case ol_tx_log_entry_type_queue_free: + { + struct ol_tx_log_queue_add_t record; + qdf_mem_copy(&record, + &pdev->txq_log.data[offset + 1 + align_pad], + sizeof(struct ol_tx_log_queue_add_t)); + qdf_spin_unlock_bh(&pdev->txq_log_spinlock); + + if (record.peer_id != 0xffff) { + peer = ol_txrx_peer_find_by_id(pdev, record.peer_id); + if (peer != NULL) + QDF_TRACE(QDF_MODULE_ID_TXRX, + QDF_TRACE_LEVEL_ERROR, + "F: %6d %5d %3d %4d (%02x:%02x:%02x:%02x:%02x:%02x)", + record.num_frms, record.num_bytes, + record.tid, + record.peer_id, + peer->mac_addr.raw[0], + peer->mac_addr.raw[1], + peer->mac_addr.raw[2], + peer->mac_addr.raw[3], + peer->mac_addr.raw[4], + peer->mac_addr.raw[5]); + else + QDF_TRACE(QDF_MODULE_ID_TXRX, + QDF_TRACE_LEVEL_ERROR, + "F: %6d %5d %3d %4d", + record.num_frms, record.num_bytes, + record.tid, record.peer_id); + } else { + /* shouldn't happen */ + QDF_TRACE(QDF_MODULE_ID_TXRX, + QDF_TRACE_LEVEL_INFO, + "Unexpected vdev queue removal\n"); + } + break; + } + + case ol_tx_log_entry_type_queue_state: + { + int i, j; + u_int32_t active_bitmap; + struct ol_tx_log_queue_state_var_sz_t record; + u_int8_t *data; + + qdf_mem_copy(&record, + &pdev->txq_log.data[offset + 1 + align_pad], + sizeof(struct ol_tx_log_queue_state_var_sz_t)); + qdf_spin_unlock_bh(&pdev->txq_log_spinlock); + + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "S: bitmap = %#x", + record.active_bitmap); + data = &record.data[0]; + j = 0; + i = 0; + active_bitmap = record.active_bitmap; + while (active_bitmap) { + if (active_bitmap & 0x1) { + u_int16_t frms; + u_int32_t bytes; + + frms = data[0] | (data[1] << 8); + bytes = (data[2] << 0) | (data[3] << 8) | + (data[4] << 16) | (data[5] << 24); + QDF_TRACE(QDF_MODULE_ID_TXRX, + QDF_TRACE_LEVEL_ERROR, + "cat %2d: %6d %5d", + i, frms, bytes); + data += 6; + j++; + } + i++; + active_bitmap >>= 1; + } + break; + } + + /*case ol_tx_log_entry_type_drop:*/ + + case ol_tx_log_entry_type_wrap: + qdf_spin_unlock_bh(&pdev->txq_log_spinlock); + return negative_sign * offset; /* go back to the top */ + + default: + qdf_spin_unlock_bh(&pdev->txq_log_spinlock); + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "*** invalid tx log entry type (%d)\n", type); + return 0; /* error */ + }; + + return size + 1 + align_pad; +} + +/** + * ol_tx_queue_log_display() - show tx queue log + * @pdev: pointer to txrx handle + * + * Return: None + */ +void +ol_tx_queue_log_display(struct ol_txrx_pdev_t *pdev) +{ + int offset; + int unwrap; + + qdf_spin_lock_bh(&pdev->txq_log_spinlock); + offset = pdev->txq_log.oldest_record_offset; + unwrap = pdev->txq_log.wrapped; + qdf_spin_unlock_bh(&pdev->txq_log_spinlock); + /* + * In theory, this should use mutex to guard against the offset + * being changed while in use, but since this is just for debugging, + * don't bother. + */ + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "Tx queue log:"); + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + ": Frames Bytes TID PEER"); + + while (unwrap || offset != pdev->txq_log.offset) { + int delta = ol_tx_queue_log_record_display(pdev, offset); + if (delta == 0) + return; /* error */ + + if (delta < 0) + unwrap = 0; + + offset += delta; + } +} + +void +ol_tx_queue_log_enqueue( + struct ol_txrx_pdev_t *pdev, + struct ol_txrx_msdu_info_t *msdu_info, + int frms, int bytes) +{ + int tid; + u_int16_t peer_id = msdu_info->htt.info.peer_id; + struct ol_tx_log_queue_add_t *log_elem; + tid = msdu_info->htt.info.ext_tid; + + qdf_spin_lock_bh(&pdev->txq_log_spinlock); + log_elem = ol_tx_queue_log_alloc(pdev, ol_tx_log_entry_type_enqueue, 0); + if (!log_elem) { + qdf_spin_unlock_bh(&pdev->txq_log_spinlock); + return; + } + + log_elem->num_frms = frms; + log_elem->num_bytes = bytes; + log_elem->peer_id = peer_id; + log_elem->tid = tid; + qdf_spin_unlock_bh(&pdev->txq_log_spinlock); +} + +void +ol_tx_queue_log_dequeue( + struct ol_txrx_pdev_t *pdev, + struct ol_tx_frms_queue_t *txq, + int frms, int bytes) +{ + int ext_tid; + u_int16_t peer_id; + struct ol_tx_log_queue_add_t *log_elem; + + ext_tid = txq->ext_tid; + qdf_spin_lock_bh(&pdev->txq_log_spinlock); + log_elem = ol_tx_queue_log_alloc(pdev, ol_tx_log_entry_type_dequeue, 0); + if (!log_elem) { + qdf_spin_unlock_bh(&pdev->txq_log_spinlock); + return; + } + + if (ext_tid < OL_TX_NUM_TIDS) { + struct ol_txrx_peer_t *peer; + struct ol_tx_frms_queue_t *txq_base; + + txq_base = txq - ext_tid; + peer = container_of(txq_base, struct ol_txrx_peer_t, txqs[0]); + peer_id = peer->peer_ids[0]; + } else { + peer_id = ~0; + } + + log_elem->num_frms = frms; + log_elem->num_bytes = bytes; + log_elem->peer_id = peer_id; + log_elem->tid = ext_tid; + qdf_spin_unlock_bh(&pdev->txq_log_spinlock); +} + +void +ol_tx_queue_log_free( + struct ol_txrx_pdev_t *pdev, + struct ol_tx_frms_queue_t *txq, + int tid, int frms, int bytes, bool is_peer_txq) +{ + u_int16_t peer_id; + struct ol_tx_log_queue_add_t *log_elem; + + qdf_spin_lock_bh(&pdev->txq_log_spinlock); + log_elem = ol_tx_queue_log_alloc(pdev, ol_tx_log_entry_type_queue_free, + 0); + if (!log_elem) { + qdf_spin_unlock_bh(&pdev->txq_log_spinlock); + return; + } + + if ((tid < OL_TX_NUM_TIDS) && is_peer_txq) { + struct ol_txrx_peer_t *peer; + struct ol_tx_frms_queue_t *txq_base; + + txq_base = txq - tid; + peer = container_of(txq_base, struct ol_txrx_peer_t, txqs[0]); + peer_id = peer->peer_ids[0]; + } else { + peer_id = ~0; + } + + log_elem->num_frms = frms; + log_elem->num_bytes = bytes; + log_elem->peer_id = peer_id; + log_elem->tid = tid; + qdf_spin_unlock_bh(&pdev->txq_log_spinlock); +} + +void +ol_tx_queue_log_sched( + struct ol_txrx_pdev_t *pdev, + int credit, + int *num_cats, + u_int32_t **active_bitmap, + u_int8_t **data) +{ + int data_size; + struct ol_tx_log_queue_state_var_sz_t *log_elem; + + data_size = sizeof(u_int32_t) /* bytes */ + + sizeof(u_int16_t) /* frms */; + data_size *= *num_cats; + + qdf_spin_lock_bh(&pdev->txq_log_spinlock); + log_elem = ol_tx_queue_log_alloc( + pdev, ol_tx_log_entry_type_queue_state, data_size); + if (!log_elem) { + *num_cats = 0; + qdf_spin_unlock_bh(&pdev->txq_log_spinlock); + return; + } + log_elem->num_cats_active = *num_cats; + log_elem->active_bitmap = 0; + log_elem->credit = credit; + + *active_bitmap = &log_elem->active_bitmap; + *data = &log_elem->data[0]; + qdf_spin_unlock_bh(&pdev->txq_log_spinlock); +} + +/** + * ol_tx_queue_log_clear() - clear tx queue log + * @pdev: pointer to txrx handle + * + * Return: None + */ +void +ol_tx_queue_log_clear(struct ol_txrx_pdev_t *pdev) +{ + qdf_spin_lock_bh(&pdev->txq_log_spinlock); + qdf_mem_zero(&pdev->txq_log, sizeof(pdev->txq_log)); + pdev->txq_log.size = OL_TXQ_LOG_SIZE; + pdev->txq_log.oldest_record_offset = 0; + pdev->txq_log.offset = 0; + pdev->txq_log.allow_wrap = 1; + pdev->txq_log.wrapped = 0; + qdf_spin_unlock_bh(&pdev->txq_log_spinlock); +} +#endif /* defined(DEBUG_HL_LOGGING) */ + +/*--- queue state printouts -------------------------------------------------*/ + +#if TXRX_DEBUG_LEVEL > 5 + +/** + * ol_tx_queue_display() - show tx queue info + * @txq: pointer to txq frames + * @indent: indent + * + * Return: None + */ +void +ol_tx_queue_display(struct ol_tx_frms_queue_t *txq, int indent) +{ + char *state; + + state = (txq->flag == ol_tx_queue_active) ? "active" : "paused"; + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_LOW, + "%*stxq %p (%s): %d frms, %d bytes\n", + indent, " ", txq, state, txq->frms, txq->bytes); +} + +void +ol_tx_queues_display(struct ol_txrx_pdev_t *pdev) +{ + struct ol_txrx_vdev_t *vdev; + + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_LOW, + "pdev %p tx queues:\n", pdev); + TAILQ_FOREACH(vdev, &pdev->vdev_list, vdev_list_elem) { + struct ol_txrx_peer_t *peer; + int i; + for (i = 0; i < QDF_ARRAY_SIZE(vdev->txqs); i++) { + if (vdev->txqs[i].frms == 0) + continue; + + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_LOW, + "vdev %d (%p), txq %d\n", vdev->vdev_id, + vdev, i); + ol_tx_queue_display(&vdev->txqs[i], 4); + } + TAILQ_FOREACH(peer, &vdev->peer_list, peer_list_elem) { + for (i = 0; i < QDF_ARRAY_SIZE(peer->txqs); i++) { + if (peer->txqs[i].frms == 0) + continue; + + QDF_TRACE(QDF_MODULE_ID_TXRX, + QDF_TRACE_LEVEL_INFO_LOW, + "peer %d (%p), txq %d\n", + peer->peer_ids[0], vdev, i); + ol_tx_queue_display(&peer->txqs[i], 6); + } + } + } +} +#endif + +#endif /* defined(CONFIG_HL_SUPPORT) */ + +#if defined(QCA_LL_LEGACY_TX_FLOW_CONTROL) + +/** + * ol_txrx_vdev_pause- Suspend all tx data for the specified virtual device + * + * @data_vdev - the virtual device being paused + * @reason - the reason for which vdev queue is getting paused + * + * This function applies primarily to HL systems, but also + * applies to LL systems that use per-vdev tx queues for MCC or + * thermal throttling. As an example, this function could be + * used when a single-channel physical device supports multiple + * channels by jumping back and forth between the channels in a + * time-shared manner. As the device is switched from channel A + * to channel B, the virtual devices that operate on channel A + * will be paused. + * + */ +void ol_txrx_vdev_pause(ol_txrx_vdev_handle vdev, uint32_t reason) +{ + /* TO DO: log the queue pause */ + /* acquire the mutex lock, since we'll be modifying the queues */ + TX_SCHED_DEBUG_PRINT("Enter %s\n", __func__); + + qdf_spin_lock_bh(&vdev->ll_pause.mutex); + vdev->ll_pause.paused_reason |= reason; + vdev->ll_pause.q_pause_cnt++; + vdev->ll_pause.is_q_paused = true; + qdf_spin_unlock_bh(&vdev->ll_pause.mutex); + + TX_SCHED_DEBUG_PRINT("Leave %s\n", __func__); +} + +/** + * ol_txrx_vdev_unpause - Resume tx for the specified virtual device + * + * @data_vdev - the virtual device being unpaused + * @reason - the reason for which vdev queue is getting unpaused + * + * This function applies primarily to HL systems, but also applies to + * LL systems that use per-vdev tx queues for MCC or thermal throttling. + * + */ +void ol_txrx_vdev_unpause(ol_txrx_vdev_handle vdev, uint32_t reason) +{ + /* TO DO: log the queue unpause */ + /* acquire the mutex lock, since we'll be modifying the queues */ + TX_SCHED_DEBUG_PRINT("Enter %s\n", __func__); + + qdf_spin_lock_bh(&vdev->ll_pause.mutex); + if (vdev->ll_pause.paused_reason & reason) { + vdev->ll_pause.paused_reason &= ~reason; + if (!vdev->ll_pause.paused_reason) { + vdev->ll_pause.is_q_paused = false; + vdev->ll_pause.q_unpause_cnt++; + qdf_spin_unlock_bh(&vdev->ll_pause.mutex); + ol_tx_vdev_ll_pause_queue_send(vdev); + } else { + qdf_spin_unlock_bh(&vdev->ll_pause.mutex); + } + } else { + qdf_spin_unlock_bh(&vdev->ll_pause.mutex); + } + TX_SCHED_DEBUG_PRINT("Leave %s\n", __func__); +} + +/** + * ol_txrx_vdev_flush - Drop all tx data for the specified virtual device + * + * @data_vdev - the virtual device being flushed + * + * This function applies primarily to HL systems, but also applies to + * LL systems that use per-vdev tx queues for MCC or thermal throttling. + * This function would typically be used by the ctrl SW after it parks + * a STA vdev and then resumes it, but to a new AP. In this case, though + * the same vdev can be used, any old tx frames queued inside it would be + * stale, and would need to be discarded. + * + */ +void ol_txrx_vdev_flush(ol_txrx_vdev_handle vdev) +{ + qdf_spin_lock_bh(&vdev->ll_pause.mutex); + qdf_timer_stop(&vdev->ll_pause.timer); + vdev->ll_pause.is_q_timer_on = false; + while (vdev->ll_pause.txq.head) { + qdf_nbuf_t next = + qdf_nbuf_next(vdev->ll_pause.txq.head); + qdf_nbuf_set_next(vdev->ll_pause.txq.head, NULL); + qdf_nbuf_unmap(vdev->pdev->osdev, + vdev->ll_pause.txq.head, + QDF_DMA_TO_DEVICE); + qdf_nbuf_tx_free(vdev->ll_pause.txq.head, + QDF_NBUF_PKT_ERROR); + vdev->ll_pause.txq.head = next; + } + vdev->ll_pause.txq.tail = NULL; + vdev->ll_pause.txq.depth = 0; + qdf_spin_unlock_bh(&vdev->ll_pause.mutex); +} +#endif /* defined(QCA_LL_LEGACY_TX_FLOW_CONTROL) */ + +#if (!defined(QCA_LL_LEGACY_TX_FLOW_CONTROL)) && (!defined(CONFIG_HL_SUPPORT)) +void ol_txrx_vdev_flush(ol_txrx_vdev_handle data_vdev) +{ + return; +} +#endif + +#ifdef QCA_LL_TX_FLOW_CONTROL_V2 +#ifndef CONFIG_ICNSS + +/** + * ol_txrx_map_to_netif_reason_type() - map to netif_reason_type + * @reason: reason + * + * Return: netif_reason_type + */ +static enum netif_reason_type +ol_txrx_map_to_netif_reason_type(uint32_t reason) +{ + switch (reason) { + case OL_TXQ_PAUSE_REASON_FW: + return WLAN_FW_PAUSE; + case OL_TXQ_PAUSE_REASON_PEER_UNAUTHORIZED: + return WLAN_PEER_UNAUTHORISED; + case OL_TXQ_PAUSE_REASON_TX_ABORT: + return WLAN_TX_ABORT; + case OL_TXQ_PAUSE_REASON_VDEV_STOP: + return WLAN_VDEV_STOP; + case OL_TXQ_PAUSE_REASON_THERMAL_MITIGATION: + return WLAN_THERMAL_MITIGATION; + default: + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "%s: reason not supported %d\n", + __func__, reason); + return WLAN_REASON_TYPE_MAX; + } +} + +/** + * ol_txrx_vdev_pause() - pause vdev network queues + * @vdev: vdev handle + * @reason: reason + * + * Return: none + */ +void ol_txrx_vdev_pause(ol_txrx_vdev_handle vdev, uint32_t reason) +{ + struct ol_txrx_pdev_t *pdev = vdev->pdev; + enum netif_reason_type netif_reason; + + if (qdf_unlikely((!pdev) || (!pdev->pause_cb))) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "%s: invalid pdev\n", __func__); + return; + } + + netif_reason = ol_txrx_map_to_netif_reason_type(reason); + if (netif_reason == WLAN_REASON_TYPE_MAX) + return; + + pdev->pause_cb(vdev->vdev_id, WLAN_STOP_ALL_NETIF_QUEUE, netif_reason); +} + +/** + * ol_txrx_vdev_unpause() - unpause vdev network queues + * @vdev: vdev handle + * @reason: reason + * + * Return: none + */ +void ol_txrx_vdev_unpause(ol_txrx_vdev_handle vdev, uint32_t reason) +{ + struct ol_txrx_pdev_t *pdev = vdev->pdev; + enum netif_reason_type netif_reason; + + if (qdf_unlikely((!pdev) || (!pdev->pause_cb))) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "%s: invalid pdev\n", __func__); + return; + } + + netif_reason = ol_txrx_map_to_netif_reason_type(reason); + if (netif_reason == WLAN_REASON_TYPE_MAX) + return; + + pdev->pause_cb(vdev->vdev_id, WLAN_WAKE_ALL_NETIF_QUEUE, + netif_reason); + +} +#endif +#endif + +#if defined(QCA_LL_TX_FLOW_CONTROL_V2) || defined(CONFIG_HL_SUPPORT) + +/** + * ol_txrx_pdev_pause() - pause network queues for each vdev + * @pdev: pdev handle + * @reason: reason + * + * Return: none + */ +void ol_txrx_pdev_pause(struct ol_txrx_pdev_t *pdev, uint32_t reason) +{ + struct ol_txrx_vdev_t *vdev = NULL, *tmp; + + TAILQ_FOREACH_SAFE(vdev, &pdev->vdev_list, vdev_list_elem, tmp) { + ol_txrx_vdev_pause(vdev, reason); + } + +} + +/** + * ol_txrx_pdev_unpause() - unpause network queues for each vdev + * @pdev: pdev handle + * @reason: reason + * + * Return: none + */ +void ol_txrx_pdev_unpause(struct ol_txrx_pdev_t *pdev, uint32_t reason) +{ + struct ol_txrx_vdev_t *vdev = NULL, *tmp; + + TAILQ_FOREACH_SAFE(vdev, &pdev->vdev_list, vdev_list_elem, tmp) { + ol_txrx_vdev_unpause(vdev, reason); + } + +} +#endif + +/*--- LL tx throttle queue code --------------------------------------------*/ +#if defined(QCA_SUPPORT_TX_THROTTLE) +#ifdef QCA_LL_TX_FLOW_CONTROL_V2 +/** + * ol_txrx_thermal_pause() - pause due to thermal mitigation + * @pdev: pdev handle + * + * Return: none + */ +static inline +void ol_txrx_thermal_pause(struct ol_txrx_pdev_t *pdev) +{ + ol_txrx_pdev_pause(pdev, OL_TXQ_PAUSE_REASON_THERMAL_MITIGATION); + return; +} +/** + * ol_txrx_thermal_unpause() - unpause due to thermal mitigation + * @pdev: pdev handle + * + * Return: none + */ +static inline +void ol_txrx_thermal_unpause(struct ol_txrx_pdev_t *pdev) +{ + ol_txrx_pdev_unpause(pdev, OL_TXQ_PAUSE_REASON_THERMAL_MITIGATION); + return; +} +#else +/** + * ol_txrx_thermal_pause() - pause due to thermal mitigation + * @pdev: pdev handle + * + * Return: none + */ +static inline +void ol_txrx_thermal_pause(struct ol_txrx_pdev_t *pdev) +{ + return; +} + +/** + * ol_txrx_thermal_unpause() - unpause due to thermal mitigation + * @pdev: pdev handle + * + * Return: none + */ +static inline +void ol_txrx_thermal_unpause(struct ol_txrx_pdev_t *pdev) +{ + ol_tx_pdev_ll_pause_queue_send_all(pdev); + return; +} +#endif + +static void ol_tx_pdev_throttle_phase_timer(void *context) +{ + struct ol_txrx_pdev_t *pdev = (struct ol_txrx_pdev_t *)context; + int ms; + enum throttle_level cur_level; + enum throttle_phase cur_phase; + + /* update the phase */ + pdev->tx_throttle.current_throttle_phase++; + + if (pdev->tx_throttle.current_throttle_phase == THROTTLE_PHASE_MAX) + pdev->tx_throttle.current_throttle_phase = THROTTLE_PHASE_OFF; + + if (pdev->tx_throttle.current_throttle_phase == THROTTLE_PHASE_OFF) { + /* Traffic is stopped */ + TXRX_PRINT(TXRX_PRINT_LEVEL_WARN, + "throttle phase --> OFF\n"); + ol_txrx_throttle_pause(pdev); + ol_txrx_thermal_pause(pdev); + cur_level = pdev->tx_throttle.current_throttle_level; + cur_phase = pdev->tx_throttle.current_throttle_phase; + ms = pdev->tx_throttle.throttle_time_ms[cur_level][cur_phase]; + if (pdev->tx_throttle.current_throttle_level != + THROTTLE_LEVEL_0) { + TXRX_PRINT(TXRX_PRINT_LEVEL_WARN, + "start timer %d ms\n", ms); + qdf_timer_start(&pdev->tx_throttle. + phase_timer, ms); + } + } else { + /* Traffic can go */ + TXRX_PRINT(TXRX_PRINT_LEVEL_WARN, + "throttle phase --> ON\n"); + ol_txrx_throttle_unpause(pdev); + ol_txrx_thermal_unpause(pdev); + cur_level = pdev->tx_throttle.current_throttle_level; + cur_phase = pdev->tx_throttle.current_throttle_phase; + ms = pdev->tx_throttle.throttle_time_ms[cur_level][cur_phase]; + if (pdev->tx_throttle.current_throttle_level != + THROTTLE_LEVEL_0) { + TXRX_PRINT(TXRX_PRINT_LEVEL_WARN, "start timer %d ms\n", + ms); + qdf_timer_start(&pdev->tx_throttle.phase_timer, + ms); + } + } +} + +#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL +static void ol_tx_pdev_throttle_tx_timer(void *context) +{ + struct ol_txrx_pdev_t *pdev = (struct ol_txrx_pdev_t *)context; + ol_tx_pdev_ll_pause_queue_send_all(pdev); +} +#endif + +#ifdef CONFIG_HL_SUPPORT + +/** + * ol_tx_set_throttle_phase_time() - Set the thermal mitgation throttle phase + * and time + * @pdev: the peer device object + * @level: throttle phase level + * @ms: throttle time + * + * Return: None + */ +static void +ol_tx_set_throttle_phase_time(struct ol_txrx_pdev_t *pdev, int level, int *ms) +{ + qdf_timer_stop(&pdev->tx_throttle.phase_timer); + + /* Set the phase */ + if (level != THROTTLE_LEVEL_0) { + pdev->tx_throttle.current_throttle_phase = THROTTLE_PHASE_OFF; + *ms = pdev->tx_throttle.throttle_time_ms[level] + [THROTTLE_PHASE_OFF]; + + /* pause all */ + ol_txrx_throttle_pause(pdev); + } else { + pdev->tx_throttle.current_throttle_phase = THROTTLE_PHASE_ON; + *ms = pdev->tx_throttle.throttle_time_ms[level] + [THROTTLE_PHASE_ON]; + + /* unpause all */ + ol_txrx_throttle_unpause(pdev); + } +} +#else + +static void +ol_tx_set_throttle_phase_time(struct ol_txrx_pdev_t *pdev, int level, int *ms) +{ + /* Reset the phase */ + pdev->tx_throttle.current_throttle_phase = THROTTLE_PHASE_OFF; + + /* Start with the new time */ + *ms = pdev->tx_throttle. + throttle_time_ms[level][THROTTLE_PHASE_OFF]; + + qdf_timer_stop(&pdev->tx_throttle.phase_timer); +} +#endif + +void ol_tx_throttle_set_level(struct ol_txrx_pdev_t *pdev, int level) +{ + int ms = 0; + + if (level >= THROTTLE_LEVEL_MAX) { + TXRX_PRINT(TXRX_PRINT_LEVEL_WARN, + "%s invalid throttle level set %d, ignoring\n", + __func__, level); + return; + } + + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, "Setting throttle level %d\n", level); + + /* Set the current throttle level */ + pdev->tx_throttle.current_throttle_level = (enum throttle_level) level; + + ol_tx_set_throttle_phase_time(pdev, level, &ms); + + if (level != THROTTLE_LEVEL_0) + qdf_timer_start(&pdev->tx_throttle.phase_timer, ms); +} + +void ol_tx_throttle_init_period(struct ol_txrx_pdev_t *pdev, int period, + uint8_t *dutycycle_level) +{ + int i; + + /* Set the current throttle level */ + pdev->tx_throttle.throttle_period_ms = period; + + TXRX_PRINT(TXRX_PRINT_LEVEL_WARN, "level OFF ON\n"); + for (i = 0; i < THROTTLE_LEVEL_MAX; i++) { + pdev->tx_throttle.throttle_time_ms[i][THROTTLE_PHASE_ON] = + pdev->tx_throttle.throttle_period_ms - + ((dutycycle_level[i] * + pdev->tx_throttle.throttle_period_ms)/100); + pdev->tx_throttle.throttle_time_ms[i][THROTTLE_PHASE_OFF] = + pdev->tx_throttle.throttle_period_ms - + pdev->tx_throttle.throttle_time_ms[ + i][THROTTLE_PHASE_ON]; + TXRX_PRINT(TXRX_PRINT_LEVEL_WARN, "%d %d %d\n", i, + pdev->tx_throttle. + throttle_time_ms[i][THROTTLE_PHASE_OFF], + pdev->tx_throttle. + throttle_time_ms[i][THROTTLE_PHASE_ON]); + } + +} + +void ol_tx_throttle_init(struct ol_txrx_pdev_t *pdev) +{ + uint32_t throttle_period; + uint8_t dutycycle_level[THROTTLE_LEVEL_MAX]; + int i; + + pdev->tx_throttle.current_throttle_level = THROTTLE_LEVEL_0; + pdev->tx_throttle.current_throttle_phase = THROTTLE_PHASE_OFF; + qdf_spinlock_create(&pdev->tx_throttle.mutex); + + throttle_period = ol_cfg_throttle_period_ms(pdev->ctrl_pdev); + + for (i = 0; i < THROTTLE_LEVEL_MAX; i++) + dutycycle_level[i] = + ol_cfg_throttle_duty_cycle_level(pdev->ctrl_pdev, i); + + ol_tx_throttle_init_period(pdev, throttle_period, &dutycycle_level[0]); + + qdf_timer_init(pdev->osdev, + &pdev->tx_throttle.phase_timer, + ol_tx_pdev_throttle_phase_timer, pdev, + QDF_TIMER_TYPE_SW); + +#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL + qdf_timer_init(pdev->osdev, + &pdev->tx_throttle.tx_timer, + ol_tx_pdev_throttle_tx_timer, pdev, + QDF_TIMER_TYPE_SW); +#endif + + pdev->tx_throttle.tx_threshold = THROTTLE_TX_THRESHOLD; +} +#endif /* QCA_SUPPORT_TX_THROTTLE */ + +#ifdef FEATURE_HL_GROUP_CREDIT_FLOW_CONTROL + +/** + * ol_tx_vdev_has_tx_queue_group() - check for vdev having txq groups + * @group: pointer to tx queue grpup + * @vdev_id: vdev id + * + * Return: true if vedv has txq groups + */ +static bool +ol_tx_vdev_has_tx_queue_group( + struct ol_tx_queue_group_t *group, + u_int8_t vdev_id) +{ + u_int16_t vdev_bitmap; + vdev_bitmap = OL_TXQ_GROUP_VDEV_ID_MASK_GET(group->membership); + if (OL_TXQ_GROUP_VDEV_ID_BIT_MASK_GET(vdev_bitmap, vdev_id)) + return true; + + return false; +} + +/** + * ol_tx_ac_has_tx_queue_group() - check for ac having txq groups + * @group: pointer to tx queue grpup + * @ac: acess category + * + * Return: true if vedv has txq groups + */ +static bool +ol_tx_ac_has_tx_queue_group( + struct ol_tx_queue_group_t *group, + u_int8_t ac) +{ + u_int16_t ac_bitmap; + ac_bitmap = OL_TXQ_GROUP_AC_MASK_GET(group->membership); + if (OL_TXQ_GROUP_AC_BIT_MASK_GET(ac_bitmap, ac)) + return true; + + return false; +} + +u_int32_t ol_tx_txq_group_credit_limit( + struct ol_txrx_pdev_t *pdev, + struct ol_tx_frms_queue_t *txq, + u_int32_t credit) +{ + u_int8_t i; + int updated_credit = credit; + /* + * If this tx queue belongs to a group, check whether the group's + * credit limit is more stringent than the global credit limit. + */ + for (i = 0; i < OL_TX_MAX_GROUPS_PER_QUEUE; i++) { + if (txq->group_ptrs[i]) { + int group_credit; + group_credit = qdf_atomic_read( + &txq->group_ptrs[i]->credit); + updated_credit = QDF_MIN(updated_credit, group_credit); + } + } + + credit = (updated_credit < 0) ? 0 : updated_credit; + + return credit; +} + +void ol_tx_txq_group_credit_update( + struct ol_txrx_pdev_t *pdev, + struct ol_tx_frms_queue_t *txq, + int32_t credit, + u_int8_t absolute) +{ + u_int8_t i; + /* + * If this tx queue belongs to a group then + * update group credit + */ + for (i = 0; i < OL_TX_MAX_GROUPS_PER_QUEUE; i++) { + if (txq->group_ptrs[i]) + ol_txrx_update_group_credit(txq->group_ptrs[i], + credit, absolute); + } + ol_tx_update_group_credit_stats(pdev); +} + +void +ol_tx_set_vdev_group_ptr( + ol_txrx_pdev_handle pdev, + u_int8_t vdev_id, + struct ol_tx_queue_group_t *grp_ptr) +{ + struct ol_txrx_vdev_t *vdev = NULL; + struct ol_txrx_peer_t *peer = NULL; + + TAILQ_FOREACH(vdev, &pdev->vdev_list, vdev_list_elem) { + if (vdev->vdev_id == vdev_id) { + u_int8_t i, j; + /* update vdev queues group pointers */ + for (i = 0; i < OL_TX_VDEV_NUM_QUEUES; i++) { + for (j = 0; j < OL_TX_MAX_GROUPS_PER_QUEUE; j++) + vdev->txqs[i].group_ptrs[j] = grp_ptr; + } + qdf_spin_lock_bh(&pdev->peer_ref_mutex); + /* Update peer queue group pointers */ + TAILQ_FOREACH(peer, &vdev->peer_list, peer_list_elem) { + for (i = 0; i < OL_TX_NUM_TIDS; i++) { + for (j = 0; + j < OL_TX_MAX_GROUPS_PER_QUEUE; + j++) + peer->txqs[i].group_ptrs[j] = + grp_ptr; + } + } + qdf_spin_unlock_bh(&pdev->peer_ref_mutex); + break; + } + } +} + +void ol_tx_txq_set_group_ptr( + struct ol_tx_frms_queue_t *txq, + struct ol_tx_queue_group_t *grp_ptr) +{ + u_int8_t i; + for (i = 0; i < OL_TX_MAX_GROUPS_PER_QUEUE; i++) + txq->group_ptrs[i] = grp_ptr; +} + +void ol_tx_set_peer_group_ptr( + ol_txrx_pdev_handle pdev, + struct ol_txrx_peer_t *peer, + u_int8_t vdev_id, + u_int8_t tid) +{ + u_int8_t i, j = 0; + struct ol_tx_queue_group_t *group = NULL; + + for (i = 0; i < OL_TX_MAX_GROUPS_PER_QUEUE; i++) + peer->txqs[tid].group_ptrs[i] = NULL; + + for (i = 0; i < OL_TX_MAX_TXQ_GROUPS; i++) { + group = &pdev->txq_grps[i]; + if (ol_tx_vdev_has_tx_queue_group(group, vdev_id)) { + if (tid < OL_TX_NUM_QOS_TIDS) { + if (ol_tx_ac_has_tx_queue_group( + group, + TXRX_TID_TO_WMM_AC(tid))) { + peer->txqs[tid].group_ptrs[j] = group; + j++; + } + } else { + peer->txqs[tid].group_ptrs[j] = group; + j++; + } + } + if (j >= OL_TX_MAX_GROUPS_PER_QUEUE) + break; + } +} + +u_int32_t ol_tx_get_max_tx_groups_supported(struct ol_txrx_pdev_t *pdev) +{ +#ifdef HIF_SDIO + return OL_TX_MAX_TXQ_GROUPS; +#else + return 0; +#endif +} +#endif + +/*--- End of LL tx throttle queue code ---------------------------------------*/ diff --git a/drivers/staging/qcacld-3.0/core/dp/txrx/ol_tx_queue.h b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_tx_queue.h new file mode 100644 index 0000000000000000000000000000000000000000..d3e3080c5d8b875b0041214f2ba72423f2f2fdd9 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_tx_queue.h @@ -0,0 +1,583 @@ +/* + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * @file ol_tx_queue.h + * @brief API definitions for the tx frame queue module within the data SW. + */ +#ifndef _OL_TX_QUEUE__H_ +#define _OL_TX_QUEUE__H_ + +#include /* qdf_nbuf_t */ +#include /* ol_txrx_vdev_t, etc. */ +#include /* bool */ + +/*--- function prototypes for optional queue log feature --------------------*/ +#if defined(ENABLE_TX_QUEUE_LOG) || \ + (defined(DEBUG_HL_LOGGING) && defined(CONFIG_HL_SUPPORT)) + +/** + * ol_tx_queue_log_enqueue() - enqueue tx queue logs + * @pdev: physical device object + * @msdu_info: tx msdu meta data + * @frms: number of frames for which logs need to be enqueued + * @bytes: number of bytes + * + * + * Return: None + */ +void +ol_tx_queue_log_enqueue(struct ol_txrx_pdev_t *pdev, + struct ol_txrx_msdu_info_t *msdu_info, + int frms, int bytes); + +/** + * ol_tx_queue_log_dequeue() - dequeue tx queue logs + * @pdev: physical device object + * @txq: tx queue + * @frms: number of frames for which logs need to be dequeued + * @bytes: number of bytes + * + * + * Return: None + */ +void +ol_tx_queue_log_dequeue(struct ol_txrx_pdev_t *pdev, + struct ol_tx_frms_queue_t *txq, int frms, int bytes); + +/** + * ol_tx_queue_log_free() - free tx queue logs + * @pdev: physical device object + * @txq: tx queue + * @tid: tid value + * @frms: number of frames for which logs need to be freed + * @bytes: number of bytes + * @is_peer_txq - peer queue or not + * + * + * Return: None + */ +void +ol_tx_queue_log_free(struct ol_txrx_pdev_t *pdev, + struct ol_tx_frms_queue_t *txq, + int tid, int frms, int bytes, bool is_peer_txq); + +#else + +static inline void +ol_tx_queue_log_enqueue(struct ol_txrx_pdev_t *pdev, + struct ol_txrx_msdu_info_t *msdu_info, + int frms, int bytes) +{ + return; +} + +static inline void +ol_tx_queue_log_dequeue(struct ol_txrx_pdev_t *pdev, + struct ol_tx_frms_queue_t *txq, int frms, int bytes) +{ + return; +} + +static inline void +ol_tx_queue_log_free(struct ol_txrx_pdev_t *pdev, + struct ol_tx_frms_queue_t *txq, + int tid, int frms, int bytes, bool is_peer_txq) +{ + return; +} + +#endif + +#if defined(CONFIG_HL_SUPPORT) + +/** + * @brief Queue a tx frame to the tid queue. + * + * @param pdev - the data virtual device sending the data + * (for storing the tx desc in the virtual dev's tx_target_list, + * and for accessing the phy dev) + * @param txq - which queue the tx frame gets stored in + * @param tx_desc - tx meta-data, including prev and next ptrs + * @param tx_msdu_info - characteristics of the tx frame + */ +void +ol_tx_enqueue( + struct ol_txrx_pdev_t *pdev, + struct ol_tx_frms_queue_t *txq, + struct ol_tx_desc_t *tx_desc, + struct ol_txrx_msdu_info_t *tx_msdu_info); + +/** + * @brief - remove the specified number of frames from the head of a tx queue + * @details + * This function removes frames from the head of a tx queue, + * and returns them as a NULL-terminated linked list. + * The function will remove frames until one of the following happens: + * 1. The tx queue is empty + * 2. The specified number of frames have been removed + * 3. Removal of more frames would exceed the specified credit limit + * + * @param pdev - the physical device object + * @param txq - which tx queue to remove frames from + * @param head - which contains return linked-list of tx frames (descriptors) + * @param num_frames - maximum number of frames to remove + * @param[in/out] credit - + * input: max credit the dequeued frames can consume + * output: how much credit the dequeued frames consume + * @param[out] bytes - the sum of the sizes of the dequeued frames + * @return number of frames dequeued +*/ +u_int16_t +ol_tx_dequeue( + struct ol_txrx_pdev_t *pdev, + struct ol_tx_frms_queue_t *txq, + ol_tx_desc_list *head, + u_int16_t num_frames, + u_int32_t *credit, + int *bytes); + +/** + * @brief - free all of frames from the tx queue while deletion + * @details + * This function frees all of frames from the tx queue. + * This function is called during peer or vdev deletion. + * This function notifies the scheduler, so the scheduler can update + * its state to account for the absence of the queue. + * + * @param pdev - the physical device object, which stores the txqs + * @param txq - which tx queue to free frames from + * @param tid - the extended TID that the queue belongs to + * @param is_peer_txq - peer queue or not + */ +void +ol_tx_queue_free( + struct ol_txrx_pdev_t *pdev, + struct ol_tx_frms_queue_t *txq, + int tid, bool is_peer_txq); + +/** + * @brief - discard pending tx frames from the tx queue + * @details + * This function is called if there are too many queues in tx scheduler. + * This function is called if we wants to flush all pending tx + * queues in tx scheduler. + * + * @param pdev - the physical device object, which stores the txqs + * @param flush_all - flush all pending tx queues if set to true + * @param tx_descs - List Of tx_descs to be discarded will be returned by this function + */ + +void +ol_tx_queue_discard( + struct ol_txrx_pdev_t *pdev, + bool flush_all, + ol_tx_desc_list *tx_descs); + +#else + +static inline void +ol_tx_enqueue( + struct ol_txrx_pdev_t *pdev, + struct ol_tx_frms_queue_t *txq, + struct ol_tx_desc_t *tx_desc, + struct ol_txrx_msdu_info_t *tx_msdu_info) +{ + return; +} + +static inline u_int16_t +ol_tx_dequeue( + struct ol_txrx_pdev_t *pdev, + struct ol_tx_frms_queue_t *txq, + ol_tx_desc_list *head, + u_int16_t num_frames, + u_int32_t *credit, + int *bytes) +{ + return 0; +} + +static inline void +ol_tx_queue_free( + struct ol_txrx_pdev_t *pdev, + struct ol_tx_frms_queue_t *txq, + int tid, bool is_peer_txq) +{ + return; +} + +static inline void +ol_tx_queue_discard( + struct ol_txrx_pdev_t *pdev, + bool flush_all, + ol_tx_desc_list *tx_descs) +{ + return; +} +#endif /* defined(CONFIG_HL_SUPPORT) */ + +#if defined(CONFIG_HL_SUPPORT) && defined(QCA_BAD_PEER_TX_FLOW_CL) + +void +ol_txrx_peer_bal_add_limit_peer( + struct ol_txrx_pdev_t *pdev, + u_int16_t peer_id, + u_int16_t peer_limit); + +void +ol_txrx_peer_bal_remove_limit_peer( + struct ol_txrx_pdev_t *pdev, + u_int16_t peer_id); + +/** + * ol_txrx_peer_pause_but_no_mgmt_q() - suspend/pause all txqs except + * management queue for a given peer + * @peer: peer device object + * + * Return: None + */ +void +ol_txrx_peer_pause_but_no_mgmt_q(ol_txrx_peer_handle peer); + +/** + * ol_txrx_peer_unpause_but_no_mgmt_q() - unpause all txqs except management + * queue for a given peer + * @peer: peer device object + * + * Return: None + */ +void +ol_txrx_peer_unpause_but_no_mgmt_q(ol_txrx_peer_handle peer); + +/** + * ol_tx_bad_peer_dequeue_check() - retrieve the send limit + * of the tx queue category + * @txq: tx queue of the head of the category list + * @max_frames: send limit of the txq category + * @tx_limit_flag: set true is tx limit is reached + * + * Return: send limit + */ +u_int16_t +ol_tx_bad_peer_dequeue_check(struct ol_tx_frms_queue_t *txq, + u_int16_t max_frames, + u_int16_t *tx_limit_flag); + +/** + * ol_tx_bad_peer_update_tx_limit() - update the send limit of the + * tx queue category + * @pdev: the physical device object + * @txq: tx queue of the head of the category list + * @frames: frames that has been dequeued + * @tx_limit_flag: tx limit reached flag + * + * Return: None + */ +void +ol_tx_bad_peer_update_tx_limit(struct ol_txrx_pdev_t *pdev, + struct ol_tx_frms_queue_t *txq, + u_int16_t frames, + u_int16_t tx_limit_flag); + +/** + * ol_txrx_set_txq_peer() - set peer to the tx queue's peer + * @txq: tx queue for a given tid + * @peer: the peer device object + * + * Return: None + */ +void +ol_txrx_set_txq_peer( + struct ol_tx_frms_queue_t *txq, + struct ol_txrx_peer_t *peer); + +/** + * @brief - initialize the peer balance context + * @param pdev - the physical device object, which stores the txqs + */ +void ol_tx_badpeer_flow_cl_init(struct ol_txrx_pdev_t *pdev); + +/** + * @brief - deinitialize the peer balance context + * @param pdev - the physical device object, which stores the txqs + */ +void ol_tx_badpeer_flow_cl_deinit(struct ol_txrx_pdev_t *pdev); + +#else + +static inline void ol_txrx_peer_bal_add_limit_peer( + struct ol_txrx_pdev_t *pdev, + u_int16_t peer_id, + u_int16_t peer_limit) +{ + return; +} + +static inline void ol_txrx_peer_bal_remove_limit_peer( + struct ol_txrx_pdev_t *pdev, + u_int16_t peer_id) +{ + return; +} + +static inline void ol_txrx_peer_pause_but_no_mgmt_q(ol_txrx_peer_handle peer) +{ + return; +} + +static inline void ol_txrx_peer_unpause_but_no_mgmt_q(ol_txrx_peer_handle peer) +{ + return; +} + +static inline u_int16_t +ol_tx_bad_peer_dequeue_check(struct ol_tx_frms_queue_t *txq, + u_int16_t max_frames, + u_int16_t *tx_limit_flag) +{ + /* just return max_frames */ + return max_frames; +} + +static inline void +ol_tx_bad_peer_update_tx_limit(struct ol_txrx_pdev_t *pdev, + struct ol_tx_frms_queue_t *txq, + u_int16_t frames, + u_int16_t tx_limit_flag) +{ + return; +} + +static inline void +ol_txrx_set_txq_peer( + struct ol_tx_frms_queue_t *txq, + struct ol_txrx_peer_t *peer) +{ + return; +} + +static inline void ol_tx_badpeer_flow_cl_init(struct ol_txrx_pdev_t *pdev) +{ + return; +} + +static inline void ol_tx_badpeer_flow_cl_deinit(struct ol_txrx_pdev_t *pdev) +{ + return; +} + +#endif /* defined(CONFIG_HL_SUPPORT) && defined(QCA_BAD_PEER_TX_FLOW_CL) */ + +#if defined(CONFIG_HL_SUPPORT) && defined(DEBUG_HL_LOGGING) + +/** + * ol_tx_queue_log_sched() - start logging of tx queues for HL + * @pdev: physical device object + * @credit: number of credits + * @num_active_tids: number of active tids for which logging needs to be done + * @active_bitmap:bitmap + * @data: buffer + * + * Return: None + */ +void +ol_tx_queue_log_sched(struct ol_txrx_pdev_t *pdev, + int credit, + int *num_active_tids, + uint32_t **active_bitmap, uint8_t **data); +#else + +static inline void +ol_tx_queue_log_sched(struct ol_txrx_pdev_t *pdev, + int credit, + int *num_active_tids, + uint32_t **active_bitmap, uint8_t **data) +{ + return; +} +#endif /* defined(CONFIG_HL_SUPPORT) && defined(DEBUG_HL_LOGGING) */ + +#if defined(CONFIG_HL_SUPPORT) && TXRX_DEBUG_LEVEL > 5 +/** + * @brief - show current state of all tx queues + * @param pdev - the physical device object, which stores the txqs + */ +void +ol_tx_queues_display(struct ol_txrx_pdev_t *pdev); + +#else + +static inline void +ol_tx_queues_display(struct ol_txrx_pdev_t *pdev) +{ + return; +} +#endif + +#define ol_tx_queue_decs_reinit(peer, peer_id) /* no-op */ + +#ifdef QCA_SUPPORT_TX_THROTTLE +/** + * @brief - initialize the throttle context + * @param pdev - the physical device object, which stores the txqs + */ +void ol_tx_throttle_init(struct ol_txrx_pdev_t *pdev); +#else +#define ol_tx_throttle_init(pdev) /*no op */ +#endif + +#ifdef FEATURE_HL_GROUP_CREDIT_FLOW_CONTROL + +static inline bool +ol_tx_is_txq_last_serviced_queue(struct ol_txrx_pdev_t *pdev, + struct ol_tx_frms_queue_t *txq) +{ + return txq == pdev->tx_sched.last_used_txq; +} + +/** + * ol_tx_txq_group_credit_limit() - check for credit limit of a given tx queue + * @pdev: physical device object + * @txq: tx queue for which credit limit needs be to checked + * @credit: number of credits of the selected category + * + * Return: updated credits + */ +u_int32_t ol_tx_txq_group_credit_limit( + struct ol_txrx_pdev_t *pdev, + struct ol_tx_frms_queue_t *txq, + u_int32_t credit); + +/** + * ol_tx_txq_group_credit_update() - update group credits of the + * selected catoegory + * @pdev: physical device object + * @txq: tx queue for which credit needs to be updated + * @credit: number of credits by which selected category needs to be updated + * @absolute: TXQ group absolute value + * + * Return: None + */ +void ol_tx_txq_group_credit_update( + struct ol_txrx_pdev_t *pdev, + struct ol_tx_frms_queue_t *txq, + int32_t credit, + u_int8_t absolute); + +/** + * ol_tx_set_vdev_group_ptr() - update vdev queues group pointer + * @pdev: physical device object + * @vdev_id: vdev id for which group pointer needs to update + * @grp_ptr: pointer to ol tx queue group which needs to be set for vdev queues + * + * Return: None + */ +void +ol_tx_set_vdev_group_ptr( + ol_txrx_pdev_handle pdev, + u_int8_t vdev_id, + struct ol_tx_queue_group_t *grp_ptr); + +/** + * ol_tx_txq_set_group_ptr() - update tx queue group pointer + * @txq: tx queue of which group pointer needs to update + * @grp_ptr: pointer to ol tx queue group which needs to be + * set for given tx queue + * + * + * Return: None + */ +void +ol_tx_txq_set_group_ptr( + struct ol_tx_frms_queue_t *txq, + struct ol_tx_queue_group_t *grp_ptr); + +/** + * ol_tx_set_peer_group_ptr() - update peer tx queues group pointer + * for a given tid + * @pdev: physical device object + * @peer: peer device object + * @vdev_id: vdev id + * @tid: tid for which group pointer needs to update + * + * + * Return: None + */ +void +ol_tx_set_peer_group_ptr( + ol_txrx_pdev_handle pdev, + struct ol_txrx_peer_t *peer, + u_int8_t vdev_id, + u_int8_t tid); +#else + +static inline bool +ol_tx_is_txq_last_serviced_queue(struct ol_txrx_pdev_t *pdev, + struct ol_tx_frms_queue_t *txq) +{ + return 0; +} + +static inline +u_int32_t ol_tx_txq_group_credit_limit( + struct ol_txrx_pdev_t *pdev, + struct ol_tx_frms_queue_t *txq, + u_int32_t credit) +{ + return credit; +} + +static inline void ol_tx_txq_group_credit_update( + struct ol_txrx_pdev_t *pdev, + struct ol_tx_frms_queue_t *txq, + int32_t credit, + u_int8_t absolute) +{ + return; +} + +static inline void +ol_tx_txq_set_group_ptr( + struct ol_tx_frms_queue_t *txq, + struct ol_tx_queue_group_t *grp_ptr) +{ + return; +} + +static inline void +ol_tx_set_peer_group_ptr( + ol_txrx_pdev_handle pdev, + struct ol_txrx_peer_t *peer, + u_int8_t vdev_id, + u_int8_t tid) +{ + return; +} +#endif + +#endif /* _OL_TX_QUEUE__H_ */ diff --git a/drivers/staging/qcacld-3.0/core/dp/txrx/ol_tx_sched.c b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_tx_sched.c new file mode 100644 index 0000000000000000000000000000000000000000..dc2dd854c56df6bf9c28bdb1de826a881b29389c --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_tx_sched.c @@ -0,0 +1,1596 @@ +/* + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#include /* qdf_nbuf_t, etc. */ +#include /* HTT_TX_EXT_TID_MGMT */ +#include /* htt_tx_desc_tid */ +#include /* ol_txrx_vdev_handle */ +#include /* ol_txrx_sync */ +#include /* TXRX_ASSERT1 */ +#include /* pdev stats, etc. */ +#include /* ol_tx_desc */ +#include /* ol_tx_send */ +#include /* OL_TX_SCHED, etc. */ +#include +#include +#include +#include /* qdf_os_mem_alloc_consistent et al */ + +#if defined(CONFIG_HL_SUPPORT) + +#if defined(DEBUG_HL_LOGGING) +static void +ol_tx_sched_log(struct ol_txrx_pdev_t *pdev); + +#else +static void +ol_tx_sched_log(struct ol_txrx_pdev_t *pdev) +{ + return; +} +#endif /* defined(DEBUG_HL_LOGGING) */ + +#if DEBUG_HTT_CREDIT +#define OL_TX_DISPATCH_LOG_CREDIT() \ + do { \ + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_LOW, \ + "TX %d bytes\n", qdf_nbuf_len(msdu)); \ + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_LOW, \ + " Decrease credit %d - 1 = %d, len:%d.\n", \ + qdf_atomic_read(&pdev->target_tx_credit), \ + qdf_atomic_read(&pdev->target_tx_credit) - 1, \ + qdf_nbuf_len(msdu)); \ + } while (0) +#else +#define OL_TX_DISPATCH_LOG_CREDIT() +#endif + +/*--- generic definitions used by the scheduler framework for all algs ---*/ + +struct ol_tx_sched_ctx { + ol_tx_desc_list head; + int frms; +}; + +typedef TAILQ_HEAD(ol_tx_frms_queue_list_s, ol_tx_frms_queue_t) + ol_tx_frms_queue_list; + +#define OL_A_MAX(_x, _y) ((_x) > (_y) ? (_x) : (_y)) + +#define OL_A_MIN(_x, _y) ((_x) < (_y) ? (_x) : (_y)) + + /*--- scheduler algorithm selection ---*/ + + /*--- scheduler options ----------------------------------------------- + * 1. Round-robin scheduler: + * Select the TID that is at the head of the list of active TIDs. + * Select the head tx queue for this TID. + * Move the tx queue to the back of the list of tx queues for + * this TID. + * Move the TID to the back of the list of active TIDs. + * Send as many frames from the tx queue as credit allows. + * 2. Weighted-round-robin advanced scheduler: + * Keep an ordered list of which TID gets selected next. + * Use a weighted-round-robin scheme to determine when to promote + * a TID within this list. + * If a TID at the head of the list is inactive, leave it at the + * head, but check the next TIDs. + * If the credit available is less than the credit threshold for the + * next active TID, don't send anything, and leave the TID at the + * head of the list. + * After a TID is selected, move it to the back of the list. + * Select the head tx queue for this TID. + * Move the tx queue to the back of the list of tx queues for this + * TID. + * Send no more frames than the limit specified for the TID. + */ +#define OL_TX_SCHED_RR 1 +#define OL_TX_SCHED_WRR_ADV 2 + +#ifndef OL_TX_SCHED + /*#define OL_TX_SCHED OL_TX_SCHED_RR*/ +#define OL_TX_SCHED OL_TX_SCHED_WRR_ADV /* default */ +#endif + + +#if OL_TX_SCHED == OL_TX_SCHED_RR + +#define ol_tx_sched_rr_t ol_tx_sched_t + +#define OL_TX_SCHED_NUM_CATEGORIES (OL_TX_NUM_TIDS + OL_TX_VDEV_NUM_QUEUES) + +#define ol_tx_sched_init ol_tx_sched_init_rr +#define ol_tx_sched_select_init(pdev) /* no-op */ +#define ol_tx_sched_select_batch ol_tx_sched_select_batch_rr +#define ol_tx_sched_txq_enqueue ol_tx_sched_txq_enqueue_rr +#define ol_tx_sched_txq_deactivate ol_tx_sched_txq_deactivate_rr +#define ol_tx_sched_category_tx_queues ol_tx_sched_category_tx_queues_rr +#define ol_tx_sched_txq_discard ol_tx_sched_txq_discard_rr +#define ol_tx_sched_category_info ol_tx_sched_category_info_rr +#define ol_tx_sched_discard_select_category \ + ol_tx_sched_discard_select_category_rr + +#elif OL_TX_SCHED == OL_TX_SCHED_WRR_ADV + +#define ol_tx_sched_wrr_adv_t ol_tx_sched_t + +#define OL_TX_SCHED_NUM_CATEGORIES OL_TX_SCHED_WRR_ADV_NUM_CATEGORIES + +#define ol_tx_sched_init ol_tx_sched_init_wrr_adv +#define ol_tx_sched_select_init(pdev) \ + do { \ + qdf_spin_lock_bh(&pdev->tx_queue_spinlock); \ + ol_tx_sched_select_init_wrr_adv(pdev); \ + qdf_spin_unlock_bh(&pdev->tx_queue_spinlock); \ + } while (0) +#define ol_tx_sched_select_batch ol_tx_sched_select_batch_wrr_adv +#define ol_tx_sched_txq_enqueue ol_tx_sched_txq_enqueue_wrr_adv +#define ol_tx_sched_txq_deactivate ol_tx_sched_txq_deactivate_wrr_adv +#define ol_tx_sched_category_tx_queues ol_tx_sched_category_tx_queues_wrr_adv +#define ol_tx_sched_txq_discard ol_tx_sched_txq_discard_wrr_adv +#define ol_tx_sched_category_info ol_tx_sched_category_info_wrr_adv +#define ol_tx_sched_discard_select_category \ + ol_tx_sched_discard_select_category_wrr_adv + +#else + +#error Unknown OL TX SCHED specification + +#endif /* OL_TX_SCHED */ + + /*--- round-robin scheduler ----------------------------------------*/ +#if OL_TX_SCHED == OL_TX_SCHED_RR + + /*--- definitions ---*/ + + struct ol_tx_active_queues_in_tid_t { + /* list_elem is used to queue up into up level queues*/ + TAILQ_ENTRY(ol_tx_active_queues_in_tid_t) list_elem; + u_int32_t frms; + u_int32_t bytes; + ol_tx_frms_queue_list head; + bool active; + int tid; + }; + + struct ol_tx_sched_rr_t { + struct ol_tx_active_queues_in_tid_t + tx_active_queues_in_tid_array[OL_TX_NUM_TIDS + + OL_TX_VDEV_NUM_QUEUES]; + TAILQ_HEAD(ol_tx_active_tids_s, ol_tx_active_queues_in_tid_t) + tx_active_tids_list; + u_int8_t discard_weights[OL_TX_NUM_TIDS + + OL_TX_VDEV_NUM_QUEUES]; + }; + +#define TX_SCH_MAX_CREDIT_FOR_THIS_TID(tidq) 16 + +/*--- functions ---*/ + +/* + * The scheduler sync spinlock has been acquired outside this function, + * so there is no need to worry about mutex within this function. + */ +static int +ol_tx_sched_select_batch_rr( + struct ol_txrx_pdev_t *pdev, + struct ol_tx_sched_ctx *sctx, + u_int32_t credit) +{ + struct ol_tx_sched_rr_t *scheduler = pdev->tx_sched.scheduler; + struct ol_tx_active_queues_in_tid_t *txq_queue; + struct ol_tx_frms_queue_t *next_tq; + u_int16_t frames, used_credits = 0, tx_limit, tx_limit_flag = 0; + int bytes; + + TX_SCHED_DEBUG_PRINT("Enter %s\n", __func__); + + if (TAILQ_EMPTY(&scheduler->tx_active_tids_list)) + return used_credits; + + txq_queue = TAILQ_FIRST(&scheduler->tx_active_tids_list); + + TAILQ_REMOVE(&scheduler->tx_active_tids_list, txq_queue, list_elem); + txq_queue->active = false; + + next_tq = TAILQ_FIRST(&txq_queue->head); + TAILQ_REMOVE(&txq_queue->head, next_tq, list_elem); + + credit = OL_A_MIN(credit, TX_SCH_MAX_CREDIT_FOR_THIS_TID(next_tq)); + frames = next_tq->frms; /* download as many frames as credit allows */ + tx_limit = ol_tx_bad_peer_dequeue_check(next_tq, + frames, + &tx_limit_flag); + frames = ol_tx_dequeue( + pdev, next_tq, &sctx->head, tx_limit, &credit, &bytes); + ol_tx_bad_peer_update_tx_limit(pdev, next_tq, frames, tx_limit_flag); + + used_credits = credit; + txq_queue->frms -= frames; + txq_queue->bytes -= bytes; + + if (next_tq->frms > 0) { + TAILQ_INSERT_TAIL(&txq_queue->head, next_tq, list_elem); + TAILQ_INSERT_TAIL( + &scheduler->tx_active_tids_list, + txq_queue, list_elem); + txq_queue->active = true; + } else if (!TAILQ_EMPTY(&txq_queue->head)) { + /* + * This tx queue is empty, but there's another tx queue for the + * same TID that is not empty. + *Thus, the TID as a whole is active. + */ + TAILQ_INSERT_TAIL( + &scheduler->tx_active_tids_list, + txq_queue, list_elem); + txq_queue->active = true; + } + sctx->frms += frames; + + TX_SCHED_DEBUG_PRINT("Leave %s\n", __func__); + return used_credits; +} + +static inline void +ol_tx_sched_txq_enqueue_rr( + struct ol_txrx_pdev_t *pdev, + struct ol_tx_frms_queue_t *txq, + int tid, + int frms, + int bytes) +{ + struct ol_tx_sched_rr_t *scheduler = pdev->tx_sched.scheduler; + struct ol_tx_active_queues_in_tid_t *txq_queue; + + txq_queue = &scheduler->tx_active_queues_in_tid_array[tid]; + if (txq->flag != ol_tx_queue_active) + TAILQ_INSERT_TAIL(&txq_queue->head, txq, list_elem); + + txq_queue->frms += frms; + txq_queue->bytes += bytes; + + if (!txq_queue->active) { + TAILQ_INSERT_TAIL( + &scheduler->tx_active_tids_list, + txq_queue, list_elem); + txq_queue->active = true; + } +} + +static inline void +ol_tx_sched_txq_deactivate_rr( + struct ol_txrx_pdev_t *pdev, + struct ol_tx_frms_queue_t *txq, + int tid) +{ + struct ol_tx_sched_rr_t *scheduler = pdev->tx_sched.scheduler; + struct ol_tx_active_queues_in_tid_t *txq_queue; + + txq_queue = &scheduler->tx_active_queues_in_tid_array[tid]; + txq_queue->frms -= txq->frms; + txq_queue->bytes -= txq->bytes; + + TAILQ_REMOVE(&txq_queue->head, txq, list_elem); + /*if (txq_queue->frms == 0 && txq_queue->active) {*/ + if (TAILQ_EMPTY(&txq_queue->head) && txq_queue->active) { + TAILQ_REMOVE(&scheduler->tx_active_tids_list, txq_queue, + list_elem); + txq_queue->active = false; + } +} + +ol_tx_frms_queue_list * +ol_tx_sched_category_tx_queues_rr(struct ol_txrx_pdev_t *pdev, int tid) +{ + struct ol_tx_sched_rr_t *scheduler = pdev->tx_sched.scheduler; + struct ol_tx_active_queues_in_tid_t *txq_queue; + + txq_queue = &scheduler->tx_active_queues_in_tid_array[tid]; + return &txq_queue->head; +} + +int +ol_tx_sched_discard_select_category_rr(struct ol_txrx_pdev_t *pdev) +{ + struct ol_tx_sched_rr_t *scheduler; + u_int8_t i, tid = 0; + int max_score = 0; + + scheduler = pdev->tx_sched.scheduler; + /* + * Choose which TID's tx frames to drop next based on two factors: + * 1. Which TID has the most tx frames present + * 2. The TID's priority (high-priority TIDs have a low discard_weight) + */ + for (i = 0; i < (OL_TX_NUM_TIDS + OL_TX_VDEV_NUM_QUEUES); i++) { + int score; + score = + scheduler->tx_active_queues_in_tid_array[i].frms * + scheduler->discard_weights[i]; + if (max_score == 0 || score > max_score) { + max_score = score; + tid = i; + } + } + return tid; +} + +void +ol_tx_sched_txq_discard_rr( + struct ol_txrx_pdev_t *pdev, + struct ol_tx_frms_queue_t *txq, + int tid, int frames, int bytes) +{ + struct ol_tx_sched_rr_t *scheduler = pdev->tx_sched.scheduler; + struct ol_tx_active_queues_in_tid_t *txq_queue; + + txq_queue = &scheduler->tx_active_queues_in_tid_array[tid]; + + if (0 == txq->frms) + TAILQ_REMOVE(&txq_queue->head, txq, list_elem); + + txq_queue->frms -= frames; + txq_queue->bytes -= bytes; + if (txq_queue->active == true && txq_queue->frms == 0) { + TAILQ_REMOVE(&scheduler->tx_active_tids_list, txq_queue, + list_elem); + txq_queue->active = false; + } +} + +void +ol_tx_sched_category_info_rr( + struct ol_txrx_pdev_t *pdev, + int cat, int *active, + int *frms, int *bytes) +{ + struct ol_tx_sched_rr_t *scheduler = pdev->tx_sched.scheduler; + struct ol_tx_active_queues_in_tid_t *txq_queue; + + txq_queue = &scheduler->tx_active_queues_in_tid_array[cat]; + + *active = txq_queue->active; + *frms = txq_queue->frms; + *bytes = txq_queue->bytes; +} + +enum { + ol_tx_sched_discard_weight_voice = 1, + ol_tx_sched_discard_weight_video = 4, + ol_tx_sched_discard_weight_ucast_default = 8, + ol_tx_sched_discard_weight_mgmt_non_qos = 1, /* 0? */ + ol_tx_sched_discard_weight_mcast = 1, /* 0? also for probe & assoc */ +}; + +void * +ol_tx_sched_init_rr( + struct ol_txrx_pdev_t *pdev) +{ + struct ol_tx_sched_rr_t *scheduler; + int i; + + scheduler = qdf_mem_malloc(sizeof(struct ol_tx_sched_rr_t)); + if (scheduler == NULL) + return scheduler; + + for (i = 0; i < (OL_TX_NUM_TIDS + OL_TX_VDEV_NUM_QUEUES); i++) { + scheduler->tx_active_queues_in_tid_array[i].tid = i; + TAILQ_INIT(&scheduler->tx_active_queues_in_tid_array[i].head); + scheduler->tx_active_queues_in_tid_array[i].active = 0; + scheduler->tx_active_queues_in_tid_array[i].frms = 0; + scheduler->tx_active_queues_in_tid_array[i].bytes = 0; + } + for (i = 0; i < OL_TX_NUM_TIDS; i++) { + scheduler->tx_active_queues_in_tid_array[i].tid = i; + if (i < OL_TX_NON_QOS_TID) { + int ac = TXRX_TID_TO_WMM_AC(i); + switch (ac) { + case TXRX_WMM_AC_VO: + scheduler->discard_weights[i] = + ol_tx_sched_discard_weight_voice; + case TXRX_WMM_AC_VI: + scheduler->discard_weights[i] = + ol_tx_sched_discard_weight_video; + default: + scheduler->discard_weights[i] = + ol_tx_sched_discard_weight_ucast_default; + }; + } else { + scheduler->discard_weights[i] = + ol_tx_sched_discard_weight_mgmt_non_qos; + } + } + for (i = 0; i < OL_TX_VDEV_NUM_QUEUES; i++) { + int j = i + OL_TX_NUM_TIDS; + scheduler->tx_active_queues_in_tid_array[j].tid = + OL_TX_NUM_TIDS - 1; + scheduler->discard_weights[j] = + ol_tx_sched_discard_weight_mcast; + } + TAILQ_INIT(&scheduler->tx_active_tids_list); + + return scheduler; +} + +void +ol_txrx_set_wmm_param(ol_txrx_pdev_handle data_pdev, + struct ol_tx_wmm_param_t wmm_param) +{ + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_LOW, + "Dummy function when OL_TX_SCHED_RR is enabled\n"); +} + +/** + * ol_tx_sched_stats_display() - tx sched stats display + * @pdev: Pointer to the PDEV structure. + * + * Return: none. + */ +void ol_tx_sched_stats_display(struct ol_txrx_pdev_t *pdev) +{ +} + +/** + * ol_tx_sched_cur_state_display() - tx sched cur stat display + * @pdev: Pointer to the PDEV structure. + * + * Return: none. + */ +void ol_tx_sched_cur_state_display(struct ol_txrx_pdev_t *pdev) +{ +} + +/** + * ol_tx_sched_cur_state_display() - reset tx sched stats + * @pdev: Pointer to the PDEV structure. + * + * Return: none. + */ +void ol_tx_sched_stats_clear(struct ol_txrx_pdev_t *pdev) +{ +} + +#endif /* OL_TX_SCHED == OL_TX_SCHED_RR */ + +/*--- advanced scheduler ----------------------------------------------------*/ +#if OL_TX_SCHED == OL_TX_SCHED_WRR_ADV + +/*--- definitions ---*/ + +struct ol_tx_sched_wrr_adv_category_info_t { + struct { + int wrr_skip_weight; + u_int32_t credit_threshold; + u_int16_t send_limit; + int credit_reserve; + int discard_weight; + } specs; + struct { + int wrr_count; + int frms; + int bytes; + ol_tx_frms_queue_list head; + bool active; + } state; +#ifdef DEBUG_HL_LOGGING + struct { + char *cat_name; + unsigned int queued; + unsigned int dispatched; + unsigned int discard; + } stat; +#endif +}; + +#define OL_TX_SCHED_WRR_ADV_CAT_CFG_SPEC(cat, \ + wrr_skip_weight, \ + credit_threshold, \ + send_limit, \ + credit_reserve, \ + discard_weights) \ +enum { OL_TX_SCHED_WRR_ADV_ ## cat ## _WRR_SKIP_WEIGHT = \ + (wrr_skip_weight) }; \ +enum { OL_TX_SCHED_WRR_ADV_ ## cat ## _CREDIT_THRESHOLD = \ + (credit_threshold) }; \ +enum { OL_TX_SCHED_WRR_ADV_ ## cat ## _SEND_LIMIT = \ + (send_limit) }; \ +enum { OL_TX_SCHED_WRR_ADV_ ## cat ## _CREDIT_RESERVE = \ + (credit_reserve) }; \ +enum { OL_TX_SCHED_WRR_ADV_ ## cat ## _DISCARD_WEIGHT = \ + (discard_weights) } + +/* Rome: + * For high-volume traffic flows (VI, BE, BK), use a credit threshold + * roughly equal to a large A-MPDU (occupying half the target memory + * available for holding tx frames) to download AMPDU-sized batches + * of traffic. + * For high-priority, low-volume traffic flows (VO and mgmt), use no + * credit threshold, to minimize download latency. + */ +/* WRR send + * skip credit limit credit disc + * wts thresh (frms) reserv wts + */ +#ifdef HIF_SDIO +OL_TX_SCHED_WRR_ADV_CAT_CFG_SPEC(VO, 1, 17, 24, 0, 1); +OL_TX_SCHED_WRR_ADV_CAT_CFG_SPEC(VI, 3, 17, 16, 1, 4); +OL_TX_SCHED_WRR_ADV_CAT_CFG_SPEC(BE, 10, 17, 16, 1, 8); +OL_TX_SCHED_WRR_ADV_CAT_CFG_SPEC(BK, 12, 6, 6, 1, 8); +OL_TX_SCHED_WRR_ADV_CAT_CFG_SPEC(NON_QOS_DATA, 12, 6, 4, 1, 8); +OL_TX_SCHED_WRR_ADV_CAT_CFG_SPEC(UCAST_MGMT, 1, 1, 4, 0, 1); +OL_TX_SCHED_WRR_ADV_CAT_CFG_SPEC(MCAST_DATA, 10, 17, 4, 1, 4); +OL_TX_SCHED_WRR_ADV_CAT_CFG_SPEC(MCAST_MGMT, 1, 1, 4, 0, 1); +#else +OL_TX_SCHED_WRR_ADV_CAT_CFG_SPEC(VO, 1, 16, 24, 0, 1); +OL_TX_SCHED_WRR_ADV_CAT_CFG_SPEC(VI, 3, 16, 16, 1, 4); +OL_TX_SCHED_WRR_ADV_CAT_CFG_SPEC(BE, 10, 12, 12, 1, 8); +OL_TX_SCHED_WRR_ADV_CAT_CFG_SPEC(BK, 12, 6, 6, 1, 8); +OL_TX_SCHED_WRR_ADV_CAT_CFG_SPEC(NON_QOS_DATA, 12, 6, 4, 1, 8); +OL_TX_SCHED_WRR_ADV_CAT_CFG_SPEC(UCAST_MGMT, 1, 1, 4, 0, 1); +OL_TX_SCHED_WRR_ADV_CAT_CFG_SPEC(MCAST_DATA, 10, 16, 4, 1, 4); +OL_TX_SCHED_WRR_ADV_CAT_CFG_SPEC(MCAST_MGMT, 1, 1, 4, 0, 1); +#endif + +#ifdef DEBUG_HL_LOGGING + +#define OL_TX_SCHED_WRR_ADV_CAT_STAT_INIT(category, scheduler) \ + do { \ + scheduler->categories[OL_TX_SCHED_WRR_ADV_CAT_ ## category] \ + .stat.queued = 0; \ + scheduler->categories[OL_TX_SCHED_WRR_ADV_CAT_ ## category] \ + .stat.discard = 0; \ + scheduler->categories[OL_TX_SCHED_WRR_ADV_CAT_ ## category] \ + .stat.dispatched = 0; \ + scheduler->categories[OL_TX_SCHED_WRR_ADV_CAT_ ## category] \ + .stat.cat_name = #category; \ + } while (0) +#define OL_TX_SCHED_WRR_ADV_CAT_STAT_INC_QUEUED(category, frms) \ + do { \ + category->stat.queued += frms; \ + } while (0) +#define OL_TX_SCHED_WRR_ADV_CAT_STAT_INC_DISCARD(category, frms) \ + do { \ + category->stat.discard += frms; \ + } while (0) +#define OL_TX_SCHED_WRR_ADV_CAT_STAT_INC_DISPATCHED(category, frms) \ + do { \ + category->stat.dispatched += frms; \ + } while (0) +#define OL_TX_SCHED_WRR_ADV_CAT_STAT_DUMP(scheduler) \ + ol_tx_sched_wrr_adv_cat_stat_dump(scheduler) +#define OL_TX_SCHED_WRR_ADV_CAT_CUR_STATE_DUMP(scheduler) \ + ol_tx_sched_wrr_adv_cat_cur_state_dump(scheduler) +#define OL_TX_SCHED_WRR_ADV_CAT_STAT_CLEAR(scheduler) \ + ol_tx_sched_wrr_adv_cat_stat_clear(scheduler) + +#else /* DEBUG_HL_LOGGING */ + +#define OL_TX_SCHED_WRR_ADV_CAT_STAT_INIT(category, scheduler) +#define OL_TX_SCHED_WRR_ADV_CAT_STAT_INC_QUEUED(category, frms) +#define OL_TX_SCHED_WRR_ADV_CAT_STAT_INC_DISCARD(category, frms) +#define OL_TX_SCHED_WRR_ADV_CAT_STAT_INC_DISPATCHED(category, frms) +#define OL_TX_SCHED_WRR_ADV_CAT_STAT_DUMP(scheduler) +#define OL_TX_SCHED_WRR_ADV_CAT_CUR_STATE_DUMP(scheduler) +#define OL_TX_SCHED_WRR_ADV_CAT_STAT_CLEAR(scheduler) + +#endif /* DEBUG_HL_LOGGING */ + +#define OL_TX_SCHED_WRR_ADV_CAT_CFG_STORE(category, scheduler) \ + do { \ + scheduler->categories[OL_TX_SCHED_WRR_ADV_CAT_ ## category] \ + .specs.wrr_skip_weight = \ + OL_TX_SCHED_WRR_ADV_ ## category ## _WRR_SKIP_WEIGHT; \ + scheduler->categories[OL_TX_SCHED_WRR_ADV_CAT_ ## category] \ + .specs.credit_threshold = \ + OL_TX_SCHED_WRR_ADV_ ## category ## _CREDIT_THRESHOLD; \ + scheduler->categories[OL_TX_SCHED_WRR_ADV_CAT_ ## category] \ + .specs.send_limit = \ + OL_TX_SCHED_WRR_ADV_ ## category ## _SEND_LIMIT; \ + scheduler->categories[OL_TX_SCHED_WRR_ADV_CAT_ ## category] \ + .specs.credit_reserve = \ + OL_TX_SCHED_WRR_ADV_ ## category ## _CREDIT_RESERVE; \ + scheduler->categories[OL_TX_SCHED_WRR_ADV_CAT_ ## category] \ + .specs.discard_weight = \ + OL_TX_SCHED_WRR_ADV_ ## category ## _DISCARD_WEIGHT; \ + OL_TX_SCHED_WRR_ADV_CAT_STAT_INIT(category, scheduler); \ + } while (0) + +struct ol_tx_sched_wrr_adv_t { + int order[OL_TX_SCHED_WRR_ADV_NUM_CATEGORIES]; + int index; + struct ol_tx_sched_wrr_adv_category_info_t + categories[OL_TX_SCHED_WRR_ADV_NUM_CATEGORIES]; +}; + +#define OL_TX_AIFS_DEFAULT_VO 2 +#define OL_TX_AIFS_DEFAULT_VI 2 +#define OL_TX_AIFS_DEFAULT_BE 3 +#define OL_TX_AIFS_DEFAULT_BK 7 +#define OL_TX_CW_MIN_DEFAULT_VO 3 +#define OL_TX_CW_MIN_DEFAULT_VI 7 +#define OL_TX_CW_MIN_DEFAULT_BE 15 +#define OL_TX_CW_MIN_DEFAULT_BK 15 + +/*--- functions ---*/ + +#ifdef DEBUG_HL_LOGGING +static void ol_tx_sched_wrr_adv_cat_stat_dump( + struct ol_tx_sched_wrr_adv_t *scheduler) +{ + int i; + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "Scheduler Stats:"); + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "====category(CRR,CRT,WSW): Queued Discard Dequeued frms wrr==="); + for (i = 0; i < OL_TX_SCHED_WRR_ADV_NUM_CATEGORIES; ++i) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "%12s(%2d, %2d, %2d): %6d %7d %8d %4d %3d", + scheduler->categories[i].stat.cat_name, + scheduler->categories[i].specs.credit_reserve, + scheduler->categories[i].specs.credit_threshold, + scheduler->categories[i].specs.wrr_skip_weight, + scheduler->categories[i].stat.queued, + scheduler->categories[i].stat.discard, + scheduler->categories[i].stat.dispatched, + scheduler->categories[i].state.frms, + scheduler->categories[i].state.wrr_count); + } +} + +static void ol_tx_sched_wrr_adv_cat_cur_state_dump( + struct ol_tx_sched_wrr_adv_t *scheduler) +{ + int i; + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "Scheduler State Snapshot:"); + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "====category(CRR,CRT,WSW): IS_Active Pend_Frames Pend_bytes wrr==="); + for (i = 0; i < OL_TX_SCHED_WRR_ADV_NUM_CATEGORIES; ++i) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "%12s(%2d, %2d, %2d): %9d %11d %10d %3d", + scheduler->categories[i].stat.cat_name, + scheduler->categories[i].specs.credit_reserve, + scheduler->categories[i].specs.credit_threshold, + scheduler->categories[i].specs.wrr_skip_weight, + scheduler->categories[i].state.active, + scheduler->categories[i].state.frms, + scheduler->categories[i].state.bytes, + scheduler->categories[i].state.wrr_count); + } +} + +static void ol_tx_sched_wrr_adv_cat_stat_clear( + struct ol_tx_sched_wrr_adv_t *scheduler) +{ + int i; + for (i = 0; i < OL_TX_SCHED_WRR_ADV_NUM_CATEGORIES; ++i) { + scheduler->categories[i].stat.queued = 0; + scheduler->categories[i].stat.discard = 0; + scheduler->categories[i].stat.dispatched = 0; + } +} + +#endif + +static void +ol_tx_sched_select_init_wrr_adv(struct ol_txrx_pdev_t *pdev) +{ + struct ol_tx_sched_wrr_adv_t *scheduler = pdev->tx_sched.scheduler; + /* start selection from the front of the ordered list */ + scheduler->index = 0; + pdev->tx_sched.last_used_txq = NULL; +} + +static void +ol_tx_sched_wrr_adv_rotate_order_list_tail( + struct ol_tx_sched_wrr_adv_t *scheduler, int idx) +{ + int value; + /* remember the value of the specified element */ + value = scheduler->order[idx]; + /* shift all further elements up one space */ + for (; idx < OL_TX_SCHED_WRR_ADV_NUM_CATEGORIES-1; idx++) + scheduler->order[idx] = scheduler->order[idx + 1]; + + /* put the specified element at the end */ + scheduler->order[idx] = value; +} + +static void +ol_tx_sched_wrr_adv_credit_sanity_check(struct ol_txrx_pdev_t *pdev, + u_int32_t credit) +{ + struct ol_tx_sched_wrr_adv_t *scheduler = pdev->tx_sched.scheduler; + int i; + int okay = 1; + + for (i = 0; i < OL_TX_SCHED_WRR_ADV_NUM_CATEGORIES; i++) { + if (scheduler->categories[i].specs.credit_threshold > credit) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "*** Config error: credit (%d) not enough to support category %d threshold (%d)\n", + credit, i, + scheduler->categories[i].specs. + credit_threshold); + okay = 0; + } + } + qdf_assert(okay); +} + +/* + * The scheduler sync spinlock has been acquired outside this function, + * so there is no need to worry about mutex within this function. + */ +static int +ol_tx_sched_select_batch_wrr_adv( + struct ol_txrx_pdev_t *pdev, + struct ol_tx_sched_ctx *sctx, + u_int32_t credit) +{ + static int first = 1; + int category_index = 0; + struct ol_tx_sched_wrr_adv_t *scheduler = pdev->tx_sched.scheduler; + struct ol_tx_frms_queue_t *txq; + int index; + struct ol_tx_sched_wrr_adv_category_info_t *category = NULL; + int frames, bytes, used_credits = 0, tx_limit; + u_int16_t tx_limit_flag; + + /* + * Just for good measure, do a sanity check that the initial credit + * is enough to cover every category's credit threshold. + */ + if (first) { + first = 0; + ol_tx_sched_wrr_adv_credit_sanity_check(pdev, credit); + } + + /* choose the traffic category from the ordered list */ + index = scheduler->index; + while (index < OL_TX_SCHED_WRR_ADV_NUM_CATEGORIES) { + category_index = scheduler->order[index]; + category = &scheduler->categories[category_index]; + if (!category->state.active) { + /* move on to the next category */ + index++; + continue; + } + if (++category->state.wrr_count < + category->specs.wrr_skip_weight) { + /* skip this cateogry (move it to the back) */ + ol_tx_sched_wrr_adv_rotate_order_list_tail(scheduler, + index); + /* try again (iterate) on the new element + *that was moved up */ + continue; + } + /* found the first active category whose WRR turn is present */ + break; + } + if (index >= OL_TX_SCHED_WRR_ADV_NUM_CATEGORIES) { + /* no categories are active */ + return 0; + } + + /* is there enough credit for the selected category? */ + if (credit < category->specs.credit_threshold) { + /* + * Can't send yet - wait until more credit becomes available. + * In the meantime, restore the WRR counter (since we didn't + * service this category after all). + */ + category->state.wrr_count = category->state.wrr_count - 1; + return 0; + } + /* enough credit is available - go ahead and send some frames */ + /* + * This category was serviced - reset the WRR counter, and move this + * category to the back of the order list. + */ + category->state.wrr_count = 0; + ol_tx_sched_wrr_adv_rotate_order_list_tail(scheduler, index); + /* + * With this category moved to the back, if there's still any credit + * left, set up the next invocation of this function to start from + * where this one left off, by looking at the category that just got + * shifted forward into the position the service category was + * occupying. + */ + scheduler->index = index; + + /* + * Take the tx queue from the head of the category list. + */ + txq = TAILQ_FIRST(&category->state.head); + + if (txq) { + TAILQ_REMOVE(&category->state.head, txq, list_elem); + credit = ol_tx_txq_group_credit_limit(pdev, txq, credit); + if (credit > category->specs.credit_reserve) { + credit -= category->specs.credit_reserve; + /* + * this tx queue will download some frames, + * so update last_used_txq + */ + pdev->tx_sched.last_used_txq = txq; + + tx_limit = ol_tx_bad_peer_dequeue_check(txq, + category->specs.send_limit, + &tx_limit_flag); + frames = ol_tx_dequeue( + pdev, txq, &sctx->head, + tx_limit, &credit, &bytes); + ol_tx_bad_peer_update_tx_limit(pdev, txq, + frames, + tx_limit_flag); + + OL_TX_SCHED_WRR_ADV_CAT_STAT_INC_DISPATCHED(category, + frames); + used_credits = credit; + category->state.frms -= frames; + category->state.bytes -= bytes; + if (txq->frms > 0) { + TAILQ_INSERT_TAIL(&category->state.head, + txq, list_elem); + } else { + if (category->state.frms == 0) + category->state.active = 0; + } + sctx->frms += frames; + ol_tx_txq_group_credit_update(pdev, txq, -credit, 0); + } else { + if (ol_tx_is_txq_last_serviced_queue(pdev, txq)) { + /* + * The scheduler has looked at all the active + * tx queues but none were able to download any + * of their tx frames. + * Nothing is changed, so if none were able + * to download before, + * they wont be able to download now. + * Return that no credit has been used, which + * will cause the scheduler to stop. + */ + TAILQ_INSERT_HEAD(&category->state.head, txq, + list_elem); + return 0; + } else { + TAILQ_INSERT_TAIL(&category->state.head, txq, + list_elem); + if (!pdev->tx_sched.last_used_txq) + pdev->tx_sched.last_used_txq = txq; + } + } + TX_SCHED_DEBUG_PRINT("Leave %s\n", __func__); + } else { + used_credits = 0; + /* TODO: find its reason */ + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "ol_tx_sched_select_batch_wrr_adv: error, no TXQ can be popped."); + } + return used_credits; +} + +static inline void +ol_tx_sched_txq_enqueue_wrr_adv( + struct ol_txrx_pdev_t *pdev, + struct ol_tx_frms_queue_t *txq, + int tid, + int frms, + int bytes) +{ + struct ol_tx_sched_wrr_adv_t *scheduler = pdev->tx_sched.scheduler; + struct ol_tx_sched_wrr_adv_category_info_t *category; + + category = &scheduler->categories[pdev->tid_to_ac[tid]]; + category->state.frms += frms; + category->state.bytes += bytes; + OL_TX_SCHED_WRR_ADV_CAT_STAT_INC_QUEUED(category, frms); + if (txq->flag != ol_tx_queue_active) { + TAILQ_INSERT_TAIL(&category->state.head, txq, list_elem); + category->state.active = 1; /* may have already been active */ + } +} + +static inline void +ol_tx_sched_txq_deactivate_wrr_adv( + struct ol_txrx_pdev_t *pdev, + struct ol_tx_frms_queue_t *txq, + int tid) +{ + struct ol_tx_sched_wrr_adv_t *scheduler = pdev->tx_sched.scheduler; + struct ol_tx_sched_wrr_adv_category_info_t *category; + + category = &scheduler->categories[pdev->tid_to_ac[tid]]; + category->state.frms -= txq->frms; + category->state.bytes -= txq->bytes; + + TAILQ_REMOVE(&category->state.head, txq, list_elem); + + if (category->state.frms == 0 && category->state.active) + category->state.active = 0; +} + +ol_tx_frms_queue_list * +ol_tx_sched_category_tx_queues_wrr_adv(struct ol_txrx_pdev_t *pdev, int cat) +{ + struct ol_tx_sched_wrr_adv_t *scheduler = pdev->tx_sched.scheduler; + struct ol_tx_sched_wrr_adv_category_info_t *category; + + category = &scheduler->categories[cat]; + return &category->state.head; +} + +int +ol_tx_sched_discard_select_category_wrr_adv(struct ol_txrx_pdev_t *pdev) +{ + struct ol_tx_sched_wrr_adv_t *scheduler; + u_int8_t i, cat = 0; + int max_score = 0; + + scheduler = pdev->tx_sched.scheduler; + /* + * Choose which category's tx frames to drop next based on two factors: + * 1. Which category has the most tx frames present + * 2. The category's priority (high-priority categories have a low + * discard_weight) + */ + for (i = 0; i < OL_TX_SCHED_WRR_ADV_NUM_CATEGORIES; i++) { + int score; + score = + scheduler->categories[i].state.frms * + scheduler->categories[i].specs.discard_weight; + if (max_score == 0 || score > max_score) { + max_score = score; + cat = i; + } + } + return cat; +} + +void +ol_tx_sched_txq_discard_wrr_adv( + struct ol_txrx_pdev_t *pdev, + struct ol_tx_frms_queue_t *txq, + int cat, int frames, int bytes) +{ + struct ol_tx_sched_wrr_adv_t *scheduler = pdev->tx_sched.scheduler; + struct ol_tx_sched_wrr_adv_category_info_t *category; + + category = &scheduler->categories[cat]; + + if (0 == txq->frms) + TAILQ_REMOVE(&category->state.head, txq, list_elem); + + + category->state.frms -= frames; + category->state.bytes -= bytes; + OL_TX_SCHED_WRR_ADV_CAT_STAT_INC_DISCARD(category, frames); + if (category->state.frms == 0) + category->state.active = 0; +} + +void +ol_tx_sched_category_info_wrr_adv( + struct ol_txrx_pdev_t *pdev, + int cat, int *active, + int *frms, int *bytes) +{ + struct ol_tx_sched_wrr_adv_t *scheduler = pdev->tx_sched.scheduler; + struct ol_tx_sched_wrr_adv_category_info_t *category; + + category = &scheduler->categories[cat]; + *active = category->state.active; + *frms = category->state.frms; + *bytes = category->state.bytes; +} + +/** + * ol_tx_sched_wrr_param_update() - update the WRR TX sched params + * @pdev: Pointer to PDEV structure. + * @scheduler: Pointer to tx scheduler. + * + * Update the WRR TX schedule parameters for each category if it is + * specified in the ini file by user. + * + * Return: none + */ +void ol_tx_sched_wrr_param_update(struct ol_txrx_pdev_t *pdev, + struct ol_tx_sched_wrr_adv_t *scheduler) +{ + int i; + char *tx_sched_wrr_name[4] = { + "BE", + "BK", + "VI", + "VO" + }; + + if (NULL == scheduler) + return; + + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO, + "%s: Tuning the TX scheduler wrr parameters by ini file:", + __func__); + + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO, + " skip credit limit credit disc"); + + for (i = OL_TX_SCHED_WRR_ADV_CAT_BE; + i <= OL_TX_SCHED_WRR_ADV_CAT_VO; i++) { + if (ol_cfg_get_wrr_skip_weight(pdev->ctrl_pdev, i)) { + scheduler->categories[i].specs.wrr_skip_weight = + ol_cfg_get_wrr_skip_weight(pdev->ctrl_pdev, i); + scheduler->categories[i].specs.credit_threshold = + ol_cfg_get_credit_threshold(pdev->ctrl_pdev, i); + scheduler->categories[i].specs.send_limit = + ol_cfg_get_send_limit(pdev->ctrl_pdev, i); + scheduler->categories[i].specs.credit_reserve = + ol_cfg_get_credit_reserve(pdev->ctrl_pdev, i); + scheduler->categories[i].specs.discard_weight = + ol_cfg_get_discard_weight(pdev->ctrl_pdev, i); + + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO, + "%s-update: %d, %d, %d, %d, %d", + tx_sched_wrr_name[i], + scheduler->categories[i].specs.wrr_skip_weight, + scheduler->categories[i].specs.credit_threshold, + scheduler->categories[i].specs.send_limit, + scheduler->categories[i].specs.credit_reserve, + scheduler->categories[i].specs.discard_weight); + } else { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO, + "%s-orig: %d, %d, %d, %d, %d", + tx_sched_wrr_name[i], + scheduler->categories[i].specs.wrr_skip_weight, + scheduler->categories[i].specs.credit_threshold, + scheduler->categories[i].specs.send_limit, + scheduler->categories[i].specs.credit_reserve, + scheduler->categories[i].specs.discard_weight); + } + } +} + +void * +ol_tx_sched_init_wrr_adv( + struct ol_txrx_pdev_t *pdev) +{ + struct ol_tx_sched_wrr_adv_t *scheduler; + int i; + + scheduler = qdf_mem_malloc( + sizeof(struct ol_tx_sched_wrr_adv_t)); + if (scheduler == NULL) + return scheduler; + + OL_TX_SCHED_WRR_ADV_CAT_CFG_STORE(VO, scheduler); + OL_TX_SCHED_WRR_ADV_CAT_CFG_STORE(VI, scheduler); + OL_TX_SCHED_WRR_ADV_CAT_CFG_STORE(BE, scheduler); + OL_TX_SCHED_WRR_ADV_CAT_CFG_STORE(BK, scheduler); + OL_TX_SCHED_WRR_ADV_CAT_CFG_STORE(NON_QOS_DATA, scheduler); + OL_TX_SCHED_WRR_ADV_CAT_CFG_STORE(UCAST_MGMT, scheduler); + OL_TX_SCHED_WRR_ADV_CAT_CFG_STORE(MCAST_DATA, scheduler); + OL_TX_SCHED_WRR_ADV_CAT_CFG_STORE(MCAST_MGMT, scheduler); + + ol_tx_sched_wrr_param_update(pdev, scheduler); + + for (i = 0; i < OL_TX_SCHED_WRR_ADV_NUM_CATEGORIES; i++) { + scheduler->categories[i].state.active = 0; + scheduler->categories[i].state.frms = 0; + /*scheduler->categories[i].state.bytes = 0;*/ + TAILQ_INIT(&scheduler->categories[i].state.head); + /* init categories to not be skipped before + *their initial selection */ + scheduler->categories[i].state.wrr_count = + scheduler->categories[i].specs.wrr_skip_weight - 1; + } + + /* + * Init the order array - the initial ordering doesn't matter, as the + * order array will get reshuffled as data arrives. + */ + for (i = 0; i < OL_TX_SCHED_WRR_ADV_NUM_CATEGORIES; i++) + scheduler->order[i] = i; + + return scheduler; +} + + +/* WMM parameters are suppposed to be passed when associate with AP. + * According to AIFS+CWMin, the function maps each queue to one of four default + * settings of the scheduler, ie. VO, VI, BE, or BK. + */ +void +ol_txrx_set_wmm_param(ol_txrx_pdev_handle data_pdev, + struct ol_tx_wmm_param_t wmm_param) +{ + struct ol_tx_sched_wrr_adv_t def_cfg; + struct ol_tx_sched_wrr_adv_t *scheduler = + data_pdev->tx_sched.scheduler; + u_int32_t i, ac_selected; + u_int32_t weight[OL_TX_NUM_WMM_AC], default_edca[OL_TX_NUM_WMM_AC]; + + OL_TX_SCHED_WRR_ADV_CAT_CFG_STORE(VO, (&def_cfg)); + OL_TX_SCHED_WRR_ADV_CAT_CFG_STORE(VI, (&def_cfg)); + OL_TX_SCHED_WRR_ADV_CAT_CFG_STORE(BE, (&def_cfg)); + OL_TX_SCHED_WRR_ADV_CAT_CFG_STORE(BK, (&def_cfg)); + + /* default_eca = AIFS + CWMin */ + default_edca[OL_TX_SCHED_WRR_ADV_CAT_VO] = + OL_TX_AIFS_DEFAULT_VO + OL_TX_CW_MIN_DEFAULT_VO; + default_edca[OL_TX_SCHED_WRR_ADV_CAT_VI] = + OL_TX_AIFS_DEFAULT_VI + OL_TX_CW_MIN_DEFAULT_VI; + default_edca[OL_TX_SCHED_WRR_ADV_CAT_BE] = + OL_TX_AIFS_DEFAULT_BE + OL_TX_CW_MIN_DEFAULT_BE; + default_edca[OL_TX_SCHED_WRR_ADV_CAT_BK] = + OL_TX_AIFS_DEFAULT_BK + OL_TX_CW_MIN_DEFAULT_BK; + + weight[OL_TX_SCHED_WRR_ADV_CAT_VO] = + wmm_param.ac[OL_TX_WMM_AC_VO].aifs + + wmm_param.ac[OL_TX_WMM_AC_VO].cwmin; + weight[OL_TX_SCHED_WRR_ADV_CAT_VI] = + wmm_param.ac[OL_TX_WMM_AC_VI].aifs + + wmm_param.ac[OL_TX_WMM_AC_VI].cwmin; + weight[OL_TX_SCHED_WRR_ADV_CAT_BK] = + wmm_param.ac[OL_TX_WMM_AC_BK].aifs + + wmm_param.ac[OL_TX_WMM_AC_BK].cwmin; + weight[OL_TX_SCHED_WRR_ADV_CAT_BE] = + wmm_param.ac[OL_TX_WMM_AC_BE].aifs + + wmm_param.ac[OL_TX_WMM_AC_BE].cwmin; + + for (i = 0; i < OL_TX_NUM_WMM_AC; i++) { + if (default_edca[OL_TX_SCHED_WRR_ADV_CAT_VO] >= weight[i]) + ac_selected = OL_TX_SCHED_WRR_ADV_CAT_VO; + else if (default_edca[OL_TX_SCHED_WRR_ADV_CAT_VI] >= weight[i]) + ac_selected = OL_TX_SCHED_WRR_ADV_CAT_VI; + else if (default_edca[OL_TX_SCHED_WRR_ADV_CAT_BE] >= weight[i]) + ac_selected = OL_TX_SCHED_WRR_ADV_CAT_BE; + else + ac_selected = OL_TX_SCHED_WRR_ADV_CAT_BK; + + + scheduler->categories[i].specs.wrr_skip_weight = + def_cfg.categories[ac_selected].specs.wrr_skip_weight; + scheduler->categories[i].specs.credit_threshold = + def_cfg.categories[ac_selected].specs.credit_threshold; + scheduler->categories[i].specs.send_limit = + def_cfg.categories[ac_selected].specs.send_limit; + scheduler->categories[i].specs.credit_reserve = + def_cfg.categories[ac_selected].specs.credit_reserve; + scheduler->categories[i].specs.discard_weight = + def_cfg.categories[ac_selected].specs.discard_weight; + } +} + +/** + * ol_tx_sched_stats_display() - tx sched stats display + * @pdev: Pointer to the PDEV structure. + * + * Return: none. + */ +void ol_tx_sched_stats_display(struct ol_txrx_pdev_t *pdev) +{ + OL_TX_SCHED_WRR_ADV_CAT_STAT_DUMP(pdev->tx_sched.scheduler); +} + +/** + * ol_tx_sched_cur_state_display() - tx sched cur stat display + * @pdev: Pointer to the PDEV structure. + * + * Return: none. + */ +void ol_tx_sched_cur_state_display(struct ol_txrx_pdev_t *pdev) +{ + OL_TX_SCHED_WRR_ADV_CAT_CUR_STATE_DUMP(pdev->tx_sched.scheduler); +} + +/** + * ol_tx_sched_cur_state_display() - reset tx sched stats + * @pdev: Pointer to the PDEV structure. + * + * Return: none. + */ +void ol_tx_sched_stats_clear(struct ol_txrx_pdev_t *pdev) +{ + OL_TX_SCHED_WRR_ADV_CAT_STAT_CLEAR(pdev->tx_sched.scheduler); +} + +#endif /* OL_TX_SCHED == OL_TX_SCHED_WRR_ADV */ + +/*--- congestion control discard --------------------------------------------*/ + +struct ol_tx_frms_queue_t * +ol_tx_sched_discard_select_txq( + struct ol_txrx_pdev_t *pdev, + ol_tx_frms_queue_list *tx_queues) +{ + struct ol_tx_frms_queue_t *txq; + struct ol_tx_frms_queue_t *selected_txq = NULL; + int max_frms = 0; + + /* return the tx queue with the most frames */ + TAILQ_FOREACH(txq, tx_queues, list_elem) { + if (txq->frms > max_frms) { + max_frms = txq->frms; + selected_txq = txq; + } + } + return selected_txq; +} + +u_int16_t +ol_tx_sched_discard_select( + struct ol_txrx_pdev_t *pdev, + u_int16_t frms, + ol_tx_desc_list *tx_descs, + bool force) +{ + int cat; + struct ol_tx_frms_queue_t *txq; + int bytes; + u_int32_t credit; + struct ol_tx_sched_notify_ctx_t notify_ctx; + + /* first decide what category of traffic (e.g. TID or AC) + *to discard next */ + cat = ol_tx_sched_discard_select_category(pdev); + + /* then decide which peer within this category to discard from next */ + txq = ol_tx_sched_discard_select_txq( + pdev, ol_tx_sched_category_tx_queues(pdev, cat)); + if (NULL == txq) + /* No More pending Tx Packets in Tx Queue. Exit Discard loop */ + return 0; + + + if (force == false) { + /* + * Now decide how many frames to discard from this peer-TID. + * Don't discard more frames than the caller has specified. + * Don't discard more than a fixed quantum of frames at a time. + * Don't discard more than 50% of the queue's frames at a time, + * but if there's only 1 frame left, go ahead and discard it. + */ +#define OL_TX_DISCARD_QUANTUM 10 + if (OL_TX_DISCARD_QUANTUM < frms) + frms = OL_TX_DISCARD_QUANTUM; + + + if (txq->frms > 1 && frms >= (txq->frms >> 1)) + frms = txq->frms >> 1; + } + + /* + * Discard from the head of the queue, because: + * 1. Front-dropping gives applications like TCP that include ARQ + * an early notification of congestion. + * 2. For time-sensitive applications like RTP, the newest frames are + * most relevant. + */ + credit = 10000; /* no credit limit */ + frms = ol_tx_dequeue(pdev, txq, tx_descs, frms, &credit, &bytes); + + notify_ctx.event = OL_TX_DISCARD_FRAMES; + notify_ctx.frames = frms; + notify_ctx.bytes = bytes; + notify_ctx.txq = txq; + notify_ctx.info.ext_tid = cat; + ol_tx_sched_notify(pdev, ¬ify_ctx); + + TX_SCHED_DEBUG_PRINT("%s Tx Drop : %d\n", __func__, frms); + return frms; +} + +/*--- scheduler framework ---------------------------------------------------*/ + +/* + * The scheduler mutex spinlock has been acquired outside this function, + * so there is need to take locks inside this function. + */ +void +ol_tx_sched_notify( + struct ol_txrx_pdev_t *pdev, + struct ol_tx_sched_notify_ctx_t *ctx) +{ + struct ol_tx_frms_queue_t *txq = ctx->txq; + int tid; + + if (!pdev->tx_sched.scheduler) + return; + + switch (ctx->event) { + case OL_TX_ENQUEUE_FRAME: + tid = ctx->info.tx_msdu_info->htt.info.ext_tid; + ol_tx_sched_txq_enqueue(pdev, txq, tid, 1, ctx->bytes); + break; + case OL_TX_DELETE_QUEUE: + tid = ctx->info.ext_tid; + if (txq->flag == ol_tx_queue_active) + ol_tx_sched_txq_deactivate(pdev, txq, tid); + + break; + case OL_TX_PAUSE_QUEUE: + tid = ctx->info.ext_tid; + if (txq->flag == ol_tx_queue_active) + ol_tx_sched_txq_deactivate(pdev, txq, tid); + + break; + case OL_TX_UNPAUSE_QUEUE: + tid = ctx->info.ext_tid; + if (txq->frms != 0) + ol_tx_sched_txq_enqueue(pdev, txq, tid, + txq->frms, txq->bytes); + + break; + case OL_TX_DISCARD_FRAMES: + /* not necessarily TID, could be category */ + tid = ctx->info.ext_tid; + ol_tx_sched_txq_discard(pdev, txq, tid, + ctx->frames, ctx->bytes); + break; + default: + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "Error: unknown sched notification (%d)\n", + ctx->event); + qdf_assert(0); + break; + } +} + +#define OL_TX_MSDU_ID_STORAGE_ERR(ptr) (NULL == ptr) + +void +ol_tx_sched_dispatch( + struct ol_txrx_pdev_t *pdev, + struct ol_tx_sched_ctx *sctx) +{ + qdf_nbuf_t msdu, prev = NULL, head_msdu = NULL; + struct ol_tx_desc_t *tx_desc; + + u_int16_t *msdu_id_storage; + u_int16_t msdu_id; + int num_msdus = 0; + TX_SCHED_DEBUG_PRINT("Enter %s\n", __func__); + while (sctx->frms) { + tx_desc = TAILQ_FIRST(&sctx->head); + if (tx_desc == NULL) { + /* TODO: find its reason */ + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "%s: err, no enough tx_desc from stx->head.\n", + __func__); + break; + } + msdu = tx_desc->netbuf; + TAILQ_REMOVE(&sctx->head, tx_desc, tx_desc_list_elem); + if (NULL == head_msdu) + head_msdu = msdu; + + if (prev) + qdf_nbuf_set_next(prev, msdu); + + prev = msdu; + +#ifndef ATH_11AC_TXCOMPACT + /* + * When the tx frame is downloaded to the target, there are two + * outstanding references: + * 1. The host download SW (HTT, HTC, HIF) + * This reference is cleared by the ol_tx_send_done callback + * functions. + * 2. The target FW + * This reference is cleared by the ol_tx_completion_handler + * function. + * It is extremely probable that the download completion is + * processed before the tx completion message. However, under + * exceptional conditions the tx completion may be processed + *first. Thus, rather that assuming that reference (1) is + *done before reference (2), + * explicit reference tracking is needed. + * Double-increment the ref count to account for both references + * described above. + */ + qdf_atomic_init(&tx_desc->ref_cnt); + qdf_atomic_inc(&tx_desc->ref_cnt); + qdf_atomic_inc(&tx_desc->ref_cnt); +#endif + + /*Store the MSDU Id for each MSDU*/ + /* store MSDU ID */ + msdu_id = ol_tx_desc_id(pdev, tx_desc); + msdu_id_storage = ol_tx_msdu_id_storage(msdu); + if (OL_TX_MSDU_ID_STORAGE_ERR(msdu_id_storage)) { + /* + * Send the prior frames as a batch, + *then send this as a single, + * then resume handling the remaining frames. + */ + if (head_msdu) + ol_tx_send_batch(pdev, head_msdu, num_msdus); + + prev = NULL; + head_msdu = prev; + num_msdus = 0; + + if (htt_tx_send_std(pdev->htt_pdev, msdu, msdu_id)) { + ol_tx_target_credit_incr(pdev, msdu); + ol_tx_desc_frame_free_nonstd(pdev, tx_desc, + 1 /* error */); + } + } else { + *msdu_id_storage = msdu_id; + num_msdus++; + } + sctx->frms--; + } + + /*Send Batch Of Frames*/ + if (head_msdu) + ol_tx_send_batch(pdev, head_msdu, num_msdus); + TX_SCHED_DEBUG_PRINT("Leave %s\n", __func__); +} + + void +ol_tx_sched(struct ol_txrx_pdev_t *pdev) +{ + struct ol_tx_sched_ctx sctx; + u_int32_t credit; + + TX_SCHED_DEBUG_PRINT("Enter %s\n", __func__); + qdf_spin_lock_bh(&pdev->tx_queue_spinlock); + if (pdev->tx_sched.tx_sched_status != ol_tx_scheduler_idle) { + qdf_spin_unlock_bh(&pdev->tx_queue_spinlock); + return; + } + pdev->tx_sched.tx_sched_status = ol_tx_scheduler_running; + + ol_tx_sched_log(pdev); + /*adf_os_print("BEFORE tx sched:\n");*/ + /*ol_tx_queues_display(pdev);*/ + qdf_spin_unlock_bh(&pdev->tx_queue_spinlock); + + TAILQ_INIT(&sctx.head); + sctx.frms = 0; + + ol_tx_sched_select_init(pdev); + while (qdf_atomic_read(&pdev->target_tx_credit) > 0) { + int num_credits; + qdf_spin_lock_bh(&pdev->tx_queue_spinlock); + credit = qdf_atomic_read(&pdev->target_tx_credit); + num_credits = ol_tx_sched_select_batch(pdev, &sctx, credit); + if (num_credits > 0) { +#if DEBUG_HTT_CREDIT + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO, + " Decrease credit %d - %d = %d.\n", + qdf_atomic_read(&pdev->target_tx_credit), + num_credits, + qdf_atomic_read(&pdev->target_tx_credit) - + num_credits); +#endif + qdf_atomic_add(-num_credits, &pdev->target_tx_credit); + } + qdf_spin_unlock_bh(&pdev->tx_queue_spinlock); + + if (num_credits == 0) + break; + } + ol_tx_sched_dispatch(pdev, &sctx); + + qdf_spin_lock_bh(&pdev->tx_queue_spinlock); + /*adf_os_print("AFTER tx sched:\n");*/ + /*ol_tx_queues_display(pdev);*/ + + pdev->tx_sched.tx_sched_status = ol_tx_scheduler_idle; + qdf_spin_unlock_bh(&pdev->tx_queue_spinlock); + TX_SCHED_DEBUG_PRINT("Leave %s\n", __func__); +} + +void * +ol_tx_sched_attach( + struct ol_txrx_pdev_t *pdev) +{ + pdev->tx_sched.tx_sched_status = ol_tx_scheduler_idle; + return ol_tx_sched_init(pdev); +} + +void +ol_tx_sched_detach( + struct ol_txrx_pdev_t *pdev) +{ + if (pdev->tx_sched.scheduler) { + qdf_mem_free(pdev->tx_sched.scheduler); + pdev->tx_sched.scheduler = NULL; + } +} + +/*--- debug functions -------------------------------------------------------*/ + +#if defined(DEBUG_HL_LOGGING) + +static void +ol_tx_sched_log(struct ol_txrx_pdev_t *pdev) +{ + u_int8_t *buf; + u_int32_t *active_bitmap; + int i, j, num_cats_active; + int active, frms, bytes; + int credit; + + /* don't bother recording state if credit is zero */ + credit = qdf_atomic_read(&pdev->target_tx_credit); + if (credit == 0) + return; + + + /* + * See how many TIDs are active, so queue state can be stored only + * for those TIDs. + * Do an initial iteration through all categories to see if any + * are active. Doing an extra iteration is inefficient, but + * efficiency is not a dominant concern when logging is enabled. + */ + num_cats_active = 0; + for (i = 0; i < OL_TX_SCHED_NUM_CATEGORIES; i++) { + ol_tx_sched_category_info(pdev, i, &active, &frms, &bytes); + if (active) + num_cats_active++; + } + /* don't bother recording state if there are no active queues */ + if (num_cats_active == 0) + return; + + + ol_tx_queue_log_sched(pdev, credit, &num_cats_active, + &active_bitmap, &buf); + + if (num_cats_active == 0) + return; + + *active_bitmap = 0; + for (i = 0, j = 0; + i < OL_TX_SCHED_NUM_CATEGORIES && j < num_cats_active; + i++) { + u_int8_t *p; + ol_tx_sched_category_info(pdev, i, &active, &frms, &bytes); + if (!active) + continue; + + p = &buf[j*6]; + p[0] = (frms >> 0) & 0xff; + p[1] = (frms >> 8) & 0xff; + + p[2] = (bytes >> 0) & 0xff; + p[3] = (bytes >> 8) & 0xff; + p[4] = (bytes >> 16) & 0xff; + p[5] = (bytes >> 24) & 0xff; + j++; + *active_bitmap |= 1 << i; + } +} + +#endif /* defined(DEBUG_HL_LOGGING) */ + +#endif /* defined(CONFIG_HL_SUPPORT) */ diff --git a/drivers/staging/qcacld-3.0/core/dp/txrx/ol_tx_sched.h b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_tx_sched.h new file mode 100644 index 0000000000000000000000000000000000000000..cc5d48bddade3a8ce433ac589562542c74d0acb5 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_tx_sched.h @@ -0,0 +1,198 @@ +/* + * Copyright (c) 2012-2013, 2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * @file ol_tx_sched.h + * @brief API definitions for the tx scheduler module within the data SW. + */ +#ifndef _OL_TX_SCHED__H_ +#define _OL_TX_SCHED__H_ + +#include + +enum ol_tx_queue_action { + OL_TX_ENQUEUE_FRAME, + OL_TX_DELETE_QUEUE, + OL_TX_PAUSE_QUEUE, + OL_TX_UNPAUSE_QUEUE, + OL_TX_DISCARD_FRAMES, +}; + +struct ol_tx_sched_notify_ctx_t { + int event; + struct ol_tx_frms_queue_t *txq; + union { + int ext_tid; + struct ol_txrx_msdu_info_t *tx_msdu_info; + } info; + int frames; + int bytes; +}; + +#if defined(CONFIG_HL_SUPPORT) + +void +ol_tx_sched_notify( + struct ol_txrx_pdev_t *pdev, + struct ol_tx_sched_notify_ctx_t *ctx); + +void +ol_tx_sched(struct ol_txrx_pdev_t *pdev); + +u_int16_t +ol_tx_sched_discard_select( + struct ol_txrx_pdev_t *pdev, + u_int16_t frms, + ol_tx_desc_list *tx_descs, + bool force); + +void * +ol_tx_sched_attach(struct ol_txrx_pdev_t *pdev); + +void +ol_tx_sched_detach(struct ol_txrx_pdev_t *pdev); + +void ol_tx_sched_stats_display(struct ol_txrx_pdev_t *pdev); + +void ol_tx_sched_cur_state_display(struct ol_txrx_pdev_t *pdev); + +void ol_tx_sched_stats_clear(struct ol_txrx_pdev_t *pdev); + +#else + +static inline void +ol_tx_sched_notify( + struct ol_txrx_pdev_t *pdev, + struct ol_tx_sched_notify_ctx_t *ctx) +{ + return; +} + +static inline void +ol_tx_sched(struct ol_txrx_pdev_t *pdev) +{ + return; +} + +static inline u_int16_t +ol_tx_sched_discard_select( + struct ol_txrx_pdev_t *pdev, + u_int16_t frms, + ol_tx_desc_list *tx_descs, + bool force) +{ + return 0; +} + +static inline void * +ol_tx_sched_attach(struct ol_txrx_pdev_t *pdev) +{ + return NULL; +} + +static inline void +ol_tx_sched_detach(struct ol_txrx_pdev_t *pdev) +{ + return; +} + +static inline void ol_tx_sched_stats_display(struct ol_txrx_pdev_t *pdev) +{ + return; +} + +static inline void ol_tx_sched_cur_state_display(struct ol_txrx_pdev_t *pdev) +{ + return; +} + +static inline void ol_tx_sched_stats_clear(struct ol_txrx_pdev_t *pdev) +{ + return; +} + +#endif /* defined(CONFIG_HL_SUPPORT) */ + +#if defined(CONFIG_HL_SUPPORT) || defined(TX_CREDIT_RECLAIM_SUPPORT) +/* + * HL needs to keep track of the amount of credit available to download + * tx frames to the target - the download scheduler decides when to + * download frames, and which frames to download, based on the credit + * availability. + * LL systems that use TX_CREDIT_RECLAIM_SUPPORT also need to keep track + * of the target_tx_credit, to determine when to poll for tx completion + * messages. + */ + +static inline void +ol_tx_target_credit_adjust(int factor, + struct ol_txrx_pdev_t *pdev, + qdf_nbuf_t msdu) +{ + qdf_atomic_add(factor * htt_tx_msdu_credit(msdu), + &pdev->target_tx_credit); +} + +static inline void ol_tx_target_credit_decr(struct ol_txrx_pdev_t *pdev, + qdf_nbuf_t msdu) +{ + ol_tx_target_credit_adjust(-1, pdev, msdu); +} + +static inline void ol_tx_target_credit_incr(struct ol_txrx_pdev_t *pdev, + qdf_nbuf_t msdu) +{ + ol_tx_target_credit_adjust(1, pdev, msdu); +} +#else +/* + * LL does not need to keep track of target credit. + * Since the host tx descriptor pool size matches the target's, + * we know the target has space for the new tx frame if the host's + * tx descriptor allocation succeeded. + */ +static inline void +ol_tx_target_credit_adjust(int factor, + struct ol_txrx_pdev_t *pdev, + qdf_nbuf_t msdu) +{ + return; +} + +static inline void ol_tx_target_credit_decr(struct ol_txrx_pdev_t *pdev, + qdf_nbuf_t msdu) +{ + return; +} + +static inline void ol_tx_target_credit_incr(struct ol_txrx_pdev_t *pdev, + qdf_nbuf_t msdu) +{ + return; +} +#endif +#endif /* _OL_TX_SCHED__H_ */ diff --git a/drivers/staging/qcacld-3.0/core/dp/txrx/ol_tx_send.c b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_tx_send.c new file mode 100644 index 0000000000000000000000000000000000000000..c32d6e3061ec9ff0caa7c7f1d674524c74a55163 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_tx_send.c @@ -0,0 +1,1290 @@ +/* + * Copyright (c) 2011-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#include /* qdf_atomic_inc, etc. */ +#include /* qdf_os_spinlock */ +#include /* qdf_system_ticks, etc. */ +#include /* qdf_nbuf_t */ +#include /* QDF_NBUF_TX_EXT_TID_INVALID */ + +#include /* TAILQ */ +#ifdef QCA_COMPUTE_TX_DELAY +#include /* ieee80211_frame, etc. */ +#include /* ethernet_hdr_t, etc. */ +#include /* ipv6_traffic_class */ +#endif + +#include /* ol_txrx_vdev_handle, etc. */ +#include /* htt_tx_compl_desc_id */ +#include /* htt_tx_status */ + +#include +#include +#include /* ol_txrx_vdev_t, etc */ +#include /* ol_tx_desc_find, ol_tx_desc_frame_free */ +#ifdef QCA_COMPUTE_TX_DELAY +#include /* ol_tx_dest_addr_find */ +#endif +#include /* OL_TX_DESC_NO_REFS, etc. */ +#include +#include /* ol_tx_reinject */ +#include + +#include /* ol_cfg_is_high_latency */ +#include +#ifdef QCA_SUPPORT_SW_TXRX_ENCAP +#include /* OL_TX_RESTORE_HDR, etc */ +#endif +#include +#include +#include + +#ifdef TX_CREDIT_RECLAIM_SUPPORT + +#define OL_TX_CREDIT_RECLAIM(pdev) \ + do { \ + if (qdf_atomic_read(&pdev->target_tx_credit) < \ + ol_cfg_tx_credit_lwm(pdev->ctrl_pdev)) { \ + ol_osif_ath_tasklet(pdev->osdev); \ + } \ + } while (0) + +#else + +#define OL_TX_CREDIT_RECLAIM(pdev) + +#endif /* TX_CREDIT_RECLAIM_SUPPORT */ + +#if defined(CONFIG_HL_SUPPORT) || defined(TX_CREDIT_RECLAIM_SUPPORT) + +/* + * HL needs to keep track of the amount of credit available to download + * tx frames to the target - the download scheduler decides when to + * download frames, and which frames to download, based on the credit + * availability. + * LL systems that use TX_CREDIT_RECLAIM_SUPPORT also need to keep track + * of the target_tx_credit, to determine when to poll for tx completion + * messages. + */ +static inline void +ol_tx_target_credit_decr_int(struct ol_txrx_pdev_t *pdev, int delta) +{ + qdf_atomic_add(-1 * delta, &pdev->target_tx_credit); +} + +static inline void +ol_tx_target_credit_incr_int(struct ol_txrx_pdev_t *pdev, int delta) +{ + qdf_atomic_add(delta, &pdev->target_tx_credit); +} +#else + +static inline void +ol_tx_target_credit_decr_int(struct ol_txrx_pdev_t *pdev, int delta) +{ + return; +} + +static inline void +ol_tx_target_credit_incr_int(struct ol_txrx_pdev_t *pdev, int delta) +{ + return; +} +#endif + +#if defined(QCA_LL_LEGACY_TX_FLOW_CONTROL) + +/** + * ol_tx_flow_ct_unpause_os_q() - Unpause OS Q + * @pdev: physical device object + * + * + * Return: None + */ +static void ol_tx_flow_ct_unpause_os_q(ol_txrx_pdev_handle pdev) +{ + struct ol_txrx_vdev_t *vdev; + TAILQ_FOREACH(vdev, &pdev->vdev_list, vdev_list_elem) { + if (qdf_atomic_read(&vdev->os_q_paused) && + (vdev->tx_fl_hwm != 0)) { + qdf_spin_lock(&pdev->tx_mutex); + if (pdev->tx_desc.num_free > vdev->tx_fl_hwm) { + qdf_atomic_set(&vdev->os_q_paused, 0); + qdf_spin_unlock(&pdev->tx_mutex); + ol_txrx_flow_control_cb(vdev, true); + } else { + qdf_spin_unlock(&pdev->tx_mutex); + } + } + } +} +#elif defined(CONFIG_HL_SUPPORT) && defined(CONFIG_PER_VDEV_TX_DESC_POOL) + +static void ol_tx_flow_ct_unpause_os_q(ol_txrx_pdev_handle pdev) +{ + struct ol_txrx_vdev_t *vdev; + TAILQ_FOREACH(vdev, &pdev->vdev_list, vdev_list_elem) { + if (qdf_atomic_read(&vdev->os_q_paused) && + (vdev->tx_fl_hwm != 0)) { + qdf_spin_lock(&pdev->tx_mutex); + if (((ol_tx_desc_pool_size_hl( + vdev->pdev->ctrl_pdev) >> 1) + - TXRX_HL_TX_FLOW_CTRL_MGMT_RESERVED) + - qdf_atomic_read(&vdev->tx_desc_count) + > vdev->tx_fl_hwm) { + qdf_atomic_set(&vdev->os_q_paused, 0); + qdf_spin_unlock(&pdev->tx_mutex); + vdev->osif_flow_control_cb(vdev, true); + } else { + qdf_spin_unlock(&pdev->tx_mutex); + } + } + } +} +#else + +static inline void ol_tx_flow_ct_unpause_os_q(ol_txrx_pdev_handle pdev) +{ + return; +} +#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */ + +static inline uint16_t +ol_tx_send_base(struct ol_txrx_pdev_t *pdev, + struct ol_tx_desc_t *tx_desc, qdf_nbuf_t msdu) +{ + int msdu_credit_consumed; + + TX_CREDIT_DEBUG_PRINT("TX %d bytes\n", qdf_nbuf_len(msdu)); + TX_CREDIT_DEBUG_PRINT(" Decrease credit %d - 1 = %d, len:%d.\n", + qdf_atomic_read(&pdev->target_tx_credit), + qdf_atomic_read(&pdev->target_tx_credit) - 1, + qdf_nbuf_len(msdu)); + + msdu_credit_consumed = htt_tx_msdu_credit(msdu); + ol_tx_target_credit_decr_int(pdev, msdu_credit_consumed); + OL_TX_CREDIT_RECLAIM(pdev); + + /* + * When the tx frame is downloaded to the target, there are two + * outstanding references: + * 1. The host download SW (HTT, HTC, HIF) + * This reference is cleared by the ol_tx_send_done callback + * functions. + * 2. The target FW + * This reference is cleared by the ol_tx_completion_handler + * function. + * It is extremely probable that the download completion is processed + * before the tx completion message. However, under exceptional + * conditions the tx completion may be processed first. Thus, rather + * that assuming that reference (1) is done before reference (2), + * explicit reference tracking is needed. + * Double-increment the ref count to account for both references + * described above. + */ + + OL_TX_DESC_REF_INIT(tx_desc); + OL_TX_DESC_REF_INC(tx_desc); + OL_TX_DESC_REF_INC(tx_desc); + + return msdu_credit_consumed; +} + +void +ol_tx_send(struct ol_txrx_pdev_t *pdev, + struct ol_tx_desc_t *tx_desc, qdf_nbuf_t msdu, uint8_t vdev_id) +{ + int msdu_credit_consumed; + uint16_t id; + int failed; + + msdu_credit_consumed = ol_tx_send_base(pdev, tx_desc, msdu); + id = ol_tx_desc_id(pdev, tx_desc); + QDF_NBUF_UPDATE_TX_PKT_COUNT(msdu, QDF_NBUF_TX_PKT_TXRX); + DPTRACE(qdf_dp_trace_ptr(msdu, QDF_DP_TRACE_TXRX_PACKET_PTR_RECORD, + qdf_nbuf_data_addr(msdu), + sizeof(qdf_nbuf_data(msdu)), tx_desc->id, + vdev_id)); + failed = htt_tx_send_std(pdev->htt_pdev, msdu, id); + if (qdf_unlikely(failed)) { + ol_tx_target_credit_incr_int(pdev, msdu_credit_consumed); + ol_tx_desc_frame_free_nonstd(pdev, tx_desc, 1 /* had error */); + } +} + +void +ol_tx_send_batch(struct ol_txrx_pdev_t *pdev, + qdf_nbuf_t head_msdu, int num_msdus) +{ + qdf_nbuf_t rejected; + OL_TX_CREDIT_RECLAIM(pdev); + + rejected = htt_tx_send_batch(pdev->htt_pdev, head_msdu, num_msdus); + while (qdf_unlikely(rejected)) { + struct ol_tx_desc_t *tx_desc; + uint16_t *msdu_id_storage; + qdf_nbuf_t next; + + next = qdf_nbuf_next(rejected); + msdu_id_storage = ol_tx_msdu_id_storage(rejected); + tx_desc = ol_tx_desc_find(pdev, *msdu_id_storage); + + ol_tx_target_credit_incr(pdev, rejected); + ol_tx_desc_frame_free_nonstd(pdev, tx_desc, 1 /* had error */); + + rejected = next; + } +} + +void +ol_tx_send_nonstd(struct ol_txrx_pdev_t *pdev, + struct ol_tx_desc_t *tx_desc, + qdf_nbuf_t msdu, enum htt_pkt_type pkt_type) +{ + int msdu_credit_consumed; + uint16_t id; + int failed; + + msdu_credit_consumed = ol_tx_send_base(pdev, tx_desc, msdu); + id = ol_tx_desc_id(pdev, tx_desc); + QDF_NBUF_UPDATE_TX_PKT_COUNT(msdu, QDF_NBUF_TX_PKT_TXRX); + failed = htt_tx_send_nonstd(pdev->htt_pdev, msdu, id, pkt_type); + if (failed) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "Error: freeing tx frame after htt_tx failed"); + ol_tx_target_credit_incr_int(pdev, msdu_credit_consumed); + ol_tx_desc_frame_free_nonstd(pdev, tx_desc, 1 /* had error */); + } +} + +static inline void +ol_tx_download_done_base(struct ol_txrx_pdev_t *pdev, + A_STATUS status, qdf_nbuf_t msdu, uint16_t msdu_id) +{ + struct ol_tx_desc_t *tx_desc; + + tx_desc = ol_tx_desc_find(pdev, msdu_id); + qdf_assert(tx_desc); + + /* + * If the download is done for + * the Management frame then + * call the download callback if registered + */ + if (tx_desc->pkt_type >= OL_TXRX_MGMT_TYPE_BASE) { + int tx_mgmt_index = tx_desc->pkt_type - OL_TXRX_MGMT_TYPE_BASE; + ol_txrx_mgmt_tx_cb download_cb = + pdev->tx_mgmt.callbacks[tx_mgmt_index].download_cb; + + if (download_cb) { + download_cb(pdev->tx_mgmt.callbacks[tx_mgmt_index].ctxt, + tx_desc->netbuf, status != A_OK); + } + } + + if (status != A_OK) { + ol_tx_target_credit_incr(pdev, msdu); + ol_tx_desc_frame_free_nonstd(pdev, tx_desc, + 1 /* download err */); + } else { + if (OL_TX_DESC_NO_REFS(tx_desc)) { + /* + * The decremented value was zero - free the frame. + * Use the tx status recorded previously during + * tx completion handling. + */ + ol_tx_desc_frame_free_nonstd(pdev, tx_desc, + tx_desc->status != + htt_tx_status_ok); + } + } +} + +void +ol_tx_download_done_ll(void *pdev, + A_STATUS status, qdf_nbuf_t msdu, uint16_t msdu_id) +{ + ol_tx_download_done_base((struct ol_txrx_pdev_t *)pdev, status, msdu, + msdu_id); +} + +void +ol_tx_download_done_hl_retain(void *txrx_pdev, + A_STATUS status, + qdf_nbuf_t msdu, uint16_t msdu_id) +{ + struct ol_txrx_pdev_t *pdev = txrx_pdev; + ol_tx_download_done_base(pdev, status, msdu, msdu_id); +} + +void +ol_tx_download_done_hl_free(void *txrx_pdev, + A_STATUS status, qdf_nbuf_t msdu, uint16_t msdu_id) +{ + struct ol_txrx_pdev_t *pdev = txrx_pdev; + struct ol_tx_desc_t *tx_desc; + + tx_desc = ol_tx_desc_find(pdev, msdu_id); + qdf_assert(tx_desc); + + ol_tx_download_done_base(pdev, status, msdu, msdu_id); + + if ((tx_desc->pkt_type != OL_TX_FRM_NO_FREE) && + (tx_desc->pkt_type < OL_TXRX_MGMT_TYPE_BASE)) { + qdf_atomic_add(1, &pdev->tx_queue.rsrc_cnt); + ol_tx_desc_frame_free_nonstd(pdev, tx_desc, status != A_OK); + } +} + +void ol_tx_target_credit_init(struct ol_txrx_pdev_t *pdev, int credit_delta) +{ + qdf_atomic_add(credit_delta, &pdev->orig_target_tx_credit); +} + +void ol_tx_target_credit_update(struct ol_txrx_pdev_t *pdev, int credit_delta) +{ + TX_CREDIT_DEBUG_PRINT(" Increase credit %d + %d = %d\n", + qdf_atomic_read(&pdev->target_tx_credit), + credit_delta, + qdf_atomic_read(&pdev->target_tx_credit) + + credit_delta); + qdf_atomic_add(credit_delta, &pdev->target_tx_credit); +} + +#ifdef QCA_COMPUTE_TX_DELAY + +static void +ol_tx_delay_compute(struct ol_txrx_pdev_t *pdev, + enum htt_tx_status status, + uint16_t *desc_ids, int num_msdus); + +#else +static inline void +ol_tx_delay_compute(struct ol_txrx_pdev_t *pdev, + enum htt_tx_status status, + uint16_t *desc_ids, int num_msdus) +{ + return; +} +#endif /* QCA_COMPUTE_TX_DELAY */ + +#ifndef OL_TX_RESTORE_HDR +#define OL_TX_RESTORE_HDR(__tx_desc, __msdu) +#endif +/* + * The following macros could have been inline functions too. + * The only rationale for choosing macros, is to force the compiler to inline + * the implementation, which cannot be controlled for actual "inline" functions, + * since "inline" is only a hint to the compiler. + * In the performance path, we choose to force the inlining, in preference to + * type-checking offered by the actual inlined functions. + */ +#define ol_tx_msdu_complete_batch(_pdev, _tx_desc, _tx_descs, _status) \ + TAILQ_INSERT_TAIL(&(_tx_descs), (_tx_desc), tx_desc_list_elem) +#ifndef ATH_11AC_TXCOMPACT +#define ol_tx_msdu_complete_single(_pdev, _tx_desc, _netbuf,\ + _lcl_freelist, _tx_desc_last) \ + do { \ + qdf_atomic_init(&(_tx_desc)->ref_cnt); \ + /* restore orginal hdr offset */ \ + OL_TX_RESTORE_HDR((_tx_desc), (_netbuf)); \ + qdf_nbuf_unmap((_pdev)->osdev, (_netbuf), QDF_DMA_TO_DEVICE); \ + qdf_nbuf_free((_netbuf)); \ + ((union ol_tx_desc_list_elem_t *)(_tx_desc))->next = \ + (_lcl_freelist); \ + if (qdf_unlikely(!lcl_freelist)) { \ + (_tx_desc_last) = (union ol_tx_desc_list_elem_t *)\ + (_tx_desc); \ + } \ + (_lcl_freelist) = (union ol_tx_desc_list_elem_t *)(_tx_desc); \ + } while (0) +#else /*!ATH_11AC_TXCOMPACT */ +#define ol_tx_msdu_complete_single(_pdev, _tx_desc, _netbuf,\ + _lcl_freelist, _tx_desc_last) \ + do { \ + /* restore orginal hdr offset */ \ + OL_TX_RESTORE_HDR((_tx_desc), (_netbuf)); \ + qdf_nbuf_unmap((_pdev)->osdev, (_netbuf), QDF_DMA_TO_DEVICE); \ + qdf_nbuf_free((_netbuf)); \ + ((union ol_tx_desc_list_elem_t *)(_tx_desc))->next = \ + (_lcl_freelist); \ + if (qdf_unlikely(!lcl_freelist)) { \ + (_tx_desc_last) = (union ol_tx_desc_list_elem_t *)\ + (_tx_desc); \ + } \ + (_lcl_freelist) = (union ol_tx_desc_list_elem_t *)(_tx_desc); \ + } while (0) + +#endif /*!ATH_11AC_TXCOMPACT */ + +#ifdef QCA_TX_SINGLE_COMPLETIONS +#ifdef QCA_TX_STD_PATH_ONLY +#define ol_tx_msdu_complete(_pdev, _tx_desc, _tx_descs, \ + _netbuf, _lcl_freelist, \ + _tx_desc_last, _status) \ + ol_tx_msdu_complete_single((_pdev), (_tx_desc), \ + (_netbuf), (_lcl_freelist), \ + _tx_desc_last) +#else /* !QCA_TX_STD_PATH_ONLY */ +#define ol_tx_msdu_complete(_pdev, _tx_desc, _tx_descs, \ + _netbuf, _lcl_freelist, \ + _tx_desc_last, _status) \ + do { \ + if (qdf_likely((_tx_desc)->pkt_type == OL_TX_FRM_STD)) { \ + ol_tx_msdu_complete_single((_pdev), (_tx_desc),\ + (_netbuf), (_lcl_freelist), \ + (_tx_desc_last)); \ + } else { \ + ol_tx_desc_frame_free_nonstd( \ + (_pdev), (_tx_desc), \ + (_status) != htt_tx_status_ok); \ + } \ + } while (0) +#endif /* !QCA_TX_STD_PATH_ONLY */ +#else /* !QCA_TX_SINGLE_COMPLETIONS */ +#ifdef QCA_TX_STD_PATH_ONLY +#define ol_tx_msdu_complete(_pdev, _tx_desc, _tx_descs, \ + _netbuf, _lcl_freelist, \ + _tx_desc_last, _status) \ + ol_tx_msdus_complete_batch((_pdev), (_tx_desc), (_tx_descs), (_status)) +#else /* !QCA_TX_STD_PATH_ONLY */ +#define ol_tx_msdu_complete(_pdev, _tx_desc, _tx_descs, \ + _netbuf, _lcl_freelist, \ + _tx_desc_last, _status) \ + do { \ + if (qdf_likely((_tx_desc)->pkt_type == OL_TX_FRM_STD)) { \ + ol_tx_msdu_complete_batch((_pdev), (_tx_desc), \ + (_tx_descs), (_status)); \ + } else { \ + ol_tx_desc_frame_free_nonstd((_pdev), (_tx_desc), \ + (_status) != \ + htt_tx_status_ok); \ + } \ + } while (0) +#endif /* !QCA_TX_STD_PATH_ONLY */ +#endif /* QCA_TX_SINGLE_COMPLETIONS */ + +#if !defined(CONFIG_HL_SUPPORT) +void ol_tx_discard_target_frms(ol_txrx_pdev_handle pdev) +{ + int i = 0; + struct ol_tx_desc_t *tx_desc; + int num_disarded = 0; + + for (i = 0; i < pdev->tx_desc.pool_size; i++) { + tx_desc = ol_tx_desc_find(pdev, i); + /* + * Confirm that each tx descriptor is "empty", i.e. it has + * no tx frame attached. + * In particular, check that there are no frames that have + * been given to the target to transmit, for which the + * target has never provided a response. + */ + if (qdf_atomic_read(&tx_desc->ref_cnt)) { + TXRX_PRINT(TXRX_PRINT_LEVEL_WARN, + "Warning: freeing tx desc %d", tx_desc->id); + ol_tx_desc_frame_free_nonstd(pdev, + tx_desc, 1); + num_disarded++; + } + } + + if (num_disarded) + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO, + "Warning: freed %d tx descs for which" + "no tx completion rcvd from the target", num_disarded); +} +#endif + +void ol_tx_credit_completion_handler(ol_txrx_pdev_handle pdev, int credits) +{ + ol_tx_target_credit_update(pdev, credits); + + if (pdev->cfg.is_high_latency) + ol_tx_sched(pdev); + + /* UNPAUSE OS Q */ + ol_tx_flow_ct_unpause_os_q(pdev); +} + + +/** + * ol_tx_update_arp_stats() - update ARP packet TX stats + * @netbuf: buffer + * + * + * Return: none + */ +static void ol_tx_update_arp_stats(qdf_nbuf_t netbuf, + enum htt_tx_status status) +{ + uint32_t tgt_ip = cds_get_arp_stats_gw_ip(); + + if (tgt_ip == qdf_nbuf_get_arp_tgt_ip(netbuf)) { + if (status != htt_tx_status_download_fail) + cds_incr_arp_stats_tx_tgt_delivered(); + if (status == htt_tx_status_ok) + cds_incr_arp_stats_tx_tgt_acked(); + } +} + +/* WARNING: ol_tx_inspect_handler()'s bahavior is similar to that of + ol_tx_completion_handler(). + * any change in ol_tx_completion_handler() must be mirrored in + ol_tx_inspect_handler(). +*/ +void +ol_tx_completion_handler(ol_txrx_pdev_handle pdev, + int num_msdus, + enum htt_tx_status status, void *tx_desc_id_iterator) +{ + int i; + uint16_t *desc_ids = (uint16_t *) tx_desc_id_iterator; + uint16_t tx_desc_id; + struct ol_tx_desc_t *tx_desc; + uint32_t byte_cnt = 0; + qdf_nbuf_t netbuf; + tp_ol_packetdump_cb packetdump_cb; + + union ol_tx_desc_list_elem_t *lcl_freelist = NULL; + union ol_tx_desc_list_elem_t *tx_desc_last = NULL; + ol_tx_desc_list tx_descs; + TAILQ_INIT(&tx_descs); + + ol_tx_delay_compute(pdev, status, desc_ids, num_msdus); + + for (i = 0; i < num_msdus; i++) { + tx_desc_id = desc_ids[i]; + tx_desc = ol_tx_desc_find(pdev, tx_desc_id); + tx_desc->status = status; + netbuf = tx_desc->netbuf; + QDF_NBUF_UPDATE_TX_PKT_COUNT(netbuf, QDF_NBUF_TX_PKT_FREE); + + if (QDF_NBUF_CB_GET_PACKET_TYPE(netbuf) == + QDF_NBUF_CB_PACKET_TYPE_ARP) { + if (qdf_nbuf_data_is_arp_req(netbuf)) + ol_tx_update_arp_stats(netbuf, status); + } + + if (tx_desc->pkt_type != OL_TX_FRM_TSO) { + packetdump_cb = pdev->ol_tx_packetdump_cb; + if (packetdump_cb) + packetdump_cb(netbuf, status, + tx_desc->vdev->vdev_id, TX_DATA_PKT); + } + + DPTRACE(qdf_dp_trace_ptr(netbuf, + QDF_DP_TRACE_FREE_PACKET_PTR_RECORD, + qdf_nbuf_data_addr(netbuf), + sizeof(qdf_nbuf_data(netbuf)), tx_desc->id, status)); + htc_pm_runtime_put(pdev->htt_pdev->htc_pdev); + ol_tx_desc_update_group_credit(pdev, tx_desc_id, 1, 0, status); + /* Per SDU update of byte count */ + byte_cnt += qdf_nbuf_len(netbuf); + if (OL_TX_DESC_NO_REFS(tx_desc)) { + ol_tx_statistics( + pdev->ctrl_pdev, + HTT_TX_DESC_VDEV_ID_GET(*((uint32_t *) + (tx_desc-> + htt_tx_desc))), + status != htt_tx_status_ok); + ol_tx_msdu_complete(pdev, tx_desc, tx_descs, netbuf, + lcl_freelist, tx_desc_last, status); + } +#ifdef QCA_SUPPORT_TXDESC_SANITY_CHECKS + tx_desc->pkt_type = ol_tx_frm_freed; +#ifdef QCA_COMPUTE_TX_DELAY + tx_desc->entry_timestamp_ticks = 0xffffffff; +#endif +#endif + } + + /* One shot protected access to pdev freelist, when setup */ + if (lcl_freelist) { + qdf_spin_lock(&pdev->tx_mutex); + tx_desc_last->next = pdev->tx_desc.freelist; + pdev->tx_desc.freelist = lcl_freelist; + pdev->tx_desc.num_free += (uint16_t) num_msdus; + qdf_spin_unlock(&pdev->tx_mutex); + } else { + ol_tx_desc_frame_list_free(pdev, &tx_descs, + status != htt_tx_status_ok); + } + + if (pdev->cfg.is_high_latency) { + /* + * Credit was already explicitly updated by HTT, + * but update the number of available tx descriptors, + * then invoke the scheduler, since new credit is probably + * available now. + */ + qdf_atomic_add(num_msdus, &pdev->tx_queue.rsrc_cnt); + ol_tx_sched(pdev); + } else { + ol_tx_target_credit_adjust(num_msdus, pdev, NULL); + } + + /* UNPAUSE OS Q */ + ol_tx_flow_ct_unpause_os_q(pdev); + /* Do one shot statistics */ + TXRX_STATS_UPDATE_TX_STATS(pdev, status, num_msdus, byte_cnt); +} + +#ifdef FEATURE_HL_GROUP_CREDIT_FLOW_CONTROL + +void ol_tx_desc_update_group_credit(ol_txrx_pdev_handle pdev, + u_int16_t tx_desc_id, int credit, u_int8_t absolute, + enum htt_tx_status status) +{ + uint8_t i, is_member; + uint16_t vdev_id_mask; + struct ol_tx_desc_t *tx_desc; + + tx_desc = ol_tx_desc_find(pdev, tx_desc_id); + for (i = 0; i < OL_TX_MAX_TXQ_GROUPS; i++) { + vdev_id_mask = + OL_TXQ_GROUP_VDEV_ID_MASK_GET( + pdev->txq_grps[i].membership); + is_member = OL_TXQ_GROUP_VDEV_ID_BIT_MASK_GET(vdev_id_mask, + tx_desc->vdev_id); + if (is_member) { + ol_txrx_update_group_credit(&pdev->txq_grps[i], + credit, absolute); + break; + } + } + ol_tx_update_group_credit_stats(pdev); +} + +#ifdef DEBUG_HL_LOGGING + +void ol_tx_update_group_credit_stats(ol_txrx_pdev_handle pdev) +{ + uint16_t curr_index; + uint8_t i; + + qdf_spin_lock_bh(&pdev->grp_stat_spinlock); + pdev->grp_stats.last_valid_index++; + if (pdev->grp_stats.last_valid_index > (OL_TX_GROUP_STATS_LOG_SIZE + - 1)) { + pdev->grp_stats.last_valid_index -= OL_TX_GROUP_STATS_LOG_SIZE; + pdev->grp_stats.wrap_around = 1; + } + curr_index = pdev->grp_stats.last_valid_index; + + for (i = 0; i < OL_TX_MAX_TXQ_GROUPS; i++) { + pdev->grp_stats.stats[curr_index].grp[i].member_vdevs = + OL_TXQ_GROUP_VDEV_ID_MASK_GET( + pdev->txq_grps[i].membership); + pdev->grp_stats.stats[curr_index].grp[i].credit = + qdf_atomic_read(&pdev->txq_grps[i].credit); + } + + qdf_spin_unlock_bh(&pdev->grp_stat_spinlock); +} + +void ol_tx_dump_group_credit_stats(ol_txrx_pdev_handle pdev) +{ + uint16_t i, j, is_break = 0; + int16_t curr_index, old_index, wrap_around; + uint16_t curr_credit, old_credit, mem_vdevs; + + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "Group credit stats:"); + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + " No: GrpID: Credit: Change: vdev_map"); + + qdf_spin_lock_bh(&pdev->grp_stat_spinlock); + curr_index = pdev->grp_stats.last_valid_index; + wrap_around = pdev->grp_stats.wrap_around; + qdf_spin_unlock_bh(&pdev->grp_stat_spinlock); + + if (curr_index < 0) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "Not initialized"); + return; + } + + for (i = 0; i < OL_TX_GROUP_STATS_LOG_SIZE; i++) { + old_index = curr_index - 1; + if (old_index < 0) { + if (wrap_around == 0) + is_break = 1; + else + old_index = OL_TX_GROUP_STATS_LOG_SIZE - 1; + } + + for (j = 0; j < OL_TX_MAX_TXQ_GROUPS; j++) { + qdf_spin_lock_bh(&pdev->grp_stat_spinlock); + curr_credit = + pdev->grp_stats.stats[curr_index]. + grp[j].credit; + if (!is_break) + old_credit = + pdev->grp_stats.stats[old_index]. + grp[j].credit; + + mem_vdevs = + pdev->grp_stats.stats[curr_index].grp[j]. + member_vdevs; + qdf_spin_unlock_bh(&pdev->grp_stat_spinlock); + + if (!is_break) + QDF_TRACE(QDF_MODULE_ID_TXRX, + QDF_TRACE_LEVEL_ERROR, + "%4d: %5d: %6d %6d %8x", + curr_index, j, + curr_credit, + (curr_credit - old_credit), + mem_vdevs); + else + QDF_TRACE(QDF_MODULE_ID_TXRX, + QDF_TRACE_LEVEL_ERROR, + "%4d: %5d: %6d %6s %8x", + curr_index, j, + curr_credit, "NA", mem_vdevs); + } + + if (is_break) + break; + + curr_index = old_index; + } +} + +void ol_tx_clear_group_credit_stats(ol_txrx_pdev_handle pdev) +{ + qdf_spin_lock_bh(&pdev->grp_stat_spinlock); + qdf_mem_zero(&pdev->grp_stats, sizeof(pdev->grp_stats)); + pdev->grp_stats.last_valid_index = -1; + pdev->grp_stats.wrap_around = 0; + qdf_spin_unlock_bh(&pdev->grp_stat_spinlock); +} +#endif +#endif + +/* + * ol_tx_single_completion_handler performs the same tx completion + * processing as ol_tx_completion_handler, but for a single frame. + * ol_tx_completion_handler is optimized to handle batch completions + * as efficiently as possible; in contrast ol_tx_single_completion_handler + * handles single frames as simply and generally as possible. + * Thus, this ol_tx_single_completion_handler function is suitable for + * intermittent usage, such as for tx mgmt frames. + */ +void +ol_tx_single_completion_handler(ol_txrx_pdev_handle pdev, + enum htt_tx_status status, uint16_t tx_desc_id) +{ + struct ol_tx_desc_t *tx_desc; + qdf_nbuf_t netbuf; + tp_ol_packetdump_cb packetdump_cb; + + tx_desc = ol_tx_desc_find_check(pdev, tx_desc_id); + if (tx_desc == NULL) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "%s: invalid desc_id(%u), ignore it.\n", + __func__, + tx_desc_id); + return; + } + + tx_desc->status = status; + netbuf = tx_desc->netbuf; + + QDF_NBUF_UPDATE_TX_PKT_COUNT(netbuf, QDF_NBUF_TX_PKT_FREE); + /* Do one shot statistics */ + TXRX_STATS_UPDATE_TX_STATS(pdev, status, 1, qdf_nbuf_len(netbuf)); + + packetdump_cb = pdev->ol_tx_packetdump_cb; + if (packetdump_cb) + packetdump_cb(netbuf, status, + tx_desc->vdev->vdev_id, TX_MGMT_PKT); + + if (OL_TX_DESC_NO_REFS(tx_desc)) { + ol_tx_desc_frame_free_nonstd(pdev, tx_desc, + status != htt_tx_status_ok); + } + + TX_CREDIT_DEBUG_PRINT(" Increase credit %d + %d = %d\n", + qdf_atomic_read(&pdev->target_tx_credit), + 1, qdf_atomic_read(&pdev->target_tx_credit) + 1); + + if (pdev->cfg.is_high_latency) { + /* + * Credit was already explicitly updated by HTT, + * but update the number of available tx descriptors, + * then invoke the scheduler, since new credit is probably + * available now. + */ + qdf_atomic_add(1, &pdev->tx_queue.rsrc_cnt); + ol_tx_sched(pdev); + } else { + qdf_atomic_add(1, &pdev->target_tx_credit); + } +} + +/* WARNING: ol_tx_inspect_handler()'s bahavior is similar to that of + ol_tx_completion_handler(). + * any change in ol_tx_completion_handler() must be mirrored here. + */ +void +ol_tx_inspect_handler(ol_txrx_pdev_handle pdev, + int num_msdus, void *tx_desc_id_iterator) +{ + uint16_t vdev_id, i; + struct ol_txrx_vdev_t *vdev; + uint16_t *desc_ids = (uint16_t *) tx_desc_id_iterator; + uint16_t tx_desc_id; + struct ol_tx_desc_t *tx_desc; + union ol_tx_desc_list_elem_t *lcl_freelist = NULL; + union ol_tx_desc_list_elem_t *tx_desc_last = NULL; + qdf_nbuf_t netbuf; + ol_tx_desc_list tx_descs; + TAILQ_INIT(&tx_descs); + + for (i = 0; i < num_msdus; i++) { + tx_desc_id = desc_ids[i]; + tx_desc = ol_tx_desc_find(pdev, tx_desc_id); + netbuf = tx_desc->netbuf; + + /* find the "vdev" this tx_desc belongs to */ + vdev_id = HTT_TX_DESC_VDEV_ID_GET(*((uint32_t *) + (tx_desc->htt_tx_desc))); + TAILQ_FOREACH(vdev, &pdev->vdev_list, vdev_list_elem) { + if (vdev->vdev_id == vdev_id) + break; + } + + /* vdev now points to the vdev for this descriptor. */ + +#ifndef ATH_11AC_TXCOMPACT + /* save this multicast packet to local free list */ + if (qdf_atomic_dec_and_test(&tx_desc->ref_cnt)) +#endif + { + /* for this function only, force htt status to be + "htt_tx_status_ok" + * for graceful freeing of this multicast frame + */ + ol_tx_msdu_complete(pdev, tx_desc, tx_descs, netbuf, + lcl_freelist, tx_desc_last, + htt_tx_status_ok); + +#ifdef QCA_SUPPORT_TXDESC_SANITY_CHECKS + tx_desc->pkt_type = ol_tx_frm_freed; +#ifdef QCA_COMPUTE_TX_DELAY + tx_desc->entry_timestamp_ticks = 0xffffffff; +#endif +#endif + } + } + + if (lcl_freelist) { + qdf_spin_lock(&pdev->tx_mutex); + tx_desc_last->next = pdev->tx_desc.freelist; + pdev->tx_desc.freelist = lcl_freelist; + qdf_spin_unlock(&pdev->tx_mutex); + } else { + ol_tx_desc_frame_list_free(pdev, &tx_descs, + htt_tx_status_discard); + } + TX_CREDIT_DEBUG_PRINT(" Increase HTT credit %d + %d = %d..\n", + qdf_atomic_read(&pdev->target_tx_credit), + num_msdus, + qdf_atomic_read(&pdev->target_tx_credit) + + num_msdus); + + if (pdev->cfg.is_high_latency) { + /* credit was already explicitly updated by HTT */ + ol_tx_sched(pdev); + } else { + ol_tx_target_credit_adjust(num_msdus, pdev, NULL); + } +} + +#ifdef QCA_COMPUTE_TX_DELAY +/** + * @brief updates the compute interval period for TSM stats. + * @details + * @param interval - interval for stats computation + */ +void ol_tx_set_compute_interval(ol_txrx_pdev_handle pdev, uint32_t interval) +{ + pdev->tx_delay.avg_period_ticks = qdf_system_msecs_to_ticks(interval); +} + +/** + * @brief Return the uplink (transmitted) packet count and loss count. + * @details + * This function will be called for getting uplink packet count and + * loss count for given stream (access category) a regular interval. + * This also resets the counters hence, the value returned is packets + * counted in last 5(default) second interval. These counter are + * incremented per access category in ol_tx_completion_handler() + * + * @param category - access category of interest + * @param out_packet_count - number of packets transmitted + * @param out_packet_loss_count - number of packets lost + */ +void +ol_tx_packet_count(ol_txrx_pdev_handle pdev, + uint16_t *out_packet_count, + uint16_t *out_packet_loss_count, int category) +{ + *out_packet_count = pdev->packet_count[category]; + *out_packet_loss_count = pdev->packet_loss_count[category]; + pdev->packet_count[category] = 0; + pdev->packet_loss_count[category] = 0; +} + +static uint32_t ol_tx_delay_avg(uint64_t sum, uint32_t num) +{ + uint32_t sum32; + int shift = 0; + /* + * To avoid doing a 64-bit divide, shift the sum down until it is + * no more than 32 bits (and shift the denominator to match). + */ + while ((sum >> 32) != 0) { + sum >>= 1; + shift++; + } + sum32 = (uint32_t) sum; + num >>= shift; + return (sum32 + (num >> 1)) / num; /* round to nearest */ +} + +void +ol_tx_delay(ol_txrx_pdev_handle pdev, + uint32_t *queue_delay_microsec, + uint32_t *tx_delay_microsec, int category) +{ + int index; + uint32_t avg_delay_ticks; + struct ol_tx_delay_data *data; + + qdf_assert(category >= 0 && category < QCA_TX_DELAY_NUM_CATEGORIES); + + qdf_spin_lock_bh(&pdev->tx_delay.mutex); + index = 1 - pdev->tx_delay.cats[category].in_progress_idx; + + data = &pdev->tx_delay.cats[category].copies[index]; + + if (data->avgs.transmit_num > 0) { + avg_delay_ticks = + ol_tx_delay_avg(data->avgs.transmit_sum_ticks, + data->avgs.transmit_num); + *tx_delay_microsec = + qdf_system_ticks_to_msecs(avg_delay_ticks * 1000); + } else { + /* + * This case should only happen if there's a query + * within 5 sec after the first tx data frame. + */ + *tx_delay_microsec = 0; + } + if (data->avgs.queue_num > 0) { + avg_delay_ticks = + ol_tx_delay_avg(data->avgs.queue_sum_ticks, + data->avgs.queue_num); + *queue_delay_microsec = + qdf_system_ticks_to_msecs(avg_delay_ticks * 1000); + } else { + /* + * This case should only happen if there's a query + * within 5 sec after the first tx data frame. + */ + *queue_delay_microsec = 0; + } + + qdf_spin_unlock_bh(&pdev->tx_delay.mutex); +} + +void +ol_tx_delay_hist(ol_txrx_pdev_handle pdev, + uint16_t *report_bin_values, int category) +{ + int index, i, j; + struct ol_tx_delay_data *data; + + qdf_assert(category >= 0 && category < QCA_TX_DELAY_NUM_CATEGORIES); + + qdf_spin_lock_bh(&pdev->tx_delay.mutex); + index = 1 - pdev->tx_delay.cats[category].in_progress_idx; + + data = &pdev->tx_delay.cats[category].copies[index]; + + for (i = 0, j = 0; i < QCA_TX_DELAY_HIST_REPORT_BINS - 1; i++) { + uint16_t internal_bin_sum = 0; + while (j < (1 << i)) + internal_bin_sum += data->hist_bins_queue[j++]; + + report_bin_values[i] = internal_bin_sum; + } + report_bin_values[i] = data->hist_bins_queue[j]; /* overflow */ + + qdf_spin_unlock_bh(&pdev->tx_delay.mutex); +} + +#ifdef QCA_COMPUTE_TX_DELAY_PER_TID + +static uint8_t +ol_tx_delay_tid_from_l3_hdr(struct ol_txrx_pdev_t *pdev, + qdf_nbuf_t msdu, struct ol_tx_desc_t *tx_desc) +{ + uint16_t ethertype; + uint8_t *dest_addr, *l3_hdr; + int is_mgmt, is_mcast; + int l2_hdr_size; + + dest_addr = ol_tx_dest_addr_find(pdev, msdu); + if (NULL == dest_addr) + return QDF_NBUF_TX_EXT_TID_INVALID; + + is_mcast = IEEE80211_IS_MULTICAST(dest_addr); + is_mgmt = tx_desc->pkt_type >= OL_TXRX_MGMT_TYPE_BASE; + if (is_mgmt) { + return (is_mcast) ? + OL_TX_NUM_TIDS + OL_TX_VDEV_DEFAULT_MGMT : + HTT_TX_EXT_TID_MGMT; + } + if (is_mcast) + return OL_TX_NUM_TIDS + OL_TX_VDEV_MCAST_BCAST; + + if (pdev->frame_format == wlan_frm_fmt_802_3) { + struct ethernet_hdr_t *enet_hdr; + enet_hdr = (struct ethernet_hdr_t *)qdf_nbuf_data(msdu); + l2_hdr_size = sizeof(struct ethernet_hdr_t); + ethertype = + (enet_hdr->ethertype[0] << 8) | enet_hdr->ethertype[1]; + if (!IS_ETHERTYPE(ethertype)) { + struct llc_snap_hdr_t *llc_hdr; + llc_hdr = (struct llc_snap_hdr_t *) + (qdf_nbuf_data(msdu) + l2_hdr_size); + l2_hdr_size += sizeof(struct llc_snap_hdr_t); + ethertype = + (llc_hdr->ethertype[0] << 8) | llc_hdr-> + ethertype[1]; + } + } else { + struct llc_snap_hdr_t *llc_hdr; + l2_hdr_size = sizeof(struct ieee80211_frame); + llc_hdr = (struct llc_snap_hdr_t *)(qdf_nbuf_data(msdu) + + l2_hdr_size); + l2_hdr_size += sizeof(struct llc_snap_hdr_t); + ethertype = + (llc_hdr->ethertype[0] << 8) | llc_hdr->ethertype[1]; + } + l3_hdr = qdf_nbuf_data(msdu) + l2_hdr_size; + if (ETHERTYPE_IPV4 == ethertype) { + return (((struct ipv4_hdr_t *)l3_hdr)->tos >> 5) & 0x7; + } else if (ETHERTYPE_IPV6 == ethertype) { + return (ipv6_traffic_class((struct ipv6_hdr_t *)l3_hdr) >> 5) & + 0x7; + } else { + return QDF_NBUF_TX_EXT_TID_INVALID; + } +} +#endif + +static int ol_tx_delay_category(struct ol_txrx_pdev_t *pdev, uint16_t msdu_id) +{ +#ifdef QCA_COMPUTE_TX_DELAY_PER_TID + struct ol_tx_desc_t *tx_desc = ol_tx_desc_find(pdev, msdu_id); + uint8_t tid; + + qdf_nbuf_t msdu = tx_desc->netbuf; + tid = qdf_nbuf_get_tid(msdu); + if (tid == QDF_NBUF_TX_EXT_TID_INVALID) { + tid = ol_tx_delay_tid_from_l3_hdr(pdev, msdu, tx_desc); + if (tid == QDF_NBUF_TX_EXT_TID_INVALID) { + /* TID could not be determined + (this is not an IP frame?) */ + return -EINVAL; + } + } + return tid; +#else + return 0; +#endif +} + +static inline int +ol_tx_delay_hist_bin(struct ol_txrx_pdev_t *pdev, uint32_t delay_ticks) +{ + int bin; + /* + * For speed, multiply and shift to approximate a divide. This causes + * a small error, but the approximation error should be much less + * than the other uncertainties in the tx delay computation. + */ + bin = (delay_ticks * pdev->tx_delay.hist_internal_bin_width_mult) >> + pdev->tx_delay.hist_internal_bin_width_shift; + if (bin >= QCA_TX_DELAY_HIST_INTERNAL_BINS) + bin = QCA_TX_DELAY_HIST_INTERNAL_BINS - 1; + + return bin; +} + +static void +ol_tx_delay_compute(struct ol_txrx_pdev_t *pdev, + enum htt_tx_status status, + uint16_t *desc_ids, int num_msdus) +{ + int i, index, cat; + uint32_t now_ticks = qdf_system_ticks(); + uint32_t tx_delay_transmit_ticks, tx_delay_queue_ticks; + uint32_t avg_time_ticks; + struct ol_tx_delay_data *data; + + qdf_assert(num_msdus > 0); + + /* + * keep static counters for total packet and lost packets + * reset them in ol_tx_delay(), function used to fetch the stats + */ + + cat = ol_tx_delay_category(pdev, desc_ids[0]); + if (cat < 0 || cat >= QCA_TX_DELAY_NUM_CATEGORIES) + return; + + pdev->packet_count[cat] = pdev->packet_count[cat] + num_msdus; + if (status != htt_tx_status_ok) { + for (i = 0; i < num_msdus; i++) { + cat = ol_tx_delay_category(pdev, desc_ids[i]); + if (cat < 0 || cat >= QCA_TX_DELAY_NUM_CATEGORIES) + return; + pdev->packet_loss_count[cat]++; + } + return; + } + + /* since we may switch the ping-pong index, provide mutex w. readers */ + qdf_spin_lock_bh(&pdev->tx_delay.mutex); + index = pdev->tx_delay.cats[cat].in_progress_idx; + + data = &pdev->tx_delay.cats[cat].copies[index]; + + if (pdev->tx_delay.tx_compl_timestamp_ticks != 0) { + tx_delay_transmit_ticks = + now_ticks - pdev->tx_delay.tx_compl_timestamp_ticks; + /* + * We'd like to account for the number of MSDUs that were + * transmitted together, but we don't know this. All we know + * is the number of MSDUs that were acked together. + * Since the frame error rate is small, this is nearly the same + * as the number of frames transmitted together. + */ + data->avgs.transmit_sum_ticks += tx_delay_transmit_ticks; + data->avgs.transmit_num += num_msdus; + } + pdev->tx_delay.tx_compl_timestamp_ticks = now_ticks; + + for (i = 0; i < num_msdus; i++) { + int bin; + uint16_t id = desc_ids[i]; + struct ol_tx_desc_t *tx_desc = ol_tx_desc_find(pdev, id); + + tx_delay_queue_ticks = + now_ticks - tx_desc->entry_timestamp_ticks; + + data->avgs.queue_sum_ticks += tx_delay_queue_ticks; + data->avgs.queue_num++; + bin = ol_tx_delay_hist_bin(pdev, tx_delay_queue_ticks); + data->hist_bins_queue[bin]++; + } + + /* check if it's time to start a new average */ + avg_time_ticks = + now_ticks - pdev->tx_delay.cats[cat].avg_start_time_ticks; + if (avg_time_ticks > pdev->tx_delay.avg_period_ticks) { + pdev->tx_delay.cats[cat].avg_start_time_ticks = now_ticks; + index = 1 - index; + pdev->tx_delay.cats[cat].in_progress_idx = index; + qdf_mem_zero(&pdev->tx_delay.cats[cat].copies[index], + sizeof(pdev->tx_delay.cats[cat].copies[index])); + } + + qdf_spin_unlock_bh(&pdev->tx_delay.mutex); +} + +#endif /* QCA_COMPUTE_TX_DELAY */ + +/** + * ol_register_packetdump_callback() - registers + * tx data packet, tx mgmt. packet and rx data packet + * dump callback handler. + * + * @ol_tx_packetdump_cb: tx packetdump cb + * @ol_rx_packetdump_cb: rx packetdump cb + * + * This function is used to register tx data pkt, tx mgmt. + * pkt and rx data pkt dump callback + * + * Return: None + * + */ +void ol_register_packetdump_callback(tp_ol_packetdump_cb ol_tx_packetdump_cb, + tp_ol_packetdump_cb ol_rx_packetdump_cb) +{ + ol_txrx_pdev_handle pdev = cds_get_context(QDF_MODULE_ID_TXRX); + + if (!pdev) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "%s: pdev is NULL", __func__); + return; + } + + pdev->ol_tx_packetdump_cb = ol_tx_packetdump_cb; + pdev->ol_rx_packetdump_cb = ol_rx_packetdump_cb; +} + +/** + * ol_deregister_packetdump_callback() - deregidters + * tx data packet, tx mgmt. packet and rx data packet + * dump callback handler + * + * This function is used to deregidter tx data pkt., + * tx mgmt. pkt and rx data pkt. dump callback + * + * Return: None + * + */ +void ol_deregister_packetdump_callback(void) +{ + ol_txrx_pdev_handle pdev = cds_get_context(QDF_MODULE_ID_TXRX); + + if (!pdev) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "%s: pdev is NULL", __func__); + return; + } + + pdev->ol_tx_packetdump_cb = NULL; + pdev->ol_rx_packetdump_cb = NULL; +} diff --git a/drivers/staging/qcacld-3.0/core/dp/txrx/ol_tx_send.h b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_tx_send.h new file mode 100644 index 0000000000000000000000000000000000000000..fe95f9b2f2cee01ae0a0a04fb5870569140efc3d --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_tx_send.h @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2011, 2014-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * @file ol_tx_send.h + * @brief API definitions for the tx sendriptor module within the data SW. + */ +#ifndef _OL_TX_SEND__H_ +#define _OL_TX_SEND__H_ + +#include /* qdf_nbuf_t */ +#include /* ol_txrx_vdev_t, etc. */ + +#if defined(CONFIG_HL_SUPPORT) + +static inline void ol_tx_discard_target_frms(ol_txrx_pdev_handle pdev) +{ + return; +} +#else + +/** + * @flush the ol tx when surprise remove. + * + */ +void ol_tx_discard_target_frms(ol_txrx_pdev_handle pdev); +#endif + +/** + * @brief Send a tx frame to the target. + * @details + * + * @param pdev - the phy dev + * @param vdev - the virtual device sending the data + * (for specifying the transmitter address for multicast / broadcast data) + * @param netbuf - the tx frame + */ +void +ol_tx_send(struct ol_txrx_pdev_t *pdev, + struct ol_tx_desc_t *tx_desc, qdf_nbuf_t msdu, uint8_t vdev_id); + +/** + * @brief Send a tx batch download to the target. + * @details + * This function is different from above in that + * it accepts a list of msdu's to be downloaded as a batch + * + * @param pdev - the phy dev + * @param msdu_list - the Head pointer to the Tx Batch + * @param num_msdus - Total msdus chained in msdu_list + */ + +void +ol_tx_send_batch(struct ol_txrx_pdev_t *pdev, + qdf_nbuf_t msdu_list, int num_msdus); + +/** + * @brief Send a tx frame with a non-std header or payload type to the target. + * @details + * + * @param pdev - the phy dev + * @param vdev - the virtual device sending the data + * (for specifying the transmitter address for multicast / broadcast data) + * @param netbuf - the tx frame + * @param pkt_type - what kind of non-std frame is being sent + */ +void +ol_tx_send_nonstd(struct ol_txrx_pdev_t *pdev, + struct ol_tx_desc_t *tx_desc, + qdf_nbuf_t msdu, enum htt_pkt_type pkt_type); +#endif /* _OL_TX_SEND__H_ */ diff --git a/drivers/staging/qcacld-3.0/core/dp/txrx/ol_txrx.c b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_txrx.c new file mode 100644 index 0000000000000000000000000000000000000000..be3b26f83c6a3682e3d8e216cd879d89a3fb951f --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_txrx.c @@ -0,0 +1,5393 @@ +/* + * Copyright (c) 2011-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/*=== includes ===*/ +/* header files for OS primitives */ +#include /* uint32_t, etc. */ +#include /* qdf_mem_malloc,free */ +#include /* qdf_device_t, qdf_print */ +#include /* qdf_spinlock */ +#include /* qdf_atomic_read */ + +#if defined(HIF_PCI) || defined(HIF_SNOC) || defined(HIF_AHB) +/* Required for WLAN_FEATURE_FASTPATH */ +#include +#endif +/* header files for utilities */ +#include /* TAILQ */ + +/* header files for configuration API */ +#include /* ol_cfg_is_high_latency */ +#include + +/* header files for HTT API */ +#include +#include + +/* header files for our own APIs */ +#include +#include +#include +#include +#include +#include +/* header files for our internal definitions */ +#include /* TXRX_ASSERT, etc. */ +#include /* WDI events */ +#include /* ol_tx_ll */ +#include /* ol_rx_deliver */ +#include /* ol_txrx_peer_find_attach, etc. */ +#include /* ol_rx_pn_check, etc. */ +#include /* ol_rx_fwd_check, etc. */ +#include /* OL_RX_REORDER_TIMEOUT_INIT, etc. */ +#include +#include /* ol_tx_discard_target_frms */ +#include /* ol_tx_desc_frame_free */ +#include +#include /* ol_tx_sched_attach, etc. */ +#include +#include +#include +#include +#include +#include +#include +#include "wma.h" +#include "hif.h" +#include +#ifndef REMOVE_PKT_LOG +#include "pktlog_ac.h" +#endif +#include +#include "epping_main.h" +#include +#include "wma_api.h" + +#include + +/* thresh for peer's cached buf queue beyond which the elements are dropped */ +#define OL_TXRX_CACHED_BUFQ_THRESH 128 + +#if defined(CONFIG_HL_SUPPORT) && defined(FEATURE_WLAN_TDLS) + +/** + * ol_txrx_copy_mac_addr_raw() - copy raw mac addr + * @vdev: the data virtual device + * @bss_addr: bss address + * + * Return: None + */ +void +ol_txrx_copy_mac_addr_raw(ol_txrx_vdev_handle vdev, uint8_t *bss_addr) +{ + if (bss_addr && vdev->last_real_peer && + !qdf_mem_cmp((u8 *)bss_addr, + vdev->last_real_peer->mac_addr.raw, + IEEE80211_ADDR_LEN)) + qdf_mem_copy(vdev->hl_tdls_ap_mac_addr.raw, + vdev->last_real_peer->mac_addr.raw, + OL_TXRX_MAC_ADDR_LEN); +} + +/** + * ol_txrx_add_last_real_peer() - add last peer + * @pdev: the data physical device + * @vdev: virtual device + * @peer_id: peer id + * + * Return: None + */ +void +ol_txrx_add_last_real_peer(ol_txrx_pdev_handle pdev, + ol_txrx_vdev_handle vdev, + uint8_t *peer_id) +{ + ol_txrx_peer_handle peer; + if (vdev->last_real_peer == NULL) { + peer = NULL; + peer = ol_txrx_find_peer_by_addr(pdev, + vdev->hl_tdls_ap_mac_addr.raw, + peer_id); + if (peer && (peer->peer_ids[0] != + HTT_INVALID_PEER_ID)) + vdev->last_real_peer = peer; + } +} + +/** + * is_vdev_restore_last_peer() - check for vdev last peer + * @peer: peer object + * + * Return: true if last peer is not null + */ +bool +is_vdev_restore_last_peer(struct ol_txrx_peer_t *peer) +{ + struct ol_txrx_vdev_t *vdev; + vdev = peer->vdev; + return vdev->last_real_peer && (vdev->last_real_peer == peer); +} + +/** + * ol_txrx_update_last_real_peer() - check for vdev last peer + * @pdev: the data physical device + * @peer: peer device + * @peer_id: peer id + * @restore_last_peer: restore last peer flag + * + * Return: None + */ +void +ol_txrx_update_last_real_peer( + ol_txrx_pdev_handle pdev, + struct ol_txrx_peer_t *peer, + uint8_t *peer_id, bool restore_last_peer) +{ + struct ol_txrx_vdev_t *vdev; + vdev = peer->vdev; + if (restore_last_peer && (vdev->last_real_peer == NULL)) { + peer = NULL; + peer = ol_txrx_find_peer_by_addr(pdev, + vdev->hl_tdls_ap_mac_addr.raw, peer_id); + if (peer && (peer->peer_ids[0] != HTT_INVALID_PEER_ID)) + vdev->last_real_peer = peer; + } +} +#endif + +/** + * ol_tx_mark_first_wakeup_packet() - set flag to indicate that + * fw is compatible for marking first packet after wow wakeup + * @value: 1 for enabled/ 0 for disabled + * + * Return: None + */ +void ol_tx_mark_first_wakeup_packet(uint8_t value) +{ + struct ol_txrx_pdev_t *pdev = cds_get_context(QDF_MODULE_ID_TXRX); + + if (!pdev) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "%s: pdev is NULL\n", __func__); + return; + } + + htt_mark_first_wakeup_packet(pdev->htt_pdev, value); +} + +u_int16_t +ol_tx_desc_pool_size_hl(ol_pdev_handle ctrl_pdev) +{ + u_int16_t desc_pool_size; + u_int16_t steady_state_tx_lifetime_ms; + u_int16_t safety_factor; + + /* + * Steady-state tx latency: + * roughly 1-2 ms flight time + * + roughly 1-2 ms prep time, + * + roughly 1-2 ms target->host notification time. + * = roughly 6 ms total + * Thus, steady state number of frames = + * steady state max throughput / frame size * tx latency, e.g. + * 1 Gbps / 1500 bytes * 6 ms = 500 + * + */ + steady_state_tx_lifetime_ms = 6; + + safety_factor = 8; + + desc_pool_size = + ol_cfg_max_thruput_mbps(ctrl_pdev) * + 1000 /* 1e6 bps/mbps / 1e3 ms per sec = 1000 */ / + (8 * OL_TX_AVG_FRM_BYTES) * + steady_state_tx_lifetime_ms * + safety_factor; + + /* minimum */ + if (desc_pool_size < OL_TX_DESC_POOL_SIZE_MIN_HL) + desc_pool_size = OL_TX_DESC_POOL_SIZE_MIN_HL; + + /* maximum */ + if (desc_pool_size > OL_TX_DESC_POOL_SIZE_MAX_HL) + desc_pool_size = OL_TX_DESC_POOL_SIZE_MAX_HL; + + return desc_pool_size; +} + +/*=== function definitions ===*/ + +/** + * ol_tx_set_is_mgmt_over_wmi_enabled() - set flag to indicate that mgmt over + * wmi is enabled or not. + * @value: 1 for enabled/ 0 for disable + * + * Return: None + */ +void ol_tx_set_is_mgmt_over_wmi_enabled(uint8_t value) +{ + struct ol_txrx_pdev_t *pdev = cds_get_context(QDF_MODULE_ID_TXRX); + if (!pdev) { + qdf_print("%s: pdev is NULL\n", __func__); + return; + } + pdev->is_mgmt_over_wmi_enabled = value; + return; +} + +/** + * ol_tx_get_is_mgmt_over_wmi_enabled() - get value of is_mgmt_over_wmi_enabled + * + * Return: is_mgmt_over_wmi_enabled + */ +uint8_t ol_tx_get_is_mgmt_over_wmi_enabled(void) +{ + struct ol_txrx_pdev_t *pdev = cds_get_context(QDF_MODULE_ID_TXRX); + if (!pdev) { + qdf_print("%s: pdev is NULL\n", __func__); + return 0; + } + return pdev->is_mgmt_over_wmi_enabled; +} + + +#ifdef QCA_SUPPORT_TXRX_LOCAL_PEER_ID +ol_txrx_peer_handle +ol_txrx_find_peer_by_addr_and_vdev(ol_txrx_pdev_handle pdev, + ol_txrx_vdev_handle vdev, + uint8_t *peer_addr, uint8_t *peer_id) +{ + struct ol_txrx_peer_t *peer; + + peer = ol_txrx_peer_vdev_find_hash(pdev, vdev, peer_addr, 0, 1); + if (!peer) + return NULL; + *peer_id = peer->local_id; + OL_TXRX_PEER_UNREF_DELETE(peer); + return peer; +} + +QDF_STATUS ol_txrx_get_vdevid(struct ol_txrx_peer_t *peer, uint8_t *vdev_id) +{ + if (!peer) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "peer argument is null!!"); + return QDF_STATUS_E_FAILURE; + } + + *vdev_id = peer->vdev->vdev_id; + return QDF_STATUS_SUCCESS; +} + +void *ol_txrx_get_vdev_by_sta_id(uint8_t sta_id) +{ + struct ol_txrx_peer_t *peer = NULL; + ol_txrx_pdev_handle pdev = NULL; + + if (sta_id >= WLAN_MAX_STA_COUNT) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_HIGH, + "Invalid sta id passed"); + return NULL; + } + + pdev = cds_get_context(QDF_MODULE_ID_TXRX); + if (!pdev) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_HIGH, + "PDEV not found for sta_id [%d]", sta_id); + return NULL; + } + + peer = ol_txrx_peer_find_by_local_id(pdev, sta_id); + if (!peer) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_HIGH, + "PEER [%d] not found", sta_id); + return NULL; + } + + return peer->vdev; +} + +/** + * ol_txrx_find_peer_by_addr() - find peer via peer mac addr and peer_id + * @pdev: pointer of type ol_txrx_pdev_handle + * @peer_addr: peer mac addr + * @peer_id: pointer to fill in the value of peer->local_id for caller + * + * This function finds a peer with given mac address and returns its peer_id. + * Note that this function does not increment the peer->ref_cnt. + * This means that the peer may be deleted in some other parallel context after + * its been found. + * + * Return: peer handle if peer is found, NULL if peer is not found. + */ +ol_txrx_peer_handle ol_txrx_find_peer_by_addr(ol_txrx_pdev_handle pdev, + uint8_t *peer_addr, + uint8_t *peer_id) +{ + struct ol_txrx_peer_t *peer; + + peer = ol_txrx_peer_find_hash_find_inc_ref(pdev, peer_addr, 0, 1); + if (!peer) + return NULL; + *peer_id = peer->local_id; + OL_TXRX_PEER_UNREF_DELETE(peer); + return peer; +} + +/** + * ol_txrx_find_peer_by_addr_inc_ref() - find peer via peer mac addr and peer_id + * @pdev: pointer of type ol_txrx_pdev_handle + * @peer_addr: peer mac addr + * @peer_id: pointer to fill in the value of peer->local_id for caller + * + * This function finds the peer with given mac address and returns its peer_id. + * Note that this function increments the peer->ref_cnt. + * This makes sure that peer will be valid. This also means the caller needs to + * call the corresponding API - OL_TXRX_PEER_UNREF_DELETE to delete the peer + * reference. + * Sample usage: + * { + * //the API call below increments the peer->ref_cnt + * peer = ol_txrx_find_peer_by_addr_inc_ref(pdev, peer_addr, peer_id); + * + * // Once peer usage is done + * + * //the API call below decrements the peer->ref_cnt + * OL_TXRX_PEER_UNREF_DELETE(peer); + * } + * + * Return: peer handle if the peer is found, NULL if peer is not found. + */ +ol_txrx_peer_handle ol_txrx_find_peer_by_addr_inc_ref(ol_txrx_pdev_handle pdev, + uint8_t *peer_addr, + uint8_t *peer_id) +{ + struct ol_txrx_peer_t *peer; + + peer = ol_txrx_peer_find_hash_find_inc_ref(pdev, peer_addr, 0, 1); + if (!peer) + return NULL; + *peer_id = peer->local_id; + return peer; +} + +uint16_t ol_txrx_local_peer_id(ol_txrx_peer_handle peer) +{ + return peer->local_id; +} + +/** + * @brief Find a txrx peer handle from a peer's local ID + * @details + * The control SW typically uses the txrx peer handle to refer to the peer. + * In unusual circumstances, if it is infeasible for the control SW maintain + * the txrx peer handle but it can maintain a small integer local peer ID, + * this function allows the peer handled to be retrieved, based on the local + * peer ID. + * + * @param pdev - the data physical device object + * @param local_peer_id - the ID txrx assigned locally to the peer in question + * @return handle to the txrx peer object + */ +ol_txrx_peer_handle +ol_txrx_peer_find_by_local_id(struct ol_txrx_pdev_t *pdev, + uint8_t local_peer_id) +{ + struct ol_txrx_peer_t *peer; + if ((local_peer_id == OL_TXRX_INVALID_LOCAL_PEER_ID) || + (local_peer_id >= OL_TXRX_NUM_LOCAL_PEER_IDS)) { + return NULL; + } + + qdf_spin_lock_bh(&pdev->local_peer_ids.lock); + peer = pdev->local_peer_ids.map[local_peer_id]; + qdf_spin_unlock_bh(&pdev->local_peer_ids.lock); + return peer; +} + +static void ol_txrx_local_peer_id_pool_init(struct ol_txrx_pdev_t *pdev) +{ + int i; + + /* point the freelist to the first ID */ + pdev->local_peer_ids.freelist = 0; + + /* link each ID to the next one */ + for (i = 0; i < OL_TXRX_NUM_LOCAL_PEER_IDS; i++) { + pdev->local_peer_ids.pool[i] = i + 1; + pdev->local_peer_ids.map[i] = NULL; + } + + /* link the last ID to itself, to mark the end of the list */ + i = OL_TXRX_NUM_LOCAL_PEER_IDS; + pdev->local_peer_ids.pool[i] = i; + + qdf_spinlock_create(&pdev->local_peer_ids.lock); +} + +static void +ol_txrx_local_peer_id_alloc(struct ol_txrx_pdev_t *pdev, + struct ol_txrx_peer_t *peer) +{ + int i; + + qdf_spin_lock_bh(&pdev->local_peer_ids.lock); + i = pdev->local_peer_ids.freelist; + if (pdev->local_peer_ids.pool[i] == i) { + /* the list is empty, except for the list-end marker */ + peer->local_id = OL_TXRX_INVALID_LOCAL_PEER_ID; + } else { + /* take the head ID and advance the freelist */ + peer->local_id = i; + pdev->local_peer_ids.freelist = pdev->local_peer_ids.pool[i]; + pdev->local_peer_ids.map[i] = peer; + } + qdf_spin_unlock_bh(&pdev->local_peer_ids.lock); +} + +static void +ol_txrx_local_peer_id_free(struct ol_txrx_pdev_t *pdev, + struct ol_txrx_peer_t *peer) +{ + int i = peer->local_id; + if ((i == OL_TXRX_INVALID_LOCAL_PEER_ID) || + (i >= OL_TXRX_NUM_LOCAL_PEER_IDS)) { + return; + } + /* put this ID on the head of the freelist */ + qdf_spin_lock_bh(&pdev->local_peer_ids.lock); + pdev->local_peer_ids.pool[i] = pdev->local_peer_ids.freelist; + pdev->local_peer_ids.freelist = i; + pdev->local_peer_ids.map[i] = NULL; + qdf_spin_unlock_bh(&pdev->local_peer_ids.lock); +} + +static void ol_txrx_local_peer_id_cleanup(struct ol_txrx_pdev_t *pdev) +{ + qdf_spinlock_destroy(&pdev->local_peer_ids.lock); +} + +#else +#define ol_txrx_local_peer_id_pool_init(pdev) /* no-op */ +#define ol_txrx_local_peer_id_alloc(pdev, peer) /* no-op */ +#define ol_txrx_local_peer_id_free(pdev, peer) /* no-op */ +#define ol_txrx_local_peer_id_cleanup(pdev) /* no-op */ +#endif + +#ifdef FEATURE_HL_GROUP_CREDIT_FLOW_CONTROL + +/** + * ol_txrx_update_group_credit() - update group credit for tx queue + * @group: for which credit needs to be updated + * @credit: credits + * @absolute: TXQ group absolute + * + * Return: allocated pool size + */ +void ol_txrx_update_group_credit( + struct ol_tx_queue_group_t *group, + int32_t credit, + u_int8_t absolute) +{ + if (absolute) + qdf_atomic_set(&group->credit, credit); + else + qdf_atomic_add(credit, &group->credit); +} + +/** + * ol_txrx_update_tx_queue_groups() - update vdev tx queue group if + * vdev id mask and ac mask is not matching + * @pdev: the data physical device + * @group_id: TXQ group id + * @credit: TXQ group credit count + * @absolute: TXQ group absolute + * @vdev_id_mask: TXQ vdev group id mask + * @ac_mask: TQX access category mask + * + * Return: None + */ +void ol_txrx_update_tx_queue_groups( + ol_txrx_pdev_handle pdev, + u_int8_t group_id, + int32_t credit, + u_int8_t absolute, + u_int32_t vdev_id_mask, + u_int32_t ac_mask + ) +{ + struct ol_tx_queue_group_t *group; + u_int32_t group_vdev_bit_mask, vdev_bit_mask, group_vdev_id_mask; + u_int32_t membership; + struct ol_txrx_vdev_t *vdev; + group = &pdev->txq_grps[group_id]; + + membership = OL_TXQ_GROUP_MEMBERSHIP_GET(vdev_id_mask, ac_mask); + + qdf_spin_lock_bh(&pdev->tx_queue_spinlock); + /* + * if the membership (vdev id mask and ac mask) + * matches then no need to update tx qeue groups. + */ + if (group->membership == membership) + /* Update Credit Only */ + goto credit_update; + + + /* + * membership (vdev id mask and ac mask) is not matching + * TODO: ignoring ac mask for now + */ + group_vdev_id_mask = + OL_TXQ_GROUP_VDEV_ID_MASK_GET(group->membership); + + TAILQ_FOREACH(vdev, &pdev->vdev_list, vdev_list_elem) { + group_vdev_bit_mask = + OL_TXQ_GROUP_VDEV_ID_BIT_MASK_GET( + group_vdev_id_mask, vdev->vdev_id); + vdev_bit_mask = + OL_TXQ_GROUP_VDEV_ID_BIT_MASK_GET( + vdev_id_mask, vdev->vdev_id); + + if (group_vdev_bit_mask != vdev_bit_mask) { + /* + * Change in vdev tx queue group + */ + if (!vdev_bit_mask) { + /* Set Group Pointer (vdev and peer) to NULL */ + ol_tx_set_vdev_group_ptr( + pdev, vdev->vdev_id, NULL); + } else { + /* Set Group Pointer (vdev and peer) */ + ol_tx_set_vdev_group_ptr( + pdev, vdev->vdev_id, group); + } + } + } + /* Update membership */ + group->membership = membership; +credit_update: + /* Update Credit */ + ol_txrx_update_group_credit(group, credit, absolute); + qdf_spin_unlock_bh(&pdev->tx_queue_spinlock); +} +#endif + +#ifdef WLAN_FEATURE_FASTPATH +/** + * setup_fastpath_ce_handles() Update pdev with ce_handle for fastpath use. + * + * @osc: pointer to HIF context + * @pdev: pointer to ol pdev + * + * Return: void + */ +static inline void setup_fastpath_ce_handles(struct hif_opaque_softc *osc, + struct ol_txrx_pdev_t *pdev) +{ + /* + * Before the HTT attach, set up the CE handles + * CE handles are (struct CE_state *) + * This is only required in the fast path + */ + pdev->ce_tx_hdl = hif_get_ce_handle(osc, CE_HTT_H2T_MSG); + +} + +#else /* not WLAN_FEATURE_FASTPATH */ +static inline void setup_fastpath_ce_handles(struct hif_opaque_softc *osc, + struct ol_txrx_pdev_t *pdev) +{ +} +#endif /* WLAN_FEATURE_FASTPATH */ + +#ifdef QCA_LL_TX_FLOW_CONTROL_V2 +/** + * ol_tx_set_desc_global_pool_size() - set global pool size + * @num_msdu_desc: total number of descriptors + * + * Return: none + */ +void ol_tx_set_desc_global_pool_size(uint32_t num_msdu_desc) +{ + struct ol_txrx_pdev_t *pdev = cds_get_context(QDF_MODULE_ID_TXRX); + if (!pdev) { + qdf_print("%s: pdev is NULL\n", __func__); + return; + } + pdev->num_msdu_desc = num_msdu_desc; + if (!ol_tx_get_is_mgmt_over_wmi_enabled()) + pdev->num_msdu_desc += TX_FLOW_MGMT_POOL_SIZE; + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, "Global pool size: %d\n", + pdev->num_msdu_desc); + return; +} + +/** + * ol_tx_get_desc_global_pool_size() - get global pool size + * @pdev: pdev handle + * + * Return: global pool size + */ +static inline +uint32_t ol_tx_get_desc_global_pool_size(struct ol_txrx_pdev_t *pdev) +{ + return pdev->num_msdu_desc; +} + +/** + * ol_tx_get_total_free_desc() - get total free descriptors + * @pdev: pdev handle + * + * Return: total free descriptors + */ +static inline +uint32_t ol_tx_get_total_free_desc(struct ol_txrx_pdev_t *pdev) +{ + struct ol_tx_flow_pool_t *pool = NULL; + uint32_t free_desc; + + free_desc = pdev->tx_desc.num_free; + qdf_spin_lock_bh(&pdev->tx_desc.flow_pool_list_lock); + TAILQ_FOREACH(pool, &pdev->tx_desc.flow_pool_list, + flow_pool_list_elem) { + qdf_spin_lock_bh(&pool->flow_pool_lock); + free_desc += pool->avail_desc; + qdf_spin_unlock_bh(&pool->flow_pool_lock); + } + qdf_spin_unlock_bh(&pdev->tx_desc.flow_pool_list_lock); + + return free_desc; +} + +#else +/** + * ol_tx_get_desc_global_pool_size() - get global pool size + * @pdev: pdev handle + * + * Return: global pool size + */ +static inline +uint32_t ol_tx_get_desc_global_pool_size(struct ol_txrx_pdev_t *pdev) +{ + return ol_cfg_target_tx_credit(pdev->ctrl_pdev); +} + +/** + * ol_tx_get_total_free_desc() - get total free descriptors + * @pdev: pdev handle + * + * Return: total free descriptors + */ +static inline +uint32_t ol_tx_get_total_free_desc(struct ol_txrx_pdev_t *pdev) +{ + return pdev->tx_desc.num_free; +} + +#endif + +#if defined(CONFIG_HL_SUPPORT) && defined(CONFIG_PER_VDEV_TX_DESC_POOL) + +/** + * ol_txrx_rsrc_threshold_lo() - set threshold low - when to start tx desc + * margin replenishment + * @desc_pool_size: tx desc pool size + * + * Return: threshold low + */ +static inline uint16_t +ol_txrx_rsrc_threshold_lo(int desc_pool_size) +{ + int threshold_low; + /* + * 5% margin of unallocated desc is too much for per + * vdev mechanism. + * Define the value seperately. + */ + threshold_low = TXRX_HL_TX_FLOW_CTRL_MGMT_RESERVED; + + return threshold_low; +} + +/** + * ol_txrx_rsrc_threshold_hi() - set threshold high - where to stop + * during tx desc margin replenishment + * @desc_pool_size: tx desc pool size + * + * Return: threshold high + */ +static inline uint16_t +ol_txrx_rsrc_threshold_hi(int desc_pool_size) +{ + int threshold_high; + /* when freeing up descriptors, + * keep going until there's a 7.5% margin + */ + threshold_high = ((15 * desc_pool_size)/100)/2; + + return threshold_high; +} +#else + +static inline uint16_t +ol_txrx_rsrc_threshold_lo(int desc_pool_size) +{ + int threshold_low; + /* always maintain a 5% margin of unallocated descriptors */ + threshold_low = (5 * desc_pool_size)/100; + + return threshold_low; +} + +static inline uint16_t +ol_txrx_rsrc_threshold_hi(int desc_pool_size) +{ + int threshold_high; + /* when freeing up descriptors, keep going until + * there's a 15% margin + */ + threshold_high = (15 * desc_pool_size)/100; + + return threshold_high; +} +#endif + +#if defined(CONFIG_HL_SUPPORT) && defined(DEBUG_HL_LOGGING) + +/** + * ol_txrx_pdev_txq_log_init() - initialise pdev txq logs + * @pdev: the physical device object + * + * Return: None + */ +static void +ol_txrx_pdev_txq_log_init(struct ol_txrx_pdev_t *pdev) +{ + qdf_spinlock_create(&pdev->txq_log_spinlock); + pdev->txq_log.size = OL_TXQ_LOG_SIZE; + pdev->txq_log.oldest_record_offset = 0; + pdev->txq_log.offset = 0; + pdev->txq_log.allow_wrap = 1; + pdev->txq_log.wrapped = 0; +} + +/** + * ol_txrx_pdev_txq_log_destroy() - remove txq log spinlock for pdev + * @pdev: the physical device object + * + * Return: None + */ +static inline void +ol_txrx_pdev_txq_log_destroy(struct ol_txrx_pdev_t *pdev) +{ + qdf_spinlock_destroy(&pdev->txq_log_spinlock); +} + +#else + +static inline void +ol_txrx_pdev_txq_log_init(struct ol_txrx_pdev_t *pdev) +{ + return; +} + +static inline void +ol_txrx_pdev_txq_log_destroy(struct ol_txrx_pdev_t *pdev) +{ + return; +} + + +#endif + +#if defined(DEBUG_HL_LOGGING) + +/** + * ol_txrx_pdev_grp_stats_init() - initialise group stat spinlock for pdev + * @pdev: the physical device object + * + * Return: None + */ +static inline void +ol_txrx_pdev_grp_stats_init(struct ol_txrx_pdev_t *pdev) +{ + qdf_spinlock_create(&pdev->grp_stat_spinlock); + pdev->grp_stats.last_valid_index = -1; + pdev->grp_stats.wrap_around = 0; +} + +/** + * ol_txrx_pdev_grp_stat_destroy() - destroy group stat spinlock for pdev + * @pdev: the physical device object + * + * Return: None + */ +static inline void +ol_txrx_pdev_grp_stat_destroy(struct ol_txrx_pdev_t *pdev) +{ + qdf_spinlock_destroy(&pdev->grp_stat_spinlock); +} +#else + +static inline void +ol_txrx_pdev_grp_stats_init(struct ol_txrx_pdev_t *pdev) +{ + return; +} + +static inline void +ol_txrx_pdev_grp_stat_destroy(struct ol_txrx_pdev_t *pdev) +{ + return; +} +#endif + +#if defined(CONFIG_HL_SUPPORT) && defined(FEATURE_WLAN_TDLS) + +/** + * ol_txrx_hl_tdls_flag_reset() - reset tdls flag for vdev + * @vdev: the virtual device object + * @flag: flag + * + * Return: None + */ +void +ol_txrx_hl_tdls_flag_reset(struct ol_txrx_vdev_t *vdev, bool flag) +{ + vdev->hlTdlsFlag = flag; +} +#endif + +#if defined(CONFIG_HL_SUPPORT) + +/** + * ol_txrx_vdev_txqs_init() - initialise vdev tx queues + * @vdev: the virtual device object + * + * Return: None + */ +static void +ol_txrx_vdev_txqs_init(struct ol_txrx_vdev_t *vdev) +{ + u_int8_t i; + for (i = 0; i < OL_TX_VDEV_NUM_QUEUES; i++) { + TAILQ_INIT(&vdev->txqs[i].head); + vdev->txqs[i].paused_count.total = 0; + vdev->txqs[i].frms = 0; + vdev->txqs[i].bytes = 0; + vdev->txqs[i].ext_tid = OL_TX_NUM_TIDS + i; + vdev->txqs[i].flag = ol_tx_queue_empty; + /* aggregation is not applicable for vdev tx queues */ + vdev->txqs[i].aggr_state = ol_tx_aggr_disabled; + ol_tx_txq_set_group_ptr(&vdev->txqs[i], NULL); + ol_txrx_set_txq_peer(&vdev->txqs[i], NULL); + } +} + +/** + * ol_txrx_vdev_tx_queue_free() - free vdev tx queues + * @vdev: the virtual device object + * + * Return: None + */ +static void +ol_txrx_vdev_tx_queue_free(struct ol_txrx_vdev_t *vdev) +{ + struct ol_txrx_pdev_t *pdev = vdev->pdev; + struct ol_tx_frms_queue_t *txq; + int i; + + for (i = 0; i < OL_TX_VDEV_NUM_QUEUES; i++) { + txq = &vdev->txqs[i]; + ol_tx_queue_free(pdev, txq, (i + OL_TX_NUM_TIDS), false); + } +} + +/** + * ol_txrx_peer_txqs_init() - initialise peer tx queues + * @pdev: the physical device object + * @peer: peer object + * + * Return: None + */ +static void +ol_txrx_peer_txqs_init(struct ol_txrx_pdev_t *pdev, + struct ol_txrx_peer_t *peer) +{ + uint8_t i; + struct ol_txrx_vdev_t *vdev = peer->vdev; + qdf_spin_lock_bh(&pdev->tx_queue_spinlock); + for (i = 0; i < OL_TX_NUM_TIDS; i++) { + TAILQ_INIT(&peer->txqs[i].head); + peer->txqs[i].paused_count.total = 0; + peer->txqs[i].frms = 0; + peer->txqs[i].bytes = 0; + peer->txqs[i].ext_tid = i; + peer->txqs[i].flag = ol_tx_queue_empty; + peer->txqs[i].aggr_state = ol_tx_aggr_untried; + ol_tx_set_peer_group_ptr(pdev, peer, vdev->vdev_id, i); + ol_txrx_set_txq_peer(&peer->txqs[i], peer); + } + qdf_spin_unlock_bh(&pdev->tx_queue_spinlock); + + /* aggregation is not applicable for mgmt and non-QoS tx queues */ + for (i = OL_TX_NUM_QOS_TIDS; i < OL_TX_NUM_TIDS; i++) + peer->txqs[i].aggr_state = ol_tx_aggr_disabled; + + ol_txrx_peer_pause(peer); +} + +/** + * ol_txrx_peer_tx_queue_free() - free peer tx queues + * @pdev: the physical device object + * @peer: peer object + * + * Return: None + */ +static void +ol_txrx_peer_tx_queue_free(struct ol_txrx_pdev_t *pdev, + struct ol_txrx_peer_t *peer) +{ + struct ol_tx_frms_queue_t *txq; + uint8_t i; + + for (i = 0; i < OL_TX_NUM_TIDS; i++) { + txq = &peer->txqs[i]; + ol_tx_queue_free(pdev, txq, i, true); + } +} +#else + +static inline void +ol_txrx_vdev_txqs_init(struct ol_txrx_vdev_t *vdev) +{ + return; +} + +static inline void +ol_txrx_vdev_tx_queue_free(struct ol_txrx_vdev_t *vdev) +{ + return; +} + +static inline void +ol_txrx_peer_txqs_init(struct ol_txrx_pdev_t *pdev, + struct ol_txrx_peer_t *peer) +{ + return; +} + +static inline void +ol_txrx_peer_tx_queue_free(struct ol_txrx_pdev_t *pdev, + struct ol_txrx_peer_t *peer) +{ + return; +} +#endif + +#if defined(FEATURE_TSO) && defined(FEATURE_TSO_DEBUG) +static void ol_txrx_tso_stats_init(ol_txrx_pdev_handle pdev) +{ + qdf_spinlock_create(&pdev->stats.pub.tx.tso.tso_stats_lock); +} + +static void ol_txrx_tso_stats_deinit(ol_txrx_pdev_handle pdev) +{ + qdf_spinlock_destroy(&pdev->stats.pub.tx.tso.tso_stats_lock); +} + +static void ol_txrx_stats_display_tso(ol_txrx_pdev_handle pdev) +{ + int msdu_idx; + int seg_idx; + + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "TSO Statistics:"); + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "TSO pkts %lld, bytes %lld\n", + pdev->stats.pub.tx.tso.tso_pkts.pkts, + pdev->stats.pub.tx.tso.tso_pkts.bytes); + + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "TSO Histogram for numbers of segments:\n" + "Single segment %d\n" + " 2-5 segments %d\n" + " 6-10 segments %d\n" + "11-15 segments %d\n" + "16-20 segments %d\n" + " 20+ segments %d\n", + pdev->stats.pub.tx.tso.tso_hist.pkts_1, + pdev->stats.pub.tx.tso.tso_hist.pkts_2_5, + pdev->stats.pub.tx.tso.tso_hist.pkts_6_10, + pdev->stats.pub.tx.tso.tso_hist.pkts_11_15, + pdev->stats.pub.tx.tso.tso_hist.pkts_16_20, + pdev->stats.pub.tx.tso.tso_hist.pkts_20_plus); + + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "TSO History Buffer: Total size %d, current_index %d", + NUM_MAX_TSO_MSDUS, + TXRX_STATS_TSO_MSDU_IDX(pdev)); + + for (msdu_idx = 0; msdu_idx < NUM_MAX_TSO_MSDUS; msdu_idx++) { + if (TXRX_STATS_TSO_MSDU_TOTAL_LEN(pdev, msdu_idx) == 0) + continue; + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "jumbo pkt idx: %d num segs %d gso_len %d total_len %d nr_frags %d", + msdu_idx, + TXRX_STATS_TSO_MSDU_NUM_SEG(pdev, msdu_idx), + TXRX_STATS_TSO_MSDU_GSO_SIZE(pdev, msdu_idx), + TXRX_STATS_TSO_MSDU_TOTAL_LEN(pdev, msdu_idx), + TXRX_STATS_TSO_MSDU_NR_FRAGS(pdev, msdu_idx)); + + for (seg_idx = 0; + ((seg_idx < TXRX_STATS_TSO_MSDU_NUM_SEG(pdev, msdu_idx)) && + (seg_idx < NUM_MAX_TSO_SEGS)); + seg_idx++) { + struct qdf_tso_seg_t tso_seg = + TXRX_STATS_TSO_SEG(pdev, msdu_idx, seg_idx); + + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "seg idx: %d", seg_idx); + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "tso_enable: %d", + tso_seg.tso_flags.tso_enable); + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "fin %d syn %d rst %d psh %d ack %d urg %d ece %d cwr %d ns %d", + tso_seg.tso_flags.fin, tso_seg.tso_flags.syn, + tso_seg.tso_flags.rst, tso_seg.tso_flags.psh, + tso_seg.tso_flags.ack, tso_seg.tso_flags.urg, + tso_seg.tso_flags.ece, tso_seg.tso_flags.cwr, + tso_seg.tso_flags.ns); + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "tcp_seq_num: 0x%x ip_id: %d", + tso_seg.tso_flags.tcp_seq_num, + tso_seg.tso_flags.ip_id); + } + } +} +#else +static void ol_txrx_stats_display_tso(ol_txrx_pdev_handle pdev) +{ + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "TSO is not supported\n"); +} + +static void ol_txrx_tso_stats_init(ol_txrx_pdev_handle pdev) +{ + /* + * keeping the body empty and not keeping an error print as print will + * will show up everytime during driver load if TSO is not enabled. + */ +} + +static void ol_txrx_tso_stats_deinit(ol_txrx_pdev_handle pdev) +{ + /* + * keeping the body empty and not keeping an error print as print will + * will show up everytime during driver unload if TSO is not enabled. + */ +} + +#endif /* defined(FEATURE_TSO) && defined(FEATURE_TSO_DEBUG) */ + +/** + * ol_txrx_pdev_attach() - allocate txrx pdev + * @ctrl_pdev: cfg pdev + * @htc_pdev: HTC pdev + * @osdev: os dev + * + * Return: txrx pdev handle + * NULL for failure + */ +ol_txrx_pdev_handle +ol_txrx_pdev_attach(ol_pdev_handle ctrl_pdev, + HTC_HANDLE htc_pdev, qdf_device_t osdev) +{ + struct ol_txrx_pdev_t *pdev; + int i; + + pdev = qdf_mem_malloc(sizeof(*pdev)); + if (!pdev) + goto fail0; + + /* init LL/HL cfg here */ + pdev->cfg.is_high_latency = ol_cfg_is_high_latency(ctrl_pdev); + pdev->cfg.default_tx_comp_req = !ol_cfg_tx_free_at_download(ctrl_pdev); + + /* store provided params */ + pdev->ctrl_pdev = ctrl_pdev; + pdev->osdev = osdev; + + for (i = 0; i < htt_num_sec_types; i++) + pdev->sec_types[i] = (enum ol_sec_type)i; + + TXRX_STATS_INIT(pdev); + ol_txrx_tso_stats_init(pdev); + + TAILQ_INIT(&pdev->vdev_list); + + /* do initial set up of the peer ID -> peer object lookup map */ + if (ol_txrx_peer_find_attach(pdev)) + goto fail1; + + /* initialize the counter of the target's tx buffer availability */ + qdf_atomic_init(&pdev->target_tx_credit); + qdf_atomic_init(&pdev->orig_target_tx_credit); + + if (ol_cfg_is_high_latency(ctrl_pdev)) { + qdf_spinlock_create(&pdev->tx_queue_spinlock); + pdev->tx_sched.scheduler = ol_tx_sched_attach(pdev); + if (pdev->tx_sched.scheduler == NULL) + goto fail2; + } + ol_txrx_pdev_txq_log_init(pdev); + ol_txrx_pdev_grp_stats_init(pdev); + + pdev->htt_pdev = + htt_pdev_alloc(pdev, ctrl_pdev, htc_pdev, osdev); + if (!pdev->htt_pdev) + goto fail3; + + htt_register_rx_pkt_dump_callback(pdev->htt_pdev, + ol_rx_pkt_dump_call); + return pdev; + +fail3: + ol_txrx_peer_find_detach(pdev); + +fail2: + if (ol_cfg_is_high_latency(ctrl_pdev)) + qdf_spinlock_destroy(&pdev->tx_queue_spinlock); + +fail1: + ol_txrx_tso_stats_deinit(pdev); + qdf_mem_free(pdev); + +fail0: + return NULL; +} + +#if !defined(REMOVE_PKT_LOG) && !defined(QVIT) +/** + * htt_pkt_log_init() - API to initialize packet log + * @handle: pdev handle + * @scn: HIF context + * + * Return: void + */ +void htt_pkt_log_init(struct ol_txrx_pdev_t *handle, void *scn) +{ + if (handle->pkt_log_init) + return; + + if (cds_get_conparam() != QDF_GLOBAL_FTM_MODE && + !QDF_IS_EPPING_ENABLED(cds_get_conparam())) { + ol_pl_sethandle(&handle->pl_dev, scn); + if (pktlogmod_init(scn)) + qdf_print("%s: pktlogmod_init failed", __func__); + else + handle->pkt_log_init = true; + } +} + +/** + * htt_pktlogmod_exit() - API to cleanup pktlog info + * @handle: Pdev handle + * @scn: HIF Context + * + * Return: void + */ +static void htt_pktlogmod_exit(struct ol_txrx_pdev_t *handle, void *scn) +{ + if (scn && cds_get_conparam() != QDF_GLOBAL_FTM_MODE && + !QDF_IS_EPPING_ENABLED(cds_get_conparam()) && + handle->pkt_log_init) { + pktlogmod_exit(scn); + handle->pkt_log_init = false; + } +} +#else +void htt_pkt_log_init(ol_txrx_pdev_handle handle, void *ol_sc) { } +static void htt_pktlogmod_exit(ol_txrx_pdev_handle handle, void *sc) { } +#endif + +/** + * ol_txrx_pdev_post_attach() - attach txrx pdev + * @pdev: txrx pdev + * + * Return: 0 for success + */ +int +ol_txrx_pdev_post_attach(ol_txrx_pdev_handle pdev) +{ + uint16_t i; + uint16_t fail_idx = 0; + int ret = 0; + uint16_t desc_pool_size; + struct hif_opaque_softc *osc = cds_get_context(QDF_MODULE_ID_HIF); + + uint16_t desc_element_size = sizeof(union ol_tx_desc_list_elem_t); + union ol_tx_desc_list_elem_t *c_element; + unsigned int sig_bit; + uint16_t desc_per_page; + + if (!osc) { + ret = -EINVAL; + goto ol_attach_fail; + } + + /* + * For LL, limit the number of host's tx descriptors to match + * the number of target FW tx descriptors. + * This simplifies the FW, by ensuring the host will never + * download more tx descriptors than the target has space for. + * The FW will drop/free low-priority tx descriptors when it + * starts to run low, so that in theory the host should never + * run out of tx descriptors. + */ + + /* + * LL - initialize the target credit outselves. + * HL - wait for a HTT target credit initialization + * during htt_attach. + */ + if (pdev->cfg.is_high_latency) { + desc_pool_size = ol_tx_desc_pool_size_hl(pdev->ctrl_pdev); + + qdf_atomic_init(&pdev->tx_queue.rsrc_cnt); + qdf_atomic_add(desc_pool_size, &pdev->tx_queue.rsrc_cnt); + + pdev->tx_queue.rsrc_threshold_lo = + ol_txrx_rsrc_threshold_lo(desc_pool_size); + pdev->tx_queue.rsrc_threshold_hi = + ol_txrx_rsrc_threshold_hi(desc_pool_size); + + for (i = 0 ; i < OL_TX_MAX_TXQ_GROUPS; i++) + qdf_atomic_init(&pdev->txq_grps[i].credit); + + ol_tx_target_credit_init(pdev, desc_pool_size); + } else { + qdf_atomic_add(ol_cfg_target_tx_credit(pdev->ctrl_pdev), + &pdev->target_tx_credit); + desc_pool_size = ol_tx_get_desc_global_pool_size(pdev); + } + + ol_tx_desc_dup_detect_init(pdev, desc_pool_size); + + setup_fastpath_ce_handles(osc, pdev); + + ret = htt_attach(pdev->htt_pdev, desc_pool_size); + if (ret) + goto htt_attach_fail; + + /* Attach micro controller data path offload resource */ + if (ol_cfg_ipa_uc_offload_enabled(pdev->ctrl_pdev)) { + ret = htt_ipa_uc_attach(pdev->htt_pdev); + if (ret) + goto uc_attach_fail; + } + + /* Calculate single element reserved size power of 2 */ + pdev->tx_desc.desc_reserved_size = qdf_get_pwr2(desc_element_size); + qdf_mem_multi_pages_alloc(pdev->osdev, &pdev->tx_desc.desc_pages, + pdev->tx_desc.desc_reserved_size, desc_pool_size, 0, true); + if ((0 == pdev->tx_desc.desc_pages.num_pages) || + (NULL == pdev->tx_desc.desc_pages.cacheable_pages)) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "Page alloc fail"); + ret = -ENOMEM; + goto page_alloc_fail; + } + desc_per_page = pdev->tx_desc.desc_pages.num_element_per_page; + pdev->tx_desc.offset_filter = desc_per_page - 1; + /* Calculate page divider to find page number */ + sig_bit = 0; + while (desc_per_page) { + sig_bit++; + desc_per_page = desc_per_page >> 1; + } + pdev->tx_desc.page_divider = (sig_bit - 1); + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "page_divider 0x%x, offset_filter 0x%x num elem %d, ol desc num page %d, ol desc per page %d", + pdev->tx_desc.page_divider, pdev->tx_desc.offset_filter, + desc_pool_size, pdev->tx_desc.desc_pages.num_pages, + pdev->tx_desc.desc_pages.num_element_per_page); + + /* + * Each SW tx desc (used only within the tx datapath SW) has a + * matching HTT tx desc (used for downloading tx meta-data to FW/HW). + * Go ahead and allocate the HTT tx desc and link it with the SW tx + * desc now, to avoid doing it during time-critical transmit. + */ + pdev->tx_desc.pool_size = desc_pool_size; + pdev->tx_desc.freelist = + (union ol_tx_desc_list_elem_t *) + (*pdev->tx_desc.desc_pages.cacheable_pages); + c_element = pdev->tx_desc.freelist; + for (i = 0; i < desc_pool_size; i++) { + void *htt_tx_desc; + void *htt_frag_desc = NULL; + qdf_dma_addr_t frag_paddr = 0; + qdf_dma_addr_t paddr; + + if (i == (desc_pool_size - 1)) + c_element->next = NULL; + else + c_element->next = (union ol_tx_desc_list_elem_t *) + ol_tx_desc_find(pdev, i + 1); + + htt_tx_desc = htt_tx_desc_alloc(pdev->htt_pdev, &paddr, i); + if (!htt_tx_desc) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_FATAL, + "%s: failed to alloc HTT tx desc (%d of %d)", + __func__, i, desc_pool_size); + fail_idx = i; + ret = -ENOMEM; + goto desc_alloc_fail; + } + + c_element->tx_desc.htt_tx_desc = htt_tx_desc; + c_element->tx_desc.htt_tx_desc_paddr = paddr; + ret = htt_tx_frag_alloc(pdev->htt_pdev, + i, &frag_paddr, &htt_frag_desc); + if (ret) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "%s: failed to alloc HTT frag dsc (%d/%d)", + __func__, i, desc_pool_size); + /* Is there a leak here, is this handling correct? */ + fail_idx = i; + goto desc_alloc_fail; + } + if (!ret && htt_frag_desc) { + /* Initialize the first 6 words (TSO flags) + of the frag descriptor */ + memset(htt_frag_desc, 0, 6 * sizeof(uint32_t)); + c_element->tx_desc.htt_frag_desc = htt_frag_desc; + c_element->tx_desc.htt_frag_desc_paddr = frag_paddr; + } +#ifdef QCA_SUPPORT_TXDESC_SANITY_CHECKS + c_element->tx_desc.pkt_type = 0xff; +#ifdef QCA_COMPUTE_TX_DELAY + c_element->tx_desc.entry_timestamp_ticks = + 0xffffffff; +#endif +#endif + c_element->tx_desc.id = i; + qdf_atomic_init(&c_element->tx_desc.ref_cnt); + c_element = c_element->next; + fail_idx = i; + } + + /* link SW tx descs into a freelist */ + pdev->tx_desc.num_free = desc_pool_size; + TXRX_PRINT(TXRX_PRINT_LEVEL_INFO1, + "%s first tx_desc:0x%p Last tx desc:0x%p\n", __func__, + (uint32_t *) pdev->tx_desc.freelist, + (uint32_t *) (pdev->tx_desc.freelist + desc_pool_size)); + + /* check what format of frames are expected to be delivered by the OS */ + pdev->frame_format = ol_cfg_frame_type(pdev->ctrl_pdev); + if (pdev->frame_format == wlan_frm_fmt_native_wifi) + pdev->htt_pkt_type = htt_pkt_type_native_wifi; + else if (pdev->frame_format == wlan_frm_fmt_802_3) { + if (ol_cfg_is_ce_classify_enabled(pdev->ctrl_pdev)) + pdev->htt_pkt_type = htt_pkt_type_eth2; + else + pdev->htt_pkt_type = htt_pkt_type_ethernet; + } else { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "%s Invalid standard frame type: %d", + __func__, pdev->frame_format); + ret = -EINVAL; + goto control_init_fail; + } + + /* setup the global rx defrag waitlist */ + TAILQ_INIT(&pdev->rx.defrag.waitlist); + + /* configure where defrag timeout and duplicate detection is handled */ + pdev->rx.flags.defrag_timeout_check = + pdev->rx.flags.dup_check = + ol_cfg_rx_host_defrag_timeout_duplicate_check(pdev->ctrl_pdev); + +#ifdef QCA_SUPPORT_SW_TXRX_ENCAP + /* Need to revisit this part. Currently,hardcode to riva's caps */ + pdev->target_tx_tran_caps = wlan_frm_tran_cap_raw; + pdev->target_rx_tran_caps = wlan_frm_tran_cap_raw; + /* + * The Riva HW de-aggregate doesn't have capability to generate 802.11 + * header for non-first subframe of A-MSDU. + */ + pdev->sw_subfrm_hdr_recovery_enable = 1; + /* + * The Riva HW doesn't have the capability to set Protected Frame bit + * in the MAC header for encrypted data frame. + */ + pdev->sw_pf_proc_enable = 1; + + if (pdev->frame_format == wlan_frm_fmt_802_3) { + /* sw llc process is only needed in + 802.3 to 802.11 transform case */ + pdev->sw_tx_llc_proc_enable = 1; + pdev->sw_rx_llc_proc_enable = 1; + } else { + pdev->sw_tx_llc_proc_enable = 0; + pdev->sw_rx_llc_proc_enable = 0; + } + + switch (pdev->frame_format) { + case wlan_frm_fmt_raw: + pdev->sw_tx_encap = + pdev->target_tx_tran_caps & wlan_frm_tran_cap_raw + ? 0 : 1; + pdev->sw_rx_decap = + pdev->target_rx_tran_caps & wlan_frm_tran_cap_raw + ? 0 : 1; + break; + case wlan_frm_fmt_native_wifi: + pdev->sw_tx_encap = + pdev-> + target_tx_tran_caps & wlan_frm_tran_cap_native_wifi + ? 0 : 1; + pdev->sw_rx_decap = + pdev-> + target_rx_tran_caps & wlan_frm_tran_cap_native_wifi + ? 0 : 1; + break; + case wlan_frm_fmt_802_3: + pdev->sw_tx_encap = + pdev->target_tx_tran_caps & wlan_frm_tran_cap_8023 + ? 0 : 1; + pdev->sw_rx_decap = + pdev->target_rx_tran_caps & wlan_frm_tran_cap_8023 + ? 0 : 1; + break; + default: + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "Invalid std frame type; [en/de]cap: f:%x t:%x r:%x", + pdev->frame_format, + pdev->target_tx_tran_caps, pdev->target_rx_tran_caps); + ret = -EINVAL; + goto control_init_fail; + } +#endif + + /* + * Determine what rx processing steps are done within the host. + * Possibilities: + * 1. Nothing - rx->tx forwarding and rx PN entirely within target. + * (This is unlikely; even if the target is doing rx->tx forwarding, + * the host should be doing rx->tx forwarding too, as a back up for + * the target's rx->tx forwarding, in case the target runs short on + * memory, and can't store rx->tx frames that are waiting for + * missing prior rx frames to arrive.) + * 2. Just rx -> tx forwarding. + * This is the typical configuration for HL, and a likely + * configuration for LL STA or small APs (e.g. retail APs). + * 3. Both PN check and rx -> tx forwarding. + * This is the typical configuration for large LL APs. + * Host-side PN check without rx->tx forwarding is not a valid + * configuration, since the PN check needs to be done prior to + * the rx->tx forwarding. + */ + if (ol_cfg_is_full_reorder_offload(pdev->ctrl_pdev)) { + /* PN check, rx-tx forwarding and rx reorder is done by + the target */ + if (ol_cfg_rx_fwd_disabled(pdev->ctrl_pdev)) + pdev->rx_opt_proc = ol_rx_in_order_deliver; + else + pdev->rx_opt_proc = ol_rx_fwd_check; + } else { + if (ol_cfg_rx_pn_check(pdev->ctrl_pdev)) { + if (ol_cfg_rx_fwd_disabled(pdev->ctrl_pdev)) { + /* + * PN check done on host, + * rx->tx forwarding not done at all. + */ + pdev->rx_opt_proc = ol_rx_pn_check_only; + } else if (ol_cfg_rx_fwd_check(pdev->ctrl_pdev)) { + /* + * Both PN check and rx->tx forwarding done + * on host. + */ + pdev->rx_opt_proc = ol_rx_pn_check; + } else { +#define TRACESTR01 "invalid config: if rx PN check is on the host,"\ +"rx->tx forwarding check needs to also be on the host" + QDF_TRACE(QDF_MODULE_ID_TXRX, + QDF_TRACE_LEVEL_ERROR, + "%s: %s", __func__, TRACESTR01); +#undef TRACESTR01 + ret = -EINVAL; + goto control_init_fail; + } + } else { + /* PN check done on target */ + if ((!ol_cfg_rx_fwd_disabled(pdev->ctrl_pdev)) && + ol_cfg_rx_fwd_check(pdev->ctrl_pdev)) { + /* + * rx->tx forwarding done on host (possibly as + * back-up for target-side primary rx->tx + * forwarding) + */ + pdev->rx_opt_proc = ol_rx_fwd_check; + } else { + /* rx->tx forwarding either done in target, + * or not done at all */ + pdev->rx_opt_proc = ol_rx_deliver; + } + } + } + + /* initialize mutexes for tx desc alloc and peer lookup */ + qdf_spinlock_create(&pdev->tx_mutex); + qdf_spinlock_create(&pdev->peer_ref_mutex); + qdf_spinlock_create(&pdev->rx.mutex); + qdf_spinlock_create(&pdev->last_real_peer_mutex); + qdf_spinlock_create(&pdev->peer_map_unmap_lock); + OL_TXRX_PEER_STATS_MUTEX_INIT(pdev); + + if (OL_RX_REORDER_TRACE_ATTACH(pdev) != A_OK) { + ret = -ENOMEM; + goto reorder_trace_attach_fail; + } + + if (OL_RX_PN_TRACE_ATTACH(pdev) != A_OK) { + ret = -ENOMEM; + goto pn_trace_attach_fail; + } + +#ifdef PERE_IP_HDR_ALIGNMENT_WAR + pdev->host_80211_enable = ol_scn_host_80211_enable_get(pdev->ctrl_pdev); +#endif + + /* + * WDI event attach + */ + wdi_event_attach(pdev); + + /* + * Initialize rx PN check characteristics for different security types. + */ + qdf_mem_set(&pdev->rx_pn[0], sizeof(pdev->rx_pn), 0); + + /* TKIP: 48-bit TSC, CCMP: 48-bit PN */ + pdev->rx_pn[htt_sec_type_tkip].len = + pdev->rx_pn[htt_sec_type_tkip_nomic].len = + pdev->rx_pn[htt_sec_type_aes_ccmp].len = 48; + pdev->rx_pn[htt_sec_type_tkip].cmp = + pdev->rx_pn[htt_sec_type_tkip_nomic].cmp = + pdev->rx_pn[htt_sec_type_aes_ccmp].cmp = ol_rx_pn_cmp48; + + /* WAPI: 128-bit PN */ + pdev->rx_pn[htt_sec_type_wapi].len = 128; + pdev->rx_pn[htt_sec_type_wapi].cmp = ol_rx_pn_wapi_cmp; + + OL_RX_REORDER_TIMEOUT_INIT(pdev); + + TXRX_PRINT(TXRX_PRINT_LEVEL_INFO1, "Created pdev %p\n", pdev); + + pdev->cfg.host_addba = ol_cfg_host_addba(pdev->ctrl_pdev); + +#ifdef QCA_SUPPORT_PEER_DATA_RX_RSSI +#define OL_TXRX_RSSI_UPDATE_SHIFT_DEFAULT 3 + +/* #if 1 -- TODO: clean this up */ +#define OL_TXRX_RSSI_NEW_WEIGHT_DEFAULT \ + /* avg = 100% * new + 0% * old */ \ + (1 << OL_TXRX_RSSI_UPDATE_SHIFT_DEFAULT) +/* +#else +#define OL_TXRX_RSSI_NEW_WEIGHT_DEFAULT + //avg = 25% * new + 25% * old + (1 << (OL_TXRX_RSSI_UPDATE_SHIFT_DEFAULT-2)) +#endif +*/ + pdev->rssi_update_shift = OL_TXRX_RSSI_UPDATE_SHIFT_DEFAULT; + pdev->rssi_new_weight = OL_TXRX_RSSI_NEW_WEIGHT_DEFAULT; +#endif + + ol_txrx_local_peer_id_pool_init(pdev); + + pdev->cfg.ll_pause_txq_limit = + ol_tx_cfg_max_tx_queue_depth_ll(pdev->ctrl_pdev); + + /* TX flow control for peer who is in very bad link status */ + ol_tx_badpeer_flow_cl_init(pdev); + +#ifdef QCA_COMPUTE_TX_DELAY + qdf_mem_zero(&pdev->tx_delay, sizeof(pdev->tx_delay)); + qdf_spinlock_create(&pdev->tx_delay.mutex); + + /* initialize compute interval with 5 seconds (ESE default) */ + pdev->tx_delay.avg_period_ticks = qdf_system_msecs_to_ticks(5000); + { + uint32_t bin_width_1000ticks; + bin_width_1000ticks = + qdf_system_msecs_to_ticks + (QCA_TX_DELAY_HIST_INTERNAL_BIN_WIDTH_MS + * 1000); + /* + * Compute a factor and shift that together are equal to the + * inverse of the bin_width time, so that rather than dividing + * by the bin width time, approximately the same result can be + * obtained much more efficiently by a multiply + shift. + * multiply_factor >> shift = 1 / bin_width_time, so + * multiply_factor = (1 << shift) / bin_width_time. + * + * Pick the shift semi-arbitrarily. + * If we knew statically what the bin_width would be, we could + * choose a shift that minimizes the error. + * Since the bin_width is determined dynamically, simply use a + * shift that is about half of the uint32_t size. This should + * result in a relatively large multiplier value, which + * minimizes error from rounding the multiplier to an integer. + * The rounding error only becomes significant if the tick units + * are on the order of 1 microsecond. In most systems, it is + * expected that the tick units will be relatively low-res, + * on the order of 1 millisecond. In such systems the rounding + * error is negligible. + * It would be more accurate to dynamically try out different + * shifts and choose the one that results in the smallest + * rounding error, but that extra level of fidelity is + * not needed. + */ + pdev->tx_delay.hist_internal_bin_width_shift = 16; + pdev->tx_delay.hist_internal_bin_width_mult = + ((1 << pdev->tx_delay.hist_internal_bin_width_shift) * + 1000 + (bin_width_1000ticks >> 1)) / + bin_width_1000ticks; + } +#endif /* QCA_COMPUTE_TX_DELAY */ + + /* Thermal Mitigation */ + ol_tx_throttle_init(pdev); + + ol_tso_seg_list_init(pdev, desc_pool_size); + + ol_tso_num_seg_list_init(pdev, desc_pool_size); + + ol_tx_register_flow_control(pdev); + + return 0; /* success */ + +pn_trace_attach_fail: + OL_RX_REORDER_TRACE_DETACH(pdev); + +reorder_trace_attach_fail: + qdf_spinlock_destroy(&pdev->tx_mutex); + qdf_spinlock_destroy(&pdev->peer_ref_mutex); + qdf_spinlock_destroy(&pdev->rx.mutex); + qdf_spinlock_destroy(&pdev->last_real_peer_mutex); + qdf_spinlock_destroy(&pdev->peer_map_unmap_lock); + OL_TXRX_PEER_STATS_MUTEX_DESTROY(pdev); + +control_init_fail: +desc_alloc_fail: + for (i = 0; i < fail_idx; i++) + htt_tx_desc_free(pdev->htt_pdev, + (ol_tx_desc_find(pdev, i))->htt_tx_desc); + + qdf_mem_multi_pages_free(pdev->osdev, + &pdev->tx_desc.desc_pages, 0, true); + +page_alloc_fail: + if (ol_cfg_ipa_uc_offload_enabled(pdev->ctrl_pdev)) + htt_ipa_uc_detach(pdev->htt_pdev); +uc_attach_fail: + htt_detach(pdev->htt_pdev); +htt_attach_fail: + ol_tx_desc_dup_detect_deinit(pdev); +ol_attach_fail: + return ret; /* fail */ +} + +/** + * ol_txrx_pdev_attach_target() - send target configuration + * + * @pdev - the physical device being initialized + * + * The majority of the data SW setup are done by the pdev_attach + * functions, but this function completes the data SW setup by + * sending datapath configuration messages to the target. + * + * Return: 0 - success 1 - failure + */ +A_STATUS ol_txrx_pdev_attach_target(ol_txrx_pdev_handle pdev) +{ + return htt_attach_target(pdev->htt_pdev) == A_OK ? 0:1; +} + +/** + * ol_tx_free_descs_inuse - free tx descriptors which are in use + * @pdev - the physical device for which tx descs need to be freed + * + * Cycle through the list of TX descriptors (for a pdev) which are in use, + * for which TX completion has not been received and free them. Should be + * called only when the interrupts are off and all lower layer RX is stopped. + * Otherwise there may be a race condition with TX completions. + * + * Return: None + */ +static void ol_tx_free_descs_inuse(ol_txrx_pdev_handle pdev) +{ + int i; + void *htt_tx_desc; + struct ol_tx_desc_t *tx_desc; + int num_freed_tx_desc = 0; + + for (i = 0; i < pdev->tx_desc.pool_size; i++) { + tx_desc = ol_tx_desc_find(pdev, i); + /* + * Confirm that each tx descriptor is "empty", i.e. it has + * no tx frame attached. + * In particular, check that there are no frames that have + * been given to the target to transmit, for which the + * target has never provided a response. + */ + if (qdf_atomic_read(&tx_desc->ref_cnt)) { + TXRX_PRINT(TXRX_PRINT_LEVEL_WARN, + "Warning: freeing tx frame (no compltn)\n"); + ol_tx_desc_frame_free_nonstd(pdev, + tx_desc, 1); + num_freed_tx_desc++; + } + htt_tx_desc = tx_desc->htt_tx_desc; + htt_tx_desc_free(pdev->htt_pdev, htt_tx_desc); + } + + if (num_freed_tx_desc) + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO, + "freed %d tx frames for which no resp from target", + num_freed_tx_desc); + +} + +/** + * ol_txrx_pdev_pre_detach() - detach the data SW state + * @pdev - the data physical device object being removed + * @force - delete the pdev (and its vdevs and peers) even if + * there are outstanding references by the target to the vdevs + * and peers within the pdev + * + * This function is used when the WLAN driver is being removed to + * detach the host data component within the driver. + * + * Return: None + */ +void ol_txrx_pdev_pre_detach(ol_txrx_pdev_handle pdev, int force) +{ + /* preconditions */ + TXRX_ASSERT2(pdev); + + /* check that the pdev has no vdevs allocated */ + TXRX_ASSERT1(TAILQ_EMPTY(&pdev->vdev_list)); + +#ifdef QCA_SUPPORT_TX_THROTTLE + /* Thermal Mitigation */ + qdf_timer_stop(&pdev->tx_throttle.phase_timer); + qdf_timer_free(&pdev->tx_throttle.phase_timer); +#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL + qdf_timer_stop(&pdev->tx_throttle.tx_timer); + qdf_timer_free(&pdev->tx_throttle.tx_timer); +#endif +#endif + + if (force) { + /* + * The assertion above confirms that all vdevs within this pdev + * were detached. However, they may not have actually been + * deleted. + * If the vdev had peers which never received a PEER_UNMAP msg + * from the target, then there are still zombie peer objects, + * and the vdev parents of the zombie peers are also zombies, + * hanging around until their final peer gets deleted. + * Go through the peer hash table and delete any peers left. + * As a side effect, this will complete the deletion of any + * vdevs that are waiting for their peers to finish deletion. + */ + TXRX_PRINT(TXRX_PRINT_LEVEL_INFO1, "Force delete for pdev %p\n", + pdev); + ol_txrx_peer_find_hash_erase(pdev); + } + + /* to get flow pool status before freeing descs */ + ol_tx_dump_flow_pool_info(); + + ol_tx_free_descs_inuse(pdev); + ol_tx_deregister_flow_control(pdev); + + /* + * ol_tso_seg_list_deinit should happen after + * ol_tx_deinit_tx_desc_inuse as it tries to access the tso seg freelist + * which is being de-initilized in ol_tso_seg_list_deinit + */ + ol_tso_seg_list_deinit(pdev); + ol_tso_num_seg_list_deinit(pdev); + + /* Stop the communication between HTT and target at first */ + htt_detach_target(pdev->htt_pdev); + + qdf_mem_multi_pages_free(pdev->osdev, + &pdev->tx_desc.desc_pages, 0, true); + pdev->tx_desc.freelist = NULL; + + /* Detach micro controller data path offload resource */ + if (ol_cfg_ipa_uc_offload_enabled(pdev->ctrl_pdev)) + htt_ipa_uc_detach(pdev->htt_pdev); + + htt_detach(pdev->htt_pdev); + ol_tx_desc_dup_detect_deinit(pdev); + + qdf_spinlock_destroy(&pdev->tx_mutex); + qdf_spinlock_destroy(&pdev->peer_ref_mutex); + qdf_spinlock_destroy(&pdev->last_real_peer_mutex); + qdf_spinlock_destroy(&pdev->rx.mutex); + qdf_spinlock_destroy(&pdev->peer_map_unmap_lock); +#ifdef QCA_SUPPORT_TX_THROTTLE + /* Thermal Mitigation */ + qdf_spinlock_destroy(&pdev->tx_throttle.mutex); +#endif + + /* TX flow control for peer who is in very bad link status */ + ol_tx_badpeer_flow_cl_deinit(pdev); + + OL_TXRX_PEER_STATS_MUTEX_DESTROY(pdev); + + OL_RX_REORDER_TRACE_DETACH(pdev); + OL_RX_PN_TRACE_DETACH(pdev); + + /* + * WDI event detach + */ + wdi_event_detach(pdev); + + ol_txrx_local_peer_id_cleanup(pdev); + +#ifdef QCA_COMPUTE_TX_DELAY + qdf_spinlock_destroy(&pdev->tx_delay.mutex); +#endif +} + +/** + * ol_txrx_pdev_detach() - delete the data SW state + * @pdev - the data physical device object being removed + * + * This function is used when the WLAN driver is being removed to + * remove the host data component within the driver. + * All virtual devices within the physical device need to be deleted + * (ol_txrx_vdev_detach) before the physical device itself is deleted. + * + * Return: None + */ +void ol_txrx_pdev_detach(ol_txrx_pdev_handle pdev) +{ + struct hif_opaque_softc *osc = cds_get_context(QDF_MODULE_ID_HIF); + + /*checking to ensure txrx pdev structure is not NULL */ + if (!pdev) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "NULL pdev passed to %s\n", __func__); + return; + } + + htt_pktlogmod_exit(pdev, osc); + + OL_RX_REORDER_TIMEOUT_CLEANUP(pdev); + + if (pdev->cfg.is_high_latency) + ol_tx_sched_detach(pdev); + + htt_deregister_rx_pkt_dump_callback(pdev->htt_pdev); + + htt_pdev_free(pdev->htt_pdev); + ol_txrx_peer_find_detach(pdev); + ol_txrx_tso_stats_deinit(pdev); + + ol_txrx_pdev_txq_log_destroy(pdev); + ol_txrx_pdev_grp_stat_destroy(pdev); +} + +#if defined(CONFIG_PER_VDEV_TX_DESC_POOL) + +/** + * ol_txrx_vdev_tx_desc_cnt_init() - initialise tx descriptor count for vdev + * @vdev: the virtual device object + * + * Return: None + */ +static inline void +ol_txrx_vdev_tx_desc_cnt_init(struct ol_txrx_vdev_t *vdev) +{ + qdf_atomic_init(&vdev->tx_desc_count); +} +#else + +static inline void +ol_txrx_vdev_tx_desc_cnt_init(struct ol_txrx_vdev_t *vdev) +{ + return; +} +#endif + +/** + * ol_txrx_vdev_attach - Allocate and initialize the data object + * for a new virtual device. + * + * @data_pdev - the physical device the virtual device belongs to + * @vdev_mac_addr - the MAC address of the virtual device + * @vdev_id - the ID used to identify the virtual device to the target + * @op_mode - whether this virtual device is operating as an AP, + * an IBSS, or a STA + * + * Return: success: handle to new data vdev object, failure: NULL + */ +ol_txrx_vdev_handle +ol_txrx_vdev_attach(ol_txrx_pdev_handle pdev, + uint8_t *vdev_mac_addr, + uint8_t vdev_id, enum wlan_op_mode op_mode) +{ + struct ol_txrx_vdev_t *vdev; + QDF_STATUS qdf_status; + + /* preconditions */ + TXRX_ASSERT2(pdev); + TXRX_ASSERT2(vdev_mac_addr); + + vdev = qdf_mem_malloc(sizeof(*vdev)); + if (!vdev) + return NULL; /* failure */ + + /* store provided params */ + vdev->pdev = pdev; + vdev->vdev_id = vdev_id; + vdev->opmode = op_mode; + + vdev->delete.pending = 0; + vdev->safemode = 0; + vdev->drop_unenc = 1; + vdev->num_filters = 0; + vdev->fwd_tx_packets = 0; + vdev->fwd_rx_packets = 0; + + ol_txrx_vdev_tx_desc_cnt_init(vdev); + + qdf_mem_copy(&vdev->mac_addr.raw[0], vdev_mac_addr, + OL_TXRX_MAC_ADDR_LEN); + + TAILQ_INIT(&vdev->peer_list); + vdev->last_real_peer = NULL; + + ol_txrx_hl_tdls_flag_reset(vdev, false); + +#ifdef QCA_IBSS_SUPPORT + vdev->ibss_peer_num = 0; + vdev->ibss_peer_heart_beat_timer = 0; +#endif + + ol_txrx_vdev_txqs_init(vdev); + + qdf_spinlock_create(&vdev->ll_pause.mutex); + vdev->ll_pause.paused_reason = 0; + vdev->ll_pause.txq.head = vdev->ll_pause.txq.tail = NULL; + vdev->ll_pause.txq.depth = 0; + qdf_timer_init(pdev->osdev, + &vdev->ll_pause.timer, + ol_tx_vdev_ll_pause_queue_send, vdev, + QDF_TIMER_TYPE_SW); + qdf_atomic_init(&vdev->os_q_paused); + qdf_atomic_set(&vdev->os_q_paused, 0); + vdev->tx_fl_lwm = 0; + vdev->tx_fl_hwm = 0; + vdev->rx = NULL; + vdev->wait_on_peer_id = OL_TXRX_INVALID_LOCAL_PEER_ID; + qdf_mem_zero(&vdev->last_peer_mac_addr, + sizeof(union ol_txrx_align_mac_addr_t)); + qdf_spinlock_create(&vdev->flow_control_lock); + vdev->osif_flow_control_cb = NULL; + vdev->osif_fc_ctx = NULL; + + /* Default MAX Q depth for every VDEV */ + vdev->ll_pause.max_q_depth = + ol_tx_cfg_max_tx_queue_depth_ll(vdev->pdev->ctrl_pdev); + qdf_status = qdf_event_create(&vdev->wait_delete_comp); + /* add this vdev into the pdev's list */ + TAILQ_INSERT_TAIL(&pdev->vdev_list, vdev, vdev_list_elem); + + TXRX_PRINT(TXRX_PRINT_LEVEL_INFO1, + "Created vdev %p (%02x:%02x:%02x:%02x:%02x:%02x)\n", + vdev, + vdev->mac_addr.raw[0], vdev->mac_addr.raw[1], + vdev->mac_addr.raw[2], vdev->mac_addr.raw[3], + vdev->mac_addr.raw[4], vdev->mac_addr.raw[5]); + + /* + * We've verified that htt_op_mode == wlan_op_mode, + * so no translation is needed. + */ + htt_vdev_attach(pdev->htt_pdev, vdev_id, op_mode); + + return vdev; +} + +/** + *ol_txrx_vdev_register - Link a vdev's data object with the + * matching OS shim vdev object. + * + * @txrx_vdev: the virtual device's data object + * @osif_vdev: the virtual device's OS shim object + * @txrx_ops: (pointers to)functions used for tx and rx data xfer + * + * The data object for a virtual device is created by the + * function ol_txrx_vdev_attach. However, rather than fully + * linking the data vdev object with the vdev objects from the + * other subsystems that the data vdev object interacts with, + * the txrx_vdev_attach function focuses primarily on creating + * the data vdev object. After the creation of both the data + * vdev object and the OS shim vdev object, this + * txrx_osif_vdev_attach function is used to connect the two + * vdev objects, so the data SW can use the OS shim vdev handle + * when passing rx data received by a vdev up to the OS shim. + */ +void ol_txrx_vdev_register(ol_txrx_vdev_handle vdev, + void *osif_vdev, + struct ol_txrx_ops *txrx_ops) +{ + if (qdf_unlikely(!vdev) || qdf_unlikely(!txrx_ops)) { + qdf_print("%s: vdev/txrx_ops is NULL!\n", __func__); + qdf_assert(0); + return; + } + + vdev->osif_dev = osif_vdev; + vdev->rx = txrx_ops->rx.rx; + txrx_ops->tx.tx = ol_tx_data; +} + +/** + * ol_txrx_set_curchan - Setup the current operating channel of + * the device + * @pdev - the data physical device object + * @chan_mhz - the channel frequency (mhz) packets on + * + * Mainly used when populating monitor mode status that requires + * the current operating channel + * + */ +void ol_txrx_set_curchan(ol_txrx_pdev_handle pdev, uint32_t chan_mhz) +{ + return; +} + +void ol_txrx_set_safemode(ol_txrx_vdev_handle vdev, uint32_t val) +{ + vdev->safemode = val; +} + +/** + * ol_txrx_set_privacy_filters - set the privacy filter + * @vdev - the data virtual device object + * @filter - filters to be set + * @num - the number of filters + * + * Rx related. Set the privacy filters. When rx packets, check + * the ether type, filter type and packet type to decide whether + * discard these packets. + */ +void +ol_txrx_set_privacy_filters(ol_txrx_vdev_handle vdev, + void *filters, uint32_t num) +{ + qdf_mem_copy(vdev->privacy_filters, filters, + num * sizeof(struct privacy_exemption)); + vdev->num_filters = num; +} + +void ol_txrx_set_drop_unenc(ol_txrx_vdev_handle vdev, uint32_t val) +{ + vdev->drop_unenc = val; +} + +#if defined(CONFIG_HL_SUPPORT) + +static void +ol_txrx_tx_desc_reset_vdev(ol_txrx_vdev_handle vdev) +{ + struct ol_txrx_pdev_t *pdev = vdev->pdev; + int i; + struct ol_tx_desc_t *tx_desc; + + qdf_spin_lock_bh(&pdev->tx_mutex); + for (i = 0; i < pdev->tx_desc.pool_size; i++) { + tx_desc = ol_tx_desc_find(pdev, i); + if (tx_desc->vdev == vdev) + tx_desc->vdev = NULL; + } + qdf_spin_unlock_bh(&pdev->tx_mutex); +} + +#else + +static void +ol_txrx_tx_desc_reset_vdev(ol_txrx_vdev_handle vdev) +{ + +} + +#endif + +/** + * ol_txrx_vdev_detach - Deallocate the specified data virtual + * device object. + * @data_vdev: data object for the virtual device in question + * @callback: function to call (if non-NULL) once the vdev has + * been wholly deleted + * @callback_context: context to provide in the callback + * + * All peers associated with the virtual device need to be deleted + * (ol_txrx_peer_detach) before the virtual device itself is deleted. + * However, for the peers to be fully deleted, the peer deletion has to + * percolate through the target data FW and back up to the host data SW. + * Thus, even though the host control SW may have issued a peer_detach + * call for each of the vdev's peers, the peer objects may still be + * allocated, pending removal of all references to them by the target FW. + * In this case, though the vdev_detach function call will still return + * immediately, the vdev itself won't actually be deleted, until the + * deletions of all its peers complete. + * The caller can provide a callback function pointer to be notified when + * the vdev deletion actually happens - whether it's directly within the + * vdev_detach call, or if it's deferred until all in-progress peer + * deletions have completed. + */ +void +ol_txrx_vdev_detach(ol_txrx_vdev_handle vdev, + ol_txrx_vdev_delete_cb callback, void *context) +{ + struct ol_txrx_pdev_t *pdev = vdev->pdev; + + /* preconditions */ + TXRX_ASSERT2(vdev); + + ol_txrx_vdev_tx_queue_free(vdev); + + qdf_spin_lock_bh(&vdev->ll_pause.mutex); + qdf_timer_stop(&vdev->ll_pause.timer); + qdf_timer_free(&vdev->ll_pause.timer); + vdev->ll_pause.is_q_timer_on = false; + while (vdev->ll_pause.txq.head) { + qdf_nbuf_t next = qdf_nbuf_next(vdev->ll_pause.txq.head); + qdf_nbuf_set_next(vdev->ll_pause.txq.head, NULL); + qdf_nbuf_unmap(pdev->osdev, vdev->ll_pause.txq.head, + QDF_DMA_TO_DEVICE); + qdf_nbuf_tx_free(vdev->ll_pause.txq.head, QDF_NBUF_PKT_ERROR); + vdev->ll_pause.txq.head = next; + } + qdf_spin_unlock_bh(&vdev->ll_pause.mutex); + qdf_spinlock_destroy(&vdev->ll_pause.mutex); + + qdf_spin_lock_bh(&vdev->flow_control_lock); + vdev->osif_flow_control_cb = NULL; + vdev->osif_fc_ctx = NULL; + qdf_spin_unlock_bh(&vdev->flow_control_lock); + qdf_spinlock_destroy(&vdev->flow_control_lock); + + /* remove the vdev from its parent pdev's list */ + TAILQ_REMOVE(&pdev->vdev_list, vdev, vdev_list_elem); + + /* + * Use peer_ref_mutex while accessing peer_list, in case + * a peer is in the process of being removed from the list. + */ + qdf_spin_lock_bh(&pdev->peer_ref_mutex); + /* check that the vdev has no peers allocated */ + if (!TAILQ_EMPTY(&vdev->peer_list)) { + /* debug print - will be removed later */ + TXRX_PRINT(TXRX_PRINT_LEVEL_INFO1, + "%s: not deleting vdev object %p (%02x:%02x:%02x:%02x:%02x:%02x) until deletion finishes for all its peers\n", + __func__, vdev, + vdev->mac_addr.raw[0], vdev->mac_addr.raw[1], + vdev->mac_addr.raw[2], vdev->mac_addr.raw[3], + vdev->mac_addr.raw[4], vdev->mac_addr.raw[5]); + /* indicate that the vdev needs to be deleted */ + vdev->delete.pending = 1; + vdev->delete.callback = callback; + vdev->delete.context = context; + qdf_spin_unlock_bh(&pdev->peer_ref_mutex); + return; + } + qdf_spin_unlock_bh(&pdev->peer_ref_mutex); + qdf_event_destroy(&vdev->wait_delete_comp); + + TXRX_PRINT(TXRX_PRINT_LEVEL_INFO1, + "%s: deleting vdev obj %p (%02x:%02x:%02x:%02x:%02x:%02x)\n", + __func__, vdev, + vdev->mac_addr.raw[0], vdev->mac_addr.raw[1], + vdev->mac_addr.raw[2], vdev->mac_addr.raw[3], + vdev->mac_addr.raw[4], vdev->mac_addr.raw[5]); + + htt_vdev_detach(pdev->htt_pdev, vdev->vdev_id); + + /* + * The ol_tx_desc_free might access the invalid content of vdev referred + * by tx desc, since this vdev might be detached in another thread + * asynchronous. + * + * Go through tx desc pool to set corresponding tx desc's vdev to NULL + * when detach this vdev, and add vdev checking in the ol_tx_desc_free + * to avoid crash. + * + */ + ol_txrx_tx_desc_reset_vdev(vdev); + + /* + * Doesn't matter if there are outstanding tx frames - + * they will be freed once the target sends a tx completion + * message for them. + */ + qdf_mem_free(vdev); + if (callback) + callback(context); +} + +/** + * ol_txrx_flush_rx_frames() - flush cached rx frames + * @peer: peer + * @drop: set flag to drop frames + * + * Return: None + */ +void ol_txrx_flush_rx_frames(struct ol_txrx_peer_t *peer, + bool drop) +{ + struct ol_txrx_cached_bufq_t *bufqi; + struct ol_rx_cached_buf *cache_buf; + QDF_STATUS ret; + ol_txrx_rx_fp data_rx = NULL; + + if (qdf_atomic_inc_return(&peer->flush_in_progress) > 1) { + qdf_atomic_dec(&peer->flush_in_progress); + return; + } + + qdf_assert(peer->vdev); + qdf_spin_lock_bh(&peer->peer_info_lock); + bufqi = &peer->bufq_info; + + if (peer->state >= OL_TXRX_PEER_STATE_CONN && peer->vdev->rx) + data_rx = peer->vdev->rx; + else + drop = true; + qdf_spin_unlock_bh(&peer->peer_info_lock); + + qdf_spin_lock_bh(&bufqi->bufq_lock); + cache_buf = list_entry((&bufqi->cached_bufq)->next, + typeof(*cache_buf), list); + while (!list_empty(&bufqi->cached_bufq)) { + list_del(&cache_buf->list); + bufqi->curr--; + qdf_assert(bufqi->curr >= 0); + qdf_spin_unlock_bh(&bufqi->bufq_lock); + if (drop) { + qdf_nbuf_free(cache_buf->buf); + } else { + /* Flush the cached frames to HDD */ + ret = data_rx(peer->vdev->osif_dev, cache_buf->buf); + if (ret != QDF_STATUS_SUCCESS) + qdf_nbuf_free(cache_buf->buf); + } + qdf_mem_free(cache_buf); + qdf_spin_lock_bh(&bufqi->bufq_lock); + cache_buf = list_entry((&bufqi->cached_bufq)->next, + typeof(*cache_buf), list); + } + bufqi->qdepth_no_thresh = bufqi->curr; + qdf_spin_unlock_bh(&bufqi->bufq_lock); + qdf_atomic_dec(&peer->flush_in_progress); +} + +void ol_txrx_flush_cache_rx_queue(void) +{ + uint8_t sta_id; + struct ol_txrx_peer_t *peer; + struct ol_txrx_pdev_t *pdev; + + pdev = cds_get_context(QDF_MODULE_ID_TXRX); + if (!pdev) + return; + + for (sta_id = 0; sta_id < WLAN_MAX_STA_COUNT; sta_id++) { + peer = ol_txrx_peer_find_by_local_id(pdev, sta_id); + if (!peer) + continue; + ol_txrx_flush_rx_frames(peer, 1); + } +} + + +/** + * ol_txrx_peer_attach - Allocate and set up references for a + * data peer object. + * @data_pdev: data physical device object that will indirectly + * own the data_peer object + * @data_vdev - data virtual device object that will directly + * own the data_peer object + * @peer_mac_addr - MAC address of the new peer + * + * When an association with a peer starts, the host's control SW + * uses this function to inform the host data SW. + * The host data SW allocates its own peer object, and stores a + * reference to the control peer object within the data peer object. + * The host data SW also stores a reference to the virtual device + * that the peer is associated with. This virtual device handle is + * used when the data SW delivers rx data frames to the OS shim layer. + * The host data SW returns a handle to the new peer data object, + * so a reference within the control peer object can be set to the + * data peer object. + * + * Return: handle to new data peer object, or NULL if the attach + * fails + */ +ol_txrx_peer_handle +ol_txrx_peer_attach(ol_txrx_vdev_handle vdev, uint8_t *peer_mac_addr) +{ + struct ol_txrx_peer_t *peer; + struct ol_txrx_peer_t *temp_peer; + uint8_t i; + bool wait_on_deletion = false; + unsigned long rc; + struct ol_txrx_pdev_t *pdev; + bool cmp_wait_mac = false; + uint8_t zero_mac_addr[QDF_MAC_ADDR_SIZE] = { 0, 0, 0, 0, 0, 0 }; + + /* preconditions */ + TXRX_ASSERT2(vdev); + TXRX_ASSERT2(peer_mac_addr); + + pdev = vdev->pdev; + TXRX_ASSERT2(pdev); + + if (qdf_mem_cmp(&zero_mac_addr, &vdev->last_peer_mac_addr, + QDF_MAC_ADDR_SIZE)) + cmp_wait_mac = true; + + qdf_spin_lock_bh(&pdev->peer_ref_mutex); + /* check for duplicate exsisting peer */ + TAILQ_FOREACH(temp_peer, &vdev->peer_list, peer_list_elem) { + if (!ol_txrx_peer_find_mac_addr_cmp(&temp_peer->mac_addr, + (union ol_txrx_align_mac_addr_t *)peer_mac_addr)) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "vdev_id %d (%02x:%02x:%02x:%02x:%02x:%02x) already exsist.\n", + vdev->vdev_id, + peer_mac_addr[0], peer_mac_addr[1], + peer_mac_addr[2], peer_mac_addr[3], + peer_mac_addr[4], peer_mac_addr[5]); + if (qdf_atomic_read(&temp_peer->delete_in_progress)) { + vdev->wait_on_peer_id = temp_peer->local_id; + qdf_event_reset(&vdev->wait_delete_comp); + wait_on_deletion = true; + break; + } else { + qdf_spin_unlock_bh(&pdev->peer_ref_mutex); + return NULL; + } + } + if (cmp_wait_mac && !ol_txrx_peer_find_mac_addr_cmp( + &temp_peer->mac_addr, + &vdev->last_peer_mac_addr)) { + TXRX_PRINT(TXRX_PRINT_LEVEL_INFO1, + "vdev_id %d (%02x:%02x:%02x:%02x:%02x:%02x) old peer exsist.\n", + vdev->vdev_id, + vdev->last_peer_mac_addr.raw[0], + vdev->last_peer_mac_addr.raw[1], + vdev->last_peer_mac_addr.raw[2], + vdev->last_peer_mac_addr.raw[3], + vdev->last_peer_mac_addr.raw[4], + vdev->last_peer_mac_addr.raw[5]); + if (qdf_atomic_read(&temp_peer->delete_in_progress)) { + vdev->wait_on_peer_id = temp_peer->local_id; + qdf_event_reset(&vdev->wait_delete_comp); + wait_on_deletion = true; + break; + } else { + qdf_spin_unlock_bh(&pdev->peer_ref_mutex); + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "peer not found"); + return NULL; + } + } + } + qdf_spin_unlock_bh(&pdev->peer_ref_mutex); + + qdf_mem_zero(&vdev->last_peer_mac_addr, + sizeof(union ol_txrx_align_mac_addr_t)); + if (wait_on_deletion) { + /* wait for peer deletion */ + rc = qdf_wait_single_event(&vdev->wait_delete_comp, + PEER_DELETION_TIMEOUT); + if (QDF_STATUS_SUCCESS != rc) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "error waiting for peer(%d) deletion, status %d\n", + vdev->wait_on_peer_id, (int) rc); + /* Added for debugging only */ + wma_peer_debug_dump(); + if (cds_is_self_recovery_enabled()) + cds_trigger_recovery(false); + else + QDF_ASSERT(0); + vdev->wait_on_peer_id = OL_TXRX_INVALID_LOCAL_PEER_ID; + return NULL; + } + } + + peer = qdf_mem_malloc(sizeof(*peer)); + if (!peer) + return NULL; /* failure */ + + /* store provided params */ + peer->vdev = vdev; + qdf_mem_copy(&peer->mac_addr.raw[0], peer_mac_addr, + OL_TXRX_MAC_ADDR_LEN); + + ol_txrx_peer_txqs_init(pdev, peer); + + INIT_LIST_HEAD(&peer->bufq_info.cached_bufq); + qdf_spin_lock_bh(&pdev->peer_ref_mutex); + /* add this peer into the vdev's list */ + TAILQ_INSERT_TAIL(&vdev->peer_list, peer, peer_list_elem); + qdf_spin_unlock_bh(&pdev->peer_ref_mutex); + /* check whether this is a real peer (peer mac addr != vdev mac addr) */ + if (ol_txrx_peer_find_mac_addr_cmp(&vdev->mac_addr, &peer->mac_addr)) + vdev->last_real_peer = peer; + + peer->rx_opt_proc = pdev->rx_opt_proc; + + ol_rx_peer_init(pdev, peer); + + /* initialize the peer_id */ + for (i = 0; i < MAX_NUM_PEER_ID_PER_PEER; i++) + peer->peer_ids[i] = HTT_INVALID_PEER; + + qdf_spinlock_create(&peer->peer_info_lock); + qdf_spinlock_create(&peer->bufq_info.bufq_lock); + + peer->bufq_info.thresh = OL_TXRX_CACHED_BUFQ_THRESH; + + qdf_atomic_init(&peer->delete_in_progress); + qdf_atomic_init(&peer->flush_in_progress); + + qdf_atomic_init(&peer->ref_cnt); + + /* keep one reference for attach */ + OL_TXRX_PEER_INC_REF_CNT(peer); + + /* + * Set a flag to indicate peer create is pending in firmware and + * increment ref_cnt so that peer will not get deleted while + * peer create command is pending in firmware. + * First peer_map event from firmware signifies successful + * peer creation and it will be decremented in peer_map handling. + */ + qdf_atomic_init(&peer->fw_create_pending); + qdf_atomic_set(&peer->fw_create_pending, 1); + OL_TXRX_PEER_INC_REF_CNT(peer); + + peer->valid = 1; + qdf_timer_init(pdev->osdev, &peer->peer_unmap_timer, + peer_unmap_timer_handler, peer, QDF_TIMER_TYPE_SW); + + ol_txrx_peer_find_hash_add(pdev, peer); + + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_HIGH, + "vdev %p created peer %p ref_cnt %d (%02x:%02x:%02x:%02x:%02x:%02x)\n", + vdev, peer, qdf_atomic_read(&peer->ref_cnt), + peer->mac_addr.raw[0], peer->mac_addr.raw[1], + peer->mac_addr.raw[2], peer->mac_addr.raw[3], + peer->mac_addr.raw[4], peer->mac_addr.raw[5]); + /* + * For every peer MAp message search and set if bss_peer + */ + if (qdf_mem_cmp(peer->mac_addr.raw, vdev->mac_addr.raw, + OL_TXRX_MAC_ADDR_LEN)) + peer->bss_peer = 1; + + /* + * The peer starts in the "disc" state while association is in progress. + * Once association completes, the peer will get updated to "auth" state + * by a call to ol_txrx_peer_state_update if the peer is in open mode, + * or else to the "conn" state. For non-open mode, the peer will + * progress to "auth" state once the authentication completes. + */ + peer->state = OL_TXRX_PEER_STATE_INVALID; + ol_txrx_peer_state_update(pdev, peer->mac_addr.raw, + OL_TXRX_PEER_STATE_DISC); + +#ifdef QCA_SUPPORT_PEER_DATA_RX_RSSI + peer->rssi_dbm = HTT_RSSI_INVALID; +#endif + if ((QDF_GLOBAL_MONITOR_MODE == cds_get_conparam()) && + !pdev->self_peer) { + pdev->self_peer = peer; + /* + * No Tx in monitor mode, otherwise results in target assert. + * Setting disable_intrabss_fwd to true + */ + ol_vdev_rx_set_intrabss_fwd(vdev, true); + } + + ol_txrx_local_peer_id_alloc(pdev, peer); + + return peer; +} + +/* + * Discarding tx filter - removes all data frames (disconnected state) + */ +static A_STATUS ol_tx_filter_discard(struct ol_txrx_msdu_info_t *tx_msdu_info) +{ + return A_ERROR; +} + +/* + * Non-autentication tx filter - filters out data frames that are not + * related to authentication, but allows EAPOL (PAE) or WAPI (WAI) + * data frames (connected state) + */ +static A_STATUS ol_tx_filter_non_auth(struct ol_txrx_msdu_info_t *tx_msdu_info) +{ + return + (tx_msdu_info->htt.info.ethertype == ETHERTYPE_PAE || + tx_msdu_info->htt.info.ethertype == + ETHERTYPE_WAI) ? A_OK : A_ERROR; +} + +/* + * Pass-through tx filter - lets all data frames through (authenticated state) + */ +static A_STATUS ol_tx_filter_pass_thru(struct ol_txrx_msdu_info_t *tx_msdu_info) +{ + return A_OK; +} + +/** + * ol_txrx_peer_get_peer_mac_addr() - return mac_addr from peer handle. + * @peer: handle to peer + * + * returns mac addrs for module which do not know peer type + * + * Return: the mac_addr from peer + */ +uint8_t * +ol_txrx_peer_get_peer_mac_addr(ol_txrx_peer_handle peer) +{ + if (!peer) + return NULL; + + return peer->mac_addr.raw; +} + +/** + * ol_txrx_get_pn_info() - Returns pn info from peer + * @peer: handle to peer + * @last_pn_valid: return last_rmf_pn_valid value from peer. + * @last_pn: return last_rmf_pn value from peer. + * @rmf_pn_replays: return rmf_pn_replays value from peer. + * + * Return: NONE + */ +void +ol_txrx_get_pn_info(ol_txrx_peer_handle peer, uint8_t **last_pn_valid, + uint64_t **last_pn, uint32_t **rmf_pn_replays) +{ + *last_pn_valid = &peer->last_rmf_pn_valid; + *last_pn = &peer->last_rmf_pn; + *rmf_pn_replays = &peer->rmf_pn_replays; +} + +/** + * ol_txrx_get_opmode() - Return operation mode of vdev + * @vdev: vdev handle + * + * Return: operation mode. + */ +int ol_txrx_get_opmode(ol_txrx_vdev_handle vdev) +{ + return vdev->opmode; +} + +/** + * ol_txrx_get_peer_state() - Return peer state of peer + * @peer: peer handle + * + * Return: return peer state + */ +int ol_txrx_get_peer_state(ol_txrx_peer_handle peer) +{ + return peer->state; +} + +/** + * ol_txrx_get_vdev_for_peer() - Return vdev from peer handle + * @peer: peer handle + * + * Return: vdev handle from peer + */ +ol_txrx_vdev_handle +ol_txrx_get_vdev_for_peer(ol_txrx_peer_handle peer) +{ + return peer->vdev; +} + +/** + * ol_txrx_get_vdev_mac_addr() - Return mac addr of vdev + * @vdev: vdev handle + * + * Return: vdev mac address + */ +uint8_t * +ol_txrx_get_vdev_mac_addr(ol_txrx_vdev_handle vdev) +{ + if (!vdev) + return NULL; + + return vdev->mac_addr.raw; +} + +/** + * ol_txrx_get_vdev_struct_mac_addr() - Return handle to struct qdf_mac_addr of + * vdev + * @vdev: vdev handle + * + * Return: Handle to struct qdf_mac_addr + */ +struct qdf_mac_addr * +ol_txrx_get_vdev_struct_mac_addr(ol_txrx_vdev_handle vdev) +{ + return (struct qdf_mac_addr *)&(vdev->mac_addr); +} + +/** + * ol_txrx_get_pdev_from_vdev() - Return handle to pdev of vdev + * @vdev: vdev handle + * + * Return: Handle to pdev + */ +ol_txrx_pdev_handle ol_txrx_get_pdev_from_vdev(ol_txrx_vdev_handle vdev) +{ + return vdev->pdev; +} + +/** + * ol_txrx_get_ctrl_pdev_from_vdev() - Return control pdev of vdev + * @vdev: vdev handle + * + * Return: Handle to control pdev + */ +ol_pdev_handle +ol_txrx_get_ctrl_pdev_from_vdev(ol_txrx_vdev_handle vdev) +{ + return vdev->pdev->ctrl_pdev; +} + +/** + * ol_txrx_is_rx_fwd_disabled() - returns the rx_fwd_disabled status on vdev + * @vdev: vdev handle + * + * Return: Rx Fwd disabled status + */ +uint8_t +ol_txrx_is_rx_fwd_disabled(ol_txrx_vdev_handle vdev) +{ + struct txrx_pdev_cfg_t *cfg = (struct txrx_pdev_cfg_t *) + vdev->pdev->ctrl_pdev; + return cfg->rx_fwd_disabled; +} + +#ifdef QCA_IBSS_SUPPORT +/** + * ol_txrx_update_ibss_add_peer_num_of_vdev() - update and return peer num + * @vdev: vdev handle + * @peer_num_delta: peer nums to be adjusted + * + * Return: -1 for failure or total peer nums after adjustment. + */ +int16_t +ol_txrx_update_ibss_add_peer_num_of_vdev(ol_txrx_vdev_handle vdev, + int16_t peer_num_delta) +{ + int16_t new_peer_num; + + new_peer_num = vdev->ibss_peer_num + peer_num_delta; + if (new_peer_num > MAX_PEERS || new_peer_num < 0) + return OL_TXRX_INVALID_NUM_PEERS; + + vdev->ibss_peer_num = new_peer_num; + + return new_peer_num; +} + +/** + * ol_txrx_set_ibss_vdev_heart_beat_timer() - Update ibss vdev heart + * beat timer + * @vdev: vdev handle + * @timer_value_sec: new heart beat timer value + * + * Return: Old timer value set in vdev. + */ +uint16_t ol_txrx_set_ibss_vdev_heart_beat_timer(ol_txrx_vdev_handle vdev, + uint16_t timer_value_sec) +{ + uint16_t old_timer_value = vdev->ibss_peer_heart_beat_timer; + + vdev->ibss_peer_heart_beat_timer = timer_value_sec; + + return old_timer_value; +} +#endif + +/** + * ol_txrx_remove_peers_for_vdev() - remove all vdev peers with lock held + * @vdev: vdev handle + * @callback: callback function to remove the peer. + * @callback_context: handle for callback function + * @remove_last_peer: Does it required to last peer. + * + * Return: NONE + */ +void +ol_txrx_remove_peers_for_vdev(ol_txrx_vdev_handle vdev, + ol_txrx_vdev_peer_remove_cb callback, + void *callback_context, bool remove_last_peer) +{ + ol_txrx_peer_handle peer, temp; + /* remove all remote peers for vdev */ + qdf_spin_lock_bh(&vdev->pdev->peer_ref_mutex); + + temp = NULL; + TAILQ_FOREACH_REVERSE(peer, &vdev->peer_list, peer_list_t, + peer_list_elem) { + if (temp) { + qdf_spin_unlock_bh(&vdev->pdev->peer_ref_mutex); + if (qdf_atomic_read(&temp->delete_in_progress) == 0) { + callback(callback_context, temp->mac_addr.raw, + vdev->vdev_id, temp, false); + } + qdf_spin_lock_bh(&vdev->pdev->peer_ref_mutex); + } + /* self peer is deleted last */ + if (peer == TAILQ_FIRST(&vdev->peer_list)) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "%s: self peer removed by caller ", + __func__); + break; + } else + temp = peer; + } + + qdf_spin_unlock_bh(&vdev->pdev->peer_ref_mutex); + + if (remove_last_peer) { + /* remove IBSS bss peer last */ + peer = TAILQ_FIRST(&vdev->peer_list); + callback(callback_context, (uint8_t *) &vdev->mac_addr, + vdev->vdev_id, peer, false); + } +} + +/** + * ol_txrx_remove_peers_for_vdev_no_lock() - remove vdev peers with no lock. + * @vdev: vdev handle + * @callback: callback function to remove the peer. + * @callback_context: handle for callback function + * + * Return: NONE + */ +void +ol_txrx_remove_peers_for_vdev_no_lock(ol_txrx_vdev_handle vdev, + ol_txrx_vdev_peer_remove_cb callback, + void *callback_context) +{ + ol_txrx_peer_handle peer = NULL; + + TAILQ_FOREACH(peer, &vdev->peer_list, peer_list_elem) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "%s: peer found for vdev id %d. deleting the peer", + __func__, vdev->vdev_id); + callback(callback_context, (uint8_t *)&vdev->mac_addr, + vdev->vdev_id, peer, false); + } +} + +/** + * ol_txrx_set_ocb_chan_info() - set OCB channel info to vdev. + * @vdev: vdev handle + * @ocb_set_chan: OCB channel information to be set in vdev. + * + * Return: NONE + */ +void ol_txrx_set_ocb_chan_info(ol_txrx_vdev_handle vdev, + struct ol_txrx_ocb_set_chan ocb_set_chan) +{ + vdev->ocb_channel_info = ocb_set_chan.ocb_channel_info; + vdev->ocb_channel_count = ocb_set_chan.ocb_channel_count; +} + +/** + * ol_txrx_get_ocb_chan_info() - return handle to vdev ocb_channel_info + * @vdev: vdev handle + * + * Return: handle to struct ol_txrx_ocb_chan_info + */ +struct ol_txrx_ocb_chan_info * +ol_txrx_get_ocb_chan_info(ol_txrx_vdev_handle vdev) +{ + return vdev->ocb_channel_info; +} + +/** + * @brief specify the peer's authentication state + * @details + * Specify the peer's authentication state (none, connected, authenticated) + * to allow the data SW to determine whether to filter out invalid data frames. + * (In the "connected" state, where security is enabled, but authentication + * has not completed, tx and rx data frames other than EAPOL or WAPI should + * be discarded.) + * This function is only relevant for systems in which the tx and rx filtering + * are done in the host rather than in the target. + * + * @param data_peer - which peer has changed its state + * @param state - the new state of the peer + * + * Return: QDF Status + */ +QDF_STATUS ol_txrx_peer_state_update(struct ol_txrx_pdev_t *pdev, + uint8_t *peer_mac, + enum ol_txrx_peer_state state) +{ + struct ol_txrx_peer_t *peer; + int peer_ref_cnt; + + if (qdf_unlikely(!pdev)) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, "Pdev is NULL"); + qdf_assert(0); + return QDF_STATUS_E_INVAL; + } + + peer = ol_txrx_peer_find_hash_find_inc_ref(pdev, peer_mac, 0, 1); + if (NULL == peer) { + TXRX_PRINT(TXRX_PRINT_LEVEL_INFO2, + "%s: peer is null for peer_mac 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", + __func__, + peer_mac[0], peer_mac[1], peer_mac[2], peer_mac[3], + peer_mac[4], peer_mac[5]); + return QDF_STATUS_E_INVAL; + } + + /* TODO: Should we send WMI command of the connection state? */ + /* avoid multiple auth state change. */ + if (peer->state == state) { +#ifdef TXRX_PRINT_VERBOSE_ENABLE + TXRX_PRINT(TXRX_PRINT_LEVEL_INFO3, + "%s: no state change, returns directly\n", + __func__); +#endif + peer_ref_cnt = OL_TXRX_PEER_UNREF_DELETE(peer); + return QDF_STATUS_SUCCESS; + } + + TXRX_PRINT(TXRX_PRINT_LEVEL_INFO2, "%s: change from %d to %d\n", + __func__, peer->state, state); + + peer->tx_filter = (state == OL_TXRX_PEER_STATE_AUTH) + ? ol_tx_filter_pass_thru + : ((state == OL_TXRX_PEER_STATE_CONN) + ? ol_tx_filter_non_auth + : ol_tx_filter_discard); + + if (peer->vdev->pdev->cfg.host_addba) { + if (state == OL_TXRX_PEER_STATE_AUTH) { + int tid; + /* + * Pause all regular (non-extended) TID tx queues until + * data arrives and ADDBA negotiation has completed. + */ + TXRX_PRINT(TXRX_PRINT_LEVEL_INFO2, + "%s: pause peer and unpause mgmt/non-qos\n", + __func__); + ol_txrx_peer_pause(peer); /* pause all tx queues */ + /* unpause mgmt and non-QoS tx queues */ + for (tid = OL_TX_NUM_QOS_TIDS; + tid < OL_TX_NUM_TIDS; tid++) + ol_txrx_peer_tid_unpause(peer, tid); + } + } + peer_ref_cnt = OL_TXRX_PEER_UNREF_DELETE(peer); + /* + * after OL_TXRX_PEER_UNREF_DELETE, peer object cannot be accessed + * if the return code was 0 + */ + if (peer_ref_cnt > 0) + /* + * Set the state after the Pause to avoid the race condiction + * with ADDBA check in tx path + */ + peer->state = state; + return QDF_STATUS_SUCCESS; +} + +void +ol_txrx_peer_keyinstalled_state_update(struct ol_txrx_peer_t *peer, uint8_t val) +{ + peer->keyinstalled = val; +} + +void +ol_txrx_peer_update(ol_txrx_vdev_handle vdev, + uint8_t *peer_mac, + union ol_txrx_peer_update_param_t *param, + enum ol_txrx_peer_update_select_t select) +{ + struct ol_txrx_peer_t *peer; + int peer_ref_cnt; + + peer = ol_txrx_peer_find_hash_find_inc_ref(vdev->pdev, peer_mac, 0, 1); + if (!peer) { + TXRX_PRINT(TXRX_PRINT_LEVEL_INFO2, "%s: peer is null", + __func__); + return; + } + + switch (select) { + case ol_txrx_peer_update_qos_capable: + { + /* save qos_capable here txrx peer, + * when HTT_ISOC_T2H_MSG_TYPE_PEER_INFO comes then save. + */ + peer->qos_capable = param->qos_capable; + /* + * The following function call assumes that the peer has a + * single ID. This is currently true, and + * is expected to remain true. + */ + htt_peer_qos_update(peer->vdev->pdev->htt_pdev, + peer->peer_ids[0], + peer->qos_capable); + break; + } + case ol_txrx_peer_update_uapsdMask: + { + peer->uapsd_mask = param->uapsd_mask; + htt_peer_uapsdmask_update(peer->vdev->pdev->htt_pdev, + peer->peer_ids[0], + peer->uapsd_mask); + break; + } + case ol_txrx_peer_update_peer_security: + { + enum ol_sec_type sec_type = param->sec_type; + enum htt_sec_type peer_sec_type = htt_sec_type_none; + + switch (sec_type) { + case ol_sec_type_none: + peer_sec_type = htt_sec_type_none; + break; + case ol_sec_type_wep128: + peer_sec_type = htt_sec_type_wep128; + break; + case ol_sec_type_wep104: + peer_sec_type = htt_sec_type_wep104; + break; + case ol_sec_type_wep40: + peer_sec_type = htt_sec_type_wep40; + break; + case ol_sec_type_tkip: + peer_sec_type = htt_sec_type_tkip; + break; + case ol_sec_type_tkip_nomic: + peer_sec_type = htt_sec_type_tkip_nomic; + break; + case ol_sec_type_aes_ccmp: + peer_sec_type = htt_sec_type_aes_ccmp; + break; + case ol_sec_type_wapi: + peer_sec_type = htt_sec_type_wapi; + break; + default: + peer_sec_type = htt_sec_type_none; + break; + } + + peer->security[txrx_sec_ucast].sec_type = + peer->security[txrx_sec_mcast].sec_type = + peer_sec_type; + + break; + } + default: + { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "ERROR: unknown param %d in %s", select, + __func__); + break; + } + } /* switch */ + peer_ref_cnt = OL_TXRX_PEER_UNREF_DELETE(peer); +} + +uint8_t +ol_txrx_peer_uapsdmask_get(struct ol_txrx_pdev_t *txrx_pdev, uint16_t peer_id) +{ + + struct ol_txrx_peer_t *peer; + peer = ol_txrx_peer_find_by_id(txrx_pdev, peer_id); + if (peer) + return peer->uapsd_mask; + return 0; +} + +uint8_t +ol_txrx_peer_qoscapable_get(struct ol_txrx_pdev_t *txrx_pdev, uint16_t peer_id) +{ + + struct ol_txrx_peer_t *peer_t = + ol_txrx_peer_find_by_id(txrx_pdev, peer_id); + if (peer_t != NULL) + return peer_t->qos_capable; + return 0; +} + +int ol_txrx_peer_unref_delete(ol_txrx_peer_handle peer, + const char *fname, + int line) +{ + int rc; + struct ol_txrx_vdev_t *vdev; + struct ol_txrx_pdev_t *pdev; + int i; + + /* preconditions */ + TXRX_ASSERT2(peer); + + vdev = peer->vdev; + if (NULL == vdev) { + TXRX_PRINT(TXRX_PRINT_LEVEL_INFO1, + "The vdev is not present anymore\n"); + return -EINVAL; + } + + pdev = vdev->pdev; + if (NULL == pdev) { + TXRX_PRINT(TXRX_PRINT_LEVEL_INFO1, + "The pdev is not present anymore\n"); + return -EINVAL; + } + + wma_peer_debug_log(vdev->vdev_id, DEBUG_PEER_UNREF_DELETE, + DEBUG_INVALID_PEER_ID, &peer->mac_addr.raw, peer, 0, + qdf_atomic_read(&peer->ref_cnt)); + + /* + * Hold the lock all the way from checking if the peer ref count + * is zero until the peer references are removed from the hash + * table and vdev list (if the peer ref count is zero). + * This protects against a new HL tx operation starting to use the + * peer object just after this function concludes it's done being used. + * Furthermore, the lock needs to be held while checking whether the + * vdev's list of peers is empty, to make sure that list is not modified + * concurrently with the empty check. + */ + qdf_spin_lock_bh(&pdev->peer_ref_mutex); + + /* + * Check for the reference count before deleting the peer + * as we noticed that sometimes we are re-entering this + * function again which is leading to dead-lock. + * (A double-free should never happen, so assert if it does.) + */ + + rc = qdf_atomic_read(&(peer->ref_cnt)); + if (rc == 0) { + qdf_spin_unlock_bh(&pdev->peer_ref_mutex); + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "The Peer is not present anymore\n"); + qdf_assert(0); + return -EACCES; + } + /* + * now decrement rc; this will be the return code. + * 0 : peer deleted + * >0: peer ref removed, but still has other references + * <0: sanity failed - no changes to the state of the peer + */ + rc--; + + if (qdf_atomic_dec_and_test(&peer->ref_cnt)) { + u_int16_t peer_id; + + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO, + "[%s][%d]: Deleting peer %p (%pM) ref_cnt %d\n", + fname, line, peer, peer->mac_addr.raw, + qdf_atomic_read(&peer->ref_cnt)); + + wma_peer_debug_log(vdev->vdev_id, DEBUG_DELETING_PEER_OBJ, + DEBUG_INVALID_PEER_ID, + &peer->mac_addr.raw, peer, 0, + qdf_atomic_read(&peer->ref_cnt)); + + peer_id = peer->local_id; + /* remove the reference to the peer from the hash table */ + ol_txrx_peer_find_hash_remove(pdev, peer); + + /* remove the peer from its parent vdev's list */ + TAILQ_REMOVE(&peer->vdev->peer_list, peer, peer_list_elem); + + /* cleanup the Rx reorder queues for this peer */ + ol_rx_peer_cleanup(vdev, peer); + + /* peer is removed from peer_list */ + qdf_atomic_set(&peer->delete_in_progress, 0); + + /* + * Set wait_delete_comp event if the current peer id matches + * with registered peer id. + */ + if (peer_id == vdev->wait_on_peer_id) { + qdf_event_set(&vdev->wait_delete_comp); + vdev->wait_on_peer_id = OL_TXRX_INVALID_LOCAL_PEER_ID; + } + + qdf_timer_sync_cancel(&peer->peer_unmap_timer); + qdf_timer_free(&peer->peer_unmap_timer); + + /* check whether the parent vdev has no peers left */ + if (TAILQ_EMPTY(&vdev->peer_list)) { + /* + * Check if the parent vdev was waiting for its peers + * to be deleted, in order for it to be deleted too. + */ + if (vdev->delete.pending) { + ol_txrx_vdev_delete_cb vdev_delete_cb = + vdev->delete.callback; + void *vdev_delete_context = + vdev->delete.context; + /* + * Now that there are no references to the peer, + * we can release the peer reference lock. + */ + qdf_spin_unlock_bh(&pdev->peer_ref_mutex); + + /* + * The ol_tx_desc_free might access the invalid content of vdev + * referred by tx desc, since this vdev might be detached in + * another thread asynchronous. + * + * Go through tx desc pool to set corresponding tx desc's vdev + * to NULL when detach this vdev, and add vdev checking in the + * ol_tx_desc_free to avoid crash. + * + */ + ol_txrx_tx_desc_reset_vdev(vdev); + TXRX_PRINT(TXRX_PRINT_LEVEL_INFO1, + "%s: deleting vdev object %p " + "(%02x:%02x:%02x:%02x:%02x:%02x)" + " - its last peer is done", + __func__, vdev, + vdev->mac_addr.raw[0], + vdev->mac_addr.raw[1], + vdev->mac_addr.raw[2], + vdev->mac_addr.raw[3], + vdev->mac_addr.raw[4], + vdev->mac_addr.raw[5]); + /* all peers are gone, go ahead and delete it */ + qdf_mem_free(vdev); + if (vdev_delete_cb) + vdev_delete_cb(vdev_delete_context); + } else { + qdf_spin_unlock_bh(&pdev->peer_ref_mutex); + } + } else { + qdf_spin_unlock_bh(&pdev->peer_ref_mutex); + } + + ol_txrx_peer_tx_queue_free(pdev, peer); + + /* Remove mappings from peer_id to peer object */ + ol_txrx_peer_clear_map_peer(pdev, peer); + + /* + * 'array' is allocated in addba handler and is supposed to be + * freed in delba handler. There is the case (for example, in + * SSR) where delba handler is not called. Because array points + * to address of 'base' by default and is reallocated in addba + * handler later, only free the memory when the array does not + * point to base. + */ + for (i = 0; i < OL_TXRX_NUM_EXT_TIDS; i++) { + if (peer->tids_rx_reorder[i].array != + &peer->tids_rx_reorder[i].base) { + TXRX_PRINT(TXRX_PRINT_LEVEL_INFO1, + "%s, delete reorder arr, tid:%d\n", + __func__, i); + qdf_mem_free(peer->tids_rx_reorder[i].array); + ol_rx_reorder_init(&peer->tids_rx_reorder[i], + (uint8_t) i); + } + } + + qdf_mem_free(peer); + } else { + qdf_spin_unlock_bh(&pdev->peer_ref_mutex); + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_HIGH, + "[%s][%d]: ref delete peer %p peer->ref_cnt = %d", + fname, line, peer, rc); + } + + return rc; +} + +/** + * ol_txrx_clear_peer_internal() - ol internal function to clear peer + * @peer: pointer to ol txrx peer structure + * + * Return: QDF Status + */ +static QDF_STATUS +ol_txrx_clear_peer_internal(struct ol_txrx_peer_t *peer) +{ + p_cds_sched_context sched_ctx = get_cds_sched_ctxt(); + /* Drop pending Rx frames in CDS */ + if (sched_ctx) + cds_drop_rxpkt_by_staid(sched_ctx, peer->local_id); + + /* Purge the cached rx frame queue */ + ol_txrx_flush_rx_frames(peer, 1); + + qdf_spin_lock_bh(&peer->peer_info_lock); + peer->state = OL_TXRX_PEER_STATE_DISC; + qdf_spin_unlock_bh(&peer->peer_info_lock); + + return QDF_STATUS_SUCCESS; +} + +/** + * ol_txrx_clear_peer() - clear peer + * @sta_id: sta id + * + * Return: QDF Status + */ +QDF_STATUS ol_txrx_clear_peer(uint8_t sta_id) +{ + struct ol_txrx_peer_t *peer; + struct ol_txrx_pdev_t *pdev = cds_get_context(QDF_MODULE_ID_TXRX); + + if (!pdev) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, "%s: Unable to find pdev!", + __func__); + return QDF_STATUS_E_FAILURE; + } + + if (sta_id >= WLAN_MAX_STA_COUNT) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, "Invalid sta id %d", sta_id); + return QDF_STATUS_E_INVAL; + } + + + peer = ol_txrx_peer_find_by_local_id(pdev, sta_id); + if (!peer) + return QDF_STATUS_E_FAULT; + + return ol_txrx_clear_peer_internal(peer); + +} + +/** + * peer_unmap_timer() - peer unmap timer function + * @data: peer object pointer + * + * Return: none + */ +void peer_unmap_timer_handler(void *data) +{ + ol_txrx_peer_handle peer = (ol_txrx_peer_handle)data; + + WMA_LOGE("%s: all unmap events not received for peer %p, ref_cnt %d", + __func__, peer, qdf_atomic_read(&peer->ref_cnt)); + WMA_LOGE("%s: peer %p (%02x:%02x:%02x:%02x:%02x:%02x)", + __func__, peer, + peer->mac_addr.raw[0], peer->mac_addr.raw[1], + peer->mac_addr.raw[2], peer->mac_addr.raw[3], + peer->mac_addr.raw[4], peer->mac_addr.raw[5]); + if (!cds_is_driver_recovering()) { + wma_peer_debug_dump(); + QDF_BUG(0); + } else { + WMA_LOGE("%s: Recovery is in progress, ignore!", __func__); + } +} + + +/** + * ol_txrx_peer_detach() - Delete a peer's data object. + * @peer - the object to detach + * + * When the host's control SW disassociates a peer, it calls + * this function to detach and delete the peer. The reference + * stored in the control peer object to the data peer + * object (set up by a call to ol_peer_store()) is provided. + * + * Return: None + */ +void ol_txrx_peer_detach(ol_txrx_peer_handle peer) +{ + struct ol_txrx_vdev_t *vdev = peer->vdev; + + /* redirect peer's rx delivery function to point to a discard func */ + peer->rx_opt_proc = ol_rx_discard; + + peer->valid = 0; + + /* flush all rx packets before clearing up the peer local_id */ + ol_txrx_clear_peer_internal(peer); + ol_txrx_local_peer_id_free(peer->vdev->pdev, peer); + + /* debug print to dump rx reorder state */ + /* htt_rx_reorder_log_print(vdev->pdev->htt_pdev); */ + + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO, + "%s:peer %p (%02x:%02x:%02x:%02x:%02x:%02x)", + __func__, peer, + peer->mac_addr.raw[0], peer->mac_addr.raw[1], + peer->mac_addr.raw[2], peer->mac_addr.raw[3], + peer->mac_addr.raw[4], peer->mac_addr.raw[5]); + + if (peer->vdev->last_real_peer == peer) + peer->vdev->last_real_peer = NULL; + + qdf_spin_lock_bh(&vdev->pdev->last_real_peer_mutex); + if (vdev->last_real_peer == peer) + vdev->last_real_peer = NULL; + qdf_spin_unlock_bh(&vdev->pdev->last_real_peer_mutex); + htt_rx_reorder_log_print(peer->vdev->pdev->htt_pdev); + + qdf_spinlock_destroy(&peer->peer_info_lock); + qdf_spinlock_destroy(&peer->bufq_info.bufq_lock); + /* + * set delete_in_progress to identify that wma + * is waiting for unmap massage for this peer + */ + qdf_atomic_set(&peer->delete_in_progress, 1); + + /* + * Create a timer to track unmap events when the sta peer gets deleted. + */ + if (vdev->opmode == wlan_op_mode_sta) { + qdf_mem_copy(&peer->vdev->last_peer_mac_addr, + &peer->mac_addr, + sizeof(union ol_txrx_align_mac_addr_t)); + qdf_timer_start(&peer->peer_unmap_timer, + OL_TXRX_PEER_UNMAP_TIMEOUT); + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "%s: started peer_unmap_timer for peer %p", + __func__, peer); + } + + /* + * Remove the reference added during peer_attach. + * The peer will still be left allocated until the + * PEER_UNMAP message arrives to remove the other + * reference, added by the PEER_MAP message. + */ + OL_TXRX_PEER_UNREF_DELETE(peer); +} + +/** + * ol_txrx_peer_detach_force_delete() - Detach and delete a peer's data object + * @peer - the object to detach + * + * Detach a peer and force peer object to be removed. It is called during + * roaming scenario when the firmware has already deleted a peer. + * Remove it from the peer_id_to_object map. Peer object is actually freed + * when last reference is deleted. + * + * Return: None + */ +void ol_txrx_peer_detach_force_delete(ol_txrx_peer_handle peer) +{ + ol_txrx_pdev_handle pdev = peer->vdev->pdev; + + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, "%s peer %p, peer->ref_cnt %d", + __func__, peer, qdf_atomic_read(&peer->ref_cnt)); + + /* Clear the peer_id_to_obj map entries */ + ol_txrx_peer_remove_obj_map_entries(pdev, peer); + ol_txrx_peer_detach(peer); +} + +ol_txrx_peer_handle +ol_txrx_peer_find_by_addr(struct ol_txrx_pdev_t *pdev, uint8_t *peer_mac_addr) +{ + struct ol_txrx_peer_t *peer; + peer = ol_txrx_peer_find_hash_find_inc_ref(pdev, peer_mac_addr, 0, 0); + if (peer) { + /* release the extra reference */ + OL_TXRX_PEER_UNREF_DELETE(peer); + } + return peer; +} + +/** + * ol_txrx_dump_tx_desc() - dump tx desc total and free count + * @txrx_pdev: Pointer to txrx pdev + * + * Return: none + */ +static void ol_txrx_dump_tx_desc(ol_txrx_pdev_handle pdev_handle) +{ + struct ol_txrx_pdev_t *pdev = (ol_txrx_pdev_handle) pdev_handle; + uint32_t total, num_free; + + if (ol_cfg_is_high_latency(pdev->ctrl_pdev)) + total = qdf_atomic_read(&pdev->orig_target_tx_credit); + else + total = ol_tx_get_desc_global_pool_size(pdev); + + num_free = ol_tx_get_total_free_desc(pdev); + + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "total tx credit %d num_free %d", + total, num_free); + + return; +} + +/** + * ol_txrx_wait_for_pending_tx() - wait for tx queue to be empty + * @timeout: timeout in ms + * + * Wait for tx queue to be empty, return timeout error if + * queue doesn't empty before timeout occurs. + * + * Return: + * QDF_STATUS_SUCCESS if the queue empties, + * QDF_STATUS_E_TIMEOUT in case of timeout, + * QDF_STATUS_E_FAULT in case of missing handle + */ +QDF_STATUS ol_txrx_wait_for_pending_tx(int timeout) +{ + ol_txrx_pdev_handle txrx_pdev = cds_get_context(QDF_MODULE_ID_TXRX); + + if (txrx_pdev == NULL) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "%s: txrx context is null", __func__); + return QDF_STATUS_E_FAULT; + } + + while (ol_txrx_get_tx_pending(txrx_pdev)) { + qdf_sleep(OL_ATH_TX_DRAIN_WAIT_DELAY); + if (timeout <= 0) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "%s: tx frames are pending", __func__); + ol_txrx_dump_tx_desc(txrx_pdev); + return QDF_STATUS_E_TIMEOUT; + } + timeout = timeout - OL_ATH_TX_DRAIN_WAIT_DELAY; + } + return QDF_STATUS_SUCCESS; +} + +#ifndef QCA_WIFI_3_0_EMU +#define SUSPEND_DRAIN_WAIT 500 +#else +#define SUSPEND_DRAIN_WAIT 3000 +#endif + +#ifdef FEATURE_RUNTIME_PM +/** + * ol_txrx_runtime_suspend() - ensure TXRX is ready to runtime suspend + * @txrx_pdev: TXRX pdev context + * + * TXRX is ready to runtime suspend if there are no pending packets + * in the tx queue. + * + * Return: QDF_STATUS + */ +QDF_STATUS ol_txrx_runtime_suspend(ol_txrx_pdev_handle txrx_pdev) +{ + if (ol_txrx_get_tx_pending(txrx_pdev)) + return QDF_STATUS_E_BUSY; + else + return QDF_STATUS_SUCCESS; +} + +/** + * ol_txrx_runtime_resume() - ensure TXRX is ready to runtime resume + * @txrx_pdev: TXRX pdev context + * + * This is a dummy function for symmetry. + * + * Return: QDF_STATUS_SUCCESS + */ +QDF_STATUS ol_txrx_runtime_resume(ol_txrx_pdev_handle txrx_pdev) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +/** + * ol_txrx_bus_suspend() - bus suspend + * + * Ensure that ol_txrx is ready for bus suspend + * + * Return: QDF_STATUS + */ +QDF_STATUS ol_txrx_bus_suspend(void) +{ + return ol_txrx_wait_for_pending_tx(SUSPEND_DRAIN_WAIT); +} + +/** + * ol_txrx_bus_resume() - bus resume + * + * Dummy function for symetry + * + * Return: QDF_STATUS_SUCCESS + */ +QDF_STATUS ol_txrx_bus_resume(void) +{ + return QDF_STATUS_SUCCESS; +} + +/** + * ol_txrx_get_tx_pending - Get the number of pending transmit + * frames that are awaiting completion. + * + * @pdev - the data physical device object + * Mainly used in clean up path to make sure all buffers have been freed + * + * Return: count of pending frames + */ +int ol_txrx_get_tx_pending(ol_txrx_pdev_handle pdev_handle) +{ + struct ol_txrx_pdev_t *pdev = (ol_txrx_pdev_handle) pdev_handle; + uint32_t total; + + if (ol_cfg_is_high_latency(pdev->ctrl_pdev)) + total = qdf_atomic_read(&pdev->orig_target_tx_credit); + else + total = ol_tx_get_desc_global_pool_size(pdev); + + return total - ol_tx_get_total_free_desc(pdev); +} + +void ol_txrx_discard_tx_pending(ol_txrx_pdev_handle pdev_handle) +{ + ol_tx_desc_list tx_descs; + /* First let hif do the qdf_atomic_dec_and_test(&tx_desc->ref_cnt) + * then let htt do the qdf_atomic_dec_and_test(&tx_desc->ref_cnt) + * which is tha same with normal data send complete path*/ + htt_tx_pending_discard(pdev_handle->htt_pdev); + + TAILQ_INIT(&tx_descs); + ol_tx_queue_discard(pdev_handle, true, &tx_descs); + /* Discard Frames in Discard List */ + ol_tx_desc_frame_list_free(pdev_handle, &tx_descs, 1 /* error */); + + ol_tx_discard_target_frms(pdev_handle); +} + +/*--- debug features --------------------------------------------------------*/ + +unsigned g_txrx_print_level = TXRX_PRINT_LEVEL_ERR; /* default */ + +void ol_txrx_print_level_set(unsigned level) +{ +#ifndef TXRX_PRINT_ENABLE + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_FATAL, + "The driver is compiled without TXRX prints enabled.\n" + "To enable them, recompile with TXRX_PRINT_ENABLE defined"); +#else + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO, + "TXRX printout level changed from %d to %d", + g_txrx_print_level, level); + g_txrx_print_level = level; +#endif +} + +struct ol_txrx_stats_req_internal { + struct ol_txrx_stats_req base; + int serviced; /* state of this request */ + int offset; +}; + +static inline +uint64_t ol_txrx_stats_ptr_to_u64(struct ol_txrx_stats_req_internal *req) +{ + return (uint64_t) ((size_t) req); +} + +static inline +struct ol_txrx_stats_req_internal *ol_txrx_u64_to_stats_ptr(uint64_t cookie) +{ + return (struct ol_txrx_stats_req_internal *)((size_t) cookie); +} + +void +ol_txrx_fw_stats_cfg(ol_txrx_vdev_handle vdev, + uint8_t cfg_stats_type, uint32_t cfg_val) +{ + uint64_t dummy_cookie = 0; + htt_h2t_dbg_stats_get(vdev->pdev->htt_pdev, 0 /* upload mask */, + 0 /* reset mask */, + cfg_stats_type, cfg_val, dummy_cookie); +} + +A_STATUS +ol_txrx_fw_stats_get(ol_txrx_vdev_handle vdev, struct ol_txrx_stats_req *req, + bool per_vdev, bool response_expected) +{ + struct ol_txrx_pdev_t *pdev = vdev->pdev; + uint64_t cookie; + struct ol_txrx_stats_req_internal *non_volatile_req; + + if (!pdev || + req->stats_type_upload_mask >= 1 << HTT_DBG_NUM_STATS || + req->stats_type_reset_mask >= 1 << HTT_DBG_NUM_STATS) { + return A_ERROR; + } + + /* + * Allocate a non-transient stats request object. + * (The one provided as an argument is likely allocated on the stack.) + */ + non_volatile_req = qdf_mem_malloc(sizeof(*non_volatile_req)); + if (!non_volatile_req) + return A_NO_MEMORY; + + /* copy the caller's specifications */ + non_volatile_req->base = *req; + non_volatile_req->serviced = 0; + non_volatile_req->offset = 0; + + /* use the non-volatile request object's address as the cookie */ + cookie = ol_txrx_stats_ptr_to_u64(non_volatile_req); + + if (htt_h2t_dbg_stats_get(pdev->htt_pdev, + req->stats_type_upload_mask, + req->stats_type_reset_mask, + HTT_H2T_STATS_REQ_CFG_STAT_TYPE_INVALID, 0, + cookie)) { + qdf_mem_free(non_volatile_req); + return A_ERROR; + } + + if (req->wait.blocking) + while (qdf_semaphore_acquire(req->wait.sem_ptr)) + ; + + if (response_expected == false) + qdf_mem_free(non_volatile_req); + + return A_OK; +} + +void +ol_txrx_fw_stats_handler(ol_txrx_pdev_handle pdev, + uint64_t cookie, uint8_t *stats_info_list) +{ + enum htt_dbg_stats_type type; + enum htt_dbg_stats_status status; + int length; + uint8_t *stats_data; + struct ol_txrx_stats_req_internal *req; + int more = 0; + + req = ol_txrx_u64_to_stats_ptr(cookie); + + do { + htt_t2h_dbg_stats_hdr_parse(stats_info_list, &type, &status, + &length, &stats_data); + if (status == HTT_DBG_STATS_STATUS_SERIES_DONE) + break; + if (status == HTT_DBG_STATS_STATUS_PRESENT || + status == HTT_DBG_STATS_STATUS_PARTIAL) { + uint8_t *buf; + int bytes = 0; + + if (status == HTT_DBG_STATS_STATUS_PARTIAL) + more = 1; + if (req->base.print.verbose || req->base.print.concise) + /* provide the header along with the data */ + htt_t2h_stats_print(stats_info_list, + req->base.print.concise); + + switch (type) { + case HTT_DBG_STATS_WAL_PDEV_TXRX: + bytes = sizeof(struct wlan_dbg_stats); + if (req->base.copy.buf) { + int lmt; + + lmt = sizeof(struct wlan_dbg_stats); + if (req->base.copy.byte_limit < lmt) + lmt = req->base.copy.byte_limit; + buf = req->base.copy.buf + req->offset; + qdf_mem_copy(buf, stats_data, lmt); + } + break; + case HTT_DBG_STATS_RX_REORDER: + bytes = sizeof(struct rx_reorder_stats); + if (req->base.copy.buf) { + int lmt; + + lmt = sizeof(struct rx_reorder_stats); + if (req->base.copy.byte_limit < lmt) + lmt = req->base.copy.byte_limit; + buf = req->base.copy.buf + req->offset; + qdf_mem_copy(buf, stats_data, lmt); + } + break; + case HTT_DBG_STATS_RX_RATE_INFO: + bytes = sizeof(wlan_dbg_rx_rate_info_t); + if (req->base.copy.buf) { + int lmt; + + lmt = sizeof(wlan_dbg_rx_rate_info_t); + if (req->base.copy.byte_limit < lmt) + lmt = req->base.copy.byte_limit; + buf = req->base.copy.buf + req->offset; + qdf_mem_copy(buf, stats_data, lmt); + } + break; + + case HTT_DBG_STATS_TX_RATE_INFO: + bytes = sizeof(wlan_dbg_tx_rate_info_t); + if (req->base.copy.buf) { + int lmt; + + lmt = sizeof(wlan_dbg_tx_rate_info_t); + if (req->base.copy.byte_limit < lmt) + lmt = req->base.copy.byte_limit; + buf = req->base.copy.buf + req->offset; + qdf_mem_copy(buf, stats_data, lmt); + } + break; + + case HTT_DBG_STATS_TX_PPDU_LOG: + bytes = 0; + /* TO DO: specify how many bytes are present */ + /* TO DO: add copying to the requestor's buf */ + + case HTT_DBG_STATS_RX_REMOTE_RING_BUFFER_INFO: + bytes = sizeof(struct rx_remote_buffer_mgmt_stats); + if (req->base.copy.buf) { + int limit; + + limit = sizeof(struct rx_remote_buffer_mgmt_stats); + if (req->base.copy.byte_limit < limit) { + limit = req->base.copy.byte_limit; + } + buf = req->base.copy.buf + req->offset; + qdf_mem_copy(buf, stats_data, limit); + } + break; + + case HTT_DBG_STATS_TXBF_INFO: + bytes = sizeof(struct wlan_dbg_txbf_data_stats); + if (req->base.copy.buf) { + int limit; + + limit = sizeof(struct wlan_dbg_txbf_data_stats); + if (req->base.copy.byte_limit < limit) + limit = req->base.copy.byte_limit; + buf = req->base.copy.buf + req->offset; + qdf_mem_copy(buf, stats_data, limit); + } + break; + + case HTT_DBG_STATS_SND_INFO: + bytes = sizeof(struct wlan_dbg_txbf_snd_stats); + if (req->base.copy.buf) { + int limit; + + limit = sizeof(struct wlan_dbg_txbf_snd_stats); + if (req->base.copy.byte_limit < limit) + limit = req->base.copy.byte_limit; + buf = req->base.copy.buf + req->offset; + qdf_mem_copy(buf, stats_data, limit); + } + break; + + case HTT_DBG_STATS_TX_SELFGEN_INFO: + bytes = sizeof(struct wlan_dbg_tx_selfgen_stats); + if (req->base.copy.buf) { + int limit; + + limit = sizeof(struct wlan_dbg_tx_selfgen_stats); + if (req->base.copy.byte_limit < limit) + limit = req->base.copy.byte_limit; + buf = req->base.copy.buf + req->offset; + qdf_mem_copy(buf, stats_data, limit); + } + break; + + case HTT_DBG_STATS_ERROR_INFO: + bytes = + sizeof(struct wlan_dbg_wifi2_error_stats); + if (req->base.copy.buf) { + int limit; + + limit = + sizeof(struct wlan_dbg_wifi2_error_stats); + if (req->base.copy.byte_limit < limit) + limit = req->base.copy.byte_limit; + buf = req->base.copy.buf + req->offset; + qdf_mem_copy(buf, stats_data, limit); + } + break; + + case HTT_DBG_STATS_TXBF_MUSU_NDPA_PKT: + bytes = + sizeof(struct rx_txbf_musu_ndpa_pkts_stats); + if (req->base.copy.buf) { + int limit; + + limit = sizeof(struct + rx_txbf_musu_ndpa_pkts_stats); + if (req->base.copy.byte_limit < limit) + limit = + req->base.copy.byte_limit; + buf = req->base.copy.buf + req->offset; + qdf_mem_copy(buf, stats_data, limit); + } + break; + + default: + break; + } + buf = req->base.copy.buf + ? req->base.copy.buf + : stats_data; + if (req->base.callback.fp) + req->base.callback.fp(req->base.callback.ctxt, + type, buf, bytes); + } + stats_info_list += length; + } while (1); + + if (!more) { + if (req->base.wait.blocking) + qdf_semaphore_release(req->base.wait.sem_ptr); + qdf_mem_free(req); + } +} + +#ifndef ATH_PERF_PWR_OFFLOAD /*---------------------------------------------*/ +int ol_txrx_debug(ol_txrx_vdev_handle vdev, int debug_specs) +{ + if (debug_specs & TXRX_DBG_MASK_OBJS) { +#if defined(TXRX_DEBUG_LEVEL) && TXRX_DEBUG_LEVEL > 5 + ol_txrx_pdev_display(vdev->pdev, 0); +#else + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_FATAL, + "The pdev,vdev,peer display functions are disabled.\n To enable them, recompile with TXRX_DEBUG_LEVEL > 5"); +#endif + } + if (debug_specs & TXRX_DBG_MASK_STATS) { + ol_txrx_stats_display(vdev->pdev); + } + if (debug_specs & TXRX_DBG_MASK_PROT_ANALYZE) { +#if defined(ENABLE_TXRX_PROT_ANALYZE) + ol_txrx_prot_ans_display(vdev->pdev); +#else + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_FATAL, + "txrx protocol analysis is disabled.\n To enable it, recompile with ENABLE_TXRX_PROT_ANALYZE defined"); +#endif + } + if (debug_specs & TXRX_DBG_MASK_RX_REORDER_TRACE) { +#if defined(ENABLE_RX_REORDER_TRACE) + ol_rx_reorder_trace_display(vdev->pdev, 0, 0); +#else + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_FATAL, + "rx reorder seq num trace is disabled.\n To enable it, recompile with ENABLE_RX_REORDER_TRACE defined"); +#endif + + } + return 0; +} +#endif + +int ol_txrx_aggr_cfg(ol_txrx_vdev_handle vdev, + int max_subfrms_ampdu, int max_subfrms_amsdu) +{ + return htt_h2t_aggr_cfg_msg(vdev->pdev->htt_pdev, + max_subfrms_ampdu, max_subfrms_amsdu); +} + +#if defined(TXRX_DEBUG_LEVEL) && TXRX_DEBUG_LEVEL > 5 +void ol_txrx_pdev_display(ol_txrx_pdev_handle pdev, int indent) +{ + struct ol_txrx_vdev_t *vdev; + + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_LOW, + "%*s%s:\n", indent, " ", "txrx pdev"); + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_LOW, + "%*spdev object: %p", indent + 4, " ", pdev); + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_LOW, + "%*svdev list:", indent + 4, " "); + TAILQ_FOREACH(vdev, &pdev->vdev_list, vdev_list_elem) { + ol_txrx_vdev_display(vdev, indent + 8); + } + ol_txrx_peer_find_display(pdev, indent + 4); + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_LOW, + "%*stx desc pool: %d elems @ %p", indent + 4, " ", + pdev->tx_desc.pool_size, pdev->tx_desc.array); + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_LOW, " "); + htt_display(pdev->htt_pdev, indent); +} + +void ol_txrx_vdev_display(ol_txrx_vdev_handle vdev, int indent) +{ + struct ol_txrx_peer_t *peer; + + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_LOW, + "%*stxrx vdev: %p\n", indent, " ", vdev); + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_LOW, + "%*sID: %d\n", indent + 4, " ", vdev->vdev_id); + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_LOW, + "%*sMAC addr: %d:%d:%d:%d:%d:%d", + indent + 4, " ", + vdev->mac_addr.raw[0], vdev->mac_addr.raw[1], + vdev->mac_addr.raw[2], vdev->mac_addr.raw[3], + vdev->mac_addr.raw[4], vdev->mac_addr.raw[5]); + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_LOW, + "%*speer list:", indent + 4, " "); + TAILQ_FOREACH(peer, &vdev->peer_list, peer_list_elem) { + ol_txrx_peer_display(peer, indent + 8); + } +} + +void ol_txrx_peer_display(ol_txrx_peer_handle peer, int indent) +{ + int i; + + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_LOW, + "%*stxrx peer: %p", indent, " ", peer); + for (i = 0; i < MAX_NUM_PEER_ID_PER_PEER; i++) { + if (peer->peer_ids[i] != HTT_INVALID_PEER) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_LOW, + "%*sID: %d", indent + 4, " ", + peer->peer_ids[i]); + } + } +} +#endif /* TXRX_DEBUG_LEVEL */ + +/** + * ol_txrx_stats() - update ol layer stats + * @vdev_id: vdev_id + * @buffer: pointer to buffer + * @buf_len: length of the buffer + * + * Return: length of string + */ +int +ol_txrx_stats(uint8_t vdev_id, char *buffer, unsigned buf_len) +{ + uint32_t len = 0; + + ol_txrx_vdev_handle vdev = ol_txrx_get_vdev_from_vdev_id(vdev_id); + if (!vdev) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "%s: vdev is NULL", __func__); + snprintf(buffer, buf_len, "vdev not found"); + return len; + } + + len = scnprintf(buffer, buf_len, + "\n\nTXRX stats:\nllQueue State : %s\npause %u unpause %u\noverflow %u\nllQueue timer state : %s", + ((vdev->ll_pause.is_q_paused == false) ? + "UNPAUSED" : "PAUSED"), + vdev->ll_pause.q_pause_cnt, + vdev->ll_pause.q_unpause_cnt, + vdev->ll_pause.q_overflow_cnt, + ((vdev->ll_pause.is_q_timer_on == false) + ? "NOT-RUNNING" : "RUNNING")); + return len; +} + +#ifdef QCA_SUPPORT_TXRX_LOCAL_PEER_ID +/** + * ol_txrx_disp_peer_cached_bufq_stats() - display peer cached_bufq stats + * @peer: peer pointer + * + * Return: None + */ +static void ol_txrx_disp_peer_cached_bufq_stats(struct ol_txrx_peer_t *peer) +{ + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "cached_bufq: curr %d drops %d hwm %d whatifs %d thresh %d", + peer->bufq_info.curr, + peer->bufq_info.dropped, + peer->bufq_info.high_water_mark, + peer->bufq_info.qdepth_no_thresh, + peer->bufq_info.thresh); +} + +/** + * ol_txrx_disp_peer_stats() - display peer stats + * @pdev: pdev pointer + * + * Return: None + */ +static void ol_txrx_disp_peer_stats(ol_txrx_pdev_handle pdev) +{ int i; + struct ol_txrx_peer_t *peer; + struct hif_opaque_softc *osc = cds_get_context(QDF_MODULE_ID_HIF); + + if (osc && hif_is_load_or_unload_in_progress(HIF_GET_SOFTC(osc))) + return; + + for (i = 0; i < OL_TXRX_NUM_LOCAL_PEER_IDS; i++) { + qdf_spin_lock_bh(&pdev->local_peer_ids.lock); + peer = pdev->local_peer_ids.map[i]; + if (peer) + OL_TXRX_PEER_INC_REF_CNT(peer); + qdf_spin_unlock_bh(&pdev->local_peer_ids.lock); + + if (peer) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "stats: peer 0x%p local peer id %d", peer, i); + ol_txrx_disp_peer_cached_bufq_stats(peer); + OL_TXRX_PEER_UNREF_DELETE(peer); + } + } +} +#else +static void ol_txrx_disp_peer_stats(ol_txrx_pdev_handle pdev) +{ + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "peer stats not supported w/o QCA_SUPPORT_TXRX_LOCAL_PEER_ID"); +} +#endif + +void ol_txrx_stats_display(ol_txrx_pdev_handle pdev) +{ + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "TX PATH Statistics:"); + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "sent %lld msdus (%lld B), host rejected %lld (%lld B), dropped %lld (%lld B)", + pdev->stats.pub.tx.from_stack.pkts, + pdev->stats.pub.tx.from_stack.bytes, + pdev->stats.pub.tx.dropped.host_reject.pkts, + pdev->stats.pub.tx.dropped.host_reject.bytes, + pdev->stats.pub.tx.dropped.download_fail.pkts + + pdev->stats.pub.tx.dropped.target_discard.pkts + + pdev->stats.pub.tx.dropped.no_ack.pkts, + pdev->stats.pub.tx.dropped.download_fail.bytes + + pdev->stats.pub.tx.dropped.target_discard.bytes + + pdev->stats.pub.tx.dropped.no_ack.bytes); + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "successfully delivered: %lld (%lld B), " + "download fail: %lld (%lld B), " + "target discard: %lld (%lld B), " + "no ack: %lld (%lld B)", + pdev->stats.pub.tx.delivered.pkts, + pdev->stats.pub.tx.delivered.bytes, + pdev->stats.pub.tx.dropped.download_fail.pkts, + pdev->stats.pub.tx.dropped.download_fail.bytes, + pdev->stats.pub.tx.dropped.target_discard.pkts, + pdev->stats.pub.tx.dropped.target_discard.bytes, + pdev->stats.pub.tx.dropped.no_ack.pkts, + pdev->stats.pub.tx.dropped.no_ack.bytes); + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "Tx completions per HTT message:\n" + "Single Packet %d\n" + " 2-10 Packets %d\n" + "11-20 Packets %d\n" + "21-30 Packets %d\n" + "31-40 Packets %d\n" + "41-50 Packets %d\n" + "51-60 Packets %d\n" + " 60+ Packets %d\n", + pdev->stats.pub.tx.comp_histogram.pkts_1, + pdev->stats.pub.tx.comp_histogram.pkts_2_10, + pdev->stats.pub.tx.comp_histogram.pkts_11_20, + pdev->stats.pub.tx.comp_histogram.pkts_21_30, + pdev->stats.pub.tx.comp_histogram.pkts_31_40, + pdev->stats.pub.tx.comp_histogram.pkts_41_50, + pdev->stats.pub.tx.comp_histogram.pkts_51_60, + pdev->stats.pub.tx.comp_histogram.pkts_61_plus); + + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "RX PATH Statistics:"); + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "%lld ppdus, %lld mpdus, %lld msdus, %lld bytes\n" + "dropped: err %lld (%lld B), peer_invalid %lld (%lld B), mic_err %lld (%lld B)\n" + "msdus with frag_ind: %d msdus with offload_ind: %d", + pdev->stats.priv.rx.normal.ppdus, + pdev->stats.priv.rx.normal.mpdus, + pdev->stats.pub.rx.delivered.pkts, + pdev->stats.pub.rx.delivered.bytes, + pdev->stats.pub.rx.dropped_err.pkts, + pdev->stats.pub.rx.dropped_err.bytes, + pdev->stats.pub.rx.dropped_peer_invalid.pkts, + pdev->stats.pub.rx.dropped_peer_invalid.bytes, + pdev->stats.pub.rx.dropped_mic_err.pkts, + pdev->stats.pub.rx.dropped_mic_err.bytes, + pdev->stats.pub.rx.msdus_with_frag_ind, + pdev->stats.pub.rx.msdus_with_offload_ind); + + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + " fwd to stack %d, fwd to fw %d, fwd to stack & fw %d\n", + pdev->stats.pub.rx.intra_bss_fwd.packets_stack, + pdev->stats.pub.rx.intra_bss_fwd.packets_fwd, + pdev->stats.pub.rx.intra_bss_fwd.packets_stack_n_fwd); + + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "Rx packets per HTT message:\n" + "Single Packet %d\n" + " 2-10 Packets %d\n" + "11-20 Packets %d\n" + "21-30 Packets %d\n" + "31-40 Packets %d\n" + "41-50 Packets %d\n" + "51-60 Packets %d\n" + " 60+ Packets %d\n", + pdev->stats.pub.rx.rx_ind_histogram.pkts_1, + pdev->stats.pub.rx.rx_ind_histogram.pkts_2_10, + pdev->stats.pub.rx.rx_ind_histogram.pkts_11_20, + pdev->stats.pub.rx.rx_ind_histogram.pkts_21_30, + pdev->stats.pub.rx.rx_ind_histogram.pkts_31_40, + pdev->stats.pub.rx.rx_ind_histogram.pkts_41_50, + pdev->stats.pub.rx.rx_ind_histogram.pkts_51_60, + pdev->stats.pub.rx.rx_ind_histogram.pkts_61_plus); + + ol_txrx_disp_peer_stats(pdev); +} + +void ol_txrx_stats_clear(ol_txrx_pdev_handle pdev) +{ + qdf_mem_zero(&pdev->stats, sizeof(pdev->stats)); +} + +#if defined(ENABLE_TXRX_PROT_ANALYZE) + +void ol_txrx_prot_ans_display(ol_txrx_pdev_handle pdev) +{ + ol_txrx_prot_an_display(pdev->prot_an_tx_sent); + ol_txrx_prot_an_display(pdev->prot_an_rx_sent); +} + +#endif /* ENABLE_TXRX_PROT_ANALYZE */ + +#ifdef QCA_SUPPORT_PEER_DATA_RX_RSSI +int16_t ol_txrx_peer_rssi(ol_txrx_peer_handle peer) +{ + return (peer->rssi_dbm == HTT_RSSI_INVALID) ? + OL_TXRX_RSSI_INVALID : peer->rssi_dbm; +} +#endif /* #ifdef QCA_SUPPORT_PEER_DATA_RX_RSSI */ + +#ifdef QCA_ENABLE_OL_TXRX_PEER_STATS +A_STATUS +ol_txrx_peer_stats_copy(ol_txrx_pdev_handle pdev, + ol_txrx_peer_handle peer, ol_txrx_peer_stats_t *stats) +{ + qdf_assert(pdev && peer && stats); + qdf_spin_lock_bh(&pdev->peer_stat_mutex); + qdf_mem_copy(stats, &peer->stats, sizeof(*stats)); + qdf_spin_unlock_bh(&pdev->peer_stat_mutex); + return A_OK; +} +#endif /* QCA_ENABLE_OL_TXRX_PEER_STATS */ + +void ol_vdev_rx_set_intrabss_fwd(ol_txrx_vdev_handle vdev, bool val) +{ + if (NULL == vdev) + return; + + vdev->disable_intrabss_fwd = val; +} + +/** + * ol_txrx_update_mac_id() - update mac_id for vdev + * @vdev_id: vdev id + * @mac_id: mac id + * + * Return: none + */ +void ol_txrx_update_mac_id(uint8_t vdev_id, uint8_t mac_id) +{ + ol_txrx_vdev_handle vdev = ol_txrx_get_vdev_from_vdev_id(vdev_id); + + if (NULL == vdev) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid vdev_id %d", __func__, vdev_id); + return; + } + vdev->mac_id = mac_id; +} + +#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL + +/** + * ol_txrx_get_vdev_from_sta_id() - get vdev from sta_id + * @sta_id: sta_id + * + * Return: vdev handle + * NULL if not found. + */ +static ol_txrx_vdev_handle ol_txrx_get_vdev_from_sta_id(uint8_t sta_id) +{ + struct ol_txrx_peer_t *peer = NULL; + ol_txrx_pdev_handle pdev = NULL; + + if (sta_id >= WLAN_MAX_STA_COUNT) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "Invalid sta id passed"); + return NULL; + } + + pdev = cds_get_context(QDF_MODULE_ID_TXRX); + if (!pdev) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "PDEV not found for sta_id [%d]", sta_id); + return NULL; + } + + peer = ol_txrx_peer_find_by_local_id(pdev, sta_id); + + if (!peer) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "PEER [%d] not found", sta_id); + return NULL; + } + + return peer->vdev; +} + +/** + * ol_txrx_register_tx_flow_control() - register tx flow control callback + * @vdev_id: vdev_id + * @flowControl: flow control callback + * @osif_fc_ctx: callback context + * + * Return: 0 for sucess or error code + */ +int ol_txrx_register_tx_flow_control (uint8_t vdev_id, + ol_txrx_tx_flow_control_fp flowControl, + void *osif_fc_ctx) +{ + ol_txrx_vdev_handle vdev = ol_txrx_get_vdev_from_vdev_id(vdev_id); + if (NULL == vdev) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid vdev_id %d", __func__, vdev_id); + return -EINVAL; + } + + qdf_spin_lock_bh(&vdev->flow_control_lock); + vdev->osif_flow_control_cb = flowControl; + vdev->osif_fc_ctx = osif_fc_ctx; + qdf_spin_unlock_bh(&vdev->flow_control_lock); + return 0; +} + +/** + * ol_txrx_de_register_tx_flow_control_cb() - deregister tx flow control callback + * @vdev_id: vdev_id + * + * Return: 0 for success or error code + */ +int ol_txrx_deregister_tx_flow_control_cb(uint8_t vdev_id) +{ + ol_txrx_vdev_handle vdev = ol_txrx_get_vdev_from_vdev_id(vdev_id); + if (NULL == vdev) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid vdev_id", __func__); + return -EINVAL; + } + + qdf_spin_lock_bh(&vdev->flow_control_lock); + vdev->osif_flow_control_cb = NULL; + vdev->osif_fc_ctx = NULL; + qdf_spin_unlock_bh(&vdev->flow_control_lock); + return 0; +} + +/** + * ol_txrx_get_tx_resource() - if tx resource less than low_watermark + * @sta_id: sta id + * @low_watermark: low watermark + * @high_watermark_offset: high watermark offset value + * + * Return: true/false + */ +bool +ol_txrx_get_tx_resource(uint8_t sta_id, + unsigned int low_watermark, + unsigned int high_watermark_offset) +{ + ol_txrx_vdev_handle vdev = ol_txrx_get_vdev_from_sta_id(sta_id); + if (NULL == vdev) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid sta_id %d", __func__, sta_id); + /* Return true so caller do not understand that resource + * is less than low_watermark. + * sta_id validation will be done in ol_tx_send_data_frame + * and if sta_id is not registered then host will drop + * packet. + */ + return true; + } + + qdf_spin_lock_bh(&vdev->pdev->tx_mutex); + + if (vdev->pdev->tx_desc.num_free < (uint16_t) low_watermark) { + vdev->tx_fl_lwm = (uint16_t) low_watermark; + vdev->tx_fl_hwm = + (uint16_t) (low_watermark + high_watermark_offset); + /* Not enough free resource, stop TX OS Q */ + qdf_atomic_set(&vdev->os_q_paused, 1); + qdf_spin_unlock_bh(&vdev->pdev->tx_mutex); + return false; + } + qdf_spin_unlock_bh(&vdev->pdev->tx_mutex); + return true; +} + +/** + * ol_txrx_ll_set_tx_pause_q_depth() - set pause queue depth + * @vdev_id: vdev id + * @pause_q_depth: pause queue depth + * + * Return: 0 for success or error code + */ +int +ol_txrx_ll_set_tx_pause_q_depth(uint8_t vdev_id, int pause_q_depth) +{ + ol_txrx_vdev_handle vdev = ol_txrx_get_vdev_from_vdev_id(vdev_id); + if (NULL == vdev) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid vdev_id %d", __func__, vdev_id); + return -EINVAL; + } + + qdf_spin_lock_bh(&vdev->ll_pause.mutex); + vdev->ll_pause.max_q_depth = pause_q_depth; + qdf_spin_unlock_bh(&vdev->ll_pause.mutex); + + return 0; +} + +/** + * ol_txrx_flow_control_cb() - call osif flow control callback + * @vdev: vdev handle + * @tx_resume: tx resume flag + * + * Return: none + */ +inline void ol_txrx_flow_control_cb(ol_txrx_vdev_handle vdev, + bool tx_resume) +{ + qdf_spin_lock_bh(&vdev->flow_control_lock); + if ((vdev->osif_flow_control_cb) && (vdev->osif_fc_ctx)) + vdev->osif_flow_control_cb(vdev->osif_fc_ctx, tx_resume); + qdf_spin_unlock_bh(&vdev->flow_control_lock); + + return; +} +#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */ + +#ifdef IPA_OFFLOAD +/** + * ol_txrx_ipa_uc_get_resource() - Client request resource information + * @pdev: handle to the HTT instance + * @ce_sr_base_paddr: copy engine source ring base physical address + * @ce_sr_ring_size: copy engine source ring size + * @ce_reg_paddr: copy engine register physical address + * @tx_comp_ring_base_paddr: tx comp ring base physical address + * @tx_comp_ring_size: tx comp ring size + * @tx_num_alloc_buffer: number of allocated tx buffer + * @rx_rdy_ring_base_paddr: rx ready ring base physical address + * @rx_rdy_ring_size: rx ready ring size + * @rx_proc_done_idx_paddr: rx process done index physical address + * @rx_proc_done_idx_vaddr: rx process done index virtual address + * @rx2_rdy_ring_base_paddr: rx done ring base physical address + * @rx2_rdy_ring_size: rx done ring size + * @rx2_proc_done_idx_paddr: rx done index physical address + * @rx2_proc_done_idx_vaddr: rx done index virtual address + * + * OL client will reuqest IPA UC related resource information + * Resource information will be distributted to IPA module + * All of the required resources should be pre-allocated + * + * Return: none + */ +void +ol_txrx_ipa_uc_get_resource(ol_txrx_pdev_handle pdev, + struct ol_txrx_ipa_resources *ipa_res) +{ + htt_ipa_uc_get_resource(pdev->htt_pdev, + &ipa_res->ce_sr_base_paddr, + &ipa_res->ce_sr_ring_size, + &ipa_res->ce_reg_paddr, + &ipa_res->tx_comp_ring_base_paddr, + &ipa_res->tx_comp_ring_size, + &ipa_res->tx_num_alloc_buffer, + &ipa_res->rx_rdy_ring_base_paddr, + &ipa_res->rx_rdy_ring_size, + &ipa_res->rx_proc_done_idx_paddr, + &ipa_res->rx_proc_done_idx_vaddr, + &ipa_res->rx2_rdy_ring_base_paddr, + &ipa_res->rx2_rdy_ring_size, + &ipa_res->rx2_proc_done_idx_paddr, + &ipa_res->rx2_proc_done_idx_vaddr); +} + +/** + * ol_txrx_ipa_uc_set_doorbell_paddr() - Client set IPA UC doorbell register + * @pdev: handle to the HTT instance + * @ipa_uc_tx_doorbell_paddr: tx comp doorbell physical address + * @ipa_uc_rx_doorbell_paddr: rx ready doorbell physical address + * + * IPA UC let know doorbell register physical address + * WLAN firmware will use this physical address to notify IPA UC + * + * Return: none + */ +void +ol_txrx_ipa_uc_set_doorbell_paddr(ol_txrx_pdev_handle pdev, + qdf_dma_addr_t ipa_tx_uc_doorbell_paddr, + qdf_dma_addr_t ipa_rx_uc_doorbell_paddr) +{ + htt_ipa_uc_set_doorbell_paddr(pdev->htt_pdev, + ipa_tx_uc_doorbell_paddr, + ipa_rx_uc_doorbell_paddr); +} + +/** + * ol_txrx_ipa_uc_set_active() - Client notify IPA UC data path active or not + * @pdev: handle to the HTT instance + * @ipa_uc_tx_doorbell_paddr: tx comp doorbell physical address + * @ipa_uc_rx_doorbell_paddr: rx ready doorbell physical address + * + * IPA UC let know doorbell register physical address + * WLAN firmware will use this physical address to notify IPA UC + * + * Return: none + */ +void +ol_txrx_ipa_uc_set_active(ol_txrx_pdev_handle pdev, bool uc_active, bool is_tx) +{ + htt_h2t_ipa_uc_set_active(pdev->htt_pdev, uc_active, is_tx); +} + +/** + * ol_txrx_ipa_uc_op_response() - Handle OP command response from firmware + * @pdev: handle to the HTT instance + * @op_msg: op response message from firmware + * + * Return: none + */ +void ol_txrx_ipa_uc_op_response(ol_txrx_pdev_handle pdev, + uint8_t *op_msg) +{ + if (pdev->ipa_uc_op_cb) { + pdev->ipa_uc_op_cb(op_msg, pdev->osif_dev); + } else { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "%s: IPA callback function is not registered", __func__); + qdf_mem_free(op_msg); + return; + } +} + +/** + * ol_txrx_ipa_uc_register_op_cb() - Register OP handler function + * @pdev: handle to the HTT instance + * @op_cb: handler function pointer + * @osif_dev: register client context + * + * Return: none + */ +void ol_txrx_ipa_uc_register_op_cb(ol_txrx_pdev_handle pdev, + ipa_uc_op_cb_type op_cb, void *osif_dev) +{ + pdev->ipa_uc_op_cb = op_cb; + pdev->osif_dev = osif_dev; +} + +/** + * ol_txrx_ipa_uc_get_stat() - Get firmware wdi status + * @pdev: handle to the HTT instance + * + * Return: none + */ +void ol_txrx_ipa_uc_get_stat(ol_txrx_pdev_handle pdev) +{ + htt_h2t_ipa_uc_get_stats(pdev->htt_pdev); +} + +void ol_txrx_ipa_uc_get_share_stats(ol_txrx_pdev_handle pdev, + uint8_t reset_stats) +{ + htt_h2t_ipa_uc_get_share_stats(pdev->htt_pdev, reset_stats); +} + +void ol_txrx_ipa_uc_set_quota(ol_txrx_pdev_handle pdev, uint64_t quota_bytes) +{ + htt_h2t_ipa_uc_set_quota(pdev->htt_pdev, quota_bytes); +} +#endif /* IPA_UC_OFFLOAD */ + +/** + * ol_txrx_display_stats() - Display OL TXRX display stats + * @value: Module id for which stats needs to be displayed + * + * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E code on failure + */ +QDF_STATUS ol_txrx_display_stats(uint16_t value) +{ + ol_txrx_pdev_handle pdev; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + pdev = cds_get_context(QDF_MODULE_ID_TXRX); + if (!pdev) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "%s: pdev is NULL", __func__); + return QDF_STATUS_E_NULL_VALUE; + } + + switch (value) { + case WLAN_TXRX_STATS: + ol_txrx_stats_display(pdev); + break; + case WLAN_TXRX_TSO_STATS: + ol_txrx_stats_display_tso(pdev); + break; + case WLAN_DUMP_TX_FLOW_POOL_INFO: + ol_tx_dump_flow_pool_info(); + break; + case WLAN_TXRX_DESC_STATS: + qdf_nbuf_tx_desc_count_display(); + break; + case WLAN_RX_BUF_DEBUG_STATS: + htt_display_rx_buf_debug(pdev->htt_pdev); + break; +#ifdef CONFIG_HL_SUPPORT + case WLAN_SCHEDULER_STATS: + ol_tx_sched_cur_state_display(pdev); + ol_tx_sched_stats_display(pdev); + break; + case WLAN_TX_QUEUE_STATS: + ol_tx_queue_log_display(pdev); + break; +#ifdef FEATURE_HL_GROUP_CREDIT_FLOW_CONTROL + case WLAN_CREDIT_STATS: + ol_tx_dump_group_credit_stats(pdev); + break; +#endif + +#ifdef DEBUG_HL_LOGGING + case WLAN_BUNDLE_STATS: + htt_dump_bundle_stats(pdev->htt_pdev); + break; +#endif +#endif + default: + status = QDF_STATUS_E_INVAL; + break; + } + return status; +} + +/** + * ol_txrx_clear_stats() - Clear OL TXRX stats + * @value: Module id for which stats needs to be cleared + * + * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E code on failure + */ +QDF_STATUS ol_txrx_clear_stats(uint16_t value) +{ + ol_txrx_pdev_handle pdev; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + pdev = cds_get_context(QDF_MODULE_ID_TXRX); + if (!pdev) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "%s: pdev is NULL", __func__); + return QDF_STATUS_E_NULL_VALUE; + } + + switch (value) { + case WLAN_TXRX_STATS: + ol_txrx_stats_clear(pdev); + break; + case WLAN_DUMP_TX_FLOW_POOL_INFO: + ol_tx_clear_flow_pool_stats(); + break; + case WLAN_TXRX_DESC_STATS: + qdf_nbuf_tx_desc_count_clear(); + break; +#ifdef CONFIG_HL_SUPPORT + case WLAN_SCHEDULER_STATS: + ol_tx_sched_stats_clear(pdev); + break; + case WLAN_TX_QUEUE_STATS: + ol_tx_queue_log_clear(pdev); + break; +#ifdef FEATURE_HL_GROUP_CREDIT_FLOW_CONTROL + case WLAN_CREDIT_STATS: + ol_tx_clear_group_credit_stats(pdev); + break; +#endif + case WLAN_BUNDLE_STATS: + htt_clear_bundle_stats(pdev->htt_pdev); + break; +#endif + default: + status = QDF_STATUS_E_INVAL; + break; + } + + return status; +} + +/** + * ol_txrx_drop_nbuf_list() - drop an nbuf list + * @buf_list: buffer list to be dropepd + * + * Return: int (number of bufs dropped) + */ +static inline int ol_txrx_drop_nbuf_list(qdf_nbuf_t buf_list) +{ + int num_dropped = 0; + qdf_nbuf_t buf, next_buf; + ol_txrx_pdev_handle pdev = cds_get_context(QDF_MODULE_ID_TXRX); + + buf = buf_list; + while (buf) { + next_buf = qdf_nbuf_queue_next(buf); + if (pdev) + TXRX_STATS_MSDU_INCR(pdev, + rx.dropped_peer_invalid, buf); + qdf_nbuf_free(buf); + buf = next_buf; + num_dropped++; + } + return num_dropped; +} + +/** + * ol_rx_data_cb() - data rx callback + * @peer: peer + * @buf_list: buffer list + * @staid: Station id + * + * Return: None + */ +static void ol_rx_data_cb(struct ol_txrx_pdev_t *pdev, + qdf_nbuf_t buf_list, uint16_t staid) +{ + void *cds_ctx = cds_get_global_context(); + void *osif_dev; + uint8_t drop_count = 0; + qdf_nbuf_t buf, next_buf; + QDF_STATUS ret; + ol_txrx_rx_fp data_rx = NULL; + struct ol_txrx_peer_t *peer; + + if (qdf_unlikely(!cds_ctx) || qdf_unlikely(!pdev)) + goto free_buf; + + /* Do not use peer directly. Derive peer from staid to + * make sure that peer is valid. + */ + peer = ol_txrx_peer_find_by_local_id(pdev, staid); + if (!peer) + goto free_buf; + + qdf_spin_lock_bh(&peer->peer_info_lock); + if (qdf_unlikely(!(peer->state >= OL_TXRX_PEER_STATE_CONN) || + !peer->vdev->rx)) { + qdf_spin_unlock_bh(&peer->peer_info_lock); + goto free_buf; + } + + data_rx = peer->vdev->rx; + osif_dev = peer->vdev->osif_dev; + qdf_spin_unlock_bh(&peer->peer_info_lock); + + qdf_spin_lock_bh(&peer->bufq_info.bufq_lock); + if (!list_empty(&peer->bufq_info.cached_bufq)) { + qdf_spin_unlock_bh(&peer->bufq_info.bufq_lock); + /* Flush the cached frames to HDD before passing new rx frame */ + ol_txrx_flush_rx_frames(peer, 0); + } else + qdf_spin_unlock_bh(&peer->bufq_info.bufq_lock); + + buf = buf_list; + while (buf) { + next_buf = qdf_nbuf_queue_next(buf); + qdf_nbuf_set_next(buf, NULL); /* Add NULL terminator */ + ret = data_rx(osif_dev, buf); + if (ret != QDF_STATUS_SUCCESS) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, "Frame Rx to HDD failed"); + if (pdev) + TXRX_STATS_MSDU_INCR(pdev, rx.dropped_err, buf); + qdf_nbuf_free(buf); + } + buf = next_buf; + } + return; + +free_buf: + + drop_count = ol_txrx_drop_nbuf_list(buf_list); + TXRX_PRINT(TXRX_PRINT_LEVEL_WARN, + "%s:Dropped frames %u", __func__, drop_count); +} + +/* print for every 16th packet */ +#define OL_TXRX_PRINT_RATE_LIMIT_THRESH 0x0f + +/** helper function to drop packets + * Note: caller must hold the cached buq lock before invoking + * this function. Also, it assumes that the pointers passed in + * are valid (non-NULL) + */ +static inline void ol_txrx_drop_frames( + struct ol_txrx_cached_bufq_t *bufqi, + qdf_nbuf_t rx_buf_list) +{ + uint32_t dropped = ol_txrx_drop_nbuf_list(rx_buf_list); + bufqi->dropped += dropped; + bufqi->qdepth_no_thresh += dropped; + + if (bufqi->qdepth_no_thresh > bufqi->high_water_mark) + bufqi->high_water_mark = bufqi->qdepth_no_thresh; +} + +static QDF_STATUS ol_txrx_enqueue_rx_frames( + struct ol_txrx_peer_t *peer, + struct ol_txrx_cached_bufq_t *bufqi, + qdf_nbuf_t rx_buf_list) +{ + struct ol_rx_cached_buf *cache_buf; + qdf_nbuf_t buf, next_buf; + static uint32_t count; + + if ((count++ & OL_TXRX_PRINT_RATE_LIMIT_THRESH) == 0) + TXRX_PRINT(TXRX_PRINT_LEVEL_INFO1, + "Data on the peer before it is registered bufq->curr %d bufq->drops %d", + bufqi->curr, bufqi->dropped); + + qdf_spin_lock_bh(&bufqi->bufq_lock); + if (bufqi->curr >= bufqi->thresh) { + ol_txrx_drop_frames(bufqi, rx_buf_list); + qdf_spin_unlock_bh(&bufqi->bufq_lock); + return QDF_STATUS_E_FAULT; + } + qdf_spin_unlock_bh(&bufqi->bufq_lock); + + buf = rx_buf_list; + while (buf) { + QDF_NBUF_CB_RX_PEER_CACHED_FRM(buf) = 1; + next_buf = qdf_nbuf_queue_next(buf); + cache_buf = qdf_mem_malloc(sizeof(*cache_buf)); + if (!cache_buf) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "Failed to allocate buf to cache the rx frames"); + qdf_nbuf_free(buf); + } else { + /* Add NULL terminator */ + qdf_nbuf_set_next(buf, NULL); + cache_buf->buf = buf; + if (peer && peer->valid) { + qdf_spin_lock_bh(&bufqi->bufq_lock); + list_add_tail(&cache_buf->list, + &bufqi->cached_bufq); + bufqi->curr++; + qdf_spin_unlock_bh(&bufqi->bufq_lock); + } else { + qdf_mem_free(cache_buf); + rx_buf_list = buf; + qdf_nbuf_set_next(rx_buf_list, next_buf); + qdf_spin_lock_bh(&bufqi->bufq_lock); + ol_txrx_drop_frames(bufqi, rx_buf_list); + qdf_spin_unlock_bh(&bufqi->bufq_lock); + return QDF_STATUS_E_FAULT; + } + } + buf = next_buf; + } + return QDF_STATUS_SUCCESS; +} +/** + * ol_rx_data_process() - process rx frame + * @peer: peer + * @rx_buf_list: rx buffer list + * + * Return: None + */ +void ol_rx_data_process(struct ol_txrx_peer_t *peer, + qdf_nbuf_t rx_buf_list) +{ + /* Firmware data path active response will use shim RX thread + * T2H MSG running on SIRQ context, + * IPA kernel module API should not be called on SIRQ CTXT */ + ol_txrx_rx_fp data_rx = NULL; + ol_txrx_pdev_handle pdev = cds_get_context(QDF_MODULE_ID_TXRX); + uint8_t drop_count; + + if ((!peer) || (!pdev)) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, "peer/pdev is NULL"); + goto drop_rx_buf; + } + + qdf_assert(peer->vdev); + + qdf_spin_lock_bh(&peer->peer_info_lock); + if (peer->state >= OL_TXRX_PEER_STATE_CONN) + data_rx = peer->vdev->rx; + qdf_spin_unlock_bh(&peer->peer_info_lock); + + /* + * If there is a data frame from peer before the peer is + * registered for data service, enqueue them on to pending queue + * which will be flushed to HDD once that station is registered. + */ + if (!data_rx) { + if (ol_txrx_enqueue_rx_frames(peer, &peer->bufq_info, + rx_buf_list) + != QDF_STATUS_SUCCESS) + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: failed to enqueue rx frm to cached_bufq", + __func__); + } else { +#ifdef QCA_CONFIG_SMP + /* + * If the kernel is SMP, schedule rx thread to + * better use multicores. + */ + if (!ol_cfg_is_rx_thread_enabled(pdev->ctrl_pdev)) { + ol_rx_data_cb(pdev, rx_buf_list, peer->local_id); + } else { + p_cds_sched_context sched_ctx = + get_cds_sched_ctxt(); + struct cds_ol_rx_pkt *pkt; + + if (unlikely(!sched_ctx)) + goto drop_rx_buf; + + pkt = cds_alloc_ol_rx_pkt(sched_ctx); + if (!pkt) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "No available Rx message buffer"); + goto drop_rx_buf; + } + pkt->callback = (cds_ol_rx_thread_cb) + ol_rx_data_cb; + pkt->context = (void *)pdev; + pkt->Rxpkt = (void *)rx_buf_list; + pkt->staId = peer->local_id; + cds_indicate_rxpkt(sched_ctx, pkt); + } +#else /* QCA_CONFIG_SMP */ + ol_rx_data_cb(pdev, rx_buf_list, peer->local_id); +#endif /* QCA_CONFIG_SMP */ + } + + return; + +drop_rx_buf: + drop_count = ol_txrx_drop_nbuf_list(rx_buf_list); + TXRX_PRINT(TXRX_PRINT_LEVEL_INFO1, "Dropped rx packets %u", drop_count); +} + +/** + * ol_txrx_register_peer() - register peer + * @sta_desc: sta descriptor + * + * Return: QDF Status + */ +QDF_STATUS ol_txrx_register_peer(struct ol_txrx_desc_type *sta_desc) +{ + struct ol_txrx_peer_t *peer; + struct ol_txrx_pdev_t *pdev = cds_get_context(QDF_MODULE_ID_TXRX); + union ol_txrx_peer_update_param_t param; + struct privacy_exemption privacy_filter; + + if (!pdev) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, "Pdev is NULL"); + return QDF_STATUS_E_INVAL; + } + + if (sta_desc->sta_id >= WLAN_MAX_STA_COUNT) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, "Invalid sta id :%d", + sta_desc->sta_id); + return QDF_STATUS_E_INVAL; + } + + peer = ol_txrx_peer_find_by_local_id(pdev, sta_desc->sta_id); + if (!peer) + return QDF_STATUS_E_FAULT; + + qdf_spin_lock_bh(&peer->peer_info_lock); + peer->state = OL_TXRX_PEER_STATE_CONN; + qdf_spin_unlock_bh(&peer->peer_info_lock); + + param.qos_capable = sta_desc->is_qos_enabled; + ol_txrx_peer_update(peer->vdev, peer->mac_addr.raw, ¶m, + ol_txrx_peer_update_qos_capable); + + if (sta_desc->is_wapi_supported) { + /*Privacy filter to accept unencrypted WAI frames */ + privacy_filter.ether_type = ETHERTYPE_WAI; + privacy_filter.filter_type = PRIVACY_FILTER_ALWAYS; + privacy_filter.packet_type = PRIVACY_FILTER_PACKET_BOTH; + ol_txrx_set_privacy_filters(peer->vdev, &privacy_filter, 1); + } + + ol_txrx_flush_rx_frames(peer, 0); + return QDF_STATUS_SUCCESS; +} + +/** + * ol_txrx_register_ocb_peer - Function to register the OCB peer + * @cds_ctx: Pointer to the global OS context + * @mac_addr: MAC address of the self peer + * @peer_id: Pointer to the peer ID + * + * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_FAILURE on failure + */ +QDF_STATUS ol_txrx_register_ocb_peer(void *cds_ctx, uint8_t *mac_addr, + uint8_t *peer_id) +{ + ol_txrx_pdev_handle pdev; + ol_txrx_peer_handle peer; + + if (!cds_ctx) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, "%s: Invalid context", + __func__); + return QDF_STATUS_E_FAILURE; + } + + pdev = cds_get_context(QDF_MODULE_ID_TXRX); + if (!pdev) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, "%s: Unable to find pdev!", + __func__); + return QDF_STATUS_E_FAILURE; + } + + peer = ol_txrx_find_peer_by_addr(pdev, mac_addr, peer_id); + if (!peer) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, "%s: Unable to find OCB peer!", + __func__); + return QDF_STATUS_E_FAILURE; + } + + ol_txrx_set_ocb_peer(pdev, peer); + + /* Set peer state to connected */ + ol_txrx_peer_state_update(pdev, peer->mac_addr.raw, + OL_TXRX_PEER_STATE_AUTH); + + return QDF_STATUS_SUCCESS; +} + +/** + * ol_txrx_set_ocb_peer - Function to store the OCB peer + * @pdev: Handle to the HTT instance + * @peer: Pointer to the peer + */ +void ol_txrx_set_ocb_peer(struct ol_txrx_pdev_t *pdev, + struct ol_txrx_peer_t *peer) +{ + if (pdev == NULL) + return; + + pdev->ocb_peer = peer; + pdev->ocb_peer_valid = (NULL != peer); +} + +/** + * ol_txrx_get_ocb_peer - Function to retrieve the OCB peer + * @pdev: Handle to the HTT instance + * @peer: Pointer to the returned peer + * + * Return: true if the peer is valid, false if not + */ +bool ol_txrx_get_ocb_peer(struct ol_txrx_pdev_t *pdev, + struct ol_txrx_peer_t **peer) +{ + int rc; + + if ((pdev == NULL) || (peer == NULL)) { + rc = false; + goto exit; + } + + if (pdev->ocb_peer_valid) { + *peer = pdev->ocb_peer; + rc = true; + } else { + rc = false; + } + +exit: + return rc; +} +#define MAX_TID 15 +#define MAX_DATARATE 7 +#define OCB_HEADER_VERSION 1 + +/** + * ol_txrx_set_ocb_def_tx_param() - Set the default OCB TX parameters + * @vdev: The OCB vdev that will use these defaults. + * @_def_tx_param: The default TX parameters. + * @def_tx_param_size: The size of the _def_tx_param buffer. + * + * Return: true if the default parameters were set correctly, false if there + * is an error, for example an invalid parameter. In the case that false is + * returned, see the kernel log for the error description. + */ +bool ol_txrx_set_ocb_def_tx_param(ol_txrx_vdev_handle vdev, + void *_def_tx_param, uint32_t def_tx_param_size) +{ + struct ocb_tx_ctrl_hdr_t *def_tx_param = + (struct ocb_tx_ctrl_hdr_t *)_def_tx_param; + + if (def_tx_param) { + /* + * Default TX parameters are provided. + * Validate the contents and + * save them in the vdev. + */ + if (def_tx_param_size != sizeof(struct ocb_tx_ctrl_hdr_t)) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "%sInvalid size of OCB default TX params", __func__); + return false; + } + + if (def_tx_param->version != OCB_HEADER_VERSION) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "%sInvalid version of OCB default TX params", __func__); + return false; + } + + if (def_tx_param->channel_freq) { + int i; + + for (i = 0; i < vdev->ocb_channel_count; i++) { + if (vdev->ocb_channel_info[i].chan_freq == + def_tx_param->channel_freq) + break; + } + if (i == vdev->ocb_channel_count) { + QDF_TRACE(QDF_MODULE_ID_TXRX, + QDF_TRACE_LEVEL_ERROR, + "%sInvalid default channel frequency", __func__); + return false; + } + } + + if (def_tx_param->valid_datarate && + def_tx_param->datarate > MAX_DATARATE) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "%sInvalid default datarate", __func__); + return false; + } + + if (def_tx_param->valid_tid && + def_tx_param->ext_tid > MAX_TID) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "%sInvalid default TID", __func__); + return false; + } + + if (vdev->ocb_def_tx_param == NULL) + vdev->ocb_def_tx_param = + qdf_mem_malloc(sizeof(*vdev->ocb_def_tx_param)); + qdf_mem_copy(vdev->ocb_def_tx_param, def_tx_param, + sizeof(*vdev->ocb_def_tx_param)); + } else { + /* + * Default TX parameters are not provided. + * Delete the old defaults. + */ + if (vdev->ocb_def_tx_param) { + qdf_mem_free(vdev->ocb_def_tx_param); + vdev->ocb_def_tx_param = NULL; + } + } + + return true; +} + +#ifdef QCA_LL_TX_FLOW_CONTROL_V2 +/** + * ol_txrx_register_pause_cb() - register pause callback + * @pause_cb: pause callback + * + * Return: QDF status + */ +QDF_STATUS ol_txrx_register_pause_cb(ol_tx_pause_callback_fp pause_cb) +{ + struct ol_txrx_pdev_t *pdev = cds_get_context(QDF_MODULE_ID_TXRX); + if (!pdev || !pause_cb) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, "pdev or pause_cb is NULL"); + return QDF_STATUS_E_INVAL; + } + pdev->pause_cb = pause_cb; + return QDF_STATUS_SUCCESS; +} +#endif + +#if defined(FEATURE_LRO) +/** + * ol_txrx_lro_flush_handler() - LRO flush handler + * @context: dev handle + * @rxpkt: rx data + * @staid: station id + * + * This function handles an LRO flush indication. + * If the rx thread is enabled, it will be invoked by the rx + * thread else it will be called in the tasklet context + * + * Return: none + */ +static void ol_txrx_lro_flush_handler(void *context, + void *rxpkt, + uint16_t staid) +{ + ol_txrx_pdev_handle pdev = cds_get_context(QDF_MODULE_ID_TXRX); + + if (qdf_unlikely(!pdev)) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid context", __func__); + qdf_assert(0); + return; + } + + if (pdev->lro_info.lro_flush_cb) + pdev->lro_info.lro_flush_cb(context); + else + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "%s: lro_flush_cb NULL", __func__); +} + +/** + * ol_txrx_lro_flush() - LRO flush callback + * @data: opaque data pointer + * + * This is the callback registered with CE to trigger + * an LRO flush + * + * Return: none + */ +static void ol_txrx_lro_flush(void *data) +{ + p_cds_sched_context sched_ctx = get_cds_sched_ctxt(); + struct cds_ol_rx_pkt *pkt; + ol_txrx_pdev_handle pdev = cds_get_context(QDF_MODULE_ID_TXRX); + + if (qdf_unlikely(!sched_ctx)) + return; + + if (qdf_unlikely(!pdev)) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "Pdev is NULL"); + return; + } + + if (!ol_cfg_is_rx_thread_enabled(pdev->ctrl_pdev)) { + ol_txrx_lro_flush_handler(data, NULL, 0); + } else { + pkt = cds_alloc_ol_rx_pkt(sched_ctx); + if (qdf_unlikely(!pkt)) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "%s: Not able to allocate context", __func__); + return; + } + + pkt->callback = + (cds_ol_rx_thread_cb) ol_txrx_lro_flush_handler; + pkt->context = data; + pkt->Rxpkt = NULL; + pkt->staId = 0; + cds_indicate_rxpkt(sched_ctx, pkt); + } +} + +/** + * ol_register_lro_flush_cb() - register the LRO flush callback + * @lro_flush_cb: flush callback function + * @lro_init_cb: Allocate and initialize LRO data structure. + * + * Store the LRO flush callback provided and in turn + * register OL's LRO flush handler with CE + * + * Return: none + */ +void ol_register_lro_flush_cb(void (lro_flush_cb)(void *), + void *(lro_init_cb)(void)) +{ + struct hif_opaque_softc *hif_device; + struct ol_txrx_pdev_t *pdev = cds_get_context(QDF_MODULE_ID_TXRX); + + if (pdev == NULL) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, "%s: pdev NULL!", __func__); + TXRX_ASSERT2(0); + goto out; + } + pdev->lro_info.lro_flush_cb = lro_flush_cb; + hif_device = (struct hif_opaque_softc *) + cds_get_context(QDF_MODULE_ID_HIF); + + if (qdf_unlikely(hif_device == NULL)) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "%s: hif_device NULL!", __func__); + qdf_assert(0); + goto out; + } + + hif_lro_flush_cb_register(hif_device, ol_txrx_lro_flush, lro_init_cb); + +out: + return; +} + +/** + * ol_deregister_lro_flush_cb() - deregister the LRO flush callback + * @lro_deinit_cb: callback function for deregistration. + * + * Remove the LRO flush callback provided and in turn + * deregister OL's LRO flush handler with CE + * + * Return: none + */ +void ol_deregister_lro_flush_cb(void (lro_deinit_cb)(void *)) +{ + struct hif_opaque_softc *hif_device; + struct ol_txrx_pdev_t *pdev = cds_get_context(QDF_MODULE_ID_TXRX); + + if (pdev == NULL) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, "%s: pdev NULL!", __func__); + return; + } + hif_device = + (struct hif_opaque_softc *)cds_get_context(QDF_MODULE_ID_HIF); + if (qdf_unlikely(hif_device == NULL)) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "%s: hif_device NULL!", __func__); + qdf_assert(0); + return; + } + + hif_lro_flush_cb_deregister(hif_device, lro_deinit_cb); + + pdev->lro_info.lro_flush_cb = NULL; +} +#endif /* FEATURE_LRO */ + +void +ol_txrx_dump_pkt(qdf_nbuf_t nbuf, uint32_t nbuf_paddr, int len) +{ + qdf_print("%s: Pkt: VA 0x%p PA 0x%llx len %d\n", __func__, + qdf_nbuf_data(nbuf), (unsigned long long int)nbuf_paddr, len); + print_hex_dump(KERN_DEBUG, "Pkt: ", DUMP_PREFIX_ADDRESS, 16, 4, + qdf_nbuf_data(nbuf), len, true); +} + +#ifdef QCA_LL_TX_FLOW_CONTROL_V2 +bool +ol_txrx_fwd_desc_thresh_check(struct ol_txrx_vdev_t *vdev) +{ + struct ol_tx_flow_pool_t *pool; + bool enough_desc_flag; + + if (!vdev) + return false; + + pool = vdev->pool; + + if (!pool) + return false; + + qdf_spin_lock_bh(&pool->flow_pool_lock); + enough_desc_flag = (pool->avail_desc < (pool->stop_th + + OL_TX_NON_FWD_RESERVE)) + ? false : true; + qdf_spin_unlock_bh(&pool->flow_pool_lock); + return enough_desc_flag; +} +#else +bool ol_txrx_fwd_desc_thresh_check(struct ol_txrx_vdev_t *vdev) +{ + return true; +} +#endif + + +/** + * ol_txrx_get_vdev_from_vdev_id() - get vdev from vdev_id + * @vdev_id: vdev_id + * + * Return: vdev handle + * NULL if not found. + */ +ol_txrx_vdev_handle ol_txrx_get_vdev_from_vdev_id(uint8_t vdev_id) +{ + ol_txrx_pdev_handle pdev = cds_get_context(QDF_MODULE_ID_TXRX); + ol_txrx_vdev_handle vdev = NULL; + + if (qdf_unlikely(!pdev)) + return NULL; + + TAILQ_FOREACH(vdev, &pdev->vdev_list, vdev_list_elem) { + if (vdev->vdev_id == vdev_id) + break; + } + + return vdev; +} + +/** + * ol_txrx_set_wisa_mode() - set wisa mode + * @vdev: vdev handle + * @enable: enable flag + * + * Return: QDF STATUS + */ +QDF_STATUS ol_txrx_set_wisa_mode(ol_txrx_vdev_handle vdev, bool enable) +{ + if (!vdev) + return QDF_STATUS_E_INVAL; + + vdev->is_wisa_mode_enable = enable; + return QDF_STATUS_SUCCESS; +} diff --git a/drivers/staging/qcacld-3.0/core/dp/txrx/ol_txrx.h b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_txrx.h new file mode 100644 index 0000000000000000000000000000000000000000..16b2fcf062ce094525e66aeca4f33a8c5e7c6c64 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_txrx.h @@ -0,0 +1,185 @@ +/* + * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef _OL_TXRX__H_ +#define _OL_TXRX__H_ + +#include /* qdf_nbuf_t */ +#include /* ol_txrx_vdev_t, etc. */ +#include "cds_sched.h" + +/* + * Pool of tx descriptors reserved for + * high-priority traffic, such as ARP/EAPOL etc + * only for forwarding path. + */ +#define OL_TX_NON_FWD_RESERVE 100 +#define OL_TXRX_PEER_UNREF_DELETE(peer) \ + ol_txrx_peer_unref_delete(peer, __func__, __LINE__); + +int ol_txrx_peer_unref_delete(ol_txrx_peer_handle peer, + const char *fname, + int line); + +ol_txrx_peer_handle ol_txrx_find_peer_by_addr_inc_ref(ol_txrx_pdev_handle pdev, + uint8_t *peer_addr, + uint8_t *peer_id); +/** + * ol_tx_desc_pool_size_hl() - allocate tx descriptor pool size for HL systems + * @ctrl_pdev: the control pdev handle + * + * Return: allocated pool size + */ +u_int16_t +ol_tx_desc_pool_size_hl(ol_pdev_handle ctrl_pdev); + +#ifndef OL_TX_AVG_FRM_BYTES +#define OL_TX_AVG_FRM_BYTES 1000 +#endif + +#ifndef OL_TX_DESC_POOL_SIZE_MIN_HL +#define OL_TX_DESC_POOL_SIZE_MIN_HL 500 +#endif + +#ifndef OL_TX_DESC_POOL_SIZE_MAX_HL +#define OL_TX_DESC_POOL_SIZE_MAX_HL 5000 +#endif + + +#ifdef CONFIG_PER_VDEV_TX_DESC_POOL +#define TXRX_HL_TX_FLOW_CTRL_VDEV_LOW_WATER_MARK 400 +#define TXRX_HL_TX_FLOW_CTRL_MGMT_RESERVED 100 +#endif + +#ifdef CONFIG_TX_DESC_HI_PRIO_RESERVE +#define TXRX_HL_TX_DESC_HI_PRIO_RESERVED 20 +#endif + +#if defined(CONFIG_HL_SUPPORT) && defined(FEATURE_WLAN_TDLS) + +void +ol_txrx_hl_tdls_flag_reset(struct ol_txrx_vdev_t *vdev, bool flag); +#else + +static inline void +ol_txrx_hl_tdls_flag_reset(struct ol_txrx_vdev_t *vdev, bool flag) +{ + return; +} +#endif + +#if defined(CONFIG_HL_SUPPORT) && defined(FEATURE_WLAN_TDLS) +void +ol_txrx_copy_mac_addr_raw(ol_txrx_vdev_handle vdev, uint8_t *bss_addr); + +void +ol_txrx_add_last_real_peer(ol_txrx_pdev_handle pdev, + ol_txrx_vdev_handle vdev, + uint8_t *peer_id); + +bool +is_vdev_restore_last_peer(struct ol_txrx_peer_t *peer); + +void +ol_txrx_update_last_real_peer( + ol_txrx_pdev_handle pdev, + struct ol_txrx_peer_t *peer, + uint8_t *peer_id, bool restore_last_peer); +#else + +static inline void +ol_txrx_copy_mac_addr_raw(ol_txrx_vdev_handle vdev, uint8_t *bss_addr) +{ + return; +} + +static inline void +ol_txrx_add_last_real_peer(ol_txrx_pdev_handle pdev, + ol_txrx_vdev_handle vdev, uint8_t *peer_id) +{ + return; +} + +static inline bool +is_vdev_restore_last_peer(struct ol_txrx_peer_t *peer) +{ + return false; +} + +static inline void +ol_txrx_update_last_real_peer( + ol_txrx_pdev_handle pdev, + struct ol_txrx_peer_t *peer, + uint8_t *peer_id, bool restore_last_peer) + +{ + return; +} +#endif + +/** + * ol_txrx_dump_pkt() - display the data in buffer and buffer's address + * @nbuf: buffer which contains data to be displayed + * @nbuf_paddr: physical address of the buffer + * @len: defines the size of the data to be displayed + * + * Return: None + */ +void +ol_txrx_dump_pkt(qdf_nbuf_t nbuf, uint32_t nbuf_paddr, int len); + +/** + * ol_txrx_fwd_desc_thresh_check() - check to forward packet to tx path + * @vdev: which virtual device the frames were addressed to + * + * This API is to check whether enough descriptors are available or not + * to forward packet to tx path. If not enough descriptors left, + * start dropping tx-path packets. + * Do not pause netif queues as still a pool of descriptors is reserved + * for high-priority traffic such as EAPOL/ARP etc. + * In case of intra-bss forwarding, it could be possible that tx-path can + * consume all the tx descriptors and pause netif queues. Due to this, + * there would be some left for stack triggered packets such as ARP packets + * which could lead to disconnection of device. To avoid this, reserved + * a pool of descriptors for high-priority packets, i.e., reduce the + * threshold of drop in the intra-bss forwarding path. + * + * Return: true ; forward the packet, i.e., below threshold + * false; not enough descriptors, drop the packet + */ +bool ol_txrx_fwd_desc_thresh_check(struct ol_txrx_vdev_t *vdev); + +ol_txrx_vdev_handle ol_txrx_get_vdev_from_vdev_id(uint8_t vdev_id); + +void htt_pkt_log_init(struct ol_txrx_pdev_t *handle, void *scn); +QDF_STATUS ol_txrx_set_wisa_mode(ol_txrx_vdev_handle vdev, + bool enable); +void ol_txrx_update_mac_id(uint8_t vdev_id, uint8_t mac_id); +void ol_txrx_peer_detach_force_delete(ol_txrx_peer_handle peer); +void peer_unmap_timer_handler(void *data); + +#endif /* _OL_TXRX__H_ */ diff --git a/drivers/staging/qcacld-3.0/core/dp/txrx/ol_txrx_encap.c b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_txrx_encap.c new file mode 100644 index 0000000000000000000000000000000000000000..95c9d65d63e73fa52a1815935b1ae1b220380726 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_txrx_encap.c @@ -0,0 +1,592 @@ +/* + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * @file ol_txrx_encap.c + * @brief Provide functions to encap/decap on txrx frames. + * @details + * This file contains functions for data frame encap/decap: + * ol_tx_encap: encap outgoing data frames. + * ol_rx_decap: decap incoming data frames. + */ +#ifdef QCA_SUPPORT_SW_TXRX_ENCAP + +#include /* qdf_nbuf_t, etc. */ +#include /* ieee80211_frame */ +#include /* struct llc, struct ether_header, etc. */ +#include /* TXRX_ASSERT1 */ +#include /* struct ol_rx_decap_info_t */ + +#define OL_TX_COPY_NATIVE_WIFI_HEADER(wh, msdu, hdsize, localbuf) \ + do { \ + wh = (struct ieee80211_frame *)qdf_nbuf_data(msdu); \ + if ((wh->i_fc[1] & \ + IEEE80211_FC1_DIR_MASK) == IEEE80211_FC1_DIR_DSTODS) { \ + hdsize = sizeof(struct ieee80211_frame_addr4); \ + } else { \ + hdsize = sizeof(struct ieee80211_frame); \ + } \ + if (qdf_nbuf_len(msdu) < hdsize) { \ + return A_ERROR; \ + } \ + qdf_mem_copy(localbuf, wh, hdsize); \ + wh = (struct ieee80211_frame *)localbuf; \ + } while (0) + +static inline A_STATUS +ol_tx_copy_native_wifi_header(qdf_nbuf_t msdu, + uint8_t *hdsize, uint8_t *localbuf) +{ + struct ieee80211_frame *wh = + (struct ieee80211_frame *)qdf_nbuf_data(msdu); + if ((wh->i_fc[1] & + IEEE80211_FC1_DIR_MASK) == IEEE80211_FC1_DIR_DSTODS) { + *hdsize = sizeof(struct ieee80211_frame_addr4); + } else { + *hdsize = sizeof(struct ieee80211_frame); + } + if (qdf_nbuf_len(msdu) < *hdsize) + return A_ERROR; + + qdf_mem_copy(localbuf, wh, *hdsize); + return A_OK; +} + +static inline A_STATUS +ol_tx_encap_from_native_wifi(struct ol_txrx_vdev_t *vdev, + struct ol_tx_desc_t *tx_desc, + qdf_nbuf_t msdu, + struct ol_txrx_msdu_info_t *tx_msdu_info) +{ + uint8_t localbuf[sizeof(struct ieee80211_qosframe_htc_addr4)]; + struct ieee80211_frame *wh; + uint8_t hdsize, new_hdsize; + struct ieee80211_qoscntl *qos_cntl; + struct ol_txrx_peer_t *peer; + + if (tx_msdu_info->htt.info.frame_type != htt_frm_type_data) + return A_OK; + + peer = tx_msdu_info->peer; + /* + * for unicast,the peer should not be NULL. + * for multicast, the peer is AP. + */ + if (tx_msdu_info->htt.info.is_unicast && peer->qos_capable) { + if (A_OK != + ol_tx_copy_native_wifi_header(msdu, &hdsize, localbuf)) + return A_ERROR; + wh = (struct ieee80211_frame *)localbuf; + + /*add qos cntl */ + qos_cntl = (struct ieee80211_qoscntl *)(localbuf + hdsize); + qos_cntl->i_qos[0] = + tx_msdu_info->htt.info.ext_tid & IEEE80211_QOS_TID; + +#ifdef NEVERDEFINED + if (wmmParam[ac].wmep_noackPolicy) + qos_cntl->i_qos[0] |= 1 << IEEE80211_QOS_ACKPOLICY_S; +#endif + + qos_cntl->i_qos[1] = 0; + wh->i_fc[0] |= IEEE80211_FC0_SUBTYPE_QOS; + /* count for qos field */ + new_hdsize = + hdsize + sizeof(struct ieee80211_qosframe) - + sizeof(struct ieee80211_frame); + + /*add ht control field if needed */ + + /* copy new hd to bd */ + qdf_mem_copy((void *) + htt_tx_desc_mpdu_header(tx_desc->htt_tx_desc, + new_hdsize), localbuf, + new_hdsize); + qdf_nbuf_pull_head(msdu, hdsize); + tx_msdu_info->htt.info.l3_hdr_offset = new_hdsize; + tx_desc->orig_l2_hdr_bytes = hdsize; + } + /* Set Protected Frame bit in MAC header */ + if (vdev->pdev->sw_pf_proc_enable + && tx_msdu_info->htt.action.do_encrypt) { + if (tx_desc->orig_l2_hdr_bytes) { + wh = (struct ieee80211_frame *) + htt_tx_desc_mpdu_header(tx_desc->htt_tx_desc, + tx_msdu_info->htt.info. + l3_hdr_offset); + } else { + if (A_OK != + ol_tx_copy_native_wifi_header(msdu, &hdsize, + localbuf)) + return A_ERROR; + wh = (struct ieee80211_frame *) + htt_tx_desc_mpdu_header(tx_desc->htt_tx_desc, + hdsize); + qdf_mem_copy((void *)wh, localbuf, hdsize); + qdf_nbuf_pull_head(msdu, hdsize); + tx_msdu_info->htt.info.l3_hdr_offset = hdsize; + tx_desc->orig_l2_hdr_bytes = hdsize; + } + wh->i_fc[1] |= IEEE80211_FC1_WEP; + } + return A_OK; +} + +static inline A_STATUS +ol_tx_encap_from_8023(struct ol_txrx_vdev_t *vdev, + struct ol_tx_desc_t *tx_desc, + qdf_nbuf_t msdu, struct ol_txrx_msdu_info_t *tx_msdu_info) +{ + uint8_t localbuf[sizeof(struct ieee80211_qosframe_htc_addr4) + + sizeof(struct llc_snap_hdr_t)]; + struct llc_snap_hdr_t *llc_hdr; + struct ethernet_hdr_t *eth_hdr; + struct ieee80211_frame *wh; + uint8_t hdsize, new_l2_hdsize, new_hdsize; + struct ieee80211_qoscntl *qos_cntl; + const uint8_t ethernet_II_llc_snap_header_prefix[] = { + 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; + struct ol_txrx_peer_t *peer; + uint16_t ether_type; + + if (tx_msdu_info->htt.info.frame_type != htt_frm_type_data) + return A_OK; + + /* + * for unicast,the peer should not be NULL. + * for multicast, the peer is AP. + */ + peer = tx_msdu_info->peer; + + eth_hdr = (struct ethernet_hdr_t *)qdf_nbuf_data(msdu); + hdsize = sizeof(struct ethernet_hdr_t); + wh = (struct ieee80211_frame *)localbuf; + wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_DATA; + *(uint16_t *) wh->i_dur = 0; + new_hdsize = 0; + + switch (vdev->opmode) { + case wlan_op_mode_ap: + /* DA , BSSID , SA */ + qdf_mem_copy(wh->i_addr1, eth_hdr->dest_addr, + IEEE80211_ADDR_LEN); + qdf_mem_copy(wh->i_addr2, &vdev->mac_addr.raw, + IEEE80211_ADDR_LEN); + qdf_mem_copy(wh->i_addr3, eth_hdr->src_addr, + IEEE80211_ADDR_LEN); + wh->i_fc[1] = IEEE80211_FC1_DIR_FROMDS; + new_hdsize = sizeof(struct ieee80211_frame); + break; + case wlan_op_mode_ibss: + /* DA, SA, BSSID */ + qdf_mem_copy(wh->i_addr1, eth_hdr->dest_addr, + IEEE80211_ADDR_LEN); + qdf_mem_copy(wh->i_addr2, eth_hdr->src_addr, + IEEE80211_ADDR_LEN); + /* need to check the bssid behaviour for IBSS vdev */ + qdf_mem_copy(wh->i_addr3, &vdev->mac_addr.raw, + IEEE80211_ADDR_LEN); + wh->i_fc[1] = IEEE80211_FC1_DIR_NODS; + new_hdsize = sizeof(struct ieee80211_frame); + break; + case wlan_op_mode_sta: + /* BSSID, SA , DA */ + qdf_mem_copy(wh->i_addr1, &peer->mac_addr.raw, + IEEE80211_ADDR_LEN); + qdf_mem_copy(wh->i_addr2, eth_hdr->src_addr, + IEEE80211_ADDR_LEN); + qdf_mem_copy(wh->i_addr3, eth_hdr->dest_addr, + IEEE80211_ADDR_LEN); + wh->i_fc[1] = IEEE80211_FC1_DIR_TODS; + new_hdsize = sizeof(struct ieee80211_frame); + break; + case wlan_op_mode_monitor: + default: + return A_ERROR; + } + /*add qos cntl */ + if (tx_msdu_info->htt.info.is_unicast && peer->qos_capable) { + qos_cntl = (struct ieee80211_qoscntl *)(localbuf + new_hdsize); + qos_cntl->i_qos[0] = + tx_msdu_info->htt.info.ext_tid & IEEE80211_QOS_TID; + wh->i_fc[0] |= IEEE80211_FC0_SUBTYPE_QOS; +#ifdef NEVERDEFINED + if (wmmParam[ac].wmep_noackPolicy) + qos_cntl->i_qos[0] |= 1 << IEEE80211_QOS_ACKPOLICY_S; +#endif + qos_cntl->i_qos[1] = 0; + new_hdsize += sizeof(struct ieee80211_qoscntl); + + /*add ht control field if needed */ + } + /* Set Protected Frame bit in MAC header */ + if (vdev->pdev->sw_pf_proc_enable + && tx_msdu_info->htt.action.do_encrypt) { + wh->i_fc[1] |= IEEE80211_FC1_WEP; + } + new_l2_hdsize = new_hdsize; + /* add llc snap if needed */ + if (vdev->pdev->sw_tx_llc_proc_enable) { + llc_hdr = (struct llc_snap_hdr_t *)(localbuf + new_hdsize); + ether_type = + (eth_hdr->ethertype[0] << 8) | (eth_hdr->ethertype[1]); + if (ether_type >= IEEE8023_MAX_LEN) { + qdf_mem_copy(llc_hdr, + ethernet_II_llc_snap_header_prefix, + sizeof + (ethernet_II_llc_snap_header_prefix)); + if (ether_type == ETHERTYPE_AARP + || ether_type == ETHERTYPE_IPX) { + llc_hdr->org_code[2] = BTEP_SNAP_ORGCODE_2; + /* 0xf8; bridge tunnel header */ + } + llc_hdr->ethertype[0] = eth_hdr->ethertype[0]; + llc_hdr->ethertype[1] = eth_hdr->ethertype[1]; + new_hdsize += sizeof(struct llc_snap_hdr_t); + } else { + /*llc ready, and it's in payload pdu, + do we need to move to BD pdu? */ + } + } + qdf_mem_copy((void *) + htt_tx_desc_mpdu_header(tx_desc->htt_tx_desc, + new_l2_hdsize), localbuf, + new_hdsize); + qdf_nbuf_pull_head(msdu, hdsize); + tx_msdu_info->htt.info.l3_hdr_offset = new_l2_hdsize; + tx_desc->orig_l2_hdr_bytes = hdsize; + return A_OK; +} + +A_STATUS +ol_tx_encap(struct ol_txrx_vdev_t *vdev, + struct ol_tx_desc_t *tx_desc, + qdf_nbuf_t msdu, struct ol_txrx_msdu_info_t *msdu_info) +{ + struct ol_txrx_pdev_t *pdev = vdev->pdev; + + if (pdev->frame_format == wlan_frm_fmt_native_wifi) { + return ol_tx_encap_from_native_wifi(vdev, tx_desc, msdu, + msdu_info); + } else if (pdev->frame_format == wlan_frm_fmt_802_3) { + return ol_tx_encap_from_8023(vdev, tx_desc, msdu, msdu_info); + } else { + /* todo for other types */ + return A_ERROR; + } +} + +static inline void +ol_rx_decap_to_native_wifi(struct ol_txrx_vdev_t *vdev, + qdf_nbuf_t msdu, + struct ol_rx_decap_info_t *info, + struct ethernet_hdr_t *ethr_hdr) +{ + struct ieee80211_frame_addr4 *wh; + uint16_t hdsize; + + /* + * we need to remove Qos control field and HT control. + * MSFT: http://msdn.microsoft.com/en-us/library/windows/ + * hardware/ff552608(v=vs.85).aspx + */ + wh = (struct ieee80211_frame_addr4 *)info->hdr; + if ((wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) == + IEEE80211_FC1_DIR_DSTODS) + hdsize = sizeof(struct ieee80211_frame_addr4); + else + hdsize = sizeof(struct ieee80211_frame); + + wh = (struct ieee80211_frame_addr4 *)qdf_nbuf_push_head(msdu, hdsize); + TXRX_ASSERT2(wh != NULL); + TXRX_ASSERT2(hdsize <= info->hdr_len); + qdf_mem_copy((uint8_t *) wh, info->hdr, hdsize); + + /* amsdu subfrm handling if ethr_hdr is not NULL */ + if (ethr_hdr != NULL) { + switch (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) { + case IEEE80211_FC1_DIR_NODS: + qdf_mem_copy(wh->i_addr1, ethr_hdr->dest_addr, + ETHERNET_ADDR_LEN); + qdf_mem_copy(wh->i_addr2, ethr_hdr->src_addr, + ETHERNET_ADDR_LEN); + break; + case IEEE80211_FC1_DIR_TODS: + qdf_mem_copy(wh->i_addr2, ethr_hdr->src_addr, + ETHERNET_ADDR_LEN); + qdf_mem_copy(wh->i_addr3, ethr_hdr->dest_addr, + ETHERNET_ADDR_LEN); + break; + case IEEE80211_FC1_DIR_FROMDS: + qdf_mem_copy(wh->i_addr1, ethr_hdr->dest_addr, + ETHERNET_ADDR_LEN); + qdf_mem_copy(wh->i_addr3, ethr_hdr->src_addr, + ETHERNET_ADDR_LEN); + break; + case IEEE80211_FC1_DIR_DSTODS: + qdf_mem_copy(wh->i_addr3, ethr_hdr->dest_addr, + ETHERNET_ADDR_LEN); + qdf_mem_copy(wh->i_addr4, ethr_hdr->src_addr, + ETHERNET_ADDR_LEN); + break; + } + } + if (IEEE80211_QOS_HAS_SEQ(wh)) { + if (wh->i_fc[1] & IEEE80211_FC1_ORDER) + wh->i_fc[1] &= ~IEEE80211_FC1_ORDER; + wh->i_fc[0] &= ~IEEE80211_FC0_SUBTYPE_QOS; + } +} + +static inline void +ol_rx_decap_to_8023(struct ol_txrx_vdev_t *vdev, + qdf_nbuf_t msdu, + struct ol_rx_decap_info_t *info, + struct ethernet_hdr_t *ethr_hdr) +{ + struct llc_snap_hdr_t *llc_hdr; + uint16_t ether_type; + uint16_t l2_hdr_space; + struct ieee80211_frame_addr4 *wh; + uint8_t local_buf[ETHERNET_HDR_LEN]; + uint8_t *buf; + + /* + * populate Ethernet header, + * if ethr_hdr is null, rx frame is 802.11 format(HW ft disabled) + * if ethr_hdr is not null, rx frame is "subfrm of amsdu". + */ + buf = (uint8_t *) qdf_nbuf_data(msdu); + llc_hdr = (struct llc_snap_hdr_t *)buf; + ether_type = (llc_hdr->ethertype[0] << 8) | llc_hdr->ethertype[1]; + /* do llc remove if needed */ + l2_hdr_space = 0; + if (IS_SNAP(llc_hdr)) { + if (IS_BTEP(llc_hdr)) { + /* remove llc */ + l2_hdr_space += sizeof(struct llc_snap_hdr_t); + llc_hdr = NULL; + } else if (IS_RFC1042(llc_hdr)) { + if (!(ether_type == ETHERTYPE_AARP || + ether_type == ETHERTYPE_IPX)) { + /* remove llc */ + l2_hdr_space += sizeof(struct llc_snap_hdr_t); + llc_hdr = NULL; + } + } + } + if (l2_hdr_space > ETHERNET_HDR_LEN) + buf = qdf_nbuf_pull_head(msdu, l2_hdr_space - ETHERNET_HDR_LEN); + else if (l2_hdr_space < ETHERNET_HDR_LEN) + buf = qdf_nbuf_push_head(msdu, ETHERNET_HDR_LEN - l2_hdr_space); + + /* normal msdu(non-subfrm of A-MSDU) if ethr_hdr is null */ + if (ethr_hdr == NULL) { + /* mpdu hdr should be present in info, + re-create ethr_hdr based on mpdu hdr */ + TXRX_ASSERT2(info->hdr_len != 0); + wh = (struct ieee80211_frame_addr4 *)info->hdr; + ethr_hdr = (struct ethernet_hdr_t *)local_buf; + switch (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) { + case IEEE80211_FC1_DIR_NODS: + qdf_mem_copy(ethr_hdr->dest_addr, wh->i_addr1, + ETHERNET_ADDR_LEN); + qdf_mem_copy(ethr_hdr->src_addr, wh->i_addr2, + ETHERNET_ADDR_LEN); + break; + case IEEE80211_FC1_DIR_TODS: + qdf_mem_copy(ethr_hdr->dest_addr, wh->i_addr3, + ETHERNET_ADDR_LEN); + qdf_mem_copy(ethr_hdr->src_addr, wh->i_addr2, + ETHERNET_ADDR_LEN); + break; + case IEEE80211_FC1_DIR_FROMDS: + qdf_mem_copy(ethr_hdr->dest_addr, wh->i_addr1, + ETHERNET_ADDR_LEN); + qdf_mem_copy(ethr_hdr->src_addr, wh->i_addr3, + ETHERNET_ADDR_LEN); + break; + case IEEE80211_FC1_DIR_DSTODS: + qdf_mem_copy(ethr_hdr->dest_addr, wh->i_addr3, + ETHERNET_ADDR_LEN); + qdf_mem_copy(ethr_hdr->src_addr, wh->i_addr4, + ETHERNET_ADDR_LEN); + break; + } + } + if (llc_hdr == NULL) { + ethr_hdr->ethertype[0] = (ether_type >> 8) & 0xff; + ethr_hdr->ethertype[1] = (ether_type) & 0xff; + } else { + uint32_t pktlen = + qdf_nbuf_len(msdu) - sizeof(ethr_hdr->ethertype); + TXRX_ASSERT2(pktlen <= ETHERNET_MTU); + ether_type = (uint16_t) pktlen; + ether_type = qdf_nbuf_len(msdu) - sizeof(struct ethernet_hdr_t); + ethr_hdr->ethertype[0] = (ether_type >> 8) & 0xff; + ethr_hdr->ethertype[1] = (ether_type) & 0xff; + } + qdf_mem_copy(buf, ethr_hdr, ETHERNET_HDR_LEN); +} + +static inline A_STATUS +ol_rx_decap_subfrm_amsdu(struct ol_txrx_vdev_t *vdev, + qdf_nbuf_t msdu, struct ol_rx_decap_info_t *info) +{ + struct ol_txrx_pdev_t *pdev = vdev->pdev; + uint8_t *subfrm_hdr; + uint8_t localbuf[ETHERNET_HDR_LEN]; + struct ethernet_hdr_t *ether_hdr = (struct ethernet_hdr_t *)localbuf; + + subfrm_hdr = (uint8_t *) qdf_nbuf_data(msdu); + if (pdev->frame_format == wlan_frm_fmt_native_wifi) { + /* decap to native wifi */ + qdf_mem_copy(ether_hdr, subfrm_hdr, ETHERNET_HDR_LEN); + qdf_nbuf_pull_head(msdu, ETHERNET_HDR_LEN); + ol_rx_decap_to_native_wifi(vdev, msdu, info, ether_hdr); + } else if (pdev->frame_format == wlan_frm_fmt_802_3) { + if (pdev->sw_rx_llc_proc_enable) { + /* remove llc snap hdr if it's necessary according to + * 802.11 table P-3 + */ + qdf_mem_copy(ether_hdr, subfrm_hdr, ETHERNET_HDR_LEN); + qdf_nbuf_pull_head(msdu, ETHERNET_HDR_LEN); + ol_rx_decap_to_8023(vdev, msdu, info, ether_hdr); + } else { + /* subfrm of A-MSDU is already in 802.3 format. + * if target HW or FW has done LLC rmv process, + * we do nothing here. + */ + } + } else { + /* todo for othertype */ + } + return A_OK; + +} + +static inline A_STATUS +ol_rx_decap_msdu(struct ol_txrx_vdev_t *vdev, + qdf_nbuf_t msdu, struct ol_rx_decap_info_t *info) +{ + struct ol_txrx_pdev_t *pdev = vdev->pdev; + struct ieee80211_frame *wh; + wh = (struct ieee80211_frame *)qdf_nbuf_data(msdu); + + if (pdev->frame_format == wlan_frm_fmt_native_wifi) { + /* Decap to native wifi because according to MSFT( + * MSFT: http://msdn.microsoft.com/en-us/library/windows/ + * hardware/ff552608(v=vs.85).aspx), + * we need to remove Qos and HTC field before indicate to OS. + */ + if (IEEE80211_QOS_HAS_SEQ(wh)) { + info->hdr_len = ol_txrx_ieee80211_hdrsize(wh); + TXRX_ASSERT2(info->hdr_len <= sizeof(info->hdr)); + qdf_mem_copy(info->hdr, /* use info->hdr as temp buf. */ + wh, info->hdr_len); + qdf_nbuf_pull_head(msdu, info->hdr_len); + ol_rx_decap_to_native_wifi(vdev, msdu, info, NULL); + /* 802.11 hdr^ eth_hdr^ */ + } + } else if (pdev->frame_format == wlan_frm_fmt_802_3) { + if (pdev->sw_rx_llc_proc_enable) { + info->hdr_len = ol_txrx_ieee80211_hdrsize(wh); + TXRX_ASSERT2(info->hdr_len <= sizeof(info->hdr)); + qdf_mem_copy(info->hdr, /* use info->hdr as temp buf. */ + wh, info->hdr_len); + qdf_nbuf_pull_head(msdu, info->hdr_len); + /* remove llc snap hdr if it's necessary according to + * 802.11 table P-3 + */ + ol_rx_decap_to_8023(vdev, msdu, info, /* 802.11 hdr */ + NULL); /* ethernet hdr */ + } else { + /* Subfrm of A-MSDU is already in 802.3 format. + * And if target HW or FW has done LLC rmv process ( + * sw_rx_lc_proc_enable == 0), we do nothing here. + */ + } + } else { + /* todo for othertype */ + } + return A_OK; + +} + +A_STATUS +ol_rx_decap(struct ol_txrx_vdev_t *vdev, + struct ol_txrx_peer_t *peer, + qdf_nbuf_t msdu, struct ol_rx_decap_info_t *info) +{ + A_STATUS status; + uint8_t *mpdu_hdr; + + if (!info->is_subfrm) { + if (info->is_msdu_cmpl_mpdu && !info->is_first_subfrm) { + /* It's normal MSDU. */ + } else { + /* It's a first subfrm of A-MSDU and + may also be the last subfrm of A-MSDU */ + info->is_subfrm = 1; + info->hdr_len = 0; + if (vdev->pdev->sw_subfrm_hdr_recovery_enable) { + /* we save the first subfrm mpdu hdr for + * subsequent subfrm 802.11 header recovery + * in certain chip(such as Riva). + */ + mpdu_hdr = qdf_nbuf_data(msdu); + info->hdr_len = + ol_txrx_ieee80211_hdrsize(mpdu_hdr); + TXRX_ASSERT2(info->hdr_len <= + sizeof(info->hdr)); + qdf_mem_copy(info->hdr, mpdu_hdr, + info->hdr_len); + qdf_nbuf_pull_head(msdu, info->hdr_len); + } + } + } + + if (info->is_subfrm && vdev->pdev->sw_subfrm_hdr_recovery_enable) { + /* + * This case is enabled for some HWs (such as Riva). The HW + * de-aggregate doesn't have capability to generate 802.11 + * header for non-first subframe of A-MSDU. That means sw needs + * to cache the first subfrm mpdu header to generate the + * subsequent subfrm's 802.11 header. + */ + TXRX_ASSERT2(info->hdr_len != 0); + status = ol_rx_decap_subfrm_amsdu(vdev, msdu, info); + } else { + status = ol_rx_decap_msdu(vdev, msdu, info); + } + + if (info->is_msdu_cmpl_mpdu) + info->is_subfrm = info->is_first_subfrm = info->hdr_len = 0; + + return status; +} +#endif diff --git a/drivers/staging/qcacld-3.0/core/dp/txrx/ol_txrx_encap.h b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_txrx_encap.h new file mode 100644 index 0000000000000000000000000000000000000000..932bdd342a453f04bd4f6201b9c210df1f1dc600 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_txrx_encap.h @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2012, 2014-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * @file ol_txrx_encap.h + * @brief definitions for txrx encap/decap function and struct + */ +#ifndef _OL_TXRX_ENCAP__H_ +#define _OL_TXRX_ENCAP__H_ + +#ifdef QCA_SUPPORT_SW_TXRX_ENCAP + +#include /* qdf_nbuf_t */ +#include /* ieee80211_qosframe_htc_addr4 */ +#include /* ol_txrx_vdev_t, etc. */ + +/** + * @brief Encap outgoing frm from OS dependent format to Target + * acceptable frm format + * @details + * For native wifi format, the function will add Qos control field + * based on peer's QOS capbabilities . + * For 802.3 format, the function will transform to 802.11 format + * with or without QOS control field based on peer's QOS capabilites. + * @param vdev - handle to vdev object + * @param tx_desc - tx desc struct,some fields will be updated. + * @param msdu - qdf_nbuf_t + * @param msdu_info - informations from tx classification. + * @return + * A_OK: encap operation sucessful + * other: operation failed,the msdu need be dropped. + */ +A_STATUS +ol_tx_encap(struct ol_txrx_vdev_t *vdev, + struct ol_tx_desc_t *tx_desc, + qdf_nbuf_t msdu, struct ol_txrx_msdu_info_t *msdu_info); + +struct ol_rx_decap_info_t { + uint8_t hdr[sizeof(struct ieee80211_qosframe_htc_addr4)]; + int hdr_len; + uint8_t is_subfrm:1, is_first_subfrm:1, is_msdu_cmpl_mpdu:1; +}; + +/** + * @brief decap incoming frm from Target to Host OS + * acceptable frm format + * @details + * For native wifi format, the function will remove Qos control field + * and HT control field if any. + * For 802.3 format, the function will will do llc snap header process + * if Target haven't done that. + * @param vdev - handle to vdev object + * @param peer - the peer object. + * @param msdu - qdf_nbuf_t + * @param info - ol_rx_decap_info_t: context info for decap + * @return + * A_OK: decap operation sucessful + * other: operation failed,the msdu need be dropped. + */ +A_STATUS +ol_rx_decap(struct ol_txrx_vdev_t *vdev, + struct ol_txrx_peer_t *peer, + qdf_nbuf_t msdu, struct ol_rx_decap_info_t *info); + +static inline A_STATUS +OL_TX_ENCAP(struct ol_txrx_vdev_t *vdev, + struct ol_tx_desc_t *tx_desc, + qdf_nbuf_t msdu, struct ol_txrx_msdu_info_t *msdu_info) +{ + if (vdev->pdev->sw_tx_encap) + return ol_tx_encap(vdev, tx_desc, msdu, msdu_info); + return A_OK; +} + +static inline A_STATUS +OL_RX_DECAP(struct ol_txrx_vdev_t *vdev, + struct ol_txrx_peer_t *peer, + qdf_nbuf_t msdu, struct ol_rx_decap_info_t *info) +{ + if (vdev->pdev->sw_rx_decap) + return ol_rx_decap(vdev, peer, msdu, info); + return A_OK; +} + +#define OL_TX_RESTORE_HDR(__tx_desc, __msdu) \ + do { \ + if (__tx_desc->orig_l2_hdr_bytes != 0) \ + qdf_nbuf_push_head(__msdu, \ + __tx_desc->orig_l2_hdr_bytes); \ + } while (0) +#else +#define OL_TX_ENCAP(vdev, tx_desc, msdu, msdu_info) A_OK +#define OL_RX_DECAP(vdev, peer, msdu, info) A_OK +#define OL_TX_RESTORE_HDR(__tx_desc, __msdu) +#endif +#endif /* _OL_TXRX_ENCAP__H_ */ diff --git a/drivers/staging/qcacld-3.0/core/dp/txrx/ol_txrx_event.c b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_txrx_event.c new file mode 100644 index 0000000000000000000000000000000000000000..ab85532715fe994f718841dfe6ce2fe453d7fc3f --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_txrx_event.c @@ -0,0 +1,228 @@ +/* + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#include "ol_txrx_types.h" + +#ifdef WDI_EVENT_ENABLE + +static inline wdi_event_subscribe *wdi_event_next_sub(wdi_event_subscribe * + wdi_sub) +{ + if (!wdi_sub) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "Invalid subscriber in %s\n", __func__); + return NULL; + } + return wdi_sub->priv.next; +} + +static inline void +wdi_event_del_subs(wdi_event_subscribe *wdi_sub, int event_index) +{ + wdi_event_notify deallocate_sub; + while (wdi_sub) { + wdi_event_subscribe *next = wdi_event_next_sub(wdi_sub); + /* + * Context is NULL for static allocation of subs + * In dynamic allocation case notify the user + */ + if (wdi_sub->context) { + deallocate_sub = wdi_sub->context; + deallocate_sub(WDI_EVENT_SUB_DEALLOCATE, + WDI_EVENT_BASE + event_index); + } + wdi_sub = next; + } + /* qdf_mem_free(wdi_sub); */ +} + +static inline void +wdi_event_iter_sub(struct ol_txrx_pdev_t *pdev, + uint32_t event_index, + wdi_event_subscribe *wdi_sub, void *data) +{ + enum WDI_EVENT event = event_index + WDI_EVENT_BASE; + + if (wdi_sub) { + do { + wdi_sub->callback(pdev, event, data); + } while ((wdi_sub = wdi_event_next_sub(wdi_sub))); + } +} + +void +wdi_event_handler(enum WDI_EVENT event, + struct ol_txrx_pdev_t *txrx_pdev, void *data) +{ + uint32_t event_index; + wdi_event_subscribe *wdi_sub; + /* + * Input validation + */ + if (!event) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "Invalid WDI event in %s\n", __func__); + return; + } + if (!txrx_pdev) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "Invalid pdev in WDI event handler\n"); + return; + } + /* + * There can be NULL data, so no validation for the data + * Subscribers must do the sanity based on the requirements + */ + event_index = event - WDI_EVENT_BASE; + + wdi_sub = txrx_pdev->wdi_event_list[event_index]; + + /* Find the subscriber */ + wdi_event_iter_sub(txrx_pdev, event_index, wdi_sub, data); +} + +A_STATUS +wdi_event_sub(struct ol_txrx_pdev_t *txrx_pdev, + wdi_event_subscribe *event_cb_sub, enum WDI_EVENT event) +{ + uint32_t event_index; + wdi_event_subscribe *wdi_sub; + /* Input validation */ + if (!txrx_pdev) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "Invalid txrx_pdev in %s", __func__); + return A_ERROR; + } + if (!event_cb_sub) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "Invalid callback in %s", __func__); + return A_ERROR; + } + if ((!event) || (event >= WDI_EVENT_LAST) || (event < WDI_EVENT_BASE)) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "Invalid event in %s", __func__); + return A_ERROR; + } + /* Input validation */ + event_index = event - WDI_EVENT_BASE; + + wdi_sub = txrx_pdev->wdi_event_list[event_index]; + /* + * Check if it is the first subscriber of the event + */ + if (!wdi_sub) { + wdi_sub = event_cb_sub; + wdi_sub->priv.next = NULL; + wdi_sub->priv.prev = NULL; + txrx_pdev->wdi_event_list[event_index] = wdi_sub; + return A_OK; + } + event_cb_sub->priv.next = wdi_sub; + event_cb_sub->priv.prev = NULL; + wdi_sub->priv.prev = event_cb_sub; + txrx_pdev->wdi_event_list[event_index] = event_cb_sub; + + return A_OK; +} + +A_STATUS +wdi_event_unsub(struct ol_txrx_pdev_t *txrx_pdev, + wdi_event_subscribe *event_cb_sub, enum WDI_EVENT event) +{ + uint32_t event_index = event - WDI_EVENT_BASE; + + /* Input validation */ + if (!event_cb_sub) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "Invalid callback in %s", __func__); + return A_ERROR; + } + if (!event_cb_sub->priv.prev) { + txrx_pdev->wdi_event_list[event_index] = + event_cb_sub->priv.next; + } else { + event_cb_sub->priv.prev->priv.next = event_cb_sub->priv.next; + } + if (event_cb_sub->priv.next) + event_cb_sub->priv.next->priv.prev = event_cb_sub->priv.prev; + + /* qdf_mem_free(event_cb_sub); */ + + return A_OK; +} + +A_STATUS wdi_event_attach(struct ol_txrx_pdev_t *txrx_pdev) +{ + /* Input validation */ + if (!txrx_pdev) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "Invalid device in %s\nWDI event attach failed", + __func__); + return A_ERROR; + } + /* Separate subscriber list for each event */ + txrx_pdev->wdi_event_list = (wdi_event_subscribe **) + qdf_mem_malloc( + sizeof(wdi_event_subscribe *) * + WDI_NUM_EVENTS); + if (!txrx_pdev->wdi_event_list) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "Insufficient memory for the WDI event lists\n"); + return A_NO_MEMORY; + } + return A_OK; +} + +A_STATUS wdi_event_detach(struct ol_txrx_pdev_t *txrx_pdev) +{ + int i; + wdi_event_subscribe *wdi_sub; + if (!txrx_pdev) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "Invalid device in %s\nWDI detach failed", + __func__); + return A_ERROR; + } + if (!txrx_pdev->wdi_event_list) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "%s: wdi_event_list is NULL", __func__); + return A_ERROR; + } + + for (i = 0; i < WDI_NUM_EVENTS; i++) { + wdi_sub = txrx_pdev->wdi_event_list[i]; + if (wdi_sub) { + /* Delete all the subscribers */ + wdi_event_del_subs(wdi_sub, i); + } + } + /* txrx_pdev->wdi_event_list would be non-null */ + qdf_mem_free(txrx_pdev->wdi_event_list); + return A_OK; +} + +#endif /* WDI_EVENT_ENABLE */ diff --git a/drivers/staging/qcacld-3.0/core/dp/txrx/ol_txrx_flow_control.c b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_txrx_flow_control.c new file mode 100644 index 0000000000000000000000000000000000000000..f3e6ea3ec0ab7a010d746893a53e0fd55f40d65a --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_txrx_flow_control.c @@ -0,0 +1,807 @@ +/* + * Copyright (c) 2015-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* OS abstraction libraries */ +#include /* qdf_nbuf_t, etc. */ +#include /* qdf_atomic_read, etc. */ +#include /* qdf_unlikely */ + +/* APIs for other modules */ +#include /* HTT_TX_EXT_TID_MGMT */ +#include /* htt_tx_desc_tid */ + +/* internal header files relevant for all systems */ +#include /* TXRX_ASSERT1 */ +#include /* ol_tx_desc */ +#include /* ol_tx_send */ +#include /* ol_txrx_get_vdev_from_vdev_id */ + +/* internal header files relevant only for HL systems */ +#include /* ol_tx_enqueue */ + +/* internal header files relevant only for specific systems (Pronto) */ +#include /* OL_TX_ENCAP, etc */ +#include +#include + +#define INVALID_FLOW_ID 0xFF +#define MAX_INVALID_BIN 3 + +#ifdef QCA_LL_TX_FLOW_GLOBAL_MGMT_POOL +#define TX_FLOW_MGMT_POOL_ID 0xEF +#define TX_FLOW_MGMT_POOL_SIZE 32 + +/** + * ol_tx_register_global_mgmt_pool() - register global pool for mgmt packets + * @pdev: pdev handler + * + * Return: none + */ +static void +ol_tx_register_global_mgmt_pool(struct ol_txrx_pdev_t *pdev) +{ + pdev->mgmt_pool = ol_tx_create_flow_pool(TX_FLOW_MGMT_POOL_ID, + TX_FLOW_MGMT_POOL_SIZE); + if (!pdev->mgmt_pool) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "Management pool creation failed\n"); + } + return; +} + +/** + * ol_tx_deregister_global_mgmt_pool() - Deregister global pool for mgmt packets + * @pdev: pdev handler + * + * Return: none + */ +static void +ol_tx_deregister_global_mgmt_pool(struct ol_txrx_pdev_t *pdev) +{ + ol_tx_dec_pool_ref(pdev->mgmt_pool, false); + return; +} +#else +static inline void +ol_tx_register_global_mgmt_pool(struct ol_txrx_pdev_t *pdev) +{ + return; +} +static inline void +ol_tx_deregister_global_mgmt_pool(struct ol_txrx_pdev_t *pdev) +{ + return; +} +#endif + +/** + * ol_tx_register_flow_control() - Register fw based tx flow control + * @pdev: pdev handle + * + * Return: none + */ +void ol_tx_register_flow_control(struct ol_txrx_pdev_t *pdev) +{ + qdf_spinlock_create(&pdev->tx_desc.flow_pool_list_lock); + TAILQ_INIT(&pdev->tx_desc.flow_pool_list); + + if (!ol_tx_get_is_mgmt_over_wmi_enabled()) + ol_tx_register_global_mgmt_pool(pdev); +} + +/** + * ol_tx_deregister_flow_control() - Deregister fw based tx flow control + * @pdev: pdev handle + * + * Return: none + */ +void ol_tx_deregister_flow_control(struct ol_txrx_pdev_t *pdev) +{ + int i = 0; + struct ol_tx_flow_pool_t *pool = NULL; + + if (!ol_tx_get_is_mgmt_over_wmi_enabled()) + ol_tx_deregister_global_mgmt_pool(pdev); + + qdf_spin_lock_bh(&pdev->tx_desc.flow_pool_list_lock); + while (!TAILQ_EMPTY(&pdev->tx_desc.flow_pool_list)) { + pool = TAILQ_FIRST(&pdev->tx_desc.flow_pool_list); + if (!pool) + break; + qdf_spin_unlock_bh(&pdev->tx_desc.flow_pool_list_lock); + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "flow pool list is not empty %d!!!\n", i++); + if (i == 1) + ol_tx_dump_flow_pool_info(); + ol_tx_dec_pool_ref(pool, true); + qdf_spin_lock_bh(&pdev->tx_desc.flow_pool_list_lock); + } + qdf_spin_unlock_bh(&pdev->tx_desc.flow_pool_list_lock); + qdf_spinlock_destroy(&pdev->tx_desc.flow_pool_list_lock); +} + +/** + * ol_tx_delete_flow_pool() - delete flow pool + * @pool: flow pool pointer + * @force: free pool forcefully + * + * Delete flow_pool if all tx descriptors are available. + * Otherwise put it in FLOW_POOL_INVALID state. + * If force is set then pull all available descriptors to + * global pool. + * + * Return: 0 for success or error + */ +static int ol_tx_delete_flow_pool(struct ol_tx_flow_pool_t *pool, bool force) +{ + struct ol_txrx_pdev_t *pdev = cds_get_context(QDF_MODULE_ID_TXRX); + uint16_t i, size; + union ol_tx_desc_list_elem_t *temp_list = NULL; + struct ol_tx_desc_t *tx_desc = NULL; + + if (!pool) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "%s: pool is NULL\n", __func__); + QDF_ASSERT(0); + return -ENOMEM; + } + if (!pdev) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "%s: pdev is NULL\n", __func__); + QDF_ASSERT(0); + return -ENOMEM; + } + + qdf_spin_lock_bh(&pool->flow_pool_lock); + if (pool->avail_desc == pool->flow_pool_size || force == true) + pool->status = FLOW_POOL_INACTIVE; + else + pool->status = FLOW_POOL_INVALID; + + /* Take all free descriptors and put it in temp_list */ + temp_list = pool->freelist; + size = pool->avail_desc; + pool->freelist = NULL; + pool->avail_desc = 0; + + if (pool->status == FLOW_POOL_INACTIVE) { + qdf_spin_unlock_bh(&pool->flow_pool_lock); + /* Free flow_pool */ + qdf_spinlock_destroy(&pool->flow_pool_lock); + qdf_mem_free(pool); + } else { /* FLOW_POOL_INVALID case*/ + pool->flow_pool_size -= size; + pool->flow_pool_id = INVALID_FLOW_ID; + qdf_spin_unlock_bh(&pool->flow_pool_lock); + ol_tx_inc_pool_ref(pool); + + pdev->tx_desc.num_invalid_bin++; + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "%s: invalid pool created %d\n", + __func__, pdev->tx_desc.num_invalid_bin); + if (pdev->tx_desc.num_invalid_bin > MAX_INVALID_BIN) + ASSERT(0); + + qdf_spin_lock_bh(&pdev->tx_desc.flow_pool_list_lock); + TAILQ_INSERT_TAIL(&pdev->tx_desc.flow_pool_list, pool, + flow_pool_list_elem); + qdf_spin_unlock_bh(&pdev->tx_desc.flow_pool_list_lock); + } + + /* put free descriptors to global pool */ + qdf_spin_lock_bh(&pdev->tx_mutex); + for (i = 0; i < size; i++) { + tx_desc = &temp_list->tx_desc; + temp_list = temp_list->next; + + ol_tx_put_desc_global_pool(pdev, tx_desc); + } + qdf_spin_unlock_bh(&pdev->tx_mutex); + + return 0; +} + +QDF_STATUS ol_tx_inc_pool_ref(struct ol_tx_flow_pool_t *pool) +{ + if (!pool) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "%s: flow pool is NULL", __func__); + return QDF_STATUS_E_INVAL; + } + + qdf_spin_lock_bh(&pool->flow_pool_lock); + qdf_atomic_inc(&pool->ref_cnt); + qdf_spin_unlock_bh(&pool->flow_pool_lock); + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "%s: pool %p, ref_cnt %x", __func__, + pool, qdf_atomic_read(&pool->ref_cnt)); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS ol_tx_dec_pool_ref(struct ol_tx_flow_pool_t *pool, bool force) +{ + struct ol_txrx_pdev_t *pdev = cds_get_context(QDF_MODULE_ID_TXRX); + + if (!pool) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "%s: flow pool is NULL", __func__); + QDF_ASSERT(0); + return QDF_STATUS_E_INVAL; + } + + if (!pdev) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "%s: pdev is NULL", __func__); + QDF_ASSERT(0); + return QDF_STATUS_E_INVAL; + } + + qdf_spin_lock_bh(&pdev->tx_desc.flow_pool_list_lock); + qdf_spin_lock_bh(&pool->flow_pool_lock); + if (qdf_atomic_dec_and_test(&pool->ref_cnt)) { + qdf_spin_unlock_bh(&pool->flow_pool_lock); + TAILQ_REMOVE(&pdev->tx_desc.flow_pool_list, pool, + flow_pool_list_elem); + qdf_spin_unlock_bh(&pdev->tx_desc.flow_pool_list_lock); + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "%s: Deleting pool %p", __func__, pool); + ol_tx_delete_flow_pool(pool, force); + } else { + qdf_spin_unlock_bh(&pool->flow_pool_lock); + qdf_spin_unlock_bh(&pdev->tx_desc.flow_pool_list_lock); + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "%s: pool %p, ref_cnt %x", + __func__, pool, qdf_atomic_read(&pool->ref_cnt)); + } + + return QDF_STATUS_SUCCESS; +} + +/** + * ol_tx_dump_flow_pool_info() - dump global_pool and flow_pool info + * + * Return: none + */ +void ol_tx_dump_flow_pool_info(void) +{ + struct ol_txrx_pdev_t *pdev = cds_get_context(QDF_MODULE_ID_TXRX); + struct ol_tx_flow_pool_t *pool = NULL, *pool_prev = NULL; + struct ol_tx_flow_pool_t tmp_pool; + + + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, "Global Pool"); + if (!pdev) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, "ERROR: pdev NULL"); + QDF_ASSERT(0); /* traceback */ + return; + } + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, "Total %d :: Available %d", + pdev->tx_desc.pool_size, pdev->tx_desc.num_free); + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, "Invalid flow_pool %d", + pdev->tx_desc.num_invalid_bin); + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, "No of pool map received %d", + pdev->pool_stats.pool_map_count); + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, "No of pool unmap received %d", + pdev->pool_stats.pool_unmap_count); + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "Pkt dropped due to unavailablity of pool %d", + pdev->pool_stats.pkt_drop_no_pool); + + /* + * Nested spin lock. + * Always take in below order. + * flow_pool_list_lock -> flow_pool_lock + */ + qdf_spin_lock_bh(&pdev->tx_desc.flow_pool_list_lock); + TAILQ_FOREACH(pool, &pdev->tx_desc.flow_pool_list, + flow_pool_list_elem) { + ol_tx_inc_pool_ref(pool); + qdf_spin_lock_bh(&pool->flow_pool_lock); + qdf_mem_copy(&tmp_pool, pool, sizeof(tmp_pool)); + qdf_spin_unlock_bh(&pool->flow_pool_lock); + qdf_spin_unlock_bh(&pdev->tx_desc.flow_pool_list_lock); + + if (pool_prev) + ol_tx_dec_pool_ref(pool_prev, false); + + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, "\n"); + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "Flow_pool_id %d :: status %d", + tmp_pool.flow_pool_id, tmp_pool.status); + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "Total %d :: Available %d :: Deficient %d", + tmp_pool.flow_pool_size, tmp_pool.avail_desc, + tmp_pool.deficient_desc); + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "Start threshold %d :: Stop threshold %d", + tmp_pool.start_th, tmp_pool.stop_th); + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "Member flow_id %d :: flow_type %d", + tmp_pool.member_flow_id, tmp_pool.flow_type); + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "Pkt dropped due to unavailablity of descriptors %d", + tmp_pool.pkt_drop_no_desc); + + pool_prev = pool; + qdf_spin_lock_bh(&pdev->tx_desc.flow_pool_list_lock); + } + qdf_spin_unlock_bh(&pdev->tx_desc.flow_pool_list_lock); + + /* decrement ref count for last pool in list */ + if (pool_prev) + ol_tx_dec_pool_ref(pool_prev, false); + + return; +} + +/** + * ol_tx_clear_flow_pool_stats() - clear flow pool statistics + * + * Return: none + */ +void ol_tx_clear_flow_pool_stats(void) +{ + struct ol_txrx_pdev_t *pdev = cds_get_context(QDF_MODULE_ID_TXRX); + + if (!pdev) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, "%s: pdev is null\n", + __func__); + return; + } + qdf_mem_zero(&pdev->pool_stats, sizeof(pdev->pool_stats)); +} + +/** + * ol_tx_move_desc_n() - Move n descriptors from src_pool to dst_pool. + * @src_pool: source pool + * @dst_pool: destination pool + * @desc_move_count: descriptor move count + * + * Return: actual descriptors moved + */ +static int ol_tx_move_desc_n(struct ol_tx_flow_pool_t *src_pool, + struct ol_tx_flow_pool_t *dst_pool, + int desc_move_count) +{ + uint16_t count = 0, i; + struct ol_tx_desc_t *tx_desc; + union ol_tx_desc_list_elem_t *temp_list = NULL; + + /* Take descriptors from source pool and put it in temp_list */ + qdf_spin_lock_bh(&src_pool->flow_pool_lock); + for (i = 0; i < desc_move_count; i++) { + tx_desc = ol_tx_get_desc_flow_pool(src_pool); + ((union ol_tx_desc_list_elem_t *)tx_desc)->next = temp_list; + temp_list = (union ol_tx_desc_list_elem_t *)tx_desc; + + } + qdf_spin_unlock_bh(&src_pool->flow_pool_lock); + + /* Take descriptors from temp_list and put it in destination pool */ + qdf_spin_lock_bh(&dst_pool->flow_pool_lock); + for (i = 0; i < desc_move_count; i++) { + if (dst_pool->deficient_desc) + dst_pool->deficient_desc--; + else + break; + tx_desc = &temp_list->tx_desc; + temp_list = temp_list->next; + ol_tx_put_desc_flow_pool(dst_pool, tx_desc); + count++; + } + qdf_spin_unlock_bh(&dst_pool->flow_pool_lock); + + /* If anything is there in temp_list put it back to source pool */ + qdf_spin_lock_bh(&src_pool->flow_pool_lock); + while (temp_list) { + tx_desc = &temp_list->tx_desc; + temp_list = temp_list->next; + ol_tx_put_desc_flow_pool(src_pool, tx_desc); + } + qdf_spin_unlock_bh(&src_pool->flow_pool_lock); + + return count; +} + + +/** + * ol_tx_distribute_descs_to_deficient_pools() - Distribute descriptors + * @src_pool: source pool + * + * Distribute all descriptors of source pool to all + * deficient pools as per flow_pool_list. + * + * Return: 0 for sucess + */ +static int +ol_tx_distribute_descs_to_deficient_pools(struct ol_tx_flow_pool_t *src_pool) +{ + struct ol_txrx_pdev_t *pdev = cds_get_context(QDF_MODULE_ID_TXRX); + struct ol_tx_flow_pool_t *dst_pool = NULL; + uint16_t desc_count = src_pool->avail_desc; + uint16_t desc_move_count = 0; + + if (!pdev) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "%s: pdev is NULL\n", __func__); + return -EINVAL; + } + qdf_spin_lock_bh(&pdev->tx_desc.flow_pool_list_lock); + TAILQ_FOREACH(dst_pool, &pdev->tx_desc.flow_pool_list, + flow_pool_list_elem) { + qdf_spin_lock_bh(&dst_pool->flow_pool_lock); + if (dst_pool->deficient_desc) { + desc_move_count = + (dst_pool->deficient_desc > desc_count) ? + desc_count : dst_pool->deficient_desc; + qdf_spin_unlock_bh(&dst_pool->flow_pool_lock); + desc_move_count = ol_tx_move_desc_n(src_pool, + dst_pool, desc_move_count); + desc_count -= desc_move_count; + + qdf_spin_lock_bh(&dst_pool->flow_pool_lock); + if (dst_pool->status == FLOW_POOL_ACTIVE_PAUSED) { + if (dst_pool->avail_desc > dst_pool->start_th) { + pdev->pause_cb(dst_pool->member_flow_id, + WLAN_WAKE_ALL_NETIF_QUEUE, + WLAN_DATA_FLOW_CONTROL); + dst_pool->status = + FLOW_POOL_ACTIVE_UNPAUSED; + } + } + } + qdf_spin_unlock_bh(&dst_pool->flow_pool_lock); + if (desc_count == 0) + break; + } + qdf_spin_unlock_bh(&pdev->tx_desc.flow_pool_list_lock); + + return 0; +} + + +/** + * ol_tx_create_flow_pool() - create flow pool + * @flow_pool_id: flow pool id + * @flow_pool_size: flow pool size + * + * Return: flow_pool pointer / NULL for error + */ +struct ol_tx_flow_pool_t *ol_tx_create_flow_pool(uint8_t flow_pool_id, + uint16_t flow_pool_size) +{ + struct ol_txrx_pdev_t *pdev = cds_get_context(QDF_MODULE_ID_TXRX); + struct ol_tx_flow_pool_t *pool; + uint16_t size = 0, i; + struct ol_tx_desc_t *tx_desc; + union ol_tx_desc_list_elem_t *temp_list = NULL; + uint32_t stop_threshold; + uint32_t start_threshold; + + if (!pdev) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "%s: pdev is NULL\n", __func__); + return NULL; + } + stop_threshold = ol_cfg_get_tx_flow_stop_queue_th(pdev->ctrl_pdev); + start_threshold = stop_threshold + + ol_cfg_get_tx_flow_start_queue_offset(pdev->ctrl_pdev); + pool = qdf_mem_malloc(sizeof(*pool)); + if (!pool) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "%s: malloc failed\n", __func__); + return NULL; + } + + pool->flow_pool_id = flow_pool_id; + pool->flow_pool_size = flow_pool_size; + pool->status = FLOW_POOL_ACTIVE_UNPAUSED; + pool->start_th = (start_threshold * flow_pool_size)/100; + pool->stop_th = (stop_threshold * flow_pool_size)/100; + qdf_spinlock_create(&pool->flow_pool_lock); + qdf_atomic_init(&pool->ref_cnt); + ol_tx_inc_pool_ref(pool); + + /* Take TX descriptor from global_pool and put it in temp_list*/ + qdf_spin_lock_bh(&pdev->tx_mutex); + if (pdev->tx_desc.num_free >= pool->flow_pool_size) + size = pool->flow_pool_size; + else + size = pdev->tx_desc.num_free; + + for (i = 0; i < size; i++) { + tx_desc = ol_tx_get_desc_global_pool(pdev); + tx_desc->pool = pool; + ((union ol_tx_desc_list_elem_t *)tx_desc)->next = temp_list; + temp_list = (union ol_tx_desc_list_elem_t *)tx_desc; + + } + qdf_spin_unlock_bh(&pdev->tx_mutex); + + /* put temp_list to flow_pool */ + pool->freelist = temp_list; + pool->avail_desc = size; + pool->deficient_desc = pool->flow_pool_size - pool->avail_desc; + + /* Add flow_pool to flow_pool_list */ + qdf_spin_lock_bh(&pdev->tx_desc.flow_pool_list_lock); + TAILQ_INSERT_TAIL(&pdev->tx_desc.flow_pool_list, pool, + flow_pool_list_elem); + qdf_spin_unlock_bh(&pdev->tx_desc.flow_pool_list_lock); + + return pool; +} + +/** + * ol_tx_free_invalid_flow_pool() - free invalid pool + * @pool: pool + * + * Return: 0 for success or failure + */ +int ol_tx_free_invalid_flow_pool(struct ol_tx_flow_pool_t *pool) +{ + struct ol_txrx_pdev_t *pdev = cds_get_context(QDF_MODULE_ID_TXRX); + + if ((!pdev) || (!pool) || (pool->status != FLOW_POOL_INVALID)) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "%s: Invalid pool/pdev\n", __func__); + return -EINVAL; + } + + /* direclty distribute to other deficient pools */ + ol_tx_distribute_descs_to_deficient_pools(pool); + + qdf_spin_lock_bh(&pool->flow_pool_lock); + pool->flow_pool_size = pool->avail_desc; + qdf_spin_unlock_bh(&pool->flow_pool_lock); + + pdev->tx_desc.num_invalid_bin--; + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "%s: invalid pool deleted %d\n", + __func__, pdev->tx_desc.num_invalid_bin); + + return ol_tx_dec_pool_ref(pool, false); +} + +/** + * ol_tx_get_flow_pool() - get flow_pool from flow_pool_id + * @flow_pool_id: flow pool id + * + * Return: flow_pool ptr / NULL if not found + */ +static struct ol_tx_flow_pool_t *ol_tx_get_flow_pool(uint8_t flow_pool_id) +{ + struct ol_txrx_pdev_t *pdev = cds_get_context(QDF_MODULE_ID_TXRX); + struct ol_tx_flow_pool_t *pool = NULL; + bool is_found = false; + + if (!pdev) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, "ERROR: pdev NULL"); + QDF_ASSERT(0); /* traceback */ + return NULL; + } + + qdf_spin_lock_bh(&pdev->tx_desc.flow_pool_list_lock); + TAILQ_FOREACH(pool, &pdev->tx_desc.flow_pool_list, + flow_pool_list_elem) { + qdf_spin_lock_bh(&pool->flow_pool_lock); + if (pool->flow_pool_id == flow_pool_id) { + qdf_spin_unlock_bh(&pool->flow_pool_lock); + is_found = true; + break; + } + qdf_spin_unlock_bh(&pool->flow_pool_lock); + } + qdf_spin_unlock_bh(&pdev->tx_desc.flow_pool_list_lock); + + if (is_found == false) + pool = NULL; + + return pool; +} + + +/** + * ol_tx_flow_pool_vdev_map() - Map flow_pool with vdev + * @pool: flow_pool + * @vdev_id: flow_id /vdev_id + * + * Return: none + */ +static void ol_tx_flow_pool_vdev_map(struct ol_tx_flow_pool_t *pool, + uint8_t vdev_id) +{ + ol_txrx_vdev_handle vdev; + + vdev = ol_txrx_get_vdev_from_vdev_id(vdev_id); + if (!vdev) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "%s: invalid vdev_id %d\n", + __func__, vdev_id); + return; + } + + vdev->pool = pool; + qdf_spin_lock_bh(&pool->flow_pool_lock); + pool->member_flow_id = vdev_id; + qdf_spin_unlock_bh(&pool->flow_pool_lock); + + return; +} + +/** + * ol_tx_flow_pool_vdev_unmap() - Unmap flow_pool from vdev + * @pool: flow_pool + * @vdev_id: flow_id /vdev_id + * + * Return: none + */ +static void ol_tx_flow_pool_vdev_unmap(struct ol_tx_flow_pool_t *pool, + uint8_t vdev_id) +{ + ol_txrx_vdev_handle vdev; + + vdev = ol_txrx_get_vdev_from_vdev_id(vdev_id); + if (!vdev) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "%s: invalid vdev_id %d\n", + __func__, vdev_id); + return; + } + + vdev->pool = NULL; + qdf_spin_lock_bh(&pool->flow_pool_lock); + pool->member_flow_id = INVALID_FLOW_ID; + qdf_spin_unlock_bh(&pool->flow_pool_lock); + + return; +} + +/** + * ol_tx_flow_pool_map_handler() - Map flow_id with pool of descriptors + * @flow_id: flow id + * @flow_type: flow type + * @flow_pool_id: pool id + * @flow_pool_size: pool size + * + * Process below target to host message + * HTT_T2H_MSG_TYPE_FLOW_POOL_MAP + * + * Return: none + */ +void ol_tx_flow_pool_map_handler(uint8_t flow_id, uint8_t flow_type, + uint8_t flow_pool_id, uint16_t flow_pool_size) +{ + struct ol_txrx_pdev_t *pdev = cds_get_context(QDF_MODULE_ID_TXRX); + struct ol_tx_flow_pool_t *pool; + uint8_t pool_create = 0; + enum htt_flow_type type = flow_type; + + + TXRX_PRINT(TXRX_PRINT_LEVEL_INFO1, + "%s: flow_id %d flow_type %d flow_pool_id %d flow_pool_size %d\n", + __func__, flow_id, flow_type, flow_pool_id, flow_pool_size); + + if (qdf_unlikely(!pdev)) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "%s: pdev is NULL", __func__); + return; + } + pdev->pool_stats.pool_map_count++; + + pool = ol_tx_get_flow_pool(flow_pool_id); + if (!pool) { + pool = ol_tx_create_flow_pool(flow_pool_id, flow_pool_size); + if (pool == NULL) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "%s: creation of flow_pool %d size %d failed\n", + __func__, flow_pool_id, flow_pool_size); + return; + } + pool_create = 1; + } + + switch (type) { + + case FLOW_TYPE_VDEV: + ol_tx_flow_pool_vdev_map(pool, flow_id); + qdf_spin_lock_bh(&pool->flow_pool_lock); + pdev->pause_cb(flow_id, + WLAN_WAKE_ALL_NETIF_QUEUE, + WLAN_DATA_FLOW_CONTROL); + qdf_spin_unlock_bh(&pool->flow_pool_lock); + break; + default: + if (pool_create) + ol_tx_dec_pool_ref(pool, false); + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "%s: flow type %d not supported !!!\n", + __func__, type); + break; + } + + return; +} + +/** + * ol_tx_flow_pool_unmap_handler() - Unmap flow_id from pool of descriptors + * @flow_id: flow id + * @flow_type: flow type + * @flow_pool_id: pool id + * + * Process below target to host message + * HTT_T2H_MSG_TYPE_FLOW_POOL_UNMAP + * + * Return: none + */ +void ol_tx_flow_pool_unmap_handler(uint8_t flow_id, uint8_t flow_type, + uint8_t flow_pool_id) +{ + struct ol_txrx_pdev_t *pdev = cds_get_context(QDF_MODULE_ID_TXRX); + struct ol_tx_flow_pool_t *pool; + enum htt_flow_type type = flow_type; + + TXRX_PRINT(TXRX_PRINT_LEVEL_INFO1, + "%s: flow_id %d flow_type %d flow_pool_id %d\n", + __func__, flow_id, flow_type, flow_pool_id); + + if (qdf_unlikely(!pdev)) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "%s: pdev is NULL", __func__); + return; + } + pdev->pool_stats.pool_unmap_count++; + + pool = ol_tx_get_flow_pool(flow_pool_id); + if (!pool) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "%s: flow_pool not available flow_pool_id %d\n", + __func__, type); + return; + } + + switch (type) { + + case FLOW_TYPE_VDEV: + ol_tx_flow_pool_vdev_unmap(pool, flow_id); + break; + default: + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "%s: flow type %d not supported !!!\n", + __func__, type); + return; + } + + /* + * only delete if all descriptors are available + * and pool ref count becomes 0 + */ + ol_tx_dec_pool_ref(pool, false); + + return; +} diff --git a/drivers/staging/qcacld-3.0/core/dp/txrx/ol_txrx_internal.h b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_txrx_internal.h new file mode 100644 index 0000000000000000000000000000000000000000..4c9a6c70ea90bb00f97b362a40beabea5677f2df --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_txrx_internal.h @@ -0,0 +1,816 @@ +/* + * Copyright (c) 2011-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef _OL_TXRX_INTERNAL__H_ +#define _OL_TXRX_INTERNAL__H_ + +#include /* qdf_assert */ +#include /* qdf_nbuf_t */ +#include /* qdf_mem_set */ +#include /* ieee80211_frame */ +#include /* htt_rx_msdu_desc_completes_mpdu, etc. */ + +#include + +#include +#include /* ETHERNET_HDR_LEN, etc. */ +#include /* IPV4_HDR_LEN, etc. */ +#include /* IPV6_HDR_LEN, etc. */ +#include /* IP_PROTOCOL_TCP, etc. */ + +#ifdef ATH_11AC_TXCOMPACT +#define OL_TX_DESC_NO_REFS(tx_desc) 1 +#define OL_TX_DESC_REF_INIT(tx_desc) /* no-op */ +#define OL_TX_DESC_REF_INC(tx_desc) /* no-op */ +#else +#define OL_TX_DESC_NO_REFS(tx_desc) \ + qdf_atomic_dec_and_test(&tx_desc->ref_cnt) +#define OL_TX_DESC_REF_INIT(tx_desc) qdf_atomic_init(&tx_desc->ref_cnt) +#define OL_TX_DESC_REF_INC(tx_desc) qdf_atomic_inc(&tx_desc->ref_cnt) +#endif + +#ifndef TXRX_ASSERT_LEVEL +#define TXRX_ASSERT_LEVEL 3 +#endif + +#ifdef __KLOCWORK__ +#define TXRX_ASSERT1(x) do { if (!(x)) abort(); } while (0) +#define TXRX_ASSERT2(x) do { if (!(x)) abort(); } while (0) +#else /* #ifdef __KLOCWORK__ */ + +#if TXRX_ASSERT_LEVEL > 0 +#define TXRX_ASSERT1(condition) qdf_assert((condition)) +#else +#define TXRX_ASSERT1(condition) +#endif + +#if TXRX_ASSERT_LEVEL > 1 +#define TXRX_ASSERT2(condition) qdf_assert((condition)) +#else +#define TXRX_ASSERT2(condition) +#endif +#endif /* #ifdef __KLOCWORK__ */ +enum { + /* FATAL_ERR - print only irrecoverable error messages */ + TXRX_PRINT_LEVEL_FATAL_ERR, + + /* ERR - include non-fatal err messages */ + TXRX_PRINT_LEVEL_ERR, + + /* WARN - include warnings */ + TXRX_PRINT_LEVEL_WARN, + + /* INFO1 - include fundamental, infrequent events */ + TXRX_PRINT_LEVEL_INFO1, + + /* INFO2 - include non-fundamental but infrequent events */ + TXRX_PRINT_LEVEL_INFO2, + + /* INFO3 - include frequent events */ + /* to avoid performance impact, don't use INFO3 + unless explicitly enabled */ +#ifdef TXRX_PRINT_VERBOSE_ENABLE + TXRX_PRINT_LEVEL_INFO3, +#endif /* TXRX_PRINT_VERBOSE_ENABLE */ +}; + +extern unsigned g_txrx_print_level; + +#ifdef TXRX_PRINT_ENABLE + +#include /* va_list */ +#include /* qdf_vprint */ + +/* Supress 4296 - expression is always true +* It will fire if level is TXRX_PRINT_LEVEL_FATAL_ERR (0) +* because g_txrx_print_level is unsigned */ +#define ol_txrx_print(level, fmt, ...) { \ + if (level <= g_txrx_print_level) \ + qdf_print(fmt, ## __VA_ARGS__); } +#define TXRX_PRINT(level, fmt, ...) \ + ol_txrx_print(level, "TXRX: " fmt, ## __VA_ARGS__) + +#ifdef TXRX_PRINT_VERBOSE_ENABLE + +#define ol_txrx_print_verbose(fmt, ...) { \ + if (TXRX_PRINT_LEVEL_INFO3 <= g_txrx_print_level) \ + qdf_print(fmt, ## __VA_ARGS__); } +#define TXRX_PRINT_VERBOSE(fmt, ...) \ + ol_txrx_print_verbose("TXRX: " fmt, ## __VA_ARGS__) +#else +#define TXRX_PRINT_VERBOSE(fmt, ...) +#endif /* TXRX_PRINT_VERBOSE_ENABLE */ + +/* define PN check failure message print rate + as 1 second */ +#define TXRX_PN_CHECK_FAILURE_PRINT_PERIOD_MS 1000 + +#else +#define TXRX_PRINT(level, fmt, ...) +#define TXRX_PRINT_VERBOSE(fmt, ...) +#endif /* TXRX_PRINT_ENABLE */ + +/*--- tx credit debug printouts ---*/ + +#ifndef DEBUG_CREDIT +#define DEBUG_CREDIT 0 +#endif + +#if DEBUG_CREDIT +#define TX_CREDIT_DEBUG_PRINT(fmt, ...) qdf_print(fmt, ## __VA_ARGS__) +#else +#define TX_CREDIT_DEBUG_PRINT(fmt, ...) +#endif + +/*--- tx scheduler debug printouts ---*/ + +#ifdef HOST_TX_SCHED_DEBUG +#define TX_SCHED_DEBUG_PRINT(fmt, ...) qdf_print(fmt, ## __VA_ARGS__) +#else +#define TX_SCHED_DEBUG_PRINT(fmt, ...) +#endif +#define TX_SCHED_DEBUG_PRINT_ALWAYS(fmt, ...) qdf_print(fmt, ## __VA_ARGS__) + +#define OL_TXRX_LIST_APPEND(head, tail, elem) \ + do { \ + if (!(head)) { \ + (head) = (elem); \ + } else { \ + qdf_nbuf_set_next((tail), (elem)); \ + } \ + (tail) = (elem); \ + } while (0) + +static inline void +ol_rx_mpdu_list_next(struct ol_txrx_pdev_t *pdev, + void *mpdu_list, + qdf_nbuf_t *mpdu_tail, qdf_nbuf_t *next_mpdu) +{ + htt_pdev_handle htt_pdev = pdev->htt_pdev; + qdf_nbuf_t msdu; + + /* + * For now, we use a simply flat list of MSDUs. + * So, traverse the list until we reach the last MSDU within the MPDU. + */ + TXRX_ASSERT2(mpdu_list); + msdu = mpdu_list; + while (!htt_rx_msdu_desc_completes_mpdu + (htt_pdev, htt_rx_msdu_desc_retrieve(htt_pdev, msdu))) { + msdu = qdf_nbuf_next(msdu); + TXRX_ASSERT2(msdu); + } + /* msdu now points to the last MSDU within the first MPDU */ + *mpdu_tail = msdu; + *next_mpdu = qdf_nbuf_next(msdu); +} + +/*--- txrx stats macros ---*/ + +/* unconditional defs */ +#define TXRX_STATS_INCR(pdev, field) TXRX_STATS_ADD(pdev, field, 1) + +/* default conditional defs (may be undefed below) */ + +#define TXRX_STATS_INIT(_pdev) \ + qdf_mem_set(&((_pdev)->stats), sizeof((_pdev)->stats), 0x0) +#define TXRX_STATS_ADD(_pdev, _field, _delta) { \ + _pdev->stats._field += _delta; } +#define TXRX_STATS_MSDU_INCR(pdev, field, netbuf) \ + do { \ + TXRX_STATS_INCR((pdev), pub.field.pkts); \ + TXRX_STATS_ADD((pdev), pub.field.bytes, qdf_nbuf_len(netbuf)); \ + } while (0) + +/* conditional defs based on verbosity level */ + + +#define TXRX_STATS_MSDU_LIST_INCR(pdev, field, netbuf_list) \ + do { \ + qdf_nbuf_t tmp_list = netbuf_list; \ + while (tmp_list) { \ + TXRX_STATS_MSDU_INCR(pdev, field, tmp_list); \ + tmp_list = qdf_nbuf_next(tmp_list); \ + } \ + } while (0) + +#define TXRX_STATS_MSDU_INCR_TX_STATUS(status, pdev, netbuf) do { \ + if (status == htt_tx_status_ok) \ + TXRX_STATS_MSDU_INCR(pdev, tx.delivered, netbuf); \ + else if (status == htt_tx_status_discard) \ + TXRX_STATS_MSDU_INCR(pdev, tx.dropped.target_discard, \ + netbuf); \ + else if (status == htt_tx_status_no_ack) \ + TXRX_STATS_MSDU_INCR(pdev, tx.dropped.no_ack, netbuf); \ + else if (status == htt_tx_status_download_fail) \ + TXRX_STATS_MSDU_INCR(pdev, tx.dropped.download_fail, \ + netbuf); \ + else \ + /* NO-OP */; \ + } while (0) + +#define TXRX_STATS_UPDATE_TX_COMP_HISTOGRAM(_pdev, _p_cntrs) \ + do { \ + if (_p_cntrs == 1) { \ + TXRX_STATS_ADD(_pdev, pub.tx.comp_histogram.pkts_1, 1);\ + } else if (_p_cntrs > 2 && _p_cntrs <= 10) { \ + TXRX_STATS_ADD(_pdev, \ + pub.tx.comp_histogram.pkts_2_10, 1); \ + } else if (_p_cntrs > 10 && _p_cntrs <= 20) { \ + TXRX_STATS_ADD(_pdev, \ + pub.tx.comp_histogram.pkts_11_20, 1); \ + } else if (_p_cntrs > 20 && _p_cntrs <= 30) { \ + TXRX_STATS_ADD(_pdev, \ + pub.tx.comp_histogram.pkts_21_30, 1); \ + } else if (_p_cntrs > 30 && _p_cntrs <= 40) { \ + TXRX_STATS_ADD(_pdev, \ + pub.tx.comp_histogram.pkts_31_40, 1); \ + } else if (_p_cntrs > 40 && _p_cntrs <= 50) { \ + TXRX_STATS_ADD(_pdev, \ + pub.tx.comp_histogram.pkts_41_50, 1); \ + } else if (_p_cntrs > 50 && _p_cntrs <= 60) { \ + TXRX_STATS_ADD(_pdev, \ + pub.tx.comp_histogram.pkts_51_60, 1); \ + } else { \ + TXRX_STATS_ADD(_pdev, \ + pub.tx.comp_histogram.pkts_61_plus, 1); \ + } \ + } while (0) + +#define TXRX_STATS_UPDATE_TX_STATS(_pdev, _status, _p_cntrs, _b_cntrs) \ + do { \ + switch (status) { \ + case htt_tx_status_ok: \ + TXRX_STATS_ADD(_pdev, \ + pub.tx.delivered.pkts, _p_cntrs); \ + TXRX_STATS_ADD(_pdev, \ + pub.tx.delivered.bytes, _b_cntrs); \ + break; \ + case htt_tx_status_discard: \ + TXRX_STATS_ADD(_pdev, \ + pub.tx.dropped.target_discard.pkts, _p_cntrs);\ + TXRX_STATS_ADD(_pdev, \ + pub.tx.dropped.target_discard.bytes, _b_cntrs);\ + break; \ + case htt_tx_status_no_ack: \ + TXRX_STATS_ADD(_pdev, pub.tx.dropped.no_ack.pkts, \ + _p_cntrs); \ + TXRX_STATS_ADD(_pdev, pub.tx.dropped.no_ack.bytes, \ + _b_cntrs); \ + break; \ + case htt_tx_status_download_fail: \ + TXRX_STATS_ADD(_pdev, \ + pub.tx.dropped.download_fail.pkts, _p_cntrs); \ + TXRX_STATS_ADD(_pdev, \ + pub.tx.dropped.download_fail.bytes, _b_cntrs);\ + break; \ + default: \ + break; \ + } \ + TXRX_STATS_UPDATE_TX_COMP_HISTOGRAM(_pdev, _p_cntrs); \ + } while (0) + + +/*--- txrx sequence number trace macros ---*/ + +#define TXRX_SEQ_NUM_ERR(_status) (0xffff - _status) + +#if defined(ENABLE_RX_REORDER_TRACE) + +A_STATUS ol_rx_reorder_trace_attach(ol_txrx_pdev_handle pdev); +void ol_rx_reorder_trace_detach(ol_txrx_pdev_handle pdev); +void ol_rx_reorder_trace_add(ol_txrx_pdev_handle pdev, + uint8_t tid, + uint16_t reorder_idx, + uint16_t seq_num, int num_mpdus); + +#define OL_RX_REORDER_TRACE_ATTACH ol_rx_reorder_trace_attach +#define OL_RX_REORDER_TRACE_DETACH ol_rx_reorder_trace_detach +#define OL_RX_REORDER_TRACE_ADD ol_rx_reorder_trace_add + +#else + +#define OL_RX_REORDER_TRACE_ATTACH(_pdev) A_OK +#define OL_RX_REORDER_TRACE_DETACH(_pdev) +#define OL_RX_REORDER_TRACE_ADD(pdev, tid, reorder_idx, seq_num, num_mpdus) + +#endif /* ENABLE_RX_REORDER_TRACE */ + +/*--- txrx packet number trace macros ---*/ + +#if defined(ENABLE_RX_PN_TRACE) + +A_STATUS ol_rx_pn_trace_attach(ol_txrx_pdev_handle pdev); +void ol_rx_pn_trace_detach(ol_txrx_pdev_handle pdev); +void ol_rx_pn_trace_add(struct ol_txrx_pdev_t *pdev, + struct ol_txrx_peer_t *peer, + uint16_t tid, void *rx_desc); + +#define OL_RX_PN_TRACE_ATTACH ol_rx_pn_trace_attach +#define OL_RX_PN_TRACE_DETACH ol_rx_pn_trace_detach +#define OL_RX_PN_TRACE_ADD ol_rx_pn_trace_add + +#else + +#define OL_RX_PN_TRACE_ATTACH(_pdev) A_OK +#define OL_RX_PN_TRACE_DETACH(_pdev) +#define OL_RX_PN_TRACE_ADD(pdev, peer, tid, rx_desc) + +#endif /* ENABLE_RX_PN_TRACE */ + +static inline int ol_txrx_ieee80211_hdrsize(const void *data) +{ + const struct ieee80211_frame *wh = (const struct ieee80211_frame *)data; + int size = sizeof(struct ieee80211_frame); + + /* NB: we don't handle control frames */ + TXRX_ASSERT1((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) != + IEEE80211_FC0_TYPE_CTL); + if ((wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) == + IEEE80211_FC1_DIR_DSTODS) + size += IEEE80211_ADDR_LEN; + if (IEEE80211_QOS_HAS_SEQ(wh)) { + size += sizeof(uint16_t); + /* Qos frame with Order bit set indicates an HTC frame */ + if (wh->i_fc[1] & IEEE80211_FC1_ORDER) + size += sizeof(struct ieee80211_htc); + } + return size; +} + +/*--- frame display utility ---*/ + +enum ol_txrx_frm_dump_options { + ol_txrx_frm_dump_contents = 0x1, + ol_txrx_frm_dump_tcp_seq = 0x2, +}; + +#ifdef TXRX_DEBUG_DATA +static inline void +ol_txrx_frms_dump(const char *name, + struct ol_txrx_pdev_t *pdev, + qdf_nbuf_t frm, + enum ol_txrx_frm_dump_options display_options, int max_len) +{ +#define TXRX_FRM_DUMP_MAX_LEN 128 + uint8_t local_buf[TXRX_FRM_DUMP_MAX_LEN] = { 0 }; + uint8_t *p; + + if (name) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO, "%s\n", + name); + } + while (frm) { + p = qdf_nbuf_data(frm); + if (display_options & ol_txrx_frm_dump_tcp_seq) { + int tcp_offset; + int l2_hdr_size; + uint16_t ethtype; + uint8_t ip_prot; + + if (pdev->frame_format == wlan_frm_fmt_802_3) { + struct ethernet_hdr_t *enet_hdr = + (struct ethernet_hdr_t *)p; + l2_hdr_size = ETHERNET_HDR_LEN; + + /* + * LLC/SNAP present? + */ + ethtype = (enet_hdr->ethertype[0] << 8) | + enet_hdr->ethertype[1]; + if (!IS_ETHERTYPE(ethertype)) { + /* 802.3 format */ + struct llc_snap_hdr_t *llc_hdr; + + llc_hdr = (struct llc_snap_hdr_t *) + (p + l2_hdr_size); + l2_hdr_size += LLC_SNAP_HDR_LEN; + ethtype = (llc_hdr->ethertype[0] << 8) | + llc_hdr->ethertype[1]; + } + } else { + struct llc_snap_hdr_t *llc_hdr; + /* (generic?) 802.11 */ + l2_hdr_size = sizeof(struct ieee80211_frame); + llc_hdr = (struct llc_snap_hdr_t *) + (p + l2_hdr_size); + l2_hdr_size += LLC_SNAP_HDR_LEN; + ethtype = (llc_hdr->ethertype[0] << 8) | + llc_hdr->ethertype[1]; + } + if (ethtype == ETHERTYPE_IPV4) { + struct ipv4_hdr_t *ipv4_hdr; + ipv4_hdr = + (struct ipv4_hdr_t *)(p + l2_hdr_size); + ip_prot = ipv4_hdr->protocol; + tcp_offset = l2_hdr_size + IPV4_HDR_LEN; + } else if (ethtype == ETHERTYPE_IPV6) { + struct ipv6_hdr_t *ipv6_hdr; + ipv6_hdr = + (struct ipv6_hdr_t *)(p + l2_hdr_size); + ip_prot = ipv6_hdr->next_hdr; + tcp_offset = l2_hdr_size + IPV6_HDR_LEN; + } else { + QDF_TRACE(QDF_MODULE_ID_TXRX, + QDF_TRACE_LEVEL_INFO, + "frame %p non-IP ethertype (%x)\n", + frm, ethtype); + goto NOT_IP_TCP; + } + if (ip_prot == IP_PROTOCOL_TCP) { +#if NEVERDEFINED + struct tcp_hdr_t *tcp_hdr; + uint32_t tcp_seq_num; + tcp_hdr = (struct tcp_hdr_t *)(p + tcp_offset); + tcp_seq_num = + (tcp_hdr->seq_num[0] << 24) | + (tcp_hdr->seq_num[1] << 16) | + (tcp_hdr->seq_num[1] << 8) | + (tcp_hdr->seq_num[1] << 0); + QDF_TRACE(QDF_MODULE_ID_TXRX, + QDF_TRACE_LEVEL_INFO, + "frame %p: TCP seq num = %d\n", frm, + tcp_seq_num); +#else + QDF_TRACE(QDF_MODULE_ID_TXRX, + QDF_TRACE_LEVEL_INFO, + "frame %p: TCP seq num = %d\n", frm, + ((*(p + tcp_offset + 4)) << 24) | + ((*(p + tcp_offset + 5)) << 16) | + ((*(p + tcp_offset + 6)) << 8) | + (*(p + tcp_offset + 7))); +#endif + } else { + QDF_TRACE(QDF_MODULE_ID_TXRX, + QDF_TRACE_LEVEL_INFO, + "frame %p non-TCP IP protocol (%x)\n", + frm, ip_prot); + } + } +NOT_IP_TCP: + if (display_options & ol_txrx_frm_dump_contents) { + int i, frag_num, len_lim; + len_lim = max_len; + if (len_lim > qdf_nbuf_len(frm)) + len_lim = qdf_nbuf_len(frm); + if (len_lim > TXRX_FRM_DUMP_MAX_LEN) + len_lim = TXRX_FRM_DUMP_MAX_LEN; + + /* + * Gather frame contents from netbuf fragments + * into a contiguous buffer. + */ + frag_num = 0; + i = 0; + while (i < len_lim) { + int frag_bytes; + frag_bytes = + qdf_nbuf_get_frag_len(frm, frag_num); + if (frag_bytes > len_lim - i) + frag_bytes = len_lim - i; + if (frag_bytes > 0) { + p = qdf_nbuf_get_frag_vaddr(frm, + frag_num); + qdf_mem_copy(&local_buf[i], p, + frag_bytes); + } + frag_num++; + i += frag_bytes; + } + + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO, + "frame %p data (%p), hex dump of bytes 0-%d of %d:\n", + frm, p, len_lim - 1, (int)qdf_nbuf_len(frm)); + p = local_buf; + while (len_lim > 16) { + QDF_TRACE(QDF_MODULE_ID_TXRX, + QDF_TRACE_LEVEL_INFO, + " " /* indent */ + "%02x %02x %02x %02x %02x %02x %02x %02x " + "%02x %02x %02x %02x %02x %02x %02x %02x\n", + *(p + 0), *(p + 1), *(p + 2), + *(p + 3), *(p + 4), *(p + 5), + *(p + 6), *(p + 7), *(p + 8), + *(p + 9), *(p + 10), *(p + 11), + *(p + 12), *(p + 13), *(p + 14), + *(p + 15)); + p += 16; + len_lim -= 16; + } + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO, + " " /* indent */); + while (len_lim > 0) { + QDF_TRACE(QDF_MODULE_ID_TXRX, + QDF_TRACE_LEVEL_INFO, "%02x ", *p); + p++; + len_lim--; + } + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO, + "\n"); + } + frm = qdf_nbuf_next(frm); + } +} +#else +#define ol_txrx_frms_dump(name, pdev, frms, display_options, max_len) +#endif /* TXRX_DEBUG_DATA */ + +#ifdef SUPPORT_HOST_STATISTICS + +#define OL_RX_ERR_STATISTICS(pdev, vdev, err_type, sec_type, is_mcast) \ + ol_rx_err_statistics(pdev->ctrl_pdev, vdev->vdev_id, err_type, \ + sec_type, is_mcast); + +#define OL_RX_ERR_STATISTICS_1(pdev, vdev, peer, rx_desc, err_type) \ + do { \ + int is_mcast; \ + enum htt_sec_type sec_type; \ + is_mcast = htt_rx_msdu_is_wlan_mcast( \ + pdev->htt_pdev, rx_desc); \ + sec_type = peer->security[is_mcast \ + ? txrx_sec_mcast \ + : txrx_sec_ucast].sec_type; \ + OL_RX_ERR_STATISTICS(pdev, vdev, err_type, \ + pdev->sec_types[sec_type], \ + is_mcast); \ + } while (false) + +#ifdef CONFIG_HL_SUPPORT + + /** + * ol_rx_err_inv_get_wifi_header() - retrieve wifi header + * @pdev: handle to the physical device + * @rx_msdu: msdu of which header needs to be retrieved + * + * Return: wifi header + */ + static inline + struct ieee80211_frame *ol_rx_err_inv_get_wifi_header( + struct ol_pdev_t *pdev, qdf_nbuf_t rx_msdu) + { + return NULL; + } +#else + + static inline + struct ieee80211_frame *ol_rx_err_inv_get_wifi_header( + struct ol_pdev_t *pdev, qdf_nbuf_t rx_msdu) + { + struct ieee80211_frame *wh = NULL; + if (ol_cfg_frame_type(pdev) == wlan_frm_fmt_native_wifi) + /* For windows, it is always native wifi header .*/ + wh = (struct ieee80211_frame *)qdf_nbuf_data(rx_msdu); + + return wh; + } +#endif + +#define OL_RX_ERR_INV_PEER_STATISTICS(pdev, rx_msdu) \ + do { \ + struct ieee80211_frame *wh = NULL; \ + /*FIX THIS : */ \ + /* Here htt_rx_mpdu_wifi_hdr_retrieve should be used. */ \ + /*But at present it seems it does not work.*/ \ + /*wh = (struct ieee80211_frame *) */ \ + /*htt_rx_mpdu_wifi_hdr_retrieve(pdev->htt_pdev, rx_desc);*/ \ + /* this only apply to LL device.*/ \ + wh = ol_rx_err_inv_get_wifi_header(pdev->ctrl_pdev, rx_msdu); \ + ol_rx_err_inv_peer_statistics(pdev->ctrl_pdev, \ + wh, OL_RX_ERR_UNKNOWN_PEER); \ + } while (false) + +#define OL_RX_ERR_STATISTICS_2(pdev, vdev, peer, rx_desc, rx_msdu, rx_status) \ + do { \ + enum ol_rx_err_type err_type = OL_RX_ERR_NONE; \ + if (rx_status == htt_rx_status_decrypt_err) \ + err_type = OL_RX_ERR_DECRYPT; \ + else if (rx_status == htt_rx_status_tkip_mic_err) \ + err_type = OL_RX_ERR_TKIP_MIC; \ + else if (rx_status == htt_rx_status_mpdu_length_err) \ + err_type = OL_RX_ERR_MPDU_LENGTH; \ + else if (rx_status == htt_rx_status_mpdu_encrypt_required_err) \ + err_type = OL_RX_ERR_ENCRYPT_REQUIRED; \ + else if (rx_status == htt_rx_status_err_dup) \ + err_type = OL_RX_ERR_DUP; \ + else if (rx_status == htt_rx_status_err_fcs) \ + err_type = OL_RX_ERR_FCS; \ + else \ + err_type = OL_RX_ERR_UNKNOWN; \ + \ + if (vdev != NULL && peer != NULL) { \ + OL_RX_ERR_STATISTICS_1(pdev, vdev, peer, \ + rx_mpdu_desc, err_type); \ + } else { \ + OL_RX_ERR_INV_PEER_STATISTICS(pdev, rx_msdu); \ + } \ + } while (false) +#else +#define OL_RX_ERR_STATISTICS(pdev, vdev, err_type, sec_type, is_mcast) +#define OL_RX_ERR_STATISTICS_1(pdev, vdev, peer, rx_desc, err_type) +#define OL_RX_ERR_STATISTICS_2(pdev, vdev, peer, rx_desc, rx_msdu, rx_status) +#endif /* SUPPORT_HOST_STATISTICS */ + +#ifdef QCA_ENABLE_OL_TXRX_PEER_STATS +#define OL_TXRX_PEER_STATS_UPDATE_BASE(peer, tx_or_rx, type, msdu) \ + do { \ + qdf_spin_lock_bh(&peer->vdev->pdev->peer_stat_mutex); \ + peer->stats.tx_or_rx.frms.type += 1; \ + peer->stats.tx_or_rx.bytes.type += qdf_nbuf_len(msdu); \ + qdf_spin_unlock_bh(&peer->vdev->pdev->peer_stat_mutex); \ + } while (0) +#define OL_TXRX_PEER_STATS_UPDATE(peer, tx_or_rx, msdu) \ + do { \ + struct ol_txrx_vdev_t *vdev = peer->vdev; \ + struct ol_txrx_pdev_t *pdev = vdev->pdev; \ + uint8_t *dest_addr; \ + if (pdev->frame_format == wlan_frm_fmt_802_3) { \ + dest_addr = qdf_nbuf_data(msdu); \ + } else { /* 802.11 format */ \ + struct ieee80211_frame *frm; \ + frm = (struct ieee80211_frame *) qdf_nbuf_data(msdu); \ + if (vdev->opmode == wlan_op_mode_ap) { \ + dest_addr = (uint8_t *) &(frm->i_addr1[0]); \ + } else { \ + dest_addr = (uint8_t *) &(frm->i_addr3[0]); \ + } \ + } \ + if (qdf_unlikely(IEEE80211_IS_BROADCAST(dest_addr))) { \ + OL_TXRX_PEER_STATS_UPDATE_BASE(peer, tx_or_rx, \ + bcast, msdu); \ + } else if (qdf_unlikely(IEEE80211_IS_MULTICAST(dest_addr))) { \ + OL_TXRX_PEER_STATS_UPDATE_BASE(peer, tx_or_rx, \ + mcast, msdu); \ + } else { \ + OL_TXRX_PEER_STATS_UPDATE_BASE(peer, tx_or_rx, \ + ucast, msdu); \ + } \ + } while (0) +#define OL_TX_PEER_STATS_UPDATE(peer, msdu) \ + OL_TXRX_PEER_STATS_UPDATE(peer, tx, msdu) +#define OL_RX_PEER_STATS_UPDATE(peer, msdu) \ + OL_TXRX_PEER_STATS_UPDATE(peer, rx, msdu) +#define OL_TXRX_PEER_STATS_MUTEX_INIT(pdev) \ + qdf_spinlock_create(&pdev->peer_stat_mutex) +#define OL_TXRX_PEER_STATS_MUTEX_DESTROY(pdev) \ + qdf_spinlock_destroy(&pdev->peer_stat_mutex) +#else +#define OL_TX_PEER_STATS_UPDATE(peer, msdu) /* no-op */ +#define OL_RX_PEER_STATS_UPDATE(peer, msdu) /* no-op */ +#define OL_TXRX_PEER_STATS_MUTEX_INIT(peer) /* no-op */ +#define OL_TXRX_PEER_STATS_MUTEX_DESTROY(peer) /* no-op */ +#endif + +#ifndef DEBUG_HTT_CREDIT +#define DEBUG_HTT_CREDIT 0 +#endif + +#if defined(FEATURE_TSO_DEBUG) +#define TXRX_STATS_TSO_HISTOGRAM(_pdev, _p_cntrs) \ + do { \ + if (_p_cntrs == 1) { \ + TXRX_STATS_ADD(_pdev, pub.tx.tso.tso_hist.pkts_1, 1); \ + } else if (_p_cntrs >= 2 && _p_cntrs <= 5) { \ + TXRX_STATS_ADD(_pdev, \ + pub.tx.tso.tso_hist.pkts_2_5, 1); \ + } else if (_p_cntrs > 5 && _p_cntrs <= 10) { \ + TXRX_STATS_ADD(_pdev, \ + pub.tx.tso.tso_hist.pkts_6_10, 1); \ + } else if (_p_cntrs > 10 && _p_cntrs <= 15) { \ + TXRX_STATS_ADD(_pdev, \ + pub.tx.tso.tso_hist.pkts_11_15, 1); \ + } else if (_p_cntrs > 15 && _p_cntrs <= 20) { \ + TXRX_STATS_ADD(_pdev, \ + pub.tx.tso.tso_hist.pkts_16_20, 1); \ + } else if (_p_cntrs > 20) { \ + TXRX_STATS_ADD(_pdev, \ + pub.tx.tso.tso_hist.pkts_20_plus, 1); \ + } \ + } while (0) + +#define TXRX_STATS_TSO_RESET_MSDU(pdev, idx) \ + do { \ + pdev->stats.pub.tx.tso.tso_info.tso_msdu_info[idx].num_seg = 0; \ + pdev->stats.pub.tx.tso.tso_info.tso_msdu_info[idx].tso_seg_idx = 0; \ + } while (0) + +#define TXRX_STATS_TSO_MSDU_IDX(pdev) \ + pdev->stats.pub.tx.tso.tso_info.tso_msdu_idx + +#define TXRX_STATS_TSO_MSDU(pdev, idx) \ + pdev->stats.pub.tx.tso.tso_info.tso_msdu_info[idx] + +#define TXRX_STATS_TSO_MSDU_NUM_SEG(pdev, idx) \ + pdev->stats.pub.tx.tso.tso_info.tso_msdu_info[idx].num_seg + +#define TXRX_STATS_TSO_MSDU_GSO_SIZE(pdev, idx) \ + pdev->stats.pub.tx.tso.tso_info.tso_msdu_info[idx].gso_size + +#define TXRX_STATS_TSO_MSDU_TOTAL_LEN(pdev, idx) \ + pdev->stats.pub.tx.tso.tso_info.tso_msdu_info[idx].total_len + +#define TXRX_STATS_TSO_MSDU_NR_FRAGS(pdev, idx) \ + pdev->stats.pub.tx.tso.tso_info.tso_msdu_info[idx].nr_frags + +#define TXRX_STATS_TSO_CURR_MSDU(pdev, idx) \ + TXRX_STATS_TSO_MSDU(pdev, idx) + +#define TXRX_STATS_TSO_SEG_IDX(pdev, idx) \ + TXRX_STATS_TSO_CURR_MSDU(pdev, idx).tso_seg_idx + +#define TXRX_STATS_TSO_INC_SEG(pdev, idx) \ + do { \ + TXRX_STATS_TSO_CURR_MSDU(pdev, idx).num_seg++; \ + TXRX_STATS_TSO_CURR_MSDU(pdev, idx).num_seg &= \ + NUM_MAX_TSO_SEGS_MASK; \ + } while (0) + +#define TXRX_STATS_TSO_RST_SEG(pdev, idx) \ + TXRX_STATS_TSO_CURR_MSDU(pdev, idx).num_seg = 0 + +#define TXRX_STATS_TSO_RST_SEG_IDX(pdev, idx) \ + TXRX_STATS_TSO_CURR_MSDU(pdev, idx).tso_seg_idx = 0 + +#define TXRX_STATS_TSO_SEG(pdev, msdu_idx, seg_idx) \ + TXRX_STATS_TSO_MSDU(pdev, msdu_idx).tso_segs[seg_idx] + +#define TXRX_STATS_TSO_CURR_SEG(pdev, idx) \ + TXRX_STATS_TSO_SEG(pdev, idx, \ + TXRX_STATS_TSO_SEG_IDX(pdev, idx)) \ + +#define TXRX_STATS_TSO_INC_SEG_IDX(pdev, idx) \ + do { \ + TXRX_STATS_TSO_SEG_IDX(pdev, idx)++; \ + TXRX_STATS_TSO_SEG_IDX(pdev, idx) &= NUM_MAX_TSO_SEGS_MASK; \ + } while (0) + +#define TXRX_STATS_TSO_SEG_UPDATE(pdev, idx, tso_seg) \ + (TXRX_STATS_TSO_CURR_SEG(pdev, idx) = tso_seg) + +#define TXRX_STATS_TSO_GSO_SIZE_UPDATE(pdev, idx, size) \ + (TXRX_STATS_TSO_CURR_MSDU(pdev, idx).gso_size = size) + +#define TXRX_STATS_TSO_TOTAL_LEN_UPDATE(pdev, idx, len) \ + (TXRX_STATS_TSO_CURR_MSDU(pdev, idx).total_len = len) + +#define TXRX_STATS_TSO_NUM_FRAGS_UPDATE(pdev, idx, frags) \ + (TXRX_STATS_TSO_CURR_MSDU(pdev, idx).nr_frags = frags) + +#else +#define TXRX_STATS_TSO_HISTOGRAM(_pdev, _p_cntrs) /* no-op */ +#define TXRX_STATS_TSO_RESET_MSDU(pdev, idx) /* no-op */ +#define TXRX_STATS_TSO_MSDU_IDX(pdev) /* no-op */ +#define TXRX_STATS_TSO_MSDU(pdev, idx) /* no-op */ +#define TXRX_STATS_TSO_MSDU_NUM_SEG(pdev, idx) /* no-op */ +#define TXRX_STATS_TSO_CURR_MSDU(pdev, idx) /* no-op */ +#define TXRX_STATS_TSO_INC_MSDU_IDX(pdev) /* no-op */ +#define TXRX_STATS_TSO_SEG_IDX(pdev, idx) /* no-op */ +#define TXRX_STATS_TSO_SEG(pdev, msdu_idx, seg_idx) /* no-op */ +#define TXRX_STATS_TSO_CURR_SEG(pdev, idx) /* no-op */ +#define TXRX_STATS_TSO_INC_SEG_IDX(pdev, idx) /* no-op */ +#define TXRX_STATS_TSO_SEG_UPDATE(pdev, idx, tso_seg) /* no-op */ +#define TXRX_STATS_TSO_INC_SEG(pdev, idx) /* no-op */ +#define TXRX_STATS_TSO_RST_SEG(pdev, idx) /* no-op */ +#define TXRX_STATS_TSO_RST_SEG_IDX(pdev, idx) /* no-op */ +#define TXRX_STATS_TSO_GSO_SIZE_UPDATE(pdev, idx, size) /* no-op */ +#define TXRX_STATS_TSO_TOTAL_LEN_UPDATE(pdev, idx, len) /* no-op */ +#define TXRX_STATS_TSO_NUM_FRAGS_UPDATE(pdev, idx, frags) /* no-op */ +#define TXRX_STATS_TSO_MSDU_GSO_SIZE(pdev, idx) /* no-op */ +#define TXRX_STATS_TSO_MSDU_TOTAL_LEN(pdev, idx) /* no-op */ +#define TXRX_STATS_TSO_MSDU_NR_FRAGS(pdev, idx) /* no-op */ + +#endif /* FEATURE_TSO_DEBUG */ + +#ifdef FEATURE_HL_GROUP_CREDIT_FLOW_CONTROL + +void +ol_txrx_update_group_credit( + struct ol_tx_queue_group_t *group, + int32_t credit, + u_int8_t absolute); +#endif + +#endif /* _OL_TXRX_INTERNAL__H_ */ diff --git a/drivers/staging/qcacld-3.0/core/dp/txrx/ol_txrx_peer_find.c b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_txrx_peer_find.c new file mode 100644 index 0000000000000000000000000000000000000000..ca31b2199f5da3570acd17cf63e425a24b2ea8b0 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_txrx_peer_find.c @@ -0,0 +1,781 @@ +/* + * Copyright (c) 2011-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/*=== includes ===*/ +/* header files for OS primitives */ +#include /* uint32_t, etc. */ +#include /* qdf_mem_malloc, etc. */ +#include /* qdf_device_t, qdf_print */ +/* header files for utilities */ +#include /* TAILQ */ + +/* header files for configuration API */ +#include /* ol_cfg_max_peer_id */ + +/* header files for our internal definitions */ +#include /* ol_txrx_pdev_t, etc. */ +#include /* TXRX_DEBUG_LEVEL */ +#include /* ol_txrx_pdev_t, etc. */ +#include /* ol_txrx_peer_unref_delete */ +#include /* ol_txrx_peer_find_attach, etc. */ +#include +#include "wma_api.h" + +/*=== misc. / utility function definitions ==================================*/ + +static int ol_txrx_log2_ceil(unsigned value) +{ + /* need to switch to unsigned math so that negative values + * will right-shift towards 0 instead of -1 + */ + unsigned tmp = value; + int log2 = -1; + + if (value == 0) { + TXRX_ASSERT2(0); + return 0; + } + + while (tmp) { + log2++; + tmp >>= 1; + } + if (1U << log2 != value) + log2++; + + return log2; +} + +/** + * __ol_txrx_peer_change_ref_cnt() - change peer ref count by the input value + * @peer: pointer to peer structure + * @change: value to add to the peer->ref_cnt, can be negative + * @fname: name of the calling function + * @line: line number of the calling function + * + * Return: the QDF_STATUS return from hdd_execute_config_command + */ +void __ol_txrx_peer_change_ref_cnt(struct ol_txrx_peer_t *peer, + int change, + const char *fname, + int line) +{ + qdf_atomic_add(change, &peer->ref_cnt); + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_HIGH, + "[%s][%d]: peer %p peer->ref_cnt changed by (%d) to %d", + fname, line, peer, change, qdf_atomic_read(&peer->ref_cnt)); +} + +/*=== function definitions for peer MAC addr --> peer object hash table =====*/ + +/* + * TXRX_PEER_HASH_LOAD_FACTOR: + * Multiply by 2 and divide by 2^0 (shift by 0), then round up to a + * power of two. + * This provides at least twice as many bins in the peer hash table + * as there will be entries. + * Having substantially more bins than spaces minimizes the probability of + * having to compare MAC addresses. + * Because the MAC address comparison is fairly efficient, it is okay if the + * hash table is sparsely loaded, but it's generally better to use extra mem + * to keep the table sparse, to keep the lookups as fast as possible. + * An optimization would be to apply a more conservative loading factor for + * high latency, where the lookup happens during the tx classification of + * every tx frame, than for low-latency, where the lookup only happens + * during association, when the PEER_MAP message is received. + */ +#define TXRX_PEER_HASH_LOAD_MULT 2 +#define TXRX_PEER_HASH_LOAD_SHIFT 0 + +static int ol_txrx_peer_find_hash_attach(struct ol_txrx_pdev_t *pdev) +{ + int i, hash_elems, log2; + + /* allocate the peer MAC address -> peer object hash table */ + hash_elems = ol_cfg_max_peer_id(pdev->ctrl_pdev) + 1; + hash_elems *= TXRX_PEER_HASH_LOAD_MULT; + hash_elems >>= TXRX_PEER_HASH_LOAD_SHIFT; + log2 = ol_txrx_log2_ceil(hash_elems); + hash_elems = 1 << log2; + + pdev->peer_hash.mask = hash_elems - 1; + pdev->peer_hash.idx_bits = log2; + /* allocate an array of TAILQ peer object lists */ + pdev->peer_hash.bins = + qdf_mem_malloc(hash_elems * + sizeof(TAILQ_HEAD(anonymous_tail_q, + ol_txrx_peer_t))); + if (!pdev->peer_hash.bins) + return 1; /* failure */ + + for (i = 0; i < hash_elems; i++) + TAILQ_INIT(&pdev->peer_hash.bins[i]); + + return 0; /* success */ +} + +static void ol_txrx_peer_find_hash_detach(struct ol_txrx_pdev_t *pdev) +{ + qdf_mem_free(pdev->peer_hash.bins); +} + +static inline unsigned +ol_txrx_peer_find_hash_index(struct ol_txrx_pdev_t *pdev, + union ol_txrx_align_mac_addr_t *mac_addr) +{ + unsigned index; + + index = + mac_addr->align2.bytes_ab ^ + mac_addr->align2.bytes_cd ^ mac_addr->align2.bytes_ef; + index ^= index >> pdev->peer_hash.idx_bits; + index &= pdev->peer_hash.mask; + return index; +} + +void +ol_txrx_peer_find_hash_add(struct ol_txrx_pdev_t *pdev, + struct ol_txrx_peer_t *peer) +{ + unsigned index; + + index = ol_txrx_peer_find_hash_index(pdev, &peer->mac_addr); + qdf_spin_lock_bh(&pdev->peer_ref_mutex); + /* + * It is important to add the new peer at the tail of the peer list + * with the bin index. Together with having the hash_find function + * search from head to tail, this ensures that if two entries with + * the same MAC address are stored, the one added first will be + * found first. + */ + TAILQ_INSERT_TAIL(&pdev->peer_hash.bins[index], peer, hash_list_elem); + qdf_spin_unlock_bh(&pdev->peer_ref_mutex); +} + +struct ol_txrx_peer_t *ol_txrx_peer_vdev_find_hash(struct ol_txrx_pdev_t *pdev, + struct ol_txrx_vdev_t *vdev, + uint8_t *peer_mac_addr, + int mac_addr_is_aligned, + uint8_t check_valid) +{ + union ol_txrx_align_mac_addr_t local_mac_addr_aligned, *mac_addr; + unsigned index; + struct ol_txrx_peer_t *peer; + + if (mac_addr_is_aligned) { + mac_addr = (union ol_txrx_align_mac_addr_t *)peer_mac_addr; + } else { + qdf_mem_copy(&local_mac_addr_aligned.raw[0], + peer_mac_addr, OL_TXRX_MAC_ADDR_LEN); + mac_addr = &local_mac_addr_aligned; + } + index = ol_txrx_peer_find_hash_index(pdev, mac_addr); + qdf_spin_lock_bh(&pdev->peer_ref_mutex); + TAILQ_FOREACH(peer, &pdev->peer_hash.bins[index], hash_list_elem) { + if (ol_txrx_peer_find_mac_addr_cmp(mac_addr, &peer->mac_addr) == + 0 && (check_valid == 0 || peer->valid) + && peer->vdev == vdev) { + /* found it - increment the ref count before releasing + the lock */ + OL_TXRX_PEER_INC_REF_CNT(peer); + qdf_spin_unlock_bh(&pdev->peer_ref_mutex); + return peer; + } + } + qdf_spin_unlock_bh(&pdev->peer_ref_mutex); + return NULL; /* failure */ +} + +struct ol_txrx_peer_t *ol_txrx_peer_find_hash_find_inc_ref(struct ol_txrx_pdev_t *pdev, + uint8_t *peer_mac_addr, + int mac_addr_is_aligned, + uint8_t check_valid) +{ + union ol_txrx_align_mac_addr_t local_mac_addr_aligned, *mac_addr; + unsigned index; + struct ol_txrx_peer_t *peer; + + if (mac_addr_is_aligned) { + mac_addr = (union ol_txrx_align_mac_addr_t *)peer_mac_addr; + } else { + qdf_mem_copy(&local_mac_addr_aligned.raw[0], + peer_mac_addr, OL_TXRX_MAC_ADDR_LEN); + mac_addr = &local_mac_addr_aligned; + } + index = ol_txrx_peer_find_hash_index(pdev, mac_addr); + qdf_spin_lock_bh(&pdev->peer_ref_mutex); + TAILQ_FOREACH(peer, &pdev->peer_hash.bins[index], hash_list_elem) { + if (ol_txrx_peer_find_mac_addr_cmp(mac_addr, &peer->mac_addr) == + 0 && (check_valid == 0 || peer->valid)) { + /* found it - increment the ref count before + releasing the lock */ + OL_TXRX_PEER_INC_REF_CNT(peer); + qdf_spin_unlock_bh(&pdev->peer_ref_mutex); + return peer; + } + } + qdf_spin_unlock_bh(&pdev->peer_ref_mutex); + return NULL; /* failure */ +} + +void +ol_txrx_peer_find_hash_remove(struct ol_txrx_pdev_t *pdev, + struct ol_txrx_peer_t *peer) +{ + unsigned index; + + index = ol_txrx_peer_find_hash_index(pdev, &peer->mac_addr); + /* + * DO NOT take the peer_ref_mutex lock here - it needs to be taken + * by the caller. + * The caller needs to hold the lock from the time the peer object's + * reference count is decremented and tested up through the time the + * reference to the peer object is removed from the hash table, by + * this function. + * Holding the lock only while removing the peer object reference + * from the hash table keeps the hash table consistent, but does not + * protect against a new HL tx context starting to use the peer object + * if it looks up the peer object from its MAC address just after the + * peer ref count is decremented to zero, but just before the peer + * object reference is removed from the hash table. + */ + /* qdf_spin_lock_bh(&pdev->peer_ref_mutex); */ + TAILQ_REMOVE(&pdev->peer_hash.bins[index], peer, hash_list_elem); + /* qdf_spin_unlock_bh(&pdev->peer_ref_mutex); */ +} + +void ol_txrx_peer_find_hash_erase(struct ol_txrx_pdev_t *pdev) +{ + unsigned i; + /* + * Not really necessary to take peer_ref_mutex lock - by this point, + * it's known that the pdev is no longer in use. + */ + + for (i = 0; i <= pdev->peer_hash.mask; i++) { + if (!TAILQ_EMPTY(&pdev->peer_hash.bins[i])) { + struct ol_txrx_peer_t *peer, *peer_next; + + /* + * TAILQ_FOREACH_SAFE must be used here to avoid any + * memory access violation after peer is freed + */ + TAILQ_FOREACH_SAFE(peer, &pdev->peer_hash.bins[i], + hash_list_elem, peer_next) { + /* + * Don't remove the peer from the hash table - + * that would modify the list we are currently + * traversing, + * and it's not necessary anyway. + */ + /* + * Artificially adjust the peer's ref count to + * 1, so it will get deleted by + * OL_TXRX_PEER_UNREF_DELETE. + */ + qdf_atomic_init(&peer->ref_cnt); /* set to 0 */ + OL_TXRX_PEER_INC_REF_CNT(peer); /* incr to 1 */ + OL_TXRX_PEER_UNREF_DELETE(peer); + } + } + } +} + +/*=== function definitions for peer id --> peer object map ==================*/ + +static int ol_txrx_peer_find_map_attach(struct ol_txrx_pdev_t *pdev) +{ + int max_peers, peer_map_size; + + /* allocate the peer ID -> peer object map */ + max_peers = ol_cfg_max_peer_id(pdev->ctrl_pdev) + 1; + peer_map_size = max_peers * sizeof(pdev->peer_id_to_obj_map[0]); + pdev->peer_id_to_obj_map = qdf_mem_malloc(peer_map_size); + if (!pdev->peer_id_to_obj_map) + return 1; /* failure */ + + return 0; /* success */ +} + +static void ol_txrx_peer_find_map_detach(struct ol_txrx_pdev_t *pdev) +{ + qdf_mem_free(pdev->peer_id_to_obj_map); +} + +/** + * ol_txrx_peer_clear_map_peer() - Remove map entries that refer to a peer. + * @pdev: pdev handle + * @peer: peer for removing obj map entries + * + * Run through the entire peer_id_to_obj map and nullify all the entries + * that map to a particular peer. Called before deleting the peer object. + * + * Return: None + */ +void ol_txrx_peer_clear_map_peer(ol_txrx_pdev_handle pdev, + struct ol_txrx_peer_t *peer) +{ + int max_peers; + int i; + + max_peers = ol_cfg_max_peer_id(pdev->ctrl_pdev) + 1; + + qdf_spin_lock_bh(&pdev->peer_map_unmap_lock); + for (i = 0; i < max_peers; i++) { + if (pdev->peer_id_to_obj_map[i].peer == peer) { + /* Found a map entry for this peer, clear it. */ + pdev->peer_id_to_obj_map[i].peer = NULL; + } + } + qdf_spin_unlock_bh(&pdev->peer_map_unmap_lock); +} + +/* + * ol_txrx_peer_find_add_id() - Add peer_id entry to peer + * + * @pdev: Handle to pdev object + * @peer_mac_addr: MAC address of peer provided by firmware + * @peer_id: peer_id provided by firmware + * + * Search for peer object for the MAC address, add the peer_id to + * its array of peer_id's and update the peer_id_to_obj map entry + * for that peer_id. Increment corresponding reference counts. + * + * Riva/Pronto has one peer id for each peer. + * Peregrine/Rome has two peer id for each peer. + * iHelium has upto three peer id for each peer. + * + * Return: None + */ +static inline void ol_txrx_peer_find_add_id(struct ol_txrx_pdev_t *pdev, + uint8_t *peer_mac_addr, uint16_t peer_id) +{ + struct ol_txrx_peer_t *peer; + int status; + int i; + uint32_t peer_id_ref_cnt; + uint32_t peer_ref_cnt; + + /* check if there's already a peer object with this MAC address */ + peer = + ol_txrx_peer_find_hash_find_inc_ref(pdev, peer_mac_addr, + 1 /* is aligned */, 0); + + if (!peer || peer_id == HTT_INVALID_PEER) { + /* + * Currently peer IDs are assigned for vdevs as well as peers. + * If the peer ID is for a vdev, then we will fail to find a + * peer with a matching MAC address. + */ + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "%s: peer not found or peer ID is %d invalid", + __func__, peer_id); + wma_peer_debug_log(DEBUG_INVALID_VDEV_ID, DEBUG_PEER_MAP_EVENT, + peer_id, peer_mac_addr, peer, 0, 0); + + return; + } + + qdf_spin_lock(&pdev->peer_map_unmap_lock); + + /* peer's ref count was already incremented by + * peer_find_hash_find + */ + if (!pdev->peer_id_to_obj_map[peer_id].peer) { + pdev->peer_id_to_obj_map[peer_id].peer = peer; + qdf_atomic_init + (&pdev->peer_id_to_obj_map[peer_id].peer_id_ref_cnt); + } + qdf_atomic_inc + (&pdev->peer_id_to_obj_map[peer_id].peer_id_ref_cnt); + + status = 1; + + /* find a place in peer_id array and insert peer_id */ + for (i = 0; i < MAX_NUM_PEER_ID_PER_PEER; i++) { + if (peer->peer_ids[i] == HTT_INVALID_PEER) { + peer->peer_ids[i] = peer_id; + status = 0; + break; + } + } + + if (qdf_atomic_read(&peer->fw_create_pending) == 1) { + /* + * First peer map event signifies successful peer + * creation in firmware. Decrement the ref count + * which was incremented when peer create command + * was sent to firmware. + */ + qdf_atomic_set(&peer->fw_create_pending, 0); + OL_TXRX_PEER_UNREF_DELETE(peer); + } + + qdf_spin_unlock(&pdev->peer_map_unmap_lock); + + peer_id_ref_cnt = qdf_atomic_read(&pdev-> + peer_id_to_obj_map[peer_id].peer_id_ref_cnt); + peer_ref_cnt = qdf_atomic_read(&peer->ref_cnt); + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: peer %p ID %d peer_id[%d] peer_id_ref_cnt %d", + __func__, peer, peer_id, i, peer_id_ref_cnt); + + wma_peer_debug_log(DEBUG_INVALID_VDEV_ID, DEBUG_PEER_MAP_EVENT, + peer_id, &peer->mac_addr.raw, peer, + peer_id_ref_cnt, + peer_ref_cnt); + + + if (status) { + /* TBDXXX: assert for now */ + qdf_assert(0); + } + + return; +} + +/*=== allocation / deallocation function definitions ========================*/ + +int ol_txrx_peer_find_attach(struct ol_txrx_pdev_t *pdev) +{ + if (ol_txrx_peer_find_map_attach(pdev)) + return 1; + if (ol_txrx_peer_find_hash_attach(pdev)) { + ol_txrx_peer_find_map_detach(pdev); + return 1; + } + return 0; /* success */ +} + +void ol_txrx_peer_find_detach(struct ol_txrx_pdev_t *pdev) +{ + ol_txrx_peer_find_map_detach(pdev); + ol_txrx_peer_find_hash_detach(pdev); +} + +/*=== function definitions for message handling =============================*/ + +#if defined(CONFIG_HL_SUPPORT) + +void +ol_rx_peer_map_handler(ol_txrx_pdev_handle pdev, + uint16_t peer_id, + uint8_t vdev_id, uint8_t *peer_mac_addr, int tx_ready) +{ + ol_txrx_peer_find_add_id(pdev, peer_mac_addr, peer_id); + if (!tx_ready) { + struct ol_txrx_peer_t *peer; + peer = ol_txrx_peer_find_by_id(pdev, peer_id); + if (!peer) { + /* ol_txrx_peer_detach called before peer map arrived*/ + return; + } else { + if (tx_ready) { + int i; + /* unpause all tx queues now, since the + * target is ready + */ + for (i = 0; i < QDF_ARRAY_SIZE(peer->txqs); + i++) + ol_txrx_peer_tid_unpause(peer, i); + + } else { + /* walk through paused mgmt queue, + * update tx descriptors + */ + ol_tx_queue_decs_reinit(peer, peer_id); + + /* keep non-mgmt tx queues paused until assoc + * is finished tx queues were paused in + * ol_txrx_peer_attach*/ + /* unpause tx mgmt queue */ + ol_txrx_peer_tid_unpause(peer, + HTT_TX_EXT_TID_MGMT); + } + } + } +} + +void ol_txrx_peer_tx_ready_handler(ol_txrx_pdev_handle pdev, uint16_t peer_id) +{ + struct ol_txrx_peer_t *peer; + peer = ol_txrx_peer_find_by_id(pdev, peer_id); + if (peer) { + int i; + /* + * Unpause all data tx queues now that the target is ready. + * The mgmt tx queue was not paused, so skip it. + */ + for (i = 0; i < QDF_ARRAY_SIZE(peer->txqs); i++) { + if (i == HTT_TX_EXT_TID_MGMT) + continue; /* mgmt tx queue was not paused */ + + ol_txrx_peer_tid_unpause(peer, i); + } + } +} +#else + +void +ol_rx_peer_map_handler(ol_txrx_pdev_handle pdev, + uint16_t peer_id, + uint8_t vdev_id, + uint8_t *peer_mac_addr, + int tx_ready) +{ + ol_txrx_peer_find_add_id(pdev, peer_mac_addr, peer_id); + +} + +void ol_txrx_peer_tx_ready_handler(ol_txrx_pdev_handle pdev, uint16_t peer_id) +{ + return; +} + +#endif + +/* + * ol_rx_peer_unmap_handler() - Handle peer unmap event from firmware + * + * @pdev: Handle to pdev pbject + * @peer_id: peer_id unmapped by firmware + * + * Decrement reference count for the peer_id in peer_id_to_obj_map, + * decrement reference count in corresponding peer object and clear the entry + * in peer's peer_ids array. + * In case of unmap events for a peer that is already deleted, just decrement + * del_peer_id_ref_cnt. + * + * Return: None + */ +void ol_rx_peer_unmap_handler(ol_txrx_pdev_handle pdev, uint16_t peer_id) +{ + struct ol_txrx_peer_t *peer; + int i = 0; + int32_t ref_cnt; + + + if (peer_id == HTT_INVALID_PEER) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "%s: invalid peer ID %d\n", __func__, peer_id); + wma_peer_debug_log(DEBUG_INVALID_VDEV_ID, + DEBUG_PEER_UNMAP_EVENT, + peer_id, NULL, NULL, 0, 0x100); + return; + } + + qdf_spin_lock_bh(&pdev->peer_map_unmap_lock); + + if (qdf_atomic_read( + &pdev->peer_id_to_obj_map[peer_id].del_peer_id_ref_cnt)) { + /* This peer_id belongs to a peer already deleted */ + qdf_atomic_dec(&pdev->peer_id_to_obj_map[peer_id]. + del_peer_id_ref_cnt); + ref_cnt = qdf_atomic_read(&pdev->peer_id_to_obj_map[peer_id]. + del_peer_id_ref_cnt); + qdf_spin_unlock_bh(&pdev->peer_map_unmap_lock); + wma_peer_debug_log(DEBUG_INVALID_VDEV_ID, + DEBUG_PEER_UNMAP_EVENT, + peer_id, NULL, NULL, ref_cnt, 0x101); + TXRX_PRINT(TXRX_PRINT_LEVEL_INFO1, + "%s: peer already deleted, peer_id %d del_peer_id_ref_cnt %d", + __func__, peer_id, ref_cnt); + return; + } + peer = pdev->peer_id_to_obj_map[peer_id].peer; + if (peer == NULL) { + /* + * Currently peer IDs are assigned for vdevs as well as peers. + * If the peer ID is for a vdev, then the peer pointer stored + * in peer_id_to_obj_map will be NULL. + */ + qdf_spin_unlock_bh(&pdev->peer_map_unmap_lock); + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "%s: peer not found for peer_id %d", + __func__, peer_id); + wma_peer_debug_log(DEBUG_INVALID_VDEV_ID, + DEBUG_PEER_UNMAP_EVENT, + peer_id, NULL, NULL, 0, 0x102); + + return; + } + + if (qdf_atomic_dec_and_test + (&pdev->peer_id_to_obj_map[peer_id].peer_id_ref_cnt)) { + pdev->peer_id_to_obj_map[peer_id].peer = NULL; + for (i = 0; i < MAX_NUM_PEER_ID_PER_PEER; i++) { + if (peer->peer_ids[i] == peer_id) { + peer->peer_ids[i] = HTT_INVALID_PEER; + break; + } + } + } + + ref_cnt = qdf_atomic_read + (&pdev->peer_id_to_obj_map[peer_id].peer_id_ref_cnt); + + qdf_spin_unlock_bh(&pdev->peer_map_unmap_lock); + + wma_peer_debug_log(DEBUG_INVALID_VDEV_ID, DEBUG_PEER_UNMAP_EVENT, + peer_id, &peer->mac_addr.raw, peer, ref_cnt, + qdf_atomic_read(&peer->ref_cnt)); + + /* + * Remove a reference to the peer. + * If there are no more references, delete the peer object. + */ + OL_TXRX_PEER_UNREF_DELETE(peer); + + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO, + "%s: peer_id %d peer %p peer_id_ref_cnt %d", + __func__, peer_id, peer, ref_cnt); +} + +/** + * ol_txrx_peer_remove_obj_map_entries() - Remove matching pdev peer map entries + * @pdev: pdev handle + * @peer: peer for removing obj map entries + * + * Saves peer_id_ref_cnt to a different field and removes the link + * to peer object. It also decrements the peer reference count by + * the number of references removed. + * + * Return: None + */ +void ol_txrx_peer_remove_obj_map_entries(ol_txrx_pdev_handle pdev, + struct ol_txrx_peer_t *peer) +{ + int i; + uint16_t peer_id; + int32_t peer_id_ref_cnt; + int32_t num_deleted_maps = 0; + + qdf_spin_lock_bh(&pdev->peer_map_unmap_lock); + for (i = 0; i < MAX_NUM_PEER_ID_PER_PEER; i++) { + peer_id = peer->peer_ids[i]; + if (peer_id == HTT_INVALID_PEER || + pdev->peer_id_to_obj_map[peer_id].peer == NULL) { + /* unused peer_id, or object is already dereferenced */ + continue; + } + if (pdev->peer_id_to_obj_map[peer_id].peer != peer) { + QDF_TRACE(QDF_MODULE_ID_TXRX, + QDF_TRACE_LEVEL_ERROR, + FL("peer pointer mismatch in peer_id_to_obj")); + continue; + } + peer_id_ref_cnt = qdf_atomic_read( + &pdev->peer_id_to_obj_map[peer_id]. + peer_id_ref_cnt); + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_LOW, + FL("peer_id = %d, peer_id_ref_cnt = %d, index = %d"), + peer_id, peer_id_ref_cnt, i); + /* + * Transfer peer_id_ref_cnt into del_peer_id_ref_cnt so that + * OL_TXRX_PEER_UNREF_DELETE will decrement del_peer_id_ref_cnt + * and any map events will increment peer_id_ref_cnt. Otherwise + * accounting will be messed up. + * + * Add operation will ensure that back to back roaming in the + * middle of unmap/map event sequence will be accounted for. + */ + qdf_atomic_add(peer_id_ref_cnt, + &pdev->peer_id_to_obj_map[peer_id].del_peer_id_ref_cnt); + qdf_atomic_init(&pdev->peer_id_to_obj_map[peer_id]. + peer_id_ref_cnt); + num_deleted_maps += peer_id_ref_cnt; + pdev->peer_id_to_obj_map[peer_id].peer = NULL; + peer->peer_ids[i] = HTT_INVALID_PEER; + } + qdf_spin_unlock_bh(&pdev->peer_map_unmap_lock); + + while (num_deleted_maps-- > 0) + OL_TXRX_PEER_UNREF_DELETE(peer); +} + +struct ol_txrx_peer_t *ol_txrx_assoc_peer_find(struct ol_txrx_vdev_t *vdev) +{ + struct ol_txrx_peer_t *peer; + + qdf_spin_lock_bh(&vdev->pdev->last_real_peer_mutex); + /* + * Check the TXRX Peer is itself valid And also + * if HTT Peer ID has been setup for this peer + */ + if (vdev->last_real_peer + && vdev->last_real_peer->peer_ids[0] != HTT_INVALID_PEER_ID) { + OL_TXRX_PEER_INC_REF_CNT(vdev->last_real_peer); + peer = vdev->last_real_peer; + } else { + peer = NULL; + } + qdf_spin_unlock_bh(&vdev->pdev->last_real_peer_mutex); + return peer; +} + + +/*=== function definitions for debug ========================================*/ + +#if defined(TXRX_DEBUG_LEVEL) && TXRX_DEBUG_LEVEL > 5 +void ol_txrx_peer_find_display(ol_txrx_pdev_handle pdev, int indent) +{ + int i, max_peers; + + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_LOW, + "%*speer map:\n", indent, " "); + max_peers = ol_cfg_max_peer_id(pdev->ctrl_pdev) + 1; + for (i = 0; i < max_peers; i++) { + if (pdev->peer_id_to_obj_map[i].peer) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_LOW, + "%*sid %d -> %p\n", + indent + 4, " ", i, + pdev->peer_id_to_obj_map[i].peer); + } + } + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_LOW, + "%*speer hash table:\n", indent, " "); + for (i = 0; i <= pdev->peer_hash.mask; i++) { + if (!TAILQ_EMPTY(&pdev->peer_hash.bins[i])) { + struct ol_txrx_peer_t *peer; + TAILQ_FOREACH(peer, &pdev->peer_hash.bins[i], + hash_list_elem) { + QDF_TRACE(QDF_MODULE_ID_TXRX, + QDF_TRACE_LEVEL_INFO_LOW, + "%*shash idx %d -> %p (%02x:%02x:%02x:%02x:%02x:%02x)\n", + indent + 4, " ", i, peer, + peer->mac_addr.raw[0], + peer->mac_addr.raw[1], + peer->mac_addr.raw[2], + peer->mac_addr.raw[3], + peer->mac_addr.raw[4], + peer->mac_addr.raw[5]); + } + } + } +} + +#endif /* if TXRX_DEBUG_LEVEL */ diff --git a/drivers/staging/qcacld-3.0/core/dp/txrx/ol_txrx_peer_find.h b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_txrx_peer_find.h new file mode 100644 index 0000000000000000000000000000000000000000..4994a03b1a38562d574a21b54f29fa2d9d200cdb --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_txrx_peer_find.h @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2011, 2015-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * @file ol_txrx_peer_find.h + * @brief Define the API for the rx peer lookup datapath module. + */ +#ifndef _OL_TXRX_PEER_FIND__H_ +#define _OL_TXRX_PEER_FIND__H_ + +#include /* HTT_INVALID_PEER */ +#include /* ol_txrx_pdev_t, etc. */ +#include /* TXRX_ASSERT */ + + +#define OL_TXRX_PEER_INC_REF_CNT(peer) \ + __ol_txrx_peer_change_ref_cnt(peer, 1, __func__, __LINE__); + +void __ol_txrx_peer_change_ref_cnt(struct ol_txrx_peer_t *peer, + int change, + const char *fname, + int line); +int ol_txrx_peer_find_attach(struct ol_txrx_pdev_t *pdev); + +void ol_txrx_peer_find_detach(struct ol_txrx_pdev_t *pdev); + +static inline +int +ol_txrx_peer_find_mac_addr_cmp(union ol_txrx_align_mac_addr_t *mac_addr1, + union ol_txrx_align_mac_addr_t *mac_addr2) +{ + return !((mac_addr1->align4.bytes_abcd == mac_addr2->align4.bytes_abcd) + /* + * Intentionally use & rather than &&. + * because the operands are binary rather than generic bool, + * the functionality is equivalent. + * Using && has the advantage of short-circuited evaluation, + * but using & has the advantage of no conditional branching, + * which is a more significant benefit. + */ + & (mac_addr1->align4.bytes_ef == mac_addr2->align4.bytes_ef)); +} + +static inline +struct ol_txrx_peer_t *ol_txrx_peer_find_by_id(struct ol_txrx_pdev_t *pdev, + uint16_t peer_id) +{ + struct ol_txrx_peer_t *peer; + peer = (peer_id > ol_cfg_max_peer_id(pdev->ctrl_pdev)) ? NULL : + pdev->peer_id_to_obj_map[peer_id].peer; + /* + * Currently, peer IDs are assigned to vdevs as well as peers. + * If the peer ID is for a vdev, the peer_id_to_obj_map entry + * will hold NULL rather than a valid peer pointer. + */ + /* TXRX_ASSERT2(peer != NULL); */ + /* + * Only return the peer object if it is valid, + * i.e. it has not already been detached. + * If it has already been detached, then returning the + * peer object could result in unpausing the peer's tx queues + * in HL systems, which is an invalid operation following peer_detach. + */ + if (peer && peer->valid) + return peer; + + return NULL; +} + +void +ol_txrx_peer_find_hash_add(struct ol_txrx_pdev_t *pdev, + struct ol_txrx_peer_t *peer); + +struct ol_txrx_peer_t *ol_txrx_peer_find_hash_find_inc_ref(struct ol_txrx_pdev_t *pdev, + uint8_t *peer_mac_addr, + int mac_addr_is_aligned, + uint8_t check_valid); + +struct +ol_txrx_peer_t *ol_txrx_peer_vdev_find_hash(struct ol_txrx_pdev_t *pdev, + struct ol_txrx_vdev_t *vdev, + uint8_t *peer_mac_addr, + int mac_addr_is_aligned, + uint8_t check_valid); + +void +ol_txrx_peer_find_hash_remove(struct ol_txrx_pdev_t *pdev, + struct ol_txrx_peer_t *peer); + +void ol_txrx_peer_find_hash_erase(struct ol_txrx_pdev_t *pdev); + +struct ol_txrx_peer_t *ol_txrx_assoc_peer_find(struct ol_txrx_vdev_t *vdev); +void ol_txrx_peer_remove_obj_map_entries(ol_txrx_pdev_handle pdev, + struct ol_txrx_peer_t *peer); +void ol_txrx_peer_clear_map_peer(ol_txrx_pdev_handle pdev, + struct ol_txrx_peer_t *peer); +#if defined(TXRX_DEBUG_LEVEL) && TXRX_DEBUG_LEVEL > 5 +void ol_txrx_peer_find_display(ol_txrx_pdev_handle pdev, int indent); +#else +#define ol_txrx_peer_find_display(pdev, indent) +#endif /* TXRX_DEBUG_LEVEL */ + +#endif /* _OL_TXRX_PEER_FIND__H_ */ diff --git a/drivers/staging/qcacld-3.0/core/dp/txrx/ol_txrx_types.h b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_txrx_types.h new file mode 100644 index 0000000000000000000000000000000000000000..3d244cdb2b5449f88f8f89f4b499f1b68b149bcf --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/dp/txrx/ol_txrx_types.h @@ -0,0 +1,1325 @@ +/* + * Copyright (c) 2013-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * @file ol_txrx_types.h + * @brief Define the major data types used internally by the host datapath SW. + */ +#ifndef _OL_TXRX_TYPES__H_ +#define _OL_TXRX_TYPES__H_ + +#include /* qdf_nbuf_t */ +#include +#include /* TAILQ */ +#include /* A_UINT8 */ +#include /* htt_sec_type, htt_pkt_type, etc. */ +#include /* qdf_atomic_t */ +#include /* wdi_event_subscribe */ +#include /* qdf_timer_t */ +#include /* qdf_spinlock */ +#include /* ol_pktlog_dev_handle */ +#include +#include +#include "ol_txrx_htt_api.h" +#include "ol_htt_tx_api.h" +#include "ol_htt_rx_api.h" +#include "ol_txrx_ctrl_api.h" /* WLAN_MAX_STA_COUNT */ +#include "ol_txrx_osif_api.h" /* ol_rx_callback_fp */ +#include "cdp_txrx_flow_ctrl_v2.h" +#include "cdp_txrx_peer_ops.h" + +/* + * The target may allocate multiple IDs for a peer. + * In particular, the target may allocate one ID to represent the + * multicast key the peer uses, and another ID to represent the + * unicast key the peer uses. + */ +#define MAX_NUM_PEER_ID_PER_PEER 16 + +#define OL_TXRX_INVALID_NUM_PEERS (-1) + +#define OL_TXRX_MAC_ADDR_LEN 6 + +/* OL_TXRX_NUM_EXT_TIDS - + * 16 "real" TIDs + 3 pseudo-TIDs for mgmt, mcast/bcast & non-QoS data + */ +#define OL_TXRX_NUM_EXT_TIDS 19 + +#define OL_TX_NUM_QOS_TIDS 16 /* 16 regular TIDs */ +#define OL_TX_NON_QOS_TID 16 +#define OL_TX_MGMT_TID 17 +#define OL_TX_NUM_TIDS 18 +#define OL_RX_MCAST_TID 18 /* Mcast TID only between f/w & host */ + +#define OL_TX_VDEV_MCAST_BCAST 0 /* HTT_TX_EXT_TID_MCAST_BCAST */ +#define OL_TX_VDEV_DEFAULT_MGMT 1 /* HTT_TX_EXT_TID_DEFALT_MGMT */ +#define OL_TX_VDEV_NUM_QUEUES 2 + +#define OL_TXRX_MGMT_TYPE_BASE htt_pkt_num_types +#define OL_TXRX_MGMT_NUM_TYPES 8 + +#define OL_TX_MUTEX_TYPE qdf_spinlock_t +#define OL_RX_MUTEX_TYPE qdf_spinlock_t + +/* TXRX Histogram defines */ +#define TXRX_DATA_HISTROGRAM_GRANULARITY 1000 +#define TXRX_DATA_HISTROGRAM_NUM_INTERVALS 100 + +#define OL_TXRX_INVALID_VDEV_ID (-1) + +struct ol_txrx_pdev_t; +struct ol_txrx_vdev_t; +struct ol_txrx_peer_t; + +/* rx filter related */ +#define MAX_PRIVACY_FILTERS 4 /* max privacy filters */ + +enum privacy_filter { + PRIVACY_FILTER_ALWAYS, + PRIVACY_FILTER_KEY_UNAVAILABLE, +}; + +enum privacy_filter_packet_type { + PRIVACY_FILTER_PACKET_UNICAST, + PRIVACY_FILTER_PACKET_MULTICAST, + PRIVACY_FILTER_PACKET_BOTH +}; + +struct privacy_exemption { + /* ethertype - + * type of ethernet frames this filter applies to, in host byte order + */ + uint16_t ether_type; + enum privacy_filter filter_type; + enum privacy_filter_packet_type packet_type; +}; + +enum ol_tx_frm_type { + OL_TX_FRM_STD = 0, /* regular frame - no added header fragments */ + OL_TX_FRM_TSO, /* TSO segment, with a modified IP header added */ + OL_TX_FRM_AUDIO, /* audio frames, with a custom LLC/SNAP hdr added */ + OL_TX_FRM_NO_FREE, /* frame requires special tx completion callback */ + ol_tx_frm_freed = 0xff, /* the tx desc is in free list */ +}; + +#if defined(CONFIG_HL_SUPPORT) && defined(QCA_BAD_PEER_TX_FLOW_CL) + +#define MAX_NO_PEERS_IN_LIMIT (2*10 + 2) + +enum ol_tx_peer_bal_state { + ol_tx_peer_bal_enable = 0, + ol_tx_peer_bal_disable, +}; + +enum ol_tx_peer_bal_timer_state { + ol_tx_peer_bal_timer_disable = 0, + ol_tx_peer_bal_timer_active, + ol_tx_peer_bal_timer_inactive, +}; + +struct ol_tx_limit_peer_t { + u_int16_t limit_flag; + u_int16_t peer_id; + u_int16_t limit; +}; + +enum tx_peer_level { + TXRX_IEEE11_B = 0, + TXRX_IEEE11_A_G, + TXRX_IEEE11_N, + TXRX_IEEE11_AC, + TXRX_IEEE11_MAX, +}; + +struct tx_peer_threshold { + u_int32_t tput_thresh; + u_int32_t tx_limit; +}; +#endif + + +struct ol_tx_desc_t { + qdf_nbuf_t netbuf; + void *htt_tx_desc; + uint16_t id; + qdf_dma_addr_t htt_tx_desc_paddr; + void *htt_frag_desc; /* struct msdu_ext_desc_t * */ + qdf_dma_addr_t htt_frag_desc_paddr; + qdf_atomic_t ref_cnt; + enum htt_tx_status status; + +#ifdef QCA_COMPUTE_TX_DELAY + uint32_t entry_timestamp_ticks; +#endif + /* + * Allow tx descriptors to be stored in (doubly-linked) lists. + * This is mainly used for HL tx queuing and scheduling, but is + * also used by LL+HL for batch processing of tx frames. + */ + TAILQ_ENTRY(ol_tx_desc_t) tx_desc_list_elem; + + /* + * Remember whether the tx frame is a regular packet, or whether + * the driver added extra header fragments (e.g. a modified IP header + * for TSO fragments, or an added LLC/SNAP header for audio interworking + * data) that need to be handled in a special manner. + * This field is filled in with the ol_tx_frm_type enum. + */ + uint8_t pkt_type; + + u_int8_t vdev_id; + + struct ol_txrx_vdev_t *vdev; + + void *txq; + +#ifdef QCA_SUPPORT_SW_TXRX_ENCAP + /* used by tx encap, to restore the os buf start offset + after tx complete */ + uint8_t orig_l2_hdr_bytes; +#endif + +#ifdef QCA_LL_TX_FLOW_CONTROL_V2 + struct ol_tx_flow_pool_t *pool; +#endif + void *tso_desc; + void *tso_num_desc; +}; + +typedef TAILQ_HEAD(some_struct_name, ol_tx_desc_t) ol_tx_desc_list; + +union ol_tx_desc_list_elem_t { + union ol_tx_desc_list_elem_t *next; + struct ol_tx_desc_t tx_desc; +}; + +union ol_txrx_align_mac_addr_t { + uint8_t raw[OL_TXRX_MAC_ADDR_LEN]; + struct { + uint16_t bytes_ab; + uint16_t bytes_cd; + uint16_t bytes_ef; + } align2; + struct { + uint32_t bytes_abcd; + uint16_t bytes_ef; + } align4; +}; + +struct ol_rx_reorder_timeout_list_elem_t { + TAILQ_ENTRY(ol_rx_reorder_timeout_list_elem_t) + reorder_timeout_list_elem; + uint32_t timestamp_ms; + struct ol_txrx_peer_t *peer; + uint8_t tid; + uint8_t active; +}; + +#define TXRX_TID_TO_WMM_AC(_tid) ( \ + (((_tid) >> 1) == 3) ? TXRX_WMM_AC_VO : \ + (((_tid) >> 1) == 2) ? TXRX_WMM_AC_VI : \ + (((_tid) ^ ((_tid) >> 1)) & 0x1) ? TXRX_WMM_AC_BK : \ + TXRX_WMM_AC_BE) + +enum { + OL_TX_SCHED_WRR_ADV_CAT_BE, + OL_TX_SCHED_WRR_ADV_CAT_BK, + OL_TX_SCHED_WRR_ADV_CAT_VI, + OL_TX_SCHED_WRR_ADV_CAT_VO, + OL_TX_SCHED_WRR_ADV_CAT_NON_QOS_DATA, + OL_TX_SCHED_WRR_ADV_CAT_UCAST_MGMT, + OL_TX_SCHED_WRR_ADV_CAT_MCAST_DATA, + OL_TX_SCHED_WRR_ADV_CAT_MCAST_MGMT, + + OL_TX_SCHED_WRR_ADV_NUM_CATEGORIES /* must be last */ +}; + +struct ol_tx_reorder_cat_timeout_t { + TAILQ_HEAD(, ol_rx_reorder_timeout_list_elem_t) virtual_timer_list; + qdf_timer_t timer; + uint32_t duration_ms; + struct ol_txrx_pdev_t *pdev; +}; + +enum ol_tx_scheduler_status { + ol_tx_scheduler_idle = 0, + ol_tx_scheduler_running, +}; + +enum ol_tx_queue_status { + ol_tx_queue_empty = 0, + ol_tx_queue_active, + ol_tx_queue_paused, +}; + +struct ol_txrx_msdu_info_t { + struct htt_msdu_info_t htt; + struct ol_txrx_peer_t *peer; + struct qdf_tso_info_t tso_info; +}; + +enum { + ol_tx_aggr_untried = 0, + ol_tx_aggr_enabled, + ol_tx_aggr_disabled, + ol_tx_aggr_retry, + ol_tx_aggr_in_progress, +}; + +#define OL_TX_MAX_GROUPS_PER_QUEUE 1 +#define OL_TX_MAX_VDEV_ID 16 +#define OL_TXQ_GROUP_VDEV_ID_MASK_GET(_membership) \ + (((_membership) & 0xffff0000) >> 16) +#define OL_TXQ_GROUP_VDEV_ID_BIT_MASK_GET(_mask, _vdev_id) \ + ((_mask >> _vdev_id) & 0x01) +#define OL_TXQ_GROUP_AC_MASK_GET(_membership) \ + ((_membership) & 0x0000ffff) +#define OL_TXQ_GROUP_AC_BIT_MASK_GET(_mask, _ac_mask) \ + ((_mask >> _ac_mask) & 0x01) +#define OL_TXQ_GROUP_MEMBERSHIP_GET(_vdev_mask, _ac_mask) \ + ((_vdev_mask << 16) | _ac_mask) + +struct ol_tx_frms_queue_t { + /* list_elem - + * Allow individual tx frame queues to be linked together into + * scheduler queues of tx frame queues + */ + TAILQ_ENTRY(ol_tx_frms_queue_t) list_elem; + uint8_t aggr_state; + struct { + uint8_t total; + /* pause requested by ctrl SW rather than txrx SW */ + uint8_t by_ctrl; + } paused_count; + uint8_t ext_tid; + uint16_t frms; + uint32_t bytes; + ol_tx_desc_list head; + enum ol_tx_queue_status flag; + struct ol_tx_queue_group_t *group_ptrs[OL_TX_MAX_GROUPS_PER_QUEUE]; +#if defined(CONFIG_HL_SUPPORT) && defined(QCA_BAD_PEER_TX_FLOW_CL) + struct ol_txrx_peer_t *peer; +#endif +}; + +enum { + ol_tx_log_entry_type_invalid, + ol_tx_log_entry_type_queue_state, + ol_tx_log_entry_type_enqueue, + ol_tx_log_entry_type_dequeue, + ol_tx_log_entry_type_drop, + ol_tx_log_entry_type_queue_free, + + ol_tx_log_entry_type_wrap, +}; + +struct ol_tx_log_queue_state_var_sz_t { + uint32_t active_bitmap; + uint16_t credit; + uint8_t num_cats_active; + uint8_t data[1]; +}; + +struct ol_tx_log_queue_add_t { + uint8_t num_frms; + uint8_t tid; + uint16_t peer_id; + uint16_t num_bytes; +}; + +struct ol_mac_addr { + uint8_t mac_addr[OL_TXRX_MAC_ADDR_LEN]; +}; + +struct ol_tx_sched_t; + + +#ifndef OL_TXRX_NUM_LOCAL_PEER_IDS +/* + * Each AP will occupy one ID, so it will occupy two IDs for AP-AP mode. + * And the remainder IDs will be assigned to other 32 clients. + */ +#define OL_TXRX_NUM_LOCAL_PEER_IDS (2 + 32) +#endif + +#ifndef ol_txrx_local_peer_id_t +#define ol_txrx_local_peer_id_t uint8_t /* default */ +#endif + +#ifdef QCA_COMPUTE_TX_DELAY +/* + * Delay histogram bins: 16 bins of 10 ms each to count delays + * from 0-160 ms, plus one overflow bin for delays > 160 ms. + */ +#define QCA_TX_DELAY_HIST_INTERNAL_BINS 17 +#define QCA_TX_DELAY_HIST_INTERNAL_BIN_WIDTH_MS 10 + +struct ol_tx_delay_data { + struct { + uint64_t transmit_sum_ticks; + uint64_t queue_sum_ticks; + uint32_t transmit_num; + uint32_t queue_num; + } avgs; + uint16_t hist_bins_queue[QCA_TX_DELAY_HIST_INTERNAL_BINS]; +}; + +#endif /* QCA_COMPUTE_TX_DELAY */ + +/* Thermal Mitigation */ + +enum throttle_level { + THROTTLE_LEVEL_0, + THROTTLE_LEVEL_1, + THROTTLE_LEVEL_2, + THROTTLE_LEVEL_3, + /* Invalid */ + THROTTLE_LEVEL_MAX, +}; + +enum throttle_phase { + THROTTLE_PHASE_OFF, + THROTTLE_PHASE_ON, + /* Invalid */ + THROTTLE_PHASE_MAX, +}; + +#define THROTTLE_TX_THRESHOLD (100) + +typedef void (*ipa_uc_op_cb_type)(uint8_t *op_msg, void *osif_ctxt); + +struct ol_tx_queue_group_t { + qdf_atomic_t credit; + u_int32_t membership; +}; +#define OL_TX_MAX_TXQ_GROUPS 2 + +#define OL_TX_GROUP_STATS_LOG_SIZE 128 +struct ol_tx_group_credit_stats_t { + struct { + struct { + u_int16_t member_vdevs; + u_int16_t credit; + } grp[OL_TX_MAX_TXQ_GROUPS]; + } stats[OL_TX_GROUP_STATS_LOG_SIZE]; + u_int16_t last_valid_index; + u_int16_t wrap_around; +}; + +#ifdef QCA_LL_TX_FLOW_CONTROL_V2 + +/** + * enum flow_pool_status - flow pool status + * @FLOW_POOL_ACTIVE_UNPAUSED : pool is active (can take/put descriptors) + * and network queues are unpaused + * @FLOW_POOL_ACTIVE_PAUSED: pool is active (can take/put descriptors) + * and network queues are paused + * @FLOW_POOL_INVALID: pool is invalid (put descriptor) + * @FLOW_POOL_INACTIVE: pool is inactive (pool is free) + */ +enum flow_pool_status { + FLOW_POOL_ACTIVE_UNPAUSED = 0, + FLOW_POOL_ACTIVE_PAUSED = 1, + FLOW_POOL_INVALID = 2, + FLOW_POOL_INACTIVE = 3, +}; + +/** + * struct ol_txrx_pool_stats - flow pool related statistics + * @pool_map_count: flow pool map received + * @pool_unmap_count: flow pool unmap received + * @pkt_drop_no_pool: packets dropped due to unavailablity of pool + */ +struct ol_txrx_pool_stats { + uint16_t pool_map_count; + uint16_t pool_unmap_count; + uint16_t pkt_drop_no_pool; +}; + +/** + * struct ol_tx_flow_pool_t - flow_pool info + * @flow_pool_list_elem: flow_pool_list element + * @flow_pool_lock: flow_pool lock + * @flow_pool_id: flow_pool id + * @flow_pool_size: flow_pool size + * @avail_desc: available descriptors + * @deficient_desc: deficient descriptors + * @status: flow pool status + * @flow_type: flow pool type + * @member_flow_id: member flow id + * @stop_th: stop threshold + * @start_th: start threshold + * @freelist: tx descriptor freelist + * @pkt_drop_no_desc: drop due to no descriptors + * @ref_cnt: pool's ref count + */ +struct ol_tx_flow_pool_t { + TAILQ_ENTRY(ol_tx_flow_pool_t) flow_pool_list_elem; + qdf_spinlock_t flow_pool_lock; + uint8_t flow_pool_id; + uint16_t flow_pool_size; + uint16_t avail_desc; + uint16_t deficient_desc; + enum flow_pool_status status; + enum htt_flow_type flow_type; + uint8_t member_flow_id; + uint16_t stop_th; + uint16_t start_th; + union ol_tx_desc_list_elem_t *freelist; + uint16_t pkt_drop_no_desc; + qdf_atomic_t ref_cnt; +}; + +#endif + +/* + * struct ol_txrx_peer_id_map - Map of firmware peer_ids to peers on host + * @peer: Pointer to peer object + * @peer_id_ref_cnt: No. of firmware references to the peer_id + * @del_peer_id_ref_cnt: No. of outstanding unmap events for peer_id + * after the peer object is deleted on the host. + * + * peer_id is used as an index into the array of ol_txrx_peer_id_map. + */ +struct ol_txrx_peer_id_map { + struct ol_txrx_peer_t *peer; + qdf_atomic_t peer_id_ref_cnt; + qdf_atomic_t del_peer_id_ref_cnt; +}; + +/* + * As depicted in the diagram below, the pdev contains an array of + * NUM_EXT_TID ol_tx_active_queues_in_tid_t elements. + * Each element identifies all the tx queues that are active for + * the TID, from the different peers. + * + * Each peer contains an array of NUM_EXT_TID ol_tx_frms_queue_t elements. + * Each element identifies the tx frames for the TID that need to be sent + * to the peer. + * + * + * pdev: ol_tx_active_queues_in_tid_t active_in_tids[NUM_EXT_TIDS] + * TID + * 0 1 2 17 + * +============+============+============+== ==+============+ + * | active (y) | active (n) | active (n) | | active (y) | + * |------------+------------+------------+-- --+------------| + * | queues | queues | queues | | queues | + * +============+============+============+== ==+============+ + * | | + * .--+-----------------------------------------------' + * | | + * | | peer X: peer Y: + * | | ol_tx_frms_queue_t ol_tx_frms_queue_t + * | | tx_queues[NUM_EXT_TIDS] tx_queues[NUM_EXT_TIDS] + * | | TID +======+ TID +======+ + * | `---->| next |-------------------------->| next |--X + * | 0 | prev | .------. .------. 0 | prev | .------. + * | | txq |-->|txdesc|-->|txdesc| | txq |-->|txdesc| + * | +======+ `------' `------' +======+ `------' + * | | next | | | 1 | next | | + * | 1 | prev | v v | prev | v + * | | txq | .------. .------. | txq | .------. + * | +======+ |netbuf| |netbuf| +======+ |netbuf| + * | | next | `------' `------' | next | `------' + * | 2 | prev | 2 | prev | + * | | txq | | txq | + * | +======+ +======+ + * | | | | | + * | + * | + * | | | | | + * | +======+ +======+ + * `------->| next |--X | next | + * 17 | prev | .------. 17 | prev | + * | txq |-->|txdesc| | txq | + * +======+ `------' +======+ + * | + * v + * .------. + * |netbuf| + * `------' + */ +struct ol_txrx_pdev_t { + /* ctrl_pdev - handle for querying config info */ + ol_pdev_handle ctrl_pdev; + + /* osdev - handle for mem alloc / free, map / unmap */ + qdf_device_t osdev; + + htt_pdev_handle htt_pdev; + +#ifdef WLAN_FEATURE_FASTPATH + struct CE_handle *ce_tx_hdl; /* Handle to Tx packet posting CE */ + struct CE_handle *ce_htt_msg_hdl; /* Handle to TxRx completion CE */ +#endif /* WLAN_FEATURE_FASTPATH */ + + struct { + int is_high_latency; + int host_addba; + int ll_pause_txq_limit; + int default_tx_comp_req; + } cfg; + + /* WDI subscriber's event list */ + wdi_event_subscribe **wdi_event_list; + +#if !defined(REMOVE_PKT_LOG) && !defined(QVIT) + bool pkt_log_init; + /* Pktlog pdev */ + struct ol_pktlog_dev_t *pl_dev; +#endif /* #ifndef REMOVE_PKT_LOG */ + + enum ol_sec_type sec_types[htt_num_sec_types]; + /* standard frame type */ + enum wlan_frm_fmt frame_format; + enum htt_pkt_type htt_pkt_type; + +#ifdef QCA_SUPPORT_SW_TXRX_ENCAP + /* txrx encap/decap */ + uint8_t sw_tx_encap; + uint8_t sw_rx_decap; + uint8_t target_tx_tran_caps; + uint8_t target_rx_tran_caps; + /* llc process */ + uint8_t sw_tx_llc_proc_enable; + uint8_t sw_rx_llc_proc_enable; + /* A-MSDU */ + uint8_t sw_subfrm_hdr_recovery_enable; + /* Protected Frame bit handling */ + uint8_t sw_pf_proc_enable; +#endif + /* + * target tx credit - + * not needed for LL, but used for HL download scheduler to keep + * track of roughly how much space is available in the target for + * tx frames + */ + qdf_atomic_t target_tx_credit; + qdf_atomic_t orig_target_tx_credit; + + /* Peer mac address to staid mapping */ + struct ol_mac_addr mac_to_staid[WLAN_MAX_STA_COUNT + 3]; + + /* ol_txrx_vdev list */ + TAILQ_HEAD(, ol_txrx_vdev_t) vdev_list; + + /* peer ID to peer object map (array of pointers to peer objects) */ + struct ol_txrx_peer_id_map *peer_id_to_obj_map; + + struct { + unsigned mask; + unsigned idx_bits; + TAILQ_HEAD(, ol_txrx_peer_t) * bins; + } peer_hash; + + /* rx specific processing */ + struct { + struct { + TAILQ_HEAD(, ol_rx_reorder_t) waitlist; + uint32_t timeout_ms; + } defrag; + struct { + int defrag_timeout_check; + int dup_check; + } flags; + + struct { + struct ol_tx_reorder_cat_timeout_t + access_cats[TXRX_NUM_WMM_AC]; + } reorder_timeout; + qdf_spinlock_t mutex; + } rx; + + /* rx proc function */ + void (*rx_opt_proc)(struct ol_txrx_vdev_t *vdev, + struct ol_txrx_peer_t *peer, + unsigned tid, qdf_nbuf_t msdu_list); + + /* tx data delivery notification callback function */ + struct { + ol_txrx_data_tx_cb func; + void *ctxt; + } tx_data_callback; + + /* tx management delivery notification callback functions */ + struct { + struct { + ol_txrx_mgmt_tx_cb download_cb; + ol_txrx_mgmt_tx_cb ota_ack_cb; + void *ctxt; + } callbacks[OL_TXRX_MGMT_NUM_TYPES]; + } tx_mgmt; + + /* packetdump callback functions */ + tp_ol_packetdump_cb ol_tx_packetdump_cb; + tp_ol_packetdump_cb ol_rx_packetdump_cb; + + struct { + uint16_t pool_size; + uint16_t num_free; + union ol_tx_desc_list_elem_t *array; + union ol_tx_desc_list_elem_t *freelist; +#ifdef QCA_LL_TX_FLOW_CONTROL_V2 + uint8_t num_invalid_bin; + qdf_spinlock_t flow_pool_list_lock; + TAILQ_HEAD(flow_pool_list_t, ol_tx_flow_pool_t) flow_pool_list; +#endif + uint32_t page_size; + uint16_t desc_reserved_size; + uint8_t page_divider; + uint32_t offset_filter; + struct qdf_mem_multi_page_t desc_pages; +#ifdef DESC_DUP_DETECT_DEBUG + unsigned long *free_list_bitmap; +#endif + } tx_desc; + + uint8_t is_mgmt_over_wmi_enabled; +#if defined(QCA_LL_TX_FLOW_CONTROL_V2) + struct ol_txrx_pool_stats pool_stats; + uint32_t num_msdu_desc; +#ifdef QCA_LL_TX_FLOW_GLOBAL_MGMT_POOL + struct ol_tx_flow_pool_t *mgmt_pool; +#endif +#endif + + struct { + int (*cmp)(union htt_rx_pn_t *new, + union htt_rx_pn_t *old, + int is_unicast, int opmode); + int len; + } rx_pn[htt_num_sec_types]; + + /* tx mutex */ + OL_TX_MUTEX_TYPE tx_mutex; + + /* + * peer ref mutex: + * 1. Protect peer object lookups until the returned peer object's + * reference count is incremented. + * 2. Provide mutex when accessing peer object lookup structures. + */ + OL_RX_MUTEX_TYPE peer_ref_mutex; + + /* + * last_real_peer_mutex: + * Protect lookups of any vdev's last_real_peer pointer until the + * reference count for the pointed-to peer object is incremented. + * This mutex could be in the vdev struct, but it's slightly simpler + * to have a single lock in the pdev struct. Since the lock is only + * held for an extremely short time, and since it's very unlikely for + * two vdev's to concurrently access the lock, there's no real + * benefit to having a per-vdev lock. + */ + OL_RX_MUTEX_TYPE last_real_peer_mutex; + + qdf_spinlock_t peer_map_unmap_lock; + + struct { + struct { + struct { + struct { + uint64_t ppdus; + uint64_t mpdus; + } normal; + struct { + /* + * mpdu_bad is general - + * replace it with the specific counters + * below + */ + uint64_t mpdu_bad; + /* uint64_t mpdu_fcs; */ + /* uint64_t mpdu_duplicate; */ + /* uint64_t mpdu_pn_replay; */ + /* uint64_t mpdu_bad_sender; */ + /* ^ comment: peer not found */ + /* uint64_t mpdu_flushed; */ + /* uint64_t msdu_defrag_mic_err; */ + uint64_t msdu_mc_dup_drop; + } err; + } rx; + } priv; + struct ol_txrx_stats pub; + } stats; + +#if defined(ENABLE_RX_REORDER_TRACE) + struct { + uint32_t mask; + uint32_t idx; + uint64_t cnt; +#define TXRX_RX_REORDER_TRACE_SIZE_LOG2 8 /* 256 entries */ + struct { + uint16_t reorder_idx; + uint16_t seq_num; + uint8_t num_mpdus; + uint8_t tid; + } *data; + } rx_reorder_trace; +#endif /* ENABLE_RX_REORDER_TRACE */ + +#if defined(ENABLE_RX_PN_TRACE) + struct { + uint32_t mask; + uint32_t idx; + uint64_t cnt; +#define TXRX_RX_PN_TRACE_SIZE_LOG2 5 /* 32 entries */ + struct { + struct ol_txrx_peer_t *peer; + uint32_t pn32; + uint16_t seq_num; + uint8_t unicast; + uint8_t tid; + } *data; + } rx_pn_trace; +#endif /* ENABLE_RX_PN_TRACE */ + +#if defined(PERE_IP_HDR_ALIGNMENT_WAR) + bool host_80211_enable; +#endif + + /* + * tx_sched only applies for HL, but is defined unconditionally + * rather than only if defined(CONFIG_HL_SUPPORT). + * This is because the struct only + * occupies a few bytes, and to avoid the complexity of + * wrapping references + * to the struct members in "defined(CONFIG_HL_SUPPORT)" conditional + * compilation. + * If this struct gets expanded to a non-trivial size, + * then it should be + * conditionally compiled to only apply if defined(CONFIG_HL_SUPPORT). + */ + qdf_spinlock_t tx_queue_spinlock; + struct { + enum ol_tx_scheduler_status tx_sched_status; + struct ol_tx_sched_t *scheduler; + struct ol_tx_frms_queue_t *last_used_txq; + } tx_sched; + /* + * tx_queue only applies for HL, but is defined unconditionally to avoid + * wrapping references to tx_queue in "defined(CONFIG_HL_SUPPORT)" + * conditional compilation. + */ + struct { + qdf_atomic_t rsrc_cnt; + /* threshold_lo - when to start tx desc margin replenishment */ + uint16_t rsrc_threshold_lo; + /* threshold_hi - where to stop during tx desc margin + replenishment */ + uint16_t rsrc_threshold_hi; + } tx_queue; + +#if defined(DEBUG_HL_LOGGING) && defined(CONFIG_HL_SUPPORT) +#define OL_TXQ_LOG_SIZE 512 + qdf_spinlock_t txq_log_spinlock; + struct { + int size; + int oldest_record_offset; + int offset; + int allow_wrap; + u_int32_t wrapped; + /* aligned to u_int32_t boundary */ + u_int8_t data[OL_TXQ_LOG_SIZE]; + } txq_log; +#endif + +#ifdef QCA_ENABLE_OL_TXRX_PEER_STATS + qdf_spinlock_t peer_stat_mutex; +#endif + + int rssi_update_shift; + int rssi_new_weight; +#ifdef QCA_SUPPORT_TXRX_LOCAL_PEER_ID + struct { + ol_txrx_local_peer_id_t pool[OL_TXRX_NUM_LOCAL_PEER_IDS + 1]; + ol_txrx_local_peer_id_t freelist; + qdf_spinlock_t lock; + ol_txrx_peer_handle map[OL_TXRX_NUM_LOCAL_PEER_IDS]; + } local_peer_ids; +#endif + +#ifdef QCA_COMPUTE_TX_DELAY +#ifdef QCA_COMPUTE_TX_DELAY_PER_TID +#define QCA_TX_DELAY_NUM_CATEGORIES \ + (OL_TX_NUM_TIDS + OL_TX_VDEV_NUM_QUEUES) +#else +#define QCA_TX_DELAY_NUM_CATEGORIES 1 +#endif + struct { + qdf_spinlock_t mutex; + struct { + struct ol_tx_delay_data copies[2]; /* ping-pong */ + int in_progress_idx; + uint32_t avg_start_time_ticks; + } cats[QCA_TX_DELAY_NUM_CATEGORIES]; + uint32_t tx_compl_timestamp_ticks; + uint32_t avg_period_ticks; + uint32_t hist_internal_bin_width_mult; + uint32_t hist_internal_bin_width_shift; + } tx_delay; + + uint16_t packet_count[QCA_TX_DELAY_NUM_CATEGORIES]; + uint16_t packet_loss_count[QCA_TX_DELAY_NUM_CATEGORIES]; + +#endif /* QCA_COMPUTE_TX_DELAY */ + + struct { + qdf_spinlock_t mutex; + /* timer used to monitor the throttle "on" phase and + "off" phase */ + qdf_timer_t phase_timer; + /* timer used to send tx frames */ + qdf_timer_t tx_timer; + /* This is the time in ms of the throttling window, it will + * include an "on" phase and an "off" phase */ + uint32_t throttle_period_ms; + /* Current throttle level set by the client ex. level 0, + level 1, etc */ + enum throttle_level current_throttle_level; + /* Index that points to the phase within the throttle period */ + enum throttle_phase current_throttle_phase; + /* Maximum number of frames to send to the target at one time */ + uint32_t tx_threshold; + /* stores time in ms of on/off phase for each throttle level */ + int throttle_time_ms[THROTTLE_LEVEL_MAX][THROTTLE_PHASE_MAX]; + /* mark true if traffic is paused due to thermal throttling */ + bool is_paused; + } tx_throttle; + +#ifdef IPA_OFFLOAD + ipa_uc_op_cb_type ipa_uc_op_cb; + void *osif_dev; +#endif /* IPA_UC_OFFLOAD */ + +#if defined(FEATURE_TSO) + struct { + uint16_t pool_size; + uint16_t num_free; + struct qdf_tso_seg_elem_t *freelist; + /* tso mutex */ + OL_TX_MUTEX_TYPE tso_mutex; + } tso_seg_pool; + struct { + uint16_t num_seg_pool_size; + uint16_t num_free; + struct qdf_tso_num_seg_elem_t *freelist; + /* tso mutex */ + OL_TX_MUTEX_TYPE tso_num_seg_mutex; + } tso_num_seg_pool; +#endif + +#if defined(CONFIG_HL_SUPPORT) && defined(QCA_BAD_PEER_TX_FLOW_CL) + struct { + enum ol_tx_peer_bal_state enabled; + qdf_spinlock_t mutex; + /* timer used to trigger more frames for bad peers */ + qdf_timer_t peer_bal_timer; + /*This is the time in ms of the peer balance timer period */ + u_int32_t peer_bal_period_ms; + /*This is the txq limit */ + u_int32_t peer_bal_txq_limit; + /*This is the state of the peer balance timer */ + enum ol_tx_peer_bal_timer_state peer_bal_timer_state; + /*This is the counter about active peers which are under + *tx flow control */ + u_int32_t peer_num; + /*This is peer list which are under tx flow control */ + struct ol_tx_limit_peer_t limit_list[MAX_NO_PEERS_IN_LIMIT]; + /*This is threshold configurationl */ + struct tx_peer_threshold ctl_thresh[TXRX_IEEE11_MAX]; + } tx_peer_bal; +#endif /* CONFIG_Hl_SUPPORT && QCA_BAD_PEER_TX_FLOW_CL */ + + struct ol_tx_queue_group_t txq_grps[OL_TX_MAX_TXQ_GROUPS]; +#ifdef DEBUG_HL_LOGGING + qdf_spinlock_t grp_stat_spinlock; + struct ol_tx_group_credit_stats_t grp_stats; +#endif + int tid_to_ac[OL_TX_NUM_TIDS + OL_TX_VDEV_NUM_QUEUES]; + uint8_t ocb_peer_valid; + struct ol_txrx_peer_t *ocb_peer; + ol_tx_pause_callback_fp pause_cb; + + struct { + void (*lro_flush_cb)(void *); + } lro_info; + struct ol_txrx_peer_t *self_peer; +}; + +struct ol_txrx_ocb_chan_info { + uint32_t chan_freq; + uint16_t disable_rx_stats_hdr:1; +}; + +struct ol_txrx_vdev_t { + struct ol_txrx_pdev_t *pdev; /* pdev - the physical device that is + the parent of this virtual device */ + uint8_t vdev_id; /* ID used to specify a particular vdev + to the target */ + void *osif_dev; + union ol_txrx_align_mac_addr_t mac_addr; /* MAC address */ + /* tx paused - NO LONGER NEEDED? */ + TAILQ_ENTRY(ol_txrx_vdev_t) vdev_list_elem; /* node in the pdev's list + of vdevs */ + TAILQ_HEAD(peer_list_t, ol_txrx_peer_t) peer_list; + struct ol_txrx_peer_t *last_real_peer; /* last real peer created for + this vdev (not "self" + pseudo-peer) */ + ol_txrx_rx_fp rx; /* receive function used by this vdev */ + + struct { + /* + * If the vdev object couldn't be deleted immediately because + * it still had some peer objects left, remember that a delete + * was requested, so it can be deleted once all its peers have + * been deleted. + */ + int pending; + /* + * Store a function pointer and a context argument to provide a + * notification for when the vdev is deleted. + */ + ol_txrx_vdev_delete_cb callback; + void *context; + } delete; + + /* safe mode control to bypass the encrypt and decipher process */ + uint32_t safemode; + + /* rx filter related */ + uint32_t drop_unenc; + struct privacy_exemption privacy_filters[MAX_PRIVACY_FILTERS]; + uint32_t num_filters; + + enum wlan_op_mode opmode; + +#ifdef QCA_IBSS_SUPPORT + /* ibss mode related */ + int16_t ibss_peer_num; /* the number of active peers */ + int16_t ibss_peer_heart_beat_timer; /* for detecting peer departure */ +#endif + +#if defined(CONFIG_HL_SUPPORT) + struct ol_tx_frms_queue_t txqs[OL_TX_VDEV_NUM_QUEUES]; +#endif + + struct { + struct { + qdf_nbuf_t head; + qdf_nbuf_t tail; + int depth; + } txq; + uint32_t paused_reason; + qdf_spinlock_t mutex; + qdf_timer_t timer; + int max_q_depth; + bool is_q_paused; + bool is_q_timer_on; + uint32_t q_pause_cnt; + uint32_t q_unpause_cnt; + uint32_t q_overflow_cnt; + } ll_pause; + bool disable_intrabss_fwd; + qdf_atomic_t os_q_paused; + uint16_t tx_fl_lwm; + uint16_t tx_fl_hwm; + qdf_spinlock_t flow_control_lock; + ol_txrx_tx_flow_control_fp osif_flow_control_cb; + void *osif_fc_ctx; + +#if defined(CONFIG_HL_SUPPORT) && defined(FEATURE_WLAN_TDLS) + union ol_txrx_align_mac_addr_t hl_tdls_ap_mac_addr; + bool hlTdlsFlag; +#endif + +#if defined(CONFIG_PER_VDEV_TX_DESC_POOL) + qdf_atomic_t tx_desc_count; +#endif + + uint16_t wait_on_peer_id; + union ol_txrx_align_mac_addr_t last_peer_mac_addr; + qdf_event_t wait_delete_comp; +#if defined(FEATURE_TSO) + struct { + int pool_elems; /* total number of elements in the pool */ + int alloc_cnt; /* number of allocated elements */ + uint32_t *freelist; /* free list of qdf_tso_seg_elem_t */ + } tso_pool_t; +#endif + + /* last channel change event recieved */ + struct { + bool is_valid; /* whether the rest of the members are valid */ + uint16_t mhz; + uint16_t band_center_freq1; + uint16_t band_center_freq2; + WLAN_PHY_MODE phy_mode; + } ocb_channel_event; + + /* Information about the schedules in the schedule */ + struct ol_txrx_ocb_chan_info *ocb_channel_info; + uint32_t ocb_channel_count; + /* Default OCB TX parameter */ + struct ocb_tx_ctrl_hdr_t *ocb_def_tx_param; + + +#ifdef QCA_LL_TX_FLOW_CONTROL_V2 + struct ol_tx_flow_pool_t *pool; +#endif + /* intra bss forwarded tx and rx packets count */ + uint64_t fwd_tx_packets; + uint64_t fwd_rx_packets; + bool is_wisa_mode_enable; + uint8_t mac_id; +}; + +struct ol_rx_reorder_array_elem_t { + qdf_nbuf_t head; + qdf_nbuf_t tail; +}; + +struct ol_rx_reorder_t { + uint8_t win_sz; + uint8_t win_sz_mask; + uint8_t num_mpdus; + struct ol_rx_reorder_array_elem_t *array; + /* base - single rx reorder element used for non-aggr cases */ + struct ol_rx_reorder_array_elem_t base; +#if defined(QCA_SUPPORT_OL_RX_REORDER_TIMEOUT) + struct ol_rx_reorder_timeout_list_elem_t timeout; +#endif + /* only used for defrag right now */ + TAILQ_ENTRY(ol_rx_reorder_t) defrag_waitlist_elem; + uint32_t defrag_timeout_ms; + /* get back to parent ol_txrx_peer_t when ol_rx_reorder_t is in a + * waitlist */ + uint16_t tid; +}; + +enum { + txrx_sec_mcast = 0, + txrx_sec_ucast +}; + +typedef A_STATUS (*ol_tx_filter_func)(struct ol_txrx_msdu_info_t * + tx_msdu_info); + +#define OL_TXRX_PEER_SECURITY_MULTICAST 0 +#define OL_TXRX_PEER_SECURITY_UNICAST 1 +#define OL_TXRX_PEER_SECURITY_MAX 2 + +/* Allow 6000 ms to receive peer unmap events after peer is deleted */ +#define OL_TXRX_PEER_UNMAP_TIMEOUT (6000) + +struct ol_txrx_cached_bufq_t { + /* cached_bufq is used to enqueue the pending RX frames from a peer + * before the peer is registered for data service. The list will be + * flushed to HDD once that station is registered. + */ + struct list_head cached_bufq; + /* mutual exclusion lock to access the cached_bufq queue */ + qdf_spinlock_t bufq_lock; + /* # entries in queue after which subsequent adds will be dropped */ + uint32_t thresh; + /* # entries in present in cached_bufq */ + uint32_t curr; + /* # max num of entries in the queue if bufq thresh was not in place */ + uint32_t high_water_mark; + /* # max num of entries in the queue if we did not drop packets */ + uint32_t qdepth_no_thresh; + /* # of packes (beyond threshold) dropped from cached_bufq */ + uint32_t dropped; +}; + +struct ol_txrx_peer_t { + struct ol_txrx_vdev_t *vdev; + + qdf_atomic_t ref_cnt; + qdf_atomic_t delete_in_progress; + qdf_atomic_t flush_in_progress; + + /* The peer state tracking is used for HL systems + * that don't support tx and rx filtering within the target. + * In such systems, the peer's state determines what kind of + * tx and rx filtering, if any, is done. + * This variable doesn't apply to LL systems, or to HL systems for + * which the target handles tx and rx filtering. However, it is + * simplest to declare and update this variable unconditionally, + * for all systems. + */ + enum ol_txrx_peer_state state; + qdf_spinlock_t peer_info_lock; + + /* Wrapper around the cached_bufq list */ + struct ol_txrx_cached_bufq_t bufq_info; + + ol_tx_filter_func tx_filter; + + /* peer ID(s) for this peer */ + uint16_t peer_ids[MAX_NUM_PEER_ID_PER_PEER]; +#ifdef QCA_SUPPORT_TXRX_LOCAL_PEER_ID + uint16_t local_id; +#endif + + union ol_txrx_align_mac_addr_t mac_addr; + + /* node in the vdev's list of peers */ + TAILQ_ENTRY(ol_txrx_peer_t) peer_list_elem; + /* node in the hash table bin's list of peers */ + TAILQ_ENTRY(ol_txrx_peer_t) hash_list_elem; + + /* + * per TID info - + * stored in separate arrays to avoid alignment padding mem overhead + */ + struct ol_rx_reorder_t tids_rx_reorder[OL_TXRX_NUM_EXT_TIDS]; + union htt_rx_pn_t tids_last_pn[OL_TXRX_NUM_EXT_TIDS]; + uint8_t tids_last_pn_valid[OL_TXRX_NUM_EXT_TIDS]; + uint16_t tids_next_rel_idx[OL_TXRX_NUM_EXT_TIDS]; + uint16_t tids_last_seq[OL_TXRX_NUM_EXT_TIDS]; + uint16_t tids_mcast_last_seq[OL_TXRX_NUM_EXT_TIDS]; + + struct { + enum htt_sec_type sec_type; + uint32_t michael_key[2]; /* relevant for TKIP */ + } security[2]; /* 0 -> multicast, 1 -> unicast */ + + /* + * rx proc function: this either is a copy of pdev's rx_opt_proc for + * regular rx processing, or has been redirected to a /dev/null discard + * function when peer deletion is in progress. + */ + void (*rx_opt_proc)(struct ol_txrx_vdev_t *vdev, + struct ol_txrx_peer_t *peer, + unsigned tid, qdf_nbuf_t msdu_list); + +#if defined(CONFIG_HL_SUPPORT) + struct ol_tx_frms_queue_t txqs[OL_TX_NUM_TIDS]; +#endif + +#ifdef QCA_ENABLE_OL_TXRX_PEER_STATS + ol_txrx_peer_stats_t stats; +#endif + int16_t rssi_dbm; + + /* NAWDS Flag and Bss Peer bit */ + uint16_t nawds_enabled:1, bss_peer:1, valid:1; + + /* QoS info */ + uint8_t qos_capable; + /* U-APSD tid mask */ + uint8_t uapsd_mask; + /*flag indicating key installed */ + uint8_t keyinstalled; + + /* Bit to indicate if PN check is done in fw */ + qdf_atomic_t fw_pn_check; + +#ifdef WLAN_FEATURE_11W + /* PN counter for Robust Management Frames */ + uint64_t last_rmf_pn; + uint32_t rmf_pn_replays; + uint8_t last_rmf_pn_valid; +#endif + + /* Properties of the last received PPDU */ + int16_t last_pkt_rssi_cmb; + int16_t last_pkt_rssi[4]; + uint8_t last_pkt_legacy_rate; + uint8_t last_pkt_legacy_rate_sel; + uint32_t last_pkt_timestamp_microsec; + uint8_t last_pkt_timestamp_submicrosec; + uint32_t last_pkt_tsf; + uint8_t last_pkt_tid; + uint16_t last_pkt_center_freq; +#if defined(CONFIG_HL_SUPPORT) && defined(QCA_BAD_PEER_TX_FLOW_CL) + u_int16_t tx_limit; + u_int16_t tx_limit_flag; + u_int16_t tx_pause_flag; +#endif + qdf_time_t last_assoc_rcvd; + qdf_time_t last_disassoc_rcvd; + qdf_time_t last_deauth_rcvd; + qdf_atomic_t fw_create_pending; + qdf_timer_t peer_unmap_timer; +}; + +enum ol_rx_err_type { + OL_RX_ERR_DEFRAG_MIC, + OL_RX_ERR_PN, + OL_RX_ERR_UNKNOWN_PEER, + OL_RX_ERR_MALFORMED, + OL_RX_ERR_TKIP_MIC, + OL_RX_ERR_DECRYPT, + OL_RX_ERR_MPDU_LENGTH, + OL_RX_ERR_ENCRYPT_REQUIRED, + OL_RX_ERR_DUP, + OL_RX_ERR_UNKNOWN, + OL_RX_ERR_FCS, + OL_RX_ERR_PRIVACY, + OL_RX_ERR_NONE_FRAG, + OL_RX_ERR_NONE = 0xFF +}; + +/** + * ol_mic_error_info - carries the information associated with + * a MIC error + * @vdev_id: virtual device ID + * @key_id: Key ID + * @pn: packet number + * @sa: source address + * @da: destination address + * @ta: transmitter address + */ +struct ol_mic_error_info { + uint8_t vdev_id; + uint32_t key_id; + uint64_t pn; + uint8_t sa[OL_TXRX_MAC_ADDR_LEN]; + uint8_t da[OL_TXRX_MAC_ADDR_LEN]; + uint8_t ta[OL_TXRX_MAC_ADDR_LEN]; +}; + +/** + * ol_error_info - carries the information associated with an + * error indicated by the firmware + * @mic_err: MIC error information + */ +struct ol_error_info { + union { + struct ol_mic_error_info mic_err; + } u; +}; + +struct ol_rx_remote_data { + qdf_nbuf_t msdu; + uint8_t mac_id; +}; + +#endif /* _OL_TXRX_TYPES__H_ */ diff --git a/drivers/staging/qcacld-3.0/core/dp/txrx/txrx.h b/drivers/staging/qcacld-3.0/core/dp/txrx/txrx.h new file mode 100644 index 0000000000000000000000000000000000000000..333899bcd1db1be592be608860e92ffd3cad7164 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/dp/txrx/txrx.h @@ -0,0 +1,222 @@ +/* + * Copyright (c) 2013-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef TXRX_H +#define TXRX_H + +#include "cds_api.h" +#include "qdf_nbuf.h" +#include "csr_api.h" +#include "sap_api.h" +#include "ol_txrx_osif_api.h" + +/* wait on peer deletion timeout value in milliseconds */ +#define PEER_DELETION_TIMEOUT 500 + +enum txrx_wmm_ac { + TXRX_WMM_AC_VO, + TXRX_WMM_AC_VI, + TXRX_WMM_AC_BK, + TXRX_WMM_AC_BE, + + TXRX_NUM_WMM_AC +}; + +struct txrx_rx_metainfo { + u8 up; + u16 dest_staid; +}; + +enum bt_frame_type { + /* BT-AMP packet of type data */ + TXRX_BT_AMP_TYPE_DATA = 0x0001, + + /* BT-AMP packet of type activity report */ + TXRX_BT_AMP_TYPE_AR = 0x0002, + + /* BT-AMP packet of type security frame */ + TXRX_BT_AMP_TYPE_SEC = 0x0003, + + /* BT-AMP packet of type Link Supervision request frame */ + TXRX_BT_AMP_TYPE_LS_REQ = 0x0004, + + /* BT-AMP packet of type Link Supervision reply frame */ + TXRX_BT_AMP_TYPE_LS_REP = 0x0005, + + /* Invalid Frame */ + TXRX_BAP_INVALID_FRAME +}; + +enum wlan_ts_direction { + /* uplink */ + WLAN_TX_DIR = 0, + + /* downlink */ + WLAN_RX_DIR = 1, + + /*bidirectional */ + WLAN_BI_DIR = 2, +}; + +enum wlan_sta_state { + /* Transition in this state made upon creation */ + WLAN_STA_INIT = 0, + + /* Transition happens after Assoc success if second level authentication + is needed */ + WLAN_STA_CONNECTED, + + /* Transition happens when second level auth is successful and keys are + properly installed */ + WLAN_STA_AUTHENTICATED, + + /* Transition happens when connectivity is lost */ + WLAN_STA_DISCONNECTED, + + WLAN_STA_MAX_STATE +}; + +struct wlan_txrx_stats { + /* Define various txrx stats here */ +}; + +struct ol_txrx_vdev_t; + +QDF_STATUS wlan_register_mgmt_client(void *pdev_txrx, + QDF_STATUS (*rx_mgmt)(void *g_cdsctx, + void *buf)); + +/* If RSSI realm is changed, send notification to Clients, SME, HDD */ +typedef QDF_STATUS (*wlan_txrx_rssi_cross_thresh)(void *adapter, u8 rssi, + void *usr_ctx, + int8_t avg_rssi); + +struct wlan_txrx_ind_req { + u16 msgType; /* message type is same as the request type */ + u16 msgLen; /* length of the entire request */ + u8 sessionId; /* sme Session Id */ + u8 rssiNotification; + u8 avgRssi; + void *tlCallback; + void *pAdapter; + void *pUserCtxt; +}; + + +/* Rx callback registered with txrx */ +typedef int (*wlan_txrx_cb_type)(void *g_cdsctx, qdf_nbuf_t buf, u8 sta_id, + struct txrx_rx_metainfo *rx_meta_info); + +static inline int wlan_txrx_get_rssi(void *g_cdsctx, u8 sta_id, int8_t *rssi) +{ + return 0; +} + +static inline int wlan_txrx_enable_uapsd_ac(void *g_cdsctx, u8 sta_id, + enum txrx_wmm_ac ac, u8 tid, u8 up, + u32 srv_int, u32 suspend_int, + enum wlan_ts_direction ts_dir) +{ + return 0; +} + +static inline int wlan_txrx_disable_uapsd_ac(void *g_cdsctx, u8 sta_id, + enum txrx_wmm_ac ac) +{ + return 0; +} + +static inline int wlan_change_sta_state(void *g_cdsctx, u8 sta_id, + enum wlan_sta_state state) +{ + return 0; +} + +static inline int wlan_deregister_mgmt_client(void *g_cdsctx) +{ + return 0; +} + +static inline void wlan_assoc_failed(u8 staid) +{ +} + +static inline int wlan_get_ap_stats(void *g_cdsctx, tSap_SoftapStats *buf, + bool reset) +{ + return 0; +} + +static inline int wlan_get_txrx_stats(void *g_cdsctx, + struct wlan_txrx_stats *stats, u8 sta_id) +{ + return 0; +} + +static inline int wlan_txrx_update_rssi_bmps(void *g_cdsctx, u8 sta_id, + int8_t rssi) +{ + return 0; +} + +static inline int wlan_txrx_deregister_rssi_indcb(void *g_cdsctx, + int8_t rssi_val, + u8 trigger_event, + wlan_txrx_rssi_cross_thresh + cb, int mod_id) +{ + return 0; +} + +static inline int wlan_txrx_register_rssi_indcb(void *g_cdsctx, + int8_t rssi_val, + u8 trigger_event, + wlan_txrx_rssi_cross_thresh cb, + int mod_id, void *usr_ctx) +{ + return 0; +} + +/* FIXME: The following stubs will be removed eventually */ +static inline int wlan_txrx_mc_process_msg(void *g_cdsctx, cds_msg_t *msg) +{ + return 0; +} + +static inline int wlan_txrx_tx_process_msg(void *g_cdsctx, cds_msg_t *msg) +{ + return 0; +} + +static inline void wlan_txrx_mc_free_msg(void *g_cdsctx, cds_msg_t *msg) +{ +} + +static inline void wlan_txrx_tx_free_msg(void *g_cdsctx, cds_msg_t *msg) +{ +} +#endif diff --git a/drivers/staging/qcacld-3.0/core/dp/txrx/wdi_event.h b/drivers/staging/qcacld-3.0/core/dp/txrx/wdi_event.h new file mode 100644 index 0000000000000000000000000000000000000000..2b0d4915f1a4a3184ec0a558bd0e1138b4e56e97 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/dp/txrx/wdi_event.h @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2013-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef _WDI_EVENT_H_ +#define _WDI_EVENT_H_ + +#include "athdefs.h" +#include "qdf_nbuf.h" +#define WDI_EVENT_BASE 0x100 /* Event starting number */ + +enum WDI_EVENT { + WDI_EVENT_TX_STATUS = WDI_EVENT_BASE, + WDI_EVENT_RX_DESC, + WDI_EVENT_RX_DESC_REMOTE, + WDI_EVENT_RATE_FIND, + WDI_EVENT_RATE_UPDATE, + WDI_EVENT_SW_EVENT, + WDI_EVENT_RX_PEER_INVALID, + /* End of new event items */ + + WDI_EVENT_LAST +}; + +struct wdi_event_rx_peer_invalid_msg { + qdf_nbuf_t msdu; + struct ieee80211_frame *wh; + uint8_t vdev_id; +}; + +#define WDI_NUM_EVENTS (WDI_EVENT_LAST - WDI_EVENT_BASE) + +#define WDI_EVENT_NOTIFY_BASE 0x200 +enum WDI_EVENT_NOTIFY { + WDI_EVENT_SUB_DEALLOCATE = WDI_EVENT_NOTIFY_BASE, + /* End of new notification types */ + + WDI_EVENT_NOTIFY_LAST +}; + +/* Opaque event callback */ +typedef void (*wdi_event_cb)(void *pdev, enum WDI_EVENT event, void *data); + +/* Opaque event notify */ +typedef void (*wdi_event_notify)(enum WDI_EVENT_NOTIFY notify, + enum WDI_EVENT event); + +/** + * @typedef wdi_event_subscribe + * @brief Used by consumers to subscribe to WDI event notifications. + * @details + * The event_subscribe struct includes pointers to other event_subscribe + * objects. These pointers are simply to simplify the management of + * lists of event subscribers. These pointers are set during the + * event_sub() function, and shall not be modified except by the + * WDI event management SW, until after the object's event subscription + * is canceled by calling event_unsub(). + */ + +typedef struct wdi_event_subscribe_t { + wdi_event_cb callback; /* subscriber event callback structure head */ + void *context; /* subscriber object that processes the event callback */ + struct { + /* private - the event subscriber SW shall not use this struct */ + struct wdi_event_subscribe_t *next; + struct wdi_event_subscribe_t *prev; + } priv; +} wdi_event_subscribe; + +#endif diff --git a/drivers/staging/qcacld-3.0/core/dp/txrx/wdi_event_api.h b/drivers/staging/qcacld-3.0/core/dp/txrx/wdi_event_api.h new file mode 100644 index 0000000000000000000000000000000000000000..5e2ce5471b7b1b2ddc469b9dccb872a19eb0ee89 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/dp/txrx/wdi_event_api.h @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2012-2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef _WDI_EVENT_API_H_ +#define _WDI_EVENT_API_H_ + +#include "wdi_event.h" + +struct ol_txrx_pdev_t; + +/** + * @brief Subscribe to a specified WDI event. + * @details + * This function adds the provided wdi_event_subscribe object to a list of + * subscribers for the specified WDI event. + * When the event in question happens, each subscriber for the event will + * have their callback function invoked. + * The order in which callback functions from multiple subscribers are + * invoked is unspecified. + * + * @param pdev - the event physical device, that maintains the event lists + * @param event_cb_sub - the callback and context for the event subscriber + * @param event - which event's notifications are being subscribed to + * @return error code, or A_OK for success + */ +A_STATUS wdi_event_sub(struct ol_txrx_pdev_t *txrx_pdev, + wdi_event_subscribe *event_cb_sub, + enum WDI_EVENT event); + +/** + * @brief Unsubscribe from a specified WDI event. + * @details + * This function removes the provided event subscription object from the + * list of subscribers for its event. + * This function shall only be called if there was a successful prior call + * to event_sub() on the same wdi_event_subscribe object. + * + * @param pdev - the event physical device with the list of event subscribers + * @param event_cb_sub - the event subscription object + * @param event - which event is being unsubscribed + * @return error code, or A_OK for success + */ +A_STATUS wdi_event_unsub(struct ol_txrx_pdev_t *txrx_pdev, + wdi_event_subscribe *event_cb_sub, + enum WDI_EVENT event); + +#ifdef WDI_EVENT_ENABLE + +void wdi_event_handler(enum WDI_EVENT event, + struct ol_txrx_pdev_t *txrx_pdev, void *data); +A_STATUS wdi_event_attach(struct ol_txrx_pdev_t *txrx_pdev); +A_STATUS wdi_event_detach(struct ol_txrx_pdev_t *txrx_pdev); + +#else + +static inline void wdi_event_handler(enum WDI_EVENT event, + struct ol_txrx_pdev_t *txrx_pdev, void *data) +{ + return; +} +static inline A_STATUS wdi_event_attach(struct ol_txrx_pdev_t *txrx_pdev) +{ + return A_OK; +} +static inline A_STATUS wdi_event_detach(struct ol_txrx_pdev_t *txrx_pdev) +{ + return A_OK; +} +#endif /* WDI_EVENT_ENABLE */ + +#endif /* _WDI_EVENT_API_H_ */ diff --git a/drivers/staging/qcacld-3.0/core/hdd/inc/qc_sap_ioctl.h b/drivers/staging/qcacld-3.0/core/hdd/inc/qc_sap_ioctl.h new file mode 100644 index 0000000000000000000000000000000000000000..c1c70ee28de2e5ae92d11c856142cd3393403820 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/inc/qc_sap_ioctl.h @@ -0,0 +1,298 @@ +/* + * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef _QC_SAP_IOCTL_H_ +#define _QC_SAP_IOCTL_H_ + +/* + * QCSAP ioctls. + */ + +/* + * Max size of optional information elements. We artificially + * constrain this; it's limited only by the max frame size (and + * the max parameter size of the wireless extensions). + */ +#define QCSAP_MAX_OPT_IE 256 +#define QCSAP_MAX_WSC_IE 256 +#define QCSAP_MAX_GET_STA_INFO 512 + +typedef struct sSSID { + uint8_t length; + uint8_t ssId[32]; +} tSSID; + +typedef struct sSSIDInfo { + tSSID ssid; + uint8_t ssidHidden; +} tSSIDInfo; + +typedef enum { + eQC_DOT11_MODE_ALL = 0, + eQC_DOT11_MODE_ABG = 0x0001, /* 11a/b/g only, no HT, no proprietary */ + eQC_DOT11_MODE_11A = 0x0002, + eQC_DOT11_MODE_11B = 0x0004, + eQC_DOT11_MODE_11G = 0x0008, + eQC_DOT11_MODE_11N = 0x0010, + eQC_DOT11_MODE_11G_ONLY = 0x0020, + eQC_DOT11_MODE_11N_ONLY = 0x0040, + eQC_DOT11_MODE_11B_ONLY = 0x0080, + eQC_DOT11_MODE_11A_ONLY = 0x0100, + /* This is for WIFI test. It is same as eWNIAPI_MAC_PROTOCOL_ALL except when it starts IBSS in 11B of 2.4GHz */ + /* It is for CSR internal use */ + eQC_DOT11_MODE_AUTO = 0x0200, + +} tQcPhyMode; + +#define QCSAP_ADDR_LEN 6 + +typedef uint8_t qcmacaddr[QCSAP_ADDR_LEN]; + +struct qc_mac_acl_entry { + qcmacaddr addr; + int vlan_id; +}; + +typedef enum { + eQC_AUTH_TYPE_OPEN_SYSTEM, + eQC_AUTH_TYPE_SHARED_KEY, + eQC_AUTH_TYPE_AUTO_SWITCH +} eQcAuthType; + +typedef enum { + eQC_WPS_BEACON_IE, + eQC_WPS_PROBE_RSP_IE, + eQC_WPS_ASSOC_RSP_IE +} eQCWPSType; + +/* + * Retrieve the WPA/RSN information element for an associated station. + */ +struct sQcSapreq_wpaie { + uint8_t wpa_ie[QCSAP_MAX_OPT_IE]; + uint8_t wpa_macaddr[QCSAP_ADDR_LEN]; +}; + +/* + * Retrieve the WSC information element for an associated station. + */ +struct sQcSapreq_wscie { + uint8_t wsc_macaddr[QCSAP_ADDR_LEN]; + uint8_t wsc_ie[QCSAP_MAX_WSC_IE]; +}; + +/* + * Retrieve the WPS PBC Probe Request IEs. + */ +typedef struct sQcSapreq_WPSPBCProbeReqIES { + struct qdf_mac_addr macaddr; + uint16_t probeReqIELen; + uint8_t probeReqIE[512]; +} sQcSapreq_WPSPBCProbeReqIES_t; + +/* + * Channel List Info + */ + +typedef struct { + uint8_t num_channels; + uint8_t channels[WNI_CFG_VALID_CHANNEL_LIST_LEN]; +} tChannelListInfo, *tpChannelListInfo; + +#ifdef __linux__ +/* + * Wireless Extensions API, private ioctl interfaces. + * + * NB: Even-numbered ioctl numbers have set semantics and are privileged! + * (regardless of the incorrect comment in wireless.h!) + */ + +#define QCSAP_IOCTL_SETPARAM (SIOCIWFIRSTPRIV + 0) +#define QCSAP_IOCTL_GETPARAM (SIOCIWFIRSTPRIV + 1) +/* (SIOCIWFIRSTPRIV+2) is unused */ +#define QCSAP_IOCTL_SET_NONE_GET_THREE (SIOCIWFIRSTPRIV + 3) +#define WE_GET_TSF 1 +#define QCSAP_IOCTL_GET_STAWPAIE (SIOCIWFIRSTPRIV + 4) +#define QCSAP_IOCTL_STOPBSS (SIOCIWFIRSTPRIV + 6) +#define QCSAP_IOCTL_VERSION (SIOCIWFIRSTPRIV + 7) +#define QCSAP_IOCTL_GET_WPS_PBC_PROBE_REQ_IES (SIOCIWFIRSTPRIV + 8) +#define QCSAP_IOCTL_GET_CHANNEL (SIOCIWFIRSTPRIV + 9) +#define QCSAP_IOCTL_ASSOC_STA_MACADDR (SIOCIWFIRSTPRIV + 10) +#define QCSAP_IOCTL_DISASSOC_STA (SIOCIWFIRSTPRIV + 11) +#define QCSAP_IOCTL_SET_PKTLOG (SIOCIWFIRSTPRIV + 12) + +/* Private ioctls and their sub-ioctls */ +#define QCSAP_PRIV_GET_CHAR_SET_NONE (SIOCIWFIRSTPRIV + 13) +#define QCSAP_GET_STATS 1 +#define QCSAP_LIST_FW_PROFILE 2 +#define QCSAP_IOCTL_CLR_STATS (SIOCIWFIRSTPRIV + 14) + +#define QCSAP_IOCTL_PRIV_SET_THREE_INT_GET_NONE (SIOCIWFIRSTPRIV + 15) +#define WE_SET_WLAN_DBG 1 +#define WE_SET_DP_TRACE 2 +#define WE_SET_SAP_CHANNELS 3 +#define QCSAP_IOCTL_PRIV_SET_VAR_INT_GET_NONE (SIOCIWFIRSTPRIV + 16) +#define WE_UNIT_TEST_CMD 7 +#define QCSAP_IOCTL_SET_CHANNEL_RANGE (SIOCIWFIRSTPRIV + 17) + +#define WE_P2P_NOA_CMD 2 + +#define QCSAP_IOCTL_MODIFY_ACL (SIOCIWFIRSTPRIV + 18) +#define QCSAP_IOCTL_GET_CHANNEL_LIST (SIOCIWFIRSTPRIV + 19) +#define QCSAP_IOCTL_SET_TX_POWER (SIOCIWFIRSTPRIV + 20) +#define QCSAP_IOCTL_GET_STA_INFO (SIOCIWFIRSTPRIV + 21) +#define QCSAP_IOCTL_SET_MAX_TX_POWER (SIOCIWFIRSTPRIV + 22) +#define QCSAP_IOCTL_GET_INI_CFG (SIOCIWFIRSTPRIV + 25) +#define QCSAP_IOCTL_SET_INI_CFG (SIOCIWFIRSTPRIV + 26) +#define QCSAP_IOCTL_SET_TWO_INT_GET_NONE (SIOCIWFIRSTPRIV + 28) +#ifdef WLAN_DEBUG +#define QCSAP_IOCTL_SET_FW_CRASH_INJECT 1 +#endif +#define QCSAP_IOCTL_DUMP_DP_TRACE_LEVEL 2 +#define QCSAP_ENABLE_FW_PROFILE 3 +#define QCSAP_SET_FW_PROFILE_HIST_INTVL 4 + +#define MAX_VAR_ARGS 7 +#define QCSAP_IOCTL_PRIV_GET_SOFTAP_LINK_SPEED (SIOCIWFIRSTPRIV + 31) + +#define QCSAP_IOCTL_MAX_STR_LEN 1024 + +#define RC_2_RATE_IDX(_rc) ((_rc) & 0x7) +#define HT_RC_2_STREAMS(_rc) ((((_rc) & 0x78) >> 3) + 1) + +#define RC_2_RATE_IDX_11AC(_rc) ((_rc) & 0xf) +#define HT_RC_2_STREAMS_11AC(_rc) ((((_rc) & 0x30) >> 4) + 1) + +/* + * + * setRadar - simulate a radar event + * + * @INPUT: None + * + * @OUTPUT: None + * + * This IOCTL is used to simulate a radar event, state machines for + * SAP will behave as same way in which a radar event is reported by WMA + * + * @E.g: iwpriv wlan0 setRadar + * + * Supported Feature: DFS + * + * Usage: Internal + * + * + */ + +/* + * + * setRadarDbg - enable/disable radar specific logs + * + * @INPUT: 1/0 + * + * @OUTPUT: None + * + * This IOCTL is enable radar phyerror info in wma + * + * @E.g: iwpriv wlan0 setRadarDbg + * iwpriv wlan0 setRadarDbg 1 + * + * Supported Feature: DFS + * + * Usage: Internal + * + * + */ + +enum { + QCSAP_PARAM_MAX_ASSOC = 1, + QCSAP_PARAM_GET_WLAN_DBG, + QCSAP_PARAM_CLR_ACL = 4, + QCSAP_PARAM_ACL_MODE, + QCSAP_PARAM_HIDE_SSID, + QCSAP_PARAM_AUTO_CHANNEL, + QCSAP_PARAM_SET_MC_RATE, + QCSAP_PARAM_SET_TXRX_FW_STATS, + QCSAP_PARAM_SET_MCC_CHANNEL_LATENCY, + QCSAP_PARAM_SET_MCC_CHANNEL_QUOTA, + QCSAP_DBGLOG_LOG_LEVEL, + QCSAP_DBGLOG_VAP_ENABLE, + QCSAP_DBGLOG_VAP_DISABLE, + QCSAP_DBGLOG_MODULE_ENABLE, + QCSAP_DBGLOG_MODULE_DISABLE, + QCSAP_DBGLOG_MOD_LOG_LEVEL, + QCSAP_DBGLOG_TYPE, + QCSAP_DBGLOG_REPORT_ENABLE, + QCASAP_TXRX_FWSTATS_RESET, + QCSAP_PARAM_RTSCTS, + QCASAP_SET_11N_RATE, + QCASAP_SET_VHT_RATE, + QCASAP_SHORT_GI, + QCSAP_SET_AMPDU, + QCSAP_SET_AMSDU, + QCSAP_GTX_HT_MCS, + QCSAP_GTX_VHT_MCS, + QCSAP_GTX_USRCFG, + QCSAP_GTX_THRE, + QCSAP_GTX_MARGIN, + QCSAP_GTX_STEP, + QCSAP_GTX_MINTPC, + QCSAP_GTX_BWMASK, + QCASAP_SET_TM_LEVEL, + QCASAP_SET_DFS_IGNORE_CAC, + QCASAP_GET_DFS_NOL, + QCASAP_SET_DFS_NOL, + QCSAP_PARAM_SET_CHANNEL_CHANGE, + QCASAP_SET_DFS_TARGET_CHNL, + QCASAP_SET_RADAR_CMD, + QCSAP_GET_ACL, + QCASAP_TX_CHAINMASK_CMD, + QCASAP_RX_CHAINMASK_CMD, + QCASAP_NSS_CMD, + QCSAP_IPA_UC_STAT, + QCASAP_SET_PHYMODE, + QCASAP_GET_TEMP_CMD, + QCASAP_DUMP_STATS, + QCASAP_CLEAR_STATS, + QCASAP_SET_RADAR_DBG, + QCSAP_GET_FW_PROFILE_DATA, + QCSAP_START_FW_PROFILING, + QCSAP_CAP_TSF, + QCSAP_GET_TSF, + QCSAP_PARAM_CONC_SYSTEM_PREF, + QCASAP_PARAM_LDPC, + QCASAP_PARAM_TX_STBC, + QCASAP_PARAM_RX_STBC, + QCSAP_PARAM_CHAN_WIDTH, +}; + +int iw_get_channel_list(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra); + +#endif /* __linux__ */ + +#endif /*_QC_SAP_IOCTL_H_*/ diff --git a/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_assoc.h b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_assoc.h new file mode 100644 index 0000000000000000000000000000000000000000..a257e268524ef362a0623bbe338b3e5343d4eedf --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_assoc.h @@ -0,0 +1,360 @@ +/* + * Copyright (c) 2013-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#if !defined(WLAN_HDD_ASSOC_H__) +#define WLAN_HDD_ASSOC_H__ + +/** + * DOC: wlan_hdd_assoc.h + * + */ + +/* Include files */ +#include +#include +#include "ol_txrx_ctrl_api.h" +#include "cdp_txrx_peer_ops.h" +#include +#include + +/* Preprocessor Definitions and Constants */ +#ifdef FEATURE_WLAN_TDLS +#define HDD_MAX_NUM_TDLS_STA 8 +#define HDD_MAX_NUM_TDLS_STA_P_UAPSD_OFFCHAN 1 +#define TDLS_STA_INDEX_VALID(staId) \ + (((staId) >= 1) && ((staId) < 0xFF)) +#endif +#define TKIP_COUNTER_MEASURE_STARTED 1 +#define TKIP_COUNTER_MEASURE_STOPED 0 +/* Timeout (in ms) for Link to Up before Registering Station */ +#define ASSOC_LINKUP_TIMEOUT 60 + +/* Timeout in ms for peer info request commpletion */ +#define IBSS_PEER_INFO_REQ_TIMOEUT 1000 + +#define INVALID_PEER_IDX -1 + +/** + * enum eConnectionState - connection state values at HDD + * @eConnectionState_NotConnected: Not associated in Infra or participating in + * in an IBSS / Ad-hoc network + * @eConnectionState_Connecting: While connection in progress + * @eConnectionState_Associated: Associated in an Infrastructure network + * @eConnectionState_IbssDisconnected: Participating in an IBSS network though + * disconnected (no partner stations in the IBSS) + * @eConnectionState_IbssConnected: Participating in an IBSS network with + * partner stations also present + * @eConnectionState_Disconnecting: Disconnecting in an Infrastructure network. + * @eConnectionState_NdiDisconnected: NDI in disconnected state - no peers + * @eConnectionState_NdiConnected: NDI in connected state - at least one peer + */ +typedef enum { + eConnectionState_NotConnected, + eConnectionState_Connecting, + eConnectionState_Associated, + eConnectionState_IbssDisconnected, + eConnectionState_IbssConnected, + eConnectionState_Disconnecting, + eConnectionState_NdiDisconnected, + eConnectionState_NdiConnected, +} eConnectionState; + +/** + * typedef ePeerStatus - Peer status + * @ePeerConnected: peer connected + * @ePeerDisconnected: peer disconnected + */ +typedef enum { + ePeerConnected = 1, + ePeerDisconnected +} ePeerStatus; + +/** + * struct hdd_conn_flag - connection flags + * @ht_present: ht element present or not + * @vht_present: vht element present or not + * @hs20_present: hs20 element present or not + * @ht_op_present: ht operation present or not + * @vht_op_present: vht operation present or not + */ +struct hdd_conn_flag { + uint8_t ht_present:1; + uint8_t vht_present:1; + uint8_t hs20_present:1; + uint8_t ht_op_present:1; + uint8_t vht_op_present:1; + uint8_t reserved:3; +}; + +/*defines for tx_BF_cap_info */ +#define TX_BF_CAP_INFO_TX_BF 0x00000001 +#define TX_BF_CAP_INFO_RX_STAG_RED_SOUNDING 0x00000002 +#define TX_BF_CAP_INFO_TX_STAG_RED_SOUNDING 0x00000004 +#define TX_BF_CAP_INFO_RX_ZFL 0x00000008 +#define TX_BF_CAP_INFO_TX_ZFL 0x00000010 +#define TX_BF_CAP_INFO_IMP_TX_BF 0x00000020 +#define TX_BF_CAP_INFO_CALIBRATION 0x000000c0 +#define TX_BF_CAP_INFO_CALIBRATION_SHIFT 6 +#define TX_BF_CAP_INFO_EXP_CSIT_BF 0x00000100 +#define TX_BF_CAP_INFO_EXP_UNCOMP_STEER_MAT 0x00000200 +#define TX_BF_CAP_INFO_EXP_BF_CSI_FB 0x00001c00 +#define TX_BF_CAP_INFO_EXP_BF_CSI_FB_SHIFT 10 +#define TX_BF_CAP_INFO_EXP_UNCMP_STEER_MAT 0x0000e000 +#define TX_BF_CAP_INFO_EXP_UNCMP_STEER_MAT_SHIFT 13 +#define TX_BF_CAP_INFO_EXP_CMP_STEER_MAT_FB 0x00070000 +#define TX_BF_CAP_INFO_EXP_CMP_STEER_MAT_FB_SHIFT 16 +#define TX_BF_CAP_INFO_CSI_NUM_BF_ANT 0x00180000 +#define TX_BF_CAP_INFO_CSI_NUM_BF_ANT_SHIFT 18 +#define TX_BF_CAP_INFO_UNCOMP_STEER_MAT_BF_ANT 0x00600000 +#define TX_BF_CAP_INFO_UNCOMP_STEER_MAT_BF_ANT_SHIFT 20 +#define TX_BF_CAP_INFO_COMP_STEER_MAT_BF_ANT 0x01800000 +#define TX_BF_CAP_INFO_COMP_STEER_MAT_BF_ANT_SHIFT 22 +#define TX_BF_CAP_INFO_RSVD 0xfe000000 + +/* defines for antenna selection info */ +#define ANTENNA_SEL_INFO 0x01 +#define ANTENNA_SEL_INFO_EXP_CSI_FB_TX 0x02 +#define ANTENNA_SEL_INFO_ANT_ID_FB_TX 0x04 +#define ANTENNA_SEL_INFO_EXP_CSI_FB 0x08 +#define ANTENNA_SEL_INFO_ANT_ID_FB 0x10 +#define ANTENNA_SEL_INFO_RX_AS 0x20 +#define ANTENNA_SEL_INFO_TX_SOUNDING_PPDU 0x40 +#define ANTENNA_SEL_INFO_RSVD 0x80 + +/** + * typedef connection_info_t - structure to store connection information + * @connState: connection state of the NIC + * @bssId: BSSID + * @SSID: SSID Info + * @staId: Station ID + * @peerMacAddress:Peer Mac Address of the IBSS Stations + * @authType: Auth Type + * @ucEncryptionType: Unicast Encryption Type + * @mcEncryptionType: Multicast Encryption Type + * @Keys: Keys + * @operationChannel: Operation Channel + * @uIsAuthenticated: Remembers authenticated state + * @dot11Mode: dot11Mode + * @proxyARPService: proxy arp service + * @ptk_installed: ptk installed state + * @gtk_installed: gtk installed state + * @nss: number of spatial streams negotiated + * @rate_flags: rate flags for current connection + * @freq: channel frequency + * @txrate: txrate structure holds nss & datarate info + * @noise: holds noise information + * @ht_caps: holds ht capabilities info + * @vht_caps: holds vht capabilities info + * @hs20vendor_ie: holds passpoint/hs20 info + * @conn_flag: flag conn info params is present or not + * @roam_count: roaming counter + * @signal: holds rssi info + * @assoc_status_code: holds assoc fail reason + * @congestion: holds congestion percentage + */ +typedef struct connection_info_s { + eConnectionState connState; + struct qdf_mac_addr bssId; + tCsrSSIDInfo SSID; + uint8_t staId[MAX_PEERS]; + struct qdf_mac_addr peerMacAddress[MAX_PEERS]; + eCsrAuthType authType; + eCsrEncryptionType ucEncryptionType; + eCsrEncryptionType mcEncryptionType; + tCsrKeys Keys; + uint8_t operationChannel; + uint8_t uIsAuthenticated; + uint32_t dot11Mode; + uint8_t proxyARPService; + bool ptk_installed; + bool gtk_installed; + uint8_t nss; + uint32_t rate_flags; + uint32_t freq; + struct rate_info txrate; + int8_t noise; + struct ieee80211_ht_cap ht_caps; + struct ieee80211_vht_cap vht_caps; + struct hdd_conn_flag conn_flag; + tDot11fIEhs20vendor_ie hs20vendor_ie; + struct ieee80211_ht_operation ht_operation; + struct ieee80211_vht_operation vht_operation; + uint32_t roam_count; + int8_t signal; + int32_t assoc_status_code; + uint32_t cca; +} connection_info_t; + +/* Forward declarations */ +typedef struct hdd_adapter_s hdd_adapter_t; +typedef struct hdd_context_s hdd_context_t; +typedef struct hdd_station_ctx hdd_station_ctx_t; +typedef struct hdd_ap_ctx_s hdd_ap_ctx_t; +typedef struct hdd_mon_ctx_s hdd_mon_ctx_t; + +/** + * hdd_is_connecting() - Function to check connection progress + * @hdd_sta_ctx: pointer to global HDD Station context + * + * Return: true if connecting, false otherwise + */ +bool hdd_is_connecting(hdd_station_ctx_t *hdd_sta_ctx); + +/** + * hdd_conn_is_connected() - Function to check connection status + * @pHddStaCtx: pointer to global HDD Station context + * + * Return: false if any errors encountered, true otherwise + */ +bool hdd_conn_is_connected(hdd_station_ctx_t *pHddStaCtx); + +/** + * hdd_conn_get_connected_band() - get current connection radio band + * @pHddStaCtx: pointer to global HDD Station context + * + * Return: eCSR_BAND_24 or eCSR_BAND_5G based on current AP connection + * eCSR_BAND_ALL if not connected + */ +eCsrBand hdd_conn_get_connected_band(hdd_station_ctx_t *pHddStaCtx); + +/** + * hdd_sme_roam_callback() - hdd sme roam callback + * @pContext: pointer to adapter context + * @pRoamInfo: pointer to roam info + * @roamId: roam id + * @roamStatus: roam status + * @roamResult: roam result + * + * Return: QDF_STATUS enumeration + */ +QDF_STATUS hdd_sme_roam_callback(void *pContext, tCsrRoamInfo *pRoamInfo, + uint32_t roamId, + eRoamCmdStatus roamStatus, + eCsrRoamResult roamResult); + +/** + * hdd_set_genie_to_csr() - set genie to csr + * @pAdapter: pointer to adapter + * @RSNAuthType: pointer to auth type + * + * Return: 0 on success, error number otherwise + */ +int hdd_set_genie_to_csr(hdd_adapter_t *pAdapter, eCsrAuthType *RSNAuthType); + +/** + * hdd_set_csr_auth_type() - set csr auth type + * @pAdapter: pointer to adapter + * @RSNAuthType: auth type + * + * Return: 0 on success, error number otherwise + */ +int hdd_set_csr_auth_type(hdd_adapter_t *pAdapter, eCsrAuthType RSNAuthType); + +#ifdef FEATURE_WLAN_TDLS +/** + * hdd_roam_register_tdlssta() - register new TDLS station + * @pAdapter: pointer to adapter + * @peerMac: pointer to peer MAC address + * @staId: station identifier + * @ucastSig: unicast signature + * + * Construct the staDesc and register with TL the new STA. + * This is called as part of ADD_STA in the TDLS setup. + * + * Return: QDF_STATUS enumeration + */ +QDF_STATUS hdd_roam_register_tdlssta(hdd_adapter_t *pAdapter, + const uint8_t *peerMac, uint16_t staId, + uint8_t ucastSig, uint8_t qos); +#endif + +QDF_STATUS hdd_roam_deregister_tdlssta(hdd_adapter_t *pAdapter, uint8_t staId); + +/** + * hdd_perform_roam_set_key_complete() - perform set key complete + * @pAdapter: pointer to adapter + * + * Return: none + */ +void hdd_perform_roam_set_key_complete(hdd_adapter_t *pAdapter); + +#ifdef FEATURE_WLAN_ESE +/** + * hdd_indicate_ese_bcn_report_no_results() - beacon report no scan results + * @pAdapter: pointer to adapter + * @measurementToken: measurement token + * @flag: flag + * @numBss: number of bss + * + * If the measurement is none and no scan results found, + * indicate the supplicant about measurement done. + * + * Return: none + */ +void +hdd_indicate_ese_bcn_report_no_results(const hdd_adapter_t *pAdapter, + const uint16_t measurementToken, + const bool flag, + const uint8_t numBss); +#endif /* FEATURE_WLAN_ESE */ + +QDF_STATUS hdd_change_peer_state(hdd_adapter_t *pAdapter, + uint8_t sta_id, + enum ol_txrx_peer_state sta_state, + bool roam_synch_in_progress); +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +bool hdd_is_roam_sync_in_progress(tCsrRoamInfo *roaminfo); +#else +static inline bool hdd_is_roam_sync_in_progress(tCsrRoamInfo *roaminfo) +{ + return false; +} +#endif + +QDF_STATUS hdd_roam_register_sta(struct hdd_adapter_s *adapter, + struct tagCsrRoamInfo *roam_info, + uint8_t sta_id, + struct qdf_mac_addr *peer_mac_addr, + struct sSirBssDescription *bss_desc); + +bool hdd_save_peer(hdd_station_ctx_t *sta_ctx, uint8_t sta_id, + struct qdf_mac_addr *peer_mac_addr); +void hdd_delete_peer(hdd_station_ctx_t *sta_ctx, uint8_t sta_id); +int hdd_get_peer_idx(hdd_station_ctx_t *sta_ctx, struct qdf_mac_addr *addr); +QDF_STATUS hdd_roam_deregister_sta(hdd_adapter_t *adapter, uint8_t sta_id); + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +void hdd_wma_send_fastreassoc_cmd(hdd_adapter_t *adapter, + const tSirMacAddr bssid, int channel); +#else +static inline void hdd_wma_send_fastreassoc_cmd(hdd_adapter_t *adapter, + const tSirMacAddr bssid, int channel) +{ +} +#endif + +#endif diff --git a/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_cfg.h b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_cfg.h new file mode 100644 index 0000000000000000000000000000000000000000..5e393768dfa8d19c002ea6833c6157663ae39b2c --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_cfg.h @@ -0,0 +1,11216 @@ +/* + * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#if !defined(HDD_CONFIG_H__) +#define HDD_CONFIG_H__ + +/** + * + * DOC: wlan_hdd_config.h + * + * WLAN Adapter Configuration functions + */ + +/* $HEADER$ */ + +/* Include files */ +#include +#include +#include +#include +#include +#include "osapi_linux.h" +#include + +#define FW_MODULE_LOG_LEVEL_STRING_LENGTH (255) +#define TX_SCHED_WRR_PARAM_STRING_LENGTH (50) +#define TX_SCHED_WRR_PARAMS_NUM (5) + +#define CFG_ENABLE_RX_THREAD (1 << 0) +#define CFG_ENABLE_RPS (1 << 1) +#define CFG_ENABLE_NAPI (1 << 2) + +#ifdef DHCP_SERVER_OFFLOAD +#define IPADDR_NUM_ENTRIES (4) +#define IPADDR_STRING_LENGTH (16) +#endif + +/* Number of items that can be configured */ +#define MAX_CFG_INI_ITEMS 1024 + +/* Defines for all of the things we read from the configuration (registry). */ + +/* + * + * RTSThreshold - Will provide RTSThreshold + * @Min: 0 + * @Max: 1048576 + * @Default: 2347 + * + * This ini is used to set default RTSThreshold + * If minimum value 0 is selectd then it will use always RTS + * + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ + +#define CFG_RTS_THRESHOLD_NAME "RTSThreshold" +#define CFG_RTS_THRESHOLD_MIN WNI_CFG_RTS_THRESHOLD_STAMIN /* min is 0, meaning always use RTS. */ +#define CFG_RTS_THRESHOLD_MAX WNI_CFG_RTS_THRESHOLD_STAMAX /* max is the max frame size */ +#define CFG_RTS_THRESHOLD_DEFAULT WNI_CFG_RTS_THRESHOLD_STADEF + +/* + * + * gFragmentationThreshold - It will set fragmentation threshold + * @Min: 256 + * @Max: 8000 + * @Default: 8000 + * + * This ini is used to indicate default fragmentation threshold + * + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ + +#define CFG_FRAG_THRESHOLD_NAME "gFragmentationThreshold" +#define CFG_FRAG_THRESHOLD_MIN WNI_CFG_FRAGMENTATION_THRESHOLD_STAMIN +#define CFG_FRAG_THRESHOLD_MAX WNI_CFG_FRAGMENTATION_THRESHOLD_STAMAX +#define CFG_FRAG_THRESHOLD_DEFAULT WNI_CFG_FRAGMENTATION_THRESHOLD_STADEF + +#define CFG_OPERATING_CHANNEL_NAME "gOperatingChannel" +#define CFG_OPERATING_CHANNEL_MIN (0) +#define CFG_OPERATING_CHANNEL_MAX (14) +#define CFG_OPERATING_CHANNEL_DEFAULT (1) + +/* + * + * gShortSlotTimeEnabled - It will set slot timing slot. + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to set default timing slot. + * + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ + +#define CFG_SHORT_SLOT_TIME_ENABLED_NAME "gShortSlotTimeEnabled" +#define CFG_SHORT_SLOT_TIME_ENABLED_MIN WNI_CFG_SHORT_SLOT_TIME_STAMIN +#define CFG_SHORT_SLOT_TIME_ENABLED_MAX WNI_CFG_SHORT_SLOT_TIME_STAMAX +#define CFG_SHORT_SLOT_TIME_ENABLED_DEFAULT WNI_CFG_SHORT_SLOT_TIME_STADEF + +#define CFG_11D_SUPPORT_ENABLED_NAME "g11dSupportEnabled" +#define CFG_11D_SUPPORT_ENABLED_MIN WNI_CFG_11D_ENABLED_STAMIN +#define CFG_11D_SUPPORT_ENABLED_MAX WNI_CFG_11D_ENABLED_STAMAX +#define CFG_11D_SUPPORT_ENABLED_DEFAULT WNI_CFG_11D_ENABLED_STADEF /* Default is ON */ + +#define CFG_11H_SUPPORT_ENABLED_NAME "g11hSupportEnabled" +#define CFG_11H_SUPPORT_ENABLED_MIN (0) +#define CFG_11H_SUPPORT_ENABLED_MAX (1) +#define CFG_11H_SUPPORT_ENABLED_DEFAULT (1) /* Default is ON */ + +/* COUNTRY Code Priority */ +#define CFG_COUNTRY_CODE_PRIORITY_NAME "gCountryCodePriority" +#define CFG_COUNTRY_CODE_PRIORITY_MIN (0) +#define CFG_COUNTRY_CODE_PRIORITY_MAX (1) +#define CFG_COUNTRY_CODE_PRIORITY_DEFAULT (0) + +#define CFG_HEARTBEAT_THRESH_24_NAME "gHeartbeat24" +#define CFG_HEARTBEAT_THRESH_24_MIN WNI_CFG_HEART_BEAT_THRESHOLD_STAMIN +#define CFG_HEARTBEAT_THRESH_24_MAX WNI_CFG_HEART_BEAT_THRESHOLD_STAMAX +#define CFG_HEARTBEAT_THRESH_24_DEFAULT WNI_CFG_HEART_BEAT_THRESHOLD_STADEF + +/* + * + * gMaxRxAmpduFactor - Provide the maximum ampdu factor. + * @Min: 0 + * @Max: 3 + * @Default: 3 + * + * This ini is used to set default maxampdu factor + * + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ + +#define CFG_MAX_RX_AMPDU_FACTOR_NAME "gMaxRxAmpduFactor" +#define CFG_MAX_RX_AMPDU_FACTOR_MIN WNI_CFG_MAX_RX_AMPDU_FACTOR_STAMIN +#define CFG_MAX_RX_AMPDU_FACTOR_MAX WNI_CFG_MAX_RX_AMPDU_FACTOR_STAMAX +#define CFG_MAX_RX_AMPDU_FACTOR_DEFAULT WNI_CFG_MAX_RX_AMPDU_FACTOR_STADEF + +/* Configuration option for HT MPDU density (Table 8-125 802.11-2012) + * 0 for no restriction + * 1 for 1/4 micro sec + * 2 for 1/2 micro sec + * 3 for 1 micro sec + * 4 for 2 micro sec + * 5 for 4 micro sec + * 6 for 8 micro sec + * 7 for 16 micro sec + */ +#define CFG_HT_MPDU_DENSITY_NAME "ght_mpdu_density" +#define CFG_HT_MPDU_DENSITY_MIN WNI_CFG_MPDU_DENSITY_STAMIN +#define CFG_HT_MPDU_DENSITY_MAX WNI_CFG_MPDU_DENSITY_STAMAX +#define CFG_HT_MPDU_DENSITY_DEFAULT WNI_CFG_MPDU_DENSITY_STADEF + +/* + * + * gEnableAdaptRxDrain - It will enable adapt received drain. + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to Configuration added to enable/disable CTS2SELF in + * Adaptive RX drain feature. + * + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ + +#define CFG_ENABLE_ADAPT_RX_DRAIN_NAME "gEnableAdaptRxDrain" +#define CFG_ENABLE_ADAPT_RX_DRAIN_MIN WNI_CFG_ENABLE_ADAPT_RX_DRAIN_STAMIN +#define CFG_ENABLE_ADAPT_RX_DRAIN_MAX WNI_CFG_ENABLE_ADAPT_RX_DRAIN_STAMAX +#define CFG_ENABLE_ADAPT_RX_DRAIN_DEFAULT WNI_CFG_ENABLE_ADAPT_RX_DRAIN_STADEF + +#define CFG_REG_CHANGE_DEF_COUNTRY_NAME "gRegulatoryChangeCountry" +#define CFG_REG_CHANGE_DEF_COUNTRY_DEFAULT (0) +#define CFG_REG_CHANGE_DEF_COUNTRY_MIN (0) +#define CFG_REG_CHANGE_DEF_COUNTRY_MAX (1) + +#define CFG_ADVERTISE_CONCURRENT_OPERATION_NAME "gAdvertiseConcurrentOperation" +#define CFG_ADVERTISE_CONCURRENT_OPERATION_DEFAULT (1) +#define CFG_ADVERTISE_CONCURRENT_OPERATION_MIN (0) +#define CFG_ADVERTISE_CONCURRENT_OPERATION_MAX (1) + +typedef enum { + eHDD_DOT11_MODE_AUTO = 0, /* covers all things we support */ + eHDD_DOT11_MODE_abg, /* 11a/b/g only, no HT, no proprietary */ + eHDD_DOT11_MODE_11b, + eHDD_DOT11_MODE_11g, + eHDD_DOT11_MODE_11n, + eHDD_DOT11_MODE_11g_ONLY, + eHDD_DOT11_MODE_11n_ONLY, + eHDD_DOT11_MODE_11b_ONLY, + eHDD_DOT11_MODE_11ac_ONLY, + eHDD_DOT11_MODE_11ac, + eHDD_DOT11_MODE_11a, +} eHddDot11Mode; + +/* + * + * gChannelBondingMode24GHz - Configures Channel Bonding in 24 GHz + * @Min: 0 + * @Max: 10 + * @Default: 0 + * + * This ini is used to set default channel bonding mode 24GHZ + * + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ + +#define CFG_CHANNEL_BONDING_MODE_24GHZ_NAME "gChannelBondingMode24GHz" +#define CFG_CHANNEL_BONDING_MODE_MIN WNI_CFG_CHANNEL_BONDING_MODE_STAMIN +#define CFG_CHANNEL_BONDING_MODE_MAX WNI_CFG_CHANNEL_BONDING_MODE_STAMAX +#define CFG_CHANNEL_BONDING_MODE_DEFAULT WNI_CFG_CHANNEL_BONDING_MODE_STADEF + +/* + * + * gChannelBondingMode5GHz - Configures Channel Bonding in 5 GHz + * @Min: 0 + * @Max: 10 + * @Default: 0 + * + * This ini is used to set default channel bonding mode 5GHZ + * + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ + +#define CFG_CHANNEL_BONDING_MODE_5GHZ_NAME "gChannelBondingMode5GHz" +#define CFG_CHANNEL_BONDING_MODE_MIN WNI_CFG_CHANNEL_BONDING_MODE_STAMIN +#define CFG_CHANNEL_BONDING_MODE_MAX WNI_CFG_CHANNEL_BONDING_MODE_STAMAX +#define CFG_CHANNEL_BONDING_MODE_DEFAULT WNI_CFG_CHANNEL_BONDING_MODE_STADEF + +/* + * + * gFixedRate - It will provide fixed rate + * @Min: 0 + * @Max: 44 + * @Default: 0 + * + * This ini is used to set default fixed rate + * + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ + +#define CFG_FIXED_RATE_NAME "gFixedRate" +#define CFG_FIXED_RATE_MIN WNI_CFG_FIXED_RATE_STAMIN +#define CFG_FIXED_RATE_MAX WNI_CFG_FIXED_RATE_STAMAX +#define CFG_FIXED_RATE_DEFAULT WNI_CFG_FIXED_RATE_STADEF + +/* + * + * gShortGI20Mhz - Short Guard Interval for HT20 + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to set default short interval for HT20 + * + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ + +#define CFG_SHORT_GI_20MHZ_NAME "gShortGI20Mhz" +#define CFG_SHORT_GI_20MHZ_MIN WNI_CFG_SHORT_GI_20MHZ_STAMIN +#define CFG_SHORT_GI_20MHZ_MAX WNI_CFG_SHORT_GI_20MHZ_STAMAX +#define CFG_SHORT_GI_20MHZ_DEFAULT WNI_CFG_SHORT_GI_20MHZ_STADEF + +/* + * + * gScanResultAgeCount - Set scan result age count + * @Min: 1 + * @Max: 100 + * @Default: 1 + * + * This ini parameter is the number of times a scan + * doesn't find it before it is removed from results. + * + * Related: None + * + * Supported Feature: Scan + * + * Usage: External + * + * + */ +#define CFG_SCAN_RESULT_AGE_COUNT_NAME "gScanResultAgeCount" +#define CFG_SCAN_RESULT_AGE_COUNT_MIN (1) +#define CFG_SCAN_RESULT_AGE_COUNT_MAX (100) +#define CFG_SCAN_RESULT_AGE_COUNT_DEFAULT (1) + +/* + * + * gNeighborScanTimerPeriod - Set neighbor scan timer period + * @Min: 3 + * @Max: 300 + * @Default: 200 + * + * This ini is used to set the timer period in secs after + * which neighbor scan is trigerred. + * + * Related: None + * + * Supported Feature: LFR Scan + * + * Usage: External + * + * + */ +#define CFG_NEIGHBOR_SCAN_TIMER_PERIOD_NAME "gNeighborScanTimerPeriod" +#define CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MIN (3) +#define CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MAX (300) +#define CFG_NEIGHBOR_SCAN_TIMER_PERIOD_DEFAULT (200) + +/* + * + * gOpportunisticThresholdDiff - Set oppurtunistic threshold diff + * @Min: 0 + * @Max: 127 + * @Default: 0 + * + * This ini is used to set opportunistic threshold diff. + * This parameter is the RSSI diff above neighbor lookup + * threshold, when opportunistic scan should be triggered. + * MAX value is choosen so that this type of scan can be + * always enabled by user. + * MIN value will cause opportunistic scan to be triggered + * in neighbor lookup RSSI range. + * + * Related: None + * + * Supported Feature: LFR Scan + * + * Usage: External + * + * + */ +#define CFG_OPPORTUNISTIC_SCAN_THRESHOLD_DIFF_NAME "gOpportunisticThresholdDiff" +#define CFG_OPPORTUNISTIC_SCAN_THRESHOLD_DIFF_MIN (0) +#define CFG_OPPORTUNISTIC_SCAN_THRESHOLD_DIFF_MAX (127) +#define CFG_OPPORTUNISTIC_SCAN_THRESHOLD_DIFF_DEFAULT (0) + +/* + * + * gNeighborScanChannelList - Set channels to be scanned + * by firmware for LFR scan + * @Default: "" + * + * This ini is used to set the channels to be scanned + * by firmware for LFR scan. + * + * Related: None + * + * Supported Feature: LFR Scan + * + * Usage: External + * + * + */ +#define CFG_NEIGHBOR_SCAN_CHAN_LIST_NAME "gNeighborScanChannelList" +#define CFG_NEIGHBOR_SCAN_CHAN_LIST_DEFAULT "" + +/* + * + * gNeighborScanChannelMinTime - Set neighbor scan channel min time + * @Min: 10 + * @Max: 40 + * @Default: 20 + * + * This ini is used to set the minimum time in secs spent on each + * channel in LFR scan inside firmware. + * + * Related: None + * + * Supported Feature: LFR Scan + * + * Usage: External + * + * + */ +#define CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_NAME "gNeighborScanChannelMinTime" +#define CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MIN (10) +#define CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MAX (40) +#define CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_DEFAULT (20) + +/* + * + * gNeighborScanChannelMaxTime - Set neighbor scan channel max time + * @Min: 3 + * @Max: 300 + * @Default: 30 + * + * This ini is used to set the maximum time in secs spent on each + * channel in LFR scan inside firmware. + * + * Related: None + * + * Supported Feature: LFR Scan + * + * Usage: External + * + * + */ +#define CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_NAME "gNeighborScanChannelMaxTime" +#define CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MIN (3) +#define CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MAX (300) +#define CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_DEFAULT (30) + +/* + * + * gNeighborScanRefreshPeriod - Set neighbor scan refresh period + * @Min: 1000 + * @Max: 60000 + * @Default: 20000 + * + * This ini is used by firmware to set scan refresh period + * in msecs for lfr scan. + * + * Related: None + * + * Supported Feature: LFR Scan + * + * Usage: External + * + * + */ +#define CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_NAME "gNeighborScanRefreshPeriod" +#define CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MIN (1000) +#define CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MAX (60000) +#define CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_DEFAULT (20000) + +/* + * + * gEmptyScanRefreshPeriod - Set empty scan refresh period + * @Min: 0 + * @Max: 60000 + * @Default: 0 + * + * This ini is used by firmware to set scan period in msecs + * following empty scan results. + * + * Related: None + * + * Supported Feature: LFR Scan + * + * Usage: External + * + * + */ +#define CFG_EMPTY_SCAN_REFRESH_PERIOD_NAME "gEmptyScanRefreshPeriod" +#define CFG_EMPTY_SCAN_REFRESH_PERIOD_MIN (0) +#define CFG_EMPTY_SCAN_REFRESH_PERIOD_MAX (60000) +#define CFG_EMPTY_SCAN_REFRESH_PERIOD_DEFAULT (0) + +/* + * + * gEnableDFSChnlScan - Enable DFS channel scan + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to enable or disable DFS channel + * scan + * + * Related: None + * + * Supported Feature: Scan + * + * Usage: External + * + * + */ +#define CFG_ENABLE_DFS_CHNL_SCAN_NAME "gEnableDFSChnlScan" +#define CFG_ENABLE_DFS_CHNL_SCAN_MIN (0) +#define CFG_ENABLE_DFS_CHNL_SCAN_MAX (1) +#define CFG_ENABLE_DFS_CHNL_SCAN_DEFAULT (1) + +/* + * + * gEnableDFSPnoChnlScan - Enable DFS PNO channel scan + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to enable or disable DFS channel + * for PNO scan + * + * Related: None + * + * Supported Feature: Scan + * + * Usage: External + * + * + */ +#define CFG_ENABLE_DFS_PNO_CHNL_SCAN_NAME "gEnableDFSPnoChnlScan" +#define CFG_ENABLE_DFS_PNO_CHNL_SCAN_MIN (0) +#define CFG_ENABLE_DFS_PNO_CHNL_SCAN_MAX (1) +#define CFG_ENABLE_DFS_PNO_CHNL_SCAN_DEFAULT (1) + +/* + * + * gEnableFirstScan2GOnly - Enable first scan 2G only + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to scan 2G channels only in first scan. + * + * Related: None + * + * Supported Feature: Scan + * + * Usage: External + * + * + */ +#define CFG_ENABLE_FIRST_SCAN_2G_ONLY_NAME "gEnableFirstScan2GOnly" +#define CFG_ENABLE_FIRST_SCAN_2G_ONLY_MIN (0) +#define CFG_ENABLE_FIRST_SCAN_2G_ONLY_MAX (1) +#define CFG_ENABLE_FIRST_SCAN_2G_ONLY_DEFAULT (0) + +/* + * + * gScanAgingTime - Set scan aging time + * @Min: 0 + * @Max: 200 + * @Default: 30 + * + * This ini is used to set scan aging timeout value + * in secs. For example after 30 secs the bss results + * greater than 30secs age will be flushed. + * + * Related: None + * + * Supported Feature: Scan + * + * Usage: External + * + * + */ +#define CFG_SCAN_AGING_PARAM_NAME "gScanAgingTime" +#define CFG_SCAN_AGING_PARAM_MIN (0) +#define CFG_SCAN_AGING_PARAM_MAX (200) +#define CFG_SCAN_AGING_PARAM_DEFAULT (30) + +#ifdef FEATURE_WLAN_SCAN_PNO +/* + * + * gPNOScanSupport - Enable or Disable PNO scan + * @Min: 1 + * @Max: 0 + * @Default: 1 + * + * This ini is used to Enable or Disable PNO scan + * + * Related: None + * + * Supported Feature: Scan + * + * Usage: External + * + * + */ +#define CFG_PNO_SCAN_SUPPORT "gPNOScanSupport" +#define CFG_PNO_SCAN_SUPPORT_ENABLE (1) +#define CFG_PNO_SCAN_SUPPORT_DISABLE (0) +#define CFG_PNO_SCAN_SUPPORT_DEFAULT (1) + +/* + * + * gPNOScanTimerRepeatValue - Set PNO scan timer repeat value + * @Min: 30 + * @Max: 0 + * @Default: 0xffffffff + * + * This ini is used by firmware to set fast scan max cycles + * equal to gPNOScanTimerRepeatValue. Taking power consumption + * into account firmware after gPNOScanTimerRepeatValue times + * fast_scan_period switches to slow_scan_period. + * + * Related: None + * + * Supported Feature: Scan + * + * Usage: External + * + * + */ +#define CFG_PNO_SCAN_TIMER_REPEAT_VALUE "gPNOScanTimerRepeatValue" +#define CFG_PNO_SCAN_TIMER_REPEAT_VALUE_DEFAULT (30) +#define CFG_PNO_SCAN_TIMER_REPEAT_VALUE_MIN (0) +#define CFG_PNO_SCAN_TIMER_REPEAT_VALUE_MAX (0xffffffff) + +/* + * + * gPNOSlowScanMultiplier - Set PNO slow scan multiplier + * @Min: 6 + * @Max: 0 + * @Default: 30 + * + * This ini is used by firmware to set slow scan period + * as gPNOSlowScanMultiplier times fast_scan_period. + * + * Related: None + * + * Supported Feature: Scan + * + * Usage: External + * + * + */ +#define CFG_PNO_SLOW_SCAN_MULTIPLIER "gPNOSlowScanMultiplier" +#define CFG_PNO_SLOW_SCAN_MULTIPLIER_DEFAULT (6) +#define CFG_PNO_SLOW_SCAN_MULTIPLIER_MIN (0) +#define CFG_PNO_SLOW_SCAN_MULTIPLIER_MAX (30) +#endif + +/* + * + * max_scan_count - Set maximum number of scans + * @Min: 1 + * @Max: 8 + * @Default: 4 + * + * This ini is used to set the maximum number of + * scans that host can queue at firmware. + * Rome firmware support 8 scan queue size and 4 + * are reserved for internal scan requests like + * roaming. So host can send 4 scan requests. + * In iHelium, there is no constraint in number of + * scan queue size at firmware but the current use + * cases needs support of maximum of 4 scan request + * from host. + * + * Related: None + * + * Supported Feature: Scan + * + * Usage: External + * + * + */ +#define CFG_MAX_SCAN_COUNT_NAME "max_scan_count" +#define CFG_MAX_SCAN_COUNT_MIN (1) +#define CFG_MAX_SCAN_COUNT_MAX (8) +#define CFG_MAX_SCAN_COUNT_DEFAULT (4) + +/* + * + * gPassiveMaxChannelTime - Set max channel time for passive scan + * @Min: 0 + * @Max: 10000 + * @Default: 110 + * + * This ini is used to set maximum channel time in secs spent in + * passive scan + * + * Related: None + * + * Supported Feature: Scan + * + * Usage: External + * + * + */ +#define CFG_PASSIVE_MAX_CHANNEL_TIME_NAME "gPassiveMaxChannelTime" +#define CFG_PASSIVE_MAX_CHANNEL_TIME_MIN (0) +#define CFG_PASSIVE_MAX_CHANNEL_TIME_MAX (10000) +#define CFG_PASSIVE_MAX_CHANNEL_TIME_DEFAULT (110) + +/* + * + * gPassiveMinChannelTime - Set min channel time for passive scan + * @Min: 0 + * @Max: 10000 + * @Default: 60 + * + * This ini is used to set minimum channel time in secs spent in + * passive scan + * + * Related: None + * + * Supported Feature: Scan + * + * Usage: External + * + * + */ +#define CFG_PASSIVE_MIN_CHANNEL_TIME_NAME "gPassiveMinChannelTime" +#define CFG_PASSIVE_MIN_CHANNEL_TIME_MIN (0) +#define CFG_PASSIVE_MIN_CHANNEL_TIME_MAX (10000) +#define CFG_PASSIVE_MIN_CHANNEL_TIME_DEFAULT (60) + +/* + * + * gActiveMaxChannelTime - Set max channel time for active scan + * @Min: 0 + * @Max: 10000 + * @Default: 40 + * + * This ini is used to set maximum channel time in secs spent in + * active scan + * + * Related: None + * + * Supported Feature: Scan + * + * Usage: External + * + * + */ +#define CFG_ACTIVE_MAX_CHANNEL_TIME_NAME "gActiveMaxChannelTime" +#define CFG_ACTIVE_MAX_CHANNEL_TIME_MIN (0) +#define CFG_ACTIVE_MAX_CHANNEL_TIME_MAX (10000) +#define CFG_ACTIVE_MAX_CHANNEL_TIME_DEFAULT (40) + +/* + * + * gActiveMinChannelTime - Set min channel time for active scan + * @Min: 0 + * @Max: 10000 + * @Default: 20 + * + * This ini is used to set minimum channel time in secs spent in + * active scan + * + * Related: None + * + * Supported Feature: Scan + * + * Usage: External + * + * + */ +#define CFG_ACTIVE_MIN_CHANNEL_TIME_NAME "gActiveMinChannelTime" +#define CFG_ACTIVE_MIN_CHANNEL_TIME_MIN (0) +#define CFG_ACTIVE_MIN_CHANNEL_TIME_MAX (10000) +#define CFG_ACTIVE_MIN_CHANNEL_TIME_DEFAULT (20) + +/* + * + * gScanNumProbes - Set the number of probes on each channel for active scan + * @Min: 0 + * @Max: 20 + * @Default: 0 + * + * This ini is used to set number of probes on each channel for + * active scan + * + * Related: None + * + * Supported Feature: Scan + * + * Usage: External + * + * + */ +#define CFG_SCAN_NUM_PROBES_NAME "gScanNumProbes" +#define CFG_SCAN_NUM_PROBES_MIN (0) +#define CFG_SCAN_NUM_PROBES_MAX (20) +#define CFG_SCAN_NUM_PROBES_DEFAULT (0) + +/* + * + * gScanProbeRepeatTime - Set probe repeat time on each channel for active scan + * @Min: 0 + * @Max: 30 + * @Default: 0 + * + * This ini is used to set probe repeat time on each channel for + * active scan + * + * Related: None + * + * Supported Feature: Scan + * + * Usage: External + * + * + */ +#define CFG_SCAN_PROBE_REPEAT_TIME_NAME "gScanProbeRepeatTime" +#define CFG_SCAN_PROBE_REPEAT_TIME_MIN (0) +#define CFG_SCAN_PROBE_REPEAT_TIME_MAX (30) +#define CFG_SCAN_PROBE_REPEAT_TIME_DEFAULT (0) + +/* + * + * allow_adj_chan_bcns - Set to accept the beacons from adjacent channels + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to accept the beacons from adjacent channels + * + * Related: None + * + * Supported Feature: Scan + * + * Usage: External + * + * + */ +#define CFG_SCAN_ALLOW_ADJ_CH_BCN_NAME "allow_adj_chan_bcns" +#define CFG_SCAN_ALLOW_ADJ_CH_BCN_MIN (0) +#define CFG_SCAN_ALLOW_ADJ_CH_BCN_MAX (1) +#define CFG_SCAN_ALLOW_ADJ_CH_BCN_DEFAULT (0) + +#ifdef FEATURE_WLAN_EXTSCAN +/* + * + * gExtScanEnable - Enable external scan + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to control enabling of external scan + * feature. + * + * Related: None + * + * Supported Feature: Scan + * + * Usage: External + * + * + */ +#define CFG_EXTSCAN_ALLOWED_NAME "gExtScanEnable" +#define CFG_EXTSCAN_ALLOWED_MIN (0) +#define CFG_EXTSCAN_ALLOWED_MAX (1) +#define CFG_EXTSCAN_ALLOWED_DEF (1) + +/* + * + * gExtScanPassiveMaxChannelTime - Set max channel time for external + * passive scan + * @Min: 0 + * @Max: 500 + * @Default: 110 + * + * This ini is used to set maximum channel time in secs spent in + * external passive scan + * + * Related: None + * + * Supported Feature: Scan + * + * Usage: External + * + * + */ +#define CFG_EXTSCAN_PASSIVE_MAX_CHANNEL_TIME_NAME "gExtScanPassiveMaxChannelTime" +#define CFG_EXTSCAN_PASSIVE_MAX_CHANNEL_TIME_MIN (0) +#define CFG_EXTSCAN_PASSIVE_MAX_CHANNEL_TIME_MAX (500) +#define CFG_EXTSCAN_PASSIVE_MAX_CHANNEL_TIME_DEFAULT (110) + +/* + * + * gExtScanPassiveMinChannelTime - Set min channel time for external + * passive scan + * @Min: 0 + * @Max: 500 + * @Default: 60 + * + * This ini is used to set minimum channel time in secs spent in + * external passive scan + * + * Related: None + * + * Supported Feature: Scan + * + * Usage: External + * + * + */ +#define CFG_EXTSCAN_PASSIVE_MIN_CHANNEL_TIME_NAME "gExtScanPassiveMinChannelTime" +#define CFG_EXTSCAN_PASSIVE_MIN_CHANNEL_TIME_MIN (0) +#define CFG_EXTSCAN_PASSIVE_MIN_CHANNEL_TIME_MAX (500) +#define CFG_EXTSCAN_PASSIVE_MIN_CHANNEL_TIME_DEFAULT (60) + +/* + * + * gExtScanActiveMaxChannelTime - Set min channel time for external + * active scan + * @Min: 0 + * @Max: 110 + * @Default: 40 + * + * This ini is used to set maximum channel time in secs spent in + * external active scan + * + * Related: None + * + * Supported Feature: Scan + * + * Usage: External + * + * + */ +#define CFG_EXTSCAN_ACTIVE_MAX_CHANNEL_TIME_NAME "gExtScanActiveMaxChannelTime" +#define CFG_EXTSCAN_ACTIVE_MAX_CHANNEL_TIME_MIN (0) +#define CFG_EXTSCAN_ACTIVE_MAX_CHANNEL_TIME_MAX (110) +#define CFG_EXTSCAN_ACTIVE_MAX_CHANNEL_TIME_DEFAULT (40) + +/* + * + * gExtScanActiveMinChannelTime - Set min channel time for external + * active scan + * @Min: 0 + * @Max: 110 + * @Default: 20 + * + * This ini is used to set minimum channel time in secs spent in + * external active scan + * + * Related: None + * + * Supported Feature: Scan + * + * Usage: External + * + * + */ +#define CFG_EXTSCAN_ACTIVE_MIN_CHANNEL_TIME_NAME "gExtScanActiveMinChannelTime" +#define CFG_EXTSCAN_ACTIVE_MIN_CHANNEL_TIME_MIN (0) +#define CFG_EXTSCAN_ACTIVE_MIN_CHANNEL_TIME_MAX (110) +#define CFG_EXTSCAN_ACTIVE_MIN_CHANNEL_TIME_DEFAULT (20) +#endif + +/* + * + * gChPredictionFullScanMs - Set periodic timer for channel + * prediction + * @Min: 3000 + * @Max: 0x7fffffff + * @Default: 60000 + * + * This ini is used to set the periodic timer upon which + * a full scan needs to be triggered when PNO channel + * prediction feature is enabled. This parameter is intended + * to tweak the internal algortihm for experiments. + * + * Related: None + * + * Supported Feature: Scan + * + * Usage: Internal + * + * + */ +#define CFG_CHANNEL_PREDICTION_FULL_SCAN_MS_NAME "gChPredictionFullScanMs" +#define CFG_CHANNEL_PREDICTION_FULL_SCAN_MS_MIN (30000) +#define CFG_CHANNEL_PREDICTION_FULL_SCAN_MS_MAX (0x7fffffff) +#define CFG_CHANNEL_PREDICTION_FULL_SCAN_MS_DEFAULT (60000) + +/* + * + * gEnableEarlyStopScan - Set early stop scan + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to set early stop scan. Early stop + * scan is a feature for roaming to stop the scans at + * an early stage as soon as we find a better AP to roam. + * This would make the roaming happen quickly. + * + * Related: None + * + * Supported Feature: LFR Scan + * + * Usage: External + * + * + */ +#define CFG_EARLY_STOP_SCAN_ENABLE "gEnableEarlyStopScan" +#define CFG_EARLY_STOP_SCAN_ENABLE_MIN (0) +#define CFG_EARLY_STOP_SCAN_ENABLE_MAX (1) +#define CFG_EARLY_STOP_SCAN_ENABLE_DEFAULT (1) + +/* + * + * gEarlyStopScanMinThreshold - Set early stop scan min + * threshold + * @Min: -80 + * @Max: -70 + * @Default: -73 + * + * This ini is used to set the early stop scan minimum + * threshold. Early stop scan minimum threshold is the + * minimum threshold to be considered for stopping the + * scan. The algorithm starts with a scan on the greedy + * channel list with the maximum threshold and steps down + * the threshold by 20% for each further channel. It can + * step down on each channel but cannot go lower than the + * minimum threshold. + * + * Related: None + * + * Supported Feature: Scan + * + * Usage: External + * + * + */ +#define CFG_EARLY_STOP_SCAN_MIN_THRESHOLD "gEarlyStopScanMinThreshold" +#define CFG_EARLY_STOP_SCAN_MIN_THRESHOLD_MIN (-80) +#define CFG_EARLY_STOP_SCAN_MIN_THRESHOLD_MAX (-70) +#define CFG_EARLY_STOP_SCAN_MIN_THRESHOLD_DEFAULT (-73) + +/* + * + * gEarlyStopScanMaxThreshold - Set early stop scan max + * threshold + * @Min: -60 + * @Max: -40 + * @Default: -43 + * + * This ini is used to set the the early stop scan maximum + * threshold at which the candidate AP should be to be + * qualified as a potential roam candidate and good enough + * to stop the roaming scan. + * + * Related: None + * + * Supported Feature: Scan + * + * Usage: External + * + * + */ +#define CFG_EARLY_STOP_SCAN_MAX_THRESHOLD "gEarlyStopScanMaxThreshold" +#define CFG_EARLY_STOP_SCAN_MAX_THRESHOLD_MIN (-60) +#define CFG_EARLY_STOP_SCAN_MAX_THRESHOLD_MAX (-40) +#define CFG_EARLY_STOP_SCAN_MAX_THRESHOLD_DEFAULT (-43) + +/* + * + * gFirstScanBucketThreshold - Set first scan bucket + * threshold + * @Min: -50 + * @Max: -30 + * @Default: -30 + * + * This ini will configure the first scan bucket + * threshold to the mentioned value and all the AP's which + * have RSSI under this threshold will fall under this + * bucket. This configuration item used to tweak and + * test the input for internal algorithm. + * + * Related: None + * + * Supported Feature: Scan + * + * Usage: Internal + * + * + */ +#define CFG_FIRST_SCAN_BUCKET_THRESHOLD_NAME "gFirstScanBucketThreshold" +#define CFG_FIRST_SCAN_BUCKET_THRESHOLD_MIN (-50) +#define CFG_FIRST_SCAN_BUCKET_THRESHOLD_MAX (-30) +#define CFG_FIRST_SCAN_BUCKET_THRESHOLD_DEFAULT (-30) + +/* + * + * obss_active_dwelltime - Set obss active dwelltime + * @Min: 5 + * @Max: 1000 + * @Default: 10 + * + * This ini is used to set dwell time in secs for active + * obss scan + * + * Related: None + * + * Supported Feature: Scan + * + * Usage: External + * + * + */ +#define CFG_OBSS_HT40_SCAN_ACTIVE_DWELL_TIME_NAME "obss_active_dwelltime" +#define CFG_OBSS_HT40_SCAN_ACTIVE_DWELL_TIME_MIN (5) +#define CFG_OBSS_HT40_SCAN_ACTIVE_DWELL_TIME_MAX (1000) +#define CFG_OBSS_HT40_SCAN_ACTIVE_DWELL_TIME_DEFAULT (10) + +/* + * + * obss_passive_dwelltime - Set obss passive dwelltime + * @Min: 10 + * @Max: 1000 + * @Default: 20 + * + * This ini is used to set dwell time in secs for passive + * obss scan + * + * Related: None + * + * Supported Feature: Scan + * + * Usage: External + * + * + */ +#define CFG_OBSS_HT40_SCAN_PASSIVE_DWELL_TIME_NAME "obss_passive_dwelltime" +#define CFG_OBSS_HT40_SCAN_PASSIVE_DWELL_TIME_MIN (10) +#define CFG_OBSS_HT40_SCAN_PASSIVE_DWELL_TIME_MAX (1000) +#define CFG_OBSS_HT40_SCAN_PASSIVE_DWELL_TIME_DEFAULT (20) + +/* + * + * obss_width_trigger_interval - Set obss trigger interval + * @Min: 10 + * @Max: 900 + * @Default: 200 + * + * This ini is used during an OBSS scan operation, + * where each channel in the set is scanned at least + * once per configured trigger interval time. + * + * Related: None + * + * Supported Feature: Scan + * + * Usage: External + * + * + */ +#define CFG_OBSS_HT40_SCAN_WIDTH_TRIGGER_INTERVAL_NAME "obss_width_trigger_interval" +#define CFG_OBSS_HT40_SCAN_WIDTH_TRIGGER_INTERVAL_MIN (10) +#define CFG_OBSS_HT40_SCAN_WIDTH_TRIGGER_INTERVAL_MAX (900) +#define CFG_OBSS_HT40_SCAN_WIDTH_TRIGGER_INTERVAL_DEFAULT (200) + +/* + * + * gbug_report_for_scan_results - Enable bug report + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to create bug report in + * case of nil scan results. + * + * Related: None + * + * Supported Feature: Scan + * + * Usage: External + * + * + */ +#define CFG_CREATE_BUG_REPORT_FOR_SCAN "gbug_report_for_scan_results" +#define CFG_CREATE_BUG_REPORT_FOR_SCAN_DISABLE (0) +#define CFG_CREATE_BUG_REPORT_FOR_SCAN_ENABLE (1) +#define CFG_CREATE_BUG_REPORT_FOR_SCAN_DEFAULT (0) + +/* + * + * hostscan_adaptive_dwell_mode - Enable adaptive dwell mode + * during host scan + * @Min: 0 + * @Max: 4 + * @Default: 0 + * + * This ini will set the algo used in dwell time optimization + * during host scan. see enum wmi_dwelltime_adaptive_mode. + * Acceptable values for this: + * 0: Default (Use firmware default mode) + * 1: Conservative optimization + * 2: Moderate optimization + * 3: Aggressive optimization + * 4: Static + * + * Related: None + * + * Supported Feature: Scan + * + * Usage: External + * + * + */ +#define CFG_ADAPTIVE_SCAN_DWELL_MODE_NAME "hostscan_adaptive_dwell_mode" +#define CFG_ADAPTIVE_SCAN_DWELL_MODE_MIN (0) +#define CFG_ADAPTIVE_SCAN_DWELL_MODE_MAX (4) +#define CFG_ADAPTIVE_SCAN_DWELL_MODE_DEFAULT (0) + +/* + * + * extscan_adaptive_dwell_mode - Enable adaptive dwell mode + * during ext scan + * @Min: 0 + * @Max: 4 + * @Default: 0 + * + * This ini will set the algo used in dwell time optimization + * during ext scan. see enum wmi_dwelltime_adaptive_mode. + * Acceptable values for this: + * 0: Default (Use firmware default mode) + * 1: Conservative optimization + * 2: Moderate optimization + * 3: Aggressive optimization + * 4: Static + * + * Related: None + * + * Supported Feature: Scan + * + * Usage: External + * + * + */ +#define CFG_ADAPTIVE_EXTSCAN_DWELL_MODE_NAME "extscan_adaptive_dwell_mode" +#define CFG_ADAPTIVE_EXTSCAN_DWELL_MODE_MIN (0) +#define CFG_ADAPTIVE_EXTSCAN_DWELL_MODE_MAX (4) +#define CFG_ADAPTIVE_EXTSCAN_DWELL_MODE_DEFAULT (0) + +/* + * + * pnoscan_adaptive_dwell_mode - Enable adaptive dwell mode + * during pno scan + * @Min: 0 + * @Max: 4 + * @Default: 0 + * + * This ini will set the algo used in dwell time optimization + * during pno scan. see enum wmi_dwelltime_adaptive_mode. + * Acceptable values for this: + * 0: Default (Use firmware default mode) + * 1: Conservative optimization + * 2: Moderate optimization + * 3: Aggressive optimization + * 4: Static + * + * Related: None + * + * Supported Feature: Scan + * + * Usage: External + * + * + */ +#define CFG_ADAPTIVE_PNOSCAN_DWELL_MODE_NAME "pnoscan_adaptive_dwell_mode" +#define CFG_ADAPTIVE_PNOSCAN_DWELL_MODE_MIN (0) +#define CFG_ADAPTIVE_PNOSCAN_DWELL_MODE_MAX (4) +#define CFG_ADAPTIVE_PNOSCAN_DWELL_MODE_DEFAULT (0) + +/* + * + * adaptive_dwell_mode_enabled - Enable adaptive dwell mode + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This parameter will globally disable/enable the adaptive dwell config. + * Following parameters will set different values of attributes for dwell + * time optimization thus reducing total scan time. + * Acceptable values for this: + * 0: Config is disabled + * 1: Config is enabled + * + * Related: None + * + * Supported Feature: Scan + * + * Usage: External + * + * + */ +#define CFG_ADAPTIVE_DWELL_MODE_ENABLED_NAME "adaptive_dwell_mode_enabled" +#define CFG_ADAPTIVE_DWELL_MODE_ENABLED_MIN (0) +#define CFG_ADAPTIVE_DWELL_MODE_ENABLED_MAX (1) +#define CFG_ADAPTIVE_DWELL_MODE_ENABLED_DEFAULT (1) + +/* + * + * global_adapt_dwelltime_mode - Set default adaptive mode + * @Min: 0 + * @Max: 4 + * @Default: 1 + * + * This parameter will set default adaptive mode, will be used if any of the + * scan dwell mode is set to default. + * For uses : see enum wmi_dwelltime_adaptive_mode + * + * Related: None + * + * Supported Feature: Scan + * + * Usage: External + * + * + */ +#define CFG_GLOBAL_ADAPTIVE_DWELL_MODE_NAME "global_adapt_dwelltime_mode" +#define CFG_GLOBAL_ADAPTIVE_DWELL_MODE_MIN (0) +#define CFG_GLOBAL_ADAPTIVE_DWELL_MODE_MAX (4) +#define CFG_GLOBAL_ADAPTIVE_DWELL_MODE_DEFAULT (1) + +/* + * gRssiCatGap - Set Rssi CatGap + * @Min: 5 + * @Max: 100 + * @Default: 5 + * + * This ini is used to set default RssiCatGap + * + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ + +#define CFG_RSSI_CATEGORY_GAP_NAME "gRssiCatGap" +#define CFG_RSSI_CATEGORY_GAP_MIN (5) +#define CFG_RSSI_CATEGORY_GAP_MAX (100) +#define CFG_RSSI_CATEGORY_GAP_DEFAULT (5) + +/* + * + * gRoamPrefer5GHz - Prefer roaming to 5GHz Bss + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to inform FW to prefer roaming to 5GHz BSS + * + * Related: None + * + * Supported Feature: Roaming + * + * Usage: External + * + * + */ +#define CFG_ROAM_PREFER_5GHZ "gRoamPrefer5GHz" +#define CFG_ROAM_PREFER_5GHZ_MIN (0) +#define CFG_ROAM_PREFER_5GHZ_MAX (1) +#define CFG_ROAM_PREFER_5GHZ_DEFAULT (1) + +/* + * + * gRoamIntraBand - Prefer roaming within Band + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to inform FW to prefer roaming within band + * + * Related: None + * + * Supported Feature: Roaming + * + * Usage: External + * + * + */ +#define CFG_ROAM_INTRA_BAND "gRoamIntraBand" +#define CFG_ROAM_INTRA_BAND_MIN (0) +#define CFG_ROAM_INTRA_BAND_MAX (1) +#define CFG_ROAM_INTRA_BAND_DEFAULT (0) + +/* + * + * FastRoamEnabled - Enable fast roaming + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to inform FW to enable fast roaming + * + * Related: None + * + * Supported Feature: Roaming + * + * Usage: External + * + * + */ +#define CFG_LFR_FEATURE_ENABLED_NAME "FastRoamEnabled" +#define CFG_LFR_FEATURE_ENABLED_MIN (0) +#define CFG_LFR_FEATURE_ENABLED_MAX (1) +#define CFG_LFR_FEATURE_ENABLED_DEFAULT (0) + +/* + * + * FastTransitionEnabled - Enable fast transition in case of 11r and ese. + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to turn ON/OFF the whole neighbor roam, pre-auth, reassoc. + * With this turned OFF 11r will completely not work. For 11r this flag has to + * be ON. For ESE fastroam will not work. + * + * Related: None + * + * Supported Feature: Roaming + * + * Usage: External + * + * + */ +#define CFG_FAST_TRANSITION_ENABLED_NAME "FastTransitionEnabled" +#define CFG_FAST_TRANSITION_ENABLED_NAME_MIN (0) +#define CFG_FAST_TRANSITION_ENABLED_NAME_MAX (1) +#define CFG_FAST_TRANSITION_ENABLED_NAME_DEFAULT (1) + +/* + * + * RoamRssiDiff - Enable roam based on rssi + * @Min: 0 + * @Max: 30 + * @Default: 5 + * + * This INI is used to decide whether to Roam or not based on RSSI. AP1 is the + * currently associated AP and AP2 is chosen for roaming. The Roaming will + * happen only if AP2 has better Signal Quality and it has a RSSI better than + * AP2. RoamRssiDiff is the number of units (typically measured in dB) AP2 + * is better than AP1. + * + * Related: None + * + * Supported Feature: Roaming + * + * Usage: External + * + * + */ +#define CFG_ROAM_RSSI_DIFF_NAME "RoamRssiDiff" +#define CFG_ROAM_RSSI_DIFF_MIN (0) +#define CFG_ROAM_RSSI_DIFF_MAX (30) +#define CFG_ROAM_RSSI_DIFF_DEFAULT (5) + +/* + * + * gRoamScanNProbes - Sets the number of probes to be sent for firmware roaming + * @Min: 1 + * @Max: 10 + * @Default: 2 + * + * This INI is used to set the maximum number of probes the firmware can send + * for firmware internal roaming cases. + * + * Related: None + * + * Supported Feature: Roaming + * + * Usage: External + * + * + */ +#define CFG_ROAM_SCAN_N_PROBES "gRoamScanNProbes" +#define CFG_ROAM_SCAN_N_PROBES_MIN (1) +#define CFG_ROAM_SCAN_N_PROBES_MAX (10) +#define CFG_ROAM_SCAN_N_PROBES_DEFAULT (2) + +/* + * + * gRoamScanHomeAwayTime - Sets the Home Away Time to firmware + * @Min: 0 + * @Max: 300 + * @Default: 0 + * + * Home Away Time should be at least equal to (gNeighborScanChannelMaxTime + * + (2*RFS)), where RFS is the RF Switching time(3). It is twice RFS + * to consider the time to go off channel and return to the home channel. + * + * Related: gNeighborScanChannelMaxTime + * + * Supported Feature: Roaming + * + * Usage: External + * + * + */ +#define CFG_ROAM_SCAN_HOME_AWAY_TIME "gRoamScanHomeAwayTime" +#define CFG_ROAM_SCAN_HOME_AWAY_TIME_MIN (0) +#define CFG_ROAM_SCAN_HOME_AWAY_TIME_MAX (300) +#define CFG_ROAM_SCAN_HOME_AWAY_TIME_DEFAULT (0) + +/* + * + * pmkidModes - Enable PMKID modes + * @Min: 0 + * @Max: 3 + * @Default: 3 + * + * This INI is used to enable PMKID feature options + * Bit 0 = Enable Opportunistic key caching + * Bit 1 = Enable PMKSA caching + * + * Related: None + * + * Supported Feature: Firmware based roaming + * + * Usage: Internal + * + * + */ +#define CFG_PMKID_MODES_NAME "pmkidModes" +#define CFG_PMKID_MODES_MIN (0x0) +#define CFG_PMKID_MODES_MAX (0x3) +#define CFG_PMKID_MODES_DEFAULT (0x3) +#define CFG_PMKID_MODES_OKC (0x1) +#define CFG_PMKID_MODES_PMKSA_CACHING (0x2) + +/* + * + * gRoamScanOffloadEnabled - Enable Roam Scan Offload + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This INI is used to enable Roam Scan Offload in firmware + * + * Related: None + * + * Supported Feature: Roaming + * + * Usage: External + * + * + */ +#define CFG_ROAM_SCAN_OFFLOAD_ENABLED "gRoamScanOffloadEnabled" +#define CFG_ROAM_SCAN_OFFLOAD_ENABLED_MIN (0) +#define CFG_ROAM_SCAN_OFFLOAD_ENABLED_MAX (1) +#define CFG_ROAM_SCAN_OFFLOAD_ENABLED_DEFAULT (1) + +/* + * + * gRoamRescanRssiDiff - Sets RSSI for Scan trigger in firmware + * @Min: 0 + * @Max: 100 + * @Default: 5 + * + * This INI is the drop in RSSI value that will trigger a precautionary + * scan by firmware. Max value is chosen in such a way that this type + * of scan can be disabled by user. + * + * Related: None + * + * Supported Feature: Roaming + * + * Usage: External + * + * + */ +#define CFG_ROAM_RESCAN_RSSI_DIFF_NAME "gRoamRescanRssiDiff" +#define CFG_ROAM_RESCAN_RSSI_DIFF_MIN (0) +#define CFG_ROAM_RESCAN_RSSI_DIFF_MAX (100) +#define CFG_ROAM_RESCAN_RSSI_DIFF_DEFAULT (5) + +/* + * + * gDroppedPktDisconnectTh - Sets dropped packet threshold in firmware + * @Min: 0 + * @Max: 512 + * @Default: 512 + * + * This INI is the packet drop threshold will trigger disconnect from remote + * peer. + * + * Related: None + * + * Supported Feature: connection + * + * Usage: External + * + * + */ +#define CFG_DROPPED_PKT_DISCONNECT_TH_NAME "gDroppedPktDisconnectTh" +#define CFG_DROPPED_PKT_DISCONNECT_TH_MIN (0) +#define CFG_DROPPED_PKT_DISCONNECT_TH_MAX (65535) +#define CFG_DROPPED_PKT_DISCONNECT_TH_DEFAULT (512) + +/* + * + * gForce1x1Exception - force 1x1 when connecting to certain peer + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This INI when enabled will force 1x1 connection with certain peer. + * + * + * Related: None + * + * Supported Feature: connection + * + * Usage: External + * + * + */ +#define CFG_FORCE_1X1_NAME "gForce1x1Exception" +#define CFG_FORCE_1X1_MIN (0) +#define CFG_FORCE_1X1_MAX (1) +#define CFG_FORCE_1X1_DEFAULT (0) + +/* + * + * g11bNumTxChains - Number of Tx Chanins in 11b mode + * @Min: 0 + * @Max: 2 + * @Default: 0 + * + * Number of Tx Chanins in 11b mode + * + * + * Related: None + * + * Supported Feature: connection + * + * Usage: External + * + * + */ +#define CFG_11B_NUM_TX_CHAIN_NAME "g11bNumTxChains" +#define CFG_11B_NUM_TX_CHAIN_MIN (0) +#define CFG_11B_NUM_TX_CHAIN_MAX (2) +#define CFG_11B_NUM_TX_CHAIN_DEFAULT (0) + +/* + * + * g11agNumTxChains - Number of Tx Chanins in 11ag mode + * @Min: 1 + * @Max: 4 + * @Default: 1 + * + * Number of Tx Chanins in 11ag mode + * + * + * Related: None + * + * Supported Feature: connection + * + * Usage: External + * + * + */ +#define CFG_11AG_NUM_TX_CHAIN_NAME "g11agNumTxChains" +#define CFG_11AG_NUM_TX_CHAIN_MIN (1) +#define CFG_11AG_NUM_TX_CHAIN_MAX (4) +#define CFG_11AG_NUM_TX_CHAIN_DEFAULT (1) + +/* + * + * gEnableFastRoamInConcurrency - Enable LFR roaming on STA during concurrency + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This INI is used to enable Legacy fast roaming(LFR) on STA link during + * concurrent sessions. + * + * Related: None + * + * Supported Feature: Roaming + * + * Usage: External + * + * + */ +#define CFG_ENABLE_FAST_ROAM_IN_CONCURRENCY "gEnableFastRoamInConcurrency" +#define CFG_ENABLE_FAST_ROAM_IN_CONCURRENCY_MIN (0) +#define CFG_ENABLE_FAST_ROAM_IN_CONCURRENCY_MAX (1) +#define CFG_ENABLE_FAST_ROAM_IN_CONCURRENCY_DEFAULT (1) + +/* + * + * gSelect5GHzMargin - Sets RSSI preference for 5GHz over 2.4GHz AP. + * @Min: 0 + * @Max: 60 + * @Default: 0 + * + * Prefer connecting to 5G AP even if its RSSI is lower by gSelect5GHzMargin + * dBm than 2.4G AP. This feature requires the dependent cfg.ini + * "gRoamPrefer5GHz" set to 1 + * + * Related: gRoamPrefer5GHz + * + * Supported Feature: Roaming + * + * Usage: External + * + * + */ +#define CFG_STRICT_5GHZ_PREF_BY_MARGIN "gSelect5GHzMargin" +#define CFG_STRICT_5GHZ_PREF_BY_MARGIN_MIN (0) +#define CFG_STRICT_5GHZ_PREF_BY_MARGIN_MAX (60) +#define CFG_STRICT_5GHZ_PREF_BY_MARGIN_DEFAULT (0) + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +/* + * + * gRoamOffloadEnabled - enable/disable roam offload feature + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This INI is used to enable/disable roam offload feature + * + * Related: None + * + * Supported Feature: Roaming + * + * Usage: External + * + * + */ +#define CFG_ROAMING_OFFLOAD_NAME "gRoamOffloadEnabled" +#define CFG_ROAMING_OFFLOAD_MIN (0) +#define CFG_ROAMING_OFFLOAD_MAX (1) +#define CFG_ROAMING_OFFLOAD_DEFAULT (1) +#endif + +/* + * + * gRoamScanHiRssiMaxCount - Sets 5GHz maximum scan count + * @Min: 0 + * @Max: 10 + * @Default: 3 + * + * This INI is used to set maximum scan count in 5GHz + * + * Related: None + * + * Supported Feature: Roaming + * + * Usage: External + * + * + */ +#define CFG_ROAM_SCAN_HI_RSSI_MAXCOUNT_NAME "gRoamScanHiRssiMaxCount" +#define CFG_ROAM_SCAN_HI_RSSI_MAXCOUNT_MIN (0) +#define CFG_ROAM_SCAN_HI_RSSI_MAXCOUNT_MAX (10) +#define CFG_ROAM_SCAN_HI_RSSI_MAXCOUNT_DEFAULT (3) + +/* + * + * gRoamScanHiRssiDelta - Sets RSSI Delta for scan trigger + * @Min: 0 + * @Max: 16 + * @Default: 10 + * + * This INI is used to set change in RSSI at which scan is triggered + * in 5GHz. + * + * Related: None + * + * Supported Feature: Roaming + * + * Usage: External + * + * + */ +#define CFG_ROAM_SCAN_HI_RSSI_DELTA_NAME "gRoamScanHiRssiDelta" +#define CFG_ROAM_SCAN_HI_RSSI_DELTA_MIN (0) +#define CFG_ROAM_SCAN_HI_RSSI_DELTA_MAX (16) +#define CFG_ROAM_SCAN_HI_RSSI_DELTA_DEFAULT (10) + +/* + * + * gRoamScanHiRssiDelay - Sets minimum delay between 5GHz scans + * @Min: 5000 + * @Max: 0x7fffffff + * @Default: 15000 + * + * This INI is used to set the minimum delay between 5GHz scans. + * + * Related: None + * + * Supported Feature: Roaming + * + * Usage: External + * + * + */ +#define CFG_ROAM_SCAN_HI_RSSI_DELAY_NAME "gRoamScanHiRssiDelay" +#define CFG_ROAM_SCAN_HI_RSSI_DELAY_MIN (5000) +#define CFG_ROAM_SCAN_HI_RSSI_DELAY_MAX (0x7fffffff) +#define CFG_ROAM_SCAN_HI_RSSI_DELAY_DEFAULT (15000) + +/* + * + * gRoamScanHiRssiUpperBound - Sets upper bound after which 5GHz scan + * @Min: -66 + * @Max: 0 + * @Default: -30 + * + * This INI is used to set the RSSI upper bound above which the 5GHz scan + * will not be performed. + * + * Related: None + * + * Supported Feature: Roaming + * + * Usage: External + * + * + */ +#define CFG_ROAM_SCAN_HI_RSSI_UB_NAME "gRoamScanHiRssiUpperBound" +#define CFG_ROAM_SCAN_HI_RSSI_UB_MIN (-66) +#define CFG_ROAM_SCAN_HI_RSSI_UB_MAX (0) +#define CFG_ROAM_SCAN_HI_RSSI_UB_DEFAULT (-30) + +#ifdef FEATURE_LFR_SUBNET_DETECTION +/* + * + * gLFRSubnetDetectionEnable - Enable LFR3 subnet detection + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * Enable IP subnet detection during legacy fast roming version 3. Legacy fast + * roaming could roam across IP subnets without host processors' knowledge. + * This feature enables firmware to wake up the host processor if it + * successfully determines change in the IP subnet. Change in IP subnet could + * potentially cause disruption in IP connnectivity if IP address is not + * refreshed. + * + * Related: None + * + * Supported Feature: Roaming + * + * Usage: External + * + * + */ +#define CFG_ENABLE_LFR_SUBNET_DETECTION "gLFRSubnetDetectionEnable" +#define CFG_ENABLE_LFR_SUBNET_MIN (0) +#define CFG_ENABLE_LFR_SUBNET_MAX (1) +#define CFG_ENABLE_LFR_SUBNET_DEFAULT (1) +#endif /* FEATURE_LFR_SUBNET_DETECTION */ + +/* + * + * groam_dense_rssi_thresh_offset - Sets dense roam RSSI threshold diff + * @Min: 0 + * @Max: 20 + * @Default: 10 + * + * This INI is used to set offset value from normal RSSI threshold to dense + * RSSI threshold Fw will optimize roaming based on new RSSI threshold once + * it detects dense enviournment. + * + * Related: None + * + * Supported Feature: Roaming + * + * Usage: External + * + * + */ +#define CFG_ROAM_DENSE_RSSI_THRE_OFFSET "groam_dense_rssi_thresh_offset" +#define CFG_ROAM_DENSE_RSSI_THRE_OFFSET_MIN (0) +#define CFG_ROAM_DENSE_RSSI_THRE_OFFSET_MAX (20) +#define CFG_ROAM_DENSE_RSSI_THRE_OFFSET_DEFAULT (10) + +/* + * + * groam_dense_min_aps - Sets minimum number of AP for dense roam + * @Min: 1 + * @Max: 5 + * @Default: 3 + * + * Minimum number of APs required for dense roam. FW will consider + * environment as dense once it detects #APs operating is more than + * groam_dense_min_aps. + * + * Related: None + * + * Supported Feature: Roaming + * + * Usage: External + * + * + */ +#define CFG_ROAM_DENSE_MIN_APS "groam_dense_min_aps" +#define CFG_ROAM_DENSE_MIN_APS_MIN (1) +#define CFG_ROAM_DENSE_MIN_APS_MAX (5) +#define CFG_ROAM_DENSE_MIN_APS_DEFAULT (3) + +/* + * + * roamscan_adaptive_dwell_mode - Sets dwell time adaptive mode + * @Min: 0 + * @Max: 4 + * @Default: 0 + * + * This parameter will set the algo used in dwell time optimization during + * roam scan. see enum wmi_dwelltime_adaptive_mode. + * Acceptable values for this: + * 0: Default (Use firmware default mode) + * 1: Conservative optimization + * 2: Moderate optimization + * 3: Aggressive optimization + * 4: Static + * + * Related: None + * + * Supported Feature: Roaming + * + * Usage: External + * + * + */ +#define CFG_ADAPTIVE_ROAMSCAN_DWELL_MODE_NAME "roamscan_adaptive_dwell_mode" +#define CFG_ADAPTIVE_ROAMSCAN_DWELL_MODE_MIN (0) +#define CFG_ADAPTIVE_ROAMSCAN_DWELL_MODE_MAX (4) +#define CFG_ADAPTIVE_ROAMSCAN_DWELL_MODE_DEFAULT (0) + +/* + * Timer waiting for interface up from the upper layer. If + * this timer expires all the cds modules shall be closed. + * Time Units: ms + */ +#define CFG_INTERFACE_CHANGE_WAIT_NAME "gInterfaceChangeWait" +#define CFG_INTERFACE_CHANGE_WAIT_MIN (10) +#define CFG_INTERFACE_CHANGE_WAIT_MAX (500000) +#define CFG_INTERFACE_CHANGE_WAIT_DEFAULT (15000) + +/* + * + * gShortPreamble - Set Short Preamble + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to set default short Preamble + * + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ + +#define CFG_SHORT_PREAMBLE_NAME "gShortPreamble" +#define CFG_SHORT_PREAMBLE_MIN WNI_CFG_SHORT_PREAMBLE_STAMIN +#define CFG_SHORT_PREAMBLE_MAX WNI_CFG_SHORT_PREAMBLE_STAMAX +#define CFG_SHORT_PREAMBLE_DEFAULT WNI_CFG_SHORT_PREAMBLE_STADEF + +/* + * + * gIbssBssid - Default IBSS BSSID if BSSID is not provided by supplicant + * @Min: "000000000000" + * @Max: "ffffffffffff" + * @Default: "000AF5040506" + * + * This ini is used to set Default IBSS BSSID if BSSID + * is not provided by supplicant and Coalesing is disabled + * + * Related: Only applicable if gCoalesingInIBSS is 0 + * + * Supported Feature: IBSS + * + * Usage: Internal/External + * + * + */ +#define CFG_IBSS_BSSID_NAME "gIbssBssid" +#define CFG_IBSS_BSSID_MIN "000000000000" +#define CFG_IBSS_BSSID_MAX "ffffffffffff" +#define CFG_IBSS_BSSID_DEFAULT "000AF5040506" + +/* + * + * gAdHocChannel5G - Default 5Ghz IBSS channel if channel is not + * provided by supplicant. + * @Min: 36 + * @Max: 165 + * @Default: 44 + * + * This ini is used to set default 5Ghz IBSS channel + * if channel is not provided by supplicant and band is 5Ghz + * + * Related: None + * + * Supported Feature: IBSS + * + * Usage: Internal/External + * + * + */ +#define CFG_IBSS_ADHOC_CHANNEL_5GHZ_NAME "gAdHocChannel5G" +#define CFG_IBSS_ADHOC_CHANNEL_5GHZ_MIN (36) +#define CFG_IBSS_ADHOC_CHANNEL_5GHZ_MAX (165) +#define CFG_IBSS_ADHOC_CHANNEL_5GHZ_DEFAULT (44) + +/* + * + * gAdHocChannel24G - Default 2.4Ghz IBSS channel if channel is not + * provided by supplicant. + * @Min: 1 + * @Max: 14 + * @Default: 6 + * + * This ini is used to set default 2.4Ghz IBSS channel + * if channel is not provided by supplicant and band is 2.4Ghz + * + * Related: None + * + * Supported Feature: IBSS + * + * Usage: Internal/External + * + * + */ +#define CFG_IBSS_ADHOC_CHANNEL_24GHZ_NAME "gAdHocChannel24G" +#define CFG_IBSS_ADHOC_CHANNEL_24GHZ_MIN (1) +#define CFG_IBSS_ADHOC_CHANNEL_24GHZ_MAX (14) +#define CFG_IBSS_ADHOC_CHANNEL_24GHZ_DEFAULT (6) + +/* + * + * gCoalesingInIBSS - If IBSS coalesing is enabled. + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to set IBSS coalesing + * + * Related: None + * + * Supported Feature: IBSS + * + * Usage: Internal/External + * + * + */ +#define CFG_COALESING_IN_IBSS_NAME "gCoalesingInIBSS" +#define CFG_COALESING_IN_IBSS_MIN (0) +#define CFG_COALESING_IN_IBSS_MAX (1) +#define CFG_COALESING_IN_IBSS_DEFAULT (0) /* disabled */ + +/* + * + * gIbssATIMWinSize - Set IBSS ATIM window size + * @Min: 0 + * @Max: 50 + * @Default: 0 + * + * This ini is used to set IBSS ATIM window size + * + * Related: None + * + * Supported Feature: IBSS + * + * Usage: Internal/External + * + * + */ +#define CFG_IBSS_ATIM_WIN_SIZE_NAME "gIbssATIMWinSize" +#define CFG_IBSS_ATIM_WIN_SIZE_MIN (0) +#define CFG_IBSS_ATIM_WIN_SIZE_MAX (50) +#define CFG_IBSS_ATIM_WIN_SIZE_DEFAULT (0) + + +/* + * + * gIbssIsPowerSaveAllowed - Indicates if IBSS Power Save is + * supported or not + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to Indicates if IBSS Power Save is + * supported or not. When not allowed,IBSS station has + * to stay awake all the time and should never set PM=1 + * in its transmitted frames. + * + * Related: valid only when gIbssATIMWinSize is non-zero + * + * Supported Feature: IBSS + * + * Usage: Internal/External + * + * + */ +#define CFG_IBSS_IS_POWER_SAVE_ALLOWED_NAME "gIbssIsPowerSaveAllowed" +#define CFG_IBSS_IS_POWER_SAVE_ALLOWED_MIN (0) +#define CFG_IBSS_IS_POWER_SAVE_ALLOWED_MAX (1) +#define CFG_IBSS_IS_POWER_SAVE_ALLOWED_DEFAULT (1) + +/* + * + * gIbssIsPowerCollapseAllowed - Indicates if IBSS Power Collapse + * is allowed + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to indicates if IBSS Power Collapse + * is allowed + * + * Related: None + * + * Supported Feature: IBSS + * + * Usage: Internal/External + * + * + */ +#define CFG_IBSS_IS_POWER_COLLAPSE_ALLOWED_NAME "gIbssIsPowerCollapseAllowed" +#define CFG_IBSS_IS_POWER_COLLAPSE_ALLOWED_MIN (0) +#define CFG_IBSS_IS_POWER_COLLAPSE_ALLOWED_MAX (1) +#define CFG_IBSS_IS_POWER_COLLAPSE_ALLOWED_DEFAULT (1) + +/* + * + * gIbssAwakeOnTxRx - Indicates whether IBSS station + * can exit power save mode and enter power active + * state whenever there is a TX/RX activity. + * + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to ndicates whether IBSS station + * can exit power save mode and enter power active + * state whenever there is a TX/RX activity. + * + * Related: None + * + * Supported Feature: IBSS + * + * Usage: Internal/External + * + * + */ +#define CFG_IBSS_AWAKE_ON_TX_RX_NAME "gIbssAwakeOnTxRx" +#define CFG_IBSS_AWAKE_ON_TX_RX_MIN (0) +#define CFG_IBSS_AWAKE_ON_TX_RX_MAX (1) +#define CFG_IBSS_AWAKE_ON_TX_RX_DEFAULT (0) + +/* + * + * gIbssInactivityTime - Indicates the data + * inactivity time in number of beacon intervals + * after which IBSS station re-inters power save + * + * @Min: 1 + * @Max: 10 + * @Default: 1 + * + * In IBSS mode if Awake on TX/RX activity is enabled + * Ibss Inactivity parameter indicates the data + * inactivity time in number of beacon intervals + * after which IBSS station re-inters power save + * by sending Null frame with PM=1 + * + * Related: Aplicable if gIbssAwakeOnTxRx is enabled + * + * Supported Feature: IBSS + * + * Usage: Internal/External + * + * + */ +#define CFG_IBSS_INACTIVITY_TIME_NAME "gIbssInactivityTime" +#define CFG_IBSS_INACTIVITY_TIME_MIN (1) +#define CFG_IBSS_INACTIVITY_TIME_MAX (10) +#define CFG_IBSS_INACTIVITY_TIME_DEFAULT (1) + +/* + * + * gIbssTxSpEndInactivityTime - Indicates the time after + * which TX Service Period is terminated by + * sending a Qos Null frame with EOSP. + * + * @Min: 0 + * @Max: 100 + * @Default: 0 + * + * In IBSS mode Tx Service Period Inactivity + * time in msecs indicates the time after + * which TX Service Period is terminated by + * sending a Qos Null frame with EOSP. + * If value is 0, TX SP is terminated with the + * last buffered packet itself instead of waiting + * for the inactivity. + * + * Related: None + * + * Supported Feature: IBSS + * + * Usage: Internal/External + * + * + */ +#define CFG_IBSS_TXSP_END_INACTIVITY_NAME "gIbssTxSpEndInactivityTime" +#define CFG_IBSS_TXSP_END_INACTIVITY_MIN (0) +#define CFG_IBSS_TXSP_END_INACTIVITY_MAX (100) +#define CFG_IBSS_TXSP_END_INACTIVITY_DEFAULT (0) + +/* + * + * gIbssPsWarmupTime - PS-supporting device + * does not enter protocol sleep state during first + * gIbssPsWarmupTime seconds. + * + * @Min: 0 + * @Max: 65535 + * @Default: 0 + * + * When IBSS network is initialized, PS-supporting device + * does not enter protocol sleep state during first + * gIbssPsWarmupTime seconds. + * + * Related: valid if gIbssIsPowerSaveAllowed is set + * + * Supported Feature: IBSS + * + * Usage: Internal/External + * + * + */ +#define CFG_IBSS_PS_WARMUP_TIME_NAME "gIbssPsWarmupTime" +#define CFG_IBSS_PS_WARMUP_TIME_MIN (0) +/* Allow unsigned Int Max for now */ +#define CFG_IBSS_PS_WARMUP_TIME_MAX (65535) +#define CFG_IBSS_PS_WARMUP_TIME_DEFAULT (0) + +/* + * + * gIbssPs1RxChainInAtim - IBSS Power Save Enable/Disable 1 RX + * chain usage during the ATIM window + * + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * IBSS Power Save Enable/Disable 1 RX + * chain usage during the ATIM window + * + * Related: Depend on gIbssIsPowerSaveAllowed + * + * Supported Feature: IBSS + * + * Usage: Internal/External + * + * + */ +#define CFG_IBSS_PS_1RX_CHAIN_IN_ATIM_WINDOW_NAME "gIbssPs1RxChainInAtim" +#define CFG_IBSS_PS_1RX_CHAIN_IN_ATIM_WINDOW_MIN (0) +#define CFG_IBSS_PS_1RX_CHAIN_IN_ATIM_WINDOW_MAX (1) +#define CFG_IBSS_PS_1RX_CHAIN_IN_ATIM_WINDOW_DEFAULT (0) + + + + +#define CFG_INTF0_MAC_ADDR_NAME "Intf0MacAddress" +#define CFG_INTF0_MAC_ADDR_MIN "000000000000" +#define CFG_INTF0_MAC_ADDR_MAX "ffffffffffff" +#define CFG_INTF0_MAC_ADDR_DEFAULT "000AF58989FF" + +#define CFG_INTF1_MAC_ADDR_NAME "Intf1MacAddress" +#define CFG_INTF1_MAC_ADDR_MIN "000000000000" +#define CFG_INTF1_MAC_ADDR_MAX "ffffffffffff" +#define CFG_INTF1_MAC_ADDR_DEFAULT "000AF58989FE" + +#define CFG_INTF2_MAC_ADDR_NAME "Intf2MacAddress" +#define CFG_INTF2_MAC_ADDR_MIN "000000000000" +#define CFG_INTF2_MAC_ADDR_MAX "ffffffffffff" +#define CFG_INTF2_MAC_ADDR_DEFAULT "000AF58989FD" + +#define CFG_INTF3_MAC_ADDR_NAME "Intf3MacAddress" +#define CFG_INTF3_MAC_ADDR_MIN "000000000000" +#define CFG_INTF3_MAC_ADDR_MAX "ffffffffffff" +#define CFG_INTF3_MAC_ADDR_DEFAULT "000AF58989FC" + +/* + * + * gDot11Mode - SAP phy mode + * @Min: 0 + * @Max: 10 (11a) + * @Default: 9 (11ac) + * + * This ini is used to set Phy Mode (auto, b, g, n, etc/) Valid values are + * 0-10, with 0 = Auto, 10 = 11a. + * + * Related: None. + * + * Supported Feature: SAP + * + * Usage: Internal/External + * + * + */ +#define CFG_DOT11_MODE_NAME "gDot11Mode" +#define CFG_DOT11_MODE_MIN eHDD_DOT11_MODE_AUTO +#define CFG_DOT11_MODE_DEFAULT eHDD_DOT11_MODE_11ac +#define CFG_DOT11_MODE_MAX eHDD_DOT11_MODE_11a + +/* + * + * gEnableApUapsd - Enable/disable UAPSD for SoftAP + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to setup setup U-APSD for Acs at association + * + * Related: None. + * + * Supported Feature: SAP + * + * Usage: Internal/External + * + * + */ +#define CFG_AP_QOS_UAPSD_MODE_NAME "gEnableApUapsd" +#define CFG_AP_QOS_UAPSD_MODE_MIN (0) +#define CFG_AP_QOS_UAPSD_MODE_MAX (1) +#define CFG_AP_QOS_UAPSD_MODE_DEFAULT (1) + +/* + * + * gEnableApRandomBssid - Create ramdom BSSID + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to create a random BSSID in SoftAP mode to meet + * the Android requirement. + * + * Related: None. + * + * Supported Feature: SAP + * + * Usage: Internal/External + * + * + */ +#define CFG_AP_ENABLE_RANDOM_BSSID_NAME "gEnableApRandomBssid" +#define CFG_AP_ENABLE_RANDOM_BSSID_MIN (0) +#define CFG_AP_ENABLE_RANDOM_BSSID_MAX (1) +#define CFG_AP_ENABLE_RANDOM_BSSID_DEFAULT (0) + +/* + * + * gEnableApProt - Enable/Disable AP protection + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to enable/disable AP protection + * + * Related: None. + * + * Supported Feature: SAP + * + * Usage: Internal/External + * + * + */ +#define CFG_AP_ENABLE_PROTECTION_MODE_NAME "gEnableApProt" +#define CFG_AP_ENABLE_PROTECTION_MODE_MIN (0) +#define CFG_AP_ENABLE_PROTECTION_MODE_MAX (1) +#define CFG_AP_ENABLE_PROTECTION_MODE_DEFAULT (1) + +/* + * + * gApProtection - Set AP protection parameter + * @Min: 0x0 + * @Max: 0xFFFF + * @Default: 0xBFFF + * + * This ini is used to set AP protection parameter + * Bit map for CFG_AP_PROTECTION_MODE_DEFAULT + * LOWER byte for associated stations + * UPPER byte for overlapping stations + * each byte will have the following info + * bit15 bit14 bit13 bit12 bit11 bit10 bit9 bit8 + * OBSS RIFS LSIG_TXOP NON_GF HT20 FROM_11G FROM_11B FROM_11A + * bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0 + * OBSS RIFS LSIG_TXOP NON_GF HT_20 FROM_11G FROM_11B FROM_11A + * + * Related: None. + * + * Supported Feature: SAP + * + * Usage: Internal/External + * + * + */ +#define CFG_AP_PROTECTION_MODE_NAME "gApProtection" +#define CFG_AP_PROTECTION_MODE_MIN (0x0) +#define CFG_AP_PROTECTION_MODE_MAX (0xFFFF) +#define CFG_AP_PROTECTION_MODE_DEFAULT (0xBFFF) + +/* + * + * gEnableApOBSSProt - Enable/Disable AP OBSS protection + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to enable/disable AP OBSS protection + * + * Related: None. + * + * Supported Feature: SAP + * + * Usage: Internal/External + * + * + */ +#define CFG_AP_OBSS_PROTECTION_MODE_NAME "gEnableApOBSSProt" +#define CFG_AP_OBSS_PROTECTION_MODE_MIN (0) +#define CFG_AP_OBSS_PROTECTION_MODE_MAX (1) +#define CFG_AP_OBSS_PROTECTION_MODE_DEFAULT (0) + +/* + * + * gDisableIntraBssFwd - Disable intrs BSS Rx packets + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to disbale to forward Intra-BSS Rx packets when + * ap_isolate=1 in hostapd.conf + * + * Related: None. + * + * Supported Feature: SAP + * + * Usage: Internal/External + * + * + */ +#define CFG_AP_STA_SECURITY_SEPERATION_NAME "gDisableIntraBssFwd" +#define CFG_AP_STA_SECURITY_SEPERATION_MIN (0) +#define CFG_AP_STA_SECURITY_SEPERATION_MAX (1) +#define CFG_AP_STA_SECURITY_SEPERATION_DEFAULT (0) + +/* + * + * gAPAutoShutOff - Auto shutdown when timer expires + * @Min: 0 + * @Max: 4294967295UL + * @Default: 0 + * + * This ini is used to configure timer value to shutdown AP once timer expired + * + * Related: None. + * + * Supported Feature: SAP + * + * Usage: Internal/External + * + * + */ +#define CFG_AP_AUTO_SHUT_OFF "gAPAutoShutOff" +#define CFG_AP_AUTO_SHUT_OFF_MIN (0) +#define CFG_AP_AUTO_SHUT_OFF_MAX (4294967295UL) +#define CFG_AP_AUTO_SHUT_OFF_DEFAULT (0) + +/* + * + * gApKeepAlivePeriod - AP keep alive period + * @Min: 1 + * @Max: 65535 + * @Default: 20 + * + * This ini is used to set keep alive period of AP + * + * Related: None. + * + * Supported Feature: SAP + * + * Usage: Internal/External + * + * + */ +#define CFG_AP_KEEP_ALIVE_PERIOD_NAME "gApKeepAlivePeriod" +#define CFG_AP_KEEP_ALIVE_PERIOD_MIN WNI_CFG_AP_KEEP_ALIVE_TIMEOUT_STAMIN +#define CFG_AP_KEEP_ALIVE_PERIOD_MAX WNI_CFG_AP_KEEP_ALIVE_TIMEOUT_STAMAX +#define CFG_AP_KEEP_ALIVE_PERIOD_DEFAULT WNI_CFG_AP_KEEP_ALIVE_TIMEOUT_STADEF + +/* + * + * gApLinkMonitorPeriod - AP keep alive period + * @Min: 3 + * @Max: 50 + * @Default: 10 + * + * This ini is used to configure AP link monitor timeout value + * + * Related: None. + * + * Supported Feature: SAP + * + * Usage: Internal/External + * + * + */ +#define CFG_AP_LINK_MONITOR_PERIOD_NAME "gApLinkMonitorPeriod" +#define CFG_AP_LINK_MONITOR_PERIOD_MIN (3) +#define CFG_AP_LINK_MONITOR_PERIOD_MAX (50) +#define CFG_AP_LINK_MONITOR_PERIOD_DEFAULT (10) + +/* + * + * gBeaconInterval - Beacon interval for SoftAP + * @Min: 0 + * @Max: 65535 + * @Default: 100 + * + * This ini is used to set beacon interval for SoftAP + * + * Related: None. + * + * Supported Feature: SAP + * + * Usage: Internal/External + * + * + */ +#define CFG_BEACON_INTERVAL_NAME "gBeaconInterval" +#define CFG_BEACON_INTERVAL_MIN WNI_CFG_BEACON_INTERVAL_STAMIN +#define CFG_BEACON_INTERVAL_MAX WNI_CFG_BEACON_INTERVAL_STAMAX +#define CFG_BEACON_INTERVAL_DEFAULT WNI_CFG_BEACON_INTERVAL_STADEF + +/* + * + * gEnableVSTASupport - Enable/disable VSTA support + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to enable/disable VSTA based on max assoc limit. + * Enable to have maximum 32 STA (P2P GC) on DUT as P2P GO or SAP + * + * Related: None. + * + * Supported Feature: SAP + * + * Usage: Internal/External + * + * + */ +#ifdef WLAN_SOFTAP_VSTA_FEATURE +#define CFG_VSTA_SUPPORT_ENABLE "gEnableVSTASupport" +#define CFG_VSTA_SUPPORT_ENABLE_MIN (0) +#define CFG_VSTA_SUPPORT_ENABLE_MAX (1) +#define CFG_VSTA_SUPPORT_ENABLE_DEFAULT (0) +#endif + +#ifdef FEATURE_WLAN_AUTO_SHUTDOWN +#define CFG_WLAN_AUTO_SHUTDOWN "gWlanAutoShutdown" +#define CFG_WLAN_AUTO_SHUTDOWN_MIN (0) +#define CFG_WLAN_AUTO_SHUTDOWN_MAX (86400) /* Max 1 day timeout */ +#define CFG_WLAN_AUTO_SHUTDOWN_DEFAULT (0) +#endif + +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH +/* + * + * gWlanMccToSccSwitchMode - Control SAP channel. + * @Min: 0 + * @Max: 2 + * @Default: 0 + * + * This ini is used to override SAP channel. + * If gWlanMccToSccSwitchMode = 0: disabled. + * If gWlanMccToSccSwitchMode = 1: override to SCC if channel overlap in + * same band. + * If gWlanMccToSccSwitchMode = 2: force to SCC in same band. + * + * Related: None. + * + * Supported Feature: Concurrency + * + * Usage: Internal/External + * + * + */ +#define CFG_WLAN_MCC_TO_SCC_SWITCH_MODE "gWlanMccToSccSwitchMode" +#define CFG_WLAN_MCC_TO_SCC_SWITCH_MODE_MIN (QDF_MCC_TO_SCC_SWITCH_DISABLE) +#define CFG_WLAN_MCC_TO_SCC_SWITCH_MODE_MAX \ + (QDF_MCC_TO_SCC_SWITCH_WITH_FAVORITE_CHANNEL) +#define CFG_WLAN_MCC_TO_SCC_SWITCH_MODE_DEFAULT (QDF_MCC_TO_SCC_SWITCH_DISABLE) +#endif + +#define CFG_DISABLE_PACKET_FILTER "gDisablePacketFilter" +#define CFG_DISABLE_PACKET_FILTER_MIN (0) +#define CFG_DISABLE_PACKET_FILTER_MAX (0x1) +#define CFG_DISABLE_PACKET_FILTER_DEFAULT (0) + +#define CFG_ENABLE_LTE_COEX "gEnableLTECoex" +#define CFG_ENABLE_LTE_COEX_MIN (0) +#define CFG_ENABLE_LTE_COEX_MAX (1) +#define CFG_ENABLE_LTE_COEX_DEFAULT (0) + +#define CFG_GO_KEEP_ALIVE_PERIOD_NAME "gGoKeepAlivePeriod" +#define CFG_GO_KEEP_ALIVE_PERIOD_MIN WNI_CFG_GO_KEEP_ALIVE_TIMEOUT_STAMIN +#define CFG_GO_KEEP_ALIVE_PERIOD_MAX WNI_CFG_GO_KEEP_ALIVE_TIMEOUT_STAMAX +#define CFG_GO_KEEP_ALIVE_PERIOD_DEFAULT WNI_CFG_GO_KEEP_ALIVE_TIMEOUT_STADEF + +/* gGoLinkMonitorPeriod is period where link is idle and where + * we send NULL frame + */ +#define CFG_GO_LINK_MONITOR_PERIOD_NAME "gGoLinkMonitorPeriod" +#define CFG_GO_LINK_MONITOR_PERIOD_MIN (3) +#define CFG_GO_LINK_MONITOR_PERIOD_MAX (50) +#define CFG_GO_LINK_MONITOR_PERIOD_DEFAULT (10) + +#define CFG_VCC_RSSI_TRIGGER_NAME "gVccRssiTrigger" +#define CFG_VCC_RSSI_TRIGGER_MIN (0) +#define CFG_VCC_RSSI_TRIGGER_MAX (80) +#define CFG_VCC_RSSI_TRIGGER_DEFAULT (80) + +#define CFG_VCC_UL_MAC_LOSS_THRESH_NAME "gVccUlMacLossThresh" +#define CFG_VCC_UL_MAC_LOSS_THRESH_MIN (0) +#define CFG_VCC_UL_MAC_LOSS_THRESH_MAX (9) +#define CFG_VCC_UL_MAC_LOSS_THRESH_DEFAULT (9) + +#define CFG_RETRY_LIMIT_ZERO_NAME "gRetryLimitZero" +#define CFG_RETRY_LIMIT_ZERO_MIN (0) +#define CFG_RETRY_LIMIT_ZERO_MAX (15) +#define CFG_RETRY_LIMIT_ZERO_DEFAULT (5) + +#define CFG_RETRY_LIMIT_ONE_NAME "gRetryLimitOne" +#define CFG_RETRY_LIMIT_ONE_MIN (0) +#define CFG_RETRY_LIMIT_ONE_MAX (15) +#define CFG_RETRY_LIMIT_ONE_DEFAULT (10) + +#define CFG_RETRY_LIMIT_TWO_NAME "gRetryLimitTwo" +#define CFG_RETRY_LIMIT_TWO_MIN (0) +#define CFG_RETRY_LIMIT_TWO_MAX (15) +#define CFG_RETRY_LIMIT_TWO_DEFAULT (15) + +#ifdef WLAN_AP_STA_CONCURRENCY +/* + * + * gPassiveMaxChannelTimeConc - Maximum passive scan time in milliseconds. + * @Min: 0 + * @Max: 10000 + * @Default: 110 + * + * This ini is used to set maximum passive scan time in STA+SAP concurrent + * mode. + * + * Related: None. + * + * Supported Feature: Concurrency + * + * Usage: Internal/External + * + * + */ +#define CFG_PASSIVE_MAX_CHANNEL_TIME_CONC_NAME "gPassiveMaxChannelTimeConc" +#define CFG_PASSIVE_MAX_CHANNEL_TIME_CONC_MIN (0) +#define CFG_PASSIVE_MAX_CHANNEL_TIME_CONC_MAX (10000) +#define CFG_PASSIVE_MAX_CHANNEL_TIME_CONC_DEFAULT (110) + +/* + * + * gPassiveMinChannelTimeConc - Minimum passive scan time in milliseconds. + * @Min: 0 + * @Max: 10000 + * @Default: 60 + * + * This ini is used to set minimum passive scan time in STA+SAP concurrent + * mode. + * + * Related: None. + * + * Supported Feature: Concurrency + * + * Usage: Internal/External + * + * + */ +#define CFG_PASSIVE_MIN_CHANNEL_TIME_CONC_NAME "gPassiveMinChannelTimeConc" +#define CFG_PASSIVE_MIN_CHANNEL_TIME_CONC_MIN (0) +#define CFG_PASSIVE_MIN_CHANNEL_TIME_CONC_MAX (10000) +#define CFG_PASSIVE_MIN_CHANNEL_TIME_CONC_DEFAULT (60) + +/* + * + * gActiveMaxChannelTimeConc - Maximum active scan time in milliseconds. + * @Min: 0 + * @Max: 10000 + * @Default: 40 + * + * This ini is used to set maximum active scan time in STA+SAP concurrent + * mode. + * + * Related: None. + * + * Supported Feature: Concurrency + * + * Usage: Internal/External + * + * + */ +#define CFG_ACTIVE_MAX_CHANNEL_TIME_CONC_NAME "gActiveMaxChannelTimeConc" +#define CFG_ACTIVE_MAX_CHANNEL_TIME_CONC_MIN (0) +#define CFG_ACTIVE_MAX_CHANNEL_TIME_CONC_MAX (10000) +#define CFG_ACTIVE_MAX_CHANNEL_TIME_CONC_DEFAULT (40) + +/* + * + * gActiveMinChannelTimeConc - Minimum active scan time in milliseconds.. + * @Min: 0 + * @Max: 10000 + * @Default: 20 + * + * This ini is used to set minimum active scan time in STA+SAP concurrent + * mode. + * + * Related: None. + * + * Supported Feature: Concurrency + * + * Usage: Internal/External + * + * + */ +#define CFG_ACTIVE_MIN_CHANNEL_TIME_CONC_NAME "gActiveMinChannelTimeConc" +#define CFG_ACTIVE_MIN_CHANNEL_TIME_CONC_MIN (0) +#define CFG_ACTIVE_MIN_CHANNEL_TIME_CONC_MAX (10000) +#define CFG_ACTIVE_MIN_CHANNEL_TIME_CONC_DEFAULT (20) + +/* + * + * gRestTimeConc - Rest time before moving to a new channel to scan. + * @Min: 0 + * @Max: 10000 + * @Default: 100 + * + * This ini is used to configure rest time. + * + * Related: None. + * + * Supported Feature: Concurrency + * + * Usage: Internal/External + * + * + */ +#define CFG_REST_TIME_CONC_NAME "gRestTimeConc" +#define CFG_REST_TIME_CONC_MIN (0) +#define CFG_REST_TIME_CONC_MAX (10000) +#define CFG_REST_TIME_CONC_DEFAULT (100) + +/* + * + * gMinRestTimeConc - Mininum time spent on home channel before moving to a + * new channel to scan. + * @Min: 0 + * @Max: 50 + * @Default: 50 + * + * This ini is used to configure minimum time spent on home channel before + * moving to a new channel to scan. + * + * Related: None. + * + * Supported Feature: Concurrency + * + * Usage: Internal/External + * + * + */ +#define CFG_MIN_REST_TIME_NAME "gMinRestTimeConc" +#define CFG_MIN_REST_TIME_MIN (0) +#define CFG_MIN_REST_TIME_MAX (50) +#define CFG_MIN_REST_TIME_DEFAULT (50) + +/* + * + * gIdleTimeConc - Data inactivity time in msec. + * @Min: 0 + * @Max: 25 + * @Default: 25 + * + * This ini is used to configure data inactivity time in msec on bss channel + * that will be used by scan engine in firmware. + * For example if this value is 25ms then firmware will check for data + * inactivity every 25ms till gRestTimeConc is reached. + * If inactive then scan engine will move from home channel to scan the next + * frequency. + * + * Related: None. + * + * Supported Feature: Concurrency + * + * Usage: Internal/External + * + * + */ +#define CFG_IDLE_TIME_NAME "gIdleTimeConc" +#define CFG_IDLE_TIME_MIN (0) +#define CFG_IDLE_TIME_MAX (25) +#define CFG_IDLE_TIME_DEFAULT (25) + + +/* + * + * gNumStaChanCombinedConc - Number of channels combined for STA in each + * split scan operation. + * @Min: 1 + * @Max: 255 + * @Default: 3 + * + * This ini is used to configure the number of channels combined for STA in + * each split scan operation. + * + * Related: None. + * + * Supported Feature: Concurrency + * + * Usage: Internal/External + * + * + */ +#define CFG_NUM_STA_CHAN_COMBINED_CONC_NAME "gNumStaChanCombinedConc" +#define CFG_NUM_STA_CHAN_COMBINED_CONC_MIN (1) +#define CFG_NUM_STA_CHAN_COMBINED_CONC_MAX (255) +#define CFG_NUM_STA_CHAN_COMBINED_CONC_DEFAULT (3) + +/* + * + * gNumP2PChanCombinedConc - Number of channels combined for P2P in each + * split scan operation. + * @Min: 1 + * @Max: 255 + * @Default: 1 + * + * This ini is used to configure the number of channels combined for P2P in + * each split scan operation. + * + * Related: None. + * + * Supported Feature: Concurrency + * + * Usage: Internal/External + * + * + */ +#define CFG_NUM_P2P_CHAN_COMBINED_CONC_NAME "gNumP2PChanCombinedConc" +#define CFG_NUM_P2P_CHAN_COMBINED_CONC_MIN (1) +#define CFG_NUM_P2P_CHAN_COMBINED_CONC_MAX (255) +#define CFG_NUM_P2P_CHAN_COMBINED_CONC_DEFAULT (1) +#endif + +#define CFG_MAX_PS_POLL_NAME "gMaxPsPoll" +#define CFG_MAX_PS_POLL_MIN WNI_CFG_MAX_PS_POLL_STAMIN +#define CFG_MAX_PS_POLL_MAX WNI_CFG_MAX_PS_POLL_STAMAX +#define CFG_MAX_PS_POLL_DEFAULT WNI_CFG_MAX_PS_POLL_STADEF + +#define CFG_MAX_TX_POWER_NAME "gTxPowerCap" +#define CFG_MAX_TX_POWER_MIN WNI_CFG_CURRENT_TX_POWER_LEVEL_STAMIN +#define CFG_MAX_TX_POWER_MAX WNI_CFG_CURRENT_TX_POWER_LEVEL_STAMAX +/* Not to use CFG default because if no registry setting, this is ignored by SME. */ +#define CFG_MAX_TX_POWER_DEFAULT WNI_CFG_CURRENT_TX_POWER_LEVEL_STAMAX + +/* This ini controls driver to honor/dishonor power constraint from AP */ +#define CFG_TX_POWER_CTRL_NAME "gAllowTPCfromAP" +#define CFG_TX_POWER_CTRL_DEFAULT (1) +#define CFG_TX_POWER_CTRL_MIN (0) +#define CFG_TX_POWER_CTRL_MAX (1) + +/* + * + * gLowGainOverride - Indicates Low Gain Override + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to set default Low Gain Override + * + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ + +#define CFG_LOW_GAIN_OVERRIDE_NAME "gLowGainOverride" +#define CFG_LOW_GAIN_OVERRIDE_MIN WNI_CFG_LOW_GAIN_OVERRIDE_STAMIN +#define CFG_LOW_GAIN_OVERRIDE_MAX WNI_CFG_LOW_GAIN_OVERRIDE_STAMAX +#define CFG_LOW_GAIN_OVERRIDE_DEFAULT WNI_CFG_LOW_GAIN_OVERRIDE_STADEF + +/* + * + * gRssiFilterPeriod - Enable gRssi Filter for RSSI Monitoring + * @Min: STAMIN + * @Max: STAMAX + * @Default: STADEF + * + * This ini is used to Increased this value for Non-ESE AP this is cause FW + * RSSI Monitoring the consumer of this value is ON by default. So to impact + * power numbers we are setting this to a high value. + * + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ + +#define CFG_RSSI_FILTER_PERIOD_NAME "gRssiFilterPeriod" +#define CFG_RSSI_FILTER_PERIOD_MIN WNI_CFG_RSSI_FILTER_PERIOD_STAMIN +#define CFG_RSSI_FILTER_PERIOD_MAX WNI_CFG_RSSI_FILTER_PERIOD_STAMAX +#define CFG_RSSI_FILTER_PERIOD_DEFAULT WNI_CFG_RSSI_FILTER_PERIOD_STADEF + +#define CFG_IGNORE_DTIM_NAME "gIgnoreDtim" +#define CFG_IGNORE_DTIM_MIN WNI_CFG_IGNORE_DTIM_STAMIN +#define CFG_IGNORE_DTIM_MAX WNI_CFG_IGNORE_DTIM_STAMAX +#define CFG_IGNORE_DTIM_DEFAULT WNI_CFG_IGNORE_DTIM_STADEF + +/* + * + * gMaxLIModulatedDTIM - Set MaxLIModulate Dtim + * @Min: 1 + * @Max: 10 + * @Default: 10 + * + * This ini is used to set default MaxLIModulatedDTIM + * + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ + +#define CFG_MAX_LI_MODULATED_DTIM_NAME "gMaxLIModulatedDTIM" +#define CFG_MAX_LI_MODULATED_DTIM_MIN (1) +#define CFG_MAX_LI_MODULATED_DTIM_MAX (10) +#define CFG_MAX_LI_MODULATED_DTIM_DEFAULT (10) + +/* + * + * gEnableFWHeartBeatMonitoring - Enable FWHeartBeat Monitor + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to set default FWHeartBeat Monitor + * + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ + +#define CFG_FW_HEART_BEAT_MONITORING_NAME "gEnableFWHeartBeatMonitoring" +#define CFG_FW_HEART_BEAT_MONITORING_MIN (0) +#define CFG_FW_HEART_BEAT_MONITORING_MAX (1) +#define CFG_FW_HEART_BEAT_MONITORING_DEFAULT (1) + +/* + * + * gEnableFWBeaconFiltering - Enable FWBeacon Filter + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to set default FWBeacon Filter + * + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ + +#define CFG_FW_BEACON_FILTERING_NAME "gEnableFWBeaconFiltering" +#define CFG_FW_BEACON_FILTERING_MIN (0) +#define CFG_FW_BEACON_FILTERING_MAX (1) +#define CFG_FW_BEACON_FILTERING_DEFAULT (1) + +/* + * + * gEnableFWRssiMonitoring - Enable FWRssi Monitor + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to set default FWRssi Monitor + * + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ + +#define CFG_FW_RSSI_MONITORING_NAME "gEnableFWRssiMonitoring" +#define CFG_FW_RSSI_MONITORING_MIN (0) +#define CFG_FW_RSSI_MONITORING_MAX (1) +#define CFG_FW_RSSI_MONITORING_DEFAULT (1) + +/* + * + * gFWMccRtsCtsProtection - RTS-CTS protection in MCC. + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to enable/disable use of long duration RTS-CTS protection + * when SAP goes off channel in MCC mode. + * + * Related: None. + * + * Supported Feature: Concurrency + * + * Usage: Internal/External + * + * + */ + +#define CFG_FW_MCC_RTS_CTS_PROT_NAME "gFWMccRtsCtsProtection" +#define CFG_FW_MCC_RTS_CTS_PROT_MIN (0) +#define CFG_FW_MCC_RTS_CTS_PROT_MAX (1) +#define CFG_FW_MCC_RTS_CTS_PROT_DEFAULT (0) + +/* + * + * gFWMccBCastProbeResponse - Broadcast Probe Response in MCC. + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to enable/disable use of broadcast probe response to + * increase the detectability of SAP in MCC mode. + * + * Related: None. + * + * Supported Feature: Concurrency + * + * Usage: Internal/External + * + * + */ +#define CFG_FW_MCC_BCAST_PROB_RESP_NAME "gFWMccBCastProbeResponse" +#define CFG_FW_MCC_BCAST_PROB_RESP_MIN (0) +#define CFG_FW_MCC_BCAST_PROB_RESP_MAX (1) +#define CFG_FW_MCC_BCAST_PROB_RESP_DEFAULT (0) + +/* + * + * gDataInactivityTimeout - Data activity timeout for non wow mode. + * @Min: 1 + * @Max: 255 + * @Default: 200 + * + * This ini is used to set data inactivity timeout in non wow mode. + * + * Supported Feature: inactivity timeout in non wow mode + * + * Usage: Internal/External + * + * + */ + +#define CFG_DATA_INACTIVITY_TIMEOUT_NAME "gDataInactivityTimeout" +#define CFG_DATA_INACTIVITY_TIMEOUT_MIN (1) +#define CFG_DATA_INACTIVITY_TIMEOUT_MAX (255) +#define CFG_DATA_INACTIVITY_TIMEOUT_DEFAULT (200) + +/* + * + * g_wow_data_inactivity_timeout - Data activity timeout in wow mode. + * @Min: 1 + * @Max: 255 + * @Default: 50 + * + * This ini is used to set data inactivity timeout in wow mode. + * + * Supported Feature: inactivity timeout in wow mode + * + * Usage: Internal/External + * + * + */ +#define CFG_WOW_DATA_INACTIVITY_TIMEOUT_NAME "g_wow_data_inactivity_timeout" +#define CFG_WOW_DATA_INACTIVITY_TIMEOUT_MIN (1) +#define CFG_WOW_DATA_INACTIVITY_TIMEOUT_MAX (255) +#define CFG_WOW_DATA_INACTIVITY_TIMEOUT_DEFAULT (50) + +/* + * + * rfSettlingTimeUs - Settle the TimeUs + * @Min: 0 + * @Max: 60000 + * @Default: 1500 + * + * This ini is used to set default TimeUs + * + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ + +#define CFG_RF_SETTLING_TIME_CLK_NAME "rfSettlingTimeUs" +#define CFG_RF_SETTLING_TIME_CLK_MIN (0) +#define CFG_RF_SETTLING_TIME_CLK_MAX (60000) +#define CFG_RF_SETTLING_TIME_CLK_DEFAULT (1500) + +/* + * + * gStaKeepAlivePeriod - Sends NULL frame to AP periodically in + * seconds to notify STA's existence + * @Min: 0 + * @Max: 65535 + * @Default: 30 + * + * This ini is used to send default NULL frame to AP + * + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ + +#define CFG_INFRA_STA_KEEP_ALIVE_PERIOD_NAME "gStaKeepAlivePeriod" +#define CFG_INFRA_STA_KEEP_ALIVE_PERIOD_MIN (0) +#define CFG_INFRA_STA_KEEP_ALIVE_PERIOD_MAX (65535) +#define CFG_INFRA_STA_KEEP_ALIVE_PERIOD_DEFAULT (90) + +/* WMM configuration */ +/* + * + * WmmIsEnabled - Enable WMM feature + * @Min: 0 + * @Max: 2 + * @Default: 0 + * + * This ini is used to enable/disable WMM. + * + * Related: None. + * + * Supported Feature: WMM + * + * Usage: Internal/External + * + * + */ +#define CFG_QOS_WMM_MODE_NAME "WmmIsEnabled" +#define CFG_QOS_WMM_MODE_MIN (0) +#define CFG_QOS_WMM_MODE_MAX (2) /* HDD_WMM_NO_QOS */ +#define CFG_QOS_WMM_MODE_DEFAULT (0) /* HDD_WMM_AUTO */ + +/* + * + * 80211eIsEnabled - Enable 802.11e feature + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to enable/disable 802.11e. + * + * Related: None. + * + * Supported Feature: 802.11e + * + * Usage: Internal/External + * + * + */ +#define CFG_QOS_WMM_80211E_ENABLED_NAME "80211eIsEnabled" +#define CFG_QOS_WMM_80211E_ENABLED_MIN (0) +#define CFG_QOS_WMM_80211E_ENABLED_MAX (1) +#define CFG_QOS_WMM_80211E_ENABLED_DEFAULT (0) + +/* + * + * UapsdMask - To setup U-APSD mask for ACs + * @Min: 0x00 + * @Max: 0xFF + * @Default: 0x00 + * + * This ini is used to setup U-APSD mask for ACs. + * + * Related: None. + * + * Supported Feature: WMM + * + * Usage: Internal/External + * + * + */ +#define CFG_QOS_WMM_UAPSD_MASK_NAME "UapsdMask" +#define CFG_QOS_WMM_UAPSD_MASK_MIN (0x00) +#define CFG_QOS_WMM_UAPSD_MASK_MAX (0xFF) +#define CFG_QOS_WMM_UAPSD_MASK_DEFAULT (0x00) + +/* + * + * ImplicitQosIsEnabled - Enableimplicit QOS + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to enable/disable implicit QOS. + * + * Related: None. + * + * Supported Feature: WMM + * + * Usage: Internal/External + * + * + */ +#define CFG_QOS_IMPLICIT_SETUP_ENABLED_NAME "ImplicitQosIsEnabled" +#define CFG_QOS_IMPLICIT_SETUP_ENABLED_MIN (0) +#define CFG_QOS_IMPLICIT_SETUP_ENABLED_MAX (1) +#define CFG_QOS_IMPLICIT_SETUP_ENABLED_DEFAULT (0) + +/* + * + * InfraUapsdVoSrvIntv - Set Uapsd service interval for voice + * @Min: 0 + * @Max: 4294967295UL + * @Default: 20 + * + * This ini is used to set Uapsd service interval for voice. + * + * Related: None. + * + * Supported Feature: WMM + * + * Usage: Internal/External + * + * + */ +#define CFG_QOS_WMM_INFRA_UAPSD_VO_SRV_INTV_NAME "InfraUapsdVoSrvIntv" +#define CFG_QOS_WMM_INFRA_UAPSD_VO_SRV_INTV_MIN (0) +#define CFG_QOS_WMM_INFRA_UAPSD_VO_SRV_INTV_MAX (4294967295UL) +#define CFG_QOS_WMM_INFRA_UAPSD_VO_SRV_INTV_DEFAULT (20) + +/* + * + * InfraUapsdVoSuspIntv - Set Uapsd suspension interval for voice + * @Min: 0 + * @Max: 4294967295UL + * @Default: 2000 + * + * This ini is used to set Uapsd suspension interval for voice. + * + * Related: None. + * + * Supported Feature: WMM + * + * Usage: Internal/External + * + * + */ +#define CFG_QOS_WMM_INFRA_UAPSD_VO_SUS_INTV_NAME "InfraUapsdVoSuspIntv" +#define CFG_QOS_WMM_INFRA_UAPSD_VO_SUS_INTV_MIN (0) +#define CFG_QOS_WMM_INFRA_UAPSD_VO_SUS_INTV_MAX (4294967295UL) +#define CFG_QOS_WMM_INFRA_UAPSD_VO_SUS_INTV_DEFAULT (2000) + +/* + * + * InfraUapsdViSrvIntv - Set Uapsd service interval for video + * @Min: 0 + * @Max: 4294967295UL + * @Default: 300 + * + * This ini is used to set Uapsd service interval for video. + * + * Related: None. + * + * Supported Feature: WMM + * + * Usage: Internal/External + * + * + */ +#define CFG_QOS_WMM_INFRA_UAPSD_VI_SRV_INTV_NAME "InfraUapsdViSrvIntv" +#define CFG_QOS_WMM_INFRA_UAPSD_VI_SRV_INTV_MIN (0) +#define CFG_QOS_WMM_INFRA_UAPSD_VI_SRV_INTV_MAX (4294967295UL) +#define CFG_QOS_WMM_INFRA_UAPSD_VI_SRV_INTV_DEFAULT (300) + +/* + * + * InfraUapsdViSuspIntv - Set Uapsd suspension interval for video + * @Min: 0 + * @Max: 4294967295UL + * @Default: 2000 + * + * This ini is used to set Uapsd suspension interval for video + * + * Related: None. + * + * Supported Feature: WMM + * + * Usage: Internal/External + * + * + */ +#define CFG_QOS_WMM_INFRA_UAPSD_VI_SUS_INTV_NAME "InfraUapsdViSuspIntv" +#define CFG_QOS_WMM_INFRA_UAPSD_VI_SUS_INTV_MIN (0) +#define CFG_QOS_WMM_INFRA_UAPSD_VI_SUS_INTV_MAX (4294967295UL) +#define CFG_QOS_WMM_INFRA_UAPSD_VI_SUS_INTV_DEFAULT (2000) + +/* + * + * InfraUapsdBeSrvIntv - Set Uapsd service interval for BE + * @Min: 0 + * @Max: 4294967295UL + * @Default: 300 + * + * This ini is used to set Uapsd service interval for BE + * + * Related: None. + * + * Supported Feature: WMM + * + * Usage: Internal/External + * + * + */ +#define CFG_QOS_WMM_INFRA_UAPSD_BE_SRV_INTV_NAME "InfraUapsdBeSrvIntv" +#define CFG_QOS_WMM_INFRA_UAPSD_BE_SRV_INTV_MIN (0) +#define CFG_QOS_WMM_INFRA_UAPSD_BE_SRV_INTV_MAX (4294967295UL) +#define CFG_QOS_WMM_INFRA_UAPSD_BE_SRV_INTV_DEFAULT (300) + +/* + * + * InfraUapsdBeSuspIntv - Set Uapsd suspension interval for BE + * @Min: 0 + * @Max: 4294967295UL + * @Default: 2000 + * + * This ini is used to set Uapsd suspension interval for BE + * + * Related: None. + * + * Supported Feature: WMM + * + * Usage: Internal/External + * + * + */ +#define CFG_QOS_WMM_INFRA_UAPSD_BE_SUS_INTV_NAME "InfraUapsdBeSuspIntv" +#define CFG_QOS_WMM_INFRA_UAPSD_BE_SUS_INTV_MIN (0) +#define CFG_QOS_WMM_INFRA_UAPSD_BE_SUS_INTV_MAX (4294967295UL) +#define CFG_QOS_WMM_INFRA_UAPSD_BE_SUS_INTV_DEFAULT (2000) + +/* + * + * InfraUapsdBkSrvIntv - Set Uapsd service interval for BK + * @Min: 0 + * @Max: 4294967295UL + * @Default: 300 + * + * This ini is used to set Uapsd service interval for BK + * + * Related: None. + * + * Supported Feature: WMM + * + * Usage: Internal/External + * + * + */ +#define CFG_QOS_WMM_INFRA_UAPSD_BK_SRV_INTV_NAME "InfraUapsdBkSrvIntv" +#define CFG_QOS_WMM_INFRA_UAPSD_BK_SRV_INTV_MIN (0) +#define CFG_QOS_WMM_INFRA_UAPSD_BK_SRV_INTV_MAX (4294967295UL) +#define CFG_QOS_WMM_INFRA_UAPSD_BK_SRV_INTV_DEFAULT (300) + +/* + * + * InfraUapsdBkSuspIntv - Set Uapsd suspension interval for BK + * @Min: 0 + * @Max: 4294967295UL + * @Default: 2000 + * + * This ini is used to set Uapsd suspension interval for BK + * + * Related: None. + * + * Supported Feature: WMM + * + * Usage: Internal/External + * + * + */ +#define CFG_QOS_WMM_INFRA_UAPSD_BK_SUS_INTV_NAME "InfraUapsdBkSuspIntv" +#define CFG_QOS_WMM_INFRA_UAPSD_BK_SUS_INTV_MIN (0) +#define CFG_QOS_WMM_INFRA_UAPSD_BK_SUS_INTV_MAX (4294967295UL) +#define CFG_QOS_WMM_INFRA_UAPSD_BK_SUS_INTV_DEFAULT (2000) + +/* default TSPEC parameters for AC_VO */ +/* + * + * InfraDirAcVo - Set TSPEC direction for VO + * @Min: 0 + * @Max: 3 + * @Default: 3 + * + * This ini is used to set TSPEC direction for VO + * + * Related: None. + * + * Supported Feature: WMM + * + * Usage: Internal/External + * + * + */ +#define CFG_QOS_WMM_INFRA_DIR_AC_VO_NAME "InfraDirAcVo" +#define CFG_QOS_WMM_INFRA_DIR_AC_VO_MIN (0) +#define CFG_QOS_WMM_INFRA_DIR_AC_VO_MAX (3) +#define CFG_QOS_WMM_INFRA_DIR_AC_VO_DEFAULT (3) /*WLAN_QCT_CUST_WMM_TSDIR_BOTH*/ + +/* + * + * InfraNomMsduSizeAcVo - Set normal MSDU size for VO + * @Min: 0x0 + * @Max: 0xFFFF + * @Default: 0x80D0 + * + * This ini is used to set normal MSDU size for VO + * + * Related: None. + * + * Supported Feature: WMM + * + * Usage: Internal/External + * + * + */ +#define CFG_QOS_WMM_INFRA_NOM_MSDU_SIZE_AC_VO_NAME "InfraNomMsduSizeAcVo" +#define CFG_QOS_WMM_INFRA_NOM_MSDU_SIZE_AC_VO_MIN (0x0) +#define CFG_QOS_WMM_INFRA_NOM_MSDU_SIZE_AC_VO_MAX (0xFFFF) +#define CFG_QOS_WMM_INFRA_NOM_MSDU_SIZE_AC_VO_DEFAULT (0x80D0) + +/* + * + * InfraMeanDataRateAcVo - Set mean data rate for VO + * @Min: 0x0 + * @Max: 0xFFFFFFFF + * @Default: 0x14500 + * + * This ini is used to set mean data rate for VO + * + * Related: None. + * + * Supported Feature: WMM + * + * Usage: Internal/External + * + * + */ +#define CFG_QOS_WMM_INFRA_MEAN_DATA_RATE_AC_VO_NAME "InfraMeanDataRateAcVo" +#define CFG_QOS_WMM_INFRA_MEAN_DATA_RATE_AC_VO_MIN (0x0) +#define CFG_QOS_WMM_INFRA_MEAN_DATA_RATE_AC_VO_MAX (0xFFFFFFFF) +#define CFG_QOS_WMM_INFRA_MEAN_DATA_RATE_AC_VO_DEFAULT (0x14500) + +/* + * + * InfraMinPhyRateAcVo - Set min PHY rate for VO + * @Min: 0x0 + * @Max: 0xFFFFFFFF + * @Default: 0x5B8D80 + * + * This ini is used to set min PHY rate for VO + * + * Related: None. + * + * Supported Feature: WMM + * + * Usage: Internal/External + * + * + */ +#define CFG_QOS_WMM_INFRA_MIN_PHY_RATE_AC_VO_NAME "InfraMinPhyRateAcVo" +#define CFG_QOS_WMM_INFRA_MIN_PHY_RATE_AC_VO_MIN (0x0) +#define CFG_QOS_WMM_INFRA_MIN_PHY_RATE_AC_VO_MAX (0xFFFFFFFF) +#define CFG_QOS_WMM_INFRA_MIN_PHY_RATE_AC_VO_DEFAULT (0x5B8D80) + +/* + * + * InfraSbaAcVo - Set surplus bandwidth allowance for VO + * @Min: 0x2001 + * @Max: 0xFFFF + * @Default: 0x2001 + * + * This ini is used to set surplus bandwidth allowance for VO + * + * Related: None. + * + * Supported Feature: WMM + * + * Usage: Internal/External + * + * + */ +#define CFG_QOS_WMM_INFRA_SBA_AC_VO_NAME "InfraSbaAcVo" +#define CFG_QOS_WMM_INFRA_SBA_AC_VO_MIN (0x2001) +#define CFG_QOS_WMM_INFRA_SBA_AC_VO_MAX (0xFFFF) +#define CFG_QOS_WMM_INFRA_SBA_AC_VO_DEFAULT (0x2001) + +/* default TSPEC parameters for AC_VI */ +/* + * + * InfraDirAcVi - Set TSPEC direction for VI + * @Min: 0 + * @Max: 3 + * @Default: 3 + * + * This ini is used to set TSPEC direction for VI + * + * Related: None. + * + * Supported Feature: WMM + * + * Usage: Internal/External + * + * + */ +#define CFG_QOS_WMM_INFRA_DIR_AC_VI_NAME "InfraDirAcVi" +#define CFG_QOS_WMM_INFRA_DIR_AC_VI_MIN (0) +#define CFG_QOS_WMM_INFRA_DIR_AC_VI_MAX (3) +#define CFG_QOS_WMM_INFRA_DIR_AC_VI_DEFAULT (3) /*WLAN_QCT_CUST_WMM_TSDIR_BOTH*/ + +/* + * + * InfraNomMsduSizeAcVi - Set normal MSDU size for VI + * @Min: 0x0 + * @Max: 0xFFFF + * @Default: 0x85DC + * + * This ini is used to set normal MSDU size for VI + * + * Related: None. + * + * Supported Feature: WMM + * + * Usage: Internal/External + * + * + */ +#define CFG_QOS_WMM_INFRA_NOM_MSDU_SIZE_AC_VI_NAME "InfraNomMsduSizeAcVi" +#define CFG_QOS_WMM_INFRA_NOM_MSDU_SIZE_AC_VI_MIN (0x0) +#define CFG_QOS_WMM_INFRA_NOM_MSDU_SIZE_AC_VI_MAX (0xFFFF) +#define CFG_QOS_WMM_INFRA_NOM_MSDU_SIZE_AC_VI_DEFAULT (0x85DC) + +/* + * + * InfraMeanDataRateAcVi - Set mean data rate for VI + * @Min: 0x0 + * @Max: 0xFFFFFFFF + * @Default: 0x57E40 + * + * This ini is used to set mean data rate for VI + * + * Related: None. + * + * Supported Feature: WMM + * + * Usage: Internal/External + * + * + */ +#define CFG_QOS_WMM_INFRA_MEAN_DATA_RATE_AC_VI_NAME "InfraMeanDataRateAcVi" +#define CFG_QOS_WMM_INFRA_MEAN_DATA_RATE_AC_VI_MIN (0x0) +#define CFG_QOS_WMM_INFRA_MEAN_DATA_RATE_AC_VI_MAX (0xFFFFFFFF) +#define CFG_QOS_WMM_INFRA_MEAN_DATA_RATE_AC_VI_DEFAULT (0x57E40) + +/* + * + * iInfraMinPhyRateAcVi - Set min PHY rate for VI + * @Min: 0x0 + * @Max: 0xFFFFFFFF + * @Default: 0x5B8D80 + * + * This ini is used to set min PHY rate for VI + * + * Related: None. + * + * Supported Feature: WMM + * + * Usage: Internal/External + * + * + */ +#define CFG_QOS_WMM_INFRA_MIN_PHY_RATE_AC_VI_NAME "InfraMinPhyRateAcVi" +#define CFG_QOS_WMM_INFRA_MIN_PHY_RATE_AC_VI_MIN (0x0) +#define CFG_QOS_WMM_INFRA_MIN_PHY_RATE_AC_VI_MAX (0xFFFFFFFF) +#define CFG_QOS_WMM_INFRA_MIN_PHY_RATE_AC_VI_DEFAULT (0x5B8D80) + +/* + * + * InfraSbaAcVi - Set surplus bandwidth allowance for VI + * @Min: 0x2001 + * @Max: 0xFFFF + * @Default: 0x2001 + * + * This ini is used to set surplus bandwidth allowance for VI + * + * Related: None. + * + * Supported Feature: WMM + * + * Usage: Internal/External + * + * + */ +#define CFG_QOS_WMM_INFRA_SBA_AC_VI_NAME "InfraSbaAcVi" +#define CFG_QOS_WMM_INFRA_SBA_AC_VI_MIN (0x2001) +#define CFG_QOS_WMM_INFRA_SBA_AC_VI_MAX (0xFFFF) +#define CFG_QOS_WMM_INFRA_SBA_AC_VI_DEFAULT (0x2001) + +/* default TSPEC parameters for AC_BE*/ +/* + * + * InfraDirAcBe - Set TSPEC direction for BE + * @Min: 0 + * @Max: 3 + * @Default: 3 + * + * This ini is used to set TSPEC direction for BE + * + * Related: None. + * + * Supported Feature: WMM + * + * Usage: Internal/External + * + * + */ +#define CFG_QOS_WMM_INFRA_DIR_AC_BE_NAME "InfraDirAcBe" +#define CFG_QOS_WMM_INFRA_DIR_AC_BE_MIN (0) +#define CFG_QOS_WMM_INFRA_DIR_AC_BE_MAX (3) +#define CFG_QOS_WMM_INFRA_DIR_AC_BE_DEFAULT (3) /*WLAN_QCT_CUST_WMM_TSDIR_BOTH*/ + +/* + * + * InfraNomMsduSizeAcBe - Set normal MSDU size for BE + * @Min: 0x0 + * @Max: 0xFFFF + * @Default: 0x85DC + * + * This ini is used to set normal MSDU size for BE + * + * Related: None. + * + * Supported Feature: WMM + * + * Usage: Internal/External + * + * + */ +#define CFG_QOS_WMM_INFRA_NOM_MSDU_SIZE_AC_BE_NAME "InfraNomMsduSizeAcBe" +#define CFG_QOS_WMM_INFRA_NOM_MSDU_SIZE_AC_BE_MIN (0x0) +#define CFG_QOS_WMM_INFRA_NOM_MSDU_SIZE_AC_BE_MAX (0xFFFF) +#define CFG_QOS_WMM_INFRA_NOM_MSDU_SIZE_AC_BE_DEFAULT (0x85DC) + +/* + * + * InfraMeanDataRateAcBe - Set mean data rate for BE + * @Min: 0x0 + * @Max: 0xFFFFFFFF + * @Default: 0x493E0 + * + * This ini is used to set mean data rate for BE + * + * Related: None. + * + * Supported Feature: WMM + * + * Usage: Internal/External + * + * + */ +#define CFG_QOS_WMM_INFRA_MEAN_DATA_RATE_AC_BE_NAME "InfraMeanDataRateAcBe" +#define CFG_QOS_WMM_INFRA_MEAN_DATA_RATE_AC_BE_MIN (0x0) +#define CFG_QOS_WMM_INFRA_MEAN_DATA_RATE_AC_BE_MAX (0xFFFFFFFF) +#define CFG_QOS_WMM_INFRA_MEAN_DATA_RATE_AC_BE_DEFAULT (0x493E0) + +/* + * + * InfraMinPhyRateAcBe - Set min PHY rate for BE + * @Min: 0x0 + * @Max: 0xFFFFFFFF + * @Default: 0x5B8D80 + * + * This ini is used to set min PHY rate for BE + * + * Related: None. + * + * Supported Feature: WMM + * + * Usage: Internal/External + * + * + */ +#define CFG_QOS_WMM_INFRA_MIN_PHY_RATE_AC_BE_NAME "InfraMinPhyRateAcBe" +#define CFG_QOS_WMM_INFRA_MIN_PHY_RATE_AC_BE_MIN (0x0) +#define CFG_QOS_WMM_INFRA_MIN_PHY_RATE_AC_BE_MAX (0xFFFFFFFF) +#define CFG_QOS_WMM_INFRA_MIN_PHY_RATE_AC_BE_DEFAULT (0x5B8D80) + +/* + * + * InfraSbaAcBe - Set surplus bandwidth allowance for BE + * @Min: 0x2001 + * @Max: 0xFFFF + * @Default: 0x2001 + * + * This ini is used to set surplus bandwidth allowance for BE + * + * Related: None. + * + * Supported Feature: WMM + * + * Usage: Internal/External + * + * + */ +#define CFG_QOS_WMM_INFRA_SBA_AC_BE_NAME "InfraSbaAcBe" +#define CFG_QOS_WMM_INFRA_SBA_AC_BE_MIN (0x2001) +#define CFG_QOS_WMM_INFRA_SBA_AC_BE_MAX (0xFFFF) +#define CFG_QOS_WMM_INFRA_SBA_AC_BE_DEFAULT (0x2001) + +/* default TSPEC parameters for AC_Bk*/ +/* + * + * InfraDirAcBk - Set TSPEC direction for BK + * @Min: 0 + * @Max: 3 + * @Default: 3 + * + * This ini is used to set TSPEC direction for BK + * + * Related: None. + * + * Supported Feature: WMM + * + * Usage: Internal/External + * + * + */ +#define CFG_QOS_WMM_INFRA_DIR_AC_BK_NAME "InfraDirAcBk" +#define CFG_QOS_WMM_INFRA_DIR_AC_BK_MIN (0) +#define CFG_QOS_WMM_INFRA_DIR_AC_BK_MAX (3) +#define CFG_QOS_WMM_INFRA_DIR_AC_BK_DEFAULT (3) /*WLAN_QCT_CUST_WMM_TSDIR_BOTH*/ + +/* + * + * InfraNomMsduSizeAcBk - Set normal MSDU size for BK + * @Min: 0x0 + * @Max: 0xFFFF + * @Default: 0x85DC + * + * This ini is used to set normal MSDU size for BK + * + * Related: None. + * + * Supported Feature: WMM + * + * Usage: Internal/External + * + * + */ +#define CFG_QOS_WMM_INFRA_NOM_MSDU_SIZE_AC_BK_NAME "InfraNomMsduSizeAcBk" +#define CFG_QOS_WMM_INFRA_NOM_MSDU_SIZE_AC_BK_MIN (0x0) +#define CFG_QOS_WMM_INFRA_NOM_MSDU_SIZE_AC_BK_MAX (0xFFFF) +#define CFG_QOS_WMM_INFRA_NOM_MSDU_SIZE_AC_BK_DEFAULT (0x85DC) + +/* + * + * InfraMeanDataRateAcBk - Set mean data rate for BK + * @Min: 0x0 + * @Max: 0xFFFFFFFF + * @Default: 0x493E0 + * + * This ini is used to set mean data rate for BK + * + * Related: None. + * + * Supported Feature: WMM + * + * Usage: Internal/External + * + * + */ +#define CFG_QOS_WMM_INFRA_MEAN_DATA_RATE_AC_BK_NAME "InfraMeanDataRateAcBk" +#define CFG_QOS_WMM_INFRA_MEAN_DATA_RATE_AC_BK_MIN (0x0) +#define CFG_QOS_WMM_INFRA_MEAN_DATA_RATE_AC_BK_MAX (0xFFFFFFFF) +#define CFG_QOS_WMM_INFRA_MEAN_DATA_RATE_AC_BK_DEFAULT (0x493E0) + +/* + * + * InfraMinPhyRateAcBke - Set min PHY rate for BK + * @Min: 0x0 + * @Max: 0xFFFFFFFF + * @Default: 0x5B8D80 + * + * This ini is used to set min PHY rate for BK + * + * Related: None. + * + * Supported Feature: WMM + * + * Usage: Internal/External + * + * + */ +#define CFG_QOS_WMM_INFRA_MIN_PHY_RATE_AC_BK_NAME "InfraMinPhyRateAcBk" +#define CFG_QOS_WMM_INFRA_MIN_PHY_RATE_AC_BK_MIN (0x0) +#define CFG_QOS_WMM_INFRA_MIN_PHY_RATE_AC_BK_MAX (0xFFFFFFFF) +#define CFG_QOS_WMM_INFRA_MIN_PHY_RATE_AC_BK_DEFAULT (0x5B8D80) + +/* + * + * InfraSbaAcBk - Set surplus bandwidth allowance for BK + * @Min: 0x2001 + * @Max: 0xFFFF + * @Default: 0x2001 + * + * This ini is used to set surplus bandwidth allowance for BK + * + * Related: None. + * + * Supported Feature: WMM + * + * Usage: Internal/External + * + * + */ +#define CFG_QOS_WMM_INFRA_SBA_AC_BK_NAME "InfraSbaAcBk" +#define CFG_QOS_WMM_INFRA_SBA_AC_BK_MIN (0x2001) +#define CFG_QOS_WMM_INFRA_SBA_AC_BK_MAX (0xFFFF) +#define CFG_QOS_WMM_INFRA_SBA_AC_BK_DEFAULT (0x2001) + +/* + * + * burstSizeDefinition - Set TS burst size + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to set TS burst size + * + * Related: None. + * + * Supported Feature: WMM + * + * Usage: Internal/External + * + * + */ +#define CFG_QOS_WMM_BURST_SIZE_DEFN_NAME "burstSizeDefinition" +#define CFG_QOS_WMM_BURST_SIZE_DEFN_MIN (0) +#define CFG_QOS_WMM_BURST_SIZE_DEFN_MAX (1) +#define CFG_QOS_WMM_BURST_SIZE_DEFN_DEFAULT (0) + +/* + * + * tsInfoAckPolicy - Set TS ack policy + * @Min: 0x00 + * @Max: 0x01 + * @Default: 0x00 + * + * This ini is used to set TS ack policy + * + * Related: None. + * + * Supported Feature: WMM + * + * Usage: Internal/External + * + * + */ +#define CFG_QOS_WMM_TS_INFO_ACK_POLICY_NAME "tsInfoAckPolicy" +#define CFG_QOS_WMM_TS_INFO_ACK_POLICY_MIN (0x00) +#define CFG_QOS_WMM_TS_INFO_ACK_POLICY_MAX (0x01) +#define CFG_QOS_WMM_TS_INFO_ACK_POLICY_DEFAULT (0x00) + +/* + * + * SingleTIDRC - Set replay counter for all TID's + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to set replay counter for all TID's + * + * Related: None. + * + * Supported Feature: WMM + * + * Usage: Internal/External + * + * + */ +#define CFG_SINGLE_TID_RC_NAME "SingleTIDRC" +#define CFG_SINGLE_TID_RC_MIN (0) /* Separate replay counter for all TID */ +#define CFG_SINGLE_TID_RC_MAX (1) /* Single replay counter for all TID */ +#define CFG_SINGLE_TID_RC_DEFAULT (1) + +/* + * + * gAddTSWhenACMIsOff - Set ACM value for AC + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to set ACM value for AC + * + * Related: None. + * + * Supported Feature: WMM + * + * Usage: Internal/External + * + * + */ +#define CFG_QOS_ADDTS_WHEN_ACM_IS_OFF_NAME "gAddTSWhenACMIsOff" +#define CFG_QOS_ADDTS_WHEN_ACM_IS_OFF_MIN (0) +/* Send AddTs even when ACM is not set for the AC */ +#define CFG_QOS_ADDTS_WHEN_ACM_IS_OFF_MAX (1) +#define CFG_QOS_ADDTS_WHEN_ACM_IS_OFF_DEFAULT (0) + +#ifdef FEATURE_WLAN_ESE +#define CFG_QOS_WMM_INFRA_INACTIVITY_INTERVAL_NAME "InfraInactivityInterval" +#define CFG_QOS_WMM_INFRA_INACTIVITY_INTERVAL_MIN (0) +#define CFG_QOS_WMM_INFRA_INACTIVITY_INTERVAL_MAX (4294967295UL) +#define CFG_QOS_WMM_INFRA_INACTIVITY_INTERVAL_DEFAULT (0) /* disabled */ + +#define CFG_ESE_FEATURE_ENABLED_NAME "EseEnabled" +#define CFG_ESE_FEATURE_ENABLED_MIN (0) +#define CFG_ESE_FEATURE_ENABLED_MAX (1) +#define CFG_ESE_FEATURE_ENABLED_DEFAULT (0) /* disabled */ +#endif /* FEATURE_WLAN_ESE */ + +#define CFG_LFR_MAWC_FEATURE_ENABLED_NAME "MAWCEnabled" +#define CFG_LFR_MAWC_FEATURE_ENABLED_MIN (0) +#define CFG_LFR_MAWC_FEATURE_ENABLED_MAX (1) +#define CFG_LFR_MAWC_FEATURE_ENABLED_DEFAULT (0) /* disabled */ + +/*This parameter is used to set Wireless Extended Security Mode.*/ +#define CFG_ENABLE_WES_MODE_NAME "gWESModeEnabled" +#define CFG_ENABLE_WES_MODE_NAME_MIN (0) +#define CFG_ENABLE_WES_MODE_NAME_MAX (1) +#define CFG_ENABLE_WES_MODE_NAME_DEFAULT (0) + +#define CFG_TL_DELAYED_TRGR_FRM_INT_NAME "DelayedTriggerFrmInt" +#define CFG_TL_DELAYED_TRGR_FRM_INT_MIN 1 +#define CFG_TL_DELAYED_TRGR_FRM_INT_MAX (4294967295UL) +#define CFG_TL_DELAYED_TRGR_FRM_INT_DEFAULT 3000 + +/* + * + * gRrmEnable - Enable/Disable RRM + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to controls the capabilities (11 k) included + * in the capabilities field. + * + * Related: None. + * + * Supported Feature: 11k + * + * Usage: Internal/External + * + * + */ +#define CFG_RRM_ENABLE_NAME "gRrmEnable" +#define CFG_RRM_ENABLE_MIN (0) +#define CFG_RRM_ENABLE_MAX (1) +#define CFG_RRM_ENABLE_DEFAULT (0) + +/* + * + * gRrmRandnIntvl - Randomization interval + * @Min: 10 + * @Max: 100 + * @Default: 100 + * + * This ini is used to set randomization interval which is used to start a timer + * of a random value within randomization interval. Next RRM Scan request + * will be issued after the expiry of this random interval. + * + * Related: None. + * + * Supported Feature: 11k + * + * Usage: Internal/External + * + * + */ +#define CFG_RRM_MEAS_RANDOMIZATION_INTVL_NAME "gRrmRandnIntvl" +#define CFG_RRM_MEAS_RANDOMIZATION_INTVL_MIN (10) +#define CFG_RRM_MEAS_RANDOMIZATION_INTVL_MAX (100) +#define CFG_RRM_MEAS_RANDOMIZATION_INTVL_DEFAULT (100) + +/* + * + * rm_capability - Configure RM enabled capabilities IE + * @Default: 73,10,91,00,04 + * + * This ini is used to configure RM enabled capabilities IE. + * Using this INI, we can set/unset any of the bits in 5 bytes + * (last 4bytes are reserved). Bit details are updated as per + * Draft version of 11mc spec. (Draft P802.11REVmc_D4.2) + * + * Bitwise details are defined as bit mask in rrm_global.h + * Comma is used as a separator for each byte. + * + * Related: None. + * + * Supported Feature: 11k + * + * Usage: Internal/External + * + * + */ +#define CFG_RM_CAPABILITY_NAME "rm_capability" +#define CFG_RM_CAPABILITY_DEFAULT "73,10,91,00,04" + +#define CFG_FT_RESOURCE_REQ_NAME "gFTResourceReqSupported" +#define CFG_FT_RESOURCE_REQ_MIN (0) +#define CFG_FT_RESOURCE_REQ_MAX (1) +#define CFG_FT_RESOURCE_REQ_DEFAULT (0) + +#define CFG_TELE_BCN_TRANS_LI_NAME "telescopicBeaconTransListenInterval" +#define CFG_TELE_BCN_TRANS_LI_MIN (0) +#define CFG_TELE_BCN_TRANS_LI_MAX (7) +#define CFG_TELE_BCN_TRANS_LI_DEFAULT (3) + +#define CFG_TELE_BCN_TRANS_LI_NUM_IDLE_BCNS_NAME "telescopicBeaconTransListenIntervalNumIdleBcns" +#define CFG_TELE_BCN_TRANS_LI_NUM_IDLE_BCNS_MIN (5) +#define CFG_TELE_BCN_TRANS_LI_NUM_IDLE_BCNS_MAX (255) +#define CFG_TELE_BCN_TRANS_LI_NUM_IDLE_BCNS_DEFAULT (10) + +#define CFG_TELE_BCN_MAX_LI_NAME "telescopicBeaconMaxListenInterval" +#define CFG_TELE_BCN_MAX_LI_MIN (0) +#define CFG_TELE_BCN_MAX_LI_MAX (7) +#define CFG_TELE_BCN_MAX_LI_DEFAULT (5) + +#define CFG_TELE_BCN_MAX_LI_NUM_IDLE_BCNS_NAME "telescopicBeaconMaxListenIntervalNumIdleBcns" +#define CFG_TELE_BCN_MAX_LI_NUM_IDLE_BCNS_MIN (5) +#define CFG_TELE_BCN_MAX_LI_NUM_IDLE_BCNS_MAX (255) +#define CFG_TELE_BCN_MAX_LI_NUM_IDLE_BCNS_DEFAULT (15) + +#define CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_NAME "gNeighborLookupThreshold" +#define CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MIN (10) +#define CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MAX (120) +#define CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_DEFAULT (78) + +#define CFG_DELAY_BEFORE_VDEV_STOP_NAME "gDelayBeforeVdevStop" +#define CFG_DELAY_BEFORE_VDEV_STOP_MIN (2) +#define CFG_DELAY_BEFORE_VDEV_STOP_MAX (200) +#define CFG_DELAY_BEFORE_VDEV_STOP_DEFAULT (20) + +#define CFG_11R_NEIGHBOR_REQ_MAX_TRIES_NAME "gMaxNeighborReqTries" +#define CFG_11R_NEIGHBOR_REQ_MAX_TRIES_MIN (1) +#define CFG_11R_NEIGHBOR_REQ_MAX_TRIES_MAX (4) +#define CFG_11R_NEIGHBOR_REQ_MAX_TRIES_DEFAULT (3) + +#define CFG_ROAM_BMISS_FIRST_BCNT_NAME "gRoamBmissFirstBcnt" +#define CFG_ROAM_BMISS_FIRST_BCNT_MIN (5) +#define CFG_ROAM_BMISS_FIRST_BCNT_MAX (100) +#define CFG_ROAM_BMISS_FIRST_BCNT_DEFAULT (10) + +#define CFG_ROAM_BMISS_FINAL_BCNT_NAME "gRoamBmissFinalBcnt" +#define CFG_ROAM_BMISS_FINAL_BCNT_MIN (5) +#define CFG_ROAM_BMISS_FINAL_BCNT_MAX (100) +#define CFG_ROAM_BMISS_FINAL_BCNT_DEFAULT (10) + +#define CFG_ROAM_BEACON_RSSI_WEIGHT_NAME "gRoamBeaconRssiWeight" +#define CFG_ROAM_BEACON_RSSI_WEIGHT_MIN (0) +#define CFG_ROAM_BEACON_RSSI_WEIGHT_MAX (16) +#define CFG_ROAM_BEACON_RSSI_WEIGHT_DEFAULT (14) + +/* + * + * McastBcastFilter - Filters Mcast/Bcast Rx packets completely + * @Min: 0 + * @Max: 3 + * @Default: 0 + * + * This ini is used to send default NULL frame to AP + * + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ + +#define CFG_MCAST_BCAST_FILTER_SETTING_NAME "McastBcastFilter" +#define CFG_MCAST_BCAST_FILTER_SETTING_MIN (0) +#define CFG_MCAST_BCAST_FILTER_SETTING_MAX (3) +#define CFG_MCAST_BCAST_FILTER_SETTING_DEFAULT (0) + +/* + * + * gDynamicPSPollvalue - Set dynamic PSpoll value + * @Min: 0 + * @Max: 255 + * @Default: 0 + * + * This ini is used to send default PSpoll value + * + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ + +#define CFG_DYNAMIC_PSPOLL_VALUE_NAME "gDynamicPSPollvalue" +#define CFG_DYNAMIC_PSPOLL_VALUE_MIN (0) +#define CFG_DYNAMIC_PSPOLL_VALUE_MAX (255) +#define CFG_DYNAMIC_PSPOLL_VALUE_DEFAULT (0) + +/* + * + * gTelescopicBeaconWakeupEn - Set teles copic beacon wakeup + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to set default teles copic beacon wakeup + * + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ + +#define CFG_TELE_BCN_WAKEUP_EN_NAME "gTelescopicBeaconWakeupEn" +#define CFG_TELE_BCN_WAKEUP_EN_MIN (0) +#define CFG_TELE_BCN_WAKEUP_EN_MAX (1) +#define CFG_TELE_BCN_WAKEUP_EN_DEFAULT (0) + +/* + * + * gValidateScanList - Set valid date scan list + * @Min: 0 + * @Max: 65535 + * @Default: 30 + * + * This ini is used to set default valid date scan list + * + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ + +#define CFG_VALIDATE_SCAN_LIST_NAME "gValidateScanList" +#define CFG_VALIDATE_SCAN_LIST_MIN (0) +#define CFG_VALIDATE_SCAN_LIST_MAX (1) +#define CFG_VALIDATE_SCAN_LIST_DEFAULT (0) + +#define CFG_NULLDATA_AP_RESP_TIMEOUT_NAME "gNullDataApRespTimeout" +#define CFG_NULLDATA_AP_RESP_TIMEOUT_MIN (WNI_CFG_PS_NULLDATA_AP_RESP_TIMEOUT_STAMIN) +#define CFG_NULLDATA_AP_RESP_TIMEOUT_MAX (WNI_CFG_PS_NULLDATA_AP_RESP_TIMEOUT_STAMAX) +#define CFG_NULLDATA_AP_RESP_TIMEOUT_DEFAULT (WNI_CFG_PS_NULLDATA_AP_RESP_TIMEOUT_STADEF) + +#define CFG_AP_DATA_AVAIL_POLL_PERIOD_NAME "gApDataAvailPollInterval" +#define CFG_AP_DATA_AVAIL_POLL_PERIOD_MIN (WNI_CFG_AP_DATA_AVAIL_POLL_PERIOD_STAMIN) +#define CFG_AP_DATA_AVAIL_POLL_PERIOD_MAX (WNI_CFG_AP_DATA_AVAIL_POLL_PERIOD_STAMAX) +#define CFG_AP_DATA_AVAIL_POLL_PERIOD_DEFAULT (WNI_CFG_AP_DATA_AVAIL_POLL_PERIOD_STADEF) + +#define CFG_ENABLE_HOST_ARPOFFLOAD_NAME "hostArpOffload" +#define CFG_ENABLE_HOST_ARPOFFLOAD_MIN (0) +#define CFG_ENABLE_HOST_ARPOFFLOAD_MAX (1) +#define CFG_ENABLE_HOST_ARPOFFLOAD_DEFAULT (1) + +#define CFG_ENABLE_HOST_SSDP_NAME "ssdp" +#define CFG_ENABLE_HOST_SSDP_MIN (0) +#define CFG_ENABLE_HOST_SSDP_MAX (1) +#define CFG_ENABLE_HOST_SSDP_DEFAULT (1) + +#define CFG_ENABLE_HOST_NSOFFLOAD_NAME "hostNSOffload" +#define CFG_ENABLE_HOST_NSOFFLOAD_MIN (0) +#define CFG_ENABLE_HOST_NSOFFLOAD_MAX (1) +#define CFG_ENABLE_HOST_NSOFFLOAD_DEFAULT (1) + +/* + * + * BandCapability - Preferred band (0: Both, 1: 2.4G only, 2: 5G only) + * @Min: 0 + * @Max: 2 + * @Default: 0 + * + * This ini is used to set default band capability + * (0: Both, 1: 2.4G only, 2: 5G only) + * + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ + +#define CFG_BAND_CAPABILITY_NAME "BandCapability" +#define CFG_BAND_CAPABILITY_MIN (0) +#define CFG_BAND_CAPABILITY_MAX (2) +#define CFG_BAND_CAPABILITY_DEFAULT (0) + +#define CFG_ENABLE_BYPASS_11D_NAME "gEnableBypass11d" +#define CFG_ENABLE_BYPASS_11D_MIN (0) +#define CFG_ENABLE_BYPASS_11D_MAX (1) +#define CFG_ENABLE_BYPASS_11D_DEFAULT (1) + +/* + * + * gEnableDFSChnlScan - enable dfs channel scan. + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to enable/disable dfs channels in scan, enabling this + * will enable driver to include dfs channels in its scan list. + * Related: NA + * + * Supported Feature: DFS, Scan + * + * Usage: Internal/External + * + * + */ +#define CFG_ENABLE_DFS_CHNL_SCAN_NAME "gEnableDFSChnlScan" +#define CFG_ENABLE_DFS_CHNL_SCAN_MIN (0) +#define CFG_ENABLE_DFS_CHNL_SCAN_MAX (1) +#define CFG_ENABLE_DFS_CHNL_SCAN_DEFAULT (1) + +/* + * + * gEnableDFSPnoChnlScan - enable dfs channels in PNO scan + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to enable/disable dfs channels in PNO scan request, + * enabling this ini enables driver to include dfs channels in its + * PNO scan request + * Related: NA + * + * Supported Feature: DFS, PNO + * + * Usage: Internal/External + * + * + */ +#define CFG_ENABLE_DFS_PNO_CHNL_SCAN_NAME "gEnableDFSPnoChnlScan" +#define CFG_ENABLE_DFS_PNO_CHNL_SCAN_MIN (0) +#define CFG_ENABLE_DFS_PNO_CHNL_SCAN_MAX (1) +#define CFG_ENABLE_DFS_PNO_CHNL_SCAN_DEFAULT (1) + +/* + * + * gEnableDumpCollect - It will use for collect the dumps + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to set collect default dump + * + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ + +#define CFG_ENABLE_RAMDUMP_COLLECTION "gEnableDumpCollect" +#define CFG_ENABLE_RAMDUMP_COLLECTION_MIN (0) +#define CFG_ENABLE_RAMDUMP_COLLECTION_MAX (1) +#define CFG_ENABLE_RAMDUMP_COLLECTION_DEFAULT (1) + +typedef enum { + eHDD_LINK_SPEED_REPORT_ACTUAL = 0, + eHDD_LINK_SPEED_REPORT_MAX = 1, + eHDD_LINK_SPEED_REPORT_MAX_SCALED = 2, +} eHddLinkSpeedReportType; + +/* + * + * gVhtChannelWidth - Channel width capability for 11ac + * @Min: 0 + * @Max: 4 + * @Default: 3 + * + * This ini is used to set channel width capability for 11AC. + * eHT_CHANNEL_WIDTH_20MHZ = 0, + * eHT_CHANNEL_WIDTH_40MHZ = 1, + * eHT_CHANNEL_WIDTH_80MHZ = 2, + * eHT_CHANNEL_WIDTH_160MHZ = 3, + * eHT_CHANNEL_WIDTH_80P80MHZ = 4, + * + * Related: NA + * + * Supported Feature: 11AC + * + * Usage: External + * + * + */ +#define CFG_VHT_CHANNEL_WIDTH "gVhtChannelWidth" +#define CFG_VHT_CHANNEL_WIDTH_MIN (0) +#define CFG_VHT_CHANNEL_WIDTH_MAX (4) +#define CFG_VHT_CHANNEL_WIDTH_DEFAULT (3) + +/* +* +* gVhtRxMCS - VHT Rx MCS capability for 1x1 mode +* @Min: 0 +* @Max: 2 +* @Default: 0 +* +* This ini is used to set VHT Rx MCS capability for 1x1 mode. +* 0, MCS0-7 +* 1, MCS0-8 +* 2, MCS0-9 +* +* Related: NA +* +* Supported Feature: 11AC +* +* Usage: Internal/External +* +* +*/ + +#define CFG_VHT_ENABLE_RX_MCS_8_9 "gVhtRxMCS" +#define CFG_VHT_ENABLE_RX_MCS_8_9_MIN (0) +#define CFG_VHT_ENABLE_RX_MCS_8_9_MAX (2) +#define CFG_VHT_ENABLE_RX_MCS_8_9_DEFAULT (0) + +/* + * + * gVhtTxMCS - VHT Tx MCS capability for 1x1 mode + * @Min: 0 + * @Max: 2 + * @Default: 0 + * + * This ini is used to set VHT Tx MCS capability for 1x1 mode. + * 0, MCS0-7 + * 1, MCS0-8 + * 2, MCS0-9 + * + * Related: NA + * + * Supported Feature: 11AC + * + * Usage: Internal/External + * + * + */ + +#define CFG_VHT_ENABLE_TX_MCS_8_9 "gVhtTxMCS" +#define CFG_VHT_ENABLE_TX_MCS_8_9_MIN (0) +#define CFG_VHT_ENABLE_TX_MCS_8_9_MAX (2) +#define CFG_VHT_ENABLE_TX_MCS_8_9_DEFAULT (0) + +/* + * + * gVhtRxMCS2x2 - VHT Rx MCS capability for 2x2 mode + * @Min: 0 + * @Max: 2 + * @Default: 0 + * + * This ini is used to set VHT Rx MCS capability for 2x2 mode. + * 0, MCS0-7 + * 1, MCS0-8 + * 2, MCS0-9 + * + * Related: NA + * + * Supported Feature: 11AC + * + * Usage: External + * + * + */ + +#define CFG_VHT_ENABLE_RX_MCS2x2_8_9 "gVhtRxMCS2x2" +#define CFG_VHT_ENABLE_RX_MCS2x2_8_9_MIN (0) +#define CFG_VHT_ENABLE_RX_MCS2x2_8_9_MAX (2) +#define CFG_VHT_ENABLE_RX_MCS2x2_8_9_DEFAULT (0) + +/* + * + * gVhtTxMCS2x2 - VHT Tx MCS capability for 2x2 mode + * @Min: 0 + * @Max: 2 + * @Default: 0 + * + * This ini is used to set VHT Tx MCS capability for 2x2 mode. + * 0, MCS0-7 + * 1, MCS0-8 + * 2, MCS0-9 + * + * Related: NA + * + * Supported Feature: 11AC + * + * Usage: External + * + * + */ + +#define CFG_VHT_ENABLE_TX_MCS2x2_8_9 "gVhtTxMCS2x2" +#define CFG_VHT_ENABLE_TX_MCS2x2_8_9_MIN (0) +#define CFG_VHT_ENABLE_TX_MCS2x2_8_9_MAX (2) +#define CFG_VHT_ENABLE_TX_MCS2x2_8_9_DEFAULT (0) + +/* + * + * gEnable2x2 - Enables/disables VHT Tx/Rx MCS values for 2x2 + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini disables/enables 2x2 mode. If this is zero then DUT operates as + * 1x1. + * + * 0, Disable. + * 1, Enable + * + * Related: NA + * + * Supported Feature: 11AC + * + * Usage: External + * + * + */ + +#define CFG_VHT_ENABLE_2x2_CAP_FEATURE "gEnable2x2" +#define CFG_VHT_ENABLE_2x2_CAP_FEATURE_MIN (0) +#define CFG_VHT_ENABLE_2x2_CAP_FEATURE_MAX (1) +#define CFG_VHT_ENABLE_2x2_CAP_FEATURE_DEFAULT (0) + +/* + * + * disable_high_ht_mcs_2x2 - disable high mcs index for 2nd stream in 2.4G + * @Min: 0 + * @Max: 8 + * @Default: 0 + * + * This ini is used to disable high HT MCS index for 2.4G STA connection. + * It has been introduced to resolve IOT issue with one of the vendor. + * + * Note: This INI is not useful with 1x1 setting. If some platform supports + * only 1x1 then this INI is not useful. + * + * 0 - It won't disable any HT MCS index (just like normal HT MCS) + * 1 - It will disable 15th bit from HT RX MCS set (from 8-15 bits slot) + * 2 - It will disable 14th & 15th bits from HT RX MCS set + * 3 - It will disable 13th, 14th, & 15th bits from HT RX MCS set + * and so on. + * + * Related: STA + * + * Supported Feature: 11n + * + * Usage: External + */ +#define CFG_DISABLE_HIGH_HT_RX_MCS_2x2 "disable_high_ht_mcs_2x2" +#define CFG_DISABLE_HIGH_HT_RX_MCS_2x2_MIN (0) +#define CFG_DISABLE_HIGH_HT_RX_MCS_2x2_MAX (8) +#define CFG_DISABLE_HIGH_HT_RX_MCS_2x2_DEFAULT (0) + +/* + * + * gStaPrefer80MHzOver160MHz - set Sta perferance to connect in 80HZ/160HZ + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to set Sta perferance to connect in 80HZ/160HZ + * + * 0 - Connects in 160MHz 1x1 when AP is 160MHz 2x2 + * 1 - Connects in 80MHz 2x2 when AP is 160MHz 2x2 + * + * Related: NA + * + * Supported Feature: 11AC + * + * Usage: External + * + * + */ + +#define CFG_STA_PREFER_80MHZ_OVER_160MHZ "gStaPrefer80MHzOver160MHz" +#define CFG_STA_PREFER_80MHZ_OVER_160MHZ_MIN (0) +#define CFG_STA_PREFER_80MHZ_OVER_160MHZ_MAX (1) +#define CFG_STA_PREFER_80MHZ_OVER_160MHZ_DEFAULT (1) + +/* + * + * gVdevTypeNss_2g - set Number of streams per VDEV for 2G band. + * @Min: 0x5555 + * @Max: 0xAAAA + * @Default: 0xAAAA + * + * This ini is used to set Number of streams per VDEV for 2G band + * + * These Nss parameters will have 32-bit configuration value, 2 bits are + * allocated for each vdev. + * Valid values are: + * Min value – 0x5555 + * Max value – 0xAAAA + * Default value will be 0xAAAA for both the parameters. + * Value 0x5555 will configure all vdevs in 1x1 mode in 2.4G band. + * Value 0xAAAA will configure all vdevs in 2x2 mode in 2.4G band. + * + * The max value is defined based on the valid max Nss of the vdev, the valid + * values for each vdev 2-bits are 0x1 and 0x2. 0x3 and 0x0 are not valid vdev + * Nss values. + * + * NSS cfg bit definition. + * STA BIT[0:1] + * SAP BIT[2:3] + * P2P_GO BIT[4:5] + * P2P_CLIENT BIT[6:7] + * IBSS BIT[8:9] + * TDLS BIT[10:11] + * P2P_DEVICE BIT[12:13] + * OCB BIT[14:15] + * + * Related: NA + * + * Supported Feature: Antenna Sharing + * + * Usage: External + * + * + */ + +#define CFG_VDEV_TYPE_NSS_2G "gVdevTypeNss_2g" +#define CFG_VDEV_TYPE_NSS_2G_MIN (0x5555) +#define CFG_VDEV_TYPE_NSS_2G_MAX (0xAAAA) +#define CFG_VDEV_TYPE_NSS_2G_DEFAULT (0xAAAA) + +/* + * + * gVdevTypeNss_5g - set Number of streams per VDEV for 5G band. + * @Min: 0x5555 + * @Max: 0xAAAA + * @Default: 0xAAAA + * + * This ini is used to set Number of streams per VDEV for 5G band + * + * These Nss parameters will have 32-bit configuration value, 2 bits are + * allocated for each vdev. + * Valid values are: + * Min value – 0x5555 + * Max value – 0xAAAA + * Default value will be 0xAAAA for both the parameters. + * Value 0x5555 will configure all vdevs in 1x1 mode in 5 band. + * Value 0xAAAA will configure all vdevs in 2x2 mode in 5 band. + * + * The max value is defined based on the valid max Nss of the vdev, the valid + * values for each vdev 2-bits are 0x1 and 0x2. 0x3 and 0x0 are not valid vdev + * Nss values. + * + * NSS cfg bit definition. + * STA BIT[0:1] + * SAP BIT[2:3] + * P2P_GO BIT[4:5] + * P2P_CLIENT BIT[6:7] + * IBSS BIT[8:9] + * TDLS BIT[10:11] + * P2P_DEVICE BIT[12:13] + * OCB BIT[14:15] + * + * Related: NA + * + * Supported Feature: Antenna Sharing + * + * Usage: External + * + * + */ + +#define CFG_VDEV_TYPE_NSS_5G "gVdevTypeNss_5g" +#define CFG_VDEV_TYPE_NSS_5G_MIN (0x5555) +#define CFG_VDEV_TYPE_NSS_5G_MAX (0xAAAA) +#define CFG_VDEV_TYPE_NSS_5G_DEFAULT (0xAAAA) + +/* + * + * gEnableMuBformee - Enables/disables multi-user (MU) beam formee capability + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini enables/disables multi-user (MU) beam formee + * capability + * + * Change MU Bformee only when gTxBFEnable is enabled. + * When gTxBFEnable and gEnableMuBformee are set, MU beam formee capability is + * enabled. + * Related: gTxBFEnable + * + * Supported Feature: 11AC + * + * Usage: External + * + * + */ + +#define CFG_VHT_ENABLE_MU_BFORMEE_CAP_FEATURE "gEnableMuBformee" +#define CFG_VHT_ENABLE_MU_BFORMEE_CAP_FEATURE_MIN (0) +#define CFG_VHT_ENABLE_MU_BFORMEE_CAP_FEATURE_MAX (1) +#define CFG_VHT_ENABLE_MU_BFORMEE_CAP_FEATURE_DEFAULT (0) + +#define CFG_VHT_ENABLE_PAID_FEATURE "gEnablePAID" +#define CFG_VHT_ENABLE_PAID_FEATURE_MIN (0) +#define CFG_VHT_ENABLE_PAID_FEATURE_MAX (1) +#define CFG_VHT_ENABLE_PAID_FEATURE_DEFAULT (0) + +#define CFG_VHT_ENABLE_GID_FEATURE "gEnableGID" +#define CFG_VHT_ENABLE_GID_FEATURE_MIN (0) +#define CFG_VHT_ENABLE_GID_FEATURE_MAX (1) +#define CFG_VHT_ENABLE_GID_FEATURE_DEFAULT (0) + +/* + * + * gSetTxChainmask1x1 - sets Transmit chain mask. + * @Min: 1 + * @Max: 2 + * @Default: 1 + * + * This ini sets Transmit chain mask. + * + * If gEnable2x2 is disabled, gSetTxChainmask1x1 and gSetRxChainmask1x1 values + * are taken into account. If chainmask value exceeds the maximum number of + * chains supported by target, the max number of chains is used. By default, + * chain0 is selected for both Tx and Rx. + * gSetTxChainmask1x1=1 or gSetRxChainmask1x1=1 to select chain0. + * gSetTxChainmask1x1=2 or gSetRxChainmask1x1=2 to select chain1. + * + * Supported Feature: 11AC + * + * Usage: External + * + * + */ + +#define CFG_VHT_ENABLE_1x1_TX_CHAINMASK "gSetTxChainmask1x1" +#define CFG_VHT_ENABLE_1x1_TX_CHAINMASK_MIN (1) +#define CFG_VHT_ENABLE_1x1_TX_CHAINMASK_MAX (2) +#define CFG_VHT_ENABLE_1x1_TX_CHAINMASK_DEFAULT (1) + +/* + * + * gSetRxChainmask1x1 - Sets Receive chain mask. + * @Min: 1 + * @Max: 2 + * @Default: 1 + * + * This ini is used to set Receive chain mask. + * + * If gEnable2x2 is disabled, gSetTxChainmask1x1 and gSetRxChainmask1x1 values + * are taken into account. If chainmask value exceeds the maximum number of + * chains supported by target, the max number of chains is used. By default, + * chain0 is selected for both Tx and Rx. + * gSetTxChainmask1x1=1 or gSetRxChainmask1x1=1 to select chain0. + * gSetTxChainmask1x1=2 or gSetRxChainmask1x1=2 to select chain1. + * + * Supported Feature: 11AC + * + * Usage: External + * + * + */ + +#define CFG_VHT_ENABLE_1x1_RX_CHAINMASK "gSetRxChainmask1x1" +#define CFG_VHT_ENABLE_1x1_RX_CHAINMASK_MIN (1) +#define CFG_VHT_ENABLE_1x1_RX_CHAINMASK_MAX (2) +#define CFG_VHT_ENABLE_1x1_RX_CHAINMASK_DEFAULT (1) + +/* + * + * gEnableAMPDUPS - Enable the AMPDUPS + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to set default AMPDUPS + * + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ + +#define CFG_ENABLE_AMPDUPS_FEATURE "gEnableAMPDUPS" +#define CFG_ENABLE_AMPDUPS_FEATURE_MIN (0) +#define CFG_ENABLE_AMPDUPS_FEATURE_MAX (1) +#define CFG_ENABLE_AMPDUPS_FEATURE_DEFAULT (0) + +#define CFG_HT_ENABLE_SMPS_CAP_FEATURE "gEnableHtSMPS" +#define CFG_HT_ENABLE_SMPS_CAP_FEATURE_MIN (0) +#define CFG_HT_ENABLE_SMPS_CAP_FEATURE_MAX (1) +#define CFG_HT_ENABLE_SMPS_CAP_FEATURE_DEFAULT (0) + +#define CFG_HT_SMPS_CAP_FEATURE "gHtSMPS" +#define CFG_HT_SMPS_CAP_FEATURE_MIN (0) +#define CFG_HT_SMPS_CAP_FEATURE_MAX (3) +#define CFG_HT_SMPS_CAP_FEATURE_DEFAULT (3) + +/* + * + * gDisableDFSChSwitch - Disable channel switch if radar is found + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to disable channel switch if radar is found + * on that channel. + * Related: NA. + * + * Supported Feature: DFS + * + * Usage: Internal + * + * + */ +#define CFG_DISABLE_DFS_CH_SWITCH "gDisableDFSChSwitch" +#define CFG_DISABLE_DFS_CH_SWITCH_MIN (0) +#define CFG_DISABLE_DFS_CH_SWITCH_MAX (1) +#define CFG_DISABLE_DFS_CH_SWITCH_DEFAULT (0) + +/* + * + * gEnableDFSMasterCap - Enable DFS master capability + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to enable/disable the DFS master capability. + * Disabling it will cause driver to not advertise the spectrum + * management capability + * Related: NA. + * + * Supported Feature: DFS + * + * Usage: Internal/External + * + * + */ +#define CFG_ENABLE_DFS_MASTER_CAPABILITY "gEnableDFSMasterCap" +#define CFG_ENABLE_DFS_MASTER_CAPABILITY_MIN (0) +#define CFG_ENABLE_DFS_MASTER_CAPABILITY_MAX (1) +#define CFG_ENABLE_DFS_MASTER_CAPABILITY_DEFAULT (0) + +/* + * + * gSapPreferredChanLocation - Restrict channel switches between ondoor and + * outdoor. + * @Min: 0 + * @Max: 2 + * @Default: 0 + * + * This ini is used for restricting channel switches between Indoor and outdoor + * channels after radar detection. + * 0- No preferred channel location + * 1- Use indoor channels only + * 2- Use outdoor channels only + * Related: NA. + * + * Supported Feature: DFS + * + * Usage: Internal/External + * + * + */ +#define CFG_SAP_PREFERRED_CHANNEL_LOCATION "gSapPreferredChanLocation" +#define CFG_SAP_PREFERRED_CHANNEL_LOCATION_MIN (0) +#define CFG_SAP_PREFERRED_CHANNEL_LOCATION_MAX (2) +#define CFG_SAP_PREFERRED_CHANNEL_LOCATION_DEFAULT (0) + +/* + * + * gDisableDfsJapanW53 - Block W53 channels in random channel selection + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to block W53 Japan channel in random channel selection + * Related: NA. + * + * Supported Feature: DFS + * + * Usage: Internal/External + * + * + */ +#define CFG_DISABLE_DFS_JAPAN_W53 "gDisableDfsJapanW53" +#define CFG_DISABLE_DFS_JAPAN_W53_MIN (0) +#define CFG_DISABLE_DFS_JAPAN_W53_MAX (1) +#define CFG_DISABLE_DFS_JAPAN_W53_DEFAULT (0) + +/* + * + * gDisableDfsJapanW53 - Enable dfs phyerror filtering offload in FW + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to to enable dfs phyerror filtering offload to firmware + * Enabling it will cause basic phy error to be discarding in firmware. + * Related: NA. + * + * Supported Feature: DFS + * + * Usage: Internal/External + * + * + */ +#define CFG_ENABLE_DFS_PHYERR_FILTEROFFLOAD_NAME "dfsPhyerrFilterOffload" +#define CFG_ENABLE_DFS_PHYERR_FILTEROFFLOAD_MIN (0) +#define CFG_ENABLE_DFS_PHYERR_FILTEROFFLOAD_MAX (1) +#define CFG_ENABLE_DFS_PHYERR_FILTEROFFLOAD_DEFAULT (0) + +#define CFG_REPORT_MAX_LINK_SPEED "gReportMaxLinkSpeed" +#define CFG_REPORT_MAX_LINK_SPEED_MIN (eHDD_LINK_SPEED_REPORT_ACTUAL) +#define CFG_REPORT_MAX_LINK_SPEED_MAX (eHDD_LINK_SPEED_REPORT_MAX_SCALED) +#define CFG_REPORT_MAX_LINK_SPEED_DEFAULT (eHDD_LINK_SPEED_REPORT_MAX_SCALED) + +/* + * + * gLinkSpeedRssiHigh - Report the max possible speed with RSSI scaling + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to set default eHDD_LINK_SPEED_REPORT + * Used when eHDD_LINK_SPEED_REPORT_SCALED is selected + * + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ + +#define CFG_LINK_SPEED_RSSI_HIGH "gLinkSpeedRssiHigh" +#define CFG_LINK_SPEED_RSSI_HIGH_MIN (-127) +#define CFG_LINK_SPEED_RSSI_HIGH_MAX (0) +#define CFG_LINK_SPEED_RSSI_HIGH_DEFAULT (-55) + +/* + * + * gLinkSpeedRssiMed - Used when eHDD_LINK_SPEED_REPORT_SCALED is selected + * @Min: -127 + * @Max: 0 + * @Default: -65 + * + * This ini is used to set medium rssi link speed + * + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ + +#define CFG_LINK_SPEED_RSSI_MID "gLinkSpeedRssiMed" +#define CFG_LINK_SPEED_RSSI_MID_MIN (-127) +#define CFG_LINK_SPEED_RSSI_MID_MAX (0) +#define CFG_LINK_SPEED_RSSI_MID_DEFAULT (-65) + +/* + * + * gLinkSpeedRssiLow - Used when eHDD_LINK_SPEED_REPORT_SCALED is selected + * @Min: -127 + * @Max: 0 + * @Default: -80 + * + * This ini is used to set low rssi link speed + * + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ + +#define CFG_LINK_SPEED_RSSI_LOW "gLinkSpeedRssiLow" +#define CFG_LINK_SPEED_RSSI_LOW_MIN (-127) +#define CFG_LINK_SPEED_RSSI_LOW_MAX (0) +#define CFG_LINK_SPEED_RSSI_LOW_DEFAULT (-80) + +/* + * + * isP2pDeviceAddrAdministrated - Enables to derive the P2P MAC address from + * the primary MAC address + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to enable/disable to derive the P2P MAC address from the + * primary MAC address. + * + * Supported Feature: P2P + * + * Usage: Internal/External + * + * + */ +#define CFG_P2P_DEVICE_ADDRESS_ADMINISTRATED_NAME "isP2pDeviceAddrAdministrated" +#define CFG_P2P_DEVICE_ADDRESS_ADMINISTRATED_MIN (0) +#define CFG_P2P_DEVICE_ADDRESS_ADMINISTRATED_MAX (1) +#define CFG_P2P_DEVICE_ADDRESS_ADMINISTRATED_DEFAULT (1) + +/* + * + * gEnableSSR - Enable/Disable SSR + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to enable/disable System Self Recovery at the times of + * System crash or fatal errors + * gEnableSSR = 0 Disabled + * gEnableSSR = 1 wlan shutdown and re-init happens + * + * Related: None + * + * Supported Feature: SSR + * + * Usage: Internal/External + * + * + */ +#define CFG_ENABLE_SSR "gEnableSSR" +#define CFG_ENABLE_SSR_MIN (0) +#define CFG_ENABLE_SSR_MAX (1) +#define CFG_ENABLE_SSR_DEFAULT (1) + +/* + * + * gEnableOverLapCh - Enables Overlap Channel. If set, allow overlapping + * channels to be selected for the SoftAP + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to set Overlap Channel + * + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ + +#define CFG_ENABLE_OVERLAP_CH "gEnableOverLapCh" +#define CFG_ENABLE_OVERLAP_CH_MIN (0) +#define CFG_ENABLE_OVERLAP_CH_MAX (1) +#define CFG_ENABLE_OVERLAP_CH_DEFAULT (0) + +/* + * + * gEnable5gEBT - Enables/disables 5G early beacon termination. When enabled + * terminate the reception of beacon if the TIM element is + * clear for the power saving + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to set default 5G early beacon termination + * + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ + +#define CFG_PPS_ENABLE_5G_EBT "gEnable5gEBT" +#define CFG_PPS_ENABLE_5G_EBT_FEATURE_MIN (0) +#define CFG_PPS_ENABLE_5G_EBT_FEATURE_MAX (1) +#define CFG_PPS_ENABLE_5G_EBT_FEATURE_DEFAULT (1) + +#define CFG_ENABLE_MEMORY_DEEP_SLEEP "gEnableMemDeepSleep" +#define CFG_ENABLE_MEMORY_DEEP_SLEEP_MIN (0) +#define CFG_ENABLE_MEMORY_DEEP_SLEEP_MAX (1) +#define CFG_ENABLE_MEMORY_DEEP_SLEEP_DEFAULT (1) + +/* + * + * gDefaultRateIndex24Ghz -Set the rate index for 24Ghz + * @Min: 1 + * @Max: 9 + * @Default: 1 + * + * This ini is used to set default rate index + * In cfg.dat 1=1MBPS, 2=2MBPS, 3=5_5MBPS, 4=11MBPS, 5=6MBPS, 6=9MBPS, + * 7=12MBPS, 8=18MBPS, 9=24MBPS. But 6=9MBPS and 8=18MBPS are not basic + * 11g rates and should not be set by gDefaultRateIndex24Ghz. + * + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ + +#define CFG_DEFAULT_RATE_INDEX_24GH "gDefaultRateIndex24Ghz" +#define CFG_DEFAULT_RATE_INDEX_24GH_MIN (1) +#define CFG_DEFAULT_RATE_INDEX_24GH_MAX (9) +#define CFG_DEFAULT_RATE_INDEX_24GH_DEFAULT (1) + +#define CFG_ENABLE_PACKET_LOG "gEnablePacketLog" +#define CFG_ENABLE_PACKET_LOG_MIN (0) +#define CFG_ENABLE_PACKET_LOG_MAX (1) +#ifdef FEATURE_PKTLOG +#define CFG_ENABLE_PACKET_LOG_DEFAULT (1) +#else +#define CFG_ENABLE_PACKET_LOG_DEFAULT (0) +#endif + + + +/* gFwDebugLogType takes values from enum dbglog_process_t, + * make default value as DBGLOG_PROCESS_NET_RAW to give the + * logs to net link since cnss_diag service is started at boot + * time by default. + */ +#define CFG_ENABLE_FW_LOG_TYPE "gFwDebugLogType" +#define CFG_ENABLE_FW_LOG_TYPE_MIN (0) +#define CFG_ENABLE_FW_LOG_TYPE_MAX (255) +#define CFG_ENABLE_FW_LOG_TYPE_DEFAULT (3) + +/* gFwDebugLogLevel takes values from enum DBGLOG_LOG_LVL, + * make default value as DBGLOG_WARN to enable error and + * warning logs by default. + */ +#define CFG_ENABLE_FW_DEBUG_LOG_LEVEL "gFwDebugLogLevel" +#define CFG_ENABLE_FW_DEBUG_LOG_LEVEL_MIN (0) +#define CFG_ENABLE_FW_DEBUG_LOG_LEVEL_MAX (255) +#define CFG_ENABLE_FW_DEBUG_LOG_LEVEL_DEFAULT (3) + +/* For valid values of log levels check enum DBGLOG_LOG_LVL and + * for valid values of module ids check enum WLAN_MODULE_ID. + */ +#define CFG_ENABLE_FW_MODULE_LOG_LEVEL "gFwDebugModuleLoglevel" +#define CFG_ENABLE_FW_MODULE_LOG_DEFAULT "2,1,3,1,5,1,9,1,13,1,14,1,18,1,19,1,26,1,28,1,29,1,31,1,36,1,38,1,46,1,47,1,50,1,52,1,53,1,56,1,60,1,61,1,4,1" + +/* + * + * gEnableRTSProfiles - It will use configuring different RTS profiles + * @Min: 0 + * @Max: 34 + * @Default: 33 + * + * This ini used for configuring different RTS profiles + * to firmware. + * Following are the valid values for the rtsprofile: + * RTSCTS_DISABLED 0 + * RTSCTS_ENABLED_4_SECOND_RATESERIES 17 + * CTS2SELF_ENABLED_4_SECOND_RATESERIES 18 + * RTSCTS_ENABLED_4_SWRETRIES 33 + * CTS2SELF_ENABLED_4_SWRETRIES 34 + * + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ + +#define CFG_ENABLE_FW_RTS_PROFILE "gEnableRTSProfiles" +#define CFG_ENABLE_FW_RTS_PROFILE_MIN (0) +#define CFG_ENABLE_FW_RTS_PROFILE_MAX (34) +#define CFG_ENABLE_FW_RTS_PROFILE_DEFAULT (33) + +#ifdef FEATURE_GREEN_AP +#define CFG_ENABLE_GREEN_AP_FEATURE "gEnableGreenAp" +#define CFG_ENABLE_GREEN_AP_FEATURE_MIN (0) +#define CFG_ENABLE_GREEN_AP_FEATURE_MAX (1) +#define CFG_ENABLE_GREEN_AP_FEATURE_DEFAULT (1) + +/* Enhanced Green AP (EGAP) flags/params */ +#define CFG_ENABLE_EGAP_ENABLE_FEATURE "gEnableEGAP" +#define CFG_ENABLE_EGAP_ENABLE_FEATURE_MIN (0) +#define CFG_ENABLE_EGAP_ENABLE_FEATURE_MAX (1) +#define CFG_ENABLE_EGAP_ENABLE_FEATURE_DEFAULT (1) + +#define CFG_ENABLE_EGAP_INACT_TIME_FEATURE "gEGAPInactTime" +#define CFG_ENABLE_EGAP_INACT_TIME_FEATURE_MIN (0) +#define CFG_ENABLE_EGAP_INACT_TIME_FEATURE_MAX (300000) +#define CFG_ENABLE_EGAP_INACT_TIME_FEATURE_DEFAULT (2000) + +#define CFG_ENABLE_EGAP_WAIT_TIME_FEATURE "gEGAPWaitTime" +#define CFG_ENABLE_EGAP_WAIT_TIME_FEATURE_MIN (0) +#define CFG_ENABLE_EGAP_WAIT_TIME_FEATURE_MAX (300000) +#define CFG_ENABLE_EGAP_WAIT_TIME_FEATURE_DEFAULT (150) + +#define CFG_ENABLE_EGAP_FLAGS_FEATURE "gEGAPFeatures" +#define CFG_ENABLE_EGAP_FLAGS_FEATURE_MIN (0) +#define CFG_ENABLE_EGAP_FLAGS_FEATURE_MAX (15) +#define CFG_ENABLE_EGAP_FLAGS_FEATURE_DEFAULT (3) +/* end Enhanced Green AP flags/params */ + +#endif + +/* + * This INI item is used to control subsystem restart(SSR) test framework + * Set it's value to 1 to enable APPS trigerred SSR testing + */ +#define CFG_ENABLE_CRASH_INJECT "gEnableForceTargetAssert" +#define CFG_ENABLE_CRASH_INJECT_MIN (0) +#define CFG_ENABLE_CRASH_INJECT_MAX (1) +#define CFG_ENABLE_CRASH_INJECT_DEFAULT (0) + +#ifdef FEATURE_WLAN_FORCE_SAP_SCC +/* + * + * gSapSccChanAvoidance - Channel avoidance for SAP in SCC. + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to enable/disable channel avoidance for SAP in SCC + * scenario. + * + * Related: None. + * + * Supported Feature: Concurrency + * + * Usage: Internal/External + * + * + */ + +#define CFG_SAP_SCC_CHAN_AVOIDANCE "gSapSccChanAvoidance" +#define CFG_SAP_SCC_CHAN_AVOIDANCE_MIN (0) +#define CFG_SAP_SCC_CHAN_AVOIDANCE_MAX (1) +#define CFG_SAP_SCC_CHAN_AVOIDANCE_DEFAULT (0) +#endif /* FEATURE_WLAN_FORCE_SAP_SCC */ + +/* + * QDF Trace Enable Control + * Notes: + * the MIN/MAX/DEFAULT values apply for all modules + * the DEFAULT value is outside the valid range. if the DEFAULT + * value is not overridden, then no change will be made to the + * "built in" default values compiled into the code + * values are a bitmap indicating which log levels are to enabled + * (must match order of qdf_trace_level enumerations) + * 00000001 FATAL + * 00000010 ERROR + * 00000100 WARN + * 00001000 INFO + * 00010000 INFO HIGH + * 00100000 INFO MED + * 01000000 INFO LOW + * 10000000 DEBUG + * + * hence a value of 0xFF would set all bits (enable all logs) + */ + +#define CFG_QDF_TRACE_ENABLE_WDI_NAME "qdf_trace_enable_wdi" +#define CFG_QDF_TRACE_ENABLE_HDD_NAME "qdf_trace_enable_hdd" +#define CFG_QDF_TRACE_ENABLE_SME_NAME "qdf_trace_enable_sme" +#define CFG_QDF_TRACE_ENABLE_PE_NAME "qdf_trace_enable_pe" +#define CFG_QDF_TRACE_ENABLE_PMC_NAME "qdf_trace_enable_pmc" +#define CFG_QDF_TRACE_ENABLE_WMA_NAME "qdf_trace_enable_wma" +#define CFG_QDF_TRACE_ENABLE_SYS_NAME "qdf_trace_enable_sys" +#define CFG_QDF_TRACE_ENABLE_QDF_NAME "qdf_trace_enable_qdf" +#define CFG_QDF_TRACE_ENABLE_SAP_NAME "qdf_trace_enable_sap" +#define CFG_QDF_TRACE_ENABLE_HDD_SAP_NAME "qdf_trace_enable_hdd_sap" +#define CFG_QDF_TRACE_ENABLE_BMI_NAME "qdf_trace_enable_bmi" +#define CFG_QDF_TRACE_ENABLE_CFG_NAME "qdf_trace_enable_cfg" +#define CFG_QDF_TRACE_ENABLE_EPPING "qdf_trace_enable_epping" +#define CFG_QDF_TRACE_ENABLE_QDF_DEVICES "qdf_trace_enable_qdf_devices" +#define CFG_QDF_TRACE_ENABLE_TXRX_NAME "cfd_trace_enable_txrx" +#define CFG_QDF_TRACE_ENABLE_HTC_NAME "qdf_trace_enable_htc" +#define CFG_QDF_TRACE_ENABLE_HIF_NAME "qdf_trace_enable_hif" +#define CFG_CDR_TRACE_ENABLE_HDD_SAP_DATA_NAME "qdf_trace_enable_hdd_sap_data" +#define CFG_QDF_TRACE_ENABLE_HDD_DATA_NAME "qdf_trace_enable_hdd_data" + +#define CFG_QDF_TRACE_ENABLE_MIN (0) +#define CFG_QDF_TRACE_ENABLE_MAX (0xff) +#define CFG_QDF_TRACE_ENABLE_DEFAULT (0xffff) + +#define HDD_MCASTBCASTFILTER_FILTER_NONE 0x00 +#define HDD_MCASTBCASTFILTER_FILTER_ALL_MULTICAST 0x01 +#define HDD_MCASTBCASTFILTER_FILTER_ALL_BROADCAST 0x02 +#define HDD_MCASTBCASTFILTER_FILTER_ALL_MULTICAST_BROADCAST 0x03 +#define HDD_MULTICAST_FILTER_LIST 0x04 +#define HDD_MULTICAST_FILTER_LIST_CLEAR 0x05 + +/* + * Enable Dynamic DTIM + * Options + * 0 -Disable DynamicDTIM + * 1 to 5 - SLM will switch to DTIM specified here when host suspends and + * switch DTIM1 when host resumes */ +#define CFG_ENABLE_DYNAMIC_DTIM_NAME "gEnableDynamicDTIM" +#define CFG_ENABLE_DYNAMIC_DTIM_MIN (0) +#define CFG_ENABLE_DYNAMIC_DTIM_MAX (9) +#define CFG_ENABLE_DYNAMIC_DTIM_DEFAULT (0) + +/* + * Driver Force ACS is reintroduced for android SAP legacy configuration method. + * If Driver force acs is enabled, channel/ hw config from hostapd is ignored. + * Driver uses INI params dot11Mode, channel bonding mode and vht chan width + * to derive ACS HW mode and operating BW. + * + * Non android platforms shall not use force ACS method and rely on hostapd + * driven ACS method for concurrent SAP ACS configuration, OBSS etc. + */ +#define CFG_FORCE_SAP_ACS "gApAutoChannelSelection" +#define CFG_FORCE_SAP_ACS_MIN (0) +#define CFG_FORCE_SAP_ACS_MAX (1) +#define CFG_FORCE_SAP_ACS_DEFAULT (0) + +#define CFG_FORCE_SAP_ACS_START_CH "gAPChannelSelectStartChannel" +#define CFG_FORCE_SAP_ACS_START_CH_MIN (0) +#define CFG_FORCE_SAP_ACS_START_CH_MAX (0xFF) +#define CFG_FORCE_SAP_ACS_START_CH_DEFAULT (1) + +#define CFG_FORCE_SAP_ACS_END_CH "gAPChannelSelectEndChannel" +#define CFG_FORCE_SAP_ACS_END_CH_MIN (0) +#define CFG_FORCE_SAP_ACS_END_CH_MAX (0xFF) +#define CFG_FORCE_SAP_ACS_END_CH_DEFAULT (11) + +/* + * + * gEnableSAPManadatoryChanList - Enable SAP Mandatory channel list + * Options. + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to enable/disable the SAP manadatory chan list + * 0 - Disable SAP mandatory chan list + * 1 - Enable SAP mandatory chan list + * + * Supported Feature: SAP + * + * + * Usage: Internal/External + * + * + */ +#define CFG_ENABLE_SAP_MANDATORY_CHAN_LIST "gEnableSAPManadatoryChanList" +#define CFG_ENABLE_SAP_MANDATORY_CHAN_LIST_MIN (0) +#define CFG_ENABLE_SAP_MANDATORY_CHAN_LIST_MAX (1) +#define CFG_ENABLE_SAP_MANDATORY_CHAN_LIST_DEFAULT (0) + + +/* + * + * gSkipDfsChannelInP2pSearch - Skip DFS Channel in case of P2P Search + * options + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to decide if DFS channels should be skipped in p2p + * search or not. + * 0 - Don't Skip DFS Channel in case of P2P Search + * 1 - Skip DFS Channel in case of P2P Search + * + * Supported Feature: P2P, Scan + * + * + * Usage: Internal/External + * + * + */ +/* + * + * gSkipDfsChannelInP2pSearch - Skip DFS Channel in case of P2P Search + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to to disable(skip) dfs channel in p2p search. + * Related: NA. + * + * Supported Feature: DFS P2P + * + * Usage: Internal/External + * + * + */ +#define CFG_ENABLE_SKIP_DFS_IN_P2P_SEARCH_NAME "gSkipDfsChannelInP2pSearch" +#define CFG_ENABLE_SKIP_DFS_IN_P2P_SEARCH_MIN (0) +#define CFG_ENABLE_SKIP_DFS_IN_P2P_SEARCH_MAX (1) +#define CFG_ENABLE_SKIP_DFS_IN_P2P_SEARCH_DEFAULT (1) + +/* + * + * gIgnoreDynamicDtimInP2pMode - Ignore Dynamic Dtim in case of P2P + * Options. + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to decide if Dynamic Dtim needs to be consider or + * not in case of P2P. + * 0 - Consider Dynamic Dtim incase of P2P + * 1 - Ignore Dynamic Dtim incase of P2P + * + * Supported Feature: P2P + * + * + * Usage: Internal/External + * + * + */ +#define CFG_IGNORE_DYNAMIC_DTIM_IN_P2P_MODE_NAME "gIgnoreDynamicDtimInP2pMode" +#define CFG_IGNORE_DYNAMIC_DTIM_IN_P2P_MODE_MIN (0) +#define CFG_IGNORE_DYNAMIC_DTIM_IN_P2P_MODE_MAX (1) +#define CFG_IGNORE_DYNAMIC_DTIM_IN_P2P_MODE_DEFAULT (0) + +/* + * + * gShortGI40Mhz - It will check gShortGI20Mhz and + * gShortGI40Mhz from session entry + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to set default gShortGI40Mhz + * + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ + +#define CFG_SHORT_GI_40MHZ_NAME "gShortGI40Mhz" +#define CFG_SHORT_GI_40MHZ_MIN 0 +#define CFG_SHORT_GI_40MHZ_MAX 1 +#define CFG_SHORT_GI_40MHZ_DEFAULT 1 + +/* + * + * gEnableMCCMode - Enable/Disable MCC feature. + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to enable/disable MCC feature. + * + * Related: None. + * + * Supported Feature: Concurrency + * + * Usage: Internal/External + * + * + */ +#define CFG_ENABLE_MCC_ENABLED_NAME "gEnableMCCMode" +#define CFG_ENABLE_MCC_ENABLED_MIN (0) +#define CFG_ENABLE_MCC_ENABLED_MAX (1) +#define CFG_ENABLE_MCC_ENABLED_DEFAULT (1) + +/* + * + * gAllowMCCGODiffBI - Allow GO in MCC mode to accept different beacon interval + * than STA's. + * @Min: 0 + * @Max: 4 + * @Default: 4 + * + * This ini is used to allow GO in MCC mode to accept different beacon interval + * than STA's. + * Added for Wi-Fi Cert. 5.1.12 + * If gAllowMCCGODiffBI = 1 + * Set to 1 for WFA certification. GO Beacon interval is not changed. + * MCC GO doesn't work well in optimized way. In worst scenario, it may + * invite STA disconnection. + * If gAllowMCCGODiffBI = 2 + * If set to 2 workaround 1 disassoc all the clients and update beacon + * Interval. + * If gAllowMCCGODiffBI = 3 + * If set to 3 tear down the P2P link in auto/Non-autonomous -GO case. + * If gAllowMCCGODiffBI = 4 + * If set to 4 don't disconnect the P2P client in autonomous/Non-auto- + * nomous -GO case update the BI dynamically + * + * Related: None. + * + * Supported Feature: Concurrency + * + * Usage: Internal/External + * + * + */ +#define CFG_ALLOW_MCC_GO_DIFF_BI_NAME "gAllowMCCGODiffBI" +#define CFG_ALLOW_MCC_GO_DIFF_BI_MIN (0) +#define CFG_ALLOW_MCC_GO_DIFF_BI_MAX (4) +#define CFG_ALLOW_MCC_GO_DIFF_BI_DEFAULT (4) + +#if defined(CONFIG_HL_SUPPORT) && defined(QCA_BAD_PEER_TX_FLOW_CL) +/* + * Enable/Disable Bad Peer TX CTL feature + * Default: Enable + */ +#define CFG_BAD_PEER_TX_CTL_ENABLE_NAME "gBadPeerTxCtlEnable" +#define CFG_BAD_PEER_TX_CTL_ENABLE_MIN (0) +#define CFG_BAD_PEER_TX_CTL_ENABLE_MAX (1) +#define CFG_BAD_PEER_TX_CTL_ENABLE_DEFAULT (1) + +#define CFG_BAD_PEER_TX_CTL_PERIOD_NAME "gBadPeerTxCtlPeriod" +#define CFG_BAD_PEER_TX_CTL_PERIOD_MIN (10) +#define CFG_BAD_PEER_TX_CTL_PERIOD_MAX (10000) +#define CFG_BAD_PEER_TX_CTL_PERIOD_DEFAULT (50) + +#define CFG_BAD_PEER_TX_CTL_TXQ_LIMIT_NAME "gBadPeerTxCtlTxqLimit" +#define CFG_BAD_PEER_TX_CTL_TXQ_LIMIT_MIN (1) +#define CFG_BAD_PEER_TX_CTL_TXQ_LIMIT_MAX (5000) +#define CFG_BAD_PEER_TX_CTL_TXQ_LIMIT_DEFAULT (100) + +#define CFG_BAD_PEER_TX_CTL_TGT_BACKOFF_T_NAME "gBadPeerTxCtlTgtBackoffTime" +#define CFG_BAD_PEER_TX_CTL_TGT_BACKOFF_T_MIN (1) +#define CFG_BAD_PEER_TX_CTL_TGT_BACKOFF_T_MAX (5000) +#define CFG_BAD_PEER_TX_CTL_TGT_BACKOFF_T_DEFAULT (20) + +#define CFG_BAD_PEER_TX_CTL_TGT_REPORT_PRD_NAME "gBadPeerTxCtlTgtReportPeriod" +#define CFG_BAD_PEER_TX_CTL_TGT_REPORT_PRD_MIN (1) +#define CFG_BAD_PEER_TX_CTL_TGT_REPORT_PRD_MAX (5000) +#define CFG_BAD_PEER_TX_CTL_TGT_REPORT_PRD_DEFAULT (500) + +#define CFG_BAD_PEER_TX_CTL_COND_LEVEL_IEEEB_NAME "gBadPeerTxCtlCondLevelIeeeB" +#define CFG_BAD_PEER_TX_CTL_COND_LEVEL_IEEEB_MIN (1) +#define CFG_BAD_PEER_TX_CTL_COND_LEVEL_IEEEB_MAX (2) +#define CFG_BAD_PEER_TX_CTL_COND_LEVEL_IEEEB_DEFAULT (2) + +#define CFG_BAD_PEER_TX_CTL_DELTA_LEVEL_IEEEB_NAME "gBadPeerTxCtlDeltaLevelIeeeB" +#define CFG_BAD_PEER_TX_CTL_DELTA_LEVEL_IEEEB_MIN (1) +#define CFG_BAD_PEER_TX_CTL_DELTA_LEVEL_IEEEB_MAX (11) +#define CFG_BAD_PEER_TX_CTL_DELTA_LEVEL_IEEEB_DEFAULT (2) + +#define CFG_BAD_PEER_TX_CTL_PCT_LEVEL_IEEEB_NAME "gBadPeerTxCtlPctLevelIeeeB" +#define CFG_BAD_PEER_TX_CTL_PCT_LEVEL_IEEEB_MIN (1) +#define CFG_BAD_PEER_TX_CTL_PCT_LEVEL_IEEEB_MAX (8) +#define CFG_BAD_PEER_TX_CTL_PCT_LEVEL_IEEEB_DEFAULT (1) + +#define CFG_BAD_PEER_TX_CTL_TPUT_LEVEL_IEEEB_NAME "gBadPeerTxCtlTputLevelIeeeB" +#define CFG_BAD_PEER_TX_CTL_TPUT_LEVEL_IEEEB_MIN (1) +#define CFG_BAD_PEER_TX_CTL_TPUT_LEVEL_IEEEB_MAX (11) +#define CFG_BAD_PEER_TX_CTL_TPUT_LEVEL_IEEEB_DEFAULT (2) + +#define CFG_BAD_PEER_TX_CTL_TX_LIMIT_LEVEL_IEEEB_NAME "gBadPeerTxCtlTxLimitLevelIeeeB" +#define CFG_BAD_PEER_TX_CTL_TX_LIMIT_LEVEL_IEEEB_MIN (0) +#define CFG_BAD_PEER_TX_CTL_TX_LIMIT_LEVEL_IEEEB_MAX (50) +#define CFG_BAD_PEER_TX_CTL_TX_LIMIT_LEVEL_IEEEB_DEFAULT (3) + +#define CFG_BAD_PEER_TX_CTL_COND_LEVEL_IEEEAG_NAME "gBadPeerTxCtlCondLevelIeeeAG" +#define CFG_BAD_PEER_TX_CTL_COND_LEVEL_IEEEAG_MIN (1) +#define CFG_BAD_PEER_TX_CTL_COND_LEVEL_IEEEAG_MAX (2) +#define CFG_BAD_PEER_TX_CTL_COND_LEVEL_IEEEAG_DEFAULT (2) + +#define CFG_BAD_PEER_TX_CTL_DELTA_LEVEL_IEEEAG_NAME "gBadPeerTxCtlDeltaLevelIeeeAG" +#define CFG_BAD_PEER_TX_CTL_DELTA_LEVEL_IEEEAG_MIN (6) +#define CFG_BAD_PEER_TX_CTL_DELTA_LEVEL_IEEEAG_MAX (54) +#define CFG_BAD_PEER_TX_CTL_DELTA_LEVEL_IEEEAG_DEFAULT (6) + +#define CFG_BAD_PEER_TX_CTL_PCT_LEVEL_IEEEAG_NAME "gBadPeerTxCtlPctLevelIeeeAG" +#define CFG_BAD_PEER_TX_CTL_PCT_LEVEL_IEEEAG_MIN (1) +#define CFG_BAD_PEER_TX_CTL_PCT_LEVEL_IEEEAG_MAX (8) +#define CFG_BAD_PEER_TX_CTL_PCT_LEVEL_IEEEAG_DEFAULT (1) + +#define CFG_BAD_PEER_TX_CTL_TPUT_LEVEL_IEEEAG_NAME "gBadPeerTxCtlTputLevelIeeeAG" +#define CFG_BAD_PEER_TX_CTL_TPUT_LEVEL_IEEEAG_MIN (6) +#define CFG_BAD_PEER_TX_CTL_TPUT_LEVEL_IEEEAG_MAX (54) +#define CFG_BAD_PEER_TX_CTL_TPUT_LEVEL_IEEEAG_DEFAULT (6) + +#define CFG_BAD_PEER_TX_CTL_TX_LIMIT_LEVEL_IEEEAG_NAME "gBadPeerTxCtlTxLimitLevelIeeeAG" +#define CFG_BAD_PEER_TX_CTL_TX_LIMIT_LEVEL_IEEEAG_MIN (0) +#define CFG_BAD_PEER_TX_CTL_TX_LIMIT_LEVEL_IEEEAG_MAX (50) +#define CFG_BAD_PEER_TX_CTL_TX_LIMIT_LEVEL_IEEEAG_DEFAULT (3) + +#define CFG_BAD_PEER_TX_CTL_COND_LEVEL_IEEEN_NAME "gBadPeerTxCtlCondLevelIeeeN" +#define CFG_BAD_PEER_TX_CTL_COND_LEVEL_IEEEN_MIN (1) +#define CFG_BAD_PEER_TX_CTL_COND_LEVEL_IEEEN_MAX (2) +#define CFG_BAD_PEER_TX_CTL_COND_LEVEL_IEEEN_DEFAULT (2) + +#define CFG_BAD_PEER_TX_CTL_DELTA_LEVEL_IEEEN_NAME "gBadPeerTxCtlDeltaLevelIeeeN" +#define CFG_BAD_PEER_TX_CTL_DELTA_LEVEL_IEEEN_MIN (6) +#define CFG_BAD_PEER_TX_CTL_DELTA_LEVEL_IEEEN_MAX (72) +#define CFG_BAD_PEER_TX_CTL_DELTA_LEVEL_IEEEN_DEFAULT (6) + +#define CFG_BAD_PEER_TX_CTL_PCT_LEVEL_IEEEN_NAME "gBadPeerTxCtlPctLevelIeeeN" +#define CFG_BAD_PEER_TX_CTL_PCT_LEVEL_IEEEN_MIN (1) +#define CFG_BAD_PEER_TX_CTL_PCT_LEVEL_IEEEN_MAX (8) +#define CFG_BAD_PEER_TX_CTL_PCT_LEVEL_IEEEN_DEFAULT (1) + +#define CFG_BAD_PEER_TX_CTL_TPUT_LEVEL_IEEEN_NAME "gBadPeerTxCtlTputLevelIeeeN" +#define CFG_BAD_PEER_TX_CTL_TPUT_LEVEL_IEEEN_MIN (6) +#define CFG_BAD_PEER_TX_CTL_TPUT_LEVEL_IEEEN_MAX (72) +#define CFG_BAD_PEER_TX_CTL_TPUT_LEVEL_IEEEN_DEFAULT (15) + +#define CFG_BAD_PEER_TX_CTL_TX_LIMIT_LEVEL_IEEEN_NAME "gBadPeerTxCtlTxLimitLevelIeeeN" +#define CFG_BAD_PEER_TX_CTL_TX_LIMIT_LEVEL_IEEEN_MIN (0) +#define CFG_BAD_PEER_TX_CTL_TX_LIMIT_LEVEL_IEEEN_MAX (50) +#define CFG_BAD_PEER_TX_CTL_TX_LIMIT_LEVEL_IEEEN_DEFAULT (3) + +#define CFG_BAD_PEER_TX_CTL_COND_LEVEL_IEEEAC_NAME "gBadPeerTxCtlCondLevelIeeeAC" +#define CFG_BAD_PEER_TX_CTL_COND_LEVEL_IEEEAC_MIN (1) +#define CFG_BAD_PEER_TX_CTL_COND_LEVEL_IEEEAC_MAX (2) +#define CFG_BAD_PEER_TX_CTL_COND_LEVEL_IEEEAC_DEFAULT (2) + +#define CFG_BAD_PEER_TX_CTL_DELTA_LEVEL_IEEEAC_NAME "gBadPeerTxCtlDeltaLevelIeeeAC" +#define CFG_BAD_PEER_TX_CTL_DELTA_LEVEL_IEEEAC_MIN (6) +#define CFG_BAD_PEER_TX_CTL_DELTA_LEVEL_IEEEAC_MAX (433) +#define CFG_BAD_PEER_TX_CTL_DELTA_LEVEL_IEEEAC_DEFAULT (6) + +#define CFG_BAD_PEER_TX_CTL_PCT_LEVEL_IEEEAC_NAME "gBadPeerTxCtlPctLevelIeeeAC" +#define CFG_BAD_PEER_TX_CTL_PCT_LEVEL_IEEEAC_MIN (1) +#define CFG_BAD_PEER_TX_CTL_PCT_LEVEL_IEEEAC_MAX (8) +#define CFG_BAD_PEER_TX_CTL_PCT_LEVEL_IEEEAC_DEFAULT (1) + +#define CFG_BAD_PEER_TX_CTL_TPUT_LEVEL_IEEEAC_NAME "gBadPeerTxCtlTputLevelIeeeAC" +#define CFG_BAD_PEER_TX_CTL_TPUT_LEVEL_IEEEAC_MIN (6) +#define CFG_BAD_PEER_TX_CTL_TPUT_LEVEL_IEEEAC_MAX (433) +#define CFG_BAD_PEER_TX_CTL_TPUT_LEVEL_IEEEAC_DEFAULT (15) + +#define CFG_BAD_PEER_TX_CTL_TX_LIMIT_LEVEL_IEEEAC_NAME "gBadPeerTxCtlTxLimitLevelIeeeAC" +#define CFG_BAD_PEER_TX_CTL_TX_LIMIT_LEVEL_IEEEAC_MIN (0) +#define CFG_BAD_PEER_TX_CTL_TX_LIMIT_LEVEL_IEEEAC_MAX (50) +#define CFG_BAD_PEER_TX_CTL_TX_LIMIT_LEVEL_IEEEAC_DEFAULT (3) +#endif + + +/* + * Enable/Disable Thermal Mitigation feature + * Default: Enable + */ +#define CFG_THERMAL_MIGRATION_ENABLE_NAME "gThermalMitigationEnable" +#define CFG_THERMAL_MIGRATION_ENABLE_MIN (0) +#define CFG_THERMAL_MIGRATION_ENABLE_MAX (1) +#define CFG_THERMAL_MIGRATION_ENABLE_DEFAULT (0) + +#define CFG_THROTTLE_PERIOD_NAME "gThrottlePeriod" +#define CFG_THROTTLE_PERIOD_MIN (10) +#define CFG_THROTTLE_PERIOD_MAX (10000) +#define CFG_THROTTLE_PERIOD_DEFAULT (4000) + +/* + * Configure Throttle Period Different Level Duty Cycle in percentage + * When temperature measured is greater than threshold at particular level, + * then throtling level will get increased by one level and + * will reduce TX duty by the given percentage + */ +#define CFG_THROTTLE_DUTY_CYCLE_LEVEL0_NAME "gThrottleDutyCycleLevel0" +#define CFG_THROTTLE_DUTY_CYCLE_LEVEL0_MIN (0) +#define CFG_THROTTLE_DUTY_CYCLE_LEVEL0_MAX (0) +#define CFG_THROTTLE_DUTY_CYCLE_LEVEL0_DEFAULT (0) + +#define CFG_THROTTLE_DUTY_CYCLE_LEVEL1_NAME "gThrottleDutyCycleLevel1" +#define CFG_THROTTLE_DUTY_CYCLE_LEVEL1_MIN (0) +#define CFG_THROTTLE_DUTY_CYCLE_LEVEL1_MAX (100) +#define CFG_THROTTLE_DUTY_CYCLE_LEVEL1_DEFAULT (50) + +#define CFG_THROTTLE_DUTY_CYCLE_LEVEL2_NAME "gThrottleDutyCycleLevel2" +#define CFG_THROTTLE_DUTY_CYCLE_LEVEL2_MIN (0) +#define CFG_THROTTLE_DUTY_CYCLE_LEVEL2_MAX (100) +#define CFG_THROTTLE_DUTY_CYCLE_LEVEL2_DEFAULT (75) + +#define CFG_THROTTLE_DUTY_CYCLE_LEVEL3_NAME "gThrottleDutyCycleLevel3" +#define CFG_THROTTLE_DUTY_CYCLE_LEVEL3_MIN (0) +#define CFG_THROTTLE_DUTY_CYCLE_LEVEL3_MAX (100) +#define CFG_THROTTLE_DUTY_CYCLE_LEVEL3_DEFAULT (94) + +#define CFG_THERMAL_TEMP_MIN_LEVEL0_NAME "gThermalTempMinLevel0" +#define CFG_THERMAL_TEMP_MIN_LEVEL0_MIN (0) +#define CFG_THERMAL_TEMP_MIN_LEVEL0_MAX (1000) +#define CFG_THERMAL_TEMP_MIN_LEVEL0_DEFAULT (0) + +#define CFG_THERMAL_TEMP_MAX_LEVEL0_NAME "gThermalTempMaxLevel0" +#define CFG_THERMAL_TEMP_MAX_LEVEL0_MIN (0) +#define CFG_THERMAL_TEMP_MAX_LEVEL0_MAX (1000) +#define CFG_THERMAL_TEMP_MAX_LEVEL0_DEFAULT (90) + +#define CFG_THERMAL_TEMP_MIN_LEVEL1_NAME "gThermalTempMinLevel1" +#define CFG_THERMAL_TEMP_MIN_LEVEL1_MIN (0) +#define CFG_THERMAL_TEMP_MIN_LEVEL1_MAX (1000) +#define CFG_THERMAL_TEMP_MIN_LEVEL1_DEFAULT (70) + +#define CFG_THERMAL_TEMP_MAX_LEVEL1_NAME "gThermalTempMaxLevel1" +#define CFG_THERMAL_TEMP_MAX_LEVEL1_MIN (0) +#define CFG_THERMAL_TEMP_MAX_LEVEL1_MAX (1000) +#define CFG_THERMAL_TEMP_MAX_LEVEL1_DEFAULT (110) + +#define CFG_THERMAL_TEMP_MIN_LEVEL2_NAME "gThermalTempMinLevel2" +#define CFG_THERMAL_TEMP_MIN_LEVEL2_MIN (0) +#define CFG_THERMAL_TEMP_MIN_LEVEL2_MAX (1000) +#define CFG_THERMAL_TEMP_MIN_LEVEL2_DEFAULT (90) + +#define CFG_THERMAL_TEMP_MAX_LEVEL2_NAME "gThermalTempMaxLevel2" +#define CFG_THERMAL_TEMP_MAX_LEVEL2_MIN (0) +#define CFG_THERMAL_TEMP_MAX_LEVEL2_MAX (1000) +#define CFG_THERMAL_TEMP_MAX_LEVEL2_DEFAULT (125) + +#define CFG_THERMAL_TEMP_MIN_LEVEL3_NAME "gThermalTempMinLevel3" +#define CFG_THERMAL_TEMP_MIN_LEVEL3_MIN (0) +#define CFG_THERMAL_TEMP_MIN_LEVEL3_MAX (1000) +#define CFG_THERMAL_TEMP_MIN_LEVEL3_DEFAULT (110) + +#define CFG_THERMAL_TEMP_MAX_LEVEL3_NAME "gThermalTempMaxLevel3" +#define CFG_THERMAL_TEMP_MAX_LEVEL3_MIN (0) +#define CFG_THERMAL_TEMP_MAX_LEVEL3_MAX (1000) +#define CFG_THERMAL_TEMP_MAX_LEVEL3_DEFAULT (0) + +/* + * Enable/Disable Modulated DTIM feature + * Default: Disable + */ +#define CFG_ENABLE_MODULATED_DTIM_NAME "gEnableModulatedDTIM" +#define CFG_ENABLE_MODULATED_DTIM_MIN (0) +#define CFG_ENABLE_MODULATED_DTIM_MAX (5) +#define CFG_ENABLE_MODULATED_DTIM_DEFAULT (0) + +/* + * + * gMCAddrListEnable - Enable/Disable Multicast MAC Address List feature + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to set default MAC Address + * Default: Enable + * + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ + +#define CFG_MC_ADDR_LIST_ENABLE_NAME "gMCAddrListEnable" +#define CFG_MC_ADDR_LIST_ENABLE_MIN (0) +#define CFG_MC_ADDR_LIST_ENABLE_MAX (1) +#define CFG_MC_ADDR_LIST_ENABLE_DEFAULT (1) + +/* + * + * gEnableRXSTBC - Enables/disables Rx STBC capability in STA mode + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to set default Rx STBC capability + * + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ + +#define CFG_ENABLE_RX_STBC "gEnableRXSTBC" +#define CFG_ENABLE_RX_STBC_MIN (0) +#define CFG_ENABLE_RX_STBC_MAX (1) +#define CFG_ENABLE_RX_STBC_DEFAULT (1) + +/* + * + * gEnableTXSTBC - Enables/disables Tx STBC capability in STA mode + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to set default Tx STBC capability + * + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ + +#define CFG_ENABLE_TX_STBC "gEnableTXSTBC" +#define CFG_ENABLE_TX_STBC_MIN (0) +#define CFG_ENABLE_TX_STBC_MAX (1) +#define CFG_ENABLE_TX_STBC_DEFAULT (0) + +/* + * + * gEnableRXLDPC - Enables/disables Rx LDPC capability in STA mode + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to set default Rx LDPC capability + * + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ + +#define CFG_ENABLE_RX_LDPC "gEnableRXLDPC" +#define CFG_ENABLE_RX_LDPC_MIN (0) +#define CFG_ENABLE_RX_LDPC_MAX (1) +#define CFG_ENABLE_RX_LDPC_DEFAULT (0) + +#ifdef FEATURE_WLAN_TDLS +/* + * + * gEnableTDLSSupport - Enable support for TDLS. + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to enable/disable TDLS support. + * + * Related: None. + * + * Supported Feature: TDLS + * + * Usage: Internal/External + * + * + */ +#define CFG_TDLS_SUPPORT_ENABLE "gEnableTDLSSupport" +#define CFG_TDLS_SUPPORT_ENABLE_MIN (0) +#define CFG_TDLS_SUPPORT_ENABLE_MAX (1) +#define CFG_TDLS_SUPPORT_ENABLE_DEFAULT (0) + +/* + * + * gEnableTDLSImplicitTrigger - Enable Implicit TDLS. + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to enable/disable implicit TDLS. + * CLD driver initiates TDLS Discovery towards a peer whenever TDLS Setup + * criteria (throughput and RSSI thresholds) is met and then it tears down + * TDLS when teardown criteria (idle packet count and RSSI) is met. + * + * Related: gEnableTDLSSupport. + * + * Supported Feature: TDLS + * + * Usage: Internal/External + * + * + */ +#define CFG_TDLS_IMPLICIT_TRIGGER "gEnableTDLSImplicitTrigger" +#define CFG_TDLS_IMPLICIT_TRIGGER_MIN (0) +#define CFG_TDLS_IMPLICIT_TRIGGER_MAX (1) +#define CFG_TDLS_IMPLICIT_TRIGGER_DEFAULT (0) + +/* + * + * gTDLSTxStatsPeriod - TDLS TX statistics time period. + * @Min: 1000 + * @Max: 4294967295 + * @Default: 2000 + * + * This ini is used to configure the time period (in ms) to evaluate whether + * the number of Tx/Rx packets exceeds TDLSTxPacketThreshold and triggers a + * TDLS Discovery request. + * + * Related: gEnableTDLSSupport. + * + * Supported Feature: TDLS + * + * Usage: Internal/External + * + * + */ +#define CFG_TDLS_TX_STATS_PERIOD "gTDLSTxStatsPeriod" +#define CFG_TDLS_TX_STATS_PERIOD_MIN (1000) +#define CFG_TDLS_TX_STATS_PERIOD_MAX (4294967295UL) +#define CFG_TDLS_TX_STATS_PERIOD_DEFAULT (2000) + +/* + * + * gMaxHTMCSForTxData - max HT mcs for TX + * @Min: 0 + * @Max: 383 + * @Default: 0 + * + * This ini is used to configure the max HT mcs + * for tx data. + * + * Usage: External + * + * bits 0-15: max HT mcs + * bits 16-31: zero to disable, otherwise enable. + * + * + */ +#define CFG_MAX_HT_MCS_FOR_TX_DATA "gMaxHTMCSForTxData" +#define CFG_MAX_HT_MCS_FOR_TX_DATA_MIN (WNI_CFG_MAX_HT_MCS_TX_DATA_STAMIN) +#define CFG_MAX_HT_MCS_FOR_TX_DATA_MAX (WNI_CFG_MAX_HT_MCS_TX_DATA_STAMAX) +#define CFG_MAX_HT_MCS_FOR_TX_DATA_DEFAULT (WNI_CFG_MAX_HT_MCS_TX_DATA_STADEF) + +/* + * + * gDisableABGRateForTxData - disable abg rate for tx data + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to disable abg rate for tx data. + * + * Usage: External + * + * + */ +#define CFG_DISABLE_ABG_RATE_FOR_TX_DATA "gDisableABGRateForTxData" +#define CFG_DISABLE_ABG_RATE_FOR_TX_DATA_MIN \ + (WNI_CFG_DISABLE_ABG_RATE_FOR_TX_DATA_STAMIN) +#define CFG_DISABLE_ABG_RATE_FOR_TX_DATA_MAX \ + (WNI_CFG_DISABLE_ABG_RATE_FOR_TX_DATA_STAMAX) +#define CFG_DISABLE_ABG_RATE_FOR_TX_DATA_DEFAULT \ + (WNI_CFG_DISABLE_ABG_RATE_FOR_TX_DATA_STADEF) + +/* + * + * gRateForTxMgmt - rate for tx mgmt frame + * @Min: 0x0 + * @Max: 0xFF + * @Default: 0xFF + * + * This ini is used to configure the rate for tx + * mgmt frame. Default 0xFF means disable. + * + * Usage: External + * + * + */ +#define CFG_RATE_FOR_TX_MGMT "gRateForTxMgmt" +#define CFG_RATE_FOR_TX_MGMT_MIN (WNI_CFG_RATE_FOR_TX_MGMT_STAMIN) +#define CFG_RATE_FOR_TX_MGMT_MAX (WNI_CFG_RATE_FOR_TX_MGMT_STAMAX) +#define CFG_RATE_FOR_TX_MGMT_DEFAULT (WNI_CFG_RATE_FOR_TX_MGMT_STADEF) + +/* + * + * gTDLSTxPacketThreshold - Tx/Rx Packet threshold for initiating TDLS. + * @Min: 0 + * @Max: 4294967295 + * @Default: 40 + * + * This ini is used to configure the number of Tx/Rx packets during the + * period of gTDLSTxStatsPeriod when exceeded, a TDLS Discovery request + * is triggered. + * Related: gEnableTDLSSupport. + * + * Supported Feature: TDLS + * + * Usage: Internal/External + * + * + */ +#define CFG_TDLS_TX_PACKET_THRESHOLD "gTDLSTxPacketThreshold" +#define CFG_TDLS_TX_PACKET_THRESHOLD_MIN (0) +#define CFG_TDLS_TX_PACKET_THRESHOLD_MAX (4294967295UL) +#define CFG_TDLS_TX_PACKET_THRESHOLD_DEFAULT (40) + +/* + * + * gTDLSMaxDiscoveryAttempt - Attempts for sending TDLS discovery requests. + * @Min: 1 + * @Max: 100 + * @Default: 5 + * + * This ini is used to configure the number of failures of discover request, + * when exceeded, the peer is assumed to be not TDLS capable and no further + * TDLS Discovery request is made. + * + * Related: gEnableTDLSSupport. + * + * Supported Feature: TDLS + * + * Usage: Internal/External + * + * + */ +#define CFG_TDLS_MAX_DISCOVERY_ATTEMPT "gTDLSMaxDiscoveryAttempt" +#define CFG_TDLS_MAX_DISCOVERY_ATTEMPT_MIN (1) +#define CFG_TDLS_MAX_DISCOVERY_ATTEMPT_MAX (100) +#define CFG_TDLS_MAX_DISCOVERY_ATTEMPT_DEFAULT (5) + +/* + * + * gTDLSIdleTimeout - Duration within which number of TX / RX frames meet the + * criteria for TDLS teardown. + * @Min: 500 + * @Max: 40000 + * @Default: 5000 + * + * This ini is used to configure the time period (in ms) to evaluate whether + * the number of Tx/Rx packets exceeds gTDLSIdlePacketThreshold and thus meets + * criteria for TDLS teardown. + * Teardown notification interval (gTDLSIdleTimeout) should be multiple of + * setup notification (gTDLSTxStatsPeriod) interval. + * e.g. + * if setup notification (gTDLSTxStatsPeriod) interval = 500, then + * teardown notification (gTDLSIdleTimeout) interval should be 1000, + * 1500, 2000, 2500... + * + * Related: gEnableTDLSSupport. + * + * Supported Feature: TDLS + * + * Usage: Internal/External + * + * + */ +#define CFG_TDLS_IDLE_TIMEOUT "gTDLSIdleTimeout" +#define CFG_TDLS_IDLE_TIMEOUT_MIN (500) +#define CFG_TDLS_IDLE_TIMEOUT_MAX (40000) +#define CFG_TDLS_IDLE_TIMEOUT_DEFAULT (5000) + + +/* + * + * gTDLSIdlePacketThreshold - Number of idle packet. + * @Min: 0 + * @Max: 40000 + * @Default: 3 + * + * This ini is used to configure the number of Tx/Rx packet, below which + * within last gTDLSTxStatsPeriod period is considered as idle condition. + * + * Related: gEnableTDLSSupport. + * + * Supported Feature: TDLS + * + * Usage: Internal/External + * + * + */ +#define CFG_TDLS_IDLE_PACKET_THRESHOLD "gTDLSIdlePacketThreshold" +#define CFG_TDLS_IDLE_PACKET_THRESHOLD_MIN (0) +#define CFG_TDLS_IDLE_PACKET_THRESHOLD_MAX (40000) +#define CFG_TDLS_IDLE_PACKET_THRESHOLD_DEFAULT (3) + +/* + * + * gTDLSRSSITriggerThreshold - RSSI threshold for TDLS connection. + * @Min: -120 + * @Max: 0 + * @Default: -75 + * + * This ini is used to configure the absolute value (in dB) of the peer RSSI, + * below which a TDLS setup request is triggered. + * + * Related: gEnableTDLSSupport. + * + * Supported Feature: TDLS + * + * Usage: Internal/External + * + * + */ +#define CFG_TDLS_RSSI_TRIGGER_THRESHOLD "gTDLSRSSITriggerThreshold" +#define CFG_TDLS_RSSI_TRIGGER_THRESHOLD_MIN (-120) +#define CFG_TDLS_RSSI_TRIGGER_THRESHOLD_MAX (0) +#define CFG_TDLS_RSSI_TRIGGER_THRESHOLD_DEFAULT (-75) + +/* + * + * gTDLSRSSITeardownThreshold - RSSI threshold for TDLS teardown. + * @Min: -120 + * @Max: 0 + * @Default: -75 + * + * This ini is used to configure the absolute value (in dB) of the peer RSSI, + * when exceed, a TDLS teardown is triggered. + * + * Related: gEnableTDLSSupport. + * + * Supported Feature: TDLS + * + * Usage: Internal/External + * + * + */ +#define CFG_TDLS_RSSI_TEARDOWN_THRESHOLD "gTDLSRSSITeardownThreshold" +#define CFG_TDLS_RSSI_TEARDOWN_THRESHOLD_MIN (-120) +#define CFG_TDLS_RSSI_TEARDOWN_THRESHOLD_MAX (0) +#define CFG_TDLS_RSSI_TEARDOWN_THRESHOLD_DEFAULT (-75) + +/* + * + * gTDLSRSSIDelta - Delta value for the peer RSSI that can trigger teardown. + * @Min: -30 + * @Max: 0 + * @Default: -20 + * + * This ini is used to . + * This ini is used to configure delta for peer RSSI such that if Peer RSSI + * is less than AP RSSI plus delta will trigger a teardown. + * + * Related: gEnableTDLSSupport. + * + * Supported Feature: TDLS + * + * Usage: Internal/External + * + * + */ +#define CFG_TDLS_RSSI_DELTA "gTDLSRSSIDelta" +#define CFG_TDLS_RSSI_DELTA_MIN (-30) +#define CFG_TDLS_RSSI_DELTA_MAX (0) +#define CFG_TDLS_RSSI_DELTA_DEFAULT (-20) + +/* + * + * gTDLSUapsdMask - ACs to setup U-APSD for TDLS Sta. + * @Min: 0 + * @Max: 0x0F + * @Default: 0x0F + * + * This ini is used to configure the ACs for which mask needs to be enabled. + * 0x1: Background 0x2: Best effort + * 0x4: Video 0x8:Voice + * + * Related: gEnableTDLSSupport. + * + * Supported Feature: TDLS + * + * Usage: Internal/External + * + * + */ +#define CFG_TDLS_QOS_WMM_UAPSD_MASK_NAME "gTDLSUapsdMask" +#define CFG_TDLS_QOS_WMM_UAPSD_MASK_MIN (0) +#define CFG_TDLS_QOS_WMM_UAPSD_MASK_MAX (0x0F) +#define CFG_TDLS_QOS_WMM_UAPSD_MASK_DEFAULT (0x0F) + +/* + * + * gEnableTDLSBufferSta - Controls the TDLS buffer. + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to control the TDLS buffer. + * Buffer STA is not enabled in CLD 2.0 yet. + * + * Related: gEnableTDLSSupport. + * + * Supported Feature: TDLS + * + * Usage: Internal/External + * + * + */ +#define CFG_TDLS_BUFFER_STA_SUPPORT_ENABLE "gEnableTDLSBufferSta" +#define CFG_TDLS_BUFFER_STA_SUPPORT_ENABLE_MIN (0) +#define CFG_TDLS_BUFFER_STA_SUPPORT_ENABLE_MAX (1) +#define CFG_TDLS_BUFFER_STA_SUPPORT_ENABLE_DEFAULT (1) + +/* + * + * gTDLSPuapsdInactivityTime - Peer UAPSD Inactivity time. + * @Min: 0 + * @Max: 10 + * @Default: 0 + * + * This ini is used to configure peer uapsd inactivity time. + * + * Related: gEnableTDLSSupport. + * + * Supported Feature: TDLS + * + * Usage: Internal/External + * + * + */ +#define CFG_TDLS_PUAPSD_INACTIVITY_TIME "gTDLSPuapsdInactivityTime" +#define CFG_TDLS_PUAPSD_INACTIVITY_TIME_MIN (0) +#define CFG_TDLS_PUAPSD_INACTIVITY_TIME_MAX (10) +#define CFG_TDLS_PUAPSD_INACTIVITY_TIME_DEFAULT (0) + +/* + * + * gTDLSPuapsdRxFrameThreshold - Peer UAPSD Rx frame threshold. + * @Min: 10 + * @Max: 20 + * @Default: 10 + * + * This ini is used to configure maximum Rx frame during SP. + * + * Related: gEnableTDLSSupport. + * + * Supported Feature: TDLS + * + * Usage: Internal/External + * + * + */ +#define CFG_TDLS_PUAPSD_RX_FRAME_THRESHOLD "gTDLSPuapsdRxFrameThreshold" +#define CFG_TDLS_PUAPSD_RX_FRAME_THRESHOLD_MIN (10) +#define CFG_TDLS_PUAPSD_RX_FRAME_THRESHOLD_MAX (20) +#define CFG_TDLS_PUAPSD_RX_FRAME_THRESHOLD_DEFAULT (10) + +/* + * + * gTDLSPuapsdPTIWindow - This ini is used to configure peer traffic indication + * window. + * @Min: 1 + * @Max: 5 + * @Default: 2 + * + * This ini is used to configure buffering time in number of beacon intervals. + * + * Related: gEnableTDLSSupport. + * + * Supported Feature: TDLS + * + * Usage: Internal/External + * + * + */ +#define CFG_TDLS_PUAPSD_PEER_TRAFFIC_IND_WINDOW "gTDLSPuapsdPTIWindow" +#define CFG_TDLS_PUAPSD_PEER_TRAFFIC_IND_WINDOW_MIN (1) +#define CFG_TDLS_PUAPSD_PEER_TRAFFIC_IND_WINDOW_MAX (5) +#define CFG_TDLS_PUAPSD_PEER_TRAFFIC_IND_WINDOW_DEFAULT (2) + +/* + * + * gTDLSPuapsdPTRTimeout - Peer Traffic Response timer duration in ms. + * @Min: 0 + * @Max: 10000 + * @Default: 5000 + * + * This ini is used to configure the peer traffic response timer duration + * in ms. + * + * Related: gEnableTDLSSupport. + * + * Supported Feature: TDLS + * + * Usage: Internal/External + * + * + */ +#define CFG_TDLS_PUAPSD_PEER_TRAFFIC_RSP_TIMEOUT "gTDLSPuapsdPTRTimeout" +#define CFG_TDLS_PUAPSD_PEER_TRAFFIC_RSP_TIMEOUT_MIN (0) +#define CFG_TDLS_PUAPSD_PEER_TRAFFIC_RSP_TIMEOUT_MAX (10000) +#define CFG_TDLS_PUAPSD_PEER_TRAFFIC_RSP_TIMEOUT_DEFAULT (5000) + +/* + * + * gTDLSExternalControl - Enable external TDLS control. + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to enable/disable external TDLS control. + * TDLS external control works with TDLS implicit trigger. TDLS external + * control allows a user to add a MAC address of potential TDLS peers so + * that the CLD driver can initiate implicit TDLS setup to only those peers + * when criteria for TDLS setup (throughput and RSSI threshold) is met. + * + * Related: gEnableTDLSSupport, gEnableTDLSImplicitTrigger. + * + * Supported Feature: TDLS + * + * Usage: Internal/External + * + * + */ +#define CFG_TDLS_EXTERNAL_CONTROL "gTDLSExternalControl" +#define CFG_TDLS_EXTERNAL_CONTROL_MIN (0) +#define CFG_TDLS_EXTERNAL_CONTROL_MAX (1) +#define CFG_TDLS_EXTERNAL_CONTROL_DEFAULT (1) + +/* + * + * gEnableTDLSOffChannel - Enables off-channel support for TDLS link. + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to enable/disable off-channel support for TDLS link. + * + * Related: gEnableTDLSSupport. + * + * Supported Feature: TDLS + * + * Usage: Internal/External + * + * + */ +#define CFG_TDLS_OFF_CHANNEL_SUPPORT_ENABLE "gEnableTDLSOffChannel" +#define CFG_TDLS_OFF_CHANNEL_SUPPORT_ENABLE_MIN (0) +#define CFG_TDLS_OFF_CHANNEL_SUPPORT_ENABLE_MAX (1) +#define CFG_TDLS_OFF_CHANNEL_SUPPORT_ENABLE_DEFAULT (0) + +/* + * + * gEnableTDLSWmmMode - Enables WMM support over TDLS link. + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to enable/disable WMM support over TDLS link. + * This is required to be set to 1 for any TDLS and uAPSD functionality. + * + * Related: gEnableTDLSSupport. + * + * Supported Feature: TDLS + * + * Usage: Internal/External + * + * + */ +#define CFG_TDLS_WMM_MODE_ENABLE "gEnableTDLSWmmMode" +#define CFG_TDLS_WMM_MODE_ENABLE_MIN (0) +#define CFG_TDLS_WMM_MODE_ENABLE_MAX (1) +#define CFG_TDLS_WMM_MODE_ENABLE_DEFAULT (1) + +/* + * + * gTDLSPrefOffChanNum - Preferred TDLS channel number when off-channel support + * is enabled. + * @Min: 1 + * @Max: 165 + * @Default: 36 + * + * This ini is used to configure preferred TDLS channel number when off-channel + * support is enabled. + * + * Related: gEnableTDLSSupport, gEnableTDLSOffChannel. + * + * Supported Feature: TDLS + * + * Usage: Internal/External + * + * + */ +#define CFG_TDLS_PREFERRED_OFF_CHANNEL_NUM "gTDLSPrefOffChanNum" +#define CFG_TDLS_PREFERRED_OFF_CHANNEL_NUM_MIN (1) +#define CFG_TDLS_PREFERRED_OFF_CHANNEL_NUM_MAX (165) +#define CFG_TDLS_PREFERRED_OFF_CHANNEL_NUM_DEFAULT (36) + +/* + * + * gTDLSPrefOffChanBandwidth - Preferred TDLS channel bandwidth when + * off-channel support is enabled. + * @Min: 0x01 + * @Max: 0x0F + * @Default: 0x07 + * + * This ini is used to configure preferred TDLS channel bandwidth when + * off-channel support is enabled. + * 0x1: 20 MHz 0x2: 40 MHz 0x4: 80 MHz 0x8: 160 MHz + * When more than one bits are set then firmware starts from the highest and + * selects one based on capability of peer. + * + * Related: gEnableTDLSSupport, gEnableTDLSOffChannel. + * + * Supported Feature: TDLS + * + * Usage: Internal/External + * + * + */ +#define CFG_TDLS_PREFERRED_OFF_CHANNEL_BW "gTDLSPrefOffChanBandwidth" +#define CFG_TDLS_PREFERRED_OFF_CHANNEL_BW_MIN (0x01) +#define CFG_TDLS_PREFERRED_OFF_CHANNEL_BW_MAX (0x0F) +#define CFG_TDLS_PREFERRED_OFF_CHANNEL_BW_DEFAULT (0x07) + +/* + * + * gEnableTDLSScan - Allow scan and maintain TDLS link. + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to enable/disable TDLS scan. + * 0: If peer is not buffer STA capable and device is not sleep STA + * capable, then teardown TDLS link when scan is initiated. If peer + * is buffer STA and we can be sleep STA then TDLS link is maintained + * during scan. + * 1: Maintain TDLS link and allow scan even if peer is not buffer STA + * capable and device is not sleep STA capable. There will be loss of + * Rx pkts since peer would not know when device moves away from tdls + * channel. Tx on TDLS link would stop when device moves away from tdls + * channel. + * + * Related: gEnableTDLSSupport. + * + * Supported Feature: TDLS + * + * Usage: Internal/External + * + * + */ +#define CFG_TDLS_SCAN_ENABLE "gEnableTDLSScan" +#define CFG_TDLS_SCAN_ENABLE_MIN (0) +#define CFG_TDLS_SCAN_ENABLE_MAX (1) +#define CFG_TDLS_SCAN_ENABLE_DEFAULT (0) + +/* + * + * gTDLSPeerKickoutThreshold - TDLS peer kickout threshold to firmware. + * @Min: 10 + * @Max: 5000 + * @Default: 96 + * + * This ini is used to configure TDLS peer kickout threshold to firmware. + * Firmware will use this value to determine, when to send TDLS + * peer kick out event to host. + * E.g. + * if peer kick out threshold is 10, then firmware will wait for 10 + * consecutive packet failures and then send TDLS kickout + * notification to host driver + * + * Related: gEnableTDLSSupport. + * + * Supported Feature: TDLS + * + * Usage: Internal/External + * + * + */ +#define CFG_TDLS_PEER_KICKOUT_THRESHOLD "gTDLSPeerKickoutThreshold" +#define CFG_TDLS_PEER_KICKOUT_THRESHOLD_MIN (10) +#define CFG_TDLS_PEER_KICKOUT_THRESHOLD_MAX (5000) +#define CFG_TDLS_PEER_KICKOUT_THRESHOLD_DEFAULT (96) + +#endif + +/* + * + * gTDLSEnableDeferTime - Timer to defer for enabling TDLS on P2P listen. + * @Min: 2000 + * @Max: 6000 + * @Default: 5000 + * + * This ini is used to set the timer to defer for enabling TDLS on P2P + * listen (value in milliseconds). + * + * Related: gEnableTDLSSupport. + * + * Supported Feature: TDLS + * + * Usage: Internal/External + * + * + */ +#define CFG_TDLS_ENABLE_DEFER_TIMER "gTDLSEnableDeferTime" +#define CFG_TDLS_ENABLE_DEFER_TIMER_MIN (2000) +#define CFG_TDLS_ENABLE_DEFER_TIMER_MAX (6000) +#define CFG_TDLS_ENABLE_DEFER_TIMER_DEFAULT (5000) + +/* Enable/Disable LPWR Image(cMEM uBSP) Transition */ +#define CFG_ENABLE_LPWR_IMG_TRANSITION_NAME "gEnableLpwrImgTransition" +#define CFG_ENABLE_LPWR_IMG_TRANSITION_MIN (0) +#define CFG_ENABLE_LPWR_IMG_TRANSITION_MAX (1) +#define CFG_ENABLE_LPWR_IMG_TRANSITION_DEFAULT (0) + +/* Config Param to enable the txLdpc capability + * 0 - disable + * 1 - HT LDPC enable + * 2 - VHT LDPC enable + * 3 - HT & VHT LDPC enable */ +#define CFG_TX_LDPC_ENABLE_FEATURE "gTxLdpcEnable" +#define CFG_TX_LDPC_ENABLE_FEATURE_MIN (0) +#define CFG_TX_LDPC_ENABLE_FEATURE_MAX (3) +#define CFG_TX_LDPC_ENABLE_FEATURE_DEFAULT (3) + +/* + * + * gEnableMCCAdaptiveScheduler - MCC Adaptive Scheduler feature. + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to enable/disable MCC Adaptive Scheduler feature. + * + * Related: None. + * + * Supported Feature: Concurrency + * + * Usage: Internal/External + * + * + */ +#define CFG_ENABLE_MCC_ADATIVE_SCHEDULER_ENABLED_NAME "gEnableMCCAdaptiveScheduler" +#define CFG_ENABLE_MCC_ADATIVE_SCHEDULER_ENABLED_MIN (0) +#define CFG_ENABLE_MCC_ADATIVE_SCHEDULER_ENABLED_MAX (1) +#define CFG_ENABLE_MCC_ADATIVE_SCHEDULER_ENABLED_DEFAULT (1) + +#define CFG_VHT_SU_BEAMFORMEE_CAP_FEATURE "gTxBFEnable" +#define CFG_VHT_SU_BEAMFORMEE_CAP_FEATURE_MIN (WNI_CFG_VHT_SU_BEAMFORMEE_CAP_STAMIN) +#define CFG_VHT_SU_BEAMFORMEE_CAP_FEATURE_MAX (WNI_CFG_VHT_SU_BEAMFORMEE_CAP_STAMAX) +#define CFG_VHT_SU_BEAMFORMEE_CAP_FEATURE_DEFAULT (WNI_CFG_VHT_SU_BEAMFORMEE_CAP_STADEF) + +/* + * Enable / Disable Tx beamformee in SAP mode + * Default: Disable + */ +#define CFG_VHT_ENABLE_TXBF_SAP_MODE "gEnableTxBFeeSAP" +#define CFG_VHT_ENABLE_TXBF_SAP_MODE_MIN (0) +#define CFG_VHT_ENABLE_TXBF_SAP_MODE_MAX (1) +#define CFG_VHT_ENABLE_TXBF_SAP_MODE_DEFAULT (0) + +#define CFG_VHT_CSN_BEAMFORMEE_ANT_SUPPORTED "gTxBFCsnValue" +#define CFG_VHT_CSN_BEAMFORMEE_ANT_SUPPORTED_MIN (WNI_CFG_VHT_CSN_BEAMFORMEE_ANT_SUPPORTED_STAMIN) +#define CFG_VHT_CSN_BEAMFORMEE_ANT_SUPPORTED_MAX (WNI_CFG_VHT_CSN_BEAMFORMEE_ANT_SUPPORTED_STAMAX - 1) +#define CFG_VHT_CSN_BEAMFORMEE_ANT_SUPPORTED_DEFAULT (WNI_CFG_VHT_CSN_BEAMFORMEE_ANT_SUPPORTED_STADEF - 1) + +#define CFG_VHT_ENABLE_TXBF_IN_20MHZ "gEnableTxBFin20MHz" +#define CFG_VHT_ENABLE_TXBF_IN_20MHZ_MIN (0) +#define CFG_VHT_ENABLE_TXBF_IN_20MHZ_MAX (1) +#define CFG_VHT_ENABLE_TXBF_IN_20MHZ_DEFAULT (0) + +#define CFG_VHT_ENABLE_TX_SU_BEAM_FORMER "gEnableTxSUBeamformer" +#define CFG_VHT_ENABLE_TX_SU_BEAM_FORMER_MIN (0) +#define CFG_VHT_ENABLE_TX_SU_BEAM_FORMER_MAX (1) +#define CFG_VHT_ENABLE_TX_SU_BEAM_FORMER_DEFAULT (0) + +/* Enable debug for remain on channel issues */ +#define CFG_DEBUG_P2P_REMAIN_ON_CHANNEL_NAME "gDebugP2pRemainOnChannel" +#define CFG_DEBUG_P2P_REMAIN_ON_CHANNEL_DEFAULT (0) +#define CFG_DEBUG_P2P_REMAIN_ON_CHANNEL_MIN (0) +#define CFG_DEBUG_P2P_REMAIN_ON_CHANNEL_MAX (1) + +/* + * SAP ALLOW All Channels + */ +#define CFG_SAP_ALLOW_ALL_CHANNEL_PARAM_NAME "gSapAllowAllChannel" +#define CFG_SAP_ALLOW_ALL_CHANNEL_PARAM_MIN (0) +#define CFG_SAP_ALLOW_ALL_CHANNEL_PARAM_MAX (1) +#define CFG_SAP_ALLOW_ALL_CHANNEL_PARAM_DEFAULT (0) + +#define CFG_DISABLE_LDPC_WITH_TXBF_AP "gDisableLDPCWithTxbfAP" +#define CFG_DISABLE_LDPC_WITH_TXBF_AP_MIN (0) +#define CFG_DISABLE_LDPC_WITH_TXBF_AP_MAX (1) +#define CFG_DISABLE_LDPC_WITH_TXBF_AP_DEFAULT (0) + +/* Parameter to control VHT support in 2.4 GHz band */ +#define CFG_ENABLE_VHT_FOR_24GHZ_NAME "gEnableVhtFor24GHzBand" +#define CFG_ENABLE_VHT_FOR_24GHZ_MIN (0) +#define CFG_ENABLE_VHT_FOR_24GHZ_MAX (1) +#define CFG_ENABLE_VHT_FOR_24GHZ_DEFAULT (0) + +/* + * Parameter to control VHT support based on vendor ie in 2.4 GHz band + * This parameter will enable SAP to read VHT capability in vendor ie in Assoc + * Req and send VHT caps in Resp to establish connection in VHT Mode. + */ +#define CFG_ENABLE_VENDOR_VHT_FOR_24GHZ_NAME "gEnableVendorVhtFor24GHzBand" +#define CFG_ENABLE_VENDOR_VHT_FOR_24GHZ_MIN (0) +#define CFG_ENABLE_VENDOR_VHT_FOR_24GHZ_MAX (1) +#define CFG_ENABLE_VENDOR_VHT_FOR_24GHZ_DEFAULT (1) + +/* + * + * gMaxMediumTime - Set Maximum channel time + * @Min: STAMIN + * @Max: STAMAX + * @Default: STADEF + * + * This ini is used to set default max channel time + * + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ + +#define CFG_MAX_MEDIUM_TIME "gMaxMediumTime" +#define CFG_MAX_MEDIUM_TIME_STAMIN WNI_CFG_MAX_MEDIUM_TIME_STAMIN +#define CFG_MAX_MEDIUM_TIME_STAMAX WNI_CFG_MAX_MEDIUM_TIME_STAMAX +#define CFG_MAX_MEDIUM_TIME_STADEFAULT WNI_CFG_MAX_MEDIUM_TIME_STADEF + +/* + * + * gEnableIbssHeartBeatOffload - Enable heart beat monitoring offload to FW + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to set default ibbs heartbeat offload + * + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ + +#define CFG_ENABLE_HEART_BEAT_OFFLOAD "gEnableIbssHeartBeatOffload" +#define CFG_ENABLE_HEART_BEAT_OFFLOAD_MIN (0) +#define CFG_ENABLE_HEART_BEAT_OFFLOAD_MAX (1) +#define CFG_ENABLE_HEART_BEAT_OFFLOAD_DEFAULT (1) + +/* + * + * gAntennaDiversity - It will use to set Antenna diversity + * @Min: 0 + * @Max: 3 + * @Default: 0 + * + * This ini is used to set default Antenna diversity + * + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ + +#define CFG_ANTENNA_DIVERSITY_PARAM_NAME "gAntennaDiversity" +#define CFG_ANTENNA_DIVERSITY_PARAM_MIN (0) +#define CFG_ANTENNA_DIVERSITY_PARAM_MAX (3) +#define CFG_ANTENNA_DIVERSITY_PARAM_DEFAULT (0) + +/* + * + * gEnableSNRMonitoring - Enables SNR Monitoring + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to set default snr monitor + * + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ + +#define CFG_ENABLE_SNR_MONITORING_NAME "gEnableSNRMonitoring" +#define CFG_ENABLE_SNR_MONITORING_MIN (0) +#define CFG_ENABLE_SNR_MONITORING_MAX (1) +#define CFG_ENABLE_SNR_MONITORING_DEFAULT (0) + +/* + * + * gMaxAmsduNum - Max number of MSDU's in aggregate + * @Min: 0 + * @Max: 3 + * @Default: 1 + * gMaxAmsduNum is the number of MSDU's transmitted in the 11n aggregate + * frame. Setting it to a value larger than 1 enables transmit aggregation. + * It is a PHY parameter that applies to all vdev's in firmware. + * + * Supported Feature: 11n aggregation + * + * Usage: Internal + * + * + */ +#define CFG_MAX_AMSDU_NUM_NAME "gMaxAmsduNum" +#define CFG_MAX_AMSDU_NUM_MIN (0) +#define CFG_MAX_AMSDU_NUM_MAX (3) +#define CFG_MAX_AMSDU_NUM_DEFAULT (1) + +/* + * + * gEnableIpTcpUdpChecksumOffload - It enables IP, TCP and UDP checksum + * offload in hardware + * @Min: 0 + * @Max: 1 + * @Default: DEF + * + * This ini is used to enable IP, TCP and UDP checksum offload in hardware + * and also advertise same to network stack + * + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ + +#define CFG_ENABLE_IP_TCP_UDP_CHKSUM_OFFLOAD "gEnableIpTcpUdpChecksumOffload" +#define CFG_ENABLE_IP_TCP_UDP_CHKSUM_OFFLOAD_DISABLE (0) +#define CFG_ENABLE_IP_TCP_UDP_CHKSUM_OFFLOAD_ENABLE (1) +#define CFG_ENABLE_IP_TCP_UDP_CHKSUM_OFFLOAD_DEFAULT (CFG_ENABLE_IP_TCP_UDP_CHKSUM_OFFLOAD_ENABLE) + +#ifdef WLAN_FEATURE_FASTPATH + +/* + * + * gEnableFastPath - Control to enable fastpath feature + * + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to enable fastpath feature + * + * Supported Feature: Wlan Fastpath Feature + * + * Usage: Internal + * + * + */ +#define CFG_ENABLE_FASTPATH "gEnableFastPath" +#define CFG_ENABLE_FASTPATH_MIN (0) +#define CFG_ENABLE_FASTPATH_MAX (1) +#define CFG_ENABLE_FASTPATH_DEFAULT (CFG_ENABLE_FASTPATH_MIN) +#endif /* WLAN_FEATURE_FASTPATH */ + +/* + * IPA Offload configuration - Each bit enables a feature + * bit0 - IPA Enable + * bit1 - IPA Pre filter enable + * bit2 - IPv6 enable + * bit3 - IPA Resource Manager (RM) enable + * bit4 - IPA Clock scaling enable + */ +#define CFG_IPA_OFFLOAD_CONFIG_NAME "gIPAConfig" +#define CFG_IPA_OFFLOAD_CONFIG_MIN (0) +#define CFG_IPA_OFFLOAD_CONFIG_MAX (0xFFFFFFFF) +#define CFG_IPA_OFFLOAD_CONFIG_DEFAULT (CFG_IPA_OFFLOAD_CONFIG_MIN) + +/* + * IPA DESC SIZE + */ +#define CFG_IPA_DESC_SIZE_NAME "gIPADescSize" +#define CFG_IPA_DESC_SIZE_MIN (800) +#define CFG_IPA_DESC_SIZE_MAX (8000) +#define CFG_IPA_DESC_SIZE_DEFAULT (800) + +#define CFG_IPA_HIGH_BANDWIDTH_MBPS "gIPAHighBandwidthMbps" +#define CFG_IPA_HIGH_BANDWIDTH_MBPS_MIN (200) +#define CFG_IPA_HIGH_BANDWIDTH_MBPS_MAX (1000) +#define CFG_IPA_HIGH_BANDWIDTH_MBPS_DEFAULT (400) + +#define CFG_IPA_MEDIUM_BANDWIDTH_MBPS "gIPAMediumBandwidthMbps" +#define CFG_IPA_MEDIUM_BANDWIDTH_MBPS_MIN (100) +#define CFG_IPA_MEDIUM_BANDWIDTH_MBPS_MAX (400) +#define CFG_IPA_MEDIUM_BANDWIDTH_MBPS_DEFAULT (200) + +#define CFG_IPA_LOW_BANDWIDTH_MBPS "gIPALowBandwidthMbps" +#define CFG_IPA_LOW_BANDWIDTH_MBPS_MIN (0) +#define CFG_IPA_LOW_BANDWIDTH_MBPS_MAX (100) +#define CFG_IPA_LOW_BANDWIDTH_MBPS_DEFAULT (100) + +/* + * Firmware uart print + */ +#define CFG_ENABLE_FW_UART_PRINT_NAME "gEnablefwprint" +#define CFG_ENABLE_FW_UART_PRINT_DISABLE (0) +#define CFG_ENABLE_FW_UART_PRINT_ENABLE (1) +#define CFG_ENABLE_FW_UART_PRINT_DEFAULT (CFG_ENABLE_FW_UART_PRINT_DISABLE) + +/* + * Firmware log + */ +#define CFG_ENABLE_FW_LOG_NAME "gEnablefwlog" +#define CFG_ENABLE_FW_LOG_DISABLE (0) +#define CFG_ENABLE_FW_LOG_WMI (1) +#define CFG_ENABLE_FW_LOG_DIAG (2) +#define CFG_ENABLE_FW_LOG_MIN (CFG_ENABLE_FW_LOG_DISABLE) +#define CFG_ENABLE_FW_LOG_MAX (CFG_ENABLE_FW_LOG_DIAG) +#define CFG_ENABLE_FW_LOG_DEFAULT (CFG_ENABLE_FW_LOG_WMI) + +/* + * + * gEnableFwSelfRecovery - Enable/disable FW self-recovery for USB + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to enable/disable FW self-recovery + * gEnableFwSelfRecovery = 0: Disabled + * gEnableFwSelfRecovery = 1: Driver triggers SSR instead of triggering + * kernel panic after firmware crash. + * + * Related: gEnableSSR + * + * Supported Feature: SSR + * + * Usage: Internal/External + * + * + */ + +#define CFG_ENABLE_FW_SELF_RECOVERY_NAME "gEnableFwSelfRecovery" +#define CFG_ENABLE_FW_SELF_RECOVERY_DISABLE (0) +#define CFG_ENABLE_FW_SELF_RECOVERY_ENABLE (1) +#define CFG_ENABLE_FW_SELF_RECOVERY_DEFAULT (CFG_ENABLE_FW_SELF_RECOVERY_DISABLE) + +/* Macro to handle maximum receive AMPDU size configuration */ +#define CFG_VHT_AMPDU_LEN_EXPONENT_NAME "gVhtAmpduLenExponent" +#define CFG_VHT_AMPDU_LEN_EXPONENT_MIN (0) +#define CFG_VHT_AMPDU_LEN_EXPONENT_MAX (7) +#define CFG_VHT_AMPDU_LEN_EXPONENT_DEFAULT (3) + +#define CFG_VHT_MPDU_LEN_NAME "gVhtMpduLen" +#define CFG_VHT_MPDU_LEN_MIN (0) +#define CFG_VHT_MPDU_LEN_MAX (2) +#define CFG_VHT_MPDU_LEN_DEFAULT (0) + +#define CFG_SAP_MAX_NO_PEERS "gSoftApMaxPeers" +#define CFG_SAP_MAX_NO_PEERS_MIN (1) +#define CFG_SAP_MAX_NO_PEERS_MAX (32) +#define CFG_SAP_MAX_NO_PEERS_DEFAULT (32) + +/* + * + * gEnableDebugLog - Enable/Disable the Connection related logs + * @Min: 0 + * @Max: 0xFF + * @Default: 0x0F + * + * This ini is used to enable/disable the connection related logs + * 0x1 - Enable mgmt pkt logs (excpet probe req/rsp, beacons). + * 0x2 - Enable EAPOL pkt logs. + * 0x4 - Enable DHCP pkt logs. + * 0x8 - Enable mgmt action frames logs. + * 0x0 - Disable all the above connection related logs. + * The default value of 0x0F will enable all the above logs + * + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ + +#define CFG_ENABLE_DEBUG_CONNECT_ISSUE "gEnableDebugLog" +#define CFG_ENABLE_DEBUG_CONNECT_ISSUE_MIN (0) +#define CFG_ENABLE_DEBUG_CONNECT_ISSUE_MAX (0xFF) +#define CFG_ENABLE_DEBUG_CONNECT_ISSUE_DEFAULT (0x0F) + +/* SAR Thermal limit values for 2g and 5g */ + +#define CFG_SET_TXPOWER_LIMIT2G_NAME "TxPower2g" +#define CFG_SET_TXPOWER_LIMIT2G_MIN (0) +#define CFG_SET_TXPOWER_LIMIT2G_MAX (30) +#define CFG_SET_TXPOWER_LIMIT2G_DEFAULT (30) + +#define CFG_SET_TXPOWER_LIMIT5G_NAME "TxPower5g" +#define CFG_SET_TXPOWER_LIMIT5G_MIN (0) +#define CFG_SET_TXPOWER_LIMIT5G_MAX (30) +#define CFG_SET_TXPOWER_LIMIT5G_DEFAULT (30) + +#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL + +/* + * + * TxFlowLowWaterMark - Low watermark for pausing network queues + * + * @Min: 0 + * @Max: 1000 + * @Default: 300 + * + * This ini specifies the low watermark of data packets transmitted + * before pausing netif queues in tx flow path. It is only applicable + * where legacy flow control is used i.e.for Rome. + * + * Related: TxFlowHighWaterMarkOffset, TxFlowMaxQueueDepth, + * TxLbwFlowLowWaterMark, TxLbwFlowHighWaterMarkOffset, + * TxLbwFlowMaxQueueDepth, TxHbwFlowLowWaterMark, + * TxHbwFlowHighWaterMarkOffset, TxHbwFlowMaxQueueDepth + * + * Supported Feature: Dynamic Flow Control + * + * Usage: Internal + * + * + */ +#define CFG_LL_TX_FLOW_LWM "TxFlowLowWaterMark" +#define CFG_LL_TX_FLOW_LWM_MIN (0) +#define CFG_LL_TX_FLOW_LWM_MAX (1000) +#define CFG_LL_TX_FLOW_LWM_DEFAULT (300) + +/* + * + * TxFlowHighWaterMarkOffset - High Watermark offset to unpause Netif queues + * @Min: 0 + * @Max: 300 + * @Default: 94 + * + * This ini specifies the offset to upause the netif queues + * when they are paused due to insufficient descriptors as guided by + * ini TxFlowLowWaterMark. It is only applicable where legacy flow control + * is used i.e.for Rome. + * + * Related: TxFlowLowWaterMark, TxFlowMaxQueueDepth, + * TxLbwFlowLowWaterMark, TxLbwFlowHighWaterMarkOffset, + * TxLbwFlowMaxQueueDepth, TxHbwFlowLowWaterMark, + * TxHbwFlowHighWaterMarkOffset, TxHbwFlowMaxQueueDepth + * + * Supported Feature: Dynamic Flow Control + * + * Usage: Internal + * + * + */ +#define CFG_LL_TX_FLOW_HWM_OFFSET "TxFlowHighWaterMarkOffset" +#define CFG_LL_TX_FLOW_HWM_OFFSET_MIN (0) +#define CFG_LL_TX_FLOW_HWM_OFFSET_MAX (300) +#define CFG_LL_TX_FLOW_HWM_OFFSET_DEFAULT (94) + +/* + * + * TxFlowMaxQueueDepth - Max pause queue depth. + * + * @Min: 400 + * @Max: 3500 + * @Default: 1500 + * + * This ini specifies the max queue pause depth.It is only applicable + * where legacy flow control is used i.e.for Rome. + * + * Related: TxFlowLowWaterMark, TxFlowHighWaterMarkOffset, + * TxLbwFlowLowWaterMark, TxLbwFlowHighWaterMarkOffset, + * TxLbwFlowMaxQueueDepth, TxHbwFlowLowWaterMark, + * TxHbwFlowHighWaterMarkOffset, TxHbwFlowMaxQueueDepth + * + * Supported Feature: Dynamic Flow Control + * + * Usage: Internal + * + * + */ +#define CFG_LL_TX_FLOW_MAX_Q_DEPTH "TxFlowMaxQueueDepth" +#define CFG_LL_TX_FLOW_MAX_Q_DEPTH_MIN (400) +#define CFG_LL_TX_FLOW_MAX_Q_DEPTH_MAX (3500) +#define CFG_LL_TX_FLOW_MAX_Q_DEPTH_DEFAULT (1500) + +/* + * + * TxLbwFlowLowWaterMark - Low watermark for pausing network queues + * in low bandwidth band + * @Min: 0 + * @Max: 1000 + * @Default: 450 + * + * This ini specifies the low watermark of data packets transmitted + * before pausing netif queues in tx flow path in low bandwidth band. + * It is only applicable where legacy flow control is used i.e.for Rome. + * + * Related: TxFlowLowWaterMark, TxFlowHighWaterMarkOffset, + * TxFlowMaxQueueDepth, TxLbwFlowHighWaterMarkOffset, + * TxLbwFlowMaxQueueDepth, TxHbwFlowLowWaterMark, + * TxHbwFlowHighWaterMarkOffset, TxHbwFlowMaxQueueDepth + * + * Supported Feature: Dynamic Flow Control + * + * Usage: Internal + * + * + */ +#define CFG_LL_TX_LBW_FLOW_LWM "TxLbwFlowLowWaterMark" +#define CFG_LL_TX_LBW_FLOW_LWM_MIN (0) +#define CFG_LL_TX_LBW_FLOW_LWM_MAX (1000) +#define CFG_LL_TX_LBW_FLOW_LWM_DEFAULT (450) + +/* + * + * TxLbwFlowHighWaterMarkOffset - High Watermark offset to unpause Netif queues + * in low bandwidth band. + * @Min: 0 + * @Max: 300 + * @Default: 50 + * + * This ini specifies the offset to upause the netif queues + * when they are paused due to insufficient descriptors as guided by + * ini TxLbwFlowLowWaterMark in low bandwidth band. It is only applicable + * where legacy flow control is used i.e.for Rome. + * + * Related: TxFlowLowWaterMark, TxFlowHighWaterMarkOffset, + * TxFlowMaxQueueDepth, TxLbwFlowLowWaterMark, + * TxLbwFlowMaxQueueDepth, TxHbwFlowLowWaterMark, + * TxHbwFlowHighWaterMarkOffset, TxHbwFlowMaxQueueDepth + * + * Supported Feature: Dynamic Flow Control + * + * Usage: Internal + * + * + */ +#define CFG_LL_TX_LBW_FLOW_HWM_OFFSET "TxLbwFlowHighWaterMarkOffset" +#define CFG_LL_TX_LBW_FLOW_HWM_OFFSET_MIN (0) +#define CFG_LL_TX_LBW_FLOW_HWM_OFFSET_MAX (300) +#define CFG_LL_TX_LBW_FLOW_HWM_OFFSET_DEFAULT (50) + +/* + * + * TxLbwFlowMaxQueueDepth - Max pause queue depth in low bandwidth band + * + * @Min: 400 + * @Max: 3500 + * @Default: 750 + * + * This ini specifies the max queue pause depth in low bandwidth band. + * It is only applicable where legacy flow control is used i.e.for Rome. + * + * Related: TxFlowLowWaterMark, TxFlowHighWaterMarkOffset, + * TxFlowMaxQueueDepth, TxLbwFlowLowWaterMark, + * TxLbwFlowHighWaterMarkOffset, TxHbwFlowLowWaterMark, + * TxHbwFlowHighWaterMarkOffset, TxHbwFlowMaxQueueDepth + * + * Supported Feature: Dynamic Flow Control + * + * Usage: Internal + * + * + */ +#define CFG_LL_TX_LBW_FLOW_MAX_Q_DEPTH "TxLbwFlowMaxQueueDepth" +#define CFG_LL_TX_LBW_FLOW_MAX_Q_DEPTH_MIN (400) +#define CFG_LL_TX_LBW_FLOW_MAX_Q_DEPTH_MAX (3500) +#define CFG_LL_TX_LBW_FLOW_MAX_Q_DEPTH_DEFAULT (750) + +/* + * + * TxHbwFlowLowWaterMark - Low watermark for pausing network queues + * in high bandwidth band + * @Min: 0 + * @Max: 1000 + * @Default: 406 + * + * This ini specifies the threshold of data packets transmitted + * before pausing netif queues.It is only applicable where + * legacy flow control is used i.e.for Rome. + * + * Related: TxFlowLowWaterMark, TxFlowHighWaterMarkOffset, + * TxFlowMaxQueueDepth, TxLbwFlowLowWaterMark, + * TxLbwFlowHighWaterMarkOffset, TxLbwFlowMaxQueueDepth, + * TxHbwFlowHighWaterMarkOffset, TxHbwFlowMaxQueueDepth + * + * Supported Feature: Dynamic Flow Control + * + * Usage: Internal + * + * + */ +#define CFG_LL_TX_HBW_FLOW_LWM "TxHbwFlowLowWaterMark" +#define CFG_LL_TX_HBW_FLOW_LWM_MIN (0) +#define CFG_LL_TX_HBW_FLOW_LWM_MAX (1000) +#define CFG_LL_TX_HBW_FLOW_LWM_DEFAULT (406) + +/* + * + * TxHbwFlowHighWaterMarkOffset - High Watermark offset to unpause Netif queues + * in high bandwidth band. + * @Min: 0 + * @Max: 300 + * @Default: 94 + * + * This ini specifies the offset to upause the netif queues + * when they are paused due to insufficient descriptors as guided by + * ini TxHbwFlowLowWaterMark in high bandwidth band. It is only applicable + * where legacy flow control is used i.e.for Rome. + * + * Related: TxFlowLowWaterMark, TxFlowHighWaterMarkOffset, + * TxFlowMaxQueueDepth, TxLbwFlowLowWaterMark, + * TxLbwFlowHighWaterMarkOffset, TxLbwFlowMaxQueueDepth, + * TxHbwFlowLowWaterMark, TxHbwFlowMaxQueueDepth + * + * Supported Feature: Dynamic Flow Control + * + * Usage: Internal + * + * + */ +#define CFG_LL_TX_HBW_FLOW_HWM_OFFSET "TxHbwFlowHighWaterMarkOffset" +#define CFG_LL_TX_HBW_FLOW_HWM_OFFSET_MIN (0) +#define CFG_LL_TX_HBW_FLOW_HWM_OFFSET_MAX (300) +#define CFG_LL_TX_HBW_FLOW_HWM_OFFSET_DEFAULT (94) + +/* + * + * TxHbwFlowMaxQueueDepth - Max pause queue depth in high bandwidth band + * @Min: 4000 + * @Max: 3500 + * @Default: 1500 + * + * This ini specifies the max queue pause depth in high bandwidth band. + * It is only applicable where legacy flow control is used i.e.for Rome. + * + * Related: TxFlowLowWaterMark, TxFlowHighWaterMarkOffset, + * TxFlowMaxQueueDepth, TxLbwFlowLowWaterMark, + * TxLbwFlowHighWaterMarkOffset, TxLbwFlowMaxQueueDepth, + * TxHbwFlowLowWaterMark, TxHbwFlowHighWaterMarkOffset + * + * Supported Feature: Dynamic Flow Control + * + * Usage: Internal + * + * + */ +#define CFG_LL_TX_HBW_FLOW_MAX_Q_DEPTH "TxHbwFlowMaxQueueDepth" +#define CFG_LL_TX_HBW_FLOW_MAX_Q_DEPTH_MIN (400) +#define CFG_LL_TX_HBW_FLOW_MAX_Q_DEPTH_MAX (3500) +#define CFG_LL_TX_HBW_FLOW_MAX_Q_DEPTH_DEFAULT (1500) +#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */ + +#ifdef QCA_LL_TX_FLOW_CONTROL_V2 + +/* + * + * TxFlowStopQueueThreshold - Stop queue Threshold to pause + * Netif queues when it reaches + * @Min: 0 + * @Max: 50 + * @Default: 15 + * + * This ini specifies the threshold of data packets transmitted + * before pausing netif queues. + * + * Related: TxFlowStartQueueOffset + * + * Supported Feature: Dynamic Flow Control + * + * Usage: Internal + * + * + */ +#define CFG_LL_TX_FLOW_STOP_QUEUE_TH "TxFlowStopQueueThreshold" +#define CFG_LL_TX_FLOW_STOP_QUEUE_TH_DEFAULT (15) +#define CFG_LL_TX_FLOW_STOP_QUEUE_TH_MIN (0) +#define CFG_LL_TX_FLOW_STOP_QUEUE_TH_MAX (50) + +/* + * + * TxFlowStartQueueOffset - Start queue offset to unpause + * Netif queues + * @Min: 0 + * @Max: 30 + * @Default: 11 + * + * This ini specifies the offset to upause the netif queues + * when they are paused due to insufficient descriptors as guided by + * ini TxFlowStopQueueThreshold. + * + * Related: TxFlowStopQueueThreshold + * + * Supported Feature: Dynamic Flow Control + * + * Usage: Internal + * + * + */ +#define CFG_LL_TX_FLOW_START_QUEUE_OFFSET "TxFlowStartQueueOffset" +#define CFG_LL_TX_FLOW_START_QUEUE_OFFSET_DEFAULT (10) +#define CFG_LL_TX_FLOW_START_QUEUE_OFFSET_MIN (0) +#define CFG_LL_TX_FLOW_START_QUEUE_OFFSET_MAX (30) + +#endif /* QCA_LL_TX_FLOW_CONTROL_V2 */ + +#define CFG_SAP_MAX_OFFLOAD_PEERS "gMaxOffloadPeers" +#define CFG_SAP_MAX_OFFLOAD_PEERS_MIN (2) +#define CFG_SAP_MAX_OFFLOAD_PEERS_MAX (5) +#define CFG_SAP_MAX_OFFLOAD_PEERS_DEFAULT (2) + +#define CFG_SAP_MAX_OFFLOAD_REORDER_BUFFS "gMaxOffloadReorderBuffs" +#define CFG_SAP_MAX_OFFLOAD_REORDER_BUFFS_MIN (0) +#define CFG_SAP_MAX_OFFLOAD_REORDER_BUFFS_MAX (3) +#define CFG_SAP_MAX_OFFLOAD_REORDER_BUFFS_DEFAULT (2) + +#ifdef FEATURE_WLAN_RA_FILTERING +#define CFG_RA_FILTER_ENABLE_NAME "gRAFilterEnable" +#define CFG_RA_FILTER_ENABLE_MIN (0) +#define CFG_RA_FILTER_ENABLE_MAX (1) +#define CFG_RA_FILTER_ENABLE_DEFAULT (1) + +#define CFG_RA_RATE_LIMIT_INTERVAL_NAME "gRArateLimitInterval" +#define CFG_RA_RATE_LIMIT_INTERVAL_MIN (60) +#define CFG_RA_RATE_LIMIT_INTERVAL_MAX (3600) +#define CFG_RA_RATE_LIMIT_INTERVAL_DEFAULT (60) /*60 SEC */ +#endif + +/* + * + * gIgnorePeerErpInfo - Used for ignore peer infrormation + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to ignore default peer info + * + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ + +#define CFG_IGNORE_PEER_ERP_INFO_NAME "gIgnorePeerErpInfo" +#define CFG_IGNORE_PEER_ERP_INFO_MIN (0) +#define CFG_IGNORE_PEER_ERP_INFO_MAX (1) +#define CFG_IGNORE_PEER_ERP_INFO_DEFAULT (0) + +/* + * + * gEnableMemoryDebug - Enables the memory debug + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to enable default memory debug + * + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ + +#ifdef MEMORY_DEBUG +#define CFG_ENABLE_MEMORY_DEBUG_NAME "gEnableMemoryDebug" +#define CFG_ENABLE_MEMORY_DEBUG_MIN (0) +#define CFG_ENABLE_MEMORY_DEBUG_MAX (1) +#define CFG_ENABLE_MEMORY_DEBUG_DEFAULT (1) +#endif + + +/* + * + * gInitialDwellTime - Used to set initial dwell time + * @Min: 0 + * @Max: 0 + * @Default: 100 + * + * This ini is used to set default initial dwell time + * + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ + +#define CFG_INITIAL_DWELL_TIME_NAME "gInitialDwellTime" +#define CFG_INITIAL_DWELL_TIME_DEFAULT (0) +#define CFG_INITIAL_DWELL_TIME_MIN (0) +#define CFG_INITIAL_DWELL_TIME_MAX (100) + +/* + * + * gInitialScanNoDFSChnl - WLAN skips scanning the DFS channels + * @Min: 0 + * @Max: 0 + * @Default: 1 + * + * This ini is used to set for the first scan after driver + * + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ + +#define CFG_INITIAL_SCAN_NO_DFS_CHNL_NAME "gInitialScanNoDFSChnl" +#define CFG_INITIAL_SCAN_NO_DFS_CHNL_DEFAULT (0) +#define CFG_INITIAL_SCAN_NO_DFS_CHNL_MIN (0) +#define CFG_INITIAL_SCAN_NO_DFS_CHNL_MAX (1) + +/* + * + * gAllowDFSChannelRoam - Allow dfs channel in roam + * @Min: 0 + * @Max: 1 + * @Default: 2 + * + * This ini is used to set default dfs channel + * + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ + +#define CFG_ROAMING_DFS_CHANNEL_NAME "gAllowDFSChannelRoam" +#define CFG_ROAMING_DFS_CHANNEL_DISABLED (0) +#define CFG_ROAMING_DFS_CHANNEL_ENABLED_NORMAL (1) +#define CFG_ROAMING_DFS_CHANNEL_ENABLED_ACTIVE (2) +#define CFG_ROAMING_DFS_CHANNEL_MIN (CFG_ROAMING_DFS_CHANNEL_DISABLED) +#define CFG_ROAMING_DFS_CHANNEL_MAX (CFG_ROAMING_DFS_CHANNEL_ENABLED_ACTIVE) +#define CFG_ROAMING_DFS_CHANNEL_DEFAULT (CFG_ROAMING_DFS_CHANNEL_DISABLED) + +#ifdef MSM_PLATFORM +#define CFG_BUS_BANDWIDTH_HIGH_THRESHOLD "gBusBandwidthHighThreshold" +#define CFG_BUS_BANDWIDTH_HIGH_THRESHOLD_DEFAULT (2000) +#define CFG_BUS_BANDWIDTH_HIGH_THRESHOLD_MIN (0) +#define CFG_BUS_BANDWIDTH_HIGH_THRESHOLD_MAX (4294967295UL) + +#define CFG_BUS_BANDWIDTH_MEDIUM_THRESHOLD "gBusBandwidthMediumThreshold" +#define CFG_BUS_BANDWIDTH_MEDIUM_THRESHOLD_DEFAULT (500) +#define CFG_BUS_BANDWIDTH_MEDIUM_THRESHOLD_MIN (0) +#define CFG_BUS_BANDWIDTH_MEDIUM_THRESHOLD_MAX (4294967295UL) + +#define CFG_BUS_BANDWIDTH_LOW_THRESHOLD "gBusBandwidthLowThreshold" +#define CFG_BUS_BANDWIDTH_LOW_THRESHOLD_DEFAULT (150) +#define CFG_BUS_BANDWIDTH_LOW_THRESHOLD_MIN (0) +#define CFG_BUS_BANDWIDTH_LOW_THRESHOLD_MAX (4294967295UL) + +#define CFG_BUS_BANDWIDTH_COMPUTE_INTERVAL "gBusBandwidthComputeInterval" +#define CFG_BUS_BANDWIDTH_COMPUTE_INTERVAL_DEFAULT (100) +#define CFG_BUS_BANDWIDTH_COMPUTE_INTERVAL_MIN (0) +#define CFG_BUS_BANDWIDTH_COMPUTE_INTERVAL_MAX (10000) +/* + * + * gTcpAdvWinScaleEnable - Control to enable TCP adv window scaling + * @Min: -0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to enable dynamic configuration of TCP adv window scaling system parameter. + * + * Supported Feature: Tcp Advance Window Scaling + * + * Usage: Internal + * + * + */ +#define CFG_ENABLE_TCP_ADV_WIN_SCALE "gTcpAdvWinScaleEnable" +#define CFG_ENABLE_TCP_ADV_WIN_SCALE_DEFAULT (1) +#define CFG_ENABLE_TCP_ADV_WIN_SCALE_MIN (0) +#define CFG_ENABLE_TCP_ADV_WIN_SCALE_MAX (1) + +/* + * + * gTcpDelAckEnable - Control to enable Dynamic Configuration of Tcp Delayed Ack + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to enable Dynamic Configuration of Tcp Delayed Ack + * + * Related: gTcpDelAckThresholdHigh, gTcpDelAckThresholdLow, + * gTcpDelAckTimerCount + * + * Supported Feature: Tcp Delayed Ack + * + * Usage: Internal + * + * + */ +#define CFG_ENABLE_TCP_DELACK "gTcpDelAckEnable" +#define CFG_ENABLE_TCP_DELACK_DEFAULT (1) +#define CFG_ENABLE_TCP_DELACK_MIN (0) +#define CFG_ENABLE_TCP_DELACK_MAX (1) + + +/* + * + * gTcpDelAckThresholdHigh - High Threshold inorder to trigger TCP Del Ack + * indication + * @Min: 0 + * @Max: 16000 + * @Default: 500 + * + * This ini is used to mention the High Threshold inorder to trigger TCP Del Ack + * indication i.e the threshold of packets received over a period of 100 ms. + * i.e to have a low RX throughput requirement + * Related: gTcpDelAckEnable, gTcpDelAckThresholdLow, gTcpDelAckTimerCount + * + * Supported Feature: Tcp Delayed Ack + * + * Usage: Internal + * + * + */ +#define CFG_TCP_DELACK_THRESHOLD_HIGH "gTcpDelAckThresholdHigh" +#define CFG_TCP_DELACK_THRESHOLD_HIGH_DEFAULT (500) +#define CFG_TCP_DELACK_THRESHOLD_HIGH_MIN (0) +#define CFG_TCP_DELACK_THRESHOLD_HIGH_MAX (16000) + +/* + * + * gTcpDelAckThresholdLow - Low Threshold inorder to trigger TCP Del Ack + * indication + * @Min: 0 + * @Max: 10000 + * @Default: 1000 + * + * This ini is used to mention the Low Threshold inorder to trigger TCP Del Ack + * indication i.e the threshold of packets received over a period of 100 ms. + * i.e to have a low RX throughput requirement + * + * Related: gTcpDelAckEnable, gTcpDelAckThresholdHigh, gTcpDelAckTimerCount + * + * Supported Feature: Tcp Delayed Ack + * + * Usage: Internal + * + * + */ +#define CFG_TCP_DELACK_THRESHOLD_LOW "gTcpDelAckThresholdLow" +#define CFG_TCP_DELACK_THRESHOLD_LOW_DEFAULT (1000) +#define CFG_TCP_DELACK_THRESHOLD_LOW_MIN (0) +#define CFG_TCP_DELACK_THRESHOLD_LOW_MAX (10000) + +/* + * + * gTcpDelAckTimerCount - Del Ack Timer Count inorder to trigger TCP Del Ack + * indication + * @Min: 1 + * @Max: 1000 + * @Default: 30 + * + * This ini is used to mention the Del Ack Timer Count inorder to + * trigger TCP Del Ack indication i.e number of 100 ms periods + * + * Related: gTcpDelAckEnable, gTcpDelAckThresholdHigh, gTcpDelAckThresholdLow + * + * Supported Feature: Tcp Delayed Ack + * + * Usage: Internal + * + * + */ +#define CFG_TCP_DELACK_TIMER_COUNT "gTcpDelAckTimerCount" +#define CFG_TCP_DELACK_TIMER_COUNT_DEFAULT (30) +#define CFG_TCP_DELACK_TIMER_COUNT_MIN (1) +#define CFG_TCP_DELACK_TIMER_COUNT_MAX (1000) + + +/* + * + * gTcpTxHighTputThreshold - High Threshold inorder to trigger High + * Tx Throughput requirement. + * @Min: 0 + * @Max: 16000 + * @Default: 500 + * + * This ini specifies the threshold of packets transmitted + * over a period of 100 ms beyond which TCP can be considered to have a high + * TX throughput requirement. The driver uses this condition to tweak TCP TX + * specific parameters (via cnss-daemon) + * + * Supported Feature: To tweak TCP TX n/w parameters + * + * Usage: Internal + * + * + */ +#define CFG_TCP_TX_HIGH_TPUT_THRESHOLD_NAME "gTcpTxHighTputThreshold" +#define CFG_TCP_TX_HIGH_TPUT_THRESHOLD_DEFAULT (500) +#define CFG_TCP_TX_HIGH_TPUT_THRESHOLD_MIN (0) +#define CFG_TCP_TX_HIGH_TPUT_THRESHOLD_MAX (16000) + +#endif /* MSM_PLATFORM */ + +#ifdef WLAN_FEATURE_11W +/* + * + * pmfSaQueryMaxRetries - Control PMF SA query retries for SAP + * @Min: 0 + * @Max: 20 + * @Default: 5 + * + * This ini to set the number of PMF SA query retries for SAP + * + * Related: None. + * + * Supported Feature: PMF(11W) + * + * Usage: Internal/External + * + * + */ +#define CFG_PMF_SA_QUERY_MAX_RETRIES_NAME "pmfSaQueryMaxRetries" +#define CFG_PMF_SA_QUERY_MAX_RETRIES_DEFAULT (5) +#define CFG_PMF_SA_QUERY_MAX_RETRIES_MIN (0) +#define CFG_PMF_SA_QUERY_MAX_RETRIES_MAX (20) + +/* + * + * pmfSaQueryRetryInterval - Control PMF SA query retry interval + * for SAP in ms + * @Min: 0 + * @Max: 2000 + * @Default: 200 + * + * This ini to set the PMF SA query retry interval for SAP in ms + * + * Related: None. + * + * Supported Feature: PMF(11W) + * + * Usage: Internal/External + * + * + */ +#define CFG_PMF_SA_QUERY_RETRY_INTERVAL_NAME "pmfSaQueryRetryInterval" +#define CFG_PMF_SA_QUERY_RETRY_INTERVAL_DEFAULT (200) +#define CFG_PMF_SA_QUERY_RETRY_INTERVAL_MIN (0) +#define CFG_PMF_SA_QUERY_RETRY_INTERVAL_MAX (2000) +#endif + +/* + * + * gMaxConcurrentActiveSessions - Maximum number of concurrent connections. + * @Min: 1 + * @Max: 4 + * @Default: 3 + * + * This ini is used to configure the maximum number of concurrent connections. + * + * Related: None. + * + * Supported Feature: Concurrency + * + * Usage: Internal/External + * + * + */ +#define CFG_MAX_CONCURRENT_CONNECTIONS_NAME "gMaxConcurrentActiveSessions" +#define CFG_MAX_CONCURRENT_CONNECTIONS_DEFAULT (3) +#define CFG_MAX_CONCURRENT_CONNECTIONS_MIN (1) +#define CFG_MAX_CONCURRENT_CONNECTIONS_MAX (4) + +/* + * + * gIgnoreCAC - Used to ignore CAC + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to set default CAC + * + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ + +#define CFG_IGNORE_CAC_NAME "gIgnoreCAC" +#define CFG_IGNORE_CAC_MIN (0) +#define CFG_IGNORE_CAC_MAX (1) +#define CFG_IGNORE_CAC_DEFAULT (0) + +#define CFG_ENABLE_SAP_DFS_CH_SIFS_BURST_NAME "gEnableSAPDfsChSifsBurst" +#define CFG_ENABLE_SAP_DFS_CH_SIFS_BURST_MIN (0) +#define CFG_ENABLE_SAP_DFS_CH_SIFS_BURST_MAX (1) +#define CFG_ENABLE_SAP_DFS_CH_SIFS_BURST_DEFAULT (1) + +#define CFG_DFS_RADAR_PRI_MULTIPLIER_NAME "gDFSradarMappingPriMultiplier" +#define CFG_DFS_RADAR_PRI_MULTIPLIER_DEFAULT (4) +#define CFG_DFS_RADAR_PRI_MULTIPLIER_MIN (0) +#define CFG_DFS_RADAR_PRI_MULTIPLIER_MAX (10) + +/* + * + * gReorderOffloadSupported - Packet reordering offload to firmware + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to set default Packet reordering + * + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ + +#define CFG_REORDER_OFFLOAD_SUPPORT_NAME "gReorderOffloadSupported" +#define CFG_REORDER_OFFLOAD_SUPPORT_MIN (0) +#define CFG_REORDER_OFFLOAD_SUPPORT_MAX (1) +#define CFG_REORDER_OFFLOAD_SUPPORT_DEFAULT (0) + +/* IpaUcTxBufCount should be power of 2 */ +#define CFG_IPA_UC_TX_BUF_COUNT_NAME "IpaUcTxBufCount" +#define CFG_IPA_UC_TX_BUF_COUNT_MIN (0) +#define CFG_IPA_UC_TX_BUF_COUNT_MAX (2048) +#define CFG_IPA_UC_TX_BUF_COUNT_DEFAULT (512) + +#define CFG_IPA_UC_TX_BUF_SIZE_NAME "IpaUcTxBufSize" +#define CFG_IPA_UC_TX_BUF_SIZE_MIN (0) +#define CFG_IPA_UC_TX_BUF_SIZE_MAX (4096) +#define CFG_IPA_UC_TX_BUF_SIZE_DEFAULT (2048) + +/* IpaUcRxIndRingCount should be power of 2 */ +#define CFG_IPA_UC_RX_IND_RING_COUNT_NAME "IpaUcRxIndRingCount" +#define CFG_IPA_UC_RX_IND_RING_COUNT_MIN (0) +#define CFG_IPA_UC_RX_IND_RING_COUNT_MAX (2048) +#define CFG_IPA_UC_RX_IND_RING_COUNT_DEFAULT (1024) + +#define CFG_IPA_UC_TX_PARTITION_BASE_NAME "IpaUcTxPartitionBase" +#define CFG_IPA_UC_TX_PARTITION_BASE_MIN (0) +#define CFG_IPA_UC_TX_PARTITION_BASE_MAX (9000) +#define CFG_IPA_UC_TX_PARTITION_BASE_DEFAULT (3000) + +#ifdef WLAN_LOGGING_SOCK_SVC_ENABLE +/* Enable WLAN Logging to app space */ +#define CFG_WLAN_LOGGING_SUPPORT_NAME "wlanLoggingEnable" +#define CFG_WLAN_LOGGING_SUPPORT_ENABLE (1) +#define CFG_WLAN_LOGGING_SUPPORT_DISABLE (0) +#define CFG_WLAN_LOGGING_SUPPORT_DEFAULT (1) + +/* Enable FATAL and ERROR logs for kmsg console */ +#define CFG_WLAN_LOGGING_FE_CONSOLE_SUPPORT_NAME "wlanLoggingFEToConsole" +#define CFG_WLAN_LOGGING_FE_CONSOLE_SUPPORT_ENABLE (1) +#define CFG_WLAN_LOGGING_FE_CONSOLE_SUPPORT_DISABLE (0) +#define CFG_WLAN_LOGGING_FE_CONSOLE_SUPPORT_DEFAULT (1) + +/* Number of buffers to be used for WLAN logging */ +#define CFG_WLAN_LOGGING_NUM_BUF_NAME "wlanLoggingNumBuf" +#define CFG_WLAN_LOGGING_NUM_BUF_MIN (4) +#define CFG_WLAN_LOGGING_NUM_BUF_MAX (512) +#define CFG_WLAN_LOGGING_NUM_BUF_DEFAULT (256) +#endif /* WLAN_LOGGING_SOCK_SVC_ENABLE */ + +/* + * + * gEnableSifsBurst - Enables Sifs Burst + * @Min: 0 + * @Max: 3 + * @Default: 0 + * + * Sifs burst mode configuration + * 0) disabled + * 1) enabled, but disabled for legacy mode + * 3) enabled + * + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ + +#define CFG_ENABLE_SIFS_BURST "gEnableSifsBurst" +#define CFG_ENABLE_SIFS_BURST_MIN (0) +#define CFG_ENABLE_SIFS_BURST_MAX (3) +#define CFG_ENABLE_SIFS_BURST_DEFAULT (0) + +#ifdef WLAN_FEATURE_LPSS +#define CFG_ENABLE_LPASS_SUPPORT "gEnableLpassSupport" +#define CFG_ENABLE_LPASS_SUPPORT_DEFAULT (0) +#define CFG_ENABLE_LPASS_SUPPORT_MIN (0) +#define CFG_ENABLE_LPASS_SUPPORT_MAX (1) +#endif + +/* + * NaN feature support configuration + * gEnableNanSupport = 0 means NaN is not supported + * gEnableNanSupport = 1 means NaN is supported + */ +#ifdef WLAN_FEATURE_NAN +#define CFG_ENABLE_NAN_SUPPORT "gEnableNanSupport" +#define CFG_ENABLE_NAN_SUPPORT_DEFAULT (0) +#define CFG_ENABLE_NAN_SUPPORT_MIN (0) +#define CFG_ENABLE_NAN_SUPPORT_MAX (1) +#endif + +#define CFG_ENABLE_SELF_RECOVERY "gEnableSelfRecovery" +#define CFG_ENABLE_SELF_RECOVERY_MIN (0) +#define CFG_ENABLE_SELF_RECOVERY_MAX (1) +#define CFG_ENABLE_SELF_RECOVERY_DEFAULT (0) + +#define CFG_ENABLE_SAP_SUSPEND "gEnableSapSuspend" +#define CFG_ENABLE_SAP_SUSPEND_MIN (0) +#define CFG_ENABLE_SAP_SUSPEND_MAX (1) +#define CFG_ENABLE_SAP_SUSPEND_DEFAULT (1) + +/* + * + * gEnableDeauthToDisassocMap - Enables deauth to disassoc map + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to set default disassoc map + * + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ + +#define CFG_ENABLE_DEAUTH_TO_DISASSOC_MAP_NAME "gEnableDeauthToDisassocMap" +#define CFG_ENABLE_DEAUTH_TO_DISASSOC_MAP_MIN (0) +#define CFG_ENABLE_DEAUTH_TO_DISASSOC_MAP_MAX (1) +#define CFG_ENABLE_DEAUTH_TO_DISASSOC_MAP_DEFAULT (0) + +#ifdef DHCP_SERVER_OFFLOAD +#define CFG_DHCP_SERVER_OFFLOAD_SUPPORT_NAME "gDHCPServerOffloadEnable" +#define CFG_DHCP_SERVER_OFFLOAD_SUPPORT_MIN (0) +#define CFG_DHCP_SERVER_OFFLOAD_SUPPORT_MAX (1) +#define CFG_DHCP_SERVER_OFFLOAD_SUPPORT_DEFAULT (CFG_DHCP_SERVER_OFFLOAD_SUPPORT_MIN) + +#define CFG_DHCP_SERVER_OFFLOAD_NUM_CLIENT_NAME "gDHCPMaxNumClients" +#define CFG_DHCP_SERVER_OFFLOAD_NUM_CLIENT_MIN (1) +#define CFG_DHCP_SERVER_OFFLOAD_NUM_CLIENT_MAX (8) +#define CFG_DHCP_SERVER_OFFLOAD_NUM_CLIENT_DEFAULT (CFG_DHCP_SERVER_OFFLOAD_NUM_CLIENT_MAX) + +#define CFG_DHCP_SERVER_IP_NAME "gDHCPServerIP" +#define CFG_DHCP_SERVER_IP_DEFAULT "" +#endif /* DHCP_SERVER_OFFLOAD */ + +/* + * + * gSendDeauthBeforeCon - It will send deauth before connection + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to set default DeauthBeforeCon + * If last disconnection was due to HB failure and we reconnect + * to same AP next time, send Deauth before starting connection + * + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ + +#define CFG_ENABLE_DEAUTH_BEFORE_CONNECTION "gSendDeauthBeforeCon" +#define CFG_ENABLE_DEAUTH_BEFORE_CONNECTION_MIN (0) +#define CFG_ENABLE_DEAUTH_BEFORE_CONNECTION_MAX (1) +#define CFG_ENABLE_DEAUTH_BEFORE_CONNECTION_DEFAULT (0) + +/* + * + * gEnableCustomConcRule1 - Enable custom concurrency rule1. + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to enable/disable custom concurrency rule1. + * If SAP comes up first and STA comes up later then SAP needs to follow STA's + * channel. + * + * Related: None. + * + * Supported Feature: Concurrency + * + * Usage: Internal/External + * + * + */ +#define CFG_ENABLE_CUSTOM_CONC_RULE1_NAME "gEnableCustomConcRule1" +#define CFG_ENABLE_CUSTOM_CONC_RULE1_NAME_MIN (0) +#define CFG_ENABLE_CUSTOM_CONC_RULE1_NAME_MAX (1) +#define CFG_ENABLE_CUSTOM_CONC_RULE1_NAME_DEFAULT (0) + +/* + * + * gEnableCustomConcRule2 - Enable custom concurrency rule2. + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to enable/disable custom concurrency rule2. + * If P2PGO comes up first and STA comes up later then P2PGO need to follow + * STA's channel in 5Ghz. In following if condition we are just adding sanity + * check to make sure that by this time P2PGO's channel is same as STA's + * channel. + * + * Related: None. + * + * Supported Feature: Concurrency + * + * Usage: Internal/External + * + * + */ +#define CFG_ENABLE_CUSTOM_CONC_RULE2_NAME "gEnableCustomConcRule2" +#define CFG_ENABLE_CUSTOM_CONC_RULE2_NAME_MIN (0) +#define CFG_ENABLE_CUSTOM_CONC_RULE2_NAME_MAX (1) +#define CFG_ENABLE_CUSTOM_CONC_RULE2_NAME_DEFAULT (0) + +#define CFG_ENABLE_STA_CONNECTION_IN_5GHZ "gEnableStaConnectionIn5Ghz" +#define CFG_ENABLE_STA_CONNECTION_IN_5GHZ_MIN (0) +#define CFG_ENABLE_STA_CONNECTION_IN_5GHZ_MAX (1) +#define CFG_ENABLE_STA_CONNECTION_IN_5GHZ_DEFAULT (1) + +#define CFG_ENABLE_MAC_ADDR_SPOOFING "gEnableMacAddrSpoof" +#define CFG_ENABLE_MAC_ADDR_SPOOFING_MIN (0) +#define CFG_ENABLE_MAC_ADDR_SPOOFING_MAX (1) +#define CFG_ENABLE_MAC_ADDR_SPOOFING_DEFAULT (1) + +#define CFG_P2P_LISTEN_DEFER_INTERVAL_NAME "gP2PListenDeferInterval" +#define CFG_P2P_LISTEN_DEFER_INTERVAL_MIN (100) +#define CFG_P2P_LISTEN_DEFER_INTERVAL_MAX (200) +#define CFG_P2P_LISTEN_DEFER_INTERVAL_DEFAULT (100) + +/* + * + * gStaMiracastMccRestTimeVal - Rest time when Miracast is running. + * @Min: 100 + * @Max: 500 + * @Default: 400 + * + * This ini is used to set rest time for home channel for Miracast before + * going for scan. + * + * Related: None. + * + * Supported Feature: Concurrency + * + * Usage: Internal/External + * + * + */ +#define CFG_STA_MIRACAST_MCC_REST_TIME_VAL "gStaMiracastMccRestTimeVal" +#define CFG_STA_MIRACAST_MCC_REST_TIME_VAL_MIN (100) +#define CFG_STA_MIRACAST_MCC_REST_TIME_VAL_MAX (500) +#define CFG_STA_MIRACAST_MCC_REST_TIME_VAL_DEFAULT (400) + +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE +/* + * + * gSapChannelAvoidance - SAP MCC channel avoidance. + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to sets sap mcc channel avoidance. + * + * Related: None. + * + * Supported Feature: Concurrency + * + * Usage: Internal/External + * + * + */ +#define CFG_SAP_MCC_CHANNEL_AVOIDANCE_NAME "gSapChannelAvoidance" +#define CFG_SAP_MCC_CHANNEL_AVOIDANCE_MIN (0) +#define CFG_SAP_MCC_CHANNEL_AVOIDANCE_MAX (1) +#define CFG_SAP_MCC_CHANNEL_AVOIDANCE_DEFAULT (0) +#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ +/* + * + * gAP11ACOverride - Override 11AC when GO follow SAP channel + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to enable/disable 11AC override. + * 1. P2P GO also follows start_bss and since p2p GO could not be + * configured to setup VHT channel width in wpa_supplicant, driver + * can override 11AC. + * 2. Android UI does not provide advanced configuration options + * for SoftAP + * Default override enabled for android. MDM shall + * disable it in ini + * + * + * Supported Feature: P2P + * + * + * Usage: Internal/External + * + * + */ +#define CFG_SAP_P2P_11AC_OVERRIDE_NAME "gAP11ACOverride" +#define CFG_SAP_P2P_11AC_OVERRIDE_MIN (0) +#define CFG_SAP_P2P_11AC_OVERRIDE_MAX (1) +#define CFG_SAP_P2P_11AC_OVERRIDE_DEFAULT (1) + +#define CFG_SAP_DOT11MC "gSapDot11mc" +#define CFG_SAP_DOT11MC_MIN (0) +#define CFG_SAP_DOT11MC_MAX (1) +#define CFG_SAP_DOT11MC_DEFAULT (0) + +#define CFG_ENABLE_NON_DFS_CHAN_ON_RADAR "gPreferNonDfsChanOnRadar" +#define CFG_ENABLE_NON_DFS_CHAN_ON_RADAR_MIN (0) +#define CFG_ENABLE_NON_DFS_CHAN_ON_RADAR_MAX (1) +#define CFG_ENABLE_NON_DFS_CHAN_ON_RADAR_DEFAULT (0) + +#define CFG_MULTICAST_HOST_FW_MSGS "gMulticastHostFwMsgs" +#define CFG_MULTICAST_HOST_FW_MSGS_MIN (0) +#define CFG_MULTICAST_HOST_FW_MSGS_MAX (1) +#define CFG_MULTICAST_HOST_FW_MSGS_DEFAULT (1) + +/* + * + * gSystemPref - Configure wlan system preference for PCL. + * @Min: 0 + * @Max: 2 + * @Default: 0 + * + * This ini is used to configure wlan system preference option to help + * policy manager decide on Preferred Channel List for a new connection. + * For possible values refer to enum hdd_conc_priority_mode + * + * Related: None. + * + * Supported Feature: DBS + * + * Usage: Internal/External + * + * + */ +#define CFG_CONC_SYSTEM_PREF "gSystemPref" +#define CFG_CONC_SYSTEM_PREF_MIN (0) +#define CFG_CONC_SYSTEM_PREF_MAX (2) +#define CFG_CONC_SYSTEM_PREF_DEFAULT (0) + +/* + * + * TSOEnable - Control to enable tso feature + * + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to enable TSO feature + * + * Supported Feature: TSO Feature + * + * Usage: Internal + * + * + */ +#define CFG_TSO_ENABLED_NAME "TSOEnable" +#define CFG_TSO_ENABLED_MIN (0) +#define CFG_TSO_ENABLED_MAX (1) +#define CFG_TSO_ENABLED_DEFAULT (0) + +/* + * + * LROEnable - Control to enable lro feature + * + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to enable LRO feature + * + * Supported Feature: LRO + * + * Usage: Internal + * + * + */ +#define CFG_LRO_ENABLED_NAME "LROEnable" +#define CFG_LRO_ENABLED_MIN (0) +#define CFG_LRO_ENABLED_MAX (1) +#define CFG_LRO_ENABLED_DEFAULT (0) + +/* + * Enable Rx traffic flow steering to enable Rx interrupts on multiple CEs based + * on the flows. Different CEs<==>different IRQs<==>probably different CPUs. + * Parallel Rx paths. + * 1 - enable 0 - disable + */ +#define CFG_FLOW_STEERING_ENABLED_NAME "gEnableFlowSteering" +#define CFG_FLOW_STEERING_ENABLED_MIN (0) +#define CFG_FLOW_STEERING_ENABLED_MAX (1) +#define CFG_FLOW_STEERING_ENABLED_DEFAULT (0) + +/* + * In static display use case when APPS is in stand alone power save mode enable + * active offload mode which helps FW to filter out MC/BC data packets to avoid + * APPS wake up and save more power. + * + * By default enable active mode offload as it helps to save more power in + * static display usecase(APPS stand alone power collapse). + * + * If active mode offload(gActiveModeOffload=1) is enabled then all applicable + * data offload/filtering is enabled immediately in FW once config is available + * in WLAN driver and FW caches this configuration accross suspend/resume + * + * If active mode offload is disabled(gActiveModeOffload=0) then all applicable + * data offload/filtering is enabled during cfg80211 suspend and disabled + * during cfg80211 resume + * + * Active mode offload feature is bydefault enabled for adrastea and disabled + * for non adrastea targets like ROME + */ + +#define CFG_ACTIVE_MODE_OFFLOAD "gActiveModeOffload" +#define CFG_ACTIVE_MODE_OFFLOAD_MIN (0) +#define CFG_ACTIVE_MODE_OFFLOAD_MAX (1) +#ifdef QCA_WIFI_3_0_ADRASTEA +#define CFG_ACTIVE_MODE_OFFLOAD_DEFAULT (1) +#else +#define CFG_ACTIVE_MODE_OFFLOAD_DEFAULT (0) +#endif + +/* + * 0: Disable BPF packet filter + * 1: Enable BPF packet filter + */ +#define CFG_BPF_PACKET_FILTER_OFFLOAD "gBpfFilterEnable" +#define CFG_BPF_PACKET_FILTER_OFFLOAD_MIN (0) +#define CFG_BPF_PACKET_FILTER_OFFLOAD_MAX (1) +#define CFG_BPF_PACKET_FILTER_OFFLOAD_DEFAULT (1) + +/* + * + * gCckChainMaskEnable - Used to enable/disable Cck ChainMask + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to set default Cck ChainMask + * 0: disable the cck tx chain mask (default) + * 1: enable the cck tx chain mask + * + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ + +#define CFG_TX_CHAIN_MASK_CCK "gCckChainMaskEnable" +#define CFG_TX_CHAIN_MASK_CCK_MIN (0) +#define CFG_TX_CHAIN_MASK_CCK_MAX (1) +#define CFG_TX_CHAIN_MASK_CCK_DEFAULT (0) +/* + * + * gTxChainMask1ss - Enables/disables tx chain Mask1ss + * @Min: 0 + * @Max: 3 + * @Default: 1 + * + * This ini is used to set default tx chain Mask1ss + * + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ + +#define CFG_TX_CHAIN_MASK_1SS "gTxChainMask1ss" +#define CFG_TX_CHAIN_MASK_1SS_MIN (0) +#define CFG_TX_CHAIN_MASK_1SS_MAX (3) +#define CFG_TX_CHAIN_MASK_1SS_DEFAULT (1) + +/* + * set the self gen power value from + * 0 to 0xffff + */ +#define CFG_SELF_GEN_FRM_PWR "gSelfGenFrmPwr" +#define CFG_SELF_GEN_FRM_PWR_MIN (0) +#define CFG_SELF_GEN_FRM_PWR_MAX (0xffff) +#define CFG_SELF_GEN_FRM_PWR_DEFAULT (0) + +/* + * + * gTxAggregationSize - Gives an option to configure Tx aggregation size + * in no of MPDUs + * @Min: 0 + * @Max: 64 + * @Default: 64 + * + * gTxAggregationSize gives an option to configure Tx aggregation size + * in no of MPDUs.This can be useful in debugging throughput issues + * + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ + +#define CFG_TX_AGGREGATION_SIZE "gTxAggregationSize" +#define CFG_TX_AGGREGATION_SIZE_MIN (0) +#define CFG_TX_AGGREGATION_SIZE_MAX (64) +#define CFG_TX_AGGREGATION_SIZE_DEFAULT (64) + +/* + * + * gRxAggregationSize - Gives an option to configure Rx aggregation size + * in no of MPDUs + * @Min: 1 + * @Max: 64 + * @Default: 64 + * + * gRxAggregationSize gives an option to configure Rx aggregation size + * in no of MPDUs. This can be useful in debugging throughput issues + * + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ + +#define CFG_RX_AGGREGATION_SIZE "gRxAggregationSize" +#define CFG_RX_AGGREGATION_SIZE_MIN (1) +#define CFG_RX_AGGREGATION_SIZE_MAX (64) +#define CFG_RX_AGGREGATION_SIZE_DEFAULT (64) + +/* + * fine timing measurement capability information + * + * <----- fine_time_meas_cap (in bits) -----> + *+----------+-----+-----+------+------+-------+-------+-----+-----+ + *| 9-31 | 8 | 7 | 5 | 4 | 3 | 2 | 1 | 0 | + *+----------+-----+-----+------+------+-------+-------+-----+-----+ + *| reserved | SAP | SAP |P2P-GO|P2P-GO|P2P-CLI|P2P-CLI| STA | STA | + *| |resp |init |resp |init |resp |init |resp |init | + *+----------+-----+-----+------+------+-------+-------+-----+-----+ + * + * resp - responder role; init- initiator role + * + * CFG_FINE_TIME_MEAS_CAPABILITY_MAX computed based on the table + * +-----------------+-----------------+-----------+ + * | Device Role | Initiator | Responder | + * +-----------------+-----------------+-----------+ + * | Station | Y | N | + * | P2P-CLI | Y | Y | + * | P2P-GO | Y | Y | + * | SAP | N | Y | + * +-----------------+-----------------+-----------+ + */ +#define CFG_FINE_TIME_MEAS_CAPABILITY "gfine_time_meas_cap" +#define CFG_FINE_TIME_MEAS_CAPABILITY_MIN (0x0000) +#define CFG_FINE_TIME_MEAS_CAPABILITY_MAX (0x00BD) +#define CFG_FINE_TIME_MEAS_CAPABILITY_DEFAULT (0x000D) + +/** + * enum dot11p_mode - The 802.11p mode of operation + * @WLAN_HDD_11P_DISABLED: 802.11p mode is disabled + * @WLAN_HDD_11P_STANDALONE: 802.11p-only operation + * @WLAN_HDD_11P_CONCURRENT: 802.11p and WLAN operate concurrently + */ +enum dot11p_mode { + WLAN_HDD_11P_DISABLED = 0, + WLAN_HDD_11P_STANDALONE, + WLAN_HDD_11P_CONCURRENT, +}; + +#define CFG_DOT11P_MODE_NAME "gDot11PMode" +#define CFG_DOT11P_MODE_DEFAULT (WLAN_HDD_11P_DISABLED) +#define CFG_DOT11P_MODE_MIN (WLAN_HDD_11P_DISABLED) +#define CFG_DOT11P_MODE_MAX (WLAN_HDD_11P_CONCURRENT) + +/* + * + * gEnable_go_cts2self_for_sta - Indicate firmware to stop NOA and + * start using cts2self + * @Min: 1 + * @Max: 1 + * @Default: 0 + * + * When gEnable_go_cts2self_for_sta is + * enabled then if a legacy client connects to P2P GO, + * Host will send a WMI VDEV command to FW to stop using NOA for P2P GO + * and start using CTS2SELF. + * + * + * Supported Feature: P2P + * + * + * Usage: Internal/External + * + * + */ +#define CFG_ENABLE_GO_CTS2SELF_FOR_STA "gEnable_go_cts2self_for_sta" +#define CFG_ENABLE_GO_CTS2SELF_FOR_STA_DEFAULT (0) +#define CFG_ENABLE_GO_CTS2SELF_FOR_STA_MIN (0) +#define CFG_ENABLE_GO_CTS2SELF_FOR_STA_MAX (1) + +#define CFG_CE_CLASSIFY_ENABLE_NAME "gCEClassifyEnable" +#define CFG_CE_CLASSIFY_ENABLE_MIN (0) +#define CFG_CE_CLASSIFY_ENABLE_MAX (1) +#define CFG_CE_CLASSIFY_ENABLE_DEFAULT (1) + +/* + * + * gDualMacFeatureDisable - Disable Dual MAC feature. + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to enable/disable dual MAC feature. + * 0 - enable DBS 1 - disable DBS + * + * Related: None. + * + * Supported Feature: DBS + * + * Usage: Internal/External + * + * + */ +#define CFG_DUAL_MAC_FEATURE_DISABLE "gDualMacFeatureDisable" +#define CFG_DUAL_MAC_FEATURE_DISABLE_MIN (0) +#define CFG_DUAL_MAC_FEATURE_DISABLE_MAX (1) +#define CFG_DUAL_MAC_FEATURE_DISABLE_DEFAULT (0) + +/* + * gPNOChannelPrediction will allow user to enable/disable the + * PNO channel prediction feature. + * In current PNO implementation, scan is always done until all configured + * channels are scanned. If we can determine DUT is stationary based on + * scanning a subset of channels, we may cancel the remaining channels. + * Hence, we can save additional power consumption. + */ +#define CFG_PNO_CHANNEL_PREDICTION_NAME "gPNOChannelPrediction" +#define CFG_PNO_CHANNEL_PREDICTION_MIN (0) +#define CFG_PNO_CHANNEL_PREDICTION_MAX (1) +#define CFG_PNO_CHANNEL_PREDICTION_DEFAULT (0) +/* + * The top K number of channels are used for tanimoto distance + * calculation. These are the top channels on which the probability + * of finding the AP's is extremely high. This number is intended + * for tweaking the internal algorithm for experiments. This should + * not be changed externally. + */ +#define CFG_TOP_K_NUM_OF_CHANNELS_NAME "gTopKNumOfChannels" +#define CFG_TOP_K_NUM_OF_CHANNELS_MIN (1) +#define CFG_TOP_K_NUM_OF_CHANNELS_MAX (5) +#define CFG_TOP_K_NUM_OF_CHANNELS_DEFAULT (3) +/* + * This is the threshold value to determine that the STA is + * stationary. If the tanimoto distance is less than this + * value, then the device is considered to be stationary. + * This parameter is intended to tweak the internal algorithm + * for experiments. This should not be changed externally. + */ +#define CFG_STATIONARY_THRESHOLD_NAME "gStationaryThreshold" +#define CFG_STATIONARY_THRESHOLD_MIN (0) +#define CFG_STATIONARY_THRESHOLD_MAX (100) +#define CFG_STATIONARY_THRESHOLD_DEFAULT (10) + +/* Option to report rssi in cfg80211_inform_bss_frame() + * 0 = use rssi value based on noise floor = -96 dBm + * 1 = use rssi value based on actual noise floor in hardware + */ +#define CFG_INFORM_BSS_RSSI_RAW_NAME "gInformBssRssiRaw" +#define CFG_INFORM_BSS_RSSI_RAW_MIN (0) +#define CFG_INFORM_BSS_RSSI_RAW_MAX (1) +#define CFG_INFORM_BSS_RSSI_RAW_DEFAULT (1) + +/* GPIO pin to toggle when capture tsf */ +#define CFG_SET_TSF_GPIO_PIN_NAME "gtsf_gpio_pin" +#define CFG_SET_TSF_GPIO_PIN_MIN (0) +#define CFG_SET_TSF_GPIO_PIN_MAX (254) +#define TSF_GPIO_PIN_INVALID (255) +#define CFG_SET_TSF_GPIO_PIN_DEFAULT (TSF_GPIO_PIN_INVALID) + +/* + * Dense traffic threshold + * traffic threshold required for dense roam scan + * Measured in kbps + */ +#define CFG_ROAM_DENSE_TRAFFIC_THRESHOLD "gtraffic_threshold" +#define CFG_ROAM_DENSE_TRAFFIC_THRESHOLD_MIN (0) +#define CFG_ROAM_DENSE_TRAFFIC_THRESHOLD_MAX (0xffffffff) +#define CFG_ROAM_DENSE_TRAFFIC_THRESHOLD_DEFAULT (400) + +/* + * Enabling gignore_peer_ht_opmode will enable 11g + * protection only when there is a 11g AP in vicinity. + */ +#define CFG_IGNORE_PEER_HT_MODE_NAME "gignore_peer_ht_opmode" +#define CFG_IGNORE_PEER_HT_MODE_MIN (0) +#define CFG_IGNORE_PEER_HT_MODE_MAX (1) +#define CFG_IGNORE_PEER_HT_MODE_DEFAULT (0) + +#ifdef WLAN_FEATURE_NAN_DATAPATH +/* + * Enable NaN data path feature. NaN data path enables + * NaN supported devices to exchange data over traditional + * TCP/UDP network stack. + */ +#define CFG_ENABLE_NAN_DATAPATH_NAME "genable_nan_datapath" +#define CFG_ENABLE_NAN_DATAPATH_MIN (0) +#define CFG_ENABLE_NAN_DATAPATH_MAX (1) +#define CFG_ENABLE_NAN_DATAPATH_DEFAULT (0) + +/* + * NAN channel on which NAN data interface to start + */ +#define CFG_ENABLE_NAN_NDI_CHANNEL_NAME "gnan_datapath_ndi_channel" +#define CFG_ENABLE_NAN_NDI_CHANNEL_MIN (6) +#define CFG_ENABLE_NAN_NDI_CHANNEL_MAX (149) +#define CFG_ENABLE_NAN_NDI_CHANNEL_DEFAULT (6) +#endif + +/* + * Enable/Disable to initiate BUG report in case of fatal event + * Default: Enable + */ +#define CFG_ENABLE_FATAL_EVENT_TRIGGER "gEnableFatalEvent" +#define CFG_ENABLE_FATAL_EVENT_TRIGGER_MIN (0) +#define CFG_ENABLE_FATAL_EVENT_TRIGGER_MAX (1) +#define CFG_ENABLE_FATAL_EVENT_TRIGGER_DEFAULT (1) + +/* + * + * gEnableEdcaParams - Enable edca parameter + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used if gEnableEdcaParams is set to 1, params gEdcaVoCwmin, + * gEdcaViCwmin, gEdcaBkCwmin, gEdcaBeCwmin, gEdcaVoCwmax, + * gEdcaViCwmax, gEdcaBkCwmax, gEdcaBeCwmax, gEdcaVoAifs, + * gEdcaViAifs, gEdcaBkAifs and gEdcaBeAifs values are used + * to overwrite the values received from AP + * + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ + +#define CFG_ENABLE_EDCA_INI_NAME "gEnableEdcaParams" +#define CFG_ENABLE_EDCA_INI_MIN (0) +#define CFG_ENABLE_EDCA_INI_MAX (1) +#define CFG_ENABLE_EDCA_INI_DEFAULT (0) + +/* + * + * gEdcaVoCwmin - Set Cwmin value for EDCA_AC_VO + * @Min: 0 + * @Max: 0x15 + * @Default: 2 + * + * This ini is used to set default Cwmin value for EDCA_AC_VO + * Cwmin value for EDCA_AC_VO. CWVomin = 2^gEdcaVoCwmin -1 + * + * Related: If gEnableEdcaParams is set to 1, params gEdcaVoCwmin etc + * are aplicable + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ + +#define CFG_EDCA_VO_CWMIN_VALUE_NAME "gEdcaVoCwmin" +#define CFG_EDCA_VO_CWMIN_VALUE_MIN (0x0) +#define CFG_EDCA_VO_CWMIN_VALUE_MAX (15) +#define CFG_EDCA_VO_CWMIN_VALUE_DEFAULT (2) + +/* + * + * gEdcaViCwmin - Set Cwmin value for EDCA_AC_VI + * @Min: 0x0 + * @Max: 15 + * @Default: 3 + * + * This ini is used to set default value for EDCA_AC_VI + * Cwmin value for EDCA_AC_VI. CWVimin = 2^gEdcaViCwmin -1 + * + * Related: If gEnableEdcaParams is set to 1, params gEdcaVoCwmin + * etc are aplicable + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ + +#define CFG_EDCA_VI_CWMIN_VALUE_NAME "gEdcaViCwmin" +#define CFG_EDCA_VI_CWMIN_VALUE_MIN (0x0) +#define CFG_EDCA_VI_CWMIN_VALUE_MAX (15) +#define CFG_EDCA_VI_CWMIN_VALUE_DEFAULT (3) + +/* + * + * gEdcaBkCwmin - Set Cwmin value for EDCA_AC_BK + * @Min: 0x0 + * @Max: 15 + * @Default: 4 + * + * This ini is used to set default Cwmin value for EDCA_AC_BK + * Cwmin value for EDCA_AC_BK. CWBkmin = 2^gEdcaBkCwmin -1 + * + * Related: If gEnableEdcaParams is set to 1, params gEdcaVoCwmin + * etc are aplicable + * + * Supported Feature: STA + * + * Usage: Internal/External + * + */ + +#define CFG_EDCA_BK_CWMIN_VALUE_NAME "gEdcaBkCwmin" +#define CFG_EDCA_BK_CWMIN_VALUE_MIN (0x0) +#define CFG_EDCA_BK_CWMIN_VALUE_MAX (15) +#define CFG_EDCA_BK_CWMIN_VALUE_DEFAULT (4) + +/* + * + * gEdcaBeCwmin - Set Cwmin value for EDCA_AC_BE + * @Min: 0x0 + * @Max: 15 + * @Default: 4 + * + * This ini is used to set default Cwmin value for EDCA_AC_BE + * Cwmin value for EDCA_AC_BE. CWBemin = 2^gEdcaBeCwmin + * + * Related: If gEnableEdcaParams is set to 1, params gEdcaVoCwmin + * etc are aplicable + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ + +#define CFG_EDCA_BE_CWMIN_VALUE_NAME "gEdcaBeCwmin" +#define CFG_EDCA_BE_CWMIN_VALUE_MIN (0x0) +#define CFG_EDCA_BE_CWMIN_VALUE_MAX (15) +#define CFG_EDCA_BE_CWMIN_VALUE_DEFAULT (4) +/* + * + * gP2PListenDeferInterval - Defer Remain on channel for some duration + * @Min: 100 + * @Max: 200 + * @Default: 100 + * + * This ini is used to defer back to back RoC request when sta is + * connected. + * If back to back listen received when sta is connected then fw is + * not getting enough time to spend on home channel so it leading to + * heartbeat failure. + * + * Supported Feature: P2P + * + * + * Usage: Internal/External + * + * + */ +#define CFG_P2P_LISTEN_DEFER_INTERVAL_NAME "gP2PListenDeferInterval" +#define CFG_P2P_LISTEN_DEFER_INTERVAL_MIN (100) +#define CFG_P2P_LISTEN_DEFER_INTERVAL_MAX (200) +#define CFG_P2P_LISTEN_DEFER_INTERVAL_DEFAULT (100) + +/* + * + * gEdcaVoCwmax - Set Cwmax value for EDCA_AC_VO + * @Min: 0 + * @Max: 15 + * @Default: 3 + * + * This ini is used to set default Cwmax value for EDCA_AC_VO + * Cwmax value for EDCA_AC_VO. CWVomax = 2^gEdcaVoCwmax -1 + * + * Related: If gEnableEdcaParams is set to 1, params gEdcaVoCwmin + * etc are aplicable + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ + +#define CFG_EDCA_VO_CWMAX_VALUE_NAME "gEdcaVoCwmax" +#define CFG_EDCA_VO_CWMAX_VALUE_MIN (0) +#define CFG_EDCA_VO_CWMAX_VALUE_MAX (15) +#define CFG_EDCA_VO_CWMAX_VALUE_DEFAULT (3) + +/* + * + * gEdcaViCwmax - Set Cwmax value for EDCA_AC_VI + * @Min: 0 + * @Max: 15 + * @Default: 4 + * + * This ini is used to set default Cwmax value for EDCA_AC_VI + * Cwmax value for EDCA_AC_VI. CWVimax = 2^gEdcaViCwmax -1 + * + * Related: If gEnableEdcaParams is set to 1, params gEdcaVoCwmin + * etc are aplicable + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define CFG_EDCA_VI_CWMAX_VALUE_NAME "gEdcaViCwmax" +#define CFG_EDCA_VI_CWMAX_VALUE_MIN (0) +#define CFG_EDCA_VI_CWMAX_VALUE_MAX (15) +#define CFG_EDCA_VI_CWMAX_VALUE_DEFAULT (4) + +/* + * + * gEdcaBkCwmax - Set Cwmax value for EDCA_AC_BK + * @Min: 0 + * @Max: 15 + * @Default: 10 + * + * This ini is used to set default Cwmax value for EDCA_AC_BK + * Cwmax value for EDCA_AC_BK. CWBkmax = 2^gEdcaBkCwmax -1 + * + * Related: If gEnableEdcaParams is set to 1, params gEdcaVoCwmin + * etc are aplicable + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ + +#define CFG_EDCA_BK_CWMAX_VALUE_NAME "gEdcaBkCwmax" +#define CFG_EDCA_BK_CWMAX_VALUE_MIN (0) +#define CFG_EDCA_BK_CWMAX_VALUE_MAX (15) +#define CFG_EDCA_BK_CWMAX_VALUE_DEFAULT (10) + +/* + * + * gEdcaBeCwmax - Set Cwmax value for EDCA_AC_BE + * @Min: 0 + * @Max: 15 + * @Default: 10 + * + * This ini is used to set default Cwmax value for EDCA_AC_BE + * Cwmax value for EDCA_AC_BE. CWBemax = 2^gEdcaBeCwmax -1 + * + * Related: If gEnableEdcaParams is set to 1, params gEdcaVoCwmin + * etc are aplicable + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ + +#define CFG_EDCA_BE_CWMAX_VALUE_NAME "gEdcaBeCwmax" +#define CFG_EDCA_BE_CWMAX_VALUE_MIN (0) +#define CFG_EDCA_BE_CWMAX_VALUE_MAX (15) +#define CFG_EDCA_BE_CWMAX_VALUE_DEFAULT (10) + +/* + * + * gEdcaVoAifs - Set Aifs value for EDCA_AC_VO + * @Min: 0 + * @Max: 15 + * @Default: 2 + * + * This ini is used to set default Aifs value for EDCA_AC_VO + * + * Related: If gEnableEdcaParams is set to 1, params gEdcaVoCwmin + * etc are aplicable + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ + +#define CFG_EDCA_VO_AIFS_VALUE_NAME "gEdcaVoAifs" +#define CFG_EDCA_VO_AIFS_VALUE_MIN (0) +#define CFG_EDCA_VO_AIFS_VALUE_MAX (15) +#define CFG_EDCA_VO_AIFS_VALUE_DEFAULT (2) + +/* + * + * gEdcaViAifs - Set Aifs value for EDCA_AC_VI + * @Min: 0 + * @Max: 15 + * @Default: 2 + * + * This ini is used to set default Aifs value for EDCA_AC_VI + * + * Related: If gEnableEdcaParams is set to 1, params gEdcaVoCwmin + * etc are aplicable + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ + +#define CFG_EDCA_VI_AIFS_VALUE_NAME "gEdcaViAifs" +#define CFG_EDCA_VI_AIFS_VALUE_MIN (0) +#define CFG_EDCA_VI_AIFS_VALUE_MAX (15) +#define CFG_EDCA_VI_AIFS_VALUE_DEFAULT (2) + +/* + * + * gEdcaBkAifs - Set Aifs value for EDCA_AC_BK + * @Min: 0 + * @Max: 15 + * @Default: 7 + * + * This ini is used to set default Aifs value for EDCA_AC_BK + * + * Related: If gEnableEdcaParams is set to 1, params gEdcaVoCwmin + * etc are aplicable + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ + +#define CFG_EDCA_BK_AIFS_VALUE_NAME "gEdcaBkAifs" +#define CFG_EDCA_BK_AIFS_VALUE_MIN (0) +#define CFG_EDCA_BK_AIFS_VALUE_MAX (15) +#define CFG_EDCA_BK_AIFS_VALUE_DEFAULT (7) + +/* + * + * gEdcaBeAifs - Set Aifs value for EDCA_AC_BE + * @Min: 0 + * @Max: 15 + * @Default: 3 + * + * This ini is used to set default Aifs value for EDCA_AC_BE + * + * Related: If gEnableEdcaParams is set to 1, params gEdcaVoCwmin + * etc are aplicable + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ + +#define CFG_EDCA_BE_AIFS_VALUE_NAME "gEdcaBeAifs" +#define CFG_EDCA_BE_AIFS_VALUE_MIN (0) +#define CFG_EDCA_BE_AIFS_VALUE_MAX (15) +#define CFG_EDCA_BE_AIFS_VALUE_DEFAULT (3) + +/* + * This key is mapping to VO defined in data path module through + * OL_TX_SCHED_WRR_ADV_CAT_CFG_SPEC. The user can tune the + * WRR TX sched parameters such as skip, credit, limit, credit, disc for VO. + * e.g., gEnableTxSchedWrrVO = 10, 9, 8, 1, 8 + */ +#define CFG_ENABLE_TX_SCHED_WRR_VO "gEnableTxSchedWrrVO" +#define CFG_ENABLE_TX_SCHED_WRR_VO_DEFAULT "" + +/* + * This key is mapping to VI defined in data path module through + * OL_TX_SCHED_WRR_ADV_CAT_CFG_SPEC. The user can tune the + * WRR TX sched parameters such as skip, credit, limit, credit, disc for VI. + * e.g., gEnableTxSchedWrrVI = 10, 9, 8, 1, 8 + */ +#define CFG_ENABLE_TX_SCHED_WRR_VI "gEnableTxSchedWrrVI" +#define CFG_ENABLE_TX_SCHED_WRR_VI_DEFAULT "" + +/* + * This key is mapping to BE defined in data path module through + * OL_TX_SCHED_WRR_ADV_CAT_CFG_SPEC. The user can tune the + * WRR TX sched parameters such as skip, credit, limit, credit, disc for BE. + * e.g., gEnableTxSchedWrrBE = 10, 9, 8, 1, 8 + */ +#define CFG_ENABLE_TX_SCHED_WRR_BE "gEnableTxSchedWrrBE" +#define CFG_ENABLE_TX_SCHED_WRR_BE_DEFAULT "" + +/* + * This key is mapping to BK defined in data path module through + * OL_TX_SCHED_WRR_ADV_CAT_CFG_SPEC. The user can tune the + * WRR TX sched parameters such as skip, credit, limit, credit, disc for BK. + * e.g., gEnableTxSchedWrrBK = 10, 9, 8, 1, 8 + */ +#define CFG_ENABLE_TX_SCHED_WRR_BK "gEnableTxSchedWrrBK" +#define CFG_ENABLE_TX_SCHED_WRR_BK_DEFAULT "" + +/* + * Enable/disable DPTRACE + * Enabling this might have performace impact. + */ +#define CFG_ENABLE_DP_TRACE "enable_dp_trace" +#define CFG_ENABLE_DP_TRACE_MIN (0) +#define CFG_ENABLE_DP_TRACE_MAX (1) +#define CFG_ENABLE_DP_TRACE_DEFAULT (1) + +/* + * This parameter will set the weight to calculate the average low pass + * filter for channel congestion. + * Acceptable values for this: 0-100 (In %) + */ +#define CFG_ADAPT_DWELL_LPF_WEIGHT_NAME "adapt_dwell_lpf_weight" +#define CFG_ADAPT_DWELL_LPF_WEIGHT_MIN (0) +#define CFG_ADAPT_DWELL_LPF_WEIGHT_MAX (100) +#define CFG_ADAPT_DWELL_LPF_WEIGHT_DEFAULT (80) + +/* + * This parameter will set interval to monitor wifi activity + * in passive scan in msec. + * Acceptable values for this: 0-25 + */ +#define CFG_ADAPT_DWELL_PASMON_INTVAL_NAME "adapt_dwell_passive_mon_intval" +#define CFG_ADAPT_DWELL_PASMON_INTVAL_MIN (0) +#define CFG_ADAPT_DWELL_PASMON_INTVAL_MAX (25) +#define CFG_ADAPT_DWELL_PASMON_INTVAL_DEFAULT (10) + +/* + * This parameter will set % of wifi activity used in passive scan 0-100. + * Acceptable values for this: 0-100 (in %) + */ +#define CFG_ADAPT_DWELL_WIFI_THRESH_NAME "adapt_dwell_wifi_act_threshold" +#define CFG_ADAPT_DWELL_WIFI_THRESH_MIN (0) +#define CFG_ADAPT_DWELL_WIFI_THRESH_MAX (100) +#define CFG_ADAPT_DWELL_WIFI_THRESH_DEFAULT (10) + +/* + * + * g_bug_on_reinit_failure - Enable/Disable bug on reinit + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to debug ssr reinit failure issues by raising vos bug so + * dumps can be collected. + * g_bug_on_reinit_failure = 0 wlan driver will only recover after driver + * unload and load + * g_bug_on_reinit_failure = 1 raise vos bug to collect dumps + * + * Related: gEnableSSR + * + * Supported Feature: SSR + * + * Usage: Internal/External + * + * + */ +#define CFG_BUG_ON_REINIT_FAILURE_NAME "g_bug_on_reinit_failure" +#define CFG_BUG_ON_REINIT_FAILURE_MIN (0) +#define CFG_BUG_ON_REINIT_FAILURE_MAX (1) +#define CFG_BUG_ON_REINIT_FAILURE_DEFAULT (1) + +/* + * + * gSub20ChannelWidth - Control sub 20 channel width (5/10 Mhz) + * @Min: 0 + * @Max: 2 + * @Default: 0 + * + * This ini is used to set the sub 20 channel width. + * gSub20ChannelWidth=0: indicates do not use Sub 20 MHz bandwidth + * gSub20ChannelWidth=1: Bring up SAP/STA in 5 MHz bandwidth + * gSub20ChannelWidth=2: Bring up SAP/STA in 10 MHz bandwidth + * + * Related: None + * + * Supported Feature: 5/10 Mhz channel width support + * + * Usage: Internal/External + * + * + */ +#define CFG_SUB_20_CHANNEL_WIDTH_NAME "gSub20ChannelWidth" +#define CFG_SUB_20_CHANNEL_WIDTH_MIN (WLAN_SUB_20_CH_WIDTH_NONE) +#define CFG_SUB_20_CHANNEL_WIDTH_MAX (WLAN_SUB_20_CH_WIDTH_10) +#define CFG_SUB_20_CHANNEL_WIDTH_DEFAULT (WLAN_SUB_20_CH_WIDTH_NONE) + +#define CFG_TGT_GTX_USR_CFG_NAME "tgt_gtx_usr_cfg" +#define CFG_TGT_GTX_USR_CFG_MIN (0) +#define CFG_TGT_GTX_USR_CFG_MAX (32) +#define CFG_TGT_GTX_USR_CFG_DEFAULT (32) + +#define CFG_SAP_INTERNAL_RESTART_NAME "gEnableSapInternalRestart" +#define CFG_SAP_INTERNAL_RESTART_MIN (0) +#define CFG_SAP_INTERNAL_RESTART_MAX (1) +#define CFG_SAP_INTERNAL_RESTART_DEFAULT (1) + +/* + * + * restart_beaconing_on_chan_avoid_event - control the beaconing entity to move + * away from active LTE channels + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to control the beaconing entity (SAP/GO) to move away from + * active LTE channels when channel avoidance event is received + * restart_beaconing_on_chan_avoid_event=0: Don't allow beaconing entity move + * from active LTE channels + * restart_beaconing_on_chan_avoid_event=1: Allow beaconing entity move from + * active LTE channels + * + * Related: None + * + * Supported Feature: channel avoidance + * + * Usage: Internal/External + * + * + */ +#define CFG_RESTART_BEACONING_ON_CH_AVOID_NAME "restart_beaconing_on_chan_avoid_event" +#define CFG_RESTART_BEACONING_ON_CH_AVOID_MIN (0) +#define CFG_RESTART_BEACONING_ON_CH_AVOID_MAX (1) +#define CFG_RESTART_BEACONING_ON_CH_AVOID_DEFAULT (1) +/* + * This parameter will avoid updating ap_sta_inactivity from hostapd.conf + * file. If a station does not send anything in ap_max_inactivity seconds, an + * empty data frame is sent to it in order to verify whether it is + * still in range. If this frame is not ACKed, the station will be + * disassociated and then deauthenticated. This feature is used to + * clear station table of old entries when the STAs move out of the + * range. + * Default : Disable + */ +#define CFG_SAP_MAX_INACTIVITY_OVERRIDE_NAME "gSapMaxInactivityOverride" +#define CFG_SAP_MAX_INACTIVITY_OVERRIDE_MIN (0) +#define CFG_SAP_MAX_INACTIVITY_OVERRIDE_MAX (1) +#define CFG_SAP_MAX_INACTIVITY_OVERRIDE_DEFAULT (0) + +/* + * + * rx_mode - Control to decide rx mode + * + * @Min: 0 + * @Max: (CFG_ENABLE_RX_THREAD | CFG_ENABLE_RPS | CFG_ENABLE_NAPI) + * @Default: MDM_PLATFORM - 0 + * HELIUMPLUS - CFG_ENABLE_NAPI + * Other cases - (CFG_ENABLE_RX_THREAD | CFG_ENABLE_NAPI) + * + * This ini is used to decide mode for the rx path + * + * Supported Feature: NAPI + * + * Usage: Internal + * + * + */ +#define CFG_RX_MODE_NAME "rx_mode" +#define CFG_RX_MODE_MIN (0) +#define CFG_RX_MODE_MAX (CFG_ENABLE_RX_THREAD | CFG_ENABLE_RPS | \ + CFG_ENABLE_NAPI) +#ifdef MDM_PLATFORM +#define CFG_RX_MODE_DEFAULT (0) +#elif defined(HELIUMPLUS) +#define CFG_RX_MODE_DEFAULT CFG_ENABLE_NAPI +#else +#define CFG_RX_MODE_DEFAULT (CFG_ENABLE_RX_THREAD | CFG_ENABLE_NAPI) +#endif + +/* List of RPS CPU maps for different rx queues registered by WLAN driver + * Ref - Kernel/Documentation/networking/scaling.txt + * RPS CPU map for a particular RX queue, selects CPU(s) for bottom half + * processing of RX packets. For example, for a system with 4 CPUs, + * 0xe: Use CPU1 - CPU3 and donot use CPU0. + * 0x0: RPS is disabled, packets are processed on the interrupting CPU. +.* + * WLAN driver registers NUM_TX_QUEUES queues for tx and rx each during + * alloc_netdev_mq. Hence, we need to have a cpu mask for each of the rx queues. + * + * For example, if the NUM_TX_QUEUES is 4, a sample WLAN ini entry may look like + * rpsRxQueueCpuMapList=a b c d + * For a 4 CPU system (CPU0 - CPU3), this implies: + * 0xa - (1010) use CPU1, CPU3 for rx queue 0 + * 0xb - (1011) use CPU0, CPU1 and CPU3 for rx queue 1 + * 0xc - (1100) use CPU2, CPU3 for rx queue 2 + * 0xd - (1101) use CPU0, CPU2 and CPU3 for rx queue 3 + + * In practice, we may want to avoid the cores which are heavily loaded. + */ + +/* Name of the ini file entry to specify RPS map for different RX queus */ +#define CFG_RPS_RX_QUEUE_CPU_MAP_LIST_NAME "rpsRxQueueCpuMapList" + +/* Default value of rpsRxQueueCpuMapList. Different platforms may have + * different configurations for NUM_TX_QUEUES and # of cpus, and will need to + * configure an appropriate value via ini file. Setting default value to 'e' to + * avoid use of CPU0 (since its heavily used by other system processes) by rx + * queue 0, which is currently being used for rx packet processing. + */ +#define CFG_RPS_RX_QUEUE_CPU_MAP_LIST_DEFAULT "e" + +/* Maximum length of string used to hold a list of cpu maps for various rx + * queues. Considering a 16 core system with 5 rx queues, a RPS CPU map + * list may look like - + * rpsRxQueueCpuMapList = ffff ffff ffff ffff ffff + * (all 5 rx queues can be processed on all 16 cores) + * max string len = 24 + 1(for '\0'). Considering 30 to be on safe side. + */ +#define CFG_RPS_RX_QUEUE_CPU_MAP_LIST_LEN 30 + +#ifdef WLAN_FEATURE_WOW_PULSE +/* + * Enable/Disable WOW PULSE feature + * Set the wakeup pulse which FW use to wake up HOST + * Default : Disable + */ +#define CFG_WOW_PULSE_SUPPORT_NAME "gwow_pulse_support" +#define CFG_WOW_PULSE_SUPPORT_MIN (0) +#define CFG_WOW_PULSE_SUPPORT_MAX (1) +#define CFG_WOW_PULSE_SUPPORT_DEFAULT (CFG_WOW_PULSE_SUPPORT_MIN) + +/* + * GPIO PIN for Pulse + * Which PIN to send the Pulse + */ +#define CFG_WOW_PULSE_PIN_NAME "gwow_pulse_pin" +#define CFG_WOW_PULSE_PIN_MIN (CFG_SET_TSF_GPIO_PIN_MIN) +#define CFG_WOW_PULSE_PIN_MAX (CFG_SET_TSF_GPIO_PIN_MAX) +#define CFG_WOW_PULSE_PIN_DEFAULT (35) + +/* + * Pulse interval low + * The interval of low level in the pulse + * The value which defined by customer should between 160 and 480 + */ +#define CFG_WOW_PULSE_INTERVAL_LOW_NAME "gwow_pulse_interval_low" +#define CFG_WOW_PULSE_INTERVAL_LOW_MIN (160) +#define CFG_WOW_PULSE_INTERVAL_LOW_MAX (480) +#define CFG_WOW_PULSE_INTERVAL_LOW_DEFAULT (180) + +/* + * Pulse interval high + * The interval of high level in the pulse + * The value which defined by customer should between 20 and 40 + */ +#define CFG_WOW_PULSE_INTERVAL_HIGH_NAME "gwow_pulse_interval_high" +#define CFG_WOW_PULSE_INTERVAL_HIGH_MIN (20) +#define CFG_WOW_PULSE_INTERVAL_HIGH_MAX (40) +#define CFG_WOW_PULSE_INTERVAL_HIGH_DEFAULT (20) +#endif + +/* + * Support to start sap in indoor channel + * Customer can config this item to enable/disable sap in indoor channel + * Default: Disable + */ +#define CFG_INDOOR_CHANNEL_SUPPORT_NAME "gindoor_channel_support" +#define CFG_INDOOR_CHANNEL_SUPPORT_MIN (0) +#define CFG_INDOOR_CHANNEL_SUPPORT_MAX (1) +#define CFG_INDOOR_CHANNEL_SUPPORT_DEFAULT (0) + +/* + * Force softap to 11n, when gSapForce11NFor11AC is set to 1 from ini + * despite of hostapd.conf request for 11ac + */ +#define CFG_SAP_FORCE_11N_FOR_11AC_NAME "gSapForce11NFor11AC" +#define CFG_SAP_FORCE_11N_FOR_11AC_MIN (0) +#define CFG_SAP_FORCE_11N_FOR_11AC_MAX (1) +#define CFG_SAP_FORCE_11N_FOR_11AC_DEFAULT (0) + +/* + * sap tx leakage threshold + * customer can set this value from 100 to 1000 which means + * sap tx leakage threshold is -10db to -100db + */ +#define CFG_SAP_TX_LEAKAGE_THRESHOLD_NAME "gsap_tx_leakage_threshold" +#define CFG_SAP_TX_LEAKAGE_THRESHOLD_MIN (100) +#define CFG_SAP_TX_LEAKAGE_THRESHOLD_MAX (1000) +#define CFG_SAP_TX_LEAKAGE_THRESHOLD_DEFAULT (310) + + +/* + * Enable filtering of replayed multicast packets + * In a typical infrastructure setup, it is quite normal to receive + * replayed multicast packets. These packets may cause more harm than + * help if not handled properly. Providing a configuration option + * to enable filtering of such packets + */ +#define CFG_FILTER_MULTICAST_REPLAY_NAME "enable_multicast_replay_filter" +#define CFG_FILTER_MULTICAST_REPLAY_MIN (0) +#define CFG_FILTER_MULTICAST_REPLAY_MAX (1) +#define CFG_FILTER_MULTICAST_REPLAY_DEFAULT (1) + +/* + * This parameter will control SIFS burst duration in FW from 0 to 12 ms. + * Default value is set to 8ms. + */ +#define CFG_SIFS_BURST_DURATION_NAME "g_sifs_burst_duration" +#define CFG_SIFS_BURST_DURATION_MIN (0) +#define CFG_SIFS_BURST_DURATION_MAX (12) +#define CFG_SIFS_BURST_DURATION_DEFAULT (8) + +/* Optimize channel avoidance indication comming from firmware */ +#define CFG_OPTIMIZE_CA_EVENT_NAME "goptimize_chan_avoid_event" +#define CFG_OPTIMIZE_CA_EVENT_DISABLE (0) +#define CFG_OPTIMIZE_CA_EVENT_ENABLE (1) +#define CFG_OPTIMIZE_CA_EVENT_DEFAULT (0) + +/* + * + * fw_timeout_crash - Enable/Disable BUG ON + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to Trigger host crash when firmware fails to send the + * response to host + * fw_timeout_crash = 0 Disabled + * fw_timeout_crash = 1 Trigger host crash + * + * Related: None + * + * Supported Feature: SSR + * + * Usage: Internal/External + * + * + */ +#define CFG_CRASH_FW_TIMEOUT_NAME "fw_timeout_crash" +#define CFG_CRASH_FW_TIMEOUT_DISABLE (0) +#define CFG_CRASH_FW_TIMEOUT_ENABLE (1) +#define CFG_CRASH_FW_TIMEOUT_DEFAULT (0) + +/* Hold wakelock for unicast RX packets for the specified duration */ +#define CFG_RX_WAKELOCK_TIMEOUT_NAME "rx_wakelock_timeout" +#define CFG_RX_WAKELOCK_TIMEOUT_DEFAULT (50) +#define CFG_RX_WAKELOCK_TIMEOUT_MIN (0) +#define CFG_RX_WAKELOCK_TIMEOUT_MAX (100) + +/* + * + * enable_5g_band_pref - Enable preference for 5G from INI. + * @Min: 0 + * @Max: 1 + * @Default: 0 + * This ini is used to enable 5G preference parameters. + * + * Related: 5g_rssi_boost_threshold, 5g_rssi_boost_factor, 5g_max_rssi_boost + * 5g_rssi_penalize_threshold, 5g_rssi_penalize_factor, 5g_max_rssi_penalize + * + * Supported Feature: 5G band preference + * + * Usage: External + * + * + */ + +#define CFG_ENABLE_5G_BAND_PREF_NAME "enable_5g_band_pref" +#define CFG_ENABLE_5G_BAND_PREF_MIN (0) +#define CFG_ENABLE_5G_BAND_PREF_MAX (1) +#define CFG_ENABLE_5G_BAND_PREF_DEFAULT (0) + +/* + * + * 5g_rssi_boost_threshold - A_band_boost_threshold above which 5 GHz is favored. + * @Min: -55 + * @Max: -70 + * @Default: -60 + * This ini is used to set threshold for 5GHz band preference. + * + * Related: 5g_rssi_boost_factor, 5g_max_rssi_boost + * 5g_rssi_penalize_threshold, 5g_rssi_penalize_factor, 5g_max_rssi_penalize + * + * Supported Feature: 5G band preference + * + * Usage: External + * + * + */ +#define CFG_5G_RSSI_BOOST_THRESHOLD_NAME "5g_rssi_boost_threshold" +#define CFG_5G_RSSI_BOOST_THRESHOLD_MIN (-55) +#define CFG_5G_RSSI_BOOST_THRESHOLD_MAX (-70) +#define CFG_5G_RSSI_BOOST_THRESHOLD_DEFAULT (-60) + +/* + * + * 5g_rssi_boost_factor - Factor by which 5GHz RSSI is boosted. + * @Min: 0 + * @Max: 2 + * @Default: 1 + * This ini is used to set the 5Ghz boost factor. + * + * Related: 5g_rssi_boost_threshold, 5g_max_rssi_boost + * 5g_rssi_penalize_threshold, 5g_rssi_penalize_factor, 5g_max_rssi_penalize + * + * Supported Feature: 5G band preference + * + * Usage: External + * + * + */ +#define CFG_5G_RSSI_BOOST_FACTOR_NAME "5g_rssi_boost_factor" +#define CFG_5G_RSSI_BOOST_FACTOR_MIN (0) +#define CFG_5G_RSSI_BOOST_FACTOR_MAX (2) +#define CFG_5G_RSSI_BOOST_FACTOR_DEFAULT (1) + +/* + * + * 5g_max_rssi_boost - Maximum boost that can be applied to 5GHz RSSI. + * @Min: 0 + * @Max: 20 + * @Default: 10 + * This ini is used to set maximum boost which can be given to a 5Ghz network. + * + * Related: 5g_rssi_boost_threshold, 5g_rssi_boost_factor + * 5g_rssi_penalize_threshold, 5g_rssi_penalize_factor, 5g_max_rssi_penalize + * + * Supported Feature: 5G band preference + * + * Usage: External + * + * + */ +#define CFG_5G_MAX_RSSI_BOOST_NAME "5g_max_rssi_boost" +#define CFG_5G_MAX_RSSI_BOOST_MIN (0) +#define CFG_5G_MAX_RSSI_BOOST_MAX (20) +#define CFG_5G_MAX_RSSI_BOOST_DEFAULT (10) + +/* + * + * 5g_rssi_penalize_threshold - A_band_penalize_threshold above which + * 5 GHz is not favored. + * @Min: -65 + * @Max: -80 + * @Default: -70 + * This ini is used to set threshold for 5GHz band preference. + * + * Related: 5g_rssi_penalize_factor, 5g_max_rssi_penalize + * 5g_rssi_boost_threshold, 5g_rssi_boost_factor, 5g_max_rssi_boost + * + * Supported Feature: 5G band preference + * + * Usage: External + * + * + */ +#define CFG_5G_RSSI_PENALIZE_THRESHOLD_NAME "5g_rssi_penalize_threshold" +#define CFG_5G_RSSI_PENALIZE_THRESHOLD_MIN (-65) +#define CFG_5G_RSSI_PENALIZE_THRESHOLD_MAX (-80) +#define CFG_5G_RSSI_PENALIZE_THRESHOLD_DEFAULT (-70) + +/* + * + * 5g_rssi_penalize_factor - Factor by which 5GHz RSSI is penalizeed. + * @Min: 0 + * @Max: 2 + * @Default: 1 + * This ini is used to set the 5Ghz penalize factor. + * + * Related: 5g_rssi_penalize_threshold, 5g_max_rssi_penalize + * 5g_rssi_boost_threshold, 5g_rssi_boost_factor, 5g_max_rssi_boost + * + * Supported Feature: 5G band preference + * + * Usage: External + * + * + */ +#define CFG_5G_RSSI_PENALIZE_FACTOR_NAME "5g_rssi_penalize_factor" +#define CFG_5G_RSSI_PENALIZE_FACTOR_MIN (0) +#define CFG_5G_RSSI_PENALIZE_FACTOR_MAX (2) +#define CFG_5G_RSSI_PENALIZE_FACTOR_DEFAULT (1) + +/* + * + * 5g_max_rssi_penalize - Maximum penalty that can be applied to 5GHz RSSI. + * @Min: 0 + * @Max: 20 + * @Default: 10 + * This ini is used to set maximum penalty which can be given to a 5Ghz network. + * + * Related: 5g_rssi_penalize_threshold, 5g_rssi_penalize_factor + * 5g_rssi_boost_threshold, 5g_rssi_boost_factor, 5g_max_rssi_boost + * + * Supported Feature: 5G band preference + * + * Usage: External + * + * + */ +#define CFG_5G_MAX_RSSI_PENALIZE_NAME "5g_max_rssi_penalize" +#define CFG_5G_MAX_RSSI_PENALIZE_MIN (0) +#define CFG_5G_MAX_RSSI_PENALIZE_MAX (20) +#define CFG_5G_MAX_RSSI_PENALIZE_DEFAULT (10) + +#ifdef WLAN_FEATURE_UDP_RESPONSE_OFFLOAD +/* + * Enable/Disable UDP response offload feature + * Default : Disable + */ +#define CFG_UDP_RESP_OFFLOAD_SUPPORT_NAME "gudp_resp_offload_support" +#define CFG_UDP_RESP_OFFLOAD_SUPPORT_MIN (0) +#define CFG_UDP_RESP_OFFLOAD_SUPPORT_MAX (1) +#define CFG_UDP_RESP_OFFLOAD_SUPPORT_DEFAULT (CFG_UDP_RESP_OFFLOAD_SUPPORT_MIN) + +/* Dest port of specific UDP packet */ +#define CFG_UDP_RESP_OFFLOAD_DEST_PORT_NAME "gudp_resp_offload_dest_port" +#define CFG_UDP_RESP_OFFLOAD_DEST_PORT_MIN (0) +#define CFG_UDP_RESP_OFFLOAD_DEST_PORT_MAX (65535) +#define CFG_UDP_RESP_OFFLOAD_DEST_PORT_DEFAULT (CFG_UDP_RESP_OFFLOAD_DEST_PORT_MAX) + +/* + * Payload filter of specific UDP packet + * Firmware will use this filter to identify the specific UDP packet + */ +#define CFG_UDP_RESP_OFFLOAD_PAYLOAD_FILTER_NAME "gudp_resp_offload_payload_filter" +#define CFG_UDP_RESP_OFFLOAD_PAYLOAD_FILTER_DEFAULT "" + +/* + * Payload of the response UDP + * The specific response UDP packet payload + */ +#define CFG_UDP_RESP_OFFLOAD_RESPONSE_PAYLOAD_NAME "gudp_resp_offload_response_payload" +#define CFG_UDP_RESP_OFFLOAD_RESPONSE_PAYLOAD_DEFAULT "status=off" +#endif + +/* + * + * g_max_sched_scan_plan_int - pno sched max scan plan interval. + * @Min: 1 + * @Max: 7200 + * @Default: 3600 + * This ini is used to set max sched scan plan interval for pno scan + * (value in seconds). + * + * Related: gPNOScanSupport + * + * Supported Feature: PNO scan + * + * Usage: External + * + * + */ +#define CFG_MAX_SCHED_SCAN_PLAN_INT_NAME "g_max_sched_scan_plan_int" +#define CFG_MAX_SCHED_SCAN_PLAN_INT_MIN (1) +#define CFG_MAX_SCHED_SCAN_PLAN_INT_MAX (7200) +#define CFG_MAX_SCHED_SCAN_PLAN_INT_DEFAULT (3600) + +/* + * + * g_max_sched_scan_plan_iterations - pno sched max scan plan iterations. + * @Min: 1 + * @Max: 100 + * @Default: 10 + * + * This ini is used to set max sched scan plan iterations for pno scan + * (value in seconds). + * Related: gPNOScanSupport + * Supported Feature: PNO scan + * + * Usage: External + * + * + */ +#define CFG_MAX_SCHED_SCAN_PLAN_ITRNS_NAME "g_max_sched_scan_plan_iterations" +#define CFG_MAX_SCHED_SCAN_PLAN_ITRNS_MIN (1) +#define CFG_MAX_SCHED_SCAN_PLAN_ITRNS_MAX (100) +#define CFG_MAX_SCHED_SCAN_PLAN_ITRNS_DEFAULT (10) + +/* + * + * gper_roam_enabled - To enabled/disable PER based roaming in FW + * @Min: 0 + * @Max: 3 + * @Default: 0 + * + * This ini is used to enable/disable Packet error based roaming, enabling this + * will cause DUT to monitor Tx and Rx traffic and roam to a better candidate + * if current is not good enough. + * + * Values supported: + * 0: disabled + * 1: enabled for Rx traffic + * 2: enabled for Tx traffic + * 3: enabled for Tx and Rx traffic + * + * Related: gper_roam_high_rate_th, gper_roam_low_rate_th, + * gper_roam_th_percent, gper_roam_rest_time + * + * Supported Feature: LFR-3.0 + * + * Usage: Internal + * + * + */ +#define CFG_PER_ROAM_ENABLE_NAME "gper_roam_enabled" +#define CFG_PER_ROAM_ENABLE_MIN (0) +#define CFG_PER_ROAM_ENABLE_MAX (3) +#define CFG_PER_ROAM_ENABLE_DEFAULT (3) + +/* + * + * gper_roam_high_rate_th - Rate at which PER based roam will stop + * @Min: 1 Mbps + * @Max: 0xffffffff + * @Default: 40 Mbps + * + * This ini is used to define the data rate in mbps*10 at which FW will stop + * monitoring the traffic for PER based roam. + * + * Related: gper_roam_enabled, gper_roam_low_rate_th, + * gper_roam_th_percent, gper_roam_rest_time + * + * Supported Feature: LFR-3.0 + * + * Usage: Internal + * + * + */ +#define CFG_PER_ROAM_CONFIG_HIGH_RATE_TH_NAME "gper_roam_high_rate_th" +#define CFG_PER_ROAM_CONFIG_HIGH_RATE_TH_MIN (10) +#define CFG_PER_ROAM_CONFIG_HIGH_RATE_TH_MAX (0xffffffff) +#define CFG_PER_ROAM_CONFIG_HIGH_RATE_TH_DEFAULT (400) + +/* + * + * gper_roam_low_rate_th - Rate at which FW starts considering traffic for PER + * based roam. + * + * @Min: 1 Mbps + * @Max: 0xffffffff + * @Default: 20 Mbps + * + * This ini is used to define the rate in mbps*10 at which FW starts considering + * traffic for PER based roam, if gper_roam_th_percent of data is below this + * rate, FW will issue a roam scan. + * + * Related: gper_roam_enabled, gper_roam_high_rate_th, + * gper_roam_th_percent, gper_roam_rest_time + * + * Supported Feature: LFR-3.0 + * + * Usage: Internal + * + * + */ +#define CFG_PER_ROAM_CONFIG_LOW_RATE_TH_NAME "gper_roam_low_rate_th" +#define CFG_PER_ROAM_CONFIG_LOW_RATE_TH_MIN (10) +#define CFG_PER_ROAM_CONFIG_LOW_RATE_TH_MAX (0xffffffff) +#define CFG_PER_ROAM_CONFIG_LOW_RATE_TH_DEFAULT (200) + +/* + * + * gper_roam_th_percent - Percentage at which FW will issue a roam scan if + * traffic is below gper_roam_low_rate_th rate. + * + * @Min: 10% + * @Max: 100% + * @Default: 60% + * + * This ini is used to define the percentage at which FW will issue a roam scan + * if traffic is below gper_roam_low_rate_th rate. + * + * Related: gper_roam_enabled, gper_roam_high_rate_th, + * gper_roam_high_rate_th, gper_roam_rest_time + * + * Supported Feature: LFR-3.0 + * + * Usage: Internal + * + * + */ +#define CFG_PER_ROAM_CONFIG_RATE_TH_PERCENT_NAME "gper_roam_th_percent" +#define CFG_PER_ROAM_CONFIG_RATE_TH_PERCENT_MIN (10) +#define CFG_PER_ROAM_CONFIG_RATE_TH_PERCENT_MAX (100) +#define CFG_PER_ROAM_CONFIG_RATE_TH_PERCENT_DEFAULT (60) + +/* + * + * gper_roam_rest_time - Time for which FW will wait once it issues a + * roam scan. + * + * @Min: 10 seconds + * @Max: 3600 seconds + * @Default: 300 seconds + * + * This ini is used to define the time for which FW will wait once it issues a + * PER based roam scan. + * + * Related: gper_roam_enabled, gper_roam_high_rate_th, + * gper_roam_high_rate_th, gper_roam_th_percent + * + * Supported Feature: LFR-3.0 + * + * Usage: Internal + * + * + */ +#define CFG_PER_ROAM_REST_TIME_NAME "gper_roam_rest_time" +#define CFG_PER_ROAM_REST_TIME_MIN (10) +#define CFG_PER_ROAM_REST_TIME_MAX (3600) +#define CFG_PER_ROAM_REST_TIME_DEFAULT (300) + +/* + * + * gper_roam_mon_time - Minimum time required in seconds to + * be considered as valid scenario for PER based roam + * @Min: 5 + * @Max: 25 + * @Default: 25 + * + * This ini is used to define minimum time in seconds for which DUT has + * collected the PER stats before it can consider the stats hysteresis to be + * valid for PER based scan. + * DUT collects following information during this period: + * 1. % of packets below gper_roam_low_rate_th + * 2. # packets above gper_roam_high_rate_th + * if DUT gets (1) greater than gper_roam_th_percent and (2) is zero during + * this period, it triggers PER based roam scan. + * + * Related: gper_roam_enabled, gper_roam_high_rate_th, gper_roam_low_rate_th, + * gper_roam_th_percent, gper_roam_rest_time + * + * Supported Feature: LFR-3.0 + * + * Usage: Internal + * + * + */ +#define CFG_PER_ROAM_MONITOR_TIME "gper_roam_mon_time" +#define CFG_PER_ROAM_MONITOR_TIME_MIN (5) +#define CFG_PER_ROAM_MONITOR_TIME_MAX (25) +#define CFG_PER_ROAM_MONTIOR_TIME_DEFAULT (25) + +/* + * + * gper_min_rssi_threshold_for_roam - Minimum roamable AP RSSI for + * candidate selection for PER based roam + * @Min: 0 + * @Max: 96 + * @Default: 83 + * + * Minimum roamable AP RSSI for candidate selection for PER based roam + * + * Related: gper_roam_enabled, gper_roam_high_rate_th, gper_roam_low_rate_th, + * gper_roam_th_percent, gper_roam_rest_time + * + * Supported Feature: LFR-3.0 + * + * Usage: Internal + * + * + */ +#define CFG_PER_ROAM_MIN_CANDIDATE_RSSI "gper_min_rssi_threshold_for_roam" +#define CFG_PER_ROAM_MIN_CANDIDATE_RSSI_MIN (0) +#define CFG_PER_ROAM_MIN_CANDIDATE_RSSI_MAX (96) +#define CFG_PER_ROAM_MIN_CANDIDATE_RSSI_DEFAULT (83) + +/* + * + * gPowerUsage - Preferred Power Usage + * @Min: Min + * @Max: Max + * @Default: Mod + * + * This ini is used to set the preferred power usage + * + * Related: None + * + * Supported Feature: Power Save + * + * Usage: External + * + * + */ +#define CFG_POWER_USAGE_NAME "gPowerUsage" +#define CFG_POWER_USAGE_MIN "Min" +#define CFG_POWER_USAGE_MAX "Max" +#define CFG_POWER_USAGE_DEFAULT "Mod" + +/* + * + * gWowlPattern - WOW Pattern to used when PBM filtering is enabled + * @Default: + * + * This ini is used to set the WOW Pattern to be used for PBM Filtering + * + * Related: gMaxWoWFilters + * + * Supported Feature: Power Save + * + * Usage: External + * + * + */ +#define CFG_WOWL_PATTERN_NAME "gWowlPattern" +#define CFG_WOWL_PATTERN_DEFAULT "" + +/* + * + * gMaxWoWFilters - Maximum WoW patterns that can be configured + * @Min: 0 + * @Max: WOW_MAX_BITMAP_FILTERS(32) + * @Default: WOW_MAX_BITMAP_FILTERS(32) + * + * This ini is used to set the maximum WoW patterns that can be configured + * + * Related: gWowlPattern + * + * Supported Feature: Power Save + * + * Usage: External + * + * + */ +#define CFG_MAX_WOW_FILTERS_NAME "gMaxWoWFilters" +#define CFG_MAX_WOW_FILTERS_MIN (0) +#define CFG_MAX_WOW_FILTERS_MAX (WOW_MAX_BITMAP_FILTERS) +#define CFG_MAX_WOW_FILTERS_DEFAULT (WOW_MAX_BITMAP_FILTERS) + +/* + * + * gEnableImps - Enable/Disable IMPS + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to enable/Disable IMPS(IdleModePowerSave) Mode + * + * Related: None + * + * Supported Feature: Power Save + * + * Usage: External + * + * + */ +#define CFG_ENABLE_IMPS_NAME "gEnableImps" +#define CFG_ENABLE_IMPS_MIN (0) +#define CFG_ENABLE_IMPS_MAX (1) +#define CFG_ENABLE_IMPS_DEFAULT (1) + +/* + * + * gEnableBmps - Enable/Disable BMPS + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to enable/Disable BMPS(BeaconModePowerSave) Mode + * + * Related: None + * + * Supported Feature: Power Save + * + * Usage: External + * + * + */ +#define CFG_ENABLE_PS_NAME "gEnableBmps" +#define CFG_ENABLE_PS_MIN (0) +#define CFG_ENABLE_PS_MAX (1) +#define CFG_ENABLE_PS_DEFAULT (1) + +/* + * + * gAutoBmpsTimerValue - Set Auto BMPS Timer value + * @Min: 0 + * @Max: 120 + * @Default: 0 + * + * This ini is used to set Auto BMPS Timer value in seconds + * + * Related: gEnableBmps + * + * Supported Feature: Power Save + * + * Usage: External + * + * + */ +#define CFG_AUTO_PS_ENABLE_TIMER_NAME "gAutoBmpsTimerValue" +#define CFG_AUTO_PS_ENABLE_TIMER_MIN (0) +#define CFG_AUTO_PS_ENABLE_TIMER_MAX (120) +#define CFG_AUTO_PS_ENABLE_TIMER_DEFAULT (0) + +/* + * + * gBmpsMinListenInterval - Set BMPS Minimum Listen Interval + * @Min: 1 + * @Max: 65535 + * @Default: 1 + * + * This ini is used to set BMPS Minimum Listen Interval. If gPowerUsage + * is set "Min", this INI need to be set. + * + * Related: gEnableBmps, gPowerUsage + * + * Supported Feature: Power Save + * + * Usage: External + * + * + */ +#define CFG_BMPS_MINIMUM_LI_NAME "gBmpsMinListenInterval" +#define CFG_BMPS_MINIMUM_LI_MIN (1) +#define CFG_BMPS_MINIMUM_LI_MAX (65535) +#define CFG_BMPS_MINIMUM_LI_DEFAULT (1) + +/* + * + * gBmpsModListenInterval - Set BMPS Moderate Listen Interval + * @Min: 1 + * @Max: 65535 + * @Default: 1 + * + * This ini is used to set BMPS Moderate Listen Interval. If gPowerUsage + * is set "Mod", this INI need to be set. + * + * Related: gEnableBmps, gPowerUsage + * + * Supported Feature: Power Save + * + * Usage: External + * + * + */ +#define CFG_BMPS_MODERATE_LI_NAME "gBmpsModListenInterval" +#define CFG_BMPS_MODERATE_LI_MIN (1) +#define CFG_BMPS_MODERATE_LI_MAX (65535) +#define CFG_BMPS_MODERATE_LI_DEFAULT (1) + +/* + * + * gBmpsMaxListenInterval - Set BMPS Maximum Listen Interval + * @Min: 1 + * @Max: 65535 + * @Default: 1 + * + * This ini is used to set BMPS Maximum Listen Interval. If gPowerUsage + * is set "Max", this INI need to be set. + * + * Related: gEnableBmps, gPowerUsage + * + * Supported Feature: Power Save + * + * Usage: External + * + * + */ +#define CFG_BMPS_MAXIMUM_LI_NAME "gBmpsMaxListenInterval" +#define CFG_BMPS_MAXIMUM_LI_MIN (1) +#define CFG_BMPS_MAXIMUM_LI_MAX (65535) +#define CFG_BMPS_MAXIMUM_LI_DEFAULT (1) + +#ifdef FEATURE_RUNTIME_PM +/* + * + * gRuntimePM - enable runtime suspend + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to enable runtime_suspend + * + * Related: None + * + * Supported Feature: Power Save + * + * Usage: External + * + * + */ +#define CFG_ENABLE_RUNTIME_PM "gRuntimePM" +#define CFG_ENABLE_RUNTIME_PM_MIN (0) +#define CFG_ENABLE_RUNTIME_PM_MAX (1) +#define CFG_ENABLE_RUNTIME_PM_DEFAULT (0) + +/* + * + * gRuntimePMDelay - Set runtime pm's inactivity timer + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to set runtime pm's inactivity timer value. + * the wlan driver will wait for this number of milliseconds of + * inactivity before performing a runtime suspend. + * + * Related: gRuntimePM + * + * Supported Feature: Power Save + * + * Usage: External + * + * + */ +#define CFG_RUNTIME_PM_DELAY_NAME "gRuntimePMDelay" +#define CFG_RUNTIME_PM_DELAY_MIN (100) +#define CFG_RUNTIME_PM_DELAY_MAX (10000) +#define CFG_RUNTIME_PM_DELAY_DEFAULT (500) +#endif + +/* + * + * gEnablePowerSaveOffload - Enable Power Save Offload + * @Min: 0 + * @Max: 5 + * @Default: 0 + * + * This ini is used to set Power Save Offload configuration: + * Current values of gEnablePowerSaveOffload: + * 0 -> Power save offload is disabled + * 1 -> Legacy Power save enabled + Deep sleep Disabled + * 2 -> QPower enabled + Deep sleep Disabled + * 3 -> Legacy Power save enabled + Deep sleep Enabled + * 4 -> QPower enabled + Deep sleep Enabled + * 5 -> Duty cycling QPower enabled + * + * Related: None + * + * Supported Feature: Power Save + * + * Usage: External + * + * + */ +#define CFG_POWERSAVE_OFFLOAD_NAME "gEnablePowerSaveOffload" +#define CFG_POWERSAVE_OFFLOAD_MIN (0) +#define CFG_POWERSAVE_OFFLOAD_MAX (PS_DUTY_CYCLING_QPOWER) +#define CFG_POWERSAVE_OFFLOAD_DEFAULT (CFG_POWERSAVE_OFFLOAD_MIN) + +/* + * + * gEnableWoW - Enable/Disable WoW + * @Min: 0 + * @Max: 3 + * @Default: 3 + * + * This ini is used to enable/disable WoW. Configurations are as follows: + * 0 - Disable both magic pattern match and pattern byte match. + * 1 - Enable magic pattern match on all interfaces. + * 2 - Enable pattern byte match on all interfaces. + * 3 - Enable both magic patter and pattern byte match on all interfaces. + * + * Related: None + * + * Supported Feature: Power Save + * + * Usage: External + * + * + */ +#define CFG_WOW_STATUS_NAME "gEnableWoW" +#define CFG_WOW_ENABLE_MIN (0) +#define CFG_WOW_ENABLE_MAX (3) +#define CFG_WOW_STATUS_DEFAULT (3) + +#ifdef WLAN_FEATURE_EXTWOW_SUPPORT +/* + * + * gExtWoWgotoSuspend - Enable/Disable Extended WoW + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to enable/disable Extended WoW. + * + * Related: None + * + * Supported Feature: Power Save + * + * Usage: External + * + * + */ +#define CFG_EXTWOW_GO_TO_SUSPEND "gExtWoWgotoSuspend" +#define CFG_EXTWOW_GO_TO_SUSPEND_MIN (0) +#define CFG_EXTWOW_GO_TO_SUSPEND_MAX (1) +#define CFG_EXTWOW_GO_TO_SUSPEND_DEFAULT (1) + +/* + * + * gExtWowApp1WakeupPinNumber - Set wakeup1 PIN number + * @Min: 0 + * @Max: 255 + * @Default: 12 + * + * This ini is used to set EXT WOW APP1 wakeup PIN number + * + * Related: None + * + * Supported Feature: Power Save + * + * Usage: External + * + * + */ +#define CFG_EXTWOW_APP1_WAKE_PIN_NUMBER "gExtWowApp1WakeupPinNumber" +#define CFG_EXTWOW_APP1_WAKE_PIN_NUMBER_MIN (0) +#define CFG_EXTWOW_APP1_WAKE_PIN_NUMBER_MAX (255) +#define CFG_EXTWOW_APP1_WAKE_PIN_NUMBER_DEFAULT (12) + +/* + * + * gExtWowApp2WakeupPinNumber - Set wakeup2 PIN number + * @Min: 0 + * @Max: 255 + * @Default: 16 + * + * This ini is used to set EXT WOW APP2 wakeup PIN number + * + * Related: None + * + * Supported Feature: Power Save + * + * Usage: External + * + * + */ +#define CFG_EXTWOW_APP2_WAKE_PIN_NUMBER "gExtWowApp2WakeupPinNumber" +#define CFG_EXTWOW_APP2_WAKE_PIN_NUMBER_MIN (0) +#define CFG_EXTWOW_APP2_WAKE_PIN_NUMBER_MAX (255) +#define CFG_EXTWOW_APP2_WAKE_PIN_NUMBER_DEFAULT (16) + +/* + * + * gExtWoWApp2KAInitPingInterval - Set Keep Alive Init Ping Interval + * @Min: 0 + * @Max: 0xffffffff + * @Default: 240 + * + * This ini is used to set Keep Alive Init Ping Interval for EXT WOW + * + * Related: None + * + * Supported Feature: Power Save + * + * Usage: External + * + * + */ +#define CFG_EXTWOW_KA_INIT_PING_INTERVAL "gExtWoWApp2KAInitPingInterval" +#define CFG_EXTWOW_KA_INIT_PING_INTERVAL_MIN (0) +#define CFG_EXTWOW_KA_INIT_PING_INTERVAL_MAX (0xffffffff) +#define CFG_EXTWOW_KA_INIT_PING_INTERVAL_DEFAULT (240) + +/* + * + * gExtWoWApp2KAMinPingInterval - Set Keep Alive Minimum Ping Interval + * @Min: 0 + * @Max: 0xffffffff + * @Default: 240 + * + * This ini is used to set Keep Alive Minimum Ping Interval for EXT WOW + * + * Related: None + * + * Supported Feature: Power Save + * + * Usage: External + * + * + */ +#define CFG_EXTWOW_KA_MIN_PING_INTERVAL "gExtWoWApp2KAMinPingInterval" +#define CFG_EXTWOW_KA_MIN_PING_INTERVAL_MIN (0) +#define CFG_EXTWOW_KA_MIN_PING_INTERVAL_MAX (0xffffffff) +#define CFG_EXTWOW_KA_MIN_PING_INTERVAL_DEFAULT (240) + +/* + * + * gExtWoWApp2KAMaxPingInterval - Set Keep Alive Maximum Ping Interval + * @Min: 0 + * @Max: 0xffffffff + * @Default: 1280 + * + * This ini is used to set Keep Alive Maximum Ping Interval for EXT WOW + * + * Related: None + * + * Supported Feature: Power Save + * + * Usage: External + * + * + */ +#define CFG_EXTWOW_KA_MAX_PING_INTERVAL "gExtWoWApp2KAMaxPingInterval" +#define CFG_EXTWOW_KA_MAX_PING_INTERVAL_MIN (0) +#define CFG_EXTWOW_KA_MAX_PING_INTERVAL_MAX (0xffffffff) +#define CFG_EXTWOW_KA_MAX_PING_INTERVAL_DEFAULT (1280) + +/* + * + * gExtWoWApp2KAIncPingInterval - Set Keep Alive increment of Ping Interval + * @Min: 0 + * @Max: 0xffffffff + * @Default: 4 + * + * This ini is used to set Keep Alive increment of Ping Interval for EXT WOW + * + * Related: None + * + * Supported Feature: Power Save + * + * Usage: External + * + * + */ +#define CFG_EXTWOW_KA_INC_PING_INTERVAL "gExtWoWApp2KAIncPingInterval" +#define CFG_EXTWOW_KA_INC_PING_INTERVAL_MIN (0) +#define CFG_EXTWOW_KA_INC_PING_INTERVAL_MAX (0xffffffff) +#define CFG_EXTWOW_KA_INC_PING_INTERVAL_DEFAULT (4) + +/* + * + * gExtWoWApp2KAIncPingInterval - Set TCP source port + * @Min: 0 + * @Max: 65535 + * @Default: 5000 + * + * This ini is used to set TCP source port when EXT WOW is enabled + * + * Related: None + * + * Supported Feature: Power Save + * + * Usage: External + * + * + */ +#define CFG_EXTWOW_TCP_SRC_PORT "gExtWoWApp2TcpSrcPort" +#define CFG_EXTWOW_TCP_SRC_PORT_MIN (0) +#define CFG_EXTWOW_TCP_SRC_PORT_MAX (65535) +#define CFG_EXTWOW_TCP_SRC_PORT_DEFAULT (5000) + +/* + * + * gExtWoWApp2TcpDstPort - Set TCP Destination port + * @Min: 0 + * @Max: 65535 + * @Default: 5001 + * + * This ini is used to set TCP Destination port when EXT WOW is enabled + * + * Related: None + * + * Supported Feature: Power Save + * + * Usage: External + * + * + */ +#define CFG_EXTWOW_TCP_DST_PORT "gExtWoWApp2TcpDstPort" +#define CFG_EXTWOW_TCP_DST_PORT_MIN (0) +#define CFG_EXTWOW_TCP_DST_PORT_MAX (65535) +#define CFG_EXTWOW_TCP_DST_PORT_DEFAULT (5001) + +/* + * + * gExtWoWApp2TcpTxTimeout - Set TCP tx timeout + * @Min: 0 + * @Max: 0xffffffff + * @Default: 200 + * + * This ini is used to set TCP Tx timeout when EXT WOW is enabled + * + * Related: None + * + * Supported Feature: Power Save + * + * Usage: External + * + * + */ +#define CFG_EXTWOW_TCP_TX_TIMEOUT "gExtWoWApp2TcpTxTimeout" +#define CFG_EXTWOW_TCP_TX_TIMEOUT_MIN (0) +#define CFG_EXTWOW_TCP_TX_TIMEOUT_MAX (0xffffffff) +#define CFG_EXTWOW_TCP_TX_TIMEOUT_DEFAULT (200) + +/* + * + * gExtWoWApp2TcpRxTimeout - Set TCP rx timeout + * @Min: 0 + * @Max: 0xffffffff + * @Default: 200 + * + * This ini is used to set TCP Rx timeout when EXT WOW is enabled + * + * Related: None + * + * Supported Feature: Power Save + * + * Usage: External + * + * + */ +#define CFG_EXTWOW_TCP_RX_TIMEOUT "gExtWoWApp2TcpRxTimeout" +#define CFG_EXTWOW_TCP_RX_TIMEOUT_MIN (0) +#define CFG_EXTWOW_TCP_RX_TIMEOUT_MAX (0xffffffff) +#define CFG_EXTWOW_TCP_RX_TIMEOUT_DEFAULT (200) +#endif + +/* + * + * gEnableFastPwrTransition - Configuration for fast power transition + * @Min: 0 + * @Max: 2 + * @Default: 0 + * + * This ini supported values: + * 0x0: Phy register retention disabled (Higher timeline, Good for power) + * 0x1: Phy register retention statically enabled + * 0x2: Phy register retention enabled/disabled dynamically + * + * Usage: Internal + * + * + */ +#define CFG_ENABLE_PHY_REG_NAME "gEnableFastPwrTransition" +#define CFG_PHY_REG_DEFAULT (0x0) +#define CFG_PHY_REG_MIN (0x0) +#define CFG_PHY_REG_MAX (0x2) + +/* + * + * gActiveBpfMode - Control active BPF mode + * @Min: 0 (disabled) + * @Max: 2 (adaptive) + * @Default: 0 (disabled) + * + * This config item is used to control BPF in active mode. There are 3 modes: + * 0) disabled - BPF is disabled in active mode + * 1) enabled - BPF is enabled for all packets in active mode + * 2) adaptive - BPF is enabled for packets up to some throughput threshold + * + * Related: N/A + * + * Supported Feature: Active Mode BPF + * + * Usage: Internal/External + * + */ +#define CFG_ACTIVE_BPF_MODE_NAME "gActiveBpfMode" +#define CFG_ACTIVE_BPF_MODE_MIN (ACTIVE_BPF_DISABLED) +#define CFG_ACTIVE_BPF_MODE_MAX (ACTIVE_BPF_MODE_COUNT - 1) +#define CFG_ACTIVE_BPF_MODE_DEFAULT (ACTIVE_BPF_DISABLED) + +enum hw_filter_mode { + HW_FILTER_DISABLED = 0, + HW_FILTER_NON_ARP_BC = 1, + HW_FILTER_NON_ICMPV6_MC = 2, +}; + +/* + * + * gHwFilterMode - configure hardware filter for DTIM mode + * @Min: 0 + * @Max: 3 + * @Default: 0 + * + * The hardware filter is only effective in DTIM mode. Use this configuration + * to blanket drop broadcast/multicast packets at the hardware level, without + * waking up the firmware + * + * Takes a bitmap of frame types to drop + * @E.g. + * # disable feature (default) + * gHwFilterMode=0 + * # drop all broadcast frames, except ARP + * gHwFilterMode=1 + * # drop all multicast frames, except ICMPv6 + * gHwFilterMode=2 + * # drop all broadcast and multicast frames, except ARP and ICMPv6 + * gHwFilterMode=3 + * + * Related: N/A + * + * Usage: Internal/External + * + * + */ +#define CFG_HW_FILTER_MODE_NAME "gHwFilterMode" +#define CFG_HW_FILTER_MODE_MIN (0) +#define CFG_HW_FILTER_MODE_MAX (3) +#define CFG_HW_FILTER_MODE_DEFAULT (0) + +/* + * + * g_enable_bcast_probe_rsp - Enable Broadcast probe response. + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to enable/disable broadcast probe response + * + * Related: None + * + * Supported Feature: FILS + * + * Usage: External + * + * + */ +#define CFG_ENABLE_BCAST_PROBE_RESP_NAME "g_enable_bcast_probe_rsp" +#define CFG_ENABLE_BCAST_PROBE_RESP_MIN (0) +#define CFG_ENABLE_BCAST_PROBE_RESP_MAX (1) +#define CFG_ENABLE_BCAST_PROBE_RESP_DEFAULT (1) + +/* + * + * g_qcn_ie_support - QCN IE Support + * @Min: 0 (disabled) + * @Max: 1 (enabled) + * @Default: 1 (enabled) + * + * This config item is used to support QCN IE in probe/assoc/reassoc request + * for STA mode. QCN IE support is not added for SAP mode. + * + * Related: N/A + * + * Supported Feature: N/A + * + * Usage: Internal/External + * + * + */ +#define CFG_QCN_IE_SUPPORT_NAME "g_qcn_ie_support" +#define CFG_QCN_IE_SUPPORT_MIN 0 +#define CFG_QCN_IE_SUPPORT_MAX 1 +#define CFG_QCN_IE_SUPPORT_DEFAULT 1 + +/* + * + * g_fils_max_chan_guard_time - Set maximum channel guard time(ms) + * @Min: 0 + * @Max: 10 + * @Default: 0 + * + * This ini is used to set maximum channel guard time in milli seconds + * + * Related: None + * + * Supported Feature: FILS + * + * Usage: External + * + * + */ +#define CFG_FILS_MAX_CHAN_GUARD_TIME_NAME "g_fils_max_chan_guard_time" +#define CFG_FILS_MAX_CHAN_GUARD_TIME_MIN (0) +#define CFG_FILS_MAX_CHAN_GUARD_TIME_MAX (10) +#define CFG_FILS_MAX_CHAN_GUARD_TIME_DEFAULT (0) + +/* + * + * g_enable_packet_filter_bitmap - Enable Packet filters before going into + * suspend mode + * @Min: 0 + * @Max: 63 + * @Default: 0 + * Below is the Detailed bit map of the Filters + * bit-0 : IPv6 multicast + * bit-1 : IPv4 multicast + * bit-2 : IPv4 broadcast + * bit-3 : XID - Exchange station Identification packet, solicits the + * identification of the receiving station + * bit-4 : STP - Spanning Tree Protocol, builds logical loop free topology + * bit-5 : DTP/LLC/CDP + * DTP - Dynamic Trunking Protocol is used by Ciscoswitches to negotiate + * whether an interconnection between two switches should be put into access or + * trunk mode + * LLC - Logical link control, used for multiplexing, flow & error control + * CDP - Cisco Discovery Protocol packet contains information about the cisco + * devices in the network + * + * This ini support to enable above mentioned packet filters + * when target goes to suspend mode, clear those when resume + * + * Related: None + * + * Supported Feature: PACKET FILTERING + * + * Usage: Internal/External + * + * + */ +#define CFG_ENABLE_PACKET_FILTERS_NAME "g_enable_packet_filter_bitmap" +#define CFG_ENABLE_PACKET_FILTERS_DEFAULT (0) +#define CFG_ENABLE_PACKET_FILTERS_MIN (0) +#define CFG_ENABLE_PACKET_FILTERS_MAX (63) + +/* + * g_is_bssid_hint_priority - Set priority for connection with bssid_hint + * BSSID. + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to give priority to BSS for connection which comes + * as part of bssid_hint + * + * Related: None + * + * Supported Feature: STA + * + * Usage: External + * + * + */ +#define CFG_IS_BSSID_HINT_PRIORITY_NAME "g_is_bssid_hint_priority" +#define CFG_IS_BSSID_HINT_PRIORITY_DEFAULT (1) +#define CFG_IS_BSSID_HINT_PRIORITY_MIN (0) +#define CFG_IS_BSSID_HINT_PRIORITY_MAX (1) + +/*--------------------------------------------------------------------------- + Type declarations + -------------------------------------------------------------------------*/ + +/* + * + * g_auto_detect_power_failure_mode - auto detect power save failure mode + * @Min: 0 : Recovery + * @Max: 1 : WMI + * @Default: 0 + * + * This ini specifies the behavior of FW in case of + * CHIP_POWER_SAVE_FAIL_DETECTED event + * + * Usage: External + * + * + */ +#define CFG_AUTO_DETECT_POWER_FAIL_MODE_NAME "g_auto_detect_power_failure_mode" +#define CFG_AUTO_DETECT_POWER_FAIL_MODE_MIN (0) +#define CFG_AUTO_DETECT_POWER_FAIL_MODE_MAX (1) +#define CFG_AUTO_DETECT_POWER_FAIL_MODE_DEFAULT (0) + +/* + * + * gItoRepeatCount - sets ito repeated count + * @Min: 0 + * @Max: 5 + * @Default: 0 + * + * This ini sets the ito count in FW + * + * Usage: External + * + * + */ +#define CFG_ITO_REPEAT_COUNT_NAME "gItoRepeatCount" +#define CFG_ITO_REPEAT_COUNT_MIN (0) +#define CFG_ITO_REPEAT_COUNT_MAX (5) +#define CFG_ITO_REPEAT_COUNT_DEFAULT (0) + +/* + * + * gEnableTxOrphan- Enable/Disable orphaning of Tx packets + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to enable/disable orphaning of Tx packets. + * + * Related: None + * + * Usage: External + * + * + */ +#define CFG_TX_ORPHAN_ENABLE_NAME "gEnableTxOrphan" +#define CFG_TX_ORPHAN_ENABLE_DEFAULT (0) +#define CFG_TX_ORPHAN_ENABLE_MIN (0) +#define CFG_TX_ORPHAN_ENABLE_MAX (1) + +struct hdd_config { + /* Bitmap to track what is explicitly configured */ + DECLARE_BITMAP(bExplicitCfg, MAX_CFG_INI_ITEMS); + + /* Config parameters */ + uint32_t RTSThreshold; + uint32_t FragmentationThreshold; + uint8_t OperatingChannel; + bool ShortSlotTimeEnabled; + bool Is11dSupportEnabled; + bool Is11hSupportEnabled; + bool fSupplicantCountryCodeHasPriority; + uint32_t HeartbeatThresh24; + char PowerUsageControl[4]; + bool fIsImpsEnabled; + bool is_ps_enabled; + uint32_t auto_bmps_timer_val; + uint32_t nBmpsModListenInterval; + uint32_t nBmpsMaxListenInterval; + uint32_t nBmpsMinListenInterval; + eHddDot11Mode dot11Mode; + uint32_t nChannelBondingMode24GHz; + uint32_t nChannelBondingMode5GHz; + uint32_t MaxRxAmpduFactor; + uint16_t TxRate; + uint32_t ShortGI20MhzEnable; + uint32_t ScanResultAgeCount; + uint8_t nRssiCatGap; + bool fIsShortPreamble; + struct qdf_mac_addr IbssBssid; + uint32_t AdHocChannel5G; + uint32_t AdHocChannel24G; + uint8_t intfAddrMask; + struct qdf_mac_addr intfMacAddr[QDF_MAX_CONCURRENCY_PERSONA]; + + bool apUapsdEnabled; + bool apRandomBssidEnabled; + bool apProtEnabled; + uint16_t apProtection; + bool apOBSSProtEnabled; + bool apDisableIntraBssFwd; + uint32_t nAPAutoShutOff; + uint8_t enableLTECoex; + uint32_t apKeepAlivePeriod; + uint32_t goKeepAlivePeriod; + uint32_t apLinkMonitorPeriod; + uint32_t goLinkMonitorPeriod; + uint32_t nBeaconInterval; + uint8_t nTxPowerCap; /* In dBm */ + bool allow_tpc_from_ap; + bool fIsLowGainOverride; + uint8_t disablePacketFilter; + bool fRrmEnable; + uint16_t nRrmRandnIntvl; + /* length includes separator */ + char rm_capability[3 * DOT11F_IE_RRMENABLEDCAP_MAX_LEN]; + + /* Vowifi 11r params */ + bool fFTResourceReqSupported; + + uint16_t nNeighborScanPeriod; + uint8_t nNeighborLookupRssiThreshold; + uint8_t delay_before_vdev_stop; + uint8_t nOpportunisticThresholdDiff; + uint8_t nRoamRescanRssiDiff; + uint8_t neighborScanChanList[WNI_CFG_VALID_CHANNEL_LIST_LEN]; + uint16_t nNeighborScanMinChanTime; + uint16_t nNeighborScanMaxChanTime; + uint16_t nMaxNeighborReqTries; + uint16_t nNeighborResultsRefreshPeriod; + uint16_t nEmptyScanRefreshPeriod; + uint8_t nRoamBmissFirstBcnt; + uint8_t nRoamBmissFinalBcnt; + uint8_t nRoamBeaconRssiWeight; + uint32_t nhi_rssi_scan_max_count; + uint32_t nhi_rssi_scan_rssi_delta; + uint32_t nhi_rssi_scan_delay; + int32_t nhi_rssi_scan_rssi_ub; + + /* Additional Handoff params */ + uint16_t nVccRssiTrigger; + uint32_t nVccUlMacLossThreshold; + + uint32_t nPassiveMinChnTime; /* in units of milliseconds */ + uint32_t nPassiveMaxChnTime; /* in units of milliseconds */ + uint32_t nActiveMinChnTime; /* in units of milliseconds */ + uint32_t nActiveMaxChnTime; /* in units of milliseconds */ + uint32_t scan_probe_repeat_time; + uint32_t scan_num_probes; + bool allow_adj_ch_bcn; + + uint32_t nInitialDwellTime; /* in units of milliseconds */ + bool initial_scan_no_dfs_chnl; + +#ifdef WLAN_AP_STA_CONCURRENCY + uint32_t nPassiveMinChnTimeConc; /* in units of milliseconds */ + uint32_t nPassiveMaxChnTimeConc; /* in units of milliseconds */ + uint32_t nActiveMinChnTimeConc; /* in units of milliseconds */ + uint32_t nActiveMaxChnTimeConc; /* in units of milliseconds */ + uint32_t nRestTimeConc; /* in units of milliseconds */ + /* In units of milliseconds */ + uint32_t min_rest_time_conc; + /* In units of milliseconds */ + uint32_t idle_time_conc; + uint8_t nNumStaChanCombinedConc; /* number of channels combined for */ + /* STA in each split scan operation */ + uint8_t nNumP2PChanCombinedConc; /* number of channels combined for */ + /* P2P in each split scan operation */ +#endif + + uint8_t nMaxPsPoll; + + uint8_t nRssiFilterPeriod; + bool fIgnoreDtim; + uint8_t fMaxLIModulatedDTIM; + + uint8_t fEnableFwHeartBeatMonitoring; + uint8_t fEnableFwBeaconFiltering; + bool fEnableFwRssiMonitoring; + bool mcc_rts_cts_prot_enable; + bool mcc_bcast_prob_resp_enable; + uint8_t nDataInactivityTimeout; + uint8_t wow_data_inactivity_timeout; + + /* WMM QoS Configuration */ + hdd_wmm_user_mode_t WmmMode; + bool b80211eIsEnabled; + uint8_t UapsdMask; /* what ACs to setup U-APSD for at assoc */ + uint32_t InfraUapsdVoSrvIntv; + uint32_t InfraUapsdVoSuspIntv; + uint32_t InfraUapsdViSrvIntv; + uint32_t InfraUapsdViSuspIntv; + uint32_t InfraUapsdBeSrvIntv; + uint32_t InfraUapsdBeSuspIntv; + uint32_t InfraUapsdBkSrvIntv; + uint32_t InfraUapsdBkSuspIntv; + bool isFastRoamIniFeatureEnabled; + bool MAWCEnabled; +#ifdef FEATURE_WLAN_ESE + uint32_t InfraInactivityInterval; + bool isEseIniFeatureEnabled; +#endif + bool isFastTransitionEnabled; + uint8_t RoamRssiDiff; + bool isWESModeEnabled; + uint32_t pmkid_modes; + bool isRoamOffloadScanEnabled; + bool bImplicitQosEnabled; + + /* default TSPEC parameters for AC_VO */ + sme_QosWmmDirType InfraDirAcVo; + uint16_t InfraNomMsduSizeAcVo; + uint32_t InfraMeanDataRateAcVo; + uint32_t InfraMinPhyRateAcVo; + uint16_t InfraSbaAcVo; + + /* default TSPEC parameters for AC_VI */ + sme_QosWmmDirType InfraDirAcVi; + uint16_t InfraNomMsduSizeAcVi; + uint32_t InfraMeanDataRateAcVi; + uint32_t InfraMinPhyRateAcVi; + uint16_t InfraSbaAcVi; + + /* default TSPEC parameters for AC_BE */ + sme_QosWmmDirType InfraDirAcBe; + uint16_t InfraNomMsduSizeAcBe; + uint32_t InfraMeanDataRateAcBe; + uint32_t InfraMinPhyRateAcBe; + uint16_t InfraSbaAcBe; + + /* default TSPEC parameters for AC_BK */ + sme_QosWmmDirType InfraDirAcBk; + uint16_t InfraNomMsduSizeAcBk; + uint32_t InfraMeanDataRateAcBk; + uint32_t InfraMinPhyRateAcBk; + uint16_t InfraSbaAcBk; + + uint32_t DelayedTriggerFrmInt; + + /* Wowl pattern */ + char wowlPattern[1024]; + + /* Control for Replay counetr. value 1 means + single replay counter for all TID */ + bool bSingleTidRc; + uint8_t mcastBcastFilterSetting; + bool fhostArpOffload; + bool ssdp; + +#ifdef FEATURE_RUNTIME_PM + bool runtime_pm; + uint32_t runtime_pm_delay; +#endif + +#ifdef FEATURE_WLAN_RA_FILTERING + bool IsRArateLimitEnabled; + uint16_t RArateLimitInterval; +#endif +#ifdef FEATURE_WLAN_SCAN_PNO + bool PnoOffload; +#endif + bool fhostNSOffload; + bool burstSizeDefinition; + uint8_t tsInfoAckPolicy; + + /* RF Settling Time Clock */ + uint32_t rfSettlingTimeUs; + + uint8_t dynamicPsPollValue; + bool AddTSWhenACMIsOff; + bool fValidateScanList; + + uint32_t infraStaKeepAlivePeriod; + uint8_t nNullDataApRespTimeout; + uint8_t nBandCapability; + + uint32_t apDataAvailPollPeriodInMs; + bool teleBcnWakeupEn; + +/* QDF Trace Control*/ + uint16_t qdf_trace_enable_wdi; + uint16_t qdf_trace_enable_hdd; + uint16_t qdf_trace_enable_sme; + uint16_t qdf_trace_enable_pe; + uint16_t qdf_trace_enable_pmc; + uint16_t qdf_trace_enable_wma; + uint16_t qdf_trace_enable_sys; + uint16_t qdf_trace_enable_qdf; + uint16_t qdf_trace_enable_sap; + uint16_t qdf_trace_enable_hdd_sap; + uint16_t qdf_trace_enable_bmi; + uint16_t qdf_trace_enable_cfg; + uint16_t cfd_trace_enable_txrx; + uint16_t qdf_trace_enable_htc; + uint16_t qdf_trace_enable_hif; + uint16_t qdf_trace_enable_hdd_sap_data; + uint16_t qdf_trace_enable_hdd_data; + uint16_t qdf_trace_enable_epping; + uint16_t qdf_trace_enable_qdf_devices; + + uint16_t nTeleBcnTransListenInterval; + uint16_t nTeleBcnMaxListenInterval; + uint16_t nTeleBcnTransLiNumIdleBeacons; + uint16_t nTeleBcnMaxLiNumIdleBeacons; + uint8_t enableBypass11d; + uint8_t enableDFSChnlScan; + uint8_t enable_dfs_pno_chnl_scan; + uint8_t enableDynamicDTIM; + uint8_t ShortGI40MhzEnable; + eHddLinkSpeedReportType reportMaxLinkSpeed; + int32_t linkSpeedRssiHigh; + int32_t linkSpeedRssiMid; + int32_t linkSpeedRssiLow; + bool nRoamPrefer5GHz; + bool nRoamIntraBand; + uint8_t nProbes; + uint16_t nRoamScanHomeAwayTime; + uint8_t enableMCC; + uint8_t allowMCCGODiffBI; + bool isP2pDeviceAddrAdministrated; + uint8_t thermalMitigationEnable; + uint32_t throttlePeriod; + uint32_t throttle_dutycycle_level0; + uint32_t throttle_dutycycle_level1; + uint32_t throttle_dutycycle_level2; + uint32_t throttle_dutycycle_level3; +#if defined(CONFIG_HL_SUPPORT) && defined(QCA_BAD_PEER_TX_FLOW_CL) + bool bad_peer_txctl_enable; + uint32_t bad_peer_txctl_prd; + uint32_t bad_peer_txctl_txq_lmt; + uint32_t bad_peer_tgt_backoff; + uint32_t bad_peer_tgt_report_prd; + uint32_t bad_peer_cond_ieee80211b; + uint32_t bad_peer_delta_ieee80211b; + uint32_t bad_peer_pct_ieee80211b; + uint32_t bad_peer_tput_ieee80211b; + uint32_t bad_peer_limit_ieee80211b; + uint32_t bad_peer_cond_ieee80211ag; + uint32_t bad_peer_delta_ieee80211ag; + uint32_t bad_peer_pct_ieee80211ag; + uint32_t bad_peer_tput_ieee80211ag; + uint32_t bad_peer_limit_ieee80211ag; + uint32_t bad_peer_cond_ieee80211n; + uint32_t bad_peer_delta_ieee80211n; + uint32_t bad_peer_pct_ieee80211n; + uint32_t bad_peer_tput_ieee80211n; + uint32_t bad_peer_limit_ieee80211n; + uint32_t bad_peer_cond_ieee80211ac; + uint32_t bad_peer_delta_ieee80211ac; + uint32_t bad_peer_pct_ieee80211ac; + uint32_t bad_peer_tput_ieee80211ac; + uint32_t bad_peer_limit_ieee80211ac; +#endif + uint8_t vhtChannelWidth; + uint8_t vhtRxMCS; + uint8_t vhtTxMCS; + bool enableTxBF; + bool enable_txbf_sap_mode; + uint8_t txBFCsnValue; + bool enable_su_tx_bformer; + uint8_t vhtRxMCS2x2; + uint8_t vhtTxMCS2x2; + uint8_t disable_high_ht_mcs_2x2; + bool enable2x2; + uint32_t vdev_type_nss_2g; + uint32_t vdev_type_nss_5g; + bool txchainmask1x1; + bool rxchainmask1x1; + bool enableMuBformee; + bool enableVhtpAid; + bool enableVhtGid; + bool enableTxBFin20MHz; + uint8_t enableAmpduPs; + uint8_t enableHtSmps; + uint8_t htSmps; + uint8_t enableModulatedDTIM; + uint32_t fEnableMCAddrList; + bool enableFirstScan2GOnly; + bool skipDfsChnlInP2pSearch; + bool ignoreDynamicDtimInP2pMode; + bool enableRxSTBC; + bool enableTxSTBC; + bool enableRxLDPC; + bool enable5gEBT; +#ifdef FEATURE_WLAN_TDLS + bool fEnableTDLSSupport; + bool fEnableTDLSImplicitTrigger; + uint32_t fTDLSTxStatsPeriod; + uint32_t fTDLSTxPacketThreshold; + uint32_t fTDLSMaxDiscoveryAttempt; + uint32_t tdls_idle_timeout; + uint32_t fTDLSIdlePacketThreshold; + int32_t fTDLSRSSITriggerThreshold; + int32_t fTDLSRSSITeardownThreshold; + int32_t fTDLSRSSIDelta; + uint32_t fTDLSUapsdMask; /* what ACs to setup U-APSD for TDLS */ + uint32_t fEnableTDLSBufferSta; + uint32_t fEnableTDLSSleepSta; + uint32_t fTDLSPuapsdInactivityTimer; + uint32_t fTDLSRxFrameThreshold; + uint32_t fTDLSPuapsdPTIWindow; + uint32_t fTDLSPuapsdPTRTimeout; + bool fTDLSExternalControl; + uint32_t fEnableTDLSOffChannel; + uint32_t fEnableTDLSWmmMode; + uint8_t fTDLSPrefOffChanNum; + uint8_t fTDLSPrefOffChanBandwidth; + uint8_t enable_tdls_scan; + uint32_t tdls_peer_kickout_threshold; +#endif +#ifdef WLAN_SOFTAP_VSTA_FEATURE + bool fEnableVSTASupport; +#endif + uint32_t enableLpwrImgTransition; + uint8_t scanAgingTimeout; + bool enableTxLdpc; + uint8_t disableLDPCWithTxbfAP; + uint8_t enableMCCAdaptiveScheduler; + bool sapAllowAllChannel; + uint8_t retryLimitZero; + uint8_t retryLimitOne; + uint8_t retryLimitTwo; + bool enableSSR; + uint32_t cfgMaxMediumTime; + bool enableVhtFor24GHzBand; + bool enable_sap_vendor_vht; + /* Flag indicating whether legacy fast roam during concurrency is enabled in cfg.ini or not */ + bool bFastRoamInConIniFeatureEnabled; + bool fEnableAdaptRxDrain; + bool enableIbssHeartBeatOffload; + uint32_t antennaDiversity; + bool fEnableSNRMonitoring; + /*PNO related parameters */ +#ifdef FEATURE_WLAN_SCAN_PNO + bool configPNOScanSupport; + uint32_t configPNOScanTimerRepeatValue; + uint32_t pno_slow_scan_multiplier; +#endif + uint8_t max_amsdu_num; + uint8_t nSelect5GHzMargin; + uint8_t isCoalesingInIBSSAllowed; + + /* IBSS Power Save related parameters */ + uint32_t ibssATIMWinSize; + uint8_t isIbssPowerSaveAllowed; + uint8_t isIbssPowerCollapseAllowed; + uint8_t isIbssAwakeOnTxRx; + uint32_t ibssInactivityCount; + uint32_t ibssTxSpEndInactivityTime; + uint32_t ibssPsWarmupTime; + uint32_t ibssPs1RxChainInAtimEnable; + + bool enable_ip_tcp_udp_checksum_offload; + uint8_t enablePowersaveOffload; + bool enablefwprint; + uint8_t enable_fw_log; + uint8_t fVhtAmpduLenExponent; + uint32_t vhtMpduLen; + uint32_t IpaConfig; + bool IpaClkScalingEnable; + uint32_t IpaDescSize; + uint32_t IpaHighBandwidthMbps; + uint32_t IpaMediumBandwidthMbps; + uint32_t IpaLowBandwidthMbps; +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH + uint32_t WlanMccToSccSwitchMode; +#endif +#ifdef FEATURE_WLAN_AUTO_SHUTDOWN + uint32_t WlanAutoShutdown; +#endif + uint8_t maxWoWFilters; + uint8_t wowEnable; + uint8_t maxNumberOfPeers; + uint8_t disableDFSChSwitch; + uint8_t enableDFSMasterCap; + uint16_t thermalTempMinLevel0; + uint16_t thermalTempMaxLevel0; + uint16_t thermalTempMinLevel1; + uint16_t thermalTempMaxLevel1; + uint16_t thermalTempMinLevel2; + uint16_t thermalTempMaxLevel2; + uint16_t thermalTempMinLevel3; + uint16_t thermalTempMaxLevel3; + uint32_t TxPower2g; + uint32_t TxPower5g; + uint32_t gEnableDebugLog; + bool fDfsPhyerrFilterOffload; + uint8_t gSapPreferredChanLocation; + uint8_t gDisableDfsJapanW53; + bool gEnableOverLapCh; + bool fRegChangeDefCountry; + uint16_t max_ht_mcs_txdata; + bool disable_abg_rate_txdata; + uint8_t rate_for_tx_mgmt; +#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL + uint32_t TxFlowLowWaterMark; + uint32_t TxFlowHighWaterMarkOffset; + uint32_t TxFlowMaxQueueDepth; + uint32_t TxLbwFlowLowWaterMark; + uint32_t TxLbwFlowHighWaterMarkOffset; + uint32_t TxLbwFlowMaxQueueDepth; + uint32_t TxHbwFlowLowWaterMark; + uint32_t TxHbwFlowHighWaterMarkOffset; + uint32_t TxHbwFlowMaxQueueDepth; +#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */ +#ifdef QCA_LL_TX_FLOW_CONTROL_V2 + uint32_t TxFlowStopQueueThreshold; + uint32_t TxFlowStartQueueOffset; +#endif + uint8_t apMaxOffloadPeers; + uint8_t apMaxOffloadReorderBuffs; + bool advertiseConcurrentOperation; + bool enableMemDeepSleep; + + uint32_t defaultRateIndex24Ghz; +#ifdef MEMORY_DEBUG + bool IsMemoryDebugSupportEnabled; +#endif + + uint8_t allowDFSChannelRoam; + + bool debugP2pRemainOnChannel; + + bool enablePacketLog; +#ifdef MSM_PLATFORM + uint32_t busBandwidthHighThreshold; + uint32_t busBandwidthMediumThreshold; + uint32_t busBandwidthLowThreshold; + uint32_t busBandwidthComputeInterval; + uint32_t enable_tcp_delack; + uint32_t enable_tcp_adv_win_scale; + uint32_t tcpDelackThresholdHigh; + uint32_t tcpDelackThresholdLow; + uint32_t tcp_tx_high_tput_thres; + uint32_t tcp_delack_timer_count; +#endif /* MSM_PLATFORM */ + + /* FW debug log parameters */ + uint32_t enableFwLogType; + uint32_t enableFwLogLevel; + uint8_t enableFwModuleLogLevel[FW_MODULE_LOG_LEVEL_STRING_LENGTH]; + + /* RTS profile parameter */ + uint32_t rts_profile; + +#ifdef WLAN_FEATURE_11W + uint32_t pmfSaQueryMaxRetries; + uint32_t pmfSaQueryRetryInterval; +#endif + + uint8_t gMaxConcurrentActiveSessions; + + uint8_t ignoreCAC; + bool IsSapDfsChSifsBurstEnabled; + +#ifdef FEATURE_GREEN_AP + bool enableGreenAP; + bool enable_egap; + uint32_t egap_feature_flag; + uint32_t egap_inact_time; + uint32_t egap_wait_time; +#endif + /* Flag to indicate crash inject enabled or not */ + bool crash_inject_enabled; + uint8_t force_sap_acs; + uint8_t force_sap_acs_st_ch; + uint8_t force_sap_acs_end_ch; + uint8_t enable_sap_mandatory_chan_list; + int32_t dfsRadarPriMultiplier; + uint8_t reorderOffloadSupport; + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + bool isRoamOffloadEnabled; +#endif + + uint32_t IpaUcTxBufCount; + uint32_t IpaUcTxBufSize; + uint32_t IpaUcRxIndRingCount; + uint32_t IpaUcTxPartitionBase; +#ifdef WLAN_LOGGING_SOCK_SVC_ENABLE + /* WLAN Logging */ + uint32_t wlanLoggingEnable; + uint32_t wlanLoggingFEToConsole; + uint32_t wlanLoggingNumBuf; +#endif /* WLAN_LOGGING_SOCK_SVC_ENABLE */ + + uint8_t enableSifsBurst; + +#ifdef WLAN_FEATURE_LPSS + bool enable_lpass_support; +#endif +#ifdef WLAN_FEATURE_NAN + bool enable_nan_support; +#endif + bool enableSelfRecovery; +#ifdef FEATURE_WLAN_FORCE_SAP_SCC + uint8_t SapSccChanAvoidance; +#endif /* FEATURE_WLAN_FORCE_SAP_SCC */ + + bool enableSapSuspend; + +#ifdef WLAN_FEATURE_EXTWOW_SUPPORT + uint8_t extWowGotoSuspend; + uint8_t extWowApp1WakeupPinNumber; + uint8_t extWowApp2WakeupPinNumber; + uint32_t extWowApp2KAInitPingInterval; + uint32_t extWowApp2KAMinPingInterval; + uint32_t extWowApp2KAMaxPingInterval; + uint32_t extWowApp2KAIncPingInterval; + uint16_t extWowApp2TcpSrcPort; + uint16_t extWowApp2TcpDstPort; + uint32_t extWowApp2TcpTxTimeout; + uint32_t extWowApp2TcpRxTimeout; +#endif + bool gEnableDeauthToDisassocMap; +#ifdef DHCP_SERVER_OFFLOAD + bool enableDHCPServerOffload; + uint32_t dhcpMaxNumClients; + uint8_t dhcpServerIP[IPADDR_STRING_LENGTH]; +#endif /* DHCP_SERVER_OFFLOAD */ + bool enable_mac_spoofing; + uint8_t conc_custom_rule1; + uint8_t conc_custom_rule2; + uint8_t is_sta_connection_in_5gz_enabled; + uint16_t p2p_listen_defer_interval; + uint32_t sta_miracast_mcc_rest_time_val; + bool is_ramdump_enabled; +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE + bool sap_channel_avoidance; +#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ + uint8_t sap_p2p_11ac_override; + uint8_t sap_dot11mc; + uint8_t prefer_non_dfs_on_radar; + bool ignore_peer_erp_info; + uint8_t multicast_host_fw_msgs; + uint8_t conc_system_pref; + bool sendDeauthBeforeCon; + bool tso_enable; + bool lro_enable; + bool flow_steering_enable; + bool active_mode_offload; + bool bpf_packet_filter_enable; + /* parameter for defer timer for enabling TDLS on p2p listen */ + uint16_t tdls_enable_defer_time; + uint32_t fine_time_meas_cap; + uint8_t max_scan_count; +#ifdef WLAN_FEATURE_FASTPATH + bool fastpath_enable; +#endif + uint8_t dot11p_mode; + uint8_t rx_mode; + uint8_t cpu_map_list[CFG_RPS_RX_QUEUE_CPU_MAP_LIST_LEN]; +#ifdef FEATURE_WLAN_EXTSCAN + bool extscan_enabled; + uint32_t extscan_passive_max_chn_time; + uint32_t extscan_passive_min_chn_time; + uint32_t extscan_active_max_chn_time; + uint32_t extscan_active_min_chn_time; +#endif + bool ce_classify_enabled; + uint32_t dual_mac_feature_disable; + bool tx_chain_mask_cck; + uint8_t tx_chain_mask_1ss; + uint16_t self_gen_frm_pwr; +#ifdef WLAN_FEATURE_UDP_RESPONSE_OFFLOAD + bool udp_resp_offload_support; + uint32_t dest_port; + char payload_filter[MAX_LEN_UDP_RESP_OFFLOAD]; + char response_payload[MAX_LEN_UDP_RESP_OFFLOAD]; +#endif +#ifdef FEATURE_WLAN_SCAN_PNO + bool pno_channel_prediction; + uint8_t top_k_num_of_channels; + uint8_t stationary_thresh; + uint32_t channel_prediction_full_scan; +#endif + bool early_stop_scan_enable; + int8_t early_stop_scan_min_threshold; + int8_t early_stop_scan_max_threshold; + int8_t first_scan_bucket_threshold; + uint8_t ht_mpdu_density; +#ifdef FEATURE_LFR_SUBNET_DETECTION + bool enable_lfr_subnet_detection; +#endif + uint16_t obss_active_dwelltime; + uint16_t obss_passive_dwelltime; + uint16_t obss_width_trigger_interval; + uint8_t inform_bss_rssi_raw; +#ifdef WLAN_FEATURE_TSF + uint32_t tsf_gpio_pin; +#endif + uint32_t roam_dense_traffic_thresh; + uint32_t roam_dense_rssi_thresh_offset; + bool ignore_peer_ht_opmode; + uint32_t roam_dense_min_aps; + bool enable_edca_params; + uint32_t edca_vo_cwmin; + uint32_t edca_vi_cwmin; + uint32_t edca_bk_cwmin; + uint32_t edca_be_cwmin; + uint32_t edca_vo_cwmax; + uint32_t edca_vi_cwmax; + uint32_t edca_bk_cwmax; + uint32_t edca_be_cwmax; + uint32_t edca_vo_aifs; + uint32_t edca_vi_aifs; + uint32_t edca_bk_aifs; + uint32_t edca_be_aifs; + + /* Tuning TX sched parameters for VO (skip credit limit credit disc) */ + uint8_t tx_sched_wrr_vo[TX_SCHED_WRR_PARAM_STRING_LENGTH]; + /* Tuning TX sched parameters for VI (skip credit limit credit disc) */ + uint8_t tx_sched_wrr_vi[TX_SCHED_WRR_PARAM_STRING_LENGTH]; + /* Tuning TX sched parameters for BE (skip credit limit credit disc) */ + uint8_t tx_sched_wrr_be[TX_SCHED_WRR_PARAM_STRING_LENGTH]; + /* Tuning TX sched parameters for BK (skip credit limit credit disc) */ + uint8_t tx_sched_wrr_bk[TX_SCHED_WRR_PARAM_STRING_LENGTH]; + + bool enable_fatal_event; + bool bpf_enabled; + bool enable_dp_trace; + bool adaptive_dwell_mode_enabled; + enum wmi_dwelltime_adaptive_mode scan_adaptive_dwell_mode; + enum wmi_dwelltime_adaptive_mode roamscan_adaptive_dwell_mode; + enum wmi_dwelltime_adaptive_mode extscan_adaptive_dwell_mode; + enum wmi_dwelltime_adaptive_mode pnoscan_adaptive_dwell_mode; + enum wmi_dwelltime_adaptive_mode global_adapt_dwelltime_mode; + uint8_t adapt_dwell_lpf_weight; + uint8_t adapt_dwell_passive_mon_intval; + uint8_t adapt_dwell_wifi_act_threshold; + bool bug_report_for_no_scan_results; + bool bug_on_reinit_failure; +#ifdef WLAN_FEATURE_NAN_DATAPATH + bool enable_nan_datapath; + uint8_t nan_datapath_ndi_channel; +#endif + uint32_t iface_change_wait_time; + /* parameter to control GTX */ + uint32_t tgt_gtx_usr_cfg; + enum cfg_sub_20_channel_width enable_sub_20_channel_width; + bool indoor_channel_support; + /* parameter to force sap into 11n */ + bool sap_force_11n_for_11ac; + uint16_t sap_tx_leakage_threshold; + bool multicast_replay_filter; + /* parameter for indicating sifs burst duration to fw */ + uint8_t sifs_burst_duration; + bool goptimize_chan_avoid_event; + bool enable_go_cts2self_for_sta; + uint32_t tx_aggregation_size; + uint32_t rx_aggregation_size; + bool sta_prefer_80MHz_over_160MHz; + uint8_t sap_max_inactivity_override; + bool fw_timeout_crash; + uint32_t rx_wakelock_timeout; +#ifdef WLAN_FEATURE_WOW_PULSE + bool wow_pulse_support; + uint8_t wow_pulse_pin; + uint16_t wow_pulse_interval_high; + uint16_t wow_pulse_interval_low; +#endif + uint8_t is_per_roam_enabled; + uint32_t per_roam_high_rate_threshold; + uint32_t per_roam_low_rate_threshold; + uint32_t per_roam_th_percent; + uint32_t per_roam_rest_time; + uint32_t per_roam_mon_time; + uint32_t min_candidate_rssi; + uint32_t max_sched_scan_plan_interval; + uint32_t max_sched_scan_plan_iterations; + uint8_t enable_phy_reg_retention; + enum active_bpf_mode active_bpf_mode; + enum hw_filter_mode hw_filter_mode; + bool sap_internal_restart; + bool restart_beaconing_on_chan_avoid_event; + bool enable_bcast_probe_rsp; + bool qcn_ie_support; + uint8_t fils_max_chan_guard_time; + /* 5G preference parameters for boosting RSSI */ + bool enable_5g_band_pref; + int8_t rssi_boost_threshold_5g; + uint8_t rssi_boost_factor_5g; + uint8_t max_rssi_boost_5g; + /* 5G preference parameters for dropping RSSI */ + int8_t rssi_penalize_threshold_5g; + uint8_t rssi_penalize_factor_5g; + uint8_t max_rssi_penalize_5g; + + uint8_t auto_pwr_save_fail_mode; + uint8_t packet_filters_bitmap; + /* threshold of packet drops at which FW initiates disconnect */ + uint16_t pkt_err_disconn_th; + bool is_bssid_hint_priority; + bool tx_orphan_enable; + bool is_force_1x1; + uint16_t num_11b_tx_chains; + uint16_t num_11ag_tx_chains; + + uint8_t ito_repeat_count; +}; + +#define VAR_OFFSET(_Struct, _Var) (offsetof(_Struct, _Var)) +#define VAR_SIZE(_Struct, _Var) (sizeof(((_Struct *)0)->_Var)) + +#define VAR_FLAGS_NONE (0) + +/* bit 0 is Required or Optional */ +#define VAR_FLAGS_REQUIRED (1 << 0) +#define VAR_FLAGS_OPTIONAL (0 << 0) + +/* + * bit 1 tells if range checking is required. + * If less than MIN, assume MIN. + * If greater than MAX, assume MAX. + */ +#define VAR_FLAGS_RANGE_CHECK (1 << 1) +#define VAR_FLAGS_RANGE_CHECK_ASSUME_MINMAX (VAR_FLAGS_RANGE_CHECK) + +/* + * bit 2 is range checking that assumes the DEFAULT value + * If less than MIN, assume DEFAULT, + * If greater than MAX, assume DEFAULT. + */ +#define VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT (1 << 2) + +/* + * Bit 3 indicates that the config item can be modified dynamicially + * on a running system + */ +#define VAR_FLAGS_DYNAMIC_CFG (1 << 3) + +typedef enum { + WLAN_PARAM_Integer, + WLAN_PARAM_SignedInteger, + WLAN_PARAM_HexInteger, + WLAN_PARAM_String, + WLAN_PARAM_MacAddr, +} WLAN_PARAMETER_TYPE; + +#define REG_VARIABLE(_Name, _Type, _Struct, _VarName, \ + _Flags, _Default, _Min, _Max) \ + { \ + (_Name), \ + (_Type), \ + (_Flags), \ + VAR_OFFSET(_Struct, _VarName), \ + VAR_SIZE(_Struct, _VarName), \ + (_Default), \ + (_Min), \ + (_Max), \ + NULL, \ + 0 \ + } + +#define REG_DYNAMIC_VARIABLE(_Name, _Type, _Struct, _VarName, \ + _Flags, _Default, _Min, _Max, \ + _CBFunc, _CBParam) \ + { \ + (_Name), \ + (_Type), \ + (VAR_FLAGS_DYNAMIC_CFG | (_Flags)), \ + VAR_OFFSET(_Struct, _VarName), \ + VAR_SIZE(_Struct, _VarName), \ + (_Default), \ + (_Min), \ + (_Max), \ + (_CBFunc), \ + (_CBParam) \ + } + +#define REG_VARIABLE_STRING(_Name, _Type, _Struct, _VarName, \ + _Flags, _Default) \ + { \ + (_Name), \ + (_Type), \ + (_Flags), \ + VAR_OFFSET(_Struct, _VarName), \ + VAR_SIZE(_Struct, _VarName), \ + (unsigned long)(_Default), \ + 0, \ + 0, \ + NULL, \ + 0 \ + } + +typedef struct tREG_TABLE_ENTRY { + + char *RegName; /* variable name in the qcom_cfg.ini file */ + WLAN_PARAMETER_TYPE RegType; /* variable type in hdd_config struct */ + unsigned long Flags; /* Specify optional parms and if RangeCheck is performed */ + unsigned short VarOffset; /* offset to field from the base address of the structure */ + unsigned short VarSize; /* size (in bytes) of the field */ + unsigned long VarDefault; /* default value to use */ + unsigned long VarMin; /* minimum value, for range checking */ + unsigned long VarMax; /* maximum value, for range checking */ + /* Dynamic modification notifier */ + void (*pfnDynamicnotify)(hdd_context_t *pHddCtx, + unsigned long notifyId); + unsigned long notifyId; /* Dynamic modification identifier */ +} REG_TABLE_ENTRY; + +static __inline unsigned long util_min(unsigned long a, unsigned long b) +{ + unsigned long r; + + r = ((a < b) ? a : b); + return r; +} + +/* Function declarations and documenation */ +QDF_STATUS hdd_parse_config_ini(hdd_context_t *pHddCtx); +QDF_STATUS hdd_update_mac_config(hdd_context_t *pHddCtx); +QDF_STATUS hdd_set_sme_config(hdd_context_t *pHddCtx); +QDF_STATUS hdd_set_sme_chan_list(hdd_context_t *hdd_ctx); +bool hdd_update_config_cfg(hdd_context_t *pHddCtx); +QDF_STATUS hdd_cfg_get_global_config(hdd_context_t *pHddCtx, char *pBuf, + int buflen); + +eCsrPhyMode hdd_cfg_xlate_to_csr_phy_mode(eHddDot11Mode dot11Mode); +QDF_STATUS hdd_execute_global_config_command(hdd_context_t *pHddCtx, + char *command); + +QDF_STATUS hdd_set_idle_ps_config(hdd_context_t *pHddCtx, bool val); +void hdd_get_pmkid_modes(hdd_context_t *pHddCtx, + struct pmkid_mode_bits *pmkid_modes); + +void hdd_update_tgt_cfg(void *context, void *param); +bool hdd_dfs_indicate_radar(void *context, void *param); + +QDF_STATUS hdd_string_to_u8_array(char *str, uint8_t *intArray, uint8_t *len, + uint8_t intArrayMaxLen); +QDF_STATUS hdd_hex_string_to_u16_array(char *str, uint16_t *int_array, + uint8_t *len, uint8_t int_array_max_len); + +void hdd_cfg_print(hdd_context_t *pHddCtx); + +QDF_STATUS hdd_update_nss(hdd_context_t *hdd_ctx, uint8_t nss); +#ifdef FEATURE_WLAN_SCAN_PNO +void hdd_set_pno_channel_prediction_config( + tpSmeConfigParams sme_config, hdd_context_t *hdd_ctx); +#else +static inline void hdd_set_pno_channel_prediction_config( + tpSmeConfigParams sme_config, hdd_context_t *hdd_ctx) +{} +#endif + +#endif diff --git a/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_conc_ut.h b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_conc_ut.h new file mode 100644 index 0000000000000000000000000000000000000000..30740a143c4ee09cb7de761b75b461a456b6cafd --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_conc_ut.h @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2015-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef __WLAN_HDD_CONC_UT_H +#define __WLAN_HDD_CONC_UT_H + +/* Include files */ + +#include "wlan_hdd_main.h" +#include "cds_concurrency.h" +#ifdef MPC_UT_FRAMEWORK +void clean_report(hdd_context_t *hdd_ctx); +void fill_report(hdd_context_t *hdd_ctx, char *title, + uint32_t first_persona, uint32_t second_persona, uint32_t third_persona, + uint32_t chnl_1st_conn, uint32_t chnl_2nd_conn, uint32_t chnl_3rd_conn, + bool status, enum cds_pcl_type pcl_type, char *reason, uint8_t *pcl); +void print_report(hdd_context_t *hdd_ctx); +void wlan_hdd_one_connection_scenario(hdd_context_t *hdd_ctx); +void wlan_hdd_two_connections_scenario(hdd_context_t *hdd_ctx, + uint8_t first_chnl, enum cds_chain_mode first_chain_mask); +void wlan_hdd_three_connections_scenario(hdd_context_t *hdd_ctx, + uint8_t first_chnl, uint8_t second_chnl, + enum cds_chain_mode chain_mask, uint8_t use_same_mac); +#else +static inline void clean_report(hdd_context_t *hdd_ctx) +{ +} + +static inline void fill_report(hdd_context_t *hdd_ctx, char *title, + uint32_t first_persona, uint32_t second_persona, uint32_t third_persona, + uint32_t chnl_1st_conn, uint32_t chnl_2nd_conn, uint32_t chnl_3rd_conn, + bool status, enum cds_pcl_type pcl_type, char *reason, uint8_t *pcl) +{ +} + +static inline void print_report(hdd_context_t *hdd_ctx) +{ +} + +static inline void wlan_hdd_one_connection_scenario(hdd_context_t *hdd_ctx) +{ +} + +static inline void wlan_hdd_two_connections_scenario(hdd_context_t *hdd_ctx, + uint8_t first_chnl, enum cds_chain_mode first_chain_mask) +{ +} + +static inline void wlan_hdd_three_connections_scenario(hdd_context_t *hdd_ctx, + uint8_t first_chnl, uint8_t second_chnl, + enum cds_chain_mode chain_mask, uint8_t use_same_mac) +{ +} +#endif +#endif diff --git a/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_debugfs.h b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_debugfs.h new file mode 100644 index 0000000000000000000000000000000000000000..9633e0018e4ef038a05c9e62682175814125da17 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_debugfs.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2013-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef _WLAN_HDD_DEBUGFS_H +#define _WLAN_HDD_DEBUGFS_H + +#ifdef WLAN_DEBUGFS +QDF_STATUS hdd_debugfs_init(hdd_adapter_t *adapter); +void hdd_debugfs_exit(hdd_adapter_t *adapter); +#else +static inline QDF_STATUS hdd_debugfs_init(hdd_adapter_t *pAdapter) +{ + return QDF_STATUS_SUCCESS; +} + +static inline void hdd_debugfs_exit(hdd_adapter_t *adapter) +{ +} +#endif /* #ifdef WLAN_DEBUGFS */ +#endif /* #ifndef _WLAN_HDD_DEBUGFS_H */ diff --git a/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_driver_ops.h b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_driver_ops.h new file mode 100644 index 0000000000000000000000000000000000000000..34c8c118c014feb35c45a89b0e8d481b7861b215 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_driver_ops.h @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2015-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef __WLAN_HDD_DRIVER_OPS_H__ +#define __WLAN_HDD_DRIVER_OPS_H__ + +#include "hif.h" + +/** + * DOC: wlan_hdd_driver_ops.h + * + * Functions to register the wlan driver. +*/ +int wlan_hdd_register_driver(void); +void wlan_hdd_unregister_driver(void); + +/** + * wlan_hdd_bus_suspend() - suspend the wlan bus + * + * This function is called by the platform driver to suspend the + * wlan bus + * + * @state: state + * + * Return: QDF_STATUS + */ +int wlan_hdd_bus_suspend(pm_message_t state); + +/** + * wlan_hdd_bus_suspend_noirq() - handle .suspend_noirq callback + * + * This function is called by the platform driver to complete the + * bus suspend callback when device interrupts are disabled by kernel. + * Call HIF and WMA suspend_noirq callbacks to make sure there is no + * wake up pending from FW before allowing suspend. + * + * Return: 0 for success and -EBUSY if FW is requesting wake up + */ +int wlan_hdd_bus_suspend_noirq(void); + +/** + * wlan_hdd_bus_resume(): wake up the bus + * + * This function is called by the platform driver to resume wlan + * bus + * + * Return: void + */ +int wlan_hdd_bus_resume(void); + +/** + * wlan_hdd_bus_resume_noirq(): handle bus resume no irq + * + * This function is called by the platform driver to do bus + * resume no IRQ before calling resume callback. Call WMA and HIF + * layers to complete the resume_noirq. + * + * Return: 0 for success and negative error code for failure + */ +int wlan_hdd_bus_resume_noirq(void); +void hdd_hif_close(void *hif_ctx); +int hdd_hif_open(struct device *dev, void *bdev, const hif_bus_id *bid, + enum qdf_bus_type bus_type, bool reinit); +#endif /* __WLAN_HDD_DRIVER_OPS_H__ */ diff --git a/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_ether.h b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_ether.h new file mode 100644 index 0000000000000000000000000000000000000000..cc20ad9b2fb01f73ff7eea664645256088c91d62 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_ether.h @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef _WLAN_HDD_ETHER_H +#define _WLAN_HDD_ETHER_H +/*============================================================================ + @file wlan_hdd_ether.h + + This module describes Ethernet packet formats for processing by HDD. + ============================================================================*/ +/* $Header$ */ + +/*---------------------------------------------------------------------------- + * Include Files + * -------------------------------------------------------------------------*/ +#include +#include +#include +#include + +/*---------------------------------------------------------------------------- + * Preprocessor Definitions and Constants + * -------------------------------------------------------------------------*/ +#define WLAN_SNAP_OUI_LEN 3 +#define WLAN_SNAP_DSAP 0xAAU +#define WLAN_SNAP_SSAP 0xAAU +#define WLAN_SNAP_CTRL 0x03 +#define WLAN_MIN_PROTO 0x0600 + +/*---------------------------------------------------------------------------- + * Type Declarations + * -------------------------------------------------------------------------*/ +struct wlan_snap_hdr { + unsigned char dsap; + unsigned char ssap; + unsigned char ctrl; + unsigned char oui[WLAN_SNAP_OUI_LEN]; +} __packed; + +struct wlan_8023 { + unsigned char h_dest[ETH_ALEN]; + unsigned char h_source[ETH_ALEN]; + __be16 h_len; + struct wlan_snap_hdr h_snap; + __be16 h_proto; +} __packed; + +struct wlan_8023_vlan { + unsigned char h_dest[ETH_ALEN]; + unsigned char h_source[ETH_ALEN]; + __be16 h_vlan_proto; + __be16 h_vlan_TCI; + __be16 h_len; + struct wlan_snap_hdr h_snap; + __be16 h_proto; +} __packed; + +union generic_ethhdr { + struct ethhdr eth_II; + struct vlan_ethhdr eth_IIv; + struct wlan_8023 eth_8023; + struct wlan_8023_vlan eth_8023v; +}; + +#endif /* #ifndef _WLAN_HDD_ETHER_H */ diff --git a/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_ftm.h b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_ftm.h new file mode 100644 index 0000000000000000000000000000000000000000..878a22e08d53aeffcf65f5c7ed82e0420cbd6d05 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_ftm.h @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2013-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef WLAN_HDD_FTM_H +#define WLAN_HDD_FTM_H + +/** + * DOC: wlan_hdd_ftm.h + * + * WLAN Host Device Driver Factory Test Mode header file + */ + +#include "qdf_status.h" +#include "cds_mq.h" +#include "cds_api.h" +#include "msg.h" +#include "qdf_types.h" +#include + +enum wlan_hdd_ftm_state { + WLAN_FTM_INITIALIZED, + WLAN_FTM_STOPPED, + WLAN_FTM_STARTED, +}; + +/** + * struct wlan_hdd_ftm_status - FTM status + * @ftm_state: The current state of the FTM process + */ +struct wlan_hdd_ftm_status { + enum wlan_hdd_ftm_state ftm_state; +}; + +int hdd_update_cds_config_ftm(hdd_context_t *hdd_ctx); +void hdd_ftm_mc_process_msg(void *message); +#if defined(QCA_WIFI_FTM) +QDF_STATUS wlan_hdd_ftm_testmode_cmd(void *data, int len); +int wlan_hdd_qcmbr_unified_ioctl(hdd_adapter_t *adapter, struct ifreq *ifr); +#endif + +#endif diff --git a/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_host_offload.h b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_host_offload.h new file mode 100644 index 0000000000000000000000000000000000000000..873b6a73d1e3653442faa9cb237f7542736323b3 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_host_offload.h @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2014-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef __WLAN_HDD_HOST_OFFLOAD_H__ +#define __WLAN_HDD_HOST_OFFLOAD_H__ + +/**=========================================================================== + + \file wlan_hdd_host_offload.h + + \brief Android WLAN HDD Host Offload API + + ==========================================================================*/ + +/* Offload types. */ +#define WLAN_IPV4_ARP_REPLY_OFFLOAD 0 +#define WLAN_IPV6_NEIGHBOR_DISCOVERY_OFFLOAD 1 + +/* Enable or disable offload. */ +#define WLAN_OFFLOAD_DISABLE 0 +#define WLAN_OFFLOAD_ENABLE 0x1 +#define WLAN_OFFLOAD_BC_FILTER_ENABLE 0x2 +#define WLAN_OFFLOAD_ARP_AND_BC_FILTER_ENABLE (WLAN_OFFLOAD_ENABLE | WLAN_OFFLOAD_BC_FILTER_ENABLE) + +/* Offload request. */ +typedef struct { + uint8_t offloadType; + uint8_t enableOrDisable; + union { + uint8_t hostIpv4Addr[SIR_IPV4_ADDR_LEN]; + uint8_t hostIpv6Addr[SIR_MAC_IPV6_ADDR_LEN]; + } params; + struct qdf_mac_addr bssId; +} tHostOffloadRequest, *tpHostOffloadRequest; + +#ifdef FEATURE_WLAN_DIAG_SUPPORT +void hdd_wlan_offload_event(uint8_t type, uint8_t state); +#else +static inline +void hdd_wlan_offload_event(uint8_t type, uint8_t state) +{ +} +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + +#endif /* __WLAN_HDD_HOST_OFFLOAD_H__ */ diff --git a/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_includes.h b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_includes.h new file mode 100644 index 0000000000000000000000000000000000000000..4eead672404f53adbb6b95be8fb0e4dd3db9c07f --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_includes.h @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2014, 2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#if !defined(HDD_INCLUDES_H__) +#define HDD_INCLUDES_H__ + +/**=========================================================================== + + \file wlan_hdd_includes.h + + \brief Internal includes for the Linux HDD + + ==========================================================================*/ + +/* $HEADER$ */ + +/*--------------------------------------------------------------------------- + Include files + -------------------------------------------------------------------------*/ + +/* throw all the includes in here f to get the .c files in the HDD to compile. */ + +#include +#include +#include +#include +#include +#include +#include "ol_txrx_ctrl_api.h" +#include +#include +#include "wlan_hdd_assoc.h" +#include "wlan_hdd_wext.h" +#include "wlan_hdd_main.h" +#include "wlan_hdd_tx_rx.h" + + +#ifdef FEATURE_OEM_DATA_SUPPORT +/*include for oem data req specific structures*/ +/*and function declarations*/ +#include "wlan_hdd_oemdata.h" +#endif + +#endif /* end #if !defined(HDD_INCLUDES_H__) */ diff --git a/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_ipa.h b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_ipa.h new file mode 100644 index 0000000000000000000000000000000000000000..1989f598fdea3375ee8e82d4176e0e553021f5da --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_ipa.h @@ -0,0 +1,276 @@ +/* + * Copyright (c) 2013-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef HDD_IPA_H__ +#define HDD_IPA_H__ + +/** + * DOC: wlan_hdd_ipa.h + * + * WLAN IPA interface module headers + * Originally written by Qualcomm Atheros, Inc + */ + +/** + * enum hdd_ipa_wlan_event - HDD IPA events + * @HDD_IPA_CLIENT_CONNECT: Client Connects + * @HDD_IPA_CLIENT_DISCONNECT: Client Disconnects + * @HDD_IPA_AP_CONNECT: SoftAP is started + * @HDD_IPA_AP_DISCONNECT: SoftAP is stopped + * @HDD_IPA_STA_CONNECT: STA associates to AP + * @HDD_IPA_STA_DISCONNECT: STA dissociates from AP + * @HDD_IPA_CLIENT_CONNECT_EX: Peer associates/re-associates to softap + * @HDD_IPA_WLAN_EVENT_MAX: Max value for the enum + */ +enum hdd_ipa_wlan_event { + HDD_IPA_CLIENT_CONNECT, + HDD_IPA_CLIENT_DISCONNECT, + HDD_IPA_AP_CONNECT, + HDD_IPA_AP_DISCONNECT, + HDD_IPA_STA_CONNECT, + HDD_IPA_STA_DISCONNECT, + HDD_IPA_CLIENT_CONNECT_EX, + HDD_IPA_WLAN_EVENT_MAX +}; + +#ifdef IPA_OFFLOAD +/* Include files */ +#include /* hdd_context_t */ + +/** + * enum hdd_ipa_forward_type: Type of forward packet received from IPA + * @HDD_IPA_FORWARD_PKT_NONE: No forward packet + * @HDD_IPA_FORWARD_PKT_LOCAL_STACK: Packet forwarded to kernel network stack + * @HDD_IPA_FORWARD_PKT_DISCARD: Discarded packet before sending to kernel stack + */ +enum hdd_ipa_forward_type { + HDD_IPA_FORWARD_PKT_NONE = 0, + HDD_IPA_FORWARD_PKT_LOCAL_STACK = 1, + HDD_IPA_FORWARD_PKT_DISCARD = 2 +}; + +/** + * FIXME: Temporary hack - until IPA functionality gets restored + * + */ +typedef void (*hdd_ipa_nbuf_cb_fn)(qdf_nbuf_t); +void hdd_ipa_nbuf_cb(qdf_nbuf_t skb); /* Fwd declare */ +static inline hdd_ipa_nbuf_cb_fn wlan_hdd_stub_ipa_fn(void) +{ + return hdd_ipa_nbuf_cb; +}; + +QDF_STATUS hdd_ipa_init(hdd_context_t *hdd_ctx); +QDF_STATUS hdd_ipa_cleanup(hdd_context_t *hdd_ctx); +QDF_STATUS hdd_ipa_process_rxt(void *cds_context, qdf_nbuf_t rxBuf, + uint8_t sta_id); +int hdd_ipa_wlan_evt(hdd_adapter_t *adapter, uint8_t sta_id, + enum hdd_ipa_wlan_event type, uint8_t *mac_addr); +int hdd_ipa_set_perf_level(hdd_context_t *hdd_ctx, uint64_t tx_packets, + uint64_t rx_packets); +int hdd_ipa_suspend(hdd_context_t *hdd_ctx); +int hdd_ipa_resume(hdd_context_t *hdd_ctx); +void hdd_ipa_uc_stat_query(hdd_context_t *hdd_ctx, uint32_t *ipa_tx_diff, + uint32_t *ipa_rx_diff); +void hdd_ipa_uc_rt_debug_host_dump(hdd_context_t *hdd_ctx); +void hdd_ipa_uc_stat_request(hdd_adapter_t *adapter, uint8_t reason); +void hdd_ipa_uc_sharing_stats_request(hdd_adapter_t *adapter, + uint8_t reset_stats); +void hdd_ipa_uc_set_quota(hdd_adapter_t *adapter, uint8_t set_quota, + uint64_t quota_bytes); +bool hdd_ipa_is_enabled(hdd_context_t *pHddCtx); +bool hdd_ipa_uc_is_enabled(hdd_context_t *pHddCtx); +#ifndef QCA_LL_TX_FLOW_CONTROL_V2 +int hdd_ipa_send_mcc_scc_msg(hdd_context_t *hdd_ctx, bool mcc_mode); +#else +static inline int hdd_ipa_send_mcc_scc_msg(hdd_context_t *hdd_ctx, + bool mcc_mode) +{ + return 0; +} +#endif +int hdd_ipa_uc_ssr_reinit(hdd_context_t *hdd_ctx); +int hdd_ipa_uc_ssr_deinit(void); +void hdd_ipa_uc_force_pipe_shutdown(hdd_context_t *hdd_ctx); +struct sk_buff *hdd_ipa_tx_packet_ipa(hdd_context_t *hdd_ctx, + struct sk_buff *skb, uint8_t session_id); +bool hdd_ipa_is_present(hdd_context_t *hdd_ctx); +void hdd_ipa_dump_info(hdd_context_t *hdd_ctx); +QDF_STATUS hdd_ipa_uc_ol_init(hdd_context_t *hdd_ctx); +int hdd_ipa_uc_ol_deinit(hdd_context_t *hdd_ctx); +#else +static inline QDF_STATUS hdd_ipa_init(hdd_context_t *hdd_ctx) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS hdd_ipa_cleanup(hdd_context_t *hdd_ctx) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS hdd_ipa_process_rxt(void *cds_context, + qdf_nbuf_t rxBuf, uint8_t sta_id) +{ + return QDF_STATUS_SUCCESS; +} + +static inline int hdd_ipa_wlan_evt(hdd_adapter_t *adapter, uint8_t sta_id, + enum hdd_ipa_wlan_event type, uint8_t *mac_addr) +{ + return 0; +} + +static inline int hdd_ipa_send_mcc_scc_msg(hdd_context_t *hdd_ctx, + bool mcc_mode) +{ + return 0; +} + +static inline int hdd_ipa_set_perf_level(hdd_context_t *hdd_ctx, + uint64_t tx_packets, + uint64_t rx_packets) +{ + return 0; +} + +static inline int hdd_ipa_suspend(hdd_context_t *hdd_ctx) +{ + return 0; +} + +static inline int hdd_ipa_resume(hdd_context_t *hdd_ctx) +{ + return 0; +} + +static inline void hdd_ipa_uc_stat_query(hdd_context_t *hdd_ctx, + uint32_t *ipa_tx_diff, + uint32_t *ipa_rx_diff) +{ + *ipa_tx_diff = 0; + *ipa_rx_diff = 0; + return; +} + +static inline void hdd_ipa_uc_stat_request(hdd_adapter_t *adapter, + uint8_t reason) +{ + return; +} + +static inline void hdd_ipa_uc_rt_debug_host_dump(hdd_context_t *hdd_ctx) +{ + return; +} + +static inline bool hdd_ipa_is_enabled(hdd_context_t *pHddCtx) +{ + return false; +} + +static inline bool hdd_ipa_uc_is_enabled(hdd_context_t *pHddCtx) +{ + return false; +} + +static inline void hdd_ipa_dump_info(hdd_context_t *hdd_ctx) +{ + return; +} + +static inline int hdd_ipa_uc_ssr_reinit(hdd_context_t *hdd_ctx) +{ + return false; +} + +static inline int hdd_ipa_uc_ssr_deinit(void) +{ + return false; +} +static inline void hdd_ipa_uc_force_pipe_shutdown(hdd_context_t *hdd_ctx) +{ + return; +} + +/** + * hdd_ipa_tx_packet_ipa() - send packet to IPA + * @hdd_ctx: Global HDD context + * @skb: skb sent to IPA + * @session_id: send packet instance session id + * + * Send TX packet which generated by system to IPA. + * This routine only will be used for function verification + * + * Return: NULL packet sent to IPA properly + * skb packet not sent to IPA. legacy data path should handle + */ +static inline struct sk_buff *hdd_ipa_tx_packet_ipa(hdd_context_t *hdd_ctx, + struct sk_buff *skb, uint8_t session_id) +{ + return skb; +} + +/** + * hdd_ipa_is_present() - get IPA hw status + * @hdd_ctx: pointer to hdd context + * + * ipa_uc_reg_rdyCB is not directly designed to check + * ipa hw status. This is an undocumented function which + * has confirmed with IPA team. + * + * Return: true - ipa hw present + * false - ipa hw not present + */ +bool hdd_ipa_is_present(hdd_context_t *hdd_ctx) +{ + return false; +} + +/** + * hdd_ipa_uc_ol_init() - Initialize IPA uC offload + * @hdd_ctx: Global HDD context + * + * Return: QDF_STATUS + */ +QDF_STATUS hdd_ipa_uc_ol_init(hdd_context_t *hdd_ctx) +{ + return QDF_STATUS_SUCCESS; +} + +/** + * hdd_ipa_uc_ol_deinit() - Disconnect IPA TX and RX pipes + * @hdd_ctx: Global HDD context + * + * Return: 0 on success, negativer errno on error + */ +static int hdd_ipa_uc_ol_deinit(hdd_context_t *hdd_ctx) +{ + return 0; +} +#endif /* IPA_OFFLOAD */ +#endif /* #ifndef HDD_IPA_H__ */ diff --git a/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_lro.h b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_lro.h new file mode 100644 index 0000000000000000000000000000000000000000..9d12b6a61ad8c79fc8f2da6643a66c210748e13d --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_lro.h @@ -0,0 +1,246 @@ +/* + * Copyright (c) 2015-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef __WLAN_HDD_LRO_H__ +#define __WLAN_HDD_LRO_H__ +/** + * DOC: wlan_hdd_lro.h + * + * WLAN LRO interface module headers + */ + +/** + * enum hdd_lro_rx_status - LRO receive frame status + * @HDD_LRO_RX: frame sent over the LRO interface + * @HDD_LRO_NO_RX: frame not sent over the LRO interface + */ +enum hdd_lro_rx_status { + HDD_LRO_RX = 0, + HDD_LRO_NO_RX = 1, +}; + +#if defined(FEATURE_LRO) + +#include +#include + +/* LRO_DESC_TABLE_SZ must be a power of 2 */ +#define LRO_DESC_TABLE_SZ 16 +#define LRO_DESC_TABLE_SZ_MASK (LRO_DESC_TABLE_SZ - 1) +#define LRO_DESC_POOL_SZ 10 + +/** + * hdd_lro_desc_entry - defines the LRO descriptor + * element stored in the list + * @lro_node: node of the list + * @lro_desc: the LRO descriptor contained in this list entry + */ +struct hdd_lro_desc_entry { + struct list_head lro_node; + struct net_lro_desc *lro_desc; +}; + +/** + * hdd_lro_desc_pool - pool of free LRO descriptors + * @lro_desc_array: array of LRO descriptors allocated + * @lro_free_list_head: head of the list + * @lro_pool_lock: lock to protect access to the list + */ +struct hdd_lro_desc_pool { + struct hdd_lro_desc_entry *lro_desc_array; + struct list_head lro_free_list_head; +}; + +/** + * hdd_lro_desc_table - defines each entry of the LRO + * hash table + * @lro_desc_list: list of LRO descriptors + */ +struct hdd_lro_desc_table { + struct list_head lro_desc_list; +}; + +/** + * hdd_lro_desc_info - structure containing the LRO + * descriptor information + * @lro_hash_table: hash table used for a quick desc. look-up + * @lro_hash_lock: lock to protect access to the hash table + * @lro_desc_pool: Free pool of LRO descriptors + */ +struct hdd_lro_desc_info { + struct hdd_lro_desc_table *lro_hash_table; + struct hdd_lro_desc_pool lro_desc_pool; +}; + +/** + * enum hdd_lro_pkt_aggr_bucket - idenitifies the bucket holding + * the count of the aggregated packets + * @HDD_LRO_BUCKET_0_7: identifies the packet count when the + * aggregate size is between 0 to 7 packets + * @HDD_LRO_BUCKET_8_15: identifies the packet count when the + * aggregate size is between 8 to 15 packets + * @HDD_LRO_BUCKET_16_23: identifies the packet count when the + * aggregate size is between 16 to 23 packets + * @HDD_LRO_BUCKET_24_31: identifies the packet count when the + * aggregate size is between 24 to 31 packets + * @HDD_LRO_BUCKET_32_39: identifies the packet count when the + * aggregate size is between 32 to 39 packets + * @HDD_LRO_BUCKET_40_47: identifies the packet count when the + * aggregate size is between 40 to 47 packets + * @HDD_LRO_BUCKET_48_OR_MORE: identifies the packet count when + * the aggregate size is 48 or more packets + * @HDD_LRO_BUCKET_MAX: identifies the packet count when the + * aggregate size is 48 or more packets + */ +enum hdd_lro_pkt_aggr_bucket { + HDD_LRO_BUCKET_0_7 = 0, + HDD_LRO_BUCKET_8_15 = 1, + HDD_LRO_BUCKET_16_23 = 2, + HDD_LRO_BUCKET_24_31 = 3, + HDD_LRO_BUCKET_32_39 = 4, + HDD_LRO_BUCKET_40_47 = 5, + HDD_LRO_BUCKET_48_OR_MORE = 6, + HDD_LRO_BUCKET_MAX = HDD_LRO_BUCKET_48_OR_MORE, +}; + +/** + * hdd_lro_stats - structure containing the LRO statistics + * information + * @pkt_aggr_hist: histogram of the number of aggregated packets + * @lro_eligible_tcp: number of LRO elgible TCP packets + * @lro_ineligible_tcp: number of LRO inelgible TCP packets + */ +struct hdd_lro_stats { + uint16_t pkt_aggr_hist[HDD_LRO_BUCKET_MAX + 1]; + uint32_t lro_eligible_tcp; + uint32_t lro_ineligible_tcp; +}; + +/** + * hdd_lro_s - LRO information per HDD adapter + * @lro_mgr: LRO manager + * @lro_desc_info: LRO descriptor information + * @lro_mgr_arr_access_lock: Lock to access LRO manager array. + * @lro_stats: LRO statistics + */ +struct hdd_lro_s { + struct net_lro_mgr *lro_mgr; + struct hdd_lro_desc_info lro_desc_info; +}; + +int hdd_lro_init(hdd_context_t *hdd_ctx); + +int hdd_lro_enable(hdd_context_t *hdd_ctx, + hdd_adapter_t *adapter); + +void hdd_lro_create(void); + +void hdd_lro_disable(hdd_context_t *hdd_ctx, hdd_adapter_t *adapter); + +void hdd_lro_destroy(void); + +enum hdd_lro_rx_status hdd_lro_rx(hdd_context_t *hdd_ctx, + hdd_adapter_t *adapter, struct sk_buff *skb); + +void hdd_lro_flush_all(hdd_context_t *hdd_ctx, + hdd_adapter_t *adapter); + +void hdd_lro_display_stats(hdd_context_t *hdd_ctx); +void hdd_enable_lro_in_concurrency(hdd_context_t *hdd_ctx); +void hdd_disable_lro_in_concurrency(hdd_context_t *hdd_ctx); +void hdd_disable_lro_for_low_tput(hdd_context_t *hdd_ctx, bool disable); +QDF_STATUS hdd_lro_set_reset(hdd_context_t *hdd_ctx, + hdd_adapter_t *adapter, + uint8_t enable_flag); +#else +struct hdd_lro_s {}; + +static inline int hdd_lro_enable(hdd_context_t *hdd_ctx, + hdd_adapter_t *adapter) +{ + return 0; +} + +static inline void hdd_lro_create(void) +{ +} + +static inline enum hdd_lro_rx_status hdd_lro_rx(hdd_context_t *hdd_ctx, + hdd_adapter_t *adapter, struct sk_buff *skb) +{ + return HDD_LRO_NO_RX; +} + +static inline int hdd_lro_init(hdd_context_t *hdd_ctx) +{ + return 0; +} + +static inline void hdd_lro_disable(hdd_context_t *hdd_ctx, + hdd_adapter_t *adapter) +{ + return; +} + +static inline void hdd_lro_destroy(void) +{ +} + +static inline void hdd_lro_display_stats(hdd_context_t *hdd_ctx) +{ + return; +} + +static inline void hdd_enable_lro_in_concurrency(hdd_context_t *hdd_ctx) +{ +} + +static inline void hdd_disable_lro_in_concurrency(hdd_context_t *hdd_ctx) +{ +} + +/** + * hdd_disable_lro_for_low_tput() - enable/disable LRO based on tput + * hdd_ctx: hdd context + * disable: boolean to enable/disable LRO + * + * This API enables/disables LRO based on tput. + * + * Return: void + */ +static inline void +hdd_disable_lro_for_low_tput(hdd_context_t *hdd_ctx, bool disable) +{ +} + +static inline QDF_STATUS hdd_lro_set_reset(hdd_context_t *hdd_ctx, + hdd_adapter_t *adapter, + uint8_t enable_flag) +{ + return 0; +} +#endif /* FEATURE_LRO */ +#endif /* __WLAN_HDD_LRO_H__ */ diff --git a/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_main.h b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_main.h new file mode 100644 index 0000000000000000000000000000000000000000..309eb77b895c28d8f13d61286d9085bdc7d3ad74 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_main.h @@ -0,0 +1,2259 @@ +/* + * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#if !defined(WLAN_HDD_MAIN_H) +#define WLAN_HDD_MAIN_H +/**=========================================================================== + + \file WLAN_HDD_MAIN_H.h + + \brief Linux HDD Adapter Type + + ==========================================================================*/ + +/*--------------------------------------------------------------------------- + Include files + -------------------------------------------------------------------------*/ + +#include +#include +#include +#include +#include +#include "sir_mac_prot_def.h" +#include "csr_api.h" +#include +#include +#include +#include +#if defined(WLAN_OPEN_SOURCE) && defined(CONFIG_HAS_WAKELOCK) +#include +#endif +#include +#include "wlan_hdd_tdls.h" +#include "wlan_hdd_tsf.h" +#include "wlan_hdd_cfg80211.h" +#include +#include "sap_api.h" +#include "ol_txrx_osif_api.h" +#include "ol_txrx_ctrl_api.h" +#include +#include "cdp_txrx_flow_ctrl_legacy.h" +#include +#include "wlan_hdd_nan_datapath.h" +#include "wlan_tgt_def_config.h" + +/*--------------------------------------------------------------------------- + Preprocessor definitions and constants + -------------------------------------------------------------------------*/ +/** Number of Tx Queues */ +#ifdef QCA_LL_TX_FLOW_CONTROL_V2 +#define NUM_TX_QUEUES 5 +#else +#define NUM_TX_QUEUES 4 +#endif + +/** Length of the TX queue for the netdev */ +#define HDD_NETDEV_TX_QUEUE_LEN (3000) + +/** Hdd Tx Time out value */ +#ifdef LIBRA_LINUX_PC +#define HDD_TX_TIMEOUT (8000) +#else +#define HDD_TX_TIMEOUT msecs_to_jiffies(5000) +#endif +/** Hdd Default MTU */ +#define HDD_DEFAULT_MTU (1500) + +#ifdef QCA_CONFIG_SMP +#define NUM_CPUS NR_CPUS +#else +#define NUM_CPUS 1 +#endif + +/**event flags registered net device*/ +#define NET_DEVICE_REGISTERED (0) +#define SME_SESSION_OPENED (1) +#define INIT_TX_RX_SUCCESS (2) +#define WMM_INIT_DONE (3) +#define SOFTAP_BSS_STARTED (4) +#define DEVICE_IFACE_OPENED (5) +#define TDLS_INIT_DONE (6) +#define ACS_PENDING (7) +#define SOFTAP_INIT_DONE (8) + +/* HDD global event flags */ +#define ACS_IN_PROGRESS (0) + +/** Maximum time(ms)to wait for disconnect to complete **/ +#ifdef QCA_WIFI_3_0_EMU +#define WLAN_WAIT_TIME_DISCONNECT 5000 +#else +#define WLAN_WAIT_TIME_DISCONNECT 5000 +#endif +#define WLAN_WAIT_TIME_STOP_ROAM 4000 +#define WLAN_WAIT_TIME_STATS 800 +#define WLAN_WAIT_TIME_POWER 800 +#define WLAN_WAIT_TIME_COUNTRY 1000 +#define WLAN_WAIT_TIME_LINK_STATUS 800 +#define WLAN_WAIT_TIME_POWER_STATS 800 +/* Amount of time to wait for sme close session callback. + This value should be larger than the timeout used by WDI to wait for + a response from WCNSS */ +#define WLAN_WAIT_TIME_SESSIONOPENCLOSE 15000 +#define WLAN_WAIT_TIME_ABORTSCAN 2000 + +/** Maximum time(ms) to wait for mc thread suspend **/ +#define WLAN_WAIT_TIME_MCTHREAD_SUSPEND 1200 + +/** Maximum time(ms) to wait for target to be ready for suspend **/ +#define WLAN_WAIT_TIME_READY_TO_SUSPEND 2000 + +/** Maximum time(ms) to wait for tdls add sta to complete **/ +#define WAIT_TIME_TDLS_ADD_STA 1500 + +/** Maximum time(ms) to wait for tdls del sta to complete **/ +#define WAIT_TIME_TDLS_DEL_STA 1500 + +/** Maximum time(ms) to wait for Link Establish Req to complete **/ +#define WAIT_TIME_TDLS_LINK_ESTABLISH_REQ 1500 + +/** Maximum time(ms) to wait for tdls mgmt to complete **/ +#define WAIT_TIME_TDLS_MGMT 11000 + +/* Scan Req Timeout */ +#define WLAN_WAIT_TIME_SCAN_REQ 100 + +#define WLAN_WAIT_TIME_ANTENNA_MODE_REQ 3000 +#define WLAN_WAIT_TIME_SET_DUAL_MAC_CFG 1500 + +#define WLAN_WAIT_TIME_BPF 1000 + +/* rcpi request timeout in milli seconds */ +#define WLAN_WAIT_TIME_RCPI 500 +/* Maximum time(ms) to wait for RSO CMD status event */ +#define WAIT_TIME_RSO_CMD_STATUS 2000 + +#define MAX_NUMBER_OF_ADAPTERS 4 + +#define MAX_CFG_STRING_LEN 255 + +#define MAC_ADDR_ARRAY(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5] +/** Mac Address string **/ +#define MAC_ADDRESS_STR "%02x:%02x:%02x:%02x:%02x:%02x" +#define MAC_ADDRESS_STR_LEN 18 /* Including null terminator */ +/* Max and min IEs length in bytes */ +#define MAX_GENIE_LEN (512) +#define MIN_GENIE_LEN (2) + +#define WLAN_CHIP_VERSION "WCNSS" + +#define hdd_log(level, args...) QDF_TRACE(QDF_MODULE_ID_HDD, level, ## args) +#define hdd_logfl(level, format, args...) hdd_log(level, FL(format), ## args) + +#define hdd_alert(format, args...) \ + hdd_logfl(QDF_TRACE_LEVEL_FATAL, format, ## args) +#define hdd_err(format, args...) \ + hdd_logfl(QDF_TRACE_LEVEL_ERROR, format, ## args) +#define hdd_warn(format, args...) \ + hdd_logfl(QDF_TRACE_LEVEL_WARN, format, ## args) +#define hdd_notice(format, args...) \ + hdd_logfl(QDF_TRACE_LEVEL_INFO, format, ## args) +#define hdd_info(format, args...) \ + hdd_logfl(QDF_TRACE_LEVEL_INFO_HIGH, format, ## args) +#define hdd_debug(format, args...) \ + hdd_logfl(QDF_TRACE_LEVEL_DEBUG, format, ## args) + +#define ENTER() hdd_logfl(QDF_TRACE_LEVEL_INFO_LOW, "enter") +#define ENTER_DEV(dev) \ + hdd_logfl(QDF_TRACE_LEVEL_INFO_LOW, "enter(%s)", (dev)->name) +#define EXIT() hdd_logfl(QDF_TRACE_LEVEL_INFO_LOW, "exit") + +#define WLAN_HDD_GET_PRIV_PTR(__dev__) (hdd_adapter_t *)(netdev_priv((__dev__))) + +#define MAX_NO_OF_2_4_CHANNELS 14 + +#define WLAN_HDD_PUBLIC_ACTION_FRAME 4 +#define WLAN_HDD_PUBLIC_ACTION_FRAME_OFFSET 24 +#define WLAN_HDD_PUBLIC_ACTION_FRAME_BODY_OFFSET 24 +#define WLAN_HDD_PUBLIC_ACTION_FRAME_TYPE_OFFSET 30 +#define WLAN_HDD_PUBLIC_ACTION_FRAME_CATEGORY_OFFSET 0 +#define WLAN_HDD_PUBLIC_ACTION_FRAME_ACTION_OFFSET 1 +#define WLAN_HDD_PUBLIC_ACTION_FRAME_OUI_OFFSET 2 +#define WLAN_HDD_PUBLIC_ACTION_FRAME_OUI_TYPE_OFFSET 5 +#define WLAN_HDD_VENDOR_SPECIFIC_ACTION 0x09 +#define WLAN_HDD_WFA_OUI 0x506F9A +#define WLAN_HDD_WFA_P2P_OUI_TYPE 0x09 +#define WLAN_HDD_P2P_SOCIAL_CHANNELS 3 +#define WLAN_HDD_P2P_SINGLE_CHANNEL_SCAN 1 +#define WLAN_HDD_PUBLIC_ACTION_FRAME_SUB_TYPE_OFFSET 6 + +#define WLAN_HDD_IS_SOCIAL_CHANNEL(center_freq) \ + (((center_freq) == 2412) || ((center_freq) == 2437) || ((center_freq) == 2462)) + +#define WLAN_HDD_CHANNEL_IN_UNII_1_BAND(center_freq) \ + (((center_freq) == 5180) || ((center_freq) == 5200) \ + || ((center_freq) == 5220) || ((center_freq) == 5240)) + +#ifdef WLAN_FEATURE_11W +#define WLAN_HDD_SA_QUERY_ACTION_FRAME 8 +#endif + +#define WLAN_HDD_PUBLIC_ACTION_TDLS_DISC_RESP 14 +#define WLAN_HDD_TDLS_ACTION_FRAME 12 + +#define WLAN_HDD_QOS_ACTION_FRAME 1 +#define WLAN_HDD_QOS_MAP_CONFIGURE 4 +#define HDD_SAP_WAKE_LOCK_DURATION 10000 /* in msecs */ + +#if defined(CONFIG_HL_SUPPORT) +#define HDD_MOD_EXIT_SSR_MAX_RETRIES 200 +#else +#define HDD_MOD_EXIT_SSR_MAX_RETRIES 75 +#endif + +#ifdef WLAN_FEATURE_GTK_OFFLOAD +#define GTK_OFFLOAD_ENABLE 0 +#define GTK_OFFLOAD_DISABLE 1 +#endif + +#define MAX_USER_COMMAND_SIZE 4096 + +#define HDD_MIN_TX_POWER (-100) /* minimum tx power */ +#define HDD_MAX_TX_POWER (+100) /* maximum tx power */ + +/* FW expects burst duration in 1020*ms */ +#define SIFS_BURST_DUR_MULTIPLIER 1020 +#define SIFS_BURST_DUR_MAX 12240 + +/* If IPA UC data path is enabled, target should reserve extra tx descriptors + * for IPA data path. + * Then host data path should allow less TX packet pumping in case + * IPA data path enabled + */ +#define WLAN_TFC_IPAUC_TX_DESC_RESERVE 100 + +/* + * NET_NAME_UNKNOWN is only introduced after Kernel 3.17, to have a macro + * here if the Kernel version is less than 3.17 to avoid the interleave + * conditional compilation. + */ +#if !((LINUX_VERSION_CODE >= KERNEL_VERSION(3, 17, 0)) || defined(WITH_BACKPORTS)) +#define NET_NAME_UNKNOWN 0 +#endif + +#define PRE_CAC_SSID "pre_cac_ssid" + +/* session ID invalid */ +#define HDD_SESSION_ID_INVALID 0xFF + +#define SCAN_REJECT_THRESHOLD_TIME 300000 /* Time is in msec, equal to 5 mins */ + +/* wait time for nud stats in milliseconds */ +#define WLAN_WAIT_TIME_NUD_STATS 800 +/* nud stats skb max length */ +#define WLAN_NUD_STATS_LEN 800 +/* ARP packet type for NUD debug stats */ +#define WLAN_NUD_STATS_ARP_PKT_TYPE 1 + +/* + * @eHDD_SCAN_REJECT_DEFAULT: default value + * @eHDD_CONNECTION_IN_PROGRESS: connection is in progress + * @eHDD_REASSOC_IN_PROGRESS: reassociation is in progress + * @eHDD_EAPOL_IN_PROGRESS: STA/P2P-CLI is in middle of EAPOL/WPS exchange + * @eHDD_SAP_EAPOL_IN_PROGRESS: SAP/P2P-GO is in middle of EAPOL/WPS exchange + */ +typedef enum { + eHDD_SCAN_REJECT_DEFAULT = 0, + eHDD_CONNECTION_IN_PROGRESS, + eHDD_REASSOC_IN_PROGRESS, + eHDD_EAPOL_IN_PROGRESS, + eHDD_SAP_EAPOL_IN_PROGRESS, +} scan_reject_states; + +/* + * Generic asynchronous request/response support + * + * Many of the APIs supported by HDD require a call to SME to + * perform an action or to retrieve some data. In most cases SME + * performs the operation asynchronously, and will execute a provided + * callback function when the request has completed. In order to + * synchronize this the HDD API allocates a context which is then + * passed to SME, and which is then, in turn, passed back to the + * callback function when the operation completes. The callback + * function then sets a completion variable inside the context which + * the HDD API is waiting on. In an ideal world the HDD API would + * wait forever (or at least for a long time) for the response to be + * received and for the completion variable to be set. However in + * most cases these HDD APIs are being invoked in the context of a + * user space thread which has invoked either a cfg80211 API or a + * wireless extensions ioctl and which has taken the kernel rtnl_lock. + * Since this lock is used to synchronize many of the kernel tasks, we + * do not want to hold it for a long time. In addition we do not want + * to block user space threads (such as the wpa supplicant's main + * thread) for an extended time. Therefore we only block for a short + * time waiting for the response before we timeout. This means that + * it is possible for the HDD API to timeout, and for the callback to + * be invoked afterwards. In order for the callback function to + * determine if the HDD API is still waiting, a magic value is also + * stored in the shared context. Only if the context has a valid + * magic will the callback routine do any work. In order to further + * synchronize these activities a spinlock is used so that if any HDD + * API timeout coincides with its callback, the operations of the two + * threads will be serialized. + */ + +struct statsContext { + struct completion completion; + hdd_adapter_t *pAdapter; + unsigned int magic; +}; + +struct linkspeedContext { + struct completion completion; + hdd_adapter_t *pAdapter; + unsigned int magic; +}; + +extern spinlock_t hdd_context_lock; +extern struct mutex hdd_init_deinit_lock; + +#define STATS_CONTEXT_MAGIC 0x53544154 /* STAT */ +#define RSSI_CONTEXT_MAGIC 0x52535349 /* RSSI */ +#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) */ +#define BPF_CONTEXT_MAGIC 0x4575354 /* BPF */ +#define POWER_STATS_MAGIC 0x14111990 +#define RCPI_CONTEXT_MAGIC 0x7778888 /* RCPI */ + +/* MAX OS Q block time value in msec + * Prevent from permanent stall, resume OS Q if timer expired */ +#define WLAN_HDD_TX_FLOW_CONTROL_OS_Q_BLOCK_TIME 1000 +#define WLAN_SAP_HDD_TX_FLOW_CONTROL_OS_Q_BLOCK_TIME 100 +#define WLAN_HDD_TX_FLOW_CONTROL_MAX_24BAND_CH 14 + +#define NUM_TX_RX_HISTOGRAM 128 +#define NUM_TX_RX_HISTOGRAM_MASK (NUM_TX_RX_HISTOGRAM - 1) + +/** + * struct hdd_tx_rx_histogram - structure to keep track of tx and rx packets + * received over 100ms intervals + * @interval_rx: # of rx packets received in the last 100ms interval + * @interval_tx: # of tx packets received in the last 100ms interval + * @next_vote_level: pld_bus_width_type voting level (high or low) + * determined on the basis of total tx and rx packets + * received in the last 100ms interval + * @next_rx_level: pld_bus_width_type voting level (high or low) + * determined on the basis of rx packets received in the + * last 100ms interval + * @next_tx_level: pld_bus_width_type voting level (high or low) + * determined on the basis of tx packets received in the + * last 100ms interval + * @qtime timestamp when the record is added + * + * The structure keeps track of throughput requirements of wlan driver. + * An entry is added if either of next_vote_level, next_rx_level or + * next_tx_level changes. An entry is not added for every 100ms interval. + */ +struct hdd_tx_rx_histogram { + uint64_t interval_rx; + uint64_t interval_tx; + uint32_t next_vote_level; + uint32_t next_rx_level; + uint32_t next_tx_level; + uint64_t qtime; +}; + +typedef struct hdd_tx_rx_stats_s { + /* start_xmit stats */ + __u32 txXmitCalled; + __u32 txXmitDropped; + __u32 txXmitOrphaned; + __u32 txXmitClassifiedAC[NUM_TX_QUEUES]; + __u32 txXmitDroppedAC[NUM_TX_QUEUES]; + + /* rx stats */ + __u32 rxPackets[NUM_CPUS]; + __u32 rxDropped[NUM_CPUS]; + __u32 rxDelivered[NUM_CPUS]; + __u32 rxRefused[NUM_CPUS]; + + /* txflow stats */ + bool is_txflow_paused; + __u32 txflow_pause_cnt; + __u32 txflow_unpause_cnt; + __u32 txflow_timer_cnt; +} hdd_tx_rx_stats_t; + +#ifdef WLAN_FEATURE_11W +typedef struct hdd_pmf_stats_s { + uint8_t numUnprotDeauthRx; + uint8_t numUnprotDisassocRx; +} hdd_pmf_stats_t; +#endif + +struct hdd_arp_stats_s { + uint16_t tx_arp_req_count; + uint16_t rx_arp_rsp_count; + uint16_t tx_dropped; + uint16_t rx_dropped; + uint16_t rx_delivered; + uint16_t rx_refused; + uint16_t tx_host_fw_sent; + uint16_t rx_host_drop_reorder; + uint16_t rx_fw_cnt; + uint16_t tx_ack_cnt; +}; + +typedef struct hdd_stats_s { + tCsrSummaryStatsInfo summary_stat; + tCsrGlobalClassAStatsInfo ClassA_stat; + tCsrGlobalClassBStatsInfo ClassB_stat; + tCsrGlobalClassCStatsInfo ClassC_stat; + tCsrGlobalClassDStatsInfo ClassD_stat; + tCsrPerStaStatsInfo perStaStats; + struct csr_per_chain_rssi_stats_info per_chain_rssi_stats; + hdd_tx_rx_stats_t hddTxRxStats; + struct hdd_arp_stats_s hdd_arp_stats; +#ifdef WLAN_FEATURE_11W + hdd_pmf_stats_t hddPmfStats; +#endif +} hdd_stats_t; + +typedef enum { + HDD_ROAM_STATE_NONE, + + /* Issuing a disconnect due to transition into low power states. */ + HDD_ROAM_STATE_DISCONNECTING_POWER, + + /* move to this state when HDD sets a key with SME/CSR. Note this is */ + /* an important state to get right because we will get calls into our SME */ + /* callback routine for SetKey activity that we did not initiate! */ + HDD_ROAM_STATE_SETTING_KEY, +} HDD_ROAM_STATE; + +typedef struct roaming_info_s { + HDD_ROAM_STATE roamingState; + qdf_event_t roamingEvent; + + tSirMacAddr bssid; + tSirMacAddr peerMac; + uint32_t roamId; + eRoamCmdStatus roamStatus; + bool deferKeyComplete; + +} roaming_info_t; + +#ifdef FEATURE_WLAN_WAPI +/* Define WAPI macros for Length, BKID count etc*/ +#define MAX_WPI_KEY_LENGTH 16 +#define MAX_NUM_PN 16 +#define MAC_ADDR_LEN 6 +#define MAX_ADDR_INDEX 12 +#define MAX_NUM_AKM_SUITES 16 +#define MAX_NUM_UNI_SUITES 16 +#define MAX_NUM_BKIDS 16 + +/** WAPI AUTH mode definition */ +enum _WAPIAuthMode { + WAPI_AUTH_MODE_OPEN = 0, + WAPI_AUTH_MODE_PSK = 1, + WAPI_AUTH_MODE_CERT +} __packed; +typedef enum _WAPIAuthMode WAPIAuthMode; + +/** WAPI Work mode structure definition */ +#define WZC_ORIGINAL 0 +#define WAPI_EXTENTION 1 + +struct _WAPI_FUNCTION_MODE { + unsigned char wapiMode; +} __packed; + +typedef struct _WAPI_FUNCTION_MODE WAPI_FUNCTION_MODE; + +typedef struct _WAPI_BKID { + uint8_t bkid[16]; +} WAPI_BKID, *pWAPI_BKID; + +/** WAPI Association information structure definition */ +struct _WAPI_AssocInfo { + uint8_t elementID; + uint8_t length; + uint16_t version; + uint16_t akmSuiteCount; + uint32_t akmSuite[MAX_NUM_AKM_SUITES]; + uint16_t unicastSuiteCount; + uint32_t unicastSuite[MAX_NUM_UNI_SUITES]; + uint32_t multicastSuite; + uint16_t wapiCability; + uint16_t bkidCount; + WAPI_BKID bkidList[MAX_NUM_BKIDS]; +} __packed; + +typedef struct _WAPI_AssocInfo WAPI_AssocInfo; +typedef struct _WAPI_AssocInfo *pWAPI_IEAssocInfo; + +/** WAPI KEY Type definition */ +enum _WAPIKeyType { + PAIRWISE_KEY, /* 0 */ + GROUP_KEY /* 1 */ +} __packed; +typedef enum _WAPIKeyType WAPIKeyType; + +/** WAPI KEY Direction definition */ +enum _KEY_DIRECTION { + None, + Rx, + Tx, + Rx_Tx +} __packed; + +typedef enum _KEY_DIRECTION WAPI_KEY_DIRECTION; + +/* WAPI KEY structure definition */ +struct WLAN_WAPI_KEY { + WAPIKeyType keyType; + WAPI_KEY_DIRECTION keyDirection; /*reserved for future use */ + uint8_t keyId; + uint8_t addrIndex[MAX_ADDR_INDEX]; /*reserved for future use */ + int wpiekLen; + uint8_t wpiek[MAX_WPI_KEY_LENGTH]; + int wpickLen; + uint8_t wpick[MAX_WPI_KEY_LENGTH]; + uint8_t pn[MAX_NUM_PN]; /*reserved for future use */ +} __packed; + +typedef struct WLAN_WAPI_KEY WLAN_WAPI_KEY; +typedef struct WLAN_WAPI_KEY *pWLAN_WAPI_KEY; + +#define WPA_GET_LE16(a) ((u16) (((a)[1] << 8) | (a)[0])) +#define WPA_GET_BE24(a) ((u32) ((a[0] << 16) | (a[1] << 8) | a[2])) +#define WLAN_EID_WAPI 68 +#define WAPI_PSK_AKM_SUITE 0x02721400 +#define WAPI_CERT_AKM_SUITE 0x01721400 + +/* WAPI BKID List structure definition */ +struct _WLAN_BKID_LIST { + uint32_t length; + uint32_t BKIDCount; + WAPI_BKID BKID[1]; +} __packed; + +typedef struct _WLAN_BKID_LIST WLAN_BKID_LIST; +typedef struct _WLAN_BKID_LIST *pWLAN_BKID_LIST; + +/* WAPI Information structure definition */ +struct hdd_wapi_info_s { + uint32_t nWapiMode; + bool fIsWapiSta; + struct qdf_mac_addr cachedMacAddr; + uint8_t wapiAuthMode; +} __packed; +typedef struct hdd_wapi_info_s hdd_wapi_info_t; +#endif /* FEATURE_WLAN_WAPI */ + +typedef struct beacon_data_s { + u8 *head; + u8 *tail; + u8 *proberesp_ies; + u8 *assocresp_ies; + int head_len; + int tail_len; + int proberesp_ies_len; + int assocresp_ies_len; + int dtim_period; +} beacon_data_t; + +typedef enum rem_on_channel_request_type { + REMAIN_ON_CHANNEL_REQUEST, + OFF_CHANNEL_ACTION_TX, +} rem_on_channel_request_type_t; + +typedef struct action_pkt_buffer { + uint8_t *frame_ptr; + uint32_t frame_length; + uint16_t freq; +} action_pkt_buffer_t; + +typedef struct hdd_remain_on_chan_ctx { + struct net_device *dev; + struct ieee80211_channel chan; + enum nl80211_channel_type chan_type; + unsigned int duration; + u64 cookie; + rem_on_channel_request_type_t rem_on_chan_request; + qdf_mc_timer_t hdd_remain_on_chan_timer; + action_pkt_buffer_t action_pkt_buff; + bool hdd_remain_on_chan_cancel_in_progress; + uint32_t scan_id; +} hdd_remain_on_chan_ctx_t; + +/* RoC Request entry */ +typedef struct hdd_roc_req { + qdf_list_node_t node; /* MUST be first element */ + hdd_adapter_t *pAdapter; + hdd_remain_on_chan_ctx_t *pRemainChanCtx; +} hdd_roc_req_t; + +/** + * struct hdd_scan_req - Scan Request entry + * @node : List entry element + * @adapter: Adapter address + * @scan_request: scan request holder + * @scan_id: scan identifier used across host layers which is generated at WMI + * @cookie: scan request identifier sent to userspace + * @source: scan request originator (NL/Vendor scan) + * @timestamp: scan request timestamp + * + * Scan request linked list element + */ +struct hdd_scan_req { + qdf_list_node_t node; + hdd_adapter_t *adapter; + struct cfg80211_scan_request *scan_request; + uint32_t scan_id; + uint8_t source; + uint32_t timestamp; +}; + +typedef enum { + HDD_IDLE, + HDD_PD_REQ_ACK_PENDING, + HDD_GO_NEG_REQ_ACK_PENDING, + HDD_INVALID_STATE, +} eP2PActionFrameState; + +typedef enum { + WLAN_HDD_GO_NEG_REQ, + WLAN_HDD_GO_NEG_RESP, + WLAN_HDD_GO_NEG_CNF, + WLAN_HDD_INVITATION_REQ, + WLAN_HDD_INVITATION_RESP, + WLAN_HDD_DEV_DIS_REQ, + WLAN_HDD_DEV_DIS_RESP, + WLAN_HDD_PROV_DIS_REQ, + WLAN_HDD_PROV_DIS_RESP, +} tActionFrmType; + +typedef struct hdd_cfg80211_state_s { + uint16_t current_freq; + u64 action_cookie; + uint8_t *buf; + size_t len; + hdd_remain_on_chan_ctx_t *remain_on_chan_ctx; + struct mutex remain_on_chan_ctx_lock; + eP2PActionFrameState actionFrmState; + /* is_go_neg_ack_received flag is set to 1 when + * the pending ack for GO negotiation req is + * received. + */ + bool is_go_neg_ack_received; +} hdd_cfg80211_state_t; + +/** + * struct hdd_mon_set_ch_info - Holds monitor mode channel switch params + * @channel: Channel number. + * @cb_mode: Channel bonding + * @channel_width: Channel width 0/1/2 for 20/40/80MHz respectively. + * @phy_mode: PHY mode + */ +struct hdd_mon_set_ch_info { + uint8_t channel; + uint8_t cb_mode; + uint32_t channel_width; + eCsrPhyMode phy_mode; +}; + +struct hdd_station_ctx { + /** Handle to the Wireless Extension State */ + hdd_wext_state_t WextState; + +#ifdef FEATURE_WLAN_TDLS + tdlsCtx_t *pHddTdlsCtx; +#endif + + /**Connection information*/ + connection_info_t conn_info; + + roaming_info_t roam_info; + + int ft_carrier_on; + +#ifdef WLAN_FEATURE_GTK_OFFLOAD + tSirGtkOffloadParams gtkOffloadReqParams; +#endif + /*Increment whenever ibss New peer joins and departs the network */ + int ibss_sta_generation; + + /* Indication of wep/wpa-none keys installation */ + bool ibss_enc_key_installed; + + /*Save the wep/wpa-none keys */ + tCsrRoamSetKey ibss_enc_key; + tSirPeerInfoRspParams ibss_peer_info; + + bool hdd_ReassocScenario; + + /* STA ctx debug variables */ + int staDebugState; + + uint8_t broadcast_staid; + + struct hdd_mon_set_ch_info ch_info; +#ifdef WLAN_FEATURE_NAN_DATAPATH + struct nan_datapath_ctx ndp_ctx; +#endif + bool ap_supports_immediate_power_save; +}; + +#define BSS_STOP 0 +#define BSS_START 1 +typedef struct hdd_hostapd_state_s { + int bssState; + qdf_event_t qdf_event; + qdf_event_t qdf_stop_bss_event; + qdf_event_t qdf_sta_disassoc_event; + QDF_STATUS qdf_status; + bool bCommit; + +} hdd_hostapd_state_t; + +/** + * enum bss_stop_reason - reasons why a BSS is stopped. + * @BSS_STOP_REASON_INVALID: no reason specified explicitly. + * @BSS_STOP_DUE_TO_MCC_SCC_SWITCH: BSS stopped due to host + * driver is trying to switch AP role to a different channel + * to maintain SCC mode with the STA role on the same card. + * this usually happens when STA is connected to an external + * AP that runs on a different channel + */ +enum bss_stop_reason { + BSS_STOP_REASON_INVALID = 0, + BSS_STOP_DUE_TO_MCC_SCC_SWITCH = 1, +}; + +/* + * Per station structure kept in HDD for multiple station support for SoftAP + */ +typedef struct { + /** The station entry is used or not */ + bool isUsed; + + /** Station ID reported back from HAL (through SAP). Broadcast + * uses station ID zero by default in both libra and volans. */ + uint8_t ucSTAId; + + /** MAC address of the station */ + struct qdf_mac_addr macAddrSTA; + + /** Current Station state so HDD knows how to deal with packet + * queue. Most recent states used to change TLSHIM STA state */ + enum ol_txrx_peer_state tlSTAState; + + /** Track QoS status of station */ + bool isQosEnabled; + + /** The station entry for which Deauth is in progress */ + bool isDeauthInProgress; + + /** Number of spatial streams supported */ + uint8_t nss; + + /** Rate Flags for this connection */ + uint32_t rate_flags; +} hdd_station_info_t; + +struct hdd_ap_ctx_s { + hdd_hostapd_state_t HostapdState; + + /* Memory differentiation mode is enabled */ + /* uint16_t uMemoryDiffThreshold; */ + /* uint8_t uNumActiveAC; */ + /* uint8_t uActiveACMask; */ + + /** Packet Count to update uNumActiveAC and uActiveACMask */ + /* uint16_t uUpdatePktCount; */ + + /** Station ID assigned after BSS starts */ + uint8_t uBCStaId; + + uint8_t uPrivacy; /* The privacy bits of configuration */ + + tSirWPSPBCProbeReq WPSPBCProbeReq; + + tsap_Config_t sapConfig; + + struct semaphore semWpsPBCOverlapInd; + + bool apDisableIntraBssFwd; + + qdf_mc_timer_t hdd_ap_inactivity_timer; + + uint8_t operatingChannel; + + bool uIsAuthenticated; + + eCsrEncryptionType ucEncryptType; + + /* This will point to group key data, if it is received before start bss. */ + tCsrRoamSetKey groupKey; + /* This will have WEP key data, if it is received before start bss */ + tCsrRoamSetKey wepKey[CSR_MAX_NUM_KEY]; + + /* WEP default key index */ + uint8_t wep_def_key_idx; + + beacon_data_t *beacon; + + bool bApActive; + + /* SAP Context */ + void *sapContext; + + bool dfs_cac_block_tx; + + enum bss_stop_reason bss_stop_reason; +}; + +typedef struct hdd_scaninfo_s { + /* The scan pending */ + uint32_t mScanPending; + + /* Counter for mScanPending so that the scan pending + error log is not printed for more than 5 times */ + uint32_t mScanPendingCounter; + + /* Additional IE for scan */ + tSirAddie scanAddIE; + + uint8_t *default_scan_ies; + uint8_t default_scan_ies_len; + /* Scan mode */ + tSirScanType scan_mode; + + /* completion variable for abortscan */ + struct completion abortscan_event_var; + +} hdd_scaninfo_t; + +#define WLAN_HDD_MAX_MC_ADDR_LIST CFG_TGT_MAX_MULTICAST_FILTER_ENTRIES + +#ifdef WLAN_FEATURE_PACKET_FILTERING +typedef struct multicast_addr_list { + uint8_t isFilterApplied; + uint8_t mc_cnt; + uint8_t addr[WLAN_HDD_MAX_MC_ADDR_LIST][ETH_ALEN]; +} t_multicast_add_list; +#endif + +#define WLAN_HDD_MAX_HISTORY_ENTRY 10 + +/** + * struct hdd_netif_queue_stats - netif queue operation statistics + * @pause_count - pause counter + * @unpause_count - unpause counter + */ +struct hdd_netif_queue_stats { + uint16_t pause_count; + uint16_t unpause_count; + qdf_time_t total_pause_time; +}; + +/** + * struct hdd_netif_queue_history - netif queue operation history + * @time: timestamp + * @netif_action: action type + * @netif_reason: reason type + * @pause_map: pause map + */ +struct hdd_netif_queue_history { + qdf_time_t time; + uint16_t netif_action; + uint16_t netif_reason; + uint32_t pause_map; +}; + +/** + * struct hdd_chan_change_params - channel related information + * @chan: operating channel + * @chan_params: channel parameters + */ +struct hdd_chan_change_params { + uint8_t chan; + struct ch_params_s chan_params; +}; + +/** + * struct hdd_runtime_pm_context - context to prevent/allow runtime pm + * @scan: scan context to prvent/allow runtime pm + * + * Prevent Runtime PM for scan + */ +struct hdd_runtime_pm_context { + qdf_runtime_lock_t scan; + qdf_runtime_lock_t roc; + qdf_runtime_lock_t dfs; +}; + +/** + * struct hdd_connect_pm_context - Runtime PM connect context per adapter + * @connect: Runtime Connect Context + * + * Structure to hold runtime pm connect context for each adapter. + */ +struct hdd_connect_pm_context { + qdf_runtime_lock_t connect; +}; + +/* + * WLAN_HDD_ADAPTER_MAGIC is a magic number used to identify net devices + * belonging to this driver from net devices belonging to other devices. + * Therefore, the magic number must be unique relative to the numbers for + * other drivers in the system. If WLAN_HDD_ADAPTER_MAGIC is already defined + * (e.g. by compiler argument), then use that. If it's not already defined, + * then use the first 4 characters of MULTI_IF_NAME to construct the magic + * number. If MULTI_IF_NAME is not defined, then use a default magic number. + */ +#ifndef WLAN_HDD_ADAPTER_MAGIC +#ifdef MULTI_IF_NAME +#define WLAN_HDD_ADAPTER_MAGIC \ + (MULTI_IF_NAME[0] == 0 ? 0x574c414e : \ + (MULTI_IF_NAME[1] == 0 ? (MULTI_IF_NAME[0] << 24) : \ + (MULTI_IF_NAME[2] == 0 ? (MULTI_IF_NAME[0] << 24) | \ + (MULTI_IF_NAME[1] << 16) : \ + (MULTI_IF_NAME[0] << 24) | (MULTI_IF_NAME[1] << 16) | \ + (MULTI_IF_NAME[2] << 8) | MULTI_IF_NAME[3]))) +#else +#define WLAN_HDD_ADAPTER_MAGIC 0x574c414e /* ASCII "WLAN" */ +#endif +#endif + +/** + * struct rcpi_info - rcpi info + * @rcpi: computed value in dB + * @mac_addr: peer mac addr for which rcpi is computed + */ +struct rcpi_info { + int32_t rcpi; + struct qdf_mac_addr mac_addr; +}; + +struct hdd_adapter_s { + /* Magic cookie for adapter sanity verification. Note that this + * needs to be at the beginning of the private data structure so + * that it will exists at the beginning of dev->priv and hence + * will always be in mapped memory + */ + uint32_t magic; + + void *pHddCtx; + + /** Handle to the network device */ + struct net_device *dev; + + enum tQDF_ADAPTER_MODE device_mode; + + /** IPv4 notifier callback for handling ARP offload on change in IP */ + struct work_struct ipv4NotifierWorkQueue; +#ifdef WLAN_NS_OFFLOAD + /** IPv6 notifier callback for handling NS offload on change in IP */ + struct work_struct ipv6NotifierWorkQueue; +#endif + + /* TODO Move this to sta Ctx */ + struct wireless_dev wdev; + struct cfg80211_scan_request *request; + + /** ops checks if Opportunistic Power Save is Enable or Not + * ctw stores ctWindow value once we receive Opps command from + * wpa_supplicant then using ctWindow value we need to Enable + * Opportunistic Power Save + */ + uint8_t ops; + uint32_t ctw; + + /** Current MAC Address for the adapter */ + struct qdf_mac_addr macAddressCurrent; + + /**Event Flags*/ + unsigned long event_flags; + + /**Device TX/RX statistics*/ + struct net_device_stats stats; + /** HDD statistics*/ + hdd_stats_t hdd_stats; + /** linkspeed statistics */ + tSirLinkSpeedInfo ls_stats; + + uint8_t sessionId; + + /* Completion variable for session close */ + struct completion session_close_comp_var; + + /* Completion variable for session open */ + struct completion session_open_comp_var; + + /* TODO: move these to sta ctx. These may not be used in AP */ + /** completion variable for disconnect callback */ + struct completion disconnect_comp_var; + + struct completion roaming_comp_var; + + /** Completion of change country code */ + struct completion change_country_code; + + /* completion variable for Linkup Event */ + struct completion linkup_event_var; + + /* completion variable for cancel remain on channel Event */ + struct completion cancel_rem_on_chan_var; + + /* completion variable for off channel remain on channel Event */ + struct completion offchannel_tx_event; + /* Completion variable for action frame */ + struct completion tx_action_cnf_event; + /* Completion variable for remain on channel ready */ + struct completion rem_on_chan_ready_event; + + struct completion sta_authorized_event; +#ifdef FEATURE_WLAN_TDLS + struct completion tdls_add_station_comp; + struct completion tdls_del_station_comp; + struct completion tdls_mgmt_comp; + struct completion tdls_link_establish_req_comp; + QDF_STATUS tdlsAddStaStatus; +#endif + + struct completion ibss_peer_info_comp; + + /* Track whether the linkup handling is needed */ + bool isLinkUpSvcNeeded; + + /* Mgmt Frames TX completion status code */ + uint32_t mgmtTxCompletionStatus; + + /* WMM Status */ + hdd_wmm_status_t hddWmmStatus; +/************************************************************* + */ +/************************************************************* + * TODO - Remove it later + */ + /** Multiple station supports */ + /** Per-station structure */ + spinlock_t staInfo_lock; /* To protect access to station Info */ + hdd_station_info_t aStaInfo[WLAN_MAX_STA_COUNT]; + /* uint8_t uNumActiveStation; */ + +/************************************************************* + */ + +#ifdef FEATURE_WLAN_WAPI + hdd_wapi_info_t wapi_info; +#endif + + int8_t rssi; + int32_t rssi_on_disconnect; +#ifdef WLAN_FEATURE_LPSS + bool rssi_send; +#endif + + uint8_t snr; + + struct work_struct monTxWorkQueue; + struct sk_buff *skb_to_tx; + + union { + hdd_station_ctx_t station; + hdd_ap_ctx_t ap; + } sessionCtx; + +#ifdef WLAN_FEATURE_TSF + /* tsf value received from firmware */ + uint32_t tsf_low; + uint32_t tsf_high; + /* TSF capture state */ + enum hdd_tsf_capture_state tsf_state; + uint64_t tsf_sync_soc_timer; +#endif + + hdd_cfg80211_state_t cfg80211State; + +#ifdef WLAN_FEATURE_PACKET_FILTERING + t_multicast_add_list mc_addr_list; +#endif + uint8_t addr_filter_pattern; + + bool higherDtimTransition; + bool survey_idx; + + hdd_scaninfo_t scan_info; +#ifdef FEATURE_WLAN_ESE + tAniTrafStrmMetrics tsmStats; +#endif + /* Flag to ensure PSB is configured through framework */ + uint8_t psbChanged; + /* UAPSD psb value configured through framework */ + uint8_t configuredPsb; +#ifdef IPA_OFFLOAD + void *ipa_context; +#endif + /* Use delayed work for Sec AP ACS as Pri AP Startup need to complete + * since CSR (PMAC Struct) Config is same for both AP + */ + struct delayed_work acs_pending_work; + + struct work_struct scan_block_work; +#ifdef MSM_PLATFORM + unsigned long prev_rx_packets; + unsigned long prev_tx_packets; + uint64_t prev_fwd_tx_packets; + uint64_t prev_fwd_rx_packets; + int connection; +#endif + bool is_roc_inprogress; + +#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL + qdf_mc_timer_t tx_flow_control_timer; + bool tx_flow_timer_initialized; + unsigned int tx_flow_low_watermark; + unsigned int tx_flow_high_watermark_offset; +#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */ + bool offloads_configured; + + /* DSCP to UP QoS Mapping */ + sme_QosWmmUpType hddWmmDscpToUpMap[WLAN_HDD_MAX_DSCP + 1]; + +#ifdef WLAN_FEATURE_LINK_LAYER_STATS + bool isLinkLayerStatsSet; +#endif + uint8_t linkStatus; + + /* variable for temperature in Celsius */ + int temperature; + + /* Time stamp for last completed RoC request */ + uint64_t last_roc_ts; + + /* Time stamp for start RoC request */ + uint64_t start_roc_ts; + + /* State for synchronous OCB requests to WMI */ + struct sir_ocb_set_config_response ocb_set_config_resp; + struct sir_ocb_get_tsf_timer_response ocb_get_tsf_timer_resp; + struct sir_dcc_get_stats_response *dcc_get_stats_resp; + struct sir_dcc_update_ndl_response dcc_update_ndl_resp; + + /* MAC addresses used for OCB interfaces */ +#ifdef WLAN_FEATURE_DSRC + struct qdf_mac_addr ocb_mac_address[QDF_MAX_CONCURRENCY_PERSONA]; + int ocb_mac_addr_count; +#endif + + /* BITMAP indicating pause reason */ + uint32_t pause_map; + spinlock_t pause_map_lock; + qdf_time_t start_time; + qdf_time_t last_time; + qdf_time_t total_pause_time; + qdf_time_t total_unpause_time; + uint8_t history_index; + struct hdd_netif_queue_history + queue_oper_history[WLAN_HDD_MAX_HISTORY_ENTRY]; + struct hdd_netif_queue_stats queue_oper_stats[WLAN_REASON_TYPE_MAX]; + ol_txrx_tx_fp tx_fn; + /* debugfs entry */ + struct dentry *debugfs_phy; + /* + * The pre cac channel is saved here and will be used when the SAP's + * channel needs to be moved from the existing 2.4GHz channel. + */ + uint8_t pre_cac_chan; + struct hdd_connect_pm_context connect_rpm_ctx; + struct power_stats_response *chip_power_stats; + + bool fast_roaming_allowed; + + /* rcpi information */ + struct rcpi_info rcpi; + /* + * Indicate if HO fails during disconnect so that + * disconnect is not initiated by HDD as its already + * initiated by CSR + */ + bool roam_ho_fail; + struct lfr_firmware_status lfr_fw_status; + bool con_status; + bool dad; +}; + +#define WLAN_HDD_GET_STATION_CTX_PTR(pAdapter) (&(pAdapter)->sessionCtx.station) +#define WLAN_HDD_GET_AP_CTX_PTR(pAdapter) (&(pAdapter)->sessionCtx.ap) +#define WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter) (&(pAdapter)->sessionCtx.station.WextState) +#define WLAN_HDD_GET_CTX(pAdapter) ((hdd_context_t *)pAdapter->pHddCtx) +#define WLAN_HDD_GET_HAL_CTX(pAdapter) (((hdd_context_t *)(pAdapter->pHddCtx))->hHal) +#define WLAN_HDD_GET_HOSTAP_STATE_PTR(pAdapter) (&(pAdapter)->sessionCtx.ap.HostapdState) +#define WLAN_HDD_GET_CFG_STATE_PTR(pAdapter) (&(pAdapter)->cfg80211State) +#define WLAN_HDD_GET_SAP_CTX_PTR(pAdapter) (pAdapter->sessionCtx.ap.sapContext) +#ifdef FEATURE_WLAN_TDLS +#define WLAN_HDD_IS_TDLS_SUPPORTED_ADAPTER(pAdapter) \ + (((QDF_STA_MODE != pAdapter->device_mode) && \ + (QDF_P2P_CLIENT_MODE != pAdapter->device_mode)) ? 0 : 1) +#define WLAN_HDD_GET_TDLS_CTX_PTR(pAdapter) \ + ((WLAN_HDD_IS_TDLS_SUPPORTED_ADAPTER(pAdapter)) ? \ + (tdlsCtx_t *)(pAdapter)->sessionCtx.station.pHddTdlsCtx : NULL) +#endif + +#ifdef WLAN_FEATURE_NAN_DATAPATH +#define WLAN_HDD_GET_NDP_CTX_PTR(adapter) \ + (&(adapter)->sessionCtx.station.ndp_ctx) +#define WLAN_HDD_IS_NDP_ENABLED(hdd_ctx) ((hdd_ctx)->nan_datapath_enabled) +#else +/* WLAN_HDD_GET_NDP_CTX_PTR and WLAN_HDD_GET_NDP_WEXT_STATE_PTR are not defined + * intentionally so that all references to these must be within NDP code. + * non-NDP code can call WLAN_HDD_IS_NDP_ENABLED(), and when it is enabled, + * invoke NDP code to do all work. + */ +#define WLAN_HDD_IS_NDP_ENABLED(hdd_ctx) (false) +#endif + +/* Set mac address locally administered bit */ +#define WLAN_HDD_RESET_LOCALLY_ADMINISTERED_BIT(macaddr) (macaddr[0] &= 0xFD) + +#define HDD_DEFAULT_MCC_P2P_QUOTA 70 +#define HDD_RESET_MCC_P2P_QUOTA 50 + +typedef struct hdd_adapter_list_node { + qdf_list_node_t node; /* MUST be first element */ + hdd_adapter_t *pAdapter; +} hdd_adapter_list_node_t; + +typedef struct hdd_priv_data_s { + uint8_t *buf; + int used_len; + int total_len; +} hdd_priv_data_t; + +#define MAX_MOD_LOGLEVEL 10 +typedef struct { + uint8_t enable; + uint8_t dl_type; + uint8_t dl_report; + uint8_t dl_loglevel; + uint8_t index; + uint32_t dl_mod_loglevel[MAX_MOD_LOGLEVEL]; + +} fw_log_info; + +/** + * enum antenna_mode - number of TX/RX chains + * @HDD_ANTENNA_MODE_INVALID: Invalid mode place holder + * @HDD_ANTENNA_MODE_1X1: Number of TX/RX chains equals 1 + * @HDD_ANTENNA_MODE_2X2: Number of TX/RX chains equals 2 + * @HDD_ANTENNA_MODE_MAX: Place holder for max mode + */ +enum antenna_mode { + HDD_ANTENNA_MODE_INVALID, + HDD_ANTENNA_MODE_1X1, + HDD_ANTENNA_MODE_2X2, + HDD_ANTENNA_MODE_MAX +}; + +/** + * enum smps_mode - SM power save mode + * @HDD_SMPS_MODE_STATIC: Static power save + * @HDD_SMPS_MODE_DYNAMIC: Dynamic power save + * @HDD_SMPS_MODE_RESERVED: Reserved + * @HDD_SMPS_MODE_DISABLED: Disable power save + * @HDD_SMPS_MODE_MAX: Place holder for max mode + */ +enum smps_mode { + HDD_SMPS_MODE_STATIC, + HDD_SMPS_MODE_DYNAMIC, + HDD_SMPS_MODE_RESERVED, + HDD_SMPS_MODE_DISABLED, + HDD_SMPS_MODE_MAX +}; + +#ifdef WLAN_FEATURE_OFFLOAD_PACKETS +/** + * struct hdd_offloaded_packets - request id to pattern id mapping + * @request_id: request id + * @pattern_id: pattern id + * + */ +struct hdd_offloaded_packets { + uint32_t request_id; + uint8_t pattern_id; +}; + +/** + * struct hdd_offloaded_packets_ctx - offloaded packets context + * @op_table: request id to pattern id table + * @op_lock: mutex lock + */ +struct hdd_offloaded_packets_ctx { + struct hdd_offloaded_packets op_table[MAXNUM_PERIODIC_TX_PTRNS]; + struct mutex op_lock; +}; +#endif + +/** + * struct hdd_bpf_context - hdd Context for bpf + * @magic: magic number + * @completion: Completion variable for BPF Get Capability + * @capability_response: capabilities response received from fw + */ +struct hdd_bpf_context { + unsigned int magic; + struct completion completion; + struct sir_bpf_get_offload capability_response; +}; + +/** + * enum driver_status: Driver Modules status + * @DRIVER_MODULES_UNINITIALIZED: Driver CDS modules uninitialized + * @DRIVER_MODULES_OPENED: Driver CDS modules opened + * @DRIVER_MODULES_ENABLED: Driver CDS modules opened + * @DRIVER_MODULES_CLOSED: Driver CDS modules closed + */ +enum driver_modules_status { + DRIVER_MODULES_UNINITIALIZED, + DRIVER_MODULES_OPENED, + DRIVER_MODULES_ENABLED, + DRIVER_MODULES_CLOSED +}; + +/** + * struct acs_dfs_policy - Define ACS policies + * @acs_dfs_mode: Dfs mode enabled/disabled. + * @acs_channel: pre defined channel to avoid ACS. + */ +struct acs_dfs_policy { + enum dfs_mode acs_dfs_mode; + uint8_t acs_channel; +}; + +/** + * enum suspend_fail_reason: Reasons a WLAN suspend might fail + * SUSPEND_FAIL_IPA: IPA in progress + * SUSPEND_FAIL_RADAR: radar scan in progress + * SUSPEND_FAIL_ROAM: roaming in progress + * SUSPEND_FAIL_SCAN: scan in progress + * SUSPEND_FAIL_INITIAL_WAKEUP: received initial wakeup from firmware + * SUSPEND_FAIL_MAX_COUNT: the number of wakeup reasons, always at the end + */ +enum suspend_fail_reason { + SUSPEND_FAIL_IPA, + SUSPEND_FAIL_RADAR, + SUSPEND_FAIL_ROAM, + SUSPEND_FAIL_SCAN, + SUSPEND_FAIL_INITIAL_WAKEUP, + SUSPEND_FAIL_MAX_COUNT +}; + +/** + * suspend_resume_stats - Collection of counters for suspend/resume events + * @suspends: number of suspends completed + * @resumes: number of resumes completed + * @suspend_fail: counters for failed suspend reasons + */ +struct suspend_resume_stats { + uint32_t suspends; + uint32_t resumes; + uint32_t suspend_fail[SUSPEND_FAIL_MAX_COUNT]; +}; + +/** + * struct hdd_nud_stats_context - hdd NUD stats context + * @response_event: NUD stats request wait event + */ +struct hdd_nud_stats_context { + struct completion response_event; +}; + +/** Adapter structure definition */ +struct hdd_context_s { + /** Global CDS context */ + v_CONTEXT_t pcds_context; + + /** HAL handle...*/ + tHalHandle hHal; + + struct wiphy *wiphy; + /* TODO Remove this from here. */ + + qdf_spinlock_t hdd_adapter_lock; + qdf_list_t hddAdapters; /* List of adapters */ + + /* One per STA: 1 for BCMC_STA_ID, 1 for each SAP_SELF_STA_ID, 1 for WDS_STAID */ + hdd_adapter_t *sta_to_adapter[WLAN_MAX_STA_COUNT + QDF_MAX_NO_OF_SAP_MODE + 2]; /* One per sta. For quick reference. */ + + /** Pointer for firmware image data */ + const struct firmware *fw; + + /** Pointer for configuration data */ + const struct firmware *cfg; + + /** Pointer to the parent device */ + struct device *parent_dev; + + /** Config values read from qcom_cfg.ini file */ + struct hdd_config *config; + + struct wlan_hdd_ftm_status ftm; + + /* Completion variable to indicate Mc Thread Suspended */ + struct completion mc_sus_event_var; + + bool isMcThreadSuspended; + +#ifdef QCA_CONFIG_SMP + bool is_ol_rx_thread_suspended; +#endif + + bool hdd_wlan_suspended; + bool suspended; + + /* Lock to avoid race condition during start/stop bss */ + struct mutex sap_lock; + +#ifdef FEATURE_OEM_DATA_SUPPORT + /* OEM App registered or not */ + bool oem_app_registered; + + /* OEM App Process ID */ + int32_t oem_pid; +#endif + + /** Concurrency Parameters*/ + uint32_t concurrency_mode; + + uint8_t no_of_open_sessions[QDF_MAX_NO_OF_MODE]; + uint8_t no_of_active_sessions[QDF_MAX_NO_OF_MODE]; + + /** P2P Device MAC Address for the adapter */ + struct qdf_mac_addr p2pDeviceAddress; + + qdf_wake_lock_t rx_wake_lock; + qdf_wake_lock_t sap_wake_lock; + +#ifdef FEATURE_WLAN_TDLS + eTDLSSupportMode tdls_mode; + eTDLSSupportMode tdls_mode_last; + tdlsConnInfo_t tdlsConnInfo[HDD_MAX_NUM_TDLS_STA]; + /* maximum TDLS station number allowed upon runtime condition */ + uint16_t max_num_tdls_sta; + /* TDLS peer connected count */ + uint16_t connected_peer_count; + tdls_scan_context_t tdls_scan_ctxt; + /* Lock to avoid race condition during TDLS operations */ + qdf_spinlock_t tdls_ct_spinlock; + /*linear mac address table for counting the packets*/ + struct tdls_ct_mac_table ct_peer_mac_table[TDLS_CT_MAC_MAX_TABLE_SIZE]; + /*number of valid mac entry in @ct_peer_mac_table*/ + uint8_t valid_mac_entries; + struct mutex tdls_lock; + uint8_t tdls_off_channel; + uint16_t tdls_channel_offset; + int32_t tdls_fw_off_chan_mode; + bool enable_tdls_connection_tracker; + uint8_t tdls_external_peer_count; + bool tdls_nss_switch_in_progress; + bool tdls_nss_teardown_complete; + enum tdls_nss_transition_type tdls_nss_transition_mode; + int32_t tdls_teardown_peers_cnt; + struct tdls_set_state_info set_state_info; +#endif + + void *hdd_ipa; + + /* Use below lock to protect access to isSchedScanUpdatePending + * since it will be accessed in two different contexts. + */ + qdf_spinlock_t sched_scan_lock; + + /* Flag keeps track of wiphy suspend/resume */ + bool isWiphySuspended; + + /* Indicates about pending sched_scan results */ + bool isSchedScanUpdatePending; + +#ifdef MSM_PLATFORM + /* DDR bus bandwidth compute timer + */ + qdf_timer_t bus_bw_timer; + bool bus_bw_timer_running; + qdf_spinlock_t bus_bw_timer_lock; + struct work_struct bus_bw_work; + int cur_vote_level; + spinlock_t bus_bw_lock; + int cur_rx_level; + uint64_t prev_rx; + int cur_tx_level; + uint64_t prev_tx; +#endif + + struct completion ready_to_suspend; + /* defining the solution type */ + uint32_t target_type; + + /* defining the firmware version */ + uint32_t target_fw_version; + uint32_t target_fw_vers_ext; + qdf_atomic_t dfs_radar_found; + + /* defining the chip/rom version */ + uint32_t target_hw_version; + /* defining the chip/rom revision */ + uint32_t target_hw_revision; + /* chip/rom name */ + const char *target_hw_name; + struct regulatory reg; +#ifdef FEATURE_WLAN_CH_AVOID + uint16_t unsafe_channel_count; + uint16_t unsafe_channel_list[NUM_CHANNELS]; +#endif /* FEATURE_WLAN_CH_AVOID */ + + uint8_t max_intf_count; + uint8_t current_intf_count; +#ifdef WLAN_FEATURE_LPSS + uint8_t lpss_support; +#endif + uint8_t ap_arpns_support; + tSirScanType ioctl_scan_mode; + +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH + qdf_work_t sta_ap_intf_check_work; +#endif + + struct work_struct sap_start_work; + bool is_sap_restart_required; + bool is_sta_connection_pending; + qdf_spinlock_t sap_update_info_lock; + qdf_spinlock_t sta_update_info_lock; + + uint8_t dev_dfs_cac_status; + + bool btCoexModeSet; +#ifdef FEATURE_GREEN_AP + struct hdd_green_ap_ctx *green_ap_ctx; +#endif + fw_log_info fw_log_settings; +#ifdef FEATURE_WLAN_AP_AP_ACS_OPTIMIZE + qdf_mc_timer_t skip_acs_scan_timer; + uint8_t skip_acs_scan_status; + uint8_t *last_acs_channel_list; + uint8_t num_of_channels; + qdf_spinlock_t acs_skip_lock; +#endif + + qdf_wake_lock_t sap_dfs_wakelock; + atomic_t sap_dfs_ref_cnt; + +#ifdef WLAN_FEATURE_EXTWOW_SUPPORT + bool is_extwow_app_type1_param_set; + bool is_extwow_app_type2_param_set; + bool ext_wow_should_suspend; + struct completion ready_to_extwow; +#endif + + /* Time since boot up to extscan start (in micro seconds) */ + uint64_t ext_scan_start_since_boot; + unsigned long g_event_flags; + /* RoC request queue and work */ + struct delayed_work roc_req_work; + qdf_spinlock_t hdd_roc_req_q_lock; + qdf_list_t hdd_roc_req_q; + qdf_spinlock_t hdd_scan_req_q_lock; + qdf_list_t hdd_scan_req_q; + uint8_t miracast_value; + +#ifdef WLAN_NS_OFFLOAD + /* IPv6 notifier callback for handling NS offload on change in IP */ + struct notifier_block ipv6_notifier; +#endif + bool ns_offload_enable; + /* IPv4 notifier callback for handling ARP offload on change in IP */ + struct notifier_block ipv4_notifier; + + /* number of rf chains supported by target */ + uint32_t num_rf_chains; + /* Is htTxSTBC supported by target */ + uint8_t ht_tx_stbc_supported; +#ifdef WLAN_FEATURE_OFFLOAD_PACKETS + struct hdd_offloaded_packets_ctx op_ctx; +#endif + bool mcc_mode; +#ifdef WLAN_FEATURE_MEMDUMP + uint8_t *fw_dump_loc; + uint32_t dump_loc_paddr; + qdf_mc_timer_t memdump_cleanup_timer; + struct mutex memdump_lock; + bool memdump_in_progress; + bool memdump_init_done; +#endif /* WLAN_FEATURE_MEMDUMP */ + uint16_t driver_dump_size; + uint8_t *driver_dump_mem; + + bool connection_in_progress; + qdf_spinlock_t connection_status_lock; + + uint16_t hdd_txrx_hist_idx; + struct hdd_tx_rx_histogram *hdd_txrx_hist; + + /* + * place to store FTM capab of target. This allows changing of FTM capab + * at runtime and intersecting it with target capab before updating. + */ + uint32_t fine_time_meas_cap_target; + uint32_t rx_high_ind_cnt; + /* completion variable to indicate set antenna mode complete*/ + struct completion set_antenna_mode_cmpl; + /* Current number of TX X RX chains being used */ + enum antenna_mode current_antenna_mode; + bool bpf_enabled; + + /* the radio index assigned by cnss_logger */ + int radio_index; + qdf_work_t sap_pre_cac_work; + bool hbw_requested; + uint32_t last_nil_scan_bug_report_timestamp; +#ifdef WLAN_FEATURE_NAN_DATAPATH + bool nan_datapath_enabled; +#endif + /* Present state of driver cds modules */ + enum driver_modules_status driver_status; + /* MC timer interface change */ + qdf_mc_timer_t iface_change_timer; + /* Interface change lock */ + struct mutex iface_change_lock; + bool rps; + bool enableRxThread; + bool napi_enable; + bool stop_modules_in_progress; + bool start_modules_in_progress; + bool update_mac_addr_to_fw; + struct acs_dfs_policy acs_policy; + uint16_t wmi_max_len; + struct suspend_resume_stats suspend_resume_stats; + struct hdd_runtime_pm_context runtime_context; + bool roaming_in_progress; + /* bit map to set/reset TDLS by different sources */ + unsigned long tdls_source_bitmap; + /* tdls source timer to enable/disable TDLS on p2p listen */ + qdf_mc_timer_t tdls_source_timer; + qdf_atomic_t disable_lro_in_concurrency; + qdf_atomic_t disable_lro_in_low_tput; + qdf_atomic_t vendor_disable_lro_flag; + bool fw_mem_dump_enabled; + uint8_t last_scan_reject_session_id; + scan_reject_states last_scan_reject_reason; + unsigned long last_scan_reject_timestamp; + uint8_t beacon_probe_rsp_cnt_per_scan; + bool rcpi_enabled; + bool imps_enabled; + int user_configured_pkt_filter_rules; + struct hdd_nud_stats_context nud_stats_context; + uint32_t track_arp_ip; +}; + +/*--------------------------------------------------------------------------- + Function declarations and documentation + -------------------------------------------------------------------------*/ +int hdd_validate_channel_and_bandwidth(hdd_adapter_t *adapter, + uint32_t chan_number, + enum phy_ch_width chan_bw); +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH +void wlan_hdd_check_sta_ap_concurrent_ch_intf(void *sta_pAdapter); +#endif + +const char *hdd_device_mode_to_string(uint8_t device_mode); + +QDF_STATUS hdd_get_front_adapter(hdd_context_t *pHddCtx, + hdd_adapter_list_node_t **ppAdapterNode); + +QDF_STATUS hdd_get_next_adapter(hdd_context_t *pHddCtx, + hdd_adapter_list_node_t *pAdapterNode, + hdd_adapter_list_node_t **pNextAdapterNode); + +QDF_STATUS hdd_remove_adapter(hdd_context_t *pHddCtx, + hdd_adapter_list_node_t *pAdapterNode); + +QDF_STATUS hdd_remove_front_adapter(hdd_context_t *pHddCtx, + hdd_adapter_list_node_t **ppAdapterNode); + +QDF_STATUS hdd_add_adapter_back(hdd_context_t *pHddCtx, + hdd_adapter_list_node_t *pAdapterNode); + +QDF_STATUS hdd_add_adapter_front(hdd_context_t *pHddCtx, + hdd_adapter_list_node_t *pAdapterNode); + +hdd_adapter_t *hdd_open_adapter(hdd_context_t *pHddCtx, uint8_t session_type, + const char *name, tSirMacAddr macAddr, + unsigned char name_assign_type, + bool rtnl_held); +QDF_STATUS hdd_close_adapter(hdd_context_t *pHddCtx, hdd_adapter_t *pAdapter, + bool rtnl_held); +QDF_STATUS hdd_close_all_adapters(hdd_context_t *pHddCtx, bool rtnl_held); +QDF_STATUS hdd_stop_all_adapters(hdd_context_t *pHddCtx); +void hdd_deinit_all_adapters(hdd_context_t *hdd_ctx, bool rtnl_held); +QDF_STATUS hdd_reset_all_adapters(hdd_context_t *pHddCtx); +QDF_STATUS hdd_start_all_adapters(hdd_context_t *pHddCtx); +hdd_adapter_t *hdd_get_adapter_by_vdev(hdd_context_t *pHddCtx, + uint32_t vdev_id); +hdd_adapter_t *hdd_get_adapter_by_macaddr(hdd_context_t *pHddCtx, + tSirMacAddr macAddr); +QDF_STATUS hdd_init_station_mode(hdd_adapter_t *pAdapter); +hdd_adapter_t *hdd_get_adapter(hdd_context_t *pHddCtx, + enum tQDF_ADAPTER_MODE mode); +void hdd_deinit_adapter(hdd_context_t *pHddCtx, hdd_adapter_t *pAdapter, + bool rtnl_held); +QDF_STATUS hdd_stop_adapter(hdd_context_t *pHddCtx, hdd_adapter_t *pAdapter, + const bool bCloseSession); +void hdd_set_station_ops(struct net_device *pWlanDev); +uint8_t *wlan_hdd_get_intf_addr(hdd_context_t *pHddCtx); +void wlan_hdd_release_intf_addr(hdd_context_t *pHddCtx, uint8_t *releaseAddr); +uint8_t hdd_get_operating_channel(hdd_context_t *pHddCtx, + enum tQDF_ADAPTER_MODE mode); + +void hdd_set_conparam(uint32_t con_param); +enum tQDF_GLOBAL_CON_MODE hdd_get_conparam(void); + +void hdd_abort_mac_scan(hdd_context_t *pHddCtx, uint8_t sessionId, + uint32_t scan_id, eCsrAbortReason reason); +void hdd_cleanup_actionframe(hdd_context_t *pHddCtx, hdd_adapter_t *pAdapter); + +void crda_regulatory_entry_default(uint8_t *countryCode, int domain_id); +void wlan_hdd_reset_prob_rspies(hdd_adapter_t *pHostapdAdapter); +void hdd_prevent_suspend(uint32_t reason); +void hdd_allow_suspend(uint32_t reason); +void hdd_prevent_suspend_timeout(uint32_t timeout, uint32_t reason); + +void wlan_hdd_cfg80211_update_wiphy_caps(struct wiphy *wiphy); +QDF_STATUS hdd_set_ibss_power_save_params(hdd_adapter_t *pAdapter); +QDF_STATUS wlan_hdd_restart_driver(hdd_context_t *pHddCtx); +void hdd_exchange_version_and_caps(hdd_context_t *pHddCtx); +int wlan_hdd_validate_context(hdd_context_t *pHddCtx); +bool hdd_is_valid_mac_address(const uint8_t *pMacAddr); +QDF_STATUS hdd_issta_p2p_clientconnected(hdd_context_t *pHddCtx); +bool wlan_hdd_modules_are_enabled(hdd_context_t *hdd_ctx); + +struct qdf_mac_addr * +hdd_wlan_get_ibss_mac_addr_from_staid(hdd_adapter_t *pAdapter, + uint8_t staIdx); +void hdd_checkandupdate_phymode(hdd_context_t *pHddCtx); +#ifdef MSM_PLATFORM +/** + * hdd_bus_bw_compute_timer_start() - start the bandwidth timer + * @hdd_ctx: the global hdd context + * + * Return: None + */ +void hdd_bus_bw_compute_timer_start(hdd_context_t *hdd_ctx); + +/** + * hdd_bus_bw_compute_timer_try_start() - try to start the bandwidth timer + * @hdd_ctx: the global hdd context + * + * This function ensures there is at least one adapter in the associated state + * before starting the bandwidth timer. + * + * Return: None + */ +void hdd_bus_bw_compute_timer_try_start(hdd_context_t *hdd_ctx); + +/** + * hdd_bus_bw_compute_timer_stop() - stop the bandwidth timer + * @hdd_ctx: the global hdd context + * + * Return: None + */ +void hdd_bus_bw_compute_timer_stop(hdd_context_t *hdd_ctx); + +/** + * hdd_bus_bw_compute_timer_try_stop() - try to stop the bandwidth timer + * @hdd_ctx: the global hdd context + * + * This function ensures there are no adapters in the associated state before + * stopping the bandwidth timer. + * + * Return: None + */ +void hdd_bus_bw_compute_timer_try_stop(hdd_context_t *hdd_ctx); + +/** + * hdd_bus_bandwidth_init() - Initialize bus bandwidth data structures. + * hdd_ctx: HDD context + * + * Initialize bus bandwidth related data structures like spinlock and timer. + * + * Return: None. + */ +int hdd_bus_bandwidth_init(hdd_context_t *hdd_ctx); + +/** + * hdd_bus_bandwidth_destroy() - Destroy bus bandwidth data structures. + * hdd_ctx: HDD context + * + * Destroy bus bandwidth related data structures like timer. + * + * Return: None. + */ +void hdd_bus_bandwidth_destroy(hdd_context_t *hdd_ctx); +#else + +void hdd_bus_bw_compute_timer_start(hdd_context_t *hdd_ctx) +{ + return; +} + +void hdd_bus_bw_compute_timer_try_start(hdd_context_t *hdd_ctx) +{ + return; +} + +void hdd_bus_bw_compute_timer_stop(hdd_context_t *hdd_ctx) +{ + return; +} + +void hdd_bus_bw_compute_timer_try_stop(hdd_context_t *hdd_ctx) +{ + return; +} + +static inline void hdd_stop_bus_bw_computer_timer(hdd_adapter_t *pAdapter) +{ + return; +} + +int hdd_bus_bandwidth_init(hdd_context_t *hdd_ctx) +{ + return 0; +} + +void hdd_bus_bandwidth_destroy(hdd_context_t *hdd_ctx) +{ + return; +} +#endif + +int hdd_init(void); +void hdd_deinit(void); + +int hdd_wlan_startup(struct device *dev); +void __hdd_wlan_exit(void); +int hdd_wlan_notify_modem_power_state(int state); +#ifdef QCA_HT_2040_COEX +int hdd_wlan_set_ht2040_mode(hdd_adapter_t *pAdapter, uint16_t staId, + struct qdf_mac_addr macAddrSTA, int width); +#endif + +void wlan_hdd_send_svc_nlink_msg(int radio, int type, void *data, int len); +#ifdef FEATURE_WLAN_AUTO_SHUTDOWN +void wlan_hdd_auto_shutdown_enable(hdd_context_t *hdd_ctx, bool enable); +#endif + +hdd_adapter_t *hdd_get_con_sap_adapter(hdd_adapter_t *this_sap_adapter, + bool check_start_bss); + +bool hdd_is_5g_supported(hdd_context_t *pHddCtx); + +int wlan_hdd_scan_abort(hdd_adapter_t *pAdapter); + +void hdd_get_fw_version(hdd_context_t *hdd_ctx, + uint32_t *major_spid, uint32_t *minor_spid, + uint32_t *siid, uint32_t *crmid); + +#ifdef WLAN_FEATURE_MEMDUMP +/** + * hdd_is_memdump_supported() - to check if memdump feature support + * + * This function is used to check if memdump feature is supported in + * the host driver + * + * Return: true if supported and false otherwise + */ +static inline bool hdd_is_memdump_supported(void) +{ + return true; +} +#else +static inline bool hdd_is_memdump_supported(void) +{ + return false; +} +#endif /* WLAN_FEATURE_MEMDUMP */ + +void hdd_update_macaddr(struct hdd_config *config, + struct qdf_mac_addr hw_macaddr); +void wlan_hdd_disable_roaming(hdd_adapter_t *pAdapter); +void wlan_hdd_enable_roaming(hdd_adapter_t *pAdapter); + +QDF_STATUS hdd_post_cds_enable_config(hdd_context_t *pHddCtx); + +QDF_STATUS hdd_abort_mac_scan_all_adapters(hdd_context_t *hdd_ctx); + +QDF_STATUS wlan_hdd_check_custom_con_channel_rules(hdd_adapter_t *sta_adapter, + hdd_adapter_t *ap_adapter, + tCsrRoamProfile *roam_profile, + tScanResultHandle *scan_cache, + bool *concurrent_chnl_same); +void wlan_hdd_stop_sap(hdd_adapter_t *ap_adapter); +void wlan_hdd_start_sap(hdd_adapter_t *ap_adapter, bool reinit); + +void wlan_hdd_soc_set_antenna_mode_cb(enum set_antenna_mode_status status); + +#ifdef QCA_CONFIG_SMP +int wlan_hdd_get_cpu(void); +#else +static inline int wlan_hdd_get_cpu(void) +{ + return 0; +} +#endif + +void wlan_hdd_sap_pre_cac_failure(void *data); +void hdd_clean_up_pre_cac_interface(hdd_context_t *hdd_ctx); + +void wlan_hdd_txrx_pause_cb(uint8_t vdev_id, + enum netif_action_type action, enum netif_reason_type reason); + +int hdd_wlan_dump_stats(hdd_adapter_t *adapter, int value); +void wlan_hdd_deinit_tx_rx_histogram(hdd_context_t *hdd_ctx); +void wlan_hdd_display_tx_rx_histogram(hdd_context_t *pHddCtx); +void wlan_hdd_clear_tx_rx_histogram(hdd_context_t *pHddCtx); +void wlan_hdd_display_netif_queue_history(hdd_context_t *hdd_ctx); +void wlan_hdd_clear_netif_queue_history(hdd_context_t *hdd_ctx); +const char *hdd_get_fwpath(void); +void hdd_indicate_mgmt_frame(tSirSmeMgmtFrameInd *frame_ind); +hdd_adapter_t *hdd_get_adapter_by_sme_session_id(hdd_context_t *hdd_ctx, + uint32_t sme_session_id); +enum phy_ch_width hdd_map_nl_chan_width(enum nl80211_chan_width ch_width); +uint8_t wlan_hdd_find_opclass(tHalHandle hal, uint8_t channel, + uint8_t bw_offset); +int hdd_update_config(hdd_context_t *hdd_ctx); + +QDF_STATUS hdd_chan_change_notify(hdd_adapter_t *adapter, + struct net_device *dev, + struct hdd_chan_change_params chan_change); +int wlan_hdd_set_channel(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_chan_def *chandef, + enum nl80211_channel_type channel_type); +int wlan_hdd_cfg80211_start_bss(hdd_adapter_t *pHostapdAdapter, + struct cfg80211_beacon_data *params, + const u8 *ssid, size_t ssid_len, + enum nl80211_hidden_ssid hidden_ssid, + bool check_for_concurrency, + bool update_beacon); +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH +QDF_STATUS hdd_register_for_sap_restart_with_channel_switch(void); +#else +static inline QDF_STATUS hdd_register_for_sap_restart_with_channel_switch(void) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +#if !defined(REMOVE_PKT_LOG) +int hdd_process_pktlog_command(hdd_context_t *hdd_ctx, uint32_t set_value, + int set_value2); +int hdd_pktlog_enable_disable(hdd_context_t *hdd_ctx, bool enable, + uint8_t user_triggered, int size); + +#else +static inline int hdd_pktlog_enable_disable(hdd_context_t *hdd_ctx, bool enable, + uint8_t user_triggered, int size) +{ + return 0; +} +static inline int hdd_process_pktlog_command(hdd_context_t *hdd_ctx, + uint32_t set_value, int set_value2) +{ + return 0; +} +#endif /* REMOVE_PKT_LOG */ + +#ifdef FEATURE_TSO +/** + * hdd_set_tso_flags() - enable TSO flags in the network device + * @hdd_ctx: HDD context + * @wlan_dev: network device structure + * + * This function enables the TSO related feature flags in the + * given network device. + * + * Return: none + */ +static inline void hdd_set_tso_flags(hdd_context_t *hdd_ctx, + struct net_device *wlan_dev) +{ + if (hdd_ctx->config->tso_enable && + hdd_ctx->config->enable_ip_tcp_udp_checksum_offload) { + /* + * We want to enable TSO only if IP/UDP/TCP TX checksum flag is + * enabled. + */ + hdd_info("TSO Enabled"); + wlan_dev->features |= + NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | + NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_SG; + } +} +#else +static inline void hdd_set_tso_flags(hdd_context_t *hdd_ctx, + struct net_device *wlan_dev){} +#endif /* FEATURE_TSO */ + +#if defined(FEATURE_WLAN_MCC_TO_SCC_SWITCH) || \ + defined(FEATURE_WLAN_STA_AP_MODE_DFS_DISABLE) +void wlan_hdd_restart_sap(hdd_adapter_t *ap_adapter); +#else +static inline void wlan_hdd_restart_sap(hdd_adapter_t *ap_adapter) +{ +} +#endif + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +static inline bool roaming_offload_enabled(hdd_context_t *hdd_ctx) +{ + return hdd_ctx->config->isRoamOffloadEnabled; +} +#else +static inline bool roaming_offload_enabled(hdd_context_t *hdd_ctx) +{ + return false; +} +#endif + +void hdd_get_ibss_peer_info_cb(void *pUserData, + tSirPeerInfoRspParams *pPeerInfo); + +#ifdef CONFIG_CNSS_LOGGER +/** + * wlan_hdd_nl_init() - wrapper function to CNSS_LOGGER case + * @hdd_ctx: the hdd context pointer + * + * The nl_srv_init() will call to cnss_logger_device_register() and + * expect to get a radio_index from cnss_logger module and assign to + * hdd_ctx->radio_index, then to maintain the consistency to original + * design, adding the radio_index check here, then return the error + * code if radio_index is not assigned correctly, which means the nl_init + * from cnss_logger is failed. + * + * Return: 0 if successfully, otherwise error code + */ +static inline int wlan_hdd_nl_init(hdd_context_t *hdd_ctx) +{ + hdd_ctx->radio_index = nl_srv_init(hdd_ctx->wiphy); + + /* radio_index is assigned from 0, so only >=0 will be valid index */ + if (hdd_ctx->radio_index >= 0) + return 0; + else + return -EINVAL; +} +#else +/** + * wlan_hdd_nl_init() - wrapper function to non CNSS_LOGGER case + * @hdd_ctx: the hdd context pointer + * + * In case of non CNSS_LOGGER case, the nl_srv_init() will initialize + * the netlink socket and return the success or not. + * + * Return: the return value from nl_srv_init() + */ +static inline int wlan_hdd_nl_init(hdd_context_t *hdd_ctx) +{ + return nl_srv_init(hdd_ctx->wiphy); +} +#endif +QDF_STATUS hdd_sme_close_session_callback(void *pContext); + +int hdd_reassoc(hdd_adapter_t *adapter, const uint8_t *bssid, + uint8_t channel, const handoff_src src); +void hdd_svc_fw_shutdown_ind(struct device *dev); +int hdd_register_cb(hdd_context_t *hdd_ctx); +void hdd_deregister_cb(hdd_context_t *hdd_ctx); +int hdd_start_station_adapter(hdd_adapter_t *adapter); +int hdd_start_ap_adapter(hdd_adapter_t *adapter); +int hdd_configure_cds(hdd_context_t *hdd_ctx, hdd_adapter_t *adapter); +int hdd_start_ftm_adapter(hdd_adapter_t *adapter); +int hdd_set_fw_params(hdd_adapter_t *adapter); +int hdd_wlan_start_modules(hdd_context_t *hdd_ctx, hdd_adapter_t *adapter, + bool reinit); +int hdd_wlan_stop_modules(hdd_context_t *hdd_ctx, bool ftm_mode); +int hdd_start_adapter(hdd_adapter_t *adapter); + +/** + * hdd_get_bss_entry() - Get the bss entry matching the chan, bssid and ssid + * @wiphy: wiphy + * @channel: channel of the BSS to find + * @bssid: bssid of the BSS to find + * @ssid: ssid of the BSS to find + * @ssid_len: ssid len of of the BSS to find + * + * The API is a wrapper to get bss from kernel matching the chan, + * bssid and ssid + * + * Return: bss structure if found else NULL + */ +struct cfg80211_bss *hdd_cfg80211_get_bss(struct wiphy *wiphy, + struct ieee80211_channel *channel, + const u8 *bssid, + const u8 *ssid, size_t ssid_len); + +void hdd_connect_result(struct net_device *dev, const u8 *bssid, + tCsrRoamInfo *roam_info, const u8 *req_ie, + size_t req_ie_len, const u8 *resp_ie, + size_t resp_ie_len, u16 status, gfp_t gfp, + bool connect_timeout, + tSirResultCodes timeout_reason); + +#ifdef WLAN_FEATURE_FASTPATH +void hdd_enable_fastpath(struct hdd_config *hdd_cfg, + void *context); +#else +static inline void hdd_enable_fastpath(struct hdd_config *hdd_cfg, + void *context) +{ +} +#endif +void hdd_wlan_update_target_info(hdd_context_t *hdd_ctx, void *context); +enum sap_acs_dfs_mode wlan_hdd_get_dfs_mode(enum dfs_mode mode); +void hdd_ch_avoid_cb(void *hdd_context, void *indi_param); +void hdd_unsafe_channel_restart_sap(hdd_context_t *hdd_ctx); +int hdd_enable_disable_ca_event(hdd_context_t *hddctx, + uint8_t set_value); +void wlan_hdd_undo_acs(hdd_adapter_t *adapter); + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 7, 0)) +static inline int +hdd_wlan_nla_put_u64(struct sk_buff *skb, int attrtype, u64 value) +{ + return nla_put_u64(skb, attrtype, value); +} +#else +static inline int +hdd_wlan_nla_put_u64(struct sk_buff *skb, int attrtype, u64 value) +{ + return nla_put_u64_64bit(skb, attrtype, value, NL80211_ATTR_PAD); +} +#endif + +static inline int wlan_hdd_validate_session_id(u8 session_id) +{ + if (session_id != HDD_SESSION_ID_INVALID) + return 0; + + return -EINVAL; +} + +bool hdd_is_roaming_in_progress(hdd_adapter_t *adapter); +void hdd_set_roaming_in_progress(bool value); +/** + * hdd_check_for_opened_interfaces()- Check for interface up + * @hdd_ctx: HDD context + * + * check if there are any wlan interfaces before starting the timer + * to close the modules + * + * Return: 0 if interface was opened else false + */ +bool hdd_check_for_opened_interfaces(hdd_context_t *hdd_ctx); +void wlan_hdd_start_sap(hdd_adapter_t *ap_adapter, bool reinit); +void hdd_set_rx_mode_rps(hdd_context_t *hdd_ctx, void *padapter, bool enable); + +/** + * hdd_init_nud_stats_ctx() - initialize NUD stats context + * @hdd_ctx: Pointer to hdd context + * + * Return: none + */ +static inline void hdd_init_nud_stats_ctx(hdd_context_t *hdd_ctx) +{ + init_completion(&hdd_ctx->nud_stats_context.response_event); + return; +} + +/** + * hdd_start_complete()- complete the start event + * @ret: return value for complete event. + * + * complete the startup event and set the return in + * global variable + * + * Return: void + */ + +void hdd_start_complete(int ret); + +/** + * hdd_unregister_notifiers()- unregister kernel notifiers + * @hdd_ctx: Hdd Context + * + * Unregister netdev notifiers like Netdevice,IPv4 and IPv6. + * + */ +void hdd_unregister_notifiers(hdd_context_t *hdd_ctx); + +/** + * hdd_chip_pwr_save_fail_detected_cb() - chip power save failure detected + * callback + * @hdd_ctx: HDD context + * @data: chip power save failure detected data + * + * This function reads the chip power save failure detected data and fill in + * the skb with NL attributes and send up the NL event. + * This callback execute in atomic context and must not invoke any + * blocking calls. + * + * Return: none + */ +void hdd_chip_pwr_save_fail_detected_cb(void *hdd_ctx, + struct chip_pwr_save_fail_detected_params + *data); + +/** + * hdd_get_rssi_snr_by_bssid() - gets the rssi and snr by bssid from scan cache + * @adapter: adapter handle + * @bssid: bssid to look for in scan cache + * @rssi: rssi value found + * @snr: snr value found + * + * Return: QDF_STATUS + */ +int hdd_get_rssi_snr_by_bssid(hdd_adapter_t *adapter, const uint8_t *bssid, + int8_t *rssi, int8_t *snr); + +#endif /* end #if !defined(WLAN_HDD_MAIN_H) */ diff --git a/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_memdump.h b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_memdump.h new file mode 100644 index 0000000000000000000000000000000000000000..5e670fe72785d6c0ebce99a1b24a024c9ee25c7b --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_memdump.h @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2015-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC : wlan_hdd_memdump.h + * + * WLAN Host Device Driver file for dumping firmware memory + * + */ + +#if !defined(WLAN_HDD_MEMDUMP_H) +#define WLAN_HDD_MEMDUMP_H + +#include "wlan_hdd_main.h" + +/* Assigned size of driver memory dump is 4096 bytes */ +#define DRIVER_MEM_DUMP_SIZE 4096 + + +#ifdef WLAN_FEATURE_MEMDUMP +/** + * enum qca_wlan_vendor_attr_memory_dump - values for memory dump attributes + * @QCA_WLAN_VENDOR_ATTR_MEMORY_DUMP_INVALID - Invalid + * @QCA_WLAN_VENDOR_ATTR_REQUEST_ID - Indicate request ID + * @QCA_WLAN_VENDOR_ATTR_MEMDUMP_SIZE - Indicate size of the memory dump + * @QCA_WLAN_VENDOR_ATTR_MEMORY_DUMP_AFTER_LAST - To keep track of the last enum + * @QCA_WLAN_VENDOR_ATTR_MEMORY_DUMP_MAX - max value possible for this type + * + * enum values are used for NL attributes for data used by + * QCA_NL80211_VENDOR_SUBCMD_WIFI_LOGGER_MEMORY_DUMP sub command. + */ +enum qca_wlan_vendor_attr_memory_dump { + QCA_WLAN_VENDOR_ATTR_MEMORY_DUMP_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_REQUEST_ID = 1, + QCA_WLAN_VENDOR_ATTR_MEMDUMP_SIZE = 2, + + QCA_WLAN_VENDOR_ATTR_MEMORY_DUMP_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_MEMORY_DUMP_MAX = + QCA_WLAN_VENDOR_ATTR_MEMORY_DUMP_AFTER_LAST - 1, +}; + +/* Size of fw memory dump is estimated to be 327680 bytes */ +#define FW_MEM_DUMP_SIZE 327680 +#define FW_DRAM_LOCATION 0x00400000 +#define FW_MEM_DUMP_REQ_ID 1 +#define FW_MEM_DUMP_NUM_SEG 1 +#define MEMDUMP_COMPLETION_TIME_MS 800 + +int memdump_init(void); +void memdump_deinit(void); +int wlan_hdd_cfg80211_get_fw_mem_dump(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len); +void wlan_hdd_cfg80211_fw_mem_dump_cb(void *ctx, struct fw_dump_rsp *dump_rsp); + +int hdd_driver_memdump_init(void); +void hdd_driver_memdump_deinit(void); + +#else +static inline int memdump_init(void) +{ + return -ENOTSUPP; +} + +static inline void memdump_deinit(void) +{ +} + +static inline int wlan_hdd_cfg80211_get_fw_mem_dump(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + return -ENOTSUPP; +} + + +static inline void wlan_hdd_cfg80211_fw_mem_dump_cb(void *ctx, + struct fw_dump_rsp + *dump_rsp) +{ +} + +static inline int hdd_driver_memdump_init(void) +{ + return -ENOTSUPP; +} + +static inline void hdd_driver_memdump_deinit(void) +{ +} + +#endif + +#endif /* if !defined(WLAN_HDD_MEMDUMP_H)*/ diff --git a/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_misc.h b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_misc.h new file mode 100644 index 0000000000000000000000000000000000000000..82e1b2b5d8fa21a36a09656261a391e9391c9447 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_misc.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2012-2014,2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef WLAN_HDD_MISC_H +#define WLAN_HDD_MISC_H +/* + * If MULTI_IF_NAME is defined, then prepend MULTI_IF_NAME to the filename + * to prevent name conflicts when loading multiple instances of the driver. + */ +#ifdef MULTI_IF_NAME +#define PREFIX MULTI_IF_NAME +#else +#define PREFIX "" +#endif + +#ifdef MSM_PLATFORM +#define WLAN_INI_FILE "wlan/qca_cld/" PREFIX "WCNSS_qcom_cfg.ini" +#define WLAN_MAC_FILE "wlan/qca_cld/" PREFIX "wlan_mac.bin" +#else +#define WLAN_INI_FILE "wlan/" PREFIX "qcom_cfg.ini" +#define WLAN_MAC_FILE "wlan/" PREFIX "wlan_mac.bin" +#endif /* MSM_PLATFORM */ + +#endif /* WLAN_HDD_MISC_H */ diff --git a/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_nan.h b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_nan.h new file mode 100644 index 0000000000000000000000000000000000000000..02947164e359d955dbd7fb7d6457e8ddfa73e425 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_nan.h @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2014-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef __WLAN_HDD_NAN_H +#define __WLAN_HDD_NAN_H + +/** + * DOC: wlan_hdd_nan.h + * + * WLAN Host Device Driver NAN API specification + */ + +struct hdd_context_s; + +#ifdef WLAN_FEATURE_NAN +struct wiphy; +struct wireless_dev; + +int wlan_hdd_cfg80211_nan_request(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len); + +bool wlan_hdd_nan_is_supported(void); +/** + * hdd_nan_populate_cds_config() - Populate NAN cds configuration + * @cds_cfg: CDS Configuration + * @hdd_ctx: Pointer to hdd context + * + * Return: none + */ +static inline void hdd_nan_populate_cds_config(struct cds_config_info *cds_cfg, + hdd_context_t *hdd_ctx) +{ + cds_cfg->is_nan_enabled = hdd_ctx->config->enable_nan_support; +} +void wlan_hdd_cfg80211_nan_callback(void *ctx, tSirNanEvent *msg); +#else +static inline bool wlan_hdd_nan_is_supported(void) +{ + return false; +} +static inline void hdd_nan_populate_cds_config(struct cds_config_info *cds_cfg, + hdd_context_t *hdd_ctx) +{ +} +static inline void wlan_hdd_cfg80211_nan_callback(void *ctx, + tSirNanEvent *msg) +{ +} +#endif /* WLAN_FEATURE_NAN */ +#endif /* __WLAN_HDD_NAN_H */ diff --git a/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_napi.h b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_napi.h new file mode 100644 index 0000000000000000000000000000000000000000..94c15c29e355613a9234da3d4b7921c7951bfe72 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_napi.h @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2015-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef __HDD_NAPI_H__ +#define __HDD_NAPI_H__ + +#ifdef FEATURE_NAPI +/** + * DOC: wlan_hdd_napi.h + * + * WLAN NAPI interface module headers + */ + +/* CLD headers */ +#include "hif_napi.h" + +/* Linux headers */ +#include /* net_device */ + +struct hdd_context_s; + +#define HDD_NAPI_ANY (-1) + +int hdd_napi_enabled(int id); +int hdd_napi_create(void); +int hdd_napi_destroy(int force); +int hdd_display_napi_stats(void); + +/* the following triggers napi_enable/disable as required */ +int hdd_napi_event(enum qca_napi_event event, void *data); + +int hdd_napi_poll(struct napi_struct *napi, int budget); + +struct qca_napi_data *hdd_napi_get_all(void); + +#ifdef HELIUMPLUS +int hdd_napi_apply_throughput_policy(struct hdd_context_s *hddctx, + uint64_t tx_packets, + uint64_t rx_packets); +int hdd_napi_serialize(int is_on); +#else /* FEATURE_NAPI and NOT HELIUM */ +static inline int hdd_napi_apply_throughput_policy(struct hdd_context_s *hddctx, + uint64_t tx_packets, + uint64_t rx_packets) +{ + return 0; +} +static inline int hdd_napi_serialize(int is_on) +{ + return -EINVAL; +}; +#endif /* HELIUMPLUS */ + +#else /* ! defined(FEATURE_NAPI) */ +#include "hif_napi.h" +/** + * Stub API + * + */ + +#define HDD_NAPI_ANY (-1) + +static inline int hdd_napi_enabled(int id) { return 0; } +static inline int hdd_napi_create(void) { return 0; } +static inline int hdd_napi_destroy(int force) { return 0; } +static inline int hdd_display_napi_stats(void) { return 0; } +static inline int hdd_napi_event(enum qca_napi_event event, void *data) +{ + return 0; +} +static inline struct qca_napi_data *hdd_napi_get_all(void) { return NULL; } +static inline int hdd_napi_apply_throughput_policy(void *hdd_ctx, + uint64_t tx_packets, uint64_t rx_packets) +{ + return 0; +} +static inline int hdd_napi_serialize(int is_on) +{ + return 0; +}; + +#endif /* FEATURE_NAPI */ + +#endif /* HDD_NAPI_H__ */ diff --git a/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_oemdata.h b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_oemdata.h new file mode 100644 index 0000000000000000000000000000000000000000..bc69f7d299fee3cb0f072d39ce8ab101dddf945f --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_oemdata.h @@ -0,0 +1,196 @@ +/* + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: wlan_hdd_oemdata.h + * + * Internal includes for the oem data + */ + +#ifndef __WLAN_HDD_OEM_DATA_H__ +#define __WLAN_HDD_OEM_DATA_H__ + +#ifdef FEATURE_OEM_DATA_SUPPORT + +#ifndef OEM_DATA_REQ_SIZE +#define OEM_DATA_REQ_SIZE 500 +#endif + +#ifndef OEM_DATA_RSP_SIZE +#define OEM_DATA_RSP_SIZE 1724 +#endif + +#define OEM_APP_SIGNATURE_LEN 16 +#define OEM_APP_SIGNATURE_STR "QUALCOMM-OEM-APP" + +#define OEM_TARGET_SIGNATURE_LEN 8 +#define OEM_TARGET_SIGNATURE "QUALCOMM" + +#define OEM_CAP_MAX_NUM_CHANNELS 128 + +/** + * typedef eOemErrorCode - OEM error codes + * @OEM_ERR_NULL_CONTEXT: %NULL context + * @OEM_ERR_APP_NOT_REGISTERED: OEM App is not registered + * @OEM_ERR_INVALID_SIGNATURE: Invalid signature + * @OEM_ERR_NULL_MESSAGE_HEADER: Invalid message header + * @OEM_ERR_INVALID_MESSAGE_TYPE: Invalid message type + * @OEM_ERR_INVALID_MESSAGE_LENGTH: Invalid length in message body + */ +typedef enum { + OEM_ERR_NULL_CONTEXT = 1, + OEM_ERR_APP_NOT_REGISTERED, + OEM_ERR_INVALID_SIGNATURE, + OEM_ERR_NULL_MESSAGE_HEADER, + OEM_ERR_INVALID_MESSAGE_TYPE, + OEM_ERR_INVALID_MESSAGE_LENGTH +} eOemErrorCode; + +/** + * typedef tDriverVersion - Driver version identifier (w.x.y.z) + * @major: Version ID major number + * @minor: Version ID minor number + * @patch: Version ID patch number + * @build: Version ID build number + */ +typedef struct qdf_packed { + uint8_t major; + uint8_t minor; + uint8_t patch; + uint8_t build; +} tDriverVersion; + +/** + * typedef t_iw_oem_data_cap - OEM Data Capabilities + * @oem_target_signature: Signature of chipset vendor, e.g. QUALCOMM + * @oem_target_type: Chip type + * @oem_fw_version: Firmware version + * @driver_version: Host software version + * @allowed_dwell_time_min: Channel dwell time - allowed minimum + * @allowed_dwell_time_max: Channel dwell time - allowed maximum + * @curr_dwell_time_min: Channel dwell time - current minimim + * @curr_dwell_time_max: Channel dwell time - current maximum + * @supported_bands: Supported bands, 2.4G or 5G Hz + * @num_channels: Num of channels IDs to follow + * @channel_list: List of channel IDs + */ +typedef struct qdf_packed { + uint8_t oem_target_signature[OEM_TARGET_SIGNATURE_LEN]; + uint32_t oem_target_type; + uint32_t oem_fw_version; + tDriverVersion driver_version; + uint16_t allowed_dwell_time_min; + uint16_t allowed_dwell_time_max; + uint16_t curr_dwell_time_min; + uint16_t curr_dwell_time_max; + uint16_t supported_bands; + uint16_t num_channels; + uint8_t channel_list[OEM_CAP_MAX_NUM_CHANNELS]; +} t_iw_oem_data_cap; + +/** + * typedef tHddChannelInfo - Channel information + * @chan_id: channel id + * @reserved0: reserved for padding and future use + * @mhz: primary 20 MHz channel frequency in mhz + * @band_center_freq1: Center frequency 1 in MHz + * @band_center_freq2: Center frequency 2 in MHz, valid only for 11ac + * VHT 80+80 mode + * @info: channel info + * @reg_info_1: regulatory information field 1 which contains min power, + * max power, reg power and reg class id + * @reg_info_2: regulatory information field 2 which contains antennamax + */ +typedef struct qdf_packed { + uint32_t chan_id; + uint32_t reserved0; + uint32_t mhz; + uint32_t band_center_freq1; + uint32_t band_center_freq2; + uint32_t info; + uint32_t reg_info_1; + uint32_t reg_info_2; +} tHddChannelInfo; + +/** + * typedef tPeerStatusInfo - Status information for a given peer + * @peer_mac_addr: peer mac address + * @peer_status: peer status: 1: CONNECTED, 2: DISCONNECTED + * @vdev_id: vdev_id for the peer mac + * @peer_capability: peer capability: 0: RTT/RTT2, 1: RTT3. Default is 0 + * @reserved0: reserved0 + * @peer_chan_info: channel info on which peer is connected + */ +typedef struct qdf_packed { + uint8_t peer_mac_addr[ETH_ALEN]; + uint8_t peer_status; + uint8_t vdev_id; + uint32_t peer_capability; + uint32_t reserved0; + tHddChannelInfo peer_chan_info; +} tPeerStatusInfo; + +/** + * enum oem_capability_mask - mask field for userspace client capabilities + * @OEM_CAP_RM_FTMRR: FTM range report mask bit + * @OEM_CAP_RM_LCI: LCI capability mask bit + */ +enum oem_capability_mask { + OEM_CAP_RM_FTMRR = (1 << (0)), + OEM_CAP_RM_LCI = (1 << (1)), +}; + +/** + * struct oem_get_capability_rsp - capabilites set by userspace and target. + * @target_cap: target capabilities + * @client_capabilities: capabilities set by userspace via set request + */ +struct oem_get_capability_rsp { + t_iw_oem_data_cap target_cap; + struct sme_oem_capability cap; +}; + +void hdd_send_peer_status_ind_to_oem_app(struct qdf_mac_addr *peerMac, + uint8_t peerStatus, + uint8_t peerTimingMeasCap, + uint8_t sessionId, + tSirSmeChanInfo *chan_info, + enum tQDF_ADAPTER_MODE dev_mode); + +int iw_get_oem_data_cap(struct net_device *dev, struct iw_request_info *info, + union iwreq_data *wrqu, char *extra); + +int oem_activate_service(struct hdd_context_s *hdd_ctx); + +void hdd_send_oem_data_rsp_msg(struct oem_data_rsp *oem_rsp); +#else +static inline int oem_activate_service(struct hdd_context_s *hdd_ctx) +{ + return 0; +} +#endif /* FEATURE_OEM_DATA_SUPPORT */ +#endif /* __WLAN_HDD_OEM_DATA_H__ */ diff --git a/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_p2p.h b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_p2p.h new file mode 100644 index 0000000000000000000000000000000000000000..dca03994011e27264e083cdc8eaae9eeb5c505f8 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_p2p.h @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef __P2P_H +#define __P2P_H +/**=========================================================================== + + \file wlan_hdd_p2p.h + + \brief Linux HDD P2P include file + + ==========================================================================*/ +#define ACTION_FRAME_TX_TIMEOUT 2000 +#define WAIT_CANCEL_REM_CHAN 1000 +#define WAIT_REM_CHAN_READY 1000 +#define WAIT_CHANGE_CHANNEL_FOR_OFFCHANNEL_TX 3000 +#define COMPLETE_EVENT_PROPOGATE_TIME 10 + +#ifdef QCA_WIFI_3_0_EMU +#define ACTION_FRAME_DEFAULT_WAIT 500 +#else +#define ACTION_FRAME_DEFAULT_WAIT 200 +#endif + +#define WLAN_HDD_GET_TYPE_FRM_FC(__fc__) (((__fc__) & 0x0F) >> 2) +#define WLAN_HDD_GET_SUBTYPE_FRM_FC(__fc__) (((__fc__) & 0xF0) >> 4) +#define WLAN_HDD_80211_FRM_DA_OFFSET 4 +#define P2P_WILDCARD_SSID_LEN 7 +#define P2P_WILDCARD_SSID "DIRECT-" +#define WLAN_HDD_80211_PEER_ADDR_OFFSET (WLAN_HDD_80211_FRM_DA_OFFSET + \ + MAC_ADDR_LEN) + + +#ifdef QCA_WIFI_3_0_EMU +#define P2P_ROC_DURATION_MULTIPLIER_GO_PRESENT 2 +#define P2P_ROC_DURATION_MULTIPLIER_GO_ABSENT 3 +#else +#define P2P_ROC_DURATION_MULTIPLIER_GO_PRESENT 2 +#define P2P_ROC_DURATION_MULTIPLIER_GO_ABSENT 5 +#endif + +#define HDD_P2P_MAX_ROC_DURATION 1000 +#define MAX_ROC_REQ_QUEUE_ENTRY 10 + +#define P2P_POWER_SAVE_TYPE_OPPORTUNISTIC (1 << 0) +#define P2P_POWER_SAVE_TYPE_PERIODIC_NOA (1 << 1) +#define P2P_POWER_SAVE_TYPE_SINGLE_NOA (1 << 2) + +#define ACTION_FRAME_RSP_WAIT 500 +#define ACTION_FRAME_ACK_WAIT 300 + +#ifdef WLAN_FEATURE_P2P_DEBUG +typedef enum { P2P_NOT_ACTIVE, + P2P_GO_NEG_PROCESS, + P2P_GO_NEG_COMPLETED, + P2P_CLIENT_CONNECTING_STATE_1, + P2P_GO_COMPLETED_STATE, + P2P_CLIENT_CONNECTED_STATE_1, + P2P_CLIENT_DISCONNECTED_STATE, + P2P_CLIENT_CONNECTING_STATE_2, + P2P_CLIENT_COMPLETED_STATE} tP2PConnectionStatus; + +extern tP2PConnectionStatus global_p2p_connection_status; +#endif + +typedef struct p2p_app_setP2pPs { + uint8_t opp_ps; + uint32_t ctWindow; + uint8_t count; + uint32_t duration; + uint32_t interval; + uint32_t single_noa_duration; + uint8_t psSelection; +} p2p_app_setP2pPs_t; + +int wlan_hdd_cfg80211_remain_on_channel(struct wiphy *wiphy, + struct wireless_dev *wdev, + struct ieee80211_channel *chan, + unsigned int duration, u64 *cookie); + +int wlan_hdd_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy, + struct wireless_dev *wdev, + u64 cookie); + +int wlan_hdd_cfg80211_mgmt_tx_cancel_wait(struct wiphy *wiphy, + struct wireless_dev *wdev, + u64 cookie); + +int hdd_set_p2p_ps(struct net_device *dev, void *msgData); +int hdd_set_p2p_opps(struct net_device *dev, uint8_t *command); +int hdd_set_p2p_noa(struct net_device *dev, uint8_t *command); + +void __hdd_indicate_mgmt_frame(hdd_adapter_t *pAdapter, + uint32_t nFrameLength, uint8_t *pbFrames, + uint8_t frameType, uint32_t rxChan, int8_t rxRssi); + +void hdd_remain_chan_ready_handler(hdd_adapter_t *pAdapter, + uint32_t scan_id); +void hdd_send_action_cnf(hdd_adapter_t *pAdapter, bool actionSendSuccess); +int wlan_hdd_check_remain_on_channel(hdd_adapter_t *pAdapter); +void hdd_send_action_cnf_cb(uint32_t session_id, bool status); +void wlan_hdd_cancel_existing_remain_on_channel(hdd_adapter_t *pAdapter); + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) +int wlan_hdd_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, + struct cfg80211_mgmt_tx_params *params, u64 *cookie); +#else +int wlan_hdd_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, + struct ieee80211_channel *chan, bool offchan, + unsigned int wait, + const u8 *buf, size_t len, bool no_cck, + bool dont_wait_for_ack, u64 *cookie); +#endif + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)) || defined(WITH_BACKPORTS) +struct wireless_dev *wlan_hdd_add_virtual_intf(struct wiphy *wiphy, + const char *name, + unsigned char name_assign_type, + enum nl80211_iftype type, + u32 *flags, + struct vif_params *params); +#else +struct wireless_dev *wlan_hdd_add_virtual_intf(struct wiphy *wiphy, + const char *name, + enum nl80211_iftype type, + u32 *flags, + struct vif_params *params); + +#endif + +int wlan_hdd_del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev); +int __wlan_hdd_del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev); + + +void wlan_hdd_cleanup_remain_on_channel_ctx(hdd_adapter_t *pAdapter); + +void wlan_hdd_roc_request_dequeue(struct work_struct *work); +#endif /* __P2P_H */ diff --git a/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_packet_filter_api.h b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_packet_filter_api.h new file mode 100644 index 0000000000000000000000000000000000000000..dc262f597096ccb545eeefc6d24a155665add390 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_packet_filter_api.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2017 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. + */ + +#if !defined(WLAN_HDD_PACKET_FILTER_API_H__) +#define WLAN_HDD_PACKET_FILTER_API_H__ + +/** + * DOC: wlan_hdd_packet_filter_rules.h + * + */ + +/* Include files */ +#include "wlan_hdd_assoc.h" +#include "wlan_hdd_power.h" +/** + * hdd_enable_default_pkt_filters() - Enable default packet filters based + * on, filters bit map provided in INI, when target goes to suspend mode + * @adapter: Adapter context for which default filters to be configure + * + * Return: zero if success, non-zero otherwise + */ +int hdd_enable_default_pkt_filters(hdd_adapter_t *pAadapter); + +/** + * hdd_disable_default_pkt_filters() - Disable default packet filters based + * on, filters bit map provided in INI, when target resumes + * @adapter: Adapter context for which default filters to be cleared + * + * Return: zero if success, non-zero otherwise + */ +int hdd_disable_default_pkt_filters(hdd_adapter_t *pAdapter); + +/** + * wlan_hdd_set_filter() - Set packet filter + * @hdd_ctx: Global HDD context + * @request: Packet filter request struct + * @sessionId: Target session for the request + * + * Return: 0 on success, non-zero on error + */ +int wlan_hdd_set_filter(hdd_context_t *hdd_ctx, + struct pkt_filter_cfg *request, + uint8_t sessionId); +#endif diff --git a/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_packet_filter_rules.h b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_packet_filter_rules.h new file mode 100644 index 0000000000000000000000000000000000000000..8d2bbfc92ebb0953462c8ed66f689ebb17932d9c --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_packet_filter_rules.h @@ -0,0 +1,180 @@ +/* + * Copyright (c) 2017 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. + */ + +#if !defined(WLAN_HDD_PACKET_FILTER_RULES_H__) +#define WLAN_HDD_PACKET_FILTER_RULES_H__ + +/** + * DOC: wlan_hdd_packet_filter_rules.h + * + */ + +/* Include files */ + +#define MAX_NUM_PACKET_FILTERS 6 + +/** + * @filter_action: Filter action, set/clear the filter + * Ex: filter_action = 1 set the filter + * filter_action = 2 clear the filter + * @filter_id: Filter id Ex: 1/2/3/4/5 .... MAX_NUM_FILTERS + * @num_params: Number of parameters Ex: 1/2/3/4/5 + * @params_data: Packet filter parameters details + * + * @protocol_layer: the type of protocol layer header to which the data + * being configured correspond + * Ex: protocol_layer = 1 - MAC Header + * protocol_layer = 2 - ARP Header + * protocol_layer = 3 - IP Header + * @compare_flag: comparison type + * EX: compare_flag = 0 - comparison is invalid + * compare_flag = 1 - compare for equality of the data present in received + * packet to the corresponding configured data + * compare_flag = 2 - compare for equality of the data present in received + * packet to the corresponding configured data after + * applying the mask + * compare_flag = 3 - compare for non-equality of the data present in + * received packet to the corresponding configured data + * compare_flag = 4 - compare for non-equality of the data present in + * received packet to the corresponding configured data + * after applying the mask + * @data_fffset: Offset of the data to compare from the respective protocol + * layer header start (as per the respective protocol + * specification) in terms of bytes + * @data_length: length of data to compare + * @compare_data: Array of 8 bytes + * @data_mask: Mask to be applied on the received packet data (Array of 8 bytes) + */ +static struct pkt_filter_cfg + packet_filter_default_rules[MAX_NUM_PACKET_FILTERS] = { + { .filter_action = 1, + .filter_id = 0, + .num_params = 3, + .params_data = { + { .protocol_layer = 1, + .compare_flag = 5, + .data_offset = 0, + .data_length = 1, + .compare_data = {1, 0, 0, 0, 0, 0, 0, 0}, + .data_mask = {0, 0, 0, 0, 0, 0, 0, 0} }, + { .protocol_layer = 2, + .compare_flag = 3, + .data_offset = 6, + .data_length = 2, + .compare_data = {134, 221, 0, 0, 0, 0, 0, 0}, + .data_mask = {0, 0, 0, 0, 0, 0, 0, 0} }, + { .protocol_layer = 3, + .compare_flag = 4, + .data_offset = 24, + .data_length = 2, + .compare_data = {255, 0, 0, 0, 0, 0, 0, 0}, + .data_mask = {255, 0, 0, 0, 0, 0, 0, 0} } } }, + + { .filter_action = 1, + .filter_id = 0, + .num_params = 3, + .params_data = { + { .protocol_layer = 1, + .compare_flag = 5, + .data_offset = 0, + .data_length = 1, + .compare_data = {1, 0, 0, 0, 0, 0, 0, 0}, + .data_mask = {0, 0, 0, 0, 0, 0, 0, 0} }, + { .protocol_layer = 2, + .compare_flag = 3, + .data_offset = 6, + .data_length = 2, + .compare_data = {8, 0, 0, 0, 0, 0, 0, 0}, + .data_mask = {0, 0, 0, 0, 0, 0, 0, 0} }, + { .protocol_layer = 3, + .compare_flag = 4, + .data_offset = 16, + .data_length = 1, + .compare_data = {224, 0, 0, 0, 0, 0, 0, 0}, + .data_mask = {240, 0, 0, 0, 0, 0, 0, 0} } } }, + { .filter_action = 1, + .filter_id = 0, + .num_params = 3, + .params_data = { + { .protocol_layer = 1, + .compare_flag = 5, + .data_offset = 0, + .data_length = 1, + .compare_data = {1, 0, 0, 0, 0, 0, 0, 0}, + .data_mask = {0, 0, 0, 0, 0, 0, 0, 0} }, + { .protocol_layer = 2, + .compare_flag = 3, + .data_offset = 6, + .data_length = 2, + .compare_data = {8, 0, 0, 0, 0, 0, 0, 0}, + .data_mask = {0, 0, 0, 0, 0, 0, 0, 0} }, + { .protocol_layer = 3, + .compare_flag = 4, + .data_offset = 18, + .data_length = 2, + .compare_data = {0, 255, 0, 0, 0, 0, 0, 0}, + .data_mask = {0, 255, 0, 0, 0, 0, 0, 0} } } }, + { .filter_action = 1, + .filter_id = 0, + .num_params = 2, + .params_data = { + { .protocol_layer = 1, + .compare_flag = 5, + .data_offset = 0, + .data_length = 1, + .compare_data = {1, 0, 0, 0, 0, 0, 0, 0}, + .data_mask = {0, 0, 0, 0, 0, 0, 0, 0} }, + { .protocol_layer = 2, + .compare_flag = 3, + .data_offset = 8, + .data_length = 4, + .compare_data = {0, 1, 175, 129, 0, 0, 0, 0}, + .data_mask = {0, 0, 0, 0, 0, 0, 0, 0} } } }, + { .filter_action = 1, + .filter_id = 0, + .num_params = 2, + .params_data = { + { .protocol_layer = 1, + .compare_flag = 5, + .data_offset = 0, + .data_length = 1, + .compare_data = {1, 0, 0, 0, 0, 0, 0, 0}, + .data_mask = {0, 0, 0, 0, 0, 0, 0, 0} }, + { .protocol_layer = 2, + .compare_flag = 3, + .data_offset = 6, + .data_length = 2, + .compare_data = {0, 39, 0, 0, 0, 0, 0, 0}, + .data_mask = {0, 0, 0, 0, 0, 0, 0, 0} } } }, + { .filter_action = 1, + .filter_id = 0, + .num_params = 2, + .params_data = { + { .protocol_layer = 1, + .compare_flag = 5, + .data_offset = 0, + .data_length = 1, + .compare_data = {1, 0, 0, 0, 0, 0, 0, 0}, + .data_mask = {0, 0, 0, 0, 0, 0, 0, 0} }, + { .protocol_layer = 2, + .compare_flag = 3, + .data_offset = 4, + .data_length = 2, + .compare_data = {0, 12, 0, 0, 0, 0, 0, 0}, + .data_mask = {0, 0, 0, 0, 0, 0, 0, 0} } } } }; +#endif diff --git a/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_power.h b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_power.h new file mode 100644 index 0000000000000000000000000000000000000000..4e926e55d907c178dbfe3f4080e0d0ad09231a34 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_power.h @@ -0,0 +1,276 @@ +/* + * Copyright (c) 2012, 2014-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef __WLAN_HDD_POWER_H +#define __WLAN_HDD_POWER_H + +/** + * DOC: wlan_hdd_power.h + * + * HDD Power Management API + */ + +#include "wlan_hdd_main.h" + +#ifdef WLAN_FEATURE_PACKET_FILTERING + +#define HDD_MAX_CMP_PER_PACKET_FILTER 5 + +/** + * enum pkt_filter_protocol_layer - packet filter protocol layer + * @HDD_FILTER_PROTO_TYPE_INVALID: Invalid initial value + * @HDD_FILTER_PROTO_TYPE_MAC: MAC protocol + * @HDD_FILTER_PROTO_TYPE_ARP: ARP protocol + * @HDD_FILTER_PROTO_TYPE_IPV4: IP V4 protocol + * @HDD_FILTER_PROTO_TYPE_IPV6: IP V6 protocol + * @HDD_FILTER_PROTO_TYPE_UDP: UDP protocol + * @HDD_FILTER_PROTO_TYPE_INVALID: Max place holder value + */ +enum pkt_filter_protocol_layer { + HDD_FILTER_PROTO_TYPE_INVALID = 0, + HDD_FILTER_PROTO_TYPE_MAC = 1, + HDD_FILTER_PROTO_TYPE_ARP = 2, + HDD_FILTER_PROTO_TYPE_IPV4 = 3, + HDD_FILTER_PROTO_TYPE_IPV6 = 4, + HDD_FILTER_PROTO_TYPE_UDP = 5, + HDD_FILTER_PROTO_TYPE_MAX +}; + +/** + * enum pkt_filter_action - packet filter action + * @HDD_RCV_FILTER_INVALID: Invalid initial value + * @HDD_RCV_FILTER_SET: Packet filter set + * @HDD_RCV_FILTER_CLEAR: Packet filter clear + * @HDD_RCV_FILTER_MAX: Max place holder value + */ +enum pkt_filter_action { + HDD_RCV_FILTER_INVALID = 0, + HDD_RCV_FILTER_SET = 1, + HDD_RCV_FILTER_CLEAR = 2, + HDD_RCV_FILTER_MAX +}; + +/** + * enum pkt_filter_compare_flag - packet filter compare flag + * @HDD_FILTER_CMP_TYPE_INVALID: Invalid initial value + * @HDD_FILTER_CMP_TYPE_EQUAL: Compare if filter is equal + * @HDD_FILTER_CMP_TYPE_MASK_EQUAL: Compare if filter mask is equal + * @HDD_FILTER_CMP_TYPE_NOT_EQUAL: Compare if filter is not equal + * @HDD_FILTER_CMP_TYPE_MASK_NOT_EQUAL: Compare if filter mask is not equal + * @HDD_FILTER_CMP_TYPE_MAX: Max place holder value + */ +enum pkt_filter_compare_flag { + HDD_FILTER_CMP_TYPE_INVALID = 0, + HDD_FILTER_CMP_TYPE_EQUAL = 1, + HDD_FILTER_CMP_TYPE_MASK_EQUAL = 2, + HDD_FILTER_CMP_TYPE_NOT_EQUAL = 3, + HDD_FILTER_CMP_TYPE_MASK_NOT_EQUAL = 4, + HDD_FILTER_CMP_TYPE_MAX +}; + +/** + * struct pkt_filter_param_cfg - packet filter parameter config + * @protocol_layer: Protocol layer + * @compare_flag: Compare flag + * @data_fffset: Data offset + * @data_length: Data length + * @compare_data: Compare data + * @data_mask: Data mask + */ +struct pkt_filter_param_cfg { + uint8_t protocol_layer; + uint8_t compare_flag; + uint8_t data_offset; + uint8_t data_length; + uint8_t compare_data[SIR_MAX_FILTER_TEST_DATA_LEN]; + uint8_t data_mask[SIR_MAX_FILTER_TEST_DATA_LEN]; +}; + +/** + * struct pkt_filter_cfg - packet filter config received from user space + * @filter_action: Filter action + * @filter_id: Filter id + * @num_params: Number of parameters + * @params_data: Packet filter parameters detail + */ +struct pkt_filter_cfg { + uint8_t filter_action; + uint8_t filter_id; + uint8_t num_params; + struct pkt_filter_param_cfg params_data[HDD_MAX_CMP_PER_PACKET_FILTER]; +}; + +#endif + +/** + * enum suspend_resume_state - Suspend resume state + * @HDD_WLAN_EARLY_SUSPEND: Early suspend state. + * @HDD_WLAN_SUSPEND: Suspend state. + * @HDD_WLAN_EARLY_RESUME: Early resume state. + * @HDD_WLAN_RESUME: Resume state. + * + * Suspend state to indicate in diag event of suspend resume. + */ +enum suspend_resume_state { + HDD_WLAN_EARLY_SUSPEND, + HDD_WLAN_SUSPEND, + HDD_WLAN_EARLY_RESUME, + HDD_WLAN_RESUME +}; + + +/* SSR shutdown & re-init functions */ +QDF_STATUS hdd_wlan_shutdown(void); +QDF_STATUS hdd_wlan_re_init(void); + +QDF_STATUS hdd_conf_arp_offload(hdd_adapter_t *pAdapter, bool fenable); +void hdd_conf_hostoffload(hdd_adapter_t *pAdapter, bool fenable); + +/** + * hdd_conf_hw_filter_mode() - configure the given mode for the given adapter + * @adapter: the adapter to configure the hw filter for + * @mode: the hw filter mode to configure + * + * Return: Errno + */ +int hdd_conf_hw_filter_mode(hdd_adapter_t *adapter, enum hw_filter_mode mode); + +#ifdef WLAN_FEATURE_PACKET_FILTERING +int wlan_hdd_set_mc_addr_list(hdd_adapter_t *pAdapter, uint8_t set); +#else +static inline void +wlan_hdd_set_mc_addr_list(hdd_adapter_t *pAdapter, uint8_t set) +{ +} +#endif + +int wlan_hdd_cfg80211_suspend_wlan(struct wiphy *wiphy, + struct cfg80211_wowlan *wow); + +int wlan_hdd_cfg80211_resume_wlan(struct wiphy *wiphy); + +void hdd_ipv4_notifier_work_queue(struct work_struct *work); +#ifdef WLAN_NS_OFFLOAD +void hdd_conf_ns_offload(hdd_adapter_t *adapter, bool fenable); +void hdd_ipv6_notifier_work_queue(struct work_struct *work); +#endif + +int wlan_hdd_cfg80211_get_txpower(struct wiphy *wiphy, + struct wireless_dev *wdev, + int *dbm); +int wlan_hdd_cfg80211_set_txpower(struct wiphy *wiphy, + struct wireless_dev *wdev, + enum nl80211_tx_power_setting type, + int dbm); +int wlan_hdd_cfg80211_set_power_mgmt(struct wiphy *wiphy, + struct net_device *dev, + bool allow_power_save, + int timeout); + +int wlan_hdd_ipv4_changed(struct notifier_block *nb, + unsigned long data, void *arg); + +int wlan_hdd_ipv6_changed(struct notifier_block *nb, + unsigned long data, void *arg); + +int hdd_set_qpower_config(hdd_context_t *hddctx, hdd_adapter_t *adapter, + uint8_t qpower); + +#ifdef FEATURE_WLAN_DIAG_SUPPORT +void hdd_wlan_suspend_resume_event(uint8_t state); +#else +static inline +void hdd_wlan_suspend_resume_event(uint8_t state) {} +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + +/** + * wlan_hdd_inc_suspend_stats() - Prints, then increments, then prints suspend + * failed statistics. + * @hdd_ctx: The HDD context to operate on + * @reason: The suspend failed reason to increment + * + * This function prints all of the suspend failed statistics, increments the + * specified suspend fail reason statistic, and prints the them all again. This + * is for easily keeping track of the most common reasons suspend fails. + * + * Return: none + */ +void wlan_hdd_inc_suspend_stats(hdd_context_t *hdd_ctx, + enum suspend_fail_reason reason); + +/* + * Unit-test suspend/resume is a testing feature that allows putting firmware + * into WoW suspend irrespective of Apps suspend status. It emulates the chain + * of events that occur durring normal system-level suspend/resume, such as + * initiating all of the suspend/resume stages in the correct order, and + * enabling/disabling appropriate copy engine irqs. + */ +#ifdef WLAN_SUSPEND_RESUME_TEST +/** + * wlan_hdd_unit_test_bus_suspend() - suspend the wlan bus + * @state: state containing the suspend source event + * + * This function does the same as wlan_hdd_bus_suspend, but additionally passes + * the appropriate flags to FW, indicating this is a unit-test suspend and it + * should use an HTC wakeup method to resume. + * + * Return: 0 for success or error code + */ +int wlan_hdd_unit_test_bus_suspend(pm_message_t state); + +/** + * hdd_wlan_fake_apps_resume() - Resume from unit-test triggered suspend + * @wiphy: the kernel wiphy struct for the device being resumed + * @dev: the kernel net_device struct for the device being resumed + * + * Return: Zero on success, calls QDF_BUG() on failure + */ +int hdd_wlan_fake_apps_resume(struct wiphy *wiphy, struct net_device *dev); + +/** + * hdd_wlan_fake_apps_suspend() - Initiate a unit-test triggered suspend + * @wiphy: the kernel wiphy struct for the device being suspended + * @dev: the kernel net_device struct for the device being suspended + * + * Return: Zero on success, suspend related non-zero error code on failure + */ +int hdd_wlan_fake_apps_suspend(struct wiphy *wiphy, struct net_device *dev); +#else +static inline int +hdd_wlan_fake_apps_resume(struct wiphy *wiphy, struct net_device *dev) +{ + return 0; +} + +static inline int +hdd_wlan_fake_apps_suspend(struct wiphy *wiphy, struct net_device *dev) +{ + return 0; +} +#endif /* WLAN_SUSPEND_RESUME_TEST */ + +#endif /* __WLAN_HDD_POWER_H */ diff --git a/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_regulatory.h b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_regulatory.h new file mode 100644 index 0000000000000000000000000000000000000000..682093399a42446a2033f691013f20d120688d0e --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_regulatory.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#if !defined __HDD_REGULATORY_H +#define __HDD_REGULATORY_H + +/** + * DOC: wlan_hdd_regulatory.h + * + * HDD Regulatory prototype implementation + */ + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) || defined(WITH_BACKPORTS) +#define IEEE80211_CHAN_PASSIVE_SCAN IEEE80211_CHAN_NO_IR +#define IEEE80211_CHAN_NO_IBSS IEEE80211_CHAN_NO_IR +#endif + +void hdd_reset_global_reg_params(void); +int hdd_regulatory_init(hdd_context_t *hdd_ctx, struct wiphy *wiphy); +void hdd_program_country_code(hdd_context_t *hdd_ctx); + +#endif diff --git a/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_softap_tx_rx.h b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_softap_tx_rx.h new file mode 100644 index 0000000000000000000000000000000000000000..6fdf85a983b96e1fb961db422bc1ba0f26da3e5f --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_softap_tx_rx.h @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2014-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#if !defined(WLAN_HDD_SOFTAP_TX_RX_H) +#define WLAN_HDD_SOFTAP_TX_RX_H + +/** + * DOC: wlan_hdd_softap_tx_rx.h + * + *Linux HDD SOFTAP Tx/RX APIs + */ + +#include +#include + +int hdd_softap_hard_start_xmit(struct sk_buff *skb, + struct net_device *dev); +void hdd_softap_tx_timeout(struct net_device *dev); +QDF_STATUS hdd_softap_init_tx_rx(hdd_adapter_t *pAdapter); +QDF_STATUS hdd_softap_deinit_tx_rx(hdd_adapter_t *pAdapter); +QDF_STATUS hdd_softap_init_tx_rx_sta(hdd_adapter_t *pAdapter, + uint8_t STAId, + struct qdf_mac_addr *pmacAddrSTA); +QDF_STATUS hdd_softap_deinit_tx_rx_sta(hdd_adapter_t *pAdapter, + uint8_t STAId); + +QDF_STATUS hdd_softap_rx_packet_cbk(void *context, qdf_nbuf_t rxBufChain); +#ifdef IPA_OFFLOAD +QDF_STATUS hdd_softap_rx_mul_packet_cbk(void *cds_context, + qdf_nbuf_t rx_buf_list, uint8_t staId); +#endif /* IPA_OFFLOAD */ + +QDF_STATUS hdd_softap_deregister_sta(hdd_adapter_t *pAdapter, + uint8_t staId); +QDF_STATUS hdd_softap_register_sta(hdd_adapter_t *pAdapter, + bool fAuthRequired, + bool fPrivacyBit, + uint8_t staId, + uint8_t ucastSig, + uint8_t bcastSig, + struct qdf_mac_addr *pPeerMacAddress, + bool fWmmEnabled); +QDF_STATUS hdd_softap_register_bc_sta(hdd_adapter_t *pAdapter, + bool fPrivacyBit); +QDF_STATUS hdd_softap_deregister_bc_sta(hdd_adapter_t *pAdapter); +QDF_STATUS hdd_softap_stop_bss(hdd_adapter_t *pHostapdAdapter); +QDF_STATUS hdd_softap_change_sta_state(hdd_adapter_t *pAdapter, + struct qdf_mac_addr *pDestMacAddress, + enum ol_txrx_peer_state state); +QDF_STATUS hdd_softap_get_sta_id(hdd_adapter_t *pAdapter, + struct qdf_mac_addr *pMacAddress, + uint8_t *staId); + +#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL +void hdd_softap_tx_resume_timer_expired_handler(void *adapter_context); +void hdd_softap_tx_resume_cb(void *adapter_context, bool tx_resume); +#else +static inline +void hdd_softap_tx_resume_timer_expired_handler(void *adapter_context) +{ + return; +} +static inline +void hdd_softap_tx_resume_cb(void *adapter_context, bool tx_resume) +{ + return; +} +#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */ + +#endif /* end #if !defined(WLAN_HDD_SOFTAP_TX_RX_H) */ diff --git a/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_tdls.h b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_tdls.h new file mode 100644 index 0000000000000000000000000000000000000000..c9e5144760492e1a3c9fa93643491a1ca253bc4a --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_tdls.h @@ -0,0 +1,928 @@ +/* + * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef __HDD_TDLS_H +#define __HDD_TDLS_H +/** + * DOC: wlan_hdd_tdls.h + * WLAN Host Device Driver TDLS include file + */ + +/* + * enum eTDLSSupportMode - TDLS support modes + * @eTDLS_SUPPORT_NOT_ENABLED: TDLS support not enabled + * @eTDLS_SUPPORT_DISABLED: suppress implicit trigger and not respond + * to the peer + * @eTDLS_SUPPORT_EXPLICIT_TRIGGER_ONLY: suppress implicit trigger, + * but respond to the peer + * @eTDLS_SUPPORT_ENABLED: implicit trigger + * @eTDLS_SUPPORT_EXTERNAL_CONTROL: implicit trigger but only to a + * peer mac configured by user space. + */ +typedef enum { + eTDLS_SUPPORT_NOT_ENABLED = 0, + eTDLS_SUPPORT_DISABLED, + eTDLS_SUPPORT_EXPLICIT_TRIGGER_ONLY, + eTDLS_SUPPORT_ENABLED, + eTDLS_SUPPORT_EXTERNAL_CONTROL, +} eTDLSSupportMode; + +/** + * enum tdls_concerned_external_events - External events that affect TDLS + * @P2P_ROC_START: P2P remain on channel starts + * @P2P_ROC_END: P2P remain on channel ends + */ +enum tdls_concerned_external_events { + P2P_ROC_START, + P2P_ROC_END, +}; + +#ifdef FEATURE_WLAN_TDLS + +/* + * Before UpdateTimer expires, we want to timeout discovery response + * should not be more than 2000. + */ +#define TDLS_DISCOVERY_TIMEOUT_BEFORE_UPDATE 1000 + +#define TDLS_CTX_MAGIC 0x54444c53 /* "TDLS" */ + +#define TDLS_MAX_SCAN_SCHEDULE 10 +#define TDLS_MAX_SCAN_REJECT 5 +#define TDLS_DELAY_SCAN_PER_CONNECTION 100 +#define TDLS_MAX_CONNECTED_PEERS_TO_ALLOW_SCAN 1 + +#define TDLS_IS_CONNECTED(peer) \ + ((eTDLS_LINK_CONNECTED == (peer)->link_status) || \ + (eTDLS_LINK_TEARING == (peer)->link_status)) + +/* Bit mask flag for tdls_option to FW */ +#define ENA_TDLS_OFFCHAN (1 << 0) /* TDLS Off Channel support */ +#define ENA_TDLS_BUFFER_STA (1 << 1) /* TDLS Buffer STA support */ +#define ENA_TDLS_SLEEP_STA (1 << 2) /* TDLS Sleep STA support */ +#define TDLS_SEC_OFFCHAN_OFFSET_0 0 +#define TDLS_SEC_OFFCHAN_OFFSET_40PLUS 40 +#define TDLS_SEC_OFFCHAN_OFFSET_40MINUS (-40) +#define TDLS_SEC_OFFCHAN_OFFSET_80 80 +#define TDLS_SEC_OFFCHAN_OFFSET_160 160 + +#define TDLS_PEER_LIST_SIZE 256 + +#define TDLS_CT_MAC_AGE_OUT_TIME (30*60*1000) /* Age out time is 30 mins */ + +#define EXTTDLS_EVENT_BUF_SIZE (4096) + +#define TDLS_CT_MAC_MAX_TABLE_SIZE 8 + +/* Define the interval for 5 minutes */ +#define TDLS_ENABLE_CDS_FLUSH_INTERVAL 300000000 + +/** + * enum tdls_disable_source - TDLS disable sources + * @HDD_SET_TDLS_MODE_SOURCE_USER: disable from user + * @HDD_SET_TDLS_MODE_SOURCE_SCAN: disable during scan + * @HDD_SET_TDLS_MODE_SOURCE_OFFCHANNEL: disable during offchannel + * @HDD_SET_TDLS_MODE_SOURCE_BTC: disable during bluetooth + * @HDD_SET_TDLS_MODE_SOURCE_P2P: disable during p2p + */ +enum tdls_disable_source { + HDD_SET_TDLS_MODE_SOURCE_USER = 0, + HDD_SET_TDLS_MODE_SOURCE_SCAN, + HDD_SET_TDLS_MODE_SOURCE_OFFCHANNEL, + HDD_SET_TDLS_MODE_SOURCE_BTC, + HDD_SET_TDLS_MODE_SOURCE_P2P, +}; + +/** + * struct tdls_config_params_t - tdls config params + * + * @tdls: tdls + * @tx_period_t: tx period + * @tx_packet_n: tx packets number + * @discovery_tries_n: discovery tries + * @idle_timeout_t: idle traffic time out value + * @idle_packet_n: idle packet number + * @rssi_trigger_threshold: rssi trigger threshold + * @rssi_teardown_threshold: rssi tear down threshold + * @rssi_delta: rssi delta + */ +typedef struct { + uint32_t tdls; + uint32_t tx_period_t; + uint32_t tx_packet_n; + uint32_t discovery_tries_n; + uint32_t idle_timeout_t; + uint32_t idle_packet_n; + int32_t rssi_trigger_threshold; + int32_t rssi_teardown_threshold; + int32_t rssi_delta; +} tdls_config_params_t; + +/** + * struct tdls_scan_context_t - tdls scan context + * + * @wiphy: pointer to wiphy structure + * @dev: pointer to netdev + * @scan_request: scan request + * @magic: magic + * @attempt: attempt + * @reject: reject + * @source: scan request source(NL/Vendor scan) + * @tdls_scan_work: delayed tdls scan work + */ +typedef struct { + struct wiphy *wiphy; + struct cfg80211_scan_request *scan_request; + uint32_t magic; + int attempt; + int reject; + uint8_t source; + struct delayed_work tdls_scan_work; +} tdls_scan_context_t; + +/** + * enum tdls_spatial_streams - TDLS spatial streams + * @TDLS_NSS_1x1_MODE: TDLS tx/rx spatial streams = 1 + * @TDLS_NSS_2x2_MODE: TDLS tx/rx spatial streams = 2 + */ +enum tdls_spatial_streams { + TDLS_NSS_1x1_MODE = 0, + TDLS_NSS_2x2_MODE = 0xff, +}; + +/** + * enum tdls_nss_transition_type - TDLS NSS transition states + * @TDLS_NSS_TRANSITION_UNKNOWN: default state + * @TDLS_NSS_TRANSITION_2x2_to_1x1: transition from 2x2 to 1x1 stream + * @TDLS_NSS_TRANSITION_1x1_to_2x2: transition from 1x1 to 2x2 stream + */ +enum tdls_nss_transition_type { + TDLS_NSS_TRANSITION_UNKNOWN = 0, + TDLS_NSS_TRANSITION_2x2_to_1x1, + TDLS_NSS_TRANSITION_1x1_to_2x2, +}; + +/** + * enum tTDLSCapType - tdls capability type + * + * @eTDLS_CAP_NOT_SUPPORTED: tdls not supported + * @eTDLS_CAP_UNKNOWN: unknown capability + * @eTDLS_CAP_SUPPORTED: tdls capability supported + */ +typedef enum eTDLSCapType { + eTDLS_CAP_NOT_SUPPORTED = -1, + eTDLS_CAP_UNKNOWN = 0, + eTDLS_CAP_SUPPORTED = 1, +} tTDLSCapType; + +/** + * enum tTDLSLinkStatus - tdls link status + * + * @eTDLS_LINK_IDLE: tdls link idle + * @eTDLS_LINK_DISCOVERING: tdls link discovering + * @eTDLS_LINK_DISCOVERED: tdls link discovered + * @eTDLS_LINK_CONNECTING: tdls link connecting + * @eTDLS_LINK_CONNECTED: tdls link connected + * @eTDLS_LINK_TEARING: tdls link tearing + */ +typedef enum eTDLSLinkStatus { + eTDLS_LINK_IDLE = 0, + eTDLS_LINK_DISCOVERING, + eTDLS_LINK_DISCOVERED, + eTDLS_LINK_CONNECTING, + eTDLS_LINK_CONNECTED, + eTDLS_LINK_TEARING, +} tTDLSLinkStatus; + +/** + * enum tdls_teardown_reason - Reason for TDLS teardown + * @eTDLS_TEARDOWN_EXT_CTRL: Reason ext ctrl. + * @eTDLS_TEARDOWN_CONCURRENCY: Reason concurrency. + * @eTDLS_TEARDOWN_RSSI_THRESHOLD: Reason rssi threshold. + * @eTDLS_TEARDOWN_TXRX_THRESHOLD: Reason txrx threshold. + * @eTDLS_TEARDOWN_BTCOEX: Reason BTCOEX. + * @eTDLS_TEARDOWN_SCAN: Reason scan. + * @eTDLS_TEARDOWN_BSS_DISCONNECT: Reason bss disconnected. + * @eTDLS_TEARDOWN_ANTENNA_SWITCH: Disconnected due to antenna switch + * + * Reason to indicate in diag event of tdls teardown. + */ +enum tdls_teardown_reason { + eTDLS_TEARDOWN_EXT_CTRL, + eTDLS_TEARDOWN_CONCURRENCY, + eTDLS_TEARDOWN_RSSI_THRESHOLD, + eTDLS_TEARDOWN_TXRX_THRESHOLD, + eTDLS_TEARDOWN_BTCOEX, + eTDLS_TEARDOWN_SCAN, + eTDLS_TEARDOWN_BSS_DISCONNECT, + eTDLS_TEARDOWN_ANTENNA_SWITCH, +}; + +/** + * enum tTDLSLinkReason - tdls link reason + * + * @eTDLS_LINK_SUCCESS: Success + * @eTDLS_LINK_UNSPECIFIED: Unspecified reason + * @eTDLS_LINK_NOT_SUPPORTED: Remote side doesn't support TDLS + * @eTDLS_LINK_UNSUPPORTED_BAND: Remote side doesn't support this band + * @eTDLS_LINK_NOT_BENEFICIAL: Going to AP is better than direct + * @eTDLS_LINK_DROPPED_BY_REMOTE: Remote side doesn't want it anymore + */ +typedef enum { + eTDLS_LINK_SUCCESS, + eTDLS_LINK_UNSPECIFIED = -1, + eTDLS_LINK_NOT_SUPPORTED = -2, + eTDLS_LINK_UNSUPPORTED_BAND = -3, + eTDLS_LINK_NOT_BENEFICIAL = -4, + eTDLS_LINK_DROPPED_BY_REMOTE = -5 +} tTDLSLinkReason; + +/** + * struct tdls_req_params_t - tdls request parameters + * + * @channel: channel hint, in channel number (NOT frequency) + * @global_operating_class: operating class to use + * @max_latency_ms: max latency that can be tolerated by apps + * @min_bandwidth_kbps: bandwidth required by apps, in kilo bits per second + */ +typedef struct { + int channel; + int global_operating_class; + int max_latency_ms; + int min_bandwidth_kbps; +} tdls_req_params_t; + +/** + * enum tdls_state_t - tdls state + * + * @QCA_WIFI_HAL_TDLS_DISABLED: TDLS is not enabled, or is disabled now + * @QCA_WIFI_HAL_TDLS_ENABLED: TDLS is enabled, but not yet tried + * @QCA_WIFI_HAL_TDLS_ESTABLISHED: Direct link is established + * @QCA_WIFI_HAL_TDLS_ESTABLISHED_OFF_CHANNEL: Direct link established using MCC + * @QCA_WIFI_HAL_TDLS_DROPPED: Direct link was established, but is now dropped + * @QCA_WIFI_HAL_TDLS_FAILED: Direct link failed + */ +typedef enum { + QCA_WIFI_HAL_TDLS_DISABLED = 1, + QCA_WIFI_HAL_TDLS_ENABLED, + QCA_WIFI_HAL_TDLS_ESTABLISHED, + QCA_WIFI_HAL_TDLS_ESTABLISHED_OFF_CHANNEL, + QCA_WIFI_HAL_TDLS_DROPPED, + QCA_WIFI_HAL_TDLS_FAILED +} tdls_state_t; + +typedef int (*cfg80211_exttdls_callback)(const uint8_t *mac, + uint32_t opclass, + uint32_t channel, + uint32_t state, + int32_t reason, void *ctx); + +/** + * struct tdls_tx_tput_config_t - tdls tx throughput config + * + * @period: period + * @bytes: bytes + */ +typedef struct { + uint16_t period; + uint16_t bytes; +} tdls_tx_tput_config_t; + +/** + * struct tdls_discovery_config_t - tdls discovery config + * + * @period: period + * @tries: number of tries + */ +typedef struct { + uint16_t period; + uint16_t tries; +} tdls_discovery_config_t; + +/** + * struct tdls_rx_idle_config_t - tdls rx idle config + * + * @timeout: timeout + */ +typedef struct { + uint16_t timeout; +} tdls_rx_idle_config_t; + +/** + * struct tdls_rssi_config_t - tdls rssi config + * + * @rssi_thres: rssi_thres + */ +typedef struct { + uint16_t rssi_thres; +} tdls_rssi_config_t; + +struct _hddTdlsPeer_t; + +/** + * struct tdls_ct_mac_table - connection tracker peer mac address table + * @mac_address: peer mac address + * @tx_packet_cnt: number of tx pkts + * @rx_packet_cnt: number of rx pkts + * @peer_timestamp_ms: time stamp of latest peer traffic + */ +struct tdls_ct_mac_table { + struct qdf_mac_addr mac_address; + uint32_t tx_packet_cnt; + uint32_t rx_packet_cnt; + uint32_t peer_timestamp_ms; +}; + +/** + * struct tdls_set_state_db - set state command data base + * @set_state_cnt: tdls set state count + * @vdev_id: vdev id of last set state command + */ +struct tdls_set_state_info { + uint8_t set_state_cnt; + uint8_t vdev_id; +}; + +/** + * struct tdlsCtx_t - tdls context + * + * @peer_list: peer list + * @pAdapter: pointer to adapter + * @peer_update_timer: connection tracker timer + * @peerDiscoverTimer: peer discovery timer + * @peerDiscoveryTimeoutTimer: peer discovery timeout timer + * @threshold_config: threshold config + * @discovery_peer_cnt: discovery peer count + * @discovery_sent_cnt: discovery sent count + * @ap_rssi: ap rssi + * @curr_candidate: current candidate + * @magic: magic + * @last_flush_ts: last timestamp when flush logs was displayed. + * + */ +typedef struct { + struct list_head peer_list[TDLS_PEER_LIST_SIZE]; + hdd_adapter_t *pAdapter; + qdf_mc_timer_t peer_update_timer; + qdf_mc_timer_t peerDiscoveryTimeoutTimer; + tdls_config_params_t threshold_config; + int32_t discovery_peer_cnt; + uint32_t discovery_sent_cnt; + int8_t ap_rssi; + struct _hddTdlsPeer_t *curr_candidate; + uint32_t magic; + uint64_t last_flush_ts; +} tdlsCtx_t; + +/** + * struct hddTdlsPeer_t - tdls peer data + * + * @node: node + * @pHddTdlsCtx: pointer to tdls context + * @peerMac: peer mac address + * @staId: station identifier + * @rssi: rssi + * @tdls_support: tdls support + * @link_status: tdls link status + * @signature: signature + * @is_responder: is responder + * @discovery_processed: discovery processed flag + * @discovery_attempt: discovery attempt + * @tx_pkt: tx packet + * @rx_pkt: rx packet + * @uapsdQueues: uapsd queues + * @maxSp: max sp + * @isBufSta: is buffer sta + * @isOffChannelSupported: is offchannel supported flag + * @supported_channels_len: supported channels length + * @supported_channels: supported channels + * @supported_oper_classes_len: supported operation classes length + * @supported_oper_classes: supported operation classes + * @isForcedPeer: is forced peer + * @op_class_for_pref_off_chan: op class for preferred off channel + * @pref_off_chan_num: preferred off channel number + * @op_class_for_pref_off_chan_is_set: op class for preferred off channel set + * @peer_idle_timer: time to check idle traffic in tdls peers + * @is_peer_idle_timer_initialised: Flag to check idle timer init + * @spatial_streams: Number of TX/RX spatial streams for TDLS + * @reason: reason + * @state_change_notification: state change notification + * @qos: QOS capability of TDLS link + */ +typedef struct _hddTdlsPeer_t { + struct list_head node; + tdlsCtx_t *pHddTdlsCtx; + tSirMacAddr peerMac; + uint16_t staId; + int8_t rssi; + tTDLSCapType tdls_support; + tTDLSLinkStatus link_status; + uint8_t signature; + uint8_t is_responder; + uint8_t discovery_processed; + uint16_t discovery_attempt; + uint16_t tx_pkt; + uint16_t rx_pkt; + uint8_t uapsdQueues; + uint8_t maxSp; + uint8_t isBufSta; + uint8_t isOffChannelSupported; + uint8_t supported_channels_len; + uint8_t supported_channels[SIR_MAC_MAX_SUPP_CHANNELS]; + uint8_t supported_oper_classes_len; + uint8_t supported_oper_classes[CDS_MAX_SUPP_OPER_CLASSES]; + bool isForcedPeer; + uint8_t op_class_for_pref_off_chan; + uint8_t pref_off_chan_num; + uint8_t op_class_for_pref_off_chan_is_set; + qdf_mc_timer_t peer_idle_timer; + bool is_peer_idle_timer_initialised; + uint8_t spatial_streams; + tTDLSLinkReason reason; + cfg80211_exttdls_callback state_change_notification; + uint8_t qos; +} hddTdlsPeer_t; + +/** + * struct tdlsConnInfo_t - tdls connection info + * + * @sessionId: Session ID + * @staId: TDLS peer station id + * @peerMac: peer mac address + */ +typedef struct { + uint8_t sessionId; + uint8_t staId; + struct qdf_mac_addr peerMac; +} tdlsConnInfo_t; + +/** + * struct tdlsInfo_t - tdls info + * + * @vdev_id: vdev id + * @tdls_state: tdls state + * @notification_interval_ms: notification interval in ms + * @tx_discovery_threshold: tx discovery threshold + * @tx_teardown_threshold: tx teardown threshold + * @rssi_teardown_threshold: rx teardown threshold + * @rssi_delta: rssi delta + * @tdls_options: tdls options + * @peer_traffic_ind_window: peer traffic indication window + * @peer_traffic_response_timeout: peer traffic response timeout + * @puapsd_mask: puapsd mask + * @puapsd_inactivity_time: puapsd inactivity time + * @puapsd_rx_frame_threshold: puapsd rx frame threshold + * @teardown_notification_ms: tdls teardown notification interval + * @tdls_peer_kickout_threshold: tdls packets threshold + * for peer kickout operation + */ +typedef struct { + uint32_t vdev_id; + uint32_t tdls_state; + uint32_t notification_interval_ms; + uint32_t tx_discovery_threshold; + uint32_t tx_teardown_threshold; + int32_t rssi_teardown_threshold; + int32_t rssi_delta; + uint32_t tdls_options; + uint32_t peer_traffic_ind_window; + uint32_t peer_traffic_response_timeout; + uint32_t puapsd_mask; + uint32_t puapsd_inactivity_time; + uint32_t puapsd_rx_frame_threshold; + uint32_t teardown_notification_ms; + uint32_t tdls_peer_kickout_threshold; +} tdlsInfo_t; + +int wlan_hdd_tdls_init(hdd_adapter_t *pAdapter); + +void wlan_hdd_tdls_exit(hdd_adapter_t *pAdapter); + +void wlan_hdd_tdls_extract_sa(struct sk_buff *skb, uint8_t *mac); + +int wlan_hdd_tdls_set_sta_id(hdd_adapter_t *pAdapter, const uint8_t *mac, + uint8_t staId); + +hddTdlsPeer_t *wlan_hdd_tdls_find_peer(hdd_adapter_t *pAdapter, + const uint8_t *mac); + +hddTdlsPeer_t *wlan_hdd_tdls_find_all_peer(hdd_context_t *pHddCtx, + const uint8_t *mac); + +int wlan_hdd_tdls_get_link_establish_params(hdd_adapter_t *pAdapter, + const uint8_t *mac, + tCsrTdlsLinkEstablishParams * + tdlsLinkEstablishParams); +hddTdlsPeer_t *wlan_hdd_tdls_get_peer(hdd_adapter_t *pAdapter, + const uint8_t *mac); + +int wlan_hdd_tdls_set_cap(hdd_adapter_t *pAdapter, const uint8_t *mac, + tTDLSCapType cap); + +void wlan_hdd_tdls_set_peer_link_status(hddTdlsPeer_t *curr_peer, + tTDLSLinkStatus status, + tTDLSLinkReason reason); +void wlan_hdd_tdls_set_link_status(hdd_adapter_t *pAdapter, + const uint8_t *mac, + tTDLSLinkStatus linkStatus, + tTDLSLinkReason reason); + +int wlan_hdd_tdls_recv_discovery_resp(hdd_adapter_t *pAdapter, + const uint8_t *mac); + +int wlan_hdd_tdls_set_peer_caps(hdd_adapter_t *pAdapter, + const uint8_t *mac, + tCsrStaParams *StaParams, + bool isBufSta, bool isOffChannelSupported, + bool is_qos_wmm_sta); + +int wlan_hdd_tdls_set_rssi(hdd_adapter_t *pAdapter, const uint8_t *mac, + int8_t rxRssi); + +int wlan_hdd_tdls_set_responder(hdd_adapter_t *pAdapter, const uint8_t *mac, + uint8_t responder); + +int wlan_hdd_tdls_set_signature(hdd_adapter_t *pAdapter, const uint8_t *mac, + uint8_t uSignature); + +int wlan_hdd_tdls_set_params(struct net_device *dev, + tdls_config_params_t *config); + +int wlan_hdd_tdls_reset_peer(hdd_adapter_t *pAdapter, const uint8_t *mac); + +uint16_t wlan_hdd_tdls_connected_peers(hdd_adapter_t *pAdapter); + +int wlan_hdd_tdls_get_all_peers(hdd_adapter_t *pAdapter, char *buf, + int buflen); + +void wlan_hdd_tdls_connection_callback(hdd_adapter_t *pAdapter); + +void wlan_hdd_tdls_disconnection_callback(hdd_adapter_t *pAdapter); + +void wlan_hdd_tdls_mgmt_completion_callback(hdd_adapter_t *pAdapter, + uint32_t statusCode); + +void wlan_hdd_tdls_increment_peer_count(hdd_adapter_t *pAdapter); + +void wlan_hdd_tdls_decrement_peer_count(hdd_adapter_t *pAdapter); + +hddTdlsPeer_t *wlan_hdd_tdls_is_progress(hdd_context_t *pHddCtx, + const uint8_t *mac, uint8_t skip_self); + +int wlan_hdd_tdls_copy_scan_context(hdd_context_t *pHddCtx, + struct wiphy *wiphy, + struct cfg80211_scan_request *request); + +int wlan_hdd_tdls_scan_callback(hdd_adapter_t *pAdapter, struct wiphy *wiphy, + struct cfg80211_scan_request *request, + uint8_t source); + +void wlan_hdd_tdls_scan_done_callback(hdd_adapter_t *pAdapter); + +void wlan_hdd_tdls_timer_restart(hdd_adapter_t *pAdapter, + qdf_mc_timer_t *timer, + uint32_t expirationTime); +void wlan_hdd_tdls_indicate_teardown(hdd_adapter_t *pAdapter, + hddTdlsPeer_t *curr_peer, + uint16_t reason); + +void wlan_hdd_tdls_implicit_send_discovery_request(tdlsCtx_t *hdd_tdls_ctx); + +int wlan_hdd_tdls_set_extctrl_param(hdd_adapter_t *pAdapter, + const uint8_t *mac, + uint32_t chan, + uint32_t max_latency, + uint32_t op_class, uint32_t min_bandwidth); +int wlan_hdd_tdls_set_force_peer(hdd_adapter_t *pAdapter, const uint8_t *mac, + bool forcePeer); + +int wlan_hdd_tdls_update_peer_mac(hdd_adapter_t *adapter, + const uint8_t *mac, + uint32_t peer_state); + +int wlan_hdd_tdls_extctrl_deconfig_peer(hdd_adapter_t *pAdapter, + const uint8_t *peer); +int wlan_hdd_tdls_extctrl_config_peer(hdd_adapter_t *pAdapter, + const uint8_t *peer, + cfg80211_exttdls_callback callback, + uint32_t chan, + uint32_t max_latency, + uint32_t op_class, + uint32_t min_bandwidth); +int wlan_hdd_tdls_get_status(hdd_adapter_t *pAdapter, + const uint8_t *mac, uint32_t *opclass, + uint32_t *channel, uint32_t *state, + int32_t *reason); +void wlan_hdd_tdls_get_wifi_hal_state(hddTdlsPeer_t *curr_peer, + uint32_t *state, int32_t *reason); +int wlan_hdd_set_callback(hddTdlsPeer_t *curr_peer, + cfg80211_exttdls_callback callback); +void wlan_hdd_update_tdls_info(hdd_adapter_t *adapter, bool tdls_prohibited, + bool tdls_chan_swit_prohibited); + +int wlan_hdd_tdls_add_station(struct wiphy *wiphy, + struct net_device *dev, const uint8_t *mac, + bool update, tCsrStaParams *StaParams); + +int wlan_hdd_cfg80211_exttdls_enable(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len); + +int wlan_hdd_cfg80211_exttdls_disable(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len); + +int wlan_hdd_cfg80211_exttdls_get_status(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len); + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)) +int wlan_hdd_cfg80211_tdls_oper(struct wiphy *wiphy, + struct net_device *dev, + const uint8_t *peer, + enum nl80211_tdls_operation oper); +#else +int wlan_hdd_cfg80211_tdls_oper(struct wiphy *wiphy, + struct net_device *dev, + uint8_t *peer, + enum nl80211_tdls_operation oper); +#endif + +#ifdef TDLS_MGMT_VERSION2 +int wlan_hdd_cfg80211_tdls_mgmt(struct wiphy *wiphy, + struct net_device *dev, u8 *peer, + u8 action_code, u8 dialog_token, + u16 status_code, u32 peer_capability, + const u8 *buf, size_t len); +#else +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 17, 0)) +int wlan_hdd_cfg80211_tdls_mgmt(struct wiphy *wiphy, + struct net_device *dev, const uint8_t *peer, + uint8_t action_code, uint8_t dialog_token, + uint16_t status_code, uint32_t peer_capability, + bool initiator, const uint8_t *buf, + size_t len); +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)) +int wlan_hdd_cfg80211_tdls_mgmt(struct wiphy *wiphy, + struct net_device *dev, const uint8_t *peer, + uint8_t action_code, uint8_t dialog_token, + uint16_t status_code, uint32_t peer_capability, + const uint8_t *buf, size_t len); +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0)) +int wlan_hdd_cfg80211_tdls_mgmt(struct wiphy *wiphy, + struct net_device *dev, uint8_t *peer, + uint8_t action_code, uint8_t dialog_token, + uint16_t status_code, uint32_t peer_capability, + const uint8_t *buf, size_t len); +#else +int wlan_hdd_cfg80211_tdls_mgmt(struct wiphy *wiphy, + struct net_device *dev, uint8_t *peer, + uint8_t action_code, uint8_t dialog_token, + uint16_t status_code, const uint8_t *buf, + size_t len); +#endif +#endif + +/** + * wlan_hdd_tdls_check_enable_tdls_scan - Check whether enable_tdls_scan ini + * is true + * @hdd_ctx: hdd context + * + * This routine is called to check whether enable_tdls_scan is true or no. + * + * Return: true if enable_tdls_scan is true, else false + */ +bool wlan_hdd_tdls_check_enable_tdls_scan(hdd_context_t *hdd_ctx); + +/** + * wlan_hdd_tdls_check_peer_buf_capable - Checks whether self-Sta is sleep-sta + * capable and all peer TDLS Sta are BufSta capable. + * @hdd_ctx: hdd context + * @connectedTdlsPeers: number of tdls peers + * + * This routine is called to check whether self-Sta is sleep-Sta capable and + * all peer TDLS Sta are BufSta capable + * + * Return: True if scan is allowed without tearing TDLS, else false + */ +bool wlan_hdd_tdls_check_peer_buf_capable(hdd_context_t *hdd_ctx, + uint16_t connectedTdlsPeers); +void hdd_update_tdls_ct_and_teardown_links(hdd_context_t *hdd_ctx); +void wlan_hdd_tdls_disable_offchan_and_teardown_links(hdd_context_t *hddctx); + +hddTdlsPeer_t *wlan_hdd_tdls_find_first_connected_peer(hdd_adapter_t *adapter); +int hdd_set_tdls_offchannel(hdd_context_t *hdd_ctx, int offchannel); +int hdd_set_tdls_secoffchanneloffset(hdd_context_t *hdd_ctx, int offchanoffset); +int hdd_set_tdls_offchannelmode(hdd_adapter_t *adapter, int offchanmode); +void wlan_hdd_tdls_update_tx_pkt_cnt(hdd_adapter_t *adapter, + struct sk_buff *skb); +void wlan_hdd_tdls_update_rx_pkt_cnt(hdd_adapter_t *adapter, + struct sk_buff *skb); +int hdd_set_tdls_scan_type(hdd_context_t *hdd_ctx, int val); +void hdd_tdls_context_init(hdd_context_t *hdd_ctx, bool ssr); +void hdd_tdls_context_destroy(hdd_context_t *hdd_ctx); +int wlan_hdd_tdls_antenna_switch(hdd_context_t *hdd_ctx, + hdd_adapter_t *adapter, + uint32_t mode); +/** + * wlan_hdd_tdls_notify_connect() - Update tdls state for every + * connect event. + * @adapter: hdd adapter + * @csr_roam_info: csr information + * + * After every connect event in the system, check whether TDLS + * can be enabled in the system. If TDLS can be enabled, update the + * TDLS state as needed. + * + * Return: None + */ +void wlan_hdd_tdls_notify_connect(hdd_adapter_t *adapter, + tCsrRoamInfo *csr_roam_info); + +/** + * wlan_hdd_tdls_notify_disconnect() - Update tdls state for every + * disconnect event. + * @adapter: hdd adapter + * @lfr_roam: roaming case + * + * After every disconnect event in the system, check whether TDLS + * can be disabled/enabled in the system and update the + * TDLS state as needed. + * + * Return: None + */ +void wlan_hdd_tdls_notify_disconnect(hdd_adapter_t *adapter, bool lfr_roam); + +/** + * wlan_hdd_check_conc_and_update_tdls_state - Check concurrency and update + * FW TDLS state if needed + * @hdd_ctx: hdd context + * @disable_tdls: disable TDLS in FW TDLS state + * + * This routine is called to teardown TDLS links, and enable/disable TDLS mode + * in FW tdls state if concurrency is detected. + * + * Return: None + */ +void wlan_hdd_check_conc_and_update_tdls_state(hdd_context_t *hdd_ctx, + bool disable_tdls); + +void wlan_hdd_change_tdls_mode(void *hdd_ctx); + +/** + * hdd_tdls_notify_p2p_roc() - Notify p2p roc event to TDLS + * @hdd_ctx: ptr to hdd context. + * @event: P2P roc event that affect TDLS + * + * P2P roc events notified to TDLS to avoid overlap between P2P listen + * and TDLS operation. + * Based on P2P remain on channel event, TDLS mode will be + * updated and TDLS source timer started with timer period + * equivalent to P2P ROC interval to revert the TDLS mode. + * + * Return: None + */ +void hdd_tdls_notify_p2p_roc(hdd_context_t *hdd_ctx, + enum tdls_concerned_external_events event); + +/** + * wlan_hdd_cfg80211_configure_tdls_mode() - configure tdls mode + * @wiphy: pointer to wireless wiphy structure. + * @wdev: pointer to wireless_dev structure. + * @data: Pointer to the data to be passed via vendor interface + * @data_len:Length of the data to be passed + * + * Return: Return the Success or Failure code. + */ +int wlan_hdd_cfg80211_configure_tdls_mode(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len); + +#else +static inline bool +wlan_hdd_tdls_check_enable_tdls_scan(hdd_context_t *hdd_ctx) +{ + return true; +} +static inline bool +wlan_hdd_tdls_check_peer_buf_capable(hdd_context_t *hdd_ctx, + uint16_t connectedTdlsPeers) +{ + return true; +} +static inline void hdd_update_tdls_ct_and_teardown_links(hdd_context_t *hdd_ctx) +{ +} +static inline void +wlan_hdd_tdls_disable_offchan_and_teardown_links(hdd_context_t *hddctx) +{ +} +static inline void wlan_hdd_tdls_exit(hdd_adapter_t *adapter) +{ +} +static inline void wlan_hdd_tdls_update_tx_pkt_cnt(hdd_adapter_t *adapter, + struct sk_buff *skb) +{ +} +static inline void wlan_hdd_tdls_update_rx_pkt_cnt(hdd_adapter_t *adapter, + struct sk_buff *skb) +{ +} +static inline void hdd_tdls_context_init(hdd_context_t *hdd_ctx, bool ssr) { } +static inline void hdd_tdls_context_destroy(hdd_context_t *hdd_ctx) { } + +static inline int wlan_hdd_tdls_antenna_switch(hdd_context_t *hdd_ctx, + hdd_adapter_t *adapter, + uint32_t mode) +{ + return 0; +} +static inline void wlan_hdd_update_tdls_info(hdd_adapter_t *adapter, + bool tdls_prohibited, + bool tdls_chan_swit_prohibited) +{ +} +static inline void wlan_hdd_tdls_notify_connect(hdd_adapter_t *adapter, + tCsrRoamInfo *csr_roam_info) +{ +} +static inline void wlan_hdd_tdls_notify_disconnect(hdd_adapter_t *adapter, + bool lfr_roam) +{ +} + +static inline void +wlan_hdd_check_conc_and_update_tdls_state(hdd_context_t *hdd_ctx, + bool disable_tdls) +{ +} + +static inline int wlan_hdd_cfg80211_configure_tdls_mode(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + return 0; +} + +static inline void wlan_hdd_change_tdls_mode(void *hdd_ctx) +{ +} +static inline void +hdd_tdls_notify_p2p_roc(hdd_context_t *hdd_ctx, + enum tdls_concerned_external_events event) +{ +} +#endif /* End of FEATURE_WLAN_TDLS */ + +#ifdef FEATURE_WLAN_DIAG_SUPPORT +void hdd_send_wlan_tdls_teardown_event(uint32_t reason, + uint8_t *peer_mac); +void hdd_wlan_tdls_enable_link_event(const uint8_t *peer_mac, + uint8_t is_off_chan_supported, + uint8_t is_off_chan_configured, + uint8_t is_off_chan_established); +void hdd_wlan_block_scan_by_tdls_event(void); +#else +static inline +void hdd_send_wlan_tdls_teardown_event(uint32_t reason, + uint8_t *peer_mac) {} +static inline +void hdd_wlan_tdls_enable_link_event(const uint8_t *peer_mac, + uint8_t is_off_chan_supported, + uint8_t is_off_chan_configured, + uint8_t is_off_chan_established) {} +static inline void hdd_wlan_block_scan_by_tdls_event(void) {} +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + +void wlan_hdd_tdls_timers_stop(tdlsCtx_t *hdd_tdls_ctx); + +#endif /* __HDD_TDLS_H */ diff --git a/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_trace.h b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_trace.h new file mode 100644 index 0000000000000000000000000000000000000000..b35fea3e44b39f02f95fe1d4e4a86e278cafdd6a --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_trace.h @@ -0,0 +1,151 @@ +/* + * Copyright (c) 2014-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef __WLAN_HDD_TRACE_H__ +#define __WLAN_HDD_TRACE_H__ + +#include "mac_trace.h" + +#define NO_SESSION 0xFF + +#undef ENUMS +#define ENUMS \ + ENUM(TRACE_CODE_HDD_OPEN_REQUEST) \ + ENUM(TRACE_CODE_HDD_STOP_REQUEST) \ + ENUM(TRACE_CODE_HDD_TX_TIMEOUT) \ + ENUM(TRACE_CODE_HDD_P2P_DEV_ADDR_IOCTL) \ + ENUM(TRACE_CODE_HDD_SETSUSPENDMODE_IOCTL) \ + ENUM(TRACE_CODE_HDD_SETROAMTRIGGER_IOCTL) \ + ENUM(TRACE_CODE_HDD_GETROAMTRIGGER_IOCTL) \ + ENUM(TRACE_CODE_HDD_SETROAMSCANPERIOD_IOCTL) \ + ENUM(TRACE_CODE_HDD_GETROAMSCANPERIOD_IOCTL) \ + ENUM(TRACE_CODE_HDD_SETROAMDELTA_IOCTL) \ + ENUM(TRACE_CODE_HDD_GETROAMDELTA_IOCTL) \ + ENUM(TRACE_CODE_HDD_GETBAND_IOCTL) \ + ENUM(TRACE_CODE_HDD_GETCOUNTRYREV_IOCTL) \ + ENUM(TRACE_CODE_HDD_SETROAMSCANCHANNELS_IOCTL) \ + ENUM(TRACE_CODE_HDD_GETROAMSCANCHANNELS_IOCTL) \ + ENUM(TRACE_CODE_HDD_HOSTAPD_OPEN_REQUEST) \ + ENUM(TRACE_CODE_HDD_HOSTAPD_STOP_REQUEST) \ + ENUM(TRACE_CODE_HDD_HOSTAPD_UNINIT_REQUEST) \ + ENUM(TRACE_CODE_HDD_SOFTAP_TX_TIMEOUT) \ + ENUM(TRACE_CODE_HDD_HOSTAPD_SET_MAC_ADDR) \ + ENUM(TRACE_CODE_HDD_HOSTAPD_P2P_SET_NOA_IOCTL) \ + ENUM(TRACE_CODE_HDD_HOSTAPD_P2P_SET_PS_IOCTL) \ + ENUM(TRACE_CODE_HDD_HOSTAPD_SET_SAP_CHANNEL_LIST_IOCTL) \ + ENUM(TRACE_CODE_HDD_ADD_VIRTUAL_INTF) \ + ENUM(TRACE_CODE_HDD_DEL_VIRTUAL_INTF) \ + ENUM(TRACE_CODE_HDD_CHANGE_VIRTUAL_INTF) \ + ENUM(TRACE_CODE_HDD_CFG80211_START_AP) \ + ENUM(TRACE_CODE_HDD_CFG80211_CHANGE_BEACON) \ + ENUM(TRACE_CODE_HDD_CFG80211_STOP_AP) \ + ENUM(TRACE_CODE_HDD_CFG80211_CHANGE_BSS) \ + ENUM(TRACE_CODE_HDD_CFG80211_ADD_KEY) \ + ENUM(TRACE_CODE_HDD_CFG80211_GET_KEY) \ + ENUM(TRACE_CODE_HDD_CFG80211_SET_DEFAULT_KEY) \ + ENUM(TRACE_CODE_HDD_CFG80211_CONNECT) \ + ENUM(TRACE_CODE_HDD_CFG80211_DISCONNECT) \ + ENUM(TRACE_CODE_HDD_CFG80211_JOIN_IBSS) \ + ENUM(TRACE_CODE_HDD_CFG80211_LEAVE_IBSS) \ + ENUM(TRACE_CODE_HDD_CFG80211_SET_WIPHY_PARAMS) \ + ENUM(TRACE_CODE_HDD_CFG80211_SET_TXPOWER) \ + ENUM(TRACE_CODE_HDD_CFG80211_GET_TXPOWER) \ + ENUM(TRACE_CODE_HDD_CFG80211_SET_CHANNEL) \ + ENUM(TRACE_CODE_HDD_CFG80211_ADD_BEACON) \ + ENUM(TRACE_CODE_HDD_CFG80211_SET_BEACON) \ + ENUM(TRACE_CODE_HDD_CFG80211_CHANGE_IFACE) \ + ENUM(TRACE_CODE_HDD_CHANGE_STATION) \ + ENUM(TRACE_CODE_HDD_CFG80211_UPDATE_BSS) \ + ENUM(TRACE_CODE_HDD_CFG80211_SCAN) \ + ENUM(TRACE_CODE_HDD_REMAIN_ON_CHANNEL) \ + ENUM(TRACE_CODE_HDD_REMAINCHANREADYHANDLER) \ + ENUM(TRACE_CODE_HDD_CFG80211_CANCEL_REMAIN_ON_CHANNEL) \ + ENUM(TRACE_CODE_HDD_ACTION) \ + ENUM(TRACE_CODE_HDD_MGMT_TX_CANCEL_WAIT) \ + ENUM(TRACE_CODE_HDD_CFG80211_GET_STA) \ + ENUM(TRACE_CODE_HDD_CFG80211_SET_POWER_MGMT) \ + ENUM(TRACE_CODE_HDD_CFG80211_DEL_STA) \ + ENUM(TRACE_CODE_HDD_CFG80211_ADD_STA) \ + ENUM(TRACE_CODE_HDD_CFG80211_SET_PMKSA) \ + ENUM(TRACE_CODE_HDD_CFG80211_UPDATE_FT_IES) \ + ENUM(TRACE_CODE_HDD_CFG80211_TDLS_MGMT) \ + ENUM(TRACE_CODE_HDD_CFG80211_TDLS_OPER) \ + ENUM(TRACE_CODE_HDD_CFG80211_SET_REKEY_DATA) \ + ENUM(TRACE_CODE_HDD_UNSUPPORTED_IOCTL) \ + ENUM(TRACE_CODE_HDD_SETROAMSCANCHANNELMINTIME_IOCTL) \ + ENUM(TRACE_CODE_HDD_GETROAMSCANCHANNELMINTIME_IOCTL) \ + ENUM(TRACE_CODE_HDD_STORE_JOIN_REQ) \ + ENUM(TRACE_CODE_HDD_CLEAR_JOIN_REQ) \ + ENUM(TRACE_CODE_HDD_ISSUE_JOIN_REQ) \ + ENUM(TRACE_CODE_HDD_CFG80211_RESUME_WLAN) \ + ENUM(TRACE_CODE_HDD_CFG80211_SUSPEND_WLAN) \ + ENUM(TRACE_CODE_HDD_CFG80211_SET_MAC_ACL) \ + ENUM(TRACE_CODE_HDD_CFG80211_TESTMODE) \ + ENUM(TRACE_CODE_HDD_CFG80211_DUMP_SURVEY) \ + ENUM(TRACE_CODE_HDD_CFG80211_SCHED_SCAN_START) \ + ENUM(TRACE_CODE_HDD_CFG80211_SCHED_SCAN_STOP) \ + ENUM(TRACE_CODE_HDD_CFG80211_DEL_PMKSA) \ + /* + * New CFG80211 enums to be added before this comment. + * TRACE_CODE_HDD_RX_SME_MSG is used as code for MTRACE commands. + */ \ + ENUM(TRACE_CODE_HDD_RX_SME_MSG) + +enum { +#undef ENUM +#define ENUM(enum) enum, + ENUMS +}; + +/** + * hdd_trace_event_string() - Convert trace event to string + * @code: trace event enumeration to convert + * + * Return: string representation of the input enumeration + */ +static inline const char *hdd_trace_event_string(uint32_t code) +{ + switch (code) { + default: + return "UNKNOWN"; + break; +#undef ENUM +#define ENUM(enum) CASE_RETURN_STRING(enum) + ENUMS + } +} + +#undef ENUMS +#undef ENUM + +#ifdef HDD_TRACE_RECORD +void hdd_trace_init(void); +#else +static inline void hdd_trace_init(void) {} +#endif + +#endif diff --git a/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_tsf.h b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_tsf.h new file mode 100644 index 0000000000000000000000000000000000000000..45e25223a50588d8b047cd4715c382dbbededb2d --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_tsf.h @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#if !defined WLAN_HDD_TSF_H +#define WLAN_HDD_TSF_H + +/** + * enum hdd_tsf_get_state - status of get tsf action + * @TSF_RETURN: get tsf + * @TSF_STA_NOT_CONNECTED_NO_TSF: sta not connected to ap + * @TSF_NOT_RETURNED_BY_FW: fw not returned tsf + * @TSF_CURRENT_IN_CAP_STATE: driver in capture state + * @TSF_CAPTURE_FAIL: capture fail + * @TSF_GET_FAIL: get fail + * @TSF_RESET_GPIO_FAIL: GPIO reset fail + * @TSF_SAP_NOT_STARTED_NO_TSF SAP not started + */ +enum hdd_tsf_get_state { + TSF_RETURN = 0, + TSF_STA_NOT_CONNECTED_NO_TSF, + TSF_NOT_RETURNED_BY_FW, + TSF_CURRENT_IN_CAP_STATE, + TSF_CAPTURE_FAIL, + TSF_GET_FAIL, + TSF_RESET_GPIO_FAIL, + TSF_SAP_NOT_STARTED_NO_TSF +}; + +/** + * enum hdd_tsf_capture_state - status of capture + * @TSF_IDLE: idle + * @TSF_CAP_STATE: current is in capture state + */ +enum hdd_tsf_capture_state { + TSF_IDLE = 0, + TSF_CAP_STATE +}; + +#ifdef WLAN_FEATURE_TSF +void wlan_hdd_tsf_init(struct hdd_context_s *hdd_ctx); +int hdd_capture_tsf(struct hdd_adapter_s *adapter, uint32_t *buf, int len); +int hdd_indicate_tsf(struct hdd_adapter_s *adapter, uint32_t *buf, int len); +int wlan_hdd_cfg80211_handle_tsf_cmd(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len); +int hdd_get_tsf_cb(void *pcb_cxt, struct stsf *ptsf); +#else +static inline void wlan_hdd_tsf_init(struct hdd_context_s *hdd_ctx) +{ + return; +} + +static inline int hdd_indicate_tsf(struct hdd_adapter_s *adapter, uint32_t *buf, + int len) +{ + return -ENOTSUPP; +} + +static inline int +hdd_capture_tsf(struct hdd_adapter_s *adapter, uint32_t *buf, int len) +{ + return -ENOTSUPP; +} + +static inline int wlan_hdd_cfg80211_handle_tsf_cmd(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + return -ENOTSUPP; +} +static inline int hdd_get_tsf_cb(void *pcb_cxt, struct stsf *ptsf) +{ + return -ENOTSUPP; +} + +#endif + +#endif diff --git a/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_tx_rx.h b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_tx_rx.h new file mode 100644 index 0000000000000000000000000000000000000000..9ce5214f250c70243bde949eccff68e3043e8cf3 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_tx_rx.h @@ -0,0 +1,155 @@ +/* + * Copyright (c) 2013-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#if !defined(WLAN_HDD_TX_RX_H) +#define WLAN_HDD_TX_RX_H + +/** + * + * DOC: wlan_hdd_tx_rx.h + * + * Linux HDD Tx/RX APIs + */ + +#include +#include +#include +#include "ol_txrx_osif_api.h" +#include "cdp_txrx_flow_ctrl_legacy.h" + +#define HDD_ETHERTYPE_802_1_X 0x888E +#define HDD_ETHERTYPE_802_1_X_FRAME_OFFSET 12 +#ifdef FEATURE_WLAN_WAPI +#define HDD_ETHERTYPE_WAI 0x88b4 +#endif + +#define HDD_PSB_CFG_INVALID 0xFF +#define HDD_PSB_CHANGED 0xFF +#define SME_QOS_UAPSD_CFG_BK_CHANGED_MASK 0xF1 +#define SME_QOS_UAPSD_CFG_BE_CHANGED_MASK 0xF2 +#define SME_QOS_UAPSD_CFG_VI_CHANGED_MASK 0xF4 +#define SME_QOS_UAPSD_CFG_VO_CHANGED_MASK 0xF8 + +int hdd_hard_start_xmit(struct sk_buff *skb, struct net_device *dev); +void hdd_tx_timeout(struct net_device *dev); + +QDF_STATUS hdd_init_tx_rx(hdd_adapter_t *pAdapter); +QDF_STATUS hdd_deinit_tx_rx(hdd_adapter_t *pAdapter); +QDF_STATUS hdd_rx_packet_cbk(void *context, qdf_nbuf_t rxBuf); + +#ifdef IPA_OFFLOAD +QDF_STATUS hdd_rx_mul_packet_cbk(void *cds_context, + qdf_nbuf_t rx_buf_list, uint8_t staId); +#endif /* IPA_OFFLOAD */ + +QDF_STATUS hdd_get_peer_sta_id(hdd_station_ctx_t *sta_ctx, + struct qdf_mac_addr *peer_mac_addr, + uint8_t *sta_id); + +#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL +void hdd_tx_resume_cb(void *adapter_context, bool tx_resume); +void hdd_tx_resume_timer_expired_handler(void *adapter_context); +void hdd_register_tx_flow_control(hdd_adapter_t *adapter, + qdf_mc_timer_callback_t timer_callback, + ol_txrx_tx_flow_control_fp flowControl); +void hdd_deregister_tx_flow_control(hdd_adapter_t *adapter); +void hdd_get_tx_resource(hdd_adapter_t *adapter, + uint8_t STAId, uint16_t timer_value); + +#else +static inline void hdd_tx_resume_cb(void *adapter_context, bool tx_resume) +{ + return; +} +static inline void hdd_tx_resume_timer_expired_handler(void *adapter_context) +{ + return; +} +static inline void hdd_register_tx_flow_control(hdd_adapter_t *adapter, + qdf_mc_timer_callback_t timer_callback, + ol_txrx_tx_flow_control_fp flowControl) +{ + return; +} +static inline void hdd_deregister_tx_flow_control(hdd_adapter_t *adapter) +{ + return; +} +static inline void hdd_get_tx_resource(hdd_adapter_t *adapter, + uint8_t STAId, uint16_t timer_value) +{ + return; +} +#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */ + +int hdd_get_peer_idx(hdd_station_ctx_t *sta_ctx, struct qdf_mac_addr *addr); + +const char *hdd_reason_type_to_string(enum netif_reason_type reason); +const char *hdd_action_type_to_string(enum netif_action_type action); +void wlan_hdd_netif_queue_control(hdd_adapter_t *adapter, + enum netif_action_type action, enum netif_reason_type reason); +int hdd_set_mon_rx_cb(struct net_device *dev); +void hdd_send_rps_ind(hdd_adapter_t *adapter); +void hdd_send_rps_disable_ind(hdd_adapter_t *adapter); +void wlan_hdd_classify_pkt(struct sk_buff *skb); + +#ifdef MSM_PLATFORM +void hdd_reset_tcp_delack(hdd_context_t *hdd_ctx); +#else +static inline void hdd_reset_tcp_delack(hdd_context_t *hdd_ctx) {} +#endif + +#ifdef FEATURE_WLAN_DIAG_SUPPORT +void hdd_event_eapol_log(struct sk_buff *skb, enum qdf_proto_dir dir); +#else +static inline +void hdd_event_eapol_log(struct sk_buff *skb, enum qdf_proto_dir dir) +{} +#endif + +/* + * As of the 4.7 kernel, net_device->trans_start is removed. Create shims to + * support compiling against older versions of the kernel. + */ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 7, 0)) +static inline void netif_trans_update(struct net_device *dev) +{ + dev->trans_start = jiffies; +} + +#define TX_TIMEOUT_TRACE(dev, module_id) QDF_TRACE( \ + module_id, QDF_TRACE_LEVEL_ERROR, \ + "%s: Transmission timeout occurred jiffies %lu trans_start %lu", \ + __func__, jiffies, dev->trans_start) +#else +#define TX_TIMEOUT_TRACE(dev, module_id) QDF_TRACE( \ + module_id, QDF_TRACE_LEVEL_ERROR, \ + "%s: Transmission timeout occurred jiffies %lu", \ + __func__, jiffies) +#endif + +#endif /* end #if !defined(WLAN_HDD_TX_RX_H) */ diff --git a/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_wext.h b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_wext.h new file mode 100644 index 0000000000000000000000000000000000000000..63362319b3e447dd0cf22bd7f2d709d393c9371a --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_wext.h @@ -0,0 +1,388 @@ +/* + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef __WEXT_IW_H__ +#define __WEXT_IW_H__ + +#include +#include +#include +#include +#include +#include +#include "qdf_event.h" + +/* + * order of parameters in addTs private ioctl + */ +#define HDD_WLAN_WMM_PARAM_HANDLE 0 +#define HDD_WLAN_WMM_PARAM_TID 1 +#define HDD_WLAN_WMM_PARAM_DIRECTION 2 +#define HDD_WLAN_WMM_PARAM_APSD 3 +#define HDD_WLAN_WMM_PARAM_USER_PRIORITY 4 +#define HDD_WLAN_WMM_PARAM_NOMINAL_MSDU_SIZE 5 +#define HDD_WLAN_WMM_PARAM_MAXIMUM_MSDU_SIZE 6 +#define HDD_WLAN_WMM_PARAM_MINIMUM_DATA_RATE 7 +#define HDD_WLAN_WMM_PARAM_MEAN_DATA_RATE 8 +#define HDD_WLAN_WMM_PARAM_PEAK_DATA_RATE 9 +#define HDD_WLAN_WMM_PARAM_MAX_BURST_SIZE 10 +#define HDD_WLAN_WMM_PARAM_MINIMUM_PHY_RATE 11 +#define HDD_WLAN_WMM_PARAM_SURPLUS_BANDWIDTH_ALLOWANCE 12 +#define HDD_WLAN_WMM_PARAM_SERVICE_INTERVAL 13 +#define HDD_WLAN_WMM_PARAM_SUSPENSION_INTERVAL 14 +#define HDD_WLAN_WMM_PARAM_BURST_SIZE_DEFN 15 +#define HDD_WLAN_WMM_PARAM_ACK_POLICY 16 +#define HDD_WLAN_WMM_PARAM_INACTIVITY_INTERVAL 17 +#define HDD_WLAN_WMM_PARAM_MAX_SERVICE_INTERVAL 18 +#define HDD_WLAN_WMM_PARAM_COUNT 19 + +#define MHZ 6 + +#define WE_MAX_STR_LEN IW_PRIV_SIZE_MASK +#define WLAN_HDD_UI_BAND_AUTO 0 +#define WLAN_HDD_UI_BAND_5_GHZ 1 +#define WLAN_HDD_UI_BAND_2_4_GHZ 2 +/* SETBAND x */ +/* 012345678 */ +#define WLAN_HDD_UI_SET_BAND_VALUE_OFFSET 8 + +typedef enum { + HDD_WLAN_WMM_DIRECTION_UPSTREAM = 0, + HDD_WLAN_WMM_DIRECTION_DOWNSTREAM = 1, + HDD_WLAN_WMM_DIRECTION_BIDIRECTIONAL = 2, +} hdd_wlan_wmm_direction_e; + +typedef enum { + HDD_WLAN_WMM_POWER_SAVE_LEGACY = 0, + HDD_WLAN_WMM_POWER_SAVE_UAPSD = 1, +} hdd_wlan_wmm_power_save_e; + +typedef enum { + /* TSPEC/re-assoc done, async */ + HDD_WLAN_WMM_STATUS_SETUP_SUCCESS = 0, + /* no need to setup TSPEC since ACM=0 and no UAPSD desired, sync + async */ + HDD_WLAN_WMM_STATUS_SETUP_SUCCESS_NO_ACM_NO_UAPSD = 1, + /* no need to setup TSPEC since ACM=0 and UAPSD already exists, sync + async */ + HDD_WLAN_WMM_STATUS_SETUP_SUCCESS_NO_ACM_UAPSD_EXISTING = 2, + /* TSPEC result pending, sync */ + HDD_WLAN_WMM_STATUS_SETUP_PENDING = 3, + /* TSPEC/re-assoc failed, sync + async */ + HDD_WLAN_WMM_STATUS_SETUP_FAILED = 4, + /* Request rejected due to invalid params, sync + async */ + HDD_WLAN_WMM_STATUS_SETUP_FAILED_BAD_PARAM = 5, + /* TSPEC request rejected since AP!=QAP, sync */ + HDD_WLAN_WMM_STATUS_SETUP_FAILED_NO_WMM = 6, + + /* TSPEC modification/re-assoc successful, async */ + HDD_WLAN_WMM_STATUS_MODIFY_SUCCESS = 7, + /* TSPEC modification a no-op since ACM=0 and no change in UAPSD, sync + async */ + HDD_WLAN_WMM_STATUS_MODIFY_SUCCESS_NO_ACM_NO_UAPSD = 8, + /* TSPEC modification a no-op since ACM=0 and requested U-APSD already exists, sync + async */ + HDD_WLAN_WMM_STATUS_MODIFY_SUCCESS_NO_ACM_UAPSD_EXISTING = 9, + /* TSPEC result pending, sync */ + HDD_WLAN_WMM_STATUS_MODIFY_PENDING = 10, + /* TSPEC modification failed, prev TSPEC in effect, sync + async */ + HDD_WLAN_WMM_STATUS_MODIFY_FAILED = 11, + /* TSPEC modification request rejected due to invalid params, sync + async */ + HDD_WLAN_WMM_STATUS_MODIFY_FAILED_BAD_PARAM = 12, + + /* TSPEC release successful, sync and also async */ + HDD_WLAN_WMM_STATUS_RELEASE_SUCCESS = 13, + /* TSPEC release pending, sync */ + HDD_WLAN_WMM_STATUS_RELEASE_PENDING = 14, + /* TSPEC release failed, sync + async */ + HDD_WLAN_WMM_STATUS_RELEASE_FAILED = 15, + /* TSPEC release rejected due to invalid params, sync */ + HDD_WLAN_WMM_STATUS_RELEASE_FAILED_BAD_PARAM = 16, + /* TSPEC modified due to the mux'ing of requests on ACs, async */ + + HDD_WLAN_WMM_STATUS_MODIFIED = 17, + /* TSPEC revoked by AP, async */ + HDD_WLAN_WMM_STATUS_LOST = 18, + /* some internal failure like memory allocation failure, etc, sync */ + HDD_WLAN_WMM_STATUS_INTERNAL_FAILURE = 19, + + /* U-APSD failed during setup but OTA setup (whether TSPEC exchnage or */ + /* re-assoc) was done so app should release this QoS, async */ + HDD_WLAN_WMM_STATUS_SETUP_UAPSD_SET_FAILED = 20, + /* U-APSD failed during modify, but OTA setup (whether TSPEC exchnage or */ + /* re-assoc) was done so app should release this QoS, async */ + HDD_WLAN_WMM_STATUS_MODIFY_UAPSD_SET_FAILED = 21 +} hdd_wlan_wmm_status_e; + +/** TS Info Ack Policy */ +typedef enum { + HDD_WLAN_WMM_TS_INFO_ACK_POLICY_NORMAL_ACK = 0, + HDD_WLAN_WMM_TS_INFO_ACK_POLICY_HT_IMMEDIATE_BLOCK_ACK = 1, +} hdd_wlan_wmm_ts_info_ack_policy_e; + +/** Maximum Length of WPA/RSN IE */ +#define MAX_WPA_RSN_IE_LEN 40 + +/** Enable 11d */ +#define ENABLE_11D 1 + +/** Disable 11d */ +#define DISABLE_11D 0 + +/* + refer wpa.h in wpa supplicant code for REASON_MICHAEL_MIC_FAILURE + + supplicant sets REASON_MICHAEL_MIC_FAILURE as the reason code when it sends the MLME deauth IOCTL + for TKIP counter measures + */ +#define HDD_REASON_MICHAEL_MIC_FAILURE 14 + +/* + * These are for TLV fields in WPS IE + */ +#define HDD_WPS_UUID_LEN 16 +#define HDD_WPS_ELEM_VERSION 0x104a +#define HDD_WPS_ELEM_REQUEST_TYPE 0x103a +#define HDD_WPS_ELEM_CONFIG_METHODS 0x1008 +#define HDD_WPS_ELEM_UUID_E 0x1047 +#define HDD_WPS_ELEM_PRIMARY_DEVICE_TYPE 0x1054 +#define HDD_WPS_ELEM_RF_BANDS 0x103c +#define HDD_WPS_ELEM_ASSOCIATION_STATE 0x1002 +#define HDD_WPS_ELEM_CONFIGURATION_ERROR 0x1009 +#define HDD_WPS_ELEM_DEVICE_PASSWORD_ID 0x1012 + +#define HDD_WPA_ELEM_VENDOR_EXTENSION 0x1049 + +#define HDD_WPS_MANUFACTURER_LEN 64 +#define HDD_WPS_MODEL_NAME_LEN 32 +#define HDD_WPS_MODEL_NUM_LEN 32 +#define HDD_WPS_SERIAL_NUM_LEN 32 +#define HDD_WPS_DEVICE_OUI_LEN 4 +#define HDD_WPS_DEVICE_NAME_LEN 32 + +#define HDD_WPS_ELEM_WPS_STATE 0x1044 +#define HDD_WPS_ELEM_APSETUPLOCK 0x1057 +#define HDD_WPS_ELEM_SELECTEDREGISTRA 0x1041 +#define HDD_WPS_ELEM_RSP_TYPE 0x103B +#define HDD_WPS_ELEM_MANUFACTURER 0x1021 +#define HDD_WPS_ELEM_MODEL_NAME 0x1023 +#define HDD_WPS_ELEM_MODEL_NUM 0x1024 +#define HDD_WPS_ELEM_SERIAL_NUM 0x1042 +#define HDD_WPS_ELEM_DEVICE_NAME 0x1011 +#define HDD_WPS_ELEM_REGISTRA_CONF_METHODS 0x1053 + +#define HDD_RTSCTS_EN_MASK 0xF +#define HDD_RTSCTS_ENABLE 1 +#define HDD_CTS_ENABLE 2 + +#define WPS_OUI_TYPE "\x00\x50\xf2\x04" +#define WPS_OUI_TYPE_SIZE 4 + +#define SS_OUI_TYPE "\x00\x16\x32" +#define SS_OUI_TYPE_SIZE 3 + +#define P2P_OUI_TYPE "\x50\x6f\x9a\x09" +#define P2P_OUI_TYPE_SIZE 4 + +#define HS20_OUI_TYPE "\x50\x6f\x9a\x10" +#define HS20_OUI_TYPE_SIZE 4 + +#define OSEN_OUI_TYPE "\x50\x6f\x9a\x12" +#define OSEN_OUI_TYPE_SIZE 4 + +#ifdef WLAN_FEATURE_WFD +#define WFD_OUI_TYPE "\x50\x6f\x9a\x0a" +#define WFD_OUI_TYPE_SIZE 4 +#endif + +#define MBO_OUI_TYPE "\x50\x6f\x9a\x16" +#define MBO_OUI_TYPE_SIZE 4 + +typedef enum { + eWEXT_WPS_OFF = 0, + eWEXT_WPS_ON = 1, +} hdd_wps_mode_e; + +/* + * This structure contains the interface level (granularity) + * configuration information in support of wireless extensions. + */ +typedef struct hdd_wext_state_s { + /** The CSR "desired" Profile */ + tCsrRoamProfile roamProfile; + + /** BSSID to which connect request is received */ + struct qdf_mac_addr req_bssId; + + /** The association status code */ + uint32_t statusCode; + + /** wpa version WPA/WPA2/None*/ + int32_t wpaVersion; + + /**WPA or RSN IE*/ + uint8_t WPARSNIE[MAX_WPA_RSN_IE_LEN]; + + /**gen IE */ + tSirAddie genIE; + + /**Additional IE for assoc */ + tSirAddie assocAddIE; + + /**auth key mgmt */ + int32_t authKeyMgmt; + + /* qdf event */ + qdf_event_t hdd_qdf_event; + + qdf_event_t scanevent; + + /**Counter measure state, Started/Stopped*/ + bool mTKIPCounterMeasures; + + /**Completion Variable*/ + struct completion completion_var; + +#ifdef FEATURE_WLAN_ESE + /* ESE state variables */ + bool isESEConnection; + eCsrAuthType collectedAuthType; /* Collected from ALL SIOCSIWAUTH Ioctls. Will be negotiatedAuthType - in tCsrProfile */ +#endif +} hdd_wext_state_t; + +typedef struct ccp_freq_chan_map_s { + /* List of frequencies */ + uint32_t freq; + uint32_t chan; +} hdd_freq_chan_map_t; + +/* Packet Types. */ +#define WLAN_KEEP_ALIVE_UNSOLICIT_ARP_RSP 2 +#define WLAN_KEEP_ALIVE_NULL_PKT 1 + +#define wlan_hdd_get_wps_ie_ptr(ie, ie_len) \ + wlan_hdd_get_vendor_oui_ie_ptr(WPS_OUI_TYPE, WPS_OUI_TYPE_SIZE, ie, ie_len) + +#define wlan_hdd_get_p2p_ie_ptr(ie, ie_len) \ + wlan_hdd_get_vendor_oui_ie_ptr(P2P_OUI_TYPE, P2P_OUI_TYPE_SIZE, ie, ie_len) + +#ifdef WLAN_FEATURE_WFD +#define wlan_hdd_get_wfd_ie_ptr(ie, ie_len) \ + wlan_hdd_get_vendor_oui_ie_ptr(WFD_OUI_TYPE, WFD_OUI_TYPE_SIZE, ie, ie_len) +#endif + +#define wlan_hdd_get_mbo_ie_ptr(ie, ie_len) \ + wlan_hdd_get_vendor_oui_ie_ptr(MBO_OUI_TYPE, MBO_OUI_TYPE_SIZE, ie, ie_len) +/* + * Defines for fw_test command + */ +#define HDD_FWTEST_PARAMS 3 +#define HDD_FWTEST_SU_PARAM_ID 53 +#define HDD_FWTEST_MU_PARAM_ID 2 +#define HDD_FWTEST_SU_DEFAULT_VALUE 100 +#define HDD_FWTEST_MU_DEFAULT_VALUE 40 +#define HDD_FWTEST_MAX_VALUE 500 + +extern int hdd_unregister_wext(struct net_device *dev); +extern int hdd_register_wext(struct net_device *dev); +extern int hdd_wlan_get_freq(uint32_t chan, uint32_t *freq); +extern int hdd_wlan_get_rts_threshold(hdd_adapter_t *pAdapter, + union iwreq_data *wrqu); +extern int hdd_wlan_get_frag_threshold(hdd_adapter_t *pAdapter, + union iwreq_data *wrqu); +extern void hdd_display_stats_help(void); +extern void hdd_wlan_get_version(hdd_context_t *hdd_ctx, + union iwreq_data *wrqu, char *extra); + +extern void hdd_wlan_get_stats(hdd_adapter_t *pAdapter, uint16_t *length, + char *buffer, uint16_t buf_len); +extern void hdd_wlan_list_fw_profile(uint16_t *length, + char *buffer, uint16_t buf_len); + +extern int iw_set_essid(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra); + +extern int iw_get_essid(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *dwrq, char *extra); + +extern int iw_set_ap_address(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra); + +extern int iw_get_ap_address(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra); + +extern int iw_set_auth(struct net_device *dev, struct iw_request_info *info, + union iwreq_data *wrqu, char *extra); + +extern int iw_get_auth(struct net_device *dev, struct iw_request_info *info, + union iwreq_data *wrqu, char *extra); + +extern int iw_set_var_ints_getnone(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra); + +extern int iw_set_three_ints_getnone(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra); + +extern int hdd_priv_get_data(struct iw_point *p_priv_data, + union iwreq_data *wrqu); + +extern void *mem_alloc_copy_from_user_helper(const void *wrqu_data, size_t len); + +int wlan_hdd_get_linkspeed_for_peermac(hdd_adapter_t *pAdapter, + struct qdf_mac_addr mac_address); +void hdd_clear_roam_profile_ie(hdd_adapter_t *pAdapter); + +uint8_t *wlan_hdd_get_vendor_oui_ie_ptr(uint8_t *oui, uint8_t oui_size, + uint8_t *ie, int ie_len); + +QDF_STATUS wlan_hdd_get_class_astats(hdd_adapter_t *pAdapter); + +QDF_STATUS wlan_hdd_get_station_stats(hdd_adapter_t *pAdapter); + +QDF_STATUS wlan_hdd_get_rssi(hdd_adapter_t *pAdapter, int8_t *rssi_value); + +QDF_STATUS wlan_hdd_get_snr(hdd_adapter_t *pAdapter, int8_t *snr); + +int hdd_get_ldpc(hdd_adapter_t *adapter, int *value); +int hdd_set_ldpc(hdd_adapter_t *adapter, int value); +int hdd_get_tx_stbc(hdd_adapter_t *adapter, int *value); +int hdd_set_tx_stbc(hdd_adapter_t *adapter, int value); +int hdd_get_rx_stbc(hdd_adapter_t *adapter, int *value); +int hdd_set_rx_stbc(hdd_adapter_t *adapter, int value); + +void wlan_hdd_change_country_code_callback(void *pAdapter); + +int hdd_set_band(struct net_device *dev, u8 ui_band); +int hdd_set_band_helper(struct net_device *dev, const char *command); +int wlan_hdd_update_phymode(struct net_device *net, tHalHandle hal, + int new_phymode, hdd_context_t *phddctx); + +int wlan_hdd_get_temperature(hdd_adapter_t *pAdapter, int *temperature); +int wlan_hdd_get_link_speed(hdd_adapter_t *sta_adapter, uint32_t *link_speed); +#endif /* __WEXT_IW_H__ */ diff --git a/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_wmm.h b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_wmm.h new file mode 100644 index 0000000000000000000000000000000000000000..3944386cfe66ca767e5fa2da503de69e0ad0260e --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_wmm.h @@ -0,0 +1,401 @@ +/* + * Copyright (c) 2011-2012,2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef _WLAN_HDD_WMM_H +#define _WLAN_HDD_WMM_H + +/** + * DOC: HDD WMM + * + * This module (wlan_hdd_wmm.h interface + wlan_hdd_wmm.c implementation) + * houses all the logic for WMM in HDD. + * + * On the control path, it has the logic to setup QoS, modify QoS and delete + * QoS (QoS here refers to a TSPEC). The setup QoS comes in two flavors: an + * explicit application invoked and an internal HDD invoked. The implicit QoS + * is for applications that do NOT call the custom QCT WLAN OIDs for QoS but + * which DO mark their traffic for priortization. It also has logic to start, + * update and stop the U-APSD trigger frame generation. It also has logic to + * read WMM related config parameters from the registry. + * + * On the data path, it has the logic to figure out the WMM AC of an egress + * packet and when to signal TL to serve a particular AC queue. It also has the + * logic to retrieve a packet based on WMM priority in response to a fetch from + * TL. + * + * The remaining functions are utility functions for information hiding. + */ + +/* Include files */ +#include +#include +#include +#include +#include + +/*Maximum number of ACs */ +#define WLAN_MAX_AC 4 + + +/* Preprocessor Definitions and Constants */ + +/* #define HDD_WMM_DEBUG 1 */ + +#define HDD_WMM_CTX_MAGIC 0x574d4d58 /* "WMMX" */ + +#define HDD_WMM_HANDLE_IMPLICIT 0xFFFFFFFF + +#define HDD_WLAN_INVALID_STA_ID 0xFF + +/* Type Declarations */ + +/** + * enum hdd_wmm_classification: types of classification supported + */ +typedef enum hdd_wmm_classification { + HDD_WMM_CLASSIFICATION_DSCP = 0, + HDD_WMM_CLASSIFICATION_802_1Q = 1 +} hdd_wmm_classification_t; + +/** + * enum hdd_wmm_user_mode - WMM modes of operation + * + * @HDD_WMM_USER_MODE_AUTO: STA can associate with any AP, & HDD looks at + * the SME notification after association to find out if associated + * with QAP and acts accordingly + * @HDD_WMM_USER_MODE_QBSS_ONLY - SME will add the extra logic to make sure + * STA associates with a QAP only + * @HDD_WMM_USER_MODE_NO_QOS - Join any AP, but uapsd is disabled + */ +typedef enum hdd_wmm_user_mode { + HDD_WMM_USER_MODE_AUTO = 0, + HDD_WMM_USER_MODE_QBSS_ONLY = 1, + HDD_WMM_USER_MODE_NO_QOS = 2, +} hdd_wmm_user_mode_t; + +/* UAPSD Mask bits */ +/* (Bit0:VO; Bit1:VI; Bit2:BK; Bit3:BE all other bits are ignored) */ +#define HDD_AC_VO 0x1 +#define HDD_AC_VI 0x2 +#define HDD_AC_BK 0x4 +#define HDD_AC_BE 0x8 + +/** + * struct hdd_wmm_qos_context - HDD WMM QoS Context + * + * This structure holds the context for a single flow which has either + * been confgured explicitly from userspace or implicitly via the + * Implicit QoS feature. + * + * @node: list node which can be used to put the context into a list + * of contexts + * @handle: identifer which uniquely identifies this context to userspace + * @qosFlowID: identifier which uniquely identifies this flow to SME + * @pAdapter: adapter upon which this flow was configured + * @acType: access category for this flow + * @lastStatus: the status of the last operation performed on this flow by SME + * @wmmAcSetupImplicitQos: work structure used for deferring implicit QoS work + * from softirq context to thread context + * @magic: magic number used to verify that this is a valid context when + * referenced anonymously + */ +typedef struct hdd_wmm_qos_context { + struct list_head node; + uint32_t handle; + uint32_t qosFlowId; + hdd_adapter_t *pAdapter; + sme_ac_enum_type acType; + hdd_wlan_wmm_status_e lastStatus; + struct work_struct wmmAcSetupImplicitQos; + uint32_t magic; + bool is_inactivity_timer_running; +} hdd_wmm_qos_context_t; + +/** + * struct hdd_wmm_ac_status - WMM related per-AC state & status info + * @wmmAcAccessRequired - does the AP require access to this AC? + * @wmmAcAccessNeeded - does the worker thread need to acquire access to + * this AC? + * @wmmAcAccessPending - is implicit QoS negotiation currently taking place? + * @wmmAcAccessFailed - has implicit QoS negotiation already failed? + * @wmmAcAccessGranted - has implicit QoS negotiation already succeeded? + * @wmmAcAccessAllowed - is access to this AC allowed, either because we + * are not doing WMM, we are not doing implicit QoS, implict QoS has + * completed, or explicit QoS has completed? + * @wmmAcTspecValid - is the wmmAcTspecInfo valid? + * @wmmAcUapsdInfoValid - are the wmmAcUapsd* fields valid? + * @wmmAcTspecInfo - current (possibly aggregate) Tspec for this AC + * @wmmAcIsUapsdEnabled - is UAPSD enabled on this AC? + * @wmmAcUapsdServiceInterval - service interval for this AC + * @wmmAcUapsdSuspensionInterval - suspension interval for this AC + * @wmmAcUapsdDirection - direction for this AC + * @wmmInactivityTime - inactivity time for this AC + * @wmmPrevTrafficCnt - TX counter used for inactivity detection + * @wmmInactivityTimer - timer used for inactivity detection + */ +typedef struct hdd_wmm_ac_status { + bool wmmAcAccessRequired; + bool wmmAcAccessNeeded; + bool wmmAcAccessPending; + bool wmmAcAccessFailed; + bool wmmAcAccessGranted; + bool wmmAcAccessAllowed; + bool wmmAcTspecValid; + bool wmmAcUapsdInfoValid; + sme_QosWmmTspecInfo wmmAcTspecInfo; + bool wmmAcIsUapsdEnabled; + uint32_t wmmAcUapsdServiceInterval; + uint32_t wmmAcUapsdSuspensionInterval; + sme_QosWmmDirType wmmAcUapsdDirection; + +#ifdef FEATURE_WLAN_ESE + uint32_t wmmInactivityTime; + uint32_t wmmPrevTrafficCnt; + qdf_mc_timer_t wmmInactivityTimer; +#endif + +} hdd_wmm_ac_status_t; + +/** + * struct hdd_wmm_status - WMM status maintained per-adapter + * @wmmContextList - list of WMM contexts active on the adapter + * @wmmLock - mutex used for exclusive access to this adapter's WMM status + * @wmmACStatus - per-AC WMM status + * @wmmQap - is this connected to a QoS-enabled AP? + * @wmmQosConnection - is this a QoS connection? + */ +typedef struct hdd_wmm_status { + struct list_head wmmContextList; + struct mutex wmmLock; + hdd_wmm_ac_status_t wmmAcStatus[WLAN_MAX_AC]; + bool wmmQap; + bool wmmQosConnection; +} hdd_wmm_status_t; + +extern const uint8_t hdd_qdisc_ac_to_tl_ac[]; +extern const uint8_t hdd_wmm_up_to_ac_map[]; +extern const uint8_t hdd_linux_up_to_ac_map[]; + +#define WLAN_HDD_MAX_DSCP 0x3f + +/** + * hdd_wmmps_helper() - Function to set uapsd psb dynamically + * + * @pAdapter: [in] pointer to adapter structure + * @ptr: [in] pointer to command buffer + * + * Return: Zero on success, appropriate error on failure. + */ +int hdd_wmmps_helper(hdd_adapter_t *pAdapter, uint8_t *ptr); + +/** + * hdd_wmm_init() - initialize the WMM DSCP configuation + * @pAdapter : [in] pointer to Adapter context + * + * This function will initialize the WMM DSCP configuation of an + * adapter to an initial state. The configuration can later be + * overwritten via application APIs or via QoS Map sent OTA. + * + * Return: QDF_STATUS enumeration + */ +QDF_STATUS hdd_wmm_init(hdd_adapter_t *pAdapter); + +/** + * hdd_wmm_adapter_init() - initialize the WMM configuration of an adapter + * @pAdapter: [in] pointer to Adapter context + * + * This function will initialize the WMM configuation and status of an + * adapter to an initial state. The configuration can later be + * overwritten via application APIs + * + * Return: QDF_STATUS enumeration + */ +QDF_STATUS hdd_wmm_adapter_init(hdd_adapter_t *pAdapter); + +/** + * hdd_wmm_close() - WMM close function + * @pAdapter: [in] pointer to adapter context + * + * Function which will perform any necessary work to to clean up the + * WMM functionality prior to the kernel module unload. + * + * Return: QDF_STATUS enumeration + */ +QDF_STATUS hdd_wmm_adapter_close(hdd_adapter_t *pAdapter); + +/** + * hdd_wmm_select_queue() - Function which will classify the packet + * according to linux qdisc expectation. + * + * @dev: [in] pointer to net_device structure + * @skb: [in] pointer to os packet + * + * Return: Qdisc queue index + */ +uint16_t hdd_wmm_select_queue(struct net_device *dev, struct sk_buff *skb); + +/** + * hdd_hostapd_select_queue() - Function which will classify the packet + * according to linux qdisc expectation. + * + * @dev: [in] pointer to net_device structure + * @skb: [in] pointer to os packet + * + * Return: Qdisc queue index + */ +uint16_t hdd_hostapd_select_queue(struct net_device *dev, struct sk_buff *skb +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0)) + , void *accel_priv +#endif +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) + , select_queue_fallback_t fallback +#endif +); + +/** + * hdd_wmm_acquire_access_required() - Function which will determine + * acquire admittance for a WMM AC is required or not based on psb configuration + * done in framework + * + * @pAdapter: [in] pointer to adapter structure + * @acType: [in] WMM AC type of OS packet + * + * Return: void + */ +void hdd_wmm_acquire_access_required(hdd_adapter_t *pAdapter, + sme_ac_enum_type acType); + +/** + * hdd_wmm_acquire_access() - Function which will attempt to acquire + * admittance for a WMM AC + * + * @pAdapter: [in] pointer to adapter context + * @acType: [in] WMM AC type of OS packet + * @pGranted: [out] pointer to bool flag when indicates if access + * has been granted or not + * + * Return: QDF_STATUS enumeration + */ +QDF_STATUS hdd_wmm_acquire_access(hdd_adapter_t *pAdapter, + sme_ac_enum_type acType, bool *pGranted); + +/** + * hdd_wmm_assoc() - Function which will handle the housekeeping + * required by WMM when association takes place + * + * @pAdapter: [in] pointer to adapter context + * @pRoamInfo: [in] pointer to roam information + * @eBssType: [in] type of BSS + * + * Return: QDF_STATUS enumeration + */ +QDF_STATUS hdd_wmm_assoc(hdd_adapter_t *pAdapter, + tCsrRoamInfo *pRoamInfo, eCsrRoamBssType eBssType); + +/** + * hdd_wmm_connect() - Function which will handle the housekeeping + * required by WMM when a connection is established + * + * @pAdapter : [in] pointer to adapter context + * @pRoamInfo: [in] pointer to roam information + * @eBssType : [in] type of BSS + * + * Return: QDF_STATUS enumeration + */ +QDF_STATUS hdd_wmm_connect(hdd_adapter_t *pAdapter, + tCsrRoamInfo *pRoamInfo, eCsrRoamBssType eBssType); + +/** + * hdd_wmm_get_uapsd_mask() - Function which will calculate the + * initial value of the UAPSD mask based upon the device configuration + * + * @pAdapter : [in] pointer to adapter context + * @pUapsdMask: [out] pointer to where the UAPSD Mask is to be stored + * + * Return: QDF_STATUS enumeration + */ +QDF_STATUS hdd_wmm_get_uapsd_mask(hdd_adapter_t *pAdapter, + uint8_t *pUapsdMask); + +/** + * hdd_wmm_is_active() - Function which will determine if WMM is + * active on the current connection + * + * @pAdapter: [in] pointer to adapter context + * + * Return: true if WMM is enabled, false if WMM is not enabled + */ +bool hdd_wmm_is_active(hdd_adapter_t *pAdapter); + +/** + * hdd_wmm_addts() - Function which will add a traffic spec at the + * request of an application + * + * @pAdapter : [in] pointer to adapter context + * @handle : [in] handle to uniquely identify a TS + * @pTspec : [in] pointer to the traffic spec + * + * Return: HDD_WLAN_WMM_STATUS_* + */ +hdd_wlan_wmm_status_e hdd_wmm_addts(hdd_adapter_t *pAdapter, + uint32_t handle, + sme_QosWmmTspecInfo *pTspec); + +/** + * hdd_wmm_delts() - Function which will delete a traffic spec at the + * request of an application + * + * @pAdapter: [in] pointer to adapter context + * @handle: [in] handle to uniquely identify a TS + * + * Return: HDD_WLAN_WMM_STATUS_* + */ +hdd_wlan_wmm_status_e hdd_wmm_delts(hdd_adapter_t *pAdapter, uint32_t handle); + +/** + * hdd_wmm_checkts() - Function which will return the status of a traffic + * spec at the request of an application + * + * @pAdapter: [in] pointer to adapter context + * @handle: [in] handle to uniquely identify a TS + * + * Return: HDD_WLAN_WMM_STATUS_* + */ +hdd_wlan_wmm_status_e hdd_wmm_checkts(hdd_adapter_t *pAdapter, + uint32_t handle); +/** + * hdd_wmm_adapter_clear() - Function which will clear the WMM status + * for all the ACs + * + * @pAdapter: [in] pointer to Adapter context + * + * Return: QDF_STATUS enumeration + */ +QDF_STATUS hdd_wmm_adapter_clear(hdd_adapter_t *pAdapter); + +void wlan_hdd_process_peer_unauthorised_pause(hdd_adapter_t *adapter); +#endif /* #ifndef _WLAN_HDD_WMM_H */ diff --git a/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_wowl.h b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_wowl.h new file mode 100644 index 0000000000000000000000000000000000000000..4697e74c95f941828d31644a9d33a00a3603950a --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_wowl.h @@ -0,0 +1,181 @@ +/* + * Copyright (c) 2013-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef _WLAN_HDD_WOWL_H +#define _WLAN_HDD_WOWL_H + +/** + * DOC: wlan_hdd_wowl + * + * This module houses all the logic for WOWL in HDD. + * + * It provides the following APIs + * + * - Ability to enable/disable following WoWL modes + * 1) Magic packet (MP) mode + * 2) Pattern Byte Matching (PBM) mode + * - Ability to add/remove patterns for PBM + * + * A Magic Packet is a packet that contains 6 0xFFs followed by 16 + * contiguous copies of the receiving NIC's Ethernet address. There is + * no API to configure Magic Packet Pattern. + * + * Wakeup pattern (used for PBM) is defined as following: + * typedef struct + * { + * U8 PatternSize; // Non-Zero pattern size + * U8 PatternMaskSize; // Non-zero pattern mask size + * U8 PatternMask[PatternMaskSize]; // Pattern mask + * U8 Pattern[PatternSize]; // Pattern + * } hdd_wowl_ptrn_t; + * + * PatternSize and PatternMaskSize indicate size of the variable + * length Pattern and PatternMask. PatternMask indicates which bytes + * of an incoming packet should be compared with corresponding bytes + * in the pattern. + * + * Maximum allowed pattern size is 128 bytes. Maximum allowed + * PatternMaskSize is 16 bytes. + * + * Maximum number of patterns that can be configured is 8 + * + * HDD will add following 2 commonly used patterns for PBM by default: + * 1) ARP Broadcast Pattern + * 2) Unicast Pattern + * + * However note that WoWL will not be enabled by default by HDD. WoWL + * needs to enabled explcitly by exercising the iwpriv command. + * + * HDD will expose an API that accepts patterns as Hex string in the + * following format: + * "PatternSize:PatternMaskSize:PatternMask:Pattern" + * + * Multiple patterns can be specified by deleimiting each pattern with + * the ';' token: + * "PatternSize1:PatternMaskSize1:PatternMask1:Pattern1;PatternSize2:..." + * + * Patterns can be configured dynamically via iwpriv cmd or statically + * via qcom_cfg.ini file + * + * PBM (when enabled) can perform filtering on unicast data or + * broadcast data or both. These configurations are part of factory + * defaults (cfg.dat) and the deafult behavior is to perform filtering + * on both unicast and data frames. + * + * MP filtering (when enabled) is performed ALWAYS on both unicast and + * broadcast data frames. + * + * Mangement frames are not subjected to WoWL filtering and are + * discarded when WoWL is enabled. + * + * Whenever a patern match succeeds, RX path is restored and packets + * (both management and data) will be pushed to the host from that + * point onwards. Therefore, exit from WoWL is implicit and happens + * automatically when the first packet match succeeds. + * + * WoWL works on top of BMPS. So when WoWL is requested, SME will + * attempt to put the device in BMPS mode (if not already in BMPS). If + * attempt to BMPS fails, request for WoWL will be rejected. + */ + +#include + +#define WOWL_PTRN_MAX_SIZE 146 +#define WOWL_PTRN_MASK_MAX_SIZE 19 +#define WOWL_MAX_PTRNS_ALLOWED CFG_MAX_WOW_FILTERS_MAX + +/** + * hdd_add_wowl_ptrn() - Function which will add the WoWL pattern to be + * used when PBM filtering is enabled + * @pAdapter: pointer to the adapter + * @ptrn: pointer to the pattern string to be added + * + * Return: false if any errors encountered, true otherwise + */ +bool hdd_add_wowl_ptrn(hdd_adapter_t *pAdapter, const char *ptrn); + +/** + * hdd_del_wowl_ptrn() - Function which will remove a WoWL pattern + * @pAdapter: pointer to the adapter + * @ptrn: pointer to the pattern string to be removed + * + * Return: false if any errors encountered, true otherwise + */ +bool hdd_del_wowl_ptrn(hdd_adapter_t *pAdapter, const char *ptrn); + +/** + * hdd_add_wowl_ptrn_debugfs() - Function which will add a WoW pattern + * sent from debugfs interface + * @pAdapter: pointer to the adapter + * @pattern_idx: index of the pattern to be added + * @pattern_offset: offset of the pattern in the frame payload + * @pattern_buf: pointer to the pattern hex string to be added + * @pattern_mask: pointer to the pattern mask hex string + * + * Return: false if any errors encountered, true otherwise + */ +bool hdd_add_wowl_ptrn_debugfs(hdd_adapter_t *pAdapter, uint8_t pattern_idx, + uint8_t pattern_offset, char *pattern_buf, + char *pattern_mask); + +/** + * hdd_del_wowl_ptrn_debugfs() - Function which will remove a WoW pattern + * sent from debugfs interface + * @pAdapter: pointer to the adapter + * @pattern_idx: index of the pattern to be removed + * + * Return: false if any errors encountered, true otherwise + */ +bool hdd_del_wowl_ptrn_debugfs(hdd_adapter_t *pAdapter, uint8_t pattern_idx); + +/** + * hdd_enter_wowl() - Function which will enable WoWL. At least one + * of MP and PBM must be enabled + * @pAdapter: pointer to the adapter + * @enable_mp: Whether to enable magic packet WoWL mode + * @enable_pbm: Whether to enable pattern byte matching WoWL mode + * + * Return: false if any errors encountered, true otherwise + */ +bool hdd_enter_wowl(hdd_adapter_t *pAdapter, bool enable_mp, bool enable_pbm); + +/** + * hdd_exit_wowl() - Function which will disable WoWL + * @pAdapter: pointer to the adapter + * + * Return: false if any errors encountered, true otherwise + */ +bool hdd_exit_wowl(hdd_adapter_t *pAdapter); + +/** + * hdd_deinit_wowl() - Deinit function to cleanup WoWL allocated memory + * + * Return: None + */ +void hdd_deinit_wowl(void); + +#endif /* #ifndef _WLAN_HDD_WOWL_H */ diff --git a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_assoc.c b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_assoc.c new file mode 100644 index 0000000000000000000000000000000000000000..93df509077b79e1c8755795f7470d4028f7f5b44 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_assoc.c @@ -0,0 +1,6293 @@ +/* + * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: wlan_hdd_assoc.c + * + * WLAN Host Device Driver implementation + * + */ + +#include "wlan_hdd_includes.h" +#include +#include "dot11f.h" +#include "wlan_hdd_power.h" +#include "wlan_hdd_trace.h" +#include +#include +#include +#include +#include "wlan_hdd_cfg80211.h" +#include "csr_inside_api.h" +#include "wlan_hdd_p2p.h" +#include "wlan_hdd_tdls.h" +#include "sme_api.h" +#include "wlan_hdd_hostapd.h" +#include +#include "wlan_hdd_lpass.h" +#include +#include "cds_concurrency.h" +#include +#include "sme_power_save_api.h" +#include "ol_txrx_ctrl_api.h" +#include "ol_txrx_types.h" +#include "ol_txrx.h" +#include "ol_rx_fwd.h" +#include "cdp_txrx_flow_ctrl_legacy.h" +#include "cdp_txrx_peer_ops.h" +#include "wlan_hdd_napi.h" +#include + +/* These are needed to recognize WPA and RSN suite types */ +#define HDD_WPA_OUI_SIZE 4 +#define HDD_RSN_OUI_SIZE 4 +uint8_t ccp_wpa_oui00[HDD_WPA_OUI_SIZE] = { 0x00, 0x50, 0xf2, 0x00 }; +uint8_t ccp_wpa_oui01[HDD_WPA_OUI_SIZE] = { 0x00, 0x50, 0xf2, 0x01 }; +uint8_t ccp_wpa_oui02[HDD_WPA_OUI_SIZE] = { 0x00, 0x50, 0xf2, 0x02 }; +uint8_t ccp_wpa_oui03[HDD_WPA_OUI_SIZE] = { 0x00, 0x50, 0xf2, 0x03 }; +uint8_t ccp_wpa_oui04[HDD_WPA_OUI_SIZE] = { 0x00, 0x50, 0xf2, 0x04 }; +uint8_t ccp_wpa_oui05[HDD_WPA_OUI_SIZE] = { 0x00, 0x50, 0xf2, 0x05 }; + +#ifdef FEATURE_WLAN_ESE +/* CCKM */ +uint8_t ccp_wpa_oui06[HDD_WPA_OUI_SIZE] = { 0x00, 0x40, 0x96, 0x00 }; +/* CCKM */ +uint8_t ccp_rsn_oui06[HDD_RSN_OUI_SIZE] = { 0x00, 0x40, 0x96, 0x00 }; +#endif /* FEATURE_WLAN_ESE */ + +/* group cipher */ +uint8_t ccp_rsn_oui00[HDD_RSN_OUI_SIZE] = { 0x00, 0x0F, 0xAC, 0x00 }; + +/* WEP-40 or RSN */ +uint8_t ccp_rsn_oui01[HDD_RSN_OUI_SIZE] = { 0x00, 0x0F, 0xAC, 0x01 }; + +/* TKIP or RSN-PSK */ +uint8_t ccp_rsn_oui02[HDD_RSN_OUI_SIZE] = { 0x00, 0x0F, 0xAC, 0x02 }; + +/* Reserved */ +uint8_t ccp_rsn_oui03[HDD_RSN_OUI_SIZE] = { 0x00, 0x0F, 0xAC, 0x03 }; + +/* AES-CCMP */ +uint8_t ccp_rsn_oui04[HDD_RSN_OUI_SIZE] = { 0x00, 0x0F, 0xAC, 0x04 }; + +/* WEP-104 */ +uint8_t ccp_rsn_oui05[HDD_RSN_OUI_SIZE] = { 0x00, 0x0F, 0xAC, 0x05 }; + +#ifdef WLAN_FEATURE_11W +/* RSN-PSK-SHA256 */ +uint8_t ccp_rsn_oui07[HDD_RSN_OUI_SIZE] = { 0x00, 0x0F, 0xAC, 0x06 }; + +/* RSN-8021X-SHA256 */ +uint8_t ccp_rsn_oui08[HDD_RSN_OUI_SIZE] = { 0x00, 0x0F, 0xAC, 0x05 }; +#endif + +/* Offset where the EID-Len-IE, start. */ +#define FT_ASSOC_RSP_IES_OFFSET 6 /* Capability(2) + AID(2) + Status Code(2) */ +#define FT_ASSOC_REQ_IES_OFFSET 4 /* Capability(2) + LI(2) */ + +#define BEACON_FRAME_IES_OFFSET 12 +#define HDD_PEER_AUTHORIZE_WAIT 10 + +/** + * beacon_filter_table - table of IEs used for beacon filtering + */ +static const int beacon_filter_table[] = { + SIR_MAC_DS_PARAM_SET_EID, + SIR_MAC_ERP_INFO_EID, + SIR_MAC_EDCA_PARAM_SET_EID, + SIR_MAC_QOS_CAPABILITY_EID, + SIR_MAC_HT_INFO_EID, + SIR_MAC_VHT_OPMODE_EID, + SIR_MAC_VHT_OPERATION_EID, +}; + +/** + * hdd_conn_set_authenticated() - set authentication state + * @pAdapter: pointer to the adapter + * @authState: authentication state + * + * This function updates the global HDD station context + * authentication state. + * + * Return: none + */ +static void +hdd_conn_set_authenticated(hdd_adapter_t *pAdapter, uint8_t authState) +{ + hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + + /* save the new connection state */ + hdd_notice("Authenticated state Changed from oldState:%d to State:%d", + pHddStaCtx->conn_info.uIsAuthenticated, authState); + pHddStaCtx->conn_info.uIsAuthenticated = authState; + + /* Check is pending ROC request or not when auth state changed */ + schedule_delayed_work(&pHddCtx->roc_req_work, 0); +} + +/** + * hdd_conn_set_connection_state() - set connection state + * @pAdapter: pointer to the adapter + * @connState: connection state + * + * This function updates the global HDD station context connection state. + * + * Return: none + */ +void hdd_conn_set_connection_state(hdd_adapter_t *pAdapter, + eConnectionState connState) +{ + hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + + /* save the new connection state */ + hdd_info("%pS Changed connectionState Changed from oldState:%d to State:%d", + (void *)_RET_IP_, pHddStaCtx->conn_info.connState, + connState); + pHddStaCtx->conn_info.connState = connState; + + /* Check is pending ROC request or not when connection state changed */ + schedule_delayed_work(&pHddCtx->roc_req_work, 0); +} + +/** + * hdd_conn_get_connection_state() - get connection state + * @pAdapter: pointer to the adapter + * @pConnState: pointer to connection state + * + * This function updates the global HDD station context connection state. + * + * Return: true if (Infra Associated or IBSS Connected) + * and sets output parameter pConnState; + * false otherwise + */ +static inline bool hdd_conn_get_connection_state(hdd_station_ctx_t *pHddStaCtx, + eConnectionState *pConnState) +{ + bool fConnected = false; + eConnectionState connState; + + /* get the connection state. */ + connState = pHddStaCtx->conn_info.connState; + + if (eConnectionState_Associated == connState || + eConnectionState_IbssConnected == connState || + eConnectionState_IbssDisconnected == connState) { + fConnected = true; + } + + if (pConnState) + *pConnState = connState; + + return fConnected; +} + +/** + * hdd_is_connecting() - Function to check connection progress + * @hdd_sta_ctx: pointer to global HDD Station context + * + * Return: true if connecting, false otherwise + */ +bool hdd_is_connecting(hdd_station_ctx_t *hdd_sta_ctx) +{ + return hdd_sta_ctx->conn_info.connState == + eConnectionState_Connecting; +} + +/** + * hdd_conn_is_connected() - Function to check connection status + * @pHddStaCtx: pointer to global HDD Station context + * + * Return: false if any errors encountered, true otherwise + */ +bool hdd_conn_is_connected(hdd_station_ctx_t *pHddStaCtx) +{ + return hdd_conn_get_connection_state(pHddStaCtx, NULL); +} + +/** + * hdd_conn_get_connected_band() - get current connection radio band + * @pHddStaCtx: pointer to global HDD Station context + * + * Return: eCSR_BAND_24 or eCSR_BAND_5G based on current AP connection + * eCSR_BAND_ALL if not connected + */ +eCsrBand hdd_conn_get_connected_band(hdd_station_ctx_t *pHddStaCtx) +{ + uint8_t staChannel = 0; + + if (eConnectionState_Associated == pHddStaCtx->conn_info.connState) + staChannel = pHddStaCtx->conn_info.operationChannel; + + if (staChannel > 0 && staChannel < 14) + return eCSR_BAND_24; + else if (staChannel >= 36 && staChannel <= 184) + return eCSR_BAND_5G; + else /* If station is not connected return as eCSR_BAND_ALL */ + return eCSR_BAND_ALL; +} + +/** + * hdd_conn_get_connected_cipher_algo() - get current connection cipher type + * @pHddStaCtx: pointer to global HDD Station context + * @pConnectedCipherAlgo: pointer to connected cipher algo + * + * Return: false if any errors encountered, true otherwise + */ +static inline bool +hdd_conn_get_connected_cipher_algo(hdd_station_ctx_t *pHddStaCtx, + eCsrEncryptionType *pConnectedCipherAlgo) +{ + bool fConnected = false; + + fConnected = hdd_conn_get_connection_state(pHddStaCtx, NULL); + + if (pConnectedCipherAlgo) + *pConnectedCipherAlgo = pHddStaCtx->conn_info.ucEncryptionType; + + return fConnected; +} + +/** + * hdd_remove_beacon_filter() - remove beacon filter + * @adapter: Pointer to the hdd adapter + * + * Return: 0 on success and errno on failure + */ +static int hdd_remove_beacon_filter(hdd_adapter_t *adapter) +{ + QDF_STATUS status; + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + + status = sme_remove_beacon_filter(hdd_ctx->hHal, + adapter->sessionId); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("sme_remove_beacon_filter() failed"); + return -EFAULT; + } + + return 0; +} + +/** + * hdd_add_beacon_filter() - add beacon filter + * @adapter: Pointer to the hdd adapter + * + * Return: 0 on success and errno on failure + */ +static int hdd_add_beacon_filter(hdd_adapter_t *adapter) +{ + int i; + uint32_t ie_map[SIR_BCN_FLT_MAX_ELEMS_IE_LIST] = {0}; + QDF_STATUS status; + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + + for (i = 0; i < ARRAY_SIZE(beacon_filter_table); i++) + qdf_set_bit((beacon_filter_table[i]), + (unsigned long int *)ie_map); + + status = sme_add_beacon_filter(hdd_ctx->hHal, + adapter->sessionId, ie_map); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("sme_add_beacon_filter() failed"); + return -EFAULT; + } + return 0; +} + +/** + * hdd_copy_vht_caps()- copy vht caps info from roam info to + * hdd station context. + * @hdd_sta_ctx: pointer to hdd station context + * @roam_info: pointer to roam info + * + * Return: None + */ +static void hdd_copy_ht_caps(hdd_station_ctx_t *hdd_sta_ctx, + tCsrRoamInfo *roam_info) +{ + tDot11fIEHTCaps *roam_ht_cap = &roam_info->ht_caps; + struct ieee80211_ht_cap *hdd_ht_cap = &hdd_sta_ctx->conn_info.ht_caps; + uint32_t i, temp_ht_cap; + + qdf_mem_zero(hdd_ht_cap, sizeof(struct ieee80211_ht_cap)); + + if (roam_ht_cap->advCodingCap) + hdd_ht_cap->cap_info |= IEEE80211_HT_CAP_LDPC_CODING; + if (roam_ht_cap->supportedChannelWidthSet) + hdd_ht_cap->cap_info |= IEEE80211_HT_CAP_SUP_WIDTH_20_40; + temp_ht_cap = roam_ht_cap->mimoPowerSave & + (IEEE80211_HT_CAP_SM_PS >> IEEE80211_HT_CAP_SM_PS_SHIFT); + if (temp_ht_cap) + hdd_ht_cap->cap_info |= + temp_ht_cap << IEEE80211_HT_CAP_SM_PS_SHIFT; + if (roam_ht_cap->greenField) + hdd_ht_cap->cap_info |= IEEE80211_HT_CAP_GRN_FLD; + if (roam_ht_cap->shortGI20MHz) + hdd_ht_cap->cap_info |= IEEE80211_HT_CAP_SGI_20; + if (roam_ht_cap->shortGI40MHz) + hdd_ht_cap->cap_info |= IEEE80211_HT_CAP_SGI_40; + if (roam_ht_cap->txSTBC) + hdd_ht_cap->cap_info |= IEEE80211_HT_CAP_TX_STBC; + temp_ht_cap = roam_ht_cap->rxSTBC & (IEEE80211_HT_CAP_RX_STBC >> + IEEE80211_HT_CAP_RX_STBC_SHIFT); + if (temp_ht_cap) + hdd_ht_cap->cap_info |= + temp_ht_cap << IEEE80211_HT_CAP_RX_STBC_SHIFT; + if (roam_ht_cap->delayedBA) + hdd_ht_cap->cap_info |= IEEE80211_HT_CAP_DELAY_BA; + if (roam_ht_cap->maximalAMSDUsize) + hdd_ht_cap->cap_info |= IEEE80211_HT_CAP_MAX_AMSDU; + if (roam_ht_cap->dsssCckMode40MHz) + hdd_ht_cap->cap_info |= IEEE80211_HT_CAP_DSSSCCK40; + if (roam_ht_cap->psmp) + hdd_ht_cap->cap_info |= IEEE80211_HT_CAP_RESERVED; + if (roam_ht_cap->stbcControlFrame) + hdd_ht_cap->cap_info |= IEEE80211_HT_CAP_40MHZ_INTOLERANT; + if (roam_ht_cap->lsigTXOPProtection) + hdd_ht_cap->cap_info |= IEEE80211_HT_CAP_LSIG_TXOP_PROT; + + /* 802.11n HT capability AMPDU settings (for ampdu_params_info) */ + if (roam_ht_cap->maxRxAMPDUFactor) + hdd_ht_cap->ampdu_params_info |= + IEEE80211_HT_AMPDU_PARM_FACTOR; + temp_ht_cap = roam_ht_cap->mpduDensity & + (IEEE80211_HT_AMPDU_PARM_DENSITY >> + IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT); + if (temp_ht_cap) + hdd_ht_cap->ampdu_params_info |= + temp_ht_cap << IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT; + + /* 802.11n HT extended capabilities masks */ + if (roam_ht_cap->pco) + hdd_ht_cap->extended_ht_cap_info |= + IEEE80211_HT_EXT_CAP_PCO; + temp_ht_cap = roam_ht_cap->transitionTime & + (IEEE80211_HT_EXT_CAP_PCO_TIME >> + IEEE80211_HT_EXT_CAP_PCO_TIME_SHIFT); + if (temp_ht_cap) + hdd_ht_cap->extended_ht_cap_info |= + temp_ht_cap << IEEE80211_HT_EXT_CAP_PCO_TIME_SHIFT; + temp_ht_cap = roam_ht_cap->mcsFeedback & + (IEEE80211_HT_EXT_CAP_MCS_FB >> IEEE80211_HT_EXT_CAP_MCS_FB_SHIFT); + if (temp_ht_cap) + hdd_ht_cap->extended_ht_cap_info |= + temp_ht_cap << IEEE80211_HT_EXT_CAP_MCS_FB_SHIFT; + + /* tx_bf_cap_info capabilities */ + if (roam_ht_cap->txBF) + hdd_ht_cap->tx_BF_cap_info |= TX_BF_CAP_INFO_TX_BF; + if (roam_ht_cap->rxStaggeredSounding) + hdd_ht_cap->tx_BF_cap_info |= + TX_BF_CAP_INFO_RX_STAG_RED_SOUNDING; + if (roam_ht_cap->txStaggeredSounding) + hdd_ht_cap->tx_BF_cap_info |= + TX_BF_CAP_INFO_TX_STAG_RED_SOUNDING; + if (roam_ht_cap->rxZLF) + hdd_ht_cap->tx_BF_cap_info |= TX_BF_CAP_INFO_RX_ZFL; + if (roam_ht_cap->txZLF) + hdd_ht_cap->tx_BF_cap_info |= TX_BF_CAP_INFO_TX_ZFL; + if (roam_ht_cap->implicitTxBF) + hdd_ht_cap->tx_BF_cap_info |= TX_BF_CAP_INFO_IMP_TX_BF; + temp_ht_cap = roam_ht_cap->calibration & + (TX_BF_CAP_INFO_CALIBRATION >> TX_BF_CAP_INFO_CALIBRATION_SHIFT); + if (temp_ht_cap) + hdd_ht_cap->tx_BF_cap_info |= + temp_ht_cap << TX_BF_CAP_INFO_CALIBRATION_SHIFT; + if (roam_ht_cap->explicitCSITxBF) + hdd_ht_cap->tx_BF_cap_info |= TX_BF_CAP_INFO_EXP_CSIT_BF; + if (roam_ht_cap->explicitUncompressedSteeringMatrix) + hdd_ht_cap->tx_BF_cap_info |= + TX_BF_CAP_INFO_EXP_UNCOMP_STEER_MAT; + temp_ht_cap = roam_ht_cap->explicitBFCSIFeedback & + (TX_BF_CAP_INFO_EXP_BF_CSI_FB >> + TX_BF_CAP_INFO_EXP_BF_CSI_FB_SHIFT); + if (temp_ht_cap) + hdd_ht_cap->tx_BF_cap_info |= + temp_ht_cap << TX_BF_CAP_INFO_EXP_BF_CSI_FB_SHIFT; + temp_ht_cap = + roam_ht_cap->explicitUncompressedSteeringMatrixFeedback & + (TX_BF_CAP_INFO_EXP_UNCMP_STEER_MAT >> + TX_BF_CAP_INFO_EXP_UNCMP_STEER_MAT_SHIFT); + if (temp_ht_cap) + hdd_ht_cap->tx_BF_cap_info |= + temp_ht_cap << + TX_BF_CAP_INFO_EXP_UNCMP_STEER_MAT_SHIFT; + temp_ht_cap = + roam_ht_cap->explicitCompressedSteeringMatrixFeedback & + (TX_BF_CAP_INFO_EXP_CMP_STEER_MAT_FB >> + TX_BF_CAP_INFO_EXP_CMP_STEER_MAT_FB_SHIFT); + if (temp_ht_cap) + hdd_ht_cap->tx_BF_cap_info |= + temp_ht_cap << + TX_BF_CAP_INFO_EXP_CMP_STEER_MAT_FB_SHIFT; + temp_ht_cap = roam_ht_cap->csiNumBFAntennae & + (TX_BF_CAP_INFO_CSI_NUM_BF_ANT >> + TX_BF_CAP_INFO_CSI_NUM_BF_ANT_SHIFT); + if (temp_ht_cap) + hdd_ht_cap->tx_BF_cap_info |= + temp_ht_cap << TX_BF_CAP_INFO_CSI_NUM_BF_ANT_SHIFT; + temp_ht_cap = roam_ht_cap->uncompressedSteeringMatrixBFAntennae & + (TX_BF_CAP_INFO_UNCOMP_STEER_MAT_BF_ANT >> + TX_BF_CAP_INFO_UNCOMP_STEER_MAT_BF_ANT_SHIFT); + if (temp_ht_cap) + hdd_ht_cap->tx_BF_cap_info |= + temp_ht_cap << + TX_BF_CAP_INFO_UNCOMP_STEER_MAT_BF_ANT_SHIFT; + temp_ht_cap = roam_ht_cap->compressedSteeringMatrixBFAntennae & + (TX_BF_CAP_INFO_COMP_STEER_MAT_BF_ANT >> + TX_BF_CAP_INFO_COMP_STEER_MAT_BF_ANT_SHIFT); + if (temp_ht_cap) + hdd_ht_cap->tx_BF_cap_info |= + temp_ht_cap << + TX_BF_CAP_INFO_COMP_STEER_MAT_BF_ANT_SHIFT; + + /* antenna selection */ + if (roam_ht_cap->antennaSelection) + hdd_ht_cap->antenna_selection_info |= ANTENNA_SEL_INFO; + if (roam_ht_cap->explicitCSIFeedbackTx) + hdd_ht_cap->antenna_selection_info |= + ANTENNA_SEL_INFO_EXP_CSI_FB_TX; + if (roam_ht_cap->antennaIndicesFeedbackTx) + hdd_ht_cap->antenna_selection_info |= + ANTENNA_SEL_INFO_ANT_ID_FB_TX; + if (roam_ht_cap->explicitCSIFeedback) + hdd_ht_cap->antenna_selection_info |= + ANTENNA_SEL_INFO_EXP_CSI_FB; + if (roam_ht_cap->antennaIndicesFeedback) + hdd_ht_cap->antenna_selection_info |= + ANTENNA_SEL_INFO_ANT_ID_FB; + if (roam_ht_cap->rxAS) + hdd_ht_cap->antenna_selection_info |= + ANTENNA_SEL_INFO_RX_AS; + if (roam_ht_cap->txSoundingPPDUs) + hdd_ht_cap->antenna_selection_info |= + ANTENNA_SEL_INFO_TX_SOUNDING_PPDU; + + /* mcs data rate */ + for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; ++i) + hdd_ht_cap->mcs.rx_mask[i] = + roam_ht_cap->supportedMCSSet[i]; + hdd_ht_cap->mcs.rx_highest = + ((short) (roam_ht_cap->supportedMCSSet[11]) << 8) | + ((short) (roam_ht_cap->supportedMCSSet[10])); + hdd_ht_cap->mcs.tx_params = + roam_ht_cap->supportedMCSSet[12]; +} + +#define VHT_CAP_MAX_MPDU_LENGTH_MASK 0x00000003 +#define VHT_CAP_SUPP_CHAN_WIDTH_MASK_SHIFT 2 +#define VHT_CAP_RXSTBC_MASK_SHIFT 8 +#define VHT_CAP_BEAMFORMEE_STS_SHIFT 13 +#define VHT_CAP_BEAMFORMEE_STS_MASK \ + (0x0000e000 >> VHT_CAP_BEAMFORMEE_STS_SHIFT) +#define VHT_CAP_SOUNDING_DIMENSIONS_SHIFT 16 +#define VHT_CAP_SOUNDING_DIMENSIONS_MASK \ + (0x00070000 >> VHT_CAP_SOUNDING_DIMENSIONS_SHIFT) +#define VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK_SHIFT 23 +#define VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK \ + (0x03800000 >> VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK_SHIFT) +#define VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB_SHIFT 26 + +/** + * hdd_copy_ht_caps()- copy ht caps info from roam info to + * hdd station context. + * @hdd_sta_ctx: pointer to hdd station context + * @roam_info: pointer to roam info + * + * Return: None + */ +static void hdd_copy_vht_caps(hdd_station_ctx_t *hdd_sta_ctx, + tCsrRoamInfo *roam_info) +{ + tDot11fIEVHTCaps *roam_vht_cap = &roam_info->vht_caps; + struct ieee80211_vht_cap *hdd_vht_cap = + &hdd_sta_ctx->conn_info.vht_caps; + uint32_t temp_vht_cap; + + qdf_mem_zero(hdd_vht_cap, sizeof(struct ieee80211_vht_cap)); + + temp_vht_cap = roam_vht_cap->maxMPDULen & VHT_CAP_MAX_MPDU_LENGTH_MASK; + hdd_vht_cap->vht_cap_info |= temp_vht_cap; + temp_vht_cap = roam_vht_cap->supportedChannelWidthSet & + (IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK >> + VHT_CAP_SUPP_CHAN_WIDTH_MASK_SHIFT); + if (temp_vht_cap) + if (roam_vht_cap->supportedChannelWidthSet & + (IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ >> + VHT_CAP_SUPP_CHAN_WIDTH_MASK_SHIFT)) + hdd_vht_cap->vht_cap_info |= + temp_vht_cap << + IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ; + if (roam_vht_cap->supportedChannelWidthSet & + (IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ >> + VHT_CAP_SUPP_CHAN_WIDTH_MASK_SHIFT)) + hdd_vht_cap->vht_cap_info |= + temp_vht_cap << + IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ; + if (roam_vht_cap->ldpcCodingCap) + hdd_vht_cap->vht_cap_info |= IEEE80211_VHT_CAP_RXLDPC; + if (roam_vht_cap->shortGI80MHz) + hdd_vht_cap->vht_cap_info |= IEEE80211_VHT_CAP_SHORT_GI_80; + if (roam_vht_cap->shortGI160and80plus80MHz) + hdd_vht_cap->vht_cap_info |= IEEE80211_VHT_CAP_SHORT_GI_160; + if (roam_vht_cap->txSTBC) + hdd_vht_cap->vht_cap_info |= IEEE80211_VHT_CAP_TXSTBC; + temp_vht_cap = roam_vht_cap->rxSTBC & (IEEE80211_VHT_CAP_RXSTBC_MASK >> + VHT_CAP_RXSTBC_MASK_SHIFT); + if (temp_vht_cap) + hdd_vht_cap->vht_cap_info |= + temp_vht_cap << VHT_CAP_RXSTBC_MASK_SHIFT; + if (roam_vht_cap->suBeamFormerCap) + hdd_vht_cap->vht_cap_info |= + IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE; + if (roam_vht_cap->suBeamformeeCap) + hdd_vht_cap->vht_cap_info |= + IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE; + temp_vht_cap = roam_vht_cap->csnofBeamformerAntSup & + (VHT_CAP_BEAMFORMEE_STS_MASK); + if (temp_vht_cap) + hdd_vht_cap->vht_cap_info |= + temp_vht_cap << VHT_CAP_BEAMFORMEE_STS_SHIFT; + temp_vht_cap = roam_vht_cap->numSoundingDim & + (VHT_CAP_SOUNDING_DIMENSIONS_MASK); + if (temp_vht_cap) + hdd_vht_cap->vht_cap_info |= + temp_vht_cap << VHT_CAP_SOUNDING_DIMENSIONS_SHIFT; + if (roam_vht_cap->muBeamformerCap) + hdd_vht_cap->vht_cap_info |= + IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE; + if (roam_vht_cap->muBeamformeeCap) + hdd_vht_cap->vht_cap_info |= + IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE; + if (roam_vht_cap->vhtTXOPPS) + hdd_vht_cap->vht_cap_info |= + IEEE80211_VHT_CAP_VHT_TXOP_PS; + if (roam_vht_cap->htcVHTCap) + hdd_vht_cap->vht_cap_info |= + IEEE80211_VHT_CAP_HTC_VHT; + temp_vht_cap = roam_vht_cap->maxAMPDULenExp & + (VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK); + if (temp_vht_cap) + hdd_vht_cap->vht_cap_info |= + temp_vht_cap << + VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK_SHIFT; + temp_vht_cap = roam_vht_cap->vhtLinkAdaptCap & + (IEEE80211_VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB >> + VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB_SHIFT); + if (temp_vht_cap) + hdd_vht_cap->vht_cap_info |= temp_vht_cap << + VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB_SHIFT; + if (roam_vht_cap->rxAntPattern) + hdd_vht_cap->vht_cap_info |= + IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN; + if (roam_vht_cap->txAntPattern) + hdd_vht_cap->vht_cap_info |= + IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN; + hdd_vht_cap->supp_mcs.rx_mcs_map = roam_vht_cap->rxMCSMap; + hdd_vht_cap->supp_mcs.rx_highest = + ((uint16_t)roam_vht_cap->rxHighSupDataRate); + hdd_vht_cap->supp_mcs.tx_mcs_map = roam_vht_cap->txMCSMap; + hdd_vht_cap->supp_mcs.tx_highest = + ((uint16_t)roam_vht_cap->txSupDataRate); +} + +/* ht param */ +#define HT_PARAM_CONTROLLED_ACCESS_ONLY 0x10 +#define HT_PARAM_SERVICE_INT_GRAN 0xe0 +#define HT_PARAM_SERVICE_INT_GRAN_SHIFT 5 + +/* operatinon mode */ +#define HT_OP_MODE_TX_BURST_LIMIT 0x0008 + +/* stbc_param */ +#define HT_STBC_PARAM_MCS 0x007f + +/** + * hdd_copy_ht_operation()- copy HT operation element from roam info to + * hdd station context. + * @hdd_sta_ctx: pointer to hdd station context + * @roam_info: pointer to roam info + * + * Return: None + */ +static void hdd_copy_ht_operation(hdd_station_ctx_t *hdd_sta_ctx, + tCsrRoamInfo *roam_info) +{ + tDot11fIEHTInfo *roam_ht_ops = &roam_info->ht_operation; + struct ieee80211_ht_operation *hdd_ht_ops = + &hdd_sta_ctx->conn_info.ht_operation; + uint32_t i, temp_ht_ops; + + qdf_mem_zero(hdd_ht_ops, sizeof(struct ieee80211_ht_operation)); + + hdd_ht_ops->primary_chan = roam_ht_ops->primaryChannel; + + /* HT_PARAMS */ + temp_ht_ops = roam_ht_ops->secondaryChannelOffset & + IEEE80211_HT_PARAM_CHA_SEC_OFFSET; + if (temp_ht_ops) + hdd_ht_ops->ht_param |= temp_ht_ops; + else + hdd_ht_ops->ht_param = IEEE80211_HT_PARAM_CHA_SEC_NONE; + if (roam_ht_ops->recommendedTxWidthSet) + hdd_ht_ops->ht_param |= IEEE80211_HT_PARAM_CHAN_WIDTH_ANY; + if (roam_ht_ops->rifsMode) + hdd_ht_ops->ht_param |= IEEE80211_HT_PARAM_RIFS_MODE; + if (roam_ht_ops->controlledAccessOnly) + hdd_ht_ops->ht_param |= HT_PARAM_CONTROLLED_ACCESS_ONLY; + temp_ht_ops = roam_ht_ops->serviceIntervalGranularity & + (HT_PARAM_SERVICE_INT_GRAN >> HT_PARAM_SERVICE_INT_GRAN_SHIFT); + if (temp_ht_ops) + hdd_ht_ops->ht_param |= temp_ht_ops << + HT_PARAM_SERVICE_INT_GRAN_SHIFT; + + /* operation mode */ + temp_ht_ops = roam_ht_ops->opMode & + IEEE80211_HT_OP_MODE_PROTECTION; + switch (temp_ht_ops) { + case IEEE80211_HT_OP_MODE_PROTECTION_NONMEMBER: + hdd_ht_ops->operation_mode |= + IEEE80211_HT_OP_MODE_PROTECTION_NONMEMBER; + break; + case IEEE80211_HT_OP_MODE_PROTECTION_20MHZ: + hdd_ht_ops->operation_mode |= + IEEE80211_HT_OP_MODE_PROTECTION_20MHZ; + break; + case IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED: + hdd_ht_ops->operation_mode |= + IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED; + break; + case IEEE80211_HT_OP_MODE_PROTECTION_NONE: + default: + hdd_ht_ops->operation_mode |= + IEEE80211_HT_OP_MODE_PROTECTION_NONE; + } + if (roam_ht_ops->nonGFDevicesPresent) + hdd_ht_ops->operation_mode |= + IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT; + if (roam_ht_ops->transmitBurstLimit) + hdd_ht_ops->operation_mode |= + HT_OP_MODE_TX_BURST_LIMIT; + if (roam_ht_ops->obssNonHTStaPresent) + hdd_ht_ops->operation_mode |= + IEEE80211_HT_OP_MODE_NON_HT_STA_PRSNT; + + /* stbc_param */ + temp_ht_ops = roam_ht_ops->basicSTBCMCS & + HT_STBC_PARAM_MCS; + if (temp_ht_ops) + hdd_ht_ops->stbc_param |= temp_ht_ops; + if (roam_ht_ops->dualCTSProtection) + hdd_ht_ops->stbc_param |= + IEEE80211_HT_STBC_PARAM_DUAL_CTS_PROT; + if (roam_ht_ops->secondaryBeacon) + hdd_ht_ops->stbc_param |= + IEEE80211_HT_STBC_PARAM_STBC_BEACON; + if (roam_ht_ops->lsigTXOPProtectionFullSupport) + hdd_ht_ops->stbc_param |= + IEEE80211_HT_STBC_PARAM_LSIG_TXOP_FULLPROT; + if (roam_ht_ops->pcoActive) + hdd_ht_ops->stbc_param |= + IEEE80211_HT_STBC_PARAM_PCO_ACTIVE; + if (roam_ht_ops->pcoPhase) + hdd_ht_ops->stbc_param |= + IEEE80211_HT_STBC_PARAM_PCO_PHASE; + + /* basic MCs set */ + for (i = 0; i < 16; ++i) + hdd_ht_ops->basic_set[i] = + roam_ht_ops->basicMCSSet[i]; +} + +/** + * hdd_copy_vht_operation()- copy VHT operations element from roam info to + * hdd station context. + * @hdd_sta_ctx: pointer to hdd station context + * @roam_info: pointer to roam info + * + * Return: None + */ +static void hdd_copy_vht_operation(hdd_station_ctx_t *hdd_sta_ctx, + tCsrRoamInfo *roam_info) +{ + tDot11fIEVHTOperation *roam_vht_ops = &roam_info->vht_operation; + struct ieee80211_vht_operation *hdd_vht_ops = + &hdd_sta_ctx->conn_info.vht_operation; + + qdf_mem_zero(hdd_vht_ops, sizeof(struct ieee80211_vht_operation)); + + hdd_vht_ops->chan_width = roam_vht_ops->chanWidth; + hdd_vht_ops->center_freq_seg1_idx = roam_vht_ops->chanCenterFreqSeg1; + hdd_vht_ops->center_freq_seg2_idx = roam_vht_ops->chanCenterFreqSeg2; + hdd_vht_ops->basic_mcs_set = roam_vht_ops->basicMCSSet; +} + + +/** + * hdd_save_bss_info() - save connection info in hdd sta ctx + * @adapter: Pointer to adapter + * @roam_info: pointer to roam info + * + * Return: None + */ +static void hdd_save_bss_info(hdd_adapter_t *adapter, + tCsrRoamInfo *roam_info) +{ + hdd_station_ctx_t *hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + + hdd_sta_ctx->conn_info.freq = cds_chan_to_freq( + hdd_sta_ctx->conn_info.operationChannel); + if (roam_info->vht_caps.present) { + hdd_sta_ctx->conn_info.conn_flag.vht_present = true; + hdd_copy_vht_caps(hdd_sta_ctx, roam_info); + } else { + hdd_sta_ctx->conn_info.conn_flag.vht_present = false; + } + if (roam_info->ht_caps.present) { + hdd_sta_ctx->conn_info.conn_flag.ht_present = true; + hdd_copy_ht_caps(hdd_sta_ctx, roam_info); + } else { + hdd_sta_ctx->conn_info.conn_flag.ht_present = false; + } + if (roam_info->reassoc) + hdd_sta_ctx->conn_info.roam_count++; + if (roam_info->hs20vendor_ie.present) { + hdd_sta_ctx->conn_info.conn_flag.hs20_present = true; + qdf_mem_copy(&hdd_sta_ctx->conn_info.hs20vendor_ie, + &roam_info->hs20vendor_ie, + sizeof(roam_info->hs20vendor_ie)); + } else { + hdd_sta_ctx->conn_info.conn_flag.hs20_present = false; + } + if (roam_info->ht_operation.present) { + hdd_sta_ctx->conn_info.conn_flag.ht_op_present = true; + hdd_copy_ht_operation(hdd_sta_ctx, roam_info); + } else { + hdd_sta_ctx->conn_info.conn_flag.ht_op_present = false; + } + if (roam_info->vht_operation.present) { + hdd_sta_ctx->conn_info.conn_flag.vht_op_present = true; + hdd_copy_vht_operation(hdd_sta_ctx, roam_info); + } else { + hdd_sta_ctx->conn_info.conn_flag.vht_op_present = false; + } +} + +/** + * hdd_conn_save_connect_info() - save current connection information + * @pAdapter: pointer to adapter + * @pRoamInfo: pointer to roam info + * @eBssType: bss type + * + * Return: none + */ +static void +hdd_conn_save_connect_info(hdd_adapter_t *pAdapter, tCsrRoamInfo *pRoamInfo, + eCsrRoamBssType eBssType) +{ + hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + eCsrEncryptionType encryptType = eCSR_ENCRYPT_TYPE_NONE; + + QDF_ASSERT(pRoamInfo); + + if (pRoamInfo) { + /* Save the BSSID for the connection */ + if (eCSR_BSS_TYPE_INFRASTRUCTURE == eBssType) { + QDF_ASSERT(pRoamInfo->pBssDesc); + qdf_copy_macaddr(&pHddStaCtx->conn_info.bssId, + &pRoamInfo->bssid); + + /* + * Save the Station ID for this station from + * the 'Roam Info'. For IBSS mode, staId is + * assigned in NEW_PEER_IND. For reassoc, + * the staID doesn't change and it may be invalid + * in this structure so no change here. + */ + if (!pRoamInfo->fReassocReq) { + pHddStaCtx->conn_info.staId[0] = + pRoamInfo->staId; + } + } else if (eCSR_BSS_TYPE_IBSS == eBssType) { + qdf_copy_macaddr(&pHddStaCtx->conn_info.bssId, + &pRoamInfo->bssid); + } else { + /* + * can't happen. We need a valid IBSS or Infra setting + * in the BSSDescription or we can't function. + */ + QDF_ASSERT(0); + } + + /* notify WMM */ + hdd_wmm_connect(pAdapter, pRoamInfo, eBssType); + + if (!pRoamInfo->u.pConnectedProfile) { + QDF_ASSERT(pRoamInfo->u.pConnectedProfile); + } else { + /* Get Multicast Encryption Type */ + encryptType = + pRoamInfo->u.pConnectedProfile->mcEncryptionType; + pHddStaCtx->conn_info.mcEncryptionType = encryptType; + /* Get Unicast Encryption Type */ + encryptType = + pRoamInfo->u.pConnectedProfile->EncryptionType; + pHddStaCtx->conn_info.ucEncryptionType = encryptType; + + pHddStaCtx->conn_info.authType = + pRoamInfo->u.pConnectedProfile->AuthType; + + pHddStaCtx->conn_info.operationChannel = + pRoamInfo->u.pConnectedProfile->operationChannel; + + /* Save the ssid for the connection */ + qdf_mem_copy(&pHddStaCtx->conn_info.SSID.SSID, + &pRoamInfo->u.pConnectedProfile->SSID, + sizeof(tSirMacSSid)); + + /* Save dot11mode in which STA associated to AP */ + pHddStaCtx->conn_info.dot11Mode = + pRoamInfo->u.pConnectedProfile->dot11Mode; + + pHddStaCtx->conn_info.proxyARPService = + pRoamInfo->u.pConnectedProfile->proxyARPService; + + pHddStaCtx->conn_info.nss = pRoamInfo->chan_info.nss; + + pHddStaCtx->conn_info.rate_flags = + pRoamInfo->chan_info.rate_flags; + } + hdd_save_bss_info(pAdapter, pRoamInfo); + } +} + +/** + * hdd_send_ft_assoc_response() - send fast transition assoc response + * @dev: pointer to net device + * @pAdapter: pointer to adapter + * @pCsrRoamInfo: pointer to roam info + * + * Send the 11R key information to the supplicant. Only then can the supplicant + * generate the PMK-R1. (BTW, the ESE supplicant also needs the Assoc Resp IEs + * for the same purpose.) + * + * Mainly the Assoc Rsp IEs are passed here. For the IMDA this contains the + * R1KHID, R0KHID and the MDID. For FT, this consists of the Reassoc Rsp FTIEs. + * This is the Assoc Response. + * + * Return: none + */ +static void +hdd_send_ft_assoc_response(struct net_device *dev, + hdd_adapter_t *pAdapter, + tCsrRoamInfo *pCsrRoamInfo) +{ + union iwreq_data wrqu; + char *buff; + unsigned int len = 0; + u8 *pFTAssocRsp = NULL; + + if (pCsrRoamInfo->nAssocRspLength == 0) { + hdd_err("pCsrRoamInfo->nAssocRspLength=%d", + (int)pCsrRoamInfo->nAssocRspLength); + return; + } + + pFTAssocRsp = + (u8 *) (pCsrRoamInfo->pbFrames + pCsrRoamInfo->nBeaconLength + + pCsrRoamInfo->nAssocReqLength); + if (pFTAssocRsp == NULL) { + hdd_err("AssocReq or AssocRsp is NULL"); + return; + } + /* pFTAssocRsp needs to point to the IEs */ + pFTAssocRsp += FT_ASSOC_RSP_IES_OFFSET; + hdd_notice("AssocRsp is now at %02x%02x", + (unsigned int)pFTAssocRsp[0], + (unsigned int)pFTAssocRsp[1]); + + /* We need to send the IEs to the supplicant. */ + buff = qdf_mem_malloc(IW_GENERIC_IE_MAX); + if (buff == NULL) { + hdd_err("unable to allocate memory"); + return; + } + /* Send the Assoc Resp, the supplicant needs this for initial Auth. */ + len = pCsrRoamInfo->nAssocRspLength - FT_ASSOC_RSP_IES_OFFSET; + wrqu.data.length = len; + memcpy(buff, pFTAssocRsp, len); + wireless_send_event(dev, IWEVASSOCRESPIE, &wrqu, buff); + + qdf_mem_free(buff); +} + +/** + * hdd_send_ft_event() - send fast transition event + * @pAdapter: pointer to adapter + * + * Send the FTIEs, RIC IEs during FT. This is eventually used to send the + * FT events to the supplicant. At the reception of Auth2 we send the RIC + * followed by the auth response IEs to the supplicant. + * Once both are received in the supplicant, an FT event is generated + * to the supplicant. + * + * Return: none + */ +static void hdd_send_ft_event(hdd_adapter_t *pAdapter) +{ + uint16_t auth_resp_len = 0; + uint32_t ric_ies_length = 0; + hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + +#if defined(KERNEL_SUPPORT_11R_CFG80211) + struct cfg80211_ft_event_params ftEvent; + uint8_t ftIe[DOT11F_IE_FTINFO_MAX_LEN]; + uint8_t ricIe[DOT11F_IE_RICDESCRIPTOR_MAX_LEN]; + struct net_device *dev = pAdapter->dev; +#else + char *buff; + union iwreq_data wrqu; + uint16_t str_len; +#endif + +#if defined(KERNEL_SUPPORT_11R_CFG80211) + qdf_mem_zero(ftIe, DOT11F_IE_FTINFO_MAX_LEN); + qdf_mem_zero(ricIe, DOT11F_IE_RICDESCRIPTOR_MAX_LEN); + + sme_get_rici_es(pHddCtx->hHal, pAdapter->sessionId, (u8 *) ricIe, + DOT11F_IE_RICDESCRIPTOR_MAX_LEN, &ric_ies_length); + if (ric_ies_length == 0) { + hdd_warn("RIC IEs is of length 0 not sending RIC Information for now"); + } + + ftEvent.ric_ies = ricIe; + ftEvent.ric_ies_len = ric_ies_length; + hdd_notice("RIC IEs is of length %d", (int)ric_ies_length); + + sme_get_ft_pre_auth_response(pHddCtx->hHal, pAdapter->sessionId, + (u8 *) ftIe, DOT11F_IE_FTINFO_MAX_LEN, + &auth_resp_len); + + if (auth_resp_len == 0) { + hdd_err("AuthRsp FTIES is of length 0"); + return; + } + + sme_set_ft_pre_auth_state(pHddCtx->hHal, pAdapter->sessionId, true); + + ftEvent.target_ap = ftIe; + + ftEvent.ies = (u8 *) (ftIe + QDF_MAC_ADDR_SIZE); + ftEvent.ies_len = auth_resp_len - QDF_MAC_ADDR_SIZE; + + hdd_notice("ftEvent.ies_len %zu", ftEvent.ies_len); + hdd_notice("ftEvent.ric_ies_len %zu", ftEvent.ric_ies_len); + hdd_notice("ftEvent.target_ap %2x-%2x-%2x-%2x-%2x-%2x", + ftEvent.target_ap[0], ftEvent.target_ap[1], + ftEvent.target_ap[2], ftEvent.target_ap[3], ftEvent.target_ap[4], + ftEvent.target_ap[5]); + + (void)cfg80211_ft_event(dev, &ftEvent); + +#else + /* We need to send the IEs to the supplicant */ + buff = qdf_mem_malloc(IW_CUSTOM_MAX); + if (buff == NULL) { + hdd_err("unable to allocate memory"); + return; + } + + /* Sme needs to send the RIC IEs first */ + str_len = strlcpy(buff, "RIC=", IW_CUSTOM_MAX); + sme_get_rici_es(pHddCtx->hHal, pAdapter->sessionId, + (u8 *) &(buff[str_len]), (IW_CUSTOM_MAX - str_len), + &ric_ies_length); + if (ric_ies_length == 0) { + hdd_warn("RIC IEs is of length 0 not sending RIC Information for now"); + } else { + wrqu.data.length = str_len + ric_ies_length; + wireless_send_event(pAdapter->dev, IWEVCUSTOM, &wrqu, buff); + } + + /* Sme needs to provide the Auth Resp */ + qdf_mem_zero(buff, IW_CUSTOM_MAX); + str_len = strlcpy(buff, "AUTH=", IW_CUSTOM_MAX); + sme_get_ft_pre_auth_response(pHddCtx->hHal, pAdapter->sessionId, + (u8 *) &buff[str_len], + (IW_CUSTOM_MAX - str_len), &auth_resp_len); + + if (auth_resp_len == 0) { + qdf_mem_free(buff); + hdd_err("AuthRsp FTIES is of length 0"); + return; + } + + wrqu.data.length = str_len + auth_resp_len; + wireless_send_event(pAdapter->dev, IWEVCUSTOM, &wrqu, buff); + + qdf_mem_free(buff); +#endif +} + +#ifdef FEATURE_WLAN_ESE +/** + * hdd_send_new_ap_channel_info() - send new ap channel info + * @dev: pointer to net device + * @pAdapter: pointer to adapter + * @pCsrRoamInfo: pointer to roam info + * + * Send the ESE required "new AP Channel info" to the supplicant. + * (This keeps the supplicant "up to date" on the current channel.) + * + * The current (new AP) channel information is passed in. + * + * Return: none + */ +static void +hdd_send_new_ap_channel_info(struct net_device *dev, hdd_adapter_t *pAdapter, + tCsrRoamInfo *pCsrRoamInfo) +{ + union iwreq_data wrqu; + tSirBssDescription *descriptor = pCsrRoamInfo->pBssDesc; + + if (descriptor == NULL) { + hdd_err("pCsrRoamInfo->pBssDesc(%p)", descriptor); + return; + } + /* + * Send the Channel event, the supplicant needs this to generate + * the Adjacent AP report. + */ + hdd_info("Sending up an SIOCGIWFREQ, channelId(%d)", + descriptor->channelId); + memset(&wrqu, '\0', sizeof(wrqu)); + wrqu.freq.m = descriptor->channelId; + wrqu.freq.e = 0; + wrqu.freq.i = 0; + wireless_send_event(pAdapter->dev, SIOCGIWFREQ, &wrqu, NULL); +} + +#endif /* FEATURE_WLAN_ESE */ + +/** + * hdd_send_update_beacon_ies_event() - send update beacons ie event + * @pAdapter: pointer to adapter + * @pCsrRoamInfo: pointer to roam info + * + * Return: none + */ +static void +hdd_send_update_beacon_ies_event(hdd_adapter_t *pAdapter, + tCsrRoamInfo *pCsrRoamInfo) +{ + union iwreq_data wrqu; + u8 *pBeaconIes; + u8 currentLen = 0; + char *buff; + int totalIeLen = 0, currentOffset = 0, strLen; + + memset(&wrqu, '\0', sizeof(wrqu)); + + if (0 == pCsrRoamInfo->nBeaconLength) { + hdd_warn("pCsrRoamInfo->nBeaconFrameLength = 0"); + return; + } + pBeaconIes = (u8 *) (pCsrRoamInfo->pbFrames + BEACON_FRAME_IES_OFFSET); + if (pBeaconIes == NULL) { + hdd_warn("Beacon IEs is NULL"); + return; + } + /* pBeaconIes needs to point to the IEs */ + hdd_notice("Beacon IEs is now at %02x%02x", + (unsigned int)pBeaconIes[0], + (unsigned int)pBeaconIes[1]); + hdd_notice("Beacon IEs length = %d", + pCsrRoamInfo->nBeaconLength - BEACON_FRAME_IES_OFFSET); + + /* We need to send the IEs to the supplicant. */ + buff = qdf_mem_malloc(IW_CUSTOM_MAX); + if (buff == NULL) { + hdd_err("unable to allocate memory"); + return; + } + + strLen = strlcpy(buff, "BEACONIEs=", IW_CUSTOM_MAX); + currentLen = strLen + 1; + + totalIeLen = pCsrRoamInfo->nBeaconLength - BEACON_FRAME_IES_OFFSET; + do { + /* + * If the beacon size exceeds max CUSTOM event size, break it + * into chunks of CUSTOM event max size and send it to + * supplicant. Changes are done in supplicant to handle this. + */ + qdf_mem_zero(&buff[strLen + 1], IW_CUSTOM_MAX - (strLen + 1)); + currentLen = + QDF_MIN(totalIeLen, IW_CUSTOM_MAX - (strLen + 1) - 1); + qdf_mem_copy(&buff[strLen + 1], pBeaconIes + currentOffset, + currentLen); + currentOffset += currentLen; + totalIeLen -= currentLen; + wrqu.data.length = strLen + 1 + currentLen; + if (totalIeLen) + buff[strLen] = 1; /* more chunks pending */ + else + buff[strLen] = 0; /* last chunk */ + + hdd_notice("Beacon IEs length to supplicant = %d", + currentLen); + wireless_send_event(pAdapter->dev, IWEVCUSTOM, &wrqu, buff); + } while (totalIeLen > 0); + + qdf_mem_free(buff); +} + +/** + * hdd_send_association_event() - send association event + * @dev: pointer to net device + * @pCsrRoamInfo: pointer to roam info + * + * Return: none + */ +static void hdd_send_association_event(struct net_device *dev, + tCsrRoamInfo *pCsrRoamInfo) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + union iwreq_data wrqu; + int we_event; + char *msg; + struct qdf_mac_addr peerMacAddr; + + /* Added to find the auth type on the fly at run time */ + /* rather than with cfg to see if FT is enabled */ + hdd_wext_state_t *pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter); + tCsrRoamProfile *pRoamProfile = &(pWextState->roamProfile); + + memset(&wrqu, '\0', sizeof(wrqu)); + wrqu.ap_addr.sa_family = ARPHRD_ETHER; + we_event = SIOCGIWAP; +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + if (NULL != pCsrRoamInfo) + if (pCsrRoamInfo->roamSynchInProgress) { + /* change logging before release */ + hdd_info("LFR3:hdd_send_association_event"); + /* Update tdls module about the disconnection event */ + wlan_hdd_tdls_notify_disconnect(pAdapter, true); + } +#endif + if (eConnectionState_Associated == pHddStaCtx->conn_info.connState) { + tSirSmeChanInfo chan_info; + + if (!pCsrRoamInfo) { + hdd_err("STA in associated state but pCsrRoamInfo is null"); + return; + } + + if (!hdd_is_roam_sync_in_progress(pCsrRoamInfo)) + cds_incr_active_session(pAdapter->device_mode, + pAdapter->sessionId); + memcpy(wrqu.ap_addr.sa_data, pCsrRoamInfo->pBssDesc->bssId, + sizeof(pCsrRoamInfo->pBssDesc->bssId)); + +#ifdef WLAN_FEATURE_P2P_DEBUG + if (pAdapter->device_mode == QDF_P2P_CLIENT_MODE) { + if (global_p2p_connection_status == + P2P_CLIENT_CONNECTING_STATE_1) { + global_p2p_connection_status = + P2P_CLIENT_CONNECTED_STATE_1; + hdd_warn("[P2P State] Changing state from Connecting state to Connected State for 8-way Handshake"); + } else if (global_p2p_connection_status == + P2P_CLIENT_CONNECTING_STATE_2) { + global_p2p_connection_status = + P2P_CLIENT_COMPLETED_STATE; + hdd_warn("[P2P State] Changing state from Connecting state to P2P Client Connection Completed"); + } + } +#endif + pr_info("wlan: " MAC_ADDRESS_STR " connected to " + MAC_ADDRESS_STR "\n", + MAC_ADDR_ARRAY(pAdapter->macAddressCurrent.bytes), + MAC_ADDR_ARRAY(wrqu.ap_addr.sa_data)); + hdd_send_update_beacon_ies_event(pAdapter, pCsrRoamInfo); + + /* + * Send IWEVASSOCRESPIE Event if WLAN_FEATURE_CIQ_METRICS + * is Enabled Or Send IWEVASSOCRESPIE Event if + * fFTEnable is true. + * Send FT Keys to the supplicant when FT is enabled + */ + if ((pRoamProfile->AuthType.authType[0] == + eCSR_AUTH_TYPE_FT_RSN_PSK) + || (pRoamProfile->AuthType.authType[0] == + eCSR_AUTH_TYPE_FT_RSN) +#ifdef FEATURE_WLAN_ESE + || (pRoamProfile->AuthType.authType[0] == + eCSR_AUTH_TYPE_CCKM_RSN) + || (pRoamProfile->AuthType.authType[0] == + eCSR_AUTH_TYPE_CCKM_WPA) +#endif + ) { + hdd_send_ft_assoc_response(dev, pAdapter, pCsrRoamInfo); + } + qdf_copy_macaddr(&peerMacAddr, + &pHddStaCtx->conn_info.bssId); + chan_info.chan_id = pCsrRoamInfo->chan_info.chan_id; + chan_info.mhz = pCsrRoamInfo->chan_info.mhz; + chan_info.info = pCsrRoamInfo->chan_info.info; + chan_info.band_center_freq1 = + pCsrRoamInfo->chan_info.band_center_freq1; + chan_info.band_center_freq2 = + pCsrRoamInfo->chan_info.band_center_freq2; + chan_info.reg_info_1 = + pCsrRoamInfo->chan_info.reg_info_1; + chan_info.reg_info_2 = + pCsrRoamInfo->chan_info.reg_info_2; + /* send peer status indication to oem app */ + hdd_send_peer_status_ind_to_oem_app(&peerMacAddr, + ePeerConnected, + pCsrRoamInfo-> + timingMeasCap, + pAdapter->sessionId, + &chan_info, + pAdapter->device_mode); + /* Update tdls module about connection event */ + wlan_hdd_tdls_notify_connect(pAdapter, pCsrRoamInfo); + +#ifdef MSM_PLATFORM +#if defined(CONFIG_ICNSS) || defined(CONFIG_CNSS) + /* start timer in sta/p2p_cli */ + spin_lock_bh(&pHddCtx->bus_bw_lock); + pAdapter->prev_tx_packets = pAdapter->stats.tx_packets; + pAdapter->prev_rx_packets = pAdapter->stats.rx_packets; + ol_get_intra_bss_fwd_pkts_count(pAdapter->sessionId, + &pAdapter->prev_fwd_tx_packets, + &pAdapter->prev_fwd_rx_packets); + spin_unlock_bh(&pHddCtx->bus_bw_lock); + hdd_bus_bw_compute_timer_start(pHddCtx); +#endif +#endif + } else if (eConnectionState_IbssConnected == /* IBss Associated */ + pHddStaCtx->conn_info.connState) { + cds_update_connection_info(pAdapter->sessionId); + memcpy(wrqu.ap_addr.sa_data, pHddStaCtx->conn_info.bssId.bytes, + ETH_ALEN); + hdd_err("wlan: new IBSS connection to " MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(pHddStaCtx->conn_info.bssId.bytes)); + } else { /* Not Associated */ + hdd_err("wlan: disconnected"); + memset(wrqu.ap_addr.sa_data, '\0', ETH_ALEN); + cds_decr_session_set_pcl(pAdapter->device_mode, + pAdapter->sessionId); + +#ifdef FEATURE_WLAN_AUTO_SHUTDOWN + wlan_hdd_auto_shutdown_enable(pHddCtx, true); +#endif + + if ((pAdapter->device_mode == QDF_STA_MODE) || + (pAdapter->device_mode == QDF_P2P_CLIENT_MODE)) { + qdf_copy_macaddr(&peerMacAddr, + &pHddStaCtx->conn_info.bssId); + + /* send peer status indication to oem app */ + hdd_send_peer_status_ind_to_oem_app(&peerMacAddr, + ePeerDisconnected, 0, + pAdapter->sessionId, + NULL, + pAdapter->device_mode); + } + hdd_lpass_notify_disconnect(pAdapter); + /* Update tdls module about the disconnection event */ + wlan_hdd_tdls_notify_disconnect(pAdapter, false); + +#ifdef MSM_PLATFORM + /* stop timer in sta/p2p_cli */ + spin_lock_bh(&pHddCtx->bus_bw_lock); + pAdapter->prev_tx_packets = 0; + pAdapter->prev_rx_packets = 0; + pAdapter->prev_fwd_tx_packets = 0; + pAdapter->prev_fwd_rx_packets = 0; + spin_unlock_bh(&pHddCtx->bus_bw_lock); + hdd_bus_bw_compute_timer_try_stop(pHddCtx); +#endif + } + cds_dump_concurrency_info(); + /* Send SCC/MCC Switching event to IPA */ + hdd_ipa_send_mcc_scc_msg(pHddCtx, pHddCtx->mcc_mode); + + msg = NULL; + /*During the WLAN uninitialization,supplicant is stopped before the + driver so not sending the status of the connection to supplicant */ + if (cds_is_load_or_unload_in_progress()) { + wireless_send_event(dev, we_event, &wrqu, msg); +#ifdef FEATURE_WLAN_ESE + if (eConnectionState_Associated == + pHddStaCtx->conn_info.connState) { + if ((pRoamProfile->AuthType.authType[0] == + eCSR_AUTH_TYPE_CCKM_RSN) || + (pRoamProfile->AuthType.authType[0] == + eCSR_AUTH_TYPE_CCKM_WPA)) + hdd_send_new_ap_channel_info(dev, pAdapter, + pCsrRoamInfo); + } +#endif + } +} + +/** + * hdd_conn_remove_connect_info() - remove connection info + * @pHddStaCtx: pointer to global HDD station context + * @pCsrRoamInfo: pointer to roam info + * + * Return: none + */ +static void hdd_conn_remove_connect_info(hdd_station_ctx_t *pHddStaCtx) +{ + /* Remove staId, bssId and peerMacAddress */ + pHddStaCtx->conn_info.staId[0] = 0; + qdf_mem_zero(&pHddStaCtx->conn_info.bssId, QDF_MAC_ADDR_SIZE); + qdf_mem_zero(&pHddStaCtx->conn_info.peerMacAddress[0], + QDF_MAC_ADDR_SIZE); + + /* Clear all security settings */ + pHddStaCtx->conn_info.authType = eCSR_AUTH_TYPE_OPEN_SYSTEM; + pHddStaCtx->conn_info.mcEncryptionType = eCSR_ENCRYPT_TYPE_NONE; + pHddStaCtx->conn_info.ucEncryptionType = eCSR_ENCRYPT_TYPE_NONE; + + qdf_mem_zero(&pHddStaCtx->conn_info.Keys, sizeof(tCsrKeys)); + qdf_mem_zero(&pHddStaCtx->ibss_enc_key, sizeof(tCsrRoamSetKey)); + + pHddStaCtx->conn_info.proxyARPService = 0; + + qdf_mem_zero(&pHddStaCtx->conn_info.SSID, sizeof(tCsrSSIDInfo)); +} + +/** + * hdd_roam_deregister_sta() - deregister station + * @pAdapter: pointer to adapter + * @staId: station identifier + * + * Return: QDF_STATUS enumeration + */ +QDF_STATUS hdd_roam_deregister_sta(hdd_adapter_t *pAdapter, uint8_t staId) +{ + QDF_STATUS qdf_status; + hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + + if (eConnectionState_IbssDisconnected == + pHddStaCtx->conn_info.connState) { + /* + * Do not set the carrier off when the last peer leaves. + * We will set the carrier off while stopping the IBSS. + */ + } + + qdf_status = ol_txrx_clear_peer(staId); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + hdd_err("ol_txrx_clear_peer() failed for staID %d. Status(%d) [0x%08X]", + staId, qdf_status, qdf_status); + } + return qdf_status; +} + +/** + * hdd_print_bss_info() - print bss info + * @hdd_sta_ctx: pointer to hdd station context + * + * Return: None + */ +static void hdd_print_bss_info(hdd_station_ctx_t *hdd_sta_ctx) +{ + uint32_t *cap_info; + + hdd_info("WIFI DATA LOGGER"); + hdd_info("channel: %d", + hdd_sta_ctx->conn_info.freq); + hdd_info("dot11mode: %d", + hdd_sta_ctx->conn_info.dot11Mode); + hdd_info("AKM: %d", + hdd_sta_ctx->conn_info.authType); + hdd_info("ssid: %.*s", + hdd_sta_ctx->conn_info.SSID.SSID.length, + hdd_sta_ctx->conn_info.SSID.SSID.ssId); + hdd_info("roam count: %d", + hdd_sta_ctx->conn_info.roam_count); + hdd_info("ant_info: %d", + hdd_sta_ctx->conn_info.txrate.nss); + hdd_info("datarate legacy %d", + hdd_sta_ctx->conn_info.txrate.legacy); + hdd_info("datarate mcs: %d", + hdd_sta_ctx->conn_info.txrate.mcs); + if (hdd_sta_ctx->conn_info.conn_flag.ht_present) { + cap_info = (uint32_t *)&hdd_sta_ctx->conn_info.ht_caps; + hdd_info("ht caps: %x", *cap_info); + } + if (hdd_sta_ctx->conn_info.conn_flag.vht_present) { + cap_info = (uint32_t *)&hdd_sta_ctx->conn_info.vht_caps; + hdd_info("vht caps: %x", *cap_info); + } + if (hdd_sta_ctx->conn_info.conn_flag.hs20_present) + hdd_info("hs20 info: %x", + hdd_sta_ctx->conn_info.hs20vendor_ie.release_num); + hdd_info("signal: %d", + hdd_sta_ctx->conn_info.signal); + hdd_info("noise: %d", + hdd_sta_ctx->conn_info.noise); +} + +/** + * hdd_dis_connect_handler() - disconnect event handler + * @pAdapter: pointer to adapter + * @pRoamInfo: pointer to roam info + * @roamId: roam identifier + * @roamStatus: roam status + * @roamResult: roam result + * + * This function handles disconnect event: + * 1. Disable transmit queues; + * 2. Clean up internal connection states and data structures; + * 3. Send disconnect indication to supplicant. + * + * Return: QDF_STATUS enumeration + */ +static QDF_STATUS hdd_dis_connect_handler(hdd_adapter_t *pAdapter, + tCsrRoamInfo *pRoamInfo, + uint32_t roamId, + eRoamCmdStatus roamStatus, + eCsrRoamResult roamResult) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + QDF_STATUS vstatus; + struct net_device *dev = pAdapter->dev; + hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + uint8_t sta_id; + bool sendDisconInd = true; + + if (dev == NULL) { + hdd_err("net_dev is released return"); + return QDF_STATUS_E_FAILURE; + } + /* notify apps that we can't pass traffic anymore */ + hdd_notice("Disabling queues"); + wlan_hdd_netif_queue_control(pAdapter, + WLAN_STOP_ALL_NETIF_QUEUE_N_CARRIER, + WLAN_CONTROL_PATH); + + if (hdd_ipa_is_enabled(pHddCtx)) + hdd_ipa_wlan_evt(pAdapter, pHddStaCtx->conn_info.staId[0], + HDD_IPA_STA_DISCONNECT, + pHddStaCtx->conn_info.bssId.bytes); + +#ifdef FEATURE_WLAN_AUTO_SHUTDOWN + wlan_hdd_auto_shutdown_enable(pHddCtx, true); +#endif + + DPTRACE(qdf_dp_trace_mgmt_pkt(QDF_DP_TRACE_MGMT_PACKET_RECORD, + pAdapter->sessionId, + QDF_PROTO_TYPE_MGMT, QDF_PROTO_MGMT_DISASSOC)); + + /* HDD has initiated disconnect, do not send disconnect indication + * to kernel. Sending disconnected event to kernel for userspace + * initiated disconnect will be handled by disconnect handler call + * to cfg80211_disconnected. + */ + if ((eConnectionState_Disconnecting == + pHddStaCtx->conn_info.connState) || + (eConnectionState_NotConnected == + pHddStaCtx->conn_info.connState)) { + hdd_notice("HDD has initiated a disconnect, no need to send disconnect indication to kernel"); + sendDisconInd = false; + } + + if (pHddStaCtx->conn_info.connState != eConnectionState_Disconnecting) { + INIT_COMPLETION(pAdapter->disconnect_comp_var); + hdd_conn_set_connection_state(pAdapter, + eConnectionState_Disconnecting); + } + + hdd_clear_roam_profile_ie(pAdapter); + hdd_wmm_init(pAdapter); + hdd_info("Invoking packetdump deregistration API"); + wlan_deregister_txrx_packetdump(); + + /* indicate 'disconnect' status to wpa_supplicant... */ + hdd_send_association_event(dev, pRoamInfo); + /* indicate disconnected event to nl80211 */ + if (roamStatus != eCSR_ROAM_IBSS_LEAVE) { + /* + * Only send indication to kernel if not initiated + * by kernel + */ + if (sendDisconInd) { + /* + * To avoid wpa_supplicant sending "HANGED" CMD + * to ICS UI. + */ + if (eCSR_ROAM_LOSTLINK == roamStatus) { + if (pRoamInfo->reasonCode == + eSIR_MAC_PEER_STA_REQ_LEAVING_BSS_REASON) + pr_info("wlan: disconnected due to poor signal, rssi is %d dB\n", pRoamInfo->rxRssi); + wlan_hdd_cfg80211_indicate_disconnect( + dev, false, + pRoamInfo->reasonCode); + } else { + wlan_hdd_cfg80211_indicate_disconnect( + dev, false, + WLAN_REASON_UNSPECIFIED + ); + } + + hdd_info("sent disconnected event to nl80211, reason code %d", + (eCSR_ROAM_LOSTLINK == roamStatus) ? + pRoamInfo->reasonCode : + WLAN_REASON_UNSPECIFIED); + } + /* + * During the WLAN uninitialization,supplicant is stopped + * before the driver so not sending the status of the + * connection to supplicant. + */ + if (cds_is_load_or_unload_in_progress()) { +#ifdef WLAN_FEATURE_P2P_DEBUG + if (pAdapter->device_mode == QDF_P2P_CLIENT_MODE) { + if (global_p2p_connection_status == + P2P_CLIENT_CONNECTED_STATE_1) { + global_p2p_connection_status = + P2P_CLIENT_DISCONNECTED_STATE; + hdd_err("[P2P State] 8 way Handshake completed and moved to disconnected state"); + } else if (global_p2p_connection_status == + P2P_CLIENT_COMPLETED_STATE) { + global_p2p_connection_status = + P2P_NOT_ACTIVE; + hdd_err("[P2P State] P2P Client is removed and moved to inactive state"); + } + } +#endif + + } + } + + hdd_wmm_adapter_clear(pAdapter); + sme_ft_reset(WLAN_HDD_GET_HAL_CTX(pAdapter), pAdapter->sessionId); + if (hdd_remove_beacon_filter(pAdapter) != 0) + hdd_warn("hdd_remove_beacon_filter() failed"); + + if (eCSR_ROAM_IBSS_LEAVE == roamStatus) { + uint8_t i; + sta_id = pHddStaCtx->broadcast_staid; + vstatus = hdd_roam_deregister_sta(pAdapter, sta_id); + if (!QDF_IS_STATUS_SUCCESS(vstatus)) { + hdd_err("hdd_roam_deregister_sta() failed for staID %d Status=%d [0x%x]", + sta_id, status, status); + status = QDF_STATUS_E_FAILURE; + } + pHddCtx->sta_to_adapter[sta_id] = NULL; + /* Clear all the peer sta register with TL. */ + for (i = 0; i < MAX_PEERS; i++) { + if (0 == pHddStaCtx->conn_info.staId[i]) + continue; + sta_id = pHddStaCtx->conn_info.staId[i]; + hdd_info("Deregister StaID %d", sta_id); + vstatus = hdd_roam_deregister_sta(pAdapter, sta_id); + if (!QDF_IS_STATUS_SUCCESS(vstatus)) { + hdd_err("hdd_roamDeregisterSTA() failed to for staID %d. Status= %d [0x%x]", + sta_id, status, status); + status = QDF_STATUS_E_FAILURE; + } + /* set the staid and peer mac as 0, all other + * reset are done in hdd_connRemoveConnectInfo. + */ + pHddStaCtx->conn_info.staId[i] = 0; + qdf_mem_zero(&pHddStaCtx->conn_info.peerMacAddress[i], + sizeof(struct qdf_mac_addr)); + if (sta_id < (WLAN_MAX_STA_COUNT + 3)) + pHddCtx->sta_to_adapter[sta_id] = NULL; + } + } else { + sta_id = pHddStaCtx->conn_info.staId[0]; + hdd_info("roamResult: %d", roamResult); + + /* clear scan cache for Link Lost */ + if (pRoamInfo && !pRoamInfo->reasonCode && + eCSR_ROAM_LOSTLINK == roamStatus) { + wlan_hdd_cfg80211_update_bss_list(pAdapter, + pHddStaCtx->conn_info.bssId.bytes); + sme_remove_bssid_from_scan_list(pHddCtx->hHal, + pHddStaCtx->conn_info.bssId.bytes); + } + pHddCtx->sta_to_adapter[sta_id] = NULL; + } + /* Clear saved connection information in HDD */ + hdd_conn_remove_connect_info(pHddStaCtx); + hdd_conn_set_connection_state(pAdapter, eConnectionState_NotConnected); +#ifdef WLAN_FEATURE_GTK_OFFLOAD + if ((QDF_STA_MODE == pAdapter->device_mode) || + (QDF_P2P_CLIENT_MODE == pAdapter->device_mode)) { + memset(&pHddStaCtx->gtkOffloadReqParams, 0, + sizeof(tSirGtkOffloadParams)); + pHddStaCtx->gtkOffloadReqParams.ulFlags = GTK_OFFLOAD_DISABLE; + } +#endif + +#ifdef FEATURE_WLAN_TDLS + if (eCSR_ROAM_IBSS_LEAVE != roamStatus) + wlan_hdd_tdls_disconnection_callback(pAdapter); +#endif + + if ((QDF_STA_MODE == pAdapter->device_mode) || + (QDF_P2P_CLIENT_MODE == pAdapter->device_mode)) { + sme_ps_disable_auto_ps_timer(WLAN_HDD_GET_HAL_CTX + (pAdapter), + pAdapter->sessionId); + } + wlan_hdd_clear_link_layer_stats(pAdapter); + + pAdapter->dad = false; + + /* Unblock anyone waiting for disconnect to complete */ + complete(&pAdapter->disconnect_comp_var); + hdd_print_bss_info(pHddStaCtx); + return status; +} + +/** + * hdd_set_peer_authorized_event() - set peer_authorized_event + * @vdev_id: vdevid + * + * Return: None + */ +static void hdd_set_peer_authorized_event(uint32_t vdev_id) +{ + hdd_context_t *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + hdd_adapter_t *adapter = NULL; + + adapter = hdd_get_adapter_by_vdev(hdd_ctx, vdev_id); + if (adapter == NULL) { + hdd_err("Invalid vdev_id"); + } + complete(&adapter->sta_authorized_event); +} + +/** + * hdd_change_peer_state() - change peer state + * @pAdapter: HDD adapter + * @sta_state: peer state + * @roam_synch_in_progress: roam synch in progress + * + * Return: QDF status + */ +QDF_STATUS hdd_change_peer_state(hdd_adapter_t *pAdapter, + uint8_t sta_id, + enum ol_txrx_peer_state sta_state, + bool roam_synch_in_progress) +{ + QDF_STATUS err; + uint8_t *peer_mac_addr; + struct ol_txrx_pdev_t *pdev = cds_get_context(QDF_MODULE_ID_TXRX); + ol_txrx_peer_handle peer; + + if (!pdev) { + hdd_err("Failed to get txrx context"); + return QDF_STATUS_E_FAULT; + } + + if (sta_id >= WLAN_MAX_STA_COUNT) { + hdd_err("Invalid sta id :%d", sta_id); + return QDF_STATUS_E_INVAL; + } + + peer = ol_txrx_peer_find_by_local_id(pdev, sta_id); + if (!peer) + return QDF_STATUS_E_FAULT; + + peer_mac_addr = ol_txrx_peer_get_peer_mac_addr(peer); + if (peer_mac_addr == NULL) { + hdd_err("peer mac addr is NULL"); + return QDF_STATUS_E_FAULT; + } + + err = ol_txrx_peer_state_update(pdev, peer_mac_addr, sta_state); + if (err != QDF_STATUS_SUCCESS) { + hdd_err("peer state update failed"); + return QDF_STATUS_E_FAULT; + } +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + if (roam_synch_in_progress) + return QDF_STATUS_SUCCESS; +#endif + + if (sta_state == OL_TXRX_PEER_STATE_AUTH) { +#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL + /* make sure event is reset */ + INIT_COMPLETION(pAdapter->sta_authorized_event); +#endif + + err = sme_set_peer_authorized(peer_mac_addr, + hdd_set_peer_authorized_event, + pAdapter->sessionId); + if (err != QDF_STATUS_SUCCESS) { + hdd_err("Failed to set the peer state to authorized"); + return QDF_STATUS_E_FAULT; + } + + if (pAdapter->device_mode == QDF_STA_MODE || + pAdapter->device_mode == QDF_P2P_CLIENT_MODE) { +#if defined(QCA_LL_LEGACY_TX_FLOW_CONTROL) || defined(QCA_LL_TX_FLOW_CONTROL_V2) + ol_txrx_vdev_handle vdev; + unsigned long rc; + + /* wait for event from firmware to set the event */ + rc = wait_for_completion_timeout( + &pAdapter->sta_authorized_event, + msecs_to_jiffies(HDD_PEER_AUTHORIZE_WAIT)); + if (!rc) { + hdd_notice("timeout waiting for sta_authorized_event"); + } + vdev = ol_txrx_get_vdev_for_peer(peer); + ol_txrx_vdev_unpause(vdev, + OL_TXQ_PAUSE_REASON_PEER_UNAUTHORIZED); +#endif + } + } + return QDF_STATUS_SUCCESS; +} + +/** + * hdd_roam_register_sta() - register station + * @pAdapter: pointer to adapter + * @pRoamInfo: pointer to roam info + * @staId: station identifier + * @pPeerMacAddress: peer MAC address + * @pBssDesc: pointer to BSS description + * + * Return: QDF_STATUS enumeration + */ +QDF_STATUS hdd_roam_register_sta(hdd_adapter_t *pAdapter, + tCsrRoamInfo *pRoamInfo, + uint8_t staId, + struct qdf_mac_addr *pPeerMacAddress, + tSirBssDescription *pBssDesc) +{ + QDF_STATUS qdf_status = QDF_STATUS_E_FAILURE; + struct ol_txrx_desc_type staDesc = { 0 }; + hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + struct ol_txrx_ops txrx_ops; + + if (NULL == pBssDesc) + return QDF_STATUS_E_FAILURE; + + /* Get the Station ID from the one saved during the association */ + staDesc.sta_id = staId; + + /* set the QoS field appropriately */ + if (hdd_wmm_is_active(pAdapter)) + staDesc.is_qos_enabled = 1; + else + staDesc.is_qos_enabled = 0; + +#ifdef FEATURE_WLAN_WAPI + hdd_notice("WAPI STA Registered: %d", + pAdapter->wapi_info.fIsWapiSta); + if (pAdapter->wapi_info.fIsWapiSta) + staDesc.is_wapi_supported = 1; + else + staDesc.is_wapi_supported = 0; +#endif /* FEATURE_WLAN_WAPI */ + + /* Register the vdev transmit and receive functions */ + qdf_mem_zero(&txrx_ops, sizeof(txrx_ops)); + txrx_ops.rx.rx = hdd_rx_packet_cbk; + ol_txrx_vdev_register( + ol_txrx_get_vdev_from_vdev_id(pAdapter->sessionId), + pAdapter, &txrx_ops); + pAdapter->tx_fn = txrx_ops.tx.tx; + + qdf_status = ol_txrx_register_peer(&staDesc); + + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + hdd_warn("ol_txrx_register_peer() failed to register. Status=%d [0x%08X]", + qdf_status, qdf_status); + return qdf_status; + } + + if (!pRoamInfo->fAuthRequired) { + /* + * Connections that do not need Upper layer auth, transition + * TLSHIM directly to 'Authenticated' state + */ + qdf_status = + hdd_change_peer_state(pAdapter, staDesc.sta_id, + OL_TXRX_PEER_STATE_AUTH, +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + pRoamInfo->roamSynchInProgress +#else + false +#endif + ); + + hdd_conn_set_authenticated(pAdapter, true); + } else { + hdd_info("ULA auth StaId= %d. Changing TL state to CONNECTED at Join time", + pHddStaCtx->conn_info.staId[0]); + qdf_status = + hdd_change_peer_state(pAdapter, staDesc.sta_id, + OL_TXRX_PEER_STATE_CONN, +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + pRoamInfo->roamSynchInProgress +#else + false +#endif + ); + hdd_conn_set_authenticated(pAdapter, false); + } + return qdf_status; +} + +/** + * hdd_send_re_assoc_event() - send reassoc event + * @dev: pointer to net device + * @pAdapter: pointer to adapter + * @pCsrRoamInfo: pointer to roam info + * @reqRsnIe: pointer to RSN Information element + * @reqRsnLength: length of RSN IE + * + * Return: none + */ +static void hdd_send_re_assoc_event(struct net_device *dev, + hdd_adapter_t *pAdapter, tCsrRoamInfo *pCsrRoamInfo, + uint8_t *reqRsnIe, uint32_t reqRsnLength) +{ + unsigned int len = 0; + u8 *pFTAssocRsp = NULL; + uint8_t *rspRsnIe = qdf_mem_malloc(IW_GENERIC_IE_MAX); + uint8_t *assoc_req_ies = qdf_mem_malloc(IW_GENERIC_IE_MAX); + uint32_t rspRsnLength = 0; + struct ieee80211_channel *chan; + uint8_t buf_ssid_ie[2 + SIR_MAC_SSID_EID_MAX]; /* 2 bytes-EID and len */ + uint8_t *buf_ptr, ssid_ie_len; + struct cfg80211_bss *bss = NULL; + uint8_t *final_req_ie = NULL; + tCsrRoamConnectedProfile roam_profile; + tHalHandle hal_handle = WLAN_HDD_GET_HAL_CTX(pAdapter); + + qdf_mem_zero(&roam_profile, sizeof(roam_profile)); + + if (!rspRsnIe) { + hdd_err("Unable to allocate RSN IE"); + goto done; + } + + if (!assoc_req_ies) { + hdd_err("Unable to allocate Assoc Req IE"); + goto done; + } + if (pCsrRoamInfo == NULL) { + hdd_err("Invalid CSR roam info"); + goto done; + } + + if (pCsrRoamInfo->nAssocRspLength == 0) { + hdd_err("Invalid assoc response length"); + goto done; + } + + pFTAssocRsp = + (u8 *) (pCsrRoamInfo->pbFrames + pCsrRoamInfo->nBeaconLength + + pCsrRoamInfo->nAssocReqLength); + if (pFTAssocRsp == NULL) + goto done; + + /* pFTAssocRsp needs to point to the IEs */ + pFTAssocRsp += FT_ASSOC_RSP_IES_OFFSET; + hdd_info("AssocRsp is now at %02x%02x", + (unsigned int)pFTAssocRsp[0], (unsigned int)pFTAssocRsp[1]); + + /* + * Active session count is decremented upon disconnection, but during + * roaming, there is no disconnect indication and hence active session + * count is not decremented. + * After roaming is completed, active session count is incremented + * as a part of connect indication but effectively after roaming the + * active session count should still be the same and hence upon + * successful reassoc decrement the active session count here. + */ + if (!hdd_is_roam_sync_in_progress(pCsrRoamInfo)) + cds_decr_session_set_pcl(pAdapter->device_mode, + pAdapter->sessionId); + + /* Send the Assoc Resp, the supplicant needs this for initial Auth */ + len = pCsrRoamInfo->nAssocRspLength - FT_ASSOC_RSP_IES_OFFSET; + rspRsnLength = len; + qdf_mem_copy(rspRsnIe, pFTAssocRsp, len); + qdf_mem_zero(rspRsnIe + len, IW_GENERIC_IE_MAX - len); + + chan = ieee80211_get_channel(pAdapter->wdev.wiphy, + (int)pCsrRoamInfo->pBssDesc->channelId); + sme_roam_get_connect_profile(hal_handle, pAdapter->sessionId, + &roam_profile); + + bss = hdd_cfg80211_get_bss(pAdapter->wdev.wiphy, + chan, pCsrRoamInfo->bssid.bytes, + &roam_profile.SSID.ssId[0], + roam_profile.SSID.length); + + if (bss == NULL) + hdd_warn("Get BSS returned NULL"); + buf_ptr = buf_ssid_ie; + *buf_ptr = SIR_MAC_SSID_EID; + buf_ptr++; + *buf_ptr = roam_profile.SSID.length; /*len of ssid*/ + buf_ptr++; + qdf_mem_copy(buf_ptr, &roam_profile.SSID.ssId[0], + roam_profile.SSID.length); + ssid_ie_len = 2 + roam_profile.SSID.length; + hdd_notice("SSIDIE:"); + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_DEBUG, + buf_ssid_ie, ssid_ie_len); + final_req_ie = qdf_mem_malloc(IW_GENERIC_IE_MAX); + if (final_req_ie == NULL) + goto done; + buf_ptr = final_req_ie; + qdf_mem_copy(buf_ptr, buf_ssid_ie, ssid_ie_len); + buf_ptr += ssid_ie_len; + qdf_mem_copy(buf_ptr, reqRsnIe, reqRsnLength); + qdf_mem_copy(rspRsnIe, pFTAssocRsp, len); + qdf_mem_zero(final_req_ie + (ssid_ie_len + reqRsnLength), + IW_GENERIC_IE_MAX - (ssid_ie_len + reqRsnLength)); + hdd_notice("Req RSN IE:"); + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_DEBUG, + final_req_ie, (ssid_ie_len + reqRsnLength)); + cfg80211_roamed_bss(dev, bss, + final_req_ie, (ssid_ie_len + reqRsnLength), + rspRsnIe, rspRsnLength, GFP_KERNEL); + + qdf_mem_copy(assoc_req_ies, + (u8 *)pCsrRoamInfo->pbFrames + pCsrRoamInfo->nBeaconLength, + pCsrRoamInfo->nAssocReqLength); + + hdd_notice("ReAssoc Req IE dump"); + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_DEBUG, + assoc_req_ies, pCsrRoamInfo->nAssocReqLength); + + wlan_hdd_send_roam_auth_event(pAdapter, pCsrRoamInfo->bssid.bytes, + assoc_req_ies, pCsrRoamInfo->nAssocReqLength, + rspRsnIe, rspRsnLength, + pCsrRoamInfo); +done: + sme_roam_free_connect_profile(&roam_profile); + if (final_req_ie) + qdf_mem_free(final_req_ie); + qdf_mem_free(rspRsnIe); + qdf_mem_free(assoc_req_ies); +} + +/** + * hdd_is_roam_sync_in_progress()- Check if roam offloaded + * @roaminfo - Roaming Information + * + * Return: roam sync status if roaming offloaded else false + */ +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +bool hdd_is_roam_sync_in_progress(tCsrRoamInfo *roaminfo) +{ + if (roaminfo) + return roaminfo->roamSynchInProgress; + else + return false; +} +#endif + + +/** + * hdd_change_sta_state_authenticated()- + * This function changes STA state to authenticated + * @adapter: pointer to the adapter structure. + * @roaminfo: pointer to the RoamInfo structure. + * + * This is called from hdd_RoamSetKeyCompleteHandler + * in context to eCSR_ROAM_SET_KEY_COMPLETE event from fw. + * + * Return: 0 on success and errno on failure + */ +static int hdd_change_sta_state_authenticated(hdd_adapter_t *adapter, + tCsrRoamInfo *roaminfo) +{ + int ret; + uint32_t timeout; + hdd_station_ctx_t *hddstactx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + + timeout = hddstactx->hdd_ReassocScenario ? + AUTO_PS_ENTRY_TIMER_DEFAULT_VALUE : + hdd_ctx->config->auto_bmps_timer_val * 1000; + + hdd_info("Changing TL state to AUTHENTICATED for StaId= %d", + hddstactx->conn_info.staId[0]); + + /* Connections that do not need Upper layer authentication, + * transition TL to 'Authenticated' state after the keys are set + */ + ret = hdd_change_peer_state(adapter, + hddstactx->conn_info.staId[0], + OL_TXRX_PEER_STATE_AUTH, + hdd_is_roam_sync_in_progress(roaminfo)); + hdd_conn_set_authenticated(adapter, true); + if ((QDF_STA_MODE == adapter->device_mode) || + (QDF_P2P_CLIENT_MODE == adapter->device_mode)) { + sme_ps_enable_auto_ps_timer( + WLAN_HDD_GET_HAL_CTX(adapter), + adapter->sessionId, + timeout, false); + } + + return ret; +} + +/** + * hdd_roam_set_key_complete_handler() - Update the security parameters + * @pAdapter: pointer to adapter + * @pRoamInfo: pointer to roam info + * @roamId: roam id + * @roamStatus: roam status + * @roamResult: roam result + * + * Return: QDF_STATUS enumeration + */ +static QDF_STATUS hdd_roam_set_key_complete_handler(hdd_adapter_t *pAdapter, + tCsrRoamInfo *pRoamInfo, + uint32_t roamId, + eRoamCmdStatus roamStatus, + eCsrRoamResult roamResult) +{ + eCsrEncryptionType connectedCipherAlgo; + bool fConnected = false; + QDF_STATUS qdf_status = QDF_STATUS_E_FAILURE; + hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + + ENTER(); + + if (NULL == pRoamInfo) { + hdd_info("pRoamInfo is NULL"); + return QDF_STATUS_E_FAILURE; + } + /* + * if (WPA), tell TL to go to 'authenticated' after the keys are set. + * then go to 'authenticated'. For all other authentication types + * (those that do not require upper layer authentication) we can put TL + * directly into 'authenticated' state. + */ + hdd_info("Set Key completion roamStatus =%d roamResult=%d " + MAC_ADDRESS_STR, roamStatus, roamResult, + MAC_ADDR_ARRAY(pRoamInfo->peerMac.bytes)); + + fConnected = hdd_conn_get_connected_cipher_algo(pHddStaCtx, + &connectedCipherAlgo); + if (fConnected) { + if (QDF_IBSS_MODE == pAdapter->device_mode) { + uint8_t staId; + + if (qdf_is_macaddr_broadcast(&pRoamInfo->peerMac)) { + pHddStaCtx->roam_info.roamingState = + HDD_ROAM_STATE_NONE; + } else { + qdf_status = hdd_get_peer_sta_id( + pHddStaCtx, + &pRoamInfo->peerMac, + &staId); + if (QDF_STATUS_SUCCESS == qdf_status) { + hdd_info("WLAN TL STA Ptk Installed for STAID=%d", + staId); + pHddStaCtx->roam_info.roamingState = + HDD_ROAM_STATE_NONE; + } + } + } else { + /* + * TODO: Considering getting a state machine in + * HDD later.This routine is invoked twice. + * 1)set PTK 2)set GTK.The following if + * statement will be TRUE when setting GTK. + * At this time we don't handle the state in detail. + * Related CR: 174048 - TL not in authenticated state + */ + if (eCSR_ROAM_RESULT_AUTHENTICATED == roamResult) { + pHddStaCtx->conn_info.gtk_installed = true; + /* + * PTK exchange happens in preauthentication + * itself if key_mgmt is FT-PSK, ptk_installed + * was false as there is no set PTK after + * roaming. STA TL state moves to authenticated + * only if ptk_installed is true. So, make + * ptk_installed to true in case of 11R roaming. + */ + if (sme_neighbor_roam_is11r_assoc( + WLAN_HDD_GET_HAL_CTX(pAdapter), + pAdapter->sessionId)) + pHddStaCtx->conn_info.ptk_installed = + true; + } else { + pHddStaCtx->conn_info.ptk_installed = true; + } + + /* In WPA case move STA to authenticated when + * ptk is installed.Earlier in WEP case STA + * was moved to AUTHENTICATED prior to setting + * the unicast key and it was resulting in sending + * few un-encrypted packet. Now in WEP case + * STA state will be moved to AUTHENTICATED + * after we set the unicast and broadcast key. + */ + if ((pHddStaCtx->conn_info.ucEncryptionType == + eCSR_ENCRYPT_TYPE_WEP40) || + (pHddStaCtx->conn_info.ucEncryptionType == + eCSR_ENCRYPT_TYPE_WEP104) || + (pHddStaCtx->conn_info.ucEncryptionType == + eCSR_ENCRYPT_TYPE_WEP40_STATICKEY) || + (pHddStaCtx->conn_info.ucEncryptionType == + eCSR_ENCRYPT_TYPE_WEP104_STATICKEY)) { + if (pHddStaCtx->conn_info.gtk_installed && + pHddStaCtx->conn_info.ptk_installed) + qdf_status = + hdd_change_sta_state_authenticated(pAdapter, + pRoamInfo); + } else if (pHddStaCtx->conn_info.ptk_installed) { + qdf_status = + hdd_change_sta_state_authenticated(pAdapter, + pRoamInfo); + } + + if (pHddStaCtx->conn_info.gtk_installed && + pHddStaCtx->conn_info.ptk_installed) { + pHddStaCtx->conn_info.gtk_installed = false; + pHddStaCtx->conn_info.ptk_installed = false; + } + + pHddStaCtx->roam_info.roamingState = + HDD_ROAM_STATE_NONE; + } + } else { + /* + * possible disassoc after issuing set key and waiting + * set key complete. + */ + pHddStaCtx->roam_info.roamingState = HDD_ROAM_STATE_NONE; + } + + EXIT(); + return QDF_STATUS_SUCCESS; +} + +/** + * hdd_perform_roam_set_key_complete() - perform set key complete + * @pAdapter: pointer to adapter + * + * Return: none + */ +void hdd_perform_roam_set_key_complete(hdd_adapter_t *pAdapter) +{ + QDF_STATUS qdf_ret_status = QDF_STATUS_SUCCESS; + hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + tCsrRoamInfo roamInfo; + roamInfo.fAuthRequired = false; + qdf_mem_copy(roamInfo.bssid.bytes, + pHddStaCtx->roam_info.bssid, QDF_MAC_ADDR_SIZE); + qdf_mem_copy(roamInfo.peerMac.bytes, + pHddStaCtx->roam_info.peerMac, QDF_MAC_ADDR_SIZE); + + qdf_ret_status = + hdd_roam_set_key_complete_handler(pAdapter, + &roamInfo, + pHddStaCtx->roam_info.roamId, + pHddStaCtx->roam_info.roamStatus, + eCSR_ROAM_RESULT_AUTHENTICATED); + if (qdf_ret_status != QDF_STATUS_SUCCESS) + hdd_err("Set Key complete failure"); + + pHddStaCtx->roam_info.deferKeyComplete = false; +} + +/** + * hdd_association_completion_handler() - association completion handler + * @pAdapter: pointer to adapter + * @pRoamInfo: pointer to roam info + * @roamId: roam id + * @roamStatus: roam status + * @roamResult: roam result + * + * Return: QDF_STATUS enumeration + */ +static QDF_STATUS hdd_association_completion_handler(hdd_adapter_t *pAdapter, + tCsrRoamInfo *pRoamInfo, + uint32_t roamId, + eRoamCmdStatus roamStatus, + eCsrRoamResult roamResult) +{ + struct net_device *dev = pAdapter->dev; + hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + QDF_STATUS qdf_status = QDF_STATUS_E_FAILURE; + uint8_t reqRsnIe[DOT11F_IE_RSN_MAX_LEN]; + uint32_t reqRsnLength = DOT11F_IE_RSN_MAX_LEN, ie_len; + int ft_carrier_on = false; + bool hddDisconInProgress = false; + unsigned long rc; + tSirResultCodes timeout_reason = 0; + + if (!pHddCtx) { + hdd_err("HDD context is NULL"); + return QDF_STATUS_E_FAILURE; + } + + /* validate config */ + if (!pHddCtx->config) { + hdd_err("config is NULL"); + return QDF_STATUS_E_NULL_VALUE; + } + /* HDD has initiated disconnect, do not send connect result indication + * to kernel as it will be handled by __cfg80211_disconnect. + */ + if (((eConnectionState_Disconnecting == + pHddStaCtx->conn_info.connState) || + (eConnectionState_NotConnected == + pHddStaCtx->conn_info.connState)) && + ((eCSR_ROAM_RESULT_ASSOCIATED == roamResult) || + (eCSR_ROAM_ASSOCIATION_FAILURE == roamStatus))) { + hdd_info("Disconnect from HDD in progress"); + hddDisconInProgress = true; + } + + if (eCSR_ROAM_RESULT_ASSOCIATED == roamResult) { + if (NULL == pRoamInfo) { + hdd_err("pRoamInfo is NULL"); + return QDF_STATUS_E_FAILURE; + } + if (!hddDisconInProgress) { + hdd_conn_set_connection_state(pAdapter, + eConnectionState_Associated); + } + /* Save the connection info from CSR... */ + hdd_conn_save_connect_info(pAdapter, pRoamInfo, + eCSR_BSS_TYPE_INFRASTRUCTURE); + + if (hdd_add_beacon_filter(pAdapter) != 0) + hdd_err("hdd_add_beacon_filter() failed"); +#ifdef FEATURE_WLAN_WAPI + if (pRoamInfo->u.pConnectedProfile->AuthType == + eCSR_AUTH_TYPE_WAPI_WAI_CERTIFICATE + || pRoamInfo->u.pConnectedProfile->AuthType == + eCSR_AUTH_TYPE_WAPI_WAI_PSK) { + pAdapter->wapi_info.fIsWapiSta = 1; + } else { + pAdapter->wapi_info.fIsWapiSta = 0; + } +#endif /* FEATURE_WLAN_WAPI */ + hdd_debug("bss_descr[%d] devicemode[%d]", !!pRoamInfo->pBssDesc, + pAdapter->device_mode); + if ((QDF_STA_MODE == pAdapter->device_mode) && + pRoamInfo->pBssDesc) { + ie_len = GET_IE_LEN_IN_BSS(pRoamInfo->pBssDesc->length); + pHddStaCtx->ap_supports_immediate_power_save = + wlan_hdd_is_ap_supports_immediate_power_save( + (uint8_t *) pRoamInfo->pBssDesc->ieFields, + ie_len); + hdd_debug("ap_supports_immediate_power_save flag [%d]", + pHddStaCtx->ap_supports_immediate_power_save); + } + + /* Indicate 'connect' status to user space */ + hdd_send_association_event(dev, pRoamInfo); + + if (cds_is_mcc_in_24G()) { + if (pHddCtx->miracast_value) + cds_set_mas(pAdapter, pHddCtx->miracast_value); + } + + /* Initialize the Linkup event completion variable */ + INIT_COMPLETION(pAdapter->linkup_event_var); + + /* + * Sometimes Switching ON the Carrier is taking time to activate + * the device properly. Before allowing any packet to go up to + * the application, device activation has to be ensured for + * proper queue mapping by the kernel. we have registered net + * device notifier for device change notification. With this we + * will come to know that the device is getting + * activated properly. + */ + if (pHddStaCtx->ft_carrier_on == false) { + /* + * Enable Linkup Event Servicing which allows the net + * device notifier to set the linkup event variable. + */ + pAdapter->isLinkUpSvcNeeded = true; + + /* Switch on the Carrier to activate the device */ + wlan_hdd_netif_queue_control(pAdapter, + WLAN_NETIF_CARRIER_ON, + WLAN_CONTROL_PATH); + + /* + * Wait for the Link to up to ensure all the queues + * are set properly by the kernel. + */ + rc = wait_for_completion_timeout( + &pAdapter->linkup_event_var, + msecs_to_jiffies(ASSOC_LINKUP_TIMEOUT) + ); + if (!rc) + hdd_warn("Warning:ASSOC_LINKUP_TIMEOUT"); + + /* + * Disable Linkup Event Servicing - no more service + * required from the net device notifier call. + */ + pAdapter->isLinkUpSvcNeeded = false; + } else { + pHddStaCtx->ft_carrier_on = false; + ft_carrier_on = true; + } + if ((WLAN_MAX_STA_COUNT + 3) > pRoamInfo->staId) + pHddCtx->sta_to_adapter[pRoamInfo->staId] = pAdapter; + else + hdd_warn("Wrong Staid: %d", pRoamInfo->staId); + + pHddCtx->sta_to_adapter[pRoamInfo->staId] = pAdapter; + + if (hdd_ipa_is_enabled(pHddCtx)) + hdd_ipa_wlan_evt(pAdapter, pRoamInfo->staId, + HDD_IPA_STA_CONNECT, + pRoamInfo->bssid.bytes); + +#ifdef FEATURE_WLAN_AUTO_SHUTDOWN + wlan_hdd_auto_shutdown_enable(pHddCtx, false); +#endif + + hdd_info("check for SAP restart"); + cds_check_concurrent_intf_and_restart_sap(pAdapter); + + DPTRACE(qdf_dp_trace_mgmt_pkt(QDF_DP_TRACE_MGMT_PACKET_RECORD, + pAdapter->sessionId, + QDF_PROTO_TYPE_MGMT, QDF_PROTO_MGMT_ASSOC)); + + /* + * For reassoc, the station is already registered, all we need + * is to change the state of the STA in TL. + * If authentication is required (WPA/WPA2/DWEP), change TL to + * CONNECTED instead of AUTHENTICATED. + */ + if (!pRoamInfo->fReassocReq) { + struct cfg80211_bss *bss; + u8 *pFTAssocRsp = NULL; + unsigned int assocRsplen = 0; + u8 *pFTAssocReq = NULL; + unsigned int assocReqlen = 0; + struct ieee80211_channel *chan; + uint8_t rspRsnIe[DOT11F_IE_RSN_MAX_LEN]; + uint32_t rspRsnLength = DOT11F_IE_RSN_MAX_LEN; + + /* add bss_id to cfg80211 data base */ + bss = + wlan_hdd_cfg80211_update_bss_db(pAdapter, + pRoamInfo); + if (NULL == bss) { + hdd_err("wlan: Not able to create BSS entry"); + wlan_hdd_netif_queue_control(pAdapter, + WLAN_NETIF_CARRIER_OFF, + WLAN_CONTROL_PATH); + if (!hddDisconInProgress) { + /* + * Here driver was not able to add bss + * in cfg80211 database this can happen + * if connected channel is not valid, + * i.e reg domain was changed during + * connection. Queue disconnect for the + * session if disconnect is not in + * progress. + */ + hdd_err("Disconnecting..."); + sme_roam_disconnect( + WLAN_HDD_GET_HAL_CTX(pAdapter), + pAdapter->sessionId, + eCSR_DISCONNECT_REASON_UNSPECIFIED); + } + return QDF_STATUS_E_FAILURE; + } + if (pRoamInfo->u.pConnectedProfile->AuthType == + eCSR_AUTH_TYPE_FT_RSN + || pRoamInfo->u.pConnectedProfile->AuthType == + eCSR_AUTH_TYPE_FT_RSN_PSK) { + + /* Association Response */ + pFTAssocRsp = + (u8 *) (pRoamInfo->pbFrames + + pRoamInfo->nBeaconLength + + pRoamInfo->nAssocReqLength); + if (pFTAssocRsp != NULL) { + /* + * pFTAssocRsp needs to point to the IEs + */ + pFTAssocRsp += FT_ASSOC_RSP_IES_OFFSET; + hdd_info("AssocRsp is now at %02x%02x", + (unsigned int)pFTAssocRsp[0], + (unsigned int)pFTAssocRsp[1]); + assocRsplen = + pRoamInfo->nAssocRspLength - + FT_ASSOC_RSP_IES_OFFSET; + } else { + hdd_warn("AssocRsp is NULL"); + assocRsplen = 0; + } + + /* Association Request */ + pFTAssocReq = (u8 *) (pRoamInfo->pbFrames + + pRoamInfo->nBeaconLength); + if (pFTAssocReq != NULL) { + if (!ft_carrier_on) { + /* + * pFTAssocReq needs to point to + * the IEs + */ + pFTAssocReq += + FT_ASSOC_REQ_IES_OFFSET; + hdd_info("pFTAssocReq is now at %02x%02x", + (unsigned int) + pFTAssocReq[0], + (unsigned int) + pFTAssocReq[1]); + assocReqlen = + pRoamInfo->nAssocReqLength - + FT_ASSOC_REQ_IES_OFFSET; + } else { + /* + * This should contain only the + * FTIEs + */ + assocReqlen = + pRoamInfo->nAssocReqLength; + } + } else { + hdd_warn("AssocReq is NULL"); + assocReqlen = 0; + } + + if (ft_carrier_on) { + if (!hddDisconInProgress) { + struct cfg80211_bss *roam_bss; + + /* + * After roaming is completed, + * active session count is + * incremented as a part of + * connect indication but + * effectively the active + * session count should still + * be the same and hence upon + * successful reassoc + * decrement the active session + * count here. + */ + if (!hdd_is_roam_sync_in_progress + (pRoamInfo)) + cds_decr_session_set_pcl + (pAdapter->device_mode, + pAdapter->sessionId); + hdd_info("ft_carrier_on is %d, sending roamed indication", + ft_carrier_on); + chan = + ieee80211_get_channel + (pAdapter->wdev.wiphy, + (int)pRoamInfo->pBssDesc-> + channelId); + hdd_info( + "assocReqlen %d assocRsplen %d", + assocReqlen, + assocRsplen); + + hdd_notice( + "Reassoc Req IE dump"); + QDF_TRACE_HEX_DUMP( + QDF_MODULE_ID_HDD, + QDF_TRACE_LEVEL_DEBUG, + pFTAssocReq, + assocReqlen); + roam_bss = + hdd_cfg80211_get_bss( + pAdapter->wdev.wiphy, + chan, + pRoamInfo->bssid.bytes, + pRoamInfo->u. + pConnectedProfile->SSID.ssId, + pRoamInfo->u. + pConnectedProfile->SSID.length); + cfg80211_roamed_bss(dev, + roam_bss, + pFTAssocReq, + assocReqlen, + pFTAssocRsp, + assocRsplen, + GFP_KERNEL); + wlan_hdd_send_roam_auth_event( + pAdapter, + pRoamInfo->bssid.bytes, + pFTAssocReq, + assocReqlen, + pFTAssocRsp, + assocRsplen, + pRoamInfo); + } + if (sme_get_ftptk_state + (WLAN_HDD_GET_HAL_CTX(pAdapter), + pAdapter->sessionId)) { + sme_set_ftptk_state + (WLAN_HDD_GET_HAL_CTX + (pAdapter), + pAdapter->sessionId, + false); + pRoamInfo->fAuthRequired = + false; + + qdf_mem_copy(pHddStaCtx-> + roam_info.bssid, + pRoamInfo->bssid.bytes, + QDF_MAC_ADDR_SIZE); + qdf_mem_copy(pHddStaCtx-> + roam_info.peerMac, + pRoamInfo->peerMac.bytes, + QDF_MAC_ADDR_SIZE); + pHddStaCtx->roam_info.roamId = + roamId; + pHddStaCtx->roam_info. + roamStatus = roamStatus; + pHddStaCtx->roam_info. + deferKeyComplete = true; + } + } else if (!hddDisconInProgress) { + hdd_info("ft_carrier_on is %d, sending connect indication", + ft_carrier_on); + hdd_connect_result(dev, + pRoamInfo-> + bssid.bytes, + pRoamInfo, + pFTAssocReq, + assocReqlen, + pFTAssocRsp, + assocRsplen, + WLAN_STATUS_SUCCESS, + GFP_KERNEL, + false, + pRoamInfo-> + statusCode); + } + } else { + /* + * wpa supplicant expecting WPA/RSN IE in + * connect result. + */ + csr_roam_get_wpa_rsn_req_ie(WLAN_HDD_GET_HAL_CTX + (pAdapter), + pAdapter->sessionId, + &reqRsnLength, + reqRsnIe); + + csr_roam_get_wpa_rsn_rsp_ie(WLAN_HDD_GET_HAL_CTX + (pAdapter), + pAdapter->sessionId, + &rspRsnLength, + rspRsnIe); + if (!hddDisconInProgress) { + if (ft_carrier_on) + hdd_send_re_assoc_event(dev, + pAdapter, + pRoamInfo, + reqRsnIe, + reqRsnLength); + else { + hdd_info("sending connect indication to nl80211:for bssid " + MAC_ADDRESS_STR + " result:%d and Status:%d", + MAC_ADDR_ARRAY + (pRoamInfo->bssid.bytes), + roamResult, roamStatus); + + /* inform connect result to nl80211 */ + hdd_connect_result(dev, + pRoamInfo-> + bssid.bytes, + pRoamInfo, + reqRsnIe, + reqRsnLength, + rspRsnIe, + rspRsnLength, + WLAN_STATUS_SUCCESS, + GFP_KERNEL, + false, + pRoamInfo-> + statusCode); + } + } + } + if (!hddDisconInProgress) { + cfg80211_put_bss( + pHddCtx->wiphy, + bss); + + /* + * Perform any WMM-related association + * processing. + */ + hdd_wmm_assoc(pAdapter, pRoamInfo, + eCSR_BSS_TYPE_INFRASTRUCTURE); + + /* + * Start the Queue - Start tx queues before + * hdd_roam_register_sta, since + * hdd_roam_register_sta will flush any cached + * data frames immediately. + */ + hdd_info("Enabling queues"); + wlan_hdd_netif_queue_control(pAdapter, + WLAN_WAKE_ALL_NETIF_QUEUE, + WLAN_CONTROL_PATH); + + /* + * Register the Station with TL after associated + */ + qdf_status = hdd_roam_register_sta(pAdapter, + pRoamInfo, + pHddStaCtx-> + conn_info. + staId[0], + NULL, + pRoamInfo-> + pBssDesc); + } + } else { + /* + * wpa supplicant expecting WPA/RSN IE in connect result + * in case of reassociation also need to indicate it to + * supplicant. + */ + csr_roam_get_wpa_rsn_req_ie( + WLAN_HDD_GET_HAL_CTX(pAdapter), + pAdapter->sessionId, + &reqRsnLength, reqRsnIe); + + hdd_send_re_assoc_event(dev, pAdapter, pRoamInfo, + reqRsnIe, reqRsnLength); + /* Reassoc successfully */ + if (pRoamInfo->fAuthRequired) { + qdf_status = + hdd_change_peer_state(pAdapter, + pHddStaCtx->conn_info.staId[0], + OL_TXRX_PEER_STATE_CONN, +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + pRoamInfo->roamSynchInProgress +#else + false +#endif + ); + hdd_conn_set_authenticated(pAdapter, false); + } else { + hdd_info("staId: %d Changing TL state to AUTHENTICATED", + pHddStaCtx->conn_info.staId[0]); + qdf_status = + hdd_change_peer_state(pAdapter, + pHddStaCtx->conn_info.staId[0], + OL_TXRX_PEER_STATE_AUTH, +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + pRoamInfo->roamSynchInProgress +#else + false +#endif + ); + hdd_conn_set_authenticated(pAdapter, true); + } + + if (QDF_IS_STATUS_SUCCESS(qdf_status)) { + /* + * Perform any WMM-related association + * processing + */ + hdd_wmm_assoc(pAdapter, pRoamInfo, + eCSR_BSS_TYPE_INFRASTRUCTURE); + } + + /* Start the tx queues */ +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + if (pRoamInfo->roamSynchInProgress) + hdd_info("LFR3:netif_tx_wake_all_queues"); +#endif + hdd_info("Enabling queues"); + wlan_hdd_netif_queue_control(pAdapter, + WLAN_WAKE_ALL_NETIF_QUEUE, + WLAN_CONTROL_PATH); + } + +#ifdef FEATURE_WLAN_TDLS + wlan_hdd_tdls_connection_callback(pAdapter); +#endif + + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + hdd_err("STA register with TL failed. status(=%d) [%08X]", + qdf_status, qdf_status); + } +#ifdef WLAN_FEATURE_11W + qdf_mem_zero(&pAdapter->hdd_stats.hddPmfStats, + sizeof(pAdapter->hdd_stats.hddPmfStats)); +#endif + } else { + bool connect_timeout = false; + hdd_wext_state_t *pWextState = + WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter); + if (pRoamInfo) + hdd_err("wlan: connection failed with " MAC_ADDRESS_STR + " result:%d and Status:%d", + MAC_ADDR_ARRAY(pRoamInfo->bssid.bytes), + roamResult, roamStatus); + else + hdd_err("wlan: connection failed with " MAC_ADDRESS_STR + " result:%d and Status:%d", + MAC_ADDR_ARRAY(pWextState->req_bssId.bytes), + roamResult, roamStatus); + + if ((eCSR_ROAM_RESULT_SCAN_FOR_SSID_FAILURE == roamResult) || + (pRoamInfo && + ((eSIR_SME_JOIN_TIMEOUT_RESULT_CODE == + pRoamInfo->statusCode) || + (eSIR_SME_AUTH_TIMEOUT_RESULT_CODE == + pRoamInfo->statusCode) || + (eSIR_SME_ASSOC_TIMEOUT_RESULT_CODE == + pRoamInfo->statusCode)))) { + wlan_hdd_cfg80211_update_bss_list(pAdapter, + pRoamInfo ? + pRoamInfo->bssid.bytes : + pWextState->req_bssId.bytes); + sme_remove_bssid_from_scan_list(pHddCtx->hHal, + pRoamInfo ? + pRoamInfo->bssid.bytes : + pWextState->req_bssId.bytes); + connect_timeout = true; + } + + /* + * CR465478: Only send up a connection failure result when CSR + * has completed operation - with a ASSOCIATION_FAILURE status. + */ + if (eCSR_ROAM_ASSOCIATION_FAILURE == roamStatus + && !hddDisconInProgress) { + if (pRoamInfo) { + hdd_err("send connect failure to nl80211: for bssid " + MAC_ADDRESS_STR + " result:%d and Status:%d reasoncode %d", + MAC_ADDR_ARRAY(pRoamInfo->bssid.bytes), + roamResult, roamStatus, + pRoamInfo->reasonCode); + pHddStaCtx->conn_info.assoc_status_code = + pRoamInfo->statusCode; + } else { + hdd_err("connect failed: for bssid " + MAC_ADDRESS_STR + " result:%d and Status:%d ", + MAC_ADDR_ARRAY(pWextState->req_bssId.bytes), + roamResult, roamStatus); + } + hdd_err("Invoking packetdump deregistration API"); + wlan_deregister_txrx_packetdump(); + + /* inform association failure event to nl80211 */ + if (eCSR_ROAM_RESULT_ASSOC_FAIL_CON_CHANNEL == + roamResult) { + if (pRoamInfo) + hdd_connect_result(dev, + pRoamInfo->bssid.bytes, + NULL, NULL, 0, NULL, 0, + WLAN_STATUS_ASSOC_DENIED_UNSPEC, + GFP_KERNEL, + connect_timeout, + pRoamInfo->statusCode); + else + hdd_connect_result(dev, + pWextState->req_bssId.bytes, + NULL, NULL, 0, NULL, 0, + WLAN_STATUS_ASSOC_DENIED_UNSPEC, + GFP_KERNEL, + connect_timeout, + timeout_reason); + } else { + if (pRoamInfo) + hdd_connect_result(dev, + pRoamInfo->bssid.bytes, + NULL, NULL, 0, NULL, 0, + pRoamInfo->reasonCode ? + pRoamInfo->reasonCode : + WLAN_STATUS_UNSPECIFIED_FAILURE, + GFP_KERNEL, + connect_timeout, + pRoamInfo->statusCode); + else + hdd_connect_result(dev, + pWextState->req_bssId.bytes, + NULL, NULL, 0, NULL, 0, + WLAN_STATUS_UNSPECIFIED_FAILURE, + GFP_KERNEL, + connect_timeout, + timeout_reason); + } + hdd_clear_roam_profile_ie(pAdapter); + } else if ((eCSR_ROAM_CANCELLED == roamStatus + && !hddDisconInProgress)) { + hdd_connect_result(dev, + pWextState->req_bssId.bytes, + NULL, NULL, 0, NULL, 0, + WLAN_STATUS_UNSPECIFIED_FAILURE, + GFP_KERNEL, + connect_timeout, + timeout_reason); + } + + /* + * Set connection state to eConnectionState_NotConnected only + * when CSR has completed operation - with a + * ASSOCIATION_FAILURE or eCSR_ROAM_CANCELLED status. + */ + if (((eCSR_ROAM_ASSOCIATION_FAILURE == roamStatus) || + (eCSR_ROAM_CANCELLED == roamStatus)) + && !hddDisconInProgress) { + hdd_conn_set_connection_state(pAdapter, + eConnectionState_NotConnected); + } + hdd_wmm_init(pAdapter); + + hdd_info("Disabling queues"); + wlan_hdd_netif_queue_control(pAdapter, + WLAN_STOP_ALL_NETIF_QUEUE_N_CARRIER, + WLAN_CONTROL_PATH); + } + + if (QDF_STATUS_SUCCESS != cds_check_and_restart_sap( + roamResult, pHddStaCtx)) + return QDF_STATUS_E_FAILURE; + + if (NULL != pRoamInfo && NULL != pRoamInfo->pBssDesc) { + cds_force_sap_on_scc(roamResult, + pRoamInfo->pBssDesc->channelId); + } else { + hdd_err("pRoamInfo profile is not set properly"); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * hdd_roam_ibss_indication_handler() - update the status of the IBSS + * @pAdapter: pointer to adapter + * @pRoamInfo: pointer to roam info + * @roamId: roam id + * @roamStatus: roam status + * @roamResult: roam result + * + * Here we update the status of the Ibss when we receive information that we + * have started/joined an ibss session. + * + * Return: none + */ +static void hdd_roam_ibss_indication_handler(hdd_adapter_t *pAdapter, + tCsrRoamInfo *pRoamInfo, + uint32_t roamId, + eRoamCmdStatus roamStatus, + eCsrRoamResult roamResult) +{ + hdd_info("%s: id %d, status %d, result %d", + pAdapter->dev->name, roamId, + roamStatus, roamResult); + + switch (roamResult) { + /* both IBSS Started and IBSS Join should come in here. */ + case eCSR_ROAM_RESULT_IBSS_STARTED: + case eCSR_ROAM_RESULT_IBSS_JOIN_SUCCESS: + case eCSR_ROAM_RESULT_IBSS_COALESCED: + { + hdd_context_t *pHddCtx = + (hdd_context_t *) pAdapter->pHddCtx; + hdd_station_ctx_t *hdd_sta_ctx = + WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + struct qdf_mac_addr broadcastMacAddr = + QDF_MAC_ADDR_BROADCAST_INITIALIZER; + + if (NULL == pRoamInfo) { + QDF_ASSERT(0); + return; + } + + /* When IBSS Started comes from CSR, we need to move + * connection state to IBSS Disconnected (meaning no peers + * are in the IBSS). + */ + hdd_conn_set_connection_state(pAdapter, + eConnectionState_IbssDisconnected); + /* notify wmm */ + hdd_wmm_connect(pAdapter, pRoamInfo, + eCSR_BSS_TYPE_IBSS); + + hdd_sta_ctx->broadcast_staid = pRoamInfo->staId; + + pHddCtx->sta_to_adapter[pRoamInfo->staId] = + pAdapter; + hdd_roam_register_sta(pAdapter, pRoamInfo, + pRoamInfo->staId, + &broadcastMacAddr, + pRoamInfo->pBssDesc); + + if (pRoamInfo->pBssDesc) { + struct cfg80211_bss *bss; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0)) + struct ieee80211_channel *chan; + int chan_no; + unsigned int freq; +#endif + /* we created the IBSS, notify supplicant */ + hdd_info("%s: created ibss " MAC_ADDRESS_STR, + pAdapter->dev->name, + MAC_ADDR_ARRAY( + pRoamInfo->pBssDesc->bssId)); + + /* we must first give cfg80211 the BSS information */ + bss = wlan_hdd_cfg80211_update_bss_db(pAdapter, + pRoamInfo); + if (NULL == bss) { + hdd_err("%s: unable to create IBSS entry", + pAdapter->dev->name); + return; + } + hdd_info("Enabling queues"); + wlan_hdd_netif_queue_control(pAdapter, + WLAN_START_ALL_NETIF_QUEUE_N_CARRIER, + WLAN_CONTROL_PATH); + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0)) + chan_no = pRoamInfo->pBssDesc->channelId; + + if (chan_no <= 14) + freq = ieee80211_channel_to_frequency(chan_no, + NL80211_BAND_2GHZ); + else + freq = ieee80211_channel_to_frequency(chan_no, + NL80211_BAND_5GHZ); + + chan = ieee80211_get_channel(pAdapter->wdev.wiphy, freq); + + if (chan) + cfg80211_ibss_joined(pAdapter->dev, + bss->bssid, chan, + GFP_KERNEL); + else + hdd_err("%s: chanId: %d, can't find channel", + pAdapter->dev->name, + (int)pRoamInfo->pBssDesc->channelId); +#else + cfg80211_ibss_joined(pAdapter->dev, bss->bssid, + GFP_KERNEL); +#endif + cfg80211_put_bss( + pHddCtx->wiphy, + bss); + } + if (eCSR_ROAM_RESULT_IBSS_STARTED == roamResult) { + cds_incr_active_session(pAdapter->device_mode, + pAdapter->sessionId); + } else if (eCSR_ROAM_RESULT_IBSS_JOIN_SUCCESS == roamResult || + eCSR_ROAM_RESULT_IBSS_COALESCED == roamResult) { + cds_update_connection_info(pAdapter->sessionId); + } + break; + } + + case eCSR_ROAM_RESULT_IBSS_START_FAILED: + { + hdd_err("%s: unable to create IBSS", pAdapter->dev->name); + break; + } + + default: + hdd_err("%s: unexpected result %d", + pAdapter->dev->name, (int)roamResult); + break; + } + + return; +} + +/** + * hdd_save_peer() - Save peer MAC address in adapter peer table. + * @sta_ctx: pointer to hdd station context + * @sta_id: station ID + * @peer_mac_addr: mac address of new peer + * + * This information is passed to iwconfig later. The peer that joined + * last is passed as information to iwconfig. + + * Return: true if success, false otherwise + */ +bool hdd_save_peer(hdd_station_ctx_t *sta_ctx, uint8_t sta_id, + struct qdf_mac_addr *peer_mac_addr) +{ + int idx; + + for (idx = 0; idx < SIR_MAX_NUM_STA_IN_IBSS; idx++) { + if (0 == sta_ctx->conn_info.staId[idx]) { + hdd_info("adding peer: %pM, sta_id: %d, at idx: %d", + peer_mac_addr, sta_id, idx); + sta_ctx->conn_info.staId[idx] = sta_id; + qdf_copy_macaddr( + &sta_ctx->conn_info.peerMacAddress[idx], + peer_mac_addr); + return true; + } + } + return false; +} + +/** + * hdd_delete_peer() - removes peer from hdd station context peer table + * @sta_ctx: pointer to hdd station context + * @sta_id: station ID + * + * Return: None + */ +void hdd_delete_peer(hdd_station_ctx_t *sta_ctx, uint8_t sta_id) +{ + int i; + + for (i = 0; i < SIR_MAX_NUM_STA_IN_IBSS; i++) { + if (sta_id == sta_ctx->conn_info.staId[i]) { + sta_ctx->conn_info.staId[i] = 0; + return; + } + } + + hdd_err(FL("sta_id %d is not present in peer table"), sta_id); +} + +/** + * roam_remove_ibss_station() - Remove the IBSS peer MAC address in the adapter + * @pAdapter: pointer to adapter + * @staId: station id + * + * Return: + * true if we remove MAX_PEERS or less STA + * false otherwise. + */ +static bool roam_remove_ibss_station(hdd_adapter_t *pAdapter, uint8_t staId) +{ + bool fSuccess = false; + int idx = 0; + uint8_t valid_idx = 0; + uint8_t del_idx = 0; + uint8_t empty_slots = 0; + hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + + for (idx = 0; idx < MAX_PEERS; idx++) { + if (staId == pHddStaCtx->conn_info.staId[idx]) { + pHddStaCtx->conn_info.staId[idx] = 0; + + qdf_zero_macaddr(&pHddStaCtx->conn_info. + peerMacAddress[idx]); + + fSuccess = true; + + /* + * Note the deleted Index, if its 0 we need special + * handling. + */ + del_idx = idx; + + empty_slots++; + } else { + if (pHddStaCtx->conn_info.staId[idx] != 0) { + valid_idx = idx; + } else { + /* Found an empty slot */ + empty_slots++; + } + } + } + + if (MAX_PEERS == empty_slots) { + /* Last peer departed, set the IBSS state appropriately */ + pHddStaCtx->conn_info.connState = + eConnectionState_IbssDisconnected; + hdd_err("Last IBSS Peer Departed!!!"); + } + /* Find next active staId, to have a valid sta trigger for TL. */ + if (fSuccess == true) { + if (del_idx == 0) { + if (pHddStaCtx->conn_info.staId[valid_idx] != 0) { + pHddStaCtx->conn_info.staId[0] = + pHddStaCtx->conn_info.staId[valid_idx]; + qdf_copy_macaddr(&pHddStaCtx->conn_info. + peerMacAddress[0], + &pHddStaCtx->conn_info. + peerMacAddress[valid_idx]); + + pHddStaCtx->conn_info.staId[valid_idx] = 0; + qdf_zero_macaddr(&pHddStaCtx->conn_info. + peerMacAddress[valid_idx]); + } + } + } + return fSuccess; +} + +/** + * roam_ibss_connect_handler() - IBSS connection handler + * @pAdapter: pointer to adapter + * @pRoamInfo: pointer to roam info + * + * We update the status of the IBSS to connected in this function. + * + * Return: QDF_STATUS enumeration + */ +static QDF_STATUS roam_ibss_connect_handler(hdd_adapter_t *pAdapter, + tCsrRoamInfo *pRoamInfo) +{ + struct cfg80211_bss *bss; + /* + * Set the internal connection state to show 'IBSS Connected' (IBSS with + * a partner stations). + */ + hdd_conn_set_connection_state(pAdapter, eConnectionState_IbssConnected); + + /* Save the connection info from CSR... */ + hdd_conn_save_connect_info(pAdapter, pRoamInfo, eCSR_BSS_TYPE_IBSS); + + /* Send the bssid address to the wext. */ + hdd_send_association_event(pAdapter->dev, pRoamInfo); + /* add bss_id to cfg80211 data base */ + bss = wlan_hdd_cfg80211_update_bss_db(pAdapter, pRoamInfo); + if (NULL == bss) { + hdd_err("%s: unable to create IBSS entry", + pAdapter->dev->name); + return QDF_STATUS_E_FAILURE; + } + cfg80211_put_bss( + WLAN_HDD_GET_CTX(pAdapter)->wiphy, + bss); + + return QDF_STATUS_SUCCESS; +} + +/** + * hdd_roam_mic_error_indication_handler() - MIC error indication handler + * @pAdapter: pointer to adapter + * @pRoamInfo: pointer to roam info + * @roamId: roam id + * @roamStatus: roam status + * @roamResult: roam result + * + * This function indicates the Mic failure to the supplicant + * + * Return: QDF_STATUS enumeration + */ +static QDF_STATUS +hdd_roam_mic_error_indication_handler(hdd_adapter_t *pAdapter, + tCsrRoamInfo *pRoamInfo, + uint32_t roamId, + eRoamCmdStatus roamStatus, + eCsrRoamResult roamResult) +{ + hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + + if (eConnectionState_Associated == pHddStaCtx->conn_info.connState && + TKIP_COUNTER_MEASURE_STOPED == + pHddStaCtx->WextState.mTKIPCounterMeasures) { + struct iw_michaelmicfailure msg; + union iwreq_data wreq; + memset(&msg, '\0', sizeof(msg)); + msg.src_addr.sa_family = ARPHRD_ETHER; + memcpy(msg.src_addr.sa_data, + pRoamInfo->u.pMICFailureInfo->taMacAddr, + sizeof(pRoamInfo->u.pMICFailureInfo->taMacAddr)); + hdd_info("MIC MAC " MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(msg.src_addr.sa_data)); + + if (pRoamInfo->u.pMICFailureInfo->multicast == eSIR_TRUE) + msg.flags = IW_MICFAILURE_GROUP; + else + msg.flags = IW_MICFAILURE_PAIRWISE; + memset(&wreq, 0, sizeof(wreq)); + wreq.data.length = sizeof(msg); + wireless_send_event(pAdapter->dev, IWEVMICHAELMICFAILURE, &wreq, + (char *)&msg); + /* inform mic failure to nl80211 */ + cfg80211_michael_mic_failure(pAdapter->dev, + pRoamInfo->u.pMICFailureInfo-> + taMacAddr, + ((pRoamInfo->u.pMICFailureInfo-> + multicast == + eSIR_TRUE) ? + NL80211_KEYTYPE_GROUP : + NL80211_KEYTYPE_PAIRWISE), + pRoamInfo->u.pMICFailureInfo-> + keyId, + pRoamInfo->u.pMICFailureInfo->TSC, + GFP_KERNEL); + + } + + return QDF_STATUS_SUCCESS; +} + +/** + * roam_roam_connect_status_update_handler() - IBSS connect status update + * @pAdapter: pointer to adapter + * @pRoamInfo: pointer to roam info + * @roamId: roam id + * @roamStatus: roam status + * @roamResult: roam result + * + * The Ibss connection status is updated regularly here in this function. + * + * Return: QDF_STATUS enumeration + */ +static QDF_STATUS +roam_roam_connect_status_update_handler(hdd_adapter_t *pAdapter, + tCsrRoamInfo *pRoamInfo, + uint32_t roamId, + eRoamCmdStatus roamStatus, + eCsrRoamResult roamResult) +{ + QDF_STATUS qdf_status; + + hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + switch (roamResult) { + case eCSR_ROAM_RESULT_IBSS_NEW_PEER: + { + hdd_station_ctx_t *pHddStaCtx = + WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + struct station_info *stainfo; + + hdd_info("IBSS New Peer indication from SME " + "with peerMac " MAC_ADDRESS_STR " BSSID: " + MAC_ADDRESS_STR " and stationID= %d", + MAC_ADDR_ARRAY(pRoamInfo->peerMac.bytes), + MAC_ADDR_ARRAY(pHddStaCtx->conn_info.bssId.bytes), + pRoamInfo->staId); + + if (!hdd_save_peer + (WLAN_HDD_GET_STATION_CTX_PTR(pAdapter), + pRoamInfo->staId, + &pRoamInfo->peerMac)) { + hdd_warn("Max reached: Can't register new IBSS peer"); + break; + } + + pHddCtx->sta_to_adapter[pRoamInfo->staId] = pAdapter; + + /* Register the Station with TL for the new peer. */ + qdf_status = hdd_roam_register_sta(pAdapter, + pRoamInfo, + pRoamInfo->staId, + &pRoamInfo->peerMac, + pRoamInfo->pBssDesc); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + hdd_err("Cannot register STA with TL for IBSS. Failed with qdf_status = %d [%08X]", + qdf_status, qdf_status); + } + pHddStaCtx->ibss_sta_generation++; + stainfo = qdf_mem_malloc(sizeof(*stainfo)); + if (stainfo == NULL) { + hdd_err("memory allocation for station_info failed"); + return QDF_STATUS_E_NOMEM; + } + stainfo->filled = 0; + stainfo->generation = pHddStaCtx->ibss_sta_generation; + + cfg80211_new_sta(pAdapter->dev, + (const u8 *)pRoamInfo->peerMac.bytes, + stainfo, GFP_KERNEL); + qdf_mem_free(stainfo); + + if (eCSR_ENCRYPT_TYPE_WEP40_STATICKEY == + pHddStaCtx->ibss_enc_key.encType + || eCSR_ENCRYPT_TYPE_WEP104_STATICKEY == + pHddStaCtx->ibss_enc_key.encType + || eCSR_ENCRYPT_TYPE_TKIP == + pHddStaCtx->ibss_enc_key.encType + || eCSR_ENCRYPT_TYPE_AES == + pHddStaCtx->ibss_enc_key.encType) { + pHddStaCtx->ibss_enc_key.keyDirection = + eSIR_TX_RX; + qdf_copy_macaddr(&pHddStaCtx->ibss_enc_key.peerMac, + &pRoamInfo->peerMac); + + hdd_info("New peer joined set PTK encType=%d", + pHddStaCtx->ibss_enc_key.encType); + + qdf_status = + sme_roam_set_key(WLAN_HDD_GET_HAL_CTX + (pAdapter), + pAdapter->sessionId, + &pHddStaCtx->ibss_enc_key, + &roamId); + + if (QDF_STATUS_SUCCESS != qdf_status) { + hdd_err("sme_roam_set_key failed, status=%d", + qdf_status); + return QDF_STATUS_E_FAILURE; + } + } + hdd_info("Enabling queues"); + wlan_hdd_netif_queue_control(pAdapter, + WLAN_START_ALL_NETIF_QUEUE_N_CARRIER, + WLAN_CONTROL_PATH); + break; + } + + case eCSR_ROAM_RESULT_IBSS_CONNECT: + { + + roam_ibss_connect_handler(pAdapter, pRoamInfo); + + break; + } + case eCSR_ROAM_RESULT_IBSS_PEER_DEPARTED: + { + hdd_station_ctx_t *pHddStaCtx = + WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + + if (!roam_remove_ibss_station(pAdapter, pRoamInfo->staId)) + hdd_warn("IBSS peer departed by cannot find peer in our registration table with TL"); + + hdd_info("IBSS Peer Departed from SME " + "with peerMac " MAC_ADDRESS_STR " BSSID: " + MAC_ADDRESS_STR " and stationID= %d", + MAC_ADDR_ARRAY(pRoamInfo->peerMac.bytes), + MAC_ADDR_ARRAY(pHddStaCtx->conn_info.bssId.bytes), + pRoamInfo->staId); + + hdd_roam_deregister_sta(pAdapter, pRoamInfo->staId); + + pHddCtx->sta_to_adapter[pRoamInfo->staId] = NULL; + pHddStaCtx->ibss_sta_generation++; + + cfg80211_del_sta(pAdapter->dev, + (const u8 *)&pRoamInfo->peerMac.bytes, + GFP_KERNEL); + break; + } + case eCSR_ROAM_RESULT_IBSS_INACTIVE: + { + hdd_info("Received eCSR_ROAM_RESULT_IBSS_INACTIVE from SME"); + /* Stop only when we are inactive */ + hdd_info("Disabling queues"); + wlan_hdd_netif_queue_control(pAdapter, + WLAN_STOP_ALL_NETIF_QUEUE_N_CARRIER, + WLAN_CONTROL_PATH); + hdd_conn_set_connection_state(pAdapter, + eConnectionState_NotConnected); + + /* Send the bssid address to the wext. */ + hdd_send_association_event(pAdapter->dev, pRoamInfo); + break; + } + default: + break; + + } + + return QDF_STATUS_SUCCESS; +} + +#ifdef FEATURE_WLAN_TDLS +/** + * hdd_roam_register_tdlssta() - register new TDLS station + * @pAdapter: pointer to adapter + * @peerMac: pointer to peer MAC address + * @staId: station identifier + * @ucastSig: unicast signature + * @qos: QOS capability of TDLS station/link + * + * Construct the staDesc and register with TL the new STA. + * This is called as part of ADD_STA in the TDLS setup. + * + * Return: QDF_STATUS enumeration + */ +QDF_STATUS hdd_roam_register_tdlssta(hdd_adapter_t *pAdapter, + const uint8_t *peerMac, uint16_t staId, + uint8_t ucastSig, uint8_t qos) +{ + QDF_STATUS qdf_status = QDF_STATUS_E_FAILURE; + struct ol_txrx_desc_type staDesc = { 0 }; + struct ol_txrx_ops txrx_ops; + + /* + * TDLS sta in BSS should be set as STA type TDLS and STA MAC should + * be peer MAC, here we are working on direct Link + */ + staDesc.sta_id = staId; + + /* set the QoS field appropriately .. */ + staDesc.is_qos_enabled = qos; + + /* Register the vdev transmit and receive functions */ + qdf_mem_zero(&txrx_ops, sizeof(txrx_ops)); + txrx_ops.rx.rx = hdd_rx_packet_cbk; + ol_txrx_vdev_register( + ol_txrx_get_vdev_from_vdev_id(pAdapter->sessionId), + pAdapter, &txrx_ops); + pAdapter->tx_fn = txrx_ops.tx.tx; + + /* Register the Station with TL... */ + qdf_status = ol_txrx_register_peer(&staDesc); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + hdd_err("ol_txrx_register_peer() failed to register. Status=%d [0x%08X]", + qdf_status, qdf_status); + return qdf_status; + } + + return qdf_status; +} + +/** + * hdd_roam_deregister_tdlssta() - deregister new TDLS station + * @pAdapter: pointer to adapter + * @staId: station identifier + * + * Return: QDF_STATUS enumeration + */ +QDF_STATUS hdd_roam_deregister_tdlssta(hdd_adapter_t *pAdapter, uint8_t staId) +{ + QDF_STATUS qdf_status; + qdf_status = ol_txrx_clear_peer(staId); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + hdd_warn("ol_txrx_clear_peer() failed for staID %d. Status=%d [0x%08X]", + staId, qdf_status, qdf_status); + } + return qdf_status; +} + +/** + * hdd_tdls_connection_tracker_update() - update connection tracker state + * @adapter: pointer to adapter + * @roam_info: pointer to roam info + * @hdd_tdls_ctx: tdls context + * + * Return: QDF_STATUS enumeration + */ +static QDF_STATUS hdd_tdls_connection_tracker_update(hdd_adapter_t *adapter, + tCsrRoamInfo *roam_info, + tdlsCtx_t *hdd_tdls_ctx) +{ + hddTdlsPeer_t *curr_peer; + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + + curr_peer = wlan_hdd_tdls_find_peer(adapter, + roam_info->peerMac.bytes); + + if (!curr_peer) { + hdd_err("curr_peer is null"); + return QDF_STATUS_E_FAILURE; + } + + if (eTDLS_LINK_CONNECTED == + curr_peer->link_status) { + hdd_notice("Received CONNECTION_TRACKER_NOTIFICATION " + MAC_ADDRESS_STR + " staId: %d, reason: %d", + MAC_ADDR_ARRAY(roam_info->peerMac.bytes), + roam_info->staId, + roam_info->reasonCode); + + if (roam_info->reasonCode == + eWNI_TDLS_PEER_ENTER_BUF_STA || + roam_info->reasonCode == + eWNI_TDLS_ENTER_BT_BUSY_MODE || + roam_info->reasonCode == + eWMI_TDLS_SCAN_STARTED_EVENT) + hdd_ctx->enable_tdls_connection_tracker = false; + else if (roam_info->reasonCode == + eWNI_TDLS_PEER_EXIT_BUF_STA || + roam_info->reasonCode == + eWNI_TDLS_EXIT_BT_BUSY_MODE || + roam_info->reasonCode == + eWMI_TDLS_SCAN_COMPLETED_EVENT) + hdd_ctx->enable_tdls_connection_tracker = true; + hdd_info("hdd_ctx->enable_tdls_connection_tracker %d", + hdd_ctx->enable_tdls_connection_tracker); + } else { + hdd_err("TDLS not connected, ignore notification, reason: %d", + roam_info->reasonCode); + } + + return QDF_STATUS_SUCCESS; +} + + + + +/** + * hdd_roam_tdls_status_update_handler() - TDLS status update handler + * @pAdapter: pointer to adapter + * @pRoamInfo: pointer to roam info + * @roamId: roam id + * @roamStatus: roam status + * @roamResult: roam result + * + * HDD interface between SME and TL to ensure TDLS client registration with + * TL in case of new TDLS client is added and deregistration at the time + * TDLS client is deleted. + * + * Return: QDF_STATUS enumeration + */ +static QDF_STATUS +hdd_roam_tdls_status_update_handler(hdd_adapter_t *pAdapter, + tCsrRoamInfo *pRoamInfo, + uint32_t roamId, + eRoamCmdStatus roamStatus, + eCsrRoamResult roamResult) +{ + hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + tdlsCtx_t *pHddTdlsCtx; + tSmeTdlsPeerStateParams smeTdlsPeerStateParams; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + uint8_t staIdx; + hddTdlsPeer_t *curr_peer; + uint32_t reason; + + hdd_info("hdd_tdlsStatusUpdate: %s staIdx %d " MAC_ADDRESS_STR, + roamResult == + eCSR_ROAM_RESULT_ADD_TDLS_PEER ? "ADD_TDLS_PEER" : roamResult + == + eCSR_ROAM_RESULT_DELETE_TDLS_PEER ? "DEL_TDLS_PEER" : + roamResult == + eCSR_ROAM_RESULT_TEARDOWN_TDLS_PEER_IND ? "DEL_TDLS_PEER_IND" + : roamResult == + eCSR_ROAM_RESULT_DELETE_ALL_TDLS_PEER_IND ? + "DEL_ALL_TDLS_PEER_IND" : roamResult == + eCSR_ROAM_RESULT_UPDATE_TDLS_PEER ? "UPDATE_TDLS_PEER" : + roamResult == + eCSR_ROAM_RESULT_LINK_ESTABLISH_REQ_RSP ? + "LINK_ESTABLISH_REQ_RSP" : roamResult == + eCSR_ROAM_RESULT_TDLS_SHOULD_DISCOVER ? "TDLS_SHOULD_DISCOVER" + : roamResult == + eCSR_ROAM_RESULT_TDLS_SHOULD_TEARDOWN ? "TDLS_SHOULD_TEARDOWN" + : roamResult == + eCSR_ROAM_RESULT_TDLS_SHOULD_PEER_DISCONNECTED ? + "TDLS_SHOULD_PEER_DISCONNECTED" : "UNKNOWN", pRoamInfo->staId, + MAC_ADDR_ARRAY(pRoamInfo->peerMac.bytes)); + + switch (roamResult) { + case eCSR_ROAM_RESULT_ADD_TDLS_PEER: + { + if (eSIR_SME_SUCCESS != pRoamInfo->statusCode) { + hdd_err("Add Sta failed. status code(=%d)", + pRoamInfo->statusCode); + pAdapter->tdlsAddStaStatus = QDF_STATUS_E_FAILURE; + + } else { + /* + * Check if there is available index for this new TDLS + * STA. + */ + for (staIdx = 0; + staIdx < pHddCtx->max_num_tdls_sta; + staIdx++) { + if (0 == + pHddCtx->tdlsConnInfo[staIdx]. + staId) { + pHddCtx->tdlsConnInfo[staIdx]. + sessionId = + pRoamInfo->sessionId; + pHddCtx->tdlsConnInfo[staIdx]. + staId = pRoamInfo->staId; + + hdd_warn("TDLS: STA IDX at %d is %d " + "of mac " + MAC_ADDRESS_STR, + staIdx, + pHddCtx-> + tdlsConnInfo[staIdx]. + staId, + MAC_ADDR_ARRAY + (pRoamInfo->peerMac.bytes)); + + qdf_copy_macaddr(&pHddCtx-> + tdlsConnInfo + [staIdx]. + peerMac, + &pRoamInfo-> + peerMac); + status = QDF_STATUS_SUCCESS; + break; + } + } + if (staIdx < pHddCtx->max_num_tdls_sta) { + if (-1 == + wlan_hdd_tdls_set_sta_id(pAdapter, + pRoamInfo-> + peerMac.bytes, + pRoamInfo-> + staId)) { + hdd_err("wlan_hdd_tdls_set_sta_id() failed"); + return QDF_STATUS_E_FAILURE; + } + + (WLAN_HDD_GET_CTX(pAdapter))-> + sta_to_adapter[pRoamInfo->staId] = + pAdapter; + /* + * store the ucast signature, + * if required for further reference. + */ + + wlan_hdd_tdls_set_signature(pAdapter, + pRoamInfo-> + peerMac.bytes, + pRoamInfo-> + ucastSig); + } else { + status = QDF_STATUS_E_FAILURE; + hdd_err("no available slot in conn_info. staId %d cannot be stored", + pRoamInfo->staId); + } + pAdapter->tdlsAddStaStatus = status; + } + complete(&pAdapter->tdls_add_station_comp); + break; + } + case eCSR_ROAM_RESULT_UPDATE_TDLS_PEER: + { + if (eSIR_SME_SUCCESS != pRoamInfo->statusCode) { + hdd_err("Add Sta failed. status code(=%d)", + pRoamInfo->statusCode); + } + /* store the ucast signature which will be used later when + * registering to TL + */ + pAdapter->tdlsAddStaStatus = pRoamInfo->statusCode; + complete(&pAdapter->tdls_add_station_comp); + break; + } + case eCSR_ROAM_RESULT_LINK_ESTABLISH_REQ_RSP: + { + if (eSIR_SME_SUCCESS != pRoamInfo->statusCode) { + hdd_err("Link Establish Request failed. status(=%d)", + pRoamInfo->statusCode); + } + complete(&pAdapter->tdls_link_establish_req_comp); + break; + } + case eCSR_ROAM_RESULT_DELETE_TDLS_PEER: + { + for (staIdx = 0; staIdx < pHddCtx->max_num_tdls_sta; + staIdx++) { + if ((pHddCtx->tdlsConnInfo[staIdx].sessionId == + pRoamInfo->sessionId) + && pRoamInfo->staId == + pHddCtx->tdlsConnInfo[staIdx].staId) { + hdd_notice("HDD: del STA IDX = %x", + pRoamInfo->staId); + mutex_lock(&pHddCtx->tdls_lock); + curr_peer = + wlan_hdd_tdls_find_peer(pAdapter, + pRoamInfo-> + peerMac.bytes); + if (NULL != curr_peer) { + hdd_info("Current status for peer " MAC_ADDRESS_STR " is %d", + MAC_ADDR_ARRAY(pRoamInfo->peerMac.bytes), + curr_peer->link_status); + if (TDLS_IS_CONNECTED(curr_peer)) { + mutex_unlock(&pHddCtx->tdls_lock); + hdd_roam_deregister_tdlssta + (pAdapter, + pRoamInfo->staId); + wlan_hdd_tdls_decrement_peer_count + (pAdapter); + } else if (eTDLS_LINK_CONNECTING == + curr_peer->link_status) { + mutex_unlock(&pHddCtx->tdls_lock); + hdd_roam_deregister_tdlssta + (pAdapter, + pRoamInfo->staId); + } else + mutex_unlock(&pHddCtx->tdls_lock); + } else + mutex_unlock(&pHddCtx->tdls_lock); + + mutex_lock(&pHddCtx->tdls_lock); + wlan_hdd_tdls_reset_peer(pAdapter, + pRoamInfo-> + peerMac.bytes); + mutex_unlock(&pHddCtx->tdls_lock); + + pHddCtx->tdlsConnInfo[staIdx].staId = 0; + pHddCtx->tdlsConnInfo[staIdx]. + sessionId = 255; + qdf_mem_zero(&pHddCtx-> + tdlsConnInfo[staIdx]. + peerMac, + QDF_MAC_ADDR_SIZE); + status = QDF_STATUS_SUCCESS; + break; + } + } + complete(&pAdapter->tdls_del_station_comp); + } + break; + case eCSR_ROAM_RESULT_TEARDOWN_TDLS_PEER_IND: + { + hdd_notice("Sending teardown to supplicant with reason code %u", + pRoamInfo->reasonCode); + + mutex_lock(&pHddCtx->tdls_lock); + curr_peer = + wlan_hdd_tdls_find_peer(pAdapter, + pRoamInfo->peerMac.bytes); + + if (!curr_peer) { + mutex_unlock(&pHddCtx->tdls_lock); + hdd_debug("peer doesn't exists"); + status = QDF_STATUS_SUCCESS; + break; + } + + wlan_hdd_tdls_indicate_teardown(pAdapter, curr_peer, + pRoamInfo->reasonCode); + hdd_send_wlan_tdls_teardown_event(eTDLS_TEARDOWN_BSS_DISCONNECT, + curr_peer->peerMac); + mutex_unlock(&pHddCtx->tdls_lock); + status = QDF_STATUS_SUCCESS; + break; + } + case eCSR_ROAM_RESULT_DELETE_ALL_TDLS_PEER_IND: + { + /* 0 staIdx is assigned to AP we dont want to touch that */ + for (staIdx = 0; staIdx < pHddCtx->max_num_tdls_sta; + staIdx++) { + if ((pHddCtx->tdlsConnInfo[staIdx].sessionId == + pRoamInfo->sessionId) + && pHddCtx->tdlsConnInfo[staIdx].staId) { + hdd_warn("hdd_tdlsStatusUpdate: staIdx %d " + MAC_ADDRESS_STR, + pHddCtx->tdlsConnInfo[staIdx]. + staId, + MAC_ADDR_ARRAY(pHddCtx-> + tdlsConnInfo + [staIdx]. + peerMac. + bytes)); + mutex_lock(&pHddCtx->tdls_lock); + wlan_hdd_tdls_reset_peer(pAdapter, + pHddCtx-> + tdlsConnInfo + [staIdx]. + peerMac.bytes); + mutex_unlock(&pHddCtx->tdls_lock); + hdd_roam_deregister_tdlssta(pAdapter, + pHddCtx-> + tdlsConnInfo + [staIdx]. + staId); + qdf_mem_zero(&smeTdlsPeerStateParams, + sizeof + (smeTdlsPeerStateParams)); + smeTdlsPeerStateParams.vdevId = + pHddCtx->tdlsConnInfo[staIdx]. + sessionId; + qdf_mem_copy(&smeTdlsPeerStateParams. + peerMacAddr, + &pHddCtx-> + tdlsConnInfo[staIdx]. + peerMac.bytes, + QDF_MAC_ADDR_SIZE); + smeTdlsPeerStateParams.peerState = + eSME_TDLS_PEER_STATE_TEARDOWN; + + hdd_info("calling sme_update_tdls_peer_state for staIdx %d " + MAC_ADDRESS_STR, + pHddCtx->tdlsConnInfo[staIdx]. + staId, + MAC_ADDR_ARRAY(pHddCtx-> + tdlsConnInfo + [staIdx]. + peerMac. + bytes)); + status = + sme_update_tdls_peer_state( + pHddCtx->hHal, + &smeTdlsPeerStateParams); + if (QDF_STATUS_SUCCESS != status) { + hdd_err("sme_update_tdls_peer_state failed for " + MAC_ADDRESS_STR, + MAC_ADDR_ARRAY + (pHddCtx-> + tdlsConnInfo[staIdx]. + peerMac.bytes)); + } + wlan_hdd_tdls_decrement_peer_count + (pAdapter); + + qdf_mem_zero(&pHddCtx-> + tdlsConnInfo[staIdx]. + peerMac, + QDF_MAC_ADDR_SIZE); + pHddCtx->tdlsConnInfo[staIdx].staId = 0; + pHddCtx->tdlsConnInfo[staIdx]. + sessionId = 255; + + status = QDF_STATUS_SUCCESS; + } + } + break; + } + case eCSR_ROAM_RESULT_TDLS_SHOULD_DISCOVER: + { + /* ignore TDLS_SHOULD_DISCOVER if any concurrency detected */ + if (!cds_check_is_tdls_allowed(pAdapter->device_mode)) { + hdd_err("TDLS not allowed, ignore SHOULD_DISCOVER"); + status = QDF_STATUS_E_FAILURE; + break; + } + + if (pHddCtx->tdls_nss_switch_in_progress) { + hdd_err("TDLS antenna switch is in progress, ignore SHOULD_DISCOVER"); + status = QDF_STATUS_SUCCESS; + break; + } + + mutex_lock(&pHddCtx->tdls_lock); + pHddTdlsCtx = WLAN_HDD_GET_TDLS_CTX_PTR(pAdapter); + if (!pHddTdlsCtx) { + mutex_unlock(&pHddCtx->tdls_lock); + hdd_info("TDLS ctx is null, ignore roamResult (%d)", + roamResult); + status = QDF_STATUS_E_FAILURE; + break; + } + + curr_peer = + wlan_hdd_tdls_get_peer(pAdapter, + pRoamInfo->peerMac.bytes); + if (!curr_peer) { + hdd_info("curr_peer is null"); + status = QDF_STATUS_E_FAILURE; + } else { + if (eTDLS_LINK_CONNECTED == + curr_peer->link_status) { + hdd_err("TDLS link status is connected, ignore SHOULD_DISCOVER"); + } else { + /* + * If external control is enabled then initiate + * TDLS only if forced peer is set otherwise + * ignore should Discover trigger from fw. + */ + if (pHddCtx->config-> + fTDLSExternalControl + && (false == + curr_peer->isForcedPeer)) { + hdd_info("TDLS ExternalControl enabled but curr_peer is not forced, ignore SHOULD_DISCOVER"); + status = QDF_STATUS_SUCCESS; + break; + } else { + hdd_info("initiate TDLS setup on SHOULD_DISCOVER, fTDLSExternalControl: %d, curr_peer->isForcedPeer: %d, reason: %d", + pHddCtx->config-> + fTDLSExternalControl, + curr_peer->isForcedPeer, + pRoamInfo->reasonCode); + } + pHddTdlsCtx->curr_candidate = curr_peer; + wlan_hdd_tdls_implicit_send_discovery_request( + pHddTdlsCtx); + } + status = QDF_STATUS_SUCCESS; + } + mutex_unlock(&pHddCtx->tdls_lock); + break; + } + + case eCSR_ROAM_RESULT_TDLS_SHOULD_TEARDOWN: + { + mutex_lock(&pHddCtx->tdls_lock); + pHddTdlsCtx = WLAN_HDD_GET_TDLS_CTX_PTR(pAdapter); + if (!pHddTdlsCtx) { + mutex_unlock(&pHddCtx->tdls_lock); + hdd_info("TDLS ctx is null, ignore roamResult (%d)", + roamResult); + status = QDF_STATUS_E_FAILURE; + break; + } + + curr_peer = + wlan_hdd_tdls_find_peer(pAdapter, + pRoamInfo->peerMac.bytes); + if (!curr_peer) { + hdd_info("curr_peer is null"); + status = QDF_STATUS_E_FAILURE; + } else { + if (eTDLS_LINK_CONNECTED == + curr_peer->link_status) { + hdd_err("Received SHOULD_TEARDOWN for peer " + MAC_ADDRESS_STR + " staId: %d, reason: %d", + MAC_ADDR_ARRAY(pRoamInfo-> + peerMac.bytes), + pRoamInfo->staId, + pRoamInfo->reasonCode); + + if (pRoamInfo->reasonCode == + eWNI_TDLS_TEARDOWN_REASON_RSSI || + pRoamInfo->reasonCode == + eWNI_TDLS_DISCONNECTED_REASON_PEER_DELETE || + pRoamInfo->reasonCode == + eWNI_TDLS_TEARDOWN_REASON_PTR_TIMEOUT || + pRoamInfo->reasonCode == + eWNI_TDLS_TEARDOWN_REASON_NO_RESPONSE) { + reason = + eSIR_MAC_TDLS_TEARDOWN_PEER_UNREACHABLE; + } else + reason = + eSIR_MAC_TDLS_TEARDOWN_UNSPEC_REASON; + + wlan_hdd_tdls_indicate_teardown + (pHddTdlsCtx->pAdapter, curr_peer, + reason); + hdd_send_wlan_tdls_teardown_event( + eTDLS_TEARDOWN_BSS_DISCONNECT, + curr_peer->peerMac); + } else { + hdd_err("TDLS link is not connected, ignore SHOULD_TEARDOWN, reason: %d", + pRoamInfo->reasonCode); + } + status = QDF_STATUS_SUCCESS; + } + mutex_unlock(&pHddCtx->tdls_lock); + break; + } + + case eCSR_ROAM_RESULT_TDLS_SHOULD_PEER_DISCONNECTED: + { + mutex_lock(&pHddCtx->tdls_lock); + pHddTdlsCtx = WLAN_HDD_GET_TDLS_CTX_PTR(pAdapter); + if (!pHddTdlsCtx) { + mutex_unlock(&pHddCtx->tdls_lock); + hdd_info("TDLS ctx is null, ignore roamResult (%d)", + roamResult); + status = QDF_STATUS_E_FAILURE; + break; + } + + curr_peer = + wlan_hdd_tdls_find_peer(pAdapter, + pRoamInfo->peerMac.bytes); + if (!curr_peer) { + hdd_info("curr_peer is null"); + status = QDF_STATUS_E_FAILURE; + } else { + if (eTDLS_LINK_CONNECTED == + curr_peer->link_status) { + hdd_err("Received SHOULD_PEER_DISCONNECTED for peer " + MAC_ADDRESS_STR + " staId: %d, reason: %d", + MAC_ADDR_ARRAY(pRoamInfo->peerMac.bytes), + pRoamInfo->staId, + pRoamInfo->reasonCode); + + if (pRoamInfo->reasonCode == + eWNI_TDLS_TEARDOWN_REASON_RSSI || + pRoamInfo->reasonCode == + eWNI_TDLS_DISCONNECTED_REASON_PEER_DELETE || + pRoamInfo->reasonCode == + eWNI_TDLS_TEARDOWN_REASON_PTR_TIMEOUT || + pRoamInfo->reasonCode == + eWNI_TDLS_TEARDOWN_REASON_NO_RESPONSE) { + reason = + eSIR_MAC_TDLS_TEARDOWN_PEER_UNREACHABLE; + } else + reason = + eSIR_MAC_TDLS_TEARDOWN_UNSPEC_REASON; + + wlan_hdd_tdls_indicate_teardown + (pHddTdlsCtx->pAdapter, curr_peer, + reason); + hdd_send_wlan_tdls_teardown_event( + eTDLS_TEARDOWN_BSS_DISCONNECT, + curr_peer->peerMac); + } else { + hdd_err("TDLS link is not connected, ignore SHOULD_PEER_DISCONNECTED, reason: %d", + pRoamInfo->reasonCode); + } + status = QDF_STATUS_SUCCESS; + } + mutex_unlock(&pHddCtx->tdls_lock); + break; + } + + case eCSR_ROAM_RESULT_TDLS_CONNECTION_TRACKER_NOTIFICATION: + mutex_lock(&pHddCtx->tdls_lock); + pHddTdlsCtx = WLAN_HDD_GET_TDLS_CTX_PTR(pAdapter); + if (!pHddTdlsCtx) { + mutex_unlock(&pHddCtx->tdls_lock); + hdd_info("TDLS ctx is null, ignore roamResult (%d)", + roamResult); + status = QDF_STATUS_E_FAILURE; + break; + } + + status = hdd_tdls_connection_tracker_update(pAdapter, + pRoamInfo, + pHddTdlsCtx); + mutex_unlock(&pHddCtx->tdls_lock); + break; + + default: + { + break; + } + } + + return status; +} +#else + +inline QDF_STATUS hdd_roam_deregister_tdlssta(hdd_adapter_t *pAdapter, + uint8_t staId) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +hdd_roam_tdls_status_update_handler(hdd_adapter_t *pAdapter, + tCsrRoamInfo *pRoamInfo, + uint32_t roamId, + eRoamCmdStatus roamStatus, + eCsrRoamResult roamResult) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +#ifdef WLAN_FEATURE_11W +/** + * hdd_indicate_unprot_mgmt_frame() - indicate unprotected management frame + * @pAdapter: pointer to the adapter + * @nFrameLength: Length of the unprotected frame being passed + * @pbFrames: Pointer to the frame buffer + * @frameType: 802.11 frame type + * + * This function forwards the unprotected management frame to the supplicant. + * + * Return: nothing + */ +static void +hdd_indicate_unprot_mgmt_frame(hdd_adapter_t *pAdapter, uint32_t nFrameLength, + uint8_t *pbFrames, uint8_t frameType) +{ + uint8_t type = 0; + uint8_t subType = 0; + + hdd_info("Frame Type = %d Frame Length = %d", + frameType, nFrameLength); + + /* Sanity Checks */ + if (NULL == pAdapter) { + hdd_err("pAdapter is NULL"); + return; + } + + if (NULL == pAdapter->dev) { + hdd_err("pAdapter->dev is NULL"); + return; + } + + if (WLAN_HDD_ADAPTER_MAGIC != pAdapter->magic) { + hdd_err("pAdapter has invalid magic"); + return; + } + + if (!nFrameLength) { + hdd_err("Frame Length is Invalid ZERO"); + return; + } + + if (NULL == pbFrames) { + hdd_err("pbFrames is NULL"); + return; + } + + type = WLAN_HDD_GET_TYPE_FRM_FC(pbFrames[0]); + subType = WLAN_HDD_GET_SUBTYPE_FRM_FC(pbFrames[0]); + + /* Get pAdapter from Destination mac address of the frame */ + if (type == SIR_MAC_MGMT_FRAME && subType == SIR_MAC_MGMT_DISASSOC) { +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)) + cfg80211_rx_unprot_mlme_mgmt(pAdapter->dev, pbFrames, + nFrameLength); +#else + cfg80211_send_unprot_disassoc(pAdapter->dev, pbFrames, + nFrameLength); +#endif + pAdapter->hdd_stats.hddPmfStats.numUnprotDisassocRx++; + } else if (type == SIR_MAC_MGMT_FRAME && + subType == SIR_MAC_MGMT_DEAUTH) { +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)) + cfg80211_rx_unprot_mlme_mgmt(pAdapter->dev, pbFrames, + nFrameLength); +#else + cfg80211_send_unprot_deauth(pAdapter->dev, pbFrames, + nFrameLength); +#endif + pAdapter->hdd_stats.hddPmfStats.numUnprotDeauthRx++; + } else { + hdd_err("Frame type %d and subtype %d are not valid", + type, subType); + return; + } +} +#endif + +#ifdef FEATURE_WLAN_ESE +/** + * hdd_indicate_tsm_ie() - send traffic stream metrics ie + * @pAdapter: pointer to adapter + * @tid: traffic identifier + * @state: state + * @measInterval: measurement interval + * + * This function sends traffic stream metrics IE information to + * the supplicant via wireless event. + * + * Return: none + */ +static void +hdd_indicate_tsm_ie(hdd_adapter_t *pAdapter, uint8_t tid, + uint8_t state, uint16_t measInterval) +{ + union iwreq_data wrqu; + char buf[IW_CUSTOM_MAX + 1]; + int nBytes = 0; + + if (NULL == pAdapter) + return; + + /* create the event */ + memset(&wrqu, '\0', sizeof(wrqu)); + memset(buf, '\0', sizeof(buf)); + + hdd_info("TSM Ind tid(%d) state(%d) MeasInt(%d)", + tid, state, measInterval); + + nBytes = + snprintf(buf, IW_CUSTOM_MAX, "TSMIE=%d:%d:%d", tid, state, + measInterval); + + wrqu.data.pointer = buf; + wrqu.data.length = nBytes; + /* send the event */ + wireless_send_event(pAdapter->dev, IWEVCUSTOM, &wrqu, buf); +} + +/** + * hdd_indicate_cckm_pre_auth() - send cckm preauth indication + * @pAdapter: pointer to adapter + * @pRoamInfo: pointer to roam info + * + * This function sends cckm preauth indication to the supplicant + * via wireless custom event. + * + * Return: none + */ +static void +hdd_indicate_cckm_pre_auth(hdd_adapter_t *pAdapter, tCsrRoamInfo *pRoamInfo) +{ + union iwreq_data wrqu; + char buf[IW_CUSTOM_MAX + 1]; + char *pos = buf; + int nBytes = 0, freeBytes = IW_CUSTOM_MAX; + + if ((NULL == pAdapter) || (NULL == pRoamInfo)) + return; + + /* create the event */ + memset(&wrqu, '\0', sizeof(wrqu)); + memset(buf, '\0', sizeof(buf)); + + /* Timestamp0 is lower 32 bits and Timestamp1 is upper 32 bits */ + hdd_info("CCXPREAUTHNOTIFY=" MAC_ADDRESS_STR " %d:%d", + MAC_ADDR_ARRAY(pRoamInfo->bssid.bytes), + pRoamInfo->timestamp[0], pRoamInfo->timestamp[1]); + + nBytes = snprintf(pos, freeBytes, "CCXPREAUTHNOTIFY="); + pos += nBytes; + freeBytes -= nBytes; + + qdf_mem_copy(pos, pRoamInfo->bssid.bytes, QDF_MAC_ADDR_SIZE); + pos += QDF_MAC_ADDR_SIZE; + freeBytes -= QDF_MAC_ADDR_SIZE; + + nBytes = snprintf(pos, freeBytes, " %u:%u", + pRoamInfo->timestamp[0], pRoamInfo->timestamp[1]); + freeBytes -= nBytes; + + wrqu.data.pointer = buf; + wrqu.data.length = (IW_CUSTOM_MAX - freeBytes); + + /* send the event */ + wireless_send_event(pAdapter->dev, IWEVCUSTOM, &wrqu, buf); +} + +/** + * hdd_indicate_ese_adj_ap_rep_ind() - send adjacent AP report indication + * @pAdapter: pointer to adapter + * @pRoamInfo: pointer to roam info + * + * Return: none + */ +static void +hdd_indicate_ese_adj_ap_rep_ind(hdd_adapter_t *pAdapter, + tCsrRoamInfo *pRoamInfo) +{ + union iwreq_data wrqu; + char buf[IW_CUSTOM_MAX + 1]; + int nBytes = 0; + + if ((NULL == pAdapter) || (NULL == pRoamInfo)) + return; + + /* create the event */ + memset(&wrqu, '\0', sizeof(wrqu)); + memset(buf, '\0', sizeof(buf)); + + hdd_info("CCXADJAPREP=%u", pRoamInfo->tsmRoamDelay); + + nBytes = + snprintf(buf, IW_CUSTOM_MAX, "CCXADJAPREP=%u", + pRoamInfo->tsmRoamDelay); + + wrqu.data.pointer = buf; + wrqu.data.length = nBytes; + + /* send the event */ + wireless_send_event(pAdapter->dev, IWEVCUSTOM, &wrqu, buf); +} + +/** + * hdd_indicate_ese_bcn_report_no_results() - beacon report no scan results + * @pAdapter: pointer to adapter + * @measurementToken: measurement token + * @flag: flag + * @numBss: number of bss + * + * If the measurement is none and no scan results found, + * indicate the supplicant about measurement done. + * + * Return: none + */ +void +hdd_indicate_ese_bcn_report_no_results(const hdd_adapter_t *pAdapter, + const uint16_t measurementToken, + const bool flag, const uint8_t numBss) +{ + union iwreq_data wrqu; + char buf[IW_CUSTOM_MAX]; + char *pos = buf; + int nBytes = 0, freeBytes = IW_CUSTOM_MAX; + + memset(&wrqu, '\0', sizeof(wrqu)); + memset(buf, '\0', sizeof(buf)); + + hdd_info("CCXBCNREP=%d %d %d", measurementToken, + flag, numBss); + + nBytes = + snprintf(pos, freeBytes, "CCXBCNREP=%d %d %d", measurementToken, + flag, numBss); + + wrqu.data.pointer = buf; + wrqu.data.length = nBytes; + /* send the event */ + wireless_send_event(pAdapter->dev, IWEVCUSTOM, &wrqu, buf); +} + +/** + * hdd_indicate_ese_bcn_report_ind() - send beacon report indication + * @pAdapter: pointer to adapter + * @pRoamInfo: pointer to roam info + * + * If the measurement is none and no scan results found, + * indicate the supplicant about measurement done. + * + * Return: none + */ +static void +hdd_indicate_ese_bcn_report_ind(const hdd_adapter_t *pAdapter, + const tCsrRoamInfo *pRoamInfo) +{ + union iwreq_data wrqu; + char buf[IW_CUSTOM_MAX]; + char *pos = buf; + int nBytes = 0, freeBytes = IW_CUSTOM_MAX; + uint8_t i = 0, len = 0; + uint8_t tot_bcn_ieLen = 0; /* total size of the beacon report data */ + uint8_t lastSent = 0, sendBss = 0; + int bcnRepFieldSize = + sizeof(pRoamInfo->pEseBcnReportRsp->bcnRepBssInfo[0]. + bcnReportFields); + uint8_t ieLenByte = 1; + /* + * CCXBCNREP=meas_tokflagno_of_bsstot_bcn_ie_len = 18 bytes + */ +#define ESEBCNREPHEADER_LEN (18) + + if ((NULL == pAdapter) || (NULL == pRoamInfo)) + return; + + /* + * Custom event can pass maximum of 256 bytes of data, + * based on the IE len we need to identify how many BSS info can + * be filled in to custom event data. + */ + /* + * meas_tokflagno_of_bsstot_bcn_ie_len bcn_rep_data + * bcn_rep_data will have bcn_rep_fields,ie_len,ie without any spaces + * CCXBCNREP=meas_tokflagno_of_bsstot_bcn_ie_len = 18 bytes + */ + + if ((pRoamInfo->pEseBcnReportRsp->flag >> 1) + && (!pRoamInfo->pEseBcnReportRsp->numBss)) { + hdd_info("Measurement Done but no scan results"); + /* If the measurement is none and no scan results found, + indicate the supplicant about measurement done */ + hdd_indicate_ese_bcn_report_no_results( + pAdapter, + pRoamInfo->pEseBcnReportRsp-> + measurementToken, + pRoamInfo->pEseBcnReportRsp->flag, + pRoamInfo->pEseBcnReportRsp->numBss); + } else { + while (lastSent < pRoamInfo->pEseBcnReportRsp->numBss) { + memset(&wrqu, '\0', sizeof(wrqu)); + memset(buf, '\0', sizeof(buf)); + tot_bcn_ieLen = 0; + sendBss = 0; + pos = buf; + freeBytes = IW_CUSTOM_MAX; + + for (i = lastSent; + i < pRoamInfo->pEseBcnReportRsp->numBss; i++) { + len = + bcnRepFieldSize + ieLenByte + + pRoamInfo->pEseBcnReportRsp-> + bcnRepBssInfo[i].ieLen; + if ((len + tot_bcn_ieLen) > + (IW_CUSTOM_MAX - ESEBCNREPHEADER_LEN)) { + break; + } + tot_bcn_ieLen += len; + sendBss++; + hdd_info("i(%d) sizeof bcnReportFields(%d) IeLength(%d) Length of Ie(%d) totLen(%d)", + i, bcnRepFieldSize, 1, + pRoamInfo->pEseBcnReportRsp-> + bcnRepBssInfo[i].ieLen, tot_bcn_ieLen); + } + + hdd_info("Sending %d BSS Info", sendBss); + hdd_info("CCXBCNREP=%d %d %d %d", + pRoamInfo->pEseBcnReportRsp->measurementToken, + pRoamInfo->pEseBcnReportRsp->flag, sendBss, + tot_bcn_ieLen); + + nBytes = snprintf(pos, freeBytes, "CCXBCNREP=%d %d %d ", + pRoamInfo->pEseBcnReportRsp-> + measurementToken, + pRoamInfo->pEseBcnReportRsp->flag, + sendBss); + pos += nBytes; + freeBytes -= nBytes; + + /* Copy total Beacon report data length */ + qdf_mem_copy(pos, (char *)&tot_bcn_ieLen, + sizeof(tot_bcn_ieLen)); + pos += sizeof(tot_bcn_ieLen); + freeBytes -= sizeof(tot_bcn_ieLen); + + for (i = 0; i < sendBss; i++) { + hdd_info("ChanNum(%d) Spare(%d) MeasDuration(%d)" + " PhyType(%d) RecvSigPower(%d) ParentTSF(%u)" + " TargetTSF[0](%u) TargetTSF[1](%u) BeaconInterval(%u)" + " CapabilityInfo(%d) BSSID(%02X:%02X:%02X:%02X:%02X:%02X)", + pRoamInfo->pEseBcnReportRsp-> + bcnRepBssInfo[i + + lastSent].bcnReportFields. + ChanNum, + pRoamInfo->pEseBcnReportRsp-> + bcnRepBssInfo[i + + lastSent].bcnReportFields. + Spare, + pRoamInfo->pEseBcnReportRsp-> + bcnRepBssInfo[i + + lastSent].bcnReportFields. + MeasDuration, + pRoamInfo->pEseBcnReportRsp-> + bcnRepBssInfo[i + + lastSent].bcnReportFields. + PhyType, + pRoamInfo->pEseBcnReportRsp-> + bcnRepBssInfo[i + + lastSent].bcnReportFields. + RecvSigPower, + pRoamInfo->pEseBcnReportRsp-> + bcnRepBssInfo[i + + lastSent].bcnReportFields. + ParentTsf, + pRoamInfo->pEseBcnReportRsp-> + bcnRepBssInfo[i + + lastSent].bcnReportFields. + TargetTsf[0], + pRoamInfo->pEseBcnReportRsp-> + bcnRepBssInfo[i + + lastSent].bcnReportFields. + TargetTsf[1], + pRoamInfo->pEseBcnReportRsp-> + bcnRepBssInfo[i + + lastSent].bcnReportFields. + BcnInterval, + pRoamInfo->pEseBcnReportRsp-> + bcnRepBssInfo[i + + lastSent].bcnReportFields. + CapabilityInfo, + pRoamInfo->pEseBcnReportRsp-> + bcnRepBssInfo[i + + lastSent].bcnReportFields. + Bssid[0], + pRoamInfo->pEseBcnReportRsp-> + bcnRepBssInfo[i + + lastSent].bcnReportFields. + Bssid[1], + pRoamInfo->pEseBcnReportRsp-> + bcnRepBssInfo[i + + lastSent].bcnReportFields. + Bssid[2], + pRoamInfo->pEseBcnReportRsp-> + bcnRepBssInfo[i + + lastSent].bcnReportFields. + Bssid[3], + pRoamInfo->pEseBcnReportRsp-> + bcnRepBssInfo[i + + lastSent].bcnReportFields. + Bssid[4], + pRoamInfo->pEseBcnReportRsp-> + bcnRepBssInfo[i + + lastSent].bcnReportFields. + Bssid[5]); + + /* bcn report fields are copied */ + len = + sizeof(pRoamInfo->pEseBcnReportRsp-> + bcnRepBssInfo[i + + lastSent]. + bcnReportFields); + qdf_mem_copy(pos, + (char *)&pRoamInfo-> + pEseBcnReportRsp->bcnRepBssInfo[i + + lastSent]. + bcnReportFields, len); + pos += len; + freeBytes -= len; + + /* Add 1 byte of ie len */ + len = + pRoamInfo->pEseBcnReportRsp-> + bcnRepBssInfo[i + lastSent].ieLen; + qdf_mem_copy(pos, (char *)&len, sizeof(len)); + pos += sizeof(len); + freeBytes -= sizeof(len); + + /* copy IE from scan results */ + qdf_mem_copy(pos, + (char *)pRoamInfo-> + pEseBcnReportRsp->bcnRepBssInfo[i + + lastSent]. + pBuf, len); + pos += len; + freeBytes -= len; + } + + wrqu.data.pointer = buf; + wrqu.data.length = IW_CUSTOM_MAX - freeBytes; + + /* send the event */ + wireless_send_event(pAdapter->dev, IWEVCUSTOM, &wrqu, + buf); + lastSent += sendBss; + } + } +} + +#endif /* FEATURE_WLAN_ESE */ + +/** + * hdd_is_8021x_sha256_auth_type() - check authentication type to 8021x_sha256 + * @pHddStaCtx: Station Context + * + * API to check if the connection authentication type is 8021x_sha256. + * + * Return: bool + */ +#ifdef WLAN_FEATURE_11W +static inline bool hdd_is_8021x_sha256_auth_type(hdd_station_ctx_t *pHddStaCtx) +{ + return eCSR_AUTH_TYPE_RSN_8021X_SHA256 == + pHddStaCtx->conn_info.authType; +} +#else +static inline bool hdd_is_8021x_sha256_auth_type(hdd_station_ctx_t *pHddStaCtx) +{ + return false; +} +#endif + +/* + * hdd_roam_channel_switch_handler() - hdd channel switch handler + * @adapter: Pointer to adapter context + * @roam_info: Pointer to roam info + * + * Return: None + */ +static void hdd_roam_channel_switch_handler(hdd_adapter_t *adapter, + tCsrRoamInfo *roam_info) +{ + struct hdd_chan_change_params chan_change; + struct cfg80211_bss *bss; + struct net_device *dev = adapter->dev; + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct wiphy *wiphy = wdev->wiphy; + QDF_STATUS status; + + hdd_info("channel switch for session:%d to channel:%d", + adapter->sessionId, roam_info->chan_info.chan_id); + + chan_change.chan = roam_info->chan_info.chan_id; + chan_change.chan_params.ch_width = + roam_info->chan_info.ch_width; + chan_change.chan_params.sec_ch_offset = + roam_info->chan_info.sec_ch_offset; + chan_change.chan_params.center_freq_seg0 = + roam_info->chan_info.band_center_freq1; + chan_change.chan_params.center_freq_seg1 = + roam_info->chan_info.band_center_freq2; + + bss = wlan_hdd_cfg80211_update_bss_db(adapter, roam_info); + if (NULL == bss) + hdd_err("%s: unable to create BSS entry", adapter->dev->name); + else + cfg80211_put_bss(wiphy, bss); + + status = hdd_chan_change_notify(adapter, adapter->dev, chan_change); + if (QDF_IS_STATUS_ERROR(status)) + hdd_err("channel change notification failed"); + + status = cds_set_hw_mode_on_channel_switch(adapter->sessionId); + if (QDF_IS_STATUS_ERROR(status)) + hdd_info("set hw mode change not done"); +} + +/** + * hdd_sme_roam_callback() - hdd sme roam callback + * @pContext: pointer to adapter context + * @pRoamInfo: pointer to roam info + * @roamId: roam id + * @roamStatus: roam status + * @roamResult: roam result + * + * Return: QDF_STATUS enumeration + */ +QDF_STATUS +hdd_sme_roam_callback(void *pContext, tCsrRoamInfo *pRoamInfo, uint32_t roamId, + eRoamCmdStatus roamStatus, eCsrRoamResult roamResult) +{ + QDF_STATUS qdf_ret_status = QDF_STATUS_SUCCESS; + hdd_adapter_t *pAdapter = (hdd_adapter_t *) pContext; + hdd_wext_state_t *pWextState = NULL; + hdd_station_ctx_t *pHddStaCtx = NULL; + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct cfg80211_bss *bss_status; + + hdd_info("CSR Callback: status= %d result= %d roamID=%d", + roamStatus, roamResult, roamId); + + /* Sanity check */ + if ((NULL == pAdapter) || (WLAN_HDD_ADAPTER_MAGIC != pAdapter->magic)) { + hdd_alert("invalid adapter or adapter has invalid magic"); + return QDF_STATUS_E_FAILURE; + } + + pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter); + pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + + /* Omitting eCSR_ROAM_UPDATE_SCAN_RESULT as this is too frequent */ + if (eCSR_ROAM_UPDATE_SCAN_RESULT != roamStatus) + MTRACE(qdf_trace(QDF_MODULE_ID_HDD, TRACE_CODE_HDD_RX_SME_MSG, + pAdapter->sessionId, roamStatus)); + + switch (roamStatus) { + case eCSR_ROAM_SESSION_OPENED: + set_bit(SME_SESSION_OPENED, &pAdapter->event_flags); + complete(&pAdapter->session_open_comp_var); + hdd_debug("session %d opened", pAdapter->sessionId); + break; + + /* + * We did pre-auth,then we attempted a 11r or ese reassoc. + * reassoc failed due to failure, timeout, reject from ap + * in any case tell the OS, our carrier is off and mark + * interface down. + */ + case eCSR_ROAM_FT_REASSOC_FAILED: + hdd_notice("Reassoc Failed with roamStatus: %d roamResult: %d SessionID: %d", + roamStatus, roamResult, pAdapter->sessionId); + qdf_ret_status = + hdd_dis_connect_handler(pAdapter, pRoamInfo, roamId, + roamStatus, roamResult); + pHddStaCtx->ft_carrier_on = false; + pHddStaCtx->hdd_ReassocScenario = false; + hdd_info("hdd_ReassocScenario set to: %d, ReAssoc Failed, session: %d", + pHddStaCtx->hdd_ReassocScenario, pAdapter->sessionId); + break; + + case eCSR_ROAM_FT_START: + /* + * When we roam for ESE and 11r, we dont want the OS to be + * informed that the link is down. So mark the link ready for + * ft_start. After this the eCSR_ROAM_SHOULD_ROAM will + * be received. Where in we will not mark the link down + * Also we want to stop tx at this point when we will be + * doing disassoc at this time. This saves 30-60 msec + * after reassoc. + */ + hdd_info("Disabling queues"); + hdd_info("Roam Synch Ind: NAPI Serialize ON"); + hdd_napi_serialize(1); + wlan_hdd_netif_queue_control(pAdapter, + WLAN_STOP_ALL_NETIF_QUEUE, + WLAN_CONTROL_PATH); + status = hdd_roam_deregister_sta(pAdapter, + pHddStaCtx->conn_info.staId[0]); + if (!QDF_IS_STATUS_SUCCESS(status)) + qdf_ret_status = QDF_STATUS_E_FAILURE; + pHddStaCtx->ft_carrier_on = true; + pHddStaCtx->hdd_ReassocScenario = true; + hdd_info("hdd_ReassocScenario set to: %d, due to eCSR_ROAM_FT_START, session: %d", + pHddStaCtx->hdd_ReassocScenario, pAdapter->sessionId); + break; + case eCSR_ROAM_NAPI_OFF: + hdd_info("After Roam Synch Comp: NAPI Serialize OFF"); + hdd_napi_serialize(0); + hdd_set_roaming_in_progress(false); + if (roamResult == eCSR_ROAM_RESULT_FAILURE) + pAdapter->roam_ho_fail = true; + else + pAdapter->roam_ho_fail = false; + complete(&pAdapter->roaming_comp_var); + break; + case eCSR_ROAM_SHOULD_ROAM: + /* notify apps that we can't pass traffic anymore */ + hdd_info("Disabling queues"); + wlan_hdd_netif_queue_control(pAdapter, + WLAN_STOP_ALL_NETIF_QUEUE, + WLAN_CONTROL_PATH); + if (pHddStaCtx->ft_carrier_on == false) { + wlan_hdd_netif_queue_control(pAdapter, + WLAN_NETIF_CARRIER_OFF, + WLAN_CONTROL_PATH); + } + break; + case eCSR_ROAM_LOSTLINK: + if (roamResult == eCSR_ROAM_RESULT_LOSTLINK) { + hdd_info("Roaming started due to connection lost"); + hdd_info("Disabling queues"); + wlan_hdd_netif_queue_control(pAdapter, + WLAN_STOP_ALL_NETIF_QUEUE_N_CARRIER, + WLAN_CONTROL_PATH); + break; + } + case eCSR_ROAM_DISASSOCIATED: + { + hdd_info("****eCSR_ROAM_DISASSOCIATED****"); + hdd_napi_serialize(0); + cds_set_connection_in_progress(false); + hdd_set_roaming_in_progress(false); + pAdapter->roam_ho_fail = false; + complete(&pAdapter->roaming_comp_var); + + qdf_ret_status = + hdd_dis_connect_handler(pAdapter, pRoamInfo, roamId, + roamStatus, roamResult); + /* Call to clear any MC Addr List filter applied after + * successful connection. + */ + if (wlan_hdd_set_mc_addr_list(pAdapter, false)) + hdd_err("Failed: to clear mc addr list"); + } + break; + case eCSR_ROAM_IBSS_LEAVE: + hdd_info("****eCSR_ROAM_IBSS_LEAVE****"); + qdf_ret_status = + hdd_dis_connect_handler(pAdapter, pRoamInfo, roamId, + roamStatus, roamResult); + break; + case eCSR_ROAM_ASSOCIATION_COMPLETION: + hdd_info("****eCSR_ROAM_ASSOCIATION_COMPLETION****"); + /* + * To Do - address probable memory leak with WEP encryption upon + * successful association. + */ + if (eCSR_ROAM_RESULT_ASSOCIATED != roamResult) { + /* Clear saved connection information in HDD */ + hdd_conn_remove_connect_info( + WLAN_HDD_GET_STATION_CTX_PTR(pAdapter)); + } + qdf_ret_status = + hdd_association_completion_handler(pAdapter, pRoamInfo, + roamId, roamStatus, + roamResult); +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + if (pRoamInfo) + pRoamInfo->roamSynchInProgress = false; +#endif + break; + case eCSR_ROAM_CANCELLED: + hdd_info("****eCSR_ROAM_CANCELLED****"); + case eCSR_ROAM_ASSOCIATION_FAILURE: + qdf_ret_status = hdd_association_completion_handler(pAdapter, + pRoamInfo, + roamId, + roamStatus, + roamResult); + break; + case eCSR_ROAM_IBSS_IND: + hdd_roam_ibss_indication_handler(pAdapter, pRoamInfo, roamId, + roamStatus, roamResult); + break; + + case eCSR_ROAM_CONNECT_STATUS_UPDATE: + qdf_ret_status = + roam_roam_connect_status_update_handler(pAdapter, + pRoamInfo, + roamId, + roamStatus, + roamResult); + break; + + case eCSR_ROAM_MIC_ERROR_IND: + qdf_ret_status = + hdd_roam_mic_error_indication_handler(pAdapter, + pRoamInfo, + roamId, + roamStatus, + roamResult); + break; + + case eCSR_ROAM_SET_KEY_COMPLETE: + { + qdf_ret_status = + hdd_roam_set_key_complete_handler(pAdapter, pRoamInfo, + roamId, roamStatus, + roamResult); + if (eCSR_ROAM_RESULT_AUTHENTICATED == roamResult) { + pHddStaCtx->hdd_ReassocScenario = false; + hdd_info("hdd_ReassocScenario set to: %d, set key complete, session: %d", + pHddStaCtx->hdd_ReassocScenario, + pAdapter->sessionId); + } + } +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + if (pRoamInfo != NULL) + pRoamInfo->roamSynchInProgress = false; +#endif + break; + + case eCSR_ROAM_FT_RESPONSE: + hdd_send_ft_event(pAdapter); + break; + + case eCSR_ROAM_PMK_NOTIFY: + if (eCSR_AUTH_TYPE_RSN == pHddStaCtx->conn_info.authType + || hdd_is_8021x_sha256_auth_type(pHddStaCtx)) { + /* notify the supplicant of a new candidate */ + qdf_ret_status = + wlan_hdd_cfg80211_pmksa_candidate_notify( + pAdapter, pRoamInfo, 1, false); + } + break; + +#ifdef FEATURE_WLAN_LFR_METRICS + case eCSR_ROAM_PREAUTH_INIT_NOTIFY: + /* This event is to notify pre-auth initiation */ + if (QDF_STATUS_SUCCESS != + wlan_hdd_cfg80211_roam_metrics_preauth(pAdapter, + pRoamInfo)) { + qdf_ret_status = QDF_STATUS_E_FAILURE; + } + break; + case eCSR_ROAM_PREAUTH_STATUS_SUCCESS: + /* + * This event will notify pre-auth completion in case of success + */ + if (QDF_STATUS_SUCCESS != + wlan_hdd_cfg80211_roam_metrics_preauth_status(pAdapter, + pRoamInfo, 1)) { + qdf_ret_status = QDF_STATUS_E_FAILURE; + } + break; + case eCSR_ROAM_PREAUTH_STATUS_FAILURE: + /* + * This event will notify pre-auth completion incase of failure. + */ + if (QDF_STATUS_SUCCESS != + wlan_hdd_cfg80211_roam_metrics_preauth_status(pAdapter, + pRoamInfo, 0)) { + qdf_ret_status = QDF_STATUS_E_FAILURE; + } + break; + case eCSR_ROAM_HANDOVER_SUCCESS: + /* This event is to notify handover success. + It will be only invoked on success */ + if (QDF_STATUS_SUCCESS != + wlan_hdd_cfg80211_roam_metrics_handover(pAdapter, + pRoamInfo)) { + qdf_ret_status = QDF_STATUS_E_FAILURE; + } + break; +#endif + case eCSR_ROAM_REMAIN_CHAN_READY: + hdd_remain_chan_ready_handler(pAdapter, pRoamInfo->roc_scan_id); + break; +#ifdef FEATURE_WLAN_TDLS + case eCSR_ROAM_TDLS_STATUS_UPDATE: + qdf_ret_status = + hdd_roam_tdls_status_update_handler(pAdapter, pRoamInfo, + roamId, + roamStatus, + roamResult); + break; + case eCSR_ROAM_RESULT_MGMT_TX_COMPLETE_IND: + wlan_hdd_tdls_mgmt_completion_callback(pAdapter, + pRoamInfo->reasonCode); + break; +#endif +#ifdef WLAN_FEATURE_11W + case eCSR_ROAM_UNPROT_MGMT_FRAME_IND: + hdd_indicate_unprot_mgmt_frame(pAdapter, + pRoamInfo->nFrameLength, + pRoamInfo->pbFrames, + pRoamInfo->frameType); + break; +#endif +#ifdef FEATURE_WLAN_ESE + case eCSR_ROAM_TSM_IE_IND: + hdd_indicate_tsm_ie(pAdapter, pRoamInfo->tsmIe.tsid, + pRoamInfo->tsmIe.state, + pRoamInfo->tsmIe.msmt_interval); + break; + + case eCSR_ROAM_CCKM_PREAUTH_NOTIFY: + { + if (eCSR_AUTH_TYPE_CCKM_WPA == + pHddStaCtx->conn_info.authType + || eCSR_AUTH_TYPE_CCKM_RSN == + pHddStaCtx->conn_info.authType) { + hdd_indicate_cckm_pre_auth(pAdapter, pRoamInfo); + } + break; + } + + case eCSR_ROAM_ESE_ADJ_AP_REPORT_IND: + { + hdd_indicate_ese_adj_ap_rep_ind(pAdapter, pRoamInfo); + break; + } + + case eCSR_ROAM_ESE_BCN_REPORT_IND: + { + hdd_indicate_ese_bcn_report_ind(pAdapter, pRoamInfo); + break; + } +#endif /* FEATURE_WLAN_ESE */ + case eCSR_ROAM_STA_CHANNEL_SWITCH: + hdd_roam_channel_switch_handler(pAdapter, pRoamInfo); + break; + + case eCSR_ROAM_UPDATE_SCAN_RESULT: + if ((NULL != pRoamInfo) && (NULL != pRoamInfo->pBssDesc)) { + bss_status = wlan_hdd_cfg80211_inform_bss_frame( + pAdapter, pRoamInfo->pBssDesc); + if (NULL == bss_status) + hdd_info("UPDATE_SCAN_RESULT returned NULL"); + else + cfg80211_put_bss( +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0)) || defined(WITH_BACKPORTS) + (WLAN_HDD_GET_CTX(pAdapter))->wiphy, +#endif + bss_status); + } + break; + case eCSR_ROAM_NDP_STATUS_UPDATE: + hdd_ndp_event_handler(pAdapter, pRoamInfo, roamId, roamStatus, + roamResult); + break; + case eCSR_ROAM_START: + hdd_info("Process ROAM_START from firmware"); + wlan_hdd_netif_queue_control(pAdapter, + WLAN_STOP_ALL_NETIF_QUEUE, + WLAN_CONTROL_PATH); + hdd_napi_serialize(1); + cds_set_connection_in_progress(true); + hdd_set_roaming_in_progress(true); + cds_restart_opportunistic_timer(true); + break; + case eCSR_ROAM_ABORT: + hdd_info("Firmware aborted roaming operation, previous connection is still valid"); + hdd_napi_serialize(0); + wlan_hdd_netif_queue_control(pAdapter, + WLAN_WAKE_ALL_NETIF_QUEUE, + WLAN_CONTROL_PATH); + cds_set_connection_in_progress(false); + hdd_set_roaming_in_progress(false); + pAdapter->roam_ho_fail = false; + complete(&pAdapter->roaming_comp_var); + break; + + default: + break; + } + return qdf_ret_status; +} + +/** + * hdd_translate_rsn_to_csr_auth_type() - Translate RSN to CSR auth type + * @auth_suite: auth suite + * + * Return: eCsrAuthType enumeration + */ +eCsrAuthType hdd_translate_rsn_to_csr_auth_type(uint8_t auth_suite[4]) +{ + eCsrAuthType auth_type; + /* is the auth type supported? */ + if (memcmp(auth_suite, ccp_rsn_oui01, 4) == 0) { + auth_type = eCSR_AUTH_TYPE_RSN; + } else if (memcmp(auth_suite, ccp_rsn_oui02, 4) == 0) { + auth_type = eCSR_AUTH_TYPE_RSN_PSK; + } else if (memcmp(auth_suite, ccp_rsn_oui04, 4) == 0) { + /* Check for 11r FT Authentication with PSK */ + auth_type = eCSR_AUTH_TYPE_FT_RSN_PSK; + } else if (memcmp(auth_suite, ccp_rsn_oui03, 4) == 0) { + /* Check for 11R FT Authentication with 802.1X */ + auth_type = eCSR_AUTH_TYPE_FT_RSN; + } else +#ifdef FEATURE_WLAN_ESE + if (memcmp(auth_suite, ccp_rsn_oui06, 4) == 0) { + auth_type = eCSR_AUTH_TYPE_CCKM_RSN; + } else +#endif /* FEATURE_WLAN_ESE */ +#ifdef WLAN_FEATURE_11W + if (memcmp(auth_suite, ccp_rsn_oui07, 4) == 0) { + auth_type = eCSR_AUTH_TYPE_RSN_PSK_SHA256; + } else if (memcmp(auth_suite, ccp_rsn_oui08, 4) == 0) { + auth_type = eCSR_AUTH_TYPE_RSN_8021X_SHA256; + } else +#endif + { + auth_type = eCSR_AUTH_TYPE_UNKNOWN; + } + return auth_type; +} + +/** + * hdd_translate_wpa_to_csr_auth_type() - Translate WPA to CSR auth type + * @auth_suite: auth suite + * + * Return: eCsrAuthType enumeration + */ +eCsrAuthType hdd_translate_wpa_to_csr_auth_type(uint8_t auth_suite[4]) +{ + eCsrAuthType auth_type; + /* is the auth type supported? */ + if (memcmp(auth_suite, ccp_wpa_oui01, 4) == 0) { + auth_type = eCSR_AUTH_TYPE_WPA; + } else if (memcmp(auth_suite, ccp_wpa_oui02, 4) == 0) { + auth_type = eCSR_AUTH_TYPE_WPA_PSK; + } else +#ifdef FEATURE_WLAN_ESE + if (memcmp(auth_suite, ccp_wpa_oui06, 4) == 0) { + auth_type = eCSR_AUTH_TYPE_CCKM_WPA; + } else +#endif /* FEATURE_WLAN_ESE */ + { + auth_type = eCSR_AUTH_TYPE_UNKNOWN; + } + hdd_info("auth_type: %d", auth_type); + return auth_type; +} + +/** + * hdd_translate_rsn_to_csr_encryption_type() - + * Translate RSN to CSR encryption type + * @cipher_suite: cipher suite + * + * Return: eCsrEncryptionType enumeration + */ +eCsrEncryptionType +hdd_translate_rsn_to_csr_encryption_type(uint8_t cipher_suite[4]) +{ + eCsrEncryptionType cipher_type; + + if (memcmp(cipher_suite, ccp_rsn_oui04, 4) == 0) + cipher_type = eCSR_ENCRYPT_TYPE_AES; + else if (memcmp(cipher_suite, ccp_rsn_oui02, 4) == 0) + cipher_type = eCSR_ENCRYPT_TYPE_TKIP; + else if (memcmp(cipher_suite, ccp_rsn_oui00, 4) == 0) + cipher_type = eCSR_ENCRYPT_TYPE_NONE; + else if (memcmp(cipher_suite, ccp_rsn_oui01, 4) == 0) + cipher_type = eCSR_ENCRYPT_TYPE_WEP40_STATICKEY; + else if (memcmp(cipher_suite, ccp_rsn_oui05, 4) == 0) + cipher_type = eCSR_ENCRYPT_TYPE_WEP104_STATICKEY; + else + cipher_type = eCSR_ENCRYPT_TYPE_FAILED; + + hdd_info("cipher_type: %d", cipher_type); + return cipher_type; +} + +/** + * hdd_translate_wpa_to_csr_encryption_type() - + * Translate WPA to CSR encryption type + * @cipher_suite: cipher suite + * + * Return: eCsrEncryptionType enumeration + */ +eCsrEncryptionType +hdd_translate_wpa_to_csr_encryption_type(uint8_t cipher_suite[4]) +{ + eCsrEncryptionType cipher_type; + + if (memcmp(cipher_suite, ccp_wpa_oui04, 4) == 0) + cipher_type = eCSR_ENCRYPT_TYPE_AES; + else if (memcmp(cipher_suite, ccp_wpa_oui02, 4) == 0) + cipher_type = eCSR_ENCRYPT_TYPE_TKIP; + else if (memcmp(cipher_suite, ccp_wpa_oui00, 4) == 0) + cipher_type = eCSR_ENCRYPT_TYPE_NONE; + else if (memcmp(cipher_suite, ccp_wpa_oui01, 4) == 0) + cipher_type = eCSR_ENCRYPT_TYPE_WEP40_STATICKEY; + else if (memcmp(cipher_suite, ccp_wpa_oui05, 4) == 0) + cipher_type = eCSR_ENCRYPT_TYPE_WEP104_STATICKEY; + else + cipher_type = eCSR_ENCRYPT_TYPE_FAILED; + + hdd_info("cipher_type: %d", cipher_type); + return cipher_type; +} + +/** + * hdd_process_genie() - process gen ie + * @pAdapter: pointer to adapter + * @bssid: pointer to mac address + * @pEncryptType: pointer to encryption type + * @mcEncryptType: pointer to multicast encryption type + * @pAuthType: pointer to auth type + * + * Return: 0 on success, error number otherwise + */ +static int32_t hdd_process_genie(hdd_adapter_t *pAdapter, + u8 *bssid, + eCsrEncryptionType *pEncryptType, + eCsrEncryptionType *mcEncryptType, + eCsrAuthType *pAuthType, +#ifdef WLAN_FEATURE_11W + uint8_t *pMfpRequired, uint8_t *pMfpCapable, +#endif + uint16_t gen_ie_len, uint8_t *gen_ie) +{ + tHalHandle halHandle = WLAN_HDD_GET_HAL_CTX(pAdapter); + QDF_STATUS result; + tDot11fIERSN dot11RSNIE; + tDot11fIEWPA dot11WPAIE; + uint32_t i; + uint8_t *pRsnIe; + uint16_t RSNIeLen; + tPmkidCacheInfo PMKIDCache[4]; /* Local transfer memory */ + bool updatePMKCache = false; + + /* + * Clear struct of tDot11fIERSN and tDot11fIEWPA specifically + * setting present flag to 0. + */ + memset(&dot11WPAIE, 0, sizeof(tDot11fIEWPA)); + memset(&dot11RSNIE, 0, sizeof(tDot11fIERSN)); + + /* Type check */ + if (gen_ie[0] == DOT11F_EID_RSN) { + /* Validity checks */ + if ((gen_ie_len < DOT11F_IE_RSN_MIN_LEN) || + (gen_ie_len > DOT11F_IE_RSN_MAX_LEN)) { + hdd_err("Invalid DOT11F RSN IE length :%d", + gen_ie_len); + return -EINVAL; + } + /* Skip past the EID byte and length byte */ + pRsnIe = gen_ie + 2; + RSNIeLen = gen_ie_len - 2; + /* Unpack the RSN IE */ + dot11f_unpack_ie_rsn((tpAniSirGlobal) halHandle, + pRsnIe, RSNIeLen, &dot11RSNIE); + /* Copy out the encryption and authentication types */ + hdd_info("pairwise cipher suite count: %d", + dot11RSNIE.pwise_cipher_suite_count); + hdd_info("authentication suite count: %d", + dot11RSNIE.akm_suite_count); + /*Here we have followed the apple base code, + but probably I suspect we can do something different */ + /* dot11RSNIE.akm_suite_count */ + /* Just translate the FIRST one */ + *pAuthType = + hdd_translate_rsn_to_csr_auth_type( + dot11RSNIE.akm_suites[0]); + /* dot11RSNIE.pwise_cipher_suite_count */ + *pEncryptType = + hdd_translate_rsn_to_csr_encryption_type( + dot11RSNIE.pwise_cipher_suites[0]); + /* dot11RSNIE.gp_cipher_suite_count */ + *mcEncryptType = + hdd_translate_rsn_to_csr_encryption_type( + dot11RSNIE.gp_cipher_suite); +#ifdef WLAN_FEATURE_11W + *pMfpRequired = (dot11RSNIE.RSN_Cap[0] >> 6) & 0x1; + *pMfpCapable = (dot11RSNIE.RSN_Cap[0] >> 7) & 0x1; +#endif + /* Set the PMKSA ID Cache for this interface */ + for (i = 0; i < dot11RSNIE.pmkid_count; i++) { + if (is_zero_ether_addr(bssid)) { + hdd_err("MAC address is all zeroes"); + break; + } + updatePMKCache = true; + /* + * For right now, I assume setASSOCIATE() has passed + * in the bssid. + */ + qdf_mem_copy(PMKIDCache[i].BSSID.bytes, + bssid, QDF_MAC_ADDR_SIZE); + qdf_mem_copy(PMKIDCache[i].PMKID, + dot11RSNIE.pmkid[i], CSR_RSN_PMKID_SIZE); + } + + if (updatePMKCache) { + /* + * Calling csr_roam_set_pmkid_cache to configure the + * PMKIDs into the cache. + */ + hdd_info("Calling sme_roam_set_pmkid_cache with cache entry %d.", + i); + /* Finally set the PMKSA ID Cache in CSR */ + result = + sme_roam_set_pmkid_cache(halHandle, + pAdapter->sessionId, + PMKIDCache, + dot11RSNIE.pmkid_count, + false); + } + } else if (gen_ie[0] == DOT11F_EID_WPA) { + /* Validity checks */ + if ((gen_ie_len < DOT11F_IE_WPA_MIN_LEN) || + (gen_ie_len > DOT11F_IE_WPA_MAX_LEN)) { + hdd_err("Invalid DOT11F WPA IE length :%d", + gen_ie_len); + return -EINVAL; + } + /* Skip past the EID and length byte - and four byte WiFi OUI */ + pRsnIe = gen_ie + 2 + 4; + RSNIeLen = gen_ie_len - (2 + 4); + /* Unpack the WPA IE */ + dot11f_unpack_ie_wpa((tpAniSirGlobal) halHandle, + pRsnIe, RSNIeLen, &dot11WPAIE); + /* Copy out the encryption and authentication types */ + hdd_info("WPA unicast cipher suite count: %d", + dot11WPAIE.unicast_cipher_count); + hdd_info("WPA authentication suite count: %d", + dot11WPAIE.auth_suite_count); + /* dot11WPAIE.auth_suite_count */ + /* Just translate the FIRST one */ + *pAuthType = + hdd_translate_wpa_to_csr_auth_type( + dot11WPAIE.auth_suites[0]); + /* dot11WPAIE.unicast_cipher_count */ + *pEncryptType = + hdd_translate_wpa_to_csr_encryption_type( + dot11WPAIE.unicast_ciphers[0]); + /* dot11WPAIE.unicast_cipher_count */ + *mcEncryptType = + hdd_translate_wpa_to_csr_encryption_type( + dot11WPAIE.multicast_cipher); + } else { + hdd_warn("gen_ie[0]: %d", gen_ie[0]); + return -EINVAL; + } + return 0; +} + +/** + * hdd_set_genie_to_csr() - set genie to csr + * @pAdapter: pointer to adapter + * @RSNAuthType: pointer to auth type + * + * Return: 0 on success, error number otherwise + */ +int hdd_set_genie_to_csr(hdd_adapter_t *pAdapter, eCsrAuthType *RSNAuthType) +{ + hdd_wext_state_t *pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter); + uint32_t status = 0; + eCsrEncryptionType RSNEncryptType; + eCsrEncryptionType mcRSNEncryptType; +#ifdef WLAN_FEATURE_11W + uint8_t RSNMfpRequired = 0; + uint8_t RSNMfpCapable = 0; +#endif + u8 bssid[ETH_ALEN]; /* MAC address of assoc peer */ + /* MAC address of assoc peer */ + /* But, this routine is only called when we are NOT associated. */ + qdf_mem_copy(bssid, + pWextState->roamProfile.BSSIDs.bssid, + sizeof(bssid)); + if (pWextState->WPARSNIE[0] == DOT11F_EID_RSN + || pWextState->WPARSNIE[0] == DOT11F_EID_WPA) { + /* continue */ + } else { + return 0; + } + /* The actual processing may eventually be more extensive than this. */ + /* Right now, just consume any PMKIDs that are sent in by the app. */ + status = hdd_process_genie(pAdapter, bssid, + &RSNEncryptType, + &mcRSNEncryptType, RSNAuthType, +#ifdef WLAN_FEATURE_11W + &RSNMfpRequired, &RSNMfpCapable, +#endif + pWextState->WPARSNIE[1] + 2, + pWextState->WPARSNIE); + if (status == 0) { + /* + * Now copy over all the security attributes + * you have parsed out. + */ + pWextState->roamProfile.EncryptionType.numEntries = 1; + pWextState->roamProfile.mcEncryptionType.numEntries = 1; + + pWextState->roamProfile.EncryptionType.encryptionType[0] = RSNEncryptType; /* Use the cipher type in the RSN IE */ + pWextState->roamProfile.mcEncryptionType.encryptionType[0] = + mcRSNEncryptType; + + if ((QDF_IBSS_MODE == pAdapter->device_mode) && + ((eCSR_ENCRYPT_TYPE_AES == mcRSNEncryptType) || + (eCSR_ENCRYPT_TYPE_TKIP == mcRSNEncryptType))) { + /* + * For wpa none supplicant sends the WPA IE with unicast + * cipher as eCSR_ENCRYPT_TYPE_NONE ,where as the + * multicast cipher as either AES/TKIP based on group + * cipher configuration mentioned in the + * wpa_supplicant.conf. + */ + + /* Set the unicast cipher same as multicast cipher */ + pWextState->roamProfile.EncryptionType.encryptionType[0] + = mcRSNEncryptType; + } +#ifdef WLAN_FEATURE_11W + hdd_info("RSNMfpRequired = %d, RSNMfpCapable = %d", + RSNMfpRequired, RSNMfpCapable); + pWextState->roamProfile.MFPRequired = RSNMfpRequired; + pWextState->roamProfile.MFPCapable = RSNMfpCapable; +#endif + hdd_info("CSR AuthType = %d, EncryptionType = %d mcEncryptionType = %d", + *RSNAuthType, RSNEncryptType, mcRSNEncryptType); + } + return 0; +} + +/** + * hdd_set_csr_auth_type() - set csr auth type + * @pAdapter: pointer to adapter + * @RSNAuthType: auth type + * + * Return: 0 on success, error number otherwise + */ +int hdd_set_csr_auth_type(hdd_adapter_t *pAdapter, eCsrAuthType RSNAuthType) +{ + hdd_wext_state_t *pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter); + tCsrRoamProfile *pRoamProfile = &(pWextState->roamProfile); + hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + + pRoamProfile->AuthType.numEntries = 1; + hdd_info("pHddStaCtx->conn_info.authType = %d", + pHddStaCtx->conn_info.authType); + + switch (pHddStaCtx->conn_info.authType) { + case eCSR_AUTH_TYPE_OPEN_SYSTEM: +#ifdef FEATURE_WLAN_ESE + case eCSR_AUTH_TYPE_CCKM_WPA: + case eCSR_AUTH_TYPE_CCKM_RSN: +#endif + if (pWextState->wpaVersion & IW_AUTH_WPA_VERSION_DISABLED) { + + pRoamProfile->AuthType.authType[0] = + eCSR_AUTH_TYPE_OPEN_SYSTEM; + } else if (pWextState->wpaVersion & IW_AUTH_WPA_VERSION_WPA) { + +#ifdef FEATURE_WLAN_ESE + if ((RSNAuthType == eCSR_AUTH_TYPE_CCKM_WPA) && + ((pWextState->authKeyMgmt & IW_AUTH_KEY_MGMT_802_1X) + == IW_AUTH_KEY_MGMT_802_1X)) { + hdd_info("set authType to CCKM WPA. AKM also 802.1X."); + pRoamProfile->AuthType.authType[0] = + eCSR_AUTH_TYPE_CCKM_WPA; + } else if (RSNAuthType == eCSR_AUTH_TYPE_CCKM_WPA) { + hdd_info("Last chance to set authType to CCKM WPA."); + pRoamProfile->AuthType.authType[0] = + eCSR_AUTH_TYPE_CCKM_WPA; + } else +#endif + if ((pWextState-> + authKeyMgmt & IW_AUTH_KEY_MGMT_802_1X) + == IW_AUTH_KEY_MGMT_802_1X) { + pRoamProfile->AuthType.authType[0] = + eCSR_AUTH_TYPE_WPA; + } else + if ((pWextState->authKeyMgmt & IW_AUTH_KEY_MGMT_PSK) + == IW_AUTH_KEY_MGMT_PSK) { + pRoamProfile->AuthType.authType[0] = + eCSR_AUTH_TYPE_WPA_PSK; + } else { + pRoamProfile->AuthType.authType[0] = + eCSR_AUTH_TYPE_WPA_NONE; + } + } + if (pWextState->wpaVersion & IW_AUTH_WPA_VERSION_WPA2) { +#ifdef FEATURE_WLAN_ESE + if ((RSNAuthType == eCSR_AUTH_TYPE_CCKM_RSN) && + ((pWextState->authKeyMgmt & IW_AUTH_KEY_MGMT_802_1X) + == IW_AUTH_KEY_MGMT_802_1X)) { + hdd_info("set authType to CCKM RSN. AKM also 802.1X."); + pRoamProfile->AuthType.authType[0] = + eCSR_AUTH_TYPE_CCKM_RSN; + } else if (RSNAuthType == eCSR_AUTH_TYPE_CCKM_RSN) { + hdd_info("Last chance to set authType to CCKM RSN."); + pRoamProfile->AuthType.authType[0] = + eCSR_AUTH_TYPE_CCKM_RSN; + } else +#endif + + if ((RSNAuthType == eCSR_AUTH_TYPE_FT_RSN) && + ((pWextState-> + authKeyMgmt & IW_AUTH_KEY_MGMT_802_1X) + == IW_AUTH_KEY_MGMT_802_1X)) { + pRoamProfile->AuthType.authType[0] = + eCSR_AUTH_TYPE_FT_RSN; + } else if ((RSNAuthType == eCSR_AUTH_TYPE_FT_RSN_PSK) + && + ((pWextState-> + authKeyMgmt & IW_AUTH_KEY_MGMT_PSK) + == IW_AUTH_KEY_MGMT_PSK)) { + pRoamProfile->AuthType.authType[0] = + eCSR_AUTH_TYPE_FT_RSN_PSK; + } else + +#ifdef WLAN_FEATURE_11W + if (RSNAuthType == eCSR_AUTH_TYPE_RSN_PSK_SHA256) { + pRoamProfile->AuthType.authType[0] = + eCSR_AUTH_TYPE_RSN_PSK_SHA256; + } else if (RSNAuthType == + eCSR_AUTH_TYPE_RSN_8021X_SHA256) { + pRoamProfile->AuthType.authType[0] = + eCSR_AUTH_TYPE_RSN_8021X_SHA256; + } else +#endif + + if ((pWextState-> + authKeyMgmt & IW_AUTH_KEY_MGMT_802_1X) + == IW_AUTH_KEY_MGMT_802_1X) { + pRoamProfile->AuthType.authType[0] = + eCSR_AUTH_TYPE_RSN; + } else + if ((pWextState->authKeyMgmt & IW_AUTH_KEY_MGMT_PSK) + == IW_AUTH_KEY_MGMT_PSK) { + pRoamProfile->AuthType.authType[0] = + eCSR_AUTH_TYPE_RSN_PSK; + } else { + pRoamProfile->AuthType.authType[0] = + eCSR_AUTH_TYPE_UNKNOWN; + } + } + break; + + case eCSR_AUTH_TYPE_SHARED_KEY: + + pRoamProfile->AuthType.authType[0] = eCSR_AUTH_TYPE_SHARED_KEY; + break; + default: + +#ifdef FEATURE_WLAN_ESE + hdd_info("In default, unknown auth type."); +#endif /* FEATURE_WLAN_ESE */ + pRoamProfile->AuthType.authType[0] = eCSR_AUTH_TYPE_UNKNOWN; + break; + } + + hdd_info("Set roam Authtype to %d", + pWextState->roamProfile.AuthType.authType[0]); + + return 0; +} + +/** + * __iw_set_essid() - This function sets the ssid received from wpa_supplicant + * to the CSR roam profile. + * + * @dev: Pointer to the net device. + * @info: Pointer to the iw_request_info. + * @wrqu: Pointer to the iwreq_data. + * @extra: Pointer to the data. + * + * Return: 0 for success, error number on failure + */ +static int __iw_set_essid(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + uint32_t status = 0; + hdd_wext_state_t *pWextState; + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *hdd_ctx; + uint32_t roamId; + tCsrRoamProfile *pRoamProfile; + eCsrAuthType RSNAuthType; + tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter); + int ret; + + ENTER_DEV(dev); + + hdd_ctx = WLAN_HDD_GET_CTX(pAdapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return ret; + + if (pAdapter->device_mode != QDF_STA_MODE && + pAdapter->device_mode != QDF_IBSS_MODE && + pAdapter->device_mode != QDF_P2P_CLIENT_MODE) { + hdd_info("device mode %s(%d) is not allowed", + hdd_device_mode_to_string(pAdapter->device_mode), + pAdapter->device_mode); + return -EINVAL; + } + + pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter); + + if (pWextState->mTKIPCounterMeasures == TKIP_COUNTER_MEASURE_STARTED) { + hdd_info("Counter measure is in progress"); + return -EBUSY; + } + if (SIR_MAC_MAX_SSID_LENGTH < wrqu->essid.length) + return -EINVAL; + + pRoamProfile = &pWextState->roamProfile; + /*Try disconnecting if already in connected state*/ + status = wlan_hdd_try_disconnect(pAdapter); + if (0 > status) { + hdd_err("Failed to disconnect the existing connection"); + return -EALREADY; + } + + /* + * when cfg80211 defined, wpa_supplicant wext driver uses + * zero-length, null-string ssid for force disconnection. + * after disconnection (if previously connected) and cleaning ssid, + * driver MUST return success. + */ + if (0 == wrqu->essid.length) + return 0; + + status = hdd_wmm_get_uapsd_mask(pAdapter, + &pWextState->roamProfile.uapsd_mask); + if (QDF_STATUS_SUCCESS != status) + pWextState->roamProfile.uapsd_mask = 0; + + pWextState->roamProfile.SSIDs.numOfSSIDs = 1; + + pWextState->roamProfile.SSIDs.SSIDList->SSID.length = + wrqu->essid.length; + + qdf_mem_zero(pWextState->roamProfile.SSIDs.SSIDList->SSID.ssId, + sizeof(pWextState->roamProfile.SSIDs.SSIDList->SSID.ssId)); + qdf_mem_copy((void *)(pWextState->roamProfile.SSIDs.SSIDList->SSID. + ssId), extra, wrqu->essid.length); + if (IW_AUTH_WPA_VERSION_WPA == pWextState->wpaVersion + || IW_AUTH_WPA_VERSION_WPA2 == pWextState->wpaVersion) { + + /* set gen ie */ + hdd_set_genie_to_csr(pAdapter, &RSNAuthType); + + /* set auth */ + hdd_set_csr_auth_type(pAdapter, RSNAuthType); + } +#ifdef FEATURE_WLAN_WAPI + hdd_notice("Setting WAPI AUTH Type and Encryption Mode values"); + if (pAdapter->wapi_info.nWapiMode) { + switch (pAdapter->wapi_info.wapiAuthMode) { + case WAPI_AUTH_MODE_PSK: + { + hdd_notice("WAPI AUTH TYPE: PSK: %d", + pAdapter->wapi_info.wapiAuthMode); + pRoamProfile->AuthType.numEntries = 1; + pRoamProfile->AuthType.authType[0] = + eCSR_AUTH_TYPE_WAPI_WAI_PSK; + break; + } + case WAPI_AUTH_MODE_CERT: + { + hdd_notice("WAPI AUTH TYPE: CERT: %d", + pAdapter->wapi_info.wapiAuthMode); + pRoamProfile->AuthType.numEntries = 1; + pRoamProfile->AuthType.authType[0] = + eCSR_AUTH_TYPE_WAPI_WAI_CERTIFICATE; + break; + } + } /* End of switch */ + if (pAdapter->wapi_info.wapiAuthMode == WAPI_AUTH_MODE_PSK || + pAdapter->wapi_info.wapiAuthMode == WAPI_AUTH_MODE_CERT) { + hdd_notice("WAPI PAIRWISE/GROUP ENCRYPTION: WPI"); + pRoamProfile->EncryptionType.numEntries = 1; + pRoamProfile->EncryptionType.encryptionType[0] = + eCSR_ENCRYPT_TYPE_WPI; + pRoamProfile->mcEncryptionType.numEntries = 1; + pRoamProfile->mcEncryptionType.encryptionType[0] = + eCSR_ENCRYPT_TYPE_WPI; + } + } +#endif /* FEATURE_WLAN_WAPI */ + /* if previous genIE is not NULL, update AssocIE */ + if (0 != pWextState->genIE.length) { + memset(&pWextState->assocAddIE, 0, + sizeof(pWextState->assocAddIE)); + memcpy(pWextState->assocAddIE.addIEdata, + pWextState->genIE.addIEdata, pWextState->genIE.length); + pWextState->assocAddIE.length = pWextState->genIE.length; + pWextState->roamProfile.pAddIEAssoc = + pWextState->assocAddIE.addIEdata; + pWextState->roamProfile.nAddIEAssocLength = + pWextState->assocAddIE.length; + + /* clear previous genIE after use it */ + memset(&pWextState->genIE, 0, sizeof(pWextState->genIE)); + } + + /* + * Assumes it is not WPS Association by default, except when + * pAddIEAssoc has WPS IE. + */ + pWextState->roamProfile.bWPSAssociation = false; + + if (NULL != wlan_hdd_get_wps_ie_ptr(pWextState->roamProfile.pAddIEAssoc, + pWextState->roamProfile. + nAddIEAssocLength)) + pWextState->roamProfile.bWPSAssociation = true; + + /* Disable auto BMPS entry by PMC until DHCP is done */ + sme_set_dhcp_till_power_active_flag(WLAN_HDD_GET_HAL_CTX(pAdapter), + true); + + pWextState->roamProfile.csrPersona = pAdapter->device_mode; + + if (eCSR_BSS_TYPE_START_IBSS == pRoamProfile->BSSType) { + pRoamProfile->ch_params.ch_width = 0; + hdd_select_cbmode(pAdapter, + (WLAN_HDD_GET_CTX(pAdapter))->config->AdHocChannel5G, + &pRoamProfile->ch_params); + } + + /* + * Change conn_state to connecting before sme_roam_connect(), + * because sme_roam_connect() has a direct path to call + * hdd_sme_roam_callback(), which will change the conn_state + * If direct path, conn_state will be accordingly changed to + * NotConnected or Associated by either + * hdd_association_completion_handler() or hdd_dis_connect_handler() + * in sme_RoamCallback()if sme_RomConnect is to be queued, + * Connecting state will remain until it is completed. + * + * If connection state is not changed, + * connection state will remain in eConnectionState_NotConnected state. + * In hdd_association_completion_handler, "hddDisconInProgress" is + * set to true if conn state is eConnectionState_NotConnected. + * If "hddDisconInProgress" is set to true then cfg80211 layer is not + * informed of connect result indication which is an issue. + */ + if (QDF_STA_MODE == pAdapter->device_mode || + QDF_P2P_CLIENT_MODE == pAdapter->device_mode) + hdd_conn_set_connection_state(pAdapter, + eConnectionState_Connecting); + + status = sme_roam_connect(hHal, pAdapter->sessionId, + &(pWextState->roamProfile), &roamId); + if ((QDF_STATUS_SUCCESS != status) && + (QDF_STA_MODE == pAdapter->device_mode || + QDF_P2P_CLIENT_MODE == pAdapter->device_mode)) { + hdd_err("sme_roam_connect (session %d) failed with status %d. -> NotConnected", + pAdapter->sessionId, status); + /* change back to NotAssociated */ + hdd_conn_set_connection_state(pAdapter, + eConnectionState_NotConnected); + } + pRoamProfile->ChannelInfo.ChannelList = NULL; + pRoamProfile->ChannelInfo.numOfChannels = 0; + + EXIT(); + return status; +} + +/** + * iw_set_essid() - set essid handler function + * @dev: Pointer to the net device. + * @info: Pointer to the iw_request_info. + * @wrqu: Pointer to the iwreq_data. + * @extra: Pointer to the data. + * + * Return: 0 for success, error number on failure + */ +int iw_set_essid(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_set_essid(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __iw_get_essid() - This function returns the essid to the wpa_supplicant + * @dev: pointer to the net device + * @info: pointer to the iw request info + * @dwrq: pointer to iw_point + * @extra: pointer to the data + * + * Return: 0 on success, error number otherwise + */ +static int __iw_get_essid(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *hdd_ctx; + hdd_wext_state_t *wextBuf = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter); + hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + int ret; + + ENTER_DEV(dev); + + hdd_ctx = WLAN_HDD_GET_CTX(pAdapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return ret; + + if ((pHddStaCtx->conn_info.connState == eConnectionState_Associated && + wextBuf->roamProfile.SSIDs.SSIDList->SSID.length > 0) || + ((pHddStaCtx->conn_info.connState == eConnectionState_IbssConnected + || pHddStaCtx->conn_info.connState == + eConnectionState_IbssDisconnected) + && wextBuf->roamProfile.SSIDs.SSIDList->SSID.length > 0)) { + dwrq->length = pHddStaCtx->conn_info.SSID.SSID.length; + memcpy(extra, pHddStaCtx->conn_info.SSID.SSID.ssId, + dwrq->length); + dwrq->flags = 1; + } else { + memset(extra, 0, dwrq->length); + dwrq->length = 0; + dwrq->flags = 0; + } + EXIT(); + return 0; +} + +/** + * iw_get_essid() - get essid handler function + * @dev: Pointer to the net device. + * @info: Pointer to the iw_request_info. + * @wrqu: Pointer to the iwreq_data. + * @extra: Pointer to the data. + * + * Return: 0 for success, error number on failure + */ +int iw_get_essid(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_get_essid(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __iw_set_auth() - + * This function sets the auth type received from the wpa_supplicant + * @dev: pointer to the net device + * @info: pointer to the iw request info + * @wrqu: pointer to iwreq_data + * @extra: pointer to the data + * + * Return: 0 on success, error number otherwise + */ +static int __iw_set_auth(struct net_device *dev, struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *hdd_ctx; + hdd_wext_state_t *pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter); + hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + tCsrRoamProfile *pRoamProfile = &pWextState->roamProfile; + eCsrEncryptionType mcEncryptionType; + eCsrEncryptionType ucEncryptionType; + int ret; + + ENTER_DEV(dev); + + hdd_ctx = WLAN_HDD_GET_CTX(pAdapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return ret; + + switch (wrqu->param.flags & IW_AUTH_INDEX) { + case IW_AUTH_WPA_VERSION: + pWextState->wpaVersion = wrqu->param.value; + break; + + case IW_AUTH_CIPHER_PAIRWISE: + { + if (wrqu->param.value & IW_AUTH_CIPHER_NONE) { + ucEncryptionType = eCSR_ENCRYPT_TYPE_NONE; + } else if (wrqu->param.value & IW_AUTH_CIPHER_TKIP) { + ucEncryptionType = eCSR_ENCRYPT_TYPE_TKIP; + } else if (wrqu->param.value & IW_AUTH_CIPHER_CCMP) { + ucEncryptionType = eCSR_ENCRYPT_TYPE_AES; + } else if (wrqu->param.value & IW_AUTH_CIPHER_WEP40) { + if ((IW_AUTH_KEY_MGMT_802_1X + == + (pWextState-> + authKeyMgmt & IW_AUTH_KEY_MGMT_802_1X)) + && (eCSR_AUTH_TYPE_OPEN_SYSTEM == + pHddStaCtx->conn_info.authType)) + /*Dynamic WEP key */ + ucEncryptionType = + eCSR_ENCRYPT_TYPE_WEP40; + else + /*Static WEP key */ + ucEncryptionType = + eCSR_ENCRYPT_TYPE_WEP40_STATICKEY; + } else if (wrqu->param.value & IW_AUTH_CIPHER_WEP104) { + if ((IW_AUTH_KEY_MGMT_802_1X + == + (pWextState-> + authKeyMgmt & IW_AUTH_KEY_MGMT_802_1X)) + && (eCSR_AUTH_TYPE_OPEN_SYSTEM == + pHddStaCtx->conn_info.authType)) + /*Dynamic WEP key */ + ucEncryptionType = + eCSR_ENCRYPT_TYPE_WEP104; + else + /*Static WEP key */ + ucEncryptionType = + eCSR_ENCRYPT_TYPE_WEP104_STATICKEY; + } else { + hdd_warn("value %d UNKNOWN IW_AUTH_CIPHER", + wrqu->param.value); + return -EINVAL; + } + + pRoamProfile->EncryptionType.numEntries = 1; + pRoamProfile->EncryptionType.encryptionType[0] = + ucEncryptionType; + } + break; + case IW_AUTH_CIPHER_GROUP: + { + if (wrqu->param.value & IW_AUTH_CIPHER_NONE) { + mcEncryptionType = eCSR_ENCRYPT_TYPE_NONE; + } else if (wrqu->param.value & IW_AUTH_CIPHER_TKIP) { + mcEncryptionType = eCSR_ENCRYPT_TYPE_TKIP; + } else if (wrqu->param.value & IW_AUTH_CIPHER_CCMP) { + mcEncryptionType = eCSR_ENCRYPT_TYPE_AES; + } else if (wrqu->param.value & IW_AUTH_CIPHER_WEP40) { + if ((IW_AUTH_KEY_MGMT_802_1X + == + (pWextState-> + authKeyMgmt & IW_AUTH_KEY_MGMT_802_1X)) + && (eCSR_AUTH_TYPE_OPEN_SYSTEM == + pHddStaCtx->conn_info.authType)) + mcEncryptionType = + eCSR_ENCRYPT_TYPE_WEP40; + else + mcEncryptionType = + eCSR_ENCRYPT_TYPE_WEP40_STATICKEY; + } else if (wrqu->param.value & IW_AUTH_CIPHER_WEP104) { + /* Dynamic WEP keys won't work with shared keys */ + if ((IW_AUTH_KEY_MGMT_802_1X + == + (pWextState-> + authKeyMgmt & IW_AUTH_KEY_MGMT_802_1X)) + && (eCSR_AUTH_TYPE_OPEN_SYSTEM == + pHddStaCtx->conn_info.authType)) { + mcEncryptionType = + eCSR_ENCRYPT_TYPE_WEP104; + } else { + mcEncryptionType = + eCSR_ENCRYPT_TYPE_WEP104_STATICKEY; + } + } else { + hdd_warn("value %d UNKNOWN IW_AUTH_CIPHER", + wrqu->param.value); + return -EINVAL; + } + + pRoamProfile->mcEncryptionType.numEntries = 1; + pRoamProfile->mcEncryptionType.encryptionType[0] = + mcEncryptionType; + } + break; + + case IW_AUTH_80211_AUTH_ALG: + { + /* Save the auth algo here and set auth type to SME Roam profile + in the iw_set_ap_address */ + if (wrqu->param.value & IW_AUTH_ALG_OPEN_SYSTEM) + pHddStaCtx->conn_info.authType = + eCSR_AUTH_TYPE_OPEN_SYSTEM; + + else if (wrqu->param.value & IW_AUTH_ALG_SHARED_KEY) + pHddStaCtx->conn_info.authType = + eCSR_AUTH_TYPE_SHARED_KEY; + + else if (wrqu->param.value & IW_AUTH_ALG_LEAP) + /*Not supported */ + pHddStaCtx->conn_info.authType = + eCSR_AUTH_TYPE_OPEN_SYSTEM; + pWextState->roamProfile.AuthType.authType[0] = + pHddStaCtx->conn_info.authType; + } + break; + + case IW_AUTH_KEY_MGMT: + { +#ifdef FEATURE_WLAN_ESE +#define IW_AUTH_KEY_MGMT_CCKM 8 /* Should be in linux/wireless.h */ + /*Check for CCKM AKM type */ + if (wrqu->param.value & IW_AUTH_KEY_MGMT_CCKM) { + hdd_info("CCKM AKM Set %d", wrqu->param.value); + /* Set the CCKM bit in authKeyMgmt */ + /* + * Right now, this breaks all ref to authKeyMgmt because + * our code doesn't realize it is a "bitfield" + */ + pWextState->authKeyMgmt |= + IW_AUTH_KEY_MGMT_CCKM; + /* Set the key management to 802.1X */ + /* pWextState->authKeyMgmt = IW_AUTH_KEY_MGMT_802_1X; */ + pWextState->isESEConnection = true; + /* + * This is test code. I need to actually KNOW whether + * this is an RSN Assoc or WPA. + */ + pWextState->collectedAuthType = + eCSR_AUTH_TYPE_CCKM_RSN; + } else if (wrqu->param.value & IW_AUTH_KEY_MGMT_PSK) { + /* Save the key management */ + pWextState->authKeyMgmt |= IW_AUTH_KEY_MGMT_PSK; + pWextState->collectedAuthType = + eCSR_AUTH_TYPE_RSN; + } else + if (!(wrqu->param.value & IW_AUTH_KEY_MGMT_802_1X)) { + pWextState->collectedAuthType = eCSR_AUTH_TYPE_NONE; + /* Save the key management anyway */ + pWextState->authKeyMgmt = wrqu->param.value; + } else { /* It must be IW_AUTH_KEY_MGMT_802_1X */ + /* Save the key management */ + pWextState->authKeyMgmt |= + IW_AUTH_KEY_MGMT_802_1X; + pWextState->collectedAuthType = + eCSR_AUTH_TYPE_RSN; + } +#else + /* Save the key management */ + pWextState->authKeyMgmt = wrqu->param.value; +#endif /* FEATURE_WLAN_ESE */ + } + break; + + case IW_AUTH_TKIP_COUNTERMEASURES: + { + if (wrqu->param.value) { + hdd_info("Counter Measure started %d", + wrqu->param.value); + pWextState->mTKIPCounterMeasures = + TKIP_COUNTER_MEASURE_STARTED; + } else { + hdd_info("Counter Measure stopped=%d", + wrqu->param.value); + pWextState->mTKIPCounterMeasures = + TKIP_COUNTER_MEASURE_STOPED; + } + } + break; + case IW_AUTH_DROP_UNENCRYPTED: + case IW_AUTH_WPA_ENABLED: + case IW_AUTH_RX_UNENCRYPTED_EAPOL: + case IW_AUTH_ROAMING_CONTROL: + case IW_AUTH_PRIVACY_INVOKED: + + default: + + hdd_warn("called with unsupported auth type %d", + wrqu->param.flags & IW_AUTH_INDEX); + break; + } + + EXIT(); + return 0; +} + +/** + * iw_set_auth() - set auth callback function + * @dev: Pointer to the net device. + * @info: Pointer to the iw_request_info. + * @wrqu: Pointer to the iwreq_data. + * @extra: Pointer to the data. + * + * Return: 0 for success, error number on failure. + */ +int iw_set_auth(struct net_device *dev, struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_set_auth(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} +/** + * __iw_get_auth() - + * This function returns the auth type to the wpa_supplicant + * @dev: pointer to the net device + * @info: pointer to the iw request info + * @wrqu: pointer to iwreq_data + * @extra: pointer to the data + * + * Return: 0 on success, error number otherwise + */ +static int __iw_get_auth(struct net_device *dev, struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *hdd_ctx; + hdd_wext_state_t *pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter); + tCsrRoamProfile *pRoamProfile = &pWextState->roamProfile; + int ret; + + ENTER_DEV(dev); + + hdd_ctx = WLAN_HDD_GET_CTX(pAdapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return ret; + + switch (pRoamProfile->negotiatedAuthType) { + case eCSR_AUTH_TYPE_WPA_NONE: + wrqu->param.flags = IW_AUTH_WPA_VERSION; + wrqu->param.value = IW_AUTH_WPA_VERSION_DISABLED; + break; + case eCSR_AUTH_TYPE_WPA: + wrqu->param.flags = IW_AUTH_WPA_VERSION; + wrqu->param.value = IW_AUTH_WPA_VERSION_WPA; + break; + + case eCSR_AUTH_TYPE_FT_RSN: + case eCSR_AUTH_TYPE_RSN: + wrqu->param.flags = IW_AUTH_WPA_VERSION; + wrqu->param.value = IW_AUTH_WPA_VERSION_WPA2; + break; + case eCSR_AUTH_TYPE_OPEN_SYSTEM: + wrqu->param.value = IW_AUTH_ALG_OPEN_SYSTEM; + break; + case eCSR_AUTH_TYPE_SHARED_KEY: + wrqu->param.value = IW_AUTH_ALG_SHARED_KEY; + break; + case eCSR_AUTH_TYPE_UNKNOWN: + hdd_info("called with unknown auth type"); + wrqu->param.value = IW_AUTH_ALG_OPEN_SYSTEM; + break; + case eCSR_AUTH_TYPE_AUTOSWITCH: + wrqu->param.value = IW_AUTH_ALG_OPEN_SYSTEM; + break; + case eCSR_AUTH_TYPE_WPA_PSK: + hdd_info("called with WPA PSK auth type"); + wrqu->param.value = IW_AUTH_ALG_OPEN_SYSTEM; + return -EIO; + + case eCSR_AUTH_TYPE_FT_RSN_PSK: + case eCSR_AUTH_TYPE_RSN_PSK: +#ifdef WLAN_FEATURE_11W + case eCSR_AUTH_TYPE_RSN_PSK_SHA256: + case eCSR_AUTH_TYPE_RSN_8021X_SHA256: +#endif + hdd_info("called with RSN PSK auth type"); + wrqu->param.value = IW_AUTH_ALG_OPEN_SYSTEM; + return -EIO; + default: + hdd_err("called with unknown auth type"); + wrqu->param.value = IW_AUTH_ALG_OPEN_SYSTEM; + return -EIO; + } + if (((wrqu->param.flags & IW_AUTH_INDEX) == IW_AUTH_CIPHER_PAIRWISE)) { + switch (pRoamProfile->negotiatedUCEncryptionType) { + case eCSR_ENCRYPT_TYPE_NONE: + wrqu->param.value = IW_AUTH_CIPHER_NONE; + break; + case eCSR_ENCRYPT_TYPE_WEP40: + case eCSR_ENCRYPT_TYPE_WEP40_STATICKEY: + wrqu->param.value = IW_AUTH_CIPHER_WEP40; + break; + case eCSR_ENCRYPT_TYPE_TKIP: + wrqu->param.value = IW_AUTH_CIPHER_TKIP; + break; + case eCSR_ENCRYPT_TYPE_WEP104: + case eCSR_ENCRYPT_TYPE_WEP104_STATICKEY: + wrqu->param.value = IW_AUTH_CIPHER_WEP104; + break; + case eCSR_ENCRYPT_TYPE_AES: + wrqu->param.value = IW_AUTH_CIPHER_CCMP; + break; + default: + hdd_notice("called with unknown auth type %d", + pRoamProfile->negotiatedUCEncryptionType); + return -EIO; + } + } + + if (((wrqu->param.flags & IW_AUTH_INDEX) == IW_AUTH_CIPHER_GROUP)) { + switch (pRoamProfile->negotiatedMCEncryptionType) { + case eCSR_ENCRYPT_TYPE_NONE: + wrqu->param.value = IW_AUTH_CIPHER_NONE; + break; + case eCSR_ENCRYPT_TYPE_WEP40: + case eCSR_ENCRYPT_TYPE_WEP40_STATICKEY: + wrqu->param.value = IW_AUTH_CIPHER_WEP40; + break; + case eCSR_ENCRYPT_TYPE_TKIP: + wrqu->param.value = IW_AUTH_CIPHER_TKIP; + break; + case eCSR_ENCRYPT_TYPE_WEP104: + case eCSR_ENCRYPT_TYPE_WEP104_STATICKEY: + wrqu->param.value = IW_AUTH_CIPHER_WEP104; + break; + case eCSR_ENCRYPT_TYPE_AES: + wrqu->param.value = IW_AUTH_CIPHER_CCMP; + break; + default: + hdd_info("called with unknown auth type %d", + pRoamProfile->negotiatedMCEncryptionType); + return -EIO; + } + } + + hdd_info("called with auth type %d", + pRoamProfile->AuthType.authType[0]); + EXIT(); + return 0; +} + +/** + * iw_get_auth() - get auth callback function + * @dev: Pointer to the net device. + * @info: Pointer to the iw_request_info. + * @wrqu: Pointer to the iwreq_data. + * @extra: Pointer to the data. + * + * Return: 0 for success, error number on failure. + */ +int iw_get_auth(struct net_device *dev, struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_get_auth(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __iw_set_ap_address() - set ap address + * @dev: pointer to the net device + * @info: pointer to the iw request info + * @wrqu: pointer to iwreq_data + * @extra: pointer to the data + * + * This function updates the HDD global station context connection info + * BSSID with the MAC address received from the wpa_supplicant. + * + * Return: 0 on success, error number otherwise + */ +static int __iw_set_ap_address(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + + hdd_adapter_t *adapter; + hdd_context_t *hdd_ctx; + hdd_station_ctx_t *pHddStaCtx = + WLAN_HDD_GET_STATION_CTX_PTR(WLAN_HDD_GET_PRIV_PTR(dev)); + uint8_t *pMacAddress = NULL; + int ret; + + ENTER_DEV(dev); + + adapter = WLAN_HDD_GET_PRIV_PTR(dev); + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return ret; + + pMacAddress = (uint8_t *) wrqu->ap_addr.sa_data; + hdd_info(" " MAC_ADDRESS_STR, MAC_ADDR_ARRAY(pMacAddress)); + qdf_mem_copy(pHddStaCtx->conn_info.bssId.bytes, pMacAddress, + sizeof(struct qdf_mac_addr)); + EXIT(); + + return 0; +} + +/** + * iw_set_ap_address() - set ap addresses callback function + * @dev: Pointer to the net device. + * @info: Pointer to the iw_request_info. + * @wrqu: Pointer to the iwreq_data. + * @extra: Pointer to the data. + * + * Return: 0 for success, error number on failure. + */ +int iw_set_ap_address(struct net_device *dev, struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_set_ap_address(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __iw_get_ap_address() - get ap address + * @dev: pointer to the net device + * @info: pointer to the iw request info + * @wrqu: pointer to iwreq_data + * @extra: pointer to the data + * + * This function returns currently associated BSSID. + * + * Return: 0 on success, error number otherwise + */ +static int __iw_get_ap_address(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *hdd_ctx; + hdd_station_ctx_t *pHddStaCtx = + WLAN_HDD_GET_STATION_CTX_PTR(adapter); + int ret; + + ENTER_DEV(dev); + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return ret; + + if (pHddStaCtx->conn_info.connState == eConnectionState_Associated || + eConnectionState_IbssConnected == pHddStaCtx->conn_info.connState) { + qdf_mem_copy(wrqu->ap_addr.sa_data, + pHddStaCtx->conn_info.bssId.bytes, + QDF_MAC_ADDR_SIZE); + } else { + memset(wrqu->ap_addr.sa_data, 0, sizeof(wrqu->ap_addr.sa_data)); + } + EXIT(); + return 0; +} + +/** + * iw_get_ap_address() - get ap addresses callback function + * @dev: Pointer to the net device. + * @info: Pointer to the iw_request_info. + * @wrqu: Pointer to the iwreq_data. + * @extra: Pointer to the data. + * + * Return: 0 for success, error number on failure. + */ +int iw_get_ap_address(struct net_device *dev, struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_get_ap_address(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} diff --git a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_cfg.c b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_cfg.c new file mode 100644 index 0000000000000000000000000000000000000000..461be70cc26757ce996065802d229d350c6ea2b6 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_cfg.c @@ -0,0 +1,7809 @@ +/* + * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: wlan_hdd_cfg.c + * + * WLAN Host Device Driver configuration interface implementation + */ + +/* Include Files */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static void +cb_notify_set_roam_prefer5_g_hz(hdd_context_t *pHddCtx, unsigned long notifyId) +{ + sme_update_roam_prefer5_g_hz(pHddCtx->hHal, + pHddCtx->config->nRoamPrefer5GHz); +} + +static void +cb_notify_set_roam_rssi_diff(hdd_context_t *pHddCtx, unsigned long notifyId) +{ + sme_update_roam_rssi_diff(pHddCtx->hHal, + 0, pHddCtx->config->RoamRssiDiff); +} + +static void +cb_notify_set_fast_transition_enabled(hdd_context_t *pHddCtx, + unsigned long notifyId) +{ + sme_update_fast_transition_enabled(pHddCtx->hHal, + pHddCtx->config-> + isFastTransitionEnabled); +} + +static void +cb_notify_set_roam_intra_band(hdd_context_t *pHddCtx, unsigned long notifyId) +{ + sme_set_roam_intra_band(pHddCtx->hHal, pHddCtx->config->nRoamIntraBand); +} + +static void cb_notify_set_wes_mode(hdd_context_t *pHddCtx, unsigned long notifyId) +{ + /* At the point this routine is called, the value in the hdd config + table has already been updated */ + sme_update_wes_mode(pHddCtx->hHal, pHddCtx->config->isWESModeEnabled, 0); +} + +static void +cb_notify_set_roam_scan_n_probes(hdd_context_t *pHddCtx, unsigned long notifyId) +{ + sme_update_roam_scan_n_probes(pHddCtx->hHal, 0, pHddCtx->config->nProbes); +} + +static void +cb_notify_set_roam_scan_home_away_time(hdd_context_t *pHddCtx, unsigned long notifyId) +{ + sme_update_roam_scan_home_away_time(pHddCtx->hHal, 0, + pHddCtx->config->nRoamScanHomeAwayTime, + true); +} + +static void +notify_is_fast_roam_ini_feature_enabled(hdd_context_t *pHddCtx, + unsigned long notifyId) +{ + /* At the point this routine is called, the value in the hdd config + table has already been updated */ + sme_update_is_fast_roam_ini_feature_enabled(pHddCtx->hHal, 0, + pHddCtx->config-> + isFastRoamIniFeatureEnabled); +} + +static void +notify_is_mawc_ini_feature_enabled(hdd_context_t *pHddCtx, unsigned long notifyId) +{ + /* At the point this routine is called, the value in the hdd config + table has already been updated */ + sme_update_is_mawc_ini_feature_enabled(pHddCtx->hHal, + pHddCtx->config->MAWCEnabled); +} + +#ifdef FEATURE_WLAN_ESE +static void +cb_notify_set_ese_feature_enabled(hdd_context_t *pHddCtx, unsigned long notifyId) +{ + /* At the point this routine is called, the value in the hdd config + table has already been updated */ + sme_update_is_ese_feature_enabled(pHddCtx->hHal, 0, + pHddCtx->config->isEseIniFeatureEnabled); +} +#endif + +static void +cb_notify_set_fw_rssi_monitoring(hdd_context_t *pHddCtx, unsigned long notifyId) +{ + /* At the point this routine is called, the value in the hdd config + table has already been updated */ + sme_update_config_fw_rssi_monitoring(pHddCtx->hHal, + pHddCtx->config-> + fEnableFwRssiMonitoring); +} + +static void cb_notify_set_opportunistic_scan_threshold_diff(hdd_context_t *pHddCtx, + unsigned long notifyId) +{ + /* At the point this routine is called, the value in the hdd config + table has already been updated */ + sme_set_roam_opportunistic_scan_threshold_diff(pHddCtx->hHal, 0, + pHddCtx->config-> + nOpportunisticThresholdDiff); +} + +static void cb_notify_set_roam_rescan_rssi_diff(hdd_context_t *pHddCtx, + unsigned long notifyId) +{ + /* At the point this routine is called, the value in the hdd config + table has already been updated */ + sme_set_roam_rescan_rssi_diff(pHddCtx->hHal, + 0, pHddCtx->config->nRoamRescanRssiDiff); +} + +static void +cb_notify_set_neighbor_lookup_rssi_threshold(hdd_context_t *pHddCtx, + unsigned long notifyId) +{ + /* At the point this routine is called, the value in the hdd config + table has already been updated */ + sme_set_neighbor_lookup_rssi_threshold(pHddCtx->hHal, 0, + pHddCtx->config-> + nNeighborLookupRssiThreshold); +} + +static void +cb_notify_set_delay_before_vdev_stop(hdd_context_t *hdd_ctx, + unsigned long notify_id) +{ + /* + * At the point this routine is called, the value in the cfg_ini + * table has already been updated + */ + sme_set_delay_before_vdev_stop(hdd_ctx->hHal, 0, + hdd_ctx->config->delay_before_vdev_stop); +} + +static void +cb_notify_set_neighbor_scan_period(hdd_context_t *pHddCtx, unsigned long notifyId) +{ + /* At the point this routine is called, the value in the hdd config + table has already been updated */ + sme_set_neighbor_scan_period(pHddCtx->hHal, 0, + pHddCtx->config->nNeighborScanPeriod); +} + +static void +cb_notify_set_neighbor_results_refresh_period(hdd_context_t *pHddCtx, + unsigned long notifyId) +{ + /* At the point this routine is called, the value in the hdd config + table has already been updated */ + sme_set_neighbor_scan_refresh_period(pHddCtx->hHal, 0, + pHddCtx->config-> + nNeighborResultsRefreshPeriod); +} + +static void +cb_notify_set_empty_scan_refresh_period(hdd_context_t *pHddCtx, + unsigned long notifyId) +{ + /* At the point this routine is called, the value in the hdd config + table has already been updated */ + sme_update_empty_scan_refresh_period(pHddCtx->hHal, 0, + pHddCtx->config-> + nEmptyScanRefreshPeriod); +} + +static void +cb_notify_set_neighbor_scan_min_chan_time(hdd_context_t *pHddCtx, + unsigned long notifyId) +{ + /* At the point this routine is called, the value in the hdd config + table has already been updated */ + sme_set_neighbor_scan_min_chan_time(pHddCtx->hHal, + pHddCtx->config-> + nNeighborScanMinChanTime, 0); +} + +static void +cb_notify_set_neighbor_scan_max_chan_time(hdd_context_t *pHddCtx, + unsigned long notifyId) +{ + sme_set_neighbor_scan_max_chan_time(pHddCtx->hHal, 0, + pHddCtx->config-> + nNeighborScanMaxChanTime); +} + +static void cb_notify_set_roam_bmiss_first_bcnt(hdd_context_t *pHddCtx, + unsigned long notifyId) +{ + /* At the point this routine is called, the value in the hdd config + table has already been updated */ + sme_set_roam_bmiss_first_bcnt(pHddCtx->hHal, + 0, pHddCtx->config->nRoamBmissFirstBcnt); +} + +static void cb_notify_set_roam_bmiss_final_bcnt(hdd_context_t *pHddCtx, + unsigned long notifyId) +{ + sme_set_roam_bmiss_final_bcnt(pHddCtx->hHal, 0, + pHddCtx->config->nRoamBmissFinalBcnt); +} + +static void cb_notify_set_roam_beacon_rssi_weight(hdd_context_t *pHddCtx, + unsigned long notifyId) +{ + sme_set_roam_beacon_rssi_weight(pHddCtx->hHal, 0, + pHddCtx->config->nRoamBeaconRssiWeight); +} + +static void +cb_notify_set_dfs_scan_mode(hdd_context_t *pHddCtx, unsigned long notifyId) +{ + /* At the point this routine is called, the value in the hdd config + table has already been updated */ + sme_update_dfs_scan_mode(pHddCtx->hHal, 0, + pHddCtx->config->allowDFSChannelRoam); +} + +static void cb_notify_set_enable_ssr(hdd_context_t *pHddCtx, + unsigned long notifyId) +{ + sme_update_enable_ssr(pHddCtx->hHal, pHddCtx->config->enableSSR); +} + +static void cb_notify_set_g_sap_preferred_chan_location(hdd_context_t *pHddCtx, + unsigned long notifyId) +{ + wlansap_set_dfs_preferred_channel_location(pHddCtx->hHal, + pHddCtx->config-> + gSapPreferredChanLocation); +} +static void ch_notify_set_g_disable_dfs_japan_w53(hdd_context_t *pHddCtx, + unsigned long notifyId) +{ + wlansap_set_dfs_restrict_japan_w53(pHddCtx->hHal, + pHddCtx->config-> + gDisableDfsJapanW53); +} +static void +cb_notify_update_roam_scan_offload_enabled(hdd_context_t *pHddCtx, + unsigned long notifyId) +{ + sme_update_roam_scan_offload_enabled(pHddCtx->hHal, + pHddCtx->config-> + isRoamOffloadScanEnabled); + if (0 == pHddCtx->config->isRoamOffloadScanEnabled) { + pHddCtx->config->bFastRoamInConIniFeatureEnabled = 0; + sme_update_enable_fast_roam_in_concurrency(pHddCtx->hHal, + pHddCtx->config-> + bFastRoamInConIniFeatureEnabled); + } +} + +static void +cb_notify_set_enable_fast_roam_in_concurrency(hdd_context_t *pHddCtx, + unsigned long notifyId) +{ + sme_update_enable_fast_roam_in_concurrency(pHddCtx->hHal, + pHddCtx->config-> + bFastRoamInConIniFeatureEnabled); +} + +/** + * cb_notify_set_roam_scan_hi_rssi_scan_params() - configure hi rssi + * scan params from cfg to sme. + * @hdd_ctx: HDD context data structure + * @notify_id: Identifies 1 of the 4 parameters to be modified + * + * Picks up the value from hdd configuration and passes it to SME. + * Return: void + */ + +static void +cb_notify_set_roam_scan_hi_rssi_scan_params(hdd_context_t *hdd_ctx, + unsigned long notify_id) +{ + int32_t val; + + if (wlan_hdd_validate_context(hdd_ctx)) { + return; + } + + switch (notify_id) { + case eCSR_HI_RSSI_SCAN_MAXCOUNT_ID: + val = hdd_ctx->config->nhi_rssi_scan_max_count; + break; + + case eCSR_HI_RSSI_SCAN_RSSI_DELTA_ID: + val = hdd_ctx->config->nhi_rssi_scan_rssi_delta; + break; + + case eCSR_HI_RSSI_SCAN_DELAY_ID: + val = hdd_ctx->config->nhi_rssi_scan_delay; + break; + + case eCSR_HI_RSSI_SCAN_RSSI_UB_ID: + val = hdd_ctx->config->nhi_rssi_scan_rssi_ub; + break; + + default: + return; + } + + sme_update_roam_scan_hi_rssi_scan_params(hdd_ctx->hHal, 0, + notify_id, val); +} + + +REG_TABLE_ENTRY g_registry_table[] = { + REG_VARIABLE(CFG_RTS_THRESHOLD_NAME, WLAN_PARAM_Integer, + struct hdd_config, RTSThreshold, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_RTS_THRESHOLD_DEFAULT, + CFG_RTS_THRESHOLD_MIN, + CFG_RTS_THRESHOLD_MAX), + + REG_VARIABLE(CFG_FRAG_THRESHOLD_NAME, WLAN_PARAM_Integer, + struct hdd_config, FragmentationThreshold, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_FRAG_THRESHOLD_DEFAULT, + CFG_FRAG_THRESHOLD_MIN, + CFG_FRAG_THRESHOLD_MAX), + + REG_VARIABLE(CFG_OPERATING_CHANNEL_NAME, WLAN_PARAM_Integer, + struct hdd_config, OperatingChannel, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_OPERATING_CHANNEL_DEFAULT, + CFG_OPERATING_CHANNEL_MIN, + CFG_OPERATING_CHANNEL_MAX), + + REG_VARIABLE(CFG_SHORT_SLOT_TIME_ENABLED_NAME, WLAN_PARAM_Integer, + struct hdd_config, ShortSlotTimeEnabled, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK, + CFG_SHORT_SLOT_TIME_ENABLED_DEFAULT, + CFG_SHORT_SLOT_TIME_ENABLED_MIN, + CFG_SHORT_SLOT_TIME_ENABLED_MAX), + + REG_VARIABLE(CFG_11D_SUPPORT_ENABLED_NAME, WLAN_PARAM_Integer, + struct hdd_config, Is11dSupportEnabled, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK, + CFG_11D_SUPPORT_ENABLED_DEFAULT, + CFG_11D_SUPPORT_ENABLED_MIN, + CFG_11D_SUPPORT_ENABLED_MAX), + + REG_VARIABLE(CFG_11H_SUPPORT_ENABLED_NAME, WLAN_PARAM_Integer, + struct hdd_config, Is11hSupportEnabled, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK, + CFG_11H_SUPPORT_ENABLED_DEFAULT, + CFG_11H_SUPPORT_ENABLED_MIN, + CFG_11H_SUPPORT_ENABLED_MAX), + + REG_VARIABLE(CFG_COUNTRY_CODE_PRIORITY_NAME, WLAN_PARAM_Integer, + struct hdd_config, fSupplicantCountryCodeHasPriority, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK, + CFG_COUNTRY_CODE_PRIORITY_DEFAULT, + CFG_COUNTRY_CODE_PRIORITY_MIN, + CFG_COUNTRY_CODE_PRIORITY_MAX), + + REG_VARIABLE(CFG_HEARTBEAT_THRESH_24_NAME, WLAN_PARAM_Integer, + struct hdd_config, HeartbeatThresh24, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_HEARTBEAT_THRESH_24_DEFAULT, + CFG_HEARTBEAT_THRESH_24_MIN, + CFG_HEARTBEAT_THRESH_24_MAX), + + REG_VARIABLE_STRING(CFG_POWER_USAGE_NAME, WLAN_PARAM_String, + struct hdd_config, PowerUsageControl, + VAR_FLAGS_OPTIONAL, + (void *)CFG_POWER_USAGE_DEFAULT), + + REG_VARIABLE(CFG_ENABLE_IMPS_NAME, WLAN_PARAM_Integer, + struct hdd_config, fIsImpsEnabled, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_IMPS_DEFAULT, + CFG_ENABLE_IMPS_MIN, + CFG_ENABLE_IMPS_MAX), + + REG_VARIABLE(CFG_ENABLE_PS_NAME, WLAN_PARAM_Integer, + struct hdd_config, is_ps_enabled, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_PS_DEFAULT, + CFG_ENABLE_PS_MIN, + CFG_ENABLE_PS_MAX), + + REG_VARIABLE(CFG_AUTO_PS_ENABLE_TIMER_NAME, WLAN_PARAM_Integer, + struct hdd_config, auto_bmps_timer_val, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_AUTO_PS_ENABLE_TIMER_DEFAULT, + CFG_AUTO_PS_ENABLE_TIMER_MIN, + CFG_AUTO_PS_ENABLE_TIMER_MAX), + + REG_VARIABLE(CFG_BMPS_MINIMUM_LI_NAME, WLAN_PARAM_Integer, + struct hdd_config, nBmpsMinListenInterval, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_BMPS_MINIMUM_LI_DEFAULT, + CFG_BMPS_MINIMUM_LI_MIN, + CFG_BMPS_MINIMUM_LI_MAX), + + REG_VARIABLE(CFG_BMPS_MAXIMUM_LI_NAME, WLAN_PARAM_Integer, + struct hdd_config, nBmpsMaxListenInterval, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_BMPS_MAXIMUM_LI_DEFAULT, + CFG_BMPS_MAXIMUM_LI_MIN, + CFG_BMPS_MAXIMUM_LI_MAX), + + REG_VARIABLE(CFG_BMPS_MODERATE_LI_NAME, WLAN_PARAM_Integer, + struct hdd_config, nBmpsModListenInterval, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_BMPS_MODERATE_LI_DEFAULT, + CFG_BMPS_MODERATE_LI_MIN, + CFG_BMPS_MODERATE_LI_MAX), + + REG_VARIABLE(CFG_DOT11_MODE_NAME, WLAN_PARAM_Integer, + struct hdd_config, dot11Mode, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK, + CFG_DOT11_MODE_DEFAULT, + CFG_DOT11_MODE_MIN, + CFG_DOT11_MODE_MAX), + + REG_VARIABLE(CFG_CHANNEL_BONDING_MODE_24GHZ_NAME, WLAN_PARAM_Integer, + struct hdd_config, nChannelBondingMode24GHz, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK, + CFG_CHANNEL_BONDING_MODE_DEFAULT, + CFG_CHANNEL_BONDING_MODE_MIN, + CFG_CHANNEL_BONDING_MODE_MAX), + + REG_VARIABLE(CFG_CHANNEL_BONDING_MODE_5GHZ_NAME, WLAN_PARAM_Integer, + struct hdd_config, nChannelBondingMode5GHz, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK, + CFG_CHANNEL_BONDING_MODE_DEFAULT, + CFG_CHANNEL_BONDING_MODE_MIN, + CFG_CHANNEL_BONDING_MODE_MAX), + + REG_VARIABLE(CFG_MAX_RX_AMPDU_FACTOR_NAME, WLAN_PARAM_Integer, + struct hdd_config, MaxRxAmpduFactor, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK, + CFG_MAX_RX_AMPDU_FACTOR_DEFAULT, + CFG_MAX_RX_AMPDU_FACTOR_MIN, + CFG_MAX_RX_AMPDU_FACTOR_MAX), + + REG_VARIABLE(CFG_HT_MPDU_DENSITY_NAME, WLAN_PARAM_Integer, + struct hdd_config, ht_mpdu_density, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK, + CFG_HT_MPDU_DENSITY_DEFAULT, + CFG_HT_MPDU_DENSITY_MIN, + CFG_HT_MPDU_DENSITY_MAX), + + REG_VARIABLE(CFG_FIXED_RATE_NAME, WLAN_PARAM_Integer, + struct hdd_config, TxRate, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK, + CFG_FIXED_RATE_DEFAULT, + CFG_FIXED_RATE_MIN, + CFG_FIXED_RATE_MAX), + + REG_VARIABLE(CFG_SHORT_GI_20MHZ_NAME, WLAN_PARAM_Integer, + struct hdd_config, ShortGI20MhzEnable, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_SHORT_GI_20MHZ_DEFAULT, + CFG_SHORT_GI_20MHZ_MIN, + CFG_SHORT_GI_20MHZ_MAX), + + REG_VARIABLE(CFG_SCAN_RESULT_AGE_COUNT_NAME, WLAN_PARAM_Integer, + struct hdd_config, ScanResultAgeCount, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK, + CFG_SCAN_RESULT_AGE_COUNT_DEFAULT, + CFG_SCAN_RESULT_AGE_COUNT_MIN, + CFG_SCAN_RESULT_AGE_COUNT_MAX), + + REG_VARIABLE(CFG_RSSI_CATEGORY_GAP_NAME, WLAN_PARAM_Integer, + struct hdd_config, nRssiCatGap, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_RSSI_CATEGORY_GAP_DEFAULT, + CFG_RSSI_CATEGORY_GAP_MIN, + CFG_RSSI_CATEGORY_GAP_MAX), + + REG_VARIABLE(CFG_SHORT_PREAMBLE_NAME, WLAN_PARAM_Integer, + struct hdd_config, fIsShortPreamble, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_SHORT_PREAMBLE_DEFAULT, + CFG_SHORT_PREAMBLE_MIN, + CFG_SHORT_PREAMBLE_MAX), + + REG_VARIABLE_STRING(CFG_IBSS_BSSID_NAME, WLAN_PARAM_MacAddr, + struct hdd_config, IbssBssid, + VAR_FLAGS_OPTIONAL, + (void *)CFG_IBSS_BSSID_DEFAULT), + + REG_VARIABLE_STRING(CFG_INTF0_MAC_ADDR_NAME, WLAN_PARAM_MacAddr, + struct hdd_config, intfMacAddr[0], + VAR_FLAGS_OPTIONAL, + (void *)CFG_INTF0_MAC_ADDR_DEFAULT), + + REG_VARIABLE_STRING(CFG_INTF1_MAC_ADDR_NAME, WLAN_PARAM_MacAddr, + struct hdd_config, intfMacAddr[1], + VAR_FLAGS_OPTIONAL, + (void *)CFG_INTF1_MAC_ADDR_DEFAULT), + + REG_VARIABLE_STRING(CFG_INTF2_MAC_ADDR_NAME, WLAN_PARAM_MacAddr, + struct hdd_config, intfMacAddr[2], + VAR_FLAGS_OPTIONAL, + (void *)CFG_INTF2_MAC_ADDR_DEFAULT), + + REG_VARIABLE_STRING(CFG_INTF3_MAC_ADDR_NAME, WLAN_PARAM_MacAddr, + struct hdd_config, intfMacAddr[3], + VAR_FLAGS_OPTIONAL, + (void *)CFG_INTF3_MAC_ADDR_DEFAULT), + + REG_VARIABLE(CFG_AP_QOS_UAPSD_MODE_NAME, WLAN_PARAM_Integer, + struct hdd_config, apUapsdEnabled, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_AP_QOS_UAPSD_MODE_DEFAULT, + CFG_AP_QOS_UAPSD_MODE_MIN, + CFG_AP_QOS_UAPSD_MODE_MAX), + + + REG_VARIABLE(CFG_AP_ENABLE_RANDOM_BSSID_NAME, WLAN_PARAM_Integer, + struct hdd_config, apRandomBssidEnabled, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_AP_ENABLE_RANDOM_BSSID_DEFAULT, + CFG_AP_ENABLE_RANDOM_BSSID_MIN, + CFG_AP_ENABLE_RANDOM_BSSID_MAX), + + REG_VARIABLE(CFG_AP_ENABLE_PROTECTION_MODE_NAME, WLAN_PARAM_Integer, + struct hdd_config, apProtEnabled, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_AP_ENABLE_PROTECTION_MODE_DEFAULT, + CFG_AP_ENABLE_PROTECTION_MODE_MIN, + CFG_AP_ENABLE_PROTECTION_MODE_MAX), + + REG_VARIABLE(CFG_AP_PROTECTION_MODE_NAME, WLAN_PARAM_HexInteger, + struct hdd_config, apProtection, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_AP_PROTECTION_MODE_DEFAULT, + CFG_AP_PROTECTION_MODE_MIN, + CFG_AP_PROTECTION_MODE_MAX), + + REG_VARIABLE(CFG_AP_OBSS_PROTECTION_MODE_NAME, WLAN_PARAM_Integer, + struct hdd_config, apOBSSProtEnabled, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_AP_OBSS_PROTECTION_MODE_DEFAULT, + CFG_AP_OBSS_PROTECTION_MODE_MIN, + CFG_AP_OBSS_PROTECTION_MODE_MAX), + + REG_VARIABLE(CFG_AP_STA_SECURITY_SEPERATION_NAME, WLAN_PARAM_Integer, + struct hdd_config, apDisableIntraBssFwd, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_AP_STA_SECURITY_SEPERATION_DEFAULT, + CFG_AP_STA_SECURITY_SEPERATION_MIN, + CFG_AP_STA_SECURITY_SEPERATION_MAX), + + REG_VARIABLE(CFG_ENABLE_LTE_COEX, WLAN_PARAM_Integer, + struct hdd_config, enableLTECoex, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_LTE_COEX_DEFAULT, + CFG_ENABLE_LTE_COEX_MIN, + CFG_ENABLE_LTE_COEX_MAX), +/* + * + * gApAutoChannelSelection - Force ACS from ini + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to set to enable force acs from driver. + * If enabled, channel/ hw config from hostapd is ignored. + * Driver uses INI params dot11Mode, channel bonding mode and vht chan width + * to derive ACS HW mode and operating BW. + * + * Non android platforms shall not use force ACS method and rely on hostapd + * driven ACS method for concurrent SAP ACS configuration, OBSS etc. + * + * Related: Only applicable if gCoalesingInIBSS is 0 + * + * Supported Feature: SAP + * + * Usage: Internal/External + * + * + */ + REG_VARIABLE(CFG_FORCE_SAP_ACS, WLAN_PARAM_Integer, + struct hdd_config, force_sap_acs, + VAR_FLAGS_DYNAMIC_CFG | + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_FORCE_SAP_ACS_DEFAULT, + CFG_FORCE_SAP_ACS_MIN, + CFG_FORCE_SAP_ACS_MAX), + +/* + * + * gAPChannelSelectStartChannel - start channel for ACS + * @Min: 0 + * @Max: 0xFF + * @Default: 1 + * + * This ini is used to set start channel for ACS. + * ACS scan will choose channel between force_sap_acs_st_ch + * and force_sap_acs_end_ch + * + * Related: Only applicable gAPChannelSelectEndChannel is set + * + * Supported Feature: SAP + * + * Usage: Internal/External + * + * + */ + REG_VARIABLE(CFG_FORCE_SAP_ACS_START_CH, WLAN_PARAM_Integer, + struct hdd_config, force_sap_acs_st_ch, + VAR_FLAGS_DYNAMIC_CFG | + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_FORCE_SAP_ACS_START_CH_DEFAULT, + CFG_FORCE_SAP_ACS_START_CH_MIN, + CFG_FORCE_SAP_ACS_START_CH_MAX), + +/* + * + * gAPChannelSelectEndChannel - end channel for ACS + * @Min: 0 + * @Max: 0xFF + * @Default: 11 + * + * This ini is used to set end channel for ACS. + * ACS scan will choose channel between force_sap_acs_st_ch + * and force_sap_acs_end_ch + * + * Related: Only applicable if gAPChannelSelectStartChannel is set + * + * Supported Feature: SAP + * + * Usage: Internal/External + * + * + */ + REG_VARIABLE(CFG_FORCE_SAP_ACS_END_CH, WLAN_PARAM_Integer, + struct hdd_config, force_sap_acs_end_ch, + VAR_FLAGS_DYNAMIC_CFG | + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_FORCE_SAP_ACS_END_CH_DEFAULT, + CFG_FORCE_SAP_ACS_END_CH_MIN, + CFG_FORCE_SAP_ACS_END_CH_MAX), + + REG_VARIABLE(CFG_ENABLE_SAP_MANDATORY_CHAN_LIST, WLAN_PARAM_Integer, + struct hdd_config, enable_sap_mandatory_chan_list, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_SAP_MANDATORY_CHAN_LIST_DEFAULT, + CFG_ENABLE_SAP_MANDATORY_CHAN_LIST_MIN, + CFG_ENABLE_SAP_MANDATORY_CHAN_LIST_MAX), + + REG_VARIABLE(CFG_AP_KEEP_ALIVE_PERIOD_NAME, WLAN_PARAM_Integer, + struct hdd_config, apKeepAlivePeriod, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_AP_KEEP_ALIVE_PERIOD_DEFAULT, + CFG_AP_KEEP_ALIVE_PERIOD_MIN, + CFG_AP_KEEP_ALIVE_PERIOD_MAX), + + REG_VARIABLE(CFG_GO_KEEP_ALIVE_PERIOD_NAME, WLAN_PARAM_Integer, + struct hdd_config, goKeepAlivePeriod, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_GO_KEEP_ALIVE_PERIOD_DEFAULT, + CFG_GO_KEEP_ALIVE_PERIOD_MIN, + CFG_GO_KEEP_ALIVE_PERIOD_MAX), + + REG_VARIABLE(CFG_AP_LINK_MONITOR_PERIOD_NAME, WLAN_PARAM_Integer, + struct hdd_config, apLinkMonitorPeriod, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_AP_LINK_MONITOR_PERIOD_DEFAULT, + CFG_AP_LINK_MONITOR_PERIOD_MIN, + CFG_AP_LINK_MONITOR_PERIOD_MAX), + + REG_VARIABLE(CFG_GO_LINK_MONITOR_PERIOD_NAME, WLAN_PARAM_Integer, + struct hdd_config, goLinkMonitorPeriod, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_GO_LINK_MONITOR_PERIOD_DEFAULT, + CFG_GO_LINK_MONITOR_PERIOD_MIN, + CFG_GO_LINK_MONITOR_PERIOD_MAX), + + REG_VARIABLE(CFG_DISABLE_PACKET_FILTER, WLAN_PARAM_Integer, + struct hdd_config, disablePacketFilter, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_DISABLE_PACKET_FILTER_DEFAULT, + CFG_DISABLE_PACKET_FILTER_MIN, + CFG_DISABLE_PACKET_FILTER_MAX), + + REG_VARIABLE(CFG_BEACON_INTERVAL_NAME, WLAN_PARAM_Integer, + struct hdd_config, nBeaconInterval, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK, + CFG_BEACON_INTERVAL_DEFAULT, + CFG_BEACON_INTERVAL_MIN, + CFG_BEACON_INTERVAL_MAX), + + REG_VARIABLE(CFG_VCC_RSSI_TRIGGER_NAME, WLAN_PARAM_Integer, + struct hdd_config, nVccRssiTrigger, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_VCC_RSSI_TRIGGER_DEFAULT, + CFG_VCC_RSSI_TRIGGER_MIN, + CFG_VCC_RSSI_TRIGGER_MAX), + + REG_VARIABLE(CFG_VCC_UL_MAC_LOSS_THRESH_NAME, WLAN_PARAM_Integer, + struct hdd_config, nVccUlMacLossThreshold, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_VCC_UL_MAC_LOSS_THRESH_DEFAULT, + CFG_VCC_UL_MAC_LOSS_THRESH_MIN, + CFG_VCC_UL_MAC_LOSS_THRESH_MAX), + + REG_VARIABLE(CFG_PASSIVE_MAX_CHANNEL_TIME_NAME, WLAN_PARAM_Integer, + struct hdd_config, nPassiveMaxChnTime, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_PASSIVE_MAX_CHANNEL_TIME_DEFAULT, + CFG_PASSIVE_MAX_CHANNEL_TIME_MIN, + CFG_PASSIVE_MAX_CHANNEL_TIME_MAX), + + REG_VARIABLE(CFG_PASSIVE_MIN_CHANNEL_TIME_NAME, WLAN_PARAM_Integer, + struct hdd_config, nPassiveMinChnTime, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_PASSIVE_MIN_CHANNEL_TIME_DEFAULT, + CFG_PASSIVE_MIN_CHANNEL_TIME_MIN, + CFG_PASSIVE_MIN_CHANNEL_TIME_MAX), + + REG_VARIABLE(CFG_ACTIVE_MAX_CHANNEL_TIME_NAME, WLAN_PARAM_Integer, + struct hdd_config, nActiveMaxChnTime, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ACTIVE_MAX_CHANNEL_TIME_DEFAULT, + CFG_ACTIVE_MAX_CHANNEL_TIME_MIN, + CFG_ACTIVE_MAX_CHANNEL_TIME_MAX), + + REG_VARIABLE(CFG_ACTIVE_MIN_CHANNEL_TIME_NAME, WLAN_PARAM_Integer, + struct hdd_config, nActiveMinChnTime, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ACTIVE_MIN_CHANNEL_TIME_DEFAULT, + CFG_ACTIVE_MIN_CHANNEL_TIME_MIN, + CFG_ACTIVE_MIN_CHANNEL_TIME_MAX), + + REG_VARIABLE(CFG_SCAN_NUM_PROBES_NAME, WLAN_PARAM_Integer, + struct hdd_config, scan_num_probes, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_SCAN_NUM_PROBES_DEFAULT, + CFG_SCAN_NUM_PROBES_MIN, + CFG_SCAN_NUM_PROBES_MAX), + + REG_VARIABLE(CFG_SCAN_PROBE_REPEAT_TIME_NAME, WLAN_PARAM_Integer, + struct hdd_config, scan_probe_repeat_time, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_SCAN_PROBE_REPEAT_TIME_DEFAULT, + CFG_SCAN_PROBE_REPEAT_TIME_MIN, + CFG_SCAN_PROBE_REPEAT_TIME_MAX), + + REG_VARIABLE(CFG_SCAN_ALLOW_ADJ_CH_BCN_NAME, WLAN_PARAM_Integer, + struct hdd_config, allow_adj_ch_bcn, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_SCAN_ALLOW_ADJ_CH_BCN_DEFAULT, + CFG_SCAN_ALLOW_ADJ_CH_BCN_MIN, + CFG_SCAN_ALLOW_ADJ_CH_BCN_MAX), + + REG_VARIABLE(CFG_RETRY_LIMIT_ZERO_NAME, WLAN_PARAM_Integer, + struct hdd_config, retryLimitZero, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_RETRY_LIMIT_ZERO_DEFAULT, + CFG_RETRY_LIMIT_ZERO_MIN, + CFG_RETRY_LIMIT_ZERO_MAX), + + REG_VARIABLE(CFG_RETRY_LIMIT_ONE_NAME, WLAN_PARAM_Integer, + struct hdd_config, retryLimitOne, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_RETRY_LIMIT_ONE_DEFAULT, + CFG_RETRY_LIMIT_ONE_MIN, + CFG_RETRY_LIMIT_ONE_MAX), + + REG_VARIABLE(CFG_RETRY_LIMIT_TWO_NAME, WLAN_PARAM_Integer, + struct hdd_config, retryLimitTwo, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_RETRY_LIMIT_TWO_DEFAULT, + CFG_RETRY_LIMIT_TWO_MIN, + CFG_RETRY_LIMIT_TWO_MAX), + +#ifdef WLAN_AP_STA_CONCURRENCY + REG_VARIABLE(CFG_PASSIVE_MAX_CHANNEL_TIME_CONC_NAME, WLAN_PARAM_Integer, + struct hdd_config, nPassiveMaxChnTimeConc, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_PASSIVE_MAX_CHANNEL_TIME_CONC_DEFAULT, + CFG_PASSIVE_MAX_CHANNEL_TIME_CONC_MIN, + CFG_PASSIVE_MAX_CHANNEL_TIME_CONC_MAX), + + REG_VARIABLE(CFG_PASSIVE_MIN_CHANNEL_TIME_CONC_NAME, WLAN_PARAM_Integer, + struct hdd_config, nPassiveMinChnTimeConc, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_PASSIVE_MIN_CHANNEL_TIME_CONC_DEFAULT, + CFG_PASSIVE_MIN_CHANNEL_TIME_CONC_MIN, + CFG_PASSIVE_MIN_CHANNEL_TIME_CONC_MAX), + + REG_VARIABLE(CFG_ACTIVE_MAX_CHANNEL_TIME_CONC_NAME, WLAN_PARAM_Integer, + struct hdd_config, nActiveMaxChnTimeConc, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ACTIVE_MAX_CHANNEL_TIME_CONC_DEFAULT, + CFG_ACTIVE_MAX_CHANNEL_TIME_CONC_MIN, + CFG_ACTIVE_MAX_CHANNEL_TIME_CONC_MAX), + + REG_VARIABLE(CFG_ACTIVE_MIN_CHANNEL_TIME_CONC_NAME, WLAN_PARAM_Integer, + struct hdd_config, nActiveMinChnTimeConc, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ACTIVE_MIN_CHANNEL_TIME_CONC_DEFAULT, + CFG_ACTIVE_MIN_CHANNEL_TIME_CONC_MIN, + CFG_ACTIVE_MIN_CHANNEL_TIME_CONC_MAX), + + REG_VARIABLE(CFG_REST_TIME_CONC_NAME, WLAN_PARAM_Integer, + struct hdd_config, nRestTimeConc, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_REST_TIME_CONC_DEFAULT, + CFG_REST_TIME_CONC_MIN, + CFG_REST_TIME_CONC_MAX), + + REG_VARIABLE(CFG_MIN_REST_TIME_NAME, WLAN_PARAM_Integer, + struct hdd_config, min_rest_time_conc, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_MIN_REST_TIME_DEFAULT, + CFG_MIN_REST_TIME_MIN, + CFG_MIN_REST_TIME_MAX), + + REG_VARIABLE(CFG_IDLE_TIME_NAME, WLAN_PARAM_Integer, + struct hdd_config, idle_time_conc, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_IDLE_TIME_DEFAULT, + CFG_IDLE_TIME_MIN, + CFG_IDLE_TIME_MAX), + + REG_VARIABLE(CFG_NUM_STA_CHAN_COMBINED_CONC_NAME, WLAN_PARAM_Integer, + struct hdd_config, nNumStaChanCombinedConc, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_NUM_STA_CHAN_COMBINED_CONC_DEFAULT, + CFG_NUM_STA_CHAN_COMBINED_CONC_MIN, + CFG_NUM_STA_CHAN_COMBINED_CONC_MAX), + + REG_VARIABLE(CFG_NUM_P2P_CHAN_COMBINED_CONC_NAME, WLAN_PARAM_Integer, + struct hdd_config, nNumP2PChanCombinedConc, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_NUM_P2P_CHAN_COMBINED_CONC_DEFAULT, + CFG_NUM_P2P_CHAN_COMBINED_CONC_MIN, + CFG_NUM_P2P_CHAN_COMBINED_CONC_MAX), +#endif + + REG_VARIABLE(CFG_MAX_PS_POLL_NAME, WLAN_PARAM_Integer, + struct hdd_config, nMaxPsPoll, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_MAX_PS_POLL_DEFAULT, + CFG_MAX_PS_POLL_MIN, + CFG_MAX_PS_POLL_MAX), + + REG_VARIABLE(CFG_MAX_TX_POWER_NAME, WLAN_PARAM_Integer, + struct hdd_config, nTxPowerCap, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_MAX_TX_POWER_DEFAULT, + CFG_MAX_TX_POWER_MIN, + CFG_MAX_TX_POWER_MAX), + + REG_VARIABLE(CFG_TX_POWER_CTRL_NAME, WLAN_PARAM_Integer, + struct hdd_config, allow_tpc_from_ap, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TX_POWER_CTRL_DEFAULT, + CFG_TX_POWER_CTRL_MIN, + CFG_TX_POWER_CTRL_MAX), + + REG_VARIABLE(CFG_LOW_GAIN_OVERRIDE_NAME, WLAN_PARAM_Integer, + struct hdd_config, fIsLowGainOverride, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_LOW_GAIN_OVERRIDE_DEFAULT, + CFG_LOW_GAIN_OVERRIDE_MIN, + CFG_LOW_GAIN_OVERRIDE_MAX), + + REG_VARIABLE(CFG_RSSI_FILTER_PERIOD_NAME, WLAN_PARAM_Integer, + struct hdd_config, nRssiFilterPeriod, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_RSSI_FILTER_PERIOD_DEFAULT, + CFG_RSSI_FILTER_PERIOD_MIN, + CFG_RSSI_FILTER_PERIOD_MAX), + + REG_VARIABLE(CFG_IGNORE_DTIM_NAME, WLAN_PARAM_Integer, + struct hdd_config, fIgnoreDtim, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_IGNORE_DTIM_DEFAULT, + CFG_IGNORE_DTIM_MIN, + CFG_IGNORE_DTIM_MAX), + + REG_VARIABLE(CFG_MAX_LI_MODULATED_DTIM_NAME, WLAN_PARAM_Integer, + struct hdd_config, fMaxLIModulatedDTIM, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_MAX_LI_MODULATED_DTIM_DEFAULT, + CFG_MAX_LI_MODULATED_DTIM_MIN, + CFG_MAX_LI_MODULATED_DTIM_MAX), + + REG_VARIABLE(CFG_FW_HEART_BEAT_MONITORING_NAME, WLAN_PARAM_Integer, + struct hdd_config, fEnableFwHeartBeatMonitoring, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_FW_HEART_BEAT_MONITORING_DEFAULT, + CFG_FW_HEART_BEAT_MONITORING_MIN, + CFG_FW_HEART_BEAT_MONITORING_MAX), + + REG_VARIABLE(CFG_FW_BEACON_FILTERING_NAME, WLAN_PARAM_Integer, + struct hdd_config, fEnableFwBeaconFiltering, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_FW_BEACON_FILTERING_DEFAULT, + CFG_FW_BEACON_FILTERING_MIN, + CFG_FW_BEACON_FILTERING_MAX), + + REG_DYNAMIC_VARIABLE(CFG_FW_RSSI_MONITORING_NAME, WLAN_PARAM_Integer, + struct hdd_config, fEnableFwRssiMonitoring, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_FW_RSSI_MONITORING_DEFAULT, + CFG_FW_RSSI_MONITORING_MIN, + CFG_FW_RSSI_MONITORING_MAX, + cb_notify_set_fw_rssi_monitoring, 0), + + REG_VARIABLE(CFG_FW_MCC_RTS_CTS_PROT_NAME, WLAN_PARAM_Integer, + struct hdd_config, mcc_rts_cts_prot_enable, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_FW_MCC_RTS_CTS_PROT_DEFAULT, + CFG_FW_MCC_RTS_CTS_PROT_MIN, + CFG_FW_MCC_RTS_CTS_PROT_MAX), + + REG_VARIABLE(CFG_FW_MCC_BCAST_PROB_RESP_NAME, WLAN_PARAM_Integer, + struct hdd_config, mcc_bcast_prob_resp_enable, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_FW_MCC_BCAST_PROB_RESP_DEFAULT, + CFG_FW_MCC_BCAST_PROB_RESP_MIN, + CFG_FW_MCC_BCAST_PROB_RESP_MAX), + + REG_VARIABLE(CFG_DATA_INACTIVITY_TIMEOUT_NAME, WLAN_PARAM_Integer, + struct hdd_config, nDataInactivityTimeout, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_DATA_INACTIVITY_TIMEOUT_DEFAULT, + CFG_DATA_INACTIVITY_TIMEOUT_MIN, + CFG_DATA_INACTIVITY_TIMEOUT_MAX), + + REG_VARIABLE(CFG_WOW_DATA_INACTIVITY_TIMEOUT_NAME, WLAN_PARAM_Integer, + struct hdd_config, wow_data_inactivity_timeout, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_WOW_DATA_INACTIVITY_TIMEOUT_DEFAULT, + CFG_WOW_DATA_INACTIVITY_TIMEOUT_MIN, + CFG_WOW_DATA_INACTIVITY_TIMEOUT_MAX), + + REG_VARIABLE(CFG_QOS_WMM_MODE_NAME, WLAN_PARAM_Integer, + struct hdd_config, WmmMode, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_QOS_WMM_MODE_DEFAULT, + CFG_QOS_WMM_MODE_MIN, + CFG_QOS_WMM_MODE_MAX), + + REG_VARIABLE(CFG_QOS_WMM_80211E_ENABLED_NAME, WLAN_PARAM_Integer, + struct hdd_config, b80211eIsEnabled, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_QOS_WMM_80211E_ENABLED_DEFAULT, + CFG_QOS_WMM_80211E_ENABLED_MIN, + CFG_QOS_WMM_80211E_ENABLED_MAX), + + REG_VARIABLE(CFG_QOS_WMM_UAPSD_MASK_NAME, WLAN_PARAM_HexInteger, + struct hdd_config, UapsdMask, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_QOS_WMM_UAPSD_MASK_DEFAULT, + CFG_QOS_WMM_UAPSD_MASK_MIN, + CFG_QOS_WMM_UAPSD_MASK_MAX), + + REG_VARIABLE(CFG_QOS_WMM_INFRA_UAPSD_VO_SRV_INTV_NAME, + WLAN_PARAM_Integer, + struct hdd_config, InfraUapsdVoSrvIntv, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_QOS_WMM_INFRA_UAPSD_VO_SRV_INTV_DEFAULT, + CFG_QOS_WMM_INFRA_UAPSD_VO_SRV_INTV_MIN, + CFG_QOS_WMM_INFRA_UAPSD_VO_SRV_INTV_MAX), + + REG_VARIABLE(CFG_QOS_WMM_INFRA_UAPSD_VO_SUS_INTV_NAME, + WLAN_PARAM_Integer, + struct hdd_config, InfraUapsdVoSuspIntv, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_QOS_WMM_INFRA_UAPSD_VO_SUS_INTV_DEFAULT, + CFG_QOS_WMM_INFRA_UAPSD_VO_SUS_INTV_MIN, + CFG_QOS_WMM_INFRA_UAPSD_VO_SUS_INTV_MAX), + + REG_VARIABLE(CFG_QOS_WMM_INFRA_UAPSD_VI_SRV_INTV_NAME, + WLAN_PARAM_Integer, + struct hdd_config, InfraUapsdViSrvIntv, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_QOS_WMM_INFRA_UAPSD_VI_SRV_INTV_DEFAULT, + CFG_QOS_WMM_INFRA_UAPSD_VI_SRV_INTV_MIN, + CFG_QOS_WMM_INFRA_UAPSD_VI_SRV_INTV_MAX), + + REG_VARIABLE(CFG_QOS_WMM_INFRA_UAPSD_VI_SUS_INTV_NAME, + WLAN_PARAM_Integer, + struct hdd_config, InfraUapsdViSuspIntv, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_QOS_WMM_INFRA_UAPSD_VI_SUS_INTV_DEFAULT, + CFG_QOS_WMM_INFRA_UAPSD_VI_SUS_INTV_MIN, + CFG_QOS_WMM_INFRA_UAPSD_VI_SUS_INTV_MAX), + + REG_VARIABLE(CFG_QOS_WMM_INFRA_UAPSD_BE_SRV_INTV_NAME, + WLAN_PARAM_Integer, + struct hdd_config, InfraUapsdBeSrvIntv, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_QOS_WMM_INFRA_UAPSD_BE_SRV_INTV_DEFAULT, + CFG_QOS_WMM_INFRA_UAPSD_BE_SRV_INTV_MIN, + CFG_QOS_WMM_INFRA_UAPSD_BE_SRV_INTV_MAX), + + REG_VARIABLE(CFG_QOS_WMM_INFRA_UAPSD_BE_SUS_INTV_NAME, + WLAN_PARAM_Integer, + struct hdd_config, InfraUapsdBeSuspIntv, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_QOS_WMM_INFRA_UAPSD_BE_SUS_INTV_DEFAULT, + CFG_QOS_WMM_INFRA_UAPSD_BE_SUS_INTV_MIN, + CFG_QOS_WMM_INFRA_UAPSD_BE_SUS_INTV_MAX), + + REG_VARIABLE(CFG_QOS_WMM_INFRA_UAPSD_BK_SRV_INTV_NAME, + WLAN_PARAM_Integer, + struct hdd_config, InfraUapsdBkSrvIntv, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_QOS_WMM_INFRA_UAPSD_BK_SRV_INTV_DEFAULT, + CFG_QOS_WMM_INFRA_UAPSD_BK_SRV_INTV_MIN, + CFG_QOS_WMM_INFRA_UAPSD_BK_SRV_INTV_MAX), + + REG_VARIABLE(CFG_QOS_WMM_INFRA_UAPSD_BK_SUS_INTV_NAME, + WLAN_PARAM_Integer, + struct hdd_config, InfraUapsdBkSuspIntv, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_QOS_WMM_INFRA_UAPSD_BK_SUS_INTV_DEFAULT, + CFG_QOS_WMM_INFRA_UAPSD_BK_SUS_INTV_MIN, + CFG_QOS_WMM_INFRA_UAPSD_BK_SUS_INTV_MAX), + +#ifdef FEATURE_WLAN_ESE + REG_VARIABLE(CFG_QOS_WMM_INFRA_INACTIVITY_INTERVAL_NAME, + WLAN_PARAM_Integer, + struct hdd_config, InfraInactivityInterval, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_QOS_WMM_INFRA_INACTIVITY_INTERVAL_DEFAULT, + CFG_QOS_WMM_INFRA_INACTIVITY_INTERVAL_MIN, + CFG_QOS_WMM_INFRA_INACTIVITY_INTERVAL_MAX), + + REG_DYNAMIC_VARIABLE(CFG_ESE_FEATURE_ENABLED_NAME, WLAN_PARAM_Integer, + struct hdd_config, isEseIniFeatureEnabled, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ESE_FEATURE_ENABLED_DEFAULT, + CFG_ESE_FEATURE_ENABLED_MIN, + CFG_ESE_FEATURE_ENABLED_MAX, + cb_notify_set_ese_feature_enabled, 0), +#endif /* FEATURE_WLAN_ESE */ + + /* flag to turn ON/OFF Legacy Fast Roaming */ + REG_DYNAMIC_VARIABLE(CFG_LFR_FEATURE_ENABLED_NAME, WLAN_PARAM_Integer, + struct hdd_config, isFastRoamIniFeatureEnabled, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_LFR_FEATURE_ENABLED_DEFAULT, + CFG_LFR_FEATURE_ENABLED_MIN, + CFG_LFR_FEATURE_ENABLED_MAX, + notify_is_fast_roam_ini_feature_enabled, 0), + + /* flag to turn ON/OFF Motion assistance for Legacy Fast Roaming */ + REG_DYNAMIC_VARIABLE(CFG_LFR_MAWC_FEATURE_ENABLED_NAME, + WLAN_PARAM_Integer, + struct hdd_config, MAWCEnabled, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_LFR_MAWC_FEATURE_ENABLED_DEFAULT, + CFG_LFR_MAWC_FEATURE_ENABLED_MIN, + CFG_LFR_MAWC_FEATURE_ENABLED_MAX, + notify_is_mawc_ini_feature_enabled, 0), + + /* flag to turn ON/OFF 11r and ESE FastTransition */ + REG_DYNAMIC_VARIABLE(CFG_FAST_TRANSITION_ENABLED_NAME, + WLAN_PARAM_Integer, + struct hdd_config, isFastTransitionEnabled, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_FAST_TRANSITION_ENABLED_NAME_DEFAULT, + CFG_FAST_TRANSITION_ENABLED_NAME_MIN, + CFG_FAST_TRANSITION_ENABLED_NAME_MAX, + cb_notify_set_fast_transition_enabled, 0), + + /* Variable to specify the delta/difference between the RSSI of current AP + * and roamable AP while roaming */ + REG_DYNAMIC_VARIABLE(CFG_ROAM_RSSI_DIFF_NAME, WLAN_PARAM_Integer, + struct hdd_config, RoamRssiDiff, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ROAM_RSSI_DIFF_DEFAULT, + CFG_ROAM_RSSI_DIFF_MIN, + CFG_ROAM_RSSI_DIFF_MAX, + cb_notify_set_roam_rssi_diff, 0), + + REG_DYNAMIC_VARIABLE(CFG_ENABLE_WES_MODE_NAME, WLAN_PARAM_Integer, + struct hdd_config, isWESModeEnabled, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_WES_MODE_NAME_DEFAULT, + CFG_ENABLE_WES_MODE_NAME_MIN, + CFG_ENABLE_WES_MODE_NAME_MAX, + cb_notify_set_wes_mode, 0), + REG_VARIABLE(CFG_PMKID_MODES_NAME, WLAN_PARAM_Integer, + struct hdd_config, pmkid_modes, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_PMKID_MODES_DEFAULT, + CFG_PMKID_MODES_MIN, + CFG_PMKID_MODES_MAX), + + REG_DYNAMIC_VARIABLE(CFG_ROAM_SCAN_OFFLOAD_ENABLED, WLAN_PARAM_Integer, + struct hdd_config, isRoamOffloadScanEnabled, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ROAM_SCAN_OFFLOAD_ENABLED_DEFAULT, + CFG_ROAM_SCAN_OFFLOAD_ENABLED_MIN, + CFG_ROAM_SCAN_OFFLOAD_ENABLED_MAX, + cb_notify_update_roam_scan_offload_enabled, 0), + + REG_VARIABLE(CFG_QOS_WMM_INFRA_DIR_AC_VO_NAME, WLAN_PARAM_Integer, + struct hdd_config, InfraDirAcVo, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_QOS_WMM_INFRA_DIR_AC_VO_DEFAULT, + CFG_QOS_WMM_INFRA_DIR_AC_VO_MIN, + CFG_QOS_WMM_INFRA_DIR_AC_VO_MAX), + + REG_VARIABLE(CFG_QOS_WMM_INFRA_NOM_MSDU_SIZE_AC_VO_NAME, + WLAN_PARAM_HexInteger, + struct hdd_config, InfraNomMsduSizeAcVo, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_QOS_WMM_INFRA_NOM_MSDU_SIZE_AC_VO_DEFAULT, + CFG_QOS_WMM_INFRA_NOM_MSDU_SIZE_AC_VO_MIN, + CFG_QOS_WMM_INFRA_NOM_MSDU_SIZE_AC_VO_MAX), + + REG_VARIABLE(CFG_QOS_WMM_INFRA_MEAN_DATA_RATE_AC_VO_NAME, + WLAN_PARAM_HexInteger, + struct hdd_config, InfraMeanDataRateAcVo, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_QOS_WMM_INFRA_MEAN_DATA_RATE_AC_VO_DEFAULT, + CFG_QOS_WMM_INFRA_MEAN_DATA_RATE_AC_VO_MIN, + CFG_QOS_WMM_INFRA_MEAN_DATA_RATE_AC_VO_MAX), + + REG_VARIABLE(CFG_QOS_WMM_INFRA_MIN_PHY_RATE_AC_VO_NAME, + WLAN_PARAM_HexInteger, + struct hdd_config, InfraMinPhyRateAcVo, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_QOS_WMM_INFRA_MIN_PHY_RATE_AC_VO_DEFAULT, + CFG_QOS_WMM_INFRA_MIN_PHY_RATE_AC_VO_MIN, + CFG_QOS_WMM_INFRA_MIN_PHY_RATE_AC_VO_MAX), + + REG_VARIABLE(CFG_QOS_WMM_INFRA_SBA_AC_VO_NAME, WLAN_PARAM_HexInteger, + struct hdd_config, InfraSbaAcVo, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_QOS_WMM_INFRA_SBA_AC_VO_DEFAULT, + CFG_QOS_WMM_INFRA_SBA_AC_VO_MIN, + CFG_QOS_WMM_INFRA_SBA_AC_VO_MAX), + + REG_VARIABLE(CFG_QOS_WMM_INFRA_DIR_AC_VI_NAME, WLAN_PARAM_Integer, + struct hdd_config, InfraDirAcVi, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_QOS_WMM_INFRA_DIR_AC_VI_DEFAULT, + CFG_QOS_WMM_INFRA_DIR_AC_VI_MIN, + CFG_QOS_WMM_INFRA_DIR_AC_VI_MAX), + + REG_VARIABLE(CFG_QOS_WMM_INFRA_NOM_MSDU_SIZE_AC_VI_NAME, + WLAN_PARAM_HexInteger, + struct hdd_config, InfraNomMsduSizeAcVi, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_QOS_WMM_INFRA_NOM_MSDU_SIZE_AC_VI_DEFAULT, + CFG_QOS_WMM_INFRA_NOM_MSDU_SIZE_AC_VI_MIN, + CFG_QOS_WMM_INFRA_NOM_MSDU_SIZE_AC_VI_MAX), + + REG_VARIABLE(CFG_QOS_WMM_INFRA_MEAN_DATA_RATE_AC_VI_NAME, + WLAN_PARAM_HexInteger, + struct hdd_config, InfraMeanDataRateAcVi, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_QOS_WMM_INFRA_MEAN_DATA_RATE_AC_VI_DEFAULT, + CFG_QOS_WMM_INFRA_MEAN_DATA_RATE_AC_VI_MIN, + CFG_QOS_WMM_INFRA_MEAN_DATA_RATE_AC_VI_MAX), + + REG_VARIABLE(CFG_QOS_WMM_INFRA_MIN_PHY_RATE_AC_VI_NAME, + WLAN_PARAM_HexInteger, + struct hdd_config, InfraMinPhyRateAcVi, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_QOS_WMM_INFRA_MIN_PHY_RATE_AC_VI_DEFAULT, + CFG_QOS_WMM_INFRA_MIN_PHY_RATE_AC_VI_MIN, + CFG_QOS_WMM_INFRA_MIN_PHY_RATE_AC_VI_MAX), + + REG_VARIABLE(CFG_QOS_WMM_INFRA_SBA_AC_VI_NAME, WLAN_PARAM_HexInteger, + struct hdd_config, InfraSbaAcVi, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_QOS_WMM_INFRA_SBA_AC_VI_DEFAULT, + CFG_QOS_WMM_INFRA_SBA_AC_VI_MIN, + CFG_QOS_WMM_INFRA_SBA_AC_VI_MAX), + + REG_VARIABLE(CFG_QOS_WMM_INFRA_DIR_AC_BE_NAME, WLAN_PARAM_Integer, + struct hdd_config, InfraDirAcBe, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_QOS_WMM_INFRA_DIR_AC_BE_DEFAULT, + CFG_QOS_WMM_INFRA_DIR_AC_BE_MIN, + CFG_QOS_WMM_INFRA_DIR_AC_BE_MAX), + + REG_VARIABLE(CFG_QOS_WMM_INFRA_NOM_MSDU_SIZE_AC_BE_NAME, + WLAN_PARAM_HexInteger, + struct hdd_config, InfraNomMsduSizeAcBe, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_QOS_WMM_INFRA_NOM_MSDU_SIZE_AC_BE_DEFAULT, + CFG_QOS_WMM_INFRA_NOM_MSDU_SIZE_AC_BE_MIN, + CFG_QOS_WMM_INFRA_NOM_MSDU_SIZE_AC_BE_MAX), + + REG_VARIABLE(CFG_QOS_WMM_INFRA_MEAN_DATA_RATE_AC_BE_NAME, + WLAN_PARAM_HexInteger, + struct hdd_config, InfraMeanDataRateAcBe, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_QOS_WMM_INFRA_MEAN_DATA_RATE_AC_BE_DEFAULT, + CFG_QOS_WMM_INFRA_MEAN_DATA_RATE_AC_BE_MIN, + CFG_QOS_WMM_INFRA_MEAN_DATA_RATE_AC_BE_MAX), + + REG_VARIABLE(CFG_QOS_WMM_INFRA_MIN_PHY_RATE_AC_BE_NAME, + WLAN_PARAM_HexInteger, + struct hdd_config, InfraMinPhyRateAcBe, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_QOS_WMM_INFRA_MIN_PHY_RATE_AC_BE_DEFAULT, + CFG_QOS_WMM_INFRA_MIN_PHY_RATE_AC_BE_MIN, + CFG_QOS_WMM_INFRA_MIN_PHY_RATE_AC_BE_MAX), + + REG_VARIABLE(CFG_QOS_WMM_INFRA_SBA_AC_BE_NAME, WLAN_PARAM_HexInteger, + struct hdd_config, InfraSbaAcBe, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_QOS_WMM_INFRA_SBA_AC_BE_DEFAULT, + CFG_QOS_WMM_INFRA_SBA_AC_BE_MIN, + CFG_QOS_WMM_INFRA_SBA_AC_BE_MAX), + + REG_VARIABLE(CFG_QOS_WMM_INFRA_DIR_AC_BK_NAME, WLAN_PARAM_Integer, + struct hdd_config, InfraDirAcBk, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_QOS_WMM_INFRA_DIR_AC_BK_DEFAULT, + CFG_QOS_WMM_INFRA_DIR_AC_BK_MIN, + CFG_QOS_WMM_INFRA_DIR_AC_BK_MAX), + + REG_VARIABLE(CFG_QOS_WMM_INFRA_NOM_MSDU_SIZE_AC_BK_NAME, + WLAN_PARAM_HexInteger, + struct hdd_config, InfraNomMsduSizeAcBk, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_QOS_WMM_INFRA_NOM_MSDU_SIZE_AC_BK_DEFAULT, + CFG_QOS_WMM_INFRA_NOM_MSDU_SIZE_AC_BK_MIN, + CFG_QOS_WMM_INFRA_NOM_MSDU_SIZE_AC_BK_MAX), + + REG_VARIABLE(CFG_QOS_WMM_INFRA_MEAN_DATA_RATE_AC_BK_NAME, + WLAN_PARAM_HexInteger, + struct hdd_config, InfraMeanDataRateAcBk, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_QOS_WMM_INFRA_MEAN_DATA_RATE_AC_BK_DEFAULT, + CFG_QOS_WMM_INFRA_MEAN_DATA_RATE_AC_BK_MIN, + CFG_QOS_WMM_INFRA_MEAN_DATA_RATE_AC_BK_MAX), + + REG_VARIABLE(CFG_QOS_WMM_INFRA_MIN_PHY_RATE_AC_BK_NAME, + WLAN_PARAM_HexInteger, + struct hdd_config, InfraMinPhyRateAcBk, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_QOS_WMM_INFRA_MIN_PHY_RATE_AC_BK_DEFAULT, + CFG_QOS_WMM_INFRA_MIN_PHY_RATE_AC_BK_MIN, + CFG_QOS_WMM_INFRA_MIN_PHY_RATE_AC_BK_MAX), + + REG_VARIABLE(CFG_QOS_WMM_INFRA_SBA_AC_BK_NAME, WLAN_PARAM_HexInteger, + struct hdd_config, InfraSbaAcBk, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_QOS_WMM_INFRA_SBA_AC_BK_DEFAULT, + CFG_QOS_WMM_INFRA_SBA_AC_BK_MIN, + CFG_QOS_WMM_INFRA_SBA_AC_BK_MAX), + + REG_VARIABLE(CFG_TL_DELAYED_TRGR_FRM_INT_NAME, WLAN_PARAM_Integer, + struct hdd_config, DelayedTriggerFrmInt, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TL_DELAYED_TRGR_FRM_INT_DEFAULT, + CFG_TL_DELAYED_TRGR_FRM_INT_MIN, + CFG_TL_DELAYED_TRGR_FRM_INT_MAX), + + REG_VARIABLE_STRING(CFG_WOWL_PATTERN_NAME, WLAN_PARAM_String, + struct hdd_config, wowlPattern, + VAR_FLAGS_OPTIONAL, + (void *)CFG_WOWL_PATTERN_DEFAULT), + + REG_VARIABLE(CFG_QOS_IMPLICIT_SETUP_ENABLED_NAME, WLAN_PARAM_Integer, + struct hdd_config, bImplicitQosEnabled, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_QOS_IMPLICIT_SETUP_ENABLED_DEFAULT, + CFG_QOS_IMPLICIT_SETUP_ENABLED_MIN, + CFG_QOS_IMPLICIT_SETUP_ENABLED_MAX), + + REG_VARIABLE(CFG_AP_AUTO_SHUT_OFF, WLAN_PARAM_Integer, + struct hdd_config, nAPAutoShutOff, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_AP_AUTO_SHUT_OFF_DEFAULT, + CFG_AP_AUTO_SHUT_OFF_MIN, + CFG_AP_AUTO_SHUT_OFF_MAX), + +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH + REG_VARIABLE(CFG_WLAN_MCC_TO_SCC_SWITCH_MODE, WLAN_PARAM_Integer, + struct hdd_config, WlanMccToSccSwitchMode, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_WLAN_MCC_TO_SCC_SWITCH_MODE_DEFAULT, + CFG_WLAN_MCC_TO_SCC_SWITCH_MODE_MIN, + CFG_WLAN_MCC_TO_SCC_SWITCH_MODE_MAX), +#endif +#ifdef FEATURE_WLAN_AUTO_SHUTDOWN + REG_VARIABLE(CFG_WLAN_AUTO_SHUTDOWN, WLAN_PARAM_Integer, + struct hdd_config, WlanAutoShutdown, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_WLAN_AUTO_SHUTDOWN_DEFAULT, + CFG_WLAN_AUTO_SHUTDOWN_MIN, + CFG_WLAN_AUTO_SHUTDOWN_MAX), +#endif + REG_VARIABLE(CFG_RRM_ENABLE_NAME, WLAN_PARAM_Integer, + struct hdd_config, fRrmEnable, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_RRM_ENABLE_DEFAULT, + CFG_RRM_ENABLE_MIN, + CFG_RRM_ENABLE_MAX), + + REG_VARIABLE(CFG_RRM_MEAS_RANDOMIZATION_INTVL_NAME, WLAN_PARAM_Integer, + struct hdd_config, nRrmRandnIntvl, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_RRM_MEAS_RANDOMIZATION_INTVL_DEFAULT, + CFG_RRM_MEAS_RANDOMIZATION_INTVL_MIN, + CFG_RRM_MEAS_RANDOMIZATION_INTVL_MAX), + + REG_VARIABLE_STRING(CFG_RM_CAPABILITY_NAME, WLAN_PARAM_String, + struct hdd_config, rm_capability, + VAR_FLAGS_OPTIONAL, + (void *) CFG_RM_CAPABILITY_DEFAULT), + + REG_VARIABLE(CFG_FT_RESOURCE_REQ_NAME, WLAN_PARAM_Integer, + struct hdd_config, fFTResourceReqSupported, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_FT_RESOURCE_REQ_DEFAULT, + CFG_FT_RESOURCE_REQ_MIN, + CFG_FT_RESOURCE_REQ_MAX), + + REG_DYNAMIC_VARIABLE(CFG_NEIGHBOR_SCAN_TIMER_PERIOD_NAME, + WLAN_PARAM_Integer, + struct hdd_config, nNeighborScanPeriod, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_NEIGHBOR_SCAN_TIMER_PERIOD_DEFAULT, + CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MIN, + CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MAX, + cb_notify_set_neighbor_scan_period, 0), + + REG_DYNAMIC_VARIABLE(CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_NAME, + WLAN_PARAM_Integer, + struct hdd_config, nNeighborLookupRssiThreshold, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_DEFAULT, + CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MIN, + CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MAX, + cb_notify_set_neighbor_lookup_rssi_threshold, 0), + + REG_DYNAMIC_VARIABLE(CFG_OPPORTUNISTIC_SCAN_THRESHOLD_DIFF_NAME, + WLAN_PARAM_Integer, + struct hdd_config, nOpportunisticThresholdDiff, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_OPPORTUNISTIC_SCAN_THRESHOLD_DIFF_DEFAULT, + CFG_OPPORTUNISTIC_SCAN_THRESHOLD_DIFF_MIN, + CFG_OPPORTUNISTIC_SCAN_THRESHOLD_DIFF_MAX, + cb_notify_set_opportunistic_scan_threshold_diff, 0), + + REG_DYNAMIC_VARIABLE(CFG_ROAM_RESCAN_RSSI_DIFF_NAME, WLAN_PARAM_Integer, + struct hdd_config, nRoamRescanRssiDiff, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ROAM_RESCAN_RSSI_DIFF_DEFAULT, + CFG_ROAM_RESCAN_RSSI_DIFF_MIN, + CFG_ROAM_RESCAN_RSSI_DIFF_MAX, + cb_notify_set_roam_rescan_rssi_diff, 0), + + REG_VARIABLE_STRING(CFG_NEIGHBOR_SCAN_CHAN_LIST_NAME, WLAN_PARAM_String, + struct hdd_config, neighborScanChanList, + VAR_FLAGS_OPTIONAL, + (void *)CFG_NEIGHBOR_SCAN_CHAN_LIST_DEFAULT), + + REG_DYNAMIC_VARIABLE(CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_NAME, + WLAN_PARAM_Integer, + struct hdd_config, nNeighborScanMinChanTime, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_DEFAULT, + CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MIN, + CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MAX, + cb_notify_set_neighbor_scan_min_chan_time, 0), + + REG_DYNAMIC_VARIABLE(CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_NAME, + WLAN_PARAM_Integer, + struct hdd_config, nNeighborScanMaxChanTime, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_DEFAULT, + CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MIN, + CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MAX, + cb_notify_set_neighbor_scan_max_chan_time, 0), + + REG_VARIABLE(CFG_11R_NEIGHBOR_REQ_MAX_TRIES_NAME, WLAN_PARAM_Integer, + struct hdd_config, nMaxNeighborReqTries, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_11R_NEIGHBOR_REQ_MAX_TRIES_DEFAULT, + CFG_11R_NEIGHBOR_REQ_MAX_TRIES_MIN, + CFG_11R_NEIGHBOR_REQ_MAX_TRIES_MAX), + + REG_DYNAMIC_VARIABLE(CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_NAME, + WLAN_PARAM_Integer, + struct hdd_config, nNeighborResultsRefreshPeriod, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_DEFAULT, + CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MIN, + CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MAX, + cb_notify_set_neighbor_results_refresh_period, 0), + + REG_DYNAMIC_VARIABLE(CFG_EMPTY_SCAN_REFRESH_PERIOD_NAME, + WLAN_PARAM_Integer, + struct hdd_config, nEmptyScanRefreshPeriod, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_EMPTY_SCAN_REFRESH_PERIOD_DEFAULT, + CFG_EMPTY_SCAN_REFRESH_PERIOD_MIN, + CFG_EMPTY_SCAN_REFRESH_PERIOD_MAX, + cb_notify_set_empty_scan_refresh_period, 0), + + REG_DYNAMIC_VARIABLE(CFG_ROAM_BMISS_FIRST_BCNT_NAME, WLAN_PARAM_Integer, + struct hdd_config, nRoamBmissFirstBcnt, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ROAM_BMISS_FIRST_BCNT_DEFAULT, + CFG_ROAM_BMISS_FIRST_BCNT_MIN, + CFG_ROAM_BMISS_FIRST_BCNT_MAX, + cb_notify_set_roam_bmiss_first_bcnt, 0), + + REG_DYNAMIC_VARIABLE(CFG_ROAM_BMISS_FINAL_BCNT_NAME, WLAN_PARAM_Integer, + struct hdd_config, nRoamBmissFinalBcnt, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ROAM_BMISS_FINAL_BCNT_DEFAULT, + CFG_ROAM_BMISS_FINAL_BCNT_MIN, + CFG_ROAM_BMISS_FINAL_BCNT_MAX, + cb_notify_set_roam_bmiss_final_bcnt, 0), + + REG_DYNAMIC_VARIABLE(CFG_ROAM_BEACON_RSSI_WEIGHT_NAME, + WLAN_PARAM_Integer, + struct hdd_config, nRoamBeaconRssiWeight, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ROAM_BEACON_RSSI_WEIGHT_DEFAULT, + CFG_ROAM_BEACON_RSSI_WEIGHT_MIN, + CFG_ROAM_BEACON_RSSI_WEIGHT_MAX, + cb_notify_set_roam_beacon_rssi_weight, 0), + + REG_DYNAMIC_VARIABLE(CFG_ROAMING_DFS_CHANNEL_NAME, WLAN_PARAM_Integer, + struct hdd_config, allowDFSChannelRoam, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ROAMING_DFS_CHANNEL_DEFAULT, + CFG_ROAMING_DFS_CHANNEL_MIN, + CFG_ROAMING_DFS_CHANNEL_MAX, + cb_notify_set_dfs_scan_mode, 0), + + REG_DYNAMIC_VARIABLE(CFG_DELAY_BEFORE_VDEV_STOP_NAME, + WLAN_PARAM_Integer, + struct hdd_config, + delay_before_vdev_stop, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_DELAY_BEFORE_VDEV_STOP_DEFAULT, + CFG_DELAY_BEFORE_VDEV_STOP_MIN, + CFG_DELAY_BEFORE_VDEV_STOP_MAX, + cb_notify_set_delay_before_vdev_stop, + 0), + + REG_DYNAMIC_VARIABLE(CFG_ROAM_SCAN_HI_RSSI_MAXCOUNT_NAME, + WLAN_PARAM_Integer, + struct hdd_config, + nhi_rssi_scan_max_count, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ROAM_SCAN_HI_RSSI_MAXCOUNT_DEFAULT, + CFG_ROAM_SCAN_HI_RSSI_MAXCOUNT_MIN, + CFG_ROAM_SCAN_HI_RSSI_MAXCOUNT_MAX, + cb_notify_set_roam_scan_hi_rssi_scan_params, + eCSR_HI_RSSI_SCAN_MAXCOUNT_ID), + + REG_DYNAMIC_VARIABLE(CFG_ROAM_SCAN_HI_RSSI_DELTA_NAME, + WLAN_PARAM_Integer, + struct hdd_config, + nhi_rssi_scan_rssi_delta, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ROAM_SCAN_HI_RSSI_DELTA_DEFAULT, + CFG_ROAM_SCAN_HI_RSSI_DELTA_MIN, + CFG_ROAM_SCAN_HI_RSSI_DELTA_MAX, + cb_notify_set_roam_scan_hi_rssi_scan_params, + eCSR_HI_RSSI_SCAN_RSSI_DELTA_ID), + + REG_DYNAMIC_VARIABLE(CFG_ROAM_SCAN_HI_RSSI_DELAY_NAME, + WLAN_PARAM_Integer, + struct hdd_config, + nhi_rssi_scan_delay, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ROAM_SCAN_HI_RSSI_DELAY_DEFAULT, + CFG_ROAM_SCAN_HI_RSSI_DELAY_MIN, + CFG_ROAM_SCAN_HI_RSSI_DELAY_MAX, + cb_notify_set_roam_scan_hi_rssi_scan_params, + eCSR_HI_RSSI_SCAN_DELAY_ID), + + REG_DYNAMIC_VARIABLE(CFG_ROAM_SCAN_HI_RSSI_UB_NAME, + WLAN_PARAM_SignedInteger, + struct hdd_config, + nhi_rssi_scan_rssi_ub, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ROAM_SCAN_HI_RSSI_UB_DEFAULT, + CFG_ROAM_SCAN_HI_RSSI_UB_MIN, + CFG_ROAM_SCAN_HI_RSSI_UB_MAX, + cb_notify_set_roam_scan_hi_rssi_scan_params, + eCSR_HI_RSSI_SCAN_RSSI_UB_ID), + + REG_VARIABLE(CFG_QOS_WMM_BURST_SIZE_DEFN_NAME, WLAN_PARAM_Integer, + struct hdd_config, burstSizeDefinition, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_QOS_WMM_BURST_SIZE_DEFN_DEFAULT, + CFG_QOS_WMM_BURST_SIZE_DEFN_MIN, + CFG_QOS_WMM_BURST_SIZE_DEFN_MAX), + + REG_VARIABLE(CFG_MCAST_BCAST_FILTER_SETTING_NAME, WLAN_PARAM_Integer, + struct hdd_config, mcastBcastFilterSetting, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_MCAST_BCAST_FILTER_SETTING_DEFAULT, + CFG_MCAST_BCAST_FILTER_SETTING_MIN, + CFG_MCAST_BCAST_FILTER_SETTING_MAX), + + REG_VARIABLE(CFG_ENABLE_HOST_ARPOFFLOAD_NAME, WLAN_PARAM_Integer, + struct hdd_config, fhostArpOffload, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_HOST_ARPOFFLOAD_DEFAULT, + CFG_ENABLE_HOST_ARPOFFLOAD_MIN, + CFG_ENABLE_HOST_ARPOFFLOAD_MAX), + +#ifdef FEATURE_WLAN_RA_FILTERING + REG_VARIABLE(CFG_RA_FILTER_ENABLE_NAME, WLAN_PARAM_Integer, + struct hdd_config, IsRArateLimitEnabled, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_RA_FILTER_ENABLE_DEFAULT, + CFG_RA_FILTER_ENABLE_MIN, + CFG_RA_FILTER_ENABLE_MAX), + + REG_VARIABLE(CFG_RA_RATE_LIMIT_INTERVAL_NAME, WLAN_PARAM_Integer, + struct hdd_config, RArateLimitInterval, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_RA_RATE_LIMIT_INTERVAL_DEFAULT, + CFG_RA_RATE_LIMIT_INTERVAL_MIN, + CFG_RA_RATE_LIMIT_INTERVAL_MAX), +#endif + + REG_VARIABLE(CFG_IGNORE_PEER_ERP_INFO_NAME, WLAN_PARAM_Integer, + struct hdd_config, ignore_peer_erp_info, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_IGNORE_PEER_ERP_INFO_DEFAULT, + CFG_IGNORE_PEER_ERP_INFO_MIN, + CFG_IGNORE_PEER_ERP_INFO_MAX), + + REG_VARIABLE(CFG_ENABLE_HOST_SSDP_NAME, WLAN_PARAM_Integer, + struct hdd_config, ssdp, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_HOST_SSDP_DEFAULT, + CFG_ENABLE_HOST_SSDP_MIN, + CFG_ENABLE_HOST_SSDP_MAX), + +#ifdef FEATURE_RUNTIME_PM + REG_VARIABLE(CFG_ENABLE_RUNTIME_PM, WLAN_PARAM_Integer, + struct hdd_config, runtime_pm, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_RUNTIME_PM_DEFAULT, + CFG_ENABLE_RUNTIME_PM_MIN, + CFG_ENABLE_RUNTIME_PM_MAX), + + REG_VARIABLE(CFG_RUNTIME_PM_DELAY_NAME, WLAN_PARAM_Integer, + struct hdd_config, runtime_pm_delay, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_RUNTIME_PM_DELAY_DEFAULT, + CFG_RUNTIME_PM_DELAY_MIN, + CFG_RUNTIME_PM_DELAY_MAX), +#endif + + + REG_VARIABLE(CFG_ENABLE_HOST_NSOFFLOAD_NAME, WLAN_PARAM_Integer, + struct hdd_config, fhostNSOffload, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_HOST_NSOFFLOAD_DEFAULT, + CFG_ENABLE_HOST_NSOFFLOAD_MIN, + CFG_ENABLE_HOST_NSOFFLOAD_MAX), + + REG_VARIABLE(CFG_QOS_WMM_TS_INFO_ACK_POLICY_NAME, WLAN_PARAM_HexInteger, + struct hdd_config, tsInfoAckPolicy, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_QOS_WMM_TS_INFO_ACK_POLICY_DEFAULT, + CFG_QOS_WMM_TS_INFO_ACK_POLICY_MIN, + CFG_QOS_WMM_TS_INFO_ACK_POLICY_MAX), + + REG_VARIABLE(CFG_SINGLE_TID_RC_NAME, WLAN_PARAM_Integer, + struct hdd_config, bSingleTidRc, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_SINGLE_TID_RC_DEFAULT, + CFG_SINGLE_TID_RC_MIN, + CFG_SINGLE_TID_RC_MAX), + + REG_VARIABLE(CFG_DYNAMIC_PSPOLL_VALUE_NAME, WLAN_PARAM_Integer, + struct hdd_config, dynamicPsPollValue, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_DYNAMIC_PSPOLL_VALUE_DEFAULT, + CFG_DYNAMIC_PSPOLL_VALUE_MIN, + CFG_DYNAMIC_PSPOLL_VALUE_MAX), + + REG_VARIABLE(CFG_TELE_BCN_WAKEUP_EN_NAME, WLAN_PARAM_Integer, + struct hdd_config, teleBcnWakeupEn, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TELE_BCN_WAKEUP_EN_DEFAULT, + CFG_TELE_BCN_WAKEUP_EN_MIN, + CFG_TELE_BCN_WAKEUP_EN_MAX), + + REG_VARIABLE(CFG_INFRA_STA_KEEP_ALIVE_PERIOD_NAME, WLAN_PARAM_Integer, + struct hdd_config, infraStaKeepAlivePeriod, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_INFRA_STA_KEEP_ALIVE_PERIOD_DEFAULT, + CFG_INFRA_STA_KEEP_ALIVE_PERIOD_MIN, + CFG_INFRA_STA_KEEP_ALIVE_PERIOD_MAX), + + REG_VARIABLE(CFG_QOS_ADDTS_WHEN_ACM_IS_OFF_NAME, WLAN_PARAM_Integer, + struct hdd_config, AddTSWhenACMIsOff, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_QOS_ADDTS_WHEN_ACM_IS_OFF_DEFAULT, + CFG_QOS_ADDTS_WHEN_ACM_IS_OFF_MIN, + CFG_QOS_ADDTS_WHEN_ACM_IS_OFF_MAX), + + REG_VARIABLE(CFG_VALIDATE_SCAN_LIST_NAME, WLAN_PARAM_Integer, + struct hdd_config, fValidateScanList, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_VALIDATE_SCAN_LIST_DEFAULT, + CFG_VALIDATE_SCAN_LIST_MIN, + CFG_VALIDATE_SCAN_LIST_MAX), + + REG_VARIABLE(CFG_NULLDATA_AP_RESP_TIMEOUT_NAME, WLAN_PARAM_Integer, + struct hdd_config, nNullDataApRespTimeout, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_NULLDATA_AP_RESP_TIMEOUT_DEFAULT, + CFG_NULLDATA_AP_RESP_TIMEOUT_MIN, + CFG_NULLDATA_AP_RESP_TIMEOUT_MAX), + + REG_VARIABLE(CFG_AP_DATA_AVAIL_POLL_PERIOD_NAME, WLAN_PARAM_Integer, + struct hdd_config, apDataAvailPollPeriodInMs, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_AP_DATA_AVAIL_POLL_PERIOD_DEFAULT, + CFG_AP_DATA_AVAIL_POLL_PERIOD_MIN, + CFG_AP_DATA_AVAIL_POLL_PERIOD_MAX), + + REG_VARIABLE(CFG_BAND_CAPABILITY_NAME, WLAN_PARAM_Integer, + struct hdd_config, nBandCapability, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_BAND_CAPABILITY_DEFAULT, + CFG_BAND_CAPABILITY_MIN, + CFG_BAND_CAPABILITY_MAX), + +/* CFG_QDF_TRACE_ENABLE Parameters */ + REG_VARIABLE(CFG_QDF_TRACE_ENABLE_WDI_NAME, WLAN_PARAM_Integer, + struct hdd_config, qdf_trace_enable_wdi, + VAR_FLAGS_OPTIONAL, + CFG_QDF_TRACE_ENABLE_DEFAULT, + CFG_QDF_TRACE_ENABLE_MIN, + CFG_QDF_TRACE_ENABLE_MAX), + + REG_VARIABLE(CFG_QDF_TRACE_ENABLE_HDD_NAME, WLAN_PARAM_Integer, + struct hdd_config, qdf_trace_enable_hdd, + VAR_FLAGS_OPTIONAL, + CFG_QDF_TRACE_ENABLE_DEFAULT, + CFG_QDF_TRACE_ENABLE_MIN, + CFG_QDF_TRACE_ENABLE_MAX), + + REG_VARIABLE(CFG_QDF_TRACE_ENABLE_BMI_NAME, WLAN_PARAM_Integer, + struct hdd_config, qdf_trace_enable_bmi, + VAR_FLAGS_OPTIONAL, + CFG_QDF_TRACE_ENABLE_DEFAULT, + CFG_QDF_TRACE_ENABLE_MIN, + CFG_QDF_TRACE_ENABLE_MAX), + + REG_VARIABLE(CFG_QDF_TRACE_ENABLE_SME_NAME, WLAN_PARAM_Integer, + struct hdd_config, qdf_trace_enable_sme, + VAR_FLAGS_OPTIONAL, + CFG_QDF_TRACE_ENABLE_DEFAULT, + CFG_QDF_TRACE_ENABLE_MIN, + CFG_QDF_TRACE_ENABLE_MAX), + + REG_VARIABLE(CFG_QDF_TRACE_ENABLE_PE_NAME, WLAN_PARAM_Integer, + struct hdd_config, qdf_trace_enable_pe, + VAR_FLAGS_OPTIONAL, + CFG_QDF_TRACE_ENABLE_DEFAULT, + CFG_QDF_TRACE_ENABLE_MIN, + CFG_QDF_TRACE_ENABLE_MAX), + + REG_VARIABLE(CFG_QDF_TRACE_ENABLE_WMA_NAME, WLAN_PARAM_Integer, + struct hdd_config, qdf_trace_enable_wma, + VAR_FLAGS_OPTIONAL, + CFG_QDF_TRACE_ENABLE_DEFAULT, + CFG_QDF_TRACE_ENABLE_MIN, + CFG_QDF_TRACE_ENABLE_MAX), + + REG_VARIABLE(CFG_QDF_TRACE_ENABLE_SYS_NAME, WLAN_PARAM_Integer, + struct hdd_config, qdf_trace_enable_sys, + VAR_FLAGS_OPTIONAL, + CFG_QDF_TRACE_ENABLE_DEFAULT, + CFG_QDF_TRACE_ENABLE_MIN, + CFG_QDF_TRACE_ENABLE_MAX), + + REG_VARIABLE(CFG_QDF_TRACE_ENABLE_QDF_NAME, WLAN_PARAM_Integer, + struct hdd_config, qdf_trace_enable_qdf, + VAR_FLAGS_OPTIONAL, + CFG_QDF_TRACE_ENABLE_DEFAULT, + CFG_QDF_TRACE_ENABLE_MIN, + CFG_QDF_TRACE_ENABLE_MAX), + + REG_VARIABLE(CFG_QDF_TRACE_ENABLE_SAP_NAME, WLAN_PARAM_Integer, + struct hdd_config, qdf_trace_enable_sap, + VAR_FLAGS_OPTIONAL, + CFG_QDF_TRACE_ENABLE_DEFAULT, + CFG_QDF_TRACE_ENABLE_MIN, + CFG_QDF_TRACE_ENABLE_MAX), + + REG_VARIABLE(CFG_QDF_TRACE_ENABLE_HDD_SAP_NAME, WLAN_PARAM_Integer, + struct hdd_config, qdf_trace_enable_hdd_sap, + VAR_FLAGS_OPTIONAL, + CFG_QDF_TRACE_ENABLE_DEFAULT, + CFG_QDF_TRACE_ENABLE_MIN, + CFG_QDF_TRACE_ENABLE_MAX), + + REG_VARIABLE(CFG_QDF_TRACE_ENABLE_CFG_NAME, WLAN_PARAM_Integer, + struct hdd_config, qdf_trace_enable_cfg, + VAR_FLAGS_OPTIONAL, + CFG_QDF_TRACE_ENABLE_DEFAULT, + CFG_QDF_TRACE_ENABLE_MIN, + CFG_QDF_TRACE_ENABLE_MAX), + + REG_VARIABLE(CFG_QDF_TRACE_ENABLE_TXRX_NAME, WLAN_PARAM_Integer, + struct hdd_config, cfd_trace_enable_txrx, + VAR_FLAGS_OPTIONAL, + CFG_QDF_TRACE_ENABLE_DEFAULT, + CFG_QDF_TRACE_ENABLE_MIN, + CFG_QDF_TRACE_ENABLE_MAX), + + REG_VARIABLE(CFG_QDF_TRACE_ENABLE_HTC_NAME, WLAN_PARAM_Integer, + struct hdd_config, qdf_trace_enable_htc, + VAR_FLAGS_OPTIONAL, + CFG_QDF_TRACE_ENABLE_DEFAULT, + CFG_QDF_TRACE_ENABLE_MIN, + CFG_QDF_TRACE_ENABLE_MAX), + + REG_VARIABLE(CFG_QDF_TRACE_ENABLE_HIF_NAME, WLAN_PARAM_Integer, + struct hdd_config, qdf_trace_enable_hif, + VAR_FLAGS_OPTIONAL, + CFG_QDF_TRACE_ENABLE_DEFAULT, + CFG_QDF_TRACE_ENABLE_MIN, + CFG_QDF_TRACE_ENABLE_MAX), + + REG_VARIABLE(CFG_CDR_TRACE_ENABLE_HDD_SAP_DATA_NAME, WLAN_PARAM_Integer, + struct hdd_config, qdf_trace_enable_hdd_sap_data, + VAR_FLAGS_OPTIONAL, + CFG_QDF_TRACE_ENABLE_DEFAULT, + CFG_QDF_TRACE_ENABLE_MIN, + CFG_QDF_TRACE_ENABLE_MAX), + + REG_VARIABLE(CFG_QDF_TRACE_ENABLE_HDD_DATA_NAME, WLAN_PARAM_Integer, + struct hdd_config, qdf_trace_enable_hdd_data, + VAR_FLAGS_OPTIONAL, + CFG_QDF_TRACE_ENABLE_DEFAULT, + CFG_QDF_TRACE_ENABLE_MIN, + CFG_QDF_TRACE_ENABLE_MAX), + + REG_VARIABLE(CFG_QDF_TRACE_ENABLE_EPPING, WLAN_PARAM_Integer, + struct hdd_config, qdf_trace_enable_epping, + VAR_FLAGS_OPTIONAL, + CFG_QDF_TRACE_ENABLE_DEFAULT, + CFG_QDF_TRACE_ENABLE_MIN, + CFG_QDF_TRACE_ENABLE_MAX), + + REG_VARIABLE(CFG_QDF_TRACE_ENABLE_QDF_DEVICES, WLAN_PARAM_Integer, + struct hdd_config, qdf_trace_enable_qdf_devices, + VAR_FLAGS_OPTIONAL, + CFG_QDF_TRACE_ENABLE_DEFAULT, + CFG_QDF_TRACE_ENABLE_MIN, + CFG_QDF_TRACE_ENABLE_MAX), + + REG_VARIABLE(CFG_TELE_BCN_TRANS_LI_NAME, WLAN_PARAM_Integer, + struct hdd_config, nTeleBcnTransListenInterval, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TELE_BCN_TRANS_LI_DEFAULT, + CFG_TELE_BCN_TRANS_LI_MIN, + CFG_TELE_BCN_TRANS_LI_MAX), + + REG_VARIABLE(CFG_TELE_BCN_TRANS_LI_NUM_IDLE_BCNS_NAME, + WLAN_PARAM_Integer, + struct hdd_config, nTeleBcnTransLiNumIdleBeacons, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TELE_BCN_TRANS_LI_NUM_IDLE_BCNS_DEFAULT, + CFG_TELE_BCN_TRANS_LI_NUM_IDLE_BCNS_MIN, + CFG_TELE_BCN_TRANS_LI_NUM_IDLE_BCNS_MAX), + + REG_VARIABLE(CFG_TELE_BCN_MAX_LI_NAME, WLAN_PARAM_Integer, + struct hdd_config, nTeleBcnMaxListenInterval, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TELE_BCN_MAX_LI_DEFAULT, + CFG_TELE_BCN_MAX_LI_MIN, + CFG_TELE_BCN_MAX_LI_MAX), + + REG_VARIABLE(CFG_TELE_BCN_MAX_LI_NUM_IDLE_BCNS_NAME, WLAN_PARAM_Integer, + struct hdd_config, nTeleBcnMaxLiNumIdleBeacons, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TELE_BCN_MAX_LI_NUM_IDLE_BCNS_DEFAULT, + CFG_TELE_BCN_MAX_LI_NUM_IDLE_BCNS_MIN, + CFG_TELE_BCN_MAX_LI_NUM_IDLE_BCNS_MAX), + + REG_VARIABLE(CFG_ENABLE_BYPASS_11D_NAME, WLAN_PARAM_Integer, + struct hdd_config, enableBypass11d, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_BYPASS_11D_DEFAULT, + CFG_ENABLE_BYPASS_11D_MIN, + CFG_ENABLE_BYPASS_11D_MAX), + + REG_VARIABLE(CFG_ENABLE_DFS_CHNL_SCAN_NAME, WLAN_PARAM_Integer, + struct hdd_config, enableDFSChnlScan, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_DFS_CHNL_SCAN_DEFAULT, + CFG_ENABLE_DFS_CHNL_SCAN_MIN, + CFG_ENABLE_DFS_CHNL_SCAN_MAX), + + REG_VARIABLE(CFG_ENABLE_DFS_PNO_CHNL_SCAN_NAME, WLAN_PARAM_Integer, + struct hdd_config, enable_dfs_pno_chnl_scan, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_DFS_PNO_CHNL_SCAN_DEFAULT, + CFG_ENABLE_DFS_PNO_CHNL_SCAN_MIN, + CFG_ENABLE_DFS_PNO_CHNL_SCAN_MAX), + + REG_VARIABLE(CFG_ENABLE_DYNAMIC_DTIM_NAME, WLAN_PARAM_Integer, + struct hdd_config, enableDynamicDTIM, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_DYNAMIC_DTIM_DEFAULT, + CFG_ENABLE_DYNAMIC_DTIM_MIN, + CFG_ENABLE_DYNAMIC_DTIM_MAX), + + REG_VARIABLE(CFG_SHORT_GI_40MHZ_NAME, WLAN_PARAM_Integer, + struct hdd_config, ShortGI40MhzEnable, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_SHORT_GI_40MHZ_DEFAULT, + CFG_SHORT_GI_40MHZ_MIN, + CFG_SHORT_GI_40MHZ_MAX), + + REG_DYNAMIC_VARIABLE(CFG_REPORT_MAX_LINK_SPEED, WLAN_PARAM_Integer, + struct hdd_config, reportMaxLinkSpeed, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_REPORT_MAX_LINK_SPEED_DEFAULT, + CFG_REPORT_MAX_LINK_SPEED_MIN, + CFG_REPORT_MAX_LINK_SPEED_MAX, + NULL, 0), + + REG_DYNAMIC_VARIABLE(CFG_LINK_SPEED_RSSI_HIGH, WLAN_PARAM_SignedInteger, + struct hdd_config, linkSpeedRssiHigh, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_LINK_SPEED_RSSI_HIGH_DEFAULT, + CFG_LINK_SPEED_RSSI_HIGH_MIN, + CFG_LINK_SPEED_RSSI_HIGH_MAX, + NULL, 0), + + REG_DYNAMIC_VARIABLE(CFG_LINK_SPEED_RSSI_MID, WLAN_PARAM_SignedInteger, + struct hdd_config, linkSpeedRssiMid, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_LINK_SPEED_RSSI_MID_DEFAULT, + CFG_LINK_SPEED_RSSI_MID_MIN, + CFG_LINK_SPEED_RSSI_MID_MAX, + NULL, 0), + + REG_DYNAMIC_VARIABLE(CFG_LINK_SPEED_RSSI_LOW, WLAN_PARAM_SignedInteger, + struct hdd_config, linkSpeedRssiLow, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_LINK_SPEED_RSSI_LOW_DEFAULT, + CFG_LINK_SPEED_RSSI_LOW_MIN, + CFG_LINK_SPEED_RSSI_LOW_MAX, + NULL, 0), + + REG_DYNAMIC_VARIABLE(CFG_ROAM_PREFER_5GHZ, WLAN_PARAM_Integer, + struct hdd_config, nRoamPrefer5GHz, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ROAM_PREFER_5GHZ_DEFAULT, + CFG_ROAM_PREFER_5GHZ_MIN, + CFG_ROAM_PREFER_5GHZ_MAX, + cb_notify_set_roam_prefer5_g_hz, 0), + + REG_DYNAMIC_VARIABLE(CFG_ROAM_INTRA_BAND, WLAN_PARAM_Integer, + struct hdd_config, nRoamIntraBand, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ROAM_INTRA_BAND_DEFAULT, + CFG_ROAM_INTRA_BAND_MIN, + CFG_ROAM_INTRA_BAND_MAX, + cb_notify_set_roam_intra_band, 0), + + REG_DYNAMIC_VARIABLE(CFG_ROAM_SCAN_N_PROBES, WLAN_PARAM_Integer, + struct hdd_config, nProbes, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ROAM_SCAN_N_PROBES_DEFAULT, + CFG_ROAM_SCAN_N_PROBES_MIN, + CFG_ROAM_SCAN_N_PROBES_MAX, + cb_notify_set_roam_scan_n_probes, 0), + + REG_DYNAMIC_VARIABLE(CFG_ROAM_SCAN_HOME_AWAY_TIME, WLAN_PARAM_Integer, + struct hdd_config, nRoamScanHomeAwayTime, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ROAM_SCAN_HOME_AWAY_TIME_DEFAULT, + CFG_ROAM_SCAN_HOME_AWAY_TIME_MIN, + CFG_ROAM_SCAN_HOME_AWAY_TIME_MAX, + cb_notify_set_roam_scan_home_away_time, 0), + + REG_VARIABLE(CFG_P2P_DEVICE_ADDRESS_ADMINISTRATED_NAME, + WLAN_PARAM_Integer, + struct hdd_config, isP2pDeviceAddrAdministrated, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_P2P_DEVICE_ADDRESS_ADMINISTRATED_DEFAULT, + CFG_P2P_DEVICE_ADDRESS_ADMINISTRATED_MIN, + CFG_P2P_DEVICE_ADDRESS_ADMINISTRATED_MAX), + + REG_VARIABLE(CFG_ENABLE_MCC_ENABLED_NAME, WLAN_PARAM_Integer, + struct hdd_config, enableMCC, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_MCC_ENABLED_DEFAULT, + CFG_ENABLE_MCC_ENABLED_MIN, + CFG_ENABLE_MCC_ENABLED_MAX), + + REG_VARIABLE(CFG_ALLOW_MCC_GO_DIFF_BI_NAME, WLAN_PARAM_Integer, + struct hdd_config, allowMCCGODiffBI, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ALLOW_MCC_GO_DIFF_BI_DEFAULT, + CFG_ALLOW_MCC_GO_DIFF_BI_MIN, + CFG_ALLOW_MCC_GO_DIFF_BI_MAX), + + REG_VARIABLE(CFG_THERMAL_MIGRATION_ENABLE_NAME, WLAN_PARAM_Integer, + struct hdd_config, thermalMitigationEnable, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_THERMAL_MIGRATION_ENABLE_DEFAULT, + CFG_THERMAL_MIGRATION_ENABLE_MIN, + CFG_THERMAL_MIGRATION_ENABLE_MAX), + + REG_VARIABLE(CFG_THROTTLE_PERIOD_NAME, WLAN_PARAM_Integer, + struct hdd_config, throttlePeriod, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_THROTTLE_PERIOD_DEFAULT, + CFG_THROTTLE_PERIOD_MIN, + CFG_THROTTLE_PERIOD_MAX), + + REG_VARIABLE(CFG_THROTTLE_DUTY_CYCLE_LEVEL0_NAME, WLAN_PARAM_Integer, + struct hdd_config, throttle_dutycycle_level0, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_THROTTLE_DUTY_CYCLE_LEVEL0_DEFAULT, + CFG_THROTTLE_DUTY_CYCLE_LEVEL0_MIN, + CFG_THROTTLE_DUTY_CYCLE_LEVEL0_MAX), + + REG_VARIABLE(CFG_THROTTLE_DUTY_CYCLE_LEVEL1_NAME, WLAN_PARAM_Integer, + struct hdd_config, throttle_dutycycle_level1, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_THROTTLE_DUTY_CYCLE_LEVEL1_DEFAULT, + CFG_THROTTLE_DUTY_CYCLE_LEVEL1_MIN, + CFG_THROTTLE_DUTY_CYCLE_LEVEL1_MAX), + + REG_VARIABLE(CFG_THROTTLE_DUTY_CYCLE_LEVEL2_NAME, WLAN_PARAM_Integer, + struct hdd_config, throttle_dutycycle_level2, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_THROTTLE_DUTY_CYCLE_LEVEL2_DEFAULT, + CFG_THROTTLE_DUTY_CYCLE_LEVEL2_MIN, + CFG_THROTTLE_DUTY_CYCLE_LEVEL2_MAX), + + REG_VARIABLE(CFG_THROTTLE_DUTY_CYCLE_LEVEL3_NAME, WLAN_PARAM_Integer, + struct hdd_config, throttle_dutycycle_level3, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_THROTTLE_DUTY_CYCLE_LEVEL3_DEFAULT, + CFG_THROTTLE_DUTY_CYCLE_LEVEL3_MIN, + CFG_THROTTLE_DUTY_CYCLE_LEVEL3_MAX), + + REG_VARIABLE(CFG_ENABLE_MODULATED_DTIM_NAME, WLAN_PARAM_Integer, + struct hdd_config, enableModulatedDTIM, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_MODULATED_DTIM_DEFAULT, + CFG_ENABLE_MODULATED_DTIM_MIN, + CFG_ENABLE_MODULATED_DTIM_MAX), + + REG_VARIABLE(CFG_MC_ADDR_LIST_ENABLE_NAME, WLAN_PARAM_Integer, + struct hdd_config, fEnableMCAddrList, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_MC_ADDR_LIST_ENABLE_DEFAULT, + CFG_MC_ADDR_LIST_ENABLE_MIN, + CFG_MC_ADDR_LIST_ENABLE_MAX), + + REG_VARIABLE(CFG_VHT_CHANNEL_WIDTH, WLAN_PARAM_Integer, + struct hdd_config, vhtChannelWidth, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK, + CFG_VHT_CHANNEL_WIDTH_DEFAULT, + CFG_VHT_CHANNEL_WIDTH_MIN, + CFG_VHT_CHANNEL_WIDTH_MAX), + + REG_VARIABLE(CFG_VHT_ENABLE_RX_MCS_8_9, WLAN_PARAM_Integer, + struct hdd_config, vhtRxMCS, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK, + CFG_VHT_ENABLE_RX_MCS_8_9_DEFAULT, + CFG_VHT_ENABLE_RX_MCS_8_9_MIN, + CFG_VHT_ENABLE_RX_MCS_8_9_MAX), + + REG_VARIABLE(CFG_VHT_ENABLE_TX_MCS_8_9, WLAN_PARAM_Integer, + struct hdd_config, vhtTxMCS, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK, + CFG_VHT_ENABLE_TX_MCS_8_9_DEFAULT, + CFG_VHT_ENABLE_TX_MCS_8_9_MIN, + CFG_VHT_ENABLE_TX_MCS_8_9_MAX), + + REG_VARIABLE(CFG_VHT_ENABLE_RX_MCS2x2_8_9, WLAN_PARAM_Integer, + struct hdd_config, vhtRxMCS2x2, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK, + CFG_VHT_ENABLE_RX_MCS2x2_8_9_DEFAULT, + CFG_VHT_ENABLE_RX_MCS2x2_8_9_MIN, + CFG_VHT_ENABLE_RX_MCS2x2_8_9_MAX), + + REG_VARIABLE(CFG_VHT_ENABLE_TX_MCS2x2_8_9, WLAN_PARAM_Integer, + struct hdd_config, vhtTxMCS2x2, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK, + CFG_VHT_ENABLE_TX_MCS2x2_8_9_DEFAULT, + CFG_VHT_ENABLE_TX_MCS2x2_8_9_MIN, + CFG_VHT_ENABLE_TX_MCS2x2_8_9_MAX), + + REG_VARIABLE(CFG_VHT_ENABLE_2x2_CAP_FEATURE, WLAN_PARAM_Integer, + struct hdd_config, enable2x2, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_VHT_ENABLE_2x2_CAP_FEATURE_DEFAULT, + CFG_VHT_ENABLE_2x2_CAP_FEATURE_MIN, + CFG_VHT_ENABLE_2x2_CAP_FEATURE_MAX), + + REG_VARIABLE(CFG_DISABLE_HIGH_HT_RX_MCS_2x2, WLAN_PARAM_Integer, + struct hdd_config, disable_high_ht_mcs_2x2, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_DISABLE_HIGH_HT_RX_MCS_2x2_DEFAULT, + CFG_DISABLE_HIGH_HT_RX_MCS_2x2_MIN, + CFG_DISABLE_HIGH_HT_RX_MCS_2x2_MAX), + + REG_VARIABLE(CFG_VDEV_TYPE_NSS_2G, WLAN_PARAM_Integer, + struct hdd_config, vdev_type_nss_2g, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_VDEV_TYPE_NSS_2G_DEFAULT, + CFG_VDEV_TYPE_NSS_2G_MIN, + CFG_VDEV_TYPE_NSS_2G_MAX), + + REG_VARIABLE(CFG_STA_PREFER_80MHZ_OVER_160MHZ, WLAN_PARAM_Integer, + struct hdd_config, sta_prefer_80MHz_over_160MHz, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_STA_PREFER_80MHZ_OVER_160MHZ_DEFAULT, + CFG_STA_PREFER_80MHZ_OVER_160MHZ_MIN, + CFG_STA_PREFER_80MHZ_OVER_160MHZ_MAX), + + REG_VARIABLE(CFG_VDEV_TYPE_NSS_5G, WLAN_PARAM_Integer, + struct hdd_config, vdev_type_nss_5g, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_VDEV_TYPE_NSS_5G_DEFAULT, + CFG_VDEV_TYPE_NSS_5G_MIN, + CFG_VDEV_TYPE_NSS_5G_MAX), + + REG_VARIABLE(CFG_VHT_ENABLE_MU_BFORMEE_CAP_FEATURE, WLAN_PARAM_Integer, + struct hdd_config, enableMuBformee, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_VHT_ENABLE_MU_BFORMEE_CAP_FEATURE_DEFAULT, + CFG_VHT_ENABLE_MU_BFORMEE_CAP_FEATURE_MIN, + CFG_VHT_ENABLE_MU_BFORMEE_CAP_FEATURE_MAX), + + REG_VARIABLE(CFG_VHT_ENABLE_PAID_FEATURE, WLAN_PARAM_Integer, + struct hdd_config, enableVhtpAid, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_VHT_ENABLE_PAID_FEATURE_DEFAULT, + CFG_VHT_ENABLE_PAID_FEATURE_MIN, + CFG_VHT_ENABLE_PAID_FEATURE_MAX), + + REG_VARIABLE(CFG_VHT_ENABLE_GID_FEATURE, WLAN_PARAM_Integer, + struct hdd_config, enableVhtGid, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_VHT_ENABLE_GID_FEATURE_DEFAULT, + CFG_VHT_ENABLE_GID_FEATURE_MIN, + CFG_VHT_ENABLE_GID_FEATURE_MAX), + + REG_VARIABLE(CFG_VHT_ENABLE_1x1_TX_CHAINMASK, WLAN_PARAM_Integer, + struct hdd_config, txchainmask1x1, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_VHT_ENABLE_1x1_TX_CHAINMASK_DEFAULT, + CFG_VHT_ENABLE_1x1_TX_CHAINMASK_MIN, + CFG_VHT_ENABLE_1x1_TX_CHAINMASK_MAX), + + REG_VARIABLE(CFG_VHT_ENABLE_1x1_RX_CHAINMASK, WLAN_PARAM_Integer, + struct hdd_config, rxchainmask1x1, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_VHT_ENABLE_1x1_RX_CHAINMASK_DEFAULT, + CFG_VHT_ENABLE_1x1_RX_CHAINMASK_MIN, + CFG_VHT_ENABLE_1x1_RX_CHAINMASK_MAX), + + REG_VARIABLE(CFG_ENABLE_AMPDUPS_FEATURE, WLAN_PARAM_Integer, + struct hdd_config, enableAmpduPs, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_AMPDUPS_FEATURE_DEFAULT, + CFG_ENABLE_AMPDUPS_FEATURE_MIN, + CFG_ENABLE_AMPDUPS_FEATURE_MAX), + + REG_VARIABLE(CFG_HT_ENABLE_SMPS_CAP_FEATURE, WLAN_PARAM_Integer, + struct hdd_config, enableHtSmps, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_HT_ENABLE_SMPS_CAP_FEATURE_DEFAULT, + CFG_HT_ENABLE_SMPS_CAP_FEATURE_MIN, + CFG_HT_ENABLE_SMPS_CAP_FEATURE_MAX), + + REG_VARIABLE(CFG_HT_SMPS_CAP_FEATURE, WLAN_PARAM_Integer, + struct hdd_config, htSmps, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_HT_SMPS_CAP_FEATURE_DEFAULT, + CFG_HT_SMPS_CAP_FEATURE_MIN, + CFG_HT_SMPS_CAP_FEATURE_MAX), + + REG_VARIABLE(CFG_DISABLE_DFS_CH_SWITCH, WLAN_PARAM_Integer, + struct hdd_config, disableDFSChSwitch, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_DISABLE_DFS_CH_SWITCH_DEFAULT, + CFG_DISABLE_DFS_CH_SWITCH_MIN, + CFG_DISABLE_DFS_CH_SWITCH_MAX), + + REG_VARIABLE(CFG_ENABLE_DFS_MASTER_CAPABILITY, WLAN_PARAM_Integer, + struct hdd_config, enableDFSMasterCap, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_DFS_MASTER_CAPABILITY_DEFAULT, + CFG_ENABLE_DFS_MASTER_CAPABILITY_MIN, + CFG_ENABLE_DFS_MASTER_CAPABILITY_MAX), + + REG_DYNAMIC_VARIABLE(CFG_SAP_PREFERRED_CHANNEL_LOCATION, + WLAN_PARAM_Integer, + struct hdd_config, gSapPreferredChanLocation, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_SAP_PREFERRED_CHANNEL_LOCATION_DEFAULT, + CFG_SAP_PREFERRED_CHANNEL_LOCATION_MIN, + CFG_SAP_PREFERRED_CHANNEL_LOCATION_MAX, + cb_notify_set_g_sap_preferred_chan_location, 0), + REG_DYNAMIC_VARIABLE(CFG_DISABLE_DFS_JAPAN_W53, WLAN_PARAM_Integer, + struct hdd_config, gDisableDfsJapanW53, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_DISABLE_DFS_JAPAN_W53_DEFAULT, + CFG_DISABLE_DFS_JAPAN_W53_MIN, + CFG_DISABLE_DFS_JAPAN_W53_MAX, + ch_notify_set_g_disable_dfs_japan_w53, 0), + + REG_VARIABLE(CFG_MAX_HT_MCS_FOR_TX_DATA, WLAN_PARAM_HexInteger, + struct hdd_config, max_ht_mcs_txdata, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_MAX_HT_MCS_FOR_TX_DATA_DEFAULT, + CFG_MAX_HT_MCS_FOR_TX_DATA_MIN, + CFG_MAX_HT_MCS_FOR_TX_DATA_MAX), + + REG_VARIABLE(CFG_DISABLE_ABG_RATE_FOR_TX_DATA, WLAN_PARAM_Integer, + struct hdd_config, disable_abg_rate_txdata, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_DISABLE_ABG_RATE_FOR_TX_DATA_DEFAULT, + CFG_DISABLE_ABG_RATE_FOR_TX_DATA_MIN, + CFG_DISABLE_ABG_RATE_FOR_TX_DATA_MAX), + + REG_VARIABLE(CFG_RATE_FOR_TX_MGMT, WLAN_PARAM_HexInteger, + struct hdd_config, rate_for_tx_mgmt, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_RATE_FOR_TX_MGMT_DEFAULT, + CFG_RATE_FOR_TX_MGMT_MIN, + CFG_RATE_FOR_TX_MGMT_MAX), + + REG_VARIABLE(CFG_ENABLE_FIRST_SCAN_2G_ONLY_NAME, WLAN_PARAM_Integer, + struct hdd_config, enableFirstScan2GOnly, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_FIRST_SCAN_2G_ONLY_DEFAULT, + CFG_ENABLE_FIRST_SCAN_2G_ONLY_MIN, + CFG_ENABLE_FIRST_SCAN_2G_ONLY_MAX), + + REG_VARIABLE(CFG_ENABLE_SKIP_DFS_IN_P2P_SEARCH_NAME, WLAN_PARAM_Integer, + struct hdd_config, skipDfsChnlInP2pSearch, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_SKIP_DFS_IN_P2P_SEARCH_DEFAULT, + CFG_ENABLE_SKIP_DFS_IN_P2P_SEARCH_MIN, + CFG_ENABLE_SKIP_DFS_IN_P2P_SEARCH_MAX), + + REG_VARIABLE(CFG_IGNORE_DYNAMIC_DTIM_IN_P2P_MODE_NAME, + WLAN_PARAM_Integer, + struct hdd_config, ignoreDynamicDtimInP2pMode, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_IGNORE_DYNAMIC_DTIM_IN_P2P_MODE_DEFAULT, + CFG_IGNORE_DYNAMIC_DTIM_IN_P2P_MODE_MIN, + CFG_IGNORE_DYNAMIC_DTIM_IN_P2P_MODE_MAX), + + REG_VARIABLE(CFG_ENABLE_RX_STBC, WLAN_PARAM_Integer, + struct hdd_config, enableRxSTBC, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_RX_STBC_DEFAULT, + CFG_ENABLE_RX_STBC_MIN, + CFG_ENABLE_RX_STBC_MAX), + + REG_VARIABLE(CFG_ENABLE_TX_STBC, WLAN_PARAM_Integer, + struct hdd_config, enableTxSTBC, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_TX_STBC_DEFAULT, + CFG_ENABLE_TX_STBC_MIN, + CFG_ENABLE_TX_STBC_MAX), + + REG_VARIABLE(CFG_ENABLE_RX_LDPC, WLAN_PARAM_Integer, + struct hdd_config, enableRxLDPC, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_RX_LDPC_DEFAULT, + CFG_ENABLE_RX_LDPC_MIN, + CFG_ENABLE_RX_LDPC_MAX), + + REG_VARIABLE(CFG_PPS_ENABLE_5G_EBT, WLAN_PARAM_Integer, + struct hdd_config, enable5gEBT, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_PPS_ENABLE_5G_EBT_FEATURE_DEFAULT, + CFG_PPS_ENABLE_5G_EBT_FEATURE_MIN, + CFG_PPS_ENABLE_5G_EBT_FEATURE_MAX), + +#ifdef FEATURE_WLAN_TDLS + REG_VARIABLE(CFG_TDLS_SUPPORT_ENABLE, WLAN_PARAM_Integer, + struct hdd_config, fEnableTDLSSupport, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TDLS_SUPPORT_ENABLE_DEFAULT, + CFG_TDLS_SUPPORT_ENABLE_MIN, + CFG_TDLS_SUPPORT_ENABLE_MAX), + + REG_VARIABLE(CFG_TDLS_IMPLICIT_TRIGGER, WLAN_PARAM_Integer, + struct hdd_config, fEnableTDLSImplicitTrigger, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TDLS_IMPLICIT_TRIGGER_DEFAULT, + CFG_TDLS_IMPLICIT_TRIGGER_MIN, + CFG_TDLS_IMPLICIT_TRIGGER_MAX), + + REG_VARIABLE(CFG_TDLS_TX_STATS_PERIOD, WLAN_PARAM_Integer, + struct hdd_config, fTDLSTxStatsPeriod, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TDLS_TX_STATS_PERIOD_DEFAULT, + CFG_TDLS_TX_STATS_PERIOD_MIN, + CFG_TDLS_TX_STATS_PERIOD_MAX), + + REG_VARIABLE(CFG_TDLS_TX_PACKET_THRESHOLD, WLAN_PARAM_Integer, + struct hdd_config, fTDLSTxPacketThreshold, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TDLS_TX_PACKET_THRESHOLD_DEFAULT, + CFG_TDLS_TX_PACKET_THRESHOLD_MIN, + CFG_TDLS_TX_PACKET_THRESHOLD_MAX), + + REG_VARIABLE(CFG_TDLS_MAX_DISCOVERY_ATTEMPT, WLAN_PARAM_Integer, + struct hdd_config, fTDLSMaxDiscoveryAttempt, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TDLS_MAX_DISCOVERY_ATTEMPT_DEFAULT, + CFG_TDLS_MAX_DISCOVERY_ATTEMPT_MIN, + CFG_TDLS_MAX_DISCOVERY_ATTEMPT_MAX), + + REG_VARIABLE(CFG_TDLS_IDLE_TIMEOUT, WLAN_PARAM_Integer, + struct hdd_config, tdls_idle_timeout, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TDLS_IDLE_TIMEOUT_DEFAULT, + CFG_TDLS_IDLE_TIMEOUT_MIN, + CFG_TDLS_IDLE_TIMEOUT_MAX), + + REG_VARIABLE(CFG_TDLS_IDLE_PACKET_THRESHOLD, WLAN_PARAM_Integer, + struct hdd_config, fTDLSIdlePacketThreshold, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TDLS_IDLE_PACKET_THRESHOLD_DEFAULT, + CFG_TDLS_IDLE_PACKET_THRESHOLD_MIN, + CFG_TDLS_IDLE_PACKET_THRESHOLD_MAX), + + REG_VARIABLE(CFG_TDLS_RSSI_TRIGGER_THRESHOLD, WLAN_PARAM_SignedInteger, + struct hdd_config, fTDLSRSSITriggerThreshold, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TDLS_RSSI_TRIGGER_THRESHOLD_DEFAULT, + CFG_TDLS_RSSI_TRIGGER_THRESHOLD_MIN, + CFG_TDLS_RSSI_TRIGGER_THRESHOLD_MAX), + + REG_VARIABLE(CFG_TDLS_RSSI_TEARDOWN_THRESHOLD, WLAN_PARAM_SignedInteger, + struct hdd_config, fTDLSRSSITeardownThreshold, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TDLS_RSSI_TEARDOWN_THRESHOLD_DEFAULT, + CFG_TDLS_RSSI_TEARDOWN_THRESHOLD_MIN, + CFG_TDLS_RSSI_TEARDOWN_THRESHOLD_MAX), + + REG_VARIABLE(CFG_TDLS_RSSI_DELTA, WLAN_PARAM_SignedInteger, + struct hdd_config, fTDLSRSSIDelta, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TDLS_RSSI_DELTA_DEFAULT, + CFG_TDLS_RSSI_DELTA_MIN, + CFG_TDLS_RSSI_DELTA_MAX), + + REG_VARIABLE(CFG_TDLS_QOS_WMM_UAPSD_MASK_NAME, WLAN_PARAM_HexInteger, + struct hdd_config, fTDLSUapsdMask, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TDLS_QOS_WMM_UAPSD_MASK_DEFAULT, + CFG_TDLS_QOS_WMM_UAPSD_MASK_MIN, + CFG_TDLS_QOS_WMM_UAPSD_MASK_MAX), + + REG_VARIABLE(CFG_TDLS_BUFFER_STA_SUPPORT_ENABLE, WLAN_PARAM_Integer, + struct hdd_config, fEnableTDLSBufferSta, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TDLS_BUFFER_STA_SUPPORT_ENABLE_DEFAULT, + CFG_TDLS_BUFFER_STA_SUPPORT_ENABLE_MIN, + CFG_TDLS_BUFFER_STA_SUPPORT_ENABLE_MAX), + + REG_VARIABLE(CFG_TDLS_OFF_CHANNEL_SUPPORT_ENABLE, WLAN_PARAM_Integer, + struct hdd_config, fEnableTDLSOffChannel, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TDLS_OFF_CHANNEL_SUPPORT_ENABLE_DEFAULT, + CFG_TDLS_OFF_CHANNEL_SUPPORT_ENABLE_MIN, + CFG_TDLS_OFF_CHANNEL_SUPPORT_ENABLE_MAX), + + REG_VARIABLE(CFG_TDLS_PREFERRED_OFF_CHANNEL_NUM, WLAN_PARAM_Integer, + struct hdd_config, fTDLSPrefOffChanNum, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TDLS_PREFERRED_OFF_CHANNEL_NUM_DEFAULT, + CFG_TDLS_PREFERRED_OFF_CHANNEL_NUM_MIN, + CFG_TDLS_PREFERRED_OFF_CHANNEL_NUM_MAX), + + REG_VARIABLE(CFG_TDLS_PREFERRED_OFF_CHANNEL_BW, WLAN_PARAM_Integer, + struct hdd_config, fTDLSPrefOffChanBandwidth, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TDLS_PREFERRED_OFF_CHANNEL_BW_DEFAULT, + CFG_TDLS_PREFERRED_OFF_CHANNEL_BW_MIN, + CFG_TDLS_PREFERRED_OFF_CHANNEL_BW_MAX), + + REG_VARIABLE(CFG_TDLS_PUAPSD_INACTIVITY_TIME, WLAN_PARAM_Integer, + struct hdd_config, fTDLSPuapsdInactivityTimer, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TDLS_PUAPSD_INACTIVITY_TIME_DEFAULT, + CFG_TDLS_PUAPSD_INACTIVITY_TIME_MIN, + CFG_TDLS_PUAPSD_INACTIVITY_TIME_MAX), + + REG_VARIABLE(CFG_TDLS_PUAPSD_RX_FRAME_THRESHOLD, WLAN_PARAM_Integer, + struct hdd_config, fTDLSRxFrameThreshold, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TDLS_PUAPSD_RX_FRAME_THRESHOLD_DEFAULT, + CFG_TDLS_PUAPSD_RX_FRAME_THRESHOLD_MIN, + CFG_TDLS_PUAPSD_RX_FRAME_THRESHOLD_MAX), + + REG_VARIABLE(CFG_TDLS_PUAPSD_PEER_TRAFFIC_IND_WINDOW, + WLAN_PARAM_Integer, + struct hdd_config, fTDLSPuapsdPTIWindow, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TDLS_PUAPSD_PEER_TRAFFIC_IND_WINDOW_DEFAULT, + CFG_TDLS_PUAPSD_PEER_TRAFFIC_IND_WINDOW_MIN, + CFG_TDLS_PUAPSD_PEER_TRAFFIC_IND_WINDOW_MAX), + + REG_VARIABLE(CFG_TDLS_PUAPSD_PEER_TRAFFIC_RSP_TIMEOUT, + WLAN_PARAM_Integer, + struct hdd_config, fTDLSPuapsdPTRTimeout, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TDLS_PUAPSD_PEER_TRAFFIC_RSP_TIMEOUT_DEFAULT, + CFG_TDLS_PUAPSD_PEER_TRAFFIC_RSP_TIMEOUT_MIN, + CFG_TDLS_PUAPSD_PEER_TRAFFIC_RSP_TIMEOUT_MAX), + + REG_VARIABLE(CFG_TDLS_EXTERNAL_CONTROL, WLAN_PARAM_Integer, + struct hdd_config, fTDLSExternalControl, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TDLS_EXTERNAL_CONTROL_DEFAULT, + CFG_TDLS_EXTERNAL_CONTROL_MIN, + CFG_TDLS_EXTERNAL_CONTROL_MAX), + REG_VARIABLE(CFG_TDLS_WMM_MODE_ENABLE, WLAN_PARAM_Integer, + struct hdd_config, fEnableTDLSWmmMode, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TDLS_WMM_MODE_ENABLE_DEFAULT, + CFG_TDLS_WMM_MODE_ENABLE_MIN, + CFG_TDLS_WMM_MODE_ENABLE_MAX), + + REG_VARIABLE(CFG_TDLS_SCAN_ENABLE, WLAN_PARAM_Integer, + struct hdd_config, enable_tdls_scan, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TDLS_SCAN_ENABLE_DEFAULT, + CFG_TDLS_SCAN_ENABLE_MIN, + CFG_TDLS_SCAN_ENABLE_MAX), + + REG_VARIABLE(CFG_TDLS_PEER_KICKOUT_THRESHOLD, WLAN_PARAM_Integer, + struct hdd_config, tdls_peer_kickout_threshold, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TDLS_PEER_KICKOUT_THRESHOLD_DEFAULT, + CFG_TDLS_PEER_KICKOUT_THRESHOLD_MIN, + CFG_TDLS_PEER_KICKOUT_THRESHOLD_MAX), + +#endif + +#ifdef WLAN_SOFTAP_VSTA_FEATURE + REG_VARIABLE(CFG_VSTA_SUPPORT_ENABLE, WLAN_PARAM_Integer, + struct hdd_config, fEnableVSTASupport, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_VSTA_SUPPORT_ENABLE_DEFAULT, + CFG_VSTA_SUPPORT_ENABLE_MIN, + CFG_VSTA_SUPPORT_ENABLE_MAX), +#endif + REG_VARIABLE(CFG_ENABLE_LPWR_IMG_TRANSITION_NAME, WLAN_PARAM_Integer, + struct hdd_config, enableLpwrImgTransition, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_LPWR_IMG_TRANSITION_DEFAULT, + CFG_ENABLE_LPWR_IMG_TRANSITION_MIN, + CFG_ENABLE_LPWR_IMG_TRANSITION_MAX), + + REG_VARIABLE(CFG_ENABLE_LPWR_IMG_TRANSITION_NAME, WLAN_PARAM_Integer, + struct hdd_config, enableLpwrImgTransition, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_LPWR_IMG_TRANSITION_DEFAULT, + CFG_ENABLE_LPWR_IMG_TRANSITION_MIN, + CFG_ENABLE_LPWR_IMG_TRANSITION_MAX), + + REG_VARIABLE(CFG_SCAN_AGING_PARAM_NAME, WLAN_PARAM_Integer, + struct hdd_config, scanAgingTimeout, + VAR_FLAGS_OPTIONAL, + CFG_SCAN_AGING_PARAM_DEFAULT, + CFG_SCAN_AGING_PARAM_MIN, + CFG_SCAN_AGING_PARAM_MAX), + + REG_VARIABLE(CFG_TX_LDPC_ENABLE_FEATURE, WLAN_PARAM_Integer, + struct hdd_config, enableTxLdpc, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TX_LDPC_ENABLE_FEATURE_DEFAULT, + CFG_TX_LDPC_ENABLE_FEATURE_MIN, + CFG_TX_LDPC_ENABLE_FEATURE_MAX), + + REG_VARIABLE(CFG_ENABLE_MCC_ADATIVE_SCHEDULER_ENABLED_NAME, + WLAN_PARAM_Integer, + struct hdd_config, enableMCCAdaptiveScheduler, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_MCC_ADATIVE_SCHEDULER_ENABLED_DEFAULT, + CFG_ENABLE_MCC_ADATIVE_SCHEDULER_ENABLED_MIN, + CFG_ENABLE_MCC_ADATIVE_SCHEDULER_ENABLED_MAX), + + REG_VARIABLE(CFG_IBSS_ADHOC_CHANNEL_5GHZ_NAME, WLAN_PARAM_Integer, + struct hdd_config, AdHocChannel5G, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_IBSS_ADHOC_CHANNEL_5GHZ_DEFAULT, + CFG_IBSS_ADHOC_CHANNEL_5GHZ_MIN, + CFG_IBSS_ADHOC_CHANNEL_5GHZ_MAX), + + REG_VARIABLE(CFG_IBSS_ADHOC_CHANNEL_24GHZ_NAME, WLAN_PARAM_Integer, + struct hdd_config, AdHocChannel24G, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_IBSS_ADHOC_CHANNEL_24GHZ_DEFAULT, + CFG_IBSS_ADHOC_CHANNEL_24GHZ_MIN, + CFG_IBSS_ADHOC_CHANNEL_24GHZ_MAX), + + REG_VARIABLE(CFG_VHT_SU_BEAMFORMEE_CAP_FEATURE, WLAN_PARAM_Integer, + struct hdd_config, enableTxBF, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_VHT_SU_BEAMFORMEE_CAP_FEATURE_DEFAULT, + CFG_VHT_SU_BEAMFORMEE_CAP_FEATURE_MIN, + CFG_VHT_SU_BEAMFORMEE_CAP_FEATURE_MAX), + + REG_VARIABLE(CFG_VHT_ENABLE_TXBF_SAP_MODE, WLAN_PARAM_Integer, + struct hdd_config, enable_txbf_sap_mode, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_VHT_ENABLE_TXBF_SAP_MODE_DEFAULT, + CFG_VHT_ENABLE_TXBF_SAP_MODE_MIN, + CFG_VHT_ENABLE_TXBF_SAP_MODE_MAX), + + REG_VARIABLE(CFG_VHT_ENABLE_TXBF_IN_20MHZ, WLAN_PARAM_Integer, + struct hdd_config, enableTxBFin20MHz, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_VHT_ENABLE_TXBF_IN_20MHZ_DEFAULT, + CFG_VHT_ENABLE_TXBF_IN_20MHZ_MIN, + CFG_VHT_ENABLE_TXBF_IN_20MHZ_MAX), + + REG_VARIABLE(CFG_VHT_CSN_BEAMFORMEE_ANT_SUPPORTED, WLAN_PARAM_Integer, + struct hdd_config, txBFCsnValue, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_VHT_CSN_BEAMFORMEE_ANT_SUPPORTED_DEFAULT, + CFG_VHT_CSN_BEAMFORMEE_ANT_SUPPORTED_MIN, + CFG_VHT_CSN_BEAMFORMEE_ANT_SUPPORTED_MAX), + + REG_VARIABLE(CFG_VHT_ENABLE_TX_SU_BEAM_FORMER, WLAN_PARAM_Integer, + struct hdd_config, enable_su_tx_bformer, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_VHT_ENABLE_TX_SU_BEAM_FORMER_DEFAULT, + CFG_VHT_ENABLE_TX_SU_BEAM_FORMER_MIN, + CFG_VHT_ENABLE_TX_SU_BEAM_FORMER_MAX), + + REG_VARIABLE(CFG_SAP_ALLOW_ALL_CHANNEL_PARAM_NAME, WLAN_PARAM_Integer, + struct hdd_config, sapAllowAllChannel, + VAR_FLAGS_OPTIONAL, + CFG_SAP_ALLOW_ALL_CHANNEL_PARAM_DEFAULT, + CFG_SAP_ALLOW_ALL_CHANNEL_PARAM_MIN, + CFG_SAP_ALLOW_ALL_CHANNEL_PARAM_MAX), + + REG_VARIABLE(CFG_DISABLE_LDPC_WITH_TXBF_AP, WLAN_PARAM_Integer, + struct hdd_config, disableLDPCWithTxbfAP, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_DISABLE_LDPC_WITH_TXBF_AP_DEFAULT, + CFG_DISABLE_LDPC_WITH_TXBF_AP_MIN, + CFG_DISABLE_LDPC_WITH_TXBF_AP_MAX), + + REG_DYNAMIC_VARIABLE(CFG_ENABLE_SSR, WLAN_PARAM_Integer, + struct hdd_config, enableSSR, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_SSR_DEFAULT, + CFG_ENABLE_SSR_MIN, + CFG_ENABLE_SSR_MAX, + cb_notify_set_enable_ssr, 0), + + REG_VARIABLE(CFG_MAX_MEDIUM_TIME, WLAN_PARAM_Integer, + struct hdd_config, cfgMaxMediumTime, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_MAX_MEDIUM_TIME_STADEFAULT, + CFG_MAX_MEDIUM_TIME_STAMIN, + CFG_MAX_MEDIUM_TIME_STAMAX), + + REG_VARIABLE(CFG_ENABLE_VHT_FOR_24GHZ_NAME, WLAN_PARAM_Integer, + struct hdd_config, enableVhtFor24GHzBand, + VAR_FLAGS_OPTIONAL, + CFG_ENABLE_VHT_FOR_24GHZ_DEFAULT, + CFG_ENABLE_VHT_FOR_24GHZ_MIN, + CFG_ENABLE_VHT_FOR_24GHZ_MAX), + + + REG_VARIABLE(CFG_ENABLE_VENDOR_VHT_FOR_24GHZ_NAME, WLAN_PARAM_Integer, + struct hdd_config, enable_sap_vendor_vht, + VAR_FLAGS_OPTIONAL, + CFG_ENABLE_VENDOR_VHT_FOR_24GHZ_DEFAULT, + CFG_ENABLE_VENDOR_VHT_FOR_24GHZ_MIN, + CFG_ENABLE_VENDOR_VHT_FOR_24GHZ_MAX), + + REG_DYNAMIC_VARIABLE(CFG_ENABLE_FAST_ROAM_IN_CONCURRENCY, + WLAN_PARAM_Integer, + struct hdd_config, bFastRoamInConIniFeatureEnabled, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_FAST_ROAM_IN_CONCURRENCY_DEFAULT, + CFG_ENABLE_FAST_ROAM_IN_CONCURRENCY_MIN, + CFG_ENABLE_FAST_ROAM_IN_CONCURRENCY_MAX, + cb_notify_set_enable_fast_roam_in_concurrency, 0), + + REG_VARIABLE(CFG_ENABLE_ADAPT_RX_DRAIN_NAME, WLAN_PARAM_Integer, + struct hdd_config, fEnableAdaptRxDrain, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK, + CFG_ENABLE_ADAPT_RX_DRAIN_DEFAULT, + CFG_ENABLE_ADAPT_RX_DRAIN_MIN, + CFG_ENABLE_ADAPT_RX_DRAIN_MAX), + + REG_VARIABLE(CFG_ENABLE_HEART_BEAT_OFFLOAD, WLAN_PARAM_Integer, + struct hdd_config, enableIbssHeartBeatOffload, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_HEART_BEAT_OFFLOAD_DEFAULT, + CFG_ENABLE_HEART_BEAT_OFFLOAD_MIN, + CFG_ENABLE_HEART_BEAT_OFFLOAD_MAX), + + REG_VARIABLE(CFG_ANTENNA_DIVERSITY_PARAM_NAME, WLAN_PARAM_Integer, + struct hdd_config, antennaDiversity, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ANTENNA_DIVERSITY_PARAM_DEFAULT, + CFG_ANTENNA_DIVERSITY_PARAM_MIN, + CFG_ANTENNA_DIVERSITY_PARAM_MAX), + + REG_VARIABLE(CFG_ENABLE_SNR_MONITORING_NAME, WLAN_PARAM_Integer, + struct hdd_config, fEnableSNRMonitoring, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK, + CFG_ENABLE_SNR_MONITORING_DEFAULT, + CFG_ENABLE_SNR_MONITORING_MIN, + CFG_ENABLE_SNR_MONITORING_MAX), + +#ifdef FEATURE_WLAN_SCAN_PNO + REG_VARIABLE(CFG_PNO_SCAN_SUPPORT, WLAN_PARAM_Integer, + struct hdd_config, configPNOScanSupport, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_PNO_SCAN_SUPPORT_DEFAULT, + CFG_PNO_SCAN_SUPPORT_DISABLE, + CFG_PNO_SCAN_SUPPORT_ENABLE), + + REG_VARIABLE(CFG_PNO_SCAN_TIMER_REPEAT_VALUE, WLAN_PARAM_Integer, + struct hdd_config, configPNOScanTimerRepeatValue, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_PNO_SCAN_TIMER_REPEAT_VALUE_DEFAULT, + CFG_PNO_SCAN_TIMER_REPEAT_VALUE_MIN, + CFG_PNO_SCAN_TIMER_REPEAT_VALUE_MAX), + + REG_VARIABLE(CFG_PNO_SLOW_SCAN_MULTIPLIER, WLAN_PARAM_Integer, + struct hdd_config, pno_slow_scan_multiplier, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_PNO_SLOW_SCAN_MULTIPLIER_DEFAULT, + CFG_PNO_SLOW_SCAN_MULTIPLIER_MIN, + CFG_PNO_SLOW_SCAN_MULTIPLIER_MAX), +#endif + REG_VARIABLE(CFG_MAX_AMSDU_NUM_NAME , WLAN_PARAM_Integer, + struct hdd_config, max_amsdu_num, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_MAX_AMSDU_NUM_DEFAULT, + CFG_MAX_AMSDU_NUM_MIN, + CFG_MAX_AMSDU_NUM_MAX), + + REG_VARIABLE(CFG_STRICT_5GHZ_PREF_BY_MARGIN, WLAN_PARAM_Integer, + struct hdd_config, nSelect5GHzMargin, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_STRICT_5GHZ_PREF_BY_MARGIN_DEFAULT, + CFG_STRICT_5GHZ_PREF_BY_MARGIN_MIN, + CFG_STRICT_5GHZ_PREF_BY_MARGIN_MAX), + + REG_VARIABLE(CFG_ENABLE_IP_TCP_UDP_CHKSUM_OFFLOAD, WLAN_PARAM_Integer, + struct hdd_config, enable_ip_tcp_udp_checksum_offload, + VAR_FLAGS_OPTIONAL, + CFG_ENABLE_IP_TCP_UDP_CHKSUM_OFFLOAD_DEFAULT, + CFG_ENABLE_IP_TCP_UDP_CHKSUM_OFFLOAD_DISABLE, + CFG_ENABLE_IP_TCP_UDP_CHKSUM_OFFLOAD_ENABLE), + + REG_VARIABLE(CFG_POWERSAVE_OFFLOAD_NAME, WLAN_PARAM_Integer, + struct hdd_config, enablePowersaveOffload, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK, + CFG_POWERSAVE_OFFLOAD_DEFAULT, + CFG_POWERSAVE_OFFLOAD_MIN, + CFG_POWERSAVE_OFFLOAD_MAX), + + REG_VARIABLE(CFG_ENABLE_FW_UART_PRINT_NAME, WLAN_PARAM_Integer, + struct hdd_config, enablefwprint, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_FW_UART_PRINT_DEFAULT, + CFG_ENABLE_FW_UART_PRINT_DISABLE, + CFG_ENABLE_FW_UART_PRINT_ENABLE), + + REG_VARIABLE(CFG_ENABLE_FW_LOG_NAME, WLAN_PARAM_Integer, + struct hdd_config, enable_fw_log, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_FW_LOG_DEFAULT, + CFG_ENABLE_FW_LOG_DISABLE, + CFG_ENABLE_FW_LOG_MAX), + +#ifdef IPA_OFFLOAD + REG_VARIABLE(CFG_IPA_OFFLOAD_CONFIG_NAME, WLAN_PARAM_HexInteger, + struct hdd_config, IpaConfig, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_IPA_OFFLOAD_CONFIG_DEFAULT, + CFG_IPA_OFFLOAD_CONFIG_MIN, + CFG_IPA_OFFLOAD_CONFIG_MAX), + + REG_VARIABLE(CFG_IPA_DESC_SIZE_NAME, WLAN_PARAM_Integer, + struct hdd_config, IpaDescSize, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_IPA_DESC_SIZE_DEFAULT, + CFG_IPA_DESC_SIZE_MIN, + CFG_IPA_DESC_SIZE_MAX), + + REG_VARIABLE(CFG_IPA_HIGH_BANDWIDTH_MBPS, WLAN_PARAM_Integer, + struct hdd_config, IpaHighBandwidthMbps, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_IPA_HIGH_BANDWIDTH_MBPS_DEFAULT, + CFG_IPA_HIGH_BANDWIDTH_MBPS_MIN, + CFG_IPA_HIGH_BANDWIDTH_MBPS_MAX), + + REG_VARIABLE(CFG_IPA_MEDIUM_BANDWIDTH_MBPS, WLAN_PARAM_Integer, + struct hdd_config, IpaMediumBandwidthMbps, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_IPA_MEDIUM_BANDWIDTH_MBPS_DEFAULT, + CFG_IPA_MEDIUM_BANDWIDTH_MBPS_MIN, + CFG_IPA_MEDIUM_BANDWIDTH_MBPS_MAX), + + REG_VARIABLE(CFG_IPA_LOW_BANDWIDTH_MBPS, WLAN_PARAM_Integer, + struct hdd_config, IpaLowBandwidthMbps, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_IPA_LOW_BANDWIDTH_MBPS_DEFAULT, + CFG_IPA_LOW_BANDWIDTH_MBPS_MIN, + CFG_IPA_LOW_BANDWIDTH_MBPS_MAX), +#endif + + REG_VARIABLE(CFG_VHT_AMPDU_LEN_EXPONENT_NAME, WLAN_PARAM_Integer, + struct hdd_config, fVhtAmpduLenExponent, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK, + CFG_VHT_AMPDU_LEN_EXPONENT_DEFAULT, + CFG_VHT_AMPDU_LEN_EXPONENT_MIN, + CFG_VHT_AMPDU_LEN_EXPONENT_MAX), + + REG_VARIABLE(CFG_VHT_MPDU_LEN_NAME, WLAN_PARAM_Integer, + struct hdd_config, vhtMpduLen, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK, + CFG_VHT_MPDU_LEN_DEFAULT, + CFG_VHT_MPDU_LEN_MIN, + CFG_VHT_MPDU_LEN_MAX), + + REG_VARIABLE(CFG_MAX_WOW_FILTERS_NAME, WLAN_PARAM_Integer, + struct hdd_config, maxWoWFilters, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK, + CFG_MAX_WOW_FILTERS_DEFAULT, + CFG_MAX_WOW_FILTERS_MIN, + CFG_MAX_WOW_FILTERS_MAX), + + REG_VARIABLE(CFG_WOW_STATUS_NAME, WLAN_PARAM_Integer, + struct hdd_config, wowEnable, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_WOW_STATUS_DEFAULT, + CFG_WOW_ENABLE_MIN, + CFG_WOW_ENABLE_MAX), + + REG_VARIABLE(CFG_COALESING_IN_IBSS_NAME, WLAN_PARAM_Integer, + struct hdd_config, isCoalesingInIBSSAllowed, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_COALESING_IN_IBSS_DEFAULT, + CFG_COALESING_IN_IBSS_MIN, + CFG_COALESING_IN_IBSS_MAX), + + REG_VARIABLE(CFG_IBSS_ATIM_WIN_SIZE_NAME, WLAN_PARAM_Integer, + struct hdd_config, ibssATIMWinSize, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_IBSS_ATIM_WIN_SIZE_DEFAULT, + CFG_IBSS_ATIM_WIN_SIZE_MIN, + CFG_IBSS_ATIM_WIN_SIZE_MAX), + + REG_VARIABLE(CFG_SAP_MAX_NO_PEERS, WLAN_PARAM_Integer, + struct hdd_config, maxNumberOfPeers, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_SAP_MAX_NO_PEERS_DEFAULT, + CFG_SAP_MAX_NO_PEERS_MIN, + CFG_SAP_MAX_NO_PEERS_MAX), + + REG_VARIABLE(CFG_IBSS_IS_POWER_SAVE_ALLOWED_NAME, WLAN_PARAM_Integer, + struct hdd_config, isIbssPowerSaveAllowed, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_IBSS_IS_POWER_SAVE_ALLOWED_DEFAULT, + CFG_IBSS_IS_POWER_SAVE_ALLOWED_MIN, + CFG_IBSS_IS_POWER_SAVE_ALLOWED_MAX), + + REG_VARIABLE(CFG_IBSS_IS_POWER_COLLAPSE_ALLOWED_NAME, + WLAN_PARAM_Integer, + struct hdd_config, isIbssPowerCollapseAllowed, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_IBSS_IS_POWER_COLLAPSE_ALLOWED_DEFAULT, + CFG_IBSS_IS_POWER_COLLAPSE_ALLOWED_MIN, + CFG_IBSS_IS_POWER_COLLAPSE_ALLOWED_MAX), + + REG_VARIABLE(CFG_IBSS_AWAKE_ON_TX_RX_NAME, WLAN_PARAM_Integer, + struct hdd_config, isIbssAwakeOnTxRx, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_IBSS_AWAKE_ON_TX_RX_DEFAULT, + CFG_IBSS_AWAKE_ON_TX_RX_MIN, + CFG_IBSS_AWAKE_ON_TX_RX_MAX), + + REG_VARIABLE(CFG_IBSS_INACTIVITY_TIME_NAME, WLAN_PARAM_Integer, + struct hdd_config, ibssInactivityCount, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_IBSS_INACTIVITY_TIME_DEFAULT, + CFG_IBSS_INACTIVITY_TIME_MIN, + CFG_IBSS_INACTIVITY_TIME_MAX), + + REG_VARIABLE(CFG_IBSS_TXSP_END_INACTIVITY_NAME, WLAN_PARAM_Integer, + struct hdd_config, ibssTxSpEndInactivityTime, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_IBSS_TXSP_END_INACTIVITY_DEFAULT, + CFG_IBSS_TXSP_END_INACTIVITY_MIN, + CFG_IBSS_TXSP_END_INACTIVITY_MAX), + + REG_VARIABLE(CFG_IBSS_PS_WARMUP_TIME_NAME, WLAN_PARAM_Integer, + struct hdd_config, ibssPsWarmupTime, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_IBSS_PS_WARMUP_TIME_DEFAULT, + CFG_IBSS_PS_WARMUP_TIME_MIN, + CFG_IBSS_PS_WARMUP_TIME_MAX), + + REG_VARIABLE(CFG_IBSS_PS_1RX_CHAIN_IN_ATIM_WINDOW_NAME, + WLAN_PARAM_Integer, + struct hdd_config, ibssPs1RxChainInAtimEnable, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_IBSS_PS_1RX_CHAIN_IN_ATIM_WINDOW_DEFAULT, + CFG_IBSS_PS_1RX_CHAIN_IN_ATIM_WINDOW_MIN, + CFG_IBSS_PS_1RX_CHAIN_IN_ATIM_WINDOW_MAX), + + REG_VARIABLE(CFG_THERMAL_TEMP_MIN_LEVEL0_NAME, WLAN_PARAM_Integer, + struct hdd_config, thermalTempMinLevel0, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_THERMAL_TEMP_MIN_LEVEL0_DEFAULT, + CFG_THERMAL_TEMP_MIN_LEVEL0_MIN, + CFG_THERMAL_TEMP_MIN_LEVEL0_MAX), + + REG_VARIABLE(CFG_THERMAL_TEMP_MAX_LEVEL0_NAME, WLAN_PARAM_Integer, + struct hdd_config, thermalTempMaxLevel0, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_THERMAL_TEMP_MAX_LEVEL0_DEFAULT, + CFG_THERMAL_TEMP_MAX_LEVEL0_MIN, + CFG_THERMAL_TEMP_MAX_LEVEL0_MAX), + + REG_VARIABLE(CFG_THERMAL_TEMP_MIN_LEVEL1_NAME, WLAN_PARAM_Integer, + struct hdd_config, thermalTempMinLevel1, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_THERMAL_TEMP_MIN_LEVEL1_DEFAULT, + CFG_THERMAL_TEMP_MIN_LEVEL1_MIN, + CFG_THERMAL_TEMP_MIN_LEVEL1_MAX), + + REG_VARIABLE(CFG_THERMAL_TEMP_MAX_LEVEL1_NAME, WLAN_PARAM_Integer, + struct hdd_config, thermalTempMaxLevel1, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_THERMAL_TEMP_MAX_LEVEL1_DEFAULT, + CFG_THERMAL_TEMP_MAX_LEVEL1_MIN, + CFG_THERMAL_TEMP_MAX_LEVEL1_MAX), + + REG_VARIABLE(CFG_THERMAL_TEMP_MIN_LEVEL2_NAME, WLAN_PARAM_Integer, + struct hdd_config, thermalTempMinLevel2, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_THERMAL_TEMP_MIN_LEVEL2_DEFAULT, + CFG_THERMAL_TEMP_MIN_LEVEL2_MIN, + CFG_THERMAL_TEMP_MIN_LEVEL2_MAX), + + REG_VARIABLE(CFG_THERMAL_TEMP_MAX_LEVEL2_NAME, WLAN_PARAM_Integer, + struct hdd_config, thermalTempMaxLevel2, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_THERMAL_TEMP_MAX_LEVEL2_DEFAULT, + CFG_THERMAL_TEMP_MAX_LEVEL2_MIN, + CFG_THERMAL_TEMP_MAX_LEVEL2_MAX), + + REG_VARIABLE(CFG_THERMAL_TEMP_MIN_LEVEL3_NAME, WLAN_PARAM_Integer, + struct hdd_config, thermalTempMinLevel3, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_THERMAL_TEMP_MIN_LEVEL3_DEFAULT, + CFG_THERMAL_TEMP_MIN_LEVEL3_MIN, + CFG_THERMAL_TEMP_MIN_LEVEL3_MAX), + + REG_VARIABLE(CFG_THERMAL_TEMP_MAX_LEVEL3_NAME, WLAN_PARAM_Integer, + struct hdd_config, thermalTempMaxLevel3, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_THERMAL_TEMP_MAX_LEVEL3_DEFAULT, + CFG_THERMAL_TEMP_MAX_LEVEL3_MIN, + CFG_THERMAL_TEMP_MAX_LEVEL3_MAX), + + REG_VARIABLE(CFG_SET_TXPOWER_LIMIT2G_NAME, WLAN_PARAM_Integer, + struct hdd_config, TxPower2g, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_SET_TXPOWER_LIMIT2G_DEFAULT, + CFG_SET_TXPOWER_LIMIT2G_MIN, + CFG_SET_TXPOWER_LIMIT2G_MAX), + + REG_VARIABLE(CFG_SET_TXPOWER_LIMIT5G_NAME, WLAN_PARAM_Integer, + struct hdd_config, TxPower5g, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_SET_TXPOWER_LIMIT5G_DEFAULT, + CFG_SET_TXPOWER_LIMIT5G_MIN, + CFG_SET_TXPOWER_LIMIT5G_MAX), + + REG_VARIABLE(CFG_ENABLE_DEBUG_CONNECT_ISSUE, WLAN_PARAM_Integer, + struct hdd_config, gEnableDebugLog, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_DEBUG_CONNECT_ISSUE_DEFAULT, + CFG_ENABLE_DEBUG_CONNECT_ISSUE_MIN, + CFG_ENABLE_DEBUG_CONNECT_ISSUE_MAX), + + REG_VARIABLE(CFG_ENABLE_DFS_PHYERR_FILTEROFFLOAD_NAME, + WLAN_PARAM_Integer, + struct hdd_config, fDfsPhyerrFilterOffload, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_DFS_PHYERR_FILTEROFFLOAD_DEFAULT, + CFG_ENABLE_DFS_PHYERR_FILTEROFFLOAD_MIN, + CFG_ENABLE_DFS_PHYERR_FILTEROFFLOAD_MAX), + + REG_VARIABLE(CFG_ENABLE_OVERLAP_CH, WLAN_PARAM_Integer, + struct hdd_config, gEnableOverLapCh, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK, + CFG_ENABLE_OVERLAP_CH_DEFAULT, + CFG_ENABLE_OVERLAP_CH_MIN, + CFG_ENABLE_OVERLAP_CH_MAX), + + REG_VARIABLE(CFG_REG_CHANGE_DEF_COUNTRY_NAME, WLAN_PARAM_Integer, + struct hdd_config, fRegChangeDefCountry, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_REG_CHANGE_DEF_COUNTRY_DEFAULT, + CFG_REG_CHANGE_DEF_COUNTRY_MIN, + CFG_REG_CHANGE_DEF_COUNTRY_MAX), + +#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL + REG_VARIABLE(CFG_LL_TX_FLOW_LWM, WLAN_PARAM_Integer, + struct hdd_config, TxFlowLowWaterMark, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_LL_TX_FLOW_LWM_DEFAULT, + CFG_LL_TX_FLOW_LWM_MIN, + CFG_LL_TX_FLOW_LWM_MAX), + REG_VARIABLE(CFG_LL_TX_FLOW_HWM_OFFSET, WLAN_PARAM_Integer, + struct hdd_config, TxFlowHighWaterMarkOffset, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_LL_TX_FLOW_HWM_OFFSET_DEFAULT, + CFG_LL_TX_FLOW_HWM_OFFSET_MIN, + CFG_LL_TX_FLOW_HWM_OFFSET_MAX), + REG_VARIABLE(CFG_LL_TX_FLOW_MAX_Q_DEPTH, WLAN_PARAM_Integer, + struct hdd_config, TxFlowMaxQueueDepth, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_LL_TX_FLOW_MAX_Q_DEPTH_DEFAULT, + CFG_LL_TX_FLOW_MAX_Q_DEPTH_MIN, + CFG_LL_TX_FLOW_MAX_Q_DEPTH_MAX), + REG_VARIABLE(CFG_LL_TX_LBW_FLOW_LWM, WLAN_PARAM_Integer, + struct hdd_config, TxLbwFlowLowWaterMark, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_LL_TX_LBW_FLOW_LWM_DEFAULT, + CFG_LL_TX_LBW_FLOW_LWM_MIN, + CFG_LL_TX_LBW_FLOW_LWM_MAX), + + REG_VARIABLE(CFG_LL_TX_LBW_FLOW_HWM_OFFSET, WLAN_PARAM_Integer, + struct hdd_config, TxLbwFlowHighWaterMarkOffset, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_LL_TX_LBW_FLOW_HWM_OFFSET_DEFAULT, + CFG_LL_TX_LBW_FLOW_HWM_OFFSET_MIN, + CFG_LL_TX_LBW_FLOW_HWM_OFFSET_MAX), + + REG_VARIABLE(CFG_LL_TX_LBW_FLOW_MAX_Q_DEPTH, WLAN_PARAM_Integer, + struct hdd_config, TxLbwFlowMaxQueueDepth, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_LL_TX_LBW_FLOW_MAX_Q_DEPTH_DEFAULT, + CFG_LL_TX_LBW_FLOW_MAX_Q_DEPTH_MIN, + CFG_LL_TX_LBW_FLOW_MAX_Q_DEPTH_MAX), + + REG_VARIABLE(CFG_LL_TX_HBW_FLOW_LWM, WLAN_PARAM_Integer, + struct hdd_config, TxHbwFlowLowWaterMark, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_LL_TX_HBW_FLOW_LWM_DEFAULT, + CFG_LL_TX_HBW_FLOW_LWM_MIN, + CFG_LL_TX_HBW_FLOW_LWM_MAX), + + REG_VARIABLE(CFG_LL_TX_HBW_FLOW_HWM_OFFSET, WLAN_PARAM_Integer, + struct hdd_config, TxHbwFlowHighWaterMarkOffset, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_LL_TX_HBW_FLOW_HWM_OFFSET_DEFAULT, + CFG_LL_TX_HBW_FLOW_HWM_OFFSET_MIN, + CFG_LL_TX_HBW_FLOW_HWM_OFFSET_MAX), + + REG_VARIABLE(CFG_LL_TX_HBW_FLOW_MAX_Q_DEPTH, WLAN_PARAM_Integer, + struct hdd_config, TxHbwFlowMaxQueueDepth, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_LL_TX_HBW_FLOW_MAX_Q_DEPTH_DEFAULT, + CFG_LL_TX_HBW_FLOW_MAX_Q_DEPTH_MIN, + CFG_LL_TX_HBW_FLOW_MAX_Q_DEPTH_MAX), +#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */ +#ifdef QCA_LL_TX_FLOW_CONTROL_V2 + + REG_VARIABLE(CFG_LL_TX_FLOW_STOP_QUEUE_TH, WLAN_PARAM_Integer, + struct hdd_config, TxFlowStopQueueThreshold, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_LL_TX_FLOW_STOP_QUEUE_TH_DEFAULT, + CFG_LL_TX_FLOW_STOP_QUEUE_TH_MIN, + CFG_LL_TX_FLOW_STOP_QUEUE_TH_MAX), + + REG_VARIABLE(CFG_LL_TX_FLOW_START_QUEUE_OFFSET, WLAN_PARAM_Integer, + struct hdd_config, TxFlowStartQueueOffset, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_LL_TX_FLOW_START_QUEUE_OFFSET_DEFAULT, + CFG_LL_TX_FLOW_START_QUEUE_OFFSET_MIN, + CFG_LL_TX_FLOW_START_QUEUE_OFFSET_MAX), + +#endif + REG_VARIABLE(CFG_INITIAL_DWELL_TIME_NAME, WLAN_PARAM_Integer, + struct hdd_config, nInitialDwellTime, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_INITIAL_DWELL_TIME_DEFAULT, + CFG_INITIAL_DWELL_TIME_MIN, + CFG_INITIAL_DWELL_TIME_MAX), + + REG_VARIABLE(CFG_INITIAL_SCAN_NO_DFS_CHNL_NAME, WLAN_PARAM_Integer, + struct hdd_config, initial_scan_no_dfs_chnl, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_INITIAL_SCAN_NO_DFS_CHNL_DEFAULT, + CFG_INITIAL_SCAN_NO_DFS_CHNL_MIN, + CFG_INITIAL_SCAN_NO_DFS_CHNL_MAX), + + REG_VARIABLE(CFG_SAP_MAX_OFFLOAD_PEERS, WLAN_PARAM_Integer, + struct hdd_config, apMaxOffloadPeers, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK, + CFG_SAP_MAX_OFFLOAD_PEERS_DEFAULT, + CFG_SAP_MAX_OFFLOAD_PEERS_MIN, + CFG_SAP_MAX_OFFLOAD_PEERS_MAX), + + REG_VARIABLE(CFG_SAP_MAX_OFFLOAD_REORDER_BUFFS, WLAN_PARAM_Integer, + struct hdd_config, apMaxOffloadReorderBuffs, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK, + CFG_SAP_MAX_OFFLOAD_REORDER_BUFFS_DEFAULT, + CFG_SAP_MAX_OFFLOAD_REORDER_BUFFS_MIN, + CFG_SAP_MAX_OFFLOAD_REORDER_BUFFS_MAX), + + REG_VARIABLE(CFG_ADVERTISE_CONCURRENT_OPERATION_NAME, + WLAN_PARAM_Integer, + struct hdd_config, advertiseConcurrentOperation, + VAR_FLAGS_OPTIONAL, + CFG_ADVERTISE_CONCURRENT_OPERATION_DEFAULT, + CFG_ADVERTISE_CONCURRENT_OPERATION_MIN, + CFG_ADVERTISE_CONCURRENT_OPERATION_MAX), + + REG_VARIABLE(CFG_ENABLE_MEMORY_DEEP_SLEEP, WLAN_PARAM_Integer, + struct hdd_config, enableMemDeepSleep, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_MEMORY_DEEP_SLEEP_DEFAULT, + CFG_ENABLE_MEMORY_DEEP_SLEEP_MIN, + CFG_ENABLE_MEMORY_DEEP_SLEEP_MAX), + + REG_VARIABLE(CFG_DEFAULT_RATE_INDEX_24GH, WLAN_PARAM_Integer, + struct hdd_config, defaultRateIndex24Ghz, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_DEFAULT_RATE_INDEX_24GH_DEFAULT, + CFG_DEFAULT_RATE_INDEX_24GH_MIN, + CFG_DEFAULT_RATE_INDEX_24GH_MAX), + +#ifdef MEMORY_DEBUG + REG_VARIABLE(CFG_ENABLE_MEMORY_DEBUG_NAME, WLAN_PARAM_Integer, + struct hdd_config, IsMemoryDebugSupportEnabled, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_MEMORY_DEBUG_DEFAULT, + CFG_ENABLE_MEMORY_DEBUG_MIN, + CFG_ENABLE_MEMORY_DEBUG_MAX), +#endif + + REG_VARIABLE(CFG_DEBUG_P2P_REMAIN_ON_CHANNEL_NAME, WLAN_PARAM_Integer, + struct hdd_config, debugP2pRemainOnChannel, + VAR_FLAGS_OPTIONAL, + CFG_DEBUG_P2P_REMAIN_ON_CHANNEL_DEFAULT, + CFG_DEBUG_P2P_REMAIN_ON_CHANNEL_MIN, + CFG_DEBUG_P2P_REMAIN_ON_CHANNEL_MAX), + + REG_VARIABLE(CFG_ENABLE_PACKET_LOG, WLAN_PARAM_Integer, + struct hdd_config, enablePacketLog, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_PACKET_LOG_DEFAULT, + CFG_ENABLE_PACKET_LOG_MIN, + CFG_ENABLE_PACKET_LOG_MAX), + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + REG_VARIABLE(CFG_ROAMING_OFFLOAD_NAME, WLAN_PARAM_Integer, + struct hdd_config, isRoamOffloadEnabled, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK, + CFG_ROAMING_OFFLOAD_DEFAULT, + CFG_ROAMING_OFFLOAD_MIN, + CFG_ROAMING_OFFLOAD_MAX), +#endif +#ifdef MSM_PLATFORM + REG_VARIABLE(CFG_BUS_BANDWIDTH_HIGH_THRESHOLD, WLAN_PARAM_Integer, + struct hdd_config, busBandwidthHighThreshold, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_BUS_BANDWIDTH_HIGH_THRESHOLD_DEFAULT, + CFG_BUS_BANDWIDTH_HIGH_THRESHOLD_MIN, + CFG_BUS_BANDWIDTH_HIGH_THRESHOLD_MAX), + + REG_VARIABLE(CFG_BUS_BANDWIDTH_MEDIUM_THRESHOLD, WLAN_PARAM_Integer, + struct hdd_config, busBandwidthMediumThreshold, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_BUS_BANDWIDTH_MEDIUM_THRESHOLD_DEFAULT, + CFG_BUS_BANDWIDTH_MEDIUM_THRESHOLD_MIN, + CFG_BUS_BANDWIDTH_MEDIUM_THRESHOLD_MAX), + + REG_VARIABLE(CFG_BUS_BANDWIDTH_LOW_THRESHOLD, WLAN_PARAM_Integer, + struct hdd_config, busBandwidthLowThreshold, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_BUS_BANDWIDTH_LOW_THRESHOLD_DEFAULT, + CFG_BUS_BANDWIDTH_LOW_THRESHOLD_MIN, + CFG_BUS_BANDWIDTH_LOW_THRESHOLD_MAX), + + REG_VARIABLE(CFG_BUS_BANDWIDTH_COMPUTE_INTERVAL, WLAN_PARAM_Integer, + struct hdd_config, busBandwidthComputeInterval, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_BUS_BANDWIDTH_COMPUTE_INTERVAL_DEFAULT, + CFG_BUS_BANDWIDTH_COMPUTE_INTERVAL_MIN, + CFG_BUS_BANDWIDTH_COMPUTE_INTERVAL_MAX), + + REG_VARIABLE(CFG_ENABLE_TCP_ADV_WIN_SCALE, WLAN_PARAM_Integer, + struct hdd_config, enable_tcp_adv_win_scale, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_TCP_ADV_WIN_SCALE_DEFAULT, + CFG_ENABLE_TCP_ADV_WIN_SCALE_MIN, + CFG_ENABLE_TCP_ADV_WIN_SCALE_MAX), + + REG_VARIABLE(CFG_ENABLE_TCP_DELACK, WLAN_PARAM_Integer, + struct hdd_config, enable_tcp_delack, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_TCP_DELACK_DEFAULT, + CFG_ENABLE_TCP_DELACK_MIN, + CFG_ENABLE_TCP_DELACK_MAX), + + REG_VARIABLE(CFG_TCP_DELACK_THRESHOLD_HIGH, WLAN_PARAM_Integer, + struct hdd_config, tcpDelackThresholdHigh, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TCP_DELACK_THRESHOLD_HIGH_DEFAULT, + CFG_TCP_DELACK_THRESHOLD_HIGH_MIN, + CFG_TCP_DELACK_THRESHOLD_HIGH_MAX), + + REG_VARIABLE(CFG_TCP_DELACK_THRESHOLD_LOW, WLAN_PARAM_Integer, + struct hdd_config, tcpDelackThresholdLow, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TCP_DELACK_THRESHOLD_LOW_DEFAULT, + CFG_TCP_DELACK_THRESHOLD_LOW_MIN, + CFG_TCP_DELACK_THRESHOLD_LOW_MAX), + + REG_VARIABLE(CFG_TCP_DELACK_TIMER_COUNT, WLAN_PARAM_Integer, + struct hdd_config, tcp_delack_timer_count, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TCP_DELACK_TIMER_COUNT_DEFAULT, + CFG_TCP_DELACK_TIMER_COUNT_MIN, + CFG_TCP_DELACK_TIMER_COUNT_MAX), + + REG_VARIABLE(CFG_TCP_TX_HIGH_TPUT_THRESHOLD_NAME, WLAN_PARAM_Integer, + struct hdd_config, tcp_tx_high_tput_thres, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TCP_TX_HIGH_TPUT_THRESHOLD_DEFAULT, + CFG_TCP_TX_HIGH_TPUT_THRESHOLD_MIN, + CFG_TCP_TX_HIGH_TPUT_THRESHOLD_MAX), +#endif + + REG_VARIABLE(CFG_ENABLE_FW_LOG_TYPE, WLAN_PARAM_Integer, + struct hdd_config, enableFwLogType, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_FW_LOG_TYPE_DEFAULT, + CFG_ENABLE_FW_LOG_TYPE_MIN, + CFG_ENABLE_FW_LOG_TYPE_MAX), + + REG_VARIABLE(CFG_ENABLE_FW_DEBUG_LOG_LEVEL, WLAN_PARAM_Integer, + struct hdd_config, enableFwLogLevel, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_FW_DEBUG_LOG_LEVEL_DEFAULT, + CFG_ENABLE_FW_DEBUG_LOG_LEVEL_MIN, + CFG_ENABLE_FW_DEBUG_LOG_LEVEL_MAX), + + REG_VARIABLE(CFG_ENABLE_FW_RTS_PROFILE, WLAN_PARAM_Integer, + struct hdd_config, rts_profile, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_FW_RTS_PROFILE_DEFAULT, + CFG_ENABLE_FW_RTS_PROFILE_MIN, + CFG_ENABLE_FW_RTS_PROFILE_MAX), + + REG_VARIABLE_STRING(CFG_ENABLE_FW_MODULE_LOG_LEVEL, WLAN_PARAM_String, + struct hdd_config, enableFwModuleLogLevel, + VAR_FLAGS_OPTIONAL, + (void *)CFG_ENABLE_FW_MODULE_LOG_DEFAULT), + +#ifdef WLAN_FEATURE_11W + REG_VARIABLE(CFG_PMF_SA_QUERY_MAX_RETRIES_NAME, WLAN_PARAM_Integer, + struct hdd_config, pmfSaQueryMaxRetries, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_PMF_SA_QUERY_MAX_RETRIES_DEFAULT, + CFG_PMF_SA_QUERY_MAX_RETRIES_MIN, + CFG_PMF_SA_QUERY_MAX_RETRIES_MAX), + + REG_VARIABLE(CFG_PMF_SA_QUERY_RETRY_INTERVAL_NAME, WLAN_PARAM_Integer, + struct hdd_config, pmfSaQueryRetryInterval, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_PMF_SA_QUERY_RETRY_INTERVAL_DEFAULT, + CFG_PMF_SA_QUERY_RETRY_INTERVAL_MIN, + CFG_PMF_SA_QUERY_RETRY_INTERVAL_MAX), +#endif + REG_VARIABLE(CFG_MAX_CONCURRENT_CONNECTIONS_NAME, WLAN_PARAM_Integer, + struct hdd_config, gMaxConcurrentActiveSessions, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_MAX_CONCURRENT_CONNECTIONS_DEFAULT, + CFG_MAX_CONCURRENT_CONNECTIONS_MIN, + CFG_MAX_CONCURRENT_CONNECTIONS_MAX), + +#ifdef FEATURE_GREEN_AP + REG_VARIABLE(CFG_ENABLE_GREEN_AP_FEATURE, WLAN_PARAM_Integer, + struct hdd_config, enableGreenAP, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_GREEN_AP_FEATURE_DEFAULT, + CFG_ENABLE_GREEN_AP_FEATURE_MIN, + CFG_ENABLE_GREEN_AP_FEATURE_MAX), + REG_VARIABLE(CFG_ENABLE_EGAP_ENABLE_FEATURE, WLAN_PARAM_Integer, + struct hdd_config, enable_egap, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_EGAP_ENABLE_FEATURE_DEFAULT, + CFG_ENABLE_EGAP_ENABLE_FEATURE_MIN, + CFG_ENABLE_EGAP_ENABLE_FEATURE_MAX), + REG_VARIABLE(CFG_ENABLE_EGAP_INACT_TIME_FEATURE, WLAN_PARAM_Integer, + struct hdd_config, egap_inact_time, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_EGAP_INACT_TIME_FEATURE_DEFAULT, + CFG_ENABLE_EGAP_INACT_TIME_FEATURE_MIN, + CFG_ENABLE_EGAP_INACT_TIME_FEATURE_MAX), + REG_VARIABLE(CFG_ENABLE_EGAP_WAIT_TIME_FEATURE, WLAN_PARAM_Integer, + struct hdd_config, egap_wait_time, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_EGAP_WAIT_TIME_FEATURE_DEFAULT, + CFG_ENABLE_EGAP_WAIT_TIME_FEATURE_MIN, + CFG_ENABLE_EGAP_WAIT_TIME_FEATURE_MAX), + REG_VARIABLE(CFG_ENABLE_EGAP_FLAGS_FEATURE, WLAN_PARAM_Integer, + struct hdd_config, egap_feature_flag, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_EGAP_FLAGS_FEATURE_DEFAULT, + CFG_ENABLE_EGAP_FLAGS_FEATURE_MIN, + CFG_ENABLE_EGAP_FLAGS_FEATURE_MAX), +#endif + + REG_VARIABLE(CFG_ENABLE_CRASH_INJECT, WLAN_PARAM_Integer, + struct hdd_config, crash_inject_enabled, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_CRASH_INJECT_DEFAULT, + CFG_ENABLE_CRASH_INJECT_MIN, + CFG_ENABLE_CRASH_INJECT_MAX), + + REG_VARIABLE(CFG_IGNORE_CAC_NAME, WLAN_PARAM_Integer, + struct hdd_config, ignoreCAC, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_IGNORE_CAC_DEFAULT, + CFG_IGNORE_CAC_MIN, + CFG_IGNORE_CAC_MAX), + + REG_VARIABLE(CFG_ENABLE_SAP_DFS_CH_SIFS_BURST_NAME, WLAN_PARAM_Integer, + struct hdd_config, IsSapDfsChSifsBurstEnabled, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_SAP_DFS_CH_SIFS_BURST_DEFAULT, + CFG_ENABLE_SAP_DFS_CH_SIFS_BURST_MIN, + CFG_ENABLE_SAP_DFS_CH_SIFS_BURST_MAX), + + REG_VARIABLE(CFG_DFS_RADAR_PRI_MULTIPLIER_NAME, WLAN_PARAM_Integer, + struct hdd_config, dfsRadarPriMultiplier, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_DFS_RADAR_PRI_MULTIPLIER_DEFAULT, + CFG_DFS_RADAR_PRI_MULTIPLIER_MIN, + CFG_DFS_RADAR_PRI_MULTIPLIER_MAX), + + REG_VARIABLE(CFG_REORDER_OFFLOAD_SUPPORT_NAME, WLAN_PARAM_Integer, + struct hdd_config, reorderOffloadSupport, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_REORDER_OFFLOAD_SUPPORT_DEFAULT, + CFG_REORDER_OFFLOAD_SUPPORT_MIN, + CFG_REORDER_OFFLOAD_SUPPORT_MAX), + + REG_VARIABLE(CFG_IPA_UC_TX_BUF_COUNT_NAME, WLAN_PARAM_Integer, + struct hdd_config, IpaUcTxBufCount, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK, + CFG_IPA_UC_TX_BUF_COUNT_DEFAULT, + CFG_IPA_UC_TX_BUF_COUNT_MIN, + CFG_IPA_UC_TX_BUF_COUNT_MAX), + + REG_VARIABLE(CFG_IPA_UC_TX_BUF_SIZE_NAME, WLAN_PARAM_Integer, + struct hdd_config, IpaUcTxBufSize, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK, + CFG_IPA_UC_TX_BUF_SIZE_DEFAULT, + CFG_IPA_UC_TX_BUF_SIZE_MIN, + CFG_IPA_UC_TX_BUF_SIZE_MAX), + + REG_VARIABLE(CFG_IPA_UC_RX_IND_RING_COUNT_NAME, WLAN_PARAM_Integer, + struct hdd_config, IpaUcRxIndRingCount, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK, + CFG_IPA_UC_RX_IND_RING_COUNT_DEFAULT, + CFG_IPA_UC_RX_IND_RING_COUNT_MIN, + CFG_IPA_UC_RX_IND_RING_COUNT_MAX), + + REG_VARIABLE(CFG_IPA_UC_TX_PARTITION_BASE_NAME, WLAN_PARAM_Integer, + struct hdd_config, IpaUcTxPartitionBase, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK, + CFG_IPA_UC_TX_PARTITION_BASE_DEFAULT, + CFG_IPA_UC_TX_PARTITION_BASE_MIN, + CFG_IPA_UC_TX_PARTITION_BASE_MAX), +#ifdef WLAN_LOGGING_SOCK_SVC_ENABLE + REG_VARIABLE(CFG_WLAN_LOGGING_SUPPORT_NAME, WLAN_PARAM_Integer, + struct hdd_config, wlanLoggingEnable, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_WLAN_LOGGING_SUPPORT_DEFAULT, + CFG_WLAN_LOGGING_SUPPORT_DISABLE, + CFG_WLAN_LOGGING_SUPPORT_ENABLE), + + REG_VARIABLE(CFG_WLAN_LOGGING_FE_CONSOLE_SUPPORT_NAME, + WLAN_PARAM_Integer, + struct hdd_config, wlanLoggingFEToConsole, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_WLAN_LOGGING_FE_CONSOLE_SUPPORT_DEFAULT, + CFG_WLAN_LOGGING_FE_CONSOLE_SUPPORT_DISABLE, + CFG_WLAN_LOGGING_FE_CONSOLE_SUPPORT_ENABLE), + + REG_VARIABLE(CFG_WLAN_LOGGING_NUM_BUF_NAME, WLAN_PARAM_Integer, + struct hdd_config, wlanLoggingNumBuf, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_WLAN_LOGGING_NUM_BUF_DEFAULT, + CFG_WLAN_LOGGING_NUM_BUF_MIN, + CFG_WLAN_LOGGING_NUM_BUF_MAX), +#endif /* WLAN_LOGGING_SOCK_SVC_ENABLE */ + + REG_VARIABLE(CFG_ENABLE_SIFS_BURST, WLAN_PARAM_Integer, + struct hdd_config, enableSifsBurst, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_SIFS_BURST_DEFAULT, + CFG_ENABLE_SIFS_BURST_MIN, + CFG_ENABLE_SIFS_BURST_MAX), + +#ifdef WLAN_FEATURE_LPSS + REG_VARIABLE(CFG_ENABLE_LPASS_SUPPORT, WLAN_PARAM_Integer, + struct hdd_config, enable_lpass_support, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_LPASS_SUPPORT_DEFAULT, + CFG_ENABLE_LPASS_SUPPORT_MIN, + CFG_ENABLE_LPASS_SUPPORT_MAX), +#endif + +#ifdef WLAN_FEATURE_NAN + REG_VARIABLE(CFG_ENABLE_NAN_SUPPORT, WLAN_PARAM_Integer, + struct hdd_config, enable_nan_support, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_NAN_SUPPORT_DEFAULT, + CFG_ENABLE_NAN_SUPPORT_MIN, + CFG_ENABLE_NAN_SUPPORT_MAX), +#endif + + REG_VARIABLE(CFG_ENABLE_SELF_RECOVERY, WLAN_PARAM_Integer, + struct hdd_config, enableSelfRecovery, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_SELF_RECOVERY_DEFAULT, + CFG_ENABLE_SELF_RECOVERY_MIN, + CFG_ENABLE_SELF_RECOVERY_MAX), + +#ifdef FEATURE_WLAN_FORCE_SAP_SCC + REG_VARIABLE(CFG_SAP_SCC_CHAN_AVOIDANCE, WLAN_PARAM_Integer, + struct hdd_config, SapSccChanAvoidance, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_SAP_SCC_CHAN_AVOIDANCE_DEFAULT, + CFG_SAP_SCC_CHAN_AVOIDANCE_MIN, + CFG_SAP_SCC_CHAN_AVOIDANCE_MAX), +#endif /* FEATURE_WLAN_FORCE_SAP_SCC */ + + REG_VARIABLE(CFG_ENABLE_SAP_SUSPEND, WLAN_PARAM_Integer, + struct hdd_config, enableSapSuspend, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_SAP_SUSPEND_DEFAULT, + CFG_ENABLE_SAP_SUSPEND_MIN, + CFG_ENABLE_SAP_SUSPEND_MAX), + +#ifdef WLAN_FEATURE_EXTWOW_SUPPORT + REG_VARIABLE(CFG_EXTWOW_GO_TO_SUSPEND, WLAN_PARAM_Integer, + struct hdd_config, extWowGotoSuspend, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_EXTWOW_GO_TO_SUSPEND_DEFAULT, + CFG_EXTWOW_GO_TO_SUSPEND_MIN, + CFG_EXTWOW_GO_TO_SUSPEND_MAX), + + REG_VARIABLE(CFG_EXTWOW_APP1_WAKE_PIN_NUMBER, WLAN_PARAM_Integer, + struct hdd_config, extWowApp1WakeupPinNumber, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_EXTWOW_APP1_WAKE_PIN_NUMBER_DEFAULT, + CFG_EXTWOW_APP1_WAKE_PIN_NUMBER_MIN, + CFG_EXTWOW_APP1_WAKE_PIN_NUMBER_MAX), + + REG_VARIABLE(CFG_EXTWOW_APP2_WAKE_PIN_NUMBER, WLAN_PARAM_Integer, + struct hdd_config, extWowApp2WakeupPinNumber, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_EXTWOW_APP2_WAKE_PIN_NUMBER_DEFAULT, + CFG_EXTWOW_APP2_WAKE_PIN_NUMBER_MIN, + CFG_EXTWOW_APP2_WAKE_PIN_NUMBER_MAX), + + REG_VARIABLE(CFG_EXTWOW_KA_INIT_PING_INTERVAL, WLAN_PARAM_Integer, + struct hdd_config, extWowApp2KAInitPingInterval, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_EXTWOW_KA_INIT_PING_INTERVAL_DEFAULT, + CFG_EXTWOW_KA_INIT_PING_INTERVAL_MIN, + CFG_EXTWOW_KA_INIT_PING_INTERVAL_MAX), + + REG_VARIABLE(CFG_EXTWOW_KA_MIN_PING_INTERVAL, WLAN_PARAM_Integer, + struct hdd_config, extWowApp2KAMinPingInterval, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_EXTWOW_KA_MIN_PING_INTERVAL_DEFAULT, + CFG_EXTWOW_KA_MIN_PING_INTERVAL_MIN, + CFG_EXTWOW_KA_MIN_PING_INTERVAL_MAX), + + REG_VARIABLE(CFG_EXTWOW_KA_MAX_PING_INTERVAL, WLAN_PARAM_Integer, + struct hdd_config, extWowApp2KAMaxPingInterval, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_EXTWOW_KA_MAX_PING_INTERVAL_DEFAULT, + CFG_EXTWOW_KA_MAX_PING_INTERVAL_MIN, + CFG_EXTWOW_KA_MAX_PING_INTERVAL_MAX), + + REG_VARIABLE(CFG_EXTWOW_KA_INC_PING_INTERVAL, WLAN_PARAM_Integer, + struct hdd_config, extWowApp2KAIncPingInterval, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_EXTWOW_KA_INC_PING_INTERVAL_DEFAULT, + CFG_EXTWOW_KA_INC_PING_INTERVAL_MIN, + CFG_EXTWOW_KA_INC_PING_INTERVAL_MAX), + + REG_VARIABLE(CFG_EXTWOW_TCP_SRC_PORT, WLAN_PARAM_Integer, + struct hdd_config, extWowApp2TcpSrcPort, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_EXTWOW_TCP_SRC_PORT_DEFAULT, + CFG_EXTWOW_TCP_SRC_PORT_MIN, + CFG_EXTWOW_TCP_SRC_PORT_MAX), + + REG_VARIABLE(CFG_EXTWOW_TCP_DST_PORT, WLAN_PARAM_Integer, + struct hdd_config, extWowApp2TcpDstPort, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_EXTWOW_TCP_DST_PORT_DEFAULT, + CFG_EXTWOW_TCP_DST_PORT_MIN, + CFG_EXTWOW_TCP_DST_PORT_MAX), + + REG_VARIABLE(CFG_EXTWOW_TCP_TX_TIMEOUT, WLAN_PARAM_Integer, + struct hdd_config, extWowApp2TcpTxTimeout, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_EXTWOW_TCP_TX_TIMEOUT_DEFAULT, + CFG_EXTWOW_TCP_TX_TIMEOUT_MIN, + CFG_EXTWOW_TCP_TX_TIMEOUT_MAX), + + REG_VARIABLE(CFG_EXTWOW_TCP_RX_TIMEOUT, WLAN_PARAM_Integer, + struct hdd_config, extWowApp2TcpRxTimeout, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_EXTWOW_TCP_RX_TIMEOUT_DEFAULT, + CFG_EXTWOW_TCP_RX_TIMEOUT_MIN, + CFG_EXTWOW_TCP_RX_TIMEOUT_MAX), +#endif + REG_VARIABLE(CFG_ENABLE_DEAUTH_TO_DISASSOC_MAP_NAME, WLAN_PARAM_Integer, + struct hdd_config, gEnableDeauthToDisassocMap, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_DEAUTH_TO_DISASSOC_MAP_DEFAULT, + CFG_ENABLE_DEAUTH_TO_DISASSOC_MAP_MIN, + CFG_ENABLE_DEAUTH_TO_DISASSOC_MAP_MAX), +#ifdef DHCP_SERVER_OFFLOAD + REG_VARIABLE(CFG_DHCP_SERVER_OFFLOAD_SUPPORT_NAME, WLAN_PARAM_Integer, + struct hdd_config, enableDHCPServerOffload, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_DHCP_SERVER_OFFLOAD_SUPPORT_DEFAULT, + CFG_DHCP_SERVER_OFFLOAD_SUPPORT_MIN, + CFG_DHCP_SERVER_OFFLOAD_SUPPORT_MAX), + REG_VARIABLE(CFG_DHCP_SERVER_OFFLOAD_NUM_CLIENT_NAME, + WLAN_PARAM_Integer, + struct hdd_config, dhcpMaxNumClients, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_DHCP_SERVER_OFFLOAD_NUM_CLIENT_DEFAULT, + CFG_DHCP_SERVER_OFFLOAD_NUM_CLIENT_MIN, + CFG_DHCP_SERVER_OFFLOAD_NUM_CLIENT_MAX), + REG_VARIABLE_STRING(CFG_DHCP_SERVER_IP_NAME, WLAN_PARAM_String, + struct hdd_config, dhcpServerIP, + VAR_FLAGS_OPTIONAL, + (void *)CFG_DHCP_SERVER_IP_DEFAULT), +#endif /* DHCP_SERVER_OFFLOAD */ + + REG_VARIABLE(CFG_ENABLE_DEAUTH_BEFORE_CONNECTION, WLAN_PARAM_Integer, + struct hdd_config, sendDeauthBeforeCon, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_DEAUTH_BEFORE_CONNECTION_DEFAULT, + CFG_ENABLE_DEAUTH_BEFORE_CONNECTION_MIN, + CFG_ENABLE_DEAUTH_BEFORE_CONNECTION_MAX), + + REG_VARIABLE(CFG_ENABLE_MAC_ADDR_SPOOFING, WLAN_PARAM_Integer, + struct hdd_config, enable_mac_spoofing, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_MAC_ADDR_SPOOFING_DEFAULT, + CFG_ENABLE_MAC_ADDR_SPOOFING_MIN, + CFG_ENABLE_MAC_ADDR_SPOOFING_MAX), + + REG_VARIABLE(CFG_ENABLE_CUSTOM_CONC_RULE1_NAME, WLAN_PARAM_Integer, + struct hdd_config, conc_custom_rule1, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK, + CFG_ENABLE_CUSTOM_CONC_RULE1_NAME_DEFAULT, + CFG_ENABLE_CUSTOM_CONC_RULE1_NAME_MIN, + CFG_ENABLE_CUSTOM_CONC_RULE1_NAME_MAX), + + REG_VARIABLE(CFG_ENABLE_CUSTOM_CONC_RULE2_NAME, WLAN_PARAM_Integer, + struct hdd_config, conc_custom_rule2, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK, + CFG_ENABLE_CUSTOM_CONC_RULE2_NAME_DEFAULT, + CFG_ENABLE_CUSTOM_CONC_RULE2_NAME_MIN, + CFG_ENABLE_CUSTOM_CONC_RULE2_NAME_MAX), + + REG_VARIABLE(CFG_ENABLE_STA_CONNECTION_IN_5GHZ, WLAN_PARAM_Integer, + struct hdd_config, is_sta_connection_in_5gz_enabled, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK, + CFG_ENABLE_STA_CONNECTION_IN_5GHZ_DEFAULT, + CFG_ENABLE_STA_CONNECTION_IN_5GHZ_MIN, + CFG_ENABLE_STA_CONNECTION_IN_5GHZ_MAX), + + REG_VARIABLE(CFG_STA_MIRACAST_MCC_REST_TIME_VAL, WLAN_PARAM_Integer, + struct hdd_config, sta_miracast_mcc_rest_time_val, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_STA_MIRACAST_MCC_REST_TIME_VAL_DEFAULT, + CFG_STA_MIRACAST_MCC_REST_TIME_VAL_MIN, + CFG_STA_MIRACAST_MCC_REST_TIME_VAL_MAX), + +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE + REG_VARIABLE(CFG_SAP_MCC_CHANNEL_AVOIDANCE_NAME, + WLAN_PARAM_Integer, + struct hdd_config, + sap_channel_avoidance, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK, + CFG_SAP_MCC_CHANNEL_AVOIDANCE_DEFAULT, + CFG_SAP_MCC_CHANNEL_AVOIDANCE_MIN, + CFG_SAP_MCC_CHANNEL_AVOIDANCE_MAX), +#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ + + REG_VARIABLE(CFG_SAP_P2P_11AC_OVERRIDE_NAME, WLAN_PARAM_Integer, + struct hdd_config, sap_p2p_11ac_override, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_SAP_P2P_11AC_OVERRIDE_DEFAULT, + CFG_SAP_P2P_11AC_OVERRIDE_MIN, + CFG_SAP_P2P_11AC_OVERRIDE_MAX), + + REG_VARIABLE(CFG_ENABLE_RAMDUMP_COLLECTION, WLAN_PARAM_Integer, + struct hdd_config, is_ramdump_enabled, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_RAMDUMP_COLLECTION_DEFAULT, + CFG_ENABLE_RAMDUMP_COLLECTION_MIN, + CFG_ENABLE_RAMDUMP_COLLECTION_MAX), + + REG_VARIABLE(CFG_SAP_DOT11MC, WLAN_PARAM_Integer, + struct hdd_config, sap_dot11mc, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_SAP_DOT11MC_DEFAULT, + CFG_SAP_DOT11MC_MIN, + CFG_SAP_DOT11MC_MAX), + + REG_VARIABLE(CFG_ENABLE_NON_DFS_CHAN_ON_RADAR, WLAN_PARAM_Integer, + struct hdd_config, prefer_non_dfs_on_radar, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_NON_DFS_CHAN_ON_RADAR_DEFAULT, + CFG_ENABLE_NON_DFS_CHAN_ON_RADAR_MIN, + CFG_ENABLE_NON_DFS_CHAN_ON_RADAR_MAX), + + REG_VARIABLE(CFG_MULTICAST_HOST_FW_MSGS, WLAN_PARAM_Integer, + struct hdd_config, multicast_host_fw_msgs, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_MULTICAST_HOST_FW_MSGS_DEFAULT, + CFG_MULTICAST_HOST_FW_MSGS_MIN, + CFG_MULTICAST_HOST_FW_MSGS_MAX), + + REG_VARIABLE(CFG_CONC_SYSTEM_PREF, WLAN_PARAM_Integer, + struct hdd_config, conc_system_pref, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_CONC_SYSTEM_PREF_DEFAULT, + CFG_CONC_SYSTEM_PREF_MIN, + CFG_CONC_SYSTEM_PREF_MAX), + + REG_VARIABLE(CFG_TSO_ENABLED_NAME, WLAN_PARAM_Integer, + struct hdd_config, tso_enable, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TSO_ENABLED_DEFAULT, + CFG_TSO_ENABLED_MIN, + CFG_TSO_ENABLED_MAX), + + REG_VARIABLE(CFG_LRO_ENABLED_NAME, WLAN_PARAM_Integer, + struct hdd_config, lro_enable, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_LRO_ENABLED_DEFAULT, + CFG_LRO_ENABLED_MIN, + CFG_LRO_ENABLED_MAX), + + REG_VARIABLE(CFG_BPF_PACKET_FILTER_OFFLOAD, WLAN_PARAM_Integer, + struct hdd_config, bpf_packet_filter_enable, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_BPF_PACKET_FILTER_OFFLOAD_DEFAULT, + CFG_BPF_PACKET_FILTER_OFFLOAD_MIN, + CFG_BPF_PACKET_FILTER_OFFLOAD_MAX), + + REG_VARIABLE(CFG_TDLS_ENABLE_DEFER_TIMER, WLAN_PARAM_Integer, + struct hdd_config, tdls_enable_defer_time, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TDLS_ENABLE_DEFER_TIMER_DEFAULT, + CFG_TDLS_ENABLE_DEFER_TIMER_MIN, + CFG_TDLS_ENABLE_DEFER_TIMER_MAX), + + REG_VARIABLE(CFG_FLOW_STEERING_ENABLED_NAME, WLAN_PARAM_Integer, + struct hdd_config, flow_steering_enable, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_FLOW_STEERING_ENABLED_DEFAULT, + CFG_FLOW_STEERING_ENABLED_MIN, + CFG_FLOW_STEERING_ENABLED_MAX), + + REG_VARIABLE(CFG_ACTIVE_MODE_OFFLOAD, WLAN_PARAM_Integer, + struct hdd_config, active_mode_offload, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ACTIVE_MODE_OFFLOAD_DEFAULT, + CFG_ACTIVE_MODE_OFFLOAD_MIN, + CFG_ACTIVE_MODE_OFFLOAD_MAX), + + REG_VARIABLE(CFG_FINE_TIME_MEAS_CAPABILITY, WLAN_PARAM_HexInteger, + struct hdd_config, fine_time_meas_cap, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_FINE_TIME_MEAS_CAPABILITY_DEFAULT, + CFG_FINE_TIME_MEAS_CAPABILITY_MIN, + CFG_FINE_TIME_MEAS_CAPABILITY_MAX), + +#ifdef WLAN_FEATURE_FASTPATH + REG_VARIABLE(CFG_ENABLE_FASTPATH, WLAN_PARAM_Integer, + struct hdd_config, fastpath_enable, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_FASTPATH_DEFAULT, + CFG_ENABLE_FASTPATH_MIN, + CFG_ENABLE_FASTPATH_MAX), +#endif + REG_VARIABLE(CFG_MAX_SCAN_COUNT_NAME, WLAN_PARAM_Integer, + struct hdd_config, max_scan_count, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_MAX_SCAN_COUNT_DEFAULT, + CFG_MAX_SCAN_COUNT_MIN, + CFG_MAX_SCAN_COUNT_MAX), + + REG_VARIABLE(CFG_DOT11P_MODE_NAME, WLAN_PARAM_Integer, + struct hdd_config, dot11p_mode, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_DOT11P_MODE_DEFAULT, + CFG_DOT11P_MODE_MIN, + CFG_DOT11P_MODE_MAX), + +#ifdef FEATURE_WLAN_EXTSCAN + REG_VARIABLE(CFG_EXTSCAN_ALLOWED_NAME, WLAN_PARAM_Integer, + struct hdd_config, extscan_enabled, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_EXTSCAN_ALLOWED_DEF, + CFG_EXTSCAN_ALLOWED_MIN, + CFG_EXTSCAN_ALLOWED_MAX), + + REG_VARIABLE(CFG_EXTSCAN_PASSIVE_MAX_CHANNEL_TIME_NAME, + WLAN_PARAM_Integer, + struct hdd_config, extscan_passive_max_chn_time, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_EXTSCAN_PASSIVE_MAX_CHANNEL_TIME_DEFAULT, + CFG_EXTSCAN_PASSIVE_MAX_CHANNEL_TIME_MIN, + CFG_EXTSCAN_PASSIVE_MAX_CHANNEL_TIME_MAX), + + REG_VARIABLE(CFG_EXTSCAN_PASSIVE_MIN_CHANNEL_TIME_NAME, + WLAN_PARAM_Integer, + struct hdd_config, extscan_passive_min_chn_time, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_EXTSCAN_PASSIVE_MIN_CHANNEL_TIME_DEFAULT, + CFG_EXTSCAN_PASSIVE_MIN_CHANNEL_TIME_MIN, + CFG_EXTSCAN_PASSIVE_MIN_CHANNEL_TIME_MAX), + + REG_VARIABLE(CFG_EXTSCAN_ACTIVE_MAX_CHANNEL_TIME_NAME, + WLAN_PARAM_Integer, + struct hdd_config, extscan_active_max_chn_time, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_EXTSCAN_ACTIVE_MAX_CHANNEL_TIME_DEFAULT, + CFG_EXTSCAN_ACTIVE_MAX_CHANNEL_TIME_MIN, + CFG_EXTSCAN_ACTIVE_MAX_CHANNEL_TIME_MAX), + + REG_VARIABLE(CFG_EXTSCAN_ACTIVE_MIN_CHANNEL_TIME_NAME, + WLAN_PARAM_Integer, + struct hdd_config, extscan_active_min_chn_time, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_EXTSCAN_ACTIVE_MIN_CHANNEL_TIME_DEFAULT, + CFG_EXTSCAN_ACTIVE_MIN_CHANNEL_TIME_MIN, + CFG_EXTSCAN_ACTIVE_MIN_CHANNEL_TIME_MAX), +#endif + +#ifdef WLAN_FEATURE_WOW_PULSE + REG_VARIABLE(CFG_WOW_PULSE_SUPPORT_NAME, WLAN_PARAM_Integer, + struct hdd_config, wow_pulse_support, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_WOW_PULSE_SUPPORT_DEFAULT, + CFG_WOW_PULSE_SUPPORT_MIN, + CFG_WOW_PULSE_SUPPORT_MAX), + + REG_VARIABLE(CFG_WOW_PULSE_PIN_NAME, WLAN_PARAM_Integer, + struct hdd_config, wow_pulse_pin, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_WOW_PULSE_PIN_DEFAULT, + CFG_WOW_PULSE_PIN_MIN, + CFG_WOW_PULSE_PIN_MAX), + + REG_VARIABLE(CFG_WOW_PULSE_INTERVAL_LOW_NAME, WLAN_PARAM_Integer, + struct hdd_config, wow_pulse_interval_low, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_WOW_PULSE_INTERVAL_LOW_DEFAULT, + CFG_WOW_PULSE_INTERVAL_LOW_MIN, + CFG_WOW_PULSE_INTERVAL_LOW_MAX), + + REG_VARIABLE(CFG_WOW_PULSE_INTERVAL_HIGH_NAME, WLAN_PARAM_Integer, + struct hdd_config, wow_pulse_interval_high, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_WOW_PULSE_INTERVAL_HIGH_DEFAULT, + CFG_WOW_PULSE_INTERVAL_HIGH_MIN, + CFG_WOW_PULSE_INTERVAL_HIGH_MAX), +#endif + + + REG_VARIABLE(CFG_CE_CLASSIFY_ENABLE_NAME, WLAN_PARAM_Integer, + struct hdd_config, ce_classify_enabled, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_CE_CLASSIFY_ENABLE_DEFAULT, + CFG_CE_CLASSIFY_ENABLE_MIN, + CFG_CE_CLASSIFY_ENABLE_MAX), + + REG_VARIABLE(CFG_DUAL_MAC_FEATURE_DISABLE, WLAN_PARAM_HexInteger, + struct hdd_config, dual_mac_feature_disable, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_DUAL_MAC_FEATURE_DISABLE_DEFAULT, + CFG_DUAL_MAC_FEATURE_DISABLE_MIN, + CFG_DUAL_MAC_FEATURE_DISABLE_MAX), +#ifdef FEATURE_WLAN_SCAN_PNO + REG_VARIABLE(CFG_PNO_CHANNEL_PREDICTION_NAME, WLAN_PARAM_Integer, + struct hdd_config, pno_channel_prediction, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_PNO_CHANNEL_PREDICTION_DEFAULT, + CFG_PNO_CHANNEL_PREDICTION_MIN, + CFG_PNO_CHANNEL_PREDICTION_MAX), + + REG_VARIABLE(CFG_TOP_K_NUM_OF_CHANNELS_NAME, WLAN_PARAM_Integer, + struct hdd_config, top_k_num_of_channels, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TOP_K_NUM_OF_CHANNELS_DEFAULT, + CFG_TOP_K_NUM_OF_CHANNELS_MIN, + CFG_TOP_K_NUM_OF_CHANNELS_MAX), + + REG_VARIABLE(CFG_STATIONARY_THRESHOLD_NAME, WLAN_PARAM_Integer, + struct hdd_config, stationary_thresh, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_STATIONARY_THRESHOLD_DEFAULT, + CFG_STATIONARY_THRESHOLD_MIN, + CFG_STATIONARY_THRESHOLD_MAX), + + REG_VARIABLE(CFG_CHANNEL_PREDICTION_FULL_SCAN_MS_NAME, + WLAN_PARAM_Integer, + struct hdd_config, channel_prediction_full_scan, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_CHANNEL_PREDICTION_FULL_SCAN_MS_DEFAULT, + CFG_CHANNEL_PREDICTION_FULL_SCAN_MS_MIN, + CFG_CHANNEL_PREDICTION_FULL_SCAN_MS_MAX), + + REG_VARIABLE(CFG_ADAPTIVE_PNOSCAN_DWELL_MODE_NAME, + WLAN_PARAM_Integer, + struct hdd_config, pnoscan_adaptive_dwell_mode, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ADAPTIVE_PNOSCAN_DWELL_MODE_DEFAULT, + CFG_ADAPTIVE_PNOSCAN_DWELL_MODE_MIN, + CFG_ADAPTIVE_PNOSCAN_DWELL_MODE_MAX), +#endif + + REG_VARIABLE(CFG_TX_CHAIN_MASK_CCK, WLAN_PARAM_Integer, + struct hdd_config, tx_chain_mask_cck, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TX_CHAIN_MASK_CCK_DEFAULT, + CFG_TX_CHAIN_MASK_CCK_MIN, + CFG_TX_CHAIN_MASK_CCK_MAX), + + REG_VARIABLE(CFG_TX_CHAIN_MASK_1SS, WLAN_PARAM_Integer, + struct hdd_config, tx_chain_mask_1ss, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TX_CHAIN_MASK_1SS_DEFAULT, + CFG_TX_CHAIN_MASK_1SS_MIN, + CFG_TX_CHAIN_MASK_1SS_MAX), + + REG_VARIABLE(CFG_SELF_GEN_FRM_PWR, WLAN_PARAM_Integer, + struct hdd_config, self_gen_frm_pwr, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_SELF_GEN_FRM_PWR_DEFAULT, + CFG_SELF_GEN_FRM_PWR_MIN, + CFG_SELF_GEN_FRM_PWR_MAX), + + REG_VARIABLE(CFG_EARLY_STOP_SCAN_ENABLE, WLAN_PARAM_Integer, + struct hdd_config, early_stop_scan_enable, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_EARLY_STOP_SCAN_ENABLE_DEFAULT, + CFG_EARLY_STOP_SCAN_ENABLE_MIN, + CFG_EARLY_STOP_SCAN_ENABLE_MAX), + + REG_VARIABLE(CFG_EARLY_STOP_SCAN_MIN_THRESHOLD, + WLAN_PARAM_SignedInteger, struct hdd_config, + early_stop_scan_min_threshold, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_EARLY_STOP_SCAN_MIN_THRESHOLD_DEFAULT, + CFG_EARLY_STOP_SCAN_MIN_THRESHOLD_MIN, + CFG_EARLY_STOP_SCAN_MIN_THRESHOLD_MAX), + + REG_VARIABLE(CFG_EARLY_STOP_SCAN_MAX_THRESHOLD, + WLAN_PARAM_SignedInteger, struct hdd_config, + early_stop_scan_max_threshold, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_EARLY_STOP_SCAN_MAX_THRESHOLD_DEFAULT, + CFG_EARLY_STOP_SCAN_MAX_THRESHOLD_MIN, + CFG_EARLY_STOP_SCAN_MAX_THRESHOLD_MAX), + + REG_VARIABLE(CFG_FIRST_SCAN_BUCKET_THRESHOLD_NAME, + WLAN_PARAM_SignedInteger, + struct hdd_config, first_scan_bucket_threshold, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_FIRST_SCAN_BUCKET_THRESHOLD_DEFAULT, + CFG_FIRST_SCAN_BUCKET_THRESHOLD_MIN, + CFG_FIRST_SCAN_BUCKET_THRESHOLD_MAX), + +#ifdef FEATURE_LFR_SUBNET_DETECTION + REG_VARIABLE(CFG_ENABLE_LFR_SUBNET_DETECTION, WLAN_PARAM_Integer, + struct hdd_config, enable_lfr_subnet_detection, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_LFR_SUBNET_DEFAULT, + CFG_ENABLE_LFR_SUBNET_MIN, + CFG_ENABLE_LFR_SUBNET_MAX), +#endif + REG_VARIABLE(CFG_OBSS_HT40_SCAN_ACTIVE_DWELL_TIME_NAME, + WLAN_PARAM_Integer, + struct hdd_config, obss_active_dwelltime, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_OBSS_HT40_SCAN_ACTIVE_DWELL_TIME_DEFAULT, + CFG_OBSS_HT40_SCAN_ACTIVE_DWELL_TIME_MIN, + CFG_OBSS_HT40_SCAN_ACTIVE_DWELL_TIME_MAX), + + REG_VARIABLE(CFG_OBSS_HT40_SCAN_PASSIVE_DWELL_TIME_NAME, + WLAN_PARAM_Integer, + struct hdd_config, obss_passive_dwelltime, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_OBSS_HT40_SCAN_PASSIVE_DWELL_TIME_DEFAULT, + CFG_OBSS_HT40_SCAN_PASSIVE_DWELL_TIME_MIN, + CFG_OBSS_HT40_SCAN_PASSIVE_DWELL_TIME_MAX), + + REG_VARIABLE(CFG_OBSS_HT40_SCAN_WIDTH_TRIGGER_INTERVAL_NAME, + WLAN_PARAM_Integer, + struct hdd_config, obss_width_trigger_interval, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_OBSS_HT40_SCAN_WIDTH_TRIGGER_INTERVAL_DEFAULT, + CFG_OBSS_HT40_SCAN_WIDTH_TRIGGER_INTERVAL_MIN, + CFG_OBSS_HT40_SCAN_WIDTH_TRIGGER_INTERVAL_MAX), + + REG_VARIABLE(CFG_INFORM_BSS_RSSI_RAW_NAME, WLAN_PARAM_Integer, + struct hdd_config, inform_bss_rssi_raw, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_INFORM_BSS_RSSI_RAW_DEFAULT, + CFG_INFORM_BSS_RSSI_RAW_MIN, + CFG_INFORM_BSS_RSSI_RAW_MAX), + +#ifdef WLAN_FEATURE_TSF + REG_VARIABLE(CFG_SET_TSF_GPIO_PIN_NAME, WLAN_PARAM_Integer, + struct hdd_config, tsf_gpio_pin, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_SET_TSF_GPIO_PIN_DEFAULT, + CFG_SET_TSF_GPIO_PIN_MIN, + CFG_SET_TSF_GPIO_PIN_MAX), +#endif + + REG_VARIABLE(CFG_ROAM_DENSE_TRAFFIC_THRESHOLD, WLAN_PARAM_Integer, + struct hdd_config, roam_dense_traffic_thresh, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ROAM_DENSE_TRAFFIC_THRESHOLD_DEFAULT, + CFG_ROAM_DENSE_TRAFFIC_THRESHOLD_MIN, + CFG_ROAM_DENSE_TRAFFIC_THRESHOLD_MAX), + + REG_VARIABLE(CFG_ROAM_DENSE_RSSI_THRE_OFFSET, WLAN_PARAM_Integer, + struct hdd_config, roam_dense_rssi_thresh_offset, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ROAM_DENSE_RSSI_THRE_OFFSET_DEFAULT, + CFG_ROAM_DENSE_RSSI_THRE_OFFSET_MIN, + CFG_ROAM_DENSE_RSSI_THRE_OFFSET_MAX), + + REG_VARIABLE(CFG_IGNORE_PEER_HT_MODE_NAME, WLAN_PARAM_Integer, + struct hdd_config, ignore_peer_ht_opmode, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_IGNORE_PEER_HT_MODE_DEFAULT, + CFG_IGNORE_PEER_HT_MODE_MIN, + CFG_IGNORE_PEER_HT_MODE_MAX), + + REG_VARIABLE(CFG_ROAM_DENSE_MIN_APS, WLAN_PARAM_Integer, + struct hdd_config, roam_dense_min_aps, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ROAM_DENSE_MIN_APS_DEFAULT, + CFG_ROAM_DENSE_MIN_APS_MIN, + CFG_ROAM_DENSE_MIN_APS_MAX), + + REG_VARIABLE(CFG_ENABLE_FATAL_EVENT_TRIGGER, WLAN_PARAM_Integer, + struct hdd_config, enable_fatal_event, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_FATAL_EVENT_TRIGGER_DEFAULT, + CFG_ENABLE_FATAL_EVENT_TRIGGER_MIN, + CFG_ENABLE_FATAL_EVENT_TRIGGER_MAX), + + REG_VARIABLE(CFG_ENABLE_EDCA_INI_NAME, WLAN_PARAM_Integer, + struct hdd_config, enable_edca_params, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_EDCA_INI_DEFAULT, + CFG_ENABLE_EDCA_INI_MIN, + CFG_ENABLE_EDCA_INI_MAX), + + REG_VARIABLE(CFG_ENABLE_GO_CTS2SELF_FOR_STA, WLAN_PARAM_Integer, + struct hdd_config, enable_go_cts2self_for_sta, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_GO_CTS2SELF_FOR_STA_DEFAULT, + CFG_ENABLE_GO_CTS2SELF_FOR_STA_MIN, + CFG_ENABLE_GO_CTS2SELF_FOR_STA_MAX), + + REG_VARIABLE(CFG_EDCA_VO_CWMIN_VALUE_NAME, WLAN_PARAM_Integer, + struct hdd_config, edca_vo_cwmin, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_EDCA_VO_CWMIN_VALUE_DEFAULT, + CFG_EDCA_VO_CWMIN_VALUE_MIN, + CFG_EDCA_VO_CWMIN_VALUE_MAX), + + REG_VARIABLE(CFG_EDCA_VI_CWMIN_VALUE_NAME, WLAN_PARAM_Integer, + struct hdd_config, edca_vi_cwmin, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_EDCA_VI_CWMIN_VALUE_DEFAULT, + CFG_EDCA_VI_CWMIN_VALUE_MIN, + CFG_EDCA_VI_CWMIN_VALUE_MAX), + + REG_VARIABLE(CFG_EDCA_BK_CWMIN_VALUE_NAME, WLAN_PARAM_Integer, + struct hdd_config, edca_bk_cwmin, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_EDCA_BK_CWMIN_VALUE_DEFAULT, + CFG_EDCA_BK_CWMIN_VALUE_MIN, + CFG_EDCA_BK_CWMIN_VALUE_MAX), + + REG_VARIABLE(CFG_EDCA_BE_CWMIN_VALUE_NAME, WLAN_PARAM_Integer, + struct hdd_config, edca_be_cwmin, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_EDCA_BE_CWMIN_VALUE_DEFAULT, + CFG_EDCA_BE_CWMIN_VALUE_MIN, + CFG_EDCA_BE_CWMIN_VALUE_MAX), + + REG_VARIABLE(CFG_EDCA_VO_CWMAX_VALUE_NAME, WLAN_PARAM_Integer, + struct hdd_config, edca_vo_cwmax, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_EDCA_VO_CWMAX_VALUE_DEFAULT, + CFG_EDCA_VO_CWMAX_VALUE_MIN, + CFG_EDCA_VO_CWMAX_VALUE_MAX), + + REG_VARIABLE(CFG_EDCA_VI_CWMAX_VALUE_NAME, WLAN_PARAM_Integer, + struct hdd_config, edca_vi_cwmax, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_EDCA_VI_CWMAX_VALUE_DEFAULT, + CFG_EDCA_VI_CWMAX_VALUE_MIN, + CFG_EDCA_VI_CWMAX_VALUE_MAX), + + REG_VARIABLE(CFG_EDCA_BK_CWMAX_VALUE_NAME, WLAN_PARAM_Integer, + struct hdd_config, edca_bk_cwmax, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_EDCA_BK_CWMAX_VALUE_DEFAULT, + CFG_EDCA_BK_CWMAX_VALUE_MIN, + CFG_EDCA_BK_CWMAX_VALUE_MAX), + + REG_VARIABLE(CFG_EDCA_BE_CWMAX_VALUE_NAME, WLAN_PARAM_Integer, + struct hdd_config, edca_be_cwmax, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_EDCA_BE_CWMAX_VALUE_DEFAULT, + CFG_EDCA_BE_CWMAX_VALUE_MIN, + CFG_EDCA_BE_CWMAX_VALUE_MAX), + + REG_VARIABLE(CFG_EDCA_VO_AIFS_VALUE_NAME, WLAN_PARAM_Integer, + struct hdd_config, edca_vo_aifs, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_EDCA_VO_AIFS_VALUE_DEFAULT, + CFG_EDCA_VO_AIFS_VALUE_MIN, + CFG_EDCA_VO_AIFS_VALUE_MAX), + + REG_VARIABLE(CFG_EDCA_VI_AIFS_VALUE_NAME, WLAN_PARAM_Integer, + struct hdd_config, edca_vi_aifs, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_EDCA_VI_AIFS_VALUE_DEFAULT, + CFG_EDCA_VI_AIFS_VALUE_MIN, + CFG_EDCA_VI_AIFS_VALUE_MAX), + + REG_VARIABLE(CFG_EDCA_BK_AIFS_VALUE_NAME, WLAN_PARAM_Integer, + struct hdd_config, edca_bk_aifs, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_EDCA_BK_AIFS_VALUE_DEFAULT, + CFG_EDCA_BK_AIFS_VALUE_MIN, + CFG_EDCA_BK_AIFS_VALUE_MAX), + + REG_VARIABLE(CFG_EDCA_BE_AIFS_VALUE_NAME, WLAN_PARAM_Integer, + struct hdd_config, edca_be_aifs, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_EDCA_BE_AIFS_VALUE_DEFAULT, + CFG_EDCA_BE_AIFS_VALUE_MIN, + CFG_EDCA_BE_AIFS_VALUE_MAX), + + REG_VARIABLE_STRING(CFG_ENABLE_TX_SCHED_WRR_VO, WLAN_PARAM_String, + struct hdd_config, tx_sched_wrr_vo, + VAR_FLAGS_OPTIONAL, + (void *) CFG_ENABLE_TX_SCHED_WRR_VO_DEFAULT), + + REG_VARIABLE_STRING(CFG_ENABLE_TX_SCHED_WRR_VI, WLAN_PARAM_String, + struct hdd_config, tx_sched_wrr_vi, + VAR_FLAGS_OPTIONAL, + (void *) CFG_ENABLE_TX_SCHED_WRR_VI_DEFAULT), + + REG_VARIABLE_STRING(CFG_ENABLE_TX_SCHED_WRR_BE, WLAN_PARAM_String, + struct hdd_config, tx_sched_wrr_be, + VAR_FLAGS_OPTIONAL, + (void *) CFG_ENABLE_TX_SCHED_WRR_BE_DEFAULT), + + REG_VARIABLE_STRING(CFG_ENABLE_TX_SCHED_WRR_BK, WLAN_PARAM_String, + struct hdd_config, tx_sched_wrr_bk, + VAR_FLAGS_OPTIONAL, + (void *) CFG_ENABLE_TX_SCHED_WRR_BK_DEFAULT), + +#ifdef WLAN_FEATURE_NAN_DATAPATH + REG_VARIABLE(CFG_ENABLE_NAN_DATAPATH_NAME, WLAN_PARAM_Integer, + struct hdd_config, enable_nan_datapath, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_NAN_DATAPATH_DEFAULT, + CFG_ENABLE_NAN_DATAPATH_MIN, + CFG_ENABLE_NAN_DATAPATH_MAX), + + REG_VARIABLE(CFG_ENABLE_NAN_NDI_CHANNEL_NAME, WLAN_PARAM_Integer, + struct hdd_config, nan_datapath_ndi_channel, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_NAN_NDI_CHANNEL_DEFAULT, + CFG_ENABLE_NAN_NDI_CHANNEL_MIN, + CFG_ENABLE_NAN_NDI_CHANNEL_MAX), +#endif + REG_VARIABLE(CFG_CREATE_BUG_REPORT_FOR_SCAN, WLAN_PARAM_Integer, + struct hdd_config, bug_report_for_no_scan_results, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_CREATE_BUG_REPORT_FOR_SCAN_DEFAULT, + CFG_CREATE_BUG_REPORT_FOR_SCAN_DISABLE, + CFG_CREATE_BUG_REPORT_FOR_SCAN_ENABLE), + + REG_VARIABLE(CFG_ENABLE_DP_TRACE, WLAN_PARAM_Integer, + struct hdd_config, enable_dp_trace, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_DP_TRACE_DEFAULT, + CFG_ENABLE_DP_TRACE_MIN, + CFG_ENABLE_DP_TRACE_MAX), + + REG_VARIABLE(CFG_ADAPTIVE_SCAN_DWELL_MODE_NAME, WLAN_PARAM_Integer, + struct hdd_config, scan_adaptive_dwell_mode, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ADAPTIVE_SCAN_DWELL_MODE_DEFAULT, + CFG_ADAPTIVE_SCAN_DWELL_MODE_MIN, + CFG_ADAPTIVE_SCAN_DWELL_MODE_MAX), + + REG_VARIABLE(CFG_ADAPTIVE_ROAMSCAN_DWELL_MODE_NAME, WLAN_PARAM_Integer, + struct hdd_config, roamscan_adaptive_dwell_mode, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ADAPTIVE_ROAMSCAN_DWELL_MODE_DEFAULT, + CFG_ADAPTIVE_ROAMSCAN_DWELL_MODE_MIN, + CFG_ADAPTIVE_ROAMSCAN_DWELL_MODE_MAX), + + REG_VARIABLE(CFG_ADAPTIVE_EXTSCAN_DWELL_MODE_NAME, WLAN_PARAM_Integer, + struct hdd_config, extscan_adaptive_dwell_mode, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ADAPTIVE_EXTSCAN_DWELL_MODE_DEFAULT, + CFG_ADAPTIVE_EXTSCAN_DWELL_MODE_MIN, + CFG_ADAPTIVE_EXTSCAN_DWELL_MODE_MAX), + + REG_VARIABLE(CFG_ADAPTIVE_DWELL_MODE_ENABLED_NAME, WLAN_PARAM_Integer, + struct hdd_config, adaptive_dwell_mode_enabled, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ADAPTIVE_DWELL_MODE_ENABLED_DEFAULT, + CFG_ADAPTIVE_DWELL_MODE_ENABLED_MIN, + CFG_ADAPTIVE_DWELL_MODE_ENABLED_MAX), + + REG_VARIABLE(CFG_GLOBAL_ADAPTIVE_DWELL_MODE_NAME, WLAN_PARAM_Integer, + struct hdd_config, global_adapt_dwelltime_mode, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_GLOBAL_ADAPTIVE_DWELL_MODE_DEFAULT, + CFG_GLOBAL_ADAPTIVE_DWELL_MODE_MIN, + CFG_GLOBAL_ADAPTIVE_DWELL_MODE_MAX), + + REG_VARIABLE(CFG_ADAPT_DWELL_LPF_WEIGHT_NAME, WLAN_PARAM_Integer, + struct hdd_config, adapt_dwell_lpf_weight, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ADAPT_DWELL_LPF_WEIGHT_DEFAULT, + CFG_ADAPT_DWELL_LPF_WEIGHT_MIN, + CFG_ADAPT_DWELL_LPF_WEIGHT_MAX), + + REG_VARIABLE(CFG_SUB_20_CHANNEL_WIDTH_NAME, WLAN_PARAM_Integer, + struct hdd_config, enable_sub_20_channel_width, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_SUB_20_CHANNEL_WIDTH_DEFAULT, + CFG_SUB_20_CHANNEL_WIDTH_MIN, + CFG_SUB_20_CHANNEL_WIDTH_MAX), + + REG_VARIABLE(CFG_TGT_GTX_USR_CFG_NAME, WLAN_PARAM_Integer, + struct hdd_config, tgt_gtx_usr_cfg, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TGT_GTX_USR_CFG_DEFAULT, + CFG_TGT_GTX_USR_CFG_MIN, + CFG_TGT_GTX_USR_CFG_MAX), + + REG_VARIABLE(CFG_ADAPT_DWELL_PASMON_INTVAL_NAME, WLAN_PARAM_Integer, + struct hdd_config, adapt_dwell_passive_mon_intval, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ADAPT_DWELL_PASMON_INTVAL_DEFAULT, + CFG_ADAPT_DWELL_PASMON_INTVAL_MIN, + CFG_ADAPT_DWELL_PASMON_INTVAL_MAX), + + REG_VARIABLE(CFG_ADAPT_DWELL_WIFI_THRESH_NAME, WLAN_PARAM_Integer, + struct hdd_config, adapt_dwell_wifi_act_threshold, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ADAPT_DWELL_WIFI_THRESH_DEFAULT, + CFG_ADAPT_DWELL_WIFI_THRESH_MIN, + CFG_ADAPT_DWELL_WIFI_THRESH_MAX), + + REG_VARIABLE(CFG_RX_MODE_NAME, WLAN_PARAM_Integer, + struct hdd_config, rx_mode, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_RX_MODE_DEFAULT, + CFG_RX_MODE_MIN, + CFG_RX_MODE_MAX), + + REG_VARIABLE_STRING(CFG_RPS_RX_QUEUE_CPU_MAP_LIST_NAME, + WLAN_PARAM_String, + struct hdd_config, cpu_map_list, + VAR_FLAGS_OPTIONAL, + (void *)CFG_RPS_RX_QUEUE_CPU_MAP_LIST_DEFAULT), + + REG_VARIABLE(CFG_INDOOR_CHANNEL_SUPPORT_NAME, + WLAN_PARAM_Integer, + struct hdd_config, indoor_channel_support, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_INDOOR_CHANNEL_SUPPORT_DEFAULT, + CFG_INDOOR_CHANNEL_SUPPORT_MIN, + CFG_INDOOR_CHANNEL_SUPPORT_MAX), + + REG_VARIABLE(CFG_SAP_TX_LEAKAGE_THRESHOLD_NAME, + WLAN_PARAM_Integer, + struct hdd_config, sap_tx_leakage_threshold, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_SAP_TX_LEAKAGE_THRESHOLD_DEFAULT, + CFG_SAP_TX_LEAKAGE_THRESHOLD_MIN, + CFG_SAP_TX_LEAKAGE_THRESHOLD_MAX), + + REG_VARIABLE(CFG_BUG_ON_REINIT_FAILURE_NAME, WLAN_PARAM_Integer, + struct hdd_config, bug_on_reinit_failure, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_BUG_ON_REINIT_FAILURE_DEFAULT, + CFG_BUG_ON_REINIT_FAILURE_MIN, + CFG_BUG_ON_REINIT_FAILURE_MAX), + + REG_VARIABLE(CFG_SAP_FORCE_11N_FOR_11AC_NAME, WLAN_PARAM_Integer, + struct hdd_config, sap_force_11n_for_11ac, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_SAP_FORCE_11N_FOR_11AC_DEFAULT, + CFG_SAP_FORCE_11N_FOR_11AC_MIN, + CFG_SAP_FORCE_11N_FOR_11AC_MAX), + + REG_VARIABLE(CFG_INTERFACE_CHANGE_WAIT_NAME, WLAN_PARAM_Integer, + struct hdd_config, iface_change_wait_time, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK, + CFG_INTERFACE_CHANGE_WAIT_DEFAULT, + CFG_INTERFACE_CHANGE_WAIT_MIN, + CFG_INTERFACE_CHANGE_WAIT_MAX), + + REG_VARIABLE(CFG_FILTER_MULTICAST_REPLAY_NAME, + WLAN_PARAM_Integer, + struct hdd_config, multicast_replay_filter, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_FILTER_MULTICAST_REPLAY_DEFAULT, + CFG_FILTER_MULTICAST_REPLAY_MIN, + CFG_FILTER_MULTICAST_REPLAY_MAX), + + REG_VARIABLE(CFG_SIFS_BURST_DURATION_NAME, WLAN_PARAM_Integer, + struct hdd_config, sifs_burst_duration, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_SIFS_BURST_DURATION_DEFAULT, + CFG_SIFS_BURST_DURATION_MIN, + CFG_SIFS_BURST_DURATION_MAX), + + REG_VARIABLE(CFG_ENABLE_PHY_REG_NAME, WLAN_PARAM_HexInteger, + struct hdd_config, enable_phy_reg_retention, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_PHY_REG_DEFAULT, + CFG_PHY_REG_MIN, + CFG_PHY_REG_MAX), + + REG_VARIABLE(CFG_OPTIMIZE_CA_EVENT_NAME, WLAN_PARAM_Integer, + struct hdd_config, goptimize_chan_avoid_event, + VAR_FLAGS_OPTIONAL | + VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_OPTIMIZE_CA_EVENT_DEFAULT, + CFG_OPTIMIZE_CA_EVENT_DISABLE, + CFG_OPTIMIZE_CA_EVENT_ENABLE), + + REG_VARIABLE(CFG_TX_AGGREGATION_SIZE, WLAN_PARAM_Integer, + struct hdd_config, tx_aggregation_size, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TX_AGGREGATION_SIZE_DEFAULT, + CFG_TX_AGGREGATION_SIZE_MIN, + CFG_TX_AGGREGATION_SIZE_MAX), + + REG_VARIABLE(CFG_RX_AGGREGATION_SIZE, WLAN_PARAM_Integer, + struct hdd_config, rx_aggregation_size, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_RX_AGGREGATION_SIZE_DEFAULT, + CFG_RX_AGGREGATION_SIZE_MIN, + CFG_RX_AGGREGATION_SIZE_MAX), + REG_VARIABLE(CFG_SAP_MAX_INACTIVITY_OVERRIDE_NAME, WLAN_PARAM_Integer, + struct hdd_config, sap_max_inactivity_override, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_SAP_MAX_INACTIVITY_OVERRIDE_DEFAULT, + CFG_SAP_MAX_INACTIVITY_OVERRIDE_MIN, + CFG_SAP_MAX_INACTIVITY_OVERRIDE_MAX), + REG_VARIABLE(CFG_CRASH_FW_TIMEOUT_NAME, WLAN_PARAM_Integer, + struct hdd_config, fw_timeout_crash, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_CRASH_FW_TIMEOUT_DEFAULT, + CFG_CRASH_FW_TIMEOUT_DISABLE, + CFG_CRASH_FW_TIMEOUT_ENABLE), + REG_VARIABLE(CFG_RX_WAKELOCK_TIMEOUT_NAME, WLAN_PARAM_Integer, + struct hdd_config, rx_wakelock_timeout, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_RX_WAKELOCK_TIMEOUT_DEFAULT, + CFG_RX_WAKELOCK_TIMEOUT_MIN, + CFG_RX_WAKELOCK_TIMEOUT_MAX), +#ifdef WLAN_FEATURE_UDP_RESPONSE_OFFLOAD + REG_VARIABLE(CFG_UDP_RESP_OFFLOAD_SUPPORT_NAME, WLAN_PARAM_Integer, + struct hdd_config, udp_resp_offload_support, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_UDP_RESP_OFFLOAD_SUPPORT_DEFAULT, + CFG_UDP_RESP_OFFLOAD_SUPPORT_MIN, + CFG_UDP_RESP_OFFLOAD_SUPPORT_MAX), + + REG_VARIABLE(CFG_UDP_RESP_OFFLOAD_DEST_PORT_NAME, WLAN_PARAM_Integer, + struct hdd_config, dest_port, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_UDP_RESP_OFFLOAD_DEST_PORT_DEFAULT, + CFG_UDP_RESP_OFFLOAD_DEST_PORT_MIN, + CFG_UDP_RESP_OFFLOAD_DEST_PORT_MAX), + + REG_VARIABLE_STRING(CFG_UDP_RESP_OFFLOAD_PAYLOAD_FILTER_NAME, + WLAN_PARAM_String, + struct hdd_config, payload_filter, + VAR_FLAGS_OPTIONAL, + (void *)CFG_UDP_RESP_OFFLOAD_PAYLOAD_FILTER_DEFAULT), + + REG_VARIABLE_STRING(CFG_UDP_RESP_OFFLOAD_RESPONSE_PAYLOAD_NAME, + WLAN_PARAM_String, + struct hdd_config, response_payload, + VAR_FLAGS_OPTIONAL, + (void *)CFG_UDP_RESP_OFFLOAD_RESPONSE_PAYLOAD_DEFAULT), +#endif + REG_VARIABLE(CFG_PER_ROAM_ENABLE_NAME, WLAN_PARAM_Integer, + struct hdd_config, is_per_roam_enabled, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_PER_ROAM_ENABLE_DEFAULT, + CFG_PER_ROAM_ENABLE_MIN, + CFG_PER_ROAM_ENABLE_MAX), + + REG_VARIABLE(CFG_PER_ROAM_CONFIG_HIGH_RATE_TH_NAME, WLAN_PARAM_Integer, + struct hdd_config, per_roam_high_rate_threshold, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_PER_ROAM_CONFIG_HIGH_RATE_TH_DEFAULT, + CFG_PER_ROAM_CONFIG_HIGH_RATE_TH_MIN, + CFG_PER_ROAM_CONFIG_HIGH_RATE_TH_MAX), + + REG_VARIABLE(CFG_PER_ROAM_CONFIG_LOW_RATE_TH_NAME, WLAN_PARAM_Integer, + struct hdd_config, per_roam_low_rate_threshold, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_PER_ROAM_CONFIG_LOW_RATE_TH_DEFAULT, + CFG_PER_ROAM_CONFIG_LOW_RATE_TH_MIN, + CFG_PER_ROAM_CONFIG_LOW_RATE_TH_MAX), + + REG_VARIABLE(CFG_PER_ROAM_CONFIG_RATE_TH_PERCENT_NAME, + WLAN_PARAM_Integer, struct hdd_config, per_roam_th_percent, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_PER_ROAM_CONFIG_RATE_TH_PERCENT_DEFAULT, + CFG_PER_ROAM_CONFIG_RATE_TH_PERCENT_MIN, + CFG_PER_ROAM_CONFIG_RATE_TH_PERCENT_MAX), + + REG_VARIABLE(CFG_PER_ROAM_REST_TIME_NAME, WLAN_PARAM_Integer, + struct hdd_config, per_roam_rest_time, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_PER_ROAM_REST_TIME_DEFAULT, + CFG_PER_ROAM_REST_TIME_MIN, + CFG_PER_ROAM_REST_TIME_MAX), + + REG_VARIABLE(CFG_PER_ROAM_MONITOR_TIME, WLAN_PARAM_Integer, + struct hdd_config, per_roam_mon_time, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_PER_ROAM_MONTIOR_TIME_DEFAULT, + CFG_PER_ROAM_MONITOR_TIME_MIN, + CFG_PER_ROAM_MONITOR_TIME_MAX), + + REG_VARIABLE(CFG_PER_ROAM_MIN_CANDIDATE_RSSI, WLAN_PARAM_Integer, + struct hdd_config, min_candidate_rssi, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_PER_ROAM_MIN_CANDIDATE_RSSI_DEFAULT, + CFG_PER_ROAM_MIN_CANDIDATE_RSSI_MIN, + CFG_PER_ROAM_MIN_CANDIDATE_RSSI_MAX), + + REG_VARIABLE(CFG_MAX_SCHED_SCAN_PLAN_INT_NAME, WLAN_PARAM_Integer, + struct hdd_config, max_sched_scan_plan_interval, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_MAX_SCHED_SCAN_PLAN_INT_DEFAULT, + CFG_MAX_SCHED_SCAN_PLAN_INT_MIN, + CFG_MAX_SCHED_SCAN_PLAN_INT_MAX), + REG_VARIABLE(CFG_MAX_SCHED_SCAN_PLAN_ITRNS_NAME, WLAN_PARAM_Integer, + struct hdd_config, max_sched_scan_plan_iterations, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_MAX_SCHED_SCAN_PLAN_ITRNS_DEFAULT, + CFG_MAX_SCHED_SCAN_PLAN_ITRNS_MIN, + CFG_MAX_SCHED_SCAN_PLAN_ITRNS_MAX), + REG_VARIABLE(CFG_ACTIVE_BPF_MODE_NAME, WLAN_PARAM_Integer, + struct hdd_config, active_bpf_mode, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ACTIVE_BPF_MODE_DEFAULT, + CFG_ACTIVE_BPF_MODE_MIN, + CFG_ACTIVE_BPF_MODE_MAX), + + REG_VARIABLE(CFG_HW_FILTER_MODE_NAME, WLAN_PARAM_Integer, + struct hdd_config, hw_filter_mode, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_HW_FILTER_MODE_DEFAULT, + CFG_HW_FILTER_MODE_MIN, + CFG_HW_FILTER_MODE_MAX), + + REG_VARIABLE(CFG_SAP_INTERNAL_RESTART_NAME, WLAN_PARAM_Integer, + struct hdd_config, sap_internal_restart, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_SAP_INTERNAL_RESTART_DEFAULT, + CFG_SAP_INTERNAL_RESTART_MIN, + CFG_SAP_INTERNAL_RESTART_MAX), + + REG_VARIABLE(CFG_RESTART_BEACONING_ON_CH_AVOID_NAME, WLAN_PARAM_Integer, + struct hdd_config, restart_beaconing_on_chan_avoid_event, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_RESTART_BEACONING_ON_CH_AVOID_DEFAULT, + CFG_RESTART_BEACONING_ON_CH_AVOID_MIN, + CFG_RESTART_BEACONING_ON_CH_AVOID_MAX), + + REG_VARIABLE(CFG_ENABLE_BCAST_PROBE_RESP_NAME, WLAN_PARAM_Integer, + struct hdd_config, enable_bcast_probe_rsp, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_BCAST_PROBE_RESP_DEFAULT, + CFG_ENABLE_BCAST_PROBE_RESP_MIN, + CFG_ENABLE_BCAST_PROBE_RESP_MAX), + + REG_VARIABLE(CFG_QCN_IE_SUPPORT_NAME, WLAN_PARAM_Integer, + struct hdd_config, qcn_ie_support, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_QCN_IE_SUPPORT_DEFAULT, + CFG_QCN_IE_SUPPORT_MIN, + CFG_QCN_IE_SUPPORT_MAX), + + REG_VARIABLE(CFG_FILS_MAX_CHAN_GUARD_TIME_NAME, WLAN_PARAM_Integer, + struct hdd_config, fils_max_chan_guard_time, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_FILS_MAX_CHAN_GUARD_TIME_DEFAULT, + CFG_FILS_MAX_CHAN_GUARD_TIME_MIN, + CFG_FILS_MAX_CHAN_GUARD_TIME_MAX), + + REG_VARIABLE(CFG_FORCE_1X1_NAME, WLAN_PARAM_Integer, + struct hdd_config, is_force_1x1, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_FORCE_1X1_DEFAULT, + CFG_FORCE_1X1_MIN, + CFG_FORCE_1X1_MAX), + + REG_VARIABLE(CFG_ENABLE_5G_BAND_PREF_NAME, WLAN_PARAM_Integer, + struct hdd_config, enable_5g_band_pref, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_5G_BAND_PREF_DEFAULT, + CFG_ENABLE_5G_BAND_PREF_MIN, + CFG_ENABLE_5G_BAND_PREF_MAX), + + REG_VARIABLE(CFG_5G_RSSI_BOOST_THRESHOLD_NAME, WLAN_PARAM_Integer, + struct hdd_config, rssi_boost_threshold_5g, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_5G_RSSI_BOOST_THRESHOLD_DEFAULT, + CFG_5G_RSSI_BOOST_THRESHOLD_MIN, + CFG_5G_RSSI_BOOST_THRESHOLD_MAX), + + REG_VARIABLE(CFG_5G_RSSI_BOOST_FACTOR_NAME, WLAN_PARAM_Integer, + struct hdd_config, rssi_boost_factor_5g, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_5G_RSSI_BOOST_FACTOR_DEFAULT, + CFG_5G_RSSI_BOOST_FACTOR_MIN, + CFG_5G_RSSI_BOOST_FACTOR_MAX), + + REG_VARIABLE(CFG_5G_MAX_RSSI_BOOST_NAME, WLAN_PARAM_Integer, + struct hdd_config, max_rssi_boost_5g, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_5G_MAX_RSSI_BOOST_DEFAULT, + CFG_5G_MAX_RSSI_BOOST_MIN, + CFG_5G_MAX_RSSI_BOOST_MAX), + + REG_VARIABLE(CFG_5G_RSSI_PENALIZE_THRESHOLD_NAME, WLAN_PARAM_Integer, + struct hdd_config, rssi_penalize_threshold_5g, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_5G_RSSI_PENALIZE_THRESHOLD_DEFAULT, + CFG_5G_RSSI_PENALIZE_THRESHOLD_MIN, + CFG_5G_RSSI_PENALIZE_THRESHOLD_MAX), + + REG_VARIABLE(CFG_5G_RSSI_PENALIZE_FACTOR_NAME, WLAN_PARAM_Integer, + struct hdd_config, rssi_penalize_factor_5g, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_5G_RSSI_PENALIZE_FACTOR_DEFAULT, + CFG_5G_RSSI_PENALIZE_FACTOR_MIN, + CFG_5G_RSSI_PENALIZE_FACTOR_MAX), + + REG_VARIABLE(CFG_5G_MAX_RSSI_PENALIZE_NAME, WLAN_PARAM_Integer, + struct hdd_config, max_rssi_penalize_5g, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_5G_MAX_RSSI_PENALIZE_DEFAULT, + CFG_5G_MAX_RSSI_PENALIZE_MIN, + CFG_5G_MAX_RSSI_PENALIZE_MAX), + REG_VARIABLE(CFG_ENABLE_PACKET_FILTERS_NAME, WLAN_PARAM_Integer, + struct hdd_config, packet_filters_bitmap, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ENABLE_PACKET_FILTERS_DEFAULT, + CFG_ENABLE_PACKET_FILTERS_MIN, + CFG_ENABLE_PACKET_FILTERS_MAX), + + REG_VARIABLE(CFG_DROPPED_PKT_DISCONNECT_TH_NAME, WLAN_PARAM_Integer, + struct hdd_config, pkt_err_disconn_th, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_DROPPED_PKT_DISCONNECT_TH_DEFAULT, + CFG_DROPPED_PKT_DISCONNECT_TH_MIN, + CFG_DROPPED_PKT_DISCONNECT_TH_MAX), + + REG_VARIABLE(CFG_AUTO_DETECT_POWER_FAIL_MODE_NAME, WLAN_PARAM_Integer, + struct hdd_config, auto_pwr_save_fail_mode, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_AUTO_DETECT_POWER_FAIL_MODE_DEFAULT, + CFG_AUTO_DETECT_POWER_FAIL_MODE_MIN, + CFG_AUTO_DETECT_POWER_FAIL_MODE_MAX), + + REG_VARIABLE(CFG_IS_BSSID_HINT_PRIORITY_NAME, WLAN_PARAM_Integer, + struct hdd_config, is_bssid_hint_priority, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_IS_BSSID_HINT_PRIORITY_DEFAULT, + CFG_IS_BSSID_HINT_PRIORITY_MIN, + CFG_IS_BSSID_HINT_PRIORITY_MAX), + + REG_VARIABLE(CFG_11B_NUM_TX_CHAIN_NAME, WLAN_PARAM_Integer, + struct hdd_config, num_11b_tx_chains, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_11B_NUM_TX_CHAIN_DEFAULT, + CFG_11B_NUM_TX_CHAIN_MIN, + CFG_11B_NUM_TX_CHAIN_MAX), + + REG_VARIABLE(CFG_11AG_NUM_TX_CHAIN_NAME, WLAN_PARAM_Integer, + struct hdd_config, num_11ag_tx_chains, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_11AG_NUM_TX_CHAIN_DEFAULT, + CFG_11AG_NUM_TX_CHAIN_MIN, + CFG_11AG_NUM_TX_CHAIN_MAX), + + REG_VARIABLE(CFG_ITO_REPEAT_COUNT_NAME, WLAN_PARAM_Integer, + struct hdd_config, ito_repeat_count, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_ITO_REPEAT_COUNT_DEFAULT, + CFG_ITO_REPEAT_COUNT_MIN, + CFG_ITO_REPEAT_COUNT_MAX), + + REG_VARIABLE(CFG_TX_ORPHAN_ENABLE_NAME, WLAN_PARAM_Integer, + struct hdd_config, tx_orphan_enable, + VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, + CFG_TX_ORPHAN_ENABLE_DEFAULT, + CFG_TX_ORPHAN_ENABLE_MIN, + CFG_TX_ORPHAN_ENABLE_MAX), +}; + +/** + * get_next_line() - find and locate the new line pointer + * @str: pointer to string + * + * This function returns a pointer to the character after the occurence + * of a new line character. It also modifies the original string by replacing + * the '\n' character with the null character. + * + * Return: the pointer to the character at new line, + * or NULL if no new line character was found + */ +static char *get_next_line(char *str) +{ + char c; + + if (str == NULL || *str == '\0') { + return NULL; + } + + c = *str; + while (c != '\n' && c != '\0' && c != 0xd) { + str = str + 1; + c = *str; + } + + if (c == '\0') { + return NULL; + } else { + *str = '\0'; + return str + 1; + } + + return NULL; +} + +/** look for space. Ascii values to look are + * 0x09 == horizontal tab + * 0x0a == Newline ("\n") + * 0x0b == vertical tab + * 0x0c == Newpage or feed form. + * 0x0d == carriage return (CR or "\r") + * Null ('\0') should not considered as space. + */ +#define i_isspace(ch) (((ch) >= 0x09 && (ch) <= 0x0d) || (ch) == ' ') + +/** + * i_trim() - trims any leading and trailing white spaces + * @str: pointer to string + * + * Return: the pointer of the string + */ +static char *i_trim(char *str) +{ + char *ptr; + + if (*str == '\0') + return str; + + /* Find the first non white-space */ + ptr = str; + while (i_isspace(*ptr)) + ptr++; + + if (*ptr == '\0') + return str; + + /* This is the new start of the string */ + str = ptr; + + /* Find the last non white-space */ + ptr += strlen(ptr) - 1; + + while (ptr != str && i_isspace(*ptr)) + ptr--; + + /* Null terminate the following character */ + ptr[1] = '\0'; + + return str; +} + +/* Maximum length of the confgiuration name and value */ +#define CFG_VALUE_MAX_LEN 256 +#define CFG_ENTRY_MAX_LEN (32+CFG_VALUE_MAX_LEN) + +/** + * hdd_cfg_get_config() - get the configuration content + * @reg_table: pointer to configuration table + * @cRegTableEntries: number of the configuration entries + * @ini_struct: pointer to the hdd config knob + * @pHddCtx: pointer to hdd context + * @pBuf: buffer to store the configuration + * @buflen: size of the buffer + * + * Return: QDF_STATUS_SUCCESS if the configuration and buffer size can carry + * the content, otherwise QDF_STATUS_E_RESOURCES + */ +static QDF_STATUS hdd_cfg_get_config(REG_TABLE_ENTRY *reg_table, + unsigned long cRegTableEntries, + uint8_t *ini_struct, + hdd_context_t *pHddCtx, char *pBuf, + int buflen) +{ + unsigned int idx; + REG_TABLE_ENTRY *pRegEntry = reg_table; + uint32_t value; + char valueStr[CFG_VALUE_MAX_LEN]; + char configStr[CFG_ENTRY_MAX_LEN]; + char *fmt; + void *pField; + struct qdf_mac_addr *pMacAddr; + char *pCur = pBuf; + int curlen; + + /* start with an empty string */ + *pCur = '\0'; + + for (idx = 0; idx < cRegTableEntries; idx++, pRegEntry++) { + pField = ini_struct + pRegEntry->VarOffset; + + if ((WLAN_PARAM_Integer == pRegEntry->RegType) || + (WLAN_PARAM_SignedInteger == pRegEntry->RegType) || + (WLAN_PARAM_HexInteger == pRegEntry->RegType)) { + value = 0; + memcpy(&value, pField, pRegEntry->VarSize); + if (WLAN_PARAM_HexInteger == pRegEntry->RegType) { + fmt = "%x"; + } else if (WLAN_PARAM_SignedInteger == + pRegEntry->RegType) { + fmt = "%d"; + } else { + fmt = "%u"; + } + snprintf(valueStr, CFG_VALUE_MAX_LEN, fmt, value); + } else if (WLAN_PARAM_String == pRegEntry->RegType) { + snprintf(valueStr, CFG_VALUE_MAX_LEN, "%s", + (char *)pField); + } else if (WLAN_PARAM_MacAddr == pRegEntry->RegType) { + pMacAddr = (struct qdf_mac_addr *) pField; + snprintf(valueStr, CFG_VALUE_MAX_LEN, + "%02x:%02x:%02x:%02x:%02x:%02x", + pMacAddr->bytes[0], + pMacAddr->bytes[1], + pMacAddr->bytes[2], + pMacAddr->bytes[3], + pMacAddr->bytes[4], pMacAddr->bytes[5]); + } else { + snprintf(valueStr, CFG_VALUE_MAX_LEN, "(unhandled)"); + } + curlen = scnprintf(configStr, CFG_ENTRY_MAX_LEN, + "%s=[%s]%s\n", + pRegEntry->RegName, + valueStr, + test_bit(idx, + (void *)&pHddCtx->config-> + bExplicitCfg) ? "*" : ""); + + /* Ideally we want to return the config to the application, + * however the config is too big so we just printk() for now + */ +#ifdef RETURN_IN_BUFFER + if (curlen < buflen) { + /* copy string + '\0' */ + memcpy(pCur, configStr, curlen + 1); + + /* account for addition; */ + pCur += curlen; + buflen -= curlen; + } else { + /* buffer space exhausted, return what we have */ + return QDF_STATUS_E_RESOURCES; + } +#else + printk(KERN_INFO "%s", configStr); +#endif /* RETURN_IN_BUFFER */ + + } + +#ifndef RETURN_IN_BUFFER + /* notify application that output is in system log */ + snprintf(pCur, buflen, "WLAN configuration written to system log"); +#endif /* RETURN_IN_BUFFER */ + + return QDF_STATUS_SUCCESS; +} + +/** struct tCfgIniEntry - ini configuration entry + * + * @name: name of the entry + * @value: value of the entry + */ +typedef struct { + char *name; + char *value; +} tCfgIniEntry; + +/** + * find_cfg_item() - find the configuration item + * @iniTable: pointer to configuration table + * @entries: number fo the configuration entries + * @name: the interested configuration to find + * @value: the value to read back + * + * Return: QDF_STATUS_SUCCESS if the interested configuration is found, + * otherwise QDF_STATUS_E_FAILURE + */ +static QDF_STATUS find_cfg_item(tCfgIniEntry *iniTable, unsigned long entries, + char *name, char **value) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + unsigned long i; + + for (i = 0; i < entries; i++) { + if (strcmp(iniTable[i].name, name) == 0) { + *value = iniTable[i].value; + hdd_info("Found %s entry for Name=[%s] Value=[%s] ", + WLAN_INI_FILE, name, *value); + return QDF_STATUS_SUCCESS; + } + } + + return status; +} + +/** + * parse_hex_digit() - conversion to hex value + * @c: the character to convert + * + * Return: the hex value, otherwise 0 + */ +static int parse_hex_digit(char c) +{ + if (c >= '0' && c <= '9') + return c - '0'; + if (c >= 'a' && c <= 'f') + return c - 'a' + 10; + if (c >= 'A' && c <= 'F') + return c - 'A' + 10; + + return 0; +} + +/** + * update_mac_from_string() - convert string to 6 bytes mac address + * @pHddCtx: the pointer to hdd context + * @macTable: the macTable to carry the conversion + * @num: number of the interface + * + * 00AA00BB00CC -> 0x00 0xAA 0x00 0xBB 0x00 0xCC + * + * Return: None + */ +static void update_mac_from_string(hdd_context_t *pHddCtx, + tCfgIniEntry *macTable, int num) +{ + int i = 0, j = 0, res = 0; + char *candidate = NULL; + struct qdf_mac_addr macaddr[QDF_MAX_CONCURRENCY_PERSONA]; + + memset(macaddr, 0, sizeof(macaddr)); + + for (i = 0; i < num; i++) { + candidate = macTable[i].value; + for (j = 0; j < QDF_MAC_ADDR_SIZE; j++) { + res = + hex2bin(&macaddr[i].bytes[j], &candidate[(j << 1)], + 1); + if (res < 0) + break; + } + if (res == 0 && !qdf_is_macaddr_zero(&macaddr[i])) { + qdf_mem_copy((uint8_t *) &pHddCtx->config-> + intfMacAddr[i].bytes[0], + (uint8_t *) &macaddr[i].bytes[0], + QDF_MAC_ADDR_SIZE); + } + } +} + +/** + * hdd_apply_cfg_ini() - apply the ini configuration file + * @pHddCtx: the pointer to hdd context + * @iniTable: pointer to configuration table + * @entries: number fo the configuration entries + * It overwrites the MAC address if config file exist. + * + * Return: QDF_STATUS_SUCCESS if the ini configuration file is correctly parsed, + * otherwise QDF_STATUS_E_INVAL + */ +static QDF_STATUS hdd_apply_cfg_ini(hdd_context_t *pHddCtx, + tCfgIniEntry *iniTable, + unsigned long entries) +{ + QDF_STATUS match_status = QDF_STATUS_E_FAILURE; + QDF_STATUS ret_status = QDF_STATUS_SUCCESS; + unsigned int idx; + void *pField; + char *value_str = NULL; + unsigned long len_value_str; + char *candidate; + uint32_t value; + int32_t svalue; + void *pStructBase = pHddCtx->config; + REG_TABLE_ENTRY *pRegEntry = g_registry_table; + unsigned long cRegTableEntries = QDF_ARRAY_SIZE(g_registry_table); + uint32_t cbOutString; + int i; + int rv; + + if (MAX_CFG_INI_ITEMS < cRegTableEntries) { + hdd_err("MAX_CFG_INI_ITEMS too small, must be at least %ld", + cRegTableEntries); + WARN_ON(1); + } + + for (idx = 0; idx < cRegTableEntries; idx++, pRegEntry++) { + /* Calculate the address of the destination field in the structure. */ + pField = ((uint8_t *) pStructBase) + pRegEntry->VarOffset; + + match_status = + find_cfg_item(iniTable, entries, pRegEntry->RegName, + &value_str); + + if ((match_status != QDF_STATUS_SUCCESS) + && (pRegEntry->Flags & VAR_FLAGS_REQUIRED)) { + /* If we could not read the cfg item and it is required, this is an error. */ + hdd_err("Failed to read required config parameter %s", pRegEntry->RegName); + ret_status = QDF_STATUS_E_FAILURE; + break; + } + + if ((WLAN_PARAM_Integer == pRegEntry->RegType) || + (WLAN_PARAM_HexInteger == pRegEntry->RegType)) { + /* If successfully read from the registry, use the value read. + * If not, use the default value. + */ + if (match_status == QDF_STATUS_SUCCESS + && (WLAN_PARAM_Integer == pRegEntry->RegType)) { + rv = kstrtou32(value_str, 10, &value); + if (rv < 0) { + hdd_err("Reg Parameter %s invalid. Enforcing default", pRegEntry->RegName); + value = pRegEntry->VarDefault; + } + } else if (match_status == QDF_STATUS_SUCCESS + && (WLAN_PARAM_HexInteger == + pRegEntry->RegType)) { + rv = kstrtou32(value_str, 16, &value); + if (rv < 0) { + hdd_err("Reg paramter %s invalid. Enforcing default", pRegEntry->RegName); + value = pRegEntry->VarDefault; + } + } else { + value = pRegEntry->VarDefault; + } + + /* If this parameter needs range checking, do it here. */ + if (pRegEntry->Flags & VAR_FLAGS_RANGE_CHECK) { + if (value > pRegEntry->VarMax) { + hdd_err("Reg Parameter %s > allowed Maximum [%u > %lu]. Enforcing Maximum", pRegEntry->RegName, + value, pRegEntry->VarMax); + value = pRegEntry->VarMax; + } + + if (value < pRegEntry->VarMin) { + hdd_err("Reg Parameter %s < allowed Minimum [%u < %lu]. Enforcing Minimum", pRegEntry->RegName, + value, pRegEntry->VarMin); + value = pRegEntry->VarMin; + } + } + /* If this parameter needs range checking, do it here. */ + else if (pRegEntry-> + Flags & VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT) { + if (value > pRegEntry->VarMax) { + hdd_err("Reg Parameter %s > allowed Maximum [%u > %lu]. Enforcing Default= %lu", pRegEntry->RegName, + value, pRegEntry->VarMax, + pRegEntry->VarDefault); + value = pRegEntry->VarDefault; + } + + if (value < pRegEntry->VarMin) { + hdd_err("Reg Parameter %s < allowed Minimum [%u < %lu]. Enforcing Default= %lu", pRegEntry->RegName, + value, pRegEntry->VarMin, + pRegEntry->VarDefault); + value = pRegEntry->VarDefault; + } + } + /* Move the variable into the output field. */ + memcpy(pField, &value, pRegEntry->VarSize); + } else if (WLAN_PARAM_SignedInteger == pRegEntry->RegType) { + /* If successfully read from the registry, use the value read. + * If not, use the default value. + */ + if (QDF_STATUS_SUCCESS == match_status) { + rv = kstrtos32(value_str, 10, &svalue); + if (rv < 0) { + hdd_warn("Reg Parameter %s invalid. Enforcing Default", pRegEntry->RegName); + svalue = + (int32_t) pRegEntry->VarDefault; + } + } else { + svalue = (int32_t) pRegEntry->VarDefault; + } + + /* If this parameter needs range checking, do it here. */ + if (pRegEntry->Flags & VAR_FLAGS_RANGE_CHECK) { + if (svalue > (int32_t) pRegEntry->VarMax) { + hdd_err("Reg Parameter %s > allowed Maximum " + "[%d > %d]. Enforcing Maximum", pRegEntry->RegName, + svalue, (int)pRegEntry->VarMax); + svalue = (int32_t) pRegEntry->VarMax; + } + + if (svalue < (int32_t) pRegEntry->VarMin) { + hdd_err("Reg Parameter %s < allowed Minimum " + "[%d < %d]. Enforcing Minimum", pRegEntry->RegName, + svalue, (int)pRegEntry->VarMin); + svalue = (int32_t) pRegEntry->VarMin; + } + } + /* If this parameter needs range checking, do it here. */ + else if (pRegEntry-> + Flags & VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT) { + if (svalue > (int32_t) pRegEntry->VarMax) { + hdd_err("Reg Parameter %s > allowed Maximum " + "[%d > %d]. Enforcing Default= %d", pRegEntry->RegName, + svalue, (int)pRegEntry->VarMax, + (int)pRegEntry->VarDefault); + svalue = + (int32_t) pRegEntry->VarDefault; + } + + if (svalue < (int32_t) pRegEntry->VarMin) { + hdd_err("Reg Parameter %s < allowed Minimum " + "[%d < %d]. Enforcing Default= %d", pRegEntry->RegName, + svalue, (int)pRegEntry->VarMin, + (int)pRegEntry->VarDefault); + svalue = pRegEntry->VarDefault; + } + } + /* Move the variable into the output field. */ + memcpy(pField, &svalue, pRegEntry->VarSize); + } + /* Handle string parameters */ + else if (WLAN_PARAM_String == pRegEntry->RegType) { +#ifdef WLAN_CFG_DEBUG + hdd_info("RegName = %s, VarOffset %u VarSize %u VarDefault %s", + pRegEntry->RegName, pRegEntry->VarOffset, + pRegEntry->VarSize, + (char *)pRegEntry->VarDefault); +#endif + + if (match_status == QDF_STATUS_SUCCESS) { + len_value_str = strlen(value_str); + + if (len_value_str > (pRegEntry->VarSize - 1)) { + hdd_err("Invalid Value=[%s] specified for Name=[%s] in %s", value_str, + pRegEntry->RegName, + WLAN_INI_FILE); + cbOutString = + util_min(strlen + ((char *)pRegEntry-> + VarDefault), + pRegEntry->VarSize - 1); + memcpy(pField, + (void *)(pRegEntry->VarDefault), + cbOutString); + ((uint8_t *) pField)[cbOutString] = + '\0'; + } else { + memcpy(pField, (void *)(value_str), + len_value_str); + ((uint8_t *) pField)[len_value_str] = + '\0'; + } + } else { + /* Failed to read the string parameter from the registry. Use the default. */ + cbOutString = + util_min(strlen((char *)pRegEntry->VarDefault), + pRegEntry->VarSize - 1); + memcpy(pField, (void *)(pRegEntry->VarDefault), + cbOutString); + ((uint8_t *) pField)[cbOutString] = '\0'; + } + } else if (WLAN_PARAM_MacAddr == pRegEntry->RegType) { + if (pRegEntry->VarSize != QDF_MAC_ADDR_SIZE) { + hdd_err("Invalid VarSize %u for Name=[%s]", pRegEntry->VarSize, + pRegEntry->RegName); + continue; + } + candidate = (char *)pRegEntry->VarDefault; + if (match_status == QDF_STATUS_SUCCESS) { + len_value_str = strlen(value_str); + if (len_value_str != (QDF_MAC_ADDR_SIZE * 2)) { + hdd_err("Invalid MAC addr [%s] specified for Name=[%s] in %s", value_str, + pRegEntry->RegName, + WLAN_INI_FILE); + } else + candidate = value_str; + } + /* parse the string and store it in the byte array */ + for (i = 0; i < QDF_MAC_ADDR_SIZE; i++) { + ((char *)pField)[i] = + (char)(parse_hex_digit(candidate[i * 2]) * + 16 + + parse_hex_digit(candidate[i * 2 + 1])); + } + } else { + hdd_err("Unknown param type for name[%s] in registry table", pRegEntry->RegName); + } + + /* did we successfully parse a cfg item for this parameter? */ + if ((match_status == QDF_STATUS_SUCCESS) && + (idx < MAX_CFG_INI_ITEMS)) { + set_bit(idx, (void *)&pHddCtx->config->bExplicitCfg); + } + } + + return ret_status; +} + +/** + * hdd_execute_config_command() - executes an arbitrary configuration command + * @reg_table: the pointer to configuration table + * @tableSize: the size of the configuration table + * @ini_struct: pointer to the hdd config knob + * @pHddCtx: the pointer to hdd context + * @command: the command to run + * + * Return: QDF_STATUS_SUCCESS if the command is found and able to execute, + * otherwise the appropriate QDF_STATUS will be returned + */ +static QDF_STATUS hdd_execute_config_command(REG_TABLE_ENTRY *reg_table, + unsigned long tableSize, + uint8_t *ini_struct, + hdd_context_t *pHddCtx, + char *command) +{ + REG_TABLE_ENTRY *pRegEntry; + char *clone; + char *pCmd; + void *pField; + char *name; + char *value_str; + uint32_t value; + int32_t svalue; + size_t len_value_str; + unsigned int idx; + unsigned int i; + QDF_STATUS vstatus; + int rv; + + /* assume failure until proven otherwise */ + vstatus = QDF_STATUS_E_FAILURE; + + /* clone the command so that we can manipulate it */ + clone = kstrdup(command, GFP_ATOMIC); + if (NULL == clone) { + hdd_err("memory allocation failure, unable to process [%s]", command); + return vstatus; + } + /* 'clone' will point to the beginning of the string so it can be freed + * 'pCmd' will be used to walk/parse the command + */ + pCmd = clone; + + /* get rid of leading/trailing whitespace */ + pCmd = i_trim(pCmd); + if ('\0' == *pCmd) { + /* only whitespace */ + hdd_err("invalid command, only whitespace:[%s]", command); + goto done; + } + /* parse the = */ + name = pCmd; + while (('=' != *pCmd) && ('\0' != *pCmd)) { + pCmd++; + } + if ('\0' == *pCmd) { + /* did not find '=' */ + hdd_err("invalid command, no '=':[%s]", command); + goto done; + } + /* replace '=' with NUL to terminate the */ + *pCmd++ = '\0'; + name = i_trim(name); + if ('\0' == *name) { + /* did not find a name */ + hdd_err("invalid command, no :[%s]", command); + goto done; + } + + value_str = i_trim(pCmd); + if ('\0' == *value_str) { + /* did not find a value */ + hdd_err("invalid command, no :[%s]", command); + goto done; + } + /* lookup the configuration item */ + for (idx = 0; idx < tableSize; idx++) { + if (0 == strcmp(name, reg_table[idx].RegName)) { + /* found a match */ + break; + } + } + if (tableSize == idx) { + /* did not match the name */ + hdd_err("invalid command, unknown configuration item:[%s]", command); + goto done; + } + + pRegEntry = ®_table[idx]; + if (!(pRegEntry->Flags & VAR_FLAGS_DYNAMIC_CFG)) { + /* does not support dynamic configuration */ + hdd_err("Global_Registry_Table.%s does not support " + "dynamic configuration", name); + vstatus = QDF_STATUS_E_PERM; + goto done; + } + + pField = ini_struct + pRegEntry->VarOffset; + + switch (pRegEntry->RegType) { + case WLAN_PARAM_Integer: + rv = kstrtou32(value_str, 10, &value); + if (rv < 0) + goto done; + if (value < pRegEntry->VarMin) { + /* out of range */ + hdd_err("invalid command, value %u < min value %lu", value, pRegEntry->VarMin); + goto done; + } + if (value > pRegEntry->VarMax) { + /* out of range */ + hdd_err("invalid command, value %u > max value %lu", value, pRegEntry->VarMax); + goto done; + } + memcpy(pField, &value, pRegEntry->VarSize); + break; + + case WLAN_PARAM_HexInteger: + rv = kstrtou32(value_str, 16, &value); + if (rv < 0) + goto done; + if (value < pRegEntry->VarMin) { + /* out of range */ + hdd_err("invalid command, value %x < min value %lx", value, pRegEntry->VarMin); + goto done; + } + if (value > pRegEntry->VarMax) { + /* out of range */ + hdd_err("invalid command, value %x > max value %lx", value, pRegEntry->VarMax); + goto done; + } + memcpy(pField, &value, pRegEntry->VarSize); + break; + + case WLAN_PARAM_SignedInteger: + rv = kstrtos32(value_str, 10, &svalue); + if (rv < 0) + goto done; + if (svalue < (int32_t) pRegEntry->VarMin) { + /* out of range */ + hdd_err("invalid command, value %d < min value %d", svalue, (int)pRegEntry->VarMin); + goto done; + } + if (svalue > (int32_t) pRegEntry->VarMax) { + /* out of range */ + hdd_err("invalid command, value %d > max value %d", svalue, (int)pRegEntry->VarMax); + goto done; + } + memcpy(pField, &svalue, pRegEntry->VarSize); + break; + + case WLAN_PARAM_String: + len_value_str = strlen(value_str); + if (len_value_str > (pRegEntry->VarSize - 1)) { + /* too big */ + hdd_err("invalid command, string [%s] length " + "%zu exceeds maximum length %u", value_str, + len_value_str, (pRegEntry->VarSize - 1)); + goto done; + } + /* copy string plus NUL */ + memcpy(pField, value_str, (len_value_str + 1)); + break; + + case WLAN_PARAM_MacAddr: + len_value_str = strlen(value_str); + if (len_value_str != (QDF_MAC_ADDR_SIZE * 2)) { + /* out of range */ + hdd_err("invalid command, MAC address [%s] length " + "%zu is not expected length %u", value_str, + len_value_str, (QDF_MAC_ADDR_SIZE * 2)); + goto done; + } + /* parse the string and store it in the byte array */ + for (i = 0; i < QDF_MAC_ADDR_SIZE; i++) { + ((char *)pField)[i] = (char) + ((parse_hex_digit(value_str[(i * 2)]) * 16) + + parse_hex_digit(value_str[(i * 2) + 1])); + } + break; + + default: + goto done; + } + + /* if we get here, we had a successful modification */ + vstatus = QDF_STATUS_SUCCESS; + + /* config table has been modified, is there a notifier? */ + if (NULL != pRegEntry->pfnDynamicnotify) { + (pRegEntry->pfnDynamicnotify)(pHddCtx, pRegEntry->notifyId); + } + /* note that this item was explicitly configured */ + if (idx < MAX_CFG_INI_ITEMS) { + set_bit(idx, (void *)&pHddCtx->config->bExplicitCfg); + } +done: + kfree(clone); + return vstatus; +} + +/** + * hdd_set_power_save_offload_config() - set power save offload configuration + * @pHddCtx: the pointer to hdd context + * + * Return: none + */ +static void hdd_set_power_save_offload_config(hdd_context_t *pHddCtx) +{ + struct hdd_config *pConfig = pHddCtx->config; + uint32_t listenInterval = 0; + + if (strcmp(pConfig->PowerUsageControl, "Min") == 0) { + listenInterval = pConfig->nBmpsMinListenInterval; + } else if (strcmp(pConfig->PowerUsageControl, "Max") == 0) { + listenInterval = pConfig->nBmpsMaxListenInterval; + } else if (strcmp(pConfig->PowerUsageControl, "Mod") == 0) { + listenInterval = pConfig->nBmpsModListenInterval; + } + + /* + * Based on Mode Set the LI + * Otherwise default LI value of 1 will + * be taken + */ + if (listenInterval) { + /* + * setcfg for listenInterval. + * Make sure CFG is updated because PE reads this + * from CFG at the time of assoc or reassoc + */ + sme_cfg_set_int(pHddCtx->hHal, WNI_CFG_LISTEN_INTERVAL, + listenInterval); + } + +} + +#ifdef FEATURE_RUNTIME_PM +static void hdd_cfg_print_runtime_pm(hdd_context_t *hdd_ctx) +{ + hdd_info("Name = [gRuntimePM] Value = [%u] ", + hdd_ctx->config->runtime_pm); + + hdd_info("Name = [gRuntimePMDelay] Value = [%u] ", + hdd_ctx->config->runtime_pm_delay); +} +#else +static void hdd_cfg_print_runtime_pm(hdd_context_t *hdd_ctx) +{ +} +#endif + +/** + * hdd_per_roam_print_ini_config()- Print PER roam specific INI configuration + * @hdd_ctx: handle to hdd context + * + * Return: None + */ +static void hdd_per_roam_print_ini_config(hdd_context_t *hdd_ctx) +{ + hdd_info("Name = [%s] Value = [%u]", + CFG_PER_ROAM_ENABLE_NAME, + hdd_ctx->config->is_per_roam_enabled); + hdd_info("Name = [%s] Value = [%u]", + CFG_PER_ROAM_CONFIG_HIGH_RATE_TH_NAME, + hdd_ctx->config->per_roam_high_rate_threshold); + hdd_info("Name = [%s] Value = [%u]", + CFG_PER_ROAM_CONFIG_LOW_RATE_TH_NAME, + hdd_ctx->config->per_roam_low_rate_threshold); + hdd_info("Name = [%s] Value = [%u]", + CFG_PER_ROAM_CONFIG_RATE_TH_PERCENT_NAME, + hdd_ctx->config->per_roam_th_percent); + hdd_info("Name = [%s] Value = [%u]", + CFG_PER_ROAM_REST_TIME_NAME, + hdd_ctx->config->per_roam_rest_time); + hdd_info("Name = [%s] Value = [%u]", + CFG_PER_ROAM_MONITOR_TIME, + hdd_ctx->config->per_roam_mon_time); + hdd_debug("Name = [%s] Value = [%u]", + CFG_PER_ROAM_MIN_CANDIDATE_RSSI, + hdd_ctx->config->min_candidate_rssi); +} + +/** + * hdd_cfg_print() - print the hdd configuration + * @iniTable: pointer to hdd context + * + * Return: None + */ +void hdd_cfg_print(hdd_context_t *pHddCtx) +{ + int i; + + hdd_info("*********Config values in HDD Adapter*******"); + hdd_info("Name = [RTSThreshold] Value = %u", + pHddCtx->config->RTSThreshold); + hdd_info("Name = [OperatingChannel] Value = [%u]", + pHddCtx->config->OperatingChannel); + hdd_info("Name = [PowerUsageControl] Value = [%s]", + pHddCtx->config->PowerUsageControl); + hdd_info("Name = [fIsImpsEnabled] Value = [%u]", + pHddCtx->config->fIsImpsEnabled); + hdd_info("Name = [nVccRssiTrigger] Value = [%u]", + pHddCtx->config->nVccRssiTrigger); + hdd_info("Name = [gIbssBssid] Value =[" MAC_ADDRESS_STR "]", + MAC_ADDR_ARRAY(pHddCtx->config->IbssBssid.bytes)); + + for (i = 0; i < QDF_MAX_CONCURRENCY_PERSONA; i++) { + hdd_info("Name = [Intf%dMacAddress] Value =[" MAC_ADDRESS_STR "]", + i, MAC_ADDR_ARRAY(pHddCtx->config->intfMacAddr[i].bytes)); + } + + hdd_info("Name = [gApEnableUapsd] value = [%u]", + pHddCtx->config->apUapsdEnabled); + + hdd_info("Name = [gEnableApProt] value = [%u]", + pHddCtx->config->apProtEnabled); + hdd_info("Name = [gAPAutoShutOff] Value = [%u]", + pHddCtx->config->nAPAutoShutOff); +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH + hdd_info("Name = [gWlanMccToSccSwitchMode] Value = [%u]", + pHddCtx->config->WlanMccToSccSwitchMode); +#endif +#ifdef FEATURE_WLAN_AUTO_SHUTDOWN + hdd_info("Name = [gWlanAutoShutdown] Value = [%u]", + pHddCtx->config->WlanAutoShutdown); +#endif + hdd_info("Name = [gApProtection] value = [%u]", + pHddCtx->config->apProtection); + hdd_info("Name = [gEnableApOBSSProt] value = [%u]", + pHddCtx->config->apOBSSProtEnabled); + hdd_info("Name = [%s] value = [%u]", CFG_FORCE_SAP_ACS, + pHddCtx->config->force_sap_acs); + hdd_info("Name = [%s] value = [%u]", CFG_FORCE_SAP_ACS_START_CH, + pHddCtx->config->force_sap_acs_st_ch); + hdd_info("Name = [%s] value = [%u]", CFG_FORCE_SAP_ACS_END_CH, + pHddCtx->config->force_sap_acs_end_ch); +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE + hdd_info("Name = [sap_channel_avoidance] value = [%u]", + pHddCtx->config->sap_channel_avoidance); +#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ + hdd_info("Name = [%s] value = [%u]", CFG_SAP_P2P_11AC_OVERRIDE_NAME, + pHddCtx->config->sap_p2p_11ac_override); + hdd_info("Name = [ChannelBondingMode] Value = [%u]", + pHddCtx->config->nChannelBondingMode24GHz); + hdd_info("Name = [ChannelBondingMode] Value = [%u]", + pHddCtx->config->nChannelBondingMode5GHz); + hdd_info("Name = [dot11Mode] Value = [%u]", + pHddCtx->config->dot11Mode); + hdd_info("Name = [WmmMode] Value = [%u] ", pHddCtx->config->WmmMode); + hdd_info("Name = [UapsdMask] Value = [0x%x] ", + pHddCtx->config->UapsdMask); + hdd_info("Name = [ImplicitQosIsEnabled] Value = [%u]", + (int)pHddCtx->config->bImplicitQosEnabled); + + hdd_info("Name = [InfraUapsdVoSrvIntv] Value = [%u] ", + pHddCtx->config->InfraUapsdVoSrvIntv); + hdd_info("Name = [InfraUapsdVoSuspIntv] Value = [%u] ", + pHddCtx->config->InfraUapsdVoSuspIntv); + + hdd_info("Name = [InfraUapsdViSrvIntv] Value = [%u] ", + pHddCtx->config->InfraUapsdViSrvIntv); + hdd_info("Name = [InfraUapsdViSuspIntv] Value = [%u] ", + pHddCtx->config->InfraUapsdViSuspIntv); + + hdd_info("Name = [InfraUapsdBeSrvIntv] Value = [%u] ", + pHddCtx->config->InfraUapsdBeSrvIntv); + hdd_info("Name = [InfraUapsdBeSuspIntv] Value = [%u] ", + pHddCtx->config->InfraUapsdBeSuspIntv); + + hdd_info("Name = [InfraUapsdBkSrvIntv] Value = [%u] ", + pHddCtx->config->InfraUapsdBkSrvIntv); + hdd_info("Name = [InfraUapsdBkSuspIntv] Value = [%u] ", + pHddCtx->config->InfraUapsdBkSuspIntv); +#ifdef FEATURE_WLAN_ESE + hdd_info("Name = [InfraInactivityInterval] Value = [%u] ", + pHddCtx->config->InfraInactivityInterval); + hdd_info("Name = [EseEnabled] Value = [%u] ", + pHddCtx->config->isEseIniFeatureEnabled); + hdd_info("Name = [FastTransitionEnabled] Value = [%u] ", + pHddCtx->config->isFastTransitionEnabled); + hdd_info("Name = [gTxPowerCap] Value = [%u] dBm ", + pHddCtx->config->nTxPowerCap); +#endif + hdd_info("Name = [gAllowTPCfromAP] Value = [%u] ", + pHddCtx->config->allow_tpc_from_ap); + hdd_info("Name = [FastRoamEnabled] Value = [%u] ", + pHddCtx->config->isFastRoamIniFeatureEnabled); + hdd_info("Name = [MAWCEnabled] Value = [%u] ", + pHddCtx->config->MAWCEnabled); + hdd_info("Name = [RoamRssiDiff] Value = [%u] ", + pHddCtx->config->RoamRssiDiff); + hdd_info("Name = [isWESModeEnabled] Value = [%u] ", + pHddCtx->config->isWESModeEnabled); + hdd_info("Name = [pmkidModes] Value = [0x%x] ", + pHddCtx->config->pmkid_modes); +#ifdef FEATURE_WLAN_SCAN_PNO + hdd_info("Name = [configPNOScanSupport] Value = [%u] ", + pHddCtx->config->configPNOScanSupport); + hdd_info("Name = [configPNOScanTimerRepeatValue] Value = [%u] ", + pHddCtx->config->configPNOScanTimerRepeatValue); + hdd_info("Name = [gPNOSlowScanMultiplier] Value = [%u] ", + pHddCtx->config->pno_slow_scan_multiplier); +#endif +#ifdef FEATURE_WLAN_TDLS + hdd_info("Name = [fEnableTDLSSupport] Value = [%u] ", + pHddCtx->config->fEnableTDLSSupport); + hdd_info("Name = [fEnableTDLSImplicitTrigger] Value = [%u] ", + pHddCtx->config->fEnableTDLSImplicitTrigger); + hdd_info("Name = [fTDLSExternalControl] Value = [%u] ", + pHddCtx->config->fTDLSExternalControl); + hdd_info("Name = [fTDLSUapsdMask] Value = [%u] ", + pHddCtx->config->fTDLSUapsdMask); + hdd_info("Name = [fEnableTDLSBufferSta] Value = [%u] ", + pHddCtx->config->fEnableTDLSBufferSta); + hdd_info("Name = [fEnableTDLSWmmMode] Value = [%u] ", + pHddCtx->config->fEnableTDLSWmmMode); + hdd_info("Name = [enable_tdls_scan] Value = [%u]", + pHddCtx->config->enable_tdls_scan); +#endif + hdd_info("Name = [InfraDirAcVo] Value = [%u] ", + pHddCtx->config->InfraDirAcVo); + hdd_info("Name = [InfraNomMsduSizeAcVo] Value = [0x%x] ", + pHddCtx->config->InfraNomMsduSizeAcVo); + hdd_info("Name = [InfraMeanDataRateAcVo] Value = [0x%x] ", + pHddCtx->config->InfraMeanDataRateAcVo); + hdd_info("Name = [InfraMinPhyRateAcVo] Value = [0x%x] ", + pHddCtx->config->InfraMinPhyRateAcVo); + hdd_info("Name = [InfraSbaAcVo] Value = [0x%x] ", + pHddCtx->config->InfraSbaAcVo); + + hdd_info("Name = [InfraDirAcVi] Value = [%u] ", + pHddCtx->config->InfraDirAcVi); + hdd_info("Name = [InfraNomMsduSizeAcVi] Value = [0x%x] ", + pHddCtx->config->InfraNomMsduSizeAcVi); + hdd_info("Name = [InfraMeanDataRateAcVi] Value = [0x%x] ", + pHddCtx->config->InfraMeanDataRateAcVi); + hdd_info("Name = [InfraMinPhyRateAcVi] Value = [0x%x] ", + pHddCtx->config->InfraMinPhyRateAcVi); + hdd_info("Name = [InfraSbaAcVi] Value = [0x%x] ", + pHddCtx->config->InfraSbaAcVi); + + hdd_info("Name = [InfraDirAcBe] Value = [%u] ", + pHddCtx->config->InfraDirAcBe); + hdd_info("Name = [InfraNomMsduSizeAcBe] Value = [0x%x] ", + pHddCtx->config->InfraNomMsduSizeAcBe); + hdd_info("Name = [InfraMeanDataRateAcBe] Value = [0x%x] ", + pHddCtx->config->InfraMeanDataRateAcBe); + hdd_info("Name = [InfraMinPhyRateAcBe] Value = [0x%x] ", + pHddCtx->config->InfraMinPhyRateAcBe); + hdd_info("Name = [InfraSbaAcBe] Value = [0x%x] ", + pHddCtx->config->InfraSbaAcBe); + + hdd_info("Name = [InfraDirAcBk] Value = [%u] ", + pHddCtx->config->InfraDirAcBk); + hdd_info("Name = [InfraNomMsduSizeAcBk] Value = [0x%x] ", + pHddCtx->config->InfraNomMsduSizeAcBk); + hdd_info("Name = [InfraMeanDataRateAcBk] Value = [0x%x] ", + pHddCtx->config->InfraMeanDataRateAcBk); + hdd_info("Name = [InfraMinPhyRateAcBk] Value = [0x%x] ", + pHddCtx->config->InfraMinPhyRateAcBk); + hdd_info("Name = [InfraSbaAcBk] Value = [0x%x] ", + pHddCtx->config->InfraSbaAcBk); + + hdd_info("Name = [DelayedTriggerFrmInt] Value = [%u] ", + pHddCtx->config->DelayedTriggerFrmInt); + hdd_info("Name = [mcastBcastFilterSetting] Value = [%u] ", + pHddCtx->config->mcastBcastFilterSetting); + hdd_info("Name = [fhostArpOffload] Value = [%u] ", + pHddCtx->config->fhostArpOffload); + hdd_info("Name = [ssdp] Value = [%u] ", pHddCtx->config->ssdp); + hdd_cfg_print_runtime_pm(pHddCtx); +#ifdef FEATURE_WLAN_RA_FILTERING + hdd_info("Name = [RArateLimitInterval] Value = [%u] ", + pHddCtx->config->RArateLimitInterval); + hdd_info("Name = [IsRArateLimitEnabled] Value = [%u] ", + pHddCtx->config->IsRArateLimitEnabled); +#endif + hdd_info("Name = [fFTResourceReqSupported] Value = [%u] ", + pHddCtx->config->fFTResourceReqSupported); + + hdd_info("Name = [nNeighborLookupRssiThreshold] Value = [%u] ", + pHddCtx->config->nNeighborLookupRssiThreshold); + hdd_info("Name = [delay_before_vdev_stop] Value = [%u] ", + pHddCtx->config->delay_before_vdev_stop); + hdd_info("Name = [nOpportunisticThresholdDiff] Value = [%u] ", + pHddCtx->config->nOpportunisticThresholdDiff); + hdd_info("Name = [nRoamRescanRssiDiff] Value = [%u] ", + pHddCtx->config->nRoamRescanRssiDiff); + hdd_info("Name = [nNeighborScanMinChanTime] Value = [%u] ", + pHddCtx->config->nNeighborScanMinChanTime); + hdd_info("Name = [nNeighborScanMaxChanTime] Value = [%u] ", + pHddCtx->config->nNeighborScanMaxChanTime); + hdd_info("Name = [nMaxNeighborRetries] Value = [%u] ", + pHddCtx->config->nMaxNeighborReqTries); + hdd_info("Name = [nNeighborScanPeriod] Value = [%u] ", + pHddCtx->config->nNeighborScanPeriod); + hdd_info("Name = [nNeighborScanResultsRefreshPeriod] Value = [%u] ", + pHddCtx->config->nNeighborResultsRefreshPeriod); + hdd_info("Name = [nEmptyScanRefreshPeriod] Value = [%u] ", + pHddCtx->config->nEmptyScanRefreshPeriod); + hdd_info("Name = [nRoamBmissFirstBcnt] Value = [%u] ", + pHddCtx->config->nRoamBmissFirstBcnt); + hdd_info("Name = [nRoamBmissFinalBcnt] Value = [%u] ", + pHddCtx->config->nRoamBmissFinalBcnt); + hdd_info("Name = [nRoamBeaconRssiWeight] Value = [%u] ", + pHddCtx->config->nRoamBeaconRssiWeight); + hdd_info("Name = [allowDFSChannelRoam] Value = [%u] ", + pHddCtx->config->allowDFSChannelRoam); + hdd_info("Name = [nhi_rssi_scan_max_count] Value = [%u] ", + pHddCtx->config->nhi_rssi_scan_max_count); + hdd_info("Name = [nhi_rssi_scan_rssi_delta] Value = [%u] ", + pHddCtx->config->nhi_rssi_scan_rssi_delta); + hdd_info("Name = [nhi_rssi_scan_delay] Value = [%u] ", + pHddCtx->config->nhi_rssi_scan_delay); + hdd_info("Name = [nhi_rssi_scan_rssi_ub] Value = [%u] ", + pHddCtx->config->nhi_rssi_scan_rssi_ub); + hdd_info("Name = [burstSizeDefinition] Value = [0x%x] ", + pHddCtx->config->burstSizeDefinition); + hdd_info("Name = [tsInfoAckPolicy] Value = [0x%x] ", + pHddCtx->config->tsInfoAckPolicy); + hdd_info("Name = [rfSettlingTimeUs] Value = [%u] ", + pHddCtx->config->rfSettlingTimeUs); + hdd_info("Name = [bSingleTidRc] Value = [%u] ", + pHddCtx->config->bSingleTidRc); + hdd_info("Name = [gDynamicPSPollvalue] Value = [%u] ", + pHddCtx->config->dynamicPsPollValue); + hdd_info("Name = [gAddTSWhenACMIsOff] Value = [%u] ", + pHddCtx->config->AddTSWhenACMIsOff); + hdd_info("Name = [gValidateScanList] Value = [%u] ", + pHddCtx->config->fValidateScanList); + + hdd_info("Name = [gStaKeepAlivePeriod] Value = [%u] ", + pHddCtx->config->infraStaKeepAlivePeriod); + hdd_info("Name = [gApDataAvailPollInterVal] Value = [%u] ", + pHddCtx->config->apDataAvailPollPeriodInMs); + hdd_info("Name = [BandCapability] Value = [%u] ", + pHddCtx->config->nBandCapability); + hdd_info("Name = [teleBcnWakeupEnable] Value = [%u] ", + pHddCtx->config->teleBcnWakeupEn); + hdd_info("Name = [transListenInterval] Value = [%u] ", + pHddCtx->config->nTeleBcnTransListenInterval); + hdd_info("Name = [transLiNumIdleBeacons] Value = [%u] ", + pHddCtx->config->nTeleBcnTransLiNumIdleBeacons); + hdd_info("Name = [maxListenInterval] Value = [%u] ", + pHddCtx->config->nTeleBcnMaxListenInterval); + hdd_info("Name = [maxLiNumIdleBeacons] Value = [%u] ", + pHddCtx->config->nTeleBcnMaxLiNumIdleBeacons); + hdd_info("Name = [gEnableBypass11d] Value = [%u] ", + pHddCtx->config->enableBypass11d); + hdd_info("Name = [gEnableDFSChnlScan] Value = [%u] ", + pHddCtx->config->enableDFSChnlScan); + hdd_info("Name = [gEnableDFSPnoChnlScan] Value = [%u] ", + pHddCtx->config->enable_dfs_pno_chnl_scan); + hdd_info("Name = [gReportMaxLinkSpeed] Value = [%u] ", + pHddCtx->config->reportMaxLinkSpeed); + hdd_info("Name = [thermalMitigationEnable] Value = [%u] ", + pHddCtx->config->thermalMitigationEnable); + hdd_info("Name = [gVhtChannelWidth] value = [%u]", + pHddCtx->config->vhtChannelWidth); + hdd_info("Name = [enableFirstScan2GOnly] Value = [%u] ", + pHddCtx->config->enableFirstScan2GOnly); + hdd_info("Name = [skipDfsChnlInP2pSearch] Value = [%u] ", + pHddCtx->config->skipDfsChnlInP2pSearch); + hdd_info("Name = [ignoreDynamicDtimInP2pMode] Value = [%u] ", + pHddCtx->config->ignoreDynamicDtimInP2pMode); + hdd_info("Name = [enableRxSTBC] Value = [%u] ", + pHddCtx->config->enableRxSTBC); + hdd_info("Name = [gEnableLpwrImgTransition] Value = [%u] ", + pHddCtx->config->enableLpwrImgTransition); + hdd_info("Name = [gEnableSSR] Value = [%u] ", + pHddCtx->config->enableSSR); + hdd_info("Name = [gEnableVhtFor24GHzBand] Value = [%u] ", + pHddCtx->config->enableVhtFor24GHzBand); + hdd_info("Name = [gEnableIbssHeartBeatOffload] Value = [%u] ", + pHddCtx->config->enableIbssHeartBeatOffload); + hdd_info("Name = [gAntennaDiversity] Value = [%u] ", + pHddCtx->config->antennaDiversity); + hdd_info("Name = [gGoLinkMonitorPeriod] Value = [%u]", + pHddCtx->config->goLinkMonitorPeriod); + hdd_info("Name = [gApLinkMonitorPeriod] Value = [%u]", + pHddCtx->config->apLinkMonitorPeriod); + hdd_info("Name = [gGoKeepAlivePeriod] Value = [%u]", + pHddCtx->config->goKeepAlivePeriod); + hdd_info("Name = [gApKeepAlivePeriod]Value = [%u]", + pHddCtx->config->apKeepAlivePeriod); + hdd_info("Name = [max_amsdu_num] Value = [%u] ", + pHddCtx->config->max_amsdu_num); + hdd_info("Name = [nSelect5GHzMargin] Value = [%u] ", + pHddCtx->config->nSelect5GHzMargin); + hdd_info("Name = [gCoalesingInIBSS] Value = [%u] ", + pHddCtx->config->isCoalesingInIBSSAllowed); + hdd_info("Name = [gIbssATIMWinSize] Value = [%u] ", + pHddCtx->config->ibssATIMWinSize); + hdd_info("Name = [gIbssIsPowerSaveAllowed] Value = [%u] ", + pHddCtx->config->isIbssPowerSaveAllowed); + hdd_info("Name = [gIbssIsPowerCollapseAllowed] Value = [%u] ", + pHddCtx->config->isIbssPowerCollapseAllowed); + hdd_info("Name = [gIbssAwakeOnTxRx] Value = [%u] ", + pHddCtx->config->isIbssAwakeOnTxRx); + hdd_info("Name = [gIbssInactivityTime] Value = [%u] ", + pHddCtx->config->ibssInactivityCount); + hdd_info("Name = [gIbssTxSpEndInactivityTime] Value = [%u] ", + pHddCtx->config->ibssTxSpEndInactivityTime); + hdd_info("Name = [gIbssPsWarmupTime] Value = [%u] ", + pHddCtx->config->ibssPsWarmupTime); + hdd_info("Name = [gIbssPs1RxChainInAtim] Value = [%u] ", + pHddCtx->config->ibssPs1RxChainInAtimEnable); + hdd_info("Name = [fDfsPhyerrFilterOffload] Value = [%u] ", + pHddCtx->config->fDfsPhyerrFilterOffload); + hdd_info("Name = [gIgnorePeerErpInfo] Value = [%u] ", + pHddCtx->config->ignore_peer_erp_info); +#ifdef IPA_OFFLOAD + hdd_info("Name = [gIPAConfig] Value = [0x%x] ", + pHddCtx->config->IpaConfig); + hdd_info("Name = [gIPADescSize] Value = [%u] ", + pHddCtx->config->IpaDescSize); + hdd_info("Name = [IpaHighBandwidthMbpsg] Value = [%u] ", + pHddCtx->config->IpaHighBandwidthMbps); + hdd_info("Name = [IpaMediumBandwidthMbps] Value = [%u] ", + pHddCtx->config->IpaMediumBandwidthMbps); + hdd_info("Name = [IpaLowBandwidthMbps] Value = [%u] ", + pHddCtx->config->IpaLowBandwidthMbps); +#endif + hdd_info("Name = [gEnableOverLapCh] Value = [%u] ", + pHddCtx->config->gEnableOverLapCh); + hdd_info("Name = [gMaxOffloadPeers] Value = [%u] ", + pHddCtx->config->apMaxOffloadPeers); + hdd_info("Name = [gMaxOffloadReorderBuffs] value = [%u] ", + pHddCtx->config->apMaxOffloadReorderBuffs); + hdd_info("Name = [gAllowDFSChannelRoam] Value = [%u] ", + pHddCtx->config->allowDFSChannelRoam); + hdd_info("Name = [gMaxConcurrentActiveSessions] Value = [%u] ", + pHddCtx->config->gMaxConcurrentActiveSessions); + +#ifdef MSM_PLATFORM + hdd_info("Name = [gBusBandwidthHighThreshold] Value = [%u] ", + pHddCtx->config->busBandwidthHighThreshold); + hdd_info("Name = [gBusBandwidthMediumThreshold] Value = [%u] ", + pHddCtx->config->busBandwidthMediumThreshold); + hdd_info("Name = [gBusBandwidthLowThreshold] Value = [%u] ", + pHddCtx->config->busBandwidthLowThreshold); + hdd_info("Name = [gbusBandwidthComputeInterval] Value = [%u] ", + pHddCtx->config->busBandwidthComputeInterval); + hdd_info("Name = [%s] Value = [%u] ", + CFG_ENABLE_TCP_ADV_WIN_SCALE, + pHddCtx->config->enable_tcp_adv_win_scale); + hdd_info("Name = [%s] Value = [%u] ", + CFG_ENABLE_TCP_DELACK, + pHddCtx->config->enable_tcp_delack); + hdd_info("Name = [gTcpDelAckThresholdHigh] Value = [%u] ", + pHddCtx->config->tcpDelackThresholdHigh); + hdd_info("Name = [gTcpDelAckThresholdLow] Value = [%u] ", + pHddCtx->config->tcpDelackThresholdLow); + hdd_info("Name = [%s] Value = [%u] ", + CFG_TCP_DELACK_TIMER_COUNT, + pHddCtx->config->tcp_delack_timer_count); + hdd_info("Name = [%s] Value = [%u] ", + CFG_TCP_TX_HIGH_TPUT_THRESHOLD_NAME, + pHddCtx->config->tcp_tx_high_tput_thres); + +#endif + + hdd_info("Name = [gIgnoreCAC] Value = [%u] ", + pHddCtx->config->ignoreCAC); + hdd_info("Name = [gSapPreferredChanLocation] Value = [%u] ", + pHddCtx->config->gSapPreferredChanLocation); + hdd_info("Name = [gDisableDfsJapanW53] Value = [%u] ", + pHddCtx->config->gDisableDfsJapanW53); +#ifdef FEATURE_GREEN_AP + hdd_info("Name = [gEnableGreenAp] Value = [%u] ", + pHddCtx->config->enableGreenAP); + hdd_info("Name = [gEenableEGAP] Value = [%u] ", + pHddCtx->config->enable_egap); + hdd_info("Name = [gEGAPInactTime] Value = [%u] ", + pHddCtx->config->egap_inact_time); + hdd_info("Name = [gEGAPWaitTime] Value = [%u] ", + pHddCtx->config->egap_wait_time); + hdd_info("Name = [gEGAPFeatures] Value = [%u] ", + pHddCtx->config->egap_feature_flag); +#endif +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + hdd_info("Name = [isRoamOffloadEnabled] Value = [%u]", + pHddCtx->config->isRoamOffloadEnabled); +#endif + hdd_info("Name = [gEnableSifsBurst] Value = [%u]", + pHddCtx->config->enableSifsBurst); + +#ifdef WLAN_FEATURE_LPSS + hdd_info("Name = [gEnableLpassSupport] Value = [%u] ", + pHddCtx->config->enable_lpass_support); +#endif + + hdd_info("Name = [gEnableSelfRecovery] Value = [%u]", + pHddCtx->config->enableSelfRecovery); + + hdd_info("Name = [gEnableSapSuspend] Value = [%u]", + pHddCtx->config->enableSapSuspend); + +#ifdef WLAN_FEATURE_EXTWOW_SUPPORT + hdd_info("Name = [gExtWoWgotoSuspend] Value = [%u]", + pHddCtx->config->extWowGotoSuspend); + + hdd_info("Name = [gExtWowApp1WakeupPinNumber] Value = [%u]", + pHddCtx->config->extWowApp1WakeupPinNumber); + + hdd_info("Name = [gExtWowApp2WakeupPinNumber] Value = [%u]", + pHddCtx->config->extWowApp2WakeupPinNumber); + + hdd_info("Name = [gExtWoWApp2KAInitPingInterval] Value = [%u]", + pHddCtx->config->extWowApp2KAInitPingInterval); + + hdd_info("Name = [gExtWoWApp2KAMinPingInterval] Value = [%u]", + pHddCtx->config->extWowApp2KAMinPingInterval); + + hdd_info("Name = [gExtWoWApp2KAMaxPingInterval] Value = [%u]", + pHddCtx->config->extWowApp2KAMaxPingInterval); + + hdd_info("Name = [gExtWoWApp2KAIncPingInterval] Value = [%u]", + pHddCtx->config->extWowApp2KAIncPingInterval); + + hdd_info("Name = [gExtWoWApp2TcpSrcPort] Value = [%u]", + pHddCtx->config->extWowApp2TcpSrcPort); + + hdd_info("Name = [gExtWoWApp2TcpDstPort] Value = [%u]", + pHddCtx->config->extWowApp2TcpDstPort); + + hdd_info("Name = [gExtWoWApp2TcpTxTimeout] Value = [%u]", + pHddCtx->config->extWowApp2TcpTxTimeout); + + hdd_info("Name = [gExtWoWApp2TcpRxTimeout] Value = [%u]", + pHddCtx->config->extWowApp2TcpRxTimeout); +#endif + +#ifdef DHCP_SERVER_OFFLOAD + hdd_info("Name = [gDHCPServerOffloadEnable] Value = [%u]", + pHddCtx->config->enableDHCPServerOffload); + hdd_info("Name = [gDHCPMaxNumClients] Value = [%u]", + pHddCtx->config->dhcpMaxNumClients); + hdd_info("Name = [gDHCPServerIP] Value = [%s]", + pHddCtx->config->dhcpServerIP); +#endif + + hdd_info("Name = [gEnableDumpCollect] Value = [%u]", + pHddCtx->config->is_ramdump_enabled); + + hdd_info("Name = [gP2PListenDeferInterval] Value = [%u]", + pHddCtx->config->p2p_listen_defer_interval); + hdd_notice("Name = [is_ps_enabled] value = [%d]", + pHddCtx->config->is_ps_enabled); + hdd_notice("Name = [tso_enable] value = [%d]", + pHddCtx->config->tso_enable); + hdd_notice("Name = [LROEnable] value = [%d]", + pHddCtx->config->lro_enable); + hdd_notice("Name = [active_mode_offload] value = [%d]", + pHddCtx->config->active_mode_offload); + hdd_notice("Name = [gfine_time_meas_cap] value = [%u]", + pHddCtx->config->fine_time_meas_cap); +#ifdef WLAN_FEATURE_FASTPATH + hdd_info("Name = [fastpath_enable] Value = [%u]", + pHddCtx->config->fastpath_enable); +#endif + hdd_notice("Name = [max_scan_count] value = [%d]", + pHddCtx->config->max_scan_count); + hdd_notice("Name = [%s] value = [%d]", + CFG_RX_MODE_NAME, pHddCtx->config->rx_mode); + hdd_info("Name = [%s] Value = [%u]", + CFG_CE_CLASSIFY_ENABLE_NAME, + pHddCtx->config->ce_classify_enabled); + hdd_notice("Name = [%s] value = [%u]", + CFG_DUAL_MAC_FEATURE_DISABLE, + pHddCtx->config->dual_mac_feature_disable); +#ifdef FEATURE_WLAN_SCAN_PNO + hdd_notice("Name = [%s] Value = [%u]", + CFG_PNO_CHANNEL_PREDICTION_NAME, + pHddCtx->config->pno_channel_prediction); + hdd_notice("Name = [%s] Value = [%u]", + CFG_TOP_K_NUM_OF_CHANNELS_NAME, + pHddCtx->config->top_k_num_of_channels); + hdd_notice("Name = [%s] Value = [%u]", + CFG_STATIONARY_THRESHOLD_NAME, + pHddCtx->config->stationary_thresh); + hdd_notice("Name = [%s] Value = [%u]", + CFG_CHANNEL_PREDICTION_FULL_SCAN_MS_NAME, + pHddCtx->config->channel_prediction_full_scan); + hdd_notice("Name = [%s] Value = [%u]", + CFG_ADAPTIVE_PNOSCAN_DWELL_MODE_NAME, + pHddCtx->config->pnoscan_adaptive_dwell_mode); +#endif + hdd_notice("Name = [%s] Value = [%d]", + CFG_EARLY_STOP_SCAN_ENABLE, + pHddCtx->config->early_stop_scan_enable); + hdd_notice("Name = [%s] Value = [%d]", + CFG_EARLY_STOP_SCAN_MIN_THRESHOLD, + pHddCtx->config->early_stop_scan_min_threshold); + hdd_notice("Name = [%s] Value = [%d]", + CFG_EARLY_STOP_SCAN_MAX_THRESHOLD, + pHddCtx->config->early_stop_scan_max_threshold); + hdd_notice("Name = [%s] Value = [%d]", + CFG_FIRST_SCAN_BUCKET_THRESHOLD_NAME, + pHddCtx->config->first_scan_bucket_threshold); + hdd_notice("Name = [%s] Value = [%u]", + CFG_HT_MPDU_DENSITY_NAME, + pHddCtx->config->ht_mpdu_density); + + +#ifdef FEATURE_LFR_SUBNET_DETECTION + hdd_notice("Name = [%s] Value = [%d]", + CFG_ENABLE_LFR_SUBNET_DETECTION, + pHddCtx->config->enable_lfr_subnet_detection); +#endif + hdd_info("Name = [%s] Value = [%u]", + CFG_ROAM_DENSE_TRAFFIC_THRESHOLD, + pHddCtx->config->roam_dense_traffic_thresh); + hdd_info("Name = [%s] Value = [%u]", + CFG_ROAM_DENSE_RSSI_THRE_OFFSET, + pHddCtx->config->roam_dense_rssi_thresh_offset); + hdd_info("Name = [%s] Value = [%u]", + CFG_IGNORE_PEER_HT_MODE_NAME, + pHddCtx->config->ignore_peer_ht_opmode); + hdd_info("Name = [%s] Value = [%u]", + CFG_ENABLE_VENDOR_VHT_FOR_24GHZ_NAME, + pHddCtx->config->enable_sap_vendor_vht); + hdd_info("Name = [%s] Value = [%u]", + CFG_ENABLE_FATAL_EVENT_TRIGGER, + pHddCtx->config->enable_fatal_event); + hdd_info("Name = [%s] Value = [%u]", + CFG_ROAM_DENSE_MIN_APS, + pHddCtx->config->roam_dense_min_aps); + hdd_info("Name = [%s] Value = [%u]", + CFG_MIN_REST_TIME_NAME, + pHddCtx->config->min_rest_time_conc); + hdd_info("Name = [%s] Value = [%u]", + CFG_IDLE_TIME_NAME, + pHddCtx->config->idle_time_conc); + hdd_info("Name = [%s] Value = [%d]", + CFG_BUG_ON_REINIT_FAILURE_NAME, + pHddCtx->config->bug_on_reinit_failure); + hdd_info("Name = [%s] Value = [%u]", + CFG_INTERFACE_CHANGE_WAIT_NAME, + pHddCtx->config->iface_change_wait_time); + + hdd_info("Name = [%s] Value = [%u]", + CFG_ENABLE_EDCA_INI_NAME, + pHddCtx->config->enable_edca_params); + + hdd_info("Name = [%s] Value = [%u]", + CFG_EDCA_VO_CWMIN_VALUE_NAME, + pHddCtx->config->edca_vo_cwmin); + hdd_info("Name = [%s] Value = [%u]", + CFG_EDCA_VI_CWMIN_VALUE_NAME, + pHddCtx->config->edca_vi_cwmin); + hdd_info("Name = [%s] Value = [%u]", + CFG_EDCA_BK_CWMIN_VALUE_NAME, + pHddCtx->config->edca_bk_cwmin); + hdd_info("Name = [%s] Value = [%u]", + CFG_EDCA_BE_CWMIN_VALUE_NAME, + pHddCtx->config->edca_be_cwmin); + + hdd_info("Name = [%s] Value = [%u]", + CFG_EDCA_VO_CWMAX_VALUE_NAME, + pHddCtx->config->edca_vo_cwmax); + hdd_info("Name = [%s] Value = [%u]", + CFG_EDCA_VI_CWMAX_VALUE_NAME, + pHddCtx->config->edca_vi_cwmax); + hdd_info("Name = [%s] Value = [%u]", + CFG_EDCA_BK_CWMAX_VALUE_NAME, + pHddCtx->config->edca_bk_cwmax); + hdd_info("Name = [%s] Value = [%u]", + CFG_EDCA_BE_CWMAX_VALUE_NAME, + pHddCtx->config->edca_be_cwmax); + + hdd_info("Name = [%s] Value = [%u]", + CFG_EDCA_VO_AIFS_VALUE_NAME, + pHddCtx->config->edca_vo_aifs); + hdd_info("Name = [%s] Value = [%u]", + CFG_EDCA_VI_AIFS_VALUE_NAME, + pHddCtx->config->edca_vi_aifs); + hdd_info("Name = [%s] Value = [%u]", + CFG_EDCA_BK_AIFS_VALUE_NAME, + pHddCtx->config->edca_bk_aifs); + hdd_info("Name = [%s] Value = [%u]", + CFG_EDCA_BE_AIFS_VALUE_NAME, + pHddCtx->config->edca_be_aifs); + + hdd_info("Name = [%s] Value = [%s]", + CFG_ENABLE_TX_SCHED_WRR_VO, + pHddCtx->config->tx_sched_wrr_vo); + hdd_info("Name = [%s] Value = [%s]", + CFG_ENABLE_TX_SCHED_WRR_VI, + pHddCtx->config->tx_sched_wrr_vi); + hdd_info("Name = [%s] Value = [%s]", + CFG_ENABLE_TX_SCHED_WRR_BK, + pHddCtx->config->tx_sched_wrr_bk); + hdd_info("Name = [%s] Value = [%s]", + CFG_ENABLE_TX_SCHED_WRR_BE, + pHddCtx->config->tx_sched_wrr_be); + + hdd_info("Name = [%s] Value = [%u]", + CFG_ENABLE_DP_TRACE, + pHddCtx->config->enable_dp_trace); + hdd_info("Name = [%s] Value = [%u]", + CFG_ADAPTIVE_SCAN_DWELL_MODE_NAME, + pHddCtx->config->scan_adaptive_dwell_mode); + hdd_info("Name = [%s] Value = [%u]", + CFG_ADAPTIVE_ROAMSCAN_DWELL_MODE_NAME, + pHddCtx->config->roamscan_adaptive_dwell_mode); + hdd_info("Name = [%s] Value = [%u]", + CFG_ADAPTIVE_EXTSCAN_DWELL_MODE_NAME, + pHddCtx->config->extscan_adaptive_dwell_mode); + hdd_info("Name = [%s] Value = [%u]", + CFG_ADAPTIVE_DWELL_MODE_ENABLED_NAME, + pHddCtx->config->adaptive_dwell_mode_enabled); + hdd_info("Name = [%s] Value = [%u]", + CFG_GLOBAL_ADAPTIVE_DWELL_MODE_NAME, + pHddCtx->config->global_adapt_dwelltime_mode); + hdd_info("Name = [%s] Value = [%u]", + CFG_ADAPT_DWELL_LPF_WEIGHT_NAME, + pHddCtx->config->adapt_dwell_lpf_weight); + hdd_info("Name = [%s] Value = [%u]", + CFG_ADAPT_DWELL_PASMON_INTVAL_NAME, + pHddCtx->config->adapt_dwell_passive_mon_intval); + hdd_info("Name = [%s] Value = [%u]", + CFG_ADAPT_DWELL_WIFI_THRESH_NAME, + pHddCtx->config->adapt_dwell_wifi_act_threshold); + hdd_info("Name = [%s] value = [%u]", + CFG_SUB_20_CHANNEL_WIDTH_NAME, + pHddCtx->config->enable_sub_20_channel_width); + hdd_info("Name = [%s] Value = [%u]", + CFG_TGT_GTX_USR_CFG_NAME, + pHddCtx->config->tgt_gtx_usr_cfg); + hdd_info("Name = [%s] Value = [%u]", + CFG_SAP_MAX_INACTIVITY_OVERRIDE_NAME, + pHddCtx->config->sap_max_inactivity_override); + hdd_ndp_print_ini_config(pHddCtx); + hdd_info("Name = [%s] Value = [%s]", + CFG_RM_CAPABILITY_NAME, + pHddCtx->config->rm_capability); + hdd_info("Name = [%s] Value = [%d]", + CFG_SAP_FORCE_11N_FOR_11AC_NAME, + pHddCtx->config->sap_force_11n_for_11ac); + hdd_info("Name = [%s] Value = [%d]", + CFG_BPF_PACKET_FILTER_OFFLOAD, + pHddCtx->config->bpf_packet_filter_enable); + hdd_info("Name = [%s] Value = [%u]", + CFG_TDLS_ENABLE_DEFER_TIMER, + pHddCtx->config->tdls_enable_defer_time); + hdd_info("Name = [%s] Value = [%d]", + CFG_FILTER_MULTICAST_REPLAY_NAME, + pHddCtx->config->multicast_replay_filter); + hdd_info("Name = [%s] Value = [%u]", + CFG_ENABLE_GO_CTS2SELF_FOR_STA, + pHddCtx->config->enable_go_cts2self_for_sta); + hdd_info("Name = [%s] Value = [%u]", + CFG_CRASH_FW_TIMEOUT_NAME, + pHddCtx->config->fw_timeout_crash); + hdd_info("Name = [%s] Value = [%u]", + CFG_ENABLE_PHY_REG_NAME, + pHddCtx->config->enable_phy_reg_retention); + hdd_debug("Name = [%s] Value = [%u]", + CFG_HW_FILTER_MODE_NAME, + pHddCtx->config->hw_filter_mode); + hdd_err("Name = [%s] Value = [%u]", + CFG_AUTO_DETECT_POWER_FAIL_MODE_NAME, + pHddCtx->config->auto_pwr_save_fail_mode); + hdd_per_roam_print_ini_config(pHddCtx); + hdd_info("Name = [%s] Value = [%d]", + CFG_SAP_INTERNAL_RESTART_NAME, + pHddCtx->config->sap_internal_restart); + hdd_debug("Name = [%s] Value = [%d]", + CFG_RESTART_BEACONING_ON_CH_AVOID_NAME, + pHddCtx->config->restart_beaconing_on_chan_avoid_event); + hdd_debug("Name = [%s] value = [%u]", + CFG_FORCE_1X1_NAME, + pHddCtx->config->is_force_1x1); + hdd_info("Name = [%s] value = [%u]", + CFG_DROPPED_PKT_DISCONNECT_TH_NAME, + pHddCtx->config->pkt_err_disconn_th); + hdd_info("Name = [%s] Value = [%u]", + CFG_IS_BSSID_HINT_PRIORITY_NAME, + pHddCtx->config->is_bssid_hint_priority); + hdd_debug("Name = [%s] value = [%u]", + CFG_11B_NUM_TX_CHAIN_NAME, + pHddCtx->config->num_11b_tx_chains); + hdd_debug("Name = [%s] value = [%u]", + CFG_11AG_NUM_TX_CHAIN_NAME, + pHddCtx->config->num_11ag_tx_chains); + hdd_debug("Name = [%s] value = [%u]", + CFG_ITO_REPEAT_COUNT_NAME, + pHddCtx->config->ito_repeat_count); + +} + + +/** + * hdd_update_mac_config() - update MAC address from cfg file + * @pHddCtx: the pointer to hdd context + * + * It overwrites the MAC address if config file exist. + * + * Return: QDF_STATUS_SUCCESS if the MAC address is found from cfg file + * and overwritten, otherwise QDF_STATUS_E_INVAL + */ +QDF_STATUS hdd_update_mac_config(hdd_context_t *pHddCtx) +{ + int status, i = 0; + const struct firmware *fw = NULL; + char *line, *buffer = NULL; + char *temp = NULL; + char *name, *value; + tCfgIniEntry macTable[QDF_MAX_CONCURRENCY_PERSONA]; + tSirMacAddr customMacAddr; + + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + + memset(macTable, 0, sizeof(macTable)); + status = request_firmware(&fw, WLAN_MAC_FILE, pHddCtx->parent_dev); + + if (status) { + hdd_warn("request_firmware failed %d", status); + qdf_status = QDF_STATUS_E_FAILURE; + return qdf_status; + } + if (!fw || !fw->data || !fw->size) { + hdd_alert("invalid firmware"); + qdf_status = QDF_STATUS_E_INVAL; + goto config_exit; + } + + hdd_debug("wlan_mac.bin size %zu", fw->size); + + temp = qdf_mem_malloc(fw->size + 1); + + if (temp == NULL) { + hdd_err("fail to alloc memory"); + qdf_status = QDF_STATUS_E_NOMEM; + goto config_exit; + } + buffer = temp; + qdf_mem_copy(buffer, fw->data, fw->size); + buffer[fw->size] = 0x0; + + /* data format: + * Intf0MacAddress=00AA00BB00CC + * Intf1MacAddress=00AA00BB00CD + * END + */ + while (buffer != NULL) { + line = get_next_line(buffer); + buffer = i_trim(buffer); + + if (strlen((char *)buffer) == 0 || *buffer == '#') { + buffer = line; + continue; + } + if (strncmp(buffer, "END", 3) == 0) + break; + + name = buffer; + buffer = strnchr(buffer, strlen(buffer), '='); + if (buffer) { + *buffer++ = '\0'; + i_trim(name); + if (strlen(name) != 0) { + buffer = i_trim(buffer); + if (strlen(buffer) == 12) { + value = buffer; + macTable[i].name = name; + macTable[i++].value = value; + if (i >= QDF_MAX_CONCURRENCY_PERSONA) + break; + } + } + } + buffer = line; + } + if (i <= QDF_MAX_CONCURRENCY_PERSONA) { + hdd_notice("%d Mac addresses provided", i); + } else { + hdd_err("invalid number of Mac address provided, nMac = %d", i); + qdf_status = QDF_STATUS_E_INVAL; + goto config_exit; + } + + update_mac_from_string(pHddCtx, &macTable[0], i); + + qdf_mem_copy(&customMacAddr, + &pHddCtx->config->intfMacAddr[0].bytes[0], + sizeof(tSirMacAddr)); + sme_set_custom_mac_addr(customMacAddr); + +config_exit: + qdf_mem_free(temp); + release_firmware(fw); + return qdf_status; +} + +/** + * hdd_disable_runtime_pm() - Override to disable runtime_pm. + * @cfg_ini: Handle to struct hdd_config + * + * Return: None + */ +#ifdef FEATURE_RUNTIME_PM +static void hdd_disable_runtime_pm(struct hdd_config *cfg_ini) +{ + cfg_ini->runtime_pm = 0; +} +#else +static void hdd_disable_runtime_pm(struct hdd_config *cfg_ini) +{ +} +#endif + +/** + * hdd_disable_auto_shutdown() - Override to disable auto_shutdown. + * @cfg_ini: Handle to struct hdd_config + * + * Return: None + */ +#ifdef FEATURE_WLAN_AUTO_SHUTDOWN +static void hdd_disable_auto_shutdown(struct hdd_config *cfg_ini) +{ + cfg_ini->WlanAutoShutdown = 0; +} +#else +static void hdd_disable_auto_shutdown(struct hdd_config *cfg_ini) +{ +} +#endif + +/** + * hdd_override_all_ps() - overrides to disables all the powersave features. + * @hdd_ctx: Pointer to HDD context. + * Overrides below powersave ini configurations. + * gEnableImps=0 + * gEnableBmps=0 + * gRuntimePM=0 + * gWlanAutoShutdown = 0 + * gEnableSuspend=0 + * gEnablePowerSaveOffload=0 + * gEnableWoW=0 + * + * Return: None + */ +static void hdd_override_all_ps(hdd_context_t *hdd_ctx) +{ + struct hdd_config *cfg_ini = hdd_ctx->config; + + cfg_ini->fIsImpsEnabled = 0; + cfg_ini->is_ps_enabled = 0; + hdd_disable_runtime_pm(cfg_ini); + hdd_disable_auto_shutdown(cfg_ini); + cfg_ini->enablePowersaveOffload = 0; + cfg_ini->wowEnable = 0; +} + +/** + * hdd_set_rx_mode_value() - set rx_mode values + * @hdd_ctx: hdd context + * + * Return: none + */ +static void hdd_set_rx_mode_value(hdd_context_t *hdd_ctx) +{ + if (hdd_ctx->config->rx_mode & CFG_ENABLE_RX_THREAD && + hdd_ctx->config->rx_mode & CFG_ENABLE_RPS) { + hdd_notice("rx_mode wrong configuration. Make it default"); + hdd_ctx->config->rx_mode = CFG_RX_MODE_DEFAULT; + } + + if (hdd_ctx->config->rx_mode & CFG_ENABLE_RX_THREAD) + hdd_ctx->enableRxThread = true; + + if (hdd_ctx->config->rx_mode & CFG_ENABLE_RPS) + hdd_ctx->rps = true; + + if (hdd_ctx->config->rx_mode & CFG_ENABLE_NAPI) + hdd_ctx->napi_enable = true; +} + +/** + * hdd_parse_config_ini() - parse the ini configuration file + * @pHddCtx: the pointer to hdd context + * + * This function reads the qcom_cfg.ini file and + * parses each 'Name=Value' pair in the ini file + * + * Return: QDF_STATUS_SUCCESS if the qcom_cfg.ini is correctly read, + * otherwise QDF_STATUS_E_INVAL + */ +QDF_STATUS hdd_parse_config_ini(hdd_context_t *pHddCtx) +{ + int status, i = 0; + /** Pointer for firmware image data */ + const struct firmware *fw = NULL; + char *buffer, *line, *pTemp = NULL; + size_t size; + char *name, *value; + /* cfgIniTable is static to avoid excess stack usage */ + static tCfgIniEntry cfgIniTable[MAX_CFG_INI_ITEMS]; + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + + memset(cfgIniTable, 0, sizeof(cfgIniTable)); + + status = request_firmware(&fw, WLAN_INI_FILE, pHddCtx->parent_dev); + + if (status) { + hdd_alert("request_firmware failed %d", status); + qdf_status = QDF_STATUS_E_FAILURE; + goto config_exit; + } + if (!fw || !fw->data || !fw->size) { + hdd_alert("%s download failed", WLAN_INI_FILE); + qdf_status = QDF_STATUS_E_FAILURE; + goto config_exit; + } + + hdd_notice("qcom_cfg.ini Size %zu", fw->size); + + buffer = (char *)qdf_mem_malloc(fw->size); + + if (NULL == buffer) { + hdd_alert("qdf_mem_malloc failure"); + release_firmware(fw); + return QDF_STATUS_E_NOMEM; + } + pTemp = buffer; + + qdf_mem_copy((void *)buffer, (void *)fw->data, fw->size); + size = fw->size; + + while (buffer != NULL) { + line = get_next_line(buffer); + buffer = i_trim(buffer); + + hdd_notice("%s: item", buffer); + + if (strlen((char *)buffer) == 0 || *buffer == '#') { + buffer = line; + continue; + } else if (strncmp(buffer, "END", 3) == 0) { + break; + } else { + name = buffer; + while (*buffer != '=' && *buffer != '\0') + buffer++; + if (*buffer != '\0') { + *buffer++ = '\0'; + i_trim(name); + if (strlen(name) != 0) { + buffer = i_trim(buffer); + if (strlen(buffer) > 0) { + value = buffer; + while (!i_isspace(*buffer) + && *buffer != '\0') + buffer++; + *buffer = '\0'; + cfgIniTable[i].name = name; + cfgIniTable[i++].value = value; + if (i >= MAX_CFG_INI_ITEMS) { + hdd_err("Number of items in %s > %d", + WLAN_INI_FILE, + MAX_CFG_INI_ITEMS); + break; + } + } + } + } + } + buffer = line; + } + + /* Loop through the registry table and apply all these configs */ + qdf_status = hdd_apply_cfg_ini(pHddCtx, cfgIniTable, i); + hdd_set_rx_mode_value(pHddCtx); + if (QDF_GLOBAL_MONITOR_MODE == cds_get_conparam()) + hdd_override_all_ps(pHddCtx); + +config_exit: + release_firmware(fw); + qdf_mem_free(pTemp); + return qdf_status; +} + +/** + * hdd_cfg_xlate_to_csr_phy_mode() - convert PHY mode + * @dot11Mode: the mode to convert + * + * Convert the configuration PHY mode to CSR PHY mode + * + * Return: the CSR phy mode value + */ +eCsrPhyMode hdd_cfg_xlate_to_csr_phy_mode(eHddDot11Mode dot11Mode) +{ + if (cds_is_sub_20_mhz_enabled()) + return eCSR_DOT11_MODE_abg; + + switch (dot11Mode) { + case (eHDD_DOT11_MODE_abg): + return eCSR_DOT11_MODE_abg; + case (eHDD_DOT11_MODE_11b): + return eCSR_DOT11_MODE_11b; + case (eHDD_DOT11_MODE_11g): + return eCSR_DOT11_MODE_11g; + default: + case (eHDD_DOT11_MODE_11n): + return eCSR_DOT11_MODE_11n; + case (eHDD_DOT11_MODE_11g_ONLY): + return eCSR_DOT11_MODE_11g_ONLY; + case (eHDD_DOT11_MODE_11n_ONLY): + return eCSR_DOT11_MODE_11n_ONLY; + case (eHDD_DOT11_MODE_11b_ONLY): + return eCSR_DOT11_MODE_11b_ONLY; + case (eHDD_DOT11_MODE_11ac_ONLY): + return eCSR_DOT11_MODE_11ac_ONLY; + case (eHDD_DOT11_MODE_11ac): + return eCSR_DOT11_MODE_11ac; + case (eHDD_DOT11_MODE_AUTO): + return eCSR_DOT11_MODE_AUTO; + case (eHDD_DOT11_MODE_11a): + return eCSR_DOT11_MODE_11a; + } + +} + +/** + * hdd_set_idle_ps_config() - set idle power save configuration + * @pHddCtx: the pointer to hdd context + * @val: the value to configure + * + * Return: QDF_STATUS_SUCCESS if command set correctly, + * otherwise the QDF_STATUS return from SME layer + */ +QDF_STATUS hdd_set_idle_ps_config(hdd_context_t *pHddCtx, bool val) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + + if (pHddCtx->imps_enabled == val) { + hdd_notice("Already in the requested power state:%d", val); + return QDF_STATUS_SUCCESS; + } + + hdd_notice("hdd_set_idle_ps_config: Enter Val %d", val); + + status = sme_set_idle_powersave_config(val); + if (QDF_STATUS_SUCCESS != status) { + hdd_err("Fail to Set Idle PS Config val %d", val); + return status; + } + + pHddCtx->imps_enabled = val; + + return status; +} + +/** + * hdd_set_fine_time_meas_cap() - set fine timing measurement capability + * @hdd_ctx: HDD context + * @sme_config: pointer to SME config + * + * This function is used to pass fine timing measurement capability coming + * from INI to SME. This function make sure that configure INI is supported + * by the device. Use bit mask to mask out the unsupported capabilities. + * + * Return: None + */ +static void hdd_set_fine_time_meas_cap(hdd_context_t *hdd_ctx, + tSmeConfigParams *sme_config) +{ + struct hdd_config *config = hdd_ctx->config; + uint32_t capability = config->fine_time_meas_cap; + + /* Make sure only supported capabilities are enabled in INI */ + capability &= CFG_FINE_TIME_MEAS_CAPABILITY_MAX; + sme_config->csrConfig.fine_time_meas_cap = capability; + + hdd_notice("fine time meas capability - INI: %04x Enabled: %04x", + config->fine_time_meas_cap, + sme_config->csrConfig.fine_time_meas_cap); + + return; +} + +/** + * hdd_convert_string_to_u8_array() - used to convert string into u8 array + * @str: String to be converted + * @hex_array: Array where converted value is stored + * @len: Length of the populated array + * @array_max_len: Maximum length of the array + * @to_hex: true, if conversion required for hex string + * + * This API is called to convert string (each byte separated by + * a comma) into an u8 array + * + * Return: QDF_STATUS + */ + +static QDF_STATUS hdd_convert_string_to_array(char *str, uint8_t *array, + uint8_t *len, uint8_t array_max_len, bool to_hex) +{ + char *format, *s = str; + + if (str == NULL || array == NULL || len == NULL) + return QDF_STATUS_E_INVAL; + + format = (to_hex) ? "%02x" : "%d"; + + *len = 0; + while ((s != NULL) && (*len < array_max_len)) { + int val; + /* Increment length only if sscanf successfully extracted + * one element. Any other return value means error. + * Ignore it. */ + if (sscanf(s, format, &val) == 1) { + array[*len] = (uint8_t) val; + *len += 1; + } + + s = strpbrk(s, ","); + if (s) + s++; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * hdd_hex_string_to_u8_array() - used to convert hex string into u8 array + * @str: Hexadecimal string + * @hex_array: Array where converted value is stored + * @len: Length of the populated array + * @array_max_len: Maximum length of the array + * + * This API is called to convert hexadecimal string (each byte separated by + * a comma) into an u8 array + * + * Return: QDF_STATUS + */ +static QDF_STATUS hdd_hex_string_to_u8_array(char *str, uint8_t *hex_array, + uint8_t *len, + uint8_t array_max_len) +{ + return hdd_convert_string_to_array(str, hex_array, len, + array_max_len, true); +} + +/** + * hdd_string_to_u8_array() - used to convert decimal string into u8 array + * @str: Decimal string + * @hex_array: Array where converted value is stored + * @len: Length of the populated array + * @array_max_len: Maximum length of the array + * + * This API is called to convert decimal string (each byte separated by + * a comma) into an u8 array + * + * Return: QDF_STATUS + */ + +QDF_STATUS hdd_string_to_u8_array(char *str, uint8_t *array, + uint8_t *len, uint8_t array_max_len) +{ + return hdd_convert_string_to_array(str, array, len, + array_max_len, false); +} + +/** + * hdd_hex_string_to_u16_array() - convert a hex string to a uint16 array + * @str: input string + * @int_array: pointer to input array of type uint16 + * @len: pointer to number of elements which the function adds to the array + * @int_array_max_len: maximum number of elements in input uint16 array + * + * This function is used to convert a space separated hex string to an array of + * uint16_t. For example, an input string str = "a b c d" would be converted to + * a unint16 array, int_array = {0xa, 0xb, 0xc, 0xd}, *len = 4. + * This assumes that input value int_array_max_len >= 4. + * + * Return: QDF_STATUS_SUCCESS - if the conversion is successful + * non zero value - if the conversion is a failure + */ +QDF_STATUS hdd_hex_string_to_u16_array(char *str, + uint16_t *int_array, uint8_t *len, uint8_t int_array_max_len) +{ + char *s = str; + uint32_t val = 0; + + if (str == NULL || int_array == NULL || len == NULL) + return QDF_STATUS_E_INVAL; + + hdd_notice("str %p intArray %p intArrayMaxLen %d", + s, int_array, int_array_max_len); + + *len = 0; + + while ((s != NULL) && (*len < int_array_max_len)) { + /* + * Increment length only if sscanf successfully extracted one + * element. Any other return value means error. Ignore it. + */ + if (sscanf(s, "%x", &val) == 1) { + int_array[*len] = (uint16_t) val; + hdd_debug("s %p val %x intArray[%d]=0x%x", + s, val, *len, int_array[*len]); + *len += 1; + } + s = strpbrk(s, " "); + if (s) + s++; + } + return QDF_STATUS_SUCCESS; +} + +/** + * hdd_update_ht_cap_in_cfg() - to update HT cap in global CFG + * @hdd_ctx: pointer to hdd context + * + * This API will update the HT config in CFG after taking intersection + * of INI and firmware capabilities provided reading CFG + * + * Return: true or false + */ +static bool hdd_update_ht_cap_in_cfg(hdd_context_t *hdd_ctx) +{ + uint32_t val32; + uint16_t val16; + bool status = true; + tSirMacHTCapabilityInfo *ht_cap_info; + + if (sme_cfg_get_int(hdd_ctx->hHal, WNI_CFG_HT_CAP_INFO, + &val32) == + QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Could not get WNI_CFG_HT_CAP_INFO"); + } + val16 = (uint16_t) val32; + ht_cap_info = (tSirMacHTCapabilityInfo *) &val16; + ht_cap_info->advCodingCap &= hdd_ctx->config->enableRxLDPC; + ht_cap_info->rxSTBC = QDF_MIN(ht_cap_info->rxSTBC, + hdd_ctx->config->enableRxSTBC); + ht_cap_info->txSTBC &= hdd_ctx->config->enableTxSTBC; + ht_cap_info->shortGI20MHz &= hdd_ctx->config->ShortGI20MhzEnable; + ht_cap_info->shortGI40MHz &= hdd_ctx->config->ShortGI40MhzEnable; + val32 = val16; + if (sme_cfg_set_int(hdd_ctx->hHal, WNI_CFG_HT_CAP_INFO, val32) == + QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Could not set WNI_CFG_HT_CAP_INFO"); + } + return status; +} + +/** + * hdd_update_vht_cap_in_cfg() - to update VHT cap in global CFG + * @hdd_ctx: pointer to hdd context + * + * This API will update the VHT config in CFG after taking intersection + * of INI and firmware capabilities provided reading CFG + * + * Return: true or false + */ +static bool hdd_update_vht_cap_in_cfg(hdd_context_t *hdd_ctx) +{ + bool status = true; + uint32_t val; + struct hdd_config *config = hdd_ctx->config; + + if (sme_cfg_set_int(hdd_ctx->hHal, WNI_CFG_VHT_ENABLE_TXBF_20MHZ, + config->enableTxBFin20MHz) == + QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Couldn't set value for WNI_CFG_VHT_ENABLE_TXBF_20MHZ"); + } + /* Based on cfg.ini, update the Basic MCS set, RX/TX MCS map + * in the cfg.dat. Valid values are 0(MCS0-7), 1(MCS0-8), 2(MCS0-9) + * we update only the least significant 2 bits in the + * corresponding fields. + */ + if ((config->dot11Mode == eHDD_DOT11_MODE_AUTO) || + (config->dot11Mode == eHDD_DOT11_MODE_11ac_ONLY) || + (config->dot11Mode == eHDD_DOT11_MODE_11ac)) { + /* Currently shortGI40Mhz is used for shortGI80Mhz */ + if (sme_cfg_set_int(hdd_ctx->hHal, WNI_CFG_VHT_SHORT_GI_80MHZ, + config->ShortGI40MhzEnable) == QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Couldn't pass WNI_VHT_SHORT_GI_80MHZ to CFG"); + } + /* Hardware is capable of doing + * 128K AMPDU in 11AC mode */ + if (sme_cfg_set_int(hdd_ctx->hHal, + WNI_CFG_VHT_AMPDU_LEN_EXPONENT, + config->fVhtAmpduLenExponent) == + QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Couldn't pass on WNI_CFG_VHT_AMPDU_LEN_EXPONENT to CFG"); + } + /* Change MU Bformee only when TxBF is enabled */ + if (config->enableTxBF) { + sme_cfg_get_int(hdd_ctx->hHal, + WNI_CFG_VHT_MU_BEAMFORMEE_CAP, &val); + + if (val != config->enableMuBformee) { + if (sme_cfg_set_int(hdd_ctx->hHal, + WNI_CFG_VHT_MU_BEAMFORMEE_CAP, + config->enableMuBformee + ) == QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Couldn't pass on WNI_CFG_VHT_MU_BEAMFORMEE_CAP to CFG"); + } + } + } + if (sme_cfg_set_int(hdd_ctx->hHal, WNI_CFG_VHT_MAX_MPDU_LENGTH, + config->vhtMpduLen) == QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Couldn't pass on WNI_CFG_VHT_MAX_MPDU_LENGTH to CFG"); + } + + if (config->enable2x2 && config->enable_su_tx_bformer) { + if (sme_cfg_set_int(hdd_ctx->hHal, + WNI_CFG_VHT_SU_BEAMFORMER_CAP, + config->enable_su_tx_bformer) == + QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("set SU_BEAMFORMER_CAP to CFG failed"); + } + if (sme_cfg_set_int(hdd_ctx->hHal, + WNI_CFG_VHT_NUM_SOUNDING_DIMENSIONS, + NUM_OF_SOUNDING_DIMENSIONS) == + QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("failed to set NUM_OF_SOUNDING_DIM"); + } + } + } + + if (sme_cfg_set_int(hdd_ctx->hHal, WNI_CFG_VHT_RXSTBC, + config->enableRxSTBC) == QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Couldn't pass on WNI_CFG_VHT_RXSTBC to CFG"); + } + + if (sme_cfg_set_int(hdd_ctx->hHal, WNI_CFG_VHT_TXSTBC, + config->enableTxSTBC) == QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Couldn't pass on WNI_CFG_VHT_TXSTBC to CFG"); + } + + if (sme_cfg_get_int(hdd_ctx->hHal, WNI_CFG_VHT_LDPC_CODING_CAP, &val) == + QDF_STATUS_E_FAILURE) { + status &= false; + hdd_err("Could not get WNI_CFG_VHT_LDPC_CODING_CAP"); + } + if (sme_cfg_set_int(hdd_ctx->hHal, WNI_CFG_VHT_LDPC_CODING_CAP, + config->enableRxLDPC & val) == QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Couldn't pass on WNI_CFG_VHT_LDPC_CODING_CAP to CFG"); + } + + if (sme_cfg_set_int(hdd_ctx->hHal, + WNI_CFG_VHT_CSN_BEAMFORMEE_ANT_SUPPORTED, + config->txBFCsnValue) == + QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Couldn't pass on WNI_CFG_VHT_CSN_BEAMFORMEE_ANT_SUPPORTED to CFG"); + } + return status; + +} + +/** + * hdd_update_config_cfg() - API to update INI setting based on hw/fw caps + * @hdd_ctx: pointer to hdd_ctx + * + * This API reads the cfg file which is updated with hardware/firmware + * capabilities and intersect it with INI setting provided by user. After + * taking intersection it adjust cfg it self. For example, if user has enabled + * RX LDPC through INI but hardware/firmware doesn't support it then disable + * it in CFG file here. + * + * Return: true or false based on outcome. + */ +bool hdd_update_config_cfg(hdd_context_t *hdd_ctx) +{ + bool status = true; + uint32_t val; + struct hdd_config *config = hdd_ctx->config; + + /* + * During the initialization both 2G and 5G capabilities should be same. + * So read 5G HT capablity and update 2G and 5G capablities. + */ + if (!hdd_update_ht_cap_in_cfg(hdd_ctx)) { + status = false; + hdd_err("Couldn't set HT CAP in cfg"); + } + + if (!hdd_update_vht_cap_in_cfg(hdd_ctx)) { + status = false; + hdd_err("Couldn't set VHT CAP in cfg"); + } + + if (sme_cfg_set_int(hdd_ctx->hHal, WNI_CFG_FIXED_RATE, config->TxRate) + == QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Couldn't pass on WNI_CFG_FIXED_RATE to CFG"); + } + + if (sme_cfg_set_int(hdd_ctx->hHal, WNI_CFG_MAX_RX_AMPDU_FACTOR, + config->MaxRxAmpduFactor) == + QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Couldn't pass on WNI_CFG_HT_AMPDU_PARAMS_MAX_RX_AMPDU_FACTOR to CFG"); + } + + if (sme_cfg_set_int(hdd_ctx->hHal, WNI_CFG_MPDU_DENSITY, + config->ht_mpdu_density) == + QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Couldn't pass on WNI_CFG_MPDU_DENSITY to CFG"); + } + + if (sme_cfg_set_int(hdd_ctx->hHal, WNI_CFG_SHORT_PREAMBLE, + config->fIsShortPreamble) == QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Couldn't pass on WNI_CFG_SHORT_PREAMBLE to CFG"); + } + + if (sme_cfg_set_int(hdd_ctx->hHal, + WNI_CFG_PASSIVE_MINIMUM_CHANNEL_TIME, + config->nPassiveMinChnTime) + == QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Couldn't pass on WNI_CFG_PASSIVE_MINIMUM_CHANNEL_TIME to CFG"); + } + + if (sme_cfg_set_int(hdd_ctx->hHal, + WNI_CFG_PASSIVE_MAXIMUM_CHANNEL_TIME, + config->nPassiveMaxChnTime) + == QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Couldn't pass on WNI_CFG_PASSIVE_MAXIMUM_CHANNEL_TIME to CFG"); + } + + if (sme_cfg_set_int(hdd_ctx->hHal, WNI_CFG_BEACON_INTERVAL, + config->nBeaconInterval) == QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Couldn't pass on WNI_CFG_BEACON_INTERVAL to CFG"); + } + + if (sme_cfg_set_int(hdd_ctx->hHal, WNI_CFG_MAX_PS_POLL, + config->nMaxPsPoll) == QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Couldn't pass on WNI_CFG_MAX_PS_POLL to CFG"); + } + + if (sme_cfg_set_int (hdd_ctx->hHal, WNI_CFG_LOW_GAIN_OVERRIDE, + config->fIsLowGainOverride) == QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Couldn't pass on WNI_CFG_LOW_GAIN_OVERRIDE to HAL"); + } + + if (sme_cfg_set_int(hdd_ctx->hHal, WNI_CFG_RSSI_FILTER_PERIOD, + config->nRssiFilterPeriod) == QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Couldn't pass on WNI_CFG_RSSI_FILTER_PERIOD to CFG"); + } + + if (sme_cfg_set_int(hdd_ctx->hHal, WNI_CFG_IGNORE_DTIM, + config->fIgnoreDtim) == QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Couldn't pass on WNI_IGNORE_DTIM to CFG"); + } + + if (sme_cfg_set_int(hdd_ctx->hHal, WNI_CFG_PS_ENABLE_HEART_BEAT, + config->fEnableFwHeartBeatMonitoring) + == QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Couldn't pass on WNI_CFG_PS_HEART_BEAT to CFG"); + } + + if (sme_cfg_set_int(hdd_ctx->hHal, WNI_CFG_PS_ENABLE_BCN_FILTER, + config->fEnableFwBeaconFiltering) == + QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Couldn't pass on WNI_CFG_PS_BCN_FILTER to CFG"); + } + + if (sme_cfg_set_int(hdd_ctx->hHal, WNI_CFG_PS_ENABLE_RSSI_MONITOR, + config->fEnableFwRssiMonitoring) == + QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Couldn't pass on WNI_CFG_PS_RSSI_MONITOR to CFG"); + } + + if (sme_cfg_set_int(hdd_ctx->hHal, WNI_CFG_PS_DATA_INACTIVITY_TIMEOUT, + config->nDataInactivityTimeout) == QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Couldn't pass on WNI_CFG_PS_DATA_INACTIVITY_TIMEOUT to CFG"); + } + + if (sme_cfg_set_int(hdd_ctx->hHal, + WNI_CFG_PS_WOW_DATA_INACTIVITY_TIMEOUT, + config->wow_data_inactivity_timeout) == QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Fail to pass WNI_CFG_PS_WOW_DATA_INACTIVITY_TO CFG"); + } + + if (sme_cfg_set_int(hdd_ctx->hHal, WNI_CFG_ENABLE_LTE_COEX, + config->enableLTECoex) == QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Couldn't pass on WNI_CFG_ENABLE_LTE_COEX to CFG"); + } + + if (sme_cfg_set_int(hdd_ctx->hHal, WNI_CFG_AP_KEEP_ALIVE_TIMEOUT, + config->apKeepAlivePeriod) == QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Couldn't pass on WNI_CFG_AP_KEEP_ALIVE_TIMEOUT to CFG"); + } + + if (sme_cfg_set_int(hdd_ctx->hHal, WNI_CFG_GO_KEEP_ALIVE_TIMEOUT, + config->goKeepAlivePeriod) == QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Couldn't pass on WNI_CFG_GO_KEEP_ALIVE_TIMEOUT to CFG"); + } + + if (sme_cfg_set_int(hdd_ctx->hHal, WNI_CFG_AP_LINK_MONITOR_TIMEOUT, + config->apLinkMonitorPeriod) == QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Couldn't pass on WNI_CFG_AP_LINK_MONITOR_TIMEOUT to CFG"); + } + + if (sme_cfg_set_int(hdd_ctx->hHal, WNI_CFG_GO_LINK_MONITOR_TIMEOUT, + config->goLinkMonitorPeriod) == QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Couldn't pass on WNI_CFG_GO_LINK_MONITOR_TIMEOUT to CFG"); + } + + if (sme_cfg_set_int(hdd_ctx->hHal, WNI_CFG_MCAST_BCAST_FILTER_SETTING, + config->mcastBcastFilterSetting) == QDF_STATUS_E_FAILURE) + status = false; + hdd_err("Couldn't pass on WNI_CFG_MCAST_BCAST_FILTER_SETTING to CFG"); + + if (sme_cfg_set_int(hdd_ctx->hHal, WNI_CFG_SINGLE_TID_RC, + config->bSingleTidRc) == QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Couldn't pass on WNI_CFG_SINGLE_TID_RC to CFG"); + } + + if (sme_cfg_set_int(hdd_ctx->hHal, WNI_CFG_TELE_BCN_WAKEUP_EN, + config->teleBcnWakeupEn) == QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Couldn't pass on WNI_CFG_TELE_BCN_WAKEUP_EN to CFG"); + } + + if (sme_cfg_set_int(hdd_ctx->hHal, WNI_CFG_TELE_BCN_TRANS_LI, + config->nTeleBcnTransListenInterval) == + QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Couldn't pass on WNI_CFG_TELE_BCN_TRANS_LI to CFG"); + } + + if (sme_cfg_set_int(hdd_ctx->hHal, WNI_CFG_TELE_BCN_MAX_LI, + config->nTeleBcnMaxListenInterval) == + QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Couldn't pass on WNI_CFG_TELE_BCN_MAX_LI to CFG"); + } + + if (sme_cfg_set_int(hdd_ctx->hHal, WNI_CFG_TELE_BCN_TRANS_LI_IDLE_BCNS, + config->nTeleBcnTransLiNumIdleBeacons) == + QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Couldn't pass on WNI_CFG_TELE_BCN_TRANS_LI_IDLE_BCNS to CFG"); + } + + if (sme_cfg_set_int(hdd_ctx->hHal, WNI_CFG_TELE_BCN_MAX_LI_IDLE_BCNS, + config->nTeleBcnMaxLiNumIdleBeacons) == + QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Couldn't pass on WNI_CFG_TELE_BCN_MAX_LI_IDLE_BCNS to CFG"); + } + + if (sme_cfg_set_int(hdd_ctx->hHal, WNI_CFG_RF_SETTLING_TIME_CLK, + config->rfSettlingTimeUs) == QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Couldn't pass on WNI_CFG_RF_SETTLING_TIME_CLK to CFG"); + } + + if (sme_cfg_set_int(hdd_ctx->hHal, WNI_CFG_INFRA_STA_KEEP_ALIVE_PERIOD, + config->infraStaKeepAlivePeriod) == + QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Couldn't pass on WNI_CFG_INFRA_STA_KEEP_ALIVE_PERIOD to CFG"); + } + if (sme_cfg_set_int(hdd_ctx->hHal, WNI_CFG_DYNAMIC_PS_POLL_VALUE, + config->dynamicPsPollValue) == QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Couldn't pass on WNI_CFG_DYNAMIC_PS_POLL_VALUE to CFG"); + } + + if (sme_cfg_set_int(hdd_ctx->hHal, WNI_CFG_PS_NULLDATA_AP_RESP_TIMEOUT, + config->nNullDataApRespTimeout) == QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Couldn't pass on WNI_CFG_PS_NULLDATA_DELAY_TIMEOUT to CFG"); + } + + if (sme_cfg_set_int(hdd_ctx->hHal, WNI_CFG_AP_DATA_AVAIL_POLL_PERIOD, + config->apDataAvailPollPeriodInMs) == + QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Couldn't pass on WNI_CFG_AP_DATA_AVAIL_POLL_PERIOD to CFG"); + } + if (sme_cfg_set_int(hdd_ctx->hHal, WNI_CFG_FRAGMENTATION_THRESHOLD, + config->FragmentationThreshold) == QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Couldn't pass on WNI_CFG_FRAGMENTATION_THRESHOLD to CFG"); + } + if (sme_cfg_set_int(hdd_ctx->hHal, WNI_CFG_RTS_THRESHOLD, + config->RTSThreshold) == QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Couldn't pass on WNI_CFG_RTS_THRESHOLD to CFG"); + } + + if (sme_cfg_set_int(hdd_ctx->hHal, WNI_CFG_11D_ENABLED, + config->Is11dSupportEnabled) == QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Couldn't pass on WNI_CFG_11D_ENABLED to CFG"); + } + + if (sme_cfg_set_int(hdd_ctx->hHal, WNI_CFG_DFS_MASTER_ENABLED, + config->enableDFSMasterCap) == + QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Failure: Couldn't set value for WNI_CFG_DFS_MASTER_ENABLED"); + } + + if (sme_cfg_set_int(hdd_ctx->hHal, WNI_CFG_HEART_BEAT_THRESHOLD, + config->HeartbeatThresh24) == QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Couldn't pass on WNI_CFG_HEART_BEAT_THRESHOLD to CFG"); + } + + if (sme_cfg_set_int(hdd_ctx->hHal, WNI_CFG_ENABLE_MC_ADDR_LIST, + config->fEnableMCAddrList) == QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Couldn't pass on WNI_CFG_ENABLE_MC_ADDR_LIST to CFG"); + } + +#ifdef WLAN_SOFTAP_VSTA_FEATURE + if (config->fEnableVSTASupport) { + sme_cfg_get_int(hdd_ctx->hHal, WNI_CFG_ASSOC_STA_LIMIT, &val); + if (val <= WNI_CFG_ASSOC_STA_LIMIT_STADEF) + val = WNI_CFG_ASSOC_STA_LIMIT_STAMAX; + } else { + val = config->maxNumberOfPeers; + + } + if (sme_cfg_set_int(hdd_ctx->hHal, WNI_CFG_ASSOC_STA_LIMIT, val) == + QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Couldn't pass on WNI_CFG_ASSOC_STA_LIMIT to CFG"); + } +#endif + if (sme_cfg_set_int(hdd_ctx->hHal, WNI_CFG_ENABLE_LPWR_IMG_TRANSITION, + config->enableLpwrImgTransition) + == QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Couldn't pass on WNI_CFG_ENABLE_LPWR_IMG_TRANSITION to CFG"); + } + + if (sme_cfg_set_int(hdd_ctx->hHal, WNI_CFG_ENABLE_MCC_ADAPTIVE_SCHED, + config->enableMCCAdaptiveScheduler) == + QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Couldn't pass on WNI_CFG_ENABLE_MCC_ADAPTIVE_SCHED to CFG"); + } + if (sme_cfg_set_int(hdd_ctx->hHal, WNI_CFG_DISABLE_LDPC_WITH_TXBF_AP, + config->disableLDPCWithTxbfAP) == QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Couldn't pass on WNI_CFG_DISABLE_LDPC_WITH_TXBF_AP to CFG"); + } + + if (sme_cfg_set_int(hdd_ctx->hHal, WNI_CFG_DYNAMIC_THRESHOLD_ZERO, + config->retryLimitZero) == QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Couldn't pass on WNI_CFG_DYNAMIC_THRESHOLD_ZERO to CFG"); + } + + if (sme_cfg_set_int(hdd_ctx->hHal, WNI_CFG_DYNAMIC_THRESHOLD_ONE, + config->retryLimitOne) == QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Couldn't pass on WNI_CFG_DYNAMIC_THRESHOLD_ONE to CFG"); + } + + if (sme_cfg_set_int(hdd_ctx->hHal, WNI_CFG_DYNAMIC_THRESHOLD_TWO, + config->retryLimitTwo) == QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Couldn't pass on WNI_CFG_DYNAMIC_THRESHOLD_TWO to CFG"); + } + + if (sme_cfg_set_int(hdd_ctx->hHal, WNI_CFG_MAX_MEDIUM_TIME, + config->cfgMaxMediumTime) == QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Couldn't pass on WNI_CFG_MAX_MEDIUM_TIME to CFG"); + } +#ifdef FEATURE_WLAN_TDLS + + if (sme_cfg_set_int(hdd_ctx->hHal, WNI_CFG_TDLS_QOS_WMM_UAPSD_MASK, + config->fTDLSUapsdMask) == QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Couldn't pass on WNI_CFG_TDLS_QOS_WMM_UAPSD_MASK to CFG"); + } + if (sme_cfg_set_int(hdd_ctx->hHal, WNI_CFG_TDLS_BUF_STA_ENABLED, + config->fEnableTDLSBufferSta) == + QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Couldn't pass on WNI_CFG_TDLS_BUF_STA_ENABLED to CFG"); + } + if (sme_cfg_set_int(hdd_ctx->hHal, WNI_CFG_TDLS_PUAPSD_INACT_TIME, + config->fTDLSPuapsdInactivityTimer) == + QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Couldn't pass on WNI_CFG_TDLS_PUAPSD_INACT_TIME to CFG"); + } + if (sme_cfg_set_int(hdd_ctx->hHal, WNI_CFG_TDLS_RX_FRAME_THRESHOLD, + config->fTDLSRxFrameThreshold) == + QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Couldn't pass on WNI_CFG_TDLS_RX_FRAME_THRESHOLD to CFG"); + } + + if (sme_cfg_set_int(hdd_ctx->hHal, WNI_CFG_TDLS_OFF_CHANNEL_ENABLED, + config->fEnableTDLSOffChannel) == + QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Couldn't pass on WNI_CFG_TDLS_BUF_STA_ENABLED to CFG"); + } + if (sme_cfg_set_int(hdd_ctx->hHal, WNI_CFG_TDLS_WMM_MODE_ENABLED, + config->fEnableTDLSWmmMode) == + QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Couldn't pass on WNI_CFG_TDLS_WMM_MODE_ENABLED to CFG"); + } +#endif + + if (sme_cfg_set_int(hdd_ctx->hHal, WNI_CFG_ENABLE_ADAPT_RX_DRAIN, + config->fEnableAdaptRxDrain) == + QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Couldn't pass on WNI_CFG_ENABLE_ADAPT_RX_DRAIN to CFG"); + } + + if (sme_cfg_set_int(hdd_ctx->hHal, WNI_CFG_ANTENNA_DIVESITY, + config->antennaDiversity) == + QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Couldn't pass on WNI_CFG_ANTENNA_DIVESITY to CFG"); + } + + if (sme_cfg_set_int(hdd_ctx->hHal, + WNI_CFG_DEFAULT_RATE_INDEX_24GHZ, + config->defaultRateIndex24Ghz) == + QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Couldn't pass on WNI_CFG_DEFAULT_RATE_INDEX_24GHZ to CFG"); + } + + if (sme_cfg_set_int(hdd_ctx->hHal, + WNI_CFG_DEBUG_P2P_REMAIN_ON_CHANNEL, + config->debugP2pRemainOnChannel) == + QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Couldn't pass on WNI_CFG_DEBUG_P2P_REMAIN_ON_CHANNEL to CFG"); + } +#ifdef WLAN_FEATURE_11W + if (sme_cfg_set_int(hdd_ctx->hHal, WNI_CFG_PMF_SA_QUERY_MAX_RETRIES, + config->pmfSaQueryMaxRetries) == + QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Couldn't pass on WNI_CFG_SA_QUERY_MAX_RETRIES to CFG"); + } + + if (sme_cfg_set_int(hdd_ctx->hHal, WNI_CFG_PMF_SA_QUERY_RETRY_INTERVAL, + config->pmfSaQueryRetryInterval) == + QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Couldn't pass on WNI_CFG_SA_QUERY_RETRY_INTERVAL to CFG"); + } +#endif + + if (sme_cfg_set_int(hdd_ctx->hHal, WNI_CFG_IBSS_ATIM_WIN_SIZE, + config->ibssATIMWinSize) == + QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Couldn't pass on WNI_CFG_IBSS_ATIM_WIN_SIZE to CFG"); + } + + if (sme_cfg_set_int(hdd_ctx->hHal, WNI_CFG_TGT_GTX_USR_CFG, + config->tgt_gtx_usr_cfg) == QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Couldn't pass on WNI_CFG_TGT_GTX_USR_CFG to CCM"); + } + + if (sme_cfg_set_int(hdd_ctx->hHal, WNI_CFG_MAX_HT_MCS_TX_DATA, + config->max_ht_mcs_txdata) == + QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Couldn't pass on WNI_CFG_MAX_HT_MCS_TX_DATA to CCM"); + } + + if (sme_cfg_set_int(hdd_ctx->hHal, WNI_CFG_DISABLE_ABG_RATE_FOR_TX_DATA, + config->disable_abg_rate_txdata) == + QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Couldn't pass on WNI_CFG_DISABLE_ABG_RATE_FOR_TX_DATA to CCM"); + } + + if (sme_cfg_set_int(hdd_ctx->hHal, WNI_CFG_RATE_FOR_TX_MGMT, + config->rate_for_tx_mgmt) == + QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Couldn't pass on WNI_CFG_RATE_FOR_TX_MGMT to CCM"); + } + + return status; +} +#ifdef FEATURE_WLAN_SCAN_PNO +/** + * hdd_set_pno_channel_prediction_config() - Set PNO configuration + * @sme_config: Config params from SME Context + * @hdd_ctx: Config params from HDD Context + * + * Copy the PNO Channel prediction feature configuration parameters + * from HDD context to SME context. + * + * Return: None + */ +void hdd_set_pno_channel_prediction_config( + tpSmeConfigParams sme_config, hdd_context_t *hdd_ctx) +{ + sme_config->csrConfig.dual_mac_feature_disable = + hdd_ctx->config->dual_mac_feature_disable; + sme_config->csrConfig.pno_channel_prediction = + hdd_ctx->config->pno_channel_prediction; + sme_config->csrConfig.top_k_num_of_channels = + hdd_ctx->config->top_k_num_of_channels; + sme_config->csrConfig.stationary_thresh = + hdd_ctx->config->stationary_thresh; + sme_config->csrConfig.channel_prediction_full_scan = + hdd_ctx->config->channel_prediction_full_scan; + sme_config->csrConfig.pnoscan_adaptive_dwell_mode = + hdd_ctx->config->pnoscan_adaptive_dwell_mode; +} +#endif + +/** + * hdd_update_per_config_to_sme() -initializes the sme config for PER roam + * + * @hdd_ctx: the pointer to hdd context + * @sme_config: sme configuation pointer + * + * Return: None + */ +static void hdd_update_per_config_to_sme(hdd_context_t *hdd_ctx, + tSmeConfigParams *sme_config) +{ + sme_config->csrConfig.per_roam_config.enable = + hdd_ctx->config->is_per_roam_enabled; + + /* Assigning Tx and Rx for same value */ + sme_config->csrConfig.per_roam_config.tx_high_rate_thresh = + hdd_ctx->config->per_roam_high_rate_threshold; + sme_config->csrConfig.per_roam_config.rx_high_rate_thresh = + hdd_ctx->config->per_roam_high_rate_threshold; + + /* Assigning Tx and Rx for same value */ + sme_config->csrConfig.per_roam_config.tx_low_rate_thresh = + hdd_ctx->config->per_roam_low_rate_threshold; + sme_config->csrConfig.per_roam_config.rx_low_rate_thresh = + hdd_ctx->config->per_roam_low_rate_threshold; + + /* Assigning Tx and Rx for same value */ + sme_config->csrConfig.per_roam_config.tx_rate_thresh_percnt = + hdd_ctx->config->per_roam_th_percent; + sme_config->csrConfig.per_roam_config.rx_rate_thresh_percnt = + hdd_ctx->config->per_roam_th_percent; + + sme_config->csrConfig.per_roam_config.per_rest_time = + hdd_ctx->config->per_roam_rest_time; + sme_config->csrConfig.per_roam_config.tx_per_mon_time = + hdd_ctx->config->per_roam_mon_time; + sme_config->csrConfig.per_roam_config.rx_per_mon_time = + hdd_ctx->config->per_roam_mon_time; + + /* Assigning minimum roamable AP RSSI for candidate selection */ + sme_config->csrConfig.per_roam_config.min_candidate_rssi = + hdd_ctx->config->min_candidate_rssi; +} + +/** + * hdd_set_sme_config() -initializes the sme configuration parameters + * + * @pHddCtx: the pointer to hdd context + * + * Return: QDF_STATUS_SUCCESS if configuration is correctly applied, + * otherwise the appropriate QDF_STATUS would be returned + */ +QDF_STATUS hdd_set_sme_config(hdd_context_t *pHddCtx) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tSmeConfigParams *smeConfig; + uint8_t rrm_capab_len; + + struct hdd_config *pConfig = pHddCtx->config; + + smeConfig = qdf_mem_malloc(sizeof(*smeConfig)); + if (NULL == smeConfig) { + hdd_err("unable to allocate smeConfig"); + return QDF_STATUS_E_NOMEM; + } + + hdd_info("%s bWmmIsEnabled=%d 802_11e_enabled=%d dot11Mode=%d", + __func__, pConfig->WmmMode, pConfig->b80211eIsEnabled, + pConfig->dot11Mode); + + /* Config params obtained from the registry + * To Do: set regulatory information here + */ + + smeConfig->csrConfig.RTSThreshold = pConfig->RTSThreshold; + smeConfig->csrConfig.FragmentationThreshold = + pConfig->FragmentationThreshold; + smeConfig->csrConfig.shortSlotTime = pConfig->ShortSlotTimeEnabled; + smeConfig->csrConfig.Is11dSupportEnabled = pConfig->Is11dSupportEnabled; + smeConfig->csrConfig.HeartbeatThresh24 = pConfig->HeartbeatThresh24; + + smeConfig->csrConfig.phyMode = + hdd_cfg_xlate_to_csr_phy_mode(pConfig->dot11Mode); + + if (pConfig->dot11Mode == eHDD_DOT11_MODE_abg || + pConfig->dot11Mode == eHDD_DOT11_MODE_11b || + pConfig->dot11Mode == eHDD_DOT11_MODE_11g || + pConfig->dot11Mode == eHDD_DOT11_MODE_11b_ONLY || + pConfig->dot11Mode == eHDD_DOT11_MODE_11g_ONLY) { + smeConfig->csrConfig.channelBondingMode24GHz = 0; + smeConfig->csrConfig.channelBondingMode5GHz = 0; + } else { + smeConfig->csrConfig.channelBondingMode24GHz = + pConfig->nChannelBondingMode24GHz; + smeConfig->csrConfig.channelBondingMode5GHz = + pConfig->nChannelBondingMode5GHz; + } + smeConfig->csrConfig.TxRate = pConfig->TxRate; + smeConfig->csrConfig.nScanResultAgeCount = pConfig->ScanResultAgeCount; + smeConfig->csrConfig.AdHocChannel24 = pConfig->OperatingChannel; + smeConfig->csrConfig.fSupplicantCountryCodeHasPriority = + pConfig->fSupplicantCountryCodeHasPriority; + smeConfig->csrConfig.bCatRssiOffset = pConfig->nRssiCatGap; + smeConfig->csrConfig.vccRssiThreshold = pConfig->nVccRssiTrigger; + smeConfig->csrConfig.vccUlMacLossThreshold = + pConfig->nVccUlMacLossThreshold; + smeConfig->csrConfig.nInitialDwellTime = pConfig->nInitialDwellTime; + smeConfig->csrConfig.initial_scan_no_dfs_chnl = + pConfig->initial_scan_no_dfs_chnl; + smeConfig->csrConfig.nActiveMaxChnTime = pConfig->nActiveMaxChnTime; + smeConfig->csrConfig.nActiveMinChnTime = pConfig->nActiveMinChnTime; + smeConfig->csrConfig.nPassiveMaxChnTime = pConfig->nPassiveMaxChnTime; + smeConfig->csrConfig.nPassiveMinChnTime = pConfig->nPassiveMinChnTime; + smeConfig->csrConfig.scan_probe_repeat_time = + pConfig->scan_probe_repeat_time; + smeConfig->csrConfig.scan_num_probes = pConfig->scan_num_probes; +#ifdef WLAN_AP_STA_CONCURRENCY + smeConfig->csrConfig.nActiveMaxChnTimeConc = + pConfig->nActiveMaxChnTimeConc; + smeConfig->csrConfig.nActiveMinChnTimeConc = + pConfig->nActiveMinChnTimeConc; + smeConfig->csrConfig.nPassiveMaxChnTimeConc = + pConfig->nPassiveMaxChnTimeConc; + smeConfig->csrConfig.nPassiveMinChnTimeConc = + pConfig->nPassiveMinChnTimeConc; + smeConfig->csrConfig.nRestTimeConc = pConfig->nRestTimeConc; + smeConfig->csrConfig.min_rest_time_conc = pConfig->min_rest_time_conc; + smeConfig->csrConfig.idle_time_conc = pConfig->idle_time_conc; + smeConfig->csrConfig.nNumStaChanCombinedConc = + pConfig->nNumStaChanCombinedConc; + smeConfig->csrConfig.nNumP2PChanCombinedConc = + pConfig->nNumP2PChanCombinedConc; + +#endif + smeConfig->csrConfig.Is11eSupportEnabled = pConfig->b80211eIsEnabled; + smeConfig->csrConfig.WMMSupportMode = pConfig->WmmMode; + + smeConfig->rrmConfig.rrm_enabled = pConfig->fRrmEnable; + smeConfig->rrmConfig.max_randn_interval = pConfig->nRrmRandnIntvl; + hdd_hex_string_to_u8_array(pConfig->rm_capability, + smeConfig->rrmConfig.rm_capability, &rrm_capab_len, + DOT11F_IE_RRMENABLEDCAP_MAX_LEN); + /* Remaining config params not obtained from registry + * On RF EVB beacon using channel 1. + */ + smeConfig->csrConfig.nVhtChannelWidth = pConfig->vhtChannelWidth; + smeConfig->csrConfig.enableTxBF = pConfig->enableTxBF; + smeConfig->csrConfig.enable_txbf_sap_mode = + pConfig->enable_txbf_sap_mode; + smeConfig->csrConfig.enable2x2 = pConfig->enable2x2; + smeConfig->csrConfig.enableVhtFor24GHz = pConfig->enableVhtFor24GHzBand; + smeConfig->csrConfig.vendor_vht_sap = + pConfig->enable_sap_vendor_vht; + smeConfig->csrConfig.enableMuBformee = pConfig->enableMuBformee; + smeConfig->csrConfig.enableVhtpAid = pConfig->enableVhtpAid; + smeConfig->csrConfig.enableVhtGid = pConfig->enableVhtGid; + smeConfig->csrConfig.enableAmpduPs = pConfig->enableAmpduPs; + smeConfig->csrConfig.enableHtSmps = pConfig->enableHtSmps; + smeConfig->csrConfig.htSmps = pConfig->htSmps; + /* This param cannot be configured from INI */ + smeConfig->csrConfig.send_smps_action = true; + smeConfig->csrConfig.AdHocChannel5G = pConfig->AdHocChannel5G; + smeConfig->csrConfig.AdHocChannel24 = pConfig->AdHocChannel24G; + smeConfig->csrConfig.ProprietaryRatesEnabled = 0; + smeConfig->csrConfig.HeartbeatThresh50 = 40; + smeConfig->csrConfig.bandCapability = pConfig->nBandCapability; + if (pConfig->nBandCapability == eCSR_BAND_24) { + smeConfig->csrConfig.Is11hSupportEnabled = 0; + } else { + smeConfig->csrConfig.Is11hSupportEnabled = + pConfig->Is11hSupportEnabled; + } + smeConfig->csrConfig.cbChoice = 0; + smeConfig->csrConfig.eBand = pConfig->nBandCapability; + smeConfig->csrConfig.nTxPowerCap = pConfig->nTxPowerCap; + smeConfig->csrConfig.allow_tpc_from_ap = pConfig->allow_tpc_from_ap; + smeConfig->csrConfig.fEnableBypass11d = pConfig->enableBypass11d; + smeConfig->csrConfig.fEnableDFSChnlScan = pConfig->enableDFSChnlScan; + smeConfig->csrConfig.nRoamPrefer5GHz = pConfig->nRoamPrefer5GHz; + smeConfig->csrConfig.nRoamIntraBand = pConfig->nRoamIntraBand; + smeConfig->csrConfig.nProbes = pConfig->nProbes; + + smeConfig->csrConfig.nRoamScanHomeAwayTime = + pConfig->nRoamScanHomeAwayTime; + smeConfig->csrConfig.fFirstScanOnly2GChnl = + pConfig->enableFirstScan2GOnly; + + smeConfig->csrConfig.Csr11dinfo.Channels.numChannels = 0; + + hdd_set_power_save_offload_config(pHddCtx); + + smeConfig->csrConfig.csr11rConfig.IsFTResourceReqSupported = + pConfig->fFTResourceReqSupported; + smeConfig->csrConfig.isFastRoamIniFeatureEnabled = + pConfig->isFastRoamIniFeatureEnabled; + smeConfig->csrConfig.MAWCEnabled = pConfig->MAWCEnabled; +#ifdef FEATURE_WLAN_ESE + smeConfig->csrConfig.isEseIniFeatureEnabled = + pConfig->isEseIniFeatureEnabled; + if (pConfig->isEseIniFeatureEnabled) { + pConfig->isFastTransitionEnabled = true; + } +#endif + smeConfig->csrConfig.isFastTransitionEnabled = + pConfig->isFastTransitionEnabled; + smeConfig->csrConfig.RoamRssiDiff = pConfig->RoamRssiDiff; + smeConfig->csrConfig.isWESModeEnabled = pConfig->isWESModeEnabled; + smeConfig->csrConfig.isRoamOffloadScanEnabled = + pConfig->isRoamOffloadScanEnabled; + smeConfig->csrConfig.bFastRoamInConIniFeatureEnabled = + pConfig->bFastRoamInConIniFeatureEnabled; + + if (0 == smeConfig->csrConfig.isRoamOffloadScanEnabled) { + /* Disable roaming in concurrency if roam scan offload is disabled */ + smeConfig->csrConfig.bFastRoamInConIniFeatureEnabled = 0; + } + smeConfig->csrConfig.neighborRoamConfig.nNeighborLookupRssiThreshold = + pConfig->nNeighborLookupRssiThreshold; + smeConfig->csrConfig.neighborRoamConfig.delay_before_vdev_stop = + pConfig->delay_before_vdev_stop; + smeConfig->csrConfig.neighborRoamConfig.nOpportunisticThresholdDiff = + pConfig->nOpportunisticThresholdDiff; + smeConfig->csrConfig.neighborRoamConfig.nRoamRescanRssiDiff = + pConfig->nRoamRescanRssiDiff; + smeConfig->csrConfig.neighborRoamConfig.nNeighborScanMaxChanTime = + pConfig->nNeighborScanMaxChanTime; + smeConfig->csrConfig.neighborRoamConfig.nNeighborScanMinChanTime = + pConfig->nNeighborScanMinChanTime; + smeConfig->csrConfig.neighborRoamConfig.nNeighborScanTimerPeriod = + pConfig->nNeighborScanPeriod; + smeConfig->csrConfig.neighborRoamConfig.nMaxNeighborRetries = + pConfig->nMaxNeighborReqTries; + smeConfig->csrConfig.neighborRoamConfig.nNeighborResultsRefreshPeriod = + pConfig->nNeighborResultsRefreshPeriod; + smeConfig->csrConfig.neighborRoamConfig.nEmptyScanRefreshPeriod = + pConfig->nEmptyScanRefreshPeriod; + hdd_string_to_u8_array(pConfig->neighborScanChanList, + smeConfig->csrConfig.neighborRoamConfig. + neighborScanChanList.channelList, + &smeConfig->csrConfig.neighborRoamConfig. + neighborScanChanList.numChannels, + WNI_CFG_VALID_CHANNEL_LIST_LEN); + smeConfig->csrConfig.neighborRoamConfig.nRoamBmissFirstBcnt = + pConfig->nRoamBmissFirstBcnt; + smeConfig->csrConfig.neighborRoamConfig.nRoamBmissFinalBcnt = + pConfig->nRoamBmissFinalBcnt; + smeConfig->csrConfig.neighborRoamConfig.nRoamBeaconRssiWeight = + pConfig->nRoamBeaconRssiWeight; + smeConfig->csrConfig.neighborRoamConfig.nhi_rssi_scan_max_count = + pConfig->nhi_rssi_scan_max_count; + smeConfig->csrConfig.neighborRoamConfig.nhi_rssi_scan_rssi_delta = + pConfig->nhi_rssi_scan_rssi_delta; + smeConfig->csrConfig.neighborRoamConfig.nhi_rssi_scan_delay = + pConfig->nhi_rssi_scan_delay; + smeConfig->csrConfig.neighborRoamConfig.nhi_rssi_scan_rssi_ub = + pConfig->nhi_rssi_scan_rssi_ub; + smeConfig->csrConfig.addTSWhenACMIsOff = pConfig->AddTSWhenACMIsOff; + smeConfig->csrConfig.fValidateList = pConfig->fValidateScanList; + smeConfig->csrConfig.allowDFSChannelRoam = pConfig->allowDFSChannelRoam; + + /* Enable/Disable MCC */ + smeConfig->csrConfig.fEnableMCCMode = pConfig->enableMCC; + smeConfig->csrConfig.mcc_rts_cts_prot_enable = + pConfig->mcc_rts_cts_prot_enable; + smeConfig->csrConfig.mcc_bcast_prob_resp_enable = + pConfig->mcc_bcast_prob_resp_enable; + smeConfig->csrConfig.fAllowMCCGODiffBI = pConfig->allowMCCGODiffBI; + + /* Scan Results Aging Time out value */ + smeConfig->csrConfig.scanCfgAgingTime = pConfig->scanAgingTimeout; + + smeConfig->csrConfig.enableTxLdpc = pConfig->enableTxLdpc; + smeConfig->csrConfig.enableRxLDPC = pConfig->enableRxLDPC; + smeConfig->csrConfig.disable_high_ht_mcs_2x2 = + pConfig->disable_high_ht_mcs_2x2; +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH + smeConfig->csrConfig.cc_switch_mode = pConfig->WlanMccToSccSwitchMode; +#endif + + smeConfig->csrConfig.max_amsdu_num = pConfig->max_amsdu_num; + smeConfig->csrConfig.nSelect5GHzMargin = pConfig->nSelect5GHzMargin; + + smeConfig->csrConfig.isCoalesingInIBSSAllowed = + pHddCtx->config->isCoalesingInIBSSAllowed; + smeConfig->csrConfig.ignore_peer_erp_info = + pConfig->ignore_peer_erp_info; + /* update SSR config */ + sme_update_enable_ssr((tHalHandle) (pHddCtx->hHal), + pHddCtx->config->enableSSR); + +#ifdef FEATURE_WLAN_SCAN_PNO + /* Update PNO offoad status */ + smeConfig->csrConfig.pnoOffload = pHddCtx->config->PnoOffload; +#endif + + /* Update maximum interfaces information */ + smeConfig->csrConfig.max_intf_count = pHddCtx->max_intf_count; + + smeConfig->csrConfig.fEnableDebugLog = pHddCtx->config->gEnableDebugLog; + + smeConfig->csrConfig.enable5gEBT = pHddCtx->config->enable5gEBT; + + smeConfig->csrConfig.enableSelfRecovery = + pHddCtx->config->enableSelfRecovery; +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + smeConfig->csrConfig.isRoamOffloadEnabled = + pHddCtx->config->isRoamOffloadEnabled; +#endif + smeConfig->csrConfig.conc_custom_rule1 = + pHddCtx->config->conc_custom_rule1; + smeConfig->csrConfig.conc_custom_rule2 = + pHddCtx->config->conc_custom_rule2; + smeConfig->csrConfig.is_sta_connection_in_5gz_enabled = + pHddCtx->config->is_sta_connection_in_5gz_enabled; + + smeConfig->csrConfig.f_sta_miracast_mcc_rest_time_val = + pHddCtx->config->sta_miracast_mcc_rest_time_val; + +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE + smeConfig->csrConfig.sap_channel_avoidance = + pHddCtx->config->sap_channel_avoidance; +#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ + + smeConfig->csrConfig.f_prefer_non_dfs_on_radar = + pHddCtx->config->prefer_non_dfs_on_radar; + + smeConfig->csrConfig.is_ps_enabled = pHddCtx->config->is_ps_enabled; + smeConfig->csrConfig.auto_bmps_timer_val = + pHddCtx->config->auto_bmps_timer_val; + hdd_set_fine_time_meas_cap(pHddCtx, smeConfig); + + cds_set_multicast_logging(pHddCtx->config->multicast_host_fw_msgs); + + smeConfig->csrConfig.sendDeauthBeforeCon = pConfig->sendDeauthBeforeCon; + + smeConfig->csrConfig.max_scan_count = + pHddCtx->config->max_scan_count; + + /* Update 802.11p config */ + smeConfig->csrConfig.enable_dot11p = + (pHddCtx->config->dot11p_mode != WLAN_HDD_11P_DISABLED); + hdd_set_pno_channel_prediction_config(smeConfig, pHddCtx); + + smeConfig->csrConfig.early_stop_scan_enable = + pHddCtx->config->early_stop_scan_enable; + smeConfig->csrConfig.early_stop_scan_min_threshold = + pHddCtx->config->early_stop_scan_min_threshold; + smeConfig->csrConfig.early_stop_scan_max_threshold = + pHddCtx->config->early_stop_scan_max_threshold; + smeConfig->csrConfig.first_scan_bucket_threshold = + pHddCtx->config->first_scan_bucket_threshold; + + smeConfig->csrConfig.roam_dense_rssi_thresh_offset = + pHddCtx->config->roam_dense_rssi_thresh_offset; + smeConfig->csrConfig.roam_dense_min_aps = + pHddCtx->config->roam_dense_min_aps; + smeConfig->csrConfig.roam_dense_traffic_thresh = + pHddCtx->config->roam_dense_traffic_thresh; + smeConfig->csrConfig.obss_width_interval = + pHddCtx->config->obss_width_trigger_interval; + smeConfig->csrConfig.obss_active_dwelltime = + pHddCtx->config->obss_active_dwelltime; + smeConfig->csrConfig.obss_passive_dwelltime = + pHddCtx->config->obss_passive_dwelltime; + smeConfig->csrConfig.ignore_peer_ht_opmode = + pConfig->ignore_peer_ht_opmode; + smeConfig->csrConfig.enable_fatal_event = + pConfig->enable_fatal_event; + smeConfig->csrConfig.scan_adaptive_dwell_mode = + pHddCtx->config->scan_adaptive_dwell_mode; + smeConfig->csrConfig.roamscan_adaptive_dwell_mode = + pHddCtx->config->roamscan_adaptive_dwell_mode; + + hdd_update_per_config_to_sme(pHddCtx, smeConfig); + + smeConfig->csrConfig.enable_edca_params = + pConfig->enable_edca_params; + + smeConfig->csrConfig.edca_vo_cwmin = + pConfig->edca_vo_cwmin; + smeConfig->csrConfig.edca_vi_cwmin = + pConfig->edca_vi_cwmin; + smeConfig->csrConfig.edca_bk_cwmin = + pConfig->edca_bk_cwmin; + smeConfig->csrConfig.edca_be_cwmin = + pConfig->edca_be_cwmin; + + smeConfig->csrConfig.edca_vo_cwmax = + pConfig->edca_vo_cwmax; + smeConfig->csrConfig.edca_vi_cwmax = + pConfig->edca_vi_cwmax; + smeConfig->csrConfig.edca_bk_cwmax = + pConfig->edca_bk_cwmax; + smeConfig->csrConfig.edca_be_cwmax = + pConfig->edca_be_cwmax; + + smeConfig->csrConfig.edca_vo_aifs = + pConfig->edca_vo_aifs; + smeConfig->csrConfig.edca_vi_aifs = + pConfig->edca_vi_aifs; + smeConfig->csrConfig.edca_bk_aifs = + pConfig->edca_bk_aifs; + smeConfig->csrConfig.edca_be_aifs = + pConfig->edca_be_aifs; + smeConfig->csrConfig.sta_roam_policy_params.dfs_mode = + CSR_STA_ROAM_POLICY_DFS_ENABLED; + smeConfig->csrConfig.sta_roam_policy_params.skip_unsafe_channels = 0; + + smeConfig->csrConfig.tx_aggregation_size = + pHddCtx->config->tx_aggregation_size; + smeConfig->csrConfig.rx_aggregation_size = + pHddCtx->config->rx_aggregation_size; + smeConfig->csrConfig.enable_bcast_probe_rsp = + pHddCtx->config->enable_bcast_probe_rsp; + smeConfig->csrConfig.qcn_ie_support = + pHddCtx->config->qcn_ie_support; + smeConfig->csrConfig.fils_max_chan_guard_time = + pHddCtx->config->fils_max_chan_guard_time; + smeConfig->csrConfig.pkt_err_disconn_th = + pHddCtx->config->pkt_err_disconn_th; + smeConfig->csrConfig.is_bssid_hint_priority = + pHddCtx->config->is_bssid_hint_priority; + smeConfig->csrConfig.is_force_1x1 = + pHddCtx->config->is_force_1x1; + smeConfig->csrConfig.num_11b_tx_chains = + pHddCtx->config->num_11b_tx_chains; + smeConfig->csrConfig.num_11ag_tx_chains = + pHddCtx->config->num_11ag_tx_chains; + + status = sme_update_config(pHddCtx->hHal, smeConfig); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("sme_update_config() return failure %d", + status); + } + + qdf_mem_free(smeConfig); + return status; +} + +/** + * hdd_execute_global_config_command() - execute the global config command + * @pHddCtx: the pointer to hdd context + * @command: the command to run + * + * Return: the QDF_STATUS return from hdd_execute_config_command + */ +QDF_STATUS hdd_execute_global_config_command(hdd_context_t *pHddCtx, + char *command) +{ + return hdd_execute_config_command(g_registry_table, + ARRAY_SIZE(g_registry_table), + (uint8_t *) pHddCtx->config, + pHddCtx, command); +} + +/** + * hdd_cfg_get_global_config() - get the configuration table + * @pHddCtx: pointer to hdd context + * @pBuf: buffer to store the configuration + * @buflen: size of the buffer + * + * Return: QDF_STATUS_SUCCESS if the configuration and buffer size can carry + * the content, otherwise QDF_STATUS_E_RESOURCES + */ +QDF_STATUS hdd_cfg_get_global_config(hdd_context_t *pHddCtx, char *pBuf, + int buflen) +{ + return hdd_cfg_get_config(g_registry_table, + ARRAY_SIZE(g_registry_table), + (uint8_t *) pHddCtx->config, pHddCtx, pBuf, + buflen); +} + +/** + * hdd_get_pmkid_modes() - returns PMKID mode bits + * @pHddCtx: the pointer to hdd context + * + * Return: value of pmkid_modes + */ +void hdd_get_pmkid_modes(hdd_context_t *pHddCtx, + struct pmkid_mode_bits *pmkid_modes) +{ + pmkid_modes->fw_okc = (pHddCtx->config->pmkid_modes & + CFG_PMKID_MODES_OKC) ? 1 : 0; + pmkid_modes->fw_pmksa_cache = (pHddCtx->config->pmkid_modes & + CFG_PMKID_MODES_PMKSA_CACHING) ? 1 : 0; +} + +/** + * hdd_update_nss() - Update the number of spatial streams supported. + * Ensure that nss is either 1 or 2 before calling this. + * + * @hdd_ctx: the pointer to hdd context + * @nss: the number of spatial streams to be updated + * + * This function is used to modify the number of spatial streams + * supported when not in connected state. + * + * Return: QDF_STATUS_SUCCESS if nss is correctly updated, + * otherwise QDF_STATUS_E_FAILURE would be returned + */ +QDF_STATUS hdd_update_nss(hdd_context_t *hdd_ctx, uint8_t nss) +{ + struct hdd_config *hdd_config = hdd_ctx->config; + uint32_t temp = 0; + uint32_t rx_supp_data_rate, tx_supp_data_rate; + bool status = true; + tSirMacHTCapabilityInfo *ht_cap_info; + uint8_t mcs_set[SIZE_OF_SUPPORTED_MCS_SET] = {0}; + uint8_t mcs_set_temp[SIZE_OF_SUPPORTED_MCS_SET]; + uint32_t val, val32; + uint16_t val16; + uint8_t enable2x2; + + if ((nss == 2) && (hdd_ctx->num_rf_chains != 2)) { + hdd_err("No support for 2 spatial streams"); + return QDF_STATUS_E_INVAL; + } + + enable2x2 = (nss == 1) ? 0 : 1; + + if (hdd_config->enable2x2 == enable2x2) { + hdd_err("NSS same as requested"); + return QDF_STATUS_SUCCESS; + } + + if (true == sme_is_any_session_in_connected_state(hdd_ctx->hHal)) { + hdd_err("Connected sessions present, Do not change NSS"); + return QDF_STATUS_E_INVAL; + } + + hdd_config->enable2x2 = enable2x2; + + if (!hdd_config->enable2x2) { + /* 1x1 */ + rx_supp_data_rate = VHT_RX_HIGHEST_SUPPORTED_DATA_RATE_1_1; + tx_supp_data_rate = VHT_TX_HIGHEST_SUPPORTED_DATA_RATE_1_1; + } else { + /* 2x2 */ + rx_supp_data_rate = VHT_RX_HIGHEST_SUPPORTED_DATA_RATE_2_2; + tx_supp_data_rate = VHT_TX_HIGHEST_SUPPORTED_DATA_RATE_2_2; + } + + /* Update Rx Highest Long GI data Rate */ + if (sme_cfg_set_int(hdd_ctx->hHal, + WNI_CFG_VHT_RX_HIGHEST_SUPPORTED_DATA_RATE, + rx_supp_data_rate) == QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Could not pass on WNI_CFG_VHT_RX_HIGHEST_SUPPORTED_DATA_RATE to CFG"); + } + + /* Update Tx Highest Long GI data Rate */ + if (sme_cfg_set_int(hdd_ctx->hHal, + WNI_CFG_VHT_TX_HIGHEST_SUPPORTED_DATA_RATE, + tx_supp_data_rate) == QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Could not pass on WNI_CFG_VHT_TX_HIGHEST_SUPPORTED_DATA_RATE to CFG"); + } + + sme_cfg_get_int(hdd_ctx->hHal, WNI_CFG_HT_CAP_INFO, &temp); + val16 = (uint16_t)temp; + ht_cap_info = (tSirMacHTCapabilityInfo *)&val16; + if (!(hdd_ctx->ht_tx_stbc_supported && hdd_config->enable2x2)) { + ht_cap_info->txSTBC = 0; + } else { + sme_cfg_get_int(hdd_ctx->hHal, WNI_CFG_VHT_TXSTBC, &val32); + hdd_notice("STBC %d", val32); + ht_cap_info->txSTBC = val32; + } + temp = val16; + if (sme_cfg_set_int(hdd_ctx->hHal, WNI_CFG_HT_CAP_INFO, + temp) == QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Could not pass on WNI_CFG_HT_CAP_INFO to CFG"); + } + + sme_cfg_get_int(hdd_ctx->hHal, WNI_CFG_VHT_BASIC_MCS_SET, &temp); + temp = (temp & 0xFFFC) | hdd_config->vhtRxMCS; + if (hdd_config->enable2x2) + temp = (temp & 0xFFF3) | (hdd_config->vhtRxMCS2x2 << 2); + else + temp |= 0x000C; + + if (sme_cfg_set_int(hdd_ctx->hHal, WNI_CFG_VHT_BASIC_MCS_SET, + temp) == QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Could not pass on WNI_CFG_VHT_BASIC_MCS_SET to CFG"); + } + + sme_cfg_get_int(hdd_ctx->hHal, WNI_CFG_VHT_RX_MCS_MAP, &temp); + temp = (temp & 0xFFFC) | hdd_config->vhtRxMCS; + if (hdd_config->enable2x2) + temp = (temp & 0xFFF3) | (hdd_config->vhtRxMCS2x2 << 2); + else + temp |= 0x000C; + + if (sme_cfg_set_int(hdd_ctx->hHal, WNI_CFG_VHT_RX_MCS_MAP, + temp) == QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Could not pass on WNI_CFG_VHT_RX_MCS_MAP to CFG"); + } + + sme_cfg_get_int(hdd_ctx->hHal, WNI_CFG_VHT_TX_MCS_MAP, &temp); + temp = (temp & 0xFFFC) | hdd_config->vhtTxMCS; + if (hdd_config->enable2x2) + temp = (temp & 0xFFF3) | (hdd_config->vhtTxMCS2x2 << 2); + else + temp |= 0x000C; + + if (sme_cfg_set_int(hdd_ctx->hHal, WNI_CFG_VHT_TX_MCS_MAP, + temp) == QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Could not pass on WNI_CFG_VHT_TX_MCS_MAP to CFG"); + } + +#define WLAN_HDD_RX_MCS_ALL_NSTREAM_RATES 0xff + val = SIZE_OF_SUPPORTED_MCS_SET; + sme_cfg_get_str(hdd_ctx->hHal, WNI_CFG_SUPPORTED_MCS_SET, + mcs_set_temp, &val); + + mcs_set[0] = mcs_set_temp[0]; + if (hdd_config->enable2x2) + for (val = 0; val < nss; val++) + mcs_set[val] = WLAN_HDD_RX_MCS_ALL_NSTREAM_RATES; + + if (sme_cfg_set_str(hdd_ctx->hHal, WNI_CFG_SUPPORTED_MCS_SET, + mcs_set, + SIZE_OF_SUPPORTED_MCS_SET) == + QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Could not pass on MCS SET to CFG"); + } +#undef WLAN_HDD_RX_MCS_ALL_NSTREAM_RATES + + if (QDF_STATUS_SUCCESS != sme_update_nss(hdd_ctx->hHal, nss)) + status = false; + + return (status == false) ? QDF_STATUS_E_FAILURE : QDF_STATUS_SUCCESS; +} diff --git a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_cfg80211.c b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_cfg80211.c new file mode 100644 index 0000000000000000000000000000000000000000..069cbb31a79533559295f212e303d3c4453b5338 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_cfg80211.c @@ -0,0 +1,16532 @@ +/* + * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: wlan_hdd_cfg80211.c + * + * WLAN Host Device Driver cfg80211 APIs implementation + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "sir_params.h" +#include "dot11f.h" +#include "wlan_hdd_assoc.h" +#include "wlan_hdd_wext.h" +#include "sme_api.h" +#include "sme_power_save_api.h" +#include "wlan_hdd_p2p.h" +#include "wlan_hdd_cfg80211.h" +#include "wlan_hdd_hostapd.h" +#include "wlan_hdd_softap_tx_rx.h" +#include "wlan_hdd_main.h" +#include "wlan_hdd_power.h" +#include "wlan_hdd_trace.h" +#include "qdf_types.h" +#include "qdf_trace.h" +#include "cds_utils.h" +#include "cds_sched.h" +#include "wlan_hdd_scan.h" +#include +#include "wlan_hdd_tdls.h" +#include "wlan_hdd_wmm.h" +#include "wma_types.h" +#include "wma.h" +#include "wlan_hdd_misc.h" +#include "wlan_hdd_nan.h" +#include +#include "wlan_logging_sock_svc.h" +#include "sap_api.h" +#include "csr_api.h" +#include "pld_common.h" + + +#ifdef FEATURE_WLAN_EXTSCAN +#include "wlan_hdd_ext_scan.h" +#endif + +#ifdef WLAN_FEATURE_LINK_LAYER_STATS +#include "wlan_hdd_stats.h" +#endif +#include "cds_concurrency.h" +#include "qwlan_version.h" +#include "wlan_hdd_memdump.h" + +#include "wlan_hdd_ocb.h" +#include "wlan_hdd_tsf.h" +#include "ol_txrx.h" + +#include "wlan_hdd_subnet_detect.h" +#include +#include "wlan_hdd_lpass.h" +#include "wlan_hdd_nan_datapath.h" +#include "wlan_hdd_disa.h" + +#define g_mode_rates_size (12) +#define a_mode_rates_size (8) +#define GET_IE_LEN_IN_BSS_DESC(lenInBss) (lenInBss + sizeof(lenInBss) - \ + ((uintptr_t)OFFSET_OF(tSirBssDescription, ieFields))) + +/* + * Android CTS verifier needs atleast this much wait time (in msec) + */ +#define MAX_REMAIN_ON_CHANNEL_DURATION (5000) + +/* + * Refer @tCfgProtection structure for definition of the bit map. + * below value is obtained by setting the following bit-fields. + * enable obss, fromllb, overlapOBSS and overlapFromllb protection. + */ +#define IBSS_CFG_PROTECTION_ENABLE_MASK 0x8282 + +#define HDD2GHZCHAN(freq, chan, flag) { \ + .band = NL80211_BAND_2GHZ, \ + .center_freq = (freq), \ + .hw_value = (chan), \ + .flags = (flag), \ + .max_antenna_gain = 0, \ + .max_power = 30, \ +} + +#define HDD5GHZCHAN(freq, chan, flag) { \ + .band = NL80211_BAND_5GHZ, \ + .center_freq = (freq), \ + .hw_value = (chan), \ + .flags = (flag), \ + .max_antenna_gain = 0, \ + .max_power = 30, \ +} + +#define HDD_G_MODE_RATETAB(rate, rate_id, flag) \ + { \ + .bitrate = rate, \ + .hw_value = rate_id, \ + .flags = flag, \ + } + +#define WLAN_AKM_SUITE_FT_8021X 0x000FAC03 +#define WLAN_AKM_SUITE_FT_PSK 0x000FAC04 + +#define HDD_CHANNEL_14 14 + +#define IS_DFS_MODE_VALID(mode) ((mode >= DFS_MODE_NONE && \ + mode <= DFS_MODE_DEPRIORITIZE)) + +#define MAX_TXPOWER_SCALE 4 +#define CDS_MAX_FEATURE_SET 8 + +static const u32 hdd_cipher_suites[] = { + WLAN_CIPHER_SUITE_WEP40, + WLAN_CIPHER_SUITE_WEP104, + WLAN_CIPHER_SUITE_TKIP, +#ifdef FEATURE_WLAN_ESE +#define WLAN_CIPHER_SUITE_BTK 0x004096fe /* use for BTK */ +#define WLAN_CIPHER_SUITE_KRK 0x004096ff /* use for KRK */ + WLAN_CIPHER_SUITE_BTK, + WLAN_CIPHER_SUITE_KRK, + WLAN_CIPHER_SUITE_CCMP, +#else + WLAN_CIPHER_SUITE_CCMP, +#endif +#ifdef FEATURE_WLAN_WAPI + WLAN_CIPHER_SUITE_SMS4, +#endif +#ifdef WLAN_FEATURE_11W + WLAN_CIPHER_SUITE_AES_CMAC, +#endif +}; + +static const struct ieee80211_channel hdd_channels_2_4_ghz[] = { + HDD2GHZCHAN(2412, 1, 0), + HDD2GHZCHAN(2417, 2, 0), + HDD2GHZCHAN(2422, 3, 0), + HDD2GHZCHAN(2427, 4, 0), + HDD2GHZCHAN(2432, 5, 0), + HDD2GHZCHAN(2437, 6, 0), + HDD2GHZCHAN(2442, 7, 0), + HDD2GHZCHAN(2447, 8, 0), + HDD2GHZCHAN(2452, 9, 0), + HDD2GHZCHAN(2457, 10, 0), + HDD2GHZCHAN(2462, 11, 0), + HDD2GHZCHAN(2467, 12, 0), + HDD2GHZCHAN(2472, 13, 0), + HDD2GHZCHAN(2484, 14, 0), +}; + +static const struct ieee80211_channel hdd_channels_5_ghz[] = { + HDD5GHZCHAN(5180, 36, 0), + HDD5GHZCHAN(5200, 40, 0), + HDD5GHZCHAN(5220, 44, 0), + HDD5GHZCHAN(5240, 48, 0), + HDD5GHZCHAN(5260, 52, 0), + HDD5GHZCHAN(5280, 56, 0), + HDD5GHZCHAN(5300, 60, 0), + HDD5GHZCHAN(5320, 64, 0), + HDD5GHZCHAN(5500, 100, 0), + HDD5GHZCHAN(5520, 104, 0), + HDD5GHZCHAN(5540, 108, 0), + HDD5GHZCHAN(5560, 112, 0), + HDD5GHZCHAN(5580, 116, 0), + HDD5GHZCHAN(5600, 120, 0), + HDD5GHZCHAN(5620, 124, 0), + HDD5GHZCHAN(5640, 128, 0), + HDD5GHZCHAN(5660, 132, 0), + HDD5GHZCHAN(5680, 136, 0), + HDD5GHZCHAN(5700, 140, 0), + HDD5GHZCHAN(5720, 144, 0), + HDD5GHZCHAN(5745, 149, 0), + HDD5GHZCHAN(5765, 153, 0), + HDD5GHZCHAN(5785, 157, 0), + HDD5GHZCHAN(5805, 161, 0), + HDD5GHZCHAN(5825, 165, 0), + HDD5GHZCHAN(5852, 170, 0), + HDD5GHZCHAN(5855, 171, 0), + HDD5GHZCHAN(5860, 172, 0), + HDD5GHZCHAN(5865, 173, 0), + HDD5GHZCHAN(5870, 174, 0), + HDD5GHZCHAN(5875, 175, 0), + HDD5GHZCHAN(5880, 176, 0), + HDD5GHZCHAN(5885, 177, 0), + HDD5GHZCHAN(5890, 178, 0), + HDD5GHZCHAN(5895, 179, 0), + HDD5GHZCHAN(5900, 180, 0), + HDD5GHZCHAN(5905, 181, 0), + HDD5GHZCHAN(5910, 182, 0), + HDD5GHZCHAN(5915, 183, 0), + HDD5GHZCHAN(5920, 184, 0), +}; + +static struct ieee80211_rate g_mode_rates[] = { + HDD_G_MODE_RATETAB(10, 0x1, 0), + HDD_G_MODE_RATETAB(20, 0x2, 0), + HDD_G_MODE_RATETAB(55, 0x4, 0), + HDD_G_MODE_RATETAB(110, 0x8, 0), + HDD_G_MODE_RATETAB(60, 0x10, 0), + HDD_G_MODE_RATETAB(90, 0x20, 0), + HDD_G_MODE_RATETAB(120, 0x40, 0), + HDD_G_MODE_RATETAB(180, 0x80, 0), + HDD_G_MODE_RATETAB(240, 0x100, 0), + HDD_G_MODE_RATETAB(360, 0x200, 0), + HDD_G_MODE_RATETAB(480, 0x400, 0), + HDD_G_MODE_RATETAB(540, 0x800, 0), +}; + +static struct ieee80211_rate a_mode_rates[] = { + HDD_G_MODE_RATETAB(60, 0x10, 0), + HDD_G_MODE_RATETAB(90, 0x20, 0), + HDD_G_MODE_RATETAB(120, 0x40, 0), + HDD_G_MODE_RATETAB(180, 0x80, 0), + HDD_G_MODE_RATETAB(240, 0x100, 0), + HDD_G_MODE_RATETAB(360, 0x200, 0), + HDD_G_MODE_RATETAB(480, 0x400, 0), + HDD_G_MODE_RATETAB(540, 0x800, 0), +}; + +static struct ieee80211_supported_band wlan_hdd_band_2_4_ghz = { + .channels = NULL, + .n_channels = ARRAY_SIZE(hdd_channels_2_4_ghz), + .band = NL80211_BAND_2GHZ, + .bitrates = g_mode_rates, + .n_bitrates = g_mode_rates_size, + .ht_cap.ht_supported = 1, + .ht_cap.cap = IEEE80211_HT_CAP_SGI_20 + | IEEE80211_HT_CAP_GRN_FLD + | IEEE80211_HT_CAP_DSSSCCK40 + | IEEE80211_HT_CAP_LSIG_TXOP_PROT + | IEEE80211_HT_CAP_SGI_40 | IEEE80211_HT_CAP_SUP_WIDTH_20_40, + .ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K, + .ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_16, + .ht_cap.mcs.rx_mask = {0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0,}, + .ht_cap.mcs.rx_highest = cpu_to_le16(72), + .ht_cap.mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED, +}; + +static struct ieee80211_supported_band wlan_hdd_band_5_ghz = { + .channels = NULL, + .n_channels = ARRAY_SIZE(hdd_channels_5_ghz), + .band = NL80211_BAND_5GHZ, + .bitrates = a_mode_rates, + .n_bitrates = a_mode_rates_size, + .ht_cap.ht_supported = 1, + .ht_cap.cap = IEEE80211_HT_CAP_SGI_20 + | IEEE80211_HT_CAP_GRN_FLD + | IEEE80211_HT_CAP_DSSSCCK40 + | IEEE80211_HT_CAP_LSIG_TXOP_PROT + | IEEE80211_HT_CAP_SGI_40 | IEEE80211_HT_CAP_SUP_WIDTH_20_40, + .ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K, + .ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_16, + .ht_cap.mcs.rx_mask = {0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0,}, + .ht_cap.mcs.rx_highest = cpu_to_le16(72), + .ht_cap.mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED, + .vht_cap.vht_supported = 1, +}; + +/* This structure contain information what kind of frame are expected in + TX/RX direction for each kind of interface */ +static const struct ieee80211_txrx_stypes + wlan_hdd_txrx_stypes[NUM_NL80211_IFTYPES] = { + [NL80211_IFTYPE_STATION] = { + .tx = 0xffff, + .rx = BIT(SIR_MAC_MGMT_ACTION) | + BIT(SIR_MAC_MGMT_PROBE_REQ), + }, + [NL80211_IFTYPE_AP] = { + .tx = 0xffff, + .rx = BIT(SIR_MAC_MGMT_ASSOC_REQ) | + BIT(SIR_MAC_MGMT_REASSOC_REQ) | + BIT(SIR_MAC_MGMT_PROBE_REQ) | + BIT(SIR_MAC_MGMT_DISASSOC) | + BIT(SIR_MAC_MGMT_AUTH) | + BIT(SIR_MAC_MGMT_DEAUTH) | + BIT(SIR_MAC_MGMT_ACTION), + }, + [NL80211_IFTYPE_ADHOC] = { + .tx = 0xffff, + .rx = BIT(SIR_MAC_MGMT_ASSOC_REQ) | + BIT(SIR_MAC_MGMT_REASSOC_REQ) | + BIT(SIR_MAC_MGMT_PROBE_REQ) | + BIT(SIR_MAC_MGMT_DISASSOC) | + BIT(SIR_MAC_MGMT_AUTH) | + BIT(SIR_MAC_MGMT_DEAUTH) | + BIT(SIR_MAC_MGMT_ACTION), + }, + [NL80211_IFTYPE_P2P_CLIENT] = { + .tx = 0xffff, + .rx = BIT(SIR_MAC_MGMT_ACTION) | + BIT(SIR_MAC_MGMT_PROBE_REQ), + }, + [NL80211_IFTYPE_P2P_GO] = { + /* This is also same as for SoftAP */ + .tx = 0xffff, + .rx = BIT(SIR_MAC_MGMT_ASSOC_REQ) | + BIT(SIR_MAC_MGMT_REASSOC_REQ) | + BIT(SIR_MAC_MGMT_PROBE_REQ) | + BIT(SIR_MAC_MGMT_DISASSOC) | + BIT(SIR_MAC_MGMT_AUTH) | + BIT(SIR_MAC_MGMT_DEAUTH) | + BIT(SIR_MAC_MGMT_ACTION), + }, +}; + +/* Interface limits and combinations registered by the driver */ + +/* STA ( + STA ) combination */ +static const struct ieee80211_iface_limit + wlan_hdd_sta_iface_limit[] = { + { + .max = 3, /* p2p0 is a STA as well */ + .types = BIT(NL80211_IFTYPE_STATION), + }, +}; + +/* ADHOC (IBSS) limit */ +static const struct ieee80211_iface_limit + wlan_hdd_adhoc_iface_limit[] = { + { + .max = 1, + .types = BIT(NL80211_IFTYPE_STATION), + }, + { + .max = 1, + .types = BIT(NL80211_IFTYPE_ADHOC), + }, +}; + +/* AP ( + AP ) combination */ +static const struct ieee80211_iface_limit + wlan_hdd_ap_iface_limit[] = { + { + .max = (QDF_MAX_NO_OF_SAP_MODE + SAP_MAX_OBSS_STA_CNT), + .types = BIT(NL80211_IFTYPE_AP), + }, +}; + +/* P2P limit */ +static const struct ieee80211_iface_limit + wlan_hdd_p2p_iface_limit[] = { + { + .max = 1, + .types = BIT(NL80211_IFTYPE_P2P_CLIENT), + }, + { + .max = 1, + .types = BIT(NL80211_IFTYPE_P2P_GO), + }, +}; + +static const struct ieee80211_iface_limit + wlan_hdd_sta_ap_iface_limit[] = { + { + /* We need 1 extra STA interface for OBSS scan when SAP starts + * with HT40 in STA+SAP concurrency mode + */ + .max = (1 + SAP_MAX_OBSS_STA_CNT), + .types = BIT(NL80211_IFTYPE_STATION), + }, + { + .max = QDF_MAX_NO_OF_SAP_MODE, + .types = BIT(NL80211_IFTYPE_AP), + }, +}; + +/* STA + P2P combination */ +static const struct ieee80211_iface_limit + wlan_hdd_sta_p2p_iface_limit[] = { + { + /* One reserved for dedicated P2PDEV usage */ + .max = 2, + .types = BIT(NL80211_IFTYPE_STATION) + }, + { + /* Support for two identical (GO + GO or CLI + CLI) + * or dissimilar (GO + CLI) P2P interfaces + */ + .max = 2, + .types = BIT(NL80211_IFTYPE_P2P_GO) | BIT(NL80211_IFTYPE_P2P_CLIENT), + }, +}; + +/* STA + AP + P2PGO combination */ +static const struct ieee80211_iface_limit +wlan_hdd_sta_ap_p2pgo_iface_limit[] = { + /* Support for AP+P2PGO interfaces */ + { + .max = 2, + .types = BIT(NL80211_IFTYPE_STATION) + }, + { + .max = 1, + .types = BIT(NL80211_IFTYPE_P2P_GO) + }, + { + .max = 1, + .types = BIT(NL80211_IFTYPE_AP) + } +}; + +/* SAP + P2P combination */ +static const struct ieee80211_iface_limit +wlan_hdd_sap_p2p_iface_limit[] = { + { + /* 1 dedicated for p2p0 which is a STA type */ + .max = 1, + .types = BIT(NL80211_IFTYPE_STATION) + }, + { + /* The p2p interface in SAP+P2P can be GO/CLI. + * The p2p connection can be formed on p2p0 or p2p-p2p0-x. + */ + .max = 1, + .types = BIT(NL80211_IFTYPE_P2P_GO) | BIT(NL80211_IFTYPE_P2P_CLIENT) + }, + { + /* SAP+GO to support only one SAP interface */ + .max = 1, + .types = BIT(NL80211_IFTYPE_AP) + } +}; + +/* P2P + P2P combination */ +static const struct ieee80211_iface_limit +wlan_hdd_p2p_p2p_iface_limit[] = { + { + /* 1 dedicated for p2p0 which is a STA type */ + .max = 1, + .types = BIT(NL80211_IFTYPE_STATION) + }, + { + /* The p2p interface in P2P+P2P can be GO/CLI. + * For P2P+P2P, the new interfaces are formed on p2p-p2p0-x. + */ + .max = 2, + .types = BIT(NL80211_IFTYPE_P2P_GO) | BIT(NL80211_IFTYPE_P2P_CLIENT) + }, +}; + +static const struct ieee80211_iface_limit + wlan_hdd_mon_iface_limit[] = { + { + .max = 3, /* Monitor interface */ + .types = BIT(NL80211_IFTYPE_MONITOR), + }, +}; + +static struct ieee80211_iface_combination + wlan_hdd_iface_combination[] = { + /* STA */ + { + .limits = wlan_hdd_sta_iface_limit, + .num_different_channels = 2, + .max_interfaces = 3, + .n_limits = ARRAY_SIZE(wlan_hdd_sta_iface_limit), + }, + /* ADHOC */ + { + .limits = wlan_hdd_adhoc_iface_limit, + .num_different_channels = 2, + .max_interfaces = 2, + .n_limits = ARRAY_SIZE(wlan_hdd_adhoc_iface_limit), + }, + /* AP */ + { + .limits = wlan_hdd_ap_iface_limit, + .num_different_channels = 2, + .max_interfaces = (SAP_MAX_OBSS_STA_CNT + QDF_MAX_NO_OF_SAP_MODE), + .n_limits = ARRAY_SIZE(wlan_hdd_ap_iface_limit), + }, + /* P2P */ + { + .limits = wlan_hdd_p2p_iface_limit, + .num_different_channels = 2, + .max_interfaces = 2, + .n_limits = ARRAY_SIZE(wlan_hdd_p2p_iface_limit), + }, + /* STA + AP */ + { + .limits = wlan_hdd_sta_ap_iface_limit, + .num_different_channels = 2, + .max_interfaces = (1 + SAP_MAX_OBSS_STA_CNT + QDF_MAX_NO_OF_SAP_MODE), + .n_limits = ARRAY_SIZE(wlan_hdd_sta_ap_iface_limit), + .beacon_int_infra_match = true, + }, + /* STA + P2P */ + { + .limits = wlan_hdd_sta_p2p_iface_limit, + .num_different_channels = 2, + /* one interface reserved for P2PDEV dedicated usage */ + .max_interfaces = 4, + .n_limits = ARRAY_SIZE(wlan_hdd_sta_p2p_iface_limit), + .beacon_int_infra_match = true, + }, + /* STA + P2P GO + SAP */ + { + .limits = wlan_hdd_sta_ap_p2pgo_iface_limit, + /* we can allow 3 channels for three different persona + * but due to firmware limitation, allow max 2 concrnt channels. + */ + .num_different_channels = 2, + /* one interface reserved for P2PDEV dedicated usage */ + .max_interfaces = 4, + .n_limits = ARRAY_SIZE(wlan_hdd_sta_ap_p2pgo_iface_limit), + .beacon_int_infra_match = true, + }, + /* SAP + P2P */ + { + .limits = wlan_hdd_sap_p2p_iface_limit, + .num_different_channels = 2, + /* 1-p2p0 + 1-SAP + 1-P2P (on p2p0 or p2p-p2p0-x) */ + .max_interfaces = 3, + .n_limits = ARRAY_SIZE(wlan_hdd_sap_p2p_iface_limit), + .beacon_int_infra_match = true, + }, + /* P2P + P2P */ + { + .limits = wlan_hdd_p2p_p2p_iface_limit, + .num_different_channels = 2, + /* 1-p2p0 + 2-P2P (on p2p-p2p0-x) */ + .max_interfaces = 3, + .n_limits = ARRAY_SIZE(wlan_hdd_p2p_p2p_iface_limit), + .beacon_int_infra_match = true, + }, + /* Monitor */ + { + .limits = wlan_hdd_mon_iface_limit, + .max_interfaces = 3, + .num_different_channels = 2, + .n_limits = ARRAY_SIZE(wlan_hdd_mon_iface_limit), + }, +}; + +static struct cfg80211_ops wlan_hdd_cfg80211_ops; +struct hdd_bpf_context bpf_context; + +#ifdef WLAN_NL80211_TESTMODE +enum wlan_hdd_tm_attr { + WLAN_HDD_TM_ATTR_INVALID = 0, + WLAN_HDD_TM_ATTR_CMD = 1, + WLAN_HDD_TM_ATTR_DATA = 2, + WLAN_HDD_TM_ATTR_STREAM_ID = 3, + WLAN_HDD_TM_ATTR_TYPE = 4, + /* keep last */ + WLAN_HDD_TM_ATTR_AFTER_LAST, + WLAN_HDD_TM_ATTR_MAX = WLAN_HDD_TM_ATTR_AFTER_LAST - 1, +}; + +enum wlan_hdd_tm_cmd { + WLAN_HDD_TM_CMD_WLAN_FTM = 0, + WLAN_HDD_TM_CMD_WLAN_HB = 1, +}; + +#define WLAN_HDD_TM_DATA_MAX_LEN 5000 + +enum wlan_hdd_vendor_ie_access_policy { + WLAN_HDD_VENDOR_IE_ACCESS_NONE = 0, + WLAN_HDD_VENDOR_IE_ACCESS_ALLOW_IF_LISTED, +}; + +static const struct nla_policy wlan_hdd_tm_policy[WLAN_HDD_TM_ATTR_MAX + 1] = { + [WLAN_HDD_TM_ATTR_CMD] = {.type = NLA_U32}, + [WLAN_HDD_TM_ATTR_DATA] = {.type = NLA_BINARY, + .len = WLAN_HDD_TM_DATA_MAX_LEN}, +}; +#endif /* WLAN_NL80211_TESTMODE */ + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)) +static const struct wiphy_wowlan_support wowlan_support_cfg80211_init = { + .flags = WIPHY_WOWLAN_MAGIC_PKT, + .n_patterns = WOWL_MAX_PTRNS_ALLOWED, + .pattern_min_len = 1, + .pattern_max_len = WOWL_PTRN_MAX_SIZE, +}; +#endif + +/** + * hdd_add_channel_switch_support()- Adds Channel Switch flag if supported + * @flags: Pointer to the flags to Add channel switch flag. + * + * This Function adds Channel Switch support flag, if channel switch is + * supported by kernel. + * Return: void. + */ +#ifdef CHANNEL_SWITCH_SUPPORTED +static inline void hdd_add_channel_switch_support(uint32_t *flags) +{ + *flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH; + return; +} +#else +static inline void hdd_add_channel_switch_support(uint32_t *flags) +{ + return; +} +#endif + +#ifdef FEATURE_WLAN_TDLS + +/* TDLS capabilities params */ +#define PARAM_MAX_TDLS_SESSION \ + QCA_WLAN_VENDOR_ATTR_TDLS_GET_CAPS_MAX_CONC_SESSIONS +#define PARAM_TDLS_FEATURE_SUPPORT \ + QCA_WLAN_VENDOR_ATTR_TDLS_GET_CAPS_FEATURES_SUPPORTED + +/** + * __wlan_hdd_cfg80211_get_tdls_capabilities() - Provide TDLS Capabilites. + * @wiphy: WIPHY structure pointer + * @wdev: Wireless device structure pointer + * @data: Pointer to the data received + * @data_len: Length of the data received + * + * This function provides TDLS capabilities + * + * Return: 0 on success and errno on failure + */ +static int __wlan_hdd_cfg80211_get_tdls_capabilities(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int status; + hdd_context_t *hdd_ctx = wiphy_priv(wiphy); + struct sk_buff *skb; + uint32_t set = 0; + + ENTER_DEV(wdev->netdev); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_warn("Command not allowed in FTM mode"); + return -EPERM; + } + + status = wlan_hdd_validate_context(hdd_ctx); + if (status) + return status; + + skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, (2 * sizeof(u32)) + + NLMSG_HDRLEN); + if (!skb) { + hdd_err("cfg80211_vendor_cmd_alloc_reply_skb failed"); + goto fail; + } + + if (false == hdd_ctx->config->fEnableTDLSSupport) { + hdd_err("TDLS feature not Enabled or Not supported in FW"); + if (nla_put_u32(skb, PARAM_MAX_TDLS_SESSION, 0) || + nla_put_u32(skb, PARAM_TDLS_FEATURE_SUPPORT, 0)) { + hdd_err("nla put fail"); + goto fail; + } + } else { + set = set | WIFI_TDLS_SUPPORT; + set = set | (hdd_ctx->config->fTDLSExternalControl ? + WIFI_TDLS_EXTERNAL_CONTROL_SUPPORT : 0); + set = set | (hdd_ctx->config->fEnableTDLSOffChannel ? + WIIF_TDLS_OFFCHANNEL_SUPPORT : 0); + hdd_notice("TDLS Feature supported value %x", set); + if (nla_put_u32(skb, PARAM_MAX_TDLS_SESSION, + hdd_ctx->max_num_tdls_sta) || + nla_put_u32(skb, PARAM_TDLS_FEATURE_SUPPORT, + set)) { + hdd_err("nla put fail"); + goto fail; + } + } + return cfg80211_vendor_cmd_reply(skb); +fail: + if (skb) + kfree_skb(skb); + return -EINVAL; +} + +/** + * wlan_hdd_cfg80211_get_tdls_capabilities() - Provide TDLS Capabilites. + * @wiphy: WIPHY structure pointer + * @wdev: Wireless device structure pointer + * @data: Pointer to the data received + * @data_len: Length of the data received + * + * This function provides TDLS capabilities + * + * Return: 0 on success and errno on failure + */ +static int +wlan_hdd_cfg80211_get_tdls_capabilities(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_get_tdls_capabilities(wiphy, wdev, + data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} +#endif + +#ifdef QCA_HT_2040_COEX +static void wlan_hdd_cfg80211_start_pending_acs(struct work_struct *work); +#endif + +#if defined(FEATURE_WLAN_CH_AVOID) || defined(FEATURE_WLAN_FORCE_SAP_SCC) +/* + * FUNCTION: wlan_hdd_send_avoid_freq_event + * This is called when wlan driver needs to send vendor specific + * avoid frequency range event to userspace + */ +int wlan_hdd_send_avoid_freq_event(hdd_context_t *pHddCtx, + tHddAvoidFreqList *pAvoidFreqList) +{ + struct sk_buff *vendor_event; + + ENTER(); + + if (!pHddCtx) { + hdd_err("HDD context is null"); + return -EINVAL; + } + + if (!pAvoidFreqList) { + hdd_err("pAvoidFreqList is null"); + return -EINVAL; + } + + vendor_event = cfg80211_vendor_event_alloc(pHddCtx->wiphy, + NULL, + sizeof(tHddAvoidFreqList), + QCA_NL80211_VENDOR_SUBCMD_AVOID_FREQUENCY_INDEX, + GFP_KERNEL); + if (!vendor_event) { + hdd_err("cfg80211_vendor_event_alloc failed"); + return -EINVAL; + } + + memcpy(skb_put(vendor_event, sizeof(tHddAvoidFreqList)), + (void *)pAvoidFreqList, sizeof(tHddAvoidFreqList)); + + cfg80211_vendor_event(vendor_event, GFP_KERNEL); + + EXIT(); + return 0; +} +#endif /* FEATURE_WLAN_CH_AVOID || FEATURE_WLAN_FORCE_SAP_SCC */ + +/* vendor specific events */ +static const struct nl80211_vendor_cmd_info wlan_hdd_cfg80211_vendor_events[] = { +#ifdef FEATURE_WLAN_CH_AVOID + [QCA_NL80211_VENDOR_SUBCMD_AVOID_FREQUENCY_INDEX] = { + .vendor_id = + QCA_NL80211_VENDOR_ID, + .subcmd = + QCA_NL80211_VENDOR_SUBCMD_AVOID_FREQUENCY + }, +#endif /* FEATURE_WLAN_CH_AVOID */ + +#ifdef WLAN_FEATURE_NAN + [QCA_NL80211_VENDOR_SUBCMD_NAN_INDEX] = { + .vendor_id = + QCA_NL80211_VENDOR_ID, + .subcmd = + QCA_NL80211_VENDOR_SUBCMD_NAN + }, +#endif + +#ifdef WLAN_FEATURE_STATS_EXT + [QCA_NL80211_VENDOR_SUBCMD_STATS_EXT_INDEX] = { + .vendor_id = + QCA_NL80211_VENDOR_ID, + .subcmd = + QCA_NL80211_VENDOR_SUBCMD_STATS_EXT + }, +#endif /* WLAN_FEATURE_STATS_EXT */ +#ifdef FEATURE_WLAN_EXTSCAN + [QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_START_INDEX] = { + .vendor_id = + QCA_NL80211_VENDOR_ID, + .subcmd = + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_START + }, + [QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_STOP_INDEX] = { + .vendor_id = + QCA_NL80211_VENDOR_ID, + .subcmd = + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_STOP + }, + [QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_GET_CAPABILITIES_INDEX] = { + . + vendor_id + = + QCA_NL80211_VENDOR_ID, + .subcmd = + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_GET_CAPABILITIES + }, + [QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_GET_CACHED_RESULTS_INDEX] = { + . + vendor_id + = + QCA_NL80211_VENDOR_ID, + . + subcmd = + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_GET_CACHED_RESULTS + }, + [QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SCAN_RESULTS_AVAILABLE_INDEX] = { + . + vendor_id + = + QCA_NL80211_VENDOR_ID, + . + subcmd + = + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SCAN_RESULTS_AVAILABLE + }, + [QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_FULL_SCAN_RESULT_INDEX] = { + . + vendor_id + = + QCA_NL80211_VENDOR_ID, + .subcmd = + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_FULL_SCAN_RESULT + }, + [QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SCAN_EVENT_INDEX] = { + .vendor_id = + QCA_NL80211_VENDOR_ID, + .subcmd = + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SCAN_EVENT + }, + [QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_HOTLIST_AP_FOUND_INDEX] = { + . + vendor_id + = + QCA_NL80211_VENDOR_ID, + .subcmd = + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_HOTLIST_AP_FOUND + }, + [QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SET_BSSID_HOTLIST_INDEX] = { + . + vendor_id + = + QCA_NL80211_VENDOR_ID, + .subcmd = + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SET_BSSID_HOTLIST + }, + [QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_RESET_BSSID_HOTLIST_INDEX] = { + . + vendor_id + = + QCA_NL80211_VENDOR_ID, + . + subcmd + = + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_RESET_BSSID_HOTLIST + }, + [QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SIGNIFICANT_CHANGE_INDEX] = { + . + vendor_id + = + QCA_NL80211_VENDOR_ID, + . + subcmd = + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SIGNIFICANT_CHANGE + }, + [QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SET_SIGNIFICANT_CHANGE_INDEX] = { + . + vendor_id + = + QCA_NL80211_VENDOR_ID, + . + subcmd + = + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SET_SIGNIFICANT_CHANGE + }, + [QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_RESET_SIGNIFICANT_CHANGE_INDEX] = { + . + vendor_id + = + QCA_NL80211_VENDOR_ID, + . + subcmd + = + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_RESET_SIGNIFICANT_CHANGE + }, +#endif /* FEATURE_WLAN_EXTSCAN */ + +#ifdef WLAN_FEATURE_LINK_LAYER_STATS + [QCA_NL80211_VENDOR_SUBCMD_LL_STATS_SET_INDEX] = { + .vendor_id = + QCA_NL80211_VENDOR_ID, + .subcmd = + QCA_NL80211_VENDOR_SUBCMD_LL_STATS_SET + }, + [QCA_NL80211_VENDOR_SUBCMD_LL_STATS_GET_INDEX] = { + .vendor_id = + QCA_NL80211_VENDOR_ID, + .subcmd = + QCA_NL80211_VENDOR_SUBCMD_LL_STATS_GET + }, + [QCA_NL80211_VENDOR_SUBCMD_LL_STATS_CLR_INDEX] = { + .vendor_id = + QCA_NL80211_VENDOR_ID, + .subcmd = + QCA_NL80211_VENDOR_SUBCMD_LL_STATS_CLR + }, + [QCA_NL80211_VENDOR_SUBCMD_LL_RADIO_STATS_INDEX] = { + .vendor_id = + QCA_NL80211_VENDOR_ID, + .subcmd = + QCA_NL80211_VENDOR_SUBCMD_LL_STATS_RADIO_RESULTS + }, + [QCA_NL80211_VENDOR_SUBCMD_LL_IFACE_STATS_INDEX] = { + .vendor_id = + QCA_NL80211_VENDOR_ID, + .subcmd = + QCA_NL80211_VENDOR_SUBCMD_LL_STATS_IFACE_RESULTS + }, + [QCA_NL80211_VENDOR_SUBCMD_LL_PEER_INFO_STATS_INDEX] = { + .vendor_id = + QCA_NL80211_VENDOR_ID, + .subcmd = + QCA_NL80211_VENDOR_SUBCMD_LL_STATS_PEERS_RESULTS + }, +#endif /* WLAN_FEATURE_LINK_LAYER_STATS */ + [QCA_NL80211_VENDOR_SUBCMD_TDLS_STATE_CHANGE_INDEX] = { + .vendor_id = + QCA_NL80211_VENDOR_ID, + .subcmd = + QCA_NL80211_VENDOR_SUBCMD_TDLS_STATE + }, + [QCA_NL80211_VENDOR_SUBCMD_DO_ACS_INDEX] = { + .vendor_id = QCA_NL80211_VENDOR_ID, + .subcmd = QCA_NL80211_VENDOR_SUBCMD_DO_ACS + }, +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + [QCA_NL80211_VENDOR_SUBCMD_KEY_MGMT_ROAM_AUTH_INDEX] = { + .vendor_id = + QCA_NL80211_VENDOR_ID, + .subcmd = + QCA_NL80211_VENDOR_SUBCMD_KEY_MGMT_ROAM_AUTH + }, +#endif + [QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_STARTED_INDEX] = { + .vendor_id = + QCA_NL80211_VENDOR_ID, + .subcmd = + QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_STARTED + }, + [QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_FINISHED_INDEX] = { + .vendor_id = + QCA_NL80211_VENDOR_ID, + .subcmd = + QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_FINISHED + }, + [QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_ABORTED_INDEX] = { + .vendor_id = + QCA_NL80211_VENDOR_ID, + .subcmd = + QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_ABORTED + }, + [QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_NOP_FINISHED_INDEX] = { + .vendor_id = + QCA_NL80211_VENDOR_ID, + .subcmd = + QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_NOP_FINISHED + }, + [QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_RADAR_DETECTED_INDEX] = { + .vendor_id = + QCA_NL80211_VENDOR_ID, + .subcmd = + QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_RADAR_DETECTED + }, +#ifdef FEATURE_WLAN_EXTSCAN + [QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_PNO_NETWORK_FOUND_INDEX] = { + .vendor_id = QCA_NL80211_VENDOR_ID, + .subcmd = QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_PNO_NETWORK_FOUND + }, + [QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_PNO_PASSPOINT_NETWORK_FOUND_INDEX] = { + .vendor_id = QCA_NL80211_VENDOR_ID, + .subcmd = QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_PNO_PASSPOINT_NETWORK_FOUND + }, + [QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_HOTLIST_AP_LOST_INDEX] = { + .vendor_id = QCA_NL80211_VENDOR_ID, + .subcmd = QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_HOTLIST_AP_LOST + }, +#endif /* FEATURE_WLAN_EXTSCAN */ + [QCA_NL80211_VENDOR_SUBCMD_MONITOR_RSSI_INDEX] = { + .vendor_id = QCA_NL80211_VENDOR_ID, + .subcmd = QCA_NL80211_VENDOR_SUBCMD_MONITOR_RSSI + }, +#ifdef WLAN_FEATURE_MEMDUMP + [QCA_NL80211_VENDOR_SUBCMD_WIFI_LOGGER_MEMORY_DUMP_INDEX] = { + .vendor_id = QCA_NL80211_VENDOR_ID, + .subcmd = QCA_NL80211_VENDOR_SUBCMD_WIFI_LOGGER_MEMORY_DUMP + }, +#endif /* WLAN_FEATURE_MEMDUMP */ +#ifdef WLAN_FEATURE_TSF + [QCA_NL80211_VENDOR_SUBCMD_TSF_INDEX] = { + .vendor_id = QCA_NL80211_VENDOR_ID, + .subcmd = QCA_NL80211_VENDOR_SUBCMD_TSF + }, +#endif + [QCA_NL80211_VENDOR_SUBCMD_SCAN_DONE_INDEX] = { + .vendor_id = QCA_NL80211_VENDOR_ID, + .subcmd = QCA_NL80211_VENDOR_SUBCMD_SCAN_DONE + }, + [QCA_NL80211_VENDOR_SUBCMD_SCAN_INDEX] = { + .vendor_id = QCA_NL80211_VENDOR_ID, + .subcmd = QCA_NL80211_VENDOR_SUBCMD_TRIGGER_SCAN + }, + /* OCB events */ + [QCA_NL80211_VENDOR_SUBCMD_DCC_STATS_EVENT_INDEX] = { + .vendor_id = QCA_NL80211_VENDOR_ID, + .subcmd = QCA_NL80211_VENDOR_SUBCMD_DCC_STATS_EVENT + }, +#ifdef FEATURE_LFR_SUBNET_DETECTION + [QCA_NL80211_VENDOR_SUBCMD_GW_PARAM_CONFIG_INDEX] = { + .vendor_id = QCA_NL80211_VENDOR_ID, + .subcmd = QCA_NL80211_VENDOR_SUBCMD_GW_PARAM_CONFIG + }, +#endif /*FEATURE_LFR_SUBNET_DETECTION */ + +#ifdef WLAN_FEATURE_NAN_DATAPATH + [QCA_NL80211_VENDOR_SUBCMD_NDP_INDEX] = { + .vendor_id = QCA_NL80211_VENDOR_ID, + .subcmd = QCA_NL80211_VENDOR_SUBCMD_NDP + }, +#endif /* WLAN_FEATURE_NAN_DATAPATH */ + + [QCA_NL80211_VENDOR_SUBCMD_P2P_LO_EVENT_INDEX] = { + .vendor_id = QCA_NL80211_VENDOR_ID, + .subcmd = QCA_NL80211_VENDOR_SUBCMD_P2P_LISTEN_OFFLOAD_STOP + }, + [QCA_NL80211_VENDOR_SUBCMD_SAP_CONDITIONAL_CHAN_SWITCH_INDEX] = { + .vendor_id = QCA_NL80211_VENDOR_ID, + .subcmd = QCA_NL80211_VENDOR_SUBCMD_SAP_CONDITIONAL_CHAN_SWITCH + }, + [QCA_NL80211_VENDOR_SUBCMD_NUD_STATS_GET_INDEX] = { + .vendor_id = QCA_NL80211_VENDOR_ID, + .subcmd = QCA_NL80211_VENDOR_SUBCMD_NUD_STATS_GET, + }, + + [QCA_NL80211_VENDOR_SUBCMD_PWR_SAVE_FAIL_DETECTED_INDEX] = { + .vendor_id = QCA_NL80211_VENDOR_ID, + .subcmd = QCA_NL80211_VENDOR_SUBCMD_CHIP_PWRSAVE_FAILURE + } +}; + +/** + * __is_driver_dfs_capable() - get driver DFS capability + * @wiphy: pointer to wireless wiphy structure. + * @wdev: pointer to wireless_dev structure. + * @data: Pointer to the data to be passed via vendor interface + * @data_len:Length of the data to be passed + * + * This function is called by userspace to indicate whether or not + * the driver supports DFS offload. + * + * Return: 0 on success, negative errno on failure + */ +static int __is_driver_dfs_capable(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + u32 dfs_capability = 0; + struct sk_buff *temp_skbuff; + int ret_val; + hdd_context_t *hdd_ctx = wiphy_priv(wiphy); + + ENTER_DEV(wdev->netdev); + + ret_val = wlan_hdd_validate_context(hdd_ctx); + if (ret_val) + return ret_val; + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_warn("Command not allowed in FTM mode"); + return -EPERM; + } + + dfs_capability = !!(wiphy->flags & WIPHY_FLAG_DFS_OFFLOAD); + + temp_skbuff = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, sizeof(u32) + + NLMSG_HDRLEN); + + if (temp_skbuff != NULL) { + ret_val = nla_put_u32(temp_skbuff, QCA_WLAN_VENDOR_ATTR_DFS, + dfs_capability); + if (ret_val) { + hdd_err("QCA_WLAN_VENDOR_ATTR_DFS put fail"); + kfree_skb(temp_skbuff); + + return ret_val; + } + + return cfg80211_vendor_cmd_reply(temp_skbuff); + } + + hdd_err("dfs capability: buffer alloc fail"); + return -ENOMEM; +} + +/** + * is_driver_dfs_capable() - get driver DFS capability + * @wiphy: pointer to wireless wiphy structure. + * @wdev: pointer to wireless_dev structure. + * @data: Pointer to the data to be passed via vendor interface + * @data_len:Length of the data to be passed + * + * This function is called by userspace to indicate whether or not + * the driver supports DFS offload. This is an SSR-protected + * wrapper function. + * + * Return: 0 on success, negative errno on failure + */ +static int is_driver_dfs_capable(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __is_driver_dfs_capable(wiphy, wdev, data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * wlan_hdd_sap_cfg_dfs_override() - DFS MCC restriction check + * + * @adapter: SAP adapter pointer + * + * DFS in MCC is not supported for Multi bssid SAP mode due to single physical + * radio. So in case of DFS MCC scenario override current SAP given config + * to follow concurrent SAP DFS config + * + * Return: 0 - No DFS issue, 1 - Override done and negative error codes + */ +int wlan_hdd_sap_cfg_dfs_override(hdd_adapter_t *adapter) +{ + hdd_adapter_t *con_sap_adapter; + tsap_Config_t *sap_config, *con_sap_config; + int con_ch; + + /* + * Check if AP+AP case, once primary AP chooses a DFS + * channel secondary AP should always follow primary APs channel + */ + if (!cds_concurrent_beaconing_sessions_running()) + return 0; + + con_sap_adapter = hdd_get_con_sap_adapter(adapter, true); + if (!con_sap_adapter) + return 0; + + sap_config = &adapter->sessionCtx.ap.sapConfig; + con_sap_config = &con_sap_adapter->sessionCtx.ap.sapConfig; + con_ch = con_sap_adapter->sessionCtx.ap.operatingChannel; + + if (!CDS_IS_DFS_CH(con_ch)) + return 0; + + hdd_err("Only SCC AP-AP DFS Permitted (ch=%d, con_ch=%d)", + sap_config->channel, con_ch); + hdd_notice("Overriding guest AP's channel"); + sap_config->channel = con_ch; + + if (con_sap_config->acs_cfg.acs_mode == true) { + if (con_ch != con_sap_config->acs_cfg.pri_ch && + con_ch != con_sap_config->acs_cfg.ht_sec_ch) { + hdd_err("Primary AP channel config error"); + hdd_err("Operating ch: %d ACS ch: %d %d", + con_ch, con_sap_config->acs_cfg.pri_ch, + con_sap_config->acs_cfg.ht_sec_ch); + return -EINVAL; + } + /* Sec AP ACS info is overwritten with Pri AP due to DFS + * MCC restriction. So free ch list allocated in do_acs + * func for Sec AP and realloc for Pri AP ch list size + */ + if (sap_config->acs_cfg.ch_list) + qdf_mem_free(sap_config->acs_cfg.ch_list); + + qdf_mem_copy(&sap_config->acs_cfg, + &con_sap_config->acs_cfg, + sizeof(struct sap_acs_cfg)); + sap_config->acs_cfg.ch_list = qdf_mem_malloc( + sizeof(uint8_t) * + con_sap_config->acs_cfg.ch_list_count); + if (!sap_config->acs_cfg.ch_list) { + hdd_err("ACS config alloc fail"); + return -ENOMEM; + } + + qdf_mem_copy(sap_config->acs_cfg.ch_list, + con_sap_config->acs_cfg.ch_list, + con_sap_config->acs_cfg.ch_list_count); + + } else { + sap_config->acs_cfg.pri_ch = con_ch; + if (sap_config->acs_cfg.ch_width > eHT_CHANNEL_WIDTH_20MHZ) + sap_config->acs_cfg.ht_sec_ch = con_sap_config->sec_ch; + } + + return con_ch; +} + +/** + * wlan_hdd_set_acs_ch_range : Start ACS channel range values + * @sap_cfg: pointer to SAP config struct + * + * This function sets the default ACS start and end channel for the given band + * and also parses the given ACS channel list. + * + * Return: None + */ + +static void wlan_hdd_set_acs_ch_range(tsap_Config_t *sap_cfg, bool ht_enabled, + bool vht_enabled) +{ + int i; + if (sap_cfg->acs_cfg.hw_mode == QCA_ACS_MODE_IEEE80211B) { + sap_cfg->acs_cfg.hw_mode = eCSR_DOT11_MODE_11b; + sap_cfg->acs_cfg.start_ch = CDS_CHANNEL_NUM(CHAN_ENUM_1); + sap_cfg->acs_cfg.end_ch = CDS_CHANNEL_NUM(CHAN_ENUM_14); + } else if (sap_cfg->acs_cfg.hw_mode == QCA_ACS_MODE_IEEE80211G) { + sap_cfg->acs_cfg.hw_mode = eCSR_DOT11_MODE_11g; + sap_cfg->acs_cfg.start_ch = CDS_CHANNEL_NUM(CHAN_ENUM_1); + sap_cfg->acs_cfg.end_ch = CDS_CHANNEL_NUM(CHAN_ENUM_13); + } else if (sap_cfg->acs_cfg.hw_mode == QCA_ACS_MODE_IEEE80211A) { + sap_cfg->acs_cfg.hw_mode = eCSR_DOT11_MODE_11a; + sap_cfg->acs_cfg.start_ch = CDS_CHANNEL_NUM(CHAN_ENUM_36); + sap_cfg->acs_cfg.end_ch = CDS_CHANNEL_NUM(CHAN_ENUM_165); + } else if (sap_cfg->acs_cfg.hw_mode == QCA_ACS_MODE_IEEE80211ANY) { + sap_cfg->acs_cfg.hw_mode = eCSR_DOT11_MODE_abg; + sap_cfg->acs_cfg.start_ch = CDS_CHANNEL_NUM(CHAN_ENUM_1); + sap_cfg->acs_cfg.end_ch = CDS_CHANNEL_NUM(CHAN_ENUM_165); + } + + if (ht_enabled) + sap_cfg->acs_cfg.hw_mode = eCSR_DOT11_MODE_11n; + + if (vht_enabled) + sap_cfg->acs_cfg.hw_mode = eCSR_DOT11_MODE_11ac; + + + /* Parse ACS Chan list from hostapd */ + if (!sap_cfg->acs_cfg.ch_list) + return; + + sap_cfg->acs_cfg.start_ch = sap_cfg->acs_cfg.ch_list[0]; + sap_cfg->acs_cfg.end_ch = + sap_cfg->acs_cfg.ch_list[sap_cfg->acs_cfg.ch_list_count - 1]; + for (i = 0; i < sap_cfg->acs_cfg.ch_list_count; i++) { + /* avoid channel as start channel */ + if (sap_cfg->acs_cfg.start_ch > sap_cfg->acs_cfg.ch_list[i] && + sap_cfg->acs_cfg.ch_list[i] != 0) + sap_cfg->acs_cfg.start_ch = sap_cfg->acs_cfg.ch_list[i]; + if (sap_cfg->acs_cfg.end_ch < sap_cfg->acs_cfg.ch_list[i]) + sap_cfg->acs_cfg.end_ch = sap_cfg->acs_cfg.ch_list[i]; + } +} + + +static void wlan_hdd_cfg80211_start_pending_acs(struct work_struct *work); + +/** + * wlan_hdd_cfg80211_start_acs : Start ACS Procedure for SAP + * @adapter: pointer to SAP adapter struct + * + * This function starts the ACS procedure if there are no + * constraints like MBSSID DFS restrictions. + * + * Return: Status of ACS Start procedure + */ + +static int wlan_hdd_cfg80211_start_acs(hdd_adapter_t *adapter) +{ + + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + tsap_Config_t *sap_config; + tpWLAN_SAPEventCB acs_event_callback; + int status; + + sap_config = &adapter->sessionCtx.ap.sapConfig; + if (hdd_ctx->acs_policy.acs_channel) + sap_config->channel = hdd_ctx->acs_policy.acs_channel; + else + sap_config->channel = AUTO_CHANNEL_SELECT; + + status = wlan_hdd_sap_cfg_dfs_override(adapter); + if (status < 0) { + return status; + } else { + if (status > 0) { + /*notify hostapd about channel override */ + wlan_hdd_cfg80211_acs_ch_select_evt(adapter); + clear_bit(ACS_IN_PROGRESS, &hdd_ctx->g_event_flags); + return 0; + } + } + status = wlan_hdd_config_acs(hdd_ctx, adapter); + if (status) { + hdd_err("ACS config failed"); + return -EINVAL; + } + + acs_event_callback = hdd_hostapd_sap_event_cb; + + qdf_mem_copy(sap_config->self_macaddr.bytes, + adapter->macAddressCurrent.bytes, sizeof(struct qdf_mac_addr)); + hdd_notice("ACS Started for wlan%d", adapter->dev->ifindex); + status = wlansap_acs_chselect( + WLAN_HDD_GET_SAP_CTX_PTR(adapter), + acs_event_callback, sap_config, adapter->dev); + + + if (status) { + hdd_err("ACS channel select failed"); + return -EINVAL; + } + if (sap_is_auto_channel_select(WLAN_HDD_GET_SAP_CTX_PTR(adapter))) + sap_config->acs_cfg.acs_mode = true; + set_bit(ACS_IN_PROGRESS, &hdd_ctx->g_event_flags); + + return 0; +} + +static const struct nla_policy +wlan_hdd_cfg80211_do_acs_policy[QCA_WLAN_VENDOR_ATTR_ACS_MAX+1] = { + [QCA_WLAN_VENDOR_ATTR_ACS_HW_MODE] = { .type = NLA_U8 }, + [QCA_WLAN_VENDOR_ATTR_ACS_HT_ENABLED] = { .type = NLA_FLAG }, + [QCA_WLAN_VENDOR_ATTR_ACS_HT40_ENABLED] = { .type = NLA_FLAG }, + [QCA_WLAN_VENDOR_ATTR_ACS_VHT_ENABLED] = { .type = NLA_FLAG }, + [QCA_WLAN_VENDOR_ATTR_ACS_CHWIDTH] = { .type = NLA_U16 }, + [QCA_WLAN_VENDOR_ATTR_ACS_CH_LIST] = { .type = NLA_UNSPEC }, + [QCA_WLAN_VENDOR_ATTR_ACS_FREQ_LIST] = { .type = NLA_UNSPEC }, +}; + +/** + * __wlan_hdd_cfg80211_do_acs(): CFG80211 handler function for DO_ACS Vendor CMD + * @wiphy: Linux wiphy struct pointer + * @wdev: Linux wireless device struct pointer + * @data: ACS information from hostapd + * @data_len: ACS information length + * + * This function handle DO_ACS Vendor command from hostapd, parses ACS config + * and starts ACS procedure. + * + * Return: ACS procedure start status + */ + +static int __wlan_hdd_cfg80211_do_acs(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + struct net_device *ndev = wdev->netdev; + hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(ndev); + hdd_context_t *hdd_ctx = wiphy_priv(wiphy); + tsap_Config_t *sap_config; + struct sk_buff *temp_skbuff; + int status = -EINVAL, i = 0; + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_ACS_MAX + 1]; + bool ht_enabled, ht40_enabled, vht_enabled; + uint8_t ch_width; + uint8_t weight_list[QDF_MAX_NUM_CHAN]; + + /* ***Note*** Donot set SME config related to ACS operation here because + * ACS operation is not synchronouse and ACS for Second AP may come when + * ACS operation for first AP is going on. So only do_acs is split to + * seperate start_acs routine. Also SME-PMAC struct that is used to + * pass paremeters from HDD to SAP is global. Thus All ACS related SME + * config shall be set only from start_acs. + */ + + ENTER_DEV(ndev); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_warn("Command not allowed in FTM mode"); + return -EPERM; + } + + if (hdd_ctx->config->force_sap_acs) { + hdd_err("Hostapd ACS rejected as Driver ACS enabled"); + return -EPERM; + } + + status = wlan_hdd_validate_context(hdd_ctx); + if (status) + goto out; + + if (cds_is_sub_20_mhz_enabled()) { + hdd_err("ACS not supported in sub 20 MHz ch wd."); + status = -EINVAL; + goto out; + } + + sap_config = &adapter->sessionCtx.ap.sapConfig; + qdf_mem_zero(&sap_config->acs_cfg, sizeof(struct sap_acs_cfg)); + + status = nla_parse(tb, QCA_WLAN_VENDOR_ATTR_ACS_MAX, data, data_len, + wlan_hdd_cfg80211_do_acs_policy); + if (status) { + hdd_err("Invalid ATTR"); + goto out; + } + + if (!tb[QCA_WLAN_VENDOR_ATTR_ACS_HW_MODE]) { + hdd_err("Attr hw_mode failed"); + goto out; + } + sap_config->acs_cfg.hw_mode = nla_get_u8( + tb[QCA_WLAN_VENDOR_ATTR_ACS_HW_MODE]); + + if (tb[QCA_WLAN_VENDOR_ATTR_ACS_HT_ENABLED]) + ht_enabled = + nla_get_flag(tb[QCA_WLAN_VENDOR_ATTR_ACS_HT_ENABLED]); + else + ht_enabled = 0; + + if (tb[QCA_WLAN_VENDOR_ATTR_ACS_HT40_ENABLED]) + ht40_enabled = + nla_get_flag(tb[QCA_WLAN_VENDOR_ATTR_ACS_HT40_ENABLED]); + else + ht40_enabled = 0; + + if (tb[QCA_WLAN_VENDOR_ATTR_ACS_VHT_ENABLED]) + vht_enabled = + nla_get_flag(tb[QCA_WLAN_VENDOR_ATTR_ACS_VHT_ENABLED]); + else + vht_enabled = 0; + + if (hdd_ctx->config->sap_force_11n_for_11ac) { + vht_enabled = 0; + hdd_log(LOG1, FL("VHT is Disabled in ACS")); + } + + if (tb[QCA_WLAN_VENDOR_ATTR_ACS_CHWIDTH]) { + ch_width = nla_get_u16(tb[QCA_WLAN_VENDOR_ATTR_ACS_CHWIDTH]); + } else { + if (ht_enabled && ht40_enabled) + ch_width = 40; + else + ch_width = 20; + } + + /* this may be possible, when sap_force_11n_for_11ac is set */ + if ((ch_width == 80 || ch_width == 160) && !vht_enabled) { + if (ht_enabled && ht40_enabled) + ch_width = 40; + else + ch_width = 20; + } + + if (ch_width == 80) + sap_config->acs_cfg.ch_width = CH_WIDTH_80MHZ; + else if (ch_width == 40) + sap_config->acs_cfg.ch_width = CH_WIDTH_40MHZ; + else + sap_config->acs_cfg.ch_width = CH_WIDTH_20MHZ; + + /* hw_mode = a/b/g: QCA_WLAN_VENDOR_ATTR_ACS_CH_LIST and + * QCA_WLAN_VENDOR_ATTR_ACS_FREQ_LIST attrs are present, and + * QCA_WLAN_VENDOR_ATTR_ACS_CH_LIST is used for obtaining the + * channel list, QCA_WLAN_VENDOR_ATTR_ACS_FREQ_LIST is ignored + * since it contains the frequency values of the channels in + * the channel list. + * hw_mode = any: only QCA_WLAN_VENDOR_ATTR_ACS_FREQ_LIST attr + * is present + */ + if (tb[QCA_WLAN_VENDOR_ATTR_ACS_CH_LIST]) { + char *tmp = nla_data(tb[QCA_WLAN_VENDOR_ATTR_ACS_CH_LIST]); + sap_config->acs_cfg.ch_list_count = nla_len( + tb[QCA_WLAN_VENDOR_ATTR_ACS_CH_LIST]); + if (sap_config->acs_cfg.ch_list_count) { + sap_config->acs_cfg.ch_list = qdf_mem_malloc( + sizeof(uint8_t) * + sap_config->acs_cfg.ch_list_count); + if (sap_config->acs_cfg.ch_list == NULL) + goto out; + + qdf_mem_copy(sap_config->acs_cfg.ch_list, tmp, + sap_config->acs_cfg.ch_list_count); + } + } else if (tb[QCA_WLAN_VENDOR_ATTR_ACS_FREQ_LIST]) { + uint32_t *freq = + nla_data(tb[QCA_WLAN_VENDOR_ATTR_ACS_FREQ_LIST]); + sap_config->acs_cfg.ch_list_count = nla_len( + tb[QCA_WLAN_VENDOR_ATTR_ACS_FREQ_LIST]) / + sizeof(uint32_t); + if (sap_config->acs_cfg.ch_list_count) { + sap_config->acs_cfg.ch_list = qdf_mem_malloc( + sap_config->acs_cfg.ch_list_count); + if (sap_config->acs_cfg.ch_list == NULL) { + hdd_err("ACS config alloc fail"); + status = -ENOMEM; + goto out; + } + + /* convert frequency to channel */ + for (i = 0; i < sap_config->acs_cfg.ch_list_count; i++) + sap_config->acs_cfg.ch_list[i] = + ieee80211_frequency_to_channel(freq[i]); + } + } + + hdd_debug("get pcl for DO_ACS vendor command"); + + /* consult policy manager to get PCL */ + status = cds_get_pcl(CDS_SAP_MODE, + sap_config->acs_cfg.pcl_channels, + &sap_config->acs_cfg.pcl_ch_count, + weight_list, QDF_ARRAY_SIZE(weight_list)); + if (QDF_STATUS_SUCCESS != status) + hdd_err("Get PCL failed"); + + /* ACS override for android */ + if (hdd_ctx->config->sap_p2p_11ac_override && ht_enabled && + !hdd_ctx->config->sap_force_11n_for_11ac) { + hdd_notice("ACS Config override for 11AC"); + vht_enabled = 1; + sap_config->acs_cfg.hw_mode = eCSR_DOT11_MODE_11ac; + sap_config->acs_cfg.ch_width = + hdd_ctx->config->vhtChannelWidth; + /* No VHT80 in 2.4G so perform ACS accordingly */ + if (sap_config->acs_cfg.end_ch <= 14 && + sap_config->acs_cfg.ch_width == eHT_CHANNEL_WIDTH_80MHZ) + sap_config->acs_cfg.ch_width = eHT_CHANNEL_WIDTH_40MHZ; + } + + wlan_hdd_set_acs_ch_range(sap_config, ht_enabled, vht_enabled); + + hdd_notice("ACS Config for wlan%d: HW_MODE: %d ACS_BW: %d HT: %d VHT: %d START_CH: %d END_CH: %d", + adapter->dev->ifindex, sap_config->acs_cfg.hw_mode, + ch_width, ht_enabled, vht_enabled, + sap_config->acs_cfg.start_ch, sap_config->acs_cfg.end_ch); + + if (sap_config->acs_cfg.ch_list_count) { + hdd_notice("ACS channel list: len: %d", + sap_config->acs_cfg.ch_list_count); + for (i = 0; i < sap_config->acs_cfg.ch_list_count; i++) + hdd_notice("%d ", sap_config->acs_cfg.ch_list[i]); + } + sap_config->acs_cfg.acs_mode = true; + if (test_bit(ACS_IN_PROGRESS, &hdd_ctx->g_event_flags)) { + /* ***Note*** Completion variable usage is not allowed + * here since ACS scan operation may take max 2.2 sec + * for 5G band: + * 9 Active channel X 40 ms active scan time + + * 16 Passive channel X 110ms passive scan time + * Since this CFG80211 call lock rtnl mutex, we cannot hold on + * for this long. So we split up the scanning part. + */ + set_bit(ACS_PENDING, &adapter->event_flags); + hdd_notice("ACS Pending for wlan%d", adapter->dev->ifindex); + status = 0; + } else { + status = wlan_hdd_cfg80211_start_acs(adapter); + } + +out: + if (0 == status) { + temp_skbuff = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, + NLMSG_HDRLEN); + if (temp_skbuff != NULL) + return cfg80211_vendor_cmd_reply(temp_skbuff); + } + wlan_hdd_undo_acs(adapter); + clear_bit(ACS_IN_PROGRESS, &hdd_ctx->g_event_flags); + + return status; +} + + /** + * wlan_hdd_cfg80211_do_acs : CFG80211 handler function for DO_ACS Vendor CMD + * @wiphy: Linux wiphy struct pointer + * @wdev: Linux wireless device struct pointer + * @data: ACS information from hostapd + * @data_len: ACS information len + * + * This function handle DO_ACS Vendor command from hostapd, parses ACS config + * and starts ACS procedure. + * + * Return: ACS procedure start status + */ + +static int wlan_hdd_cfg80211_do_acs(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_do_acs(wiphy, wdev, data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * wlan_hdd_undo_acs : Do cleanup of DO_ACS + * @adapter: Pointer to adapter struct + * + * This function handle cleanup of what was done in DO_ACS, including free + * memory. + * + * Return: void + */ + +void wlan_hdd_undo_acs(hdd_adapter_t *adapter) +{ + if (adapter == NULL) + return; + if (adapter->sessionCtx.ap.sapConfig.acs_cfg.ch_list) { + qdf_mem_free(adapter->sessionCtx.ap.sapConfig.acs_cfg.ch_list); + adapter->sessionCtx.ap.sapConfig.acs_cfg.ch_list = NULL; + } +} + +/** + * wlan_hdd_cfg80211_start_pending_acs : Start pending ACS procedure for SAP + * @work: Linux workqueue struct pointer for ACS work + * + * This function starts the ACS procedure which was marked pending when an ACS + * procedure was in progress for a concurrent SAP interface. + * + * Return: None + */ + +static void wlan_hdd_cfg80211_start_pending_acs(struct work_struct *work) +{ + hdd_adapter_t *adapter = container_of(work, hdd_adapter_t, + acs_pending_work.work); + wlan_hdd_cfg80211_start_acs(adapter); +} + +/** + * wlan_hdd_cfg80211_acs_ch_select_evt: Callback function for ACS evt + * @adapter: Pointer to SAP adapter struct + * @pri_channel: SAP ACS procedure selected Primary channel + * @sec_channel: SAP ACS procedure selected secondary channel + * + * This is a callback function from SAP module on ACS procedure is completed. + * This function send the ACS selected channel information to hostapd + * + * Return: None + */ + +void wlan_hdd_cfg80211_acs_ch_select_evt(hdd_adapter_t *adapter) +{ + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + tsap_Config_t *sap_cfg = &(WLAN_HDD_GET_AP_CTX_PTR(adapter))->sapConfig; + struct sk_buff *vendor_event; + int ret_val; + hdd_adapter_t *con_sap_adapter; + uint16_t ch_width; + + vendor_event = cfg80211_vendor_event_alloc(hdd_ctx->wiphy, + &(adapter->wdev), + 4 * sizeof(u8) + 1 * sizeof(u16) + 4 + NLMSG_HDRLEN, + QCA_NL80211_VENDOR_SUBCMD_DO_ACS_INDEX, + GFP_KERNEL); + + if (!vendor_event) { + hdd_err("cfg80211_vendor_event_alloc failed"); + return; + } + + ret_val = nla_put_u8(vendor_event, + QCA_WLAN_VENDOR_ATTR_ACS_PRIMARY_CHANNEL, + sap_cfg->acs_cfg.pri_ch); + if (ret_val) { + hdd_err("QCA_WLAN_VENDOR_ATTR_ACS_PRIMARY_CHANNEL put fail"); + kfree_skb(vendor_event); + return; + } + + ret_val = nla_put_u8(vendor_event, + QCA_WLAN_VENDOR_ATTR_ACS_SECONDARY_CHANNEL, + sap_cfg->acs_cfg.ht_sec_ch); + if (ret_val) { + hdd_err("QCA_WLAN_VENDOR_ATTR_ACS_SECONDARY_CHANNEL put fail"); + kfree_skb(vendor_event); + return; + } + + ret_val = nla_put_u8(vendor_event, + QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_CHANNEL, + sap_cfg->acs_cfg.vht_seg0_center_ch); + if (ret_val) { + hdd_err("QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_CHANNEL put fail"); + kfree_skb(vendor_event); + return; + } + + ret_val = nla_put_u8(vendor_event, + QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG1_CENTER_CHANNEL, + sap_cfg->acs_cfg.vht_seg1_center_ch); + if (ret_val) { + hdd_err("QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG1_CENTER_CHANNEL put fail"); + kfree_skb(vendor_event); + return; + } + + if (sap_cfg->acs_cfg.ch_width == CH_WIDTH_80MHZ) + ch_width = 80; + else if (sap_cfg->acs_cfg.ch_width == CH_WIDTH_40MHZ) + ch_width = 40; + else + ch_width = 20; + + ret_val = nla_put_u16(vendor_event, + QCA_WLAN_VENDOR_ATTR_ACS_CHWIDTH, + ch_width); + if (ret_val) { + hdd_err("QCA_WLAN_VENDOR_ATTR_ACS_CHWIDTH put fail"); + kfree_skb(vendor_event); + return; + } + if (sap_cfg->acs_cfg.pri_ch > 14) + ret_val = nla_put_u8(vendor_event, + QCA_WLAN_VENDOR_ATTR_ACS_HW_MODE, + QCA_ACS_MODE_IEEE80211A); + else + ret_val = nla_put_u8(vendor_event, + QCA_WLAN_VENDOR_ATTR_ACS_HW_MODE, + QCA_ACS_MODE_IEEE80211G); + + if (ret_val) { + hdd_err("QCA_WLAN_VENDOR_ATTR_ACS_HW_MODE put fail"); + kfree_skb(vendor_event); + return; + } + + hdd_notice("ACS result for wlan%d: PRI_CH: %d SEC_CH: %d VHT_SEG0: %d VHT_SEG1: %d ACS_BW: %d", + adapter->dev->ifindex, sap_cfg->acs_cfg.pri_ch, + sap_cfg->acs_cfg.ht_sec_ch, sap_cfg->acs_cfg.vht_seg0_center_ch, + sap_cfg->acs_cfg.vht_seg1_center_ch, ch_width); + + cfg80211_vendor_event(vendor_event, GFP_KERNEL); + /* ***Note*** As already mentioned Completion variable usage is not + * allowed here since ACS scan operation may take max 2.2 sec. + * Further in AP-AP mode pending ACS is resumed here to serailize ACS + * operation. + * TODO: Delayed operation is used since SME-PMAC strut is global. Thus + * when Primary AP ACS is complete and secondary AP ACS is started here + * immediately, Primary AP start_bss may come inbetween ACS operation + * and overwrite Sec AP ACS paramters. Thus Sec AP ACS is executed with + * delay. This path and below constraint will be removed on sessionizing + * SAP acs parameters and decoupling SAP from PMAC (WIP). + * As per design constraint user space control application must take + * care of serailizing hostapd start for each VIF in AP-AP mode to avoid + * this code path. Sec AP hostapd should be started after Primary AP + * start beaconing which can be confirmed by getchannel iwpriv command + */ + + con_sap_adapter = hdd_get_con_sap_adapter(adapter, false); + if (con_sap_adapter && + test_bit(ACS_PENDING, &con_sap_adapter->event_flags)) { + INIT_DELAYED_WORK(&con_sap_adapter->acs_pending_work, + wlan_hdd_cfg80211_start_pending_acs); + /* Lets give 500ms for OBSS + START_BSS to complete */ + schedule_delayed_work(&con_sap_adapter->acs_pending_work, + msecs_to_jiffies(500)); + clear_bit(ACS_PENDING, &con_sap_adapter->event_flags); + } + + return; +} + +static int +__wlan_hdd_cfg80211_get_supported_features(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + hdd_context_t *pHddCtx = wiphy_priv(wiphy); + struct sk_buff *skb = NULL; + uint32_t fset = 0; + int ret; + + /* ENTER_DEV() intentionally not used in a frequently invoked API */ + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_warn("Command not allowed in FTM mode"); + return -EPERM; + } + + ret = wlan_hdd_validate_context(pHddCtx); + if (ret) + return ret; + + if (wiphy->interface_modes & BIT(NL80211_IFTYPE_STATION)) { + hdd_notice("Infra Station mode is supported by driver"); + fset |= WIFI_FEATURE_INFRA; + } + if (true == hdd_is_5g_supported(pHddCtx)) { + hdd_notice("INFRA_5G is supported by firmware"); + fset |= WIFI_FEATURE_INFRA_5G; + } +#ifdef WLAN_FEATURE_P2P + if ((wiphy->interface_modes & BIT(NL80211_IFTYPE_P2P_CLIENT)) && + (wiphy->interface_modes & BIT(NL80211_IFTYPE_P2P_GO))) { + hdd_notice("WiFi-Direct is supported by driver"); + fset |= WIFI_FEATURE_P2P; + } +#endif + fset |= WIFI_FEATURE_SOFT_AP; + + /* HOTSPOT is a supplicant feature, enable it by default */ + fset |= WIFI_FEATURE_HOTSPOT; + +#ifdef FEATURE_WLAN_EXTSCAN + if (pHddCtx->config->extscan_enabled && + sme_is_feature_supported_by_fw(EXTENDED_SCAN)) { + hdd_notice("EXTScan is supported by firmware"); + fset |= WIFI_FEATURE_EXTSCAN | WIFI_FEATURE_HAL_EPNO; + } +#endif + if (wlan_hdd_nan_is_supported()) { + hdd_notice("NAN is supported by firmware"); + fset |= WIFI_FEATURE_NAN; + } + if (sme_is_feature_supported_by_fw(RTT)) { + hdd_notice("RTT is supported by firmware"); + fset |= WIFI_FEATURE_D2D_RTT; + fset |= WIFI_FEATURE_D2AP_RTT; + } +#ifdef FEATURE_WLAN_SCAN_PNO + if (pHddCtx->config->configPNOScanSupport && + sme_is_feature_supported_by_fw(PNO)) { + hdd_notice("PNO is supported by firmware"); + fset |= WIFI_FEATURE_PNO; + } +#endif + fset |= WIFI_FEATURE_ADDITIONAL_STA; +#ifdef FEATURE_WLAN_TDLS + if ((true == pHddCtx->config->fEnableTDLSSupport) && + sme_is_feature_supported_by_fw(TDLS)) { + hdd_notice("TDLS is supported by firmware"); + fset |= WIFI_FEATURE_TDLS; + } + if (sme_is_feature_supported_by_fw(TDLS) && + (true == pHddCtx->config->fEnableTDLSOffChannel) && + sme_is_feature_supported_by_fw(TDLS_OFF_CHANNEL)) { + hdd_notice("TDLS off-channel is supported by firmware"); + fset |= WIFI_FEATURE_TDLS_OFFCHANNEL; + } +#endif +#ifdef WLAN_AP_STA_CONCURRENCY + fset |= WIFI_FEATURE_AP_STA; +#endif + fset |= WIFI_FEATURE_RSSI_MONITOR; + fset |= WIFI_FEATURE_TX_TRANSMIT_POWER; + + if (hdd_link_layer_stats_supported()) + fset |= WIFI_FEATURE_LINK_LAYER_STATS; + + skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, sizeof(fset) + + NLMSG_HDRLEN); + if (!skb) { + hdd_err("cfg80211_vendor_cmd_alloc_reply_skb failed"); + return -EINVAL; + } + hdd_notice("Supported Features : 0x%x", fset); + if (nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_FEATURE_SET, fset)) { + hdd_err("nla put fail"); + goto nla_put_failure; + } + ret = cfg80211_vendor_cmd_reply(skb); + return ret; +nla_put_failure: + kfree_skb(skb); + return -EINVAL; +} + +/** + * wlan_hdd_cfg80211_get_supported_features() - get supported features + * @wiphy: pointer to wireless wiphy structure. + * @wdev: pointer to wireless_dev structure. + * @data: Pointer to the data to be passed via vendor interface + * @data_len:Length of the data to be passed + * + * Return: Return the Success or Failure code. + */ +static int +wlan_hdd_cfg80211_get_supported_features(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + int ret = 0; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_get_supported_features(wiphy, wdev, + data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __wlan_hdd_cfg80211_set_scanning_mac_oui() - set scan MAC + * @wiphy: pointer to wireless wiphy structure. + * @wdev: pointer to wireless_dev structure. + * @data: Pointer to the data to be passed via vendor interface + * @data_len:Length of the data to be passed + * + * Set the MAC OUI which will be used to spoof sa and enable sq.no randomization + * of probe req frames + * + * Return: Return the Success or Failure code. + */ +static int +__wlan_hdd_cfg80211_set_scanning_mac_oui(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + tpSirScanMacOui pReqMsg = NULL; + hdd_context_t *pHddCtx = wiphy_priv(wiphy); + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_SET_SCANNING_MAC_OUI_MAX + 1]; + QDF_STATUS status; + int ret; + struct net_device *ndev = wdev->netdev; + hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(ndev); + + ENTER_DEV(wdev->netdev); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_warn("Command not allowed in FTM mode"); + return -EPERM; + } + + ret = wlan_hdd_validate_context(pHddCtx); + if (ret) + return ret; + + if (false == pHddCtx->config->enable_mac_spoofing) { + hdd_warn("MAC address spoofing is not enabled"); + return -ENOTSUPP; + } + + if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_SET_SCANNING_MAC_OUI_MAX, + data, data_len, NULL)) { + hdd_err("Invalid ATTR"); + return -EINVAL; + } + pReqMsg = qdf_mem_malloc(sizeof(*pReqMsg)); + if (!pReqMsg) { + hdd_err("qdf_mem_malloc failed"); + return -ENOMEM; + } + if (!tb[QCA_WLAN_VENDOR_ATTR_SET_SCANNING_MAC_OUI]) { + hdd_err("attr mac oui failed"); + goto fail; + } + nla_memcpy(&pReqMsg->oui[0], + tb[QCA_WLAN_VENDOR_ATTR_SET_SCANNING_MAC_OUI], + sizeof(pReqMsg->oui)); + + /* populate pReqMsg for mac addr randomization */ + pReqMsg->vdev_id = adapter->sessionId; + pReqMsg->enb_probe_req_sno_randomization = true; + + hdd_notice("Oui (%02x:%02x:%02x), vdev_id = %d", pReqMsg->oui[0], + pReqMsg->oui[1], pReqMsg->oui[2], pReqMsg->vdev_id); + status = sme_set_scanning_mac_oui(pHddCtx->hHal, pReqMsg); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("sme_set_scanning_mac_oui failed(err=%d)", status); + goto fail; + } + return 0; +fail: + qdf_mem_free(pReqMsg); + return -EINVAL; +} + +/** + * wlan_hdd_cfg80211_set_scanning_mac_oui() - set scan MAC + * @wiphy: pointer to wireless wiphy structure. + * @wdev: pointer to wireless_dev structure. + * @data: Pointer to the data to be passed via vendor interface + * @data_len:Length of the data to be passed + * + * Set the MAC address that is to be used for scanning. This is an + * SSR-protecting wrapper function. + * + * Return: Return the Success or Failure code. + */ +static int +wlan_hdd_cfg80211_set_scanning_mac_oui(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_set_scanning_mac_oui(wiphy, wdev, + data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +#define MAX_CONCURRENT_MATRIX \ + QCA_WLAN_VENDOR_ATTR_GET_CONCURRENCY_MATRIX_MAX +#define MATRIX_CONFIG_PARAM_SET_SIZE_MAX \ + QCA_WLAN_VENDOR_ATTR_GET_CONCURRENCY_MATRIX_CONFIG_PARAM_SET_SIZE_MAX +static const struct nla_policy +wlan_hdd_get_concurrency_matrix_policy[MAX_CONCURRENT_MATRIX + 1] = { + [MATRIX_CONFIG_PARAM_SET_SIZE_MAX] = {.type = NLA_U32}, +}; + +/** + * __wlan_hdd_cfg80211_get_concurrency_matrix() - to retrieve concurrency matrix + * @wiphy: pointer phy adapter + * @wdev: pointer to wireless device structure + * @data: pointer to data buffer + * @data_len: length of data + * + * This routine will give concurrency matrix + * + * Return: int status code + */ +static int __wlan_hdd_cfg80211_get_concurrency_matrix(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + uint32_t feature_set_matrix[CDS_MAX_FEATURE_SET] = {0}; + uint8_t i, feature_sets, max_feature_sets; + struct nlattr *tb[MAX_CONCURRENT_MATRIX + 1]; + struct sk_buff *reply_skb; + hdd_context_t *hdd_ctx = wiphy_priv(wiphy); + int ret; + + ENTER_DEV(wdev->netdev); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_warn("Command not allowed in FTM mode"); + return -EPERM; + } + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return ret; + + if (nla_parse(tb, MAX_CONCURRENT_MATRIX, data, data_len, + wlan_hdd_get_concurrency_matrix_policy)) { + hdd_err("Invalid ATTR"); + return -EINVAL; + } + + /* Parse and fetch max feature set */ + if (!tb[MATRIX_CONFIG_PARAM_SET_SIZE_MAX]) { + hdd_err("Attr max feature set size failed"); + return -EINVAL; + } + max_feature_sets = nla_get_u32(tb[MATRIX_CONFIG_PARAM_SET_SIZE_MAX]); + hdd_debug("Max feature set size: %d", max_feature_sets); + + /* Fill feature combination matrix */ + feature_sets = 0; + feature_set_matrix[feature_sets++] = WIFI_FEATURE_INFRA | + WIFI_FEATURE_P2P; + feature_set_matrix[feature_sets++] = WIFI_FEATURE_INFRA | + WIFI_FEATURE_NAN; + /* Add more feature combinations here */ + + feature_sets = QDF_MIN(feature_sets, max_feature_sets); + hdd_info("Number of feature sets: %d", feature_sets); + hdd_info("Feature set matrix"); + for (i = 0; i < feature_sets; i++) + hdd_info("[%d] 0x%02X", i, feature_set_matrix[i]); + + reply_skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, sizeof(u32) + + sizeof(u32) * feature_sets + NLMSG_HDRLEN); + if (!reply_skb) { + hdd_err("Feature set matrix: buffer alloc fail"); + return -ENOMEM; + } + + if (nla_put_u32(reply_skb, + QCA_WLAN_VENDOR_ATTR_GET_CONCURRENCY_MATRIX_RESULTS_SET_SIZE, + feature_sets) || + nla_put(reply_skb, + QCA_WLAN_VENDOR_ATTR_GET_CONCURRENCY_MATRIX_RESULTS_SET, + sizeof(u32) * feature_sets, + feature_set_matrix)) { + hdd_err("nla put fail"); + kfree_skb(reply_skb); + return -EINVAL; + } + return cfg80211_vendor_cmd_reply(reply_skb); +} + +#undef MAX_CONCURRENT_MATRIX +#undef MATRIX_CONFIG_PARAM_SET_SIZE_MAX + +/** + * wlan_hdd_cfg80211_get_concurrency_matrix() - get concurrency matrix + * @wiphy: pointer to wireless wiphy structure. + * @wdev: pointer to wireless_dev structure. + * @data: Pointer to the data to be passed via vendor interface + * @data_len:Length of the data to be passed + * + * Retrieves the concurrency feature set matrix + * + * Return: 0 on success, negative errno on failure + */ +static int +wlan_hdd_cfg80211_get_concurrency_matrix(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_get_concurrency_matrix(wiphy, wdev, + data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * wlan_hdd_cfg80211_set_feature() - Set the bitmask for supported features + * @feature_flags: pointer to the byte array of features. + * @feature: Feature to be turned ON in the byte array. + * + * Return: None + * + * This is called to turn ON or SET the feature flag for the requested feature. + **/ +#define NUM_BITS_IN_BYTE 8 +static void wlan_hdd_cfg80211_set_feature(uint8_t *feature_flags, + uint8_t feature) +{ + uint32_t index; + uint8_t bit_mask; + + index = feature / NUM_BITS_IN_BYTE; + bit_mask = 1 << (feature % NUM_BITS_IN_BYTE); + feature_flags[index] |= bit_mask; +} + +/** + * __wlan_hdd_cfg80211_get_features() - Get the Driver Supported features + * @wiphy: pointer to wireless wiphy structure. + * @wdev: pointer to wireless_dev structure. + * @data: Pointer to the data to be passed via vendor interface + * @data_len:Length of the data to be passed + * + * This is called when wlan driver needs to send supported feature set to + * supplicant upon a request/query from the supplicant. + * + * Return: Return the Success or Failure code. + **/ +#define MAX_CONCURRENT_CHAN_ON_24G 2 +#define MAX_CONCURRENT_CHAN_ON_5G 2 +static int +__wlan_hdd_cfg80211_get_features(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + struct sk_buff *skb = NULL; + uint32_t dbs_capability = 0; + bool one_by_one_dbs, two_by_two_dbs; + QDF_STATUS ret = QDF_STATUS_E_FAILURE; + int ret_val; + + uint8_t feature_flags[(NUM_QCA_WLAN_VENDOR_FEATURES + 7) / 8] = {0}; + hdd_context_t *hdd_ctx_ptr = wiphy_priv(wiphy); + + ENTER_DEV(wdev->netdev); + + ret_val = wlan_hdd_validate_context(hdd_ctx_ptr); + if (ret_val) + return ret_val; + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_warn("Command not allowed in FTM mode"); + return -EPERM; + } + + if (roaming_offload_enabled(hdd_ctx_ptr)) { + hdd_notice("Key Mgmt Offload is supported"); + wlan_hdd_cfg80211_set_feature(feature_flags, + QCA_WLAN_VENDOR_FEATURE_KEY_MGMT_OFFLOAD); + } + + wlan_hdd_cfg80211_set_feature(feature_flags, + QCA_WLAN_VENDOR_FEATURE_SUPPORT_HW_MODE_ANY); + if (wma_is_scan_simultaneous_capable()) + wlan_hdd_cfg80211_set_feature(feature_flags, + QCA_WLAN_VENDOR_FEATURE_OFFCHANNEL_SIMULTANEOUS); + + if (wma_is_p2p_lo_capable()) + wlan_hdd_cfg80211_set_feature(feature_flags, + QCA_WLAN_VENDOR_FEATURE_P2P_LISTEN_OFFLOAD); + + skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, sizeof(feature_flags) + + NLMSG_HDRLEN); + + if (!skb) { + hdd_err("cfg80211_vendor_cmd_alloc_reply_skb failed"); + return -ENOMEM; + } + + if (nla_put(skb, QCA_WLAN_VENDOR_ATTR_FEATURE_FLAGS, + sizeof(feature_flags), feature_flags)) + goto nla_put_failure; + + ret = wma_get_dbs_hw_modes(&one_by_one_dbs, &two_by_two_dbs); + if (QDF_STATUS_SUCCESS == ret) { + if (one_by_one_dbs) + dbs_capability = DRV_DBS_CAPABILITY_1X1; + + if (two_by_two_dbs) + dbs_capability = DRV_DBS_CAPABILITY_2X2; + + if (!one_by_one_dbs && !two_by_two_dbs) + dbs_capability = DRV_DBS_CAPABILITY_DISABLED; + } else { + hdd_err("wma_get_dbs_hw_mode failed"); + dbs_capability = DRV_DBS_CAPABILITY_DISABLED; + } + + hdd_info("dbs_capability is %d", dbs_capability); + + if (nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_MAX_CONCURRENT_CHANNELS_2_4_BAND, + MAX_CONCURRENT_CHAN_ON_24G)) + goto nla_put_failure; + + if (nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_MAX_CONCURRENT_CHANNELS_5_0_BAND, + MAX_CONCURRENT_CHAN_ON_5G)) + goto nla_put_failure; + + return cfg80211_vendor_cmd_reply(skb); + +nla_put_failure: + kfree_skb(skb); + return -EINVAL; +} + +/** + * wlan_hdd_cfg80211_get_features() - Get the Driver Supported features + * @wiphy: pointer to wireless wiphy structure. + * @wdev: pointer to wireless_dev structure. + * @data: Pointer to the data to be passed via vendor interface + * @data_len:Length of the data to be passed + * + * This is called when wlan driver needs to send supported feature set to + * supplicant upon a request/query from the supplicant. + * + * Return: Return the Success or Failure code. + */ +static int +wlan_hdd_cfg80211_get_features(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_get_features(wiphy, wdev, + data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +#define PARAM_NUM_NW \ + QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_WHITE_LIST_SSID_NUM_NETWORKS +#define PARAM_SET_BSSID \ + QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS_BSSID +#define PRAM_SSID_LIST QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_WHITE_LIST_SSID_LIST +#define PARAM_LIST_SSID QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_WHITE_LIST_SSID + +#define MAX_ROAMING_PARAM \ + QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_MAX + +static const struct nla_policy +wlan_hdd_set_roam_param_policy[MAX_ROAMING_PARAM + 1] = { + [QCA_WLAN_VENDOR_ATTR_ROAMING_SUBCMD] = {.type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_ROAMING_REQ_ID] = {.type = NLA_U32}, + [PARAM_NUM_NW] = {.type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_A_BAND_BOOST_FACTOR] = { + .type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_A_BAND_PENALTY_FACTOR] = { + .type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_A_BAND_MAX_BOOST] = { + .type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_LAZY_ROAM_HISTERESYS] = { + .type = NLA_S32}, + [QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_A_BAND_BOOST_THRESHOLD] = { + .type = NLA_S32}, + [QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_A_BAND_PENALTY_THRESHOLD] = { + .type = NLA_S32}, + [QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_ALERT_ROAM_RSSI_TRIGGER] = { + .type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_LAZY_ROAM_ENABLE] = { + .type = NLA_S32}, + [QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_LAZY_ROAM_NUM_BSSID] = { + .type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_LAZY_ROAM_RSSI_MODIFIER] = { + .type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS_NUM_BSSID] = { + .type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_LAZY_ROAM_BSSID] = { + .type = NLA_UNSPEC, + .len = QDF_MAC_ADDR_SIZE}, + [PARAM_SET_BSSID] = {.type = NLA_UNSPEC, .len = QDF_MAC_ADDR_SIZE}, +}; + +/** + * __wlan_hdd_cfg80211_set_ext_roam_params() - Settings for roaming parameters + * @wiphy: The wiphy structure + * @wdev: The wireless device + * @data: Data passed by framework + * @data_len: Parameters to be configured passed as data + * + * The roaming related parameters are configured by the framework + * using this interface. + * + * Return: Return either success or failure code. + */ +static int +__wlan_hdd_cfg80211_set_ext_roam_params(struct wiphy *wiphy, + struct wireless_dev *wdev, const void *data, int data_len) +{ + struct net_device *dev = wdev->netdev; + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *pHddCtx = wiphy_priv(wiphy); + uint8_t session_id; + struct roam_ext_params roam_params; + uint32_t cmd_type, req_id; + struct nlattr *curr_attr = NULL; + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_MAX + 1]; + struct nlattr *tb2[QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_MAX + 1]; + int rem, i; + uint32_t buf_len = 0; + uint32_t count; + int ret; + + ENTER_DEV(dev); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_warn("Command not allowed in FTM mode"); + return -EPERM; + } + + ret = wlan_hdd_validate_context(pHddCtx); + if (ret) + return ret; + + if (pHddCtx->driver_status == DRIVER_MODULES_CLOSED) { + hdd_err("Driver Modules are closed"); + return -EINVAL; + } + + if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_MAX, + data, data_len, + wlan_hdd_set_roam_param_policy)) { + hdd_err("Invalid ATTR"); + return -EINVAL; + } + /* Parse and fetch Command Type*/ + if (!tb[QCA_WLAN_VENDOR_ATTR_ROAMING_SUBCMD]) { + hdd_err("roam cmd type failed"); + goto fail; + } + session_id = pAdapter->sessionId; + qdf_mem_set(&roam_params, sizeof(roam_params), 0); + cmd_type = nla_get_u32(tb[QCA_WLAN_VENDOR_ATTR_ROAMING_SUBCMD]); + if (!tb[QCA_WLAN_VENDOR_ATTR_ROAMING_REQ_ID]) { + hdd_err("attr request id failed"); + goto fail; + } + req_id = nla_get_u32( + tb[QCA_WLAN_VENDOR_ATTR_ROAMING_REQ_ID]); + hdd_debug("Req Id (%d)", req_id); + hdd_debug("Cmd Type (%d)", cmd_type); + switch (cmd_type) { + case QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_SSID_WHITE_LIST: + i = 0; + if (tb[PARAM_NUM_NW]) { + count = nla_get_u32( + tb[PARAM_NUM_NW]); + } else { + hdd_err("Number of networks is not provided"); + goto fail; + } + + if (count && + tb[PRAM_SSID_LIST]) { + nla_for_each_nested(curr_attr, + tb[PRAM_SSID_LIST], rem) { + if (nla_parse(tb2, + QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_MAX, + nla_data(curr_attr), nla_len(curr_attr), + wlan_hdd_set_roam_param_policy)) { + hdd_err("nla_parse failed"); + goto fail; + } + /* Parse and Fetch allowed SSID list*/ + if (!tb2[PARAM_LIST_SSID]) { + hdd_err("attr allowed ssid failed"); + goto fail; + } + buf_len = nla_len(tb2[PARAM_LIST_SSID]); + /* + * Upper Layers include a null termination + * character. Check for the actual permissible + * length of SSID and also ensure not to copy + * the NULL termination character to the driver + * buffer. + */ + if (buf_len && (i < MAX_SSID_ALLOWED_LIST) && + ((buf_len - 1) <= + SIR_MAC_MAX_SSID_LENGTH)) { + nla_memcpy( + roam_params.ssid_allowed_list[i].ssId, + tb2[PARAM_LIST_SSID], buf_len - 1); + roam_params.ssid_allowed_list[i].length + = buf_len - 1; + hdd_debug("SSID[%d]: %.*s,length = %d", + i, + roam_params.ssid_allowed_list[i].length, + roam_params.ssid_allowed_list[i].ssId, + roam_params.ssid_allowed_list[i].length); + i++; + } else { + hdd_err("Invalid buffer length"); + } + } + } + if (i != count) { + hdd_err("Invalid number of SSIDs i = %d, count = %d", + i, count); + goto fail; + } + + roam_params.num_ssid_allowed_list = i; + hdd_debug("Num of Allowed SSID %d", + roam_params.num_ssid_allowed_list); + sme_update_roam_params(pHddCtx->hHal, session_id, + roam_params, REASON_ROAM_SET_SSID_ALLOWED); + break; + case QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_SET_EXTSCAN_ROAM_PARAMS: + /* Parse and fetch 5G Boost Threshold */ + if (!tb[QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_A_BAND_BOOST_THRESHOLD]) { + hdd_err("5G boost threshold failed"); + goto fail; + } + roam_params.raise_rssi_thresh_5g = nla_get_s32( + tb[QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_A_BAND_BOOST_THRESHOLD]); + hdd_debug("5G Boost Threshold (%d)", + roam_params.raise_rssi_thresh_5g); + /* Parse and fetch 5G Penalty Threshold */ + if (!tb[QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_A_BAND_PENALTY_THRESHOLD]) { + hdd_err("5G penalty threshold failed"); + goto fail; + } + roam_params.drop_rssi_thresh_5g = nla_get_s32( + tb[QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_A_BAND_PENALTY_THRESHOLD]); + hdd_debug("5G Penalty Threshold (%d)", + roam_params.drop_rssi_thresh_5g); + /* Parse and fetch 5G Boost Factor */ + if (!tb[QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_A_BAND_BOOST_FACTOR]) { + hdd_err("5G boost Factor failed"); + goto fail; + } + roam_params.raise_factor_5g = nla_get_u32( + tb[QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_A_BAND_BOOST_FACTOR]); + hdd_debug("5G Boost Factor (%d)", + roam_params.raise_factor_5g); + /* Parse and fetch 5G Penalty factor */ + if (!tb[QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_A_BAND_PENALTY_FACTOR]) { + hdd_err("5G Penalty Factor failed"); + goto fail; + } + roam_params.drop_factor_5g = nla_get_u32( + tb[QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_A_BAND_PENALTY_FACTOR]); + hdd_debug("5G Penalty factor (%d)", + roam_params.drop_factor_5g); + /* Parse and fetch 5G Max Boost */ + if (!tb[QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_A_BAND_MAX_BOOST]) { + hdd_err("5G Max Boost failed"); + goto fail; + } + roam_params.max_raise_rssi_5g = nla_get_u32( + tb[QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_A_BAND_MAX_BOOST]); + hdd_debug("5G Max Boost (%d)", + roam_params.max_raise_rssi_5g); + /* Parse and fetch Rssi Diff */ + if (!tb[QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_LAZY_ROAM_HISTERESYS]) { + hdd_err("Rssi Diff failed"); + goto fail; + } + roam_params.rssi_diff = nla_get_s32( + tb[QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_LAZY_ROAM_HISTERESYS]); + hdd_debug("RSSI Diff (%d)", + roam_params.rssi_diff); + /* Parse and fetch Alert Rssi Threshold */ + if (!tb[QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_ALERT_ROAM_RSSI_TRIGGER]) { + hdd_err("Alert Rssi Threshold failed"); + goto fail; + } + roam_params.alert_rssi_threshold = nla_get_u32( + tb[QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_ALERT_ROAM_RSSI_TRIGGER]); + hdd_debug("Alert RSSI Threshold (%d)", + roam_params.alert_rssi_threshold); + sme_update_roam_params(pHddCtx->hHal, session_id, + roam_params, + REASON_ROAM_EXT_SCAN_PARAMS_CHANGED); + break; + case QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_SET_LAZY_ROAM: + /* Parse and fetch Activate Good Rssi Roam */ + if (!tb[QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_LAZY_ROAM_ENABLE]) { + hdd_err("Activate Good Rssi Roam failed"); + goto fail; + } + roam_params.good_rssi_roam = nla_get_s32( + tb[QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_LAZY_ROAM_ENABLE]); + hdd_debug("Activate Good Rssi Roam (%d)", + roam_params.good_rssi_roam); + sme_update_roam_params(pHddCtx->hHal, session_id, + roam_params, REASON_ROAM_GOOD_RSSI_CHANGED); + break; + case QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_SET_BSSID_PREFS: + /* Parse and fetch number of preferred BSSID */ + if (!tb[QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_LAZY_ROAM_NUM_BSSID]) { + hdd_err("attr num of preferred bssid failed"); + goto fail; + } + count = nla_get_u32( + tb[QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_LAZY_ROAM_NUM_BSSID]); + if (count > MAX_BSSID_FAVORED) { + hdd_err("Preferred BSSID count %u exceeds max %u", + count, MAX_BSSID_FAVORED); + goto fail; + } + hdd_debug("Num of Preferred BSSID (%d)", count); + if (!tb[QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PREFS]) { + hdd_err("attr Preferred BSSID failed"); + goto fail; + } + i = 0; + nla_for_each_nested(curr_attr, + tb[QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PREFS], + rem) { + + if (i == count) { + hdd_warn("Ignoring excess Preferred BSSID"); + break; + } + + if (nla_parse(tb2, + QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_MAX, + nla_data(curr_attr), nla_len(curr_attr), + wlan_hdd_set_roam_param_policy)) { + hdd_err("nla_parse failed"); + goto fail; + } + /* Parse and fetch MAC address */ + if (!tb2[QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_LAZY_ROAM_BSSID]) { + hdd_err("attr mac address failed"); + goto fail; + } + nla_memcpy(roam_params.bssid_favored[i].bytes, + tb2[QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_LAZY_ROAM_BSSID], + QDF_MAC_ADDR_SIZE); + hdd_debug(MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(roam_params.bssid_favored[i].bytes)); + /* Parse and fetch preference factor*/ + if (!tb2[QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_LAZY_ROAM_RSSI_MODIFIER]) { + hdd_err("BSSID Preference score failed"); + goto fail; + } + roam_params.bssid_favored_factor[i] = nla_get_u32( + tb2[QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_LAZY_ROAM_RSSI_MODIFIER]); + hdd_debug("BSSID Preference score (%d)", + roam_params.bssid_favored_factor[i]); + i++; + } + if (i < count) + hdd_warn("Num Preferred BSSID %u less than expected %u", + i, count); + roam_params.num_bssid_favored = i; + sme_update_roam_params(pHddCtx->hHal, session_id, + roam_params, REASON_ROAM_SET_FAVORED_BSSID); + break; + case QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_SET_BLACKLIST_BSSID: + /* Parse and fetch number of blacklist BSSID */ + if (!tb[QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS_NUM_BSSID]) { + hdd_err("attr num of blacklist bssid failed"); + goto fail; + } + count = nla_get_u32( + tb[QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS_NUM_BSSID]); + if (count > MAX_BSSID_AVOID_LIST) { + hdd_err("Blacklist BSSID count %u exceeds max %u", + count, MAX_BSSID_AVOID_LIST); + goto fail; + } + hdd_debug("Num of blacklist BSSID (%d)", count); + i = 0; + + if (count && + tb[QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS]) { + nla_for_each_nested(curr_attr, + tb[QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS], + rem) { + + if (i == count) { + hdd_warn("Ignoring excess Blacklist BSSID"); + break; + } + + if (nla_parse(tb2, + QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_MAX, + nla_data(curr_attr), nla_len(curr_attr), + wlan_hdd_set_roam_param_policy)) { + hdd_err("nla_parse failed"); + goto fail; + } + /* Parse and fetch MAC address */ + if (!tb2[PARAM_SET_BSSID]) { + hdd_err("attr blacklist addr failed"); + goto fail; + } + nla_memcpy( + roam_params.bssid_avoid_list[i].bytes, + tb2[PARAM_SET_BSSID], QDF_MAC_ADDR_SIZE); + hdd_debug(MAC_ADDRESS_STR, + MAC_ADDR_ARRAY( + roam_params.bssid_avoid_list[i].bytes)); + i++; + } + } + if (i < count) + hdd_warn("Num Blacklist BSSID %u less than expected %u", + i, count); + roam_params.num_bssid_avoid_list = i; + sme_update_roam_params(pHddCtx->hHal, session_id, + roam_params, REASON_ROAM_SET_BLACKLIST_BSSID); + break; + } + return 0; +fail: + return -EINVAL; +} +#undef PARAM_NUM_NW +#undef PARAM_SET_BSSID +#undef PRAM_SSID_LIST +#undef PARAM_LIST_SSID + + +/** + * wlan_hdd_cfg80211_set_ext_roam_params() - set ext scan roam params + * @wiphy: pointer to wireless wiphy structure. + * @wdev: pointer to wireless_dev structure. + * @data: Pointer to the data to be passed via vendor interface + * @data_len:Length of the data to be passed + * + * Return: Return the Success or Failure code. + */ +static int +wlan_hdd_cfg80211_set_ext_roam_params(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_set_ext_roam_params(wiphy, wdev, + data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +static const struct nla_policy +wlan_hdd_set_no_dfs_flag_config_policy[QCA_WLAN_VENDOR_ATTR_SET_NO_DFS_FLAG_MAX + +1] = { + [QCA_WLAN_VENDOR_ATTR_SET_NO_DFS_FLAG] = {.type = NLA_U32 }, +}; + +/** + * wlan_hdd_check_dfs_channel_for_adapter() - check dfs channel in adapter + * @hdd_ctx: HDD context + * @device_mode: device mode + * Return: bool + */ +static bool wlan_hdd_check_dfs_channel_for_adapter(hdd_context_t *hdd_ctx, + enum tQDF_ADAPTER_MODE device_mode) +{ + hdd_adapter_t *adapter; + hdd_adapter_list_node_t *adapter_node = NULL, *next = NULL; + hdd_ap_ctx_t *ap_ctx; + hdd_station_ctx_t *sta_ctx; + QDF_STATUS qdf_status; + + qdf_status = hdd_get_front_adapter(hdd_ctx, + &adapter_node); + + while ((NULL != adapter_node) && + (QDF_STATUS_SUCCESS == qdf_status)) { + adapter = adapter_node->pAdapter; + + if ((device_mode == adapter->device_mode) && + (device_mode == QDF_SAP_MODE)) { + ap_ctx = + WLAN_HDD_GET_AP_CTX_PTR(adapter); + + /* + * if there is SAP already running on DFS channel, + * do not disable scan on dfs channels. Note that + * with SAP on DFS, there cannot be conurrency on + * single radio. But then we can have multiple + * radios !! + */ + if (CHANNEL_STATE_DFS == + cds_get_channel_state( + ap_ctx->operatingChannel)) { + hdd_err("SAP running on DFS channel"); + return true; + } + } + + if ((device_mode == adapter->device_mode) && + (device_mode == QDF_STA_MODE)) { + sta_ctx = + WLAN_HDD_GET_STATION_CTX_PTR(adapter); + + /* + * if STA is already connected on DFS channel, + * do not disable scan on dfs channels + */ + if (hdd_conn_is_connected(sta_ctx) && + (CHANNEL_STATE_DFS == + cds_get_channel_state( + sta_ctx->conn_info.operationChannel))) { + hdd_err("client connected on DFS channel"); + return true; + } + } + + qdf_status = hdd_get_next_adapter(hdd_ctx, + adapter_node, + &next); + adapter_node = next; + } + + return false; +} + +/** + * wlan_hdd_disable_dfs_chan_scan() - disable/enable DFS channels + * @hdd_ctx: HDD context within host driver + * @adapter: Adapter pointer + * @no_dfs_flag: If TRUE, DFS channels cannot be used for scanning + * + * Loops through devices to see who is operating on DFS channels + * and then disables/enables DFS channels by calling SME API. + * Fails the disable request if any device is active on a DFS channel. + * + * Return: 0 or other error codes. + */ + +int wlan_hdd_disable_dfs_chan_scan(hdd_context_t *hdd_ctx, + hdd_adapter_t *adapter, + uint32_t no_dfs_flag) +{ + tHalHandle h_hal = WLAN_HDD_GET_HAL_CTX(adapter); + QDF_STATUS status; + int ret_val = -EPERM; + + if (no_dfs_flag == hdd_ctx->config->enableDFSChnlScan) { + if (no_dfs_flag) { + status = wlan_hdd_check_dfs_channel_for_adapter( + hdd_ctx, QDF_STA_MODE); + + if (true == status) + return -EOPNOTSUPP; + + status = wlan_hdd_check_dfs_channel_for_adapter( + hdd_ctx, QDF_SAP_MODE); + + if (true == status) + return -EOPNOTSUPP; + } + + hdd_ctx->config->enableDFSChnlScan = !no_dfs_flag; + + hdd_abort_mac_scan_all_adapters(hdd_ctx); + + /* + * call the SME API to tunnel down the new channel list + * to the firmware + */ + status = sme_handle_dfs_chan_scan( + h_hal, hdd_ctx->config->enableDFSChnlScan); + + if (QDF_STATUS_SUCCESS == status) { + ret_val = 0; + + /* + * Clear the SME scan cache also. Note that the + * clearing of scan results is independent of session; + * so no need to iterate over + * all sessions + */ + status = sme_scan_flush_result(h_hal); + if (QDF_STATUS_SUCCESS != status) + ret_val = -EPERM; + } + + } else { + hdd_notice(" the DFS flag has not changed"); + ret_val = 0; + } + return ret_val; +} + +/** + * __wlan_hdd_cfg80211_disable_dfs_chan_scan() - DFS channel configuration + * @wiphy: corestack handler + * @wdev: wireless device + * @data: data + * @data_len: data length + * Return: success(0) or reason code for failure + */ +static int __wlan_hdd_cfg80211_disable_dfs_chan_scan(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + struct net_device *dev = wdev->netdev; + hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *hdd_ctx = wiphy_priv(wiphy); + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_SET_NO_DFS_FLAG_MAX + 1]; + int ret_val; + uint32_t no_dfs_flag = 0; + + ENTER_DEV(dev); + + ret_val = wlan_hdd_validate_context(hdd_ctx); + if (ret_val) + return ret_val; + + if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_SET_NO_DFS_FLAG_MAX, + data, data_len, + wlan_hdd_set_no_dfs_flag_config_policy)) { + hdd_err("invalid attr"); + return -EINVAL; + } + + if (!tb[QCA_WLAN_VENDOR_ATTR_SET_NO_DFS_FLAG]) { + hdd_err("attr dfs flag failed"); + return -EINVAL; + } + + no_dfs_flag = nla_get_u32( + tb[QCA_WLAN_VENDOR_ATTR_SET_NO_DFS_FLAG]); + + hdd_notice(" DFS flag = %d", no_dfs_flag); + + if (no_dfs_flag > 1) { + hdd_err("invalid value of dfs flag"); + return -EINVAL; + } + + ret_val = wlan_hdd_disable_dfs_chan_scan(hdd_ctx, adapter, + no_dfs_flag); + return ret_val; +} + +/** + * wlan_hdd_cfg80211_disable_dfs_chan_scan () - DFS scan vendor command + * + * @wiphy: wiphy device pointer + * @wdev: wireless device pointer + * @data: Vendor command data buffer + * @data_len: Buffer length + * + * Handles QCA_WLAN_VENDOR_ATTR_SET_NO_DFS_FLAG_MAX. Validate it and + * call wlan_hdd_disable_dfs_chan_scan to send it to firmware. + * + * Return: EOK or other error codes. + */ + +static int wlan_hdd_cfg80211_disable_dfs_chan_scan(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_disable_dfs_chan_scan(wiphy, wdev, + data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +static const struct nla_policy +wlan_hdd_wisa_cmd_policy[QCA_WLAN_VENDOR_ATTR_WISA_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_WISA_MODE] = {.type = NLA_U32 }, +}; + +/** + * __wlan_hdd_cfg80211_handle_wisa_cmd() - Handle WISA vendor cmd + * @wiphy: wiphy device pointer + * @wdev: wireless device pointer + * @data: Vendor command data buffer + * @data_len: Buffer length + * + * Handles QCA_WLAN_VENDOR_SUBCMD_WISA. Validate cmd attributes and + * setup WISA Mode features. + * + * Return: Success(0) or reason code for failure + */ +static int __wlan_hdd_cfg80211_handle_wisa_cmd(struct wiphy *wiphy, + struct wireless_dev *wdev, const void *data, int data_len) +{ + struct net_device *dev = wdev->netdev; + hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *hdd_ctx = wiphy_priv(wiphy); + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_WISA_MAX + 1]; + struct sir_wisa_params wisa; + int ret_val; + QDF_STATUS status; + bool wisa_mode; + + ENTER_DEV(dev); + ret_val = wlan_hdd_validate_context(hdd_ctx); + if (ret_val) + goto err; + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_warn("Command not allowed in FTM mode"); + return -EPERM; + } + + if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_WISA_MAX, data, data_len, + wlan_hdd_wisa_cmd_policy)) { + hdd_err("Invalid WISA cmd attributes"); + ret_val = -EINVAL; + goto err; + } + if (!tb[QCA_WLAN_VENDOR_ATTR_WISA_MODE]) { + hdd_err("Invalid WISA mode"); + ret_val = -EINVAL; + goto err; + } + + wisa_mode = !!nla_get_u32(tb[QCA_WLAN_VENDOR_ATTR_WISA_MODE]); + hdd_info("WISA Mode: %d", wisa_mode); + wisa.mode = wisa_mode; + wisa.vdev_id = adapter->sessionId; + status = sme_set_wisa_params(hdd_ctx->hHal, &wisa); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("Unable to set WISA mode: %d to FW", wisa_mode); + ret_val = -EINVAL; + } + if (QDF_IS_STATUS_SUCCESS(status) || wisa_mode == false) + ol_txrx_set_wisa_mode(ol_txrx_get_vdev_from_vdev_id( + adapter->sessionId), wisa_mode); +err: + EXIT(); + return ret_val; +} + +/** + * wlan_hdd_cfg80211_handle_wisa_cmd() - Handle WISA vendor cmd + * @wiphy: corestack handler + * @wdev: wireless device + * @data: data + * @data_len: data length + * + * Handles QCA_WLAN_VENDOR_SUBCMD_WISA. Validate cmd attributes and + * setup WISA mode features. + * + * Return: Success(0) or reason code for failure + */ +static int wlan_hdd_cfg80211_handle_wisa_cmd(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_handle_wisa_cmd(wiphy, wdev, data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +/* + * define short names for the global vendor params + * used by __wlan_hdd_cfg80211_get_station_cmd() + */ +#define STATION_INVALID \ + QCA_WLAN_VENDOR_ATTR_GET_STATION_INVALID +#define STATION_INFO \ + QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO +#define STATION_ASSOC_FAIL_REASON \ + QCA_WLAN_VENDOR_ATTR_GET_STATION_ASSOC_FAIL_REASON +#define STATION_MAX \ + QCA_WLAN_VENDOR_ATTR_GET_STATION_MAX + +static const struct nla_policy +hdd_get_station_policy[STATION_MAX + 1] = { + [STATION_INFO] = {.type = NLA_FLAG}, + [STATION_ASSOC_FAIL_REASON] = {.type = NLA_FLAG}, +}; + +/** + * hdd_get_station_assoc_fail() - Handle get station assoc fail + * @hdd_ctx: HDD context within host driver + * @wdev: wireless device + * + * Handles QCA_NL80211_VENDOR_SUBCMD_GET_STATION_ASSOC_FAIL. + * Validate cmd attributes and send the station info to upper layers. + * + * Return: Success(0) or reason code for failure + */ +static int hdd_get_station_assoc_fail(hdd_context_t *hdd_ctx, + hdd_adapter_t *adapter) +{ + struct sk_buff *skb = NULL; + uint32_t nl_buf_len; + hdd_station_ctx_t *hdd_sta_ctx; + + nl_buf_len = NLMSG_HDRLEN; + nl_buf_len += sizeof(uint32_t); + skb = cfg80211_vendor_cmd_alloc_reply_skb(hdd_ctx->wiphy, nl_buf_len); + + if (!skb) { + hdd_err("cfg80211_vendor_cmd_alloc_reply_skb failed"); + return -ENOMEM; + } + + hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + + if (nla_put_u32(skb, INFO_ASSOC_FAIL_REASON, + hdd_sta_ctx->conn_info.assoc_status_code)) { + hdd_err("put fail"); + goto fail; + } + + hdd_info("congestion:%d", hdd_sta_ctx->conn_info.cca); + if (nla_put_u32(skb, NL80211_SURVEY_INFO_CHANNEL_TIME_BUSY, + hdd_sta_ctx->conn_info.cca)) { + hdd_err("put fail"); + goto fail; + } + + return cfg80211_vendor_cmd_reply(skb); +fail: + if (skb) + kfree_skb(skb); + return -EINVAL; +} + +/** + * hdd_map_auth_type() - transform auth type specific to + * vendor command + * @auth_type: csr auth type + * + * Return: Success(0) or reason code for failure + */ +static int hdd_convert_auth_type(uint32_t auth_type) +{ + uint32_t ret_val; + + switch (auth_type) { + case eCSR_AUTH_TYPE_OPEN_SYSTEM: + ret_val = QCA_WLAN_AUTH_TYPE_OPEN; + break; + case eCSR_AUTH_TYPE_SHARED_KEY: + ret_val = QCA_WLAN_AUTH_TYPE_SHARED; + break; + case eCSR_AUTH_TYPE_WPA: + ret_val = QCA_WLAN_AUTH_TYPE_WPA; + break; + case eCSR_AUTH_TYPE_WPA_PSK: + ret_val = QCA_WLAN_AUTH_TYPE_WPA_PSK; + break; + case eCSR_AUTH_TYPE_AUTOSWITCH: + ret_val = QCA_WLAN_AUTH_TYPE_AUTOSWITCH; + break; + case eCSR_AUTH_TYPE_WPA_NONE: + ret_val = QCA_WLAN_AUTH_TYPE_WPA_NONE; + break; + case eCSR_AUTH_TYPE_RSN: + ret_val = QCA_WLAN_AUTH_TYPE_RSN; + break; + case eCSR_AUTH_TYPE_RSN_PSK: + ret_val = QCA_WLAN_AUTH_TYPE_RSN_PSK; + break; + case eCSR_AUTH_TYPE_FT_RSN: + ret_val = QCA_WLAN_AUTH_TYPE_FT; + break; + case eCSR_AUTH_TYPE_FT_RSN_PSK: + ret_val = QCA_WLAN_AUTH_TYPE_FT_PSK; + break; + case eCSR_AUTH_TYPE_WAPI_WAI_CERTIFICATE: + ret_val = QCA_WLAN_AUTH_TYPE_WAI; + break; + case eCSR_AUTH_TYPE_WAPI_WAI_PSK: + ret_val = QCA_WLAN_AUTH_TYPE_WAI_PSK; + break; + case eCSR_AUTH_TYPE_CCKM_WPA: + ret_val = QCA_WLAN_AUTH_TYPE_CCKM_WPA; + break; + case eCSR_AUTH_TYPE_CCKM_RSN: + ret_val = QCA_WLAN_AUTH_TYPE_CCKM_RSN; + break; + case eCSR_AUTH_TYPE_RSN_PSK_SHA256: + ret_val = QCA_WLAN_AUTH_TYPE_SHA256_PSK; + break; + case eCSR_AUTH_TYPE_RSN_8021X_SHA256: + ret_val = QCA_WLAN_AUTH_TYPE_SHA256; + break; + case eCSR_NUM_OF_SUPPORT_AUTH_TYPE: + case eCSR_AUTH_TYPE_FAILED: + case eCSR_AUTH_TYPE_NONE: + default: + ret_val = QCA_WLAN_AUTH_TYPE_INVALID; + break; + } + return ret_val; +} + +/** + * hdd_map_dot_11_mode() - transform dot11mode type specific to + * vendor command + * @dot11mode: dot11mode + * + * Return: Success(0) or reason code for failure + */ +static int hdd_convert_dot11mode(uint32_t dot11mode) +{ + uint32_t ret_val; + + switch (dot11mode) { + case eCSR_CFG_DOT11_MODE_11A: + ret_val = QCA_WLAN_802_11_MODE_11A; + break; + case eCSR_CFG_DOT11_MODE_11B: + ret_val = QCA_WLAN_802_11_MODE_11B; + break; + case eCSR_CFG_DOT11_MODE_11G: + ret_val = QCA_WLAN_802_11_MODE_11G; + break; + case eCSR_CFG_DOT11_MODE_11N: + ret_val = QCA_WLAN_802_11_MODE_11N; + break; + case eCSR_CFG_DOT11_MODE_11AC: + ret_val = QCA_WLAN_802_11_MODE_11AC; + break; + case eCSR_CFG_DOT11_MODE_AUTO: + case eCSR_CFG_DOT11_MODE_ABG: + default: + ret_val = QCA_WLAN_802_11_MODE_INVALID; + } + return ret_val; +} + +/** + * hdd_add_tx_bitrate() - add tx bitrate attribute + * @skb: pointer to sk buff + * @hdd_sta_ctx: pointer to hdd station context + * @idx: attribute index + * + * Return: Success(0) or reason code for failure + */ +static int32_t hdd_add_tx_bitrate(struct sk_buff *skb, + hdd_station_ctx_t *hdd_sta_ctx, + int idx) +{ + struct nlattr *nla_attr; + uint32_t bitrate, bitrate_compat; + + nla_attr = nla_nest_start(skb, idx); + if (!nla_attr) + goto fail; + /* cfg80211_calculate_bitrate will return 0 for mcs >= 32 */ + bitrate = cfg80211_calculate_bitrate(&hdd_sta_ctx->conn_info.txrate); + + /* report 16-bit bitrate only if we can */ + bitrate_compat = bitrate < (1UL << 16) ? bitrate : 0; + if (bitrate > 0 && + nla_put_u32(skb, NL80211_RATE_INFO_BITRATE32, bitrate)) { + hdd_err("put fail"); + goto fail; + } + if (bitrate_compat > 0 && + nla_put_u16(skb, NL80211_RATE_INFO_BITRATE, bitrate_compat)) { + hdd_err("put fail"); + goto fail; + } + if (nla_put_u8(skb, NL80211_RATE_INFO_VHT_NSS, + hdd_sta_ctx->conn_info.txrate.nss)) { + hdd_err("put fail"); + goto fail; + } + nla_nest_end(skb, nla_attr); + return 0; +fail: + return -EINVAL; +} + +/** + * hdd_add_sta_info() - add station info attribute + * @skb: pointer to sk buff + * @hdd_sta_ctx: pointer to hdd station context + * @idx: attribute index + * + * Return: Success(0) or reason code for failure + */ +static int32_t hdd_add_sta_info(struct sk_buff *skb, + hdd_station_ctx_t *hdd_sta_ctx, int idx) +{ + struct nlattr *nla_attr; + + nla_attr = nla_nest_start(skb, idx); + if (!nla_attr) + goto fail; + if (nla_put_u8(skb, NL80211_STA_INFO_SIGNAL, + (hdd_sta_ctx->conn_info.signal + 100))) { + hdd_err("put fail"); + goto fail; + } + if (hdd_add_tx_bitrate(skb, hdd_sta_ctx, NL80211_STA_INFO_TX_BITRATE)) + goto fail; + nla_nest_end(skb, nla_attr); + return 0; +fail: + return -EINVAL; +} + +/** + * hdd_add_survey_info() - add survey info attribute + * @skb: pointer to sk buff + * @hdd_sta_ctx: pointer to hdd station context + * @idx: attribute index + * + * Return: Success(0) or reason code for failure + */ +static int32_t hdd_add_survey_info(struct sk_buff *skb, + hdd_station_ctx_t *hdd_sta_ctx, + int idx) +{ + struct nlattr *nla_attr; + + nla_attr = nla_nest_start(skb, idx); + if (!nla_attr) + goto fail; + if (nla_put_u32(skb, NL80211_SURVEY_INFO_FREQUENCY, + hdd_sta_ctx->conn_info.freq) || + nla_put_u8(skb, NL80211_SURVEY_INFO_NOISE, + (hdd_sta_ctx->conn_info.noise + 100))) { + hdd_err("put fail"); + goto fail; + } + nla_nest_end(skb, nla_attr); + return 0; +fail: + return -EINVAL; +} + +/** + * hdd_add_link_standard_info() - add link info attribute + * @skb: pointer to sk buff + * @hdd_sta_ctx: pointer to hdd station context + * @idx: attribute index + * + * Return: Success(0) or reason code for failure + */ +static int32_t +hdd_add_link_standard_info(struct sk_buff *skb, + hdd_station_ctx_t *hdd_sta_ctx, int idx) +{ + struct nlattr *nla_attr; + + nla_attr = nla_nest_start(skb, idx); + if (!nla_attr) + goto fail; + if (nla_put(skb, + NL80211_ATTR_SSID, + hdd_sta_ctx->conn_info.SSID.SSID.length, + hdd_sta_ctx->conn_info.SSID.SSID.ssId)) { + hdd_err("put fail"); + goto fail; + } + if (hdd_add_survey_info(skb, hdd_sta_ctx, NL80211_ATTR_SURVEY_INFO)) + goto fail; + if (hdd_add_sta_info(skb, hdd_sta_ctx, NL80211_ATTR_STA_INFO)) + goto fail; + nla_nest_end(skb, nla_attr); + return 0; +fail: + return -EINVAL; +} + +/** + * hdd_add_ap_standard_info() - add ap info attribute + * @skb: pointer to sk buff + * @hdd_sta_ctx: pointer to hdd station context + * @idx: attribute index + * + * Return: Success(0) or reason code for failure + */ +static int32_t +hdd_add_ap_standard_info(struct sk_buff *skb, + hdd_station_ctx_t *hdd_sta_ctx, int idx) +{ + struct nlattr *nla_attr; + + nla_attr = nla_nest_start(skb, idx); + if (!nla_attr) + goto fail; + if (hdd_sta_ctx->conn_info.conn_flag.vht_present) + if (nla_put(skb, NL80211_ATTR_VHT_CAPABILITY, + sizeof(hdd_sta_ctx->conn_info.vht_caps), + &hdd_sta_ctx->conn_info.vht_caps)) { + hdd_err("put fail"); + goto fail; + } + if (hdd_sta_ctx->conn_info.conn_flag.ht_present) + if (nla_put(skb, NL80211_ATTR_HT_CAPABILITY, + sizeof(hdd_sta_ctx->conn_info.ht_caps), + &hdd_sta_ctx->conn_info.ht_caps)) { + hdd_err("put fail"); + goto fail; + } + nla_nest_end(skb, nla_attr); + return 0; +fail: + return -EINVAL; +} + +/** + * hdd_get_station_info() - send BSS information to supplicant + * @hdd_ctx: pointer to hdd context + * @adapter: pointer to adapter + * + * Return: 0 if success else error status + */ +static int hdd_get_station_info(hdd_context_t *hdd_ctx, + hdd_adapter_t *adapter) +{ + struct sk_buff *skb = NULL; + uint8_t *tmp_hs20 = NULL; + uint32_t nl_buf_len; + hdd_station_ctx_t *hdd_sta_ctx; + + hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + + nl_buf_len = NLMSG_HDRLEN; + nl_buf_len += sizeof(hdd_sta_ctx->conn_info.SSID.SSID.length) + + sizeof(hdd_sta_ctx->conn_info.freq) + + sizeof(hdd_sta_ctx->conn_info.noise) + + sizeof(hdd_sta_ctx->conn_info.signal) + + (sizeof(uint32_t) * 2) + + sizeof(hdd_sta_ctx->conn_info.txrate.nss) + + sizeof(hdd_sta_ctx->conn_info.roam_count) + + sizeof(hdd_sta_ctx->conn_info.authType) + + sizeof(hdd_sta_ctx->conn_info.dot11Mode); + if (hdd_sta_ctx->conn_info.conn_flag.vht_present) + nl_buf_len += sizeof(hdd_sta_ctx->conn_info.vht_caps); + if (hdd_sta_ctx->conn_info.conn_flag.ht_present) + nl_buf_len += sizeof(hdd_sta_ctx->conn_info.ht_caps); + if (hdd_sta_ctx->conn_info.conn_flag.hs20_present) { + tmp_hs20 = (uint8_t *)&(hdd_sta_ctx->conn_info.hs20vendor_ie); + nl_buf_len += (sizeof(hdd_sta_ctx->conn_info.hs20vendor_ie) - + 1); + } + if (hdd_sta_ctx->conn_info.conn_flag.ht_op_present) + nl_buf_len += sizeof(hdd_sta_ctx->conn_info.ht_operation); + if (hdd_sta_ctx->conn_info.conn_flag.vht_op_present) + nl_buf_len += sizeof(hdd_sta_ctx->conn_info.vht_operation); + + + skb = cfg80211_vendor_cmd_alloc_reply_skb(hdd_ctx->wiphy, nl_buf_len); + if (!skb) { + hdd_err(FL("cfg80211_vendor_cmd_alloc_reply_skb failed")); + return -ENOMEM; + } + + if (hdd_add_link_standard_info(skb, hdd_sta_ctx, + LINK_INFO_STANDARD_NL80211_ATTR)) { + hdd_err("put fail"); + goto fail; + } + if (hdd_add_ap_standard_info(skb, hdd_sta_ctx, + AP_INFO_STANDARD_NL80211_ATTR)) { + hdd_err("put fail"); + goto fail; + } + if (nla_put_u32(skb, INFO_ROAM_COUNT, + hdd_sta_ctx->conn_info.roam_count) || + nla_put_u32(skb, INFO_AKM, + hdd_convert_auth_type( + hdd_sta_ctx->conn_info.authType)) || + nla_put_u32(skb, WLAN802_11_MODE, + hdd_convert_dot11mode( + hdd_sta_ctx->conn_info.dot11Mode))) { + hdd_err("put fail"); + goto fail; + } + if (hdd_sta_ctx->conn_info.conn_flag.ht_op_present) + if (nla_put(skb, HT_OPERATION, + (sizeof(hdd_sta_ctx->conn_info.ht_operation)), + &hdd_sta_ctx->conn_info.ht_operation)) { + hdd_err("put fail"); + goto fail; + } + if (hdd_sta_ctx->conn_info.conn_flag.vht_op_present) + if (nla_put(skb, VHT_OPERATION, + (sizeof(hdd_sta_ctx->conn_info.vht_operation)), + &hdd_sta_ctx->conn_info.vht_operation)) { + hdd_err("put fail"); + goto fail; + } + if (hdd_sta_ctx->conn_info.conn_flag.hs20_present) + if (nla_put(skb, AP_INFO_HS20_INDICATION, + (sizeof(hdd_sta_ctx->conn_info.hs20vendor_ie) - 1), + tmp_hs20 + 1)) { + hdd_err("put fail"); + goto fail; + } + + return cfg80211_vendor_cmd_reply(skb); +fail: + if (skb) + kfree_skb(skb); + return -EINVAL; +} + +/** + * __hdd_cfg80211_get_station_cmd() - Handle get station vendor cmd + * @wiphy: corestack handler + * @wdev: wireless device + * @data: data + * @data_len: data length + * + * Handles QCA_NL80211_VENDOR_SUBCMD_GET_STATION. + * Validate cmd attributes and send the station info to upper layers. + * + * Return: Success(0) or reason code for failure + */ +static int +__hdd_cfg80211_get_station_cmd(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + hdd_context_t *hdd_ctx = wiphy_priv(wiphy); + struct net_device *dev = wdev->netdev; + hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_GET_STATION_MAX + 1]; + int32_t status; + + ENTER_DEV(dev); + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_warn("Command not allowed in FTM mode"); + status = -EPERM; + goto out; + } + + status = wlan_hdd_validate_context(hdd_ctx); + if (0 != status) + goto out; + + + status = nla_parse(tb, QCA_WLAN_VENDOR_ATTR_GET_STATION_MAX, + data, data_len, NULL); + if (status) { + hdd_err("Invalid ATTR"); + goto out; + } + + /* Parse and fetch Command Type*/ + if (tb[STATION_INFO]) { + status = hdd_get_station_info(hdd_ctx, adapter); + } else if (tb[STATION_ASSOC_FAIL_REASON]) { + status = hdd_get_station_assoc_fail(hdd_ctx, adapter); + } else { + hdd_err("get station info cmd type failed"); + status = -EINVAL; + goto out; + } + EXIT(); +out: + return status; +} + +/** + * wlan_hdd_cfg80211_get_station_cmd() - Handle get station vendor cmd + * @wiphy: corestack handler + * @wdev: wireless device + * @data: data + * @data_len: data length + * + * Handles QCA_NL80211_VENDOR_SUBCMD_GET_STATION. + * Validate cmd attributes and send the station info to upper layers. + * + * Return: Success(0) or reason code for failure + */ +static int32_t +hdd_cfg80211_get_station_cmd(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __hdd_cfg80211_get_station_cmd(wiphy, wdev, data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +/* + * undef short names defined for get station command + * used by __wlan_hdd_cfg80211_get_station_cmd() + */ +#undef STATION_INVALID +#undef STATION_INFO +#undef STATION_ASSOC_FAIL_REASON +#undef STATION_MAX + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +/** + * __wlan_hdd_cfg80211_keymgmt_set_key() - Store the Keys in the driver session + * @wiphy: pointer to wireless wiphy structure. + * @wdev: pointer to wireless_dev structure. + * @data: Pointer to the Key data + * @data_len:Length of the data passed + * + * This is called when wlan driver needs to save the keys received via + * vendor specific command. + * + * Return: Return the Success or Failure code. + */ +static int __wlan_hdd_cfg80211_keymgmt_set_key(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + uint8_t local_pmk[SIR_ROAM_SCAN_PSK_SIZE]; + struct net_device *dev = wdev->netdev; + hdd_adapter_t *hdd_adapter_ptr = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *hdd_ctx_ptr; + int status; + struct pmkid_mode_bits pmkid_modes; + + ENTER_DEV(dev); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_warn("Command not allowed in FTM mode"); + return -EPERM; + } + + if ((data == NULL) || (data_len == 0) || + (data_len > SIR_ROAM_SCAN_PSK_SIZE)) { + hdd_err("Invalid data"); + return -EINVAL; + } + + hdd_ctx_ptr = WLAN_HDD_GET_CTX(hdd_adapter_ptr); + if (!hdd_ctx_ptr) { + hdd_err("HDD context is null"); + return -EINVAL; + } + + status = wlan_hdd_validate_context(hdd_ctx_ptr); + if (status) + return status; + + hdd_get_pmkid_modes(hdd_ctx_ptr, &pmkid_modes); + + sme_update_roam_key_mgmt_offload_enabled(hdd_ctx_ptr->hHal, + hdd_adapter_ptr->sessionId, + true, + &pmkid_modes); + qdf_mem_zero(&local_pmk, SIR_ROAM_SCAN_PSK_SIZE); + qdf_mem_copy(local_pmk, data, data_len); + sme_roam_set_psk_pmk(WLAN_HDD_GET_HAL_CTX(hdd_adapter_ptr), + hdd_adapter_ptr->sessionId, local_pmk, data_len); + return 0; +} + +/** + * wlan_hdd_cfg80211_keymgmt_set_key() - Store the Keys in the driver session + * @wiphy: pointer to wireless wiphy structure. + * @wdev: pointer to wireless_dev structure. + * @data: Pointer to the Key data + * @data_len:Length of the data passed + * + * This is called when wlan driver needs to save the keys received via + * vendor specific command. + * + * Return: Return the Success or Failure code. + */ +static int wlan_hdd_cfg80211_keymgmt_set_key(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_keymgmt_set_key(wiphy, wdev, data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} +#endif + +static const struct nla_policy qca_wlan_vendor_get_wifi_info_policy[ + QCA_WLAN_VENDOR_ATTR_WIFI_INFO_GET_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_WIFI_INFO_DRIVER_VERSION] = {.type = NLA_U8 }, + [QCA_WLAN_VENDOR_ATTR_WIFI_INFO_FIRMWARE_VERSION] = {.type = NLA_U8 }, + [QCA_WLAN_VENDOR_ATTR_WIFI_INFO_RADIO_INDEX] = {.type = NLA_U32 }, +}; + +/** + * __wlan_hdd_cfg80211_get_wifi_info() - Get the wifi driver related info + * @wiphy: pointer to wireless wiphy structure. + * @wdev: pointer to wireless_dev structure. + * @data: Pointer to the data to be passed via vendor interface + * @data_len:Length of the data to be passed + * + * This is called when wlan driver needs to send wifi driver related info + * (driver/fw version) to the user space application upon request. + * + * Return: Return the Success or Failure code. + */ +static int +__wlan_hdd_cfg80211_get_wifi_info(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + hdd_context_t *hdd_ctx = wiphy_priv(wiphy); + struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_WIFI_INFO_GET_MAX + 1]; + tSirVersionString driver_version; + tSirVersionString firmware_version; + uint32_t major_spid = 0, minor_spid = 0, siid = 0, crmid = 0; + int status; + struct sk_buff *reply_skb; + uint32_t skb_len = 0, count = 0; + + ENTER_DEV(wdev->netdev); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_warn("Command not allowed in FTM mode"); + return -EPERM; + } + + status = wlan_hdd_validate_context(hdd_ctx); + if (status) + return status; + + if (nla_parse(tb_vendor, QCA_WLAN_VENDOR_ATTR_WIFI_INFO_GET_MAX, data, + data_len, qca_wlan_vendor_get_wifi_info_policy)) { + hdd_err("WIFI_INFO_GET NL CMD parsing failed"); + return -EINVAL; + } + + if (tb_vendor[QCA_WLAN_VENDOR_ATTR_WIFI_INFO_DRIVER_VERSION]) { + hdd_err("Rcvd req for Driver version"); + strlcpy(driver_version, QWLAN_VERSIONSTR, + sizeof(driver_version)); + skb_len += strlen(driver_version) + 1; + count++; + } + + if (tb_vendor[QCA_WLAN_VENDOR_ATTR_WIFI_INFO_FIRMWARE_VERSION]) { + hdd_info("Rcvd req for FW version"); + hdd_get_fw_version(hdd_ctx, &major_spid, &minor_spid, &siid, + &crmid); + snprintf(firmware_version, sizeof(firmware_version), + "%d:%d:%d:%d", major_spid, minor_spid, siid, crmid); + skb_len += strlen(firmware_version) + 1; + count++; + } + + if (count == 0) { + hdd_err("unknown attribute in get_wifi_info request"); + return -EINVAL; + } + + skb_len += (NLA_HDRLEN * count) + NLMSG_HDRLEN; + reply_skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, skb_len); + + if (!reply_skb) { + hdd_err("cfg80211_vendor_cmd_alloc_reply_skb failed"); + return -ENOMEM; + } + + if (tb_vendor[QCA_WLAN_VENDOR_ATTR_WIFI_INFO_DRIVER_VERSION]) { + if (nla_put_string(reply_skb, + QCA_WLAN_VENDOR_ATTR_WIFI_INFO_DRIVER_VERSION, + driver_version)) + goto error_nla_fail; + } + + if (tb_vendor[QCA_WLAN_VENDOR_ATTR_WIFI_INFO_FIRMWARE_VERSION]) { + if (nla_put_string(reply_skb, + QCA_WLAN_VENDOR_ATTR_WIFI_INFO_FIRMWARE_VERSION, + firmware_version)) + goto error_nla_fail; + } + + if (tb_vendor[QCA_WLAN_VENDOR_ATTR_WIFI_INFO_RADIO_INDEX]) { + if (nla_put_u32(reply_skb, + QCA_WLAN_VENDOR_ATTR_WIFI_INFO_RADIO_INDEX, + hdd_ctx->radio_index)) + goto error_nla_fail; + } + + return cfg80211_vendor_cmd_reply(reply_skb); + +error_nla_fail: + hdd_err("nla put fail"); + kfree_skb(reply_skb); + return -EINVAL; +} + +/** + * wlan_hdd_cfg80211_get_wifi_info() - Get the wifi driver related info + * @wiphy: pointer to wireless wiphy structure. + * @wdev: pointer to wireless_dev structure. + * @data: Pointer to the data to be passed via vendor interface + * @data_len:Length of the data to be passed + * + * This is called when wlan driver needs to send wifi driver related info + * (driver/fw version) to the user space application upon request. + * + * Return: Return the Success or Failure code. + */ +static int +wlan_hdd_cfg80211_get_wifi_info(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_get_wifi_info(wiphy, wdev, data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __wlan_hdd_cfg80211_get_logger_supp_feature() - Get the wifi logger features + * @wiphy: pointer to wireless wiphy structure. + * @wdev: pointer to wireless_dev structure. + * @data: Pointer to the data to be passed via vendor interface + * @data_len:Length of the data to be passed + * + * This is called by userspace to know the supported logger features + * + * Return: Return the Success or Failure code. + */ +static int +__wlan_hdd_cfg80211_get_logger_supp_feature(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + hdd_context_t *hdd_ctx = wiphy_priv(wiphy); + int status; + uint32_t features; + struct sk_buff *reply_skb = NULL; + + ENTER_DEV(wdev->netdev); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_warn("Command not allowed in FTM mode"); + return -EPERM; + } + + status = wlan_hdd_validate_context(hdd_ctx); + if (status) + return status; + + features = 0; + + if (hdd_is_memdump_supported()) + features |= WIFI_LOGGER_MEMORY_DUMP_SUPPORTED; + features |= WIFI_LOGGER_PER_PACKET_TX_RX_STATUS_SUPPORTED; + features |= WIFI_LOGGER_CONNECT_EVENT_SUPPORTED; + features |= WIFI_LOGGER_WAKE_LOCK_SUPPORTED; + + reply_skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, + sizeof(uint32_t) + NLA_HDRLEN + NLMSG_HDRLEN); + if (!reply_skb) { + hdd_err("cfg80211_vendor_cmd_alloc_reply_skb failed"); + return -ENOMEM; + } + + hdd_notice("Supported logger features: 0x%0x", features); + if (nla_put_u32(reply_skb, QCA_WLAN_VENDOR_ATTR_LOGGER_SUPPORTED, + features)) { + hdd_err("nla put fail"); + kfree_skb(reply_skb); + return -EINVAL; + } + + return cfg80211_vendor_cmd_reply(reply_skb); +} + +/** + * wlan_hdd_cfg80211_get_logger_supp_feature() - Get the wifi logger features + * @wiphy: pointer to wireless wiphy structure. + * @wdev: pointer to wireless_dev structure. + * @data: Pointer to the data to be passed via vendor interface + * @data_len:Length of the data to be passed + * + * This is called by userspace to know the supported logger features + * + * Return: Return the Success or Failure code. + */ +static int +wlan_hdd_cfg80211_get_logger_supp_feature(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_get_logger_supp_feature(wiphy, wdev, + data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * wlan_hdd_save_gtk_offload_params() - Save gtk offload parameters in STA + * context for offload operations. + * @adapter: Adapter context + * @kck_ptr: KCK buffer pointer + * @kek_ptr: KEK buffer pointer + * @replay_ctr: Pointer to 64 bit long replay counter + * @big_endian: true if replay_ctr is in big endian format + * @ul_flags: Offload flags + * + * Return: None + */ +#ifdef WLAN_FEATURE_GTK_OFFLOAD +static void wlan_hdd_save_gtk_offload_params(hdd_adapter_t *adapter, + uint8_t *kck_ptr, + uint8_t *kek_ptr, + uint8_t *replay_ctr, + bool big_endian, + uint32_t ul_flags) +{ + hdd_station_ctx_t *hdd_sta_ctx; + uint8_t *p; + int i; + + hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + memcpy(hdd_sta_ctx->gtkOffloadReqParams.aKCK, kck_ptr, + NL80211_KCK_LEN); + memcpy(hdd_sta_ctx->gtkOffloadReqParams.aKEK, kek_ptr, + NL80211_KEK_LEN); + qdf_copy_macaddr(&hdd_sta_ctx->gtkOffloadReqParams.bssid, + &hdd_sta_ctx->conn_info.bssId); + /* + * changing from big to little endian since driver + * works on little endian format + */ + p = (uint8_t *)&hdd_sta_ctx->gtkOffloadReqParams.ullKeyReplayCounter; + + for (i = 0; i < 8; i++) { + if (big_endian) + p[7 - i] = replay_ctr[i]; + else + p[i] = replay_ctr[i]; + } + hdd_sta_ctx->gtkOffloadReqParams.ulFlags = ul_flags; +} +#else +static void wlan_hdd_save_gtk_offload_params(hdd_adapter_t *adapter, + uint8_t *kck_ptr, + uint8_t *kek_ptr, + uint8_t *replay_ctr, + bool big_endian, + uint32_t ul_flags) +{ +} +#endif + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +/** + * wlan_hdd_send_roam_auth_event() - Send the roamed and authorized event + * @adapter: Pointer to adapter struct + * @bssid: pointer to bssid of roamed AP. + * @req_rsn_ie: Pointer to request RSN IE + * @req_rsn_len: Length of the request RSN IE + * @rsp_rsn_ie: Pointer to response RSN IE + * @rsp_rsn_len: Length of the response RSN IE + * @roam_info_ptr: Pointer to the roaming related information + * + * This is called when wlan driver needs to send the roaming and + * authorization information after roaming. + * + * The information that would be sent is the request RSN IE, response + * RSN IE and BSSID of the newly roamed AP. + * + * If the Authorized status is authenticated, then additional parameters + * like PTK's KCK and KEK and Replay Counter would also be passed to the + * supplicant. + * + * The supplicant upon receiving this event would ignore the legacy + * cfg80211_roamed call and use the entire information from this event. + * The cfg80211_roamed should still co-exist since the kernel will + * make use of the parameters even if the supplicant ignores it. + * + * Return: Return the Success or Failure code. + */ +int wlan_hdd_send_roam_auth_event(hdd_adapter_t *adapter, uint8_t *bssid, + uint8_t *req_rsn_ie, uint32_t req_rsn_len, uint8_t *rsp_rsn_ie, + uint32_t rsp_rsn_len, tCsrRoamInfo *roam_info_ptr) +{ + hdd_context_t *hdd_ctx_ptr = WLAN_HDD_GET_CTX(adapter); + struct sk_buff *skb = NULL; + eCsrAuthType auth_type; + + ENTER(); + + if (wlan_hdd_validate_context(hdd_ctx_ptr)) + return -EINVAL; + + if (!roaming_offload_enabled(hdd_ctx_ptr) || + !roam_info_ptr->roamSynchInProgress) + return 0; + + skb = cfg80211_vendor_event_alloc(hdd_ctx_ptr->wiphy, + &(adapter->wdev), + ETH_ALEN + req_rsn_len + rsp_rsn_len + + sizeof(uint8_t) + SIR_REPLAY_CTR_LEN + + SIR_KCK_KEY_LEN + SIR_KCK_KEY_LEN + + sizeof(uint8_t) + (8 * NLMSG_HDRLEN), + QCA_NL80211_VENDOR_SUBCMD_KEY_MGMT_ROAM_AUTH_INDEX, + GFP_KERNEL); + + if (!skb) { + hdd_err("cfg80211_vendor_event_alloc failed"); + return -EINVAL; + } + + if (nla_put(skb, QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_BSSID, + ETH_ALEN, bssid) || + nla_put(skb, QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_REQ_IE, + req_rsn_len, req_rsn_ie) || + nla_put(skb, QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_RESP_IE, + rsp_rsn_len, rsp_rsn_ie)) { + hdd_err("nla put fail"); + goto nla_put_failure; + } + hdd_debug("Auth Status = %d", roam_info_ptr->synchAuthStatus); + if (roam_info_ptr->synchAuthStatus == + CSR_ROAM_AUTH_STATUS_AUTHENTICATED) { + hdd_debug("Include Auth Params TLV's"); + if (nla_put_u8(skb, + QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_AUTHORIZED, true)) { + hdd_err("nla put fail"); + goto nla_put_failure; + } + auth_type = roam_info_ptr->u.pConnectedProfile->AuthType; + /* if FT or CCKM connection: dont send replay counter */ + if (auth_type != eCSR_AUTH_TYPE_FT_RSN && + auth_type != eCSR_AUTH_TYPE_FT_RSN_PSK && + auth_type != eCSR_AUTH_TYPE_CCKM_WPA && + auth_type != eCSR_AUTH_TYPE_CCKM_RSN && + nla_put(skb, + QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_KEY_REPLAY_CTR, + SIR_REPLAY_CTR_LEN, + roam_info_ptr->replay_ctr)) { + hdd_err("non FT/non CCKM connection."); + hdd_err("failed to send replay counter."); + goto nla_put_failure; + } + if (nla_put(skb, + QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_PTK_KCK, + SIR_KCK_KEY_LEN, roam_info_ptr->kck) || + nla_put(skb, + QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_PTK_KEK, + SIR_KEK_KEY_LEN, roam_info_ptr->kek)) { + hdd_err("nla put fail"); + goto nla_put_failure; + } + + /* + * Save the gtk rekey parameters in HDD STA context. They will + * be used next time when host enables GTK offload and goes + * into power save state. + */ + wlan_hdd_save_gtk_offload_params(adapter, roam_info_ptr->kck, + roam_info_ptr->kek, + roam_info_ptr->replay_ctr, + true, + GTK_OFFLOAD_DISABLE); + hdd_info("roam_info_ptr->replay_ctr 0x%llx", + *((uint64_t *)roam_info_ptr->replay_ctr)); + + } else { + hdd_debug("No Auth Params TLV's"); + if (nla_put_u8(skb, QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_AUTHORIZED, + false)) { + hdd_err("nla put fail"); + goto nla_put_failure; + } + } + + hdd_debug("Subnet Change Status = %d", + roam_info_ptr->subnet_change_status); + + /* + * Add subnet change status if subnet has changed + * 0 = unchanged + * 1 = changed + * 2 = unknown + */ + if (roam_info_ptr->subnet_change_status) { + if (nla_put_u8(skb, + QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_SUBNET_STATUS, + roam_info_ptr->subnet_change_status)) { + hdd_err("nla put fail"); + goto nla_put_failure; + } + } + + cfg80211_vendor_event(skb, GFP_KERNEL); + return 0; + +nla_put_failure: + kfree_skb(skb); + return -EINVAL; +} +#endif + +static const struct nla_policy +wlan_hdd_wifi_config_policy[QCA_WLAN_VENDOR_ATTR_CONFIG_MAX + 1] = { + + [QCA_WLAN_VENDOR_ATTR_CONFIG_MODULATED_DTIM] = {.type = NLA_U32 }, + [QCA_WLAN_VENDOR_ATTR_CONFIG_STATS_AVG_FACTOR] = {.type = NLA_U16 }, + [QCA_WLAN_VENDOR_ATTR_CONFIG_GUARD_TIME] = {.type = NLA_U32 }, + [QCA_WLAN_VENDOR_ATTR_CONFIG_FINE_TIME_MEASUREMENT] = {.type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_CONFIG_CHANNEL_AVOIDANCE_IND] = {.type = NLA_U8 }, + [QCA_WLAN_VENDOR_ATTR_CONFIG_TX_MPDU_AGGREGATION] = {.type = NLA_U8 }, + [QCA_WLAN_VENDOR_ATTR_CONFIG_RX_MPDU_AGGREGATION] = {.type = NLA_U8 }, + [QCA_WLAN_VENDOR_ATTR_CONFIG_NON_AGG_RETRY] = {.type = NLA_U8 }, + [QCA_WLAN_VENDOR_ATTR_CONFIG_AGG_RETRY] = {.type = NLA_U8 }, + [QCA_WLAN_VENDOR_ATTR_CONFIG_MGMT_RETRY] = {.type = NLA_U8 }, + [QCA_WLAN_VENDOR_ATTR_CONFIG_CTRL_RETRY] = {.type = NLA_U8 }, + [QCA_WLAN_VENDOR_ATTR_CONFIG_PROPAGATION_DELAY] = {.type = NLA_U8 }, + [QCA_WLAN_VENDOR_ATTR_CONFIG_TX_FAIL_COUNT] = {.type = NLA_U32 }, + [QCA_WLAN_VENDOR_ATTR_CONFIG_LRO] = {.type = NLA_U8 }, +}; + +/** + * wlan_hdd_save_default_scan_ies() - API to store the default scan IEs + * + * @adapter: Pointer to HDD adapter + * @ie_data: Pointer to Scan IEs buffer + * @ie_len: Length of Scan IEs + * + * Return: 0 on success; error number otherwise + */ +static int wlan_hdd_save_default_scan_ies(hdd_adapter_t *adapter, + uint8_t *ie_data, uint8_t ie_len) +{ + hdd_scaninfo_t *scan_info = NULL; + scan_info = &adapter->scan_info; + + if (scan_info->default_scan_ies) { + qdf_mem_free(scan_info->default_scan_ies); + scan_info->default_scan_ies = NULL; + } + + scan_info->default_scan_ies = qdf_mem_malloc(ie_len); + if (!scan_info->default_scan_ies) + return -ENOMEM; + + memcpy(scan_info->default_scan_ies, ie_data, ie_len); + scan_info->default_scan_ies_len = ie_len; + return 0; +} + +/** + * __wlan_hdd_cfg80211_wifi_configuration_set() - Wifi configuration + * vendor command + * + * @wiphy: wiphy device pointer + * @wdev: wireless device pointer + * @data: Vendor command data buffer + * @data_len: Buffer length + * + * Handles QCA_WLAN_VENDOR_ATTR_CONFIG_MAX. + * + * Return: Error code. + */ +static int +__wlan_hdd_cfg80211_wifi_configuration_set(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + struct net_device *dev = wdev->netdev; + hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *hdd_ctx = wiphy_priv(wiphy); + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_CONFIG_MAX + 1]; + int ret_val = 0; + u32 modulated_dtim; + u16 stats_avg_factor; + u32 guard_time; + uint8_t set_value; + u32 ftm_capab; + u8 qpower; + QDF_STATUS status; + int attr_len; + int access_policy = 0; + char vendor_ie[SIR_MAC_MAX_IE_LENGTH + 2]; + bool vendor_ie_present = false, access_policy_present = false; + uint16_t scan_ie_len = 0; + uint8_t *scan_ie; + struct sir_set_tx_rx_aggregation_size request; + QDF_STATUS qdf_status; + uint8_t retry, delay, enable_flag; + int param_id; + uint32_t tx_fail_count; + + ENTER_DEV(dev); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_warn("Command not allowed in FTM mode"); + return -EPERM; + } + + ret_val = wlan_hdd_validate_context(hdd_ctx); + if (ret_val) + return ret_val; + + if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_CONFIG_MAX, + data, data_len, + wlan_hdd_wifi_config_policy)) { + hdd_err("invalid attr"); + return -EINVAL; + } + + if (tb[QCA_WLAN_VENDOR_ATTR_CONFIG_FINE_TIME_MEASUREMENT]) { + ftm_capab = nla_get_u32(tb[ + QCA_WLAN_VENDOR_ATTR_CONFIG_FINE_TIME_MEASUREMENT]); + hdd_ctx->config->fine_time_meas_cap = + hdd_ctx->fine_time_meas_cap_target & ftm_capab; + sme_update_fine_time_measurement_capab(hdd_ctx->hHal, + adapter->sessionId, + hdd_ctx->config->fine_time_meas_cap); + hdd_info("FTM capability: user value: 0x%x, target value: 0x%x, final value: 0x%x", + ftm_capab, hdd_ctx->fine_time_meas_cap_target, + hdd_ctx->config->fine_time_meas_cap); + } + + if (tb[QCA_WLAN_VENDOR_ATTR_CONFIG_MODULATED_DTIM]) { + modulated_dtim = nla_get_u32( + tb[QCA_WLAN_VENDOR_ATTR_CONFIG_MODULATED_DTIM]); + + status = sme_configure_modulated_dtim(hdd_ctx->hHal, + adapter->sessionId, + modulated_dtim); + + if (QDF_STATUS_SUCCESS != status) + ret_val = -EPERM; + } + + if (tb[QCA_WLAN_VENDOR_ATTR_CONFIG_LRO]) { + enable_flag = nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_CONFIG_LRO]); + ret_val = hdd_lro_set_reset(hdd_ctx, adapter, + enable_flag); + } + + if (tb[QCA_WLAN_VENDOR_ATTR_CONFIG_QPOWER]) { + qpower = nla_get_u8( + tb[QCA_WLAN_VENDOR_ATTR_CONFIG_QPOWER]); + if (hdd_set_qpower_config(hdd_ctx, adapter, qpower) != 0) + ret_val = -EINVAL; + } + + if (tb[QCA_WLAN_VENDOR_ATTR_CONFIG_STATS_AVG_FACTOR]) { + stats_avg_factor = nla_get_u16( + tb[QCA_WLAN_VENDOR_ATTR_CONFIG_STATS_AVG_FACTOR]); + status = sme_configure_stats_avg_factor(hdd_ctx->hHal, + adapter->sessionId, + stats_avg_factor); + + if (QDF_STATUS_SUCCESS != status) + ret_val = -EPERM; + } + + + if (tb[QCA_WLAN_VENDOR_ATTR_CONFIG_GUARD_TIME]) { + guard_time = nla_get_u32( + tb[QCA_WLAN_VENDOR_ATTR_CONFIG_GUARD_TIME]); + status = sme_configure_guard_time(hdd_ctx->hHal, + adapter->sessionId, + guard_time); + + if (QDF_STATUS_SUCCESS != status) + ret_val = -EPERM; + } + + if (tb[QCA_WLAN_VENDOR_ATTR_CONFIG_ACCESS_POLICY_IE_LIST]) { + qdf_mem_zero(&vendor_ie[0], SIR_MAC_MAX_IE_LENGTH + 2); + attr_len = nla_len( + tb[QCA_WLAN_VENDOR_ATTR_CONFIG_ACCESS_POLICY_IE_LIST]); + if (attr_len < 0 || attr_len > SIR_MAC_MAX_IE_LENGTH + 2) { + hdd_info("Invalid value. attr_len %d", + attr_len); + return -EINVAL; + } + + nla_memcpy(&vendor_ie, + tb[QCA_WLAN_VENDOR_ATTR_CONFIG_ACCESS_POLICY_IE_LIST], + attr_len); + vendor_ie_present = true; + hdd_info("Access policy vendor ie present.attr_len %d", + attr_len); + qdf_trace_hex_dump(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO, + &vendor_ie[0], attr_len); + } + + if (tb[QCA_WLAN_VENDOR_ATTR_CONFIG_ACCESS_POLICY]) { + access_policy = (int) nla_get_u32( + tb[QCA_WLAN_VENDOR_ATTR_CONFIG_ACCESS_POLICY]); + if ((access_policy < QCA_ACCESS_POLICY_ACCEPT_UNLESS_LISTED) || + (access_policy > + QCA_ACCESS_POLICY_DENY_UNLESS_LISTED)) { + hdd_info("Invalid value. access_policy %d", + access_policy); + return -EINVAL; + } + access_policy_present = true; + hdd_info("Access policy present. access_policy %d", + access_policy); + } + + if (tb[QCA_WLAN_VENDOR_ATTR_CONFIG_NON_AGG_RETRY]) { + retry = nla_get_u8(tb[ + QCA_WLAN_VENDOR_ATTR_CONFIG_NON_AGG_RETRY]); + retry = retry > CFG_NON_AGG_RETRY_MAX ? + CFG_NON_AGG_RETRY_MAX : retry; + param_id = WMI_PDEV_PARAM_NON_AGG_SW_RETRY_TH; + ret_val = wma_cli_set_command(adapter->sessionId, param_id, + retry, PDEV_CMD); + } + + if (tb[QCA_WLAN_VENDOR_ATTR_CONFIG_AGG_RETRY]) { + retry = nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_CONFIG_AGG_RETRY]); + retry = retry > CFG_AGG_RETRY_MAX ? + CFG_AGG_RETRY_MAX : retry; + + /* Value less than CFG_AGG_RETRY_MIN has side effect to t-put */ + retry = ((retry > 0) && (retry < CFG_AGG_RETRY_MIN)) ? + CFG_AGG_RETRY_MIN : retry; + param_id = WMI_PDEV_PARAM_AGG_SW_RETRY_TH; + ret_val = wma_cli_set_command(adapter->sessionId, param_id, + retry, PDEV_CMD); + } + + if (tb[QCA_WLAN_VENDOR_ATTR_CONFIG_MGMT_RETRY]) { + retry = nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_CONFIG_MGMT_RETRY]); + retry = retry > CFG_MGMT_RETRY_MAX ? + CFG_MGMT_RETRY_MAX : retry; + param_id = WMI_PDEV_PARAM_MGMT_RETRY_LIMIT; + ret_val = wma_cli_set_command(adapter->sessionId, param_id, + retry, PDEV_CMD); + } + + if (tb[QCA_WLAN_VENDOR_ATTR_CONFIG_CTRL_RETRY]) { + retry = nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_CONFIG_CTRL_RETRY]); + retry = retry > CFG_CTRL_RETRY_MAX ? + CFG_CTRL_RETRY_MAX : retry; + param_id = WMI_PDEV_PARAM_CTRL_RETRY_LIMIT; + ret_val = wma_cli_set_command(adapter->sessionId, param_id, + retry, PDEV_CMD); + } + + if (tb[QCA_WLAN_VENDOR_ATTR_CONFIG_PROPAGATION_DELAY]) { + delay = nla_get_u8(tb[ + QCA_WLAN_VENDOR_ATTR_CONFIG_PROPAGATION_DELAY]); + delay = delay > CFG_PROPAGATION_DELAY_MAX ? + CFG_PROPAGATION_DELAY_MAX : delay; + param_id = WMI_PDEV_PARAM_PROPAGATION_DELAY; + ret_val = wma_cli_set_command(adapter->sessionId, param_id, + delay, PDEV_CMD); + } + + if (tb[QCA_WLAN_VENDOR_ATTR_CONFIG_TX_FAIL_COUNT]) { + tx_fail_count = nla_get_u32( + tb[QCA_WLAN_VENDOR_ATTR_CONFIG_TX_FAIL_COUNT]); + if (tx_fail_count) { + status = sme_update_tx_fail_cnt_threshold(hdd_ctx->hHal, + adapter->sessionId, tx_fail_count); + if (QDF_STATUS_SUCCESS != status) { + hdd_info("sme_update_tx_fail_cnt_threshold (err=%d)", + status); + return -EINVAL; + } + } + } + + if (vendor_ie_present && access_policy_present) { + if (access_policy == QCA_ACCESS_POLICY_DENY_UNLESS_LISTED) { + access_policy = + WLAN_HDD_VENDOR_IE_ACCESS_ALLOW_IF_LISTED; + } else { + access_policy = WLAN_HDD_VENDOR_IE_ACCESS_NONE; + } + + hdd_info("calling sme_update_access_policy_vendor_ie"); + status = sme_update_access_policy_vendor_ie(hdd_ctx->hHal, + adapter->sessionId, &vendor_ie[0], + access_policy); + if (QDF_STATUS_SUCCESS != status) { + hdd_info("Failed to set vendor ie and access policy."); + return -EINVAL; + } + } + + if (tb[QCA_WLAN_VENDOR_ATTR_CONFIG_CHANNEL_AVOIDANCE_IND]) { + set_value = nla_get_u8( + tb[QCA_WLAN_VENDOR_ATTR_CONFIG_CHANNEL_AVOIDANCE_IND]); + hdd_info("set_value: %d", set_value); + ret_val = hdd_enable_disable_ca_event(hdd_ctx, set_value); + } + + if (tb[QCA_WLAN_VENDOR_ATTR_CONFIG_SCAN_DEFAULT_IES]) { + scan_ie_len = nla_len( + tb[QCA_WLAN_VENDOR_ATTR_CONFIG_SCAN_DEFAULT_IES]); + hdd_info("Received default scan IE of len %d session %d device mode %d", + scan_ie_len, adapter->sessionId, + adapter->device_mode); + if (scan_ie_len && (scan_ie_len <= MAX_DEFAULT_SCAN_IE_LEN)) { + scan_ie = (uint8_t *) nla_data(tb + [QCA_WLAN_VENDOR_ATTR_CONFIG_SCAN_DEFAULT_IES]); + + if (wlan_hdd_save_default_scan_ies(adapter, scan_ie, + scan_ie_len)) + hdd_err("Failed to save default scan IEs"); + + if (adapter->device_mode == QDF_STA_MODE) { + status = sme_set_default_scan_ie(hdd_ctx->hHal, + adapter->sessionId, scan_ie, + scan_ie_len); + if (QDF_STATUS_SUCCESS != status) + ret_val = -EPERM; + } + } else + ret_val = -EPERM; + } + + if (tb[QCA_WLAN_VENDOR_ATTR_CONFIG_TX_MPDU_AGGREGATION] || + tb[QCA_WLAN_VENDOR_ATTR_CONFIG_RX_MPDU_AGGREGATION]) { + /* if one is specified, both must be specified */ + if (!tb[QCA_WLAN_VENDOR_ATTR_CONFIG_TX_MPDU_AGGREGATION] || + !tb[QCA_WLAN_VENDOR_ATTR_CONFIG_RX_MPDU_AGGREGATION]) { + hdd_err("Both TX and RX MPDU Aggregation required"); + return -EINVAL; + } + + request.tx_aggregation_size = nla_get_u8( + tb[QCA_WLAN_VENDOR_ATTR_CONFIG_TX_MPDU_AGGREGATION]); + request.rx_aggregation_size = nla_get_u8( + tb[QCA_WLAN_VENDOR_ATTR_CONFIG_RX_MPDU_AGGREGATION]); + request.vdev_id = adapter->sessionId; + + if (request.tx_aggregation_size >= + CFG_TX_AGGREGATION_SIZE_MIN && + request.tx_aggregation_size <= + CFG_TX_AGGREGATION_SIZE_MAX && + request.rx_aggregation_size >= + CFG_RX_AGGREGATION_SIZE_MIN && + request.rx_aggregation_size <= + CFG_RX_AGGREGATION_SIZE_MAX) { + qdf_status = wma_set_tx_rx_aggregation_size(&request); + if (qdf_status != QDF_STATUS_SUCCESS) { + hdd_err("failed to set aggr sizes err %d", + qdf_status); + ret_val = -EPERM; + } + } else { + hdd_err("TX %d RX %d MPDU aggr size not in range", + request.tx_aggregation_size, + request.rx_aggregation_size); + ret_val = -EINVAL; + } + } + + if (tb[QCA_WLAN_VENDOR_ATTR_CONFIG_IGNORE_ASSOC_DISALLOWED]) { + uint8_t ignore_assoc_disallowed; + + ignore_assoc_disallowed + = nla_get_u8(tb[ + QCA_WLAN_VENDOR_ATTR_CONFIG_IGNORE_ASSOC_DISALLOWED]); + hdd_info("Set ignore_assoc_disallowed value - %d", + ignore_assoc_disallowed); + if ((ignore_assoc_disallowed < + QCA_IGNORE_ASSOC_DISALLOWED_DISABLE) || + (ignore_assoc_disallowed > + QCA_IGNORE_ASSOC_DISALLOWED_ENABLE)) + return -EPERM; + + sme_update_session_param(hdd_ctx->hHal, + adapter->sessionId, + SIR_PARAM_IGNORE_ASSOC_DISALLOWED, + ignore_assoc_disallowed); + } + + return ret_val; +} + +/** + * wlan_hdd_cfg80211_wifi_configuration_set() - Wifi configuration + * vendor command + * + * @wiphy: wiphy device pointer + * @wdev: wireless device pointer + * @data: Vendor command data buffer + * @data_len: Buffer length + * + * Handles QCA_WLAN_VENDOR_ATTR_CONFIG_MAX. + * + * Return: EOK or other error codes. + */ +static int wlan_hdd_cfg80211_wifi_configuration_set(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_wifi_configuration_set(wiphy, wdev, + data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +static const struct +nla_policy +qca_wlan_vendor_wifi_logger_start_policy +[QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_START_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_RING_ID] + = {.type = NLA_U32 }, + [QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_VERBOSE_LEVEL] + = {.type = NLA_U32 }, + [QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_FLAGS] + = {.type = NLA_U32 }, +}; + +/** + * __wlan_hdd_cfg80211_wifi_logger_start() - This function is used to enable + * or disable the collection of packet statistics from the firmware + * @wiphy: WIPHY structure pointer + * @wdev: Wireless device structure pointer + * @data: Pointer to the data received + * @data_len: Length of the data received + * + * This function enables or disables the collection of packet statistics from + * the firmware + * + * Return: 0 on success and errno on failure + */ +static int __wlan_hdd_cfg80211_wifi_logger_start(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + QDF_STATUS status; + hdd_context_t *hdd_ctx = wiphy_priv(wiphy); + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_START_MAX + 1]; + struct sir_wifi_start_log start_log; + + ENTER_DEV(wdev->netdev); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_warn("Command not allowed in FTM mode"); + return -EPERM; + } + + status = wlan_hdd_validate_context(hdd_ctx); + if (status) + return status; + + if (hdd_ctx->driver_status == DRIVER_MODULES_CLOSED) { + hdd_err("Driver Modules are closed, can not start logger"); + return -EINVAL; + } + + if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_START_MAX, + data, data_len, + qca_wlan_vendor_wifi_logger_start_policy)) { + hdd_err("Invalid attribute"); + return -EINVAL; + } + + /* Parse and fetch ring id */ + if (!tb[QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_RING_ID]) { + hdd_err("attr ATTR failed"); + return -EINVAL; + } + start_log.ring_id = nla_get_u32( + tb[QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_RING_ID]); + hdd_info("Ring ID=%d", start_log.ring_id); + + /* Parse and fetch verbose level */ + if (!tb[QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_VERBOSE_LEVEL]) { + hdd_err("attr verbose_level failed"); + return -EINVAL; + } + start_log.verbose_level = nla_get_u32( + tb[QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_VERBOSE_LEVEL]); + hdd_info("verbose_level=%d", start_log.verbose_level); + + /* Parse and fetch flag */ + if (!tb[QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_FLAGS]) { + hdd_err("attr flag failed"); + return -EINVAL; + } + start_log.is_iwpriv_command = nla_get_u32( + tb[QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_FLAGS]); + hdd_info("is_iwpriv_command =%d", start_log.is_iwpriv_command); + + /* size is buff size which can be set using iwpriv command*/ + start_log.size = 0; + start_log.is_pktlog_buff_clear = false; + + cds_set_ring_log_level(start_log.ring_id, start_log.verbose_level); + + if (start_log.ring_id == RING_ID_WAKELOCK) { + /* Start/stop wakelock events */ + if (start_log.verbose_level > WLAN_LOG_LEVEL_OFF) + cds_set_wakelock_logging(true); + else + cds_set_wakelock_logging(false); + return 0; + } + + status = sme_wifi_start_logger(hdd_ctx->hHal, start_log); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("sme_wifi_start_logger failed(err=%d)", + status); + return -EINVAL; + } + return 0; +} + +/** + * wlan_hdd_cfg80211_wifi_logger_start() - Wrapper function used to enable + * or disable the collection of packet statistics from the firmware + * @wiphy: WIPHY structure pointer + * @wdev: Wireless device structure pointer + * @data: Pointer to the data received + * @data_len: Length of the data received + * + * This function is used to enable or disable the collection of packet + * statistics from the firmware + * + * Return: 0 on success and errno on failure + */ +static int wlan_hdd_cfg80211_wifi_logger_start(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int ret = 0; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_wifi_logger_start(wiphy, + wdev, data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +static const struct +nla_policy +qca_wlan_vendor_wifi_logger_get_ring_data_policy +[QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_GET_RING_DATA_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_GET_RING_DATA_ID] + = {.type = NLA_U32 }, +}; + +/** + * __wlan_hdd_cfg80211_wifi_logger_get_ring_data() - Flush per packet stats + * @wiphy: WIPHY structure pointer + * @wdev: Wireless device structure pointer + * @data: Pointer to the data received + * @data_len: Length of the data received + * + * This function is used to flush or retrieve the per packet statistics from + * the driver + * + * Return: 0 on success and errno on failure + */ +static int __wlan_hdd_cfg80211_wifi_logger_get_ring_data(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + QDF_STATUS status; + uint32_t ring_id; + hdd_context_t *hdd_ctx = wiphy_priv(wiphy); + struct nlattr *tb + [QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_GET_RING_DATA_MAX + 1]; + + ENTER_DEV(wdev->netdev); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_warn("Command not allowed in FTM mode"); + return -EPERM; + } + + status = wlan_hdd_validate_context(hdd_ctx); + if (status) + return status; + + if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_GET_RING_DATA_MAX, + data, data_len, + qca_wlan_vendor_wifi_logger_get_ring_data_policy)) { + hdd_err("Invalid attribute"); + return -EINVAL; + } + + /* Parse and fetch ring id */ + if (!tb[QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_GET_RING_DATA_ID]) { + hdd_err("attr ATTR failed"); + return -EINVAL; + } + + ring_id = nla_get_u32( + tb[QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_GET_RING_DATA_ID]); + + if (ring_id == RING_ID_PER_PACKET_STATS) { + wlan_logging_set_per_pkt_stats(); + hdd_notice("Flushing/Retrieving packet stats"); + } else if (ring_id == RING_ID_DRIVER_DEBUG) { + /* + * As part of DRIVER ring ID, flush both driver and fw logs. + * For other Ring ID's driver doesn't have any rings to flush + */ + hdd_notice("Bug report triggered by framework"); + + status = cds_flush_logs(WLAN_LOG_TYPE_NON_FATAL, + WLAN_LOG_INDICATOR_FRAMEWORK, + WLAN_LOG_REASON_CODE_UNUSED, + true, false); + if (QDF_STATUS_SUCCESS != status) { + hdd_err("Failed to trigger bug report"); + return -EINVAL; + } + } else { + wlan_report_log_completion(WLAN_LOG_TYPE_NON_FATAL, + WLAN_LOG_INDICATOR_FRAMEWORK, + WLAN_LOG_REASON_CODE_UNUSED, ring_id); + } + return 0; +} + +/** + * wlan_hdd_cfg80211_wifi_logger_get_ring_data() - Wrapper to flush packet stats + * @wiphy: WIPHY structure pointer + * @wdev: Wireless device structure pointer + * @data: Pointer to the data received + * @data_len: Length of the data received + * + * This function is used to flush or retrieve the per packet statistics from + * the driver + * + * Return: 0 on success and errno on failure + */ +static int wlan_hdd_cfg80211_wifi_logger_get_ring_data(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int ret = 0; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_wifi_logger_get_ring_data(wiphy, + wdev, data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +#ifdef WLAN_FEATURE_OFFLOAD_PACKETS +/** + * hdd_map_req_id_to_pattern_id() - map request id to pattern id + * @hdd_ctx: HDD context + * @request_id: [input] request id + * @pattern_id: [output] pattern id + * + * This function loops through request id to pattern id array + * if the slot is available, store the request id and return pattern id + * if entry exists, return the pattern id + * + * Return: 0 on success and errno on failure + */ +static int hdd_map_req_id_to_pattern_id(hdd_context_t *hdd_ctx, + uint32_t request_id, + uint8_t *pattern_id) +{ + uint32_t i; + + mutex_lock(&hdd_ctx->op_ctx.op_lock); + for (i = 0; i < MAXNUM_PERIODIC_TX_PTRNS; i++) { + if (hdd_ctx->op_ctx.op_table[i].request_id == MAX_REQUEST_ID) { + hdd_ctx->op_ctx.op_table[i].request_id = request_id; + *pattern_id = hdd_ctx->op_ctx.op_table[i].pattern_id; + mutex_unlock(&hdd_ctx->op_ctx.op_lock); + return 0; + } else if (hdd_ctx->op_ctx.op_table[i].request_id == + request_id) { + *pattern_id = hdd_ctx->op_ctx.op_table[i].pattern_id; + mutex_unlock(&hdd_ctx->op_ctx.op_lock); + return 0; + } + } + mutex_unlock(&hdd_ctx->op_ctx.op_lock); + return -EINVAL; +} + +/** + * hdd_unmap_req_id_to_pattern_id() - unmap request id to pattern id + * @hdd_ctx: HDD context + * @request_id: [input] request id + * @pattern_id: [output] pattern id + * + * This function loops through request id to pattern id array + * reset request id to 0 (slot available again) and + * return pattern id + * + * Return: 0 on success and errno on failure + */ +static int hdd_unmap_req_id_to_pattern_id(hdd_context_t *hdd_ctx, + uint32_t request_id, + uint8_t *pattern_id) +{ + uint32_t i; + + mutex_lock(&hdd_ctx->op_ctx.op_lock); + for (i = 0; i < MAXNUM_PERIODIC_TX_PTRNS; i++) { + if (hdd_ctx->op_ctx.op_table[i].request_id == request_id) { + hdd_ctx->op_ctx.op_table[i].request_id = MAX_REQUEST_ID; + *pattern_id = hdd_ctx->op_ctx.op_table[i].pattern_id; + mutex_unlock(&hdd_ctx->op_ctx.op_lock); + return 0; + } + } + mutex_unlock(&hdd_ctx->op_ctx.op_lock); + return -EINVAL; +} + + +/* + * define short names for the global vendor params + * used by __wlan_hdd_cfg80211_offloaded_packets() + */ +#define PARAM_MAX QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_MAX +#define PARAM_REQUEST_ID \ + QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_REQUEST_ID +#define PARAM_CONTROL \ + QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_SENDING_CONTROL +#define PARAM_IP_PACKET \ + QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_IP_PACKET_DATA +#define PARAM_SRC_MAC_ADDR \ + QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_SRC_MAC_ADDR +#define PARAM_DST_MAC_ADDR \ + QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_DST_MAC_ADDR +#define PARAM_PERIOD QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_PERIOD + +/** + * wlan_hdd_add_tx_ptrn() - add tx pattern + * @adapter: adapter pointer + * @hdd_ctx: hdd context + * @tb: nl attributes + * + * This function reads the NL attributes and forms a AddTxPtrn message + * posts it to SME. + * + */ +static int +wlan_hdd_add_tx_ptrn(hdd_adapter_t *adapter, hdd_context_t *hdd_ctx, + struct nlattr **tb) +{ + struct sSirAddPeriodicTxPtrn *add_req; + QDF_STATUS status; + uint32_t request_id, ret, len; + uint8_t pattern_id = 0; + struct qdf_mac_addr dst_addr; + uint16_t eth_type = htons(ETH_P_IP); + + if (!hdd_conn_is_connected(WLAN_HDD_GET_STATION_CTX_PTR(adapter))) { + hdd_err("Not in Connected state!"); + return -ENOTSUPP; + } + + add_req = qdf_mem_malloc(sizeof(*add_req)); + if (!add_req) { + hdd_err("memory allocation failed"); + return -ENOMEM; + } + + /* Parse and fetch request Id */ + if (!tb[PARAM_REQUEST_ID]) { + hdd_err("attr request id failed"); + goto fail; + } + + request_id = nla_get_u32(tb[PARAM_REQUEST_ID]); + if (request_id == MAX_REQUEST_ID) { + hdd_err("request_id cannot be MAX"); + return -EINVAL; + } + hdd_notice("Request Id: %u", request_id); + + if (!tb[PARAM_PERIOD]) { + hdd_err("attr period failed"); + goto fail; + } + add_req->usPtrnIntervalMs = nla_get_u32(tb[PARAM_PERIOD]); + hdd_notice("Period: %u ms", add_req->usPtrnIntervalMs); + if (add_req->usPtrnIntervalMs == 0) { + hdd_err("Invalid interval zero, return failure"); + goto fail; + } + + if (!tb[PARAM_SRC_MAC_ADDR]) { + hdd_err("attr source mac address failed"); + goto fail; + } + nla_memcpy(add_req->mac_address.bytes, tb[PARAM_SRC_MAC_ADDR], + QDF_MAC_ADDR_SIZE); + hdd_notice("input src mac address: "MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(add_req->mac_address.bytes)); + + if (!qdf_is_macaddr_equal(&add_req->mac_address, + &adapter->macAddressCurrent)) { + hdd_err("input src mac address and connected ap bssid are different"); + goto fail; + } + + if (!tb[PARAM_DST_MAC_ADDR]) { + hdd_err("attr dst mac address failed"); + goto fail; + } + nla_memcpy(dst_addr.bytes, tb[PARAM_DST_MAC_ADDR], QDF_MAC_ADDR_SIZE); + hdd_notice("input dst mac address: "MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(dst_addr.bytes)); + + if (!tb[PARAM_IP_PACKET]) { + hdd_err("attr ip packet failed"); + goto fail; + } + add_req->ucPtrnSize = nla_len(tb[PARAM_IP_PACKET]); + hdd_notice("IP packet len: %u", add_req->ucPtrnSize); + + if (add_req->ucPtrnSize < 0 || + add_req->ucPtrnSize > (PERIODIC_TX_PTRN_MAX_SIZE - + ETH_HLEN)) { + hdd_err("Invalid IP packet len: %d", + add_req->ucPtrnSize); + goto fail; + } + + len = 0; + qdf_mem_copy(&add_req->ucPattern[0], dst_addr.bytes, QDF_MAC_ADDR_SIZE); + len += QDF_MAC_ADDR_SIZE; + qdf_mem_copy(&add_req->ucPattern[len], add_req->mac_address.bytes, + QDF_MAC_ADDR_SIZE); + len += QDF_MAC_ADDR_SIZE; + qdf_mem_copy(&add_req->ucPattern[len], ð_type, 2); + len += 2; + + /* + * This is the IP packet, add 14 bytes Ethernet (802.3) header + * ------------------------------------------------------------ + * | 14 bytes Ethernet (802.3) header | IP header and payload | + * ------------------------------------------------------------ + */ + qdf_mem_copy(&add_req->ucPattern[len], + nla_data(tb[PARAM_IP_PACKET]), + add_req->ucPtrnSize); + add_req->ucPtrnSize += len; + + ret = hdd_map_req_id_to_pattern_id(hdd_ctx, request_id, &pattern_id); + if (ret) { + hdd_warn("req id to pattern id failed (ret=%d)", ret); + goto fail; + } + add_req->ucPtrnId = pattern_id; + hdd_notice("pattern id: %d", add_req->ucPtrnId); + + status = sme_add_periodic_tx_ptrn(hdd_ctx->hHal, add_req); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("sme_add_periodic_tx_ptrn failed (err=%d)", status); + goto fail; + } + + EXIT(); + qdf_mem_free(add_req); + return 0; + +fail: + qdf_mem_free(add_req); + return -EINVAL; +} + +/** + * wlan_hdd_del_tx_ptrn() - delete tx pattern + * @adapter: adapter pointer + * @hdd_ctx: hdd context + * @tb: nl attributes + * + * This function reads the NL attributes and forms a DelTxPtrn message + * posts it to SME. + * + */ +static int +wlan_hdd_del_tx_ptrn(hdd_adapter_t *adapter, hdd_context_t *hdd_ctx, + struct nlattr **tb) +{ + struct sSirDelPeriodicTxPtrn *del_req; + QDF_STATUS status; + uint32_t request_id, ret; + uint8_t pattern_id = 0; + + /* Parse and fetch request Id */ + if (!tb[PARAM_REQUEST_ID]) { + hdd_err("attr request id failed"); + return -EINVAL; + } + request_id = nla_get_u32(tb[PARAM_REQUEST_ID]); + if (request_id == MAX_REQUEST_ID) { + hdd_err("request_id cannot be MAX"); + return -EINVAL; + } + + ret = hdd_unmap_req_id_to_pattern_id(hdd_ctx, request_id, &pattern_id); + if (ret) { + hdd_warn("req id to pattern id failed (ret=%d)", ret); + return -EINVAL; + } + + del_req = qdf_mem_malloc(sizeof(*del_req)); + if (!del_req) { + hdd_err("memory allocation failed"); + return -ENOMEM; + } + + qdf_copy_macaddr(&del_req->mac_address, &adapter->macAddressCurrent); + hdd_info(MAC_ADDRESS_STR, MAC_ADDR_ARRAY(del_req->mac_address.bytes)); + del_req->ucPtrnId = pattern_id; + hdd_notice("Request Id: %u Pattern id: %d", + request_id, del_req->ucPtrnId); + + status = sme_del_periodic_tx_ptrn(hdd_ctx->hHal, del_req); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("sme_del_periodic_tx_ptrn failed (err=%d)", status); + goto fail; + } + + EXIT(); + qdf_mem_free(del_req); + return 0; + +fail: + qdf_mem_free(del_req); + return -EINVAL; +} + + +/** + * __wlan_hdd_cfg80211_offloaded_packets() - send offloaded packets + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Data length + * + * Return: 0 on success, negative errno on failure + */ +static int +__wlan_hdd_cfg80211_offloaded_packets(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + struct net_device *dev = wdev->netdev; + hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *hdd_ctx = wiphy_priv(wiphy); + struct nlattr *tb[PARAM_MAX + 1]; + uint8_t control; + int ret; + static const struct nla_policy policy[PARAM_MAX + 1] = { + [PARAM_REQUEST_ID] = { .type = NLA_U32 }, + [PARAM_CONTROL] = { .type = NLA_U32 }, + [PARAM_SRC_MAC_ADDR] = { .type = NLA_BINARY, + .len = QDF_MAC_ADDR_SIZE }, + [PARAM_DST_MAC_ADDR] = { .type = NLA_BINARY, + .len = QDF_MAC_ADDR_SIZE }, + [PARAM_PERIOD] = { .type = NLA_U32 }, + }; + + ENTER_DEV(dev); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_warn("Command not allowed in FTM mode"); + return -EPERM; + } + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return ret; + + if (!sme_is_feature_supported_by_fw(WLAN_PERIODIC_TX_PTRN)) { + hdd_err("Periodic Tx Pattern Offload feature is not supported in FW!"); + return -ENOTSUPP; + } + + if (nla_parse(tb, PARAM_MAX, data, data_len, policy)) { + hdd_err("Invalid ATTR"); + return -EINVAL; + } + + if (!tb[PARAM_CONTROL]) { + hdd_err("attr control failed"); + return -EINVAL; + } + control = nla_get_u32(tb[PARAM_CONTROL]); + hdd_notice("Control: %d", control); + + if (control == WLAN_START_OFFLOADED_PACKETS) + return wlan_hdd_add_tx_ptrn(adapter, hdd_ctx, tb); + else if (control == WLAN_STOP_OFFLOADED_PACKETS) + return wlan_hdd_del_tx_ptrn(adapter, hdd_ctx, tb); + else { + hdd_err("Invalid control: %d", control); + return -EINVAL; + } +} + +/* + * done with short names for the global vendor params + * used by __wlan_hdd_cfg80211_offloaded_packets() + */ +#undef PARAM_MAX +#undef PARAM_REQUEST_ID +#undef PARAM_CONTROL +#undef PARAM_IP_PACKET +#undef PARAM_SRC_MAC_ADDR +#undef PARAM_DST_MAC_ADDR +#undef PARAM_PERIOD + +/** + * wlan_hdd_cfg80211_offloaded_packets() - Wrapper to offload packets + * @wiphy: wiphy structure pointer + * @wdev: Wireless device structure pointer + * @data: Pointer to the data received + * @data_len: Length of @data + * + * Return: 0 on success; errno on failure + */ +static int wlan_hdd_cfg80211_offloaded_packets(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int ret = 0; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_offloaded_packets(wiphy, + wdev, data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} +#endif + +/* + * define short names for the global vendor params + * used by __wlan_hdd_cfg80211_monitor_rssi() + */ +#define PARAM_MAX QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_MAX +#define PARAM_REQUEST_ID QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_REQUEST_ID +#define PARAM_CONTROL QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_CONTROL +#define PARAM_MIN_RSSI QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_MIN_RSSI +#define PARAM_MAX_RSSI QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_MAX_RSSI + +/** + * __wlan_hdd_cfg80211_monitor_rssi() - monitor rssi + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Data length + * + * Return: 0 on success, negative errno on failure + */ +static int +__wlan_hdd_cfg80211_monitor_rssi(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + struct net_device *dev = wdev->netdev; + hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *hdd_ctx = wiphy_priv(wiphy); + struct nlattr *tb[PARAM_MAX + 1]; + struct rssi_monitor_req req; + QDF_STATUS status; + int ret; + uint32_t control; + static const struct nla_policy policy[PARAM_MAX + 1] = { + [PARAM_REQUEST_ID] = { .type = NLA_U32 }, + [PARAM_CONTROL] = { .type = NLA_U32 }, + [PARAM_MIN_RSSI] = { .type = NLA_S8 }, + [PARAM_MAX_RSSI] = { .type = NLA_S8 }, + }; + + ENTER_DEV(dev); + + if (wlan_hdd_validate_session_id(adapter->sessionId)) { + hdd_err("invalid session id: %d", adapter->sessionId); + return -EINVAL; + } + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return ret; + + if (!hdd_conn_is_connected(WLAN_HDD_GET_STATION_CTX_PTR(adapter))) { + hdd_err("Not in Connected state!"); + return -ENOTSUPP; + } + + if (nla_parse(tb, PARAM_MAX, data, data_len, policy)) { + hdd_err("Invalid ATTR"); + return -EINVAL; + } + + if (!tb[PARAM_REQUEST_ID]) { + hdd_err("attr request id failed"); + return -EINVAL; + } + + if (!tb[PARAM_CONTROL]) { + hdd_err("attr control failed"); + return -EINVAL; + } + + req.request_id = nla_get_u32(tb[PARAM_REQUEST_ID]); + req.session_id = adapter->sessionId; + control = nla_get_u32(tb[PARAM_CONTROL]); + + if (control == QCA_WLAN_RSSI_MONITORING_START) { + req.control = true; + if (!tb[PARAM_MIN_RSSI]) { + hdd_err("attr min rssi failed"); + return -EINVAL; + } + + if (!tb[PARAM_MAX_RSSI]) { + hdd_err("attr max rssi failed"); + return -EINVAL; + } + + req.min_rssi = nla_get_s8(tb[PARAM_MIN_RSSI]); + req.max_rssi = nla_get_s8(tb[PARAM_MAX_RSSI]); + + if (!(req.min_rssi < req.max_rssi)) { + hdd_warn("min_rssi: %d must be less than max_rssi: %d", + req.min_rssi, req.max_rssi); + return -EINVAL; + } + hdd_notice("Min_rssi: %d Max_rssi: %d", + req.min_rssi, req.max_rssi); + + } else if (control == QCA_WLAN_RSSI_MONITORING_STOP) + req.control = false; + else { + hdd_err("Invalid control cmd: %d", control); + return -EINVAL; + } + hdd_notice("Request Id: %u Session_id: %d Control: %d", + req.request_id, req.session_id, req.control); + + status = sme_set_rssi_monitoring(hdd_ctx->hHal, &req); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("sme_set_rssi_monitoring failed(err=%d)", status); + return -EINVAL; + } + + return 0; +} + +/* + * done with short names for the global vendor params + * used by __wlan_hdd_cfg80211_monitor_rssi() + */ +#undef PARAM_MAX +#undef PARAM_CONTROL +#undef PARAM_REQUEST_ID +#undef PARAM_MAX_RSSI +#undef PARAM_MIN_RSSI + +/** + * wlan_hdd_cfg80211_monitor_rssi() - SSR wrapper to rssi monitoring + * @wiphy: wiphy structure pointer + * @wdev: Wireless device structure pointer + * @data: Pointer to the data received + * @data_len: Length of @data + * + * Return: 0 on success; errno on failure + */ +static int +wlan_hdd_cfg80211_monitor_rssi(struct wiphy *wiphy, struct wireless_dev *wdev, + const void *data, int data_len) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_monitor_rssi(wiphy, wdev, data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * hdd_rssi_threshold_breached() - rssi breached NL event + * @hddctx: HDD context + * @data: rssi breached event data + * + * This function reads the rssi breached event %data and fill in the skb with + * NL attributes and send up the NL event. + * + * Return: none + */ +void hdd_rssi_threshold_breached(void *hddctx, + struct rssi_breach_event *data) +{ + hdd_context_t *hdd_ctx = hddctx; + struct sk_buff *skb; + + ENTER(); + + if (wlan_hdd_validate_context(hdd_ctx)) + return; + if (!data) { + hdd_err("data is null"); + return; + } + + skb = cfg80211_vendor_event_alloc(hdd_ctx->wiphy, + NULL, + EXTSCAN_EVENT_BUF_SIZE + NLMSG_HDRLEN, + QCA_NL80211_VENDOR_SUBCMD_MONITOR_RSSI_INDEX, + GFP_KERNEL); + + if (!skb) { + hdd_err("cfg80211_vendor_event_alloc failed"); + return; + } + + hdd_notice("Req Id: %u Current rssi: %d", + data->request_id, data->curr_rssi); + hdd_notice("Current BSSID: "MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(data->curr_bssid.bytes)); + + if (nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_REQUEST_ID, + data->request_id) || + nla_put(skb, QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_CUR_BSSID, + sizeof(data->curr_bssid), data->curr_bssid.bytes) || + nla_put_s8(skb, QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_CUR_RSSI, + data->curr_rssi)) { + hdd_err("nla put fail"); + goto fail; + } + + cfg80211_vendor_event(skb, GFP_KERNEL); + return; + +fail: + kfree_skb(skb); + return; +} + +#define PWR_SAVE_FAIL_CMD_INDEX \ + QCA_NL80211_VENDOR_SUBCMD_PWR_SAVE_FAIL_DETECTED_INDEX +/** + * hdd_chip_pwr_save_fail_detected_cb() - chip power save failure detected + * callback + * @hdd_ctx: HDD context + * @data: chip power save failure detected data + * + * This function reads the chip power save failure detected data and fill in + * the skb with NL attributes and send up the NL event. + * This callback execute in atomic context and must not invoke any + * blocking calls. + * + * Return: none + */ +void hdd_chip_pwr_save_fail_detected_cb(void *ctx, + struct chip_pwr_save_fail_detected_params + *data) +{ + hdd_context_t *hdd_ctx = ctx; + struct sk_buff *skb; + int flags = cds_get_gfp_flags(); + + ENTER(); + + if (wlan_hdd_validate_context(hdd_ctx)) + return; + + if (!data) { + hdd_notice("data is null"); + return; + } + + skb = cfg80211_vendor_event_alloc(hdd_ctx->wiphy, + NULL, NLMSG_HDRLEN + + sizeof(data->failure_reason_code) + + NLMSG_HDRLEN, PWR_SAVE_FAIL_CMD_INDEX, + flags); + + if (!skb) { + hdd_notice("cfg80211_vendor_event_alloc failed"); + return; + } + + hdd_info(FL("failure reason code: %u"), + data->failure_reason_code); + + if (nla_put_u32(skb, + QCA_ATTR_CHIP_POWER_SAVE_FAILURE_REASON, + data->failure_reason_code)) + goto fail; + + cfg80211_vendor_event(skb, flags); + EXIT(); + return; + +fail: + kfree_skb(skb); +} +#undef PWR_SAVE_FAIL_CMD_INDEX + +static const struct nla_policy +ns_offload_set_policy[QCA_WLAN_VENDOR_ATTR_ND_OFFLOAD_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_ND_OFFLOAD_FLAG] = {.type = NLA_U8}, +}; + +/** + * __wlan_hdd_cfg80211_set_ns_offload() - enable/disable NS offload + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Length of @data + * + * Return: 0 on success, negative errno on failure + */ +static int +__wlan_hdd_cfg80211_set_ns_offload(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + int status; + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_ND_OFFLOAD_MAX + 1]; + hdd_context_t *pHddCtx = wiphy_priv(wiphy); + struct net_device *dev = wdev->netdev; + hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + + ENTER_DEV(wdev->netdev); + + status = wlan_hdd_validate_context(pHddCtx); + if (0 != status) + return status; + if (!pHddCtx->config->fhostNSOffload) { + hdd_err("ND Offload not supported"); + return -EINVAL; + } + + if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_ND_OFFLOAD_MAX, + (struct nlattr *)data, + data_len, ns_offload_set_policy)) { + hdd_err("nla_parse failed"); + return -EINVAL; + } + + if (!tb[QCA_WLAN_VENDOR_ATTR_ND_OFFLOAD_FLAG]) { + hdd_err("ND Offload flag attribute not present"); + return -EINVAL; + } + + pHddCtx->ns_offload_enable = + nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_ND_OFFLOAD_FLAG]); + + /* update ns offload in case it is already enabled/disabled */ + hdd_conf_ns_offload(adapter, pHddCtx->ns_offload_enable); + + return 0; +} + +/** + * wlan_hdd_cfg80211_set_ns_offload() - enable/disable NS offload + * @wiphy: pointer to wireless wiphy structure. + * @wdev: pointer to wireless_dev structure. + * @data: Pointer to the data to be passed via vendor interface + * @data_len:Length of the data to be passed + * + * Return: Return the Success or Failure code. + */ +static int wlan_hdd_cfg80211_set_ns_offload(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_set_ns_offload(wiphy, wdev, data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +static const struct nla_policy get_preferred_freq_list_policy + [QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST_IFACE_TYPE] = { + .type = NLA_U32}, +}; + +/** __wlan_hdd_cfg80211_get_preferred_freq_list() - get preferred frequency list + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Data length + * + * This function return the preferred frequency list generated by the policy + * manager. + * + * Return: success or failure code + */ +static int __wlan_hdd_cfg80211_get_preferred_freq_list(struct wiphy *wiphy, + struct wireless_dev + *wdev, const void *data, + int data_len) +{ + hdd_context_t *hdd_ctx = wiphy_priv(wiphy); + int i, ret = 0; + QDF_STATUS status; + uint8_t pcl[QDF_MAX_NUM_CHAN], weight_list[QDF_MAX_NUM_CHAN]; + uint32_t pcl_len = 0; + uint32_t freq_list[QDF_MAX_NUM_CHAN]; + enum cds_con_mode intf_mode; + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST_MAX + 1]; + struct sk_buff *reply_skb; + + ENTER_DEV(wdev->netdev); + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return -EINVAL; + + if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST_MAX, + data, data_len, get_preferred_freq_list_policy)) { + hdd_err("Invalid ATTR"); + return -EINVAL; + } + + if (!tb[QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST_IFACE_TYPE]) { + hdd_err("attr interface type failed"); + return -EINVAL; + } + + intf_mode = nla_get_u32(tb + [QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST_IFACE_TYPE]); + + if (intf_mode < CDS_STA_MODE || intf_mode >= CDS_MAX_NUM_OF_MODE) { + hdd_err("Invalid interface type"); + return -EINVAL; + } + + hdd_debug("Userspace requested pref freq list"); + + status = cds_get_pcl(intf_mode, pcl, &pcl_len, + weight_list, QDF_ARRAY_SIZE(weight_list)); + if (status != QDF_STATUS_SUCCESS) { + hdd_err("Get pcl failed"); + return -EINVAL; + } + + /* convert channel number to frequency */ + for (i = 0; i < pcl_len; i++) { + if (pcl[i] <= ARRAY_SIZE(hdd_channels_2_4_ghz)) + freq_list[i] = + ieee80211_channel_to_frequency(pcl[i], + NL80211_BAND_2GHZ); + else + freq_list[i] = + ieee80211_channel_to_frequency(pcl[i], + NL80211_BAND_5GHZ); + } + + /* send the freq_list back to supplicant */ + reply_skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, sizeof(u32) + + sizeof(u32) * + pcl_len + + NLMSG_HDRLEN); + + if (!reply_skb) { + hdd_err("Allocate reply_skb failed"); + return -EINVAL; + } + + if (nla_put_u32(reply_skb, + QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST_IFACE_TYPE, + intf_mode) || + nla_put(reply_skb, + QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST, + sizeof(uint32_t) * pcl_len, + freq_list)) { + hdd_err("nla put fail"); + kfree_skb(reply_skb); + return -EINVAL; + } + + return cfg80211_vendor_cmd_reply(reply_skb); +} + +/** wlan_hdd_cfg80211_get_preferred_freq_list () - get preferred frequency list + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Data length + * + * This function return the preferred frequency list generated by the policy + * manager. + * + * Return: success or failure code + */ +static int wlan_hdd_cfg80211_get_preferred_freq_list(struct wiphy *wiphy, + struct wireless_dev + *wdev, const void *data, + int data_len) +{ + int ret = 0; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_get_preferred_freq_list(wiphy, wdev, + data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +static const struct nla_policy set_probable_oper_channel_policy + [QCA_WLAN_VENDOR_ATTR_PROBABLE_OPER_CHANNEL_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_PROBABLE_OPER_CHANNEL_IFACE_TYPE] = { + .type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_PROBABLE_OPER_CHANNEL_FREQ] = { + .type = NLA_U32}, +}; + +/** + * __wlan_hdd_cfg80211_set_probable_oper_channel () - set probable channel + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Data length + * + * Return: 0 on success, negative errno on failure + */ +static int __wlan_hdd_cfg80211_set_probable_oper_channel(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + struct net_device *ndev = wdev->netdev; + hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(ndev); + hdd_context_t *hdd_ctx = wiphy_priv(wiphy); + int ret = 0; + enum cds_con_mode intf_mode; + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_PROBABLE_OPER_CHANNEL_MAX + 1]; + uint32_t channel_hint; + + ENTER_DEV(ndev); + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return ret; + + if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_PROBABLE_OPER_CHANNEL_MAX, + data, data_len, set_probable_oper_channel_policy)) { + hdd_err("Invalid ATTR"); + return -EINVAL; + } + + if (!tb[QCA_WLAN_VENDOR_ATTR_PROBABLE_OPER_CHANNEL_IFACE_TYPE]) { + hdd_err("attr interface type failed"); + return -EINVAL; + } + + intf_mode = nla_get_u32(tb + [QCA_WLAN_VENDOR_ATTR_PROBABLE_OPER_CHANNEL_IFACE_TYPE]); + + if (intf_mode < CDS_STA_MODE || intf_mode >= CDS_MAX_NUM_OF_MODE) { + hdd_err("Invalid interface type"); + return -EINVAL; + } + + if (!tb[QCA_WLAN_VENDOR_ATTR_PROBABLE_OPER_CHANNEL_FREQ]) { + hdd_err("attr probable freq failed"); + return -EINVAL; + } + + channel_hint = cds_freq_to_chan(nla_get_u32(tb + [QCA_WLAN_VENDOR_ATTR_PROBABLE_OPER_CHANNEL_FREQ])); + + /* check pcl table */ + if (!cds_allow_concurrency(intf_mode, + channel_hint, HW_MODE_20_MHZ)) { + hdd_err("Set channel hint failed due to concurrency check"); + return -EINVAL; + } + + if (0 != wlan_hdd_check_remain_on_channel(adapter)) + hdd_warn("Remain On Channel Pending"); + + ret = qdf_reset_connection_update(); + if (!QDF_IS_STATUS_SUCCESS(ret)) + hdd_err("clearing event failed"); + + ret = cds_current_connections_update(adapter->sessionId, + channel_hint, + SIR_UPDATE_REASON_SET_OPER_CHAN); + if (QDF_STATUS_E_FAILURE == ret) { + /* return in the failure case */ + hdd_err("ERROR: connections update failed!!"); + return -EINVAL; + } + + if (QDF_STATUS_SUCCESS == ret) { + /* + * Success is the only case for which we expect hw mode + * change to take place, hence we need to wait. + * For any other return value it should be a pass + * through + */ + ret = qdf_wait_for_connection_update(); + if (!QDF_IS_STATUS_SUCCESS(ret)) { + hdd_err("ERROR: qdf wait for event failed!!"); + return -EINVAL; + } + + } + + return 0; +} + +/** + * wlan_hdd_cfg80211_set_probable_oper_channel () - set probable channel + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Data length + * + * Return: 0 on success, negative errno on failure + */ +static int wlan_hdd_cfg80211_set_probable_oper_channel(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int ret = 0; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_set_probable_oper_channel(wiphy, wdev, + data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +static const struct +nla_policy +qca_wlan_vendor_attr_policy[QCA_WLAN_VENDOR_ATTR_MAX+1] = { + [QCA_WLAN_VENDOR_ATTR_MAC_ADDR] = { + .type = NLA_BINARY, .len = QDF_MAC_ADDR_SIZE }, +}; + +/** + * __wlan_hdd_cfg80211_get_link_properties() - Get link properties + * @wiphy: WIPHY structure pointer + * @wdev: Wireless device structure pointer + * @data: Pointer to the data received + * @data_len: Length of the data received + * + * This function is used to get link properties like nss, rate flags and + * operating frequency for the active connection with the given peer. + * + * Return: 0 on success and errno on failure + */ +static int __wlan_hdd_cfg80211_get_link_properties(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + hdd_context_t *hdd_ctx = wiphy_priv(wiphy); + struct net_device *dev = wdev->netdev; + hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_station_ctx_t *hdd_sta_ctx; + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_MAX+1]; + uint8_t peer_mac[QDF_MAC_ADDR_SIZE]; + uint32_t sta_id; + struct sk_buff *reply_skb; + uint32_t rate_flags = 0; + uint8_t nss; + uint8_t final_rate_flags = 0; + uint32_t freq; + + ENTER_DEV(dev); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_warn("Command not allowed in FTM mode"); + return -EPERM; + } + + if (0 != wlan_hdd_validate_context(hdd_ctx)) + return -EINVAL; + + if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_MAX, data, data_len, + qca_wlan_vendor_attr_policy)) { + hdd_err("Invalid attribute"); + return -EINVAL; + } + + if (!tb[QCA_WLAN_VENDOR_ATTR_MAC_ADDR]) { + hdd_err("Attribute peerMac not provided for mode=%d", + adapter->device_mode); + return -EINVAL; + } + + if (nla_len(tb[QCA_WLAN_VENDOR_ATTR_MAC_ADDR]) < QDF_MAC_ADDR_SIZE) { + hdd_err("Attribute peerMac is invalid for mode=%d", + adapter->device_mode); + return -EINVAL; + } + + qdf_mem_copy(peer_mac, nla_data(tb[QCA_WLAN_VENDOR_ATTR_MAC_ADDR]), + QDF_MAC_ADDR_SIZE); + hdd_notice("peerMac="MAC_ADDRESS_STR" for device_mode:%d", + MAC_ADDR_ARRAY(peer_mac), adapter->device_mode); + + if (adapter->device_mode == QDF_STA_MODE || + adapter->device_mode == QDF_P2P_CLIENT_MODE) { + hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + if ((hdd_sta_ctx->conn_info.connState != + eConnectionState_Associated) || + qdf_mem_cmp(hdd_sta_ctx->conn_info.bssId.bytes, + peer_mac, QDF_MAC_ADDR_SIZE)) { + hdd_err("Not Associated to mac "MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(peer_mac)); + return -EINVAL; + } + + nss = hdd_sta_ctx->conn_info.nss; + freq = cds_chan_to_freq( + hdd_sta_ctx->conn_info.operationChannel); + rate_flags = hdd_sta_ctx->conn_info.rate_flags; + } else if (adapter->device_mode == QDF_P2P_GO_MODE || + adapter->device_mode == QDF_SAP_MODE) { + + for (sta_id = 0; sta_id < WLAN_MAX_STA_COUNT; sta_id++) { + if (adapter->aStaInfo[sta_id].isUsed && + !qdf_is_macaddr_broadcast( + &adapter->aStaInfo[sta_id].macAddrSTA) && + !qdf_mem_cmp( + &adapter->aStaInfo[sta_id].macAddrSTA.bytes, + peer_mac, QDF_MAC_ADDR_SIZE)) + break; + } + + if (WLAN_MAX_STA_COUNT == sta_id) { + hdd_err("No active peer with mac="MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(peer_mac)); + return -EINVAL; + } + + nss = adapter->aStaInfo[sta_id].nss; + freq = cds_chan_to_freq( + (WLAN_HDD_GET_AP_CTX_PTR(adapter))->operatingChannel); + rate_flags = adapter->aStaInfo[sta_id].rate_flags; + } else { + hdd_err("Not Associated! with mac "MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(peer_mac)); + return -EINVAL; + } + + if (!(rate_flags & eHAL_TX_RATE_LEGACY)) { + if (rate_flags & eHAL_TX_RATE_VHT80) { + final_rate_flags |= RATE_INFO_FLAGS_VHT_MCS; +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 0, 0)) && !defined(WITH_BACKPORTS) + final_rate_flags |= RATE_INFO_FLAGS_80_MHZ_WIDTH; +#endif + } else if (rate_flags & eHAL_TX_RATE_VHT40) { + final_rate_flags |= RATE_INFO_FLAGS_VHT_MCS; +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 0, 0)) && !defined(WITH_BACKPORTS) + final_rate_flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH; +#endif + } else if (rate_flags & eHAL_TX_RATE_VHT20) { + final_rate_flags |= RATE_INFO_FLAGS_VHT_MCS; + } else if (rate_flags & + (eHAL_TX_RATE_HT20 | eHAL_TX_RATE_HT40)) { + final_rate_flags |= RATE_INFO_FLAGS_MCS; +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 0, 0)) && !defined(WITH_BACKPORTS) + if (rate_flags & eHAL_TX_RATE_HT40) + final_rate_flags |= + RATE_INFO_FLAGS_40_MHZ_WIDTH; +#endif + } + + if (rate_flags & eHAL_TX_RATE_SGI) { + if (!(final_rate_flags & RATE_INFO_FLAGS_VHT_MCS)) + final_rate_flags |= RATE_INFO_FLAGS_MCS; + final_rate_flags |= RATE_INFO_FLAGS_SHORT_GI; + } + } + + reply_skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, + sizeof(u8) + sizeof(u8) + sizeof(u32) + NLMSG_HDRLEN); + + if (NULL == reply_skb) { + hdd_err("getLinkProperties: skb alloc failed"); + return -EINVAL; + } + + if (nla_put_u8(reply_skb, + QCA_WLAN_VENDOR_ATTR_LINK_PROPERTIES_NSS, + nss) || + nla_put_u8(reply_skb, + QCA_WLAN_VENDOR_ATTR_LINK_PROPERTIES_RATE_FLAGS, + final_rate_flags) || + nla_put_u32(reply_skb, + QCA_WLAN_VENDOR_ATTR_LINK_PROPERTIES_FREQ, + freq)) { + hdd_err("nla_put failed"); + kfree_skb(reply_skb); + return -EINVAL; + } + + return cfg80211_vendor_cmd_reply(reply_skb); +} + +/** + * wlan_hdd_cfg80211_get_link_properties() - Wrapper function to get link + * properties. + * @wiphy: WIPHY structure pointer + * @wdev: Wireless device structure pointer + * @data: Pointer to the data received + * @data_len: Length of the data received + * + * This function is used to get link properties like nss, rate flags and + * operating frequency for the active connection with the given peer. + * + * Return: 0 on success and errno on failure + */ +static int wlan_hdd_cfg80211_get_link_properties(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int ret = 0; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_get_link_properties(wiphy, + wdev, data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +static const struct +nla_policy +qca_wlan_vendor_ota_test_policy +[QCA_WLAN_VENDOR_ATTR_OTA_TEST_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_OTA_TEST_ENABLE] = {.type = NLA_U8 }, +}; + +/** + * __wlan_hdd_cfg80211_set_ota_test () - enable/disable OTA test + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Data length + * + * Return: 0 on success, negative errno on failure + */ +static int __wlan_hdd_cfg80211_set_ota_test(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + struct net_device *dev = wdev->netdev; + hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + tHalHandle hal = WLAN_HDD_GET_HAL_CTX(adapter); + hdd_context_t *hdd_ctx = wiphy_priv(wiphy); + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_OTA_TEST_MAX + 1]; + uint8_t ota_enable = 0; + QDF_STATUS status; + uint32_t current_roam_state; + + ENTER_DEV(dev); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_warn("Command not allowed in FTM mode"); + return -EPERM; + } + + if (0 != wlan_hdd_validate_context(hdd_ctx)) + return -EINVAL; + + if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_OTA_TEST_MAX, + data, data_len, + qca_wlan_vendor_ota_test_policy)) { + hdd_err("invalid attr"); + return -EINVAL; + } + + if (!tb[QCA_WLAN_VENDOR_ATTR_OTA_TEST_ENABLE]) { + hdd_err("attr ota test failed"); + return -EINVAL; + } + + ota_enable = nla_get_u8( + tb[QCA_WLAN_VENDOR_ATTR_OTA_TEST_ENABLE]); + + hdd_info(" OTA test enable = %d", ota_enable); + if (ota_enable != 1) { + hdd_err("Invalid value, only enable test mode is supported!"); + return -EINVAL; + } + + current_roam_state = + sme_get_current_roam_state(hal, adapter->sessionId); + status = sme_stop_roaming(hal, adapter->sessionId, + eCsrHddIssued); + if (status != QDF_STATUS_SUCCESS) { + hdd_err("Enable/Disable roaming failed"); + return -EINVAL; + } + + status = sme_ps_enable_disable(hal, adapter->sessionId, + SME_PS_DISABLE); + if (status != QDF_STATUS_SUCCESS) { + hdd_err("Enable/Disable power save failed"); + /* restore previous roaming setting */ + if (current_roam_state == eCSR_ROAMING_STATE_JOINING || + current_roam_state == eCSR_ROAMING_STATE_JOINED) + status = sme_start_roaming(hal, adapter->sessionId, + eCsrHddIssued); + else if (current_roam_state == eCSR_ROAMING_STATE_STOP || + current_roam_state == eCSR_ROAMING_STATE_IDLE) + status = sme_stop_roaming(hal, adapter->sessionId, + eCsrHddIssued); + + if (status != QDF_STATUS_SUCCESS) + hdd_err("Restoring roaming state failed"); + + return -EINVAL; + } + + + return 0; +} + +/** + * wlan_hdd_cfg80211_set_ota_test () - Enable or disable OTA test + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Data length + * + * Return: 0 on success, negative errno on failure + */ +static int wlan_hdd_cfg80211_set_ota_test(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int ret = 0; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_set_ota_test(wiphy, wdev, data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +static const struct nla_policy +txpower_scale_policy[QCA_WLAN_VENDOR_ATTR_TXPOWER_SCALE_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_TXPOWER_SCALE] = { .type = NLA_U8 }, +}; + +/** + * __wlan_hdd_cfg80211_txpower_scale () - txpower scaling + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Data length + * + * Return: 0 on success, negative errno on failure + */ +static int __wlan_hdd_cfg80211_txpower_scale(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + hdd_context_t *hdd_ctx = wiphy_priv(wiphy); + struct net_device *dev = wdev->netdev; + hdd_adapter_t *adapter; + int ret; + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_TXPOWER_SCALE_MAX + 1]; + uint8_t scale_value; + QDF_STATUS status; + + ENTER_DEV(dev); + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return ret; + + adapter = WLAN_HDD_GET_PRIV_PTR(dev); + + if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_TXPOWER_SCALE_MAX, + data, data_len, txpower_scale_policy)) { + hdd_err("Invalid ATTR"); + return -EINVAL; + } + + if (!tb[QCA_WLAN_VENDOR_ATTR_TXPOWER_SCALE]) { + hdd_err("attr tx power scale failed"); + return -EINVAL; + } + + scale_value = nla_get_u8(tb + [QCA_WLAN_VENDOR_ATTR_TXPOWER_SCALE]); + + if (scale_value > MAX_TXPOWER_SCALE) { + hdd_err("Invalid tx power scale level"); + return -EINVAL; + } + + status = wma_set_tx_power_scale(adapter->sessionId, scale_value); + + if (QDF_STATUS_SUCCESS != status) { + hdd_err("Set tx power scale failed"); + return -EINVAL; + } + + return 0; +} + +/** + * wlan_hdd_cfg80211_txpower_scale () - txpower scaling + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Data length + * + * Return: 0 on success, negative errno on failure + */ +static int wlan_hdd_cfg80211_txpower_scale(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_txpower_scale(wiphy, wdev, + data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +static const struct nla_policy txpower_scale_decr_db_policy +[QCA_WLAN_VENDOR_ATTR_TXPOWER_SCALE_DECR_DB_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_TXPOWER_SCALE_DECR_DB] = { .type = NLA_U8 }, +}; + +/** + * __wlan_hdd_cfg80211_txpower_scale_decr_db () - txpower scaling + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Data length + * + * Return: 0 on success, negative errno on failure + */ +static int __wlan_hdd_cfg80211_txpower_scale_decr_db(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + hdd_context_t *hdd_ctx = wiphy_priv(wiphy); + struct net_device *dev = wdev->netdev; + hdd_adapter_t *adapter; + int ret; + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_TXPOWER_SCALE_DECR_DB_MAX + 1]; + uint8_t scale_value; + QDF_STATUS status; + + ENTER_DEV(dev); + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return ret; + + adapter = WLAN_HDD_GET_PRIV_PTR(dev); + + if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_TXPOWER_SCALE_DECR_DB_MAX, + data, data_len, txpower_scale_decr_db_policy)) { + hdd_err("Invalid ATTR"); + return -EINVAL; + } + + if (!tb[QCA_WLAN_VENDOR_ATTR_TXPOWER_SCALE_DECR_DB]) { + hdd_err("attr tx power decrease db value failed"); + return -EINVAL; + } + + scale_value = nla_get_u8(tb + [QCA_WLAN_VENDOR_ATTR_TXPOWER_SCALE_DECR_DB]); + + status = wma_set_tx_power_scale_decr_db(adapter->sessionId, + scale_value); + + if (QDF_STATUS_SUCCESS != status) { + hdd_err("Set tx power decrease db failed"); + return -EINVAL; + } + + return 0; +} + +/** + * wlan_hdd_cfg80211_txpower_scale_decr_db () - txpower scaling + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Data length + * + * Return: 0 on success, negative errno on failure + */ +static int wlan_hdd_cfg80211_txpower_scale_decr_db(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_txpower_scale_decr_db(wiphy, wdev, + data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __wlan_hdd_cfg80211_conditional_chan_switch() - Conditional channel switch + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Data length + * + * Processes the conditional channel switch request and invokes the helper + * APIs to process the channel switch request. + * + * Return: 0 on success, negative errno on failure + */ +static int __wlan_hdd_cfg80211_conditional_chan_switch(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int ret; + hdd_context_t *hdd_ctx = wiphy_priv(wiphy); + struct net_device *dev = wdev->netdev; + hdd_adapter_t *adapter; + struct nlattr + *tb[QCA_WLAN_VENDOR_ATTR_SAP_CONDITIONAL_CHAN_SWITCH_MAX + 1]; + uint32_t freq_len, i; + uint32_t *freq; + uint8_t chans[QDF_MAX_NUM_CHAN] = {0}; + + ENTER_DEV(dev); + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return ret; + + if (!hdd_ctx->config->enableDFSMasterCap) { + hdd_err("DFS master capability is not present in the driver"); + return -EINVAL; + } + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_warn("Command not allowed in FTM mode"); + return -EPERM; + } + + adapter = WLAN_HDD_GET_PRIV_PTR(dev); + if (adapter->device_mode != QDF_SAP_MODE) { + hdd_err("Invalid device mode %d", adapter->device_mode); + return -EINVAL; + } + + if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_SAP_CONDITIONAL_CHAN_SWITCH_MAX, + data, data_len, NULL)) { + hdd_err("Invalid ATTR"); + return -EINVAL; + } + + if (!tb[QCA_WLAN_VENDOR_ATTR_SAP_CONDITIONAL_CHAN_SWITCH_FREQ_LIST]) { + hdd_err("Frequency list is missing"); + return -EINVAL; + } + + freq_len = nla_len( + tb[QCA_WLAN_VENDOR_ATTR_SAP_CONDITIONAL_CHAN_SWITCH_FREQ_LIST])/ + sizeof(uint32_t); + + if (freq_len > QDF_MAX_NUM_CHAN) { + hdd_err("insufficient space to hold channels"); + return -ENOMEM; + } + + hdd_debug("freq_len=%d", freq_len); + + freq = nla_data( + tb[QCA_WLAN_VENDOR_ATTR_SAP_CONDITIONAL_CHAN_SWITCH_FREQ_LIST]); + + + for (i = 0; i < freq_len; i++) { + if (freq[i] == 0) + chans[i] = 0; + else + chans[i] = ieee80211_frequency_to_channel(freq[i]); + + hdd_debug("freq[%d]=%d", i, freq[i]); + } + + /* + * The input frequency list from user space is designed to be a + * priority based frequency list. This is only to accommodate any + * future request. But, current requirement is only to perform CAC + * on a single channel. So, the first entry from the list is picked. + * + * If channel is zero, any channel in the available outdoor regulatory + * domain will be selected. + */ + ret = wlan_hdd_request_pre_cac(chans[0]); + if (ret) { + hdd_err("pre cac request failed with reason:%d", ret); + return ret; + } + + return 0; +} + +/* P2P listen offload device types parameters length in bytes */ +#define P2P_LO_MAX_REQ_DEV_TYPE_COUNT (10) +#define P2P_LO_WPS_DEV_TYPE_LEN (8) +#define P2P_LO_DEV_TYPE_MAX_LEN \ + (P2P_LO_MAX_REQ_DEV_TYPE_COUNT * P2P_LO_WPS_DEV_TYPE_LEN) + +static const struct nla_policy +p2p_listen_offload_policy[QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_CHANNEL] = { .type = NLA_U32 }, + [QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_PERIOD] = { .type = NLA_U32 }, + [QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_INTERVAL] = { + .type = NLA_U32 }, + [QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_COUNT] = { .type = NLA_U32 }, + [QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_DEVICE_TYPES] = { + .type = NLA_BINARY, + .len = P2P_LO_DEV_TYPE_MAX_LEN }, + [QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_VENDOR_IE] = { + .type = NLA_BINARY, + .len = MAX_GENIE_LEN }, + [QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_CTRL_FLAG] = { + .type = NLA_U32 }, + [QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_CHANNEL] = { .type = NLA_U32 }, + [QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_STOP_REASON] = { + .type = NLA_U8 }, +}; + +/** + * __wlan_hdd_cfg80211_p2p_lo_start () - start P2P Listen Offload + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Data length + * + * This function is to process the p2p listen offload start vendor + * command. It parses the input parameters and invoke WMA API to + * send the command to firmware. + * + * Return: 0 on success, negative errno on failure + */ +static int __wlan_hdd_cfg80211_p2p_lo_start(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int ret; + hdd_context_t *hdd_ctx = wiphy_priv(wiphy); + struct net_device *dev = wdev->netdev; + hdd_adapter_t *adapter; + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_MAX + 1]; + struct sir_p2p_lo_start params; + QDF_STATUS status; + + ENTER_DEV(dev); + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return ret; + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_warn("Command not allowed in FTM mode"); + return -EPERM; + } + + adapter = WLAN_HDD_GET_PRIV_PTR(dev); + if ((adapter->device_mode != QDF_P2P_DEVICE_MODE) && + (adapter->device_mode != QDF_P2P_CLIENT_MODE) && + (adapter->device_mode != QDF_P2P_GO_MODE)) { + hdd_err("Invalid device mode %d", adapter->device_mode); + return -EINVAL; + } + + if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_MAX, + data, data_len, p2p_listen_offload_policy)) { + hdd_err("Invalid ATTR"); + return -EINVAL; + } + + memset(¶ms, 0, sizeof(params)); + + if (!tb[QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_CTRL_FLAG]) + params.ctl_flags = 1; /* set to default value */ + else + params.ctl_flags = nla_get_u32(tb + [QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_CTRL_FLAG]); + + if (!tb[QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_CHANNEL] || + !tb[QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_PERIOD] || + !tb[QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_INTERVAL] || + !tb[QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_COUNT] || + !tb[QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_DEVICE_TYPES] || + !tb[QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_VENDOR_IE]) { + hdd_err("Attribute parsing failed"); + return -EINVAL; + } + + params.vdev_id = adapter->sessionId; + params.freq = nla_get_u32(tb + [QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_CHANNEL]); + if ((params.freq != 2412) && (params.freq != 2437) && + (params.freq != 2462)) { + hdd_err("Invalid listening channel: %d", params.freq); + return -EINVAL; + } + + params.period = nla_get_u32(tb + [QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_PERIOD]); + if (!((params.period > 0) && (params.period < UINT_MAX))) { + hdd_err("Invalid period: %d", params.period); + return -EINVAL; + } + + params.interval = nla_get_u32(tb + [QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_INTERVAL]); + if (!((params.interval > 0) && (params.interval < UINT_MAX))) { + hdd_err("Invalid interval: %d", params.interval); + return -EINVAL; + } + + params.count = nla_get_u32(tb + [QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_COUNT]); + if (!((params.count >= 0) && (params.count < UINT_MAX))) { + hdd_err("Invalid count: %d", params.count); + return -EINVAL; + } + + params.device_types = nla_data(tb + [QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_DEVICE_TYPES]); + if (params.device_types == NULL) { + hdd_err("Invalid device types"); + return -EINVAL; + } + + params.dev_types_len = nla_len(tb + [QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_DEVICE_TYPES]); + /* device type length has to be multiple of P2P_LO_WPS_DEV_TYPE_LEN */ + if (0 != (params.dev_types_len % P2P_LO_WPS_DEV_TYPE_LEN)) { + hdd_err("Invalid device type length: %d", params.dev_types_len); + return -EINVAL; + } + + params.probe_resp_tmplt = nla_data(tb + [QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_VENDOR_IE]); + if (params.probe_resp_tmplt == NULL) { + hdd_err("Invalid probe response template"); + return -EINVAL; + } + + /* + * IEs minimum length should be 2 bytes: 1 byte for element id + * and 1 byte for element id length. + */ + params.probe_resp_len = nla_len(tb + [QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_VENDOR_IE]); + if (params.probe_resp_len < MIN_GENIE_LEN) { + hdd_err("Invalid probe resp template length: %d", + params.probe_resp_len); + return -EINVAL; + } + + hdd_debug("P2P LO params: freq=%d, period=%d, interval=%d, count=%d", + params.freq, params.period, params.interval, params.count); + + status = wma_p2p_lo_start(¶ms); + + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("P2P LO start failed"); + return -EINVAL; + } + + return 0; +} + + +/** + * wlan_hdd_cfg80211_p2p_lo_start () - start P2P Listen Offload + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Data length + * + * This function inovkes internal __wlan_hdd_cfg80211_p2p_lo_start() + * to process p2p listen offload start vendor command. + * + * Return: 0 on success, negative errno on failure + */ +static int wlan_hdd_cfg80211_p2p_lo_start(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int ret = 0; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_p2p_lo_start(wiphy, wdev, + data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __wlan_hdd_cfg80211_p2p_lo_stop () - stop P2P Listen Offload + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Data length + * + * This function is to process the p2p listen offload stop vendor + * command. It invokes WMA API to send command to firmware. + * + * Return: 0 on success, negative errno on failure + */ +static int __wlan_hdd_cfg80211_p2p_lo_stop(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + QDF_STATUS status; + hdd_adapter_t *adapter; + struct net_device *dev = wdev->netdev; + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_warn("Command not allowed in FTM mode"); + return -EPERM; + } + + adapter = WLAN_HDD_GET_PRIV_PTR(dev); + if ((adapter->device_mode != QDF_P2P_DEVICE_MODE) && + (adapter->device_mode != QDF_P2P_CLIENT_MODE) && + (adapter->device_mode != QDF_P2P_GO_MODE)) { + hdd_err("Invalid device mode"); + return -EINVAL; + } + + status = wma_p2p_lo_stop(adapter->sessionId); + + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("P2P LO stop failed"); + return -EINVAL; + } + + return 0; +} + +/** + * wlan_hdd_cfg80211_p2p_lo_stop () - stop P2P Listen Offload + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Data length + * + * This function inovkes internal __wlan_hdd_cfg80211_p2p_lo_stop() + * to process p2p listen offload stop vendor command. + * + * Return: 0 on success, negative errno on failure + */ +static int wlan_hdd_cfg80211_p2p_lo_stop(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int ret = 0; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_p2p_lo_stop(wiphy, wdev, + data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * wlan_hdd_cfg80211_conditional_chan_switch() - SAP conditional channel switch + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Data length + * + * Inovkes internal API __wlan_hdd_cfg80211_conditional_chan_switch() + * to process the conditional channel switch request. + * + * Return: 0 on success, negative errno on failure + */ +static int wlan_hdd_cfg80211_conditional_chan_switch(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_conditional_chan_switch(wiphy, wdev, + data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +/* + * define short names for the global vendor params + * used by __wlan_hdd_cfg80211_bpf_offload() + */ +#define BPF_INVALID \ + QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_INVALID +#define BPF_SET_RESET \ + QCA_WLAN_VENDOR_ATTR_SET_RESET_PACKET_FILTER +#define BPF_VERSION \ + QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_VERSION +#define BPF_FILTER_ID \ + QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_ID +#define BPF_PACKET_SIZE \ + QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_SIZE +#define BPF_CURRENT_OFFSET \ + QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_CURRENT_OFFSET +#define BPF_PROGRAM \ + QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_PROGRAM +#define BPF_MAX \ + QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_MAX + +static const struct nla_policy +wlan_hdd_bpf_offload_policy[BPF_MAX + 1] = { + [BPF_SET_RESET] = {.type = NLA_U32}, + [BPF_VERSION] = {.type = NLA_U32}, + [BPF_FILTER_ID] = {.type = NLA_U32}, + [BPF_PACKET_SIZE] = {.type = NLA_U32}, + [BPF_CURRENT_OFFSET] = {.type = NLA_U32}, + [BPF_PROGRAM] = {.type = NLA_U8}, +}; + +/** + * hdd_get_bpf_offload_cb() - Callback function to BPF Offload + * @hdd_context: hdd_context + * @bpf_get_offload: struct for get offload + * + * This function receives the response/data from the lower layer and + * checks to see if the thread is still waiting then post the results to + * upper layer, if the request has timed out then ignore. + * + * Return: None + */ +void hdd_get_bpf_offload_cb(void *hdd_context, + struct sir_bpf_get_offload *data) +{ + hdd_context_t *hdd_ctx = hdd_context; + struct hdd_bpf_context *context; + + ENTER(); + + if (wlan_hdd_validate_context(hdd_ctx) || !data) { + hdd_err("HDD context is invalid or data(%p) is null", + data); + return; + } + + spin_lock(&hdd_context_lock); + + context = &bpf_context; + /* The caller presumably timed out so there is nothing we can do */ + if (context->magic != BPF_CONTEXT_MAGIC) { + spin_unlock(&hdd_context_lock); + return; + } + + /* context is valid so caller is still waiting */ + /* paranoia: invalidate the magic */ + context->magic = 0; + + context->capability_response = *data; + complete(&context->completion); + + spin_unlock(&hdd_context_lock); + + return; +} + +/** + * hdd_post_get_bpf_capabilities_rsp() - Callback function to BPF Offload + * @hdd_context: hdd_context + * @bpf_get_offload: struct for get offload + * + * Return: 0 on success, error number otherwise. + */ +static int hdd_post_get_bpf_capabilities_rsp(hdd_context_t *hdd_ctx, + struct sir_bpf_get_offload *bpf_get_offload) +{ + struct sk_buff *skb; + uint32_t nl_buf_len; + + ENTER(); + + nl_buf_len = NLMSG_HDRLEN; + nl_buf_len += + (sizeof(bpf_get_offload->max_bytes_for_bpf_inst) + NLA_HDRLEN) + + (sizeof(bpf_get_offload->bpf_version) + NLA_HDRLEN); + + skb = cfg80211_vendor_cmd_alloc_reply_skb(hdd_ctx->wiphy, nl_buf_len); + if (!skb) { + hdd_err("cfg80211_vendor_cmd_alloc_reply_skb failed"); + return -ENOMEM; + } + + hdd_notice("BPF Version: %u BPF max bytes: %u", + bpf_get_offload->bpf_version, + bpf_get_offload->max_bytes_for_bpf_inst); + + if (nla_put_u32(skb, BPF_PACKET_SIZE, + bpf_get_offload->max_bytes_for_bpf_inst) || + nla_put_u32(skb, BPF_VERSION, bpf_get_offload->bpf_version)) { + hdd_err("nla put failure"); + goto nla_put_failure; + } + + cfg80211_vendor_cmd_reply(skb); + EXIT(); + return 0; + +nla_put_failure: + kfree_skb(skb); + return -EINVAL; +} + +/** + * hdd_get_bpf_offload - Get BPF offload Capabilities + * @hdd_ctx: Hdd context + * + * Return: 0 on success, errno on failure + */ +static int hdd_get_bpf_offload(hdd_context_t *hdd_ctx) +{ + unsigned long rc; + static struct hdd_bpf_context *context; + QDF_STATUS status; + int ret; + + ENTER(); + + spin_lock(&hdd_context_lock); + context = &bpf_context; + context->magic = BPF_CONTEXT_MAGIC; + INIT_COMPLETION(context->completion); + spin_unlock(&hdd_context_lock); + + status = sme_get_bpf_offload_capabilities(hdd_ctx->hHal); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("Unable to retrieve BPF caps"); + return -EINVAL; + } + /* request was sent -- wait for the response */ + rc = wait_for_completion_timeout(&context->completion, + msecs_to_jiffies(WLAN_WAIT_TIME_BPF)); + if (!rc) { + hdd_err("Target response timed out"); + spin_lock(&hdd_context_lock); + context->magic = 0; + spin_unlock(&hdd_context_lock); + + return -ETIMEDOUT; + } + ret = hdd_post_get_bpf_capabilities_rsp(hdd_ctx, + &bpf_context.capability_response); + if (ret) + hdd_err("Failed to post get bpf capabilities"); + + EXIT(); + return ret; +} + +/** + * hdd_set_reset_bpf_offload - Post set/reset bpf to SME + * @hdd_ctx: Hdd context + * @tb: Length of @data + * @adapter: pointer to adapter struct + * + * Return: 0 on success; errno on failure + */ +static int hdd_set_reset_bpf_offload(hdd_context_t *hdd_ctx, + struct nlattr **tb, + hdd_adapter_t *adapter) +{ + struct sir_bpf_set_offload *bpf_set_offload; + QDF_STATUS status; + int prog_len; + int ret = 0; + + ENTER(); + + if (adapter->device_mode == QDF_STA_MODE || + adapter->device_mode == QDF_P2P_CLIENT_MODE) { + if (!hdd_conn_is_connected( + WLAN_HDD_GET_STATION_CTX_PTR(adapter))) { + hdd_err("Not in Connected state!"); + return -ENOTSUPP; + } + } + + bpf_set_offload = qdf_mem_malloc(sizeof(*bpf_set_offload)); + if (bpf_set_offload == NULL) { + hdd_err("qdf_mem_malloc failed for bpf_set_offload"); + return -ENOMEM; + } + + /* Parse and fetch bpf packet size */ + if (!tb[BPF_PACKET_SIZE]) { + hdd_err("attr bpf packet size failed"); + ret = -EINVAL; + goto fail; + } + bpf_set_offload->total_length = nla_get_u32(tb[BPF_PACKET_SIZE]); + + if (!bpf_set_offload->total_length) { + hdd_notice("BPF reset packet filter received"); + goto post_sme; + } + + /* Parse and fetch bpf program */ + if (!tb[BPF_PROGRAM]) { + hdd_err("attr bpf program failed"); + ret = -EINVAL; + goto fail; + } + + prog_len = nla_len(tb[BPF_PROGRAM]); + bpf_set_offload->program = qdf_mem_malloc(sizeof(uint8_t) * prog_len); + + if (bpf_set_offload->program == NULL) { + hdd_err("qdf_mem_malloc failed for bpf offload program"); + ret = -ENOMEM; + goto fail; + } + + bpf_set_offload->current_length = prog_len; + nla_memcpy(bpf_set_offload->program, tb[BPF_PROGRAM], prog_len); + bpf_set_offload->session_id = adapter->sessionId; + + hdd_info("BPF set instructions"); + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO, + bpf_set_offload->program, prog_len); + + /* Parse and fetch filter Id */ + if (!tb[BPF_FILTER_ID]) { + hdd_err("attr filter id failed"); + ret = -EINVAL; + goto fail; + } + bpf_set_offload->filter_id = nla_get_u32(tb[BPF_FILTER_ID]); + + /* Parse and fetch current offset */ + if (!tb[BPF_CURRENT_OFFSET]) { + hdd_err("attr current offset failed"); + ret = -EINVAL; + goto fail; + } + bpf_set_offload->current_offset = nla_get_u32(tb[BPF_CURRENT_OFFSET]); + +post_sme: + hdd_notice("Posting BPF SET/RESET to SME, session_id: %d Bpf Version: %d filter ID: %d total_length: %d current_length: %d current offset: %d", + bpf_set_offload->session_id, + bpf_set_offload->version, + bpf_set_offload->filter_id, + bpf_set_offload->total_length, + bpf_set_offload->current_length, + bpf_set_offload->current_offset); + + status = sme_set_bpf_instructions(hdd_ctx->hHal, bpf_set_offload); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("sme_set_bpf_instructions failed(err=%d)", status); + ret = -EINVAL; + goto fail; + } + EXIT(); + +fail: + if (bpf_set_offload->current_length) + qdf_mem_free(bpf_set_offload->program); + qdf_mem_free(bpf_set_offload); + return ret; +} + +/** + * wlan_hdd_cfg80211_bpf_offload() - Set/Reset to BPF Offload + * @wiphy: wiphy structure pointer + * @wdev: Wireless device structure pointer + * @data: Pointer to the data received + * @data_len: Length of @data + * + * Return: 0 on success; errno on failure + */ +static int +__wlan_hdd_cfg80211_bpf_offload(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + hdd_context_t *hdd_ctx = wiphy_priv(wiphy); + struct net_device *dev = wdev->netdev; + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct nlattr *tb[BPF_MAX + 1]; + int ret_val, packet_filter_subcmd; + + ENTER(); + + ret_val = wlan_hdd_validate_context(hdd_ctx); + if (ret_val) + return ret_val; + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_warn("Command not allowed in FTM mode"); + return -EINVAL; + } + + if (!hdd_ctx->bpf_enabled) { + hdd_err("BPF offload is not supported/enabled"); + return -ENOTSUPP; + } + + if (nla_parse(tb, BPF_MAX, data, data_len, + wlan_hdd_bpf_offload_policy)) { + hdd_err("Invalid ATTR"); + return -EINVAL; + } + + if (!tb[BPF_SET_RESET]) { + hdd_err("attr bpf set reset failed"); + return -EINVAL; + } + + packet_filter_subcmd = nla_get_u32(tb[BPF_SET_RESET]); + + if (packet_filter_subcmd == QCA_WLAN_GET_PACKET_FILTER) + return hdd_get_bpf_offload(hdd_ctx); + else + return hdd_set_reset_bpf_offload(hdd_ctx, tb, + pAdapter); +} + +/** + * wlan_hdd_cfg80211_bpf_offload() - SSR Wrapper to BPF Offload + * @wiphy: wiphy structure pointer + * @wdev: Wireless device structure pointer + * @data: Pointer to the data received + * @data_len: Length of @data + * + * Return: 0 on success; errno on failure + */ + +static int wlan_hdd_cfg80211_bpf_offload(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_bpf_offload(wiphy, wdev, data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * wlan_hdd_set_pre_cac_status() - Set the pre cac status + * @pre_cac_adapter: AP adapter used for pre cac + * @status: Status (true or false) + * @handle: Global handle + * + * Sets the status of pre cac i.e., whether the pre cac is active or not + * + * Return: Zero on success, non-zero on failure + */ +static int wlan_hdd_set_pre_cac_status(hdd_adapter_t *pre_cac_adapter, + bool status, tHalHandle handle) +{ + QDF_STATUS ret; + + ret = wlan_sap_set_pre_cac_status( + WLAN_HDD_GET_SAP_CTX_PTR(pre_cac_adapter), status, handle); + if (QDF_IS_STATUS_ERROR(ret)) + return -EINVAL; + + return 0; +} + +/** + * wlan_hdd_set_chan_before_pre_cac() - Save the channel before pre cac + * @ap_adapter: AP adapter + * @chan_before_pre_cac: Channel + * + * Saves the channel which the AP was beaconing on before moving to the pre + * cac channel. If radar is detected on the pre cac channel, this saved + * channel will be used for AP operations. + * + * Return: Zero on success, non-zero on failure + */ +static int wlan_hdd_set_chan_before_pre_cac(hdd_adapter_t *ap_adapter, + uint8_t chan_before_pre_cac) +{ + QDF_STATUS ret; + + ret = wlan_sap_set_chan_before_pre_cac( + WLAN_HDD_GET_SAP_CTX_PTR(ap_adapter), chan_before_pre_cac); + if (QDF_IS_STATUS_ERROR(ret)) + return -EINVAL; + + return 0; +} + +/** + * wlan_hdd_sap_get_nol() - Get SAPs NOL + * @ap_adapter: AP adapter + * @nol: Non-occupancy list + * @nol_len: Length of NOL + * + * Get the NOL for SAP + * + * Return: Zero on success, non-zero on failure + */ +static int wlan_hdd_sap_get_nol(hdd_adapter_t *ap_adapter, uint8_t *nol, + uint32_t *nol_len) +{ + QDF_STATUS ret; + + ret = wlansap_get_dfs_nol(WLAN_HDD_GET_SAP_CTX_PTR(ap_adapter), + nol, nol_len); + if (QDF_IS_STATUS_ERROR(ret)) + return -EINVAL; + + return 0; +} + +/** + * wlan_hdd_validate_and_get_pre_cac_ch() - Validate and get pre cac channel + * @hdd_ctx: HDD context + * @ap_adapter: AP adapter + * @channel: Channel requested by userspace + * @pre_cac_chan: Pointer to the pre CAC channel + * + * Validates the channel provided by userspace. If user provided channel 0, + * a valid outdoor channel must be selected from the regulatory channel. + * + * Return: Zero on success and non zero value on error + */ +static int wlan_hdd_validate_and_get_pre_cac_ch(hdd_context_t *hdd_ctx, + hdd_adapter_t *ap_adapter, + uint8_t channel, + uint8_t *pre_cac_chan) +{ + uint32_t i, j; + QDF_STATUS status; + int ret; + uint8_t nol[QDF_MAX_NUM_CHAN]; + uint32_t nol_len = 0, weight_len = 0; + bool found; + uint32_t len = WNI_CFG_VALID_CHANNEL_LIST_LEN; + uint8_t channel_list[QDF_MAX_NUM_CHAN] = {0}; + uint8_t pcl_weights[QDF_MAX_NUM_CHAN] = {0}; + + if (0 == channel) { + /* Channel is not obtained from PCL because PCL may not have + * the entire channel list. For example: if SAP is up on + * channel 6 and PCL is queried for the next SAP interface, + * if SCC is preferred, the PCL will contain only the channel + * 6. But, we are in need of a DFS channel. So, going with the + * first channel from the valid channel list. + */ + status = cds_get_valid_chans(channel_list, &len); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to get channel list"); + return -EINVAL; + } + cds_update_with_safe_channel_list(channel_list, &len, + pcl_weights, weight_len); + ret = wlan_hdd_sap_get_nol(ap_adapter, nol, &nol_len); + for (i = 0; i < len; i++) { + found = false; + for (j = 0; j < nol_len; j++) { + if (channel_list[i] == nol[j]) { + found = true; + break; + } + } + if (found) + continue; + if (CDS_IS_DFS_CH(channel_list[i])) { + *pre_cac_chan = channel_list[i]; + break; + } + } + if (*pre_cac_chan == 0) { + hdd_err("unable to find outdoor channel"); + return -EINVAL; + } + } else { + /* Only when driver selects a channel, check is done for + * unnsafe and NOL channels. When user provides a fixed channel + * the user is expected to take care of this. + */ + if (!sme_is_channel_valid(hdd_ctx->hHal, channel) || + !CDS_IS_DFS_CH(channel)) { + hdd_err("Invalid channel for pre cac:%d", channel); + return -EINVAL; + } else { + *pre_cac_chan = channel; + } + } + hdd_info("selected pre cac channel:%d", *pre_cac_chan); + return 0; +} + +/** + * wlan_hdd_request_pre_cac() - Start pre CAC in the driver + * @channel: Channel option provided by userspace + * + * Sets the driver to the required hardware mode and start an adapater for + * pre CAC which will mimic an AP. + * + * Return: Zero on success, non-zero value on error + */ +int wlan_hdd_request_pre_cac(uint8_t channel) +{ + uint8_t pre_cac_chan = 0, *mac_addr; + hdd_context_t *hdd_ctx; + int ret; + hdd_adapter_t *ap_adapter, *pre_cac_adapter; + hdd_ap_ctx_t *hdd_ap_ctx; + QDF_STATUS status; + struct wiphy *wiphy; + struct net_device *dev; + struct cfg80211_chan_def chandef; + enum nl80211_channel_type channel_type; + uint32_t freq; + struct ieee80211_channel *chan; + tHalHandle handle; + bool val; + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (0 != wlan_hdd_validate_context(hdd_ctx)) + return -EINVAL; + + if (cds_get_connection_count() > 1) { + hdd_err("pre cac not allowed in concurrency"); + return -EINVAL; + } + + ap_adapter = hdd_get_adapter(hdd_ctx, QDF_SAP_MODE); + if (!ap_adapter) { + hdd_err("unable to get SAP adapter"); + return -EINVAL; + } + + handle = WLAN_HDD_GET_HAL_CTX(ap_adapter); + if (!handle) { + hdd_err("Invalid handle"); + return -EINVAL; + } + + val = wlan_sap_is_pre_cac_active(handle); + if (val) { + hdd_err("pre cac is already in progress"); + return -EINVAL; + } + + hdd_ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(ap_adapter); + if (!hdd_ap_ctx) { + hdd_err("SAP context is NULL"); + return -EINVAL; + } + + if (CDS_IS_DFS_CH(hdd_ap_ctx->operatingChannel)) { + hdd_err("SAP is already on DFS channel:%d", + hdd_ap_ctx->operatingChannel); + return -EINVAL; + } + + if (!CDS_IS_CHANNEL_24GHZ(hdd_ap_ctx->operatingChannel)) { + hdd_err("pre CAC alllowed only when SAP is in 2.4GHz:%d", + hdd_ap_ctx->operatingChannel); + return -EINVAL; + } + + mac_addr = wlan_hdd_get_intf_addr(hdd_ctx); + if (!mac_addr) { + hdd_err("can't add virtual intf: Not getting valid mac addr"); + return -EINVAL; + } + + hdd_info("channel:%d", channel); + + ret = wlan_hdd_validate_and_get_pre_cac_ch(hdd_ctx, ap_adapter, channel, + &pre_cac_chan); + if (ret != 0) { + hdd_err("can't validate pre-cac channel"); + goto release_intf_addr_and_return_failure; + } + + hdd_debug("starting pre cac SAP adapter"); + + /* Starting a SAP adapter: + * Instead of opening an adapter, we could just do a SME open session + * for AP type. But, start BSS would still need an adapter. + * So, this option is not taken. + * + * hdd open adapter is going to register this precac interface with + * user space. This interface though exposed to user space will be in + * DOWN state. Consideration was done to avoid this registration to the + * user space. But, as part of SAP operations multiple events are sent + * to user space. Some of these events received from unregistered + * interface was causing crashes. So, retaining the registration. + * + * So, this interface would remain registered and will remain in DOWN + * state for the CAC duration. We will add notes in the feature + * announcement to not use this temporary interface for any activity + * from user space. + */ + pre_cac_adapter = hdd_open_adapter(hdd_ctx, QDF_SAP_MODE, "precac%d", + mac_addr, NET_NAME_UNKNOWN, true); + if (!pre_cac_adapter) { + hdd_err("error opening the pre cac adapter"); + goto release_intf_addr_and_return_failure; + } + + /* + * This interface is internally created by the driver. So, no interface + * up comes for this interface from user space and hence starting + * the adapter internally. + */ + if (hdd_start_adapter(pre_cac_adapter)) { + hdd_err("error starting the pre cac adapter"); + goto close_pre_cac_adapter; + } + + hdd_debug("preparing for start ap/bss on the pre cac adapter"); + + wiphy = hdd_ctx->wiphy; + dev = pre_cac_adapter->dev; + + /* Since this is only a dummy interface lets us use the IEs from the + * other active SAP interface. In regular scenarios, these IEs would + * come from the user space entity + */ + pre_cac_adapter->sessionCtx.ap.beacon = qdf_mem_malloc( + sizeof(*ap_adapter->sessionCtx.ap.beacon)); + if (!pre_cac_adapter->sessionCtx.ap.beacon) { + hdd_err("failed to alloc mem for beacon"); + goto stop_close_pre_cac_adapter; + } + qdf_mem_copy(pre_cac_adapter->sessionCtx.ap.beacon, + ap_adapter->sessionCtx.ap.beacon, + sizeof(*pre_cac_adapter->sessionCtx.ap.beacon)); + pre_cac_adapter->sessionCtx.ap.sapConfig.ch_width_orig = + ap_adapter->sessionCtx.ap.sapConfig.ch_width_orig; + pre_cac_adapter->sessionCtx.ap.sapConfig.authType = + ap_adapter->sessionCtx.ap.sapConfig.authType; + + /* Premise is that on moving from 2.4GHz to 5GHz, the SAP will continue + * to operate on the same bandwidth as that of the 2.4GHz operations. + * Only bandwidths 20MHz/40MHz are possible on 2.4GHz band. + */ + switch (ap_adapter->sessionCtx.ap.sapConfig.ch_width_orig) { + case CH_WIDTH_20MHZ: + channel_type = NL80211_CHAN_HT20; + break; + case CH_WIDTH_40MHZ: + if (ap_adapter->sessionCtx.ap.sapConfig.sec_ch > + ap_adapter->sessionCtx.ap.sapConfig.channel) + channel_type = NL80211_CHAN_HT40PLUS; + else + channel_type = NL80211_CHAN_HT40MINUS; + break; + default: + channel_type = NL80211_CHAN_NO_HT; + break; + } + + freq = cds_chan_to_freq(pre_cac_chan); + chan = __ieee80211_get_channel(wiphy, freq); + if (!chan) { + hdd_err("channel converion failed"); + goto stop_close_pre_cac_adapter; + } + + cfg80211_chandef_create(&chandef, chan, channel_type); + + hdd_debug("orig width:%d channel_type:%d freq:%d", + ap_adapter->sessionCtx.ap.sapConfig.ch_width_orig, + channel_type, freq); + /* + * Doing update after opening and starting pre-cac adapter will make + * sure that driver won't do hardware mode change if there are any + * initial hick-ups or issues in pre-cac adapter's configuration. + * Since current SAP is in 2.4GHz and pre CAC channel is in 5GHz, this + * connection update should result in DBS mode + */ + status = cds_update_and_wait_for_connection_update( + ap_adapter->sessionId, + pre_cac_chan, + SIR_UPDATE_REASON_PRE_CAC); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("error in moving to DBS mode"); + goto stop_close_pre_cac_adapter; + } + + + ret = wlan_hdd_set_channel(wiphy, dev, &chandef, channel_type); + if (0 != ret) { + hdd_err("failed to set channel"); + goto stop_close_pre_cac_adapter; + } + + status = wlan_hdd_cfg80211_start_bss(pre_cac_adapter, NULL, + PRE_CAC_SSID, qdf_str_len(PRE_CAC_SSID), + eHIDDEN_SSID_NOT_IN_USE, false, false); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("start bss failed"); + goto stop_close_pre_cac_adapter; + } + + /* + * The pre cac status is set here. But, it would not be reset explicitly + * anywhere, since after the pre cac success/failure, the pre cac + * adapter itself would be removed. + */ + ret = wlan_hdd_set_pre_cac_status(pre_cac_adapter, true, handle); + if (0 != ret) { + hdd_err("failed to set pre cac status"); + goto stop_close_pre_cac_adapter; + } + + ret = wlan_hdd_set_chan_before_pre_cac(ap_adapter, + hdd_ap_ctx->operatingChannel); + if (0 != ret) { + hdd_err("failed to set channel before pre cac"); + goto stop_close_pre_cac_adapter; + } + + ap_adapter->pre_cac_chan = pre_cac_chan; + + return 0; + +stop_close_pre_cac_adapter: + hdd_stop_adapter(hdd_ctx, pre_cac_adapter, true); + qdf_mem_free(pre_cac_adapter->sessionCtx.ap.beacon); + pre_cac_adapter->sessionCtx.ap.beacon = NULL; +close_pre_cac_adapter: + hdd_close_adapter(hdd_ctx, pre_cac_adapter, false); +release_intf_addr_and_return_failure: + /* + * Release the interface address as the adapter + * failed to start, if you don't release then next + * adapter which is trying to come wouldn't get valid + * mac address. Remember we have limited pool of mac addresses + */ + wlan_hdd_release_intf_addr(hdd_ctx, mac_addr); + return -EINVAL; +} + +/** + * hdd_init_bpf_completion() - Initialize the completion event for bpf + * + * Return: None + */ +void hdd_init_bpf_completion(void) +{ + init_completion(&bpf_context.completion); +} + +static const struct nla_policy +wlan_hdd_sap_config_policy[QCA_WLAN_VENDOR_ATTR_SAP_CONFIG_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_SAP_CONFIG_CHANNEL] = {.type = NLA_U8 }, +}; + +static const struct nla_policy +wlan_hdd_set_acs_dfs_config_policy[QCA_WLAN_VENDOR_ATTR_ACS_DFS_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_ACS_DFS_MODE] = {.type = NLA_U8 }, + [QCA_WLAN_VENDOR_ATTR_ACS_CHANNEL_HINT] = {.type = NLA_U8 }, +}; + +/** + * __wlan_hdd_cfg80211_acs_dfs_mode() - set ACS DFS mode and channel + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Length of @data + * + * This function parses the incoming NL vendor command data attributes and + * updates the SAP context about channel_hint and DFS mode. + * If channel_hint is set, SAP will choose that channel + * as operating channel. + * + * If DFS mode is enabled, driver will include DFS channels + * in ACS else driver will skip DFS channels. + * + * Return: 0 on success, negative errno on failure + */ +static int +__wlan_hdd_cfg80211_acs_dfs_mode(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + hdd_context_t *hdd_ctx = wiphy_priv(wiphy); + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_ACS_DFS_MAX + 1]; + int ret; + struct acs_dfs_policy *acs_policy; + int mode = DFS_MODE_NONE; + int channel_hint = 0; + + ENTER_DEV(wdev->netdev); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_warn("Command not allowed in FTM mode"); + return -EINVAL; + } + + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_ACS_DFS_MAX, + data, data_len, + wlan_hdd_set_acs_dfs_config_policy)) { + hdd_err("invalid attr"); + return -EINVAL; + } + + acs_policy = &hdd_ctx->acs_policy; + /* + * SCM sends this attribute to restrict SAP from choosing + * DFS channels from ACS. + */ + if (tb[QCA_WLAN_VENDOR_ATTR_ACS_DFS_MODE]) + mode = nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_ACS_DFS_MODE]); + + if (!IS_DFS_MODE_VALID(mode)) { + hdd_err("attr acs dfs mode is not valid"); + return -EINVAL; + } + acs_policy->acs_dfs_mode = mode; + + /* + * SCM sends this attribute to provide an active channel, + * to skip redundant ACS between drivers, and save driver start up time + */ + if (tb[QCA_WLAN_VENDOR_ATTR_ACS_CHANNEL_HINT]) + channel_hint = nla_get_u8( + tb[QCA_WLAN_VENDOR_ATTR_ACS_CHANNEL_HINT]); + + if (!IS_CHANNEL_VALID(channel_hint)) { + hdd_err("acs channel is not valid"); + return -EINVAL; + } + acs_policy->acs_channel = channel_hint; + + return 0; +} + +/** + * wlan_hdd_cfg80211_acs_dfs_mode() - Wrapper to set ACS DFS mode + * @wiphy: wiphy structure pointer + * @wdev: Wireless device structure pointer + * @data: Pointer to the data received + * @data_len: Length of @data + * + * This function parses the incoming NL vendor command data attributes and + * updates the SAP context about channel_hint and DFS mode. + * + * Return: 0 on success; errno on failure + */ +static int wlan_hdd_cfg80211_acs_dfs_mode(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_acs_dfs_mode(wiphy, wdev, data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * wlan_hdd_get_sta_roam_dfs_mode() - get sta roam dfs mode policy + * @mode : cfg80211 dfs mode + * + * Return: return csr sta roam dfs mode else return NONE + */ +static enum sta_roam_policy_dfs_mode wlan_hdd_get_sta_roam_dfs_mode( + enum dfs_mode mode) +{ + switch (mode) { + case DFS_MODE_ENABLE: + return CSR_STA_ROAM_POLICY_DFS_ENABLED; + break; + case DFS_MODE_DISABLE: + return CSR_STA_ROAM_POLICY_DFS_DISABLED; + break; + case DFS_MODE_DEPRIORITIZE: + return CSR_STA_ROAM_POLICY_DFS_DEPRIORITIZE; + break; + default: + hdd_err("STA Roam policy dfs mode is NONE"); + return CSR_STA_ROAM_POLICY_NONE; + } +} + +/* + * hdd_get_sap_operating_band: Get current operating channel + * for sap. + * @hdd_ctx: hdd context + * + * Return : Corresponding band for SAP operating channel + */ +uint8_t hdd_get_sap_operating_band(hdd_context_t *hdd_ctx) +{ + hdd_adapter_list_node_t *adapter_node = NULL, *next = NULL; + QDF_STATUS status; + hdd_adapter_t *adapter; + uint8_t operating_channel = 0; + uint8_t sap_operating_band = 0; + status = hdd_get_front_adapter(hdd_ctx, &adapter_node); + while (NULL != adapter_node && QDF_STATUS_SUCCESS == status) { + adapter = adapter_node->pAdapter; + + if (!(adapter && (QDF_SAP_MODE == adapter->device_mode))) { + status = hdd_get_next_adapter(hdd_ctx, adapter_node, + &next); + adapter_node = next; + continue; + } + operating_channel = adapter->sessionCtx.ap.operatingChannel; + if (IS_24G_CH(operating_channel)) + sap_operating_band = eCSR_BAND_24; + else if (IS_5G_CH(operating_channel)) + sap_operating_band = eCSR_BAND_5G; + else + sap_operating_band = eCSR_BAND_ALL; + status = hdd_get_next_adapter(hdd_ctx, adapter_node, + &next); + adapter_node = next; + } + return sap_operating_band; +} + +static const struct nla_policy +wlan_hdd_set_sta_roam_config_policy[ +QCA_WLAN_VENDOR_ATTR_STA_CONNECT_ROAM_POLICY_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_STA_DFS_MODE] = {.type = NLA_U8 }, + [QCA_WLAN_VENDOR_ATTR_STA_SKIP_UNSAFE_CHANNEL] = {.type = NLA_U8 }, +}; + +/** + * __wlan_hdd_cfg80211_sta_roam_policy() - Set params to restrict scan channels + * for station connection or roaming. + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Length of @data + * + * __wlan_hdd_cfg80211_sta_roam_policy will decide if DFS channels or unsafe + * channels needs to be skipped in scanning or not. + * If dfs_mode is disabled, driver will not scan DFS channels. + * If skip_unsafe_channels is set, driver will skip unsafe channels + * in Scanning. + * + * Return: 0 on success, negative errno on failure + */ +static int +__wlan_hdd_cfg80211_sta_roam_policy(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + struct net_device *dev = wdev->netdev; + hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *hdd_ctx = wiphy_priv(wiphy); + struct nlattr *tb[ + QCA_WLAN_VENDOR_ATTR_STA_CONNECT_ROAM_POLICY_MAX + 1]; + int ret; + enum sta_roam_policy_dfs_mode sta_roam_dfs_mode; + enum dfs_mode mode = DFS_MODE_NONE; + bool skip_unsafe_channels = false; + QDF_STATUS status; + uint8_t sap_operating_band; + + ENTER_DEV(dev); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_warn("Command not allowed in FTM mode"); + return -EINVAL; + } + + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_STA_CONNECT_ROAM_POLICY_MAX, + data, data_len, + wlan_hdd_set_sta_roam_config_policy)) { + hdd_err("invalid attr"); + return -EINVAL; + } + if (tb[QCA_WLAN_VENDOR_ATTR_STA_DFS_MODE]) + mode = nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_STA_DFS_MODE]); + if (!IS_DFS_MODE_VALID(mode)) { + hdd_err("attr sta roam dfs mode policy is not valid"); + return -EINVAL; + } + + sta_roam_dfs_mode = wlan_hdd_get_sta_roam_dfs_mode(mode); + + if (tb[QCA_WLAN_VENDOR_ATTR_STA_SKIP_UNSAFE_CHANNEL]) + skip_unsafe_channels = nla_get_u8( + tb[QCA_WLAN_VENDOR_ATTR_STA_SKIP_UNSAFE_CHANNEL]); + sap_operating_band = hdd_get_sap_operating_band(hdd_ctx); + status = sme_update_sta_roam_policy(hdd_ctx->hHal, sta_roam_dfs_mode, + skip_unsafe_channels, adapter->sessionId, + sap_operating_band); + + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("sme_update_sta_roam_policy (err=%d)", status); + return -EINVAL; + } + return 0; +} + +/** + * wlan_hdd_cfg80211_sta_roam_policy() - Wrapper to restrict scan channels, + * connection and roaming for station. + * @wiphy: wiphy structure pointer + * @wdev: Wireless device structure pointer + * @data: Pointer to the data received + * @data_len: Length of @data + * + * __wlan_hdd_cfg80211_sta_roam_policy will decide if DFS channels or unsafe + * channels needs to be skipped in scanning or not. + * If dfs_mode is disabled, driver will not scan DFS channels. + * If skip_unsafe_channels is set, driver will skip unsafe channels + * in Scanning. + * Return: 0 on success; errno on failure + */ +static int wlan_hdd_cfg80211_sta_roam_policy(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_sta_roam_policy(wiphy, wdev, data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +#ifdef FEATURE_WLAN_CH_AVOID +/** + * __wlan_hdd_cfg80211_avoid_freq() - ask driver to restart SAP if SAP + * is on unsafe channel. + * @wiphy: wiphy structure pointer + * @wdev: Wireless device structure pointer + * @data: Pointer to the data received + * @data_len: Length of @data + * + * wlan_hdd_cfg80211_avoid_freq do restart the sap if sap is already + * on any of unsafe channels. + * If sap is on any of unsafe channel, hdd_unsafe_channel_restart_sap + * will send WLAN_SVC_LTE_COEX_IND indication to userspace to restart. + * + * Return: 0 on success; errno on failure + */ +static int +__wlan_hdd_cfg80211_avoid_freq(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + hdd_context_t *hdd_ctx = wiphy_priv(wiphy); + int ret; + uint16_t unsafe_channel_count; + int unsafe_channel_index; + qdf_device_t qdf_ctx = cds_get_context(QDF_MODULE_ID_QDF_DEVICE); + + ENTER_DEV(wdev->netdev); + + if (!qdf_ctx) { + cds_err("qdf_ctx is NULL"); + return -EINVAL; + } + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_warn("Command not allowed in FTM mode"); + return -EINVAL; + } + + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + pld_get_wlan_unsafe_channel(qdf_ctx->dev, hdd_ctx->unsafe_channel_list, + &(hdd_ctx->unsafe_channel_count), + sizeof(hdd_ctx->unsafe_channel_list)); + + unsafe_channel_count = QDF_MIN((uint16_t)hdd_ctx->unsafe_channel_count, + (uint16_t)NUM_CHANNELS); + for (unsafe_channel_index = 0; + unsafe_channel_index < unsafe_channel_count; + unsafe_channel_index++) { + hdd_info("Channel %d is not safe", + hdd_ctx->unsafe_channel_list[unsafe_channel_index]); + } + hdd_unsafe_channel_restart_sap(hdd_ctx); + return 0; +} + +/** + * wlan_hdd_cfg80211_avoid_freq() - ask driver to restart SAP if SAP + * is on unsafe channel. + * @wiphy: wiphy structure pointer + * @wdev: Wireless device structure pointer + * @data: Pointer to the data received + * @data_len: Length of @data + * + * wlan_hdd_cfg80211_avoid_freq do restart the sap if sap is already + * on any of unsafe channels. + * If sap is on any of unsafe channel, hdd_unsafe_channel_restart_sap + * will send WLAN_SVC_LTE_COEX_IND indication to userspace to restart. + * + * Return: 0 on success; errno on failure + */ +static int wlan_hdd_cfg80211_avoid_freq(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_avoid_freq(wiphy, wdev, data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +#endif +/** + * __wlan_hdd_cfg80211_sap_configuration_set() - ask driver to restart SAP if + * SAP is on unsafe channel. + * @wiphy: wiphy structure pointer + * @wdev: Wireless device structure pointer + * @data: Pointer to the data received + * @data_len: Length of @data + * + * __wlan_hdd_cfg80211_sap_configuration_set function set SAP params to + * driver. + * QCA_WLAN_VENDOR_ATTR_SAP_CONFIG_CHAN will set sap config channel and + * will initiate restart of sap. + * + * Return: 0 on success; errno on failure + */ +static int +__wlan_hdd_cfg80211_sap_configuration_set(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + struct net_device *ndev = wdev->netdev; + hdd_adapter_t *hostapd_adapter = WLAN_HDD_GET_PRIV_PTR(ndev); + hdd_context_t *hdd_ctx = wiphy_priv(wiphy); + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_SAP_CONFIG_MAX + 1]; + uint8_t config_channel = 0; + hdd_ap_ctx_t *ap_ctx; + int ret; + QDF_STATUS status; + + ENTER(); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_warn("Command not allowed in FTM mode"); + return -EINVAL; + } + + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return -EINVAL; + + if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_SAP_CONFIG_MAX, + data, data_len, + wlan_hdd_sap_config_policy)) { + hdd_err("invalid attr"); + return -EINVAL; + } + + if (tb[QCA_WLAN_VENDOR_ATTR_SAP_CONFIG_CHANNEL]) { + if (!test_bit(SOFTAP_BSS_STARTED, + &hostapd_adapter->event_flags)) { + hdd_err("SAP is not started yet. Restart sap will be invalid"); + return -EINVAL; + } + + config_channel = + nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_SAP_CONFIG_CHANNEL]); + + if (!((IS_24G_CH(config_channel)) || + (IS_5G_CH(config_channel)))) { + hdd_err("Channel %d is not valid to restart SAP", + config_channel); + return -ENOTSUPP; + } + + ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(hostapd_adapter); + ap_ctx->sapConfig.channel = config_channel; + ap_ctx->sapConfig.ch_params.ch_width = + ap_ctx->sapConfig.ch_width_orig; + + cds_set_channel_params(ap_ctx->sapConfig.channel, + ap_ctx->sapConfig.sec_ch, + &ap_ctx->sapConfig.ch_params); + + cds_restart_sap(hostapd_adapter); + } + + if (tb[QCA_WLAN_VENDOR_ATTR_SAP_MANDATORY_FREQUENCY_LIST]) { + uint32_t freq_len, i; + uint32_t *freq; + uint8_t chans[QDF_MAX_NUM_CHAN]; + + hdd_debug("setting mandatory freq/chan list"); + + freq_len = nla_len( + tb[QCA_WLAN_VENDOR_ATTR_SAP_MANDATORY_FREQUENCY_LIST])/ + sizeof(uint32_t); + + if (freq_len > QDF_MAX_NUM_CHAN) { + hdd_err("insufficient space to hold channels"); + return -ENOMEM; + } + + freq = nla_data( + tb[QCA_WLAN_VENDOR_ATTR_SAP_MANDATORY_FREQUENCY_LIST]); + + hdd_debug("freq_len=%d", freq_len); + + for (i = 0; i < freq_len; i++) { + chans[i] = ieee80211_frequency_to_channel(freq[i]); + hdd_debug("freq[%d]=%d", i, freq[i]); + } + + status = cds_set_sap_mandatory_channels(chans, freq_len); + if (QDF_IS_STATUS_ERROR(status)) + return -EINVAL; + } + + return 0; +} + +/** + * wlan_hdd_cfg80211_sap_configuration_set() - sap configuration vendor command + * @wiphy: wiphy structure pointer + * @wdev: Wireless device structure pointer + * @data: Pointer to the data received + * @data_len: Length of @data + * + * __wlan_hdd_cfg80211_sap_configuration_set function set SAP params to + * driver. + * QCA_WLAN_VENDOR_ATTR_SAP_CONFIG_CHAN will set sap config channel and + * will initiate restart of sap. + * + * Return: 0 on success; errno on failure + */ +static int wlan_hdd_cfg80211_sap_configuration_set(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_sap_configuration_set(wiphy, + wdev, data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +#undef BPF_INVALID +#undef BPF_SET_RESET +#undef BPF_VERSION +#undef BPF_ID +#undef BPF_PACKET_SIZE +#undef BPF_CURRENT_OFFSET +#undef BPF_PROGRAM +#undef BPF_MAX + +/** + * define short names for the global vendor params + * used by wlan_hdd_cfg80211_wakelock_stats_rsp_callback() + */ +#define PARAM_TOTAL_CMD_EVENT_WAKE \ + QCA_WLAN_VENDOR_ATTR_TOTAL_CMD_EVENT_WAKE +#define PARAM_CMD_EVENT_WAKE_CNT_PTR \ + QCA_WLAN_VENDOR_ATTR_CMD_EVENT_WAKE_CNT_PTR +#define PARAM_CMD_EVENT_WAKE_CNT_SZ \ + QCA_WLAN_VENDOR_ATTR_CMD_EVENT_WAKE_CNT_SZ +#define PARAM_TOTAL_DRIVER_FW_LOCAL_WAKE \ + QCA_WLAN_VENDOR_ATTR_TOTAL_DRIVER_FW_LOCAL_WAKE +#define PARAM_DRIVER_FW_LOCAL_WAKE_CNT_PTR \ + QCA_WLAN_VENDOR_ATTR_DRIVER_FW_LOCAL_WAKE_CNT_PTR +#define PARAM_DRIVER_FW_LOCAL_WAKE_CNT_SZ \ + QCA_WLAN_VENDOR_ATTR_DRIVER_FW_LOCAL_WAKE_CNT_SZ +#define PARAM_TOTAL_RX_DATA_WAKE \ + QCA_WLAN_VENDOR_ATTR_TOTAL_RX_DATA_WAKE +#define PARAM_RX_UNICAST_CNT \ + QCA_WLAN_VENDOR_ATTR_RX_UNICAST_CNT +#define PARAM_RX_MULTICAST_CNT \ + QCA_WLAN_VENDOR_ATTR_RX_MULTICAST_CNT +#define PARAM_RX_BROADCAST_CNT \ + QCA_WLAN_VENDOR_ATTR_RX_BROADCAST_CNT +#define PARAM_ICMP_PKT \ + QCA_WLAN_VENDOR_ATTR_ICMP_PKT +#define PARAM_ICMP6_PKT \ + QCA_WLAN_VENDOR_ATTR_ICMP6_PKT +#define PARAM_ICMP6_RA \ + QCA_WLAN_VENDOR_ATTR_ICMP6_RA +#define PARAM_ICMP6_NA \ + QCA_WLAN_VENDOR_ATTR_ICMP6_NA +#define PARAM_ICMP6_NS \ + QCA_WLAN_VENDOR_ATTR_ICMP6_NS +#define PARAM_ICMP4_RX_MULTICAST_CNT \ + QCA_WLAN_VENDOR_ATTR_ICMP4_RX_MULTICAST_CNT +#define PARAM_ICMP6_RX_MULTICAST_CNT \ + QCA_WLAN_VENDOR_ATTR_ICMP6_RX_MULTICAST_CNT +#define PARAM_OTHER_RX_MULTICAST_CNT \ + QCA_WLAN_VENDOR_ATTR_OTHER_RX_MULTICAST_CNT +#define PARAM_RSSI_BREACH_CNT \ + QCA_WLAN_VENDOR_ATTR_RSSI_BREACH_CNT +#define PARAM_LOW_RSSI_CNT \ + QCA_WLAN_VENDOR_ATTR_LOW_RSSI_CNT +#define PARAM_GSCAN_CNT \ + QCA_WLAN_VENDOR_ATTR_GSCAN_CNT +#define PARAM_PNO_COMPLETE_CNT \ + QCA_WLAN_VENDOR_ATTR_PNO_COMPLETE_CNT +#define PARAM_PNO_MATCH_CNT \ + QCA_WLAN_VENDOR_ATTR_PNO_MATCH_CNT + + + +/** + * hdd_send_wakelock_stats() - API to send wakelock stats + * @ctx: context to be passed to callback + * @data: data passed to callback + * + * This function is used to send wake lock stats to HAL layer + * + * Return: 0 on success, error number otherwise. + */ +static uint32_t hdd_send_wakelock_stats(hdd_context_t *hdd_ctx, + const struct sir_wake_lock_stats *data) +{ + struct sk_buff *skb; + uint32_t nl_buf_len; + uint32_t total_rx_data_wake, rx_multicast_cnt; + uint32_t ipv6_rx_multicast_addr_cnt; + uint32_t icmpv6_cnt; + + ENTER(); + + nl_buf_len = NLMSG_HDRLEN; + nl_buf_len += + QCA_WLAN_VENDOR_GET_WAKE_STATS_MAX * + (NLMSG_HDRLEN + sizeof(uint32_t)); + + skb = cfg80211_vendor_cmd_alloc_reply_skb(hdd_ctx->wiphy, nl_buf_len); + + if (!skb) { + hdd_err("cfg80211_vendor_cmd_alloc_reply_skb failed"); + return -ENOMEM; + } + + hdd_info("wow_ucast_wake_up_count %d", + data->wow_ucast_wake_up_count); + hdd_info("wow_bcast_wake_up_count %d", + data->wow_bcast_wake_up_count); + hdd_info("wow_ipv4_mcast_wake_up_count %d", + data->wow_ipv4_mcast_wake_up_count); + hdd_info("wow_ipv6_mcast_wake_up_count %d", + data->wow_ipv6_mcast_wake_up_count); + hdd_info("wow_ipv6_mcast_ra_stats %d", + data->wow_ipv6_mcast_ra_stats); + hdd_info("wow_ipv6_mcast_ns_stats %d", + data->wow_ipv6_mcast_ns_stats); + hdd_info("wow_ipv6_mcast_na_stats %d", + data->wow_ipv6_mcast_na_stats); + hdd_info("wow_icmpv4_count %d", data->wow_icmpv4_count); + hdd_info("wow_icmpv6_count %d", + data->wow_icmpv6_count); + hdd_info("wow_rssi_breach_wake_up_count %d", + data->wow_rssi_breach_wake_up_count); + hdd_info("wow_low_rssi_wake_up_count %d", + data->wow_low_rssi_wake_up_count); + hdd_info("wow_gscan_wake_up_count %d", + data->wow_gscan_wake_up_count); + hdd_info("wow_pno_complete_wake_up_count %d", + data->wow_pno_complete_wake_up_count); + hdd_info("wow_pno_match_wake_up_count %d", + data->wow_pno_match_wake_up_count); + + ipv6_rx_multicast_addr_cnt = + data->wow_ipv6_mcast_wake_up_count; + + icmpv6_cnt = + data->wow_icmpv6_count; + + rx_multicast_cnt = + data->wow_ipv4_mcast_wake_up_count + + ipv6_rx_multicast_addr_cnt; + + total_rx_data_wake = + data->wow_ucast_wake_up_count + + data->wow_bcast_wake_up_count + + rx_multicast_cnt; + + if (nla_put_u32(skb, PARAM_TOTAL_CMD_EVENT_WAKE, 0) || + nla_put_u32(skb, PARAM_CMD_EVENT_WAKE_CNT_PTR, 0) || + nla_put_u32(skb, PARAM_CMD_EVENT_WAKE_CNT_SZ, 0) || + nla_put_u32(skb, PARAM_TOTAL_DRIVER_FW_LOCAL_WAKE, 0) || + nla_put_u32(skb, PARAM_DRIVER_FW_LOCAL_WAKE_CNT_PTR, 0) || + nla_put_u32(skb, PARAM_DRIVER_FW_LOCAL_WAKE_CNT_SZ, 0) || + nla_put_u32(skb, PARAM_TOTAL_RX_DATA_WAKE, + total_rx_data_wake) || + nla_put_u32(skb, PARAM_RX_UNICAST_CNT, + data->wow_ucast_wake_up_count) || + nla_put_u32(skb, PARAM_RX_MULTICAST_CNT, + rx_multicast_cnt) || + nla_put_u32(skb, PARAM_RX_BROADCAST_CNT, + data->wow_bcast_wake_up_count) || + nla_put_u32(skb, PARAM_ICMP_PKT, + data->wow_icmpv4_count) || + nla_put_u32(skb, PARAM_ICMP6_PKT, + icmpv6_cnt) || + nla_put_u32(skb, PARAM_ICMP6_RA, + data->wow_ipv6_mcast_ra_stats) || + nla_put_u32(skb, PARAM_ICMP6_NA, + data->wow_ipv6_mcast_na_stats) || + nla_put_u32(skb, PARAM_ICMP6_NS, + data->wow_ipv6_mcast_ns_stats) || + nla_put_u32(skb, PARAM_ICMP4_RX_MULTICAST_CNT, + data->wow_ipv4_mcast_wake_up_count) || + nla_put_u32(skb, PARAM_ICMP6_RX_MULTICAST_CNT, + ipv6_rx_multicast_addr_cnt) || + nla_put_u32(skb, PARAM_OTHER_RX_MULTICAST_CNT, 0) || + nla_put_u32(skb, PARAM_RSSI_BREACH_CNT, + data->wow_rssi_breach_wake_up_count) || + nla_put_u32(skb, PARAM_LOW_RSSI_CNT, + data->wow_low_rssi_wake_up_count) || + nla_put_u32(skb, PARAM_GSCAN_CNT, + data->wow_gscan_wake_up_count) || + nla_put_u32(skb, PARAM_PNO_COMPLETE_CNT, + data->wow_pno_complete_wake_up_count) || + nla_put_u32(skb, PARAM_PNO_MATCH_CNT, + data->wow_pno_match_wake_up_count)) { + hdd_err("nla put fail"); + goto nla_put_failure; + } + + cfg80211_vendor_cmd_reply(skb); + + EXIT(); + return 0; + +nla_put_failure: + kfree_skb(skb); + return -EINVAL; +} + +/** + * __wlan_hdd_cfg80211_get_wakelock_stats() - gets wake lock stats + * @wiphy: wiphy pointer + * @wdev: pointer to struct wireless_dev + * @data: pointer to incoming NL vendor data + * @data_len: length of @data + * + * This function parses the incoming NL vendor command data attributes and + * invokes the SME Api and blocks on a completion variable. + * WMA copies required data and invokes callback + * wlan_hdd_cfg80211_wakelock_stats_rsp_callback to send wake lock stats. + * + * Return: 0 on success; error number otherwise. + */ +static int __wlan_hdd_cfg80211_get_wakelock_stats(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + hdd_context_t *hdd_ctx = wiphy_priv(wiphy); + int status, ret; + struct sir_wake_lock_stats wake_lock_stats; + QDF_STATUS qdf_status; + + ENTER(); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_warn("Command not allowed in FTM mode"); + return -EINVAL; + } + + status = wlan_hdd_validate_context(hdd_ctx); + if (0 != status) + return -EINVAL; + + qdf_status = wma_get_wakelock_stats(&wake_lock_stats); + if (qdf_status != QDF_STATUS_SUCCESS) { + hdd_err("failed to get wakelock stats(err=%d)", qdf_status); + return -EINVAL; + } + + ret = hdd_send_wakelock_stats(hdd_ctx, + &wake_lock_stats); + if (ret) + hdd_err("Failed to post wake lock stats"); + + EXIT(); + return ret; +} + +/** + * wlan_hdd_cfg80211_get_wakelock_stats() - gets wake lock stats + * @wiphy: wiphy pointer + * @wdev: pointer to struct wireless_dev + * @data: pointer to incoming NL vendor data + * @data_len: length of @data + * + * This function parses the incoming NL vendor command data attributes and + * invokes the SME Api and blocks on a completion variable. + * WMA copies required data and invokes callback + * wlan_hdd_cfg80211_wakelock_stats_rsp_callback to send wake lock stats. + * + * Return: 0 on success; error number otherwise. + */ +static int wlan_hdd_cfg80211_get_wakelock_stats(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_get_wakelock_stats(wiphy, wdev, data, + data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __wlan_hdd_cfg80211_get_bus_size() - Get WMI Bus size + * @wiphy: wiphy structure pointer + * @wdev: Wireless device structure pointer + * @data: Pointer to the data received + * @data_len: Length of @data + * + * This function reads wmi max bus size and fill in the skb with + * NL attributes and send up the NL event. + * Return: 0 on success; errno on failure + */ +static int +__wlan_hdd_cfg80211_get_bus_size(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + hdd_context_t *hdd_ctx = wiphy_priv(wiphy); + int ret_val; + struct sk_buff *skb; + uint32_t nl_buf_len; + + ENTER(); + + ret_val = wlan_hdd_validate_context(hdd_ctx); + if (ret_val) + return ret_val; + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_warn("Command not allowed in FTM mode"); + return -EINVAL; + } + + hdd_info("WMI Max Bus size: %d", hdd_ctx->wmi_max_len); + + nl_buf_len = NLMSG_HDRLEN; + nl_buf_len += (sizeof(hdd_ctx->wmi_max_len) + NLA_HDRLEN); + + skb = cfg80211_vendor_cmd_alloc_reply_skb(hdd_ctx->wiphy, nl_buf_len); + if (!skb) { + hdd_err("cfg80211_vendor_cmd_alloc_reply_skb failed"); + return -ENOMEM; + } + + if (nla_put_u16(skb, QCA_WLAN_VENDOR_ATTR_DRV_INFO_BUS_SIZE, + hdd_ctx->wmi_max_len)) { + hdd_err("nla put failure"); + goto nla_put_failure; + } + + cfg80211_vendor_cmd_reply(skb); + + EXIT(); + + return 0; + +nla_put_failure: + kfree_skb(skb); + return -EINVAL; +} + +/** + * wlan_hdd_cfg80211_get_bus_size() - SSR Wrapper to Get Bus size + * @wiphy: wiphy structure pointer + * @wdev: Wireless device structure pointer + * @data: Pointer to the data received + * @data_len: Length of @data + * + * Return: 0 on success; errno on failure + */ +static int wlan_hdd_cfg80211_get_bus_size(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_get_bus_size(wiphy, wdev, data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + *__wlan_hdd_cfg80211_setband() - set band + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Length of @data + * + * Return: 0 on success, negative errno on failure + */ +static int __wlan_hdd_cfg80211_setband(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + struct net_device *dev = wdev->netdev; + hdd_context_t *hdd_ctx = wiphy_priv(wiphy); + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_MAX + 1]; + int ret; + static const struct nla_policy policy[QCA_WLAN_VENDOR_ATTR_MAX + 1] + = {[QCA_WLAN_VENDOR_ATTR_SETBAND_VALUE] = { .type = NLA_U32 } }; + + ENTER(); + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return ret; + + if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_MAX, data, data_len, policy)) { + hdd_err(FL("Invalid ATTR")); + return -EINVAL; + } + + if (!tb[QCA_WLAN_VENDOR_ATTR_SETBAND_VALUE]) { + hdd_err(FL("attr SETBAND_VALUE failed")); + return -EINVAL; + } + + ret = hdd_set_band(dev, + nla_get_u32(tb[QCA_WLAN_VENDOR_ATTR_SETBAND_VALUE])); + + EXIT(); + return ret; +} + +/** + * wlan_hdd_cfg80211_setband() - Wrapper to setband + * @wiphy: wiphy structure pointer + * @wdev: Wireless device structure pointer + * @data: Pointer to the data received + * @data_len: Length of @data + * + * Return: 0 on success; errno on failure + */ +static int wlan_hdd_cfg80211_setband(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_setband(wiphy, wdev, data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * wlan_hdd_cfg80211_sar_convert_limit_set() - Convert limit set value + * @nl80211_value: Vendor command attribute value + * @wmi_value: Pointer to return converted WMI return value + * + * Convert NL80211 vendor command value for SAR limit set to WMI value + * Return: 0 on success, -1 on invalid value + */ +static int wlan_hdd_cfg80211_sar_convert_limit_set(u32 nl80211_value, + u32 *wmi_value) +{ + int ret = 0; + + switch (nl80211_value) { + case QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_NONE: + *wmi_value = WMI_SAR_FEATURE_OFF; + break; + case QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_BDF0: + *wmi_value = WMI_SAR_FEATURE_ON_SET_0; + break; + case QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_BDF1: + *wmi_value = WMI_SAR_FEATURE_ON_SET_1; + break; + case QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_BDF2: + *wmi_value = WMI_SAR_FEATURE_ON_SET_2; + break; + case QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_BDF3: + *wmi_value = WMI_SAR_FEATURE_ON_SET_3; + break; + case QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_BDF4: + *wmi_value = WMI_SAR_FEATURE_ON_SET_4; + break; + case QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_USER: + *wmi_value = WMI_SAR_FEATURE_ON_USER_DEFINED; + break; + default: + ret = -1; + } + return ret; +} + +/** + * wlan_hdd_cfg80211_sar_convert_band() - Convert WLAN band value + * @nl80211_value: Vendor command attribute value + * @wmi_value: Pointer to return converted WMI return value + * + * Convert NL80211 vendor command value for SAR BAND to WMI value + * Return: 0 on success, -1 on invalid value + */ +static int wlan_hdd_cfg80211_sar_convert_band(u32 nl80211_value, u32 *wmi_value) +{ + int ret = 0; + + switch (nl80211_value) { + case NL80211_BAND_2GHZ: + *wmi_value = WMI_SAR_2G_ID; + break; + case NL80211_BAND_5GHZ: + *wmi_value = WMI_SAR_5G_ID; + break; + default: + ret = -1; + } + return ret; +} + +/** + * wlan_hdd_cfg80211_sar_convert_modulation() - Convert WLAN modulation value + * @nl80211_value: Vendor command attribute value + * @wmi_value: Pointer to return converted WMI return value + * + * Convert NL80211 vendor command value for SAR Modulation to WMI value + * Return: 0 on success, -1 on invalid value + */ +static int wlan_hdd_cfg80211_sar_convert_modulation(u32 nl80211_value, + u32 *wmi_value) +{ + int ret = 0; + + switch (nl80211_value) { + case QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_MODULATION_CCK: + *wmi_value = WMI_SAR_MOD_CCK; + break; + case QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_MODULATION_OFDM: + *wmi_value = WMI_SAR_MOD_OFDM; + break; + default: + ret = -1; + } + return ret; +} + +static const struct nla_policy +sar_limits_policy[QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SAR_ENABLE] = {.type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_NUM_SPECS] = {.type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_BAND] = {.type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_CHAIN] = {.type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_MODULATION] = {.type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_POWER_LIMIT] = {.type = NLA_U32}, +}; + +/** + * __wlan_hdd_set_sar_power_limits() - Set SAR power limits + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Length of @data + * + * This function is used to setup Specific Absorption Rate limit specs. + * + * Return: 0 on success, negative errno on failure + */ +static int __wlan_hdd_set_sar_power_limits(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + hdd_context_t *hdd_ctx = wiphy_priv(wiphy); + struct nlattr *sar_spec[QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_MAX + 1], + *tb[QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_MAX + 1], + *sar_spec_list; + struct sar_limit_cmd_params sar_limit_cmd = {0}; + int ret = -EINVAL, i = 0, rem = 0; + + ENTER(); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_warn("Command not allowed in FTM mode"); + return -EPERM; + } + + if (wlan_hdd_validate_context(hdd_ctx)) + return -EINVAL; + + if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_MAX, + data, data_len, sar_limits_policy)) { + hdd_err("Invalid SAR attributes"); + return -EINVAL; + } + + /* Vendor command manadates all SAR Specs in single call */ + sar_limit_cmd.commit_limits = 1; + sar_limit_cmd.sar_enable = WMI_SAR_FEATURE_NO_CHANGE; + if (tb[QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SAR_ENABLE]) { + if (wlan_hdd_cfg80211_sar_convert_limit_set(nla_get_u32( + tb[QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SAR_ENABLE]), + &sar_limit_cmd.sar_enable) < 0) { + hdd_err("Invalid SAR Enable attr"); + goto fail; + } + } + hdd_info("attr sar sar_enable %d", sar_limit_cmd.sar_enable); + + if (tb[QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_NUM_SPECS]) { + sar_limit_cmd.num_limit_rows = nla_get_u32( + tb[QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_NUM_SPECS]); + hdd_info("attr sar num_limit_rows %d", + sar_limit_cmd.num_limit_rows); + } + if (sar_limit_cmd.num_limit_rows > MAX_SAR_LIMIT_ROWS_SUPPORTED) { + hdd_err("SAR Spec list exceed supported size"); + goto fail; + } + if (sar_limit_cmd.num_limit_rows == 0) + goto send_sar_limits; + sar_limit_cmd.sar_limit_row_list = qdf_mem_malloc(sizeof( + struct sar_limit_cmd_row) * + sar_limit_cmd.num_limit_rows); + if (!sar_limit_cmd.sar_limit_row_list) { + ret = -ENOMEM; + goto fail; + } + if (!tb[QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC]) { + hdd_err("Invalid SAR SPECs list"); + goto fail; + } + + nla_for_each_nested(sar_spec_list, + tb[QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC], rem) { + if (i == sar_limit_cmd.num_limit_rows) { + hdd_warn("SAR Cmd has excess SPECs in list"); + break; + } + + if (nla_parse(sar_spec, QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_MAX, + nla_data(sar_spec_list), nla_len(sar_spec_list), + sar_limits_policy)) { + hdd_err("nla_parse failed for SAR Spec list"); + goto fail; + } + sar_limit_cmd.sar_limit_row_list[i].validity_bitmap = 0; + if (sar_spec[ + QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_POWER_LIMIT]) { + sar_limit_cmd.sar_limit_row_list[i].limit_value = + nla_get_u32(sar_spec[ + QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_POWER_LIMIT]); + } else { + hdd_err("SAR Spec does not have power limit value"); + goto fail; + } + + if (sar_spec[QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_BAND]) { + if (wlan_hdd_cfg80211_sar_convert_band(nla_get_u32( + sar_spec[QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_BAND]), + &sar_limit_cmd.sar_limit_row_list[i].band_id) + < 0) { + hdd_err("Invalid SAR Band attr"); + goto fail; + } + sar_limit_cmd.sar_limit_row_list[i].validity_bitmap |= + WMI_SAR_BAND_ID_VALID_MASK; + } + if (sar_spec[QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_CHAIN]) { + sar_limit_cmd.sar_limit_row_list[i].chain_id = + nla_get_u32(sar_spec[ + QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_CHAIN]); + sar_limit_cmd.sar_limit_row_list[i].validity_bitmap |= + WMI_SAR_CHAIN_ID_VALID_MASK; + } + if (sar_spec[QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_MODULATION]) { + if (wlan_hdd_cfg80211_sar_convert_modulation(nla_get_u32( + sar_spec[QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_MODULATION]), + &sar_limit_cmd.sar_limit_row_list[i].mod_id) + < 0) { + hdd_err("Invalid SAR Modulation attr"); + goto fail; + } + sar_limit_cmd.sar_limit_row_list[i].validity_bitmap |= + WMI_SAR_MOD_ID_VALID_MASK; + } + hdd_info("Spec_ID: %d, Band: %d Chain: %d Mod: %d POW_Limit: %d Validity_Bitmap: %d", + i, sar_limit_cmd.sar_limit_row_list[i].band_id, + sar_limit_cmd.sar_limit_row_list[i].chain_id, + sar_limit_cmd.sar_limit_row_list[i].mod_id, + sar_limit_cmd.sar_limit_row_list[i].limit_value, + sar_limit_cmd.sar_limit_row_list[i].validity_bitmap); + i++; + } + + if (i < sar_limit_cmd.num_limit_rows) { + hdd_warn("SAR Cmd has less SPECs in list"); + sar_limit_cmd.num_limit_rows = i; + } + +send_sar_limits: + if (sme_set_sar_power_limits(hdd_ctx->hHal, &sar_limit_cmd) == + QDF_STATUS_SUCCESS) + ret = 0; +fail: + qdf_mem_free(sar_limit_cmd.sar_limit_row_list); + return ret; +} + +/** + * wlan_hdd_cfg80211_set_sar_power_limits() - Set SAR power limits + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Length of @data + * + * Wrapper function of __wlan_hdd_cfg80211_set_sar_power_limits() + * + * Return: 0 on success, negative errno on failure + */ +static int wlan_hdd_cfg80211_set_sar_power_limits(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_set_sar_power_limits(wiphy, wdev, data, + data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +static const struct +nla_policy qca_wlan_vendor_attr[QCA_WLAN_VENDOR_ATTR_MAX+1] = { + [QCA_WLAN_VENDOR_ATTR_ROAMING_POLICY] = {.type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_MAC_ADDR] = {.type = NLA_BINARY, + .len = QDF_MAC_ADDR_SIZE}, +}; + +void wlan_hdd_rso_cmd_status_cb(void *ctx, struct rso_cmd_status *rso_status) +{ + hdd_context_t *hdd_ctx = (hdd_context_t *)ctx; + hdd_adapter_t *adapter; + + adapter = hdd_get_adapter_by_vdev(hdd_ctx, rso_status->vdev_id); + if (!adapter) { + hdd_err("adapter NULL"); + return; + } + + adapter->lfr_fw_status.is_disabled = rso_status->status; + complete(&adapter->lfr_fw_status.disable_lfr_event); +} + +/** + * __wlan_hdd_cfg80211_set_fast_roaming() - enable/disable roaming + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Length of @data + * + * This function is used to enable/disable roaming using vendor commands + * + * Return: 0 on success, negative errno on failure + */ +static int __wlan_hdd_cfg80211_set_fast_roaming(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + hdd_context_t *hdd_ctx = wiphy_priv(wiphy); + struct net_device *dev = wdev->netdev; + hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_MAX + 1]; + uint32_t is_fast_roam_enabled, enable_lfr_fw; + int ret; + QDF_STATUS qdf_status; + unsigned long rc; + hdd_station_ctx_t *hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + + ENTER_DEV(dev); + + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_warn("Command not allowed in FTM mode"); + return -EINVAL; + } + + ret = nla_parse(tb, QCA_WLAN_VENDOR_ATTR_MAX, data, data_len, + qca_wlan_vendor_attr); + if (ret) { + hdd_err("Invalid ATTR"); + return -EINVAL; + } + + /* Parse and fetch Enable flag */ + if (!tb[QCA_WLAN_VENDOR_ATTR_ROAMING_POLICY]) { + hdd_err("attr enable failed"); + return -EINVAL; + } + + is_fast_roam_enabled = nla_get_u32( + tb[QCA_WLAN_VENDOR_ATTR_ROAMING_POLICY]); + hdd_notice("isFastRoamEnabled %d fast_roaming_allowed %d", + is_fast_roam_enabled, adapter->fast_roaming_allowed); + + if (!adapter->fast_roaming_allowed) { + hdd_err("fast roaming not allowed on %s interface", + adapter->dev->name); + return -EINVAL; + } + + /* Update roaming */ + enable_lfr_fw = (is_fast_roam_enabled && adapter->fast_roaming_allowed); + qdf_status = sme_config_fast_roaming(hdd_ctx->hHal, adapter->sessionId, + enable_lfr_fw); + if (qdf_status != QDF_STATUS_SUCCESS) + hdd_err("sme_config_fast_roaming failed with status=%d", + qdf_status); + ret = qdf_status_to_os_return(qdf_status); + + if (eConnectionState_Associated == hdd_sta_ctx->conn_info.connState && + QDF_IS_STATUS_SUCCESS(qdf_status) && !enable_lfr_fw) { + + INIT_COMPLETION(adapter->lfr_fw_status.disable_lfr_event); + /* + * wait only for LFR disable in fw as LFR enable + * is always success + */ + rc = wait_for_completion_timeout( + &adapter->lfr_fw_status.disable_lfr_event, + msecs_to_jiffies(WAIT_TIME_RSO_CMD_STATUS)); + if (!rc) { + hdd_err("Timed out waiting for RSO CMD status"); + return -ETIMEDOUT; + } + + if (!adapter->lfr_fw_status.is_disabled) { + hdd_err("Roam disable attempt in FW fails"); + return -EBUSY; + } + } + + EXIT(); + return ret; +} + +/** + * wlan_hdd_cfg80211_set_fast_roaming() - enable/disable roaming + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Length of @data + * + * Wrapper function of __wlan_hdd_cfg80211_set_fast_roaming() + * + * Return: 0 on success, negative errno on failure + */ +static int wlan_hdd_cfg80211_set_fast_roaming(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_set_fast_roaming(wiphy, wdev, data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +/* + * define short names for the global vendor params + * used by wlan_hdd_cfg80211_setarp_stats_cmd() + */ +#define STATS_SET_INVALID \ + QCA_ATTR_NUD_STATS_SET_INVALID +#define STATS_SET_START \ + QCA_ATTR_NUD_STATS_SET_START +#define STATS_GW_IPV4 \ + QCA_ATTR_NUD_STATS_GW_IPV4 +#define STATS_SET_MAX \ + QCA_ATTR_NUD_STATS_SET_MAX + +const struct nla_policy +qca_wlan_vendor_set_nud_stats[STATS_SET_MAX + 1] = { + [STATS_SET_START] = {.type = NLA_FLAG }, + [STATS_GW_IPV4] = {.type = NLA_U32 }, +}; + +/** + * __wlan_hdd_cfg80211_set_nud_stats() - set arp stats command to firmware + * @wiphy: pointer to wireless wiphy structure. + * @wdev: pointer to wireless_dev structure. + * @data: pointer to apfind configuration data. + * @data_len: the length in byte of apfind data. + * + * This is called when wlan driver needs to send arp stats to + * firmware. + * + * Return: An error code or 0 on success. + */ +static int __wlan_hdd_cfg80211_set_nud_stats(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + struct nlattr *tb[STATS_SET_MAX + 1]; + struct net_device *dev = wdev->netdev; + hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *hdd_ctx = wiphy_priv(wiphy); + struct set_arp_stats_params arp_stats_params; + int err = 0; + + ENTER(); + + err = wlan_hdd_validate_context(hdd_ctx); + if (0 != err) + return err; + + err = nla_parse(tb, STATS_SET_MAX, data, data_len, + qca_wlan_vendor_set_nud_stats); + if (err) { + QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR, + "%s STATS_SET_START ATTR", __func__); + return err; + } + + if (tb[STATS_SET_START]) { + if (!tb[STATS_GW_IPV4]) { + QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR, + "%s STATS_SET_START CMD", __func__); + return -EINVAL; + } + arp_stats_params.flag = true; + arp_stats_params.ip_addr = nla_get_u32(tb[STATS_GW_IPV4]); + hdd_ctx->track_arp_ip = arp_stats_params.ip_addr; + } else { + arp_stats_params.flag = false; + } + if (arp_stats_params.flag) { + QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO, + "%s STATS_SET_START Cleared!!", __func__); + } + qdf_mem_zero(&adapter->hdd_stats.hdd_arp_stats, + sizeof(adapter->hdd_stats.hdd_arp_stats)); + + arp_stats_params.pkt_type = WLAN_NUD_STATS_ARP_PKT_TYPE; + arp_stats_params.vdev_id = adapter->sessionId; + + if (QDF_STATUS_SUCCESS != + sme_set_nud_debug_stats(hdd_ctx->hHal, &arp_stats_params)) { + QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR, + "%s STATS_SET_START CMD Failed!!", __func__); + return -EINVAL; + } + + EXIT(); + + return err; +} + +/** + * wlan_hdd_cfg80211_set_nud_stats() - set arp stats command to firmware + * @wiphy: pointer to wireless wiphy structure. + * @wdev: pointer to wireless_dev structure. + * @data: pointer to apfind configuration data. + * @data_len: the length in byte of apfind data. + * + * This is called when wlan driver needs to send arp stats to + * firmware. + * + * Return: An error code or 0 on success. + */ +static int wlan_hdd_cfg80211_set_nud_stats(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_set_nud_stats(wiphy, wdev, data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +#undef STATS_SET_INVALID +#undef STATS_SET_START +#undef STATS_GW_IPV4 +#undef STATS_SET_MAX + +/* + * define short names for the global vendor params + * used by wlan_hdd_cfg80211_setarp_stats_cmd() + */ +#define STATS_GET_INVALID \ + QCA_ATTR_NUD_STATS_SET_INVALID +#define COUNT_FROM_NETDEV \ + QCA_ATTR_NUD_STATS_ARP_REQ_COUNT_FROM_NETDEV +#define COUNT_TO_LOWER_MAC \ + QCA_ATTR_NUD_STATS_ARP_REQ_COUNT_TO_LOWER_MAC +#define RX_COUNT_BY_LOWER_MAC \ + QCA_ATTR_NUD_STATS_ARP_REQ_RX_COUNT_BY_LOWER_MAC +#define COUNT_TX_SUCCESS \ + QCA_ATTR_NUD_STATS_ARP_REQ_COUNT_TX_SUCCESS +#define RSP_RX_COUNT_BY_LOWER_MAC \ + QCA_ATTR_NUD_STATS_ARP_RSP_RX_COUNT_BY_LOWER_MAC +#define RSP_RX_COUNT_BY_UPPER_MAC \ + QCA_ATTR_NUD_STATS_ARP_RSP_RX_COUNT_BY_UPPER_MAC +#define RSP_COUNT_TO_NETDEV \ + QCA_ATTR_NUD_STATS_ARP_RSP_COUNT_TO_NETDEV +#define RSP_COUNT_OUT_OF_ORDER_DROP \ + QCA_ATTR_NUD_STATS_ARP_RSP_COUNT_OUT_OF_ORDER_DROP +#define AP_LINK_ACTIVE \ + QCA_ATTR_NUD_STATS_AP_LINK_ACTIVE +#define AP_LINK_DAD \ + QCA_ATTR_NUD_STATS_AP_LINK_DAD +#define STATS_GET_MAX \ + QCA_ATTR_NUD_STATS_GET_MAX + +const struct nla_policy +qca_wlan_vendor_get_nud_stats[STATS_GET_MAX + 1] = { + [COUNT_FROM_NETDEV] = {.type = NLA_U16 }, + [COUNT_TO_LOWER_MAC] = {.type = NLA_U16 }, + [RX_COUNT_BY_LOWER_MAC] = {.type = NLA_U16 }, + [COUNT_TX_SUCCESS] = {.type = NLA_U16 }, + [RSP_RX_COUNT_BY_LOWER_MAC] = {.type = NLA_U16 }, + [RSP_RX_COUNT_BY_UPPER_MAC] = {.type = NLA_U16 }, + [RSP_COUNT_TO_NETDEV] = {.type = NLA_U16 }, + [RSP_COUNT_OUT_OF_ORDER_DROP] = {.type = NLA_U16 }, + [AP_LINK_ACTIVE] = {.type = NLA_FLAG }, + [AP_LINK_DAD] = {.type = NLA_FLAG }, +}; + +/** + * __wlan_hdd_cfg80211_get_nud_stats() - get arp stats command to firmware + * @wiphy: pointer to wireless wiphy structure. + * @wdev: pointer to wireless_dev structure. + * @data: pointer to apfind configuration data. + * @data_len: the length in byte of apfind data. + * + * This is called when wlan driver needs to get arp stats to + * firmware. + * + * Return: An error code or 0 on success. + */ +static int __wlan_hdd_cfg80211_get_nud_stats(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + int err = 0; + unsigned long rc; + struct hdd_nud_stats_context *context; + struct net_device *dev = wdev->netdev; + hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *hdd_ctx = wiphy_priv(wiphy); + struct get_arp_stats_params arp_stats_params; + struct sk_buff *skb; + + ENTER(); + + err = wlan_hdd_validate_context(hdd_ctx); + if (0 != err) + return err; + + arp_stats_params.pkt_type = WLAN_NUD_STATS_ARP_PKT_TYPE; + arp_stats_params.vdev_id = adapter->sessionId; + + spin_lock(&hdd_context_lock); + context = &hdd_ctx->nud_stats_context; + INIT_COMPLETION(context->response_event); + spin_unlock(&hdd_context_lock); + + if (QDF_STATUS_SUCCESS != + sme_get_nud_debug_stats(hdd_ctx->hHal, &arp_stats_params)) { + QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR, + "%s STATS_SET_START CMD Failed!!", __func__); + return -EINVAL; + } + + rc = wait_for_completion_timeout(&context->response_event, + msecs_to_jiffies( + WLAN_WAIT_TIME_NUD_STATS)); + if (!rc) { + hdd_err("Target response timed out request "); + return -ETIMEDOUT; + } + + skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, + WLAN_NUD_STATS_LEN); + if (!skb) { + hdd_err("%s: cfg80211_vendor_cmd_alloc_reply_skb failed", + __func__); + return -ENOMEM; + } + + if (nla_put_u16(skb, COUNT_FROM_NETDEV, + adapter->hdd_stats.hdd_arp_stats.tx_arp_req_count) || + nla_put_u16(skb, COUNT_TO_LOWER_MAC, + adapter->hdd_stats.hdd_arp_stats.tx_host_fw_sent) || + nla_put_u16(skb, RX_COUNT_BY_LOWER_MAC, + adapter->hdd_stats.hdd_arp_stats.tx_host_fw_sent) || + nla_put_u16(skb, COUNT_TX_SUCCESS, + adapter->hdd_stats.hdd_arp_stats.tx_ack_cnt) || + nla_put_u16(skb, RSP_RX_COUNT_BY_LOWER_MAC, + adapter->hdd_stats.hdd_arp_stats.rx_fw_cnt) || + nla_put_u16(skb, RSP_RX_COUNT_BY_UPPER_MAC, + adapter->hdd_stats.hdd_arp_stats.rx_arp_rsp_count) || + nla_put_u16(skb, RSP_COUNT_TO_NETDEV, + adapter->hdd_stats.hdd_arp_stats.rx_delivered) || + nla_put_u16(skb, RSP_COUNT_OUT_OF_ORDER_DROP, + adapter->hdd_stats.hdd_arp_stats. + rx_host_drop_reorder)) { + hdd_err("nla put fail"); + kfree_skb(skb); + return -EINVAL; + } + if (adapter->con_status) + nla_put_flag(skb, AP_LINK_ACTIVE); + if (adapter->dad) + nla_put_flag(skb, AP_LINK_DAD); + + hdd_ctx->track_arp_ip = 0; + cfg80211_vendor_cmd_reply(skb); + return err; +} + +/** + * wlan_hdd_cfg80211_get_nud_stats() - get arp stats command to firmware + * @wiphy: pointer to wireless wiphy structure. + * @wdev: pointer to wireless_dev structure. + * @data: pointer to apfind configuration data. + * @data_len: the length in byte of apfind data. + * + * This is called when wlan driver needs to get arp stats to + * firmware. + * + * Return: An error code or 0 on success. + */ +static int wlan_hdd_cfg80211_get_nud_stats(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_get_nud_stats(wiphy, wdev, data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +#undef QCA_ATTR_NUD_STATS_SET_INVALID +#undef QCA_ATTR_NUD_STATS_ARP_REQ_COUNT_FROM_NETDEV +#undef QCA_ATTR_NUD_STATS_ARP_REQ_COUNT_TO_LOWER_MAC +#undef QCA_ATTR_NUD_STATS_ARP_REQ_RX_COUNT_BY_LOWER_MAC +#undef QCA_ATTR_NUD_STATS_ARP_REQ_COUNT_TX_SUCCESS +#undef QCA_ATTR_NUD_STATS_ARP_RSP_RX_COUNT_BY_LOWER_MAC +#undef QCA_ATTR_NUD_STATS_ARP_RSP_RX_COUNT_BY_UPPER_MAC +#undef QCA_ATTR_NUD_STATS_ARP_RSP_COUNT_TO_NETDEV +#undef QCA_ATTR_NUD_STATS_ARP_RSP_COUNT_OUT_OF_ORDER_DROP +#undef QCA_ATTR_NUD_STATS_AP_LINK_ACTIVE +#undef QCA_ATTR_NUD_STATS_GET_MAX + +void hdd_update_cca_info_cb(void *context, uint32_t congestion, + uint32_t vdev_id) +{ + hdd_context_t *hdd_ctx = (hdd_context_t *)context; + int status; + hdd_adapter_t *adapter = NULL; + hdd_station_ctx_t *hdd_sta_ctx; + + status = wlan_hdd_validate_context(hdd_ctx); + if (status != 0) + return; + + adapter = hdd_get_adapter_by_vdev(hdd_ctx, vdev_id); + if (adapter == NULL) { + hdd_err("vdev_id %d does not exist with host", vdev_id); + return; + } + + hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + hdd_sta_ctx->conn_info.cca = congestion; + hdd_info("congestion:%d", congestion); +} + +const struct wiphy_vendor_command hdd_wiphy_vendor_commands[] = { + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_DFS_CAPABILITY, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = is_driver_dfs_capable + }, + +#ifdef WLAN_FEATURE_NAN + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_NAN, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_nan_request + }, +#endif + +#ifdef WLAN_FEATURE_STATS_EXT + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_STATS_EXT, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_stats_ext_request + }, +#endif +#ifdef FEATURE_WLAN_EXTSCAN + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_START, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_extscan_start + }, + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_STOP, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_extscan_stop + }, + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_GET_VALID_CHANNELS, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_extscan_get_valid_channels + }, + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_GET_CAPABILITIES, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wlan_hdd_cfg80211_extscan_get_capabilities + }, + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_GET_CACHED_RESULTS, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_extscan_get_cached_results + }, + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SET_BSSID_HOTLIST, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_extscan_set_bssid_hotlist + }, + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_RESET_BSSID_HOTLIST, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_extscan_reset_bssid_hotlist + }, + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SET_SIGNIFICANT_CHANGE, + .flags = + WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_extscan_set_significant_change + }, + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_RESET_SIGNIFICANT_CHANGE, + .flags = + WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_extscan_reset_significant_change + }, + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_PNO_SET_LIST, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_set_epno_list + }, +#endif /* FEATURE_WLAN_EXTSCAN */ + +#ifdef WLAN_FEATURE_LINK_LAYER_STATS + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_LL_STATS_CLR, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_ll_stats_clear + }, + + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_LL_STATS_SET, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_ll_stats_set + }, + + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_LL_STATS_GET, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_ll_stats_get + }, +#endif /* WLAN_FEATURE_LINK_LAYER_STATS */ +#ifdef FEATURE_WLAN_TDLS + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_TDLS_ENABLE, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_exttdls_enable + }, + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_TDLS_DISABLE, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_exttdls_disable + }, + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_TDLS_GET_STATUS, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wlan_hdd_cfg80211_exttdls_get_status + }, +#endif + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_GET_SUPPORTED_FEATURES, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wlan_hdd_cfg80211_get_supported_features + }, + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_SCANNING_MAC_OUI, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_set_scanning_mac_oui + }, + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_GET_CONCURRENCY_MATRIX, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wlan_hdd_cfg80211_get_concurrency_matrix + }, + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_NO_DFS_FLAG, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_disable_dfs_chan_scan + }, + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_WISA, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_handle_wisa_cmd + }, + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_GET_STATION, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = hdd_cfg80211_get_station_cmd + }, + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_DO_ACS, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_do_acs + }, + + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_GET_FEATURES, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wlan_hdd_cfg80211_get_features + }, +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_KEY_MGMT_SET_KEY, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_keymgmt_set_key + }, +#endif +#ifdef FEATURE_WLAN_EXTSCAN + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_PNO_SET_PASSPOINT_LIST, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_set_passpoint_list + }, + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_PNO_RESET_PASSPOINT_LIST, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_reset_passpoint_list + }, +#endif /* FEATURE_WLAN_EXTSCAN */ + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_GET_WIFI_INFO, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wlan_hdd_cfg80211_get_wifi_info + }, + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_SET_WIFI_CONFIGURATION, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_wifi_configuration_set + }, + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_ROAM, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_set_ext_roam_params + }, + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_WIFI_LOGGER_START, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_wifi_logger_start + }, + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_GET_RING_DATA, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_wifi_logger_get_ring_data + }, + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = + QCA_NL80211_VENDOR_SUBCMD_GET_PREFERRED_FREQ_LIST, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_get_preferred_freq_list + }, + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = + QCA_NL80211_VENDOR_SUBCMD_SET_PROBABLE_OPER_CHANNEL, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_set_probable_oper_channel + }, +#ifdef WLAN_FEATURE_TSF + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_TSF, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_handle_tsf_cmd + }, +#endif +#ifdef FEATURE_WLAN_TDLS + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_TDLS_GET_CAPABILITIES, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_get_tdls_capabilities + }, +#endif +#ifdef WLAN_FEATURE_OFFLOAD_PACKETS + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_OFFLOADED_PACKETS, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_offloaded_packets + }, +#endif + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_MONITOR_RSSI, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_monitor_rssi + }, + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_ND_OFFLOAD, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_set_ns_offload + }, + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_GET_LOGGER_FEATURE_SET, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_get_logger_supp_feature + }, +#ifdef WLAN_FEATURE_MEMDUMP + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_WIFI_LOGGER_MEMORY_DUMP, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_get_fw_mem_dump + }, +#endif /* WLAN_FEATURE_MEMDUMP */ + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_TRIGGER_SCAN, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_vendor_scan + }, + + /* Vendor abort scan */ + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_ABORT_SCAN, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_vendor_abort_scan + }, + + /* OCB commands */ + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_OCB_SET_CONFIG, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_ocb_set_config + }, + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_OCB_SET_UTC_TIME, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_ocb_set_utc_time + }, + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = + QCA_NL80211_VENDOR_SUBCMD_OCB_START_TIMING_ADVERT, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_ocb_start_timing_advert + }, + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_OCB_STOP_TIMING_ADVERT, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_ocb_stop_timing_advert + }, + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_OCB_GET_TSF_TIMER, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_ocb_get_tsf_timer + }, + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_DCC_GET_STATS, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_dcc_get_stats + }, + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_DCC_CLEAR_STATS, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_dcc_clear_stats + }, + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_DCC_UPDATE_NDL, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_dcc_update_ndl + }, + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_LINK_PROPERTIES, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_get_link_properties + }, + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_OTA_TEST, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_set_ota_test + }, +#ifdef FEATURE_LFR_SUBNET_DETECTION + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_GW_PARAM_CONFIG, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_set_gateway_params + }, +#endif /* FEATURE_LFR_SUBNET_DETECTION */ + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_SET_TXPOWER_SCALE, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_txpower_scale + }, + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = + QCA_NL80211_VENDOR_SUBCMD_SET_TXPOWER_SCALE_DECR_DB, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_txpower_scale_decr_db + }, + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_PACKET_FILTER, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_bpf_offload + }, + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_ACS_POLICY, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_acs_dfs_mode + }, + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_STA_CONNECT_ROAM_POLICY, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_sta_roam_policy + }, +#ifdef FEATURE_WLAN_CH_AVOID + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_AVOID_FREQUENCY, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_avoid_freq + }, +#endif + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_SET_SAP_CONFIG, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_sap_configuration_set + }, + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = + QCA_NL80211_VENDOR_SUBCMD_P2P_LISTEN_OFFLOAD_START, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_p2p_lo_start + }, + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = + QCA_NL80211_VENDOR_SUBCMD_P2P_LISTEN_OFFLOAD_STOP, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_p2p_lo_stop + }, + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = + QCA_NL80211_VENDOR_SUBCMD_SAP_CONDITIONAL_CHAN_SWITCH, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_conditional_chan_switch + }, +#ifdef WLAN_FEATURE_NAN_DATAPATH + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_NDP, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_process_ndp_cmd + }, +#endif + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_GET_WAKE_REASON_STATS, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_get_wakelock_stats + }, + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_GET_BUS_SIZE, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wlan_hdd_cfg80211_get_bus_size + }, + { + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_SETBAND, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_setband + }, + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_ROAMING, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_set_fast_roaming + }, +#ifdef WLAN_FEATURE_DISA + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = + QCA_NL80211_VENDOR_SUBCMD_ENCRYPTION_TEST, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_encrypt_decrypt_msg + }, +#endif +#ifdef FEATURE_WLAN_TDLS + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = + QCA_NL80211_VENDOR_SUBCMD_CONFIGURE_TDLS, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_configure_tdls_mode + }, +#endif + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_SET_SAR_LIMITS, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_set_sar_power_limits + }, + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_NUD_STATS_SET, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_set_nud_stats + }, + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_NUD_STATS_GET, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_get_nud_stats + }, +}; + +#if ((LINUX_VERSION_CODE > KERNEL_VERSION(4, 4, 0)) || \ + defined(CFG80211_MULTI_SCAN_PLAN_BACKPORT)) && \ + defined(FEATURE_WLAN_SCAN_PNO) +/** + * hdd_config_sched_scan_plans_to_wiphy() - configure sched scan plans to wiphy + * @wiphy: pointer to wiphy + * @config: pointer to config + * + * Return: None + */ +static void hdd_config_sched_scan_plans_to_wiphy(struct wiphy *wiphy, + struct hdd_config *config) +{ + if (config->configPNOScanSupport) { + wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN; + wiphy->max_sched_scan_ssids = SIR_PNO_MAX_SUPP_NETWORKS; + wiphy->max_match_sets = SIR_PNO_MAX_SUPP_NETWORKS; + wiphy->max_sched_scan_ie_len = SIR_MAC_MAX_IE_LENGTH; + wiphy->max_sched_scan_plans = SIR_PNO_MAX_PLAN_REQUEST; + if (config->max_sched_scan_plan_interval) + wiphy->max_sched_scan_plan_interval = + config->max_sched_scan_plan_interval; + if (config->max_sched_scan_plan_iterations) + wiphy->max_sched_scan_plan_iterations = + config->max_sched_scan_plan_iterations; + } +} +#else +static void hdd_config_sched_scan_plans_to_wiphy(struct wiphy *wiphy, + struct hdd_config *config) +{ +} +#endif + +/** + * hdd_cfg80211_wiphy_alloc() - Allocate wiphy context + * @priv_size: Size of the hdd context. + * + * Allocate wiphy context and hdd context. + * + * Return: hdd context on success and NULL on failure. + */ +hdd_context_t *hdd_cfg80211_wiphy_alloc(int priv_size) +{ + struct wiphy *wiphy; + hdd_context_t *hdd_ctx; + + ENTER(); + + wiphy = wiphy_new(&wlan_hdd_cfg80211_ops, priv_size); + + if (!wiphy) { + hdd_err("wiphy init failed!\n"); + return NULL; + } + + hdd_ctx = wiphy_priv(wiphy); + + hdd_ctx->wiphy = wiphy; + + return hdd_ctx; +} + +/* + * FUNCTION: wlan_hdd_cfg80211_update_band + * This function is called from the supplicant through a + * private ioctl to change the band value + */ +int wlan_hdd_cfg80211_update_band(struct wiphy *wiphy, eCsrBand eBand) +{ + int i, j; + enum channel_state channelEnabledState; + + ENTER(); + + for (i = 0; i < NUM_NL80211_BANDS; i++) { + + if (NULL == wiphy->bands[i]) + continue; + + for (j = 0; j < wiphy->bands[i]->n_channels; j++) { + struct ieee80211_supported_band *band = wiphy->bands[i]; + + channelEnabledState = + cds_get_channel_state(band->channels[j]. + hw_value); + + if (NL80211_BAND_2GHZ == i && eCSR_BAND_5G == eBand) { + /* 5G only */ +#ifdef WLAN_ENABLE_SOCIAL_CHANNELS_5G_ONLY + /* Enable Social channels for P2P */ + if (WLAN_HDD_IS_SOCIAL_CHANNEL + (band->channels[j].center_freq) + && CHANNEL_STATE_ENABLE == + channelEnabledState) + band->channels[j].flags &= + ~IEEE80211_CHAN_DISABLED; + else +#endif + band->channels[j].flags |= + IEEE80211_CHAN_DISABLED; + continue; + } else if (NL80211_BAND_5GHZ == i && + eCSR_BAND_24 == eBand) { + /* 2G only */ + band->channels[j].flags |= + IEEE80211_CHAN_DISABLED; + continue; + } + + if (CHANNEL_STATE_DISABLE != channelEnabledState) + band->channels[j].flags &= + ~IEEE80211_CHAN_DISABLED; + } + } + return 0; +} + +#if defined(CFG80211_SCAN_RANDOM_MAC_ADDR) || \ + (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)) +static void wlan_hdd_cfg80211_scan_randomization_init(struct wiphy *wiphy) +{ + wiphy->features |= NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR; + wiphy->features |= NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR; +} +#else +static void wlan_hdd_cfg80211_scan_randomization_init(struct wiphy *wiphy) +{ +} +#endif + +/* Max number of supported csa_counters in beacons + * and probe responses. Set to the same value as + * IEEE80211_MAX_CSA_COUNTERS_NUM + */ +#define WLAN_HDD_MAX_NUM_CSA_COUNTERS 2 + +/* + * FUNCTION: wlan_hdd_cfg80211_init + * This function is called by hdd_wlan_startup() + * during initialization. + * This function is used to initialize and register wiphy structure. + */ +int wlan_hdd_cfg80211_init(struct device *dev, + struct wiphy *wiphy, struct hdd_config *pCfg) +{ + int i, j; + hdd_context_t *pHddCtx = wiphy_priv(wiphy); + + ENTER(); + + /* Now bind the underlying wlan device with wiphy */ + set_wiphy_dev(wiphy, dev); + + wiphy->mgmt_stypes = wlan_hdd_txrx_stypes; + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) + wiphy->regulatory_flags |= REGULATORY_DISABLE_BEACON_HINTS; + wiphy->regulatory_flags |= REGULATORY_COUNTRY_IE_IGNORE; +#else + wiphy->flags |= WIPHY_FLAG_DISABLE_BEACON_HINTS; + wiphy->country_ie_pref |= NL80211_COUNTRY_IE_IGNORE_CORE; +#endif + + wiphy->flags |= WIPHY_FLAG_HAVE_AP_SME + | WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD + | WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL +#ifdef FEATURE_WLAN_STA_4ADDR_SCHEME + | WIPHY_FLAG_4ADDR_STATION +#endif + | WIPHY_FLAG_OFFCHAN_TX; + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)) + wiphy->wowlan = &wowlan_support_cfg80211_init; +#else + wiphy->wowlan.flags = WIPHY_WOWLAN_MAGIC_PKT; + wiphy->wowlan.n_patterns = WOWL_MAX_PTRNS_ALLOWED; + wiphy->wowlan.pattern_min_len = 1; + wiphy->wowlan.pattern_max_len = WOWL_PTRN_MAX_SIZE; +#endif + + if (pCfg->isFastTransitionEnabled || pCfg->isFastRoamIniFeatureEnabled +#ifdef FEATURE_WLAN_ESE + || pCfg->isEseIniFeatureEnabled +#endif + ) { + wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM; + } +#ifdef FEATURE_WLAN_TDLS + wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS + | WIPHY_FLAG_TDLS_EXTERNAL_SETUP; +#endif + + wiphy->features |= NL80211_FEATURE_HT_IBSS; + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)) + wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_VHT_IBSS); +#endif + + hdd_config_sched_scan_plans_to_wiphy(wiphy, pCfg); + +#if defined QCA_WIFI_FTM + if (cds_get_conparam() != QDF_GLOBAL_FTM_MODE) { +#endif + + /* even with WIPHY_FLAG_CUSTOM_REGULATORY, + driver can still register regulatory callback and + it will get regulatory settings in wiphy->band[], but + driver need to determine what to do with both + regulatory settings */ + + wiphy->reg_notifier = hdd_reg_notifier; + +#if defined QCA_WIFI_FTM +} +#endif + + wiphy->max_scan_ssids = MAX_SCAN_SSID; + + wiphy->max_scan_ie_len = SIR_MAC_MAX_ADD_IE_LENGTH; + + wiphy->max_acl_mac_addrs = MAX_ACL_MAC_ADDRESS; + + wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) + | BIT(NL80211_IFTYPE_ADHOC) + | BIT(NL80211_IFTYPE_P2P_CLIENT) + | BIT(NL80211_IFTYPE_P2P_GO) + | BIT(NL80211_IFTYPE_AP) + | BIT(NL80211_IFTYPE_MONITOR); + + if (pCfg->advertiseConcurrentOperation) { + if (pCfg->enableMCC) { + int i; + + for (i = 0; + i < ARRAY_SIZE(wlan_hdd_iface_combination); + i++) { + if (!pCfg->allowMCCGODiffBI) + wlan_hdd_iface_combination[i]. + beacon_int_infra_match = true; + } + } + wiphy->n_iface_combinations = + ARRAY_SIZE(wlan_hdd_iface_combination); + wiphy->iface_combinations = wlan_hdd_iface_combination; + } + + /* Before registering we need to update the ht capabilitied based + * on ini values*/ + if (!pCfg->ShortGI20MhzEnable) { + wlan_hdd_band_2_4_ghz.ht_cap.cap &= ~IEEE80211_HT_CAP_SGI_20; + wlan_hdd_band_5_ghz.ht_cap.cap &= ~IEEE80211_HT_CAP_SGI_20; + } + + if (!pCfg->ShortGI40MhzEnable) { + wlan_hdd_band_5_ghz.ht_cap.cap &= ~IEEE80211_HT_CAP_SGI_40; + } + + if (!pCfg->nChannelBondingMode5GHz) { + wlan_hdd_band_5_ghz.ht_cap.cap &= + ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; + } + + /* + * In case of static linked driver at the time of driver unload, + * module exit doesn't happens. Module cleanup helps in cleaning + * of static memory. + * If driver load happens statically, at the time of driver unload, + * wiphy flags don't get reset because of static memory. + * It's better not to store channel in static memory. + */ + wiphy->bands[NL80211_BAND_2GHZ] = &wlan_hdd_band_2_4_ghz; + wiphy->bands[NL80211_BAND_2GHZ]->channels = + qdf_mem_malloc(sizeof(hdd_channels_2_4_ghz)); + if (wiphy->bands[NL80211_BAND_2GHZ]->channels == NULL) { + hdd_err("Not enough memory to allocate channels"); + return -ENOMEM; + } + qdf_mem_copy(wiphy->bands[NL80211_BAND_2GHZ]->channels, + &hdd_channels_2_4_ghz[0], + sizeof(hdd_channels_2_4_ghz)); + if ((hdd_is_5g_supported(pHddCtx)) && + ((eHDD_DOT11_MODE_11b != pCfg->dot11Mode) && + (eHDD_DOT11_MODE_11g != pCfg->dot11Mode) && + (eHDD_DOT11_MODE_11b_ONLY != pCfg->dot11Mode) && + (eHDD_DOT11_MODE_11g_ONLY != pCfg->dot11Mode))) { + wiphy->bands[NL80211_BAND_5GHZ] = &wlan_hdd_band_5_ghz; + wiphy->bands[NL80211_BAND_5GHZ]->channels = + qdf_mem_malloc(sizeof(hdd_channels_5_ghz)); + if (wiphy->bands[NL80211_BAND_5GHZ]->channels == NULL) { + hdd_err("Not enough memory to allocate channels"); + qdf_mem_free(wiphy-> + bands[NL80211_BAND_2GHZ]->channels); + wiphy->bands[NL80211_BAND_2GHZ]->channels = NULL; + return -ENOMEM; + } + qdf_mem_copy(wiphy->bands[NL80211_BAND_5GHZ]->channels, + &hdd_channels_5_ghz[0], + sizeof(hdd_channels_5_ghz)); + } + + for (i = 0; i < NUM_NL80211_BANDS; i++) { + + if (NULL == wiphy->bands[i]) + continue; + + for (j = 0; j < wiphy->bands[i]->n_channels; j++) { + struct ieee80211_supported_band *band = wiphy->bands[i]; + + if (NL80211_BAND_2GHZ == i && + eCSR_BAND_5G == pCfg->nBandCapability) { + /* 5G only */ +#ifdef WLAN_ENABLE_SOCIAL_CHANNELS_5G_ONLY + /* Enable social channels for P2P */ + if (WLAN_HDD_IS_SOCIAL_CHANNEL + (band->channels[j].center_freq)) + band->channels[j].flags &= + ~IEEE80211_CHAN_DISABLED; + else +#endif + band->channels[j].flags |= + IEEE80211_CHAN_DISABLED; + continue; + } else if (NL80211_BAND_5GHZ == i && + eCSR_BAND_24 == pCfg->nBandCapability) { + /* 2G only */ + band->channels[j].flags |= + IEEE80211_CHAN_DISABLED; + continue; + } + } + } + /*Initialise the supported cipher suite details */ + wiphy->cipher_suites = hdd_cipher_suites; + wiphy->n_cipher_suites = ARRAY_SIZE(hdd_cipher_suites); + + /*signal strength in mBm (100*dBm) */ + wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; + wiphy->max_remain_on_channel_duration = MAX_REMAIN_ON_CHANNEL_DURATION; + + if (cds_get_conparam() != QDF_GLOBAL_FTM_MODE) { + wiphy->n_vendor_commands = + ARRAY_SIZE(hdd_wiphy_vendor_commands); + wiphy->vendor_commands = hdd_wiphy_vendor_commands; + + wiphy->vendor_events = wlan_hdd_cfg80211_vendor_events; + wiphy->n_vendor_events = + ARRAY_SIZE(wlan_hdd_cfg80211_vendor_events); + } + + if (pCfg->enableDFSMasterCap) { + wiphy->flags |= WIPHY_FLAG_DFS_OFFLOAD; + } + + wiphy->max_ap_assoc_sta = pCfg->maxNumberOfPeers; + +#ifdef QCA_HT_2040_COEX + wiphy->features |= NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE; +#endif + wiphy->features |= NL80211_FEATURE_INACTIVITY_TIMER; + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 8, 0)) || \ + defined(CFG80211_BEACON_TX_RATE_CUSTOM_BACKPORT) + wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_BEACON_RATE_LEGACY); + wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_BEACON_RATE_HT); + wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_BEACON_RATE_VHT); +#endif + + hdd_add_channel_switch_support(&wiphy->flags); + wiphy->max_num_csa_counters = WLAN_HDD_MAX_NUM_CSA_COUNTERS; + wlan_hdd_cfg80211_scan_randomization_init(wiphy); + + EXIT(); + return 0; +} + +/** + * wlan_hdd_cfg80211_deinit() - Deinit cfg80211 + * @wiphy: the wiphy to validate against + * + * this function deinit cfg80211 and cleanup the + * memory allocated in wlan_hdd_cfg80211_init also + * reset the global reg params. + * + * Return: void + */ +void wlan_hdd_cfg80211_deinit(struct wiphy *wiphy) +{ + int i; + + for (i = 0; i < NUM_NL80211_BANDS; i++) { + if (NULL != wiphy->bands[i] && + (NULL != wiphy->bands[i]->channels)) { + qdf_mem_free(wiphy->bands[i]->channels); + wiphy->bands[i]->channels = NULL; + } + } + hdd_reset_global_reg_params(); +} + +/** + * wlan_hdd_update_band_cap() - update capabilities for supported bands + * @hdd_ctx: HDD context + * + * this function will update capabilities for supported bands + * + * Return: void + */ +static void wlan_hdd_update_band_cap(hdd_context_t *hdd_ctx) +{ + uint32_t val32; + uint16_t val16; + tSirMacHTCapabilityInfo *ht_cap_info; + QDF_STATUS status; + + status = sme_cfg_get_int(hdd_ctx->hHal, WNI_CFG_HT_CAP_INFO, &val32); + if (QDF_STATUS_SUCCESS != status) { + hdd_err("could not get HT capability info"); + val32 = 0; + } + val16 = (uint16_t)val32; + ht_cap_info = (tSirMacHTCapabilityInfo *)&val16; + + if (ht_cap_info->txSTBC == true) { + if (NULL != hdd_ctx->wiphy->bands[NL80211_BAND_2GHZ]) + hdd_ctx->wiphy->bands[NL80211_BAND_2GHZ]->ht_cap.cap |= + IEEE80211_HT_CAP_TX_STBC; + if (NULL != hdd_ctx->wiphy->bands[NL80211_BAND_5GHZ]) + hdd_ctx->wiphy->bands[NL80211_BAND_5GHZ]->ht_cap.cap |= + IEEE80211_HT_CAP_TX_STBC; + } + + if (!sme_is_feature_supported_by_fw(DOT11AC)) { + hdd_ctx->wiphy->bands[NL80211_BAND_2GHZ]-> + vht_cap.vht_supported = 0; + hdd_ctx->wiphy->bands[NL80211_BAND_2GHZ]->vht_cap.cap = 0; + hdd_ctx->wiphy->bands[NL80211_BAND_5GHZ]-> + vht_cap.vht_supported = 0; + hdd_ctx->wiphy->bands[NL80211_BAND_5GHZ]->vht_cap.cap = 0; + } +} + +/* + * In this function, wiphy structure is updated after QDF + * initialization. In wlan_hdd_cfg80211_init, only the + * default values will be initialized. The final initialization + * of all required members can be done here. + */ +void wlan_hdd_update_wiphy(hdd_context_t *hdd_ctx) +{ + hdd_ctx->wiphy->max_ap_assoc_sta = hdd_ctx->config->maxNumberOfPeers; + + wlan_hdd_update_band_cap(hdd_ctx); +} + +/** + * wlan_hdd_update_11n_mode - update 11n mode in hdd cfg + * @cfg: hdd cfg + * + * this function update 11n mode in hdd cfg + * + * Return: void + */ +void wlan_hdd_update_11n_mode(struct hdd_config *cfg) +{ + if (sme_is_feature_supported_by_fw(DOT11AC)) { + hdd_notice("support 11ac"); + } else { + hdd_notice("not support 11ac"); + if ((cfg->dot11Mode == eHDD_DOT11_MODE_11ac_ONLY) || + (cfg->dot11Mode == eHDD_DOT11_MODE_11ac)) { + cfg->dot11Mode = eHDD_DOT11_MODE_11n; + cfg->sap_p2p_11ac_override = 0; + } + } +} + +/* In this function we are registering wiphy. */ +int wlan_hdd_cfg80211_register(struct wiphy *wiphy) +{ + ENTER(); + /* Register our wiphy dev with cfg80211 */ + if (0 > wiphy_register(wiphy)) { + hdd_err("wiphy register failed"); + return -EIO; + } + + EXIT(); + return 0; +} + +/* + HDD function to update wiphy capability based on target offload status. + + wlan_hdd_cfg80211_init() does initialization of all wiphy related + capability even before downloading firmware to the target. In discrete + case, host will get know certain offload capability (say sched_scan + caps) only after downloading firmware to the target and target boots up. + This function is used to override setting done in wlan_hdd_cfg80211_init() + based on target capability. + */ +void wlan_hdd_cfg80211_update_wiphy_caps(struct wiphy *wiphy) +{ +#ifdef FEATURE_WLAN_SCAN_PNO + hdd_context_t *pHddCtx = wiphy_priv(wiphy); + struct hdd_config *pCfg = pHddCtx->config; + + /* wlan_hdd_cfg80211_init() sets sched_scan caps already in wiphy before + * control comes here. Here just we need to clear it if firmware doesn't + * have PNO support. */ + if (!pCfg->PnoOffload) { + wiphy->flags &= ~WIPHY_FLAG_SUPPORTS_SCHED_SCAN; + wiphy->max_sched_scan_ssids = 0; + wiphy->max_match_sets = 0; + wiphy->max_sched_scan_ie_len = 0; + } +#endif +} + +/* This function registers for all frame which supplicant is interested in */ +void wlan_hdd_cfg80211_register_frames(hdd_adapter_t *pAdapter) +{ + tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter); + /* Register for all P2P action, public action etc frames */ + uint16_t type = (SIR_MAC_MGMT_FRAME << 2) | (SIR_MAC_MGMT_ACTION << 4); + + ENTER(); + + /* Register frame indication call back */ + sme_register_mgmt_frame_ind_callback(hHal, hdd_indicate_mgmt_frame); + + /* Register for p2p ack indication */ + sme_register_p2p_ack_ind_callback(hHal, hdd_send_action_cnf_cb); + + /* Right now we are registering these frame when driver is getting + initialized. Once we will move to 2.6.37 kernel, in which we have + frame register ops, we will move this code as a part of that */ + /* GAS Initial Request */ + sme_register_mgmt_frame(hHal, SME_SESSION_ID_ANY, type, + (uint8_t *) GAS_INITIAL_REQ, + GAS_INITIAL_REQ_SIZE); + + /* GAS Initial Response */ + sme_register_mgmt_frame(hHal, SME_SESSION_ID_ANY, type, + (uint8_t *) GAS_INITIAL_RSP, + GAS_INITIAL_RSP_SIZE); + + /* GAS Comeback Request */ + sme_register_mgmt_frame(hHal, SME_SESSION_ID_ANY, type, + (uint8_t *) GAS_COMEBACK_REQ, + GAS_COMEBACK_REQ_SIZE); + + /* GAS Comeback Response */ + sme_register_mgmt_frame(hHal, SME_SESSION_ID_ANY, type, + (uint8_t *) GAS_COMEBACK_RSP, + GAS_COMEBACK_RSP_SIZE); + + /* P2P Public Action */ + sme_register_mgmt_frame(hHal, SME_SESSION_ID_ANY, type, + (uint8_t *) P2P_PUBLIC_ACTION_FRAME, + P2P_PUBLIC_ACTION_FRAME_SIZE); + + /* P2P Action */ + sme_register_mgmt_frame(hHal, SME_SESSION_ID_ANY, type, + (uint8_t *) P2P_ACTION_FRAME, + P2P_ACTION_FRAME_SIZE); + + /* WNM BSS Transition Request frame */ + sme_register_mgmt_frame(hHal, SME_SESSION_ID_ANY, type, + (uint8_t *) WNM_BSS_ACTION_FRAME, + WNM_BSS_ACTION_FRAME_SIZE); + + /* WNM-Notification */ + sme_register_mgmt_frame(hHal, pAdapter->sessionId, type, + (uint8_t *) WNM_NOTIFICATION_FRAME, + WNM_NOTIFICATION_FRAME_SIZE); +} + +void wlan_hdd_cfg80211_deregister_frames(hdd_adapter_t *pAdapter) +{ + tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter); + /* Register for all P2P action, public action etc frames */ + uint16_t type = (SIR_MAC_MGMT_FRAME << 2) | (SIR_MAC_MGMT_ACTION << 4); + + ENTER(); + + /* Right now we are registering these frame when driver is getting + initialized. Once we will move to 2.6.37 kernel, in which we have + frame register ops, we will move this code as a part of that */ + /* GAS Initial Request */ + + sme_deregister_mgmt_frame(hHal, SME_SESSION_ID_ANY, type, + (uint8_t *) GAS_INITIAL_REQ, + GAS_INITIAL_REQ_SIZE); + + /* GAS Initial Response */ + sme_deregister_mgmt_frame(hHal, SME_SESSION_ID_ANY, type, + (uint8_t *) GAS_INITIAL_RSP, + GAS_INITIAL_RSP_SIZE); + + /* GAS Comeback Request */ + sme_deregister_mgmt_frame(hHal, SME_SESSION_ID_ANY, type, + (uint8_t *) GAS_COMEBACK_REQ, + GAS_COMEBACK_REQ_SIZE); + + /* GAS Comeback Response */ + sme_deregister_mgmt_frame(hHal, SME_SESSION_ID_ANY, type, + (uint8_t *) GAS_COMEBACK_RSP, + GAS_COMEBACK_RSP_SIZE); + + /* P2P Public Action */ + sme_deregister_mgmt_frame(hHal, SME_SESSION_ID_ANY, type, + (uint8_t *) P2P_PUBLIC_ACTION_FRAME, + P2P_PUBLIC_ACTION_FRAME_SIZE); + + /* P2P Action */ + sme_deregister_mgmt_frame(hHal, SME_SESSION_ID_ANY, type, + (uint8_t *) P2P_ACTION_FRAME, + P2P_ACTION_FRAME_SIZE); + + /* WNM-Notification */ + sme_deregister_mgmt_frame(hHal, pAdapter->sessionId, type, + (uint8_t *) WNM_NOTIFICATION_FRAME, + WNM_NOTIFICATION_FRAME_SIZE); +} + +#ifdef FEATURE_WLAN_WAPI +void wlan_hdd_cfg80211_set_key_wapi(hdd_adapter_t *pAdapter, uint8_t key_index, + const uint8_t *mac_addr, const uint8_t *key, + int key_Len) +{ + hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + tCsrRoamSetKey setKey; + bool isConnected = true; + int status = 0; + uint32_t roamId = 0xFF; + uint8_t *pKeyPtr = NULL; + int n = 0; + + hdd_notice("Device_mode %s(%d)", + hdd_device_mode_to_string(pAdapter->device_mode), + pAdapter->device_mode); + + qdf_mem_zero(&setKey, sizeof(tCsrRoamSetKey)); + setKey.keyId = key_index; /* Store Key ID */ + setKey.encType = eCSR_ENCRYPT_TYPE_WPI; /* SET WAPI Encryption */ + setKey.keyDirection = eSIR_TX_RX; /* Key Directionn both TX and RX */ + setKey.paeRole = 0; /* the PAE role */ + if (!mac_addr || is_broadcast_ether_addr(mac_addr)) { + qdf_set_macaddr_broadcast(&setKey.peerMac); + } else { + qdf_mem_copy(setKey.peerMac.bytes, mac_addr, QDF_MAC_ADDR_SIZE); + } + setKey.keyLength = key_Len; + pKeyPtr = setKey.Key; + memcpy(pKeyPtr, key, key_Len); + + hdd_notice("WAPI KEY LENGTH:0x%04x", key_Len); + for (n = 0; n < key_Len; n++) + hdd_notice("WAPI KEY Data[%d]:%02x ", + n, setKey.Key[n]); + + pHddStaCtx->roam_info.roamingState = HDD_ROAM_STATE_SETTING_KEY; + if (isConnected) { + status = sme_roam_set_key(WLAN_HDD_GET_HAL_CTX(pAdapter), + pAdapter->sessionId, &setKey, &roamId); + } + if (status != 0) { + hdd_err("sme_roam_set_key returned ERROR status= %d", + status); + pHddStaCtx->roam_info.roamingState = HDD_ROAM_STATE_NONE; + } +} +#endif /* FEATURE_WLAN_WAPI */ + +uint8_t *wlan_hdd_cfg80211_get_ie_ptr(const uint8_t *ies_ptr, int length, + uint8_t eid) +{ + int left = length; + uint8_t *ptr = (uint8_t *)ies_ptr; + uint8_t elem_id, elem_len; + + while (left >= 2) { + elem_id = ptr[0]; + elem_len = ptr[1]; + left -= 2; + if (elem_len > left) { + hdd_alert("Invalid IEs eid = %d elem_len=%d left=%d", + eid, elem_len, left); + return NULL; + } + if (elem_id == eid) { + return ptr; + } + + left -= elem_len; + ptr += (elem_len + 2); + } + return NULL; +} + +bool wlan_hdd_is_ap_supports_immediate_power_save(uint8_t *ies, int length) +{ + uint8_t *vendor_ie; + + if (length < 2) { + hdd_debug("bss size is less than expected"); + return true; + } + if (!ies) { + hdd_debug("invalid IE pointer"); + return true; + } + vendor_ie = wlan_hdd_get_vendor_oui_ie_ptr(VENDOR1_AP_OUI_TYPE, + VENDOR1_AP_OUI_TYPE_SIZE, ies, length); + if (vendor_ie) { + hdd_debug("AP can't support immediate powersave. defer it"); + return false; + } + return true; +} + +/* + * FUNCTION: wlan_hdd_validate_operation_channel + * called by wlan_hdd_cfg80211_start_bss() and + * wlan_hdd_set_channel() + * This function validates whether given channel is part of valid + * channel list. + */ +QDF_STATUS wlan_hdd_validate_operation_channel(hdd_adapter_t *pAdapter, + int channel) +{ + + uint32_t num_ch = 0; + u8 valid_ch[WNI_CFG_VALID_CHANNEL_LIST_LEN]; + u32 indx = 0; + tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter); + uint8_t fValidChannel = false, count = 0; + struct hdd_config *hdd_pConfig_ini = (WLAN_HDD_GET_CTX(pAdapter))->config; + + num_ch = WNI_CFG_VALID_CHANNEL_LIST_LEN; + + if (hdd_pConfig_ini->sapAllowAllChannel) { + /* Validate the channel */ + for (count = CHAN_ENUM_1; count <= CHAN_ENUM_165; count++) { + if (channel == CDS_CHANNEL_NUM(count)) { + fValidChannel = true; + break; + } + } + if (fValidChannel != true) { + hdd_err("Invalid Channel [%d]", channel); + return QDF_STATUS_E_FAILURE; + } + } else { + if (0 != sme_cfg_get_str(hHal, WNI_CFG_VALID_CHANNEL_LIST, + valid_ch, &num_ch)) { + hdd_err("failed to get valid channel list"); + return QDF_STATUS_E_FAILURE; + } + for (indx = 0; indx < num_ch; indx++) { + if (channel == valid_ch[indx]) { + break; + } + } + + if (indx >= num_ch) { + hdd_err("Invalid Channel [%d]", channel); + return QDF_STATUS_E_FAILURE; + } + } + return QDF_STATUS_SUCCESS; + +} + +#ifdef DHCP_SERVER_OFFLOAD +static void wlan_hdd_set_dhcp_server_offload(hdd_adapter_t *pHostapdAdapter) +{ + hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pHostapdAdapter); + tpSirDhcpSrvOffloadInfo pDhcpSrvInfo; + uint8_t numEntries = 0; + uint8_t srv_ip[IPADDR_NUM_ENTRIES]; + uint8_t num; + uint32_t temp; + pDhcpSrvInfo = qdf_mem_malloc(sizeof(*pDhcpSrvInfo)); + if (NULL == pDhcpSrvInfo) { + hdd_err("could not allocate tDhcpSrvOffloadInfo!"); + return; + } + pDhcpSrvInfo->vdev_id = pHostapdAdapter->sessionId; + pDhcpSrvInfo->dhcpSrvOffloadEnabled = true; + pDhcpSrvInfo->dhcpClientNum = pHddCtx->config->dhcpMaxNumClients; + hdd_string_to_u8_array(pHddCtx->config->dhcpServerIP, + srv_ip, &numEntries, IPADDR_NUM_ENTRIES); + if (numEntries != IPADDR_NUM_ENTRIES) { + hdd_err("incorrect IP address (%s) assigned for DHCP server!", pHddCtx->config->dhcpServerIP); + goto end; + } + if ((srv_ip[0] >= 224) && (srv_ip[0] <= 239)) { + hdd_err("invalid IP address (%s)! It could NOT be multicast IP address!", pHddCtx->config->dhcpServerIP); + goto end; + } + if (srv_ip[IPADDR_NUM_ENTRIES - 1] >= 100) { + hdd_err("invalid IP address (%s)! The last field must be less than 100!", pHddCtx->config->dhcpServerIP); + goto end; + } + for (num = 0; num < numEntries; num++) { + temp = srv_ip[num]; + pDhcpSrvInfo->dhcpSrvIP |= (temp << (8 * num)); + } + if (QDF_STATUS_SUCCESS != + sme_set_dhcp_srv_offload(pHddCtx->hHal, pDhcpSrvInfo)) { + hdd_err("sme_setDHCPSrvOffload fail!"); + goto end; + } + hdd_info("enable DHCP Server offload successfully!"); +end: + qdf_mem_free(pDhcpSrvInfo); + return; +} +#endif /* DHCP_SERVER_OFFLOAD */ + +static int __wlan_hdd_cfg80211_change_bss(struct wiphy *wiphy, + struct net_device *dev, + struct bss_parameters *params) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + int ret = 0; + QDF_STATUS qdf_ret_status; + + ENTER(); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_warn("Command not allowed in FTM mode"); + return -EINVAL; + } + + if (wlan_hdd_validate_session_id(pAdapter->sessionId)) { + hdd_err("invalid session id: %d", pAdapter->sessionId); + return -EINVAL; + } + + MTRACE(qdf_trace(QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_CFG80211_CHANGE_BSS, + pAdapter->sessionId, params->ap_isolate)); + hdd_notice("Device_mode %s(%d), ap_isolate = %d", + hdd_device_mode_to_string(pAdapter->device_mode), + pAdapter->device_mode, params->ap_isolate); + + pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + ret = wlan_hdd_validate_context(pHddCtx); + if (0 != ret) + return ret; + + if (!(pAdapter->device_mode == QDF_SAP_MODE || + pAdapter->device_mode == QDF_P2P_GO_MODE)) { + return -EOPNOTSUPP; + } + + /* ap_isolate == -1 means that in change bss, upper layer doesn't + * want to update this parameter */ + if (-1 != params->ap_isolate) { + pAdapter->sessionCtx.ap.apDisableIntraBssFwd = + !!params->ap_isolate; + + qdf_ret_status = sme_ap_disable_intra_bss_fwd(pHddCtx->hHal, + pAdapter->sessionId, + pAdapter->sessionCtx. + ap. + apDisableIntraBssFwd); + if (!QDF_IS_STATUS_SUCCESS(qdf_ret_status)) { + ret = -EINVAL; + } + } + + EXIT(); + return ret; +} + +/** + * wlan_hdd_change_client_iface_to_new_mode() - to change iface to provided mode + * @ndev: pointer to net device provided by supplicant + * @type: type of the interface, upper layer wanted to change + * + * Upper layer provides the new interface mode that needs to be changed + * for given net device + * + * Return: success or failure in terms of integer value + */ +static int wlan_hdd_change_client_iface_to_new_mode(struct net_device *ndev, + enum nl80211_iftype type) +{ + hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(ndev); + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + struct hdd_config *config = hdd_ctx->config; + hdd_wext_state_t *wext; + struct wireless_dev *wdev; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + ENTER(); + + if (test_bit(ACS_IN_PROGRESS, &hdd_ctx->g_event_flags)) { + hdd_warn("ACS is in progress, don't change iface!"); + return -EBUSY; + } + + wdev = ndev->ieee80211_ptr; + hdd_stop_adapter(hdd_ctx, adapter, true); + hdd_deinit_adapter(hdd_ctx, adapter, true); + wdev->iftype = type; + /*Check for sub-string p2p to confirm its a p2p interface */ + if (NULL != strnstr(ndev->name, "p2p", 3)) { + adapter->device_mode = + (type == NL80211_IFTYPE_STATION) ? + QDF_P2P_DEVICE_MODE : QDF_P2P_CLIENT_MODE; + } else if (type == NL80211_IFTYPE_ADHOC) { + adapter->device_mode = QDF_IBSS_MODE; + } else { + adapter->device_mode = + (type == NL80211_IFTYPE_STATION) ? + QDF_STA_MODE : QDF_P2P_CLIENT_MODE; + } + memset(&adapter->sessionCtx, 0, sizeof(adapter->sessionCtx)); + hdd_set_station_ops(adapter->dev); + wext = WLAN_HDD_GET_WEXT_STATE_PTR(adapter); + wext->roamProfile.pAddIEScan = adapter->scan_info.scanAddIE.addIEdata; + wext->roamProfile.nAddIEScanLength = + adapter->scan_info.scanAddIE.length; + if (type == NL80211_IFTYPE_ADHOC) { + status = hdd_init_station_mode(adapter); + wext->roamProfile.BSSType = eCSR_BSS_TYPE_START_IBSS; + wext->roamProfile.phyMode = + hdd_cfg_xlate_to_csr_phy_mode(config->dot11Mode); + } + EXIT(); + + return qdf_status_to_os_return(status); +} + +static int wlan_hdd_cfg80211_change_bss(struct wiphy *wiphy, + struct net_device *dev, + struct bss_parameters *params) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_change_bss(wiphy, dev, params); + cds_ssr_unprotect(__func__); + + return ret; +} + +/* FUNCTION: wlan_hdd_change_country_code_cd + * to wait for contry code completion + */ +void *wlan_hdd_change_country_code_cb(void *pAdapter) +{ + hdd_adapter_t *call_back_pAdapter = pAdapter; + complete(&call_back_pAdapter->change_country_code); + return NULL; +} + +/** + * __wlan_hdd_cfg80211_change_iface() - change interface cfg80211 op + * @wiphy: Pointer to the wiphy structure + * @ndev: Pointer to the net device + * @type: Interface type + * @flags: Flags for change interface + * @params: Pointer to change interface parameters + * + * Return: 0 for success, error number on failure. + */ +static int __wlan_hdd_cfg80211_change_iface(struct wiphy *wiphy, + struct net_device *ndev, + enum nl80211_iftype type, + u32 *flags, + struct vif_params *params) +{ + struct wireless_dev *wdev; + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(ndev); + hdd_context_t *pHddCtx; + tCsrRoamProfile *pRoamProfile = NULL; + eCsrRoamBssType LastBSSType; + struct hdd_config *pConfig = NULL; + int status; + + ENTER(); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_warn("Command not allowed in FTM mode"); + return -EINVAL; + } + + pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + status = wlan_hdd_validate_context(pHddCtx); + if (0 != status) + return status; + + MTRACE(qdf_trace(QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_CFG80211_CHANGE_IFACE, + pAdapter->sessionId, type)); + + hdd_notice("Device_mode = %d, IFTYPE = 0x%x", + pAdapter->device_mode, type); + + status = hdd_wlan_start_modules(pHddCtx, pAdapter, false); + if (status) { + hdd_err("Failed to start modules"); + return -EINVAL; + } + + if (!cds_allow_concurrency( + wlan_hdd_convert_nl_iftype_to_hdd_type(type), + 0, HW_MODE_20_MHZ)) { + hdd_debug("This concurrency combination is not allowed"); + return -EINVAL; + } + + pConfig = pHddCtx->config; + wdev = ndev->ieee80211_ptr; + + /* Reset the current device mode bit mask */ + cds_clear_concurrency_mode(pAdapter->device_mode); + + hdd_update_tdls_ct_and_teardown_links(pHddCtx); + if ((pAdapter->device_mode == QDF_STA_MODE) || + (pAdapter->device_mode == QDF_P2P_CLIENT_MODE) || + (pAdapter->device_mode == QDF_P2P_DEVICE_MODE) || + (pAdapter->device_mode == QDF_IBSS_MODE)) { + hdd_wext_state_t *pWextState = + WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter); + + pRoamProfile = &pWextState->roamProfile; + LastBSSType = pRoamProfile->BSSType; + + switch (type) { + case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_P2P_CLIENT: + case NL80211_IFTYPE_ADHOC: + if (type == NL80211_IFTYPE_ADHOC) { + wlan_hdd_tdls_exit(pAdapter); + hdd_deregister_tx_flow_control(pAdapter); + hdd_notice("Setting interface Type to ADHOC"); + } + status = wlan_hdd_change_client_iface_to_new_mode(ndev, + type); + if (status) { + hdd_err("Failed to change iface to new mode:%d status %d", + type, status); + return status; + } + if (hdd_start_adapter(pAdapter)) { + hdd_err("Failed to start adapter :%d", + pAdapter->device_mode); + return -EINVAL; + } + goto done; + case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_P2P_GO: + { + hdd_info("Setting interface Type to %s", + (type == + NL80211_IFTYPE_AP) ? "SoftAP" : + "P2pGo"); + + /* Cancel any remain on channel for GO mode */ + if (NL80211_IFTYPE_P2P_GO == type) { + wlan_hdd_cancel_existing_remain_on_channel + (pAdapter); + } + + hdd_stop_adapter(pHddCtx, pAdapter, true); + /* De-init the adapter */ + hdd_deinit_adapter(pHddCtx, pAdapter, true); + memset(&pAdapter->sessionCtx, 0, + sizeof(pAdapter->sessionCtx)); + pAdapter->device_mode = + (type == + NL80211_IFTYPE_AP) ? QDF_SAP_MODE : + QDF_P2P_GO_MODE; + + /* + * Fw will take care incase of concurrency + */ + + if ((QDF_SAP_MODE == pAdapter->device_mode) + && (pConfig->apRandomBssidEnabled)) { + /* To meet Android requirements create a randomized + MAC address of the form 02:1A:11:Fx:xx:xx */ + get_random_bytes(&ndev->dev_addr[3], 3); + ndev->dev_addr[0] = 0x02; + ndev->dev_addr[1] = 0x1A; + ndev->dev_addr[2] = 0x11; + ndev->dev_addr[3] |= 0xF0; + memcpy(pAdapter->macAddressCurrent. + bytes, ndev->dev_addr, + QDF_MAC_ADDR_SIZE); + pr_info("wlan: Generated HotSpot BSSID " + MAC_ADDRESS_STR "\n", + MAC_ADDR_ARRAY(ndev->dev_addr)); + } + + hdd_set_ap_ops(pAdapter->dev); + + if (hdd_start_adapter(pAdapter)) { + hdd_err("Error initializing the ap mode"); + return -EINVAL; + } + /* Interface type changed update in wiphy structure */ + if (wdev) { + wdev->iftype = type; + } else { + hdd_err("Wireless dev is NULL"); + return -EINVAL; + } + goto done; + } + + default: + hdd_err("Unsupported interface type (%d)", + type); + return -EOPNOTSUPP; + } + } else if ((pAdapter->device_mode == QDF_SAP_MODE) || + (pAdapter->device_mode == QDF_P2P_GO_MODE)) { + switch (type) { + case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_P2P_CLIENT: + case NL80211_IFTYPE_ADHOC: + status = wlan_hdd_change_client_iface_to_new_mode(ndev, + type); + if (status != QDF_STATUS_SUCCESS) + return status; + if (hdd_start_adapter(pAdapter)) { + hdd_err("Failed to start adapter :%d", + pAdapter->device_mode); + return -EINVAL; + } + goto done; + + case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_P2P_GO: + wdev->iftype = type; + pAdapter->device_mode = (type == NL80211_IFTYPE_AP) ? + QDF_SAP_MODE : QDF_P2P_GO_MODE; + goto done; + + default: + hdd_err("Unsupported interface type(%d)", + type); + return -EOPNOTSUPP; + } + } else { + hdd_err("Unsupported device mode(%d)", + pAdapter->device_mode); + return -EOPNOTSUPP; + } +done: + /* Set bitmask based on updated value */ + cds_set_concurrency_mode(pAdapter->device_mode); + + hdd_lpass_notify_mode_change(pAdapter); + + EXIT(); + return 0; +} + +/** + * wlan_hdd_cfg80211_change_iface() - change interface cfg80211 op + * @wiphy: Pointer to the wiphy structure + * @ndev: Pointer to the net device + * @type: Interface type + * @flags: Flags for change interface + * @params: Pointer to change interface parameters + * + * Return: 0 for success, error number on failure. + */ +static int wlan_hdd_cfg80211_change_iface(struct wiphy *wiphy, + struct net_device *ndev, + enum nl80211_iftype type, + u32 *flags, + struct vif_params *params) +{ + int ret; + + cds_ssr_protect(__func__); + ret = + __wlan_hdd_cfg80211_change_iface(wiphy, ndev, type, flags, params); + cds_ssr_unprotect(__func__); + + return ret; +} + +#ifdef FEATURE_WLAN_TDLS +static bool wlan_hdd_is_duplicate_channel(uint8_t *arr, + int index, uint8_t match) +{ + int i; + for (i = 0; i < index; i++) { + if (arr[i] == match) + return true; + } + return false; +} +#endif + +/** + * __wlan_hdd_change_station() - change station + * @wiphy: Pointer to the wiphy structure + * @dev: Pointer to the net device. + * @mac: bssid + * @params: Pointer to station parameters + * + * Return: 0 for success, error number on failure. + */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)) +static int __wlan_hdd_change_station(struct wiphy *wiphy, + struct net_device *dev, + const uint8_t *mac, + struct station_parameters *params) +#else +static int __wlan_hdd_change_station(struct wiphy *wiphy, + struct net_device *dev, + uint8_t *mac, + struct station_parameters *params) +#endif +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *pHddCtx; + hdd_station_ctx_t *pHddStaCtx; + struct qdf_mac_addr STAMacAddress; +#ifdef FEATURE_WLAN_TDLS + tCsrStaParams StaParams = { 0 }; + uint8_t isBufSta = 0; + uint8_t isOffChannelSupported = 0; + bool is_qos_wmm_sta = false; +#endif + int ret; + + ENTER(); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_warn("Command not allowed in FTM mode"); + return -EINVAL; + } + + MTRACE(qdf_trace(QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_CHANGE_STATION, + pAdapter->sessionId, params->listen_interval)); + + if (wlan_hdd_validate_session_id(pAdapter->sessionId)) { + hdd_err("invalid session id: %d", pAdapter->sessionId); + return -EINVAL; + } + + pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + ret = wlan_hdd_validate_context(pHddCtx); + if (0 != ret) + return ret; + + pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + + qdf_mem_copy(STAMacAddress.bytes, mac, QDF_MAC_ADDR_SIZE); + + if ((pAdapter->device_mode == QDF_SAP_MODE) || + (pAdapter->device_mode == QDF_P2P_GO_MODE)) { + if (params->sta_flags_set & BIT(NL80211_STA_FLAG_AUTHORIZED)) { + status = + hdd_softap_change_sta_state(pAdapter, + &STAMacAddress, + OL_TXRX_PEER_STATE_AUTH); + + if (status != QDF_STATUS_SUCCESS) { + hdd_notice("Not able to change TL state to AUTHENTICATED"); + return -EINVAL; + } + } + } else if ((pAdapter->device_mode == QDF_STA_MODE) || + (pAdapter->device_mode == QDF_P2P_CLIENT_MODE)) { +#ifdef FEATURE_WLAN_TDLS + if (params->sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)) { + + if (cds_is_sub_20_mhz_enabled()) { + hdd_err("TDLS not allowed with sub 20 MHz"); + return -EINVAL; + } + + StaParams.capability = params->capability; + StaParams.uapsd_queues = params->uapsd_queues; + StaParams.max_sp = params->max_sp; + + /* Convert (first channel , number of channels) tuple to + * the total list of channels. This goes with the assumption + * that if the first channel is < 14, then the next channels + * are an incremental of 1 else an incremental of 4 till the number + * of channels. + */ + hdd_notice("params->supported_channels_len: %d", params->supported_channels_len); + if (0 != params->supported_channels_len) { + int i = 0, j = 0, k = 0, no_of_channels = 0; + int num_unique_channels; + int next; + for (i = 0; + i < params->supported_channels_len + && j < SIR_MAC_MAX_SUPP_CHANNELS; i += 2) { + int wifi_chan_index; + if (!wlan_hdd_is_duplicate_channel + (StaParams.supported_channels, j, + params->supported_channels[i])) { + StaParams. + supported_channels[j] = + params-> + supported_channels[i]; + } else { + continue; + } + wifi_chan_index = + ((StaParams.supported_channels[j] <= + HDD_CHANNEL_14) ? 1 : 4); + no_of_channels = + params->supported_channels[i + 1]; + + hdd_notice("i: %d, j: %d, k: %d, StaParams.supported_channels[%d]: %d, wifi_chan_index: %d, no_of_channels: %d", i, j, k, j, + StaParams. + supported_channels[j], + wifi_chan_index, + no_of_channels); + for (k = 1; k <= no_of_channels && + j < SIR_MAC_MAX_SUPP_CHANNELS - 1; + k++) { + next = + StaParams. + supported_channels[j] + + wifi_chan_index; + if (!wlan_hdd_is_duplicate_channel(StaParams.supported_channels, j + 1, next)) { + StaParams. + supported_channels[j + + + 1] + = next; + } else { + continue; + } + hdd_notice("i: %d, j: %d, k: %d, StaParams.supported_channels[%d]: %d", i, j, k, + j + 1, + StaParams. + supported_channels[j + + 1]); + j += 1; + } + } + num_unique_channels = j + 1; + hdd_notice("Unique Channel List"); + for (i = 0; i < num_unique_channels; i++) { + hdd_notice("StaParams.supported_channels[%d]: %d,", i, + StaParams. + supported_channels[i]); + } + if (MAX_CHANNEL < num_unique_channels) + num_unique_channels = MAX_CHANNEL; + StaParams.supported_channels_len = + num_unique_channels; + hdd_notice("After removing duplcates StaParams.supported_channels_len: %d", + StaParams.supported_channels_len); + } + if (params->supported_oper_classes_len > + CDS_MAX_SUPP_OPER_CLASSES) { + hdd_notice("received oper classes:%d, resetting it to max supported: %d", + params->supported_oper_classes_len, + CDS_MAX_SUPP_OPER_CLASSES); + params->supported_oper_classes_len = + CDS_MAX_SUPP_OPER_CLASSES; + } + qdf_mem_copy(StaParams.supported_oper_classes, + params->supported_oper_classes, + params->supported_oper_classes_len); + StaParams.supported_oper_classes_len = + params->supported_oper_classes_len; + + if (params->ext_capab_len > + sizeof(StaParams.extn_capability)) { + hdd_debug("received extn capabilities:%d, resetting it to max supported", + params->ext_capab_len); + params->ext_capab_len = + sizeof(StaParams.extn_capability); + } + if (0 != params->ext_capab_len) + qdf_mem_copy(StaParams.extn_capability, + params->ext_capab, + params->ext_capab_len); + + if (NULL != params->ht_capa) { + StaParams.htcap_present = 1; + qdf_mem_copy(&StaParams.HTCap, params->ht_capa, + sizeof(tSirHTCap)); + } + + StaParams.supported_rates_len = + params->supported_rates_len; + + /* Note : The Maximum sizeof supported_rates sent by the Supplicant is 32. + * The supported_rates array , for all the structures propogating till Add Sta + * to the firmware has to be modified , if the supplicant (ieee80211) is + * modified to send more rates. + */ + + /* To avoid Data Currption , set to max length to SIR_MAC_MAX_SUPP_RATES + */ + if (StaParams.supported_rates_len > + SIR_MAC_MAX_SUPP_RATES) + StaParams.supported_rates_len = + SIR_MAC_MAX_SUPP_RATES; + + if (0 != StaParams.supported_rates_len) { + int i = 0; + qdf_mem_copy(StaParams.supported_rates, + params->supported_rates, + StaParams.supported_rates_len); + hdd_notice("Supported Rates with Length %d", + StaParams.supported_rates_len); + for (i = 0; i < StaParams.supported_rates_len; + i++) + hdd_notice("[%d]: %0x", i, + StaParams.supported_rates[i]); + } + + if (NULL != params->vht_capa) { + StaParams.vhtcap_present = 1; + qdf_mem_copy(&StaParams.VHTCap, + params->vht_capa, + sizeof(tSirVHTCap)); + } + + if (0 != params->ext_capab_len) { + /*Define A Macro : TODO Sunil */ + if ((1 << 4) & StaParams.extn_capability[3]) { + isBufSta = 1; + } + /* TDLS Channel Switching Support */ + if ((1 << 6) & StaParams.extn_capability[3]) { + isOffChannelSupported = 1; + } + } + + if (pHddCtx->config->fEnableTDLSWmmMode && + (params->ht_capa || params->vht_capa || + (params->sta_flags_set & BIT(NL80211_STA_FLAG_WME)))) + is_qos_wmm_sta = true; + + hdd_notice("%s: TDLS Peer is QOS capable" + " is_qos_wmm_sta= %d HTcapPresent = %d", + __func__, is_qos_wmm_sta, + StaParams.htcap_present); + + status = wlan_hdd_tdls_set_peer_caps(pAdapter, mac, + &StaParams, + isBufSta, + isOffChannelSupported, + is_qos_wmm_sta); + if (QDF_STATUS_SUCCESS != status) { + hdd_err("wlan_hdd_tdls_set_peer_caps failed!"); + return -EINVAL; + } + + status = + wlan_hdd_tdls_add_station(wiphy, dev, mac, 1, + &StaParams); + if (QDF_STATUS_SUCCESS != status) { + hdd_err("wlan_hdd_tdls_add_station failed!"); + return -EINVAL; + } + } +#endif + } + EXIT(); + return ret; +} + +/** + * wlan_hdd_change_station() - cfg80211 change station handler function + * @wiphy: Pointer to the wiphy structure + * @dev: Pointer to the net device. + * @mac: bssid + * @params: Pointer to station parameters + * + * This is the cfg80211 change station handler function which invokes + * the internal function @__wlan_hdd_change_station with + * SSR protection. + * + * Return: 0 for success, error number on failure. + */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)) || defined(WITH_BACKPORTS) +static int wlan_hdd_change_station(struct wiphy *wiphy, + struct net_device *dev, + const u8 *mac, + struct station_parameters *params) +#else +static int wlan_hdd_change_station(struct wiphy *wiphy, + struct net_device *dev, + u8 *mac, + struct station_parameters *params) +#endif +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_change_station(wiphy, dev, mac, params); + cds_ssr_unprotect(__func__); + + return ret; +} + +/* + * FUNCTION: __wlan_hdd_cfg80211_add_key + * This function is used to initialize the key information + */ +static int __wlan_hdd_cfg80211_add_key(struct wiphy *wiphy, + struct net_device *ndev, + u8 key_index, bool pairwise, + const u8 *mac_addr, + struct key_params *params) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(ndev); + tCsrRoamSetKey setKey; + int status; + uint32_t roamId = 0xFF; + hdd_hostapd_state_t *pHostapdState; + QDF_STATUS qdf_ret_status; + hdd_context_t *pHddCtx; + hdd_ap_ctx_t *ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(pAdapter); + + ENTER(); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_warn("Command not allowed in FTM mode"); + return -EINVAL; + } + + if (wlan_hdd_validate_session_id(pAdapter->sessionId)) { + hdd_err("invalid session id: %d", pAdapter->sessionId); + return -EINVAL; + } + + MTRACE(qdf_trace(QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_CFG80211_ADD_KEY, + pAdapter->sessionId, params->key_len)); + pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + status = wlan_hdd_validate_context(pHddCtx); + + if (0 != status) + return status; + + hdd_notice("Device_mode %s(%d)", + hdd_device_mode_to_string(pAdapter->device_mode), + pAdapter->device_mode); + + if (CSR_MAX_NUM_KEY <= key_index) { + hdd_err("Invalid key index %d", key_index); + + return -EINVAL; + } + + if (CSR_MAX_KEY_LEN < params->key_len) { + hdd_err("Invalid key length %d", params->key_len); + + return -EINVAL; + } + + hdd_notice("called with key index = %d & key length %d", key_index, params->key_len); + + /*extract key idx, key len and key */ + qdf_mem_zero(&setKey, sizeof(tCsrRoamSetKey)); + setKey.keyId = key_index; + setKey.keyLength = params->key_len; + qdf_mem_copy(&setKey.Key[0], params->key, params->key_len); + + switch (params->cipher) { + case WLAN_CIPHER_SUITE_WEP40: + setKey.encType = eCSR_ENCRYPT_TYPE_WEP40_STATICKEY; + break; + + case WLAN_CIPHER_SUITE_WEP104: + setKey.encType = eCSR_ENCRYPT_TYPE_WEP104_STATICKEY; + break; + + case WLAN_CIPHER_SUITE_TKIP: + { + u8 *pKey = &setKey.Key[0]; + setKey.encType = eCSR_ENCRYPT_TYPE_TKIP; + + qdf_mem_zero(pKey, CSR_MAX_KEY_LEN); + + /*Supplicant sends the 32bytes key in this order + + |--------------|----------|----------| + | Tk1 |TX-MIC | RX Mic | + |||--------------|----------|----------| + <---16bytes---><--8bytes--><--8bytes--> + + */ + /*Sme expects the 32 bytes key to be in the below order + + |--------------|----------|----------| + | Tk1 |RX-MIC | TX Mic | + |||--------------|----------|----------| + <---16bytes---><--8bytes--><--8bytes--> + */ + /* Copy the Temporal Key 1 (TK1) */ + qdf_mem_copy(pKey, params->key, 16); + + /*Copy the rx mic first */ + qdf_mem_copy(&pKey[16], ¶ms->key[24], 8); + + /*Copy the tx mic */ + qdf_mem_copy(&pKey[24], ¶ms->key[16], 8); + + break; + } + + case WLAN_CIPHER_SUITE_CCMP: + setKey.encType = eCSR_ENCRYPT_TYPE_AES; + break; + +#ifdef FEATURE_WLAN_WAPI + case WLAN_CIPHER_SUITE_SMS4: + { + qdf_mem_zero(&setKey, sizeof(tCsrRoamSetKey)); + wlan_hdd_cfg80211_set_key_wapi(pAdapter, key_index, + mac_addr, params->key, + params->key_len); + return 0; + } +#endif + +#ifdef FEATURE_WLAN_ESE + case WLAN_CIPHER_SUITE_KRK: + setKey.encType = eCSR_ENCRYPT_TYPE_KRK; + break; +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + case WLAN_CIPHER_SUITE_BTK: + setKey.encType = eCSR_ENCRYPT_TYPE_BTK; + break; +#endif +#endif + +#ifdef WLAN_FEATURE_11W + case WLAN_CIPHER_SUITE_AES_CMAC: + setKey.encType = eCSR_ENCRYPT_TYPE_AES_CMAC; + break; +#endif + + default: + hdd_err("unsupported cipher type %u", params->cipher); + return -EOPNOTSUPP; + } + + hdd_info("encryption type %d", setKey.encType); + + if (!pairwise) { + /* set group key */ + hdd_notice("%s- %d: setting Broadcast key", __func__, __LINE__); + setKey.keyDirection = eSIR_RX_ONLY; + qdf_set_macaddr_broadcast(&setKey.peerMac); + } else { + /* set pairwise key */ + hdd_notice("%s- %d: setting pairwise key", __func__, __LINE__); + setKey.keyDirection = eSIR_TX_RX; + qdf_mem_copy(setKey.peerMac.bytes, mac_addr, QDF_MAC_ADDR_SIZE); + } + if ((QDF_IBSS_MODE == pAdapter->device_mode) && !pairwise) { + /* if a key is already installed, block all subsequent ones */ + if (pAdapter->sessionCtx.station.ibss_enc_key_installed) { + hdd_info("IBSS key installed already"); + return 0; + } + + setKey.keyDirection = eSIR_TX_RX; + /*Set the group key */ + status = sme_roam_set_key(WLAN_HDD_GET_HAL_CTX(pAdapter), + pAdapter->sessionId, &setKey, &roamId); + + if (0 != status) { + hdd_err("sme_roam_set_key failed, returned %d", status); + return -EINVAL; + } + /*Save the keys here and call sme_roam_set_key for setting + the PTK after peer joins the IBSS network */ + qdf_mem_copy(&pAdapter->sessionCtx.station.ibss_enc_key, + &setKey, sizeof(tCsrRoamSetKey)); + + pAdapter->sessionCtx.station.ibss_enc_key_installed = 1; + return status; + } + if ((pAdapter->device_mode == QDF_SAP_MODE) || + (pAdapter->device_mode == QDF_P2P_GO_MODE)) { + pHostapdState = WLAN_HDD_GET_HOSTAP_STATE_PTR(pAdapter); + if (pHostapdState->bssState == BSS_START) { + status = wlansap_set_key_sta( + WLAN_HDD_GET_SAP_CTX_PTR(pAdapter), &setKey); + if (status != QDF_STATUS_SUCCESS) { + hdd_err("[%4d] wlansap_set_key_sta returned ERROR status= %d", + __LINE__, status); + } + } + + /* Save the key in ap ctx for use on START_BASS and restart */ + if (pairwise || + eCSR_ENCRYPT_TYPE_WEP40_STATICKEY == setKey.encType || + eCSR_ENCRYPT_TYPE_WEP104_STATICKEY == setKey.encType) + qdf_mem_copy(&ap_ctx->wepKey[key_index], &setKey, + sizeof(tCsrRoamSetKey)); + else + qdf_mem_copy(&ap_ctx->groupKey, &setKey, + sizeof(tCsrRoamSetKey)); + + } else if ((pAdapter->device_mode == QDF_STA_MODE) || + (pAdapter->device_mode == QDF_P2P_CLIENT_MODE)) { + hdd_wext_state_t *pWextState = + WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter); + hdd_station_ctx_t *pHddStaCtx = + WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + + if (!pairwise) { + /* set group key */ + if (pHddStaCtx->roam_info.deferKeyComplete) { + hdd_notice("%s- %d: Perform Set key Complete", + __func__, __LINE__); + hdd_perform_roam_set_key_complete(pAdapter); + } + } + + pWextState->roamProfile.Keys.KeyLength[key_index] = + (u8) params->key_len; + + pWextState->roamProfile.Keys.defaultIndex = key_index; + + qdf_mem_copy(&pWextState->roamProfile.Keys. + KeyMaterial[key_index][0], params->key, + params->key_len); + + pHddStaCtx->roam_info.roamingState = HDD_ROAM_STATE_SETTING_KEY; + + hdd_info("Set key for peerMac "MAC_ADDRESS_STR" direction %d", + MAC_ADDR_ARRAY(setKey.peerMac.bytes), + setKey.keyDirection); + + /* The supplicant may attempt to set the PTK once pre-authentication + is done. Save the key in the UMAC and include it in the ADD BSS + request */ + qdf_ret_status = sme_ft_update_key(WLAN_HDD_GET_HAL_CTX(pAdapter), + pAdapter->sessionId, &setKey); + if (qdf_ret_status == QDF_STATUS_FT_PREAUTH_KEY_SUCCESS) { + hdd_info("Update PreAuth Key success"); + return 0; + } else if (qdf_ret_status == QDF_STATUS_FT_PREAUTH_KEY_FAILED) { + hdd_err("Update PreAuth Key failed"); + return -EINVAL; + } + + /* issue set key request to SME */ + status = sme_roam_set_key(WLAN_HDD_GET_HAL_CTX(pAdapter), + pAdapter->sessionId, &setKey, &roamId); + + if (0 != status) { + hdd_err("sme_roam_set_key failed, returned %d", status); + pHddStaCtx->roam_info.roamingState = + HDD_ROAM_STATE_NONE; + return -EINVAL; + } + + /* in case of IBSS as there was no information available about WEP keys during + * IBSS join, group key intialized with NULL key, so re-initialize group key + * with correct value*/ + if ((eCSR_BSS_TYPE_START_IBSS == + pWextState->roamProfile.BSSType) + && + !((IW_AUTH_KEY_MGMT_802_1X == + (pWextState->authKeyMgmt & IW_AUTH_KEY_MGMT_802_1X)) + && (eCSR_AUTH_TYPE_OPEN_SYSTEM == + pHddStaCtx->conn_info.authType) + ) + && ((WLAN_CIPHER_SUITE_WEP40 == params->cipher) + || (WLAN_CIPHER_SUITE_WEP104 == params->cipher) + ) + ) { + setKey.keyDirection = eSIR_RX_ONLY; + qdf_set_macaddr_broadcast(&setKey.peerMac); + + hdd_info("Set key peerMac "MAC_ADDRESS_STR" direction %d", + MAC_ADDR_ARRAY(setKey.peerMac.bytes), + setKey.keyDirection); + + status = sme_roam_set_key(WLAN_HDD_GET_HAL_CTX(pAdapter), + pAdapter->sessionId, &setKey, + &roamId); + + if (0 != status) { + hdd_err("sme_roam_set_key failed for group key (IBSS), returned %d", status); + pHddStaCtx->roam_info.roamingState = + HDD_ROAM_STATE_NONE; + return -EINVAL; + } + } + } + EXIT(); + return 0; +} + +static int wlan_hdd_cfg80211_add_key(struct wiphy *wiphy, + struct net_device *ndev, + u8 key_index, bool pairwise, + const u8 *mac_addr, + struct key_params *params) +{ + int ret; + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_add_key(wiphy, ndev, key_index, pairwise, + mac_addr, params); + cds_ssr_unprotect(__func__); + + return ret; +} + +/* + * FUNCTION: __wlan_hdd_cfg80211_get_key + * This function is used to get the key information + */ +static int __wlan_hdd_cfg80211_get_key(struct wiphy *wiphy, + struct net_device *ndev, + u8 key_index, bool pairwise, + const u8 *mac_addr, void *cookie, + void (*callback)(void *cookie, + struct key_params *) + ) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(ndev); + hdd_wext_state_t *pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter); + tCsrRoamProfile *pRoamProfile = &(pWextState->roamProfile); + struct key_params params; + + ENTER(); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_warn("Command not allowed in FTM mode"); + return -EINVAL; + } + + hdd_notice("Device_mode %s(%d)", + hdd_device_mode_to_string(pAdapter->device_mode), + pAdapter->device_mode); + + memset(¶ms, 0, sizeof(params)); + + if (CSR_MAX_NUM_KEY <= key_index) { + hdd_err("invalid key index %d", + key_index); + return -EINVAL; + } + + switch (pRoamProfile->EncryptionType.encryptionType[0]) { + case eCSR_ENCRYPT_TYPE_NONE: + params.cipher = IW_AUTH_CIPHER_NONE; + break; + + case eCSR_ENCRYPT_TYPE_WEP40_STATICKEY: + case eCSR_ENCRYPT_TYPE_WEP40: + params.cipher = WLAN_CIPHER_SUITE_WEP40; + break; + + case eCSR_ENCRYPT_TYPE_WEP104_STATICKEY: + case eCSR_ENCRYPT_TYPE_WEP104: + params.cipher = WLAN_CIPHER_SUITE_WEP104; + break; + + case eCSR_ENCRYPT_TYPE_TKIP: + params.cipher = WLAN_CIPHER_SUITE_TKIP; + break; + + case eCSR_ENCRYPT_TYPE_AES: + params.cipher = WLAN_CIPHER_SUITE_AES_CMAC; + break; + + default: + params.cipher = IW_AUTH_CIPHER_NONE; + break; + } + + MTRACE(qdf_trace(QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_CFG80211_GET_KEY, + pAdapter->sessionId, params.cipher)); + + params.key_len = pRoamProfile->Keys.KeyLength[key_index]; + params.seq_len = 0; + params.seq = NULL; + params.key = &pRoamProfile->Keys.KeyMaterial[key_index][0]; + callback(cookie, ¶ms); + + EXIT(); + return 0; +} + +static int wlan_hdd_cfg80211_get_key(struct wiphy *wiphy, + struct net_device *ndev, + u8 key_index, bool pairwise, + const u8 *mac_addr, void *cookie, + void (*callback)(void *cookie, + struct key_params *) + ) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_get_key(wiphy, ndev, key_index, pairwise, + mac_addr, cookie, callback); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __wlan_hdd_cfg80211_del_key() - Delete the encryption key for station + * @wiphy: wiphy interface context + * @ndev: pointer to net device + * @key_index: Key index used in 802.11 frames + * @unicast: true if it is unicast key + * @multicast: true if it is multicast key + * + * This function is required for cfg80211_ops API. + * It is used to delete the key information + * Underlying hardware implementation does not have API to delete the + * encryption key. It is automatically deleted when the peer is + * removed. Hence this function currently does nothing. + * Future implementation may interprete delete key operation to + * replacing the key with a random junk value, effectively making it + * useless. + * + * Return: status code, always 0. + */ + +static int __wlan_hdd_cfg80211_del_key(struct wiphy *wiphy, + struct net_device *ndev, + u8 key_index, + bool pairwise, const u8 *mac_addr) +{ + EXIT(); + return 0; +} + +/** + * wlan_hdd_cfg80211_del_key() - cfg80211 delete key handler function + * @wiphy: Pointer to wiphy structure. + * @dev: Pointer to net_device structure. + * @key_index: key index + * @pairwise: pairwise + * @mac_addr: mac address + * + * This is the cfg80211 delete key handler function which invokes + * the internal function @__wlan_hdd_cfg80211_del_key with + * SSR protection. + * + * Return: 0 for success, error number on failure. + */ +static int wlan_hdd_cfg80211_del_key(struct wiphy *wiphy, + struct net_device *dev, + u8 key_index, + bool pairwise, const u8 *mac_addr) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_del_key(wiphy, dev, key_index, + pairwise, mac_addr); + cds_ssr_unprotect(__func__); + + return ret; +} + +/* + * FUNCTION: __wlan_hdd_cfg80211_set_default_key + * This function is used to set the default tx key index + */ +static int __wlan_hdd_cfg80211_set_default_key(struct wiphy *wiphy, + struct net_device *ndev, + u8 key_index, + bool unicast, bool multicast) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(ndev); + hdd_wext_state_t *pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter); + hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + hdd_context_t *pHddCtx; + int status; + + ENTER(); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_warn("Command not allowed in FTM mode"); + return -EINVAL; + } + + if (wlan_hdd_validate_session_id(pAdapter->sessionId)) { + hdd_err("invalid session id: %d", pAdapter->sessionId); + return -EINVAL; + } + + MTRACE(qdf_trace(QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_CFG80211_SET_DEFAULT_KEY, + pAdapter->sessionId, key_index)); + + hdd_notice("Device_mode %s(%d) key_index = %d", + hdd_device_mode_to_string(pAdapter->device_mode), + pAdapter->device_mode, key_index); + + if (CSR_MAX_NUM_KEY <= key_index) { + hdd_err("Invalid key index %d", key_index); + return -EINVAL; + } + + pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + status = wlan_hdd_validate_context(pHddCtx); + + if (0 != status) + return status; + + if ((pAdapter->device_mode == QDF_STA_MODE) || + (pAdapter->device_mode == QDF_P2P_CLIENT_MODE)) { + if ((eCSR_ENCRYPT_TYPE_TKIP != + pHddStaCtx->conn_info.ucEncryptionType) && + (eCSR_ENCRYPT_TYPE_AES != + pHddStaCtx->conn_info.ucEncryptionType)) { + /* If default key index is not same as previous one, + * then update the default key index */ + + tCsrRoamSetKey setKey; + uint32_t roamId = 0xFF; + tCsrKeys *Keys = &pWextState->roamProfile.Keys; + + hdd_info("Default tx key index %d", key_index); + + Keys->defaultIndex = (u8) key_index; + qdf_mem_zero(&setKey, sizeof(tCsrRoamSetKey)); + setKey.keyId = key_index; + setKey.keyLength = Keys->KeyLength[key_index]; + + qdf_mem_copy(&setKey.Key[0], + &Keys->KeyMaterial[key_index][0], + Keys->KeyLength[key_index]); + + setKey.keyDirection = eSIR_TX_RX; + + qdf_copy_macaddr(&setKey.peerMac, + &pHddStaCtx->conn_info.bssId); + + if (Keys->KeyLength[key_index] == CSR_WEP40_KEY_LEN && + pWextState->roamProfile.EncryptionType. + encryptionType[0] == eCSR_ENCRYPT_TYPE_WEP104) { + /* In the case of dynamic wep supplicant hardcodes DWEP type + * to eCSR_ENCRYPT_TYPE_WEP104 even though ap is configured for + * WEP-40 encryption. In this canse the key length is 5 but the + * encryption type is 104 hence checking the key langht(5) and + * encryption type(104) and switching encryption type to 40*/ + pWextState->roamProfile.EncryptionType. + encryptionType[0] = eCSR_ENCRYPT_TYPE_WEP40; + pWextState->roamProfile.mcEncryptionType. + encryptionType[0] = eCSR_ENCRYPT_TYPE_WEP40; + } + + setKey.encType = + pWextState->roamProfile.EncryptionType. + encryptionType[0]; + + /* Issue set key request */ + status = sme_roam_set_key(WLAN_HDD_GET_HAL_CTX(pAdapter), + pAdapter->sessionId, &setKey, + &roamId); + + if (0 != status) { + hdd_err("sme_roam_set_key failed, returned %d", + status); + return -EINVAL; + } + } + } else if (QDF_SAP_MODE == pAdapter->device_mode) { + /* In SoftAp mode setting key direction for default mode */ + if ((eCSR_ENCRYPT_TYPE_TKIP != + pWextState->roamProfile.EncryptionType.encryptionType[0]) + && (eCSR_ENCRYPT_TYPE_AES != + pWextState->roamProfile.EncryptionType. + encryptionType[0])) { + /* Saving key direction for default key index to TX default */ + hdd_ap_ctx_t *pAPCtx = + WLAN_HDD_GET_AP_CTX_PTR(pAdapter); + pAPCtx->wepKey[key_index].keyDirection = + eSIR_TX_DEFAULT; + hdd_info("WEP default key index set to SAP context %d", + key_index); + pAPCtx->wep_def_key_idx = key_index; + } + } + + EXIT(); + return status; +} + +static int wlan_hdd_cfg80211_set_default_key(struct wiphy *wiphy, + struct net_device *ndev, + u8 key_index, + bool unicast, bool multicast) +{ + int ret; + cds_ssr_protect(__func__); + ret = + __wlan_hdd_cfg80211_set_default_key(wiphy, ndev, key_index, unicast, + multicast); + cds_ssr_unprotect(__func__); + + return ret; +} + +/* + * wlan_hdd_cfg80211_update_bss_list :to inform nl80211 + * interface that BSS might have been lost. + * @pAdapter: adaptor + * @bssid: bssid which might have been lost + * + * Return: bss which is unlinked from kernel cache + */ +struct cfg80211_bss *wlan_hdd_cfg80211_update_bss_list( + hdd_adapter_t *pAdapter, tSirMacAddr bssid) +{ + struct net_device *dev = pAdapter->dev; + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct wiphy *wiphy = wdev->wiphy; + struct cfg80211_bss *bss = NULL; + + bss = hdd_cfg80211_get_bss(wiphy, NULL, bssid, + NULL, 0); + if (bss == NULL) { + hdd_err("BSS not present"); + } else { + hdd_info("cfg80211_unlink_bss called for BSSID " + MAC_ADDRESS_STR, MAC_ADDR_ARRAY(bssid)); + cfg80211_unlink_bss(wiphy, bss); + } + return bss; +} + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4 , 3, 0)) || \ + defined (CFG80211_INFORM_BSS_FRAME_DATA) +static struct cfg80211_bss * +wlan_hdd_cfg80211_inform_bss_frame_data(struct wiphy *wiphy, + struct ieee80211_channel *chan, + struct ieee80211_mgmt *mgmt, + size_t frame_len, + int rssi, gfp_t gfp, + uint64_t boottime_ns) +{ + struct cfg80211_bss *bss_status = NULL; + struct cfg80211_inform_bss data = {0}; + + data.chan = chan; + data.boottime_ns = boottime_ns; + data.signal = rssi; + bss_status = cfg80211_inform_bss_frame_data(wiphy, &data, mgmt, + frame_len, gfp); + return bss_status; +} +#else +static struct cfg80211_bss * +wlan_hdd_cfg80211_inform_bss_frame_data(struct wiphy *wiphy, + struct ieee80211_channel *chan, + struct ieee80211_mgmt *mgmt, + size_t frame_len, + int rssi, gfp_t gfp, + uint64_t boottime_ns) +{ + struct cfg80211_bss *bss_status = NULL; + + bss_status = cfg80211_inform_bss_frame(wiphy, chan, mgmt, frame_len, + rssi, gfp); + return bss_status; +} +#endif + +/** + * wlan_hdd_cfg80211_inform_bss_frame() - inform bss details to NL80211 + * @pAdapter: Pointer to adapter + * @bss_desc: Pointer to bss descriptor + * + * This function is used to inform the BSS details to nl80211 interface. + * + * Return: struct cfg80211_bss pointer + */ +struct cfg80211_bss *wlan_hdd_cfg80211_inform_bss_frame(hdd_adapter_t *pAdapter, + tSirBssDescription *bss_desc) +{ + /* + * cfg80211_inform_bss() is not updating ie field of bss entry, if entry + * already exists in bss data base of cfg80211 for that particular BSS + * ID. Using cfg80211_inform_bss_frame to update the bss entry instead + * of cfg80211_inform_bss, But this call expects mgmt packet as input. + * As of now there is no possibility to get the mgmt(probe response) + * frame from PE, converting bss_desc to ieee80211_mgmt(probe response) + * and passing to cfg80211_inform_bss_frame. + */ + struct net_device *dev = pAdapter->dev; + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct wiphy *wiphy = wdev->wiphy; + int chan_no = bss_desc->channelId; +#ifdef WLAN_ENABLE_AGEIE_ON_SCAN_RESULTS + qcom_ie_age *qie_age = NULL; + int ie_length = + GET_IE_LEN_IN_BSS_DESC(bss_desc->length) + sizeof(qcom_ie_age); +#else + int ie_length = GET_IE_LEN_IN_BSS_DESC(bss_desc->length); +#endif + const char *ie = + ((ie_length != 0) ? (const char *)&bss_desc->ieFields : NULL); + unsigned int freq; + struct ieee80211_channel *chan; + struct ieee80211_mgmt *mgmt = NULL; + struct cfg80211_bss *bss_status = NULL; + size_t frame_len = sizeof(struct ieee80211_mgmt) + ie_length; + int rssi = 0; + hdd_context_t *pHddCtx; + int status; + struct timespec ts; + struct hdd_config *cfg_param; + + pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + status = wlan_hdd_validate_context(pHddCtx); + if (0 != status) + return NULL; + + cfg_param = pHddCtx->config; + mgmt = qdf_mem_malloc((sizeof(struct ieee80211_mgmt) + ie_length)); + if (!mgmt) { + hdd_err("memory allocation failed"); + return NULL; + } + + memcpy(mgmt->bssid, bss_desc->bssId, ETH_ALEN); + + /* Android does not want the timestamp from the frame. + Instead it wants a monotonic increasing value */ + get_monotonic_boottime(&ts); + mgmt->u.probe_resp.timestamp = + ((u64) ts.tv_sec * 1000000) + (ts.tv_nsec / 1000); + + mgmt->u.probe_resp.beacon_int = bss_desc->beaconInterval; + mgmt->u.probe_resp.capab_info = bss_desc->capabilityInfo; + +#ifdef WLAN_ENABLE_AGEIE_ON_SCAN_RESULTS + /* GPS Requirement: need age ie per entry. Using vendor specific. */ + /* Assuming this is the last IE, copy at the end */ + ie_length -= sizeof(qcom_ie_age); + qie_age = (qcom_ie_age *) (mgmt->u.probe_resp.variable + ie_length); + qie_age->element_id = QCOM_VENDOR_IE_ID; + qie_age->len = QCOM_VENDOR_IE_AGE_LEN; + qie_age->oui_1 = QCOM_OUI1; + qie_age->oui_2 = QCOM_OUI2; + qie_age->oui_3 = QCOM_OUI3; + qie_age->type = QCOM_VENDOR_IE_AGE_TYPE; + /* + * Lowi expects the timestamp of bss in units of 1/10 ms. In driver + * all bss related timestamp is in units of ms. Due to this when scan + * results are sent to lowi the scan age is high.To address this, + * send age in units of 1/10 ms. + */ + qie_age->age = + (uint32_t)(qdf_mc_timer_get_system_time() - bss_desc->received_time)/10; + qie_age->tsf_delta = bss_desc->tsf_delta; + memcpy(&qie_age->beacon_tsf, bss_desc->timeStamp, + sizeof(qie_age->beacon_tsf)); + memcpy(&qie_age->seq_ctrl, &bss_desc->seq_ctrl, + sizeof(qie_age->seq_ctrl)); +#endif + + memcpy(mgmt->u.probe_resp.variable, ie, ie_length); + if (bss_desc->fProbeRsp) { + mgmt->frame_control |= + (u16) (IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_PROBE_RESP); + } else { + mgmt->frame_control |= + (u16) (IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_BEACON); + } + + if (chan_no <= ARRAY_SIZE(hdd_channels_2_4_ghz) && + (wiphy->bands[NL80211_BAND_2GHZ] != NULL)) { + freq = + ieee80211_channel_to_frequency(chan_no, + NL80211_BAND_2GHZ); + } else if ((chan_no > ARRAY_SIZE(hdd_channels_2_4_ghz)) + && (wiphy->bands[NL80211_BAND_5GHZ] != NULL)) { + freq = + ieee80211_channel_to_frequency(chan_no, + NL80211_BAND_5GHZ); + } else { + hdd_err("Invalid chan_no %d", chan_no); + qdf_mem_free(mgmt); + return NULL; + } + + chan = __ieee80211_get_channel(wiphy, freq); + /* When the band is changed on the fly using the GUI, three things are done + * 1. scan abort + * 2. flush scan results from cache + * 3. update the band with the new band user specified (refer to the + * hdd_set_band_helper function) as part of the scan abort, message will be + * queued to PE and we proceed with flushing and changinh the band. + * PE will stop the scanning further and report back the results what ever + * it had till now by calling the call back function. + * if the time between update band and scandone call back is sufficient + * enough the band change reflects in SME, SME validates the channels + * and discards the channels correponding to previous band and calls back + * with zero bss results. but if the time between band update and scan done + * callback is very small then band change will not reflect in SME and SME + * reports to HDD all the channels correponding to previous band.this is due + * to race condition.but those channels are invalid to the new band and so + * this function __ieee80211_get_channel will return NULL.Each time we + * report scan result with this pointer null warning kernel trace is printed. + * if the scan results contain large number of APs continuosly kernel + * warning trace is printed and it will lead to apps watch dog bark. + * So drop the bss and continue to next bss. + */ + if (chan == NULL) { + hdd_err("chan pointer is NULL, chan_no: %d freq: %d", + chan_no, freq); + qdf_mem_free(mgmt); + return NULL; + } + + /* Based on .ini configuration, raw rssi can be reported for bss. + * Raw rssi is typically used for estimating power. + */ + + rssi = (cfg_param->inform_bss_rssi_raw) ? bss_desc->rssi_raw : + bss_desc->rssi; + + /* Supplicant takes the signal strength in terms of mBm(100*dBm) */ + rssi = QDF_MIN(rssi, 0) * 100; + + hdd_log(LOG1, "BSSID: " MAC_ADDRESS_STR " Channel:%d RSSI:%d TSF %u", + MAC_ADDR_ARRAY(mgmt->bssid), chan->center_freq, + (int)(rssi / 100), + bss_desc->timeStamp[0]); + + bss_status = wlan_hdd_cfg80211_inform_bss_frame_data(wiphy, chan, mgmt, + frame_len, rssi, + GFP_KERNEL, + bss_desc->scansystimensec); + pHddCtx->beacon_probe_rsp_cnt_per_scan++; + qdf_mem_free(mgmt); + return bss_status; +} + +/** + * wlan_hdd_cfg80211_update_bss_db() - update bss database of CF80211 + * @pAdapter: Pointer to adapter + * @pRoamInfo: Pointer to roam info + * + * This function is used to update the BSS data base of CFG8011 + * + * Return: struct cfg80211_bss pointer + */ +struct cfg80211_bss *wlan_hdd_cfg80211_update_bss_db(hdd_adapter_t *pAdapter, + tCsrRoamInfo *pRoamInfo) +{ + tCsrRoamConnectedProfile roamProfile; + tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter); + struct cfg80211_bss *bss = NULL; + + memset(&roamProfile, 0, sizeof(tCsrRoamConnectedProfile)); + sme_roam_get_connect_profile(hHal, pAdapter->sessionId, &roamProfile); + + if (NULL != roamProfile.pBssDesc) { + bss = wlan_hdd_cfg80211_inform_bss_frame(pAdapter, + roamProfile.pBssDesc); + + if (NULL == bss) + hdd_notice("wlan_hdd_cfg80211_inform_bss_frame returned NULL"); + + sme_roam_free_connect_profile(&roamProfile); + } else { + hdd_err("roamProfile.pBssDesc is NULL"); + } + return bss; +} +/** + * wlan_hdd_cfg80211_update_bss() - update bss + * @wiphy: Pointer to wiphy + * @pAdapter: Pointer to adapter + * @scan_time: scan request timestamp + * + * Return: zero if success, non-zero otherwise + */ +int wlan_hdd_cfg80211_update_bss(struct wiphy *wiphy, + hdd_adapter_t *pAdapter, + uint32_t scan_time) +{ + tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter); + tCsrScanResultInfo *pScanResult; + QDF_STATUS status = 0; + tScanResultHandle pResult; + struct cfg80211_bss *bss_status = NULL; + hdd_context_t *pHddCtx; + int ret; + + ENTER(); + + if (wlan_hdd_validate_session_id(pAdapter->sessionId)) { + hdd_err("invalid session id: %d", pAdapter->sessionId); + return -EINVAL; + } + + MTRACE(qdf_trace(QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_CFG80211_UPDATE_BSS, + NO_SESSION, pAdapter->sessionId)); + + pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + ret = wlan_hdd_validate_context(pHddCtx); + if (0 != ret) + return ret; + + /* start getting scan results and populate cgf80211 BSS database */ + status = sme_scan_get_result(hHal, pAdapter->sessionId, NULL, &pResult); + + /* no scan results */ + if (NULL == pResult) { + hdd_err("No scan result Status %d", status); + return -EAGAIN; + } + + pScanResult = sme_scan_result_get_first(hHal, pResult); + + while (pScanResult) { + /* + * - cfg80211_inform_bss() is not updating ie field of bss + * entry if entry already exists in bss data base of cfg80211 + * for that particular BSS ID. Using cfg80211_inform_bss_frame + * to update thebss entry instead of cfg80211_inform_bss, + * But this call expects mgmt packet as input. As of now + * there is no possibility to get the mgmt(probe response) + * frame from PE, converting bss_desc to + * ieee80211_mgmt(probe response) and passing to c + * fg80211_inform_bss_frame. + * - Update BSS only if beacon timestamp is later than + * scan request timestamp. + */ + if ((scan_time == 0) || + (scan_time < + pScanResult->BssDescriptor.received_time)) { + bss_status = + wlan_hdd_cfg80211_inform_bss_frame(pAdapter, + &pScanResult->BssDescriptor); + + if (NULL == bss_status) { + hdd_info("NULL returned by cfg80211_inform_bss_frame"); + } else { + cfg80211_put_bss( + wiphy, + bss_status); + } + } else { + hdd_info("BSSID: " MAC_ADDRESS_STR " Skipped", + MAC_ADDR_ARRAY(pScanResult->BssDescriptor.bssId)); + } + pScanResult = sme_scan_result_get_next(hHal, pResult); + } + + sme_scan_result_purge(hHal, pResult); + /* + * For SAP mode, scan is invoked by hostapd during SAP start + * if hostapd is restarted, we need to flush previous scan + * result so that it will reflect environment change + */ + if (pAdapter->device_mode == QDF_SAP_MODE +#ifdef FEATURE_WLAN_AP_AP_ACS_OPTIMIZE + && pHddCtx->skip_acs_scan_status != eSAP_SKIP_ACS_SCAN +#endif + ) + sme_scan_flush_result(hHal); + + EXIT(); + return 0; +} + +/** + * wlan_hdd_cfg80211_pmksa_candidate_notify() - notify a new PMSKA candidate + * @pAdapter: Pointer to adapter + * @pRoamInfo: Pointer to roam info + * @index: Index + * @preauth: Preauth flag + * + * This function is used to notify the supplicant of a new PMKSA candidate. + * PMK value is notified to supplicant whether PMK caching or OKC is enabled + * in firmware or not. Supplicant needs this value becaue it uses PMK caching + * by default. + * + * Return: 0 for success, non-zero for failure + */ +int wlan_hdd_cfg80211_pmksa_candidate_notify(hdd_adapter_t *adapter, + tCsrRoamInfo *roam_info, + int index, bool preauth) +{ + struct net_device *dev = adapter->dev; + hdd_context_t *hdd_ctx = (hdd_context_t *) adapter->pHddCtx; + struct pmkid_mode_bits pmkid_modes; + + ENTER(); + hdd_notice("is going to notify supplicant of:"); + + if (NULL == roam_info) { + hdd_alert("pRoamInfo is NULL"); + return -EINVAL; + } + + hdd_get_pmkid_modes(hdd_ctx, &pmkid_modes); + if (pmkid_modes.fw_okc) { + hdd_notice(MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(roam_info->bssid.bytes)); + cfg80211_pmksa_candidate_notify(dev, index, + roam_info->bssid.bytes, + preauth, GFP_KERNEL); + } + return 0; +} + +#ifdef FEATURE_WLAN_LFR_METRICS +/** + * wlan_hdd_cfg80211_roam_metrics_preauth() - roam metrics preauth + * @pAdapter: Pointer to adapter + * @pRoamInfo: Pointer to roam info + * + * 802.11r/LFR metrics reporting function to report preauth initiation + * + * Return: QDF status + */ +#define MAX_LFR_METRICS_EVENT_LENGTH 100 +QDF_STATUS wlan_hdd_cfg80211_roam_metrics_preauth(hdd_adapter_t *pAdapter, + tCsrRoamInfo *pRoamInfo) +{ + unsigned char metrics_notification[MAX_LFR_METRICS_EVENT_LENGTH + 1]; + union iwreq_data wrqu; + + ENTER(); + + if (NULL == pAdapter) { + hdd_err("pAdapter is NULL!"); + return QDF_STATUS_E_FAILURE; + } + + /* create the event */ + memset(&wrqu, 0, sizeof(wrqu)); + memset(metrics_notification, 0, sizeof(metrics_notification)); + + wrqu.data.pointer = metrics_notification; + wrqu.data.length = scnprintf(metrics_notification, + sizeof(metrics_notification), + "QCOM: LFR_PREAUTH_INIT " MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(pRoamInfo->bssid.bytes)); + + wireless_send_event(pAdapter->dev, IWEVCUSTOM, &wrqu, + metrics_notification); + + EXIT(); + + return QDF_STATUS_SUCCESS; +} + +/** + * wlan_hdd_cfg80211_roam_metrics_handover() - roam metrics hand over + * @pAdapter: Pointer to adapter + * @pRoamInfo: Pointer to roam info + * @preauth_status: Preauth status + * + * 802.11r/LFR metrics reporting function to report handover initiation + * + * Return: QDF status + */ +QDF_STATUS +wlan_hdd_cfg80211_roam_metrics_preauth_status(hdd_adapter_t *pAdapter, + tCsrRoamInfo *pRoamInfo, + bool preauth_status) +{ + unsigned char metrics_notification[MAX_LFR_METRICS_EVENT_LENGTH + 1]; + union iwreq_data wrqu; + + ENTER(); + + if (NULL == pAdapter) { + hdd_err("pAdapter is NULL!"); + return QDF_STATUS_E_FAILURE; + } + + /* create the event */ + memset(&wrqu, 0, sizeof(wrqu)); + memset(metrics_notification, 0, sizeof(metrics_notification)); + + scnprintf(metrics_notification, sizeof(metrics_notification), + "QCOM: LFR_PREAUTH_STATUS " MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(pRoamInfo->bssid.bytes)); + + if (1 == preauth_status) + strlcat(metrics_notification, " true", + sizeof(metrics_notification)); + else + strlcat(metrics_notification, " false", + sizeof(metrics_notification)); + + wrqu.data.pointer = metrics_notification; + wrqu.data.length = strlen(metrics_notification); + + wireless_send_event(pAdapter->dev, IWEVCUSTOM, &wrqu, + metrics_notification); + + EXIT(); + + return QDF_STATUS_SUCCESS; +} + +/** + * wlan_hdd_cfg80211_roam_metrics_handover() - roam metrics hand over + * @pAdapter: Pointer to adapter + * @pRoamInfo: Pointer to roam info + * + * 802.11r/LFR metrics reporting function to report handover initiation + * + * Return: QDF status + */ +QDF_STATUS wlan_hdd_cfg80211_roam_metrics_handover(hdd_adapter_t *pAdapter, + tCsrRoamInfo *pRoamInfo) +{ + unsigned char metrics_notification[MAX_LFR_METRICS_EVENT_LENGTH + 1]; + union iwreq_data wrqu; + + ENTER(); + + if (NULL == pAdapter) { + hdd_err("pAdapter is NULL!"); + return QDF_STATUS_E_FAILURE; + } + + /* create the event */ + memset(&wrqu, 0, sizeof(wrqu)); + memset(metrics_notification, 0, sizeof(metrics_notification)); + + wrqu.data.pointer = metrics_notification; + wrqu.data.length = scnprintf(metrics_notification, + sizeof(metrics_notification), + "QCOM: LFR_PREAUTH_HANDOVER " + MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(pRoamInfo->bssid.bytes)); + + wireless_send_event(pAdapter->dev, IWEVCUSTOM, &wrqu, + metrics_notification); + + EXIT(); + + return QDF_STATUS_SUCCESS; +} +#endif + +/** + * hdd_select_cbmode() - select channel bonding mode + * @pAdapter: Pointer to adapter + * @operatingChannel: Operating channel + * @ch_params: channel info struct to populate + * + * Return: none + */ +void hdd_select_cbmode(hdd_adapter_t *pAdapter, uint8_t operationChannel, + struct ch_params_s *ch_params) +{ + hdd_station_ctx_t *station_ctx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + struct hdd_mon_set_ch_info *ch_info = &station_ctx->ch_info; + uint8_t sec_ch = 0; + + /* + * CDS api expects secondary channel for calculating + * the channel params + */ + if ((ch_params->ch_width == CH_WIDTH_40MHZ) && + (CDS_IS_CHANNEL_24GHZ(operationChannel))) { + if (operationChannel >= 1 && operationChannel <= 5) + sec_ch = operationChannel + 4; + else if (operationChannel >= 6 && operationChannel <= 13) + sec_ch = operationChannel - 4; + } + + /* This call decides required channel bonding mode */ + cds_set_channel_params(operationChannel, sec_ch, ch_params); + + if (QDF_GLOBAL_MONITOR_MODE == cds_get_conparam()) { + eHddDot11Mode hdd_dot11_mode; + uint8_t iniDot11Mode = + (WLAN_HDD_GET_CTX(pAdapter))->config->dot11Mode; + + hdd_notice("Dot11Mode is %u", iniDot11Mode); + switch (iniDot11Mode) { + case eHDD_DOT11_MODE_AUTO: + case eHDD_DOT11_MODE_11ac: + case eHDD_DOT11_MODE_11ac_ONLY: + if (sme_is_feature_supported_by_fw(DOT11AC)) + hdd_dot11_mode = eHDD_DOT11_MODE_11ac; + else + hdd_dot11_mode = eHDD_DOT11_MODE_11n; + break; + case eHDD_DOT11_MODE_11n: + case eHDD_DOT11_MODE_11n_ONLY: + hdd_dot11_mode = eHDD_DOT11_MODE_11n; + break; + default: + hdd_dot11_mode = iniDot11Mode; + break; + } + ch_info->channel_width = ch_params->ch_width; + ch_info->phy_mode = + hdd_cfg_xlate_to_csr_phy_mode(hdd_dot11_mode); + ch_info->channel = operationChannel; + ch_info->cb_mode = ch_params->ch_width; + hdd_info("ch_info width %d, phymode %d channel %d", + ch_info->channel_width, ch_info->phy_mode, + ch_info->channel); + } +} + +/** + * wlan_hdd_handle_sap_sta_dfs_conc() - to handle SAP STA DFS conc + * @adapter: STA adapter + * @roam_profile: STA roam profile + * + * This routine will move SAP from dfs to non-dfs, if sta is coming up. + * + * Return: false if sta-sap conc is not allowed, else return true + */ +static bool wlan_hdd_handle_sap_sta_dfs_conc(hdd_adapter_t *adapter, + tCsrRoamProfile *roam_profile) +{ + hdd_context_t *hdd_ctx; + hdd_adapter_t *ap_adapter; + hdd_ap_ctx_t *hdd_ap_ctx; + hdd_hostapd_state_t *hostapd_state; + uint8_t channel = 0; + QDF_STATUS status; + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (!hdd_ctx) { + hdd_err("HDD context is NULL"); + return true; + } + + ap_adapter = hdd_get_adapter(hdd_ctx, QDF_SAP_MODE); + /* probably no sap running, no handling required */ + if (ap_adapter == NULL) + return true; + + /* + * sap is not in started state, so it is fine to go ahead with sta. + * if sap is currently doing CAC then don't allow sta to go further. + */ + if (!test_bit(SOFTAP_BSS_STARTED, &(ap_adapter)->event_flags) && + (hdd_ctx->dev_dfs_cac_status != DFS_CAC_IN_PROGRESS)) + return true; + + if (hdd_ctx->dev_dfs_cac_status == DFS_CAC_IN_PROGRESS) { + hdd_err("Concurrent SAP is in CAC state, STA is not allowed"); + return false; + } + + /* + * log and return error, if we allow STA to go through, we don't + * know what is going to happen better stop sta connection + */ + hdd_ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(ap_adapter); + if (NULL == hdd_ap_ctx) { + hdd_err("AP context not found"); + return false; + } + + /* sap is on non-dfs channel, nothing to handle */ + if (!CDS_IS_DFS_CH(hdd_ap_ctx->operatingChannel)) { + hdd_info("sap is on non-dfs channel, sta is allowed"); + return true; + } + /* + * find out by looking in to scan cache where sta is going to + * connect by passing its roam_profile. + */ + status = cds_get_channel_from_scan_result(adapter, + roam_profile, &channel); + + /* + * If the STA's channel is 2.4 GHz, then set pcl with only 2.4 GHz + * channels for roaming case. + */ + if (CDS_IS_CHANNEL_24GHZ(channel)) { + hdd_info("sap is on dfs, new sta conn on 2.4 is allowed"); + return true; + } + + /* + * If channel is 0 or DFS then better to call pcl and find out the + * best channel. If channel is non-dfs 5 GHz then better move SAP + * to STA's channel to make scc, so we have room for 3port MCC + * scenario. + */ + if ((0 == channel) || CDS_IS_DFS_CH(channel)) + channel = cds_get_nondfs_preferred_channel(CDS_SAP_MODE, + true); + + hostapd_state = WLAN_HDD_GET_HOSTAP_STATE_PTR(ap_adapter); + qdf_event_reset(&hostapd_state->qdf_event); + status = wlansap_set_channel_change_with_csa( + WLAN_HDD_GET_SAP_CTX_PTR(ap_adapter), channel, + hdd_ap_ctx->sapConfig.ch_width_orig); + + if (QDF_STATUS_SUCCESS != status) { + hdd_err("Set channel with CSA IE failed, can't allow STA"); + return false; + } + + /* + * wait here for SAP to finish the channel switch. When channel + * switch happens, SAP sends few beacons with CSA_IE. After + * successfully Transmission of those beacons, it will move its + * state from started to disconnected and move to new channel. + * once it moves to new channel, sap again moves its state + * machine from disconnected to started and set this event. + * wait for 10 secs to finish this. + */ + status = qdf_wait_single_event(&hostapd_state->qdf_event, 10000); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("wait for qdf_event failed, STA not allowed!!"); + return false; + } + + return true; +} + +/** + * wlan_hdd_cfg80211_connect_start() - to start the association process + * @pAdapter: Pointer to adapter + * @ssid: Pointer to ssid + * @ssid_len: Length of ssid + * @bssid: Pointer to bssid + * @bssid_hint: Pointer to bssid hint + * @operatingChannel: Operating channel + * @ch_width: channel width. this is needed only for IBSS + * + * This function is used to start the association process + * + * Return: 0 for success, non-zero for failure + */ +static int wlan_hdd_cfg80211_connect_start(hdd_adapter_t *pAdapter, + const u8 *ssid, size_t ssid_len, + const u8 *bssid, const u8 *bssid_hint, + u8 operatingChannel, + enum nl80211_chan_width ch_width) +{ + int status = 0; + QDF_STATUS qdf_status; + hdd_wext_state_t *pWextState; + hdd_context_t *pHddCtx; + hdd_station_ctx_t *hdd_sta_ctx; + uint32_t roamId; + tCsrRoamProfile *pRoamProfile; + eCsrAuthType RSNAuthType; + tSmeConfigParams *sme_config; + uint8_t channel = 0; + bool disable_fw_tdls_state = false; + + ENTER(); + + pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter); + pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + + status = wlan_hdd_validate_context(pHddCtx); + if (status) + goto ret_status; + + if (SIR_MAC_MAX_SSID_LENGTH < ssid_len) { + hdd_err("wrong SSID len"); + status = -EINVAL; + goto ret_status; + } + + if (true == cds_is_connection_in_progress(NULL, NULL)) { + hdd_err("Connection refused: conn in progress"); + status = -EINVAL; + goto ret_status; + } + + disable_fw_tdls_state = true; + wlan_hdd_check_conc_and_update_tdls_state(pHddCtx, + disable_fw_tdls_state); + + pRoamProfile = &pWextState->roamProfile; + qdf_mem_zero(&hdd_sta_ctx->conn_info.conn_flag, + sizeof(hdd_sta_ctx->conn_info.conn_flag)); + + if (pRoamProfile) { + hdd_station_ctx_t *pHddStaCtx; + pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + + /* Restart the opportunistic timer + * + * If hw_mode_change_in_progress is true, then wait + * till firmware sends the callback for hw_mode change. + * + * Else set connect_in_progress as true and proceed. + */ + cds_restart_opportunistic_timer(false); + if (cds_is_hw_mode_change_in_progress()) { + qdf_status = qdf_wait_for_connection_update(); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + hdd_err("qdf wait for event failed!!"); + status = -EINVAL; + goto ret_status; + } + } + cds_set_connection_in_progress(true); + + if (HDD_WMM_USER_MODE_NO_QOS == + (WLAN_HDD_GET_CTX(pAdapter))->config->WmmMode) { + /*QoS not enabled in cfg file */ + pRoamProfile->uapsd_mask = 0; + } else { + /*QoS enabled, update uapsd mask from cfg file */ + pRoamProfile->uapsd_mask = + (WLAN_HDD_GET_CTX(pAdapter))->config->UapsdMask; + } + + pRoamProfile->SSIDs.numOfSSIDs = 1; + pRoamProfile->SSIDs.SSIDList->SSID.length = ssid_len; + qdf_mem_zero(pRoamProfile->SSIDs.SSIDList->SSID.ssId, + sizeof(pRoamProfile->SSIDs.SSIDList->SSID.ssId)); + qdf_mem_copy((void *)(pRoamProfile->SSIDs.SSIDList->SSID.ssId), + ssid, ssid_len); + + pRoamProfile->do_not_roam = !pAdapter->fast_roaming_allowed; + /* cleanup bssid hint */ + qdf_mem_zero(pRoamProfile->bssid_hint.bytes, + QDF_MAC_ADDR_SIZE); + qdf_mem_zero((void *)(pRoamProfile->BSSIDs.bssid), + QDF_MAC_ADDR_SIZE); + + if (bssid) { + pRoamProfile->BSSIDs.numOfBSSIDs = 1; + pRoamProfile->do_not_roam = true; + qdf_mem_copy((void *)(pRoamProfile->BSSIDs.bssid), + bssid, QDF_MAC_ADDR_SIZE); + /* + * Save BSSID in seperate variable as + * pRoamProfile's BSSID is getting zeroed out in the + * association process. In case of join failure + * we should send valid BSSID to supplicant + */ + qdf_mem_copy((void *)(pWextState->req_bssId.bytes), + bssid, QDF_MAC_ADDR_SIZE); + hdd_info("bssid is given by upper layer %pM", bssid); + } else if (bssid_hint) { + qdf_mem_copy(pRoamProfile->bssid_hint.bytes, + bssid_hint, QDF_MAC_ADDR_SIZE); + /* + * Save BSSID in a separate variable as + * pRoamProfile's BSSID is getting zeroed out in the + * association process. In case of join failure + * we should send valid BSSID to supplicant + */ + qdf_mem_copy((void *)(pWextState->req_bssId.bytes), + bssid_hint, QDF_MAC_ADDR_SIZE); + hdd_info("bssid_hint is given by upper layer %pM", + bssid_hint); + } + + hdd_notice("Connect to SSID: %.*s operating Channel: %u", + pRoamProfile->SSIDs.SSIDList->SSID.length, + pRoamProfile->SSIDs.SSIDList->SSID.ssId, + operatingChannel); + + if ((IW_AUTH_WPA_VERSION_WPA == pWextState->wpaVersion) || + (IW_AUTH_WPA_VERSION_WPA2 == pWextState->wpaVersion)) { + hdd_set_genie_to_csr(pAdapter, &RSNAuthType); + hdd_set_csr_auth_type(pAdapter, RSNAuthType); + } +#ifdef FEATURE_WLAN_WAPI + if (pAdapter->wapi_info.nWapiMode) { + hdd_notice("Setting WAPI AUTH Type and Encryption Mode values"); + switch (pAdapter->wapi_info.wapiAuthMode) { + case WAPI_AUTH_MODE_PSK: + { + hdd_notice("WAPI AUTH TYPE: PSK: %d", + pAdapter->wapi_info.wapiAuthMode); + pRoamProfile->AuthType.authType[0] = + eCSR_AUTH_TYPE_WAPI_WAI_PSK; + break; + } + case WAPI_AUTH_MODE_CERT: + { + hdd_notice("WAPI AUTH TYPE: CERT: %d", + pAdapter->wapi_info.wapiAuthMode); + pRoamProfile->AuthType.authType[0] = + eCSR_AUTH_TYPE_WAPI_WAI_CERTIFICATE; + break; + } + } /* End of switch */ + if (pAdapter->wapi_info.wapiAuthMode == + WAPI_AUTH_MODE_PSK + || pAdapter->wapi_info.wapiAuthMode == + WAPI_AUTH_MODE_CERT) { + hdd_notice("WAPI PAIRWISE/GROUP ENCRYPTION: WPI"); + pRoamProfile->AuthType.numEntries = 1; + pRoamProfile->EncryptionType.numEntries = 1; + pRoamProfile->EncryptionType.encryptionType[0] = + eCSR_ENCRYPT_TYPE_WPI; + pRoamProfile->mcEncryptionType.numEntries = 1; + pRoamProfile->mcEncryptionType. + encryptionType[0] = eCSR_ENCRYPT_TYPE_WPI; + } + } +#endif +#ifdef WLAN_FEATURE_GTK_OFFLOAD + /* Initializing gtkOffloadReqParams */ + if ((QDF_STA_MODE == pAdapter->device_mode) || + (QDF_P2P_CLIENT_MODE == pAdapter->device_mode)) { + memset(&pHddStaCtx->gtkOffloadReqParams, 0, + sizeof(tSirGtkOffloadParams)); + pHddStaCtx->gtkOffloadReqParams.ulFlags = + GTK_OFFLOAD_DISABLE; + } +#endif + pRoamProfile->csrPersona = pAdapter->device_mode; + + if (operatingChannel) { + pRoamProfile->ChannelInfo.ChannelList = + &operatingChannel; + pRoamProfile->ChannelInfo.numOfChannels = 1; + } else { + pRoamProfile->ChannelInfo.ChannelList = NULL; + pRoamProfile->ChannelInfo.numOfChannels = 0; + } + if ((QDF_IBSS_MODE == pAdapter->device_mode) + && operatingChannel) { + /* + * Need to post the IBSS power save parameters + * to WMA. WMA will configure this parameters + * to firmware if power save is enabled by the + * firmware. + */ + qdf_status = hdd_set_ibss_power_save_params(pAdapter); + + if (QDF_STATUS_SUCCESS != qdf_status) { + hdd_err("Set IBSS Power Save Params Failed"); + status = -EINVAL; + goto conn_failure; + } + pRoamProfile->ch_params.ch_width = + hdd_map_nl_chan_width(ch_width); + /* + * In IBSS mode while operating in 2.4 GHz, + * the device supports only 20 MHz. + */ + if (CDS_IS_CHANNEL_24GHZ(operatingChannel)) + pRoamProfile->ch_params.ch_width = + CH_WIDTH_20MHZ; + hdd_select_cbmode(pAdapter, operatingChannel, + &pRoamProfile->ch_params); + } + /* + * if MFPEnabled is set but the peer AP is non-PMF i.e 80211w=2 + * or pmf=2 is an explicit configuration in the supplicant + * configuration, drop the connection request. + */ + if (pWextState->roamProfile.MFPEnabled && + !(pWextState->roamProfile.MFPRequired || + pWextState->roamProfile.MFPCapable)) { + hdd_err("Drop connect req as supplicant has indicated PMF req for a non-PMF peer. MFPEnabled %d MFPRequired %d MFPCapable %d", + pWextState->roamProfile.MFPEnabled, + pWextState->roamProfile.MFPRequired, + pWextState->roamProfile.MFPCapable); + status = -EINVAL; + goto conn_failure; + } + + /* + * After 8-way handshake supplicant should give the scan command + * in that it update the additional IEs, But because of scan + * enhancements, the supplicant is not issuing the scan command + * now. So the unicast frames which are sent from the host are + * not having the additional IEs. If it is P2P CLIENT and there + * is no additional IE present in roamProfile, then use the + * addtional IE form scan_info + */ + + if ((pAdapter->device_mode == QDF_P2P_CLIENT_MODE) && + (!pRoamProfile->pAddIEScan)) { + pRoamProfile->pAddIEScan = + &pAdapter->scan_info.scanAddIE.addIEdata[0]; + pRoamProfile->nAddIEScanLength = + pAdapter->scan_info.scanAddIE.length; + } + /* + * When policy manager is enabled from ini file, we shouldn't + * check for other concurrency rules. + */ + if (wma_is_hw_dbs_capable() == false) { + cds_handle_conc_rule1(pAdapter, pRoamProfile); + if (true != cds_handle_conc_rule2( + pAdapter, pRoamProfile, &roamId)) { + status = 0; + goto conn_failure; + } + } + + if ((wma_is_hw_dbs_capable() == true) && + (false == wlan_hdd_handle_sap_sta_dfs_conc(pAdapter, + pRoamProfile))) { + hdd_err("sap-sta conc will fail, can't allow sta"); + hdd_conn_set_connection_state(pAdapter, + eConnectionState_NotConnected); + status = -ENOMEM; + goto conn_failure; + } + + sme_config = qdf_mem_malloc(sizeof(*sme_config)); + if (!sme_config) { + hdd_err("unable to allocate sme_config"); + hdd_conn_set_connection_state(pAdapter, + eConnectionState_NotConnected); + status = -ENOMEM; + goto conn_failure; + } + sme_get_config_param(pHddCtx->hHal, sme_config); + /* These values are not sessionized. So, any change in these SME + * configs on an older or parallel interface will affect the + * cb mode. So, restoring the default INI params before starting + * interfaces such as sta, cli etc., + */ + sme_config->csrConfig.channelBondingMode5GHz = + pHddCtx->config->nChannelBondingMode5GHz; + sme_config->csrConfig.channelBondingMode24GHz = + pHddCtx->config->nChannelBondingMode24GHz; + sme_update_config(pHddCtx->hHal, sme_config); + qdf_mem_free(sme_config); + /* + * Change conn_state to connecting before sme_roam_connect(), + * because sme_roam_connect() has a direct path to call + * hdd_sme_roam_callback(), which will change the conn_state + * If direct path, conn_state will be accordingly changed to + * NotConnected or Associated by either + * hdd_association_completion_handler() or + * hdd_dis_connect_handler() in sme_RoamCallback()if + * sme_RomConnect is to be queued, + * Connecting state will remain until it is completed. + * + * If connection state is not changed, connection state will + * remain in eConnectionState_NotConnected state. + * In hdd_association_completion_handler, "hddDisconInProgress" + * is set to true if conn state is + * eConnectionState_NotConnected. + * If "hddDisconInProgress" is set to true then cfg80211 layer + * is not informed of connect result indication which + * is an issue. + */ + if (QDF_STA_MODE == pAdapter->device_mode || + QDF_P2P_CLIENT_MODE == pAdapter->device_mode) + hdd_conn_set_connection_state(pAdapter, + eConnectionState_Connecting); + + qdf_runtime_pm_prevent_suspend(&pAdapter->connect_rpm_ctx. + connect); + qdf_status = sme_roam_connect(WLAN_HDD_GET_HAL_CTX(pAdapter), + pAdapter->sessionId, pRoamProfile, + &roamId); + if (QDF_IS_STATUS_ERROR(qdf_status)) + status = -EINVAL; + if ((QDF_STATUS_SUCCESS != qdf_status) && + (QDF_STA_MODE == pAdapter->device_mode || + QDF_P2P_CLIENT_MODE == pAdapter->device_mode)) { + hdd_err("sme_roam_connect (session %d) failed with " + "qdf_status %d. -> NotConnected", + pAdapter->sessionId, qdf_status); + /* change back to NotAssociated */ + hdd_conn_set_connection_state(pAdapter, + eConnectionState_NotConnected); + qdf_runtime_pm_allow_suspend(&pAdapter->connect_rpm_ctx. + connect); + } + + /* Reset connect_in_progress */ + cds_set_connection_in_progress(false); + + pRoamProfile->ChannelInfo.ChannelList = NULL; + pRoamProfile->ChannelInfo.numOfChannels = 0; + + if ((QDF_STA_MODE == pAdapter->device_mode) + && wma_is_current_hwmode_dbs()) { + cds_get_channel_from_scan_result(pAdapter, + pRoamProfile, &channel); + if (channel) + cds_checkn_update_hw_mode_single_mac_mode + (channel); + } + + } else { + hdd_err("No valid Roam profile"); + status = -EINVAL; + } + goto ret_status; + +conn_failure: + /* Reset connect_in_progress */ + cds_set_connection_in_progress(false); + +ret_status: + if (disable_fw_tdls_state) + wlan_hdd_check_conc_and_update_tdls_state(pHddCtx, false); + + EXIT(); + return status; +} + +/** + * wlan_hdd_cfg80211_set_auth_type() - set auth type + * @pAdapter: Pointer to adapter + * @auth_type: Auth type + * + * This function is used to set the authentication type (OPEN/SHARED). + * + * Return: 0 for success, non-zero for failure + */ +static int wlan_hdd_cfg80211_set_auth_type(hdd_adapter_t *pAdapter, + enum nl80211_auth_type auth_type) +{ + hdd_wext_state_t *pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter); + hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + + /*set authentication type */ + switch (auth_type) { + case NL80211_AUTHTYPE_AUTOMATIC: + hdd_notice("set authentication type to AUTOSWITCH"); + pHddStaCtx->conn_info.authType = eCSR_AUTH_TYPE_AUTOSWITCH; + break; + + case NL80211_AUTHTYPE_OPEN_SYSTEM: + case NL80211_AUTHTYPE_FT: + hdd_notice("set authentication type to OPEN"); + pHddStaCtx->conn_info.authType = eCSR_AUTH_TYPE_OPEN_SYSTEM; + break; + + case NL80211_AUTHTYPE_SHARED_KEY: + hdd_notice("set authentication type to SHARED"); + pHddStaCtx->conn_info.authType = eCSR_AUTH_TYPE_SHARED_KEY; + break; +#ifdef FEATURE_WLAN_ESE + case NL80211_AUTHTYPE_NETWORK_EAP: + hdd_notice("set authentication type to CCKM WPA"); + pHddStaCtx->conn_info.authType = eCSR_AUTH_TYPE_CCKM_WPA; + break; +#endif + + default: + hdd_err("Unsupported authentication type %d", auth_type); + pHddStaCtx->conn_info.authType = eCSR_AUTH_TYPE_UNKNOWN; + return -EINVAL; + } + + pWextState->roamProfile.AuthType.authType[0] = + pHddStaCtx->conn_info.authType; + return 0; +} + +/** + * wlan_hdd_set_akm_suite() - set key management type + * @pAdapter: Pointer to adapter + * @key_mgmt: Key management type + * + * This function is used to set the key mgmt type(PSK/8021x). + * + * Return: 0 for success, non-zero for failure + */ +static int wlan_hdd_set_akm_suite(hdd_adapter_t *pAdapter, u32 key_mgmt) +{ + hdd_wext_state_t *pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter); + +#define WLAN_AKM_SUITE_8021X_SHA256 0x000FAC05 +#define WLAN_AKM_SUITE_PSK_SHA256 0x000FAC06 + /*set key mgmt type */ + switch (key_mgmt) { + case WLAN_AKM_SUITE_PSK: + case WLAN_AKM_SUITE_PSK_SHA256: + case WLAN_AKM_SUITE_FT_PSK: + hdd_notice("setting key mgmt type to PSK"); + pWextState->authKeyMgmt |= IW_AUTH_KEY_MGMT_PSK; + break; + + case WLAN_AKM_SUITE_8021X_SHA256: + case WLAN_AKM_SUITE_8021X: + case WLAN_AKM_SUITE_FT_8021X: + hdd_notice("setting key mgmt type to 8021x"); + pWextState->authKeyMgmt |= IW_AUTH_KEY_MGMT_802_1X; + break; +#ifdef FEATURE_WLAN_ESE +#define WLAN_AKM_SUITE_CCKM 0x00409600 /* Should be in ieee802_11_defs.h */ +#define IW_AUTH_KEY_MGMT_CCKM 8 /* Should be in linux/wireless.h */ + case WLAN_AKM_SUITE_CCKM: + hdd_notice("setting key mgmt type to CCKM"); + pWextState->authKeyMgmt |= IW_AUTH_KEY_MGMT_CCKM; + break; +#endif +#ifndef WLAN_AKM_SUITE_OSEN +#define WLAN_AKM_SUITE_OSEN 0x506f9a01 /* Should be in ieee802_11_defs.h */ +#endif + case WLAN_AKM_SUITE_OSEN: + hdd_notice("setting key mgmt type to OSEN"); + pWextState->authKeyMgmt |= IW_AUTH_KEY_MGMT_802_1X; + break; + + default: + hdd_err("Unsupported key mgmt type %d", key_mgmt); + return -EINVAL; + + } + return 0; +} + +/** + * wlan_hdd_cfg80211_set_cipher() - set encryption type + * @pAdapter: Pointer to adapter + * @cipher: Cipher type + * @ucast: Unicast flag + * + * This function is used to set the encryption type + * (NONE/WEP40/WEP104/TKIP/CCMP). + * + * Return: 0 for success, non-zero for failure + */ +static int wlan_hdd_cfg80211_set_cipher(hdd_adapter_t *pAdapter, + u32 cipher, bool ucast) +{ + eCsrEncryptionType encryptionType = eCSR_ENCRYPT_TYPE_NONE; + hdd_wext_state_t *pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter); + hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + + if (!cipher) { + hdd_info("received cipher %d - considering none", cipher); + encryptionType = eCSR_ENCRYPT_TYPE_NONE; + } else { + + /*set encryption method */ + switch (cipher) { + case IW_AUTH_CIPHER_NONE: + encryptionType = eCSR_ENCRYPT_TYPE_NONE; + break; + + case WLAN_CIPHER_SUITE_WEP40: + encryptionType = eCSR_ENCRYPT_TYPE_WEP40; + break; + + case WLAN_CIPHER_SUITE_WEP104: + encryptionType = eCSR_ENCRYPT_TYPE_WEP104; + break; + + case WLAN_CIPHER_SUITE_TKIP: + encryptionType = eCSR_ENCRYPT_TYPE_TKIP; + break; + + case WLAN_CIPHER_SUITE_CCMP: + encryptionType = eCSR_ENCRYPT_TYPE_AES; + break; +#ifdef FEATURE_WLAN_WAPI + case WLAN_CIPHER_SUITE_SMS4: + encryptionType = eCSR_ENCRYPT_TYPE_WPI; + break; +#endif + +#ifdef FEATURE_WLAN_ESE + case WLAN_CIPHER_SUITE_KRK: + encryptionType = eCSR_ENCRYPT_TYPE_KRK; + break; +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + case WLAN_CIPHER_SUITE_BTK: + encryptionType = eCSR_ENCRYPT_TYPE_BTK; + break; +#endif +#endif + default: + hdd_err("Unsupported cipher type %d", cipher); + return -EOPNOTSUPP; + } + } + + if (ucast) { + hdd_notice("setting unicast cipher type to %d", encryptionType); + pHddStaCtx->conn_info.ucEncryptionType = encryptionType; + pWextState->roamProfile.EncryptionType.numEntries = 1; + pWextState->roamProfile.EncryptionType.encryptionType[0] = + encryptionType; + } else { + hdd_notice("setting mcast cipher type to %d", encryptionType); + pHddStaCtx->conn_info.mcEncryptionType = encryptionType; + pWextState->roamProfile.mcEncryptionType.numEntries = 1; + pWextState->roamProfile.mcEncryptionType.encryptionType[0] = + encryptionType; + } + + return 0; +} + +/** + * wlan_hdd_add_assoc_ie() - Add Assoc IE to roamProfile + * @wext_state: Pointer to wext state + * @gen_ie: Pointer to IE data + * @len: length of IE data + * + * Return: 0 for success, non-zero for failure + */ +static int wlan_hdd_add_assoc_ie(hdd_wext_state_t *wext_state, + const uint8_t *gen_ie, uint16_t len) +{ + uint16_t cur_add_ie_len = + wext_state->assocAddIE.length; + + if (SIR_MAC_MAX_ADD_IE_LENGTH < + (wext_state->assocAddIE.length + len)) { + hdd_err("Cannot accommodate assocAddIE Need bigger buffer space"); + QDF_ASSERT(0); + return -ENOMEM; + } + memcpy(wext_state->assocAddIE.addIEdata + + cur_add_ie_len, gen_ie, len); + wext_state->assocAddIE.length += len; + + wext_state->roamProfile.pAddIEAssoc = + wext_state->assocAddIE.addIEdata; + wext_state->roamProfile.nAddIEAssocLength = + wext_state->assocAddIE.length; + return 0; +} + +/** + * wlan_hdd_cfg80211_set_ie() - set IEs + * @pAdapter: Pointer to adapter + * @ie: Pointer ot ie + * @ie: IE length + * + * Return: 0 for success, non-zero for failure + */ +static int wlan_hdd_cfg80211_set_ie(hdd_adapter_t *pAdapter, const uint8_t *ie, + size_t ie_len) +{ + hdd_wext_state_t *pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter); + const uint8_t *genie = ie; + uint16_t remLen = ie_len; +#ifdef FEATURE_WLAN_WAPI + uint32_t akmsuite[MAX_NUM_AKM_SUITES]; + u16 *tmp; + uint16_t akmsuiteCount; + int *akmlist; +#endif + int status; + + /* clear previous assocAddIE */ + pWextState->assocAddIE.length = 0; + pWextState->roamProfile.bWPSAssociation = false; + pWextState->roamProfile.bOSENAssociation = false; + + while (remLen >= 2) { + uint16_t eLen = 0; + uint8_t elementId; + elementId = *genie++; + eLen = *genie++; + remLen -= 2; + + /* Sanity check on eLen */ + if (eLen > remLen) { + hdd_err("%s: Invalid IE length[%d] for IE[0x%X]", + __func__, eLen, elementId); + QDF_ASSERT(0); + return -EINVAL; + } + + hdd_notice("IE[0x%X], LEN[%d]", elementId, eLen); + + switch (elementId) { + case DOT11F_EID_WPA: + if (4 > eLen) { /* should have at least OUI which is 4 bytes so extra 2 bytes not needed */ + hdd_err("Invalid WPA IE"); + return -EINVAL; + } else if (0 == + memcmp(&genie[0], "\x00\x50\xf2\x04", 4)) { + uint16_t curAddIELen = + pWextState->assocAddIE.length; + hdd_notice("Set WPS IE(len %d)", eLen + 2); + + if (SIR_MAC_MAX_ADD_IE_LENGTH < + (pWextState->assocAddIE.length + eLen)) { + hdd_err("Cannot accommodate assocAddIE. Need bigger buffer space"); + QDF_ASSERT(0); + return -ENOMEM; + } + /* WSC IE is saved to Additional IE ; it should be accumulated to handle WPS IE + P2P IE */ + memcpy(pWextState->assocAddIE.addIEdata + + curAddIELen, genie - 2, eLen + 2); + pWextState->assocAddIE.length += eLen + 2; + + pWextState->roamProfile.bWPSAssociation = true; + pWextState->roamProfile.pAddIEAssoc = + pWextState->assocAddIE.addIEdata; + pWextState->roamProfile.nAddIEAssocLength = + pWextState->assocAddIE.length; + } else if (0 == memcmp(&genie[0], "\x00\x50\xf2", 3)) { + if (eLen > (MAX_WPA_RSN_IE_LEN - 2)) { + hdd_err("%s: Invalid WPA RSN IE length[%d]", + __func__, eLen); + QDF_ASSERT(0); + return -EINVAL; + } + hdd_notice("Set WPA IE (len %d)", eLen + 2); + memset(pWextState->WPARSNIE, 0, + MAX_WPA_RSN_IE_LEN); + memcpy(pWextState->WPARSNIE, genie - 2, + (eLen + 2)); + pWextState->roamProfile.pWPAReqIE = + pWextState->WPARSNIE; + pWextState->roamProfile.nWPAReqIELength = eLen + 2; /* ie_len; */ + } else if ((0 == memcmp(&genie[0], P2P_OUI_TYPE, + P2P_OUI_TYPE_SIZE))) { + uint16_t curAddIELen = + pWextState->assocAddIE.length; + hdd_notice("Set P2P IE(len %d)", eLen + 2); + + if (SIR_MAC_MAX_ADD_IE_LENGTH < + (pWextState->assocAddIE.length + eLen)) { + hdd_err("Cannot accommodate assocAddIE Need bigger buffer space"); + QDF_ASSERT(0); + return -ENOMEM; + } + /* P2P IE is saved to Additional IE ; it should be accumulated to handle WPS IE + P2P IE */ + memcpy(pWextState->assocAddIE.addIEdata + + curAddIELen, genie - 2, eLen + 2); + pWextState->assocAddIE.length += eLen + 2; + + pWextState->roamProfile.pAddIEAssoc = + pWextState->assocAddIE.addIEdata; + pWextState->roamProfile.nAddIEAssocLength = + pWextState->assocAddIE.length; + } +#ifdef WLAN_FEATURE_WFD + else if ((0 == memcmp(&genie[0], WFD_OUI_TYPE, + WFD_OUI_TYPE_SIZE)) && + /* Consider WFD IE, only for P2P Client */ + (QDF_P2P_CLIENT_MODE == + pAdapter->device_mode)) { + uint16_t curAddIELen = + pWextState->assocAddIE.length; + hdd_notice("Set WFD IE(len %d)", eLen + 2); + + if (SIR_MAC_MAX_ADD_IE_LENGTH < + (pWextState->assocAddIE.length + eLen)) { + hdd_err("Cannot accommodate assocAddIE Need bigger buffer space"); + QDF_ASSERT(0); + return -ENOMEM; + } + /* WFD IE is saved to Additional IE ; it should + * be accumulated to handle WPS IE + P2P IE + + * WFD IE */ + memcpy(pWextState->assocAddIE.addIEdata + + curAddIELen, genie - 2, eLen + 2); + pWextState->assocAddIE.length += eLen + 2; + + pWextState->roamProfile.pAddIEAssoc = + pWextState->assocAddIE.addIEdata; + pWextState->roamProfile.nAddIEAssocLength = + pWextState->assocAddIE.length; + } +#endif + /* Appending HS 2.0 Indication Element in Assiciation Request */ + else if ((0 == memcmp(&genie[0], HS20_OUI_TYPE, + HS20_OUI_TYPE_SIZE))) { + uint16_t curAddIELen = + pWextState->assocAddIE.length; + hdd_notice("Set HS20 IE(len %d)", eLen + 2); + + if (SIR_MAC_MAX_ADD_IE_LENGTH < + (pWextState->assocAddIE.length + eLen)) { + hdd_err("Cannot accommodate assocAddIE Need bigger buffer space"); + QDF_ASSERT(0); + return -ENOMEM; + } + memcpy(pWextState->assocAddIE.addIEdata + + curAddIELen, genie - 2, eLen + 2); + pWextState->assocAddIE.length += eLen + 2; + + pWextState->roamProfile.pAddIEAssoc = + pWextState->assocAddIE.addIEdata; + pWextState->roamProfile.nAddIEAssocLength = + pWextState->assocAddIE.length; + } + /* Appending OSEN Information Element in Assiciation Request */ + else if ((0 == memcmp(&genie[0], OSEN_OUI_TYPE, + OSEN_OUI_TYPE_SIZE))) { + uint16_t curAddIELen = + pWextState->assocAddIE.length; + hdd_notice("Set OSEN IE(len %d)", eLen + 2); + + if (SIR_MAC_MAX_ADD_IE_LENGTH < + (pWextState->assocAddIE.length + eLen)) { + hdd_err("Cannot accommodate assocAddIE Need bigger buffer space"); + QDF_ASSERT(0); + return -ENOMEM; + } + memcpy(pWextState->assocAddIE.addIEdata + + curAddIELen, genie - 2, eLen + 2); + pWextState->assocAddIE.length += eLen + 2; + + pWextState->roamProfile.bOSENAssociation = true; + pWextState->roamProfile.pAddIEAssoc = + pWextState->assocAddIE.addIEdata; + pWextState->roamProfile.nAddIEAssocLength = + pWextState->assocAddIE.length; + } else if ((0 == memcmp(&genie[0], MBO_OUI_TYPE, + MBO_OUI_TYPE_SIZE))){ + hdd_info("Set MBO IE(len %d)", eLen + 2); + status = wlan_hdd_add_assoc_ie(pWextState, + genie - 2, eLen + 2); + if (status) + return status; + } else { + uint16_t add_ie_len = + pWextState->assocAddIE.length; + + hdd_info("Set OSEN IE(len %d)", eLen + 2); + + if (SIR_MAC_MAX_ADD_IE_LENGTH < + (pWextState->assocAddIE.length + eLen)) { + hdd_err("Cannot accommodate assocAddIE Need bigger buffer space"); + QDF_ASSERT(0); + return -ENOMEM; + } + + memcpy(pWextState->assocAddIE.addIEdata + + add_ie_len, genie - 2, eLen + 2); + pWextState->assocAddIE.length += eLen + 2; + + pWextState->roamProfile.pAddIEAssoc = + pWextState->assocAddIE.addIEdata; + pWextState->roamProfile.nAddIEAssocLength = + pWextState->assocAddIE.length; + } + break; + case DOT11F_EID_RSN: + hdd_notice("Set RSN IE(len %d)", eLen + 2); + memset(pWextState->WPARSNIE, 0, MAX_WPA_RSN_IE_LEN); + memcpy(pWextState->WPARSNIE, genie - 2, + (eLen + 2)); + pWextState->roamProfile.pRSNReqIE = + pWextState->WPARSNIE; + pWextState->roamProfile.nRSNReqIELength = eLen + 2; /* ie_len; */ + break; + /* + * Appending Extended Capabilities with Interworking bit set + * in Assoc Req. + * + * In assoc req this EXT Cap will only be taken into account if + * interworkingService bit is set to 1. Currently + * driver is only interested in interworkingService capability + * from supplicant. If in future any other EXT Cap info is + * required from supplicat, it needs to be handled while + * sending Assoc Req in LIM. + */ + case DOT11F_EID_EXTCAP: + { + uint16_t curAddIELen = + pWextState->assocAddIE.length; + hdd_notice("Set Extended CAPS IE(len %d)", eLen + 2); + + if (SIR_MAC_MAX_ADD_IE_LENGTH < + (pWextState->assocAddIE.length + eLen)) { + hdd_err("Cannot accommodate assocAddIE Need bigger buffer space"); + QDF_ASSERT(0); + return -ENOMEM; + } + memcpy(pWextState->assocAddIE.addIEdata + + curAddIELen, genie - 2, eLen + 2); + pWextState->assocAddIE.length += eLen + 2; + + pWextState->roamProfile.pAddIEAssoc = + pWextState->assocAddIE.addIEdata; + pWextState->roamProfile.nAddIEAssocLength = + pWextState->assocAddIE.length; + break; + } +#ifdef FEATURE_WLAN_WAPI + case WLAN_EID_WAPI: + /* Setting WAPI Mode to ON=1 */ + pAdapter->wapi_info.nWapiMode = 1; + hdd_notice("WAPI MODE IS %u", pAdapter->wapi_info.nWapiMode); + tmp = (u16 *) ie; + tmp = tmp + 2; /* Skip element Id and Len, Version */ + akmsuiteCount = WPA_GET_LE16(tmp); + tmp = tmp + 1; + akmlist = (int *)(tmp); + if (akmsuiteCount <= MAX_NUM_AKM_SUITES) { + memcpy(akmsuite, akmlist, (4 * akmsuiteCount)); + } else { + hdd_err("Invalid akmSuite count"); + QDF_ASSERT(0); + return -EINVAL; + } + + if (WAPI_PSK_AKM_SUITE == akmsuite[0]) { + hdd_notice("WAPI AUTH MODE SET TO PSK"); + pAdapter->wapi_info.wapiAuthMode = + WAPI_AUTH_MODE_PSK; + } + if (WAPI_CERT_AKM_SUITE == akmsuite[0]) { + hdd_notice("WAPI AUTH MODE SET TO CERTIFICATE"); + pAdapter->wapi_info.wapiAuthMode = + WAPI_AUTH_MODE_CERT; + } + break; +#endif + case DOT11F_EID_SUPPOPERATINGCLASSES: + { + hdd_info("Set Supported Operating Classes IE(len %d)", eLen + 2); + status = wlan_hdd_add_assoc_ie(pWextState, + genie - 2, eLen + 2); + if (status) + return status; + break; + } + default: + hdd_err("Set UNKNOWN IE %X", elementId); + /* when Unknown IE is received we should break and continue + * to the next IE in the buffer instead we were returning + * so changing this to break */ + break; + } + genie += eLen; + remLen -= eLen; + } + return 0; +} + +/** + * hdd_is_wpaie_present() - check for WPA ie + * @ie: Pointer to ie + * @ie_len: Ie length + * + * Parse the received IE to find the WPA IE + * + * Return: true if wpa ie is found else false + */ +static bool hdd_is_wpaie_present(const uint8_t *ie, uint8_t ie_len) +{ + uint8_t eLen = 0; + uint16_t remLen = ie_len; + uint8_t elementId = 0; + + while (remLen >= 2) { + elementId = *ie++; + eLen = *ie++; + remLen -= 2; + if (eLen > remLen) { + hdd_err("IE length is wrong %d", eLen); + return false; + } + if ((elementId == DOT11F_EID_WPA) && (remLen > 5)) { + /* OUI - 0x00 0X50 0XF2 + * WPA Information Element - 0x01 + * WPA version - 0x01 + */ + if (0 == memcmp(&ie[0], "\x00\x50\xf2\x01\x01", 5)) + return true; + } + ie += eLen; + remLen -= eLen; + } + return false; +} + +/** + * wlan_hdd_cfg80211_set_privacy() - set security parameters during connection + * @pAdapter: Pointer to adapter + * @req: Pointer to security parameters + * + * Return: 0 for success, non-zero for failure + */ +static int wlan_hdd_cfg80211_set_privacy(hdd_adapter_t *pAdapter, + struct cfg80211_connect_params *req) +{ + int status = 0; + hdd_wext_state_t *pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter); + ENTER(); + + /*set wpa version */ + pWextState->wpaVersion = IW_AUTH_WPA_VERSION_DISABLED; + + if (req->crypto.wpa_versions) { + if (NL80211_WPA_VERSION_1 == req->crypto.wpa_versions) { + pWextState->wpaVersion = IW_AUTH_WPA_VERSION_WPA; + } else if (NL80211_WPA_VERSION_2 == req->crypto.wpa_versions) { + pWextState->wpaVersion = IW_AUTH_WPA_VERSION_WPA2; + } + } + + hdd_notice("set wpa version to %d", pWextState->wpaVersion); + + /*set authentication type */ + status = wlan_hdd_cfg80211_set_auth_type(pAdapter, req->auth_type); + + if (0 > status) { + hdd_err("failed to set authentication type "); + return status; + } + + /*set key mgmt type */ + if (req->crypto.n_akm_suites) { + status = + wlan_hdd_set_akm_suite(pAdapter, req->crypto.akm_suites[0]); + if (0 > status) { + hdd_err("failed to set akm suite"); + return status; + } + } + + /*set pairwise cipher type */ + if (req->crypto.n_ciphers_pairwise) { + status = wlan_hdd_cfg80211_set_cipher(pAdapter, + req->crypto. + ciphers_pairwise[0], + true); + if (0 > status) { + hdd_err("failed to set unicast cipher type"); + return status; + } + } else { + /*Reset previous cipher suite to none */ + status = wlan_hdd_cfg80211_set_cipher(pAdapter, 0, true); + if (0 > status) { + hdd_err("failed to set unicast cipher type"); + return status; + } + } + + /*set group cipher type */ + status = + wlan_hdd_cfg80211_set_cipher(pAdapter, req->crypto.cipher_group, + false); + + if (0 > status) { + hdd_err("failed to set mcast cipher type"); + return status; + } +#ifdef WLAN_FEATURE_11W + pWextState->roamProfile.MFPEnabled = (req->mfp == NL80211_MFP_REQUIRED); +#endif + + /*parse WPA/RSN IE, and set the correspoing fileds in Roam profile */ + if (req->ie_len) { + status = + wlan_hdd_cfg80211_set_ie(pAdapter, req->ie, req->ie_len); + if (0 > status) { + hdd_err("failed to parse the WPA/RSN IE"); + return status; + } + } + + /*incase of WEP set default key information */ + if (req->key && req->key_len) { + if ((WLAN_CIPHER_SUITE_WEP40 == req->crypto.ciphers_pairwise[0]) + || (WLAN_CIPHER_SUITE_WEP104 == + req->crypto.ciphers_pairwise[0]) + ) { + if (IW_AUTH_KEY_MGMT_802_1X + == + (pWextState-> + authKeyMgmt & IW_AUTH_KEY_MGMT_802_1X)) { + hdd_err("Dynamic WEP not supported"); + return -EOPNOTSUPP; + } else { + u8 key_len = req->key_len; + u8 key_idx = req->key_idx; + + if ((eCSR_SECURITY_WEP_KEYSIZE_MAX_BYTES >= + key_len) + && (CSR_MAX_NUM_KEY > key_idx) + ) { + hdd_notice("setting default wep key, key_idx = %hu key_len %hu", + key_idx, key_len); + qdf_mem_copy(&pWextState->roamProfile. + Keys. + KeyMaterial[key_idx][0], + req->key, key_len); + pWextState->roamProfile.Keys. + KeyLength[key_idx] = (u8) key_len; + pWextState->roamProfile.Keys. + defaultIndex = (u8) key_idx; + } + } + } + } + + return status; +} + +int wlan_hdd_try_disconnect(hdd_adapter_t *pAdapter) +{ + unsigned long rc; + hdd_station_ctx_t *pHddStaCtx; + int status, result = 0; + tHalHandle hal; + + pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + hal = WLAN_HDD_GET_HAL_CTX(pAdapter); + if (pAdapter->device_mode == QDF_STA_MODE) { + hdd_notice("Stop firmware roaming"); + sme_stop_roaming(hal, pAdapter->sessionId, eCsrForcedDisassoc); + + /* + * If firmware has already started roaming process, driver + * needs to wait for processing of this disconnect request. + * + */ + INIT_COMPLETION(pAdapter->roaming_comp_var); + if (hdd_is_roaming_in_progress(pAdapter)) { + rc = wait_for_completion_timeout( + &pAdapter->roaming_comp_var, + msecs_to_jiffies(WLAN_WAIT_TIME_STOP_ROAM)); + if (!rc) { + hdd_err("roaming comp var timed out session Id: %d", + pAdapter->sessionId); + } + if (pAdapter->roam_ho_fail) { + INIT_COMPLETION(pAdapter->disconnect_comp_var); + hdd_conn_set_connection_state(pAdapter, + eConnectionState_Disconnecting); + } + } + } + + if ((QDF_IBSS_MODE == pAdapter->device_mode) || + (eConnectionState_Associated == pHddStaCtx->conn_info.connState) || + (eConnectionState_Connecting == pHddStaCtx->conn_info.connState) || + (eConnectionState_IbssConnected == pHddStaCtx->conn_info.connState)) { + hdd_conn_set_connection_state(pAdapter, + eConnectionState_Disconnecting); + /* Issue disconnect to CSR */ + INIT_COMPLETION(pAdapter->disconnect_comp_var); + + status = sme_roam_disconnect(WLAN_HDD_GET_HAL_CTX(pAdapter), + pAdapter->sessionId, + eCSR_DISCONNECT_REASON_UNSPECIFIED); + /* + * Wait here instead of returning directly, this will block the + * next connect command and allow processing of the scan for + * ssid and the previous connect command in CSR. Else we might + * hit some race conditions leading to SME and HDD out of sync. + */ + if (QDF_STATUS_CMD_NOT_QUEUED == status) { + hdd_info("Already disconnected or connect was in sme/roam pending list and removed by disconnect"); + } else if (0 != status) { + hdd_err("csrRoamDisconnect failure, returned %d", + (int)status); + pHddStaCtx->staDebugState = status; + result = -EINVAL; + goto disconnected; + } + + rc = wait_for_completion_timeout( + &pAdapter->disconnect_comp_var, + msecs_to_jiffies(WLAN_WAIT_TIME_DISCONNECT)); + if (!rc && (QDF_STATUS_CMD_NOT_QUEUED != status)) { + hdd_err("Sme disconnect event timed out session Id %d staDebugState %d", + pAdapter->sessionId, pHddStaCtx->staDebugState); + result = -ETIMEDOUT; + } + } else if (eConnectionState_Disconnecting == + pHddStaCtx->conn_info.connState) { + rc = wait_for_completion_timeout(&pAdapter->disconnect_comp_var, + msecs_to_jiffies(WLAN_WAIT_TIME_DISCONNECT)); + if (!rc) { + hdd_err("Disconnect event timed out session Id %d staDebugState %d", + pAdapter->sessionId, pHddStaCtx->staDebugState); + result = -ETIMEDOUT; + } + } +disconnected: + hdd_conn_set_connection_state(pAdapter, eConnectionState_NotConnected); + return result; +} + +/** + * wlan_hdd_reassoc_bssid_hint() - Start reassociation if bssid is present + * @adapter: Pointer to the HDD adapter + * @req: Pointer to the structure cfg_connect_params receieved from user space + * @status: out variable for status of reassoc request + * + * This function will start reassociation if prev_bssid is set and bssid/ + * bssid_hint, channel/channel_hint parameters are present in connect request. + * + * Return: true if connect was for ReAssociation, false otherwise + */ +#if defined(CFG80211_CONNECT_PREV_BSSID) || \ + (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 7, 0)) +static bool wlan_hdd_reassoc_bssid_hint(hdd_adapter_t *adapter, + struct cfg80211_connect_params *req, + int *status) +{ + bool reassoc = false; + const uint8_t *bssid = NULL; + uint16_t channel = 0; + hdd_wext_state_t *wext_state = WLAN_HDD_GET_WEXT_STATE_PTR(adapter); + + if (req->bssid) + bssid = req->bssid; + else if (req->bssid_hint) + bssid = req->bssid_hint; + + if (req->channel) + channel = req->channel->hw_value; + else if (req->channel_hint) + channel = req->channel_hint->hw_value; + + if (bssid && channel && req->prev_bssid) { + reassoc = true; + hdd_info(FL("REASSOC Attempt on channel %d to "MAC_ADDRESS_STR), + channel, MAC_ADDR_ARRAY(bssid)); + /* + * Save BSSID in a separate variable as + * pRoamProfile's BSSID is getting zeroed out in the + * association process. In case of join failure + * we should send valid BSSID to supplicant + */ + qdf_mem_copy(wext_state->req_bssId.bytes, bssid, + QDF_MAC_ADDR_SIZE); + + *status = hdd_reassoc(adapter, bssid, channel, + CONNECT_CMD_USERSPACE); + hdd_debug("hdd_reassoc: status: %d", *status); + } + return reassoc; +} +#else +static bool wlan_hdd_reassoc_bssid_hint(hdd_adapter_t *adapter, + struct cfg80211_connect_params *req, + int *status) +{ + return false; +} +#endif + +/** + * __wlan_hdd_cfg80211_connect() - cfg80211 connect api + * @wiphy: Pointer to wiphy + * @dev: Pointer to network device + * @req: Pointer to cfg80211 connect request + * + * This function is used to start the association process + * + * Return: 0 for success, non-zero for failure + */ +static int __wlan_hdd_cfg80211_connect(struct wiphy *wiphy, + struct net_device *ndev, + struct cfg80211_connect_params *req) +{ + int status; + u16 channel; + const u8 *bssid = NULL; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0)) + const u8 *bssid_hint = req->bssid_hint; +#else + const u8 *bssid_hint = NULL; +#endif + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(ndev); + hdd_context_t *pHddCtx; + + ENTER(); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_warn("Command not allowed in FTM mode"); + return -EINVAL; + } + + if (wlan_hdd_validate_session_id(pAdapter->sessionId)) { + hdd_err("invalid session id: %d", pAdapter->sessionId); + return -EINVAL; + } + + MTRACE(qdf_trace(QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_CFG80211_CONNECT, + pAdapter->sessionId, pAdapter->device_mode)); + hdd_notice("Device_mode %s(%d)", + hdd_device_mode_to_string(pAdapter->device_mode), + pAdapter->device_mode); + + if (pAdapter->device_mode != QDF_STA_MODE && + pAdapter->device_mode != QDF_P2P_CLIENT_MODE) { + hdd_err("Device_mode %s(%d) is not supported", + hdd_device_mode_to_string(pAdapter->device_mode), + pAdapter->device_mode); + return -EINVAL; + } + + pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + if (!pHddCtx) { + hdd_err("HDD context is null"); + return -EINVAL; + } + + status = wlan_hdd_validate_context(pHddCtx); + if (0 != status) + return status; + + if (req->bssid) + bssid = req->bssid; + else if (bssid_hint) + bssid = bssid_hint; + + if (bssid && hdd_get_adapter_by_macaddr(pHddCtx, (uint8_t *)bssid)) { + hdd_err("adapter exist with same mac address " MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(bssid)); + return -EINVAL; + } + + if (true == wlan_hdd_reassoc_bssid_hint(pAdapter, req, &status)) + return status; + + /* Try disconnecting if already in connected state */ + status = wlan_hdd_try_disconnect(pAdapter); + if (0 > status) { + hdd_err("Failed to disconnect the existing connection"); + return -EALREADY; + } + + /* Check for max concurrent connections after doing disconnect if any */ + if (req->channel) { + if (!cds_allow_concurrency( + cds_convert_device_mode_to_qdf_type( + pAdapter->device_mode), + req->channel->hw_value, HW_MODE_20_MHZ)) { + hdd_err("This concurrency combination is not allowed"); + return -ECONNREFUSED; + } + } else { + if (!cds_allow_concurrency( + cds_convert_device_mode_to_qdf_type( + pAdapter->device_mode), 0, HW_MODE_20_MHZ)) { + hdd_err("This concurrency combination is not allowed"); + return -ECONNREFUSED; + } + } + + /*initialise security parameters */ + status = wlan_hdd_cfg80211_set_privacy(pAdapter, req); + + if (0 > status) { + hdd_err("failed to set security params"); + return status; + } + + if (req->channel) + channel = req->channel->hw_value; + else + channel = 0; + status = wlan_hdd_cfg80211_connect_start(pAdapter, req->ssid, + req->ssid_len, req->bssid, + bssid_hint, channel, 0); + if (0 > status) { + hdd_err("connect failed"); + return status; + } + EXIT(); + return status; +} + +/** + * wlan_hdd_cfg80211_connect() - cfg80211 connect api + * @wiphy: Pointer to wiphy + * @dev: Pointer to network device + * @req: Pointer to cfg80211 connect request + * + * Return: 0 for success, non-zero for failure + */ +static int wlan_hdd_cfg80211_connect(struct wiphy *wiphy, + struct net_device *ndev, + struct cfg80211_connect_params *req) +{ + int ret; + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_connect(wiphy, ndev, req); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * wlan_hdd_disconnect() - hdd disconnect api + * @pAdapter: Pointer to adapter + * @reason: Disconnect reason code + * + * This function is used to issue a disconnect request to SME + * + * Return: 0 for success, non-zero for failure + */ +static int wlan_hdd_disconnect(hdd_adapter_t *pAdapter, u16 reason) +{ + int status, result = 0; + unsigned long rc; + hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + eConnectionState prev_conn_state; + tHalHandle hal = WLAN_HDD_GET_HAL_CTX(pAdapter); + + ENTER(); + + status = wlan_hdd_validate_context(pHddCtx); + + if (0 != status) + return status; + if (pAdapter->device_mode == QDF_STA_MODE) { + hdd_notice("Stop firmware roaming"); + status = sme_stop_roaming(hal, pAdapter->sessionId, + eCsrForcedDisassoc); + /* + * If firmware has already started roaming process, driver + * needs to wait for processing of this disconnect request. + * + */ + INIT_COMPLETION(pAdapter->roaming_comp_var); + if (hdd_is_roaming_in_progress(pAdapter)) { + rc = wait_for_completion_timeout( + &pAdapter->roaming_comp_var, + msecs_to_jiffies(WLAN_WAIT_TIME_STOP_ROAM)); + if (!rc) { + hdd_err("roaming comp var timed out session Id: %d", + pAdapter->sessionId); + } + if (pAdapter->roam_ho_fail) { + INIT_COMPLETION(pAdapter->disconnect_comp_var); + hdd_notice("Disabling queues"); + wlan_hdd_netif_queue_control(pAdapter, + WLAN_STOP_ALL_NETIF_QUEUE_N_CARRIER, + WLAN_CONTROL_PATH); + hdd_conn_set_connection_state(pAdapter, + eConnectionState_Disconnecting); + goto wait_for_disconnect; + } + } + } + + prev_conn_state = pHddStaCtx->conn_info.connState; + /*stop tx queues */ + hdd_notice("Disabling queues"); + wlan_hdd_netif_queue_control(pAdapter, + WLAN_STOP_ALL_NETIF_QUEUE_N_CARRIER, + WLAN_CONTROL_PATH); + hdd_notice("Set HDD connState to eConnectionState_Disconnecting"); + pHddStaCtx->conn_info.connState = eConnectionState_Disconnecting; + + + INIT_COMPLETION(pAdapter->disconnect_comp_var); + + /* issue disconnect */ + + status = sme_roam_disconnect(WLAN_HDD_GET_HAL_CTX(pAdapter), + pAdapter->sessionId, reason); + if ((QDF_STATUS_CMD_NOT_QUEUED == status) && + prev_conn_state != eConnectionState_Connecting) { + hdd_notice("status = %d, already disconnected", status); + result = 0; + goto disconnected; + } else if (QDF_STATUS_CMD_NOT_QUEUED == status) { + /* + * Wait here instead of returning directly, this will block the + * next connect command and allow processing of the scan for + * ssid and the previous connect command in CSR. Else we might + * hit some race conditions leading to SME and HDD out of sync. + */ + hdd_info("Already disconnected or connect was in sme/roam pending list and removed by disconnect"); + } else if (0 != status) { + hdd_err("csr_roam_disconnect failure, returned %d", + (int)status); + pHddStaCtx->staDebugState = status; + result = -EINVAL; + goto disconnected; + } +wait_for_disconnect: + rc = wait_for_completion_timeout(&pAdapter->disconnect_comp_var, + msecs_to_jiffies + (WLAN_WAIT_TIME_DISCONNECT)); + + if (!rc && (QDF_STATUS_CMD_NOT_QUEUED != status)) { + hdd_err("Failed to disconnect, timed out"); + result = -ETIMEDOUT; + } +disconnected: + hdd_conn_set_connection_state(pAdapter, eConnectionState_NotConnected); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0) + /* Sending disconnect event to userspace for kernel version < 3.11 + * is handled by __cfg80211_disconnect call to __cfg80211_disconnected + */ + hdd_notice("Send disconnected event to userspace"); + wlan_hdd_cfg80211_indicate_disconnect(pAdapter->dev, true, + WLAN_REASON_UNSPECIFIED); +#endif + + return result; +} + +/** + * hdd_ieee80211_reason_code_to_str() - return string conversion of reason code + * @reason: ieee80211 reason code. + * + * This utility function helps log string conversion of reason code. + * + * Return: string conversion of reason code, if match found; + * "Unknown" otherwise. + */ +static const char *hdd_ieee80211_reason_code_to_str(uint16_t reason) +{ + switch (reason) { + CASE_RETURN_STRING(WLAN_REASON_UNSPECIFIED); + CASE_RETURN_STRING(WLAN_REASON_PREV_AUTH_NOT_VALID); + CASE_RETURN_STRING(WLAN_REASON_DEAUTH_LEAVING); + CASE_RETURN_STRING(WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY); + CASE_RETURN_STRING(WLAN_REASON_DISASSOC_AP_BUSY); + CASE_RETURN_STRING(WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA); + CASE_RETURN_STRING(WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA); + CASE_RETURN_STRING(WLAN_REASON_DISASSOC_STA_HAS_LEFT); + CASE_RETURN_STRING(WLAN_REASON_STA_REQ_ASSOC_WITHOUT_AUTH); + CASE_RETURN_STRING(WLAN_REASON_DISASSOC_BAD_POWER); + CASE_RETURN_STRING(WLAN_REASON_DISASSOC_BAD_SUPP_CHAN); + CASE_RETURN_STRING(WLAN_REASON_INVALID_IE); + CASE_RETURN_STRING(WLAN_REASON_MIC_FAILURE); + CASE_RETURN_STRING(WLAN_REASON_4WAY_HANDSHAKE_TIMEOUT); + CASE_RETURN_STRING(WLAN_REASON_GROUP_KEY_HANDSHAKE_TIMEOUT); + CASE_RETURN_STRING(WLAN_REASON_IE_DIFFERENT); + CASE_RETURN_STRING(WLAN_REASON_INVALID_GROUP_CIPHER); + CASE_RETURN_STRING(WLAN_REASON_INVALID_PAIRWISE_CIPHER); + CASE_RETURN_STRING(WLAN_REASON_INVALID_AKMP); + CASE_RETURN_STRING(WLAN_REASON_UNSUPP_RSN_VERSION); + CASE_RETURN_STRING(WLAN_REASON_INVALID_RSN_IE_CAP); + CASE_RETURN_STRING(WLAN_REASON_IEEE8021X_FAILED); + CASE_RETURN_STRING(WLAN_REASON_CIPHER_SUITE_REJECTED); + CASE_RETURN_STRING(WLAN_REASON_DISASSOC_UNSPECIFIED_QOS); + CASE_RETURN_STRING(WLAN_REASON_DISASSOC_QAP_NO_BANDWIDTH); + CASE_RETURN_STRING(WLAN_REASON_DISASSOC_LOW_ACK); + CASE_RETURN_STRING(WLAN_REASON_DISASSOC_QAP_EXCEED_TXOP); + CASE_RETURN_STRING(WLAN_REASON_QSTA_LEAVE_QBSS); + CASE_RETURN_STRING(WLAN_REASON_QSTA_NOT_USE); + CASE_RETURN_STRING(WLAN_REASON_QSTA_REQUIRE_SETUP); + CASE_RETURN_STRING(WLAN_REASON_QSTA_TIMEOUT); + CASE_RETURN_STRING(WLAN_REASON_QSTA_CIPHER_NOT_SUPP); + CASE_RETURN_STRING(WLAN_REASON_MESH_PEER_CANCELED); + CASE_RETURN_STRING(WLAN_REASON_MESH_MAX_PEERS); + CASE_RETURN_STRING(WLAN_REASON_MESH_CONFIG); + CASE_RETURN_STRING(WLAN_REASON_MESH_CLOSE); + CASE_RETURN_STRING(WLAN_REASON_MESH_MAX_RETRIES); + CASE_RETURN_STRING(WLAN_REASON_MESH_CONFIRM_TIMEOUT); + CASE_RETURN_STRING(WLAN_REASON_MESH_INVALID_GTK); + CASE_RETURN_STRING(WLAN_REASON_MESH_INCONSISTENT_PARAM); + CASE_RETURN_STRING(WLAN_REASON_MESH_INVALID_SECURITY); + CASE_RETURN_STRING(WLAN_REASON_MESH_PATH_ERROR); + CASE_RETURN_STRING(WLAN_REASON_MESH_PATH_NOFORWARD); + CASE_RETURN_STRING(WLAN_REASON_MESH_PATH_DEST_UNREACHABLE); + CASE_RETURN_STRING(WLAN_REASON_MAC_EXISTS_IN_MBSS); + CASE_RETURN_STRING(WLAN_REASON_MESH_CHAN_REGULATORY); + CASE_RETURN_STRING(WLAN_REASON_MESH_CHAN); + default: + return "Unknown"; + } +} + +/** + * __wlan_hdd_cfg80211_disconnect() - cfg80211 disconnect api + * @wiphy: Pointer to wiphy + * @dev: Pointer to network device + * @reason: Disconnect reason code + * + * This function is used to issue a disconnect request to SME + * + * Return: 0 for success, non-zero for failure + */ +static int __wlan_hdd_cfg80211_disconnect(struct wiphy *wiphy, + struct net_device *dev, u16 reason) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + int status; + hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); +#ifdef FEATURE_WLAN_TDLS + uint8_t staIdx; +#endif + + ENTER(); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_warn("Command not allowed in FTM mode"); + return -EINVAL; + } + + if (wlan_hdd_validate_session_id(pAdapter->sessionId)) { + hdd_err("invalid session id: %d", pAdapter->sessionId); + return -EINVAL; + } + + MTRACE(qdf_trace(QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_CFG80211_DISCONNECT, + pAdapter->sessionId, reason)); + hdd_notice("Device_mode %s(%d) reason code(%d)", + hdd_device_mode_to_string(pAdapter->device_mode), + pAdapter->device_mode, reason); + + status = wlan_hdd_validate_context(pHddCtx); + + if (0 != status) + return status; + + /* Issue disconnect request to SME, if station is in connected state */ + if ((pHddStaCtx->conn_info.connState == eConnectionState_Associated) || + (pHddStaCtx->conn_info.connState == eConnectionState_Connecting)) { + eCsrRoamDisconnectReason reasonCode = + eCSR_DISCONNECT_REASON_UNSPECIFIED; + hdd_scaninfo_t *pScanInfo; + + switch (reason) { + case WLAN_REASON_MIC_FAILURE: + reasonCode = eCSR_DISCONNECT_REASON_MIC_ERROR; + break; + + case WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY: + case WLAN_REASON_DISASSOC_AP_BUSY: + case WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA: + reasonCode = eCSR_DISCONNECT_REASON_DISASSOC; + break; + + case WLAN_REASON_PREV_AUTH_NOT_VALID: + case WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA: + reasonCode = eCSR_DISCONNECT_REASON_DEAUTH; + break; + + case WLAN_REASON_DEAUTH_LEAVING: + reasonCode = + pHddCtx->config-> + gEnableDeauthToDisassocMap ? + eCSR_DISCONNECT_REASON_STA_HAS_LEFT : + eCSR_DISCONNECT_REASON_DEAUTH; + break; + case WLAN_REASON_DISASSOC_STA_HAS_LEFT: + reasonCode = eCSR_DISCONNECT_REASON_STA_HAS_LEFT; + break; + default: + reasonCode = eCSR_DISCONNECT_REASON_UNSPECIFIED; + break; + } + hdd_notice("convert to internal reason %d to reasonCode %d", + reason, reasonCode); + pScanInfo = &pAdapter->scan_info; + if (pScanInfo->mScanPending) { + hdd_notice("Disconnect is in progress, Aborting Scan"); + hdd_abort_mac_scan(pHddCtx, pAdapter->sessionId, + INVALID_SCAN_ID, + eCSR_SCAN_ABORT_DEFAULT); + } + wlan_hdd_cleanup_remain_on_channel_ctx(pAdapter); +#ifdef FEATURE_WLAN_TDLS + /* First clean up the tdls peers if any */ + for (staIdx = 0; staIdx < pHddCtx->max_num_tdls_sta; staIdx++) { + if ((pHddCtx->tdlsConnInfo[staIdx].sessionId == + pAdapter->sessionId) + && (pHddCtx->tdlsConnInfo[staIdx].staId)) { + uint8_t *mac; + mac = + pHddCtx->tdlsConnInfo[staIdx].peerMac.bytes; + hdd_notice("call sme_delete_tdls_peer_sta staId %d sessionId %d " + MAC_ADDRESS_STR, + pHddCtx->tdlsConnInfo[staIdx].staId, + pAdapter->sessionId, + MAC_ADDR_ARRAY(mac)); + sme_delete_tdls_peer_sta(WLAN_HDD_GET_HAL_CTX + (pAdapter), + pAdapter->sessionId, mac); + } + } +#endif + hdd_notice("Disconnecting with reasoncode:%u", + reasonCode); + hdd_info("Disconnect request from user space with reason: %s", + hdd_ieee80211_reason_code_to_str(reason)); + status = wlan_hdd_disconnect(pAdapter, reasonCode); + if (0 != status) { + hdd_err("failure, returned %d", status); + return -EINVAL; + } + } else { + hdd_err("unexpected cfg disconnect called while in state (%d)", + pHddStaCtx->conn_info.connState); + } + + return status; +} + +/** + * wlan_hdd_cfg80211_disconnect() - cfg80211 disconnect api + * @wiphy: Pointer to wiphy + * @dev: Pointer to network device + * @reason: Disconnect reason code + * + * Return: 0 for success, non-zero for failure + */ +static int wlan_hdd_cfg80211_disconnect(struct wiphy *wiphy, + struct net_device *dev, u16 reason) +{ + int ret; + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_disconnect(wiphy, dev, reason); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * wlan_hdd_cfg80211_set_privacy_ibss() - set ibss privacy + * @pAdapter: Pointer to adapter + * @param: Pointer to IBSS parameters + * + * This function is used to initialize the security settings in IBSS mode + * + * Return: 0 for success, non-zero for failure + */ +static int wlan_hdd_cfg80211_set_privacy_ibss(hdd_adapter_t *pAdapter, + struct cfg80211_ibss_params + *params) +{ + int status = 0; + hdd_wext_state_t *pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter); + eCsrEncryptionType encryptionType = eCSR_ENCRYPT_TYPE_NONE; + hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + + ENTER(); + + pWextState->wpaVersion = IW_AUTH_WPA_VERSION_DISABLED; + qdf_mem_zero(&pHddStaCtx->ibss_enc_key, sizeof(tCsrRoamSetKey)); + pHddStaCtx->ibss_enc_key_installed = 0; + + if (params->ie_len && (NULL != params->ie)) { + if (wlan_hdd_cfg80211_get_ie_ptr(params->ie, + params->ie_len, WLAN_EID_RSN)) { + pWextState->wpaVersion = IW_AUTH_WPA_VERSION_WPA2; + encryptionType = eCSR_ENCRYPT_TYPE_AES; + } else if (hdd_is_wpaie_present(params->ie, params->ie_len)) { + tDot11fIEWPA dot11WPAIE; + tHalHandle halHandle = WLAN_HDD_GET_HAL_CTX(pAdapter); + u8 *ie; + + memset(&dot11WPAIE, 0, sizeof(dot11WPAIE)); + ie = wlan_hdd_cfg80211_get_ie_ptr(params->ie, + params->ie_len, + DOT11F_EID_WPA); + if (NULL != ie) { + pWextState->wpaVersion = + IW_AUTH_WPA_VERSION_WPA; + /* Unpack the WPA IE */ + /* Skip past the EID byte and length byte - and four byte WiFi OUI */ + dot11f_unpack_ie_wpa((tpAniSirGlobal) halHandle, + &ie[2 + 4], + ie[1] - 4, &dot11WPAIE); + /*Extract the multicast cipher, the encType for unicast + cipher for wpa-none is none */ + encryptionType = + hdd_translate_wpa_to_csr_encryption_type + (dot11WPAIE.multicast_cipher); + } + } + + status = + wlan_hdd_cfg80211_set_ie(pAdapter, params->ie, + params->ie_len); + + if (0 > status) { + hdd_err("failed to parse WPA/RSN IE"); + return status; + } + } + + pWextState->roamProfile.AuthType.authType[0] = + pHddStaCtx->conn_info.authType = eCSR_AUTH_TYPE_OPEN_SYSTEM; + + if (params->privacy) { + /* Security enabled IBSS, At this time there is no information + * available about the security paramters, so initialise the + * encryption type to eCSR_ENCRYPT_TYPE_WEP40_STATICKEY. + * The correct security parameters will be updated later in + * wlan_hdd_cfg80211_add_key Hal expects encryption type to be + * set inorder enable privacy bit in beacons + */ + + encryptionType = eCSR_ENCRYPT_TYPE_WEP40_STATICKEY; + } + hdd_info("encryptionType=%d", encryptionType); + pHddStaCtx->conn_info.ucEncryptionType = encryptionType; + pWextState->roamProfile.EncryptionType.numEntries = 1; + pWextState->roamProfile.EncryptionType.encryptionType[0] = + encryptionType; + return status; +} + +/** + * __wlan_hdd_cfg80211_join_ibss() - join ibss + * @wiphy: Pointer to wiphy + * @dev: Pointer to network device + * @param: Pointer to IBSS join parameters + * + * This function is used to create/join an IBSS network + * + * Return: 0 for success, non-zero for failure + */ +static int __wlan_hdd_cfg80211_join_ibss(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_ibss_params *params) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_wext_state_t *pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter); + tCsrRoamProfile *pRoamProfile; + int status; + hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + struct qdf_mac_addr bssid; + u8 channelNum = 0; + + ENTER(); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_warn("Command not allowed in FTM mode"); + return -EINVAL; + } + + if (wlan_hdd_validate_session_id(pAdapter->sessionId)) { + hdd_err("invalid session id: %d", pAdapter->sessionId); + return -EINVAL; + } + + MTRACE(qdf_trace(QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_CFG80211_JOIN_IBSS, + pAdapter->sessionId, pAdapter->device_mode)); + hdd_notice("Device_mode %s(%d)", + hdd_device_mode_to_string(pAdapter->device_mode), + pAdapter->device_mode); + + status = wlan_hdd_validate_context(pHddCtx); + + if (0 != status) + return status; + + if (NULL != + params->chandef.chan) { + uint32_t numChans = WNI_CFG_VALID_CHANNEL_LIST_LEN; + uint8_t validChan[WNI_CFG_VALID_CHANNEL_LIST_LEN]; + tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter); + int indx; + + /* Get channel number */ + channelNum = ieee80211_frequency_to_channel( + params-> + chandef. + chan-> + center_freq); + + if (0 != sme_cfg_get_str(hHal, WNI_CFG_VALID_CHANNEL_LIST, + validChan, &numChans)) { + hdd_err("No valid channel list"); + return -EOPNOTSUPP; + } + + for (indx = 0; indx < numChans; indx++) { + if (channelNum == validChan[indx]) { + break; + } + } + if (indx >= numChans) { + hdd_err("Not valid Channel %d", channelNum); + return -EINVAL; + } + } + + if (!cds_allow_concurrency(CDS_IBSS_MODE, channelNum, + HW_MODE_20_MHZ)) { + hdd_err("This concurrency combination is not allowed"); + return -ECONNREFUSED; + } + + status = qdf_reset_connection_update(); + if (!QDF_IS_STATUS_SUCCESS(status)) + hdd_err("ERR: clear event failed"); + + status = cds_current_connections_update(pAdapter->sessionId, + channelNum, + SIR_UPDATE_REASON_JOIN_IBSS); + if (QDF_STATUS_E_FAILURE == status) { + hdd_err("ERROR: connections update failed!!"); + return -EINVAL; + } + + if (QDF_STATUS_SUCCESS == status) { + status = qdf_wait_for_connection_update(); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("ERROR: qdf wait for event failed!!"); + return -EINVAL; + } + } + + /*Try disconnecting if already in connected state */ + status = wlan_hdd_try_disconnect(pAdapter); + if (0 > status) { + hdd_err("Failed to disconnect the existing IBSS connection"); + return -EALREADY; + } + + pRoamProfile = &pWextState->roamProfile; + + if (eCSR_BSS_TYPE_START_IBSS != pRoamProfile->BSSType) { + hdd_err("Interface type is not set to IBSS"); + return -EINVAL; + } + + /* enable selected protection checks in IBSS mode */ + pRoamProfile->cfg_protection = IBSS_CFG_PROTECTION_ENABLE_MASK; + + if (QDF_STATUS_E_FAILURE == sme_cfg_set_int(pHddCtx->hHal, + WNI_CFG_IBSS_ATIM_WIN_SIZE, + pHddCtx->config-> + ibssATIMWinSize)) { + hdd_err("Could not pass on WNI_CFG_IBSS_ATIM_WIN_SIZE to CCM"); + } + + /* BSSID is provided by upper layers hence no need to AUTO generate */ + if (NULL != params->bssid) { + if (sme_cfg_set_int(pHddCtx->hHal, WNI_CFG_IBSS_AUTO_BSSID, 0) + == QDF_STATUS_E_FAILURE) { + hdd_err("ccmCfgStInt failed for WNI_CFG_IBSS_AUTO_BSSID"); + return -EIO; + } + qdf_mem_copy(bssid.bytes, params->bssid, QDF_MAC_ADDR_SIZE); + } else if (pHddCtx->config->isCoalesingInIBSSAllowed == 0) { + if (sme_cfg_set_int(pHddCtx->hHal, WNI_CFG_IBSS_AUTO_BSSID, 0) + == QDF_STATUS_E_FAILURE) { + hdd_err("ccmCfgStInt failed for WNI_CFG_IBSS_AUTO_BSSID"); + return -EIO; + } + qdf_copy_macaddr(&bssid, &pHddCtx->config->IbssBssid); + } + if ((params->beacon_interval > CFG_BEACON_INTERVAL_MIN) + && (params->beacon_interval <= CFG_BEACON_INTERVAL_MAX)) + pRoamProfile->beaconInterval = params->beacon_interval; + else { + pRoamProfile->beaconInterval = CFG_BEACON_INTERVAL_DEFAULT; + hdd_info("input beacon interval %d TU is invalid, use default %d TU", + params->beacon_interval, pRoamProfile->beaconInterval); + } + + /* Set Channel */ + if (channelNum) { + /* Set the Operational Channel */ + hdd_info("set channel %d", channelNum); + pRoamProfile->ChannelInfo.numOfChannels = 1; + pHddStaCtx->conn_info.operationChannel = channelNum; + pRoamProfile->ChannelInfo.ChannelList = + &pHddStaCtx->conn_info.operationChannel; + } + + /* Initialize security parameters */ + status = wlan_hdd_cfg80211_set_privacy_ibss(pAdapter, params); + if (status < 0) { + hdd_err("failed to set security parameters"); + return status; + } + + /* Issue connect start */ + status = wlan_hdd_cfg80211_connect_start(pAdapter, params->ssid, + params->ssid_len, + bssid.bytes, NULL, + pHddStaCtx->conn_info. + operationChannel, + params->chandef.width); + + if (0 > status) { + hdd_err("connect failed"); + return status; + } + EXIT(); + return 0; +} + +/** + * wlan_hdd_cfg80211_join_ibss() - join ibss + * @wiphy: Pointer to wiphy + * @dev: Pointer to network device + * @param: Pointer to IBSS join parameters + * + * This function is used to create/join an IBSS network + * + * Return: 0 for success, non-zero for failure + */ +static int wlan_hdd_cfg80211_join_ibss(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_ibss_params *params) +{ + int ret = 0; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_join_ibss(wiphy, dev, params); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __wlan_hdd_cfg80211_leave_ibss() - leave ibss + * @wiphy: Pointer to wiphy + * @dev: Pointer to network device + * + * This function is used to leave an IBSS network + * + * Return: 0 for success, non-zero for failure + */ +static int __wlan_hdd_cfg80211_leave_ibss(struct wiphy *wiphy, + struct net_device *dev) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_wext_state_t *pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter); + tCsrRoamProfile *pRoamProfile; + hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + int status; + QDF_STATUS hal_status; + unsigned long rc; + tSirUpdateIE updateIE; + + ENTER(); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_warn("Command not allowed in FTM mode"); + return -EINVAL; + } + + if (wlan_hdd_validate_session_id(pAdapter->sessionId)) { + hdd_err("invalid session id: %d", pAdapter->sessionId); + return -EINVAL; + } + + MTRACE(qdf_trace(QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_CFG80211_LEAVE_IBSS, + pAdapter->sessionId, + eCSR_DISCONNECT_REASON_IBSS_LEAVE)); + status = wlan_hdd_validate_context(pHddCtx); + if (0 != status) + return status; + + hdd_notice("Device_mode %s(%d)", + hdd_device_mode_to_string(pAdapter->device_mode), + pAdapter->device_mode); + if (NULL == pWextState) { + hdd_err("Data Storage Corruption"); + return -EIO; + } + + pRoamProfile = &pWextState->roamProfile; + + /* Issue disconnect only if interface type is set to IBSS */ + if (eCSR_BSS_TYPE_START_IBSS != pRoamProfile->BSSType) { + hdd_err("BSS Type is not set to IBSS"); + return -EINVAL; + } + /* Clearing add IE of beacon */ + qdf_mem_copy(updateIE.bssid.bytes, pAdapter->macAddressCurrent.bytes, + sizeof(tSirMacAddr)); + updateIE.smeSessionId = pAdapter->sessionId; + updateIE.ieBufferlength = 0; + updateIE.pAdditionIEBuffer = NULL; + updateIE.append = true; + updateIE.notify = true; + if (sme_update_add_ie(WLAN_HDD_GET_HAL_CTX(pAdapter), + &updateIE, + eUPDATE_IE_PROBE_BCN) == QDF_STATUS_E_FAILURE) { + hdd_err("Could not pass on PROBE_RSP_BCN data to PE"); + } + + /* Reset WNI_CFG_PROBE_RSP Flags */ + wlan_hdd_reset_prob_rspies(pAdapter); + + /* Issue Disconnect request */ + INIT_COMPLETION(pAdapter->disconnect_comp_var); + hal_status = sme_roam_disconnect(WLAN_HDD_GET_HAL_CTX(pAdapter), + pAdapter->sessionId, + eCSR_DISCONNECT_REASON_IBSS_LEAVE); + if (!QDF_IS_STATUS_SUCCESS(hal_status)) { + hdd_err("sme_roam_disconnect failed hal_status(%d)", + hal_status); + return -EAGAIN; + } + + /* wait for mc thread to cleanup and then return to upper stack + * so by the time upper layer calls the change interface, we are + * all set to proceed further + */ + rc = wait_for_completion_timeout(&pAdapter->disconnect_comp_var, + msecs_to_jiffies(WLAN_WAIT_TIME_DISCONNECT)); + if (!rc) { + hdd_err("Failed to disconnect, timed out"); + return -ETIMEDOUT; + } + + EXIT(); + return 0; +} + +/** + * wlan_hdd_cfg80211_leave_ibss() - leave ibss + * @wiphy: Pointer to wiphy + * @dev: Pointer to network device + * + * This function is used to leave an IBSS network + * + * Return: 0 for success, non-zero for failure + */ +static int wlan_hdd_cfg80211_leave_ibss(struct wiphy *wiphy, + struct net_device *dev) +{ + int ret = 0; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_leave_ibss(wiphy, dev); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __wlan_hdd_cfg80211_set_wiphy_params() - set wiphy parameters + * @wiphy: Pointer to wiphy + * @changed: Parameters changed + * + * This function is used to set the phy parameters. RTS Threshold/FRAG + * Threshold/Retry Count etc. + * + * Return: 0 for success, non-zero for failure + */ +static int __wlan_hdd_cfg80211_set_wiphy_params(struct wiphy *wiphy, + u32 changed) +{ + hdd_context_t *pHddCtx = wiphy_priv(wiphy); + tHalHandle hHal = pHddCtx->hHal; + int status; + + ENTER(); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_warn("Command not allowed in FTM mode"); + return -EINVAL; + } + + MTRACE(qdf_trace(QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_CFG80211_SET_WIPHY_PARAMS, + NO_SESSION, wiphy->rts_threshold)); + status = wlan_hdd_validate_context(pHddCtx); + + if (0 != status) + return status; + + if (changed & WIPHY_PARAM_RTS_THRESHOLD) { + u32 rts_threshold = (wiphy->rts_threshold == -1) ? + WNI_CFG_RTS_THRESHOLD_STAMAX : wiphy->rts_threshold; + + if ((WNI_CFG_RTS_THRESHOLD_STAMIN > rts_threshold) || + (WNI_CFG_RTS_THRESHOLD_STAMAX < rts_threshold)) { + hdd_err("Invalid RTS Threshold value %u", + rts_threshold); + return -EINVAL; + } + + if (0 != sme_cfg_set_int(hHal, WNI_CFG_RTS_THRESHOLD, + rts_threshold)) { + hdd_err("sme_cfg_set_int failed for rts_threshold value %u", + rts_threshold); + return -EIO; + } + + hdd_info("set rts threshold %u", rts_threshold); + } + + if (changed & WIPHY_PARAM_FRAG_THRESHOLD) { + u16 frag_threshold = (wiphy->frag_threshold == -1) ? + WNI_CFG_FRAGMENTATION_THRESHOLD_STAMAX : + wiphy->frag_threshold; + + if ((WNI_CFG_FRAGMENTATION_THRESHOLD_STAMIN > frag_threshold) || + (WNI_CFG_FRAGMENTATION_THRESHOLD_STAMAX < frag_threshold)) { + hdd_err("Invalid frag_threshold value %hu", + frag_threshold); + return -EINVAL; + } + + if (0 != sme_cfg_set_int(hHal, WNI_CFG_FRAGMENTATION_THRESHOLD, + frag_threshold)) { + hdd_err("sme_cfg_set_int failed for frag_threshold value %hu", + frag_threshold); + return -EIO; + } + + hdd_info("set frag threshold %hu", frag_threshold); + } + + if ((changed & WIPHY_PARAM_RETRY_SHORT) + || (changed & WIPHY_PARAM_RETRY_LONG)) { + u8 retry_value = (changed & WIPHY_PARAM_RETRY_SHORT) ? + wiphy->retry_short : wiphy->retry_long; + + if ((WNI_CFG_LONG_RETRY_LIMIT_STAMIN > retry_value) || + (WNI_CFG_LONG_RETRY_LIMIT_STAMAX < retry_value)) { + hdd_err("Invalid Retry count %hu", retry_value); + return -EINVAL; + } + + if (changed & WIPHY_PARAM_RETRY_SHORT) { + if (0 != sme_cfg_set_int(hHal, + WNI_CFG_LONG_RETRY_LIMIT, + retry_value)) { + hdd_err("sme_cfg_set_int failed for long retry count %hu", + retry_value); + return -EIO; + } + hdd_info("set long retry count %hu", retry_value); + } else if (changed & WIPHY_PARAM_RETRY_SHORT) { + if (0 != sme_cfg_set_int(hHal, + WNI_CFG_SHORT_RETRY_LIMIT, + retry_value)) { + hdd_err("sme_cfg_set_int failed for short retry count %hu", + retry_value); + return -EIO; + } + hdd_info("set short retry count %hu", retry_value); + } + } + EXIT(); + return 0; +} + +/** + * wlan_hdd_cfg80211_set_wiphy_params() - set wiphy parameters + * @wiphy: Pointer to wiphy + * @changed: Parameters changed + * + * Return: 0 for success, non-zero for failure + */ +static int wlan_hdd_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_set_wiphy_params(wiphy, changed); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __wlan_hdd_set_default_mgmt_key() - dummy implementation of set default mgmt + * key + * @wiphy: Pointer to wiphy + * @dev: Pointer to network device + * @key_index: Key index + * + * Return: 0 + */ +static int __wlan_hdd_set_default_mgmt_key(struct wiphy *wiphy, + struct net_device *netdev, + u8 key_index) +{ + ENTER(); + return 0; +} + +/** + * wlan_hdd_set_default_mgmt_key() - SSR wrapper for + * wlan_hdd_set_default_mgmt_key + * @wiphy: pointer to wiphy + * @netdev: pointer to net_device structure + * @key_index: key index + * + * Return: 0 on success, error number on failure + */ +static int wlan_hdd_set_default_mgmt_key(struct wiphy *wiphy, + struct net_device *netdev, + u8 key_index) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_set_default_mgmt_key(wiphy, netdev, key_index); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __wlan_hdd_set_txq_params() - dummy implementation of set tx queue params + * @wiphy: Pointer to wiphy + * @dev: Pointer to network device + * @params: Pointer to tx queue parameters + * + * Return: 0 + */ +static int __wlan_hdd_set_txq_params(struct wiphy *wiphy, + struct net_device *dev, + struct ieee80211_txq_params *params) +{ + ENTER(); + return 0; +} + +/** + * wlan_hdd_set_txq_params() - SSR wrapper for wlan_hdd_set_txq_params + * @wiphy: pointer to wiphy + * @netdev: pointer to net_device structure + * @params: pointer to ieee80211_txq_params + * + * Return: 0 on success, error number on failure + */ +static int wlan_hdd_set_txq_params(struct wiphy *wiphy, + struct net_device *dev, + struct ieee80211_txq_params *params) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_set_txq_params(wiphy, dev, params); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __wlan_hdd_cfg80211_del_station() - delete station v2 + * @wiphy: Pointer to wiphy + * @param: Pointer to delete station parameter + * + * Return: 0 for success, non-zero for failure + */ +static +int __wlan_hdd_cfg80211_del_station(struct wiphy *wiphy, + struct net_device *dev, + struct tagCsrDelStaParams *pDelStaParams) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *pHddCtx; + QDF_STATUS qdf_status = QDF_STATUS_E_FAILURE; + hdd_hostapd_state_t *hapd_state; + int status; + uint8_t staId; + uint8_t *mac; + + ENTER(); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_warn("Command not allowed in FTM mode"); + return -EINVAL; + } + + if (wlan_hdd_validate_session_id(pAdapter->sessionId)) { + hdd_err("invalid session id: %d", pAdapter->sessionId); + return -EINVAL; + } + + MTRACE(qdf_trace(QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_CFG80211_DEL_STA, + pAdapter->sessionId, pAdapter->device_mode)); + + pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + status = wlan_hdd_validate_context(pHddCtx); + + if (0 != status) + return status; + + mac = (uint8_t *) pDelStaParams->peerMacAddr.bytes; + + if ((QDF_SAP_MODE == pAdapter->device_mode) || + (QDF_P2P_GO_MODE == pAdapter->device_mode)) { + + hapd_state = WLAN_HDD_GET_HOSTAP_STATE_PTR(pAdapter); + if (!hapd_state) { + hdd_err("Hostapd State is Null"); + return 0; + } + + if (qdf_is_macaddr_broadcast((struct qdf_mac_addr *) mac)) { + uint16_t i; + for (i = 0; i < WLAN_MAX_STA_COUNT; i++) { + if ((pAdapter->aStaInfo[i].isUsed) && + (!pAdapter->aStaInfo[i]. + isDeauthInProgress)) { + qdf_mem_copy( + mac, + pAdapter->aStaInfo[i]. + macAddrSTA.bytes, + QDF_MAC_ADDR_SIZE); + hdd_notice("Delete STA with MAC::" + MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(mac)); + + if (pHddCtx->dev_dfs_cac_status == + DFS_CAC_IN_PROGRESS) + goto fn_end; + + qdf_event_reset(&hapd_state->qdf_sta_disassoc_event); + hdd_softap_sta_disassoc(pAdapter, + pDelStaParams); + qdf_status = + hdd_softap_sta_deauth(pAdapter, + pDelStaParams); + if (QDF_IS_STATUS_SUCCESS(qdf_status)) { + pAdapter->aStaInfo[i]. + isDeauthInProgress = true; + qdf_status = + qdf_wait_single_event( + &hapd_state-> + qdf_sta_disassoc_event, + SME_CMD_TIMEOUT_VALUE); + if (!QDF_IS_STATUS_SUCCESS( + qdf_status)) + hdd_err("Deauth wait time expired"); + } + } + } + } else { + qdf_status = + hdd_softap_get_sta_id(pAdapter, + (struct qdf_mac_addr *) mac, + &staId); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + hdd_notice("Skip DEL STA as this is not used::" + MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(mac)); + return -ENOENT; + } + + if (pAdapter->aStaInfo[staId].isDeauthInProgress == + true) { + hdd_notice("Skip DEL STA as deauth is in progress::" + MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(mac)); + return -ENOENT; + } + + pAdapter->aStaInfo[staId].isDeauthInProgress = true; + + hdd_notice("Delete STA with MAC::" MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(mac)); + + /* Case: SAP in ACS selected DFS ch and client connected + * Now Radar detected. Then if random channel is another + * DFS ch then new CAC is initiated and no TX allowed. + * So do not send any mgmt frames as it will timeout + * during CAC. + */ + + if (pHddCtx->dev_dfs_cac_status == DFS_CAC_IN_PROGRESS) + goto fn_end; + + qdf_event_reset(&hapd_state->qdf_sta_disassoc_event); + sme_send_disassoc_req_frame(WLAN_HDD_GET_HAL_CTX + (pAdapter), pAdapter->sessionId, + (uint8_t *)&pDelStaParams->peerMacAddr, + pDelStaParams->reason_code, 0); + qdf_status = hdd_softap_sta_deauth(pAdapter, + pDelStaParams); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + pAdapter->aStaInfo[staId].isDeauthInProgress = + false; + hdd_notice("STA removal failed for ::" + MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(mac)); + return -ENOENT; + } else { + qdf_status = qdf_wait_single_event( + &hapd_state-> + qdf_sta_disassoc_event, + SME_CMD_TIMEOUT_VALUE); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) + hdd_err("Deauth wait time expired"); + } + } + } + +fn_end: + EXIT(); + return 0; +} + +#if defined(USE_CFG80211_DEL_STA_V2) +/** + * wlan_hdd_del_station() - delete station wrapper + * @adapter: pointer to the hdd adapter + * + * Return: None + */ +void wlan_hdd_del_station(hdd_adapter_t *adapter) +{ + struct station_del_parameters del_sta; + del_sta.mac = NULL; + del_sta.subtype = SIR_MAC_MGMT_DEAUTH >> 4; + del_sta.reason_code = eCsrForcedDeauthSta; + + wlan_hdd_cfg80211_del_station(adapter->wdev.wiphy, adapter->dev, + &del_sta); +} +#else +void wlan_hdd_del_station(hdd_adapter_t *adapter) +{ + wlan_hdd_cfg80211_del_station(adapter->wdev.wiphy, adapter->dev, NULL); +} +#endif + +#if defined(USE_CFG80211_DEL_STA_V2) +/** + * wlan_hdd_cfg80211_del_station() - delete station v2 + * @wiphy: Pointer to wiphy + * @param: Pointer to delete station parameter + * + * Return: 0 for success, non-zero for failure + */ +int wlan_hdd_cfg80211_del_station(struct wiphy *wiphy, + struct net_device *dev, + struct station_del_parameters *param) +#else +/** + * wlan_hdd_cfg80211_del_station() - delete station + * @wiphy: Pointer to wiphy + * @mac: Pointer to station mac address + * + * Return: 0 for success, non-zero for failure + */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)) +int wlan_hdd_cfg80211_del_station(struct wiphy *wiphy, + struct net_device *dev, + const uint8_t *mac) +#else +int wlan_hdd_cfg80211_del_station(struct wiphy *wiphy, + struct net_device *dev, + uint8_t *mac) +#endif +#endif +{ + int ret; + struct tagCsrDelStaParams delStaParams; + + cds_ssr_protect(__func__); +#if defined(USE_CFG80211_DEL_STA_V2) + if (NULL == param) { + hdd_err("Invalid argument passed"); + return -EINVAL; + } + wlansap_populate_del_sta_params(param->mac, param->reason_code, + param->subtype, &delStaParams); +#else + wlansap_populate_del_sta_params(mac, eSIR_MAC_DEAUTH_LEAVING_BSS_REASON, + (SIR_MAC_MGMT_DEAUTH >> 4), + &delStaParams); +#endif + ret = __wlan_hdd_cfg80211_del_station(wiphy, dev, &delStaParams); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __wlan_hdd_cfg80211_add_station() - add station + * @wiphy: Pointer to wiphy + * @mac: Pointer to station mac address + * @pmksa: Pointer to add station parameter + * + * Return: 0 for success, non-zero for failure + */ +static int __wlan_hdd_cfg80211_add_station(struct wiphy *wiphy, + struct net_device *dev, + const uint8_t *mac, + struct station_parameters *params) +{ + int status = -EPERM; +#ifdef FEATURE_WLAN_TDLS + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *pHddCtx = wiphy_priv(wiphy); + u32 mask, set; + + ENTER(); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_warn("Command not allowed in FTM mode"); + return -EINVAL; + } + + if (wlan_hdd_validate_session_id(pAdapter->sessionId)) { + hdd_err("invalid session id: %d", pAdapter->sessionId); + return -EINVAL; + } + + MTRACE(qdf_trace(QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_CFG80211_ADD_STA, + pAdapter->sessionId, params->listen_interval)); + + if (0 != wlan_hdd_validate_context(pHddCtx)) + return -EINVAL; + + mask = params->sta_flags_mask; + + set = params->sta_flags_set; + + hdd_notice("mask 0x%x set 0x%x " MAC_ADDRESS_STR, mask, set, + MAC_ADDR_ARRAY(mac)); + + if (mask & BIT(NL80211_STA_FLAG_TDLS_PEER)) { + if (set & BIT(NL80211_STA_FLAG_TDLS_PEER)) { + status = + wlan_hdd_tdls_add_station(wiphy, dev, mac, 0, NULL); + } + } +#endif + EXIT(); + return status; +} + +/** + * wlan_hdd_cfg80211_add_station() - add station + * @wiphy: Pointer to wiphy + * @mac: Pointer to station mac address + * @pmksa: Pointer to add station parameter + * + * Return: 0 for success, non-zero for failure + */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)) +static int wlan_hdd_cfg80211_add_station(struct wiphy *wiphy, + struct net_device *dev, + const uint8_t *mac, + struct station_parameters *params) +#else +static int wlan_hdd_cfg80211_add_station(struct wiphy *wiphy, + struct net_device *dev, uint8_t *mac, + struct station_parameters *params) +#endif +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_add_station(wiphy, dev, mac, params); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __wlan_hdd_cfg80211_set_pmksa() - set pmksa + * @wiphy: Pointer to wiphy + * @dev: Pointer to network device + * @pmksa: Pointer to set pmksa parameter + * + * Return: 0 for success, non-zero for failure + */ +static int __wlan_hdd_cfg80211_set_pmksa(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_pmksa *pmksa) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + tHalHandle halHandle; + QDF_STATUS result = QDF_STATUS_SUCCESS; + int status; + tPmkidCacheInfo pmk_id; + + ENTER(); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_warn("Command not allowed in FTM mode"); + return -EINVAL; + } + + if (wlan_hdd_validate_session_id(pAdapter->sessionId)) { + hdd_err("invalid session id: %d", pAdapter->sessionId); + return -EINVAL; + } + + if (!pmksa) { + hdd_err("pmksa is NULL"); + return -EINVAL; + } + + if (!pmksa->bssid || !pmksa->pmkid) { + hdd_err("pmksa->bssid(%p) or pmksa->pmkid(%p) is NULL", + pmksa->bssid, pmksa->pmkid); + return -EINVAL; + } + + hdd_warn("set PMKSA for " MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(pmksa->bssid)); + + status = wlan_hdd_validate_context(pHddCtx); + + if (0 != status) + return status; + + halHandle = WLAN_HDD_GET_HAL_CTX(pAdapter); + + qdf_mem_copy(pmk_id.BSSID.bytes, pmksa->bssid, QDF_MAC_ADDR_SIZE); + qdf_mem_copy(pmk_id.PMKID, pmksa->pmkid, CSR_RSN_PMKID_SIZE); + + /* Add to the PMKSA ID Cache in CSR */ + result = sme_roam_set_pmkid_cache(halHandle, pAdapter->sessionId, + &pmk_id, 1, false); + + MTRACE(qdf_trace(QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_CFG80211_SET_PMKSA, + pAdapter->sessionId, result)); + + EXIT(); + return QDF_IS_STATUS_SUCCESS(result) ? 0 : -EINVAL; +} + +/** + * wlan_hdd_cfg80211_set_pmksa() - set pmksa + * @wiphy: Pointer to wiphy + * @dev: Pointer to network device + * @pmksa: Pointer to set pmksa parameter + * + * Return: 0 for success, non-zero for failure + */ +static int wlan_hdd_cfg80211_set_pmksa(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_pmksa *pmksa) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_set_pmksa(wiphy, dev, pmksa); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __wlan_hdd_cfg80211_del_pmksa() - delete pmksa + * @wiphy: Pointer to wiphy + * @dev: Pointer to network device + * @pmksa: Pointer to pmksa parameter + * + * Return: 0 for success, non-zero for failure + */ +static int __wlan_hdd_cfg80211_del_pmksa(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_pmksa *pmksa) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + tHalHandle halHandle; + int status = 0; + + ENTER(); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_warn("Command not allowed in FTM mode"); + return -EINVAL; + } + + if (wlan_hdd_validate_session_id(pAdapter->sessionId)) { + hdd_err("invalid session id: %d", pAdapter->sessionId); + return -EINVAL; + } + + if (!pmksa) { + hdd_err("pmksa is NULL"); + return -EINVAL; + } + + if (!pmksa->bssid) { + hdd_err("pmksa->bssid is NULL"); + return -EINVAL; + } + + hdd_debug("Deleting PMKSA for " MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(pmksa->bssid)); + + status = wlan_hdd_validate_context(pHddCtx); + + if (0 != status) + return status; + + halHandle = WLAN_HDD_GET_HAL_CTX(pAdapter); + + MTRACE(qdf_trace(QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_CFG80211_DEL_PMKSA, + pAdapter->sessionId, 0)); + /* Delete the PMKID CSR cache */ + if (QDF_STATUS_SUCCESS != + sme_roam_del_pmkid_from_cache(halHandle, + pAdapter->sessionId, pmksa->bssid, + false)) { + hdd_err("Failed to delete PMKSA for " MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(pmksa->bssid)); + status = -EINVAL; + } + EXIT(); + return status; +} + +/** + * wlan_hdd_cfg80211_del_pmksa() - delete pmksa + * @wiphy: Pointer to wiphy + * @dev: Pointer to network device + * @pmksa: Pointer to pmksa parameter + * + * Return: 0 for success, non-zero for failure + */ +static int wlan_hdd_cfg80211_del_pmksa(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_pmksa *pmksa) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_del_pmksa(wiphy, dev, pmksa); + cds_ssr_unprotect(__func__); + + return ret; + +} + +/** + * __wlan_hdd_cfg80211_flush_pmksa() - flush pmksa + * @wiphy: Pointer to wiphy + * @dev: Pointer to network device + * + * Return: 0 for success, non-zero for failure + */ +static int __wlan_hdd_cfg80211_flush_pmksa(struct wiphy *wiphy, + struct net_device *dev) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + tHalHandle halHandle; + int status = 0; + + ENTER(); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_warn("Command not allowed in FTM mode"); + return -EINVAL; + } + + if (wlan_hdd_validate_session_id(pAdapter->sessionId)) { + hdd_err("invalid session id: %d", pAdapter->sessionId); + return -EINVAL; + } + + hdd_warn("Flushing PMKSA"); + + pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + status = wlan_hdd_validate_context(pHddCtx); + + if (0 != status) + return status; + + /* Retrieve halHandle */ + halHandle = WLAN_HDD_GET_HAL_CTX(pAdapter); + + /* Flush the PMKID cache in CSR */ + if (QDF_STATUS_SUCCESS != + sme_roam_del_pmkid_from_cache(halHandle, pAdapter->sessionId, NULL, + true)) { + hdd_err("Cannot flush PMKIDCache"); + status = -EINVAL; + } + EXIT(); + return status; +} + +/** + * wlan_hdd_cfg80211_flush_pmksa() - flush pmksa + * @wiphy: Pointer to wiphy + * @dev: Pointer to network device + * + * Return: 0 for success, non-zero for failure + */ +static int wlan_hdd_cfg80211_flush_pmksa(struct wiphy *wiphy, + struct net_device *dev) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_flush_pmksa(wiphy, dev); + cds_ssr_unprotect(__func__); + + return ret; +} + +#if defined(KERNEL_SUPPORT_11R_CFG80211) +/** + * __wlan_hdd_cfg80211_update_ft_ies() - update fast transition ies + * @wiphy: Pointer to wiphy + * @dev: Pointer to network device + * @ftie: Pointer to fast transition ie parameter + * + * Return: 0 for success, non-zero for failure + */ +static int +__wlan_hdd_cfg80211_update_ft_ies(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_update_ft_ies_params *ftie) +{ + hdd_context_t *hdd_ctx = wiphy_priv(wiphy); + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + int status; + + ENTER(); + + status = wlan_hdd_validate_context(hdd_ctx); + if (status) + return status; + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_warn("Command not allowed in FTM mode"); + return -EINVAL; + } + + if (wlan_hdd_validate_session_id(pAdapter->sessionId)) { + hdd_err("invalid session id: %d", pAdapter->sessionId); + return -EINVAL; + } + + MTRACE(qdf_trace(QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_CFG80211_UPDATE_FT_IES, + pAdapter->sessionId, pHddStaCtx->conn_info.connState)); + /* Added for debug on reception of Re-assoc Req. */ + if (eConnectionState_Associated != pHddStaCtx->conn_info.connState) { + hdd_err("Called with Ie of length = %zu when not associated", + ftie->ie_len); + hdd_err("Should be Re-assoc Req IEs"); + } + hdd_notice("%s called with Ie of length = %zu", __func__, + ftie->ie_len); + + /* Pass the received FT IEs to SME */ + sme_set_ft_ies(WLAN_HDD_GET_HAL_CTX(pAdapter), pAdapter->sessionId, + (const u8 *)ftie->ie, ftie->ie_len); + EXIT(); + return 0; +} + +/** + * wlan_hdd_cfg80211_update_ft_ies() - update fast transition ies + * @wiphy: Pointer to wiphy + * @dev: Pointer to network device + * @ftie: Pointer to fast transition ie parameter + * + * Return: 0 for success, non-zero for failure + */ +static int +wlan_hdd_cfg80211_update_ft_ies(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_update_ft_ies_params *ftie) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_update_ft_ies(wiphy, dev, ftie); + cds_ssr_unprotect(__func__); + + return ret; +} +#endif + +#ifdef WLAN_FEATURE_GTK_OFFLOAD +/** + * wlan_hdd_cfg80211_update_replay_counter_callback() - replay counter callback + * @callbackContext: Callback context + * @pGtkOffloadGetInfoRsp: Pointer to gtk offload response parameter + * + * Callback rountine called upon receiving response for get offload info + * + * Return: none + */ +void wlan_hdd_cfg80211_update_replay_counter_callback(void *callbackContext, + tpSirGtkOffloadGetInfoRspParams + pGtkOffloadGetInfoRsp) +{ + hdd_adapter_t *pAdapter = (hdd_adapter_t *) callbackContext; + uint8_t tempReplayCounter[8]; + hdd_station_ctx_t *pHddStaCtx; + + ENTER(); + + if (NULL == pAdapter) { + hdd_err("HDD adapter is Null"); + return; + } + + if (NULL == pGtkOffloadGetInfoRsp) { + hdd_err("pGtkOffloadGetInfoRsp is Null"); + return; + } + + if (QDF_STATUS_SUCCESS != pGtkOffloadGetInfoRsp->ulStatus) { + hdd_err("wlan Failed to get replay counter value"); + return; + } + + pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + /* Update replay counter */ + pHddStaCtx->gtkOffloadReqParams.ullKeyReplayCounter = + pGtkOffloadGetInfoRsp->ullKeyReplayCounter; + + { + /* changing from little to big endian since supplicant + * works on big endian format + */ + int i; + uint8_t *p = + (uint8_t *) &pGtkOffloadGetInfoRsp->ullKeyReplayCounter; + + for (i = 0; i < 8; i++) { + tempReplayCounter[7 - i] = (uint8_t) p[i]; + } + } + + hdd_info("GtkOffloadGetInfoRsp replay counter 0x%llx, value reported to supplicant 0x%llx", + pGtkOffloadGetInfoRsp->ullKeyReplayCounter, + *((uint64_t *)tempReplayCounter)); + + /* Update replay counter to NL */ + cfg80211_gtk_rekey_notify(pAdapter->dev, + pGtkOffloadGetInfoRsp->bssid.bytes, + tempReplayCounter, GFP_KERNEL); +} + +/** + * __wlan_hdd_cfg80211_set_rekey_data() - set rekey data + * @wiphy: Pointer to wiphy + * @dev: Pointer to network device + * @data: Pointer to rekey data + * + * This function is used to offload GTK rekeying job to the firmware. + * + * Return: 0 for success, non-zero for failure + */ +static +int __wlan_hdd_cfg80211_set_rekey_data(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_gtk_rekey_data *data) +{ + hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *hdd_ctx = wiphy_priv(wiphy); + hdd_station_ctx_t *hdd_sta_ctx; + tHalHandle hal; + int result; + tSirGtkOffloadParams hdd_gtk_offload_req_params; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + + ENTER(); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_warn("Command not allowed in FTM mode"); + return -EINVAL; + } + + if (wlan_hdd_validate_session_id(adapter->sessionId)) { + hdd_err("invalid session id: %d", adapter->sessionId); + return -EINVAL; + } + + MTRACE(qdf_trace(QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_CFG80211_SET_REKEY_DATA, + adapter->sessionId, adapter->device_mode)); + + result = wlan_hdd_validate_context(hdd_ctx); + + if (0 != result) + return result; + + hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + hal = WLAN_HDD_GET_HAL_CTX(adapter); + if (NULL == hal) { + hdd_err("HAL context is Null!!!"); + return -EAGAIN; + } + + /* + * Save gtk rekey parameters in HDD STA context. They will be used + * repeatedly when host goes into power save mode. + */ + wlan_hdd_save_gtk_offload_params(adapter, + (uint8_t *)data->kck, + (uint8_t *)data->kek, + (uint8_t *)data->replay_ctr, + true, + GTK_OFFLOAD_ENABLE); + hdd_info("replay counter from supplicant 0x%llx, value stored in ullKeyReplayCounter 0x%llx", + *((uint64_t *)data->replay_ctr), + hdd_sta_ctx->gtkOffloadReqParams.ullKeyReplayCounter); + + + if (hdd_ctx->hdd_wlan_suspended) { + /* if wlan is suspended, enable GTK offload directly from here */ + memcpy(&hdd_gtk_offload_req_params, + &hdd_sta_ctx->gtkOffloadReqParams, + sizeof(tSirGtkOffloadParams)); + status = + sme_set_gtk_offload(hal, &hdd_gtk_offload_req_params, + adapter->sessionId); + + if (QDF_STATUS_SUCCESS != status) { + hdd_err("sme_set_gtk_offload failed, status(%d)", + status); + return -EINVAL; + } + hdd_notice("sme_set_gtk_offload successful"); + } else { + hdd_notice("wlan not suspended GTKOffload request is stored"); + } + EXIT(); + return result; +} + +/** + * wlan_hdd_cfg80211_set_rekey_data() - set rekey data + * @wiphy: Pointer to wiphy + * @dev: Pointer to network device + * @data: Pointer to rekey data + * + * This function is used to offload GTK rekeying job to the firmware. + * + * Return: 0 for success, non-zero for failure + */ +static +int wlan_hdd_cfg80211_set_rekey_data(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_gtk_rekey_data *data) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_set_rekey_data(wiphy, dev, data); + cds_ssr_unprotect(__func__); + + return ret; +} +#endif /*WLAN_FEATURE_GTK_OFFLOAD */ + +/** + * __wlan_hdd_cfg80211_set_mac_acl() - set access control policy + * @wiphy: Pointer to wiphy + * @dev: Pointer to network device + * @param: Pointer to access control parameter + * + * Return: 0 for success, non-zero for failure + */ +static int __wlan_hdd_cfg80211_set_mac_acl(struct wiphy *wiphy, + struct net_device *dev, + const struct cfg80211_acl_data *params) +{ + int i; + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_hostapd_state_t *pHostapdState; + tsap_Config_t *pConfig; + v_CONTEXT_t p_cds_context = NULL; + hdd_context_t *pHddCtx; + int status; + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + + ENTER(); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_warn("Command not allowed in FTM mode"); + return -EINVAL; + } + + if (NULL == params) { + hdd_err("params is Null"); + return -EINVAL; + } + + pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + status = wlan_hdd_validate_context(pHddCtx); + + if (0 != status) + return status; + + p_cds_context = pHddCtx->pcds_context; + pHostapdState = WLAN_HDD_GET_HOSTAP_STATE_PTR(pAdapter); + + if (NULL == pHostapdState) { + hdd_err("pHostapdState is Null"); + return -EINVAL; + } + + hdd_err("acl policy: = %d no acl entries = %d", params->acl_policy, + params->n_acl_entries); + + MTRACE(qdf_trace(QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_CFG80211_SET_MAC_ACL, + pAdapter->sessionId, pAdapter->device_mode)); + if (QDF_SAP_MODE == pAdapter->device_mode) { + pConfig = &pAdapter->sessionCtx.ap.sapConfig; + + /* default value */ + pConfig->num_accept_mac = 0; + pConfig->num_deny_mac = 0; + + /** + * access control policy + * @NL80211_ACL_POLICY_ACCEPT_UNLESS_LISTED: Deny stations which are + * listed in hostapd.deny file. + * @NL80211_ACL_POLICY_DENY_UNLESS_LISTED: Allow stations which are + * listed in hostapd.accept file. + */ + if (NL80211_ACL_POLICY_DENY_UNLESS_LISTED == params->acl_policy) { + pConfig->SapMacaddr_acl = eSAP_DENY_UNLESS_ACCEPTED; + } else if (NL80211_ACL_POLICY_ACCEPT_UNLESS_LISTED == + params->acl_policy) { + pConfig->SapMacaddr_acl = eSAP_ACCEPT_UNLESS_DENIED; + } else { + hdd_err("Acl Policy : %d is not supported", + params->acl_policy); + return -ENOTSUPP; + } + + if (eSAP_DENY_UNLESS_ACCEPTED == pConfig->SapMacaddr_acl) { + pConfig->num_accept_mac = params->n_acl_entries; + for (i = 0; i < params->n_acl_entries; i++) { + hdd_notice("** Add ACL MAC entry %i in WhiletList :" + MAC_ADDRESS_STR, i, + MAC_ADDR_ARRAY( + params->mac_addrs[i].addr)); + + qdf_mem_copy(&pConfig->accept_mac[i], + params->mac_addrs[i].addr, + sizeof(qcmacaddr)); + } + } else if (eSAP_ACCEPT_UNLESS_DENIED == pConfig->SapMacaddr_acl) { + pConfig->num_deny_mac = params->n_acl_entries; + for (i = 0; i < params->n_acl_entries; i++) { + hdd_notice("** Add ACL MAC entry %i in BlackList :" + MAC_ADDRESS_STR, i, + MAC_ADDR_ARRAY( + params->mac_addrs[i].addr)); + + qdf_mem_copy(&pConfig->deny_mac[i], + params->mac_addrs[i].addr, + sizeof(qcmacaddr)); + } + } + qdf_status = wlansap_set_mac_acl( + WLAN_HDD_GET_SAP_CTX_PTR(pAdapter), pConfig); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + hdd_err("SAP Set Mac Acl fail"); + return -EINVAL; + } + } else { + hdd_notice("Invalid device_mode %s(%d)", + hdd_device_mode_to_string(pAdapter->device_mode), + pAdapter->device_mode); + return -EINVAL; + } + EXIT(); + return 0; +} + +/** + * wlan_hdd_cfg80211_set_mac_acl() - SSR wrapper for + * __wlan_hdd_cfg80211_set_mac_acl + * @wiphy: pointer to wiphy structure + * @dev: pointer to net_device + * @params: pointer to cfg80211_acl_data + * + * Return; 0 on success, error number otherwise + */ +static int +wlan_hdd_cfg80211_set_mac_acl(struct wiphy *wiphy, + struct net_device *dev, + const struct cfg80211_acl_data *params) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_set_mac_acl(wiphy, dev, params); + cds_ssr_unprotect(__func__); + + return ret; +} + +#ifdef WLAN_NL80211_TESTMODE +#ifdef FEATURE_WLAN_LPHB +/** + * wlan_hdd_cfg80211_lphb_ind_handler() - handle low power heart beat indication + * @pHddCtx: Pointer to hdd context + * @lphbInd: Pointer to low power heart beat indication parameter + * + * Return: none + */ +static void wlan_hdd_cfg80211_lphb_ind_handler(void *pHddCtx, + tSirLPHBInd *lphbInd) +{ + struct sk_buff *skb; + + hdd_err("LPHB indication arrived"); + + if (0 != wlan_hdd_validate_context((hdd_context_t *) pHddCtx)) + return; + + if (NULL == lphbInd) { + hdd_err("invalid argument lphbInd"); + return; + } + + skb = cfg80211_testmode_alloc_event_skb(((hdd_context_t *) pHddCtx)-> + wiphy, sizeof(tSirLPHBInd), + GFP_ATOMIC); + if (!skb) { + hdd_err("LPHB timeout, NL buffer alloc fail"); + return; + } + + if (nla_put_u32(skb, WLAN_HDD_TM_ATTR_CMD, WLAN_HDD_TM_CMD_WLAN_HB)) { + hdd_err("WLAN_HDD_TM_ATTR_CMD put fail"); + goto nla_put_failure; + } + if (nla_put_u32(skb, WLAN_HDD_TM_ATTR_TYPE, lphbInd->protocolType)) { + hdd_err("WLAN_HDD_TM_ATTR_TYPE put fail"); + goto nla_put_failure; + } + if (nla_put(skb, WLAN_HDD_TM_ATTR_DATA, sizeof(tSirLPHBInd), lphbInd)) { + hdd_err("WLAN_HDD_TM_ATTR_DATA put fail"); + goto nla_put_failure; + } + cfg80211_testmode_event(skb, GFP_ATOMIC); + return; + +nla_put_failure: + hdd_err("NLA Put fail"); + kfree_skb(skb); + + return; +} +#endif /* FEATURE_WLAN_LPHB */ + +/** + * __wlan_hdd_cfg80211_testmode() - test mode + * @wiphy: Pointer to wiphy + * @data: Data pointer + * @len: Data length + * + * Return: 0 for success, non-zero for failure + */ +static int __wlan_hdd_cfg80211_testmode(struct wiphy *wiphy, + void *data, int len) +{ + struct nlattr *tb[WLAN_HDD_TM_ATTR_MAX + 1]; + int err; + hdd_context_t *pHddCtx = wiphy_priv(wiphy); + + ENTER(); + + err = wlan_hdd_validate_context(pHddCtx); + if (err) + return err; + + err = nla_parse(tb, WLAN_HDD_TM_ATTR_MAX, data, + len, wlan_hdd_tm_policy); + if (err) { + hdd_err("Testmode INV ATTR"); + return err; + } + + if (!tb[WLAN_HDD_TM_ATTR_CMD]) { + hdd_err("Testmode INV CMD"); + return -EINVAL; + } + + MTRACE(qdf_trace(QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_CFG80211_TESTMODE, + NO_SESSION, nla_get_u32(tb[WLAN_HDD_TM_ATTR_CMD]))); + switch (nla_get_u32(tb[WLAN_HDD_TM_ATTR_CMD])) { +#ifdef FEATURE_WLAN_LPHB + /* Low Power Heartbeat configuration request */ + case WLAN_HDD_TM_CMD_WLAN_HB: + { + int buf_len; + void *buf; + tSirLPHBReq *hb_params = NULL; + tSirLPHBReq *hb_params_temp = NULL; + QDF_STATUS smeStatus; + + if (!tb[WLAN_HDD_TM_ATTR_DATA]) { + hdd_err("Testmode INV DATA"); + return -EINVAL; + } + + buf = nla_data(tb[WLAN_HDD_TM_ATTR_DATA]); + buf_len = nla_len(tb[WLAN_HDD_TM_ATTR_DATA]); + + hb_params_temp = (tSirLPHBReq *) buf; + if ((hb_params_temp->cmd == LPHB_SET_TCP_PARAMS_INDID) + && (hb_params_temp->params.lphbTcpParamReq. + timePeriodSec == 0)) + return -EINVAL; + + if (buf_len > sizeof(*hb_params)) { + hdd_err("buf_len=%d exceeded hb_params size limit", + buf_len); + return -ERANGE; + } + + hb_params = + (tSirLPHBReq *) qdf_mem_malloc(sizeof(tSirLPHBReq)); + if (NULL == hb_params) { + hdd_err("Request Buffer Alloc Fail"); + return -ENOMEM; + } + + qdf_mem_zero(hb_params, sizeof(tSirLPHBReq)); + qdf_mem_copy(hb_params, buf, buf_len); + smeStatus = + sme_lphb_config_req((tHalHandle) (pHddCtx->hHal), + hb_params, + wlan_hdd_cfg80211_lphb_ind_handler); + if (QDF_STATUS_SUCCESS != smeStatus) { + hdd_err("LPHB Config Fail, disable"); + qdf_mem_free(hb_params); + } + return 0; + } +#endif /* FEATURE_WLAN_LPHB */ + +#if defined(QCA_WIFI_FTM) + case WLAN_HDD_TM_CMD_WLAN_FTM: + { + int buf_len; + void *buf; + QDF_STATUS status; + + if (hdd_get_conparam() != QDF_GLOBAL_FTM_MODE) { + hdd_err("Device is not in FTM mode"); + return -EINVAL; + } + + if (!tb[WLAN_HDD_TM_ATTR_DATA]) { + hdd_err("WLAN_HDD_TM_ATTR_DATA attribute is invalid"); + return -EINVAL; + } + + buf = nla_data(tb[WLAN_HDD_TM_ATTR_DATA]); + buf_len = nla_len(tb[WLAN_HDD_TM_ATTR_DATA]); + + hdd_info("****FTM Tx cmd len = %d*****", buf_len); + + status = wlan_hdd_ftm_testmode_cmd(buf, buf_len); + + if (status != QDF_STATUS_SUCCESS) + err = -EBUSY; + break; + } +#endif + + default: + hdd_err("command %d not supported", + nla_get_u32(tb[WLAN_HDD_TM_ATTR_CMD])); + return -EOPNOTSUPP; + } + EXIT(); + return err; +} + +/** + * wlan_hdd_cfg80211_testmode() - test mode + * @wiphy: Pointer to wiphy + * @dev: Pointer to network device + * @data: Data pointer + * @len: Data length + * + * Return: 0 for success, non-zero for failure + */ +static int wlan_hdd_cfg80211_testmode(struct wiphy *wiphy, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)) + struct wireless_dev *wdev, +#endif + void *data, int len) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_testmode(wiphy, data, len); + cds_ssr_unprotect(__func__); + + return ret; +} + +#if defined(QCA_WIFI_FTM) +/** + * wlan_hdd_testmode_rx_event() - test mode rx event handler + * @buf: Pointer to buffer + * @buf_len: Buffer length + * + * Return: none + */ +void wlan_hdd_testmode_rx_event(void *buf, size_t buf_len) +{ + struct sk_buff *skb; + hdd_context_t *hdd_ctx; + + if (!buf || !buf_len) { + hdd_err("buf or buf_len invalid, buf = %p buf_len = %zu", buf, buf_len); + return; + } + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (!hdd_ctx) { + hdd_err("hdd context invalid"); + return; + } + + skb = cfg80211_testmode_alloc_event_skb(hdd_ctx->wiphy, + buf_len, GFP_KERNEL); + if (!skb) { + hdd_err("failed to allocate testmode rx skb!"); + return; + } + + if (nla_put_u32(skb, WLAN_HDD_TM_ATTR_CMD, WLAN_HDD_TM_CMD_WLAN_FTM) || + nla_put(skb, WLAN_HDD_TM_ATTR_DATA, buf_len, buf)) + goto nla_put_failure; + + hdd_info("****FTM Rx cmd len = %zu*****", buf_len); + + cfg80211_testmode_event(skb, GFP_KERNEL); + return; + +nla_put_failure: + kfree_skb(skb); + hdd_err("nla_put failed on testmode rx skb!"); +} +#endif +#endif /* CONFIG_NL80211_TESTMODE */ + +#ifdef QCA_HT_2040_COEX +/** + * __wlan_hdd_cfg80211_set_ap_channel_width() - set ap channel bandwidth + * @wiphy: Pointer to wiphy + * @dev: Pointer to network device + * @chandef: Pointer to channel definition parameter + * + * Return: 0 for success, non-zero for failure + */ +static int +__wlan_hdd_cfg80211_set_ap_channel_width(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_chan_def *chandef) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *pHddCtx; + QDF_STATUS status; + tSmeConfigParams sme_config; + bool cbModeChange = false; + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_warn("Command not allowed in FTM mode"); + return -EINVAL; + } + + if (wlan_hdd_validate_session_id(pAdapter->sessionId)) { + hdd_err("invalid session id: %d", pAdapter->sessionId); + return -EINVAL; + } + + pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + status = wlan_hdd_validate_context(pHddCtx); + if (status) + return status; + + qdf_mem_zero(&sme_config, sizeof(tSmeConfigParams)); + sme_get_config_param(pHddCtx->hHal, &sme_config); + switch (chandef->width) { + case NL80211_CHAN_WIDTH_20: + case NL80211_CHAN_WIDTH_20_NOHT: + if (sme_config.csrConfig.channelBondingMode24GHz != + eCSR_INI_SINGLE_CHANNEL_CENTERED) { + sme_config.csrConfig.channelBondingMode24GHz = + eCSR_INI_SINGLE_CHANNEL_CENTERED; + sme_update_config(pHddCtx->hHal, &sme_config); + cbModeChange = true; + } + break; + + case NL80211_CHAN_WIDTH_40: + if (sme_config.csrConfig.channelBondingMode24GHz == + eCSR_INI_SINGLE_CHANNEL_CENTERED) { + if (NL80211_CHAN_HT40MINUS == + cfg80211_get_chandef_type(chandef)) + sme_config.csrConfig.channelBondingMode24GHz = + eCSR_INI_DOUBLE_CHANNEL_HIGH_PRIMARY; + else + sme_config.csrConfig.channelBondingMode24GHz = + eCSR_INI_DOUBLE_CHANNEL_LOW_PRIMARY; + sme_update_config(pHddCtx->hHal, &sme_config); + cbModeChange = true; + } + break; + + default: + hdd_err("Error!!! Invalid HT20/40 mode !"); + return -EINVAL; + } + + if (!cbModeChange) + return 0; + + if (QDF_SAP_MODE != pAdapter->device_mode) + return 0; + + hdd_notice("Channel bonding changed to %d", + sme_config.csrConfig.channelBondingMode24GHz); + + /* Change SAP ht2040 mode */ + status = hdd_set_sap_ht2040_mode(pAdapter, + cfg80211_get_chandef_type(chandef)); + if (status != QDF_STATUS_SUCCESS) { + hdd_err("Error!!! Cannot set SAP HT20/40 mode!"); + return -EINVAL; + } + + return 0; +} + +/** + * wlan_hdd_cfg80211_set_ap_channel_width() - set ap channel bandwidth + * @wiphy: Pointer to wiphy + * @dev: Pointer to network device + * @chandef: Pointer to channel definition parameter + * + * Return: 0 for success, non-zero for failure + */ +static int +wlan_hdd_cfg80211_set_ap_channel_width(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_chan_def *chandef) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_set_ap_channel_width(wiphy, dev, chandef); + cds_ssr_unprotect(__func__); + + return ret; +} +#endif + +#ifdef CHANNEL_SWITCH_SUPPORTED +/** + * __wlan_hdd_cfg80211_channel_switch()- function to switch + * channel in SAP/GO + * @wiphy: wiphy pointer + * @dev: dev pointer. + * @csa_params: Change channel params + * + * This function is called to switch channel in SAP/GO + * + * Return: 0 if success else return non zero + */ +static int __wlan_hdd_cfg80211_channel_switch(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_csa_settings *csa_params) +{ + hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *hdd_ctx; + uint8_t channel; + uint16_t freq; + int ret; + enum phy_ch_width ch_width; + + hdd_notice("Set Freq %d", + csa_params->chandef.chan->center_freq); + + if (wlan_hdd_validate_session_id(adapter->sessionId)) { + hdd_err("invalid session id: %d", adapter->sessionId); + return -EINVAL; + } + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + + if (0 != ret) + return ret; + + if ((QDF_P2P_GO_MODE != adapter->device_mode) && + (QDF_SAP_MODE != adapter->device_mode)) + return -ENOTSUPP; + + freq = csa_params->chandef.chan->center_freq; + channel = cds_freq_to_chan(freq); + + ch_width = hdd_map_nl_chan_width(csa_params->chandef.width); + + ret = hdd_softap_set_channel_change(dev, channel, ch_width); + return ret; +} + +/** + * wlan_hdd_cfg80211_channel_switch()- function to switch + * channel in SAP/GO + * @wiphy: wiphy pointer + * @dev: dev pointer. + * @csa_params: Change channel params + * + * This function is called to switch channel in SAP/GO + * + * Return: 0 if success else return non zero + */ +static int wlan_hdd_cfg80211_channel_switch(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_csa_settings *csa_params) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_channel_switch(wiphy, dev, csa_params); + cds_ssr_unprotect(__func__); + return ret; +} +#endif + +/** + * wlan_hdd_convert_nl_iftype_to_hdd_type() - provides the type + * translation from NL to policy manager type + * @type: Generic connection mode type defined in NL + * + * + * This function provides the type translation + * + * Return: cds_con_mode enum + */ +enum cds_con_mode wlan_hdd_convert_nl_iftype_to_hdd_type( + enum nl80211_iftype type) +{ + enum cds_con_mode mode = CDS_MAX_NUM_OF_MODE; + switch (type) { + case NL80211_IFTYPE_STATION: + mode = CDS_STA_MODE; + break; + case NL80211_IFTYPE_P2P_CLIENT: + mode = CDS_P2P_CLIENT_MODE; + break; + case NL80211_IFTYPE_P2P_GO: + mode = CDS_P2P_GO_MODE; + break; + case NL80211_IFTYPE_AP: + mode = CDS_SAP_MODE; + break; + case NL80211_IFTYPE_ADHOC: + mode = CDS_IBSS_MODE; + break; + default: + hdd_err("Unsupported interface type (%d)", + type); + } + return mode; +} + +/** + * wlan_hdd_cfg80211_set_mon_ch() - Set monitor mode capture channel + * @wiphy: Handle to struct wiphy to get handle to module context. + * @chandef: Contains information about the capture channel to be set. + * + * This interface is called if and only if monitor mode interface alone is + * active. + * + * Return: 0 success or error code on failure. + */ +static int __wlan_hdd_cfg80211_set_mon_ch(struct wiphy *wiphy, + struct cfg80211_chan_def *chandef) +{ + hdd_context_t *hdd_ctx = wiphy_priv(wiphy); + hdd_adapter_t *adapter; + hdd_station_ctx_t *sta_ctx; + struct hdd_mon_set_ch_info *ch_info; + QDF_STATUS status; + tHalHandle hal_hdl; + struct qdf_mac_addr bssid; + tCsrRoamProfile roam_profile; + struct ch_params_s ch_params; + uint8_t sec_ch = 0; + int ret; + uint16_t chan_num = cds_freq_to_chan(chandef->chan->center_freq); + + ENTER(); + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return ret; + + hal_hdl = hdd_ctx->hHal; + + adapter = hdd_get_adapter(hdd_ctx, QDF_MONITOR_MODE); + if (!adapter) + return -EIO; + + hdd_info("%s: set monitor mode Channel %d and freq %d", + adapter->dev->name, chan_num, chandef->chan->center_freq); + + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + ch_info = &sta_ctx->ch_info; + roam_profile.ChannelInfo.ChannelList = &ch_info->channel; + roam_profile.ChannelInfo.numOfChannels = 1; + roam_profile.phyMode = ch_info->phy_mode; + roam_profile.ch_params.ch_width = chandef->width; + hdd_select_cbmode(adapter, chan_num, &roam_profile.ch_params); + + qdf_mem_copy(bssid.bytes, adapter->macAddressCurrent.bytes, + QDF_MAC_ADDR_SIZE); + + ch_params.ch_width = chandef->width; + /* + * CDS api expects secondary channel for calculating + * the channel params + */ + if ((ch_params.ch_width == CH_WIDTH_40MHZ) && + (CDS_IS_CHANNEL_24GHZ(chan_num))) { + if (chan_num >= 1 && chan_num <= 5) + sec_ch = chan_num + 4; + else if (chan_num >= 6 && chan_num <= 13) + sec_ch = chan_num - 4; + } + cds_set_channel_params(chan_num, sec_ch, &ch_params); + status = sme_roam_channel_change_req(hal_hdl, bssid, &ch_params, + &roam_profile); + if (status) { + hdd_err("Status: %d Failed to set sme_RoamChannel for monitor mode", + status); + ret = qdf_status_to_os_return(status); + return ret; + } + EXIT(); + return 0; +} + +/** + * wlan_hdd_cfg80211_set_mon_ch() - Set monitor mode capture channel + * @wiphy: Handle to struct wiphy to get handle to module context. + * @chandef: Contains information about the capture channel to be set. + * + * This interface is called if and only if monitor mode interface alone is + * active. + * + * Return: 0 success or error code on failure. + */ +static int wlan_hdd_cfg80211_set_mon_ch(struct wiphy *wiphy, + struct cfg80211_chan_def *chandef) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_set_mon_ch(wiphy, chandef); + cds_ssr_unprotect(__func__); + return ret; +} + +/** + * wlan_hdd_clear_link_layer_stats() - clear link layer stats + * @adapter: pointer to adapter + * + * Wrapper function to clear link layer stats. + * return - void + */ +void wlan_hdd_clear_link_layer_stats(hdd_adapter_t *adapter) +{ + tSirLLStatsClearReq link_layer_stats_clear_req; + tHalHandle hal = WLAN_HDD_GET_HAL_CTX(adapter); + + link_layer_stats_clear_req.statsClearReqMask = WIFI_STATS_IFACE_AC | + WIFI_STATS_IFACE_ALL_PEER; + link_layer_stats_clear_req.stopReq = 0; + link_layer_stats_clear_req.reqId = 1; + link_layer_stats_clear_req.staId = adapter->sessionId; + sme_ll_stats_clear_req(hal, &link_layer_stats_clear_req); + + return; +} + +/** + * struct cfg80211_ops - cfg80211_ops + * + * @add_virtual_intf: Add virtual interface + * @del_virtual_intf: Delete virtual interface + * @change_virtual_intf: Change virtual interface + * @change_station: Change station + * @add_beacon: Add beacon in sap mode + * @del_beacon: Delete beacon in sap mode + * @set_beacon: Set beacon in sap mode + * @start_ap: Start ap + * @change_beacon: Change beacon + * @stop_ap: Stop ap + * @change_bss: Change bss + * @add_key: Add key + * @get_key: Get key + * @del_key: Delete key + * @set_default_key: Set default key + * @set_channel: Set channel + * @scan: Scan + * @connect: Connect + * @disconnect: Disconnect + * @join_ibss = Join ibss + * @leave_ibss = Leave ibss + * @set_wiphy_params = Set wiphy params + * @set_tx_power = Set tx power + * @get_tx_power = get tx power + * @remain_on_channel = Remain on channel + * @cancel_remain_on_channel = Cancel remain on channel + * @mgmt_tx = Tx management frame + * @mgmt_tx_cancel_wait = Cancel management tx wait + * @set_default_mgmt_key = Set default management key + * @set_txq_params = Set tx queue parameters + * @get_station = Get station + * @set_power_mgmt = Set power management + * @del_station = Delete station + * @add_station = Add station + * @set_pmksa = Set pmksa + * @del_pmksa = Delete pmksa + * @flush_pmksa = Flush pmksa + * @update_ft_ies = Update FT IEs + * @tdls_mgmt = Tdls management + * @tdls_oper = Tdls operation + * @set_rekey_data = Set rekey data + * @sched_scan_start = Scheduled scan start + * @sched_scan_stop = Scheduled scan stop + * @resume = Resume wlan + * @suspend = Suspend wlan + * @set_mac_acl = Set mac acl + * @testmode_cmd = Test mode command + * @set_ap_chanwidth = Set AP channel bandwidth + * @dump_survey = Dump survey + * @key_mgmt_set_pmk = Set pmk key management + */ +static struct cfg80211_ops wlan_hdd_cfg80211_ops = { + .add_virtual_intf = wlan_hdd_add_virtual_intf, + .del_virtual_intf = wlan_hdd_del_virtual_intf, + .change_virtual_intf = wlan_hdd_cfg80211_change_iface, + .change_station = wlan_hdd_change_station, + .start_ap = wlan_hdd_cfg80211_start_ap, + .change_beacon = wlan_hdd_cfg80211_change_beacon, + .stop_ap = wlan_hdd_cfg80211_stop_ap, + .change_bss = wlan_hdd_cfg80211_change_bss, + .add_key = wlan_hdd_cfg80211_add_key, + .get_key = wlan_hdd_cfg80211_get_key, + .del_key = wlan_hdd_cfg80211_del_key, + .set_default_key = wlan_hdd_cfg80211_set_default_key, + .scan = wlan_hdd_cfg80211_scan, + .connect = wlan_hdd_cfg80211_connect, + .disconnect = wlan_hdd_cfg80211_disconnect, + .join_ibss = wlan_hdd_cfg80211_join_ibss, + .leave_ibss = wlan_hdd_cfg80211_leave_ibss, + .set_wiphy_params = wlan_hdd_cfg80211_set_wiphy_params, + .set_tx_power = wlan_hdd_cfg80211_set_txpower, + .get_tx_power = wlan_hdd_cfg80211_get_txpower, + .remain_on_channel = wlan_hdd_cfg80211_remain_on_channel, + .cancel_remain_on_channel = wlan_hdd_cfg80211_cancel_remain_on_channel, + .mgmt_tx = wlan_hdd_mgmt_tx, + .mgmt_tx_cancel_wait = wlan_hdd_cfg80211_mgmt_tx_cancel_wait, + .set_default_mgmt_key = wlan_hdd_set_default_mgmt_key, + .set_txq_params = wlan_hdd_set_txq_params, + .dump_station = wlan_hdd_cfg80211_dump_station, + .get_station = wlan_hdd_cfg80211_get_station, + .set_power_mgmt = wlan_hdd_cfg80211_set_power_mgmt, + .del_station = wlan_hdd_cfg80211_del_station, + .add_station = wlan_hdd_cfg80211_add_station, + .set_pmksa = wlan_hdd_cfg80211_set_pmksa, + .del_pmksa = wlan_hdd_cfg80211_del_pmksa, + .flush_pmksa = wlan_hdd_cfg80211_flush_pmksa, +#if defined(KERNEL_SUPPORT_11R_CFG80211) + .update_ft_ies = wlan_hdd_cfg80211_update_ft_ies, +#endif +#ifdef FEATURE_WLAN_TDLS + .tdls_mgmt = wlan_hdd_cfg80211_tdls_mgmt, + .tdls_oper = wlan_hdd_cfg80211_tdls_oper, +#endif +#ifdef WLAN_FEATURE_GTK_OFFLOAD + .set_rekey_data = wlan_hdd_cfg80211_set_rekey_data, +#endif /* WLAN_FEATURE_GTK_OFFLOAD */ +#ifdef FEATURE_WLAN_SCAN_PNO + .sched_scan_start = wlan_hdd_cfg80211_sched_scan_start, + .sched_scan_stop = wlan_hdd_cfg80211_sched_scan_stop, +#endif /*FEATURE_WLAN_SCAN_PNO */ + .resume = wlan_hdd_cfg80211_resume_wlan, + .suspend = wlan_hdd_cfg80211_suspend_wlan, + .set_mac_acl = wlan_hdd_cfg80211_set_mac_acl, +#ifdef WLAN_NL80211_TESTMODE + .testmode_cmd = wlan_hdd_cfg80211_testmode, +#endif +#ifdef QCA_HT_2040_COEX + .set_ap_chanwidth = wlan_hdd_cfg80211_set_ap_channel_width, +#endif + .dump_survey = wlan_hdd_cfg80211_dump_survey, +#ifdef CHANNEL_SWITCH_SUPPORTED + .channel_switch = wlan_hdd_cfg80211_channel_switch, +#endif + .set_monitor_channel = wlan_hdd_cfg80211_set_mon_ch, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 5, 0)) || \ + defined(CFG80211_ABORT_SCAN) + .abort_scan = wlan_hdd_cfg80211_abort_scan, +#endif +}; diff --git a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_cfg80211.h b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_cfg80211.h new file mode 100644 index 0000000000000000000000000000000000000000..13a819b46fa5c888da2254b2001dd3a07682ab43 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_cfg80211.h @@ -0,0 +1,3707 @@ +/* + * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: wlan_hdd_cfg80211.h + * + * WLAN host device driver cfg80211 functions declaration + */ + +#if !defined(HDD_CFG80211_H__) +#define HDD_CFG80211_H__ + +/* value for initial part of frames and number of bytes to be compared */ +#define GAS_INITIAL_REQ "\x04\x0a" +#define GAS_INITIAL_REQ_SIZE 2 + +#define GAS_INITIAL_RSP "\x04\x0b" +#define GAS_INITIAL_RSP_SIZE 2 + +#define GAS_COMEBACK_REQ "\x04\x0c" +#define GAS_COMEBACK_REQ_SIZE 2 + +#define GAS_COMEBACK_RSP "\x04\x0d" +#define GAS_COMEBACK_RSP_SIZE 2 + +#define P2P_PUBLIC_ACTION_FRAME "\x04\x09\x50\x6f\x9a\x09" +#define P2P_PUBLIC_ACTION_FRAME_SIZE 6 + +#define P2P_ACTION_FRAME "\x7f\x50\x6f\x9a\x09" +#define P2P_ACTION_FRAME_SIZE 5 + +#define SA_QUERY_FRAME_REQ "\x08\x00" +#define SA_QUERY_FRAME_REQ_SIZE 2 + +#define SA_QUERY_FRAME_RSP "\x08\x01" +#define SA_QUERY_FRAME_RSP_SIZE 2 + +#define HDD_P2P_WILDCARD_SSID "DIRECT-" +#define HDD_P2P_WILDCARD_SSID_LEN 7 + +#define WNM_BSS_ACTION_FRAME "\x0a\x07" +#define WNM_BSS_ACTION_FRAME_SIZE 2 + +#define WNM_NOTIFICATION_FRAME "\x0a\x1a" +#define WNM_NOTIFICATION_FRAME_SIZE 2 + +#define WPA_OUI_TYPE "\x00\x50\xf2\x01" +#define BLACKLIST_OUI_TYPE "\x00\x50\x00\x00" +#define WHITELIST_OUI_TYPE "\x00\x50\x00\x01" +#define WPA_OUI_TYPE_SIZE 4 +#define WMM_OUI_TYPE "\x00\x50\xf2\x02\x01" +#define WMM_OUI_TYPE_SIZE 5 + +#define VENDOR1_AP_OUI_TYPE "\x00\xE0\x4C" +#define VENDOR1_AP_OUI_TYPE_SIZE 3 + +#define WLAN_BSS_MEMBERSHIP_SELECTOR_VHT_PHY 126 +#define WLAN_BSS_MEMBERSHIP_SELECTOR_HT_PHY 127 +#define BASIC_RATE_MASK 0x80 +#define RATE_MASK 0x7f + +#ifdef WLAN_ENABLE_AGEIE_ON_SCAN_RESULTS +/* GPS application requirement */ +#define QCOM_VENDOR_IE_ID 221 +#define QCOM_OUI1 0x00 +#define QCOM_OUI2 0xA0 +#define QCOM_OUI3 0xC6 +#define QCOM_VENDOR_IE_AGE_TYPE 0x100 +#define QCOM_VENDOR_IE_AGE_LEN (sizeof(qcom_ie_age) - 2) + +/** + * typedef struct qcom_ie_age - age ie + * + * @element_id: Element id + * @len: Length + * @oui_1: OUI 1 + * @oui_2: OUI 2 + * @oui_3: OUI 3 + * @type: Type + * @age: Age + * @tsf_delta: tsf delta from FW + * @beacon_tsf: original beacon TSF + * @seq_ctrl: sequence control field + */ +typedef struct { + u8 element_id; + u8 len; + u8 oui_1; + u8 oui_2; + u8 oui_3; + u32 type; + u32 age; + u32 tsf_delta; + u64 beacon_tsf; + u16 seq_ctrl; +} __attribute__ ((packed)) qcom_ie_age; +#endif + +#ifdef FEATURE_WLAN_TDLS +#define WLAN_IS_TDLS_SETUP_ACTION(action) \ + ((SIR_MAC_TDLS_SETUP_REQ <= action) && \ + (SIR_MAC_TDLS_SETUP_CNF >= action)) +#if !defined (TDLS_MGMT_VERSION2) +#define TDLS_MGMT_VERSION2 0 +#endif + +#endif + +#ifdef WLAN_FEATURE_LINK_LAYER_STATS +void wlan_hdd_clear_link_layer_stats(hdd_adapter_t *adapter); +#else +static inline void wlan_hdd_clear_link_layer_stats(hdd_adapter_t *adapter) {} +#endif + +#define MAX_CHANNEL (NUM_24GHZ_CHANNELS + NUM_5GHZ_CHANNELS) +#define MAX_SCAN_SSID 10 + +#define IS_CHANNEL_VALID(channel) ((channel >= 0 && channel < 15) \ + || (channel >= 36 && channel <= 184)) + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)) \ + || defined(BACKPORTED_CHANNEL_SWITCH_PRESENT) +#define CHANNEL_SWITCH_SUPPORTED +#endif + +#if defined(CFG80211_DEL_STA_V2) || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)) || defined(WITH_BACKPORTS) +#define USE_CFG80211_DEL_STA_V2 +#endif + +/** + * enum eDFS_CAC_STATUS: CAC status + * + * @DFS_CAC_NEVER_DONE: CAC never done + * @DFS_CAC_IN_PROGRESS: CAC is in progress + * @DFS_CAC_IN_PROGRESS: CAC already done + */ +typedef enum { + DFS_CAC_NEVER_DONE, + DFS_CAC_IN_PROGRESS, + DFS_CAC_ALREADY_DONE, +} eDFS_CAC_STATUS; + +/* Vendor id to be used in vendor specific command and events + * to user space. + * NOTE: The authoritative place for definition of QCA_NL80211_VENDOR_ID, + * vendor subcmd definitions prefixed with QCA_NL80211_VENDOR_SUBCMD, and + * qca_wlan_vendor_attr is open source file src/common/qca-vendor.h in + * git://w1.fi/srv/git/hostap.git; the values here are just a copy of that + */ + +#define QCA_NL80211_VENDOR_ID 0x001374 +#define MAX_REQUEST_ID 0xFFFFFFFF + +/** + * enum qca_nl80211_vendor_subcmds: NL 80211 vendor sub command + * + * @QCA_NL80211_VENDOR_SUBCMD_UNSPEC: Unspecified + * @QCA_NL80211_VENDOR_SUBCMD_TEST: Test + * Sub commands 2 to 8 are not used + * @QCA_NL80211_VENDOR_SUBCMD_ROAMING: Roaming + * @QCA_NL80211_VENDOR_SUBCMD_AVOID_FREQUENCY: Avoid frequency. + * @QCA_NL80211_VENDOR_SUBCMD_DFS_CAPABILITY: DFS capability + * @QCA_NL80211_VENDOR_SUBCMD_NAN: Nan + * @QCA_NL80211_VENDOR_SUBCMD_STATS_EXT: Ext stats + * @QCA_NL80211_VENDOR_SUBCMD_LL_STATS_SET: Link layer stats set + * @QCA_NL80211_VENDOR_SUBCMD_LL_STATS_GET: Link layer stats get + * @QCA_NL80211_VENDOR_SUBCMD_LL_STATS_CLR: Link layer stats clear + * @QCA_NL80211_VENDOR_SUBCMD_LL_STATS_RADIO_RESULTS: Link layer stats radio + * results + * @QCA_NL80211_VENDOR_SUBCMD_LL_STATS_IFACE_RESULTS: Link layer stats interface + * results + * @QCA_NL80211_VENDOR_SUBCMD_LL_STATS_PEERS_RESULTS: Link layer stats peer + * results + * @QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_START: Ext scan start + * @QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_STOP: Ext scan stop + * @QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_GET_VALID_CHANNELS: Ext scan get valid + * channels + * @QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_GET_CAPABILITIES: Ext scan get capability + * @QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_GET_CACHED_RESULTS: Ext scan get cached + * results + * @QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SCAN_RESULTS_AVAILABLE: Ext scan results + * available. Used when report_threshold is reached in scan cache. + * @QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_FULL_SCAN_RESULT: Ext scan full scan + * result. Used to report scan results when each probe rsp. is received, + * if report_events enabled in wifi_scan_cmd_params. + * @QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SCAN_EVENT: Ext scan event from target. + * Indicates progress of scanning state-machine. + * @QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_HOTLIST_AP_FOUND: Ext scan hotlist + * ap found + * @QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SET_BSSID_HOTLIST: Ext scan set hotlist + * bssid + * @QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_RESET_BSSID_HOTLIST: Ext scan reset + * hotlist bssid + * @QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SIGNIFICANT_CHANGE: Ext scan significant + * change + * @QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SET_SIGNIFICANT_CHANGE: Ext scan set + * significant change + * ap found + * @QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_RESET_SIGNIFICANT_CHANGE: Ext scan reset + * significant change + * @QCA_NL80211_VENDOR_SUBCMD_TDLS_ENABLE: Ext tdls enable + * @QCA_NL80211_VENDOR_SUBCMD_TDLS_DISABLE: Ext tdls disable + * @QCA_NL80211_VENDOR_SUBCMD_TDLS_GET_STATUS: Ext tdls get status + * @QCA_NL80211_VENDOR_SUBCMD_TDLS_STATE: Ext tdls state + * @QCA_NL80211_VENDOR_SUBCMD_GET_SUPPORTED_FEATURES: Get supported features + * @QCA_NL80211_VENDOR_SUBCMD_SCANNING_MAC_OUI: Set scanning_mac_oui + * @QCA_NL80211_VENDOR_SUBCMD_NO_DFS_FLAG: No DFS flag + * @QCA_NL80211_VENDOR_SUBCMD_GET_CONCURRENCY_MATRIX: Get Concurrency Matrix + * @QCA_NL80211_VENDOR_SUBCMD_KEY_MGMT_SET_KEY: Get the key mgmt offload keys + * @QCA_NL80211_VENDOR_SUBCMD_KEY_MGMT_ROAM_AUTH: After roaming, send the + * roaming and auth information. + * @QCA_NL80211_VENDOR_SUBCMD_OCB_SET_SCHED: Set OCB schedule + * @QCA_NL80211_VENDOR_SUBCMD_DO_ACS: ACS offload flag + * @QCA_NL80211_VENDOR_SUBCMD_GET_FEATURES: Get the supported features by the + * driver. + * @QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_STARTED: Indicate that driver + * started CAC on DFS channel + * @QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_FINISHED: Indicate that driver + * completed the CAC check on DFS channel + * @QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_ABORTED: Indicate that the CAC + * check was aborted by the driver + * @QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_NOP_FINISHED: Indicate that the + * driver completed NOP + * @QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_RADAR_DETECTED: Indicate that the + * driver detected radar signal on the current operating channel + * @QCA_NL80211_VENDOR_SUBCMD_GET_WIFI_INFO: get wlan driver information + * @QCA_NL80211_VENDOR_SUBCMD_WIFI_LOGGER_START: start wifi logger + * @QCA_NL80211_VENDOR_SUBCMD_WIFI_LOGGER_MEMORY_DUMP: memory dump request + * @QCA_NL80211_VENDOR_SUBCMD_GET_LOGGER_FEATURE_SET: get logger feature set + * @QCA_NL80211_VENDOR_SUBCMD_ROAM: roam + * @QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_PNO_SET_LIST: set pno list + * @QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_PNO_SET_PASSPOINT_LIST: set passpoint list + * @QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_PNO_RESET_PASSPOINT_LIST: + * reset passpoint list + * @QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_PNO_NETWORK_FOUND: pno network found + * @QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_PNO_PASSPOINT_NETWORK_FOUND: + * passpoint network found + * @QCA_NL80211_VENDOR_SUBCMD_SET_WIFI_CONFIGURATION: set wifi config + * @QCA_NL80211_VENDOR_SUBCMD_GET_WIFI_CONFIGURATION: get wifi config + * @QCA_NL80211_VENDOR_SUBCMD_GET_LOGGER_FEATURE_SET: get logging features + * @QCA_NL80211_VENDOR_SUBCMD_LINK_PROPERTIES: get link properties + * @QCA_NL80211_VENDOR_SUBCMD_GW_PARAM_CONFIG: set gateway parameters + * @QCA_NL80211_VENDOR_SUBCMD_GET_PREFERRED_FREQ_LIST: get preferred channel + list + * @QCA_NL80211_VENDOR_SUBCMD_SET_PROBABLE_OPER_CHANNEL: channel hint + * @QCA_NL80211_VENDOR_SUBCMD_SETBAND: vendor setband command + * @QCA_NL80211_VENDOR_SUBCMD_TRIGGER_SCAN: venodr scan command + * @QCA_NL80211_VENDOR_SUBCMD_SCAN_DONE: vendor scan complete + * @QCA_NL80211_VENDOR_SUBCMD_ABORT_SCAN: vendor abort scan + * @QCA_NL80211_VENDOR_SUBCMD_OTA_TEST: enable OTA test + * @QCA_NL80211_VENDOR_SUBCMD_SET_TXPOWER_SCALE: set tx power by percentage + * @QCA_NL80211_VENDOR_SUBCMD_SET_TXPOWER_SCALE_DECR_DB: reduce tx power by DB + * @QCA_NL80211_VENDOR_SUBCMD_SET_SAP_CONFIG: SAP configuration + * @QCA_NL80211_VENDOR_SUBCMD_TSF: TSF operations command + * @QCA_NL80211_VENDOR_SUBCMD_WISA: WISA mode configuration + * @QCA_NL80211_VENDOR_SUBCMD_P2P_LISTEN_OFFLOAD_START: Command used to + * start the P2P Listen Offload function in device and pass the listen + * channel, period, interval, count, number of device types, device + * types and vendor information elements to device driver and firmware. + * @QCA_NL80211_VENDOR_SUBCMD_P2P_LISTEN_OFFLOAD_STOP: Command/event used to + * indicate stop request/response of the P2P Listen Offload function in + * device. As an event, it indicates either the feature stopped after it + * was already running or feature has actually failed to start. + * @QCA_NL80211_VENDOR_SUBCMD_GET_STATION: send BSS Information + * @QCA_NL80211_VENDOR_SUBCMD_SAP_CONDITIONAL_CHAN_SWITCH: After SAP starts + * beaconing, this sub command provides the driver, the frequencies on the + * 5 GHz to check for any radar activity. Driver selects one channel from + * this priority list provided through + * @QCA_WLAN_VENDOR_ATTR_SAP_CONDITIONAL_CHAN_SWITCH_FREQ_LIST and starts + * to check for radar activity on it. If no radar activity is detected + * during the channel availability check period, driver internally switches + * to the selected frequency of operation. If the frequency is zero, driver + * internally selects a channel. The status of this conditional switch is + * indicated through an event using the same sub command through + * @QCA_WLAN_VENDOR_ATTR_SAP_CONDITIONAL_CHAN_SWITCH_STATUS. Attributes are + * listed in qca_wlan_vendor_attr_sap_conditional_chan_switch + * @QCA_NL80211_VENDOR_SUBCMD_CONFIGURE_TDLS: Configure the TDLS behavior + * in the host driver. The different TDLS configurations are defined + * by the attributes in enum qca_wlan_vendor_attr_tdls_configuration. + * @QCA_NL80211_VENDOR_SUBCMD_SET_SAR_LIMITS:Set the Specific Absorption Rate + * (SAR) power limits. A critical regulation for FCC compliance, OEMs + * require methods to set SAR limits on TX power of WLAN/WWAN. + * enum qca_vendor_attr_sar_limits attributes are used with this command. + * @QCA_NL80211_VENDOR_SUBCMD_NUD_STATS_SET + * Start / Stop the NUD stats collections + * @QCA_NL80211_VENDOR_SUBCMD_NUD_STATS_GET + * Get the NUD stats, represented by the enum qca_attr_nud_stats_get + */ + +enum qca_nl80211_vendor_subcmds { + QCA_NL80211_VENDOR_SUBCMD_UNSPEC = 0, + QCA_NL80211_VENDOR_SUBCMD_TEST = 1, + QCA_NL80211_VENDOR_SUBCMD_ROAMING = 9, + QCA_NL80211_VENDOR_SUBCMD_AVOID_FREQUENCY = 10, + QCA_NL80211_VENDOR_SUBCMD_DFS_CAPABILITY = 11, + QCA_NL80211_VENDOR_SUBCMD_NAN = 12, + QCA_NL80211_VENDOR_SUBCMD_STATS_EXT = 13, + + QCA_NL80211_VENDOR_SUBCMD_LL_STATS_SET = 14, + QCA_NL80211_VENDOR_SUBCMD_LL_STATS_GET = 15, + QCA_NL80211_VENDOR_SUBCMD_LL_STATS_CLR = 16, + QCA_NL80211_VENDOR_SUBCMD_LL_STATS_RADIO_RESULTS = 17, + QCA_NL80211_VENDOR_SUBCMD_LL_STATS_IFACE_RESULTS = 18, + QCA_NL80211_VENDOR_SUBCMD_LL_STATS_PEERS_RESULTS = 19, + + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_START = 20, + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_STOP = 21, + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_GET_VALID_CHANNELS = 22, + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_GET_CAPABILITIES = 23, + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_GET_CACHED_RESULTS = 24, + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SCAN_RESULTS_AVAILABLE = 25, + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_FULL_SCAN_RESULT = 26, + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SCAN_EVENT = 27, + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_HOTLIST_AP_FOUND = 28, + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SET_BSSID_HOTLIST = 29, + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_RESET_BSSID_HOTLIST = 30, + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SIGNIFICANT_CHANGE = 31, + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SET_SIGNIFICANT_CHANGE = 32, + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_RESET_SIGNIFICANT_CHANGE = 33, + + QCA_NL80211_VENDOR_SUBCMD_TDLS_ENABLE = 34, + QCA_NL80211_VENDOR_SUBCMD_TDLS_DISABLE = 35, + QCA_NL80211_VENDOR_SUBCMD_TDLS_GET_STATUS = 36, + QCA_NL80211_VENDOR_SUBCMD_TDLS_STATE = 37, + + QCA_NL80211_VENDOR_SUBCMD_GET_SUPPORTED_FEATURES = 38, + + QCA_NL80211_VENDOR_SUBCMD_SCANNING_MAC_OUI = 39, + QCA_NL80211_VENDOR_SUBCMD_NO_DFS_FLAG = 40, + + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_HOTLIST_AP_LOST = 41, + + /* Get Concurrency Matrix */ + QCA_NL80211_VENDOR_SUBCMD_GET_CONCURRENCY_MATRIX = 42, + + QCA_NL80211_VENDOR_SUBCMD_KEY_MGMT_SET_KEY = 50, + QCA_NL80211_VENDOR_SUBCMD_KEY_MGMT_ROAM_AUTH = 51, + + /* Deprecated */ + QCA_NL80211_VENDOR_SUBCMD_OCB_SET_SCHED = 53, + + QCA_NL80211_VENDOR_SUBCMD_DO_ACS = 54, + + QCA_NL80211_VENDOR_SUBCMD_GET_FEATURES = 55, + + /* Off loaded DFS events */ + QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_STARTED = 56, + QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_FINISHED = 57, + QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_ABORTED = 58, + QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_NOP_FINISHED = 59, + QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_RADAR_DETECTED = 60, + + QCA_NL80211_VENDOR_SUBCMD_GET_WIFI_INFO = 61, + QCA_NL80211_VENDOR_SUBCMD_WIFI_LOGGER_START = 62, + QCA_NL80211_VENDOR_SUBCMD_WIFI_LOGGER_MEMORY_DUMP = 63, + QCA_NL80211_VENDOR_SUBCMD_ROAM = 64, + + /* + * APIs corresponding to the sub commands 65-68 are deprecated. + * These sub commands are reserved and not supposed to be used + * for any other purpose + */ + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_PNO_SET_LIST = 69, + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_PNO_SET_PASSPOINT_LIST = 70, + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_PNO_RESET_PASSPOINT_LIST = 71, + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_PNO_NETWORK_FOUND = 72, + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_PNO_PASSPOINT_NETWORK_FOUND = 73, + + /* Wi-Fi Configuration subcommands */ + QCA_NL80211_VENDOR_SUBCMD_SET_WIFI_CONFIGURATION = 74, + QCA_NL80211_VENDOR_SUBCMD_GET_WIFI_CONFIGURATION = 75, + QCA_NL80211_VENDOR_SUBCMD_GET_LOGGER_FEATURE_SET = 76, + QCA_NL80211_VENDOR_SUBCMD_GET_RING_DATA = 77, + + QCA_NL80211_VENDOR_SUBCMD_TDLS_GET_CAPABILITIES = 78, + QCA_NL80211_VENDOR_SUBCMD_OFFLOADED_PACKETS = 79, + QCA_NL80211_VENDOR_SUBCMD_MONITOR_RSSI = 80, + QCA_NL80211_VENDOR_SUBCMD_NDP = 81, + + /* NS Offload enable/disable cmd */ + QCA_NL80211_VENDOR_SUBCMD_ND_OFFLOAD = 82, + + QCA_NL80211_VENDOR_SUBCMD_PACKET_FILTER = 83, + QCA_NL80211_VENDOR_SUBCMD_GET_BUS_SIZE = 84, + + QCA_NL80211_VENDOR_SUBCMD_GET_WAKE_REASON_STATS = 85, + + /* OCB commands */ + QCA_NL80211_VENDOR_SUBCMD_OCB_SET_CONFIG = 92, + QCA_NL80211_VENDOR_SUBCMD_OCB_SET_UTC_TIME = 93, + QCA_NL80211_VENDOR_SUBCMD_OCB_START_TIMING_ADVERT = 94, + QCA_NL80211_VENDOR_SUBCMD_OCB_STOP_TIMING_ADVERT = 95, + QCA_NL80211_VENDOR_SUBCMD_OCB_GET_TSF_TIMER = 96, + QCA_NL80211_VENDOR_SUBCMD_DCC_GET_STATS = 97, + QCA_NL80211_VENDOR_SUBCMD_DCC_CLEAR_STATS = 98, + QCA_NL80211_VENDOR_SUBCMD_DCC_UPDATE_NDL = 99, + QCA_NL80211_VENDOR_SUBCMD_DCC_STATS_EVENT = 100, + + /* subcommand to get link properties */ + QCA_NL80211_VENDOR_SUBCMD_LINK_PROPERTIES = 101, + /* LFR Subnet Detection */ + QCA_NL80211_VENDOR_SUBCMD_GW_PARAM_CONFIG = 102, + + /* DBS subcommands */ + QCA_NL80211_VENDOR_SUBCMD_GET_PREFERRED_FREQ_LIST = 103, + QCA_NL80211_VENDOR_SUBCMD_SET_PROBABLE_OPER_CHANNEL = 104, + + /* Vendor setband command */ + QCA_NL80211_VENDOR_SUBCMD_SETBAND = 105, + + /* Vendor scan commands */ + QCA_NL80211_VENDOR_SUBCMD_TRIGGER_SCAN = 106, + QCA_NL80211_VENDOR_SUBCMD_SCAN_DONE = 107, + + /* OTA test subcommand */ + QCA_NL80211_VENDOR_SUBCMD_OTA_TEST = 108, + /* Tx power scaling subcommands */ + QCA_NL80211_VENDOR_SUBCMD_SET_TXPOWER_SCALE = 109, + /* Tx power scaling in db subcommands */ + QCA_NL80211_VENDOR_SUBCMD_SET_TXPOWER_SCALE_DECR_DB = 115, + QCA_NL80211_VENDOR_SUBCMD_ACS_POLICY = 116, + QCA_NL80211_VENDOR_SUBCMD_STA_CONNECT_ROAM_POLICY = 117, + QCA_NL80211_VENDOR_SUBCMD_SET_SAP_CONFIG = 118, + QCA_NL80211_VENDOR_SUBCMD_TSF = 119, + QCA_NL80211_VENDOR_SUBCMD_WISA = 120, + QCA_NL80211_VENDOR_SUBCMD_GET_STATION = 121, + QCA_NL80211_VENDOR_SUBCMD_P2P_LISTEN_OFFLOAD_START = 122, + QCA_NL80211_VENDOR_SUBCMD_P2P_LISTEN_OFFLOAD_STOP = 123, + QCA_NL80211_VENDOR_SUBCMD_SAP_CONDITIONAL_CHAN_SWITCH = 124, + + /* Encrypt/Decrypt command */ + QCA_NL80211_VENDOR_SUBCMD_ENCRYPTION_TEST = 137, + + /* Configure the TDLS mode from user space */ + QCA_NL80211_VENDOR_SUBCMD_CONFIGURE_TDLS = 143, + + /* Vendor abort scan command */ + QCA_NL80211_VENDOR_SUBCMD_ABORT_SCAN = 145, + + /* Set Specific Absorption Rate(SAR) Power Limits */ + QCA_NL80211_VENDOR_SUBCMD_SET_SAR_LIMITS = 146, + QCA_NL80211_VENDOR_SUBCMD_CHIP_PWRSAVE_FAILURE = 148, + QCA_NL80211_VENDOR_SUBCMD_NUD_STATS_SET = 149, + QCA_NL80211_VENDOR_SUBCMD_NUD_STATS_GET = 150, +}; + +/** + * enum qca_wlan_vendor_attr_get_station - Sub commands used by + * QCA_NL80211_VENDOR_SUBCMD_GET_STATION to get the corresponding + * station information. The information obtained through these + * commands signify the current info in connected state and + * latest cached information during the connected state , if queried + * when in disconnected state. + * + * @QCA_WLAN_VENDOR_ATTR_GET_STATION_INVALID: Invalid attribute + * @QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO: bss info + * @QCA_WLAN_VENDOR_ATTR_GET_STATION_ASSOC_FAIL_REASON: assoc fail reason + * @QCA_WLAN_VENDOR_ATTR_GET_STATION_AFTER_LAST: After last + */ +enum qca_wlan_vendor_attr_get_station { + QCA_WLAN_VENDOR_ATTR_GET_STATION_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO, + QCA_WLAN_VENDOR_ATTR_GET_STATION_ASSOC_FAIL_REASON, + + /* keep last */ + QCA_WLAN_VENDOR_ATTR_GET_STATION_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_GET_STATION_MAX = + QCA_WLAN_VENDOR_ATTR_GET_STATION_AFTER_LAST - 1, +}; + +/** + * enum qca_wlan_802_11_mode - dot11 mode + * @QCA_WLAN_802_11_MODE_INVALID: Invalid dot11 mode + * @QCA_WLAN_802_11_MODE_11A: mode A + * @QCA_WLAN_802_11_MODE_11B: mode B + * @QCA_WLAN_802_11_MODE_11G: mode G + * @QCA_WLAN_802_11_MODE_11N: mode N + * @QCA_WLAN_802_11_MODE_11AC: mode AC + */ +enum qca_wlan_802_11_mode { + QCA_WLAN_802_11_MODE_INVALID, + QCA_WLAN_802_11_MODE_11A, + QCA_WLAN_802_11_MODE_11B, + QCA_WLAN_802_11_MODE_11G, + QCA_WLAN_802_11_MODE_11N, + QCA_WLAN_802_11_MODE_11AC, +}; + +/** + * enum qca_wlan_auth_type - Authentication key management type + * @QCA_WLAN_AUTH_TYPE_INVALID: Invalid key management type + * @QCA_WLAN_AUTH_TYPE_OPEN: Open key + * @QCA_WLAN_AUTH_TYPE_SHARED: shared key + * @QCA_WLAN_AUTH_TYPE_WPA: wpa key + * @QCA_WLAN_AUTH_TYPE_WPA_PSK: wpa psk key + * @QCA_WLAN_AUTH_TYPE_WPA_NONE: wpa none key + * @QCA_WLAN_AUTH_TYPE_RSN: rsn key + * @QCA_WLAN_AUTH_TYPE_RSN_PSK: rsn psk key + * @QCA_WLAN_AUTH_TYPE_FT: ft key + * @QCA_WLAN_AUTH_TYPE_FT_PSK: ft psk key + * @QCA_WLAN_AUTH_TYPE_SHA256: shared 256 key + * @QCA_WLAN_AUTH_TYPE_SHA256_PSK: shared 256 psk + * @QCA_WLAN_AUTH_TYPE_WAI: wai key + * @QCA_WLAN_AUTH_TYPE_WAI_PSK wai psk key + * @QCA_WLAN_AUTH_TYPE_CCKM_WPA: cckm wpa key + * @QCA_WLAN_AUTH_TYPE_CCKM_RSN: cckm rsn key + */ +enum qca_wlan_auth_type { + QCA_WLAN_AUTH_TYPE_INVALID, + QCA_WLAN_AUTH_TYPE_OPEN, + QCA_WLAN_AUTH_TYPE_SHARED, + QCA_WLAN_AUTH_TYPE_WPA, + QCA_WLAN_AUTH_TYPE_WPA_PSK, + QCA_WLAN_AUTH_TYPE_WPA_NONE, + QCA_WLAN_AUTH_TYPE_RSN, + QCA_WLAN_AUTH_TYPE_RSN_PSK, + QCA_WLAN_AUTH_TYPE_FT, + QCA_WLAN_AUTH_TYPE_FT_PSK, + QCA_WLAN_AUTH_TYPE_SHA256, + QCA_WLAN_AUTH_TYPE_SHA256_PSK, + QCA_WLAN_AUTH_TYPE_WAI, + QCA_WLAN_AUTH_TYPE_WAI_PSK, + QCA_WLAN_AUTH_TYPE_CCKM_WPA, + QCA_WLAN_AUTH_TYPE_CCKM_RSN, + QCA_WLAN_AUTH_TYPE_AUTOSWITCH, +}; + +/** + * enum qca_wlan_vendor_attr_get_station_info - Station Info queried + * through QCA_NL80211_VENDOR_SUBCMD_GET_STATION. + * + * @QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_INVALID: Invalid Attribute + * @QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_LINK_STANDARD_NL80211_ATTR: + * Get the standard NL attributes Nested with this attribute. + * Ex : Query BW , BITRATE32 , NSS , Signal , Noise of the Link - + * NL80211_ATTR_SSID / NL80211_ATTR_SURVEY_INFO (Connected Channel) / + * NL80211_ATTR_STA_INFO + * @QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_AP_STANDARD_NL80211_ATTR: + * Get the standard NL attributes Nested with this attribute. + * Ex : Query HT/VHT Capability advertized by the AP. + * NL80211_ATTR_VHT_CAPABILITY / NL80211_ATTR_HT_CAPABILITY + * @QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_ROAM_COUNT: + * Number of successful Roam attempts before a + * disconnect, Unsigned 32 bit value + * @QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_AKM: + * Authentication Key Management Type used for the connected session. + * Signified by enum qca_wlan_auth_type + * @QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_802_11_MODE: 802.11 Mode of the + * connected Session, signified by enum qca_wlan_802_11_mode + * @QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_AP_HS20_INDICATION: + * HS20 Indication Element + * @QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_ASSOC_FAIL_REASON: + * Status Code Corresponding to the Association Failure. + * Unsigned 32 bit value. + * @QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_AFTER_LAST: After last + */ +enum qca_wlan_vendor_attr_get_station_info { + QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_LINK_STANDARD_NL80211_ATTR, + QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_AP_STANDARD_NL80211_ATTR, + QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_ROAM_COUNT, + QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_AKM, + QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_802_11_MODE, + QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_AP_HS20_INDICATION, + QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_HT_OPERATION, + QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_VHT_OPERATION, + QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_ASSOC_FAIL_REASON, + /* keep last */ + QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_MAX = + QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_AFTER_LAST - 1, +}; + +/* define short names for get station info attributes */ +#define LINK_INFO_STANDARD_NL80211_ATTR \ + QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_LINK_STANDARD_NL80211_ATTR +#define AP_INFO_STANDARD_NL80211_ATTR \ + QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_AP_STANDARD_NL80211_ATTR +#define INFO_ROAM_COUNT \ + QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_ROAM_COUNT +#define INFO_AKM \ + QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_AKM +#define WLAN802_11_MODE \ + QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_802_11_MODE +#define AP_INFO_HS20_INDICATION \ + QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_AP_HS20_INDICATION +#define HT_OPERATION \ + QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_HT_OPERATION +#define VHT_OPERATION \ + QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_VHT_OPERATION +#define INFO_ASSOC_FAIL_REASON \ + QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_ASSOC_FAIL_REASON + +/** + * enum qca_nl80211_vendor_subcmds_index - vendor sub commands index + * + * @QCA_NL80211_VENDOR_SUBCMD_AVOID_FREQUENCY_INDEX: Avoid frequency + * @QCA_NL80211_VENDOR_SUBCMD_NAN_INDEX: Nan + * @QCA_NL80211_VENDOR_SUBCMD_STATS_EXT_INDEX: Ext stats + * @QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_START_INDEX: Ext scan start + * @QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_STOP_INDEX: Ext scan stop + * @QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_GET_CAPABILITIES_INDEX: Ext scan get + * capability + * @QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_GET_CACHED_RESULTS_INDEX: Ext scan get + * cached results + * @QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SCAN_RESULTS_AVAILABLE_INDEX: Ext scan + * results available + * @QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_FULL_SCAN_RESULT_INDEX: Ext scan full + * scan result + * @QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SCAN_EVENT_INDEX: Ext scan event + * @QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_HOTLIST_AP_FOUND_INDEX: Ext scan hot list + * AP found + * @QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SET_BSSID_HOTLIST_INDEX: Ext scan set + * bssid hotlist + * @QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_RESET_BSSID_HOTLIST_INDEX: Ext scan reset + * bssid hotlist + * @QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SIGNIFICANT_CHANGE_INDEX: Ext scan + * significant change + * @QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SET_SIGNIFICANT_CHANGE_INDEX: Ext scan + * set significant change + * @QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_RESET_SIGNIFICANT_CHANGE_INDEX: Ext scan + * reset significant change + * @QCA_NL80211_VENDOR_SUBCMD_LL_STATS_SET_INDEX: Set stats + * @QCA_NL80211_VENDOR_SUBCMD_LL_STATS_GET_INDEX: Get stats + * @QCA_NL80211_VENDOR_SUBCMD_LL_STATS_CLR_INDEX: Clear stats + * @QCA_NL80211_VENDOR_SUBCMD_LL_RADIO_STATS_INDEX: Radio stats + * @QCA_NL80211_VENDOR_SUBCMD_LL_IFACE_STATS_INDEX: Iface stats + * @QCA_NL80211_VENDOR_SUBCMD_LL_PEER_INFO_STATS_INDEX: Peer info stats + * @QCA_NL80211_VENDOR_SUBCMD_TDLS_STATE_CHANGE_INDEX: Ext tdls state change + * @QCA_NL80211_VENDOR_SUBCMD_DO_ACS_INDEX: ACS command + * @QCA_NL80211_VENDOR_SUBCMD_KEY_MGMT_ROAM_AUTH_INDEX: Pass Roam and Auth info + * @QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_HOTLIST_AP_LOST_INDEX: hotlist ap lost + * @QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_PNO_NETWORK_FOUND_INDEX: + * pno network found index + * @QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_PNO_PASSPOINT_NETWORK_FOUND_INDEX: + * passpoint match found index + * @QCA_NL80211_VENDOR_SUBCMD_DCC_STATS_EVENT_INDEX + * dcc stats event index + * @QCA_NL80211_VENDOR_SUBCMD_SCAN_INDEX: vendor scan index + * @QCA_NL80211_VENDOR_SUBCMD_SCAN_DONE_INDEX: + * vendor scan complete event index + * @QCA_NL80211_VENDOR_SUBCMD_GW_PARAM_CONFIG_INDEX: + * update gateway parameters index + * @QCA_NL80211_VENDOR_SUBCMD_TSF_INDEX: TSF response events index + * @QCA_NL80211_VENDOR_SUBCMD_P2P_LO_EVENT_INDEX: + * P2P listen offload index + * @QCA_NL80211_VENDOR_SUBCMD_SAP_CONDITIONAL_CHAN_SWITCH_INDEX: SAP + * conditional channel switch index + * @QCA_NL80211_VENDOR_SUBCMD_NUD_STATS_GET_INDEX: NUD DEBUG Stats index + */ + +enum qca_nl80211_vendor_subcmds_index { +#if defined(FEATURE_WLAN_CH_AVOID) || defined(FEATURE_WLAN_FORCE_SAP_SCC) + QCA_NL80211_VENDOR_SUBCMD_AVOID_FREQUENCY_INDEX = 0, +#endif /* FEATURE_WLAN_CH_AVOID || FEATURE_WLAN_FORCE_SAP_SCC */ + +#ifdef WLAN_FEATURE_NAN + QCA_NL80211_VENDOR_SUBCMD_NAN_INDEX, +#endif /* WLAN_FEATURE_NAN */ + +#ifdef WLAN_FEATURE_STATS_EXT + QCA_NL80211_VENDOR_SUBCMD_STATS_EXT_INDEX, +#endif /* WLAN_FEATURE_STATS_EXT */ + +#ifdef FEATURE_WLAN_EXTSCAN + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_START_INDEX, + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_STOP_INDEX, + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_GET_CAPABILITIES_INDEX, + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_GET_CACHED_RESULTS_INDEX, + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SCAN_RESULTS_AVAILABLE_INDEX, + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_FULL_SCAN_RESULT_INDEX, + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SCAN_EVENT_INDEX, + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_HOTLIST_AP_FOUND_INDEX, + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SET_BSSID_HOTLIST_INDEX, + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_RESET_BSSID_HOTLIST_INDEX, + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SIGNIFICANT_CHANGE_INDEX, + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SET_SIGNIFICANT_CHANGE_INDEX, + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_RESET_SIGNIFICANT_CHANGE_INDEX, +#endif /* FEATURE_WLAN_EXTSCAN */ + +#ifdef WLAN_FEATURE_LINK_LAYER_STATS + QCA_NL80211_VENDOR_SUBCMD_LL_STATS_SET_INDEX, + QCA_NL80211_VENDOR_SUBCMD_LL_STATS_GET_INDEX, + QCA_NL80211_VENDOR_SUBCMD_LL_STATS_CLR_INDEX, + QCA_NL80211_VENDOR_SUBCMD_LL_RADIO_STATS_INDEX, + QCA_NL80211_VENDOR_SUBCMD_LL_IFACE_STATS_INDEX, + QCA_NL80211_VENDOR_SUBCMD_LL_PEER_INFO_STATS_INDEX, +#endif /* WLAN_FEATURE_LINK_LAYER_STATS */ + + QCA_NL80211_VENDOR_SUBCMD_TDLS_STATE_CHANGE_INDEX, + QCA_NL80211_VENDOR_SUBCMD_DO_ACS_INDEX, +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + QCA_NL80211_VENDOR_SUBCMD_KEY_MGMT_ROAM_AUTH_INDEX, +#endif + /* DFS */ + QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_STARTED_INDEX, + QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_FINISHED_INDEX, + QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_ABORTED_INDEX, + QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_NOP_FINISHED_INDEX, + QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_RADAR_DETECTED_INDEX, +#ifdef FEATURE_WLAN_EXTSCAN + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_HOTLIST_AP_LOST_INDEX, + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_PNO_NETWORK_FOUND_INDEX, + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_PNO_PASSPOINT_NETWORK_FOUND_INDEX, +#endif /* FEATURE_WLAN_EXTSCAN */ + QCA_NL80211_VENDOR_SUBCMD_MONITOR_RSSI_INDEX, +#ifdef WLAN_FEATURE_MEMDUMP + QCA_NL80211_VENDOR_SUBCMD_WIFI_LOGGER_MEMORY_DUMP_INDEX, +#endif /* WLAN_FEATURE_MEMDUMP */ + /* OCB events */ + QCA_NL80211_VENDOR_SUBCMD_DCC_STATS_EVENT_INDEX, + QCA_NL80211_VENDOR_SUBCMD_SCAN_INDEX, + QCA_NL80211_VENDOR_SUBCMD_SCAN_DONE_INDEX, + QCA_NL80211_VENDOR_SUBCMD_GW_PARAM_CONFIG_INDEX, +#ifdef WLAN_FEATURE_TSF + QCA_NL80211_VENDOR_SUBCMD_TSF_INDEX, +#endif +#ifdef WLAN_FEATURE_NAN_DATAPATH + QCA_NL80211_VENDOR_SUBCMD_NDP_INDEX, +#endif /* WLAN_FEATURE_NAN_DATAPATH */ + QCA_NL80211_VENDOR_SUBCMD_P2P_LO_EVENT_INDEX, + QCA_NL80211_VENDOR_SUBCMD_SAP_CONDITIONAL_CHAN_SWITCH_INDEX, + QCA_NL80211_VENDOR_SUBCMD_NUD_STATS_GET_INDEX, + QCA_NL80211_VENDOR_SUBCMD_PWR_SAVE_FAIL_DETECTED_INDEX, +}; + +/** + * enum qca_attr_nud_stats_set - attribute to vendor subcmd + * QCA_NL80211_VENDOR_SUBCMD_NUD_STATS_SET. This carry the requisite + * information to start / stop the NUD stats collection. + * @QCA_ATTR_NUD_STATS_SET_START: set nud debug stats + * Flag to Start / Stop the NUD stats collection + * Start - If included , Stop - If not included + * @QCA_ATTR_NUD_STATS_GW_IPV4: set gatway ipv4 address + * IPv4 address of Default Gateway (in network byte order) + */ +enum qca_attr_nud_stats_set { + QCA_ATTR_NUD_STATS_SET_INVALID = 0, + QCA_ATTR_NUD_STATS_SET_START = 1, + QCA_ATTR_NUD_STATS_GW_IPV4 = 2, + /* keep last */ + QCA_ATTR_NUD_STATS_SET_LAST, + QCA_ATTR_NUD_STATS_SET_MAX = + QCA_ATTR_NUD_STATS_SET_LAST - 1, +}; + +/** + * enum qca_attr_nud_stats_get - attribute to vendor subcmd + * QCA_NL80211_VENDOR_SUBCMD_NUD_STATS_GET. This carry the requisite + * NUD stats collected when queried. + * @QCA_ATTR_NUD_STATS_ARP_REQ_COUNT_FROM_NETDEV: ARP Request Count from net + * dev + * @QCA_ATTR_NUD_STATS_ARP_REQ_COUNT_TO_LOWER_MAC: ARP Request Count sent + * to lower MAC from upper MAC + * @QCA_ATTR_NUD_STATS_ARP_REQ_RX_COUNT_BY_LOWER_MAC: ARP Request Count + * received by lower MAC from upper MAC + * @QCA_ATTR_NUD_STATS_ARP_REQ_COUNT_TX_SUCCESS: ARP Request Count successfully + * transmitted by the device + * @QCA_ATTR_NUD_STATS_ARP_RSP_RX_COUNT_BY_LOWER_MAC: ARP Response Count + * received by lower MAC + * @QCA_ATTR_NUD_STATS_ARP_RSP_RX_COUNT_BY_UPPER_MAC: ARP Response Count + * received by upper MAC + * @QCA_ATTR_NUD_STATS_ARP_RSP_COUNT_TO_NETDEV: ARP Response Count delivered + * to netdev + * @QCA_ATTR_NUD_STATS_ARP_RSP_COUNT_OUT_OF_ORDER_DROP: ARP Response Count + * delivered to netdev + * @QCA_ATTR_NUD_STATS_AP_LINK_ACTIVE: Flag indicating if the Stations + * Link to AP is active. + * Active Link - If exists, Inactive link - If not included + * @QCA_ATTR_NUD_STATS_AP_LINK_DAD: Flag indicating if the Stations + * Duplicate Address detected. + */ +enum qca_attr_nud_stats_get { + QCA_ATTR_NUD_STATS_GET_INVALID = 0, + QCA_ATTR_NUD_STATS_ARP_REQ_COUNT_FROM_NETDEV = 1, + QCA_ATTR_NUD_STATS_ARP_REQ_COUNT_TO_LOWER_MAC = 2, + QCA_ATTR_NUD_STATS_ARP_REQ_RX_COUNT_BY_LOWER_MAC = 3, + QCA_ATTR_NUD_STATS_ARP_REQ_COUNT_TX_SUCCESS = 4, + QCA_ATTR_NUD_STATS_ARP_RSP_RX_COUNT_BY_LOWER_MAC = 5, + QCA_ATTR_NUD_STATS_ARP_RSP_RX_COUNT_BY_UPPER_MAC = 6, + QCA_ATTR_NUD_STATS_ARP_RSP_COUNT_TO_NETDEV = 7, + QCA_ATTR_NUD_STATS_ARP_RSP_COUNT_OUT_OF_ORDER_DROP = 8, + QCA_ATTR_NUD_STATS_AP_LINK_ACTIVE = 9, + QCA_ATTR_NUD_STATS_AP_LINK_DAD = 10, + /* keep last */ + QCA_ATTR_NUD_STATS_GET_LAST, + QCA_ATTR_NUD_STATS_GET_MAX = + QCA_ATTR_NUD_STATS_GET_LAST - 1, +}; + +/** + * enum qca_wlan_vendor_attr_tdls_enable - TDLS enable attribute + * + * @QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_INVALID: Invalid initial value + * @QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_MAC_ADDR: An array of 6 x Unsigned 8-bit + * value + * @QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_CHANNEL: Signed 32-bit value, but lets + * keep as unsigned for now + * @QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_GLOBAL_OPERATING_CLASS: operating class + * @QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_MAX_LATENCY_MS: Enable max latency in ms + * @QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_MIN_BANDWIDTH_KBPS: Enable min bandwidth + * in KBPS + * @QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_AFTER_LAST: After last + * @QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_MAX: Max value + */ +enum qca_wlan_vendor_attr_tdls_enable { + QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_MAC_ADDR, + QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_CHANNEL, + QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_GLOBAL_OPERATING_CLASS, + QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_MAX_LATENCY_MS, + QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_MIN_BANDWIDTH_KBPS, + QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_MAX = + QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_AFTER_LAST - 1, +}; + +/** + * enum qca_wlan_vendor_attr_tdls_disable: tdls disable attribute + * + * @QCA_WLAN_VENDOR_ATTR_TDLS_DISABLE_INVALID: Invalid initial value + * @QCA_WLAN_VENDOR_ATTR_TDLS_DISABLE_MAC_ADDR: An array of 6 x Unsigned + * 8-bit value + * @QCA_WLAN_VENDOR_ATTR_TDLS_DISABLE_AFTER_LAST: After last + * @QCA_WLAN_VENDOR_ATTR_TDLS_DISABLE_MAX: Max value + */ +enum qca_wlan_vendor_attr_tdls_disable { + QCA_WLAN_VENDOR_ATTR_TDLS_DISABLE_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_TDLS_DISABLE_MAC_ADDR, + QCA_WLAN_VENDOR_ATTR_TDLS_DISABLE_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_TDLS_DISABLE_MAX = + QCA_WLAN_VENDOR_ATTR_TDLS_DISABLE_AFTER_LAST - 1, +}; + +/** + * qca_chip_power_save_failure_reason: Power save failure reason + * @QCA_CHIP_POWER_SAVE_FAILURE_REASON_PROTOCOL: Indicates power save failure + * due to protocol/module. + * @QCA_CHIP_POWER_SAVE_FAILURE_REASON_HARDWARE: power save failure + * due to hardware + */ +enum qca_chip_power_save_failure_reason { + QCA_CHIP_POWER_SAVE_FAILURE_REASON_PROTOCOL = 0, + QCA_CHIP_POWER_SAVE_FAILURE_REASON_HARDWARE = 1, +}; + +/** + * qca_attr_chip_power_save_failure: attributes to vendor subcmd + * @QCA_NL80211_VENDOR_SUBCMD_CHIP_PWRSAVE_FAILURE. This carry the requisite + * information leading to the power save failure. + * @QCA_ATTR_CHIP_POWER_SAVE_FAILURE_INVALID : invalid + * @QCA_ATTR_CHIP_POWER_SAVE_FAILURE_REASON : power save failure reason + * represented by enum qca_chip_power_save_failure_reason + * @QCA_ATTR_CHIP_POWER_SAVE_FAILURE_LAST : Last + * @QCA_ATTR_CHIP_POWER_SAVE_FAILURE_MAX : Max value + */ +enum qca_attr_chip_power_save_failure { + QCA_ATTR_CHIP_POWER_SAVE_FAILURE_INVALID = 0, + + QCA_ATTR_CHIP_POWER_SAVE_FAILURE_REASON = 1, + + /* keep last */ + QCA_ATTR_CHIP_POWER_SAVE_FAILURE_LAST, + QCA_ATTR_CHIP_POWER_SAVE_FAILURE_MAX = + QCA_ATTR_CHIP_POWER_SAVE_FAILURE_LAST - 1, +}; + +/** + * enum qca_wlan_vendor_attr_tdls_get_status - tdls get status attribute + * + * @QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_INVALID: Invalid initial value + * @QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_MAC_ADDR: An array of 6 x Unsigned + * 8-bit value + * @QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_STATE: get status state, + * unsigned 32-bit value + * @QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_REASON: get status reason + * @QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_CHANNEL: get status channel, + * unsigned 32-bit value + * @QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_GLOBAL_OPERATING_CLASS: get operating + * class, unsigned 32-bit value + * @QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_AFTER_LAST: After last + * @QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_MAX: Max value + */ +enum qca_wlan_vendor_attr_tdls_get_status { + QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_MAC_ADDR, + QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_STATE, + QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_REASON, + QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_CHANNEL, + QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_GLOBAL_OPERATING_CLASS, + QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_MAX = + QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_AFTER_LAST - 1, +}; + +/** + * enum qca_wlan_vendor_attr_tdls_state - tdls state attribute + * + * @QCA_WLAN_VENDOR_ATTR_TDLS_STATE_INVALID: Initial invalid value + * @QCA_WLAN_VENDOR_ATTR_TDLS_STATE_MAC_ADDR: An array of 6 x Unsigned + * 8-bit value + * @QCA_WLAN_VENDOR_ATTR_TDLS_NEW_STATE: TDLS new state, + * unsigned 32-bit value + * @QCA_WLAN_VENDOR_ATTR_TDLS_STATE_REASON: TDLS state reason + * @QCA_WLAN_VENDOR_ATTR_TDLS_STATE_CHANNEL: TDLS state channel, + * unsigned 32-bit value + * @QCA_WLAN_VENDOR_ATTR_TDLS_STATE_GLOBAL_OPERATING_CLASS: TDLS state + * operating class, unsigned 32-bit value + * @QCA_WLAN_VENDOR_ATTR_TDLS_STATE_AFTER_LAST: After last + * @QCA_WLAN_VENDOR_ATTR_TDLS_STATE_MAX: Max value + */ +enum qca_wlan_vendor_attr_tdls_state { + QCA_WLAN_VENDOR_ATTR_TDLS_STATE_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_TDLS_STATE_MAC_ADDR, + QCA_WLAN_VENDOR_ATTR_TDLS_NEW_STATE, + QCA_WLAN_VENDOR_ATTR_TDLS_STATE_REASON, + QCA_WLAN_VENDOR_ATTR_TDLS_STATE_CHANNEL, + QCA_WLAN_VENDOR_ATTR_TDLS_STATE_GLOBAL_OPERATING_CLASS, + QCA_WLAN_VENDOR_ATTR_TDLS_STATE_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_TDLS_STATE_MAX = + QCA_WLAN_VENDOR_ATTR_TDLS_STATE_AFTER_LAST - 1, +}; + +/* enum's to provide TDLS capabilites */ +enum qca_wlan_vendor_attr_get_tdls_capabilities { + QCA_WLAN_VENDOR_ATTR_TDLS_GET_CAPS_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_TDLS_GET_CAPS_MAX_CONC_SESSIONS = 1, + QCA_WLAN_VENDOR_ATTR_TDLS_GET_CAPS_FEATURES_SUPPORTED = 2, + + /* keep last */ + QCA_WLAN_VENDOR_ATTR_TDLS_GET_CAPS_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_TDLS_GET_CAPS_MAX = + QCA_WLAN_VENDOR_ATTR_TDLS_GET_CAPS_AFTER_LAST - 1, +}; + +/** + * enum qca_wlan_vendor_attr - wlan vendor attribute + * + * @QCA_WLAN_VENDOR_ATTR_INVALID: Initial invalid value + * @QCA_WLAN_VENDOR_ATTR_DFS: DFS attribute which is used by + * QCA_NL80211_VENDOR_SUBCMD_DFS_CAPABILITY + * @QCA_WLAN_VENDOR_ATTR_NAN: NAN attribute which is used by + * QCA_NL80211_VENDOR_SUBCMD_NAN + * @QCA_WLAN_VENDOR_ATTR_STATS_EXT: Ext stats attribute which is used by + * QCA_NL80211_VENDOR_SUBCMD_STATS_EXT + * @QCA_WLAN_VENDOR_ATTR_IFINDEX: After IFINDEX + * @QCA_WLAN_VENDOR_ATTR_ROAMING_POLICY: Roaming policy which is used by + * QCA_NL80211_VENDOR_SUBCMD_ROAMING + * @QCA_WLAN_VENDOR_ATTR_MAC_ADDR: MAC Address attribute which is used by + * QCA_NL80211_VENDOR_SUBCMD_LINK_PROPERTIES + * @QCA_WLAN_VENDOR_ATTR_FEATURE_FLAGS: Supported Features + *@QCA_WLAN_VENDOR_ATTR_SETBAND_VALUE: setband attribute which is used by + * QCA_NL80211_VENDOR_SUBCMD_SETBAND + * @QCA_WLAN_VENDOR_ATTR_AFTER_LAST: After last + * @QCA_WLAN_VENDOR_ATTR_MAX: Max value + */ +enum qca_wlan_vendor_attr { + QCA_WLAN_VENDOR_ATTR_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_DFS = 1, + QCA_WLAN_VENDOR_ATTR_NAN = 2, + QCA_WLAN_VENDOR_ATTR_STATS_EXT = 3, + QCA_WLAN_VENDOR_ATTR_IFINDEX = 4, + QCA_WLAN_VENDOR_ATTR_ROAMING_POLICY = 5, + QCA_WLAN_VENDOR_ATTR_MAC_ADDR = 6, + QCA_WLAN_VENDOR_ATTR_FEATURE_FLAGS = 7, + QCA_WLAN_VENDOR_ATTR_CONCURRENCY_CAPA = 9, + QCA_WLAN_VENDOR_ATTR_MAX_CONCURRENT_CHANNELS_2_4_BAND = 10, + QCA_WLAN_VENDOR_ATTR_MAX_CONCURRENT_CHANNELS_5_0_BAND = 11, + QCA_WLAN_VENDOR_ATTR_SETBAND_VALUE = 12, + + /* keep last */ + QCA_WLAN_VENDOR_ATTR_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_MAX = QCA_WLAN_VENDOR_ATTR_AFTER_LAST - 1 +}; + +#ifdef FEATURE_WLAN_EXTSCAN +/** + * enum qca_wlan_vendor_attr_extscan_config_params - ext scan config params + * + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_INVALID: Invalid initial + * value + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID: + * Unsigned 32-bit value; Middleware provides it to the driver. Middle ware + * either gets it from caller, e.g., framework, or generates one if + * framework doesn't provide it. + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_GET_VALID_CHANNELS_CONFIG_PARAM_WIFI_BAND: + * NL attributes for data used by + * QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_GET_VALID_CHANNELS sub command. + * It is unsigned 32-bit value. + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_GET_VALID_CHANNELS_CONFIG_PARAM_MAX_CHANNELS: + * Unsigned 32-bit value + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_CHANNEL_SPEC_CHANNEL: + * NL attributes for input params used by + * QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_START sub command. Unsigned 32-bit + * value; channel frequency + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_CHANNEL_SPEC_DWELL_TIME: Unsigned 32-bit value; + * dwell time in ms + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_CHANNEL_SPEC_PASSIVE: Unsigned 8-bit value: + * 0: active; 1: passive; N/A for DFS + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_CHANNEL_SPEC_CLASS: Unsigned 8-bit value + * channel class + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_INDEX: Unsigned 8-bit value + * bucket index, 0 based + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_BAND: Unsigned 8-bit value; band + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_PERIOD: Unsigned 32-bit value; + * desired period, in ms + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_REPORT_EVENTS: Unsigned 8-bit + * value; report events semantics + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_NUM_CHANNEL_SPECS: Unsigned 32-bit + * value. Followed by a nested array of EXTSCAN_CHANNEL_SPEC_* attributes. + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_CHANNEL_SPEC: + * Array of QCA_WLAN_VENDOR_ATTR_EXTSCAN_CHANNEL_SPEC_* attributes. + * Array size: QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_NUM_CHANNEL_SPECS + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_SCAN_CMD_PARAMS_BASE_PERIOD: Unsigned 32-bit + * value; base timer period in ms + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_SCAN_CMD_PARAMS_MAX_AP_PER_SCAN: Unsigned + * 32-bit value; number of APs to store in each scan in the + * BSSID/RSSI history buffer (keep the highest RSSI APs) + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_SCAN_CMD_PARAMS_REPORT_THRESHOLD_PERCENT: + * Unsigned 8-bit value; in %, when scan buffer is this much full, + * wake up APPS. + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_SCAN_CMD_PARAMS_NUM_BUCKETS: Unsigned 8-bit + * value; number of scan bucket specs; followed by a nested array + * of_EXTSCAN_BUCKET_SPEC_* attributes and values. The size of the array + * is determined by NUM_BUCKETS + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC: Array of + * QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_* attributes. Array size: + * QCA_WLAN_VENDOR_ATTR_EXTSCAN_SCAN_CMD_PARAMS_NUM_BUCKETS + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_GET_CACHED_SCAN_RESULTS_CONFIG_PARAM_FLUSH: + * Unsigned 8-bit value + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_GET_CACHED_SCAN_RESULTS_CONFIG_PARAM_MAX: + * Unsigned 32-bit value; maximum number of results to be returned + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM_BSSID: An array of + * 6 x Unsigned 8-bit value + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM_RSSI_LOW: Signed 32-bit + * value + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM_RSSI_HIGH: Signed 32-bit + * value + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM_CHANNEL: Signed 32-bit + * value + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_BSSID_HOTLIST_PARAMS_NUM_AP: Number of hotlist + * APs as unsigned 32-bit value, followed by a nested array of + * AP_THRESHOLD_PARAM attributes and values. The size of the array is + * determined by NUM_AP. + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM: Array of + * QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM_* attributes. + * Array size: QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_NUM_CHANNEL_SPECS + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_SIGNIFICANT_CHANGE_PARAMS_RSSI_SAMPLE_SIZE: + * Unsigned 32bit value; number of samples for averaging RSSI + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_SIGNIFICANT_CHANGE_PARAMS_LOST_AP_SAMPLE_SIZE: + * Unsigned 32bit value; number of samples to confirm AP loss + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_SIGNIFICANT_CHANGE_PARAMS_MIN_BREACHING: + * Unsigned 32bit value; number of APs breaching threshold. + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_SIGNIFICANT_CHANGE_PARAMS_NUM_AP: + * Unsigned 32bit value; number of APs. Followed by an array of + * AP_THRESHOLD_PARAM attributes. Size of the array is NUM_AP. + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_BSSID_HOTLIST_PARAMS_LOST_AP_SAMPLE_SIZE: + * Unsigned 32bit value; number of samples to confirm AP loss. + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_MAX_PERIOD: + * Unsigned 32-bit value. If max_period is non zero or different than + * period, then this bucket is an exponential backoff bucket. + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_BASE: + * Unsigned 32-bit value. For exponential back off bucket, + * number of scans to performed for a given period. + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_STEP_COUNT: + * Unsigned 8-bit value; in number of scans, wake up AP after these + * many scans. + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_SCAN_CMD_PARAMS_REPORT_THRESHOLD_NUM_SCANS: + * Unsigned 8-bit value; in number of scans, wake up AP after these + * many scans. + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_SSID_HOTLIST_PARAMS_LOST_SSID_SAMPLE_SIZE: + * Unsigned 32bit value; number of samples to confirm SSID loss + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_SSID_HOTLIST_PARAMS_NUM_SSID: + * Number of hotlist SSIDs as unsigned 32-bit value, followed by a nested + * array of SSID_THRESHOLD_PARAM_* attributes and values. The size of the + * array is determined by NUM_SSID + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_SSID_THRESHOLD_PARAM: + * Array of QCA_WLAN_VENDOR_ATTR_EXTSCAN_SSID_THRESHOLD_PARAM_* attributes + * Array size: QCA_WLAN_VENDOR_ATTR_EXTSCAN_SSID_HOTLIST_PARAMS_NUM_SSID + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_SSID_THRESHOLD_PARAM_SSID: + * An array of 33 x Unsigned 8-bit value; NULL terminated SSID + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_SSID_THRESHOLD_PARAM_BAND: + * Signed 32-bit value; band + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_SSID_THRESHOLD_PARAM_RSSI_LOW: + * Signed 32-bit value; low rssi + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_SSID_THRESHOLD_PARAM_RSSI_HIGH: + * Signed 32-bit value; high rssi + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_CONFIGURATION_FLAGS: + * Unsigned 32-bit value; a bitmask w/additional extscan config flag. + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_AFTER_LAST: After last + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX: Max value + */ +enum qca_wlan_vendor_attr_extscan_config_params { + QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_INVALID = 0, + + QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID, + + QCA_WLAN_VENDOR_ATTR_EXTSCAN_GET_VALID_CHANNELS_CONFIG_PARAM_WIFI_BAND, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_GET_VALID_CHANNELS_CONFIG_PARAM_MAX_CHANNELS, + + QCA_WLAN_VENDOR_ATTR_EXTSCAN_CHANNEL_SPEC_CHANNEL, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_CHANNEL_SPEC_DWELL_TIME, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_CHANNEL_SPEC_PASSIVE, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_CHANNEL_SPEC_CLASS, + + QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_INDEX, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_BAND, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_PERIOD, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_REPORT_EVENTS, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_NUM_CHANNEL_SPECS, + + QCA_WLAN_VENDOR_ATTR_EXTSCAN_CHANNEL_SPEC, + + QCA_WLAN_VENDOR_ATTR_EXTSCAN_SCAN_CMD_PARAMS_BASE_PERIOD, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_SCAN_CMD_PARAMS_MAX_AP_PER_SCAN, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_SCAN_CMD_PARAMS_REPORT_THRESHOLD_PERCENT, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_SCAN_CMD_PARAMS_NUM_BUCKETS, + + QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC, + + QCA_WLAN_VENDOR_ATTR_EXTSCAN_GET_CACHED_SCAN_RESULTS_CONFIG_PARAM_FLUSH, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_GET_CACHED_SCAN_RESULTS_CONFIG_PARAM_MAX, + + QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM_BSSID, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM_RSSI_LOW, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM_RSSI_HIGH, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM_CHANNEL, + + QCA_WLAN_VENDOR_ATTR_EXTSCAN_BSSID_HOTLIST_PARAMS_NUM_AP, + + QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM, + + QCA_WLAN_VENDOR_ATTR_EXTSCAN_SIGNIFICANT_CHANGE_PARAMS_RSSI_SAMPLE_SIZE, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_SIGNIFICANT_CHANGE_PARAMS_LOST_AP_SAMPLE_SIZE, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_SIGNIFICANT_CHANGE_PARAMS_MIN_BREACHING, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_SIGNIFICANT_CHANGE_PARAMS_NUM_AP, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_BSSID_HOTLIST_PARAMS_LOST_AP_SAMPLE_SIZE, + + QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_MAX_PERIOD, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_BASE, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_STEP_COUNT, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_SCAN_CMD_PARAMS_REPORT_THRESHOLD_NUM_SCANS, + + QCA_WLAN_VENDOR_ATTR_EXTSCAN_SSID_HOTLIST_PARAMS_LOST_SSID_SAMPLE_SIZE, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_SSID_HOTLIST_PARAMS_NUM_SSID, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_SSID_THRESHOLD_PARAM, + + QCA_WLAN_VENDOR_ATTR_EXTSCAN_SSID_THRESHOLD_PARAM_SSID, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_SSID_THRESHOLD_PARAM_BAND, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_SSID_THRESHOLD_PARAM_RSSI_LOW, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_SSID_THRESHOLD_PARAM_RSSI_HIGH, + + QCA_WLAN_VENDOR_ATTR_EXTSCAN_CONFIGURATION_FLAGS, + + QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX = + QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_AFTER_LAST - 1, +}; + +/** + * enum qca_wlan_vendor_attr_extscan_results - vendor attribute ext scan results + * + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_INVALID: Invalid initial value + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_REQUEST_ID: Unsigned 32-bit value + * must match the request Id supplied by Wi-Fi HAL in the corresponding + * subcmd NL msg + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_STATUS: Unsigned 32-bit value used to + * indicate the status response from firmware/driver for the vendor + * sub-command + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_NUM_CHANNELS: EXTSCAN Valid Channels + * attributes. Unsigned 32bit value followed by a nested array of CHANNELS + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CHANNELS: An array of NUM_CHANNELS x + * Unsigned 32bit value integers representing channel numbers. + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_SCAN_CACHE_SIZE: + * Unsigned 32bit value + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_SCAN_BUCKETS: + * Unsigned 32bit value + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_AP_CACHE_PER_SCAN: + * Unsigned 32bit value + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_RSSI_SAMPLE_SIZE: + * Unsigned 32bit value + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_SCAN_REPORTING_THRESHOLD: + * Unsigned 32bit value + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_HOTLIST_APS: + * Unsigned 32bit value + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_SIGNIFICANT_WIFI_CHANGE_APS: + * Unsigned 32bit value + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_BSSID_HISTORY_ENTRIES: + * Unsigned 32bit value + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_NUM_RESULTS_AVAILABLE: Unsigned 32-bit + * value + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_LIST: An array of + * NUM_RESULTS_AVAILABLE x QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_* + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_TIME_STAMP: Unsigned + * 64-bit value age of sample at the time of retrieval + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_SSID: 33 x unsigned 8-bit + * value; NULL terminated SSID + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_BSSID: An array of 6 x + * Unsigned 8-bit value + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_CHANNEL: Unsigned 32-bit + * value; channel frequency in MHz + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_RSSI: Signed 32-bit value + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_RTT: Unsigned 32-bit value + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_RTT_SD: Unsigned 32-bit + * value + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_BEACON_PERIOD: + * Unsigned 16-bit value + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_CAPABILITY: + * Unsigned 16-bit value + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_IE_LENGTH: + * Unsigned 32-bit value; size of the IE DATA blob + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_IE_DATA: + * An array of IE_LENGTH x Unsigned 8-bit value; blob of all the + * information elements found in the beacon; this data should be + * a packed list of wifi_information_element objects, one after + * the other. + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_MORE_DATA: + * Unsigned 8-bit value; set by driver to indicate more scan results are + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_EVENT_TYPE: Unsigned 8-bit value + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_EVENT_STATUS: Unsigned 32-bit + * value + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SIGNIFICANT_CHANGE_RESULT_BSSID: + * An array of 6 x Unsigned 8-bit value + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SIGNIFICANT_CHANGE_RESULT_CHANNEL: + * Unsigned 32-bit value + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SIGNIFICANT_CHANGE_RESULT_NUM_RSSI: + * Unsigned 32-bit value + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SIGNIFICANT_CHANGE_RESULT_RSSI_LIST: + * A nested array of signed 32-bit RSSI values. Size of the array is + * determined by (NUM_RSSI of SIGNIFICANT_CHANGE_RESULT_NUM_RSSI. + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_CACHED_RESULTS_LIST: + * An array of NUM_RESULTS_AVAILABLE x + * QCA_NL80211_VENDOR_ATTR_EXTSCAN_CACHED_RESULTS_* + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_CACHED_RESULTS_SCAN_ID: + * Unsigned 32-bit value; a unique identifier for the scan unit + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_CACHED_RESULTS_FLAGS: + * Unsigned 32-bit value; a bitmask w/additional information about scan + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_PNO_RESULTS_PASSPOINT_NETWORK_FOUND_NUM_MATCHES: + * Unsigned 32-bit value; number of found network matches + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_PNO_RESULTS_PASSPOINT_MATCH_RESULT_LIST: + * A nested array of + * QCA_WLAN_VENDOR_ATTR_EXTSCAN_PNO_RESULTS_PASSPOINT_MATCH_* + * attributes. Array size = + * *_ATTR_EXTSCAN_PNO_RESULTS_PASSPOINT_NETWORK_FOUND_NUM_MATCHES. + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_PNO_RESULTS_PASSPOINT_MATCH_ID: + * Unsigned 32-bit value; network block id for the matched network + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_PNO_RESULTS_PASSPOINT_MATCH_ANQP_LEN: + * Unsigned 32-bit value; ANQP length + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_PNO_RESULTS_PASSPOINT_MATCH_ANQP: + * An array size of PASSPOINT_MATCH_ANQP_LEN of unsigned 8-bit values; + * ANQP data in the information_element format. + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_HOTLIST_SSIDS: + * Unsigned 32bit value; Max hotlist ssids. + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_NUM_EPNO_NETS: + * Unsigned 32bit value; Max number of epno networks + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_NUM_EPNO_NETS_BY_SSID: + * Unsigned 32bit value; Max number of epno networks by ssid + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_NUM_WHITELISTED_SSID: + * Unsigned 32bit value; Max number of whitelisted ssids + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_BUCKETS_SCANNED: + * Unsigned 32bit value, Bit mask of all buckets scanned in the + * current EXTSCAN CYCLE. For e.g. If fw scan is going to scan + * following buckets 0, 1, 2 in current cycle then it will be (0x111) + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_MAX_NUM_BLACKLISTED_BSSID: + * Unsigned 32bit value; a EXTSCAN Capabilities attribute to send + * maximum umber of blacklist bssid's that firmware can support. + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_AFTER_LAST: After last + * @QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_MAX: Max value + */ +enum qca_wlan_vendor_attr_extscan_results { + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_INVALID = 0, + + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_REQUEST_ID, + + QCA_WLAN_VENDOR_ATTR_EXTSCAN_STATUS, + + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_NUM_CHANNELS, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CHANNELS, + + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_SCAN_CACHE_SIZE, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_SCAN_BUCKETS, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_AP_CACHE_PER_SCAN, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_RSSI_SAMPLE_SIZE, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_SCAN_REPORTING_THRESHOLD, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_HOTLIST_BSSIDS, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_SIGNIFICANT_WIFI_CHANGE_APS, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_BSSID_HISTORY_ENTRIES, + + QCA_WLAN_VENDOR_ATTR_EXTSCAN_NUM_RESULTS_AVAILABLE, + + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_LIST, + + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_TIME_STAMP, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_SSID, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_BSSID, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_CHANNEL, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_RSSI, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_RTT, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_RTT_SD, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_BEACON_PERIOD, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_CAPABILITY, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_IE_LENGTH, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_IE_DATA, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_MORE_DATA, + + /* Use attr QCA_WLAN_VENDOR_ATTR_EXTSCAN_NUM_RESULTS_AVAILABLE + * to indicate number of wifi scan results/bssids retrieved by the scan. + * Also, use QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_LIST to indicate the + * list of wifi scan results returned for each cached result block. + */ + + /* EXTSCAN attributes for + * QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SCAN_EVENT sub-command. + */ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_EVENT_TYPE, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_EVENT_STATUS, + + /* EXTSCAN attributes for + * QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_HOTLIST_AP_FOUND sub-command. + */ + /* Use attr QCA_WLAN_VENDOR_ATTR_EXTSCAN_NUM_RESULTS_AVAILABLE + * to indicate number of results. + */ + + /* EXTSCAN attributes for + * QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SIGNIFICANT_CHANGE sub-command. + */ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SIGNIFICANT_CHANGE_RESULT_BSSID, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SIGNIFICANT_CHANGE_RESULT_CHANNEL, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SIGNIFICANT_CHANGE_RESULT_NUM_RSSI, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SIGNIFICANT_CHANGE_RESULT_RSSI_LIST, + + /* EXTSCAN attributes used with + * QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_GET_CACHED_RESULTS sub-command. + */ + /* Use attr QCA_WLAN_VENDOR_ATTR_EXTSCAN_NUM_RESULTS_AVAILABLE + * to indicate number of gscan cached results returned. + * Also, use QCA_WLAN_VENDOR_ATTR_EXTSCAN_CACHED_RESULTS_LIST to + * indicate the list of gscan cached results. + */ + + QCA_WLAN_VENDOR_ATTR_EXTSCAN_CACHED_RESULTS_LIST, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_CACHED_RESULTS_SCAN_ID, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_CACHED_RESULTS_FLAGS, + /* Use attr QCA_WLAN_VENDOR_ATTR_EXTSCAN_NUM_RESULTS_AVAILABLE + * to indicate number of wifi scan results/bssids retrieved by the scan. + * Also, use QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_LIST to indicate the + * list of wifi scan results returned for each cached result block. + */ + + /* EXTSCAN attributes for + * QCA_NL80211_VENDOR_SUBCMD_PNO_NETWORK_FOUND sub-command. + */ + /* Use QCA_WLAN_VENDOR_ATTR_EXTSCAN_NUM_RESULTS_AVAILABLE for number + * of results. + * Use QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_LIST to indicate the nested + * list of wifi scan results returned for each + * wifi_passpoint_match_result block. + * Array size: QCA_WLAN_VENDOR_ATTR_EXTSCAN_NUM_RESULTS_AVAILABLE. + */ + + /* EXTSCAN attributes for + * QCA_NL80211_VENDOR_SUBCMD_PNO_PASSPOINT_NETWORK_FOUND sub-command. + */ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_PNO_RESULTS_PASSPOINT_NETWORK_FOUND_NUM_MATCHES, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_PNO_RESULTS_PASSPOINT_MATCH_RESULT_LIST, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_PNO_RESULTS_PASSPOINT_MATCH_ID, + /* Use QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_LIST to indicate the nested + * list of wifi scan results returned for each + * wifi_passpoint_match_result block. + */ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_PNO_RESULTS_PASSPOINT_MATCH_ANQP_LEN, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_PNO_RESULTS_PASSPOINT_MATCH_ANQP, + + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_HOTLIST_SSIDS, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_NUM_EPNO_NETS, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_NUM_EPNO_NETS_BY_SSID, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_NUM_WHITELISTED_SSID, + + /* Use attr QCA_WLAN_VENDOR_ATTR_EXTSCAN_NUM_RESULTS_AVAILABLE + * to indicate number of results. + */ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_BUCKETS_SCANNED, + + QCA_WLAN_VENDOR_ATTR_EXTSCAN_MAX_NUM_BLACKLISTED_BSSID, + + /* keep last */ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_MAX = + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_AFTER_LAST - 1, +}; + +#endif + +#ifdef WLAN_FEATURE_LINK_LAYER_STATS + +/** + * enum qca_wlan_vendor_attr_ll_stats_set - vendor attribute set stats + * + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_INVALID: Invalid initial value + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_CONFIG_MPDU_SIZE_THRESHOLD: Size threshold + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_CONFIG_AGGRESSIVE_STATS_GATHERING: + * Aggresive stats gathering + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_AFTER_LAST: After last + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_MAX: Max value + */ +enum qca_wlan_vendor_attr_ll_stats_set { + QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_CONFIG_MPDU_SIZE_THRESHOLD = 1, + QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_CONFIG_AGGRESSIVE_STATS_GATHERING, + /* keep last */ + QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_MAX = + QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_AFTER_LAST - 1 +}; + +/** + * enum qca_wlan_vendor_attr_ll_stats_get - vendor attribute get stats + * + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_INVALID: Invalid initial value + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_CONFIG_REQ_ID: Unsigned 32bit value + * provided by the caller issuing the GET stats command. When reporting + * the stats results, the driver uses the same value to indicate which + * GET request the results correspond to. + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_CONFIG_REQ_MASK: Get config request mask + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_RSP_MASK: Config response mask + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_STOP_RSP: Config stop response + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_AFTER_LAST: After last + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_MAX: Max value + */ +enum qca_wlan_vendor_attr_ll_stats_get { + QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_CONFIG_REQ_ID, + QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_CONFIG_REQ_MASK, + QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_MAX = + QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_AFTER_LAST - 1 +}; + +/** + * enum qca_wlan_vendor_attr_ll_stats_clr - vendor attribute clear stats + * + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_INVALID: Invalid initial value + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_REQ_MASK: Config request mask + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_STOP_REQ: Config stop mask + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_RSP_MASK: Config response mask + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_STOP_RSP: Config stop response + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_AFTER_LAST: After last + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_MAX: Max value + */ +enum qca_wlan_vendor_attr_ll_stats_clr { + QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_REQ_MASK, + QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_STOP_REQ, + QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_RSP_MASK, + QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_STOP_RSP, + QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_MAX = + QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_AFTER_LAST - 1 +}; + +/** + * enum qca_wlan_vendor_attr_ll_stats_results_type - ll stats result type + * + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE_INVALID: Initial invalid value + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE_RADIO: Link layer stats type radio + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE_IFACE: Link layer stats type interface + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE_PEER: Link layer stats type peer + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE_AFTER_LAST: Last value + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE_MAX: Max value + */ +enum qca_wlan_vendor_attr_ll_stats_results_type { + QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE_INVALID = 0, + + QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE_RADIO = 1, + QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE_IFACE, + QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE_PEER, + + QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE_MAX = + QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE_AFTER_LAST - 1 +}; + +/** + * enum qca_wlan_vendor_attr_ll_stats_results - vendor attribute stats results + * + * Attributes of type QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_* are nested + * within the interface stats. + * + * Attributes of type QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_* could be nested + * within the interface stats. + * + * Attributes of type QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_* are nested + * within the interface stats. + * + * Attributes of type QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_* could be nested + * within the peer info stats. + * + * Attributes of type QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_* could be + * nested within the channel stats. + * + * Attributes of type QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_ could be nested + * within the radio stats. + * + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_INVALID: Invalid initial value + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_RESULTS_REQ_ID: Unsigned 32bit value + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_BEACON_RX: Unsigned 32bit value + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_MGMT_RX: Unsigned 32bit value + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_MGMT_ACTION_RX: Unsigned 32bit value + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_MGMT_ACTION_TX: Unsigned 32bit value + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_RSSI_MGMT: Unsigned 32bit value + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_RSSI_DATA: Unsigned 32bit value + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_RSSI_ACK: Unsigned 32bit value + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_MODE: Interface mode, e.g., STA, + * SOFTAP, IBSS, etc. Type = enum wifi_interface_mode + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_MAC_ADDR: Interface MAC address. + * An array of 6 Unsigned int8_t + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_STATE: + * Type = enum wifi_connection_state, e.g., DISCONNECTED, AUTHENTICATING, + * etc. Valid for STA, CLI only + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_ROAMING: + * Type = enum wifi_roam_state. Roaming state, e.g., IDLE or ACTIVE + * (is that valid for STA only?) + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_CAPABILITIES: Unsigned 32bit value. + * WIFI_CAPABILITY_XXX + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_SSID: NULL terminated SSID. An + * array of 33 Unsigned 8bit values + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_BSSID: BSSID. An array of 6 + * Unsigned 8bit values + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_AP_COUNTRY_STR: Country string + * advertised by AP. An array of 3 Unsigned 8bit values + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_COUNTRY_STR: Country string for + * this association. An array of 3 Unsigned 8bit values + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_AC: Type = enum wifi_traffic_ac e.g. + * V0, VI, BE and BK + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_TX_MPDU: Unsigned int 32 value + * corresponding to respective AC + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RX_MPDU: Unsigned int 32 value + * corresponding to respective AC + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_TX_MCAST: Unsigned int 32 value + * corresponding to respective AC + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RX_MCAST: Unsigned int 32 value + * corresponding to respective AC + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RX_AMPDU: Unsigned int 32 value + * corresponding to respective AC + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_TX_AMPDU: Unsigned int 32 value + * corresponding to respective AC + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_MPDU_LOST: Unsigned int 32 value + * corresponding to respective AC + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RETRIES: Unsigned int 32 value + * corresponding to respective AC + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RETRIES_SHORT: Unsigned int 32 value + * corresponding to respective AC + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_CONTENTION_TIME_MIN: Unsigned int 32 + * value corresponding to respective AC + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_CONTENTION_TIME_MAX: Unsigned int 32 + * value corresponding to respective AC + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_CONTENTION_TIME_AVG: Unsigned int 32 + * value corresponding to respective AC + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_CONTENTION_NUM_SAMPLES: Unsigned int 32 + * value corresponding to respective AC + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_NUM_PEERS: Unsigned int 32 + * value corresponding to respective AC + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_TYPE: Type = enum wifi_peer_type + * Peer type, e.g., STA, AP, P2P GO etc + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_MAC_ADDRESS: MAC addr corresponding + * to respective peer. An array of 6 Unsigned 8bit values + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_CAPABILITIES: Unsigned int 32bit + * value representing capabilities corresponding to respective peer. + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_NUM_RATES: Unsigned 32bit value. + * Number of rates + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_PREAMBLE: Unsigned int 8bit value: + * 0: OFDM, 1:CCK, 2:HT 3:VHT 4..7 reserved + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_NSS: Unsigned int 8bit value: + * 0:1x1, 1:2x2, 3:3x3, 4:4x4 + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_BW: Unsigned int 8bit value: + * 0:20MHz, 1:40Mhz, 2:80Mhz, 3:160Mhz + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_MCS_INDEX: Unsigned int 8bit value: + * OFDM/CCK rate code would be as per IEEE Std in the units of 0.5mbps + * HT/VHT it would be mcs index + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_BIT_RATE: Unsigned 32bit value. + * Bit rate in units of 100Kbps + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_TX_MPDU: Unsigned int 32bit value. + * Number of successfully transmitted data pkts i.e., with ACK received + * corresponding to the respective rate + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_RX_MPDU: Unsigned int 32bit value. + * Number of received data pkts corresponding to the respective rate + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_MPDU_LOST: Unsigned int 32bit value. + * Number of data pkts losses, i.e., no ACK received corresponding to + * the respective rate + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_RETRIES: Unsigned int 32bit value. + * Total number of data pkt retries for the respective rate + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_RETRIES_SHORT: Unsigned int 32bit value. + * Total number of short data pkt retries for the respective rate + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_RETRIES_LONG: Unsigned int 32bit value. + * Total number of long data pkt retries for the respective rate + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ID: Radio id + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME: Unsigned 32bit value. + * Total number of msecs the radio is awake accruing over time + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_TX_TIME: Unsigned 32bit value. + * Total number of msecs the radio is transmitting accruing over time + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_RX_TIME: Unsigned 32bit value. + * Total number of msecs the radio is in active receive accruing over time + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_SCAN: Unsigned 32bit value. + * Total number of msecs the radio is awake due to all scan accruing + * over time + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_NBD: Unsigned 32bit value. + * Total number of msecs the radio is awake due to NAN accruing over time. + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_GSCAN: Unsigned 32bit value. + * Total number of msecs the radio is awake due to GSCAN accruing over time + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_ROAM_SCAN: Unsigned 32bit value. + * Total number of msecs the radio is awake due to roam scan accruing over + * time. + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_PNO_SCAN: Unsigned 32bit value. + * Total number of msecs the radio is awake due to PNO scan accruing over + * time. + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_HS20: Unsigned 32bit value. + * Total number of msecs the radio is awake due to HS2.0 scans and GAS + * exchange accruing over time. + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_NUM_CHANNELS: Unsigned 32bit value. + * Number of channels + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_WIDTH: + * Type = enum wifi_channel_width. Channel width, e.g., 20, 40, 80, etc. + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_CENTER_FREQ: + * Unsigned 32bit value. Primary 20MHz channel. + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_CENTER_FREQ0: + * Unsigned 32bit value. Center frequency (MHz) first segment. + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_CENTER_FREQ1: + * Unsigned 32bit value. Center frequency (MHz) second segment. + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_ON_TIME: Unsigned int 32bit value + * representing total number of msecs the radio is awake on that channel + * accruing over time, corresponding to the respective channel. + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_CCA_BUSY_TIME: Unsigned int 32bit + * value representing total number of msecs the CCA register is busy + * accruing over time corresponding to the respective channel. + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_NUM_RADIOS: Number of radios + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_CH_INFO: Channel info + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO: Peer info + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_RATE_INFO: Peer rate info + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_INFO: WMM info + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_RESULTS_MORE_DATA: Unsigned 8bit value. + * Used by the driver; if set to 1, it indicates that more stats, e.g., + * peers or radio, are to follow in the next + * QCA_NL80211_VENDOR_SUBCMD_LL_STATS_*_RESULTS event. Otherwise, it + * is set to 0. + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_AVERAGE_TSF_OFFSET: tsf offset + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_LEAKY_AP_DETECTED: leaky ap detected + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_LEAKY_AP_AVG_NUM_FRAMES_LEAKED: + * average number of frames leaked + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_LEAKY_AP_GUARD_TIME: guard time + * @QCA_WLAN_VENDOR_ATTR_LL_STATS_AFTER_LAST: After last + * @QCA_WLAN_VENDOR_ATTR_FEATURE_SET_MAX: Max value + */ + +enum qca_wlan_vendor_attr_ll_stats_results { + QCA_WLAN_VENDOR_ATTR_LL_STATS_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_LL_STATS_RESULTS_REQ_ID = 1, + + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_BEACON_RX, + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_MGMT_RX, + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_MGMT_ACTION_RX, + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_MGMT_ACTION_TX, + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_RSSI_MGMT, + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_RSSI_DATA, + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_RSSI_ACK, + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_MODE, + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_MAC_ADDR, + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_STATE, + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_ROAMING, + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_CAPABILITIES, + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_SSID, + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_BSSID, + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_AP_COUNTRY_STR, + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_COUNTRY_STR, + + QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_AC, + QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_TX_MPDU, + QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RX_MPDU, + QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_TX_MCAST, + QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RX_MCAST, + QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RX_AMPDU, + QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_TX_AMPDU, + QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_MPDU_LOST, + QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RETRIES, + QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RETRIES_SHORT, + QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RETRIES_LONG, + QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_CONTENTION_TIME_MIN, + QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_CONTENTION_TIME_MAX, + QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_CONTENTION_TIME_AVG, + QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_CONTENTION_NUM_SAMPLES, + + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_NUM_PEERS, + + QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_TYPE, + QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_MAC_ADDRESS, + QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_CAPABILITIES, + QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_NUM_RATES, + + QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_PREAMBLE, + QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_NSS, + QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_BW, + QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_MCS_INDEX, + QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_BIT_RATE, + + QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_TX_MPDU, + QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_RX_MPDU, + QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_MPDU_LOST, + QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_RETRIES, + QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_RETRIES_SHORT, + QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_RETRIES_LONG, + + QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ID, + QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME, + QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_TX_TIME, + QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_RX_TIME, + QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_SCAN, + QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_NBD, + QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_GSCAN, + QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_ROAM_SCAN, + QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_PNO_SCAN, + QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_HS20, + QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_NUM_CHANNELS, + + QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_WIDTH, + QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_CENTER_FREQ, + QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_CENTER_FREQ0, + QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_CENTER_FREQ1, + + QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_ON_TIME, + QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_CCA_BUSY_TIME, + + QCA_WLAN_VENDOR_ATTR_LL_STATS_NUM_RADIOS, + QCA_WLAN_VENDOR_ATTR_LL_STATS_CH_INFO, + QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO, + QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_RATE_INFO, + QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_INFO, + + QCA_WLAN_VENDOR_ATTR_LL_STATS_RESULTS_MORE_DATA, + + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_AVERAGE_TSF_OFFSET, + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_LEAKY_AP_DETECTED, + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_LEAKY_AP_AVG_NUM_FRAMES_LEAKED, + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_LEAKY_AP_GUARD_TIME, + + /* Unsigned 32bit value to indicate ll stats result type */ + QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE, + + /* Unsigned 32bit value */ + QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_NUM_TX_LEVELS, + + /* Unsigned 32bit value + * Number of msecs the radio spent in transmitting for each power level + */ + QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_TX_TIME_PER_LEVEL, + + /* Unsigned 32bit value */ + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_RTS_SUCC_CNT, + /* Unsigned 32bit value */ + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_RTS_FAIL_CNT, + /* Unsigned 32bit value */ + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_PPDU_SUCC_CNT, + /* Unsigned 32bit value */ + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_PPDU_FAIL_CNT, + + /* keep last */ + QCA_WLAN_VENDOR_ATTR_LL_STATS_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_LL_STATS_MAX = + QCA_WLAN_VENDOR_ATTR_LL_STATS_AFTER_LAST - 1 +}; + +#endif /* WLAN_FEATURE_LINK_LAYER_STATS */ + +/** + * enum qca_wlan_vendor_attr_get_supported_features - get supported feature + * + * @QCA_WLAN_VENDOR_ATTR_FEATURE_SET_INVALID: Invalid initial value + * @QCA_WLAN_VENDOR_ATTR_FEATURE_SET: Unsigned 32bit value + * @QCA_WLAN_VENDOR_ATTR_FEATURE_SET_AFTER_LAST: After last + * @QCA_WLAN_VENDOR_ATTR_FEATURE_SET_MAX: Max value + */ +enum qca_wlan_vendor_attr_get_supported_features { + QCA_WLAN_VENDOR_ATTR_FEATURE_SET_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_FEATURE_SET = 1, + QCA_WLAN_VENDOR_ATTR_FEATURE_SET_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_FEATURE_SET_MAX = + QCA_WLAN_VENDOR_ATTR_FEATURE_SET_AFTER_LAST - 1, +}; + +/** + * enum qca_wlan_vendor_attr_set_scanning_mac_oui - set scanning mac oui + * + * @QCA_WLAN_VENDOR_ATTR_SET_SCANNING_MAC_OUI_INVALID: Invalid initial value + * @QCA_WLAN_VENDOR_ATTR_SET_SCANNING_MAC_OUI: An array of 3 x Unsigned 8-bit + * value + * @QCA_WLAN_VENDOR_ATTR_SET_SCANNING_MAC_OUI_AFTER_LAST: After last + * @QCA_WLAN_VENDOR_ATTR_SET_SCANNING_MAC_OUI_MAX: Max value + */ +enum qca_wlan_vendor_attr_set_scanning_mac_oui { + QCA_WLAN_VENDOR_ATTR_SET_SCANNING_MAC_OUI_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_SET_SCANNING_MAC_OUI = 1, + QCA_WLAN_VENDOR_ATTR_SET_SCANNING_MAC_OUI_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_SET_SCANNING_MAC_OUI_MAX = + QCA_WLAN_VENDOR_ATTR_SET_SCANNING_MAC_OUI_AFTER_LAST - 1, +}; + +/** + * enum qca_wlan_vendor_attr_scan - Specifies vendor scan attributes + * + * @QCA_WLAN_VENDOR_ATTR_SCAN_IE: IEs that should be included as part of scan + * @QCA_WLAN_VENDOR_ATTR_SCAN_FREQUENCIES: Nested unsigned 32-bit attributes + * with frequencies to be scanned (in MHz) + * @QCA_WLAN_VENDOR_ATTR_SCAN_SSIDS: Nested attribute with SSIDs to be scanned + * @QCA_WLAN_VENDOR_ATTR_SCAN_SUPP_RATES: Nested array attribute of supported + * rates to be included + * @QCA_WLAN_VENDOR_ATTR_SCAN_TX_NO_CCK_RATE: flag used to send probe requests + * at non CCK rate in 2GHz band + * @QCA_WLAN_VENDOR_ATTR_SCAN_FLAGS: Unsigned 32-bit scan flags + * @QCA_WLAN_VENDOR_ATTR_SCAN_COOKIE: Unsigned 64-bit cookie provided by the + * driver for the specific scan request + * @QCA_WLAN_VENDOR_ATTR_SCAN_STATUS: Unsigned 8-bit status of the scan + * request decoded as in enum scan_status + * @QCA_WLAN_VENDOR_ATTR_SCAN_MAC: 6-byte MAC address to use when randomisation + * scan flag is set + * @QCA_WLAN_VENDOR_ATTR_SCAN_MAC_MASK: 6-byte MAC address mask to be used with + * randomisation + * @QCA_WLAN_VENDOR_ATTR_SCAN_BSSID: BSSID provided to do scan for specific BSS + */ +enum qca_wlan_vendor_attr_scan { + QCA_WLAN_VENDOR_ATTR_SCAN_INVALID_PARAM = 0, + QCA_WLAN_VENDOR_ATTR_SCAN_IE, + QCA_WLAN_VENDOR_ATTR_SCAN_FREQUENCIES, + QCA_WLAN_VENDOR_ATTR_SCAN_SSIDS, + QCA_WLAN_VENDOR_ATTR_SCAN_SUPP_RATES, + QCA_WLAN_VENDOR_ATTR_SCAN_TX_NO_CCK_RATE, + QCA_WLAN_VENDOR_ATTR_SCAN_FLAGS, + QCA_WLAN_VENDOR_ATTR_SCAN_COOKIE, + QCA_WLAN_VENDOR_ATTR_SCAN_STATUS, + QCA_WLAN_VENDOR_ATTR_SCAN_MAC, + QCA_WLAN_VENDOR_ATTR_SCAN_MAC_MASK, + QCA_WLAN_VENDOR_ATTR_SCAN_BSSID, + QCA_WLAN_VENDOR_ATTR_SCAN_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_SCAN_MAX = + QCA_WLAN_VENDOR_ATTR_SCAN_AFTER_LAST - 1 +}; + +/** + * enum scan_status - Specifies the valid values the vendor scan attribute + * QCA_WLAN_VENDOR_ATTR_SCAN_STATUS can take + * @VENDOR_SCAN_STATUS_NEW_RESULTS: implies the vendor scan is successful with + * new scan results + * @VENDOR_SCAN_STATUS_ABORTED: implies the vendor scan was aborted in-between + */ +enum scan_status { + VENDOR_SCAN_STATUS_NEW_RESULTS, + VENDOR_SCAN_STATUS_ABORTED, + VENDOR_SCAN_STATUS_MAX, +}; + +/** + * enum qca_wlan_vendor_attr_get_concurrency_matrix - get concurrency matrix + * + * NL attributes for data used by + * QCA_NL80211_VENDOR_SUBCMD_GET_CONCURRENCY_MATRIX sub command. + * + * @QCA_WLAN_VENDOR_ATTR_GET_CONCURRENCY_MATRIX_INVALID: Invalid initial value + * @QCA_WLAN_VENDOR_ATTR_GET_CONCURRENCY_MATRIX_CONFIG_PARAM_SET_SIZE_MAX: + * Unsigned 32-bit value + * @QCA_WLAN_VENDOR_ATTR_GET_CONCURRENCY_MATRIX_RESULTS_SET_SIZE: + * Unsigned 32-bit value + * @QCA_WLAN_VENDOR_ATTR_GET_CONCURRENCY_MATRIX_RESULTS_SET: Set results. An + * array of SET_SIZE x Unsigned 32bit values representing concurrency + * combinations + * @QCA_WLAN_VENDOR_ATTR_GET_CONCURRENCY_MATRIX_AFTER_LAST: After last + * @QCA_WLAN_VENDOR_ATTR_GET_CONCURRENCY_MATRIX_MAX: Max value + */ +enum qca_wlan_vendor_attr_get_concurrency_matrix { + QCA_WLAN_VENDOR_ATTR_GET_CONCURRENCY_MATRIX_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_GET_CONCURRENCY_MATRIX_CONFIG_PARAM_SET_SIZE_MAX + = 1, + QCA_WLAN_VENDOR_ATTR_GET_CONCURRENCY_MATRIX_RESULTS_SET_SIZE = 2, + QCA_WLAN_VENDOR_ATTR_GET_CONCURRENCY_MATRIX_RESULTS_SET = 3, + QCA_WLAN_VENDOR_ATTR_GET_CONCURRENCY_MATRIX_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_GET_CONCURRENCY_MATRIX_MAX = + QCA_WLAN_VENDOR_ATTR_GET_CONCURRENCY_MATRIX_AFTER_LAST - 1, +}; + +/** + * enum qca_wlan_vendor_attr_set_no_dfs_flag - vendor attribute set no dfs flag + * + * @QCA_WLAN_VENDOR_ATTR_SET_NO_DFS_FLAG_INVALID: Invalid initial value + * @QCA_WLAN_VENDOR_ATTR_SET_NO_DFS_FLAG: Unsigned 32-bit value + * @QCA_WLAN_VENDOR_ATTR_SET_NO_DFS_FLAG_AFTER_LAST: After last + * @QCA_WLAN_VENDOR_ATTR_SET_NO_DFS_FLAG_MAX: Max value + */ +enum qca_wlan_vendor_attr_set_no_dfs_flag { + QCA_WLAN_VENDOR_ATTR_SET_NO_DFS_FLAG_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_SET_NO_DFS_FLAG = 1, + QCA_WLAN_VENDOR_ATTR_SET_NO_DFS_FLAG_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_SET_NO_DFS_FLAG_MAX = + QCA_WLAN_VENDOR_ATTR_SET_NO_DFS_FLAG_AFTER_LAST - 1, +}; + +/** + * enum qca_vendor_attr_wisa_cmd + * @QCA_WLAN_VENDOR_ATTR_WISA_INVALID: Invalid attr + * @QCA_WLAN_VENDOR_ATTR_WISA_MODE: WISA mode value attr (u32) + * @QCA_WLAN_VENDOR_ATTR_WISA_AFTER_LAST: After last + * @QCA_WLAN_VENDOR_ATTR_WISA_MAX: Max Value + * WISA setup vendor commands + */ +enum qca_vendor_attr_wisa_cmd { + QCA_WLAN_VENDOR_ATTR_WISA_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_WISA_MODE, + QCA_WLAN_VENDOR_ATTR_WISA_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_WISA_MAX = + QCA_WLAN_VENDOR_ATTR_WISA_AFTER_LAST - 1 +}; + +/** + * enum qca_wlan_vendor_attr_roam_auth - vendor event for roaming + * @QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_BSSID: BSSID of the roamed AP + * @QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_REQ_IE: Request IE + * @QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_RESP_IE: Response IE + * @QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_AUTHORIZED: Authorization Status + * @QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_KEY_REPLAY_CTR: Replay Counter + * @QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_PTK_KCK: KCK of the PTK + * @QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_PTK_KEK: KEK of the PTK + * @QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_SUBNET_STATUS: subnet change status + */ +enum qca_wlan_vendor_attr_roam_auth { + QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_BSSID, + QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_REQ_IE, + QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_RESP_IE, + QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_AUTHORIZED, + QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_KEY_REPLAY_CTR, + QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_PTK_KCK, + QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_PTK_KEK, + QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_SUBNET_STATUS, + QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_MAX = + QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_AFTER_LAST - 1 +}; + +/** + * enum qca_wlan_vendor_attr_wifi_config - wifi config + * + * @QCA_WLAN_VENDOR_ATTR_WIFI_CONFIG_INVALID: Invalid initial value + * @QCA_WLAN_VENDOR_ATTR_WIFI_CONFIG_DYNAMIC_DTIM: dynamic DTIM + * @QCA_WLAN_VENDOR_ATTR_WIFI_CONFIG_STATS_AVG_FACTOR: avg factor + * @QCA_WLAN_VENDOR_ATTR_WIFI_CONFIG_GUARD_TIME: guard time + * @QCA_WLAN_VENDOR_ATTR_WIFI_CONFIG_AFTER_LAST: after last + * @QCA_WLAN_VENDOR_ATTR_WIFI_CONFIG_MAX: max value + */ +enum qca_wlan_vendor_attr_wifi_config { + QCA_WLAN_VENDOR_ATTR_WIFI_CONFIG_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_WIFI_CONFIG_DYNAMIC_DTIM = 1, + QCA_WLAN_VENDOR_ATTR_WIFI_CONFIG_STATS_AVG_FACTOR = 2, + QCA_WLAN_VENDOR_ATTR_WIFI_CONFIG_GUARD_TIME = 3, + + /* keep last */ + QCA_WLAN_VENDOR_ATTR_WIFI_CONFIG_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_WIFI_CONFIG_MAX = + QCA_WLAN_VENDOR_ATTR_WIFI_CONFIG_AFTER_LAST - 1, +}; + +/** + * enum qca_wlan_epno_type - the type of request to the EPNO command + * @QCA_WLAN_EPNO: epno type request + * @QCA_WLAN_PNO: pno type request + */ +enum qca_wlan_epno_type { + QCA_WLAN_EPNO, + QCA_WLAN_PNO +}; + +/** + * enum qca_wlan_vendor_attr_pno_config_params - pno config params + * + * @QCA_WLAN_VENDOR_ATTR_PNO_INVALID - Invalid initial value + * + * NL attributes for data used by + * QCA_NL80211_VENDOR_SUBCMD_PNO_SET_PASSPOINT_LIST sub command. + * @QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_LIST_PARAM_NUM: + * Unsigned 32-bit value; pno passpoint number of networks + * @QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_LIST_PARAM_NETWORK_ARRAY: + * Array of nested QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_NETWORK_PARAM_* + * attributes. Array size = + * QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_LIST_PARAM_NUM. + * @QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_NETWORK_PARAM_ID: + * Unsigned 32-bit value; network id + * @QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_NETWORK_PARAM_REALM: + * An array of 256 x Unsigned 8-bit value; NULL terminated UTF8 encoded + * realm, 0 if unspecified. + * @QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_NETWORK_PARAM_ROAM_CNSRTM_ID: + * An array of 16 x Unsigned 32-bit value; roaming consortium ids + * to match, 0 if unspecified. + * @QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_NETWORK_PARAM_ROAM_PLMN: + * An array of 6 x Unsigned 8-bit value; mcc/mnc combination, 0s if + * unspecified. + * + * NL attributes for data used by + * QCA_NL80211_VENDOR_SUBCMD_PNO_SET_LIST sub command. + * @QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_NUM_NETWORKS: + * Unsigned 32-bit value; set pno number of networks + * @QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORKS_LIST: + * Array of nested + * QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORK_* + * attributes. Array size = + * QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_NUM_NETWORKS + * @QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORK_SSID: + * An array of 33 x Unsigned 8-bit value; NULL terminated SSID + * @QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORK_RSSI_THRESHOLD: + * Signed 8-bit value; threshold for considering this SSID as found, + * required granularity for this threshold is 4dBm to 8dBm + * @QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORK_FLAGS: + * Unsigned 8-bit value; WIFI_PNO_FLAG_XXX + * @QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORK_AUTH_BIT: + * Unsigned 8-bit value; auth bit field for matching WPA IE + * @QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_TYPE + * Unsigned 8-bit to indicate ePNO type; values from qca_wlan_epno_type + *@QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_CHANNEL_LIST + * Nested attribute to send the channel list + *@QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_SCAN_INTERVAL + * Unsigned 32-bit value; indicates the Interval between PNO scan + * cycles in msec + *@QCA_WLAN_VENDOR_ATTR_EPNO_MIN5GHZ_RSSI + * Signed 32-bit value; minimum 5GHz RSSI for a BSSID to be considered + *@QCA_WLAN_VENDOR_ATTR_EPNO_MIN24GHZ_RSSI + * Signed 32-bit value; minimum 2.4GHz RSSI for a BSSID to be considered + * This attribute is obsolete now. + *@QCA_WLAN_VENDOR_ATTR_EPNO_INITIAL_SCORE_MAX + * Signed 32-bit value; the maximum score that a network + * can have before bonuses + *@QCA_WLAN_VENDOR_ATTR_EPNO_CURRENT_CONNECTION_BONUS + * Signed 32-bit value; only report when there is a network's + * score this much higher han the current connection + *@QCA_WLAN_VENDOR_ATTR_EPNO_SAME_NETWORK_BONUS + * Signed 32-bit value; score bonus for all networks with + * the same network flag + *@QCA_WLAN_VENDOR_ATTR_EPNO_SECURE_BONUS + * Signed 32-bit value; score bonus for networks that are not open + *@QCA_WLAN_VENDOR_ATTR_EPNO_BAND5GHZ_BONUS + * Signed 32-bit value; 5GHz RSSI score bonus applied to all + * 5GHz networks + * @QCA_WLAN_VENDOR_ATTR_PNO_AFTER_LAST: After last + * @QCA_WLAN_VENDOR_ATTR_PNO_MAX: max + */ +enum qca_wlan_vendor_attr_pno_config_params { + QCA_WLAN_VENDOR_ATTR_PNO_INVALID = 0, + + QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_LIST_PARAM_NUM = 1, + QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_LIST_PARAM_NETWORK_ARRAY = 2, + QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_NETWORK_PARAM_ID = 3, + QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_NETWORK_PARAM_REALM = 4, + QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_NETWORK_PARAM_ROAM_CNSRTM_ID = 5, + QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_NETWORK_PARAM_ROAM_PLMN = 6, + + QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_NUM_NETWORKS = 7, + QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORKS_LIST = 8, + QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORK_SSID = 9, + QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORK_RSSI_THRESHOLD = 10, + QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORK_FLAGS = 11, + QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORK_AUTH_BIT = 12, + QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_TYPE = 13, + QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_CHANNEL_LIST = 14, + QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_SCAN_INTERVAL = 15, + QCA_WLAN_VENDOR_ATTR_EPNO_MIN5GHZ_RSSI = 16, + QCA_WLAN_VENDOR_ATTR_EPNO_MIN24GHZ_RSSI = 17, + QCA_WLAN_VENDOR_ATTR_EPNO_INITIAL_SCORE_MAX = 18, + QCA_WLAN_VENDOR_ATTR_EPNO_CURRENT_CONNECTION_BONUS = 19, + QCA_WLAN_VENDOR_ATTR_EPNO_SAME_NETWORK_BONUS = 20, + QCA_WLAN_VENDOR_ATTR_EPNO_SECURE_BONUS = 21, + QCA_WLAN_VENDOR_ATTR_EPNO_BAND5GHZ_BONUS = 22, + + /* keep last */ + QCA_WLAN_VENDOR_ATTR_PNO_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_PNO_MAX = + QCA_WLAN_VENDOR_ATTR_PNO_AFTER_LAST - 1, +}; + +/** + * enum qca_wlan_vendor_attr_roaming_config_params - roaming config params + * + * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_INVALID: Invalid initial value + * @QCA_WLAN_VENDOR_ATTR_ROAMING_SUBCMD: roaming sub command + * @QCA_WLAN_VENDOR_ATTR_ROAMING_REQ_ID: Request id + * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_WHITE_LIST_SSID_NUM_NETWORKS: + * number of whitelist networks + * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_WHITE_LIST_SSID_LIST: + * Whitelist ssid list + * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_WHITE_LIST_SSID: + * white list ssid + * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_A_BAND_BOOST_THRESHOLD: + * 'a' band boost threshold + * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_A_BAND_PENALTY_THRESHOLD: + * 'a' band penalty threshold + * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_A_BAND_BOOST_FACTOR: + * 'a' band boost factor + * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_A_BAND_PENALTY_FACTOR: + * 'a' band penalty factor + * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_A_BAND_MAX_BOOST: + * 'a' band max boost + * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_LAZY_ROAM_HISTERESYS: + * lazy roam histeresys + * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_ALERT_ROAM_RSSI_TRIGGER: + * alert roam rssi trigger + * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_LAZY_ROAM_ENABLE: + * set lazy roam enable + * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PREFS: + * set bssid preference + * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_LAZY_ROAM_NUM_BSSID: + * set lazy roam number of bssid + * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_LAZY_ROAM_BSSID: + * set lazy roam bssid + * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_LAZY_ROAM_RSSI_MODIFIER: + * set lazy roam rssi modifier + * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS: + * set bssid params + * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS_NUM_BSSID: + * set bssid params num bssid + * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS_BSSID: + * set bssid params bssid + * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_AFTER_LAST: After last + * @QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_MAX: Max + */ +enum qca_wlan_vendor_attr_roaming_config_params { + QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_INVALID = 0, + + QCA_WLAN_VENDOR_ATTR_ROAMING_SUBCMD = 1, + QCA_WLAN_VENDOR_ATTR_ROAMING_REQ_ID = 2, + + QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_WHITE_LIST_SSID_NUM_NETWORKS = 3, + QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_WHITE_LIST_SSID_LIST = 4, + QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_WHITE_LIST_SSID = 5, + + QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_A_BAND_BOOST_THRESHOLD = 6, + QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_A_BAND_PENALTY_THRESHOLD = 7, + QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_A_BAND_BOOST_FACTOR = 8, + QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_A_BAND_PENALTY_FACTOR = 9, + QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_A_BAND_MAX_BOOST = 10, + QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_LAZY_ROAM_HISTERESYS = 11, + QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_ALERT_ROAM_RSSI_TRIGGER = 12, + + QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_LAZY_ROAM_ENABLE = 13, + + QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PREFS = 14, + QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_LAZY_ROAM_NUM_BSSID = 15, + QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_LAZY_ROAM_BSSID = 16, + QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_LAZY_ROAM_RSSI_MODIFIER = 17, + + QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS = 18, + QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS_NUM_BSSID = 19, + QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS_BSSID = 20, + + /* keep last */ + QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_MAX = + QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_AFTER_LAST - 1, +}; + +/** + * enum qca_wlan_vendor_attr_roam_subcmd - roam sub commands + * + * @QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_INVALID: Invalid initial value + * @QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_SSID_WHITE_LIST: ssid white list + * @QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_SET_EXTSCAN_ROAM_PARAMS: roam params + * @QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_SET_LAZY_ROAM: set lazy roam + * @QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_SET_BSSID_PREFS: set bssid prefs + * @QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_SET_BSSID_PARAMS: set bssid params + * @QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_SET_BLACKLIST_BSSID: set blacklist bssid + * @QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_AFTER_LAST: after last + * @QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_MAX: subcmd max + */ +enum qca_wlan_vendor_attr_roam_subcmd { + QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_SSID_WHITE_LIST = 1, + QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_SET_EXTSCAN_ROAM_PARAMS = 2, + QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_SET_LAZY_ROAM = 3, + QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_SET_BSSID_PREFS = 4, + QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_SET_BSSID_PARAMS = 5, + QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_SET_BLACKLIST_BSSID = 6, + + /* KEEP LAST */ + QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_MAX = + QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_AFTER_LAST - 1, +}; + +/** + * enum qca_wlan_vendor_attr_get_wifi_info - wifi driver information + * + * @QCA_WLAN_VENDOR_ATTR_WIFI_INFO_GET_INVALID: Invalid initial value + * @QCA_WLAN_VENDOR_ATTR_WIFI_INFO_DRIVER_VERSION: get host driver version + * @QCA_WLAN_VENDOR_ATTR_WIFI_INFO_FIRMWARE_VERSION: ger firmware version + * @QCA_WLAN_VENDOR_ATTR_WIFI_INFO_RADIO_INDEX - get radio index + * @QCA_WLAN_VENDOR_ATTR_WIFI_INFO_GET_AFTER_LAST: after last + * @QCA_WLAN_VENDOR_ATTR_WIFI_INFO_GET_MAX: subcmd max + */ +enum qca_wlan_vendor_attr_get_wifi_info { + QCA_WLAN_VENDOR_ATTR_WIFI_INFO_GET_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_WIFI_INFO_DRIVER_VERSION = 1, + QCA_WLAN_VENDOR_ATTR_WIFI_INFO_FIRMWARE_VERSION = 2, + QCA_WLAN_VENDOR_ATTR_WIFI_INFO_RADIO_INDEX = 3, + + /* KEEP LAST */ + QCA_WLAN_VENDOR_ATTR_WIFI_INFO_GET_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_WIFI_INFO_GET_MAX = + QCA_WLAN_VENDOR_ATTR_WIFI_INFO_GET_AFTER_LAST - 1, +}; + +/** + * enum qca_wlan_vendor_attr_get_logger_features - value for logger + * supported features + * @QCA_WLAN_VENDOR_ATTR_LOGGER_INVALID - Invalid + * @QCA_WLAN_VENDOR_ATTR_LOGGER_SUPPORTED - Indicate the supported features + * @QCA_WLAN_VENDOR_ATTR_LOGGER_AFTER_LAST - To keep track of the last enum + * @QCA_WLAN_VENDOR_ATTR_LOGGER_MAX - max value possible for this type + * + * enum values are used for NL attributes for data used by + * QCA_NL80211_VENDOR_SUBCMD_GET_LOGGER_FEATURE_SET sub command. + */ +enum qca_wlan_vendor_attr_get_logger_features { + QCA_WLAN_VENDOR_ATTR_LOGGER_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_LOGGER_SUPPORTED = 1, + + /* keep last */ + QCA_WLAN_VENDOR_ATTR_LOGGER_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_LOGGER_MAX = + QCA_WLAN_VENDOR_ATTR_LOGGER_AFTER_LAST - 1, +}; + +/** + * enum qca_wlan_vendor_attr_link_properties - link properties + * + * @QCA_WLAN_VENDOR_ATTR_LINK_PROPERTIES_INVALID: Invalid initial value + * @QCA_WLAN_VENDOR_ATTR_LINK_PROPERTIES_NSS: Unsigned 8-bit value to + * specify the number of spatial streams negotiated + * @QCA_WLAN_VENDOR_ATTR_LINK_PROPERTIES_RATE_FLAGS: Unsigned 8-bit value + * to specify negotiated rate flags i.e. ht, vht and channel width + * @QCA_WLAN_VENDOR_ATTR_LINK_PROPERTIES_FREQ: Unsigned 32bit value to + * specify the operating frequency + * @QCA_WLAN_VENDOR_ATTR_LINK_PROPERTIES_AFTER_LAST: after last + * @QCA_WLAN_VENDOR_ATTR_LINK_PROPERTIES_MAX: max value + */ +enum qca_wlan_vendor_attr_link_properties { + QCA_WLAN_VENDOR_ATTR_LINK_PROPERTIES_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_LINK_PROPERTIES_NSS = 1, + QCA_WLAN_VENDOR_ATTR_LINK_PROPERTIES_RATE_FLAGS = 2, + QCA_WLAN_VENDOR_ATTR_LINK_PROPERTIES_FREQ = 3, + + /* KEEP LAST */ + QCA_WLAN_VENDOR_ATTR_LINK_PROPERTIES_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_LINK_PROPERTIES_MAX = + QCA_WLAN_VENDOR_ATTR_LINK_PROPERTIES_AFTER_LAST - 1, +}; + +/** + * enum qca_wlan_vendor_attr_nd_offload - vendor NS offload support + * + * @QCA_WLAN_VENDOR_ATTR_ND_OFFLOAD_INVALID - Invalid + * @QCA_WLAN_VENDOR_ATTR_ND_OFFLOAD_FLAG - Flag to set NS offload + * @QCA_WLAN_VENDOR_ATTR_ND_OFFLOAD_AFTER_LAST - To keep track of the last enum + * @QCA_WLAN_VENDOR_ATTR_ND_OFFLOAD_MAX - max value possible for this type + * + * enum values are used for NL attributes for data used by + * QCA_NL80211_VENDOR_SUBCMD_ND_OFFLOAD sub command. + */ +enum qca_wlan_vendor_attr_nd_offload { + QCA_WLAN_VENDOR_ATTR_ND_OFFLOAD_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_ND_OFFLOAD_FLAG, + + /* Keep last */ + QCA_WLAN_VENDOR_ATTR_ND_OFFLOAD_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_ND_OFFLOAD_MAX = + QCA_WLAN_VENDOR_ATTR_ND_OFFLOAD_AFTER_LAST - 1, +}; + +/** + * enum qca_wlan_vendor_features - vendor device/driver features + * @QCA_WLAN_VENDOR_FEATURE_KEY_MGMT_OFFLOAD: Device supports key + * management offload, a mechanism where the station's firmware + * does the exchange with the AP to establish the temporal keys + * after roaming, rather than having the supplicant do it. + * @QCA_WLAN_VENDOR_FEATURE_OFFCHANNEL_SIMULTANEOUS: Device supports + * simultaneous off-channel operations. + * @QQCA_WLAN_VENDOR_FEATURE_P2P_LISTEN_OFFLOAD: Device supports P2P + * Listen offload; a mechanism where the station's firmware + * takes care of responding to incoming Probe Request frames received + * from other P2P devices whilst in Listen state, rather than having the + * user space wpa_supplicant do it. Information from received P2P + * Requests are forwarded from firmware to host whenever the APPS + * processor exits power collapse state. + */ +enum qca_wlan_vendor_features { + QCA_WLAN_VENDOR_FEATURE_KEY_MGMT_OFFLOAD = 0, + QCA_WLAN_VENDOR_FEATURE_SUPPORT_HW_MODE_ANY = 1, + QCA_WLAN_VENDOR_FEATURE_OFFCHANNEL_SIMULTANEOUS = 2, + QCA_WLAN_VENDOR_FEATURE_P2P_LISTEN_OFFLOAD = 3, + /* Additional features need to be added above this */ + NUM_QCA_WLAN_VENDOR_FEATURES +}; + +/** + * enum qca_wlan_vendor_attr_sap_conditional_chan_switch - Parameters for SAP + * conditional channel switch + * @QCA_WLAN_VENDOR_ATTR_SAP_CONDITIONAL_CHAN_SWITCH_INVALID: Invalid initial + * value + * @QCA_WLAN_VENDOR_ATTR_SAP_CONDITIONAL_CHAN_SWITCH_FREQ_LIST: Priority based + * frequency list (an array of u32 values in host byte order) + * @QCA_WLAN_VENDOR_ATTR_SAP_CONDITIONAL_CHAN_SWITCH_STATUS: Status of the + * conditional switch (u32)- 0: Success, Non-zero: Failure + * @QCA_WLAN_VENDOR_ATTR_SAP_CONDITIONAL_CHAN_SWITCH_AFTER_LAST: After last + * @QCA_WLAN_VENDOR_ATTR_SAP_CONDITIONAL_CHAN_SWITCH_MAX: Subcommand max + */ +enum qca_wlan_vendor_attr_sap_conditional_chan_switch { + QCA_WLAN_VENDOR_ATTR_SAP_CONDITIONAL_CHAN_SWITCH_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_SAP_CONDITIONAL_CHAN_SWITCH_FREQ_LIST = 1, + QCA_WLAN_VENDOR_ATTR_SAP_CONDITIONAL_CHAN_SWITCH_STATUS = 2, + + /* Keep Last */ + QCA_WLAN_VENDOR_ATTR_SAP_CONDITIONAL_CHAN_SWITCH_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_SAP_CONDITIONAL_CHAN_SWITCH_MAX = + QCA_WLAN_VENDOR_ATTR_SAP_CONDITIONAL_CHAN_SWITCH_AFTER_LAST - 1, +}; + +/* Feature defines */ +#define WIFI_FEATURE_INFRA 0x0001 /* Basic infrastructure mode */ +#define WIFI_FEATURE_INFRA_5G 0x0002 /* Support for 5 GHz Band */ +#define WIFI_FEATURE_HOTSPOT 0x0004 /* Support for GAS/ANQP */ +#define WIFI_FEATURE_P2P 0x0008 /* Wifi-Direct */ +#define WIFI_FEATURE_SOFT_AP 0x0010 /* Soft AP */ +#define WIFI_FEATURE_EXTSCAN 0x0020 /* Extended Scan APIs */ +#define WIFI_FEATURE_NAN 0x0040 /* Neighbor Awareness + Networking */ +#define WIFI_FEATURE_D2D_RTT 0x0080 /* Device-to-device RTT */ +#define WIFI_FEATURE_D2AP_RTT 0x0100 /* Device-to-AP RTT */ +#define WIFI_FEATURE_BATCH_SCAN 0x0200 /* Batched Scan (legacy) */ +#define WIFI_FEATURE_PNO 0x0400 /* Preferred network offload */ +#define WIFI_FEATURE_ADDITIONAL_STA 0x0800 /* Support for two STAs */ +#define WIFI_FEATURE_TDLS 0x1000 /* Tunnel directed link + setup */ +#define WIFI_FEATURE_TDLS_OFFCHANNEL 0x2000 /* Support for TDLS off + channel */ +#define WIFI_FEATURE_EPR 0x4000 /* Enhanced power reporting */ +#define WIFI_FEATURE_AP_STA 0x8000 /* Support for AP STA + Concurrency */ +#define WIFI_FEATURE_LINK_LAYER_STATS 0x10000 /* Link layer stats */ +#define WIFI_FEATURE_LOGGER 0x20000 /* WiFi Logger */ +#define WIFI_FEATURE_HAL_EPNO 0x40000 /* WiFi PNO enhanced */ +#define WIFI_FEATURE_RSSI_MONITOR 0x80000 /* RSSI Monitor */ +#define WIFI_FEATURE_MKEEP_ALIVE 0x100000 /* WiFi mkeep_alive */ +#define WIFI_FEATURE_CONFIG_NDO 0x200000 /* ND offload configure */ +#define WIFI_FEATURE_TX_TRANSMIT_POWER 0x400000 /* Tx transmit power levels */ + +/** + * enum wifi_logger_supported_features - values for supported logger features + * @WIFI_LOGGER_MEMORY_DUMP_SUPPORTED - Memory dump of FW + * @WIFI_LOGGER_PER_PACKET_TX_RX_STATUS_SUPPORTED - Per packet statistics + * @WIFI_LOGGER_CONNECT_EVENT_SUPPORTED - Logging of Connectivity events + * @WIFI_LOGGER_POWER_EVENT_SUPPORTED - Power of driver + * @WIFI_LOGGER_WAKE_LOCK_SUPPORTED - Wakelock of driver + * @WIFI_LOGGER_WATCHDOG_TIMER_SUPPORTED - monitor FW health + */ +enum wifi_logger_supported_features { + WIFI_LOGGER_MEMORY_DUMP_SUPPORTED = (1 << (0)), + WIFI_LOGGER_PER_PACKET_TX_RX_STATUS_SUPPORTED = (1 << (1)), + WIFI_LOGGER_CONNECT_EVENT_SUPPORTED = (1 << (2)), + WIFI_LOGGER_POWER_EVENT_SUPPORTED = (1 << (3)), + WIFI_LOGGER_WAKE_LOCK_SUPPORTED = (1 << (4)), + WIFI_LOGGER_VERBOSE_SUPPORTED = (1 << (5)), + WIFI_LOGGER_WATCHDOG_TIMER_SUPPORTED = (1 << (6)), +}; + +/* Add more features here */ +#define WIFI_TDLS_SUPPORT BIT(0) +#define WIFI_TDLS_EXTERNAL_CONTROL_SUPPORT BIT(1) +#define WIIF_TDLS_OFFCHANNEL_SUPPORT BIT(2) + +#if defined(FEATURE_WLAN_CH_AVOID) || defined(FEATURE_WLAN_FORCE_SAP_SCC) +#define HDD_MAX_AVOID_FREQ_RANGES 4 +/** + * typedef struct sHddAvoidFreqRange - avoid frequency range + * + * @startFreq: Start frequency range + * @endFreq: End frequency range + */ +typedef struct sHddAvoidFreqRange { + u32 startFreq; + u32 endFreq; +} tHddAvoidFreqRange; + +/** + * typedef struct sHddAvoidFreqList - avoid frequency list + * + * @avoidFreqRangeCount: Avoid frequency range count + * @avoidFreqRange: Avoid frequency list + */ +typedef struct sHddAvoidFreqList { + u32 avoidFreqRangeCount; + tHddAvoidFreqRange avoidFreqRange[HDD_MAX_AVOID_FREQ_RANGES]; +} tHddAvoidFreqList; +#endif /* FEATURE_WLAN_CH_AVOID || FEATURE_WLAN_FORCE_SAP_SCC */ + +/** + * enum qca_wlan_vendor_attr_acs_offload + * + * @QCA_WLAN_VENDOR_ATTR_ACS_PRIMARY_CHANNEL: ACS selected primary channel + * @QCA_WLAN_VENDOR_ATTR_ACS_SECONDARY_CHANNEL: ACS selected secondary channel + * @QCA_WLAN_VENDOR_ATTR_ACS_HW_MODE: hw_mode for ACS + * @QCA_WLAN_VENDOR_ATTR_ACS_HT_ENABLED: indicate if HT capability is enabled + * @QCA_WLAN_VENDOR_ATTR_ACS_HT40_ENABLED: indicate HT capability + */ +enum qca_wlan_vendor_attr_acs_offload { + QCA_WLAN_VENDOR_ATTR_ACS_CHANNEL_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_ACS_PRIMARY_CHANNEL, + QCA_WLAN_VENDOR_ATTR_ACS_SECONDARY_CHANNEL, + QCA_WLAN_VENDOR_ATTR_ACS_HW_MODE, + QCA_WLAN_VENDOR_ATTR_ACS_HT_ENABLED, + QCA_WLAN_VENDOR_ATTR_ACS_HT40_ENABLED, + QCA_WLAN_VENDOR_ATTR_ACS_VHT_ENABLED, + QCA_WLAN_VENDOR_ATTR_ACS_CHWIDTH, + QCA_WLAN_VENDOR_ATTR_ACS_CH_LIST, + QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_CHANNEL, + QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG1_CENTER_CHANNEL, + QCA_WLAN_VENDOR_ATTR_ACS_FREQ_LIST, + /* keep last */ + QCA_WLAN_VENDOR_ATTR_ACS_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_ACS_MAX = + QCA_WLAN_VENDOR_ATTR_ACS_AFTER_LAST - 1 +}; + +/** + * enum qca_wlan_vendor_acs_hw_mode + * + * @QCA_ACS_MODE_IEEE80211B: 11b mode + * @QCA_ACS_MODE_IEEE80211G: 11g mode + * @QCA_ACS_MODE_IEEE80211A: 11a mode + * @QCA_ACS_MODE_IEEE80211AD: 11ad mode + */ +enum qca_wlan_vendor_acs_hw_mode { + QCA_ACS_MODE_IEEE80211B, + QCA_ACS_MODE_IEEE80211G, + QCA_ACS_MODE_IEEE80211A, + QCA_ACS_MODE_IEEE80211AD, + QCA_ACS_MODE_IEEE80211ANY, +}; + +#define CFG_NON_AGG_RETRY_MAX (31) +#define CFG_AGG_RETRY_MAX (31) +#define CFG_MGMT_RETRY_MAX (31) +#define CFG_CTRL_RETRY_MAX (31) +#define CFG_PROPAGATION_DELAY_MAX (63) +#define CFG_AGG_RETRY_MIN (5) + +/** + * enum qca_access_policy - access control policy + * + * Access control policy is applied on the configured IE + * (QCA_WLAN_VENDOR_ATTR_CONFIG_ACCESS_POLICY_IE). + * To be set with QCA_WLAN_VENDOR_ATTR_CONFIG_ACCESS_POLICY. + * + * @QCA_ACCESS_POLICY_ACCEPT_UNLESS_LISTED: Deny Wi-Fi Connections which match + *» with the specific configuration (IE) set, i.e. allow all the + *» connections which do not match the configuration. + * @QCA_ACCESS_POLICY_DENY_UNLESS_LISTED: Accept Wi-Fi Connections which match + *» with the specific configuration (IE) set, i.e. deny all the + *» connections which do not match the configuration. + */ +enum qca_access_policy { + QCA_ACCESS_POLICY_ACCEPT_UNLESS_LISTED, + QCA_ACCESS_POLICY_DENY_UNLESS_LISTED, +}; + +/** + * enum qca_ignore_assoc_disallowed - Ignore assoc disallowed values + * + * The valid values for the ignore assoc disallowed + * + * @QCA_IGNORE_ASSOC_DISALLOWED_DISABLE: Disable ignore assoc disallowed + * @QCA_IGNORE_ASSOC_DISALLOWED_ENABLE: Enable ignore assoc disallowed + * + */ +enum qca_ignore_assoc_disallowed { + QCA_IGNORE_ASSOC_DISALLOWED_DISABLE, + QCA_IGNORE_ASSOC_DISALLOWED_ENABLE +}; + +/** + * enum qca_wlan_vendor_config: wifi config attr + * + * @QCA_WLAN_VENDOR_ATTR_CONFIG_INVALID: invalid config + * @QCA_WLAN_VENDOR_ATTR_CONFIG_MODULATED_DTIM: modulated dtim + * @QCA_WLAN_VENDOR_ATTR_CONFIG_STATS_AVG_FACTOR: stats avg. factor + * @QCA_WLAN_VENDOR_ATTR_CONFIG_GUARD_TIME: guard time + * @QCA_WLAN_VENDOR_ATTR_CONFIG_FINE_TIME_MEASUREMENT: fine time measurement + * @QCA_WLAN_VENDOR_ATTR_CONF_TX_RATE: Configure maximum TX rate dynamically + * @QCA_WLAN_VENDOR_ATTR_CONFIG_PENALIZE_AFTER_NCONS_BEACON_MISS: + * Configure the number of continuous Beacon Miss + * @QCA_WLAN_VENDOR_ATTR_CONFIG_CHANNEL_AVOIDANCE_IND: + * Configure the channel avoidance indication + * @QCA_WLAN_VENDOR_ATTR_CONFIG_TX_MPDU_AGGREGATION: + * Tx aggregation size (8-bit unsigned value) + * @QCA_WLAN_VENDOR_ATTR_CONFIG_RX_MPDU_AGGREGATION: + * Rx aggregation size (8-bit unsigned value) + * @QCA_WLAN_VENDOR_ATTR_CONFIG_NON_AGG_RETRY: + * Non aggregrate/11g sw retry threshold + * @QCA_WLAN_VENDOR_ATTR_CONFIG_AGG_RETRY: aggregrate sw retry threshold + * @QCA_WLAN_VENDOR_ATTR_CONFIG_MGMT_RETRY: management frame sw retry threshold + * @QCA_WLAN_VENDOR_ATTR_CONFIG_CTRL_RETRY: control frame sw retry threshold + * @QCA_WLAN_VENDOR_ATTR_CONFIG_PROPAGATION_DELAY: + * Propagation delay for 2G/5G band (units in us) + * @QCA_WLAN_VENDOR_ATTR_CONFIG_TX_FAIL_COUNT: + * Configure the number of unicast TX fail packet count + * @QCA_WLAN_VENDOR_ATTR_CONFIG_SCAN_DEFAULT_IES: Update the default scan IEs + * @QCA_WLAN_VENDOR_ATTR_CONFIG_GENERIC_COMMAND: + * Unsigned 32-bit value attribute for generic commands + * @QCA_WLAN_VENDOR_ATTR_CONFIG_GENERIC_VALUE: + * Unsigned 32-bit data attribute for generic command response + * @QCA_WLAN_VENDOR_ATTR_CONFIG_GENERIC_DATA: + * Unsigned 32-bit data attribute for generic command response + * @QCA_WLAN_VENDOR_ATTR_CONFIG_GENERIC_LENGTH: + * Unsigned 32-bit length attribute for + * QCA_WLAN_VENDOR_ATTR_CONFIG_GENERIC_DATA + * @QCA_WLAN_VENDOR_ATTR_CONFIG_GENERIC_FLAGS: + * Unsigned 32-bit flags attribute for + * QCA_WLAN_VENDOR_ATTR_CONFIG_GENERIC_DATA + * @QCA_WLAN_VENDOR_ATTR_CONFIG_ACCESS_POLICY: Vendor IE access policy + * @QCA_WLAN_VENDOR_ATTR_CONFIG_ACCESS_POLICY_IE_LIST: + * Vendor IE to be used with access policy + * @QCA_WLAN_VENDOR_ATTR_CONFIG_IFINDEX: + * interface index for vdev specific parameters + * @QCA_WLAN_VENDOR_ATTR_CONFIG_QPOWER: + * Unsigned 8bit length attribute to update power save config + * to turn off/on qpower + * @QCA_WLAN_VENDOR_ATTR_CONFIG_IGNORE_ASSOC_DISALLOWED: + * Ignore Assoc Disallowed[MBO] + * @QCA_WLAN_VENDOR_ATTR_CONFIG_LAST: last config + * @QCA_WLAN_VENDOR_ATTR_CONFIG_MAX: max config + * @QCA_WLAN_VENDOR_ATTR_CONFIG_LRO: enable/disable LRO + */ +enum qca_wlan_vendor_config { + QCA_WLAN_VENDOR_ATTR_CONFIG_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_CONFIG_MODULATED_DTIM = 1, + QCA_WLAN_VENDOR_ATTR_CONFIG_STATS_AVG_FACTOR = 2, + QCA_WLAN_VENDOR_ATTR_CONFIG_GUARD_TIME = 3, + QCA_WLAN_VENDOR_ATTR_CONFIG_FINE_TIME_MEASUREMENT = 4, + /* Unsigned 16-bit value to configure maximum TX rate dynamically */ + QCA_WLAN_VENDOR_ATTR_CONF_TX_RATE = 5, + QCA_WLAN_VENDOR_ATTR_CONFIG_PENALIZE_AFTER_NCONS_BEACON_MISS = 6, + QCA_WLAN_VENDOR_ATTR_CONFIG_CHANNEL_AVOIDANCE_IND = 7, + + QCA_WLAN_VENDOR_ATTR_CONFIG_TX_MPDU_AGGREGATION = 8, + QCA_WLAN_VENDOR_ATTR_CONFIG_RX_MPDU_AGGREGATION = 9, + + /* 8-bit unsigned value to configure the Non aggregrate/11g sw + * retry threshold (0 disable, 31 max). */ + QCA_WLAN_VENDOR_ATTR_CONFIG_NON_AGG_RETRY = 10, + /* 8-bit unsigned value to configure the aggregrate sw + * retry threshold (0 disable, 31 max). */ + QCA_WLAN_VENDOR_ATTR_CONFIG_AGG_RETRY = 11, + /* 8-bit unsigned value to configure the MGMT frame + * retry threshold (0 disable, 31 max). */ + QCA_WLAN_VENDOR_ATTR_CONFIG_MGMT_RETRY = 12, + /* 8-bit unsigned value to configure the CTRL frame + * retry threshold (0 disable, 31 max). */ + QCA_WLAN_VENDOR_ATTR_CONFIG_CTRL_RETRY = 13, + /* 8-bit unsigned value to configure the propagation delay for + * 2G/5G band (0~63, units in us) */ + QCA_WLAN_VENDOR_ATTR_CONFIG_PROPAGATION_DELAY = 14, + + /* Unsigned 32-bit value to configure the number of unicast TX fail + * packet count. The peer is disconnected once this threshold is + * reached. */ + QCA_WLAN_VENDOR_ATTR_CONFIG_TX_FAIL_COUNT = 15, + /* Attribute used to set scan default IEs to the driver. + * + * These IEs can be used by scan operations that will be initiated by + * the driver/firmware. + * + * For further scan requests coming to the driver, these IEs should be + * merged with the IEs received along with scan request coming to the + * driver. If a particular IE is present in the scan default IEs but not + * present in the scan request, then that IE should be added to the IEs + * sent in the Probe Request frames for that scan request. */ + QCA_WLAN_VENDOR_ATTR_CONFIG_SCAN_DEFAULT_IES = 16, + /* Unsigned 32-bit attribute for generic commands */ + QCA_WLAN_VENDOR_ATTR_CONFIG_GENERIC_COMMAND = 17, + /* Unsigned 32-bit value attribute for generic commands */ + QCA_WLAN_VENDOR_ATTR_CONFIG_GENERIC_VALUE = 18, + /* Unsigned 32-bit data attribute for generic command response */ + QCA_WLAN_VENDOR_ATTR_CONFIG_GENERIC_DATA = 19, + /* Unsigned 32-bit length attribute for + * QCA_WLAN_VENDOR_ATTR_CONFIG_GENERIC_DATA */ + QCA_WLAN_VENDOR_ATTR_CONFIG_GENERIC_LENGTH = 20, + /* Unsigned 32-bit flags attribute for + * QCA_WLAN_VENDOR_ATTR_CONFIG_GENERIC_DATA */ + QCA_WLAN_VENDOR_ATTR_CONFIG_GENERIC_FLAGS = 21, + /* Unsigned 32-bit, defining the access policy. + * See enum qca_access_policy. Used with + * QCA_WLAN_VENDOR_ATTR_CONFIG_ACCESS_POLICY_IE_LIST. */ + QCA_WLAN_VENDOR_ATTR_CONFIG_ACCESS_POLICY = 22, + /* Sets the list of full set of IEs for which a specific access policy + * has to be applied. Used along with + * QCA_WLAN_VENDOR_ATTR_CONFIG_ACCESS_POLICY to control the access. + * Zero length payload can be used to clear this access constraint. */ + QCA_WLAN_VENDOR_ATTR_CONFIG_ACCESS_POLICY_IE_LIST = 23, + /* Unsigned 32-bit, specifies the interface index (netdev) for which the + * corresponding configurations are applied. If the interface index is + * not specified, the configurations are attributed to the respective + * wiphy. */ + QCA_WLAN_VENDOR_ATTR_CONFIG_IFINDEX = 24, + /* Unsigned 8-bit, for setting qpower dynamically */ + QCA_WLAN_VENDOR_ATTR_CONFIG_QPOWER = 25, + QCA_WLAN_VENDOR_ATTR_CONFIG_IGNORE_ASSOC_DISALLOWED = 26, + /* + * 8 bit unsigned value to enable/disable LRO (Large Receive Offload) + * on an interface. + * 1 - Enable , 0 - Disable. + */ + QCA_WLAN_VENDOR_ATTR_CONFIG_LRO = 50, + /* keep last */ + QCA_WLAN_VENDOR_ATTR_CONFIG_LAST, + QCA_WLAN_VENDOR_ATTR_CONFIG_MAX = + QCA_WLAN_VENDOR_ATTR_CONFIG_LAST - 1 +}; + +/** + * enum qca_wlan_vendor_attr_wifi_logger_start - Enum for wifi logger starting + * @QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_START_INVALID: Invalid attribute + * @QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_RING_ID: Ring ID + * @QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_VERBOSE_LEVEL: Verbose level + * @QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_FLAGS: Flag + * @QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_START_AFTER_LAST: Last value + * @QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_START_MAX: Max value + */ +enum qca_wlan_vendor_attr_wifi_logger_start { + QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_START_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_RING_ID = 1, + QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_VERBOSE_LEVEL = 2, + QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_FLAGS = 3, + /* keep last */ + QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_START_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_START_MAX = + QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_START_AFTER_LAST - 1, +}; + +/* + * enum qca_wlan_vendor_attr_wifi_logger_get_ring_data - Get ring data + * @QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_GET_RING_DATA_INVALID: Invalid attribute + * @QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_GET_RING_DATA_ID: Ring ID + * @QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_GET_RING_DATA_AFTER_LAST: Last value + * @QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_GET_RING_DATA_MAX: Max value + */ +enum qca_wlan_vendor_attr_wifi_logger_get_ring_data { + QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_GET_RING_DATA_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_GET_RING_DATA_ID = 1, + /* keep last */ + QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_GET_RING_DATA_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_GET_RING_DATA_MAX = + QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_GET_RING_DATA_AFTER_LAST - 1, +}; + +#ifdef WLAN_FEATURE_OFFLOAD_PACKETS +/** + * enum wlan_offloaded_packets_control - control commands + * @WLAN_START_OFFLOADED_PACKETS: start offloaded packets + * @WLAN_STOP_OFFLOADED_PACKETS: stop offloaded packets + * + */ +enum wlan_offloaded_packets_control { + WLAN_START_OFFLOADED_PACKETS = 1, + WLAN_STOP_OFFLOADED_PACKETS = 2 +}; + +/** + * enum qca_wlan_vendor_attr_offloaded_packets - offloaded packets + * @QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_INVALID: invalid + * @QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_SENDING_CONTROL: control + * @QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_REQUEST_ID: request id + * @QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_IP_PACKET_DATA: ip packet data + * @QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_SRC_MAC_ADDR: src mac address + * @QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_DST_MAC_ADDR: destination mac address + * @QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_PERIOD: period in milli seconds + * @QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_AFTER_LAST: after last + * @QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_MAX: max + */ +enum qca_wlan_vendor_attr_offloaded_packets { + QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_SENDING_CONTROL, + QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_REQUEST_ID, + + /* Packet in hex format */ + QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_IP_PACKET_DATA, + QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_SRC_MAC_ADDR, + QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_DST_MAC_ADDR, + QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_PERIOD, + + /* keep last */ + QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_MAX = + QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_AFTER_LAST - 1, +}; +#endif + +/** + * enum qca_wlan_rssi_monitoring_control - rssi control commands + * @QCA_WLAN_RSSI_MONITORING_CONTROL_INVALID: invalid + * @QCA_WLAN_RSSI_MONITORING_START: rssi monitoring start + * @QCA_WLAN_RSSI_MONITORING_STOP: rssi monitoring stop + */ +enum qca_wlan_rssi_monitoring_control { + QCA_WLAN_RSSI_MONITORING_CONTROL_INVALID = 0, + QCA_WLAN_RSSI_MONITORING_START, + QCA_WLAN_RSSI_MONITORING_STOP, +}; + +/** + * enum qca_wlan_vendor_attr_rssi_monitoring - rssi monitoring + * @QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_INVALID: Invalid + * @QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_CONTROL: control + * @QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_MAX_RSSI: max rssi + * @QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_MIN_RSSI: min rssi + * @QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_CUR_BSSID: current bssid + * @QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_CUR_RSSI: current rssi + * @QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_AFTER_LAST: after last + * @QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_MAX: max + */ +enum qca_wlan_vendor_attr_rssi_monitoring { + QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_INVALID = 0, + + QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_CONTROL, + QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_REQUEST_ID, + + QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_MAX_RSSI, + QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_MIN_RSSI, + + /* attributes to be used/received in callback */ + QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_CUR_BSSID, + QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_CUR_RSSI, + + /* keep last */ + QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_MAX = + QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_AFTER_LAST - 1, +}; + +/** + * enum set_reset_packet_filter - set packet filter control commands + * @QCA_WLAN_SET_PACKET_FILTER: Set Packet Filter + * @QCA_WLAN_GET_PACKET_FILTER: Get Packet filter + */ +enum set_reset_packet_filter { + QCA_WLAN_SET_PACKET_FILTER = 1, + QCA_WLAN_GET_PACKET_FILTER = 2, +}; + +/** + * enum qca_wlan_vendor_attr_packet_filter - BPF control commands + * @QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_INVALID: Invalid + * @QCA_WLAN_VENDOR_ATTR_SET_RESET_PACKET_FILTER: Filter ID + * @QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_VERSION: Filter Version + * @QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_SIZE: Total Length + * @QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_CURRENT_OFFSET: Current offset + * @QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_PROGRAM: length of BPF instructions + */ +enum qca_wlan_vendor_attr_packet_filter { + QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_SET_RESET_PACKET_FILTER, + QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_VERSION, + QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_ID, + QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_SIZE, + QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_CURRENT_OFFSET, + QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_PROGRAM, + + /* keep last */ + QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_MAX = + QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_AFTER_LAST - 1, +}; + +/** + * enum qca_wlan_vendor_attr_wake_stats - wake lock stats + * @QCA_WLAN_VENDOR_ATTR_GET_WAKE_STATS_INVALID: invalid + * @QCA_WLAN_VENDOR_ATTR_TOTAL_CMD_EVENT_WAKE: + * @QCA_WLAN_VENDOR_ATTR_CMD_EVENT_WAKE_CNT_PTR: + * @QCA_WLAN_VENDOR_ATTR_CMD_EVENT_WAKE_CNT_SZ: + * @QCA_WLAN_VENDOR_ATTR_TOTAL_DRIVER_FW_LOCAL_WAKE: + * @QCA_WLAN_VENDOR_ATTR_DRIVER_FW_LOCAL_WAKE_CNT_PTR: + * @QCA_WLAN_VENDOR_ATTR_DRIVER_FW_LOCAL_WAKE_CNT_SZ: + * @QCA_WLAN_VENDOR_ATTR_TOTAL_RX_DATA_WAKE: + * total rx wakeup count + * @QCA_WLAN_VENDOR_ATTR_RX_UNICAST_CNT: + * Total rx unicast packet which woke up host + * @QCA_WLAN_VENDOR_ATTR_RX_MULTICAST_CNT: + * Total rx multicast packet which woke up host + * @QCA_WLAN_VENDOR_ATTR_RX_BROADCAST_CNT: + * Total rx broadcast packet which woke up host + * @QCA_WLAN_VENDOR_ATTR_ICMP_PKT: + * wake icmp packet count + * @QCA_WLAN_VENDOR_ATTR_ICMP6_PKT: + * wake icmp6 packet count + * @QCA_WLAN_VENDOR_ATTR_ICMP6_RA: + * wake icmp6 RA packet count + * @QCA_WLAN_VENDOR_ATTR_ICMP6_NA: + * wake icmp6 NA packet count + * @QCA_WLAN_VENDOR_ATTR_ICMP6_NS: + * wake icmp6 NS packet count + * @QCA_WLAN_VENDOR_ATTR_ICMP4_RX_MULTICAST_CNT: + * Rx wake packet count due to ipv4 multicast + * @QCA_WLAN_VENDOR_ATTR_ICMP6_RX_MULTICAST_CNT: + * Rx wake packet count due to ipv6 multicast + * @QCA_WLAN_VENDOR_ATTR_OTHER_RX_MULTICAST_CNT: + * Rx wake packet count due to non-ipv4 and non-ipv6 packets + * @QCA_WLAN_VENDOR_ATTR_RSSI_BREACH_CNT: + * wake rssi breach packet count + * @QCA_WLAN_VENDOR_ATTR_LOW_RSSI_CNT: + * wake low rssi packet count + * @QCA_WLAN_VENDOR_ATTR_GSCAN_CNT: + * wake gscan packet count + * @QCA_WLAN_VENDOR_ATTR_PNO_COMPLETE_CNT: + * wake pno complete packet count + * @QCA_WLAN_VENDOR_ATTR_PNO_MATCH_CNT: + * wake pno match packet count + */ +enum qca_wlan_vendor_attr_wake_stats { + QCA_WLAN_VENDOR_ATTR_GET_WAKE_STATS_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_TOTAL_CMD_EVENT_WAKE, + QCA_WLAN_VENDOR_ATTR_CMD_EVENT_WAKE_CNT_PTR, + QCA_WLAN_VENDOR_ATTR_CMD_EVENT_WAKE_CNT_SZ, + QCA_WLAN_VENDOR_ATTR_TOTAL_DRIVER_FW_LOCAL_WAKE, + QCA_WLAN_VENDOR_ATTR_DRIVER_FW_LOCAL_WAKE_CNT_PTR, + QCA_WLAN_VENDOR_ATTR_DRIVER_FW_LOCAL_WAKE_CNT_SZ, + QCA_WLAN_VENDOR_ATTR_TOTAL_RX_DATA_WAKE, + QCA_WLAN_VENDOR_ATTR_RX_UNICAST_CNT, + QCA_WLAN_VENDOR_ATTR_RX_MULTICAST_CNT, + QCA_WLAN_VENDOR_ATTR_RX_BROADCAST_CNT, + QCA_WLAN_VENDOR_ATTR_ICMP_PKT, + QCA_WLAN_VENDOR_ATTR_ICMP6_PKT, + QCA_WLAN_VENDOR_ATTR_ICMP6_RA, + QCA_WLAN_VENDOR_ATTR_ICMP6_NA, + QCA_WLAN_VENDOR_ATTR_ICMP6_NS, + QCA_WLAN_VENDOR_ATTR_ICMP4_RX_MULTICAST_CNT, + QCA_WLAN_VENDOR_ATTR_ICMP6_RX_MULTICAST_CNT, + QCA_WLAN_VENDOR_ATTR_OTHER_RX_MULTICAST_CNT, + QCA_WLAN_VENDOR_ATTR_RSSI_BREACH_CNT, + QCA_WLAN_VENDOR_ATTR_LOW_RSSI_CNT, + QCA_WLAN_VENDOR_ATTR_GSCAN_CNT, + QCA_WLAN_VENDOR_ATTR_PNO_COMPLETE_CNT, + QCA_WLAN_VENDOR_ATTR_PNO_MATCH_CNT, + /* keep last */ + QCA_WLAN_VENDOR_GET_WAKE_STATS_AFTER_LAST, + QCA_WLAN_VENDOR_GET_WAKE_STATS_MAX = + QCA_WLAN_VENDOR_GET_WAKE_STATS_AFTER_LAST - 1, +}; + +/** + * enum qca_vendor_attr_get_tsf: Vendor attributes for TSF capture + * @QCA_WLAN_VENDOR_ATTR_TSF_INVALID: Invalid attribute value + * @QCA_WLAN_VENDOR_ATTR_TSF_CMD: enum qca_tsf_operation (u32) + * @QCA_WLAN_VENDOR_ATTR_TSF_TIMER_VALUE: Unsigned 64 bit TSF timer value + * @QCA_WLAN_VENDOR_ATTR_TSF_SOC_TIMER_VALUE: Unsigned 64 bit Synchronized + * SOC timer value at TSF capture + * @QCA_WLAN_VENDOR_ATTR_TSF_AFTER_LAST: after last + * @QCA_WLAN_VENDOR_ATTR_TSF_MAX: Max value + */ +enum qca_vendor_attr_tsf_cmd { + QCA_WLAN_VENDOR_ATTR_TSF_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_TSF_CMD, + QCA_WLAN_VENDOR_ATTR_TSF_TIMER_VALUE, + QCA_WLAN_VENDOR_ATTR_TSF_SOC_TIMER_VALUE, + QCA_WLAN_VENDOR_ATTR_TSF_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_TSF_MAX = + QCA_WLAN_VENDOR_ATTR_TSF_AFTER_LAST - 1 +}; + +/** + * enum qca_tsf_operation: TSF driver commands + * @QCA_TSF_CAPTURE: Initiate TSF Capture + * @QCA_TSF_GET: Get TSF capture value + * @QCA_TSF_SYNC_GET: Initiate TSF capture and return with captured value + */ +enum qca_tsf_cmd { + QCA_TSF_CAPTURE, + QCA_TSF_GET, + QCA_TSF_SYNC_GET, +}; + +/** + * enum qca_vendor_attr_get_preferred_freq_list - get preferred channel list + * @QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST_INVALID: invalid value + * @QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST_IFACE_TYPE: interface type + * @QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST: preferred frequency list + * @QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST_AFTER_LAST: after last + * @QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST_MAX: max + */ +enum qca_vendor_attr_get_preferred_freq_list { + QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST_INVALID, + /* A 32-unsigned value; the interface type/mode for which the preferred + * frequency list is requested (see enum qca_iface_type for possible + * values); used in both south- and north-bound. + */ + QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST_IFACE_TYPE, + /* An array of 32-unsigned values; values are frequency (MHz); used + * in north-bound only. + */ + QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST, + /* keep last */ + QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST_MAX = + QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST_AFTER_LAST - 1 +}; + +/** + * enum qca_vendor_attr_probable_oper_channel - channel hint + * @QCA_WLAN_VENDOR_ATTR_PROBABLE_OPER_CHANNEL_INVALID: invalid value + * @QCA_WLAN_VENDOR_ATTR_PROBABLE_OPER_CHANNEL_IFACE_TYPE: interface type + * @QCA_WLAN_VENDOR_ATTR_PROBABLE_OPER_CHANNEL_FREQ: frequency hint value + * @QCA_WLAN_VENDOR_ATTR_PROBABLE_OPER_CHANNEL_AFTER_LAST: last + * @QCA_WLAN_VENDOR_ATTR_PROBABLE_OPER_CHANNEL_MAX: max + */ +enum qca_vendor_attr_probable_oper_channel { + QCA_WLAN_VENDOR_ATTR_PROBABLE_OPER_CHANNEL_INVALID, + /* 32-bit unsigned value; indicates the connection/iface type likely to + * come on this channel (see enum qca_iface_type). + */ + QCA_WLAN_VENDOR_ATTR_PROBABLE_OPER_CHANNEL_IFACE_TYPE, + /* 32-bit unsigned value; the frequency (MHz) of the probable channel */ + QCA_WLAN_VENDOR_ATTR_PROBABLE_OPER_CHANNEL_FREQ, + /* keep last */ + QCA_WLAN_VENDOR_ATTR_PROBABLE_OPER_CHANNEL_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_PROBABLE_OPER_CHANNEL_MAX = + QCA_WLAN_VENDOR_ATTR_PROBABLE_OPER_CHANNEL_AFTER_LAST - 1 +}; + +/** + * enum qca_wlan_vendor_attr_gw_param_config - gateway param config + * @QCA_WLAN_VENDOR_ATTR_GW_PARAM_CONFIG_INVALID: Invalid + * @QCA_WLAN_VENDOR_ATTR_GW_PARAM_CONFIG_GW_MAC_ADDR: gateway mac addr + * @QCA_WLAN_VENDOR_ATTR_GW_PARAM_CONFIG_IPV4_ADDR: ipv4 addr + * @QCA_WLAN_VENDOR_ATTR_GW_PARAM_CONFIG_IPV6_ADDR: ipv6 addr + */ +enum qca_wlan_vendor_attr_gw_param_config { + QCA_WLAN_VENDOR_ATTR_GW_PARAM_CONFIG_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_GW_PARAM_CONFIG_GW_MAC_ADDR, + QCA_WLAN_VENDOR_ATTR_GW_PARAM_CONFIG_IPV4_ADDR, + QCA_WLAN_VENDOR_ATTR_GW_PARAM_CONFIG_IPV6_ADDR, + QCA_WLAN_VENDOR_ATTR_GW_PARAM_CONFIG_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_GW_PARAM_CONFIG_MAX = + QCA_WLAN_VENDOR_ATTR_GW_PARAM_CONFIG_AFTER_LAST - 1, +}; + +/** + * enum drv_dbs_capability - DBS capability + * @DRV_DBS_CAPABILITY_DISABLED: DBS disabled + * @DRV_DBS_CAPABILITY_1X1: 1x1 + * @DRV_DBS_CAPABILITY_2X2: 2x2 + */ +enum drv_dbs_capability { + DRV_DBS_CAPABILITY_DISABLED, /* not supported or disabled */ + DRV_DBS_CAPABILITY_1X1, + DRV_DBS_CAPABILITY_2X2, +}; + +/** + * enum qca_vendor_attr_ota_test - Enable OTA test + * @QCA_WLAN_VENDOR_ATTR_OTA_TEST_INVALID: invalid value + * @QCA_WLAN_VENDOR_ATTR_OTA_TEST_ENABLE: enable OTA test + * @QCA_WLAN_VENDOR_ATTR_OTA_TEST_AFTER_LAST: after last + * @QCA_WLAN_VENDOR_ATTR_OTA_TEST_MAX: max + */ +enum qca_vendor_attr_ota_test { + QCA_WLAN_VENDOR_ATTR_OTA_TEST_INVALID, + /* 8-bit unsigned value to indicate if OTA test is enabled */ + QCA_WLAN_VENDOR_ATTR_OTA_TEST_ENABLE, + /* keep last */ + QCA_WLAN_VENDOR_ATTR_OTA_TEST_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_OTA_TEST_MAX = + QCA_WLAN_VENDOR_ATTR_OTA_TEST_AFTER_LAST - 1 +}; + +/** enum qca_vendor_attr_txpower_scale - vendor sub commands index + * @QCA_WLAN_VENDOR_ATTR_TXPOWER_SCALE_INVALID: invalid value + * @QCA_WLAN_VENDOR_ATTR_TXPOWER_SCALE: scaling value + * @QCA_WLAN_VENDOR_ATTR_TXPOWER_SCALE_AFTER_LAST: last value + * @QCA_WLAN_VENDOR_ATTR_TXPOWER_SCALE_MAX: max value + */ +enum qca_vendor_attr_txpower_scale { + QCA_WLAN_VENDOR_ATTR_TXPOWER_SCALE_INVALID, + /* 8-bit unsigned value to indicate the scaling of tx power */ + QCA_WLAN_VENDOR_ATTR_TXPOWER_SCALE, + /* keep last */ + QCA_WLAN_VENDOR_ATTR_TXPOWER_SCALE_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_TXPOWER_SCALE_MAX = + QCA_WLAN_VENDOR_ATTR_TXPOWER_SCALE_AFTER_LAST - 1 +}; + +/** + * enum qca_vendor_attr_txpower_scale_decr_db - vendor sub commands index + * @QCA_WLAN_VENDOR_ATTR_TXPOWER_SCALE_DECR_DB_INVALID: invalid value + * @QCA_WLAN_VENDOR_ATTR_TXPOWER_SCALE_DECR_DB: scaling value + * @QCA_WLAN_VENDOR_ATTR_TXPOWER_SCALE_DECR_DB_AFTER_LAST: last value + * @QCA_WLAN_VENDOR_ATTR_TXPOWER_SCALE_DECR_DB_MAX: max value + */ +enum qca_vendor_attr_txpower_scale_decr_db { + QCA_WLAN_VENDOR_ATTR_TXPOWER_SCALE_DECR_DB_INVALID, + /* 8-bit unsigned value to indicate the scaling of tx power */ + QCA_WLAN_VENDOR_ATTR_TXPOWER_SCALE_DECR_DB, + /* keep last */ + QCA_WLAN_VENDOR_ATTR_TXPOWER_SCALE_DECR_DB_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_TXPOWER_SCALE_DECR_DB_MAX = + QCA_WLAN_VENDOR_ATTR_TXPOWER_SCALE_DECR_DB_AFTER_LAST - 1 +}; + +/** + * enum dfs_mode - state of DFS mode + * @DFS_MODE_NONE: DFS mode attribute is none + * @DFS_MODE_ENABLE: DFS mode is enabled + * @DFS_MODE_DISABLE: DFS mode is disabled + * @DFS_MODE_DEPRIORITIZE: Deprioritize DFS channels in scanning + */ +enum dfs_mode { + DFS_MODE_NONE, + DFS_MODE_ENABLE, + DFS_MODE_DISABLE, + DFS_MODE_DEPRIORITIZE +}; + +/** + * enum qca_wlan_vendor_attr_acs_config - Config params for ACS + * @QCA_WLAN_VENDOR_ATTR_ACS_MODE_INVALID: Invalid + * @QCA_WLAN_VENDOR_ATTR_ACS_DFS_MODE: Dfs mode for ACS + * QCA_WLAN_VENDOR_ATTR_ACS_CHANNEL_HINT: channel_hint for ACS + * QCA_WLAN_VENDOR_ATTR_ACS_DFS_AFTER_LAST: after_last + * QCA_WLAN_VENDOR_ATTR_ACS_DFS_MAX: max attribute + */ +enum qca_wlan_vendor_attr_acs_config { + QCA_WLAN_VENDOR_ATTR_ACS_MODE_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_ACS_DFS_MODE, + QCA_WLAN_VENDOR_ATTR_ACS_CHANNEL_HINT, + + QCA_WLAN_VENDOR_ATTR_ACS_DFS_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_ACS_DFS_MAX = + QCA_WLAN_VENDOR_ATTR_ACS_DFS_AFTER_LAST - 1, + +}; + +/** + * enum qca_wlan_vendor_attr_sta_connect_roam_policy_config - + * config params for sta roam policy + * @QCA_WLAN_VENDOR_ATTR_STA_CONNECT_ROAM_POLICY_INVALID: Invalid + * @QCA_WLAN_VENDOR_ATTR_STA_DFS_MODE: If sta should skip Dfs channels + * @QCA_WLAN_VENDOR_ATTR_STA_SKIP_UNSAFE_CHANNEL: + * If sta should skip unsafe channels or not in scanning + * @QCA_WLAN_VENDOR_ATTR_STA_CONNECT_ROAM_POLICY_LAST: + * @QCA_WLAN_VENDOR_ATTR_STA_CONNECT_ROAM_POLICY_MAX: max attribute + */ +enum qca_wlan_vendor_attr_sta_connect_roam_policy_config { + QCA_WLAN_VENDOR_ATTR_STA_CONNECT_ROAM_POLICY_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_STA_DFS_MODE, + QCA_WLAN_VENDOR_ATTR_STA_SKIP_UNSAFE_CHANNEL, + + QCA_WLAN_VENDOR_ATTR_STA_CONNECT_ROAM_POLICY_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_STA_CONNECT_ROAM_POLICY_MAX = + QCA_WLAN_VENDOR_ATTR_STA_CONNECT_ROAM_POLICY_AFTER_LAST - 1, +}; + + +/** + * enum qca_wlan_vendor_attr_sap_config - config params for sap configuration + * @QCA_WLAN_VENDOR_ATTR_SAP_CONFIG_INVALID: invalid + * @QCA_WLAN_VENDOR_ATTR_SAP_CONFIG_CHANNEL: Channel on which SAP should start + * @QCA_WLAN_VENDOR_ATTR_SAP_MANDATORY_FREQUENCY_LIST: List of frequencies on + * which AP is expected to operate. This is irrespective of ACS configuration. + * This list is a priority based one and is looked for before the AP is created + * to ensure the best concurrency sessions (avoid MCC and use DBS/SCC) co-exist + * in the system. + * @QCA_WLAN_VENDOR_ATTR_SAP_CONFIG_AFTER_LAST: after last + * @QCA_WLAN_VENDOR_ATTR_SAP_CONFIG_MAX: max attribute + */ +enum qca_wlan_vendor_attr_sap_config { + QCA_WLAN_VENDOR_ATTR_SAP_CONFIG_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_SAP_CONFIG_CHANNEL, + QCA_WLAN_VENDOR_ATTR_SAP_MANDATORY_FREQUENCY_LIST = 2, + /* keep last */ + QCA_WLAN_VENDOR_ATTR_SAP_CONFIG_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_SAP_CONFIG_MAX = + QCA_WLAN_VENDOR_ATTR_SAP_CONFIG_AFTER_LAST - 1, +}; + +/** + * enum qca_wlan_vendor_attr_p2p_listen_offload - vendor sub commands index + * @QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_INVALID: invalid value + * @QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_CHANNEL: + * A 32-bit unsigned value; the P2P listen frequency (MHz); must be one + * of the social channels. + * @QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_PERIOD: listen offload period + * A 32-bit unsigned value; the P2P listen offload period (ms). + * @QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_INTERVAL: + * A 32-bit unsigned value; the P2P listen interval duration (ms). + * @QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_COUNT: + * A 32-bit unsigned value; number of interval times the Firmware needs + * to run the offloaded P2P listen operation before it stops. + * @QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_DEVICE_TYPES: device types + * An array of unsigned 8-bit characters; vendor information elements. + * @QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_VENDOR_IE: vendor IEs + * @QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_CTRL_FLAG: control flag for FW + * A 32-bit unsigned value; a control flag to indicate whether listen + * results need to be flushed to wpa_supplicant. + * @QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_STOP_REASON: offload stop reason + * A 8-bit unsigned value; reason code for P2P listen offload stop + * event. + * @QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_AFTER_LAST: last value + * @QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_MAX: max value + */ +enum qca_wlan_vendor_attr_p2p_listen_offload { + QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_CHANNEL, + QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_PERIOD, + QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_INTERVAL, + QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_COUNT, + QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_DEVICE_TYPES, + QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_VENDOR_IE, + QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_CTRL_FLAG, + QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_STOP_REASON, + /* keep last */ + QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_MAX = + QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_AFTER_LAST - 1 +}; + +/** + * enum qca_wlan_vendor_drv_info - WLAN driver info + * @QCA_WLAN_VENDOR_ATTR_DRV_INFO_INVALID: Invalid + * @QCA_WLAN_VENDOR_ATTR_DRV_INFO_BUS_SIZE: Maximum Message size info + * between Firmware & Host. + */ +enum qca_wlan_vendor_drv_info { + QCA_WLAN_VENDOR_ATTR_DRV_INFO_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_DRV_INFO_BUS_SIZE, + + /* keep last */ + QCA_WLAN_VENDOR_ATTR_DRV_INFO_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_DRV_INFO_MAX = + QCA_WLAN_VENDOR_ATTR_DRV_INFO_AFTER_LAST - 1, +}; + +/** + * enum qca_wlan_vendor_attr_encryption_test - Attributes to + * validate encryption engine + * + * @QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_NEEDS_DECRYPTION: Flag attribute. + * This will be included if the request is for decryption; if not included, + * the request is treated as a request for encryption by default. + * @QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_CIPHER: Unsigned 32-bit value + * indicating the key cipher suite. Takes same values as + * NL80211_ATTR_KEY_CIPHER. + * @QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_KEYID: Unsigned 8-bit value + * Key Id to be used for encryption + * @QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_TK: Array of 8-bit values. + * Key (TK) to be used for encryption/decryption + * @QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_PN: Array of 8-bit values. + * Packet number to be specified for encryption/decryption + * 6 bytes for TKIP/CCMP/GCMP. + * @QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_DATA: Array of 8-bit values + * representing the 802.11 packet (header + payload + FCS) that + * needs to be encrypted/decrypted. + * Encrypted/decrypted response from the driver will also be sent + * to userspace with the same attribute. + */ +enum qca_wlan_vendor_attr_encryption_test { + QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_NEEDS_DECRYPTION, + QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_CIPHER, + QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_KEYID, + QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_TK, + QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_PN, + QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_DATA, + + /* keep last */ + QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_MAX = + QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_AFTER_LAST - 1 +}; + +/** + * enum qca_wlan_vendor_attr_tdls_configuration - Attributes for + * @QCA_NL80211_VENDOR_SUBCMD_CONFIGURE_TDLS configuration to the host driver. + * + * @QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_TRIGGER_MODE: Configure the TDLS trigger + * mode in the host driver. enum qca_wlan_vendor_tdls_trigger_mode + * represents the different TDLS trigger modes. + * @QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_TX_STATS_PERIOD: Duration (u32) within + * which QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_TX_THRESHOLD number + * of packets shall meet the criteria for implicit TDLS setup. + * @QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_TX_THRESHOLD: Number (u32) of Tx/Rx + * packets within a duration. + * QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_TX_STATS_PERIOD to initiate + * a TDLS setup. + * @QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_DISCOVERY_PERIOD: Time (u32) to inititate + * a TDLS Discovery to the Peer. + * @QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_MAX_DISCOVERY_ATTEMPT: Max number (u32) of + * discovery attempts to know the TDLS capability of the peer. A peer is + * marked as TDLS not capable if there is no response for all the attempts. + * @QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_IDLE_TIMEOUT: Represents a duration (u32) + * within which QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_IDLE_PACKET_THRESHOLD + * number of TX / RX frames meet the criteria for TDLS teardown. + * @QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_IDLE_PACKET_THRESHOLD: Minumum number + * (u32) of Tx/Rx packets within a duration + * CA_WLAN_VENDOR_ATTR_TDLS_CONFIG_IDLE_TIMEOUT to tear down a TDLS link + * @QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_SETUP_RSSI_THRESHOLD: Threshold + * corresponding to the RSSI of the peer below which a TDLS + * setup is triggered. + * @QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_TEARDOWN_RSSI_THRESHOLD: Threshold + * corresponding to the RSSI of the peer above which + * a TDLS teardown is triggered. + */ +enum qca_wlan_vendor_attr_tdls_configuration { + QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_TRIGGER_MODE = 1, + + /* Attributes configuring the TDLS Implicit Trigger */ + QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_TX_STATS_PERIOD = 2, + QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_TX_THRESHOLD = 3, + QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_DISCOVERY_PERIOD = 4, + QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_MAX_DISCOVERY_ATTEMPT = 5, + QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_IDLE_TIMEOUT = 6, + QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_IDLE_PACKET_THRESHOLD = 7, + QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_SETUP_RSSI_THRESHOLD = 8, + QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_TEARDOWN_RSSI_THRESHOLD = 9, + + /* keep last */ + QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_MAX = + QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_AFTER_LAST - 1 +}; + +/** + * enum qca_wlan_vendor_tdls_trigger_mode: Represents the TDLS trigger mode in + * the driver. + * + * The following are the different values for + * QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_TRIGGER_MODE. + * + * @QCA_WLAN_VENDOR_TDLS_TRIGGER_MODE_EXPLICIT: The trigger to + * initiate/teardown the TDLS connection to a respective peer comes + * from the user space. wpa_supplicant provides the commands + * TDLS_SETUP, TDLS_TEARDOWN, TDLS_DISCOVER to do this. + * @QCA_WLAN_VENDOR_TDLS_TRIGGER_MODE_IMPLICIT: Host driver triggers this TDLS + * setup/teardown to the eligible peer once the configured criteria + * (such as TX/RX threshold, RSSI) is met. The attributes + * in QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_IMPLICIT_PARAMS correspond to + * the different configuration criteria for the TDLS trigger from the + * host driver. + * @QCA_WLAN_VENDOR_TDLS_TRIGGER_MODE_EXTERNAL: Enables the driver to trigger + * the TDLS setup / teardown through the implicit mode, only to the + * configured MAC addresses(wpa_supplicant, with tdls_external_control = 1, + * configures the MAC address through TDLS_SETUP/TDLS_TEARDOWN commands). + * External mode works on top of the implicit mode, thus the host Driver + * is expected to be configured in TDLS Implicit mode too to operate in + * External mode. Configuring External mode alone without Implicit + * mode is invalid. + * + * All the above implementations work as expected only when the host driver + * advertises the capability WPA_DRIVER_FLAGS_TDLS_EXTERNAL_SETUP - + * representing that the TDLS message exchange is not internal to the host + * driver, but depends on wpa_supplicant to do the message exchange. + */ +enum qca_wlan_vendor_tdls_trigger_mode { + QCA_WLAN_VENDOR_TDLS_TRIGGER_MODE_EXPLICIT = 1 << 0, + QCA_WLAN_VENDOR_TDLS_TRIGGER_MODE_IMPLICIT = 1 << 1, + QCA_WLAN_VENDOR_TDLS_TRIGGER_MODE_EXTERNAL = 1 << 2, +}; + +/** + * enum qca_vendor_attr_sar_limits_selections - Source of SAR power limits + * @QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_BDF0: Select SAR profile #0 + * that is hard-coded in the Board Data File (BDF). + * @QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_BDF1: Select SAR profile #1 + * that is hard-coded in the Board Data File (BDF). + * @QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_BDF2: Select SAR profile #2 + * that is hard-coded in the Board Data File (BDF). + * @QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_BDF3: Select SAR profile #3 + * that is hard-coded in the Board Data File (BDF). + * @QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_BDF4: Select SAR profile #4 + * that is hard-coded in the Board Data File (BDF). + * @QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_NONE: Do not select any + * source of SAR power limits, thereby disabling the SAR power + * limit feature. + * @QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_USER: Select the SAR power + * limits configured by %QCA_NL80211_VENDOR_SUBCMD_SET_SAR. + * + * This enumerates the valid set of values that may be supplied for + * attribute %QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT in an instance of + * the %QCA_NL80211_VENDOR_SUBCMD_SET_SAR_LIMITS vendor command. + */ +enum qca_vendor_attr_sar_limits_selections { + QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_BDF0 = 0, + QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_BDF1 = 1, + QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_BDF2 = 2, + QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_BDF3 = 3, + QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_BDF4 = 4, + QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_NONE = 5, + QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_USER = 6, +}; + +/** + * enum qca_vendor_attr_sar_limits_spec_modulations - + * SAR limits specification modulation + * @QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_MODULATION_CCK - + * CCK modulation + * @QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_MODULATION_OFDM - + * OFDM modulation + * + * This enumerates the valid set of values that may be supplied for + * attribute %QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_MODULATION in an + * instance of attribute %QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC in an + * instance of the %QCA_NL80211_VENDOR_SUBCMD_SET_SAR_LIMITS vendor + * command. + */ +enum qca_vendor_attr_sar_limits_spec_modulations { + QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_MODULATION_CCK = 0, + QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_MODULATION_OFDM = 1, +}; + +/** + * enum qca_vendor_attr_sar_limits - Attributes for SAR power limits + * + * @QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SAR_ENABLE: Optional (u32) value to + * select which SAR power limit table should be used. Valid + * values are enumerated in enum + * %qca_vendor_attr_sar_limits_selections. The existing SAR + * power limit selection is unchanged if this attribute is not + * present. + * + * @QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_NUM_SPECS: Optional (u32) value + * which specifies the number of SAR power limit specifications + * which will follow. + * + * @QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC: Nested array of SAR power + * limit specifications. The number of specifications is + * specified by @QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_NUM_SPECS. Each + * specification contains a set of + * QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_* attributes. A + * specification is uniquely identified by the attributes + * %QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_BAND, + * %QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_CHAIN, and + * %QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_MODULATION and always + * contains as a payload the attribute + * %QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_POWER_LIMIT. + * + * @QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_BAND: Optional (u32) value to + * indicate for which band this specification applies. Valid + * values are enumerated in enum %nl80211_band (although not all + * bands may be supported by a given device). If the attribute is + * not supplied then the specification will be applied to all + * supported bands. + * + * @QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_CHAIN: Optional (u32) value + * to indicate for which antenna chain this specification + * applies, i.e. 1 for chain 1, 2 for chain 2, etc. If the + * attribute is not supplied then the specification will be + * applied to all chains. + * + * @QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_MODULATION: Optional (u32) + * value to indicate for which modulation scheme this + * specification applies. Valid values are enumerated in enum + * %qca_vendor_attr_sar_limits_spec_modulations. If the attribute + * is not supplied then the specification will be applied to all + * modulation schemes. + * + * @QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_POWER_LIMIT: Required (u32) + * value to specify the actual power limit value in steps of 0.5 + * dbm. + * + * These attributes are used with %QCA_NL80211_VENDOR_SUBCMD_SET_SAR_LIMITS. + */ +enum qca_vendor_attr_sar_limits { + QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SAR_ENABLE = 1, + QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_NUM_SPECS = 2, + QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC = 3, + QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_BAND = 4, + QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_CHAIN = 5, + QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_MODULATION = 6, + QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_POWER_LIMIT = 7, + + QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_MAX = + QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_AFTER_LAST - 1 +}; + +struct cfg80211_bss *wlan_hdd_cfg80211_update_bss_db(hdd_adapter_t *pAdapter, + tCsrRoamInfo *pRoamInfo); + +int wlan_hdd_cfg80211_pmksa_candidate_notify(hdd_adapter_t *pAdapter, + tCsrRoamInfo *pRoamInfo, + int index, bool preauth); + +#ifdef FEATURE_WLAN_LFR_METRICS +QDF_STATUS wlan_hdd_cfg80211_roam_metrics_preauth(hdd_adapter_t *pAdapter, + tCsrRoamInfo *pRoamInfo); + +QDF_STATUS wlan_hdd_cfg80211_roam_metrics_preauth_status(hdd_adapter_t * + pAdapter, + tCsrRoamInfo * + pRoamInfo, + bool preauth_status); + +QDF_STATUS wlan_hdd_cfg80211_roam_metrics_handover(hdd_adapter_t *pAdapter, + tCsrRoamInfo *pRoamInfo); +#endif + +#ifdef FEATURE_WLAN_WAPI +void wlan_hdd_cfg80211_set_key_wapi(hdd_adapter_t *pAdapter, uint8_t key_index, + const uint8_t *mac_addr, const uint8_t *key, + int key_Len); +#endif +hdd_context_t *hdd_cfg80211_wiphy_alloc(int priv_size); + +int wlan_hdd_cfg80211_tdls_scan(struct wiphy *wiphy, + struct cfg80211_scan_request *request, + uint8_t source); + +int wlan_hdd_cfg80211_scan(struct wiphy *wiphy, + struct cfg80211_scan_request *request); + +int wlan_hdd_cfg80211_init(struct device *dev, + struct wiphy *wiphy, struct hdd_config *pCfg); + +void wlan_hdd_cfg80211_deinit(struct wiphy *wiphy); + +void wlan_hdd_update_wiphy(hdd_context_t *hdd_ctx); + +void wlan_hdd_update_11n_mode(struct hdd_config *cfg); + +int wlan_hdd_cfg80211_register(struct wiphy *wiphy); +void wlan_hdd_cfg80211_register_frames(hdd_adapter_t *pAdapter); + +void wlan_hdd_cfg80211_deregister_frames(hdd_adapter_t *pAdapter); + +void hdd_reg_notifier(struct wiphy *wiphy, + struct regulatory_request *request); + +extern void hdd_conn_set_connection_state(hdd_adapter_t *pAdapter, + eConnectionState connState); +QDF_STATUS wlan_hdd_validate_operation_channel(hdd_adapter_t *pAdapter, + int channel); +#ifdef FEATURE_WLAN_TDLS +int wlan_hdd_cfg80211_send_tdls_discover_req(struct wiphy *wiphy, + struct net_device *dev, u8 *peer); +#endif +#ifdef WLAN_FEATURE_GTK_OFFLOAD +extern void wlan_hdd_cfg80211_update_replay_counter_callback(void + *callbackContext, + tpSirGtkOffloadGetInfoRspParams + pGtkOffloadGetInfoRsp); +#endif +void *wlan_hdd_change_country_code_cb(void *pAdapter); +void hdd_select_cbmode(hdd_adapter_t *pAdapter, uint8_t operationChannel, + struct ch_params_s *ch_params); + +uint8_t *wlan_hdd_cfg80211_get_ie_ptr(const uint8_t *ies_ptr, int length, + uint8_t eid); +/** + * wlan_hdd_is_ap_supports_immediate_power_save() - to find certain vendor APs + * which do not support immediate power-save. + * @ies: beacon IE of the AP which STA is connecting/connected to + * @length: beacon IE length only + * + * This API takes the IE of connected/connecting AP and determines that + * whether it has specific vendor OUI. If it finds then it will return false to + * notify that AP doesn't support immediate power-save. + * + * Return: true or false based on findings + */ +bool wlan_hdd_is_ap_supports_immediate_power_save(uint8_t *ies, int length); +void wlan_hdd_del_station(hdd_adapter_t *adapter); + +#if defined(USE_CFG80211_DEL_STA_V2) +int wlan_hdd_cfg80211_del_station(struct wiphy *wiphy, + struct net_device *dev, + struct station_del_parameters *param); +#else +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)) +int wlan_hdd_cfg80211_del_station(struct wiphy *wiphy, + struct net_device *dev, + const uint8_t *mac); +#else +int wlan_hdd_cfg80211_del_station(struct wiphy *wiphy, + struct net_device *dev, + uint8_t *mac); +#endif +#endif /* USE_CFG80211_DEL_STA_V2 */ + + +#if defined(QCA_WIFI_FTM) && defined(CONFIG_NL80211_TESTMODE) +void wlan_hdd_testmode_rx_event(void *buf, size_t buf_len); +#endif + +#if defined(FEATURE_WLAN_CH_AVOID) || defined(FEATURE_WLAN_FORCE_SAP_SCC) +int wlan_hdd_send_avoid_freq_event(hdd_context_t *pHddCtx, + tHddAvoidFreqList * pAvoidFreqList); +#endif /* FEATURE_WLAN_CH_AVOID || FEATURE_WLAN_FORCE_SAP_SCC */ + +#ifdef FEATURE_WLAN_EXTSCAN +void wlan_hdd_cfg80211_extscan_callback(void *ctx, + const uint16_t evType, void *pMsg); +#endif /* FEATURE_WLAN_EXTSCAN */ + +/** + * wlan_hdd_rso_cmd_status_cb() - HDD callback to read RSO command status + * @ctx: void pointer to hdd context + * @rso_status: rso command status + * + * This callback function is invoked by firmware to update + * the RSO(ROAM SCAN OFFLOAD) command status. + * + * Return: None + */ +void wlan_hdd_rso_cmd_status_cb(void *ctx, struct rso_cmd_status *rso_status); + +void hdd_rssi_threshold_breached(void *hddctx, + struct rssi_breach_event *data); + +struct cfg80211_bss *wlan_hdd_cfg80211_update_bss_list(hdd_adapter_t *pAdapter, + tSirMacAddr bssid); + +int wlan_hdd_cfg80211_update_bss(struct wiphy *wiphy, + hdd_adapter_t *pAdapter, + uint32_t scan_timestamp); + +void wlan_hdd_cfg80211_acs_ch_select_evt(hdd_adapter_t *adapter); + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +int wlan_hdd_send_roam_auth_event(hdd_adapter_t *adapter, uint8_t *bssid, + uint8_t *req_rsn_ie, uint32_t req_rsn_length, uint8_t + *rsp_rsn_ie, uint32_t rsp_rsn_length, tCsrRoamInfo + *roam_info_ptr); +#else +static inline int wlan_hdd_send_roam_auth_event(hdd_adapter_t *adapter, + uint8_t *bssid, uint8_t *req_rsn_ie, uint32_t req_rsn_length, + uint8_t *rsp_rsn_ie, uint32_t rsp_rsn_length, tCsrRoamInfo + *roam_info_ptr) +{ + return 0; +} +#endif + +int wlan_hdd_cfg80211_update_apies(hdd_adapter_t *adapter); + +#if !(defined (SUPPORT_WDEV_CFG80211_VENDOR_EVENT_ALLOC)) && \ + (LINUX_VERSION_CODE < KERNEL_VERSION(4, 1, 0)) && \ + !(defined(WITH_BACKPORTS)) + +static inline struct sk_buff * +backported_cfg80211_vendor_event_alloc(struct wiphy *wiphy, + struct wireless_dev *wdev, + int approxlen, + int event_idx, gfp_t gfp) +{ + struct sk_buff *skb; + + skb = cfg80211_vendor_event_alloc(wiphy, approxlen, event_idx, gfp); + + if (skb && wdev) { + struct nlattr *attr; + u32 ifindex = wdev->netdev->ifindex; + + nla_nest_cancel(skb, ((void **)skb->cb)[2]); + if (nla_put_u32(skb, NL80211_ATTR_IFINDEX, ifindex)) + goto nla_fail; + + attr = nla_nest_start(skb, NL80211_ATTR_VENDOR_DATA); + ((void **)skb->cb)[2] = attr; + } + + return skb; + +nla_fail: + kfree_skb(skb); + return NULL; +} +#define cfg80211_vendor_event_alloc backported_cfg80211_vendor_event_alloc +#endif +int wlan_hdd_request_pre_cac(uint8_t channel); +int wlan_hdd_sap_cfg_dfs_override(hdd_adapter_t *adapter); + +enum cds_con_mode wlan_hdd_convert_nl_iftype_to_hdd_type( + enum nl80211_iftype type); + +int wlan_hdd_disable_dfs_chan_scan(hdd_context_t *hdd_ctx, + hdd_adapter_t *adapter, + uint32_t no_dfs_flag); + +int wlan_hdd_cfg80211_update_band(struct wiphy *wiphy, + eCsrBand eBand); + +void hdd_get_bpf_offload_cb(void *hdd_context, struct sir_bpf_get_offload *); +void hdd_init_bpf_completion(void); + +#if defined(CFG80211_DISCONNECTED_V2) || \ +(LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0)) +static inline void wlan_hdd_cfg80211_indicate_disconnect(struct net_device *dev, + bool locally_generated, + int reason) +{ + cfg80211_disconnected(dev, reason, NULL, 0, + locally_generated, GFP_KERNEL); +} +#else +static inline void wlan_hdd_cfg80211_indicate_disconnect(struct net_device *dev, + bool locally_generated, + int reason) +{ + cfg80211_disconnected(dev, reason, NULL, 0, + GFP_KERNEL); +} +#endif +struct cfg80211_bss *wlan_hdd_cfg80211_inform_bss_frame(hdd_adapter_t *pAdapter, + tSirBssDescription *bss_desc); + +/* + * As of 4.7, ieee80211_band is removed; add shims so we can reference + * nl80211_band instead + */ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 7, 0)) +#define NUM_NL80211_BANDS ((enum nl80211_band)IEEE80211_NUM_BANDS) +#endif + +/** + * hdd_lost_link_info_cb() - callback function to get lost link information + * @context: HDD context + * @lost_link_info: lost link information + * + * Return: none + */ +void hdd_lost_link_info_cb(void *context, + struct sir_lost_link_info *lost_link_info); +/* + * hdd_get_sap_operating_band: Get current operating channel + * for sap. + * @hdd_ctx: hdd context + * + * Return : Corresponding band for SAP operating channel + */ +uint8_t hdd_get_sap_operating_band(hdd_context_t *hdd_ctx); + +/** + * hdd_process_defer_disconnect() - Handle the deferred disconnect + * @adapter: HDD Adapter + * + * If roaming is in progress and there is a request to + * disconnect the session, then it is deferred. Once + * roaming is complete/aborted, then this routine is + * used to resume the disconnect that was deferred + * + * Return: None + */ +void hdd_process_defer_disconnect(hdd_adapter_t *adapter); + +/** + * wlan_hdd_try_disconnect() - try disconnnect from previous connection + * @adapter: Pointer to adapter + * + * This function is used to disconnect from previous connection + * + * Return: 0 for success, non-zero for failure + */ +int wlan_hdd_try_disconnect(hdd_adapter_t *adapter); + +/** + * hdd_update_cca_info_cb() - stores congestion value in station context + * @context : HDD context + * @congestion : congestion + * @vdev_id : vdev id + * + * Return: None + */ +void hdd_update_cca_info_cb(void *context, uint32_t congestion, + uint32_t vdev_id); + +#endif diff --git a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_conc_ut.c b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_conc_ut.c new file mode 100644 index 0000000000000000000000000000000000000000..8de063cede9a3a80708cfe2ba88e842489557571 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_conc_ut.c @@ -0,0 +1,875 @@ +/* + * Copyright (c) 2015-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* Include files */ + +#include +#include +#include +#include +#include +#include "wlan_hdd_trace.h" +#include "cds_concurrency.h" +#include "wlan_hdd_conc_ut.h" +#include "qdf_types.h" +#include "qdf_trace.h" +#include "cds_utils.h" +#include "cds_reg_service.h" +#include "wma_types.h" +#include "wma.h" +#include "wma_api.h" + +#define NUMBER_OF_SCENARIO 300 +#define MAX_ALLOWED_CHAR_IN_REPORT 50 + +/** + * struct report_t: Data structure to fill report + * + * @title: title of the concurrency case scenario + * @first_persona: device type of first persona + * @second_persona: device type of second persona + * @third_persona: device type of third persona + * @dbs_value: string to mention whether dbs enable or disable + * @system_conf: string to mention what is system's configuration + * @status: status field + * @result_code: string to mention whether test case passed or failed + * @reason: reason why test case failed + * @pcl: preferred channel list + * + * This structure will be used by unit test framework to fill + * report after running various concurrency scenarios. + */ +struct report_t { + char title[2 * MAX_ALLOWED_CHAR_IN_REPORT]; + char first_persona[MAX_ALLOWED_CHAR_IN_REPORT]; + char second_persona[MAX_ALLOWED_CHAR_IN_REPORT]; + char third_persona[MAX_ALLOWED_CHAR_IN_REPORT]; + char dbs_value[MAX_ALLOWED_CHAR_IN_REPORT]; + char system_conf[MAX_ALLOWED_CHAR_IN_REPORT]; + bool status; + char result_code[MAX_ALLOWED_CHAR_IN_REPORT]; + char reason[MAX_ALLOWED_CHAR_IN_REPORT]; + char pcl[2 * QDF_MAX_NUM_CHAN]; +}; + +static struct report_t report[NUMBER_OF_SCENARIO]; +static uint32_t report_idx; + +static uint8_t wlan_hdd_valid_type_of_persona(uint32_t sub_type) +{ + switch (sub_type) { + case CDS_STA_MODE: + return WMI_VDEV_TYPE_STA; + case CDS_IBSS_MODE: + return WMI_VDEV_TYPE_IBSS; + case CDS_SAP_MODE: + case CDS_P2P_CLIENT_MODE: + case CDS_P2P_GO_MODE: + return WMI_VDEV_TYPE_AP; + default: + return WMI_VDEV_TYPE_STA; + } +} + +static const char *system_config_to_string(uint8_t idx) +{ + switch (idx) { + CASE_RETURN_STRING(CDS_THROUGHPUT); + CASE_RETURN_STRING(CDS_POWERSAVE); + CASE_RETURN_STRING(CDS_LATENCY); + default: + return "Unknown"; + } + +} + +static const char *device_mode_to_string(uint8_t idx) +{ + switch (idx) { + CASE_RETURN_STRING(CDS_STA_MODE); + CASE_RETURN_STRING(CDS_SAP_MODE); + CASE_RETURN_STRING(CDS_P2P_CLIENT_MODE); + CASE_RETURN_STRING(CDS_P2P_GO_MODE); + CASE_RETURN_STRING(CDS_IBSS_MODE); + default: + return "none"; + } +} + +static const char *pcl_type_to_string(uint8_t idx) +{ + switch (idx) { + CASE_RETURN_STRING(CDS_NONE); + CASE_RETURN_STRING(CDS_24G); + CASE_RETURN_STRING(CDS_5G); + CASE_RETURN_STRING(CDS_SCC_CH); + CASE_RETURN_STRING(CDS_MCC_CH); + CASE_RETURN_STRING(CDS_SCC_CH_24G); + CASE_RETURN_STRING(CDS_SCC_CH_5G); + CASE_RETURN_STRING(CDS_24G_SCC_CH); + CASE_RETURN_STRING(CDS_5G_SCC_CH); + CASE_RETURN_STRING(CDS_SCC_ON_5_SCC_ON_24_24G); + CASE_RETURN_STRING(CDS_SCC_ON_5_SCC_ON_24_5G); + CASE_RETURN_STRING(CDS_SCC_ON_24_SCC_ON_5_24G); + CASE_RETURN_STRING(CDS_SCC_ON_24_SCC_ON_5_5G); + CASE_RETURN_STRING(CDS_SCC_ON_5_SCC_ON_24); + CASE_RETURN_STRING(CDS_SCC_ON_24_SCC_ON_5); + CASE_RETURN_STRING(CDS_MCC_CH_24G); + CASE_RETURN_STRING(CDS_MCC_CH_5G); + CASE_RETURN_STRING(CDS_24G_MCC_CH); + CASE_RETURN_STRING(CDS_5G_MCC_CH); + default: + return "Unknown"; + } +} + +void clean_report(hdd_context_t *hdd_ctx) +{ + uint32_t idx = 0; + while (idx < NUMBER_OF_SCENARIO) { + qdf_mem_zero(&report[idx], sizeof(struct report_t)); + idx++; + } + report_idx = 0; +} + +void print_report(hdd_context_t *hdd_ctx) +{ + uint32_t idx = 0; + pr_info("+----------Report start -----------+\n"); + while (idx < report_idx) { + pr_info("Idx:[%d]\nTitle:%s\nResult:[%s]\n\t1st_person[%s]\n\t2nd_persona[%s]\n\t3rd_persona[%s]\n\tDBS[%s]\n\tsystem_config[%s]\n\treason[%s]\n\tpcl[%s]\n", + idx, + report[idx].title, report[idx].result_code, + report[idx].first_persona, report[idx].second_persona, + report[idx].third_persona, report[idx].dbs_value, + report[idx].system_conf, report[idx].reason, + report[idx].pcl); + idx++; + } + pr_info("+----------Report end -----------+\n"); +} + +void fill_report(hdd_context_t *hdd_ctx, char *title, + uint32_t first_persona, uint32_t second_persona, uint32_t third_persona, + uint32_t chnl_1st_conn, uint32_t chnl_2nd_conn, uint32_t chnl_3rd_conn, + bool status, enum cds_pcl_type pcl_type, char *reason, uint8_t *pcl) +{ + int i; + char buf[4] = {0}; + + if (report_idx >= NUMBER_OF_SCENARIO) + return; + snprintf(report[report_idx].title, + 2 * MAX_ALLOWED_CHAR_IN_REPORT, "pcl for[%s] pcl_type[%s]", + title, pcl_type_to_string(pcl_type)); + if (chnl_1st_conn == 0) + snprintf(report[report_idx].first_persona, + MAX_ALLOWED_CHAR_IN_REPORT, "%s", + device_mode_to_string(first_persona)); + else + snprintf(report[report_idx].first_persona, + MAX_ALLOWED_CHAR_IN_REPORT, + "%s-chnl{%d}", + device_mode_to_string(first_persona), chnl_1st_conn); + if (chnl_2nd_conn == 0) + snprintf(report[report_idx].second_persona, + MAX_ALLOWED_CHAR_IN_REPORT, "%s", + device_mode_to_string(second_persona)); + else + snprintf(report[report_idx].second_persona, + MAX_ALLOWED_CHAR_IN_REPORT, + "%s-chnl{%d}", + device_mode_to_string(second_persona), chnl_2nd_conn); + if (chnl_3rd_conn == 0) + snprintf(report[report_idx].third_persona, + MAX_ALLOWED_CHAR_IN_REPORT, "%s", + device_mode_to_string(third_persona)); + else + snprintf(report[report_idx].third_persona, + MAX_ALLOWED_CHAR_IN_REPORT, + "%s-chnl{%d}", + device_mode_to_string(third_persona), chnl_3rd_conn); + + report[report_idx].status = status; + snprintf(report[report_idx].dbs_value, + MAX_ALLOWED_CHAR_IN_REPORT, "%s", + wma_is_hw_dbs_capable() ? "enable" : "disable"); + snprintf(report[report_idx].system_conf, + MAX_ALLOWED_CHAR_IN_REPORT, "%s", + system_config_to_string(hdd_ctx->config->conc_system_pref)); + snprintf(report[report_idx].result_code, + MAX_ALLOWED_CHAR_IN_REPORT, "%s", + status ? "PASS" : "FAIL"); + snprintf(report[report_idx].reason, + MAX_ALLOWED_CHAR_IN_REPORT, + reason); + if (pcl) { + qdf_mem_zero(report[report_idx].pcl, + sizeof(report[report_idx].pcl)); + for (i = 0; i < QDF_MAX_NUM_CHAN; i++) { + if (pcl[i] == 0) + break; + qdf_mem_zero(buf, sizeof(buf)); + snprintf(buf, sizeof(buf), "%d ", pcl[i]); + strlcat(report[report_idx].pcl, buf, + sizeof(report[report_idx].pcl)); + strlcat(report[report_idx].pcl, ", ", + sizeof(report[report_idx].pcl)); + } + } + report_idx++; +} + +static bool wlan_hdd_validate_pcl(hdd_context_t *hdd_ctx, + enum cds_pcl_type pcl_type, uint8_t *pcl, uint32_t pcl_len, + uint8_t first_connection_chnl, uint8_t second_connection_chnl, + char *reason, uint32_t reason_length) +{ + bool status = true; + uint32_t first_idx = 0; + + if ((pcl_type != CDS_NONE) && (pcl_len == 0)) { + snprintf(reason, reason_length, "no of channels = 0"); + return false; + } + + switch (pcl_type) { + case CDS_NONE: + if (pcl_len != 0) { + snprintf(reason, reason_length, "no of channels>0"); + return false; + } + break; + case CDS_5G: + for (first_idx = 0; first_idx < pcl_len; first_idx++) { + if (!CDS_IS_CHANNEL_5GHZ(pcl[first_idx])) { + snprintf(reason, reason_length, + "2G channel found"); + return false; + } + } + break; + case CDS_24G: + for (first_idx = 0; first_idx < pcl_len; first_idx++) { + if (!CDS_IS_CHANNEL_24GHZ(pcl[first_idx])) { + snprintf(reason, reason_length, + "5G channel found"); + return false; + } + } + break; + case CDS_SCC_CH: + if (second_connection_chnl > 0 && + (first_connection_chnl != second_connection_chnl)) { + snprintf(reason, reason_length, + "invalid connections"); + return false; + } + if (pcl[0] != first_connection_chnl) { + snprintf(reason, reason_length, + "No SCC found"); + return false; + } + break; + case CDS_MCC_CH: + if ((pcl[0] != first_connection_chnl) && + ((second_connection_chnl > 0) && + (pcl[0] != second_connection_chnl))) { + snprintf(reason, reason_length, + "MCC invalid"); + return false; + } + if ((second_connection_chnl > 0) && + (pcl[1] != first_connection_chnl && + pcl[1] != second_connection_chnl)) { + snprintf(reason, reason_length, + "MCC invalid"); + return false; + } + break; + case CDS_SCC_CH_24G: + if (second_connection_chnl > 0 && + (first_connection_chnl != second_connection_chnl)) { + snprintf(reason, reason_length, + "invalid connections"); + return false; + } + if (pcl[0] != first_connection_chnl) { + snprintf(reason, reason_length, + "No SCC found"); + return false; + } + if (!CDS_IS_CHANNEL_24GHZ(pcl[pcl_len-1])) { + snprintf(reason, reason_length, + "No 2.4Ghz chnl"); + return false; + } + break; + case CDS_SCC_CH_5G: + if (second_connection_chnl > 0 && + (first_connection_chnl != second_connection_chnl)) { + snprintf(reason, reason_length, + "invalid connections"); + return false; + } + if (pcl[0] != first_connection_chnl) { + snprintf(reason, reason_length, + "No SCC found"); + return false; + } + if (!CDS_IS_CHANNEL_5GHZ(pcl[pcl_len-1])) { + snprintf(reason, reason_length, + "No 5Ghz chnl"); + return false; + } + break; + case CDS_24G_SCC_CH: + if (!CDS_IS_CHANNEL_24GHZ(pcl[0])) { + snprintf(reason, reason_length, + "No 2.4Ghz chnl"); + return false; + } + if (second_connection_chnl > 0 && + (first_connection_chnl != second_connection_chnl)) { + snprintf(reason, reason_length, + "invalid connections"); + return false; + } + if (pcl[pcl_len-1] != first_connection_chnl) { + snprintf(reason, reason_length, + "No SCC found"); + return false; + } + break; + case CDS_5G_SCC_CH: + if (!CDS_IS_CHANNEL_5GHZ(pcl[0])) { + snprintf(reason, reason_length, + "No 5Ghz chnl"); + return false; + } + if (second_connection_chnl > 0 && + (first_connection_chnl != second_connection_chnl)) { + snprintf(reason, reason_length, + "invalid connections"); + return false; + } + if (pcl[pcl_len-1] != first_connection_chnl) { + snprintf(reason, reason_length, + "No SCC found"); + return false; + } + break; + case CDS_MCC_CH_24G: + if ((pcl[0] != first_connection_chnl) && + ((second_connection_chnl > 0) && + (pcl[0] != second_connection_chnl))) { + snprintf(reason, reason_length, + "MCC invalid"); + return false; + } + if ((second_connection_chnl > 0) && + (pcl[1] != first_connection_chnl && + pcl[1] != second_connection_chnl)) { + snprintf(reason, reason_length, + "MCC invalid"); + return false; + } + if (!CDS_IS_CHANNEL_24GHZ(pcl[pcl_len-1])) { + snprintf(reason, reason_length, + "No 24Ghz chnl"); + return false; + } + break; + case CDS_MCC_CH_5G: + if ((pcl[0] != first_connection_chnl) && + ((second_connection_chnl > 0) && + (pcl[0] != second_connection_chnl))) { + snprintf(reason, reason_length, + "MCC invalid"); + return false; + } + if ((second_connection_chnl > 0) && + (pcl[1] != first_connection_chnl && + pcl[1] != second_connection_chnl)) { + snprintf(reason, reason_length, + "MCC invalid"); + return false; + } + if (!CDS_IS_CHANNEL_5GHZ(pcl[pcl_len-1])) { + snprintf(reason, reason_length, + "No 5Ghz chnl"); + return false; + } + break; + case CDS_24G_MCC_CH: + if (!CDS_IS_CHANNEL_24GHZ(pcl[0])) { + snprintf(reason, reason_length, + "No 24Ghz chnl"); + return false; + } + if ((pcl[pcl_len-1] != first_connection_chnl) && + ((second_connection_chnl > 0) && + (pcl[pcl_len-1] != second_connection_chnl))) { + snprintf(reason, reason_length, + "MCC invalid"); + return false; + } + if ((second_connection_chnl > 0) && + (pcl[pcl_len-2] != first_connection_chnl && + pcl[pcl_len-2] != second_connection_chnl)) { + snprintf(reason, reason_length, + "MCC invalid"); + return false; + } + break; + case CDS_5G_MCC_CH: + if (!CDS_IS_CHANNEL_5GHZ(pcl[0])) { + snprintf(reason, reason_length, + "No 5Ghz chnl"); + return false; + } + if ((pcl[pcl_len-1] != first_connection_chnl) && + ((second_connection_chnl > 0) && + (pcl[pcl_len-1] != second_connection_chnl))) { + snprintf(reason, reason_length, + "MCC invalid"); + return false; + } + if ((second_connection_chnl > 0) && + (pcl[pcl_len-2] != first_connection_chnl && + pcl[pcl_len-2] != second_connection_chnl)) { + snprintf(reason, reason_length, + "MCC invalid"); + return false; + } + break; + case CDS_SCC_ON_5_SCC_ON_24_24G: + if (!CDS_IS_CHANNEL_5GHZ(pcl[0]) || + (pcl[0] != first_connection_chnl && + pcl[0] != second_connection_chnl)) { + snprintf(reason, reason_length, + "No 5Ghz chnl/scc"); + return false; + } + if (!CDS_IS_CHANNEL_24GHZ(pcl[1]) || + (pcl[1] != first_connection_chnl && + pcl[1] != second_connection_chnl)) { + snprintf(reason, reason_length, + "No 24Ghz chnl/scc"); + return false; + } + if (!CDS_IS_CHANNEL_24GHZ(pcl[pcl_len-1])) { + snprintf(reason, reason_length, + "No 24Ghz chnls"); + return false; + } + break; + case CDS_SCC_ON_5_SCC_ON_24_5G: + if (!CDS_IS_CHANNEL_5GHZ(pcl[0]) || + (pcl[0] != first_connection_chnl && + pcl[0] != second_connection_chnl)) { + snprintf(reason, reason_length, + "No 5Ghz chnl/scc"); + return false; + } + if (!CDS_IS_CHANNEL_24GHZ(pcl[1]) || + (pcl[1] != first_connection_chnl && + pcl[1] != second_connection_chnl)) { + snprintf(reason, reason_length, + "No 24Ghz chnl/scc"); + return false; + } + if (!CDS_IS_CHANNEL_5GHZ(pcl[pcl_len-1])) { + snprintf(reason, reason_length, + "No 5Ghz chnls"); + return false; + } + break; + case CDS_SCC_ON_24_SCC_ON_5_24G: + if (!CDS_IS_CHANNEL_24GHZ(pcl[0]) || + (pcl[0] != first_connection_chnl && + pcl[0] != second_connection_chnl)) { + snprintf(reason, reason_length, + "No 24Ghz chnl/scc"); + return false; + } + if (!CDS_IS_CHANNEL_5GHZ(pcl[1]) || + (pcl[1] != first_connection_chnl && + pcl[1] != second_connection_chnl)) { + snprintf(reason, reason_length, + "No 5Ghz chnl/scc"); + return false; + } + if (!CDS_IS_CHANNEL_24GHZ(pcl[pcl_len-1])) { + snprintf(reason, reason_length, + "No 24Ghz chnls"); + return false; + } + break; + case CDS_SCC_ON_24_SCC_ON_5_5G: + if (!CDS_IS_CHANNEL_24GHZ(pcl[0]) || + (pcl[0] != first_connection_chnl && + pcl[0] != second_connection_chnl)) { + snprintf(reason, reason_length, + "No 24Ghz chnl/scc"); + return false; + } + if (!CDS_IS_CHANNEL_5GHZ(pcl[1]) || + (pcl[1] != first_connection_chnl && + pcl[1] != second_connection_chnl)) { + snprintf(reason, reason_length, + "No 5Ghz chnl/scc"); + return false; + } + if (!CDS_IS_CHANNEL_5GHZ(pcl[pcl_len-1])) { + snprintf(reason, reason_length, + "No 5Ghz chnls"); + return false; + } + break; + case CDS_SCC_ON_5_SCC_ON_24: + if (!CDS_IS_CHANNEL_5GHZ(pcl[0]) || + (pcl[0] != first_connection_chnl && + pcl[0] != second_connection_chnl)) { + snprintf(reason, reason_length, + "No 5Ghz chnl/scc"); + return false; + } + if (!CDS_IS_CHANNEL_24GHZ(pcl[1]) || + (pcl[1] != first_connection_chnl && + pcl[1] != second_connection_chnl)) { + snprintf(reason, reason_length, + "No 24Ghz chnl/scc"); + return false; + } + if (pcl_len != 2) { + snprintf(reason, reason_length, + "more than 2 chnls"); + return false; + } + break; + case CDS_SCC_ON_24_SCC_ON_5: + if (!CDS_IS_CHANNEL_24GHZ(pcl[0]) || + (pcl[0] != first_connection_chnl && + pcl[0] != second_connection_chnl)) { + snprintf(reason, reason_length, + "No 24Ghz chnl/scc"); + return false; + } + if (!CDS_IS_CHANNEL_5GHZ(pcl[1]) || + (pcl[1] != first_connection_chnl && + pcl[1] != second_connection_chnl)) { + snprintf(reason, reason_length, + "No 5Ghz chnl/scc"); + return false; + } + if (pcl_len != 2) { + snprintf(reason, reason_length, + "more than 2 chnls"); + return false; + } + break; + default: + snprintf(reason, reason_length, + "Unknown option"); + status = false; + } + if (status == true) { + snprintf(reason, reason_length, + "success"); + } + return status; +} + +static void wlan_hdd_map_subtypes_hdd_wma(enum cds_con_mode *dst, + enum cds_con_mode *src) +{ + /* + * wma defined sap subtype as 0 + * Rest of the mappings are same + * In future, if mapping gets changed then re-map it here + */ + if (*src == CDS_SAP_MODE) + *dst = 0; + else + *dst = *src; +} + +void wlan_hdd_one_connection_scenario(hdd_context_t *hdd_ctx) +{ + enum cds_con_mode sub_type; + enum cds_conc_priority_mode system_pref = + hdd_ctx->config->conc_system_pref; + uint8_t pcl[QDF_MAX_NUM_CHAN] = {0}, + weight_list[QDF_MAX_NUM_CHAN] = {0}; + uint32_t pcl_len = 0; + bool status = false; + enum cds_pcl_type pcl_type; + char reason[20] = {0}; + QDF_STATUS ret; + struct cds_sme_cbacks sme_cbacks; + + sme_cbacks.sme_get_valid_channels = sme_get_cfg_valid_channels; + sme_cbacks.sme_get_nss_for_vdev = sme_get_vdev_type_nss; + /* flush the entire table first */ + ret = cds_init_policy_mgr(&sme_cbacks); + if (!QDF_IS_STATUS_SUCCESS(ret)) { + hdd_err("Policy manager initialization failed"); + return; + } + + for (sub_type = 0; sub_type < CDS_MAX_NUM_OF_MODE; sub_type++) { + /* validate one connection is created or no */ + if (cds_get_connection_count() != 0) { + hdd_err("Test failed - No. of connection is not 0"); + return; + } + qdf_mem_zero(pcl, sizeof(pcl)); + pcl_len = 0; + pcl_type = get_pcl_from_first_conn_table(sub_type, system_pref); + + /* check PCL value for second connection is correct or no */ + cds_get_pcl(sub_type, pcl, &pcl_len, + weight_list, QDF_ARRAY_SIZE(weight_list)); + status = wlan_hdd_validate_pcl(hdd_ctx, + pcl_type, pcl, pcl_len, 0, 0, + reason, sizeof(reason)); + if ((pcl_type == CDS_MAX_PCL_TYPE) && (pcl[0] == 0)) + continue; + + fill_report(hdd_ctx, "1 connection", sub_type, + CDS_MAX_NUM_OF_MODE, + CDS_MAX_NUM_OF_MODE, + 0, 0, 0, + status, pcl_type, reason, pcl); + } +} + +void wlan_hdd_two_connections_scenario(hdd_context_t *hdd_ctx, + uint8_t first_chnl, enum cds_chain_mode first_chain_mask) +{ + uint8_t vdevid = 0, tx_stream = 2, rx_stream = 2; + uint8_t type = WMI_VDEV_TYPE_STA, channel_id = first_chnl, mac_id = 1; + uint8_t pcl[QDF_MAX_NUM_CHAN] = {0}, + weight_list[QDF_MAX_NUM_CHAN] = {0}; + uint32_t pcl_len = 0; + enum cds_chain_mode chain_mask = first_chain_mask; + enum cds_con_mode sub_type, next_sub_type, dummy_type; + enum cds_conc_priority_mode system_pref = + hdd_ctx->config->conc_system_pref; + enum cds_pcl_type pcl_type; + enum cds_one_connection_mode second_index; + char reason[20] = {0}; + bool status = false; + QDF_STATUS ret; + struct cds_sme_cbacks sme_cbacks; + + for (sub_type = CDS_STA_MODE; + sub_type < CDS_MAX_NUM_OF_MODE; sub_type++) { + type = wlan_hdd_valid_type_of_persona(sub_type); + + sme_cbacks.sme_get_valid_channels = sme_get_cfg_valid_channels; + sme_cbacks.sme_get_nss_for_vdev = sme_get_vdev_type_nss; + /* flush the entire table first */ + ret = cds_init_policy_mgr(&sme_cbacks); + if (!QDF_IS_STATUS_SUCCESS(ret)) { + hdd_err("Policy manager initialization failed"); + return; + } + + /* sub_type mapping between HDD and WMA are different */ + wlan_hdd_map_subtypes_hdd_wma(&dummy_type, &sub_type); + /* add first connection as STA */ + cds_incr_connection_count_utfw(vdevid, tx_stream, + rx_stream, chain_mask, type, dummy_type, + channel_id, mac_id); + /* validate one connection is created or no */ + if (cds_get_connection_count() != 1) { + hdd_err("Test failed - No. of connection is not 1"); + return; + } + next_sub_type = CDS_STA_MODE; + while (next_sub_type < CDS_MAX_NUM_OF_MODE) { + /* get the PCL value & check the channels accordingly */ + second_index = + cds_get_second_connection_pcl_table_index(); + if (CDS_MAX_ONE_CONNECTION_MODE == second_index) { + /* not valid combination*/ + hdd_err("couldn't find index for 2nd connection pcl table"); + next_sub_type++; + continue; + } + qdf_mem_zero(pcl, sizeof(pcl)); + pcl_len = 0; + pcl_type = get_pcl_from_second_conn_table(second_index, + next_sub_type, system_pref, + wma_is_hw_dbs_capable()); + /* check PCL for second connection is correct or no */ + cds_get_pcl(next_sub_type, pcl, &pcl_len, + weight_list, QDF_ARRAY_SIZE(weight_list)); + status = wlan_hdd_validate_pcl(hdd_ctx, + pcl_type, pcl, pcl_len, channel_id, 0, + reason, sizeof(reason)); + if ((pcl_type == CDS_MAX_PCL_TYPE) && (pcl[0] == 0)) { + next_sub_type++; + continue; + } + fill_report(hdd_ctx, "2 connections", sub_type, + next_sub_type, + CDS_MAX_NUM_OF_MODE, first_chnl, + 0, 0, status, pcl_type, reason, pcl); + next_sub_type++; + } + } +} + +void wlan_hdd_three_connections_scenario(hdd_context_t *hdd_ctx, + uint8_t first_chnl, uint8_t second_chnl, + enum cds_chain_mode chain_mask, uint8_t use_same_mac) +{ + uint8_t vdevid_1 = 0, tx_stream_1 = 2, rx_stream_1 = 2; + uint8_t vdevid_2 = 1, tx_stream_2 = 2, rx_stream_2 = 2; + uint8_t channel_id_1 = first_chnl, channel_id_2 = second_chnl; + uint8_t mac_id_1, mac_id_2; + uint8_t type_1 = WMI_VDEV_TYPE_STA, type_2 = WMI_VDEV_TYPE_STA; + uint8_t pcl[MAX_NUM_CHAN] = {0}, weight_list[MAX_NUM_CHAN] = {0}; + uint32_t pcl_len = 0; + enum cds_chain_mode chain_mask_1; + enum cds_chain_mode chain_mask_2; + enum cds_con_mode sub_type_1, sub_type_2, next_sub_type; + enum cds_con_mode dummy_type_1, dummy_type_2; + enum cds_conc_priority_mode system_pref = + hdd_ctx->config->conc_system_pref; + enum cds_pcl_type pcl_type; + enum cds_two_connection_mode third_index; + char reason[20] = {0}; + bool status = false; + QDF_STATUS ret; + struct cds_sme_cbacks sme_cbacks; + + /* let's set the chain_mask, mac_ids*/ + if (chain_mask == CDS_TWO_TWO) { + mac_id_1 = 1; + mac_id_2 = 1; + chain_mask_1 = CDS_TWO_TWO; + chain_mask_2 = CDS_TWO_TWO; + } else if (use_same_mac == 1) { + mac_id_1 = 1; + mac_id_2 = 1; + chain_mask_1 = CDS_ONE_ONE; + chain_mask_2 = CDS_ONE_ONE; + } else { + mac_id_1 = 1; + mac_id_2 = 2; + chain_mask_1 = CDS_ONE_ONE; + chain_mask_2 = CDS_ONE_ONE; + } + + for (sub_type_1 = CDS_STA_MODE; + sub_type_1 < CDS_MAX_NUM_OF_MODE; sub_type_1++) { + + type_1 = wlan_hdd_valid_type_of_persona(sub_type_1); + + sme_cbacks.sme_get_valid_channels = sme_get_cfg_valid_channels; + sme_cbacks.sme_get_nss_for_vdev = sme_get_vdev_type_nss; + /* flush the entire table first */ + ret = cds_init_policy_mgr(&sme_cbacks); + if (!QDF_IS_STATUS_SUCCESS(ret)) { + hdd_err("Policy manager initialization failed"); + return; + } + + /* sub_type mapping between HDD and WMA are different */ + wlan_hdd_map_subtypes_hdd_wma(&dummy_type_1, &sub_type_1); + /* add first connection as STA */ + cds_incr_connection_count_utfw(vdevid_1, + tx_stream_1, rx_stream_1, chain_mask_1, type_1, + dummy_type_1, channel_id_1, mac_id_1); + /* validate one connection is created or no */ + if (cds_get_connection_count() != 1) { + hdd_err("Test fail - No. of connection not 1"); + return; + } + for (sub_type_2 = CDS_STA_MODE; + sub_type_2 < CDS_MAX_NUM_OF_MODE; sub_type_2++) { + + type_2 = wlan_hdd_valid_type_of_persona(sub_type_2); + /* sub_type mapping between HDD and WMA are different */ + wlan_hdd_map_subtypes_hdd_wma(&dummy_type_2, + &sub_type_2); + cds_incr_connection_count_utfw(vdevid_2, + tx_stream_2, rx_stream_2, chain_mask_2, type_2, + dummy_type_2, channel_id_2, mac_id_2); + /* validate two connections are created or no */ + if (cds_get_connection_count() != 2) { + hdd_err("Test fail - No. connection not 2"); + return; + } + next_sub_type = CDS_STA_MODE; + while (next_sub_type < CDS_MAX_NUM_OF_MODE) { + third_index = + cds_get_third_connection_pcl_table_index(); + if (CDS_MAX_TWO_CONNECTION_MODE == + third_index) { + /* not valid combination */ + next_sub_type++; + continue; + } + qdf_mem_zero(pcl, sizeof(pcl)); + pcl_len = 0; + pcl_type = + get_pcl_from_third_conn_table( + third_index, next_sub_type, + system_pref, + wma_is_hw_dbs_capable()); + cds_get_pcl(next_sub_type, + pcl, &pcl_len, + weight_list, + QDF_ARRAY_SIZE(weight_list)); + status = wlan_hdd_validate_pcl(hdd_ctx, + pcl_type, pcl, pcl_len, + channel_id_1, channel_id_2, + reason, sizeof(reason)); + if ((pcl_type == CDS_MAX_PCL_TYPE) && + (pcl[0] == 0)) { + next_sub_type++; + continue; + } + fill_report(hdd_ctx, "3 connections", + sub_type_1, sub_type_2, + next_sub_type, first_chnl, + second_chnl, 0, status, + pcl_type, reason, pcl); + next_sub_type++; + } + /* remove entry to make a room for next iteration */ + cds_decr_connection_count(vdevid_2); + } + next_sub_type = CDS_STA_MODE; + } +} diff --git a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_debugfs.c b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_debugfs.c new file mode 100644 index 0000000000000000000000000000000000000000..edfb1ff1416c167a845ceb6e5c5409d391c16fc0 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_debugfs.c @@ -0,0 +1,916 @@ +/* + * Copyright (c) 2013-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: wlan_hdd_debugfs.c + * + * This driver currently supports the following debugfs files: + * wlan_wcnss/wow_enable to enable/disable WoWL. + * wlan_wcnss/wow_pattern to configure WoWL patterns. + * wlan_wcnss/pattern_gen to configure periodic TX patterns. + */ + +#ifdef WLAN_OPEN_SOURCE +#include +#include +#include +#include + +#define MAX_USER_COMMAND_SIZE_WOWL_ENABLE 8 +#define MAX_USER_COMMAND_SIZE_WOWL_PATTERN 512 +#define MAX_USER_COMMAND_SIZE_FRAME 4096 + +#ifdef WLAN_POWER_DEBUGFS +#define POWER_DEBUGFS_BUFFER_MAX_LEN 4096 +#endif + +/** + * __wcnss_wowenable_write() - wow_enable debugfs handler + * @file: debugfs file handle + * @buf: text being written to the debugfs + * @count: size of @buf + * @ppos: (unused) offset into the virtual file system + * + * Return: number of bytes processed + */ +static ssize_t __wcnss_wowenable_write(struct file *file, + const char __user *buf, size_t count, + loff_t *ppos) +{ + hdd_adapter_t *pAdapter; + hdd_context_t *hdd_ctx; + char cmd[MAX_USER_COMMAND_SIZE_WOWL_ENABLE + 1]; + char *sptr, *token; + uint8_t wow_enable = 0; + uint8_t wow_mp = 0; + uint8_t wow_pbm = 0; + int ret; + + ENTER(); + + pAdapter = (hdd_adapter_t *)file->private_data; + if ((NULL == pAdapter) || (WLAN_HDD_ADAPTER_MAGIC != pAdapter->magic)) { + hdd_alert("Invalid adapter or adapter has invalid magic."); + + return -EINVAL; + } + + hdd_ctx = WLAN_HDD_GET_CTX(pAdapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + if (!wlan_hdd_modules_are_enabled(hdd_ctx)) + return -EINVAL; + + if (!sme_is_feature_supported_by_fw(WOW)) { + hdd_err("Wake-on-Wireless feature is not supported in firmware!"); + + return -EINVAL; + } + + if (count > MAX_USER_COMMAND_SIZE_WOWL_ENABLE) { + hdd_err("Command length is larger than %d bytes.", + MAX_USER_COMMAND_SIZE_WOWL_ENABLE); + + return -EINVAL; + } + + /* Get command from user */ + if (copy_from_user(cmd, buf, count)) + return -EFAULT; + cmd[count] = '\0'; + sptr = cmd; + + /* Get enable or disable wow */ + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + if (kstrtou8(token, 0, &wow_enable)) + return -EINVAL; + + /* Disable wow */ + if (!wow_enable) { + if (!hdd_exit_wowl(pAdapter)) { + hdd_err("hdd_exit_wowl failed!"); + + return -EFAULT; + } + + return count; + } + + /* Get enable or disable magic packet mode */ + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + if (kstrtou8(token, 0, &wow_mp)) + return -EINVAL; + if (wow_mp > 1) + wow_mp = 1; + + /* Get enable or disable pattern byte matching mode */ + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + if (kstrtou8(token, 0, &wow_pbm)) + return -EINVAL; + if (wow_pbm > 1) + wow_pbm = 1; + + if (!hdd_enter_wowl(pAdapter, wow_mp, wow_pbm)) { + hdd_err("hdd_enter_wowl failed!"); + + return -EFAULT; + } + EXIT(); + return count; +} + +/** + * wcnss_wowenable_write() - SSR wrapper for wcnss_wowenable_write + * @file: file pointer + * @buf: buffer + * @count: count + * @ppos: position pointer + * + * Return: 0 on success, error number otherwise + */ +static ssize_t wcnss_wowenable_write(struct file *file, + const char __user *buf, + size_t count, loff_t *ppos) +{ + ssize_t ret; + + cds_ssr_protect(__func__); + ret = __wcnss_wowenable_write(file, buf, count, ppos); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __wcnss_wowpattern_write() - wow_pattern debugfs handler + * @file: debugfs file handle + * @buf: text being written to the debugfs + * @count: size of @buf + * @ppos: (unused) offset into the virtual file system + * + * Return: number of bytes processed + */ +static ssize_t __wcnss_wowpattern_write(struct file *file, + const char __user *buf, size_t count, + loff_t *ppos) +{ + hdd_adapter_t *pAdapter = (hdd_adapter_t *) file->private_data; + hdd_context_t *hdd_ctx; + char cmd[MAX_USER_COMMAND_SIZE_WOWL_PATTERN + 1]; + char *sptr, *token; + uint8_t pattern_idx = 0; + uint8_t pattern_offset = 0; + char *pattern_buf; + char *pattern_mask; + int ret; + + ENTER(); + + if ((NULL == pAdapter) || (WLAN_HDD_ADAPTER_MAGIC != pAdapter->magic)) { + hdd_alert("Invalid adapter or adapter has invalid magic."); + + return -EINVAL; + } + + hdd_ctx = WLAN_HDD_GET_CTX(pAdapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + if (!wlan_hdd_modules_are_enabled(hdd_ctx)) + return -EINVAL; + + if (!sme_is_feature_supported_by_fw(WOW)) { + hdd_err("Wake-on-Wireless feature is not supported in firmware!"); + + return -EINVAL; + } + + if (count > MAX_USER_COMMAND_SIZE_WOWL_PATTERN) { + hdd_err("Command length is larger than %d bytes.", + MAX_USER_COMMAND_SIZE_WOWL_PATTERN); + + return -EINVAL; + } + + /* Get command from user */ + if (copy_from_user(cmd, buf, count)) + return -EFAULT; + cmd[count] = '\0'; + sptr = cmd; + + /* Get pattern idx */ + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + + if (kstrtou8(token, 0, &pattern_idx)) + return -EINVAL; + + /* Get pattern offset */ + token = strsep(&sptr, " "); + + /* Delete pattern if no further argument */ + if (!token) { + hdd_del_wowl_ptrn_debugfs(pAdapter, pattern_idx); + + return count; + } + + if (kstrtou8(token, 0, &pattern_offset)) + return -EINVAL; + + /* Get pattern */ + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + + pattern_buf = token; + + /* Get pattern mask */ + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + + pattern_mask = token; + pattern_mask[strlen(pattern_mask) - 1] = '\0'; + + hdd_add_wowl_ptrn_debugfs(pAdapter, pattern_idx, pattern_offset, + pattern_buf, pattern_mask); + EXIT(); + return count; +} + +/** + * wcnss_wowpattern_write() - SSR wrapper for __wcnss_wowpattern_write + * @file: file pointer + * @buf: buffer + * @count: count + * @ppos: position pointer + * + * Return: 0 on success, error number otherwise + */ +static ssize_t wcnss_wowpattern_write(struct file *file, + const char __user *buf, + size_t count, loff_t *ppos) +{ + ssize_t ret; + + cds_ssr_protect(__func__); + ret = __wcnss_wowpattern_write(file, buf, count, ppos); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * wcnss_patterngen_write() - pattern_gen debugfs handler + * @file: debugfs file handle + * @buf: text being written to the debugfs + * @count: size of @buf + * @ppos: (unused) offset into the virtual file system + * + * Return: number of bytes processed + */ +static ssize_t __wcnss_patterngen_write(struct file *file, + const char __user *buf, size_t count, + loff_t *ppos) +{ + hdd_adapter_t *pAdapter; + hdd_context_t *pHddCtx; + tSirAddPeriodicTxPtrn *addPeriodicTxPtrnParams; + tSirDelPeriodicTxPtrn *delPeriodicTxPtrnParams; + + char *cmd, *sptr, *token; + uint8_t pattern_idx = 0; + uint8_t pattern_duration = 0; + char *pattern_buf; + uint16_t pattern_len = 0; + uint16_t i = 0; + QDF_STATUS status; + int ret; + + ENTER(); + + pAdapter = (hdd_adapter_t *)file->private_data; + if ((NULL == pAdapter) || (WLAN_HDD_ADAPTER_MAGIC != pAdapter->magic)) { + hdd_alert("Invalid adapter or adapter has invalid magic."); + + return -EINVAL; + } + + pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + ret = wlan_hdd_validate_context(pHddCtx); + if (0 != ret) + return ret; + + if (!wlan_hdd_modules_are_enabled(pHddCtx)) + return -EINVAL; + + if (!sme_is_feature_supported_by_fw(WLAN_PERIODIC_TX_PTRN)) { + hdd_err("Periodic Tx Pattern Offload feature is not supported in firmware!"); + return -EINVAL; + } + + /* Get command from user */ + if (count <= MAX_USER_COMMAND_SIZE_FRAME) + cmd = qdf_mem_malloc(count + 1); + else { + hdd_err("Command length is larger than %d bytes.", + MAX_USER_COMMAND_SIZE_FRAME); + + return -EINVAL; + } + + if (!cmd) { + hdd_err("Memory allocation for cmd failed!"); + return -ENOMEM; + } + + if (copy_from_user(cmd, buf, count)) { + qdf_mem_free(cmd); + return -EFAULT; + } + cmd[count] = '\0'; + sptr = cmd; + + /* Get pattern idx */ + token = strsep(&sptr, " "); + if (!token) + goto failure; + if (kstrtou8(token, 0, &pattern_idx)) + goto failure; + + if (pattern_idx > (MAXNUM_PERIODIC_TX_PTRNS - 1)) { + hdd_err("Pattern index %d is not in the range (0 ~ %d).", + pattern_idx, MAXNUM_PERIODIC_TX_PTRNS - 1); + + goto failure; + } + + /* Get pattern duration */ + token = strsep(&sptr, " "); + if (!token) + goto failure; + if (kstrtou8(token, 0, &pattern_duration)) + goto failure; + + /* Delete pattern using index if duration is 0 */ + if (!pattern_duration) { + delPeriodicTxPtrnParams = + qdf_mem_malloc(sizeof(tSirDelPeriodicTxPtrn)); + if (!delPeriodicTxPtrnParams) { + hdd_err("Memory allocation failed!"); + qdf_mem_free(cmd); + return -ENOMEM; + } + delPeriodicTxPtrnParams->ucPtrnId = pattern_idx; + delPeriodicTxPtrnParams->ucPatternIdBitmap = 1 << pattern_idx; + qdf_copy_macaddr(&delPeriodicTxPtrnParams->mac_address, + &pAdapter->macAddressCurrent); + + /* Delete pattern */ + status = sme_del_periodic_tx_ptrn(pHddCtx->hHal, + delPeriodicTxPtrnParams); + if (QDF_STATUS_SUCCESS != status) { + hdd_err("sme_del_periodic_tx_ptrn() failed!"); + + qdf_mem_free(delPeriodicTxPtrnParams); + goto failure; + } + qdf_mem_free(cmd); + qdf_mem_free(delPeriodicTxPtrnParams); + return count; + } + + /* + * In SAP mode allow configuration without any connection check + * In STA mode check if it's in connected state before adding + * patterns + */ + hdd_info("device mode %d", pAdapter->device_mode); + if ((QDF_STA_MODE == pAdapter->device_mode) && + (!hdd_conn_is_connected(WLAN_HDD_GET_STATION_CTX_PTR(pAdapter)))) { + hdd_err("Not in Connected state!"); + goto failure; + } + + /* Get pattern */ + token = strsep(&sptr, " "); + if (!token) + goto failure; + + pattern_buf = token; + pattern_buf[strlen(pattern_buf) - 1] = '\0'; + pattern_len = strlen(pattern_buf); + + /* Since the pattern is a hex string, 2 characters represent 1 byte. */ + if (pattern_len % 2) { + hdd_err("Malformed pattern!"); + + goto failure; + } else + pattern_len >>= 1; + + if (pattern_len < 14 || pattern_len > PERIODIC_TX_PTRN_MAX_SIZE) { + hdd_err("Not an 802.3 frame!"); + + goto failure; + } + + addPeriodicTxPtrnParams = qdf_mem_malloc(sizeof(tSirAddPeriodicTxPtrn)); + if (!addPeriodicTxPtrnParams) { + hdd_err("Memory allocation failed!"); + qdf_mem_free(cmd); + return -ENOMEM; + } + + addPeriodicTxPtrnParams->ucPtrnId = pattern_idx; + addPeriodicTxPtrnParams->usPtrnIntervalMs = pattern_duration * 500; + addPeriodicTxPtrnParams->ucPtrnSize = pattern_len; + qdf_copy_macaddr(&addPeriodicTxPtrnParams->mac_address, + &pAdapter->macAddressCurrent); + + /* Extract the pattern */ + for (i = 0; i < addPeriodicTxPtrnParams->ucPtrnSize; i++) { + addPeriodicTxPtrnParams->ucPattern[i] = + (hex_to_bin(pattern_buf[0]) << 4) + + hex_to_bin(pattern_buf[1]); + + /* Skip to next byte */ + pattern_buf += 2; + } + + /* Add pattern */ + status = sme_add_periodic_tx_ptrn(pHddCtx->hHal, + addPeriodicTxPtrnParams); + if (QDF_STATUS_SUCCESS != status) { + hdd_err("sme_add_periodic_tx_ptrn() failed!"); + + qdf_mem_free(addPeriodicTxPtrnParams); + goto failure; + } + qdf_mem_free(cmd); + qdf_mem_free(addPeriodicTxPtrnParams); + EXIT(); + return count; + +failure: + hdd_err("Invalid input. Input format is: ptrn_idx duration pattern"); + qdf_mem_free(cmd); + return -EINVAL; +} + +/** + * wcnss_patterngen_write() - SSR wrapper for __wcnss_patterngen_write + * @file: file pointer + * @buf: buffer + * @count: count + * @ppos: position pointer + * + * Return: 0 on success, error number otherwise + */ +static ssize_t wcnss_patterngen_write(struct file *file, + const char __user *buf, + size_t count, loff_t *ppos) +{ + ssize_t ret; + + cds_ssr_protect(__func__); + ret = __wcnss_patterngen_write(file, buf, count, ppos); + cds_ssr_unprotect(__func__); + + return ret; +} + +#ifdef WLAN_POWER_DEBUGFS +/** + * hdd_power_debugstats_cb() - callback routine for Power stats debugs + * @response: Pointer to Power stats response + * @context: Pointer to statsContext + * + * Return: None + */ +static void hdd_power_debugstats_cb(struct power_stats_response *response, + void *context) +{ + struct statsContext *stats_context; + struct power_stats_response *power_stats; + hdd_adapter_t *adapter; + uint32_t power_stats_len; + uint32_t stats_registers_len; + + ENTER(); + if (!context) { + hdd_err("context is NULL"); + return; + } + + stats_context = (struct statsContext *)context; + + spin_lock(&hdd_context_lock); + adapter = stats_context->pAdapter; + if ((POWER_STATS_MAGIC != stats_context->magic) || + (!adapter) || (WLAN_HDD_ADAPTER_MAGIC != adapter->magic)) { + spin_unlock(&hdd_context_lock); + hdd_err("Invalid context, adapter [%p] magic [%08x]", + adapter, stats_context->magic); + return; + } + + stats_context->magic = 0; + stats_registers_len = (sizeof(response->debug_registers[0]) * + response->num_debug_register); + power_stats_len = stats_registers_len + sizeof(*power_stats); + adapter->chip_power_stats = qdf_mem_malloc(power_stats_len); + if (!adapter->chip_power_stats) { + hdd_err("Power stats memory alloc fails!"); + goto exit_stats_cb; + } + + power_stats = adapter->chip_power_stats; + power_stats->cumulative_sleep_time_ms + = response->cumulative_sleep_time_ms; + power_stats->cumulative_total_on_time_ms + = response->cumulative_total_on_time_ms; + power_stats->deep_sleep_enter_counter + = response->deep_sleep_enter_counter; + power_stats->last_deep_sleep_enter_tstamp_ms + = response->last_deep_sleep_enter_tstamp_ms; + power_stats->debug_register_fmt + = response->debug_register_fmt; + power_stats->num_debug_register + = response->num_debug_register; + + power_stats->debug_registers = (uint32_t *)(power_stats + 1); + + qdf_mem_copy(power_stats->debug_registers, + response->debug_registers, stats_registers_len); + +exit_stats_cb: + complete(&stats_context->completion); + spin_unlock(&hdd_context_lock); + EXIT(); +} + +/** + * __wlan_hdd_read_power_debugfs() - API to collect Chip power stats from FW + * @file: file pointer + * @buf: buffer + * @count: count + * @pos: position pointer + * + * Return: Number of bytes read on success, error number otherwise + */ +static ssize_t __wlan_hdd_read_power_debugfs(struct file *file, + char __user *buf, + size_t count, loff_t *pos) +{ + hdd_adapter_t *adapter; + hdd_context_t *hdd_ctx; + static struct statsContext context; + struct power_stats_response *chip_power_stats; + ssize_t ret_cnt = 0; + int rc = 0, j; + unsigned int len = 0; + char *power_debugfs_buf; + + ENTER(); + adapter = (hdd_adapter_t *)file->private_data; + if ((!adapter) || (WLAN_HDD_ADAPTER_MAGIC != adapter->magic)) { + hdd_err("Invalid adapter or adapter has invalid magic"); + return -EINVAL; + } + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret_cnt = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret_cnt) + return ret_cnt; + + if (!wlan_hdd_modules_are_enabled(hdd_ctx)) + return -EINVAL; + + if (adapter->chip_power_stats) + qdf_mem_free(adapter->chip_power_stats); + + adapter->chip_power_stats = NULL; + context.pAdapter = adapter; + context.magic = POWER_STATS_MAGIC; + + init_completion(&context.completion); + + if (QDF_STATUS_SUCCESS != + sme_power_debug_stats_req(hdd_ctx->hHal, + hdd_power_debugstats_cb, + &context)) { + hdd_err("chip power stats request failed"); + return -EINVAL; + } + + rc = wait_for_completion_timeout(&context.completion, + msecs_to_jiffies(WLAN_WAIT_TIME_POWER_STATS)); + if (!rc) { + hdd_err("Target response timed out Power stats"); + /* Invalidate the Stats context magic */ + spin_lock(&hdd_context_lock); + context.magic = 0; + spin_unlock(&hdd_context_lock); + return -ETIMEDOUT; + } + + chip_power_stats = adapter->chip_power_stats; + if (!chip_power_stats) { + hdd_err("Power stats retrieval fails!"); + return -EINVAL; + } + + power_debugfs_buf = qdf_mem_malloc(POWER_DEBUGFS_BUFFER_MAX_LEN); + if (!power_debugfs_buf) { + hdd_err("Power stats buffer alloc fails!"); + qdf_mem_free(chip_power_stats); + adapter->chip_power_stats = NULL; + return -EINVAL; + } + + len += scnprintf(power_debugfs_buf, POWER_DEBUGFS_BUFFER_MAX_LEN, + "POWER DEBUG STATS\n=================\n" + "cumulative_sleep_time_ms: %d\n" + "cumulative_total_on_time_ms: %d\n" + "deep_sleep_enter_counter: %d\n" + "last_deep_sleep_enter_tstamp_ms: %d\n" + "debug_register_fmt: %d\n" + "num_debug_register: %d\n", + chip_power_stats->cumulative_sleep_time_ms, + chip_power_stats->cumulative_total_on_time_ms, + chip_power_stats->deep_sleep_enter_counter, + chip_power_stats->last_deep_sleep_enter_tstamp_ms, + chip_power_stats->debug_register_fmt, + chip_power_stats->num_debug_register); + + for (j = 0; j < chip_power_stats->num_debug_register; j++) { + if ((POWER_DEBUGFS_BUFFER_MAX_LEN - len) > 0) + len += scnprintf(power_debugfs_buf + len, + POWER_DEBUGFS_BUFFER_MAX_LEN - len, + "debug_registers[%d]: 0x%x\n", j, + chip_power_stats->debug_registers[j]); + else + j = chip_power_stats->num_debug_register; + } + + qdf_mem_free(chip_power_stats); + adapter->chip_power_stats = NULL; + + ret_cnt = simple_read_from_buffer(buf, count, pos, + power_debugfs_buf, len); + qdf_mem_free(power_debugfs_buf); + return ret_cnt; +} + +/** + * wlan_hdd_read_power_debugfs() - SSR wrapper function to read power debugfs + * @file: file pointer + * @buf: buffer + * @count: count + * @pos: position pointer + * + * Return: Number of bytes read on success, error number otherwise + */ +static ssize_t wlan_hdd_read_power_debugfs(struct file *file, + char __user *buf, + size_t count, loff_t *pos) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_read_power_debugfs(file, buf, count, pos); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __wlan_hdd_open_power_debugfs() - Function to save private on open + * @inode: Pointer to inode structure + * @file: file pointer + * + * Return: zero + */ +static int __wlan_hdd_open_power_debugfs(struct inode *inode, struct file *file) +{ + file->private_data = inode->i_private; + return 0; +} + + +/** + * wlan_hdd_open_power_debugfs() - SSR wrapper function to save private on open + * @inode: Pointer to inode structure + * @file: file pointer + * + * Return: zero + */ +static int wlan_hdd_open_power_debugfs(struct inode *inode, struct file *file) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_open_power_debugfs(inode, file); + cds_ssr_unprotect(__func__); + + return ret; +} +#endif + +/** + * __wcnss_debugfs_open() - Generic debugfs open() handler + * @inode: inode of the debugfs file + * @file: file handle of the debugfs file + * + * Return: 0 + */ +static int __wcnss_debugfs_open(struct inode *inode, struct file *file) +{ + hdd_adapter_t *adapter; + hdd_context_t *hdd_ctx; + int ret; + + ENTER(); + + if (inode->i_private) + file->private_data = inode->i_private; + + adapter = (hdd_adapter_t *)file->private_data; + if ((NULL == adapter) || (WLAN_HDD_ADAPTER_MAGIC != adapter->magic)) { + hdd_alert("Invalid adapter or adapter has invalid magic."); + return -EINVAL; + } + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + EXIT(); + return 0; +} + +/** + * wcnss_debugfs_open() - SSR wrapper for __wcnss_debugfs_open + * @inode: inode pointer + * @file: file pointer + * + * Return: 0 on success, error number otherwise + */ +static int wcnss_debugfs_open(struct inode *inode, struct file *file) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wcnss_debugfs_open(inode, file); + cds_ssr_unprotect(__func__); + + return ret; +} + +static const struct file_operations fops_wowenable = { + .write = wcnss_wowenable_write, + .open = wcnss_debugfs_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + +static const struct file_operations fops_wowpattern = { + .write = wcnss_wowpattern_write, + .open = wcnss_debugfs_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + +static const struct file_operations fops_patterngen = { + .write = wcnss_patterngen_write, + .open = wcnss_debugfs_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + +#ifdef WLAN_POWER_DEBUGFS +static const struct file_operations fops_powerdebugs = { + .read = wlan_hdd_read_power_debugfs, + .open = wlan_hdd_open_power_debugfs, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + +/** + * wlan_hdd_create_power_stats_file() - API to create power stats file + * @adapter: interface adapter pointer + * + * Return: QDF_STATUS + */ +static QDF_STATUS wlan_hdd_create_power_stats_file(hdd_adapter_t *adapter) +{ + if (!debugfs_create_file("power_stats", S_IRUSR | S_IRGRP | S_IROTH, + adapter->debugfs_phy, adapter, + &fops_powerdebugs)) + return QDF_STATUS_E_FAILURE; + + return QDF_STATUS_SUCCESS; +} + +#else +static QDF_STATUS wlan_hdd_create_power_stats_file(hdd_adapter_t *adapter) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +/** + * hdd_debugfs_init() - Initialize debugfs interface + * @adapter: interface adapter pointer + * + * Register support for the debugfs files supported by the driver. + * + * NB: The current implementation only supports debugfs operations + * on the primary interface, i.e. wlan0 + * + * Return: QDF_STATUS_SUCCESS if all files registered, + * QDF_STATUS_E_FAILURE on failure + */ +QDF_STATUS hdd_debugfs_init(hdd_adapter_t *adapter) +{ + struct net_device *dev = adapter->dev; + adapter->debugfs_phy = debugfs_create_dir(dev->name, 0); + + if (NULL == adapter->debugfs_phy) + return QDF_STATUS_E_FAILURE; + + if (NULL == debugfs_create_file("wow_enable", S_IRUSR | S_IWUSR, + adapter->debugfs_phy, adapter, + &fops_wowenable)) + return QDF_STATUS_E_FAILURE; + + if (NULL == debugfs_create_file("wow_pattern", S_IRUSR | S_IWUSR, + adapter->debugfs_phy, adapter, + &fops_wowpattern)) + return QDF_STATUS_E_FAILURE; + + if (NULL == debugfs_create_file("pattern_gen", S_IRUSR | S_IWUSR, + adapter->debugfs_phy, adapter, + &fops_patterngen)) + return QDF_STATUS_E_FAILURE; + + if (QDF_STATUS_SUCCESS != wlan_hdd_create_power_stats_file(adapter)) + return QDF_STATUS_E_FAILURE; + + return QDF_STATUS_SUCCESS; +} + +/** + * hdd_debugfs_exit() - Shutdown debugfs interface + * @adapter: interface adapter pointer + * + * Unregister support for the debugfs files supported by the driver. + * + * Return: None + */ +void hdd_debugfs_exit(hdd_adapter_t *adapter) +{ + struct net_device *dev = adapter->dev; + + if (adapter->debugfs_phy) + debugfs_remove_recursive(adapter->debugfs_phy); + else + hdd_info("Interface %s has no debugfs entry", dev->name); +} +#endif /* #ifdef WLAN_OPEN_SOURCE */ diff --git a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_disa.c b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_disa.c new file mode 100644 index 0000000000000000000000000000000000000000..39e6bd1f6c723faff773cfaaba88605a2d9b1bef --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_disa.c @@ -0,0 +1,510 @@ +/* + * Copyright (c) 2016-2017 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. + */ + +/** + * DOC : wlan_hdd_disa.c + * + * WLAN Host Device Driver file for DISA certification + * + */ + +#include "wlan_hdd_disa.h" +#include "sme_api.h" + +#define ENCRYPT_DECRYPT_CONTEXT_MAGIC 0x4475354 +#define WLAN_WAIT_TIME_ENCRYPT_DECRYPT 1000 + + +/** + * hdd_encrypt_decrypt_msg_context - hdd encrypt/decrypt message context + * + * @magic: magic number + * @completion: Completion variable for encrypt/decrypt message + * @response_event: encrypt/decrypt message request wait event + */ +struct hdd_encrypt_decrypt_msg_context { + unsigned int magic; + struct completion completion; + struct sir_encrypt_decrypt_rsp_params response; +}; +static struct hdd_encrypt_decrypt_msg_context encrypt_decrypt_msg_context; + +/** + * hdd_encrypt_decrypt_msg_cb () - sends encrypt/decrypt data to user space + * @encrypt_decrypt_rsp_params: encrypt/decrypt response parameters + * + * Return: none + */ +static void hdd_encrypt_decrypt_msg_cb(void *hdd_context, + struct sir_encrypt_decrypt_rsp_params *encrypt_decrypt_rsp_params) +{ + hdd_context_t *hdd_ctx = hdd_context; + int ret; + struct hdd_encrypt_decrypt_msg_context *context; + + ENTER(); + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return; + + if (!encrypt_decrypt_rsp_params) { + hdd_err("rsp params is NULL"); + return; + } + + print_hex_dump(KERN_INFO, "Data in hdd_encrypt_decrypt_msg_cb: ", + DUMP_PREFIX_NONE, 16, 1, + encrypt_decrypt_rsp_params->data, + encrypt_decrypt_rsp_params->data_length, 0); + + hdd_info("vdev_id %d,status %d data_length %d", + encrypt_decrypt_rsp_params->vdev_id, + encrypt_decrypt_rsp_params->status, + encrypt_decrypt_rsp_params->data_length); + + spin_lock(&hdd_context_lock); + + context = &encrypt_decrypt_msg_context; + /* The caller presumably timed out so there is nothing we can do */ + if (context->magic != ENCRYPT_DECRYPT_CONTEXT_MAGIC) { + spin_unlock(&hdd_context_lock); + return; + } + + /* context is valid so caller is still waiting */ + context->response = *encrypt_decrypt_rsp_params; + + if (encrypt_decrypt_rsp_params->data_length) { + context->response.data = + qdf_mem_malloc(sizeof(uint8_t) * + encrypt_decrypt_rsp_params->data_length); + if (context->response.data == NULL) { + hdd_err("cdf_mem_alloc failed for data"); + spin_unlock(&hdd_context_lock); + return; + } + qdf_mem_copy(context->response.data, + encrypt_decrypt_rsp_params->data, + encrypt_decrypt_rsp_params->data_length); + } + + /* + * Indicate to calling thread that + * response data is available + */ + context->magic = 0; + + complete(&context->completion); + + spin_unlock(&hdd_context_lock); + + + EXIT(); +} + + +/** + * hdd_encrypt_decrypt_msg_cb () - sends encrypt/decrypt data to user space + * @encrypt_decrypt_rsp_params: encrypt/decrypt response parameters + * + * Return: none + */ +static int hdd_post_encrypt_decrypt_msg_rsp(hdd_context_t *hdd_ctx, + struct sir_encrypt_decrypt_rsp_params *encrypt_decrypt_rsp_params) +{ + struct sk_buff *skb; + uint32_t nl_buf_len; + + ENTER(); + + nl_buf_len = encrypt_decrypt_rsp_params->data_length + NLA_HDRLEN; + + skb = cfg80211_vendor_cmd_alloc_reply_skb(hdd_ctx->wiphy, nl_buf_len); + if (!skb) { + hdd_err(FL("cfg80211_vendor_cmd_alloc_reply_skb failed")); + return -ENOMEM; + } + + if (encrypt_decrypt_rsp_params->data_length) { + if (nla_put(skb, QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_DATA, + encrypt_decrypt_rsp_params->data_length, + encrypt_decrypt_rsp_params->data)) { + hdd_err(FL("put fail")); + goto nla_put_failure; + } + } + + cfg80211_vendor_cmd_reply(skb); + EXIT(); + return 0; + +nla_put_failure: + kfree_skb(skb); + return -EINVAL; +} + +static const struct nla_policy +encrypt_decrypt_policy[QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_NEEDS_DECRYPTION] = { + .type = NLA_FLAG}, + [QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_KEYID] = { + .type = NLA_U8}, + [QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_CIPHER] = { + .type = NLA_U32}, +}; + +/** + * hdd_fill_encrypt_decrypt_params () - parses data from user space + * and fills encrypt/decrypt parameters + * @encrypt_decrypt_params: encrypt/decrypt request parameters + * @adapter : adapter context + * @data: Pointer to data + * @data_len: Data length + * + Return: 0 on success, negative errno on failure + */ +static int hdd_fill_encrypt_decrypt_params(struct encrypt_decrypt_req_params + *encrypt_decrypt_params, + hdd_adapter_t *adapter, + const void *data, + int data_len) +{ + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_MAX + 1]; + uint8_t len, mac_hdr_len; + uint8_t *tmp; + uint8_t fc[2]; + + if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_MAX, + data, data_len, encrypt_decrypt_policy)) { + hdd_err("Invalid ATTR"); + return -EINVAL; + } + + encrypt_decrypt_params->vdev_id = adapter->sessionId; + hdd_info("vdev_id : %d", encrypt_decrypt_params->vdev_id); + + if (!tb[QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_NEEDS_DECRYPTION]) { + hdd_err("attr flag NEEDS_DECRYPTION not present"); + encrypt_decrypt_params->key_flag = WMI_ENCRYPT; + } else { + hdd_err("attr flag NEEDS_DECRYPTION present"); + encrypt_decrypt_params->key_flag = WMI_DECRYPT; + } + hdd_info("Key flag : %d", encrypt_decrypt_params->key_flag); + + if (!tb[QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_KEYID]) { + hdd_err("attr key id failed"); + return -EINVAL; + } + encrypt_decrypt_params->key_idx = nla_get_u8(tb + [QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_KEYID]); + hdd_info("Key Idx : %d", encrypt_decrypt_params->key_idx); + + if (!tb[QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_CIPHER]) { + hdd_err("attr Cipher failed"); + return -EINVAL; + } + encrypt_decrypt_params->key_cipher = nla_get_u32(tb + [QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_CIPHER]); + hdd_info("key_cipher : %d", encrypt_decrypt_params->key_cipher); + + if (!tb[QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_TK]) { + hdd_err("attr TK failed"); + return -EINVAL; + } + encrypt_decrypt_params->key_len = + nla_len(tb[QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_TK]); + if (!encrypt_decrypt_params->key_len) { + hdd_err("Invalid TK length"); + return -EINVAL; + } + hdd_err("Key len : %d", encrypt_decrypt_params->key_len); + + if (encrypt_decrypt_params->key_len > SIR_MAC_MAX_KEY_LENGTH) + encrypt_decrypt_params->key_len = SIR_MAC_MAX_KEY_LENGTH; + + tmp = nla_data(tb[QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_TK]); + + qdf_mem_copy(encrypt_decrypt_params->key_data, tmp, + encrypt_decrypt_params->key_len); + + print_hex_dump(KERN_INFO, "Key : ", DUMP_PREFIX_NONE, 16, 1, + &encrypt_decrypt_params->key_data, + encrypt_decrypt_params->key_len, 0); + + if (!tb[QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_PN]) { + hdd_err("attr PN failed"); + return -EINVAL; + } + len = nla_len(tb[QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_PN]); + if (!len || len > sizeof(encrypt_decrypt_params->pn)) { + hdd_err("Invalid PN length %u", len); + return -EINVAL; + } + + tmp = nla_data(tb[QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_PN]); + + qdf_mem_copy(encrypt_decrypt_params->pn, tmp, len); + + print_hex_dump(KERN_INFO, "PN received : ", DUMP_PREFIX_NONE, 16, 1, + &encrypt_decrypt_params->pn, len, 0); + + if (!tb[QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_DATA]) { + hdd_err("attr header failed"); + return -EINVAL; + } + len = nla_len(tb[QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_DATA]); + if (len < MIN_MAC_HEADER_LEN) { + hdd_err("Invalid header and payload length %u", len); + return -EINVAL; + } + + hdd_info("Header and Payload length %d ", len); + + tmp = nla_data(tb[QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_DATA]); + + print_hex_dump(KERN_INFO, "Header and Payload received: ", + DUMP_PREFIX_NONE, 16, 1, + tmp, len, 0); + + mac_hdr_len = MIN_MAC_HEADER_LEN; + + /* + * Check to find out address 4. Address 4 is present if ToDS and FromDS + * are 1 and data representation is little endian. + */ + fc[1] = *tmp; + fc[0] = *(tmp + 1); + if ((fc[0] & 0x03) == 0x03) { + hdd_err("Address 4 is present"); + mac_hdr_len += IEEE80211_ADDR_LEN; + } + + /* + * Check to find out Qos control field. Qos control field is present + * if msb of subtype field is 1 and data representation is + * little endian. + */ + if (fc[1] & 0x80) { + hdd_err("Qos control is present"); + mac_hdr_len += QOS_CONTROL_LEN; + } + + hdd_notice("mac_hdr_len %d", mac_hdr_len); + + if (len < mac_hdr_len) { + hdd_err("Invalid header and payload length %u", len); + return -EINVAL; + } + qdf_mem_copy(encrypt_decrypt_params->mac_header, + tmp, mac_hdr_len); + + print_hex_dump(KERN_INFO, "Header received in request: ", + DUMP_PREFIX_NONE, 16, 1, + encrypt_decrypt_params->mac_header, + mac_hdr_len, 0); + + encrypt_decrypt_params->data_len = + len - mac_hdr_len; + + hdd_notice("Payload length : %d", encrypt_decrypt_params->data_len); + + if (encrypt_decrypt_params->data_len) { + encrypt_decrypt_params->data = + qdf_mem_malloc(sizeof(uint8_t) * + encrypt_decrypt_params->data_len); + + if (encrypt_decrypt_params->data == NULL) { + hdd_err("cdf_mem_alloc failed for data"); + return -ENOMEM; + } + + qdf_mem_copy(encrypt_decrypt_params->data, + tmp + mac_hdr_len, + encrypt_decrypt_params->data_len); + + print_hex_dump(KERN_INFO, "Data received in request: ", + DUMP_PREFIX_NONE, 16, 1, + encrypt_decrypt_params->data, + encrypt_decrypt_params->data_len, 0); + } + + return 0; +} + +/** + * hdd_encrypt_decrypt_msg () - process encrypt/decrypt message + * @adapter : adapter context + * @hdd_ctx: hdd context + * @data: Pointer to data + * @data_len: Data length + * + Return: 0 on success, negative errno on failure + */ +static int hdd_encrypt_decrypt_msg(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + const void *data, + int data_len) +{ + struct encrypt_decrypt_req_params encrypt_decrypt_params = {0}; + QDF_STATUS qdf_status; + int ret; + struct hdd_encrypt_decrypt_msg_context *context; + unsigned long rc; + + ret = hdd_fill_encrypt_decrypt_params(&encrypt_decrypt_params, + adapter, data, data_len); + if (ret) + return ret; + + spin_lock(&hdd_context_lock); + context = &encrypt_decrypt_msg_context; + context->magic = ENCRYPT_DECRYPT_CONTEXT_MAGIC; + INIT_COMPLETION(context->completion); + spin_unlock(&hdd_context_lock); + + qdf_status = sme_encrypt_decrypt_msg(hdd_ctx->hHal, + &encrypt_decrypt_params); + + qdf_mem_free(encrypt_decrypt_params.data); + + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + hdd_err("Unable to post encrypt/decrypt message"); + return -EINVAL; + } + + rc = wait_for_completion_timeout(&context->completion, + msecs_to_jiffies(WLAN_WAIT_TIME_ENCRYPT_DECRYPT)); + + spin_lock(&hdd_context_lock); + if (!rc && (context->magic == + ENCRYPT_DECRYPT_CONTEXT_MAGIC)) { + hdd_err("Target response timed out"); + context->magic = 0; + spin_unlock(&hdd_context_lock); + return -ETIMEDOUT; + } + + spin_unlock(&hdd_context_lock); + ret = hdd_post_encrypt_decrypt_msg_rsp(hdd_ctx, + &encrypt_decrypt_msg_context.response); + if (ret) + hdd_err("Failed to post encrypt/decrypt message response"); + + qdf_mem_free(encrypt_decrypt_msg_context.response.data); + + EXIT(); + return ret; +} + +/** + * hdd_encrypt_decrypt_init () - exposes encrypt/decrypt initialization + * functionality + * @hdd_ctx: hdd context + * + Return: 0 on success, negative errno on failure + */ +int hdd_encrypt_decrypt_init(hdd_context_t *hdd_ctx) +{ + QDF_STATUS status; + + init_completion(&encrypt_decrypt_msg_context.completion); + + status = sme_encrypt_decrypt_msg_register_callback(hdd_ctx->hHal, + hdd_encrypt_decrypt_msg_cb); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("encrypt/decrypt callback failed %d", status); + return -EINVAL; + } + return 0; +} + +/** + * hdd_encrypt_decrypt_deinit () - exposes encrypt/decrypt deinitialization + * functionality + * @hdd_ctx: hdd context + * + Return: 0 on success, negative errno on failure + */ +int hdd_encrypt_decrypt_deinit(hdd_context_t *hdd_ctx) +{ + QDF_STATUS status; + + status = sme_encrypt_decrypt_msg_deregister_callback(hdd_ctx->hHal); + if (!QDF_IS_STATUS_SUCCESS(status)) + hdd_err("De-register encrypt/decrypt callback failed: %d", + status); + return 0; +} + +/** + * __wlan_hdd_cfg80211_encrypt_decrypt_msg () - Encrypt/Decrypt msg + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Data length + * + * Return: 0 on success, negative errno on failure + */ +static int __wlan_hdd_cfg80211_encrypt_decrypt_msg(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + hdd_context_t *hdd_ctx = wiphy_priv(wiphy); + struct net_device *dev = wdev->netdev; + hdd_adapter_t *adapter = NULL; + int ret; + + ENTER_DEV(dev); + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return ret; + + adapter = WLAN_HDD_GET_PRIV_PTR(dev); + + ret = hdd_encrypt_decrypt_msg(adapter, hdd_ctx, data, data_len); + + return ret; +} + +/** + * wlan_hdd_cfg80211_encrypt_decrypt_msg () - Encrypt/Decrypt msg + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Data length + * + * Return: 0 on success, negative errno on failure + */ +int wlan_hdd_cfg80211_encrypt_decrypt_msg(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_encrypt_decrypt_msg(wiphy, wdev, + data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} diff --git a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_disa.h b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_disa.h new file mode 100644 index 0000000000000000000000000000000000000000..b35c02c5dbbe01b731f992bf42e93fde36c9af59 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_disa.h @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2016 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_DISA_H +#define _WLAN_HDD_DISA_H + +#include "wlan_hdd_main.h" +#include "sir_api.h" + +#ifdef WLAN_FEATURE_DISA +/** + * hdd_encrypt_decrypt_init () - exposes encrypt/decrypt initialization + * functionality + * @hdd_ctx: hdd context + * + Return: 0 on success, negative errno on failure + */ +int hdd_encrypt_decrypt_init(hdd_context_t *hdd_ctx); + +/** + * hdd_encrypt_decrypt_deinit () - exposes encrypt/decrypt deinitialization + * functionality + * @hdd_ctx: hdd context + * + Return: 0 on success, negative errno on failure + */ +int hdd_encrypt_decrypt_deinit(hdd_context_t *hdd_ctx); +#else +static inline int hdd_encrypt_decrypt_init(hdd_context_t *hdd_ctx) +{ + return -ENOTSUPP; +} +static inline int hdd_encrypt_decrypt_deinit(hdd_context_t *hdd_ctx) +{ + return -ENOTSUPP; +} +#endif + +#ifdef WLAN_FEATURE_DISA +/** + * wlan_hdd_cfg80211_encrypt_decrypt_msg () - Encrypt/Decrypt msg + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Data length + * + * Return: 0 on success, negative errno on failure + */ +int wlan_hdd_cfg80211_encrypt_decrypt_msg(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len); +#endif + +#endif diff --git a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_driver_ops.c b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_driver_ops.c new file mode 100644 index 0000000000000000000000000000000000000000..7aa485f82b22b3e53402fdb1f4712dc99361c456 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_driver_ops.c @@ -0,0 +1,1276 @@ +/* + * Copyright (c) 2015-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#include +#include +#include "cds_api.h" +#include "qdf_status.h" +#include "qdf_lock.h" +#include "cds_sched.h" +#include "osdep.h" +#include "hif.h" +#include "htc.h" +#include "epping_main.h" +#include "wlan_hdd_main.h" +#include "wlan_hdd_power.h" +#include "wlan_logging_sock_svc.h" +#include "wma_api.h" +#include "wlan_hdd_napi.h" +#include "cds_concurrency.h" +#include "qwlan_version.h" +#include "bmi.h" +#include "cdp_txrx_bus.h" +#include "pld_common.h" +#include "wlan_hdd_driver_ops.h" + +#ifdef MODULE +#define WLAN_MODULE_NAME module_name(THIS_MODULE) +#else +#define WLAN_MODULE_NAME "wlan" +#endif + +#define DISABLE_KRAIT_IDLE_PS_VAL 1 + +/* + * In BMI Phase we are only sending small chunk (256 bytes) of the FW image at + * a time, and wait for the completion interrupt to start the next transfer. + * During this phase, the KRAIT is entering IDLE/StandAlone(SA) Power Save(PS). + * The delay incurred for resuming from IDLE/SA PS is huge during driver load. + * So prevent APPS IDLE/SA PS durint driver load for reducing interrupt latency. + */ + +static inline void hdd_request_pm_qos(struct device *dev, int val) +{ + pld_request_pm_qos(dev, val); +} + +static inline void hdd_remove_pm_qos(struct device *dev) +{ + pld_remove_pm_qos(dev); +} + +/** + * hdd_set_recovery_in_progress() - API to set recovery in progress + * @data: Context + * @val: Value to set + * + * Return: None + */ +static void hdd_set_recovery_in_progress(void *data, uint8_t val) +{ + cds_set_recovery_in_progress(val); +} + +/** + * hdd_is_driver_unloading() - API to query if driver is unloading + * @data: Private Data + * + * Return: True/False + */ +static bool hdd_is_driver_unloading(void *data) +{ + return cds_is_driver_unloading(); +} + +/** + * hdd_is_load_or_unload_in_progress() - API to query if driver is + * loading/unloading + * @data: Private Data + * + * Return: bool + */ +static bool hdd_is_load_or_unload_in_progress(void *data) +{ + return cds_is_load_or_unload_in_progress(); +} + +/** + * hdd_is_recovery_in_progress() - API to query if recovery in progress + * @data: Private Data + * + * Return: bool + */ +static bool hdd_is_recovery_in_progress(void *data) +{ + return cds_is_driver_recovering(); +} + +/** + * hdd_hif_init_driver_state_callbacks() - API to initialize HIF callbacks + * @data: Private Data + * @cbk: HIF Driver State callbacks + * + * HIF should be independent of CDS calls. Pass CDS Callbacks to HIF, HIF will + * call the callbacks. + * + * Return: void + */ +static void hdd_hif_init_driver_state_callbacks(void *data, + struct hif_driver_state_callbacks *cbk) +{ + cbk->context = data; + cbk->set_recovery_in_progress = hdd_set_recovery_in_progress; + cbk->is_recovery_in_progress = hdd_is_recovery_in_progress; + cbk->is_load_unload_in_progress = hdd_is_load_or_unload_in_progress; + cbk->is_driver_unloading = hdd_is_driver_unloading; +} + +/** + * hdd_init_cds_hif_context() - API to set CDS HIF Context + * @hif: HIF Context + * + * Return: success/failure + */ +static int hdd_init_cds_hif_context(void *hif) +{ + QDF_STATUS status; + + status = cds_set_context(QDF_MODULE_ID_HIF, hif); + + if (status) + return -ENOENT; + + return 0; +} + +/** + * hdd_deinit_cds_hif_context() - API to clear CDS HIF COntext + * + * Return: None + */ +static void hdd_deinit_cds_hif_context(void) +{ + QDF_STATUS status; + + status = cds_set_context(QDF_MODULE_ID_HIF, NULL); + + if (status) + hdd_err("Failed to reset CDS HIF Context"); + + return; +} + +/** + * to_bus_type() - Map PLD bus type to low level bus type + * @bus_type: PLD bus type + * + * Map PLD bus type to low level bus type. + * + * Return: low level bus type. + */ +static enum qdf_bus_type to_bus_type(enum pld_bus_type bus_type) +{ + switch (bus_type) { + case PLD_BUS_TYPE_PCIE: + return QDF_BUS_TYPE_PCI; + case PLD_BUS_TYPE_SNOC: + return QDF_BUS_TYPE_SNOC; + case PLD_BUS_TYPE_SDIO: + return QDF_BUS_TYPE_SDIO; + case PLD_BUS_TYPE_USB: + return QDF_BUS_TYPE_USB; + default: + return QDF_BUS_TYPE_NONE; + } +} + +/** + * hdd_hif_open() - HIF open helper + * @dev: wlan device structure + * @bdev: bus device structure + * @bid: bus identifier for shared busses + * @bus_type: underlying bus type + * @reinit: true if we are reinitializing the driver during recovery phase + * + * This function brings-up HIF layer during load/recovery phase. + * + * Return: 0 on success and errno on failure. + */ +int hdd_hif_open(struct device *dev, void *bdev, const hif_bus_id *bid, + enum qdf_bus_type bus_type, bool reinit) +{ + QDF_STATUS status; + int ret = 0; + struct hif_opaque_softc *hif_ctx; + qdf_device_t qdf_ctx = cds_get_context(QDF_MODULE_ID_QDF_DEVICE); + struct hif_driver_state_callbacks cbk; + uint32_t mode = cds_get_conparam(); + hdd_context_t *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + + if (!hdd_ctx) { + hdd_err("hdd_ctx error"); + return -EFAULT; + } + + hdd_hif_init_driver_state_callbacks(dev, &cbk); + + hif_ctx = hif_open(qdf_ctx, mode, bus_type, &cbk); + if (!hif_ctx) { + hdd_err("hif_open error"); + return -ENOMEM; + } + + ret = hdd_init_cds_hif_context(hif_ctx); + if (ret) { + hdd_err("Failed to set global HIF CDS Context err:%d", ret); + goto err_hif_close; + } + + status = hif_enable(hif_ctx, dev, bdev, bid, bus_type, + (reinit == true) ? HIF_ENABLE_TYPE_REINIT : + HIF_ENABLE_TYPE_PROBE); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("hif_enable error = %d, reinit = %d", + status, reinit); + ret = qdf_status_to_os_return(status); + goto err_hif_close; + } else { + ret = hdd_napi_create(); + hdd_info("hdd_napi_create returned: %d", ret); + if (ret == 0) + hdd_warn("NAPI: no instances are created"); + else if (ret < 0) { + hdd_err("NAPI creation error, rc: 0x%x, reinit = %d", + ret, reinit); + ret = -EFAULT; + goto err_hif_close; + } else { + hdd_napi_event(NAPI_EVT_INI_FILE, + (void *)hdd_ctx->napi_enable); + } + } + + return 0; + +err_hif_close: + hdd_deinit_cds_hif_context(); + hif_close(hif_ctx); + return ret; +} + +/** + * hdd_hif_close() - HIF close helper + * @hif_ctx: HIF context + * + * Helper function to close HIF + */ +void hdd_hif_close(void *hif_ctx) +{ + if (hif_ctx == NULL) + return; + + hif_disable(hif_ctx, HIF_DISABLE_TYPE_REMOVE); + + hdd_napi_destroy(true); + + hdd_deinit_cds_hif_context(); + hif_close(hif_ctx); +} + +/** + * hdd_init_qdf_ctx() - API to initialize global QDF Device structure + * @dev: Device Pointer + * @bdev: Bus Device pointer + * @bus_type: Underlying bus type + * @bid: Bus id passed by platform driver + * + * Return: void + */ +static void hdd_init_qdf_ctx(struct device *dev, void *bdev, + enum qdf_bus_type bus_type, + const struct hif_bus_id *bid) +{ + qdf_device_t qdf_dev = cds_get_context(QDF_MODULE_ID_QDF_DEVICE); + + if (!qdf_dev) { + hdd_err("Invalid QDF device"); + return; + } + + qdf_dev->dev = dev; + qdf_dev->drv_hdl = bdev; + qdf_dev->bus_type = bus_type; + qdf_dev->bid = bid; +} + +/** + * wlan_hdd_probe() - handles probe request + * + * This function is called to probe the wlan driver + * + * @dev: wlan device structure + * @bdev: bus device structure + * @bid: bus identifier for shared busses + * @bus_type: underlying bus type + * @reinit: true if we are reinitiallizing the driver after a subsystem restart + * + * Return: 0 on successfull probe + */ +static int wlan_hdd_probe(struct device *dev, void *bdev, const hif_bus_id *bid, + enum qdf_bus_type bus_type, bool reinit) +{ + int ret = 0; + + mutex_lock(&hdd_init_deinit_lock); + pr_info("%s: %sprobing driver v%s\n", WLAN_MODULE_NAME, + reinit ? "re-" : "", QWLAN_VERSIONSTR); + + hdd_prevent_suspend(WIFI_POWER_EVENT_WAKELOCK_DRIVER_INIT); + + /* + * The Krait is going to Idle/Stand Alone Power Save + * more aggressively which is resulting in the longer driver load time. + * The Fix is to not allow Krait to enter Idle Power Save during driver + * load. + */ + hdd_request_pm_qos(dev, DISABLE_KRAIT_IDLE_PS_VAL); + + if (reinit) + cds_set_recovery_in_progress(true); + else + cds_set_load_in_progress(true); + + hdd_init_qdf_ctx(dev, bdev, bus_type, (const struct hif_bus_id *)bid); + + if (reinit) + ret = hdd_wlan_re_init(); + else + ret = hdd_wlan_startup(dev); + + if (ret) + goto err_hdd_deinit; + + + if (reinit) { + cds_set_recovery_in_progress(false); + } else { + cds_set_load_in_progress(false); + cds_set_driver_loaded(true); + } + + hdd_allow_suspend(WIFI_POWER_EVENT_WAKELOCK_DRIVER_INIT); + hdd_remove_pm_qos(dev); + + mutex_unlock(&hdd_init_deinit_lock); + return 0; + + +err_hdd_deinit: + if (reinit) + cds_set_recovery_in_progress(false); + else + cds_set_load_in_progress(false); + hdd_allow_suspend(WIFI_POWER_EVENT_WAKELOCK_DRIVER_INIT); + hdd_remove_pm_qos(dev); + mutex_unlock(&hdd_init_deinit_lock); + return ret; +} + +static inline void hdd_pld_driver_unloading(struct device *dev) +{ + pld_set_driver_status(dev, PLD_LOAD_UNLOAD); +} + +/** + * wlan_hdd_remove() - wlan_hdd_remove + * + * This function is called by the platform driver to remove the + * driver + * + * Return: void + */ +static void wlan_hdd_remove(struct device *dev) +{ + pr_info("%s: Removing driver v%s\n", WLAN_MODULE_NAME, + QWLAN_VERSIONSTR); + + + cds_set_driver_loaded(false); + cds_set_unload_in_progress(true); + + if (!cds_wait_for_external_threads_completion(__func__)) + hdd_err("External threads are still active attempting driver unload anyway"); + + hdd_pld_driver_unloading(dev); + + if (QDF_IS_EPPING_ENABLED(cds_get_conparam())) { + epping_disable(); + epping_close(); + } else { + __hdd_wlan_exit(); + } + + cds_set_unload_in_progress(false); + + pr_info("%s: Driver De-initialized\n", WLAN_MODULE_NAME); +} + +#ifdef FEATURE_WLAN_DIAG_SUPPORT +/** + * hdd_wlan_ssr_shutdown_event()- send ssr shutdown state + * + * This Function send send ssr shutdown state diag event + * + * Return: void. + */ +static void hdd_wlan_ssr_shutdown_event(void) +{ + WLAN_HOST_DIAG_EVENT_DEF(ssr_shutdown, + struct host_event_wlan_ssr_shutdown); + qdf_mem_zero(&ssr_shutdown, sizeof(ssr_shutdown)); + ssr_shutdown.status = SSR_SUB_SYSTEM_SHUTDOWN; + WLAN_HOST_DIAG_EVENT_REPORT(&ssr_shutdown, + EVENT_WLAN_SSR_SHUTDOWN_SUBSYSTEM); +} +#else +static inline void hdd_wlan_ssr_shutdown_event(void) +{ + +}; +#endif + +/** + * wlan_hdd_shutdown() - wlan_hdd_shutdown + * + * This is routine is called by platform driver to shutdown the + * driver + * + * Return: void + */ +static void wlan_hdd_shutdown(void) +{ + void *hif_ctx = cds_get_context(QDF_MODULE_ID_HIF); + + if (hdd_get_conparam() == QDF_GLOBAL_FTM_MODE) { + hdd_err("Crash recovery is not allowed in FTM mode"); + QDF_BUG(0); + return; + } + + if (cds_is_load_or_unload_in_progress()) { + hdd_warn("Load/unload in progress, ignore SSR shutdown"); + return; + } + /* this is for cases, where shutdown invoked from platform */ + cds_set_recovery_in_progress(true); + hdd_wlan_ssr_shutdown_event(); + + if (!cds_wait_for_external_threads_completion(__func__)) + hdd_err("Host is not ready for SSR, attempting anyway"); + + if (!QDF_IS_EPPING_ENABLED(cds_get_conparam())) { + if (!hif_ctx) + hdd_err("Invalid hif ctx!"); + else + hif_disable_isr(hif_ctx); + hdd_wlan_shutdown(); + } +} + +/** + * wlan_hdd_crash_shutdown() - wlan_hdd_crash_shutdown + * + * HDD crash shutdown funtion: This function is called by + * platfrom driver's crash shutdown routine + * + * Return: void + */ +static void wlan_hdd_crash_shutdown(void) +{ + hif_crash_shutdown(cds_get_context(QDF_MODULE_ID_HIF)); +} + +/** + * wlan_hdd_notify_handler() - wlan_hdd_notify_handler + * + * This function is called by the platform driver to notify the + * COEX + * + * @state: state + * + * Return: void + */ +static void wlan_hdd_notify_handler(int state) +{ + if (!QDF_IS_EPPING_ENABLED(cds_get_conparam())) { + int ret = 0; + ret = hdd_wlan_notify_modem_power_state(state); + if (ret < 0) + hdd_err("Fail to send notify"); + } +} + +/** + * __wlan_hdd_bus_suspend() - handles platform supsend + * @state: suspend message from the kernel + * @wow_flags: bitmap of WMI WOW flags to pass to FW + * + * Does precondtion validation. Ensures that a subsystem restart isn't in + * progress. Ensures that no load or unload is in progress. + * Calls ol_txrx_bus_suspend to ensure the layer is ready for a bus suspend. + * Calls wma_suspend to configure offloads. + * Calls hif_suspend to suspend the bus. + * + * Return: 0 for success, -EFAULT for null pointers, + * -EBUSY or -EAGAIN if another opperation is in progress and + * wlan will not be ready to suspend in time. + */ +static int __wlan_hdd_bus_suspend(pm_message_t state, uint32_t wow_flags) +{ + hdd_context_t *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + void *hif_ctx; + int err; + int status; + + hdd_info("starting bus suspend; event:%d, flags:%u", + state.event, wow_flags); + + err = wlan_hdd_validate_context(hdd_ctx); + if (err) { + hdd_err("Invalid hdd context"); + goto done; + } + + if (hdd_ctx->driver_status != DRIVER_MODULES_ENABLED) { + hdd_info("Driver Module closed; return success"); + return 0; + } + + hif_ctx = cds_get_context(QDF_MODULE_ID_HIF); + if (NULL == hif_ctx) { + hdd_err("Failed to get hif context"); + err = -EINVAL; + goto done; + } + + err = qdf_status_to_os_return(ol_txrx_bus_suspend()); + if (err) { + hdd_err("Failed tx/rx bus suspend"); + goto done; + } + + err = hif_bus_early_suspend(hif_ctx); + if (err) { + hdd_err("Failed hif bus early suspend"); + goto resume_oltxrx; + } + + err = wma_bus_suspend(wow_flags); + if (err) { + hdd_err("Failed wma bus suspend"); + goto late_hif_resume; + } + + err = hif_bus_suspend(hif_ctx); + if (err) { + hdd_err("Failed hif bus suspend"); + goto resume_wma; + } + + hdd_info("bus suspend succeeded"); + return 0; + +resume_wma: + status = wma_bus_resume(); + QDF_BUG(!status); +late_hif_resume: + status = hif_bus_late_resume(hif_ctx); + QDF_BUG(!status); +resume_oltxrx: + status = ol_txrx_bus_resume(); + QDF_BUG(!status); +done: + hdd_err("suspend failed, status = %d", err); + return err; +} + +int wlan_hdd_bus_suspend(pm_message_t state) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_bus_suspend(state, 0); + cds_ssr_unprotect(__func__); + + return ret; +} + +#ifdef WLAN_SUSPEND_RESUME_TEST +int wlan_hdd_unit_test_bus_suspend(pm_message_t state) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_bus_suspend(state, WMI_WOW_FLAG_UNIT_TEST_ENABLE | + WMI_WOW_FLAG_DO_HTC_WAKEUP); + cds_ssr_unprotect(__func__); + + return ret; +} +#endif + +/** + * __wlan_hdd_bus_suspend_noirq() - handle .suspend_noirq callback + * + * This function is called by the platform driver to complete the + * bus suspend callback when device interrupts are disabled by kernel. + * Call HIF and WMA suspend_noirq callbacks to make sure there is no + * wake up pending from FW before allowing suspend. + * + * Return: 0 for success and -EBUSY if FW is requesting wake up + */ +static int __wlan_hdd_bus_suspend_noirq(void) +{ + hdd_context_t *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + void *hif_ctx; + int err; + int status; + + err = wlan_hdd_validate_context(hdd_ctx); + if (err) { + hdd_err("Invalid HDD context: %d", err); + return err; + } + + if (hdd_ctx->driver_status != DRIVER_MODULES_ENABLED) { + hdd_info("Driver Module closed return success"); + return 0; + } + + hif_ctx = cds_get_context(QDF_MODULE_ID_HIF); + if (NULL == hif_ctx) { + err = -EINVAL; + goto done; + } + + err = hif_bus_suspend_noirq(hif_ctx); + if (err) + goto done; + + err = wma_is_target_wake_up_received(); + if (err) + goto resume_hif_noirq; + + hdd_ctx->suspend_resume_stats.suspends++; + + hdd_info("suspend_noirq done"); + return 0; + +resume_hif_noirq: + status = hif_bus_resume_noirq(hif_ctx); + QDF_BUG(!status); +done: + if (err == -EAGAIN) { + hdd_err("Firmware attempting wakeup, try again"); + wlan_hdd_inc_suspend_stats(hdd_ctx, + SUSPEND_FAIL_INITIAL_WAKEUP); + } else { + hdd_err("suspend_noirq failed, status = %d", err); + } + + return err; +} + +int wlan_hdd_bus_suspend_noirq(void) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_bus_suspend_noirq(); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __wlan_hdd_bus_resume() - handles platform resume + * + * Does precondtion validation. Ensures that a subsystem restart isn't in + * progress. Ensures that no load or unload is in progress. Ensures that + * it has valid pointers for the required contexts. + * Calls into hif to resume the bus opperation. + * Calls into wma to handshake with firmware and notify it that the bus is up. + * Calls into ol_txrx for symetry. + * Failures are treated as catastrophic. + * + * return: error code or 0 for success + */ +static int __wlan_hdd_bus_resume(void) +{ + hdd_context_t *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + void *hif_ctx; + int status; + QDF_STATUS qdf_status; + + if (cds_is_driver_recovering()) + return 0; + + hdd_info("starting bus resume"); + + status = wlan_hdd_validate_context(hdd_ctx); + if (status) { + hdd_err("Invalid hdd context"); + return status; + } + + if (hdd_ctx->driver_status != DRIVER_MODULES_ENABLED) { + hdd_info("Driver Module closed; return success"); + return 0; + } + + hif_ctx = cds_get_context(QDF_MODULE_ID_HIF); + if (NULL == hif_ctx) { + hdd_err("Failed to get hif context"); + return -EINVAL; + } + + status = hif_bus_resume(hif_ctx); + if (status) { + hdd_err("Failed hif bus resume"); + goto out; + } + + status = wma_bus_resume(); + if (status) { + hdd_err("Failed wma bus resume"); + goto out; + } + + status = hif_bus_late_resume(hif_ctx); + if (status) { + hdd_err("Failed hif bus late resume"); + goto out; + } + + qdf_status = ol_txrx_bus_resume(); + status = qdf_status_to_os_return(qdf_status); + if (status) { + hdd_err("Failed tx/rx bus resume"); + goto out; + } + + hdd_info("bus resume succeeded"); + return 0; + +out: + if (cds_is_driver_recovering()) + return 0; + + QDF_BUG(false); + + return status; +} + +int wlan_hdd_bus_resume(void) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_bus_resume(); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __wlan_hdd_bus_resume_noirq(): handle bus resume no irq + * + * This function is called by the platform driver to do bus + * resume no IRQ before calling resume callback. Call WMA and HIF + * layers to complete the resume_noirq. + * + * Return: 0 for success and negative error code for failure + */ +static int __wlan_hdd_bus_resume_noirq(void) +{ + hdd_context_t *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + void *hif_ctx; + int status; + + if (cds_is_driver_recovering()) + return 0; + + status = wlan_hdd_validate_context(hdd_ctx); + if (status) { + hdd_err("Invalid HDD context: %d", status); + return status; + } + + if (hdd_ctx->driver_status != DRIVER_MODULES_ENABLED) { + hdd_info("Driver Module closed return success"); + return 0; + } + + hif_ctx = cds_get_context(QDF_MODULE_ID_HIF); + if (NULL == hif_ctx) + return -EINVAL; + + status = wma_clear_target_wake_up(); + QDF_BUG(!status); + + status = hif_bus_resume_noirq(hif_ctx); + QDF_BUG(!status); + + hdd_info("resume_noirq done"); + return status; +} + +int wlan_hdd_bus_resume_noirq(void) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_bus_resume_noirq(); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * wlan_hdd_bus_reset_resume() - resume wlan bus after reset + * + * This function is called to tell the driver that the device has been resumed + * and it has also been reset. The driver should redo any necessary + * initialization. It is mainly used by the USB bus + * + * Return: int 0 for success, non zero for failure + */ +static int wlan_hdd_bus_reset_resume(void) +{ + int ret; + struct hif_opaque_softc *scn = NULL; + + scn = cds_get_context(QDF_MODULE_ID_HIF); + if (!scn) { + hdd_err("Failed to get HIF context"); + return -EFAULT; + } + + cds_ssr_protect(__func__); + ret = hif_bus_reset_resume(scn); + cds_ssr_unprotect(__func__); + return ret; +} + +#ifdef FEATURE_RUNTIME_PM +/** + * __wlan_hdd_runtime_suspend() - suspend the wlan bus without apps suspend + * + * Each layer is responsible for its own suspend actions. wma_runtime_suspend + * takes care of the parts of the 802.11 suspend that we want to do for runtime + * suspend. + * + * Return: 0 or errno + */ +static int __wlan_hdd_runtime_suspend(struct device *dev) +{ + hdd_context_t *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + void *hif_ctx = cds_get_context(QDF_MODULE_ID_HIF); + void *txrx_pdev = cds_get_context(QDF_MODULE_ID_TXRX); + void *htc_ctx = cds_get_context(QDF_MODULE_ID_HTC); + int status = wlan_hdd_validate_context(hdd_ctx); + + if (0 != status) + goto process_failure; + + status = hif_pre_runtime_suspend(hif_ctx); + if (status) + goto process_failure; + + status = qdf_status_to_os_return(ol_txrx_runtime_suspend(txrx_pdev)); + if (status) + goto process_failure; + + status = htc_runtime_suspend(htc_ctx); + if (status) + goto resume_txrx; + + status = wma_runtime_suspend(0); + if (status) + goto resume_htc; + + status = hif_runtime_suspend(hif_ctx); + if (status) + goto resume_wma; + + status = pld_auto_suspend(dev); + if (status) + goto resume_hif; + + hif_process_runtime_suspend_success(hif_ctx); + return status; + +resume_hif: + QDF_BUG(!hif_runtime_resume(hif_ctx)); +resume_wma: + QDF_BUG(!wma_runtime_resume()); +resume_htc: + QDF_BUG(!htc_runtime_resume(htc_ctx)); +resume_txrx: + QDF_BUG(!qdf_status_to_os_return(ol_txrx_runtime_resume(txrx_pdev))); +process_failure: + hif_process_runtime_suspend_failure(hif_ctx); + return status; +} + + +/** + * wlan_hdd_runtime_suspend() - suspend the wlan bus without apps suspend + * + * This function is called by the platform driver to suspend the + * wlan bus separately from system suspend + * + * Return: 0 or errno + */ +static int wlan_hdd_runtime_suspend(struct device *dev) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_runtime_suspend(dev); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __wlan_hdd_runtime_resume() - resume the wlan bus from runtime suspend + * + * Sets the runtime pm state and coordinates resume between hif wma and + * ol_txrx. + * + * Return: success since failure is a bug + */ +static int __wlan_hdd_runtime_resume(struct device *dev) +{ + void *hif_ctx = cds_get_context(QDF_MODULE_ID_HIF); + void *htc_ctx = cds_get_context(QDF_MODULE_ID_HTC); + void *txrx_pdev = cds_get_context(QDF_MODULE_ID_TXRX); + + hif_pre_runtime_resume(hif_ctx); + QDF_BUG(!pld_auto_resume(dev)); + QDF_BUG(!hif_runtime_resume(hif_ctx)); + QDF_BUG(!wma_runtime_resume()); + QDF_BUG(!htc_runtime_resume(htc_ctx)); + QDF_BUG(!qdf_status_to_os_return(ol_txrx_runtime_resume(txrx_pdev))); + hif_process_runtime_resume_success(hif_ctx); + return 0; +} + +/** + * wlan_hdd_runtime_resume() - resume the wlan bus from runtime suspend + * + * This function is called by the platform driver to resume the + * wlan bus separately from system suspend + * + * Return: success since failure is a bug + */ +static int wlan_hdd_runtime_resume(struct device *dev) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_runtime_resume(dev); + cds_ssr_unprotect(__func__); + + return ret; +} +#endif + +/** + * wlan_hdd_pld_probe() - probe function registered to PLD + * @dev: device + * @pld_bus_type: PLD bus type + * @bdev: bus device structure + * @id: bus identifier for shared busses + * + * Return: 0 on success + */ +static int wlan_hdd_pld_probe(struct device *dev, + enum pld_bus_type pld_bus_type, + void *bdev, void *id) +{ + enum qdf_bus_type bus_type; + + bus_type = to_bus_type(pld_bus_type); + if (bus_type == QDF_BUS_TYPE_NONE) { + hdd_err("Invalid bus type %d->%d", + pld_bus_type, bus_type); + return -EINVAL; + } + + return wlan_hdd_probe(dev, bdev, id, bus_type, false); +} + +/** + * wlan_hdd_pld_remove() - remove function registered to PLD + * @dev: device + * @pld_bus_type: PLD bus type + * + * Return: void + */ +static void wlan_hdd_pld_remove(struct device *dev, + enum pld_bus_type bus_type) +{ + ENTER(); + mutex_lock(&hdd_init_deinit_lock); + wlan_hdd_remove(dev); + mutex_unlock(&hdd_init_deinit_lock); + EXIT(); +} + +/** + * wlan_hdd_pld_shutdown() - shutdown function registered to PLD + * @dev: device + * @pld_bus_type: PLD bus type + * + * Return: void + */ +static void wlan_hdd_pld_shutdown(struct device *dev, + enum pld_bus_type bus_type) +{ + ENTER(); + mutex_lock(&hdd_init_deinit_lock); + wlan_hdd_shutdown(); + mutex_unlock(&hdd_init_deinit_lock); + EXIT(); +} + +/** + * wlan_hdd_pld_reinit() - reinit function registered to PLD + * @dev: device + * @pld_bus_type: PLD bus type + * @bdev: bus device structure + * @id: bus identifier for shared busses + * + * Return: 0 on success + */ +static int wlan_hdd_pld_reinit(struct device *dev, + enum pld_bus_type pld_bus_type, + void *bdev, void *id) +{ + enum qdf_bus_type bus_type; + + bus_type = to_bus_type(pld_bus_type); + if (bus_type == QDF_BUS_TYPE_NONE) { + hdd_err("Invalid bus type %d->%d", + pld_bus_type, bus_type); + return -EINVAL; + } + + return wlan_hdd_probe(dev, bdev, id, bus_type, true); +} + +/** + * wlan_hdd_pld_crash_shutdown() - crash_shutdown function registered to PLD + * @dev: device + * @pld_bus_type: PLD bus type + * + * Return: void + */ +static void wlan_hdd_pld_crash_shutdown(struct device *dev, + enum pld_bus_type bus_type) +{ + wlan_hdd_crash_shutdown(); +} + +/** + * wlan_hdd_pld_suspend() - suspend function registered to PLD + * @dev: device + * @pld_bus_type: PLD bus type + * @state: PM state + * + * Return: 0 on success + */ +static int wlan_hdd_pld_suspend(struct device *dev, + enum pld_bus_type bus_type, + pm_message_t state) + +{ + return wlan_hdd_bus_suspend(state); +} + +/** + * wlan_hdd_pld_resume() - resume function registered to PLD + * @dev: device + * @pld_bus_type: PLD bus type + * + * Return: 0 on success + */ +static int wlan_hdd_pld_resume(struct device *dev, + enum pld_bus_type bus_type) +{ + return wlan_hdd_bus_resume(); +} + + +/** + * wlan_hdd_pld_suspend_noirq() - handle suspend no irq + * @dev: device + * @pld_bus_type: PLD bus type + * + * Complete the actions started by suspend(). Carry out any + * additional operations required for suspending the device that might be + * racing with its driver's interrupt handler, which is guaranteed not to + * run while suspend_noirq() is being executed. Make sure to resume device + * if FW has sent initial wake up message and expecting APPS to wake up. + * + * Return: 0 on success + */ +static int wlan_hdd_pld_suspend_noirq(struct device *dev, + enum pld_bus_type bus_type) +{ + return wlan_hdd_bus_suspend_noirq(); +} + +/** + * wlan_hdd_pld_resume_noirq() - handle resume no irq + * @dev: device + * @pld_bus_type: PLD bus type + * + * Prepare for the execution of resume() by carrying out any + * operations required for resuming the device that might be racing with + * its driver's interrupt handler, which is guaranteed not to run while + * resume_noirq() is being executed. Make sure to clear target initial + * wake up request such that next suspend can happen cleanly. + * + * Return: 0 on success + */ +static int wlan_hdd_pld_resume_noirq(struct device *dev, + enum pld_bus_type bus_type) +{ + return wlan_hdd_bus_resume_noirq(); +} + +/** + * wlan_hdd_pld_reset_resume() - reset resume function registered to PLD + * @dev: device + * @pld_bus_type: PLD bus type + * + * Return: 0 on success + */ +static int wlan_hdd_pld_reset_resume(struct device *dev, + enum pld_bus_type bus_type) +{ + return wlan_hdd_bus_reset_resume(); +} + +/** + * wlan_hdd_pld_notify_handler() - notify_handler function registered to PLD + * @dev: device + * @pld_bus_type: PLD bus type + * @state: Modem power state + * + * Return: void + */ +static void wlan_hdd_pld_notify_handler(struct device *dev, + enum pld_bus_type bus_type, + int state) +{ + wlan_hdd_notify_handler(state); +} + +/** + * wlan_hdd_pld_uevent() - update driver status + * @dev: device + * @uevent: uevent status + * + * Return: void + */ +static void wlan_hdd_pld_uevent(struct device *dev, + struct pld_uevent_data *uevent) +{ + if (uevent->uevent == PLD_RECOVERY) + cds_set_recovery_in_progress(true); +} + +#ifdef FEATURE_RUNTIME_PM +/** + * wlan_hdd_pld_runtime_suspend() - runtime suspend function registered to PLD + * @dev: device + * @pld_bus_type: PLD bus type + * + * Return: 0 on success + */ +static int wlan_hdd_pld_runtime_suspend(struct device *dev, + enum pld_bus_type bus_type) +{ + return wlan_hdd_runtime_suspend(dev); +} + +/** + * wlan_hdd_pld_runtime_resume() - runtime resume function registered to PLD + * @dev: device + * @pld_bus_type: PLD bus type + * + * Return: 0 on success + */ +static int wlan_hdd_pld_runtime_resume(struct device *dev, + enum pld_bus_type bus_type) +{ + return wlan_hdd_runtime_resume(dev); +} +#endif + +struct pld_driver_ops wlan_drv_ops = { + .probe = wlan_hdd_pld_probe, + .remove = wlan_hdd_pld_remove, + .shutdown = wlan_hdd_pld_shutdown, + .reinit = wlan_hdd_pld_reinit, + .crash_shutdown = wlan_hdd_pld_crash_shutdown, + .suspend = wlan_hdd_pld_suspend, + .resume = wlan_hdd_pld_resume, + .suspend_noirq = wlan_hdd_pld_suspend_noirq, + .resume_noirq = wlan_hdd_pld_resume_noirq, + .reset_resume = wlan_hdd_pld_reset_resume, + .modem_status = wlan_hdd_pld_notify_handler, + .uevent = wlan_hdd_pld_uevent, +#ifdef FEATURE_RUNTIME_PM + .runtime_suspend = wlan_hdd_pld_runtime_suspend, + .runtime_resume = wlan_hdd_pld_runtime_resume, +#endif +}; + +/** + * wlan_hdd_register_driver() - wlan_hdd_register_driver + * + * Return: int + */ +int wlan_hdd_register_driver(void) +{ + return pld_register_driver(&wlan_drv_ops); +} + +/** + * wlan_hdd_unregister_driver() - wlan_hdd_unregister_driver + * + * Return: void + */ +void wlan_hdd_unregister_driver(void) +{ + pld_unregister_driver(); +} diff --git a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_ext_scan.c b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_ext_scan.c new file mode 100644 index 0000000000000000000000000000000000000000..ae81cd6b09340160899b19f88c251cb7fa3bbfde --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_ext_scan.c @@ -0,0 +1,4365 @@ +/* + * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/** + * DOC: wlan_hdd_ext_scan.c + * + * WLAN Host Device Driver EXT SCAN feature implementation + * + */ + +#ifdef FEATURE_WLAN_EXTSCAN + +#include "wlan_hdd_ext_scan.h" +#include "wlan_hdd_regulatory.h" +#include "cds_utils.h" +#include "cds_sched.h" + +/* amount of time to wait for a synchronous request/response operation */ +#define WLAN_WAIT_TIME_EXTSCAN 1000 + +/** + * struct hdd_ext_scan_context - hdd ext scan context + * @request_id: userspace-assigned ID associated with the request + * @response_event: Ext scan wait event + * @response_status: Status returned by FW in response to a request + * @ignore_cached_results: Flag to ignore cached results or not + * @context_lock: Spinlock to serialize all context accesses + * @capability_response: Ext scan capability response data from target + * @buckets_scanned: bitmask of buckets scanned in extscan cycle + */ +struct hdd_ext_scan_context { + uint32_t request_id; + int response_status; + bool ignore_cached_results; + struct completion response_event; + spinlock_t context_lock; + struct ext_scan_capabilities_response capability_response; + uint32_t buckets_scanned; +}; +static struct hdd_ext_scan_context ext_scan_context; + +static const struct nla_policy wlan_hdd_extscan_config_policy +[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID] = { + .type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_GET_VALID_CHANNELS_CONFIG_PARAM_WIFI_BAND] = { + .type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_GET_VALID_CHANNELS_CONFIG_PARAM_MAX_CHANNELS] = { + .type = NLA_U32 }, + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_CHANNEL_SPEC_CHANNEL] = {.type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_CHANNEL_SPEC_DWELL_TIME] = { + .type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_CHANNEL_SPEC_PASSIVE] = {.type = NLA_U8}, + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_CHANNEL_SPEC_CLASS] = {.type = NLA_U8}, + + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_INDEX] = {.type = NLA_U8}, + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_BAND] = {.type = NLA_U8}, + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_PERIOD] = {.type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_REPORT_EVENTS] = { + .type = NLA_U8}, + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_NUM_CHANNEL_SPECS] = { + .type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SCAN_CMD_PARAMS_BASE_PERIOD] = { + .type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SCAN_CMD_PARAMS_MAX_AP_PER_SCAN] = { + .type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SCAN_CMD_PARAMS_REPORT_THRESHOLD_PERCENT] = { + .type = NLA_U8}, + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SCAN_CMD_PARAMS_REPORT_THRESHOLD_NUM_SCANS] = { + .type = NLA_U8 }, + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SCAN_CMD_PARAMS_NUM_BUCKETS] = { + .type = NLA_U8}, + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_GET_CACHED_SCAN_RESULTS_CONFIG_PARAM_FLUSH] = { + .type = NLA_U8}, + + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_GET_CACHED_SCAN_RESULTS_CONFIG_PARAM_MAX] = { + .type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM_BSSID] = { + .type = NLA_UNSPEC, + .len = QDF_MAC_ADDR_SIZE}, + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM_RSSI_LOW] = { + .type = NLA_S32}, + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM_RSSI_HIGH] = { + .type = NLA_S32}, + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM_CHANNEL] = { + .type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_BSSID_HOTLIST_PARAMS_NUM_AP] = { + .type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SIGNIFICANT_CHANGE_PARAMS_RSSI_SAMPLE_SIZE] = { + .type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SIGNIFICANT_CHANGE_PARAMS_LOST_AP_SAMPLE_SIZE] = { + .type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SIGNIFICANT_CHANGE_PARAMS_MIN_BREACHING] = { + .type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SIGNIFICANT_CHANGE_PARAMS_NUM_AP] = { + .type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_MAX_PERIOD] = { + .type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_BASE] = { + .type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_STEP_COUNT] = { + .type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SSID_THRESHOLD_PARAM_SSID] = { + .type = NLA_BINARY, + .len = IEEE80211_MAX_SSID_LEN + 1 }, + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SSID_HOTLIST_PARAMS_LOST_SSID_SAMPLE_SIZE] = { + .type = NLA_U32 }, + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SSID_HOTLIST_PARAMS_NUM_SSID] = { + .type = NLA_U32 }, + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SSID_THRESHOLD_PARAM_BAND] = { + .type = NLA_U8 }, + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SSID_THRESHOLD_PARAM_RSSI_LOW] = { + .type = NLA_S32 }, + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SSID_THRESHOLD_PARAM_RSSI_HIGH] = { + .type = NLA_S32 }, + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_CONFIGURATION_FLAGS] = { + .type = NLA_U32 }, + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_BSSID_HOTLIST_PARAMS_LOST_AP_SAMPLE_SIZE] = { + .type = NLA_U32 }, +}; + +static const struct nla_policy +wlan_hdd_pno_config_policy[QCA_WLAN_VENDOR_ATTR_PNO_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_LIST_PARAM_NUM] = { + .type = NLA_U32 + }, + [QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_NETWORK_PARAM_ID] = { + .type = NLA_U32 + }, + [QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_NUM_NETWORKS] = { + .type = NLA_U32 + }, + [QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORK_SSID] = { + .type = NLA_BINARY, + .len = IEEE80211_MAX_SSID_LEN + 1 + }, + [QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORK_FLAGS] = { + .type = NLA_U8 + }, + [QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORK_AUTH_BIT] = { + .type = NLA_U8 + }, + [QCA_WLAN_VENDOR_ATTR_EPNO_MIN5GHZ_RSSI] = { + .type = NLA_U32 + }, + [QCA_WLAN_VENDOR_ATTR_EPNO_MIN24GHZ_RSSI] = { + .type = NLA_U32 + }, + [QCA_WLAN_VENDOR_ATTR_EPNO_INITIAL_SCORE_MAX] = { + .type = NLA_U32 + }, + [QCA_WLAN_VENDOR_ATTR_EPNO_CURRENT_CONNECTION_BONUS] = { + .type = NLA_U32 + }, + [QCA_WLAN_VENDOR_ATTR_EPNO_SAME_NETWORK_BONUS] = { + .type = NLA_U32 + }, + [QCA_WLAN_VENDOR_ATTR_EPNO_SECURE_BONUS] = { + .type = NLA_U32 + }, + [QCA_WLAN_VENDOR_ATTR_EPNO_BAND5GHZ_BONUS] = { + .type = NLA_U32 + }, +}; + +static const struct nla_policy +wlan_hdd_extscan_results_policy[QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_BEACON_PERIOD] = { + .type = NLA_U16}, + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_CAPABILITY] = { + .type = NLA_U16}, +}; + +/** + * wlan_hdd_cfg80211_extscan_get_capabilities_rsp() - response from target + * @ctx: Pointer to hdd context + * @data: Pointer to ext scan capabilities response from fw + * + * Return: None + */ +static void +wlan_hdd_cfg80211_extscan_get_capabilities_rsp(void *ctx, + struct ext_scan_capabilities_response *data) +{ + struct hdd_ext_scan_context *context; + hdd_context_t *hdd_ctx = ctx; + + ENTER(); + + if (wlan_hdd_validate_context(hdd_ctx)) + return; + if (!data) { + hdd_err("data is null"); + return; + } + + context = &ext_scan_context; + + spin_lock(&context->context_lock); + /* validate response received from target*/ + if (context->request_id != data->requestId) { + spin_unlock(&context->context_lock); + hdd_err("Target response id did not match: request_id %d response_id %d", + context->request_id, data->requestId); + return; + } else { + context->capability_response = *data; + complete(&context->response_event); + } + + spin_unlock(&context->context_lock); + + return; +} + +/* + * define short names for the global vendor params + * used by hdd_extscan_nl_fill_bss() + */ +#define PARAM_TIME_STAMP \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_TIME_STAMP +#define PARAM_SSID \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_SSID +#define PARAM_BSSID \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_BSSID +#define PARAM_CHANNEL \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_CHANNEL +#define PARAM_RSSI \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_RSSI +#define PARAM_RTT \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_RTT +#define PARAM_RTT_SD \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_RTT_SD +#define PARAM_BEACON_PERIOD \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_BEACON_PERIOD +#define PARAM_CAPABILITY \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_CAPABILITY +#define PARAM_IE_LENGTH \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_IE_LENGTH +#define PARAM_IE_DATA \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_IE_DATA + +/** hdd_extscan_nl_fill_bss() - extscan nl fill bss + * @skb: socket buffer + * @ap: bss information + * @idx: nesting index + * + * Return: 0 on success; error number otherwise + */ +static int hdd_extscan_nl_fill_bss(struct sk_buff *skb, tSirWifiScanResult *ap, + int idx) +{ + struct nlattr *nla_ap; + + nla_ap = nla_nest_start(skb, idx); + if (!nla_ap) + return -EINVAL; + + if (hdd_wlan_nla_put_u64(skb, PARAM_TIME_STAMP, ap->ts) || + nla_put(skb, PARAM_SSID, sizeof(ap->ssid), ap->ssid) || + nla_put(skb, PARAM_BSSID, sizeof(ap->bssid), ap->bssid.bytes) || + nla_put_u32(skb, PARAM_CHANNEL, ap->channel) || + nla_put_s32(skb, PARAM_RSSI, ap->rssi) || + nla_put_u32(skb, PARAM_RTT, ap->rtt) || + nla_put_u32(skb, PARAM_RTT_SD, ap->rtt_sd) || + nla_put_u16(skb, PARAM_BEACON_PERIOD, ap->beaconPeriod) || + nla_put_u16(skb, PARAM_CAPABILITY, ap->capability) || + nla_put_u16(skb, PARAM_IE_LENGTH, ap->ieLength)) { + hdd_err("put fail"); + return -EINVAL; + } + + if (ap->ieLength) + if (nla_put(skb, PARAM_IE_DATA, ap->ieLength, ap->ieData)) { + hdd_err("put fail"); + return -EINVAL; + } + + nla_nest_end(skb, nla_ap); + + return 0; +} +/* + * done with short names for the global vendor params + * used by hdd_extscan_nl_fill_bss() + */ +#undef PARAM_TIME_STAMP +#undef PARAM_SSID +#undef PARAM_BSSID +#undef PARAM_CHANNEL +#undef PARAM_RSSI +#undef PARAM_RTT +#undef PARAM_RTT_SD +#undef PARAM_BEACON_PERIOD +#undef PARAM_CAPABILITY +#undef PARAM_IE_LENGTH +#undef PARAM_IE_DATA + +/** wlan_hdd_cfg80211_extscan_cached_results_ind() - get cached results + * @ctx: hdd global context + * @data: cached results + * + * This function reads the cached results %data, populated the NL + * attributes and sends the NL event to the upper layer. + * + * Return: none + */ +static void +wlan_hdd_cfg80211_extscan_cached_results_ind(void *ctx, + struct extscan_cached_scan_results *data) +{ + hdd_context_t *pHddCtx = ctx; + struct sk_buff *skb = NULL; + struct hdd_ext_scan_context *context; + struct extscan_cached_scan_result *result; + tSirWifiScanResult *ap; + uint32_t i, j, nl_buf_len; + bool ignore_cached_results = false; + + /* ENTER() intentionally not used in a frequently invoked API */ + + if (wlan_hdd_validate_context(pHddCtx)) + return; + if (!data) { + hdd_err("data is null"); + return; + } + + context = &ext_scan_context; + spin_lock(&context->context_lock); + ignore_cached_results = context->ignore_cached_results; + spin_unlock(&context->context_lock); + + if (ignore_cached_results) { + hdd_err("Ignore the cached results received after timeout"); + return; + } + +#define EXTSCAN_CACHED_NEST_HDRLEN NLA_HDRLEN +#define EXTSCAN_CACHED_NL_FIXED_TLV \ + ((sizeof(data->request_id) + NLA_HDRLEN) + \ + (sizeof(data->num_scan_ids) + NLA_HDRLEN) + \ + (sizeof(data->more_data) + NLA_HDRLEN)) +#define EXTSCAN_CACHED_NL_SCAN_ID_TLV \ + ((sizeof(result->scan_id) + NLA_HDRLEN) + \ + (sizeof(result->flags) + NLA_HDRLEN) + \ + (sizeof(result->num_results) + NLA_HDRLEN))+ \ + (sizeof(result->buckets_scanned) + NLA_HDRLEN) +#define EXTSCAN_CACHED_NL_SCAN_RESULTS_TLV \ + ((sizeof(ap->ts) + NLA_HDRLEN) + \ + (sizeof(ap->ssid) + NLA_HDRLEN) + \ + (sizeof(ap->bssid) + NLA_HDRLEN) + \ + (sizeof(ap->channel) + NLA_HDRLEN) + \ + (sizeof(ap->rssi) + NLA_HDRLEN) + \ + (sizeof(ap->rtt) + NLA_HDRLEN) + \ + (sizeof(ap->rtt_sd) + NLA_HDRLEN) + \ + (sizeof(ap->beaconPeriod) + NLA_HDRLEN) + \ + (sizeof(ap->capability) + NLA_HDRLEN) + \ + (sizeof(ap->ieLength) + NLA_HDRLEN)) +#define EXTSCAN_CACHED_NL_SCAN_RESULTS_IE_DATA_TLV \ + (ap->ieLength + NLA_HDRLEN) + + nl_buf_len = NLMSG_HDRLEN; + nl_buf_len += EXTSCAN_CACHED_NL_FIXED_TLV; + if (data->num_scan_ids) { + nl_buf_len += sizeof(result->scan_id) + NLA_HDRLEN; + nl_buf_len += EXTSCAN_CACHED_NEST_HDRLEN; + result = &data->result[0]; + for (i = 0; i < data->num_scan_ids; i++) { + nl_buf_len += EXTSCAN_CACHED_NEST_HDRLEN; + nl_buf_len += EXTSCAN_CACHED_NL_SCAN_ID_TLV; + nl_buf_len += EXTSCAN_CACHED_NEST_HDRLEN; + + ap = &result->ap[0]; + for (j = 0; j < result->num_results; j++) { + nl_buf_len += EXTSCAN_CACHED_NEST_HDRLEN; + nl_buf_len += + EXTSCAN_CACHED_NL_SCAN_RESULTS_TLV; + if (ap->ieLength) + nl_buf_len += + EXTSCAN_CACHED_NL_SCAN_RESULTS_IE_DATA_TLV; + ap++; + } + result++; + } + } + + skb = cfg80211_vendor_cmd_alloc_reply_skb(pHddCtx->wiphy, nl_buf_len); + + if (!skb) { + hdd_err("cfg80211_vendor_cmd_alloc_reply_skb failed"); + goto fail; + } + hdd_notice("Req Id %u Num_scan_ids %u More Data %u", + data->request_id, data->num_scan_ids, data->more_data); + + result = &data->result[0]; + for (i = 0; i < data->num_scan_ids; i++) { + hdd_notice("[i=%d] scan_id %u flags %u num_results %u buckets scanned %u", + i, result->scan_id, result->flags, result->num_results, + result->buckets_scanned); + + ap = &result->ap[0]; + for (j = 0; j < result->num_results; j++) { + /* + * Firmware returns timestamp from ext scan start till + * BSSID was cached (in micro seconds). Add this with + * time gap between system boot up to ext scan start + * to derive the time since boot when the + * BSSID was cached. + */ + ap->ts += pHddCtx->ext_scan_start_since_boot; + hdd_notice("Timestamp %llu " + "Ssid: %s " + "Bssid (" MAC_ADDRESS_STR ") " + "Channel %u " + "Rssi %d " + "RTT %u " + "RTT_SD %u " + "Beacon Period %u " + "Capability 0x%x " + "Ie length %d", + ap->ts, + ap->ssid, + MAC_ADDR_ARRAY(ap->bssid.bytes), + ap->channel, + ap->rssi, + ap->rtt, + ap->rtt_sd, + ap->beaconPeriod, + ap->capability, + ap->ieLength); + ap++; + } + result++; + } + + if (nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_REQUEST_ID, + data->request_id) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_NUM_RESULTS_AVAILABLE, + data->num_scan_ids) || + nla_put_u8(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_MORE_DATA, + data->more_data)) { + hdd_err("put fail"); + goto fail; + } + + if (data->num_scan_ids) { + struct nlattr *nla_results; + result = &data->result[0]; + + if (nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_CACHED_RESULTS_SCAN_ID, + result->scan_id)) { + hdd_err("put fail"); + goto fail; + } + nla_results = nla_nest_start(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_CACHED_RESULTS_LIST); + if (!nla_results) + goto fail; + + for (i = 0; i < data->num_scan_ids; i++) { + struct nlattr *nla_result; + struct nlattr *nla_aps; + + nla_result = nla_nest_start(skb, i); + if (!nla_result) + goto fail; + + if (nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_CACHED_RESULTS_SCAN_ID, + result->scan_id) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_CACHED_RESULTS_FLAGS, + result->flags) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_BUCKETS_SCANNED, + result->buckets_scanned) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_NUM_RESULTS_AVAILABLE, + result->num_results)) { + hdd_err("put fail"); + goto fail; + } + + nla_aps = nla_nest_start(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_LIST); + if (!nla_aps) + goto fail; + + ap = &result->ap[0]; + for (j = 0; j < result->num_results; j++) { + if (hdd_extscan_nl_fill_bss(skb, ap, j)) + goto fail; + + ap++; + } + nla_nest_end(skb, nla_aps); + nla_nest_end(skb, nla_result); + result++; + } + nla_nest_end(skb, nla_results); + } + + cfg80211_vendor_cmd_reply(skb); + + if (!data->more_data) { + spin_lock(&context->context_lock); + context->response_status = 0; + complete(&context->response_event); + spin_unlock(&context->context_lock); + } + return; + +fail: + if (skb) + kfree_skb(skb); + + spin_lock(&context->context_lock); + context->response_status = -EINVAL; + spin_unlock(&context->context_lock); + + return; +} + +/** + * wlan_hdd_cfg80211_extscan_hotlist_match_ind() - hot list match ind + * @ctx: Pointer to hdd context + * @pData: Pointer to ext scan result event + * + * This callback execute in atomic context and must not invoke any + * blocking calls. + * + * Return: none + */ +static void +wlan_hdd_cfg80211_extscan_hotlist_match_ind(void *ctx, + struct extscan_hotlist_match *data) +{ + hdd_context_t *pHddCtx = ctx; + struct sk_buff *skb = NULL; + uint32_t i, index; + int flags = cds_get_gfp_flags(); + + ENTER(); + + if (wlan_hdd_validate_context(pHddCtx)) + return; + if (!data) { + hdd_err("data is null"); + return; + } + + if (data->ap_found) + index = QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_HOTLIST_AP_FOUND_INDEX; + else + index = QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_HOTLIST_AP_LOST_INDEX; + + skb = cfg80211_vendor_event_alloc( + pHddCtx->wiphy, + NULL, + EXTSCAN_EVENT_BUF_SIZE + NLMSG_HDRLEN, + index, flags); + + if (!skb) { + hdd_err("cfg80211_vendor_event_alloc failed"); + return; + } + hdd_info("Req Id: %u Num_APs: %u MoreData: %u ap_found: %u", + data->requestId, data->numOfAps, data->moreData, + data->ap_found); + + for (i = 0; i < data->numOfAps; i++) { + data->ap[i].ts = qdf_get_monotonic_boottime(); + + hdd_notice("[i=%d] Timestamp %llu " + "Ssid: %s " + "Bssid (" MAC_ADDRESS_STR ") " + "Channel %u " + "Rssi %d " + "RTT %u " + "RTT_SD %u", + i, + data->ap[i].ts, + data->ap[i].ssid, + MAC_ADDR_ARRAY(data->ap[i].bssid.bytes), + data->ap[i].channel, + data->ap[i].rssi, + data->ap[i].rtt, data->ap[i].rtt_sd); + } + + if (nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_REQUEST_ID, + data->requestId) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_NUM_RESULTS_AVAILABLE, + data->numOfAps)) { + hdd_err("put fail"); + goto fail; + } + + if (data->numOfAps) { + struct nlattr *aps; + + aps = nla_nest_start(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_LIST); + if (!aps) + goto fail; + + for (i = 0; i < data->numOfAps; i++) { + struct nlattr *ap; + + ap = nla_nest_start(skb, i); + if (!ap) + goto fail; + + if (hdd_wlan_nla_put_u64(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_TIME_STAMP, + data->ap[i].ts) || + nla_put(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_SSID, + sizeof(data->ap[i].ssid), + data->ap[i].ssid) || + nla_put(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_BSSID, + sizeof(data->ap[i].bssid), + data->ap[i].bssid.bytes) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_CHANNEL, + data->ap[i].channel) || + nla_put_s32(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_RSSI, + data->ap[i].rssi) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_RTT, + data->ap[i].rtt) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_RTT_SD, + data->ap[i].rtt_sd)) + goto fail; + + nla_nest_end(skb, ap); + } + nla_nest_end(skb, aps); + + if (nla_put_u8(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_MORE_DATA, + data->moreData)) + goto fail; + } + + cfg80211_vendor_event(skb, flags); + EXIT(); + return; + +fail: + kfree_skb(skb); + return; +} + +/** + * wlan_hdd_cfg80211_extscan_signif_wifi_change_results_ind() - + * significant wifi change results indication + * @ctx: Pointer to hdd context + * @pData: Pointer to signif wifi change event + * + * This callback execute in atomic context and must not invoke any + * blocking calls. + * + * Return: none + */ +static void +wlan_hdd_cfg80211_extscan_signif_wifi_change_results_ind( + void *ctx, + tpSirWifiSignificantChangeEvent pData) +{ + hdd_context_t *pHddCtx = (hdd_context_t *) ctx; + struct sk_buff *skb = NULL; + tSirWifiSignificantChange *ap_info; + int32_t *rssi; + uint32_t i, j; + int flags = cds_get_gfp_flags(); + + ENTER(); + + if (wlan_hdd_validate_context(pHddCtx)) + return; + if (!pData) { + hdd_err("pData is null"); + return; + } + + skb = cfg80211_vendor_event_alloc( + pHddCtx->wiphy, + NULL, + EXTSCAN_EVENT_BUF_SIZE + NLMSG_HDRLEN, + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SIGNIFICANT_CHANGE_INDEX, + flags); + + if (!skb) { + hdd_err("cfg80211_vendor_event_alloc failed"); + return; + } + hdd_notice("Req Id %u Num results %u More Data %u", + pData->requestId, pData->numResults, pData->moreData); + + ap_info = &pData->ap[0]; + for (i = 0; i < pData->numResults; i++) { + hdd_notice("[i=%d] " + "Bssid (" MAC_ADDRESS_STR ") " + "Channel %u " + "numOfRssi %d", + i, + MAC_ADDR_ARRAY(ap_info->bssid.bytes), + ap_info->channel, ap_info->numOfRssi); + rssi = &(ap_info)->rssi[0]; + for (j = 0; j < ap_info->numOfRssi; j++) + hdd_notice("Rssi %d", *rssi++); + + ap_info += ap_info->numOfRssi * sizeof(*rssi); + } + + if (nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_REQUEST_ID, + pData->requestId) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_NUM_RESULTS_AVAILABLE, + pData->numResults)) { + hdd_err("put fail"); + goto fail; + } + + if (pData->numResults) { + struct nlattr *aps; + + aps = nla_nest_start(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_LIST); + if (!aps) + goto fail; + + ap_info = &pData->ap[0]; + for (i = 0; i < pData->numResults; i++) { + struct nlattr *ap; + + ap = nla_nest_start(skb, i); + if (!ap) + goto fail; + + if (nla_put(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SIGNIFICANT_CHANGE_RESULT_BSSID, + QDF_MAC_ADDR_SIZE, ap_info->bssid.bytes) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SIGNIFICANT_CHANGE_RESULT_CHANNEL, + ap_info->channel) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SIGNIFICANT_CHANGE_RESULT_NUM_RSSI, + ap_info->numOfRssi) || + nla_put(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SIGNIFICANT_CHANGE_RESULT_RSSI_LIST, + sizeof(s32) * ap_info->numOfRssi, + &(ap_info)->rssi[0])) + goto fail; + + nla_nest_end(skb, ap); + + ap_info += ap_info->numOfRssi * sizeof(*rssi); + } + nla_nest_end(skb, aps); + + if (nla_put_u8(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_MORE_DATA, + pData->moreData)) + goto fail; + } + + cfg80211_vendor_event(skb, flags); + return; + +fail: + kfree_skb(skb); + return; + +} + +/** + * wlan_hdd_cfg80211_extscan_full_scan_result_event() - full scan result event + * @ctx: Pointer to hdd context + * @pData: Pointer to full scan result event + * + * This callback execute in atomic context and must not invoke any + * blocking calls. + * + * Return: none + */ +static void +wlan_hdd_cfg80211_extscan_full_scan_result_event(void *ctx, + tpSirWifiFullScanResultEvent + pData) +{ + hdd_context_t *pHddCtx = (hdd_context_t *) ctx; + struct sk_buff *skb = NULL; + struct timespec ts; + struct hdd_ext_scan_context *context; + + int flags = cds_get_gfp_flags(); + + /* ENTER() intentionally not used in a frequently invoked API */ + + if (wlan_hdd_validate_context(pHddCtx)) + return; + if (!pData) { + hdd_err("pData is null"); + return; + } + + if ((sizeof(*pData) + pData->ap.ieLength) >= EXTSCAN_EVENT_BUF_SIZE) { + hdd_err("Frame exceeded NL size limitation, drop it!!"); + return; + } + skb = cfg80211_vendor_event_alloc( + pHddCtx->wiphy, + NULL, + EXTSCAN_EVENT_BUF_SIZE + NLMSG_HDRLEN, + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_FULL_SCAN_RESULT_INDEX, + flags); + + if (!skb) { + hdd_err("cfg80211_vendor_event_alloc failed"); + return; + } + + pData->ap.channel = cds_chan_to_freq(pData->ap.channel); + + /* Android does not want the time stamp from the frame. + Instead it wants a monotonic increasing value since boot */ + get_monotonic_boottime(&ts); + pData->ap.ts = ((u64)ts.tv_sec * 1000000) + (ts.tv_nsec / 1000); + + hdd_notice("Req Id %u More Data %u", pData->requestId, + pData->moreData); + hdd_notice("AP Info: Timestamp %llu Ssid: %s " + "Bssid (" MAC_ADDRESS_STR ") " + "Channel %u " + "Rssi %d " + "RTT %u " + "RTT_SD %u " + "Bcn Period %d " + "Capability 0x%X " + "IE Length %d", + pData->ap.ts, + pData->ap.ssid, + MAC_ADDR_ARRAY(pData->ap.bssid.bytes), + pData->ap.channel, + pData->ap.rssi, + pData->ap.rtt, + pData->ap.rtt_sd, + pData->ap.beaconPeriod, + pData->ap.capability, pData->ap.ieLength); + + if (nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_REQUEST_ID, + pData->requestId) || + hdd_wlan_nla_put_u64(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_TIME_STAMP, + pData->ap.ts) || + nla_put(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_SSID, + sizeof(pData->ap.ssid), + pData->ap.ssid) || + nla_put(skb, QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_BSSID, + sizeof(pData->ap.bssid), + pData->ap.bssid.bytes) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_CHANNEL, + pData->ap.channel) || + nla_put_s32(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_RSSI, + pData->ap.rssi) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_RTT, + pData->ap.rtt) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_RTT_SD, + pData->ap.rtt_sd) || + nla_put_u16(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_BEACON_PERIOD, + pData->ap.beaconPeriod) || + nla_put_u16(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_CAPABILITY, + pData->ap.capability) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_IE_LENGTH, + pData->ap.ieLength) || + nla_put_u8(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_MORE_DATA, + pData->moreData)) { + hdd_err("nla put fail"); + goto nla_put_failure; + } + + if (pData->ap.ieLength) { + if (nla_put(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_IE_DATA, + pData->ap.ieLength, pData->ap.ieData)) + goto nla_put_failure; + } + + context = &ext_scan_context; + spin_lock(&context->context_lock); + if (nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_BUCKETS_SCANNED, + context->buckets_scanned)) { + spin_unlock(&context->context_lock); + hdd_notice("Failed to include buckets_scanned"); + goto nla_put_failure; + } + spin_unlock(&context->context_lock); + + cfg80211_vendor_event(skb, flags); + return; + +nla_put_failure: + kfree_skb(skb); + return; +} + +/** + * wlan_hdd_cfg80211_extscan_scan_res_available_event() - scan result event + * @ctx: Pointer to hdd context + * @pData: Pointer to scan results available indication param + * + * This callback execute in atomic context and must not invoke any + * blocking calls. + * + * Return: none + */ +static void +wlan_hdd_cfg80211_extscan_scan_res_available_event( + void *ctx, + tpSirExtScanResultsAvailableIndParams pData) +{ + hdd_context_t *pHddCtx = (hdd_context_t *) ctx; + struct sk_buff *skb = NULL; + int flags = cds_get_gfp_flags(); + + ENTER(); + + if (wlan_hdd_validate_context(pHddCtx)) + return; + if (!pData) { + hdd_err("pData is null"); + return; + } + + skb = cfg80211_vendor_event_alloc( + pHddCtx->wiphy, + NULL, + EXTSCAN_EVENT_BUF_SIZE + NLMSG_HDRLEN, + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SCAN_RESULTS_AVAILABLE_INDEX, + flags); + + if (!skb) { + hdd_err("cfg80211_vendor_event_alloc failed"); + return; + } + + hdd_notice("Req Id %u Num results %u", + pData->requestId, pData->numResultsAvailable); + if (nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_REQUEST_ID, + pData->requestId) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_NUM_RESULTS_AVAILABLE, + pData->numResultsAvailable)) { + hdd_err("nla put fail"); + goto nla_put_failure; + } + + cfg80211_vendor_event(skb, flags); + EXIT(); + return; + +nla_put_failure: + kfree_skb(skb); + return; +} + +/** + * wlan_hdd_cfg80211_extscan_scan_progress_event() - scan progress event + * @ctx: Pointer to hdd context + * @pData: Pointer to scan event indication param + * + * This callback execute in atomic context and must not invoke any + * blocking calls. + * + * Return: none + */ +static void +wlan_hdd_cfg80211_extscan_scan_progress_event(void *ctx, + tpSirExtScanOnScanEventIndParams + pData) +{ + hdd_context_t *pHddCtx = (hdd_context_t *) ctx; + struct sk_buff *skb = NULL; + int flags = cds_get_gfp_flags(); + struct hdd_ext_scan_context *context; + + /* ENTER() intentionally not used in a frequently invoked API */ + + if (wlan_hdd_validate_context(pHddCtx)) + return; + if (!pData) { + hdd_err("pData is null"); + return; + } + + skb = cfg80211_vendor_event_alloc( + pHddCtx->wiphy, + NULL, + EXTSCAN_EVENT_BUF_SIZE + NLMSG_HDRLEN, + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SCAN_EVENT_INDEX, + flags); + + if (!skb) { + hdd_err("cfg80211_vendor_event_alloc failed"); + return; + } + + hdd_notice("Request Id: %u Scan event type: %u Scan event status: %u buckets scanned: %u", + pData->requestId, pData->scanEventType, pData->status, + pData->buckets_scanned); + + context = &ext_scan_context; + spin_lock(&context->context_lock); + if (pData->scanEventType == WIFI_EXTSCAN_CYCLE_COMPLETED_EVENT) { + context->buckets_scanned = 0; + pData->scanEventType = WIFI_EXTSCAN_RESULTS_AVAILABLE; + spin_unlock(&context->context_lock); + } else if (pData->scanEventType == WIFI_EXTSCAN_CYCLE_STARTED_EVENT) { + context->buckets_scanned = pData->buckets_scanned; + /* No need to report to user space */ + spin_unlock(&context->context_lock); + goto nla_put_failure; + } else { + spin_unlock(&context->context_lock); + } + + if (nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_REQUEST_ID, + pData->requestId) || + nla_put_u8(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_EVENT_TYPE, + pData->scanEventType)) { + hdd_err("nla put fail"); + goto nla_put_failure; + } + + cfg80211_vendor_event(skb, flags); + return; + +nla_put_failure: + kfree_skb(skb); + return; +} + +/** + * wlan_hdd_cfg80211_extscan_epno_match_found() - pno match found + * @hddctx: HDD context + * @data: matched network data + * + * This function reads the matched network data and fills NL vendor attributes + * and send it to upper layer. + * This callback execute in atomic context and must not invoke any + * blocking calls. + * + * Return: 0 on success, error number otherwise + */ +static void +wlan_hdd_cfg80211_extscan_epno_match_found(void *ctx, + struct pno_match_found *data) +{ + hdd_context_t *pHddCtx = (hdd_context_t *)ctx; + struct sk_buff *skb = NULL; + uint32_t len, i; + int flags = cds_get_gfp_flags(); + + ENTER(); + + if (wlan_hdd_validate_context(pHddCtx)) + return; + if (!data) { + hdd_err("data is null"); + return; + } + + /* + * If the number of match found APs including IE data exceeds NL 4K size + * limitation, drop that beacon/probe rsp frame. + */ + len = sizeof(*data) + + (data->num_results + sizeof(tSirWifiScanResult)); + for (i = 0; i < data->num_results; i++) + len += data->ap[i].ieLength; + + if (len >= EXTSCAN_EVENT_BUF_SIZE) { + hdd_err("Frame exceeded NL size limitation, drop it!"); + return; + } + + skb = cfg80211_vendor_event_alloc(pHddCtx->wiphy, + NULL, + EXTSCAN_EVENT_BUF_SIZE + NLMSG_HDRLEN, + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_PNO_NETWORK_FOUND_INDEX, + flags); + + if (!skb) { + hdd_err("cfg80211_vendor_event_alloc failed"); + return; + } + + hdd_notice("Req Id %u More Data %u num_results %d", + data->request_id, data->more_data, data->num_results); + for (i = 0; i < data->num_results; i++) { + data->ap[i].channel = cds_chan_to_freq(data->ap[i].channel); + hdd_notice("AP Info: Timestamp %llu) Ssid: %s " + "Bssid (" MAC_ADDRESS_STR ") " + "Channel %u " + "Rssi %d " + "RTT %u " + "RTT_SD %u " + "Bcn Period %d " + "Capability 0x%X " + "IE Length %d", + data->ap[i].ts, + data->ap[i].ssid, + MAC_ADDR_ARRAY(data->ap[i].bssid.bytes), + data->ap[i].channel, + data->ap[i].rssi, + data->ap[i].rtt, + data->ap[i].rtt_sd, + data->ap[i].beaconPeriod, + data->ap[i].capability, + data->ap[i].ieLength); + } + + if (nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_REQUEST_ID, + data->request_id) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_NUM_RESULTS_AVAILABLE, + data->num_results) || + nla_put_u8(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_MORE_DATA, + data->more_data)) { + hdd_err("nla put fail"); + goto fail; + } + + if (data->num_results) { + struct nlattr *nla_aps; + nla_aps = nla_nest_start(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_LIST); + if (!nla_aps) + goto fail; + + for (i = 0; i < data->num_results; i++) { + if (hdd_extscan_nl_fill_bss(skb, &data->ap[i], i)) + goto fail; + } + nla_nest_end(skb, nla_aps); + } + + cfg80211_vendor_event(skb, flags); + return; + +fail: + kfree_skb(skb); + return; +} + +/** + * wlan_hdd_cfg80211_passpoint_match_found() - passpoint match found + * @hddctx: HDD context + * @data: matched network data + * + * This function reads the match network %data and fill in the skb with + * NL attributes and send up the NL event + * This callback execute in atomic context and must not invoke any + * blocking calls. + * + * Return: none + */ +static void +wlan_hdd_cfg80211_passpoint_match_found(void *ctx, + struct wifi_passpoint_match *data) +{ + hdd_context_t *pHddCtx = ctx; + struct sk_buff *skb = NULL; + uint32_t len, i, num_matches = 1, more_data = 0; + struct nlattr *nla_aps, *nla_bss; + int flags = cds_get_gfp_flags(); + + ENTER(); + + if (wlan_hdd_validate_context(pHddCtx)) + return; + if (!data) { + hdd_err("data is null"); + return; + } + + len = sizeof(*data) + data->ap.ieLength + data->anqp_len; + if (len >= EXTSCAN_EVENT_BUF_SIZE) { + hdd_err("Result exceeded NL size limitation, drop it"); + return; + } + + skb = cfg80211_vendor_event_alloc(pHddCtx->wiphy, + NULL, + EXTSCAN_EVENT_BUF_SIZE + NLMSG_HDRLEN, + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_PNO_PASSPOINT_NETWORK_FOUND_INDEX, + flags); + + if (!skb) { + hdd_err("cfg80211_vendor_event_alloc failed"); + return; + } + + hdd_notice("Req Id %u Id %u ANQP length %u num_matches %u", + data->request_id, data->id, data->anqp_len, num_matches); + for (i = 0; i < num_matches; i++) { + hdd_notice("AP Info: Timestamp %llu Ssid: %s " + "Bssid (" MAC_ADDRESS_STR ") " + "Channel %u " + "Rssi %d " + "RTT %u " + "RTT_SD %u " + "Bcn Period %d " + "Capability 0x%X " + "IE Length %d", + data->ap.ts, + data->ap.ssid, + MAC_ADDR_ARRAY(data->ap.bssid.bytes), + data->ap.channel, + data->ap.rssi, + data->ap.rtt, + data->ap.rtt_sd, + data->ap.beaconPeriod, + data->ap.capability, + data->ap.ieLength); + } + + if (nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_REQUEST_ID, + data->request_id) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_PNO_RESULTS_PASSPOINT_NETWORK_FOUND_NUM_MATCHES, + num_matches) || + nla_put_u8(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_MORE_DATA, + more_data)) { + hdd_err("nla put fail"); + goto fail; + } + + nla_aps = nla_nest_start(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_PNO_RESULTS_PASSPOINT_MATCH_RESULT_LIST); + if (!nla_aps) + goto fail; + + for (i = 0; i < num_matches; i++) { + struct nlattr *nla_ap; + + nla_ap = nla_nest_start(skb, i); + if (!nla_ap) + goto fail; + + if (nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_PNO_RESULTS_PASSPOINT_MATCH_ID, + data->id) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_PNO_RESULTS_PASSPOINT_MATCH_ANQP_LEN, + data->anqp_len)) { + goto fail; + } + + if (data->anqp_len) + if (nla_put(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_PNO_RESULTS_PASSPOINT_MATCH_ANQP, + data->anqp_len, data->anqp)) + goto fail; + + nla_bss = nla_nest_start(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_LIST); + if (!nla_bss) + goto fail; + + if (hdd_extscan_nl_fill_bss(skb, &data->ap, 0)) + goto fail; + + nla_nest_end(skb, nla_bss); + nla_nest_end(skb, nla_ap); + } + nla_nest_end(skb, nla_aps); + + cfg80211_vendor_event(skb, flags); + return; + +fail: + kfree_skb(skb); + return; +} + +/** + * wlan_hdd_cfg80211_extscan_generic_rsp() - + * Handle a generic ExtScan Response message + * @ctx: HDD context registered with SME + * @response: The ExtScan response from firmware + * + * This function will handle a generic ExtScan response message from + * firmware and will communicate the result to the userspace thread + * that is waiting for the response. + * + * Return: none + */ +static void +wlan_hdd_cfg80211_extscan_generic_rsp + (void *ctx, + struct sir_extscan_generic_response *response) +{ + hdd_context_t *hdd_ctx = ctx; + struct hdd_ext_scan_context *context; + + ENTER(); + + if (wlan_hdd_validate_context(hdd_ctx) || !response) { + hdd_err("HDD context is not valid or response(%p) is null", + response); + return; + } + + hdd_notice("request %u status %u", + response->request_id, response->status); + + context = &ext_scan_context; + spin_lock(&context->context_lock); + if (context->request_id == response->request_id) { + context->response_status = response->status ? -EINVAL : 0; + complete(&context->response_event); + } + spin_unlock(&context->context_lock); + + return; +} + +/** + * wlan_hdd_cfg80211_extscan_callback() - ext scan callback + * @ctx: Pointer to hdd context + * @evType: Event type + * @pMag: Pointer to message + * + * Return: none + */ +void wlan_hdd_cfg80211_extscan_callback(void *ctx, const uint16_t evType, + void *pMsg) +{ + hdd_context_t *pHddCtx = (hdd_context_t *) ctx; + + /* ENTER() intentionally not used in a frequently invoked API */ + + if (wlan_hdd_validate_context(pHddCtx)) + return; + + hdd_notice("Rcvd Event %d", evType); + + switch (evType) { + case eSIR_EXTSCAN_CACHED_RESULTS_RSP: + /* There is no need to send this response to upper layer + Just log the message */ + hdd_notice("Rcvd eSIR_EXTSCAN_CACHED_RESULTS_RSP"); + break; + + case eSIR_EXTSCAN_GET_CAPABILITIES_IND: + wlan_hdd_cfg80211_extscan_get_capabilities_rsp(ctx, + (struct ext_scan_capabilities_response *) pMsg); + break; + + case eSIR_EXTSCAN_HOTLIST_MATCH_IND: + wlan_hdd_cfg80211_extscan_hotlist_match_ind(ctx, pMsg); + break; + + case eSIR_EXTSCAN_SIGNIFICANT_WIFI_CHANGE_RESULTS_IND: + wlan_hdd_cfg80211_extscan_signif_wifi_change_results_ind(ctx, + (tpSirWifiSignificantChangeEvent) pMsg); + break; + + case eSIR_EXTSCAN_CACHED_RESULTS_IND: + wlan_hdd_cfg80211_extscan_cached_results_ind(ctx, pMsg); + break; + + case eSIR_EXTSCAN_SCAN_RES_AVAILABLE_IND: + wlan_hdd_cfg80211_extscan_scan_res_available_event(ctx, + (tpSirExtScanResultsAvailableIndParams) pMsg); + break; + + case eSIR_EXTSCAN_FULL_SCAN_RESULT_IND: + wlan_hdd_cfg80211_extscan_full_scan_result_event(ctx, + (tpSirWifiFullScanResultEvent) pMsg); + break; + + case eSIR_EPNO_NETWORK_FOUND_IND: + wlan_hdd_cfg80211_extscan_epno_match_found(ctx, + (struct pno_match_found *)pMsg); + break; + + case eSIR_EXTSCAN_SCAN_PROGRESS_EVENT_IND: + wlan_hdd_cfg80211_extscan_scan_progress_event(ctx, + (tpSirExtScanOnScanEventIndParams) pMsg); + break; + + case eSIR_PASSPOINT_NETWORK_FOUND_IND: + wlan_hdd_cfg80211_passpoint_match_found(ctx, + (struct wifi_passpoint_match *) pMsg); + break; + + case eSIR_EXTSCAN_START_RSP: + case eSIR_EXTSCAN_STOP_RSP: + case eSIR_EXTSCAN_SET_BSSID_HOTLIST_RSP: + case eSIR_EXTSCAN_RESET_BSSID_HOTLIST_RSP: + case eSIR_EXTSCAN_SET_SIGNIFICANT_WIFI_CHANGE_RSP: + case eSIR_EXTSCAN_RESET_SIGNIFICANT_WIFI_CHANGE_RSP: + case eSIR_EXTSCAN_SET_SSID_HOTLIST_RSP: + case eSIR_EXTSCAN_RESET_SSID_HOTLIST_RSP: + wlan_hdd_cfg80211_extscan_generic_rsp(ctx, pMsg); + break; + + default: + hdd_err("Unknown event type %u", evType); + break; + } +} + +/* + * define short names for the global vendor params + * used by wlan_hdd_send_ext_scan_capability() + */ +#define PARAM_REQUEST_ID \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID +#define PARAM_STATUS \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_STATUS +#define MAX_SCAN_CACHE_SIZE \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_SCAN_CACHE_SIZE +#define MAX_SCAN_BUCKETS \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_SCAN_BUCKETS +#define MAX_AP_CACHE_PER_SCAN \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_AP_CACHE_PER_SCAN +#define MAX_RSSI_SAMPLE_SIZE \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_RSSI_SAMPLE_SIZE +#define MAX_SCAN_RPT_THRHOLD \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_SCAN_REPORTING_THRESHOLD +#define MAX_HOTLIST_BSSIDS \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_HOTLIST_BSSIDS +#define MAX_SIGNIFICANT_WIFI_CHANGE_APS \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_SIGNIFICANT_WIFI_CHANGE_APS +#define MAX_BSSID_HISTORY_ENTRIES \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_BSSID_HISTORY_ENTRIES +#define MAX_HOTLIST_SSIDS \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_HOTLIST_SSIDS +#define MAX_NUM_EPNO_NETS \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_NUM_EPNO_NETS +#define MAX_NUM_EPNO_NETS_BY_SSID \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_NUM_EPNO_NETS_BY_SSID +#define MAX_NUM_WHITELISTED_SSID \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_NUM_WHITELISTED_SSID +#define MAX_NUM_BLACKLISTED_BSSID \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_MAX_NUM_BLACKLISTED_BSSID + +/** + * wlan_hdd_send_ext_scan_capability - send ext scan capability to user space + * @hdd_ctx: Pointer to hdd context + * + * Return: 0 for success, non-zero for failure + */ +static int wlan_hdd_send_ext_scan_capability(hdd_context_t *hdd_ctx) +{ + int ret; + struct sk_buff *skb; + struct ext_scan_capabilities_response *data; + uint32_t nl_buf_len; + + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + data = &(ext_scan_context.capability_response); + + nl_buf_len = NLMSG_HDRLEN; + nl_buf_len += (sizeof(data->requestId) + NLA_HDRLEN) + + (sizeof(data->status) + NLA_HDRLEN) + + (sizeof(data->max_scan_cache_size) + NLA_HDRLEN) + + (sizeof(data->max_scan_buckets) + NLA_HDRLEN) + + (sizeof(data->max_ap_cache_per_scan) + NLA_HDRLEN) + + (sizeof(data->max_rssi_sample_size) + NLA_HDRLEN) + + (sizeof(data->max_scan_reporting_threshold) + NLA_HDRLEN) + + (sizeof(data->max_hotlist_bssids) + NLA_HDRLEN) + + (sizeof(data->max_significant_wifi_change_aps) + NLA_HDRLEN) + + (sizeof(data->max_bssid_history_entries) + NLA_HDRLEN) + + (sizeof(data->max_hotlist_ssids) + NLA_HDRLEN) + + (sizeof(data->max_number_epno_networks) + NLA_HDRLEN) + + (sizeof(data->max_number_epno_networks_by_ssid) + NLA_HDRLEN) + + (sizeof(data->max_number_of_white_listed_ssid) + NLA_HDRLEN) + + (sizeof(data->max_number_of_black_listed_bssid) + NLA_HDRLEN); + + skb = cfg80211_vendor_cmd_alloc_reply_skb(hdd_ctx->wiphy, nl_buf_len); + + if (!skb) { + hdd_err("cfg80211_vendor_cmd_alloc_reply_skb failed"); + return -ENOMEM; + } + + + hdd_notice("Req Id %u", data->requestId); + hdd_notice("Status %u", data->status); + hdd_notice("Scan cache size %u", + data->max_scan_cache_size); + hdd_notice("Scan buckets %u", data->max_scan_buckets); + hdd_notice("Max AP per scan %u", + data->max_ap_cache_per_scan); + hdd_notice("max_rssi_sample_size %u", + data->max_rssi_sample_size); + hdd_notice("max_scan_reporting_threshold %u", + data->max_scan_reporting_threshold); + hdd_notice("max_hotlist_bssids %u", + data->max_hotlist_bssids); + hdd_notice("max_significant_wifi_change_aps %u", + data->max_significant_wifi_change_aps); + hdd_notice("max_bssid_history_entries %u", + data->max_bssid_history_entries); + hdd_notice("max_hotlist_ssids %u", data->max_hotlist_ssids); + hdd_notice("max_number_epno_networks %u", + data->max_number_epno_networks); + hdd_notice("max_number_epno_networks_by_ssid %u", + data->max_number_epno_networks_by_ssid); + hdd_notice("max_number_of_white_listed_ssid %u", + data->max_number_of_white_listed_ssid); + hdd_notice("max_number_of_black_listed_bssid (%u)", + data->max_number_of_black_listed_bssid); + + if (nla_put_u32(skb, PARAM_REQUEST_ID, data->requestId) || + nla_put_u32(skb, PARAM_STATUS, data->status) || + nla_put_u32(skb, MAX_SCAN_CACHE_SIZE, data->max_scan_cache_size) || + nla_put_u32(skb, MAX_SCAN_BUCKETS, data->max_scan_buckets) || + nla_put_u32(skb, MAX_AP_CACHE_PER_SCAN, + data->max_ap_cache_per_scan) || + nla_put_u32(skb, MAX_RSSI_SAMPLE_SIZE, + data->max_rssi_sample_size) || + nla_put_u32(skb, MAX_SCAN_RPT_THRHOLD, + data->max_scan_reporting_threshold) || + nla_put_u32(skb, MAX_HOTLIST_BSSIDS, data->max_hotlist_bssids) || + nla_put_u32(skb, MAX_SIGNIFICANT_WIFI_CHANGE_APS, + data->max_significant_wifi_change_aps) || + nla_put_u32(skb, MAX_BSSID_HISTORY_ENTRIES, + data->max_bssid_history_entries) || + nla_put_u32(skb, MAX_HOTLIST_SSIDS, data->max_hotlist_ssids) || + nla_put_u32(skb, MAX_NUM_EPNO_NETS, + data->max_number_epno_networks) || + nla_put_u32(skb, MAX_NUM_EPNO_NETS_BY_SSID, + data->max_number_epno_networks_by_ssid) || + nla_put_u32(skb, MAX_NUM_WHITELISTED_SSID, + data->max_number_of_white_listed_ssid) || + nla_put_u32(skb, MAX_NUM_BLACKLISTED_BSSID, + data->max_number_of_black_listed_bssid)) { + hdd_err("nla put fail"); + goto nla_put_failure; + } + + cfg80211_vendor_cmd_reply(skb); + return 0; + +nla_put_failure: + kfree_skb(skb); + return -EINVAL; +} +/* + * done with short names for the global vendor params + * used by wlan_hdd_send_ext_scan_capability() + */ +#undef PARAM_REQUEST_ID +#undef PARAM_STATUS +#undef MAX_SCAN_CACHE_SIZE +#undef MAX_SCAN_BUCKETS +#undef MAX_AP_CACHE_PER_SCAN +#undef MAX_RSSI_SAMPLE_SIZE +#undef MAX_SCAN_RPT_THRHOLD +#undef MAX_HOTLIST_BSSIDS +#undef MAX_SIGNIFICANT_WIFI_CHANGE_APS +#undef MAX_BSSID_HISTORY_ENTRIES +#undef MAX_HOTLIST_SSIDS +#undef MAX_NUM_EPNO_NETS +#undef MAX_NUM_EPNO_NETS_BY_SSID +#undef MAX_NUM_WHITELISTED_SSID +#undef MAX_NUM_BLACKLISTED_BSSID + +/** + * __wlan_hdd_cfg80211_extscan_get_capabilities() - get ext scan capabilities + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Data length + * + * Return: none + */ +static int __wlan_hdd_cfg80211_extscan_get_capabilities(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + int ret; + unsigned long rc; + struct hdd_ext_scan_context *context; + tpSirGetExtScanCapabilitiesReqParams pReqMsg = NULL; + struct net_device *dev = wdev->netdev; + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *pHddCtx = wiphy_priv(wiphy); + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX + + 1]; + QDF_STATUS status; + + ENTER_DEV(dev); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + ret = wlan_hdd_validate_context(pHddCtx); + if (0 != ret) + return -EINVAL; + + if (pHddCtx->driver_status == DRIVER_MODULES_CLOSED) { + hdd_err("Driver Modules are closed"); + return -EINVAL; + } + + if (!pHddCtx->config->extscan_enabled) { + hdd_err("extscan not supported"); + return -ENOTSUPP; + } + if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX, + data, data_len, wlan_hdd_extscan_config_policy)) { + hdd_err("Invalid ATTR"); + return -EINVAL; + } + + pReqMsg = qdf_mem_malloc(sizeof(*pReqMsg)); + if (!pReqMsg) { + hdd_err("qdf_mem_malloc failed"); + return -ENOMEM; + } + + /* Parse and fetch request Id */ + if (!tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID]) { + hdd_err("attr request id failed"); + goto fail; + } + + pReqMsg->requestId = + nla_get_u32(tb + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID]); + pReqMsg->sessionId = pAdapter->sessionId; + hdd_notice("Req Id %d Session Id %d", + pReqMsg->requestId, pReqMsg->sessionId); + + context = &ext_scan_context; + spin_lock(&context->context_lock); + context->request_id = pReqMsg->requestId; + INIT_COMPLETION(context->response_event); + spin_unlock(&context->context_lock); + + status = sme_ext_scan_get_capabilities(pHddCtx->hHal, pReqMsg); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("sme_ext_scan_get_capabilities failed(err=%d)", + status); + goto fail; + } + + rc = wait_for_completion_timeout(&context->response_event, + msecs_to_jiffies(WLAN_WAIT_TIME_EXTSCAN)); + if (!rc) { + hdd_err("Target response timed out"); + return -ETIMEDOUT; + } + + ret = wlan_hdd_send_ext_scan_capability(pHddCtx); + if (ret) + hdd_err("Failed to send ext scan capability to user space"); + EXIT(); + return ret; +fail: + qdf_mem_free(pReqMsg); + return -EINVAL; +} + +/** + * wlan_hdd_cfg80211_extscan_get_capabilities() - get ext scan capabilities + * @wiphy: Pointer to wiphy + * @wdev: Pointer to wdev + * @data: Pointer to data + * @data_len: Data length + * + * Return: 0 for success, non-zero for failure + */ +int wlan_hdd_cfg80211_extscan_get_capabilities(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + int ret = 0; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_extscan_get_capabilities(wiphy, wdev, data, + data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +/* + * define short names for the global vendor params + * used by wlan_hdd_cfg80211_extscan_get_cached_results() + */ +#define PARAM_MAX \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX +#define PARAM_REQUEST_ID \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID +#define PARAM_FLUSH \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_GET_CACHED_SCAN_RESULTS_CONFIG_PARAM_FLUSH +/** + * __wlan_hdd_cfg80211_extscan_get_cached_results() - extscan get cached results + * @wiphy: wiphy pointer + * @wdev: pointer to struct wireless_dev + * @data: pointer to incoming NL vendor data + * @data_len: length of @data + * + * This function parses the incoming NL vendor command data attributes and + * invokes the SME Api and blocks on a completion variable. + * Each WMI event with cached scan results data chunk results in + * function call wlan_hdd_cfg80211_extscan_cached_results_ind and each + * data chunk is sent up the layer in cfg80211_vendor_cmd_alloc_reply_skb. + * + * If timeout happens before receiving all of the data, this function sets + * a context variable @ignore_cached_results to %true, all of the next data + * chunks are checked against this variable and dropped. + * + * Return: 0 on success; error number otherwise. + */ +static int __wlan_hdd_cfg80211_extscan_get_cached_results(struct wiphy *wiphy, + struct wireless_dev + *wdev, const void *data, + int data_len) +{ + tpSirExtScanGetCachedResultsReqParams pReqMsg = NULL; + struct net_device *dev = wdev->netdev; + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *pHddCtx = wiphy_priv(wiphy); + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX + + 1]; + struct hdd_ext_scan_context *context; + QDF_STATUS status; + int retval = 0; + unsigned long rc; + + /* ENTER_DEV() intentionally not used in a frequently invoked API */ + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + retval = wlan_hdd_validate_context(pHddCtx); + if (0 != retval) + return -EINVAL; + + if (!pHddCtx->config->extscan_enabled) { + hdd_err("extscan not supported"); + return -ENOTSUPP; + } + if (nla_parse(tb, PARAM_MAX, data, data_len, + wlan_hdd_extscan_config_policy)) { + hdd_err("Invalid ATTR"); + return -EINVAL; + } + + pReqMsg = qdf_mem_malloc(sizeof(*pReqMsg)); + if (!pReqMsg) { + hdd_err("qdf_mem_malloc failed"); + return -ENOMEM; + } + + /* Parse and fetch request Id */ + if (!tb[PARAM_REQUEST_ID]) { + hdd_err("attr request id failed"); + goto fail; + } + + pReqMsg->requestId = nla_get_u32(tb[PARAM_REQUEST_ID]); + pReqMsg->sessionId = pAdapter->sessionId; + + /* Parse and fetch flush parameter */ + if (!tb[PARAM_FLUSH]) { + hdd_err("attr flush failed"); + goto fail; + } + pReqMsg->flush = nla_get_u8(tb[PARAM_FLUSH]); + hdd_notice("Req Id: %u Session Id: %d Flush: %d", + pReqMsg->requestId, pReqMsg->sessionId, pReqMsg->flush); + + context = &ext_scan_context; + spin_lock(&context->context_lock); + context->request_id = pReqMsg->requestId; + context->ignore_cached_results = false; + INIT_COMPLETION(context->response_event); + spin_unlock(&context->context_lock); + + status = sme_get_cached_results(pHddCtx->hHal, pReqMsg); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("sme_get_cached_results failed(err=%d)", status); + goto fail; + } + + rc = wait_for_completion_timeout(&context->response_event, + msecs_to_jiffies(WLAN_WAIT_TIME_EXTSCAN)); + if (!rc) { + hdd_err("Target response timed out"); + retval = -ETIMEDOUT; + spin_lock(&context->context_lock); + context->ignore_cached_results = true; + spin_unlock(&context->context_lock); + } else { + spin_lock(&context->context_lock); + retval = context->response_status; + spin_unlock(&context->context_lock); + } + return retval; + +fail: + qdf_mem_free(pReqMsg); + return -EINVAL; +} +/* + * done with short names for the global vendor params + * used by wlan_hdd_cfg80211_extscan_get_cached_results() + */ +#undef PARAM_MAX +#undef PARAM_REQUEST_ID +#undef PARAM_FLUSH + +/** + * wlan_hdd_cfg80211_extscan_get_cached_results() - extscan get cached results + * @wiphy: wiphy pointer + * @wdev: pointer to struct wireless_dev + * @data: pointer to incoming NL vendor data + * @data_len: length of @data + * + * This function parses the incoming NL vendor command data attributes and + * invokes the SME Api and blocks on a completion variable. + * Each WMI event with cached scan results data chunk results in + * function call wlan_hdd_cfg80211_extscan_cached_results_ind and each + * data chunk is sent up the layer in cfg80211_vendor_cmd_alloc_reply_skb. + * + * If timeout happens before receiving all of the data, this function sets + * a context variable @ignore_cached_results to %true, all of the next data + * chunks are checked against this variable and dropped. + * + * Return: 0 on success; error number otherwise. + */ +int wlan_hdd_cfg80211_extscan_get_cached_results(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + int ret = 0; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_extscan_get_cached_results(wiphy, wdev, data, + data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __wlan_hdd_cfg80211_extscan_set_bssid_hotlist() - set bssid hot list + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Data length + * + * Return: none + */ +static int +__wlan_hdd_cfg80211_extscan_set_bssid_hotlist(struct wiphy *wiphy, + struct wireless_dev + *wdev, const void *data, + int data_len) +{ + tpSirExtScanSetBssidHotListReqParams pReqMsg = NULL; + struct net_device *dev = wdev->netdev; + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *pHddCtx = wiphy_priv(wiphy); + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX + + 1]; + struct nlattr *tb2[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX + + 1]; + struct nlattr *apTh; + struct hdd_ext_scan_context *context; + uint32_t request_id; + QDF_STATUS status; + uint8_t i; + int rem, retval; + unsigned long rc; + + ENTER_DEV(dev); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + retval = wlan_hdd_validate_context(pHddCtx); + if (0 != retval) + return -EINVAL; + + if (!pHddCtx->config->extscan_enabled) { + hdd_err("extscan not supported"); + return -ENOTSUPP; + } + if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX, + data, data_len, wlan_hdd_extscan_config_policy)) { + hdd_err("Invalid ATTR"); + return -EINVAL; + } + + pReqMsg = qdf_mem_malloc(sizeof(*pReqMsg)); + if (!pReqMsg) { + hdd_err("qdf_mem_malloc failed"); + return -ENOMEM; + } + + /* Parse and fetch request Id */ + if (!tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID]) { + hdd_err("attr request id failed"); + goto fail; + } + + pReqMsg->requestId = + nla_get_u32(tb + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID]); + hdd_notice("Req Id %d", pReqMsg->requestId); + + /* Parse and fetch number of APs */ + if (!tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_BSSID_HOTLIST_PARAMS_NUM_AP]) { + hdd_err("attr number of AP failed"); + goto fail; + } + pReqMsg->numAp = + nla_get_u32(tb + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_BSSID_HOTLIST_PARAMS_NUM_AP]); + if (pReqMsg->numAp > WLAN_EXTSCAN_MAX_HOTLIST_APS) { + hdd_err("Number of AP: %u exceeds max: %u", + pReqMsg->numAp, WLAN_EXTSCAN_MAX_HOTLIST_APS); + goto fail; + } + pReqMsg->sessionId = pAdapter->sessionId; + hdd_notice("Number of AP %d Session Id %d", + pReqMsg->numAp, pReqMsg->sessionId); + + /* Parse and fetch lost ap sample size */ + if (!tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_BSSID_HOTLIST_PARAMS_LOST_AP_SAMPLE_SIZE]) { + hdd_err("attr lost ap sample size failed"); + goto fail; + } + + pReqMsg->lost_ap_sample_size = nla_get_u32( + tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_BSSID_HOTLIST_PARAMS_LOST_AP_SAMPLE_SIZE]); + hdd_notice("Lost ap sample size %d", + pReqMsg->lost_ap_sample_size); + + if (!tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM]) { + hdd_err("attr ap threshold failed"); + goto fail; + } + i = 0; + nla_for_each_nested(apTh, + tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM], + rem) { + if (i == pReqMsg->numAp) { + hdd_warn("Ignoring excess AP"); + break; + } + + if (nla_parse + (tb2, QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX, + nla_data(apTh), nla_len(apTh), + wlan_hdd_extscan_config_policy)) { + hdd_err("nla_parse failed"); + goto fail; + } + + /* Parse and fetch MAC address */ + if (!tb2[QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM_BSSID]) { + hdd_err("attr mac address failed"); + goto fail; + } + nla_memcpy(pReqMsg->ap[i].bssid.bytes, + tb2 + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM_BSSID], + QDF_MAC_ADDR_SIZE); + hdd_notice(MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(pReqMsg->ap[i].bssid.bytes)); + + /* Parse and fetch low RSSI */ + if (!tb2 + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM_RSSI_LOW]) { + hdd_err("attr low RSSI failed"); + goto fail; + } + pReqMsg->ap[i].low = + nla_get_s32(tb2 + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM_RSSI_LOW]); + hdd_notice("RSSI low %d", pReqMsg->ap[i].low); + + /* Parse and fetch high RSSI */ + if (!tb2 + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM_RSSI_HIGH]) { + hdd_err("attr high RSSI failed"); + goto fail; + } + pReqMsg->ap[i].high = + nla_get_s32(tb2 + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM_RSSI_HIGH]); + hdd_notice("RSSI High %d", pReqMsg->ap[i].high); + + i++; + } + + if (i < pReqMsg->numAp) { + hdd_warn("Number of AP %u less than expected %u", + i, pReqMsg->numAp); + pReqMsg->numAp = i; + } + + context = &ext_scan_context; + spin_lock(&context->context_lock); + INIT_COMPLETION(context->response_event); + context->request_id = request_id = pReqMsg->requestId; + spin_unlock(&context->context_lock); + + status = sme_set_bss_hotlist(pHddCtx->hHal, pReqMsg); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("sme_set_bss_hotlist failed(err=%d)", status); + goto fail; + } + + /* request was sent -- wait for the response */ + rc = wait_for_completion_timeout + (&context->response_event, + msecs_to_jiffies(WLAN_WAIT_TIME_EXTSCAN)); + + if (!rc) { + hdd_err("sme_set_bss_hotlist timed out"); + retval = -ETIMEDOUT; + } else { + spin_lock(&context->context_lock); + if (context->request_id == request_id) + retval = context->response_status; + else + retval = -EINVAL; + spin_unlock(&context->context_lock); + } + EXIT(); + return retval; + +fail: + qdf_mem_free(pReqMsg); + return -EINVAL; +} + +/** + * wlan_hdd_cfg80211_extscan_set_bssid_hotlist() - set ext scan bssid hotlist + * @wiphy: Pointer to wiphy + * @wdev: Pointer to wdev + * @data: Pointer to data + * @data_len: Data length + * + * Return: 0 for success, non-zero for failure + */ +int wlan_hdd_cfg80211_extscan_set_bssid_hotlist(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + int ret = 0; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_extscan_set_bssid_hotlist(wiphy, wdev, data, + data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + + +/** + * __wlan_hdd_cfg80211_extscan_set_significant_change () - set significant change + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Data length + * + * Return: none + */ +static int +__wlan_hdd_cfg80211_extscan_set_significant_change(struct wiphy *wiphy, + struct wireless_dev + *wdev, const void *data, + int data_len) +{ + tpSirExtScanSetSigChangeReqParams pReqMsg = NULL; + struct net_device *dev = wdev->netdev; + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *pHddCtx = wiphy_priv(wiphy); + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX + + 1]; + struct nlattr *tb2[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX + + 1]; + struct nlattr *apTh; + struct hdd_ext_scan_context *context; + uint32_t request_id; + QDF_STATUS status; + uint8_t i; + int rem, retval; + unsigned long rc; + + ENTER_DEV(dev); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + retval = wlan_hdd_validate_context(pHddCtx); + if (0 != retval) + return -EINVAL; + + if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX, + data, data_len, wlan_hdd_extscan_config_policy)) { + hdd_err("Invalid ATTR"); + return -EINVAL; + } + + pReqMsg = qdf_mem_malloc(sizeof(*pReqMsg)); + if (!pReqMsg) { + hdd_err("qdf_mem_malloc failed"); + return -ENOMEM; + } + + /* Parse and fetch request Id */ + if (!tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID]) { + hdd_err("attr request id failed"); + goto fail; + } + + pReqMsg->requestId = + nla_get_u32(tb + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID]); + hdd_notice("Req Id %d", pReqMsg->requestId); + + /* Parse and fetch RSSI sample size */ + if (!tb + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SIGNIFICANT_CHANGE_PARAMS_RSSI_SAMPLE_SIZE]) { + hdd_err("attr RSSI sample size failed"); + goto fail; + } + pReqMsg->rssiSampleSize = + nla_get_u32(tb + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SIGNIFICANT_CHANGE_PARAMS_RSSI_SAMPLE_SIZE]); + hdd_notice("RSSI sample size %u", pReqMsg->rssiSampleSize); + + /* Parse and fetch lost AP sample size */ + if (!tb + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SIGNIFICANT_CHANGE_PARAMS_LOST_AP_SAMPLE_SIZE]) { + hdd_err("attr lost AP sample size failed"); + goto fail; + } + pReqMsg->lostApSampleSize = + nla_get_u32(tb + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SIGNIFICANT_CHANGE_PARAMS_LOST_AP_SAMPLE_SIZE]); + hdd_notice("Lost AP sample size %u", pReqMsg->lostApSampleSize); + + /* Parse and fetch AP min breacing */ + if (!tb + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SIGNIFICANT_CHANGE_PARAMS_MIN_BREACHING]) { + hdd_err("attr AP min breaching"); + goto fail; + } + pReqMsg->minBreaching = + nla_get_u32(tb + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SIGNIFICANT_CHANGE_PARAMS_MIN_BREACHING]); + hdd_notice("AP min breaching %u", pReqMsg->minBreaching); + + /* Parse and fetch number of APs */ + if (!tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SIGNIFICANT_CHANGE_PARAMS_NUM_AP]) { + hdd_err("attr number of AP failed"); + goto fail; + } + pReqMsg->numAp = + nla_get_u32(tb + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SIGNIFICANT_CHANGE_PARAMS_NUM_AP]); + if (pReqMsg->numAp > WLAN_EXTSCAN_MAX_SIGNIFICANT_CHANGE_APS) { + hdd_err("Number of AP %u exceeds max %u", + pReqMsg->numAp, + WLAN_EXTSCAN_MAX_SIGNIFICANT_CHANGE_APS); + goto fail; + } + + pReqMsg->sessionId = pAdapter->sessionId; + hdd_notice("Number of AP %d Session Id %d", + pReqMsg->numAp, pReqMsg->sessionId); + + if (!tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM]) { + hdd_err("attr ap threshold failed"); + goto fail; + } + i = 0; + nla_for_each_nested(apTh, + tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM], + rem) { + + if (i == pReqMsg->numAp) { + hdd_warn("Ignoring excess AP"); + break; + } + + if (nla_parse + (tb2, QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX, + nla_data(apTh), nla_len(apTh), + wlan_hdd_extscan_config_policy)) { + hdd_err("nla_parse failed"); + goto fail; + } + + /* Parse and fetch MAC address */ + if (!tb2[QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM_BSSID]) { + hdd_err("attr mac address failed"); + goto fail; + } + nla_memcpy(pReqMsg->ap[i].bssid.bytes, + tb2 + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM_BSSID], + QDF_MAC_ADDR_SIZE); + hdd_notice(MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(pReqMsg->ap[i].bssid.bytes)); + + /* Parse and fetch low RSSI */ + if (!tb2 + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM_RSSI_LOW]) { + hdd_err("attr low RSSI failed"); + goto fail; + } + pReqMsg->ap[i].low = + nla_get_s32(tb2 + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM_RSSI_LOW]); + hdd_notice("RSSI low %d", pReqMsg->ap[i].low); + + /* Parse and fetch high RSSI */ + if (!tb2 + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM_RSSI_HIGH]) { + hdd_err("attr high RSSI failed"); + goto fail; + } + pReqMsg->ap[i].high = + nla_get_s32(tb2 + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM_RSSI_HIGH]); + hdd_notice("RSSI High %d", pReqMsg->ap[i].high); + + i++; + } + if (i < pReqMsg->numAp) { + hdd_warn("Number of AP %u less than expected %u", + i, pReqMsg->numAp); + pReqMsg->numAp = i; + } + + context = &ext_scan_context; + spin_lock(&context->context_lock); + INIT_COMPLETION(context->response_event); + context->request_id = request_id = pReqMsg->requestId; + spin_unlock(&context->context_lock); + + status = sme_set_significant_change(pHddCtx->hHal, pReqMsg); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("sme_set_significant_change failed(err=%d)", status); + qdf_mem_free(pReqMsg); + return -EINVAL; + } + + /* request was sent -- wait for the response */ + rc = wait_for_completion_timeout(&context->response_event, + msecs_to_jiffies(WLAN_WAIT_TIME_EXTSCAN)); + + if (!rc) { + hdd_err("sme_set_significant_change timed out"); + retval = -ETIMEDOUT; + } else { + spin_lock(&context->context_lock); + if (context->request_id == request_id) + retval = context->response_status; + else + retval = -EINVAL; + spin_unlock(&context->context_lock); + } + EXIT(); + return retval; + +fail: + qdf_mem_free(pReqMsg); + return -EINVAL; +} + +/** + * wlan_hdd_cfg80211_extscan_set_significant_change() - set significant change + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Data length + * + * Return: 0 on success, negative errno on failure + */ +int wlan_hdd_cfg80211_extscan_set_significant_change(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + int ret = 0; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_extscan_set_significant_change(wiphy, wdev, + data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * hdd_remove_dsrc_channels () - remove dsrc chanels + * @wiphy: Pointer to wireless phy + * @chan_list: channel list + * @num_channels: number of channels + * + * Return: none + */ +static void hdd_remove_dsrc_channels(struct wiphy *wiphy, uint32_t *chan_list, + uint8_t *num_channels) +{ + uint8_t num_chan_temp = 0; + int i; + + for (i = 0; i < *num_channels; i++) { + if (!cds_is_dsrc_channel(chan_list[i])) { + chan_list[num_chan_temp] = chan_list[i]; + num_chan_temp++; + } + } + + *num_channels = num_chan_temp; +} + +/** + * hdd_remove_passive_channels () - remove passive channels + * @wiphy: Pointer to wireless phy + * @chan_list: channel list + * @num_channels: number of channels + * + * Return: none + */ +static void hdd_remove_passive_channels(struct wiphy *wiphy, + uint32_t *chan_list, + uint8_t *num_channels) +{ + uint8_t num_chan_temp = 0; + int i, j, k; + + for (i = 0; i < *num_channels; i++) + for (j = 0; j < NUM_NL80211_BANDS; j++) { + if (wiphy->bands[j] == NULL) + continue; + for (k = 0; k < wiphy->bands[j]->n_channels; k++) { + if ((chan_list[i] == + wiphy->bands[j]->channels[k].center_freq) + && (!(wiphy->bands[j]->channels[k].flags & + IEEE80211_CHAN_PASSIVE_SCAN)) + ) { + chan_list[num_chan_temp] = chan_list[i]; + num_chan_temp++; + } + } + } + + *num_channels = num_chan_temp; +} + +/** + * __wlan_hdd_cfg80211_extscan_get_valid_channels () - get valid channels + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Data length + * + * Return: none + */ +static int +__wlan_hdd_cfg80211_extscan_get_valid_channels(struct wiphy *wiphy, + struct wireless_dev + *wdev, const void *data, + int data_len) +{ + hdd_context_t *pHddCtx = wiphy_priv(wiphy); + struct net_device *dev = wdev->netdev; + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + uint32_t chan_list[WNI_CFG_VALID_CHANNEL_LIST_LEN] = {0}; + uint8_t num_channels = 0, i, buf[256] = {0}; + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX + + 1]; + uint32_t requestId, maxChannels; + tWifiBand wifiBand; + QDF_STATUS status; + struct sk_buff *reply_skb; + int ret, len = 0; + + /* ENTER_DEV() intentionally not used in a frequently invoked API */ + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + ret = wlan_hdd_validate_context(pHddCtx); + if (0 != ret) + return -EINVAL; + + if (!pHddCtx->config->extscan_enabled) { + hdd_err("extscan not supported"); + return -ENOTSUPP; + } + if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX, + data, data_len, wlan_hdd_extscan_config_policy)) { + hdd_err("Invalid ATTR"); + return -EINVAL; + } + + /* Parse and fetch request Id */ + if (!tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID]) { + hdd_err("attr request id failed"); + return -EINVAL; + } + requestId = + nla_get_u32(tb + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID]); + + /* Parse and fetch wifi band */ + if (!tb + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_GET_VALID_CHANNELS_CONFIG_PARAM_WIFI_BAND]) { + hdd_err("attr wifi band failed"); + return -EINVAL; + } + wifiBand = + nla_get_u32(tb + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_GET_VALID_CHANNELS_CONFIG_PARAM_WIFI_BAND]); + + if (!tb + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_GET_VALID_CHANNELS_CONFIG_PARAM_MAX_CHANNELS]) { + hdd_err("attr max channels failed"); + return -EINVAL; + } + maxChannels = + nla_get_u32(tb + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_GET_VALID_CHANNELS_CONFIG_PARAM_MAX_CHANNELS]); + + if (maxChannels > WNI_CFG_VALID_CHANNEL_LIST_LEN) { + hdd_err("Max channels %d exceeded Valid channel list len %d", + maxChannels, WNI_CFG_VALID_CHANNEL_LIST_LEN); + return -EINVAL; + } + + hdd_notice("Req Id: %u Wifi band: %d Max channels: %d", requestId, + wifiBand, maxChannels); + status = sme_get_valid_channels_by_band((tHalHandle) (pHddCtx->hHal), + wifiBand, chan_list, + &num_channels); + if (QDF_STATUS_SUCCESS != status) { + hdd_err("sme_get_valid_channels_by_band failed (err=%d)", + status); + return -EINVAL; + } + + num_channels = QDF_MIN(num_channels, maxChannels); + + hdd_remove_dsrc_channels(wiphy, chan_list, &num_channels); + + if ((QDF_SAP_MODE == pAdapter->device_mode) || + !strncmp(hdd_get_fwpath(), "ap", 2)) + hdd_remove_passive_channels(wiphy, chan_list, + &num_channels); + + hdd_notice("Number of channels: %d", num_channels); + for (i = 0; i < num_channels; i++) + len += scnprintf(buf + len, sizeof(buf) - len, + "%u ", chan_list[i]); + + hdd_notice("Channels: %s", buf); + + reply_skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, sizeof(u32) + + sizeof(u32) * + num_channels + + NLMSG_HDRLEN); + + if (reply_skb) { + if (nla_put_u32(reply_skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_NUM_CHANNELS, + num_channels) || + nla_put(reply_skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CHANNELS, + sizeof(u32) * num_channels, chan_list)) { + hdd_err("nla put fail"); + kfree_skb(reply_skb); + return -EINVAL; + } + ret = cfg80211_vendor_cmd_reply(reply_skb); + return ret; + } + + hdd_err("valid channels: buffer alloc fail"); + return -EINVAL; +} + +/** + * wlan_hdd_cfg80211_extscan_get_valid_channels() - get ext scan valid channels + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Data length + * + * Return: 0 on success, negative errno on failure + */ +int wlan_hdd_cfg80211_extscan_get_valid_channels(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + int ret = 0; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_extscan_get_valid_channels(wiphy, wdev, data, + data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * hdd_extscan_update_dwell_time_limits() - update dwell times + * @req_msg: Pointer to request message + * @bkt_idx: Index of current bucket being processed + * @active_min: minimum active dwell time + * @active_max: maximum active dwell time + * @passive_min: minimum passive dwell time + * @passive_max: maximum passive dwell time + * + * Return: none + */ +static void hdd_extscan_update_dwell_time_limits( + tpSirWifiScanCmdReqParams req_msg, uint32_t bkt_idx, + uint32_t active_min, uint32_t active_max, + uint32_t passive_min, uint32_t passive_max) +{ + /* update per-bucket dwell times */ + if (req_msg->buckets[bkt_idx].min_dwell_time_active > + active_min) { + req_msg->buckets[bkt_idx].min_dwell_time_active = + active_min; + } + if (req_msg->buckets[bkt_idx].max_dwell_time_active < + active_max) { + req_msg->buckets[bkt_idx].max_dwell_time_active = + active_max; + } + if (req_msg->buckets[bkt_idx].min_dwell_time_passive > + passive_min) { + req_msg->buckets[bkt_idx].min_dwell_time_passive = + passive_min; + } + if (req_msg->buckets[bkt_idx].max_dwell_time_passive < + passive_max) { + req_msg->buckets[bkt_idx].max_dwell_time_passive = + passive_max; + } + /* update dwell-time across all buckets */ + if (req_msg->min_dwell_time_active > + req_msg->buckets[bkt_idx].min_dwell_time_active) { + req_msg->min_dwell_time_active = + req_msg->buckets[bkt_idx].min_dwell_time_active; + } + if (req_msg->max_dwell_time_active < + req_msg->buckets[bkt_idx].max_dwell_time_active) { + req_msg->max_dwell_time_active = + req_msg->buckets[bkt_idx].max_dwell_time_active; + } + if (req_msg->min_dwell_time_passive > + req_msg->buckets[bkt_idx].min_dwell_time_passive) { + req_msg->min_dwell_time_passive = + req_msg->buckets[bkt_idx].min_dwell_time_passive; + } + if (req_msg->max_dwell_time_passive > + req_msg->buckets[bkt_idx].max_dwell_time_passive) { + req_msg->max_dwell_time_passive = + req_msg->buckets[bkt_idx].max_dwell_time_passive; + } +} + +/** + * hdd_extscan_channel_max_reached() - channel max reached + * @req: extscan request structure + * @total_channels: total number of channels + * + * Return: true if total channels reached max, false otherwise + */ +static bool hdd_extscan_channel_max_reached(tSirWifiScanCmdReqParams *req, + uint8_t total_channels) +{ + if (total_channels == WLAN_EXTSCAN_MAX_CHANNELS) { + hdd_warn( + "max #of channels %d reached, take only first %d bucket(s)", + total_channels, req->numBuckets); + return true; + } + return false; +} + +/** + * hdd_extscan_start_fill_bucket_channel_spec() - fill bucket channel spec + * @hdd_ctx: HDD global context + * @req_msg: Pointer to request structure + * @tb: pointer to NL attributes + * + * Return: 0 on success; error number otherwise + */ +static int hdd_extscan_start_fill_bucket_channel_spec( + hdd_context_t *hdd_ctx, + tpSirWifiScanCmdReqParams req_msg, + struct nlattr **tb) +{ + struct nlattr *bucket[ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX + 1]; + struct nlattr *channel[ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX + 1]; + struct nlattr *buckets; + struct nlattr *channels; + int rem1, rem2; + QDF_STATUS status; + uint8_t bkt_index, j, num_channels, total_channels = 0; + uint32_t expected_buckets; + uint32_t chan_list[WNI_CFG_VALID_CHANNEL_LIST_LEN] = {0}; + + uint32_t min_dwell_time_active_bucket = + hdd_ctx->config->extscan_active_max_chn_time; + uint32_t max_dwell_time_active_bucket = + hdd_ctx->config->extscan_active_max_chn_time; + uint32_t min_dwell_time_passive_bucket = + hdd_ctx->config->extscan_passive_max_chn_time; + uint32_t max_dwell_time_passive_bucket = + hdd_ctx->config->extscan_passive_max_chn_time; + + req_msg->min_dwell_time_active = + req_msg->max_dwell_time_active = + hdd_ctx->config->extscan_active_max_chn_time; + + req_msg->min_dwell_time_passive = + req_msg->max_dwell_time_passive = + hdd_ctx->config->extscan_passive_max_chn_time; + + expected_buckets = req_msg->numBuckets; + req_msg->numBuckets = 0; + bkt_index = 0; + + nla_for_each_nested(buckets, + tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC], rem1) { + + if (bkt_index >= expected_buckets) { + hdd_warn("ignoring excess buckets"); + break; + } + + if (nla_parse(bucket, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX, + nla_data(buckets), nla_len(buckets), + wlan_hdd_extscan_config_policy)) { + hdd_err("nla_parse failed"); + return -EINVAL; + } + + /* Parse and fetch bucket spec */ + if (!bucket[QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_INDEX]) { + hdd_err("attr bucket index failed"); + return -EINVAL; + } + req_msg->buckets[bkt_index].bucket = nla_get_u8( + bucket[QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_INDEX]); + + /* Parse and fetch wifi band */ + if (!bucket[QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_BAND]) { + hdd_err("attr wifi band failed"); + return -EINVAL; + } + req_msg->buckets[bkt_index].band = nla_get_u8( + bucket[QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_BAND]); + + /* Parse and fetch period */ + if (!bucket[QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_PERIOD]) { + hdd_err("attr period failed"); + return -EINVAL; + } + req_msg->buckets[bkt_index].period = nla_get_u32( + bucket[QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_PERIOD]); + + /* Parse and fetch report events */ + if (!bucket[ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_REPORT_EVENTS]) { + hdd_err("attr report events failed"); + return -EINVAL; + } + req_msg->buckets[bkt_index].reportEvents = nla_get_u8( + bucket[ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_REPORT_EVENTS]); + + /* Parse and fetch max period */ + if (!bucket[QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_MAX_PERIOD]) { + hdd_err("attr max period failed"); + return -EINVAL; + } + req_msg->buckets[bkt_index].max_period = nla_get_u32( + bucket[QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_MAX_PERIOD]); + + /* Parse and fetch base */ + if (!bucket[QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_BASE]) { + hdd_err("attr base failed"); + return -EINVAL; + } + req_msg->buckets[bkt_index].exponent = nla_get_u32( + bucket[QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_BASE]); + + /* Parse and fetch step count */ + if (!bucket[QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_STEP_COUNT]) { + hdd_err("attr step count failed"); + return -EINVAL; + } + req_msg->buckets[bkt_index].step_count = nla_get_u32( + bucket[QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_STEP_COUNT]); + hdd_notice("Bucket spec Index: %d Wifi band: %d period: %d report events: %d max period: %u base: %u Step count: %u", + req_msg->buckets[bkt_index].bucket, + req_msg->buckets[bkt_index].band, + req_msg->buckets[bkt_index].period, + req_msg->buckets[bkt_index].reportEvents, + req_msg->buckets[bkt_index].max_period, + req_msg->buckets[bkt_index].exponent, + req_msg->buckets[bkt_index].step_count); + + /* start with known good values for bucket dwell times */ + req_msg->buckets[bkt_index].min_dwell_time_active = + req_msg->buckets[bkt_index].max_dwell_time_active = + hdd_ctx->config->extscan_active_max_chn_time; + + req_msg->buckets[bkt_index].min_dwell_time_passive = + req_msg->buckets[bkt_index].max_dwell_time_passive = + hdd_ctx->config->extscan_passive_max_chn_time; + + /* Framework shall pass the channel list if the input WiFi band + * is WIFI_BAND_UNSPECIFIED. + * If the input WiFi band is specified (any value other than + * WIFI_BAND_UNSPECIFIED) then driver populates the channel list + */ + if (req_msg->buckets[bkt_index].band != WIFI_BAND_UNSPECIFIED) { + if (hdd_extscan_channel_max_reached(req_msg, + total_channels)) + return 0; + + num_channels = 0; + hdd_notice("WiFi band is specified, driver to fill channel list"); + status = sme_get_valid_channels_by_band(hdd_ctx->hHal, + req_msg->buckets[bkt_index].band, + chan_list, &num_channels); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("sme_GetValidChannelsByBand failed (err=%d)", + status); + return -EINVAL; + } + hdd_notice("before trimming, num_channels: %d", + num_channels); + + req_msg->buckets[bkt_index].numChannels = + QDF_MIN(num_channels, + (WLAN_EXTSCAN_MAX_CHANNELS - + total_channels)); + hdd_info("Adj Num channels/bucket: %d total_channels: %d", + req_msg->buckets[bkt_index].numChannels, + total_channels); + total_channels += + req_msg->buckets[bkt_index].numChannels; + + for (j = 0; j < req_msg->buckets[bkt_index].numChannels; + j++) { + req_msg->buckets[bkt_index].channels[j].channel = + chan_list[j]; + req_msg->buckets[bkt_index].channels[j]. + chnlClass = 0; + if (CDS_IS_PASSIVE_OR_DISABLE_CH( + cds_freq_to_chan(chan_list[j]))) { + req_msg->buckets[bkt_index].channels[j]. + passive = 1; + req_msg->buckets[bkt_index].channels[j]. + dwellTimeMs = + hdd_ctx->config-> + extscan_passive_max_chn_time; + /* reconfigure per-bucket dwell time */ + if (min_dwell_time_passive_bucket > + req_msg->buckets[bkt_index].channels[j].dwellTimeMs) { + min_dwell_time_passive_bucket = + req_msg->buckets[bkt_index].channels[j].dwellTimeMs; + } + if (max_dwell_time_passive_bucket < + req_msg->buckets[bkt_index].channels[j].dwellTimeMs) { + max_dwell_time_passive_bucket = + req_msg->buckets[bkt_index].channels[j].dwellTimeMs; + } + + } else { + req_msg->buckets[bkt_index].channels[j]. + passive = 0; + req_msg->buckets[bkt_index].channels[j]. + dwellTimeMs = + hdd_ctx->config->extscan_active_max_chn_time; + /* reconfigure per-bucket dwell times */ + if (min_dwell_time_active_bucket > + req_msg->buckets[bkt_index].channels[j].dwellTimeMs) { + min_dwell_time_active_bucket = + req_msg->buckets[bkt_index].channels[j].dwellTimeMs; + } + if (max_dwell_time_active_bucket < + req_msg->buckets[bkt_index].channels[j].dwellTimeMs) { + max_dwell_time_active_bucket = + req_msg->buckets[bkt_index].channels[j].dwellTimeMs; + } + + } + + hdd_notice("Channel: %u Passive: %u Dwell time: %u ms Class: %u", + req_msg->buckets[bkt_index].channels[j].channel, + req_msg->buckets[bkt_index].channels[j].passive, + req_msg->buckets[bkt_index].channels[j].dwellTimeMs, + req_msg->buckets[bkt_index].channels[j].chnlClass); + } + + hdd_extscan_update_dwell_time_limits( + req_msg, bkt_index, + min_dwell_time_active_bucket, + max_dwell_time_active_bucket, + min_dwell_time_passive_bucket, + max_dwell_time_passive_bucket); + + hdd_notice("bkt_index:%d actv_min:%d actv_max:%d pass_min:%d pass_max:%d", + bkt_index, + req_msg->buckets[bkt_index].min_dwell_time_active, + req_msg->buckets[bkt_index].max_dwell_time_active, + req_msg->buckets[bkt_index].min_dwell_time_passive, + req_msg->buckets[bkt_index].max_dwell_time_passive); + + bkt_index++; + req_msg->numBuckets++; + continue; + } + + /* Parse and fetch number of channels */ + if (!bucket[ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_NUM_CHANNEL_SPECS]) { + hdd_err("attr num channels failed"); + return -EINVAL; + } + req_msg->buckets[bkt_index].numChannels = + nla_get_u32(bucket[ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_NUM_CHANNEL_SPECS]); + hdd_info("before trimming: num channels %d", + req_msg->buckets[bkt_index].numChannels); + + req_msg->buckets[bkt_index].numChannels = + QDF_MIN(req_msg->buckets[bkt_index].numChannels, + (WLAN_EXTSCAN_MAX_CHANNELS - total_channels)); + hdd_info("Num channels/bucket: %d total_channels: %d", + req_msg->buckets[bkt_index].numChannels, + total_channels); + if (hdd_extscan_channel_max_reached(req_msg, total_channels)) + return 0; + + if (!bucket[QCA_WLAN_VENDOR_ATTR_EXTSCAN_CHANNEL_SPEC]) { + hdd_err("attr channel spec failed"); + return -EINVAL; + } + + j = 0; + nla_for_each_nested(channels, + bucket[QCA_WLAN_VENDOR_ATTR_EXTSCAN_CHANNEL_SPEC], rem2) { + if ((j >= req_msg->buckets[bkt_index].numChannels) || + hdd_extscan_channel_max_reached(req_msg, + total_channels)) + break; + + if (nla_parse(channel, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX, + nla_data(channels), nla_len(channels), + wlan_hdd_extscan_config_policy)) { + hdd_err("nla_parse failed"); + return -EINVAL; + } + + /* Parse and fetch channel */ + if (!channel[ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_CHANNEL_SPEC_CHANNEL]) { + hdd_err("attr channel failed"); + return -EINVAL; + } + req_msg->buckets[bkt_index].channels[j].channel = + nla_get_u32(channel[ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_CHANNEL_SPEC_CHANNEL]); + hdd_notice("channel %u", + req_msg->buckets[bkt_index].channels[j].channel); + + /* Parse and fetch dwell time */ + if (!channel[ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_CHANNEL_SPEC_DWELL_TIME]) { + hdd_err("attr dwelltime failed"); + return -EINVAL; + } + req_msg->buckets[bkt_index].channels[j].dwellTimeMs = + nla_get_u32(channel[ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_CHANNEL_SPEC_DWELL_TIME]); + + /* Override dwell time if required */ + if (req_msg->buckets[bkt_index].channels[j].dwellTimeMs < + hdd_ctx->config->extscan_active_min_chn_time || + req_msg->buckets[bkt_index].channels[j].dwellTimeMs > + hdd_ctx->config->extscan_active_max_chn_time) { + hdd_notice("WiFi band is unspecified, dwellTime:%d", + req_msg->buckets[bkt_index].channels[j].dwellTimeMs); + + if (CDS_IS_PASSIVE_OR_DISABLE_CH( + cds_freq_to_chan( + req_msg->buckets[bkt_index].channels[j].channel))) { + req_msg->buckets[bkt_index].channels[j].dwellTimeMs = + hdd_ctx->config->extscan_passive_max_chn_time; + } else { + req_msg->buckets[bkt_index].channels[j].dwellTimeMs = + hdd_ctx->config->extscan_active_max_chn_time; + } + } + + hdd_notice("New Dwell time %u ms", + req_msg->buckets[bkt_index].channels[j].dwellTimeMs); + + if (CDS_IS_PASSIVE_OR_DISABLE_CH( + cds_freq_to_chan( + req_msg->buckets[bkt_index].channels[j].channel))) { + if (min_dwell_time_passive_bucket > + req_msg->buckets[bkt_index].channels[j].dwellTimeMs) { + min_dwell_time_passive_bucket = + req_msg->buckets[bkt_index].channels[j].dwellTimeMs; + } + if (max_dwell_time_passive_bucket < + req_msg->buckets[bkt_index].channels[j].dwellTimeMs) { + max_dwell_time_passive_bucket = + req_msg->buckets[bkt_index].channels[j].dwellTimeMs; + } + } else { + if (min_dwell_time_active_bucket > + req_msg->buckets[bkt_index].channels[j].dwellTimeMs) { + min_dwell_time_active_bucket = + req_msg->buckets[bkt_index].channels[j].dwellTimeMs; + } + if (max_dwell_time_active_bucket < + req_msg->buckets[bkt_index].channels[j].dwellTimeMs) { + max_dwell_time_active_bucket = + req_msg->buckets[bkt_index].channels[j].dwellTimeMs; + } + } + + /* Parse and fetch channel spec passive */ + if (!channel[ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_CHANNEL_SPEC_PASSIVE]) { + hdd_err("attr channel spec passive failed"); + return -EINVAL; + } + req_msg->buckets[bkt_index].channels[j].passive = + nla_get_u8(channel[ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_CHANNEL_SPEC_PASSIVE]); + hdd_notice("Chnl spec passive %u", + req_msg->buckets[bkt_index].channels[j].passive); + /* Override scan type if required */ + if (CDS_IS_PASSIVE_OR_DISABLE_CH( + cds_freq_to_chan( + req_msg->buckets[bkt_index].channels[j].channel))) { + req_msg->buckets[bkt_index].channels[j].passive = true; + } else { + req_msg->buckets[bkt_index].channels[j].passive = false; + } + j++; + total_channels++; + } + + hdd_extscan_update_dwell_time_limits( + req_msg, bkt_index, + min_dwell_time_active_bucket, + max_dwell_time_active_bucket, + min_dwell_time_passive_bucket, + max_dwell_time_passive_bucket); + + hdd_notice("bktIndex:%d actv_min:%d actv_max:%d pass_min:%d pass_max:%d", + bkt_index, + req_msg->buckets[bkt_index].min_dwell_time_active, + req_msg->buckets[bkt_index].max_dwell_time_active, + req_msg->buckets[bkt_index].min_dwell_time_passive, + req_msg->buckets[bkt_index].max_dwell_time_passive); + + bkt_index++; + req_msg->numBuckets++; + } + + hdd_notice("Global: actv_min:%d actv_max:%d pass_min:%d pass_max:%d", + req_msg->min_dwell_time_active, + req_msg->max_dwell_time_active, + req_msg->min_dwell_time_passive, + req_msg->max_dwell_time_passive); + + return 0; +} + +/* + * hdd_extscan_map_usr_drv_config_flags() - map userspace to driver config flags + * @config_flags - [input] configuration flags. + * + * This function maps user space received configuration flags to + * driver representation. + * + * Return: configuration flags + */ +static uint32_t hdd_extscan_map_usr_drv_config_flags(uint32_t config_flags) +{ + uint32_t configuration_flags = 0; + + if (config_flags & EXTSCAN_LP_EXTENDED_BATCHING) + configuration_flags |= EXTSCAN_LP_EXTENDED_BATCHING; + + return configuration_flags; +} + +/* + * define short names for the global vendor params + * used by __wlan_hdd_cfg80211_extscan_start() + */ +#define PARAM_MAX \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX +#define PARAM_REQUEST_ID \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID +#define PARAM_BASE_PERIOD \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_SCAN_CMD_PARAMS_BASE_PERIOD +#define PARAM_MAX_AP_PER_SCAN \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_SCAN_CMD_PARAMS_MAX_AP_PER_SCAN +#define PARAM_RPT_THRHLD_PERCENT \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_SCAN_CMD_PARAMS_REPORT_THRESHOLD_PERCENT +#define PARAM_RPT_THRHLD_NUM_SCANS \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_SCAN_CMD_PARAMS_REPORT_THRESHOLD_NUM_SCANS +#define PARAM_NUM_BUCKETS \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_SCAN_CMD_PARAMS_NUM_BUCKETS +#define PARAM_CONFIG_FLAGS \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_CONFIGURATION_FLAGS + +/** + * __wlan_hdd_cfg80211_extscan_start() - ext scan start + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Length of @data + * + * Return: 0 on success; error number otherwise + */ +static int +__wlan_hdd_cfg80211_extscan_start(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + tpSirWifiScanCmdReqParams pReqMsg = NULL; + struct net_device *dev = wdev->netdev; + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *pHddCtx = wiphy_priv(wiphy); + struct nlattr *tb[PARAM_MAX + 1]; + struct hdd_ext_scan_context *context; + uint32_t request_id, num_buckets; + QDF_STATUS status; + int retval; + unsigned long rc; + + ENTER_DEV(dev); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + retval = wlan_hdd_validate_context(pHddCtx); + if (0 != retval) + return -EINVAL; + + if (!pHddCtx->config->extscan_enabled) { + hdd_err("extscan not supported"); + return -ENOTSUPP; + } + if (nla_parse(tb, PARAM_MAX, data, data_len, + wlan_hdd_extscan_config_policy)) { + hdd_err("Invalid ATTR"); + return -EINVAL; + } + + pReqMsg = qdf_mem_malloc(sizeof(*pReqMsg)); + if (!pReqMsg) { + hdd_err("memory allocation failed"); + return -ENOMEM; + } + + /* Parse and fetch request Id */ + if (!tb[PARAM_REQUEST_ID]) { + hdd_err("attr request id failed"); + goto fail; + } + + pReqMsg->requestId = nla_get_u32(tb[PARAM_REQUEST_ID]); + pReqMsg->sessionId = pAdapter->sessionId; + + /* Parse and fetch base period */ + if (!tb[PARAM_BASE_PERIOD]) { + hdd_err("attr base period failed"); + goto fail; + } + pReqMsg->basePeriod = nla_get_u32(tb[PARAM_BASE_PERIOD]); + + /* Parse and fetch max AP per scan */ + if (!tb[PARAM_MAX_AP_PER_SCAN]) { + hdd_err("attr max_ap_per_scan failed"); + goto fail; + } + pReqMsg->maxAPperScan = nla_get_u32(tb[PARAM_MAX_AP_PER_SCAN]); + + /* Parse and fetch report threshold percent */ + if (!tb[PARAM_RPT_THRHLD_PERCENT]) { + hdd_err("attr report_threshold percent failed"); + goto fail; + } + pReqMsg->report_threshold_percent = nla_get_u8(tb[PARAM_RPT_THRHLD_PERCENT]); + + /* Parse and fetch report threshold num scans */ + if (!tb[PARAM_RPT_THRHLD_NUM_SCANS]) { + hdd_err("attr report_threshold num scans failed"); + goto fail; + } + pReqMsg->report_threshold_num_scans = nla_get_u8(tb[PARAM_RPT_THRHLD_NUM_SCANS]); + hdd_notice("Req Id: %d Session Id: %d Base Period: %d Max AP per Scan: %d Report Threshold percent: %d Report Threshold num scans: %d", + pReqMsg->requestId, pReqMsg->sessionId, + pReqMsg->basePeriod, pReqMsg->maxAPperScan, + pReqMsg->report_threshold_percent, + pReqMsg->report_threshold_num_scans); + + /* Parse and fetch number of buckets */ + if (!tb[PARAM_NUM_BUCKETS]) { + hdd_err("attr number of buckets failed"); + goto fail; + } + num_buckets = nla_get_u8(tb[PARAM_NUM_BUCKETS]); + if (num_buckets > WLAN_EXTSCAN_MAX_BUCKETS) { + hdd_warn("Exceeded MAX number of buckets: %d", + WLAN_EXTSCAN_MAX_BUCKETS); + num_buckets = WLAN_EXTSCAN_MAX_BUCKETS; + } + hdd_info("Input: Number of Buckets %d", num_buckets); + pReqMsg->numBuckets = num_buckets; + + /* This is optional attribute, if not present set it to 0 */ + if (!tb[PARAM_CONFIG_FLAGS]) + pReqMsg->configuration_flags = 0; + else + pReqMsg->configuration_flags = + hdd_extscan_map_usr_drv_config_flags( + nla_get_u32(tb[PARAM_CONFIG_FLAGS])); + + pReqMsg->extscan_adaptive_dwell_mode = + pHddCtx->config->extscan_adaptive_dwell_mode; + + hdd_notice("Configuration flags: %u", + pReqMsg->configuration_flags); + + if (!tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC]) { + hdd_err("attr bucket spec failed"); + goto fail; + } + + if (hdd_extscan_start_fill_bucket_channel_spec(pHddCtx, pReqMsg, tb)) + goto fail; + + context = &ext_scan_context; + spin_lock(&context->context_lock); + INIT_COMPLETION(context->response_event); + context->request_id = request_id = pReqMsg->requestId; + context->buckets_scanned = 0; + spin_unlock(&context->context_lock); + + status = sme_ext_scan_start(pHddCtx->hHal, pReqMsg); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("sme_ext_scan_start failed(err=%d)", status); + goto fail; + } + + pHddCtx->ext_scan_start_since_boot = qdf_get_monotonic_boottime(); + hdd_notice("Timestamp since boot: %llu", + pHddCtx->ext_scan_start_since_boot); + + /* request was sent -- wait for the response */ + rc = wait_for_completion_timeout(&context->response_event, + msecs_to_jiffies(WLAN_WAIT_TIME_EXTSCAN)); + + if (!rc) { + hdd_err("sme_ext_scan_start timed out"); + retval = -ETIMEDOUT; + } else { + spin_lock(&context->context_lock); + if (context->request_id == request_id) + retval = context->response_status; + else + retval = -EINVAL; + spin_unlock(&context->context_lock); + } + EXIT(); + return retval; + +fail: + qdf_mem_free(pReqMsg); + return -EINVAL; +} +/* + * done with short names for the global vendor params + * used by __wlan_hdd_cfg80211_extscan_start() + */ +#undef PARAM_MAX +#undef PARAM_REQUEST_ID +#undef PARAM_BASE_PERIOD +#undef PARAMS_MAX_AP_PER_SCAN +#undef PARAMS_RPT_THRHLD_PERCENT +#undef PARAMS_RPT_THRHLD_NUM_SCANS +#undef PARAMS_NUM_BUCKETS +#undef PARAM_CONFIG_FLAGS + +/** + * wlan_hdd_cfg80211_extscan_start() - start extscan + * @wiphy: Pointer to wireless phy. + * @wdev: Pointer to wireless device. + * @data: Pointer to input data. + * @data_len: Length of @data. + * + * Return: 0 on success, negative errno on failure + */ +int wlan_hdd_cfg80211_extscan_start(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + int ret = 0; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_extscan_start(wiphy, wdev, data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + + +/* + * define short names for the global vendor params + * used by __wlan_hdd_cfg80211_extscan_stop() + */ +#define PARAM_MAX \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX +#define PARAM_REQUEST_ID \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID + +/** + * __wlan_hdd_cfg80211_extscan_stop() - ext scan stop + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Data length + * + * Return: none + */ +static int +__wlan_hdd_cfg80211_extscan_stop(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + tpSirExtScanStopReqParams pReqMsg = NULL; + struct net_device *dev = wdev->netdev; + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *pHddCtx = wiphy_priv(wiphy); + struct nlattr *tb[PARAM_MAX + 1]; + struct hdd_ext_scan_context *context; + QDF_STATUS status; + uint32_t request_id; + int retval; + unsigned long rc; + + ENTER_DEV(dev); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + retval = wlan_hdd_validate_context(pHddCtx); + if (0 != retval) + return -EINVAL; + + if (!pHddCtx->config->extscan_enabled) { + hdd_err("extscan not supported"); + return -ENOTSUPP; + } + if (nla_parse(tb, PARAM_MAX, data, data_len, + wlan_hdd_extscan_config_policy)) { + hdd_err("Invalid ATTR"); + return -EINVAL; + } + + pReqMsg = qdf_mem_malloc(sizeof(*pReqMsg)); + if (!pReqMsg) { + hdd_err("qdf_mem_malloc failed"); + return -ENOMEM; + } + + /* Parse and fetch request Id */ + if (!tb[PARAM_REQUEST_ID]) { + hdd_err("attr request id failed"); + goto fail; + } + + pReqMsg->requestId = nla_get_u32(tb[PARAM_REQUEST_ID]); + pReqMsg->sessionId = pAdapter->sessionId; + hdd_notice("Req Id %d Session Id %d", + pReqMsg->requestId, pReqMsg->sessionId); + + context = &ext_scan_context; + spin_lock(&context->context_lock); + INIT_COMPLETION(context->response_event); + context->request_id = request_id = pReqMsg->requestId; + spin_unlock(&context->context_lock); + + status = sme_ext_scan_stop(pHddCtx->hHal, pReqMsg); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("sme_ext_scan_stop failed(err=%d)", status); + goto fail; + } + + /* request was sent -- wait for the response */ + rc = wait_for_completion_timeout(&context->response_event, + msecs_to_jiffies(WLAN_WAIT_TIME_EXTSCAN)); + + if (!rc) { + hdd_err("sme_ext_scan_stop timed out"); + retval = -ETIMEDOUT; + } else { + spin_lock(&context->context_lock); + if (context->request_id == request_id) + retval = context->response_status; + else + retval = -EINVAL; + spin_unlock(&context->context_lock); + } + EXIT(); + return retval; + +fail: + qdf_mem_free(pReqMsg); + return -EINVAL; +} +/* + * done with short names for the global vendor params + * used by wlan_hdd_cfg80211_extscan_stop() + */ +#undef PARAM_MAX +#undef PARAM_REQUEST_ID + + +/** + * wlan_hdd_cfg80211_extscan_stop() - stop extscan + * @wiphy: Pointer to wireless phy. + * @wdev: Pointer to wireless device. + * @data: Pointer to input data. + * @data_len: Length of @data. + * + * Return: 0 on success, negative errno on failure + */ +int wlan_hdd_cfg80211_extscan_stop(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + int ret = 0; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_extscan_stop(wiphy, wdev, data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + + +/** + * __wlan_hdd_cfg80211_extscan_reset_bssid_hotlist() - reset bssid hotlist + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Data length + * + * Return: none + */ +static int +__wlan_hdd_cfg80211_extscan_reset_bssid_hotlist(struct wiphy *wiphy, + struct wireless_dev + *wdev, const void *data, + int data_len) +{ + tpSirExtScanResetBssidHotlistReqParams pReqMsg = NULL; + struct net_device *dev = wdev->netdev; + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *pHddCtx = wiphy_priv(wiphy); + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX + + 1]; + struct hdd_ext_scan_context *context; + uint32_t request_id; + QDF_STATUS status; + int retval; + unsigned long rc; + + ENTER_DEV(dev); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + retval = wlan_hdd_validate_context(pHddCtx); + if (0 != retval) + return -EINVAL; + + if (!pHddCtx->config->extscan_enabled) { + hdd_err("extscan not supported"); + return -ENOTSUPP; + } + if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX, + data, data_len, wlan_hdd_extscan_config_policy)) { + hdd_err("Invalid ATTR"); + return -EINVAL; + } + + pReqMsg = qdf_mem_malloc(sizeof(*pReqMsg)); + if (!pReqMsg) { + hdd_err("qdf_mem_malloc failed"); + return -ENOMEM; + } + + /* Parse and fetch request Id */ + if (!tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID]) { + hdd_err("attr request id failed"); + goto fail; + } + + pReqMsg->requestId = + nla_get_u32(tb + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID]); + pReqMsg->sessionId = pAdapter->sessionId; + hdd_notice("Req Id %d Session Id %d", + pReqMsg->requestId, pReqMsg->sessionId); + + context = &ext_scan_context; + spin_lock(&context->context_lock); + INIT_COMPLETION(context->response_event); + context->request_id = request_id = pReqMsg->requestId; + spin_unlock(&context->context_lock); + + status = sme_reset_bss_hotlist(pHddCtx->hHal, pReqMsg); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("sme_reset_bss_hotlist failed(err=%d)", status); + goto fail; + } + + /* request was sent -- wait for the response */ + rc = wait_for_completion_timeout + (&context->response_event, + msecs_to_jiffies(WLAN_WAIT_TIME_EXTSCAN)); + if (!rc) { + hdd_err("sme_reset_bss_hotlist timed out"); + retval = -ETIMEDOUT; + } else { + spin_lock(&context->context_lock); + if (context->request_id == request_id) + retval = context->response_status; + else + retval = -EINVAL; + spin_unlock(&context->context_lock); + } + EXIT(); + return retval; + +fail: + qdf_mem_free(pReqMsg); + return -EINVAL; +} + +/** + * wlan_hdd_cfg80211_extscan_reset_bssid_hotlist() - reset bssid hot list + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Data length + * + * Return: 0 on success, negative errno on failure + */ +int wlan_hdd_cfg80211_extscan_reset_bssid_hotlist(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + int ret = 0; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_extscan_reset_bssid_hotlist(wiphy, wdev, + data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __wlan_hdd_cfg80211_extscan_reset_significant_change() - + * reset significant change + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Data length + * + * Return: none + */ +static int +__wlan_hdd_cfg80211_extscan_reset_significant_change(struct wiphy + *wiphy, + struct + wireless_dev + *wdev, const void *data, + int data_len) +{ + tpSirExtScanResetSignificantChangeReqParams pReqMsg = NULL; + struct net_device *dev = wdev->netdev; + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *pHddCtx = wiphy_priv(wiphy); + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX + + 1]; + struct hdd_ext_scan_context *context; + uint32_t request_id; + QDF_STATUS status; + int retval; + unsigned long rc; + + ENTER_DEV(dev); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + retval = wlan_hdd_validate_context(pHddCtx); + if (0 != retval) + return -EINVAL; + + if (!pHddCtx->config->extscan_enabled) { + hdd_err("extscan not supported"); + return -ENOTSUPP; + } + if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX, + data, data_len, wlan_hdd_extscan_config_policy)) { + hdd_err("Invalid ATTR"); + return -EINVAL; + } + + pReqMsg = qdf_mem_malloc(sizeof(*pReqMsg)); + if (!pReqMsg) { + hdd_err("qdf_mem_malloc failed"); + return -ENOMEM; + } + + /* Parse and fetch request Id */ + if (!tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID]) { + hdd_err("attr request id failed"); + goto fail; + } + + pReqMsg->requestId = + nla_get_u32(tb + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID]); + pReqMsg->sessionId = pAdapter->sessionId; + hdd_notice("Req Id %d Session Id %d", + pReqMsg->requestId, pReqMsg->sessionId); + + context = &ext_scan_context; + spin_lock(&context->context_lock); + INIT_COMPLETION(context->response_event); + context->request_id = request_id = pReqMsg->requestId; + spin_unlock(&context->context_lock); + + status = sme_reset_significant_change(pHddCtx->hHal, pReqMsg); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("sme_reset_significant_change failed(err=%d)", + status); + qdf_mem_free(pReqMsg); + return -EINVAL; + } + + /* request was sent -- wait for the response */ + rc = wait_for_completion_timeout(&context->response_event, + msecs_to_jiffies(WLAN_WAIT_TIME_EXTSCAN)); + + if (!rc) { + hdd_err("sme_ResetSignificantChange timed out"); + retval = -ETIMEDOUT; + } else { + spin_lock(&context->context_lock); + if (context->request_id == request_id) + retval = context->response_status; + else + retval = -EINVAL; + spin_unlock(&context->context_lock); + } + EXIT(); + return retval; + +fail: + qdf_mem_free(pReqMsg); + return -EINVAL; +} + +/** + * wlan_hdd_cfg80211_extscan_reset_significant_change() - reset significant + * change + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Data length + * + * Return: 0 on success, negative errno on failure + */ +int wlan_hdd_cfg80211_extscan_reset_significant_change(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + int ret = 0; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_extscan_reset_significant_change(wiphy, wdev, + data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + + +/** + * hdd_extscan_epno_fill_network_list() - epno fill network list + * @hddctx: HDD context + * @req_msg: request message + * @tb: vendor attribute table + * + * This function reads the network block NL vendor attributes from %tb and + * fill in the epno request message. + * + * Return: 0 on success, error number otherwise + */ +static int hdd_extscan_epno_fill_network_list( + hdd_context_t *hddctx, + struct wifi_epno_params *req_msg, + struct nlattr **tb) +{ + struct nlattr *network[QCA_WLAN_VENDOR_ATTR_PNO_MAX + 1]; + struct nlattr *networks; + int rem1, ssid_len; + uint8_t index, *ssid; + uint32_t expected_networks; + + expected_networks = req_msg->num_networks; + index = 0; + + if (!tb[QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORKS_LIST]) { + hdd_err("attr networks list failed"); + return -EINVAL; + } + nla_for_each_nested(networks, + tb[QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORKS_LIST], + rem1) { + + if (index == expected_networks) { + hdd_warn("ignoring excess networks"); + break; + } + + if (nla_parse(network, QCA_WLAN_VENDOR_ATTR_PNO_MAX, + nla_data(networks), nla_len(networks), + wlan_hdd_pno_config_policy)) { + hdd_err("nla_parse failed"); + return -EINVAL; + } + + /* Parse and fetch ssid */ + if (!network[QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORK_SSID]) { + hdd_err("attr network ssid failed"); + return -EINVAL; + } + ssid_len = nla_len( + network[QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORK_SSID]); + + /* nla_parse will detect overflow but not underflow */ + if (0 == ssid_len) { + hdd_err("zero ssid length"); + return -EINVAL; + } + + /* Decrement by 1, don't count null character */ + ssid_len--; + + req_msg->networks[index].ssid.length = ssid_len; + hdd_notice("network ssid length %d", ssid_len); + ssid = nla_data(network[QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORK_SSID]); + qdf_mem_copy(req_msg->networks[index].ssid.ssId, + ssid, ssid_len); + hdd_notice("Ssid (%.*s)", + req_msg->networks[index].ssid.length, + req_msg->networks[index].ssid.ssId); + + /* Parse and fetch epno flags */ + if (!network[QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORK_FLAGS]) { + hdd_err("attr epno flags failed"); + return -EINVAL; + } + req_msg->networks[index].flags = nla_get_u8( + network[QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORK_FLAGS]); + hdd_notice("flags %u", req_msg->networks[index].flags); + + /* Parse and fetch auth bit */ + if (!network[QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORK_AUTH_BIT]) { + hdd_err("attr auth bit failed"); + return -EINVAL; + } + req_msg->networks[index].auth_bit_field = nla_get_u8( + network[QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORK_AUTH_BIT]); + hdd_notice("auth bit %u", + req_msg->networks[index].auth_bit_field); + + index++; + } + req_msg->num_networks = index; + return 0; +} + +/** + * __wlan_hdd_cfg80211_set_epno_list() - epno set network list + * @wiphy: wiphy + * @wdev: pointer to wireless dev + * @data: data pointer + * @data_len: data length + * + * This function reads the NL vendor attributes from %tb and + * fill in the epno request message. + * + * Return: 0 on success, error number otherwise + */ +static int __wlan_hdd_cfg80211_set_epno_list(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + struct wifi_epno_params *req_msg = NULL; + struct net_device *dev = wdev->netdev; + hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *hdd_ctx = wiphy_priv(wiphy); + struct nlattr *tb[ + QCA_WLAN_VENDOR_ATTR_PNO_MAX + 1]; + QDF_STATUS status; + uint32_t num_networks, len; + int ret_val; + + ENTER_DEV(dev); + + ret_val = wlan_hdd_validate_context(hdd_ctx); + if (ret_val) + return ret_val; + + if (!hdd_ctx->config->extscan_enabled) { + hdd_err("extscan not supported"); + return -ENOTSUPP; + } + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_PNO_MAX, + data, data_len, + wlan_hdd_pno_config_policy)) { + hdd_err("Invalid ATTR"); + return -EINVAL; + } + + /* Parse and fetch number of networks */ + if (!tb[QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_NUM_NETWORKS]) { + hdd_err("attr num networks failed"); + return -EINVAL; + } + + /* + * num_networks is also used as EPNO SET/RESET request. + * if num_networks is zero then it is treated as RESET. + */ + num_networks = nla_get_u32( + tb[QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_NUM_NETWORKS]); + + if (num_networks > MAX_EPNO_NETWORKS) { + hdd_notice("num of nw: %d exceeded max: %d, resetting to: %d", + num_networks, MAX_EPNO_NETWORKS, MAX_EPNO_NETWORKS); + num_networks = MAX_EPNO_NETWORKS; + } + + hdd_notice("num networks %u", num_networks); + len = sizeof(*req_msg) + + (num_networks * sizeof(struct wifi_epno_network)); + + req_msg = qdf_mem_malloc(len); + if (!req_msg) { + hdd_err("qdf_mem_malloc failed"); + return -ENOMEM; + } + req_msg->num_networks = num_networks; + + /* Parse and fetch request Id */ + if (!tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID]) { + hdd_err("attr request id failed"); + goto fail; + } + req_msg->request_id = nla_get_u32( + tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID]); + hdd_notice("Req Id %u", req_msg->request_id); + + req_msg->session_id = adapter->sessionId; + hdd_notice("Session Id %d", req_msg->session_id); + + if (num_networks) { + + /* Parse and fetch min_5ghz_rssi */ + if (!tb[QCA_WLAN_VENDOR_ATTR_EPNO_MIN5GHZ_RSSI]) { + hdd_err("min_5ghz_rssi id failed"); + goto fail; + } + req_msg->min_5ghz_rssi = nla_get_u32( + tb[QCA_WLAN_VENDOR_ATTR_EPNO_MIN5GHZ_RSSI]); + + /* Parse and fetch min_24ghz_rssi */ + if (!tb[QCA_WLAN_VENDOR_ATTR_EPNO_MIN24GHZ_RSSI]) { + hdd_err("min_24ghz_rssi id failed"); + goto fail; + } + req_msg->min_24ghz_rssi = nla_get_u32( + tb[QCA_WLAN_VENDOR_ATTR_EPNO_MIN24GHZ_RSSI]); + + /* Parse and fetch initial_score_max */ + if (!tb[QCA_WLAN_VENDOR_ATTR_EPNO_INITIAL_SCORE_MAX]) { + hdd_err("initial_score_max id failed"); + goto fail; + } + req_msg->initial_score_max = nla_get_u32( + tb[QCA_WLAN_VENDOR_ATTR_EPNO_INITIAL_SCORE_MAX]); + + /* Parse and fetch current_connection_bonus */ + if (!tb[QCA_WLAN_VENDOR_ATTR_EPNO_CURRENT_CONNECTION_BONUS]) { + hdd_err("current_connection_bonus id failed"); + goto fail; + } + req_msg->current_connection_bonus = nla_get_u32( + tb[QCA_WLAN_VENDOR_ATTR_EPNO_CURRENT_CONNECTION_BONUS] + ); + + /* Parse and fetch same_network_bonus */ + if (!tb[QCA_WLAN_VENDOR_ATTR_EPNO_SAME_NETWORK_BONUS]) { + hdd_err("same_network_bonus id failed"); + goto fail; + } + req_msg->same_network_bonus = nla_get_u32( + tb[QCA_WLAN_VENDOR_ATTR_EPNO_SAME_NETWORK_BONUS]); + + /* Parse and fetch secure_bonus */ + if (!tb[QCA_WLAN_VENDOR_ATTR_EPNO_SECURE_BONUS]) { + hdd_err("secure_bonus id failed"); + goto fail; + } + req_msg->secure_bonus = nla_get_u32( + tb[QCA_WLAN_VENDOR_ATTR_EPNO_SECURE_BONUS]); + + /* Parse and fetch band_5ghz_bonus */ + if (!tb[QCA_WLAN_VENDOR_ATTR_EPNO_BAND5GHZ_BONUS]) { + hdd_err("band_5ghz_bonus id failed"); + goto fail; + } + req_msg->band_5ghz_bonus = nla_get_u32( + tb[QCA_WLAN_VENDOR_ATTR_EPNO_BAND5GHZ_BONUS]); + + hdd_notice("min_5ghz_rssi: %d min_24ghz_rssi: %d", + req_msg->min_5ghz_rssi, + req_msg->min_24ghz_rssi); + hdd_notice("initial_score_max: %d current_connection_bonus:%d", + req_msg->initial_score_max, + req_msg->current_connection_bonus); + hdd_notice("Bonuses same_network: %d secure: %d band_5ghz: %d", + req_msg->same_network_bonus, + req_msg->secure_bonus, + req_msg->band_5ghz_bonus); + + if (hdd_extscan_epno_fill_network_list(hdd_ctx, req_msg, tb)) + goto fail; + + } + + status = sme_set_epno_list(hdd_ctx->hHal, req_msg); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("sme_set_epno_list failed(err=%d)", status); + goto fail; + } + + EXIT(); + qdf_mem_free(req_msg); + return 0; + +fail: + qdf_mem_free(req_msg); + return -EINVAL; +} + + /** + * wlan_hdd_cfg80211_set_epno_list() - epno set network list + * @wiphy: wiphy + * @wdev: pointer to wireless dev + * @data: data pointer + * @data_len: data length + * + * This function reads the NL vendor attributes from %tb and + * fill in the epno request message. + * + * Return: 0 on success, error number otherwise + */ +int wlan_hdd_cfg80211_set_epno_list(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_set_epno_list(wiphy, wdev, + data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * hdd_extscan_passpoint_fill_network_list() - passpoint fill network list + * @hddctx: HDD context + * @req_msg: request message + * @tb: vendor attribute table + * + * This function reads the network block NL vendor attributes from %tb and + * fill in the passpoint request message. + * + * Return: 0 on success, error number otherwise + */ +static int hdd_extscan_passpoint_fill_network_list( + hdd_context_t *hddctx, + struct wifi_passpoint_req *req_msg, + struct nlattr **tb) +{ + struct nlattr *network[QCA_WLAN_VENDOR_ATTR_PNO_MAX + 1]; + struct nlattr *networks; + int rem1, len; + uint8_t index; + uint32_t expected_networks; + + expected_networks = req_msg->num_networks; + index = 0; + + if (!tb[QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_LIST_PARAM_NETWORK_ARRAY]) { + hdd_err("attr network array failed"); + return -EINVAL; + } + nla_for_each_nested(networks, + tb[QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_LIST_PARAM_NETWORK_ARRAY], + rem1) { + + if (index == expected_networks) { + hdd_warn("ignoring excess networks"); + break; + } + + if (nla_parse(network, + QCA_WLAN_VENDOR_ATTR_PNO_MAX, + nla_data(networks), nla_len(networks), + wlan_hdd_pno_config_policy)) { + hdd_err("nla_parse failed"); + return -EINVAL; + } + + /* Parse and fetch identifier */ + if (!network[QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_NETWORK_PARAM_ID]) { + hdd_err("attr passpoint id failed"); + return -EINVAL; + } + req_msg->networks[index].id = nla_get_u32( + network[QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_NETWORK_PARAM_ID]); + hdd_notice("Id %u", req_msg->networks[index].id); + + /* Parse and fetch realm */ + if (!network[QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_NETWORK_PARAM_REALM]) { + hdd_err("attr realm failed"); + return -EINVAL; + } + len = nla_len( + network[QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_NETWORK_PARAM_REALM]); + if (len < 0 || len > SIR_PASSPOINT_REALM_LEN) { + hdd_err("Invalid realm size %d", len); + return -EINVAL; + } + qdf_mem_copy(req_msg->networks[index].realm, + nla_data(network[QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_NETWORK_PARAM_REALM]), + len); + hdd_notice("realm len %d", len); + hdd_notice("realm: %s", req_msg->networks[index].realm); + + /* Parse and fetch roaming consortium ids */ + if (!network[QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_NETWORK_PARAM_ROAM_CNSRTM_ID]) { + hdd_err("attr roaming consortium ids failed"); + return -EINVAL; + } + nla_memcpy(&req_msg->networks[index].roaming_consortium_ids, + network[QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_NETWORK_PARAM_ROAM_CNSRTM_ID], + sizeof(req_msg->networks[0].roaming_consortium_ids)); + hdd_notice("roaming consortium ids"); + + /* Parse and fetch plmn */ + if (!network[QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_NETWORK_PARAM_ROAM_PLMN]) { + hdd_err("attr plmn failed"); + return -EINVAL; + } + nla_memcpy(&req_msg->networks[index].plmn, + network[QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_NETWORK_PARAM_ROAM_PLMN], + SIR_PASSPOINT_PLMN_LEN); + hdd_notice("plmn %02x:%02x:%02x)", + req_msg->networks[index].plmn[0], + req_msg->networks[index].plmn[1], + req_msg->networks[index].plmn[2]); + + index++; + } + req_msg->num_networks = index; + return 0; +} + +/** + * __wlan_hdd_cfg80211_set_passpoint_list() - set passpoint network list + * @wiphy: wiphy + * @wdev: pointer to wireless dev + * @data: data pointer + * @data_len: data length + * + * This function reads the NL vendor attributes from %tb and + * fill in the passpoint request message. + * + * Return: 0 on success, error number otherwise + */ +static int __wlan_hdd_cfg80211_set_passpoint_list(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + struct wifi_passpoint_req *req_msg = NULL; + struct net_device *dev = wdev->netdev; + hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *hdd_ctx = wiphy_priv(wiphy); + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_PNO_MAX + 1]; + QDF_STATUS status; + uint32_t num_networks = 0; + int ret; + + ENTER_DEV(dev); + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return ret; + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_PNO_MAX, data, data_len, + wlan_hdd_pno_config_policy)) { + hdd_err("Invalid ATTR"); + return -EINVAL; + } + + /* Parse and fetch number of networks */ + if (!tb[QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_LIST_PARAM_NUM]) { + hdd_err("attr num networks failed"); + return -EINVAL; + } + num_networks = nla_get_u32( + tb[QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_LIST_PARAM_NUM]); + if (num_networks > SIR_PASSPOINT_LIST_MAX_NETWORKS) { + hdd_err("num networks %u exceeds max %u", + num_networks, SIR_PASSPOINT_LIST_MAX_NETWORKS); + return -EINVAL; + } + + hdd_notice("num networks %u", num_networks); + + req_msg = qdf_mem_malloc(sizeof(*req_msg) + + (num_networks * sizeof(req_msg->networks[0]))); + if (!req_msg) { + hdd_err("qdf_mem_malloc failed"); + return -ENOMEM; + } + req_msg->num_networks = num_networks; + + /* Parse and fetch request Id */ + if (!tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID]) { + hdd_err("attr request id failed"); + goto fail; + } + req_msg->request_id = nla_get_u32( + tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID]); + + req_msg->session_id = adapter->sessionId; + hdd_notice("Req Id %u Session Id %d", req_msg->request_id, + req_msg->session_id); + + if (hdd_extscan_passpoint_fill_network_list(hdd_ctx, req_msg, tb)) + goto fail; + + status = sme_set_passpoint_list(hdd_ctx->hHal, req_msg); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("sme_set_passpoint_list failed(err=%d)", status); + goto fail; + } + + EXIT(); + qdf_mem_free(req_msg); + return 0; + +fail: + qdf_mem_free(req_msg); + return -EINVAL; +} + +/** + * wlan_hdd_cfg80211_set_passpoint_list() - set passpoint network list + * @wiphy: wiphy + * @wdev: pointer to wireless dev + * @data: data pointer + * @data_len: data length + * + * This function reads the NL vendor attributes from %tb and + * fill in the passpoint request message. + * + * Return: 0 on success, error number otherwise + */ +int wlan_hdd_cfg80211_set_passpoint_list(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_set_passpoint_list(wiphy, wdev, + data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __wlan_hdd_cfg80211_reset_passpoint_list() - reset passpoint network list + * @wiphy: wiphy + * @wdev: pointer to wireless dev + * @data: data pointer + * @data_len: data length + * + * This function resets passpoint networks list + * + * Return: 0 on success, error number otherwise + */ +static int __wlan_hdd_cfg80211_reset_passpoint_list(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + struct wifi_passpoint_req *req_msg = NULL; + struct net_device *dev = wdev->netdev; + hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *hdd_ctx = wiphy_priv(wiphy); + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_PNO_MAX + 1]; + QDF_STATUS status; + int ret; + + ENTER_DEV(dev); + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return ret; + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_PNO_MAX, data, data_len, + wlan_hdd_extscan_config_policy)) { + hdd_err("Invalid ATTR"); + return -EINVAL; + } + + req_msg = qdf_mem_malloc(sizeof(*req_msg)); + if (!req_msg) { + hdd_err("qdf_mem_malloc failed"); + return -ENOMEM; + } + + /* Parse and fetch request Id */ + if (!tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID]) { + hdd_err("attr request id failed"); + goto fail; + } + req_msg->request_id = nla_get_u32( + tb[QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID]); + + req_msg->session_id = adapter->sessionId; + hdd_notice("Req Id %u Session Id %d", + req_msg->request_id, req_msg->session_id); + + status = sme_reset_passpoint_list(hdd_ctx->hHal, req_msg); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("sme_reset_passpoint_list failed(err=%d)", status); + goto fail; + } + + EXIT(); + qdf_mem_free(req_msg); + return 0; + +fail: + qdf_mem_free(req_msg); + return -EINVAL; +} + +/** + * wlan_hdd_cfg80211_reset_passpoint_list() - reset passpoint network list + * @wiphy: wiphy + * @wdev: pointer to wireless dev + * @data: data pointer + * @data_len: data length + * + * This function resets passpoint networks list + * + * Return: 0 on success, error number otherwise + */ +int wlan_hdd_cfg80211_reset_passpoint_list(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_reset_passpoint_list(wiphy, wdev, + data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * wlan_hdd_init_completion_extwow() - Initialize ext wow variable + * @hdd_ctx: Global HDD context + * + * Return: none + */ +#ifdef WLAN_FEATURE_EXTWOW_SUPPORT +static inline void wlan_hdd_init_completion_extwow(hdd_context_t *pHddCtx) +{ + init_completion(&pHddCtx->ready_to_extwow); +} +#else +static inline void wlan_hdd_init_completion_extwow(hdd_context_t *pHddCtx) +{ + return; +} +#endif + +/** + * wlan_hdd_cfg80211_extscan_init() - Initialize the ExtScan feature + * @hdd_ctx: Global HDD context + * + * Return: none + */ +void wlan_hdd_cfg80211_extscan_init(hdd_context_t *hdd_ctx) +{ + wlan_hdd_init_completion_extwow(hdd_ctx); + init_completion(&ext_scan_context.response_event); + spin_lock_init(&ext_scan_context.context_lock); +} + +#endif /* FEATURE_WLAN_EXTSCAN */ diff --git a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_ext_scan.h b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_ext_scan.h new file mode 100644 index 0000000000000000000000000000000000000000..68afaf46f3d77c08336a4ba7a3f22fe9acba2070 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_ext_scan.h @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2012-2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +#if !defined(WLAN_HDD_EXT_SCAN_H) +#define WLAN_HDD_EXT_SCAN_H + +/** + * DOC: wlan_hdd_ext_scan.h + * + * WLAN Host Device Driver EXT SCAN feature implementation + * + */ + +#ifdef FEATURE_WLAN_EXTSCAN + +#include "wlan_hdd_main.h" + +/* + * Used to allocate the size of 4096 for the EXTScan NL data. + * The size of 4096 is considered assuming that all data per + * respective event fit with in the limit.Please take a call + * on the limit based on the data requirements. + */ + +#define EXTSCAN_EVENT_BUF_SIZE 4096 + +int wlan_hdd_cfg80211_extscan_start(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len); + +int wlan_hdd_cfg80211_extscan_stop(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len); + +int wlan_hdd_cfg80211_extscan_get_valid_channels(struct wiphy *wiphy, + struct wireless_dev + *wdev, const void *data, + int data_len); + +int wlan_hdd_cfg80211_extscan_get_capabilities(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len); + +int wlan_hdd_cfg80211_extscan_get_cached_results(struct wiphy *wiphy, + struct wireless_dev + *wdev, const void *data, + int data_len); + +int wlan_hdd_cfg80211_extscan_set_bssid_hotlist(struct wiphy *wiphy, + struct wireless_dev + *wdev, const void *data, + int data_len); + +int wlan_hdd_cfg80211_extscan_reset_bssid_hotlist(struct wiphy *wiphy, + struct wireless_dev + *wdev, const void *data, + int data_len); + +int wlan_hdd_cfg80211_extscan_set_significant_change(struct wiphy *wiphy, + struct wireless_dev + *wdev, const void *data, + int data_len); + +int wlan_hdd_cfg80211_extscan_reset_significant_change(struct wiphy + *wiphy, + struct + wireless_dev + *wdev, const void *data, + int data_len); + +int wlan_hdd_cfg80211_set_epno_list(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len); + +int wlan_hdd_cfg80211_set_passpoint_list(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len); + +int wlan_hdd_cfg80211_reset_passpoint_list(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len); + +int +wlan_hdd_cfg80211_extscan_set_ssid_hotlist(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len); + +int +wlan_hdd_cfg80211_extscan_reset_ssid_hotlist(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len); + +void wlan_hdd_cfg80211_extscan_init(hdd_context_t *hdd_ctx); + +#else /* FEATURE_WLAN_EXTSCAN */ + +static void wlan_hdd_cfg80211_extscan_init(hdd_context_t *hdd_ctx) +{ +} + +#endif /* End of FEATURE_WLAN_EXTSCAN */ + +#endif /* end #if !defined(WLAN_HDD_EXT_SCAN_H) */ diff --git a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_ftm.c b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_ftm.c new file mode 100644 index 0000000000000000000000000000000000000000..dfc14ca78eef1450c2767571a476a2bb98be5b16 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_ftm.c @@ -0,0 +1,387 @@ +/* + * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: wlan_hdd_ftm.c + * + * This file contains the WLAN factory test mode implementation + */ + +#include +#include "cds_sched.h" +#include +#include "sir_types.h" +#include "qdf_types.h" +#include "sir_api.h" +#include "sir_mac_prot_def.h" +#include "sme_api.h" +#include "mac_init_api.h" +#include "wlan_qct_sys.h" +#include "wlan_hdd_misc.h" +#include "i_cds_packet.h" +#include "cds_reg_service.h" +#include "wlan_hdd_main.h" +#include "wlan_hdd_lpass.h" +#include "qwlan_version.h" +#include "wma_types.h" +#include "cfg_api.h" + +#if defined(QCA_WIFI_FTM) +#include "bmi.h" +#include "ol_fw.h" +#include "wlan_hdd_cfg80211.h" +#include "hif.h" +#endif + +#define HDD_FTM_WMA_PRE_START_TIMEOUT (30000) /* 30 seconds */ + +#if defined(QCA_WIFI_FTM) +#if defined(LINUX_QCMBR) +#define ATH_XIOCTL_UNIFIED_UTF_CMD 0x1000 +#define ATH_XIOCTL_UNIFIED_UTF_RSP 0x1001 +#define MAX_UTF_LENGTH 1024 +typedef struct qcmbr_data_s { + unsigned int cmd; + unsigned int length; + unsigned char buf[MAX_UTF_LENGTH + 4]; + unsigned int copy_to_user; +} qcmbr_data_t; +typedef struct qcmbr_queue_s { + unsigned char utf_buf[MAX_UTF_LENGTH + 4]; + struct list_head list; +} qcmbr_queue_t; +LIST_HEAD(qcmbr_queue_head); +DEFINE_SPINLOCK(qcmbr_queue_lock); +static void wlanqcmbr_mc_process_msg(void *message); +#endif +#endif + +/** + * wlan_ftm_postmsg() - Post FTM message + * @cmd_ptr: Pointer to FTM command buffer + * @cmd_len: Length of command in @cmd_ptr + * + * This function is used to send FTM commands to firmware + * + * Return: 0 for success, non zero for failure + */ +static uint32_t wlan_ftm_postmsg(uint8_t *cmd_ptr, uint16_t cmd_len) +{ + cds_msg_t ftmMsg; + + ENTER(); + + ftmMsg.type = WMA_FTM_CMD_REQ; + ftmMsg.reserved = 0; + ftmMsg.bodyptr = (uint8_t *) cmd_ptr; + ftmMsg.bodyval = 0; + + if (QDF_STATUS_SUCCESS != cds_mq_post_message(QDF_MODULE_ID_WMA, + &ftmMsg)) { + hdd_err("Failed to post Msg to HAL"); + + return QDF_STATUS_E_FAILURE; + } + + EXIT(); + return QDF_STATUS_SUCCESS; +} + +/** + * hdd_update_cds_config_ftm() - API to update cds configuration parameters + * for FTM mode. + * @hdd_ctx: HDD Context + * + * Return: 0 on success; errno on failure + */ + +int hdd_update_cds_config_ftm(hdd_context_t *hdd_ctx) +{ + struct cds_config_info *cds_cfg; + + cds_cfg = qdf_mem_malloc(sizeof(*cds_cfg)); + if (!cds_cfg) { + hdd_err("failed to allocate cds config"); + return -ENOMEM; + } + + cds_cfg->driver_type = eDRIVER_TYPE_MFG; + cds_cfg->powersave_offload_enabled = + hdd_ctx->config->enablePowersaveOffload; + hdd_lpass_populate_cds_config(cds_cfg, hdd_ctx); + cds_cfg->sub_20_channel_width = WLAN_SUB_20_CH_WIDTH_NONE; + cds_init_ini_config(cds_cfg); + + return 0; +} + +/** + * hdd_ftm_mc_process_msg() - Process FTM mailbox message + * @message: FTM response message + * + * Process FTM mailbox message + * + * Return: void + */ +void hdd_ftm_mc_process_msg(void *message) +{ + void *data; + uint32_t data_len; + + if (!message) { + hdd_err("Message is NULL, nothing to process."); + return; + } + + data_len = *((uint32_t *) message); + data = (uint32_t *) message + 1; + +#if defined(LINUX_QCMBR) + wlanqcmbr_mc_process_msg(message); +#else +#ifdef CONFIG_NL80211_TESTMODE + wlan_hdd_testmode_rx_event(data, (size_t) data_len); +#endif +#endif + return; +} + +#if defined(QCA_WIFI_FTM) +#if defined(LINUX_QCMBR) +/** + * wlan_hdd_qcmbr_command() - QCMBR command handler + * @adapter: adapter upon which the command was received + * @pqcmbr_data: QCMBR command + * + * Return: 0 on success, non-zero on error + */ +static int wlan_hdd_qcmbr_command(hdd_adapter_t *adapter, + qcmbr_data_t *pqcmbr_data) +{ + int ret = 0; + qcmbr_queue_t *qcmbr_buf = NULL; + + switch (pqcmbr_data->cmd) { + case ATH_XIOCTL_UNIFIED_UTF_CMD: { + pqcmbr_data->copy_to_user = 0; + if (pqcmbr_data->length && + pqcmbr_data->length <= sizeof(pqcmbr_data->buf)) { + if (wlan_hdd_ftm_testmode_cmd(pqcmbr_data->buf, + pqcmbr_data-> + length) + != QDF_STATUS_SUCCESS) { + ret = -EBUSY; + } else { + ret = 0; + } + } + } + break; + + case ATH_XIOCTL_UNIFIED_UTF_RSP: { + pqcmbr_data->copy_to_user = 1; + + spin_lock_bh(&qcmbr_queue_lock); + if (!list_empty(&qcmbr_queue_head)) { + qcmbr_buf = list_first_entry(&qcmbr_queue_head, + qcmbr_queue_t, + list); + list_del(&qcmbr_buf->list); + ret = 0; + } else { + ret = -1; + } + spin_unlock_bh(&qcmbr_queue_lock); + + if (!ret) { + memcpy(pqcmbr_data->buf, qcmbr_buf->utf_buf, + (MAX_UTF_LENGTH + 4)); + qdf_mem_free(qcmbr_buf); + } else { + ret = -EAGAIN; + } + } + break; + } + + return ret; +} + +#ifdef CONFIG_COMPAT +/** + * wlan_hdd_qcmbr_ioctl() - Compatability-mode QCMBR ioctl handler + * @adapter: adapter upon which the ioctl was received + * @ifr: the ioctl request + * + * Return: 0 on success, non-zero on error + */ +static int wlan_hdd_qcmbr_compat_ioctl(hdd_adapter_t *adapter, + struct ifreq *ifr) +{ + qcmbr_data_t *qcmbr_data; + int ret = 0; + + qcmbr_data = qdf_mem_malloc(sizeof(qcmbr_data_t)); + if (qcmbr_data == NULL) + return -ENOMEM; + + if (copy_from_user(qcmbr_data, ifr->ifr_data, sizeof(*qcmbr_data))) { + ret = -EFAULT; + goto exit; + } + + ret = wlan_hdd_qcmbr_command(adapter, qcmbr_data); + if ((ret == 0) && qcmbr_data->copy_to_user) { + ret = copy_to_user(ifr->ifr_data, qcmbr_data->buf, + (MAX_UTF_LENGTH + 4)); + } + +exit: + qdf_mem_free(qcmbr_data); + return ret; +} +#else /* CONFIG_COMPAT */ +static int wlan_hdd_qcmbr_compat_ioctl(hdd_adapter_t *adapter, + struct ifreq *ifr) +{ + return 0; +} +#endif /* CONFIG_COMPAT */ + +/** + * wlan_hdd_qcmbr_ioctl() - Standard QCMBR ioctl handler + * @adapter: adapter upon which the ioctl was received + * @ifr: the ioctl request + * + * Return: 0 on success, non-zero on error + */ +static int wlan_hdd_qcmbr_ioctl(hdd_adapter_t *adapter, struct ifreq *ifr) +{ + qcmbr_data_t *qcmbr_data; + int ret = 0; + + qcmbr_data = qdf_mem_malloc(sizeof(qcmbr_data_t)); + if (qcmbr_data == NULL) + return -ENOMEM; + + if (copy_from_user(qcmbr_data, ifr->ifr_data, sizeof(*qcmbr_data))) { + ret = -EFAULT; + goto exit; + } + + ret = wlan_hdd_qcmbr_command(adapter, qcmbr_data); + if ((ret == 0) && qcmbr_data->copy_to_user) { + ret = copy_to_user(ifr->ifr_data, qcmbr_data->buf, + (MAX_UTF_LENGTH + 4)); + } + +exit: + qdf_mem_free(qcmbr_data); + return ret; +} + +/** + * wlan_hdd_qcmbr_unified_ioctl() - Unified QCMBR ioctl handler + * @adapter: adapter upon which the ioctl was received + * @ifr: the ioctl request + * + * Return: 0 on success, non-zero on error + */ +int wlan_hdd_qcmbr_unified_ioctl(hdd_adapter_t *adapter, struct ifreq *ifr) +{ + int ret = 0; + + if (is_compat_task()) { + ret = wlan_hdd_qcmbr_compat_ioctl(adapter, ifr); + } else { + ret = wlan_hdd_qcmbr_ioctl(adapter, ifr); + } + + return ret; +} + +/** + * wlanqcmbr_mc_process_msg() - Process QCMBR response message + * @message: QCMBR message + * + * Return: None + */ +static void wlanqcmbr_mc_process_msg(void *message) +{ + qcmbr_queue_t *qcmbr_buf = NULL; + uint32_t data_len; + + data_len = *((uint32_t *) message) + sizeof(uint32_t); + qcmbr_buf = qdf_mem_malloc(sizeof(qcmbr_queue_t)); + if (qcmbr_buf != NULL) { + memcpy(qcmbr_buf->utf_buf, message, data_len); + spin_lock_bh(&qcmbr_queue_lock); + list_add_tail(&(qcmbr_buf->list), &qcmbr_queue_head); + spin_unlock_bh(&qcmbr_queue_lock); + } +} +#endif /*LINUX_QCMBR */ + +/** + * wlan_hdd_ftm_testmode_cmd() - Process FTM testmode command + * @data: FTM testmode command + * @len: length of @data + * + * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_** on error + */ +QDF_STATUS wlan_hdd_ftm_testmode_cmd(void *data, int len) +{ + struct ar6k_testmode_cmd_data *cmd_data; + + cmd_data = (struct ar6k_testmode_cmd_data *) + qdf_mem_malloc(sizeof(*cmd_data)); + + if (!cmd_data) { + hdd_err("Failed to allocate FTM command data"); + return QDF_STATUS_E_NOMEM; + } + + cmd_data->data = qdf_mem_malloc(len); + + if (!cmd_data->data) { + hdd_err("Failed to allocate FTM command data buffer"); + qdf_mem_free(cmd_data); + return QDF_STATUS_E_NOMEM; + } + + cmd_data->len = len; + qdf_mem_copy(cmd_data->data, data, len); + + if (wlan_ftm_postmsg((uint8_t *) cmd_data, sizeof(*cmd_data))) { + qdf_mem_free(cmd_data->data); + qdf_mem_free(cmd_data); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} +#endif /*QCA_WIFI_FTM */ diff --git a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_green_ap.c b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_green_ap.c new file mode 100644 index 0000000000000000000000000000000000000000..335ecc27ae15fa73cd247b100334c0eed17ea2d8 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_green_ap.c @@ -0,0 +1,606 @@ +/* + * Copyright (c) 2014-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/** + * DOC: wlan_hdd_green_ap.c + * + * WLAN Host Device Driver Green AP implementation + * + */ + +/* Include Files */ +#include +#include +#include "wlan_hdd_green_ap.h" +#include "wma_api.h" +#include "cds_concurrency.h" + +#define GREEN_AP_PS_ON_TIME (0) +#define GREEN_AP_PS_DELAY_TIME (20) + +/** + * enum hdd_green_ap_ps_state - Green-AP power save states + * @GREEN_AP_PS_IDLE_STATE: the Green_AP is not enabled + * @GREEN_AP_PS_OFF_STATE: in Power Saving OFF state + * @GREEN_AP_PS_WAIT_STATE: in transition to Power Saving ON state + * @GREEN_AP_PS_ON_STATE: in Power Saving ON state + */ +enum hdd_green_ap_ps_state { + GREEN_AP_PS_IDLE_STATE = 1, + GREEN_AP_PS_OFF_STATE, + GREEN_AP_PS_WAIT_STATE, + GREEN_AP_PS_ON_STATE, +}; + +/** + * enum hdd_green_ap_event - Green-AP power save events + * @GREEN_AP_PS_START_EVENT: event to indicate to enable Green_AP + * @GREEN_AP_PS_START_EVENT: event to indicate to disable Green_AP + * @GREEN_AP_ADD_STA_EVENT: event to indicate a new STA connected + * @GREEN_AP_DEL_STA_EVENT: event to indicate a STA disconnected + * @GREEN_AP_PS_ON_EVENT: event to indicate to enter Power Saving state + * @GREEN_AP_PS_WAIT_EVENT: event to indicate in the transition to Power Saving + */ +enum hdd_green_ap_event { + GREEN_AP_PS_START_EVENT = 1, + GREEN_AP_PS_STOP_EVENT, + GREEN_AP_ADD_STA_EVENT, + GREEN_AP_DEL_STA_EVENT, + GREEN_AP_PS_ON_EVENT, + GREEN_AP_PS_WAIT_EVENT, +}; + +/** + * struct hdd_green_ap_ctx - Green-AP context + * @ps_enable: Whether or not Green AP is enabled + * @ps_on_time: Amount of time to stay in Green AP power saving state + * @ps_delay_time: Amount of time to delay when changing states + * @num_nodes: Number of connected clients + * @ps_state: Current state + * @ps_event: Event to trigger when timer expires + * @ps_timer: Event timer + * @egap_support: Enhanced Green AP support flag + */ +struct hdd_green_ap_ctx { + uint8_t ps_enable; + uint32_t ps_on_time; + uint32_t ps_delay_time; + uint32_t num_nodes; + + enum hdd_green_ap_ps_state ps_state; + enum hdd_green_ap_event ps_event; + + qdf_mc_timer_t ps_timer; + + bool egap_support; +}; + +/** + * hdd_green_ap_update() - update the current State and Event + * @hdd_ctx: Global HDD context + * @state: New state + * @event: New event + * + * Return: none + */ +static void hdd_green_ap_update(struct hdd_context_s *hdd_ctx, + enum hdd_green_ap_ps_state state, + enum hdd_green_ap_event event) +{ + struct hdd_green_ap_ctx *green_ap = hdd_ctx->green_ap_ctx; + + green_ap->ps_state = state; + green_ap->ps_event = event; +} + +/** + * hdd_green_ap_enable() - Send Green AP configuration to firmware + * @adapter: Adapter upon which Green AP is being configured + * @enable: Flag which indicates if Green AP is being enabled or disabled + * + * Return: 0 upon success, non-zero upon failure + */ +static int hdd_green_ap_enable(hdd_adapter_t *adapter, uint8_t enable) +{ + int ret; + + hdd_notice("Set Green-AP val: %d", enable); + + ret = wma_cli_set_command(adapter->sessionId, + WMI_PDEV_GREEN_AP_PS_ENABLE_CMDID, + enable, DBG_CMD); + + return ret; +} + +/** + * hdd_green_ap_mc() - Green AP state machine + * @hdd_ctx: HDD global context + * @event: New event being processed + * + * Return: none + */ +static void hdd_green_ap_mc(struct hdd_context_s *hdd_ctx, + enum hdd_green_ap_event event) +{ + struct hdd_green_ap_ctx *green_ap; + hdd_adapter_t *adapter; + + green_ap = hdd_ctx->green_ap_ctx; + if (green_ap == NULL) + return; + + hdd_notice("Green-AP event: %d, state: %d, num_nodes: %d", + event, green_ap->ps_state, green_ap->num_nodes); + + /* handle the green ap ps event */ + switch (event) { + case GREEN_AP_PS_START_EVENT: + green_ap->ps_enable = 1; + break; + + case GREEN_AP_PS_STOP_EVENT: + green_ap->ps_enable = 0; + break; + + case GREEN_AP_ADD_STA_EVENT: + green_ap->num_nodes++; + break; + + case GREEN_AP_DEL_STA_EVENT: + if (green_ap->num_nodes) + green_ap->num_nodes--; + break; + + case GREEN_AP_PS_ON_EVENT: + case GREEN_AP_PS_WAIT_EVENT: + break; + + default: + hdd_err("invalid event %d", event); + break; + } + + adapter = hdd_get_adapter(hdd_ctx, QDF_SAP_MODE); + if (adapter == NULL) { + goto done; + } + + /* Confirm that power save is enabled before doing state transitions */ + if (!green_ap->ps_enable) { + hdd_notice("Green-AP is disabled"); + hdd_green_ap_update(hdd_ctx, + GREEN_AP_PS_OFF_STATE, + GREEN_AP_PS_WAIT_EVENT); + if (hdd_green_ap_enable(adapter, 0)) + hdd_err("failed to set green ap mode"); + goto done; + } + + /* handle the green ap ps state */ + switch (green_ap->ps_state) { + case GREEN_AP_PS_IDLE_STATE: + hdd_green_ap_update(hdd_ctx, + GREEN_AP_PS_OFF_STATE, + GREEN_AP_PS_WAIT_EVENT); + break; + + case GREEN_AP_PS_OFF_STATE: + if (!green_ap->num_nodes) { + hdd_green_ap_update(hdd_ctx, + GREEN_AP_PS_WAIT_STATE, + GREEN_AP_PS_WAIT_EVENT); + qdf_mc_timer_start(&green_ap->ps_timer, + green_ap->ps_delay_time); + } + break; + + case GREEN_AP_PS_WAIT_STATE: + if (!green_ap->num_nodes) { + hdd_green_ap_update(hdd_ctx, + GREEN_AP_PS_ON_STATE, + GREEN_AP_PS_WAIT_EVENT); + + hdd_green_ap_enable(adapter, 1); + + if (green_ap->ps_on_time) { + hdd_green_ap_update(hdd_ctx, + 0, + GREEN_AP_PS_WAIT_EVENT); + qdf_mc_timer_start(&green_ap->ps_timer, + green_ap->ps_on_time); + } + } else { + hdd_green_ap_update(hdd_ctx, + GREEN_AP_PS_OFF_STATE, + GREEN_AP_PS_WAIT_EVENT); + } + break; + + case GREEN_AP_PS_ON_STATE: + if (green_ap->num_nodes) { + if (hdd_green_ap_enable(adapter, 0)) { + hdd_err("FAILED TO SET GREEN-AP mode"); + goto done; + } + hdd_green_ap_update(hdd_ctx, + GREEN_AP_PS_OFF_STATE, + GREEN_AP_PS_WAIT_EVENT); + } else if ((green_ap->ps_event == GREEN_AP_PS_WAIT_EVENT) + && (green_ap->ps_on_time)) { + + /* ps_on_time timeout, switch to ps off */ + hdd_green_ap_update(hdd_ctx, + GREEN_AP_PS_WAIT_STATE, + GREEN_AP_PS_ON_EVENT); + + if (hdd_green_ap_enable(adapter, 0)) { + hdd_err("FAILED TO SET GREEN-AP mode"); + goto done; + } + + qdf_mc_timer_start(&green_ap->ps_timer, + green_ap->ps_delay_time); + } + break; + + default: + hdd_err("invalid state %d", green_ap->ps_state); + hdd_green_ap_update(hdd_ctx, GREEN_AP_PS_OFF_STATE, + GREEN_AP_PS_WAIT_EVENT); + break; + } + +done: + return; +} + +/** + * hdd_green_ap_timer_fn() - Green AP Timer handler + * @ctx: Global HDD context + * + * Return: none + */ +static void hdd_green_ap_timer_fn(void *ctx) +{ + struct hdd_context_s *hdd_ctx = ctx; + struct hdd_green_ap_ctx *green_ap; + + if (wlan_hdd_validate_context(hdd_ctx)) + return; + + green_ap = hdd_ctx->green_ap_ctx; + if (green_ap) + hdd_green_ap_mc(hdd_ctx, green_ap->ps_event); +} + +/** + * hdd_green_ap_attach() - Attach Green AP context to HDD context + * @hdd_ctx: Global HDD contect + * + * Return: QDF_STATUS_SUCCESS on success, otherwise QDF_STATUS_E_** error + */ +static QDF_STATUS hdd_green_ap_attach(struct hdd_context_s *hdd_ctx) +{ + struct hdd_green_ap_ctx *green_ap; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + ENTER(); + + green_ap = qdf_mem_malloc(sizeof(*green_ap)); + if (!green_ap) { + hdd_alert("Memory allocation for Green-AP failed!"); + status = QDF_STATUS_E_NOMEM; + goto error; + } + + green_ap->ps_state = GREEN_AP_PS_OFF_STATE; + green_ap->ps_event = 0; + green_ap->num_nodes = 0; + green_ap->ps_on_time = GREEN_AP_PS_ON_TIME; + green_ap->ps_delay_time = GREEN_AP_PS_DELAY_TIME; + + qdf_mc_timer_init(&green_ap->ps_timer, + QDF_TIMER_TYPE_SW, + hdd_green_ap_timer_fn, hdd_ctx); + +error: + hdd_ctx->green_ap_ctx = green_ap; + + EXIT(); + return status; +} + +/** + * hdd_green_ap_deattach() - Detach Green AP context from HDD context + * @hdd_ctx: Global HDD contect + * + * Return: QDF_STATUS_SUCCESS on success, otherwise QDF_STATUS_E_** error + */ +static QDF_STATUS hdd_green_ap_deattach(struct hdd_context_s *hdd_ctx) +{ + struct hdd_green_ap_ctx *green_ap = hdd_ctx->green_ap_ctx; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + ENTER(); + + if (green_ap == NULL) { + hdd_notice("Green-AP is not enabled"); + status = QDF_STATUS_E_NOSUPPORT; + goto done; + } + + /* check if the timer status is destroyed */ + if (QDF_TIMER_STATE_RUNNING == + qdf_mc_timer_get_current_state(&green_ap->ps_timer)) + qdf_mc_timer_stop(&green_ap->ps_timer); + + /* Destroy the Green AP timer */ + if (!QDF_IS_STATUS_SUCCESS(qdf_mc_timer_destroy(&green_ap->ps_timer))) + hdd_notice("Cannot deallocate Green-AP's timer"); + + /* release memory */ + qdf_mem_zero(green_ap, sizeof(*green_ap)); + qdf_mem_free(green_ap); + hdd_ctx->green_ap_ctx = NULL; + +done: + + EXIT(); + return status; +} + +/* + * hdd_green_ap_init() - Initialize Green AP feature + * (public function documented in wlan_hdd_green_ap.h) + */ +void hdd_green_ap_init(struct hdd_context_s *hdd_ctx) +{ + if (!QDF_IS_STATUS_SUCCESS(hdd_green_ap_attach(hdd_ctx))) + hdd_err("Failed to allocate Green-AP resource"); +} + +/* + * hdd_green_ap_deinit() - De-initialize Green AP feature + * (public function documented in wlan_hdd_green_ap.h) + */ +void hdd_green_ap_deinit(struct hdd_context_s *hdd_ctx) +{ + if (!QDF_IS_STATUS_SUCCESS(hdd_green_ap_deattach(hdd_ctx))) + hdd_err("Cannot deallocate Green-AP resource"); +} + +/* + * hdd_is_egap_enabled() - Get Enhance Green AP feature status + * @fw_egap_support: flag whether firmware supports egap or not + * @cfg: pointer to the struct hdd_config + * + * Return: true if firmware, feature_flag and ini are all enabled the egap + */ +static bool hdd_is_egap_enabled(bool fw_egap_support, struct hdd_config *cfg) +{ + /* check if the firmware and ini are both enabled the egap, + * and also the feature_flag enable. + */ + if (fw_egap_support && cfg->enable_egap && + cfg->egap_feature_flag) + return true; + return false; +} + +/* + * hdd_enable_egap() - Enable Enhance Green AP + * @hdd_ctx: HDD global context + * + * Return: 0 on success, negative errno on failure + */ +int hdd_enable_egap(struct hdd_context_s *hdd_ctx) +{ + struct hdd_config *cfg; + + if (!hdd_ctx) { + hdd_err("hdd context is NULL"); + return -EINVAL; + } + + cfg = hdd_ctx->config; + + if (!cfg) { + hdd_err("hdd cfg is NULL"); + return -EINVAL; + } + + if (!hdd_ctx->green_ap_ctx) { + hdd_err("green ap context is NULL"); + return -EINVAL; + } + + if (!hdd_is_egap_enabled(hdd_ctx->green_ap_ctx->egap_support, + hdd_ctx->config)) + return -ENOTSUPP; + + if (QDF_STATUS_SUCCESS != sme_send_egap_conf_params(cfg->enable_egap, + cfg->egap_inact_time, + cfg->egap_wait_time, + cfg->egap_feature_flag)) + return -EINVAL; + return 0; +} + +/* + * hdd_green_ap_start_bss() - Notify Green AP of Start BSS event + * (public function documented in wlan_hdd_green_ap.h) + */ +void hdd_green_ap_start_bss(struct hdd_context_s *hdd_ctx) +{ + struct hdd_config *cfg; + + if (!hdd_ctx) { + hdd_err("hdd context is NULL"); + return; + } + + cfg = hdd_ctx->config; + + if (!cfg) { + hdd_err("hdd cfg is NULL"); + return; + } + + if (!hdd_ctx->green_ap_ctx) { + hdd_err("Green AP is not enabled. green_ap_ctx = NULL"); + return; + } + + if (hdd_is_egap_enabled(hdd_ctx->green_ap_ctx->egap_support, + hdd_ctx->config)) + return; + + if ((hdd_ctx->concurrency_mode & QDF_SAP_MASK) && + !(hdd_ctx->concurrency_mode & (QDF_SAP_MASK)) && + cfg->enable2x2 && cfg->enableGreenAP) { + hdd_notice("Green AP enabled - sta_con: %d, 2x2: %d, GAP: %d", + QDF_STA_MASK & hdd_ctx->concurrency_mode, + cfg->enable2x2, cfg->enableGreenAP); + hdd_green_ap_mc(hdd_ctx, GREEN_AP_PS_START_EVENT); + } else { + hdd_green_ap_mc(hdd_ctx, GREEN_AP_PS_STOP_EVENT); + hdd_notice("Green-AP: is disabled, due to sta_concurrency: %d, enable2x2: %d, enableGreenAP: %d", + QDF_STA_MASK & hdd_ctx->concurrency_mode, + cfg->enable2x2, cfg->enableGreenAP); + } +} + +/* + * hdd_green_ap_stop_bss() - Notify Green AP of Stop BSS event + * (public function documented in wlan_hdd_green_ap.h) + */ +void hdd_green_ap_stop_bss(struct hdd_context_s *hdd_ctx) +{ + struct hdd_config *cfg; + + if (!hdd_ctx) { + hdd_err("hdd context is NULL"); + return; + } + + cfg = hdd_ctx->config; + + if (!cfg) { + hdd_err("hdd cfg is NULL"); + return; + } + + if (!hdd_ctx->green_ap_ctx) { + hdd_err("Green AP is not enabled. green_ap_ctx = NULL"); + return; + } + + if (hdd_is_egap_enabled(hdd_ctx->green_ap_ctx->egap_support, + hdd_ctx->config)) + return; + + /* For AP+AP mode, only trigger GREEN_AP_PS_STOP_EVENT, when the + * last AP stops. + */ + + if (1 == (hdd_ctx->no_of_open_sessions[QDF_SAP_MODE])) + hdd_green_ap_mc(hdd_ctx, GREEN_AP_PS_STOP_EVENT); +} + +/* + * hdd_green_ap_add_sta() - Notify Green AP of Add Station event + * (public function documented in wlan_hdd_green_ap.h) + */ +void hdd_green_ap_add_sta(struct hdd_context_s *hdd_ctx) +{ + struct hdd_config *cfg; + + if (!hdd_ctx) { + hdd_err("hdd context is NULL"); + return; + } + + cfg = hdd_ctx->config; + + if (!cfg) { + hdd_err("hdd cfg is NULL"); + return; + } + + if (!hdd_ctx->green_ap_ctx) { + hdd_err("Green AP is not enabled. green_ap_ctx = NULL"); + return; + } + + if (hdd_is_egap_enabled(hdd_ctx->green_ap_ctx->egap_support, + hdd_ctx->config)) + return; + + hdd_green_ap_mc(hdd_ctx, GREEN_AP_ADD_STA_EVENT); +} + +/* + * hdd_green_ap_del_sta() - Notify Green AP of Delete Station event + * (public function documented in wlan_hdd_green_ap.h) + */ +void hdd_green_ap_del_sta(struct hdd_context_s *hdd_ctx) +{ + struct hdd_config *cfg; + + if (!hdd_ctx) { + hdd_err("hdd context is NULL"); + return; + } + + cfg = hdd_ctx->config; + + if (!cfg) { + hdd_err("hdd cfg is NULL"); + return; + } + + if (!hdd_ctx->green_ap_ctx) { + hdd_err("Green AP is not enabled. green_ap_ctx = NULL"); + return; + } + + if (hdd_is_egap_enabled(hdd_ctx->green_ap_ctx->egap_support, + hdd_ctx->config)) + return; + + hdd_green_ap_mc(hdd_ctx, GREEN_AP_DEL_STA_EVENT); +} + +/* + * hdd_green_ap_target_config() - Handle Green AP target configuration + * (public function documented in wlan_hdd_green_ap.h) + * + * Implementation notes: + * Target indicates whether or not Enhanced Green AP (EGAP) is supported + */ +void hdd_green_ap_target_config(struct hdd_context_s *hdd_ctx, + struct wma_tgt_cfg *target_config) +{ + struct hdd_green_ap_ctx *green_ap = hdd_ctx->green_ap_ctx; + + green_ap->egap_support = target_config->egap_support; +} diff --git a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_green_ap.h b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_green_ap.h new file mode 100644 index 0000000000000000000000000000000000000000..6cadd71ff0ec120d35a33ff9006a8b4ed3d4c803 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_green_ap.h @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef __WLAN_HDD_GREEN_AP_H +#define __WLAN_HDD_GREEN_AP_H + +/** + * DOC: wlan_hdd_green_ap.h + * + * WLAN Host Device Driver Green AP API specification + */ + +struct hdd_context_s; +struct wma_tgt_cfg; + +#ifdef FEATURE_GREEN_AP +/** + * hdd_green_ap_init() - Initialize Green AP feature + * @hdd_ctx: HDD global context + * + * Return: none + */ +void hdd_green_ap_init(struct hdd_context_s *hdd_ctx); + +/** + * hdd_green_ap_deinit() - De-initialize Green AP feature + * @hdd_ctx: HDD global context + * + * Return: none + */ +void hdd_green_ap_deinit(struct hdd_context_s *hdd_ctx); + +/** + * hdd_green_ap_start_bss() - Notify Green AP of Start BSS event + * @hdd_ctx: HDD global context + * + * Return: none + */ +void hdd_green_ap_start_bss(struct hdd_context_s *hdd_ctx); + +/** + * hdd_green_ap_stop_bss() - Notify Green AP of Stop BSS event + * @hdd_ctx: HDD global context + * + * Return: none + */ +void hdd_green_ap_stop_bss(struct hdd_context_s *hdd_ctx); + +/** + * hdd_green_ap_add_sta() - Notify Green AP of Add Station event + * @hdd_ctx: HDD global context + * + * Return: none + */ +void hdd_green_ap_add_sta(struct hdd_context_s *hdd_ctx); + +/** + * hdd_green_ap_del_sta() - Notify Green AP of Delete Station event + * @hdd_ctx: HDD global context + * + * Return: none + */ +void hdd_green_ap_del_sta(struct hdd_context_s *hdd_ctx); + +/** + * hdd_enable_egap() - Enable Enhance Green AP + * @hdd_ctx: HDD global context + * + * Return: 0 on success, negative errno on failure + */ +int hdd_enable_egap(struct hdd_context_s *hdd_ctx); + +/** + * hdd_green_ap_target_config() - Handle Green AP target configuration + * @hdd_ctx: HDD global context where Green AP information is stored + * @target_config: Target configuration containing Green AP info + * + * This function updates the HDD context with Green AP-specific + * information provided by the target. + * + * Return: none + */ +void hdd_green_ap_target_config(struct hdd_context_s *hdd_ctx, + struct wma_tgt_cfg *target_config); +#else +static inline void hdd_green_ap_init(struct hdd_context_s *hdd_ctx) {} +static inline void hdd_green_ap_deinit(struct hdd_context_s *hdd_ctx) {} +static inline void hdd_green_ap_start_bss(struct hdd_context_s *hdd_ctx) {} +static inline void hdd_green_ap_stop_bss(struct hdd_context_s *hdd_ctx) {} +static inline void hdd_green_ap_add_sta(struct hdd_context_s *hdd_ctx) {} +static inline void hdd_green_ap_del_sta(struct hdd_context_s *hdd_ctx) {} +static inline int hdd_enable_egap(struct hdd_context_s *hdd_ctx) +{ + return -EINVAL; +} +static inline void hdd_green_ap_target_config(struct hdd_context_s *hdd_ctx, + struct wma_tgt_cfg *target_config) +{ +} +#endif /* FEATURE_GREEN_AP */ +#endif /* __WLAN_HDD_GREEN_AP_H */ diff --git a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_hostapd.c b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_hostapd.c new file mode 100644 index 0000000000000000000000000000000000000000..146cf5097c95a3f651fdb4969118515b6f9198e2 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_hostapd.c @@ -0,0 +1,8639 @@ +/* + * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: wlan_hdd_hostapd.c + * + * WLAN Host Device Driver implementation + */ + +/* Include Files */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "wlan_hdd_p2p.h" +#include +#include "cfg_api.h" +#include "wni_cfg.h" +#include "wlan_hdd_misc.h" +#include +#include "pld_common.h" + +#include "wma.h" +#ifdef WLAN_DEBUG +#include "wma_api.h" +#endif +#include "wlan_hdd_trace.h" +#include "qdf_types.h" +#include "qdf_trace.h" +#include "wlan_hdd_cfg.h" +#include "cds_concurrency.h" +#include "wlan_hdd_tsf.h" +#include "wlan_hdd_green_ap.h" +#include "ol_rx_fwd.h" + +#define IS_UP(_dev) \ + (((_dev)->flags & (IFF_RUNNING|IFF_UP)) == (IFF_RUNNING|IFF_UP)) +#define IS_UP_AUTO(_ic) \ + (IS_UP((_ic)->ic_dev) && (_ic)->ic_roaming == IEEE80211_ROAMING_AUTO) +#define WE_WLAN_VERSION 1 +#define WE_GET_STA_INFO_SIZE 30 +/* WEXT limitation: MAX allowed buf len for any * + * IW_PRIV_TYPE_CHAR is 2Kbytes * + */ +#define WE_SAP_MAX_STA_INFO 0x7FF + +#define RC_2_RATE_IDX(_rc) ((_rc) & 0x7) +#define HT_RC_2_STREAMS(_rc) ((((_rc) & 0x78) >> 3) + 1) +#define RC_2_RATE_IDX_11AC(_rc) ((_rc) & 0xf) +#define HT_RC_2_STREAMS_11AC(_rc) ((((_rc) & 0x30) >> 4) + 1) + +#define SAP_24GHZ_CH_COUNT (14) +#define ACS_SCAN_EXPIRY_TIMEOUT_S 4 + + +/* Function definitions */ + +/** + * hdd_sap_context_init() - Initialize SAP context. + * @hdd_ctx: HDD context. + * + * Initialize SAP context. + * + * Return: 0 on success. + */ +int hdd_sap_context_init(hdd_context_t *hdd_ctx) +{ + qdf_wake_lock_create(&hdd_ctx->sap_dfs_wakelock, "sap_dfs_wakelock"); + atomic_set(&hdd_ctx->sap_dfs_ref_cnt, 0); + + mutex_init(&hdd_ctx->sap_lock); + qdf_wake_lock_create(&hdd_ctx->sap_wake_lock, "qcom_sap_wakelock"); + qdf_spinlock_create(&hdd_ctx->sap_update_info_lock); + + qdf_atomic_init(&hdd_ctx->dfs_radar_found); + + return 0; +} + +/** + * hdd_hostapd_channel_allow_suspend() - allow suspend in a channel. + * Called when, 1. bss stopped, 2. channel switch + * + * @pAdapter: pointer to hdd adapter + * @channel: current channel + * + * Return: None + */ +static void hdd_hostapd_channel_allow_suspend(hdd_adapter_t *pAdapter, + uint8_t channel) +{ + + hdd_context_t *pHddCtx = (hdd_context_t *) (pAdapter->pHddCtx); + hdd_hostapd_state_t *pHostapdState = + WLAN_HDD_GET_HOSTAP_STATE_PTR(pAdapter); + + hdd_notice("bssState: %d, channel: %d, dfs_ref_cnt: %d", + pHostapdState->bssState, channel, + atomic_read(&pHddCtx->sap_dfs_ref_cnt)); + + /* Return if BSS is already stopped */ + if (pHostapdState->bssState == BSS_STOP) + return; + + if (CHANNEL_STATE_DFS != cds_get_channel_state(channel)) + return; + + /* Release wakelock when no more DFS channels are used */ + if (atomic_dec_and_test(&pHddCtx->sap_dfs_ref_cnt)) { + hdd_err("DFS: allowing suspend (chan %d)", channel); + qdf_wake_lock_release(&pHddCtx->sap_dfs_wakelock, + WIFI_POWER_EVENT_WAKELOCK_DFS); + qdf_runtime_pm_allow_suspend(&pHddCtx->runtime_context.dfs); + + } +} + +/** + * hdd_hostapd_channel_prevent_suspend() - prevent suspend in a channel. + * Called when, 1. bss started, 2. channel switch + * + * @pAdapter: pointer to hdd adapter + * @channel: current channel + * + * Return - None + */ +static void hdd_hostapd_channel_prevent_suspend(hdd_adapter_t *pAdapter, + uint8_t channel) +{ + hdd_context_t *pHddCtx = (hdd_context_t *) (pAdapter->pHddCtx); + hdd_hostapd_state_t *pHostapdState = + WLAN_HDD_GET_HOSTAP_STATE_PTR(pAdapter); + + hdd_notice("bssState: %d, channel: %d, dfs_ref_cnt: %d", + pHostapdState->bssState, channel, + atomic_read(&pHddCtx->sap_dfs_ref_cnt)); + + /* Return if BSS is already started && wakelock is acquired */ + if ((pHostapdState->bssState == BSS_START) && + (atomic_read(&pHddCtx->sap_dfs_ref_cnt) >= 1)) + return; + + if (CHANNEL_STATE_DFS != cds_get_channel_state(channel)) + return; + + /* Acquire wakelock if we have at least one DFS channel in use */ + if (atomic_inc_return(&pHddCtx->sap_dfs_ref_cnt) == 1) { + hdd_err("DFS: preventing suspend (chan %d)", channel); + qdf_runtime_pm_prevent_suspend(&pHddCtx->runtime_context.dfs); + qdf_wake_lock_acquire(&pHddCtx->sap_dfs_wakelock, + WIFI_POWER_EVENT_WAKELOCK_DFS); + } +} + +/** + * hdd_sap_context_destroy() - Destroy SAP context + * + * @hdd_ctx: HDD context. + * + * Destroy SAP context. + * + * Return: None + */ +void hdd_sap_context_destroy(hdd_context_t *hdd_ctx) +{ + if (atomic_read(&hdd_ctx->sap_dfs_ref_cnt)) { + qdf_wake_lock_release(&hdd_ctx->sap_dfs_wakelock, + WIFI_POWER_EVENT_WAKELOCK_DRIVER_EXIT); + + atomic_set(&hdd_ctx->sap_dfs_ref_cnt, 0); + hdd_warn("DFS: Allowing suspend"); + } + + qdf_wake_lock_destroy(&hdd_ctx->sap_dfs_wakelock); + + mutex_destroy(&hdd_ctx->sap_lock); + qdf_wake_lock_destroy(&hdd_ctx->sap_wake_lock); + + qdf_spinlock_destroy(&hdd_ctx->sap_update_info_lock); + +} + +/** + * __hdd_hostapd_open() - hdd open function for hostapd interface + * This is called in response to ifconfig up + * @dev: pointer to net_device structure + * + * Return - 0 for success non-zero for failure + */ +static int __hdd_hostapd_open(struct net_device *dev) +{ + hdd_adapter_t *pAdapter = netdev_priv(dev); + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(pAdapter); + int ret; + + ENTER_DEV(dev); + + MTRACE(qdf_trace(QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_HOSTAPD_OPEN_REQUEST, NO_SESSION, 0)); + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return ret; + /* + * Check statemachine state and also stop iface change timer if running + */ + ret = hdd_wlan_start_modules(hdd_ctx, pAdapter, false); + if (ret) { + hdd_err("Failed to start WLAN modules return"); + return ret; + } + + if (!test_bit(SME_SESSION_OPENED, &pAdapter->event_flags)) { + ret = hdd_start_adapter(pAdapter); + if (ret) { + hdd_err("Failed to start adapter :%d", + pAdapter->device_mode); + return ret; + } + } + + set_bit(DEVICE_IFACE_OPENED, &pAdapter->event_flags); + /* Enable all Tx queues */ + hdd_notice("Enabling queues"); + wlan_hdd_netif_queue_control(pAdapter, + WLAN_START_ALL_NETIF_QUEUE_N_CARRIER, + WLAN_CONTROL_PATH); + EXIT(); + return 0; +} + +/** + * hdd_hostapd_open() - SSR wrapper for __hdd_hostapd_open + * @dev: pointer to net device + * + * Return: 0 on success, error number otherwise + */ +static int hdd_hostapd_open(struct net_device *dev) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __hdd_hostapd_open(dev); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __hdd_hostapd_stop() - hdd stop function for hostapd interface + * This is called in response to ifconfig down + * + * @dev: pointer to net_device structure + * + * Return - 0 for success non-zero for failure + */ +static int __hdd_hostapd_stop(struct net_device *dev) +{ + hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ptSapContext sap_ctx = adapter->sessionCtx.ap.sapContext; + int ret; + + ENTER_DEV(dev); + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return ret; + + if (!sap_ctx) { + hdd_err("invalid sap ctx : %p", sap_ctx); + return -ENODEV; + } + + hdd_stop_adapter(hdd_ctx, adapter, true); + + clear_bit(DEVICE_IFACE_OPENED, &adapter->event_flags); + /* Stop all tx queues */ + hdd_notice("Disabling queues"); + wlan_hdd_netif_queue_control(adapter, + WLAN_STOP_ALL_NETIF_QUEUE_N_CARRIER, + WLAN_CONTROL_PATH); + + EXIT(); + return 0; +} + +/** + * hdd_hostapd_stop() - SSR wrapper for__hdd_hostapd_stop + * @dev: pointer to net_device + * + * This is called in response to ifconfig down + * + * Return: 0 on success, error number otherwise + */ +int hdd_hostapd_stop(struct net_device *dev) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __hdd_hostapd_stop(dev); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __hdd_hostapd_uninit() - hdd uninit function + * This is called during the netdev unregister to uninitialize all data + * associated with the device. + * + * @dev: pointer to net_device structure + * + * Return: None + */ +static void __hdd_hostapd_uninit(struct net_device *dev) +{ + hdd_adapter_t *adapter = netdev_priv(dev); + hdd_context_t *hdd_ctx; + + ENTER_DEV(dev); + + if (WLAN_HDD_ADAPTER_MAGIC != adapter->magic) { + hdd_err("Invalid magic"); + return; + } + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + if (NULL == hdd_ctx) { + hdd_err("NULL hdd_ctx"); + return; + } + + hdd_deinit_adapter(hdd_ctx, adapter, true); + + /* after uninit our adapter structure will no longer be valid */ + adapter->dev = NULL; + adapter->magic = 0; + + EXIT(); +} + +/** + * hdd_hostapd_uninit() - SSR wrapper for __hdd_hostapd_uninit + * @dev: pointer to net_device + * + * Return: 0 on success, error number otherwise + */ +static void hdd_hostapd_uninit(struct net_device *dev) +{ + cds_ssr_protect(__func__); + __hdd_hostapd_uninit(dev); + cds_ssr_unprotect(__func__); +} + +/** + * __hdd_hostapd_change_mtu() - change mtu + * @dev: pointer to net_device + * @new_mtu: new mtu + * + * Return: 0 on success, error number otherwise + */ +static int __hdd_hostapd_change_mtu(struct net_device *dev, int new_mtu) +{ + ENTER_DEV(dev); + + return 0; +} + +/** + * hdd_hostapd_change_mtu() - SSR wrapper for __hdd_hostapd_change_mtu + * @dev: pointer to net_device + * @new_mtu: new mtu + * + * Return: 0 on success, error number otherwise + */ +static int hdd_hostapd_change_mtu(struct net_device *dev, int new_mtu) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __hdd_hostapd_change_mtu(dev, new_mtu); + cds_ssr_unprotect(__func__); + + return ret; +} + +#ifdef QCA_HT_2040_COEX +QDF_STATUS hdd_set_sap_ht2040_mode(hdd_adapter_t *pHostapdAdapter, + uint8_t channel_type) +{ + QDF_STATUS qdf_ret_status = QDF_STATUS_E_FAILURE; + void *hHal = NULL; + + hdd_err("change HT20/40 mode"); + + if (QDF_SAP_MODE == pHostapdAdapter->device_mode) { + hHal = WLAN_HDD_GET_HAL_CTX(pHostapdAdapter); + if (NULL == hHal) { + hdd_err("Hal ctx is null"); + return QDF_STATUS_E_FAULT; + } + qdf_ret_status = + sme_set_ht2040_mode(hHal, pHostapdAdapter->sessionId, + channel_type, true); + if (qdf_ret_status == QDF_STATUS_E_FAILURE) { + hdd_err("Failed to change HT20/40 mode"); + return QDF_STATUS_E_FAILURE; + } + } + return QDF_STATUS_SUCCESS; +} +#endif + +/** + * __hdd_hostapd_set_mac_address() - + * This function sets the user specified mac address using + * the command ifconfig wlanX hw ether . + * + * @dev: pointer to the net device. + * @addr: pointer to the sockaddr. + * + * Return: 0 for success, non zero for failure + */ +static int __hdd_hostapd_set_mac_address(struct net_device *dev, void *addr) +{ + struct sockaddr *psta_mac_addr = addr; + hdd_adapter_t *adapter; + hdd_context_t *hdd_ctx; + int ret = 0; + + ENTER_DEV(dev); + + adapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + memcpy(dev->dev_addr, psta_mac_addr->sa_data, ETH_ALEN); + EXIT(); + return 0; +} + +/** + * hdd_hostapd_set_mac_address() - set mac address + * @dev: pointer to net_device + * @addr: mac address + * + * Return: 0 on success, error number otherwise + */ +static int hdd_hostapd_set_mac_address(struct net_device *dev, void *addr) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __hdd_hostapd_set_mac_address(dev, addr); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * hdd_hostapd_inactivity_timer_cb() - Inactivity timeout handler + * @context: Context registered with qdf_mc_timer_init() + * + * This is the callback function registered with qdf_mc_timer_init() + * to handle the AP inactivity timer. The @context registered is the + * struct net_device associated with the interface. When this + * function is called it means the AP inactivity timer has fired, and + * this function in turn indicates the timeout to userspace. + */ + +static void hdd_hostapd_inactivity_timer_cb(void *context) +{ + struct net_device *dev = (struct net_device *)context; + uint8_t we_custom_event[64]; + union iwreq_data wrqu; +#ifdef DISABLE_CONCURRENCY_AUTOSAVE + QDF_STATUS qdf_status; + hdd_adapter_t *pHostapdAdapter; + hdd_ap_ctx_t *pHddApCtx; +#endif /* DISABLE_CONCURRENCY_AUTOSAVE */ + + /* event_name space-delimiter driver_module_name + * Format of the event is "AUTO-SHUT.indication" " " "module_name" + */ + char *autoShutEvent = "AUTO-SHUT.indication" " " KBUILD_MODNAME; + + /* For the NULL at the end */ + int event_len = strlen(autoShutEvent) + 1; + + ENTER_DEV(dev); + +#ifdef DISABLE_CONCURRENCY_AUTOSAVE + if (cds_concurrent_open_sessions_running()) { + /* + * This timer routine is going to be called only when AP + * persona is up. + * If there are concurrent sessions running we do not want + * to shut down the Bss.Instead we run the timer again so + * that if Autosave is enabled next time and other session + was down only then we bring down AP + */ + pHostapdAdapter = netdev_priv(dev); + if (WLAN_HDD_ADAPTER_MAGIC != pHostapdAdapter->magic) { + hdd_err("invalid adapter: %p", pHostapdAdapter); + return; + } + pHddApCtx = WLAN_HDD_GET_AP_CTX_PTR(pHostapdAdapter); + qdf_status = + qdf_mc_timer_start(&pHddApCtx->hdd_ap_inactivity_timer, + (WLAN_HDD_GET_CTX(pHostapdAdapter))-> + config->nAPAutoShutOff * 1000); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + hdd_err("Failed to init AP inactivity timer"); + } + EXIT(); + return; + } +#endif /* DISABLE_CONCURRENCY_AUTOSAVE */ + memset(&we_custom_event, '\0', sizeof(we_custom_event)); + memcpy(&we_custom_event, autoShutEvent, event_len); + + memset(&wrqu, 0, sizeof(wrqu)); + wrqu.data.length = event_len; + + hdd_notice("Shutting down AP interface due to inactivity"); + wireless_send_event(dev, IWEVCUSTOM, &wrqu, (char *)we_custom_event); + + EXIT(); +} + +static void hdd_clear_all_sta(hdd_adapter_t *pHostapdAdapter, + void *usrDataForCallback) +{ + uint8_t staId = 0; + struct net_device *dev; + struct tagCsrDelStaParams del_sta_params; + dev = (struct net_device *)usrDataForCallback; + + hdd_err("Clearing all the STA entry...."); + for (staId = 0; staId < WLAN_MAX_STA_COUNT; staId++) { + if (pHostapdAdapter->aStaInfo[staId].isUsed && + (staId != + (WLAN_HDD_GET_AP_CTX_PTR(pHostapdAdapter))->uBCStaId)) { + wlansap_populate_del_sta_params( + &pHostapdAdapter->aStaInfo[staId].macAddrSTA. + bytes[0], eSIR_MAC_DEAUTH_LEAVING_BSS_REASON, + (SIR_MAC_MGMT_DISASSOC >> 4), &del_sta_params); + + /* Disconnect all the stations */ + hdd_softap_sta_disassoc(pHostapdAdapter, + &del_sta_params); + } + } +} + +static int hdd_stop_bss_link(hdd_adapter_t *pHostapdAdapter, + void *usrDataForCallback) +{ + struct net_device *dev; + hdd_context_t *pHddCtx = NULL; + QDF_STATUS status = QDF_STATUS_SUCCESS; + dev = (struct net_device *)usrDataForCallback; + ENTER(); + + pHddCtx = WLAN_HDD_GET_CTX(pHostapdAdapter); + status = wlan_hdd_validate_context(pHddCtx); + + if (0 != status) + return status; + + if (test_bit(SOFTAP_BSS_STARTED, &pHostapdAdapter->event_flags)) { + status = wlansap_stop_bss( + WLAN_HDD_GET_SAP_CTX_PTR(pHostapdAdapter)); + if (QDF_IS_STATUS_SUCCESS(status)) + hdd_err("Deleting SAP/P2P link!!!!!!"); + + clear_bit(SOFTAP_BSS_STARTED, &pHostapdAdapter->event_flags); + cds_decr_session_set_pcl(pHostapdAdapter->device_mode, + pHostapdAdapter->sessionId); + } + EXIT(); + return (status == QDF_STATUS_SUCCESS) ? 0 : -EBUSY; +} + +/** + * hdd_issue_stored_joinreq() - This function will trigger stations's + * cached connect request to proceed. + * @hdd_ctx: pointer to hdd context. + * @sta_adater: pointer to station adapter. + * + * This function will call SME to release station's stored/cached connect + * request to proceed. + * + * Return: none. + */ +static void hdd_issue_stored_joinreq(hdd_adapter_t *sta_adapter, + hdd_context_t *hdd_ctx) +{ + tHalHandle hal_handle; + uint32_t roam_id; + + if (NULL == sta_adapter) { + hdd_err("Invalid station adapter, ignore issueing join req"); + return; + } + hal_handle = WLAN_HDD_GET_HAL_CTX(sta_adapter); + + if (true == cds_is_sta_connection_pending()) { + MTRACE(qdf_trace(QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_ISSUE_JOIN_REQ, + sta_adapter->sessionId, roam_id)); + if (QDF_STATUS_SUCCESS != + sme_issue_stored_joinreq(hal_handle, + &roam_id, + sta_adapter->sessionId)) { + /* change back to NotAssociated */ + hdd_conn_set_connection_state(sta_adapter, + eConnectionState_NotConnected); + } + cds_change_sta_conn_pending_status(false); + } +} + +/** + * hdd_chan_change_notify() - Function to notify hostapd about channel change + * @hostapd_adapter hostapd adapter + * @dev: Net device structure + * @chan_change: New channel change parameters + * + * This function is used to notify hostapd about the channel change + * + * Return: Success on intimating userspace + * + */ +QDF_STATUS hdd_chan_change_notify(hdd_adapter_t *adapter, + struct net_device *dev, + struct hdd_chan_change_params chan_change) +{ + struct ieee80211_channel *chan; + struct cfg80211_chan_def chandef; + enum nl80211_channel_type channel_type; + uint32_t freq; + tHalHandle hal = WLAN_HDD_GET_HAL_CTX(adapter); + + if (NULL == hal) { + hdd_err("hal is NULL"); + return QDF_STATUS_E_FAILURE; + } + + hdd_info("chan:%d width:%d sec_ch_offset:%d seg0:%d seg1:%d", + chan_change.chan, chan_change.chan_params.ch_width, + chan_change.chan_params.sec_ch_offset, + chan_change.chan_params.center_freq_seg0, + chan_change.chan_params.center_freq_seg1); + + freq = cds_chan_to_freq(chan_change.chan); + + chan = __ieee80211_get_channel(adapter->wdev.wiphy, freq); + + if (!chan) { + hdd_err("Invalid input frequency for channel conversion"); + return QDF_STATUS_E_FAILURE; + } + + switch (chan_change.chan_params.sec_ch_offset) { + case PHY_SINGLE_CHANNEL_CENTERED: + channel_type = NL80211_CHAN_HT20; + break; + case PHY_DOUBLE_CHANNEL_HIGH_PRIMARY: + channel_type = NL80211_CHAN_HT40MINUS; + break; + case PHY_DOUBLE_CHANNEL_LOW_PRIMARY: + channel_type = NL80211_CHAN_HT40PLUS; + break; + default: + channel_type = NL80211_CHAN_NO_HT; + break; + } + + cfg80211_chandef_create(&chandef, chan, channel_type); + + /* cfg80211_chandef_create() does update of width and center_freq1 + * only for NL80211_CHAN_NO_HT, NL80211_CHAN_HT20, NL80211_CHAN_HT40PLUS + * and NL80211_CHAN_HT40MINUS. + */ + if (chan_change.chan_params.ch_width == CH_WIDTH_80MHZ) + chandef.width = NL80211_CHAN_WIDTH_80; + else if (chan_change.chan_params.ch_width == CH_WIDTH_80P80MHZ) + chandef.width = NL80211_CHAN_WIDTH_80P80; + else if (chan_change.chan_params.ch_width == CH_WIDTH_160MHZ) + chandef.width = NL80211_CHAN_WIDTH_160; + + if ((chan_change.chan_params.ch_width == CH_WIDTH_80MHZ) || + (chan_change.chan_params.ch_width == CH_WIDTH_80P80MHZ) || + (chan_change.chan_params.ch_width == CH_WIDTH_160MHZ)) { + if (chan_change.chan_params.center_freq_seg0) + chandef.center_freq1 = cds_chan_to_freq( + chan_change.chan_params.center_freq_seg0); + + if (chan_change.chan_params.center_freq_seg1) + chandef.center_freq2 = cds_chan_to_freq( + chan_change.chan_params.center_freq_seg1); + } + + hdd_info("notify: chan:%d width:%d freq1:%d freq2:%d", + chandef.chan->center_freq, chandef.width, chandef.center_freq1, + chandef.center_freq2); + + cfg80211_ch_switch_notify(dev, &chandef); + + return QDF_STATUS_SUCCESS; +} + +/** + * hdd_send_radar_event() - Function to send radar events to user space + * @hdd_context: HDD context + * @event: Type of radar event + * @dfs_info: Structure containing DFS channel and country + * @wdev: Wireless device structure + * + * This function is used to send radar events such as CAC start, CAC + * end etc., to userspace + * + * Return: Success on sending notifying userspace + * + */ +static QDF_STATUS hdd_send_radar_event(hdd_context_t *hdd_context, + eSapHddEvent event, + struct wlan_dfs_info dfs_info, + struct wireless_dev *wdev) +{ + + struct sk_buff *vendor_event; + enum qca_nl80211_vendor_subcmds_index index; + uint32_t freq, ret; + uint32_t data_size; + + if (!hdd_context) { + hdd_err("HDD context is NULL"); + return QDF_STATUS_E_FAILURE; + } + + freq = cds_chan_to_freq(dfs_info.channel); + + switch (event) { + case eSAP_DFS_CAC_START: + index = + QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_STARTED_INDEX; + data_size = sizeof(uint32_t); + break; + case eSAP_DFS_CAC_END: + index = + QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_FINISHED_INDEX; + data_size = sizeof(uint32_t); + break; + case eSAP_DFS_RADAR_DETECT: + index = + QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_RADAR_DETECTED_INDEX; + data_size = sizeof(uint32_t); + break; + default: + return QDF_STATUS_E_FAILURE; + } + + vendor_event = cfg80211_vendor_event_alloc(hdd_context->wiphy, + wdev, + data_size + NLMSG_HDRLEN, + index, + GFP_KERNEL); + if (!vendor_event) { + hdd_err("cfg80211_vendor_event_alloc failed for %d", index); + return QDF_STATUS_E_FAILURE; + } + + ret = nla_put_u32(vendor_event, NL80211_ATTR_WIPHY_FREQ, freq); + + if (ret) { + hdd_err("NL80211_ATTR_WIPHY_FREQ put fail"); + kfree_skb(vendor_event); + return QDF_STATUS_E_FAILURE; + } + + cfg80211_vendor_event(vendor_event, GFP_KERNEL); + return QDF_STATUS_SUCCESS; +} + +/** + * hdd_send_conditional_chan_switch_status() - Send conditional channel switch + * status + * @hdd_ctx: HDD context + * @wdev: Wireless device structure + * @status: Status of conditional channel switch + * (0: Success, Non-zero: Failure) + * + * Sends the status of conditional channel switch to user space. This is named + * conditional channel switch because the SAP will move to the provided channel + * after some condition (pre-cac) is met. + * + * Return: None + */ +static void hdd_send_conditional_chan_switch_status(hdd_context_t *hdd_ctx, + struct wireless_dev *wdev, + bool status) +{ + struct sk_buff *event; + + ENTER_DEV(wdev->netdev); + + if (!hdd_ctx) { + hdd_err("Invalid HDD context pointer"); + return; + } + + event = cfg80211_vendor_event_alloc(hdd_ctx->wiphy, + wdev, sizeof(uint32_t) + NLMSG_HDRLEN, + QCA_NL80211_VENDOR_SUBCMD_SAP_CONDITIONAL_CHAN_SWITCH_INDEX, + GFP_KERNEL); + if (!event) { + hdd_err("cfg80211_vendor_event_alloc failed"); + return; + } + + if (nla_put_u32(event, + QCA_WLAN_VENDOR_ATTR_SAP_CONDITIONAL_CHAN_SWITCH_STATUS, + status)) { + hdd_err("nla put failed"); + kfree_skb(event); + return; + } + + cfg80211_vendor_event(event, GFP_KERNEL); +} + +/** + * wlan_hdd_set_pre_cac_complete_status() - Set pre cac complete status + * @ap_adapter: AP adapter + * @status: Status which can be true or false + * + * Sets the status of pre cac i.e., whether it is complete or not + * + * Return: Zero on success, non-zero on failure + */ +static int wlan_hdd_set_pre_cac_complete_status(hdd_adapter_t *ap_adapter, + bool status) +{ + QDF_STATUS ret; + + ret = wlan_sap_set_pre_cac_complete_status( + WLAN_HDD_GET_SAP_CTX_PTR(ap_adapter), status); + if (QDF_IS_STATUS_ERROR(ret)) + return -EINVAL; + + return 0; +} + +/** + * wlan_hdd_sap_pre_cac_failure() - Process the pre cac failure + * @data: AP adapter + * + * Deletes the pre cac adapter + * + * Return: None + */ +void wlan_hdd_sap_pre_cac_failure(void *data) +{ + hdd_adapter_t *pHostapdAdapter; + hdd_context_t *hdd_ctx; + + ENTER(); + + pHostapdAdapter = (hdd_adapter_t *) data; + if (!pHostapdAdapter) { + hdd_err("AP adapter is NULL"); + return; + } + + hdd_ctx = (hdd_context_t *) (pHostapdAdapter->pHddCtx); + if (!hdd_ctx) { + hdd_err("HDD context is null"); + return; + } + + cds_ssr_protect(__func__); + wlan_hdd_release_intf_addr(hdd_ctx, + pHostapdAdapter->macAddressCurrent.bytes); + hdd_stop_adapter(hdd_ctx, pHostapdAdapter, true); + hdd_close_adapter(hdd_ctx, pHostapdAdapter, false); + cds_ssr_unprotect(__func__); +} + + +/** + * wlan_hdd_sap_pre_cac_success() - Process the pre cac result + * @data: AP adapter + * + * Deletes the pre cac adapter and moves the existing SAP to the pre cac + * channel + * + * Return: None + */ +static void wlan_hdd_sap_pre_cac_success(void *data) +{ + hdd_adapter_t *pHostapdAdapter, *ap_adapter; + int i; + hdd_context_t *hdd_ctx; + + ENTER(); + + pHostapdAdapter = (hdd_adapter_t *) data; + if (!pHostapdAdapter) { + hdd_err("AP adapter is NULL"); + return; + } + + hdd_ctx = (hdd_context_t *) (pHostapdAdapter->pHddCtx); + if (!hdd_ctx) { + hdd_err("HDD context is null"); + return; + } + + cds_ssr_protect(__func__); + wlan_hdd_release_intf_addr(hdd_ctx, + pHostapdAdapter->macAddressCurrent.bytes); + hdd_stop_adapter(hdd_ctx, pHostapdAdapter, true); + hdd_close_adapter(hdd_ctx, pHostapdAdapter, false); + cds_ssr_unprotect(__func__); + + /* Prepare to switch AP from 2.4GHz channel to the pre CAC channel */ + ap_adapter = hdd_get_adapter(hdd_ctx, QDF_SAP_MODE); + if (!ap_adapter) { + hdd_err("failed to get SAP adapter, no restart on pre CAC channel"); + return; + } + + /* + * Setting of the pre cac complete status will ensure that on channel + * switch to the pre CAC DFS channel, there is no CAC again. + */ + wlan_hdd_set_pre_cac_complete_status(ap_adapter, true); + i = hdd_softap_set_channel_change(ap_adapter->dev, + ap_adapter->pre_cac_chan, + CH_WIDTH_MAX); + if (0 != i) { + hdd_err("failed to change channel"); + wlan_hdd_set_pre_cac_complete_status(ap_adapter, false); + } +} + +#ifdef FEATURE_WLAN_AP_AP_ACS_OPTIMIZE +/** + * hdd_handle_acs_scan_event() - handle acs scan event for SAP + * @sap_event: tpSap_Event + * @adapter: hdd_adapter_t for SAP + * + * The function is to handle the eSAP_ACS_SCAN_SUCCESS_EVENT event. + * It will update scan result to cfg80211 and start a timer to flush the + * cached acs scan result. + * + * Return: QDF_STATUS_SUCCESS on success, + * other value on failure + */ +static QDF_STATUS hdd_handle_acs_scan_event(tpSap_Event sap_event, + hdd_adapter_t *adapter) +{ + hdd_context_t *hdd_ctx; + struct sap_acs_scan_complete_event *comp_evt; + QDF_STATUS qdf_status; + int chan_list_size; + + hdd_ctx = (hdd_context_t *)(adapter->pHddCtx); + if (!hdd_ctx) { + hdd_err("HDD context is null"); + return QDF_STATUS_E_FAILURE; + } + comp_evt = &sap_event->sapevt.sap_acs_scan_comp; + hdd_ctx->skip_acs_scan_status = eSAP_SKIP_ACS_SCAN; + qdf_spin_lock(&hdd_ctx->acs_skip_lock); + qdf_mem_free(hdd_ctx->last_acs_channel_list); + hdd_ctx->last_acs_channel_list = NULL; + hdd_ctx->num_of_channels = 0; + /* cache the previous ACS scan channel list . + * If the following OBSS scan chan list is covered by ACS chan list, + * we can skip OBSS Scan to save SAP starting total time. + */ + if (comp_evt->num_of_channels && comp_evt->channellist) { + chan_list_size = comp_evt->num_of_channels * + sizeof(comp_evt->channellist[0]); + hdd_ctx->last_acs_channel_list = qdf_mem_malloc( + chan_list_size); + if (hdd_ctx->last_acs_channel_list) { + qdf_mem_copy(hdd_ctx->last_acs_channel_list, + comp_evt->channellist, + chan_list_size); + hdd_ctx->num_of_channels = comp_evt->num_of_channels; + } + } + qdf_spin_unlock(&hdd_ctx->acs_skip_lock); + /* Update ACS scan result to cfg80211. Then OBSS scan can reuse the + * scan result. + */ + if (wlan_hdd_cfg80211_update_bss(hdd_ctx->wiphy, adapter, 0)) + hdd_info("NO SCAN result"); + + hdd_info("Reusing Last ACS scan result for %d sec", + ACS_SCAN_EXPIRY_TIMEOUT_S); + qdf_mc_timer_stop(&hdd_ctx->skip_acs_scan_timer); + qdf_status = qdf_mc_timer_start(&hdd_ctx->skip_acs_scan_timer, + ACS_SCAN_EXPIRY_TIMEOUT_S * 1000); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) + hdd_err("Failed to start ACS scan expiry timer"); + return QDF_STATUS_SUCCESS; +} +#else +static QDF_STATUS hdd_handle_acs_scan_event(tpSap_Event sap_event, + hdd_adapter_t *adapter) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +/** + * hdd_update_scan_result() - Update the scan result to CFG80211 + * @sap_event: SAP event + * @adapter: adapter for SAP + * + * The function is to update the scan result to CFG80211 + * + * Return: QDF_STATUS_SUCCESS on success, + * other value on failure + */ +static QDF_STATUS hdd_update_scan_result(tpSap_Event sap_event, + hdd_adapter_t *adapter) +{ + struct cfg80211_bss *bss_status; + + if (NULL != sap_event->sapevt.bss_desc) { + bss_status = wlan_hdd_cfg80211_inform_bss_frame( + adapter, + sap_event->sapevt.bss_desc); + if (NULL == bss_status) { + hdd_info("UPDATE_SCAN_RESULT returned NULL"); + return QDF_STATUS_E_FAILURE; + } else { + cfg80211_put_bss( +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0)) || defined(WITH_BACKPORTS) + (WLAN_HDD_GET_CTX(adapter))->wiphy, +#endif + bss_status); + } + } + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS hdd_hostapd_sap_event_cb(tpSap_Event pSapEvent, + void *usrDataForCallback) +{ + hdd_adapter_t *pHostapdAdapter; + hdd_ap_ctx_t *pHddApCtx; + hdd_hostapd_state_t *pHostapdState; + struct net_device *dev; + eSapHddEvent sapEvent; + union iwreq_data wrqu; + uint8_t *we_custom_event_generic = NULL; + int we_event = 0; + int i = 0; + uint8_t staId; + QDF_STATUS qdf_status; + bool bWPSState; + bool bAuthRequired = true; + tpSap_AssocMacAddr pAssocStasArray = NULL; + char unknownSTAEvent[IW_CUSTOM_MAX + 1]; + char maxAssocExceededEvent[IW_CUSTOM_MAX + 1]; + uint8_t we_custom_start_event[64]; + char *startBssEvent; + hdd_context_t *pHddCtx; + hdd_scaninfo_t *pScanInfo = NULL; + struct iw_michaelmicfailure msg; + uint8_t ignoreCAC = 0; + struct hdd_config *cfg = NULL; + struct wlan_dfs_info dfs_info; + uint8_t cc_len = WLAN_SVC_COUNTRY_CODE_LEN; + hdd_adapter_t *con_sap_adapter; + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct hdd_chan_change_params chan_change; + int ret = 0; + + dev = (struct net_device *)usrDataForCallback; + if (!dev) { + hdd_err("usrDataForCallback is null"); + return QDF_STATUS_E_FAILURE; + } + + pHostapdAdapter = netdev_priv(dev); + + if ((NULL == pHostapdAdapter) || + (WLAN_HDD_ADAPTER_MAGIC != pHostapdAdapter->magic)) { + hdd_err("invalid adapter or adapter has invalid magic"); + return QDF_STATUS_E_FAILURE; + } + + pHostapdState = WLAN_HDD_GET_HOSTAP_STATE_PTR(pHostapdAdapter); + pHddApCtx = WLAN_HDD_GET_AP_CTX_PTR(pHostapdAdapter); + + if (!pSapEvent) { + hdd_err("pSapEvent is null"); + return QDF_STATUS_E_FAILURE; + } + + sapEvent = pSapEvent->sapHddEventCode; + memset(&wrqu, '\0', sizeof(wrqu)); + pHddCtx = (hdd_context_t *) (pHostapdAdapter->pHddCtx); + + if (!pHddCtx) { + hdd_err("HDD context is null"); + return QDF_STATUS_E_FAILURE; + } + + cfg = pHddCtx->config; + + if (!cfg) { + hdd_err("HDD config is null"); + return QDF_STATUS_E_FAILURE; + } + + dfs_info.channel = pHddApCtx->operatingChannel; + sme_get_country_code(pHddCtx->hHal, dfs_info.country_code, &cc_len); + + switch (sapEvent) { + case eSAP_START_BSS_EVENT: + hdd_notice("BSS status = %s, channel = %u, bc sta Id = %d", + pSapEvent->sapevt.sapStartBssCompleteEvent. + status ? "eSAP_STATUS_FAILURE" : "eSAP_STATUS_SUCCESS", + pSapEvent->sapevt.sapStartBssCompleteEvent. + operatingChannel, + pSapEvent->sapevt.sapStartBssCompleteEvent.staId); + + pHostapdAdapter->sessionId = + pSapEvent->sapevt.sapStartBssCompleteEvent.sessionId; + + pHostapdState->qdf_status = + pSapEvent->sapevt.sapStartBssCompleteEvent.status; + + qdf_atomic_set(&pHddCtx->dfs_radar_found, 0); + wlansap_get_dfs_ignore_cac(pHddCtx->hHal, &ignoreCAC); + + /* DFS requirement: DO NOT transmit during CAC. */ + if ((CHANNEL_STATE_DFS != + cds_get_channel_state(pHddApCtx->operatingChannel)) + || ignoreCAC + || pHddCtx->dev_dfs_cac_status == DFS_CAC_ALREADY_DONE) + pHddApCtx->dfs_cac_block_tx = false; + else + pHddApCtx->dfs_cac_block_tx = true; + + hdd_debug("The value of dfs_cac_block_tx[%d] for ApCtx[%p]:%d", + pHddApCtx->dfs_cac_block_tx, pHddApCtx, + pHostapdAdapter->sessionId); + + if (pHostapdState->qdf_status) { + hdd_err("ERROR: startbss event failed!!"); + /* + * Make sure to set the event before proceeding + * for error handling otherwise caller thread will + * wait till 10 secs and no other connection will + * go through before that. + */ + pHostapdState->bssState = BSS_STOP; + qdf_event_set(&pHostapdState->qdf_event); + goto stopbss; + } else { + sme_ch_avoid_update_req(pHddCtx->hHal); + + pHddApCtx->uBCStaId = + pSapEvent->sapevt.sapStartBssCompleteEvent.staId; + + hdd_register_tx_flow_control(pHostapdAdapter, + hdd_softap_tx_resume_timer_expired_handler, + hdd_softap_tx_resume_cb); + + /* @@@ need wep logic here to set privacy bit */ + qdf_status = + hdd_softap_register_bc_sta(pHostapdAdapter, + pHddApCtx->uPrivacy); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + hdd_warn("Failed to register BC STA %d", + qdf_status); + hdd_stop_bss_link(pHostapdAdapter, + usrDataForCallback); + } + } + + if (hdd_ipa_is_enabled(pHddCtx)) { + status = hdd_ipa_wlan_evt(pHostapdAdapter, + pHddApCtx->uBCStaId, + HDD_IPA_AP_CONNECT, + pHostapdAdapter->dev->dev_addr); + if (status) { + hdd_err("WLAN_AP_CONNECT event failed!!"); + /* + * Make sure to set the event before proceeding + * for error handling otherwise caller thread + * will wait till 10 secs and no other + * connection will go through before that. + */ + qdf_event_set(&pHostapdState->qdf_event); + goto stopbss; + } + } + + if (0 != + (WLAN_HDD_GET_CTX(pHostapdAdapter))->config-> + nAPAutoShutOff) { + /* AP Inactivity timer init and start */ + qdf_status = + qdf_mc_timer_init(&pHddApCtx-> + hdd_ap_inactivity_timer, + QDF_TIMER_TYPE_SW, + hdd_hostapd_inactivity_timer_cb, + dev); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) + hdd_err("Failed to init inactivity timer"); + + qdf_status = + qdf_mc_timer_start(&pHddApCtx-> + hdd_ap_inactivity_timer, + (WLAN_HDD_GET_CTX + (pHostapdAdapter))->config-> + nAPAutoShutOff * 1000); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) + hdd_err("Failed to init inactivity timer"); + + } +#ifdef FEATURE_WLAN_AUTO_SHUTDOWN + wlan_hdd_auto_shutdown_enable(pHddCtx, true); +#endif + pHddApCtx->operatingChannel = + pSapEvent->sapevt.sapStartBssCompleteEvent.operatingChannel; + + hdd_hostapd_channel_prevent_suspend(pHostapdAdapter, + pHddApCtx-> + operatingChannel); + + pHostapdState->bssState = BSS_START; + + /* Set default key index */ + QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO, + "%s: default key index %hu", __func__, + pHddApCtx->wep_def_key_idx); + + sme_roam_set_default_key_index( + WLAN_HDD_GET_HAL_CTX(pHostapdAdapter), + pHostapdAdapter->sessionId, + pHddApCtx->wep_def_key_idx); + + /* Set group key / WEP key every time when BSS is restarted */ + if (pHddApCtx->groupKey.keyLength) { + status = wlansap_set_key_sta( + WLAN_HDD_GET_SAP_CTX_PTR(pHostapdAdapter), + &pHddApCtx->groupKey); + if (!QDF_IS_STATUS_SUCCESS(status)) + hdd_err("wlansap_set_key_sta failed"); + } else { + for (i = 0; i < CSR_MAX_NUM_KEY; i++) { + if (!pHddApCtx->wepKey[i].keyLength) + continue; + + status = wlansap_set_key_sta( + WLAN_HDD_GET_SAP_CTX_PTR + (pHostapdAdapter), + &pHddApCtx->wepKey[i]); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("set_key failed idx %d", i); + } + } + } + + + if ((CHANNEL_STATE_DFS == + cds_get_channel_state(pHddApCtx->operatingChannel)) + && (pHddCtx->config->IsSapDfsChSifsBurstEnabled == 0)) { + + hdd_notice("Set SIFS Burst disable for DFS channel %d", + pHddApCtx->operatingChannel); + + if (wma_cli_set_command(pHostapdAdapter->sessionId, + WMI_PDEV_PARAM_BURST_ENABLE, + 0, PDEV_CMD)) { + hdd_err("Failed to Set SIFS Burst %d", + pHddApCtx->operatingChannel); + } + } + /* Fill the params for sending IWEVCUSTOM Event with SOFTAP.enabled */ + startBssEvent = "SOFTAP.enabled"; + memset(&we_custom_start_event, '\0', + sizeof(we_custom_start_event)); + memcpy(&we_custom_start_event, startBssEvent, + strlen(startBssEvent)); + memset(&wrqu, 0, sizeof(wrqu)); + wrqu.data.length = strlen(startBssEvent); + we_event = IWEVCUSTOM; + we_custom_event_generic = we_custom_start_event; + cds_dump_concurrency_info(); + /* Send SCC/MCC Switching event to IPA */ + hdd_ipa_send_mcc_scc_msg(pHddCtx, pHddCtx->mcc_mode); + + if (cds_is_hw_mode_change_after_vdev_up()) { + hdd_info("check for possible hw mode change"); + status = cds_set_hw_mode_on_channel_switch( + pHostapdAdapter->sessionId); + if (QDF_IS_STATUS_ERROR(status)) + hdd_info("set hw mode change not done"); + cds_set_do_hw_mode_change_flag(false); + } + /* + * set this event at the very end because once this events + * get set, caller thread is waiting to do further processing. + * so once this event gets set, current worker thread might get + * pre-empted by caller thread. + */ + qdf_status = qdf_event_set(&pHostapdState->qdf_event); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + hdd_err("ERROR: startbss event set failed!!"); + goto stopbss; + } + break; /* Event will be sent after Switch-Case stmt */ + + case eSAP_STOP_BSS_EVENT: + hdd_notice("BSS stop status = %s", + pSapEvent->sapevt.sapStopBssCompleteEvent. + status ? "eSAP_STATUS_FAILURE" : "eSAP_STATUS_SUCCESS"); + + hdd_hostapd_channel_allow_suspend(pHostapdAdapter, + pHddApCtx->operatingChannel); + + /* Free up Channel List incase if it is set */ + sap_cleanup_channel_list( + WLAN_HDD_GET_SAP_CTX_PTR(pHostapdAdapter)); + + /* Invalidate the channel info. */ + pHddApCtx->operatingChannel = 0; + if (hdd_ipa_is_enabled(pHddCtx)) { + status = hdd_ipa_wlan_evt(pHostapdAdapter, + pHddApCtx->uBCStaId, + HDD_IPA_AP_DISCONNECT, + pHostapdAdapter->dev->dev_addr); + if (status) { + hdd_err("WLAN_AP_DISCONNECT event failed!!"); + goto stopbss; + } + } + + /* reset the dfs_cac_status and dfs_cac_block_tx flag only when + * the last BSS is stopped + */ + con_sap_adapter = hdd_get_con_sap_adapter(pHostapdAdapter, true); + if (!con_sap_adapter) { + pHddApCtx->dfs_cac_block_tx = true; + pHddCtx->dev_dfs_cac_status = DFS_CAC_NEVER_DONE; + } + if (pHddCtx->config->conc_custom_rule2 && + (QDF_P2P_GO_MODE == pHostapdAdapter->device_mode)) { + hdd_adapter_t *sta_adapter = hdd_get_adapter(pHddCtx, + QDF_STA_MODE); + hdd_info("P2PGO is going down now"); + hdd_issue_stored_joinreq(sta_adapter, pHddCtx); + } + + hdd_info("bss_stop_reason=%d", pHddApCtx->bss_stop_reason); + if (pHddApCtx->bss_stop_reason != + BSS_STOP_DUE_TO_MCC_SCC_SWITCH) { + /* when MCC to SCC switching happens, key storage + * should not be cleared due to hostapd will not + * repopulate the original keys + */ + pHddApCtx->groupKey.keyLength = 0; + for (i = 0; i < CSR_MAX_NUM_KEY; i++) + pHddApCtx->wepKey[i].keyLength = 0; + } + + /* clear the reason code in case BSS is stopped + * in another place + */ + pHddApCtx->bss_stop_reason = BSS_STOP_REASON_INVALID; + goto stopbss; + + case eSAP_DFS_CAC_START: + wlan_hdd_send_svc_nlink_msg(pHddCtx->radio_index, + WLAN_SVC_DFS_CAC_START_IND, + &dfs_info, + sizeof(struct wlan_dfs_info)); + pHddCtx->dev_dfs_cac_status = DFS_CAC_IN_PROGRESS; + if (QDF_STATUS_SUCCESS != + hdd_send_radar_event(pHddCtx, eSAP_DFS_CAC_START, + dfs_info, &pHostapdAdapter->wdev)) { + hdd_err("Unable to indicate CAC start NL event"); + } else { + hdd_info("Sent CAC start to user space"); + } + + qdf_atomic_set(&pHddCtx->dfs_radar_found, 0); + break; + case eSAP_DFS_CAC_INTERRUPTED: + /* + * The CAC timer did not run completely and a radar was detected + * during the CAC time. This new state will keep the tx path + * blocked since we do not want any transmission on the DFS + * channel. CAC end will only be reported here since the user + * space applications are waiting on CAC end for their state + * management. + */ + if (QDF_STATUS_SUCCESS != + hdd_send_radar_event(pHddCtx, eSAP_DFS_CAC_END, + dfs_info, &pHostapdAdapter->wdev)) { + hdd_err("Unable to indicate CAC end (interrupted) event"); + } else { + hdd_info("Sent CAC end (interrupted) to user space"); + } + break; + case eSAP_DFS_CAC_END: + wlan_hdd_send_svc_nlink_msg(pHddCtx->radio_index, + WLAN_SVC_DFS_CAC_END_IND, + &dfs_info, + sizeof(struct wlan_dfs_info)); + pHddApCtx->dfs_cac_block_tx = false; + pHddCtx->dev_dfs_cac_status = DFS_CAC_ALREADY_DONE; + if (QDF_STATUS_SUCCESS != + hdd_send_radar_event(pHddCtx, eSAP_DFS_CAC_END, + dfs_info, &pHostapdAdapter->wdev)) { + hdd_err("Unable to indicate CAC end NL event"); + } else { + hdd_info("Sent CAC end to user space"); + } + break; + case eSAP_DFS_RADAR_DETECT: + wlan_hdd_send_svc_nlink_msg(pHddCtx->radio_index, + WLAN_SVC_DFS_RADAR_DETECT_IND, + &dfs_info, + sizeof(struct wlan_dfs_info)); + pHddCtx->dev_dfs_cac_status = DFS_CAC_NEVER_DONE; + if (QDF_STATUS_SUCCESS != + hdd_send_radar_event(pHddCtx, eSAP_DFS_RADAR_DETECT, + dfs_info, &pHostapdAdapter->wdev)) { + hdd_err("Unable to indicate Radar detect NL event"); + } else { + hdd_info("Sent radar detected to user space"); + } + break; + case eSAP_DFS_RADAR_DETECT_DURING_PRE_CAC: + hdd_debug("notification for radar detect during pre cac:%d", + pHostapdAdapter->sessionId); + hdd_send_conditional_chan_switch_status(pHddCtx, + &pHostapdAdapter->wdev, false); + pHddCtx->dev_dfs_cac_status = DFS_CAC_NEVER_DONE; + qdf_create_work(0, &pHddCtx->sap_pre_cac_work, + wlan_hdd_sap_pre_cac_failure, + (void *)pHostapdAdapter); + qdf_sched_work(0, &pHddCtx->sap_pre_cac_work); + break; + case eSAP_DFS_PRE_CAC_END: + hdd_debug("pre cac end notification received:%d", + pHostapdAdapter->sessionId); + hdd_send_conditional_chan_switch_status(pHddCtx, + &pHostapdAdapter->wdev, true); + pHddApCtx->dfs_cac_block_tx = false; + pHddCtx->dev_dfs_cac_status = DFS_CAC_ALREADY_DONE; + + qdf_create_work(0, &pHddCtx->sap_pre_cac_work, + wlan_hdd_sap_pre_cac_success, + (void *)pHostapdAdapter); + qdf_sched_work(0, &pHddCtx->sap_pre_cac_work); + break; + case eSAP_DFS_NO_AVAILABLE_CHANNEL: + wlan_hdd_send_svc_nlink_msg + (pHddCtx->radio_index, + WLAN_SVC_DFS_ALL_CHANNEL_UNAVAIL_IND, &dfs_info, + sizeof(struct wlan_dfs_info)); + break; + + case eSAP_STA_SET_KEY_EVENT: + /* TODO: + * forward the message to hostapd once implementation + * is done for now just print + */ + hdd_notice("SET Key: configured status = %s", + pSapEvent->sapevt.sapStationSetKeyCompleteEvent. + status ? "eSAP_STATUS_FAILURE" : "eSAP_STATUS_SUCCESS"); + return QDF_STATUS_SUCCESS; + case eSAP_STA_MIC_FAILURE_EVENT: + { + memset(&msg, '\0', sizeof(msg)); + msg.src_addr.sa_family = ARPHRD_ETHER; + memcpy(msg.src_addr.sa_data, + &pSapEvent->sapevt.sapStationMICFailureEvent. + staMac, QDF_MAC_ADDR_SIZE); + hdd_notice("MIC MAC " MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(msg.src_addr.sa_data)); + if (pSapEvent->sapevt.sapStationMICFailureEvent. + multicast == eSAP_TRUE) + msg.flags = IW_MICFAILURE_GROUP; + else + msg.flags = IW_MICFAILURE_PAIRWISE; + memset(&wrqu, 0, sizeof(wrqu)); + wrqu.data.length = sizeof(msg); + we_event = IWEVMICHAELMICFAILURE; + we_custom_event_generic = (uint8_t *) &msg; + } + /* inform mic failure to nl80211 */ + cfg80211_michael_mic_failure(dev, + pSapEvent-> + sapevt.sapStationMICFailureEvent. + staMac.bytes, + ((pSapEvent->sapevt. + sapStationMICFailureEvent. + multicast == + eSAP_TRUE) ? + NL80211_KEYTYPE_GROUP : + NL80211_KEYTYPE_PAIRWISE), + pSapEvent->sapevt. + sapStationMICFailureEvent.keyId, + pSapEvent->sapevt. + sapStationMICFailureEvent.TSC, + GFP_KERNEL); + break; + + case eSAP_STA_ASSOC_EVENT: + case eSAP_STA_REASSOC_EVENT: + wrqu.addr.sa_family = ARPHRD_ETHER; + memcpy(wrqu.addr.sa_data, + &pSapEvent->sapevt.sapStationAssocReassocCompleteEvent. + staMac, QDF_MAC_ADDR_SIZE); + hdd_notice(" associated " MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(wrqu.addr.sa_data)); + we_event = IWEVREGISTERED; + + wlansap_get_wps_state( + WLAN_HDD_GET_SAP_CTX_PTR(pHostapdAdapter), + &bWPSState); + + if ((eCSR_ENCRYPT_TYPE_NONE == pHddApCtx->ucEncryptType) || + (eCSR_ENCRYPT_TYPE_WEP40_STATICKEY == + pHddApCtx->ucEncryptType) + || (eCSR_ENCRYPT_TYPE_WEP104_STATICKEY == + pHddApCtx->ucEncryptType)) { + bAuthRequired = false; + } + + if (bAuthRequired || bWPSState == true) { + qdf_status = hdd_softap_register_sta( + pHostapdAdapter, + true, + pHddApCtx->uPrivacy, + pSapEvent->sapevt. + sapStationAssocReassocCompleteEvent. + staId, 0, 0, + (struct qdf_mac_addr *) + wrqu.addr.sa_data, + pSapEvent->sapevt. + sapStationAssocReassocCompleteEvent. + wmmEnabled); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) + hdd_warn("Failed to register STA %d " + MAC_ADDRESS_STR "", qdf_status, + MAC_ADDR_ARRAY(wrqu.addr.sa_data)); + } else { + qdf_status = hdd_softap_register_sta( + pHostapdAdapter, + false, + pHddApCtx->uPrivacy, + pSapEvent->sapevt. + sapStationAssocReassocCompleteEvent. + staId, 0, 0, + (struct qdf_mac_addr *) + wrqu.addr.sa_data, + pSapEvent->sapevt. + sapStationAssocReassocCompleteEvent. + wmmEnabled); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) + hdd_warn("Failed to register STA %d " + MAC_ADDRESS_STR "", qdf_status, + MAC_ADDR_ARRAY(wrqu.addr.sa_data)); + } + + staId = + pSapEvent->sapevt.sapStationAssocReassocCompleteEvent.staId; + if (QDF_IS_STATUS_SUCCESS(qdf_status)) { + pHostapdAdapter->aStaInfo[staId].nss = + pSapEvent->sapevt. + sapStationAssocReassocCompleteEvent. + chan_info.nss; + pHostapdAdapter->aStaInfo[staId].rate_flags = + pSapEvent->sapevt. + sapStationAssocReassocCompleteEvent. + chan_info.rate_flags; + } + + if (hdd_ipa_is_enabled(pHddCtx)) { + status = hdd_ipa_wlan_evt(pHostapdAdapter, + pSapEvent->sapevt. + sapStationAssocReassocCompleteEvent. + staId, HDD_IPA_CLIENT_CONNECT_EX, + pSapEvent->sapevt. + sapStationAssocReassocCompleteEvent. + staMac.bytes); + if (status) { + hdd_err("WLAN_CLIENT_CONNECT_EX event failed"); + goto stopbss; + } + } + + DPTRACE(qdf_dp_trace_mgmt_pkt(QDF_DP_TRACE_MGMT_PACKET_RECORD, + pHostapdAdapter->sessionId, + QDF_PROTO_TYPE_MGMT, QDF_PROTO_MGMT_ASSOC)); + +#ifdef MSM_PLATFORM + /* start timer in sap/p2p_go */ + if (pHddApCtx->bApActive == false) { + spin_lock_bh(&pHddCtx->bus_bw_lock); + pHostapdAdapter->prev_tx_packets = + pHostapdAdapter->stats.tx_packets; + pHostapdAdapter->prev_rx_packets = + pHostapdAdapter->stats.rx_packets; + ol_get_intra_bss_fwd_pkts_count( + pHostapdAdapter->sessionId, + &pHostapdAdapter->prev_fwd_tx_packets, + &pHostapdAdapter->prev_fwd_rx_packets); + spin_unlock_bh(&pHddCtx->bus_bw_lock); + hdd_bus_bw_compute_timer_start(pHddCtx); + } +#endif + pHddApCtx->bApActive = true; + /* Stop AP inactivity timer */ + if (pHddApCtx->hdd_ap_inactivity_timer.state == + QDF_TIMER_STATE_RUNNING) { + qdf_status = + qdf_mc_timer_stop(&pHddApCtx-> + hdd_ap_inactivity_timer); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + hdd_err("Failed to start inactivity timer"); + } + } +#ifdef FEATURE_WLAN_AUTO_SHUTDOWN + wlan_hdd_auto_shutdown_enable(pHddCtx, false); +#endif + cds_host_diag_log_work(&pHddCtx->sap_wake_lock, + HDD_SAP_WAKE_LOCK_DURATION, + WIFI_POWER_EVENT_WAKELOCK_SAP); + qdf_wake_lock_timeout_acquire(&pHddCtx->sap_wake_lock, + HDD_SAP_WAKE_LOCK_DURATION); + { + struct station_info *sta_info; + uint16_t iesLen = + pSapEvent->sapevt. + sapStationAssocReassocCompleteEvent.iesLen; + + sta_info = qdf_mem_malloc(sizeof(*sta_info)); + if (!sta_info) { + hdd_err("Failed to allocate station info"); + return QDF_STATUS_E_FAILURE; + } + if (iesLen <= MAX_ASSOC_IND_IE_LEN) { + sta_info->assoc_req_ies = + (const u8 *)&pSapEvent->sapevt. + sapStationAssocReassocCompleteEvent.ies[0]; + sta_info->assoc_req_ies_len = iesLen; +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 0, 0)) && !defined(WITH_BACKPORTS) + /* + * After Kernel 4.0, it's no longer need to set + * STATION_INFO_ASSOC_REQ_IES flag, as it + * changed to use assoc_req_ies_len length to + * check the existance of request IE. + */ + sta_info->filled |= STATION_INFO_ASSOC_REQ_IES; +#endif + cfg80211_new_sta(dev, + (const u8 *)&pSapEvent->sapevt. + sapStationAssocReassocCompleteEvent. + staMac.bytes[0], sta_info, + GFP_KERNEL); + } else { + hdd_err("Assoc Ie length is too long"); + } + qdf_mem_free(sta_info); + } + pScanInfo = &pHostapdAdapter->scan_info; + /* Lets do abort scan to ensure smooth authentication for client */ + if ((pScanInfo != NULL) && pScanInfo->mScanPending) { + hdd_abort_mac_scan(pHddCtx, pHostapdAdapter->sessionId, + INVALID_SCAN_ID, + eCSR_SCAN_ABORT_DEFAULT); + } + if (pHostapdAdapter->device_mode == QDF_P2P_GO_MODE) { + /* send peer status indication to oem app */ + hdd_send_peer_status_ind_to_oem_app(&pSapEvent->sapevt. + sapStationAssocReassocCompleteEvent. + staMac, ePeerConnected, + pSapEvent->sapevt. + sapStationAssocReassocCompleteEvent. + timingMeasCap, + pHostapdAdapter->sessionId, + &pSapEvent->sapevt. + sapStationAssocReassocCompleteEvent. + chan_info, + pHostapdAdapter->device_mode); + } + hdd_green_ap_add_sta(pHddCtx); + break; + + case eSAP_STA_DISASSOC_EVENT: + memcpy(wrqu.addr.sa_data, + &pSapEvent->sapevt.sapStationDisassocCompleteEvent. + staMac, QDF_MAC_ADDR_SIZE); + hdd_notice(" disassociated " MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(wrqu.addr.sa_data)); + + qdf_status = qdf_event_set(&pHostapdState->qdf_sta_disassoc_event); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) + hdd_err("ERR: Station Deauth event Set failed"); + + if (pSapEvent->sapevt.sapStationDisassocCompleteEvent.reason == + eSAP_USR_INITATED_DISASSOC) + hdd_notice(" User initiated disassociation"); + else + hdd_notice(" MAC initiated disassociation"); + we_event = IWEVEXPIRED; + qdf_status = + hdd_softap_get_sta_id(pHostapdAdapter, + &pSapEvent->sapevt. + sapStationDisassocCompleteEvent.staMac, + &staId); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + hdd_err("ERROR: HDD Failed to find sta id!!"); + return QDF_STATUS_E_FAILURE; + } +#ifdef IPA_OFFLOAD + if (!cds_is_driver_recovering() && + hdd_ipa_is_enabled(pHddCtx)) { + status = hdd_ipa_wlan_evt(pHostapdAdapter, staId, + HDD_IPA_CLIENT_DISCONNECT, + pSapEvent->sapevt. + sapStationDisassocCompleteEvent. + staMac.bytes); + + if (status) { + hdd_err("ERROR: WLAN_CLIENT_DISCONNECT event failed!!"); + goto stopbss; + } + } +#endif + DPTRACE(qdf_dp_trace_mgmt_pkt(QDF_DP_TRACE_MGMT_PACKET_RECORD, + pHostapdAdapter->sessionId, + QDF_PROTO_TYPE_MGMT, QDF_PROTO_MGMT_DISASSOC)); + + hdd_softap_deregister_sta(pHostapdAdapter, staId); + + pHddApCtx->bApActive = false; + spin_lock_bh(&pHostapdAdapter->staInfo_lock); + for (i = 0; i < WLAN_MAX_STA_COUNT; i++) { + if (pHostapdAdapter->aStaInfo[i].isUsed + && i != + (WLAN_HDD_GET_AP_CTX_PTR(pHostapdAdapter))-> + uBCStaId) { + pHddApCtx->bApActive = true; + break; + } + } + spin_unlock_bh(&pHostapdAdapter->staInfo_lock); + + /* Start AP inactivity timer if no stations associated with it */ + if ((0 != + (WLAN_HDD_GET_CTX(pHostapdAdapter))->config-> + nAPAutoShutOff)) { + if (pHddApCtx->bApActive == false) { + if (pHddApCtx->hdd_ap_inactivity_timer.state == + QDF_TIMER_STATE_STOPPED) { + qdf_status = + qdf_mc_timer_start(&pHddApCtx-> + hdd_ap_inactivity_timer, + (WLAN_HDD_GET_CTX + (pHostapdAdapter))-> + config-> + nAPAutoShutOff * + 1000); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) + hdd_err("Failed to init AP inactivity timer"); + } else + QDF_ASSERT + (qdf_mc_timer_get_current_state + (&pHddApCtx-> + hdd_ap_inactivity_timer) == + QDF_TIMER_STATE_STOPPED); + } + } +#ifdef FEATURE_WLAN_AUTO_SHUTDOWN + wlan_hdd_auto_shutdown_enable(pHddCtx, true); +#endif + + cfg80211_del_sta(dev, + (const u8 *)&pSapEvent->sapevt. + sapStationDisassocCompleteEvent.staMac. + bytes[0], GFP_KERNEL); + + /* Update the beacon Interval if it is P2P GO */ + qdf_status = cds_change_mcc_go_beacon_interval(pHostapdAdapter); + if (QDF_STATUS_SUCCESS != qdf_status) { + hdd_err("failed to update Beacon interval %d", + qdf_status); + } + if (pHostapdAdapter->device_mode == QDF_P2P_GO_MODE) { + /* send peer status indication to oem app */ + hdd_send_peer_status_ind_to_oem_app(&pSapEvent->sapevt. + sapStationDisassocCompleteEvent. + staMac, ePeerDisconnected, + 0, + pHostapdAdapter->sessionId, + NULL, + pHostapdAdapter->device_mode); + } +#ifdef MSM_PLATFORM + /*stop timer in sap/p2p_go */ + if (pHddApCtx->bApActive == false) { + spin_lock_bh(&pHddCtx->bus_bw_lock); + pHostapdAdapter->prev_tx_packets = 0; + pHostapdAdapter->prev_rx_packets = 0; + pHostapdAdapter->prev_fwd_tx_packets = 0; + pHostapdAdapter->prev_fwd_rx_packets = 0; + spin_unlock_bh(&pHddCtx->bus_bw_lock); + hdd_bus_bw_compute_timer_try_stop(pHddCtx); + } +#endif + hdd_green_ap_del_sta(pHddCtx); + break; + + case eSAP_WPS_PBC_PROBE_REQ_EVENT: + { + static const char *message = + "MLMEWPSPBCPROBEREQ.indication"; + union iwreq_data wreq; + + down(&pHddApCtx->semWpsPBCOverlapInd); + pHddApCtx->WPSPBCProbeReq.probeReqIELen = + pSapEvent->sapevt.sapPBCProbeReqEvent. + WPSPBCProbeReq.probeReqIELen; + + qdf_mem_copy(pHddApCtx->WPSPBCProbeReq.probeReqIE, + pSapEvent->sapevt.sapPBCProbeReqEvent. + WPSPBCProbeReq.probeReqIE, + pHddApCtx->WPSPBCProbeReq.probeReqIELen); + + qdf_copy_macaddr(&pHddApCtx->WPSPBCProbeReq.peer_macaddr, + &pSapEvent->sapevt.sapPBCProbeReqEvent. + WPSPBCProbeReq.peer_macaddr); + hdd_notice("WPS PBC probe req " MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(pHddApCtx->WPSPBCProbeReq. + peer_macaddr.bytes)); + memset(&wreq, 0, sizeof(wreq)); + wreq.data.length = strlen(message); /* This is length of message */ + wireless_send_event(dev, IWEVCUSTOM, &wreq, + (char *)message); + + return QDF_STATUS_SUCCESS; + } + case eSAP_ASSOC_STA_CALLBACK_EVENT: + pAssocStasArray = + pSapEvent->sapevt.sapAssocStaListEvent.pAssocStas; + if (pSapEvent->sapevt.sapAssocStaListEvent.noOfAssocSta != 0) { /* List of associated stations */ + for (i = 0; + i < + pSapEvent->sapevt.sapAssocStaListEvent. + noOfAssocSta; i++) { + hdd_notice("Associated Sta Num %d:assocId=%d, staId=%d, staMac=" + MAC_ADDRESS_STR, i + 1, + pAssocStasArray->assocId, + pAssocStasArray->staId, + MAC_ADDR_ARRAY(pAssocStasArray->staMac. + bytes)); + pAssocStasArray++; + } + } + qdf_mem_free(pSapEvent->sapevt.sapAssocStaListEvent.pAssocStas); /* Release caller allocated memory here */ + pSapEvent->sapevt.sapAssocStaListEvent.pAssocStas = NULL; + return QDF_STATUS_SUCCESS; + case eSAP_REMAIN_CHAN_READY: + hdd_remain_chan_ready_handler(pHostapdAdapter, + pSapEvent->sapevt.sap_roc_ind.scan_id); + return QDF_STATUS_SUCCESS; + case eSAP_UNKNOWN_STA_JOIN: + snprintf(unknownSTAEvent, IW_CUSTOM_MAX, + "JOIN_UNKNOWN_STA-%02x:%02x:%02x:%02x:%02x:%02x", + pSapEvent->sapevt.sapUnknownSTAJoin.macaddr.bytes[0], + pSapEvent->sapevt.sapUnknownSTAJoin.macaddr.bytes[1], + pSapEvent->sapevt.sapUnknownSTAJoin.macaddr.bytes[2], + pSapEvent->sapevt.sapUnknownSTAJoin.macaddr.bytes[3], + pSapEvent->sapevt.sapUnknownSTAJoin.macaddr.bytes[4], + pSapEvent->sapevt.sapUnknownSTAJoin.macaddr.bytes[5]); + we_event = IWEVCUSTOM; /* Discovered a new node (AP mode). */ + wrqu.data.pointer = unknownSTAEvent; + wrqu.data.length = strlen(unknownSTAEvent); + we_custom_event_generic = (uint8_t *) unknownSTAEvent; + hdd_err("%s", unknownSTAEvent); + break; + + case eSAP_MAX_ASSOC_EXCEEDED: + snprintf(maxAssocExceededEvent, IW_CUSTOM_MAX, + "Peer %02x:%02x:%02x:%02x:%02x:%02x denied" + " assoc due to Maximum Mobile Hotspot connections reached. Please disconnect" + " one or more devices to enable the new device connection", + pSapEvent->sapevt.sapMaxAssocExceeded.macaddr.bytes[0], + pSapEvent->sapevt.sapMaxAssocExceeded.macaddr.bytes[1], + pSapEvent->sapevt.sapMaxAssocExceeded.macaddr.bytes[2], + pSapEvent->sapevt.sapMaxAssocExceeded.macaddr.bytes[3], + pSapEvent->sapevt.sapMaxAssocExceeded.macaddr.bytes[4], + pSapEvent->sapevt.sapMaxAssocExceeded.macaddr. + bytes[5]); + we_event = IWEVCUSTOM; /* Discovered a new node (AP mode). */ + wrqu.data.pointer = maxAssocExceededEvent; + wrqu.data.length = strlen(maxAssocExceededEvent); + we_custom_event_generic = (uint8_t *) maxAssocExceededEvent; + hdd_notice("%s", maxAssocExceededEvent); + break; + case eSAP_STA_ASSOC_IND: + return QDF_STATUS_SUCCESS; + + case eSAP_DISCONNECT_ALL_P2P_CLIENT: + hdd_notice(" Disconnecting all the P2P Clients...."); + hdd_clear_all_sta(pHostapdAdapter, usrDataForCallback); + return QDF_STATUS_SUCCESS; + + case eSAP_MAC_TRIG_STOP_BSS_EVENT: + qdf_status = + hdd_stop_bss_link(pHostapdAdapter, usrDataForCallback); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + hdd_warn("hdd_stop_bss_link failed %d", + qdf_status); + } + return QDF_STATUS_SUCCESS; + + case eSAP_CHANNEL_CHANGE_EVENT: + hdd_notice("Received eSAP_CHANNEL_CHANGE_EVENT event"); + if (pHostapdState->bssState != BSS_STOP) { + /* Prevent suspend for new channel */ + hdd_hostapd_channel_prevent_suspend(pHostapdAdapter, + pSapEvent->sapevt.sap_ch_selected.pri_ch); + /* Allow suspend for old channel */ + hdd_hostapd_channel_allow_suspend(pHostapdAdapter, + pHddApCtx->operatingChannel); + } + /* SME/PE is already updated for new operation channel. So update + * HDD layer also here. This resolves issue in AP-AP mode where + * AP1 channel is changed due to RADAR then CAC is going on and + * START_BSS on new channel has not come to HDD. At this case if + * AP2 is start it needs current operation channel for MCC DFS + * restiction + */ + pHddApCtx->operatingChannel = + pSapEvent->sapevt.sap_ch_selected.pri_ch; + pHddApCtx->sapConfig.acs_cfg.pri_ch = + pSapEvent->sapevt.sap_ch_selected.pri_ch; + pHddApCtx->sapConfig.acs_cfg.ht_sec_ch = + pSapEvent->sapevt.sap_ch_selected.ht_sec_ch; + pHddApCtx->sapConfig.acs_cfg.vht_seg0_center_ch = + pSapEvent->sapevt.sap_ch_selected.vht_seg0_center_ch; + pHddApCtx->sapConfig.acs_cfg.vht_seg1_center_ch = + pSapEvent->sapevt.sap_ch_selected.vht_seg1_center_ch; + pHddApCtx->sapConfig.acs_cfg.ch_width = + pSapEvent->sapevt.sap_ch_selected.ch_width; + + /* Indicate operating channel change to hostapd + * only for non driver override acs + */ + if (pHostapdAdapter->device_mode == QDF_SAP_MODE && + pHddCtx->config->force_sap_acs) { + return QDF_STATUS_SUCCESS; + } else { + chan_change.chan = + pSapEvent->sapevt.sap_ch_selected.pri_ch; + chan_change.chan_params.ch_width = + pSapEvent->sapevt.sap_ch_selected.ch_width; + chan_change.chan_params.sec_ch_offset = + pSapEvent->sapevt.sap_ch_selected.ht_sec_ch; + chan_change.chan_params.center_freq_seg0 = + pSapEvent->sapevt.sap_ch_selected.vht_seg0_center_ch; + chan_change.chan_params.center_freq_seg1 = + pSapEvent->sapevt.sap_ch_selected.vht_seg1_center_ch; + + return hdd_chan_change_notify(pHostapdAdapter, dev, + chan_change); + } + case eSAP_ACS_SCAN_SUCCESS_EVENT: + return hdd_handle_acs_scan_event(pSapEvent, pHostapdAdapter); + case eSAP_DFS_NOL_GET: + hdd_notice("Received eSAP_DFS_NOL_GET event"); + + /* get the dfs nol from PLD */ + ret = pld_wlan_get_dfs_nol(pHddCtx->parent_dev, + pSapEvent->sapevt.sapDfsNolInfo. + pDfsList, + pSapEvent->sapevt.sapDfsNolInfo. + sDfsList); + + if (ret > 0) { + hdd_info("Get %d bytes of dfs nol from PLD", ret); + return QDF_STATUS_SUCCESS; + } else { + hdd_info("No dfs nol entry in PLD, ret: %d", ret); + return QDF_STATUS_E_FAULT; + } + case eSAP_DFS_NOL_SET: + hdd_notice("Received eSAP_DFS_NOL_SET event"); + + /* set the dfs nol to PLD */ + ret = pld_wlan_set_dfs_nol(pHddCtx->parent_dev, + pSapEvent->sapevt.sapDfsNolInfo. + pDfsList, + pSapEvent->sapevt.sapDfsNolInfo. + sDfsList); + + if (ret) { + hdd_info("Failed to set dfs nol - ret: %d", ret); + } else { + hdd_info(" Set %d bytes dfs nol to PLD", + pSapEvent->sapevt.sapDfsNolInfo.sDfsList); + } + return QDF_STATUS_SUCCESS; + case eSAP_ACS_CHANNEL_SELECTED: + hdd_notice("ACS Completed for wlan%d", + pHostapdAdapter->dev->ifindex); + clear_bit(ACS_PENDING, &pHostapdAdapter->event_flags); + clear_bit(ACS_IN_PROGRESS, &pHddCtx->g_event_flags); + pHddApCtx->sapConfig.acs_cfg.pri_ch = + pSapEvent->sapevt.sap_ch_selected.pri_ch; + pHddApCtx->sapConfig.acs_cfg.ht_sec_ch = + pSapEvent->sapevt.sap_ch_selected.ht_sec_ch; + pHddApCtx->sapConfig.acs_cfg.vht_seg0_center_ch = + pSapEvent->sapevt.sap_ch_selected.vht_seg0_center_ch; + pHddApCtx->sapConfig.acs_cfg.vht_seg1_center_ch = + pSapEvent->sapevt.sap_ch_selected.vht_seg1_center_ch; + pHddApCtx->sapConfig.acs_cfg.ch_width = + pSapEvent->sapevt.sap_ch_selected.ch_width; + /* send vendor event to hostapd only for hostapd based acs*/ + if (!pHddCtx->config->force_sap_acs) + wlan_hdd_cfg80211_acs_ch_select_evt(pHostapdAdapter); + return QDF_STATUS_SUCCESS; + case eSAP_ECSA_CHANGE_CHAN_IND: + hdd_notice("Channel change indication from peer for channel %d", + pSapEvent->sapevt.sap_chan_cng_ind.new_chan); + if (hdd_softap_set_channel_change(dev, + pSapEvent->sapevt.sap_chan_cng_ind.new_chan, + CH_WIDTH_MAX)) + return QDF_STATUS_E_FAILURE; + else + return QDF_STATUS_SUCCESS; + case eSAP_UPDATE_SCAN_RESULT: + return hdd_update_scan_result(pSapEvent, + pHostapdAdapter); + default: + hdd_notice("SAP message is not handled"); + goto stopbss; + return QDF_STATUS_SUCCESS; + } + wireless_send_event(dev, we_event, &wrqu, + (char *)we_custom_event_generic); + + return QDF_STATUS_SUCCESS; + +stopbss: + { + uint8_t we_custom_event[64]; + char *stopBssEvent = "STOP-BSS.response"; /* 17 */ + int event_len = strlen(stopBssEvent); + + hdd_notice("BSS stop status = %s", + pSapEvent->sapevt.sapStopBssCompleteEvent.status ? + "eSAP_STATUS_FAILURE" : "eSAP_STATUS_SUCCESS"); + + /* Change the BSS state now since, as we are shutting things down, + * we don't want interfaces to become re-enabled */ + pHostapdState->bssState = BSS_STOP; + + if (0 != + (WLAN_HDD_GET_CTX(pHostapdAdapter))->config-> + nAPAutoShutOff) { + if (QDF_TIMER_STATE_RUNNING == + pHddApCtx->hdd_ap_inactivity_timer.state) { + qdf_status = + qdf_mc_timer_stop(&pHddApCtx-> + hdd_ap_inactivity_timer); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + hdd_err("Failed to stop AP inactivity timer"); + } + } + + qdf_status = + qdf_mc_timer_destroy(&pHddApCtx-> + hdd_ap_inactivity_timer); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) + hdd_err("Failed to Destroy AP inactivity timer"); + } +#ifdef FEATURE_WLAN_AUTO_SHUTDOWN + wlan_hdd_auto_shutdown_enable(pHddCtx, true); +#endif + + /* Stop the pkts from n/w stack as we are going to free all of + * the TX WMM queues for all STAID's */ + hdd_notice("Disabling queues"); + wlan_hdd_netif_queue_control(pHostapdAdapter, + WLAN_STOP_ALL_NETIF_QUEUE_N_CARRIER, + WLAN_CONTROL_PATH); + + /* reclaim all resources allocated to the BSS */ + qdf_status = hdd_softap_stop_bss(pHostapdAdapter); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + hdd_warn("hdd_softap_stop_bss failed %d", + qdf_status); + } + + /* notify userspace that the BSS has stopped */ + memset(&we_custom_event, '\0', sizeof(we_custom_event)); + memcpy(&we_custom_event, stopBssEvent, event_len); + memset(&wrqu, 0, sizeof(wrqu)); + wrqu.data.length = event_len; + we_event = IWEVCUSTOM; + we_custom_event_generic = we_custom_event; + wireless_send_event(dev, we_event, &wrqu, + (char *)we_custom_event_generic); + + /* once the event is set, structure dev/pHostapdAdapter should + * not be touched since they are now subject to being deleted + * by another thread + */ + if (eSAP_STOP_BSS_EVENT == sapEvent) + qdf_event_set(&pHostapdState->qdf_stop_bss_event); + + cds_dump_concurrency_info(); + /* Send SCC/MCC Switching event to IPA */ + hdd_ipa_send_mcc_scc_msg(pHddCtx, pHddCtx->mcc_mode); + } + return QDF_STATUS_SUCCESS; +} + +int hdd_softap_unpack_ie(tHalHandle halHandle, + eCsrEncryptionType *pEncryptType, + eCsrEncryptionType *mcEncryptType, + eCsrAuthType *pAuthType, + bool *pMFPCapable, + bool *pMFPRequired, + uint16_t gen_ie_len, uint8_t *gen_ie) +{ + tDot11fIERSN dot11RSNIE; + tDot11fIEWPA dot11WPAIE; + + uint8_t *pRsnIe; + uint16_t RSNIeLen; + + if (NULL == halHandle) { + hdd_err("Error haHandle returned NULL"); + return -EINVAL; + } + /* Validity checks */ + if ((gen_ie_len < QDF_MIN(DOT11F_IE_RSN_MIN_LEN, DOT11F_IE_WPA_MIN_LEN)) + || (gen_ie_len > + QDF_MAX(DOT11F_IE_RSN_MAX_LEN, DOT11F_IE_WPA_MAX_LEN))) + return -EINVAL; + /* Type check */ + if (gen_ie[0] == DOT11F_EID_RSN) { + /* Validity checks */ + if ((gen_ie_len < DOT11F_IE_RSN_MIN_LEN) || + (gen_ie_len > DOT11F_IE_RSN_MAX_LEN)) { + return QDF_STATUS_E_FAILURE; + } + /* Skip past the EID byte and length byte */ + pRsnIe = gen_ie + 2; + RSNIeLen = gen_ie_len - 2; + /* Unpack the RSN IE */ + memset(&dot11RSNIE, 0, sizeof(tDot11fIERSN)); + dot11f_unpack_ie_rsn((tpAniSirGlobal) halHandle, + pRsnIe, RSNIeLen, &dot11RSNIE); + /* Copy out the encryption and authentication types */ + hdd_notice("pairwise cipher suite count: %d", + dot11RSNIE.pwise_cipher_suite_count); + hdd_notice("authentication suite count: %d", + dot11RSNIE.akm_suite_count); + /*Here we have followed the apple base code, + but probably I suspect we can do something different */ + /* dot11RSNIE.akm_suite_count */ + /* Just translate the FIRST one */ + *pAuthType = + hdd_translate_rsn_to_csr_auth_type(dot11RSNIE.akm_suites[0]); + /* dot11RSNIE.pwise_cipher_suite_count */ + *pEncryptType = + hdd_translate_rsn_to_csr_encryption_type(dot11RSNIE. + pwise_cipher_suites[0]); + /* dot11RSNIE.gp_cipher_suite_count */ + *mcEncryptType = + hdd_translate_rsn_to_csr_encryption_type(dot11RSNIE. + gp_cipher_suite); + /* Set the PMKSA ID Cache for this interface */ + *pMFPCapable = 0 != (dot11RSNIE.RSN_Cap[0] & 0x80); + *pMFPRequired = 0 != (dot11RSNIE.RSN_Cap[0] & 0x40); + /* Calling csr_roam_set_pmkid_cache to configure the PMKIDs into the cache */ + } else if (gen_ie[0] == DOT11F_EID_WPA) { + /* Validity checks */ + if ((gen_ie_len < DOT11F_IE_WPA_MIN_LEN) || + (gen_ie_len > DOT11F_IE_WPA_MAX_LEN)) { + return QDF_STATUS_E_FAILURE; + } + /* Skip past the EID byte and length byte - and four byte WiFi OUI */ + pRsnIe = gen_ie + 2 + 4; + RSNIeLen = gen_ie_len - (2 + 4); + /* Unpack the WPA IE */ + memset(&dot11WPAIE, 0, sizeof(tDot11fIEWPA)); + dot11f_unpack_ie_wpa((tpAniSirGlobal) halHandle, + pRsnIe, RSNIeLen, &dot11WPAIE); + /* Copy out the encryption and authentication types */ + hdd_notice("WPA unicast cipher suite count: %d", + dot11WPAIE.unicast_cipher_count); + hdd_notice("WPA authentication suite count: %d", + dot11WPAIE.auth_suite_count); + /* dot11WPAIE.auth_suite_count */ + /* Just translate the FIRST one */ + *pAuthType = + hdd_translate_wpa_to_csr_auth_type(dot11WPAIE.auth_suites[0]); + /* dot11WPAIE.unicast_cipher_count */ + *pEncryptType = + hdd_translate_wpa_to_csr_encryption_type(dot11WPAIE. + unicast_ciphers[0]); + /* dot11WPAIE.unicast_cipher_count */ + *mcEncryptType = + hdd_translate_wpa_to_csr_encryption_type(dot11WPAIE. + multicast_cipher); + *pMFPCapable = false; + *pMFPRequired = false; + } else { + hdd_warn("gen_ie[0]: %d", gen_ie[0]); + return QDF_STATUS_E_FAILURE; + } + return QDF_STATUS_SUCCESS; +} + +/** + * hdd_softap_set_channel_change() - + * This function to support SAP channel change with CSA IE + * set in the beacons. + * + * @dev: pointer to the net device. + * @target_channel: target channel number. + * @target_bw: Target bandwidth to move. + * If no bandwidth is specified, the value is CH_WIDTH_MAX + * + * Return: 0 for success, non zero for failure + */ +int hdd_softap_set_channel_change(struct net_device *dev, int target_channel, + enum phy_ch_width target_bw) +{ + QDF_STATUS status; + int ret = 0; + hdd_adapter_t *pHostapdAdapter = (netdev_priv(dev)); + hdd_context_t *pHddCtx = NULL; + hdd_adapter_t *sta_adapter; + hdd_station_ctx_t *sta_ctx; + + pHddCtx = WLAN_HDD_GET_CTX(pHostapdAdapter); + ret = wlan_hdd_validate_context(pHddCtx); + if (ret) + return ret; + + ret = hdd_validate_channel_and_bandwidth(pHostapdAdapter, + target_channel, target_bw); + if (ret) { + hdd_err("Invalid CH and BW combo"); + return ret; + } + + sta_adapter = hdd_get_adapter(pHddCtx, QDF_STA_MODE); + /* + * conc_custom_rule1: + * Force SCC for SAP + STA + * if STA is already connected then we shouldn't allow + * channel switch in SAP interface. + */ + if (sta_adapter && pHddCtx->config->conc_custom_rule1) { + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(sta_adapter); + if (hdd_conn_is_connected(sta_ctx)) { + hdd_err("Channel switch not allowed after STA connection with conc_custom_rule1 enabled"); + return -EBUSY; + } + } + + /* + * Set the dfs_radar_found flag to mimic channel change + * when a radar is found. This will enable synchronizing + * SAP and HDD states similar to that of radar indication. + * Suspend the netif queues to stop queuing Tx frames + * from upper layers. netif queues will be resumed + * once the channel change is completed and SAP will + * post eSAP_START_BSS_EVENT success event to HDD. + */ + if (qdf_atomic_inc_return(&pHddCtx->dfs_radar_found) > 1) { + hdd_err("Channel switch in progress!!"); + return -EBUSY; + } + + /* + * Post the Channel Change request to SAP. + */ + status = wlansap_set_channel_change_with_csa( + WLAN_HDD_GET_SAP_CTX_PTR(pHostapdAdapter), + (uint32_t)target_channel, + target_bw); + + if (QDF_STATUS_SUCCESS != status) { + hdd_err("SAP set channel failed for channel = %d, bw:%d", + target_channel, target_bw); + /* + * If channel change command fails then clear the + * radar found flag and also restart the netif + * queues. + */ + qdf_atomic_set(&pHddCtx->dfs_radar_found, 0); + + ret = -EINVAL; + } + + return ret; +} + +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH +/** + * hdd_sap_restart_with_channel_switch() - SAP channel change with E/CSA + * @ap_adapter: HDD adapter + * @target_channel: Channel to which switch must happen + * @target_bw: Bandwidth of the target channel + * + * Invokes the necessary API to perform channel switch for the SAP or GO + * + * Return: None + */ +void hdd_sap_restart_with_channel_switch(hdd_adapter_t *ap_adapter, + uint32_t target_channel, + uint32_t target_bw) +{ + struct net_device *dev = ap_adapter->dev; + int ret; + + ENTER(); + + if (!dev) { + hdd_err("Invalid dev pointer"); + return; + } + + ret = hdd_softap_set_channel_change(dev, target_channel, target_bw); + if (ret) { + hdd_err("channel switch failed"); + return; + } +} +#endif + +int +static __iw_softap_set_ini_cfg(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + QDF_STATUS vstatus; + int ret = 0; /* success */ + hdd_adapter_t *pAdapter = (netdev_priv(dev)); + hdd_context_t *pHddCtx; + + ENTER_DEV(dev); + + pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + ret = wlan_hdd_validate_context(pHddCtx); + if (ret) + return ret; + + hdd_notice("Received data %s", extra); + + vstatus = hdd_execute_global_config_command(pHddCtx, extra); + if (QDF_STATUS_SUCCESS != vstatus) { + ret = -EINVAL; + } + + return ret; +} + +int +static iw_softap_set_ini_cfg(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_softap_set_ini_cfg(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +static int hdd_sap_get_chan_width(hdd_adapter_t *adapter, int *value) +{ + void *cds_ctx; + hdd_hostapd_state_t *hostapdstate; + + ENTER(); + hostapdstate = WLAN_HDD_GET_HOSTAP_STATE_PTR(adapter); + + if (hostapdstate->bssState != BSS_START) { + *value = -EINVAL; + return -EINVAL; + } + + cds_ctx = WLAN_HDD_GET_SAP_CTX_PTR(adapter); + + *value = wlansap_get_chan_width(cds_ctx); + hdd_notice("chan_width = %d", *value); + + return 0; +} + +int +static __iw_softap_get_ini_cfg(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *pHddCtx; + int ret = 0; + + ENTER_DEV(dev); + + pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + ret = wlan_hdd_validate_context(pHddCtx); + if (ret != 0) + return ret; + + hdd_notice("Printing CLD global INI Config"); + hdd_cfg_get_global_config(pHddCtx, extra, QCSAP_IOCTL_MAX_STR_LEN); + wrqu->data.length = strlen(extra) + 1; + + return 0; +} + +int +static iw_softap_get_ini_cfg(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_softap_get_ini_cfg(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * iw_softap_set_two_ints_getnone() - Generic "set two integer" ioctl handler + * @dev: device upon which the ioctl was received + * @info: ioctl request information + * @wrqu: ioctl request data + * @extra: ioctl extra data + * + * Return: 0 on success, non-zero on error + */ +static int __iw_softap_set_two_ints_getnone(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + int ret; + int *value = (int *)extra; + int sub_cmd = value[0]; + hdd_context_t *hdd_ctx; + + ENTER_DEV(dev); + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret != 0) + goto out; + + switch (sub_cmd) { +#ifdef WLAN_DEBUG + case QCSAP_IOCTL_SET_FW_CRASH_INJECT: + hdd_err("WE_SET_FW_CRASH_INJECT: %d %d", + value[1], value[2]); + if (!hdd_ctx->config->crash_inject_enabled) { + hdd_err("Crash Inject ini disabled, Ignore Crash Inject"); + return 0; + } + ret = wma_cli_set2_command(adapter->sessionId, + GEN_PARAM_CRASH_INJECT, + value[1], value[2], + GEN_CMD); + break; +#endif + case QCSAP_IOCTL_DUMP_DP_TRACE_LEVEL: + hdd_info("WE_DUMP_DP_TRACE: %d %d", + value[1], value[2]); + if (value[1] == DUMP_DP_TRACE) + qdf_dp_trace_dump_all(value[2]); + else if (value[1] == ENABLE_DP_TRACE_LIVE_MODE) + qdf_dp_trace_enable_live_mode(); + else if (value[1] == CLEAR_DP_TRACE_BUFFER) + qdf_dp_trace_clear_buffer(); + break; + case QCSAP_ENABLE_FW_PROFILE: + hdd_notice("QCSAP_ENABLE_FW_PROFILE: %d %d", + value[1], value[2]); + ret = wma_cli_set2_command(adapter->sessionId, + WMI_WLAN_PROFILE_ENABLE_PROFILE_ID_CMDID, + value[1], value[2], DBG_CMD); + break; + case QCSAP_SET_FW_PROFILE_HIST_INTVL: + hdd_notice("QCSAP_SET_FW_PROFILE_HIST_INTVL: %d %d", + value[1], value[2]); + ret = wma_cli_set2_command(adapter->sessionId, + WMI_WLAN_PROFILE_SET_HIST_INTVL_CMDID, + value[1], value[2], DBG_CMD); + default: + hdd_err("Invalid IOCTL command %d", sub_cmd); + break; + } + +out: + return ret; +} + +static int iw_softap_set_two_ints_getnone(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_softap_set_two_ints_getnone(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +static void print_mac_list(struct qdf_mac_addr *macList, uint8_t size) +{ + int i; + uint8_t *macArray; + + for (i = 0; i < size; i++) { + macArray = (macList + i)->bytes; + pr_info("** ACL entry %i - %02x:%02x:%02x:%02x:%02x:%02x \n", + i, MAC_ADDR_ARRAY(macArray)); + } + return; +} + +static QDF_STATUS hdd_print_acl(hdd_adapter_t *pHostapdAdapter) +{ + eSapMacAddrACL acl_mode; + struct qdf_mac_addr MacList[MAX_ACL_MAC_ADDRESS]; + uint8_t listnum; + void *p_cds_gctx = NULL; + + p_cds_gctx = WLAN_HDD_GET_SAP_CTX_PTR(pHostapdAdapter); + qdf_mem_zero(&MacList[0], sizeof(MacList)); + if (QDF_STATUS_SUCCESS == wlansap_get_acl_mode(p_cds_gctx, &acl_mode)) { + pr_info("******** ACL MODE *********\n"); + switch (acl_mode) { + case eSAP_ACCEPT_UNLESS_DENIED: + pr_info("ACL Mode = ACCEPT_UNLESS_DENIED\n"); + break; + case eSAP_DENY_UNLESS_ACCEPTED: + pr_info("ACL Mode = DENY_UNLESS_ACCEPTED\n"); + break; + case eSAP_SUPPORT_ACCEPT_AND_DENY: + pr_info("ACL Mode = ACCEPT_AND_DENY\n"); + break; + case eSAP_ALLOW_ALL: + pr_info("ACL Mode = ALLOW_ALL\n"); + break; + default: + pr_info("Invalid SAP ACL Mode = %d\n", acl_mode); + return QDF_STATUS_E_FAILURE; + } + } else { + return QDF_STATUS_E_FAILURE; + } + + if (QDF_STATUS_SUCCESS == wlansap_get_acl_accept_list(p_cds_gctx, + &MacList[0], + &listnum)) { + pr_info("******* WHITE LIST ***********\n"); + if (listnum <= MAX_ACL_MAC_ADDRESS) + print_mac_list(&MacList[0], listnum); + } else { + return QDF_STATUS_E_FAILURE; + } + + if (QDF_STATUS_SUCCESS == wlansap_get_acl_deny_list(p_cds_gctx, + &MacList[0], + &listnum)) { + pr_info("******* BLACK LIST ***********\n"); + if (listnum <= MAX_ACL_MAC_ADDRESS) + print_mac_list(&MacList[0], listnum); + } else { + return QDF_STATUS_E_FAILURE; + } + return QDF_STATUS_SUCCESS; +} + +int +static __iw_softap_setparam(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + hdd_adapter_t *pHostapdAdapter = (netdev_priv(dev)); + tHalHandle hHal; + int *value = (int *)extra; + int sub_cmd = value[0]; + int set_value = value[1]; + QDF_STATUS status; + int ret = 0; /* success */ + hdd_context_t *hdd_ctx; + + ENTER_DEV(dev); + + hdd_ctx = WLAN_HDD_GET_CTX(pHostapdAdapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return -EINVAL; + + hHal = WLAN_HDD_GET_HAL_CTX(pHostapdAdapter); + if (!hHal) { + hdd_err("Hal ctx is null"); + return -EINVAL; + } + + switch (sub_cmd) { + case QCASAP_SET_RADAR_DBG: + hdd_notice("QCASAP_SET_RADAR_DBG called with: value: %d", + set_value); + wlan_sap_enable_phy_error_logs(hHal, (bool) set_value); + break; + + case QCSAP_PARAM_CLR_ACL: + if (QDF_STATUS_SUCCESS != wlansap_clear_acl( + WLAN_HDD_GET_SAP_CTX_PTR(pHostapdAdapter))) { + ret = -EIO; + } + break; + + case QCSAP_PARAM_ACL_MODE: + if ((eSAP_ALLOW_ALL < (eSapMacAddrACL) set_value) || + (eSAP_ACCEPT_UNLESS_DENIED > (eSapMacAddrACL) set_value)) { + hdd_err("Invalid ACL Mode value %d", + set_value); + ret = -EINVAL; + } else { + wlansap_set_mode( + WLAN_HDD_GET_SAP_CTX_PTR(pHostapdAdapter), + set_value); + } + break; + + case QCSAP_PARAM_SET_CHANNEL_CHANGE: + if ((QDF_SAP_MODE == pHostapdAdapter->device_mode) || + (QDF_P2P_GO_MODE == pHostapdAdapter->device_mode)) { + hdd_notice("SET Channel Change to new channel= %d", + set_value); + ret = hdd_softap_set_channel_change(dev, set_value, + CH_WIDTH_MAX); + } else { + hdd_err("Channel Change Failed, Device in test mode"); + ret = -EINVAL; + } + break; + case QCSAP_PARAM_AUTO_CHANNEL: + if (set_value == 0 || set_value == 1) + (WLAN_HDD_GET_CTX( + pHostapdAdapter))->config->force_sap_acs = + set_value; + else + ret = -EINVAL; + break; + case QCSAP_PARAM_CONC_SYSTEM_PREF: + hdd_info("New preference: %d", set_value); + if (!((set_value >= CFG_CONC_SYSTEM_PREF_MIN) && + (set_value <= CFG_CONC_SYSTEM_PREF_MAX))) { + hdd_err("Invalid system preference %d", set_value); + return -EINVAL; + } + /* hdd_ctx, hdd_ctx->config are already checked for null */ + hdd_ctx->config->conc_system_pref = set_value; + break; + case QCSAP_PARAM_MAX_ASSOC: + if (WNI_CFG_ASSOC_STA_LIMIT_STAMIN > set_value) { + hdd_err("Invalid setMaxAssoc value %d", + set_value); + ret = -EINVAL; + } else { + if (WNI_CFG_ASSOC_STA_LIMIT_STAMAX < set_value) { + hdd_warn("setMaxAssoc %d > max allowed %d.", + set_value, + WNI_CFG_ASSOC_STA_LIMIT_STAMAX); + hdd_warn("Setting it to max allowed and continuing"); + set_value = WNI_CFG_ASSOC_STA_LIMIT_STAMAX; + } + status = sme_cfg_set_int(hHal, WNI_CFG_ASSOC_STA_LIMIT, + set_value); + if (status != QDF_STATUS_SUCCESS) { + hdd_err("setMaxAssoc failure, status %d", + status); + ret = -EIO; + } + } + break; + + case QCSAP_PARAM_HIDE_SSID: + { + QDF_STATUS status; + status = sme_update_session_param(hHal, + pHostapdAdapter->sessionId, + SIR_PARAM_SSID_HIDDEN, set_value); + if (QDF_STATUS_SUCCESS != status) { + hdd_err("QCSAP_PARAM_HIDE_SSID failed"); + return -EIO; + } + break; + } + case QCSAP_PARAM_SET_MC_RATE: + { + tSirRateUpdateInd rateUpdate = {0}; + struct hdd_config *pConfig = hdd_ctx->config; + + hdd_notice("MC Target rate %d", set_value); + qdf_copy_macaddr(&rateUpdate.bssid, + &pHostapdAdapter->macAddressCurrent); + rateUpdate.nss = (pConfig->enable2x2 == 0) ? 0 : 1; + rateUpdate.dev_mode = pHostapdAdapter->device_mode; + rateUpdate.mcastDataRate24GHz = set_value; + rateUpdate.mcastDataRate24GHzTxFlag = 1; + rateUpdate.mcastDataRate5GHz = set_value; + rateUpdate.bcastDataRate = -1; + status = sme_send_rate_update_ind(hHal, &rateUpdate); + if (QDF_STATUS_SUCCESS != status) { + hdd_err("SET_MC_RATE failed"); + ret = -1; + } + break; + } + + case QCSAP_PARAM_SET_TXRX_FW_STATS: + { + hdd_notice("QCSAP_PARAM_SET_TXRX_FW_STATS val %d", set_value); + ret = wma_cli_set_command(pHostapdAdapter->sessionId, + WMA_VDEV_TXRX_FWSTATS_ENABLE_CMDID, + set_value, VDEV_CMD); + break; + } + /* Firmware debug log */ + case QCSAP_DBGLOG_LOG_LEVEL: + { + hdd_notice("QCSAP_DBGLOG_LOG_LEVEL val %d", set_value); + ret = wma_cli_set_command(pHostapdAdapter->sessionId, + WMI_DBGLOG_LOG_LEVEL, + set_value, DBG_CMD); + break; + } + + case QCSAP_DBGLOG_VAP_ENABLE: + { + hdd_notice("QCSAP_DBGLOG_VAP_ENABLE val %d", set_value); + ret = wma_cli_set_command(pHostapdAdapter->sessionId, + WMI_DBGLOG_VAP_ENABLE, + set_value, DBG_CMD); + break; + } + + case QCSAP_DBGLOG_VAP_DISABLE: + { + hdd_notice("QCSAP_DBGLOG_VAP_DISABLE val %d", set_value); + ret = wma_cli_set_command(pHostapdAdapter->sessionId, + WMI_DBGLOG_VAP_DISABLE, + set_value, DBG_CMD); + break; + } + + case QCSAP_DBGLOG_MODULE_ENABLE: + { + hdd_notice("QCSAP_DBGLOG_MODULE_ENABLE val %d", set_value); + ret = wma_cli_set_command(pHostapdAdapter->sessionId, + WMI_DBGLOG_MODULE_ENABLE, + set_value, DBG_CMD); + break; + } + + case QCSAP_DBGLOG_MODULE_DISABLE: + { + hdd_notice("QCSAP_DBGLOG_MODULE_DISABLE val %d", set_value); + ret = wma_cli_set_command(pHostapdAdapter->sessionId, + WMI_DBGLOG_MODULE_DISABLE, + set_value, DBG_CMD); + break; + } + + case QCSAP_DBGLOG_MOD_LOG_LEVEL: + { + hdd_notice("QCSAP_DBGLOG_MOD_LOG_LEVEL val %d", set_value); + ret = wma_cli_set_command(pHostapdAdapter->sessionId, + WMI_DBGLOG_MOD_LOG_LEVEL, + set_value, DBG_CMD); + break; + } + + case QCSAP_DBGLOG_TYPE: + { + hdd_notice("QCSAP_DBGLOG_TYPE val %d", set_value); + ret = wma_cli_set_command(pHostapdAdapter->sessionId, + WMI_DBGLOG_TYPE, + set_value, DBG_CMD); + break; + } + case QCSAP_DBGLOG_REPORT_ENABLE: + { + hdd_notice("QCSAP_DBGLOG_REPORT_ENABLE val %d", set_value); + ret = wma_cli_set_command(pHostapdAdapter->sessionId, + WMI_DBGLOG_REPORT_ENABLE, + set_value, DBG_CMD); + break; + } + case QCSAP_PARAM_SET_MCC_CHANNEL_LATENCY: + { + cds_set_mcc_latency(pHostapdAdapter, set_value); + break; + } + + case QCSAP_PARAM_SET_MCC_CHANNEL_QUOTA: + { + hdd_notice("iwpriv cmd to set MCC quota value %dms", + set_value); + ret = cds_go_set_mcc_p2p_quota(pHostapdAdapter, + set_value); + break; + } + + case QCASAP_TXRX_FWSTATS_RESET: + { + hdd_notice("WE_TXRX_FWSTATS_RESET val %d", set_value); + ret = wma_cli_set_command(pHostapdAdapter->sessionId, + WMA_VDEV_TXRX_FWSTATS_RESET_CMDID, + set_value, VDEV_CMD); + break; + } + + case QCSAP_PARAM_RTSCTS: + { + ret = wma_cli_set_command(pHostapdAdapter->sessionId, + WMI_VDEV_PARAM_ENABLE_RTSCTS, + set_value, VDEV_CMD); + if (ret) { + hdd_err("FAILED TO SET RTSCTS at SAP"); + ret = -EIO; + } + break; + } + case QCASAP_SET_11N_RATE: + { + uint8_t preamble = 0, nss = 0, rix = 0; + tsap_Config_t *pConfig = + &pHostapdAdapter->sessionCtx.ap.sapConfig; + + hdd_notice("SET_HT_RATE val %d", set_value); + + if (set_value != 0xff) { + rix = RC_2_RATE_IDX(set_value); + if (set_value & 0x80) { + if (pConfig->SapHw_mode == + eCSR_DOT11_MODE_11b + || pConfig->SapHw_mode == + eCSR_DOT11_MODE_11b_ONLY + || pConfig->SapHw_mode == + eCSR_DOT11_MODE_11g + || pConfig->SapHw_mode == + eCSR_DOT11_MODE_11g_ONLY + || pConfig->SapHw_mode == + eCSR_DOT11_MODE_abg + || pConfig->SapHw_mode == + eCSR_DOT11_MODE_11a) { + hdd_err("Not valid mode for HT"); + ret = -EIO; + break; + } + preamble = WMI_RATE_PREAMBLE_HT; + nss = HT_RC_2_STREAMS(set_value) - 1; + } else if (set_value & 0x10) { + if (pConfig->SapHw_mode == + eCSR_DOT11_MODE_11a) { + hdd_err("Not valid for cck"); + ret = -EIO; + break; + } + preamble = WMI_RATE_PREAMBLE_CCK; + /* Enable Short preamble always + * for CCK except 1mbps + */ + if (rix != 0x3) + rix |= 0x4; + } else { + if (pConfig->SapHw_mode == + eCSR_DOT11_MODE_11b + || pConfig->SapHw_mode == + eCSR_DOT11_MODE_11b_ONLY) { + hdd_err("Not valid for OFDM"); + ret = -EIO; + break; + } + preamble = WMI_RATE_PREAMBLE_OFDM; + } + set_value = (preamble << 6) | (nss << 4) | rix; + } + hdd_notice("SET_HT_RATE val %d rix %d preamble %x nss %d", + set_value, rix, preamble, nss); + ret = wma_cli_set_command(pHostapdAdapter->sessionId, + WMI_VDEV_PARAM_FIXED_RATE, + set_value, VDEV_CMD); + break; + } + + case QCASAP_SET_VHT_RATE: + { + uint8_t preamble = 0, nss = 0, rix = 0; + tsap_Config_t *pConfig = + &pHostapdAdapter->sessionCtx.ap.sapConfig; + + if (pConfig->SapHw_mode != eCSR_DOT11_MODE_11ac && + pConfig->SapHw_mode != eCSR_DOT11_MODE_11ac_ONLY) { + hdd_err("SET_VHT_RATE error: SapHw_mode= 0x%x, ch = %d", + pConfig->SapHw_mode, pConfig->channel); + ret = -EIO; + break; + } + + if (set_value != 0xff) { + rix = RC_2_RATE_IDX_11AC(set_value); + preamble = WMI_RATE_PREAMBLE_VHT; + nss = HT_RC_2_STREAMS_11AC(set_value) - 1; + + set_value = (preamble << 6) | (nss << 4) | rix; + } + hdd_notice("SET_VHT_RATE val %d rix %d preamble %x nss %d", + set_value, rix, preamble, nss); + + ret = wma_cli_set_command(pHostapdAdapter->sessionId, + WMI_VDEV_PARAM_FIXED_RATE, + set_value, VDEV_CMD); + break; + } + + case QCASAP_SHORT_GI: + { + hdd_notice("QCASAP_SET_SHORT_GI val %d", set_value); + + /* same as 40MHZ */ + ret = sme_update_ht_config(hHal, pHostapdAdapter->sessionId, + WNI_CFG_HT_CAP_INFO_SHORT_GI_20MHZ, + set_value); + if (ret) + hdd_err("Failed to set ShortGI value ret(%d)", ret); + break; + } + + case QCSAP_SET_AMPDU: + { + hdd_notice("QCSAP_SET_AMPDU %d", set_value); + ret = wma_cli_set_command(pHostapdAdapter->sessionId, + GEN_VDEV_PARAM_AMPDU, + set_value, GEN_CMD); + break; + } + + case QCSAP_SET_AMSDU: + { + hdd_notice("QCSAP_SET_AMSDU %d", set_value); + ret = wma_cli_set_command(pHostapdAdapter->sessionId, + GEN_VDEV_PARAM_AMSDU, + set_value, GEN_CMD); + break; + } + case QCSAP_GTX_HT_MCS: + { + hdd_notice("WMI_VDEV_PARAM_GTX_HT_MCS %d", set_value); + ret = wma_cli_set_command(pHostapdAdapter->sessionId, + WMI_VDEV_PARAM_GTX_HT_MCS, + set_value, GTX_CMD); + break; + } + + case QCSAP_GTX_VHT_MCS: + { + hdd_notice("WMI_VDEV_PARAM_GTX_VHT_MCS %d", set_value); + ret = wma_cli_set_command(pHostapdAdapter->sessionId, + WMI_VDEV_PARAM_GTX_VHT_MCS, + set_value, GTX_CMD); + break; + } + + case QCSAP_GTX_USRCFG: + { + hdd_notice("WMI_VDEV_PARAM_GTX_USR_CFG %d", set_value); + ret = wma_cli_set_command(pHostapdAdapter->sessionId, + WMI_VDEV_PARAM_GTX_USR_CFG, + set_value, GTX_CMD); + break; + } + + case QCSAP_GTX_THRE: + { + hdd_notice("WMI_VDEV_PARAM_GTX_THRE %d", set_value); + ret = wma_cli_set_command(pHostapdAdapter->sessionId, + WMI_VDEV_PARAM_GTX_THRE, + set_value, GTX_CMD); + break; + } + + case QCSAP_GTX_MARGIN: + { + hdd_notice("WMI_VDEV_PARAM_GTX_MARGIN %d", set_value); + ret = wma_cli_set_command(pHostapdAdapter->sessionId, + WMI_VDEV_PARAM_GTX_MARGIN, + set_value, GTX_CMD); + break; + } + + case QCSAP_GTX_STEP: + { + hdd_notice("WMI_VDEV_PARAM_GTX_STEP %d", set_value); + ret = wma_cli_set_command(pHostapdAdapter->sessionId, + WMI_VDEV_PARAM_GTX_STEP, + set_value, GTX_CMD); + break; + } + + case QCSAP_GTX_MINTPC: + { + hdd_notice("WMI_VDEV_PARAM_GTX_MINTPC %d", set_value); + ret = wma_cli_set_command(pHostapdAdapter->sessionId, + WMI_VDEV_PARAM_GTX_MINTPC, + set_value, GTX_CMD); + break; + } + + case QCSAP_GTX_BWMASK: + { + hdd_notice("WMI_VDEV_PARAM_GTX_BWMASK %d", set_value); + ret = wma_cli_set_command(pHostapdAdapter->sessionId, + WMI_VDEV_PARAM_GTX_BW_MASK, + set_value, GTX_CMD); + break; + } + + case QCASAP_SET_TM_LEVEL: + { + hdd_notice("Set Thermal Mitigation Level %d", set_value); + (void)sme_set_thermal_level(hHal, set_value); + break; + } + + case QCASAP_SET_DFS_IGNORE_CAC: + { + hdd_notice("Set Dfs ignore CAC %d", set_value); + + if (pHostapdAdapter->device_mode != QDF_SAP_MODE) + return -EINVAL; + + ret = wlansap_set_dfs_ignore_cac(hHal, set_value); + break; + } + + case QCASAP_SET_DFS_TARGET_CHNL: + { + hdd_notice("Set Dfs target channel %d", set_value); + + if (pHostapdAdapter->device_mode != QDF_SAP_MODE) + return -EINVAL; + + ret = wlansap_set_dfs_target_chnl(hHal, set_value); + break; + } + + case QCASAP_SET_DFS_NOL: + wlansap_set_dfs_nol( + WLAN_HDD_GET_SAP_CTX_PTR(pHostapdAdapter), + (eSapDfsNolType) set_value); + break; + + case QCASAP_SET_RADAR_CMD: + { + hdd_context_t *pHddCtx = + WLAN_HDD_GET_CTX(pHostapdAdapter); + uint8_t ch = + (WLAN_HDD_GET_AP_CTX_PTR(pHostapdAdapter))-> + operatingChannel; + bool isDfsch; + int32_t dfs_radar_found; + + isDfsch = (CHANNEL_STATE_DFS == + cds_get_channel_state(ch)); + + hdd_notice("Set QCASAP_SET_RADAR_CMD val %d", set_value); + + dfs_radar_found = qdf_atomic_read(&pHddCtx->dfs_radar_found); + if (!dfs_radar_found && isDfsch) { + ret = wma_cli_set_command(pHostapdAdapter->sessionId, + WMA_VDEV_DFS_CONTROL_CMDID, + set_value, VDEV_CMD); + } else { + hdd_err("Ignore, radar_found: %d, dfs_channel: %d", + dfs_radar_found, isDfsch); + } + break; + } + case QCASAP_TX_CHAINMASK_CMD: + { + hdd_notice("QCASAP_TX_CHAINMASK_CMD val %d", set_value); + ret = wma_cli_set_command(pHostapdAdapter->sessionId, + WMI_PDEV_PARAM_TX_CHAIN_MASK, + set_value, PDEV_CMD); + break; + } + + case QCASAP_RX_CHAINMASK_CMD: + { + hdd_notice("QCASAP_RX_CHAINMASK_CMD val %d", set_value); + ret = wma_cli_set_command(pHostapdAdapter->sessionId, + WMI_PDEV_PARAM_RX_CHAIN_MASK, + set_value, PDEV_CMD); + break; + } + + case QCASAP_NSS_CMD: + { + hdd_notice("QCASAP_NSS_CMD val %d", set_value); + ret = wma_cli_set_command(pHostapdAdapter->sessionId, + WMI_VDEV_PARAM_NSS, + set_value, VDEV_CMD); + break; + } + + case QCSAP_IPA_UC_STAT: + { + /* If input value is non-zero get stats */ + switch (set_value) { + case 1: + hdd_ipa_uc_stat_request(pHostapdAdapter, set_value); + break; + case 3: + hdd_ipa_uc_rt_debug_host_dump(hdd_ctx); + break; + case 4: + hdd_ipa_dump_info(hdd_ctx); + break; + default: + /* place holder for stats clean up + * Stats clean not implemented yet on FW and IPA + */ + break; + } + return ret; + } + + case QCASAP_SET_PHYMODE: + { + hdd_context_t *phddctx = + WLAN_HDD_GET_CTX(pHostapdAdapter); + + ret = + wlan_hdd_update_phymode(dev, hHal, set_value, + phddctx); + break; + } + case QCASAP_DUMP_STATS: + { + hdd_notice("QCASAP_DUMP_STATS val %d", set_value); + ret = hdd_wlan_dump_stats(pHostapdAdapter, set_value); + break; + } + case QCASAP_CLEAR_STATS: + { + hdd_context_t *hdd_ctx = + WLAN_HDD_GET_CTX(pHostapdAdapter); + hdd_notice("QCASAP_CLEAR_STATS val %d", set_value); + switch (set_value) { + case WLAN_HDD_STATS: + memset(&pHostapdAdapter->stats, 0, + sizeof(pHostapdAdapter->stats)); + memset(&pHostapdAdapter->hdd_stats, 0, + sizeof(pHostapdAdapter->hdd_stats)); + break; + case WLAN_TXRX_HIST_STATS: + wlan_hdd_clear_tx_rx_histogram(hdd_ctx); + break; + case WLAN_HDD_NETIF_OPER_HISTORY: + wlan_hdd_clear_netif_queue_history(hdd_ctx); + break; + case WLAN_HIF_STATS: + hdd_clear_hif_stats(); + break; + default: + if (ol_txrx_clear_stats(set_value) == + QDF_STATUS_E_INVAL) { + hdd_display_stats_help(); + ret = EINVAL; + } + } + break; + } + case QCSAP_START_FW_PROFILING: + hdd_notice("QCSAP_START_FW_PROFILING %d", set_value); + ret = wma_cli_set_command(pHostapdAdapter->sessionId, + WMI_WLAN_PROFILE_TRIGGER_CMDID, + set_value, DBG_CMD); + break; + case QCASAP_PARAM_LDPC: + ret = hdd_set_ldpc(pHostapdAdapter, set_value); + break; + case QCASAP_PARAM_TX_STBC: + ret = hdd_set_tx_stbc(pHostapdAdapter, set_value); + break; + case QCASAP_PARAM_RX_STBC: + ret = hdd_set_rx_stbc(pHostapdAdapter, set_value); + break; + + default: + hdd_err("Invalid setparam command %d value %d", + sub_cmd, set_value); + ret = -EINVAL; + break; + } + EXIT(); + return ret; +} + +/** + * __iw_softap_get_three() - return three value to upper layer. + * @dev: pointer of net_device of this wireless card + * @info: meta data about Request sent + * @wrqu: include request info + * @extra: buf used for in/out + * + * Return: execute result + */ +static int __iw_softap_get_three(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + uint32_t *value = (uint32_t *)extra; + uint32_t sub_cmd = value[0]; + int ret = 0; /* success */ + struct hdd_context_s *hdd_ctx; + struct hdd_adapter_s *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret != 0) + return ret; + + switch (sub_cmd) { + case QCSAP_GET_TSF: + ret = hdd_indicate_tsf(adapter, value, 3); + break; + default: + hdd_err("Invalid getparam command %d", sub_cmd); + ret = -EINVAL; + break; + } + return ret; +} + + +/** + * iw_softap_get_three() - return three value to upper layer. + * + * @dev: pointer of net_device of this wireless card + * @info: meta data about Request sent + * @wrqu: include request info + * @extra: buf used for in/Output + * + * Return: execute result + */ +static int iw_softap_get_three(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_softap_get_three(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +int +static iw_softap_setparam(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_softap_setparam(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +int +static __iw_softap_getparam(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + hdd_adapter_t *pHostapdAdapter = (netdev_priv(dev)); + tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pHostapdAdapter); + int *value = (int *)extra; + int sub_cmd = value[0]; + QDF_STATUS status; + int ret; + hdd_context_t *hdd_ctx; + uint8_t nol[QDF_MAX_NUM_CHAN]; + uint32_t nol_len = 0; + + ENTER_DEV(dev); + + hdd_ctx = WLAN_HDD_GET_CTX(pHostapdAdapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + switch (sub_cmd) { + case QCSAP_PARAM_MAX_ASSOC: + status = + sme_cfg_get_int(hHal, WNI_CFG_ASSOC_STA_LIMIT, + (uint32_t *) value); + if (QDF_STATUS_SUCCESS != status) { + hdd_err("failed to get WNI_CFG_ASSOC_STA_LIMIT from cfg %d", + status); + ret = -EIO; + } + break; + + case QCSAP_PARAM_AUTO_CHANNEL: + *value = (WLAN_HDD_GET_CTX + (pHostapdAdapter))->config->force_sap_acs; + break; + + case QCSAP_PARAM_GET_WLAN_DBG: + { + qdf_trace_display(); + *value = 0; + break; + } + + case QCSAP_PARAM_RTSCTS: + { + *value = wma_cli_get_command(pHostapdAdapter->sessionId, + WMI_VDEV_PARAM_ENABLE_RTSCTS, + VDEV_CMD); + break; + } + + case QCASAP_SHORT_GI: + { + *value = (int)sme_get_ht_config(hHal, + pHostapdAdapter-> + sessionId, + WNI_CFG_HT_CAP_INFO_SHORT_GI_20MHZ); + break; + } + + case QCSAP_GTX_HT_MCS: + { + hdd_notice("GET WMI_VDEV_PARAM_GTX_HT_MCS"); + *value = wma_cli_get_command(pHostapdAdapter->sessionId, + WMI_VDEV_PARAM_GTX_HT_MCS, + GTX_CMD); + break; + } + + case QCSAP_GTX_VHT_MCS: + { + hdd_notice("GET WMI_VDEV_PARAM_GTX_VHT_MCS"); + *value = wma_cli_get_command(pHostapdAdapter->sessionId, + WMI_VDEV_PARAM_GTX_VHT_MCS, + GTX_CMD); + break; + } + + case QCSAP_GTX_USRCFG: + { + hdd_notice("GET WMI_VDEV_PARAM_GTX_USR_CFG"); + *value = wma_cli_get_command(pHostapdAdapter->sessionId, + WMI_VDEV_PARAM_GTX_USR_CFG, + GTX_CMD); + break; + } + + case QCSAP_GTX_THRE: + { + hdd_notice("GET WMI_VDEV_PARAM_GTX_THRE"); + *value = wma_cli_get_command(pHostapdAdapter->sessionId, + WMI_VDEV_PARAM_GTX_THRE, + GTX_CMD); + break; + } + + case QCSAP_GTX_MARGIN: + { + hdd_notice("GET WMI_VDEV_PARAM_GTX_MARGIN"); + *value = wma_cli_get_command(pHostapdAdapter->sessionId, + WMI_VDEV_PARAM_GTX_MARGIN, + GTX_CMD); + break; + } + + case QCSAP_GTX_STEP: + { + hdd_notice("GET WMI_VDEV_PARAM_GTX_STEP"); + *value = wma_cli_get_command(pHostapdAdapter->sessionId, + WMI_VDEV_PARAM_GTX_STEP, + GTX_CMD); + break; + } + + case QCSAP_GTX_MINTPC: + { + hdd_notice("GET WMI_VDEV_PARAM_GTX_MINTPC"); + *value = wma_cli_get_command(pHostapdAdapter->sessionId, + WMI_VDEV_PARAM_GTX_MINTPC, + GTX_CMD); + break; + } + + case QCSAP_GTX_BWMASK: + { + hdd_notice("GET WMI_VDEV_PARAM_GTX_BW_MASK"); + *value = wma_cli_get_command(pHostapdAdapter->sessionId, + WMI_VDEV_PARAM_GTX_BW_MASK, + GTX_CMD); + break; + } + + case QCASAP_GET_DFS_NOL: + { + wlansap_get_dfs_nol( + WLAN_HDD_GET_SAP_CTX_PTR(pHostapdAdapter), + nol, &nol_len); + } + break; + + case QCSAP_GET_ACL: + { + hdd_notice("QCSAP_GET_ACL"); + if (hdd_print_acl(pHostapdAdapter) != + QDF_STATUS_SUCCESS) { + hdd_err("QCSAP_GET_ACL returned Error: not completed"); + } + *value = 0; + break; + } + + case QCASAP_TX_CHAINMASK_CMD: + { + hdd_notice("QCASAP_TX_CHAINMASK_CMD"); + *value = wma_cli_get_command(pHostapdAdapter->sessionId, + WMI_PDEV_PARAM_TX_CHAIN_MASK, + PDEV_CMD); + break; + } + + case QCASAP_RX_CHAINMASK_CMD: + { + hdd_notice("QCASAP_RX_CHAINMASK_CMD"); + *value = wma_cli_get_command(pHostapdAdapter->sessionId, + WMI_PDEV_PARAM_RX_CHAIN_MASK, + PDEV_CMD); + break; + } + + case QCASAP_NSS_CMD: + { + hdd_notice("QCASAP_NSS_CMD"); + *value = wma_cli_get_command(pHostapdAdapter->sessionId, + WMI_VDEV_PARAM_NSS, + VDEV_CMD); + break; + } + case QCSAP_CAP_TSF: + ret = hdd_capture_tsf(pHostapdAdapter, (uint32_t *)value, 1); + break; + case QCASAP_GET_TEMP_CMD: + { + hdd_notice("QCASAP_GET_TEMP_CMD"); + ret = wlan_hdd_get_temperature(pHostapdAdapter, value); + break; + } + case QCSAP_GET_FW_PROFILE_DATA: + hdd_notice("QCSAP_GET_FW_PROFILE_DATA"); + ret = wma_cli_set_command(pHostapdAdapter->sessionId, + WMI_WLAN_PROFILE_GET_PROFILE_DATA_CMDID, + 0, DBG_CMD); + break; + case QCASAP_PARAM_LDPC: + { + ret = hdd_get_ldpc(pHostapdAdapter, value); + break; + } + case QCASAP_PARAM_TX_STBC: + { + ret = hdd_get_tx_stbc(pHostapdAdapter, value); + break; + } + case QCASAP_PARAM_RX_STBC: + { + ret = hdd_get_rx_stbc(pHostapdAdapter, value); + break; + } + case QCSAP_PARAM_CHAN_WIDTH: + { + ret = hdd_sap_get_chan_width(pHostapdAdapter, value); + break; + } + default: + hdd_err("Invalid getparam command %d", sub_cmd); + ret = -EINVAL; + break; + + } + EXIT(); + return ret; +} + +int +static iw_softap_getparam(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_softap_getparam(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +/* Usage: + BLACK_LIST = 0 + WHITE_LIST = 1 + ADD MAC = 0 + REMOVE MAC = 1 + + mac addr will be accepted as a 6 octet mac address with each octet inputted in hex + for e.g. 00:0a:f5:11:22:33 will be represented as 0x00 0x0a 0xf5 0x11 0x22 0x33 + while using this ioctl + + Syntax: + iwpriv softap.0 modify_acl + <6 octet mac addr> + + Examples: + eg 1. to add a mac addr 00:0a:f5:89:89:90 to the black list + iwpriv softap.0 modify_acl 0x00 0x0a 0xf5 0x89 0x89 0x90 0 0 + eg 2. to delete a mac addr 00:0a:f5:89:89:90 from white list + iwpriv softap.0 modify_acl 0x00 0x0a 0xf5 0x89 0x89 0x90 1 1 + */ +static +int __iw_softap_modify_acl(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + hdd_adapter_t *pHostapdAdapter = (netdev_priv(dev)); + uint8_t *value = (uint8_t *) extra; + uint8_t pPeerStaMac[QDF_MAC_ADDR_SIZE]; + int listType, cmd, i; + int ret; + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + hdd_context_t *hdd_ctx; + + ENTER_DEV(dev); + + hdd_ctx = WLAN_HDD_GET_CTX(pHostapdAdapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + for (i = 0; i < QDF_MAC_ADDR_SIZE; i++) + pPeerStaMac[i] = *(value + i); + + listType = (int)(*(value + i)); + i++; + cmd = (int)(*(value + i)); + + hdd_notice("Modify ACL mac:" MAC_ADDRESS_STR " type: %d cmd: %d", + MAC_ADDR_ARRAY(pPeerStaMac), listType, cmd); + + qdf_status = wlansap_modify_acl( + WLAN_HDD_GET_SAP_CTX_PTR(pHostapdAdapter), + pPeerStaMac, (eSapACLType) listType, (eSapACLCmdType) cmd); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + hdd_err("Modify ACL failed"); + ret = -EIO; + } + EXIT(); + return ret; +} + +static +int iw_softap_modify_acl(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_softap_modify_acl(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +int +static __iw_softap_getchannel(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + hdd_adapter_t *pHostapdAdapter = (netdev_priv(dev)); + hdd_context_t *hdd_ctx; + int *value = (int *)extra; + int ret; + + ENTER_DEV(dev); + + hdd_ctx = WLAN_HDD_GET_CTX(pHostapdAdapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + *value = 0; + if (test_bit(SOFTAP_BSS_STARTED, &pHostapdAdapter->event_flags)) + *value = (WLAN_HDD_GET_AP_CTX_PTR( + pHostapdAdapter))->operatingChannel; + EXIT(); + return 0; +} + +int +static iw_softap_getchannel(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_softap_getchannel(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +int +static __iw_softap_set_max_tx_power(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + hdd_adapter_t *pHostapdAdapter = (netdev_priv(dev)); + hdd_context_t *hdd_ctx; + tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pHostapdAdapter); + int *value = (int *)extra; + int set_value; + int ret; + struct qdf_mac_addr bssid = QDF_MAC_ADDR_BROADCAST_INITIALIZER; + struct qdf_mac_addr selfMac = QDF_MAC_ADDR_BROADCAST_INITIALIZER; + + ENTER_DEV(dev); + + if (NULL == value) + return -ENOMEM; + + hdd_ctx = WLAN_HDD_GET_CTX(pHostapdAdapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + /* Assign correct slef MAC address */ + qdf_copy_macaddr(&bssid, &pHostapdAdapter->macAddressCurrent); + qdf_copy_macaddr(&selfMac, &pHostapdAdapter->macAddressCurrent); + + set_value = value[0]; + if (QDF_STATUS_SUCCESS != + sme_set_max_tx_power(hHal, bssid, selfMac, set_value)) { + hdd_err("Setting maximum tx power failed"); + return -EIO; + } + EXIT(); + return 0; +} + +int +static iw_softap_set_max_tx_power(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_softap_set_max_tx_power(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +int +static __iw_softap_set_pktlog(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + hdd_adapter_t *pHostapdAdapter = netdev_priv(dev); + hdd_context_t *hdd_ctx; + int *value = (int *)extra; + + ENTER_DEV(dev); + + if (NULL == value) + return -ENOMEM; + + if (wrqu->data.length < 1 || wrqu->data.length > 2) { + hdd_err("pktlog: either 1 or 2 parameters are required"); + return -EINVAL; + } + + hdd_ctx = WLAN_HDD_GET_CTX(pHostapdAdapter); + return hdd_process_pktlog_command(hdd_ctx, value[0], value[1]); +} + +int +static iw_softap_set_pktlog(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_softap_set_pktlog(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + + +int +static __iw_softap_set_tx_power(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + hdd_adapter_t *pHostapdAdapter = (netdev_priv(dev)); + tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pHostapdAdapter); + hdd_context_t *hdd_ctx; + int *value = (int *)extra; + int set_value; + struct qdf_mac_addr bssid; + int ret; + + ENTER_DEV(dev); + + hdd_ctx = WLAN_HDD_GET_CTX(pHostapdAdapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + if (NULL == value) + return -ENOMEM; + + qdf_copy_macaddr(&bssid, &pHostapdAdapter->macAddressCurrent); + + set_value = value[0]; + if (QDF_STATUS_SUCCESS != + sme_set_tx_power(hHal, pHostapdAdapter->sessionId, bssid, + pHostapdAdapter->device_mode, set_value)) { + hdd_err("Setting tx power failed"); + return -EIO; + } + EXIT(); + return 0; +} + +int +static iw_softap_set_tx_power(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_softap_set_tx_power(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +#define IS_BROADCAST_MAC(x) (((x[0] & x[1] & x[2] & x[3] & x[4] & x[5]) == 0xff) ? 1 : 0) + +int +static __iw_softap_getassoc_stamacaddr(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + hdd_adapter_t *pHostapdAdapter = (netdev_priv(dev)); + hdd_station_info_t *pStaInfo = pHostapdAdapter->aStaInfo; + hdd_context_t *hdd_ctx; + char *buf; + int cnt = 0; + int left; + int ret; + /* maclist_index must be u32 to match userspace */ + u32 maclist_index; + + ENTER_DEV(dev); + + /* + * NOTE WELL: this is a "get" ioctl but it uses an even ioctl + * number, and even numbered iocts are supposed to have "set" + * semantics. Hence the wireless extensions support in the kernel + * won't correctly copy the result to userspace, so the ioctl + * handler itself must copy the data. Output format is 32-bit + * record length, followed by 0 or more 6-byte STA MAC addresses. + * + * Further note that due to the incorrect semantics, the "iwpriv" + * userspace application is unable to correctly invoke this API, + * hence it is not registered in the hostapd_private_args. This + * API can only be invoked by directly invoking the ioctl() system + * call. + */ + + hdd_ctx = WLAN_HDD_GET_CTX(pHostapdAdapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + /* make sure userspace allocated a reasonable buffer size */ + if (wrqu->data.length < sizeof(maclist_index)) { + hdd_notice("invalid userspace buffer"); + return -EINVAL; + } + + /* allocate local buffer to build the response */ + buf = qdf_mem_malloc(wrqu->data.length); + if (!buf) { + hdd_notice("failed to allocate response buffer"); + return -ENOMEM; + } + + /* start indexing beyond where the record count will be written */ + maclist_index = sizeof(maclist_index); + left = wrqu->data.length - maclist_index; + + spin_lock_bh(&pHostapdAdapter->staInfo_lock); + while ((cnt < WLAN_MAX_STA_COUNT) && (left >= QDF_MAC_ADDR_SIZE)) { + if ((pStaInfo[cnt].isUsed) && + (!IS_BROADCAST_MAC(pStaInfo[cnt].macAddrSTA.bytes))) { + memcpy(&buf[maclist_index], &(pStaInfo[cnt].macAddrSTA), + QDF_MAC_ADDR_SIZE); + maclist_index += QDF_MAC_ADDR_SIZE; + left -= QDF_MAC_ADDR_SIZE; + } + cnt++; + } + spin_unlock_bh(&pHostapdAdapter->staInfo_lock); + + *((u32 *) buf) = maclist_index; + wrqu->data.length = maclist_index; + if (copy_to_user(wrqu->data.pointer, buf, maclist_index)) { + hdd_notice("failed to copy response to user buffer"); + ret = -EFAULT; + } + qdf_mem_free(buf); + EXIT(); + return ret; +} + +int +static iw_softap_getassoc_stamacaddr(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_softap_getassoc_stamacaddr(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +/* Usage: + mac addr will be accepted as a 6 octet mac address with each octet inputted in hex + for e.g. 00:0a:f5:11:22:33 will be represented as 0x00 0x0a 0xf5 0x11 0x22 0x33 + while using this ioctl + + Syntax: + iwpriv softap.0 disassoc_sta <6 octet mac address> + + e.g. + disassociate sta with mac addr 00:0a:f5:11:22:33 from softap + iwpriv softap.0 disassoc_sta 0x00 0x0a 0xf5 0x11 0x22 0x33 + */ + +int +static __iw_softap_disassoc_sta(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + hdd_adapter_t *pHostapdAdapter = (netdev_priv(dev)); + hdd_context_t *hdd_ctx; + uint8_t *peerMacAddr; + int ret; + struct tagCsrDelStaParams del_sta_params; + + ENTER_DEV(dev); + + if (!capable(CAP_NET_ADMIN)) { + hdd_err("permission check failed"); + return -EPERM; + } + + hdd_ctx = WLAN_HDD_GET_CTX(pHostapdAdapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + /* iwpriv tool or framework calls this ioctl with + * data passed in extra (less than 16 octets); + */ + peerMacAddr = (uint8_t *) (extra); + + hdd_notice("data " MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(peerMacAddr)); + wlansap_populate_del_sta_params(peerMacAddr, + eSIR_MAC_DEAUTH_LEAVING_BSS_REASON, + (SIR_MAC_MGMT_DISASSOC >> 4), + &del_sta_params); + hdd_softap_sta_disassoc(pHostapdAdapter, &del_sta_params); + EXIT(); + return 0; +} + +int +static iw_softap_disassoc_sta(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_softap_disassoc_sta(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * iw_get_char_setnone() - Generic "get char" private ioctl handler + * @dev: device upon which the ioctl was received + * @info: ioctl request information + * @wrqu: ioctl request data + * @extra: ioctl extra data + * + * Return: 0 on success, non-zero on error + */ +static int __iw_get_char_setnone(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + int ret; + int sub_cmd = wrqu->data.flags; + hdd_context_t *hdd_ctx; + + ENTER_DEV(dev); + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret != 0) + return ret; + + switch (sub_cmd) { + case QCSAP_GET_STATS: + hdd_wlan_get_stats(adapter, &(wrqu->data.length), + extra, WE_MAX_STR_LEN); + break; + case QCSAP_LIST_FW_PROFILE: + hdd_wlan_list_fw_profile(&(wrqu->data.length), + extra, WE_MAX_STR_LEN); + break; + } + + EXIT(); + return ret; +} + +static int iw_get_char_setnone(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_get_char_setnone(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +static int wlan_hdd_set_force_acs_ch_range(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + hdd_adapter_t *adapter = (netdev_priv(dev)); + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + int *value = (int *)extra; + + ENTER_DEV(dev); + + if (!capable(CAP_NET_ADMIN)) { + hdd_err("permission check failed"); + return -EPERM; + } + + if (wlan_hdd_validate_operation_channel(adapter, value[0]) != + QDF_STATUS_SUCCESS || + wlan_hdd_validate_operation_channel(adapter, value[1]) != + QDF_STATUS_SUCCESS) { + return -EINVAL; + } else { + hdd_ctx->config->force_sap_acs_st_ch = value[0]; + hdd_ctx->config->force_sap_acs_end_ch = value[1]; + } + + return 0; +} + +static int iw_softap_set_force_acs_ch_range(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + cds_ssr_protect(__func__); + ret = wlan_hdd_set_force_acs_ch_range(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + return ret; +} + +static int __iw_get_channel_list(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + uint32_t num_channels = 0; + uint8_t i = 0; + uint8_t band_start_channel = CHAN_ENUM_1; + uint8_t band_end_channel = CHAN_ENUM_184; + hdd_adapter_t *hostapd_adapter = (netdev_priv(dev)); + tHalHandle hal = WLAN_HDD_GET_HAL_CTX(hostapd_adapter); + tpChannelListInfo channel_list = (tpChannelListInfo) extra; + eCsrBand cur_band = eCSR_BAND_ALL; + hdd_context_t *hdd_ctx; + int ret; + bool is_dfs_mode_enabled = false; + + ENTER_DEV(dev); + + hdd_ctx = WLAN_HDD_GET_CTX(hostapd_adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + if (QDF_STATUS_SUCCESS != sme_get_freq_band(hal, &cur_band)) { + hdd_err("not able get the current frequency band"); + return -EIO; + } + wrqu->data.length = sizeof(tChannelListInfo); + + if (eCSR_BAND_24 == cur_band) { + band_start_channel = CHAN_ENUM_1; + band_end_channel = CHAN_ENUM_14; + } else if (eCSR_BAND_5G == cur_band) { + band_start_channel = CHAN_ENUM_36; + band_end_channel = CHAN_ENUM_184; + } + if (cur_band != eCSR_BAND_24) { + if (hdd_ctx->config->dot11p_mode) + band_end_channel = CHAN_ENUM_184; + else + band_end_channel = CHAN_ENUM_165; + } + + if (hostapd_adapter->device_mode == QDF_STA_MODE && + hdd_ctx->config->enableDFSChnlScan) { + is_dfs_mode_enabled = true; + } else if (hostapd_adapter->device_mode == QDF_SAP_MODE && + hdd_ctx->config->enableDFSMasterCap) { + is_dfs_mode_enabled = true; + } + + hdd_notice("curBand = %d, StartChannel = %hu, EndChannel = %hu is_dfs_mode_enabled = %d ", + cur_band, band_start_channel, band_end_channel, + is_dfs_mode_enabled); + + for (i = band_start_channel; i <= band_end_channel; i++) { + if ((CHANNEL_STATE_ENABLE == CDS_CHANNEL_STATE(i)) || + (is_dfs_mode_enabled && + CHANNEL_STATE_DFS == CDS_CHANNEL_STATE(i))) { + channel_list->channels[num_channels] = + CDS_CHANNEL_NUM(i); + num_channels++; + } + } + + hdd_notice(" number of channels %d", num_channels); + + channel_list->num_channels = num_channels; + EXIT(); + + return 0; +} + +int iw_get_channel_list(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_get_channel_list(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +static +int __iw_get_genie(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + hdd_adapter_t *pHostapdAdapter = (netdev_priv(dev)); + hdd_context_t *hdd_ctx; + int ret; + QDF_STATUS status; + uint32_t length = DOT11F_IE_RSN_MAX_LEN; + uint8_t genIeBytes[DOT11F_IE_RSN_MAX_LEN]; + + ENTER_DEV(dev); + + hdd_ctx = WLAN_HDD_GET_CTX(pHostapdAdapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + /* + * Actually retrieve the RSN IE from CSR. + * (We previously sent it down in the CSR Roam Profile.) + */ + status = wlan_sap_getstation_ie_information( + WLAN_HDD_GET_SAP_CTX_PTR(pHostapdAdapter), + &length, genIeBytes); + if (status == QDF_STATUS_SUCCESS) { + wrqu->data.length = length; + if (length > DOT11F_IE_RSN_MAX_LEN) { + hdd_notice("invalid buffer length length:%d", length); + return -E2BIG; + } + qdf_mem_copy(extra, genIeBytes, length); + hdd_notice(" RSN IE of %d bytes returned", + wrqu->data.length); + } else { + wrqu->data.length = 0; + hdd_notice(" RSN IE failed to populate"); + } + + EXIT(); + return 0; +} + +static +int iw_get_genie(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_get_genie(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +static +int __iw_get_wpspbc_probe_req_ies(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + hdd_adapter_t *pHostapdAdapter = (netdev_priv(dev)); + sQcSapreq_WPSPBCProbeReqIES_t WPSPBCProbeReqIEs; + hdd_ap_ctx_t *pHddApCtx = WLAN_HDD_GET_AP_CTX_PTR(pHostapdAdapter); + hdd_context_t *hdd_ctx; + int ret; + + ENTER_DEV(dev); + + hdd_ctx = WLAN_HDD_GET_CTX(pHostapdAdapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + hdd_notice("get_WPSPBCProbeReqIEs ioctl"); + memset((void *)&WPSPBCProbeReqIEs, 0, sizeof(WPSPBCProbeReqIEs)); + + WPSPBCProbeReqIEs.probeReqIELen = + pHddApCtx->WPSPBCProbeReq.probeReqIELen; + qdf_mem_copy(&WPSPBCProbeReqIEs.probeReqIE, + pHddApCtx->WPSPBCProbeReq.probeReqIE, + WPSPBCProbeReqIEs.probeReqIELen); + qdf_copy_macaddr(&WPSPBCProbeReqIEs.macaddr, + &pHddApCtx->WPSPBCProbeReq.peer_macaddr); + if (copy_to_user(wrqu->data.pointer, + (void *)&WPSPBCProbeReqIEs, + sizeof(WPSPBCProbeReqIEs))) { + hdd_notice("failed to copy data to user buffer"); + return -EFAULT; + } + wrqu->data.length = 12 + WPSPBCProbeReqIEs.probeReqIELen; + hdd_info("Macaddress : " MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(WPSPBCProbeReqIEs.macaddr.bytes)); + up(&pHddApCtx->semWpsPBCOverlapInd); + EXIT(); + return 0; +} + +static +int iw_get_wpspbc_probe_req_ies(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_get_wpspbc_probe_req_ies(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __iw_set_auth_hostap() - + * This function sets the auth type received from the wpa_supplicant. + * + * @dev: pointer to the net device. + * @info: pointer to the iw_request_info. + * @wrqu: pointer to the iwreq_data. + * @extra: pointer to the data. + * + * Return: 0 for success, non zero for failure + */ +static +int __iw_set_auth_hostap(struct net_device *dev, struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_wext_state_t *pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter); + hdd_context_t *hdd_ctx; + int ret; + + ENTER_DEV(dev); + + hdd_ctx = WLAN_HDD_GET_CTX(pAdapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + switch (wrqu->param.flags & IW_AUTH_INDEX) { + case IW_AUTH_TKIP_COUNTERMEASURES: + { + if (wrqu->param.value) { + hdd_info("Counter Measure started %d", + wrqu->param.value); + pWextState->mTKIPCounterMeasures = + TKIP_COUNTER_MEASURE_STARTED; + } else { + hdd_info("Counter Measure stopped=%d", + wrqu->param.value); + pWextState->mTKIPCounterMeasures = + TKIP_COUNTER_MEASURE_STOPED; + } + + hdd_softap_tkip_mic_fail_counter_measure(pAdapter, + wrqu->param. + value); + } + break; + + default: + + hdd_warn("called with unsupported auth type %d", + wrqu->param.flags & IW_AUTH_INDEX); + break; + } + + EXIT(); + return 0; +} + +/** + * iw_set_auth_hostap() - Wrapper function to protect __iw_set_auth_hostap + * from the SSR. + * + * @dev - Pointer to the net device. + * @info - Pointer to the iw_request_info. + * @wrqu - Pointer to the iwreq_data. + * @extra - Pointer to the data. + * + * Return: 0 for success, non zero for failure. + */ +static int +iw_set_auth_hostap(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_set_auth_hostap(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __iw_set_ap_encodeext() - set ap encode + * + * @dev - Pointer to the net device. + * @info - Pointer to the iw_request_info. + * @wrqu - Pointer to the iwreq_data. + * @extra - Pointer to the data. + * + * Return: 0 for success, non zero for failure. + */ +static int __iw_set_ap_encodeext(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + hdd_adapter_t *pHostapdAdapter = (netdev_priv(dev)); + hdd_ap_ctx_t *pHddApCtx = WLAN_HDD_GET_AP_CTX_PTR(pHostapdAdapter); + hdd_context_t *hdd_ctx; + int ret; + QDF_STATUS vstatus; + struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; + int key_index; + struct iw_point *encoding = &wrqu->encoding; + tCsrRoamSetKey setKey; + int i; + + ENTER_DEV(dev); + + hdd_ctx = WLAN_HDD_GET_CTX(pHostapdAdapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + key_index = encoding->flags & IW_ENCODE_INDEX; + + if (key_index > 0) { + /*Convert from 1-based to 0-based keying */ + key_index--; + } + if (!ext->key_len) + return ret; + + qdf_mem_zero(&setKey, sizeof(tCsrRoamSetKey)); + + setKey.keyId = key_index; + setKey.keyLength = ext->key_len; + + if (ext->key_len <= CSR_MAX_KEY_LEN) { + qdf_mem_copy(&setKey.Key[0], ext->key, ext->key_len); + } + + if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) { + /*Key direction for group is RX only */ + setKey.keyDirection = eSIR_RX_ONLY; + qdf_set_macaddr_broadcast(&setKey.peerMac); + } else { + + setKey.keyDirection = eSIR_TX_RX; + qdf_mem_copy(setKey.peerMac.bytes, ext->addr.sa_data, + QDF_MAC_ADDR_SIZE); + } + if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) { + setKey.keyDirection = eSIR_TX_DEFAULT; + qdf_mem_copy(setKey.peerMac.bytes, ext->addr.sa_data, + QDF_MAC_ADDR_SIZE); + } + + /*For supplicant pae role is zero */ + setKey.paeRole = 0; + + switch (ext->alg) { + case IW_ENCODE_ALG_NONE: + setKey.encType = eCSR_ENCRYPT_TYPE_NONE; + break; + + case IW_ENCODE_ALG_WEP: + setKey.encType = + (ext->key_len == + 5) ? eCSR_ENCRYPT_TYPE_WEP40 : eCSR_ENCRYPT_TYPE_WEP104; + pHddApCtx->uPrivacy = 1; + hdd_notice("uPrivacy=%d", pHddApCtx->uPrivacy); + break; + + case IW_ENCODE_ALG_TKIP: + { + uint8_t *pKey = &setKey.Key[0]; + + setKey.encType = eCSR_ENCRYPT_TYPE_TKIP; + + qdf_mem_zero(pKey, CSR_MAX_KEY_LEN); + + /*Supplicant sends the 32bytes key in this order + + |--------------|----------|----------| + | Tk1 |TX-MIC | RX Mic | + |||--------------|----------|----------| + <---16bytes---><--8bytes--><--8bytes--> + + */ + /*Sme expects the 32 bytes key to be in the below order + + |--------------|----------|----------| + | Tk1 |RX-MIC | TX Mic | + |||--------------|----------|----------| + <---16bytes---><--8bytes--><--8bytes--> + */ + /* Copy the Temporal Key 1 (TK1) */ + qdf_mem_copy(pKey, ext->key, 16); + + /*Copy the rx mic first */ + qdf_mem_copy(&pKey[16], &ext->key[24], 8); + + /*Copy the tx mic */ + qdf_mem_copy(&pKey[24], &ext->key[16], 8); + + } + break; + + case IW_ENCODE_ALG_CCMP: + setKey.encType = eCSR_ENCRYPT_TYPE_AES; + break; + + default: + setKey.encType = eCSR_ENCRYPT_TYPE_NONE; + break; + } + + hdd_notice(":EncryptionType:%d key_len:%d, KeyId:%d", + setKey.encType, setKey.keyLength, setKey.keyId); + for (i = 0; i < ext->key_len; i++) + hdd_notice("%02x", setKey.Key[i]); + + vstatus = wlansap_set_key_sta( + WLAN_HDD_GET_SAP_CTX_PTR(pHostapdAdapter), &setKey); + + if (vstatus != QDF_STATUS_SUCCESS) { + hdd_err("wlansap_set_key_sta failed, status= %d", + vstatus); + ret = -EINVAL; + } + EXIT(); + return ret; +} + +/** + * iw_set_ap_encodeext() - Wrapper function to protect __iw_set_ap_encodeext + * from the SSR. + * + * @dev - Pointer to the net device. + * @info - Pointer to the iw_request_info. + * @wrqu - Pointer to the iwreq_data. + * @extra - Pointer to the data. + * + * Return: 0 for success, non zero for failure. + */ +static int iw_set_ap_encodeext(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_set_ap_encodeext(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __iw_set_ap_mlme() - set ap mlme + * @dev: pointer to net_device + * @info: pointer to iw_request_info + * @wrqu; pointer to iwreq_data + * @extra: extra + * + * Return; 0 on success, error number otherwise + */ +static int __iw_set_ap_mlme(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + ENTER_DEV(dev); + return 0; +} + +/** + * iw_set_ap_mlme() - SSR wrapper for __iw_set_ap_mlme + * @dev: pointer to net_device + * @info: pointer to iw_request_info + * @wrqu; pointer to iwreq_data + * @extra: extra + * + * Return; 0 on success, error number otherwise + */ +static int iw_set_ap_mlme(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_set_ap_mlme(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __iw_get_ap_rts_threshold() - get ap rts threshold + * @dev - Pointer to the net device. + * @info - Pointer to the iw_request_info. + * @wrqu - Pointer to the iwreq_data. + * @extra - Pointer to the data. + * + * Return: 0 for success, non zero for failure. + */ +static int __iw_get_ap_rts_threshold(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) { + + hdd_adapter_t *pHostapdAdapter = netdev_priv(dev); + int ret; + hdd_context_t *hdd_ctx; + + ENTER_DEV(dev); + + hdd_ctx = WLAN_HDD_GET_CTX(pHostapdAdapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + ret = hdd_wlan_get_rts_threshold(pHostapdAdapter, wrqu); + + return ret; +} + +/** + * iw_get_ap_rts_threshold() - Wrapper function to protect + * __iw_get_ap_rts_threshold from the SSR. + * @dev - Pointer to the net device. + * @info - Pointer to the iw_request_info. + * @wrqu - Pointer to the iwreq_data. + * @extra - Pointer to the data. + * + * Return: 0 for success, non zero for failure. + */ +static int iw_get_ap_rts_threshold(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_get_ap_rts_threshold(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __iw_get_ap_frag_threshold() - get ap fragmentation threshold + * @dev - Pointer to the net device. + * @info - Pointer to the iw_request_info. + * @wrqu - Pointer to the iwreq_data. + * @extra - Pointer to the data. + * + * Return: 0 for success, non zero for failure. + */ +static int __iw_get_ap_frag_threshold(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) { + + hdd_adapter_t *pHostapdAdapter = netdev_priv(dev); + hdd_context_t *hdd_ctx; + int ret = 0; + + ENTER_DEV(dev); + + hdd_ctx = WLAN_HDD_GET_CTX(pHostapdAdapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + ret = hdd_wlan_get_frag_threshold(pHostapdAdapter, wrqu); + + return ret; +} + +/** + * iw_get_ap_frag_threshold() - Wrapper function to protect + * __iw_get_ap_frag_threshold from the SSR. + * @dev - Pointer to the net device. + * @info - Pointer to the iw_request_info. + * @wrqu - Pointer to the iwreq_data. + * @extra - Pointer to the data. + * + * Return: 0 for success, non zero for failure. + */ +static int iw_get_ap_frag_threshold(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_get_ap_frag_threshold(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __iw_get_ap_freq() - get ap frequency + * @dev - Pointer to the net device. + * @info - Pointer to the iw_request_info. + * @wrqu - Pointer to the iwreq_data. + * @extra - Pointer to the data. + * + * Return: 0 for success, non zero for failure. + */ +static int __iw_get_ap_freq(struct net_device *dev, + struct iw_request_info *info, struct iw_freq *fwrq, + char *extra) { + uint32_t status = false, channel = 0, freq = 0; + hdd_adapter_t *pHostapdAdapter = (netdev_priv(dev)); + hdd_context_t *hdd_ctx; + tHalHandle hHal; + hdd_hostapd_state_t *pHostapdState; + hdd_ap_ctx_t *pHddApCtx = WLAN_HDD_GET_AP_CTX_PTR(pHostapdAdapter); + int ret; + + ENTER_DEV(dev); + + hdd_ctx = WLAN_HDD_GET_CTX(pHostapdAdapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + pHostapdState = WLAN_HDD_GET_HOSTAP_STATE_PTR(pHostapdAdapter); + hHal = WLAN_HDD_GET_HAL_CTX(pHostapdAdapter); + + if (pHostapdState->bssState == BSS_STOP) { + if (sme_cfg_get_int(hHal, WNI_CFG_CURRENT_CHANNEL, &channel) + != QDF_STATUS_SUCCESS) { + return -EIO; + } else { + status = hdd_wlan_get_freq(channel, &freq); + if (true == status) { + /* Set Exponent parameter as 6 (MHZ) in struct + * iw_freq * iwlist & iwconfig command + * shows frequency into proper + * format (2.412 GHz instead of 246.2 MHz) + */ + fwrq->m = freq; + fwrq->e = MHZ; + } + } + } else { + channel = pHddApCtx->operatingChannel; + status = hdd_wlan_get_freq(channel, &freq); + if (true == status) { + /* Set Exponent parameter as 6 (MHZ) in struct iw_freq + * iwlist & iwconfig command shows frequency into proper + * format (2.412 GHz instead of 246.2 MHz)*/ + fwrq->m = freq; + fwrq->e = MHZ; + } + } + EXIT(); + return 0; +} + +/** + * iw_get_ap_freq() - Wrapper function to protect + * __iw_get_ap_freq from the SSR. + * @dev - Pointer to the net device. + * @info - Pointer to the iw_request_info. + * @wrqu - Pointer to the iwreq_data. + * @extra - Pointer to the data. + * + * Return: 0 for success, non zero for failure. + */ +static int iw_get_ap_freq(struct net_device *dev, + struct iw_request_info *info, + struct iw_freq *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_get_ap_freq(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __iw_get_mode() - get mode + * @dev - Pointer to the net device. + * @info - Pointer to the iw_request_info. + * @wrqu - Pointer to the iwreq_data. + * @extra - Pointer to the data. + * + * Return: 0 for success, non zero for failure. + */ +static int __iw_get_mode(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) { + + hdd_adapter_t *adapter; + hdd_context_t *hdd_ctx; + int ret; + + ENTER_DEV(dev); + + adapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + wrqu->mode = IW_MODE_MASTER; + + return ret; +} + +/** + * iw_get_mode() - Wrapper function to protect __iw_get_mode from the SSR. + * @dev - Pointer to the net device. + * @info - Pointer to the iw_request_info. + * @wrqu - Pointer to the iwreq_data. + * @extra - Pointer to the data. + * + * Return: 0 for success, non zero for failure. + */ +static int iw_get_mode(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_get_mode(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +static int +__iw_softap_stopbss(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + hdd_adapter_t *pHostapdAdapter = (netdev_priv(dev)); + QDF_STATUS status = QDF_STATUS_SUCCESS; + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + hdd_context_t *hdd_ctx; + + ENTER_DEV(dev); + + hdd_ctx = WLAN_HDD_GET_CTX(pHostapdAdapter); + status = wlan_hdd_validate_context(hdd_ctx); + if (0 != status) + return status; + + if (test_bit(SOFTAP_BSS_STARTED, &pHostapdAdapter->event_flags)) { + hdd_hostapd_state_t *pHostapdState = + WLAN_HDD_GET_HOSTAP_STATE_PTR(pHostapdAdapter); + + qdf_event_reset(&pHostapdState->qdf_stop_bss_event); + status = wlansap_stop_bss( + WLAN_HDD_GET_SAP_CTX_PTR(pHostapdAdapter)); + if (QDF_IS_STATUS_SUCCESS(status)) { + qdf_status = + qdf_wait_single_event(&pHostapdState-> + qdf_stop_bss_event, + SME_CMD_TIMEOUT_VALUE); + + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + hdd_err("wait for single_event failed!!"); + QDF_ASSERT(0); + } + } + clear_bit(SOFTAP_BSS_STARTED, &pHostapdAdapter->event_flags); + cds_decr_session_set_pcl(pHostapdAdapter->device_mode, + pHostapdAdapter->sessionId); + } + EXIT(); + return (status == QDF_STATUS_SUCCESS) ? 0 : -EBUSY; +} + +static int iw_softap_stopbss(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_softap_stopbss(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +static int +__iw_softap_version(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + hdd_adapter_t *pHostapdAdapter = netdev_priv(dev); + hdd_context_t *hdd_ctx; + int ret; + + ENTER_DEV(dev); + + hdd_ctx = WLAN_HDD_GET_CTX(pHostapdAdapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + hdd_wlan_get_version(hdd_ctx, wrqu, extra); + EXIT(); + return 0; +} + +static int iw_softap_version(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_softap_version(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +static +QDF_STATUS hdd_softap_get_sta_info(hdd_adapter_t *pAdapter, uint8_t *pBuf, + int buf_len) { + uint8_t i; + uint8_t maxSta = 0; + int len = 0; + const char sta_info_header[] = "staId staAddress"; + hdd_context_t *hdd_ctx; + + ENTER(); + + if (NULL == pAdapter) { + hdd_err("Adapter is NULL"); + return -EINVAL; + } + + hdd_ctx = WLAN_HDD_GET_CTX(pAdapter); + if (0 != wlan_hdd_validate_context(hdd_ctx)) + return QDF_STATUS_E_FAULT; + + len = scnprintf(pBuf, buf_len, sta_info_header); + pBuf += len; + buf_len -= len; + + maxSta = hdd_ctx->config->maxNumberOfPeers; + + for (i = 0; i <= maxSta; i++) { + if (pAdapter->aStaInfo[i].isUsed) { + len = + scnprintf(pBuf, buf_len, + "%5d .%02x:%02x:%02x:%02x:%02x:%02x", + pAdapter->aStaInfo[i].ucSTAId, + pAdapter->aStaInfo[i].macAddrSTA.bytes[0], + pAdapter->aStaInfo[i].macAddrSTA.bytes[1], + pAdapter->aStaInfo[i].macAddrSTA.bytes[2], + pAdapter->aStaInfo[i].macAddrSTA.bytes[3], + pAdapter->aStaInfo[i].macAddrSTA.bytes[4], + pAdapter->aStaInfo[i].macAddrSTA. + bytes[5]); + pBuf += len; + buf_len -= len; + } + if (WE_GET_STA_INFO_SIZE > buf_len) { + break; + } + } + EXIT(); + return QDF_STATUS_SUCCESS; +} + +static int __iw_softap_get_sta_info(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + hdd_adapter_t *pHostapdAdapter = netdev_priv(dev); + QDF_STATUS status; + hdd_context_t *hdd_ctx; + int ret; + + ENTER_DEV(dev); + + hdd_ctx = WLAN_HDD_GET_CTX(pHostapdAdapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + status = + hdd_softap_get_sta_info(pHostapdAdapter, extra, + WE_SAP_MAX_STA_INFO); + + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("Failed to get sta info: %d", status); + return -EINVAL; + } + wrqu->data.length = strlen(extra); + EXIT(); + return 0; +} + +static int iw_softap_get_sta_info(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_softap_get_sta_info(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __iw_set_ap_genie() - set ap wpa/rsn ie + * + * @dev - Pointer to the net device. + * @info - Pointer to the iw_request_info. + * @wrqu - Pointer to the iwreq_data. + * @extra - Pointer to the data. + * + * Return: 0 for success, non zero for failure. + */ +static int __iw_set_ap_genie(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) { + + hdd_adapter_t *pHostapdAdapter = netdev_priv(dev); + hdd_context_t *hdd_ctx; + QDF_STATUS qdf_ret_status = QDF_STATUS_SUCCESS; + uint8_t *genie = (uint8_t *)extra; + int ret; + + ENTER_DEV(dev); + + hdd_ctx = WLAN_HDD_GET_CTX(pHostapdAdapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + if (!wrqu->data.length) { + EXIT(); + return 0; + } + + if (wrqu->data.length > DOT11F_IE_RSN_MAX_LEN) { + hdd_err("%s: WPARSN Ie input length is more than max[%d]", + __func__, wrqu->data.length); + return QDF_STATUS_E_INVAL; + } + + switch (genie[0]) { + case DOT11F_EID_WPA: + case DOT11F_EID_RSN: + if ((WLAN_HDD_GET_AP_CTX_PTR(pHostapdAdapter))->uPrivacy == 0) { + hdd_softap_deregister_bc_sta(pHostapdAdapter); + hdd_softap_register_bc_sta(pHostapdAdapter, 1); + } + (WLAN_HDD_GET_AP_CTX_PTR(pHostapdAdapter))->uPrivacy = 1; + qdf_ret_status = wlansap_set_wparsn_ies( + WLAN_HDD_GET_SAP_CTX_PTR(pHostapdAdapter), + genie, wrqu->data.length); + break; + + default: + hdd_err("Set UNKNOWN IE %X", genie[0]); + qdf_ret_status = 0; + } + + EXIT(); + return qdf_ret_status; +} + +/** + * iw_set_ap_genie() - Wrapper function to protect __iw_set_ap_genie + * from the SSR. + * + * @dev - Pointer to the net device. + * @info - Pointer to the iw_request_info. + * @wrqu - Pointer to the iwreq_data. + * @extra - Pointer to the data. + * + * Return: 0 for success, non zero for failure. + */ +static int +iw_set_ap_genie(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_set_ap_genie(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +static +int __iw_get_softap_linkspeed(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + hdd_adapter_t *pHostapdAdapter = (netdev_priv(dev)); + hdd_context_t *hdd_ctx; + char *pLinkSpeed = (char *)extra; + uint32_t link_speed = 0; + int len = sizeof(uint32_t) + 1; + struct qdf_mac_addr macAddress; + char pmacAddress[MAC_ADDRESS_STR_LEN + 1]; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + int rc, errno, i; + + ENTER_DEV(dev); + + hdd_ctx = WLAN_HDD_GET_CTX(pHostapdAdapter); + errno = wlan_hdd_validate_context(hdd_ctx); + if (errno) + return errno; + + hdd_notice("wrqu->data.length(%d)", wrqu->data.length); + + /* Linkspeed is allowed only for P2P mode */ + if (pHostapdAdapter->device_mode != QDF_P2P_GO_MODE) { + hdd_err("Link Speed is not allowed in Device mode %s(%d)", + hdd_device_mode_to_string( + pHostapdAdapter->device_mode), + pHostapdAdapter->device_mode); + return -ENOTSUPP; + } + + if (wrqu->data.length >= MAC_ADDRESS_STR_LEN - 1) { + if (copy_from_user((void *)pmacAddress, + wrqu->data.pointer, MAC_ADDRESS_STR_LEN)) { + hdd_notice("failed to copy data to user buffer"); + return -EFAULT; + } + pmacAddress[MAC_ADDRESS_STR_LEN - 1] = '\0'; + + if (!mac_pton(pmacAddress, macAddress.bytes)) { + hdd_err("String to Hex conversion Failed"); + return -EINVAL; + } + } + /* If no mac address is passed and/or its length is less than 17, + * link speed for first connected client will be returned. + */ + if (wrqu->data.length < 17 || !QDF_IS_STATUS_SUCCESS(status)) { + for (i = 0; i < WLAN_MAX_STA_COUNT; i++) { + if (pHostapdAdapter->aStaInfo[i].isUsed && + (!qdf_is_macaddr_broadcast + (&pHostapdAdapter->aStaInfo[i].macAddrSTA))) { + qdf_copy_macaddr( + &macAddress, + &pHostapdAdapter->aStaInfo[i]. + macAddrSTA); + status = QDF_STATUS_SUCCESS; + break; + } + } + } + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("Invalid peer macaddress"); + return -EINVAL; + } + errno = wlan_hdd_get_linkspeed_for_peermac(pHostapdAdapter, + macAddress); + if (errno) { + hdd_err("Unable to retrieve SME linkspeed: %d", errno); + return errno; + } + + link_speed = pHostapdAdapter->ls_stats.estLinkSpeed; + + /* linkspeed in units of 500 kbps */ + link_speed = link_speed / 500; + wrqu->data.length = len; + rc = snprintf(pLinkSpeed, len, "%u", link_speed); + if ((rc < 0) || (rc >= len)) { + /* encoding or length error? */ + hdd_err("Unable to encode link speed"); + return -EIO; + } + EXIT(); + return 0; +} + +static int +iw_get_softap_linkspeed(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_get_softap_linkspeed(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +static const iw_handler hostapd_handler[] = { + (iw_handler) NULL, /* SIOCSIWCOMMIT */ + (iw_handler) NULL, /* SIOCGIWNAME */ + (iw_handler) NULL, /* SIOCSIWNWID */ + (iw_handler) NULL, /* SIOCGIWNWID */ + (iw_handler) NULL, /* SIOCSIWFREQ */ + (iw_handler) iw_get_ap_freq, /* SIOCGIWFREQ */ + (iw_handler) NULL, /* SIOCSIWMODE */ + (iw_handler) iw_get_mode, /* SIOCGIWMODE */ + (iw_handler) NULL, /* SIOCSIWSENS */ + (iw_handler) NULL, /* SIOCGIWSENS */ + (iw_handler) NULL, /* SIOCSIWRANGE */ + (iw_handler) NULL, /* SIOCGIWRANGE */ + (iw_handler) NULL, /* SIOCSIWPRIV */ + (iw_handler) NULL, /* SIOCGIWPRIV */ + (iw_handler) NULL, /* SIOCSIWSTATS */ + (iw_handler) NULL, /* SIOCGIWSTATS */ + (iw_handler) NULL, /* SIOCSIWSPY */ + (iw_handler) NULL, /* SIOCGIWSPY */ + (iw_handler) NULL, /* SIOCSIWTHRSPY */ + (iw_handler) NULL, /* SIOCGIWTHRSPY */ + (iw_handler) NULL, /* SIOCSIWAP */ + (iw_handler) NULL, /* SIOCGIWAP */ + (iw_handler) iw_set_ap_mlme, /* SIOCSIWMLME */ + (iw_handler) NULL, /* SIOCGIWAPLIST */ + (iw_handler) NULL, /* SIOCSIWSCAN */ + (iw_handler) NULL, /* SIOCGIWSCAN */ + (iw_handler) NULL, /* SIOCSIWESSID */ + (iw_handler) NULL, /* SIOCGIWESSID */ + (iw_handler) NULL, /* SIOCSIWNICKN */ + (iw_handler) NULL, /* SIOCGIWNICKN */ + (iw_handler) NULL, /* -- hole -- */ + (iw_handler) NULL, /* -- hole -- */ + (iw_handler) NULL, /* SIOCSIWRATE */ + (iw_handler) NULL, /* SIOCGIWRATE */ + (iw_handler) NULL, /* SIOCSIWRTS */ + (iw_handler) iw_get_ap_rts_threshold, /* SIOCGIWRTS */ + (iw_handler) NULL, /* SIOCSIWFRAG */ + (iw_handler) iw_get_ap_frag_threshold, /* SIOCGIWFRAG */ + (iw_handler) NULL, /* SIOCSIWTXPOW */ + (iw_handler) NULL, /* SIOCGIWTXPOW */ + (iw_handler) NULL, /* SIOCSIWRETRY */ + (iw_handler) NULL, /* SIOCGIWRETRY */ + (iw_handler) NULL, /* SIOCSIWENCODE */ + (iw_handler) NULL, /* SIOCGIWENCODE */ + (iw_handler) NULL, /* SIOCSIWPOWER */ + (iw_handler) NULL, /* SIOCGIWPOWER */ + (iw_handler) NULL, /* -- hole -- */ + (iw_handler) NULL, /* -- hole -- */ + (iw_handler) iw_set_ap_genie, /* SIOCSIWGENIE */ + (iw_handler) NULL, /* SIOCGIWGENIE */ + (iw_handler) iw_set_auth_hostap, /* SIOCSIWAUTH */ + (iw_handler) NULL, /* SIOCGIWAUTH */ + (iw_handler) iw_set_ap_encodeext, /* SIOCSIWENCODEEXT */ + (iw_handler) NULL, /* SIOCGIWENCODEEXT */ + (iw_handler) NULL, /* SIOCSIWPMKSA */ +}; + +/* + * Note that the following ioctls were defined with semantics which + * cannot be handled by the "iwpriv" userspace application and hence + * they are not included in the hostapd_private_args array + * QCSAP_IOCTL_ASSOC_STA_MACADDR + */ + +static const struct iw_priv_args hostapd_private_args[] = { + { + QCSAP_IOCTL_SETPARAM, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, "setparam" + }, { + QCSAP_IOCTL_SETPARAM, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "" + }, { + QCSAP_PARAM_MAX_ASSOC, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, + "setMaxAssoc" + }, { + QCSAP_PARAM_HIDE_SSID, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "hideSSID" + }, { + QCSAP_PARAM_SET_MC_RATE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "setMcRate" + }, + { + QCSAP_PARAM_SET_TXRX_FW_STATS, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, + "txrx_fw_stats" + }, { + QCSAP_PARAM_SET_MCC_CHANNEL_LATENCY, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, + "setMccLatency" + }, { + QCSAP_PARAM_SET_MCC_CHANNEL_QUOTA, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, + "setMccQuota" + }, { + QCSAP_PARAM_SET_CHANNEL_CHANGE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, + "setChanChange" + }, { + QCSAP_PARAM_AUTO_CHANNEL, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, + "setAutoChannel" + }, { + QCSAP_PARAM_CONC_SYSTEM_PREF, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, + "setConcSysPref" + }, + /* Sub-cmds DBGLOG specific commands */ + { + QCSAP_DBGLOG_LOG_LEVEL, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "dl_loglevel" + }, { + QCSAP_DBGLOG_VAP_ENABLE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "dl_vapon" + }, { + QCSAP_DBGLOG_VAP_DISABLE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "dl_vapoff" + }, { + QCSAP_DBGLOG_MODULE_ENABLE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "dl_modon" + }, { + QCSAP_DBGLOG_MODULE_DISABLE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "dl_modoff" + }, { + QCSAP_DBGLOG_MOD_LOG_LEVEL, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "dl_mod_loglevel" + }, { + QCSAP_DBGLOG_TYPE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "dl_type" + }, { + QCSAP_DBGLOG_REPORT_ENABLE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "dl_report" + }, { + QCASAP_TXRX_FWSTATS_RESET, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "txrx_fw_st_rst" + }, { + QCSAP_PARAM_RTSCTS, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "enablertscts" + }, { + QCASAP_SET_11N_RATE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "set11NRates" + }, { + QCASAP_SET_VHT_RATE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "set11ACRates" + }, { + QCASAP_SHORT_GI, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "enable_short_gi" + }, { + QCSAP_SET_AMPDU, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "ampdu" + }, { + QCSAP_SET_AMSDU, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "amsdu" + }, { + QCSAP_GTX_HT_MCS, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "gtxHTMcs" + }, { + QCSAP_GTX_VHT_MCS, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "gtxVHTMcs" + }, { + QCSAP_GTX_USRCFG, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "gtxUsrCfg" + }, { + QCSAP_GTX_THRE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "gtxThre" + }, { + QCSAP_GTX_MARGIN, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "gtxMargin" + }, { + QCSAP_GTX_STEP, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "gtxStep" + }, { + QCSAP_GTX_MINTPC, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "gtxMinTpc" + }, { + QCSAP_GTX_BWMASK, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "gtxBWMask" + }, { + QCSAP_PARAM_CLR_ACL, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "setClearAcl" + }, { + QCSAP_PARAM_ACL_MODE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "setAclMode" + }, + { + QCASAP_SET_TM_LEVEL, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "setTmLevel" + }, { + QCASAP_SET_DFS_IGNORE_CAC, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "setDfsIgnoreCAC" + }, { + QCASAP_SET_DFS_NOL, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "setdfsnol" + }, { + QCASAP_SET_DFS_TARGET_CHNL, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "setNextChnl" + }, { + QCASAP_SET_RADAR_CMD, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "setRadar" + }, + { + QCSAP_IPA_UC_STAT, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "ipaucstat" + }, + { + QCASAP_TX_CHAINMASK_CMD, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "set_txchainmask" + }, { + QCASAP_RX_CHAINMASK_CMD, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "set_rxchainmask" + }, { + QCASAP_NSS_CMD, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "set_nss" + }, { + QCASAP_SET_PHYMODE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "setphymode" + }, { + QCASAP_DUMP_STATS, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "dumpStats" + }, { + QCASAP_CLEAR_STATS, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "clearStats" + }, { + QCSAP_START_FW_PROFILING, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "startProfile" + }, { + QCASAP_PARAM_LDPC, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "set_ldpc" + }, { + QCASAP_PARAM_TX_STBC, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "set_tx_stbc" + }, { + QCASAP_PARAM_RX_STBC, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "set_rx_stbc" + }, { + QCSAP_IOCTL_GETPARAM, 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getparam" + }, { + QCSAP_IOCTL_GETPARAM, 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "" + }, { + QCSAP_PARAM_MAX_ASSOC, 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getMaxAssoc" + }, { + QCSAP_PARAM_GET_WLAN_DBG, 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getwlandbg" + }, { + QCSAP_PARAM_AUTO_CHANNEL, 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getAutoChannel" + }, { + QCSAP_GTX_BWMASK, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_gtxBWMask" + }, { + QCSAP_GTX_MINTPC, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_gtxMinTpc" + }, { + QCSAP_GTX_STEP, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_gtxStep" + }, { + QCSAP_GTX_MARGIN, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_gtxMargin" + }, { + QCSAP_GTX_THRE, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_gtxThre" + }, { + QCSAP_GTX_USRCFG, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_gtxUsrCfg" + }, { + QCSAP_GTX_VHT_MCS, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_gtxVHTMcs" + }, { + QCSAP_GTX_HT_MCS, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_gtxHTMcs" + }, { + QCASAP_SHORT_GI, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_short_gi" + }, { + QCSAP_PARAM_RTSCTS, 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_rtscts" + }, { + QCASAP_GET_DFS_NOL, 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getdfsnol" + }, { + QCSAP_GET_ACL, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_acl_list" + }, { + QCASAP_PARAM_LDPC, 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_ldpc" + }, { + QCASAP_PARAM_TX_STBC, 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_tx_stbc" + }, { + QCASAP_PARAM_RX_STBC, 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_rx_stbc" + }, { + QCSAP_PARAM_CHAN_WIDTH, 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_chwidth" + }, { + QCASAP_TX_CHAINMASK_CMD, 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_txchainmask" + }, { + QCASAP_RX_CHAINMASK_CMD, 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_rxchainmask" + }, { + QCASAP_NSS_CMD, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_nss" + }, { + QCSAP_CAP_TSF, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "cap_tsf" + }, { + QCSAP_IOCTL_SET_NONE_GET_THREE, 0, IW_PRIV_TYPE_INT | + IW_PRIV_SIZE_FIXED | 3, "" + }, { + QCSAP_GET_TSF, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 3, + "get_tsf" + }, { + QCASAP_GET_TEMP_CMD, 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_temp" + }, { + QCSAP_GET_FW_PROFILE_DATA, 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getProfileData" + }, { + QCSAP_IOCTL_GET_STAWPAIE, + 0, IW_PRIV_TYPE_BYTE | DOT11F_IE_RSN_MAX_LEN, + "get_staWPAIE" + }, { + QCSAP_IOCTL_STOPBSS, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED, 0, + "stopbss" + }, { + QCSAP_IOCTL_VERSION, 0, IW_PRIV_TYPE_CHAR | WE_MAX_STR_LEN, + "version" + }, { + QCSAP_IOCTL_GET_STA_INFO, 0, + IW_PRIV_TYPE_CHAR | WE_SAP_MAX_STA_INFO, "get_sta_info" + }, { + QCSAP_IOCTL_GET_WPS_PBC_PROBE_REQ_IES, + IW_PRIV_TYPE_BYTE | + sizeof(sQcSapreq_WPSPBCProbeReqIES_t) | + IW_PRIV_SIZE_FIXED, 0, "getProbeReqIEs" + } + , { + QCSAP_IOCTL_GET_CHANNEL, 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getchannel" + } + , { + QCSAP_IOCTL_DISASSOC_STA, + IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 6, 0, + "disassoc_sta" + } + /* handler for main ioctl */ + , { + QCSAP_PRIV_GET_CHAR_SET_NONE, 0, + IW_PRIV_TYPE_CHAR | WE_MAX_STR_LEN, "" + } + /* handler for sub-ioctl */ + , { + QCSAP_GET_STATS, 0, + IW_PRIV_TYPE_CHAR | WE_MAX_STR_LEN, "getStats" + } + , { + QCSAP_LIST_FW_PROFILE, 0, + IW_PRIV_TYPE_CHAR | WE_MAX_STR_LEN, "listProfile" + } + , { + QCSAP_IOCTL_PRIV_GET_SOFTAP_LINK_SPEED, + IW_PRIV_TYPE_CHAR | 18, + IW_PRIV_TYPE_CHAR | 5, "getLinkSpeed" + } + , { + QCSAP_IOCTL_PRIV_SET_THREE_INT_GET_NONE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 3, 0, "" + } + , + /* handlers for sub-ioctl */ + { + WE_SET_WLAN_DBG, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 3, 0, "setwlandbg" + }, { + WE_SET_SAP_CHANNELS, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 3, 0, "setsapchannels" + } + , + /* handlers for sub-ioctl */ + { + WE_SET_DP_TRACE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 3, 0, "set_dp_trace" + } + , + /* handlers for main ioctl */ + { + QCSAP_IOCTL_PRIV_SET_VAR_INT_GET_NONE, + IW_PRIV_TYPE_INT | MAX_VAR_ARGS, 0, "" + } + , { + WE_P2P_NOA_CMD, IW_PRIV_TYPE_INT | MAX_VAR_ARGS, 0, "SetP2pPs" + } + , { + WE_UNIT_TEST_CMD, IW_PRIV_TYPE_INT | MAX_VAR_ARGS, 0, + "setUnitTestCmd" + } + , + /* handlers for main ioctl */ + { + QCSAP_IOCTL_MODIFY_ACL, + IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 8, 0, "modify_acl" + } + , + /* handlers for main ioctl */ + { + QCSAP_IOCTL_GET_CHANNEL_LIST, + 0, + IW_PRIV_TYPE_BYTE | sizeof(tChannelListInfo), + "getChannelList" + } + , + /* handlers for main ioctl */ + { + QCSAP_IOCTL_SET_TX_POWER, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "setTxPower" + } + , + /* handlers for main ioctl */ + { + QCSAP_IOCTL_SET_MAX_TX_POWER, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "setTxMaxPower" + } + , + { + QCSAP_IOCTL_SET_PKTLOG, + IW_PRIV_TYPE_INT | MAX_VAR_ARGS, + 0, "pktlog" + } + , + /* Set HDD CFG Ini param */ + { + QCSAP_IOCTL_SET_INI_CFG, + IW_PRIV_TYPE_CHAR | QCSAP_IOCTL_MAX_STR_LEN, 0, "setConfig" + } + , + /* Get HDD CFG Ini param */ + { + QCSAP_IOCTL_GET_INI_CFG, + 0, IW_PRIV_TYPE_CHAR | QCSAP_IOCTL_MAX_STR_LEN, "getConfig" + } + , + /* handlers for main ioctl */ + { + /* handlers for main ioctl */ + QCSAP_IOCTL_SET_TWO_INT_GET_NONE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, "" + } + , + /* handlers for sub-ioctl */ +#ifdef WLAN_DEBUG + { + QCSAP_IOCTL_SET_FW_CRASH_INJECT, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, + 0, "crash_inject" + } + , +#endif + { + QCASAP_SET_RADAR_DBG, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "setRadarDbg" + } + , + /* dump dp trace - descriptor or dp trace records */ + { + QCSAP_IOCTL_DUMP_DP_TRACE_LEVEL, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, + 0, "dump_dp_trace" + } + , + { + QCSAP_ENABLE_FW_PROFILE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, + 0, "enableProfile" + } + , + { + QCSAP_SET_FW_PROFILE_HIST_INTVL, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, + 0, "set_hist_intvl" + } +}; + +static const iw_handler hostapd_private[] = { + /* set priv ioctl */ + [QCSAP_IOCTL_SETPARAM - SIOCIWFIRSTPRIV] = iw_softap_setparam, + /* get priv ioctl */ + [QCSAP_IOCTL_GETPARAM - SIOCIWFIRSTPRIV] = iw_softap_getparam, + [QCSAP_IOCTL_SET_NONE_GET_THREE - SIOCIWFIRSTPRIV] = + iw_softap_get_three, + /* get station genIE */ + [QCSAP_IOCTL_GET_STAWPAIE - SIOCIWFIRSTPRIV] = iw_get_genie, + /* stop bss */ + [QCSAP_IOCTL_STOPBSS - SIOCIWFIRSTPRIV] = iw_softap_stopbss, + /* get driver version */ + [QCSAP_IOCTL_VERSION - SIOCIWFIRSTPRIV] = iw_softap_version, + [QCSAP_IOCTL_GET_WPS_PBC_PROBE_REQ_IES - SIOCIWFIRSTPRIV] = + iw_get_wpspbc_probe_req_ies, + [QCSAP_IOCTL_GET_CHANNEL - SIOCIWFIRSTPRIV] = + iw_softap_getchannel, + [QCSAP_IOCTL_ASSOC_STA_MACADDR - SIOCIWFIRSTPRIV] = + iw_softap_getassoc_stamacaddr, + [QCSAP_IOCTL_DISASSOC_STA - SIOCIWFIRSTPRIV] = + iw_softap_disassoc_sta, + [QCSAP_PRIV_GET_CHAR_SET_NONE - SIOCIWFIRSTPRIV] = + iw_get_char_setnone, + [QCSAP_IOCTL_PRIV_SET_THREE_INT_GET_NONE - + SIOCIWFIRSTPRIV] = + iw_set_three_ints_getnone, + [QCSAP_IOCTL_PRIV_SET_VAR_INT_GET_NONE - + SIOCIWFIRSTPRIV] = + iw_set_var_ints_getnone, + [QCSAP_IOCTL_SET_CHANNEL_RANGE - SIOCIWFIRSTPRIV] = + iw_softap_set_force_acs_ch_range, + [QCSAP_IOCTL_MODIFY_ACL - SIOCIWFIRSTPRIV] = + iw_softap_modify_acl, + [QCSAP_IOCTL_GET_CHANNEL_LIST - SIOCIWFIRSTPRIV] = + iw_get_channel_list, + [QCSAP_IOCTL_GET_STA_INFO - SIOCIWFIRSTPRIV] = + iw_softap_get_sta_info, + [QCSAP_IOCTL_PRIV_GET_SOFTAP_LINK_SPEED - + SIOCIWFIRSTPRIV] = + iw_get_softap_linkspeed, + [QCSAP_IOCTL_SET_TX_POWER - SIOCIWFIRSTPRIV] = + iw_softap_set_tx_power, + [QCSAP_IOCTL_SET_MAX_TX_POWER - SIOCIWFIRSTPRIV] = + iw_softap_set_max_tx_power, + [QCSAP_IOCTL_SET_PKTLOG - SIOCIWFIRSTPRIV] = + iw_softap_set_pktlog, + [QCSAP_IOCTL_SET_INI_CFG - SIOCIWFIRSTPRIV] = + iw_softap_set_ini_cfg, + [QCSAP_IOCTL_GET_INI_CFG - SIOCIWFIRSTPRIV] = + iw_softap_get_ini_cfg, + [QCSAP_IOCTL_SET_TWO_INT_GET_NONE - SIOCIWFIRSTPRIV] = + iw_softap_set_two_ints_getnone, +}; +const struct iw_handler_def hostapd_handler_def = { + .num_standard = QDF_ARRAY_SIZE(hostapd_handler), + .num_private = QDF_ARRAY_SIZE(hostapd_private), + .num_private_args = QDF_ARRAY_SIZE(hostapd_private_args), + .standard = (iw_handler *) hostapd_handler, + .private = (iw_handler *) hostapd_private, + .private_args = hostapd_private_args, + .get_wireless_stats = NULL, +}; + +struct net_device_ops net_ops_struct = { + .ndo_open = hdd_hostapd_open, + .ndo_stop = hdd_hostapd_stop, + .ndo_uninit = hdd_hostapd_uninit, + .ndo_start_xmit = hdd_softap_hard_start_xmit, + .ndo_tx_timeout = hdd_softap_tx_timeout, + .ndo_get_stats = hdd_get_stats, + .ndo_set_mac_address = hdd_hostapd_set_mac_address, + .ndo_do_ioctl = hdd_ioctl, + .ndo_change_mtu = hdd_hostapd_change_mtu, + .ndo_select_queue = hdd_hostapd_select_queue, +}; + +static int hdd_set_hostapd(hdd_adapter_t *pAdapter) +{ + return QDF_STATUS_SUCCESS; +} + +void hdd_set_ap_ops(struct net_device *pWlanHostapdDev) +{ + pWlanHostapdDev->netdev_ops = &net_ops_struct; +} + +QDF_STATUS hdd_init_ap_mode(hdd_adapter_t *pAdapter, bool reinit) +{ + hdd_hostapd_state_t *phostapdBuf; + struct net_device *dev = pAdapter->dev; + hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + QDF_STATUS status; + QDF_STATUS qdf_status; + v_CONTEXT_t p_cds_context = (WLAN_HDD_GET_CTX(pAdapter))->pcds_context; + v_CONTEXT_t sapContext = NULL; + int ret; + enum tQDF_ADAPTER_MODE mode; + uint32_t session_id = CSR_SESSION_ID_INVALID; + enum dfs_mode acs_dfs_mode; + + ENTER(); + + hdd_info("SSR in progress: %d", reinit); + + if (reinit) + sapContext = pAdapter->sessionCtx.ap.sapContext; + else { + sapContext = wlansap_open(p_cds_context); + if (sapContext == NULL) { + hdd_err("ERROR: wlansap_open failed!!"); + return QDF_STATUS_E_FAULT; + } + + pAdapter->sessionCtx.ap.sapContext = sapContext; + pAdapter->sessionCtx.ap.sapConfig.channel = + pHddCtx->acs_policy.acs_channel; + acs_dfs_mode = pHddCtx->acs_policy.acs_dfs_mode; + pAdapter->sessionCtx.ap.sapConfig.acs_dfs_mode = + wlan_hdd_get_dfs_mode(acs_dfs_mode); + } + + if (pAdapter->device_mode == QDF_P2P_GO_MODE) { + mode = QDF_P2P_GO_MODE; + } else if (pAdapter->device_mode == QDF_SAP_MODE) { + mode = QDF_SAP_MODE; + } else { + hdd_err("Invalid mode for AP: %d", pAdapter->device_mode); + return QDF_STATUS_E_FAULT; + } + + status = wlansap_start(sapContext, hdd_hostapd_sap_event_cb, mode, + pAdapter->macAddressCurrent.bytes, + &session_id, pAdapter->dev); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("ERROR: wlansap_start failed!!"); + wlansap_close(sapContext); + pAdapter->sessionCtx.ap.sapContext = NULL; + return status; + } + pAdapter->sessionId = session_id; + set_bit(SME_SESSION_OPENED, &pAdapter->event_flags); + + /* Allocate the Wireless Extensions state structure */ + phostapdBuf = WLAN_HDD_GET_HOSTAP_STATE_PTR(pAdapter); + + sme_set_curr_device_mode(pHddCtx->hHal, pAdapter->device_mode); + + /* Zero the memory. This zeros the profile structure. */ + memset(phostapdBuf, 0, sizeof(hdd_hostapd_state_t)); + + /* Set up the pointer to the Wireless Extensions state structure */ + /* NOP */ + status = hdd_set_hostapd(pAdapter); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("ERROR: hdd_set_hostapd failed!!"); + wlansap_close(sapContext); + pAdapter->sessionCtx.ap.sapContext = NULL; + return status; + } + + qdf_status = qdf_event_create(&phostapdBuf->qdf_event); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + hdd_err("ERROR: Hostapd HDD qdf event init failed!!"); + wlansap_close(sapContext); + pAdapter->sessionCtx.ap.sapContext = NULL; + return qdf_status; + } + + qdf_status = qdf_event_create(&phostapdBuf->qdf_stop_bss_event); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + hdd_err("ERROR: Hostapd HDD stop bss event init failed!!"); + wlansap_close(sapContext); + pAdapter->sessionCtx.ap.sapContext = NULL; + return qdf_status; + } + + qdf_status = qdf_event_create(&phostapdBuf->qdf_sta_disassoc_event); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + hdd_err("ERROR: Hostapd HDD sta disassoc event init failed!!"); + wlansap_close(sapContext); + pAdapter->sessionCtx.ap.sapContext = NULL; + return qdf_status; + } + + init_completion(&pAdapter->session_close_comp_var); + init_completion(&pAdapter->session_open_comp_var); + + sema_init(&(WLAN_HDD_GET_AP_CTX_PTR(pAdapter))->semWpsPBCOverlapInd, 1); + + /* Register as a wireless device */ + dev->wireless_handlers = (struct iw_handler_def *)&hostapd_handler_def; + + /* Initialize the data path module */ + status = hdd_softap_init_tx_rx(pAdapter); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_alert("hdd_softap_init_tx_rx failed"); + } + + status = hdd_wmm_adapter_init(pAdapter); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("hdd_wmm_adapter_init() failed code %08d [x%08x]", + status, status); + goto error_wmm_init; + } + + set_bit(WMM_INIT_DONE, &pAdapter->event_flags); + + ret = wma_cli_set_command(pAdapter->sessionId, + WMI_PDEV_PARAM_BURST_ENABLE, + pHddCtx->config->enableSifsBurst, + PDEV_CMD); + + if (0 != ret) { + hdd_err("WMI_PDEV_PARAM_BURST_ENABLE set failed %d", ret); + } + + if (!reinit) { + pAdapter->sessionCtx.ap.sapConfig.acs_cfg.acs_mode = false; + qdf_mem_free(pAdapter->sessionCtx.ap.sapConfig.acs_cfg.ch_list); + qdf_mem_zero(&pAdapter->sessionCtx.ap.sapConfig.acs_cfg, + sizeof(struct sap_acs_cfg)); + } + + /* rcpi info initialization */ + qdf_mem_zero(&pAdapter->rcpi, sizeof(pAdapter->rcpi)); + + return status; + +error_wmm_init: + hdd_softap_deinit_tx_rx(pAdapter); + wlansap_close(sapContext); + pAdapter->sessionCtx.ap.sapContext = NULL; + EXIT(); + return status; +} + +/** + * hdd_wlan_create_ap_dev() - create an AP-mode device + * @pHddCtx: Global HDD context + * @macAddr: MAC address to assign to the interface + * @name_assign_type: the name of assign type of the netdev + * @iface_name: User-visible name of the interface + * + * This function will allocate a Linux net_device and configuration it + * for an AP mode of operation. Note that the device is NOT actually + * registered with the kernel at this time. + * + * Return: A pointer to the private data portion of the net_device if + * the allocation and initialization was successful, NULL otherwise. + */ +hdd_adapter_t *hdd_wlan_create_ap_dev(hdd_context_t *pHddCtx, + tSirMacAddr macAddr, + unsigned char name_assign_type, + uint8_t *iface_name) +{ + struct net_device *pWlanHostapdDev = NULL; + hdd_adapter_t *pHostapdAdapter = NULL; + + hdd_info("iface_name = %s", iface_name); + + pWlanHostapdDev = alloc_netdev_mq(sizeof(hdd_adapter_t), iface_name, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 17, 0)) || defined(WITH_BACKPORTS) + name_assign_type, +#endif + ether_setup, NUM_TX_QUEUES); + + if (pWlanHostapdDev != NULL) { + pHostapdAdapter = netdev_priv(pWlanHostapdDev); + + /* Init the net_device structure */ + ether_setup(pWlanHostapdDev); + + /* Initialize the adapter context to zeros. */ + qdf_mem_zero(pHostapdAdapter, sizeof(hdd_adapter_t)); + pHostapdAdapter->dev = pWlanHostapdDev; + pHostapdAdapter->pHddCtx = pHddCtx; + pHostapdAdapter->magic = WLAN_HDD_ADAPTER_MAGIC; + pHostapdAdapter->sessionId = HDD_SESSION_ID_INVALID; + + hdd_info("pWlanHostapdDev = %p, pHostapdAdapter = %p, concurrency_mode=0x%x", + pWlanHostapdDev, + pHostapdAdapter, + (int)cds_get_concurrency_mode()); + + /* Init the net_device structure */ + strlcpy(pWlanHostapdDev->name, (const char *)iface_name, + IFNAMSIZ); + + hdd_set_ap_ops(pHostapdAdapter->dev); + + pWlanHostapdDev->watchdog_timeo = HDD_TX_TIMEOUT; + pWlanHostapdDev->mtu = HDD_DEFAULT_MTU; + pWlanHostapdDev->tx_queue_len = HDD_NETDEV_TX_QUEUE_LEN; + + if (pHddCtx->config->enable_ip_tcp_udp_checksum_offload) + pWlanHostapdDev->features |= + NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM; + pWlanHostapdDev->features |= NETIF_F_RXCSUM; + + qdf_mem_copy(pWlanHostapdDev->dev_addr, (void *)macAddr, + sizeof(tSirMacAddr)); + qdf_mem_copy(pHostapdAdapter->macAddressCurrent.bytes, + (void *)macAddr, sizeof(tSirMacAddr)); + + pHostapdAdapter->offloads_configured = false; + pWlanHostapdDev->destructor = free_netdev; + pWlanHostapdDev->ieee80211_ptr = &pHostapdAdapter->wdev; + pHostapdAdapter->wdev.wiphy = pHddCtx->wiphy; + pHostapdAdapter->wdev.netdev = pWlanHostapdDev; + hdd_set_tso_flags(pHddCtx, pWlanHostapdDev); + init_completion(&pHostapdAdapter->tx_action_cnf_event); + init_completion(&pHostapdAdapter->cancel_rem_on_chan_var); + init_completion(&pHostapdAdapter->rem_on_chan_ready_event); + init_completion(&pHostapdAdapter->sta_authorized_event); + init_completion(&pHostapdAdapter->offchannel_tx_event); + init_completion(&pHostapdAdapter->scan_info. + abortscan_event_var); + + SET_NETDEV_DEV(pWlanHostapdDev, pHddCtx->parent_dev); + spin_lock_init(&pHostapdAdapter->pause_map_lock); + pHostapdAdapter->start_time = + pHostapdAdapter->last_time = qdf_system_ticks(); + } + return pHostapdAdapter; +} + +/** + * hdd_register_hostapd() - register hostapd + * @pAdapter: Pointer to hostapd adapter + * @rtnl_lock_held: RTNL lock held + * + * Return: QDF status + */ +QDF_STATUS hdd_register_hostapd(hdd_adapter_t *pAdapter, + uint8_t rtnl_lock_held) { + struct net_device *dev = pAdapter->dev; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + ENTER(); + + if (rtnl_lock_held) { + if (strnchr(dev->name, strlen(dev->name), '%')) { + if (dev_alloc_name(dev, dev->name) < 0) { + hdd_err("Failed:dev_alloc_name"); + return QDF_STATUS_E_FAILURE; + } + } + if (register_netdevice(dev)) { + hdd_err("Failed:register_netdevice"); + return QDF_STATUS_E_FAILURE; + } + } else { + if (register_netdev(dev)) { + hdd_err("Failed:register_netdev"); + return QDF_STATUS_E_FAILURE; + } + } + set_bit(NET_DEVICE_REGISTERED, &pAdapter->event_flags); + + EXIT(); + return status; +} + +/** + * hdd_unregister_hostapd() - unregister hostapd + * @pAdapter: Pointer to hostapd adapter + * @rtnl_held: true if rtnl lock held; false otherwise + * + * Return: QDF_STATUS enumaration + */ +int hdd_unregister_hostapd(hdd_adapter_t *pAdapter, bool rtnl_held) +{ + QDF_STATUS status; + void *sapContext = WLAN_HDD_GET_SAP_CTX_PTR(pAdapter); + + ENTER(); + + hdd_softap_deinit_tx_rx(pAdapter); + + /* if we are being called during driver unload, + * then the dev has already been invalidated. + * if we are being called at other times, then we can + * detach the wireless device handlers + */ + if (pAdapter->dev) { + if (rtnl_held) + pAdapter->dev->wireless_handlers = NULL; + else { + rtnl_lock(); + pAdapter->dev->wireless_handlers = NULL; + rtnl_unlock(); + } + } + + if (!test_bit(DEVICE_IFACE_OPENED, &pAdapter->event_flags)) { + hdd_info("iface is not opened"); + return 0; + } + + status = wlansap_stop(sapContext); + if (!QDF_IS_STATUS_SUCCESS(status)) + hdd_err("Failed:wlansap_stop"); + + status = wlansap_close(sapContext); + if (!QDF_IS_STATUS_SUCCESS(status)) + hdd_err("Failed:WLANSAP_close"); + pAdapter->sessionCtx.ap.sapContext = NULL; + + EXIT(); + return 0; +} + +/** + * wlan_hdd_rate_is_11g() - check if rate is 11g rate or not + * @rate: Rate to be checked + * + * Return: true if rate if 11g else false + */ +static bool wlan_hdd_rate_is_11g(u8 rate) +{ + static const u8 gRateArray[8] = {12, 18, 24, 36, 48, 72, + 96, 108}; /* actual rate * 2 */ + u8 i; + for (i = 0; i < 8; i++) { + if (rate == gRateArray[i]) + return true; + } + return false; +} + +#ifdef QCA_HT_2040_COEX +/** + * wlan_hdd_get_sap_obss() - Get SAP OBSS enable config based on HT_CAPAB IE + * @pHostapdAdapter: Pointer to hostapd adapter + * + * Return: HT support channel width config value + */ +static bool wlan_hdd_get_sap_obss(hdd_adapter_t *pHostapdAdapter) +{ + uint8_t ht_cap_ie[DOT11F_IE_HTCAPS_MAX_LEN]; + tDot11fIEHTCaps dot11_ht_cap_ie = {0}; + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(pHostapdAdapter); + beacon_data_t *beacon = pHostapdAdapter->sessionCtx.ap.beacon; + uint8_t *ie = NULL; + + ie = wlan_hdd_cfg80211_get_ie_ptr(beacon->tail, beacon->tail_len, + WLAN_EID_HT_CAPABILITY); + if (ie && ie[1]) { + qdf_mem_copy(ht_cap_ie, &ie[2], DOT11F_IE_HTCAPS_MAX_LEN); + dot11f_unpack_ie_ht_caps((tpAniSirGlobal)hdd_ctx->hHal, + ht_cap_ie, ie[1], &dot11_ht_cap_ie); + return dot11_ht_cap_ie.supportedChannelWidthSet; + } + + return false; +} +#else +static bool wlan_hdd_get_sap_obss(hdd_adapter_t *pHostapdAdapter) +{ + return false; +} +#endif +/** + * wlan_hdd_set_channel() - set channel in sap mode + * @wiphy: Pointer to wiphy structure + * @dev: Pointer to net_device structure + * @chandef: Pointer to channel definition structure + * @channel_type: Channel type + * + * Return: 0 for success non-zero for failure + */ +int wlan_hdd_set_channel(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_chan_def *chandef, + enum nl80211_channel_type channel_type) +{ + hdd_adapter_t *pAdapter = NULL; + uint32_t num_ch = 0; + int channel = 0; + int channel_seg2 = 0; + hdd_context_t *pHddCtx; + int status; + + tSmeConfigParams *sme_config; + tsap_Config_t *sap_config; + + ENTER(); + + + if (NULL == dev) { + hdd_err("Called with dev = NULL."); + return -ENODEV; + } + pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + + MTRACE(qdf_trace(QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_CFG80211_SET_CHANNEL, + pAdapter->sessionId, channel_type)); + + hdd_notice("Device_mode %s(%d) freq = %d", + hdd_device_mode_to_string(pAdapter->device_mode), + pAdapter->device_mode, chandef->chan->center_freq); + + pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + status = wlan_hdd_validate_context(pHddCtx); + if (status) + return status; + + + /* + * Do freq to chan conversion + * TODO: for 11a + */ + + channel = ieee80211_frequency_to_channel(chandef->chan->center_freq); + + if (NL80211_CHAN_WIDTH_80P80 == chandef->width || + NL80211_CHAN_WIDTH_160 == chandef->width) { + if (chandef->center_freq2) + channel_seg2 = ieee80211_frequency_to_channel( + chandef->center_freq2); + else + hdd_err("Invalid center_freq2"); + } + + /* Check freq range */ + if ((WNI_CFG_CURRENT_CHANNEL_STAMIN > channel) || + (WNI_CFG_CURRENT_CHANNEL_STAMAX < channel)) { + hdd_err("Channel [%d] is outside valid range from %d to %d", + channel, WNI_CFG_CURRENT_CHANNEL_STAMIN, + WNI_CFG_CURRENT_CHANNEL_STAMAX); + return -EINVAL; + } + + /* Check freq range */ + + if ((WNI_CFG_CURRENT_CHANNEL_STAMIN > channel_seg2) || + (WNI_CFG_CURRENT_CHANNEL_STAMAX < channel_seg2)) { + hdd_err("Channel [%d] is outside valid range from %d to %d", + channel_seg2, WNI_CFG_CURRENT_CHANNEL_STAMIN, + WNI_CFG_CURRENT_CHANNEL_STAMAX); + return -EINVAL; + } + + num_ch = WNI_CFG_VALID_CHANNEL_LIST_LEN; + + if ((QDF_SAP_MODE != pAdapter->device_mode) && + (QDF_P2P_GO_MODE != pAdapter->device_mode)) { + if (QDF_STATUS_SUCCESS != + wlan_hdd_validate_operation_channel(pAdapter, channel)) { + hdd_err("Invalid Channel [%d]", channel); + return -EINVAL; + } + hdd_info("set channel to [%d] for device mode %s(%d)", + channel, + hdd_device_mode_to_string(pAdapter->device_mode), + pAdapter->device_mode); + } + + if ((pAdapter->device_mode == QDF_STA_MODE) + || (pAdapter->device_mode == QDF_P2P_CLIENT_MODE) + ) { + hdd_wext_state_t *pWextState = + WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter); + tCsrRoamProfile *pRoamProfile = &pWextState->roamProfile; + hdd_station_ctx_t *pHddStaCtx = + WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + + if (eConnectionState_IbssConnected == + pHddStaCtx->conn_info.connState) { + /* Link is up then return cant set channel */ + hdd_err("IBSS Associated, can't set the channel"); + return -EINVAL; + } + + num_ch = pRoamProfile->ChannelInfo.numOfChannels = 1; + pHddStaCtx->conn_info.operationChannel = channel; + pRoamProfile->ChannelInfo.ChannelList = + &pHddStaCtx->conn_info.operationChannel; + } else if ((pAdapter->device_mode == QDF_SAP_MODE) + || (pAdapter->device_mode == QDF_P2P_GO_MODE) + ) { + sap_config = &((WLAN_HDD_GET_AP_CTX_PTR(pAdapter))->sapConfig); + if (QDF_P2P_GO_MODE == pAdapter->device_mode) { + if (QDF_STATUS_SUCCESS != + wlan_hdd_validate_operation_channel(pAdapter, + channel)) { + hdd_err("Invalid Channel [%d]", channel); + return -EINVAL; + } + sap_config->channel = channel; + sap_config->ch_params.center_freq_seg1 = channel_seg2; + } else { + /* set channel to what hostapd configured */ + if (QDF_STATUS_SUCCESS != + wlan_hdd_validate_operation_channel(pAdapter, + channel)) { + hdd_err("Invalid Channel [%d]", channel); + return -EINVAL; + } + + sap_config->channel = channel; + sap_config->ch_params.center_freq_seg1 = channel_seg2; + + sme_config = qdf_mem_malloc(sizeof(*sme_config)); + + if (!sme_config) { + hdd_err("Unable to allocate memory for smeconfig!"); + return -ENOMEM; + } + sme_get_config_param(pHddCtx->hHal, sme_config); + switch (channel_type) { + case NL80211_CHAN_HT20: + case NL80211_CHAN_NO_HT: + sme_config->csrConfig.obssEnabled = false; + sap_config->sec_ch = 0; + break; + case NL80211_CHAN_HT40MINUS: + sap_config->sec_ch = sap_config->channel - 4; + break; + case NL80211_CHAN_HT40PLUS: + sap_config->sec_ch = sap_config->channel + 4; + break; + default: + hdd_err("Error!!! Invalid HT20/40 mode !"); + qdf_mem_free(sme_config); + return -EINVAL; + } + sme_config->csrConfig.obssEnabled = + wlan_hdd_get_sap_obss(pAdapter); + + sme_update_config(pHddCtx->hHal, sme_config); + qdf_mem_free(sme_config); + } + } else { + hdd_err("Invalid device mode failed to set valid channel"); + return -EINVAL; + } + EXIT(); + return status; +} + +/** + * wlan_hdd_check_11gmode() - check for 11g mode + * @pIe: Pointer to IE + * @require_ht: Pointer to require ht + * @require_vht: Pointer to require vht + * @pCheckRatesfor11g: Pointer to check rates for 11g mode + * @pSapHw_mode: SAP HW mode + * + * Check for 11g rate and set proper 11g only mode + * + * Return: none + */ +static void wlan_hdd_check_11gmode(u8 *pIe, u8 *require_ht, u8 *require_vht, + u8 *pCheckRatesfor11g, + eCsrPhyMode *pSapHw_mode) +{ + u8 i, num_rates = pIe[0]; + + pIe += 1; + for (i = 0; i < num_rates; i++) { + if (*pCheckRatesfor11g + && (true == wlan_hdd_rate_is_11g(pIe[i] & RATE_MASK))) { + /* If rate set have 11g rate than change the mode + * to 11G + */ + *pSapHw_mode = eCSR_DOT11_MODE_11g; + if (pIe[i] & BASIC_RATE_MASK) { + /* If we have 11g rate as basic rate, it + * means mode is 11g only mode. + */ + *pSapHw_mode = eCSR_DOT11_MODE_11g_ONLY; + *pCheckRatesfor11g = false; + } + } else { + if ((BASIC_RATE_MASK | + WLAN_BSS_MEMBERSHIP_SELECTOR_HT_PHY) == pIe[i]) + *require_ht = true; + else if ((BASIC_RATE_MASK | + WLAN_BSS_MEMBERSHIP_SELECTOR_VHT_PHY) == pIe[i]) + *require_vht = true; + } + } + return; +} + +/** + * wlan_hdd_add_ie() - add ie + * @pHostapdAdapter: Pointer to hostapd adapter + * @genie: Pointer to ie to be added + * @total_ielen: Pointer to store total ie length + * @oui: Pointer to oui + * @oui_size: Size of oui + * + * Return: 0 for success non-zero for failure + */ +static int wlan_hdd_add_ie(hdd_adapter_t *pHostapdAdapter, uint8_t *genie, + uint16_t *total_ielen, uint8_t *oui, + uint8_t oui_size) +{ + uint16_t ielen = 0; + uint8_t *pIe = NULL; + beacon_data_t *pBeacon = pHostapdAdapter->sessionCtx.ap.beacon; + + pIe = wlan_hdd_get_vendor_oui_ie_ptr(oui, oui_size, + pBeacon->tail, pBeacon->tail_len); + + if (pIe) { + ielen = pIe[1] + 2; + if ((*total_ielen + ielen) <= MAX_GENIE_LEN) { + qdf_mem_copy(&genie[*total_ielen], pIe, ielen); + } else { + hdd_err("**Ie Length is too big***"); + return -EINVAL; + } + *total_ielen += ielen; + } + return 0; +} + +/** + * wlan_hdd_add_hostapd_conf_vsie() - configure vsie in sap mode + * @pHostapdAdapter: Pointer to hostapd adapter + * @genie: Pointer to vsie + * @total_ielen: Pointer to store total ie length + * + * Return: none + */ +static void wlan_hdd_add_hostapd_conf_vsie(hdd_adapter_t *pHostapdAdapter, + uint8_t *genie, + uint16_t *total_ielen) +{ + beacon_data_t *pBeacon = pHostapdAdapter->sessionCtx.ap.beacon; + int left = pBeacon->tail_len; + uint8_t *ptr = pBeacon->tail; + uint8_t elem_id, elem_len; + uint16_t ielen = 0; + + if (NULL == ptr || 0 == left) + return; + + while (left >= 2) { + elem_id = ptr[0]; + elem_len = ptr[1]; + left -= 2; + if (elem_len > left || elem_len < WPS_OUI_TYPE_SIZE) { + hdd_err("****Invalid IEs eid = %d elem_len=%d left=%d*****", + elem_id, elem_len, left); + return; + } + if (IE_EID_VENDOR == elem_id) { + /* skipping the VSIE's which we don't want to include or + * it will be included by existing code + */ + if ((memcmp(&ptr[2], WPS_OUI_TYPE, WPS_OUI_TYPE_SIZE) != + 0) && +#ifdef WLAN_FEATURE_WFD + (memcmp(&ptr[2], WFD_OUI_TYPE, WFD_OUI_TYPE_SIZE) != + 0) && +#endif + (memcmp + (&ptr[2], WHITELIST_OUI_TYPE, + WPA_OUI_TYPE_SIZE) != 0) + && + (memcmp + (&ptr[2], BLACKLIST_OUI_TYPE, + WPA_OUI_TYPE_SIZE) != 0) + && + (memcmp + (&ptr[2], "\x00\x50\xf2\x02", + WPA_OUI_TYPE_SIZE) != 0) + && (memcmp(&ptr[2], WPA_OUI_TYPE, WPA_OUI_TYPE_SIZE) + != 0) + && (memcmp(&ptr[2], P2P_OUI_TYPE, P2P_OUI_TYPE_SIZE) + != 0)) { + ielen = ptr[1] + 2; + if ((*total_ielen + ielen) <= MAX_GENIE_LEN) { + qdf_mem_copy(&genie[*total_ielen], ptr, + ielen); + *total_ielen += ielen; + } else { + hdd_err("IE Length is too big IEs eid=%d elem_len=%d total_ie_lent=%d", + elem_id, elem_len, *total_ielen); + } + } + } + + left -= elem_len; + ptr += (elem_len + 2); + } + return; +} + +/** + * wlan_hdd_add_extra_ie() - add extra ies in beacon + * @pHostapdAdapter: Pointer to hostapd adapter + * @genie: Pointer to extra ie + * @total_ielen: Pointer to store total ie length + * @temp_ie_id: ID of extra ie + * + * Return: none + */ +static void wlan_hdd_add_extra_ie(hdd_adapter_t *pHostapdAdapter, + uint8_t *genie, uint16_t *total_ielen, + uint8_t temp_ie_id) +{ + beacon_data_t *pBeacon = pHostapdAdapter->sessionCtx.ap.beacon; + int left = pBeacon->tail_len; + uint8_t *ptr = pBeacon->tail; + uint8_t elem_id, elem_len; + uint16_t ielen = 0; + + if (NULL == ptr || 0 == left) + return; + + while (left >= 2) { + elem_id = ptr[0]; + elem_len = ptr[1]; + left -= 2; + if (elem_len > left) { + hdd_err("****Invalid IEs eid = %d elem_len=%d left=%d*****", + elem_id, elem_len, left); + return; + } + + if (temp_ie_id == elem_id) { + ielen = ptr[1] + 2; + if ((*total_ielen + ielen) <= MAX_GENIE_LEN) { + qdf_mem_copy(&genie[*total_ielen], ptr, ielen); + *total_ielen += ielen; + } else { + hdd_err("IE Length is too big IEs eid=%d elem_len=%d total_ie_lent=%d", + elem_id, elem_len, *total_ielen); + } + } + + left -= elem_len; + ptr += (elem_len + 2); + } + return; +} + +/** + * wlan_hdd_cfg80211_alloc_new_beacon() - alloc beacon in ap mode + * @pAdapter: Pointer to hostapd adapter + * @ppBeacon: Pointer to pointer to beacon data + * @params: Pointer to beacon parameters + * @dtim_period: DTIM period + * + * Return: 0 for success non-zero for failure + */ +static int +wlan_hdd_cfg80211_alloc_new_beacon(hdd_adapter_t *pAdapter, + beacon_data_t **ppBeacon, + struct cfg80211_beacon_data *params, + int dtim_period) +{ + int size; + beacon_data_t *beacon = NULL; + beacon_data_t *old = NULL; + int head_len, tail_len, proberesp_ies_len, assocresp_ies_len; + const u8 *head, *tail, *proberesp_ies, *assocresp_ies; + + ENTER(); + if (params->head && !params->head_len) { + hdd_err("head_len is NULL"); + return -EINVAL; + } + + old = pAdapter->sessionCtx.ap.beacon; + + if (!params->head && !old) { + hdd_err("session(%d) old and new heads points to NULL", + pAdapter->sessionId); + return -EINVAL; + } + + if (params->head) { + head_len = params->head_len; + head = params->head; + } else { + head_len = old->head_len; + head = old->head; + } + + if (params->tail || !old) { + tail_len = params->tail_len; + tail = params->tail; + } else { + tail_len = old->tail_len; + tail = old->tail; + } + + if (params->proberesp_ies || !old) { + proberesp_ies_len = params->proberesp_ies_len; + proberesp_ies = params->proberesp_ies; + } else { + proberesp_ies_len = old->proberesp_ies_len; + proberesp_ies = old->proberesp_ies; + } + + if (params->assocresp_ies || !old) { + assocresp_ies_len = params->assocresp_ies_len; + assocresp_ies = params->assocresp_ies; + } else { + assocresp_ies_len = old->assocresp_ies_len; + assocresp_ies = old->assocresp_ies; + } + + size = sizeof(beacon_data_t) + head_len + tail_len + + proberesp_ies_len + assocresp_ies_len; + + beacon = qdf_mem_malloc(size); + + if (beacon == NULL) { + hdd_err("Mem allocation for beacon failed"); + return -ENOMEM; + } + if (dtim_period) + beacon->dtim_period = dtim_period; + else if (old) + beacon->dtim_period = old->dtim_period; + /* ----------------------------------------------- + * | head | tail | proberesp_ies | assocresp_ies | + * ----------------------------------------------- + */ + beacon->head = ((u8 *) beacon) + sizeof(beacon_data_t); + beacon->tail = beacon->head + head_len; + beacon->proberesp_ies = beacon->tail + tail_len; + beacon->assocresp_ies = beacon->proberesp_ies + proberesp_ies_len; + + beacon->head_len = head_len; + beacon->tail_len = tail_len; + beacon->proberesp_ies_len = proberesp_ies_len; + beacon->assocresp_ies_len = assocresp_ies_len; + + if (head && head_len) + memcpy(beacon->head, head, head_len); + if (tail && tail_len) + memcpy(beacon->tail, tail, tail_len); + if (proberesp_ies && proberesp_ies_len) + memcpy(beacon->proberesp_ies, proberesp_ies, proberesp_ies_len); + if (assocresp_ies && assocresp_ies_len) + memcpy(beacon->assocresp_ies, assocresp_ies, assocresp_ies_len); + + *ppBeacon = beacon; + + pAdapter->sessionCtx.ap.beacon = NULL; + qdf_mem_free(old); + + return 0; + +} + +#ifdef QCA_HT_2040_COEX +static void wlan_hdd_add_sap_obss_scan_ie( + hdd_adapter_t *hostapd_adapter, uint8_t *ie_buf, uint16_t *ie_len) +{ + if (QDF_SAP_MODE == hostapd_adapter->device_mode) { + if (wlan_hdd_get_sap_obss(hostapd_adapter)) + wlan_hdd_add_extra_ie(hostapd_adapter, ie_buf, ie_len, + WLAN_EID_OVERLAP_BSS_SCAN_PARAM); + } +} +#else +static void wlan_hdd_add_sap_obss_scan_ie( + hdd_adapter_t *hostapd_adapter, uint8_t *ie_buf, uint16_t *ie_len) +{ +} +#endif + +/** + * wlan_hdd_cfg80211_update_apies() - update ap mode ies + * @adapter: Pointer to hostapd adapter + * + * Return: 0 for success non-zero for failure + */ +int wlan_hdd_cfg80211_update_apies(hdd_adapter_t *adapter) +{ + uint8_t *genie; + uint16_t total_ielen = 0; + int ret = 0; + tsap_Config_t *pConfig; + tSirUpdateIE updateIE; + beacon_data_t *beacon = NULL; + uint16_t proberesp_ies_len; + uint8_t *proberesp_ies = NULL; + + pConfig = &adapter->sessionCtx.ap.sapConfig; + beacon = adapter->sessionCtx.ap.beacon; + + genie = qdf_mem_malloc(MAX_GENIE_LEN); + + if (genie == NULL) + return -ENOMEM; + + wlan_hdd_add_extra_ie(adapter, genie, &total_ielen, + WLAN_EID_VHT_TX_POWER_ENVELOPE); + + /* Extract and add the extended capabilities and interworking IE */ + wlan_hdd_add_extra_ie(adapter, genie, &total_ielen, + WLAN_EID_EXT_CAPABILITY); + + wlan_hdd_add_extra_ie(adapter, genie, &total_ielen, + WLAN_EID_INTERWORKING); + + if (0 != wlan_hdd_add_ie(adapter, genie, + &total_ielen, WPS_OUI_TYPE, WPS_OUI_TYPE_SIZE)) { + hdd_err("Adding WPS IE failed"); + ret = -EINVAL; + goto done; + } +#ifdef WLAN_FEATURE_WFD + if (0 != wlan_hdd_add_ie(adapter, genie, + &total_ielen, WFD_OUI_TYPE, WFD_OUI_TYPE_SIZE)) { + hdd_err("Adding WFD IE failed"); + ret = -EINVAL; + goto done; + } +#endif + +#ifdef FEATURE_WLAN_WAPI + if (QDF_SAP_MODE == adapter->device_mode) { + wlan_hdd_add_extra_ie(adapter, genie, &total_ielen, + WLAN_EID_WAPI); + } +#endif + + if (adapter->device_mode == QDF_SAP_MODE || + adapter->device_mode == QDF_P2P_GO_MODE) + wlan_hdd_add_hostapd_conf_vsie(adapter, genie, + &total_ielen); + + if (wlan_hdd_add_ie(adapter, genie, + &total_ielen, P2P_OUI_TYPE, P2P_OUI_TYPE_SIZE) != 0) { + hdd_err("Adding P2P IE failed"); + ret = -EINVAL; + goto done; + } + + wlan_hdd_add_sap_obss_scan_ie(adapter, genie, &total_ielen); + + qdf_copy_macaddr(&updateIE.bssid, &adapter->macAddressCurrent); + updateIE.smeSessionId = adapter->sessionId; + + if (test_bit(SOFTAP_BSS_STARTED, &adapter->event_flags)) { + updateIE.ieBufferlength = total_ielen; + updateIE.pAdditionIEBuffer = genie; + updateIE.append = false; + updateIE.notify = true; + if (sme_update_add_ie(WLAN_HDD_GET_HAL_CTX(adapter), + &updateIE, + eUPDATE_IE_PROBE_BCN) == + QDF_STATUS_E_FAILURE) { + hdd_err("Could not pass on Add Ie probe beacon data"); + ret = -EINVAL; + goto done; + } + wlansap_reset_sap_config_add_ie(pConfig, eUPDATE_IE_PROBE_BCN); + } else { + wlansap_update_sap_config_add_ie(pConfig, + genie, + total_ielen, + eUPDATE_IE_PROBE_BCN); + } + + /* Added for Probe Response IE */ + proberesp_ies = qdf_mem_malloc(beacon->proberesp_ies_len + + MAX_GENIE_LEN); + if (proberesp_ies == NULL) { + hdd_err("mem alloc failed for probe resp ies %d", + proberesp_ies_len); + ret = -EINVAL; + goto done; + } + qdf_mem_copy(proberesp_ies, beacon->proberesp_ies, + beacon->proberesp_ies_len); + proberesp_ies_len = beacon->proberesp_ies_len; + + wlan_hdd_add_sap_obss_scan_ie(adapter, proberesp_ies, + &proberesp_ies_len); + + if (test_bit(SOFTAP_BSS_STARTED, &adapter->event_flags)) { + updateIE.ieBufferlength = proberesp_ies_len; + updateIE.pAdditionIEBuffer = proberesp_ies; + updateIE.append = false; + updateIE.notify = false; + if (sme_update_add_ie(WLAN_HDD_GET_HAL_CTX(adapter), + &updateIE, + eUPDATE_IE_PROBE_RESP) == + QDF_STATUS_E_FAILURE) { + hdd_err("Could not pass on PROBE_RESP add Ie data"); + ret = -EINVAL; + goto done; + } + wlansap_reset_sap_config_add_ie(pConfig, eUPDATE_IE_PROBE_RESP); + } else { + wlansap_update_sap_config_add_ie(pConfig, + proberesp_ies, + proberesp_ies_len, + eUPDATE_IE_PROBE_RESP); + } + + /* Assoc resp Add ie Data */ + if (test_bit(SOFTAP_BSS_STARTED, &adapter->event_flags)) { + updateIE.ieBufferlength = beacon->assocresp_ies_len; + updateIE.pAdditionIEBuffer = (uint8_t *) beacon->assocresp_ies; + updateIE.append = false; + updateIE.notify = false; + if (sme_update_add_ie(WLAN_HDD_GET_HAL_CTX(adapter), + &updateIE, + eUPDATE_IE_ASSOC_RESP) == + QDF_STATUS_E_FAILURE) { + hdd_err("Could not pass on Add Ie Assoc Response data"); + ret = -EINVAL; + goto done; + } + wlansap_reset_sap_config_add_ie(pConfig, eUPDATE_IE_ASSOC_RESP); + } else { + wlansap_update_sap_config_add_ie(pConfig, + beacon->assocresp_ies, + beacon->assocresp_ies_len, + eUPDATE_IE_ASSOC_RESP); + } + +done: + qdf_mem_free(genie); + qdf_mem_free(proberesp_ies); + return ret; +} + +/** + * wlan_hdd_set_sap_hwmode() - set sap hw mode + * @pHostapdAdapter: Pointer to hostapd adapter + * + * Return: none + */ +static void wlan_hdd_set_sap_hwmode(hdd_adapter_t *pHostapdAdapter) +{ + tsap_Config_t *pConfig = &pHostapdAdapter->sessionCtx.ap.sapConfig; + beacon_data_t *pBeacon = pHostapdAdapter->sessionCtx.ap.beacon; + struct ieee80211_mgmt *pMgmt_frame = + (struct ieee80211_mgmt *)pBeacon->head; + u8 checkRatesfor11g = true; + u8 require_ht = false, require_vht = false; + u8 *pIe = NULL; + + pConfig->SapHw_mode = eCSR_DOT11_MODE_11b; + + pIe = wlan_hdd_cfg80211_get_ie_ptr(&pMgmt_frame->u.beacon.variable[0], + pBeacon->head_len, + WLAN_EID_SUPP_RATES); + if (pIe != NULL) { + pIe += 1; + wlan_hdd_check_11gmode(pIe, &require_ht, &require_vht, + &checkRatesfor11g, &pConfig->SapHw_mode); + } + + pIe = wlan_hdd_cfg80211_get_ie_ptr(pBeacon->tail, pBeacon->tail_len, + WLAN_EID_EXT_SUPP_RATES); + if (pIe != NULL) { + pIe += 1; + wlan_hdd_check_11gmode(pIe, &require_ht, &require_vht, + &checkRatesfor11g, &pConfig->SapHw_mode); + } + + if (pConfig->channel > 14) + pConfig->SapHw_mode = eCSR_DOT11_MODE_11a; + + pIe = wlan_hdd_cfg80211_get_ie_ptr(pBeacon->tail, pBeacon->tail_len, + WLAN_EID_HT_CAPABILITY); + + if (pIe) { + pConfig->SapHw_mode = eCSR_DOT11_MODE_11n; + if (require_ht) + pConfig->SapHw_mode = eCSR_DOT11_MODE_11n_ONLY; + } + + pIe = wlan_hdd_cfg80211_get_ie_ptr(pBeacon->tail, pBeacon->tail_len, + WLAN_EID_VHT_CAPABILITY); + + if (pIe) { + pConfig->SapHw_mode = eCSR_DOT11_MODE_11ac; + if (require_vht) + pConfig->SapHw_mode = eCSR_DOT11_MODE_11ac_ONLY; + } +} + +/** + * wlan_hdd_config_acs() - config ACS needed parameters + * @hdd_ctx: HDD context + * @adapter: Adapter pointer + * + * This function get ACS related INI paramters and populated + * sap config and smeConfig for ACS needed configurations. + * + * Return: The QDF_STATUS code associated with performing the operation. + */ +QDF_STATUS wlan_hdd_config_acs(hdd_context_t *hdd_ctx, hdd_adapter_t *adapter) +{ + tsap_Config_t *sap_config; + struct hdd_config *ini_config; + tHalHandle hal; + + hal = WLAN_HDD_GET_HAL_CTX(adapter); + sap_config = &adapter->sessionCtx.ap.sapConfig; + ini_config = hdd_ctx->config; + + sap_config->enOverLapCh = !!hdd_ctx->config->gEnableOverLapCh; + +#ifdef FEATURE_WLAN_AP_AP_ACS_OPTIMIZE + hdd_notice("HDD_ACS_SKIP_STATUS = %d", + hdd_ctx->skip_acs_scan_status); + if (hdd_ctx->skip_acs_scan_status == eSAP_SKIP_ACS_SCAN) { + hdd_adapter_t *con_sap_adapter; + tsap_Config_t *con_sap_config = NULL; + + con_sap_adapter = hdd_get_con_sap_adapter(adapter, false); + + if (con_sap_adapter) + con_sap_config = + &con_sap_adapter->sessionCtx.ap.sapConfig; + + sap_config->acs_cfg.skip_scan_status = eSAP_DO_NEW_ACS_SCAN; + + if (con_sap_config && + con_sap_config->acs_cfg.acs_mode == true && + hdd_ctx->skip_acs_scan_status == eSAP_SKIP_ACS_SCAN && + con_sap_config->acs_cfg.hw_mode == + sap_config->acs_cfg.hw_mode) { + uint8_t con_sap_st_ch, con_sap_end_ch; + uint8_t cur_sap_st_ch, cur_sap_end_ch; + uint8_t bandStartChannel, bandEndChannel; + + con_sap_st_ch = + con_sap_config->acs_cfg.start_ch; + con_sap_end_ch = + con_sap_config->acs_cfg.end_ch; + cur_sap_st_ch = sap_config->acs_cfg.start_ch; + cur_sap_end_ch = sap_config->acs_cfg.end_ch; + + wlansap_extend_to_acs_range( + &cur_sap_st_ch, &cur_sap_end_ch, + &bandStartChannel, &bandEndChannel); + + wlansap_extend_to_acs_range( + &con_sap_st_ch, &con_sap_end_ch, + &bandStartChannel, &bandEndChannel); + + if (con_sap_st_ch <= cur_sap_st_ch && + con_sap_end_ch >= cur_sap_end_ch) { + sap_config->acs_cfg.skip_scan_status = + eSAP_SKIP_ACS_SCAN; + + } else if (con_sap_st_ch >= cur_sap_st_ch && + con_sap_end_ch >= cur_sap_end_ch) { + sap_config->acs_cfg.skip_scan_status = + eSAP_DO_PAR_ACS_SCAN; + + sap_config->acs_cfg.skip_scan_range1_stch = + cur_sap_st_ch; + sap_config->acs_cfg.skip_scan_range1_endch = + con_sap_st_ch - 1; + sap_config->acs_cfg.skip_scan_range2_stch = + 0; + sap_config->acs_cfg.skip_scan_range2_endch = + 0; + + } else if (con_sap_st_ch <= cur_sap_st_ch && + con_sap_end_ch <= cur_sap_end_ch) { + sap_config->acs_cfg.skip_scan_status = + eSAP_DO_PAR_ACS_SCAN; + + sap_config->acs_cfg.skip_scan_range1_stch = + con_sap_end_ch + 1; + sap_config->acs_cfg.skip_scan_range1_endch = + cur_sap_end_ch; + sap_config->acs_cfg.skip_scan_range2_stch = + 0; + sap_config->acs_cfg.skip_scan_range2_endch = + 0; + + } else if (con_sap_st_ch >= cur_sap_st_ch && + con_sap_end_ch <= cur_sap_end_ch) { + sap_config->acs_cfg.skip_scan_status = + eSAP_DO_PAR_ACS_SCAN; + + sap_config->acs_cfg.skip_scan_range1_stch = + cur_sap_st_ch; + sap_config->acs_cfg.skip_scan_range1_endch = + con_sap_st_ch - 1; + sap_config->acs_cfg.skip_scan_range2_stch = + con_sap_end_ch; + sap_config->acs_cfg.skip_scan_range2_endch = + cur_sap_end_ch + 1; + + } else + sap_config->acs_cfg.skip_scan_status = + eSAP_DO_NEW_ACS_SCAN; + + + hdd_notice(FL( + "SecAP ACS Skip=%d, ACS CH RANGE=%d-%d, %d-%d"), + sap_config->acs_cfg.skip_scan_status, + sap_config->acs_cfg.skip_scan_range1_stch, + sap_config->acs_cfg.skip_scan_range1_endch, + sap_config->acs_cfg.skip_scan_range2_stch, + sap_config->acs_cfg.skip_scan_range2_endch); + } + } +#endif + + return QDF_STATUS_SUCCESS; +} + +/** + * wlan_hdd_setup_driver_overrides : Overrides SAP / P2P GO Params + * @adapter: pointer to adapter struct + * + * This function overrides SAP / P2P Go configuration based on driver INI + * parameters for 11AC override and ACS. This overrides are done to support + * android legacy configuration method. + * + * NOTE: Non android platform supports concurrency and these overrides shall + * not be used. Also future driver based overrides shall be consolidated in this + * function only. Avoid random overrides in other location based on ini. + * + * Return: 0 for Success or Negative error codes. + */ +static int wlan_hdd_setup_driver_overrides(hdd_adapter_t *ap_adapter) +{ + tsap_Config_t *sap_cfg = &ap_adapter->sessionCtx.ap.sapConfig; + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(ap_adapter); + + if (ap_adapter->device_mode == QDF_SAP_MODE && + hdd_ctx->config->force_sap_acs) + goto setup_acs_overrides; + + /* Fixed channel 11AC override: + * 11AC override in qcacld is introduced for following reasons: + * 1. P2P GO also follows start_bss and since p2p GO could not be + * configured to setup VHT channel width in wpa_supplicant + * 2. Android UI does not provide advanced configuration options for SAP + * + * Default override enabled (for android). MDM shall disable this in ini + */ + /* + * sub_20 MHz channel width is incompatible with 11AC rates, hence do + * not allow 11AC rates or more than 20 MHz channel width when + * enable_sub_20_channel_width is non zero + */ + if (!hdd_ctx->config->enable_sub_20_channel_width && + hdd_ctx->config->sap_p2p_11ac_override && + (sap_cfg->SapHw_mode == eCSR_DOT11_MODE_11n || + sap_cfg->SapHw_mode == eCSR_DOT11_MODE_11ac || + sap_cfg->SapHw_mode == eCSR_DOT11_MODE_11ac_ONLY) && + !hdd_ctx->config->sap_force_11n_for_11ac) { + hdd_notice("** Driver force 11AC override for SAP/Go **"); + + /* 11n only shall not be overridden since it may be on purpose*/ + if (sap_cfg->SapHw_mode == eCSR_DOT11_MODE_11n) + sap_cfg->SapHw_mode = eCSR_DOT11_MODE_11ac; + + if (sap_cfg->channel >= 36) { + sap_cfg->ch_width_orig = + hdd_ctx->config->vhtChannelWidth; + } else { + /* + * Allow 40 Mhz in 2.4 Ghz only if indicated by + * supplicant after OBSS scan and if 2.4 Ghz channel + * bonding is set in INI + */ + if (sap_cfg->ch_width_orig >= eHT_CHANNEL_WIDTH_40MHZ && + hdd_ctx->config->nChannelBondingMode24GHz) + sap_cfg->ch_width_orig = + eHT_CHANNEL_WIDTH_40MHZ; + else + sap_cfg->ch_width_orig = + eHT_CHANNEL_WIDTH_20MHZ; + } + } + sap_cfg->ch_params.ch_width = sap_cfg->ch_width_orig; + cds_set_channel_params(sap_cfg->channel, + sap_cfg->sec_ch, &sap_cfg->ch_params); + + return 0; + +setup_acs_overrides: + hdd_err("** Driver force ACS override **"); + + sap_cfg->channel = AUTO_CHANNEL_SELECT; + sap_cfg->acs_cfg.acs_mode = true; + sap_cfg->acs_cfg.start_ch = hdd_ctx->config->force_sap_acs_st_ch; + sap_cfg->acs_cfg.end_ch = hdd_ctx->config->force_sap_acs_end_ch; + + if (sap_cfg->acs_cfg.start_ch > sap_cfg->acs_cfg.end_ch) { + hdd_err("Driver force ACS start ch (%d) > end ch (%d)", + sap_cfg->acs_cfg.start_ch, sap_cfg->acs_cfg.end_ch); + return -EINVAL; + } + + /* Derive ACS HW mode */ + sap_cfg->SapHw_mode = hdd_cfg_xlate_to_csr_phy_mode( + hdd_ctx->config->dot11Mode); + if (sap_cfg->SapHw_mode == eCSR_DOT11_MODE_AUTO) + sap_cfg->SapHw_mode = eCSR_DOT11_MODE_11ac; + + if (hdd_ctx->config->sap_force_11n_for_11ac) { + if (sap_cfg->SapHw_mode == eCSR_DOT11_MODE_11ac || + sap_cfg->SapHw_mode == eCSR_DOT11_MODE_11ac_ONLY) + sap_cfg->SapHw_mode = eCSR_DOT11_MODE_11n; + } + + if ((sap_cfg->SapHw_mode == eCSR_DOT11_MODE_11b || + sap_cfg->SapHw_mode == eCSR_DOT11_MODE_11g || + sap_cfg->SapHw_mode == eCSR_DOT11_MODE_11g_ONLY) && + sap_cfg->acs_cfg.start_ch > 14) { + hdd_err("Invalid ACS HW Mode %d + CH range <%d - %d>", + sap_cfg->SapHw_mode, sap_cfg->acs_cfg.start_ch, + sap_cfg->acs_cfg.end_ch); + return -EINVAL; + } + sap_cfg->acs_cfg.hw_mode = sap_cfg->SapHw_mode; + + /* Derive ACS BW */ + sap_cfg->ch_width_orig = eHT_CHANNEL_WIDTH_20MHZ; + if (sap_cfg->SapHw_mode == eCSR_DOT11_MODE_11ac || + sap_cfg->SapHw_mode == eCSR_DOT11_MODE_11ac_ONLY) { + + sap_cfg->ch_width_orig = hdd_ctx->config->vhtChannelWidth; + /* VHT in 2.4G depends on gChannelBondingMode24GHz INI param */ + if (sap_cfg->acs_cfg.end_ch <= 14) + sap_cfg->ch_width_orig = + hdd_ctx->config->nChannelBondingMode24GHz ? + eHT_CHANNEL_WIDTH_40MHZ : + eHT_CHANNEL_WIDTH_20MHZ; + } + + if (sap_cfg->SapHw_mode == eCSR_DOT11_MODE_11n || + sap_cfg->SapHw_mode == eCSR_DOT11_MODE_11n_ONLY) { + if (sap_cfg->acs_cfg.end_ch <= 14) + sap_cfg->ch_width_orig = + hdd_ctx->config->nChannelBondingMode24GHz ? + eHT_CHANNEL_WIDTH_40MHZ : + eHT_CHANNEL_WIDTH_20MHZ; + else + sap_cfg->ch_width_orig = + hdd_ctx->config->nChannelBondingMode5GHz ? + eHT_CHANNEL_WIDTH_40MHZ : + eHT_CHANNEL_WIDTH_20MHZ; + } + sap_cfg->acs_cfg.ch_width = sap_cfg->ch_width_orig; + + hdd_notice("Force ACS Config: HW_MODE: %d ACS_BW: %d", + sap_cfg->acs_cfg.hw_mode, sap_cfg->acs_cfg.ch_width); + hdd_notice("Force ACS Config: ST_CH: %d END_CH: %d", + sap_cfg->acs_cfg.start_ch, sap_cfg->acs_cfg.end_ch); + + return 0; +} + +#ifdef WLAN_FEATURE_UDP_RESPONSE_OFFLOAD +/** + * wlan_hdd_set_udp_resp_offload() - get specific udp and response udp info from + * ini file + * @padapter: hdd adapter pointer + * @enable: enable or disable the specific udp and response behaviour + * + * This function reads specific udp and response udp related info from ini file, + * these configurations will be sent to fw through wmi. + * + * Return: 0 on success, otherwise error value + */ +static int wlan_hdd_set_udp_resp_offload(hdd_adapter_t *padapter, bool enable) +{ + hdd_context_t *phddctx = WLAN_HDD_GET_CTX(padapter); + struct hdd_config *pcfg_ini = phddctx->config; + struct udp_resp_offload udp_resp_cmd_info; + QDF_STATUS status; + uint8_t udp_payload_filter_len; + uint8_t udp_response_payload_len; + + hdd_info("udp_resp_offload enable flag is %d", enable); + + /* prepare the request to send to SME */ + if ((enable == true) && + (pcfg_ini->udp_resp_offload_support)) { + if (pcfg_ini->response_payload[0] != '\0') { + udp_resp_cmd_info.vdev_id = padapter->sessionId; + udp_resp_cmd_info.enable = 1; + udp_resp_cmd_info.dest_port = + pcfg_ini->dest_port; + + udp_payload_filter_len = + strlen(pcfg_ini->payload_filter); + hdd_info("payload_filter[%s]", + pcfg_ini->payload_filter); + udp_response_payload_len = + strlen(pcfg_ini->response_payload); + hdd_info("response_payload[%s]", + pcfg_ini->response_payload); + + qdf_mem_copy(udp_resp_cmd_info.udp_payload_filter, + pcfg_ini->payload_filter, + udp_payload_filter_len + 1); + + qdf_mem_copy(udp_resp_cmd_info.udp_response_payload, + pcfg_ini->response_payload, + udp_response_payload_len + 1); + + status = sme_set_udp_resp_offload(&udp_resp_cmd_info); + if (QDF_STATUS_E_FAILURE == status) { + hdd_err("sme_set_udp_resp_offload failure!"); + return -EIO; + } + hdd_info("sme_set_udp_resp_offload success!"); + } + } else { + udp_resp_cmd_info.vdev_id = padapter->sessionId; + udp_resp_cmd_info.enable = 0; + udp_resp_cmd_info.dest_port = 0; + udp_resp_cmd_info.udp_payload_filter[0] = '\0'; + udp_resp_cmd_info.udp_response_payload[0] = '\0'; + status = sme_set_udp_resp_offload(&udp_resp_cmd_info); + if (QDF_STATUS_E_FAILURE == status) { + hdd_err("sme_set_udp_resp_offload failure!"); + return -EIO; + } + hdd_info("sme_set_udp_resp_offload success!"); + } + return 0; +} +#else +static inline int wlan_hdd_set_udp_resp_offload(hdd_adapter_t *padapter, + bool enable) +{ + return 0; +} +#endif + +/** + * wlan_hdd_cfg80211_start_bss() - start bss + * @pHostapdAdapter: Pointer to hostapd adapter + * @params: Pointer to start bss beacon parameters + * @ssid: Pointer ssid + * @ssid_len: Length of ssid + * @hidden_ssid: Hidden SSID parameter + * @check_for_concurrency: Flag to indicate if check for concurrency is needed + * + * Return: 0 for success non-zero for failure + */ +int wlan_hdd_cfg80211_start_bss(hdd_adapter_t *pHostapdAdapter, + struct cfg80211_beacon_data *params, + const u8 *ssid, size_t ssid_len, + enum nl80211_hidden_ssid hidden_ssid, + bool check_for_concurrency, + bool update_beacon) +{ + tsap_Config_t *pConfig; + beacon_data_t *pBeacon = NULL; + struct ieee80211_mgmt *pMgmt_frame; + uint8_t *pIe = NULL; + uint16_t capab_info; + eCsrAuthType RSNAuthType; + eCsrEncryptionType RSNEncryptType; + eCsrEncryptionType mcRSNEncryptType; + int status = QDF_STATUS_SUCCESS, ret; + int qdf_status = QDF_STATUS_SUCCESS; + tpWLAN_SAPEventCB pSapEventCallback; + hdd_hostapd_state_t *pHostapdState; + tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pHostapdAdapter); + struct qc_mac_acl_entry *acl_entry = NULL; + int32_t i; + struct hdd_config *iniConfig; + hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pHostapdAdapter); + tSmeConfigParams sme_config; + bool MFPCapable = false; + bool MFPRequired = false; + uint16_t prev_rsn_length = 0; + enum dfs_mode mode; + bool disable_fw_tdls_state = false; + + ENTER(); + + if (!update_beacon && cds_is_connection_in_progress(NULL, NULL)) { + hdd_err("Can't start BSS: connection is in progress"); + return -EINVAL; + } + + disable_fw_tdls_state = true; + wlan_hdd_check_conc_and_update_tdls_state(pHddCtx, + disable_fw_tdls_state); + + if (cds_is_hw_mode_change_in_progress()) { + status = qdf_wait_for_connection_update(); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("qdf wait for event failed!!"); + ret = -EINVAL; + goto ret_status; + } + } + + iniConfig = pHddCtx->config; + pHostapdState = WLAN_HDD_GET_HOSTAP_STATE_PTR(pHostapdAdapter); + + clear_bit(ACS_PENDING, &pHostapdAdapter->event_flags); + clear_bit(ACS_IN_PROGRESS, &pHddCtx->g_event_flags); + + pConfig = &pHostapdAdapter->sessionCtx.ap.sapConfig; + + pBeacon = pHostapdAdapter->sessionCtx.ap.beacon; + + pMgmt_frame = (struct ieee80211_mgmt *)pBeacon->head; + + pConfig->beacon_int = pMgmt_frame->u.beacon.beacon_int; + + pConfig->disableDFSChSwitch = iniConfig->disableDFSChSwitch; + + /* channel is already set in the set_channel Call back */ + /* pConfig->channel = pCommitConfig->channel; */ + + /* Protection parameter to enable or disable */ + pConfig->protEnabled = iniConfig->apProtEnabled; + + pConfig->enOverLapCh = iniConfig->gEnableOverLapCh; + pConfig->dtim_period = pBeacon->dtim_period; + hdd_info("acs_mode %d", pConfig->acs_cfg.acs_mode); + + if (pConfig->acs_cfg.acs_mode == true) { + hdd_info("acs_channel %d, acs_dfs_mode %d", + pHddCtx->acs_policy.acs_channel, + pHddCtx->acs_policy.acs_dfs_mode); + + if (pHddCtx->acs_policy.acs_channel) + pConfig->channel = pHddCtx->acs_policy.acs_channel; + mode = pHddCtx->acs_policy.acs_dfs_mode; + pConfig->acs_dfs_mode = wlan_hdd_get_dfs_mode(mode); + } + + hdd_info("pConfig->channel %d, pConfig->acs_dfs_mode %d", + pConfig->channel, pConfig->acs_dfs_mode); + + hdd_info("****pConfig->dtim_period=%d***", + pConfig->dtim_period); + + if (pHostapdAdapter->device_mode == QDF_SAP_MODE) { + pIe = + wlan_hdd_cfg80211_get_ie_ptr(pBeacon->tail, + pBeacon->tail_len, + WLAN_EID_COUNTRY); + if (pIe) { + pConfig->ieee80211d = 1; + qdf_mem_copy(pConfig->countryCode, &pIe[2], 3); + sme_set_reg_info(hHal, pConfig->countryCode); + sme_apply_channel_power_info_to_fw(hHal); + } else { + pConfig->countryCode[0] = pHddCtx->reg.alpha2[0]; + pConfig->countryCode[1] = pHddCtx->reg.alpha2[1]; + pConfig->ieee80211d = 0; + } + + ret = wlan_hdd_sap_cfg_dfs_override(pHostapdAdapter); + if (ret < 0) { + goto error; + } else { + if (ret == 0) { + if (CDS_IS_DFS_CH(pConfig->channel)) + pHddCtx->dev_dfs_cac_status = + DFS_CAC_NEVER_DONE; + } + } + + /* + * If auto channel is configured i.e. channel is 0, + * so skip channel validation. + */ + if (AUTO_CHANNEL_SELECT != pConfig->channel) { + if (QDF_STATUS_SUCCESS != + wlan_hdd_validate_operation_channel(pHostapdAdapter, + pConfig->channel)) { + hdd_err("Invalid Channel [%d]", + pConfig->channel); + ret = -EINVAL; + goto error; + } + + /* reject SAP if DFS channel scan is not allowed */ + if (!(pHddCtx->config->enableDFSChnlScan) && + (CHANNEL_STATE_DFS == cds_get_channel_state( + pConfig->channel))) { + hdd_err("No SAP start on DFS channel"); + ret = -EOPNOTSUPP; + goto error; + } + } + wlansap_set_dfs_ignore_cac(hHal, iniConfig->ignoreCAC); + wlansap_set_dfs_restrict_japan_w53(hHal, + iniConfig->gDisableDfsJapanW53); + wlansap_set_dfs_preferred_channel_location(hHal, + iniConfig->gSapPreferredChanLocation); +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE + wlan_sap_set_channel_avoidance(hHal, + iniConfig->sap_channel_avoidance); +#endif + } else if (pHostapdAdapter->device_mode == QDF_P2P_GO_MODE) { + pConfig->countryCode[0] = pHddCtx->reg.alpha2[0]; + pConfig->countryCode[1] = pHddCtx->reg.alpha2[1]; + pConfig->ieee80211d = 0; + } else { + pConfig->ieee80211d = 0; + } + + wlansap_set_tx_leakage_threshold(hHal, + iniConfig->sap_tx_leakage_threshold); + + capab_info = pMgmt_frame->u.beacon.capab_info; + + pConfig->privacy = (pMgmt_frame->u.beacon.capab_info & + WLAN_CAPABILITY_PRIVACY) ? true : false; + + (WLAN_HDD_GET_AP_CTX_PTR(pHostapdAdapter))->uPrivacy = pConfig->privacy; + + /*Set wps station to configured */ + pIe = wlan_hdd_get_wps_ie_ptr(pBeacon->tail, pBeacon->tail_len); + + if (pIe) { + if (pIe[1] < (2 + WPS_OUI_TYPE_SIZE)) { + hdd_err("**Wps Ie Length is too small***"); + ret = -EINVAL; + goto error; + } else if (memcmp(&pIe[2], WPS_OUI_TYPE, WPS_OUI_TYPE_SIZE) == + 0) { + hdd_notice("** WPS IE(len %d) ***", (pIe[1] + 2)); + /* Check 15 bit of WPS IE as it contain information for + * wps state + */ + if (SAP_WPS_ENABLED_UNCONFIGURED == pIe[15]) { + pConfig->wps_state = + SAP_WPS_ENABLED_UNCONFIGURED; + } else if (SAP_WPS_ENABLED_CONFIGURED == pIe[15]) { + pConfig->wps_state = SAP_WPS_ENABLED_CONFIGURED; + } + } + } else { + hdd_info("WPS disabled"); + pConfig->wps_state = SAP_WPS_DISABLED; + } + /* Forward WPS PBC probe request frame up */ + pConfig->fwdWPSPBCProbeReq = 1; + + pConfig->RSNEncryptType = eCSR_ENCRYPT_TYPE_NONE; + pConfig->mcRSNEncryptType = eCSR_ENCRYPT_TYPE_NONE; + (WLAN_HDD_GET_AP_CTX_PTR(pHostapdAdapter))->ucEncryptType = + eCSR_ENCRYPT_TYPE_NONE; + + pConfig->RSNWPAReqIELength = 0; + memset(&pConfig->RSNWPAReqIE[0], 0, sizeof(pConfig->RSNWPAReqIE)); + pIe = wlan_hdd_cfg80211_get_ie_ptr(pBeacon->tail, pBeacon->tail_len, + WLAN_EID_RSN); + if (pIe && pIe[1]) { + pConfig->RSNWPAReqIELength = pIe[1] + 2; + if (pConfig->RSNWPAReqIELength < sizeof(pConfig->RSNWPAReqIE)) + memcpy(&pConfig->RSNWPAReqIE[0], pIe, + pConfig->RSNWPAReqIELength); + else + hdd_err("RSNWPA IE MAX Length exceeded; length =%d", + pConfig->RSNWPAReqIELength); + /* The actual processing may eventually be more extensive than + * this. Right now, just consume any PMKIDs that are sent in + * by the app. + * */ + status = + hdd_softap_unpack_ie(cds_get_context + (QDF_MODULE_ID_SME), + &RSNEncryptType, &mcRSNEncryptType, + &RSNAuthType, &MFPCapable, + &MFPRequired, + pConfig->RSNWPAReqIE[1] + 2, + pConfig->RSNWPAReqIE); + + if (QDF_STATUS_SUCCESS == status) { + /* Now copy over all the security attributes you have + * parsed out. Use the cipher type in the RSN IE + */ + pConfig->RSNEncryptType = RSNEncryptType; + pConfig->mcRSNEncryptType = mcRSNEncryptType; + (WLAN_HDD_GET_AP_CTX_PTR(pHostapdAdapter))-> + ucEncryptType = RSNEncryptType; + hdd_notice("CSR AuthType = %d, EncryptionType = %d mcEncryptionType = %d", + RSNAuthType, RSNEncryptType, mcRSNEncryptType); + } + } + + pIe = wlan_hdd_get_vendor_oui_ie_ptr(WPA_OUI_TYPE, WPA_OUI_TYPE_SIZE, + pBeacon->tail, pBeacon->tail_len); + + if (pIe && pIe[1] && (pIe[0] == DOT11F_EID_WPA)) { + if (pConfig->RSNWPAReqIE[0]) { + /*Mixed mode WPA/WPA2 */ + prev_rsn_length = pConfig->RSNWPAReqIELength; + pConfig->RSNWPAReqIELength += pIe[1] + 2; + if (pConfig->RSNWPAReqIELength < + sizeof(pConfig->RSNWPAReqIE)) + memcpy(&pConfig->RSNWPAReqIE[0] + + prev_rsn_length, pIe, pIe[1] + 2); + else + hdd_err("RSNWPA IE MAX Length exceeded; length =%d", + pConfig->RSNWPAReqIELength); + } else { + pConfig->RSNWPAReqIELength = pIe[1] + 2; + if (pConfig->RSNWPAReqIELength < + sizeof(pConfig->RSNWPAReqIE)) + memcpy(&pConfig->RSNWPAReqIE[0], pIe, + pConfig->RSNWPAReqIELength); + else + hdd_err("RSNWPA IE MAX Length exceeded; length =%d", + pConfig->RSNWPAReqIELength); + status = hdd_softap_unpack_ie + (cds_get_context(QDF_MODULE_ID_SME), + &RSNEncryptType, + &mcRSNEncryptType, &RSNAuthType, + &MFPCapable, &MFPRequired, + pConfig->RSNWPAReqIE[1] + 2, + pConfig->RSNWPAReqIE); + + if (QDF_STATUS_SUCCESS == status) { + /* Now copy over all the security attributes + * you have parsed out. Use the cipher type + * in the RSN IE + */ + pConfig->RSNEncryptType = RSNEncryptType; + pConfig->mcRSNEncryptType = mcRSNEncryptType; + (WLAN_HDD_GET_AP_CTX_PTR(pHostapdAdapter))-> + ucEncryptType = RSNEncryptType; + hdd_notice("CSR AuthType = %d, EncryptionType = %d mcEncryptionType = %d", + RSNAuthType, RSNEncryptType, + mcRSNEncryptType); + } + } + } + + if (pConfig->RSNWPAReqIELength > sizeof(pConfig->RSNWPAReqIE)) { + hdd_err("**RSNWPAReqIELength is too large***"); + ret = -EINVAL; + goto error; + } + + pConfig->SSIDinfo.ssidHidden = false; + + if (ssid != NULL) { + qdf_mem_copy(pConfig->SSIDinfo.ssid.ssId, ssid, ssid_len); + pConfig->SSIDinfo.ssid.length = ssid_len; + + switch (hidden_ssid) { + case NL80211_HIDDEN_SSID_NOT_IN_USE: + hdd_notice("HIDDEN_SSID_NOT_IN_USE"); + pConfig->SSIDinfo.ssidHidden = eHIDDEN_SSID_NOT_IN_USE; + break; + case NL80211_HIDDEN_SSID_ZERO_LEN: + hdd_notice("HIDDEN_SSID_ZERO_LEN"); + pConfig->SSIDinfo.ssidHidden = eHIDDEN_SSID_ZERO_LEN; + break; + case NL80211_HIDDEN_SSID_ZERO_CONTENTS: + hdd_notice("HIDDEN_SSID_ZERO_CONTENTS"); + pConfig->SSIDinfo.ssidHidden = + eHIDDEN_SSID_ZERO_CONTENTS; + break; + default: + hdd_err("Wrong hidden_ssid param %d", hidden_ssid); + break; + } + } + + qdf_mem_copy(pConfig->self_macaddr.bytes, + pHostapdAdapter->macAddressCurrent.bytes, + QDF_MAC_ADDR_SIZE); + + /* default value */ + pConfig->SapMacaddr_acl = eSAP_ACCEPT_UNLESS_DENIED; + pConfig->num_accept_mac = 0; + pConfig->num_deny_mac = 0; +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH + /* + * We don't want P2PGO to follow STA's channel + * so lets limit the logic for SAP only. + * Later if we decide to make p2pgo follow STA's + * channel then remove this check. + */ + if ((0 == pHddCtx->config->conc_custom_rule1) || + (pHddCtx->config->conc_custom_rule1 && + QDF_SAP_MODE == pHostapdAdapter->device_mode)) + pConfig->cc_switch_mode = iniConfig->WlanMccToSccSwitchMode; +#endif + + pIe = + wlan_hdd_get_vendor_oui_ie_ptr(BLACKLIST_OUI_TYPE, + WPA_OUI_TYPE_SIZE, pBeacon->tail, + pBeacon->tail_len); + + /* pIe for black list is following form: + * type : 1 byte + * length : 1 byte + * OUI : 4 bytes + * acl type : 1 byte + * no of mac addr in black list: 1 byte + * list of mac_acl_entries: variable, 6 bytes per mac + * address + sizeof(int) for vlan id + */ + if ((pIe != NULL) && (pIe[1] != 0)) { + pConfig->SapMacaddr_acl = pIe[6]; + pConfig->num_deny_mac = pIe[7]; + hdd_notice("acl type = %d no deny mac = %d", pIe[6], pIe[7]); + if (pConfig->num_deny_mac > MAX_ACL_MAC_ADDRESS) + pConfig->num_deny_mac = MAX_ACL_MAC_ADDRESS; + acl_entry = (struct qc_mac_acl_entry *)(pIe + 8); + for (i = 0; i < pConfig->num_deny_mac; i++) { + qdf_mem_copy(&pConfig->deny_mac[i], acl_entry->addr, + sizeof(qcmacaddr)); + acl_entry++; + } + } + pIe = wlan_hdd_get_vendor_oui_ie_ptr(WHITELIST_OUI_TYPE, + WPA_OUI_TYPE_SIZE, pBeacon->tail, + pBeacon->tail_len); + + /* pIe for white list is following form: + * type : 1 byte + * length : 1 byte + * OUI : 4 bytes + * acl type : 1 byte + * no of mac addr in white list: 1 byte + * list of mac_acl_entries: variable, 6 bytes per mac + * address + sizeof(int) for vlan id + */ + if ((pIe != NULL) && (pIe[1] != 0)) { + pConfig->SapMacaddr_acl = pIe[6]; + pConfig->num_accept_mac = pIe[7]; + hdd_notice("acl type = %d no accept mac = %d", + pIe[6], pIe[7]); + if (pConfig->num_accept_mac > MAX_ACL_MAC_ADDRESS) + pConfig->num_accept_mac = MAX_ACL_MAC_ADDRESS; + acl_entry = (struct qc_mac_acl_entry *)(pIe + 8); + for (i = 0; i < pConfig->num_accept_mac; i++) { + qdf_mem_copy(&pConfig->accept_mac[i], acl_entry->addr, + sizeof(qcmacaddr)); + acl_entry++; + } + } + if (!pHddCtx->config->force_sap_acs && + !(ssid && (0 == qdf_mem_cmp(ssid, PRE_CAC_SSID, ssid_len)))) { + pIe = wlan_hdd_cfg80211_get_ie_ptr( + &pMgmt_frame->u.beacon.variable[0], + pBeacon->head_len, WLAN_EID_SUPP_RATES); + + if (pIe != NULL) { + pIe++; + pConfig->supported_rates.numRates = pIe[0]; + pIe++; + for (i = 0; + i < pConfig->supported_rates.numRates; i++) { + if (pIe[i]) { + pConfig->supported_rates.rate[i] = pIe[i]; + hdd_info("Configured Supported rate is %2x", + pConfig->supported_rates.rate[i]); + } + } + } + pIe = wlan_hdd_cfg80211_get_ie_ptr(pBeacon->tail, + pBeacon->tail_len, + WLAN_EID_EXT_SUPP_RATES); + if (pIe != NULL) { + pIe++; + pConfig->extended_rates.numRates = pIe[0]; + pIe++; + for (i = 0; i < pConfig->extended_rates.numRates; i++) { + if (pIe[i]) { + pConfig->extended_rates.rate[i] = pIe[i]; + hdd_info("Configured ext Supported rate is %2x", + pConfig->extended_rates.rate[i]); + } + } + } + } + + if (!cds_is_sub_20_mhz_enabled()) + wlan_hdd_set_sap_hwmode(pHostapdAdapter); + + if (pHddCtx->config->sap_force_11n_for_11ac) { + if (pConfig->SapHw_mode == eCSR_DOT11_MODE_11ac || + pConfig->SapHw_mode == eCSR_DOT11_MODE_11ac_ONLY) + pConfig->SapHw_mode = eCSR_DOT11_MODE_11n; + } + + qdf_mem_zero(&sme_config, sizeof(tSmeConfigParams)); + sme_get_config_param(pHddCtx->hHal, &sme_config); + /* Override hostapd.conf wmm_enabled only for 11n and 11AC configs (IOT) + * As per spec 11N/AC STA are QOS STA and may not connect or throughput + * may not be good with non QOS 11N AP + * Default: enable QOS for SAP unless WMM IE not present for 11bga + */ + sme_config.csrConfig.WMMSupportMode = eCsrRoamWmmAuto; + pIe = wlan_hdd_get_vendor_oui_ie_ptr(WMM_OUI_TYPE, WMM_OUI_TYPE_SIZE, + pBeacon->tail, pBeacon->tail_len); + if (!pIe && (pConfig->SapHw_mode == eCSR_DOT11_MODE_11a || + pConfig->SapHw_mode == eCSR_DOT11_MODE_11g || + pConfig->SapHw_mode == eCSR_DOT11_MODE_11b)) + sme_config.csrConfig.WMMSupportMode = eCsrRoamWmmNoQos; + sme_update_config(pHddCtx->hHal, &sme_config); + + if (!pHddCtx->config->sap_force_11n_for_11ac) { + pConfig->ch_width_orig = + hdd_map_nl_chan_width(pConfig->ch_width_orig); + } else { + if (pConfig->ch_width_orig >= NL80211_CHAN_WIDTH_40) + pConfig->ch_width_orig = CH_WIDTH_40MHZ; + else + pConfig->ch_width_orig = CH_WIDTH_20MHZ; + } + + if (wlan_hdd_setup_driver_overrides(pHostapdAdapter)) { + ret = -EINVAL; + goto error; + } + + /* ht_capab is not what the name conveys,this is used for protection + * bitmap */ + pConfig->ht_capab = iniConfig->apProtection; + + if (0 != wlan_hdd_cfg80211_update_apies(pHostapdAdapter)) { + hdd_err("SAP Not able to set AP IEs"); + wlansap_reset_sap_config_add_ie(pConfig, eUPDATE_IE_ALL); + ret = -EINVAL; + goto error; + } + /* Uapsd Enabled Bit */ + pConfig->UapsdEnable = iniConfig->apUapsdEnabled; + /* Enable OBSS protection */ + pConfig->obssProtEnabled = iniConfig->apOBSSProtEnabled; + + if (pHostapdAdapter->device_mode == QDF_SAP_MODE) + pConfig->sap_dot11mc = + (WLAN_HDD_GET_CTX(pHostapdAdapter))->config->sap_dot11mc; + else /* for P2P-Go case */ + pConfig->sap_dot11mc = 1; + + hdd_notice("11MC Support Enabled : %d\n", + pConfig->sap_dot11mc); + +#ifdef WLAN_FEATURE_11W + pConfig->mfpCapable = MFPCapable; + pConfig->mfpRequired = MFPRequired; + hdd_notice("Soft AP MFP capable %d, MFP required %d", + pConfig->mfpCapable, pConfig->mfpRequired); +#endif + + hdd_warn("SOftAP macaddress : " MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(pHostapdAdapter->macAddressCurrent.bytes)); + hdd_warn("ssid =%s, beaconint=%d, channel=%d", + pConfig->SSIDinfo.ssid.ssId, (int)pConfig->beacon_int, + (int)pConfig->channel); + hdd_warn("hw_mode=%x, privacy=%d, authType=%d", + pConfig->SapHw_mode, pConfig->privacy, pConfig->authType); + hdd_warn("RSN/WPALen=%d, Uapsd = %d", + (int)pConfig->RSNWPAReqIELength, pConfig->UapsdEnable); + hdd_warn("ProtEnabled = %d, OBSSProtEnabled = %d", + pConfig->protEnabled, pConfig->obssProtEnabled); + + if (test_bit(SOFTAP_BSS_STARTED, &pHostapdAdapter->event_flags)) { + wlansap_reset_sap_config_add_ie(pConfig, eUPDATE_IE_ALL); + /* Bss already started. just return. */ + /* TODO Probably it should update some beacon params. */ + hdd_err("Bss Already started...Ignore the request"); + EXIT(); + return 0; + } + + if (check_for_concurrency) { + if (!cds_allow_concurrency( + cds_convert_device_mode_to_qdf_type( + pHostapdAdapter->device_mode), + pConfig->channel, HW_MODE_20_MHZ)) { + hdd_warn("This concurrency combination is not allowed"); + ret = -EINVAL; + goto error; + } + } + + if (!cds_set_connection_in_progress(true)) { + hdd_err("Can't start BSS: set connnection in progress failed"); + ret = -EINVAL; + goto error; + } + + pConfig->persona = pHostapdAdapter->device_mode; + + pSapEventCallback = hdd_hostapd_sap_event_cb; + + (WLAN_HDD_GET_AP_CTX_PTR(pHostapdAdapter))->dfs_cac_block_tx = true; + set_bit(SOFTAP_INIT_DONE, &pHostapdAdapter->event_flags); + + qdf_event_reset(&pHostapdState->qdf_event); + status = wlansap_start_bss( + WLAN_HDD_GET_SAP_CTX_PTR(pHostapdAdapter), + pSapEventCallback, pConfig, pHostapdAdapter->dev); + if (!QDF_IS_STATUS_SUCCESS(status)) { + wlansap_reset_sap_config_add_ie(pConfig, eUPDATE_IE_ALL); + cds_set_connection_in_progress(false); + hdd_err("SAP Start Bss fail"); + ret = -EINVAL; + goto error; + } + + hdd_notice("Waiting for Scan to complete(auto mode) and BSS to start"); + + qdf_status = qdf_wait_single_event(&pHostapdState->qdf_event, + SME_CMD_TIMEOUT_VALUE); + + wlansap_reset_sap_config_add_ie(pConfig, eUPDATE_IE_ALL); + + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + hdd_err("ERROR: HDD qdf wait for single_event failed!!"); + cds_set_connection_in_progress(false); + sme_get_command_q_status(hHal); + wlansap_stop_bss(WLAN_HDD_GET_SAP_CTX_PTR(pHostapdAdapter)); + QDF_ASSERT(0); + ret = -EINVAL; + goto error; + } + /* Succesfully started Bss update the state bit. */ + set_bit(SOFTAP_BSS_STARTED, &pHostapdAdapter->event_flags); + /* Initialize WMM configuation */ + hdd_wmm_init(pHostapdAdapter); + if (pHostapdState->bssState == BSS_START) + cds_incr_active_session(pHostapdAdapter->device_mode, + pHostapdAdapter->sessionId); +#ifdef DHCP_SERVER_OFFLOAD + if (iniConfig->enableDHCPServerOffload) + wlan_hdd_set_dhcp_server_offload(pHostapdAdapter); +#endif /* DHCP_SERVER_OFFLOAD */ + +#ifdef WLAN_FEATURE_P2P_DEBUG + if (pHostapdAdapter->device_mode == QDF_P2P_GO_MODE) { + if (global_p2p_connection_status == P2P_GO_NEG_COMPLETED) { + global_p2p_connection_status = P2P_GO_COMPLETED_STATE; + hdd_err("[P2P State] From Go nego completed to Non-autonomous Group started"); + } else if (global_p2p_connection_status == P2P_NOT_ACTIVE) { + global_p2p_connection_status = P2P_GO_COMPLETED_STATE; + hdd_err("[P2P State] From Inactive to Autonomous Group started"); + } + } +#endif + /* Check and restart SAP if it is on unsafe channel */ + hdd_unsafe_channel_restart_sap(pHddCtx); + + cds_set_connection_in_progress(false); + pHostapdState->bCommit = true; + EXIT(); + + return 0; + +error: + clear_bit(SOFTAP_INIT_DONE, &pHostapdAdapter->event_flags); + if (pHostapdAdapter->sessionCtx.ap.sapConfig.acs_cfg.ch_list) { + qdf_mem_free(pHostapdAdapter->sessionCtx.ap.sapConfig. + acs_cfg.ch_list); + pHostapdAdapter->sessionCtx.ap.sapConfig.acs_cfg.ch_list = NULL; + } + +ret_status: + if (disable_fw_tdls_state) + wlan_hdd_check_conc_and_update_tdls_state(pHddCtx, false); + return ret; +} + +/** + * __wlan_hdd_cfg80211_stop_ap() - stop soft ap + * @wiphy: Pointer to wiphy structure + * @dev: Pointer to net_device structure + * + * Return: 0 for success non-zero for failure + */ +static int __wlan_hdd_cfg80211_stop_ap(struct wiphy *wiphy, + struct net_device *dev) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *pHddCtx = wiphy_priv(wiphy); + hdd_scaninfo_t *pScanInfo = NULL; + hdd_adapter_t *staAdapter = NULL; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + QDF_STATUS qdf_status = QDF_STATUS_E_FAILURE; + tSirUpdateIE updateIE; + beacon_data_t *old; + int ret; + unsigned long rc; + hdd_adapter_list_node_t *pAdapterNode = NULL; + hdd_adapter_list_node_t *pNext = NULL; + tsap_Config_t *pConfig; + + ENTER(); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EINVAL; + } + + if (pHddCtx->driver_status == DRIVER_MODULES_CLOSED) { + hdd_err("Driver module is closed; dropping request"); + return -EINVAL; + } + + if (wlan_hdd_validate_session_id(pAdapter->sessionId)) { + hdd_err("invalid session id: %d", pAdapter->sessionId); + return -EINVAL; + } + + MTRACE(qdf_trace(QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_CFG80211_STOP_AP, + pAdapter->sessionId, pAdapter->device_mode)); + + if (!(pAdapter->device_mode == QDF_SAP_MODE || + pAdapter->device_mode == QDF_P2P_GO_MODE)) { + return -EOPNOTSUPP; + } + /* Clear SOFTAP_INIT_DONE flag to mark stop_ap deinit. So that we do + * not restart SAP after SSR as SAP is already stopped from user space. + * This update is moved to start of this function to resolve stop_ap + * call during SSR case. Adapter gets cleaned up as part of SSR. + */ + clear_bit(SOFTAP_INIT_DONE, &pAdapter->event_flags); + hdd_notice("Device_mode %s(%d)", + hdd_device_mode_to_string(pAdapter->device_mode), + pAdapter->device_mode); + + ret = wlan_hdd_validate_context(pHddCtx); + if (0 != ret) + return ret; + + if (pAdapter->device_mode == QDF_SAP_MODE) { + wlan_hdd_del_station(pAdapter); + hdd_green_ap_stop_bss(pHddCtx); + } + + status = hdd_get_front_adapter(pHddCtx, &pAdapterNode); + while (NULL != pAdapterNode && QDF_STATUS_SUCCESS == status) { + staAdapter = pAdapterNode->pAdapter; + + if (QDF_STA_MODE == staAdapter->device_mode || + (QDF_P2P_CLIENT_MODE == staAdapter->device_mode) || + (QDF_P2P_GO_MODE == staAdapter->device_mode)) { + pScanInfo = &staAdapter->scan_info; + + if (pScanInfo && pScanInfo->mScanPending) { + hdd_notice("Aborting pending scan for device mode:%d", + staAdapter->device_mode); + INIT_COMPLETION(pScanInfo->abortscan_event_var); + hdd_abort_mac_scan(staAdapter->pHddCtx, + staAdapter->sessionId, + INVALID_SCAN_ID, + eCSR_SCAN_ABORT_DEFAULT); + rc = wait_for_completion_timeout( + &pScanInfo->abortscan_event_var, + msecs_to_jiffies( + WLAN_WAIT_TIME_ABORTSCAN)); + if (!rc) { + hdd_err("Timeout occurred while waiting for abortscan"); + QDF_ASSERT(pScanInfo->mScanPending); + } + } + } + + status = hdd_get_next_adapter(pHddCtx, pAdapterNode, &pNext); + pAdapterNode = pNext; + } + /* + * When ever stop ap adapter gets called, we need to check + * whether any restart AP work is pending. If any restart is pending + * then lets finish it and go ahead from there. + */ + if (pHddCtx->config->conc_custom_rule1 && + (QDF_SAP_MODE == pAdapter->device_mode)) { + cds_flush_work(&pHddCtx->sap_start_work); + hdd_warn("Canceled the pending restart work"); + qdf_spin_lock(&pHddCtx->sap_update_info_lock); + pHddCtx->is_sap_restart_required = false; + qdf_spin_unlock(&pHddCtx->sap_update_info_lock); + } + + pConfig = &pAdapter->sessionCtx.ap.sapConfig; + pConfig->acs_cfg.acs_mode = false; + wlan_hdd_undo_acs(pAdapter); + qdf_mem_zero(&pConfig->acs_cfg, sizeof(struct sap_acs_cfg)); + + /* Remove the channel no from sap mandatory list if it is a + * 5GHz channel */ + if (CDS_IS_CHANNEL_5GHZ(pConfig->channel)) + cds_remove_sap_mandatory_chan(pConfig->channel); + + /* Stop all tx queues */ + hdd_notice("Disabling queues"); + wlan_hdd_netif_queue_control(pAdapter, + WLAN_STOP_ALL_NETIF_QUEUE_N_CARRIER, + WLAN_CONTROL_PATH); + + old = pAdapter->sessionCtx.ap.beacon; + if (!old) { + hdd_err("Session(%d) beacon data points to NULL", + pAdapter->sessionId); + return -EINVAL; + } + + hdd_cleanup_actionframe(pHddCtx, pAdapter); + wlan_hdd_cleanup_remain_on_channel_ctx(pAdapter); + + mutex_lock(&pHddCtx->sap_lock); + if (test_bit(SOFTAP_BSS_STARTED, &pAdapter->event_flags)) { + hdd_hostapd_state_t *pHostapdState = + WLAN_HDD_GET_HOSTAP_STATE_PTR(pAdapter); + + qdf_event_reset(&pHostapdState->qdf_stop_bss_event); + status = wlansap_stop_bss(WLAN_HDD_GET_SAP_CTX_PTR(pAdapter)); + if (QDF_IS_STATUS_SUCCESS(status)) { + qdf_status = + qdf_wait_single_event(&pHostapdState-> + qdf_stop_bss_event, + SME_CMD_TIMEOUT_VALUE); + + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + hdd_err("HDD qdf wait for single_event failed!!"); + QDF_ASSERT(0); + } + } + clear_bit(SOFTAP_BSS_STARTED, &pAdapter->event_flags); + /*BSS stopped, clear the active sessions for this device mode*/ + cds_decr_session_set_pcl(pAdapter->device_mode, + pAdapter->sessionId); + pAdapter->sessionCtx.ap.beacon = NULL; + qdf_mem_free(old); + } + mutex_unlock(&pHddCtx->sap_lock); + + if (wlan_sap_is_pre_cac_active(pHddCtx->hHal)) + hdd_clean_up_pre_cac_interface(pHddCtx); + + if (status != QDF_STATUS_SUCCESS) { + hdd_err("Stopping the BSS"); + return -EINVAL; + } + + qdf_copy_macaddr(&updateIE.bssid, &pAdapter->macAddressCurrent); + updateIE.smeSessionId = pAdapter->sessionId; + updateIE.ieBufferlength = 0; + updateIE.pAdditionIEBuffer = NULL; + updateIE.append = true; + updateIE.notify = true; + if (sme_update_add_ie(WLAN_HDD_GET_HAL_CTX(pAdapter), + &updateIE, + eUPDATE_IE_PROBE_BCN) == QDF_STATUS_E_FAILURE) { + hdd_err("Could not pass on PROBE_RSP_BCN data to PE"); + } + + if (sme_update_add_ie(WLAN_HDD_GET_HAL_CTX(pAdapter), + &updateIE, + eUPDATE_IE_ASSOC_RESP) == QDF_STATUS_E_FAILURE) { + hdd_err("Could not pass on ASSOC_RSP data to PE"); + } + /* Reset WNI_CFG_PROBE_RSP Flags */ + wlan_hdd_reset_prob_rspies(pAdapter); + +#ifdef WLAN_FEATURE_P2P_DEBUG + if ((pAdapter->device_mode == QDF_P2P_GO_MODE) && + (global_p2p_connection_status == P2P_GO_COMPLETED_STATE)) { + hdd_err("[P2P State] From GO completed to Inactive state GO got removed"); + global_p2p_connection_status = P2P_NOT_ACTIVE; + } +#endif + pAdapter->sessionId = HDD_SESSION_ID_INVALID; + wlan_hdd_check_conc_and_update_tdls_state(pHddCtx, false); + EXIT(); + return ret; +} + +/** + * wlan_hdd_get_channel_bw() - get channel bandwidth + * @width: input channel width in nl80211_chan_width value + * + * Return: channel width value defined by driver + */ +static enum hw_mode_bandwidth wlan_hdd_get_channel_bw( + enum nl80211_chan_width width) +{ + enum hw_mode_bandwidth ch_bw = HW_MODE_20_MHZ; + + switch (width) { + case NL80211_CHAN_WIDTH_20_NOHT: + case NL80211_CHAN_WIDTH_20: + ch_bw = HW_MODE_20_MHZ; + break; + case NL80211_CHAN_WIDTH_40: + ch_bw = HW_MODE_40_MHZ; + break; + case NL80211_CHAN_WIDTH_80: + ch_bw = HW_MODE_80_MHZ; + break; + case NL80211_CHAN_WIDTH_80P80: + ch_bw = HW_MODE_80_PLUS_80_MHZ; + break; + case NL80211_CHAN_WIDTH_160: + ch_bw = HW_MODE_160_MHZ; + break; + default: + hdd_err("Invalid width: %d, using default 20MHz", width); + break; + } + + return ch_bw; +} + +/** + * wlan_hdd_cfg80211_stop_ap() - stop sap + * @wiphy: Pointer to wiphy + * @dev: Pointer to netdev + * + * Return: zero for success non-zero for failure + */ +int wlan_hdd_cfg80211_stop_ap(struct wiphy *wiphy, + struct net_device *dev) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_stop_ap(wiphy, dev); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __wlan_hdd_cfg80211_start_ap() - start soft ap mode + * @wiphy: Pointer to wiphy structure + * @dev: Pointer to net_device structure + * @params: Pointer to AP settings parameters + * + * Return: 0 for success non-zero for failure + */ +static int __wlan_hdd_cfg80211_start_ap(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_ap_settings *params) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *pHddCtx; + enum hw_mode_bandwidth channel_width; + int status; + struct sme_sta_inactivity_timeout *sta_inactivity_timer; + uint8_t channel; + + ENTER(); + + clear_bit(SOFTAP_INIT_DONE, &pAdapter->event_flags); + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EINVAL; + } + + if (wlan_hdd_validate_session_id(pAdapter->sessionId)) { + hdd_err("invalid session id: %d", pAdapter->sessionId); + return -EINVAL; + } + + MTRACE(qdf_trace(QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_CFG80211_START_AP, pAdapter->sessionId, + params->beacon_interval)); + if (WLAN_HDD_ADAPTER_MAGIC != pAdapter->magic) { + hdd_err("HDD adapter magic is invalid"); + return -ENODEV; + } + + pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + status = wlan_hdd_validate_context(pHddCtx); + if (0 != status) + return status; + + hdd_info("pAdapter = %p, Device mode %s(%d) sub20 %d", + pAdapter, hdd_device_mode_to_string(pAdapter->device_mode), + pAdapter->device_mode, cds_is_sub_20_mhz_enabled()); + + if (cds_is_connection_in_progress(NULL, NULL)) { + hdd_err("Can't start BSS: connection is in progress"); + return -EBUSY; + } + + if (cds_is_hw_mode_change_in_progress()) { + status = qdf_wait_for_connection_update(); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("qdf wait for event failed!!"); + return -EINVAL; + } + } + + channel_width = wlan_hdd_get_channel_bw(params->chandef.width); + channel = ieee80211_frequency_to_channel( + params->chandef.chan->center_freq); + + if (cds_is_sap_mandatory_chan_list_enabled()) { + if (!cds_get_sap_mandatory_chan_list_len()) + cds_init_sap_mandatory_2g_chan(); + + if (CDS_IS_CHANNEL_5GHZ(channel)) { + hdd_debug("channel %hu, sap mandatory chan list enabled", + channel); + cds_add_sap_mandatory_chan(channel); + } + } + + if (cds_is_sub_20_mhz_enabled()) { + enum channel_state ch_state; + enum phy_ch_width sub_20_ch_width = CH_WIDTH_INVALID; + tsap_Config_t *sap_cfg = &pAdapter->sessionCtx.ap.sapConfig; + + /* Avoid ACS/DFS, and overwrite ch wd to 20 */ + if (channel == 0) { + hdd_err("Can't start SAP-ACS (channel=0) with sub 20 MHz ch width."); + return -EINVAL; + } + if (CHANNEL_STATE_DFS == cds_get_channel_state(channel)) { + hdd_err("Can't start SAP-DFS (channel=%d)with sub 20 MHz ch wd", + channel); + return -EINVAL; + } + if (channel_width != HW_MODE_20_MHZ) { + hdd_err("Hostapd (20+ MHz) conflits with config.ini (sub 20 MHz)"); + return -EINVAL; + } + if (cds_is_5_mhz_enabled()) + sub_20_ch_width = CH_WIDTH_5MHZ; + if (cds_is_10_mhz_enabled()) + sub_20_ch_width = CH_WIDTH_10MHZ; + if (CDS_IS_CHANNEL_5GHZ(channel)) + ch_state = cds_get_5g_bonded_channel_state(channel, + sub_20_ch_width); + else + ch_state = cds_get_2g_bonded_channel_state(channel, + sub_20_ch_width, 0); + if (CHANNEL_STATE_DISABLE == ch_state) { + hdd_err("Given ch width not supported by reg domain."); + return -EINVAL; + } + sap_cfg->SapHw_mode = eCSR_DOT11_MODE_abg; + } + + /* check if concurrency is allowed */ + if (!cds_allow_concurrency( + cds_convert_device_mode_to_qdf_type( + pAdapter->device_mode), + channel, + channel_width)) { + hdd_err("Connection failed due to concurrency check failure"); + return -EINVAL; + } + + status = qdf_reset_connection_update(); + if (!QDF_IS_STATUS_SUCCESS(status)) + hdd_err("ERR: clear event failed"); + + status = cds_current_connections_update(pAdapter->sessionId, + channel, + SIR_UPDATE_REASON_START_AP); + if (QDF_STATUS_E_FAILURE == status) { + hdd_err("ERROR: connections update failed!!"); + return -EINVAL; + } + + if (QDF_STATUS_SUCCESS == status) { + status = qdf_wait_for_connection_update(); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("ERROR: qdf wait for event failed!!"); + return -EINVAL; + } + } + + if (QDF_SAP_MODE == pAdapter->device_mode) + hdd_green_ap_start_bss(pHddCtx); + + if (pAdapter->device_mode == QDF_P2P_GO_MODE) { + hdd_adapter_t *p2p_adapter; + p2p_adapter = hdd_get_adapter(pHddCtx, QDF_P2P_DEVICE_MODE); + if (p2p_adapter) { + hdd_info("cancel active p2p device ROC before GO " + "starting"); + wlan_hdd_cancel_existing_remain_on_channel( + p2p_adapter); + } + } + + if ((pAdapter->device_mode == QDF_SAP_MODE) + || (pAdapter->device_mode == QDF_P2P_GO_MODE) + ) { + beacon_data_t *old, *new; + enum nl80211_channel_type channel_type; + + old = pAdapter->sessionCtx.ap.beacon; + + if (old) + return -EALREADY; + + status = + wlan_hdd_cfg80211_alloc_new_beacon(pAdapter, &new, + ¶ms->beacon, + params->dtim_period); + + if (status != 0) { + hdd_err("Error!!! Allocating the new beacon"); + return -EINVAL; + } + pAdapter->sessionCtx.ap.beacon = new; + + if (params->chandef.width < NL80211_CHAN_WIDTH_80) + channel_type = cfg80211_get_chandef_type( + &(params->chandef)); + else + channel_type = NL80211_CHAN_HT40PLUS; + + + wlan_hdd_set_channel(wiphy, dev, + ¶ms->chandef, + channel_type); + + /* set authentication type */ + switch (params->auth_type) { + case NL80211_AUTHTYPE_OPEN_SYSTEM: + pAdapter->sessionCtx.ap.sapConfig.authType = + eSAP_OPEN_SYSTEM; + break; + case NL80211_AUTHTYPE_SHARED_KEY: + pAdapter->sessionCtx.ap.sapConfig.authType = + eSAP_SHARED_KEY; + break; + default: + pAdapter->sessionCtx.ap.sapConfig.authType = + eSAP_AUTO_SWITCH; + } + pAdapter->sessionCtx.ap.sapConfig.ch_width_orig = + params->chandef.width; + status = + wlan_hdd_cfg80211_start_bss(pAdapter, + ¶ms->beacon, + params->ssid, params->ssid_len, + params->hidden_ssid, true, false); + + if (status != 0) { + hdd_err("Error Start bss Failed"); + goto err_start_bss; + } + + if (pHddCtx->config->sap_max_inactivity_override) { + sta_inactivity_timer = qdf_mem_malloc( + sizeof(*sta_inactivity_timer)); + if (!sta_inactivity_timer) { + hdd_err("Failed to allocate Memory"); + return QDF_STATUS_E_FAILURE; + } + sta_inactivity_timer->session_id = pAdapter->sessionId; + sta_inactivity_timer->sta_inactivity_timeout = + params->inactivity_timeout; + sme_update_sta_inactivity_timeout(WLAN_HDD_GET_HAL_CTX + (pAdapter), sta_inactivity_timer); + } + + if (status == 0) { + if (0 != + wlan_hdd_set_udp_resp_offload(pAdapter, true)) + hdd_notice("set udp resp cmd failed %d", + status); + } + } + + goto success; + +err_start_bss: + if (pAdapter->sessionCtx.ap.beacon) + qdf_mem_free(pAdapter->sessionCtx.ap.beacon); + pAdapter->sessionCtx.ap.beacon = NULL; +success: + EXIT(); + return status; +} + +/** + * wlan_hdd_cfg80211_start_ap() - start sap + * @wiphy: Pointer to wiphy + * @dev: Pointer to netdev + * @params: Pointer to start ap configuration parameters + * + * Return: zero for success non-zero for failure + */ +int wlan_hdd_cfg80211_start_ap(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_ap_settings *params) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_start_ap(wiphy, dev, params); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __wlan_hdd_cfg80211_change_beacon() - change beacon for sofatap/p2p go + * @wiphy: Pointer to wiphy structure + * @dev: Pointer to net_device structure + * @params: Pointer to change beacon parameters + * + * Return: 0 for success non-zero for failure + */ +static int __wlan_hdd_cfg80211_change_beacon(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_beacon_data *params) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *pHddCtx; + beacon_data_t *old, *new; + int status; + + ENTER(); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EINVAL; + } + + if (wlan_hdd_validate_session_id(pAdapter->sessionId)) { + hdd_err("invalid session id: %d", pAdapter->sessionId); + return -EINVAL; + } + + MTRACE(qdf_trace(QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_CFG80211_CHANGE_BEACON, + pAdapter->sessionId, pAdapter->device_mode)); + hdd_notice("Device_mode %s(%d)", + hdd_device_mode_to_string(pAdapter->device_mode), + pAdapter->device_mode); + + pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + status = wlan_hdd_validate_context(pHddCtx); + + if (0 != status) + return status; + + if (!(pAdapter->device_mode == QDF_SAP_MODE || + pAdapter->device_mode == QDF_P2P_GO_MODE)) { + return -EOPNOTSUPP; + } + + old = pAdapter->sessionCtx.ap.beacon; + + if (!old) { + hdd_err("session(%d) beacon data points to NULL", + pAdapter->sessionId); + return -EINVAL; + } + + status = wlan_hdd_cfg80211_alloc_new_beacon(pAdapter, &new, params, 0); + + if (status != QDF_STATUS_SUCCESS) { + hdd_err("new beacon alloc failed"); + return -EINVAL; + } + + pAdapter->sessionCtx.ap.beacon = new; + hdd_debug("update beacon for P2P GO/SAP"); + status = wlan_hdd_cfg80211_start_bss(pAdapter, params, NULL, + 0, 0, false, true); + + EXIT(); + return status; +} + +/** + * wlan_hdd_cfg80211_change_beacon() - change beacon content in sap mode + * @wiphy: Pointer to wiphy + * @dev: Pointer to netdev + * @params: Pointer to change beacon parameters + * + * Return: zero for success non-zero for failure + */ +int wlan_hdd_cfg80211_change_beacon(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_beacon_data *params) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_change_beacon(wiphy, dev, params); + cds_ssr_unprotect(__func__); + + return ret; +} + +bool hdd_is_peer_associated(hdd_adapter_t *adapter, + struct qdf_mac_addr *mac_addr) +{ + uint32_t cnt = 0; + hdd_station_info_t *sta_info = NULL; + + if (!adapter || !mac_addr) { + hdd_err("Invalid adapter or mac_addr"); + return false; + } + + sta_info = adapter->aStaInfo; + spin_lock_bh(&adapter->staInfo_lock); + for (cnt = 0; cnt < WLAN_MAX_STA_COUNT; cnt++) { + if ((sta_info[cnt].isUsed) && + !qdf_mem_cmp(&(sta_info[cnt].macAddrSTA), mac_addr, + QDF_MAC_ADDR_SIZE)) + break; + } + spin_unlock_bh(&adapter->staInfo_lock); + if (cnt != WLAN_MAX_STA_COUNT) + return true; + + return false; +} + +/** + * hdd_sap_indicate_disconnect_for_sta() - Indicate disconnect indication + * to supplicant, if there any clients connected to SAP interface. + * @adapter: sap adapter context + * + * Return: nothing + */ +void hdd_sap_indicate_disconnect_for_sta(hdd_adapter_t *adapter) +{ + tSap_Event sap_event; + int sta_id; + ptSapContext sap_ctx; + + ENTER(); + + sap_ctx = WLAN_HDD_GET_SAP_CTX_PTR(adapter); + if (!sap_ctx) { + hdd_err("invalid sap context"); + return; + } + + for (sta_id = 0; sta_id < WLAN_MAX_STA_COUNT; sta_id++) { + if (adapter->aStaInfo[sta_id].isUsed) { + hdd_info("sta_id: %d isUsed: %d %p", + sta_id, adapter->aStaInfo[sta_id].isUsed, + adapter); + + if (qdf_is_macaddr_broadcast( + &adapter->aStaInfo[sta_id].macAddrSTA)) + continue; + + sap_event.sapHddEventCode = eSAP_STA_DISASSOC_EVENT; + qdf_mem_copy( + &sap_event.sapevt. + sapStationDisassocCompleteEvent.staMac, + &adapter->aStaInfo[sta_id].macAddrSTA, + sizeof(struct qdf_mac_addr)); + sap_event.sapevt.sapStationDisassocCompleteEvent. + reason = + eSAP_MAC_INITATED_DISASSOC; + sap_event.sapevt.sapStationDisassocCompleteEvent. + statusCode = + QDF_STATUS_E_RESOURCES; + hdd_hostapd_sap_event_cb(&sap_event, + sap_ctx->pUsrContext); + } + } + + EXIT(); +} + +/** + * hdd_sap_destroy_events() - Destroy sap evets + * @adapter: sap adapter context + * + * Return: nothing + */ +void hdd_sap_destroy_events(hdd_adapter_t *adapter) +{ + ptSapContext sap_ctx; + + ENTER(); + sap_ctx = WLAN_HDD_GET_SAP_CTX_PTR(adapter); + if (!sap_ctx) { + hdd_err("invalid sap context"); + return; + } + + qdf_event_destroy(&sap_ctx->sap_session_opened_evt); + if (!QDF_IS_STATUS_SUCCESS( + qdf_mutex_destroy(&sap_ctx->SapGlobalLock))) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "wlansap_stop failed destroy lock"); + return; + } + EXIT(); +} diff --git a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_hostapd.h b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_hostapd.h new file mode 100644 index 0000000000000000000000000000000000000000..7e65d498528e216dcc97908402db6f135ee1212b --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_hostapd.h @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2013-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#if !defined(WLAN_HDD_HOSTAPD_H) +#define WLAN_HDD_HOSTAPD_H + +/** + * DOC: wlan_hdd_hostapd.h + * + * WLAN Host Device driver hostapd header file + */ + +/* Include files */ + +#include +#include +#include +#include +#include + +/* Preprocessor definitions and constants */ + +/* max length of command string in hostapd ioctl */ +#define HOSTAPD_IOCTL_COMMAND_STRLEN_MAX 8192 + +hdd_adapter_t *hdd_wlan_create_ap_dev(hdd_context_t *pHddCtx, + tSirMacAddr macAddr, + unsigned char name_assign_type, + uint8_t *name); + +QDF_STATUS hdd_register_hostapd(hdd_adapter_t *pAdapter, uint8_t rtnl_held); + +int hdd_unregister_hostapd(hdd_adapter_t *pAdapter, bool rtnl_held); + +eCsrAuthType +hdd_translate_rsn_to_csr_auth_type(uint8_t auth_suite[4]); + +int hdd_softap_set_channel_change(struct net_device *dev, + int target_channel, + enum phy_ch_width target_bw); + +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH +void hdd_sap_restart_with_channel_switch(hdd_adapter_t *adapter, + uint32_t target_channel, + uint32_t target_bw); +#endif + +eCsrEncryptionType +hdd_translate_rsn_to_csr_encryption_type(uint8_t cipher_suite[4]); + +eCsrEncryptionType +hdd_translate_rsn_to_csr_encryption_type(uint8_t cipher_suite[4]); + +eCsrAuthType +hdd_translate_wpa_to_csr_auth_type(uint8_t auth_suite[4]); + +eCsrEncryptionType +hdd_translate_wpa_to_csr_encryption_type(uint8_t cipher_suite[4]); + +QDF_STATUS hdd_softap_sta_deauth(hdd_adapter_t *, + struct tagCsrDelStaParams *); +void hdd_softap_sta_disassoc(hdd_adapter_t *, struct tagCsrDelStaParams *); +void hdd_softap_tkip_mic_fail_counter_measure(hdd_adapter_t *, bool); +int hdd_softap_unpack_ie(tHalHandle halHandle, + eCsrEncryptionType *pEncryptType, + eCsrEncryptionType *mcEncryptType, + eCsrAuthType *pAuthType, + bool *pMFPCapable, + bool *pMFPRequired, + uint16_t gen_ie_len, uint8_t *gen_ie); + +QDF_STATUS hdd_hostapd_sap_event_cb(tpSap_Event pSapEvent, + void *usrDataForCallback); +QDF_STATUS hdd_init_ap_mode(hdd_adapter_t *pAdapter, bool reinit); +void hdd_set_ap_ops(struct net_device *pWlanHostapdDev); +int hdd_hostapd_stop(struct net_device *dev); +int hdd_sap_context_init(hdd_context_t *hdd_ctx); +void hdd_sap_context_destroy(hdd_context_t *hdd_ctx); +#ifdef FEATURE_WLAN_FORCE_SAP_SCC +void hdd_restart_softap(hdd_context_t *pHddCtx, hdd_adapter_t *pAdapter); +#endif /* FEATURE_WLAN_FORCE_SAP_SCC */ +#ifdef QCA_HT_2040_COEX +QDF_STATUS hdd_set_sap_ht2040_mode(hdd_adapter_t *pHostapdAdapter, + uint8_t channel_type); +#endif + + +int wlan_hdd_cfg80211_stop_ap(struct wiphy *wiphy, + struct net_device *dev); + +int wlan_hdd_cfg80211_start_ap(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_ap_settings *params); + +int wlan_hdd_cfg80211_change_beacon(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_beacon_data *params); + +QDF_STATUS wlan_hdd_config_acs(hdd_context_t *hdd_ctx, hdd_adapter_t *adapter); + +/** + * hdd_is_peer_associated - is peer connected to softap + * @adapter: pointer to softap adapter + * @mac_addr: address to check in peer list + * + * This function has to be invoked only when bss is started and is used + * to check whether station with specified addr is peer or not + * + * Return: true if peer mac, else false + */ +bool hdd_is_peer_associated(hdd_adapter_t *adapter, + struct qdf_mac_addr *mac_addr); +void hdd_sap_indicate_disconnect_for_sta(hdd_adapter_t *adapter); +void hdd_sap_destroy_events(hdd_adapter_t *adapter); +#endif /* end #if !defined(WLAN_HDD_HOSTAPD_H) */ diff --git a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_ioctl.c b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_ioctl.c new file mode 100644 index 0000000000000000000000000000000000000000..d1fa6514ea45c643a14acecf2d8d085a1fd82ac5 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_ioctl.c @@ -0,0 +1,7224 @@ +/* + * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* Include Files */ + +#include +#include +#include "wlan_hdd_trace.h" +#include "wlan_hdd_ioctl.h" +#include "wlan_hdd_power.h" +#include "wlan_hdd_driver_ops.h" +#include "cds_concurrency.h" +#include "wlan_hdd_hostapd.h" + +#include "wlan_hdd_p2p.h" +#include +#include "wma.h" +#include "wlan_hdd_napi.h" + +#ifdef FEATURE_WLAN_ESE +#include +#include +#endif +#include "hif.h" + +#if defined(LINUX_QCMBR) +#define SIOCIOCTLTX99 (SIOCDEVPRIVATE+13) +#endif + +/* + * Size of Driver command strings from upper layer + */ +#define SIZE_OF_SETROAMMODE 11 /* size of SETROAMMODE */ +#define SIZE_OF_GETROAMMODE 11 /* size of GETROAMMODE */ + +/* + * Ibss prop IE from command will be of size: + * size = sizeof(oui) + sizeof(oui_data) + 1(Element ID) + 1(EID Length) + * OUI_DATA should be at least 3 bytes long + */ +#define WLAN_HDD_IBSS_MIN_OUI_DATA_LENGTH (3) + +#ifdef FEATURE_WLAN_ESE +#define TID_MIN_VALUE 0 +#define TID_MAX_VALUE 15 +#endif /* FEATURE_WLAN_ESE */ + +/* + * Maximum buffer size used for returning the data back to user space + */ +#define WLAN_MAX_BUF_SIZE 1024 +#define WLAN_PRIV_DATA_MAX_LEN 8192 + +/* + * Driver miracast parameters 0-Disabled + * 1-Source, 2-Sink + */ +#define WLAN_HDD_DRIVER_MIRACAST_CFG_MIN_VAL 0 +#define WLAN_HDD_DRIVER_MIRACAST_CFG_MAX_VAL 2 + +/* + * When ever we need to print IBSSPEERINFOALL for more than 16 STA + * we will split the printing. + */ +#define NUM_OF_STA_DATA_TO_PRINT 16 + +/* + * Android DRIVER command structures + */ +struct android_wifi_reassoc_params { + unsigned char bssid[18]; + int channel; +}; + +#define ANDROID_WIFI_ACTION_FRAME_SIZE 1040 +struct android_wifi_af_params { + unsigned char bssid[18]; + int channel; + int dwell_time; + int len; + unsigned char data[ANDROID_WIFI_ACTION_FRAME_SIZE]; +}; + +/* + * Define HDD driver command handling entry, each contains a command + * string and the handler. + */ +typedef int (*hdd_drv_cmd_handler_t)(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *cmd, + uint8_t cmd_name_len, + hdd_priv_data_t *priv_data); + +typedef struct { + const char *cmd; + hdd_drv_cmd_handler_t handler; +} hdd_drv_cmd_t; + +#ifdef WLAN_FEATURE_EXTWOW_SUPPORT +#define WLAN_WAIT_TIME_READY_TO_EXTWOW 2000 +#define WLAN_HDD_MAX_TCP_PORT 65535 +#endif + +static uint16_t cesium_pid; +extern struct sock *cesium_nl_srv_sock; + +#ifdef FEATURE_WLAN_ESE +static void hdd_get_tsm_stats_cb(tAniTrafStrmMetrics tsm_metrics, + const uint32_t staId, void *context) +{ + struct statsContext *stats_context = NULL; + hdd_adapter_t *adapter = NULL; + + if (NULL == context) { + hdd_err("Bad param, context [%p]", context); + 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); + + stats_context = context; + adapter = stats_context->pAdapter; + if ((NULL == adapter) || + (STATS_CONTEXT_MAGIC != stats_context->magic)) { + /* + * the caller presumably timed out so there is + * nothing we can do + */ + spin_unlock(&hdd_context_lock); + hdd_warn("Invalid context, adapter [%p] magic [%08x]", + adapter, stats_context->magic); + return; + } + + /* context is valid so caller is still waiting */ + + /* paranoia: invalidate the magic */ + stats_context->magic = 0; + + /* copy over the tsm stats */ + adapter->tsmStats.UplinkPktQueueDly = tsm_metrics.UplinkPktQueueDly; + qdf_mem_copy(adapter->tsmStats.UplinkPktQueueDlyHist, + tsm_metrics.UplinkPktQueueDlyHist, + sizeof(adapter->tsmStats.UplinkPktQueueDlyHist) / + sizeof(adapter->tsmStats.UplinkPktQueueDlyHist[0])); + adapter->tsmStats.UplinkPktTxDly = tsm_metrics.UplinkPktTxDly; + adapter->tsmStats.UplinkPktLoss = tsm_metrics.UplinkPktLoss; + adapter->tsmStats.UplinkPktCount = tsm_metrics.UplinkPktCount; + adapter->tsmStats.RoamingCount = tsm_metrics.RoamingCount; + adapter->tsmStats.RoamingDly = tsm_metrics.RoamingDly; + + /* notify the caller */ + complete(&stats_context->completion); + + /* serialization is complete */ + spin_unlock(&hdd_context_lock); +} + +static +QDF_STATUS hdd_get_tsm_stats(hdd_adapter_t *adapter, + const uint8_t tid, + tAniTrafStrmMetrics *tsm_metrics) +{ + hdd_station_ctx_t *hdd_sta_ctx = NULL; + QDF_STATUS hstatus; + QDF_STATUS vstatus = QDF_STATUS_SUCCESS; + unsigned long rc; + static struct statsContext context; + hdd_context_t *hdd_ctx = NULL; + + if (NULL == adapter) { + hdd_err("adapter is NULL"); + return QDF_STATUS_E_FAULT; + } + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + + /* we are connected prepare our callback context */ + init_completion(&context.completion); + context.pAdapter = adapter; + context.magic = STATS_CONTEXT_MAGIC; + + /* query tsm stats */ + hstatus = sme_get_tsm_stats(hdd_ctx->hHal, hdd_get_tsm_stats_cb, + hdd_sta_ctx->conn_info.staId[0], + hdd_sta_ctx->conn_info.bssId, + &context, hdd_ctx->pcds_context, tid); + if (QDF_STATUS_SUCCESS != hstatus) { + hdd_err("Unable to retrieve statistics"); + vstatus = QDF_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) { + hdd_err("SME timed out while retrieving statistics"); + vstatus = QDF_STATUS_E_TIMEOUT; + } + } + + /* + * 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 (QDF_STATUS_SUCCESS == vstatus) { + tsm_metrics->UplinkPktQueueDly = + adapter->tsmStats.UplinkPktQueueDly; + qdf_mem_copy(tsm_metrics->UplinkPktQueueDlyHist, + adapter->tsmStats.UplinkPktQueueDlyHist, + sizeof(adapter->tsmStats.UplinkPktQueueDlyHist) / + sizeof(adapter->tsmStats. + UplinkPktQueueDlyHist[0])); + tsm_metrics->UplinkPktTxDly = adapter->tsmStats.UplinkPktTxDly; + tsm_metrics->UplinkPktLoss = adapter->tsmStats.UplinkPktLoss; + tsm_metrics->UplinkPktCount = adapter->tsmStats.UplinkPktCount; + tsm_metrics->RoamingCount = adapter->tsmStats.RoamingCount; + tsm_metrics->RoamingDly = adapter->tsmStats.RoamingDly; + } + return vstatus; +} +#endif /*FEATURE_WLAN_ESE */ + +/* Function header is left blank intentionally */ +static int hdd_parse_setrmcenable_command(uint8_t *pValue, + uint8_t *pRmcEnable) +{ + uint8_t *inPtr = pValue; + int tempInt; + int v = 0; + char buf[32]; + *pRmcEnable = 0; + + inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE); + + if (NULL == inPtr) { + return 0; + } + + else if (SPACE_ASCII_VALUE != *inPtr) { + return 0; + } + + while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr)) + inPtr++; + + if ('\0' == *inPtr) { + return 0; + } + + sscanf(inPtr, "%32s ", buf); + v = kstrtos32(buf, 10, &tempInt); + if (v < 0) { + return -EINVAL; + } + + *pRmcEnable = tempInt; + + hdd_info("ucRmcEnable: %d", *pRmcEnable); + + return 0; +} + +/* Function header is left blank intentionally */ +static int hdd_parse_setrmcactionperiod_command(uint8_t *pValue, + uint32_t *pActionPeriod) +{ + uint8_t *inPtr = pValue; + int tempInt; + int v = 0; + char buf[32]; + *pActionPeriod = 0; + + inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE); + + if (NULL == inPtr) { + return -EINVAL; + } + + else if (SPACE_ASCII_VALUE != *inPtr) { + return -EINVAL; + } + + while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr)) + inPtr++; + + if ('\0' == *inPtr) { + return 0; + } + + sscanf(inPtr, "%32s ", buf); + v = kstrtos32(buf, 10, &tempInt); + if (v < 0) { + return -EINVAL; + } + + if ((tempInt < WNI_CFG_RMC_ACTION_PERIOD_FREQUENCY_STAMIN) || + (tempInt > WNI_CFG_RMC_ACTION_PERIOD_FREQUENCY_STAMAX)) { + return -EINVAL; + } + + *pActionPeriod = tempInt; + + hdd_info("uActionPeriod: %d", *pActionPeriod); + + return 0; +} + +/* Function header is left blank intentionally */ +static int hdd_parse_setrmcrate_command(uint8_t *pValue, + uint32_t *pRate, + tTxrateinfoflags *pTxFlags) +{ + uint8_t *inPtr = pValue; + int tempInt; + int v = 0; + char buf[32]; + *pRate = 0; + *pTxFlags = 0; + + inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE); + + if (NULL == inPtr) { + return -EINVAL; + } + + else if (SPACE_ASCII_VALUE != *inPtr) { + return -EINVAL; + } + + while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr)) + inPtr++; + + if ('\0' == *inPtr) { + return 0; + } + + sscanf(inPtr, "%31s ", buf); + v = kstrtos32(buf, 10, &tempInt); + if (v < 0) { + return -EINVAL; + } + + switch (tempInt) { + default: + hdd_warn("Unsupported rate: %d", tempInt); + return -EINVAL; + case 0: + case 6: + case 9: + case 12: + case 18: + case 24: + case 36: + case 48: + case 54: + *pTxFlags = eHAL_TX_RATE_LEGACY; + *pRate = tempInt * 10; + break; + case 65: + *pTxFlags = eHAL_TX_RATE_HT20; + *pRate = tempInt * 10; + break; + case 72: + *pTxFlags = eHAL_TX_RATE_HT20 | eHAL_TX_RATE_SGI; + *pRate = 722; + break; + } + + hdd_info("Rate: %d", *pRate); + + return 0; +} + +/** + * hdd_get_ibss_peer_info_cb() - IBSS peer Info request callback + * @UserData: Adapter private data + * @pPeerInfoRsp: Peer info response + * + * This is an asynchronous callback function from SME when the peer info + * is received + * + * Return: 0 for success non-zero for failure + */ +void +hdd_get_ibss_peer_info_cb(void *pUserData, + tSirPeerInfoRspParams *pPeerInfo) +{ + hdd_adapter_t *adapter = (hdd_adapter_t *) pUserData; + hdd_station_ctx_t *pStaCtx; + uint8_t i; + + /* Sanity check */ + if ((NULL == adapter) || + (WLAN_HDD_ADAPTER_MAGIC != adapter->magic)) { + hdd_alert("invalid adapter or adapter has invalid magic"); + return; + } + + pStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + if (NULL != pPeerInfo && QDF_STATUS_SUCCESS == pPeerInfo->status) { + /* validate number of peers */ + if (pPeerInfo->numPeers > SIR_MAX_NUM_STA_IN_IBSS) { + hdd_warn("Limiting num_peers %u to %u", + pPeerInfo->numPeers, SIR_MAX_NUM_STA_IN_IBSS); + pPeerInfo->numPeers = SIR_MAX_NUM_STA_IN_IBSS; + } + pStaCtx->ibss_peer_info.status = pPeerInfo->status; + pStaCtx->ibss_peer_info.numPeers = pPeerInfo->numPeers; + + for (i = 0; i < pPeerInfo->numPeers; i++) + pStaCtx->ibss_peer_info.peerInfoParams[i] = + pPeerInfo->peerInfoParams[i]; + } else { + hdd_err("peerInfo %s: status %u, numPeers %u", + pPeerInfo ? "valid" : "null", + pPeerInfo ? pPeerInfo->status : QDF_STATUS_E_FAILURE, + pPeerInfo ? pPeerInfo->numPeers : 0); + pStaCtx->ibss_peer_info.numPeers = 0; + pStaCtx->ibss_peer_info.status = QDF_STATUS_E_FAILURE; + } + + complete(&adapter->ibss_peer_info_comp); +} + +/** + * hdd_cfg80211_get_ibss_peer_info_all() - get ibss peers' info + * @adapter: Adapter context + * + * Request function to get IBSS peer info from lower layers + * + * Return: 0 for success non-zero for failure + */ +static +QDF_STATUS hdd_cfg80211_get_ibss_peer_info_all(hdd_adapter_t *adapter) +{ + tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(adapter); + QDF_STATUS retStatus = QDF_STATUS_E_FAILURE; + unsigned long rc; + + INIT_COMPLETION(adapter->ibss_peer_info_comp); + + retStatus = sme_request_ibss_peer_info(hHal, adapter, + hdd_get_ibss_peer_info_cb, + true, 0xFF); + + if (QDF_STATUS_SUCCESS == retStatus) { + rc = wait_for_completion_timeout + (&adapter->ibss_peer_info_comp, + msecs_to_jiffies(IBSS_PEER_INFO_REQ_TIMOEUT)); + + /* status will be 0 if timed out */ + if (!rc) { + hdd_warn("Warning: IBSS_PEER_INFO_TIMEOUT"); + retStatus = QDF_STATUS_E_FAILURE; + return retStatus; + } + } else { + hdd_warn("Warning: sme_request_ibss_peer_info Request failed"); + } + + return retStatus; +} + +/** + * hdd_cfg80211_get_ibss_peer_info() - get ibss peer info + * @adapter: Adapter context + * @staIdx: Sta index for which the peer info is requested + * + * Request function to get IBSS peer info from lower layers + * + * Return: 0 for success non-zero for failure + */ +static QDF_STATUS +hdd_cfg80211_get_ibss_peer_info(hdd_adapter_t *adapter, uint8_t staIdx) +{ + unsigned long rc; + tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(adapter); + QDF_STATUS retStatus = QDF_STATUS_E_FAILURE; + + INIT_COMPLETION(adapter->ibss_peer_info_comp); + + retStatus = sme_request_ibss_peer_info(hHal, adapter, + hdd_get_ibss_peer_info_cb, + false, staIdx); + + if (QDF_STATUS_SUCCESS == retStatus) { + rc = wait_for_completion_timeout( + &adapter->ibss_peer_info_comp, + msecs_to_jiffies(IBSS_PEER_INFO_REQ_TIMOEUT)); + + /* status = 0 on timeout */ + if (!rc) { + hdd_warn("Warning: IBSS_PEER_INFO_TIMEOUT"); + retStatus = QDF_STATUS_E_FAILURE; + return retStatus; + } + } else { + hdd_warn("Warning: sme_request_ibss_peer_info Request failed"); + } + + return retStatus; +} + +/* Function header is left blank intentionally */ +static QDF_STATUS +hdd_parse_get_ibss_peer_info(uint8_t *pValue, struct qdf_mac_addr *pPeerMacAddr) +{ + uint8_t *inPtr = pValue; + inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE); + + if (NULL == inPtr) { + return QDF_STATUS_E_FAILURE;; + } + + else if (SPACE_ASCII_VALUE != *inPtr) { + return QDF_STATUS_E_FAILURE;; + } + + while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr)) + inPtr++; + + if ('\0' == *inPtr) { + return QDF_STATUS_E_FAILURE;; + } + + if (inPtr[2] != ':' || inPtr[5] != ':' || inPtr[8] != ':' || + inPtr[11] != ':' || inPtr[14] != ':') { + return QDF_STATUS_E_FAILURE;; + } + sscanf(inPtr, "%2x:%2x:%2x:%2x:%2x:%2x", + (unsigned int *)&pPeerMacAddr->bytes[0], + (unsigned int *)&pPeerMacAddr->bytes[1], + (unsigned int *)&pPeerMacAddr->bytes[2], + (unsigned int *)&pPeerMacAddr->bytes[3], + (unsigned int *)&pPeerMacAddr->bytes[4], + (unsigned int *)&pPeerMacAddr->bytes[5]); + + return QDF_STATUS_SUCCESS; +} + +static void hdd_get_band_helper(hdd_context_t *hdd_ctx, int *pBand) +{ + eCsrBand band = -1; + sme_get_freq_band((tHalHandle) (hdd_ctx->hHal), &band); + switch (band) { + case eCSR_BAND_ALL: + *pBand = WLAN_HDD_UI_BAND_AUTO; + break; + + case eCSR_BAND_24: + *pBand = WLAN_HDD_UI_BAND_2_4_GHZ; + break; + + case eCSR_BAND_5G: + *pBand = WLAN_HDD_UI_BAND_5_GHZ; + break; + + default: + hdd_warn("Invalid Band %d", band); + *pBand = -1; + break; + } +} + +/** + * _hdd_parse_bssid_and_chan() - helper function to parse bssid and channel + * @data: input data + * @target_ap_bssid: pointer to bssid (output parameter) + * @channel: pointer to channel (output parameter) + * + * Return: 0 if parsing is successful; -EINVAL otherwise + */ +static int _hdd_parse_bssid_and_chan(const uint8_t **data, + uint8_t *bssid, + uint8_t *channel) +{ + const uint8_t *in_ptr; + int v = 0; + int temp_int; + uint8_t temp_buf[32]; + + /* 12 hexa decimal digits, 5 ':' and '\0' */ + uint8_t mac_addr[18]; + + if (!data || !*data) + return -EINVAL; + + in_ptr = *data; + + in_ptr = strnchr(in_ptr, strlen(in_ptr), SPACE_ASCII_VALUE); + /* no argument after the command */ + if (NULL == in_ptr) + goto error; + /* no space after the command */ + else if (SPACE_ASCII_VALUE != *in_ptr) + goto error; + + /* remove empty spaces */ + while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr)) + in_ptr++; + + /* no argument followed by spaces */ + if ('\0' == *in_ptr) + goto error; + + v = sscanf(in_ptr, "%17s", mac_addr); + if (!((1 == v) && hdd_is_valid_mac_address(mac_addr))) { + hdd_err("Invalid MAC address or All hex inputs are not read (%d)", + v); + goto error; + } + + bssid[0] = hex_to_bin(mac_addr[0]) << 4 | + hex_to_bin(mac_addr[1]); + bssid[1] = hex_to_bin(mac_addr[3]) << 4 | + hex_to_bin(mac_addr[4]); + bssid[2] = hex_to_bin(mac_addr[6]) << 4 | + hex_to_bin(mac_addr[7]); + bssid[3] = hex_to_bin(mac_addr[9]) << 4 | + hex_to_bin(mac_addr[10]); + bssid[4] = hex_to_bin(mac_addr[12]) << 4 | + hex_to_bin(mac_addr[13]); + bssid[5] = hex_to_bin(mac_addr[15]) << 4 | + hex_to_bin(mac_addr[16]); + + /* point to the next argument */ + in_ptr = strnchr(in_ptr, strlen(in_ptr), SPACE_ASCII_VALUE); + /* no argument after the command */ + if (NULL == in_ptr) + goto error; + + /* remove empty spaces */ + while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr)) + in_ptr++; + + /* no argument followed by spaces */ + if ('\0' == *in_ptr) + goto error; + + /* get the next argument ie the channel number */ + v = sscanf(in_ptr, "%31s ", temp_buf); + if (1 != v) + goto error; + + v = kstrtos32(temp_buf, 10, &temp_int); + if ((v < 0) || (temp_int < 0) || + (temp_int > WNI_CFG_CURRENT_CHANNEL_STAMAX)) + return -EINVAL; + + *channel = temp_int; + *data = in_ptr; + return 0; +error: + *data = in_ptr; + return -EINVAL; +} + +/** + * hdd_parse_send_action_frame_data() - HDD Parse send action frame data + * @pValue: Pointer to input data + * @pTargetApBssid: Pointer to target Ap bssid + * @pChannel: Pointer to the Target AP channel + * @pDwellTime: Pointer to the time to stay off-channel + * after transmitting action frame + * @pBuf: Pointer to data + * @pBufLen: Pointer to data length + * + * This function parses the send action frame data passed in the format + * SENDACTIONFRAME + * + * Return: 0 for success non-zero for failure + */ +static int +hdd_parse_send_action_frame_v1_data(const uint8_t *pValue, + uint8_t *pTargetApBssid, + uint8_t *pChannel, uint8_t *pDwellTime, + uint8_t **pBuf, uint8_t *pBufLen) +{ + const uint8_t *inPtr = pValue; + const uint8_t *dataEnd; + int tempInt; + int j = 0; + int i = 0; + int v = 0; + uint8_t tempBuf[32]; + uint8_t tempByte = 0; + + if (_hdd_parse_bssid_and_chan(&inPtr, pTargetApBssid, pChannel)) + return -EINVAL; + + /* point to the next argument */ + inPtr = strnchr(inPtr, strlen(inPtr), SPACE_ASCII_VALUE); + /* no argument after the command */ + if (NULL == inPtr) + return -EINVAL; + /* removing empty spaces */ + while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr)) + inPtr++; + + /* no argument followed by spaces */ + if ('\0' == *inPtr) { + return -EINVAL; + } + + /* getting the next argument ie the dwell time */ + v = sscanf(inPtr, "%31s ", tempBuf); + if (1 != v) + return -EINVAL; + + v = kstrtos32(tempBuf, 10, &tempInt); + if (v < 0 || tempInt < 0) + return -EINVAL; + + *pDwellTime = tempInt; + + /* point to the next argument */ + inPtr = strnchr(inPtr, strlen(inPtr), SPACE_ASCII_VALUE); + /* no argument after the command */ + if (NULL == inPtr) + return -EINVAL; + /* removing empty spaces */ + while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr)) + inPtr++; + + /* no argument followed by spaces */ + if ('\0' == *inPtr) { + return -EINVAL; + } + + /* find the length of data */ + dataEnd = inPtr; + while (('\0' != *dataEnd)) { + dataEnd++; + } + *pBufLen = dataEnd - inPtr; + if (*pBufLen <= 0) + return -EINVAL; + + /* + * Allocate the number of bytes based on the number of input characters + * whether it is even or odd. + * if the number of input characters are even, then we need N/2 byte. + * if the number of input characters are odd, then we need do (N+1)/2 + * to compensate rounding off. + * For example, if N = 18, then (18 + 1)/2 = 9 bytes are enough. + * If N = 19, then we need 10 bytes, hence (19 + 1)/2 = 10 bytes + */ + *pBuf = qdf_mem_malloc((*pBufLen + 1) / 2); + if (NULL == *pBuf) { + hdd_err("qdf_mem_malloc failed"); + return -ENOMEM; + } + + /* the buffer received from the upper layer is character buffer, + * we need to prepare the buffer taking 2 characters in to a U8 hex + * decimal number for example 7f0000f0...form a buffer to contain 7f + * in 0th location, 00 in 1st and f0 in 3rd location + */ + for (i = 0, j = 0; j < *pBufLen; j += 2) { + if (j + 1 == *pBufLen) { + tempByte = hex_to_bin(inPtr[j]); + } else { + tempByte = + (hex_to_bin(inPtr[j]) << 4) | + (hex_to_bin(inPtr[j + 1])); + } + (*pBuf)[i++] = tempByte; + } + *pBufLen = i; + return 0; +} + +/** + * hdd_parse_reassoc_command_data() - HDD Parse reassoc command data + * @pValue: Pointer to input data (its a NULL terminated string) + * @pTargetApBssid: Pointer to target Ap bssid + * @pChannel: Pointer to the Target AP channel + * + * This function parses the reasoc command data passed in the format + * REASSOC + * + * Return: 0 for success non-zero for failure + */ +static int hdd_parse_reassoc_command_v1_data(const uint8_t *pValue, + uint8_t *pTargetApBssid, + uint8_t *pChannel) +{ + const uint8_t *inPtr = pValue; + + if (_hdd_parse_bssid_and_chan(&inPtr, pTargetApBssid, pChannel)) + return -EINVAL; + + return 0; +} + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +void hdd_wma_send_fastreassoc_cmd(hdd_adapter_t *adapter, + const tSirMacAddr bssid, int channel) +{ + QDF_STATUS status; + hdd_wext_state_t *wext_state = WLAN_HDD_GET_WEXT_STATE_PTR(adapter); + tCsrRoamProfile *profile = &wext_state->roamProfile; + struct wma_roam_invoke_cmd *fastreassoc; + cds_msg_t msg = {0}; + + fastreassoc = qdf_mem_malloc(sizeof(*fastreassoc)); + if (NULL == fastreassoc) { + hdd_err("qdf_mem_malloc failed for fastreassoc"); + return; + } + fastreassoc->vdev_id = adapter->sessionId; + fastreassoc->channel = channel; + fastreassoc->bssid[0] = bssid[0]; + fastreassoc->bssid[1] = bssid[1]; + fastreassoc->bssid[2] = bssid[2]; + fastreassoc->bssid[3] = bssid[3]; + fastreassoc->bssid[4] = bssid[4]; + fastreassoc->bssid[5] = bssid[5]; + + status = sme_get_beacon_frm(WLAN_HDD_GET_HAL_CTX(adapter), profile, + bssid, &fastreassoc->frame_buf, + &fastreassoc->frame_len); + + if (QDF_STATUS_SUCCESS != status) { + hdd_err("sme_get_beacon_frm failed"); + fastreassoc->frame_buf = NULL; + fastreassoc->frame_len = 0; + } + + msg.type = SIR_HAL_ROAM_INVOKE; + msg.reserved = 0; + msg.bodyptr = fastreassoc; + status = cds_mq_post_message(QDF_MODULE_ID_WMA, &msg); + if (QDF_STATUS_SUCCESS != status) { + hdd_err("Not able to post ROAM_INVOKE_CMD message to WMA"); + qdf_mem_free(fastreassoc); + } +} +#endif + +/** + * hdd_reassoc() - perform a userspace-directed reassoc + * @adapter: Adapter upon which the command was received + * @bssid: BSSID with which to reassociate + * @channel: channel upon which to reassociate + * @src: The source for the trigger of this action + * + * This function performs a userspace-directed reassoc operation + * + * Return: 0 for success non-zero for failure + */ +int hdd_reassoc(hdd_adapter_t *adapter, const uint8_t *bssid, + uint8_t channel, const handoff_src src) +{ + hdd_station_ctx_t *pHddStaCtx; + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + int ret = 0; + + if (hdd_ctx == NULL) { + hdd_err("Invalid hdd ctx"); + return -EINVAL; + } + + if (QDF_STA_MODE != adapter->device_mode) { + hdd_warn("Unsupported in mode %s(%d)", + hdd_device_mode_to_string(adapter->device_mode), + adapter->device_mode); + return -EINVAL; + } + + pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + + /* if not associated, no need to proceed with reassoc */ + if (eConnectionState_Associated != pHddStaCtx->conn_info.connState) { + hdd_info("Not associated"); + ret = -EINVAL; + goto exit; + } + + /* + * if the target bssid is same as currently associated AP, + * use the current connections's channel. + */ + if (!memcmp(bssid, pHddStaCtx->conn_info.bssId.bytes, + QDF_MAC_ADDR_SIZE)) { + hdd_info("Reassoc BSSID is same as currently associated AP bssid"); + channel = pHddStaCtx->conn_info.operationChannel; + } + + /* Check channel number is a valid channel number */ + if (QDF_STATUS_SUCCESS != + wlan_hdd_validate_operation_channel(adapter, channel)) { + hdd_err("Invalid Channel %d", channel); + ret = -EINVAL; + goto exit; + } + + /* Proceed with reassoc */ + if (roaming_offload_enabled(hdd_ctx)) { + hdd_wma_send_fastreassoc_cmd(adapter, + bssid, (int)channel); + } else { + tCsrHandoffRequest handoffInfo; + + handoffInfo.channel = channel; + handoffInfo.src = src; + qdf_mem_copy(handoffInfo.bssid.bytes, bssid, QDF_MAC_ADDR_SIZE); + sme_handoff_request(hdd_ctx->hHal, adapter->sessionId, + &handoffInfo); + } +exit: + return ret; +} + +/** + * hdd_parse_reassoc_v1() - parse version 1 of the REASSOC command + * @adapter: Adapter upon which the command was received + * @command: ASCII text command that was received + * + * This function parses the v1 REASSOC command with the format + * + * REASSOC xx:xx:xx:xx:xx:xx CH + * + * Where "xx:xx:xx:xx:xx:xx" is the Hex-ASCII representation of the + * BSSID and CH is the ASCII representation of the channel. For + * example + * + * REASSOC 00:0a:0b:11:22:33 48 + * + * Return: 0 for success non-zero for failure + */ +static int hdd_parse_reassoc_v1(hdd_adapter_t *adapter, const char *command) +{ + uint8_t channel = 0; + tSirMacAddr bssid; + int ret; + + ret = hdd_parse_reassoc_command_v1_data(command, bssid, &channel); + if (ret) { + hdd_err("Failed to parse reassoc command data"); + } else { + ret = hdd_reassoc(adapter, bssid, channel, REASSOC); + } + return ret; +} + +/** + * hdd_parse_reassoc_v2() - parse version 2 of the REASSOC command + * @adapter: Adapter upon which the command was received + * @command: Command that was received, ASCII command + * followed by binary data + * + * This function parses the v2 REASSOC command with the format + * + * REASSOC + * + * Return: 0 for success non-zero for failure + */ +static int hdd_parse_reassoc_v2(hdd_adapter_t *adapter, const char *command) +{ + struct android_wifi_reassoc_params params; + tSirMacAddr bssid; + int ret; + + /* The params are located after "REASSOC " */ + memcpy(¶ms, command + 8, sizeof(params)); + + if (!mac_pton(params.bssid, (u8 *) &bssid)) { + hdd_err("MAC address parsing failed"); + ret = -EINVAL; + } else { + ret = hdd_reassoc(adapter, bssid, params.channel, REASSOC); + } + return ret; +} + +/** + * hdd_parse_reassoc() - parse the REASSOC command + * @adapter: Adapter upon which the command was received + * @command: Command that was received + * + * There are two different versions of the REASSOC command. Version 1 + * of the command contains a parameter list that is ASCII characters + * whereas version 2 contains a combination of ASCII and binary + * payload. Determine if a version 1 or a version 2 command is being + * parsed by examining the parameters, and then dispatch the parser + * that is appropriate for the command. + * + * Return: 0 for success non-zero for failure + */ +static int hdd_parse_reassoc(hdd_adapter_t *adapter, const char *command) +{ + int ret; + + /* both versions start with "REASSOC " + * v1 has a bssid and channel # as an ASCII string + * REASSOC xx:xx:xx:xx:xx:xx CH + * v2 has a C struct + * REASSOC + * + * The first field in the v2 struct is also the bssid in ASCII. + * But in the case of a v2 message the BSSID is NUL-terminated. + * Hence we can peek at that offset to see if this is V1 or V2 + * REASSOC xx:xx:xx:xx:xx:xx* + * 1111111111222222 + * 01234567890123456789012345 + */ + if (command[25]) { + ret = hdd_parse_reassoc_v1(adapter, command); + } else { + ret = hdd_parse_reassoc_v2(adapter, command); + } + + return ret; +} + +/** + * hdd_sendactionframe() - send a userspace-supplied action frame + * @adapter: Adapter upon which the command was received + * @bssid: BSSID target of the action frame + * @channel: Channel upon which to send the frame + * @dwell_time: Amount of time to dwell when the frame is sent + * @payload_len:Length of the payload + * @payload: Payload of the frame + * + * This function sends a userspace-supplied action frame + * + * Return: 0 for success non-zero for failure + */ +static int +hdd_sendactionframe(hdd_adapter_t *adapter, const uint8_t *bssid, + const uint8_t channel, const uint8_t dwell_time, + const int payload_len, const uint8_t *payload) +{ + struct ieee80211_channel chan; + int frame_len, ret = 0; + uint8_t *frame; + struct ieee80211_hdr_3addr *hdr; + u64 cookie; + hdd_station_ctx_t *pHddStaCtx; + hdd_context_t *hdd_ctx; + tpSirMacVendorSpecificFrameHdr pVendorSpecific = + (tpSirMacVendorSpecificFrameHdr) payload; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) + struct cfg80211_mgmt_tx_params params; +#endif + + if (QDF_STA_MODE != adapter->device_mode) { + hdd_warn("Unsupported in mode %s(%d)", + hdd_device_mode_to_string(adapter->device_mode), + adapter->device_mode); + return -EINVAL; + } + + pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + + /* if not associated, no need to send action frame */ + if (eConnectionState_Associated != pHddStaCtx->conn_info.connState) { + hdd_info("Not associated"); + ret = -EINVAL; + goto exit; + } + + /* + * if the target bssid is different from currently associated AP, + * then no need to send action frame + */ + if (memcmp(bssid, pHddStaCtx->conn_info.bssId.bytes, + QDF_MAC_ADDR_SIZE)) { + hdd_info("STA is not associated to this AP"); + ret = -EINVAL; + goto exit; + } + + chan.center_freq = sme_chn_to_freq(channel); + /* Check if it is specific action frame */ + if (pVendorSpecific->category == + SIR_MAC_ACTION_VENDOR_SPECIFIC_CATEGORY) { + static const uint8_t Oui[] = { 0x00, 0x00, 0xf0 }; + if (!qdf_mem_cmp(pVendorSpecific->Oui, (void *)Oui, 3)) { + /* + * if the channel number is different from operating + * channel then no need to send action frame + */ + if (channel != 0) { + if (channel != + pHddStaCtx->conn_info.operationChannel) { + hdd_info("channel(%d) is different from operating channel(%d)", + channel, + pHddStaCtx->conn_info. + operationChannel); + ret = -EINVAL; + goto exit; + } + /* + * If channel number is specified and same + * as home channel, ensure that action frame + * is sent immediately by cancelling + * roaming scans. Otherwise large dwell times + * may cause long delays in sending action + * frames. + */ + sme_abort_roam_scan(hdd_ctx->hHal, + adapter->sessionId); + } else { + /* + * 0 is accepted as current home channel, + * delayed transmission of action frame is ok. + */ + chan.center_freq = + sme_chn_to_freq(pHddStaCtx->conn_info. + operationChannel); + } + } + } + if (chan.center_freq == 0) { + hdd_err("Invalid channel number %d", channel); + ret = -EINVAL; + goto exit; + } + + frame_len = payload_len + 24; + frame = qdf_mem_malloc(frame_len); + if (!frame) { + hdd_err("memory allocation failed"); + ret = -ENOMEM; + goto exit; + } + + hdr = (struct ieee80211_hdr_3addr *)frame; + hdr->frame_control = + cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_ACTION); + qdf_mem_copy(hdr->addr1, bssid, QDF_MAC_ADDR_SIZE); + qdf_mem_copy(hdr->addr2, adapter->macAddressCurrent.bytes, + QDF_MAC_ADDR_SIZE); + qdf_mem_copy(hdr->addr3, bssid, QDF_MAC_ADDR_SIZE); + qdf_mem_copy(hdr + 1, payload, payload_len); + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) + params.chan = &chan; + params.offchan = 0; + params.wait = dwell_time; + params.buf = frame; + params.len = frame_len; + params.no_cck = 1; + params.dont_wait_for_ack = 1; + ret = wlan_hdd_mgmt_tx(NULL, &adapter->wdev, ¶ms, &cookie); +#else + ret = wlan_hdd_mgmt_tx(NULL, + &(adapter->wdev), + &chan, 0, + + dwell_time, frame, frame_len, 1, 1, &cookie); +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) */ + + qdf_mem_free(frame); +exit: + return ret; +} + +/** + * hdd_parse_sendactionframe_v1() - parse version 1 of the + * SENDACTIONFRAME command + * @adapter: Adapter upon which the command was received + * @command: ASCII text command that was received + * + * This function parses the v1 SENDACTIONFRAME command with the format + * + * SENDACTIONFRAME xx:xx:xx:xx:xx:xx CH DW xxxxxx + * + * Where "xx:xx:xx:xx:xx:xx" is the Hex-ASCII representation of the + * BSSID, CH is the ASCII representation of the channel, DW is the + * ASCII representation of the dwell time, and xxxxxx is the Hex-ASCII + * payload. For example + * + * SENDACTIONFRAME 00:0a:0b:11:22:33 48 40 aabbccddee + * + * Return: 0 for success non-zero for failure + */ +static int +hdd_parse_sendactionframe_v1(hdd_adapter_t *adapter, const char *command) +{ + uint8_t channel = 0; + uint8_t dwell_time = 0; + uint8_t payload_len = 0; + uint8_t *payload = NULL; + tSirMacAddr bssid; + int ret; + + ret = hdd_parse_send_action_frame_v1_data(command, bssid, &channel, + &dwell_time, &payload, + &payload_len); + if (ret) { + hdd_err("Failed to parse send action frame data"); + } else { + ret = hdd_sendactionframe(adapter, bssid, channel, + dwell_time, payload_len, payload); + qdf_mem_free(payload); + } + + return ret; +} + +/** + * hdd_parse_sendactionframe_v2() - parse version 2 of the + * SENDACTIONFRAME command + * @adapter: Adapter upon which the command was received + * @command: Command that was received, ASCII command + * followed by binary data + * + * This function parses the v2 SENDACTIONFRAME command with the format + * + * SENDACTIONFRAME + * + * Return: 0 for success non-zero for failure + */ +static int +hdd_parse_sendactionframe_v2(hdd_adapter_t *adapter, + const char *command, int total_len) +{ + struct android_wifi_af_params *params; + tSirMacAddr bssid; + int ret; + + /* The params are located after "SENDACTIONFRAME " */ + total_len -= 16; + params = (struct android_wifi_af_params *)(command + 16); + + if (params->len <= 0 || params->len > ANDROID_WIFI_ACTION_FRAME_SIZE || + (params->len > total_len)) { + hdd_err("Invalid payload length: %d", params->len); + return -EINVAL; + } + + if (!mac_pton(params->bssid, (u8 *)&bssid)) { + hdd_err("MAC address parsing failed"); + return -EINVAL; + } + + if (params->channel < 0 || + params->channel > WNI_CFG_CURRENT_CHANNEL_STAMAX) { + hdd_err("Invalid channel: %d", params->channel); + return -EINVAL; + } + + if (params->dwell_time < 0) { + hdd_err("Invalid dwell_time: %d", params->dwell_time); + return -EINVAL; + } + + ret = hdd_sendactionframe(adapter, bssid, params->channel, + params->dwell_time, params->len, params->data); + + return ret; +} + +/** + * hdd_parse_sendactionframe() - parse the SENDACTIONFRAME command + * @adapter: Adapter upon which the command was received + * @command: Command that was received + * + * There are two different versions of the SENDACTIONFRAME command. + * Version 1 of the command contains a parameter list that is ASCII + * characters whereas version 2 contains a combination of ASCII and + * binary payload. Determine if a version 1 or a version 2 command is + * being parsed by examining the parameters, and then dispatch the + * parser that is appropriate for the version of the command. + * + * Return: 0 for success non-zero for failure + */ +static int +hdd_parse_sendactionframe(hdd_adapter_t *adapter, const char *command, + int total_len) +{ + int ret; + + /* + * both versions start with "SENDACTIONFRAME " + * v1 has a bssid and other parameters as an ASCII string + * SENDACTIONFRAME xx:xx:xx:xx:xx:xx CH DWELL LEN FRAME + * v2 has a C struct + * SENDACTIONFRAME + * + * The first field in the v2 struct is also the bssid in ASCII. + * But in the case of a v2 message the BSSID is NUL-terminated. + * Hence we can peek at that offset to see if this is V1 or V2 + * SENDACTIONFRAME xx:xx:xx:xx:xx:xx* + * 111111111122222222223333 + * 0123456789012345678901234567890123 + * For both the commands, a valid command must have atleast + * first 34 length of data. + */ + if (total_len < 34) { + hdd_err("Invalid command (total_len=%d)", total_len); + return -EINVAL; + } + + if (command[33]) { + ret = hdd_parse_sendactionframe_v1(adapter, command); + } else { + ret = hdd_parse_sendactionframe_v2(adapter, command, total_len); + } + + return ret; +} + +/** + * hdd_parse_channellist() - HDD Parse channel list + * @pValue: Pointer to input channel list + * @ChannelList: Pointer to local output array to record + * channel list + * @pNumChannels: Pointer to number of roam scan channels + * + * This function parses the channel list passed in the format + * SETROAMSCANCHANNELSChannel 1Channel 2Channel N + * if the Number of channels (N) does not match with the actual number + * of channels passed then take the minimum of N and count of + * (Ch1, Ch2, ...Ch M). For example, if SETROAMSCANCHANNELS 3 36 40 44 48, + * only 36, 40 and 44 shall be taken. If SETROAMSCANCHANNELS 5 36 40 44 48, + * ignore 5 and take 36, 40, 44 and 48. This function does not take care of + * removing duplicate channels from the list + * + * Return: 0 for success non-zero for failure + */ +static int +hdd_parse_channellist(const uint8_t *pValue, uint8_t *pChannelList, + uint8_t *pNumChannels) +{ + const uint8_t *inPtr = pValue; + int tempInt; + int j = 0; + int v = 0; + char buf[32]; + + inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE); + /* no argument after the command */ + if (NULL == inPtr) { + return -EINVAL; + } + + /* no space after the command */ + else if (SPACE_ASCII_VALUE != *inPtr) { + return -EINVAL; + } + + /* remove empty spaces */ + while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr)) + inPtr++; + + /* no argument followed by spaces */ + if ('\0' == *inPtr) { + return -EINVAL; + } + + /* get the first argument ie the number of channels */ + v = sscanf(inPtr, "%31s ", buf); + if (1 != v) + return -EINVAL; + + v = kstrtos32(buf, 10, &tempInt); + if ((v < 0) || + (tempInt <= 0) || (tempInt > WNI_CFG_VALID_CHANNEL_LIST_LEN)) { + return -EINVAL; + } + + *pNumChannels = tempInt; + + hdd_info("Number of channels are: %d", *pNumChannels); + + for (j = 0; j < (*pNumChannels); j++) { + /* + * inPtr pointing to the beginning of first space after number + * of channels + */ + inPtr = strpbrk(inPtr, " "); + /* no channel list after the number of channels argument */ + if (NULL == inPtr) { + if (0 != j) { + *pNumChannels = j; + return 0; + } else { + return -EINVAL; + } + } + + /* remove empty space */ + while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr)) + inPtr++; + + /* + * no channel list after the number of channels + * argument and spaces + */ + if ('\0' == *inPtr) { + if (0 != j) { + *pNumChannels = j; + return 0; + } else { + return -EINVAL; + } + } + + v = sscanf(inPtr, "%31s ", buf); + if (1 != v) + return -EINVAL; + + v = kstrtos32(buf, 10, &tempInt); + if ((v < 0) || + (tempInt <= 0) || + (tempInt > WNI_CFG_CURRENT_CHANNEL_STAMAX)) { + return -EINVAL; + } + pChannelList[j] = tempInt; + + hdd_info("Channel %d added to preferred channel list", + pChannelList[j]); + } + + return 0; +} + +/** + * hdd_parse_set_roam_scan_channels_v1() - parse version 1 of the + * SETROAMSCANCHANNELS command + * @adapter: Adapter upon which the command was received + * @command: ASCII text command that was received + * + * This function parses the v1 SETROAMSCANCHANNELS command with the format + * + * SETROAMSCANCHANNELS N C1 C2 ... Cn + * + * Where "N" is the ASCII representation of the number of channels and + * C1 thru Cn is the ASCII representation of the channels. For example + * + * SETROAMSCANCHANNELS 4 36 40 44 48 + * + * Return: 0 for success non-zero for failure + */ +static int +hdd_parse_set_roam_scan_channels_v1(hdd_adapter_t *adapter, + const char *command) +{ + uint8_t channel_list[WNI_CFG_VALID_CHANNEL_LIST_LEN] = { 0 }; + uint8_t num_chan = 0; + QDF_STATUS status; + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + int ret; + + ret = hdd_parse_channellist(command, channel_list, &num_chan); + if (ret) { + hdd_err("Failed to parse channel list information"); + goto exit; + } + + MTRACE(qdf_trace(QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_SETROAMSCANCHANNELS_IOCTL, + adapter->sessionId, num_chan)); + + if (num_chan > WNI_CFG_VALID_CHANNEL_LIST_LEN) { + hdd_err("number of channels (%d) supported exceeded max (%d)", + num_chan, WNI_CFG_VALID_CHANNEL_LIST_LEN); + ret = -EINVAL; + goto exit; + } + + status = + sme_change_roam_scan_channel_list(hdd_ctx->hHal, + adapter->sessionId, + channel_list, num_chan); + if (QDF_STATUS_SUCCESS != status) { + hdd_err("Failed to update channel list information"); + ret = -EINVAL; + goto exit; + } +exit: + return ret; +} + +/** + * hdd_parse_set_roam_scan_channels_v2() - parse version 2 of the + * SETROAMSCANCHANNELS command + * @adapter: Adapter upon which the command was received + * @command: Command that was received, ASCII command + * followed by binary data + * + * This function parses the v2 SETROAMSCANCHANNELS command with the format + * + * SETROAMSCANCHANNELS [N][C1][C2][Cn] + * + * The command begins with SETROAMSCANCHANNELS followed by a space, but + * what follows the space is an array of u08 parameters. For example + * + * SETROAMSCANCHANNELS [0x04 0x24 0x28 0x2c 0x30] + * + * Return: 0 for success non-zero for failure + */ +static int +hdd_parse_set_roam_scan_channels_v2(hdd_adapter_t *adapter, + const char *command) +{ + const uint8_t *value; + uint8_t channel_list[WNI_CFG_VALID_CHANNEL_LIST_LEN] = { 0 }; + uint8_t channel; + uint8_t num_chan; + int i; + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + QDF_STATUS status; + int ret = 0; + + /* array of values begins after "SETROAMSCANCHANNELS " */ + value = command + 20; + + num_chan = *value++; + if (num_chan > WNI_CFG_VALID_CHANNEL_LIST_LEN) { + hdd_err("number of channels (%d) supported exceeded max (%d)", + num_chan, WNI_CFG_VALID_CHANNEL_LIST_LEN); + ret = -EINVAL; + goto exit; + } + + MTRACE(qdf_trace(QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_SETROAMSCANCHANNELS_IOCTL, + adapter->sessionId, num_chan)); + + for (i = 0; i < num_chan; i++) { + channel = *value++; + if (channel > WNI_CFG_CURRENT_CHANNEL_STAMAX) { + hdd_err("index %d invalid channel %d", + i, channel); + ret = -EINVAL; + goto exit; + } + channel_list[i] = channel; + } + status = + sme_change_roam_scan_channel_list(hdd_ctx->hHal, + adapter->sessionId, + channel_list, num_chan); + if (QDF_STATUS_SUCCESS != status) { + hdd_err("Failed to update channel list information"); + ret = -EINVAL; + goto exit; + } +exit: + return ret; +} + +/** + * hdd_parse_set_roam_scan_channels() - parse the + * SETROAMSCANCHANNELS command + * @adapter: Adapter upon which the command was received + * @command: Command that was received + * + * There are two different versions of the SETROAMSCANCHANNELS command. + * Version 1 of the command contains a parameter list that is ASCII + * characters whereas version 2 contains a binary payload. Determine + * if a version 1 or a version 2 command is being parsed by examining + * the parameters, and then dispatch the parser that is appropriate for + * the command. + * + * Return: 0 for success non-zero for failure + */ +static int +hdd_parse_set_roam_scan_channels(hdd_adapter_t *adapter, const char *command) +{ + const char *cursor; + char ch; + bool v1; + int ret; + + /* start after "SETROAMSCANCHANNELS " */ + cursor = command + 20; + + /* assume we have a version 1 command until proven otherwise */ + v1 = true; + + /* v1 params will only contain ASCII digits and space */ + while ((ch = *cursor++) && v1) { + if (!(isdigit(ch) || isspace(ch))) { + v1 = false; + } + } + if (v1) { + ret = hdd_parse_set_roam_scan_channels_v1(adapter, command); + } else { + ret = hdd_parse_set_roam_scan_channels_v2(adapter, command); + } + + return ret; +} + +#ifdef FEATURE_WLAN_ESE +/** + * hdd_parse_plm_cmd() - HDD Parse Plm command + * @pValue: Pointer to input data + * @pPlmRequest:Pointer to output struct tpSirPlmReq + * + * This function parses the plm command passed in the format + * CCXPLMREQ + * + * + * + * + * + * Return: 0 for success non-zero for failure + */ +static QDF_STATUS hdd_parse_plm_cmd(uint8_t *pValue, tSirPlmReq *pPlmRequest) +{ + uint8_t *cmdPtr = NULL; + int count, content = 0, ret = 0; + char buf[32]; + + /* move to argument list */ + cmdPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE); + if (NULL == cmdPtr) + return QDF_STATUS_E_FAILURE; + + /* no space after the command */ + if (SPACE_ASCII_VALUE != *cmdPtr) + return QDF_STATUS_E_FAILURE; + + /* remove empty spaces */ + while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr)) + cmdPtr++; + + /* START/STOP PLM req */ + ret = sscanf(cmdPtr, "%31s ", buf); + if (1 != ret) + return QDF_STATUS_E_FAILURE; + + ret = kstrtos32(buf, 10, &content); + if (ret < 0) + return QDF_STATUS_E_FAILURE; + + pPlmRequest->enable = content; + cmdPtr = strpbrk(cmdPtr, " "); + + if (NULL == cmdPtr) + return QDF_STATUS_E_FAILURE; + + /* remove empty spaces */ + while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr)) + cmdPtr++; + + /* Dialog token of radio meas req containing meas reqIE */ + ret = sscanf(cmdPtr, "%31s ", buf); + if (1 != ret) + return QDF_STATUS_E_FAILURE; + + ret = kstrtos32(buf, 10, &content); + if (ret < 0) + return QDF_STATUS_E_FAILURE; + + pPlmRequest->diag_token = content; + hdd_debug("diag token %d", pPlmRequest->diag_token); + cmdPtr = strpbrk(cmdPtr, " "); + + if (NULL == cmdPtr) + return QDF_STATUS_E_FAILURE; + + /* remove empty spaces */ + while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr)) + cmdPtr++; + + /* measurement token of meas req IE */ + ret = sscanf(cmdPtr, "%31s ", buf); + if (1 != ret) + return QDF_STATUS_E_FAILURE; + + ret = kstrtos32(buf, 10, &content); + if (ret < 0) + return QDF_STATUS_E_FAILURE; + + pPlmRequest->meas_token = content; + hdd_debug("meas token %d", pPlmRequest->meas_token); + + hdd_err("PLM req %s", pPlmRequest->enable ? "START" : "STOP"); + if (pPlmRequest->enable) { + + cmdPtr = strpbrk(cmdPtr, " "); + + if (NULL == cmdPtr) + return QDF_STATUS_E_FAILURE; + + /* remove empty spaces */ + while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr)) + cmdPtr++; + + /* total number of bursts after which STA stops sending */ + ret = sscanf(cmdPtr, "%31s ", buf); + if (1 != ret) + return QDF_STATUS_E_FAILURE; + + ret = kstrtos32(buf, 10, &content); + if (ret < 0) + return QDF_STATUS_E_FAILURE; + + if (content < 0) + return QDF_STATUS_E_FAILURE; + + pPlmRequest->numBursts = content; + hdd_debug("num burst %d", pPlmRequest->numBursts); + cmdPtr = strpbrk(cmdPtr, " "); + + if (NULL == cmdPtr) + return QDF_STATUS_E_FAILURE; + + /* remove empty spaces */ + while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr)) + cmdPtr++; + + /* burst interval in seconds */ + ret = sscanf(cmdPtr, "%31s ", buf); + if (1 != ret) + return QDF_STATUS_E_FAILURE; + + ret = kstrtos32(buf, 10, &content); + if (ret < 0) + return QDF_STATUS_E_FAILURE; + + if (content <= 0) + return QDF_STATUS_E_FAILURE; + + pPlmRequest->burstInt = content; + hdd_debug("burst Int %d", pPlmRequest->burstInt); + cmdPtr = strpbrk(cmdPtr, " "); + + if (NULL == cmdPtr) + return QDF_STATUS_E_FAILURE; + + /* remove empty spaces */ + while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr)) + cmdPtr++; + + /* Meas dur in TU's,STA goes off-ch and transmit PLM bursts */ + ret = sscanf(cmdPtr, "%31s ", buf); + if (1 != ret) + return QDF_STATUS_E_FAILURE; + + ret = kstrtos32(buf, 10, &content); + if (ret < 0) + return QDF_STATUS_E_FAILURE; + + if (content <= 0) + return QDF_STATUS_E_FAILURE; + + pPlmRequest->measDuration = content; + hdd_debug("measDur %d", pPlmRequest->measDuration); + cmdPtr = strpbrk(cmdPtr, " "); + + if (NULL == cmdPtr) + return QDF_STATUS_E_FAILURE; + + /* remove empty spaces */ + while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr)) + cmdPtr++; + + /* burst length of PLM bursts */ + ret = sscanf(cmdPtr, "%31s ", buf); + if (1 != ret) + return QDF_STATUS_E_FAILURE; + + ret = kstrtos32(buf, 10, &content); + if (ret < 0) + return QDF_STATUS_E_FAILURE; + + if (content <= 0) + return QDF_STATUS_E_FAILURE; + + pPlmRequest->burstLen = content; + hdd_debug("burstLen %d", pPlmRequest->burstLen); + cmdPtr = strpbrk(cmdPtr, " "); + + if (NULL == cmdPtr) + return QDF_STATUS_E_FAILURE; + + /* remove empty spaces */ + while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr)) + cmdPtr++; + + /* desired tx power for transmission of PLM bursts */ + ret = sscanf(cmdPtr, "%31s ", buf); + if (1 != ret) + return QDF_STATUS_E_FAILURE; + + ret = kstrtos32(buf, 10, &content); + if (ret < 0) + return QDF_STATUS_E_FAILURE; + + if (content <= 0) + return QDF_STATUS_E_FAILURE; + + pPlmRequest->desiredTxPwr = content; + hdd_debug("desiredTxPwr %d", + pPlmRequest->desiredTxPwr); + + for (count = 0; count < QDF_MAC_ADDR_SIZE; count++) { + cmdPtr = strpbrk(cmdPtr, " "); + + if (NULL == cmdPtr) + return QDF_STATUS_E_FAILURE; + + /* remove empty spaces */ + while ((SPACE_ASCII_VALUE == *cmdPtr) + && ('\0' != *cmdPtr)) + cmdPtr++; + + ret = sscanf(cmdPtr, "%31s ", buf); + if (1 != ret) + return QDF_STATUS_E_FAILURE; + + ret = kstrtos32(buf, 16, &content); + if (ret < 0) + return QDF_STATUS_E_FAILURE; + + pPlmRequest->mac_addr.bytes[count] = content; + } + + hdd_debug("MC addr " MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(pPlmRequest->mac_addr.bytes)); + + cmdPtr = strpbrk(cmdPtr, " "); + + if (NULL == cmdPtr) + return QDF_STATUS_E_FAILURE; + + /* remove empty spaces */ + while ((SPACE_ASCII_VALUE == *cmdPtr) && ('\0' != *cmdPtr)) + cmdPtr++; + + /* number of channels */ + ret = sscanf(cmdPtr, "%31s ", buf); + if (1 != ret) + return QDF_STATUS_E_FAILURE; + + ret = kstrtos32(buf, 10, &content); + if (ret < 0) + return QDF_STATUS_E_FAILURE; + + if (content < 0) + return QDF_STATUS_E_FAILURE; + + content = QDF_MIN(content, WNI_CFG_VALID_CHANNEL_LIST_LEN); + pPlmRequest->plmNumCh = content; + hdd_debug("numch: %d", pPlmRequest->plmNumCh); + + /* Channel numbers */ + for (count = 0; count < pPlmRequest->plmNumCh; count++) { + cmdPtr = strpbrk(cmdPtr, " "); + + if (NULL == cmdPtr) + return QDF_STATUS_E_FAILURE; + + /* remove empty spaces */ + while ((SPACE_ASCII_VALUE == *cmdPtr) + && ('\0' != *cmdPtr)) + cmdPtr++; + + ret = sscanf(cmdPtr, "%31s ", buf); + if (1 != ret) + return QDF_STATUS_E_FAILURE; + + ret = kstrtos32(buf, 10, &content); + if (ret < 0 || content <= 0 || + content > WNI_CFG_CURRENT_CHANNEL_STAMAX) + return QDF_STATUS_E_FAILURE; + + pPlmRequest->plmChList[count] = content; + hdd_debug(" ch- %d", pPlmRequest->plmChList[count]); + } + } + /* If PLM START */ + return QDF_STATUS_SUCCESS; +} +#endif + +#ifdef WLAN_FEATURE_EXTWOW_SUPPORT +static void wlan_hdd_ready_to_extwow(void *callbackContext, bool is_success) +{ + hdd_context_t *hdd_ctx = (hdd_context_t *) callbackContext; + int rc; + + rc = wlan_hdd_validate_context(hdd_ctx); + if (rc) + return; + hdd_ctx->ext_wow_should_suspend = is_success; + complete(&hdd_ctx->ready_to_extwow); +} + +static int hdd_enable_ext_wow(hdd_adapter_t *adapter, + tpSirExtWoWParams arg_params) +{ + tSirExtWoWParams params; + QDF_STATUS qdf_ret_status = QDF_STATUS_E_FAILURE; + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(adapter); + int rc; + + qdf_mem_copy(¶ms, arg_params, sizeof(params)); + + INIT_COMPLETION(hdd_ctx->ready_to_extwow); + + qdf_ret_status = sme_configure_ext_wow(hHal, ¶ms, + &wlan_hdd_ready_to_extwow, + hdd_ctx); + if (QDF_STATUS_SUCCESS != qdf_ret_status) { + hdd_err("sme_configure_ext_wow returned failure %d", + qdf_ret_status); + return -EPERM; + } + + rc = wait_for_completion_timeout(&hdd_ctx->ready_to_extwow, + msecs_to_jiffies(WLAN_WAIT_TIME_READY_TO_EXTWOW)); + if (!rc) { + hdd_err("Failed to get ready to extwow"); + return -EPERM; + } + + if (hdd_ctx->ext_wow_should_suspend) { + if (hdd_ctx->config->extWowGotoSuspend) { + pm_message_t state; + + state.event = PM_EVENT_SUSPEND; + hdd_info("Received ready to ExtWoW. Going to suspend"); + + rc = wlan_hdd_cfg80211_suspend_wlan(hdd_ctx->wiphy, NULL); + if (rc < 0) { + hdd_err("wlan_hdd_cfg80211_suspend_wlan failed, error = %d", + rc); + return rc; + } + qdf_ret_status = wlan_hdd_bus_suspend(state); + if (qdf_ret_status != QDF_STATUS_SUCCESS) { + hdd_err("wlan_hdd_suspend failed, status = %d", + qdf_ret_status); + wlan_hdd_cfg80211_resume_wlan(hdd_ctx->wiphy); + return -EPERM; + } + } + } else { + hdd_err("Received ready to ExtWoW failure"); + return -EPERM; + } + + return 0; +} + +static int hdd_enable_ext_wow_parser(hdd_adapter_t *adapter, int vdev_id, + int value) +{ + tSirExtWoWParams params; + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + int rc; + + rc = wlan_hdd_validate_context(hdd_ctx); + if (rc) + return rc; + + if (value < EXT_WOW_TYPE_APP_TYPE1 || + value > EXT_WOW_TYPE_APP_TYPE1_2) { + hdd_err("Invalid type"); + return -EINVAL; + } + + if (value == EXT_WOW_TYPE_APP_TYPE1 && + hdd_ctx->is_extwow_app_type1_param_set) + params.type = value; + else if (value == EXT_WOW_TYPE_APP_TYPE2 && + hdd_ctx->is_extwow_app_type2_param_set) + params.type = value; + else if (value == EXT_WOW_TYPE_APP_TYPE1_2 && + hdd_ctx->is_extwow_app_type1_param_set && + hdd_ctx->is_extwow_app_type2_param_set) + params.type = value; + else { + hdd_err("Set app params before enable it value %d", + value); + return -EINVAL; + } + + params.vdev_id = vdev_id; + params.wakeup_pin_num = hdd_ctx->config->extWowApp1WakeupPinNumber | + (hdd_ctx->config->extWowApp2WakeupPinNumber + << 8); + + return hdd_enable_ext_wow(adapter, ¶ms); +} + +static int hdd_set_app_type1_params(tHalHandle hHal, + tpSirAppType1Params arg_params) +{ + tSirAppType1Params params; + QDF_STATUS qdf_ret_status = QDF_STATUS_E_FAILURE; + + qdf_mem_copy(¶ms, arg_params, sizeof(params)); + + qdf_ret_status = sme_configure_app_type1_params(hHal, ¶ms); + if (QDF_STATUS_SUCCESS != qdf_ret_status) { + hdd_err("sme_configure_app_type1_params returned failure %d", + qdf_ret_status); + return -EPERM; + } + + return 0; +} + +static int hdd_set_app_type1_parser(hdd_adapter_t *adapter, + char *arg, int len) +{ + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(adapter); + char id[20], password[20]; + tSirAppType1Params params; + int rc; + + rc = wlan_hdd_validate_context(hdd_ctx); + if (rc) + return rc; + + if (2 != sscanf(arg, "%8s %16s", id, password)) { + hdd_err("Invalid Number of arguments"); + return -EINVAL; + } + + memset(¶ms, 0, sizeof(tSirAppType1Params)); + params.vdev_id = adapter->sessionId; + qdf_copy_macaddr(¶ms.wakee_mac_addr, &adapter->macAddressCurrent); + + params.id_length = strlen(id); + qdf_mem_copy(params.identification_id, id, params.id_length); + params.pass_length = strlen(password); + qdf_mem_copy(params.password, password, params.pass_length); + + hdd_info("%d %pM %.8s %u %.16s %u", + params.vdev_id, params.wakee_mac_addr.bytes, + params.identification_id, params.id_length, + params.password, params.pass_length); + + return hdd_set_app_type1_params(hHal, ¶ms); +} + +static int hdd_set_app_type2_params(tHalHandle hHal, + tpSirAppType2Params arg_params) +{ + tSirAppType2Params params; + QDF_STATUS qdf_ret_status = QDF_STATUS_E_FAILURE; + + qdf_mem_copy(¶ms, arg_params, sizeof(params)); + + qdf_ret_status = sme_configure_app_type2_params(hHal, ¶ms); + if (QDF_STATUS_SUCCESS != qdf_ret_status) { + hdd_err("sme_configure_app_type2_params returned failure %d", + qdf_ret_status); + return -EPERM; + } + + return 0; +} + +static int hdd_set_app_type2_parser(hdd_adapter_t *adapter, + char *arg, int len) +{ + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(adapter); + char mac_addr[20], rc4_key[20]; + unsigned int gateway_mac[QDF_MAC_ADDR_SIZE]; + tSirAppType2Params params; + int ret; + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return ret; + + memset(¶ms, 0, sizeof(tSirAppType2Params)); + + ret = sscanf(arg, "%17s %16s %x %x %x %u %u %hu %hu %u %u %u %u %u %u", + mac_addr, rc4_key, (unsigned int *)¶ms.ip_id, + (unsigned int *)¶ms.ip_device_ip, + (unsigned int *)¶ms.ip_server_ip, + (unsigned int *)¶ms.tcp_seq, + (unsigned int *)¶ms.tcp_ack_seq, + (uint16_t *)¶ms.tcp_src_port, + (uint16_t *)¶ms.tcp_dst_port, + (unsigned int *)¶ms.keepalive_init, + (unsigned int *)¶ms.keepalive_min, + (unsigned int *)¶ms.keepalive_max, + (unsigned int *)¶ms.keepalive_inc, + (unsigned int *)¶ms.tcp_tx_timeout_val, + (unsigned int *)¶ms.tcp_rx_timeout_val); + + if (ret != 15 && ret != 7) { + hdd_err("Invalid Number of arguments"); + return -EINVAL; + } + + if (6 != + sscanf(mac_addr, "%02x:%02x:%02x:%02x:%02x:%02x", &gateway_mac[0], + &gateway_mac[1], &gateway_mac[2], &gateway_mac[3], + &gateway_mac[4], &gateway_mac[5])) { + hdd_err("Invalid MacAddress Input %s", mac_addr); + return -EINVAL; + } + + if (params.tcp_src_port > WLAN_HDD_MAX_TCP_PORT || + params.tcp_dst_port > WLAN_HDD_MAX_TCP_PORT) { + hdd_err("Invalid TCP Port Number"); + return -EINVAL; + } + + qdf_mem_copy(¶ms.gateway_mac.bytes, (uint8_t *) &gateway_mac, + QDF_MAC_ADDR_SIZE); + + params.rc4_key_len = strlen(rc4_key); + qdf_mem_copy(params.rc4_key, rc4_key, params.rc4_key_len); + + params.vdev_id = adapter->sessionId; + params.tcp_src_port = (params.tcp_src_port != 0) ? + params.tcp_src_port : hdd_ctx->config->extWowApp2TcpSrcPort; + params.tcp_dst_port = (params.tcp_dst_port != 0) ? + params.tcp_dst_port : hdd_ctx->config->extWowApp2TcpDstPort; + params.keepalive_init = (params.keepalive_init != 0) ? + params.keepalive_init : hdd_ctx->config-> + extWowApp2KAInitPingInterval; + params.keepalive_min = + (params.keepalive_min != 0) ? + params.keepalive_min : + hdd_ctx->config->extWowApp2KAMinPingInterval; + params.keepalive_max = + (params.keepalive_max != 0) ? + params.keepalive_max : + hdd_ctx->config->extWowApp2KAMaxPingInterval; + params.keepalive_inc = + (params.keepalive_inc != 0) ? + params.keepalive_inc : + hdd_ctx->config->extWowApp2KAIncPingInterval; + params.tcp_tx_timeout_val = + (params.tcp_tx_timeout_val != 0) ? + params.tcp_tx_timeout_val : + hdd_ctx->config->extWowApp2TcpTxTimeout; + params.tcp_rx_timeout_val = + (params.tcp_rx_timeout_val != 0) ? + params.tcp_rx_timeout_val : + hdd_ctx->config->extWowApp2TcpRxTimeout; + + hdd_info("%pM %.16s %u %u %u %u %u %u %u %u %u %u %u %u %u", + gateway_mac, rc4_key, params.ip_id, + params.ip_device_ip, params.ip_server_ip, params.tcp_seq, + params.tcp_ack_seq, params.tcp_src_port, params.tcp_dst_port, + params.keepalive_init, params.keepalive_min, + params.keepalive_max, params.keepalive_inc, + params.tcp_tx_timeout_val, params.tcp_rx_timeout_val); + + return hdd_set_app_type2_params(hHal, ¶ms); +} +#endif /* WLAN_FEATURE_EXTWOW_SUPPORT */ + +/** + * hdd_parse_setmaxtxpower_command() - HDD Parse MAXTXPOWER command + * @pValue: Pointer to MAXTXPOWER command + * @pDbm: Pointer to tx power + * + * This function parses the MAXTXPOWER command passed in the format + * MAXTXPOWERX(Tx power in dbm) + * + * For example input commands: + * 1) MAXTXPOWER -8 -> This is translated into set max TX power to -8 dbm + * 2) MAXTXPOWER -23 -> This is translated into set max TX power to -23 dbm + * + * Return: 0 for success non-zero for failure + */ +static int hdd_parse_setmaxtxpower_command(uint8_t *pValue, int *pTxPower) +{ + uint8_t *inPtr = pValue; + int tempInt; + int v = 0; + *pTxPower = 0; + + inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE); + /* no argument after the command */ + if (NULL == inPtr) { + return -EINVAL; + } + + /* no space after the command */ + else if (SPACE_ASCII_VALUE != *inPtr) { + return -EINVAL; + } + + /* remove empty spaces */ + while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr)) + inPtr++; + + /* no argument followed by spaces */ + if ('\0' == *inPtr) { + return 0; + } + + v = kstrtos32(inPtr, 10, &tempInt); + + /* Range checking for passed parameter */ + if ((tempInt < HDD_MIN_TX_POWER) || (tempInt > HDD_MAX_TX_POWER)) { + return -EINVAL; + } + + *pTxPower = tempInt; + + hdd_info("SETMAXTXPOWER: %d", *pTxPower); + + return 0; +} /* End of hdd_parse_setmaxtxpower_command */ + +static int hdd_get_dwell_time(struct hdd_config *pCfg, uint8_t *command, + char *extra, uint8_t n, uint8_t *len) +{ + int ret = 0; + + if (!pCfg || !command || !extra || !len) { + hdd_err("argument passed for GETDWELLTIME is incorrect"); + ret = -EINVAL; + return ret; + } + + if (strncmp(command, "GETDWELLTIME ACTIVE MAX", 23) == 0) { + *len = scnprintf(extra, n, "GETDWELLTIME ACTIVE MAX %u\n", + (int)pCfg->nActiveMaxChnTime); + return ret; + } else if (strncmp(command, "GETDWELLTIME ACTIVE MIN", 23) == 0) { + *len = scnprintf(extra, n, "GETDWELLTIME ACTIVE MIN %u\n", + (int)pCfg->nActiveMinChnTime); + return ret; + } else if (strncmp(command, "GETDWELLTIME PASSIVE MAX", 24) == 0) { + *len = scnprintf(extra, n, "GETDWELLTIME PASSIVE MAX %u\n", + (int)pCfg->nPassiveMaxChnTime); + return ret; + } else if (strncmp(command, "GETDWELLTIME PASSIVE MIN", 24) == 0) { + *len = scnprintf(extra, n, "GETDWELLTIME PASSIVE MIN %u\n", + (int)pCfg->nPassiveMinChnTime); + return ret; + } else if (strncmp(command, "GETDWELLTIME", 12) == 0) { + *len = scnprintf(extra, n, "GETDWELLTIME %u \n", + (int)pCfg->nActiveMaxChnTime); + return ret; + } else { + ret = -EINVAL; + } + + return ret; +} + +static int hdd_set_dwell_time(hdd_adapter_t *adapter, uint8_t *command) +{ + tHalHandle hHal; + struct hdd_config *pCfg; + uint8_t *value = command; + tSmeConfigParams smeConfig; + int val = 0, temp = 0; + + pCfg = (WLAN_HDD_GET_CTX(adapter))->config; + hHal = WLAN_HDD_GET_HAL_CTX(adapter); + if (!pCfg || !hHal) { + hdd_err("argument passed for SETDWELLTIME is incorrect"); + return -EINVAL; + } + + qdf_mem_zero(&smeConfig, sizeof(smeConfig)); + sme_get_config_param(hHal, &smeConfig); + + if (strncmp(command, "SETDWELLTIME ACTIVE MAX", 23) == 0) { + value = value + 24; + temp = kstrtou32(value, 10, &val); + if (temp != 0 || val < CFG_ACTIVE_MAX_CHANNEL_TIME_MIN || + val > CFG_ACTIVE_MAX_CHANNEL_TIME_MAX) { + hdd_err("argument passed for SETDWELLTIME ACTIVE MAX is incorrect"); + return -EFAULT; + } + pCfg->nActiveMaxChnTime = val; + smeConfig.csrConfig.nActiveMaxChnTime = val; + sme_update_config(hHal, &smeConfig); + } else if (strncmp(command, "SETDWELLTIME ACTIVE MIN", 23) == 0) { + value = value + 24; + temp = kstrtou32(value, 10, &val); + if (temp != 0 || val < CFG_ACTIVE_MIN_CHANNEL_TIME_MIN || + val > CFG_ACTIVE_MIN_CHANNEL_TIME_MAX) { + hdd_err("argument passed for SETDWELLTIME ACTIVE MIN is incorrect"); + return -EFAULT; + } + pCfg->nActiveMinChnTime = val; + smeConfig.csrConfig.nActiveMinChnTime = val; + sme_update_config(hHal, &smeConfig); + } else if (strncmp(command, "SETDWELLTIME PASSIVE MAX", 24) == 0) { + value = value + 25; + temp = kstrtou32(value, 10, &val); + if (temp != 0 || val < CFG_PASSIVE_MAX_CHANNEL_TIME_MIN || + val > CFG_PASSIVE_MAX_CHANNEL_TIME_MAX) { + hdd_err("argument passed for SETDWELLTIME PASSIVE MAX is incorrect"); + return -EFAULT; + } + pCfg->nPassiveMaxChnTime = val; + smeConfig.csrConfig.nPassiveMaxChnTime = val; + sme_update_config(hHal, &smeConfig); + } else if (strncmp(command, "SETDWELLTIME PASSIVE MIN", 24) == 0) { + value = value + 25; + temp = kstrtou32(value, 10, &val); + if (temp != 0 || val < CFG_PASSIVE_MIN_CHANNEL_TIME_MIN || + val > CFG_PASSIVE_MIN_CHANNEL_TIME_MAX) { + hdd_err("argument passed for SETDWELLTIME PASSIVE MIN is incorrect"); + return -EFAULT; + } + pCfg->nPassiveMinChnTime = val; + smeConfig.csrConfig.nPassiveMinChnTime = val; + sme_update_config(hHal, &smeConfig); + } else if (strncmp(command, "SETDWELLTIME", 12) == 0) { + value = value + 13; + temp = kstrtou32(value, 10, &val); + if (temp != 0 || val < CFG_ACTIVE_MAX_CHANNEL_TIME_MIN || + val > CFG_ACTIVE_MAX_CHANNEL_TIME_MAX) { + hdd_err("argument passed for SETDWELLTIME is incorrect"); + return -EFAULT; + } + pCfg->nActiveMaxChnTime = val; + smeConfig.csrConfig.nActiveMaxChnTime = val; + sme_update_config(hHal, &smeConfig); + } else { + return -EINVAL; + } + + return 0; +} + +static void hdd_get_link_status_cb(uint8_t status, void *context) +{ + struct statsContext *pLinkContext; + hdd_adapter_t *adapter; + + if (NULL == context) { + hdd_err("Bad context [%p]", context); + return; + } + + pLinkContext = context; + adapter = pLinkContext->pAdapter; + + spin_lock(&hdd_context_lock); + + if ((NULL == adapter) || + (LINK_STATUS_MAGIC != pLinkContext->magic)) { + /* + * the caller presumably timed out so there is + * nothing we can do + */ + spin_unlock(&hdd_context_lock); + hdd_warn("Invalid context, adapter [%p] magic [%08x]", + adapter, pLinkContext->magic); + return; + } + + /* context is valid so caller is still waiting */ + + /* paranoia: invalidate the magic */ + pLinkContext->magic = 0; + + /* copy over the status */ + adapter->linkStatus = status; + + /* notify the caller */ + complete(&pLinkContext->completion); + + /* serialization is complete */ + spin_unlock(&hdd_context_lock); +} + +/** + * wlan_hdd_get_link_status() - get link status + * @pAdapter: pointer to the adapter + * + * This function sends a request to query the link status and waits + * on a timer to invoke the callback. if the callback is invoked then + * latest link status shall be returned or otherwise cached value + * will be returned. + * + * Return: On success, link status shall be returned. + * On error or not associated, link status 0 will be returned. + */ +static int wlan_hdd_get_link_status(hdd_adapter_t *adapter) +{ + + hdd_station_ctx_t *pHddStaCtx = + WLAN_HDD_GET_STATION_CTX_PTR(adapter); + static struct statsContext context; + QDF_STATUS hstatus; + unsigned long rc; + + if (cds_is_driver_recovering()) { + hdd_warn("Recovery in Progress. State: 0x%x Ignore!!!", + cds_get_driver_state()); + return 0; + } + + if ((QDF_STA_MODE != adapter->device_mode) && + (QDF_P2P_CLIENT_MODE != adapter->device_mode)) { + hdd_warn("Unsupported in mode %s(%d)", + hdd_device_mode_to_string(adapter->device_mode), + adapter->device_mode); + return 0; + } + + pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + if (eConnectionState_Associated != pHddStaCtx->conn_info.connState) { + /* If not associated, then expected link status return + * value is 0 + */ + hdd_info("Not associated!"); + return 0; + } + + init_completion(&context.completion); + context.pAdapter = adapter; + context.magic = LINK_STATUS_MAGIC; + hstatus = sme_get_link_status(WLAN_HDD_GET_HAL_CTX(adapter), + hdd_get_link_status_cb, + &context, adapter->sessionId); + if (QDF_STATUS_SUCCESS != hstatus) { + hdd_err("Unable to retrieve link status"); + /* 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) + hdd_err("SME timed out while retrieving link status"); + } + + spin_lock(&hdd_context_lock); + context.magic = 0; + spin_unlock(&hdd_context_lock); + + /* either callback updated adapter stats or it has cached data */ + return adapter->linkStatus; +} + +static void hdd_tx_fail_ind_callback(uint8_t *MacAddr, uint8_t seqNo) +{ + int payload_len; + struct sk_buff *skb; + struct nlmsghdr *nlh; + uint8_t *data; + + payload_len = ETH_ALEN; + + if (0 == cesium_pid || cesium_nl_srv_sock == NULL) { + hdd_err("cesium process not registered"); + return; + } + + skb = nlmsg_new(payload_len, GFP_ATOMIC); + if (skb == NULL) { + hdd_err("nlmsg_new() failed for msg size[%d]", + NLMSG_SPACE(payload_len)); + return; + } + + nlh = nlmsg_put(skb, cesium_pid, seqNo, 0, payload_len, NLM_F_REQUEST); + + if (NULL == nlh) { + hdd_err("nlmsg_put() failed for msg size[%d]", + NLMSG_SPACE(payload_len)); + + kfree_skb(skb); + return; + } + + data = nlmsg_data(nlh); + memcpy(data, MacAddr, ETH_ALEN); + + if (nlmsg_unicast(cesium_nl_srv_sock, skb, cesium_pid) < 0) { + hdd_err("nlmsg_unicast() failed for msg size[%d]", + NLMSG_SPACE(payload_len)); + } + + return; +} + + +/** + * hdd_ParseuserParams - return a pointer to the next argument + * @pValue: Input argument string + * @ppArg: Output pointer to the next argument + * + * This function parses argument stream and finds the pointer + * to the next argument + * + * Return: 0 if the next argument found; -EINVAL otherwise + */ +static int hdd_parse_user_params(uint8_t *pValue, uint8_t **ppArg) +{ + uint8_t *pVal; + + pVal = strnchr(pValue, strlen(pValue), ' '); + + if (NULL == pVal) { + /* no argument remains */ + return -EINVAL; + } else if (SPACE_ASCII_VALUE != *pVal) { + /* no space after the current argument */ + return -EINVAL; + } + + pVal++; + + /* remove empty spaces */ + while ((SPACE_ASCII_VALUE == *pVal) && ('\0' != *pVal)) { + pVal++; + } + + /* no argument followed by spaces */ + if ('\0' == *pVal) { + return -EINVAL; + } + + *ppArg = pVal; + + return 0; +} + +/** + * hdd_parse_ibsstx_fail_event_params - Parse params + * for SETIBSSTXFAILEVENT + * @pValue: Input ibss tx fail event argument + * @tx_fail_count: (Output parameter) Tx fail counter + * @pid: (Output parameter) PID + * + * Return: 0 if the parsing succeeds; -EINVAL otherwise + */ +static int hdd_parse_ibsstx_fail_event_params(uint8_t *pValue, + uint8_t *tx_fail_count, + uint16_t *pid) +{ + uint8_t *param = NULL; + int ret; + + ret = hdd_parse_user_params(pValue, ¶m); + + if (0 == ret && NULL != param) { + if (1 != sscanf(param, "%hhu", tx_fail_count)) { + ret = -EINVAL; + goto done; + } + } else { + goto done; + } + + if (0 == *tx_fail_count) { + *pid = 0; + goto done; + } + + pValue = param; + pValue++; + + ret = hdd_parse_user_params(pValue, ¶m); + + if (0 == ret) { + if (1 != sscanf(param, "%hu", pid)) { + ret = -EINVAL; + goto done; + } + } else { + goto done; + } + +done: + return ret; +} + +#ifdef FEATURE_WLAN_ESE +/** + * hdd_parse_ese_beacon_req() - Parse ese beacon request + * @pValue: Pointer to data + * @pEseBcnReq: Output pointer to store parsed ie information + * + * This function parses the ese beacon request passed in the format + * CCXBEACONREQ + * Channel 1Scan Mode Meas DurationChannel N + * Scan Mode NMeas Duration N + * + * If the Number of bcn req fields (N) does not match with the + * actual number of fields passed then take N. + * and are treated + * as one pair. For example, CCXBEACONREQ 2 1 1 1 30 2 44 0 40. + * This function does not take care of removing duplicate channels from the + * list + * + * Return: 0 for success non-zero for failure + */ +static int hdd_parse_ese_beacon_req(uint8_t *pValue, + tCsrEseBeaconReq *pEseBcnReq) +{ + uint8_t *inPtr = pValue; + uint8_t input = 0; + uint32_t tempInt = 0; + int j = 0, i = 0, v = 0; + char buf[32]; + + inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE); + /* no argument after the command */ + if (NULL == inPtr) { + return -EINVAL; + } + /* no space after the command */ + else if (SPACE_ASCII_VALUE != *inPtr) { + return -EINVAL; + } + + /* remove empty spaces */ + while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr)) + inPtr++; + + /* no argument followed by spaces */ + if ('\0' == *inPtr) + return -EINVAL; + + /* Getting the first argument ie Number of IE fields */ + v = sscanf(inPtr, "%31s ", buf); + if (1 != v) + return -EINVAL; + + v = kstrtou8(buf, 10, &input); + if (v < 0) + return -EINVAL; + + input = QDF_MIN(input, SIR_ESE_MAX_MEAS_IE_REQS); + pEseBcnReq->numBcnReqIe = input; + + hdd_info("Number of Bcn Req Ie fields: %d", pEseBcnReq->numBcnReqIe); + + for (j = 0; j < (pEseBcnReq->numBcnReqIe); j++) { + for (i = 0; i < 4; i++) { + /* + * inPtr pointing to the beginning of 1st space + * after number of ie fields + */ + inPtr = strpbrk(inPtr, " "); + /* no ie data after the number of ie fields argument */ + if (NULL == inPtr) + return -EINVAL; + + /* remove empty space */ + while ((SPACE_ASCII_VALUE == *inPtr) + && ('\0' != *inPtr)) + inPtr++; + + /* + * no ie data after the number of ie fields + * argument and spaces + */ + if ('\0' == *inPtr) + return -EINVAL; + + v = sscanf(inPtr, "%31s ", buf); + if (1 != v) + return -EINVAL; + + v = kstrtou32(buf, 10, &tempInt); + if (v < 0) + return -EINVAL; + + switch (i) { + case 0: /* Measurement token */ + if (!tempInt) { + hdd_err("Invalid Measurement Token: %u", + tempInt); + return -EINVAL; + } + pEseBcnReq->bcnReq[j].measurementToken = + tempInt; + break; + + case 1: /* Channel number */ + if (!tempInt || + (tempInt > + WNI_CFG_CURRENT_CHANNEL_STAMAX)) { + hdd_err("Invalid Channel Number: %u", + tempInt); + return -EINVAL; + } + pEseBcnReq->bcnReq[j].channel = tempInt; + break; + + case 2: /* Scan mode */ + if ((tempInt < eSIR_PASSIVE_SCAN) + || (tempInt > eSIR_BEACON_TABLE)) { + hdd_err("Invalid Scan Mode: %u Expected{0|1|2}", + tempInt); + return -EINVAL; + } + pEseBcnReq->bcnReq[j].scanMode = tempInt; + break; + + case 3: /* Measurement duration */ + if ((!tempInt + && (pEseBcnReq->bcnReq[j].scanMode != + eSIR_BEACON_TABLE)) || + (pEseBcnReq->bcnReq[j].scanMode == + eSIR_BEACON_TABLE)) { + hdd_err("Invalid Measurement Duration: %u", + tempInt); + return -EINVAL; + } + pEseBcnReq->bcnReq[j].measurementDuration = + tempInt; + break; + } + } + } + + for (j = 0; j < pEseBcnReq->numBcnReqIe; j++) { + hdd_info("Index: %d Measurement Token: %u Channel: %u Scan Mode: %u Measurement Duration: %u", + j, + pEseBcnReq->bcnReq[j].measurementToken, + pEseBcnReq->bcnReq[j].channel, + pEseBcnReq->bcnReq[j].scanMode, + pEseBcnReq->bcnReq[j].measurementDuration); + } + + return 0; +} + +/** + * hdd_parse_get_cckm_ie() - HDD Parse and fetch the CCKM IE + * @pValue: Pointer to input data + * @pCckmIe: Pointer to output cckm Ie + * @pCckmIeLen: Pointer to output cckm ie length + * + * This function parses the SETCCKM IE command + * SETCCKMIE + * + * Return: 0 for success non-zero for failure + */ +static int hdd_parse_get_cckm_ie(uint8_t *pValue, uint8_t **pCckmIe, + uint8_t *pCckmIeLen) +{ + uint8_t *inPtr = pValue; + uint8_t *dataEnd; + int j = 0; + int i = 0; + uint8_t tempByte = 0; + inPtr = strnchr(pValue, strlen(pValue), SPACE_ASCII_VALUE); + /* no argument after the command */ + if (NULL == inPtr) { + return -EINVAL; + } + /* no space after the command */ + else if (SPACE_ASCII_VALUE != *inPtr) { + return -EINVAL; + } + /* remove empty spaces */ + while ((SPACE_ASCII_VALUE == *inPtr) && ('\0' != *inPtr)) + inPtr++; + /* no argument followed by spaces */ + if ('\0' == *inPtr) { + return -EINVAL; + } + /* find the length of data */ + dataEnd = inPtr; + while (('\0' != *dataEnd)) { + dataEnd++; + ++(*pCckmIeLen); + } + if (*pCckmIeLen <= 0) + return -EINVAL; + /* + * Allocate the number of bytes based on the number of input characters + * whether it is even or odd. + * if the number of input characters are even, then we need N / 2 byte. + * if the number of input characters are odd, then we need do + * (N + 1) / 2 to compensate rounding off. + * For example, if N = 18, then (18 + 1) / 2 = 9 bytes are enough. + * If N = 19, then we need 10 bytes, hence (19 + 1) / 2 = 10 bytes + */ + *pCckmIe = qdf_mem_malloc((*pCckmIeLen + 1) / 2); + if (NULL == *pCckmIe) { + hdd_err("qdf_mem_malloc failed"); + return -ENOMEM; + } + /* + * the buffer received from the upper layer is character buffer, + * we need to prepare the buffer taking 2 characters in to a U8 hex + * decimal number for example 7f0000f0...form a buffer to contain + * 7f in 0th location, 00 in 1st and f0 in 3rd location + */ + for (i = 0, j = 0; j < *pCckmIeLen; j += 2) { + tempByte = (hex_to_bin(inPtr[j]) << 4) | + (hex_to_bin(inPtr[j + 1])); + (*pCckmIe)[i++] = tempByte; + } + *pCckmIeLen = i; + return 0; +} +#endif /* FEATURE_WLAN_ESE */ + +int wlan_hdd_set_mc_rate(hdd_adapter_t *pAdapter, int targetRate) +{ + tSirRateUpdateInd rateUpdate = {0}; + QDF_STATUS status; + hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + struct hdd_config *pConfig = NULL; + + if (pHddCtx == NULL) { + hdd_err("HDD context is null"); + return -EINVAL; + } + if ((QDF_IBSS_MODE != pAdapter->device_mode) && + (QDF_SAP_MODE != pAdapter->device_mode) && + (QDF_STA_MODE != pAdapter->device_mode)) { + hdd_err("Received SETMCRATE cmd in invalid mode %s(%d)", + hdd_device_mode_to_string(pAdapter->device_mode), + pAdapter->device_mode); + hdd_err("SETMCRATE cmd is allowed only in STA, IBSS or SOFTAP mode"); + return -EINVAL; + } + pConfig = pHddCtx->config; + rateUpdate.nss = (pConfig->enable2x2 == 0) ? 0 : 1; + rateUpdate.dev_mode = pAdapter->device_mode; + rateUpdate.mcastDataRate24GHz = targetRate; + rateUpdate.mcastDataRate24GHzTxFlag = 1; + rateUpdate.mcastDataRate5GHz = targetRate; + rateUpdate.bcastDataRate = -1; + qdf_copy_macaddr(&rateUpdate.bssid, &pAdapter->macAddressCurrent); + hdd_info("MC Target rate %d, mac = %pM, dev_mode %s(%d)", + rateUpdate.mcastDataRate24GHz, rateUpdate.bssid.bytes, + hdd_device_mode_to_string(pAdapter->device_mode), + pAdapter->device_mode); + status = sme_send_rate_update_ind(pHddCtx->hHal, &rateUpdate); + if (QDF_STATUS_SUCCESS != status) { + hdd_err("SETMCRATE failed"); + return -EFAULT; + } + return 0; +} + +static int drv_cmd_p2p_dev_addr(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret = 0; + + MTRACE(qdf_trace(QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_P2P_DEV_ADDR_IOCTL, + adapter->sessionId, + (unsigned)(*(hdd_ctx->p2pDeviceAddress.bytes + 2) + << 24 | *(hdd_ctx->p2pDeviceAddress.bytes + + 3) << 16 | *(hdd_ctx-> + p2pDeviceAddress.bytes + 4) << 8 | + *(hdd_ctx->p2pDeviceAddress.bytes + + 5)))); + + if (copy_to_user(priv_data->buf, hdd_ctx->p2pDeviceAddress.bytes, + sizeof(tSirMacAddr))) { + hdd_err("failed to copy data to user buffer"); + ret = -EFAULT; + } + + return ret; +} + +/** + * drv_cmd_p2p_set_noa() - Handler for P2P_SET_NOA driver command + * @adapter: Adapter on which the command was received + * @hdd_ctx: HDD global context + * @command: Entire driver command received from userspace + * @command_len: Length of @command + * @priv_data: Pointer to ioctl private data structure + * + * This is a trivial command hander function which simply forwards the + * command to the actual command processor within the P2P module. + * + * Return: 0 on success, non-zero on failure + */ +static int drv_cmd_p2p_set_noa(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + return hdd_set_p2p_noa(adapter->dev, command); +} + +/** + * drv_cmd_p2p_set_ps() - Handler for P2P_SET_PS driver command + * @adapter: Adapter on which the command was received + * @hdd_ctx: HDD global context + * @command: Entire driver command received from userspace + * @command_len: Length of @command + * @priv_data: Pointer to ioctl private data structure + * + * This is a trivial command hander function which simply forwards the + * command to the actual command processor within the P2P module. + * + * Return: 0 on success, non-zero on failure + */ +static int drv_cmd_p2p_set_ps(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + return hdd_set_p2p_opps(adapter->dev, command); +} + +static int drv_cmd_set_band(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret = 0; + + uint8_t *ptr = command; + + /* Change band request received */ + + /* + * First 8 bytes will have "SETBAND " and + * 9 byte will have band setting value + */ + hdd_info("SetBandCommand Info comm %s UL %d, TL %d", + command, priv_data->used_len, + priv_data->total_len); + + /* Change band request received */ + ret = hdd_set_band_helper(adapter->dev, ptr); + + return ret; +} + +static int drv_cmd_set_wmmps(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + return hdd_wmmps_helper(adapter, command); +} + +static int drv_cmd_country(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret = 0; + QDF_STATUS status; + unsigned long rc; + char *country_code; + + country_code = command + 8; + + INIT_COMPLETION(adapter->change_country_code); + + status = sme_change_country_code(hdd_ctx->hHal, + wlan_hdd_change_country_code_callback, + country_code, + adapter, + hdd_ctx->pcds_context, + eSIR_TRUE, + eSIR_TRUE); + if (status == QDF_STATUS_SUCCESS) { + rc = wait_for_completion_timeout( + &adapter->change_country_code, + msecs_to_jiffies(WLAN_WAIT_TIME_COUNTRY)); + if (!rc) + hdd_err("SME while setting country code timed out"); + } else { + hdd_err("SME Change Country code fail, status %d", + status); + ret = -EINVAL; + } + + return ret; +} + +static int drv_cmd_set_roam_trigger(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret = 0; + uint8_t *value = command; + int8_t rssi = 0; + uint8_t lookUpThreshold = CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_DEFAULT; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + /* Move pointer to ahead of SETROAMTRIGGER */ + value = value + command_len + 1; + + /* Convert the value from ascii to integer */ + ret = kstrtos8(value, 10, &rssi); + if (ret < 0) { + /* + * If the input value is greater than max value of datatype, + * then also kstrtou8 fails + */ + hdd_err("kstrtou8 failed Input value may be out of range[%d - %d]", + CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MIN, + CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MAX); + ret = -EINVAL; + goto exit; + } + + lookUpThreshold = abs(rssi); + + if ((lookUpThreshold < CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MIN) + || (lookUpThreshold > CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MAX)) { + hdd_err("Neighbor lookup threshold value %d is out of range (Min: %d Max: %d)", + lookUpThreshold, + CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MIN, + CFG_NEIGHBOR_LOOKUP_RSSI_THRESHOLD_MAX); + ret = -EINVAL; + goto exit; + } + + MTRACE(qdf_trace(QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_SETROAMTRIGGER_IOCTL, + adapter->sessionId, lookUpThreshold)); + hdd_info("Received Command to Set Roam trigger (Neighbor lookup threshold) = %d", + lookUpThreshold); + + hdd_ctx->config->nNeighborLookupRssiThreshold = lookUpThreshold; + status = sme_set_neighbor_lookup_rssi_threshold(hdd_ctx->hHal, + adapter->sessionId, + lookUpThreshold); + if (QDF_STATUS_SUCCESS != status) { + hdd_err("Failed to set roam trigger, try again"); + ret = -EPERM; + goto exit; + } + +exit: + return ret; +} + +static int drv_cmd_get_roam_trigger(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret = 0; + uint8_t lookUpThreshold = + sme_get_neighbor_lookup_rssi_threshold(hdd_ctx->hHal); + int rssi = (-1) * lookUpThreshold; + char extra[32]; + uint8_t len = 0; + + MTRACE(qdf_trace(QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_GETROAMTRIGGER_IOCTL, + adapter->sessionId, lookUpThreshold)); + + len = scnprintf(extra, sizeof(extra), "%s %d", command, rssi); + len = QDF_MIN(priv_data->total_len, len + 1); + if (copy_to_user(priv_data->buf, &extra, len)) { + hdd_err("failed to copy data to user buffer"); + ret = -EFAULT; + } + + return ret; +} + +static int drv_cmd_set_roam_scan_period(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret = 0; + uint8_t *value = command; + uint8_t roamScanPeriod = 0; + uint16_t neighborEmptyScanRefreshPeriod = + CFG_EMPTY_SCAN_REFRESH_PERIOD_DEFAULT; + + /* input refresh period is in terms of seconds */ + + /* Move pointer to ahead of SETROAMSCANPERIOD */ + value = value + command_len + 1; + + /* Convert the value from ascii to integer */ + ret = kstrtou8(value, 10, &roamScanPeriod); + if (ret < 0) { + /* + * If the input value is greater than max value of datatype, + * then also kstrtou8 fails + */ + hdd_err("kstrtou8 failed Input value may be out of range[%d - %d]", + (CFG_EMPTY_SCAN_REFRESH_PERIOD_MIN / 1000), + (CFG_EMPTY_SCAN_REFRESH_PERIOD_MAX / 1000)); + ret = -EINVAL; + goto exit; + } + + if ((roamScanPeriod < (CFG_EMPTY_SCAN_REFRESH_PERIOD_MIN / 1000)) + || (roamScanPeriod > (CFG_EMPTY_SCAN_REFRESH_PERIOD_MAX / 1000))) { + hdd_err("Roam scan period value %d is out of range (Min: %d Max: %d)", + roamScanPeriod, + (CFG_EMPTY_SCAN_REFRESH_PERIOD_MIN / 1000), + (CFG_EMPTY_SCAN_REFRESH_PERIOD_MAX / 1000)); + ret = -EINVAL; + goto exit; + } + MTRACE(qdf_trace(QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_SETROAMSCANPERIOD_IOCTL, + adapter->sessionId, roamScanPeriod)); + neighborEmptyScanRefreshPeriod = roamScanPeriod * 1000; + + hdd_info("Received Command to Set roam scan period (Empty Scan refresh period) = %d", + roamScanPeriod); + + hdd_ctx->config->nEmptyScanRefreshPeriod = + neighborEmptyScanRefreshPeriod; + sme_update_empty_scan_refresh_period(hdd_ctx->hHal, + adapter->sessionId, + neighborEmptyScanRefreshPeriod); + +exit: + return ret; +} + +static int drv_cmd_get_roam_scan_period(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret = 0; + uint16_t nEmptyScanRefreshPeriod = + sme_get_empty_scan_refresh_period(hdd_ctx->hHal); + char extra[32]; + uint8_t len = 0; + + MTRACE(qdf_trace(QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_GETROAMSCANPERIOD_IOCTL, + adapter->sessionId, + nEmptyScanRefreshPeriod)); + len = scnprintf(extra, sizeof(extra), "%s %d", + "GETROAMSCANPERIOD", + (nEmptyScanRefreshPeriod / 1000)); + /* Returned value is in units of seconds */ + len = QDF_MIN(priv_data->total_len, len + 1); + if (copy_to_user(priv_data->buf, &extra, len)) { + hdd_err("failed to copy data to user buffer"); + ret = -EFAULT; + } + + return ret; +} + +static int drv_cmd_set_roam_scan_refresh_period(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret = 0; + uint8_t *value = command; + uint8_t roamScanRefreshPeriod = 0; + uint16_t neighborScanRefreshPeriod = + CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_DEFAULT; + + /* input refresh period is in terms of seconds */ + /* Move pointer to ahead of SETROAMSCANREFRESHPERIOD */ + value = value + command_len + 1; + + /* Convert the value from ascii to integer */ + ret = kstrtou8(value, 10, &roamScanRefreshPeriod); + if (ret < 0) { + /* + * If the input value is greater than max value of datatype, + * then also kstrtou8 fails + */ + hdd_err("kstrtou8 failed Input value may be out of range[%d - %d]", + CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MIN / 1000, + CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MAX / 1000); + ret = -EINVAL; + goto exit; + } + + if ((roamScanRefreshPeriod < + (CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MIN / 1000)) + || (roamScanRefreshPeriod > + (CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MAX / 1000))) { + hdd_err("Neighbor scan results refresh period value %d is out of range (Min: %d Max: %d)", + roamScanRefreshPeriod, + (CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MIN + / 1000), + (CFG_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD_MAX + / 1000)); + ret = -EINVAL; + goto exit; + } + neighborScanRefreshPeriod = roamScanRefreshPeriod * 1000; + + hdd_info("Received Command to Set roam scan refresh period (Scan refresh period) = %d", + roamScanRefreshPeriod); + + hdd_ctx->config->nNeighborResultsRefreshPeriod = + neighborScanRefreshPeriod; + sme_set_neighbor_scan_refresh_period(hdd_ctx->hHal, + adapter->sessionId, + neighborScanRefreshPeriod); + +exit: + return ret; +} + +static int drv_cmd_get_roam_scan_refresh_period(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret = 0; + uint16_t value = + sme_get_neighbor_scan_refresh_period(hdd_ctx->hHal); + char extra[32]; + uint8_t len = 0; + + len = scnprintf(extra, sizeof(extra), "%s %d", + "GETROAMSCANREFRESHPERIOD", + (value / 1000)); + /* Returned value is in units of seconds */ + len = QDF_MIN(priv_data->total_len, len + 1); + if (copy_to_user(priv_data->buf, &extra, len)) { + hdd_err("failed to copy data to user buffer"); + ret = -EFAULT; + } + + return ret; +} + +static int drv_cmd_set_roam_mode(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret = 0; + uint8_t *value = command; + uint8_t roamMode = CFG_LFR_FEATURE_ENABLED_DEFAULT; + + if (!adapter->fast_roaming_allowed) { + hdd_err("Roaming is always disabled on this interface"); + goto exit; + } + + /* Move pointer to ahead of SETROAMMODE */ + value = value + SIZE_OF_SETROAMMODE + 1; + + /* Convert the value from ascii to integer */ + ret = kstrtou8(value, SIZE_OF_SETROAMMODE, &roamMode); + if (ret < 0) { + /* + * If the input value is greater than max value of datatype, + * then also kstrtou8 fails + */ + hdd_err("kstrtou8 failed range [%d - %d]", + CFG_LFR_FEATURE_ENABLED_MIN, + CFG_LFR_FEATURE_ENABLED_MAX); + ret = -EINVAL; + goto exit; + } + if ((roamMode < CFG_LFR_FEATURE_ENABLED_MIN) || + (roamMode > CFG_LFR_FEATURE_ENABLED_MAX)) { + hdd_err("Roam Mode value %d is out of range (Min: %d Max: %d)", + roamMode, + CFG_LFR_FEATURE_ENABLED_MIN, + CFG_LFR_FEATURE_ENABLED_MAX); + ret = -EINVAL; + goto exit; + } + + hdd_debug("Received Command to Set Roam Mode = %d", + roamMode); + /* + * Note that + * SETROAMMODE 0 is to enable LFR while + * SETROAMMODE 1 is to disable LFR, but + * notify_is_fast_roam_ini_feature_enabled 0/1 is to + * enable/disable. So, we have to invert the value + * to call sme_update_is_fast_roam_ini_feature_enabled. + */ + if (CFG_LFR_FEATURE_ENABLED_MIN == roamMode) + roamMode = CFG_LFR_FEATURE_ENABLED_MAX; /* Roam enable */ + else + roamMode = CFG_LFR_FEATURE_ENABLED_MIN; /* Roam disable */ + + hdd_ctx->config->isFastRoamIniFeatureEnabled = roamMode; + if (roamMode) { + hdd_ctx->config->isRoamOffloadScanEnabled = roamMode; + sme_update_roam_scan_offload_enabled( + (tHalHandle)(hdd_ctx->hHal), + hdd_ctx->config->isRoamOffloadScanEnabled); + sme_update_is_fast_roam_ini_feature_enabled( + hdd_ctx->hHal, + adapter->sessionId, + roamMode); + } else { + sme_update_is_fast_roam_ini_feature_enabled( + hdd_ctx->hHal, + adapter->sessionId, + roamMode); + hdd_ctx->config->isRoamOffloadScanEnabled = roamMode; + sme_update_roam_scan_offload_enabled( + (tHalHandle)(hdd_ctx->hHal), + hdd_ctx->config->isRoamOffloadScanEnabled); + } + + +exit: + return ret; +} + +static int drv_cmd_get_roam_mode(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret = 0; + bool roamMode = sme_get_is_lfr_feature_enabled(hdd_ctx->hHal); + char extra[32]; + uint8_t len = 0; + + /* + * roamMode value shall be inverted because the sementics is different. + */ + if (CFG_LFR_FEATURE_ENABLED_MIN == roamMode) + roamMode = CFG_LFR_FEATURE_ENABLED_MAX; + else + roamMode = CFG_LFR_FEATURE_ENABLED_MIN; + + len = scnprintf(extra, sizeof(extra), "%s %d", command, roamMode); + len = QDF_MIN(priv_data->total_len, len + 1); + if (copy_to_user(priv_data->buf, &extra, len)) { + hdd_err("failed to copy data to user buffer"); + ret = -EFAULT; + } + + return ret; +} + +static int drv_cmd_set_roam_delta(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret = 0; + uint8_t *value = command; + uint8_t roamRssiDiff = CFG_ROAM_RSSI_DIFF_DEFAULT; + + /* Move pointer to ahead of SETROAMDELTA */ + value = value + command_len + 1; + + /* Convert the value from ascii to integer */ + ret = kstrtou8(value, 10, &roamRssiDiff); + if (ret < 0) { + /* + * If the input value is greater than max value of datatype, + * then also kstrtou8 fails + */ + hdd_err("kstrtou8 failed range [%d - %d]", + CFG_ROAM_RSSI_DIFF_MIN, + CFG_ROAM_RSSI_DIFF_MAX); + ret = -EINVAL; + goto exit; + } + + if ((roamRssiDiff < CFG_ROAM_RSSI_DIFF_MIN) || + (roamRssiDiff > CFG_ROAM_RSSI_DIFF_MAX)) { + hdd_err("Roam rssi diff value %d is out of range (Min: %d Max: %d)", + roamRssiDiff, + CFG_ROAM_RSSI_DIFF_MIN, + CFG_ROAM_RSSI_DIFF_MAX); + ret = -EINVAL; + goto exit; + } + + hdd_info("Received Command to Set roam rssi diff = %d", + roamRssiDiff); + + hdd_ctx->config->RoamRssiDiff = roamRssiDiff; + sme_update_roam_rssi_diff(hdd_ctx->hHal, + adapter->sessionId, + roamRssiDiff); + +exit: + return ret; +} + +static int drv_cmd_get_roam_delta(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret = 0; + uint8_t roamRssiDiff = + sme_get_roam_rssi_diff(hdd_ctx->hHal); + char extra[32]; + uint8_t len = 0; + + MTRACE(qdf_trace(QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_GETROAMDELTA_IOCTL, + adapter->sessionId, roamRssiDiff)); + + len = scnprintf(extra, sizeof(extra), "%s %d", + command, roamRssiDiff); + len = QDF_MIN(priv_data->total_len, len + 1); + + if (copy_to_user(priv_data->buf, &extra, len)) { + hdd_err("failed to copy data to user buffer"); + ret = -EFAULT; + } + + return ret; +} + +static int drv_cmd_get_band(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret = 0; + int band = -1; + char extra[32]; + uint8_t len = 0; + + hdd_get_band_helper(hdd_ctx, &band); + + MTRACE(qdf_trace(QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_GETBAND_IOCTL, + adapter->sessionId, band)); + + len = scnprintf(extra, sizeof(extra), "%s %d", command, band); + len = QDF_MIN(priv_data->total_len, len + 1); + + if (copy_to_user(priv_data->buf, &extra, len)) { + hdd_err("failed to copy data to user buffer"); + ret = -EFAULT; + } + + return ret; +} + +static int drv_cmd_set_roam_scan_channels(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + return hdd_parse_set_roam_scan_channels(adapter, command); +} + +static int drv_cmd_get_roam_scan_channels(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret = 0; + uint8_t ChannelList[WNI_CFG_VALID_CHANNEL_LIST_LEN] = { 0 }; + uint8_t numChannels = 0; + uint8_t j = 0; + char extra[128] = { 0 }; + int len; + + if (QDF_STATUS_SUCCESS != + sme_get_roam_scan_channel_list(hdd_ctx->hHal, + ChannelList, + &numChannels, + adapter->sessionId)) { + hdd_alert("failed to get roam scan channel list"); + ret = -EFAULT; + goto exit; + } + + MTRACE(qdf_trace(QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_GETROAMSCANCHANNELS_IOCTL, + adapter->sessionId, numChannels)); + /* + * output channel list is of the format + * [Number of roam scan channels][Channel1][Channel2]... + * copy the number of channels in the 0th index + */ + len = scnprintf(extra, sizeof(extra), "%s %d", command, + numChannels); + for (j = 0; (j < numChannels) && len <= sizeof(extra); j++) + len += scnprintf(extra + len, sizeof(extra) - len, + " %d", ChannelList[j]); + + len = QDF_MIN(priv_data->total_len, len + 1); + if (copy_to_user(priv_data->buf, &extra, len)) { + hdd_err("failed to copy data to user buffer"); + ret = -EFAULT; + goto exit; + } + +exit: + return ret; +} + +static int drv_cmd_get_ccx_mode(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret = 0; + bool eseMode = sme_get_is_ese_feature_enabled(hdd_ctx->hHal); + char extra[32]; + uint8_t len = 0; + struct pmkid_mode_bits pmkid_modes; + + hdd_get_pmkid_modes(hdd_ctx, &pmkid_modes); + /* + * Check if the features PMKID/ESE/11R are supported simultaneously, + * then this operation is not permitted (return FAILURE) + */ + if (eseMode && + (pmkid_modes.fw_okc || pmkid_modes.fw_pmksa_cache) && + sme_get_is_ft_feature_enabled(hdd_ctx->hHal)) { + hdd_warn("PMKID/ESE/11R are supported simultaneously hence this operation is not permitted!"); + ret = -EPERM; + goto exit; + } + + len = scnprintf(extra, sizeof(extra), "%s %d", + "GETCCXMODE", eseMode); + len = QDF_MIN(priv_data->total_len, len + 1); + if (copy_to_user(priv_data->buf, &extra, len)) { + hdd_err("failed to copy data to user buffer"); + ret = -EFAULT; + goto exit; + } + +exit: + return ret; +} + +static int drv_cmd_get_okc_mode(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret = 0; + struct pmkid_mode_bits pmkid_modes; + char extra[32]; + uint8_t len = 0; + + hdd_get_pmkid_modes(hdd_ctx, &pmkid_modes); + /* + * Check if the features OKC/ESE/11R are supported simultaneously, + * then this operation is not permitted (return FAILURE) + */ + if (pmkid_modes.fw_okc && + sme_get_is_ese_feature_enabled(hdd_ctx->hHal) && + sme_get_is_ft_feature_enabled(hdd_ctx->hHal)) { + hdd_warn("PMKID/ESE/11R are supported simultaneously hence this operation is not permitted!"); + ret = -EPERM; + goto exit; + } + + len = scnprintf(extra, sizeof(extra), "%s %d", + "GETOKCMODE", pmkid_modes.fw_okc); + len = QDF_MIN(priv_data->total_len, len + 1); + + if (copy_to_user(priv_data->buf, &extra, len)) { + hdd_err("failed to copy data to user buffer"); + ret = -EFAULT; + goto exit; + } + +exit: + return ret; +} + +static int drv_cmd_get_fast_roam(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret = 0; + bool lfrMode = sme_get_is_lfr_feature_enabled(hdd_ctx->hHal); + char extra[32]; + uint8_t len = 0; + + len = scnprintf(extra, sizeof(extra), "%s %d", + "GETFASTROAM", lfrMode); + len = QDF_MIN(priv_data->total_len, len + 1); + + if (copy_to_user(priv_data->buf, &extra, len)) { + hdd_err("failed to copy data to user buffer"); + ret = -EFAULT; + } + + return ret; +} + +static int drv_cmd_get_fast_transition(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret = 0; + bool ft = sme_get_is_ft_feature_enabled(hdd_ctx->hHal); + char extra[32]; + uint8_t len = 0; + + len = scnprintf(extra, sizeof(extra), "%s %d", + "GETFASTTRANSITION", ft); + len = QDF_MIN(priv_data->total_len, len + 1); + + if (copy_to_user(priv_data->buf, &extra, len)) { + hdd_err("failed to copy data to user buffer"); + ret = -EFAULT; + } + + return ret; +} + +static int drv_cmd_set_roam_scan_channel_min_time(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret = 0; + uint8_t *value = command; + uint8_t minTime = CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_DEFAULT; + + /* Move pointer to ahead of SETROAMSCANCHANNELMINTIME */ + value = value + command_len + 1; + + /* Convert the value from ascii to integer */ + ret = kstrtou8(value, 10, &minTime); + if (ret < 0) { + /* + * If the input value is greater than max value of datatype, + * then also kstrtou8 fails + */ + hdd_err("kstrtou8 failed range [%d - %d]", + CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MIN, + CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MAX); + ret = -EINVAL; + goto exit; + } + + if ((minTime < CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MIN) || + (minTime > CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MAX)) { + hdd_err("scan min channel time value %d is out of range (Min: %d Max: %d)", + minTime, + CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MIN, + CFG_NEIGHBOR_SCAN_MIN_CHAN_TIME_MAX); + ret = -EINVAL; + goto exit; + } + + MTRACE(qdf_trace(QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_SETROAMSCANCHANNELMINTIME_IOCTL, + adapter->sessionId, minTime)); + hdd_info("Received Command to change channel min time = %d", + minTime); + + hdd_ctx->config->nNeighborScanMinChanTime = minTime; + sme_set_neighbor_scan_min_chan_time(hdd_ctx->hHal, + minTime, + adapter->sessionId); + +exit: + return ret; +} + +static int drv_cmd_send_action_frame(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + return hdd_parse_sendactionframe(adapter, command, + priv_data->total_len); +} + +static int drv_cmd_get_roam_scan_channel_min_time(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret = 0; + uint16_t val = sme_get_neighbor_scan_min_chan_time(hdd_ctx->hHal, + adapter->sessionId); + char extra[32]; + uint8_t len = 0; + + /* value is interms of msec */ + len = scnprintf(extra, sizeof(extra), "%s %d", + "GETROAMSCANCHANNELMINTIME", val); + len = QDF_MIN(priv_data->total_len, len + 1); + + MTRACE(qdf_trace(QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_GETROAMSCANCHANNELMINTIME_IOCTL, + adapter->sessionId, val)); + + if (copy_to_user(priv_data->buf, &extra, len)) { + hdd_err("failed to copy data to user buffer"); + ret = -EFAULT; + } + + return ret; +} + +static int drv_cmd_set_scan_channel_time(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret = 0; + uint8_t *value = command; + uint16_t maxTime = CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_DEFAULT; + + /* Move pointer to ahead of SETSCANCHANNELTIME */ + value = value + command_len + 1; + + /* Convert the value from ascii to integer */ + ret = kstrtou16(value, 10, &maxTime); + if (ret < 0) { + /* + * If the input value is greater than max value of datatype, + * then also kstrtou8 fails + */ + hdd_err("kstrtou16 failed range [%d - %d]", + CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MIN, + CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MAX); + ret = -EINVAL; + goto exit; + } + + if ((maxTime < CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MIN) || + (maxTime > CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MAX)) { + hdd_err("lfr mode value %d is out of range (Min: %d Max: %d)", + maxTime, + CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MIN, + CFG_NEIGHBOR_SCAN_MAX_CHAN_TIME_MAX); + ret = -EINVAL; + goto exit; + } + + hdd_info("Received Command to change channel max time = %d", + maxTime); + + hdd_ctx->config->nNeighborScanMaxChanTime = maxTime; + sme_set_neighbor_scan_max_chan_time(hdd_ctx->hHal, + adapter->sessionId, + maxTime); + +exit: + return ret; +} + +static int drv_cmd_get_scan_channel_time(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret = 0; + uint16_t val = sme_get_neighbor_scan_max_chan_time(hdd_ctx->hHal, + adapter->sessionId); + char extra[32]; + uint8_t len = 0; + + /* value is interms of msec */ + len = scnprintf(extra, sizeof(extra), "%s %d", + "GETSCANCHANNELTIME", val); + len = QDF_MIN(priv_data->total_len, len + 1); + + if (copy_to_user(priv_data->buf, &extra, len)) { + hdd_err("failed to copy data to user buffer"); + ret = -EFAULT; + } + + return ret; +} + +static int drv_cmd_set_scan_home_time(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret = 0; + uint8_t *value = command; + uint16_t val = CFG_NEIGHBOR_SCAN_TIMER_PERIOD_DEFAULT; + + /* Move pointer to ahead of SETSCANHOMETIME */ + value = value + command_len + 1; + + /* Convert the value from ascii to integer */ + ret = kstrtou16(value, 10, &val); + if (ret < 0) { + /* + * If the input value is greater than max value of datatype, + * then also kstrtou8 fails + */ + hdd_err("kstrtou16 failed range [%d - %d]", + CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MIN, + CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MAX); + ret = -EINVAL; + goto exit; + } + + if ((val < CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MIN) || + (val > CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MAX)) { + hdd_err("scan home time value %d is out of range (Min: %d Max: %d)", + val, + CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MIN, + CFG_NEIGHBOR_SCAN_TIMER_PERIOD_MAX); + ret = -EINVAL; + goto exit; + } + + hdd_info("Received Command to change scan home time = %d", + val); + + hdd_ctx->config->nNeighborScanPeriod = val; + sme_set_neighbor_scan_period(hdd_ctx->hHal, + adapter->sessionId, val); + +exit: + return ret; +} + +static int drv_cmd_get_scan_home_time(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret = 0; + uint16_t val = sme_get_neighbor_scan_period(hdd_ctx->hHal, + adapter-> + sessionId); + char extra[32]; + uint8_t len = 0; + + /* value is interms of msec */ + len = scnprintf(extra, sizeof(extra), "%s %d", + "GETSCANHOMETIME", val); + len = QDF_MIN(priv_data->total_len, len + 1); + + if (copy_to_user(priv_data->buf, &extra, len)) { + hdd_err("failed to copy data to user buffer"); + ret = -EFAULT; + } + + return ret; +} + +static int drv_cmd_set_roam_intra_band(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret = 0; + uint8_t *value = command; + uint8_t val = CFG_ROAM_INTRA_BAND_DEFAULT; + + /* Move pointer to ahead of SETROAMINTRABAND */ + value = value + command_len + 1; + + /* Convert the value from ascii to integer */ + ret = kstrtou8(value, 10, &val); + if (ret < 0) { + /* + * If the input value is greater than max value of datatype, + * then also kstrtou8 fails + */ + hdd_err("kstrtou8 failed range [%d - %d]", + CFG_ROAM_INTRA_BAND_MIN, + CFG_ROAM_INTRA_BAND_MAX); + ret = -EINVAL; + goto exit; + } + + if ((val < CFG_ROAM_INTRA_BAND_MIN) || + (val > CFG_ROAM_INTRA_BAND_MAX)) { + hdd_err("intra band mode value %d is out of range (Min: %d Max: %d)", + val, + CFG_ROAM_INTRA_BAND_MIN, + CFG_ROAM_INTRA_BAND_MAX); + ret = -EINVAL; + goto exit; + } + hdd_info("Received Command to change intra band = %d", + val); + + hdd_ctx->config->nRoamIntraBand = val; + sme_set_roam_intra_band(hdd_ctx->hHal, val); + +exit: + return ret; +} + +static int drv_cmd_get_roam_intra_band(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret = 0; + uint16_t val = sme_get_roam_intra_band(hdd_ctx->hHal); + char extra[32]; + uint8_t len = 0; + + /* value is interms of msec */ + len = scnprintf(extra, sizeof(extra), "%s %d", + "GETROAMINTRABAND", val); + len = QDF_MIN(priv_data->total_len, len + 1); + if (copy_to_user(priv_data->buf, &extra, len)) { + hdd_err("failed to copy data to user buffer"); + ret = -EFAULT; + } + + return ret; +} + +static int drv_cmd_set_scan_n_probes(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret = 0; + uint8_t *value = command; + uint8_t nProbes = CFG_ROAM_SCAN_N_PROBES_DEFAULT; + + /* Move pointer to ahead of SETSCANNPROBES */ + value = value + command_len + 1; + + /* Convert the value from ascii to integer */ + ret = kstrtou8(value, 10, &nProbes); + if (ret < 0) { + /* + * If the input value is greater than max value of datatype, + * then also kstrtou8 fails + */ + hdd_err("kstrtou8 failed range [%d - %d]", + CFG_ROAM_SCAN_N_PROBES_MIN, + CFG_ROAM_SCAN_N_PROBES_MAX); + ret = -EINVAL; + goto exit; + } + + if ((nProbes < CFG_ROAM_SCAN_N_PROBES_MIN) || + (nProbes > CFG_ROAM_SCAN_N_PROBES_MAX)) { + hdd_err("NProbes value %d is out of range (Min: %d Max: %d)", + nProbes, + CFG_ROAM_SCAN_N_PROBES_MIN, + CFG_ROAM_SCAN_N_PROBES_MAX); + ret = -EINVAL; + goto exit; + } + + hdd_info("Received Command to Set nProbes = %d", + nProbes); + + hdd_ctx->config->nProbes = nProbes; + sme_update_roam_scan_n_probes(hdd_ctx->hHal, + adapter->sessionId, nProbes); + +exit: + return ret; +} + +static int drv_cmd_get_scan_n_probes(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret = 0; + uint8_t val = sme_get_roam_scan_n_probes(hdd_ctx->hHal); + char extra[32]; + uint8_t len = 0; + + len = scnprintf(extra, sizeof(extra), "%s %d", command, val); + len = QDF_MIN(priv_data->total_len, len + 1); + if (copy_to_user(priv_data->buf, &extra, len)) { + hdd_err("failed to copy data to user buffer"); + ret = -EFAULT; + } + + return ret; +} + +static int drv_cmd_set_scan_home_away_time(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret = 0; + uint8_t *value = command; + uint16_t homeAwayTime = CFG_ROAM_SCAN_HOME_AWAY_TIME_DEFAULT; + + /* input value is in units of msec */ + + /* Move pointer to ahead of SETSCANHOMEAWAYTIME */ + value = value + command_len + 1; + + /* Convert the value from ascii to integer */ + ret = kstrtou16(value, 10, &homeAwayTime); + if (ret < 0) { + /* + * If the input value is greater than max value of datatype, + * then also kstrtou8 fails + */ + hdd_err("kstrtou8 failed range [%d - %d]", + CFG_ROAM_SCAN_HOME_AWAY_TIME_MIN, + CFG_ROAM_SCAN_HOME_AWAY_TIME_MAX); + ret = -EINVAL; + goto exit; + } + + if ((homeAwayTime < CFG_ROAM_SCAN_HOME_AWAY_TIME_MIN) || + (homeAwayTime > CFG_ROAM_SCAN_HOME_AWAY_TIME_MAX)) { + hdd_err("homeAwayTime value %d is out of range (Min: %d Max: %d)", + homeAwayTime, + CFG_ROAM_SCAN_HOME_AWAY_TIME_MIN, + CFG_ROAM_SCAN_HOME_AWAY_TIME_MAX); + ret = -EINVAL; + goto exit; + } + + hdd_info("Received Command to Set scan away time = %d", + homeAwayTime); + + if (hdd_ctx->config->nRoamScanHomeAwayTime != + homeAwayTime) { + hdd_ctx->config->nRoamScanHomeAwayTime = homeAwayTime; + sme_update_roam_scan_home_away_time(hdd_ctx->hHal, + adapter->sessionId, + homeAwayTime, + true); + } + +exit: + return ret; +} + +static int drv_cmd_get_scan_home_away_time(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret = 0; + uint16_t val = sme_get_roam_scan_home_away_time(hdd_ctx->hHal); + char extra[32]; + uint8_t len = 0; + + len = scnprintf(extra, sizeof(extra), "%s %d", command, val); + len = QDF_MIN(priv_data->total_len, len + 1); + + if (copy_to_user(priv_data->buf, &extra, len)) { + hdd_err("failed to copy data to user buffer"); + ret = -EFAULT; + } + + return ret; +} + +static int drv_cmd_reassoc(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + return hdd_parse_reassoc(adapter, command); +} + +static int drv_cmd_set_wes_mode(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret = 0; + uint8_t *value = command; + uint8_t wesMode = CFG_ENABLE_WES_MODE_NAME_DEFAULT; + + /* Move pointer to ahead of SETWESMODE */ + value = value + command_len + 1; + + /* Convert the value from ascii to integer */ + ret = kstrtou8(value, 10, &wesMode); + if (ret < 0) { + /* + * If the input value is greater than max value of datatype, + * then also kstrtou8 fails + */ + hdd_err("kstrtou8 failed range [%d - %d]", + CFG_ENABLE_WES_MODE_NAME_MIN, + CFG_ENABLE_WES_MODE_NAME_MAX); + ret = -EINVAL; + goto exit; + } + + if ((wesMode < CFG_ENABLE_WES_MODE_NAME_MIN) || + (wesMode > CFG_ENABLE_WES_MODE_NAME_MAX)) { + hdd_err("WES Mode value %d is out of range (Min: %d Max: %d)", + wesMode, + CFG_ENABLE_WES_MODE_NAME_MIN, + CFG_ENABLE_WES_MODE_NAME_MAX); + ret = -EINVAL; + goto exit; + } + + hdd_info("Received Command to Set WES Mode rssi diff = %d", + wesMode); + + hdd_ctx->config->isWESModeEnabled = wesMode; + sme_update_wes_mode(hdd_ctx->hHal, wesMode, adapter->sessionId); + +exit: + return ret; +} + +static int drv_cmd_get_wes_mode(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret = 0; + bool wesMode = sme_get_wes_mode(hdd_ctx->hHal); + char extra[32]; + uint8_t len = 0; + + len = scnprintf(extra, sizeof(extra), "%s %d", command, wesMode); + len = QDF_MIN(priv_data->total_len, len + 1); + if (copy_to_user(priv_data->buf, &extra, len)) { + hdd_err("failed to copy data to user buffer"); + ret = -EFAULT; + } + + return ret; +} + +static int drv_cmd_set_opportunistic_rssi_diff(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret = 0; + uint8_t *value = command; + uint8_t nOpportunisticThresholdDiff = + CFG_OPPORTUNISTIC_SCAN_THRESHOLD_DIFF_DEFAULT; + + /* Move pointer to ahead of SETOPPORTUNISTICRSSIDIFF */ + value = value + command_len + 1; + + /* Convert the value from ascii to integer */ + ret = kstrtou8(value, 10, &nOpportunisticThresholdDiff); + if (ret < 0) { + /* + * If the input value is greater than max value of datatype, + * then also kstrtou8 fails + */ + hdd_err("kstrtou8 failed."); + ret = -EINVAL; + goto exit; + } + + hdd_info("Received Command to Set Opportunistic Threshold diff = %d", + nOpportunisticThresholdDiff); + + sme_set_roam_opportunistic_scan_threshold_diff(hdd_ctx->hHal, + adapter->sessionId, + nOpportunisticThresholdDiff); + +exit: + return ret; +} + +static int drv_cmd_get_opportunistic_rssi_diff(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret = 0; + int8_t val = sme_get_roam_opportunistic_scan_threshold_diff( + hdd_ctx->hHal); + char extra[32]; + uint8_t len = 0; + + len = scnprintf(extra, sizeof(extra), "%s %d", command, val); + len = QDF_MIN(priv_data->total_len, len + 1); + if (copy_to_user(priv_data->buf, &extra, len)) { + hdd_err("failed to copy data to user buffer"); + ret = -EFAULT; + } + + return ret; +} + +static int drv_cmd_set_roam_rescan_rssi_diff(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret = 0; + uint8_t *value = command; + uint8_t nRoamRescanRssiDiff = CFG_ROAM_RESCAN_RSSI_DIFF_DEFAULT; + + /* Move pointer to ahead of SETROAMRESCANRSSIDIFF */ + value = value + command_len + 1; + + /* Convert the value from ascii to integer */ + ret = kstrtou8(value, 10, &nRoamRescanRssiDiff); + if (ret < 0) { + /* + * If the input value is greater than max value of datatype, + * then also kstrtou8 fails + */ + hdd_err("kstrtou8 failed."); + ret = -EINVAL; + goto exit; + } + + hdd_info("Received Command to Set Roam Rescan RSSI Diff = %d", + nRoamRescanRssiDiff); + + sme_set_roam_rescan_rssi_diff(hdd_ctx->hHal, + adapter->sessionId, + nRoamRescanRssiDiff); + +exit: + return ret; +} + +static int drv_cmd_get_roam_rescan_rssi_diff(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret = 0; + uint8_t val = sme_get_roam_rescan_rssi_diff(hdd_ctx->hHal); + char extra[32]; + uint8_t len = 0; + + len = scnprintf(extra, sizeof(extra), "%s %d", command, val); + len = QDF_MIN(priv_data->total_len, len + 1); + if (copy_to_user(priv_data->buf, &extra, len)) { + hdd_err("failed to copy data to user buffer"); + ret = -EFAULT; + } + + return ret; +} + +static int drv_cmd_set_fast_roam(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret = 0; + uint8_t *value = command; + uint8_t lfrMode = CFG_LFR_FEATURE_ENABLED_DEFAULT; + + if (!adapter->fast_roaming_allowed) { + hdd_err("Roaming is always disabled on this interface"); + goto exit; + } + + /* Move pointer to ahead of SETFASTROAM */ + value = value + command_len + 1; + + /* Convert the value from ascii to integer */ + ret = kstrtou8(value, 10, &lfrMode); + if (ret < 0) { + /* + * If the input value is greater than max value of datatype, + * then also kstrtou8 fails + */ + hdd_err("kstrtou8 failed range [%d - %d]", + CFG_LFR_FEATURE_ENABLED_MIN, + CFG_LFR_FEATURE_ENABLED_MAX); + ret = -EINVAL; + goto exit; + } + + if ((lfrMode < CFG_LFR_FEATURE_ENABLED_MIN) || + (lfrMode > CFG_LFR_FEATURE_ENABLED_MAX)) { + hdd_err("lfr mode value %d is out of range (Min: %d Max: %d)", + lfrMode, + CFG_LFR_FEATURE_ENABLED_MIN, + CFG_LFR_FEATURE_ENABLED_MAX); + ret = -EINVAL; + goto exit; + } + + hdd_info("Received Command to change lfr mode = %d", + lfrMode); + + hdd_ctx->config->isFastRoamIniFeatureEnabled = lfrMode; + sme_update_is_fast_roam_ini_feature_enabled(hdd_ctx->hHal, + adapter-> + sessionId, + lfrMode); + +exit: + return ret; +} + +static int drv_cmd_set_fast_transition(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret = 0; + uint8_t *value = command; + uint8_t ft = CFG_FAST_TRANSITION_ENABLED_NAME_DEFAULT; + + /* Move pointer to ahead of SETFASTROAM */ + value = value + command_len + 1; + + /* Convert the value from ascii to integer */ + ret = kstrtou8(value, 10, &ft); + if (ret < 0) { + /* + * If the input value is greater than max value of datatype, + * then also kstrtou8 fails + */ + hdd_err("kstrtou8 failed range [%d - %d]", + CFG_FAST_TRANSITION_ENABLED_NAME_MIN, + CFG_FAST_TRANSITION_ENABLED_NAME_MAX); + ret = -EINVAL; + goto exit; + } + + if ((ft < CFG_FAST_TRANSITION_ENABLED_NAME_MIN) || + (ft > CFG_FAST_TRANSITION_ENABLED_NAME_MAX)) { + hdd_err("ft mode value %d is out of range (Min: %d Max: %d)", + ft, + CFG_FAST_TRANSITION_ENABLED_NAME_MIN, + CFG_FAST_TRANSITION_ENABLED_NAME_MAX); + ret = -EINVAL; + goto exit; + } + + hdd_info("Received Command to change ft mode = %d", ft); + + hdd_ctx->config->isFastTransitionEnabled = ft; + sme_update_fast_transition_enabled(hdd_ctx->hHal, ft); + +exit: + return ret; +} + +static int drv_cmd_fast_reassoc(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret = 0; + uint8_t *value = command; + uint8_t channel = 0; + tSirMacAddr targetApBssid; + uint32_t roamId = 0; + tCsrRoamModifyProfileFields modProfileFields; + tCsrHandoffRequest handoffInfo; + hdd_station_ctx_t *pHddStaCtx; + + if (QDF_STA_MODE != adapter->device_mode) { + hdd_warn("Unsupported in mode %s(%d)", + hdd_device_mode_to_string(adapter->device_mode), + adapter->device_mode); + return -EINVAL; + } + + pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + + /* if not associated, no need to proceed with reassoc */ + if (eConnectionState_Associated != pHddStaCtx->conn_info.connState) { + hdd_info("Not associated!"); + ret = -EINVAL; + goto exit; + } + + ret = hdd_parse_reassoc_command_v1_data(value, targetApBssid, + &channel); + if (ret) { + hdd_err("Failed to parse reassoc command data"); + goto exit; + } + + /* + * if the target bssid is same as currently associated AP, + * issue reassoc to same AP + */ + if (!qdf_mem_cmp(targetApBssid, + pHddStaCtx->conn_info.bssId.bytes, + QDF_MAC_ADDR_SIZE)) { + hdd_info("Reassoc BSSID is same as currently associated AP bssid"); + if (roaming_offload_enabled(hdd_ctx)) { + hdd_wma_send_fastreassoc_cmd(adapter, + targetApBssid, + pHddStaCtx->conn_info.operationChannel); + } else { + sme_get_modify_profile_fields(hdd_ctx->hHal, + adapter->sessionId, + &modProfileFields); + sme_roam_reassoc(hdd_ctx->hHal, adapter->sessionId, + NULL, modProfileFields, &roamId, 1); + } + return 0; + } + + /* Check channel number is a valid channel number */ + if (QDF_STATUS_SUCCESS != + wlan_hdd_validate_operation_channel(adapter, channel)) { + hdd_err("Invalid Channel [%d]", channel); + return -EINVAL; + } + + if (roaming_offload_enabled(hdd_ctx)) { + hdd_wma_send_fastreassoc_cmd(adapter, + targetApBssid, (int)channel); + goto exit; + } + /* Proceed with reassoc */ + handoffInfo.channel = channel; + handoffInfo.src = FASTREASSOC; + qdf_mem_copy(handoffInfo.bssid.bytes, targetApBssid, + sizeof(tSirMacAddr)); + sme_handoff_request(hdd_ctx->hHal, adapter->sessionId, + &handoffInfo); +exit: + return ret; +} + +static int drv_cmd_set_roam_scan_control(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret = 0; + uint8_t *value = command; + uint8_t roamScanControl = 0; + + /* Move pointer to ahead of SETROAMSCANCONTROL */ + value = value + command_len + 1; + + /* Convert the value from ascii to integer */ + ret = kstrtou8(value, 10, &roamScanControl); + if (ret < 0) { + /* + * If the input value is greater than max value of datatype, + * then also kstrtou8 fails + */ + hdd_err("kstrtou8 failed "); + ret = -EINVAL; + goto exit; + } + + hdd_info("Received Command to Set roam scan control = %d", + roamScanControl); + + if (0 != roamScanControl) { + ret = 0; /* return success but ignore param value "true" */ + goto exit; + } + + sme_set_roam_scan_control(hdd_ctx->hHal, + adapter->sessionId, + roamScanControl); + +exit: + return ret; +} + +static int drv_cmd_set_okc_mode(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret = 0; + uint8_t *value = command; + uint32_t okc_mode; + struct pmkid_mode_bits pmkid_modes; + + hdd_get_pmkid_modes(hdd_ctx, &pmkid_modes); + + /* + * Check if the features PMKID/ESE/11R are supported simultaneously, + * then this operation is not permitted (return FAILURE) + */ + if (sme_get_is_ese_feature_enabled(hdd_ctx->hHal) && + pmkid_modes.fw_okc && + sme_get_is_ft_feature_enabled(hdd_ctx->hHal)) { + hdd_warn("PMKID/ESE/11R are supported simultaneously hence this operation is not permitted!"); + ret = -EPERM; + goto exit; + } + + /* Move pointer to ahead of SETOKCMODE */ + value = value + command_len + 1; + + /* get the current configured value */ + okc_mode = (hdd_ctx->config->pmkid_modes & CFG_PMKID_MODES_OKC) ? 1 : 0; + + /* Convert the value from ascii to integer */ + ret = kstrtou32(value, 10, &okc_mode); + if (ret < 0) { + /* + * If the input value is greater than max value of datatype, + * then also kstrtou8 fails + */ + hdd_err("value out of range [0 - 1]"); + ret = -EINVAL; + goto exit; + } + + if ((okc_mode < 0) || + (okc_mode > 1)) { + hdd_err("Okc mode value %d is out of range (Min: 0 Max: 1)", + okc_mode); + ret = -EINVAL; + goto exit; + } + hdd_info("Received Command to change okc mode = %d", + okc_mode); + + if (okc_mode) + hdd_ctx->config->pmkid_modes |= CFG_PMKID_MODES_OKC; + else + hdd_ctx->config->pmkid_modes &= ~CFG_PMKID_MODES_OKC; + +exit: + return ret; +} + +static int drv_cmd_get_roam_scan_control(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret = 0; + bool roamScanControl = sme_get_roam_scan_control(hdd_ctx->hHal); + char extra[32]; + uint8_t len = 0; + + len = scnprintf(extra, sizeof(extra), "%s %d", + command, roamScanControl); + len = QDF_MIN(priv_data->total_len, len + 1); + if (copy_to_user(priv_data->buf, &extra, len)) { + hdd_err("failed to copy data to user buffer"); + ret = -EFAULT; + } + + return ret; +} + +static int drv_cmd_bt_coex_mode(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret = 0; + char *bcMode; + + bcMode = command + 11; + if ('1' == *bcMode) { + hdd_debug("BTCOEXMODE %d", *bcMode); + hdd_ctx->btCoexModeSet = true; + ret = wlan_hdd_scan_abort(adapter); + if (ret < 0) { + hdd_err("Failed to abort existing scan status: %d", + ret); + } + } else if ('2' == *bcMode) { + hdd_debug("BTCOEXMODE %d", *bcMode); + hdd_ctx->btCoexModeSet = false; + } + + return ret; +} + +static int drv_cmd_scan_active(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + hdd_ctx->ioctl_scan_mode = eSIR_ACTIVE_SCAN; + return 0; +} + +static int drv_cmd_scan_passive(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + hdd_ctx->ioctl_scan_mode = eSIR_PASSIVE_SCAN; + return 0; +} + +static int drv_cmd_get_dwell_time(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret = 0; + struct hdd_config *pCfg = + (WLAN_HDD_GET_CTX(adapter))->config; + char extra[32]; + uint8_t len = 0; + + memset(extra, 0, sizeof(extra)); + ret = hdd_get_dwell_time(pCfg, command, extra, sizeof(extra), &len); + len = QDF_MIN(priv_data->total_len, len + 1); + if (ret != 0 || copy_to_user(priv_data->buf, &extra, len)) { + hdd_err("failed to copy data to user buffer"); + ret = -EFAULT; + goto exit; + } + ret = len; +exit: + return ret; +} + +static int drv_cmd_set_dwell_time(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + return hdd_set_dwell_time(adapter, command); +} + +static int drv_cmd_miracast(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + QDF_STATUS ret_status; + int ret = 0; + tHalHandle hHal; + uint8_t filterType = 0; + hdd_context_t *pHddCtx = NULL; + uint8_t *value; + + pHddCtx = WLAN_HDD_GET_CTX(adapter); + if (wlan_hdd_validate_context(pHddCtx)) + return -EINVAL; + + hHal = pHddCtx->hHal; + value = command + 9; + + /* Convert the value from ascii to integer */ + ret = kstrtou8(value, 10, &filterType); + if (ret < 0) { + /* + * If the input value is greater than max value of datatype, + * then also kstrtou8 fails + */ + hdd_err("kstrtou8 failed range "); + ret = -EINVAL; + goto exit; + } + if ((filterType < WLAN_HDD_DRIVER_MIRACAST_CFG_MIN_VAL) + || (filterType > + WLAN_HDD_DRIVER_MIRACAST_CFG_MAX_VAL)) { + hdd_err("Accepted Values are 0 to 2. 0-Disabled, 1-Source, 2-Sink "); + ret = -EINVAL; + goto exit; + } + /* Filtertype value should be either 0-Disabled, 1-Source, 2-sink */ + pHddCtx->miracast_value = filterType; + + ret_status = sme_set_miracast(hHal, filterType); + if (QDF_STATUS_SUCCESS != ret_status) { + hdd_err("Failed to set miracast"); + return -EBUSY; + } + + if (cds_is_mcc_in_24G()) + return cds_set_mas(adapter, filterType); + +exit: + return ret; +} + +/* Function header is left blank intentionally */ +static int hdd_parse_set_ibss_oui_data_command(uint8_t *command, uint8_t *ie, + int32_t *oui_length, int32_t limit) +{ + uint8_t len; + uint8_t data; + + while ((SPACE_ASCII_VALUE == *command) && ('\0' != *command)) { + command++; + limit--; + } + + len = 2; + + while ((SPACE_ASCII_VALUE != *command) && ('\0' != *command) && + (limit > 1)) { + sscanf(command, "%02x", (unsigned int *)&data); + ie[len++] = data; + command += 2; + limit -= 2; + } + + *oui_length = len - 2; + + while ((SPACE_ASCII_VALUE == *command) && ('\0' != *command)) { + command++; + limit--; + } + + while ((SPACE_ASCII_VALUE != *command) && ('\0' != *command) && + (limit > 1)) { + sscanf(command, "%02x", (unsigned int *)&data); + ie[len++] = data; + command += 2; + limit -= 2; + } + + ie[0] = IE_EID_VENDOR; + ie[1] = len - 2; + + return len; +} + +/** + * drv_cmd_set_ibss_beacon_oui_data() - set ibss oui data command + * @adapter: Pointer to adapter + * @hdd_ctx: Pointer to HDD context + * @command: Pointer to command string + * @command_len : Command length + * @priv_data : Pointer to priv data + * + * Return: + * int status code + */ +static int drv_cmd_set_ibss_beacon_oui_data(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int i = 0; + int status; + int ret = 0; + uint8_t *ibss_ie; + int32_t oui_length = 0; + uint32_t ibss_ie_length; + uint8_t *value = command; + tSirModifyIE ibssModifyIE; + tCsrRoamProfile *pRoamProfile; + hdd_wext_state_t *pWextState; + + + if (QDF_IBSS_MODE != adapter->device_mode) { + hdd_info("Device_mode %s(%d) not IBSS", + hdd_device_mode_to_string(adapter->device_mode), + adapter->device_mode); + return ret; + } + + pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(adapter); + + hdd_info("received command %s", ((char *)value)); + + + /* validate argument of command */ + if (strlen(value) <= command_len) { + hdd_err("No arguments in command length %zu", + strlen(value)); + ret = -EFAULT; + goto exit; + } + + /* moving to arguments of commands */ + value = value + command_len; + command_len = strlen(value); + + /* oui_data can't be less than 3 bytes */ + if (command_len < (2 * WLAN_HDD_IBSS_MIN_OUI_DATA_LENGTH)) { + hdd_err("Invalid SETIBSSBEACONOUIDATA command length %d", + command_len); + ret = -EFAULT; + goto exit; + } + + ibss_ie = qdf_mem_malloc(command_len); + if (!ibss_ie) { + hdd_err("Could not allocate memory for command length %d", + command_len); + ret = -ENOMEM; + goto exit; + } + + ibss_ie_length = hdd_parse_set_ibss_oui_data_command(value, ibss_ie, + &oui_length, + command_len); + if (ibss_ie_length <= (2 * WLAN_HDD_IBSS_MIN_OUI_DATA_LENGTH)) { + hdd_err("Could not parse command %s return length %d", + value, ibss_ie_length); + ret = -EFAULT; + qdf_mem_free(ibss_ie); + goto exit; + } + + pRoamProfile = &pWextState->roamProfile; + + qdf_copy_macaddr(&ibssModifyIE.bssid, + pRoamProfile->BSSIDs.bssid); + + ibssModifyIE.smeSessionId = adapter->sessionId; + ibssModifyIE.notify = true; + ibssModifyIE.ieID = IE_EID_VENDOR; + ibssModifyIE.ieIDLen = ibss_ie_length; + ibssModifyIE.ieBufferlength = ibss_ie_length; + ibssModifyIE.pIEBuffer = ibss_ie; + ibssModifyIE.oui_length = oui_length; + + hdd_warn("ibss_ie length %d oui_length %d ibss_ie:", + ibss_ie_length, oui_length); + while (i < ibssModifyIE.ieBufferlength) + hdd_warn("0x%x", ibss_ie[i++]); + + /* Probe Bcn modification */ + sme_modify_add_ie(WLAN_HDD_GET_HAL_CTX(adapter), + &ibssModifyIE, eUPDATE_IE_PROBE_BCN); + + /* Populating probe resp frame */ + sme_modify_add_ie(WLAN_HDD_GET_HAL_CTX(adapter), + &ibssModifyIE, eUPDATE_IE_PROBE_RESP); + + qdf_mem_free(ibss_ie); + + status = sme_send_cesium_enable_ind((tHalHandle)(hdd_ctx->hHal), + adapter->sessionId); + if (QDF_STATUS_SUCCESS != status) { + hdd_err("Could not send cesium enable indication %d", + status); + ret = -EINVAL; + goto exit; + } + +exit: + return ret; +} + +static int drv_cmd_set_rmc_enable(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret = 0; + uint8_t *value = command; + uint8_t ucRmcEnable = 0; + int status; + + if ((QDF_IBSS_MODE != adapter->device_mode) && + (QDF_SAP_MODE != adapter->device_mode)) { + hdd_err("Received SETRMCENABLE cmd in invalid mode %s(%d)", + hdd_device_mode_to_string(adapter->device_mode), + adapter->device_mode); + hdd_err("SETRMCENABLE cmd is allowed only in IBSS/SOFTAP mode"); + ret = -EINVAL; + goto exit; + } + + status = hdd_parse_setrmcenable_command(value, &ucRmcEnable); + if (status) { + hdd_err("Invalid SETRMCENABLE command "); + ret = -EINVAL; + goto exit; + } + + hdd_info("ucRmcEnable %d ", ucRmcEnable); + + if (true == ucRmcEnable) { + status = sme_enable_rmc((tHalHandle) + (hdd_ctx->hHal), + adapter->sessionId); + } else if (false == ucRmcEnable) { + status = sme_disable_rmc((tHalHandle) + (hdd_ctx->hHal), + adapter->sessionId); + } else { + hdd_err("Invalid SETRMCENABLE command %d", + ucRmcEnable); + ret = -EINVAL; + goto exit; + } + + if (QDF_STATUS_SUCCESS != status) { + hdd_err("SETRMC %d failed status %d", + ucRmcEnable, status); + ret = -EINVAL; + goto exit; + } + +exit: + return ret; +} + +static int drv_cmd_set_rmc_action_period(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret = 0; + uint8_t *value = command; + uint32_t uActionPeriod = 0; + int status; + + if ((QDF_IBSS_MODE != adapter->device_mode) && + (QDF_SAP_MODE != adapter->device_mode)) { + hdd_err("Received SETRMC cmd in invalid mode %s(%d)", + hdd_device_mode_to_string(adapter->device_mode), + adapter->device_mode); + hdd_err("SETRMC cmd is allowed only in IBSS/SOFTAP mode"); + ret = -EINVAL; + goto exit; + } + + status = hdd_parse_setrmcactionperiod_command(value, &uActionPeriod); + if (status) { + hdd_err("Invalid SETRMCACTIONPERIOD command "); + ret = -EINVAL; + goto exit; + } + + hdd_info("uActionPeriod %d ", + uActionPeriod); + + if (sme_cfg_set_int(hdd_ctx->hHal, + WNI_CFG_RMC_ACTION_PERIOD_FREQUENCY, + uActionPeriod)) { + hdd_err("Could not set SETRMCACTIONPERIOD %d", + uActionPeriod); + ret = -EINVAL; + goto exit; + } + + status = sme_send_rmc_action_period((tHalHandle)(hdd_ctx->hHal), + adapter->sessionId); + if (QDF_STATUS_SUCCESS != status) { + hdd_err("Could not send cesium enable indication %d", + status); + ret = -EINVAL; + goto exit; + } + +exit: + return ret; +} + +static int drv_cmd_get_ibss_peer_info_all(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret = 0; + int status = QDF_STATUS_SUCCESS; + hdd_station_ctx_t *pHddStaCtx = NULL; + char *extra = NULL; + int idx = 0; + int length = 0; + uint8_t mac_addr[QDF_MAC_ADDR_SIZE]; + uint32_t numOfBytestoPrint = 0; + + if (QDF_IBSS_MODE != adapter->device_mode) { + hdd_warn("Unsupported in mode %s(%d)", + hdd_device_mode_to_string(adapter->device_mode), + adapter->device_mode); + return -EINVAL; + } + + pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + hdd_info("Received GETIBSSPEERINFOALL Command"); + + /* Handle the command */ + status = hdd_cfg80211_get_ibss_peer_info_all(adapter); + if (QDF_STATUS_SUCCESS == status) { + /* + * The variable extra needed to be allocated on the heap since + * amount of memory required to copy the data for 32 devices + * exceeds the size of 1024 bytes of default stack size. On + * 64 bit devices, the default max stack size of 2048 bytes + */ + extra = qdf_mem_malloc(WLAN_MAX_BUF_SIZE); + + if (NULL == extra) { + hdd_err("memory allocation failed"); + ret = -ENOMEM; + goto exit; + } + + /* Copy number of stations */ + length = scnprintf(extra, WLAN_MAX_BUF_SIZE, "%d ", + pHddStaCtx->ibss_peer_info.numPeers); + numOfBytestoPrint = length; + for (idx = 0; idx < pHddStaCtx->ibss_peer_info.numPeers; + idx++) { + int8_t rssi; + uint32_t tx_rate; + + qdf_mem_copy(mac_addr, + pHddStaCtx->ibss_peer_info.peerInfoParams[idx]. + mac_addr, sizeof(mac_addr)); + + tx_rate = + pHddStaCtx->ibss_peer_info.peerInfoParams[idx]. + txRate; + /* + * Only lower 3 bytes are rate info. Mask of the MSByte + */ + tx_rate &= 0x00FFFFFF; + + rssi = pHddStaCtx->ibss_peer_info.peerInfoParams[idx]. + rssi; + + length += scnprintf((extra + length), + WLAN_MAX_BUF_SIZE - length, + "%02x:%02x:%02x:%02x:%02x:%02x %d %d ", + mac_addr[0], mac_addr[1], mac_addr[2], + mac_addr[3], mac_addr[4], mac_addr[5], + tx_rate, rssi); + /* + * cdf_trace_msg has limitation of 512 bytes for the + * print buffer. Hence printing the data in two chunks. + * The first chunk will have the data for 16 devices + * and the second chunk will have the rest. + */ + if (idx < NUM_OF_STA_DATA_TO_PRINT) + numOfBytestoPrint = length; + } + + /* + * Copy the data back into buffer, if the data to copy is + * more than 512 bytes than we will split the data and do + * it in two shots + */ + if (copy_to_user(priv_data->buf, extra, numOfBytestoPrint)) { + hdd_err("Copy into user data buffer failed "); + ret = -EFAULT; + goto exit; + } + + priv_data->buf[numOfBytestoPrint] = '\0'; + hdd_debug("%s", priv_data->buf); + + if (length > numOfBytestoPrint) { + if (copy_to_user + (priv_data->buf + numOfBytestoPrint, + extra + numOfBytestoPrint, + length - numOfBytestoPrint + 1)) { + hdd_err("Copy into user data buffer failed "); + ret = -EFAULT; + goto exit; + } + hdd_debug("%s", &priv_data->buf[numOfBytestoPrint]); + } + + /* Free temporary buffer */ + qdf_mem_free(extra); + } else { + /* Command failed, log error */ + hdd_err("GETIBSSPEERINFOALL command failed with status code %d", + status); + ret = -EINVAL; + goto exit; + } + ret = 0; + +exit: + return ret; +} + +/* Peer Info command */ +static int drv_cmd_get_ibss_peer_info(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret = 0; + uint8_t *value = command; + QDF_STATUS status; + hdd_station_ctx_t *pHddStaCtx = NULL; + char extra[128] = { 0 }; + uint32_t length = 0; + uint8_t staIdx = 0; + struct qdf_mac_addr peerMacAddr; + + if (QDF_IBSS_MODE != adapter->device_mode) { + hdd_warn("Unsupported in mode %s(%d)", + hdd_device_mode_to_string(adapter->device_mode), + adapter->device_mode); + return -EINVAL; + } + + pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + + hdd_info("Received GETIBSSPEERINFO Command"); + + /* if there are no peers, no need to continue with the command */ + if (eConnectionState_IbssConnected != + pHddStaCtx->conn_info.connState) { + hdd_info("No IBSS Peers coalesced"); + ret = -EINVAL; + goto exit; + } + + /* Parse the incoming command buffer */ + status = hdd_parse_get_ibss_peer_info(value, &peerMacAddr); + if (QDF_STATUS_SUCCESS != status) { + hdd_err("Invalid GETIBSSPEERINFO command"); + ret = -EINVAL; + goto exit; + } + + /* Get station index for the peer mac address and sanitize it */ + hdd_get_peer_sta_id(pHddStaCtx, &peerMacAddr, &staIdx); + + if (staIdx > MAX_PEERS) { + hdd_err("Invalid StaIdx %d returned", staIdx); + ret = -EINVAL; + goto exit; + } + + /* Handle the command */ + status = hdd_cfg80211_get_ibss_peer_info(adapter, staIdx); + if (QDF_STATUS_SUCCESS == status) { + uint32_t txRate = + pHddStaCtx->ibss_peer_info.peerInfoParams[0].txRate; + /* Only lower 3 bytes are rate info. Mask of the MSByte */ + txRate &= 0x00FFFFFF; + + length = scnprintf(extra, sizeof(extra), "%d %d", + (int)txRate, + (int)pHddStaCtx->ibss_peer_info. + peerInfoParams[0].rssi); + + /* Copy the data back into buffer */ + if (copy_to_user(priv_data->buf, &extra, length + 1)) { + hdd_err("copy data to user buffer failed GETIBSSPEERINFO command"); + ret = -EFAULT; + goto exit; + } + } else { + /* Command failed, log error */ + hdd_err("GETIBSSPEERINFO command failed with status code %d", + status); + ret = -EINVAL; + goto exit; + } + + /* Success ! */ + hdd_debug("%s", priv_data->buf); + ret = 0; + +exit: + return ret; +} + +static int drv_cmd_set_rmc_tx_rate(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret = 0; + uint8_t *value = command; + uint32_t uRate = 0; + tTxrateinfoflags txFlags = 0; + tSirRateUpdateInd rateUpdateParams = {0}; + int status; + struct hdd_config *pConfig = hdd_ctx->config; + + if ((QDF_IBSS_MODE != adapter->device_mode) && + (QDF_SAP_MODE != adapter->device_mode)) { + hdd_err("Received SETRMCTXRATE cmd in invalid mode %s(%d)", + hdd_device_mode_to_string(adapter->device_mode), + adapter->device_mode); + hdd_err("SETRMCTXRATE cmd is allowed only in IBSS/SOFTAP mode"); + ret = -EINVAL; + goto exit; + } + + status = hdd_parse_setrmcrate_command(value, &uRate, &txFlags); + if (status) { + hdd_err("Invalid SETRMCTXRATE command "); + ret = -EINVAL; + goto exit; + } + hdd_info("uRate %d ", uRate); + /* -1 implies ignore this param */ + rateUpdateParams.ucastDataRate = -1; + + /* + * Fill the user specifieed RMC rate param + * and the derived tx flags. + */ + rateUpdateParams.nss = (pConfig->enable2x2 == 0) ? 0 : 1; + rateUpdateParams.reliableMcastDataRate = uRate; + rateUpdateParams.reliableMcastDataRateTxFlag = txFlags; + rateUpdateParams.dev_mode = adapter->device_mode; + rateUpdateParams.bcastDataRate = -1; + memcpy(rateUpdateParams.bssid.bytes, + adapter->macAddressCurrent.bytes, + sizeof(rateUpdateParams.bssid)); + status = sme_send_rate_update_ind((tHalHandle) (hdd_ctx->hHal), + &rateUpdateParams); + +exit: + return ret; +} + +static int drv_cmd_set_ibss_tx_fail_event(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret = 0; + char *value; + uint8_t tx_fail_count = 0; + uint16_t pid = 0; + + value = command; + + ret = hdd_parse_ibsstx_fail_event_params(value, &tx_fail_count, &pid); + + if (0 != ret) { + hdd_info("Failed to parse SETIBSSTXFAILEVENT arguments"); + goto exit; + } + + hdd_info("tx_fail_cnt=%hhu, pid=%hu", tx_fail_count, pid); + + if (0 == tx_fail_count) { + /* Disable TX Fail Indication */ + if (QDF_STATUS_SUCCESS == + sme_tx_fail_monitor_start_stop_ind(hdd_ctx->hHal, + tx_fail_count, + NULL)) { + cesium_pid = 0; + } else { + hdd_err("failed to disable TX Fail Event "); + ret = -EINVAL; + } + } else { + if (QDF_STATUS_SUCCESS == + sme_tx_fail_monitor_start_stop_ind(hdd_ctx->hHal, + tx_fail_count, + (void *)hdd_tx_fail_ind_callback)) { + cesium_pid = pid; + hdd_info("Registered Cesium pid %u", + cesium_pid); + } else { + hdd_err("Failed to enable TX Fail Monitoring"); + ret = -EINVAL; + } + } + +exit: + return ret; +} + +#ifdef FEATURE_WLAN_ESE +static int drv_cmd_set_ccx_roam_scan_channels(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret = 0; + uint8_t *value = command; + uint8_t ChannelList[WNI_CFG_VALID_CHANNEL_LIST_LEN] = { 0 }; + uint8_t numChannels = 0; + QDF_STATUS status; + + ret = hdd_parse_channellist(value, ChannelList, &numChannels); + if (ret) { + hdd_err("Failed to parse channel list information"); + goto exit; + } + if (numChannels > WNI_CFG_VALID_CHANNEL_LIST_LEN) { + hdd_err("number of channels (%d) supported exceeded max (%d)", + numChannels, + WNI_CFG_VALID_CHANNEL_LIST_LEN); + ret = -EINVAL; + goto exit; + } + status = sme_set_ese_roam_scan_channel_list(hdd_ctx->hHal, + adapter->sessionId, + ChannelList, + numChannels); + if (QDF_STATUS_SUCCESS != status) { + hdd_err("Failed to update channel list information"); + ret = -EINVAL; + goto exit; + } + +exit: + return ret; +} + +static int drv_cmd_get_tsm_stats(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret = 0; + uint8_t *value = command; + char extra[128] = { 0 }; + int len = 0; + uint8_t tid = 0; + hdd_station_ctx_t *pHddStaCtx; + tAniTrafStrmMetrics tsm_metrics; + + if ((QDF_STA_MODE != adapter->device_mode) && + (QDF_P2P_CLIENT_MODE != adapter->device_mode)) { + hdd_warn("Unsupported in mode %s(%d)", + hdd_device_mode_to_string(adapter->device_mode), + adapter->device_mode); + return -EINVAL; + } + + pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + + /* if not associated, return error */ + if (eConnectionState_Associated != pHddStaCtx->conn_info.connState) { + hdd_err("Not associated!"); + ret = -EINVAL; + goto exit; + } + + /* Move pointer to ahead of GETTSMSTATS */ + value = value + command_len + 1; + + /* Convert the value from ascii to integer */ + ret = kstrtou8(value, 10, &tid); + if (ret < 0) { + /* + * If the input value is greater than max value of datatype, + * then also kstrtou8 fails + */ + hdd_err("kstrtou8 failed range [%d - %d]", + TID_MIN_VALUE, + TID_MAX_VALUE); + ret = -EINVAL; + goto exit; + } + if ((tid < TID_MIN_VALUE) || (tid > TID_MAX_VALUE)) { + hdd_err("tid value %d is out of range (Min: %d Max: %d)", + tid, TID_MIN_VALUE, TID_MAX_VALUE); + ret = -EINVAL; + goto exit; + } + hdd_info("Received Command to get tsm stats tid = %d", + tid); + if (QDF_STATUS_SUCCESS != + hdd_get_tsm_stats(adapter, tid, &tsm_metrics)) { + hdd_err("failed to get tsm stats"); + ret = -EFAULT; + goto exit; + } + hdd_info( + "UplinkPktQueueDly(%d) UplinkPktQueueDlyHist[0](%d) UplinkPktQueueDlyHist[1](%d) UplinkPktQueueDlyHist[2](%d) UplinkPktQueueDlyHist[3](%d) UplinkPktTxDly(%u) UplinkPktLoss(%d) UplinkPktCount(%d) RoamingCount(%d) RoamingDly(%d)", + tsm_metrics.UplinkPktQueueDly, + tsm_metrics.UplinkPktQueueDlyHist[0], + tsm_metrics.UplinkPktQueueDlyHist[1], + tsm_metrics.UplinkPktQueueDlyHist[2], + tsm_metrics.UplinkPktQueueDlyHist[3], + tsm_metrics.UplinkPktTxDly, + tsm_metrics.UplinkPktLoss, + tsm_metrics.UplinkPktCount, + tsm_metrics.RoamingCount, + tsm_metrics.RoamingDly); + /* + * Output TSM stats is of the format + * GETTSMSTATS [PktQueueDly] + * [PktQueueDlyHist[0]]:[PktQueueDlyHist[1]] ...[RoamingDly] + * eg., GETTSMSTATS 10 1:0:0:161 20 1 17 8 39800 + */ + len = scnprintf(extra, + sizeof(extra), + "%s %d %d:%d:%d:%d %u %d %d %d %d", + command, + tsm_metrics.UplinkPktQueueDly, + tsm_metrics.UplinkPktQueueDlyHist[0], + tsm_metrics.UplinkPktQueueDlyHist[1], + tsm_metrics.UplinkPktQueueDlyHist[2], + tsm_metrics.UplinkPktQueueDlyHist[3], + tsm_metrics.UplinkPktTxDly, + tsm_metrics.UplinkPktLoss, + tsm_metrics.UplinkPktCount, + tsm_metrics.RoamingCount, + tsm_metrics.RoamingDly); + len = QDF_MIN(priv_data->total_len, len + 1); + if (copy_to_user(priv_data->buf, &extra, len)) { + hdd_err("failed to copy data to user buffer"); + ret = -EFAULT; + goto exit; + } + +exit: + return ret; +} + +static int drv_cmd_set_cckm_ie(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret; + uint8_t *value = command; + uint8_t *cckmIe = NULL; + uint8_t cckmIeLen = 0; + + ret = hdd_parse_get_cckm_ie(value, &cckmIe, &cckmIeLen); + if (ret) { + hdd_err("Failed to parse cckm ie data"); + goto exit; + } + + if (cckmIeLen > DOT11F_IE_RSN_MAX_LEN) { + hdd_err("CCKM Ie input length is more than max[%d]", + DOT11F_IE_RSN_MAX_LEN); + if (NULL != cckmIe) { + qdf_mem_free(cckmIe); + cckmIe = NULL; + } + ret = -EINVAL; + goto exit; + } + + sme_set_cckm_ie(hdd_ctx->hHal, adapter->sessionId, + cckmIe, cckmIeLen); + if (NULL != cckmIe) { + qdf_mem_free(cckmIe); + cckmIe = NULL; + } + +exit: + return ret; +} + +static int drv_cmd_ccx_beacon_req(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret; + uint8_t *value = command; + tCsrEseBeaconReq eseBcnReq; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + if (QDF_STA_MODE != adapter->device_mode) { + hdd_warn("Unsupported in mode %s(%d)", + hdd_device_mode_to_string(adapter->device_mode), + adapter->device_mode); + return -EINVAL; + } + + ret = hdd_parse_ese_beacon_req(value, &eseBcnReq); + if (ret) { + hdd_err("Failed to parse ese beacon req"); + goto exit; + } + + if (!hdd_conn_is_connected(WLAN_HDD_GET_STATION_CTX_PTR(adapter))) { + hdd_info("Not associated"); + hdd_indicate_ese_bcn_report_no_results(adapter, + eseBcnReq.bcnReq[0].measurementToken, + 0x02, /* BIT(1) set for measurement done */ + 0); /* no BSS */ + goto exit; + } + + status = sme_set_ese_beacon_request(hdd_ctx->hHal, + adapter->sessionId, + &eseBcnReq); + + if (QDF_STATUS_E_RESOURCES == status) { + hdd_info("sme_set_ese_beacon_request failed (%d), a request already in progress", + status); + ret = -EBUSY; + goto exit; + } else if (QDF_STATUS_SUCCESS != status) { + hdd_err("sme_set_ese_beacon_request failed (%d)", + status); + ret = -EINVAL; + goto exit; + } + +exit: + return ret; +} + +/** + * drv_cmd_ccx_plm_req() - Set ESE PLM request + * @adapter: Pointer to the HDD adapter + * @hdd_ctx: Pointer to the HDD context + * @command: Driver command string + * @command_len: Driver command string length + * @priv_data: Private data coming with the driver command. Unused here + * + * This function handles driver command that sets the ESE PLM request + * + * Return: 0 on success; negative errno otherwise + */ +static int drv_cmd_ccx_plm_req(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret = 0; + uint8_t *value = command; + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpSirPlmReq pPlmRequest = NULL; + + pPlmRequest = qdf_mem_malloc(sizeof(tSirPlmReq)); + if (NULL == pPlmRequest) { + ret = -ENOMEM; + goto exit; + } + + status = hdd_parse_plm_cmd(value, pPlmRequest); + if (QDF_STATUS_SUCCESS != status) { + qdf_mem_free(pPlmRequest); + pPlmRequest = NULL; + ret = -EINVAL; + goto exit; + } + pPlmRequest->sessionId = adapter->sessionId; + + status = sme_set_plm_request(hdd_ctx->hHal, pPlmRequest); + if (QDF_STATUS_SUCCESS != status) { + qdf_mem_free(pPlmRequest); + pPlmRequest = NULL; + ret = -EINVAL; + goto exit; + } + +exit: + return ret; +} + +/** + * drv_cmd_set_ccx_mode() - Set ESE mode + * @adapter: Pointer to the HDD adapter + * @hdd_ctx: Pointer to the HDD context + * @command: Driver command string + * @command_len: Driver command string length + * @priv_data: Private data coming with the driver command. Unused here + * + * This function handles driver command that sets ESE mode + * + * Return: 0 on success; negative errno otherwise + */ +static int drv_cmd_set_ccx_mode(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret = 0; + uint8_t *value = command; + uint8_t eseMode = CFG_ESE_FEATURE_ENABLED_DEFAULT; + struct pmkid_mode_bits pmkid_modes; + + hdd_get_pmkid_modes(hdd_ctx, &pmkid_modes); + /* + * Check if the features OKC/ESE/11R are supported simultaneously, + * then this operation is not permitted (return FAILURE) + */ + if (sme_get_is_ese_feature_enabled(hdd_ctx->hHal) && + pmkid_modes.fw_okc && + sme_get_is_ft_feature_enabled(hdd_ctx->hHal)) { + hdd_warn("OKC/ESE/11R are supported simultaneously hence this operation is not permitted!"); + ret = -EPERM; + goto exit; + } + + if (!adapter->fast_roaming_allowed) { + hdd_warn("Fast roaming is not allowed on this device hence this operation is not permitted!"); + ret = -EPERM; + goto exit; + } + + /* Move pointer to ahead of SETCCXMODE */ + value = value + command_len + 1; + + /* Convert the value from ascii to integer */ + ret = kstrtou8(value, 10, &eseMode); + if (ret < 0) { + /* + * If the input value is greater than max value of datatype, + * then also kstrtou8 fails + */ + hdd_err("kstrtou8 failed range [%d - %d]", + CFG_ESE_FEATURE_ENABLED_MIN, + CFG_ESE_FEATURE_ENABLED_MAX); + ret = -EINVAL; + goto exit; + } + + if ((eseMode < CFG_ESE_FEATURE_ENABLED_MIN) || + (eseMode > CFG_ESE_FEATURE_ENABLED_MAX)) { + hdd_err("Ese mode value %d is out of range (Min: %d Max: %d)", + eseMode, + CFG_ESE_FEATURE_ENABLED_MIN, + CFG_ESE_FEATURE_ENABLED_MAX); + ret = -EINVAL; + goto exit; + } + hdd_info("Received Command to change ese mode = %d", eseMode); + + hdd_ctx->config->isEseIniFeatureEnabled = eseMode; + sme_update_is_ese_feature_enabled(hdd_ctx->hHal, + adapter->sessionId, + eseMode); + +exit: + return ret; +} +#endif /* FEATURE_WLAN_ESE */ + +static int drv_cmd_set_mc_rate(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret = 0; + uint8_t *value = command; + int targetRate; + + /* input value is in units of hundred kbps */ + + /* Move pointer to ahead of SETMCRATE */ + value = value + command_len + 1; + + /* Convert the value from ascii to integer, decimal base */ + ret = kstrtouint(value, 10, &targetRate); + + ret = wlan_hdd_set_mc_rate(adapter, targetRate); + return ret; +} + +static int drv_cmd_max_tx_power(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret = 0; + int status; + int txPower; + QDF_STATUS qdf_status; + QDF_STATUS smeStatus; + uint8_t *value = command; + struct qdf_mac_addr bssid = QDF_MAC_ADDR_BROADCAST_INITIALIZER; + struct qdf_mac_addr selfMac = QDF_MAC_ADDR_BROADCAST_INITIALIZER; + hdd_adapter_list_node_t *pAdapterNode = NULL; + hdd_adapter_list_node_t *pNext = NULL; + + status = hdd_parse_setmaxtxpower_command(value, &txPower); + if (status) { + hdd_err("Invalid MAXTXPOWER command "); + ret = -EINVAL; + goto exit; + } + + qdf_status = hdd_get_front_adapter(hdd_ctx, &pAdapterNode); + while (NULL != pAdapterNode + && QDF_STATUS_SUCCESS == qdf_status) { + adapter = pAdapterNode->pAdapter; + /* Assign correct self MAC address */ + qdf_copy_macaddr(&bssid, + &adapter->macAddressCurrent); + qdf_copy_macaddr(&selfMac, + &adapter->macAddressCurrent); + + hdd_info("Device mode %d max tx power %d selfMac: " + MAC_ADDRESS_STR " bssId: " MAC_ADDRESS_STR " ", + adapter->device_mode, txPower, + MAC_ADDR_ARRAY(selfMac.bytes), + MAC_ADDR_ARRAY(bssid.bytes)); + + smeStatus = sme_set_max_tx_power(hdd_ctx->hHal, + bssid, selfMac, txPower); + if (QDF_STATUS_SUCCESS != status) { + hdd_err("Set max tx power failed"); + ret = -EINVAL; + goto exit; + } + hdd_info("Set max tx power success"); + qdf_status = hdd_get_next_adapter(hdd_ctx, pAdapterNode, + &pNext); + pAdapterNode = pNext; + } + +exit: + return ret; +} + +static int drv_cmd_set_dfs_scan_mode(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret = 0; + uint8_t *value = command; + uint8_t dfsScanMode = CFG_ROAMING_DFS_CHANNEL_DEFAULT; + + /* Move pointer to ahead of SETDFSSCANMODE */ + value = value + command_len + 1; + + /* Convert the value from ascii to integer */ + ret = kstrtou8(value, 10, &dfsScanMode); + if (ret < 0) { + /* + * If the input value is greater than max value of datatype, + * then also kstrtou8 fails + */ + hdd_err("kstrtou8 failed range [%d - %d]", + CFG_ROAMING_DFS_CHANNEL_MIN, + CFG_ROAMING_DFS_CHANNEL_MAX); + ret = -EINVAL; + goto exit; + } + + if ((dfsScanMode < CFG_ROAMING_DFS_CHANNEL_MIN) || + (dfsScanMode > CFG_ROAMING_DFS_CHANNEL_MAX)) { + hdd_err("dfsScanMode value %d is out of range (Min: %d Max: %d)", + dfsScanMode, + CFG_ROAMING_DFS_CHANNEL_MIN, + CFG_ROAMING_DFS_CHANNEL_MAX); + ret = -EINVAL; + goto exit; + } + + hdd_info("Received Command to Set DFS Scan Mode = %d", + dfsScanMode); + + /* When DFS scanning is disabled, the DFS channels need to be + * removed from the operation of device. + */ + ret = wlan_hdd_disable_dfs_chan_scan(hdd_ctx, adapter, + (dfsScanMode == CFG_ROAMING_DFS_CHANNEL_DISABLED)); + if (ret < 0) { + /* Some conditions prevented it from disabling DFS channels */ + hdd_err("disable/enable DFS channel request was denied"); + goto exit; + } + + hdd_ctx->config->allowDFSChannelRoam = dfsScanMode; + sme_update_dfs_scan_mode(hdd_ctx->hHal, adapter->sessionId, + dfsScanMode); + +exit: + return ret; +} + +static int drv_cmd_get_dfs_scan_mode(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret = 0; + uint8_t dfsScanMode = sme_get_dfs_scan_mode(hdd_ctx->hHal); + char extra[32]; + uint8_t len = 0; + + len = scnprintf(extra, sizeof(extra), "%s %d", command, dfsScanMode); + len = QDF_MIN(priv_data->total_len, len + 1); + if (copy_to_user(priv_data->buf, &extra, len)) { + hdd_err("failed to copy data to user buffer"); + ret = -EFAULT; + } + + return ret; +} + +static int drv_cmd_get_link_status(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret = 0; + int value = wlan_hdd_get_link_status(adapter); + char extra[32]; + uint8_t len; + + len = scnprintf(extra, sizeof(extra), "%s %d", command, value); + len = QDF_MIN(priv_data->total_len, len + 1); + if (copy_to_user(priv_data->buf, &extra, len)) { + hdd_err("failed to copy data to user buffer"); + ret = -EFAULT; + } + + return ret; +} + +#ifdef WLAN_FEATURE_EXTWOW_SUPPORT +static int drv_cmd_enable_ext_wow(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + uint8_t *value = command; + int set_value; + + /* Move pointer to ahead of ENABLEEXTWOW */ + value = value + command_len; + + if (!(sscanf(value, "%d", &set_value))) { + QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO, + ("No input identified")); + return -EINVAL; + } + + return hdd_enable_ext_wow_parser(adapter, + adapter->sessionId, + set_value); +} + +static int drv_cmd_set_app1_params(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret; + uint8_t *value = command; + + /* Move pointer to ahead of SETAPP1PARAMS */ + value = value + command_len; + + ret = hdd_set_app_type1_parser(adapter, + value, strlen(value)); + if (ret >= 0) + hdd_ctx->is_extwow_app_type1_param_set = true; + + return ret; +} + +static int drv_cmd_set_app2_params(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret; + uint8_t *value = command; + + /* Move pointer to ahead of SETAPP2PARAMS */ + value = value + command_len; + + ret = hdd_set_app_type2_parser(adapter, value, strlen(value)); + if (ret >= 0) + hdd_ctx->is_extwow_app_type2_param_set = true; + + return ret; +} +#endif /* WLAN_FEATURE_EXTWOW_SUPPORT */ + +#ifdef FEATURE_WLAN_TDLS +/** + * drv_cmd_tdls_secondary_channel_offset() - secondary tdls off channel offset + * @adapter: Pointer to the HDD adapter + * @hdd_ctx: Pointer to the HDD context + * @command: Driver command string + * @command_len: Driver command string length + * @priv_data: Private data coming with the driver command. Unused here + * + * This function handles driver command that sets the secondary tdls off channel + * offset + * + * Return: 0 on success; negative errno otherwise + */ +static int drv_cmd_tdls_secondary_channel_offset(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret; + uint8_t *value = command; + int set_value; + + /* Move pointer to point the string */ + value += command_len; + + ret = sscanf(value, "%d", &set_value); + if (ret != 1) + return -EINVAL; + + hdd_info("Tdls offchannel offset:%d", set_value); + + ret = hdd_set_tdls_secoffchanneloffset(hdd_ctx, set_value); + + return ret; +} + +/** + * drv_cmd_tdls_off_channel_mode() - set tdls off channel mode + * @adapter: Pointer to the HDD adapter + * @hdd_ctx: Pointer to the HDD context + * @command: Driver command string + * @command_len: Driver command string length + * @priv_data: Private data coming with the driver command. Unused here + * + * This function handles driver command that sets tdls off channel mode + * + * Return: 0 on success; negative errno otherwise + */ +static int drv_cmd_tdls_off_channel_mode(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret; + uint8_t *value = command; + int set_value; + + /* Move pointer to point the string */ + value += command_len; + + ret = sscanf(value, "%d", &set_value); + if (ret != 1) + return -EINVAL; + + hdd_info("Tdls offchannel mode:%d", set_value); + + ret = hdd_set_tdls_offchannelmode(adapter, set_value); + + return ret; +} + +/** + * drv_cmd_tdls_off_channel() - set tdls off channel number + * @adapter: Pointer to the HDD adapter + * @hdd_ctx: Pointer to the HDD context + * @command: Driver command string + * @command_len: Driver command string length + * @priv_data: Private data coming with the driver command. Unused here + * + * This function handles driver command that sets tdls off channel number + * + * Return: 0 on success; negative errno otherwise + */ +static int drv_cmd_tdls_off_channel(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret; + uint8_t *value = command; + int set_value; + + /* Move pointer to point the string */ + value += command_len; + + ret = sscanf(value, "%d", &set_value); + if (ret != 1) + return -EINVAL; + + if (CDS_IS_DFS_CH(set_value)) { + hdd_err("DFS channel %d is passed for hdd_set_tdls_offchannel", + set_value); + return -EINVAL; + } + + hdd_info("Tdls offchannel num: %d", set_value); + + ret = hdd_set_tdls_offchannel(hdd_ctx, set_value); + + return ret; +} + +/** + * drv_cmd_tdls_scan() - set tdls scan type + * @adapter: Pointer to the HDD adapter + * @hdd_ctx: Pointer to the HDD context + * @command: Driver command string + * @command_len: Driver command string length + * @priv_data: Private data coming with the driver command. Unused here + * + * This function handles driver command that sets tdls scan type + * + * Return: 0 on success; negative errno otherwise + */ +static int drv_cmd_tdls_scan(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret; + uint8_t *value = command; + int set_value; + + /* Move pointer to point the string */ + value += command_len; + + ret = sscanf(value, "%d", &set_value); + if (ret != 1) + return -EINVAL; + + hdd_info("Tdls scan type val: %d", set_value); + + ret = hdd_set_tdls_scan_type(hdd_ctx, set_value); + + return ret; +} +#endif + +static int drv_cmd_get_rssi(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret = 0; + int8_t rssi = 0; + char extra[32]; + + uint8_t len = 0; + + wlan_hdd_get_rssi(adapter, &rssi); + + len = scnprintf(extra, sizeof(extra), "%s %d", command, rssi); + len = QDF_MIN(priv_data->total_len, len + 1); + + if (copy_to_user(priv_data->buf, &extra, len)) { + hdd_err("Failed to copy data to user buffer"); + ret = -EFAULT; + } + + return ret; +} + +static int drv_cmd_get_linkspeed(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + int ret; + uint32_t link_speed = 0; + char extra[32]; + uint8_t len = 0; + + ret = wlan_hdd_get_link_speed(adapter, &link_speed); + if (0 != ret) + return ret; + + len = scnprintf(extra, sizeof(extra), "%s %d", command, link_speed); + len = QDF_MIN(priv_data->total_len, len + 1); + if (copy_to_user(priv_data->buf, &extra, len)) { + hdd_err("Failed to copy data to user buffer"); + ret = -EFAULT; + } + + return ret; +} + +/** + * hdd_set_rx_filter() - set RX filter + * @adapter: Pointer to adapter + * @action: Filter action + * @pattern: Address pattern + * + * Address pattern is most significant byte of address for example + * 0x01 for IPV4 multicast address + * 0x33 for IPV6 multicast address + * 0xFF for broadcast address + * + * Return: 0 for success, non-zero for failure + */ +static int hdd_set_rx_filter(hdd_adapter_t *adapter, bool action, + uint8_t pattern) +{ + int ret; + uint8_t i, j; + tHalHandle handle; + tSirRcvFltMcAddrList *filter; + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + handle = hdd_ctx->hHal; + + if (NULL == handle) { + hdd_err("HAL Handle is NULL"); + return -EINVAL; + } + + if (!hdd_ctx->config->fEnableMCAddrList) { + hdd_notice("mc addr ini is disabled"); + return -EINVAL; + } + + /* + * If action is false it means start dropping packets + * Set addr_filter_pattern which will be used when sending + * MC/BC address list to target + */ + if (!action) + adapter->addr_filter_pattern = pattern; + else + adapter->addr_filter_pattern = 0; + + if (((adapter->device_mode == QDF_STA_MODE) || + (adapter->device_mode == QDF_P2P_CLIENT_MODE)) && + adapter->mc_addr_list.mc_cnt && + hdd_conn_is_connected(WLAN_HDD_GET_STATION_CTX_PTR(adapter))) { + + + filter = qdf_mem_malloc(sizeof(*filter)); + if (NULL == filter) { + hdd_err("Could not allocate Memory"); + return -ENOMEM; + } + filter->action = action; + for (i = 0, j = 0; i < adapter->mc_addr_list.mc_cnt; i++) { + if (!memcmp(adapter->mc_addr_list.addr[i], + &pattern, 1)) { + memcpy(filter->multicastAddr[j].bytes, + adapter->mc_addr_list.addr[i], + sizeof(adapter->mc_addr_list.addr[i])); + + hdd_info("%s RX filter : addr =" + MAC_ADDRESS_STR, + action ? "setting" : "clearing", + MAC_ADDR_ARRAY(filter->multicastAddr[j].bytes)); + j++; + } + if (j == WLAN_HDD_MAX_MC_ADDR_LIST) + break; + } + filter->ulMulticastAddrCnt = j; + /* Set rx filter */ + sme_8023_multicast_list(handle, adapter->sessionId, filter); + qdf_mem_free(filter); + } else { + hdd_info("mode %d mc_cnt %d", + adapter->device_mode, adapter->mc_addr_list.mc_cnt); + } + + return 0; +} + +/** + * hdd_driver_rxfilter_comand_handler() - RXFILTER driver command handler + * @command: Pointer to input string driver command + * @adapter: Pointer to adapter + * @action: Action to enable/disable filtering + * + * If action == false + * Start filtering out data packets based on type + * RXFILTER-REMOVE 0 -> Start filtering out unicast data packets + * RXFILTER-REMOVE 1 -> Start filtering out broadcast data packets + * RXFILTER-REMOVE 2 -> Start filtering out IPV4 mcast data packets + * RXFILTER-REMOVE 3 -> Start filtering out IPV6 mcast data packets + * + * if action == true + * Stop filtering data packets based on type + * RXFILTER-ADD 0 -> Stop filtering unicast data packets + * RXFILTER-ADD 1 -> Stop filtering broadcast data packets + * RXFILTER-ADD 2 -> Stop filtering IPV4 mcast data packets + * RXFILTER-ADD 3 -> Stop filtering IPV6 mcast data packets + * + * Current implementation only supports IPV4 address filtering by + * selectively allowing IPV4 multicast data packest based on + * address list received in .ndo_set_rx_mode + * + * Return: 0 for success, non-zero for failure + */ +static int hdd_driver_rxfilter_comand_handler(uint8_t *command, + hdd_adapter_t *adapter, + bool action) +{ + int ret = 0; + uint8_t *value; + uint8_t type; + + value = command; + /* Skip space after RXFILTER-REMOVE OR RXFILTER-ADD based on action */ + if (!action) + value = command + 16; + else + value = command + 13; + ret = kstrtou8(value, 10, &type); + if (ret < 0) { + hdd_err("kstrtou8 failed invalid input value %d", type); + return -EINVAL; + } + + switch (type) { + case 2: + /* Set rx filter for IPV4 multicast data packets */ + ret = hdd_set_rx_filter(adapter, action, 0x01); + break; + default: + hdd_info("Unsupported RXFILTER type %d", type); + break; + } + + return ret; +} + +/** + * drv_cmd_rx_filter_remove() - RXFILTER REMOVE driver command handler + * @adapter: Pointer to network adapter + * @hdd_ctx: Pointer to hdd context + * @command: Pointer to input command + * @command_len: Command length + * @priv_data: Pointer to private data in command + */ +static int drv_cmd_rx_filter_remove(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + return hdd_driver_rxfilter_comand_handler(command, adapter, false); +} + +/** + * drv_cmd_rx_filter_add() - RXFILTER ADD driver command handler + * @adapter: Pointer to network adapter + * @hdd_ctx: Pointer to hdd context + * @command: Pointer to input command + * @command_len: Command length + * @priv_data: Pointer to private data in command + */ +static int drv_cmd_rx_filter_add(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + return hdd_driver_rxfilter_comand_handler(command, adapter, true); +} + +/** + * hdd_parse_setantennamode_command() - HDD Parse SETANTENNAMODE + * command + * @value: Pointer to SETANTENNAMODE command + * @mode: Pointer to antenna mode + * @reason: Pointer to reason for set antenna mode + * + * This function parses the SETANTENNAMODE command passed in the format + * SETANTENNAMODEmode + * + * Return: 0 for success non-zero for failure + */ +static int hdd_parse_setantennamode_command(const uint8_t *value) +{ + const uint8_t *in_ptr = value; + int tmp, v; + char arg1[32]; + + in_ptr = strnchr(value, strlen(value), SPACE_ASCII_VALUE); + + /* no argument after the command */ + if (NULL == in_ptr) { + hdd_err("No argument after the command"); + return -EINVAL; + } + + /* no space after the command */ + if (SPACE_ASCII_VALUE != *in_ptr) { + hdd_err("No space after the command"); + return -EINVAL; + } + + /* remove empty spaces */ + while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr)) + in_ptr++; + + /* no argument followed by spaces */ + if ('\0' == *in_ptr) { + hdd_err("No argument followed by spaces"); + return -EINVAL; + } + + /* get the argument i.e. antenna mode */ + v = sscanf(in_ptr, "%31s ", arg1); + if (1 != v) { + hdd_err("argument retrieval from cmd string failed"); + return -EINVAL; + } + + v = kstrtos32(arg1, 10, &tmp); + if (v < 0) { + hdd_err("argument string to int conversion failed"); + return -EINVAL; + } + + return tmp; +} + +/** + * hdd_is_supported_chain_mask_2x2() - Verify if supported chain + * mask is 2x2 mode + * @hdd_ctx: Pointer to hdd contex + * + * Return: true if supported chain mask 2x2 else false + */ +static bool hdd_is_supported_chain_mask_2x2(hdd_context_t *hdd_ctx) +{ + /* + * Revisit and the update logic to determine the number + * of TX/RX chains supported in the system when + * antenna sharing per band chain mask support is + * brought in + */ + return (hdd_ctx->config->enable2x2 == 0x01) ? true : false; +} + +/** + * hdd_is_supported_chain_mask_1x1() - Verify if the supported + * chain mask is 1x1 + * @hdd_ctx: Pointer to hdd contex + * + * Return: true if supported chain mask 1x1 else false + */ +static bool hdd_is_supported_chain_mask_1x1(hdd_context_t *hdd_ctx) +{ + /* + * Revisit and update the logic to determine the number + * of TX/RX chains supported in the system when + * antenna sharing per band chain mask support is + * brought in + */ + return (!hdd_ctx->config->enable2x2) ? true : false; +} + +QDF_STATUS hdd_update_smps_antenna_mode(hdd_context_t *hdd_ctx, int mode) +{ + QDF_STATUS status; + uint8_t smps_mode; + uint8_t smps_enable; + + /* Update SME SMPS config */ + if (HDD_ANTENNA_MODE_1X1 == mode) { + smps_enable = true; + smps_mode = HDD_SMPS_MODE_STATIC; + } else { + smps_enable = false; + smps_mode = HDD_SMPS_MODE_DISABLED; + } + + hdd_info("Update SME SMPS enable: %d mode: %d", + smps_enable, smps_mode); + status = sme_update_mimo_power_save( + hdd_ctx->hHal, smps_enable, smps_mode, false); + if (QDF_STATUS_SUCCESS != status) { + hdd_err("Update SMPS config failed enable: %d mode: %d" + "status: %d", + smps_enable, smps_mode, status); + return QDF_STATUS_E_FAILURE; + } + + hdd_ctx->current_antenna_mode = mode; + /* + * Update the user requested nss in the mac context. + * This will be used in tdls protocol engine to form tdls + * Management frames. + */ + sme_update_user_configured_nss( + hdd_ctx->hHal, + hdd_ctx->current_antenna_mode); + + hdd_info("Successfully switched to mode: %d x %d", + hdd_ctx->current_antenna_mode, + hdd_ctx->current_antenna_mode); + + return QDF_STATUS_SUCCESS; +} + +/** + * drv_cmd_set_antenna_mode() - SET ANTENNA MODE driver command + * handler + * @adapter: Pointer to network adapter + * @hdd_ctx: Pointer to hdd context + * @command: Pointer to input command + * @command_len: Command length + * @priv_data: Pointer to private data in command + */ +static int drv_cmd_set_antenna_mode(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + struct sir_antenna_mode_param params; + QDF_STATUS status; + int ret = 0; + int mode; + uint8_t *value = command; + + if (((1 << QDF_STA_MODE) != hdd_ctx->concurrency_mode) || + (hdd_ctx->no_of_active_sessions[QDF_STA_MODE] > 1)) { + hdd_err("Operation invalid in non sta or concurrent mode"); + ret = -EPERM; + goto exit; + } + + mode = hdd_parse_setantennamode_command(value); + if (mode < 0) { + hdd_err("Invalid SETANTENNA command"); + ret = mode; + goto exit; + } + + hdd_info("Processing antenna mode switch to: %d", mode); + + if (hdd_ctx->current_antenna_mode == mode) { + hdd_err("System already in the requested mode"); + ret = 0; + goto exit; + } + + if ((HDD_ANTENNA_MODE_2X2 == mode) && + (!hdd_is_supported_chain_mask_2x2(hdd_ctx))) { + hdd_err("System does not support 2x2 mode"); + ret = -EPERM; + goto exit; + } + + if ((HDD_ANTENNA_MODE_1X1 == mode) && + hdd_is_supported_chain_mask_1x1(hdd_ctx)) { + hdd_err("System only supports 1x1 mode"); + ret = 0; + goto exit; + } + + switch (mode) { + case HDD_ANTENNA_MODE_1X1: + params.num_rx_chains = 1; + params.num_tx_chains = 1; + break; + case HDD_ANTENNA_MODE_2X2: + params.num_rx_chains = 2; + params.num_tx_chains = 2; + break; + default: + hdd_err("unsupported antenna mode"); + ret = -EINVAL; + goto exit; + } + + /* Check TDLS status and update antenna mode */ + if ((QDF_STA_MODE == adapter->device_mode) && + cds_is_sta_active_connection_exists()) { + ret = wlan_hdd_tdls_antenna_switch(hdd_ctx, adapter, + mode); + if (0 != ret) + goto exit; + } + + params.set_antenna_mode_resp = + (void *)wlan_hdd_soc_set_antenna_mode_cb; + hdd_info("Set antenna mode rx chains: %d tx chains: %d", + params.num_rx_chains, + params.num_tx_chains); + + + INIT_COMPLETION(hdd_ctx->set_antenna_mode_cmpl); + status = sme_soc_set_antenna_mode(hdd_ctx->hHal, ¶ms); + if (QDF_STATUS_SUCCESS != status) { + hdd_err("set antenna mode failed status : %d", status); + ret = -EFAULT; + goto exit; + } + + ret = wait_for_completion_timeout( + &hdd_ctx->set_antenna_mode_cmpl, + msecs_to_jiffies(WLAN_WAIT_TIME_ANTENNA_MODE_REQ)); + if (!ret) { + ret = -EFAULT; + hdd_err("send set antenna mode timed out"); + goto exit; + } + + status = hdd_update_smps_antenna_mode(hdd_ctx, mode); + if (QDF_STATUS_SUCCESS != status) { + ret = -EFAULT; + goto exit; + } + ret = 0; +exit: +#ifdef FEATURE_WLAN_TDLS + /* Reset tdls NSS flags */ + if (hdd_ctx->tdls_nss_switch_in_progress && + hdd_ctx->tdls_nss_teardown_complete) { + hdd_ctx->tdls_nss_switch_in_progress = false; + hdd_ctx->tdls_nss_teardown_complete = false; + } + hdd_info("tdls_nss_switch_in_progress: %d tdls_nss_teardown_complete: %d", + hdd_ctx->tdls_nss_switch_in_progress, + hdd_ctx->tdls_nss_teardown_complete); +#endif + hdd_info("Set antenna status: %d current mode: %d", + ret, hdd_ctx->current_antenna_mode); + return ret; + +} + +/** + * drv_cmd_get_antenna_mode() - GET ANTENNA MODE driver command + * handler + * @adapter: Pointer to hdd adapter + * @hdd_ctx: Pointer to hdd context + * @command: Pointer to input command + * @command_len: length of the command + * @priv_data: private data coming with the driver command + * + * Return: 0 for success non-zero for failure + */ +static inline int drv_cmd_get_antenna_mode(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + uint32_t antenna_mode = 0; + char extra[32]; + uint8_t len = 0; + + antenna_mode = hdd_ctx->current_antenna_mode; + len = scnprintf(extra, sizeof(extra), "%s %d", command, + antenna_mode); + len = QDF_MIN(priv_data->total_len, len + 1); + if (copy_to_user(priv_data->buf, &extra, len)) { + hdd_err("Failed to copy data to user buffer"); + return -EFAULT; + } + + hdd_info("Get antenna mode: %d", antenna_mode); + + return 0; +} + +/* + * dummy (no-op) hdd driver command handler + */ +static int drv_cmd_dummy(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + hdd_info("%s: Ignoring driver command \"%s\"", + adapter->dev->name, command); + return 0; +} + +/* + * handler for any unsupported wlan hdd driver command + */ +static int drv_cmd_invalid(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + MTRACE(qdf_trace(QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_UNSUPPORTED_IOCTL, + adapter->sessionId, 0)); + + hdd_warn("%s: Unsupported driver command \"%s\"", + adapter->dev->name, command); + + return -ENOTSUPP; +} + +/** + * drv_cmd_set_fcc_channel() - handle fcc constraint request + * @adapter: HDD adapter + * @hdd_ctx: HDD context + * @command: command ptr, SET_FCC_CHANNEL 0/1 is the command + * @command_len: command len + * @priv_data: private data + * + * Return: status + */ +static int drv_cmd_set_fcc_channel(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + uint8_t *value; + uint8_t fcc_constraint; + QDF_STATUS status; + bool scan_pending; + int ret = 0; + + /* + * this command would be called by user-space when it detects WLAN + * ON after airplane mode is set. When APM is set, WLAN turns off. + * But it can be turned back on. Otherwise; when APM is turned back + * off, WLAN would turn back on. So at that point the command is + * expected to come down. 0 means disable, 1 means enable. The + * constraint is removed when parameter 1 is set or different + * country code is set + */ + + value = command + command_len + 1; + + ret = kstrtou8(value, 10, &fcc_constraint); + if ((ret < 0) || (fcc_constraint > 1)) { + /* + * If the input value is greater than max value of datatype, + * then also it is a failure + */ + hdd_err("value out of range"); + return -EINVAL; + } + + scan_pending = !qdf_list_empty(&hdd_ctx->hdd_scan_req_q); + status = sme_handle_set_fcc_channel(hdd_ctx->hHal, !fcc_constraint, + scan_pending); + if (status != QDF_STATUS_SUCCESS) { + hdd_err("sme disable fn. returned err"); + ret = -EPERM; + } + + return ret; +} + +/** + * hdd_parse_set_channel_switch_command() - Parse and validate CHANNEL_SWITCH + * command + * @value: Pointer to the command + * @chan_number: Pointer to the channel number + * @chan_bw: Pointer to the channel bandwidth + * + * Parses and provides the channel number and channel width from the input + * command which is expected to be of the format: CHANNEL_SWITCH + * is channel number to move (where 1 = channel 1, 149 = channel 149, ...) + * is bandwidth to move (where 20 = BW 20, 40 = BW 40, 80 = BW 80) + * + * Return: 0 for success, non-zero for failure + */ +static int hdd_parse_set_channel_switch_command(uint8_t *value, + uint32_t *chan_number, + uint32_t *chan_bw) +{ + const uint8_t *in_ptr = value; + int ret; + + in_ptr = strnchr(value, strlen(value), SPACE_ASCII_VALUE); + + /* no argument after the command */ + if (NULL == in_ptr) { + hdd_err("No argument after the command"); + return -EINVAL; + } + + /* no space after the command */ + if (SPACE_ASCII_VALUE != *in_ptr) { + hdd_err("No space after the command "); + return -EINVAL; + } + + /* remove empty spaces and move the next argument */ + while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr)) + in_ptr++; + + /* no argument followed by spaces */ + if ('\0' == *in_ptr) { + hdd_err("No argument followed by spaces"); + return -EINVAL; + } + + /* get the two arguments: channel number and bandwidth */ + ret = sscanf(in_ptr, "%u %u", chan_number, chan_bw); + if (ret != 2) { + hdd_err("Arguments retrieval from cmd string failed"); + return -EINVAL; + } + + return 0; +} + +/** + * drv_cmd_set_channel_switch() - Switch SAP/P2P-GO operating channel + * @adapter: HDD adapter + * @hdd_ctx: HDD context + * @command: Pointer to the input command CHANNEL_SWITCH + * @command_len: Command len + * @priv_data: Private data + * + * Handles private IOCTL CHANNEL_SWITCH command to switch the operating channel + * of SAP/P2P-GO + * + * Return: 0 for success, non-zero for failure + */ +static int drv_cmd_set_channel_switch(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx, + uint8_t *command, + uint8_t command_len, + hdd_priv_data_t *priv_data) +{ + struct net_device *dev = adapter->dev; + int status; + uint32_t chan_number = 0, chan_bw = 0; + uint8_t *value = command; + enum phy_ch_width width; + + if ((adapter->device_mode != QDF_P2P_GO_MODE) && + (adapter->device_mode != QDF_SAP_MODE)) { + hdd_err("IOCTL CHANNEL_SWITCH not supported for mode %d", + adapter->device_mode); + return -EINVAL; + } + + status = hdd_parse_set_channel_switch_command(value, + &chan_number, &chan_bw); + if (status) { + hdd_err("Invalid CHANNEL_SWITCH command"); + return status; + } + + if ((chan_bw != 20) && (chan_bw != 40) && (chan_bw != 80)) { + hdd_err("BW %d is not allowed for CHANNEL_SWITCH", chan_bw); + return -EINVAL; + } + + if (chan_bw == 80) + width = CH_WIDTH_80MHZ; + else if (chan_bw == 40) + width = CH_WIDTH_40MHZ; + else + width = CH_WIDTH_20MHZ; + + hdd_info("CH:%d BW:%d", chan_number, chan_bw); + + status = hdd_softap_set_channel_change(dev, chan_number, width); + if (status) { + hdd_err("Set channel change fail"); + return status; + } + + return 0; +} + +/* + * The following table contains all supported WLAN HDD + * IOCTL driver commands and the handler for each of them. + */ +static const hdd_drv_cmd_t hdd_drv_cmds[] = { + {"P2P_DEV_ADDR", drv_cmd_p2p_dev_addr}, + {"P2P_SET_NOA", drv_cmd_p2p_set_noa}, + {"P2P_SET_PS", drv_cmd_p2p_set_ps}, + {"SETBAND", drv_cmd_set_band}, + {"SETWMMPS", drv_cmd_set_wmmps}, + {"COUNTRY", drv_cmd_country}, + {"SETSUSPENDMODE", drv_cmd_dummy}, + {"SET_AP_WPS_P2P_IE", drv_cmd_dummy}, + {"BTCOEXSCAN", drv_cmd_dummy}, + {"RXFILTER", drv_cmd_dummy}, + {"SETROAMTRIGGER", drv_cmd_set_roam_trigger}, + {"GETROAMTRIGGER", drv_cmd_get_roam_trigger}, + {"SETROAMSCANPERIOD", drv_cmd_set_roam_scan_period}, + {"GETROAMSCANPERIOD", drv_cmd_get_roam_scan_period}, + {"SETROAMSCANREFRESHPERIOD", drv_cmd_set_roam_scan_refresh_period}, + {"GETROAMSCANREFRESHPERIOD", drv_cmd_get_roam_scan_refresh_period}, + {"SETROAMMODE", drv_cmd_set_roam_mode}, + {"GETROAMMODE", drv_cmd_get_roam_mode}, + {"SETROAMDELTA", drv_cmd_set_roam_delta}, + {"GETROAMDELTA", drv_cmd_get_roam_delta}, + {"GETBAND", drv_cmd_get_band}, + {"SETROAMSCANCHANNELS", drv_cmd_set_roam_scan_channels}, + {"GETROAMSCANCHANNELS", drv_cmd_get_roam_scan_channels}, + {"GETCCXMODE", drv_cmd_get_ccx_mode}, + {"GETOKCMODE", drv_cmd_get_okc_mode}, + {"GETFASTROAM", drv_cmd_get_fast_roam}, + {"GETFASTTRANSITION", drv_cmd_get_fast_transition}, + {"SETROAMSCANCHANNELMINTIME", drv_cmd_set_roam_scan_channel_min_time}, + {"SENDACTIONFRAME", drv_cmd_send_action_frame}, + {"GETROAMSCANCHANNELMINTIME", drv_cmd_get_roam_scan_channel_min_time}, + {"SETSCANCHANNELTIME", drv_cmd_set_scan_channel_time}, + {"GETSCANCHANNELTIME", drv_cmd_get_scan_channel_time}, + {"SETSCANHOMETIME", drv_cmd_set_scan_home_time}, + {"GETSCANHOMETIME", drv_cmd_get_scan_home_time}, + {"SETROAMINTRABAND", drv_cmd_set_roam_intra_band}, + {"GETROAMINTRABAND", drv_cmd_get_roam_intra_band}, + {"SETSCANNPROBES", drv_cmd_set_scan_n_probes}, + {"GETSCANNPROBES", drv_cmd_get_scan_n_probes}, + {"SETSCANHOMEAWAYTIME", drv_cmd_set_scan_home_away_time}, + {"GETSCANHOMEAWAYTIME", drv_cmd_get_scan_home_away_time}, + {"REASSOC", drv_cmd_reassoc}, + {"SETWESMODE", drv_cmd_set_wes_mode}, + {"GETWESMODE", drv_cmd_get_wes_mode}, + {"SETOPPORTUNISTICRSSIDIFF", drv_cmd_set_opportunistic_rssi_diff}, + {"GETOPPORTUNISTICRSSIDIFF", drv_cmd_get_opportunistic_rssi_diff}, + {"SETROAMRESCANRSSIDIFF", drv_cmd_set_roam_rescan_rssi_diff}, + {"GETROAMRESCANRSSIDIFF", drv_cmd_get_roam_rescan_rssi_diff}, + {"SETFASTROAM", drv_cmd_set_fast_roam}, + {"SETFASTTRANSITION", drv_cmd_set_fast_transition}, + {"FASTREASSOC", drv_cmd_fast_reassoc}, + {"SETROAMSCANCONTROL", drv_cmd_set_roam_scan_control}, + {"SETOKCMODE", drv_cmd_set_okc_mode}, + {"GETROAMSCANCONTROL", drv_cmd_get_roam_scan_control}, + {"BTCOEXMODE", drv_cmd_bt_coex_mode}, + {"SCAN-ACTIVE", drv_cmd_scan_active}, + {"SCAN-PASSIVE", drv_cmd_scan_passive}, + {"GETDWELLTIME", drv_cmd_get_dwell_time}, + {"SETDWELLTIME", drv_cmd_set_dwell_time}, + {"MIRACAST", drv_cmd_miracast}, + {"SETIBSSBEACONOUIDATA", drv_cmd_set_ibss_beacon_oui_data}, + {"SETRMCENABLE", drv_cmd_set_rmc_enable}, + {"SETRMCACTIONPERIOD", drv_cmd_set_rmc_action_period}, + {"GETIBSSPEERINFOALL", drv_cmd_get_ibss_peer_info_all}, + {"GETIBSSPEERINFO", drv_cmd_get_ibss_peer_info}, + {"SETRMCTXRATE", drv_cmd_set_rmc_tx_rate}, + {"SETIBSSTXFAILEVENT", drv_cmd_set_ibss_tx_fail_event}, +#ifdef FEATURE_WLAN_ESE + {"SETCCXROAMSCANCHANNELS", drv_cmd_set_ccx_roam_scan_channels}, + {"GETTSMSTATS", drv_cmd_get_tsm_stats}, + {"SETCCKMIE", drv_cmd_set_cckm_ie}, + {"CCXBEACONREQ", drv_cmd_ccx_beacon_req}, + {"CCXPLMREQ", drv_cmd_ccx_plm_req}, + {"SETCCXMODE", drv_cmd_set_ccx_mode}, +#endif /* FEATURE_WLAN_ESE */ + {"SETMCRATE", drv_cmd_set_mc_rate}, + {"MAXTXPOWER", drv_cmd_max_tx_power}, + {"SETDFSSCANMODE", drv_cmd_set_dfs_scan_mode}, + {"GETDFSSCANMODE", drv_cmd_get_dfs_scan_mode}, + {"GETLINKSTATUS", drv_cmd_get_link_status}, +#ifdef WLAN_FEATURE_EXTWOW_SUPPORT + {"ENABLEEXTWOW", drv_cmd_enable_ext_wow}, + {"SETAPP1PARAMS", drv_cmd_set_app1_params}, + {"SETAPP2PARAMS", drv_cmd_set_app2_params}, +#endif +#ifdef FEATURE_WLAN_TDLS + {"TDLSSECONDARYCHANNELOFFSET", drv_cmd_tdls_secondary_channel_offset}, + {"TDLSOFFCHANNELMODE", drv_cmd_tdls_off_channel_mode}, + {"TDLSOFFCHANNEL", drv_cmd_tdls_off_channel}, + {"TDLSSCAN", drv_cmd_tdls_scan}, +#endif + {"RSSI", drv_cmd_get_rssi}, + {"LINKSPEED", drv_cmd_get_linkspeed}, + {"RXFILTER-REMOVE", drv_cmd_rx_filter_remove}, + {"RXFILTER-ADD", drv_cmd_rx_filter_add}, + {"SET_FCC_CHANNEL", drv_cmd_set_fcc_channel}, + {"CHANNEL_SWITCH", drv_cmd_set_channel_switch}, + {"SETANTENNAMODE", drv_cmd_set_antenna_mode}, + {"GETANTENNAMODE", drv_cmd_get_antenna_mode}, + {"STOP", drv_cmd_dummy}, +}; + +/** + * hdd_drv_cmd_process() - chooses and runs the proper + * handler based on the input command + * @adapter: Pointer to the hdd adapter + * @cmd: Pointer to the driver command + * @priv_data: Pointer to the data associated with the command + * + * This function parses the input hdd driver command and runs + * the proper handler + * + * Return: 0 for success non-zero for failure + */ +static int hdd_drv_cmd_process(hdd_adapter_t *adapter, + uint8_t *cmd, + hdd_priv_data_t *priv_data) +{ + hdd_context_t *hdd_ctx; + int i; + const int cmd_num_total = ARRAY_SIZE(hdd_drv_cmds); + uint8_t *cmd_i = NULL; + hdd_drv_cmd_handler_t handler = NULL; + int len = 0; + + if (!adapter || !cmd || !priv_data) { + hdd_err("at least 1 param is NULL"); + return -EINVAL; + } + + hdd_ctx = (hdd_context_t *)adapter->pHddCtx; + + for (i = 0; i < cmd_num_total; i++) { + + cmd_i = (uint8_t *)hdd_drv_cmds[i].cmd; + handler = hdd_drv_cmds[i].handler; + len = strlen(cmd_i); + + if (!handler) { + hdd_err("no. %d handler is NULL", i); + return -EINVAL; + } + + if (strncasecmp(cmd, cmd_i, len) == 0) + return handler(adapter, hdd_ctx, + cmd, len, priv_data); + } + + return drv_cmd_invalid(adapter, hdd_ctx, cmd, len, priv_data); +} + +/** + * hdd_driver_command() - top level wlan hdd driver command handler + * @adapter: Pointer to the hdd adapter + * @priv_data: Pointer to the raw command data + * + * This function is the top level wlan hdd driver command handler. It + * handles the command with the help of hdd_drv_cmd_process() + * + * Return: 0 for success non-zero for failure + */ +static int hdd_driver_command(hdd_adapter_t *adapter, + hdd_priv_data_t *priv_data) +{ + uint8_t *command = NULL; + int ret = 0; + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + + ENTER(); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EINVAL; + } + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return ret; + + if (hdd_ctx->driver_status == DRIVER_MODULES_CLOSED) { + hdd_err("Driver module is closed; command can not be processed"); + return -EINVAL; + } + + /* + * Note that valid pointers are provided by caller + */ + + /* copy to local struct to avoid numerous changes to legacy code */ + if (priv_data->total_len <= 0 || + priv_data->total_len > WLAN_PRIV_DATA_MAX_LEN) { + hdd_warn("Invalid priv_data.total_len(%d)!!!", + priv_data->total_len); + ret = -EINVAL; + goto exit; + } + + /* Allocate +1 for '\0' */ + command = qdf_mem_malloc(priv_data->total_len + 1); + if (!command) { + hdd_err("failed to allocate memory"); + ret = -ENOMEM; + goto exit; + } + + if (copy_from_user(command, priv_data->buf, priv_data->total_len)) { + ret = -EFAULT; + goto exit; + } + + /* Make sure the command is NUL-terminated */ + command[priv_data->total_len] = '\0'; + + hdd_info("%s: %s", adapter->dev->name, command); + ret = hdd_drv_cmd_process(adapter, command, priv_data); + +exit: + if (command) + qdf_mem_free(command); + EXIT(); + return ret; +} + +#ifdef CONFIG_COMPAT +static int hdd_driver_compat_ioctl(hdd_adapter_t *adapter, struct ifreq *ifr) +{ + struct { + compat_uptr_t buf; + int used_len; + int total_len; + } compat_priv_data; + hdd_priv_data_t priv_data; + int ret = 0; + + /* + * Note that adapter and ifr have already been verified by caller, + * and HDD context has also been validated + */ + if (copy_from_user(&compat_priv_data, ifr->ifr_data, + sizeof(compat_priv_data))) { + ret = -EFAULT; + goto exit; + } + priv_data.buf = compat_ptr(compat_priv_data.buf); + priv_data.used_len = compat_priv_data.used_len; + priv_data.total_len = compat_priv_data.total_len; + ret = hdd_driver_command(adapter, &priv_data); +exit: + return ret; +} +#else /* CONFIG_COMPAT */ +static int hdd_driver_compat_ioctl(hdd_adapter_t *adapter, struct ifreq *ifr) +{ + /* will never be invoked */ + return 0; +} +#endif /* CONFIG_COMPAT */ + +static int hdd_driver_ioctl(hdd_adapter_t *adapter, struct ifreq *ifr) +{ + hdd_priv_data_t priv_data; + int ret = 0; + + /* + * Note that adapter and ifr have already been verified by caller, + * and HDD context has also been validated + */ + if (copy_from_user(&priv_data, ifr->ifr_data, sizeof(priv_data))) + ret = -EFAULT; + else + ret = hdd_driver_command(adapter, &priv_data); + + return ret; +} + +/** + * __hdd_ioctl() - ioctl handler for wlan network interfaces + * @dev: device upon which the ioctl was received + * @ifr: ioctl request information + * @cmd: ioctl command + * + * This function does initial processing of wlan device ioctls. + * Currently two flavors of ioctls are supported. The primary ioctl + * that is supported is the (SIOCDEVPRIVATE + 1) ioctl which is used + * for Android "DRIVER" commands. The other ioctl that is + * conditionally supported is the SIOCIOCTLTX99 ioctl which is used + * for FTM on some platforms. This function simply verifies that the + * driver is in a sane state, and that the ioctl is one of the + * supported flavors, in which case flavor-specific handlers are + * dispatched. + * + * Return: 0 on success, non-zero on error + */ +static int __hdd_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) +{ + hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *hdd_ctx; + int ret; + + ENTER_DEV(dev); + + if (dev != adapter->dev) { + hdd_alert("HDD adapter/dev inconsistency"); + ret = -ENODEV; + goto exit; + } + + if ((!ifr) || (!ifr->ifr_data)) { + hdd_err("invalid data"); + ret = -EINVAL; + goto exit; + } +#if defined(QCA_WIFI_FTM) && defined(LINUX_QCMBR) + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + if (SIOCIOCTLTX99 == cmd) { + ret = wlan_hdd_qcmbr_unified_ioctl(adapter, ifr); + goto exit; + } + } +#endif + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + goto exit; + + switch (cmd) { + case (SIOCDEVPRIVATE + 1): + if (is_compat_task()) + ret = hdd_driver_compat_ioctl(adapter, ifr); + else + ret = hdd_driver_ioctl(adapter, ifr); + break; + default: + hdd_warn("unknown ioctl %d", cmd); + ret = -EINVAL; + break; + } +exit: + EXIT(); + return ret; +} + +/** + * hdd_ioctl() - ioctl handler (wrapper) for wlan network interfaces + * @dev: device upon which the ioctl was received + * @ifr: ioctl request information + * @cmd: ioctl command + * + * This function acts as an SSR-protecting wrapper to __hdd_ioctl() + * which is where the ioctls are really handled. + * + * Return: 0 on success, non-zero on error + */ +int hdd_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __hdd_ioctl(dev, ifr, cmd); + cds_ssr_unprotect(__func__); + return ret; +} diff --git a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_ioctl.h b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_ioctl.h new file mode 100644 index 0000000000000000000000000000000000000000..0a5388ddd90e46b19e0b5565c521d7d445efd2cc --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_ioctl.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2012-2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#if !defined(WLAN_HDD_IOCTL_H) +#define WLAN_HDD_IOCTL_H + +#include +#include +#include "wlan_hdd_main.h" + +int hdd_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd); +int wlan_hdd_set_mc_rate(hdd_adapter_t *pAdapter, int targetRate); + +/** + * hdd_update_smps_antenna_mode() - set smps and antenna mode + * @hdd_ctx: Pointer to hdd context + * @mode: antenna mode + * + * This function will set smps and antenna mode. + * + * Return: QDF_STATUS + */ +QDF_STATUS hdd_update_smps_antenna_mode(hdd_context_t *hdd_ctx, int mode); +#endif /* end #if !defined(WLAN_HDD_IOCTL_H) */ diff --git a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_ipa.c b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_ipa.c new file mode 100644 index 0000000000000000000000000000000000000000..c6eb0b4c9f39df762956f095372d885fed375e1b --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_ipa.c @@ -0,0 +1,6084 @@ +/* + * Copyright (c) 2013-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: wlan_hdd_ipa.c + * + * WLAN HDD and ipa interface implementation + * Originally written by Qualcomm Atheros, Inc + */ + +#ifdef IPA_OFFLOAD + +/* Include Files */ +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cds_sched.h" + +#include "wma.h" +#include "wma_api.h" +#include "wal_rx_desc.h" + +#include "cdp_txrx_ipa.h" + +#define HDD_IPA_DESC_BUFFER_RATIO 4 +#define HDD_IPA_IPV4_NAME_EXT "_ipv4" +#define HDD_IPA_IPV6_NAME_EXT "_ipv6" + +#define HDD_IPA_RX_INACTIVITY_MSEC_DELAY 1000 +#define HDD_IPA_UC_WLAN_8023_HDR_SIZE 14 +/* WDI TX and RX PIPE */ +#define HDD_IPA_UC_NUM_WDI_PIPE 2 +#define HDD_IPA_UC_MAX_PENDING_EVENT 33 + +#define HDD_IPA_UC_DEBUG_DUMMY_MEM_SIZE 32000 +#define HDD_IPA_UC_RT_DEBUG_PERIOD 300 +#define HDD_IPA_UC_RT_DEBUG_BUF_COUNT 30 +#define HDD_IPA_UC_RT_DEBUG_FILL_INTERVAL 10000 + +#define HDD_IPA_WLAN_HDR_DES_MAC_OFFSET 0 +#define HDD_IPA_MAX_IFACE 3 +#define HDD_IPA_MAX_SYSBAM_PIPE 4 +#define HDD_IPA_RX_PIPE HDD_IPA_MAX_IFACE +#define HDD_IPA_ENABLE_MASK BIT(0) +#define HDD_IPA_PRE_FILTER_ENABLE_MASK BIT(1) +#define HDD_IPA_IPV6_ENABLE_MASK BIT(2) +#define HDD_IPA_RM_ENABLE_MASK BIT(3) +#define HDD_IPA_CLK_SCALING_ENABLE_MASK BIT(4) +#define HDD_IPA_UC_ENABLE_MASK BIT(5) +#define HDD_IPA_UC_STA_ENABLE_MASK BIT(6) +#define HDD_IPA_REAL_TIME_DEBUGGING BIT(8) + +#define HDD_IPA_MAX_PENDING_EVENT_COUNT 20 + +typedef enum { + HDD_IPA_UC_OPCODE_TX_SUSPEND = 0, + HDD_IPA_UC_OPCODE_TX_RESUME = 1, + HDD_IPA_UC_OPCODE_RX_SUSPEND = 2, + HDD_IPA_UC_OPCODE_RX_RESUME = 3, + HDD_IPA_UC_OPCODE_STATS = 4, +#ifdef FEATURE_METERING + HDD_IPA_UC_OPCODE_SHARING_STATS = 5, + HDD_IPA_UC_OPCODE_QUOTA_RSP = 6, + HDD_IPA_UC_OPCODE_QUOTA_IND = 7, +#endif + HDD_IPA_UC_OPCODE_UC_READY = 8, + /* keep this last */ + HDD_IPA_UC_OPCODE_MAX +} hdd_ipa_uc_op_code; + +/** + * enum - Reason codes for stat query + * + * @HDD_IPA_UC_STAT_REASON_NONE: Initial value + * @HDD_IPA_UC_STAT_REASON_DEBUG: For debug/info + * @HDD_IPA_UC_STAT_REASON_BW_CAL: For bandwidth calibration + * @HDD_IPA_UC_STAT_REASON_DUMP_INFO: For debug info dump + */ +enum { + HDD_IPA_UC_STAT_REASON_NONE, + HDD_IPA_UC_STAT_REASON_DEBUG, + HDD_IPA_UC_STAT_REASON_BW_CAL, + HDD_IPA_UC_STAT_REASON_DUMP_INFO +}; + +/** + * enum hdd_ipa_rm_state - IPA resource manager state + * @HDD_IPA_RM_RELEASED: PROD pipe resource released + * @HDD_IPA_RM_GRANT_PENDING: PROD pipe resource requested but not granted yet + * @HDD_IPA_RM_GRANTED: PROD pipe resource granted + */ +enum hdd_ipa_rm_state { + HDD_IPA_RM_RELEASED, + HDD_IPA_RM_GRANT_PENDING, + HDD_IPA_RM_GRANTED, +}; + +struct llc_snap_hdr { + uint8_t dsap; + uint8_t ssap; + uint8_t resv[4]; + __be16 eth_type; +} __packed; + +/** + * struct hdd_ipa_tx_hdr - header type which IPA should handle to TX packet + * @eth: ether II header + * @llc_snap: LLC snap header + * + */ +struct hdd_ipa_tx_hdr { + struct ethhdr eth; + struct llc_snap_hdr llc_snap; +} __packed; + +/** + * struct frag_header - fragment header type registered to IPA hardware + * @length: fragment length + * @reserved1: Reserved not used + * @reserved2: Reserved not used + * + */ +struct frag_header { + uint16_t length; + uint32_t reserved1; + uint32_t reserved2; +} __packed; + +/** + * struct ipa_header - ipa header type registered to IPA hardware + * @vdev_id: vdev id + * @reserved: Reserved not used + * + */ +struct ipa_header { + uint32_t + vdev_id:8, /* vdev_id field is LSB of IPA DESC */ + reserved:24; +} __packed; + +/** + * struct hdd_ipa_uc_tx_hdr - full tx header registered to IPA hardware + * @frag_hd: fragment header + * @ipa_hd: ipa header + * @eth: ether II header + * + */ +struct hdd_ipa_uc_tx_hdr { + struct frag_header frag_hd; + struct ipa_header ipa_hd; + struct ethhdr eth; +} __packed; + +/** + * struct hdd_ipa_cld_hdr - IPA CLD Header + * @reserved: reserved fields + * @iface_id: interface ID + * @sta_id: Station ID + * + * Packed 32-bit structure + * +----------+----------+--------------+--------+ + * | Reserved | QCMAP ID | interface id | STA ID | + * +----------+----------+--------------+--------+ + */ +struct hdd_ipa_cld_hdr { + uint8_t reserved[2]; + uint8_t iface_id; + uint8_t sta_id; +} __packed; + +struct hdd_ipa_rx_hdr { + struct hdd_ipa_cld_hdr cld_hdr; + struct ethhdr eth; +} __packed; + +struct hdd_ipa_pm_tx_cb { + bool exception; + hdd_adapter_t *adapter; + struct hdd_ipa_iface_context *iface_context; + struct ipa_rx_data *ipa_tx_desc; +}; + +struct hdd_ipa_uc_rx_hdr { + struct ethhdr eth; +} __packed; + +struct hdd_ipa_sys_pipe { + uint32_t conn_hdl; + uint8_t conn_hdl_valid; + struct ipa_sys_connect_params ipa_sys_params; +}; + +struct hdd_ipa_iface_stats { + uint64_t num_tx; + uint64_t num_tx_drop; + uint64_t num_tx_err; + uint64_t num_tx_cac_drop; + uint64_t num_rx_prefilter; + uint64_t num_rx_ipa_excep; + uint64_t num_rx_recv; + uint64_t num_rx_recv_mul; + uint64_t num_rx_send_desc_err; + uint64_t max_rx_mul; +}; + +struct hdd_ipa_priv; + +struct hdd_ipa_iface_context { + struct hdd_ipa_priv *hdd_ipa; + hdd_adapter_t *adapter; + void *tl_context; + + enum ipa_client_type cons_client; + enum ipa_client_type prod_client; + + uint8_t iface_id; /* This iface ID */ + uint8_t sta_id; /* This iface station ID */ + qdf_spinlock_t interface_lock; + uint32_t ifa_address; + struct hdd_ipa_iface_stats stats; +}; + +struct hdd_ipa_stats { + uint32_t event[IPA_WLAN_EVENT_MAX]; + uint64_t num_send_msg; + uint64_t num_free_msg; + + uint64_t num_rm_grant; + uint64_t num_rm_release; + uint64_t num_rm_grant_imm; + uint64_t num_cons_perf_req; + uint64_t num_prod_perf_req; + + uint64_t num_rx_drop; + uint64_t num_rx_ipa_tx_dp; + uint64_t num_rx_ipa_splice; + uint64_t num_rx_ipa_loop; + uint64_t num_rx_ipa_tx_dp_err; + uint64_t num_rx_ipa_write_done; + uint64_t num_max_ipa_tx_mul; + uint64_t num_rx_ipa_hw_maxed_out; + + uint64_t num_tx_desc_q_cnt; + uint64_t num_tx_desc_error; + uint64_t num_tx_comp_cnt; + uint64_t num_tx_queued; + uint64_t num_tx_dequeued; + uint64_t num_max_pm_queue; + + uint64_t num_freeq_empty; + uint64_t num_pri_freeq_empty; + uint64_t num_rx_excep; + uint64_t num_tx_fwd_ok; + uint64_t num_tx_fwd_err; +}; + +struct ipa_uc_stas_map { + bool is_reserved; + uint8_t sta_id; +}; +struct op_msg_type { + uint8_t msg_t; + uint8_t rsvd; + uint16_t op_code; + uint16_t len; + uint16_t rsvd_snd; +}; + +struct ipa_uc_fw_stats { + uint32_t tx_comp_ring_base; + uint32_t tx_comp_ring_size; + uint32_t tx_comp_ring_dbell_addr; + uint32_t tx_comp_ring_dbell_ind_val; + uint32_t tx_comp_ring_dbell_cached_val; + uint32_t tx_pkts_enqueued; + uint32_t tx_pkts_completed; + uint32_t tx_is_suspend; + uint32_t tx_reserved; + uint32_t rx_ind_ring_base; + uint32_t rx_ind_ring_size; + uint32_t rx_ind_ring_dbell_addr; + uint32_t rx_ind_ring_dbell_ind_val; + uint32_t rx_ind_ring_dbell_ind_cached_val; + uint32_t rx_ind_ring_rdidx_addr; + uint32_t rx_ind_ring_rd_idx_cached_val; + uint32_t rx_refill_idx; + uint32_t rx_num_pkts_indicated; + uint32_t rx_buf_refilled; + uint32_t rx_num_ind_drop_no_space; + uint32_t rx_num_ind_drop_no_buf; + uint32_t rx_is_suspend; + uint32_t rx_reserved; +}; + +struct ipa_uc_pending_event { + qdf_list_node_t node; + hdd_adapter_t *adapter; + enum ipa_wlan_event type; + uint8_t sta_id; + uint8_t mac_addr[QDF_MAC_ADDR_SIZE]; +}; + +/** + * struct uc_rm_work_struct + * @work: uC RM work + * @event: IPA RM event + */ +struct uc_rm_work_struct { + struct work_struct work; + enum ipa_rm_event event; +}; + +/** + * struct uc_op_work_struct + * @work: uC OP work + * @msg: OP message + */ +struct uc_op_work_struct { + struct work_struct work; + struct op_msg_type *msg; +}; + +/** + * struct uc_rt_debug_info + * @time: system time + * @ipa_excep_count: IPA exception packet count + * @rx_drop_count: IPA Rx drop packet count + * @net_sent_count: IPA Rx packet sent to network stack count + * @rx_discard_count: IPA Rx discard packet count + * @tx_fwd_ok_count: IPA Tx forward success packet count + * @tx_fwd_count: IPA Tx forward packet count + * @rx_destructor_call: IPA Rx packet destructor count + */ +struct uc_rt_debug_info { + uint64_t time; + uint64_t ipa_excep_count; + uint64_t rx_drop_count; + uint64_t net_sent_count; + uint64_t rx_discard_count; + uint64_t tx_fwd_ok_count; + uint64_t tx_fwd_count; + uint64_t rx_destructor_call; +}; + +/** + * struct hdd_ipa_tx_desc + * @link: link to list head + * @priv: pointer to priv list entry + * @id: Tx desc idex + * @ipa_tx_desc_ptr: pointer to IPA Tx descriptor + */ +struct hdd_ipa_tx_desc { + struct list_head link; + void *priv; + uint32_t id; + struct ipa_rx_data *ipa_tx_desc_ptr; +}; + +#ifdef FEATURE_METERING +struct ipa_uc_sharing_stats { + uint64_t ipv4_rx_packets; + uint64_t ipv4_rx_bytes; + uint64_t ipv6_rx_packets; + uint64_t ipv6_rx_bytes; + uint64_t ipv4_tx_packets; + uint64_t ipv4_tx_bytes; + uint64_t ipv6_tx_packets; + uint64_t ipv6_tx_bytes; +}; + +struct ipa_uc_quota_rsp { + uint8_t success; + uint8_t reserved[3]; + uint32_t quota_lo; /* quota limit low bytes */ + uint32_t quota_hi; /* quota limit high bytes */ +}; + +struct ipa_uc_quota_ind { + uint64_t quota_bytes; /* quota limit in bytes */ +}; +#endif + +struct hdd_ipa_priv { + struct hdd_ipa_sys_pipe sys_pipe[HDD_IPA_MAX_SYSBAM_PIPE]; + struct hdd_ipa_iface_context iface_context[HDD_IPA_MAX_IFACE]; + uint8_t num_iface; + enum hdd_ipa_rm_state rm_state; + /* + * IPA driver can send RM notifications with IRQ disabled so using qdf + * APIs as it is taken care gracefully. Without this, kernel would throw + * an warning if spin_lock_bh is used while IRQ is disabled + */ + qdf_spinlock_t rm_lock; + struct uc_rm_work_struct uc_rm_work; + struct uc_op_work_struct uc_op_work[HDD_IPA_UC_OPCODE_MAX]; + qdf_wake_lock_t wake_lock; + struct delayed_work wake_lock_work; + bool wake_lock_released; + + enum ipa_client_type prod_client; + + atomic_t tx_ref_cnt; + qdf_nbuf_queue_t pm_queue_head; + struct work_struct pm_work; + qdf_spinlock_t pm_lock; + bool suspended; + + qdf_spinlock_t q_lock; + + struct list_head pend_desc_head; + struct hdd_ipa_tx_desc *tx_desc_list; + struct list_head free_tx_desc_head; + + hdd_context_t *hdd_ctx; + + struct dentry *debugfs_dir; + struct hdd_ipa_stats stats; + + struct notifier_block ipv4_notifier; + uint32_t curr_prod_bw; + uint32_t curr_cons_bw; + + uint8_t activated_fw_pipe; + uint8_t sap_num_connected_sta; + uint8_t sta_connected; + uint32_t tx_pipe_handle; + uint32_t rx_pipe_handle; + bool resource_loading; + bool resource_unloading; + bool pending_cons_req; + struct ipa_uc_stas_map assoc_stas_map[WLAN_MAX_STA_COUNT]; + qdf_list_t pending_event; + qdf_mutex_t event_lock; + bool ipa_pipes_down; + uint32_t ipa_tx_packets_diff; + uint32_t ipa_rx_packets_diff; + uint32_t ipa_p_tx_packets; + uint32_t ipa_p_rx_packets; + uint32_t stat_req_reason; + uint64_t ipa_tx_forward; + uint64_t ipa_rx_discard; + uint64_t ipa_rx_net_send_count; + uint64_t ipa_rx_internel_drop_count; + uint64_t ipa_rx_destructor_count; + qdf_mc_timer_t rt_debug_timer; + struct uc_rt_debug_info rt_bug_buffer[HDD_IPA_UC_RT_DEBUG_BUF_COUNT]; + unsigned int rt_buf_fill_index; + struct ipa_wdi_in_params cons_pipe_in; + struct ipa_wdi_in_params prod_pipe_in; + bool uc_loaded; + qdf_mc_timer_t rt_debug_fill_timer; + qdf_mutex_t rt_debug_lock; + qdf_mutex_t ipa_lock; + struct ol_txrx_ipa_resources ipa_resource; + /* IPA UC doorbell registers paddr */ + qdf_dma_addr_t tx_comp_doorbell_paddr; + qdf_dma_addr_t rx_ready_doorbell_paddr; + uint8_t vdev_to_iface[CSR_ROAM_SESSION_MAX]; + bool vdev_offload_enabled[CSR_ROAM_SESSION_MAX]; +#ifdef FEATURE_METERING + struct ipa_uc_sharing_stats ipa_sharing_stats; + struct ipa_uc_quota_rsp ipa_quota_rsp; + struct ipa_uc_quota_ind ipa_quota_ind; + struct completion ipa_uc_sharing_stats_comp; + struct completion ipa_uc_set_quota_comp; +#endif + struct completion ipa_resource_comp; +}; + +#define HDD_IPA_WLAN_FRAG_HEADER sizeof(struct frag_header) +#define HDD_IPA_WLAN_IPA_HEADER sizeof(struct ipa_header) +#define HDD_IPA_WLAN_CLD_HDR_LEN sizeof(struct hdd_ipa_cld_hdr) +#define HDD_IPA_UC_WLAN_CLD_HDR_LEN 0 +#define HDD_IPA_WLAN_TX_HDR_LEN sizeof(struct hdd_ipa_tx_hdr) +#define HDD_IPA_UC_WLAN_TX_HDR_LEN sizeof(struct hdd_ipa_uc_tx_hdr) +#define HDD_IPA_WLAN_RX_HDR_LEN sizeof(struct hdd_ipa_rx_hdr) +#define HDD_IPA_UC_WLAN_RX_HDR_LEN sizeof(struct hdd_ipa_uc_rx_hdr) +#define HDD_IPA_UC_WLAN_HDR_DES_MAC_OFFSET \ + (HDD_IPA_WLAN_FRAG_HEADER + HDD_IPA_WLAN_IPA_HEADER) + +#define HDD_IPA_GET_IFACE_ID(_data) \ + (((struct hdd_ipa_cld_hdr *) (_data))->iface_id) + +#define HDD_IPA_LOG(LVL, fmt, args ...) \ + QDF_TRACE(QDF_MODULE_ID_HDD, LVL, \ + "%s:%d: "fmt, __func__, __LINE__, ## args) + +#define HDD_IPA_DP_LOG(LVL, fmt, args...) \ + QDF_TRACE(QDF_MODULE_ID_HDD_DATA, LVL, \ + "%s:%d: "fmt, __func__, __LINE__, ## args) + +#define HDD_IPA_DBG_DUMP(_lvl, _prefix, _buf, _len) \ + do { \ + QDF_TRACE(QDF_MODULE_ID_HDD_DATA, _lvl, "%s:", _prefix); \ + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_HDD_DATA, _lvl, _buf, _len); \ + } while (0) + +#define HDD_IPA_IS_CONFIG_ENABLED(_hdd_ctx, _mask) \ + (((_hdd_ctx)->config->IpaConfig & (_mask)) == (_mask)) + +#define HDD_IPA_INCREASE_INTERNAL_DROP_COUNT(hdd_ipa) \ + do { \ + hdd_ipa->ipa_rx_internel_drop_count++; \ + } while (0) +#define HDD_IPA_INCREASE_NET_SEND_COUNT(hdd_ipa) \ + do { \ + hdd_ipa->ipa_rx_net_send_count++; \ + } while (0) +#define HDD_BW_GET_DIFF(_x, _y) (unsigned long)((ULONG_MAX - (_y)) + (_x) + 1) + +#if defined (QCA_WIFI_3_0) && defined (CONFIG_IPA3) +#define HDD_IPA_WDI2_SET(pipe_in, ipa_ctxt) \ +do { \ + pipe_in.u.ul.rdy_ring_rp_va = \ + ipa_ctxt->ipa_resource.rx_proc_done_idx_vaddr; \ + pipe_in.u.ul.rdy_comp_ring_base_pa = \ + ipa_ctxt->ipa_resource.rx2_rdy_ring_base_paddr;\ + pipe_in.u.ul.rdy_comp_ring_size = \ + ipa_ctxt->ipa_resource.rx2_rdy_ring_size; \ + pipe_in.u.ul.rdy_comp_ring_wp_pa = \ + ipa_ctxt->ipa_resource.rx2_proc_done_idx_paddr; \ + pipe_in.u.ul.rdy_comp_ring_wp_va = \ + ipa_ctxt->ipa_resource.rx2_proc_done_idx_vaddr; \ +} while (0) + +#define HDD_IPA_CHECK_HW() ipa_uc_reg_rdyCB(NULL) +#else +/* Do nothing */ +#define HDD_IPA_WDI2_SET(pipe_in, ipa_ctxt) +#define HDD_IPA_CHECK_HW() 0 +#endif /* IPA3 */ + +#define HDD_IPA_DBG_DUMP_RX_LEN 32 +#define HDD_IPA_DBG_DUMP_TX_LEN 48 + +static struct hdd_ipa_adapter_2_client { + enum ipa_client_type cons_client; + enum ipa_client_type prod_client; +} hdd_ipa_adapter_2_client[HDD_IPA_MAX_IFACE] = { + { + IPA_CLIENT_WLAN2_CONS, IPA_CLIENT_WLAN1_PROD + }, { + IPA_CLIENT_WLAN3_CONS, IPA_CLIENT_WLAN1_PROD + }, { + IPA_CLIENT_WLAN4_CONS, IPA_CLIENT_WLAN1_PROD + }, +}; + +/* For Tx pipes, use Ethernet-II Header format */ +struct hdd_ipa_uc_tx_hdr ipa_uc_tx_hdr = { + { + 0x0000, + 0x00000000, + 0x00000000 + }, + { + 0x00000000 + }, + { + {0x00, 0x03, 0x7f, 0xaa, 0xbb, 0xcc}, + {0x00, 0x03, 0x7f, 0xdd, 0xee, 0xff}, + 0x0008 + } +}; + +/* For Tx pipes, use 802.3 Header format */ +static struct hdd_ipa_tx_hdr ipa_tx_hdr = { + { + {0xDE, 0xAD, 0xBE, 0xEF, 0xFF, 0xFF}, + {0xDE, 0xAD, 0xBE, 0xEF, 0xFF, 0xFF}, + 0x00 /* length can be zero */ + }, + { + /* LLC SNAP header 8 bytes */ + 0xaa, 0xaa, + {0x03, 0x00, 0x00, 0x00}, + 0x0008 /* type value(2 bytes) ,filled by wlan */ + /* 0x0800 - IPV4, 0x86dd - IPV6 */ + } +}; + +#ifdef FEATURE_METERING +#define IPA_UC_SHARING_STATES_WAIT_TIME 500 +#define IPA_UC_SET_QUOTA_WAIT_TIME 500 +#endif + +#define IPA_RESOURCE_COMP_WAIT_TIME 100 + +static struct hdd_ipa_priv *ghdd_ipa; + +/* Local Function Prototypes */ +static void hdd_ipa_i2w_cb(void *priv, enum ipa_dp_evt_type evt, + unsigned long data); +static void hdd_ipa_w2i_cb(void *priv, enum ipa_dp_evt_type evt, + unsigned long data); +static void hdd_ipa_msg_free_fn(void *buff, uint32_t len, uint32_t type); + +static void hdd_ipa_cleanup_iface(struct hdd_ipa_iface_context *iface_context); +static void hdd_ipa_uc_proc_pending_event (struct hdd_ipa_priv *hdd_ipa); + +#if ((defined(QCA_WIFI_3_0) && defined(CONFIG_IPA3)) || \ + defined(IPA_CLIENT_IS_MHI_CONS)) +/** + * hdd_ipa_uc_get_db_paddr() - Get Doorbell physical address + * @db_paddr: Doorbell physical address should be given bu IPA + * @client: IPA client type + * + * Query doorbell physical address from IPA + * IPA will give physical address for TX COMP and RX READY + * + * Return: None + */ +static void hdd_ipa_uc_get_db_paddr(qdf_dma_addr_t *db_paddr, + enum ipa_client_type client) +{ + struct ipa_wdi_db_params dbpa; + + dbpa.client = client; + ipa_uc_wdi_get_dbpa(&dbpa); + *db_paddr = dbpa.uc_door_bell_pa; + HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "%s PROD DB get dbpa 0x%x", + __func__, (unsigned int)dbpa.uc_door_bell_pa); +} + +/** + * hdd_ipa_uc_loaded_uc_cb() - IPA UC loaded event callback + * @priv_ctxt: hdd ipa local context + * + * Will be called by IPA context. + * It's atomic context, then should be scheduled to kworker thread + * + * Return: None + */ +static void hdd_ipa_uc_loaded_uc_cb(void *priv_ctxt) +{ + struct hdd_ipa_priv *hdd_ipa; + struct op_msg_type *msg; + struct uc_op_work_struct *uc_op_work; + + if (priv_ctxt == NULL) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Invalid IPA context"); + return; + } + + hdd_ipa = (struct hdd_ipa_priv *)priv_ctxt; + msg = (struct op_msg_type *)qdf_mem_malloc(sizeof(*msg)); + if (!msg) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "op_msg allocation fails"); + return; + } + + msg->op_code = HDD_IPA_UC_OPCODE_UC_READY; + + uc_op_work = &hdd_ipa->uc_op_work[msg->op_code]; + + /* When the same uC OPCODE is already pended, just return */ + if (uc_op_work->msg) + return; + + uc_op_work->msg = msg; + schedule_work(&uc_op_work->work); +} + +/** + * hdd_ipa_uc_register_uc_ready() - Register UC ready callback function to IPA + * @hdd_ipa: HDD IPA local context + * + * Register IPA UC ready callback function to IPA kernel driver + * Even IPA UC loaded later than WLAN kernel driver, WLAN kernel driver will + * open WDI pipe after WLAN driver loading finished + * + * Return: 0 Success + * -EPERM Registration fail + */ +static int hdd_ipa_uc_register_uc_ready(struct hdd_ipa_priv *hdd_ipa) +{ + struct ipa_wdi_uc_ready_params uc_ready_param; + + hdd_ipa->uc_loaded = false; + uc_ready_param.priv = (void *)hdd_ipa; + uc_ready_param.notify = hdd_ipa_uc_loaded_uc_cb; + if (ipa_uc_reg_rdyCB(&uc_ready_param)) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, + "UC Ready CB register fail"); + return -EPERM; + } + if (true == uc_ready_param.is_uC_ready) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "UC Ready"); + hdd_ipa->uc_loaded = true; + } + + return 0; +} + +#ifdef QCA_LL_TX_FLOW_CONTROL_V2 +static int hdd_ipa_uc_send_wdi_control_msg(bool ctrl) +{ + return 0; +} +#else +/** + * hdd_ipa_uc_send_wdi_control_msg() - Set WDI control message + * @ctrl: WDI control value + * + * Send WLAN_WDI_ENABLE for ctrl = true and WLAN_WDI_DISABLE otherwise. + * + * Return: 0 on message send to ipa, -1 on failure + */ +static int hdd_ipa_uc_send_wdi_control_msg(bool ctrl) +{ + struct ipa_msg_meta meta; + struct ipa_wlan_msg *ipa_msg; + int ret = 0; + + /* WDI enable message to IPA */ + meta.msg_len = sizeof(*ipa_msg); + ipa_msg = qdf_mem_malloc(meta.msg_len); + if (ipa_msg == NULL) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, + "msg allocation failed"); + return -ENOMEM; + } + + if (ctrl == true) + meta.msg_type = WLAN_WDI_ENABLE; + else + meta.msg_type = WLAN_WDI_DISABLE; + + HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, + "ipa_send_msg(Evt:%d)", meta.msg_type); + ret = ipa_send_msg(&meta, ipa_msg, hdd_ipa_msg_free_fn); + if (ret) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, + "ipa_send_msg(Evt:%d)-fail=%d", + meta.msg_type, ret); + qdf_mem_free(ipa_msg); + } + return 0; +} +#endif /* QCA_LL_TX_FLOW_CONTROL_V2 */ + +#else +static void hdd_ipa_uc_get_db_paddr(qdf_dma_addr_t *db_paddr, + enum ipa_client_type client) +{ + /* Do nothing */ +} + +static int hdd_ipa_uc_register_uc_ready(struct hdd_ipa_priv *hdd_ipa) +{ + hdd_ipa->uc_loaded = true; + return 0; +} + +static int hdd_ipa_uc_send_wdi_control_msg(bool ctrl) +{ + return 0; +} +#endif + +/** + * hdd_ipa_is_enabled() - Is IPA enabled? + * @hdd_ctx: Global HDD context + * + * Return: true if IPA is enabled, false otherwise + */ +bool hdd_ipa_is_enabled(hdd_context_t *hdd_ctx) +{ + return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx, HDD_IPA_ENABLE_MASK); +} + +/** + * hdd_ipa_uc_is_enabled() - Is IPA uC offload enabled? + * @hdd_ctx: Global HDD context + * + * Return: true if IPA uC offload is enabled, false otherwise + */ +bool hdd_ipa_uc_is_enabled(hdd_context_t *hdd_ctx) +{ + return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx, HDD_IPA_UC_ENABLE_MASK); +} + +/** + * hdd_ipa_uc_sta_is_enabled() - Is STA mode IPA uC offload enabled? + * @hdd_ctx: Global HDD context + * + * Return: true if STA mode IPA uC offload is enabled, false otherwise + */ +static inline bool hdd_ipa_uc_sta_is_enabled(hdd_context_t *hdd_ctx) +{ + return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx, HDD_IPA_UC_STA_ENABLE_MASK); +} + +/** + * hdd_ipa_uc_sta_reset_sta_connected() - Reset sta_connected flag + * @hdd_ipa: Global HDD IPA context + * + * Return: None + */ +static inline void hdd_ipa_uc_sta_reset_sta_connected( + struct hdd_ipa_priv *hdd_ipa) +{ + qdf_mutex_acquire(&hdd_ipa->ipa_lock); + hdd_ipa->sta_connected = 0; + qdf_mutex_release(&hdd_ipa->ipa_lock); +} + +/** + * hdd_ipa_is_pre_filter_enabled() - Is IPA pre-filter enabled? + * @hdd_ipa: Global HDD IPA context + * + * Return: true if pre-filter is enabled, otherwise false + */ +static inline bool hdd_ipa_is_pre_filter_enabled(hdd_context_t *hdd_ctx) +{ + return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx, + HDD_IPA_PRE_FILTER_ENABLE_MASK); +} + +/** + * hdd_ipa_is_ipv6_enabled() - Is IPA IPv6 enabled? + * @hdd_ipa: Global HDD IPA context + * + * Return: true if IPv6 is enabled, otherwise false + */ +static inline bool hdd_ipa_is_ipv6_enabled(hdd_context_t *hdd_ctx) +{ + return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx, HDD_IPA_IPV6_ENABLE_MASK); +} + +/** + * hdd_ipa_is_rm_enabled() - Is IPA resource manager enabled? + * @hdd_ipa: Global HDD IPA context + * + * Return: true if resource manager is enabled, otherwise false + */ +static inline bool hdd_ipa_is_rm_enabled(hdd_context_t *hdd_ctx) +{ + return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx, HDD_IPA_RM_ENABLE_MASK); +} + +/** + * hdd_ipa_is_rt_debugging_enabled() - Is IPA real-time debug enabled? + * @hdd_ipa: Global HDD IPA context + * + * Return: true if resource manager is enabled, otherwise false + */ +static inline bool hdd_ipa_is_rt_debugging_enabled(hdd_context_t *hdd_ctx) +{ + return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx, HDD_IPA_REAL_TIME_DEBUGGING); +} + +/** + * hdd_ipa_is_clk_scaling_enabled() - Is IPA clock scaling enabled? + * @hdd_ipa: Global HDD IPA context + * + * Return: true if clock scaling is enabled, otherwise false + */ +static inline bool hdd_ipa_is_clk_scaling_enabled(hdd_context_t *hdd_ctx) +{ + return HDD_IPA_IS_CONFIG_ENABLED(hdd_ctx, + HDD_IPA_CLK_SCALING_ENABLE_MASK | + HDD_IPA_RM_ENABLE_MASK); +} + +/** + * hdd_ipa_uc_rt_debug_host_fill - fill rt debug buffer + * @ctext: pointer to hdd context. + * + * If rt debug enabled, periodically called, and fill debug buffer + * + * Return: none + */ +static void hdd_ipa_uc_rt_debug_host_fill(void *ctext) +{ + hdd_context_t *hdd_ctx = (hdd_context_t *)ctext; + struct hdd_ipa_priv *hdd_ipa; + struct uc_rt_debug_info *dump_info = NULL; + + if (wlan_hdd_validate_context(hdd_ctx)) + return; + + if (!hdd_ctx->hdd_ipa || !hdd_ipa_uc_is_enabled(hdd_ctx)) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, + "%s: IPA UC is not enabled", __func__); + return; + } + + hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa; + + qdf_mutex_acquire(&hdd_ipa->rt_debug_lock); + dump_info = &hdd_ipa->rt_bug_buffer[ + hdd_ipa->rt_buf_fill_index % HDD_IPA_UC_RT_DEBUG_BUF_COUNT]; + + dump_info->time = (uint64_t)qdf_mc_timer_get_system_time(); + dump_info->ipa_excep_count = hdd_ipa->stats.num_rx_excep; + dump_info->rx_drop_count = hdd_ipa->ipa_rx_internel_drop_count; + dump_info->net_sent_count = hdd_ipa->ipa_rx_net_send_count; + dump_info->tx_fwd_count = hdd_ipa->ipa_tx_forward; + dump_info->tx_fwd_ok_count = hdd_ipa->stats.num_tx_fwd_ok; + dump_info->rx_discard_count = hdd_ipa->ipa_rx_discard; + dump_info->rx_destructor_call = hdd_ipa->ipa_rx_destructor_count; + hdd_ipa->rt_buf_fill_index++; + qdf_mutex_release(&hdd_ipa->rt_debug_lock); + + qdf_mc_timer_start(&hdd_ipa->rt_debug_fill_timer, + HDD_IPA_UC_RT_DEBUG_FILL_INTERVAL); +} + +/** + * __hdd_ipa_uc_rt_debug_host_dump - dump rt debug buffer + * @hdd_ctx: pointer to hdd context. + * + * If rt debug enabled, dump debug buffer contents based on requirement + * + * Return: none + */ +static void __hdd_ipa_uc_rt_debug_host_dump(hdd_context_t *hdd_ctx) +{ + struct hdd_ipa_priv *hdd_ipa; + unsigned int dump_count; + unsigned int dump_index; + struct uc_rt_debug_info *dump_info = NULL; + + if (wlan_hdd_validate_context(hdd_ctx)) + return; + + hdd_ipa = hdd_ctx->hdd_ipa; + if (!hdd_ipa || !hdd_ipa_uc_is_enabled(hdd_ctx)) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, + "%s: IPA UC is not enabled", __func__); + return; + } + + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, + "========= WLAN-IPA DEBUG BUF DUMP ==========\n"); + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, + " TM : EXEP : DROP : NETS : FWOK : TXFD : DSTR : DSCD\n"); + + qdf_mutex_acquire(&hdd_ipa->rt_debug_lock); + for (dump_count = 0; + dump_count < HDD_IPA_UC_RT_DEBUG_BUF_COUNT; + dump_count++) { + dump_index = (hdd_ipa->rt_buf_fill_index + dump_count) % + HDD_IPA_UC_RT_DEBUG_BUF_COUNT; + dump_info = &hdd_ipa->rt_bug_buffer[dump_index]; + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, + "%12llu:%10llu:%10llu:%10llu:%10llu:%10llu:%10llu:%10llu\n", + dump_info->time, dump_info->ipa_excep_count, + dump_info->rx_drop_count, dump_info->net_sent_count, + dump_info->tx_fwd_ok_count, dump_info->tx_fwd_count, + dump_info->rx_destructor_call, + dump_info->rx_discard_count); + } + qdf_mutex_release(&hdd_ipa->rt_debug_lock); + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, + "======= WLAN-IPA DEBUG BUF DUMP END ========\n"); +} + +/** + * hdd_ipa_uc_rt_debug_host_dump - SSR wrapper for + * __hdd_ipa_uc_rt_debug_host_dump + * @hdd_ctx: pointer to hdd context. + * + * If rt debug enabled, dump debug buffer contents based on requirement + * + * Return: none + */ +void hdd_ipa_uc_rt_debug_host_dump(hdd_context_t *hdd_ctx) +{ + cds_ssr_protect(__func__); + __hdd_ipa_uc_rt_debug_host_dump(hdd_ctx); + cds_ssr_unprotect(__func__); +} + +/** + * hdd_ipa_uc_rt_debug_handler - periodic memory health monitor handler + * @ctext: pointer to hdd context. + * + * periodically called by timer expire + * will try to alloc dummy memory and detect out of memory condition + * if out of memory detected, dump wlan-ipa stats + * + * Return: none + */ +static void hdd_ipa_uc_rt_debug_handler(void *ctext) +{ + hdd_context_t *hdd_ctx = (hdd_context_t *)ctext; + struct hdd_ipa_priv *hdd_ipa; + void *dummy_ptr = NULL; + + if (wlan_hdd_validate_context(hdd_ctx)) + return; + + hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa; + + if (!hdd_ipa_is_rt_debugging_enabled(hdd_ctx)) { + hdd_notice("IPA RT debug is not enabled"); + return; + } + + /* Allocate dummy buffer periodically and free immediately. this will + * proactively detect OOM and if allocation fails dump ipa stats + */ + dummy_ptr = kmalloc(HDD_IPA_UC_DEBUG_DUMMY_MEM_SIZE, + GFP_KERNEL | GFP_ATOMIC); + if (!dummy_ptr) { + hdd_alert("Dummy alloc fail"); + hdd_ipa_uc_rt_debug_host_dump(hdd_ctx); + hdd_ipa_uc_stat_request( + hdd_get_adapter(hdd_ctx, QDF_SAP_MODE), + HDD_IPA_UC_STAT_REASON_DEBUG); + } else { + kfree(dummy_ptr); + } + + qdf_mc_timer_start(&hdd_ipa->rt_debug_timer, + HDD_IPA_UC_RT_DEBUG_PERIOD); +} + +/** + * hdd_ipa_uc_rt_debug_destructor() - called by data packet free + * @skb: packet pinter + * + * when free data packet, will be invoked by wlan client and will increase + * free counter + * + * Return: none + */ +static void hdd_ipa_uc_rt_debug_destructor(struct sk_buff *skb) +{ + if (!ghdd_ipa) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, + "%s: invalid hdd context", __func__); + return; + } + + ghdd_ipa->ipa_rx_destructor_count++; +} + +/** + * hdd_ipa_uc_rt_debug_deinit() - remove resources to handle rt debugging + * @hdd_ctx: hdd main context + * + * free all rt debugging resources + * + * Return: none + */ +static void hdd_ipa_uc_rt_debug_deinit(hdd_context_t *hdd_ctx) +{ + struct hdd_ipa_priv *hdd_ipa; + + if (wlan_hdd_validate_context(hdd_ctx)) + return; + + hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa; + + qdf_mutex_destroy(&hdd_ipa->rt_debug_lock); + + if (!hdd_ipa_is_rt_debugging_enabled(hdd_ctx)) { + hdd_notice("IPA RT debug is not enabled"); + return; + } + + if (QDF_TIMER_STATE_STOPPED != + qdf_mc_timer_get_current_state(&hdd_ipa->rt_debug_fill_timer)) { + qdf_mc_timer_stop(&hdd_ipa->rt_debug_fill_timer); + } + qdf_mc_timer_destroy(&hdd_ipa->rt_debug_fill_timer); + + if (QDF_TIMER_STATE_STOPPED != + qdf_mc_timer_get_current_state(&hdd_ipa->rt_debug_timer)) { + qdf_mc_timer_stop(&hdd_ipa->rt_debug_timer); + } + qdf_mc_timer_destroy(&hdd_ipa->rt_debug_timer); +} + +/** + * hdd_ipa_uc_rt_debug_init() - intialize resources to handle rt debugging + * @hdd_ctx: hdd main context + * + * alloc and initialize all rt debugging resources + * + * Return: none + */ +static void hdd_ipa_uc_rt_debug_init(hdd_context_t *hdd_ctx) +{ + struct hdd_ipa_priv *hdd_ipa; + + if (wlan_hdd_validate_context(hdd_ctx)) + return; + + hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa; + + qdf_mutex_create(&hdd_ipa->rt_debug_lock); + hdd_ipa->rt_buf_fill_index = 0; + qdf_mem_zero(hdd_ipa->rt_bug_buffer, + sizeof(struct uc_rt_debug_info) * + HDD_IPA_UC_RT_DEBUG_BUF_COUNT); + hdd_ipa->ipa_tx_forward = 0; + hdd_ipa->ipa_rx_discard = 0; + hdd_ipa->ipa_rx_net_send_count = 0; + hdd_ipa->ipa_rx_internel_drop_count = 0; + hdd_ipa->ipa_rx_destructor_count = 0; + + /* Reatime debug enable on feature enable */ + if (!hdd_ipa_is_rt_debugging_enabled(hdd_ctx)) { + hdd_notice("IPA RT debug is not enabled"); + return; + } + + qdf_mc_timer_init(&hdd_ipa->rt_debug_fill_timer, QDF_TIMER_TYPE_SW, + hdd_ipa_uc_rt_debug_host_fill, (void *)hdd_ctx); + qdf_mc_timer_start(&hdd_ipa->rt_debug_fill_timer, + HDD_IPA_UC_RT_DEBUG_FILL_INTERVAL); + + qdf_mc_timer_init(&hdd_ipa->rt_debug_timer, QDF_TIMER_TYPE_SW, + hdd_ipa_uc_rt_debug_handler, (void *)hdd_ctx); + qdf_mc_timer_start(&hdd_ipa->rt_debug_timer, + HDD_IPA_UC_RT_DEBUG_PERIOD); + +} + +/** + * hdd_ipa_dump_hdd_ipa() - dump entries in HDD IPA struct + * @hdd_ipa: HDD IPA struct + * + * Dump entries in struct hdd_ipa + * + * Return: none + */ +static void hdd_ipa_dump_hdd_ipa(struct hdd_ipa_priv *hdd_ipa) +{ + int i; + + /* HDD IPA */ + hdd_err("==== HDD IPA ====\n" + "num_iface: %d\n" + "rm_state: %d\n" + "rm_lock: %p\n" + "uc_rm_work: %p\n" + "uc_op_work: %p\n" + "wake_lock: %p\n" + "wake_lock_work: %p\n" + "wake_lock_released: %d\n" + "prod_client: %d\n" + "tx_ref_cnt: %d\n" + "pm_queue_head----\n" + "\thead: %p\n" + "\ttail: %p\n" + "\tqlen: %d\n" + "pm_work: %p\n" + "pm_lock: %p\n" + "suspended: %d\n", + hdd_ipa->num_iface, + hdd_ipa->rm_state, + &hdd_ipa->rm_lock, + &hdd_ipa->uc_rm_work, + &hdd_ipa->uc_op_work, + &hdd_ipa->wake_lock, + &hdd_ipa->wake_lock_work, + hdd_ipa->wake_lock_released, + hdd_ipa->prod_client, + hdd_ipa->tx_ref_cnt.counter, + hdd_ipa->pm_queue_head.head, + hdd_ipa->pm_queue_head.tail, + hdd_ipa->pm_queue_head.qlen, + &hdd_ipa->pm_work, + &hdd_ipa->pm_lock, + hdd_ipa->suspended); + hdd_err("\nq_lock: %p\n" + "pend_desc_head----\n" + "\tnext: %p\n" + "\tprev: %p\n" + "hdd_ctx: %p\n" + "debugfs_dir: %p\n" + "stats: %p\n" + "ipv4_notifier: %p\n" + "curr_prod_bw: %d\n" + "curr_cons_bw: %d\n" + "activated_fw_pipe: %d\n" + "sap_num_connected_sta: %d\n" + "sta_connected: %d\n", + &hdd_ipa->q_lock, + hdd_ipa->pend_desc_head.next, + hdd_ipa->pend_desc_head.prev, + hdd_ipa->hdd_ctx, + hdd_ipa->debugfs_dir, + &hdd_ipa->stats, + &hdd_ipa->ipv4_notifier, + hdd_ipa->curr_prod_bw, + hdd_ipa->curr_cons_bw, + hdd_ipa->activated_fw_pipe, + hdd_ipa->sap_num_connected_sta, + (unsigned int)hdd_ipa->sta_connected + ); + hdd_err("\ntx_pipe_handle: 0x%x\n" + "rx_pipe_handle: 0x%x\n" + "resource_loading: %d\n" + "resource_unloading: %d\n" + "pending_cons_req: %d\n" + "pending_event----\n" + "\tanchor.next: %p\n" + "\tanchor.prev: %p\n" + "\tcount: %d\n" + "\tmax_size: %d\n" + "event_lock: %p\n" + "ipa_tx_packets_diff: %d\n" + "ipa_rx_packets_diff: %d\n" + "ipa_p_tx_packets: %d\n" + "ipa_p_rx_packets: %d\n" + "stat_req_reason: %d\n", + hdd_ipa->tx_pipe_handle, + hdd_ipa->rx_pipe_handle, + hdd_ipa->resource_loading, + hdd_ipa->resource_unloading, + hdd_ipa->pending_cons_req, + hdd_ipa->pending_event.anchor.next, + hdd_ipa->pending_event.anchor.prev, + hdd_ipa->pending_event.count, + hdd_ipa->pending_event.max_size, + &hdd_ipa->event_lock, + hdd_ipa->ipa_tx_packets_diff, + hdd_ipa->ipa_rx_packets_diff, + hdd_ipa->ipa_p_tx_packets, + hdd_ipa->ipa_p_rx_packets, + hdd_ipa->stat_req_reason); + + hdd_err("assoc_stas_map([id]is_reserved/sta_id): "); + for (i = 0; i < WLAN_MAX_STA_COUNT; i++) { + hdd_err(" [%d]%d/%d", i, + hdd_ipa->assoc_stas_map[i].is_reserved, + hdd_ipa->assoc_stas_map[i].sta_id); + } +} + +/** + * hdd_ipa_dump_sys_pipe() - dump HDD IPA SYS Pipe struct + * @hdd_ipa: HDD IPA struct + * + * Dump entire struct hdd_ipa_sys_pipe + * + * Return: none + */ +static void hdd_ipa_dump_sys_pipe(struct hdd_ipa_priv *hdd_ipa) +{ + int i; + + /* IPA SYS Pipes */ + hdd_err("==== IPA SYS Pipes ====\n"); + + for (i = 0; i < HDD_IPA_MAX_SYSBAM_PIPE; i++) { + struct hdd_ipa_sys_pipe *sys_pipe; + struct ipa_sys_connect_params *ipa_sys_params; + + sys_pipe = &hdd_ipa->sys_pipe[i]; + ipa_sys_params = &sys_pipe->ipa_sys_params; + + hdd_err("sys_pipe[%d]----\n" + "\tconn_hdl: 0x%x\n" + "\tconn_hdl_valid: %d\n" + "\tnat_en: %d\n" + "\thdr_len %d\n" + "\thdr_additional_const_len: %d\n" + "\thdr_ofst_pkt_size_valid: %d\n" + "\thdr_ofst_pkt_size: %d\n" + "\thdr_little_endian: %d\n" + "\tmode: %d\n" + "\tclient: %d\n" + "\tdesc_fifo_sz: %d\n" + "\tpriv: %p\n" + "\tnotify: %p\n" + "\tskip_ep_cfg: %d\n" + "\tkeep_ipa_awake: %d\n", + i, + sys_pipe->conn_hdl, + sys_pipe->conn_hdl_valid, + ipa_sys_params->ipa_ep_cfg.nat.nat_en, + ipa_sys_params->ipa_ep_cfg.hdr.hdr_len, + ipa_sys_params->ipa_ep_cfg.hdr.hdr_additional_const_len, + ipa_sys_params->ipa_ep_cfg.hdr.hdr_ofst_pkt_size_valid, + ipa_sys_params->ipa_ep_cfg.hdr.hdr_ofst_pkt_size, + ipa_sys_params->ipa_ep_cfg.hdr_ext.hdr_little_endian, + ipa_sys_params->ipa_ep_cfg.mode.mode, + ipa_sys_params->client, + ipa_sys_params->desc_fifo_sz, + ipa_sys_params->priv, + ipa_sys_params->notify, + ipa_sys_params->skip_ep_cfg, + ipa_sys_params->keep_ipa_awake); + } +} + +/** + * hdd_ipa_dump_iface_context() - dump HDD IPA Interface Context struct + * @hdd_ipa: HDD IPA struct + * + * Dump entire struct hdd_ipa_iface_context + * + * Return: none + */ +static void hdd_ipa_dump_iface_context(struct hdd_ipa_priv *hdd_ipa) +{ + int i; + + /* IPA Interface Contexts */ + hdd_err("==== IPA Interface Contexts ====\n"); + + for (i = 0; i < HDD_IPA_MAX_IFACE; i++) { + struct hdd_ipa_iface_context *iface_context; + + iface_context = &hdd_ipa->iface_context[i]; + + hdd_err("iface_context[%d]----\n" + "\thdd_ipa: %p\n" + "\tadapter: %p\n" + "\ttl_context: %p\n" + "\tcons_client: %d\n" + "\tprod_client: %d\n" + "\tiface_id: %d\n" + "\tsta_id: %d\n" + "\tinterface_lock: %p\n" + "\tifa_address: 0x%x\n", + i, + iface_context->hdd_ipa, + iface_context->adapter, + iface_context->tl_context, + iface_context->cons_client, + iface_context->prod_client, + iface_context->iface_id, + iface_context->sta_id, + &iface_context->interface_lock, + iface_context->ifa_address); + } +} + +/** + * hdd_ipa_dump_info() - dump HDD IPA struct + * @pHddCtx: hdd main context + * + * Dump entire struct hdd_ipa + * + * Return: none + */ +void hdd_ipa_dump_info(hdd_context_t *hdd_ctx) +{ + struct hdd_ipa_priv *hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa; + + hdd_ipa_dump_hdd_ipa(hdd_ipa); + hdd_ipa_dump_sys_pipe(hdd_ipa); + hdd_ipa_dump_iface_context(hdd_ipa); +} + +/** + * __hdd_ipa_uc_stat_query() - Query the IPA stats + * @hdd_ctx: Global HDD context + * @ipa_tx_diff: tx packet count diff from previous tx packet count + * @ipa_rx_diff: rx packet count diff from previous rx packet count + * + * Return: true if IPA is enabled, false otherwise + */ +static void __hdd_ipa_uc_stat_query(hdd_context_t *hdd_ctx, + uint32_t *ipa_tx_diff, uint32_t *ipa_rx_diff) +{ + struct hdd_ipa_priv *hdd_ipa; + + *ipa_tx_diff = 0; + *ipa_rx_diff = 0; + + if (wlan_hdd_validate_context(hdd_ctx)) + return; + + hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa; + + if (!hdd_ipa_is_enabled(hdd_ctx) || + !(hdd_ipa_uc_is_enabled(hdd_ctx))) { + return; + } + + qdf_mutex_acquire(&hdd_ipa->ipa_lock); + if ((HDD_IPA_UC_NUM_WDI_PIPE == hdd_ipa->activated_fw_pipe) && + (false == hdd_ipa->resource_loading)) { + *ipa_tx_diff = hdd_ipa->ipa_tx_packets_diff; + *ipa_rx_diff = hdd_ipa->ipa_rx_packets_diff; + hdd_debug("STAT Query TX DIFF %d, RX DIFF %d", + *ipa_tx_diff, *ipa_rx_diff); + } + qdf_mutex_release(&hdd_ipa->ipa_lock); + return; +} + +/** + * hdd_ipa_uc_stat_query() - SSR wrapper for __hdd_ipa_uc_stat_query + * @hdd_ctx: Global HDD context + * @ipa_tx_diff: tx packet count diff from previous tx packet count + * @ipa_rx_diff: rx packet count diff from previous rx packet count + * + * Return: true if IPA is enabled, false otherwise + */ +void hdd_ipa_uc_stat_query(hdd_context_t *hdd_ctx, + uint32_t *ipa_tx_diff, uint32_t *ipa_rx_diff) +{ + cds_ssr_protect(__func__); + __hdd_ipa_uc_stat_query(hdd_ctx, ipa_tx_diff, ipa_rx_diff); + cds_ssr_unprotect(__func__); +} + +/** + * __hdd_ipa_uc_stat_request() - Get IPA stats from IPA. + * @adapter: network adapter + * @reason: STAT REQ Reason + * + * Return: None + */ +static void __hdd_ipa_uc_stat_request(hdd_adapter_t *adapter, uint8_t reason) +{ + hdd_context_t *hdd_ctx; + struct hdd_ipa_priv *hdd_ipa; + + if (!adapter) + return; + + hdd_ctx = (hdd_context_t *)adapter->pHddCtx; + + if (wlan_hdd_validate_context(hdd_ctx)) + return; + + hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa; + if (!hdd_ipa_is_enabled(hdd_ctx) || + !(hdd_ipa_uc_is_enabled(hdd_ctx))) { + return; + } + + hdd_debug("STAT REQ Reason %d", reason); + qdf_mutex_acquire(&hdd_ipa->ipa_lock); + if ((HDD_IPA_UC_NUM_WDI_PIPE == hdd_ipa->activated_fw_pipe) && + (false == hdd_ipa->resource_loading)) { + hdd_ipa->stat_req_reason = reason; + qdf_mutex_release(&hdd_ipa->ipa_lock); + sme_ipa_uc_stat_request(WLAN_HDD_GET_HAL_CTX(adapter), + adapter->sessionId, + WMA_VDEV_TXRX_GET_IPA_UC_FW_STATS_CMDID, + 0, VDEV_CMD); + } else { + qdf_mutex_release(&hdd_ipa->ipa_lock); + } +} + +/** + * hdd_ipa_uc_stat_request() - SSR wrapper for __hdd_ipa_uc_stat_request + * @adapter: network adapter + * @reason: STAT REQ Reason + * + * Return: None + */ +void hdd_ipa_uc_stat_request(hdd_adapter_t *adapter, uint8_t reason) +{ + cds_ssr_protect(__func__); + __hdd_ipa_uc_stat_request(adapter, reason); + cds_ssr_unprotect(__func__); +} + +#ifdef FEATURE_METERING +/** + * hdd_ipa_uc_sharing_stats_request() - Get IPA stats from IPA. + * @adapter: network adapter + * @reset_stats: reset stat countis after response + * + * Return: None + */ +void hdd_ipa_uc_sharing_stats_request(hdd_adapter_t *adapter, + uint8_t reset_stats) +{ + hdd_context_t *pHddCtx; + struct hdd_ipa_priv *hdd_ipa; + + if (!adapter) + return; + + pHddCtx = adapter->pHddCtx; + hdd_ipa = pHddCtx->hdd_ipa; + if (!hdd_ipa_is_enabled(pHddCtx) || + !(hdd_ipa_uc_is_enabled(pHddCtx))) { + return; + } + + HDD_IPA_LOG(LOG1, "SHARING_STATS: reset_stats=%d", reset_stats); + qdf_mutex_acquire(&hdd_ipa->ipa_lock); + if (false == hdd_ipa->resource_loading) { + qdf_mutex_release(&hdd_ipa->ipa_lock); + wma_cli_set_command( + (int)adapter->sessionId, + (int)WMA_VDEV_TXRX_GET_IPA_UC_SHARING_STATS_CMDID, + reset_stats, VDEV_CMD); + } else { + qdf_mutex_release(&hdd_ipa->ipa_lock); + } +} + +/** + * hdd_ipa_uc_set_quota() - Set quota limit bytes from IPA. + * @adapter: network adapter + * @set_quota: when 1, FW starts quota monitoring + * @quota_bytes: quota limit in bytes + * + * Return: None + */ +void hdd_ipa_uc_set_quota(hdd_adapter_t *adapter, uint8_t set_quota, + uint64_t quota_bytes) +{ + hdd_context_t *pHddCtx; + struct hdd_ipa_priv *hdd_ipa; + + if (!adapter) + return; + + pHddCtx = adapter->pHddCtx; + hdd_ipa = pHddCtx->hdd_ipa; + if (!hdd_ipa_is_enabled(pHddCtx) || + !(hdd_ipa_uc_is_enabled(pHddCtx))) { + return; + } + + HDD_IPA_LOG(LOG1, "SET_QUOTA: set_quota=%d, quota_bytes=%llu", + set_quota, quota_bytes); + + qdf_mutex_acquire(&hdd_ipa->ipa_lock); + if (false == hdd_ipa->resource_loading) { + qdf_mutex_release(&hdd_ipa->ipa_lock); + wma_cli_set2_command( + (int)adapter->sessionId, + (int)WMA_VDEV_TXRX_SET_IPA_UC_QUOTA_CMDID, + (set_quota ? quota_bytes&0xffffffff : 0), + (set_quota ? quota_bytes>>32 : 0), + VDEV_CMD); + } else { + qdf_mutex_release(&hdd_ipa->ipa_lock); + } +} +#endif + +/** + * hdd_ipa_uc_find_add_assoc_sta() - Find associated station + * @hdd_ipa: Global HDD IPA context + * @sta_add: Should station be added + * @sta_id: ID of the station being queried + * + * Return: true if the station was found + */ +static bool hdd_ipa_uc_find_add_assoc_sta(struct hdd_ipa_priv *hdd_ipa, + bool sta_add, uint8_t sta_id) +{ + bool sta_found = false; + uint8_t idx; + for (idx = 0; idx < WLAN_MAX_STA_COUNT; idx++) { + if ((hdd_ipa->assoc_stas_map[idx].is_reserved) && + (hdd_ipa->assoc_stas_map[idx].sta_id == sta_id)) { + sta_found = true; + break; + } + } + if (sta_add && sta_found) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, + "%s: STA ID %d already exist, cannot add", + __func__, sta_id); + return sta_found; + } + if (sta_add) { + for (idx = 0; idx < WLAN_MAX_STA_COUNT; idx++) { + if (!hdd_ipa->assoc_stas_map[idx].is_reserved) { + hdd_ipa->assoc_stas_map[idx].is_reserved = true; + hdd_ipa->assoc_stas_map[idx].sta_id = sta_id; + return sta_found; + } + } + } + if (!sta_add && !sta_found) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, + "%s: STA ID %d does not exist, cannot delete", + __func__, sta_id); + return sta_found; + } + if (!sta_add) { + for (idx = 0; idx < WLAN_MAX_STA_COUNT; idx++) { + if ((hdd_ipa->assoc_stas_map[idx].is_reserved) && + (hdd_ipa->assoc_stas_map[idx].sta_id == sta_id)) { + hdd_ipa->assoc_stas_map[idx].is_reserved = + false; + hdd_ipa->assoc_stas_map[idx].sta_id = 0xFF; + return sta_found; + } + } + } + return sta_found; +} + +/** + * hdd_ipa_uc_enable_pipes() - Enable IPA uC pipes + * @hdd_ipa: Global HDD IPA context + * + * Return: 0 on success, negative errno if error + */ +static int hdd_ipa_uc_enable_pipes(struct hdd_ipa_priv *hdd_ipa) +{ + int result; + p_cds_contextType cds_ctx = hdd_ipa->hdd_ctx->pcds_context; + + /* ACTIVATE TX PIPE */ + HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, + "%s: Enable TX PIPE(tx_pipe_handle=%d)", + __func__, hdd_ipa->tx_pipe_handle); + result = ipa_enable_wdi_pipe(hdd_ipa->tx_pipe_handle); + if (result) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, + "%s: Enable TX PIPE fail, code %d", + __func__, result); + return result; + } + result = ipa_resume_wdi_pipe(hdd_ipa->tx_pipe_handle); + if (result) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, + "%s: Resume TX PIPE fail, code %d", + __func__, result); + return result; + } + ol_txrx_ipa_uc_set_active(cds_ctx->pdev_txrx_ctx, true, true); + + /* ACTIVATE RX PIPE */ + HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, + "%s: Enable RX PIPE(rx_pipe_handle=%d)", + __func__, hdd_ipa->rx_pipe_handle); + result = ipa_enable_wdi_pipe(hdd_ipa->rx_pipe_handle); + if (result) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, + "%s: Enable RX PIPE fail, code %d", + __func__, result); + return result; + } + result = ipa_resume_wdi_pipe(hdd_ipa->rx_pipe_handle); + if (result) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, + "%s: Resume RX PIPE fail, code %d", + __func__, result); + return result; + } + INIT_COMPLETION(hdd_ipa->ipa_resource_comp); + ol_txrx_ipa_uc_set_active(cds_ctx->pdev_txrx_ctx, true, false); + hdd_ipa->ipa_pipes_down = false; + return 0; +} + +/** + * hdd_ipa_uc_disable_pipes() - Disable IPA uC pipes + * @hdd_ipa: Global HDD IPA context + * + * Return: 0 on success, negative errno if error + */ +static int hdd_ipa_uc_disable_pipes(struct hdd_ipa_priv *hdd_ipa) +{ + int result; + + hdd_ipa->ipa_pipes_down = true; + + HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "%s: Disable RX PIPE", __func__); + result = ipa_suspend_wdi_pipe(hdd_ipa->rx_pipe_handle); + if (result) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, + "%s: Suspend RX PIPE fail, code %d", + __func__, result); + return result; + } + result = ipa_disable_wdi_pipe(hdd_ipa->rx_pipe_handle); + if (result) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, + "%s: Disable RX PIPE fail, code %d", + __func__, result); + return result; + } + + HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "%s: Disable TX PIPE", __func__); + result = ipa_suspend_wdi_pipe(hdd_ipa->tx_pipe_handle); + if (result) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, + "%s: Suspend TX PIPE fail, code %d", + __func__, result); + return result; + } + result = ipa_disable_wdi_pipe(hdd_ipa->tx_pipe_handle); + if (result) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, + "%s: Disable TX PIPE fail, code %d", + __func__, result); + return result; + } + + return 0; +} + +/** + * hdd_ipa_uc_handle_first_con() - Handle first uC IPA connection + * @hdd_ipa: Global HDD IPA context + * + * Return: 0 on success, negative errno if error + */ +static int hdd_ipa_uc_handle_first_con(struct hdd_ipa_priv *hdd_ipa) +{ + hdd_ipa->activated_fw_pipe = 0; + hdd_ipa->resource_loading = true; + + /* If RM feature enabled + * Request PROD Resource first + * PROD resource may return sync or async manners */ + if (hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx)) { + if (!ipa_rm_request_resource(IPA_RM_RESOURCE_WLAN_PROD)) { + /* RM PROD request sync return + * enable pipe immediately + */ + if (!hdd_ipa->ipa_pipes_down) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, + "%s: IPA WDI Pipe already activated", + __func__); + return 0; + } + + if (hdd_ipa_uc_enable_pipes(hdd_ipa)) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, + "%s: IPA WDI Pipe activation failed", + __func__); + hdd_ipa->resource_loading = false; + return -EBUSY; + } + } else { + HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, + "%s: IPA WDI Pipe activation deferred", + __func__); + } + } else { + /* RM Disabled + * Just enabled all the PIPEs + */ + if (hdd_ipa_uc_enable_pipes(hdd_ipa)) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, + "%s: IPA WDI Pipe activation failed", + __func__); + hdd_ipa->resource_loading = false; + return -EBUSY; + } + hdd_ipa->resource_loading = false; + } + + HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, + "%s: IPA WDI Pipes activated successfully", __func__); + return 0; +} + +/** + * hdd_ipa_uc_handle_last_discon() - Handle last uC IPA disconnection + * @hdd_ipa: Global HDD IPA context + * + * Return: None + */ +static void hdd_ipa_uc_handle_last_discon(struct hdd_ipa_priv *hdd_ipa) +{ + p_cds_contextType cds_ctx = hdd_ipa->hdd_ctx->pcds_context; + + if (!cds_ctx || !cds_ctx->pdev_txrx_ctx) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "txrx context is NULL"); + QDF_ASSERT(0); + return; + } + + hdd_ipa->resource_unloading = true; + INIT_COMPLETION(hdd_ipa->ipa_resource_comp); + HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "%s: Disable FW RX PIPE", __func__); + ol_txrx_ipa_uc_set_active(cds_ctx->pdev_txrx_ctx, false, false); + HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "%s: Disable FW TX PIPE", __func__); + ol_txrx_ipa_uc_set_active(cds_ctx->pdev_txrx_ctx, false, true); +} + +/** + * hdd_ipa_uc_rm_notify_handler() - IPA uC resource notification handler + * @context: User context registered with TL (the IPA Global context is + * registered + * @rxpkt: Packet containing the notification + * @staid: ID of the station associated with the packet + * + * Return: None + */ +static void +hdd_ipa_uc_rm_notify_handler(void *context, enum ipa_rm_event event) +{ + struct hdd_ipa_priv *hdd_ipa = context; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + /* + * When SSR is going on or driver is unloading, just return. + */ + status = wlan_hdd_validate_context(hdd_ipa->hdd_ctx); + if (status) + return; + + if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx)) + return; + + HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "%s, event code %d", + __func__, event); + + switch (event) { + case IPA_RM_RESOURCE_GRANTED: + /* Differed RM Granted */ + hdd_ipa_uc_enable_pipes(hdd_ipa); + qdf_mutex_acquire(&hdd_ipa->ipa_lock); + if ((false == hdd_ipa->resource_unloading) && + (!hdd_ipa->activated_fw_pipe)) { + hdd_ipa_uc_enable_pipes(hdd_ipa); + } + qdf_mutex_release(&hdd_ipa->ipa_lock); + break; + + case IPA_RM_RESOURCE_RELEASED: + /* Differed RM Released */ + hdd_ipa->resource_unloading = false; + break; + + default: + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, + "%s, invalid event code %d", __func__, event); + break; + } +} + +/** + * hdd_ipa_uc_rm_notify_defer() - Defer IPA uC notification + * @hdd_ipa: Global HDD IPA context + * @event: IPA resource manager event to be deferred + * + * This function is called when a resource manager event is received + * from firmware in interrupt context. This function will defer the + * handling to the OL RX thread + * + * Return: None + */ +static void hdd_ipa_uc_rm_notify_defer(struct work_struct *work) +{ + enum ipa_rm_event event; + struct uc_rm_work_struct *uc_rm_work = container_of(work, + struct uc_rm_work_struct, work); + struct hdd_ipa_priv *hdd_ipa = container_of(uc_rm_work, + struct hdd_ipa_priv, uc_rm_work); + + cds_ssr_protect(__func__); + event = uc_rm_work->event; + HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO_HIGH, + "%s, posted event %d", __func__, event); + + hdd_ipa_uc_rm_notify_handler(hdd_ipa, event); + cds_ssr_unprotect(__func__); + + return; +} + +/** + * hdd_ipa_uc_op_metering() - IPA uC operation for stats and quota limit + * @hdd_ctx: Global HDD context + * @op_msg: operation message received from firmware + * + * Return: QDF_STATUS enumeration + */ +#ifdef FEATURE_METERING +static QDF_STATUS hdd_ipa_uc_op_metering(hdd_context_t *hdd_ctx, + struct op_msg_type *op_msg) +{ + struct op_msg_type *msg = op_msg; + struct ipa_uc_sharing_stats *uc_sharing_stats; + struct ipa_uc_quota_rsp *uc_quota_rsp; + struct ipa_uc_quota_ind *uc_quota_ind; + struct hdd_ipa_priv *hdd_ipa; + hdd_adapter_t *adapter; + + hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa; + + if (HDD_IPA_UC_OPCODE_SHARING_STATS == msg->op_code) { + /* fill-up ipa_uc_sharing_stats structure from FW */ + uc_sharing_stats = (struct ipa_uc_sharing_stats *) + ((uint8_t *)op_msg + sizeof(struct op_msg_type)); + + memcpy(&(hdd_ipa->ipa_sharing_stats), uc_sharing_stats, + sizeof(struct ipa_uc_sharing_stats)); + + complete(&hdd_ipa->ipa_uc_sharing_stats_comp); + + HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG, + "%s: %llu,%llu,%llu,%llu,%llu,%llu,%llu,%llu", + "HDD_IPA_UC_OPCODE_SHARING_STATS", + hdd_ipa->ipa_sharing_stats.ipv4_rx_packets, + hdd_ipa->ipa_sharing_stats.ipv4_rx_bytes, + hdd_ipa->ipa_sharing_stats.ipv6_rx_packets, + hdd_ipa->ipa_sharing_stats.ipv6_rx_bytes, + hdd_ipa->ipa_sharing_stats.ipv4_tx_packets, + hdd_ipa->ipa_sharing_stats.ipv4_tx_bytes, + hdd_ipa->ipa_sharing_stats.ipv6_tx_packets, + hdd_ipa->ipa_sharing_stats.ipv6_tx_bytes); + } else if (HDD_IPA_UC_OPCODE_QUOTA_RSP == msg->op_code) { + /* received set quota response */ + uc_quota_rsp = (struct ipa_uc_quota_rsp *) + ((uint8_t *)op_msg + sizeof(struct op_msg_type)); + + memcpy(&(hdd_ipa->ipa_quota_rsp), uc_quota_rsp, + sizeof(struct ipa_uc_quota_rsp)); + + complete(&hdd_ipa->ipa_uc_set_quota_comp); + HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG, + "%s: success=%d, quota_bytes=%llu", + "HDD_IPA_UC_OPCODE_QUOTA_RSP", + hdd_ipa->ipa_quota_rsp.success, + ((uint64_t)(hdd_ipa->ipa_quota_rsp.quota_hi)<<32)| + hdd_ipa->ipa_quota_rsp.quota_lo); + } else if (HDD_IPA_UC_OPCODE_QUOTA_IND == msg->op_code) { + /* hit quota limit */ + uc_quota_ind = (struct ipa_uc_quota_ind *) + ((uint8_t *)op_msg + sizeof(struct op_msg_type)); + + hdd_ipa->ipa_quota_ind.quota_bytes = + uc_quota_ind->quota_bytes; + + /* send quota exceeded indication to IPA */ + HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG, + "OPCODE_QUOTA_IND: quota exceed! (quota_bytes=%llu)", + hdd_ipa->ipa_quota_ind.quota_bytes); + + adapter = hdd_get_adapter(hdd_ipa->hdd_ctx, QDF_STA_MODE); + if (adapter) + ipa_broadcast_wdi_quota_reach_ind( + adapter->dev->ifindex, + uc_quota_ind->quota_bytes); + else + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, + "Failed quota_reach_ind: NULL adapter"); + } else { + return QDF_STATUS_E_INVAL; + } + + return QDF_STATUS_SUCCESS; +} +#else +static QDF_STATUS hdd_ipa_uc_op_metering(hdd_context_t *hdd_ctx, + struct op_msg_type *op_msg) +{ + return QDF_STATUS_E_INVAL; +} +#endif + +/** + * hdd_ipa_uc_loaded_handler() - Process IPA uC loaded indication + * @ipa_ctxt: hdd ipa local context + * + * Will handle IPA UC image loaded indication comes from IPA kernel + * + * Return: None + */ +static void hdd_ipa_uc_loaded_handler(struct hdd_ipa_priv *ipa_ctxt) +{ + struct ipa_wdi_out_params pipe_out; + + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "%s : UC READY", __func__); + if (true == ipa_ctxt->uc_loaded) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO_HIGH, "%s : UC already loaded", + __func__); + return; + } + + ipa_ctxt->uc_loaded = true; + /* Connect pipe */ + ipa_connect_wdi_pipe(&ipa_ctxt->cons_pipe_in, &pipe_out); + ipa_ctxt->tx_pipe_handle = pipe_out.clnt_hdl; + ipa_ctxt->tx_comp_doorbell_paddr = pipe_out.uc_door_bell_pa; + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, + "%s : TX PIPE Handle %d, DBPA 0x%llx", + __func__, ipa_ctxt->tx_pipe_handle, + (unsigned long long) pipe_out.uc_door_bell_pa); + + ipa_connect_wdi_pipe(&ipa_ctxt->prod_pipe_in, &pipe_out); + ipa_ctxt->rx_pipe_handle = pipe_out.clnt_hdl; + ipa_ctxt->rx_ready_doorbell_paddr = pipe_out.uc_door_bell_pa; + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, + "%s : RX PIPE Handle %d, DBPA 0x%llx", + __func__, ipa_ctxt->rx_pipe_handle, + (unsigned long long) pipe_out.uc_door_bell_pa); + + /* If already any STA connected, enable IPA/FW PIPEs */ + if (ipa_ctxt->sap_num_connected_sta) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, + "Client already connected, enable IPA/FW PIPEs"); + hdd_ipa_uc_handle_first_con(ipa_ctxt); + } +} + +/** + * hdd_ipa_uc_op_cb() - IPA uC operation callback + * @op_msg: operation message received from firmware + * @usr_ctxt: user context registered with TL (we register the HDD Global + * context) + * + * Return: None + */ +static void hdd_ipa_uc_op_cb(struct op_msg_type *op_msg, void *usr_ctxt) +{ + struct op_msg_type *msg = op_msg; + struct ipa_uc_fw_stats *uc_fw_stat; + struct IpaHwStatsWDIInfoData_t ipa_stat; + struct hdd_ipa_priv *hdd_ipa; + hdd_context_t *hdd_ctx; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + if (!op_msg || !usr_ctxt) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "%s, INVALID ARG", __func__); + return; + } + + if (HDD_IPA_UC_OPCODE_MAX <= msg->op_code) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, + "%s, INVALID OPCODE %d", __func__, msg->op_code); + return; + } + + hdd_ctx = (hdd_context_t *) usr_ctxt; + + /* + * When SSR is going on or driver is unloading, just return. + */ + status = wlan_hdd_validate_context(hdd_ctx); + if (status) { + qdf_mem_free(op_msg); + return; + } + + hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa; + + HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG, + "OPCODE=%d", msg->op_code); + + if ((HDD_IPA_UC_OPCODE_TX_RESUME == msg->op_code) || + (HDD_IPA_UC_OPCODE_RX_RESUME == msg->op_code)) { + qdf_mutex_acquire(&hdd_ipa->ipa_lock); + hdd_ipa->activated_fw_pipe++; + if (HDD_IPA_UC_NUM_WDI_PIPE == hdd_ipa->activated_fw_pipe) { + hdd_ipa->resource_loading = false; + complete(&hdd_ipa->ipa_resource_comp); + if (hdd_ipa_uc_send_wdi_control_msg(true) < 0) { + qdf_mutex_release(&hdd_ipa->event_lock); + qdf_mem_free(op_msg); + return; + } + hdd_ipa_uc_proc_pending_event(hdd_ipa); + if (hdd_ipa->pending_cons_req) + ipa_rm_notify_completion( + IPA_RM_RESOURCE_GRANTED, + IPA_RM_RESOURCE_WLAN_CONS); + hdd_ipa->pending_cons_req = false; + } + qdf_mutex_release(&hdd_ipa->ipa_lock); + } else if ((HDD_IPA_UC_OPCODE_TX_SUSPEND == msg->op_code) || + (HDD_IPA_UC_OPCODE_RX_SUSPEND == msg->op_code)) { + qdf_mutex_acquire(&hdd_ipa->ipa_lock); + hdd_ipa->activated_fw_pipe--; + if (!hdd_ipa->activated_fw_pipe) { + /* + * Async return success from FW + * Disable/suspend all the PIPEs + */ + hdd_ipa_uc_disable_pipes(hdd_ipa); + if (hdd_ipa_uc_send_wdi_control_msg(false) < 0) { + qdf_mutex_release(&hdd_ipa->event_lock); + qdf_mem_free(op_msg); + return; + } + if (hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx)) + ipa_rm_release_resource( + IPA_RM_RESOURCE_WLAN_PROD); + hdd_ipa->resource_unloading = false; + complete(&hdd_ipa->ipa_resource_comp); + hdd_ipa_uc_proc_pending_event(hdd_ipa); + hdd_ipa->pending_cons_req = false; + } + qdf_mutex_release(&hdd_ipa->ipa_lock); + } else if ((HDD_IPA_UC_OPCODE_STATS == msg->op_code) && + (HDD_IPA_UC_STAT_REASON_DEBUG == hdd_ipa->stat_req_reason)) { + struct ol_txrx_ipa_resources *res = &hdd_ipa->ipa_resource; + /* STATs from host */ + QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR, + "==== IPA_UC WLAN_HOST CE ====\n" + "CE RING BASE: %pad\n" + "CE RING SIZE: %d\n" + "CE REG ADDR : %pad", + &res->ce_sr_base_paddr, + res->ce_sr_ring_size, + &res->ce_reg_paddr); + QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR, + "==== IPA_UC WLAN_HOST TX ====\n" + "COMP RING BASE: %pad\n" + "COMP RING SIZE: %d\n" + "NUM ALLOC BUF: %d\n" + "COMP RING DBELL : %pad", + &res->tx_comp_ring_base_paddr, + res->tx_comp_ring_size, + res->tx_num_alloc_buffer, + &hdd_ipa->tx_comp_doorbell_paddr); + QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR, + "==== IPA_UC WLAN_HOST RX ====\n" + "IND RING BASE: %pad\n" + "IND RING SIZE: %d\n" + "IND RING DBELL : %pad\n" + "PROC DONE IND ADDR : %pad\n" + "NUM EXCP PKT : %llu\n" + "NUM TX FWD OK : %llu\n" + "NUM TX FWD ERR : %llu", + &res->rx_rdy_ring_base_paddr, + res->rx_rdy_ring_size, + &hdd_ipa->rx_ready_doorbell_paddr, + &res->rx_proc_done_idx_paddr, + hdd_ipa->stats.num_rx_excep, + hdd_ipa->stats.num_tx_fwd_ok, + hdd_ipa->stats.num_tx_fwd_err); + QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR, + "==== IPA_UC WLAN_HOST CONTROL ====\n" + "SAP NUM STAs: %d\n" + "STA CONNECTED: %d\n" + "CONCURRENT MODE: %s\n" + "TX PIPE HDL: 0x%x\n" + "RX PIPE HDL : 0x%x\n" + "RSC LOADING : %d\n" + "RSC UNLOADING : %d\n" + "PNDNG CNS RQT : %d", + hdd_ipa->sap_num_connected_sta, + hdd_ipa->sta_connected, + (hdd_ctx->mcc_mode ? "MCC" : "SCC"), + hdd_ipa->tx_pipe_handle, + hdd_ipa->rx_pipe_handle, + hdd_ipa->resource_loading, + hdd_ipa->resource_unloading, + hdd_ipa->pending_cons_req); + + /* STATs from FW */ + uc_fw_stat = (struct ipa_uc_fw_stats *) + ((uint8_t *)op_msg + sizeof(struct op_msg_type)); + QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR, + "==== IPA_UC WLAN_FW TX ====\n" + "COMP RING BASE: 0x%x\n" + "COMP RING SIZE: %d\n" + "COMP RING DBELL : 0x%x\n" + "COMP RING DBELL IND VAL : %d\n" + "COMP RING DBELL CACHED VAL : %d\n" + "COMP RING DBELL CACHED VAL : %d\n" + "PKTS ENQ : %d\n" + "PKTS COMP : %d\n" + "IS SUSPEND : %d\n" + "RSVD : 0x%x", + uc_fw_stat->tx_comp_ring_base, + uc_fw_stat->tx_comp_ring_size, + uc_fw_stat->tx_comp_ring_dbell_addr, + uc_fw_stat->tx_comp_ring_dbell_ind_val, + uc_fw_stat->tx_comp_ring_dbell_cached_val, + uc_fw_stat->tx_comp_ring_dbell_cached_val, + uc_fw_stat->tx_pkts_enqueued, + uc_fw_stat->tx_pkts_completed, + uc_fw_stat->tx_is_suspend, + uc_fw_stat->tx_reserved); + QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR, + "==== IPA_UC WLAN_FW RX ====\n" + "IND RING BASE: 0x%x\n" + "IND RING SIZE: %d\n" + "IND RING DBELL : 0x%x\n" + "IND RING DBELL IND VAL : %d\n" + "IND RING DBELL CACHED VAL : %d\n" + "RDY IND ADDR : 0x%x\n" + "RDY IND CACHE VAL : %d\n" + "RFIL IND : %d\n" + "NUM PKT INDICAT : %d\n" + "BUF REFIL : %d\n" + "NUM DROP NO SPC : %d\n" + "NUM DROP NO BUF : %d\n" + "IS SUSPND : %d\n" + "RSVD : 0x%x\n", + uc_fw_stat->rx_ind_ring_base, + uc_fw_stat->rx_ind_ring_size, + uc_fw_stat->rx_ind_ring_dbell_addr, + uc_fw_stat->rx_ind_ring_dbell_ind_val, + uc_fw_stat->rx_ind_ring_dbell_ind_cached_val, + uc_fw_stat->rx_ind_ring_rdidx_addr, + uc_fw_stat->rx_ind_ring_rd_idx_cached_val, + uc_fw_stat->rx_refill_idx, + uc_fw_stat->rx_num_pkts_indicated, + uc_fw_stat->rx_buf_refilled, + uc_fw_stat->rx_num_ind_drop_no_space, + uc_fw_stat->rx_num_ind_drop_no_buf, + uc_fw_stat->rx_is_suspend, + uc_fw_stat->rx_reserved); + /* STATs from IPA */ + ipa_get_wdi_stats(&ipa_stat); + QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR, + "==== IPA_UC IPA TX ====\n" + "NUM PROCD : %d\n" + "CE DBELL : 0x%x\n" + "NUM DBELL FIRED : %d\n" + "COMP RNG FULL : %d\n" + "COMP RNG EMPT : %d\n" + "COMP RNG USE HGH : %d\n" + "COMP RNG USE LOW : %d\n" + "BAM FIFO FULL : %d\n" + "BAM FIFO EMPT : %d\n" + "BAM FIFO USE HGH : %d\n" + "BAM FIFO USE LOW : %d\n" + "NUM DBELL : %d\n" + "NUM UNEXP DBELL : %d\n" + "NUM BAM INT HDL : 0x%x\n" + "NUM BAM INT NON-RUN : 0x%x\n" + "NUM QMB INT HDL : 0x%x", + ipa_stat.tx_ch_stats.num_pkts_processed, + ipa_stat.tx_ch_stats.copy_engine_doorbell_value, + ipa_stat.tx_ch_stats.num_db_fired, + ipa_stat.tx_ch_stats.tx_comp_ring_stats.ringFull, + ipa_stat.tx_ch_stats.tx_comp_ring_stats.ringEmpty, + ipa_stat.tx_ch_stats.tx_comp_ring_stats.ringUsageHigh, + ipa_stat.tx_ch_stats.tx_comp_ring_stats.ringUsageLow, + ipa_stat.tx_ch_stats.bam_stats.bamFifoFull, + ipa_stat.tx_ch_stats.bam_stats.bamFifoEmpty, + ipa_stat.tx_ch_stats.bam_stats.bamFifoUsageHigh, + ipa_stat.tx_ch_stats.bam_stats.bamFifoUsageLow, + ipa_stat.tx_ch_stats.num_db, + ipa_stat.tx_ch_stats.num_unexpected_db, + ipa_stat.tx_ch_stats.num_bam_int_handled, + ipa_stat.tx_ch_stats. + num_bam_int_in_non_runnning_state, + ipa_stat.tx_ch_stats.num_qmb_int_handled); + + QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR, + "==== IPA_UC IPA RX ====\n" + "MAX OST PKT : %d\n" + "NUM PKT PRCSD : %d\n" + "RNG RP : 0x%x\n" + "COMP RNG FULL : %d\n" + "COMP RNG EMPT : %d\n" + "COMP RNG USE HGH : %d\n" + "COMP RNG USE LOW : %d\n" + "BAM FIFO FULL : %d\n" + "BAM FIFO EMPT : %d\n" + "BAM FIFO USE HGH : %d\n" + "BAM FIFO USE LOW : %d\n" + "NUM DB : %d\n" + "NUM UNEXP DB : %d\n" + "NUM BAM INT HNDL : 0x%x\n", + ipa_stat.rx_ch_stats.max_outstanding_pkts, + ipa_stat.rx_ch_stats.num_pkts_processed, + ipa_stat.rx_ch_stats.rx_ring_rp_value, + ipa_stat.rx_ch_stats.rx_ind_ring_stats.ringFull, + ipa_stat.rx_ch_stats.rx_ind_ring_stats.ringEmpty, + ipa_stat.rx_ch_stats.rx_ind_ring_stats.ringUsageHigh, + ipa_stat.rx_ch_stats.rx_ind_ring_stats.ringUsageLow, + ipa_stat.rx_ch_stats.bam_stats.bamFifoFull, + ipa_stat.rx_ch_stats.bam_stats.bamFifoEmpty, + ipa_stat.rx_ch_stats.bam_stats.bamFifoUsageHigh, + ipa_stat.rx_ch_stats.bam_stats.bamFifoUsageLow, + ipa_stat.rx_ch_stats.num_db, + ipa_stat.rx_ch_stats.num_unexpected_db, + ipa_stat.rx_ch_stats.num_bam_int_handled); + } else if ((HDD_IPA_UC_OPCODE_STATS == msg->op_code) && + (HDD_IPA_UC_STAT_REASON_BW_CAL == hdd_ipa->stat_req_reason)) { + /* STATs from FW */ + uc_fw_stat = (struct ipa_uc_fw_stats *) + ((uint8_t *)op_msg + sizeof(struct op_msg_type)); + qdf_mutex_acquire(&hdd_ipa->ipa_lock); + hdd_ipa->ipa_tx_packets_diff = HDD_BW_GET_DIFF( + uc_fw_stat->tx_pkts_completed, + hdd_ipa->ipa_p_tx_packets); + hdd_ipa->ipa_rx_packets_diff = HDD_BW_GET_DIFF( + (uc_fw_stat->rx_num_ind_drop_no_space + + uc_fw_stat->rx_num_ind_drop_no_buf + + uc_fw_stat->rx_num_pkts_indicated), + hdd_ipa->ipa_p_rx_packets); + + hdd_ipa->ipa_p_tx_packets = uc_fw_stat->tx_pkts_completed; + hdd_ipa->ipa_p_rx_packets = + (uc_fw_stat->rx_num_ind_drop_no_space + + uc_fw_stat->rx_num_ind_drop_no_buf + + uc_fw_stat->rx_num_pkts_indicated); + qdf_mutex_release(&hdd_ipa->ipa_lock); + } else if (msg->op_code == HDD_IPA_UC_OPCODE_UC_READY) { + qdf_mutex_acquire(&hdd_ipa->ipa_lock); + hdd_ipa_uc_loaded_handler(hdd_ipa); + qdf_mutex_release(&hdd_ipa->ipa_lock); + } else if (hdd_ipa_uc_op_metering(hdd_ctx, op_msg)) { + HDD_IPA_LOG(LOGE, "Invalid message: op_code=%d, reason=%d", + msg->op_code, hdd_ipa->stat_req_reason); + } + + qdf_mem_free(op_msg); +} + + +/** + * hdd_ipa_uc_offload_enable_disable() - wdi enable/disable notify to fw + * @adapter: device adapter instance + * @offload_type: MCC or SCC + * @enable: TX offload enable or disable + * + * Return: none + */ +static void hdd_ipa_uc_offload_enable_disable(hdd_adapter_t *adapter, + uint32_t offload_type, bool enable) +{ + struct hdd_ipa_priv *hdd_ipa = ghdd_ipa; + struct sir_ipa_offload_enable_disable ipa_offload_enable_disable; + struct hdd_ipa_iface_context *iface_context = NULL; + uint8_t session_id; + + if (!adapter || !hdd_ipa) + return; + + iface_context = adapter->ipa_context; + session_id = adapter->sessionId; + + if (!iface_context) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, + "Interface context is NULL"); + return; + } + + if (enable == hdd_ipa->vdev_offload_enabled[session_id]) { + /* IPA offload status is already set as desired */ + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, + "%s: (offload_type=%d, vdev_id=%d, enable=%d)", + "IPA offload status is already set", + offload_type, session_id, enable); + return; + } + + if (wlan_hdd_validate_session_id(adapter->sessionId)) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, + "invalid session id: %d, offload_type=%d, enable=%d", + adapter->sessionId, offload_type, enable); + return; + } + + qdf_mem_zero(&ipa_offload_enable_disable, + sizeof(ipa_offload_enable_disable)); + ipa_offload_enable_disable.offload_type = offload_type; + ipa_offload_enable_disable.vdev_id = session_id; + ipa_offload_enable_disable.enable = enable; + + HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, + "offload_type=%d, vdev_id=%d, enable=%d", + ipa_offload_enable_disable.offload_type, + ipa_offload_enable_disable.vdev_id, + ipa_offload_enable_disable.enable); + + if (QDF_STATUS_SUCCESS != + sme_ipa_offload_enable_disable(WLAN_HDD_GET_HAL_CTX(adapter), + adapter->sessionId, &ipa_offload_enable_disable)) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, + "%s: Failure to enable IPA offload (offload_type=%d, vdev_id=%d, enable=%d)", + __func__, + ipa_offload_enable_disable.offload_type, + ipa_offload_enable_disable.vdev_id, + ipa_offload_enable_disable.enable); + } else { + /* Update the IPA offload status */ + hdd_ipa->vdev_offload_enabled[session_id] = + ipa_offload_enable_disable.enable; + } +} + +/** + * hdd_ipa_uc_fw_op_event_handler - IPA uC FW OPvent handler + * @work: uC OP work + * + * Return: None + */ +static void hdd_ipa_uc_fw_op_event_handler(struct work_struct *work) +{ + struct op_msg_type *msg; + struct uc_op_work_struct *uc_op_work = container_of(work, + struct uc_op_work_struct, work); + struct hdd_ipa_priv *hdd_ipa = ghdd_ipa; + + cds_ssr_protect(__func__); + + msg = uc_op_work->msg; + uc_op_work->msg = NULL; + HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO_HIGH, + "%s, posted msg %d", __func__, msg->op_code); + + hdd_ipa_uc_op_cb(msg, hdd_ipa->hdd_ctx); + + cds_ssr_unprotect(__func__); + + return; +} + +/** + * hdd_ipa_uc_op_event_handler() - Adapter lookup + * hdd_ipa_uc_fw_op_event_handler - IPA uC FW OPvent handler + * @op_msg: operation message received from firmware + * @hdd_ctx: Global HDD context + * + * Return: None + */ +static void hdd_ipa_uc_op_event_handler(uint8_t *op_msg, void *hdd_ctx) +{ + struct hdd_ipa_priv *hdd_ipa; + struct op_msg_type *msg; + struct uc_op_work_struct *uc_op_work; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + status = wlan_hdd_validate_context(hdd_ctx); + if (status) + goto end; + + msg = (struct op_msg_type *)op_msg; + hdd_ipa = ((hdd_context_t *)hdd_ctx)->hdd_ipa; + + if (unlikely(!hdd_ipa)) + goto end; + + if (HDD_IPA_UC_OPCODE_MAX <= msg->op_code) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "%s: Invalid OP Code (%d)", + __func__, msg->op_code); + goto end; + } + + uc_op_work = &hdd_ipa->uc_op_work[msg->op_code]; + if (uc_op_work->msg) + /* When the same uC OPCODE is already pended, just return */ + goto end; + + uc_op_work->msg = msg; + schedule_work(&uc_op_work->work); + return; + +end: + qdf_mem_free(op_msg); +} + +/** + * hdd_ipa_init_uc_op_work - init ipa uc op work + * @work: struct work_struct + * @work_handler: work_handler + * + * Return: none + */ +static void hdd_ipa_init_uc_op_work(struct work_struct *work, + work_func_t work_handler) +{ + INIT_WORK(work, work_handler); +} + +#ifdef FEATURE_METERING +/** + * __hdd_ipa_wdi_meter_notifier_cb() - WLAN to IPA callback handler. + * IPA calls to get WLAN stats or set quota limit. + * @priv: pointer to private data registered with IPA (we register a + *» pointer to the global IPA context) + * @evt: the IPA event which triggered the callback + * @data: data associated with the event + * + * Return: None + */ +static void __hdd_ipa_wdi_meter_notifier_cb(enum ipa_wdi_meter_evt_type evt, + void *data) +{ + struct hdd_ipa_priv *hdd_ipa = ghdd_ipa; + hdd_adapter_t *adapter = NULL; + struct ipa_get_wdi_sap_stats *wdi_sap_stats; + struct ipa_set_wifi_quota *ipa_set_quota; + int ret = 0; + + if (wlan_hdd_validate_context(hdd_ipa->hdd_ctx)) + return; + + adapter = hdd_get_adapter(hdd_ipa->hdd_ctx, QDF_STA_MODE); + + HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "event=%d", evt); + + switch (evt) { + case IPA_GET_WDI_SAP_STATS: + /* fill-up ipa_get_wdi_sap_stats structure after getting + ipa_uc_fw_stats from FW */ + wdi_sap_stats = data; + + if (!adapter) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, + "IPA uC share stats failed - no adapter"); + wdi_sap_stats->stats_valid = 0; + return; + } + + INIT_COMPLETION(hdd_ipa->ipa_uc_sharing_stats_comp); + hdd_ipa_uc_sharing_stats_request(adapter, + wdi_sap_stats->reset_stats); + ret = wait_for_completion_timeout( + &hdd_ipa->ipa_uc_sharing_stats_comp, + msecs_to_jiffies(IPA_UC_SHARING_STATES_WAIT_TIME)); + if (!ret) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, + "IPA uC share stats request timed out"); + wdi_sap_stats->stats_valid = 0; + } else { + wdi_sap_stats->stats_valid = 1; + + wdi_sap_stats->ipv4_rx_packets = + hdd_ipa->ipa_sharing_stats.ipv4_rx_packets; + wdi_sap_stats->ipv4_rx_bytes = + hdd_ipa->ipa_sharing_stats.ipv4_rx_bytes; + wdi_sap_stats->ipv6_rx_packets = + hdd_ipa->ipa_sharing_stats.ipv6_rx_packets; + wdi_sap_stats->ipv6_rx_bytes = + hdd_ipa->ipa_sharing_stats.ipv6_rx_bytes; + wdi_sap_stats->ipv4_tx_packets = + hdd_ipa->ipa_sharing_stats.ipv4_tx_packets; + wdi_sap_stats->ipv4_tx_bytes = + hdd_ipa->ipa_sharing_stats.ipv4_tx_bytes; + wdi_sap_stats->ipv6_tx_packets = + hdd_ipa->ipa_sharing_stats.ipv6_tx_packets; + wdi_sap_stats->ipv6_tx_bytes = + hdd_ipa->ipa_sharing_stats.ipv6_tx_bytes; + HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG, + "%s:%d,%llu,%llu,%llu,%llu,%llu,%llu,%llu,%llu", + "IPA_GET_WDI_SAP_STATS", + wdi_sap_stats->stats_valid, + wdi_sap_stats->ipv4_rx_packets, + wdi_sap_stats->ipv4_rx_bytes, + wdi_sap_stats->ipv6_rx_packets, + wdi_sap_stats->ipv6_rx_bytes, + wdi_sap_stats->ipv4_tx_packets, + wdi_sap_stats->ipv4_tx_bytes, + wdi_sap_stats->ipv6_tx_packets, + wdi_sap_stats->ipv6_tx_bytes); + } + break; + case IPA_SET_WIFI_QUOTA: + /* get ipa_set_wifi_quota structure from IPA and pass to FW + through quota_exceeded field in ipa_uc_fw_stats */ + ipa_set_quota = data; + + if (!adapter) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, + "IPA uC set quota failed - no adapter"); + ipa_set_quota->set_valid = 0; + return; + } + + INIT_COMPLETION(hdd_ipa->ipa_uc_set_quota_comp); + hdd_ipa_uc_set_quota(adapter, ipa_set_quota->set_quota, + ipa_set_quota->quota_bytes); + + ret = wait_for_completion_timeout( + &hdd_ipa->ipa_uc_set_quota_comp, + msecs_to_jiffies(IPA_UC_SET_QUOTA_WAIT_TIME)); + if (!ret) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, + "IPA uC set quota request timed out"); + ipa_set_quota->set_valid = 0; + } else { + ipa_set_quota->quota_bytes = + ((uint64_t)(hdd_ipa->ipa_quota_rsp.quota_hi) + <<32)|hdd_ipa->ipa_quota_rsp.quota_lo; + ipa_set_quota->set_valid = + hdd_ipa->ipa_quota_rsp.success; + } + + HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG, "SET_QUOTA: %llu, %d", + ipa_set_quota->quota_bytes, + ipa_set_quota->set_valid); + break; + } +} + +/** + * hdd_ipa_wdi_meter_notifier_cb() - WLAN to IPA callback handler. + * IPA calls to get WLAN stats or set quota limit. + * @priv: pointer to private data registered with IPA (we register a + *» pointer to the global IPA context) + * @evt: the IPA event which triggered the callback + * @data: data associated with the event + * + * Return: None + */ +static void hdd_ipa_wdi_meter_notifier_cb(enum ipa_wdi_meter_evt_type evt, + void *data) +{ + cds_ssr_protect(__func__); + __hdd_ipa_wdi_meter_notifier_cb(evt, data); + cds_ssr_unprotect(__func__); +} + +static void hdd_ipa_init_metering(struct hdd_ipa_priv *ipa_ctxt, + struct ipa_wdi_in_params *pipe_in) +{ + pipe_in->wdi_notify = hdd_ipa_wdi_meter_notifier_cb; + + init_completion(&ipa_ctxt->ipa_uc_sharing_stats_comp); + init_completion(&ipa_ctxt->ipa_uc_set_quota_comp); +} +#else +static void hdd_ipa_init_metering(struct hdd_ipa_priv *ipa_ctxt, + struct ipa_wdi_in_params *pipe_in) +{ +} +#endif + +/** + * hdd_ipa_uc_ol_init() - Initialize IPA uC offload + * @hdd_ctx: Global HDD context + * + * This function is called to update IPA pipe configuration with resources + * allocated by wlan driver (cds_pre_enable) before enabling it in FW + * (cds_enable) + * + * Return: QDF_STATUS + */ +QDF_STATUS hdd_ipa_uc_ol_init(hdd_context_t *hdd_ctx) +{ + struct ipa_wdi_in_params pipe_in; + struct ipa_wdi_out_params pipe_out; + struct hdd_ipa_priv *ipa_ctxt = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa; + struct ol_txrx_pdev_t *pdev = NULL; + int ret; + QDF_STATUS stat = QDF_STATUS_SUCCESS; + + if (!hdd_ipa_uc_is_enabled(hdd_ctx)) + return stat; + + ENTER(); + /* Do only IPA Pipe specific configuration here. All one time + * initialization wrt IPA UC shall in hdd_ipa_init and those need + * to be reinit at SSR shall in be SSR deinit / reinit functions. + */ + pdev = cds_get_context(QDF_MODULE_ID_TXRX); + if (!pdev) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL, "pdev is NULL"); + stat = QDF_STATUS_E_FAILURE; + goto fail_return; + } + ol_txrx_ipa_uc_get_resource(pdev, &ipa_ctxt->ipa_resource); + if ((ipa_ctxt->ipa_resource.ce_sr_base_paddr == 0) || + (ipa_ctxt->ipa_resource.tx_comp_ring_base_paddr == 0) || + (ipa_ctxt->ipa_resource.rx_rdy_ring_base_paddr == 0) || + (ipa_ctxt->ipa_resource.rx2_rdy_ring_base_paddr == 0)) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL, + "IPA UC resource alloc fail"); + stat = QDF_STATUS_E_FAILURE; + goto fail_return; + } + qdf_mem_zero(&ipa_ctxt->cons_pipe_in, sizeof(struct ipa_wdi_in_params)); + qdf_mem_zero(&ipa_ctxt->prod_pipe_in, sizeof(struct ipa_wdi_in_params)); + qdf_mem_zero(&pipe_in, sizeof(struct ipa_wdi_in_params)); + qdf_mem_zero(&pipe_out, sizeof(struct ipa_wdi_out_params)); + + /* TX PIPE */ + pipe_in.sys.ipa_ep_cfg.nat.nat_en = IPA_BYPASS_NAT; + pipe_in.sys.ipa_ep_cfg.hdr.hdr_len = HDD_IPA_UC_WLAN_TX_HDR_LEN; + pipe_in.sys.ipa_ep_cfg.hdr.hdr_ofst_pkt_size_valid = 1; + pipe_in.sys.ipa_ep_cfg.hdr.hdr_ofst_pkt_size = 0; + pipe_in.sys.ipa_ep_cfg.hdr.hdr_additional_const_len = + HDD_IPA_UC_WLAN_8023_HDR_SIZE; + pipe_in.sys.ipa_ep_cfg.mode.mode = IPA_BASIC; + pipe_in.sys.client = IPA_CLIENT_WLAN1_CONS; + pipe_in.sys.desc_fifo_sz = hdd_ctx->config->IpaDescSize; + pipe_in.sys.priv = hdd_ctx->hdd_ipa; + pipe_in.sys.ipa_ep_cfg.hdr_ext.hdr_little_endian = true; + pipe_in.sys.notify = hdd_ipa_i2w_cb; + if (!hdd_ipa_is_rm_enabled(hdd_ctx)) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, + "IPA RM DISABLED, IPA AWAKE"); + pipe_in.sys.keep_ipa_awake = true; + } + + pipe_in.u.dl.comp_ring_base_pa = + ipa_ctxt->ipa_resource.tx_comp_ring_base_paddr; + /* IPA requires total byte counts of Tx comp ring */ + pipe_in.u.dl.comp_ring_size = + ipa_ctxt->ipa_resource.tx_comp_ring_size * + sizeof(target_paddr_t); + pipe_in.u.dl.ce_ring_base_pa = + ipa_ctxt->ipa_resource.ce_sr_base_paddr; + pipe_in.u.dl.ce_door_bell_pa = ipa_ctxt->ipa_resource.ce_reg_paddr; + pipe_in.u.dl.ce_ring_size = + ipa_ctxt->ipa_resource.ce_sr_ring_size; + pipe_in.u.dl.num_tx_buffers = + ipa_ctxt->ipa_resource.tx_num_alloc_buffer; + + qdf_mem_copy(&ipa_ctxt->cons_pipe_in, &pipe_in, + sizeof(struct ipa_wdi_in_params)); + hdd_ipa_uc_get_db_paddr(&ipa_ctxt->tx_comp_doorbell_paddr, + IPA_CLIENT_WLAN1_CONS); + + if (true == ipa_ctxt->uc_loaded) { + /* Connect WDI IPA PIPE */ + ret = ipa_connect_wdi_pipe(&ipa_ctxt->cons_pipe_in, &pipe_out); + if (ret) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, + "ipa_connect_wdi_pipe falied for Tx: ret=%d", + ret); + stat = QDF_STATUS_E_FAILURE; + goto fail_return; + } + /* Micro Controller Doorbell register */ + HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO_HIGH, + "CONS DB pipe out 0x%x TX PIPE Handle 0x%x", + (unsigned int)pipe_out.uc_door_bell_pa, + ipa_ctxt->tx_pipe_handle); + + /* Micro Controller Doorbell register */ + ipa_ctxt->tx_comp_doorbell_paddr = pipe_out.uc_door_bell_pa; + + /* WLAN TX PIPE Handle */ + ipa_ctxt->tx_pipe_handle = pipe_out.clnt_hdl; + + if (ipa_ctxt->tx_pipe_handle == 0) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, + "TX Handle zero"); + QDF_BUG(0); + } + + HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, + "CONS DB pipe out 0x%x TX PIPE Handle 0x%x", + (unsigned int)pipe_out.uc_door_bell_pa, + ipa_ctxt->tx_pipe_handle); + HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, + "TX : CRBPA 0x%x, CRS %d, CERBPA 0x%x, CEDPA 0x%x," + " CERZ %d, NB %d, CDBPAD 0x%x", + (unsigned int)pipe_in.u.dl.comp_ring_base_pa, + pipe_in.u.dl.comp_ring_size, + (unsigned int)pipe_in.u.dl.ce_ring_base_pa, + (unsigned int)pipe_in.u.dl.ce_door_bell_pa, + pipe_in.u.dl.ce_ring_size, + pipe_in.u.dl.num_tx_buffers, + (unsigned int)ipa_ctxt->tx_comp_doorbell_paddr); + } + + /* RX PIPE */ + pipe_in.sys.ipa_ep_cfg.nat.nat_en = IPA_BYPASS_NAT; + pipe_in.sys.ipa_ep_cfg.hdr.hdr_len = HDD_IPA_UC_WLAN_RX_HDR_LEN; + pipe_in.sys.ipa_ep_cfg.hdr.hdr_ofst_metadata_valid = 0; + pipe_in.sys.ipa_ep_cfg.hdr.hdr_metadata_reg_valid = 1; + pipe_in.sys.ipa_ep_cfg.mode.mode = IPA_BASIC; + pipe_in.sys.client = IPA_CLIENT_WLAN1_PROD; + pipe_in.sys.desc_fifo_sz = hdd_ctx->config->IpaDescSize + + sizeof(struct sps_iovec); + pipe_in.sys.notify = hdd_ipa_w2i_cb; + if (!hdd_ipa_is_rm_enabled(hdd_ctx)) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, + "%s: IPA RM DISABLED, IPA AWAKE", __func__); + pipe_in.sys.keep_ipa_awake = true; + } + + pipe_in.u.ul.rdy_ring_base_pa = + ipa_ctxt->ipa_resource.rx_rdy_ring_base_paddr; + pipe_in.u.ul.rdy_ring_size = + ipa_ctxt->ipa_resource.rx_rdy_ring_size; + pipe_in.u.ul.rdy_ring_rp_pa = + ipa_ctxt->ipa_resource.rx_proc_done_idx_paddr; + HDD_IPA_WDI2_SET(pipe_in, ipa_ctxt); + + hdd_ipa_init_metering(ipa_ctxt, &pipe_in); + + qdf_mem_copy(&ipa_ctxt->prod_pipe_in, &pipe_in, + sizeof(struct ipa_wdi_in_params)); + hdd_ipa_uc_get_db_paddr(&ipa_ctxt->rx_ready_doorbell_paddr, + IPA_CLIENT_WLAN1_PROD); + + if (true == ipa_ctxt->uc_loaded) { + ret = ipa_connect_wdi_pipe(&ipa_ctxt->prod_pipe_in, &pipe_out); + if (ret) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, + "ipa_connect_wdi_pipe failed for Rx: ret=%d", + ret); + stat = QDF_STATUS_E_FAILURE; + ret = ipa_disconnect_wdi_pipe(ipa_ctxt->tx_pipe_handle); + if (ret) + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, + "disconnect failed for TX: ret=%d", + ret); + goto fail_return; + } + ipa_ctxt->rx_ready_doorbell_paddr = pipe_out.uc_door_bell_pa; + ipa_ctxt->rx_pipe_handle = pipe_out.clnt_hdl; + if (ipa_ctxt->rx_pipe_handle == 0) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, + "RX Handle zero"); + QDF_BUG(0); + } + + HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, + "PROD DB pipe out 0x%x RX PIPE Handle 0x%x", + (unsigned int)pipe_out.uc_door_bell_pa, + ipa_ctxt->rx_pipe_handle); + HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, + "RX : RRBPA 0x%x, RRS %d, PDIPA 0x%x, RDY_DB_PAD 0x%x", + (unsigned int)pipe_in.u.ul.rdy_ring_base_pa, + pipe_in.u.ul.rdy_ring_size, + (unsigned int)pipe_in.u.ul.rdy_ring_rp_pa, + (unsigned int)ipa_ctxt->rx_ready_doorbell_paddr); + } + + ol_txrx_ipa_uc_set_doorbell_paddr(pdev, + ipa_ctxt->tx_comp_doorbell_paddr, + ipa_ctxt->rx_ready_doorbell_paddr); + + ol_txrx_ipa_uc_register_op_cb(pdev, + hdd_ipa_uc_op_event_handler, + (void *)hdd_ctx); + + HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO_HIGH, + "ipa_uc_op_cb=0x%p, tx_comp_idx_paddr=0x%x, rx_rdy_idx_paddr=0x%x", + pdev->ipa_uc_op_cb, + (unsigned int)pdev->htt_pdev->ipa_uc_tx_rsc.tx_comp_idx_paddr, + (unsigned int)pdev->htt_pdev->ipa_uc_rx_rsc.rx_rdy_idx_paddr); + +fail_return: + EXIT(); + return stat; +} + +/** + * hdd_ipa_uc_ol_deinit() - Disconnect IPA TX and RX pipes + * @hdd_ctx: Global HDD context + * + * Return: 0 on success, negativer errno on error + */ +int hdd_ipa_uc_ol_deinit(hdd_context_t *hdd_ctx) +{ + struct hdd_ipa_priv *hdd_ipa = hdd_ctx->hdd_ipa; + int ret = 0; + + if (!hdd_ipa_uc_is_enabled(hdd_ctx)) + return ret; + + if (!hdd_ipa->ipa_pipes_down) + hdd_ipa_uc_disable_pipes(hdd_ipa); + + if (true == hdd_ipa->uc_loaded) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, + "%s: Disconnect TX PIPE tx_pipe_handle=0x%x", + __func__, hdd_ipa->tx_pipe_handle); + ret = ipa_disconnect_wdi_pipe(hdd_ipa->tx_pipe_handle); + HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, + "%s: Disconnect RX PIPE rx_pipe_handle=0x%x", + __func__, hdd_ipa->rx_pipe_handle); + ret = ipa_disconnect_wdi_pipe(hdd_ipa->rx_pipe_handle); + } + + return ret; +} + +/** + * __hdd_ipa_uc_force_pipe_shutdown() - Force shutdown IPA pipe + * @hdd_ctx: hdd main context + * + * Force shutdown IPA pipe + * Independent of FW pipe status, IPA pipe shutdonw progress + * in case, any STA does not leave properly, IPA HW pipe should cleaned up + * independent from FW pipe status + * + * Return: NONE + */ +static void __hdd_ipa_uc_force_pipe_shutdown(hdd_context_t *hdd_ctx) +{ + struct hdd_ipa_priv *hdd_ipa; + + if (!hdd_ipa_is_enabled(hdd_ctx) || !hdd_ctx->hdd_ipa) + return; + + hdd_ipa = (struct hdd_ipa_priv *)hdd_ctx->hdd_ipa; + if (false == hdd_ipa->ipa_pipes_down) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, + "IPA pipes are not down yet, force shutdown"); + hdd_ipa_uc_disable_pipes(hdd_ipa); + } else { + HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, + "IPA pipes are down, do nothing"); + } + + return; +} + +/** + * hdd_ipa_uc_force_pipe_shutdown() - SSR wrapper for + * __hdd_ipa_uc_force_pipe_shutdown + * @hdd_ctx: hdd main context + * + * Force shutdown IPA pipe + * Independent of FW pipe status, IPA pipe shutdonw progress + * in case, any STA does not leave properly, IPA HW pipe should cleaned up + * independent from FW pipe status + * + * Return: NONE + */ +void hdd_ipa_uc_force_pipe_shutdown(hdd_context_t *hdd_ctx) +{ + cds_ssr_protect(__func__); + __hdd_ipa_uc_force_pipe_shutdown(hdd_ctx); + cds_ssr_unprotect(__func__); +} + +/** + * hdd_ipa_msg_free_fn() - Free an IPA message + * @buff: pointer to the IPA message + * @len: length of the IPA message + * @type: type of IPA message + * + * Return: None + */ +static void hdd_ipa_msg_free_fn(void *buff, uint32_t len, uint32_t type) +{ + HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "msg type:%d, len:%d", type, len); + ghdd_ipa->stats.num_free_msg++; + qdf_mem_free(buff); +} + +/** + * hdd_ipa_uc_send_evt() - send event to ipa + * @hdd_ctx: pointer to hdd context + * @type: event type + * @mac_addr: pointer to mac address + * + * Send event to IPA driver + * + * Return: 0 - Success + */ +static int hdd_ipa_uc_send_evt(hdd_adapter_t *adapter, + enum ipa_wlan_event type, uint8_t *mac_addr) +{ + struct hdd_ipa_priv *hdd_ipa = ghdd_ipa; + struct ipa_msg_meta meta; + struct ipa_wlan_msg *msg; + int ret = 0; + + meta.msg_len = sizeof(struct ipa_wlan_msg); + msg = qdf_mem_malloc(meta.msg_len); + if (msg == NULL) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, + "msg allocation failed"); + return -ENOMEM; + } + + meta.msg_type = type; + strlcpy(msg->name, adapter->dev->name, + IPA_RESOURCE_NAME_MAX); + memcpy(msg->mac_addr, mac_addr, ETH_ALEN); + HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "%s: Evt: %d", + msg->name, meta.msg_type); + ret = ipa_send_msg(&meta, msg, hdd_ipa_msg_free_fn); + if (ret) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, + "%s: Evt: %d fail:%d", + msg->name, meta.msg_type, ret); + qdf_mem_free(msg); + return ret; + } + + hdd_ipa->stats.num_send_msg++; + + return ret; +} + +/** + * hdd_ipa_uc_disconnect_client() - send client disconnect event + * @hdd_ctx: pointer to hdd adapter + * + * Send disconnect client event to IPA driver during SSR + * + * Return: 0 - Success + */ +static int hdd_ipa_uc_disconnect_client(hdd_adapter_t *adapter) +{ + struct hdd_ipa_priv *hdd_ipa = ghdd_ipa; + int ret = 0; + int i; + + for (i = 0; i < WLAN_MAX_STA_COUNT; i++) { + if (qdf_is_macaddr_broadcast(&adapter->aStaInfo[i].macAddrSTA)) + continue; + if ((adapter->aStaInfo[i].isUsed) && + (!adapter->aStaInfo[i].isDeauthInProgress) && + hdd_ipa->sap_num_connected_sta) { + hdd_ipa_uc_send_evt(adapter, WLAN_CLIENT_DISCONNECT, + adapter->aStaInfo[i].macAddrSTA.bytes); + hdd_ipa->sap_num_connected_sta--; + } + } + + return ret; +} + +/** + * hdd_ipa_uc_disconnect_ap() - send ap disconnect event + * @hdd_ctx: pointer to hdd adapter + * + * Send disconnect ap event to IPA driver during SSR + * + * Return: 0 - Success + */ + +static int hdd_ipa_uc_disconnect_ap(hdd_adapter_t *adapter) +{ + int ret = 0; + + if (adapter->ipa_context) + hdd_ipa_uc_send_evt(adapter, WLAN_AP_DISCONNECT, + adapter->dev->dev_addr); + + return ret; +} + +#ifdef IPA_UC_STA_OFFLOAD +/** + * hdd_ipa_uc_disconnect_sta() - send sta disconnect event + * @hdd_ctx: pointer to hdd adapter + * + * Send disconnect sta event to IPA driver during SSR + * + * Return: 0 - Success + */ +static int hdd_ipa_uc_disconnect_sta(hdd_adapter_t *adapter) +{ + hdd_station_ctx_t *pHddStaCtx; + struct hdd_ipa_priv *hdd_ipa = ghdd_ipa; + int ret = 0; + + if (hdd_ipa_uc_sta_is_enabled(hdd_ipa) && + hdd_ipa->sta_connected) { + pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + hdd_ipa_uc_send_evt(adapter, WLAN_STA_DISCONNECT, + pHddStaCtx->conn_info.bssId); + } + + return ret; +} +#else +static int hdd_ipa_uc_disconnect_sta(hdd_adapter_t *adapter) +{ + return 0; +} + +#endif + +/** + * hdd_ipa_uc_disconnect() - send disconnect ipa event + * @hdd_ctx: pointer to hdd context + * + * Send disconnect event to IPA driver during SSR + * + * Return: 0 - Success + */ +static int hdd_ipa_uc_disconnect(hdd_context_t *hdd_ctx) +{ + hdd_adapter_list_node_t *adapter_node = NULL, *next = NULL; + QDF_STATUS status; + hdd_adapter_t *adapter; + int ret = 0; + + status = hdd_get_front_adapter(hdd_ctx, &adapter_node); + while (NULL != adapter_node && QDF_STATUS_SUCCESS == status) { + adapter = adapter_node->pAdapter; + if (adapter->device_mode == QDF_SAP_MODE) { + hdd_ipa_uc_disconnect_client(adapter); + hdd_ipa_uc_disconnect_ap(adapter); + } else if (adapter->device_mode == QDF_STA_MODE) { + hdd_ipa_uc_disconnect_sta(adapter); + } + + status = hdd_get_next_adapter( + hdd_ctx, adapter_node, &next); + adapter_node = next; + } + + return ret; +} + +/** + * __hdd_ipa_uc_ssr_deinit() - handle ipa deinit for SSR + * + * Deinit basic IPA UC host side to be in sync reloaded FW during + * SSR + * + * Return: 0 - Success + */ +static int __hdd_ipa_uc_ssr_deinit(void) +{ + struct hdd_ipa_priv *hdd_ipa = ghdd_ipa; + int idx; + struct hdd_ipa_iface_context *iface_context; + hdd_context_t *hdd_ctx; + + if (!hdd_ipa) + return 0; + + hdd_ctx = hdd_ipa->hdd_ctx; + if (!hdd_ipa_uc_is_enabled(hdd_ctx)) + return 0; + + /* send disconnect to ipa driver */ + hdd_ipa_uc_disconnect(hdd_ctx); + + /* Clean up HDD IPA interfaces */ + for (idx = 0; (hdd_ipa->num_iface > 0) && + (idx < HDD_IPA_MAX_IFACE); idx++) { + iface_context = &hdd_ipa->iface_context[idx]; + if (iface_context->adapter && iface_context->adapter->magic == + WLAN_HDD_ADAPTER_MAGIC) + hdd_ipa_cleanup_iface(iface_context); + } + hdd_ipa->num_iface = 0; + /* After SSR, wlan driver reloads FW again. But we need to protect + * IPA submodule during SSR transient state. So deinit basic IPA + * UC host side to be in sync with reloaded FW during SSR + */ + + qdf_mutex_acquire(&hdd_ipa->ipa_lock); + for (idx = 0; idx < WLAN_MAX_STA_COUNT; idx++) { + hdd_ipa->assoc_stas_map[idx].is_reserved = false; + hdd_ipa->assoc_stas_map[idx].sta_id = 0xFF; + } + qdf_mutex_release(&hdd_ipa->ipa_lock); + + if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx)) + hdd_ipa_uc_sta_reset_sta_connected(hdd_ipa); + + for (idx = 0; idx < HDD_IPA_UC_OPCODE_MAX; idx++) { + cancel_work_sync(&hdd_ipa->uc_op_work[idx].work); + qdf_mem_free(hdd_ipa->uc_op_work[idx].msg); + hdd_ipa->uc_op_work[idx].msg = NULL; + } + return 0; +} + +/** + * hdd_ipa_uc_ssr_deinit() - SSR wrapper for __hdd_ipa_uc_ssr_deinit + * + * Deinit basic IPA UC host side to be in sync reloaded FW during + * SSR + * + * Return: 0 - Success + */ +int hdd_ipa_uc_ssr_deinit(void) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __hdd_ipa_uc_ssr_deinit(); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __hdd_ipa_uc_ssr_reinit() - handle ipa reinit after SSR + * + * Init basic IPA UC host side to be in sync with reloaded FW after + * SSR to resume IPA UC operations + * + * Return: 0 - Success + */ +static int __hdd_ipa_uc_ssr_reinit(hdd_context_t *hdd_ctx) +{ + + struct hdd_ipa_priv *hdd_ipa = ghdd_ipa; + int i; + struct hdd_ipa_iface_context *iface_context = NULL; + + if (!hdd_ipa || !hdd_ipa_uc_is_enabled(hdd_ctx)) + return 0; + + /* Create the interface context */ + for (i = 0; i < HDD_IPA_MAX_IFACE; i++) { + iface_context = &hdd_ipa->iface_context[i]; + iface_context->hdd_ipa = hdd_ipa; + iface_context->cons_client = + hdd_ipa_adapter_2_client[i].cons_client; + iface_context->prod_client = + hdd_ipa_adapter_2_client[i].prod_client; + iface_context->iface_id = i; + iface_context->adapter = NULL; + } + for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) { + hdd_ipa->vdev_to_iface[i] = CSR_ROAM_SESSION_MAX; + hdd_ipa->vdev_offload_enabled[i] = false; + } + + if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) { + hdd_ipa->resource_loading = false; + hdd_ipa->resource_unloading = false; + hdd_ipa->sta_connected = 0; + hdd_ipa->ipa_pipes_down = true; + hdd_ipa->uc_loaded = true; + } + + return 0; +} + +/** + * hdd_ipa_uc_ssr_reinit() - SSR wrapper for __hdd_ipa_uc_ssr_reinit + * + * Init basic IPA UC host side to be in sync with reloaded FW after + * SSR to resume IPA UC operations + * + * Return: 0 - Success + */ +int hdd_ipa_uc_ssr_reinit(hdd_context_t *hdd_ctx) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __hdd_ipa_uc_ssr_reinit(hdd_ctx); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __hdd_ipa_tx_packet_ipa() - send packet to IPA + * @hdd_ctx: Global HDD context + * @skb: skb sent to IPA + * @session_id: send packet instance session id + * + * Send TX packet which generated by system to IPA. + * This routine only will be used for function verification + * + * Return: NULL packet sent to IPA properly + * NULL invalid packet drop + * skb packet not sent to IPA. legacy data path should handle + */ +static struct sk_buff *__hdd_ipa_tx_packet_ipa(hdd_context_t *hdd_ctx, + struct sk_buff *skb, uint8_t session_id) +{ + struct ipa_header *ipa_header; + struct frag_header *frag_header; + struct hdd_ipa_priv *hdd_ipa; + + if (wlan_hdd_validate_context(hdd_ctx)) + return skb; + + hdd_ipa = hdd_ctx->hdd_ipa; + + if (!hdd_ipa_uc_is_enabled(hdd_ctx)) + return skb; + + if (!hdd_ipa) + return skb; + + if (HDD_IPA_UC_NUM_WDI_PIPE != hdd_ipa->activated_fw_pipe) + return skb; + + if (skb_headroom(skb) < + (sizeof(struct ipa_header) + sizeof(struct frag_header))) + return skb; + + ipa_header = (struct ipa_header *) skb_push(skb, + sizeof(struct ipa_header)); + if (!ipa_header) { + /* No headroom, legacy */ + return skb; + } + memset(ipa_header, 0, sizeof(*ipa_header)); + ipa_header->vdev_id = 0; + + frag_header = (struct frag_header *) skb_push(skb, + sizeof(struct frag_header)); + if (!frag_header) { + /* No headroom, drop */ + kfree_skb(skb); + return NULL; + } + memset(frag_header, 0, sizeof(*frag_header)); + frag_header->length = skb->len - sizeof(struct frag_header) + - sizeof(struct ipa_header); + + ipa_tx_dp(IPA_CLIENT_WLAN1_CONS, skb, NULL); + return NULL; +} + +/** + * hdd_ipa_tx_packet_ipa() - SSR wrapper for __hdd_ipa_tx_packet_ipa + * @hdd_ctx: Global HDD context + * @skb: skb sent to IPA + * @session_id: send packet instance session id + * + * Send TX packet which generated by system to IPA. + * This routine only will be used for function verification + * + * Return: NULL packet sent to IPA properly + * NULL invalid packet drop + * skb packet not sent to IPA. legacy data path should handle + */ +struct sk_buff *hdd_ipa_tx_packet_ipa(hdd_context_t *hdd_ctx, + struct sk_buff *skb, uint8_t session_id) +{ + struct sk_buff *ret; + + cds_ssr_protect(__func__); + ret = __hdd_ipa_tx_packet_ipa(hdd_ctx, skb, session_id); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * hdd_ipa_wake_lock_timer_func() - Wake lock work handler + * @work: scheduled work + * + * When IPA resources are released in hdd_ipa_rm_try_release() we do + * not want to immediately release the wake lock since the system + * would then potentially try to suspend when there is a healthy data + * rate. Deferred work is scheduled and this function handles the + * work. When this function is called, if the IPA resource is still + * released then we release the wake lock. + * + * Return: None + */ +static void hdd_ipa_wake_lock_timer_func(struct work_struct *work) +{ + struct hdd_ipa_priv *hdd_ipa = container_of(to_delayed_work(work), + struct hdd_ipa_priv, + wake_lock_work); + + qdf_spin_lock_bh(&hdd_ipa->rm_lock); + + if (hdd_ipa->rm_state != HDD_IPA_RM_RELEASED) + goto end; + + hdd_ipa->wake_lock_released = true; + qdf_wake_lock_release(&hdd_ipa->wake_lock, + WIFI_POWER_EVENT_WAKELOCK_IPA); + +end: + qdf_spin_unlock_bh(&hdd_ipa->rm_lock); +} + +/** + * hdd_ipa_rm_request() - Request resource from IPA + * @hdd_ipa: Global HDD IPA context + * + * Return: 0 on success, negative errno on error + */ +static int hdd_ipa_rm_request(struct hdd_ipa_priv *hdd_ipa) +{ + int ret = 0; + + if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx)) + return 0; + + qdf_spin_lock_bh(&hdd_ipa->rm_lock); + + switch (hdd_ipa->rm_state) { + case HDD_IPA_RM_GRANTED: + qdf_spin_unlock_bh(&hdd_ipa->rm_lock); + return 0; + case HDD_IPA_RM_GRANT_PENDING: + qdf_spin_unlock_bh(&hdd_ipa->rm_lock); + return -EINPROGRESS; + case HDD_IPA_RM_RELEASED: + hdd_ipa->rm_state = HDD_IPA_RM_GRANT_PENDING; + break; + } + + qdf_spin_unlock_bh(&hdd_ipa->rm_lock); + + ret = ipa_rm_inactivity_timer_request_resource( + IPA_RM_RESOURCE_WLAN_PROD); + + qdf_spin_lock_bh(&hdd_ipa->rm_lock); + if (ret == 0) { + hdd_ipa->rm_state = HDD_IPA_RM_GRANTED; + hdd_ipa->stats.num_rm_grant_imm++; + } + + cancel_delayed_work(&hdd_ipa->wake_lock_work); + if (hdd_ipa->wake_lock_released) { + qdf_wake_lock_acquire(&hdd_ipa->wake_lock, + WIFI_POWER_EVENT_WAKELOCK_IPA); + hdd_ipa->wake_lock_released = false; + } + qdf_spin_unlock_bh(&hdd_ipa->rm_lock); + + return ret; +} + +/** + * hdd_ipa_rm_try_release() - Attempt to release IPA resource + * @hdd_ipa: Global HDD IPA context + * + * Return: 0 if resources released, negative errno otherwise + */ +static int hdd_ipa_rm_try_release(struct hdd_ipa_priv *hdd_ipa) +{ + int ret = 0; + + if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx)) + return 0; + + if (atomic_read(&hdd_ipa->tx_ref_cnt)) + return -EAGAIN; + + qdf_spin_lock_bh(&hdd_ipa->pm_lock); + + if (!qdf_nbuf_is_queue_empty(&hdd_ipa->pm_queue_head)) { + qdf_spin_unlock_bh(&hdd_ipa->pm_lock); + return -EAGAIN; + } + qdf_spin_unlock_bh(&hdd_ipa->pm_lock); + + qdf_spin_lock_bh(&hdd_ipa->rm_lock); + switch (hdd_ipa->rm_state) { + case HDD_IPA_RM_GRANTED: + break; + case HDD_IPA_RM_GRANT_PENDING: + qdf_spin_unlock_bh(&hdd_ipa->rm_lock); + return -EINPROGRESS; + case HDD_IPA_RM_RELEASED: + qdf_spin_unlock_bh(&hdd_ipa->rm_lock); + return 0; + } + + /* IPA driver returns immediately so set the state here to avoid any + * race condition. + */ + hdd_ipa->rm_state = HDD_IPA_RM_RELEASED; + hdd_ipa->stats.num_rm_release++; + qdf_spin_unlock_bh(&hdd_ipa->rm_lock); + + ret = + ipa_rm_inactivity_timer_release_resource(IPA_RM_RESOURCE_WLAN_PROD); + + qdf_spin_lock_bh(&hdd_ipa->rm_lock); + if (unlikely(ret != 0)) { + hdd_ipa->rm_state = HDD_IPA_RM_GRANTED; + WARN_ON(1); + } + + /* + * If wake_lock is released immediately, kernel would try to suspend + * immediately as well, Just avoid ping-pong between suspend-resume + * while there is healthy amount of data transfer going on by + * releasing the wake_lock after some delay. + */ + schedule_delayed_work(&hdd_ipa->wake_lock_work, + msecs_to_jiffies + (HDD_IPA_RX_INACTIVITY_MSEC_DELAY)); + + qdf_spin_unlock_bh(&hdd_ipa->rm_lock); + + return ret; +} + +/** + * hdd_ipa_rm_notify() - IPA resource manager notifier callback + * @user_data: user data registered with IPA + * @event: the IPA resource manager event that occurred + * @data: the data associated with the event + * + * Return: None + */ +static void hdd_ipa_rm_notify(void *user_data, enum ipa_rm_event event, + unsigned long data) +{ + struct hdd_ipa_priv *hdd_ipa = user_data; + + if (unlikely(!hdd_ipa)) + return; + + if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx)) + return; + + HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "Evt: %d", event); + + switch (event) { + case IPA_RM_RESOURCE_GRANTED: + if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) { + /* RM Notification comes with ISR context + * it should be serialized into work queue to avoid + * ISR sleep problem + */ + hdd_ipa->uc_rm_work.event = event; + schedule_work(&hdd_ipa->uc_rm_work.work); + break; + } + qdf_spin_lock_bh(&hdd_ipa->rm_lock); + hdd_ipa->rm_state = HDD_IPA_RM_GRANTED; + qdf_spin_unlock_bh(&hdd_ipa->rm_lock); + hdd_ipa->stats.num_rm_grant++; + break; + + case IPA_RM_RESOURCE_RELEASED: + HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "RM Release"); + hdd_ipa->resource_unloading = false; + break; + + default: + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Unknown RM Evt: %d", event); + break; + } +} + +/** + * hdd_ipa_rm_cons_release() - WLAN consumer resource release handler + * + * Callback function registered with IPA that is called when IPA wants + * to release the WLAN consumer resource + * + * Return: 0 if the request is granted, negative errno otherwise + */ +static int hdd_ipa_rm_cons_release(void) +{ + return 0; +} + +/** + * hdd_ipa_rm_cons_request() - WLAN consumer resource request handler + * + * Callback function registered with IPA that is called when IPA wants + * to access the WLAN consumer resource + * + * Return: 0 if the request is granted, negative errno otherwise + */ +static int hdd_ipa_rm_cons_request(void) +{ + int ret = 0; + + if (ghdd_ipa->resource_loading) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL, + "%s: IPA resource loading in progress", + __func__); + ghdd_ipa->pending_cons_req = true; + ret = -EINPROGRESS; + } else if (ghdd_ipa->resource_unloading) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL, + "%s: IPA resource unloading in progress", + __func__); + ghdd_ipa->pending_cons_req = true; + ret = -EPERM; + } + + return ret; +} + +/** + * __hdd_ipa_set_perf_level() - Set IPA performance level + * @hdd_ctx: Global HDD context + * @tx_packets: Number of packets transmitted in the last sample period + * @rx_packets: Number of packets received in the last sample period + * + * Return: 0 on success, negative errno on error + */ +static int __hdd_ipa_set_perf_level(hdd_context_t *hdd_ctx, uint64_t tx_packets, + uint64_t rx_packets) +{ + uint32_t next_cons_bw, next_prod_bw; + struct hdd_ipa_priv *hdd_ipa; + struct ipa_rm_perf_profile profile; + int ret; + + if (wlan_hdd_validate_context(hdd_ctx)) + return 0; + + hdd_ipa = hdd_ctx->hdd_ipa; + + if ((!hdd_ipa_is_enabled(hdd_ctx)) || + (!hdd_ipa_is_clk_scaling_enabled(hdd_ctx))) + return 0; + + memset(&profile, 0, sizeof(profile)); + + if (tx_packets > (hdd_ctx->config->busBandwidthHighThreshold / 2)) + next_cons_bw = hdd_ctx->config->IpaHighBandwidthMbps; + else if (tx_packets > + (hdd_ctx->config->busBandwidthMediumThreshold / 2)) + next_cons_bw = hdd_ctx->config->IpaMediumBandwidthMbps; + else + next_cons_bw = hdd_ctx->config->IpaLowBandwidthMbps; + + if (rx_packets > (hdd_ctx->config->busBandwidthHighThreshold / 2)) + next_prod_bw = hdd_ctx->config->IpaHighBandwidthMbps; + else if (rx_packets > + (hdd_ctx->config->busBandwidthMediumThreshold / 2)) + next_prod_bw = hdd_ctx->config->IpaMediumBandwidthMbps; + else + next_prod_bw = hdd_ctx->config->IpaLowBandwidthMbps; + + HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG, + "CONS perf curr: %d, next: %d", + hdd_ipa->curr_cons_bw, next_cons_bw); + HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_DEBUG, + "PROD perf curr: %d, next: %d", + hdd_ipa->curr_prod_bw, next_prod_bw); + + if (hdd_ipa->curr_cons_bw != next_cons_bw) { + hdd_debug("Requesting CONS perf curr: %d, next: %d", + hdd_ipa->curr_cons_bw, next_cons_bw); + profile.max_supported_bandwidth_mbps = next_cons_bw; + ret = ipa_rm_set_perf_profile(IPA_RM_RESOURCE_WLAN_CONS, + &profile); + if (ret) { + hdd_err("RM CONS set perf profile failed: %d", ret); + + return ret; + } + hdd_ipa->curr_cons_bw = next_cons_bw; + hdd_ipa->stats.num_cons_perf_req++; + } + + if (hdd_ipa->curr_prod_bw != next_prod_bw) { + hdd_debug("Requesting PROD perf curr: %d, next: %d", + hdd_ipa->curr_prod_bw, next_prod_bw); + profile.max_supported_bandwidth_mbps = next_prod_bw; + ret = ipa_rm_set_perf_profile(IPA_RM_RESOURCE_WLAN_PROD, + &profile); + if (ret) { + hdd_err("RM PROD set perf profile failed: %d", ret); + return ret; + } + hdd_ipa->curr_prod_bw = next_prod_bw; + hdd_ipa->stats.num_prod_perf_req++; + } + + return 0; +} + +/** + * hdd_ipa_set_perf_level() - SSR wrapper for __hdd_ipa_set_perf_level + * @hdd_ctx: Global HDD context + * @tx_packets: Number of packets transmitted in the last sample period + * @rx_packets: Number of packets received in the last sample period + * + * Return: 0 on success, negative errno on error + */ +int hdd_ipa_set_perf_level(hdd_context_t *hdd_ctx, uint64_t tx_packets, + uint64_t rx_packets) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __hdd_ipa_set_perf_level(hdd_ctx, tx_packets, rx_packets); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * hdd_ipa_init_uc_rm_work - init ipa uc resource manager work + * @work: struct work_struct + * @work_handler: work_handler + * + * Return: none + */ +static void hdd_ipa_init_uc_rm_work(struct work_struct *work, + work_func_t work_handler) +{ + INIT_WORK(work, work_handler); +} + +/** + * hdd_ipa_setup_rm() - Setup IPA resource management + * @hdd_ipa: Global HDD IPA context + * + * Return: 0 on success, negative errno on error + */ +static int hdd_ipa_setup_rm(struct hdd_ipa_priv *hdd_ipa) +{ + struct ipa_rm_create_params create_params = { 0 }; + int ret; + + if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx)) + return 0; + + hdd_ipa_init_uc_rm_work(&hdd_ipa->uc_rm_work.work, + hdd_ipa_uc_rm_notify_defer); + memset(&create_params, 0, sizeof(create_params)); + create_params.name = IPA_RM_RESOURCE_WLAN_PROD; + create_params.reg_params.user_data = hdd_ipa; + create_params.reg_params.notify_cb = hdd_ipa_rm_notify; + create_params.floor_voltage = IPA_VOLTAGE_SVS; + + ret = ipa_rm_create_resource(&create_params); + if (ret) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, + "Create RM resource failed: %d", ret); + goto setup_rm_fail; + } + + memset(&create_params, 0, sizeof(create_params)); + create_params.name = IPA_RM_RESOURCE_WLAN_CONS; + create_params.request_resource = hdd_ipa_rm_cons_request; + create_params.release_resource = hdd_ipa_rm_cons_release; + create_params.floor_voltage = IPA_VOLTAGE_SVS; + + ret = ipa_rm_create_resource(&create_params); + if (ret) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, + "Create RM CONS resource failed: %d", ret); + goto delete_prod; + } + + ipa_rm_add_dependency(IPA_RM_RESOURCE_WLAN_PROD, + IPA_RM_RESOURCE_APPS_CONS); + + ret = ipa_rm_inactivity_timer_init(IPA_RM_RESOURCE_WLAN_PROD, + HDD_IPA_RX_INACTIVITY_MSEC_DELAY); + if (ret) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Timer init failed: %d", + ret); + goto timer_init_failed; + } + + /* Set the lowest bandwidth to start with */ + ret = hdd_ipa_set_perf_level(hdd_ipa->hdd_ctx, 0, 0); + + if (ret) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, + "Set perf level failed: %d", ret); + goto set_perf_failed; + } + + qdf_wake_lock_create(&hdd_ipa->wake_lock, "wlan_ipa"); + INIT_DELAYED_WORK(&hdd_ipa->wake_lock_work, + hdd_ipa_wake_lock_timer_func); + qdf_spinlock_create(&hdd_ipa->rm_lock); + hdd_ipa->rm_state = HDD_IPA_RM_RELEASED; + hdd_ipa->wake_lock_released = true; + atomic_set(&hdd_ipa->tx_ref_cnt, 0); + + return ret; + +set_perf_failed: + ipa_rm_inactivity_timer_destroy(IPA_RM_RESOURCE_WLAN_PROD); + +timer_init_failed: + ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_CONS); + +delete_prod: + ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_PROD); + +setup_rm_fail: + return ret; +} + +/** + * hdd_ipa_destroy_rm_resource() - Destroy IPA resources + * @hdd_ipa: Global HDD IPA context + * + * Destroys all resources associated with the IPA resource manager + * + * Return: None + */ +static void hdd_ipa_destroy_rm_resource(struct hdd_ipa_priv *hdd_ipa) +{ + int ret; + + if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx)) + return; + + cancel_delayed_work_sync(&hdd_ipa->wake_lock_work); + qdf_wake_lock_destroy(&hdd_ipa->wake_lock); + cancel_work_sync(&hdd_ipa->uc_rm_work.work); + qdf_spinlock_destroy(&hdd_ipa->rm_lock); + + ipa_rm_inactivity_timer_destroy(IPA_RM_RESOURCE_WLAN_PROD); + + ret = ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_PROD); + if (ret) + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, + "RM PROD resource delete failed %d", ret); + + ret = ipa_rm_delete_resource(IPA_RM_RESOURCE_WLAN_CONS); + if (ret) + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, + "RM CONS resource delete failed %d", ret); +} + +/** + * hdd_ipa_send_skb_to_network() - Send skb to kernel + * @skb: network buffer + * @adapter: network adapter + * + * Called when a network buffer is received which should not be routed + * to the IPA module. + * + * Return: None + */ +static void hdd_ipa_send_skb_to_network(qdf_nbuf_t skb, + hdd_adapter_t *adapter) +{ + struct hdd_ipa_priv *hdd_ipa = ghdd_ipa; + unsigned int cpu_index; + + if (!adapter || adapter->magic != WLAN_HDD_ADAPTER_MAGIC) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO_LOW, "Invalid adapter: 0x%p", + adapter); + HDD_IPA_INCREASE_INTERNAL_DROP_COUNT(hdd_ipa); + kfree_skb(skb); + return; + } + + if (cds_is_driver_unloading()) { + HDD_IPA_INCREASE_INTERNAL_DROP_COUNT(hdd_ipa); + kfree_skb(skb); + return; + } + + skb->destructor = hdd_ipa_uc_rt_debug_destructor; + skb->dev = adapter->dev; + skb->protocol = eth_type_trans(skb, skb->dev); + skb->ip_summed = CHECKSUM_NONE; + + cpu_index = wlan_hdd_get_cpu(); + + ++adapter->hdd_stats.hddTxRxStats.rxPackets[cpu_index]; + if (netif_rx_ni(skb) == NET_RX_SUCCESS) + ++adapter->hdd_stats.hddTxRxStats.rxDelivered[cpu_index]; + else + ++adapter->hdd_stats.hddTxRxStats.rxRefused[cpu_index]; + + HDD_IPA_INCREASE_NET_SEND_COUNT(hdd_ipa); + adapter->dev->last_rx = jiffies; +} + +/** + * hdd_ipa_forward() - handle packet forwarding to wlan tx + * @hdd_ipa: pointer to hdd ipa context + * @adapter: network adapter + * @skb: data pointer + * + * if exception packet has set forward bit, copied new packet should be + * forwarded to wlan tx. if wlan subsystem is in suspend state, packet should + * put into pm queue and tx procedure will be differed + * + * Return: None + */ +static void hdd_ipa_forward(struct hdd_ipa_priv *hdd_ipa, + hdd_adapter_t *adapter, qdf_nbuf_t skb) +{ + struct hdd_ipa_pm_tx_cb *pm_tx_cb; + + qdf_spin_lock_bh(&hdd_ipa->pm_lock); + /* WLAN subsystem is in suspend, put int queue */ + if (hdd_ipa->suspended) { + qdf_spin_unlock_bh(&hdd_ipa->pm_lock); + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, + "TX in SUSPEND PUT QUEUE"); + qdf_mem_set(skb->cb, sizeof(skb->cb), 0); + pm_tx_cb = (struct hdd_ipa_pm_tx_cb *)skb->cb; + pm_tx_cb->exception = true; + pm_tx_cb->adapter = adapter; + qdf_spin_lock_bh(&hdd_ipa->pm_lock); + qdf_nbuf_queue_add(&hdd_ipa->pm_queue_head, skb); + qdf_spin_unlock_bh(&hdd_ipa->pm_lock); + hdd_ipa->stats.num_tx_queued++; + } else { + /* Resume, put packet into WLAN TX */ + qdf_spin_unlock_bh(&hdd_ipa->pm_lock); + if (hdd_softap_hard_start_xmit(skb, adapter->dev)) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, + "packet tx fail"); + hdd_ipa->stats.num_tx_fwd_err++; + } else { + hdd_ipa->stats.num_tx_fwd_ok++; + hdd_ipa->ipa_tx_forward++; + } + } +} + +/** + * hdd_ipa_intrabss_forward() - Forward intra bss packets. + * @hdd_ipa: pointer to HDD IPA struct + * @adapter: hdd adapter pointer + * @desc: Firmware descriptor + * @skb: Data buffer + * + * Return: + * HDD_IPA_FORWARD_PKT_NONE + * HDD_IPA_FORWARD_PKT_DISCARD + * HDD_IPA_FORWARD_PKT_LOCAL_STACK + * + */ + +static enum hdd_ipa_forward_type hdd_ipa_intrabss_forward( + struct hdd_ipa_priv *hdd_ipa, + hdd_adapter_t *adapter, + uint8_t desc, + qdf_nbuf_t skb) +{ + int ret = HDD_IPA_FORWARD_PKT_NONE; + + if ((desc & FW_RX_DESC_FORWARD_M)) { + if (!ol_txrx_fwd_desc_thresh_check( + ol_txrx_get_vdev_from_vdev_id(adapter->sessionId))) { + /* Drop the packet*/ + hdd_ipa->stats.num_tx_fwd_err++; + kfree_skb(skb); + ret = HDD_IPA_FORWARD_PKT_DISCARD; + return ret; + } + HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, + "Forward packet to Tx (fw_desc=%d)", desc); + hdd_ipa->ipa_tx_forward++; + + if ((desc & FW_RX_DESC_DISCARD_M)) { + hdd_ipa_forward(hdd_ipa, adapter, skb); + hdd_ipa->ipa_rx_internel_drop_count++; + hdd_ipa->ipa_rx_discard++; + ret = HDD_IPA_FORWARD_PKT_DISCARD; + } else { + struct sk_buff *cloned_skb = skb_clone(skb, GFP_ATOMIC); + if (cloned_skb) + hdd_ipa_forward(hdd_ipa, adapter, cloned_skb); + else + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, + "%s: tx skb alloc failed", + __func__); + ret = HDD_IPA_FORWARD_PKT_LOCAL_STACK; + } + } + + return ret; +} + +/** + * __hdd_ipa_w2i_cb() - WLAN to IPA callback handler + * @priv: pointer to private data registered with IPA (we register a + * pointer to the global IPA context) + * @evt: the IPA event which triggered the callback + * @data: data associated with the event + * + * Return: None + */ +static void __hdd_ipa_w2i_cb(void *priv, enum ipa_dp_evt_type evt, + unsigned long data) +{ + struct hdd_ipa_priv *hdd_ipa = NULL; + hdd_adapter_t *adapter = NULL; + qdf_nbuf_t skb; + uint8_t iface_id; + uint8_t session_id; + struct hdd_ipa_iface_context *iface_context; + uint8_t fw_desc; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + hdd_ipa = (struct hdd_ipa_priv *)priv; + + if (!hdd_ipa || wlan_hdd_validate_context(hdd_ipa->hdd_ctx)) + return; + + switch (evt) { + case IPA_RECEIVE: + skb = (qdf_nbuf_t) data; + + /* + * When SSR is going on or driver is unloading, + * just drop the packets. + */ + status = wlan_hdd_validate_context(hdd_ipa->hdd_ctx); + if (0 != status) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, + "Invalid context: drop packet"); + HDD_IPA_INCREASE_INTERNAL_DROP_COUNT(hdd_ipa); + kfree_skb(skb); + return; + } + + if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) { + session_id = (uint8_t)skb->cb[0]; + iface_id = hdd_ipa->vdev_to_iface[session_id]; + HDD_IPA_DP_LOG(QDF_TRACE_LEVEL_INFO_HIGH, + "IPA_RECEIVE: session_id=%u, iface_id=%u", + session_id, iface_id); + } else { + iface_id = HDD_IPA_GET_IFACE_ID(skb->data); + } + + if (iface_id >= HDD_IPA_MAX_IFACE) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, + "IPA_RECEIVE: Invalid iface_id: %u", + iface_id); + HDD_IPA_DBG_DUMP(QDF_TRACE_LEVEL_INFO_HIGH, + "w2i -- skb", + skb->data, HDD_IPA_DBG_DUMP_RX_LEN); + HDD_IPA_INCREASE_INTERNAL_DROP_COUNT(hdd_ipa); + kfree_skb(skb); + return; + } + + iface_context = &hdd_ipa->iface_context[iface_id]; + adapter = iface_context->adapter; + if (!adapter) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, + "IPA_RECEIVE: Adapter is NULL"); + HDD_IPA_INCREASE_INTERNAL_DROP_COUNT(hdd_ipa); + kfree_skb(skb); + return; + } + + HDD_IPA_DBG_DUMP(QDF_TRACE_LEVEL_DEBUG, + "w2i -- skb", + skb->data, HDD_IPA_DBG_DUMP_RX_LEN); + if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) { + hdd_ipa->stats.num_rx_excep++; + skb_pull(skb, HDD_IPA_UC_WLAN_CLD_HDR_LEN); + } else { + skb_pull(skb, HDD_IPA_WLAN_CLD_HDR_LEN); + } + + iface_context->stats.num_rx_ipa_excep++; + + /* Disable to forward Intra-BSS Rx packets when + * ap_isolate=1 in hostapd.conf + */ + if (!adapter->sessionCtx.ap.apDisableIntraBssFwd) { + /* + * When INTRA_BSS_FWD_OFFLOAD is enabled, FW will send + * all Rx packets to IPA uC, which need to be forwarded + * to other interface. + * And, IPA driver will send back to WLAN host driver + * through exception pipe with fw_desc field set by FW. + * Here we are checking fw_desc field for FORWARD bit + * set, and forward to Tx. Then copy to kernel stack + * only when DISCARD bit is not set. + */ + fw_desc = (uint8_t)skb->cb[1]; + if (HDD_IPA_FORWARD_PKT_DISCARD == + hdd_ipa_intrabss_forward(hdd_ipa, adapter, + fw_desc, skb)) + break; + } else { + HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO_HIGH, + "Intra-BSS FWD is disabled-skip forward to Tx"); + } + + hdd_ipa_send_skb_to_network(skb, adapter); + break; + + default: + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, + "w2i cb wrong event: 0x%x", evt); + return; + } +} + +/** + * hdd_ipa_w2i_cb() - SSR wrapper for __hdd_ipa_w2i_cb + * @priv: pointer to private data registered with IPA (we register a + * pointer to the global IPA context) + * @evt: the IPA event which triggered the callback + * @data: data associated with the event + * + * Return: None + */ +static void hdd_ipa_w2i_cb(void *priv, enum ipa_dp_evt_type evt, + unsigned long data) +{ + cds_ssr_protect(__func__); + __hdd_ipa_w2i_cb(priv, evt, data); + cds_ssr_unprotect(__func__); +} + +/** + * hdd_ipa_nbuf_cb() - IPA TX complete callback + * @skb: packet buffer which was transmitted + * + * Return: None + */ +void hdd_ipa_nbuf_cb(qdf_nbuf_t skb) +{ + struct hdd_ipa_priv *hdd_ipa = ghdd_ipa; + struct ipa_rx_data *ipa_tx_desc; + struct hdd_ipa_tx_desc *tx_desc; + uint16_t id; + + if (!qdf_nbuf_ipa_owned_get(skb)) { + dev_kfree_skb_any(skb); + return; + } + + /* Get Tx desc pointer from SKB CB */ + id = QDF_NBUF_CB_TX_IPA_PRIV(skb); + tx_desc = hdd_ipa->tx_desc_list + id; + ipa_tx_desc = tx_desc->ipa_tx_desc_ptr; + + /* Return Tx Desc to IPA */ + ipa_free_skb(ipa_tx_desc); + + /* Return to free tx desc list */ + qdf_spin_lock_bh(&hdd_ipa->q_lock); + tx_desc->ipa_tx_desc_ptr = NULL; + list_add_tail(&tx_desc->link, &hdd_ipa->free_tx_desc_head); + hdd_ipa->stats.num_tx_desc_q_cnt--; + qdf_spin_unlock_bh(&hdd_ipa->q_lock); + + hdd_ipa->stats.num_tx_comp_cnt++; + + atomic_dec(&hdd_ipa->tx_ref_cnt); + + hdd_ipa_rm_try_release(hdd_ipa); +} + +/** + * hdd_ipa_send_pkt_to_tl() - Send an IPA packet to TL + * @iface_context: interface-specific IPA context + * @ipa_tx_desc: packet data descriptor + * + * Return: None + */ +static void hdd_ipa_send_pkt_to_tl( + struct hdd_ipa_iface_context *iface_context, + struct ipa_rx_data *ipa_tx_desc) +{ + struct hdd_ipa_priv *hdd_ipa = iface_context->hdd_ipa; + hdd_adapter_t *adapter = NULL; + qdf_nbuf_t skb; + struct hdd_ipa_tx_desc *tx_desc; + + qdf_spin_lock_bh(&iface_context->interface_lock); + adapter = iface_context->adapter; + if (!adapter) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_WARN, "Interface Down"); + ipa_free_skb(ipa_tx_desc); + iface_context->stats.num_tx_drop++; + qdf_spin_unlock_bh(&iface_context->interface_lock); + hdd_ipa_rm_try_release(hdd_ipa); + return; + } + + /* + * During CAC period, data packets shouldn't be sent over the air so + * drop all the packets here + */ + if (WLAN_HDD_GET_AP_CTX_PTR(adapter)->dfs_cac_block_tx) { + ipa_free_skb(ipa_tx_desc); + qdf_spin_unlock_bh(&iface_context->interface_lock); + iface_context->stats.num_tx_cac_drop++; + hdd_ipa_rm_try_release(hdd_ipa); + return; + } + + ++adapter->stats.tx_packets; + + qdf_spin_unlock_bh(&iface_context->interface_lock); + + skb = ipa_tx_desc->skb; + + qdf_mem_set(skb->cb, sizeof(skb->cb), 0); + + /* Store IPA Tx buffer ownership into SKB CB */ + qdf_nbuf_ipa_owned_set(skb); + if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx)) { + qdf_nbuf_mapped_paddr_set(skb, + ipa_tx_desc->dma_addr + + HDD_IPA_WLAN_FRAG_HEADER + + HDD_IPA_WLAN_IPA_HEADER); + ipa_tx_desc->skb->len -= + HDD_IPA_WLAN_FRAG_HEADER + HDD_IPA_WLAN_IPA_HEADER; + } else + qdf_nbuf_mapped_paddr_set(skb, ipa_tx_desc->dma_addr); + + qdf_spin_lock_bh(&hdd_ipa->q_lock); + /* get free Tx desc and assign ipa_tx_desc pointer */ + if (!list_empty(&hdd_ipa->free_tx_desc_head)) { + tx_desc = list_first_entry(&hdd_ipa->free_tx_desc_head, + struct hdd_ipa_tx_desc, link); + list_del(&tx_desc->link); + tx_desc->ipa_tx_desc_ptr = ipa_tx_desc; + hdd_ipa->stats.num_tx_desc_q_cnt++; + qdf_spin_unlock_bh(&hdd_ipa->q_lock); + /* Store Tx Desc index into SKB CB */ + QDF_NBUF_CB_TX_IPA_PRIV(skb) = tx_desc->id; + } else { + hdd_ipa->stats.num_tx_desc_error++; + qdf_spin_unlock_bh(&hdd_ipa->q_lock); + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "No free Tx desc!"); + ipa_free_skb(ipa_tx_desc); + hdd_ipa_rm_try_release(hdd_ipa); + return; + } + + adapter->stats.tx_bytes += ipa_tx_desc->skb->len; + + skb = ol_tx_send_ipa_data_frame(iface_context->tl_context, + ipa_tx_desc->skb); + if (skb) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "TLSHIM tx fail"); + ipa_free_skb(ipa_tx_desc); + iface_context->stats.num_tx_err++; + hdd_ipa_rm_try_release(hdd_ipa); + return; + } + + atomic_inc(&hdd_ipa->tx_ref_cnt); + + iface_context->stats.num_tx++; +} + +/** + * hdd_ipa_is_present() - get IPA hw status + * @hdd_ctx: pointer to hdd context + * + * ipa_uc_reg_rdyCB is not directly designed to check + * ipa hw status. This is an undocumented function which + * has confirmed with IPA team. + * + * Return: true - ipa hw present + * false - ipa hw not present + */ +bool hdd_ipa_is_present(hdd_context_t *hdd_ctx) +{ + /* Check if ipa hw is enabled */ + if (HDD_IPA_CHECK_HW() != -EPERM) + return true; + else + return false; +} + +/** + * hdd_ipa_pm_flush() - flush queued packets + * @work: pointer to the scheduled work + * + * Called during PM resume to send packets to TL which were queued + * while host was in the process of suspending. + * + * Return: None + */ +static void hdd_ipa_pm_flush(struct work_struct *work) +{ + struct hdd_ipa_priv *hdd_ipa = container_of(work, + struct hdd_ipa_priv, + pm_work); + struct hdd_ipa_pm_tx_cb *pm_tx_cb = NULL; + qdf_nbuf_t skb; + uint32_t dequeued = 0; + + qdf_wake_lock_acquire(&hdd_ipa->wake_lock, + WIFI_POWER_EVENT_WAKELOCK_IPA); + qdf_spin_lock_bh(&hdd_ipa->pm_lock); + while (((skb = qdf_nbuf_queue_remove(&hdd_ipa->pm_queue_head)) + != NULL)) { + qdf_spin_unlock_bh(&hdd_ipa->pm_lock); + + pm_tx_cb = (struct hdd_ipa_pm_tx_cb *)skb->cb; + dequeued++; + if (pm_tx_cb->exception) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, + "FLUSH EXCEPTION"); + hdd_softap_hard_start_xmit(skb, pm_tx_cb->adapter->dev); + } else { + hdd_ipa_send_pkt_to_tl(pm_tx_cb->iface_context, + pm_tx_cb->ipa_tx_desc); + } + qdf_spin_lock_bh(&hdd_ipa->pm_lock); + } + qdf_spin_unlock_bh(&hdd_ipa->pm_lock); + qdf_wake_lock_release(&hdd_ipa->wake_lock, + WIFI_POWER_EVENT_WAKELOCK_IPA); + + hdd_ipa->stats.num_tx_dequeued += dequeued; + if (dequeued > hdd_ipa->stats.num_max_pm_queue) + hdd_ipa->stats.num_max_pm_queue = dequeued; +} + +/** + * __hdd_ipa_i2w_cb() - IPA to WLAN callback + * @priv: pointer to private data registered with IPA (we register a + * pointer to the interface-specific IPA context) + * @evt: the IPA event which triggered the callback + * @data: data associated with the event + * + * Return: None + */ +static void __hdd_ipa_i2w_cb(void *priv, enum ipa_dp_evt_type evt, + unsigned long data) +{ + struct hdd_ipa_priv *hdd_ipa = NULL; + struct ipa_rx_data *ipa_tx_desc; + struct hdd_ipa_iface_context *iface_context; + qdf_nbuf_t skb; + struct hdd_ipa_pm_tx_cb *pm_tx_cb = NULL; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + iface_context = (struct hdd_ipa_iface_context *)priv; + ipa_tx_desc = (struct ipa_rx_data *)data; + hdd_ipa = iface_context->hdd_ipa; + + if (evt != IPA_RECEIVE) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Event is not IPA_RECEIVE"); + ipa_free_skb(ipa_tx_desc); + iface_context->stats.num_tx_drop++; + return; + } + + /* + * When SSR is going on or driver is unloading, just drop the packets. + * During SSR, there is no use in queueing the packets as STA has to + * connect back any way + */ + status = wlan_hdd_validate_context(hdd_ipa->hdd_ctx); + if (status) { + ipa_free_skb(ipa_tx_desc); + iface_context->stats.num_tx_drop++; + return; + } + + skb = ipa_tx_desc->skb; + + HDD_IPA_DBG_DUMP(QDF_TRACE_LEVEL_DEBUG, + "i2w", skb->data, HDD_IPA_DBG_DUMP_TX_LEN); + + /* + * If PROD resource is not requested here then there may be cases where + * IPA hardware may be clocked down because of not having proper + * dependency graph between WLAN CONS and modem PROD pipes. Adding the + * workaround to request PROD resource while data is going over CONS + * pipe to prevent the IPA hardware clockdown. + */ + hdd_ipa_rm_request(hdd_ipa); + + qdf_spin_lock_bh(&hdd_ipa->pm_lock); + /* + * If host is still suspended then queue the packets and these will be + * drained later when resume completes. When packet is arrived here and + * host is suspended, this means that there is already resume is in + * progress. + */ + if (hdd_ipa->suspended) { + qdf_mem_set(skb->cb, sizeof(skb->cb), 0); + pm_tx_cb = (struct hdd_ipa_pm_tx_cb *)skb->cb; + pm_tx_cb->iface_context = iface_context; + pm_tx_cb->ipa_tx_desc = ipa_tx_desc; + qdf_nbuf_queue_add(&hdd_ipa->pm_queue_head, skb); + hdd_ipa->stats.num_tx_queued++; + + qdf_spin_unlock_bh(&hdd_ipa->pm_lock); + return; + } + + qdf_spin_unlock_bh(&hdd_ipa->pm_lock); + + /* + * If we are here means, host is not suspended, wait for the work queue + * to finish. + */ + flush_work(&hdd_ipa->pm_work); + + return hdd_ipa_send_pkt_to_tl(iface_context, ipa_tx_desc); +} + +/* + * hdd_ipa_i2w_cb() - SSR wrapper for __hdd_ipa_i2w_cb + * @priv: pointer to private data registered with IPA (we register a + * pointer to the interface-specific IPA context) + * @evt: the IPA event which triggered the callback + * @data: data associated with the event + * + * Return: None + */ +static void hdd_ipa_i2w_cb(void *priv, enum ipa_dp_evt_type evt, + unsigned long data) +{ + cds_ssr_protect(__func__); + __hdd_ipa_i2w_cb(priv, evt, data); + cds_ssr_unprotect(__func__); +} + +/** + * __hdd_ipa_suspend() - Suspend IPA + * @hdd_ctx: Global HDD context + * + * Return: 0 on success, negativer errno on error + */ +static int __hdd_ipa_suspend(hdd_context_t *hdd_ctx) +{ + struct hdd_ipa_priv *hdd_ipa; + + if (wlan_hdd_validate_context(hdd_ctx)) + return 0; + + hdd_ipa = hdd_ctx->hdd_ipa; + + if (!hdd_ipa_is_enabled(hdd_ctx)) + return 0; + + /* + * Check if IPA is ready for suspend, If we are here means, there is + * high chance that suspend would go through but just to avoid any race + * condition after suspend started, these checks are conducted before + * allowing to suspend. + */ + if (atomic_read(&hdd_ipa->tx_ref_cnt)) + return -EAGAIN; + + qdf_spin_lock_bh(&hdd_ipa->rm_lock); + + if (hdd_ipa->rm_state != HDD_IPA_RM_RELEASED) { + qdf_spin_unlock_bh(&hdd_ipa->rm_lock); + return -EAGAIN; + } + qdf_spin_unlock_bh(&hdd_ipa->rm_lock); + + qdf_spin_lock_bh(&hdd_ipa->pm_lock); + hdd_ipa->suspended = true; + qdf_spin_unlock_bh(&hdd_ipa->pm_lock); + + return 0; +} + +/** + * hdd_ipa_suspend() - SSR wrapper for __hdd_ipa_suspend + * @hdd_ctx: Global HDD context + * + * Return: 0 on success, negativer errno on error + */ +int hdd_ipa_suspend(hdd_context_t *hdd_ctx) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __hdd_ipa_suspend(hdd_ctx); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __hdd_ipa_resume() - Resume IPA following suspend + * hdd_ctx: Global HDD context + * + * Return: 0 on success, negative errno on error + */ +static int __hdd_ipa_resume(hdd_context_t *hdd_ctx) +{ + struct hdd_ipa_priv *hdd_ipa; + + if (wlan_hdd_validate_context(hdd_ctx)) + return 0; + + hdd_ipa = hdd_ctx->hdd_ipa; + + if (!hdd_ipa_is_enabled(hdd_ctx)) + return 0; + + schedule_work(&hdd_ipa->pm_work); + + qdf_spin_lock_bh(&hdd_ipa->pm_lock); + hdd_ipa->suspended = false; + qdf_spin_unlock_bh(&hdd_ipa->pm_lock); + + return 0; +} + +/** + * hdd_ipa_resume() - SSR wrapper for __hdd_ipa_resume + * hdd_ctx: Global HDD context + * + * Return: 0 on success, negative errno on error + */ +int hdd_ipa_resume(hdd_context_t *hdd_ctx) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __hdd_ipa_resume(hdd_ctx); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * hdd_ipa_alloc_tx_desc_list() - Allocate IPA Tx desc list + * @hdd_ipa: Global HDD IPA context + * + * Return: 0 on success, negative errno on error + */ +static int hdd_ipa_alloc_tx_desc_list(struct hdd_ipa_priv *hdd_ipa) +{ + int i; + uint32_t max_desc_cnt; + struct hdd_ipa_tx_desc *tmp_desc; + + max_desc_cnt = hdd_ipa->hdd_ctx->config->IpaUcTxBufCount; + + INIT_LIST_HEAD(&hdd_ipa->free_tx_desc_head); + + tmp_desc = qdf_mem_malloc(sizeof(struct hdd_ipa_tx_desc)*max_desc_cnt); + + if (!tmp_desc) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, + "Free Tx descriptor allocation failed"); + return -ENOMEM; + } + + hdd_ipa->tx_desc_list = tmp_desc; + + qdf_spin_lock_bh(&hdd_ipa->q_lock); + for (i = 0; i < max_desc_cnt; i++) { + tmp_desc->id = i; + tmp_desc->ipa_tx_desc_ptr = NULL; + list_add_tail(&tmp_desc->link, + &hdd_ipa->free_tx_desc_head); + tmp_desc++; + } + + hdd_ipa->stats.num_tx_desc_q_cnt = 0; + hdd_ipa->stats.num_tx_desc_error = 0; + + qdf_spin_unlock_bh(&hdd_ipa->q_lock); + + return 0; +} + +/** + * hdd_ipa_setup_sys_pipe() - Setup all IPA Sys pipes + * @hdd_ipa: Global HDD IPA context + * + * Return: 0 on success, negative errno on error + */ +static int hdd_ipa_setup_sys_pipe(struct hdd_ipa_priv *hdd_ipa) +{ + int i, ret = 0; + struct ipa_sys_connect_params *ipa; + uint32_t desc_fifo_sz; + + /* The maximum number of descriptors that can be provided to a BAM at + * once is one less than the total number of descriptors that the buffer + * can contain. + * If max_num_of_descriptors = (BAM_PIPE_DESCRIPTOR_FIFO_SIZE / sizeof + * (SPS_DESCRIPTOR)), then (max_num_of_descriptors - 1) descriptors can + * be provided at once. + * Because of above requirement, one extra descriptor will be added to + * make sure hardware always has one descriptor. + */ + desc_fifo_sz = hdd_ipa->hdd_ctx->config->IpaDescSize + + sizeof(struct sps_iovec); + + /*setup TX pipes */ + for (i = 0; i < HDD_IPA_MAX_IFACE; i++) { + ipa = &hdd_ipa->sys_pipe[i].ipa_sys_params; + + ipa->client = hdd_ipa_adapter_2_client[i].cons_client; + ipa->desc_fifo_sz = desc_fifo_sz; + ipa->priv = &hdd_ipa->iface_context[i]; + ipa->notify = hdd_ipa_i2w_cb; + + if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx)) { + ipa->ipa_ep_cfg.hdr.hdr_len = + HDD_IPA_UC_WLAN_TX_HDR_LEN; + ipa->ipa_ep_cfg.nat.nat_en = IPA_BYPASS_NAT; + ipa->ipa_ep_cfg.hdr.hdr_ofst_pkt_size_valid = 1; + ipa->ipa_ep_cfg.hdr.hdr_ofst_pkt_size = 0; + ipa->ipa_ep_cfg.hdr.hdr_additional_const_len = + HDD_IPA_UC_WLAN_8023_HDR_SIZE; + ipa->ipa_ep_cfg.hdr_ext.hdr_little_endian = true; + } else { + ipa->ipa_ep_cfg.hdr.hdr_len = HDD_IPA_WLAN_TX_HDR_LEN; + } + ipa->ipa_ep_cfg.mode.mode = IPA_BASIC; + + if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx)) + ipa->keep_ipa_awake = 1; + + ret = ipa_setup_sys_pipe(ipa, &(hdd_ipa->sys_pipe[i].conn_hdl)); + if (ret) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Failed for pipe %d" + " ret: %d", i, ret); + goto setup_sys_pipe_fail; + } + if (!hdd_ipa->sys_pipe[i].conn_hdl) + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Invalid conn handle sys_pipe: %d" + "conn handle: %d", i, hdd_ipa->sys_pipe[i].conn_hdl); + hdd_ipa->sys_pipe[i].conn_hdl_valid = 1; + } + + if (!hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx)) { + /* + * Hard code it here, this can be extended if in case + * PROD pipe is also per interface. + * Right now there is no advantage of doing this. + */ + hdd_ipa->prod_client = IPA_CLIENT_WLAN1_PROD; + + ipa = &hdd_ipa->sys_pipe[HDD_IPA_RX_PIPE].ipa_sys_params; + + ipa->client = hdd_ipa->prod_client; + + ipa->desc_fifo_sz = desc_fifo_sz; + ipa->priv = hdd_ipa; + ipa->notify = hdd_ipa_w2i_cb; + + ipa->ipa_ep_cfg.nat.nat_en = IPA_BYPASS_NAT; + ipa->ipa_ep_cfg.hdr.hdr_len = HDD_IPA_WLAN_RX_HDR_LEN; + ipa->ipa_ep_cfg.hdr.hdr_ofst_metadata_valid = 1; + ipa->ipa_ep_cfg.mode.mode = IPA_BASIC; + + if (!hdd_ipa_is_rm_enabled(hdd_ipa->hdd_ctx)) + ipa->keep_ipa_awake = 1; + + ret = ipa_setup_sys_pipe(ipa, &(hdd_ipa->sys_pipe[i].conn_hdl)); + if (ret) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, + "Failed for RX pipe: %d", ret); + goto setup_sys_pipe_fail; + } + if (!hdd_ipa->sys_pipe[i].conn_hdl) + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Invalid conn handle sys_pipe: %d" + "conn handle: %d", i, hdd_ipa->sys_pipe[i].conn_hdl); + hdd_ipa->sys_pipe[HDD_IPA_RX_PIPE].conn_hdl_valid = 1; + } + + /* Allocate free Tx desc list */ + ret = hdd_ipa_alloc_tx_desc_list(hdd_ipa); + if (ret) + goto setup_sys_pipe_fail; + + return ret; + +setup_sys_pipe_fail: + + while (--i >= 0) { + ipa_teardown_sys_pipe(hdd_ipa->sys_pipe[i].conn_hdl); + qdf_mem_zero(&hdd_ipa->sys_pipe[i], + sizeof(struct hdd_ipa_sys_pipe)); + } + + return ret; +} + +/** + * hdd_ipa_teardown_sys_pipe() - Tear down all IPA Sys pipes + * @hdd_ipa: Global HDD IPA context + * + * Return: None + */ +static void hdd_ipa_teardown_sys_pipe(struct hdd_ipa_priv *hdd_ipa) +{ + int ret = 0, i; + uint32_t max_desc_cnt; + struct hdd_ipa_tx_desc *tmp_desc; + struct ipa_rx_data *ipa_tx_desc; + + for (i = 0; i < HDD_IPA_MAX_SYSBAM_PIPE; i++) { + if (hdd_ipa->sys_pipe[i].conn_hdl_valid) { + ret = + ipa_teardown_sys_pipe(hdd_ipa->sys_pipe[i]. + conn_hdl); + if (ret) + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Failed: %d", + ret); + + hdd_ipa->sys_pipe[i].conn_hdl_valid = 0; + } + } + + if (hdd_ipa->tx_desc_list) { + max_desc_cnt = hdd_ipa->hdd_ctx->config->IpaUcTxBufCount; + + qdf_spin_lock_bh(&hdd_ipa->q_lock); + for (i = 0; i < max_desc_cnt; i++) { + tmp_desc = hdd_ipa->tx_desc_list + i; + ipa_tx_desc = tmp_desc->ipa_tx_desc_ptr; + if (ipa_tx_desc) + ipa_free_skb(ipa_tx_desc); + } + tmp_desc = hdd_ipa->tx_desc_list; + hdd_ipa->tx_desc_list = NULL; + hdd_ipa->stats.num_tx_desc_q_cnt = 0; + hdd_ipa->stats.num_tx_desc_error = 0; + qdf_spin_unlock_bh(&hdd_ipa->q_lock); + qdf_mem_free(tmp_desc); + } +} + +/** + * hdd_ipa_register_interface() - register IPA interface + * @hdd_ipa: Global IPA context + * @iface_context: Per-interface IPA context + * + * Return: 0 on success, negative errno on error + */ +static int hdd_ipa_register_interface(struct hdd_ipa_priv *hdd_ipa, + struct hdd_ipa_iface_context + *iface_context) +{ + struct ipa_tx_intf tx_intf; + struct ipa_rx_intf rx_intf; + struct ipa_ioc_tx_intf_prop *tx_prop = NULL; + struct ipa_ioc_rx_intf_prop *rx_prop = NULL; + char *ifname = iface_context->adapter->dev->name; + + char ipv4_hdr_name[IPA_RESOURCE_NAME_MAX]; + char ipv6_hdr_name[IPA_RESOURCE_NAME_MAX]; + + int num_prop = 1; + int ret = 0; + + if (hdd_ipa_is_ipv6_enabled(hdd_ipa->hdd_ctx)) + num_prop++; + + /* Allocate TX properties for TOS categories, 1 each for IPv4 & IPv6 */ + tx_prop = + qdf_mem_malloc(sizeof(struct ipa_ioc_tx_intf_prop) * num_prop); + if (!tx_prop) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "tx_prop allocation failed"); + goto register_interface_fail; + } + + /* Allocate RX properties, 1 each for IPv4 & IPv6 */ + rx_prop = + qdf_mem_malloc(sizeof(struct ipa_ioc_rx_intf_prop) * num_prop); + if (!rx_prop) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "rx_prop allocation failed"); + goto register_interface_fail; + } + + qdf_mem_zero(&tx_intf, sizeof(tx_intf)); + qdf_mem_zero(&rx_intf, sizeof(rx_intf)); + + snprintf(ipv4_hdr_name, IPA_RESOURCE_NAME_MAX, "%s%s", + ifname, HDD_IPA_IPV4_NAME_EXT); + snprintf(ipv6_hdr_name, IPA_RESOURCE_NAME_MAX, "%s%s", + ifname, HDD_IPA_IPV6_NAME_EXT); + + rx_prop[IPA_IP_v4].ip = IPA_IP_v4; + rx_prop[IPA_IP_v4].src_pipe = iface_context->prod_client; + rx_prop[IPA_IP_v4].hdr_l2_type = IPA_HDR_L2_ETHERNET_II; + rx_prop[IPA_IP_v4].attrib.attrib_mask = IPA_FLT_META_DATA; + + /* + * Interface ID is 3rd byte in the CLD header. Add the meta data and + * mask to identify the interface in IPA hardware + */ + rx_prop[IPA_IP_v4].attrib.meta_data = + htonl(iface_context->adapter->sessionId << 16); + rx_prop[IPA_IP_v4].attrib.meta_data_mask = htonl(0x00FF0000); + + rx_intf.num_props++; + if (hdd_ipa_is_ipv6_enabled(hdd_ipa->hdd_ctx)) { + rx_prop[IPA_IP_v6].ip = IPA_IP_v6; + rx_prop[IPA_IP_v6].src_pipe = iface_context->prod_client; + rx_prop[IPA_IP_v6].hdr_l2_type = IPA_HDR_L2_ETHERNET_II; + rx_prop[IPA_IP_v4].attrib.attrib_mask = IPA_FLT_META_DATA; + rx_prop[IPA_IP_v4].attrib.meta_data = + htonl(iface_context->adapter->sessionId << 16); + rx_prop[IPA_IP_v4].attrib.meta_data_mask = htonl(0x00FF0000); + + rx_intf.num_props++; + } + + tx_prop[IPA_IP_v4].ip = IPA_IP_v4; + tx_prop[IPA_IP_v4].hdr_l2_type = IPA_HDR_L2_ETHERNET_II; + tx_prop[IPA_IP_v4].dst_pipe = IPA_CLIENT_WLAN1_CONS; + tx_prop[IPA_IP_v4].alt_dst_pipe = iface_context->cons_client; + strlcpy(tx_prop[IPA_IP_v4].hdr_name, ipv4_hdr_name, + IPA_RESOURCE_NAME_MAX); + tx_intf.num_props++; + + if (hdd_ipa_is_ipv6_enabled(hdd_ipa->hdd_ctx)) { + tx_prop[IPA_IP_v6].ip = IPA_IP_v6; + tx_prop[IPA_IP_v6].hdr_l2_type = IPA_HDR_L2_ETHERNET_II; + tx_prop[IPA_IP_v6].dst_pipe = IPA_CLIENT_WLAN1_CONS; + tx_prop[IPA_IP_v6].alt_dst_pipe = iface_context->cons_client; + strlcpy(tx_prop[IPA_IP_v6].hdr_name, ipv6_hdr_name, + IPA_RESOURCE_NAME_MAX); + tx_intf.num_props++; + } + + tx_intf.prop = tx_prop; + rx_intf.prop = rx_prop; + + /* Call the ipa api to register interface */ + ret = ipa_register_intf(ifname, &tx_intf, &rx_intf); + + /* Register IPA Tx desc free callback */ + qdf_nbuf_reg_free_cb(hdd_ipa_nbuf_cb); + +register_interface_fail: + qdf_mem_free(tx_prop); + qdf_mem_free(rx_prop); + return ret; +} + +/** + * hdd_remove_ipa_header() - Remove a specific header from IPA + * @name: Name of the header to be removed + * + * Return: None + */ +static void hdd_ipa_remove_header(char *name) +{ + struct ipa_ioc_get_hdr hdrlookup; + int ret = 0, len; + struct ipa_ioc_del_hdr *ipa_hdr; + + qdf_mem_zero(&hdrlookup, sizeof(hdrlookup)); + strlcpy(hdrlookup.name, name, sizeof(hdrlookup.name)); + ret = ipa_get_hdr(&hdrlookup); + if (ret) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "Hdr deleted already %s, %d", + name, ret); + return; + } + + HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "hdl: 0x%x", hdrlookup.hdl); + len = sizeof(struct ipa_ioc_del_hdr) + sizeof(struct ipa_hdr_del) * 1; + ipa_hdr = (struct ipa_ioc_del_hdr *)qdf_mem_malloc(len); + if (ipa_hdr == NULL) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "ipa_hdr allocation failed"); + return; + } + ipa_hdr->num_hdls = 1; + ipa_hdr->commit = 0; + ipa_hdr->hdl[0].hdl = hdrlookup.hdl; + ipa_hdr->hdl[0].status = -1; + ret = ipa_del_hdr(ipa_hdr); + if (ret != 0) + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "Delete header failed: %d", + ret); + + qdf_mem_free(ipa_hdr); +} + +/** + * wlan_ipa_add_hdr() - Add IPA Tx header + * @ipa_hdr: pointer to IPA header addition parameters + * + * Call IPA API to add IPA Tx header descriptor + * and dump Tx header struct + * + * Return: 0 for success, non-zero for failure + */ +static int wlan_ipa_add_hdr(struct ipa_ioc_add_hdr *ipa_hdr) +{ + int ret; + + hdd_info("==== IPA Tx Header ====\n" + "name: %s\n" + "hdr_len: %d\n" + "type: %d\n" + "is_partial: %d\n" + "hdr_hdl: 0x%x\n" + "status: %d\n" + "is_eth2_ofst_valid: %d\n" + "eth2_ofst: %d\n", + ipa_hdr->hdr[0].name, + ipa_hdr->hdr[0].hdr_len, + ipa_hdr->hdr[0].type, + ipa_hdr->hdr[0].is_partial, + ipa_hdr->hdr[0].hdr_hdl, + ipa_hdr->hdr[0].status, + ipa_hdr->hdr[0].is_eth2_ofst_valid, + ipa_hdr->hdr[0].eth2_ofst); + + HDD_IPA_DBG_DUMP(QDF_TRACE_LEVEL_ERROR, "hdr:", + ipa_hdr->hdr[0].hdr, HDD_IPA_UC_WLAN_TX_HDR_LEN); + + ret = ipa_add_hdr(ipa_hdr); + return ret; +} + +/** + * hdd_ipa_add_header_info() - Add IPA header for a given interface + * @hdd_ipa: Global HDD IPA context + * @iface_context: Interface-specific HDD IPA context + * @mac_addr: Interface MAC address + * + * Return: 0 on success, negativer errno value on error + */ +static int hdd_ipa_add_header_info(struct hdd_ipa_priv *hdd_ipa, + struct hdd_ipa_iface_context *iface_context, + uint8_t *mac_addr) +{ + hdd_adapter_t *adapter = iface_context->adapter; + char *ifname; + struct ipa_ioc_add_hdr *ipa_hdr = NULL; + int ret = -EINVAL; + struct hdd_ipa_tx_hdr *tx_hdr = NULL; + struct hdd_ipa_uc_tx_hdr *uc_tx_hdr = NULL; + + ifname = adapter->dev->name; + + HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "Add Partial hdr: %s, %pM", + ifname, mac_addr); + + /* dynamically allocate the memory to add the hdrs */ + ipa_hdr = qdf_mem_malloc(sizeof(struct ipa_ioc_add_hdr) + + sizeof(struct ipa_hdr_add)); + if (!ipa_hdr) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, + "%s: ipa_hdr allocation failed", ifname); + ret = -ENOMEM; + goto end; + } + + ipa_hdr->commit = 0; + ipa_hdr->num_hdrs = 1; + + if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) { + uc_tx_hdr = (struct hdd_ipa_uc_tx_hdr *)ipa_hdr->hdr[0].hdr; + memcpy(uc_tx_hdr, &ipa_uc_tx_hdr, HDD_IPA_UC_WLAN_TX_HDR_LEN); + memcpy(uc_tx_hdr->eth.h_source, mac_addr, ETH_ALEN); + uc_tx_hdr->ipa_hd.vdev_id = iface_context->adapter->sessionId; + HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, + "ifname=%s, vdev_id=%d", + ifname, uc_tx_hdr->ipa_hd.vdev_id); + snprintf(ipa_hdr->hdr[0].name, IPA_RESOURCE_NAME_MAX, "%s%s", + ifname, HDD_IPA_IPV4_NAME_EXT); + ipa_hdr->hdr[0].hdr_len = HDD_IPA_UC_WLAN_TX_HDR_LEN; + ipa_hdr->hdr[0].type = IPA_HDR_L2_ETHERNET_II; + ipa_hdr->hdr[0].is_partial = 1; + ipa_hdr->hdr[0].hdr_hdl = 0; + ipa_hdr->hdr[0].is_eth2_ofst_valid = 1; + ipa_hdr->hdr[0].eth2_ofst = HDD_IPA_UC_WLAN_HDR_DES_MAC_OFFSET; + + ret = wlan_ipa_add_hdr(ipa_hdr); + } else { + tx_hdr = (struct hdd_ipa_tx_hdr *)ipa_hdr->hdr[0].hdr; + + /* Set the Source MAC */ + memcpy(tx_hdr, &ipa_tx_hdr, HDD_IPA_WLAN_TX_HDR_LEN); + memcpy(tx_hdr->eth.h_source, mac_addr, ETH_ALEN); + + snprintf(ipa_hdr->hdr[0].name, IPA_RESOURCE_NAME_MAX, "%s%s", + ifname, HDD_IPA_IPV4_NAME_EXT); + ipa_hdr->hdr[0].hdr_len = HDD_IPA_WLAN_TX_HDR_LEN; + ipa_hdr->hdr[0].is_partial = 1; + ipa_hdr->hdr[0].hdr_hdl = 0; + ipa_hdr->hdr[0].is_eth2_ofst_valid = 1; + ipa_hdr->hdr[0].eth2_ofst = HDD_IPA_WLAN_HDR_DES_MAC_OFFSET; + + /* Set the type to IPV4 in the header */ + tx_hdr->llc_snap.eth_type = cpu_to_be16(ETH_P_IP); + + ret = ipa_add_hdr(ipa_hdr); + } + if (ret) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "%s IPv4 add hdr failed: %d", + ifname, ret); + goto end; + } + + HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "%s: IPv4 hdr_hdl: 0x%x", + ipa_hdr->hdr[0].name, ipa_hdr->hdr[0].hdr_hdl); + + if (hdd_ipa_is_ipv6_enabled(hdd_ipa->hdd_ctx)) { + snprintf(ipa_hdr->hdr[0].name, IPA_RESOURCE_NAME_MAX, "%s%s", + ifname, HDD_IPA_IPV6_NAME_EXT); + + if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) { + uc_tx_hdr = + (struct hdd_ipa_uc_tx_hdr *)ipa_hdr->hdr[0].hdr; + uc_tx_hdr->eth.h_proto = cpu_to_be16(ETH_P_IPV6); + ret = wlan_ipa_add_hdr(ipa_hdr); + } else { + /* Set the type to IPV6 in the header */ + tx_hdr = (struct hdd_ipa_tx_hdr *)ipa_hdr->hdr[0].hdr; + tx_hdr->llc_snap.eth_type = cpu_to_be16(ETH_P_IPV6); + ret = ipa_add_hdr(ipa_hdr); + } + + if (ret) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, + "%s: IPv6 add hdr failed: %d", ifname, ret); + goto clean_ipv4_hdr; + } + + HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "%s: IPv6 hdr_hdl: 0x%x", + ipa_hdr->hdr[0].name, ipa_hdr->hdr[0].hdr_hdl); + } + + qdf_mem_free(ipa_hdr); + + return ret; + +clean_ipv4_hdr: + snprintf(ipa_hdr->hdr[0].name, IPA_RESOURCE_NAME_MAX, "%s%s", + ifname, HDD_IPA_IPV4_NAME_EXT); + hdd_ipa_remove_header(ipa_hdr->hdr[0].name); +end: + if (ipa_hdr) + qdf_mem_free(ipa_hdr); + + return ret; +} + +/** + * hdd_ipa_clean_hdr() - Cleanup IPA on a given adapter + * @adapter: Adapter upon which IPA was previously configured + * + * Return: None + */ +static void hdd_ipa_clean_hdr(hdd_adapter_t *adapter) +{ + struct hdd_ipa_priv *hdd_ipa = ghdd_ipa; + int ret; + char name_ipa[IPA_RESOURCE_NAME_MAX]; + + /* Remove the headers */ + snprintf(name_ipa, IPA_RESOURCE_NAME_MAX, "%s%s", + adapter->dev->name, HDD_IPA_IPV4_NAME_EXT); + hdd_ipa_remove_header(name_ipa); + + if (hdd_ipa_is_ipv6_enabled(hdd_ipa->hdd_ctx)) { + snprintf(name_ipa, IPA_RESOURCE_NAME_MAX, "%s%s", + adapter->dev->name, HDD_IPA_IPV6_NAME_EXT); + hdd_ipa_remove_header(name_ipa); + } + /* unregister the interface with IPA */ + ret = ipa_deregister_intf(adapter->dev->name); + if (ret) + HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, + "%s: ipa_deregister_intf fail: %d", + adapter->dev->name, ret); +} + +/** + * hdd_ipa_cleanup_iface() - Cleanup IPA on a given interface + * @iface_context: interface-specific IPA context + * + * Return: None + */ +static void hdd_ipa_cleanup_iface(struct hdd_ipa_iface_context *iface_context) +{ + if (iface_context == NULL) + return; + if (iface_context->adapter->magic != WLAN_HDD_ADAPTER_MAGIC) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, + "%s: bad adapter(%p).magic(%d)!", + __func__, iface_context->adapter, + iface_context->adapter->magic); + return; + } + + hdd_ipa_clean_hdr(iface_context->adapter); + + qdf_spin_lock_bh(&iface_context->interface_lock); + iface_context->adapter->ipa_context = NULL; + iface_context->adapter = NULL; + iface_context->tl_context = NULL; + qdf_spin_unlock_bh(&iface_context->interface_lock); + iface_context->ifa_address = 0; + if (!iface_context->hdd_ipa->num_iface) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, + "NUM INTF 0, Invalid"); + QDF_ASSERT(0); + } + iface_context->hdd_ipa->num_iface--; +} + +/** + * hdd_ipa_setup_iface() - Setup IPA on a given interface + * @hdd_ipa: HDD IPA global context + * @adapter: Interface upon which IPA is being setup + * @sta_id: Station ID of the API instance + * + * Return: 0 on success, negative errno value on error + */ +static int hdd_ipa_setup_iface(struct hdd_ipa_priv *hdd_ipa, + hdd_adapter_t *adapter, uint8_t sta_id) +{ + struct hdd_ipa_iface_context *iface_context = NULL; + void *tl_context = NULL; + int i, ret = 0; + + /* Lower layer may send multiple START_BSS_EVENT in DFS mode or during + * channel change indication. Since these indications are sent by lower + * layer as SAP updates and IPA doesn't have to do anything for these + * updates so ignoring! + */ + if (QDF_SAP_MODE == adapter->device_mode && adapter->ipa_context) + return 0; + + for (i = 0; i < HDD_IPA_MAX_IFACE; i++) { + if (hdd_ipa->iface_context[i].adapter == NULL) { + iface_context = &(hdd_ipa->iface_context[i]); + break; + } + } + + if (iface_context == NULL) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, + "All the IPA interfaces are in use"); + ret = -ENOMEM; + goto end; + } + + adapter->ipa_context = iface_context; + iface_context->adapter = adapter; + iface_context->sta_id = sta_id; + tl_context = ol_txrx_get_vdev_by_sta_id(sta_id); + + if (tl_context == NULL) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, + "Not able to get TL context sta_id: %d", sta_id); + ret = -EINVAL; + goto end; + } + + iface_context->tl_context = tl_context; + + ret = hdd_ipa_add_header_info(hdd_ipa, iface_context, + adapter->dev->dev_addr); + + if (ret) + goto end; + + /* Configure the TX and RX pipes filter rules */ + ret = hdd_ipa_register_interface(hdd_ipa, iface_context); + if (ret) + goto cleanup_header; + + hdd_ipa->num_iface++; + return ret; + +cleanup_header: + + hdd_ipa_clean_hdr(adapter); +end: + if (iface_context) + hdd_ipa_cleanup_iface(iface_context); + return ret; +} + +#ifndef QCA_LL_TX_FLOW_CONTROL_V2 +/** + * __hdd_ipa_send_mcc_scc_msg() - send IPA WLAN_SWITCH_TO_MCC/SCC message + * @mcc_mode: 0=MCC/1=SCC + * + * Return: 0 on success, negative errno value on error + */ +static int __hdd_ipa_send_mcc_scc_msg(hdd_context_t *hdd_ctx, bool mcc_mode) +{ + hdd_adapter_list_node_t *adapter_node = NULL, *next = NULL; + QDF_STATUS status; + hdd_adapter_t *pAdapter; + struct ipa_msg_meta meta; + struct ipa_wlan_msg *msg; + int ret; + + if (wlan_hdd_validate_context(hdd_ctx)) + return -EINVAL; + + if (!hdd_ipa_uc_sta_is_enabled(hdd_ctx)) + return -EINVAL; + + if (!hdd_ctx->mcc_mode) { + /* Flush TxRx queue for each adapter before switch to SCC */ + status = hdd_get_front_adapter(hdd_ctx, &adapter_node); + while (NULL != adapter_node && QDF_STATUS_SUCCESS == status) { + pAdapter = adapter_node->pAdapter; + if (pAdapter->device_mode == QDF_STA_MODE || + pAdapter->device_mode == QDF_SAP_MODE) { + hdd_info("MCC->SCC: Flush TxRx queue(d_mode=%d)", + pAdapter->device_mode); + hdd_deinit_tx_rx(pAdapter); + } + status = hdd_get_next_adapter( + hdd_ctx, adapter_node, &next); + adapter_node = next; + } + } + + /* Send SCC/MCC Switching event to IPA */ + meta.msg_len = sizeof(*msg); + msg = qdf_mem_malloc(meta.msg_len); + if (msg == NULL) { + hdd_err("msg allocation failed"); + return -ENOMEM; + } + + meta.msg_type = mcc_mode ? + WLAN_SWITCH_TO_MCC : WLAN_SWITCH_TO_SCC; + hdd_info("ipa_send_msg(Evt:%d)", meta.msg_type); + + ret = ipa_send_msg(&meta, msg, hdd_ipa_msg_free_fn); + + if (ret) { + hdd_err("ipa_send_msg(Evt:%d) - fail=%d", + meta.msg_type, ret); + qdf_mem_free(msg); + } + + return ret; +} + +/** + * hdd_ipa_send_mcc_scc_msg() - SSR wrapper for __hdd_ipa_send_mcc_scc_msg + * @mcc_mode: 0=MCC/1=SCC + * + * Return: 0 on success, negative errno value on error + */ +int hdd_ipa_send_mcc_scc_msg(hdd_context_t *hdd_ctx, bool mcc_mode) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __hdd_ipa_send_mcc_scc_msg(hdd_ctx, mcc_mode); + cds_ssr_unprotect(__func__); + + return ret; +} +#endif + +/** + * hdd_ipa_wlan_event_to_str() - convert IPA WLAN event to string + * @event: IPA WLAN event to be converted to a string + * + * Return: ASCII string representing the IPA WLAN event + */ +static inline char *hdd_ipa_wlan_event_to_str(enum ipa_wlan_event event) +{ + switch (event) { + case WLAN_CLIENT_CONNECT: + return "WLAN_CLIENT_CONNECT"; + case WLAN_CLIENT_DISCONNECT: + return "WLAN_CLIENT_DISCONNECT"; + case WLAN_CLIENT_POWER_SAVE_MODE: + return "WLAN_CLIENT_POWER_SAVE_MODE"; + case WLAN_CLIENT_NORMAL_MODE: + return "WLAN_CLIENT_NORMAL_MODE"; + case SW_ROUTING_ENABLE: + return "SW_ROUTING_ENABLE"; + case SW_ROUTING_DISABLE: + return "SW_ROUTING_DISABLE"; + case WLAN_AP_CONNECT: + return "WLAN_AP_CONNECT"; + case WLAN_AP_DISCONNECT: + return "WLAN_AP_DISCONNECT"; + case WLAN_STA_CONNECT: + return "WLAN_STA_CONNECT"; + case WLAN_STA_DISCONNECT: + return "WLAN_STA_DISCONNECT"; + case WLAN_CLIENT_CONNECT_EX: + return "WLAN_CLIENT_CONNECT_EX"; + + case IPA_WLAN_EVENT_MAX: + default: + return "UNKNOWN"; + } +} + +/** + * hdd_to_ipa_wlan_event() - convert hdd_ipa_wlan_event to ipa_wlan_event + * @hdd_ipa_event_type: HDD IPA WLAN event to be converted to an ipa_wlan_event + * + * Return: ipa_wlan_event representing the hdd_ipa_wlan_event + */ +static enum ipa_wlan_event +hdd_to_ipa_wlan_event(enum hdd_ipa_wlan_event hdd_ipa_event_type) +{ + enum ipa_wlan_event ipa_event; + + switch (hdd_ipa_event_type) { + case HDD_IPA_CLIENT_CONNECT: + ipa_event = WLAN_CLIENT_CONNECT; + break; + case HDD_IPA_CLIENT_DISCONNECT: + ipa_event = WLAN_CLIENT_DISCONNECT; + break; + case HDD_IPA_AP_CONNECT: + ipa_event = WLAN_AP_CONNECT; + break; + case HDD_IPA_AP_DISCONNECT: + ipa_event = WLAN_AP_DISCONNECT; + break; + case HDD_IPA_STA_CONNECT: + ipa_event = WLAN_STA_CONNECT; + break; + case HDD_IPA_STA_DISCONNECT: + ipa_event = WLAN_STA_DISCONNECT; + break; + case HDD_IPA_CLIENT_CONNECT_EX: + ipa_event = WLAN_CLIENT_CONNECT_EX; + break; + case HDD_IPA_WLAN_EVENT_MAX: + default: + ipa_event = IPA_WLAN_EVENT_MAX; + break; + } + return ipa_event; + +} + +/** + * __hdd_ipa_wlan_evt() - IPA event handler + * @adapter: adapter upon which the event was received + * @sta_id: station id for the event + * @type: event enum of type ipa_wlan_event + * @mac_address: MAC address associated with the event + * + * This function is meant to be called from within wlan_hdd_ipa.c + * + * Return: 0 on success, negative errno value on error + */ +static int __hdd_ipa_wlan_evt(hdd_adapter_t *adapter, uint8_t sta_id, + enum ipa_wlan_event type, uint8_t *mac_addr) +{ + struct hdd_ipa_priv *hdd_ipa = ghdd_ipa; + struct ipa_msg_meta meta; + struct ipa_wlan_msg *msg; + struct ipa_wlan_msg_ex *msg_ex = NULL; + int ret; + + HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "%s: %s evt, MAC: %pM sta_id: %d", + adapter->dev->name, hdd_ipa_wlan_event_to_str(type), + mac_addr, sta_id); + + if (type >= IPA_WLAN_EVENT_MAX) + return -EINVAL; + + if (WARN_ON(is_zero_ether_addr(mac_addr))) + return -EINVAL; + + if (!hdd_ipa || !hdd_ipa_is_enabled(hdd_ipa->hdd_ctx)) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "IPA OFFLOAD NOT ENABLED"); + return -EINVAL; + } + + if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx) && + !hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) && + (QDF_SAP_MODE != adapter->device_mode)) { + return 0; + } + + /* + * During IPA UC resource loading/unloading new events can be issued. + */ + if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx) && + (hdd_ipa->resource_loading || hdd_ipa->resource_unloading)) { + unsigned int pending_event_count; + struct ipa_uc_pending_event *pending_event = NULL; + + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, + "%s:IPA resource %s inprogress", + hdd_ipa_wlan_event_to_str(type), + hdd_ipa->resource_loading ? + "load" : "unload"); + + /* Wait until completion of the long/unloading */ + ret = wait_for_completion_timeout(&hdd_ipa->ipa_resource_comp, + msecs_to_jiffies(IPA_RESOURCE_COMP_WAIT_TIME)); + if (!ret) { + /* + * If timed out, store the events separately and + * handle them later. + */ + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, + "IPA resource %s timed out", + hdd_ipa->resource_loading ? + "load" : "unload"); + + if (hdd_ipa->resource_loading) { + qdf_mutex_acquire(&hdd_ipa->ipa_lock); + + pending_event_count = + qdf_list_size(&hdd_ipa->pending_event); + if (pending_event_count >= + HDD_IPA_MAX_PENDING_EVENT_COUNT) { + hdd_debug( + "Reached max pending event count"); + qdf_list_remove_front( + &hdd_ipa->pending_event, + (qdf_list_node_t **) + &pending_event); + } else { + pending_event = + (struct ipa_uc_pending_event *) + qdf_mem_malloc(sizeof( + struct ipa_uc_pending_event)); + } + + if (!pending_event) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, + "Pending event memory alloc fail"); + qdf_mutex_release(&hdd_ipa->ipa_lock); + return -ENOMEM; + } + + pending_event->adapter = adapter; + pending_event->sta_id = sta_id; + pending_event->type = type; + qdf_mem_copy(pending_event->mac_addr, + mac_addr, QDF_MAC_ADDR_SIZE); + qdf_list_insert_back(&hdd_ipa->pending_event, + &pending_event->node); + + qdf_mutex_release(&hdd_ipa->ipa_lock); + } + return 0; + } else { + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, + "IPA resource %s completed", + hdd_ipa->resource_loading ? + "load" : "unload"); + } + } + + hdd_ipa->stats.event[type]++; + + meta.msg_type = type; + switch (type) { + case WLAN_STA_CONNECT: + qdf_mutex_acquire(&hdd_ipa->event_lock); + + /* STA already connected and without disconnect, connect again + * This is Roaming scenario + */ + if (hdd_ipa->sta_connected) + hdd_ipa_cleanup_iface(adapter->ipa_context); + + ret = hdd_ipa_setup_iface(hdd_ipa, adapter, sta_id); + if (ret) { + qdf_mutex_release(&hdd_ipa->event_lock); + goto end; + } + + if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) && + (hdd_ipa->sap_num_connected_sta > 0) && + !hdd_ipa->sta_connected) { + qdf_mutex_release(&hdd_ipa->event_lock); + hdd_ipa_uc_offload_enable_disable(adapter, + SIR_STA_RX_DATA_OFFLOAD, true); + qdf_mutex_acquire(&hdd_ipa->event_lock); + } + + hdd_ipa->vdev_to_iface[adapter->sessionId] = + ((struct hdd_ipa_iface_context *) + (adapter->ipa_context))->iface_id; + + hdd_ipa->sta_connected = 1; + + qdf_mutex_release(&hdd_ipa->event_lock); + break; + + case WLAN_AP_CONNECT: + qdf_mutex_acquire(&hdd_ipa->event_lock); + + /* For DFS channel we get two start_bss event (before and after + * CAC). Also when ACS range includes both DFS and non DFS + * channels, we could possibly change channel many times due to + * RADAR detection and chosen channel may not be a DFS channels. + * So dont return error here. Just discard the event. + */ + if (adapter->ipa_context) { + qdf_mutex_release(&hdd_ipa->event_lock); + return 0; + } + + ret = hdd_ipa_setup_iface(hdd_ipa, adapter, sta_id); + if (ret) { + hdd_err("%s: Evt: %d, Interface setup failed", + msg_ex->name, meta.msg_type); + qdf_mutex_release(&hdd_ipa->event_lock); + goto end; + } + + if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) { + qdf_mutex_release(&hdd_ipa->event_lock); + hdd_ipa_uc_offload_enable_disable(adapter, + SIR_AP_RX_DATA_OFFLOAD, true); + qdf_mutex_acquire(&hdd_ipa->event_lock); + } + + hdd_ipa->vdev_to_iface[adapter->sessionId] = + ((struct hdd_ipa_iface_context *) + (adapter->ipa_context))->iface_id; + + qdf_mutex_release(&hdd_ipa->event_lock); + break; + + case WLAN_STA_DISCONNECT: + qdf_mutex_acquire(&hdd_ipa->event_lock); + + if (!hdd_ipa->sta_connected) { + hdd_err("%s: Evt: %d, STA already disconnected", + msg_ex->name, meta.msg_type); + qdf_mutex_release(&hdd_ipa->event_lock); + return -EINVAL; + } + + hdd_ipa->sta_connected = 0; + + if (!hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) { + hdd_notice("%s: IPA UC OFFLOAD NOT ENABLED", + msg_ex->name); + } else { + /* Disable IPA UC TX PIPE when STA disconnected */ + if (!hdd_ipa->num_iface && + (HDD_IPA_UC_NUM_WDI_PIPE == + hdd_ipa->activated_fw_pipe)) + hdd_ipa_uc_handle_last_discon(hdd_ipa); + } + + if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) && + (hdd_ipa->sap_num_connected_sta > 0)) { + qdf_mutex_release(&hdd_ipa->event_lock); + hdd_ipa_uc_offload_enable_disable(adapter, + SIR_STA_RX_DATA_OFFLOAD, false); + qdf_mutex_acquire(&hdd_ipa->event_lock); + hdd_ipa->vdev_to_iface[adapter->sessionId] = + CSR_ROAM_SESSION_MAX; + } + + hdd_ipa_cleanup_iface(adapter->ipa_context); + + qdf_mutex_release(&hdd_ipa->event_lock); + break; + + case WLAN_AP_DISCONNECT: + qdf_mutex_acquire(&hdd_ipa->event_lock); + + if (!adapter->ipa_context) { + hdd_err("%s: Evt: %d, SAP already disconnected", + msg_ex->name, meta.msg_type); + qdf_mutex_release(&hdd_ipa->event_lock); + return -EINVAL; + } + + if ((!hdd_ipa->num_iface) && + (HDD_IPA_UC_NUM_WDI_PIPE == + hdd_ipa->activated_fw_pipe)) { + if (cds_is_driver_unloading()) { + /* + * We disable WDI pipes directly here since + * IPA_OPCODE_TX/RX_SUSPEND message will not be + * processed when unloading WLAN driver is in + * progress + */ + hdd_ipa_uc_disable_pipes(hdd_ipa); + } else { + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, + "NO INTF left but still pipe clean up"); + hdd_ipa_uc_handle_last_discon(hdd_ipa); + } + } + + if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) { + qdf_mutex_release(&hdd_ipa->event_lock); + hdd_ipa_uc_offload_enable_disable(adapter, + SIR_AP_RX_DATA_OFFLOAD, false); + qdf_mutex_acquire(&hdd_ipa->event_lock); + hdd_ipa->vdev_to_iface[adapter->sessionId] = + CSR_ROAM_SESSION_MAX; + } + + hdd_ipa_cleanup_iface(adapter->ipa_context); + + qdf_mutex_release(&hdd_ipa->event_lock); + break; + + case WLAN_CLIENT_CONNECT_EX: + if (!hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, + "%s: Evt: %d, IPA UC OFFLOAD NOT ENABLED", + adapter->dev->name, type); + return 0; + } + + qdf_mutex_acquire(&hdd_ipa->event_lock); + if (hdd_ipa_uc_find_add_assoc_sta(hdd_ipa, + true, sta_id)) { + qdf_mutex_release(&hdd_ipa->event_lock); + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, + "%s: STA ID %d found, not valid", + adapter->dev->name, sta_id); + return 0; + } + + /* Enable IPA UC Data PIPEs when first STA connected */ + if (hdd_ipa->sap_num_connected_sta == 0 && + hdd_ipa->uc_loaded == true) { + if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) && + hdd_ipa->sta_connected) { + qdf_mutex_release(&hdd_ipa->event_lock); + hdd_ipa_uc_offload_enable_disable( + hdd_get_adapter(hdd_ipa->hdd_ctx, + QDF_STA_MODE), + SIR_STA_RX_DATA_OFFLOAD, true); + qdf_mutex_acquire(&hdd_ipa->event_lock); + } + + ret = hdd_ipa_uc_handle_first_con(hdd_ipa); + if (ret) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, + "%s: handle 1st con ret %d", + adapter->dev->name, ret); + + if (hdd_ipa_uc_sta_is_enabled( + hdd_ipa->hdd_ctx) && + hdd_ipa->sta_connected) { + qdf_mutex_release(&hdd_ipa->event_lock); + hdd_ipa_uc_offload_enable_disable( + hdd_get_adapter( + hdd_ipa->hdd_ctx, + QDF_STA_MODE), + SIR_STA_RX_DATA_OFFLOAD, false); + } else { + qdf_mutex_release(&hdd_ipa->event_lock); + } + + return ret; + } + } + + hdd_ipa->sap_num_connected_sta++; + + qdf_mutex_release(&hdd_ipa->event_lock); + + meta.msg_type = type; + meta.msg_len = (sizeof(struct ipa_wlan_msg_ex) + + sizeof(struct ipa_wlan_hdr_attrib_val)); + msg_ex = qdf_mem_malloc(meta.msg_len); + + if (msg_ex == NULL) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, + "msg_ex allocation failed"); + return -ENOMEM; + } + strlcpy(msg_ex->name, adapter->dev->name, + IPA_RESOURCE_NAME_MAX); + msg_ex->num_of_attribs = 1; + msg_ex->attribs[0].attrib_type = WLAN_HDR_ATTRIB_MAC_ADDR; + if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) { + msg_ex->attribs[0].offset = + HDD_IPA_UC_WLAN_HDR_DES_MAC_OFFSET; + } else { + msg_ex->attribs[0].offset = + HDD_IPA_WLAN_HDR_DES_MAC_OFFSET; + } + memcpy(msg_ex->attribs[0].u.mac_addr, mac_addr, + IPA_MAC_ADDR_SIZE); + + ret = ipa_send_msg(&meta, msg_ex, hdd_ipa_msg_free_fn); + + if (ret) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "%s: Evt: %d : %d", + adapter->dev->name, type, ret); + qdf_mem_free(msg_ex); + return ret; + } + hdd_ipa->stats.num_send_msg++; + return ret; + + case WLAN_CLIENT_DISCONNECT: + if (!hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, + "%s: IPA UC OFFLOAD NOT ENABLED", + msg_ex->name); + return 0; + } + qdf_mutex_acquire(&hdd_ipa->event_lock); + if (!hdd_ipa_uc_find_add_assoc_sta(hdd_ipa, false, sta_id)) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, + "%s: STA ID %d NOT found, not valid", + msg_ex->name, sta_id); + qdf_mutex_release(&hdd_ipa->event_lock); + return 0; + } + hdd_ipa->sap_num_connected_sta--; + + /* Disable IPA UC TX PIPE when last STA disconnected */ + if (!hdd_ipa->sap_num_connected_sta && + hdd_ipa->uc_loaded == true) { + if ((false == hdd_ipa->resource_unloading) + && (HDD_IPA_UC_NUM_WDI_PIPE == + hdd_ipa->activated_fw_pipe)) { + hdd_ipa_uc_handle_last_discon(hdd_ipa); + } + + qdf_mutex_release(&hdd_ipa->event_lock); + + if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx) && + hdd_ipa->sta_connected) + hdd_ipa_uc_offload_enable_disable( + hdd_get_adapter(hdd_ipa->hdd_ctx, + QDF_STA_MODE), + SIR_STA_RX_DATA_OFFLOAD, false); + } else { + qdf_mutex_release(&hdd_ipa->event_lock); + } + break; + + default: + return 0; + } + + meta.msg_len = sizeof(struct ipa_wlan_msg); + msg = qdf_mem_malloc(meta.msg_len); + if (msg == NULL) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, "msg allocation failed"); + return -ENOMEM; + } + + meta.msg_type = type; + strlcpy(msg->name, adapter->dev->name, IPA_RESOURCE_NAME_MAX); + memcpy(msg->mac_addr, mac_addr, ETH_ALEN); + + HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, "%s: Evt: %d", + msg->name, meta.msg_type); + + ret = ipa_send_msg(&meta, msg, hdd_ipa_msg_free_fn); + + if (ret) { + hdd_err("%s: Evt: %d fail:%d", + msg->name, meta.msg_type, ret); + qdf_mem_free(msg); + return ret; + } + + hdd_ipa->stats.num_send_msg++; + +end: + return ret; +} + +/** + * hdd_ipa_wlan_evt() - SSR wrapper for __hdd_ipa_wlan_evt + * @adapter: adapter upon which the event was received + * @sta_id: station id for the event + * @hdd_event_type: event enum of type hdd_ipa_wlan_event + * @mac_address: MAC address associated with the event + * + * This function is meant to be called from outside of wlan_hdd_ipa.c. + * + * Return: 0 on success, negative errno value on error + */ +int hdd_ipa_wlan_evt(hdd_adapter_t *adapter, uint8_t sta_id, + enum hdd_ipa_wlan_event hdd_event_type, uint8_t *mac_addr) +{ + enum ipa_wlan_event type = hdd_to_ipa_wlan_event(hdd_event_type); + int ret = 0; + + cds_ssr_protect(__func__); + + /* Data path offload only support for STA and SAP mode */ + if ((QDF_STA_MODE == adapter->device_mode) || + (QDF_SAP_MODE == adapter->device_mode)) + ret = __hdd_ipa_wlan_evt(adapter, sta_id, type, mac_addr); + + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * hdd_ipa_uc_proc_pending_event() - Process IPA uC pending events + * @hdd_ipa: Global HDD IPA context + * + * Return: None + */ +static void +hdd_ipa_uc_proc_pending_event(struct hdd_ipa_priv *hdd_ipa) +{ + unsigned int pending_event_count; + struct ipa_uc_pending_event *pending_event = NULL; + + pending_event_count = qdf_list_size(&hdd_ipa->pending_event); + HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, + "%s, Pending Event Count %d", __func__, pending_event_count); + if (!pending_event_count) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_INFO, + "%s, No Pending Event", __func__); + return; + } + + qdf_list_remove_front(&hdd_ipa->pending_event, + (qdf_list_node_t **)&pending_event); + while (pending_event != NULL) { + __hdd_ipa_wlan_evt(pending_event->adapter, + pending_event->type, + pending_event->sta_id, + pending_event->mac_addr); + qdf_mem_free(pending_event); + pending_event = NULL; + qdf_list_remove_front(&hdd_ipa->pending_event, + (qdf_list_node_t **)&pending_event); + } +} + +/** + * hdd_ipa_rm_state_to_str() - Convert IPA RM state to string + * @state: IPA RM state value + * + * Return: ASCII string representing the IPA RM state + */ +static inline char *hdd_ipa_rm_state_to_str(enum hdd_ipa_rm_state state) +{ + switch (state) { + case HDD_IPA_RM_RELEASED: + return "RELEASED"; + case HDD_IPA_RM_GRANT_PENDING: + return "GRANT_PENDING"; + case HDD_IPA_RM_GRANTED: + return "GRANTED"; + } + + return "UNKNOWN"; +} + +/** + * __hdd_ipa_init() - IPA initialization function + * @hdd_ctx: HDD global context + * + * Allocate hdd_ipa resources, ipa pipe resource and register + * wlan interface with IPA module. + * + * Return: QDF_STATUS enumeration + */ +static QDF_STATUS __hdd_ipa_init(hdd_context_t *hdd_ctx) +{ + struct hdd_ipa_priv *hdd_ipa = NULL; + int ret, i; + struct hdd_ipa_iface_context *iface_context = NULL; + struct ol_txrx_pdev_t *pdev = NULL; + + if (!hdd_ipa_is_enabled(hdd_ctx)) + return QDF_STATUS_SUCCESS; + + ENTER(); + + pdev = cds_get_context(QDF_MODULE_ID_TXRX); + if (!pdev) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL, "pdev is NULL"); + goto fail_return; + } + + hdd_ipa = qdf_mem_malloc(sizeof(*hdd_ipa)); + if (!hdd_ipa) { + HDD_IPA_LOG(QDF_TRACE_LEVEL_FATAL, "hdd_ipa allocation failed"); + goto fail_return; + } + + hdd_ctx->hdd_ipa = hdd_ipa; + ghdd_ipa = hdd_ipa; + hdd_ipa->hdd_ctx = hdd_ctx; + hdd_ipa->num_iface = 0; + + /* Create the interface context */ + for (i = 0; i < HDD_IPA_MAX_IFACE; i++) { + iface_context = &hdd_ipa->iface_context[i]; + iface_context->hdd_ipa = hdd_ipa; + iface_context->cons_client = + hdd_ipa_adapter_2_client[i].cons_client; + iface_context->prod_client = + hdd_ipa_adapter_2_client[i].prod_client; + iface_context->iface_id = i; + iface_context->adapter = NULL; + qdf_spinlock_create(&iface_context->interface_lock); + } + for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) { + hdd_ipa->vdev_to_iface[i] = CSR_ROAM_SESSION_MAX; + hdd_ipa->vdev_offload_enabled[i] = false; + } + + INIT_WORK(&hdd_ipa->pm_work, hdd_ipa_pm_flush); + qdf_spinlock_create(&hdd_ipa->pm_lock); + qdf_spinlock_create(&hdd_ipa->q_lock); + qdf_nbuf_queue_init(&hdd_ipa->pm_queue_head); + qdf_list_create(&hdd_ipa->pending_event, 1000); + qdf_mutex_create(&hdd_ipa->event_lock); + qdf_mutex_create(&hdd_ipa->ipa_lock); + + ret = hdd_ipa_setup_rm(hdd_ipa); + if (ret) + goto fail_setup_rm; + + if (hdd_ipa_uc_is_enabled(hdd_ipa->hdd_ctx)) { + hdd_ipa_uc_rt_debug_init(hdd_ctx); + qdf_mem_zero(&hdd_ipa->stats, sizeof(hdd_ipa->stats)); + hdd_ipa->sap_num_connected_sta = 0; + hdd_ipa->ipa_tx_packets_diff = 0; + hdd_ipa->ipa_rx_packets_diff = 0; + hdd_ipa->ipa_p_tx_packets = 0; + hdd_ipa->ipa_p_rx_packets = 0; + hdd_ipa->resource_loading = false; + hdd_ipa->resource_unloading = false; + hdd_ipa->sta_connected = 0; + hdd_ipa->ipa_pipes_down = true; + /* Setup IPA sys_pipe for MCC */ + if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx)) { + ret = hdd_ipa_setup_sys_pipe(hdd_ipa); + if (ret) + goto fail_create_sys_pipe; + } + if (hdd_ipa_uc_register_uc_ready(hdd_ipa)) + goto fail_create_sys_pipe; + + for (i = 0; i < HDD_IPA_UC_OPCODE_MAX; i++) { + hdd_ipa_init_uc_op_work(&hdd_ipa->uc_op_work[i].work, + hdd_ipa_uc_fw_op_event_handler); + hdd_ipa->uc_op_work[i].msg = NULL; + } + } else { + ret = hdd_ipa_setup_sys_pipe(hdd_ipa); + if (ret) + goto fail_create_sys_pipe; + } + + init_completion(&hdd_ipa->ipa_resource_comp); + + EXIT(); + return QDF_STATUS_SUCCESS; + +fail_create_sys_pipe: + hdd_ipa_destroy_rm_resource(hdd_ipa); +fail_setup_rm: + qdf_spinlock_destroy(&hdd_ipa->pm_lock); + qdf_mem_free(hdd_ipa); + hdd_ctx->hdd_ipa = NULL; + ghdd_ipa = NULL; +fail_return: + EXIT(); + return QDF_STATUS_E_FAILURE; +} + +/** + * hdd_ipa_init() - SSR wrapper for __hdd_ipa_init + * @hdd_ctx: HDD global context + * + * Allocate hdd_ipa resources, ipa pipe resource and register + * wlan interface with IPA module. + * + * Return: QDF_STATUS enumeration + */ +QDF_STATUS hdd_ipa_init(hdd_context_t *hdd_ctx) +{ + QDF_STATUS ret; + + cds_ssr_protect(__func__); + ret = __hdd_ipa_init(hdd_ctx); + cds_ssr_unprotect(__func__); + + return ret; +} + + +/** + * hdd_ipa_cleanup_pending_event() - Cleanup IPA pending event list + * @hdd_ipa: pointer to HDD IPA struct + * + * Return: none + */ +static void hdd_ipa_cleanup_pending_event(struct hdd_ipa_priv *hdd_ipa) +{ + struct ipa_uc_pending_event *pending_event = NULL; + + while (qdf_list_remove_front(&hdd_ipa->pending_event, + (qdf_list_node_t **)&pending_event) == QDF_STATUS_SUCCESS) { + qdf_mem_free(pending_event); + } + + qdf_list_destroy(&hdd_ipa->pending_event); +} + +/** + * __hdd_ipa_cleanup - IPA cleanup function + * @hdd_ctx: HDD global context + * + * Return: QDF_STATUS enumeration + */ +static QDF_STATUS __hdd_ipa_cleanup(hdd_context_t *hdd_ctx) +{ + struct hdd_ipa_priv *hdd_ipa = hdd_ctx->hdd_ipa; + int i; + struct hdd_ipa_iface_context *iface_context = NULL; + qdf_nbuf_t skb; + struct hdd_ipa_pm_tx_cb *pm_tx_cb = NULL; + + if (!hdd_ipa_is_enabled(hdd_ctx)) + return QDF_STATUS_SUCCESS; + + if (!hdd_ipa_uc_is_enabled(hdd_ctx)) { + unregister_inetaddr_notifier(&hdd_ipa->ipv4_notifier); + hdd_ipa_teardown_sys_pipe(hdd_ipa); + } + + /* Teardown IPA sys_pipe for MCC */ + if (hdd_ipa_uc_sta_is_enabled(hdd_ipa->hdd_ctx)) + hdd_ipa_teardown_sys_pipe(hdd_ipa); + + hdd_ipa_destroy_rm_resource(hdd_ipa); + + cancel_work_sync(&hdd_ipa->pm_work); + qdf_spin_lock_bh(&hdd_ipa->pm_lock); + + while (((skb = qdf_nbuf_queue_remove(&hdd_ipa->pm_queue_head)) + != NULL)) { + qdf_spin_unlock_bh(&hdd_ipa->pm_lock); + + pm_tx_cb = (struct hdd_ipa_pm_tx_cb *)skb->cb; + if (pm_tx_cb->ipa_tx_desc) + ipa_free_skb(pm_tx_cb->ipa_tx_desc); + + qdf_spin_lock_bh(&hdd_ipa->pm_lock); + } + qdf_spin_unlock_bh(&hdd_ipa->pm_lock); + + qdf_spinlock_destroy(&hdd_ipa->pm_lock); + qdf_spinlock_destroy(&hdd_ipa->q_lock); + + /* destory the interface lock */ + for (i = 0; i < HDD_IPA_MAX_IFACE; i++) { + iface_context = &hdd_ipa->iface_context[i]; + qdf_spinlock_destroy(&iface_context->interface_lock); + } + + if (hdd_ipa_uc_is_enabled(hdd_ctx)) { + if (ipa_uc_dereg_rdyCB()) + HDD_IPA_LOG(QDF_TRACE_LEVEL_ERROR, + "UC Ready CB deregister fail"); + hdd_ipa_uc_rt_debug_deinit(hdd_ctx); + qdf_mutex_destroy(&hdd_ipa->event_lock); + qdf_mutex_destroy(&hdd_ipa->ipa_lock); + hdd_ipa_cleanup_pending_event(hdd_ipa); + + for (i = 0; i < HDD_IPA_UC_OPCODE_MAX; i++) { + cancel_work_sync(&hdd_ipa->uc_op_work[i].work); + hdd_ipa->uc_op_work[i].msg = NULL; + } + } + + qdf_mem_free(hdd_ipa); + hdd_ctx->hdd_ipa = NULL; + + return QDF_STATUS_SUCCESS; +} + +/** + * hdd_ipa_cleanup - SSR wrapper for __hdd_ipa_cleanup + * @hdd_ctx: HDD global context + * + * Return: QDF_STATUS enumeration + */ +QDF_STATUS hdd_ipa_cleanup(hdd_context_t *hdd_ctx) +{ + QDF_STATUS ret; + + cds_ssr_protect(__func__); + ret = __hdd_ipa_cleanup(hdd_ctx); + cds_ssr_unprotect(__func__); + + return ret; +} +#endif /* IPA_OFFLOAD */ diff --git a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_lpass.c b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_lpass.c new file mode 100644 index 0000000000000000000000000000000000000000..2642c224d2c5ea84d232bce2b433242ba5de90d8 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_lpass.c @@ -0,0 +1,360 @@ +/* + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: wlan_hdd_lpass.c + * + * WLAN Host Device Driver LPASS feature implementation + * + */ + +/* Include Files */ +#include "wlan_hdd_main.h" +#include "wlan_hdd_lpass.h" +#include +#include "qwlan_version.h" + +/** + * wlan_hdd_gen_wlan_status_pack() - Create lpass adapter status package + * @data: Status data record to be created + * @adapter: Adapter whose status is to being packaged + * @sta_ctx: Station-specific context of @adapter + * @is_on: Is wlan driver loaded? + * @is_connected: Is @adapater connected to an AP? + * + * Generate a wlan vdev status package. The status info includes wlan + * on/off status, vdev ID, vdev mode, supported channels, etc. + * + * Return: 0 if package was created, otherwise a negative errno + */ +static int wlan_hdd_gen_wlan_status_pack(struct wlan_status_data *data, + hdd_adapter_t *adapter, + hdd_station_ctx_t *sta_ctx, + uint8_t is_on, uint8_t is_connected) +{ + hdd_context_t *hdd_ctx = NULL; + uint8_t buflen = WLAN_SVC_COUNTRY_CODE_LEN; + + if (!data) { + hdd_err("invalid data pointer"); + return -EINVAL; + } + if (!adapter) { + if (is_on) { + /* no active interface */ + data->lpss_support = 0; + data->is_on = is_on; + return 0; + } + hdd_err("invalid adapter pointer"); + return -EINVAL; + } + + if (wlan_hdd_validate_session_id(adapter->sessionId)) { + hdd_err("invalid session id: %d", adapter->sessionId); + return -EINVAL; + } + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + if (hdd_ctx->lpss_support && hdd_ctx->config->enable_lpass_support) + data->lpss_support = 1; + else + data->lpss_support = 0; + data->numChannels = WLAN_SVC_MAX_NUM_CHAN; + sme_get_cfg_valid_channels(hdd_ctx->hHal, data->channel_list, + &data->numChannels); + sme_get_country_code(hdd_ctx->hHal, data->country_code, &buflen); + data->is_on = is_on; + data->vdev_id = adapter->sessionId; + data->vdev_mode = adapter->device_mode; + if (sta_ctx) { + data->is_connected = is_connected; + data->rssi = adapter->rssi; + data->freq = + cds_chan_to_freq(sta_ctx->conn_info.operationChannel); + if (WLAN_SVC_MAX_SSID_LEN >= + sta_ctx->conn_info.SSID.SSID.length) { + data->ssid_len = sta_ctx->conn_info.SSID.SSID.length; + memcpy(data->ssid, + sta_ctx->conn_info.SSID.SSID.ssId, + sta_ctx->conn_info.SSID.SSID.length); + } + if (QDF_MAC_ADDR_SIZE >= sizeof(sta_ctx->conn_info.bssId)) + memcpy(data->bssid, sta_ctx->conn_info.bssId.bytes, + QDF_MAC_ADDR_SIZE); + } + return 0; +} + +/** + * wlan_hdd_gen_wlan_version_pack() - Create lpass version package + * @data: Version data record to be created + * @fw_version: Version code from firmware + * @chip_id: WLAN chip ID + * @chip_name: WLAN chip name + * + * Generate a wlan software/hw version info package. The version info + * includes wlan host driver version, wlan fw driver version, wlan hw + * chip id & wlan hw chip name. + * + * Return: 0 if package was created, otherwise a negative errno + */ +static int wlan_hdd_gen_wlan_version_pack(struct wlan_version_data *data, + uint32_t fw_version, + uint32_t chip_id, + const char *chip_name) +{ + if (!data) { + hdd_err("invalid data pointer"); + return -EINVAL; + } + + data->chip_id = chip_id; + strlcpy(data->chip_name, chip_name, WLAN_SVC_MAX_STR_LEN); + if (strncmp(chip_name, "Unknown", 7)) + strlcpy(data->chip_from, "Qualcomm", WLAN_SVC_MAX_STR_LEN); + else + strlcpy(data->chip_from, "Unknown", WLAN_SVC_MAX_STR_LEN); + strlcpy(data->host_version, QWLAN_VERSIONSTR, WLAN_SVC_MAX_STR_LEN); + scnprintf(data->fw_version, WLAN_SVC_MAX_STR_LEN, "%d.%d.%d.%d", + (fw_version & 0xf0000000) >> 28, + (fw_version & 0xf000000) >> 24, + (fw_version & 0xf00000) >> 20, (fw_version & 0x7fff)); + return 0; +} + +/** + * wlan_hdd_send_status_pkg() - Send adapter status to lpass + * @adapter: Adapter whose status is to be sent to lpass + * @sta_ctx: Station-specific context of @adapter + * @is_on: Is @adapter enabled + * @is_connected: Is @adapater connected + * + * Generate wlan vdev status pacakge and send it to a user space + * daemon through netlink. + * + * Return: none + */ +static void wlan_hdd_send_status_pkg(struct hdd_adapter_s *adapter, + struct hdd_station_ctx *sta_ctx, + uint8_t is_on, uint8_t is_connected) +{ + int ret = 0; + struct wlan_status_data data; + hdd_context_t *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + + if (!hdd_ctx) + return; + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) + return; + + memset(&data, 0, sizeof(struct wlan_status_data)); + if (is_on) + ret = wlan_hdd_gen_wlan_status_pack(&data, adapter, sta_ctx, + is_on, is_connected); + + if (!ret) + wlan_hdd_send_svc_nlink_msg(hdd_ctx->radio_index, + WLAN_SVC_WLAN_STATUS_IND, + &data, sizeof(data)); +} + +/** + * wlan_hdd_send_version_pkg() - report version information to lpass + * @fw_version: Version code from firmware + * @chip_id: WLAN chip ID + * @chip_name: WLAN chip name + * + * Generate a wlan sw/hw version info package and send it to a user + * space daemon through netlink. + * + * Return: none + */ +static void wlan_hdd_send_version_pkg(uint32_t fw_version, + uint32_t chip_id, + const char *chip_name) +{ + int ret = 0; + struct wlan_version_data data; + hdd_context_t *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + + if (!hdd_ctx) + return; + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) + return; + + memset(&data, 0, sizeof(struct wlan_version_data)); + ret = wlan_hdd_gen_wlan_version_pack(&data, fw_version, chip_id, + chip_name); + if (!ret) + wlan_hdd_send_svc_nlink_msg(hdd_ctx->radio_index, + WLAN_SVC_WLAN_VERSION_IND, + &data, sizeof(data)); +} + +/** + * wlan_hdd_send_all_scan_intf_info() - report scan interfaces to lpass + * @hdd_ctx: The global HDD context + * + * This function iterates through all of the interfaces registered + * with HDD and indicates to lpass all that support scanning. + * If no interfaces support scanning then that fact is also indicated. + * + * Return: none + */ +static void wlan_hdd_send_all_scan_intf_info(struct hdd_context_s *hdd_ctx) +{ + hdd_adapter_t *adapter = NULL; + hdd_adapter_list_node_t *node = NULL, *next = NULL; + bool scan_intf_found = false; + QDF_STATUS status; + + if (!hdd_ctx) { + hdd_err("NULL pointer for hdd_ctx"); + return; + } + + status = hdd_get_front_adapter(hdd_ctx, &node); + while (NULL != node && QDF_STATUS_SUCCESS == status) { + adapter = node->pAdapter; + if (adapter) { + if (adapter->device_mode == QDF_STA_MODE + || adapter->device_mode == QDF_P2P_CLIENT_MODE + || adapter->device_mode == + QDF_P2P_DEVICE_MODE) { + scan_intf_found = true; + wlan_hdd_send_status_pkg(adapter, NULL, 1, 0); + } + } + status = hdd_get_next_adapter(hdd_ctx, node, &next); + node = next; + } + + if (!scan_intf_found) + wlan_hdd_send_status_pkg(adapter, NULL, 1, 0); +} + +/* + * hdd_lpass_target_config() - Handle LPASS target configuration + * (public function documented in wlan_hdd_lpass.h) + */ +void hdd_lpass_target_config(struct hdd_context_s *hdd_ctx, + struct wma_tgt_cfg *target_config) +{ + hdd_ctx->lpss_support = target_config->lpss_support; +} + +/* + * hdd_lpass_populate_cds_config() - Populate LPASS configuration + * (public function documented in wlan_hdd_lpass.h) + */ +void hdd_lpass_populate_cds_config(struct cds_config_info *cds_config, + struct hdd_context_s *hdd_ctx) +{ + cds_config->is_lpass_enabled = hdd_ctx->config->enable_lpass_support; +} + +/* + * hdd_lpass_notify_connect() - Notify LPASS of interface connect + * (public function documented in wlan_hdd_lpass.h) + */ +void hdd_lpass_notify_connect(struct hdd_adapter_s *adapter) +{ + struct hdd_station_ctx *sta_ctx; + + /* only send once per connection */ + if (adapter->rssi_send) + return; + + /* don't send if driver is unloading */ + if (cds_is_driver_unloading()) + return; + + adapter->rssi_send = true; + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + wlan_hdd_send_status_pkg(adapter, sta_ctx, 1, 1); +} + +/* + * hdd_lpass_notify_disconnect() - Notify LPASS of interface disconnect + * (public function documented in wlan_hdd_lpass.h) + */ +void hdd_lpass_notify_disconnect(struct hdd_adapter_s *adapter) +{ + struct hdd_station_ctx *sta_ctx; + + adapter->rssi_send = false; + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + wlan_hdd_send_status_pkg(adapter, sta_ctx, 1, 0); +} + +/* + * hdd_lpass_notify_mode_change() - Notify LPASS of interface mode change + * (public function documented in wlan_hdd_lpass.h) + * + * implementation note: when one interfaces changes we notify the + * state of all of the interfaces. + */ +void hdd_lpass_notify_mode_change(struct hdd_adapter_s *adapter) +{ + struct hdd_context_s *hdd_ctx; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + wlan_hdd_send_all_scan_intf_info(hdd_ctx); +} + +/* + * hdd_lpass_notify_start() - Notify LPASS of driver start + * (public function documented in wlan_hdd_lpass.h) + */ +void hdd_lpass_notify_start(struct hdd_context_s *hdd_ctx) +{ + wlan_hdd_send_all_scan_intf_info(hdd_ctx); + wlan_hdd_send_version_pkg(hdd_ctx->target_fw_version, + hdd_ctx->target_hw_version, + hdd_ctx->target_hw_name); +} + +/* + * hdd_lpass_notify_stop() - Notify LPASS of driver stop + * (public function documented in wlan_hdd_lpass.h) + */ +void hdd_lpass_notify_stop(struct hdd_context_s *hdd_ctx) +{ + wlan_hdd_send_status_pkg(NULL, NULL, 0, 0); +} + +/* + * hdd_lpass_is_supported() - Is lpass feature supported? + * (public function documented in wlan_hdd_lpass.h) + */ +bool hdd_lpass_is_supported(struct hdd_context_s *hdd_ctx) +{ + return hdd_ctx->config->enable_lpass_support; +} diff --git a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_lpass.h b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_lpass.h new file mode 100644 index 0000000000000000000000000000000000000000..8ecc3e782df2ef639b21fdd15ac8f046cbe6277f --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_lpass.h @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#if !defined(WLAN_HDD_LPASS_H) +#define WLAN_HDD_LPASS_H + +struct cds_config_info; +struct wma_tgt_cfg; +struct hdd_context_s; +struct hdd_adapter_s; + +#ifdef WLAN_FEATURE_LPSS +/** + * hdd_lpass_target_config() - Handle LPASS target configuration + * @hdd_ctx: HDD global context where lpass information is stored + * @target_config: Target configuration containing lpass info + * + * This function updates the HDD context with lpass-specific + * information provided by the target. + * + * Return: none + */ +void hdd_lpass_target_config(struct hdd_context_s *hdd_ctx, + struct wma_tgt_cfg *target_config); + +/** + * hdd_lpass_populate_cds_config() - Populate LPASS configuration + * @cds_config: CDS configuration to populate with lpass info + * @hdd_ctx: HDD global context which contains lpass information + * + * This function seeds the CDS configuration structure with + * lpass-specific information gleaned from the HDD context. + * + * Return: none + */ +void hdd_lpass_populate_cds_config(struct cds_config_info *cds_config, + struct hdd_context_s *hdd_ctx); + +/** + * hdd_lpass_notify_connect() - Notify LPASS of interface connect + * @adapter: The adapter that connected + * + * This function is used to notify the LPASS feature that an adapter + * has connected. + * + * Return: none + */ +void hdd_lpass_notify_connect(struct hdd_adapter_s *adapter); + +/** + * hdd_lpass_notify_disconnect() - Notify LPASS of interface disconnect + * @adapter: The adapter that connected + * + * This function is used to notify the LPASS feature that an adapter + * has disconnected. + * + * Return: none + */ +void hdd_lpass_notify_disconnect(struct hdd_adapter_s *adapter); + +/** + * hdd_lpass_notify_mode_change() - Notify LPASS of interface mode change + * @adapter: The adapter whose mode was changed + * + * This function is used to notify the LPASS feature that an adapter + * had its mode changed. + * + * Return: none + */ +void hdd_lpass_notify_mode_change(struct hdd_adapter_s *adapter); + +/** + * hdd_lpass_notify_start() - Notify LPASS of driver start + * @hdd_ctx: The global HDD context + * + * This function is used to notify the LPASS feature that the wlan + * driver has (re-)started. + * + * Return: none + */ +void hdd_lpass_notify_start(struct hdd_context_s *hdd_ctx); + +/** + * hdd_lpass_notify_stop() - Notify LPASS of driver stop + * @hdd_ctx: The global HDD context + * + * This function is used to notify the LPASS feature that the wlan + * driver has stopped. + * + * Return: none + */ +void hdd_lpass_notify_stop(struct hdd_context_s *hdd_ctx); + +/** + * hdd_lpass_is_supported() - Is lpass feature supported? + * @hdd_ctx: The global HDD context + * + * Return: true if feature is enabled and supported by firmware, false + * if the feature is not enabled or not supported by firmware. + */ +bool hdd_lpass_is_supported(struct hdd_context_s *hdd_ctx); + +#else +static inline void hdd_lpass_target_config(struct hdd_context_s *hdd_ctx, + struct wma_tgt_cfg *target_config) +{ +} +static inline +void hdd_lpass_populate_cds_config(struct cds_config_info *cds_config, + struct hdd_context_s *hdd_ctx) +{ +} +static inline void hdd_lpass_notify_connect(struct hdd_adapter_s *adapter) +{ +} +static inline void hdd_lpass_notify_disconnect(struct hdd_adapter_s *adapter) +{ +} +static inline void hdd_lpass_notify_mode_change(struct hdd_adapter_s *adapter) +{ +} +static inline void hdd_lpass_notify_start(struct hdd_context_s *hdd_ctx) { } +static inline void hdd_lpass_notify_stop(struct hdd_context_s *hdd_ctx) { } +static inline bool hdd_lpass_is_supported(struct hdd_context_s *hdd_ctx) +{ + return false; +} +#endif + +#endif /* WLAN_HDD_LPASS_H */ diff --git a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_lro.c b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_lro.c new file mode 100644 index 0000000000000000000000000000000000000000..62d527f93b54bdd77d539d351dac713cb595ba03 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_lro.c @@ -0,0 +1,773 @@ +/* + * Copyright (c) 2015-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: wlan_hdd_lro.c + * + * WLAN HDD LRO interface implementation + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#define LRO_MAX_AGGR_SIZE 100 + +#define LRO_VALID_FIELDS \ + (LRO_DESC | LRO_ELIGIBILITY_CHECKED | LRO_TCP_ACK_NUM | \ + LRO_TCP_DATA_CSUM | LRO_TCP_SEQ_NUM | LRO_TCP_WIN) + +/** + * hdd_lro_get_skb_header() - LRO callback function + * @skb: network buffer + * @ip_hdr: contains a pointer to the IP header + * @tcpudp_hdr: contains a pointer to the TCP header + * @hdr_flags: indicates if this is a TCP, IPV4 frame + * @priv: private driver specific opaque pointer + * + * Get the IP and TCP headers from the skb + * + * Return: 0 - success, < 0 - failure + */ +static int hdd_lro_get_skb_header(struct sk_buff *skb, void **ip_hdr, + void **tcpudp_hdr, u64 *hdr_flags, void *priv) +{ + if (QDF_NBUF_CB_RX_IPV6_PROTO(skb)) { + hdr_flags = 0; + return -EINVAL; + } + + *hdr_flags |= (LRO_IPV4 | LRO_TCP); + (*ip_hdr) = skb->data; + (*tcpudp_hdr) = skb->data + QDF_NBUF_CB_RX_TCP_OFFSET(skb); + return 0; +} + +/** + * hdd_lro_desc_pool_init() - Initialize the free pool of LRO + * descriptors + * @lro_desc_pool: free pool of the LRO descriptors + * @lro_mgr: LRO manager + * + * Initialize a list that holds the free LRO descriptors + * + * Return: none + */ +static void hdd_lro_desc_pool_init(struct hdd_lro_desc_pool *lro_desc_pool, + struct net_lro_mgr *lro_mgr) +{ + int i; + + INIT_LIST_HEAD(&lro_desc_pool->lro_free_list_head); + + for (i = 0; i < LRO_DESC_POOL_SZ; i++) { + lro_desc_pool->lro_desc_array[i].lro_desc = + &lro_mgr->lro_arr[i]; + list_add_tail(&lro_desc_pool->lro_desc_array[i].lro_node, + &lro_desc_pool->lro_free_list_head); + } +} + +/** + * hdd_lro_desc_info_init() - Initialize the LRO descriptors + * @hdd_info: HDD LRO data structure + * + * Initialize the free pool of LRO descriptors and the entries + * of the hash table + * + * Return: none + */ +static void hdd_lro_desc_info_init(struct hdd_lro_s *hdd_info) +{ + int i; + + /* Initialize pool of free LRO desc.*/ + hdd_lro_desc_pool_init(&hdd_info->lro_desc_info.lro_desc_pool, + hdd_info->lro_mgr); + + /* Initialize the hash table of LRO desc.*/ + for (i = 0; i < LRO_DESC_TABLE_SZ; i++) { + /* initialize the flows in the hash table */ + INIT_LIST_HEAD(&hdd_info->lro_desc_info. + lro_hash_table[i].lro_desc_list); + } + +} + +/** + * hdd_lro_tcp_flow_match() - function to check for a flow match + * @iph: IP header + * @tcph: TCP header + * @lro_desc: LRO decriptor + * + * Checks if the descriptor belongs to the same flow as the one + * indicated by the TCP and IP header. + * + * Return: true - flow match, false - flow does not match + */ +static inline bool hdd_lro_tcp_flow_match(struct net_lro_desc *lro_desc, + struct iphdr *iph, + struct tcphdr *tcph) +{ + if ((lro_desc->tcph->source != tcph->source) || + (lro_desc->tcph->dest != tcph->dest) || + (lro_desc->iph->saddr != iph->saddr) || + (lro_desc->iph->daddr != iph->daddr)) + return false; + + return true; + +} + +/** + * hdd_lro_desc_find() - LRO descriptor look-up function + * + * @adapter: HDD adaptor + * @skb: network buffer + * @iph: IP header + * @tcph: TCP header + * @lro_desc: contains a pointer to the LRO decriptor + * + * Look-up the LRO descriptor in the hash table based on the + * flow ID toeplitz. If the flow is not found, allocates a new + * LRO descriptor and places it in the hash table + * + * Return: 0 - success, < 0 - failure + */ +static int hdd_lro_desc_find(struct hdd_lro_s *lro_info, + struct sk_buff *skb, struct iphdr *iph, struct tcphdr *tcph, + struct net_lro_desc **lro_desc) +{ + uint32_t i; + struct hdd_lro_desc_table *lro_hash_table; + struct list_head *ptr; + struct hdd_lro_desc_entry *entry; + struct hdd_lro_desc_pool *free_pool; + struct hdd_lro_desc_info *desc_info = &lro_info->lro_desc_info; + + *lro_desc = NULL; + i = QDF_NBUF_CB_RX_FLOW_ID_TOEPLITZ(skb) & LRO_DESC_TABLE_SZ_MASK; + + lro_hash_table = &desc_info->lro_hash_table[i]; + + if (!lro_hash_table) { + hdd_err("Invalid hash entry"); + QDF_ASSERT(0); + return -EINVAL; + } + + /* Check if this flow exists in the descriptor list */ + list_for_each(ptr, &lro_hash_table->lro_desc_list) { + struct net_lro_desc *tmp_lro_desc = NULL; + entry = list_entry(ptr, struct hdd_lro_desc_entry, lro_node); + tmp_lro_desc = entry->lro_desc; + if (tmp_lro_desc->active) { + if (hdd_lro_tcp_flow_match(tmp_lro_desc, iph, tcph)) { + *lro_desc = entry->lro_desc; + return 0; + } + } + } + + /* no existing flow found, a new LRO desc needs to be allocated */ + free_pool = &lro_info->lro_desc_info.lro_desc_pool; + entry = list_first_entry_or_null( + &free_pool->lro_free_list_head, + struct hdd_lro_desc_entry, lro_node); + if (NULL == entry) { + hdd_debug("Could not allocate LRO desc!"); + return -ENOMEM; + } + + list_del_init(&entry->lro_node); + + if (NULL == entry->lro_desc) { + hdd_err("entry->lro_desc is NULL!"); + return -EINVAL; + } + + qdf_mem_zero((void *)entry->lro_desc, sizeof(struct net_lro_desc)); + + /* + * lro_desc->active should be 0 and lro_desc->tcp_rcv_tsval + * should be 0 for newly allocated lro descriptors + */ + list_add_tail(&entry->lro_node, + &lro_hash_table->lro_desc_list); + *lro_desc = entry->lro_desc; + + return 0; +} + +/** + * hdd_lro_get_desc() - LRO descriptor look-up function + * @iph: IP header + * @tcph: TCP header + * @lro_arr: Array of LRO decriptors + * @lro_mgr: LRO manager + * + * Looks-up the LRO descriptor for a given flow + * + * Return: LRO descriptor + */ +static struct net_lro_desc *hdd_lro_get_desc(struct net_lro_mgr *lro_mgr, + struct net_lro_desc *lro_arr, + struct iphdr *iph, + struct tcphdr *tcph) +{ + int i; + + for (i = 0; i < lro_mgr->max_desc; i++) { + if (lro_arr[i].active) + if (hdd_lro_tcp_flow_match(&lro_arr[i], iph, tcph)) + return &lro_arr[i]; + } + + return NULL; +} + +/** + * hdd_lro_eligible() - LRO eligibilty check + * @iph: IP header + * @tcph: TCP header + * @adapter: HDD adaptor + * @desc: LRO descriptor + * @skb: network buffer + * + * Determines if the frame is LRO eligible + * + * Return: true - LRO eligible frame, false - frame is not LRO + * eligible + */ +static bool hdd_lro_eligible(struct hdd_lro_s *lro_info, struct sk_buff *skb, + struct iphdr *iph, struct tcphdr *tcph, struct net_lro_desc **desc) +{ + struct net_lro_desc *lro_desc = NULL; + int hw_lro_eligible = + QDF_NBUF_CB_RX_LRO_ELIGIBLE(skb) && + (!QDF_NBUF_CB_RX_TCP_PURE_ACK(skb)); + + if (!hw_lro_eligible) + return false; + + if (0 != hdd_lro_desc_find(lro_info, skb, iph, tcph, desc)) { + hdd_debug("finding the LRO desc failed"); + return false; + } + + lro_desc = *desc; + if (!lro_desc) + return false; + + /* if this is not the first skb, check the timestamp option */ + if (lro_desc->tcp_rcv_tsval) { + if (tcph->doff == 8) { + __be32 *topt = (__be32 *)(tcph + 1); + + if (*topt != htonl((TCPOPT_NOP << 24) + |(TCPOPT_NOP << 16) + | (TCPOPT_TIMESTAMP << 8) + | TCPOLEN_TIMESTAMP)) + return true; + + /* timestamp should be in right order */ + topt++; + if (after(ntohl(lro_desc->tcp_rcv_tsval), + ntohl(*topt))) + return false; + + /* timestamp reply should not be zero */ + topt++; + if (*topt == 0) + return false; + } + } + + return true; +} + +/** + * hdd_lro_desc_free() - Free the LRO descriptor + * @adapter: HDD adaptor + * @desc: LRO descriptor + * + * Return the LRO descriptor to the free pool + * + * Return: none + */ +static void hdd_lro_desc_free(struct net_lro_desc *desc, + struct hdd_lro_s *lro_info) +{ + struct hdd_lro_desc_entry *entry; + struct net_lro_mgr *lro_mgr = lro_info->lro_mgr; + struct net_lro_desc *arr_base = lro_mgr->lro_arr; + struct hdd_lro_desc_info *desc_info = &lro_info->lro_desc_info; + int i = desc - arr_base; + + if (i >= LRO_DESC_POOL_SZ) { + hdd_err("invalid index %d", i); + return; + } + + entry = &desc_info->lro_desc_pool.lro_desc_array[i]; + + list_del_init(&entry->lro_node); + + list_add_tail(&entry->lro_node, &desc_info-> + lro_desc_pool.lro_free_list_head); +} + +/** + * hdd_lro_flush_pkt() - function to flush the LRO flow + * @iph: IP header + * @tcph: TCP header + * @adapter: HDD adaptor + * @lro_mgr: LRO manager + * + * Flush all the packets aggregated in the LRO manager for the + * flow indicated by the TCP and IP header + * + * Return: none + */ +static void hdd_lro_flush_pkt(struct net_lro_mgr *lro_mgr, + struct iphdr *iph, struct tcphdr *tcph, + struct hdd_lro_s *lro_info) +{ + struct net_lro_desc *lro_desc; + + lro_desc = hdd_lro_get_desc(lro_mgr, lro_mgr->lro_arr, iph, tcph); + + if (lro_desc) { + /* statistics */ + hdd_lro_desc_free(lro_desc, lro_info); + lro_flush_desc(lro_mgr, lro_desc); + } +} + +/** + * hdd_lro_flush() - LRO flush callback + * @data: opaque pointer containing HDD specific information + * + * Callback registered to flush all the packets aggregated in + * the LRO manager for all the flows + * + * Return: none + */ +static void hdd_lro_flush(void *data) +{ + struct hdd_lro_s *hdd_lro = data; + struct net_lro_mgr *lro_mgr = hdd_lro->lro_mgr; + int i; + + for (i = 0; i < lro_mgr->max_desc; i++) { + if (lro_mgr->lro_arr[i].active) { + hdd_lro_desc_free(&lro_mgr->lro_arr[i], hdd_lro); + lro_flush_desc(lro_mgr, &lro_mgr->lro_arr[i]); + } + } +} + +/** + * hdd_lro_init() - initialization for LRO + * @hdd_ctx: HDD context + * + * This function sends the LRO configuration to the firmware + * via WMA + * Make sure that this function gets called after NAPI + * instances have been created. + * + * Return: 0 - success, < 0 - failure + */ +int hdd_lro_init(hdd_context_t *hdd_ctx) +{ + struct wma_lro_config_cmd_t lro_config; + + if ((!hdd_ctx->config->lro_enable) && + (hdd_napi_enabled(HDD_NAPI_ANY) == 0)) { + hdd_warn("LRO and NAPI are both disabled."); + return 0; + } + + lro_config.lro_enable = 1; + lro_config.tcp_flag = TCPHDR_ACK; + lro_config.tcp_flag_mask = TCPHDR_FIN | TCPHDR_SYN | TCPHDR_RST | + TCPHDR_ACK | TCPHDR_URG | TCPHDR_ECE | TCPHDR_CWR; + + get_random_bytes(lro_config.toeplitz_hash_ipv4, + (sizeof(lro_config.toeplitz_hash_ipv4[0]) * + LRO_IPV4_SEED_ARR_SZ)); + + get_random_bytes(lro_config.toeplitz_hash_ipv6, + (sizeof(lro_config.toeplitz_hash_ipv6[0]) * + LRO_IPV6_SEED_ARR_SZ)); + + hdd_debug("sending the LRO configuration to the fw"); + if (0 != wma_lro_init(&lro_config)) { + hdd_err("Failed to send LRO configuration!"); + hdd_ctx->config->lro_enable = 0; + return -EAGAIN; + } + + return 0; +} + +static void *hdd_init_lro_mgr(void) +{ + struct hdd_lro_s *hdd_lro; + hdd_context_t *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + size_t lro_info_sz, lro_mgr_sz, desc_arr_sz, desc_pool_sz; + size_t hash_table_sz; + uint8_t *lro_mem_ptr; + + if (NULL == hdd_ctx) { + hdd_err("hdd_ctx is NULL"); + return NULL; + } + /* + * Allocate all the LRO data structures at once and then carve + * them up as needed + */ + lro_info_sz = sizeof(struct hdd_lro_s); + lro_mgr_sz = sizeof(struct net_lro_mgr); + desc_arr_sz = (LRO_DESC_POOL_SZ * sizeof(struct net_lro_desc)); + desc_pool_sz = (LRO_DESC_POOL_SZ * sizeof(struct hdd_lro_desc_entry)); + hash_table_sz = (sizeof(struct hdd_lro_desc_table) * LRO_DESC_TABLE_SZ); + + lro_mem_ptr = qdf_mem_malloc(lro_info_sz + lro_mgr_sz + desc_arr_sz + + desc_pool_sz + hash_table_sz); + + if (NULL == lro_mem_ptr) { + hdd_err("Unable to allocate memory for LRO"); + hdd_ctx->config->lro_enable = 0; + return NULL; + } + + hdd_lro = (struct hdd_lro_s *)lro_mem_ptr; + lro_mem_ptr += lro_info_sz; + /* LRO manager */ + hdd_lro->lro_mgr = (struct net_lro_mgr *)lro_mem_ptr; + lro_mem_ptr += lro_mgr_sz; + + /* LRO decriptor array */ + hdd_lro->lro_mgr->lro_arr = (struct net_lro_desc *)lro_mem_ptr; + lro_mem_ptr += desc_arr_sz; + + /* LRO descriptor pool */ + hdd_lro->lro_desc_info.lro_desc_pool.lro_desc_array = + (struct hdd_lro_desc_entry *)lro_mem_ptr; + lro_mem_ptr += desc_pool_sz; + + /* hash table to store the LRO descriptors */ + hdd_lro->lro_desc_info.lro_hash_table = + (struct hdd_lro_desc_table *)lro_mem_ptr; + + /* Initialize the LRO descriptors */ + hdd_lro_desc_info_init(hdd_lro); + + if (hdd_ctx->enableRxThread) + hdd_lro->lro_mgr->features = LRO_F_NI; + + if (hdd_napi_enabled(HDD_NAPI_ANY)) + hdd_lro->lro_mgr->features |= LRO_F_NAPI; + + hdd_lro->lro_mgr->ip_summed_aggr = CHECKSUM_UNNECESSARY; + hdd_lro->lro_mgr->max_aggr = LRO_MAX_AGGR_SIZE; + hdd_lro->lro_mgr->get_skb_header = hdd_lro_get_skb_header; + hdd_lro->lro_mgr->ip_summed = CHECKSUM_UNNECESSARY; + hdd_lro->lro_mgr->max_desc = LRO_DESC_POOL_SZ; + + return hdd_lro; +} + +/** + * hdd_lro_enable() - enable LRO + * @hdd_ctx: HDD context + * @adapter: HDD adapter + * + * This function enables LRO in the network device attached to + * the HDD adapter. It also allocates the HDD LRO instance for + * that network device + * + * Return: 0 - success, < 0 - failure + */ +int hdd_lro_enable(hdd_context_t *hdd_ctx, hdd_adapter_t *adapter) +{ + + if (!hdd_ctx->config->lro_enable || + QDF_STA_MODE != adapter->device_mode) { + hdd_info("LRO Disabled"); + return 0; + } + + /* + * In case of USB tethering, LRO is disabled. If SSR happened + * during that time, then as part of SSR init, do not enable + * the LRO again. Keep the LRO state same as before SSR. + */ + if (qdf_atomic_read(&hdd_ctx->vendor_disable_lro_flag)) + return 0; + + adapter->dev->features |= NETIF_F_LRO; + + if (hdd_ctx->config->enable_tcp_delack) { + hdd_ctx->config->enable_tcp_delack = 0; + hdd_reset_tcp_delack(hdd_ctx); + } + + hdd_info("LRO Enabled"); + + return 0; +} + +/** + * hdd_lro_create() - Allocate LRO managers via callbacks + * + * Return: none + */ +void hdd_lro_create(void) +{ + /* Register the flush callback */ + ol_register_lro_flush_cb(hdd_lro_flush, hdd_init_lro_mgr); +} + +static void hdd_deinit_lro_mgr(void *lro_info) +{ + if (lro_info) { + hdd_notice("LRO instance %p is being freed", lro_info); + qdf_mem_free(lro_info); + } +} + +/** + * hdd_lro_disable() - disable LRO + * @hdd_ctx: HDD context + * @adapter: HDD adapter + * + * This function frees the HDD LRO instance for the network + * device attached to the HDD adapter + * + * Return: none + */ +void hdd_lro_disable(hdd_context_t *hdd_ctx, hdd_adapter_t *adapter) +{ + if (!hdd_ctx->config->lro_enable || + QDF_STA_MODE != adapter->device_mode) + return; + +} + +/** + * hdd_lro_destroy() - Free LRO managers via callbacks + * + * Return: none + */ +void hdd_lro_destroy(void) +{ + /* Deregister the flush callback */ + ol_deregister_lro_flush_cb(hdd_deinit_lro_mgr); + + return; +} + +/** + * hdd_lro_rx() - LRO receive function + * @hdd_ctx: HDD context + * @adapter: HDD adapter + * @skb: network buffer + * + * Delivers LRO eligible frames to the LRO manager + * + * Return: HDD_LRO_RX - frame delivered to LRO manager + * HDD_LRO_NO_RX - frame not delivered + */ +enum hdd_lro_rx_status hdd_lro_rx(hdd_context_t *hdd_ctx, + hdd_adapter_t *adapter, struct sk_buff *skb) +{ + enum hdd_lro_rx_status status = HDD_LRO_NO_RX; + + if (((adapter->dev->features & NETIF_F_LRO) != NETIF_F_LRO) || + qdf_atomic_read(&hdd_ctx->disable_lro_in_concurrency) || + QDF_NBUF_CB_RX_PEER_CACHED_FRM(skb) || + qdf_atomic_read(&hdd_ctx->disable_lro_in_low_tput)) + return status; + + if (QDF_NBUF_CB_RX_TCP_PROTO(skb)) { + struct iphdr *iph; + struct tcphdr *tcph; + struct net_lro_desc *lro_desc = NULL; + struct hdd_lro_s *lro_info; + struct hif_opaque_softc *hif_hdl = + (struct hif_opaque_softc *)cds_get_context( + QDF_MODULE_ID_HIF); + if (hif_hdl == NULL) { + hdd_err("hif_hdl is NULL"); + return status; + } + + lro_info = hif_get_lro_info(QDF_NBUF_CB_RX_CTX_ID(skb), + hif_hdl); + if (lro_info == NULL) { + hdd_err("LRO mgr is NULL, vdev could be going down"); + return status; + } + + iph = (struct iphdr *)skb->data; + tcph = (struct tcphdr *)(skb->data + QDF_NBUF_CB_RX_TCP_OFFSET(skb)); + lro_info->lro_mgr->dev = adapter->dev; + if (hdd_lro_eligible(lro_info, skb, iph, tcph, &lro_desc)) { + struct net_lro_info hdd_lro_info; + + hdd_lro_info.valid_fields = LRO_VALID_FIELDS; + + hdd_lro_info.lro_desc = lro_desc; + hdd_lro_info.lro_eligible = 1; + hdd_lro_info.tcp_ack_num = QDF_NBUF_CB_RX_TCP_ACK_NUM(skb); + hdd_lro_info.tcp_data_csum = + csum_unfold(htons(QDF_NBUF_CB_RX_TCP_CHKSUM(skb))); + hdd_lro_info.tcp_seq_num = QDF_NBUF_CB_RX_TCP_SEQ_NUM(skb); + hdd_lro_info.tcp_win = QDF_NBUF_CB_RX_TCP_WIN(skb); + + lro_receive_skb_ext(lro_info->lro_mgr, skb, + (void *)adapter, &hdd_lro_info); + + if (!hdd_lro_info.lro_desc->active) { + hdd_lro_desc_free(lro_desc, lro_info); + } + + status = HDD_LRO_RX; + } else { + hdd_lro_flush_pkt(lro_info->lro_mgr, + iph, tcph, lro_info); + } + } + return status; +} + +/** + * wlan_hdd_display_lro_stats() - display LRO statistics + * @hdd_ctx: hdd context + * + * Return: none + */ +void hdd_lro_display_stats(hdd_context_t *hdd_ctx) +{ + hdd_err("LRO stats is broken, will fix it"); +} + +/** + * hdd_enable_lro_in_concurrency() - Enable LRO if concurrency is not active + * @hdd_ctx: hdd context + * + * Return: none + */ +void hdd_enable_lro_in_concurrency(hdd_context_t *hdd_ctx) +{ + if (hdd_ctx->config->enable_tcp_delack) { + hdd_info("Disable TCP delack as LRO is enabled"); + hdd_ctx->config->enable_tcp_delack = 0; + hdd_reset_tcp_delack(hdd_ctx); + } + qdf_atomic_set(&hdd_ctx->disable_lro_in_concurrency, 0); +} + +/** + * hdd_disable_lro_in_concurrency() - Disable LRO due to concurrency + * @hdd_ctx: hdd context + * + * Return: none + */ +void hdd_disable_lro_in_concurrency(hdd_context_t *hdd_ctx) +{ + if (!hdd_ctx->config->enable_tcp_delack) { + struct wlan_rx_tp_data rx_tp_data = {0}; + + hdd_info("Enable TCP delack as LRO disabled in concurrency"); + rx_tp_data.rx_tp_flags |= TCP_DEL_ACK_IND; + rx_tp_data.level = hdd_ctx->cur_rx_level; + wlan_hdd_send_svc_nlink_msg(hdd_ctx->radio_index, + WLAN_SVC_WLAN_TP_IND, &rx_tp_data, sizeof(rx_tp_data)); + hdd_ctx->config->enable_tcp_delack = 1; + } + qdf_atomic_set(&hdd_ctx->disable_lro_in_concurrency, 1); +} + +void hdd_disable_lro_for_low_tput(hdd_context_t *hdd_ctx, bool disable) +{ + if (disable) + qdf_atomic_set(&hdd_ctx->disable_lro_in_low_tput, 1); + else + qdf_atomic_set(&hdd_ctx->disable_lro_in_low_tput, 0); +} + +/** + * hdd_lro_set_reset() - vendor command for Disable/Enable LRO + * @hdd_ctx: hdd context + * @hdd_adapter_t: adapter + * @enable_flag: enable or disable LRO. + * + * Return: none + */ +QDF_STATUS +hdd_lro_set_reset(hdd_context_t *hdd_ctx, hdd_adapter_t *adapter, + uint8_t enable_flag) +{ + if (enable_flag) { + qdf_atomic_set(&hdd_ctx->vendor_disable_lro_flag, 0); + hdd_lro_enable(hdd_ctx, adapter); + } else { + if (!hdd_ctx->config->lro_enable || + QDF_STA_MODE != adapter->device_mode) + return 0; + + /* Disable LRO, Enable tcpdelack*/ + qdf_atomic_set(&hdd_ctx->vendor_disable_lro_flag, 1); + adapter->dev->features &= ~NETIF_F_LRO; + hdd_debug("LRO Disabled"); + + if (!hdd_ctx->config->enable_tcp_delack) { + struct wlan_rx_tp_data rx_tp_data; + + hdd_debug("Enable TCP delack as LRO is disabled."); + rx_tp_data.rx_tp_flags = TCP_DEL_ACK_IND; + rx_tp_data.level = hdd_ctx->cur_rx_level; + wlan_hdd_send_svc_nlink_msg(hdd_ctx->radio_index, + WLAN_SVC_WLAN_TP_IND, &rx_tp_data, + sizeof(rx_tp_data)); + hdd_ctx->config->enable_tcp_delack = 1; + } + } + return 0; +} diff --git a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_main.c b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_main.c new file mode 100644 index 0000000000000000000000000000000000000000..1585fa5095772e9322e20d2f13405a68c16b3b97 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_main.c @@ -0,0 +1,10976 @@ +/* + * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: wlan_hdd_main.c + * + * WLAN Host Device Driver implementation + * + */ + +/* Include Files */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "wlan_hdd_trace.h" +#include "wlan_hdd_ioctl.h" +#include "wlan_hdd_ftm.h" +#include "wlan_hdd_power.h" +#include "wlan_hdd_stats.h" +#include "wlan_hdd_scan.h" +#include "qdf_types.h" +#include "qdf_trace.h" +#include + +#include +#include +#include +#include +#include +#include "wlan_hdd_cfg80211.h" +#include "wlan_hdd_ext_scan.h" +#include "wlan_hdd_p2p.h" +#include +#include "sap_api.h" +#include +#include +#include +#ifdef MSM_PLATFORM +#include +#endif +#include +#include +#include "cfg_api.h" +#include "qwlan_version.h" +#include "wma_types.h" +#include "wlan_hdd_tdls.h" +#ifdef FEATURE_WLAN_CH_AVOID +#include "cds_regdomain.h" +#include "cdp_txrx_flow_ctrl_v2.h" +#endif /* FEATURE_WLAN_CH_AVOID */ +#include "pld_common.h" +#include "wlan_hdd_ocb.h" +#include "wlan_hdd_nan.h" +#include "wlan_hdd_debugfs.h" +#include "wlan_hdd_driver_ops.h" +#include "epping_main.h" +#include "wlan_hdd_memdump.h" + +#include +#include "hif.h" +#include "wma.h" +#include "cds_concurrency.h" +#include "wlan_hdd_tsf.h" +#include "wlan_hdd_green_ap.h" +#include "bmi.h" +#include +#include "ol_rx_fwd.h" +#include "wlan_hdd_lpass.h" +#include "nan_api.h" +#include +#include "wlan_hdd_disa.h" +#include "ol_txrx.h" +#include "cds_utils.h" +#include "sir_api.h" + +#ifdef MODULE +#define WLAN_MODULE_NAME module_name(THIS_MODULE) +#else +#define WLAN_MODULE_NAME "wlan" +#endif + +#ifdef TIMER_MANAGER +#define TIMER_MANAGER_STR " +TIMER_MANAGER" +#else +#define TIMER_MANAGER_STR "" +#endif + +#ifdef MEMORY_DEBUG +#define MEMORY_DEBUG_STR " +MEMORY_DEBUG" +#else +#define MEMORY_DEBUG_STR "" +#endif + +int wlan_start_ret_val; +static DECLARE_COMPLETION(wlan_start_comp); +static unsigned int dev_num = 1; +static struct cdev wlan_hdd_state_cdev; +static struct class *class; +static dev_t device; +#ifndef MODULE +static struct gwlan_loader *wlan_loader; +static ssize_t wlan_boot_cb(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, size_t count); +struct gwlan_loader { + bool loaded_state; + struct kobject *boot_wlan_obj; + struct attribute_group *attr_group; +}; + +static struct kobj_attribute wlan_boot_attribute = + __ATTR(boot_wlan, 0220, NULL, wlan_boot_cb); + +static struct attribute *attrs[] = { + &wlan_boot_attribute.attr, + NULL, +}; + +#define MODULE_INITIALIZED 1 +#endif + +/* the Android framework expects this param even though we don't use it */ +#define BUF_LEN 20 +static char fwpath_buffer[BUF_LEN]; +static struct kparam_string fwpath = { + .string = fwpath_buffer, + .maxlen = BUF_LEN, +}; + +static char *country_code; +static int enable_11d = -1; +static int enable_dfs_chan_scan = -1; + +/* + * spinlock for synchronizing asynchronous request/response + * (full description of use in wlan_hdd_main.h) + */ +DEFINE_SPINLOCK(hdd_context_lock); + +DEFINE_MUTEX(hdd_init_deinit_lock); + +#define WLAN_NLINK_CESIUM 30 + +static qdf_wake_lock_t wlan_wake_lock; + +#define WOW_MAX_FILTER_LISTS 1 +#define WOW_MAX_FILTERS_PER_LIST 4 +#define WOW_MIN_PATTERN_SIZE 6 +#define WOW_MAX_PATTERN_SIZE 64 + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)) +static const struct wiphy_wowlan_support wowlan_support_reg_init = { + .flags = WIPHY_WOWLAN_ANY | + WIPHY_WOWLAN_MAGIC_PKT | + WIPHY_WOWLAN_DISCONNECT | + WIPHY_WOWLAN_SUPPORTS_GTK_REKEY | + WIPHY_WOWLAN_GTK_REKEY_FAILURE | + WIPHY_WOWLAN_EAP_IDENTITY_REQ | + WIPHY_WOWLAN_4WAY_HANDSHAKE | + WIPHY_WOWLAN_RFKILL_RELEASE, + .n_patterns = WOW_MAX_FILTER_LISTS * WOW_MAX_FILTERS_PER_LIST, + .pattern_min_len = WOW_MIN_PATTERN_SIZE, + .pattern_max_len = WOW_MAX_PATTERN_SIZE, +}; +#endif + +/* internal function declaration */ + +struct sock *cesium_nl_srv_sock; +#ifdef FEATURE_WLAN_AUTO_SHUTDOWN +void wlan_hdd_auto_shutdown_cb(void); +#endif + +void hdd_start_complete(int ret) +{ + wlan_start_ret_val = ret; + + complete(&wlan_start_comp); +} + +/** + * hdd_set_rps_cpu_mask - set RPS CPU mask for interfaces + * @hdd_ctx: pointer to hdd_context_t + * + * Return: none + */ +static void hdd_set_rps_cpu_mask(hdd_context_t *hdd_ctx) +{ + hdd_adapter_t *adapter; + hdd_adapter_list_node_t *adapter_node, *next; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + status = hdd_get_front_adapter(hdd_ctx, &adapter_node); + while (NULL != adapter_node && QDF_STATUS_SUCCESS == status) { + adapter = adapter_node->pAdapter; + if (NULL != adapter) + hdd_send_rps_ind(adapter); + status = hdd_get_next_adapter(hdd_ctx, adapter_node, &next); + adapter_node = next; + } +} + +/** + * wlan_hdd_txrx_pause_cb() - pause callback from txrx layer + * @vdev_id: vdev_id + * @action: action type + * @reason: reason type + * + * Return: none + */ +void wlan_hdd_txrx_pause_cb(uint8_t vdev_id, + enum netif_action_type action, enum netif_reason_type reason) +{ + hdd_context_t *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + hdd_adapter_t *adapter; + + if (!hdd_ctx) { + hdd_err("hdd ctx is NULL"); + return; + } + adapter = hdd_get_adapter_by_vdev(hdd_ctx, vdev_id); + + wlan_hdd_netif_queue_control(adapter, action, reason); + return; +} + +/* + * Store WLAN driver version info in a global variable such that crash debugger + * can extract it from driver debug symbol and crashdump for post processing + */ +uint8_t g_wlan_driver_version[] = QWLAN_VERSIONSTR; + +/** + * hdd_device_mode_to_string() - return string conversion of device mode + * @device_mode: device mode + * + * This utility function helps log string conversion of device mode. + * + * Return: string conversion of device mode, if match found; + * "Unknown" otherwise. + */ +const char *hdd_device_mode_to_string(uint8_t device_mode) +{ + switch (device_mode) { + CASE_RETURN_STRING(QDF_STA_MODE); + CASE_RETURN_STRING(QDF_SAP_MODE); + CASE_RETURN_STRING(QDF_P2P_CLIENT_MODE); + CASE_RETURN_STRING(QDF_P2P_GO_MODE); + CASE_RETURN_STRING(QDF_FTM_MODE); + CASE_RETURN_STRING(QDF_IBSS_MODE); + CASE_RETURN_STRING(QDF_P2P_DEVICE_MODE); + CASE_RETURN_STRING(QDF_OCB_MODE); + CASE_RETURN_STRING(QDF_NDI_MODE); + default: + return "Unknown"; + } +} + +/** + * hdd_validate_channel_and_bandwidth() - Validate the channel-bandwidth combo + * @adapter: HDD adapter + * @chan_number: Channel number + * @chan_bw: Bandwidth + * + * Checks if the given bandwidth is valid for the given channel number. + * + * Return: 0 for success, non-zero for failure + */ +int hdd_validate_channel_and_bandwidth(hdd_adapter_t *adapter, + uint32_t chan_number, + enum phy_ch_width chan_bw) +{ + uint8_t chan[WNI_CFG_VALID_CHANNEL_LIST_LEN]; + uint32_t len = WNI_CFG_VALID_CHANNEL_LIST_LEN, i; + bool found = false; + tHalHandle hal; + + hal = WLAN_HDD_GET_HAL_CTX(adapter); + if (!hal) { + hdd_err("Invalid HAL context"); + return -EINVAL; + } + + if (0 != sme_cfg_get_str(hal, WNI_CFG_VALID_CHANNEL_LIST, chan, &len)) { + hdd_err("No valid channel list"); + return -EOPNOTSUPP; + } + + for (i = 0; i < len; i++) { + if (chan[i] == chan_number) { + found = true; + break; + } + } + + if (found == false) { + hdd_err("Channel not in driver's valid channel list"); + return -EOPNOTSUPP; + } + + if ((!CDS_IS_CHANNEL_24GHZ(chan_number)) && + (!CDS_IS_CHANNEL_5GHZ(chan_number))) { + hdd_err("CH %d is not in 2.4GHz or 5GHz", chan_number); + return -EINVAL; + } + + if (CDS_IS_CHANNEL_24GHZ(chan_number)) { + if (chan_bw == CH_WIDTH_80MHZ) { + hdd_err("BW80 not possible in 2.4GHz band"); + return -EINVAL; + } + if ((chan_bw != CH_WIDTH_20MHZ) && (chan_number == 14) && + (chan_bw != CH_WIDTH_MAX)) { + hdd_err("Only BW20 possible on channel 14"); + return -EINVAL; + } + } + + if (CDS_IS_CHANNEL_5GHZ(chan_number)) { + if ((chan_bw != CH_WIDTH_20MHZ) && (chan_number == 165) && + (chan_bw != CH_WIDTH_MAX)) { + hdd_err("Only BW20 possible on channel 165"); + return -EINVAL; + } + } + + return 0; +} + +static int __hdd_netdev_notifier_call(struct notifier_block *nb, + unsigned long state, void *data) +{ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)) + struct netdev_notifier_info *dev_notif_info = data; + struct net_device *dev = dev_notif_info->dev; +#else + struct net_device *dev = data; +#endif + hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *hdd_ctx; + + ENTER_DEV(dev); + + /* Make sure that this callback corresponds to our device. */ + if ((strncmp(dev->name, "wlan", 4)) && (strncmp(dev->name, "p2p", 3))) + return NOTIFY_DONE; + + if ((adapter->magic != WLAN_HDD_ADAPTER_MAGIC) || + (adapter->dev != dev)) { + hdd_err("device adapter is not matching!!!"); + return NOTIFY_DONE; + } + + if (!dev->ieee80211_ptr) { + hdd_err("ieee80211_ptr is NULL!!!"); + return NOTIFY_DONE; + } + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + if (NULL == hdd_ctx) { + hdd_alert("HDD Context Null Pointer"); + QDF_ASSERT(0); + return NOTIFY_DONE; + } + if (cds_is_driver_recovering()) + return NOTIFY_DONE; + + hdd_notice("%s New Net Device State = %lu", + dev->name, state); + + switch (state) { + case NETDEV_REGISTER: + break; + + case NETDEV_UNREGISTER: + break; + + case NETDEV_UP: + sme_ch_avoid_update_req(hdd_ctx->hHal); + break; + + case NETDEV_DOWN: + break; + + case NETDEV_CHANGE: + if (true == adapter->isLinkUpSvcNeeded) + complete(&adapter->linkup_event_var); + break; + + case NETDEV_GOING_DOWN: + if (adapter->scan_info.mScanPending != false) { + unsigned long rc; + INIT_COMPLETION(adapter->scan_info. + abortscan_event_var); + hdd_abort_mac_scan(adapter->pHddCtx, + adapter->sessionId, + INVALID_SCAN_ID, + eCSR_SCAN_ABORT_DEFAULT); + rc = wait_for_completion_timeout( + &adapter->scan_info.abortscan_event_var, + msecs_to_jiffies(WLAN_WAIT_TIME_ABORTSCAN)); + if (!rc) { + hdd_err("Timeout occurred while waiting for abortscan"); + } + } else { + hdd_notice("Scan is not Pending from user"); + } + break; + + default: + break; + } + + return NOTIFY_DONE; +} + +/** + * hdd_netdev_notifier_call() - netdev notifier callback function + * @nb: pointer to notifier block + * @state: state + * @ndev: ndev pointer + * + * Return: 0 on success, error number otherwise. + */ +static int hdd_netdev_notifier_call(struct notifier_block *nb, + unsigned long state, + void *ndev) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __hdd_netdev_notifier_call(nb, state, ndev); + cds_ssr_unprotect(__func__); + + return ret; +} + +struct notifier_block hdd_netdev_notifier = { + .notifier_call = hdd_netdev_notifier_call, +}; + +/* variable to hold the insmod parameters */ +static int con_mode; + +/* Variable to hold connection mode including module parameter con_mode */ +static int curr_con_mode; + +/** + * hdd_map_nl_chan_width() - Map NL channel width to internal representation + * @ch_width: NL channel width + * + * Converts the NL channel width to the driver's internal representation + * + * Return: Converted channel width. In case of non matching NL channel width, + * CH_WIDTH_MAX will be returned. + */ +enum phy_ch_width hdd_map_nl_chan_width(enum nl80211_chan_width ch_width) +{ + uint8_t fw_ch_bw; + fw_ch_bw = wma_get_vht_ch_width(); + switch (ch_width) { + case NL80211_CHAN_WIDTH_20_NOHT: + case NL80211_CHAN_WIDTH_20: + return CH_WIDTH_20MHZ; + case NL80211_CHAN_WIDTH_40: + return CH_WIDTH_40MHZ; + break; + case NL80211_CHAN_WIDTH_80: + return CH_WIDTH_80MHZ; + case NL80211_CHAN_WIDTH_80P80: + if (fw_ch_bw == WNI_CFG_VHT_CHANNEL_WIDTH_80_PLUS_80MHZ) + return CH_WIDTH_80P80MHZ; + else if (fw_ch_bw == WNI_CFG_VHT_CHANNEL_WIDTH_160MHZ) + return CH_WIDTH_160MHZ; + else + return CH_WIDTH_80MHZ; + case NL80211_CHAN_WIDTH_160: + if (fw_ch_bw >= WNI_CFG_VHT_CHANNEL_WIDTH_160MHZ) + return CH_WIDTH_160MHZ; + else + return CH_WIDTH_80MHZ; + case NL80211_CHAN_WIDTH_5: + return CH_WIDTH_5MHZ; + case NL80211_CHAN_WIDTH_10: + return CH_WIDTH_10MHZ; + default: + hdd_warn("Invalid channel width %d, setting to default", + ch_width); + return CH_WIDTH_INVALID; + } +} + +/* wlan_hdd_find_opclass() - Find operating class for a channel + * @hal: handler to HAL + * @channel: channel id + * @bw_offset: bandwidth offset + * + * Function invokes sme api to find the operating class + * + * Return: operating class + */ +uint8_t wlan_hdd_find_opclass(tHalHandle hal, uint8_t channel, + uint8_t bw_offset) +{ + uint8_t opclass = 0; + + sme_get_opclass(hal, channel, bw_offset, &opclass); + return opclass; +} + +/** + * hdd_qdf_trace_enable() - configure initial QDF Trace enable + * @moduleId: Module whose trace level is being configured + * @bitmask: Bitmask of log levels to be enabled + * + * Called immediately after the cfg.ini is read in order to configure + * the desired trace levels. + * + * Return: None + */ +static void hdd_qdf_trace_enable(QDF_MODULE_ID moduleId, uint32_t bitmask) +{ + QDF_TRACE_LEVEL level; + + /* + * if the bitmask is the default value, then a bitmask was not + * specified in cfg.ini, so leave the logging level alone (it + * will remain at the "compiled in" default value) + */ + if (CFG_QDF_TRACE_ENABLE_DEFAULT == bitmask) { + return; + } + + /* a mask was specified. start by disabling all logging */ + qdf_trace_set_value(moduleId, QDF_TRACE_LEVEL_NONE, 0); + + /* now cycle through the bitmask until all "set" bits are serviced */ + level = QDF_TRACE_LEVEL_FATAL; + while (0 != bitmask) { + if (bitmask & 1) { + qdf_trace_set_value(moduleId, level, 1); + } + level++; + bitmask >>= 1; + } +} + +/** + * wlan_hdd_validate_context() - check the HDD context + * @hdd_ctx: HDD context pointer + * + * Return: 0 if the context is valid. Error code otherwise + */ +int wlan_hdd_validate_context(hdd_context_t *hdd_ctx) +{ + if (NULL == hdd_ctx || NULL == hdd_ctx->config) { + hdd_info("%pS HDD context is Null", (void *)_RET_IP_); + return -ENODEV; + } + + if (cds_is_driver_recovering()) { + hdd_info("%pS Recovery in Progress. State: 0x%x Ignore!!!", + (void *)_RET_IP_, cds_get_driver_state()); + return -EAGAIN; + } + + if (cds_is_load_or_unload_in_progress()) { + hdd_info("%pS Unloading/Loading in Progress. Ignore!!!: 0x%x", + (void *)_RET_IP_, cds_get_driver_state()); + return -EAGAIN; + } + + if (hdd_ctx->start_modules_in_progress || + hdd_ctx->stop_modules_in_progress) { + hdd_info("%pS Start/Stop Modules in progress. Ignore!!!", + (void *)_RET_IP_); + return -EAGAIN; + } + + return 0; +} + +/** + * wlan_hdd_modules_are_enabled() - Check modules status + * @hdd_ctx: HDD context pointer + * + * Check's the driver module's state and returns true if the + * modules are enabled returns false if modules are closed. + * + * Return: True if modules are enabled or false. + */ +bool wlan_hdd_modules_are_enabled(hdd_context_t *hdd_ctx) +{ + mutex_lock(&hdd_ctx->iface_change_lock); + if (hdd_ctx->driver_status != DRIVER_MODULES_ENABLED) { + mutex_unlock(&hdd_ctx->iface_change_lock); + hdd_notice("Modules not enabled, Present status: %d", + hdd_ctx->driver_status); + return false; + } + mutex_unlock(&hdd_ctx->iface_change_lock); + return true; +} + +/** + * hdd_set_ibss_power_save_params() - update IBSS Power Save params to WMA. + * @hdd_adapter_t Hdd adapter. + * + * This function sets the IBSS power save config parameters to WMA + * which will send it to firmware if FW supports IBSS power save + * before vdev start. + * + * Return: QDF_STATUS QDF_STATUS_SUCCESS on Success and QDF_STATUS_E_FAILURE + * on failure. + */ +QDF_STATUS hdd_set_ibss_power_save_params(hdd_adapter_t *adapter) +{ + int ret; + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + + if (hdd_ctx == NULL) { + hdd_err("HDD context is null"); + return QDF_STATUS_E_FAILURE; + } + + ret = sme_cli_set_command(adapter->sessionId, + WMA_VDEV_IBSS_SET_ATIM_WINDOW_SIZE, + hdd_ctx->config->ibssATIMWinSize, + VDEV_CMD); + if (0 != ret) { + hdd_err("WMA_VDEV_IBSS_SET_ATIM_WINDOW_SIZE failed %d", ret); + return QDF_STATUS_E_FAILURE; + } + + ret = sme_cli_set_command(adapter->sessionId, + WMA_VDEV_IBSS_SET_POWER_SAVE_ALLOWED, + hdd_ctx->config->isIbssPowerSaveAllowed, + VDEV_CMD); + if (0 != ret) { + hdd_err("WMA_VDEV_IBSS_SET_POWER_SAVE_ALLOWED failed %d", + ret); + return QDF_STATUS_E_FAILURE; + } + + ret = sme_cli_set_command(adapter->sessionId, + WMA_VDEV_IBSS_SET_POWER_COLLAPSE_ALLOWED, + hdd_ctx->config-> + isIbssPowerCollapseAllowed, VDEV_CMD); + if (0 != ret) { + hdd_err("WMA_VDEV_IBSS_SET_POWER_COLLAPSE_ALLOWED failed %d", + ret); + return QDF_STATUS_E_FAILURE; + } + + ret = sme_cli_set_command(adapter->sessionId, + WMA_VDEV_IBSS_SET_AWAKE_ON_TX_RX, + hdd_ctx->config->isIbssAwakeOnTxRx, + VDEV_CMD); + if (0 != ret) { + hdd_err("WMA_VDEV_IBSS_SET_AWAKE_ON_TX_RX failed %d", ret); + return QDF_STATUS_E_FAILURE; + } + + ret = sme_cli_set_command(adapter->sessionId, + WMA_VDEV_IBSS_SET_INACTIVITY_TIME, + hdd_ctx->config->ibssInactivityCount, + VDEV_CMD); + if (0 != ret) { + hdd_err("WMA_VDEV_IBSS_SET_INACTIVITY_TIME failed %d", ret); + return QDF_STATUS_E_FAILURE; + } + + ret = sme_cli_set_command(adapter->sessionId, + WMA_VDEV_IBSS_SET_TXSP_END_INACTIVITY_TIME, + hdd_ctx->config->ibssTxSpEndInactivityTime, + VDEV_CMD); + if (0 != ret) { + hdd_err("WMA_VDEV_IBSS_SET_TXSP_END_INACTIVITY_TIME failed %d", + ret); + return QDF_STATUS_E_FAILURE; + } + + ret = sme_cli_set_command(adapter->sessionId, + WMA_VDEV_IBSS_PS_SET_WARMUP_TIME_SECS, + hdd_ctx->config->ibssPsWarmupTime, + VDEV_CMD); + if (0 != ret) { + hdd_err("WMA_VDEV_IBSS_PS_SET_WARMUP_TIME_SECS failed %d", + ret); + return QDF_STATUS_E_FAILURE; + } + + ret = sme_cli_set_command(adapter->sessionId, + WMA_VDEV_IBSS_PS_SET_1RX_CHAIN_IN_ATIM_WINDOW, + hdd_ctx->config->ibssPs1RxChainInAtimEnable, + VDEV_CMD); + if (0 != ret) { + hdd_err("WMA_VDEV_IBSS_PS_SET_1RX_CHAIN_IN_ATIM_WINDOW failed %d", + ret); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +#define INTF_MACADDR_MASK 0x7 + +/** + * hdd_update_macaddr() - update mac address + * @config: hdd configuration + * @hw_macaddr: mac address + * + * Mac address for multiple virtual interface is found as following + * i) The mac address of the first interface is just the actual hw mac address. + * ii) MSM 3 or 4 bits of byte5 of the actual mac address are used to + * define the mac address for the remaining interfaces and locally + * admistered bit is set. INTF_MACADDR_MASK is based on the number of + * supported virtual interfaces, right now this is 0x07 (meaning 8 + * interface). + * Byte[3] of second interface will be hw_macaddr[3](bit5..7) + 1, + * for third interface it will be hw_macaddr[3](bit5..7) + 2, etc. + * + * Return: None + */ +void hdd_update_macaddr(struct hdd_config *config, + struct qdf_mac_addr hw_macaddr) +{ + int8_t i; + uint8_t macaddr_b3, tmp_br3; + + qdf_mem_copy(config->intfMacAddr[0].bytes, hw_macaddr.bytes, + QDF_MAC_ADDR_SIZE); + for (i = 1; i < QDF_MAX_CONCURRENCY_PERSONA; i++) { + qdf_mem_copy(config->intfMacAddr[i].bytes, hw_macaddr.bytes, + QDF_MAC_ADDR_SIZE); + macaddr_b3 = config->intfMacAddr[i].bytes[3]; + tmp_br3 = ((macaddr_b3 >> 4 & INTF_MACADDR_MASK) + i) & + INTF_MACADDR_MASK; + macaddr_b3 += tmp_br3; + + /* XOR-ing bit-24 of the mac address. This will give enough + * mac address range before collision + */ + macaddr_b3 ^= (1 << 7); + + /* Set locally administered bit */ + config->intfMacAddr[i].bytes[0] |= 0x02; + config->intfMacAddr[i].bytes[3] = macaddr_b3; + hdd_notice("config->intfMacAddr[%d]: " + MAC_ADDRESS_STR, i, + MAC_ADDR_ARRAY(config->intfMacAddr[i].bytes)); + } +} + +static void hdd_update_tgt_services(hdd_context_t *hdd_ctx, + struct wma_tgt_services *cfg) +{ + struct hdd_config *config = hdd_ctx->config; + + /* Set up UAPSD */ + config->apUapsdEnabled &= cfg->uapsd; + + /* 11AC mode support */ + if ((config->dot11Mode == eHDD_DOT11_MODE_11ac || + config->dot11Mode == eHDD_DOT11_MODE_11ac_ONLY) && !cfg->en_11ac) + config->dot11Mode = eHDD_DOT11_MODE_AUTO; + + /* ARP offload: override user setting if invalid */ + config->fhostArpOffload &= cfg->arp_offload; + +#ifdef FEATURE_WLAN_SCAN_PNO + /* PNO offload */ + hdd_info("PNO Capability in f/w = %d", cfg->pno_offload); + if (cfg->pno_offload) + config->PnoOffload = true; +#endif +#ifdef FEATURE_WLAN_TDLS + config->fEnableTDLSSupport &= cfg->en_tdls; + config->fEnableTDLSOffChannel = config->fEnableTDLSOffChannel && + cfg->en_tdls_offchan; + config->fEnableTDLSBufferSta = config->fEnableTDLSBufferSta && + cfg->en_tdls_uapsd_buf_sta; + if (config->fTDLSUapsdMask && cfg->en_tdls_uapsd_sleep_sta) { + config->fEnableTDLSSleepSta = true; + } else { + config->fEnableTDLSSleepSta = false; + } +#endif +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + config->isRoamOffloadEnabled &= cfg->en_roam_offload; +#endif + sme_update_tgt_services(hdd_ctx->hHal, cfg); + +} + +/** + * hdd_update_vdev_nss() - sets the vdev nss + * @hdd_ctx: HDD context + * + * Sets the Nss per vdev type based on INI + * + * Return: None + */ +static void hdd_update_vdev_nss(hdd_context_t *hdd_ctx) +{ + struct hdd_config *cfg_ini = hdd_ctx->config; + uint8_t max_supp_nss = 1; + + if (cfg_ini->enable2x2 && !cds_is_sub_20_mhz_enabled()) + max_supp_nss = 2; + + sme_update_vdev_type_nss(hdd_ctx->hHal, max_supp_nss, + cfg_ini->vdev_type_nss_2g, eCSR_BAND_24); + + sme_update_vdev_type_nss(hdd_ctx->hHal, max_supp_nss, + cfg_ini->vdev_type_nss_5g, eCSR_BAND_5G); +} + +/** + * hdd_update_hw_dbs_capable() - sets the dbs capability of the device + * @hdd_ctx: HDD context + * + * Sets the DBS capability as per INI and firmware capability + * + * Return: None + */ +static void hdd_update_hw_dbs_capable(hdd_context_t *hdd_ctx) +{ + struct hdd_config *cfg_ini = hdd_ctx->config; + uint8_t hw_dbs_capable = 0; + + if ((!cfg_ini->dual_mac_feature_disable) + && wma_is_hw_dbs_capable()) + hw_dbs_capable = 1; + + sme_update_hw_dbs_capable(hdd_ctx->hHal, hw_dbs_capable); +} + +static void hdd_update_tgt_ht_cap(hdd_context_t *hdd_ctx, + struct wma_tgt_ht_cap *cfg) +{ + QDF_STATUS status; + uint32_t value, val32; + uint16_t val16; + struct hdd_config *pconfig = hdd_ctx->config; + tSirMacHTCapabilityInfo *phtCapInfo; + uint8_t mcs_set[SIZE_OF_SUPPORTED_MCS_SET]; + uint8_t enable_tx_stbc; + + /* check and update RX STBC */ + if (pconfig->enableRxSTBC && !cfg->ht_rx_stbc) + pconfig->enableRxSTBC = cfg->ht_rx_stbc; + + /* get the MPDU density */ + status = sme_cfg_get_int(hdd_ctx->hHal, WNI_CFG_MPDU_DENSITY, &value); + + if (status != QDF_STATUS_SUCCESS) { + hdd_err("could not get MPDU DENSITY"); + value = 0; + } + + /* + * MPDU density: + * override user's setting if value is larger + * than the one supported by target + */ + if (value > cfg->mpdu_density) { + status = sme_cfg_set_int(hdd_ctx->hHal, WNI_CFG_MPDU_DENSITY, + cfg->mpdu_density); + + if (status == QDF_STATUS_E_FAILURE) + hdd_alert("could not set MPDU DENSITY to CCM"); + } + + /* get the HT capability info */ + status = sme_cfg_get_int(hdd_ctx->hHal, WNI_CFG_HT_CAP_INFO, &val32); + if (QDF_STATUS_SUCCESS != status) { + hdd_err("could not get HT capability info"); + return; + } + val16 = (uint16_t) val32; + phtCapInfo = (tSirMacHTCapabilityInfo *) &val16; + + /* Set the LDPC capability */ + phtCapInfo->advCodingCap = cfg->ht_rx_ldpc; + + if (pconfig->ShortGI20MhzEnable && !cfg->ht_sgi_20) + pconfig->ShortGI20MhzEnable = cfg->ht_sgi_20; + + if (pconfig->ShortGI40MhzEnable && !cfg->ht_sgi_40) + pconfig->ShortGI40MhzEnable = cfg->ht_sgi_40; + + hdd_ctx->num_rf_chains = cfg->num_rf_chains; + hdd_ctx->ht_tx_stbc_supported = cfg->ht_tx_stbc; + + enable_tx_stbc = pconfig->enableTxSTBC; + + if (pconfig->enable2x2 && (cfg->num_rf_chains == 2)) { + pconfig->enable2x2 = 1; + } else { + pconfig->enable2x2 = 0; + enable_tx_stbc = 0; + + /* 1x1 */ + /* Update Rx Highest Long GI data Rate */ + if (sme_cfg_set_int(hdd_ctx->hHal, + WNI_CFG_VHT_RX_HIGHEST_SUPPORTED_DATA_RATE, + VHT_RX_HIGHEST_SUPPORTED_DATA_RATE_1_1) + == QDF_STATUS_E_FAILURE) { + hdd_err("Could not pass on WNI_CFG_VHT_RX_HIGHEST_SUPPORTED_DATA_RATE to CCM"); + } + + /* Update Tx Highest Long GI data Rate */ + if (sme_cfg_set_int + (hdd_ctx->hHal, + WNI_CFG_VHT_TX_HIGHEST_SUPPORTED_DATA_RATE, + VHT_TX_HIGHEST_SUPPORTED_DATA_RATE_1_1) == + QDF_STATUS_E_FAILURE) { + hdd_err("VHT_TX_HIGHEST_SUPP_RATE_1_1 to CCM fail"); + } + } + if (!(cfg->ht_tx_stbc && pconfig->enable2x2)) + enable_tx_stbc = 0; + phtCapInfo->txSTBC = enable_tx_stbc; + + val32 = val16; + status = sme_cfg_set_int(hdd_ctx->hHal, WNI_CFG_HT_CAP_INFO, val32); + if (status != QDF_STATUS_SUCCESS) + hdd_alert("could not set HT capability to CCM"); +#define WLAN_HDD_RX_MCS_ALL_NSTREAM_RATES 0xff + value = SIZE_OF_SUPPORTED_MCS_SET; + if (sme_cfg_get_str(hdd_ctx->hHal, WNI_CFG_SUPPORTED_MCS_SET, mcs_set, + &value) == QDF_STATUS_SUCCESS) { + hdd_notice("Read MCS rate set"); + + if (pconfig->enable2x2) { + for (value = 0; value < cfg->num_rf_chains; value++) + mcs_set[value] = + WLAN_HDD_RX_MCS_ALL_NSTREAM_RATES; + + status = + sme_cfg_set_str(hdd_ctx->hHal, + WNI_CFG_SUPPORTED_MCS_SET, + mcs_set, + SIZE_OF_SUPPORTED_MCS_SET); + if (status == QDF_STATUS_E_FAILURE) + hdd_alert("could not set MCS SET to CCM"); + } + } +#undef WLAN_HDD_RX_MCS_ALL_NSTREAM_RATES +} + +static void hdd_update_tgt_vht_cap(hdd_context_t *hdd_ctx, + struct wma_tgt_vht_cap *cfg) +{ + QDF_STATUS status; + uint32_t value = 0; + struct hdd_config *pconfig = hdd_ctx->config; + struct wiphy *wiphy = hdd_ctx->wiphy; + struct ieee80211_supported_band *band_5g = + wiphy->bands[NL80211_BAND_5GHZ]; + uint32_t temp = 0; + uint32_t ch_width = eHT_CHANNEL_WIDTH_80MHZ; + + if (!band_5g) { + hdd_info("5GHz band disabled, skipping capability population"); + return; + } + + /* Get the current MPDU length */ + status = + sme_cfg_get_int(hdd_ctx->hHal, WNI_CFG_VHT_MAX_MPDU_LENGTH, + &value); + + if (status != QDF_STATUS_SUCCESS) { + hdd_err("could not get MPDU LENGTH"); + value = 0; + } + + /* + * VHT max MPDU length: + * override if user configured value is too high + * that the target cannot support + */ + if (value > cfg->vht_max_mpdu) { + status = sme_cfg_set_int(hdd_ctx->hHal, + WNI_CFG_VHT_MAX_MPDU_LENGTH, + cfg->vht_max_mpdu); + + if (status == QDF_STATUS_E_FAILURE) { + hdd_alert("could not set VHT MAX MPDU LENGTH"); + } + } + + sme_cfg_get_int(hdd_ctx->hHal, WNI_CFG_VHT_BASIC_MCS_SET, &temp); + temp = (temp & VHT_MCS_1x1) | pconfig->vhtRxMCS; + + if (pconfig->enable2x2) + temp = (temp & VHT_MCS_2x2) | (pconfig->vhtRxMCS2x2 << 2); + + if (sme_cfg_set_int(hdd_ctx->hHal, WNI_CFG_VHT_BASIC_MCS_SET, temp) == + QDF_STATUS_E_FAILURE) { + hdd_err("Could not pass VHT_BASIC_MCS_SET to CCM"); + } + + sme_cfg_get_int(hdd_ctx->hHal, WNI_CFG_VHT_RX_MCS_MAP, &temp); + temp = (temp & VHT_MCS_1x1) | pconfig->vhtRxMCS; + if (pconfig->enable2x2) + temp = (temp & VHT_MCS_2x2) | (pconfig->vhtRxMCS2x2 << 2); + + if (sme_cfg_set_int(hdd_ctx->hHal, WNI_CFG_VHT_RX_MCS_MAP, temp) == + QDF_STATUS_E_FAILURE) { + hdd_err("Could not pass WNI_CFG_VHT_RX_MCS_MAP to CCM"); + } + + sme_cfg_get_int(hdd_ctx->hHal, WNI_CFG_VHT_TX_MCS_MAP, &temp); + temp = (temp & VHT_MCS_1x1) | pconfig->vhtTxMCS; + if (pconfig->enable2x2) + temp = (temp & VHT_MCS_2x2) | (pconfig->vhtTxMCS2x2 << 2); + + hdd_info("vhtRxMCS2x2 - %x temp - %u enable2x2 %d", + pconfig->vhtRxMCS2x2, temp, pconfig->enable2x2); + + if (sme_cfg_set_int(hdd_ctx->hHal, WNI_CFG_VHT_TX_MCS_MAP, temp) == + QDF_STATUS_E_FAILURE) { + hdd_err("Could not pass WNI_CFG_VHT_TX_MCS_MAP to CCM"); + } + /* Get the current RX LDPC setting */ + status = sme_cfg_get_int(hdd_ctx->hHal, WNI_CFG_VHT_LDPC_CODING_CAP, + &value); + + if (status != QDF_STATUS_SUCCESS) { + hdd_err("could not get VHT LDPC CODING CAP"); + value = 0; + } + + /* Set the LDPC capability */ + if (value && !cfg->vht_rx_ldpc) { + status = sme_cfg_set_int(hdd_ctx->hHal, + WNI_CFG_VHT_LDPC_CODING_CAP, + cfg->vht_rx_ldpc); + + if (status == QDF_STATUS_E_FAILURE) { + hdd_alert("could not set VHT LDPC CODING CAP to CCM"); + } + } + + /* Get current GI 80 value */ + status = sme_cfg_get_int(hdd_ctx->hHal, WNI_CFG_VHT_SHORT_GI_80MHZ, + &value); + + if (status != QDF_STATUS_SUCCESS) { + hdd_err("could not get SHORT GI 80MHZ"); + value = 0; + } + + /* set the Guard interval 80MHz */ + if (value && !cfg->vht_short_gi_80) { + status = sme_cfg_set_int(hdd_ctx->hHal, + WNI_CFG_VHT_SHORT_GI_80MHZ, + cfg->vht_short_gi_80); + + if (status == QDF_STATUS_E_FAILURE) { + hdd_alert("could not set SHORT GI 80MHZ to CCM"); + } + } + + /* Get current GI 160 value */ + status = sme_cfg_get_int(hdd_ctx->hHal, + WNI_CFG_VHT_SHORT_GI_160_AND_80_PLUS_80MHZ, + &value); + + if (status != QDF_STATUS_SUCCESS) { + hdd_err("could not get SHORT GI 80 & 160"); + value = 0; + } + + /* Get VHT TX STBC cap */ + status = sme_cfg_get_int(hdd_ctx->hHal, WNI_CFG_VHT_TXSTBC, &value); + + if (status != QDF_STATUS_SUCCESS) { + hdd_err("could not get VHT TX STBC"); + value = 0; + } + + /* VHT TX STBC cap */ + if (value && !cfg->vht_tx_stbc) { + status = sme_cfg_set_int(hdd_ctx->hHal, WNI_CFG_VHT_TXSTBC, + cfg->vht_tx_stbc); + + if (status == QDF_STATUS_E_FAILURE) { + hdd_alert("could not set the VHT TX STBC to CCM"); + } + } + + /* Get VHT RX STBC cap */ + status = sme_cfg_get_int(hdd_ctx->hHal, WNI_CFG_VHT_RXSTBC, &value); + + if (status != QDF_STATUS_SUCCESS) { + hdd_err("could not get VHT RX STBC"); + value = 0; + } + + /* VHT RX STBC cap */ + if (value && !cfg->vht_rx_stbc) { + status = sme_cfg_set_int(hdd_ctx->hHal, WNI_CFG_VHT_RXSTBC, + cfg->vht_rx_stbc); + + if (status == QDF_STATUS_E_FAILURE) { + hdd_alert("could not set the VHT RX STBC to CCM"); + } + } + + /* Get VHT SU Beamformer cap */ + status = sme_cfg_get_int(hdd_ctx->hHal, WNI_CFG_VHT_SU_BEAMFORMER_CAP, + &value); + + if (status != QDF_STATUS_SUCCESS) { + hdd_err("could not get VHT SU BEAMFORMER CAP"); + value = 0; + } + + /* set VHT SU Beamformer cap */ + if (value && !cfg->vht_su_bformer) { + status = sme_cfg_set_int(hdd_ctx->hHal, + WNI_CFG_VHT_SU_BEAMFORMER_CAP, + cfg->vht_su_bformer); + + if (status == QDF_STATUS_E_FAILURE) { + hdd_alert("could not set VHT SU BEAMFORMER CAP"); + } + } + + /* check and update SU BEAMFORMEE capabality */ + if (pconfig->enableTxBF && !cfg->vht_su_bformee) + pconfig->enableTxBF = cfg->vht_su_bformee; + + status = sme_cfg_set_int(hdd_ctx->hHal, + WNI_CFG_VHT_SU_BEAMFORMEE_CAP, + pconfig->enableTxBF); + + if (status == QDF_STATUS_E_FAILURE) { + hdd_alert("could not set VHT SU BEAMFORMEE CAP"); + } + + /* Get VHT MU Beamformer cap */ + status = sme_cfg_get_int(hdd_ctx->hHal, WNI_CFG_VHT_MU_BEAMFORMER_CAP, + &value); + + if (status != QDF_STATUS_SUCCESS) { + hdd_err("could not get VHT MU BEAMFORMER CAP"); + value = 0; + } + + /* set VHT MU Beamformer cap */ + if (value && !cfg->vht_mu_bformer) { + status = sme_cfg_set_int(hdd_ctx->hHal, + WNI_CFG_VHT_MU_BEAMFORMER_CAP, + cfg->vht_mu_bformer); + + if (status == QDF_STATUS_E_FAILURE) { + hdd_alert("could not set the VHT MU BEAMFORMER CAP to CCM"); + } + } + + /* Get VHT MU Beamformee cap */ + status = sme_cfg_get_int(hdd_ctx->hHal, WNI_CFG_VHT_MU_BEAMFORMEE_CAP, + &value); + + if (status != QDF_STATUS_SUCCESS) { + hdd_err("could not get VHT MU BEAMFORMEE CAP"); + value = 0; + } + + /* set VHT MU Beamformee cap */ + if (value && !cfg->vht_mu_bformee) { + status = sme_cfg_set_int(hdd_ctx->hHal, + WNI_CFG_VHT_MU_BEAMFORMEE_CAP, + cfg->vht_mu_bformee); + + if (status == QDF_STATUS_E_FAILURE) { + hdd_alert("could not set VHT MU BEAMFORMER CAP"); + } + } + + /* Get VHT MAX AMPDU Len exp */ + status = sme_cfg_get_int(hdd_ctx->hHal, WNI_CFG_VHT_AMPDU_LEN_EXPONENT, + &value); + + if (status != QDF_STATUS_SUCCESS) { + hdd_err("could not get VHT AMPDU LEN"); + value = 0; + } + + /* + * VHT max AMPDU len exp: + * override if user configured value is too high + * that the target cannot support. + * Even though Rome publish ampdu_len=7, it can + * only support 4 because of some h/w bug. + */ + + if (value > cfg->vht_max_ampdu_len_exp) { + status = sme_cfg_set_int(hdd_ctx->hHal, + WNI_CFG_VHT_AMPDU_LEN_EXPONENT, + cfg->vht_max_ampdu_len_exp); + + if (status == QDF_STATUS_E_FAILURE) { + hdd_alert("could not set the VHT AMPDU LEN EXP"); + } + } + + /* Get VHT TXOP PS CAP */ + status = sme_cfg_get_int(hdd_ctx->hHal, WNI_CFG_VHT_TXOP_PS, &value); + + if (status != QDF_STATUS_SUCCESS) { + hdd_err("could not get VHT TXOP PS"); + value = 0; + } + + /* set VHT TXOP PS cap */ + if (value && !cfg->vht_txop_ps) { + status = sme_cfg_set_int(hdd_ctx->hHal, WNI_CFG_VHT_TXOP_PS, + cfg->vht_txop_ps); + + if (status == QDF_STATUS_E_FAILURE) { + hdd_alert("could not set the VHT TXOP PS"); + } + } + + if (WMI_VHT_CAP_MAX_MPDU_LEN_11454 == cfg->vht_max_mpdu) + band_5g->vht_cap.cap |= IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454; + else if (WMI_VHT_CAP_MAX_MPDU_LEN_7935 == cfg->vht_max_mpdu) + band_5g->vht_cap.cap |= IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991; + else + band_5g->vht_cap.cap |= IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_3895; + + + if (cfg->supp_chan_width & (1 << eHT_CHANNEL_WIDTH_80P80MHZ)) { + status = sme_cfg_set_int(hdd_ctx->hHal, + WNI_CFG_VHT_SUPPORTED_CHAN_WIDTH_SET, + VHT_CAP_160_AND_80P80_SUPP); + if (status == QDF_STATUS_E_FAILURE) + hdd_alert("could not set the VHT CAP 160"); + band_5g->vht_cap.cap |= + IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ; + ch_width = eHT_CHANNEL_WIDTH_80P80MHZ; + } else if (cfg->supp_chan_width & (1 << eHT_CHANNEL_WIDTH_160MHZ)) { + status = sme_cfg_set_int(hdd_ctx->hHal, + WNI_CFG_VHT_SUPPORTED_CHAN_WIDTH_SET, + VHT_CAP_160_SUPP); + if (status == QDF_STATUS_E_FAILURE) + hdd_alert("could not set the VHT CAP 160"); + band_5g->vht_cap.cap |= + IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ; + ch_width = eHT_CHANNEL_WIDTH_160MHZ; + } else { + status = sme_cfg_set_int(hdd_ctx->hHal, + WNI_CFG_VHT_SUPPORTED_CHAN_WIDTH_SET, + VHT_CAP_80_SUPP); + if (status == QDF_STATUS_E_FAILURE) + hdd_alert("could not set the VHT CH BW"); + } + pconfig->vhtChannelWidth = QDF_MIN(pconfig->vhtChannelWidth, + ch_width); + /* Get the current supported chan width */ + status = sme_cfg_get_int(hdd_ctx->hHal, + WNI_CFG_VHT_SUPPORTED_CHAN_WIDTH_SET, + &value); + if (status != QDF_STATUS_SUCCESS) { + hdd_err("could not get CH BW"); + value = 0; + } + /* set the Guard interval 160MHz */ + if (value) { + if (cfg->vht_short_gi_160 & WMI_VHT_CAP_SGI_160MHZ) + band_5g->vht_cap.cap |= IEEE80211_VHT_CAP_SHORT_GI_160; + value = cfg->vht_short_gi_160; + } else { + value = 0; + } + + status = sme_cfg_set_int(hdd_ctx->hHal, + WNI_CFG_VHT_SHORT_GI_160_AND_80_PLUS_80MHZ, + value); + + if (status == QDF_STATUS_E_FAILURE) + hdd_alert("failed to set SHORT GI 160MHZ"); + + if (cfg->vht_rx_ldpc & WMI_VHT_CAP_RX_LDPC) + band_5g->vht_cap.cap |= IEEE80211_VHT_CAP_RXLDPC; + + if (cfg->vht_short_gi_80 & WMI_VHT_CAP_SGI_80MHZ) + band_5g->vht_cap.cap |= IEEE80211_VHT_CAP_SHORT_GI_80; + + if (cfg->vht_tx_stbc & WMI_VHT_CAP_TX_STBC) + band_5g->vht_cap.cap |= IEEE80211_VHT_CAP_TXSTBC; + + if (cfg->vht_rx_stbc & WMI_VHT_CAP_RX_STBC_1SS) + band_5g->vht_cap.cap |= IEEE80211_VHT_CAP_RXSTBC_1; + if (cfg->vht_rx_stbc & WMI_VHT_CAP_RX_STBC_2SS) + band_5g->vht_cap.cap |= IEEE80211_VHT_CAP_RXSTBC_2; + if (cfg->vht_rx_stbc & WMI_VHT_CAP_RX_STBC_3SS) + band_5g->vht_cap.cap |= IEEE80211_VHT_CAP_RXSTBC_3; + + band_5g->vht_cap.cap |= + (cfg->vht_max_ampdu_len_exp << + IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT); + + if (cfg->vht_su_bformer & WMI_VHT_CAP_SU_BFORMER) + band_5g->vht_cap.cap |= IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE; + if (cfg->vht_su_bformee & WMI_VHT_CAP_SU_BFORMEE) + band_5g->vht_cap.cap |= IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE; + if (cfg->vht_mu_bformer & WMI_VHT_CAP_MU_BFORMER) + band_5g->vht_cap.cap |= IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE; + if (cfg->vht_mu_bformee & WMI_VHT_CAP_MU_BFORMEE) + band_5g->vht_cap.cap |= IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE; + + if (cfg->vht_txop_ps & WMI_VHT_CAP_TXOP_PS) + band_5g->vht_cap.cap |= IEEE80211_VHT_CAP_VHT_TXOP_PS; + +} + +/** + * hdd_generate_macaddr_auto() - Auto-generate mac address + * @hdd_ctx: Pointer to the HDD context + * + * Auto-generate mac address using device serial number. + * Keep the first 3 bytes of OUI as before and replace + * the last 3 bytes with the lower 3 bytes of serial number. + * + * Return: 0 for success + * Non zero failure code for errors + */ +static int hdd_generate_macaddr_auto(hdd_context_t *hdd_ctx) +{ + unsigned int serialno = 0; + struct qdf_mac_addr mac_addr = { + {0x00, 0x0A, 0xF5, 0x00, 0x00, 0x00} + }; + + serialno = pld_socinfo_get_serial_number(hdd_ctx->parent_dev); + if (serialno == 0) + return -EINVAL; + + serialno &= 0x00ffffff; + + mac_addr.bytes[3] = (serialno >> 16) & 0xff; + mac_addr.bytes[4] = (serialno >> 8) & 0xff; + mac_addr.bytes[5] = serialno & 0xff; + + hdd_update_macaddr(hdd_ctx->config, mac_addr); + return 0; +} + +/** + * hdd_update_ra_rate_limit() - Update RA rate limit from target + * configuration to cfg_ini in HDD + * @hdd_ctx: Pointer to hdd_ctx + * @cfg: target configuration + * + * Return: None + */ +#ifdef FEATURE_WLAN_RA_FILTERING +static void hdd_update_ra_rate_limit(hdd_context_t *hdd_ctx, + struct wma_tgt_cfg *cfg) +{ + hdd_ctx->config->IsRArateLimitEnabled = cfg->is_ra_rate_limit_enabled; +} +#else +static void hdd_update_ra_rate_limit(hdd_context_t *hdd_ctx, + struct wma_tgt_cfg *cfg) +{ +} +#endif + +void hdd_update_tgt_cfg(void *context, void *param) +{ + hdd_context_t *hdd_ctx = (hdd_context_t *) context; + struct wma_tgt_cfg *cfg = param; + uint8_t temp_band_cap; + struct cds_config_info *cds_cfg = cds_get_ini_config(); + uint8_t antenna_mode; + + if (cds_cfg) { + if (hdd_ctx->config->enable_sub_20_channel_width != + WLAN_SUB_20_CH_WIDTH_NONE && !cfg->sub_20_support) { + hdd_warn("User requested sub 20 MHz channel width but unsupported by FW."); + cds_cfg->sub_20_channel_width = + WLAN_SUB_20_CH_WIDTH_NONE; + } else { + cds_cfg->sub_20_channel_width = + hdd_ctx->config->enable_sub_20_channel_width; + } + } + + /* first store the INI band capability */ + temp_band_cap = hdd_ctx->config->nBandCapability; + + hdd_ctx->config->nBandCapability = cfg->band_cap; + + /* now overwrite the target band capability with INI + setting if INI setting is a subset */ + + if ((hdd_ctx->config->nBandCapability == eCSR_BAND_ALL) && + (temp_band_cap != eCSR_BAND_ALL)) + hdd_ctx->config->nBandCapability = temp_band_cap; + else if ((hdd_ctx->config->nBandCapability != eCSR_BAND_ALL) && + (temp_band_cap != eCSR_BAND_ALL) && + (hdd_ctx->config->nBandCapability != temp_band_cap)) { + hdd_warn("ini BandCapability not supported by the target"); + } + + if (!cds_is_driver_recovering()) { + hdd_ctx->reg.reg_domain = cfg->reg_domain; + hdd_ctx->reg.eeprom_rd_ext = cfg->eeprom_rd_ext; + } + + /* This can be extended to other configurations like ht, vht cap... */ + + if (!qdf_is_macaddr_zero(&cfg->hw_macaddr)) { + hdd_update_macaddr(hdd_ctx->config, cfg->hw_macaddr); + hdd_ctx->update_mac_addr_to_fw = false; + } else { + static struct qdf_mac_addr default_mac_addr = { + {0x00, 0x0A, 0xF5, 0x89, 0x89, 0xFF} + }; + if (qdf_is_macaddr_equal(&hdd_ctx->config->intfMacAddr[0], + &default_mac_addr)) { + if (hdd_generate_macaddr_auto(hdd_ctx) != 0) + hdd_warn("Fail to auto-generate MAC, using MAC from ini file " + MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(hdd_ctx->config-> + intfMacAddr[0].bytes)); + } else { + hdd_warn("Invalid MAC passed from target, using MAC from ini file " + MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(hdd_ctx->config-> + intfMacAddr[0].bytes)); + } + hdd_ctx->update_mac_addr_to_fw = true; + } + + hdd_ctx->target_fw_version = cfg->target_fw_version; + hdd_ctx->target_fw_vers_ext = cfg->target_fw_vers_ext; + + hdd_ctx->max_intf_count = cfg->max_intf_count; + + hdd_lpass_target_config(hdd_ctx, cfg); + hdd_green_ap_target_config(hdd_ctx, cfg); + + hdd_ctx->ap_arpns_support = cfg->ap_arpns_support; + hdd_update_tgt_services(hdd_ctx, &cfg->services); + + hdd_update_tgt_ht_cap(hdd_ctx, &cfg->ht_cap); + + hdd_update_tgt_vht_cap(hdd_ctx, &cfg->vht_cap); + + hdd_update_vdev_nss(hdd_ctx); + + hdd_update_hw_dbs_capable(hdd_ctx); + + hdd_ctx->config->fine_time_meas_cap &= cfg->fine_time_measurement_cap; + hdd_ctx->fine_time_meas_cap_target = cfg->fine_time_measurement_cap; + hdd_info("fine_time_meas_cap: 0x%x", + hdd_ctx->config->fine_time_meas_cap); + + antenna_mode = (hdd_ctx->config->enable2x2 == 0x01) ? + HDD_ANTENNA_MODE_2X2 : HDD_ANTENNA_MODE_1X1; + hdd_update_smps_antenna_mode(hdd_ctx, antenna_mode); + hdd_info("Init current antenna mode: %d", + hdd_ctx->current_antenna_mode); + + hdd_ctx->bpf_enabled = (cfg->bpf_enabled && + hdd_ctx->config->bpf_packet_filter_enable); + hdd_ctx->rcpi_enabled = cfg->rcpi_enabled; + hdd_update_ra_rate_limit(hdd_ctx, cfg); + + hdd_ctx->fw_mem_dump_enabled = cfg->fw_mem_dump_enabled; + + if ((hdd_ctx->config->txBFCsnValue > + WNI_CFG_VHT_CSN_BEAMFORMEE_ANT_SUPPORTED_FW_DEF) && + !cfg->tx_bfee_8ss_enabled) + hdd_ctx->config->txBFCsnValue = + WNI_CFG_VHT_CSN_BEAMFORMEE_ANT_SUPPORTED_FW_DEF; + + if (sme_cfg_set_int(hdd_ctx->hHal, + WNI_CFG_VHT_CSN_BEAMFORMEE_ANT_SUPPORTED, + hdd_ctx->config->txBFCsnValue) == QDF_STATUS_E_FAILURE) + hdd_err("fw update WNI_CFG_VHT_CSN_BEAMFORMEE_ANT_SUPPORTED to CFG fails"); + + + hdd_debug("Target BPF %d Host BPF %d 8ss fw support %d txBFCsnValue %d", + cfg->bpf_enabled, hdd_ctx->config->bpf_packet_filter_enable, + cfg->tx_bfee_8ss_enabled, hdd_ctx->config->txBFCsnValue); + /* + * If BPF is enabled, maxWowFilters set to WMA_STA_WOW_DEFAULT_PTRN_MAX + * because we need atleast WMA_STA_WOW_DEFAULT_PTRN_MAX free slots to + * configure the STA mode wow pattern. + */ + if (hdd_ctx->bpf_enabled) + hdd_ctx->config->maxWoWFilters = WMA_STA_WOW_DEFAULT_PTRN_MAX; + + hdd_ctx->wmi_max_len = cfg->wmi_max_len; + + /* Configure NAN datapath features */ + hdd_nan_datapath_target_config(hdd_ctx, cfg); +} + +/** + * hdd_dfs_indicate_radar() - handle radar detection on current SAP channel + * @context: HDD context pointer + * @param: HDD radar indication pointer + * + * This function is invoked in atomic context when a radar + * is found on the SAP current operating channel and Data Tx + * from netif has to be stopped to honor the DFS regulations. + * Actions: Stop the netif Tx queues,Indicate Radar present + * in HDD context for future usage. + * + * Return: true to allow radar indication to host else false + */ +bool hdd_dfs_indicate_radar(void *context, void *param) +{ + hdd_context_t *hdd_ctx = (hdd_context_t *) context; + struct wma_dfs_radar_ind *hdd_radar_event = + (struct wma_dfs_radar_ind *)param; + hdd_adapter_list_node_t *adapterNode = NULL, *pNext = NULL; + hdd_adapter_t *adapter; + QDF_STATUS status; + hdd_ap_ctx_t *ap_ctx; + + if (!hdd_ctx || !hdd_radar_event || + hdd_ctx->config->disableDFSChSwitch) + return true; + + if (true == hdd_radar_event->dfs_radar_status) { + if (qdf_atomic_inc_return(&hdd_ctx->dfs_radar_found) > 1) { + /* + * Application already triggered channel switch + * on current channel, so return here. + */ + return false; + } + + status = hdd_get_front_adapter(hdd_ctx, &adapterNode); + while (NULL != adapterNode && QDF_STATUS_SUCCESS == status) { + adapter = adapterNode->pAdapter; + ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(adapter); + if ((QDF_SAP_MODE == adapter->device_mode || + QDF_P2P_GO_MODE == adapter->device_mode) && + (CHANNEL_STATE_DFS == + cds_get_channel_state(ap_ctx->operatingChannel))) { + WLAN_HDD_GET_AP_CTX_PTR(adapter)-> + dfs_cac_block_tx = true; + hdd_info("tx blocked for session:%d", + adapter->sessionId); + } + + status = hdd_get_next_adapter(hdd_ctx, + adapterNode, + &pNext); + adapterNode = pNext; + } + } + + return true; +} + +/** + * hdd_is_valid_mac_address() - validate MAC address + * @pMacAddr: Pointer to the input MAC address + * + * This function validates whether the given MAC address is valid or not + * Expected MAC address is of the format XX:XX:XX:XX:XX:XX + * where X is the hexa decimal digit character and separated by ':' + * This algorithm works even if MAC address is not separated by ':' + * + * This code checks given input string mac contains exactly 12 hexadecimal + * digits and a separator colon : appears in the input string only after + * an even number of hex digits. + * + * Return: 1 for valid and 0 for invalid + */ +bool hdd_is_valid_mac_address(const uint8_t *pMacAddr) +{ + int xdigit = 0; + int separator = 0; + while (*pMacAddr) { + if (isxdigit(*pMacAddr)) { + xdigit++; + } else if (':' == *pMacAddr) { + if (0 == xdigit || ((xdigit / 2) - 1) != separator) + break; + + ++separator; + } else { + /* Invalid MAC found */ + return 0; + } + ++pMacAddr; + } + return xdigit == 12 && (separator == 5 || separator == 0); +} + +/** + * hdd_mon_mode_ether_setup() - Update monitor mode struct net_device. + * @dev: Handle to struct net_device to be updated. + * + * Return: None + */ +static void hdd_mon_mode_ether_setup(struct net_device *dev) +{ + dev->header_ops = NULL; + dev->type = ARPHRD_IEEE80211_RADIOTAP; + dev->hard_header_len = ETH_HLEN; + dev->mtu = ETH_DATA_LEN; + dev->addr_len = ETH_ALEN; + dev->tx_queue_len = 1000; /* Ethernet wants good queues */ + dev->flags = IFF_BROADCAST|IFF_MULTICAST; + dev->priv_flags |= IFF_TX_SKB_SHARING; + + memset(dev->broadcast, 0xFF, ETH_ALEN); +} + +/** + * __hdd__mon_open() - HDD Open function + * @dev: Pointer to net_device structure + * + * This is called in response to ifconfig up + * + * Return: 0 for success; non-zero for failure + */ +static int __hdd_mon_open(struct net_device *dev) +{ + int ret; + + ENTER_DEV(dev); + hdd_mon_mode_ether_setup(dev); + ret = hdd_set_mon_rx_cb(dev); + return ret; +} + +/** + * hdd_mon_open() - Wrapper function for __hdd_mon_open to protect it from SSR + * @dev: Pointer to net_device structure + * + * This is called in response to ifconfig up + * + * Return: 0 for success; non-zero for failure + */ +static int hdd_mon_open(struct net_device *dev) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __hdd_mon_open(dev); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * hdd_start_adapter() - Wrapper function for device specific adapter + * @adapter: pointer to HDD adapter + * + * This function is called to start the device specific adapter for + * the mode passed in the adapter's device_mode. + * + * Return: 0 for success; non-zero for failure + */ +int hdd_start_adapter(hdd_adapter_t *adapter) +{ + + int ret; + enum tQDF_ADAPTER_MODE device_mode = adapter->device_mode; + + ENTER_DEV(adapter->dev); + hdd_info("Start_adapter for mode : %d", adapter->device_mode); + + switch (device_mode) { + case QDF_P2P_CLIENT_MODE: + case QDF_P2P_DEVICE_MODE: + case QDF_OCB_MODE: + case QDF_STA_MODE: + case QDF_MONITOR_MODE: + ret = hdd_start_station_adapter(adapter); + if (ret) + goto err_start_adapter; + break; + case QDF_P2P_GO_MODE: + case QDF_SAP_MODE: + ret = hdd_start_ap_adapter(adapter); + if (ret) + goto err_start_adapter; + break; + case QDF_IBSS_MODE: + /* + * For IBSS interface is initialized as part of + * hdd_init_station_mode() + */ + return 0; + case QDF_FTM_MODE: + ret = hdd_start_ftm_adapter(adapter); + if (ret) + goto err_start_adapter; + goto exit; + default: + hdd_err("Invalid session type %d", device_mode); + QDF_ASSERT(0); + goto err_start_adapter; + } + if (hdd_set_fw_params(adapter)) + hdd_err("Failed to set the FW params for the adapter!"); + + /* + * Action frame registered in one adapter which will + * applicable to all interfaces + */ + wlan_hdd_cfg80211_register_frames(adapter); +exit: + EXIT(); + return 0; +err_start_adapter: + return -EINVAL; +} + +/** + * hdd_enable_power_management() - API to Enable Power Management + * + * API invokes Bus Interface Layer power management functionality + * + * Return: None + */ +static void hdd_enable_power_management(void) +{ + void *hif_ctx = cds_get_context(QDF_MODULE_ID_HIF); + + if (!hif_ctx) { + hdd_err("Bus Interface Context is Invalid"); + return; + } + + hif_enable_power_management(hif_ctx, cds_is_packet_log_enabled()); +} + +/** + * hdd_disable_power_management() - API to disable Power Management + * + * API disable Bus Interface Layer Power management functionality + * + * Return: None + */ +static void hdd_disable_power_management(void) +{ + void *hif_ctx = cds_get_context(QDF_MODULE_ID_HIF); + + if (!hif_ctx) { + hdd_err("Bus Interface Context is Invalid"); + return; + } + + hif_disable_power_management(hif_ctx); +} + +/** + * hdd_update_hw_sw_info() - API to update the HW/SW information + * + * API to update the HW and SW information in the driver + * + * Return: None + */ +static void hdd_update_hw_sw_info(hdd_context_t *hdd_ctx) +{ + void *hif_sc; + + hif_sc = cds_get_context(QDF_MODULE_ID_HIF); + if (!hif_sc) { + hdd_err("HIF context is NULL"); + return; + } + + /* + * target hw version/revision would only be retrieved after firmware + * download + */ + hif_get_hw_info(hif_sc, &hdd_ctx->target_hw_version, + &hdd_ctx->target_hw_revision, + &hdd_ctx->target_hw_name); + + /* Get the wlan hw/fw version */ + hdd_wlan_get_version(hdd_ctx, NULL, NULL); + + return; +} + +/** + * hdd_wlan_start_modules() - Single driver state machine for starting modules + * @hdd_ctx: HDD context + * @adapter: HDD adapter + * @reinit: flag to indicate from SSR or normal path + * + * This function maintains the driver state machine it will be invoked from + * startup, reinit and change interface. Depending on the driver state shall + * perform the opening of the modules. + * + * Return: 0 for success; non-zero for failure + */ +int hdd_wlan_start_modules(hdd_context_t *hdd_ctx, hdd_adapter_t *adapter, + bool reinit) +{ + int ret; + qdf_device_t qdf_dev; + QDF_STATUS status; + p_cds_contextType p_cds_context; + bool unint = false; + void *hif_ctx; + + ENTER(); + + p_cds_context = cds_get_global_context(); + if (!p_cds_context) { + hdd_err("Global Context is NULL"); + QDF_ASSERT(0); + return -EINVAL; + } + + hdd_info("start modules called in state! :%d reinit: %d", + hdd_ctx->driver_status, reinit); + + qdf_dev = cds_get_context(QDF_MODULE_ID_QDF_DEVICE); + if (!qdf_dev) { + hdd_err("QDF Device Context is Invalid return"); + return -EINVAL; + } + + mutex_lock(&hdd_ctx->iface_change_lock); + hdd_ctx->start_modules_in_progress = true; + + if (QDF_TIMER_STATE_RUNNING == + qdf_mc_timer_get_current_state(&hdd_ctx->iface_change_timer)) { + + hdd_info("Interface change Timer running Stop timer"); + qdf_mc_timer_stop(&hdd_ctx->iface_change_timer); + } + + switch (hdd_ctx->driver_status) { + case DRIVER_MODULES_UNINITIALIZED: + unint = true; + /* Fall through dont add break here */ + case DRIVER_MODULES_CLOSED: + if (!reinit && !unint) { + ret = pld_power_on(qdf_dev->dev); + if (ret) { + hdd_err("Failed to Powerup the device: %d", ret); + goto release_lock; + } + } + ret = hdd_hif_open(qdf_dev->dev, qdf_dev->drv_hdl, qdf_dev->bid, + qdf_dev->bus_type, + (reinit == true) ? HIF_ENABLE_TYPE_REINIT : + HIF_ENABLE_TYPE_PROBE); + if (ret) { + hdd_err("Failed to open hif: %d", ret); + goto power_down; + } + + hif_ctx = cds_get_context(QDF_MODULE_ID_HIF); + if (!hif_ctx) { + hdd_err("hif context is null!!"); + goto power_down; + } + + status = ol_cds_init(qdf_dev, hif_ctx); + if (status != QDF_STATUS_SUCCESS) { + hdd_err("No Memory to Create BMI Context :%d", status); + goto hif_close; + } + + ret = hdd_update_config(hdd_ctx); + if (ret) { + hdd_err("Failed to update configuration :%d", ret); + goto ol_cds_free; + } + + status = cds_open(); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("Failed to Open CDS: %d", status); + goto ol_cds_free; + } + + hdd_ctx->hHal = cds_get_context(QDF_MODULE_ID_SME); + + status = cds_pre_enable(hdd_ctx->pcds_context); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("Failed to pre-enable CDS: %d", status); + goto close; + } + + hdd_ctx->driver_status = DRIVER_MODULES_OPENED; + hdd_update_hw_sw_info(hdd_ctx); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + sme_register_ftm_msg_processor(hdd_ctx->hHal, + hdd_ftm_mc_process_msg); + break; + } + if (unint) { + hdd_info("In phase-1 initialization don't enable modules"); + break; + } + + if (reinit) { + if (hdd_ipa_uc_ssr_reinit(hdd_ctx)) { + hdd_err("HDD IPA UC reinit failed"); + goto post_disable; + } + } + + /* Fall through dont add break here */ + case DRIVER_MODULES_OPENED: + if (!adapter) { + hdd_alert("adapter is Null"); + goto post_disable; + } + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("in ftm mode, no need to configure cds modules"); + break; + } + if (hdd_configure_cds(hdd_ctx, adapter)) { + hdd_err("Failed to Enable cds modules"); + goto post_disable; + } + hdd_enable_power_management(); + hdd_info("Driver Modules Successfully Enabled"); + hdd_ctx->driver_status = DRIVER_MODULES_ENABLED; + break; + case DRIVER_MODULES_ENABLED: + hdd_info("Driver modules already Enabled"); + break; + default: + hdd_err("WLAN start invoked in wrong state! :%d\n", + hdd_ctx->driver_status); + goto release_lock; + } + hdd_ctx->start_modules_in_progress = false; + mutex_unlock(&hdd_ctx->iface_change_lock); + EXIT(); + return 0; + +post_disable: + cds_post_disable(); + +close: + hdd_ctx->driver_status = DRIVER_MODULES_CLOSED; + cds_close(p_cds_context); + +ol_cds_free: + ol_cds_free(); + +hif_close: + hdd_hif_close(p_cds_context->pHIFContext); +power_down: + if (!reinit && !unint) + pld_power_off(qdf_dev->dev); +release_lock: + hdd_ctx->start_modules_in_progress = false; + mutex_unlock(&hdd_ctx->iface_change_lock); + EXIT(); + + return -EINVAL; +} + +/** + * __hdd_open() - HDD Open function + * @dev: Pointer to net_device structure + * + * This is called in response to ifconfig up + * + * Return: 0 for success; non-zero for failure + */ +static int __hdd_open(struct net_device *dev) +{ + hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + int ret; + + ENTER_DEV(dev); + MTRACE(qdf_trace(QDF_MODULE_ID_HDD, TRACE_CODE_HDD_OPEN_REQUEST, + adapter->sessionId, adapter->device_mode)); + + mutex_lock(&hdd_init_deinit_lock); + + /* + * This scenario can be hit in cases where in the wlan driver after + * registering the netdevices and there is a failure in driver + * initialization. So return error gracefully because the netdevices + * will be de-registered as part of the load failure. + */ + if (!cds_is_driver_loaded()) { + hdd_err("Failed to start the wlan driver!!"); + ret = -EIO; + goto err_hdd_hdd_init_deinit_lock; + } + + + ret = hdd_wlan_start_modules(hdd_ctx, adapter, false); + if (ret) { + hdd_err("Failed to start WLAN modules return"); + goto err_hdd_hdd_init_deinit_lock; + } + + + if (!test_bit(SME_SESSION_OPENED, &adapter->event_flags)) { + ret = hdd_start_adapter(adapter); + if (ret) { + hdd_err("Failed to start adapter :%d", + adapter->device_mode); + goto err_hdd_hdd_init_deinit_lock; + } + } + + set_bit(DEVICE_IFACE_OPENED, &adapter->event_flags); + + if (hdd_conn_is_connected(WLAN_HDD_GET_STATION_CTX_PTR(adapter))) { + hdd_info("Enabling Tx Queues"); + /* Enable TX queues only when we are connected */ + wlan_hdd_netif_queue_control(adapter, + WLAN_START_ALL_NETIF_QUEUE, + WLAN_CONTROL_PATH); + } + + /* Enable carrier and transmit queues for NDI */ + if (WLAN_HDD_IS_NDI(adapter)) { + hdd_notice("Enabling Tx Queues"); + wlan_hdd_netif_queue_control(adapter, + WLAN_START_ALL_NETIF_QUEUE_N_CARRIER, + WLAN_CONTROL_PATH); + } + +err_hdd_hdd_init_deinit_lock: + mutex_unlock(&hdd_init_deinit_lock); + return ret; +} + + +/** + * hdd_open() - Wrapper function for __hdd_open to protect it from SSR + * @dev: Pointer to net_device structure + * + * This is called in response to ifconfig up + * + * Return: 0 for success; non-zero for failure + */ +static int hdd_open(struct net_device *dev) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __hdd_open(dev); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __hdd_stop() - HDD stop function + * @dev: Pointer to net_device structure + * + * This is called in response to ifconfig down + * + * Return: 0 for success; non-zero for failure + */ +static int __hdd_stop(struct net_device *dev) +{ + hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + int ret; + + ENTER_DEV(dev); + + MTRACE(qdf_trace(QDF_MODULE_ID_HDD, TRACE_CODE_HDD_STOP_REQUEST, + adapter->sessionId, adapter->device_mode)); + + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + /* Nothing to be done if the interface is not opened */ + if (false == test_bit(DEVICE_IFACE_OPENED, &adapter->event_flags)) { + hdd_err("NETDEV Interface is not OPENED"); + return -ENODEV; + } + + /* + * Disable TX on the interface, after this hard_start_xmit() will not + * be called on that interface + */ + hdd_notice("Disabling queues"); + wlan_hdd_netif_queue_control(adapter, + WLAN_STOP_ALL_NETIF_QUEUE_N_CARRIER, + WLAN_CONTROL_PATH); + + /* + * NAN data interface is different in some sense. The traffic on NDI is + * bursty in nature and depends on the need to transfer. The service + * layer may down the interface after the usage and up again when + * required. In some sense, the NDI is expected to be available + * (like SAP) iface until NDI delete request is issued by the service + * layer. Skip BSS termination and adapter deletion for NAN Data + * interface (NDI). + */ + if (WLAN_HDD_IS_NDI(adapter)) + return 0; + + /* + * The interface is marked as down for outside world (aka kernel) + * But the driver is pretty much alive inside. The driver needs to + * tear down the existing connection on the netdev (session) + * cleanup the data pipes and wait until the control plane is stabilized + * for this interface. The call also needs to wait until the above + * mentioned actions are completed before returning to the caller. + * Notice that the hdd_stop_adapter is requested not to close the session + * That is intentional to be able to scan if it is a STA/P2P interface + */ + hdd_stop_adapter(hdd_ctx, adapter, true); + + /* DeInit the adapter. This ensures datapath cleanup as well */ + hdd_deinit_adapter(hdd_ctx, adapter, true); + + /* Make sure the interface is marked as closed */ + clear_bit(DEVICE_IFACE_OPENED, &adapter->event_flags); + + /* + * Find if any iface is up. If any iface is up then can't put device to + * sleep/power save mode + */ + if (hdd_check_for_opened_interfaces(hdd_ctx)) { + hdd_info("Closing all modules from the hdd_stop"); + qdf_mc_timer_start(&hdd_ctx->iface_change_timer, + hdd_ctx->config->iface_change_wait_time); + } + + EXIT(); + return 0; +} + +/** + * hdd_stop() - Wrapper function for __hdd_stop to protect it from SSR + * @dev: pointer to net_device structure + * + * This is called in response to ifconfig down + * + * Return: 0 for success and error number for failure + */ +static int hdd_stop(struct net_device *dev) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __hdd_stop(dev); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __hdd_uninit() - HDD uninit function + * @dev: Pointer to net_device structure + * + * This is called during the netdev unregister to uninitialize all data + * associated with the device + * + * Return: None + */ +static void __hdd_uninit(struct net_device *dev) +{ + hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + + ENTER_DEV(dev); + + do { + if (WLAN_HDD_ADAPTER_MAGIC != adapter->magic) { + hdd_alert("Invalid magic"); + break; + } + + if (NULL == adapter->pHddCtx) { + hdd_alert("NULL hdd_ctx"); + break; + } + + if (dev != adapter->dev) { + hdd_alert("Invalid device reference"); + /* + * we haven't validated all cases so let this go for + * now + */ + } + + hdd_deinit_adapter(adapter->pHddCtx, adapter, true); + + /* after uninit our adapter structure will no longer be valid */ + adapter->dev = NULL; + adapter->magic = 0; + } while (0); + + EXIT(); +} + +/** + * hdd_uninit() - Wrapper function to protect __hdd_uninit from SSR + * @dev: pointer to net_device structure + * + * This is called during the netdev unregister to uninitialize all data + * associated with the device + * + * Return: none + */ +static void hdd_uninit(struct net_device *dev) +{ + cds_ssr_protect(__func__); + __hdd_uninit(dev); + cds_ssr_unprotect(__func__); +} + +static int hdd_open_cesium_nl_sock(void) +{ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) + struct netlink_kernel_cfg cfg = { + .groups = WLAN_NLINK_MCAST_GRP_ID, + .input = NULL + }; +#endif + int ret = 0; + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) + cesium_nl_srv_sock = netlink_kernel_create(&init_net, WLAN_NLINK_CESIUM, +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 7, 0)) + THIS_MODULE, +#endif + &cfg); +#else + cesium_nl_srv_sock = netlink_kernel_create(&init_net, WLAN_NLINK_CESIUM, + WLAN_NLINK_MCAST_GRP_ID, + NULL, NULL, THIS_MODULE); +#endif + + if (cesium_nl_srv_sock == NULL) { + hdd_err("NLINK: cesium netlink_kernel_create failed"); + ret = -ECONNREFUSED; + } + + return ret; +} + +static void hdd_close_cesium_nl_sock(void) +{ + if (NULL != cesium_nl_srv_sock) { + netlink_kernel_release(cesium_nl_srv_sock); + cesium_nl_srv_sock = NULL; + } +} + +/** + * __hdd_set_mac_address() - set the user specified mac address + * @dev: Pointer to the net device. + * @addr: Pointer to the sockaddr. + * + * This function sets the user specified mac address using + * the command ifconfig wlanX hw ether . + * + * Return: 0 for success, non zero for failure + */ +static int __hdd_set_mac_address(struct net_device *dev, void *addr) +{ + hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *hdd_ctx; + struct sockaddr *psta_mac_addr = addr; + QDF_STATUS qdf_ret_status = QDF_STATUS_SUCCESS; + int ret; + + ENTER_DEV(dev); + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + memcpy(&adapter->macAddressCurrent, psta_mac_addr->sa_data, ETH_ALEN); + memcpy(dev->dev_addr, psta_mac_addr->sa_data, ETH_ALEN); + + EXIT(); + return qdf_ret_status; +} + +/** + * hdd_set_mac_address() - Wrapper function to protect __hdd_set_mac_address() + * function from SSR + * @dev: pointer to net_device structure + * @addr: Pointer to the sockaddr + * + * This function sets the user specified mac address using + * the command ifconfig wlanX hw ether . + * + * Return: 0 for success. + */ +static int hdd_set_mac_address(struct net_device *dev, void *addr) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __hdd_set_mac_address(dev, addr); + cds_ssr_unprotect(__func__); + + return ret; +} + +uint8_t *wlan_hdd_get_intf_addr(hdd_context_t *hdd_ctx) +{ + int i; + for (i = 0; i < QDF_MAX_CONCURRENCY_PERSONA; i++) { + if (0 == ((hdd_ctx->config->intfAddrMask) & (1 << i))) + break; + } + + if (QDF_MAX_CONCURRENCY_PERSONA == i) + return NULL; + + hdd_ctx->config->intfAddrMask |= (1 << i); + return &hdd_ctx->config->intfMacAddr[i].bytes[0]; +} + +void wlan_hdd_release_intf_addr(hdd_context_t *hdd_ctx, uint8_t *releaseAddr) +{ + int i; + for (i = 0; i < QDF_MAX_CONCURRENCY_PERSONA; i++) { + if (!memcmp(releaseAddr, + &hdd_ctx->config->intfMacAddr[i].bytes[0], + 6)) { + hdd_ctx->config->intfAddrMask &= ~(1 << i); + break; + } + } + return; +} + +#ifdef WLAN_FEATURE_PACKET_FILTERING +/** + * __hdd_set_multicast_list() - set the multicast address list + * @dev: Pointer to the WLAN device. + * @skb: Pointer to OS packet (sk_buff). + * + * This funciton sets the multicast address list. + * + * Return: None + */ +static void __hdd_set_multicast_list(struct net_device *dev) +{ + hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + int mc_count; + int i = 0, status; + struct netdev_hw_addr *ha; + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + static const uint8_t ipv6_router_solicitation[] + = {0x33, 0x33, 0x00, 0x00, 0x00, 0x02}; + + ENTER_DEV(dev); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) + return; + + status = wlan_hdd_validate_context(hdd_ctx); + if (0 != status) + return; + + if (!hdd_ctx->config->fEnableMCAddrList) { + hdd_info("gMCAddrListEnable ini param not enabled"); + adapter->mc_addr_list.mc_cnt = 0; + return; + } + + /* Delete already configured multicast address list */ + if (adapter->mc_addr_list.mc_cnt > 0) + if (wlan_hdd_set_mc_addr_list(adapter, false)) { + hdd_info("failed to clear mc addr list"); + return; + } + + if (dev->flags & IFF_ALLMULTI) { + hdd_notice("allow all multicast frames"); + adapter->mc_addr_list.mc_cnt = 0; + } else { + mc_count = netdev_mc_count(dev); + hdd_notice("mc_count : %u", mc_count); + + if (mc_count > WLAN_HDD_MAX_MC_ADDR_LIST) { + hdd_notice("Exceeded max MC filter addresses (%d). Allowing all MC frames by disabling MC address filtering", + WLAN_HDD_MAX_MC_ADDR_LIST); + + if (wlan_hdd_set_mc_addr_list(adapter, false)) + hdd_info("failed to clear mc addr list"); + + adapter->mc_addr_list.mc_cnt = 0; + return; + } + + adapter->mc_addr_list.mc_cnt = mc_count; + + netdev_for_each_mc_addr(ha, dev) { + hdd_notice("ha_addr[%d] "MAC_ADDRESS_STR, + i, MAC_ADDR_ARRAY(ha->addr)); + + if (i == mc_count) + break; + /* + * Skip following addresses: + * 1)IPv6 router solicitation address + * 2)Any other address pattern if its set during + * RXFILTER REMOVE driver command based on + * addr_filter_pattern + */ + if ((!memcmp(ha->addr, ipv6_router_solicitation, + ETH_ALEN)) || + (adapter->addr_filter_pattern && (!memcmp(ha->addr, + &adapter->addr_filter_pattern, 1)))) { + hdd_info("MC/BC filtering Skip addr ="MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(ha->addr)); + adapter->mc_addr_list.mc_cnt--; + continue; + } + + memset(&(adapter->mc_addr_list.addr[i][0]), 0, + ETH_ALEN); + memcpy(&(adapter->mc_addr_list.addr[i][0]), ha->addr, + ETH_ALEN); + hdd_notice("mlist[%d] = " MAC_ADDRESS_STR, i, + MAC_ADDR_ARRAY(adapter->mc_addr_list.addr[i])); + i++; + } + } + if (hdd_ctx->config->active_mode_offload) { + hdd_info("enable mc filtering"); + if (wlan_hdd_set_mc_addr_list(adapter, true)) + hdd_err("Failed: to set mc addr list"); + } else { + hdd_info("skip mc filtering enable it during cfg80211 suspend"); + } + EXIT(); + return; +} + +/** + * hdd_set_multicast_list() - SSR wrapper function for __hdd_set_multicast_list + * @dev: pointer to net_device + * + * Return: none + */ +static void hdd_set_multicast_list(struct net_device *dev) +{ + cds_ssr_protect(__func__); + __hdd_set_multicast_list(dev); + cds_ssr_unprotect(__func__); +} +#endif + +/** + * hdd_select_queue() - used by Linux OS to decide which queue to use first + * @dev: Pointer to the WLAN device. + * @skb: Pointer to OS packet (sk_buff). + * + * This function is registered with the Linux OS for network + * core to decide which queue to use first. + * + * Return: ac, Queue Index/access category corresponding to UP in IP header + */ +static uint16_t hdd_select_queue(struct net_device *dev, struct sk_buff *skb +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0)) + , void *accel_priv +#endif +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) + , select_queue_fallback_t fallback +#endif +) +{ + return hdd_wmm_select_queue(dev, skb); +} + +static struct net_device_ops wlan_drv_ops = { + .ndo_open = hdd_open, + .ndo_stop = hdd_stop, + .ndo_uninit = hdd_uninit, + .ndo_start_xmit = hdd_hard_start_xmit, + .ndo_tx_timeout = hdd_tx_timeout, + .ndo_get_stats = hdd_get_stats, + .ndo_do_ioctl = hdd_ioctl, + .ndo_set_mac_address = hdd_set_mac_address, + .ndo_select_queue = hdd_select_queue, +#ifdef WLAN_FEATURE_PACKET_FILTERING + .ndo_set_rx_mode = hdd_set_multicast_list, +#endif +}; + +/* Monitor mode net_device_ops, doesnot Tx and most of operations. */ +static struct net_device_ops wlan_mon_drv_ops = { + .ndo_open = hdd_mon_open, + .ndo_stop = hdd_stop, + .ndo_get_stats = hdd_get_stats, +}; + +/** + * hdd_set_station_ops() - update net_device ops for monitor mode + * @pWlanDev: Handle to struct net_device to be updated. + * Return: None + */ +void hdd_set_station_ops(struct net_device *pWlanDev) +{ + if (QDF_GLOBAL_MONITOR_MODE == cds_get_conparam()) + pWlanDev->netdev_ops = &wlan_mon_drv_ops; + else + pWlanDev->netdev_ops = &wlan_drv_ops; +} + +#ifdef FEATURE_RUNTIME_PM +/** + * hdd_runtime_suspend_context_init() - API to initialize HDD Runtime Contexts + * @hdd_ctx: HDD context + * + * Return: None + */ +static void hdd_runtime_suspend_context_init(hdd_context_t *hdd_ctx) +{ + struct hdd_runtime_pm_context *ctx = &hdd_ctx->runtime_context; + + qdf_runtime_lock_init(&ctx->scan); + qdf_runtime_lock_init(&ctx->roc); + qdf_runtime_lock_init(&ctx->dfs); +} + +/** + * hdd_runtime_suspend_context_deinit() - API to deinit HDD runtime context + * @hdd_ctx: HDD Context + * + * Return: None + */ +static void hdd_runtime_suspend_context_deinit(hdd_context_t *hdd_ctx) +{ + struct hdd_runtime_pm_context *ctx = &hdd_ctx->runtime_context; + + qdf_runtime_lock_deinit(&ctx->scan); + qdf_runtime_lock_deinit(&ctx->roc); + qdf_runtime_lock_deinit(&ctx->dfs); +} + +static void hdd_adapter_runtime_suspend_init(hdd_adapter_t *adapter) +{ + struct hdd_connect_pm_context *ctx = &adapter->connect_rpm_ctx; + + qdf_runtime_lock_init(&ctx->connect); +} + +static void hdd_adapter_runtime_suspend_denit(hdd_adapter_t *adapter) +{ + struct hdd_connect_pm_context *ctx = &adapter->connect_rpm_ctx; + + qdf_runtime_lock_deinit(&ctx->connect); + ctx->connect = NULL; +} +#else /* FEATURE_RUNTIME_PM */ +static void hdd_runtime_suspend_context_init(hdd_context_t *hdd_ctx) {} +static void hdd_runtime_suspend_context_deinit(hdd_context_t *hdd_ctx) {} +static inline void hdd_adapter_runtime_suspend_init(hdd_adapter_t *adapter) {} +static inline void hdd_adapter_runtime_suspend_denit(hdd_adapter_t *adapter) {} +#endif /* FEATURE_RUNTIME_PM */ +/** + * hdd_alloc_station_adapter() - allocate the station hdd adapter + * @hdd_ctx: global hdd context + * @macAddr: mac address to assign to the interface + * @name: User-visible name of the interface + * + * hdd adapter pointer would point to the netdev->priv space, this function + * would retrive the pointer, and setup the hdd adapter configuration. + * + * Return: the pointer to hdd adapter, otherwise NULL + */ +static hdd_adapter_t *hdd_alloc_station_adapter(hdd_context_t *hdd_ctx, + tSirMacAddr macAddr, + unsigned char name_assign_type, + const char *name) +{ + struct net_device *pWlanDev = NULL; + hdd_adapter_t *adapter = NULL; + /* + * cfg80211 initialization and registration.... + */ + pWlanDev = alloc_netdev_mq(sizeof(hdd_adapter_t), name, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 17, 0)) || defined(WITH_BACKPORTS) + name_assign_type, +#endif + (QDF_GLOBAL_MONITOR_MODE == cds_get_conparam() ? + hdd_mon_mode_ether_setup : ether_setup), + NUM_TX_QUEUES); + + if (pWlanDev != NULL) { + + /* Save the pointer to the net_device in the HDD adapter */ + adapter = (hdd_adapter_t *) netdev_priv(pWlanDev); + + qdf_mem_zero(adapter, sizeof(hdd_adapter_t)); + + adapter->dev = pWlanDev; + adapter->pHddCtx = hdd_ctx; + adapter->magic = WLAN_HDD_ADAPTER_MAGIC; + adapter->sessionId = HDD_SESSION_ID_INVALID; + + init_completion(&adapter->session_open_comp_var); + init_completion(&adapter->session_close_comp_var); + init_completion(&adapter->disconnect_comp_var); + init_completion(&adapter->roaming_comp_var); + init_completion(&adapter->linkup_event_var); + init_completion(&adapter->cancel_rem_on_chan_var); + init_completion(&adapter->rem_on_chan_ready_event); + init_completion(&adapter->sta_authorized_event); + init_completion(&adapter->offchannel_tx_event); + init_completion(&adapter->tx_action_cnf_event); +#ifdef FEATURE_WLAN_TDLS + init_completion(&adapter->tdls_add_station_comp); + init_completion(&adapter->tdls_del_station_comp); + init_completion(&adapter->tdls_mgmt_comp); + init_completion(&adapter->tdls_link_establish_req_comp); +#endif + init_completion(&adapter->ibss_peer_info_comp); + init_completion(&adapter->change_country_code); + + + init_completion(&adapter->scan_info.abortscan_event_var); + init_completion(&adapter->lfr_fw_status.disable_lfr_event); + + adapter->offloads_configured = false; + adapter->isLinkUpSvcNeeded = false; + adapter->higherDtimTransition = true; + /* Init the net_device structure */ + strlcpy(pWlanDev->name, name, IFNAMSIZ); + + qdf_mem_copy(pWlanDev->dev_addr, (void *)macAddr, + sizeof(tSirMacAddr)); + qdf_mem_copy(adapter->macAddressCurrent.bytes, macAddr, + sizeof(tSirMacAddr)); + pWlanDev->watchdog_timeo = HDD_TX_TIMEOUT; + + if (hdd_ctx->config->enable_ip_tcp_udp_checksum_offload) + pWlanDev->features |= + NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM; + pWlanDev->features |= NETIF_F_RXCSUM; + + hdd_set_tso_flags(hdd_ctx, pWlanDev); + + hdd_set_station_ops(adapter->dev); + + pWlanDev->destructor = free_netdev; + pWlanDev->ieee80211_ptr = &adapter->wdev; + pWlanDev->tx_queue_len = HDD_NETDEV_TX_QUEUE_LEN; + adapter->wdev.wiphy = hdd_ctx->wiphy; + adapter->wdev.netdev = pWlanDev; + /* set pWlanDev's parent to underlying device */ + SET_NETDEV_DEV(pWlanDev, hdd_ctx->parent_dev); + hdd_wmm_init(adapter); + hdd_adapter_runtime_suspend_init(adapter); + spin_lock_init(&adapter->pause_map_lock); + adapter->start_time = adapter->last_time = qdf_system_ticks(); + } + + return adapter; +} + +static QDF_STATUS hdd_register_interface(hdd_adapter_t *adapter, + bool rtnl_held) +{ + struct net_device *pWlanDev = adapter->dev; + + if (rtnl_held) { + if (strnchr(pWlanDev->name, strlen(pWlanDev->name), '%')) { + if (dev_alloc_name(pWlanDev, pWlanDev->name) < 0) { + hdd_err("Failed:dev_alloc_name"); + return QDF_STATUS_E_FAILURE; + } + } + if (register_netdevice(pWlanDev)) { + hdd_err("Failed:register_netdev"); + return QDF_STATUS_E_FAILURE; + } + } else { + if (register_netdev(pWlanDev)) { + hdd_err("Failed:register_netdev"); + return QDF_STATUS_E_FAILURE; + } + } + set_bit(NET_DEVICE_REGISTERED, &adapter->event_flags); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS hdd_sme_close_session_callback(void *pContext) +{ + hdd_adapter_t *adapter = pContext; + + if (NULL == adapter) { + hdd_alert("NULL adapter"); + return QDF_STATUS_E_INVAL; + } + + if (WLAN_HDD_ADAPTER_MAGIC != adapter->magic) { + hdd_alert("Invalid magic"); + return QDF_STATUS_NOT_INITIALIZED; + } + + /* + * For NAN Data interface, the close session results in the final + * indication to the userspace + */ + if (adapter->device_mode == QDF_NDI_MODE) + hdd_ndp_session_end_handler(adapter); + + clear_bit(SME_SESSION_OPENED, &adapter->event_flags); + + /* + * We can be blocked while waiting for scheduled work to be + * flushed, and the adapter structure can potentially be freed, in + * which case the magic will have been reset. So make sure the + * magic is still good, and hence the adapter structure is still + * valid, before signaling completion + */ + if (WLAN_HDD_ADAPTER_MAGIC == adapter->magic) + complete(&adapter->session_close_comp_var); + + return QDF_STATUS_SUCCESS; +} + +/** + * hdd_check_and_init_tdls() - check and init TDLS operation for desired mode + * @adapter: pointer to device adapter + * @type: type of interface + * + * This routine will check the mode of adapter and if it is required then it + * will initialize the TDLS operations + * + * Return: QDF_STATUS + */ +#ifdef FEATURE_WLAN_TDLS +static QDF_STATUS hdd_check_and_init_tdls(hdd_adapter_t *adapter, uint32_t type) +{ + if (QDF_IBSS_MODE != type) { + if (0 != wlan_hdd_tdls_init(adapter)) { + hdd_err("wlan_hdd_tdls_init failed"); + return QDF_STATUS_E_FAILURE; + } + set_bit(TDLS_INIT_DONE, &adapter->event_flags); + } + return QDF_STATUS_SUCCESS; +} +#else +static QDF_STATUS hdd_check_and_init_tdls(hdd_adapter_t *adapter, uint32_t type) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +QDF_STATUS hdd_init_station_mode(hdd_adapter_t *adapter) +{ + struct net_device *pWlanDev = adapter->dev; + hdd_station_ctx_t *pHddStaCtx = &adapter->sessionCtx.station; + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + QDF_STATUS qdf_ret_status = QDF_STATUS_SUCCESS; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + uint32_t type, subType; + unsigned long rc; + int ret_val; + + INIT_COMPLETION(adapter->session_open_comp_var); + sme_set_curr_device_mode(hdd_ctx->hHal, adapter->device_mode); + sme_set_pdev_ht_vht_ies(hdd_ctx->hHal, hdd_ctx->config->enable2x2); + status = cds_get_vdev_types(adapter->device_mode, &type, &subType); + if (QDF_STATUS_SUCCESS != status) { + hdd_err("failed to get vdev type"); + goto error_sme_open; + } + /* Open a SME session for future operation */ + qdf_ret_status = + sme_open_session(hdd_ctx->hHal, hdd_sme_roam_callback, adapter, + (uint8_t *) &adapter->macAddressCurrent, + &adapter->sessionId, type, subType); + if (!QDF_IS_STATUS_SUCCESS(qdf_ret_status)) { + hdd_alert("sme_open_session() failed, status code %08d [x%08x]", + qdf_ret_status, qdf_ret_status); + status = QDF_STATUS_E_FAILURE; + goto error_sme_open; + } + /* Block on a completion variable. Can't wait forever though. */ + rc = wait_for_completion_timeout( + &adapter->session_open_comp_var, + msecs_to_jiffies(WLAN_WAIT_TIME_SESSIONOPENCLOSE)); + if (!rc) { + hdd_alert("Session is not opened within timeout period code %ld", + rc); + status = QDF_STATUS_E_FAILURE; + goto error_register_wext; + } + + sme_set_vdev_ies_per_band(hdd_ctx->hHal, adapter->sessionId); + /* Register wireless extensions */ + qdf_ret_status = hdd_register_wext(pWlanDev); + if (QDF_STATUS_SUCCESS != qdf_ret_status) { + hdd_alert("hdd_register_wext() failed, status code %08d [x%08x]", + qdf_ret_status, qdf_ret_status); + status = QDF_STATUS_E_FAILURE; + goto error_register_wext; + } + /* Set the Connection State to Not Connected */ + hdd_notice("Set HDD connState to eConnectionState_NotConnected"); + pHddStaCtx->conn_info.connState = eConnectionState_NotConnected; + + qdf_mem_set(pHddStaCtx->conn_info.staId, + sizeof(pHddStaCtx->conn_info.staId), HDD_WLAN_INVALID_STA_ID); + + /* set fast roaming capability in sme session */ + status = sme_config_fast_roaming(hdd_ctx->hHal, adapter->sessionId, + adapter->fast_roaming_allowed); + /* Set the default operation channel */ + pHddStaCtx->conn_info.operationChannel = + hdd_ctx->config->OperatingChannel; + + /* Make the default Auth Type as OPEN */ + pHddStaCtx->conn_info.authType = eCSR_AUTH_TYPE_OPEN_SYSTEM; + + status = hdd_init_tx_rx(adapter); + if (QDF_STATUS_SUCCESS != status) { + hdd_alert("hdd_init_tx_rx() failed, status code %08d [x%08x]", + status, status); + goto error_init_txrx; + } + + set_bit(INIT_TX_RX_SUCCESS, &adapter->event_flags); + + status = hdd_wmm_adapter_init(adapter); + if (QDF_STATUS_SUCCESS != status) { + hdd_alert("hdd_wmm_adapter_init() failed, status code %08d [x%08x]", + status, status); + goto error_wmm_init; + } + + set_bit(WMM_INIT_DONE, &adapter->event_flags); + + ret_val = sme_cli_set_command(adapter->sessionId, + WMI_PDEV_PARAM_BURST_ENABLE, + hdd_ctx->config->enableSifsBurst, + PDEV_CMD); + + if (0 != ret_val) { + hdd_err("WMI_PDEV_PARAM_BURST_ENABLE set failed %d", + ret_val); + } + status = hdd_check_and_init_tdls(adapter, type); + if (status != QDF_STATUS_SUCCESS) + goto error_tdls_init; + + status = hdd_lro_enable(hdd_ctx, adapter); + if (status != QDF_STATUS_SUCCESS) + goto error_lro_enable; + + /* rcpi info initialization */ + qdf_mem_zero(&adapter->rcpi, sizeof(adapter->rcpi)); + + return QDF_STATUS_SUCCESS; + +error_lro_enable: + wlan_hdd_tdls_exit(adapter); +error_tdls_init: + clear_bit(WMM_INIT_DONE, &adapter->event_flags); + hdd_wmm_adapter_close(adapter); +error_wmm_init: + clear_bit(INIT_TX_RX_SUCCESS, &adapter->event_flags); + hdd_deinit_tx_rx(adapter); +error_init_txrx: + hdd_unregister_wext(pWlanDev); +error_register_wext: + if (adapter->sessionId != HDD_SESSION_ID_INVALID) { + INIT_COMPLETION(adapter->session_close_comp_var); + if (QDF_STATUS_SUCCESS == sme_close_session(hdd_ctx->hHal, + adapter->sessionId, + hdd_sme_close_session_callback, + adapter)) { + /* + * Block on a completion variable. + * Can't wait forever though. + */ + rc = wait_for_completion_timeout( + &adapter->session_close_comp_var, + msecs_to_jiffies + (WLAN_WAIT_TIME_SESSIONOPENCLOSE)); + if (rc <= 0) + hdd_err("Session is not closed within timeout period code %ld", + rc); + } + adapter->sessionId = HDD_SESSION_ID_INVALID; + } +error_sme_open: + return status; +} + +void hdd_cleanup_actionframe(hdd_context_t *hdd_ctx, hdd_adapter_t *adapter) +{ + hdd_cfg80211_state_t *cfgState; + + cfgState = WLAN_HDD_GET_CFG_STATE_PTR(adapter); + + if (NULL != cfgState->buf) { + unsigned long rc; + rc = wait_for_completion_timeout( + &adapter->tx_action_cnf_event, + msecs_to_jiffies(ACTION_FRAME_TX_TIMEOUT)); + if (!rc) { + hdd_err("HDD Wait for Action Confirmation Failed!!"); + /* + * Inform tx status as FAILURE to upper layer and free + * cfgState->buf + */ + hdd_send_action_cnf(adapter, false); + } + } + return; +} + +/** + * hdd_station_adapter_deinit() - De-initialize the station adapter + * @hdd_ctx: global hdd context + * @adapter: HDD adapter + * @rtnl_held: Used to indicate whether or not the caller is holding + * the kernel rtnl_mutex + * + * This function De-initializes the STA/P2P/OCB adapter. + * + * Return: None. + */ +static void hdd_station_adapter_deinit(hdd_context_t *hdd_ctx, + hdd_adapter_t *adapter, + bool rtnl_held) +{ + ENTER_DEV(adapter->dev); + + if (adapter->dev) { + if (rtnl_held) + adapter->dev->wireless_handlers = NULL; + else { + rtnl_lock(); + adapter->dev->wireless_handlers = NULL; + rtnl_unlock(); + } + } + + if (test_bit(INIT_TX_RX_SUCCESS, &adapter->event_flags)) { + hdd_deinit_tx_rx(adapter); + clear_bit(INIT_TX_RX_SUCCESS, &adapter->event_flags); + } + + if (test_bit(WMM_INIT_DONE, &adapter->event_flags)) { + hdd_wmm_adapter_close(adapter); + clear_bit(WMM_INIT_DONE, &adapter->event_flags); + } + + hdd_cleanup_actionframe(hdd_ctx, adapter); + wlan_hdd_tdls_exit(adapter); + + EXIT(); +} + +/** + * hdd_ap_adapter_deinit() - De-initialize the ap adapter + * @hdd_ctx: global hdd context + * @adapter: HDD adapter + * @rtnl_held: the rtnl lock hold flag + * This function De-initializes the AP/P2PGo adapter. + * + * Return: None. + */ +static void hdd_ap_adapter_deinit(hdd_context_t *hdd_ctx, + hdd_adapter_t *adapter, + bool rtnl_held) +{ + ENTER_DEV(adapter->dev); + + if (test_bit(WMM_INIT_DONE, &adapter->event_flags)) { + hdd_wmm_adapter_close(adapter); + clear_bit(WMM_INIT_DONE, &adapter->event_flags); + } + wlan_hdd_undo_acs(adapter); + + hdd_cleanup_actionframe(hdd_ctx, adapter); + + hdd_unregister_hostapd(adapter, rtnl_held); + + EXIT(); +} + +void hdd_deinit_adapter(hdd_context_t *hdd_ctx, hdd_adapter_t *adapter, + bool rtnl_held) +{ + ENTER(); + + switch (adapter->device_mode) { + case QDF_STA_MODE: + case QDF_P2P_CLIENT_MODE: + case QDF_P2P_DEVICE_MODE: + { + hdd_station_adapter_deinit(hdd_ctx, adapter, rtnl_held); + break; + } + + case QDF_SAP_MODE: + case QDF_P2P_GO_MODE: + { + + hdd_ap_adapter_deinit(hdd_ctx, adapter, rtnl_held); + break; + } + + default: + break; + } + + EXIT(); +} + +static void hdd_cleanup_adapter(hdd_context_t *hdd_ctx, hdd_adapter_t *adapter, + bool rtnl_held) +{ + struct net_device *pWlanDev = NULL; + + if (adapter) + pWlanDev = adapter->dev; + else { + hdd_err("adapter is Null"); + return; + } + + hdd_debugfs_exit(adapter); + + if (adapter->scan_info.default_scan_ies) { + qdf_mem_free(adapter->scan_info.default_scan_ies); + adapter->scan_info.default_scan_ies = NULL; + } + + hdd_adapter_runtime_suspend_denit(adapter); + + /* + * The adapter is marked as closed. When hdd_wlan_exit() call returns, + * the driver is almost closed and cannot handle either control + * messages or data. However, unregister_netdevice() call above will + * eventually invoke hdd_stop (ndo_close) driver callback, which attempts + * to close the active connections (basically excites control path) which + * is not right. Setting this flag helps hdd_stop() to recognize that + * the interface is closed and restricts any operations on that + */ + clear_bit(DEVICE_IFACE_OPENED, &adapter->event_flags); + + if (test_bit(NET_DEVICE_REGISTERED, &adapter->event_flags)) { + if (rtnl_held) { + unregister_netdevice(pWlanDev); + } else { + unregister_netdev(pWlanDev); + } + /* + * Note that the adapter is no longer valid at this point + * since the memory has been reclaimed + */ + } +} + +static QDF_STATUS hdd_check_for_existing_macaddr(hdd_context_t *hdd_ctx, + tSirMacAddr macAddr) +{ + hdd_adapter_list_node_t *adapterNode = NULL, *pNext = NULL; + hdd_adapter_t *adapter; + QDF_STATUS status; + status = hdd_get_front_adapter(hdd_ctx, &adapterNode); + while (NULL != adapterNode && QDF_STATUS_SUCCESS == status) { + adapter = adapterNode->pAdapter; + if (adapter + && !qdf_mem_cmp(adapter->macAddressCurrent.bytes, + macAddr, sizeof(tSirMacAddr))) { + return QDF_STATUS_E_FAILURE; + } + status = hdd_get_next_adapter(hdd_ctx, adapterNode, &pNext); + adapterNode = pNext; + } + return QDF_STATUS_SUCCESS; +} + +#ifdef CONFIG_FW_LOGS_BASED_ON_INI +/** + * hdd_set_fw_log_params() - Set log parameters to FW + * @hdd_ctx: HDD Context + * @adapter: HDD Adapter + * + * This function set the FW Debug log level based on the INI. + * + * Return: None + */ +static void hdd_set_fw_log_params(hdd_context_t *hdd_ctx, + hdd_adapter_t *adapter) +{ + uint8_t count = 0, numentries = 0, + moduleloglevel[FW_MODULE_LOG_LEVEL_STRING_LENGTH]; + uint32_t value = 0; + int ret; + + if (QDF_GLOBAL_FTM_MODE == cds_get_conparam() || + (!hdd_ctx->config->enable_fw_log)) { + hdd_info("enable_fw_log not enabled in INI or in FTM mode return"); + return; + } + + /* Enable FW logs based on INI configuration */ + hdd_ctx->fw_log_settings.dl_type = + hdd_ctx->config->enableFwLogType; + ret = sme_cli_set_command(adapter->sessionId, + WMI_DBGLOG_TYPE, + hdd_ctx->config->enableFwLogType, + DBG_CMD); + if (ret != 0) + hdd_warn("Failed to enable FW log type ret %d", + ret); + + hdd_ctx->fw_log_settings.dl_loglevel = + hdd_ctx->config->enableFwLogLevel; + ret = sme_cli_set_command(adapter->sessionId, + WMI_DBGLOG_LOG_LEVEL, + hdd_ctx->config->enableFwLogLevel, + DBG_CMD); + if (ret != 0) + hdd_warn("Failed to enable FW log level ret %d", + ret); + + hdd_string_to_u8_array( + hdd_ctx->config->enableFwModuleLogLevel, + moduleloglevel, + &numentries, + FW_MODULE_LOG_LEVEL_STRING_LENGTH); + + while (count < numentries) { + /* + * FW module log level input string looks like + * below: + * gFwDebugModuleLoglevel=, + * ,... + * For example: + * gFwDebugModuleLoglevel= + * 1,0,2,1,3,2,4,3,5,4,6,5,7,6 + * Above input string means : + * For FW module ID 1 enable log level 0 + * For FW module ID 2 enable log level 1 + * For FW module ID 3 enable log level 2 + * For FW module ID 4 enable log level 3 + * For FW module ID 5 enable log level 4 + * For FW module ID 6 enable log level 5 + * For FW module ID 7 enable log level 6 + */ + + if ((moduleloglevel[count] > WLAN_MODULE_ID_MAX) + || (moduleloglevel[count + 1] > DBGLOG_LVL_MAX)) { + hdd_err("Module id %d and dbglog level %d input length is more than max", + moduleloglevel[count], + moduleloglevel[count + 1]); + return; + } + + value = moduleloglevel[count] << 16; + value |= moduleloglevel[count + 1]; + ret = sme_cli_set_command(adapter->sessionId, + WMI_DBGLOG_MOD_LOG_LEVEL, + value, DBG_CMD); + if (ret != 0) + hdd_err("Failed to enable FW module log level %d ret %d", + value, ret); + + count += 2; + } + +} +#else +static void hdd_set_fw_log_params(hdd_context_t *hdd_ctx, + hdd_adapter_t *adapter) +{ +} + +#endif + +/** + * hdd_set_fw_params() - Set parameters to firmware + * @adapter: HDD adapter + * + * This function Sets various parameters to fw once the + * adapter is started. + * + * Return: 0 on success or errno on failure + */ +int hdd_set_fw_params(hdd_adapter_t *adapter) +{ + int ret; + hdd_context_t *hdd_ctx; + + ENTER_DEV(adapter->dev); + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (!hdd_ctx) + return -EINVAL; + + if ((cds_get_conparam() != QDF_GLOBAL_FTM_MODE) && + (!hdd_ctx->config->enable2x2)) { +#define HDD_DTIM_1CHAIN_RX_ID 0x5 +#define HDD_SMPS_PARAM_VALUE_S 29 + /* + * Disable DTIM 1 chain Rx when in 1x1, + * we are passing two value + * as param_id << 29 | param_value. + * Below param_value = 0(disable) + */ + ret = sme_cli_set_command(adapter->sessionId, + WMI_STA_SMPS_PARAM_CMDID, + HDD_DTIM_1CHAIN_RX_ID << + HDD_SMPS_PARAM_VALUE_S, + VDEV_CMD); + if (ret) { + hdd_err("DTIM 1 chain set failed %d", ret); + goto error; + } + + ret = sme_cli_set_command(adapter->sessionId, + WMI_PDEV_PARAM_TX_CHAIN_MASK, + hdd_ctx->config->txchainmask1x1, + PDEV_CMD); + if (ret) { + hdd_err("WMI_PDEV_PARAM_TX_CHAIN_MASK set failed %d", + ret); + goto error; + } + + ret = sme_cli_set_command(adapter->sessionId, + WMI_PDEV_PARAM_RX_CHAIN_MASK, + hdd_ctx->config->rxchainmask1x1, + PDEV_CMD); + if (ret) { + hdd_err("WMI_PDEV_PARAM_RX_CHAIN_MASK set failed %d", + ret); + goto error; + } +#undef HDD_DTIM_1CHAIN_RX_ID +#undef HDD_SMPS_PARAM_VALUE_S + } else { + hdd_info("FTM Mode or 2x2 mode - Do not set 1x1 params"); + } + + if (QDF_GLOBAL_FTM_MODE != cds_get_conparam()) { + ret = sme_cli_set_command(adapter->sessionId, + WMI_PDEV_PARAM_HYST_EN, + hdd_ctx->config->enableMemDeepSleep, + PDEV_CMD); + + if (ret) { + hdd_err("WMI_PDEV_PARAM_HYST_EN set failed %d", + ret); + goto error; + } + + ret = sme_cli_set_command(adapter->sessionId, + WMI_VDEV_PARAM_ENABLE_RTSCTS, + hdd_ctx->config->rts_profile, + VDEV_CMD); + if (ret) { + hdd_err("FAILED TO SET RTSCTS Profile ret:%d", ret); + goto error; + } + + hdd_info("SET AMSDU num %d", hdd_ctx->config->max_amsdu_num); + + ret = sme_cli_set_command(adapter->sessionId, + GEN_VDEV_PARAM_AMSDU, + hdd_ctx->config->max_amsdu_num, + GEN_CMD); + if (ret != 0) { + hdd_err("GEN_VDEV_PARAM_AMSDU set failed %d", ret); + goto error; + } + } + + hdd_set_fw_log_params(hdd_ctx, adapter); + + EXIT(); + return 0; + +error: + return -EINVAL; +} + +/** + * hdd_open_adapter() - open and setup the hdd adatper + * @hdd_ctx: global hdd context + * @session_type: type of the interface to be created + * @iface_name: User-visible name of the interface + * @macAddr: MAC address to assign to the interface + * @name_assign_type: the name of assign type of the netdev + * @rtnl_held: the rtnl lock hold flag + * + * This function open and setup the hdd adpater according to the device + * type request, assign the name, the mac address assigned, and then prepared + * the hdd related parameters, queue, lock and ready to start. + * + * Return: the pointer of hdd adapter, otherwise NULL. + */ +hdd_adapter_t *hdd_open_adapter(hdd_context_t *hdd_ctx, uint8_t session_type, + const char *iface_name, tSirMacAddr macAddr, + unsigned char name_assign_type, + bool rtnl_held) +{ + hdd_adapter_t *adapter = NULL; + hdd_adapter_list_node_t *pHddAdapterNode = NULL; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + hdd_cfg80211_state_t *cfgState; + + hdd_info("iface(%s) type(%d)", iface_name, session_type); + + if (hdd_ctx->current_intf_count >= hdd_ctx->max_intf_count) { + /* + * Max limit reached on the number of vdevs configured by the + * host. Return error + */ + hdd_err("Unable to add virtual intf: currentVdevCnt=%d,hostConfiguredVdevCnt=%d", + hdd_ctx->current_intf_count, hdd_ctx->max_intf_count); + return NULL; + } + + if (macAddr == NULL) { + /* Not received valid macAddr */ + hdd_err("Unable to add virtual intf: Not able to get valid mac address"); + return NULL; + } + status = hdd_check_for_existing_macaddr(hdd_ctx, macAddr); + if (QDF_STATUS_E_FAILURE == status) { + hdd_err("Duplicate MAC addr: " MAC_ADDRESS_STR + " already exists", + MAC_ADDR_ARRAY(macAddr)); + return NULL; + } + + switch (session_type) { + case QDF_STA_MODE: + /* Reset locally administered bit if the device mode is STA */ + WLAN_HDD_RESET_LOCALLY_ADMINISTERED_BIT(macAddr); + /* fall through */ + case QDF_P2P_CLIENT_MODE: + case QDF_P2P_DEVICE_MODE: + case QDF_OCB_MODE: + case QDF_NDI_MODE: + case QDF_MONITOR_MODE: + adapter = hdd_alloc_station_adapter(hdd_ctx, macAddr, + name_assign_type, + iface_name); + + if (NULL == adapter) { + hdd_err("failed to allocate adapter for session %d", + session_type); + return NULL; + } + + if (QDF_P2P_CLIENT_MODE == session_type) + adapter->wdev.iftype = NL80211_IFTYPE_P2P_CLIENT; + else if (QDF_P2P_DEVICE_MODE == session_type) + adapter->wdev.iftype = NL80211_IFTYPE_P2P_DEVICE; + else if (QDF_MONITOR_MODE == session_type) + adapter->wdev.iftype = NL80211_IFTYPE_MONITOR; + else + adapter->wdev.iftype = NL80211_IFTYPE_STATION; + + adapter->device_mode = session_type; + + if (QDF_NDI_MODE == session_type) { + status = hdd_init_nan_data_mode(adapter); + if (QDF_STATUS_SUCCESS != status) + goto err_free_netdev; + } + + /* + * Workqueue which gets scheduled in IPv4 notification + * callback + */ + INIT_WORK(&adapter->ipv4NotifierWorkQueue, + hdd_ipv4_notifier_work_queue); + +#ifdef WLAN_NS_OFFLOAD + /* + * Workqueue which gets scheduled in IPv6 + * notification callback. + */ + INIT_WORK(&adapter->ipv6NotifierWorkQueue, + hdd_ipv6_notifier_work_queue); +#endif + status = hdd_register_interface(adapter, rtnl_held); + if (QDF_STATUS_SUCCESS != status) { + hdd_deinit_adapter(hdd_ctx, adapter, rtnl_held); + goto err_free_netdev; + } + + /* Stop the Interface TX queue. */ + hdd_info("Disabling queues"); + wlan_hdd_netif_queue_control(adapter, + WLAN_STOP_ALL_NETIF_QUEUE_N_CARRIER, + WLAN_CONTROL_PATH); + break; + + + case QDF_P2P_GO_MODE: + case QDF_SAP_MODE: + adapter = hdd_wlan_create_ap_dev(hdd_ctx, macAddr, + name_assign_type, + (uint8_t *) iface_name); + if (NULL == adapter) { + hdd_alert("failed to allocate adapter for session %d", + session_type); + return NULL; + } + + adapter->wdev.iftype = + (session_type == + QDF_SAP_MODE) ? NL80211_IFTYPE_AP : + NL80211_IFTYPE_P2P_GO; + adapter->device_mode = session_type; + + status = hdd_register_hostapd(adapter, rtnl_held); + if (QDF_STATUS_SUCCESS != status) { + hdd_deinit_adapter(hdd_ctx, adapter, rtnl_held); + goto err_free_netdev; + } + hdd_info("Disabling queues"); + wlan_hdd_netif_queue_control(adapter, + WLAN_STOP_ALL_NETIF_QUEUE_N_CARRIER, + WLAN_CONTROL_PATH); + break; + case QDF_FTM_MODE: + adapter = hdd_alloc_station_adapter(hdd_ctx, macAddr, + name_assign_type, + "wlan0"); + if (NULL == adapter) { + hdd_err("Failed to allocate adapter for FTM mode"); + return NULL; + } + adapter->wdev.iftype = NL80211_IFTYPE_STATION; + adapter->device_mode = session_type; + status = hdd_register_interface(adapter, rtnl_held); + if (QDF_STATUS_SUCCESS != status) { + hdd_deinit_adapter(hdd_ctx, adapter, rtnl_held); + goto err_free_netdev; + } + /* Stop the Interface TX queue. */ + hdd_info("Disabling queues"); + wlan_hdd_netif_queue_control(adapter, + WLAN_STOP_ALL_NETIF_QUEUE_N_CARRIER, + WLAN_CONTROL_PATH); + break; + default: + hdd_alert("Invalid session type %d", session_type); + QDF_ASSERT(0); + return NULL; + } + + cfgState = WLAN_HDD_GET_CFG_STATE_PTR(adapter); + mutex_init(&cfgState->remain_on_chan_ctx_lock); + + if (QDF_STATUS_SUCCESS == status) { + /* Add it to the hdd's session list. */ + pHddAdapterNode = + qdf_mem_malloc(sizeof(hdd_adapter_list_node_t)); + if (NULL == pHddAdapterNode) { + status = QDF_STATUS_E_NOMEM; + } else { + pHddAdapterNode->pAdapter = adapter; + status = hdd_add_adapter_back(hdd_ctx, pHddAdapterNode); + } + } + + if (QDF_STATUS_SUCCESS != status) { + if (NULL != adapter) { + hdd_cleanup_adapter(hdd_ctx, adapter, rtnl_held); + adapter = NULL; + } + if (NULL != pHddAdapterNode) { + qdf_mem_free(pHddAdapterNode); + } + return NULL; + } + + if (QDF_STATUS_SUCCESS == status) { + cds_set_concurrency_mode(session_type); + + /* Adapter successfully added. Increment the vdev count */ + hdd_ctx->current_intf_count++; + + hdd_debug("current_intf_count=%d", + hdd_ctx->current_intf_count); + + cds_check_and_restart_sap_with_non_dfs_acs(); + } + + if (QDF_STATUS_SUCCESS != hdd_debugfs_init(adapter)) + hdd_err("Interface %s wow debug_fs init failed", iface_name); + + return adapter; + +err_free_netdev: + wlan_hdd_release_intf_addr(hdd_ctx, adapter->macAddressCurrent.bytes); + free_netdev(adapter->dev); + + return NULL; +} + +QDF_STATUS hdd_close_adapter(hdd_context_t *hdd_ctx, hdd_adapter_t *adapter, + bool rtnl_held) +{ + hdd_adapter_list_node_t *adapterNode, *pCurrent, *pNext; + QDF_STATUS status; + + status = hdd_get_front_adapter(hdd_ctx, &pCurrent); + if (QDF_STATUS_SUCCESS != status) { + hdd_warn("adapter list empty %d", + status); + return status; + } + + while (pCurrent->pAdapter != adapter) { + status = hdd_get_next_adapter(hdd_ctx, pCurrent, &pNext); + if (QDF_STATUS_SUCCESS != status) + break; + + pCurrent = pNext; + } + adapterNode = pCurrent; + if (QDF_STATUS_SUCCESS == status) { + hdd_debug("wait for bus bw work to flush"); + hdd_bus_bw_compute_timer_stop(hdd_ctx); + cancel_work_sync(&hdd_ctx->bus_bw_work); + + /* cleanup adapter */ + cds_clear_concurrency_mode(adapter->device_mode); + hdd_cleanup_adapter(hdd_ctx, adapterNode->pAdapter, rtnl_held); + hdd_remove_adapter(hdd_ctx, adapterNode); + qdf_mem_free(adapterNode); + adapterNode = NULL; + + /* conditionally restart the bw timer */ + hdd_bus_bw_compute_timer_try_start(hdd_ctx); + + /* Adapter removed. Decrement vdev count */ + if (hdd_ctx->current_intf_count != 0) + hdd_ctx->current_intf_count--; + + /* Fw will take care incase of concurrency */ + return QDF_STATUS_SUCCESS; + } + + return QDF_STATUS_E_FAILURE; +} + +/** + * hdd_close_all_adapters - Close all open adapters + * @hdd_ctx: Hdd context + * rtnl_held: True if RTNL lock held + * + * Close all open adapters. + * + * Return: QDF status code + */ +QDF_STATUS hdd_close_all_adapters(hdd_context_t *hdd_ctx, bool rtnl_held) +{ + hdd_adapter_list_node_t *pHddAdapterNode; + QDF_STATUS status; + + ENTER(); + + do { + status = hdd_remove_front_adapter(hdd_ctx, &pHddAdapterNode); + if (pHddAdapterNode && QDF_STATUS_SUCCESS == status) { + wlan_hdd_release_intf_addr(hdd_ctx, + pHddAdapterNode->pAdapter->macAddressCurrent.bytes); + hdd_cleanup_adapter(hdd_ctx, pHddAdapterNode->pAdapter, + rtnl_held); + qdf_mem_free(pHddAdapterNode); + /* Adapter removed. Decrement vdev count */ + if (hdd_ctx->current_intf_count != 0) + hdd_ctx->current_intf_count--; + } + } while (NULL != pHddAdapterNode && QDF_STATUS_E_EMPTY != status); + + EXIT(); + + return QDF_STATUS_SUCCESS; +} + +void wlan_hdd_reset_prob_rspies(hdd_adapter_t *pHostapdAdapter) +{ + struct qdf_mac_addr *bssid = NULL; + tSirUpdateIE updateIE; + switch (pHostapdAdapter->device_mode) { + case QDF_STA_MODE: + case QDF_P2P_CLIENT_MODE: + { + hdd_station_ctx_t *pHddStaCtx = + WLAN_HDD_GET_STATION_CTX_PTR(pHostapdAdapter); + bssid = &pHddStaCtx->conn_info.bssId; + break; + } + case QDF_SAP_MODE: + case QDF_P2P_GO_MODE: + case QDF_IBSS_MODE: + { + bssid = &pHostapdAdapter->macAddressCurrent; + break; + } + case QDF_FTM_MODE: + case QDF_P2P_DEVICE_MODE: + default: + /* + * wlan_hdd_reset_prob_rspies should not have been called + * for these kind of devices + */ + hdd_err("Unexpected request for the current device type %d", + pHostapdAdapter->device_mode); + return; + } + + qdf_copy_macaddr(&updateIE.bssid, bssid); + updateIE.smeSessionId = pHostapdAdapter->sessionId; + updateIE.ieBufferlength = 0; + updateIE.pAdditionIEBuffer = NULL; + updateIE.append = true; + updateIE.notify = false; + if (sme_update_add_ie(WLAN_HDD_GET_HAL_CTX(pHostapdAdapter), + &updateIE, + eUPDATE_IE_PROBE_RESP) == QDF_STATUS_E_FAILURE) { + hdd_err("Could not pass on PROBE_RSP_BCN data to PE"); + } +} + +/** + * hdd_wait_for_sme_close_sesion() - Close and wait for SME session close + * @hdd_ctx: HDD context which is already NULL validated + * @adapter: HDD adapter which is already NULL validated + * + * Close the SME session and wait for its completion, if needed. + * + * Return: None + */ +static void hdd_wait_for_sme_close_sesion(hdd_context_t *hdd_ctx, + hdd_adapter_t *adapter) +{ + unsigned long rc; + + if (!test_bit(SME_SESSION_OPENED, &adapter->event_flags)) { + hdd_err("session is not opened:%d", adapter->sessionId); + return; + } + + INIT_COMPLETION(adapter->session_close_comp_var); + if (QDF_STATUS_SUCCESS == + sme_close_session(hdd_ctx->hHal, adapter->sessionId, + hdd_sme_close_session_callback, + adapter)) { + /* + * Block on a completion variable. Can't wait + * forever though. + */ + rc = wait_for_completion_timeout( + &adapter->session_close_comp_var, + msecs_to_jiffies + (WLAN_WAIT_TIME_SESSIONOPENCLOSE)); + if (!rc) { + hdd_err("failure waiting for session_close_comp_var"); + if (adapter->device_mode == QDF_NDI_MODE) + hdd_ndp_session_end_handler(adapter); + clear_bit(SME_SESSION_OPENED, &adapter->event_flags); + return; + } + adapter->sessionId = HDD_SESSION_ID_INVALID; + } +} + +QDF_STATUS hdd_stop_adapter(hdd_context_t *hdd_ctx, hdd_adapter_t *adapter, + const bool bCloseSession) +{ + QDF_STATUS qdf_ret_status = QDF_STATUS_SUCCESS; + hdd_wext_state_t *pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(adapter); + union iwreq_data wrqu; + tSirUpdateIE updateIE; + unsigned long rc; + hdd_scaninfo_t *scan_info = NULL; + void *sap_ctx; + + ENTER(); + + if (!test_bit(SME_SESSION_OPENED, &adapter->event_flags)) { + hdd_info("session %d is not open %lu", + adapter->device_mode, adapter->event_flags); + return -ENODEV; + } + + scan_info = &adapter->scan_info; + hdd_notice("Disabling queues"); + wlan_hdd_netif_queue_control(adapter, + WLAN_STOP_ALL_NETIF_QUEUE_N_CARRIER, + WLAN_CONTROL_PATH); + switch (adapter->device_mode) { + case QDF_STA_MODE: + case QDF_P2P_CLIENT_MODE: + case QDF_IBSS_MODE: + case QDF_P2P_DEVICE_MODE: + case QDF_NDI_MODE: + if ((QDF_NDI_MODE == adapter->device_mode) || + hdd_conn_is_connected( + WLAN_HDD_GET_STATION_CTX_PTR(adapter)) || + hdd_is_connecting( + WLAN_HDD_GET_STATION_CTX_PTR(adapter))) { + INIT_COMPLETION(adapter->disconnect_comp_var); + /* + * For NDI do not use pWextState from sta_ctx, if needed + * extract from ndi_ctx. + */ + if (QDF_NDI_MODE == adapter->device_mode) + qdf_ret_status = sme_roam_disconnect( + hdd_ctx->hHal, + adapter->sessionId, + eCSR_DISCONNECT_REASON_NDI_DELETE); + else if (pWextState->roamProfile.BSSType == + eCSR_BSS_TYPE_START_IBSS) + qdf_ret_status = sme_roam_disconnect( + hdd_ctx->hHal, + adapter->sessionId, + eCSR_DISCONNECT_REASON_IBSS_LEAVE); + else if (QDF_STA_MODE == adapter->device_mode) + qdf_ret_status = + wlan_hdd_try_disconnect(adapter); + else + qdf_ret_status = sme_roam_disconnect( + hdd_ctx->hHal, + adapter->sessionId, + eCSR_DISCONNECT_REASON_UNSPECIFIED); + /* success implies disconnect command got queued up successfully */ + if (qdf_ret_status == QDF_STATUS_SUCCESS && + QDF_STA_MODE != adapter->device_mode) { + rc = wait_for_completion_timeout( + &adapter->disconnect_comp_var, + msecs_to_jiffies + (WLAN_WAIT_TIME_DISCONNECT)); + if (!rc) + hdd_warn("wait on disconnect_comp_var failed"); + } + if (qdf_ret_status != QDF_STATUS_SUCCESS) + hdd_warn("failed to post disconnect"); + memset(&wrqu, '\0', sizeof(wrqu)); + wrqu.ap_addr.sa_family = ARPHRD_ETHER; + memset(wrqu.ap_addr.sa_data, '\0', ETH_ALEN); + wireless_send_event(adapter->dev, SIOCGIWAP, &wrqu, + NULL); + } + if (scan_info != NULL && scan_info->mScanPending) { + wlan_hdd_scan_abort(adapter); + } + hdd_lro_disable(hdd_ctx, adapter); + wlan_hdd_cleanup_remain_on_channel_ctx(adapter); + +#ifdef WLAN_OPEN_SOURCE + cancel_work_sync(&adapter->ipv4NotifierWorkQueue); +#endif + + hdd_deregister_tx_flow_control(adapter); + +#ifdef WLAN_NS_OFFLOAD +#ifdef WLAN_OPEN_SOURCE + cancel_work_sync(&adapter->ipv6NotifierWorkQueue); +#endif +#endif + + /* + * It is possible that the caller of this function does not + * wish to close the session + */ + if (true == bCloseSession) + hdd_wait_for_sme_close_sesion(hdd_ctx, adapter); + break; + + case QDF_SAP_MODE: + case QDF_P2P_GO_MODE: + if (hdd_ctx->config->conc_custom_rule1 && + (QDF_SAP_MODE == adapter->device_mode)) { + /* + * Before stopping the sap adapter, lets make sure there + * is no sap restart work pending. + */ + cds_flush_work(&hdd_ctx->sap_start_work); + hdd_info("Canceled the pending SAP restart work"); + cds_change_sap_restart_required_status(false); + } + /* Any softap specific cleanup here... */ + if (adapter->device_mode == QDF_P2P_GO_MODE) + wlan_hdd_cleanup_remain_on_channel_ctx(adapter); + + hdd_deregister_tx_flow_control(adapter); + + mutex_lock(&hdd_ctx->sap_lock); + if (test_bit(SOFTAP_BSS_STARTED, &adapter->event_flags)) { + QDF_STATUS status; + QDF_STATUS qdf_status; + + /* Stop Bss. */ + status = wlansap_stop_bss( + WLAN_HDD_GET_SAP_CTX_PTR(adapter)); + + if (QDF_IS_STATUS_SUCCESS(status)) { + hdd_hostapd_state_t *hostapd_state = + WLAN_HDD_GET_HOSTAP_STATE_PTR(adapter); + qdf_event_reset(&hostapd_state-> + qdf_stop_bss_event); + qdf_status = + qdf_wait_single_event(&hostapd_state-> + qdf_stop_bss_event, + SME_CMD_TIMEOUT_VALUE); + + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + hdd_err("failure waiting for wlansap_stop_bss %d", + qdf_status); + } + } else { + hdd_err("failure in wlansap_stop_bss"); + } + clear_bit(SOFTAP_BSS_STARTED, &adapter->event_flags); + cds_decr_session_set_pcl( + adapter->device_mode, + adapter->sessionId); + + qdf_copy_macaddr(&updateIE.bssid, + &adapter->macAddressCurrent); + updateIE.smeSessionId = adapter->sessionId; + updateIE.ieBufferlength = 0; + updateIE.pAdditionIEBuffer = NULL; + updateIE.append = false; + updateIE.notify = false; + /* Probe bcn reset */ + if (sme_update_add_ie(WLAN_HDD_GET_HAL_CTX(adapter), + &updateIE, eUPDATE_IE_PROBE_BCN) + == QDF_STATUS_E_FAILURE) { + hdd_err("Could not pass on PROBE_RSP_BCN data to PE"); + } + /* Assoc resp reset */ + if (sme_update_add_ie(WLAN_HDD_GET_HAL_CTX(adapter), + &updateIE, + eUPDATE_IE_ASSOC_RESP) == + QDF_STATUS_E_FAILURE) { + hdd_err("Could not pass on ASSOC_RSP data to PE"); + } + /* Reset WNI_CFG_PROBE_RSP Flags */ + wlan_hdd_reset_prob_rspies(adapter); + qdf_mem_free(adapter->sessionCtx.ap.beacon); + adapter->sessionCtx.ap.beacon = NULL; + } + if (true == bCloseSession) + hdd_wait_for_sme_close_sesion(hdd_ctx, adapter); + + sap_ctx = WLAN_HDD_GET_SAP_CTX_PTR(adapter); + if (wlansap_stop(sap_ctx) != QDF_STATUS_SUCCESS) + hdd_err("Failed:wlansap_stop"); + + if (wlansap_close(sap_ctx) != QDF_STATUS_SUCCESS) + hdd_err("Failed:WLANSAP_close"); + clear_bit(SME_SESSION_OPENED, &adapter->event_flags); + adapter->sessionCtx.ap.sapContext = NULL; + mutex_unlock(&hdd_ctx->sap_lock); + + break; + case QDF_OCB_MODE: + ol_txrx_clear_peer(WLAN_HDD_GET_STATION_CTX_PTR(adapter)-> + conn_info.staId[0]); + break; + default: + break; + } + + EXIT(); + return QDF_STATUS_SUCCESS; +} + +/** + * hdd_deinit_all_adapters - deinit all adapters + * @hdd_ctx: HDD context + * @rtnl_held: True if RTNL lock held + * + */ +void hdd_deinit_all_adapters(hdd_context_t *hdd_ctx, bool rtnl_held) +{ + hdd_adapter_list_node_t *adapter_node = NULL, *next = NULL; + QDF_STATUS status; + hdd_adapter_t *adapter; + + ENTER(); + + status = hdd_get_front_adapter(hdd_ctx, &adapter_node); + + while (NULL != adapter_node && QDF_STATUS_SUCCESS == status) { + adapter = adapter_node->pAdapter; + hdd_deinit_adapter(hdd_ctx, adapter, rtnl_held); + status = hdd_get_next_adapter(hdd_ctx, adapter_node, &next); + adapter_node = next; + } + + EXIT(); +} + +QDF_STATUS hdd_stop_all_adapters(hdd_context_t *hdd_ctx) +{ + hdd_adapter_list_node_t *adapterNode = NULL, *pNext = NULL; + QDF_STATUS status; + hdd_adapter_t *adapter; + + ENTER(); + + cds_flush_work(&hdd_ctx->sap_pre_cac_work); + + status = hdd_get_front_adapter(hdd_ctx, &adapterNode); + + while (NULL != adapterNode && QDF_STATUS_SUCCESS == status) { + adapter = adapterNode->pAdapter; + hdd_stop_adapter(hdd_ctx, adapter, true); + status = hdd_get_next_adapter(hdd_ctx, adapterNode, &pNext); + adapterNode = pNext; + } + + EXIT(); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS hdd_reset_all_adapters(hdd_context_t *hdd_ctx) +{ + hdd_adapter_list_node_t *adapterNode = NULL, *pNext = NULL; + QDF_STATUS status; + hdd_adapter_t *adapter; + tdlsCtx_t *tdls_ctx; + + ENTER(); + + cds_flush_work(&hdd_ctx->sap_pre_cac_work); + + status = hdd_get_front_adapter(hdd_ctx, &adapterNode); + + while (NULL != adapterNode && QDF_STATUS_SUCCESS == status) { + adapter = adapterNode->pAdapter; + + if ((adapter->device_mode == QDF_STA_MODE) || + (adapter->device_mode == QDF_P2P_CLIENT_MODE)) { + /* Stop tdls timers */ + tdls_ctx = WLAN_HDD_GET_TDLS_CTX_PTR(adapter); + if (tdls_ctx) + wlan_hdd_tdls_timers_stop(tdls_ctx); + } + + hdd_debug("Disabling queues"); + if (hdd_ctx->config->sap_internal_restart && + adapter->device_mode == QDF_SAP_MODE) { + wlan_hdd_netif_queue_control(adapter, + WLAN_STOP_ALL_NETIF_QUEUE, + WLAN_CONTROL_PATH); + if (test_bit(SOFTAP_BSS_STARTED, + &adapter->event_flags)) { + hdd_sap_indicate_disconnect_for_sta(adapter); + hdd_cleanup_actionframe(hdd_ctx, adapter); + hdd_sap_destroy_events(adapter); + } + clear_bit(SOFTAP_BSS_STARTED, &adapter->event_flags); + } else { + wlan_hdd_netif_queue_control(adapter, + WLAN_STOP_ALL_NETIF_QUEUE_N_CARRIER, + WLAN_CONTROL_PATH); + } + adapter->sessionCtx.station.hdd_ReassocScenario = false; + + hdd_deinit_tx_rx(adapter); + hdd_lro_disable(hdd_ctx, adapter); + cds_decr_session_set_pcl(adapter->device_mode, + adapter->sessionId); + if (test_bit(WMM_INIT_DONE, &adapter->event_flags)) { + hdd_wmm_adapter_close(adapter); + clear_bit(WMM_INIT_DONE, &adapter->event_flags); + } + + /* + * If adapter is SAP, set session ID to invalid since SAP + * session will be cleanup during SSR. + */ + if (adapter->device_mode == QDF_SAP_MODE) + wlansap_set_invalid_session( + WLAN_HDD_GET_SAP_CTX_PTR(adapter)); + + status = hdd_get_next_adapter(hdd_ctx, adapterNode, &pNext); + adapterNode = pNext; + } + + EXIT(); + + return QDF_STATUS_SUCCESS; +} + +bool hdd_check_for_opened_interfaces(hdd_context_t *hdd_ctx) +{ + hdd_adapter_list_node_t *adapter_node = NULL, *next = NULL; + QDF_STATUS status; + bool close_modules = true; + + status = hdd_get_front_adapter(hdd_ctx, &adapter_node); + while ((NULL != adapter_node) && (QDF_STATUS_SUCCESS == status)) { + if (test_bit(DEVICE_IFACE_OPENED, + &adapter_node->pAdapter->event_flags)) { + hdd_info("Still other ifaces are up cannot close modules"); + close_modules = false; + break; + } + status = hdd_get_next_adapter(hdd_ctx, adapter_node, &next); + adapter_node = next; + } + + return close_modules; +} + +/** + * hdd_is_interface_up()- Checkfor interface up before ssr + * @hdd_ctx: HDD context + * + * check if there are any wlan interfaces before SSR accordingly start + * the interface. + * + * Return: 0 if interface was opened else false + */ +static bool hdd_is_interface_up(hdd_adapter_t *adapter) +{ + if (test_bit(DEVICE_IFACE_OPENED, &adapter->event_flags)) + return true; + else + return false; +} + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 1, 0)) \ + && !defined(WITH_BACKPORTS) +struct cfg80211_bss *hdd_cfg80211_get_bss(struct wiphy *wiphy, + struct ieee80211_channel *channel, + const u8 *bssid, const u8 *ssid, + size_t ssid_len) +{ + return cfg80211_get_bss(wiphy, channel, bssid, + ssid, ssid_len, + WLAN_CAPABILITY_ESS, + WLAN_CAPABILITY_ESS); +} +#else +struct cfg80211_bss *hdd_cfg80211_get_bss(struct wiphy *wiphy, + struct ieee80211_channel *channel, + const u8 *bssid, const u8 *ssid, + size_t ssid_len) +{ + return cfg80211_get_bss(wiphy, channel, bssid, + ssid, ssid_len, + IEEE80211_BSS_TYPE_ESS, + IEEE80211_PRIVACY_ANY); +} +#endif + +#if defined CFG80211_CONNECT_BSS +#if defined CFG80211_CONNECT_TIMEOUT_REASON_CODE || \ + (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 10, 0)) +/** + * hdd_convert_timeout_reason() - Convert to kernel specific enum + * @timeout_reason: reason for connect timeout + * + * This function is used to convert host timeout + * reason enum to kernel specific enum. + * + * Return: nl timeout enum + */ +static enum nl80211_timeout_reason hdd_convert_timeout_reason( + tSirResultCodes timeout_reason) +{ + switch (timeout_reason) { + case eSIR_SME_JOIN_TIMEOUT_RESULT_CODE: + return NL80211_TIMEOUT_SCAN; + case eSIR_SME_AUTH_TIMEOUT_RESULT_CODE: + return NL80211_TIMEOUT_AUTH; + case eSIR_SME_ASSOC_TIMEOUT_RESULT_CODE: + return NL80211_TIMEOUT_ASSOC; + default: + return NL80211_TIMEOUT_UNSPECIFIED; + } +} + +/** + * hdd_cfg80211_connect_timeout() - API to send connection timeout reason + * @dev: network device + * @bssid: bssid to which we want to associate + * @timeout_reason: reason for connect timeout + * + * This API is used to send connection timeout reason to supplicant + * + * Return: void + */ +static void hdd_cfg80211_connect_timeout(struct net_device *dev, + const u8 *bssid, + tSirResultCodes timeout_reason) +{ + enum nl80211_timeout_reason nl_timeout_reason; + nl_timeout_reason = hdd_convert_timeout_reason(timeout_reason); + + cfg80211_connect_timeout(dev, bssid, NULL, 0, GFP_KERNEL, + nl_timeout_reason); +} + +/** + * __hdd_connect_bss() - API to send connection status to supplicant + * @dev: network device + * @bssid: bssid to which we want to associate + * @req_ie: Request Information Element + * @req_ie_len: len of the req IE + * @resp_ie: Response IE + * @resp_ie_len: len of ht response IE + * @status: status + * @gfp: Kernel Flag + * @timeout_reason: reason for connect timeout + * + * Return: void + */ +static void __hdd_connect_bss(struct net_device *dev, const u8 *bssid, + struct cfg80211_bss *bss, const u8 *req_ie, + size_t req_ie_len, const u8 *resp_ie, + size_t resp_ie_len, int status, gfp_t gfp, + tSirResultCodes timeout_reason) +{ + enum nl80211_timeout_reason nl_timeout_reason; + nl_timeout_reason = hdd_convert_timeout_reason(timeout_reason); + + cfg80211_connect_bss(dev, bssid, bss, req_ie, req_ie_len, + resp_ie, resp_ie_len, status, gfp, + nl_timeout_reason); +} +#else +#if defined CFG80211_CONNECT_TIMEOUT +static void hdd_cfg80211_connect_timeout(struct net_device *dev, + const u8 *bssid, + tSirResultCodes timeout_reason) +{ + cfg80211_connect_timeout(dev, bssid, NULL, 0, GFP_KERNEL); +} +#endif + +static void __hdd_connect_bss(struct net_device *dev, const u8 *bssid, + struct cfg80211_bss *bss, const u8 *req_ie, + size_t req_ie_len, const u8 *resp_ie, + size_t resp_ie_len, int status, gfp_t gfp, + tSirResultCodes timeout_reason) +{ + cfg80211_connect_bss(dev, bssid, bss, req_ie, req_ie_len, + resp_ie, resp_ie_len, status, gfp); +} +#endif + +/** + * hdd_connect_bss() - API to send connection status to supplicant + * @dev: network device + * @bssid: bssid to which we want to associate + * @req_ie: Request Information Element + * @req_ie_len: len of the req IE + * @resp_ie: Response IE + * @resp_ie_len: len of ht response IE + * @status: status + * @gfp: Kernel Flag + * @connect_timeout: If timed out waiting for Auth/Assoc/Probe resp + * @timeout_reason: reason for connect timeout + * + * The API is a wrapper to send connection status to supplicant + * + * Return: Void + */ +#if defined CFG80211_CONNECT_TIMEOUT +static void hdd_connect_bss(struct net_device *dev, const u8 *bssid, + struct cfg80211_bss *bss, const u8 *req_ie, + size_t req_ie_len, const u8 *resp_ie, + size_t resp_ie_len, int status, gfp_t gfp, + bool connect_timeout, + tSirResultCodes timeout_reason) +{ + if (connect_timeout) + hdd_cfg80211_connect_timeout(dev, bssid, timeout_reason); + else + __hdd_connect_bss(dev, bssid, bss, req_ie, req_ie_len, resp_ie, + resp_ie_len, status, gfp, timeout_reason); +} +#else +static void hdd_connect_bss(struct net_device *dev, const u8 *bssid, + struct cfg80211_bss *bss, const u8 *req_ie, + size_t req_ie_len, const u8 *resp_ie, + size_t resp_ie_len, int status, gfp_t gfp, + bool connect_timeout, + tSirResultCodes timeout_reason) +{ + __hdd_connect_bss(dev, bssid, bss, req_ie, req_ie_len, resp_ie, + resp_ie_len, status, gfp, timeout_reason); +} +#endif + +/** + * hdd_connect_result() - API to send connection status to supplicant + * @dev: network device + * @bssid: bssid to which we want to associate + * @roam_info: information about connected bss + * @req_ie: Request Information Element + * @req_ie_len: len of the req IE + * @resp_ie: Response IE + * @resp_ie_len: len of ht response IE + * @status: status + * @gfp: Kernel Flag + * @connect_timeout: If timed out waiting for Auth/Assoc/Probe resp + * @timeout_reason: reason for connect timeout + * + * The API is a wrapper to send connection status to supplicant + * and allow runtime suspend + * + * Return: Void + */ +void hdd_connect_result(struct net_device *dev, const u8 *bssid, + tCsrRoamInfo *roam_info, const u8 *req_ie, + size_t req_ie_len, const u8 *resp_ie, + size_t resp_ie_len, u16 status, gfp_t gfp, + bool connect_timeout, + tSirResultCodes timeout_reason) +{ + hdd_adapter_t *padapter = (hdd_adapter_t *) netdev_priv(dev); + struct cfg80211_bss *bss = NULL; + + if (WLAN_STATUS_SUCCESS == status) { + struct ieee80211_channel *chan; + int freq; + int chan_no = roam_info->pBssDesc->channelId; + + if (chan_no <= 14) + freq = ieee80211_channel_to_frequency(chan_no, + NL80211_BAND_2GHZ); + else + freq = ieee80211_channel_to_frequency(chan_no, + NL80211_BAND_5GHZ); + + chan = ieee80211_get_channel(padapter->wdev.wiphy, freq); + bss = hdd_cfg80211_get_bss(padapter->wdev.wiphy, chan, bssid, + roam_info->u.pConnectedProfile->SSID.ssId, + roam_info->u.pConnectedProfile->SSID.length); + } + + hdd_connect_bss(dev, bssid, bss, req_ie, + req_ie_len, resp_ie, resp_ie_len, + status, gfp, connect_timeout, timeout_reason); + + qdf_runtime_pm_allow_suspend(&padapter->connect_rpm_ctx.connect); +} +#else +void hdd_connect_result(struct net_device *dev, const u8 *bssid, + tCsrRoamInfo *roam_info, const u8 *req_ie, + size_t req_ie_len, const u8 *resp_ie, + size_t resp_ie_len, u16 status, gfp_t gfp, + bool connect_timeout, + tSirResultCodes timeout_reason) +{ + hdd_adapter_t *padapter = (hdd_adapter_t *) netdev_priv(dev); + + cfg80211_connect_result(dev, bssid, req_ie, req_ie_len, + resp_ie, resp_ie_len, status, gfp); + qdf_runtime_pm_allow_suspend(&padapter->connect_rpm_ctx.connect); +} +#endif + + +QDF_STATUS hdd_start_all_adapters(hdd_context_t *hdd_ctx) +{ + hdd_adapter_list_node_t *adapterNode = NULL, *pNext = NULL; + QDF_STATUS status; + hdd_adapter_t *adapter; +#ifndef MSM_PLATFORM + struct qdf_mac_addr bcastMac = QDF_MAC_ADDR_BROADCAST_INITIALIZER; +#endif + eConnectionState connState; + + ENTER(); + + status = hdd_get_front_adapter(hdd_ctx, &adapterNode); + while (NULL != adapterNode && QDF_STATUS_SUCCESS == status) { + adapter = adapterNode->pAdapter; + + if (!hdd_is_interface_up(adapter)) + goto get_adapter; + + hdd_wmm_init(adapter); + + adapter->scan_info.mScanPending = false; + + switch (adapter->device_mode) { + case QDF_STA_MODE: + case QDF_P2P_CLIENT_MODE: + case QDF_P2P_DEVICE_MODE: + + connState = (WLAN_HDD_GET_STATION_CTX_PTR(adapter)) + ->conn_info.connState; + + hdd_init_station_mode(adapter); + /* Open the gates for HDD to receive Wext commands */ + adapter->isLinkUpSvcNeeded = false; + + /* Indicate disconnect event to supplicant if associated previously */ + if (eConnectionState_Associated == connState || + eConnectionState_IbssConnected == connState || + eConnectionState_NotConnected == connState || + eConnectionState_IbssDisconnected == connState || + eConnectionState_Disconnecting == connState) { + union iwreq_data wrqu; + memset(&wrqu, '\0', sizeof(wrqu)); + wrqu.ap_addr.sa_family = ARPHRD_ETHER; + memset(wrqu.ap_addr.sa_data, '\0', ETH_ALEN); + wireless_send_event(adapter->dev, SIOCGIWAP, + &wrqu, NULL); + adapter->sessionCtx.station. + hdd_ReassocScenario = false; + + /* indicate disconnected event to nl80211 */ + wlan_hdd_cfg80211_indicate_disconnect( + adapter->dev, false, + WLAN_REASON_UNSPECIFIED); + } else if (eConnectionState_Connecting == connState) { + /* + * Indicate connect failure to supplicant if we were in the + * process of connecting + */ + hdd_connect_result(adapter->dev, NULL, NULL, + NULL, 0, NULL, 0, + WLAN_STATUS_ASSOC_DENIED_UNSPEC, + GFP_KERNEL, false, + 0); + } + + hdd_register_tx_flow_control(adapter, + hdd_tx_resume_timer_expired_handler, + hdd_tx_resume_cb); + + break; + + case QDF_SAP_MODE: + if (hdd_ctx->config->sap_internal_restart) + hdd_init_ap_mode(adapter, true); + + break; + + case QDF_P2P_GO_MODE: +#ifdef MSM_PLATFORM + hdd_notice("[SSR] send stop ap to supplicant"); + cfg80211_ap_stopped(adapter->dev, GFP_KERNEL); +#else + hdd_notice("[SSR] send restart supplicant"); + /* event supplicant to restart */ + cfg80211_del_sta(adapter->dev, + (const u8 *)&bcastMac.bytes[0], + GFP_KERNEL); +#endif + break; + + default: + break; + } +get_adapter: + status = hdd_get_next_adapter(hdd_ctx, adapterNode, &pNext); + adapterNode = pNext; + } + + EXIT(); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS hdd_get_front_adapter(hdd_context_t *hdd_ctx, + hdd_adapter_list_node_t **padapterNode) +{ + QDF_STATUS status; + qdf_spin_lock_bh(&hdd_ctx->hdd_adapter_lock); + status = qdf_list_peek_front(&hdd_ctx->hddAdapters, + (qdf_list_node_t **) padapterNode); + qdf_spin_unlock_bh(&hdd_ctx->hdd_adapter_lock); + return status; +} + +QDF_STATUS hdd_get_next_adapter(hdd_context_t *hdd_ctx, + hdd_adapter_list_node_t *adapterNode, + hdd_adapter_list_node_t **pNextAdapterNode) +{ + QDF_STATUS status; + qdf_spin_lock_bh(&hdd_ctx->hdd_adapter_lock); + status = qdf_list_peek_next(&hdd_ctx->hddAdapters, + (qdf_list_node_t *) adapterNode, + (qdf_list_node_t **) pNextAdapterNode); + + qdf_spin_unlock_bh(&hdd_ctx->hdd_adapter_lock); + return status; +} + +QDF_STATUS hdd_remove_adapter(hdd_context_t *hdd_ctx, + hdd_adapter_list_node_t *adapterNode) +{ + QDF_STATUS status; + qdf_spin_lock_bh(&hdd_ctx->hdd_adapter_lock); + status = qdf_list_remove_node(&hdd_ctx->hddAdapters, + &adapterNode->node); + qdf_spin_unlock_bh(&hdd_ctx->hdd_adapter_lock); + return status; +} + +QDF_STATUS hdd_remove_front_adapter(hdd_context_t *hdd_ctx, + hdd_adapter_list_node_t **padapterNode) +{ + QDF_STATUS status; + qdf_spin_lock_bh(&hdd_ctx->hdd_adapter_lock); + status = qdf_list_remove_front(&hdd_ctx->hddAdapters, + (qdf_list_node_t **) padapterNode); + qdf_spin_unlock_bh(&hdd_ctx->hdd_adapter_lock); + return status; +} + +QDF_STATUS hdd_add_adapter_back(hdd_context_t *hdd_ctx, + hdd_adapter_list_node_t *adapterNode) +{ + QDF_STATUS status; + qdf_spin_lock_bh(&hdd_ctx->hdd_adapter_lock); + status = qdf_list_insert_back(&hdd_ctx->hddAdapters, + (qdf_list_node_t *) adapterNode); + qdf_spin_unlock_bh(&hdd_ctx->hdd_adapter_lock); + return status; +} + +QDF_STATUS hdd_add_adapter_front(hdd_context_t *hdd_ctx, + hdd_adapter_list_node_t *adapterNode) +{ + QDF_STATUS status; + qdf_spin_lock_bh(&hdd_ctx->hdd_adapter_lock); + status = qdf_list_insert_front(&hdd_ctx->hddAdapters, + (qdf_list_node_t *) adapterNode); + qdf_spin_unlock_bh(&hdd_ctx->hdd_adapter_lock); + return status; +} + +hdd_adapter_t *hdd_get_adapter_by_macaddr(hdd_context_t *hdd_ctx, + tSirMacAddr macAddr) +{ + hdd_adapter_list_node_t *adapterNode = NULL, *pNext = NULL; + hdd_adapter_t *adapter; + QDF_STATUS status; + + status = hdd_get_front_adapter(hdd_ctx, &adapterNode); + + while (NULL != adapterNode && QDF_STATUS_SUCCESS == status) { + adapter = adapterNode->pAdapter; + + if (adapter + && !qdf_mem_cmp(adapter->macAddressCurrent.bytes, + macAddr, sizeof(tSirMacAddr))) { + return adapter; + } + status = hdd_get_next_adapter(hdd_ctx, adapterNode, &pNext); + adapterNode = pNext; + } + + return NULL; + +} + +hdd_adapter_t *hdd_get_adapter_by_vdev(hdd_context_t *hdd_ctx, + uint32_t vdev_id) +{ + hdd_adapter_list_node_t *adapterNode = NULL, *pNext = NULL; + hdd_adapter_t *adapter; + QDF_STATUS qdf_status; + + qdf_status = hdd_get_front_adapter(hdd_ctx, &adapterNode); + + while ((NULL != adapterNode) && (QDF_STATUS_SUCCESS == qdf_status)) { + adapter = adapterNode->pAdapter; + + if (adapter->sessionId == vdev_id) + return adapter; + + qdf_status = + hdd_get_next_adapter(hdd_ctx, adapterNode, &pNext); + adapterNode = pNext; + } + + hdd_err("vdev_id %d does not exist with host", vdev_id); + + return NULL; +} + +/** + * hdd_get_adapter_by_sme_session_id() - Return adapter with + * the sessionid + * @hdd_ctx: hdd context. + * @sme_session_id: sme session is for the adapter to get. + * + * This function is used to get the adapter with provided session id + * + * Return: adapter pointer if found + * + */ +hdd_adapter_t *hdd_get_adapter_by_sme_session_id(hdd_context_t *hdd_ctx, + uint32_t sme_session_id) +{ + hdd_adapter_list_node_t *adapter_node = NULL, *next = NULL; + hdd_adapter_t *adapter; + QDF_STATUS qdf_status; + + + qdf_status = hdd_get_front_adapter(hdd_ctx, &adapter_node); + + while ((NULL != adapter_node) && + (QDF_STATUS_SUCCESS == qdf_status)) { + adapter = adapter_node->pAdapter; + + if (adapter && + adapter->sessionId == sme_session_id) + return adapter; + + qdf_status = + hdd_get_next_adapter(hdd_ctx, + adapter_node, &next); + adapter_node = next; + } + return NULL; +} + +/** + * hdd_get_adapter() - to get adapter matching the mode + * @hdd_ctx: hdd context + * @mode: adapter mode + * + * This routine will return the pointer to adapter matching + * with the passed mode. + * + * Return: pointer to adapter or null + */ +hdd_adapter_t *hdd_get_adapter(hdd_context_t *hdd_ctx, + enum tQDF_ADAPTER_MODE mode) +{ + hdd_adapter_list_node_t *adapterNode = NULL, *pNext = NULL; + hdd_adapter_t *adapter; + QDF_STATUS status; + + status = hdd_get_front_adapter(hdd_ctx, &adapterNode); + + while (NULL != adapterNode && QDF_STATUS_SUCCESS == status) { + adapter = adapterNode->pAdapter; + + if (adapter && (mode == adapter->device_mode)) + return adapter; + + status = hdd_get_next_adapter(hdd_ctx, adapterNode, &pNext); + adapterNode = pNext; + } + + return NULL; + +} + +/** + * hdd_get_operating_channel() - return operating channel of the device mode + * @hdd_ctx: Pointer to the HDD context. + * @mode: Device mode for which operating channel is required. + * Suported modes: + * QDF_STA_MODE, + * QDF_P2P_CLIENT_MODE, + * QDF_SAP_MODE, + * QDF_P2P_GO_MODE. + * + * This API returns the operating channel of the requested device mode + * + * Return: channel number. "0" id the requested device is not found OR it is + * not connected. + */ +uint8_t hdd_get_operating_channel(hdd_context_t *hdd_ctx, + enum tQDF_ADAPTER_MODE mode) +{ + hdd_adapter_list_node_t *adapterNode = NULL, *pNext = NULL; + QDF_STATUS status; + hdd_adapter_t *adapter; + uint8_t operatingChannel = 0; + + status = hdd_get_front_adapter(hdd_ctx, &adapterNode); + + while (NULL != adapterNode && QDF_STATUS_SUCCESS == status) { + adapter = adapterNode->pAdapter; + + if (mode == adapter->device_mode) { + switch (adapter->device_mode) { + case QDF_STA_MODE: + case QDF_P2P_CLIENT_MODE: + if (hdd_conn_is_connected + (WLAN_HDD_GET_STATION_CTX_PTR + (adapter))) { + operatingChannel = + (WLAN_HDD_GET_STATION_CTX_PTR + (adapter))->conn_info. + operationChannel; + } + break; + case QDF_SAP_MODE: + case QDF_P2P_GO_MODE: + /* softap connection info */ + if (test_bit + (SOFTAP_BSS_STARTED, + &adapter->event_flags)) + operatingChannel = + (WLAN_HDD_GET_AP_CTX_PTR + (adapter))->operatingChannel; + break; + default: + break; + } + + break; /* Found the device of interest. break the loop */ + } + + status = hdd_get_next_adapter(hdd_ctx, adapterNode, &pNext); + adapterNode = pNext; + } + return operatingChannel; +} + +static inline QDF_STATUS hdd_unregister_wext_all_adapters(hdd_context_t * + hdd_ctx) +{ + hdd_adapter_list_node_t *adapterNode = NULL, *pNext = NULL; + QDF_STATUS status; + hdd_adapter_t *adapter; + + ENTER(); + + status = hdd_get_front_adapter(hdd_ctx, &adapterNode); + + while (NULL != adapterNode && QDF_STATUS_SUCCESS == status) { + adapter = adapterNode->pAdapter; + if ((adapter->device_mode == QDF_STA_MODE) || + (adapter->device_mode == QDF_P2P_CLIENT_MODE) || + (adapter->device_mode == QDF_IBSS_MODE) || + (adapter->device_mode == QDF_P2P_DEVICE_MODE) || + (adapter->device_mode == QDF_SAP_MODE) || + (adapter->device_mode == QDF_P2P_GO_MODE)) { + wlan_hdd_cfg80211_deregister_frames(adapter); + hdd_unregister_wext(adapter->dev); + } + status = hdd_get_next_adapter(hdd_ctx, adapterNode, &pNext); + adapterNode = pNext; + } + + EXIT(); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS hdd_abort_mac_scan_all_adapters(hdd_context_t *hdd_ctx) +{ + hdd_adapter_list_node_t *adapterNode = NULL, *pNext = NULL; + QDF_STATUS status; + hdd_adapter_t *adapter; + + ENTER(); + + status = hdd_get_front_adapter(hdd_ctx, &adapterNode); + + while (NULL != adapterNode && QDF_STATUS_SUCCESS == status) { + adapter = adapterNode->pAdapter; + if ((adapter->device_mode == QDF_STA_MODE) || + (adapter->device_mode == QDF_P2P_CLIENT_MODE) || + (adapter->device_mode == QDF_IBSS_MODE) || + (adapter->device_mode == QDF_P2P_DEVICE_MODE) || + (adapter->device_mode == QDF_SAP_MODE) || + (adapter->device_mode == QDF_P2P_GO_MODE)) { + hdd_abort_mac_scan(hdd_ctx, adapter->sessionId, + INVALID_SCAN_ID, + eCSR_SCAN_ABORT_DEFAULT); + } + status = hdd_get_next_adapter(hdd_ctx, adapterNode, &pNext); + adapterNode = pNext; + } + + EXIT(); + + return QDF_STATUS_SUCCESS; +} + +/** + * hdd_abort_sched_scan_all_adapters() - stops scheduled (PNO) scans for all + * adapters + * @hdd_ctx: The HDD context containing the adapters to operate on + * + * return: QDF_STATUS_SUCCESS + */ +static QDF_STATUS hdd_abort_sched_scan_all_adapters(hdd_context_t *hdd_ctx) +{ + hdd_adapter_list_node_t *adapter_node = NULL, *next_node = NULL; + QDF_STATUS status; + hdd_adapter_t *adapter; + int err; + + ENTER(); + + status = hdd_get_front_adapter(hdd_ctx, &adapter_node); + + while (NULL != adapter_node && QDF_STATUS_SUCCESS == status) { + adapter = adapter_node->pAdapter; + if ((adapter->device_mode == QDF_STA_MODE) || + (adapter->device_mode == QDF_P2P_CLIENT_MODE) || + (adapter->device_mode == QDF_IBSS_MODE) || + (adapter->device_mode == QDF_P2P_DEVICE_MODE) || + (adapter->device_mode == QDF_SAP_MODE) || + (adapter->device_mode == QDF_P2P_GO_MODE)) { + err = wlan_hdd_sched_scan_stop(adapter->dev); + if (err) + hdd_err("Unable to stop scheduled scan"); + } + status = hdd_get_next_adapter(hdd_ctx, adapter_node, &next_node); + adapter_node = next_node; + } + + EXIT(); + + return QDF_STATUS_SUCCESS; +} + +#ifdef WLAN_NS_OFFLOAD +/** + * hdd_wlan_unregister_ip6_notifier() - unregister IPv6 change notifier + * @hdd_ctx: Pointer to hdd context + * + * Unregister for IPv6 address change notifications. + * + * Return: None + */ +static void hdd_wlan_unregister_ip6_notifier(hdd_context_t *hdd_ctx) +{ + unregister_inet6addr_notifier(&hdd_ctx->ipv6_notifier); + + return; +} + +/** + * hdd_wlan_register_ip6_notifier() - register IPv6 change notifier + * @hdd_ctx: Pointer to hdd context + * + * Register for IPv6 address change notifications. + * + * Return: 0 on success and errno on failure. + */ +static int hdd_wlan_register_ip6_notifier(hdd_context_t *hdd_ctx) +{ + int ret; + + hdd_ctx->ipv6_notifier.notifier_call = wlan_hdd_ipv6_changed; + ret = register_inet6addr_notifier(&hdd_ctx->ipv6_notifier); + if (ret) { + hdd_err("Failed to register IPv6 notifier: %d", ret); + goto out; + } + + hdd_info("Registered IPv6 notifier"); +out: + return ret; +} +#else +/** + * hdd_wlan_unregister_ip6_notifier() - unregister IPv6 change notifier + * @hdd_ctx: Pointer to hdd context + * + * Unregister for IPv6 address change notifications. + * + * Return: None + */ +static void hdd_wlan_unregister_ip6_notifier(hdd_context_t *hdd_ctx) +{ +} + +/** + * hdd_wlan_register_ip6_notifier() - register IPv6 change notifier + * @hdd_ctx: Pointer to hdd context + * + * Register for IPv6 address change notifications. + * + * Return: None + */ +static int hdd_wlan_register_ip6_notifier(hdd_context_t *hdd_ctx) +{ + return 0; +} +#endif + +#ifdef WLAN_LOGGING_SOCK_SVC_ENABLE +/** + * hdd_logging_sock_activate_svc() - Activate logging + * @hdd_ctx: HDD context + * + * Activates the logging service + * + * Return: Zero in case of success, negative value otherwise + */ +static int hdd_logging_sock_activate_svc(hdd_context_t *hdd_ctx) +{ + int ret; + struct hdd_config *config = hdd_ctx->config; + + if (!config->wlanLoggingEnable) + return 0; + + ret = wlan_logging_sock_activate_svc(config->wlanLoggingFEToConsole, + config->wlanLoggingNumBuf); + if (ret) + hdd_err("wlan_logging_sock_activate_svc failed: %d", ret); + return ret; +} + +/** + * wlan_hdd_logging_sock_deactivate_svc() - Deactivate logging + * @hdd_ctx: HDD context + * + * Deactivates the logging service + * + * Return: 0 on deactivating the logging service + */ +static int hdd_logging_sock_deactivate_svc(hdd_context_t *hdd_ctx) +{ + if (hdd_ctx && hdd_ctx->config->wlanLoggingEnable) + return wlan_logging_sock_deactivate_svc(); + + return 0; +} +#else +static inline int hdd_logging_sock_activate_svc(hdd_context_t *hdd_ctx) +{ + return 0; +} + +static inline int hdd_logging_sock_deactivate_svc(hdd_context_t *hdd_ctx) +{ + return 0; +} +#endif + +/** + * hdd_register_notifiers - Register netdev notifiers. + * @hdd_ctx: HDD context + * + * Register netdev notifiers like IPv4 and IPv6. + * + * Return: 0 on success and errno on failure + */ +static int hdd_register_notifiers(hdd_context_t *hdd_ctx) +{ + int ret; + + ret = hdd_wlan_register_ip6_notifier(hdd_ctx); + if (ret) + goto out; + + hdd_ctx->ipv4_notifier.notifier_call = wlan_hdd_ipv4_changed; + ret = register_inetaddr_notifier(&hdd_ctx->ipv4_notifier); + if (ret) { + hdd_err("Failed to register IPv4 notifier: %d", ret); + goto unregister_ip6_notifier; + } + + return 0; + +unregister_ip6_notifier: + hdd_wlan_unregister_ip6_notifier(hdd_ctx); +out: + return ret; + +} + +/** + * hdd_unregister_notifiers - Unregister netdev notifiers. + * @hdd_ctx: HDD context + * + * Unregister netdev notifiers like IPv4 and IPv6. + * + * Return: None. + */ +void hdd_unregister_notifiers(hdd_context_t *hdd_ctx) +{ + hdd_wlan_unregister_ip6_notifier(hdd_ctx); + + unregister_inetaddr_notifier(&hdd_ctx->ipv4_notifier); +} + +/** + * hdd_exit_netlink_services - Exit netlink services + * @hdd_ctx: HDD context + * + * Exit netlink services like cnss_diag, cesium netlink socket, ptt socket and + * nl service. + * + * Return: None. + */ +static void hdd_exit_netlink_services(hdd_context_t *hdd_ctx) +{ + hdd_close_cesium_nl_sock(); + + ptt_sock_deactivate_svc(); + + nl_srv_exit(); +} + +/** + * hdd_init_netlink_services- Init netlink services + * @hdd_ctx: HDD context + * + * Init netlink services like cnss_diag, cesium netlink socket, ptt socket and + * nl service. + * + * Return: 0 on success and errno on failure. + */ +static int hdd_init_netlink_services(hdd_context_t *hdd_ctx) +{ + int ret; + + ret = wlan_hdd_nl_init(hdd_ctx); + if (ret) { + hdd_alert("nl_srv_init failed: %d", ret); + goto out; + } + cds_set_radio_index(hdd_ctx->radio_index); + + ret = oem_activate_service(hdd_ctx); + if (ret) { + hdd_alert("oem_activate_service failed: %d", ret); + goto err_nl_srv; + } + + ret = ptt_sock_activate_svc(); + if (ret) { + hdd_alert("ptt_sock_activate_svc failed: %d", ret); + goto err_nl_srv; + } + + ret = hdd_open_cesium_nl_sock(); + if (ret) + hdd_warn("hdd_open_cesium_nl_sock failed"); + + ret = cnss_diag_activate_service(); + if (ret) { + hdd_alert("cnss_diag_activate_service failed: %d", ret); + goto err_close_cesium; + } + + return 0; + +err_close_cesium: + hdd_close_cesium_nl_sock(); + ptt_sock_deactivate_svc(); +err_nl_srv: + nl_srv_exit(); +out: + return ret; +} + +/** + * hdd_rx_wake_lock_destroy() - Destroy RX wakelock + * @hdd_ctx: HDD context. + * + * Destroy RX wakelock. + * + * Return: None. + */ +static void hdd_rx_wake_lock_destroy(hdd_context_t *hdd_ctx) +{ + qdf_wake_lock_destroy(&hdd_ctx->rx_wake_lock); +} + +/** + * hdd_rx_wake_lock_create() - Create RX wakelock + * @hdd_ctx: HDD context. + * + * Create RX wakelock. + * + * Return: None. + */ +static void hdd_rx_wake_lock_create(hdd_context_t *hdd_ctx) +{ + qdf_wake_lock_create(&hdd_ctx->rx_wake_lock, "qcom_rx_wakelock"); +} + +/** + * hdd_roc_context_init() - Init ROC context + * @hdd_ctx: HDD context. + * + * Initialize ROC context. + * + * Return: 0 on success and errno on failure. + */ +static int hdd_roc_context_init(hdd_context_t *hdd_ctx) +{ + qdf_spinlock_create(&hdd_ctx->hdd_roc_req_q_lock); + qdf_list_create(&hdd_ctx->hdd_roc_req_q, MAX_ROC_REQ_QUEUE_ENTRY); + + INIT_DELAYED_WORK(&hdd_ctx->roc_req_work, wlan_hdd_roc_request_dequeue); + + return 0; +} + +/** + * hdd_destroy_roc_req_q() - Free allocations in ROC Req Queue + * @hdd_ctx: HDD context. + * + * Free memory allocations made in ROC Req Queue nodes. + * + * Return: None. + */ +static void hdd_destroy_roc_req_q(hdd_context_t *hdd_ctx) +{ + hdd_roc_req_t *hdd_roc_req; + QDF_STATUS status; + + qdf_spin_lock(&hdd_ctx->hdd_roc_req_q_lock); + + while (!qdf_list_empty(&hdd_ctx->hdd_roc_req_q)) { + status = qdf_list_remove_front(&hdd_ctx->hdd_roc_req_q, + (qdf_list_node_t **) &hdd_roc_req); + + if (QDF_STATUS_SUCCESS != status) { + hdd_debug("unable to remove roc element from list in %s", + __func__); + QDF_ASSERT(0); + return; + } + + if (hdd_roc_req->pRemainChanCtx) + qdf_mem_free(hdd_roc_req->pRemainChanCtx); + + qdf_mem_free(hdd_roc_req); + } + + qdf_spin_unlock(&hdd_ctx->hdd_roc_req_q_lock); +} + +/** + * hdd_roc_context_destroy() - Destroy ROC context + * @hdd_ctx: HDD context. + * + * Destroy roc list and flush the pending roc work. + * + * Return: None. + */ +static void hdd_roc_context_destroy(hdd_context_t *hdd_ctx) +{ + flush_delayed_work(&hdd_ctx->roc_req_work); + hdd_destroy_roc_req_q(hdd_ctx); + qdf_spinlock_destroy(&hdd_ctx->hdd_roc_req_q_lock); +} + +/** + * hdd_context_deinit() - Deinitialize HDD context + * @hdd_ctx: HDD context. + * + * Deinitialize HDD context along with all the feature specific contexts but + * do not free hdd context itself. Caller of this API is supposed to free + * HDD context. + * + * return: 0 on success and errno on failure. + */ +static int hdd_context_deinit(hdd_context_t *hdd_ctx) +{ + wlan_hdd_cfg80211_deinit(hdd_ctx->wiphy); + + hdd_roc_context_destroy(hdd_ctx); + + hdd_sap_context_destroy(hdd_ctx); + + hdd_rx_wake_lock_destroy(hdd_ctx); + + hdd_tdls_context_destroy(hdd_ctx); + + hdd_scan_context_destroy(hdd_ctx); + + qdf_list_destroy(&hdd_ctx->hddAdapters); + + return 0; +} + +/** + * hdd_context_destroy() - Destroy HDD context + * @hdd_ctx: HDD context to be destroyed. + * + * Free config and HDD context as well as destroy all the resources. + * + * Return: None + */ +static void hdd_context_destroy(hdd_context_t *hdd_ctx) +{ + + hdd_logging_sock_deactivate_svc(hdd_ctx); + + wlan_hdd_deinit_tx_rx_histogram(hdd_ctx); + + hdd_context_deinit(hdd_ctx); + + qdf_mem_free(hdd_ctx->config); + hdd_ctx->config = NULL; + + wiphy_free(hdd_ctx->wiphy); +} + +/** + * wlan_destroy_bug_report_lock() - Destroy bug report lock + * + * This function is used to destroy bug report lock + * + * Return: None + */ +static void wlan_destroy_bug_report_lock(void) +{ + p_cds_contextType p_cds_context; + + p_cds_context = cds_get_global_context(); + if (!p_cds_context) { + hdd_err("cds context is NULL"); + return; + } + + qdf_spinlock_destroy(&p_cds_context->bug_report_lock); +} + +/** + * hdd_wlan_exit() - HDD WLAN exit function + * @hdd_ctx: Pointer to the HDD Context + * + * This is the driver exit point (invoked during rmmod) + * + * Return: None + */ +static void hdd_wlan_exit(hdd_context_t *hdd_ctx) +{ + v_CONTEXT_t p_cds_context = hdd_ctx->pcds_context; + QDF_STATUS qdf_status; + struct wiphy *wiphy = hdd_ctx->wiphy; + int driver_status; + + ENTER(); + + if (QDF_TIMER_STATE_RUNNING == + qdf_mc_timer_get_current_state(&hdd_ctx->iface_change_timer)) { + hdd_info("Stpp interface change timer"); + qdf_mc_timer_stop(&hdd_ctx->iface_change_timer); + } + + if (!QDF_IS_STATUS_SUCCESS + (qdf_mc_timer_destroy(&hdd_ctx->iface_change_timer))) + hdd_err("Cannot delete interface change timer"); + + + hdd_unregister_notifiers(hdd_ctx); + + qdf_mc_timer_destroy(&hdd_ctx->tdls_source_timer); + + hdd_bus_bandwidth_destroy(hdd_ctx); + +#ifdef FEATURE_WLAN_AP_AP_ACS_OPTIMIZE + if (QDF_TIMER_STATE_RUNNING == + qdf_mc_timer_get_current_state(&hdd_ctx->skip_acs_scan_timer)) { + qdf_mc_timer_stop(&hdd_ctx->skip_acs_scan_timer); + } + + if (!QDF_IS_STATUS_SUCCESS + (qdf_mc_timer_destroy(&hdd_ctx->skip_acs_scan_timer))) { + hdd_err("Cannot deallocate ACS Skip timer"); + } + qdf_spin_lock(&hdd_ctx->acs_skip_lock); + qdf_mem_free(hdd_ctx->last_acs_channel_list); + hdd_ctx->last_acs_channel_list = NULL; + hdd_ctx->num_of_channels = 0; + qdf_spin_unlock(&hdd_ctx->acs_skip_lock); +#endif + + mutex_lock(&hdd_ctx->iface_change_lock); + driver_status = hdd_ctx->driver_status; + mutex_unlock(&hdd_ctx->iface_change_lock); + + /* + * Powersave Offload Case + * Disable Idle Power Save Mode + */ + hdd_set_idle_ps_config(hdd_ctx, false); + + if (driver_status != DRIVER_MODULES_CLOSED) { + hdd_unregister_wext_all_adapters(hdd_ctx); + /* + * Cancel any outstanding scan requests. We are about to close + * all of our adapters, but an adapter structure is what SME + * passes back to our callback function. Hence if there + * are any outstanding scan requests then there is a + * race condition between when the adapter is closed and + * when the callback is invoked. We try to resolve that + * race condition here by canceling any outstanding scans + * before we close the adapters. + * Note that the scans may be cancelled in an asynchronous + * manner, so ideally there needs to be some kind of + * synchronization. Rather than introduce a new + * synchronization here, we will utilize the fact that we are + * about to Request Full Power, and since that is synchronized, + * the expectation is that by the time Request Full Power has + * completed, all scans will be cancelled + */ + hdd_cleanup_scan_queue(hdd_ctx); + hdd_abort_mac_scan_all_adapters(hdd_ctx); + hdd_abort_sched_scan_all_adapters(hdd_ctx); + hdd_stop_all_adapters(hdd_ctx); + } + + wlan_destroy_bug_report_lock(); + + /* + * Close the scheduler before calling cds_close to make sure + * no thread is scheduled after the each module close is + * is called i.e after all the data structures are freed. + */ + qdf_status = cds_sched_close(p_cds_context); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + hdd_alert("Failed to close CDS Scheduler"); + QDF_ASSERT(QDF_IS_STATUS_SUCCESS(qdf_status)); + } + + hdd_wlan_stop_modules(hdd_ctx, false); + + qdf_spinlock_destroy(&hdd_ctx->hdd_adapter_lock); + qdf_spinlock_destroy(&hdd_ctx->sta_update_info_lock); + qdf_spinlock_destroy(&hdd_ctx->connection_status_lock); + + /* + * Close CDS + * This frees pMac(HAL) context. There should not be any call + * that requires pMac access after this. + */ + + hdd_green_ap_deinit(hdd_ctx); + + hdd_runtime_suspend_context_deinit(hdd_ctx); + hdd_close_all_adapters(hdd_ctx, false); + + unregister_netdevice_notifier(&hdd_netdev_notifier); + + hdd_ipa_cleanup(hdd_ctx); + + /* Free up RoC request queue and flush workqueue */ + cds_flush_work(&hdd_ctx->roc_req_work); + + wlansap_global_deinit(); + /* + * If there is re_init failure wiphy would have already de-registered + * check the wiphy status before un-registering again + */ + if (wiphy && wiphy->registered) { + wiphy_unregister(wiphy); + wlan_hdd_cfg80211_deinit(wiphy); + hdd_lpass_notify_stop(hdd_ctx); + } + + hdd_exit_netlink_services(hdd_ctx); + mutex_destroy(&hdd_ctx->iface_change_lock); + hdd_context_destroy(hdd_ctx); +} + +void __hdd_wlan_exit(void) +{ + hdd_context_t *hdd_ctx; + + ENTER(); + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (!hdd_ctx) { + hdd_alert("Invalid HDD Context"); + EXIT(); + return; + } + + memdump_deinit(); + hdd_driver_memdump_deinit(); + + /* Do all the cleanup before deregistering the driver */ + hdd_wlan_exit(hdd_ctx); + + EXIT(); +} + +#ifdef FEATURE_WLAN_AP_AP_ACS_OPTIMIZE +/** + * hdd_skip_acs_scan_timer_handler() - skip ACS scan timer timeout handler + * @data: pointer to hdd_context_t + * + * This function will reset acs_scan_status to eSAP_DO_NEW_ACS_SCAN. + * Then new ACS request will do a fresh scan without reusing the cached + * scan information. + * + * Return: void + */ +static void hdd_skip_acs_scan_timer_handler(void *data) +{ + hdd_context_t *hdd_ctx = (hdd_context_t *) data; + + hdd_notice("ACS Scan result expired. Reset ACS scan skip"); + hdd_ctx->skip_acs_scan_status = eSAP_DO_NEW_ACS_SCAN; + qdf_spin_lock(&hdd_ctx->acs_skip_lock); + qdf_mem_free(hdd_ctx->last_acs_channel_list); + hdd_ctx->last_acs_channel_list = NULL; + hdd_ctx->num_of_channels = 0; + qdf_spin_unlock(&hdd_ctx->acs_skip_lock); + + if (!hdd_ctx->hHal) + return; + sme_scan_flush_result(hdd_ctx->hHal); +} +#endif + +#ifdef QCA_HT_2040_COEX +/** + * hdd_wlan_set_ht2040_mode() - notify FW with HT20/HT40 mode + * @adapter: pointer to adapter + * @staId: station id + * @macAddrSTA: station MAC address + * @channel_type: channel type + * + * This function notifies FW with HT20/HT40 mode + * + * Return: 0 if successful, error number otherwise + */ +int hdd_wlan_set_ht2040_mode(hdd_adapter_t *adapter, uint16_t staId, + struct qdf_mac_addr macAddrSTA, int channel_type) +{ + int status; + QDF_STATUS qdf_status; + hdd_context_t *hdd_ctx = NULL; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + + status = wlan_hdd_validate_context(hdd_ctx); + if (status) + return status; + + if (!hdd_ctx->hHal) + return -EINVAL; + + qdf_status = sme_notify_ht2040_mode(hdd_ctx->hHal, staId, macAddrSTA, + adapter->sessionId, channel_type); + if (QDF_STATUS_SUCCESS != qdf_status) { + hdd_err("Fail to send notification with ht2040 mode"); + return -EINVAL; + } + + return 0; +} +#endif + +/** + * hdd_wlan_notify_modem_power_state() - notify FW with modem power status + * @state: state + * + * This function notifies FW with modem power status + * + * Return: 0 if successful, error number otherwise + */ +int hdd_wlan_notify_modem_power_state(int state) +{ + int status; + QDF_STATUS qdf_status; + hdd_context_t *hdd_ctx; + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + status = wlan_hdd_validate_context(hdd_ctx); + if (status) + return status; + + if (!hdd_ctx->hHal) + return -EINVAL; + + qdf_status = sme_notify_modem_power_state(hdd_ctx->hHal, state); + if (QDF_STATUS_SUCCESS != qdf_status) { + hdd_err("Fail to send notification with modem power state %d", + state); + return -EINVAL; + } + return 0; +} + +/** + * + * hdd_post_cds_enable_config() - HDD post cds start config helper + * @adapter - Pointer to the HDD + * + * Return: None + */ +QDF_STATUS hdd_post_cds_enable_config(hdd_context_t *hdd_ctx) +{ + QDF_STATUS qdf_ret_status; + + /* + * Send ready indication to the HDD. This will kick off the MAC + * into a 'running' state and should kick off an initial scan. + */ + qdf_ret_status = sme_hdd_ready_ind(hdd_ctx->hHal); + if (!QDF_IS_STATUS_SUCCESS(qdf_ret_status)) { + hdd_err("sme_hdd_ready_ind() failed with status code %08d [x%08x]", + qdf_ret_status, qdf_ret_status); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/* wake lock APIs for HDD */ +void hdd_prevent_suspend(uint32_t reason) +{ + qdf_wake_lock_acquire(&wlan_wake_lock, reason); +} + +void hdd_allow_suspend(uint32_t reason) +{ + qdf_wake_lock_release(&wlan_wake_lock, reason); +} + +void hdd_prevent_suspend_timeout(uint32_t timeout, uint32_t reason) +{ + cds_host_diag_log_work(&wlan_wake_lock, timeout, reason); + qdf_wake_lock_timeout_acquire(&wlan_wake_lock, timeout); +} + +/** + * hdd_exchange_version_and_caps() - exchange version and capability with target + * @hdd_ctx: Pointer to HDD context + * + * This is the HDD function to exchange version and capability information + * between Host and Target + * + * This function gets reported version of FW. + * It also finds the version of target headers used to compile the host; + * It compares the above two and prints a warning if they are different; + * It gets the SW and HW version string; + * Finally, it exchanges capabilities between host and target i.e. host + * and target exchange a msg indicating the features they support through a + * bitmap + * + * Return: None + */ +void hdd_exchange_version_and_caps(hdd_context_t *hdd_ctx) +{ + + tSirVersionType versionCompiled; + tSirVersionType versionReported; + tSirVersionString versionString; + uint8_t fwFeatCapsMsgSupported = 0; + QDF_STATUS vstatus; + + memset(&versionCompiled, 0, sizeof(versionCompiled)); + memset(&versionReported, 0, sizeof(versionReported)); + + /* retrieve and display WCNSS version information */ + do { + + vstatus = sme_get_wcnss_wlan_compiled_version(hdd_ctx->hHal, + &versionCompiled); + if (!QDF_IS_STATUS_SUCCESS(vstatus)) { + hdd_alert("unable to retrieve WCNSS WLAN compiled version"); + break; + } + + vstatus = sme_get_wcnss_wlan_reported_version(hdd_ctx->hHal, + &versionReported); + if (!QDF_IS_STATUS_SUCCESS(vstatus)) { + hdd_alert("unable to retrieve WCNSS WLAN reported version"); + break; + } + + if ((versionCompiled.major != versionReported.major) || + (versionCompiled.minor != versionReported.minor) || + (versionCompiled.version != versionReported.version) || + (versionCompiled.revision != versionReported.revision)) { + pr_err("%s: WCNSS WLAN Version %u.%u.%u.%u, " + "Host expected %u.%u.%u.%u\n", + WLAN_MODULE_NAME, + (int)versionReported.major, + (int)versionReported.minor, + (int)versionReported.version, + (int)versionReported.revision, + (int)versionCompiled.major, + (int)versionCompiled.minor, + (int)versionCompiled.version, + (int)versionCompiled.revision); + } else { + pr_info("%s: WCNSS WLAN version %u.%u.%u.%u\n", + WLAN_MODULE_NAME, + (int)versionReported.major, + (int)versionReported.minor, + (int)versionReported.version, + (int)versionReported.revision); + } + + vstatus = sme_get_wcnss_software_version(hdd_ctx->hHal, + versionString, + sizeof(versionString)); + if (!QDF_IS_STATUS_SUCCESS(vstatus)) { + hdd_alert("unable to retrieve WCNSS software version string"); + break; + } + + pr_info("%s: WCNSS software version %s\n", + WLAN_MODULE_NAME, versionString); + + vstatus = sme_get_wcnss_hardware_version(hdd_ctx->hHal, + versionString, + sizeof(versionString)); + if (!QDF_IS_STATUS_SUCCESS(vstatus)) { + hdd_alert("unable to retrieve WCNSS hardware version string"); + break; + } + + pr_info("%s: WCNSS hardware version %s\n", + WLAN_MODULE_NAME, versionString); + + /* + * 1.Check if FW version is greater than 0.1.1.0. Only then + * send host-FW capability exchange message + * 2.Host-FW capability exchange message is only present on + * target 1.1 so send the message only if it the target is 1.1 + * minor numbers for different target branches: + * 0 -> (1.0)Mainline Build + * 1 -> (1.1)Mainline Build + * 2->(1.04) Stability Build + */ + if (((versionReported.major > 0) || (versionReported.minor > 1) + || ((versionReported.minor >= 1) + && (versionReported.version >= 1))) + && ((versionReported.major == 1) + && (versionReported.minor >= 1))) + fwFeatCapsMsgSupported = 1; + + if (fwFeatCapsMsgSupported) { + /* + * Indicate if IBSS heartbeat monitoring needs to be + * offloaded + */ + if (!hdd_ctx->config->enableIbssHeartBeatOffload) { + sme_disable_feature_capablity + (IBSS_HEARTBEAT_OFFLOAD); + } + + sme_feature_caps_exchange(hdd_ctx->hHal); + } + + } while (0); + +} + +/* Initialize channel list in sme based on the country code */ +QDF_STATUS hdd_set_sme_chan_list(hdd_context_t *hdd_ctx) +{ + return sme_init_chan_list(hdd_ctx->hHal, hdd_ctx->reg.alpha2, + hdd_ctx->reg.cc_src); +} + +/** + * hdd_is_5g_supported() - check if hardware supports 5GHz + * @hdd_ctx: Pointer to the hdd context + * + * HDD function to know if hardware supports 5GHz + * + * Return: true if hardware supports 5GHz + */ +bool hdd_is_5g_supported(hdd_context_t *hdd_ctx) +{ + if (!hdd_ctx || !hdd_ctx->config) + return true; + + if (hdd_ctx->config->nBandCapability != eCSR_BAND_24) + return true; + else + return false; +} + +static int hdd_wiphy_init(hdd_context_t *hdd_ctx) +{ + struct wiphy *wiphy; + int ret_val; + + wiphy = hdd_ctx->wiphy; + + /* + * The channel information in + * wiphy needs to be initialized before wiphy registration + */ + ret_val = hdd_regulatory_init(hdd_ctx, wiphy); + if (ret_val) { + hdd_alert("regulatory init failed"); + return ret_val; + } + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)) + wiphy->wowlan = &wowlan_support_reg_init; +#else + wiphy->wowlan.flags = WIPHY_WOWLAN_ANY | + WIPHY_WOWLAN_MAGIC_PKT | + WIPHY_WOWLAN_DISCONNECT | + WIPHY_WOWLAN_SUPPORTS_GTK_REKEY | + WIPHY_WOWLAN_GTK_REKEY_FAILURE | + WIPHY_WOWLAN_EAP_IDENTITY_REQ | + WIPHY_WOWLAN_4WAY_HANDSHAKE | + WIPHY_WOWLAN_RFKILL_RELEASE; + + wiphy->wowlan.n_patterns = (WOW_MAX_FILTER_LISTS * + WOW_MAX_FILTERS_PER_LIST); + wiphy->wowlan.pattern_min_len = WOW_MIN_PATTERN_SIZE; + wiphy->wowlan.pattern_max_len = WOW_MAX_PATTERN_SIZE; +#endif + + /* registration of wiphy dev with cfg80211 */ + ret_val = wlan_hdd_cfg80211_register(wiphy); + if (0 > ret_val) { + hdd_err("wiphy registration failed"); + return ret_val; + } + + pld_increment_driver_load_cnt(hdd_ctx->parent_dev); + + hdd_program_country_code(hdd_ctx); + + return ret_val; +} + +/** + * hdd_pld_request_bus_bandwidth() - Function to control bus bandwidth + * @hdd_ctx - handle to hdd context + * @tx_packets - transmit packet count + * @rx_packets - receive packet count + * + * The function controls the bus bandwidth and dynamic control of + * tcp delayed ack configuration + * + * Returns: None + */ +#ifdef MSM_PLATFORM +static void hdd_pld_request_bus_bandwidth(hdd_context_t *hdd_ctx, + const uint64_t tx_packets, + const uint64_t rx_packets) +{ + uint64_t total = tx_packets + rx_packets; + uint64_t temp_rx = 0; + uint64_t temp_tx = 0; + enum pld_bus_width_type next_vote_level = PLD_BUS_WIDTH_NONE; + static enum wlan_tp_level next_rx_level = WLAN_SVC_TP_NONE; + enum wlan_tp_level next_tx_level = WLAN_SVC_TP_NONE; + uint32_t delack_timer_cnt = hdd_ctx->config->tcp_delack_timer_count; + uint16_t index = 0; + bool vote_level_change = false; + bool rx_level_change = false; + bool tx_level_change = false; + + if (total > hdd_ctx->config->busBandwidthHighThreshold) + next_vote_level = PLD_BUS_WIDTH_HIGH; + else if (total > hdd_ctx->config->busBandwidthMediumThreshold) + next_vote_level = PLD_BUS_WIDTH_MEDIUM; + else if (total > hdd_ctx->config->busBandwidthLowThreshold) + next_vote_level = PLD_BUS_WIDTH_LOW; + else + next_vote_level = PLD_BUS_WIDTH_NONE; + + if (hdd_ctx->cur_vote_level != next_vote_level) { + hdd_debug("trigger level %d, tx_packets: %lld, rx_packets: %lld", + next_vote_level, tx_packets, rx_packets); + hdd_ctx->cur_vote_level = next_vote_level; + vote_level_change = true; + pld_request_bus_bandwidth(hdd_ctx->parent_dev, next_vote_level); + if (next_vote_level == PLD_BUS_WIDTH_LOW) { + if (hdd_ctx->hbw_requested) { + pld_remove_pm_qos(hdd_ctx->parent_dev); + hdd_ctx->hbw_requested = false; + } + if (cds_sched_handle_throughput_req(false)) + hdd_warn("low bandwidth set rx affinity fail"); + } else { + if (!hdd_ctx->hbw_requested) { + pld_request_pm_qos(hdd_ctx->parent_dev, 1); + hdd_ctx->hbw_requested = true; + } + + if (cds_sched_handle_throughput_req(true)) + hdd_warn("high bandwidth set rx affinity fail"); + } + hdd_napi_apply_throughput_policy(hdd_ctx, tx_packets, rx_packets); + } + + /* fine-tuning parameters for RX Flows */ + temp_rx = (rx_packets + hdd_ctx->prev_rx) / 2; + + hdd_ctx->prev_rx = rx_packets; + + if (temp_rx < hdd_ctx->config->busBandwidthLowThreshold) + hdd_disable_lro_for_low_tput(hdd_ctx, true); + else + hdd_disable_lro_for_low_tput(hdd_ctx, false); + + if (temp_rx > hdd_ctx->config->tcpDelackThresholdHigh) { + if ((hdd_ctx->cur_rx_level != WLAN_SVC_TP_HIGH) && + (++hdd_ctx->rx_high_ind_cnt == delack_timer_cnt)) { + next_rx_level = WLAN_SVC_TP_HIGH; + } + } else { + hdd_ctx->rx_high_ind_cnt = 0; + next_rx_level = WLAN_SVC_TP_LOW; + } + + if (hdd_ctx->cur_rx_level != next_rx_level) { + struct wlan_rx_tp_data rx_tp_data = {0}; + + hdd_debug("TCP DELACK trigger level %d, average_rx: %llu", + next_rx_level, temp_rx); + hdd_ctx->cur_rx_level = next_rx_level; + rx_level_change = true; + /* Send throughput indication only if it is enabled. + * Disabling tcp_del_ack will revert the tcp stack behavior + * to default delayed ack. Note that this will disable the + * dynamic delayed ack mechanism across the system + */ + if (hdd_ctx->config->enable_tcp_delack) + rx_tp_data.rx_tp_flags |= TCP_DEL_ACK_IND; + + if (hdd_ctx->config->enable_tcp_adv_win_scale) + rx_tp_data.rx_tp_flags |= TCP_ADV_WIN_SCL; + + rx_tp_data.level = next_rx_level; + wlan_hdd_send_svc_nlink_msg(hdd_ctx->radio_index, + WLAN_SVC_WLAN_TP_IND, &rx_tp_data, + sizeof(rx_tp_data)); + } + + /* fine-tuning parameters for TX Flows */ + temp_tx = (tx_packets + hdd_ctx->prev_tx) / 2; + hdd_ctx->prev_tx = tx_packets; + if (temp_tx > hdd_ctx->config->tcp_tx_high_tput_thres) + next_tx_level = WLAN_SVC_TP_HIGH; + else + next_tx_level = WLAN_SVC_TP_LOW; + + if (hdd_ctx->cur_tx_level != next_tx_level) { + hdd_debug("change TCP TX trigger level %d, average_tx: %llu", + next_tx_level, temp_tx); + hdd_ctx->cur_tx_level = next_tx_level; + tx_level_change = true; + wlan_hdd_send_svc_nlink_msg(hdd_ctx->radio_index, + WLAN_SVC_WLAN_TP_TX_IND, + &next_tx_level, + sizeof(next_tx_level)); + } + + index = hdd_ctx->hdd_txrx_hist_idx; + + if (vote_level_change || tx_level_change || rx_level_change) { + hdd_ctx->hdd_txrx_hist[index].next_tx_level = next_tx_level; + hdd_ctx->hdd_txrx_hist[index].next_rx_level = next_rx_level; + hdd_ctx->hdd_txrx_hist[index].next_vote_level = next_vote_level; + hdd_ctx->hdd_txrx_hist[index].interval_rx = rx_packets; + hdd_ctx->hdd_txrx_hist[index].interval_tx = tx_packets; + hdd_ctx->hdd_txrx_hist[index].qtime = qdf_get_log_timestamp(); + hdd_ctx->hdd_txrx_hist_idx++; + hdd_ctx->hdd_txrx_hist_idx &= NUM_TX_RX_HISTOGRAM_MASK; + } +} + +#define HDD_BW_GET_DIFF(_x, _y) (unsigned long)((ULONG_MAX - (_y)) + (_x) + 1) +static void hdd_bus_bw_work_handler(struct work_struct *work) +{ + hdd_context_t *hdd_ctx = container_of(work, hdd_context_t, + bus_bw_work); + hdd_adapter_t *adapter = NULL; + uint64_t tx_packets = 0, rx_packets = 0; + uint64_t fwd_tx_packets = 0, fwd_rx_packets = 0; + uint64_t fwd_tx_packets_diff = 0, fwd_rx_packets_diff = 0; + uint64_t total_tx = 0, total_rx = 0; + hdd_adapter_list_node_t *adapterNode = NULL; + QDF_STATUS status = 0; + A_STATUS ret; + bool connected = false; + uint32_t ipa_tx_packets = 0, ipa_rx_packets = 0; + + if (wlan_hdd_validate_context(hdd_ctx)) + return; + + for (status = hdd_get_front_adapter(hdd_ctx, &adapterNode); + NULL != adapterNode && QDF_STATUS_SUCCESS == status; + status = + hdd_get_next_adapter(hdd_ctx, adapterNode, &adapterNode)) { + + if (adapterNode->pAdapter == NULL) + continue; + adapter = adapterNode->pAdapter; + /* + * Validate magic so we don't end up accessing + * an invalid adapter. + */ + if (adapter->magic != WLAN_HDD_ADAPTER_MAGIC) + continue; + + if ((adapter->device_mode == QDF_STA_MODE || + adapter->device_mode == QDF_P2P_CLIENT_MODE) && + WLAN_HDD_GET_STATION_CTX_PTR(adapter)->conn_info.connState + != eConnectionState_Associated) { + + continue; + } + + if ((adapter->device_mode == QDF_SAP_MODE || + adapter->device_mode == QDF_P2P_GO_MODE) && + WLAN_HDD_GET_AP_CTX_PTR(adapter)->bApActive == false) { + + continue; + } + + tx_packets += HDD_BW_GET_DIFF(adapter->stats.tx_packets, + adapter->prev_tx_packets); + rx_packets += HDD_BW_GET_DIFF(adapter->stats.rx_packets, + adapter->prev_rx_packets); + + if (adapter->device_mode == QDF_SAP_MODE || + adapter->device_mode == QDF_P2P_GO_MODE || + adapter->device_mode == QDF_IBSS_MODE) { + + ret = ol_get_intra_bss_fwd_pkts_count( + adapter->sessionId, + &fwd_tx_packets, &fwd_rx_packets); + if (ret == A_OK) { + fwd_tx_packets_diff += HDD_BW_GET_DIFF( + fwd_tx_packets, + adapter->prev_fwd_tx_packets); + fwd_rx_packets_diff += HDD_BW_GET_DIFF( + fwd_tx_packets, + adapter->prev_fwd_rx_packets); + } + } + + total_rx += adapter->stats.rx_packets; + total_tx += adapter->stats.tx_packets; + + spin_lock_bh(&hdd_ctx->bus_bw_lock); + adapter->prev_tx_packets = adapter->stats.tx_packets; + adapter->prev_rx_packets = adapter->stats.rx_packets; + adapter->prev_fwd_tx_packets = fwd_tx_packets; + adapter->prev_fwd_rx_packets = fwd_rx_packets; + spin_unlock_bh(&hdd_ctx->bus_bw_lock); + connected = true; + } + + /* add intra bss forwarded tx and rx packets */ + tx_packets += fwd_tx_packets_diff; + rx_packets += fwd_rx_packets_diff; + + hdd_ipa_uc_stat_query(hdd_ctx, &ipa_tx_packets, &ipa_rx_packets); + tx_packets += (uint64_t)ipa_tx_packets; + rx_packets += (uint64_t)ipa_rx_packets; + + if (!connected) { + hdd_err("bus bandwidth timer running in disconnected state"); + return; + } + + hdd_pld_request_bus_bandwidth(hdd_ctx, tx_packets, rx_packets); + + hdd_ipa_set_perf_level(hdd_ctx, tx_packets, rx_packets); + hdd_ipa_uc_stat_request(adapter, 2); + + /* ensure periodic timer should still be running before restarting it */ + qdf_spinlock_acquire(&hdd_ctx->bus_bw_timer_lock); + if (hdd_ctx->bus_bw_timer_running) + qdf_timer_mod(&hdd_ctx->bus_bw_timer, + hdd_ctx->config->busBandwidthComputeInterval); + qdf_spinlock_release(&hdd_ctx->bus_bw_timer_lock); +} + +/** + * __hdd_bus_bw_cbk() - Bus bandwidth data structure callback. + * @arg: Argument of timer function + * + * Schedule a workqueue in this function where all the processing is done. + * + * Return: None. + */ +static void __hdd_bus_bw_cbk(void *arg) +{ + hdd_context_t *hdd_ctx = (hdd_context_t *) arg; + + if (wlan_hdd_validate_context(hdd_ctx)) + return; + + schedule_work(&hdd_ctx->bus_bw_work); +} + +/** + * hdd_bus_bw_cbk() - Wrapper for bus bw callback for SSR protection. + * @arg: Argument of timer function + * + * Return: None. + */ +static void hdd_bus_bw_cbk(void *arg) +{ + cds_ssr_protect(__func__); + __hdd_bus_bw_cbk(arg); + cds_ssr_unprotect(__func__); +} + +int hdd_bus_bandwidth_init(hdd_context_t *hdd_ctx) +{ + spin_lock_init(&hdd_ctx->bus_bw_lock); + INIT_WORK(&hdd_ctx->bus_bw_work, + hdd_bus_bw_work_handler); + hdd_ctx->bus_bw_timer_running = false; + qdf_spinlock_create(&hdd_ctx->bus_bw_timer_lock); + qdf_timer_init(NULL, + &hdd_ctx->bus_bw_timer, + hdd_bus_bw_cbk, (void *)hdd_ctx, + QDF_TIMER_TYPE_SW); + + return 0; +} + +void hdd_bus_bandwidth_destroy(hdd_context_t *hdd_ctx) +{ + if (hdd_ctx->bus_bw_timer_running) + hdd_reset_tcp_delack(hdd_ctx); + + hdd_info("wait for bus bw work to flush"); + cancel_work_sync(&hdd_ctx->bus_bw_work); + qdf_timer_free(&hdd_ctx->bus_bw_timer); + hdd_ctx->bus_bw_timer_running = false; + qdf_spinlock_destroy(&hdd_ctx->bus_bw_timer_lock); +} +#endif + +/** + * wlan_hdd_init_tx_rx_histogram() - init tx/rx histogram stats + * @hdd_ctx: hdd context + * + * Return: 0 for success or error code + */ +static int wlan_hdd_init_tx_rx_histogram(hdd_context_t *hdd_ctx) +{ + hdd_ctx->hdd_txrx_hist = qdf_mem_malloc( + (sizeof(struct hdd_tx_rx_histogram) * NUM_TX_RX_HISTOGRAM)); + if (hdd_ctx->hdd_txrx_hist == NULL) { + hdd_err("Failed malloc for hdd_txrx_hist"); + return -ENOMEM; + } + return 0; +} + +/** + * wlan_hdd_deinit_tx_rx_histogram() - deinit tx/rx histogram stats + * @hdd_ctx: hdd context + * + * Return: none + */ +void wlan_hdd_deinit_tx_rx_histogram(hdd_context_t *hdd_ctx) +{ + if (!hdd_ctx || hdd_ctx->hdd_txrx_hist == NULL) + return; + + qdf_mem_free(hdd_ctx->hdd_txrx_hist); + hdd_ctx->hdd_txrx_hist = NULL; +} + +static uint8_t *convert_level_to_string(uint32_t level) +{ + switch (level) { + /* initialize the wlan sub system */ + case WLAN_SVC_TP_NONE: + return "NONE"; + case WLAN_SVC_TP_LOW: + return "LOW"; + case WLAN_SVC_TP_MEDIUM: + return "MED"; + case WLAN_SVC_TP_HIGH: + return "HIGH"; + default: + return "INVAL"; + } +} + + +/** + * wlan_hdd_display_tx_rx_histogram() - display tx rx histogram + * @hdd_ctx: hdd context + * + * Return: none + */ +void wlan_hdd_display_tx_rx_histogram(hdd_context_t *hdd_ctx) +{ + int i; + +#ifdef MSM_PLATFORM + hdd_notice("BW compute Interval: %dms", + hdd_ctx->config->busBandwidthComputeInterval); + hdd_notice("BW High TH: %d BW Med TH: %d BW Low TH: %d", + hdd_ctx->config->busBandwidthHighThreshold, + hdd_ctx->config->busBandwidthMediumThreshold, + hdd_ctx->config->busBandwidthLowThreshold); + hdd_notice("Enable TCP DEL ACK: %d", + hdd_ctx->config->enable_tcp_delack); + hdd_notice("TCP DEL High TH: %d TCP DEL Low TH: %d", + hdd_ctx->config->tcpDelackThresholdHigh, + hdd_ctx->config->tcpDelackThresholdLow); + hdd_notice("TCP TX HIGH TP TH: %d (Use to set tcp_output_bytes_limit)", + hdd_ctx->config->tcp_tx_high_tput_thres); +#endif + + hdd_notice("Total entries: %d Current index: %d", + NUM_TX_RX_HISTOGRAM, hdd_ctx->hdd_txrx_hist_idx); + + hdd_notice("[index][timestamp]: interval_rx, interval_tx, bus_bw_level, RX TP Level, TX TP Level"); + + for (i = 0; i < NUM_TX_RX_HISTOGRAM; i++) { + /* using hdd_log to avoid printing function name */ + if (hdd_ctx->hdd_txrx_hist[i].qtime > 0) + hdd_log(QDF_TRACE_LEVEL_ERROR, + "[%3d][%15llu]: %6llu, %6llu, %s, %s, %s", + i, hdd_ctx->hdd_txrx_hist[i].qtime, + hdd_ctx->hdd_txrx_hist[i].interval_rx, + hdd_ctx->hdd_txrx_hist[i].interval_tx, + convert_level_to_string( + hdd_ctx->hdd_txrx_hist[i]. + next_vote_level), + convert_level_to_string( + hdd_ctx->hdd_txrx_hist[i]. + next_rx_level), + convert_level_to_string( + hdd_ctx->hdd_txrx_hist[i]. + next_tx_level)); + } + + return; +} + +/** + * wlan_hdd_clear_tx_rx_histogram() - clear tx rx histogram + * @hdd_ctx: hdd context + * + * Return: none + */ +void wlan_hdd_clear_tx_rx_histogram(hdd_context_t *hdd_ctx) +{ + hdd_ctx->hdd_txrx_hist_idx = 0; + qdf_mem_zero(hdd_ctx->hdd_txrx_hist, + (sizeof(struct hdd_tx_rx_histogram) * NUM_TX_RX_HISTOGRAM)); +} + +/** + * wlan_hdd_display_netif_queue_history() - display netif queue operation history + * @pHddCtx: hdd context + * + * Return: none + */ +void wlan_hdd_display_netif_queue_history(hdd_context_t *hdd_ctx) +{ + + hdd_adapter_t *adapter = NULL; + hdd_adapter_list_node_t *adapter_node = NULL, *next = NULL; + QDF_STATUS status; + int i; + qdf_time_t total, pause, unpause, curr_time, delta; + + status = hdd_get_front_adapter(hdd_ctx, &adapter_node); + while (NULL != adapter_node && QDF_STATUS_SUCCESS == status) { + adapter = adapter_node->pAdapter; + + hdd_notice("Netif queue operation statistics:"); + hdd_notice("Session_id %d device mode %d", + adapter->sessionId, adapter->device_mode); + hdd_notice("Current pause_map value %x", adapter->pause_map); + curr_time = qdf_system_ticks(); + total = curr_time - adapter->start_time; + delta = curr_time - adapter->last_time; + if (adapter->pause_map) { + pause = adapter->total_pause_time + delta; + unpause = adapter->total_unpause_time; + } else { + unpause = adapter->total_unpause_time + delta; + pause = adapter->total_pause_time; + } + hdd_notice("Total: %ums Pause: %ums Unpause: %ums", + qdf_system_ticks_to_msecs(total), + qdf_system_ticks_to_msecs(pause), + qdf_system_ticks_to_msecs(unpause)); + hdd_info("reason_type: pause_cnt: unpause_cnt: pause_time"); + + for (i = WLAN_CONTROL_PATH; i < WLAN_REASON_TYPE_MAX; i++) { + qdf_time_t pause_delta = 0; + + if (adapter->pause_map & (1 << i)) + pause_delta = delta; + + /* using hdd_log to avoid printing function name */ + hdd_log(QDF_TRACE_LEVEL_ERROR, + "%s: %d: %d: %ums", + hdd_reason_type_to_string(i), + adapter->queue_oper_stats[i].pause_count, + adapter->queue_oper_stats[i].unpause_count, + qdf_system_ticks_to_msecs( + adapter->queue_oper_stats[i].total_pause_time + + pause_delta)); + } + + hdd_notice("Netif queue operation history:"); + hdd_notice("Total entries: %d current index %d", + WLAN_HDD_MAX_HISTORY_ENTRY, adapter->history_index); + + hdd_notice("index: time: action_type: reason_type: pause_map"); + + for (i = 0; i < WLAN_HDD_MAX_HISTORY_ENTRY; i++) { + /* using hdd_log to avoid printing function name */ + if (adapter->queue_oper_history[i].time == 0) + continue; + hdd_log(QDF_TRACE_LEVEL_ERROR, + "%d: %u: %s: %s: %x", + i, qdf_system_ticks_to_msecs( + adapter->queue_oper_history[i].time), + hdd_action_type_to_string( + adapter->queue_oper_history[i].netif_action), + hdd_reason_type_to_string( + adapter->queue_oper_history[i].netif_reason), + adapter->queue_oper_history[i].pause_map); + } + + status = hdd_get_next_adapter(hdd_ctx, adapter_node, &next); + adapter_node = next; + } + + +} + +/** + * wlan_hdd_clear_netif_queue_history() - clear netif queue operation history + * @hdd_ctx: hdd context + * + * Return: none + */ +void wlan_hdd_clear_netif_queue_history(hdd_context_t *hdd_ctx) +{ + hdd_adapter_t *adapter = NULL; + hdd_adapter_list_node_t *adapter_node = NULL, *next = NULL; + QDF_STATUS status; + + status = hdd_get_front_adapter(hdd_ctx, &adapter_node); + while (NULL != adapter_node && QDF_STATUS_SUCCESS == status) { + adapter = adapter_node->pAdapter; + + qdf_mem_zero(adapter->queue_oper_stats, + sizeof(adapter->queue_oper_stats)); + qdf_mem_zero(adapter->queue_oper_history, + sizeof(adapter->queue_oper_history)); + adapter->history_index = 0; + adapter->start_time = adapter->last_time = qdf_system_ticks(); + adapter->total_pause_time = 0; + adapter->total_unpause_time = 0; + status = hdd_get_next_adapter(hdd_ctx, adapter_node, &next); + adapter_node = next; + } +} + +/** + * hdd_11d_scan_done() - callback for 11d scan completion of flushing results + * @halHandle: Hal handle + * @pContext: Pointer to the context + * @sessionId: Session ID + * @scanId: Scan ID + * @status: Status + * + * This is the callback to be executed when 11d scan is completed to flush out + * the scan results + * + * 11d scan is done during driver load and is a passive scan on all + * channels supported by the device, 11d scans may find some APs on + * frequencies which are forbidden to be used in the regulatory domain + * the device is operating in. If these APs are notified to the supplicant + * it may try to connect to these APs, thus flush out all the scan results + * which are present in SME after 11d scan is done. + * + * Return: QDF_STATUS_SUCCESS + */ +static QDF_STATUS hdd_11d_scan_done(tHalHandle halHandle, void *pContext, + uint8_t sessionId, uint32_t scanId, + eCsrScanStatus status) +{ + ENTER(); + + sme_scan_flush_result(halHandle); + + EXIT(); + + return QDF_STATUS_SUCCESS; +} + +#ifdef WLAN_FEATURE_OFFLOAD_PACKETS +/** + * hdd_init_offloaded_packets_ctx() - Initialize offload packets context + * @hdd_ctx: hdd global context + * + * Return: none + */ +static void hdd_init_offloaded_packets_ctx(hdd_context_t *hdd_ctx) +{ + uint8_t i; + + mutex_init(&hdd_ctx->op_ctx.op_lock); + for (i = 0; i < MAXNUM_PERIODIC_TX_PTRNS; i++) { + hdd_ctx->op_ctx.op_table[i].request_id = MAX_REQUEST_ID; + hdd_ctx->op_ctx.op_table[i].pattern_id = i; + } +} +#else +static void hdd_init_offloaded_packets_ctx(hdd_context_t *hdd_ctx) +{ +} +#endif + +#ifdef WLAN_FEATURE_WOW_PULSE +/** + * wlan_hdd_set_wow_pulse() - call SME to send wmi cmd of wow pulse + * @phddctx: hdd_context_t structure pointer + * @enable: enable or disable this behaviour + * + * Return: int + */ +static int wlan_hdd_set_wow_pulse(hdd_context_t *phddctx, bool enable) +{ + struct hdd_config *pcfg_ini = phddctx->config; + struct wow_pulse_mode wow_pulse_set_info; + QDF_STATUS status; + + hdd_notice("wow pulse enable flag is %d", enable); + + if (false == phddctx->config->wow_pulse_support) + return 0; + + /* prepare the request to send to SME */ + if (enable == true) { + wow_pulse_set_info.wow_pulse_enable = true; + wow_pulse_set_info.wow_pulse_pin = + pcfg_ini->wow_pulse_pin; + wow_pulse_set_info.wow_pulse_interval_low = + pcfg_ini->wow_pulse_interval_low; + wow_pulse_set_info.wow_pulse_interval_high = + pcfg_ini->wow_pulse_interval_high; + } else { + wow_pulse_set_info.wow_pulse_enable = false; + wow_pulse_set_info.wow_pulse_pin = 0; + wow_pulse_set_info.wow_pulse_interval_low = 0; + wow_pulse_set_info.wow_pulse_interval_high = 0; + } + hdd_notice("enable %d pin %d low %d high %d", + wow_pulse_set_info.wow_pulse_enable, + wow_pulse_set_info.wow_pulse_pin, + wow_pulse_set_info.wow_pulse_interval_low, + wow_pulse_set_info.wow_pulse_interval_high); + + status = sme_set_wow_pulse(&wow_pulse_set_info); + if (QDF_STATUS_E_FAILURE == status) { + hdd_notice("sme_set_wow_pulse failure!"); + return -EIO; + } + hdd_notice("sme_set_wow_pulse success!"); + return 0; +} +#else +static inline int wlan_hdd_set_wow_pulse(hdd_context_t *phddctx, bool enable) +{ + return 0; +} +#endif + +#ifdef WLAN_FEATURE_FASTPATH +/** + * hdd_enable_fastpath() - Enable fastpath if enabled in config INI + * @hdd_cfg: hdd config + * @context: lower layer context + * + * Return: none + */ +void hdd_enable_fastpath(struct hdd_config *hdd_cfg, + void *context) +{ + if (hdd_cfg->fastpath_enable) + hif_enable_fastpath(context); +} +#endif + +#if defined(FEATURE_WLAN_CH_AVOID) +/** + * hdd_set_thermal_level_cb() - set thermal level callback function + * @context: hdd context pointer + * @level: thermal level + * + * Change IPA data path to SW path when the thermal throttle level greater + * than 0, and restore the original data path when throttle level is 0 + * + * Return: none + */ +static void hdd_set_thermal_level_cb(void *context, u_int8_t level) +{ + hdd_context_t *hdd_ctx = context; + + /* Change IPA to SW path when throttle level greater than 0 */ + if (level > THROTTLE_LEVEL_0) + hdd_ipa_send_mcc_scc_msg(hdd_ctx, true); + else + /* restore original concurrency mode */ + hdd_ipa_send_mcc_scc_msg(hdd_ctx, hdd_ctx->mcc_mode); +} + +/** + * hdd_get_safe_channel_from_pcl_and_acs_range() - Get safe channel for SAP + * restart + * @adapter: AP adapter, which should be checked for NULL + * + * Get a safe channel to restart SAP. PCL already takes into account the + * unsafe channels. So, the PCL is validated with the ACS range to provide + * a safe channel for the SAP to restart. + * + * Return: Channel number to restart SAP in case of success. In case of any + * failure, the channel number returned is zero. + */ +static uint8_t hdd_get_safe_channel_from_pcl_and_acs_range( + hdd_adapter_t *adapter) +{ + struct sir_pcl_list pcl; + QDF_STATUS status; + uint32_t i, j; + tHalHandle *hal_handle; + hdd_context_t *hdd_ctx; + bool found = false; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + if (!hdd_ctx) { + hdd_err("invalid HDD context"); + return INVALID_CHANNEL_ID; + } + + hal_handle = WLAN_HDD_GET_HAL_CTX(adapter); + if (!hal_handle) { + hdd_err("invalid HAL handle"); + return INVALID_CHANNEL_ID; + } + + status = cds_get_pcl_for_existing_conn(CDS_SAP_MODE, + pcl.pcl_list, &pcl.pcl_len, + pcl.weight_list, QDF_ARRAY_SIZE(pcl.weight_list)); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Get PCL failed"); + return INVALID_CHANNEL_ID; + } + + if (!pcl.pcl_len) { + hdd_alert("pcl length is zero. this is not expected"); + return INVALID_CHANNEL_ID; + } + + hdd_info("start:%d end:%d", + adapter->sessionCtx.ap.sapConfig.acs_cfg.start_ch, + adapter->sessionCtx.ap.sapConfig.acs_cfg.end_ch); + + /* PCL already takes unsafe channel into account */ + for (i = 0; i < pcl.pcl_len; i++) { + hdd_info("chan[%d]:%d", i, pcl.pcl_list[i]); + if ((pcl.pcl_list[i] >= + adapter->sessionCtx.ap.sapConfig.acs_cfg.start_ch) && + (pcl.pcl_list[i] <= + adapter->sessionCtx.ap.sapConfig.acs_cfg.end_ch)) { + hdd_info("found PCL safe chan:%d", pcl.pcl_list[i]); + return pcl.pcl_list[i]; + } + } + + hdd_info("no safe channel from PCL found in ACS range"); + + /* Try for safe channel from all valid channel */ + pcl.pcl_len = MAX_NUM_CHAN; + status = sme_get_cfg_valid_channels(hal_handle, pcl.pcl_list, + &pcl.pcl_len); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("error in getting valid channel list"); + return INVALID_CHANNEL_ID; + } + + for (i = 0; i < pcl.pcl_len; i++) { + hdd_info("chan[%d]:%d", i, pcl.pcl_list[i]); + found = false; + for (j = 0; j < hdd_ctx->unsafe_channel_count; j++) { + if (pcl.pcl_list[i] == + hdd_ctx->unsafe_channel_list[j]) { + hdd_info("unsafe chan:%d", pcl.pcl_list[i]); + found = true; + break; + } + } + + if (found) + continue; + + if ((pcl.pcl_list[i] >= + adapter->sessionCtx.ap.sapConfig.acs_cfg.start_ch) && + (pcl.pcl_list[i] <= + adapter->sessionCtx.ap.sapConfig.acs_cfg.end_ch)) { + hdd_info("found safe chan:%d", pcl.pcl_list[i]); + return pcl.pcl_list[i]; + } + } + + return INVALID_CHANNEL_ID; +} + +/** + * hdd_restart_sap() - Restarts SAP on the given channel + * @adapter: AP adapter + * @channel: Channel + * + * Restarts the SAP interface by invoking the function which executes the + * callback to perform channel switch using (E)CSA. + * + * Return: None + */ +static void hdd_restart_sap(hdd_adapter_t *adapter, uint8_t channel) +{ + hdd_ap_ctx_t *hdd_ap_ctx; + tHalHandle *hal_handle; + + if (!adapter) { + hdd_err("invalid adapter"); + return; + } + + hdd_ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(adapter); + + hal_handle = WLAN_HDD_GET_HAL_CTX(adapter); + if (!hal_handle) { + hdd_err("invalid HAL handle"); + return; + } + + hdd_ap_ctx->sapConfig.channel = channel; + hdd_ap_ctx->sapConfig.ch_params.ch_width = + hdd_ap_ctx->sapConfig.ch_width_orig; + + hdd_info("chan:%d width:%d", + channel, hdd_ap_ctx->sapConfig.ch_width_orig); + + cds_set_channel_params(hdd_ap_ctx->sapConfig.channel, + hdd_ap_ctx->sapConfig.sec_ch, + &hdd_ap_ctx->sapConfig.ch_params); + + cds_change_sap_channel_with_csa(adapter, hdd_ap_ctx); +} +/** + * hdd_unsafe_channel_restart_sap() - restart sap if sap is on unsafe channel + * @hdd_ctx: hdd context pointer + * + * hdd_unsafe_channel_restart_sap check all unsafe channel list + * and if ACS is enabled, driver will ask userspace to restart the + * sap. User space on LTE coex indication restart driver. + * + * Return - none + */ +void hdd_unsafe_channel_restart_sap(hdd_context_t *hdd_ctxt) +{ + QDF_STATUS status; + hdd_adapter_list_node_t *adapter_node = NULL, *next = NULL; + hdd_adapter_t *adapter_temp; + uint32_t i; + bool found = false; + uint8_t restart_chan; + + status = hdd_get_front_adapter(hdd_ctxt, &adapter_node); + while (NULL != adapter_node && QDF_STATUS_SUCCESS == status) { + adapter_temp = adapter_node->pAdapter; + + if (!adapter_temp) { + hdd_err("adapter is NULL, moving to next one"); + goto next_adapater; + } + + if (!((adapter_temp->device_mode == QDF_SAP_MODE) && + (adapter_temp->sessionCtx.ap.sapConfig.acs_cfg.acs_mode))) { + hdd_info("skip device mode:%d acs:%d", + adapter_temp->device_mode, + adapter_temp->sessionCtx.ap.sapConfig. + acs_cfg.acs_mode); + goto next_adapater; + } + + found = false; + for (i = 0; i < hdd_ctxt->unsafe_channel_count; i++) { + if (adapter_temp->sessionCtx.ap.operatingChannel == + hdd_ctxt->unsafe_channel_list[i]) { + found = true; + hdd_info("operating ch:%d is unsafe", + adapter_temp->sessionCtx.ap.operatingChannel); + break; + } + } + + if (!found) { + hdd_info("ch:%d is safe. no need to change channel", + adapter_temp->sessionCtx.ap.operatingChannel); + goto next_adapater; + } + + restart_chan = + hdd_get_safe_channel_from_pcl_and_acs_range( + adapter_temp); + if (!restart_chan) { + hdd_alert("fail to restart SAP"); + } else { + /* SAP restart due to unsafe channel. While restarting + * the SAP, make sure to clear acs_channel, channel to + * reset to 0. Otherwise these settings will override + * the ACS while restart. + */ + hdd_ctxt->acs_policy.acs_channel = AUTO_CHANNEL_SELECT; + adapter_temp->sessionCtx.ap.sapConfig.channel = + AUTO_CHANNEL_SELECT; + hdd_info("sending coex indication"); + wlan_hdd_send_svc_nlink_msg(hdd_ctxt->radio_index, + WLAN_SVC_LTE_COEX_IND, NULL, 0); + hdd_restart_sap(adapter_temp, restart_chan); + } + +next_adapater: + status = hdd_get_next_adapter(hdd_ctxt, adapter_node, &next); + adapter_node = next; + } +} +/** + * hdd_ch_avoid_cb() - Avoid notified channels from FW handler + * @adapter: HDD adapter pointer + * @indParam: Channel avoid notification parameter + * + * Avoid channel notification from FW handler. + * FW will send un-safe channel list to avoid over wrapping. + * hostapd should not use notified channel + * + * Return: None + */ +void hdd_ch_avoid_cb(void *hdd_context, void *indi_param) +{ + hdd_context_t *hdd_ctxt; + tSirChAvoidIndType *ch_avoid_indi; + uint8_t range_loop; + enum channel_enum channel_loop, start_channel_idx = INVALID_CHANNEL, + end_channel_idx = INVALID_CHANNEL; + uint16_t start_channel; + uint16_t end_channel; + v_CONTEXT_t cds_context; + tHddAvoidFreqList hdd_avoid_freq_list; + uint32_t i; + + /* Basic sanity */ + if (!hdd_context || !indi_param) { + hdd_err("Invalid arguments"); + return; + } + + hdd_ctxt = (hdd_context_t *) hdd_context; + ch_avoid_indi = (tSirChAvoidIndType *) indi_param; + cds_context = hdd_ctxt->pcds_context; + + /* Make unsafe channel list */ + hdd_notice("band count %d", + ch_avoid_indi->avoid_range_count); + + /* generate vendor specific event */ + qdf_mem_zero((void *)&hdd_avoid_freq_list, sizeof(tHddAvoidFreqList)); + for (i = 0; i < ch_avoid_indi->avoid_range_count; i++) { + hdd_avoid_freq_list.avoidFreqRange[i].startFreq = + ch_avoid_indi->avoid_freq_range[i].start_freq; + hdd_avoid_freq_list.avoidFreqRange[i].endFreq = + ch_avoid_indi->avoid_freq_range[i].end_freq; + } + hdd_avoid_freq_list.avoidFreqRangeCount = + ch_avoid_indi->avoid_range_count; + + /* clear existing unsafe channel cache */ + hdd_ctxt->unsafe_channel_count = 0; + qdf_mem_zero(hdd_ctxt->unsafe_channel_list, + sizeof(hdd_ctxt->unsafe_channel_list)); + + for (range_loop = 0; range_loop < ch_avoid_indi->avoid_range_count; + range_loop++) { + if (hdd_ctxt->unsafe_channel_count >= NUM_CHANNELS) { + hdd_warn("LTE Coex unsafe channel list full"); + break; + } + + start_channel = ieee80211_frequency_to_channel( + ch_avoid_indi->avoid_freq_range[range_loop].start_freq); + end_channel = ieee80211_frequency_to_channel( + ch_avoid_indi->avoid_freq_range[range_loop].end_freq); + hdd_notice("start %d : %d, end %d : %d", + ch_avoid_indi->avoid_freq_range[range_loop].start_freq, + start_channel, + ch_avoid_indi->avoid_freq_range[range_loop].end_freq, + end_channel); + + /* do not process frequency bands that are not mapped to + * predefined channels + */ + if (start_channel == 0 || end_channel == 0) + continue; + + for (channel_loop = CHAN_ENUM_1; channel_loop <= + CHAN_ENUM_184; channel_loop++) { + if (CDS_CHANNEL_FREQ(channel_loop) >= + ch_avoid_indi->avoid_freq_range[ + range_loop].start_freq) { + start_channel_idx = channel_loop; + break; + } + } + for (channel_loop = CHAN_ENUM_1; channel_loop <= + CHAN_ENUM_184; channel_loop++) { + if (CDS_CHANNEL_FREQ(channel_loop) >= + ch_avoid_indi->avoid_freq_range[ + range_loop].end_freq) { + end_channel_idx = channel_loop; + if (CDS_CHANNEL_FREQ(channel_loop) > + ch_avoid_indi->avoid_freq_range[ + range_loop].end_freq) + end_channel_idx--; + break; + } + } + + if (start_channel_idx == INVALID_CHANNEL || + end_channel_idx == INVALID_CHANNEL) + continue; + + for (channel_loop = start_channel_idx; channel_loop <= + end_channel_idx; channel_loop++) { + hdd_ctxt->unsafe_channel_list[ + hdd_ctxt->unsafe_channel_count++] = + CDS_CHANNEL_NUM(channel_loop); + if (hdd_ctxt->unsafe_channel_count >= + NUM_CHANNELS) { + hdd_warn("LTECoex unsafe ch list full"); + break; + } + } + } + + hdd_notice("number of unsafe channels is %d ", + hdd_ctxt->unsafe_channel_count); + + if (pld_set_wlan_unsafe_channel(hdd_ctxt->parent_dev, + hdd_ctxt->unsafe_channel_list, + hdd_ctxt->unsafe_channel_count)) { + hdd_err("Failed to set unsafe channel"); + + /* clear existing unsafe channel cache */ + hdd_ctxt->unsafe_channel_count = 0; + qdf_mem_zero(hdd_ctxt->unsafe_channel_list, + sizeof(hdd_ctxt->unsafe_channel_list)); + + return; + } + + for (channel_loop = 0; + channel_loop < hdd_ctxt->unsafe_channel_count; channel_loop++) { + hdd_notice("channel %d is not safe ", + hdd_ctxt->unsafe_channel_list[channel_loop]); + } + + /* + * first update the unsafe channel list to the platform driver and + * send the avoid freq event to the application + */ + if (hdd_ctxt->config->restart_beaconing_on_chan_avoid_event) { + wlan_hdd_send_avoid_freq_event(hdd_ctxt, &hdd_avoid_freq_list); + + if (!hdd_ctxt->unsafe_channel_count) { + hdd_info("no unsafe channels - not restarting SAP"); + return; + } + + hdd_unsafe_channel_restart_sap(hdd_ctxt); + } + + return; +} + +/** + * hdd_init_channel_avoidance() - Initialize channel avoidance + * @hdd_ctx: HDD global context + * + * Initialize the channel avoidance logic by retrieving the unsafe + * channel list from the platform driver and plumbing the data + * down to the lower layers. Then subscribe to subsequent channel + * avoidance events. + * + * Return: None + */ +static void hdd_init_channel_avoidance(hdd_context_t *hdd_ctx) +{ + uint16_t unsafe_channel_count; + int index; + + pld_get_wlan_unsafe_channel(hdd_ctx->parent_dev, + hdd_ctx->unsafe_channel_list, + &(hdd_ctx->unsafe_channel_count), + sizeof(uint16_t) * NUM_CHANNELS); + + hdd_notice("num of unsafe channels is %d", + hdd_ctx->unsafe_channel_count); + + unsafe_channel_count = QDF_MIN((uint16_t)hdd_ctx->unsafe_channel_count, + (uint16_t)NUM_CHANNELS); + + for (index = 0; index < unsafe_channel_count; index++) { + hdd_notice("channel %d is not safe", + hdd_ctx->unsafe_channel_list[index]); + + } + + /* Plug in avoid channel notification callback */ + sme_add_ch_avoid_callback(hdd_ctx->hHal, hdd_ch_avoid_cb); +} +#else +static void hdd_init_channel_avoidance(hdd_context_t *hdd_ctx) +{ +} +static void hdd_set_thermal_level_cb(void *context, u_int8_t level) +{ +} +#endif /* defined(FEATURE_WLAN_CH_AVOID) */ + +/** + * hdd_indicate_mgmt_frame() - Wrapper to indicate management frame to + * user space + * @frame_ind: Management frame data to be informed. + * + * This function is used to indicate management frame to + * user space + * + * Return: None + * + */ +void hdd_indicate_mgmt_frame(tSirSmeMgmtFrameInd *frame_ind) +{ + hdd_context_t *hdd_ctx = NULL; + hdd_adapter_t *adapter = NULL; + void *cds_context = NULL; + int i; + + /* Get the global VOSS context.*/ + cds_context = cds_get_global_context(); + if (!cds_context) { + hdd_err("Global CDS context is Null"); + return; + } + /* Get the HDD context.*/ + hdd_ctx = (hdd_context_t *)cds_get_context(QDF_MODULE_ID_HDD); + + if (0 != wlan_hdd_validate_context(hdd_ctx)) + return; + + if (SME_SESSION_ID_ANY == frame_ind->sessionId) { + for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) { + adapter = + hdd_get_adapter_by_sme_session_id(hdd_ctx, i); + if (adapter) + break; + } + } else { + adapter = hdd_get_adapter_by_sme_session_id(hdd_ctx, + frame_ind->sessionId); + } + + if ((NULL != adapter) && + (WLAN_HDD_ADAPTER_MAGIC == adapter->magic)) + __hdd_indicate_mgmt_frame(adapter, + frame_ind->frame_len, + frame_ind->frameBuf, + frame_ind->frameType, + frame_ind->rxChan, + frame_ind->rxRssi); + return; +} + +/** + * wlan_hdd_disable_all_dual_mac_features() - Disable dual mac features + * @hdd_ctx: HDD context + * + * Disables all the dual mac features like DBS, Agile DFS etc. + * + * Return: QDF_STATUS_SUCCESS on success + */ +static QDF_STATUS wlan_hdd_disable_all_dual_mac_features(hdd_context_t *hdd_ctx) +{ + struct sir_dual_mac_config cfg; + QDF_STATUS status; + + if (!hdd_ctx) { + hdd_err("HDD context is NULL"); + return QDF_STATUS_E_FAILURE; + } + + cfg.scan_config = 0; + cfg.fw_mode_config = 0; + cfg.set_dual_mac_cb = cds_soc_set_dual_mac_cfg_cb; + + hdd_debug("Disabling all dual mac features..."); + + status = sme_soc_set_dual_mac_config(hdd_ctx->hHal, cfg); + if (status != QDF_STATUS_SUCCESS) { + hdd_err("sme_soc_set_dual_mac_config failed %d", status); + return status; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * hdd_override_ini_config - Override INI config + * @hdd_ctx: HDD context + * + * Override INI config based on module parameter. + * + * Return: None + */ +static void hdd_override_ini_config(hdd_context_t *hdd_ctx) +{ + + if (0 == enable_dfs_chan_scan || 1 == enable_dfs_chan_scan) { + hdd_ctx->config->enableDFSChnlScan = enable_dfs_chan_scan; + hdd_notice("Module enable_dfs_chan_scan set to %d", + enable_dfs_chan_scan); + } + if (0 == enable_11d || 1 == enable_11d) { + hdd_ctx->config->Is11dSupportEnabled = enable_11d; + hdd_notice("Module enable_11d set to %d", enable_11d); + } + + if (!hdd_ipa_is_present(hdd_ctx)) + hdd_ctx->config->IpaConfig = 0; +} + +/** + * hdd_set_trace_level_for_each - Set trace level for each INI config + * @hdd_ctx - HDD context + * + * Set trace level for each module based on INI config. + * + * Return: None + */ +static void hdd_set_trace_level_for_each(hdd_context_t *hdd_ctx) +{ + hdd_qdf_trace_enable(QDF_MODULE_ID_WMI, + hdd_ctx->config->qdf_trace_enable_wdi); + hdd_qdf_trace_enable(QDF_MODULE_ID_HDD, + hdd_ctx->config->qdf_trace_enable_hdd); + hdd_qdf_trace_enable(QDF_MODULE_ID_SME, + hdd_ctx->config->qdf_trace_enable_sme); + hdd_qdf_trace_enable(QDF_MODULE_ID_PE, + hdd_ctx->config->qdf_trace_enable_pe); + hdd_qdf_trace_enable(QDF_MODULE_ID_WMA, + hdd_ctx->config->qdf_trace_enable_wma); + hdd_qdf_trace_enable(QDF_MODULE_ID_SYS, + hdd_ctx->config->qdf_trace_enable_sys); + hdd_qdf_trace_enable(QDF_MODULE_ID_QDF, + hdd_ctx->config->qdf_trace_enable_qdf); + hdd_qdf_trace_enable(QDF_MODULE_ID_SAP, + hdd_ctx->config->qdf_trace_enable_sap); + hdd_qdf_trace_enable(QDF_MODULE_ID_HDD_SOFTAP, + hdd_ctx->config->qdf_trace_enable_hdd_sap); + hdd_qdf_trace_enable(QDF_MODULE_ID_BMI, + hdd_ctx->config->qdf_trace_enable_bmi); + hdd_qdf_trace_enable(QDF_MODULE_ID_CFG, + hdd_ctx->config->qdf_trace_enable_cfg); + hdd_qdf_trace_enable(QDF_MODULE_ID_EPPING, + hdd_ctx->config->qdf_trace_enable_epping); + hdd_qdf_trace_enable(QDF_MODULE_ID_QDF_DEVICE, + hdd_ctx->config->qdf_trace_enable_qdf_devices); + hdd_qdf_trace_enable(QDF_MODULE_ID_TXRX, + hdd_ctx->config->cfd_trace_enable_txrx); + hdd_qdf_trace_enable(QDF_MODULE_ID_HTC, + hdd_ctx->config->qdf_trace_enable_htc); + hdd_qdf_trace_enable(QDF_MODULE_ID_HIF, + hdd_ctx->config->qdf_trace_enable_hif); + hdd_qdf_trace_enable(QDF_MODULE_ID_HDD_SAP_DATA, + hdd_ctx->config->qdf_trace_enable_hdd_sap_data); + hdd_qdf_trace_enable(QDF_MODULE_ID_HDD_DATA, + hdd_ctx->config->qdf_trace_enable_hdd_data); + + hdd_cfg_print(hdd_ctx); +} + +/** + * hdd_context_init() - Initialize HDD context + * @hdd_ctx: HDD context. + * + * Initialize HDD context along with all the feature specific contexts. + * + * return: 0 on success and errno on failure. + */ +static int hdd_context_init(hdd_context_t *hdd_ctx) +{ + int ret; + + hdd_ctx->ioctl_scan_mode = eSIR_ACTIVE_SCAN; + hdd_ctx->max_intf_count = CSR_ROAM_SESSION_MAX; + + hdd_init_ll_stats_ctx(); + hdd_init_nud_stats_ctx(hdd_ctx); + + init_completion(&hdd_ctx->mc_sus_event_var); + init_completion(&hdd_ctx->ready_to_suspend); + + hdd_init_bpf_completion(); + + qdf_spinlock_create(&hdd_ctx->connection_status_lock); + qdf_spinlock_create(&hdd_ctx->sta_update_info_lock); + qdf_spinlock_create(&hdd_ctx->hdd_adapter_lock); + + qdf_list_create(&hdd_ctx->hddAdapters, MAX_NUMBER_OF_ADAPTERS); + + init_completion(&hdd_ctx->set_antenna_mode_cmpl); + + ret = hdd_scan_context_init(hdd_ctx); + if (ret) + goto list_destroy; + + hdd_tdls_context_init(hdd_ctx, false); + + hdd_rx_wake_lock_create(hdd_ctx); + + ret = hdd_sap_context_init(hdd_ctx); + if (ret) + goto scan_destroy; + + ret = hdd_roc_context_init(hdd_ctx); + if (ret) + goto sap_destroy; + + wlan_hdd_cfg80211_extscan_init(hdd_ctx); + + hdd_init_offloaded_packets_ctx(hdd_ctx); + + ret = wlan_hdd_cfg80211_init(hdd_ctx->parent_dev, hdd_ctx->wiphy, + hdd_ctx->config); + if (ret) + goto roc_destroy; + + return 0; + +roc_destroy: + hdd_roc_context_destroy(hdd_ctx); + +sap_destroy: + hdd_sap_context_destroy(hdd_ctx); + +scan_destroy: + hdd_scan_context_destroy(hdd_ctx); + hdd_rx_wake_lock_destroy(hdd_ctx); + hdd_tdls_context_destroy(hdd_ctx); + +list_destroy: + qdf_list_destroy(&hdd_ctx->hddAdapters); + return ret; +} + +/** + * hdd_context_create() - Allocate and inialize HDD context. + * @dev: Device Pointer to the underlying device + * + * Allocate and initialize HDD context. HDD context is allocated as part of + * wiphy allocation and then context is initialized. + * + * Return: HDD context on success and ERR_PTR on failure + */ +static hdd_context_t *hdd_context_create(struct device *dev) +{ + QDF_STATUS status; + int ret = 0; + hdd_context_t *hdd_ctx; + v_CONTEXT_t p_cds_context; + + ENTER(); + + p_cds_context = cds_get_global_context(); + if (p_cds_context == NULL) { + hdd_alert("Failed to get CDS global context"); + ret = -EINVAL; + goto err_out; + } + + hdd_ctx = hdd_cfg80211_wiphy_alloc(sizeof(hdd_context_t)); + + if (hdd_ctx == NULL) { + ret = -ENOMEM; + goto err_out; + } + + hdd_ctx->pcds_context = p_cds_context; + hdd_ctx->parent_dev = dev; + hdd_ctx->last_scan_reject_session_id = 0xFF; + + hdd_ctx->config = qdf_mem_malloc(sizeof(struct hdd_config)); + if (hdd_ctx->config == NULL) { + hdd_alert("Failed to alloc memory for HDD config!"); + ret = -ENOMEM; + goto err_free_hdd_context; + } + + /* Read and parse the qcom_cfg.ini file */ + status = hdd_parse_config_ini(hdd_ctx); + if (QDF_STATUS_SUCCESS != status) { + hdd_err("Error (status: %d) parsing INI file: %s", status, + WLAN_INI_FILE); + ret = -EINVAL; + goto err_free_config; + } + + hdd_notice("Setting configuredMcastBcastFilter: %d", + hdd_ctx->config->mcastBcastFilterSetting); + + if (hdd_ctx->config->fhostNSOffload) + hdd_ctx->ns_offload_enable = true; + + cds_set_fatal_event(hdd_ctx->config->enable_fatal_event); + + hdd_override_ini_config(hdd_ctx); + + ((cds_context_type *) (p_cds_context))->pHDDContext = (void *)hdd_ctx; + + ret = hdd_context_init(hdd_ctx); + + if (ret) + goto err_free_config; + + + pld_set_fw_log_mode(hdd_ctx->parent_dev, + hdd_ctx->config->enable_fw_log); + + + /* Uses to enabled logging after SSR */ + hdd_ctx->fw_log_settings.enable = hdd_ctx->config->enable_fw_log; + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) + goto skip_multicast_logging; + + cds_set_multicast_logging(hdd_ctx->config->multicast_host_fw_msgs); + + ret = wlan_hdd_init_tx_rx_histogram(hdd_ctx); + if (ret) + goto err_deinit_hdd_context; + + ret = hdd_logging_sock_activate_svc(hdd_ctx); + if (ret) + goto err_free_histogram; + + + /* + * Update QDF trace levels based upon the code. The multicast + * levels of the code need not be set when the logger thread + * is not enabled. + */ + if (cds_is_multicast_logging()) + wlan_logging_set_log_level(); + +skip_multicast_logging: + hdd_set_trace_level_for_each(hdd_ctx); + + return hdd_ctx; + +err_free_histogram: + wlan_hdd_deinit_tx_rx_histogram(hdd_ctx); + +err_deinit_hdd_context: + hdd_context_deinit(hdd_ctx); + +err_free_config: + qdf_mem_free(hdd_ctx->config); + +err_free_hdd_context: + wiphy_free(hdd_ctx->wiphy); + +err_out: + return ERR_PTR(ret); +} + +#ifdef WLAN_OPEN_P2P_INTERFACE +/** + * hdd_open_p2p_interface - Open P2P interface + * @hdd_ctx: HDD context + * @rtnl_held: True if RTNL lock held + * + * Open P2P interface during probe. This function called to open the P2P + * interface at probe along with STA interface. + * + * Return: 0 on success and errno on failure + */ +static int hdd_open_p2p_interface(hdd_context_t *hdd_ctx, bool rtnl_held) +{ + hdd_adapter_t *adapter; + uint8_t *p2p_dev_addr; + + if (hdd_ctx->config->isP2pDeviceAddrAdministrated && + !(hdd_ctx->config->intfMacAddr[0].bytes[0] & 0x02)) { + qdf_mem_copy(hdd_ctx->p2pDeviceAddress.bytes, + hdd_ctx->config->intfMacAddr[0].bytes, + sizeof(tSirMacAddr)); + + /* + * Generate the P2P Device Address. This consists of + * the device's primary MAC address with the locally + * administered bit set. + */ + hdd_ctx->p2pDeviceAddress.bytes[0] |= 0x02; + } else { + p2p_dev_addr = wlan_hdd_get_intf_addr(hdd_ctx); + if (p2p_dev_addr == NULL) { + hdd_alert("Failed to allocate mac_address for p2p_device"); + return -ENOSPC; + } + + qdf_mem_copy(&hdd_ctx->p2pDeviceAddress.bytes[0], p2p_dev_addr, + QDF_MAC_ADDR_SIZE); + } + + adapter = hdd_open_adapter(hdd_ctx, QDF_P2P_DEVICE_MODE, "p2p%d", + &hdd_ctx->p2pDeviceAddress.bytes[0], + NET_NAME_UNKNOWN, rtnl_held); + + if (NULL == adapter) { + hdd_alert("Failed to do hdd_open_adapter for P2P Device Interface"); + return -ENOSPC; + } + + return 0; +} +#else +static inline int hdd_open_p2p_interface(hdd_context_t *hdd_ctx, + bool rtnl_held) +{ + return 0; +} +#endif + +static int hdd_open_ocb_interface(hdd_context_t *hdd_ctx, bool rtnl_held) +{ + hdd_adapter_t *adapter; + int ret = 0; + + adapter = hdd_open_adapter(hdd_ctx, QDF_OCB_MODE, "wlanocb%d", + wlan_hdd_get_intf_addr(hdd_ctx), + NET_NAME_UNKNOWN, rtnl_held); + if (adapter == NULL) { + hdd_err("Failed to open 802.11p interface"); + ret = -ENOSPC; + } + + return ret; +} + +/** + * hdd_start_station_adapter()- Start the Station Adapter + * @adapter: HDD adapter + * + * This function initializes the adapter for the station mode. + * + * Return: 0 on success or errno on failure. + */ +int hdd_start_station_adapter(hdd_adapter_t *adapter) +{ + QDF_STATUS status; + + ENTER_DEV(adapter->dev); + + status = hdd_init_station_mode(adapter); + + if (QDF_STATUS_SUCCESS != status) { + hdd_err("Error Initializing station mode: %d", status); + return qdf_status_to_os_return(status); + } + + hdd_register_tx_flow_control(adapter, + hdd_tx_resume_timer_expired_handler, + hdd_tx_resume_cb); + + EXIT(); + return 0; +} + +/** + * hdd_start_ap_adapter()- Start AP Adapter + * @adapter: HDD adapter + * + * This function initializes the adapter for the AP mode. + * + * Return: 0 on success errno on failure. + */ +int hdd_start_ap_adapter(hdd_adapter_t *adapter) +{ + QDF_STATUS status; + + ENTER(); + + status = hdd_init_ap_mode(adapter, false); + + if (QDF_STATUS_SUCCESS != status) { + hdd_err("Error Initializing the AP mode: %d", status); + return qdf_status_to_os_return(status); + } + + hdd_register_tx_flow_control(adapter, + hdd_softap_tx_resume_timer_expired_handler, + hdd_softap_tx_resume_cb); + + EXIT(); + return 0; +} + +/** + * hdd_start_ftm_adapter()- Start FTM adapter + * @adapter: HDD adapter + * + * This function initializes the adapter for the FTM mode. + * + * Return: 0 on success or errno on failure. + */ +int hdd_start_ftm_adapter(hdd_adapter_t *adapter) +{ + QDF_STATUS qdf_status; + + ENTER_DEV(adapter->dev); + + qdf_status = hdd_init_tx_rx(adapter); + + if (QDF_STATUS_SUCCESS != qdf_status) { + hdd_err("Failed to start FTM adapter: %d", qdf_status); + return qdf_status_to_os_return(qdf_status); + } + + return 0; + EXIT(); +} + +/** + * hdd_open_interfaces - Open all required interfaces + * hdd_ctx: HDD context + * rtnl_held: True if RTNL lock is held + * + * Open all the interfaces like STA, P2P and OCB based on the configuration. + * + * Return: 0 if all interfaces were created, otherwise negative errno + */ +static int hdd_open_interfaces(hdd_context_t *hdd_ctx, bool rtnl_held) +{ + hdd_adapter_t *adapter; + int ret; + + if (hdd_ctx->config->dot11p_mode == WLAN_HDD_11P_STANDALONE) + /* Create only 802.11p interface */ + return hdd_open_ocb_interface(hdd_ctx, rtnl_held); + + adapter = hdd_open_adapter(hdd_ctx, QDF_STA_MODE, "wlan%d", + wlan_hdd_get_intf_addr(hdd_ctx), + NET_NAME_UNKNOWN, rtnl_held); + + if (adapter == NULL) + return -ENOSPC; + + /* fast roaming is allowed only on first STA, i.e. wlan adapter */ + adapter->fast_roaming_allowed = true; + + ret = hdd_open_p2p_interface(hdd_ctx, rtnl_held); + if (ret) + goto err_close_adapters; + + /* Open 802.11p Interface */ + if (hdd_ctx->config->dot11p_mode == WLAN_HDD_11P_CONCURRENT) { + ret = hdd_open_ocb_interface(hdd_ctx, rtnl_held); + if (ret) + goto err_close_adapters; + } + + return 0; + +err_close_adapters: + hdd_close_all_adapters(hdd_ctx, rtnl_held); + return ret; +} + +/** + * hdd_update_country_code - Update country code + * @hdd_ctx: HDD context + * @adapter: Primary adapter context + * + * Update country code based on module parameter country_code at SME and wait + * for the settings to take effect. + * + * Return: 0 on success and errno on failure + */ +static int hdd_update_country_code(hdd_context_t *hdd_ctx, + hdd_adapter_t *adapter) +{ + QDF_STATUS status; + int ret = 0; + unsigned long rc; + + if (country_code == NULL) + return 0; + + INIT_COMPLETION(adapter->change_country_code); + + status = sme_change_country_code(hdd_ctx->hHal, + wlan_hdd_change_country_code_callback, + country_code, adapter, + hdd_ctx->pcds_context, eSIR_TRUE, + eSIR_TRUE); + + + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("SME Change Country code from module param fail ret=%d", + ret); + return -EINVAL; + } + + rc = wait_for_completion_timeout(&adapter->change_country_code, + msecs_to_jiffies(WLAN_WAIT_TIME_COUNTRY)); + if (!rc) { + hdd_err("SME while setting country code timed out"); + ret = -ETIMEDOUT; + } + + return ret; +} + +#ifdef QCA_LL_TX_FLOW_CONTROL_V2 +/** + * hdd_txrx_populate_cds_config() - Populate txrx cds configuration + * @cds_cfg: CDS Configuration + * @hdd_ctx: Pointer to hdd context + * + * Return: none + */ +static inline void hdd_txrx_populate_cds_config(struct cds_config_info + *cds_cfg, + hdd_context_t *hdd_ctx) +{ + cds_cfg->tx_flow_stop_queue_th = + hdd_ctx->config->TxFlowStopQueueThreshold; + cds_cfg->tx_flow_start_queue_offset = + hdd_ctx->config->TxFlowStartQueueOffset; +} +#else +static inline void hdd_txrx_populate_cds_config(struct cds_config_info + *cds_cfg, + hdd_context_t *hdd_ctx) +{ +} +#endif + +#ifdef FEATURE_WLAN_RA_FILTERING +/** + * hdd_ra_populate_cds_config() - Populate RA filtering cds configuration + * @cds_cfg: CDS Configuration + * @hdd_ctx: Pointer to hdd context + * + * Return: none + */ +static inline void hdd_ra_populate_cds_config(struct cds_config_info *cds_cfg, + hdd_context_t *hdd_ctx) +{ + cds_cfg->ra_ratelimit_interval = + hdd_ctx->config->RArateLimitInterval; + cds_cfg->is_ra_ratelimit_enabled = + hdd_ctx->config->IsRArateLimitEnabled; +} +#else +static inline void hdd_ra_populate_cds_config(struct cds_config_info *cds_cfg, + hdd_context_t *hdd_ctx) +{ +} +#endif + +/** + * hdd_update_cds_config() - API to update cds configuration parameters + * @hdd_ctx: HDD Context + * + * Return: 0 for Success, errno on failure + */ +static int hdd_update_cds_config(hdd_context_t *hdd_ctx) +{ + struct cds_config_info *cds_cfg; + + cds_cfg = (struct cds_config_info *)qdf_mem_malloc(sizeof(*cds_cfg)); + if (!cds_cfg) { + hdd_err("failed to allocate cds config"); + return -ENOMEM; + } + + cds_cfg->driver_type = DRIVER_TYPE_PRODUCTION; + if (!hdd_ctx->config->nMaxPsPoll || + !hdd_ctx->config->enablePowersaveOffload) { + cds_cfg->powersave_offload_enabled = + hdd_ctx->config->enablePowersaveOffload; + } else { + if ((hdd_ctx->config->enablePowersaveOffload == + PS_QPOWER_NODEEPSLEEP) || + (hdd_ctx->config->enablePowersaveOffload == + PS_LEGACY_NODEEPSLEEP)) + cds_cfg->powersave_offload_enabled = + PS_LEGACY_NODEEPSLEEP; + else + cds_cfg->powersave_offload_enabled = + PS_LEGACY_DEEPSLEEP; + hdd_info("Qpower disabled in cds config, %d", + cds_cfg->powersave_offload_enabled); + } + cds_cfg->sta_dynamic_dtim = hdd_ctx->config->enableDynamicDTIM; + cds_cfg->sta_mod_dtim = hdd_ctx->config->enableModulatedDTIM; + cds_cfg->sta_maxlimod_dtim = hdd_ctx->config->fMaxLIModulatedDTIM; + cds_cfg->wow_enable = hdd_ctx->config->wowEnable; + cds_cfg->max_wow_filters = hdd_ctx->config->maxWoWFilters; + + /* Here ol_ini_info is used to store ini status of arp offload + * ns offload and others. Currently 1st bit is used for arp + * off load and 2nd bit for ns offload currently, rest bits are unused + */ + if (hdd_ctx->config->fhostArpOffload) + cds_cfg->ol_ini_info = cds_cfg->ol_ini_info | 0x1; + if (hdd_ctx->config->fhostNSOffload) + cds_cfg->ol_ini_info = cds_cfg->ol_ini_info | 0x2; + + /* + * Copy the DFS Phyerr Filtering Offload status. + * This parameter reflects the value of the + * dfs_phyerr_filter_offload flag as set in the ini. + */ + cds_cfg->dfs_phyerr_filter_offload = + hdd_ctx->config->fDfsPhyerrFilterOffload; + if (hdd_ctx->config->ssdp) + cds_cfg->ssdp = hdd_ctx->config->ssdp; + + cds_cfg->force_target_assert_enabled = + hdd_ctx->config->crash_inject_enabled; + + cds_cfg->enable_mc_list = hdd_ctx->config->fEnableMCAddrList; + cds_cfg->ap_maxoffload_peers = hdd_ctx->config->apMaxOffloadPeers; + + cds_cfg->ap_maxoffload_reorderbuffs = + hdd_ctx->config->apMaxOffloadReorderBuffs; + + cds_cfg->ap_disable_intrabss_fwd = + hdd_ctx->config->apDisableIntraBssFwd; + + cds_cfg->dfs_pri_multiplier = + hdd_ctx->config->dfsRadarPriMultiplier; + cds_cfg->reorder_offload = + hdd_ctx->config->reorderOffloadSupport; + + /* IPA micro controller data path offload resource config item */ + cds_cfg->uc_offload_enabled = hdd_ipa_uc_is_enabled(hdd_ctx); + if (!is_power_of_2(hdd_ctx->config->IpaUcTxBufCount)) { + /* IpaUcTxBufCount should be power of 2 */ + hdd_warn("Round down IpaUcTxBufCount %d to nearest power of 2", + hdd_ctx->config->IpaUcTxBufCount); + hdd_ctx->config->IpaUcTxBufCount = + rounddown_pow_of_two( + hdd_ctx->config->IpaUcTxBufCount); + if (!hdd_ctx->config->IpaUcTxBufCount) { + hdd_err("Failed to round down IpaUcTxBufCount"); + return -EINVAL; + } + hdd_warn("IpaUcTxBufCount rounded down to %d", + hdd_ctx->config->IpaUcTxBufCount); + } + cds_cfg->uc_txbuf_count = hdd_ctx->config->IpaUcTxBufCount; + cds_cfg->uc_txbuf_size = hdd_ctx->config->IpaUcTxBufSize; + if (!is_power_of_2(hdd_ctx->config->IpaUcRxIndRingCount)) { + /* IpaUcRxIndRingCount should be power of 2 */ + hdd_warn("Round down IpaUcRxIndRingCount %d to nearest power of 2", + hdd_ctx->config->IpaUcRxIndRingCount); + hdd_ctx->config->IpaUcRxIndRingCount = + rounddown_pow_of_two( + hdd_ctx->config->IpaUcRxIndRingCount); + if (!hdd_ctx->config->IpaUcRxIndRingCount) { + hdd_err("Failed to round down IpaUcRxIndRingCount"); + return -EINVAL; + } + hdd_info("IpaUcRxIndRingCount rounded down to %d", + hdd_ctx->config->IpaUcRxIndRingCount); + } + cds_cfg->uc_rxind_ringcount = + hdd_ctx->config->IpaUcRxIndRingCount; + cds_cfg->uc_tx_partition_base = + hdd_ctx->config->IpaUcTxPartitionBase; + cds_cfg->max_scan = hdd_ctx->config->max_scan_count; + + cds_cfg->ip_tcp_udp_checksum_offload = + hdd_ctx->config->enable_ip_tcp_udp_checksum_offload; + cds_cfg->enable_rxthread = hdd_ctx->enableRxThread; + cds_cfg->ce_classify_enabled = + hdd_ctx->config->ce_classify_enabled; + cds_cfg->bpf_packet_filter_enable = + hdd_ctx->config->bpf_packet_filter_enable; + cds_cfg->tx_chain_mask_cck = hdd_ctx->config->tx_chain_mask_cck; + cds_cfg->self_gen_frm_pwr = hdd_ctx->config->self_gen_frm_pwr; + cds_cfg->max_station = hdd_ctx->config->maxNumberOfPeers; + cds_cfg->sub_20_channel_width = WLAN_SUB_20_CH_WIDTH_NONE; + cds_cfg->flow_steering_enabled = hdd_ctx->config->flow_steering_enable; + cds_cfg->self_recovery_enabled = hdd_ctx->config->enableSelfRecovery; + cds_cfg->fw_timeout_crash = hdd_ctx->config->fw_timeout_crash; + cds_cfg->active_bpf_mode = hdd_ctx->config->active_bpf_mode; + cds_cfg->auto_power_save_fail_mode = + hdd_ctx->config->auto_pwr_save_fail_mode; + + cds_cfg->ito_repeat_count = hdd_ctx->config->ito_repeat_count; + + hdd_ra_populate_cds_config(cds_cfg, hdd_ctx); + hdd_txrx_populate_cds_config(cds_cfg, hdd_ctx); + hdd_nan_populate_cds_config(cds_cfg, hdd_ctx); + hdd_lpass_populate_cds_config(cds_cfg, hdd_ctx); + cds_init_ini_config(cds_cfg); + return 0; +} + +/** + * hdd_init_thermal_info - Initialize thermal level + * @hdd_ctx: HDD context + * + * Initialize thermal level at SME layer and set the thermal level callback + * which would be called when a configured thermal threshold is hit. + * + * Return: 0 on success and errno on failure + */ +static int hdd_init_thermal_info(hdd_context_t *hdd_ctx) +{ + tSmeThermalParams thermal_param; + QDF_STATUS status; + + thermal_param.smeThermalMgmtEnabled = + hdd_ctx->config->thermalMitigationEnable; + thermal_param.smeThrottlePeriod = hdd_ctx->config->throttlePeriod; + + thermal_param.sme_throttle_duty_cycle_tbl[0] = + hdd_ctx->config->throttle_dutycycle_level0; + thermal_param.sme_throttle_duty_cycle_tbl[1] = + hdd_ctx->config->throttle_dutycycle_level1; + thermal_param.sme_throttle_duty_cycle_tbl[2] = + hdd_ctx->config->throttle_dutycycle_level2; + thermal_param.sme_throttle_duty_cycle_tbl[3] = + hdd_ctx->config->throttle_dutycycle_level3; + + thermal_param.smeThermalLevels[0].smeMinTempThreshold = + hdd_ctx->config->thermalTempMinLevel0; + thermal_param.smeThermalLevels[0].smeMaxTempThreshold = + hdd_ctx->config->thermalTempMaxLevel0; + thermal_param.smeThermalLevels[1].smeMinTempThreshold = + hdd_ctx->config->thermalTempMinLevel1; + thermal_param.smeThermalLevels[1].smeMaxTempThreshold = + hdd_ctx->config->thermalTempMaxLevel1; + thermal_param.smeThermalLevels[2].smeMinTempThreshold = + hdd_ctx->config->thermalTempMinLevel2; + thermal_param.smeThermalLevels[2].smeMaxTempThreshold = + hdd_ctx->config->thermalTempMaxLevel2; + thermal_param.smeThermalLevels[3].smeMinTempThreshold = + hdd_ctx->config->thermalTempMinLevel3; + thermal_param.smeThermalLevels[3].smeMaxTempThreshold = + hdd_ctx->config->thermalTempMaxLevel3; + + status = sme_init_thermal_info(hdd_ctx->hHal, thermal_param); + + if (!QDF_IS_STATUS_SUCCESS(status)) + return qdf_status_to_os_return(status); + + sme_add_set_thermal_level_callback(hdd_ctx->hHal, + hdd_set_thermal_level_cb); + + return 0; + +} + +#if defined(CONFIG_HDD_INIT_WITH_RTNL_LOCK) +/** + * hdd_hold_rtnl_lock - Hold RTNL lock + * + * Hold RTNL lock + * + * Return: True if held and false otherwise + */ +static inline bool hdd_hold_rtnl_lock(void) +{ + rtnl_lock(); + return true; +} + +/** + * hdd_release_rtnl_lock - Release RTNL lock + * + * Release RTNL lock + * + * Return: None + */ +static inline void hdd_release_rtnl_lock(void) +{ + rtnl_unlock(); +} +#else +static inline bool hdd_hold_rtnl_lock(void) { return false; } +static inline void hdd_release_rtnl_lock(void) { } +#endif + +#if !defined(REMOVE_PKT_LOG) + +/* MAX iwpriv command support */ +#define PKTLOG_SET_BUFF_SIZE 3 +#define PKTLOG_CLEAR_BUFF 4 +#define MAX_PKTLOG_SIZE 16 + +/** + * hdd_pktlog_set_buff_size() - set pktlog buffer size + * @hdd_ctx: hdd context + * @set_value2: pktlog buffer size value + * + * + * Return: 0 for success or error. + */ +static int hdd_pktlog_set_buff_size(hdd_context_t *hdd_ctx, int set_value2) +{ + struct sir_wifi_start_log start_log = { 0 }; + QDF_STATUS status; + + start_log.ring_id = RING_ID_PER_PACKET_STATS; + start_log.verbose_level = WLAN_LOG_LEVEL_OFF; + start_log.ini_triggered = cds_is_packet_log_enabled(); + start_log.user_triggered = 1; + start_log.size = set_value2; + start_log.is_pktlog_buff_clear = false; + + status = sme_wifi_start_logger(hdd_ctx->hHal, start_log); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("sme_wifi_start_logger failed(err=%d)", status); + EXIT(); + return -EINVAL; + } + + return 0; +} + +/** + * hdd_pktlog_clear_buff() - clear pktlog buffer + * @hdd_ctx: hdd context + * + * Return: 0 for success or error. + */ +static int hdd_pktlog_clear_buff(hdd_context_t *hdd_ctx) +{ + struct sir_wifi_start_log start_log; + QDF_STATUS status; + + start_log.ring_id = RING_ID_PER_PACKET_STATS; + start_log.verbose_level = WLAN_LOG_LEVEL_OFF; + start_log.ini_triggered = cds_is_packet_log_enabled(); + start_log.user_triggered = 1; + start_log.size = 0; + start_log.is_pktlog_buff_clear = true; + + status = sme_wifi_start_logger(hdd_ctx->hHal, start_log); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("sme_wifi_start_logger failed(err=%d)", status); + EXIT(); + return -EINVAL; + } + + return 0; +} + +/** + * hdd_process_pktlog_command() - process pktlog command + * @hdd_ctx: hdd context + * @set_value: value set by user + * @set_value2: pktlog buffer size value + * + * This function process pktlog command. + * set_value2 only matters when set_value is 3 (set buff size) + * otherwise we ignore it. + * + * Return: 0 for success or error. + */ +int hdd_process_pktlog_command(hdd_context_t *hdd_ctx, uint32_t set_value, + int set_value2) +{ + int ret; + bool enable; + uint8_t user_triggered = 0; + + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + hdd_info("set pktlog %d, set size %d", set_value, set_value2); + + if (set_value > PKTLOG_CLEAR_BUFF) { + hdd_err("invalid pktlog value %d", set_value); + return -EINVAL; + } + + if (set_value == PKTLOG_SET_BUFF_SIZE) { + if (set_value2 <= 0) { + hdd_err("invalid pktlog size %d", set_value2); + return -EINVAL; + } else if (set_value2 > MAX_PKTLOG_SIZE) { + hdd_err("Pktlog buff size is too large. max value is 16MB.\n"); + return -EINVAL; + } + return hdd_pktlog_set_buff_size(hdd_ctx, set_value2); + } else if (set_value == PKTLOG_CLEAR_BUFF) { + return hdd_pktlog_clear_buff(hdd_ctx); + } + + /* + * set_value = 0 then disable packetlog + * set_value = 1 enable packetlog forcefully + * set_vlaue = 2 then disable packetlog if disabled through ini or + * enable packetlog with AUTO type. + */ + enable = ((set_value > 0) && cds_is_packet_log_enabled()) ? + true : false; + + if (1 == set_value) { + enable = true; + user_triggered = 1; + } + + return hdd_pktlog_enable_disable(hdd_ctx, enable, user_triggered, 0); +} +/** + * hdd_pktlog_enable_disable() - Enable/Disable packet logging + * @hdd_ctx: HDD context + * @enable: Flag to enable/disable + * @user_triggered: triggered through iwpriv + * @size: buffer size to be used for packetlog + * + * Return: 0 on success; error number otherwise + */ +int hdd_pktlog_enable_disable(hdd_context_t *hdd_ctx, bool enable, + uint8_t user_triggered, int size) +{ + struct sir_wifi_start_log start_log; + QDF_STATUS status; + + start_log.ring_id = RING_ID_PER_PACKET_STATS; + start_log.verbose_level = + enable ? WLAN_LOG_LEVEL_ACTIVE : WLAN_LOG_LEVEL_OFF; + start_log.ini_triggered = cds_is_packet_log_enabled(); + start_log.user_triggered = user_triggered; + start_log.size = size; + start_log.is_pktlog_buff_clear = false; + /* + * Use "is_iwpriv_command" flag to distinguish iwpriv command from other + * commands. Host uses this flag to decide whether to send pktlog + * disable command to fw without sending pktlog enable command + * previously. For eg, If vendor sends pktlog disable command without + * sending pktlog enable command, then host discards the packet + * but for iwpriv command, host will send it to fw. + */ + start_log.is_iwpriv_command = 1; + status = sme_wifi_start_logger(hdd_ctx->hHal, start_log); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("sme_wifi_start_logger failed(err=%d)", status); + EXIT(); + return -EINVAL; + } + + return 0; +} +#endif /* REMOVE_PKT_LOG */ + + +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH +/** + * hdd_register_for_sap_restart_with_channel_switch() - Register for SAP channel + * switch without restart + * + * Registers callback function to change the operating channel of SAP by using + * channel switch announcements instead of restarting SAP. + * + * Return: QDF_STATUS + */ +QDF_STATUS hdd_register_for_sap_restart_with_channel_switch(void) +{ + QDF_STATUS status; + + status = cds_register_sap_restart_channel_switch_cb( + (void *)hdd_sap_restart_with_channel_switch); + if (!QDF_IS_STATUS_SUCCESS(status)) + hdd_err("restart cb registration failed"); + + return status; +} +#endif + +/** + * hdd_get_platform_wlan_mac_buff() - API to query platform driver + * for MAC address + * @dev: Device Pointer + * @num: Number of Valid Mac address + * + * Return: Pointer to MAC address buffer + */ +static uint8_t *hdd_get_platform_wlan_mac_buff(struct device *dev, + uint32_t *num) +{ + return pld_get_wlan_mac_address(dev, num); +} + +/** + * hdd_populate_random_mac_addr() - API to populate random mac addresses + * @hdd_ctx: HDD Context + * @num: Number of random mac addresses needed + * + * Generate random addresses using bit manipulation on the base mac address + * + * Return: None + */ +static void hdd_populate_random_mac_addr(hdd_context_t *hdd_ctx, uint32_t num) +{ + uint32_t start_idx = QDF_MAX_CONCURRENCY_PERSONA - num; + uint32_t iter; + struct hdd_config *ini = hdd_ctx->config; + uint8_t *buf = NULL; + uint8_t macaddr_b3, tmp_br3; + uint8_t *src = ini->intfMacAddr[0].bytes; + + for (iter = start_idx; iter < QDF_MAX_CONCURRENCY_PERSONA; ++iter) { + buf = ini->intfMacAddr[iter].bytes; + qdf_mem_copy(buf, src, QDF_MAC_ADDR_SIZE); + macaddr_b3 = buf[3]; + tmp_br3 = ((macaddr_b3 >> 4 & INTF_MACADDR_MASK) + iter) & + INTF_MACADDR_MASK; + macaddr_b3 += tmp_br3; + macaddr_b3 ^= (1 << INTF_MACADDR_MASK); + buf[0] |= 0x02; + buf[3] = macaddr_b3; + hdd_info(MAC_ADDRESS_STR, MAC_ADDR_ARRAY(buf)); + } +} + +/** + * hdd_platform_wlan_mac() - API to get mac addresses from platform driver + * @hdd_ctx: HDD Context + * + * API to get mac addresses from platform driver and update the driver + * structures and configure FW with the base mac address. + * Return: int + */ +static int hdd_platform_wlan_mac(hdd_context_t *hdd_ctx) +{ + uint32_t no_of_mac_addr, iter; + uint32_t max_mac_addr = QDF_MAX_CONCURRENCY_PERSONA; + uint32_t mac_addr_size = QDF_MAC_ADDR_SIZE; + uint8_t *addr, *buf; + struct device *dev = hdd_ctx->parent_dev; + struct hdd_config *ini = hdd_ctx->config; + tSirMacAddr mac_addr; + QDF_STATUS status; + + addr = hdd_get_platform_wlan_mac_buff(dev, &no_of_mac_addr); + + if (no_of_mac_addr == 0 || !addr) { + hdd_warn("Platform Driver Doesn't have wlan mac addresses"); + return -EINVAL; + } + + if (no_of_mac_addr > max_mac_addr) + no_of_mac_addr = max_mac_addr; + + qdf_mem_copy(&mac_addr, addr, mac_addr_size); + + for (iter = 0; iter < no_of_mac_addr; ++iter, addr += mac_addr_size) { + buf = ini->intfMacAddr[iter].bytes; + qdf_mem_copy(buf, addr, QDF_MAC_ADDR_SIZE); + hdd_info(MAC_ADDRESS_STR, MAC_ADDR_ARRAY(buf)); + } + + status = sme_set_custom_mac_addr(mac_addr); + + if (!QDF_IS_STATUS_SUCCESS(status)) + return -EAGAIN; + if (no_of_mac_addr < max_mac_addr) + hdd_populate_random_mac_addr(hdd_ctx, max_mac_addr - + no_of_mac_addr); + return 0; +} + +/** + * hdd_update_mac_addr_to_fw() - API to update wlan mac addresses to FW + * @hdd_ctx: HDD Context + * + * Update MAC address to FW. If MAC address passed by FW is invalid, host + * will generate its own MAC and update it to FW. + * + * Return: 0 for success + * Non-zero error code for failure + */ +static int hdd_update_mac_addr_to_fw(hdd_context_t *hdd_ctx) +{ + tSirMacAddr customMacAddr; + QDF_STATUS status; + + qdf_mem_copy(&customMacAddr, + &hdd_ctx->config->intfMacAddr[0].bytes[0], + sizeof(tSirMacAddr)); + status = sme_set_custom_mac_addr(customMacAddr); + if (!QDF_IS_STATUS_SUCCESS(status)) + return -EAGAIN; + return 0; +} + +/** + * hdd_initialize_mac_address() - API to get wlan mac addresses + * @hdd_ctx: HDD Context + * + * Get MAC addresses from platform driver or wlan_mac.bin. If platform driver + * is provisioned with mac addresses, driver uses it, else it will use + * wlan_mac.bin to update HW MAC addresses. + * + * Return: None + */ +static void hdd_initialize_mac_address(hdd_context_t *hdd_ctx) +{ + QDF_STATUS status; + int ret; + + ret = hdd_platform_wlan_mac(hdd_ctx); + if (ret == 0) + return; + + hdd_warn("Can't update mac config via platform driver ret:%d", ret); + + status = hdd_update_mac_config(hdd_ctx); + + if (QDF_IS_STATUS_SUCCESS(status)) + return; + + hdd_warn("can't update mac config via wlan_mac.bin, using MAC from ini file or auto-gen"); + + if (hdd_ctx->update_mac_addr_to_fw) { + ret = hdd_update_mac_addr_to_fw(hdd_ctx); + if (ret != 0) { + hdd_err("MAC address out-of-sync, ret:%d", ret); + QDF_ASSERT(ret); + } + } +} + +/** + * hdd_tsf_init() - Initialize the TSF synchronization interface + * @hdd_ctx: HDD global context + * + * When TSF synchronization via GPIO is supported by the driver and + * has been enabled in the configuration file, this function plumbs + * the GPIO value down to firmware via SME. + * + * Return: None + */ +#ifdef WLAN_FEATURE_TSF +static void hdd_tsf_init(hdd_context_t *hdd_ctx) +{ + QDF_STATUS status; + + if (hdd_ctx->config->tsf_gpio_pin == TSF_GPIO_PIN_INVALID) + return; + + status = sme_set_tsf_gpio(hdd_ctx->hHal, + hdd_ctx->config->tsf_gpio_pin); + if (!QDF_IS_STATUS_SUCCESS(status)) + hdd_err("Set tsf GPIO failed, status: %d", status); +} +#else +static void hdd_tsf_init(hdd_context_t *hdd_ctx) +{ +} +#endif + +/** + * hdd_pre_enable_configure() - Configurations prior to cds_enable + * @hdd_ctx: HDD context + * + * Pre configurations to be done at lower layer before calling cds enable. + * + * Return: 0 on success and errno on failure. + */ +static int hdd_pre_enable_configure(hdd_context_t *hdd_ctx) +{ + int ret; + QDF_STATUS status; + tSirRetStatus hal_status; + + ol_txrx_register_pause_cb(wlan_hdd_txrx_pause_cb); + + /* + * Set 802.11p config + * TODO-OCB: This has been temporarily added here to ensure this + * parameter is set in CSR when we init the channel list. This should + * be removed once the 5.9 GHz channels are added to the regulatory + * domain. + */ + hdd_set_dot11p_config(hdd_ctx); + + /* + * Note that the cds_pre_enable() sequence triggers the cfg download. + * The cfg download must occur before we update the SME config + * since the SME config operation must access the cfg database + */ + status = hdd_set_sme_config(hdd_ctx); + + if (QDF_STATUS_SUCCESS != status) { + hdd_alert("Failed hdd_set_sme_config: %d", status); + ret = qdf_status_to_os_return(status); + goto out; + } + + ret = sme_cli_set_command(0, WMI_PDEV_PARAM_TX_CHAIN_MASK_1SS, + hdd_ctx->config->tx_chain_mask_1ss, + PDEV_CMD); + if (0 != ret) { + hdd_err("WMI_PDEV_PARAM_TX_CHAIN_MASK_1SS failed %d", ret); + goto out; + } + + status = hdd_set_sme_chan_list(hdd_ctx); + if (status != QDF_STATUS_SUCCESS) { + hdd_alert("Failed to init channel list: %d", status); + ret = qdf_status_to_os_return(status); + goto out; + } + + /* Apply the cfg.ini to cfg.dat */ + if (!hdd_update_config_cfg(hdd_ctx)) { + hdd_alert("config update failed"); + ret = -EINVAL; + goto out; + } + + /* + * Set the MAC Address Currently this is used by HAL to add self sta. + * Remove this once self sta is added as part of session open. + */ + hal_status = cfg_set_str(hdd_ctx->hHal, WNI_CFG_STA_ID, + hdd_ctx->config->intfMacAddr[0].bytes, + sizeof(hdd_ctx->config->intfMacAddr[0])); + + if (!IS_SIR_STATUS_SUCCESS(hal_status)) { + hdd_err("Failed to set MAC Address. HALStatus is %08d [x%08x]", + hal_status, hal_status); + ret = -EINVAL; + goto out; + } + + hdd_init_channel_avoidance(hdd_ctx); + + /* update enable sap mandatory chan list */ + cds_enable_disable_sap_mandatory_chan_list( + hdd_ctx->config->enable_sap_mandatory_chan_list); + +out: + return ret; +} + +/** + * wlan_hdd_p2p_lo_event_callback - P2P listen offload stop event handler + * @context_ptr - hdd context pointer + * @event_ptr - event structure pointer + * + * This is the p2p listen offload stop event handler, it sends vendor + * event back to supplicant to notify the stop reason. + * + * Return: None + */ +static void wlan_hdd_p2p_lo_event_callback(void *context_ptr, + void *event_ptr) +{ + hdd_context_t *hdd_ctx = (hdd_context_t *)context_ptr; + struct sir_p2p_lo_event *evt = event_ptr; + struct sk_buff *vendor_event; + + ENTER(); + + if (hdd_ctx == NULL) { + hdd_err("Invalid HDD context pointer"); + return; + } + + vendor_event = + cfg80211_vendor_event_alloc(hdd_ctx->wiphy, + NULL, sizeof(uint32_t) + NLMSG_HDRLEN, + QCA_NL80211_VENDOR_SUBCMD_P2P_LO_EVENT_INDEX, + GFP_KERNEL); + + if (!vendor_event) { + hdd_err("cfg80211_vendor_event_alloc failed"); + return; + } + + if (nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_STOP_REASON, + evt->reason_code)) { + hdd_err("nla put failed"); + kfree_skb(vendor_event); + return; + } + + cfg80211_vendor_event(vendor_event, GFP_KERNEL); +} + +/** + * hdd_adaptive_dwelltime_init() - initialization for adaptive dwell time config + * @hdd_ctx: HDD context + * + * This function sends the adaptive dwell time config configuration to the + * firmware via WMA + * + * Return: 0 - success, < 0 - failure + */ +static int hdd_adaptive_dwelltime_init(hdd_context_t *hdd_ctx) +{ + QDF_STATUS status; + struct adaptive_dwelltime_params dwelltime_params; + + dwelltime_params.is_enabled = + hdd_ctx->config->adaptive_dwell_mode_enabled; + dwelltime_params.dwelltime_mode = + hdd_ctx->config->global_adapt_dwelltime_mode; + dwelltime_params.lpf_weight = + hdd_ctx->config->adapt_dwell_lpf_weight; + dwelltime_params.passive_mon_intval = + hdd_ctx->config->adapt_dwell_passive_mon_intval; + dwelltime_params.wifi_act_threshold = + hdd_ctx->config->adapt_dwell_wifi_act_threshold; + + status = sme_set_adaptive_dwelltime_config(hdd_ctx->hHal, + &dwelltime_params); + + hdd_debug("Sending Adaptive Dwelltime Configuration to fw"); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("Failed to send Adaptive Dwelltime configuration!"); + return -EAGAIN; + } + return 0; +} + +#ifdef FEATURE_WLAN_AUTO_SHUTDOWN +/** + * hdd_set_auto_shutdown_cb() - Set auto shutdown callback + * @hdd_ctx: HDD context + * + * Set auto shutdown callback to get indications from firmware to indicate + * userspace to shutdown WLAN after a configured amount of inactivity. + * + * Return: 0 on success and errno on failure. + */ +static int hdd_set_auto_shutdown_cb(hdd_context_t *hdd_ctx) +{ + QDF_STATUS status; + + if (!hdd_ctx->config->WlanAutoShutdown) + return 0; + + status = sme_set_auto_shutdown_cb(hdd_ctx->hHal, + wlan_hdd_auto_shutdown_cb); + if (status != QDF_STATUS_SUCCESS) + hdd_err("Auto shutdown feature could not be enabled: %d", + status); + + return qdf_status_to_os_return(status); +} +#else +static int hdd_set_auto_shutdown_cb(hdd_context_t *hdd_ctx) +{ + return 0; +} +#endif + +/** + * hdd_features_init() - Init features + * @hdd_ctx: HDD context + * @adapter: Primary adapter context + * + * Initialize features and their feature context after WLAN firmware is up. + * + * Return: 0 on success and errno on failure. + */ +static int hdd_features_init(hdd_context_t *hdd_ctx, hdd_adapter_t *adapter) +{ + tSirTxPowerLimit hddtxlimit; + QDF_STATUS status; + struct sme_5g_band_pref_params band_pref_params; + int ret; + + ENTER(); + + ret = hdd_update_country_code(hdd_ctx, adapter); + if (ret) { + hdd_err("Failed to update country code: %d", ret); + goto out; + } + + /* FW capabilities received, Set the Dot11 mode */ + sme_setdef_dot11mode(hdd_ctx->hHal); + sme_set_prefer_80MHz_over_160MHz(hdd_ctx->hHal, + hdd_ctx->config->sta_prefer_80MHz_over_160MHz); + + sme_set_allow_adj_ch_bcn(hdd_ctx->hHal, + hdd_ctx->config->allow_adj_ch_bcn); + + if (hdd_ctx->config->fIsImpsEnabled) + hdd_set_idle_ps_config(hdd_ctx, true); + else + hdd_set_idle_ps_config(hdd_ctx, false); + + if (hdd_ctx->config->enable_go_cts2self_for_sta) + sme_set_cts2self_for_p2p_go(hdd_ctx->hHal); + + if (hdd_lro_init(hdd_ctx)) + hdd_warn("Unable to initialize LRO in fw"); + + if (hdd_adaptive_dwelltime_init(hdd_ctx)) + hdd_warn("Unable to send adaptive dwelltime setting to FW"); + + ret = hdd_init_thermal_info(hdd_ctx); + if (ret) { + hdd_err("Error while initializing thermal information"); + goto deregister_frames; + } + + if (cds_is_packet_log_enabled()) + hdd_pktlog_enable_disable(hdd_ctx, true, 0, 0); + + hddtxlimit.txPower2g = hdd_ctx->config->TxPower2g; + hddtxlimit.txPower5g = hdd_ctx->config->TxPower5g; + status = sme_txpower_limit(hdd_ctx->hHal, &hddtxlimit); + if (!QDF_IS_STATUS_SUCCESS(status)) + hdd_err("Error setting txlimit in sme: %d", status); + + hdd_tsf_init(hdd_ctx); + hdd_encrypt_decrypt_init(hdd_ctx); + + ret = hdd_register_cb(hdd_ctx); + if (ret) { + hdd_err("Failed to register HDD callbacks!"); + goto deregister_frames; + } + + if (hdd_ctx->config->dual_mac_feature_disable) { + status = wlan_hdd_disable_all_dual_mac_features(hdd_ctx); + if (status != QDF_STATUS_SUCCESS) { + hdd_err("Failed to disable dual mac features"); + goto deregister_cb; + } + } + if (hdd_ctx->config->goptimize_chan_avoid_event) { + status = sme_enable_disable_chanavoidind_event( + hdd_ctx->hHal, 0); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("Failed to disable Chan Avoidance Indication"); + goto deregister_cb; + } + } + + if (hdd_ctx->config->enable_5g_band_pref) { + band_pref_params.rssi_boost_threshold_5g = + hdd_ctx->config->rssi_boost_threshold_5g; + band_pref_params.rssi_boost_factor_5g = + hdd_ctx->config->rssi_boost_factor_5g; + band_pref_params.max_rssi_boost_5g = + hdd_ctx->config->max_rssi_boost_5g; + band_pref_params.rssi_penalize_threshold_5g = + hdd_ctx->config->rssi_penalize_threshold_5g; + band_pref_params.rssi_penalize_factor_5g = + hdd_ctx->config->rssi_penalize_factor_5g; + band_pref_params.max_rssi_penalize_5g = + hdd_ctx->config->max_rssi_penalize_5g; + sme_set_5g_band_pref(hdd_ctx->hHal, &band_pref_params); + } + + /* register P2P Listen Offload event callback */ + if (wma_is_p2p_lo_capable()) + sme_register_p2p_lo_event(hdd_ctx->hHal, hdd_ctx, + wlan_hdd_p2p_lo_event_callback); + + ret = hdd_set_auto_shutdown_cb(hdd_ctx); + + if (ret) + goto deregister_cb; + + EXIT(); + return 0; + +deregister_cb: + hdd_deregister_cb(hdd_ctx); +deregister_frames: + wlan_hdd_cfg80211_deregister_frames(adapter); +out: + return -EINVAL; + +} + + +/** + * hdd_set_rx_mode_rps() - Enable/disable RPS in SAP mode + * @hdd_context_t *hdd_ctx + * @hdd_adapter_t *padapter + * @bool enble + * + * Return: none + */ +void hdd_set_rx_mode_rps(hdd_context_t *hdd_ctx, void *padapter, + bool enable) +{ + struct cds_config_info *cds_cfg = cds_get_ini_config(); + hdd_adapter_t *adapter = padapter; + + if (adapter && hdd_ctx && cds_cfg && + !hdd_ctx->rps && cds_cfg->uc_offload_enabled) { + if (enable && !cds_cfg->rps_enabled) + hdd_send_rps_ind(adapter); + else if (!enable && cds_cfg->rps_enabled) + hdd_send_rps_disable_ind(adapter); + } +} + + +/** + * hdd_configure_cds() - Configure cds modules + * @hdd_ctx: HDD context + * @adapter: Primary adapter context + * + * Enable Cds modules after WLAN firmware is up. + * + * Return: 0 on success and errno on failure. + */ +int hdd_configure_cds(hdd_context_t *hdd_ctx, hdd_adapter_t *adapter) +{ + int ret; + QDF_STATUS status; + /* structure of SME function pointers to be used by CDS */ + struct cds_sme_cbacks sme_cbacks; + + /* structure of datapath function pointers to be used by CDS */ + struct cds_dp_cbacks dp_cbacks = {0}; + + ret = hdd_pre_enable_configure(hdd_ctx); + if (ret) { + hdd_err("Failed to pre-configure cds"); + goto out; + } + + /* Always get latest IPA resources allocated from cds_open and configure + * IPA module before configuring them to FW. Sequence required as crash + * observed otherwise. + */ + if (hdd_ipa_uc_ol_init(hdd_ctx)) { + hdd_err("Failed to setup pipes"); + goto out; + } + + /* + * Start CDS which starts up the SME/MAC/HAL modules and everything + * else + */ + status = cds_enable(hdd_ctx->pcds_context); + + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_alert("cds_enable failed"); + goto out; + } + + status = hdd_post_cds_enable_config(hdd_ctx); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_alert("hdd_post_cds_enable_config failed"); + goto cds_disable; + } + + ret = hdd_features_init(hdd_ctx, adapter); + if (ret) + goto cds_disable; + + sme_cbacks.sme_get_valid_channels = sme_get_cfg_valid_channels; + sme_cbacks.sme_get_nss_for_vdev = sme_get_vdev_type_nss; + status = cds_init_policy_mgr(&sme_cbacks); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("Policy manager initialization failed"); + goto hdd_features_deinit; + } + + if (hdd_ctx->config->lro_enable) { + dp_cbacks.hdd_en_lro_in_cc_cb = hdd_enable_lro_in_concurrency; + dp_cbacks.hdd_disble_lro_in_cc_cb = + hdd_disable_lro_in_concurrency; + } + + dp_cbacks.hdd_set_rx_mode_rps_cb = hdd_set_rx_mode_rps; + + dp_cbacks.ol_txrx_update_mac_id_cb = ol_txrx_update_mac_id; + if (cds_register_dp_cb(&dp_cbacks) != QDF_STATUS_SUCCESS) + hdd_err("Unable to register datapath callbacks in CDS"); + + if (hdd_ctx->config->enable_phy_reg_retention) + sme_cli_set_command(0, WMI_PDEV_PARAM_FAST_PWR_TRANSITION, + hdd_ctx->config->enable_phy_reg_retention, PDEV_CMD); + + return 0; + +hdd_features_deinit: + hdd_deregister_cb(hdd_ctx); + wlan_hdd_cfg80211_deregister_frames(adapter); +cds_disable: + cds_disable(hdd_ctx->pcds_context); +out: + return -EINVAL; +} + +/** + * hdd_deconfigure_cds() -De-Configure cds + * @hdd_ctx: HDD context + * + * Deconfigure Cds modules before WLAN firmware is down. + * + * Return: 0 on success and errno on failure. + */ +static int hdd_deconfigure_cds(hdd_context_t *hdd_ctx) +{ + QDF_STATUS qdf_status; + int ret = 0; + + ENTER(); + /* De-register the SME callbacks */ + hdd_deregister_cb(hdd_ctx); + hdd_encrypt_decrypt_deinit(hdd_ctx); + + /* De-init Policy Manager */ + if (!QDF_IS_STATUS_SUCCESS(cds_deinit_policy_mgr())) { + hdd_err("Failed to deinit policy manager"); + /* Proceed and complete the clean up */ + ret = -EINVAL; + } + + qdf_status = cds_deregister_dp_cb(); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + hdd_err("Failed to deregister datapath callbacks from CDS :%d", + qdf_status); + } + + qdf_status = cds_disable(hdd_ctx->pcds_context); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + hdd_err("Failed to Disable the CDS Modules! :%d", + qdf_status); + ret = -EINVAL; + } + + if (hdd_ipa_uc_ol_deinit(hdd_ctx)) { + hdd_err("Failed to disconnect pipes"); + ret = -EINVAL; + } + + EXIT(); + return ret; +} + + +/** + * hdd_wlan_stop_modules - Single driver state machine for stoping modules + * @hdd_ctx: HDD context + * @ftm_mode: ftm mode + * + * This function maintains the driver state machine it will be invoked from + * exit, shutdown and con_mode change handler. Depending on the driver state + * shall perform the stopping/closing of the modules. + * + * Return: 0 for success; non-zero for failure + */ +int hdd_wlan_stop_modules(hdd_context_t *hdd_ctx, bool ftm_mode) +{ + void *hif_ctx; + qdf_device_t qdf_ctx; + QDF_STATUS qdf_status; + int ret = 0; + p_cds_sched_context cds_sched_context = NULL; + bool is_unload_stop = cds_is_driver_unloading(); + bool is_recover_stop = cds_is_driver_recovering(); + bool is_idle_stop = !is_unload_stop && !is_recover_stop; + int active_threads; + + ENTER(); + + qdf_ctx = cds_get_context(QDF_MODULE_ID_QDF_DEVICE); + if (!qdf_ctx) { + hdd_err("QDF device context NULL"); + return -EINVAL; + } + + mutex_lock(&hdd_ctx->iface_change_lock); + hdd_ctx->stop_modules_in_progress = true; + + active_threads = cds_return_external_threads_count(); + if (active_threads > 0 || hdd_ctx->isWiphySuspended) { + hdd_warn("External threads %d wiphy suspend %d", + active_threads, hdd_ctx->isWiphySuspended); + + cds_print_external_threads(); + + if (is_idle_stop && !ftm_mode) { + mutex_unlock(&hdd_ctx->iface_change_lock); + qdf_mc_timer_start(&hdd_ctx->iface_change_timer, + hdd_ctx->config->iface_change_wait_time); + hdd_ctx->stop_modules_in_progress = false; + return 0; + } + } + + hdd_info("Present Driver Status: %d", hdd_ctx->driver_status); + + switch (hdd_ctx->driver_status) { + case DRIVER_MODULES_UNINITIALIZED: + hdd_info("Modules not initialized just return"); + goto done; + case DRIVER_MODULES_CLOSED: + hdd_info("Modules already closed"); + goto done; + case DRIVER_MODULES_ENABLED: + hdd_disable_power_management(); + if (hdd_deconfigure_cds(hdd_ctx)) { + hdd_alert("Failed to de-configure CDS"); + QDF_ASSERT(0); + ret = -EINVAL; + } + hdd_info("successfully Disabled the CDS modules!"); + hdd_ctx->driver_status = DRIVER_MODULES_OPENED; + break; + case DRIVER_MODULES_OPENED: + hdd_info("Closing CDS modules!"); + break; + default: + hdd_err("Trying to stop wlan in a wrong state: %d", + hdd_ctx->driver_status); + QDF_ASSERT(0); + ret = -EINVAL; + goto done; + } + + qdf_status = cds_post_disable(); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + hdd_err("Failed to process post CDS disable Modules! :%d", + qdf_status); + ret = -EINVAL; + QDF_ASSERT(0); + } + qdf_status = cds_close(hdd_ctx->pcds_context); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + hdd_warn("Failed to stop CDS:%d", qdf_status); + ret = -EINVAL; + QDF_ASSERT(0); + } + + /* Clean up message queues of TX, RX and MC thread */ + if (!is_recover_stop) { + cds_sched_context = get_cds_sched_ctxt(); + if (cds_sched_context) + cds_sched_flush_mc_mqs(cds_sched_context); + } + + hif_ctx = cds_get_context(QDF_MODULE_ID_HIF); + if (!hif_ctx) { + hdd_err("Hif context is Null"); + ret = -EINVAL; + } + + hdd_hif_close(hif_ctx); + + ol_cds_free(); + + if (is_idle_stop) { + ret = pld_power_off(qdf_ctx->dev); + if (ret) + hdd_err("CNSS power down failed put device into Low power mode:%d", + ret); + } + /* Once the firmware sequence is completed reset this flag */ + hdd_ctx->imps_enabled = false; + hdd_ctx->driver_status = DRIVER_MODULES_CLOSED; + +done: + hdd_ctx->stop_modules_in_progress = false; + mutex_unlock(&hdd_ctx->iface_change_lock); + EXIT(); + + return ret; + +} + +/** + * hdd_iface_change_callback() - Function invoked when stop modules expires + * @priv: pointer to hdd context + * + * This function is invoked when the timer waiting for the interface change + * expires, it shall cut-down the power to wlan and stop all the modules. + * + * Return: void + */ +static void hdd_iface_change_callback(void *priv) +{ + hdd_context_t *hdd_ctx = (hdd_context_t *) priv; + int ret; + int status = wlan_hdd_validate_context(hdd_ctx); + + if (status) + return; + + ENTER(); + hdd_info("Interface change timer expired close the modules!"); + ret = hdd_wlan_stop_modules(hdd_ctx, false); + if (ret) + hdd_alert("Failed to stop modules"); + EXIT(); +} + +/** + * hdd_state_info_dump() - prints state information of hdd layer + * @buf: buffer pointer + * @size: size of buffer to be filled + * + * This function is used to dump state information of hdd layer + * + * Return: None + */ +static void hdd_state_info_dump(char **buf_ptr, uint16_t *size) +{ + hdd_context_t *hdd_ctx; + hdd_adapter_list_node_t *adapter_node = NULL, *next = NULL; + QDF_STATUS status; + hdd_station_ctx_t *hdd_sta_ctx; + hdd_adapter_t *adapter; + uint16_t len = 0; + char *buf = *buf_ptr; + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (!hdd_ctx) { + hdd_err("Failed to get hdd context "); + return; + } + + hdd_notice("size of buffer: %d", *size); + + len += scnprintf(buf + len, *size - len, + "\n isWiphySuspended %d", hdd_ctx->isWiphySuspended); + len += scnprintf(buf + len, *size - len, + "\n isMcThreadSuspended %d", + hdd_ctx->isMcThreadSuspended); + + status = hdd_get_front_adapter(hdd_ctx, &adapter_node); + + while (NULL != adapter_node && QDF_STATUS_SUCCESS == status) { + adapter = adapter_node->pAdapter; + if (adapter->dev) + len += scnprintf(buf + len, *size - len, + "\n device name: %s", adapter->dev->name); + len += scnprintf(buf + len, *size - len, + "\n device_mode: %d", adapter->device_mode); + switch (adapter->device_mode) { + case QDF_STA_MODE: + case QDF_P2P_CLIENT_MODE: + hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + len += scnprintf(buf + len, *size - len, + "\n connState: %d", + hdd_sta_ctx->conn_info.connState); + break; + + default: + break; + } + status = hdd_get_next_adapter(hdd_ctx, adapter_node, &next); + adapter_node = next; + } + + *size -= len; + *buf_ptr += len; +} + +/** + * hdd_register_debug_callback() - registration function for hdd layer + * to print hdd state information + * + * Return: None + */ +static void hdd_register_debug_callback(void) +{ + qdf_register_debug_callback(QDF_MODULE_ID_HDD, &hdd_state_info_dump); +} + +/* + * wlan_init_bug_report_lock() - Initialize bug report lock + * + * This function is used to create bug report lock + * + * Return: None + */ +static void wlan_init_bug_report_lock(void) +{ + p_cds_contextType p_cds_context; + + p_cds_context = cds_get_global_context(); + if (!p_cds_context) { + hdd_err("cds context is NULL"); + return; + } + + qdf_spinlock_create(&p_cds_context->bug_report_lock); +} + +/** + * hdd_wlan_startup() - HDD init function + * @dev: Pointer to the underlying device + * + * This is the driver startup code executed once a WLAN device has been detected + * + * Return: 0 for success, < 0 for failure + */ +int hdd_wlan_startup(struct device *dev) +{ + QDF_STATUS status; + hdd_context_t *hdd_ctx; + int ret; + bool rtnl_held; + int set_value; + uint32_t num_abg_tx_chains = 0; + uint32_t num_11b_tx_chains = 0; + uint32_t num_11ag_tx_chains = 0; + + ENTER(); + + hdd_ctx = hdd_context_create(dev); + + if (IS_ERR(hdd_ctx)) + return PTR_ERR(hdd_ctx); + + qdf_mc_timer_init(&hdd_ctx->iface_change_timer, QDF_TIMER_TYPE_SW, + hdd_iface_change_callback, (void *)hdd_ctx); + + mutex_init(&hdd_ctx->iface_change_lock); + + ret = hdd_init_netlink_services(hdd_ctx); + if (ret) + goto err_hdd_free_context; + + hdd_green_ap_init(hdd_ctx); + + ret = hdd_wlan_start_modules(hdd_ctx, NULL, false); + if (ret) { + hdd_alert("Failed to start modules: %d", ret); + goto err_exit_nl_srv; + } + + wlan_init_bug_report_lock(); + + wlan_hdd_update_wiphy(hdd_ctx); + + if (0 != wlan_hdd_set_wow_pulse(hdd_ctx, true)) + hdd_notice("Failed to set wow pulse"); + + hdd_ctx->hHal = cds_get_context(QDF_MODULE_ID_SME); + + if (NULL == hdd_ctx->hHal) { + hdd_alert("HAL context is null"); + goto err_stop_modules; + } + + ret = hdd_wiphy_init(hdd_ctx); + if (ret) { + hdd_alert("Failed to initialize wiphy: %d", ret); + goto err_stop_modules; + } + + if (hdd_ctx->config->enable_dp_trace) + qdf_dp_trace_init(); + + if (hdd_ipa_init(hdd_ctx) == QDF_STATUS_E_FAILURE) + goto err_wiphy_unregister; + + hdd_initialize_mac_address(hdd_ctx); + + ret = register_netdevice_notifier(&hdd_netdev_notifier); + if (ret) { + hdd_err("register_netdevice_notifier failed: %d", ret); + goto err_ipa_cleanup; + } + + rtnl_held = hdd_hold_rtnl_lock(); + + ret = hdd_open_interfaces(hdd_ctx, rtnl_held); + if (ret) { + hdd_alert("Failed to open interfaces: %d", ret); + goto err_release_rtnl_lock; + } + + hdd_release_rtnl_lock(); + rtnl_held = false; + + wlan_hdd_update_11n_mode(hdd_ctx->config); + +#ifdef FEATURE_WLAN_AP_AP_ACS_OPTIMIZE + status = qdf_mc_timer_init(&hdd_ctx->skip_acs_scan_timer, + QDF_TIMER_TYPE_SW, + hdd_skip_acs_scan_timer_handler, + (void *)hdd_ctx); + if (!QDF_IS_STATUS_SUCCESS(status)) + hdd_err("Failed to init ACS Skip timer"); + qdf_spinlock_create(&hdd_ctx->acs_skip_lock); +#endif + + qdf_mc_timer_init(&hdd_ctx->tdls_source_timer, + QDF_TIMER_TYPE_SW, + wlan_hdd_change_tdls_mode, + hdd_ctx); + + hdd_bus_bandwidth_init(hdd_ctx); + + hdd_lpass_notify_start(hdd_ctx); + + if (hdd_ctx->rps) + hdd_set_rps_cpu_mask(hdd_ctx); + + ret = hdd_register_notifiers(hdd_ctx); + if (ret) + goto err_close_adapters; + + status = wlansap_global_init(); + if (QDF_IS_STATUS_ERROR(status)) + goto err_close_adapters; + + hdd_runtime_suspend_context_init(hdd_ctx); + memdump_init(); + hdd_driver_memdump_init(); + + if (hdd_enable_egap(hdd_ctx)) + hdd_warn("enhance green ap is not enabled"); + + if (hdd_ctx->config->fIsImpsEnabled) + hdd_set_idle_ps_config(hdd_ctx, true); + + if (hdd_ctx->config->sifs_burst_duration) { + set_value = (SIFS_BURST_DUR_MULTIPLIER) * + hdd_ctx->config->sifs_burst_duration; + + if ((set_value > 0) && (set_value <= SIFS_BURST_DUR_MAX)) + sme_cli_set_command(0, (int)WMI_PDEV_PARAM_BURST_DUR, + set_value, PDEV_CMD); + } + + /* set chip power save failure detected callback */ + sme_set_chip_pwr_save_fail_cb(hdd_ctx->hHal, + hdd_chip_pwr_save_fail_detected_cb); + + if (hdd_ctx->config->is_force_1x1) + sme_cli_set_command(0, (int)WMI_PDEV_PARAM_SET_IOT_PATTERN, + 1, PDEV_CMD); + + num_11b_tx_chains = hdd_ctx->config->num_11b_tx_chains; + num_11ag_tx_chains = hdd_ctx->config->num_11ag_tx_chains; + if (!hdd_ctx->config->enable2x2) { + if (num_11b_tx_chains > 1) + num_11b_tx_chains = 1; + if (num_11ag_tx_chains > 1) + num_11ag_tx_chains = 1; + } + WMI_PDEV_PARAM_SET_11B_TX_CHAIN_NUM(num_abg_tx_chains, + num_11b_tx_chains); + WMI_PDEV_PARAM_SET_11AG_TX_CHAIN_NUM(num_abg_tx_chains, + num_11ag_tx_chains); + sme_cli_set_command(0, (int)WMI_PDEV_PARAM_ABG_MODE_TX_CHAIN_NUM, + num_abg_tx_chains, PDEV_CMD); + + qdf_mc_timer_start(&hdd_ctx->iface_change_timer, + hdd_ctx->config->iface_change_wait_time); + + hdd_start_complete(0); + goto success; + +err_close_adapters: + hdd_close_all_adapters(hdd_ctx, rtnl_held); + +err_release_rtnl_lock: + if (rtnl_held) + hdd_release_rtnl_lock(); + +err_ipa_cleanup: + hdd_ipa_cleanup(hdd_ctx); + +err_wiphy_unregister: + wiphy_unregister(hdd_ctx->wiphy); + +err_stop_modules: + hdd_wlan_stop_modules(hdd_ctx, false); + +err_exit_nl_srv: + if (DRIVER_MODULES_CLOSED == hdd_ctx->driver_status) { + status = cds_sched_close(hdd_ctx->pcds_context); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("Failed to close CDS Scheduler"); + QDF_ASSERT(QDF_IS_STATUS_SUCCESS(status)); + } + } + + hdd_green_ap_deinit(hdd_ctx); + hdd_exit_netlink_services(hdd_ctx); + + cds_deinit_ini_config(); +err_hdd_free_context: + hdd_start_complete(ret); + qdf_mc_timer_destroy(&hdd_ctx->iface_change_timer); + mutex_destroy(&hdd_ctx->iface_change_lock); + hdd_context_destroy(hdd_ctx); + QDF_BUG(1); + return -EIO; + +success: + EXIT(); + return 0; +} + +/** + * hdd_wlan_update_target_info() - update target type info + * @hdd_ctx: HDD context + * @context: hif context + * + * Update target info received from firmware in hdd context + * Return:None + */ + +void hdd_wlan_update_target_info(hdd_context_t *hdd_ctx, void *context) +{ + struct hif_target_info *tgt_info = hif_get_target_info_handle(context); + + if (!tgt_info) { + hdd_err("Target info is Null"); + return; + } + + hdd_ctx->target_type = tgt_info->target_type; +} + +/** + * hdd_get_nud_stats_cb() - callback api to update the stats + * received from the firmware + * @data: pointer to adapter. + * @rsp: pointer to data received from FW. + * + * This is called when wlan driver received response event for + * get arp stats to firmware. + * + * Return: None + */ +static void hdd_get_nud_stats_cb(void *data, struct rsp_stats *rsp) +{ + hdd_context_t *hdd_ctx = (hdd_context_t *)data; + struct hdd_nud_stats_context *context; + int status; + hdd_adapter_t *adapter = NULL; + + ENTER(); + + if (!rsp) { + hdd_err("data is null"); + return; + } + + status = wlan_hdd_validate_context(hdd_ctx); + if (0 != status) + return; + + adapter = hdd_get_adapter_by_vdev(hdd_ctx, rsp->vdev_id); + if ((NULL == adapter) || (WLAN_HDD_ADAPTER_MAGIC != adapter->magic)) { + hdd_err("Invalid adapter or adapter has invalid magic"); + return; + } + + hdd_notice("rsp->arp_req_enqueue :%x", rsp->arp_req_enqueue); + hdd_notice("rsp->arp_req_tx_success :%x", rsp->arp_req_tx_success); + hdd_notice("rsp->arp_req_tx_failure :%x", rsp->arp_req_tx_failure); + hdd_notice("rsp->arp_rsp_recvd :%x", rsp->arp_rsp_recvd); + hdd_notice("rsp->out_of_order_arp_rsp_drop_cnt :%x", + rsp->out_of_order_arp_rsp_drop_cnt); + hdd_notice("rsp->dad_detected :%x", rsp->dad_detected); + hdd_notice("rsp->connect_status :%x", rsp->connect_status); + hdd_notice("rsp->ba_session_establishment_status :%x", + rsp->ba_session_establishment_status); + + adapter->hdd_stats.hdd_arp_stats.rx_fw_cnt = rsp->arp_rsp_recvd; + adapter->dad |= rsp->dad_detected; + adapter->con_status = rsp->connect_status; + + spin_lock(&hdd_context_lock); + context = &hdd_ctx->nud_stats_context; + complete(&context->response_event); + spin_unlock(&hdd_context_lock); + + EXIT(); + + return; +} + +/** + * hdd_register_cb - Register HDD callbacks. + * @hdd_ctx: HDD context + * + * Register the HDD callbacks to CDS/SME. + * + * Return: 0 for success or Error code for failure + */ +int hdd_register_cb(hdd_context_t *hdd_ctx) +{ + QDF_STATUS status; + int ret = 0; + + ENTER(); + + sme_register11d_scan_done_callback(hdd_ctx->hHal, hdd_11d_scan_done); + + sme_register_oem_data_rsp_callback(hdd_ctx->hHal, + hdd_send_oem_data_rsp_msg); + + status = sme_fw_mem_dump_register_cb(hdd_ctx->hHal, + wlan_hdd_cfg80211_fw_mem_dump_cb); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("Failed to register memdump callback"); + ret = -EINVAL; + return ret; + } + sme_register_mgmt_frame_ind_callback(hdd_ctx->hHal, + hdd_indicate_mgmt_frame); + sme_set_tsfcb(hdd_ctx->hHal, hdd_get_tsf_cb, hdd_ctx); + sme_nan_register_callback(hdd_ctx->hHal, + wlan_hdd_cfg80211_nan_callback); + sme_stats_ext_register_callback(hdd_ctx->hHal, + wlan_hdd_cfg80211_stats_ext_callback); + + sme_ext_scan_register_callback(hdd_ctx->hHal, + wlan_hdd_cfg80211_extscan_callback); + + status = cds_register_sap_restart_channel_switch_cb( + (void *)hdd_sap_restart_with_channel_switch); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("restart cb registration failed"); + ret = -EINVAL; + return ret; + } + + sme_set_rssi_threshold_breached_cb(hdd_ctx->hHal, + hdd_rssi_threshold_breached); + + sme_set_nud_debug_stats_cb(hdd_ctx->hHal, + hdd_get_nud_stats_cb); + + status = sme_bpf_offload_register_callback(hdd_ctx->hHal, + hdd_get_bpf_offload_cb); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("set bpf offload callback failed"); + ret = -EINVAL; + return ret; + } + + sme_set_link_layer_stats_ind_cb(hdd_ctx->hHal, + wlan_hdd_cfg80211_link_layer_stats_callback); + + sme_rso_cmd_status_cb(hdd_ctx->hHal, wlan_hdd_rso_cmd_status_cb); + + status = sme_set_lost_link_info_cb(hdd_ctx->hHal, + hdd_lost_link_info_cb); + /* print error and not block the startup process */ + if (!QDF_IS_STATUS_SUCCESS(status)) + hdd_err("set lost link info callback failed"); + + wlan_hdd_dcc_register_for_dcc_stats_event(hdd_ctx); + + status = sme_congestion_register_callback(hdd_ctx->hHal, + hdd_update_cca_info_cb); + if (!QDF_IS_STATUS_SUCCESS(status)) + hdd_err("set congestion callback failed"); + + EXIT(); + + return ret; +} + +/** + * hdd_deregister_cb() - De-Register HDD callbacks. + * @hdd_ctx: HDD context + * + * De-Register the HDD callbacks to CDS/SME. + * + * Return: void + */ +void hdd_deregister_cb(hdd_context_t *hdd_ctx) +{ + QDF_STATUS status; + + ENTER(); + + status = sme_deregister_for_dcc_stats_event(hdd_ctx->hHal); + if (!QDF_IS_STATUS_SUCCESS(status)) + hdd_err("De-register of dcc stats callback failed: %d", + status); + + sme_reset_link_layer_stats_ind_cb(hdd_ctx->hHal); + status = sme_bpf_offload_deregister_callback(hdd_ctx->hHal); + if (!QDF_IS_STATUS_SUCCESS(status)) + hdd_warn("De-register bpf offload callback failed: %d", + status); + sme_reset_rssi_threshold_breached_cb(hdd_ctx->hHal); + + status = cds_deregister_sap_restart_channel_switch_cb(); + if (!QDF_IS_STATUS_SUCCESS(status)) + hdd_warn("De-register restart cb registration failed: %d", + status); + + sme_stats_ext_register_callback(hdd_ctx->hHal, + wlan_hdd_cfg80211_stats_ext_callback); + + sme_nan_deregister_callback(hdd_ctx->hHal); + status = sme_reset_tsfcb(hdd_ctx->hHal); + if (!QDF_IS_STATUS_SUCCESS(status)) + hdd_err("Failed to de-register tsfcb the callback:%d", + status); + status = sme_fw_mem_dump_unregister_cb(hdd_ctx->hHal); + if (!QDF_IS_STATUS_SUCCESS(status)) + hdd_err("Failed to de-register the fw mem dump callback: %d", + status); + + sme_deregister_oem_data_rsp_callback(hdd_ctx->hHal); + sme_deregister11d_scan_done_callback(hdd_ctx->hHal); + + EXIT(); +} + +/** + * hdd_softap_sta_deauth() - handle deauth req from HDD + * @adapter: Pointer to the HDD + * @enable: bool value + * + * This to take counter measure to handle deauth req from HDD + * + * Return: None + */ +QDF_STATUS hdd_softap_sta_deauth(hdd_adapter_t *adapter, + struct tagCsrDelStaParams *pDelStaParams) +{ + QDF_STATUS qdf_status = QDF_STATUS_E_FAULT; + + ENTER(); + + hdd_notice("hdd_softap_sta_deauth:(%p, false)", + (WLAN_HDD_GET_CTX(adapter))->pcds_context); + + /* Ignore request to deauth bcmc station */ + if (pDelStaParams->peerMacAddr.bytes[0] & 0x1) + return qdf_status; + + qdf_status = + wlansap_deauth_sta(WLAN_HDD_GET_SAP_CTX_PTR(adapter), + pDelStaParams); + + EXIT(); + return qdf_status; +} + +/** + * hdd_softap_sta_disassoc() - take counter measure to handle deauth req from HDD + * @adapter: Pointer to the HDD + * @p_del_sta_params: pointer to station deletion parameters + * + * This to take counter measure to handle deauth req from HDD + * + * Return: None + */ +void hdd_softap_sta_disassoc(hdd_adapter_t *adapter, + struct tagCsrDelStaParams *pDelStaParams) +{ + ENTER(); + + hdd_notice("hdd_softap_sta_disassoc:(%p, false)", + (WLAN_HDD_GET_CTX(adapter))->pcds_context); + + /* Ignore request to disassoc bcmc station */ + if (pDelStaParams->peerMacAddr.bytes[0] & 0x1) + return; + + wlansap_disassoc_sta(WLAN_HDD_GET_SAP_CTX_PTR(adapter), + pDelStaParams); +} + +void hdd_softap_tkip_mic_fail_counter_measure(hdd_adapter_t *adapter, + bool enable) +{ + ENTER(); + + hdd_notice("hdd_softap_tkip_mic_fail_counter_measure:(%p, false)", + (WLAN_HDD_GET_CTX(adapter))->pcds_context); + + wlansap_set_counter_measure(WLAN_HDD_GET_SAP_CTX_PTR(adapter), + (bool) enable); +} + +/** + * hdd_issta_p2p_clientconnected() - check if sta or p2p client is connected + * @hdd_ctx: HDD Context + * + * API to find if there is any STA or P2P-Client is connected + * + * Return: true if connected; false otherwise + */ +QDF_STATUS hdd_issta_p2p_clientconnected(hdd_context_t *hdd_ctx) +{ + return sme_is_sta_p2p_client_connected(hdd_ctx->hHal); +} + +/** + * wlan_hdd_disable_roaming() - disable roaming on all STAs except the input one + * @adapter: HDD adapter pointer + * + * This function loop through each adapter and disable roaming on each STA + * device mode except the input adapter. + * + * Note: On the input adapter roaming is not enabled yet hence no need to + * disable. + * + * Return: None + */ +void wlan_hdd_disable_roaming(hdd_adapter_t *adapter) +{ + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + hdd_adapter_t *adapterIdx = NULL; + hdd_adapter_list_node_t *adapterNode = NULL; + hdd_adapter_list_node_t *pNext = NULL; + QDF_STATUS status; + + if (hdd_ctx->config->isFastRoamIniFeatureEnabled && + hdd_ctx->config->isRoamOffloadScanEnabled && + QDF_STA_MODE == adapter->device_mode && + cds_is_sta_active_connection_exists()) { + hdd_notice("Connect received on STA sessionId(%d)", + adapter->sessionId); + /* + * Loop through adapter and disable roaming for each STA device + * mode except the input adapter. + */ + status = hdd_get_front_adapter(hdd_ctx, &adapterNode); + + while (NULL != adapterNode && QDF_STATUS_SUCCESS == status) { + adapterIdx = adapterNode->pAdapter; + + if (QDF_STA_MODE == adapterIdx->device_mode + && adapter->sessionId != adapterIdx->sessionId) { + hdd_notice("Disable Roaming on sessionId(%d)", + adapterIdx->sessionId); + sme_stop_roaming(WLAN_HDD_GET_HAL_CTX + (adapterIdx), + adapterIdx->sessionId, 0); + } + + status = hdd_get_next_adapter(hdd_ctx, + adapterNode, + &pNext); + adapterNode = pNext; + } + } +} + +/** + * wlan_hdd_enable_roaming() - enable roaming on all STAs except the input one + * @adapter: HDD adapter pointer + * + * This function loop through each adapter and enable roaming on each STA + * device mode except the input adapter. + * Note: On the input adapter no need to enable roaming because link got + * disconnected on this. + * + * Return: None + */ +void wlan_hdd_enable_roaming(hdd_adapter_t *adapter) +{ + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + hdd_adapter_t *adapterIdx = NULL; + hdd_adapter_list_node_t *adapterNode = NULL; + hdd_adapter_list_node_t *pNext = NULL; + QDF_STATUS status; + + if (hdd_ctx->config->isFastRoamIniFeatureEnabled && + hdd_ctx->config->isRoamOffloadScanEnabled && + QDF_STA_MODE == adapter->device_mode && + cds_is_sta_active_connection_exists()) { + hdd_notice("Disconnect received on STA sessionId(%d)", + adapter->sessionId); + /* + * Loop through adapter and enable roaming for each STA device + * mode except the input adapter. + */ + status = hdd_get_front_adapter(hdd_ctx, &adapterNode); + + while (NULL != adapterNode && QDF_STATUS_SUCCESS == status) { + adapterIdx = adapterNode->pAdapter; + + if (QDF_STA_MODE == adapterIdx->device_mode + && adapter->sessionId != adapterIdx->sessionId) { + hdd_notice("Enabling Roaming on sessionId(%d)", + adapterIdx->sessionId); + sme_start_roaming(WLAN_HDD_GET_HAL_CTX + (adapterIdx), + adapterIdx->sessionId, + REASON_CONNECT); + } + + status = hdd_get_next_adapter(hdd_ctx, + adapterNode, + &pNext); + adapterNode = pNext; + } + } +} + +void wlan_hdd_send_svc_nlink_msg(int radio, int type, void *data, int len) +{ + struct sk_buff *skb; + struct nlmsghdr *nlh; + tAniMsgHdr *ani_hdr; + void *nl_data = NULL; + int flags = GFP_KERNEL; + struct radio_index_tlv *radio_info; + int tlv_len; + + if (in_interrupt() || irqs_disabled() || in_atomic()) + flags = GFP_ATOMIC; + + skb = alloc_skb(NLMSG_SPACE(WLAN_NL_MAX_PAYLOAD), flags); + + if (skb == NULL) { + hdd_err("alloc_skb failed"); + return; + } + + nlh = (struct nlmsghdr *)skb->data; + nlh->nlmsg_pid = 0; /* from kernel */ + nlh->nlmsg_flags = 0; + nlh->nlmsg_seq = 0; + nlh->nlmsg_type = WLAN_NL_MSG_SVC; + + ani_hdr = NLMSG_DATA(nlh); + ani_hdr->type = type; + + switch (type) { + case WLAN_SVC_FW_CRASHED_IND: + case WLAN_SVC_FW_SHUTDOWN_IND: + case WLAN_SVC_LTE_COEX_IND: + case WLAN_SVC_WLAN_AUTO_SHUTDOWN_IND: + case WLAN_SVC_WLAN_AUTO_SHUTDOWN_CANCEL_IND: + ani_hdr->length = 0; + nlh->nlmsg_len = NLMSG_LENGTH((sizeof(tAniMsgHdr))); + break; + case WLAN_SVC_WLAN_STATUS_IND: + case WLAN_SVC_WLAN_VERSION_IND: + case WLAN_SVC_DFS_CAC_START_IND: + case WLAN_SVC_DFS_CAC_END_IND: + case WLAN_SVC_DFS_RADAR_DETECT_IND: + case WLAN_SVC_DFS_ALL_CHANNEL_UNAVAIL_IND: + case WLAN_SVC_WLAN_TP_IND: + case WLAN_SVC_WLAN_TP_TX_IND: + case WLAN_SVC_RPS_ENABLE_IND: + case WLAN_SVC_CORE_MINFREQ: + ani_hdr->length = len; + nlh->nlmsg_len = NLMSG_LENGTH((sizeof(tAniMsgHdr) + len)); + nl_data = (char *)ani_hdr + sizeof(tAniMsgHdr); + memcpy(nl_data, data, len); + break; + + default: + hdd_err("WLAN SVC: Attempt to send unknown nlink message %d", + type); + kfree_skb(skb); + return; + } + + /* + * Add radio index at the end of the svc event in TLV format to maintain + * the backward compatibility with userspace applications. + */ + + tlv_len = 0; + + if ((sizeof(*ani_hdr) + len + sizeof(struct radio_index_tlv)) + < WLAN_NL_MAX_PAYLOAD) { + radio_info = (struct radio_index_tlv *)((char *) ani_hdr + + sizeof(*ani_hdr) + len); + radio_info->type = (unsigned short) WLAN_SVC_WLAN_RADIO_INDEX; + radio_info->length = (unsigned short) sizeof(radio_info->radio); + radio_info->radio = radio; + tlv_len = sizeof(*radio_info); + QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO, + "Added radio index tlv - radio index %d", + radio_info->radio); + } + + nlh->nlmsg_len += tlv_len; + skb_put(skb, NLMSG_SPACE(sizeof(tAniMsgHdr) + len + tlv_len)); + + nl_srv_bcast(skb); + + return; +} + +#ifdef FEATURE_WLAN_AUTO_SHUTDOWN +void wlan_hdd_auto_shutdown_cb(void) +{ + hdd_context_t *hdd_ctx = cds_get_global_context(); + + if (!hdd_ctx) + return; + + hdd_notice("Wlan Idle. Sending Shutdown event.."); + wlan_hdd_send_svc_nlink_msg(hdd_ctx->radio_index, + WLAN_SVC_WLAN_AUTO_SHUTDOWN_IND, NULL, 0); +} + +void wlan_hdd_auto_shutdown_enable(hdd_context_t *hdd_ctx, bool enable) +{ + hdd_adapter_list_node_t *adapterNode = NULL, *pNext = NULL; + QDF_STATUS status; + hdd_adapter_t *adapter; + bool ap_connected = false, sta_connected = false; + tHalHandle hal_handle; + + hal_handle = hdd_ctx->hHal; + if (hal_handle == NULL) + return; + + if (hdd_ctx->config->WlanAutoShutdown == 0) + return; + + if (enable == false) { + if (sme_set_auto_shutdown_timer(hal_handle, 0) != + QDF_STATUS_SUCCESS) { + hdd_err("Failed to stop wlan auto shutdown timer"); + } + wlan_hdd_send_svc_nlink_msg(hdd_ctx->radio_index, + WLAN_SVC_WLAN_AUTO_SHUTDOWN_CANCEL_IND, NULL, 0); + return; + } + + /* To enable shutdown timer check conncurrency */ + if (cds_concurrent_open_sessions_running()) { + status = hdd_get_front_adapter(hdd_ctx, &adapterNode); + + while (NULL != adapterNode && QDF_STATUS_SUCCESS == status) { + adapter = adapterNode->pAdapter; + if (adapter + && adapter->device_mode == + QDF_STA_MODE) { + if (WLAN_HDD_GET_STATION_CTX_PTR(adapter)-> + conn_info.connState == + eConnectionState_Associated) { + sta_connected = true; + break; + } + } + if (adapter + && adapter->device_mode == QDF_SAP_MODE) { + if (WLAN_HDD_GET_AP_CTX_PTR(adapter)-> + bApActive == true) { + ap_connected = true; + break; + } + } + status = hdd_get_next_adapter(hdd_ctx, + adapterNode, + &pNext); + adapterNode = pNext; + } + } + + if (ap_connected == true || sta_connected == true) { + hdd_notice("CC Session active. Shutdown timer not enabled"); + return; + } else { + if (sme_set_auto_shutdown_timer(hal_handle, + hdd_ctx->config-> + WlanAutoShutdown) + != QDF_STATUS_SUCCESS) + hdd_err("Failed to start wlan auto shutdown timer"); + else + hdd_notice("Auto Shutdown timer for %d seconds enabled", + hdd_ctx->config->WlanAutoShutdown); + + } +} +#endif + +hdd_adapter_t *hdd_get_con_sap_adapter(hdd_adapter_t *this_sap_adapter, + bool check_start_bss) +{ + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(this_sap_adapter); + hdd_adapter_t *adapter, *con_sap_adapter; + QDF_STATUS status = QDF_STATUS_SUCCESS; + hdd_adapter_list_node_t *adapterNode = NULL, *pNext = NULL; + + con_sap_adapter = NULL; + + status = hdd_get_front_adapter(hdd_ctx, &adapterNode); + while (NULL != adapterNode && QDF_STATUS_SUCCESS == status) { + adapter = adapterNode->pAdapter; + if (adapter && ((adapter->device_mode == QDF_SAP_MODE) || + (adapter->device_mode == QDF_P2P_GO_MODE)) && + adapter != this_sap_adapter) { + if (check_start_bss) { + if (test_bit(SOFTAP_BSS_STARTED, + &adapter->event_flags)) { + con_sap_adapter = adapter; + break; + } + } else { + con_sap_adapter = adapter; + break; + } + } + status = hdd_get_next_adapter(hdd_ctx, adapterNode, &pNext); + adapterNode = pNext; + } + + return con_sap_adapter; +} + +#ifdef MSM_PLATFORM +static inline bool hdd_adapter_is_client(hdd_adapter_t *adapter) +{ + return adapter->device_mode == QDF_STA_MODE || + adapter->device_mode == QDF_P2P_CLIENT_MODE; +} + +static inline bool hdd_adapter_is_ap(hdd_adapter_t *adapter) +{ + return adapter->device_mode == QDF_SAP_MODE || + adapter->device_mode == QDF_P2P_GO_MODE; +} + +static bool hdd_any_adapter_is_assoc(hdd_context_t *hdd_ctx) +{ + QDF_STATUS status; + hdd_adapter_list_node_t *node; + + status = hdd_get_front_adapter(hdd_ctx, &node); + while (QDF_IS_STATUS_SUCCESS(status) && node) { + hdd_adapter_t *adapter = node->pAdapter; + + if (adapter && + hdd_adapter_is_client(adapter) && + WLAN_HDD_GET_STATION_CTX_PTR(adapter)-> + conn_info.connState == eConnectionState_Associated) { + return true; + } + + if (adapter && + hdd_adapter_is_ap(adapter) && + WLAN_HDD_GET_AP_CTX_PTR(adapter)->bApActive) { + return true; + } + + status = hdd_get_next_adapter(hdd_ctx, node, &node); + } + + return false; +} + +static bool hdd_bus_bw_compute_timer_is_running(hdd_context_t *hdd_ctx) +{ + bool is_running; + + qdf_spinlock_acquire(&hdd_ctx->bus_bw_timer_lock); + is_running = hdd_ctx->bus_bw_timer_running; + qdf_spinlock_release(&hdd_ctx->bus_bw_timer_lock); + + return is_running; +} + +static void __hdd_bus_bw_compute_timer_start(hdd_context_t *hdd_ctx) +{ + qdf_spinlock_acquire(&hdd_ctx->bus_bw_timer_lock); + hdd_ctx->bus_bw_timer_running = true; + qdf_timer_start(&hdd_ctx->bus_bw_timer, + hdd_ctx->config->busBandwidthComputeInterval); + qdf_spinlock_release(&hdd_ctx->bus_bw_timer_lock); +} + +void hdd_bus_bw_compute_timer_start(hdd_context_t *hdd_ctx) +{ + ENTER(); + + if (hdd_bus_bw_compute_timer_is_running(hdd_ctx)) { + hdd_debug("Bandwidth compute timer already started"); + return; + } + + __hdd_bus_bw_compute_timer_start(hdd_ctx); + + EXIT(); +} + +void hdd_bus_bw_compute_timer_try_start(hdd_context_t *hdd_ctx) +{ + ENTER(); + + if (hdd_bus_bw_compute_timer_is_running(hdd_ctx)) { + hdd_debug("Bandwidth compute timer already started"); + return; + } + + if (hdd_any_adapter_is_assoc(hdd_ctx)) + __hdd_bus_bw_compute_timer_start(hdd_ctx); + + EXIT(); +} + +static void __hdd_bus_bw_compute_timer_stop(hdd_context_t *hdd_ctx) +{ + hdd_ipa_set_perf_level(hdd_ctx, 0, 0); + + qdf_spinlock_acquire(&hdd_ctx->bus_bw_timer_lock); + qdf_timer_stop(&hdd_ctx->bus_bw_timer); + hdd_ctx->bus_bw_timer_running = false; + qdf_spinlock_release(&hdd_ctx->bus_bw_timer_lock); + + hdd_reset_tcp_delack(hdd_ctx); +} + +void hdd_bus_bw_compute_timer_stop(hdd_context_t *hdd_ctx) +{ + ENTER(); + + if (!hdd_bus_bw_compute_timer_is_running(hdd_ctx)) { + hdd_debug("Bandwidth compute timer already stopped"); + return; + } + + __hdd_bus_bw_compute_timer_stop(hdd_ctx); + + EXIT(); +} + +void hdd_bus_bw_compute_timer_try_stop(hdd_context_t *hdd_ctx) +{ + ENTER(); + + if (!hdd_bus_bw_compute_timer_is_running(hdd_ctx)) { + hdd_debug("Bandwidth compute timer already stopped"); + return; + } + + if (!hdd_any_adapter_is_assoc(hdd_ctx)) + __hdd_bus_bw_compute_timer_stop(hdd_ctx); + + EXIT(); +} +#endif + +/** + * wlan_hdd_check_custom_con_channel_rules() - This function checks the sap's + * and sta's operating channel. + * @sta_adapter: Describe the first argument to foobar. + * @ap_adapter: Describe the second argument to foobar. + * @roam_profile: Roam profile of AP to which STA wants to connect. + * @concurrent_chnl_same: If both SAP and STA channels are same then + * set this flag to true else false. + * + * This function checks the sap's operating channel and sta's operating channel. + * if both are same then it will return false else it will restart the sap in + * sta's channel and return true. + * + * Return: QDF_STATUS_SUCCESS or QDF_STATUS_E_FAILURE. + */ +QDF_STATUS wlan_hdd_check_custom_con_channel_rules(hdd_adapter_t *sta_adapter, + hdd_adapter_t *ap_adapter, + tCsrRoamProfile *roam_profile, + tScanResultHandle *scan_cache, + bool *concurrent_chnl_same) +{ + hdd_ap_ctx_t *hdd_ap_ctx; + uint8_t channel_id; + QDF_STATUS status; + enum tQDF_ADAPTER_MODE device_mode = ap_adapter->device_mode; + *concurrent_chnl_same = true; + + hdd_ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(ap_adapter); + status = + sme_get_ap_channel_from_scan_cache(WLAN_HDD_GET_HAL_CTX(sta_adapter), + roam_profile, + scan_cache, + &channel_id); + if ((QDF_STATUS_SUCCESS == status)) { + if ((QDF_SAP_MODE == device_mode) && + (channel_id < SIR_11A_CHANNEL_BEGIN)) { + if (hdd_ap_ctx->operatingChannel != channel_id) { + *concurrent_chnl_same = false; + hdd_info("channels are different"); + } + } else if ((QDF_P2P_GO_MODE == device_mode) && + (channel_id >= SIR_11A_CHANNEL_BEGIN)) { + if (hdd_ap_ctx->operatingChannel != channel_id) { + *concurrent_chnl_same = false; + hdd_info("channels are different"); + } + } + } else { + /* + * Lets handle worst case scenario here, Scan cache lookup is + * failed so we have to stop the SAP to avoid any channel + * discrepancy between SAP's channel and STA's channel. + * Return the status as failure so caller function could know + * that scan look up is failed. + */ + hdd_err("Finding AP from scan cache failed"); + return QDF_STATUS_E_FAILURE; + } + return QDF_STATUS_SUCCESS; +} + +/** + * wlan_hdd_stop_sap() - This function stops bss of SAP. + * @ap_adapter: SAP adapter + * + * This function will process the stopping of sap adapter. + * + * Return: None + */ +void wlan_hdd_stop_sap(hdd_adapter_t *ap_adapter) +{ + hdd_ap_ctx_t *hdd_ap_ctx; + hdd_hostapd_state_t *hostapd_state; + QDF_STATUS qdf_status; + hdd_context_t *hdd_ctx; + + if (NULL == ap_adapter) { + hdd_err("ap_adapter is NULL here"); + return; + } + + hdd_ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(ap_adapter); + hdd_ctx = WLAN_HDD_GET_CTX(ap_adapter); + if (wlan_hdd_validate_context(hdd_ctx)) + return; + + mutex_lock(&hdd_ctx->sap_lock); + if (test_bit(SOFTAP_BSS_STARTED, &ap_adapter->event_flags)) { + wlan_hdd_del_station(ap_adapter); + hdd_cleanup_actionframe(hdd_ctx, ap_adapter); + hostapd_state = WLAN_HDD_GET_HOSTAP_STATE_PTR(ap_adapter); + hdd_info("Now doing SAP STOPBSS"); + qdf_event_reset(&hostapd_state->qdf_stop_bss_event); + if (QDF_STATUS_SUCCESS == wlansap_stop_bss(hdd_ap_ctx-> + sapContext)) { + qdf_status = qdf_wait_single_event(&hostapd_state-> + qdf_stop_bss_event, + SME_CMD_TIMEOUT_VALUE); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + mutex_unlock(&hdd_ctx->sap_lock); + hdd_err("SAP Stop Failed"); + return; + } + } + clear_bit(SOFTAP_BSS_STARTED, &ap_adapter->event_flags); + cds_decr_session_set_pcl(ap_adapter->device_mode, + ap_adapter->sessionId); + hdd_info("SAP Stop Success"); + } else { + hdd_err("Can't stop ap because its not started"); + } + mutex_unlock(&hdd_ctx->sap_lock); + return; +} + +/** + * wlan_hdd_start_sap() - this function starts bss of SAP. + * @ap_adapter: SAP adapter + * + * This function will process the starting of sap adapter. + * + * Return: None + */ +void wlan_hdd_start_sap(hdd_adapter_t *ap_adapter, bool reinit) +{ + hdd_ap_ctx_t *hdd_ap_ctx; + hdd_hostapd_state_t *hostapd_state; + QDF_STATUS qdf_status; + hdd_context_t *hdd_ctx; + tsap_Config_t *sap_config; + + if (NULL == ap_adapter) { + hdd_err("ap_adapter is NULL here"); + return; + } + + if (QDF_SAP_MODE != ap_adapter->device_mode) { + hdd_err("SoftAp role has not been enabled"); + return; + } + + hdd_ctx = WLAN_HDD_GET_CTX(ap_adapter); + hdd_ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(ap_adapter); + hostapd_state = WLAN_HDD_GET_HOSTAP_STATE_PTR(ap_adapter); + sap_config = &ap_adapter->sessionCtx.ap.sapConfig; + + mutex_lock(&hdd_ctx->sap_lock); + if (test_bit(SOFTAP_BSS_STARTED, &ap_adapter->event_flags)) + goto end; + + if (0 != wlan_hdd_cfg80211_update_apies(ap_adapter)) { + hdd_err("SAP Not able to set AP IEs"); + wlansap_reset_sap_config_add_ie(sap_config, eUPDATE_IE_ALL); + goto end; + } + + qdf_event_reset(&hostapd_state->qdf_event); + if (wlansap_start_bss(hdd_ap_ctx->sapContext, hdd_hostapd_sap_event_cb, + &hdd_ap_ctx->sapConfig, + ap_adapter->dev) + != QDF_STATUS_SUCCESS) + goto end; + + hdd_info("Waiting for SAP to start"); + qdf_status = qdf_wait_single_event(&hostapd_state->qdf_event, + SME_CMD_TIMEOUT_VALUE); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + hdd_err("SAP Start failed"); + goto end; + } + hdd_info("SAP Start Success"); + set_bit(SOFTAP_BSS_STARTED, &ap_adapter->event_flags); + if (hostapd_state->bssState == BSS_START) + cds_incr_active_session(ap_adapter->device_mode, + ap_adapter->sessionId); + hostapd_state->bCommit = true; + +end: + mutex_unlock(&hdd_ctx->sap_lock); + return; +} + +/** + * wlan_hdd_soc_set_antenna_mode_cb() - Callback for set dual + * mac scan config + * @status: Status of set antenna mode + * + * Callback on setting the dual mac configuration + * + * Return: None + */ +void wlan_hdd_soc_set_antenna_mode_cb( + enum set_antenna_mode_status status) +{ + hdd_context_t *hdd_ctx; + + hdd_info("Status: %d", status); + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (0 != wlan_hdd_validate_context(hdd_ctx)) + return; + + /* Signal the completion of set dual mac config */ + complete(&hdd_ctx->set_antenna_mode_cmpl); +} + +/** + * hdd_get_fw_version() - Get FW version + * @hdd_ctx: pointer to HDD context. + * @major_spid: FW version - major spid. + * @minor_spid: FW version - minor spid + * @ssid: FW version - ssid + * @crmid: FW version - crmid + * + * This function is called to get the firmware build version stored + * as part of the HDD context + * + * Return: None + */ +void hdd_get_fw_version(hdd_context_t *hdd_ctx, + uint32_t *major_spid, uint32_t *minor_spid, + uint32_t *siid, uint32_t *crmid) +{ + *major_spid = (hdd_ctx->target_fw_version & 0xf0000000) >> 28; + *minor_spid = (hdd_ctx->target_fw_version & 0xf000000) >> 24; + *siid = (hdd_ctx->target_fw_version & 0xf00000) >> 20; + *crmid = hdd_ctx->target_fw_version & 0x7fff; +} + +#ifdef QCA_CONFIG_SMP +/** + * wlan_hdd_get_cpu() - get cpu_index + * + * Return: cpu_index + */ +int wlan_hdd_get_cpu(void) +{ + int cpu_index = get_cpu(); + put_cpu(); + return cpu_index; +} +#endif + +/** + * hdd_get_fwpath() - get framework path + * + * This function is used to get the string written by + * userspace to start the wlan driver + * + * Return: string + */ +const char *hdd_get_fwpath(void) +{ + return fwpath.string; +} + +/** + * hdd_init() - Initialize Driver + * + * This function initilizes CDS global context with the help of cds_init. This + * has to be the first function called after probe to get a valid global + * context. + * + * Return: 0 for success, errno on failure + */ +int hdd_init(void) +{ + v_CONTEXT_t p_cds_context = NULL; + int ret = 0; + + p_cds_context = cds_init(); +#ifdef WLAN_LOGGING_SOCK_SVC_ENABLE + wlan_logging_sock_init_svc(); +#endif + + if (p_cds_context == NULL) { + hdd_alert("Failed to allocate CDS context"); + ret = -ENOMEM; + goto err_out; + } + + hdd_trace_init(); + hdd_register_debug_callback(); + +err_out: + return ret; +} + +/** + * hdd_deinit() - Deinitialize Driver + * + * This function frees CDS global context with the help of cds_deinit. This + * has to be the last function call in remove callback to free the global + * context. + */ +void hdd_deinit(void) +{ + hdd_deinit_wowl(); + cds_deinit(); + +#ifdef WLAN_LOGGING_SOCK_SVC_ENABLE + wlan_logging_sock_deinit_svc(); +#endif +} + +#define HDD_WLAN_START_WAIT_TIME (CDS_WMA_TIMEOUT + 5000) + +static int wlan_hdd_state_ctrl_param_open(struct inode *inode, + struct file *file) +{ + return 0; +} + +static ssize_t wlan_hdd_state_ctrl_param_write(struct file *filp, + const char __user *user_buf, + size_t count, + loff_t *f_pos) +{ + char buf[3]; + static const char wlan_off_str[] = "OFF"; + static const char wlan_on_str[] = "ON"; + int ret; + unsigned long rc; + + if (copy_from_user(buf, user_buf, 3)) { + pr_err("Failed to read buffer\n"); + return -EINVAL; + } + + if (strncmp(buf, wlan_off_str, strlen(wlan_off_str)) == 0) { + pr_debug("Wifi turning off from UI\n"); + goto exit; + } + + if (strncmp(buf, wlan_on_str, strlen(wlan_on_str)) != 0) { + pr_err("Invalid value received from framework"); + goto exit; + } + + if (!cds_is_driver_loaded()) { + rc = wait_for_completion_timeout(&wlan_start_comp, + msecs_to_jiffies(HDD_WLAN_START_WAIT_TIME)); + if (!rc) { + hdd_alert("Timed-out waiting in wlan_hdd_state_ctrl_param_write"); + ret = -EINVAL; + hdd_start_complete(ret); + return ret; + } + + hdd_start_complete(0); + } + +exit: + return count; +} + + +const struct file_operations wlan_hdd_state_fops = { + .owner = THIS_MODULE, + .open = wlan_hdd_state_ctrl_param_open, + .write = wlan_hdd_state_ctrl_param_write, +}; + +static int wlan_hdd_state_ctrl_param_create(void) +{ + unsigned int wlan_hdd_state_major = 0; + int ret; + struct device *dev; + + device = MKDEV(wlan_hdd_state_major, 0); + + ret = alloc_chrdev_region(&device, 0, dev_num, "qcwlanstate"); + if (ret) { + pr_err("Failed to register qcwlanstate"); + goto dev_alloc_err; + } + wlan_hdd_state_major = MAJOR(device); + + class = class_create(THIS_MODULE, WLAN_MODULE_NAME); + if (IS_ERR(class)) { + pr_err("wlan_hdd_state class_create error"); + goto class_err; + } + + dev = device_create(class, NULL, device, NULL, WLAN_MODULE_NAME); + if (IS_ERR(dev)) { + pr_err("wlan_hdd_statedevice_create error"); + goto err_class_destroy; + } + + cdev_init(&wlan_hdd_state_cdev, &wlan_hdd_state_fops); + ret = cdev_add(&wlan_hdd_state_cdev, device, dev_num); + if (ret) { + pr_err("Failed to add cdev error"); + goto cdev_add_err; + } + + pr_info("wlan_hdd_state %s major(%d) initialized", + WLAN_MODULE_NAME, wlan_hdd_state_major); + + return 0; + +cdev_add_err: + device_destroy(class, device); +err_class_destroy: + class_destroy(class); +class_err: + unregister_chrdev_region(device, dev_num); +dev_alloc_err: + return -ENODEV; +} + +static void wlan_hdd_state_ctrl_param_destroy(void) +{ + cdev_del(&wlan_hdd_state_cdev); + device_destroy(class, device); + class_destroy(class); + unregister_chrdev_region(device, dev_num); + + pr_info("Device node unregistered"); +} + +/** + * __hdd_module_init - Module init helper + * + * Module init helper function used by both module and static driver. + * + * Return: 0 for success, errno on failure + */ +static int __hdd_module_init(void) +{ + int ret = 0; + unsigned long rc; + + pr_err("%s: Loading driver v%s\n", WLAN_MODULE_NAME, + QWLAN_VERSIONSTR TIMER_MANAGER_STR MEMORY_DEBUG_STR); + + ret = wlan_hdd_state_ctrl_param_create(); + if (ret) { + pr_err("wlan_hdd_state_create:%x\n", ret); + goto err_dev_state; + } + + pld_init(); + + ret = hdd_init(); + if (ret) { + pr_err("hdd_init failed %x\n", ret); + goto err_hdd_init; + } + + qdf_wake_lock_create(&wlan_wake_lock, "wlan"); + + hdd_set_conparam((uint32_t) con_mode); + + init_completion(&wlan_start_comp); + ret = wlan_hdd_register_driver(); + if (ret) { + pr_err("%s: driver load failure, err %d\n", WLAN_MODULE_NAME, + ret); + goto out; + } + /* + * This wait is temporarily introduced till + * boardconfig changes for dev node are merged + */ + rc = wait_for_completion_timeout(&wlan_start_comp, + msecs_to_jiffies(HDD_WLAN_START_WAIT_TIME)); + if (!rc) { + hdd_alert("Timed-out waiting for wlan_hdd_register_driver"); + ret = -ETIMEDOUT; + wlan_hdd_unregister_driver(); + goto out; + } + pr_info("%s: driver loaded\n", WLAN_MODULE_NAME); + + return 0; +out: + qdf_wake_lock_destroy(&wlan_wake_lock); + hdd_deinit(); +err_hdd_init: + pld_deinit(); + wlan_hdd_state_ctrl_param_destroy(); +err_dev_state: + return ret; +} + +/** + * hdd_wait_for_recovery_completion() - Wait for cds recovery completion + * + * Block the unloading of the driver until the cds recovery is completed + * + * Return: None + */ +static void hdd_wait_for_recovery_completion(void) +{ + int retry = 0; + + /* Wait for recovery to complete */ + while (cds_is_driver_recovering()) { + hdd_alert("Recovery in progress; wait here!!!"); + msleep(1000); + if (retry++ == HDD_MOD_EXIT_SSR_MAX_RETRIES) { + hdd_alert("SSR never completed, fatal error"); + QDF_BUG(0); + } + } +} + +/** + * __hdd_module_exit - Module exit helper + * + * Module exit helper function used by both module and static driver. + */ +static void __hdd_module_exit(void) +{ + pr_info("%s: Unloading driver v%s\n", WLAN_MODULE_NAME, + QWLAN_VERSIONSTR); + + hdd_wait_for_recovery_completion(); + + wlan_hdd_unregister_driver(); + + qdf_wake_lock_destroy(&wlan_wake_lock); + + hdd_deinit(); + pld_deinit(); + wlan_hdd_state_ctrl_param_destroy(); + return; +} + +#ifndef MODULE +/** + * wlan_boot_cb() - Wlan boot callback + * @kobj: object whose directory we're creating the link in. + * @attr: attribute the user is interacting with + * @buff: the buffer containing the user data + * @count: number of bytes in the buffer + * + * This callback is invoked when the fs is ready to start the + * wlan driver initialization. + * + * Return: 'count' on success or a negative error code in case of failure + */ +static ssize_t wlan_boot_cb(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, + size_t count) +{ + + if (wlan_loader->loaded_state) { + pr_err("%s: wlan driver already initialized\n", __func__); + return -EALREADY; + } + + if (__hdd_module_init()) { + pr_err("%s: wlan driver initialization failed\n", __func__); + return -EIO; + } + + wlan_loader->loaded_state = MODULE_INITIALIZED; + + return count; + +} + +/** + * hdd_sysfs_cleanup() - cleanup sysfs + * + * Return: None + * + */ +static void hdd_sysfs_cleanup(void) +{ + + /* remove from group */ + if (wlan_loader->boot_wlan_obj && wlan_loader->attr_group) + sysfs_remove_group(wlan_loader->boot_wlan_obj, + wlan_loader->attr_group); + + /* unlink the object from parent */ + kobject_del(wlan_loader->boot_wlan_obj); + + /* free the object */ + kobject_put(wlan_loader->boot_wlan_obj); + + kfree(wlan_loader->attr_group); + kfree(wlan_loader); + + wlan_loader = NULL; +} + +/** + * wlan_init_sysfs() - Creates the sysfs to be invoked when the fs is + * ready + * + * This is creates the syfs entry boot_wlan. Which shall be invoked + * when the filesystem is ready. + * + * QDF API cannot be used here since this function is called even before + * initializing WLAN driver. + * + * Return: 0 for success, errno on failure + */ +static int wlan_init_sysfs(void) +{ + int ret = -ENOMEM; + + wlan_loader = kzalloc(sizeof(*wlan_loader), GFP_KERNEL); + if (!wlan_loader) { + pr_err("%s: memory alloc failed\n", __func__); + return -ENOMEM; + } + + wlan_loader->boot_wlan_obj = NULL; + wlan_loader->attr_group = kzalloc(sizeof(*(wlan_loader->attr_group)), + GFP_KERNEL); + if (!wlan_loader->attr_group) { + pr_err("%s: malloc attr_group failed\n", __func__); + goto error_return; + } + + wlan_loader->loaded_state = 0; + wlan_loader->attr_group->attrs = attrs; + + wlan_loader->boot_wlan_obj = kobject_create_and_add("boot_wlan", + kernel_kobj); + if (!wlan_loader->boot_wlan_obj) { + pr_err("%s: sysfs create and add failed\n", __func__); + goto error_return; + } + + ret = sysfs_create_group(wlan_loader->boot_wlan_obj, + wlan_loader->attr_group); + if (ret) { + pr_err("%s: sysfs create group failed %d\n", __func__, ret); + goto error_return; + } + + return 0; + +error_return: + hdd_sysfs_cleanup(); + + return ret; +} + +/** + * wlan_deinit_sysfs() - Removes the sysfs created to initialize the wlan + * + * Return: 0 on success or errno on failure + */ +static int wlan_deinit_sysfs(void) +{ + if (!wlan_loader) { + hdd_alert("wlan loader context is Null!"); + return -EINVAL; + } + + hdd_sysfs_cleanup(); + return 0; +} + +#endif /* MODULE */ + +#ifdef MODULE +/** + * __hdd_module_init - Module init helper + * + * Module init helper function used by both module and static driver. + * + * Return: 0 for success, errno on failure + */ +static int hdd_module_init(void) +{ + int ret = 0; + + pr_err("%s: Loading driver v%s\n", WLAN_MODULE_NAME, + QWLAN_VERSIONSTR TIMER_MANAGER_STR MEMORY_DEBUG_STR); + + if (__hdd_module_init()) { + pr_err("%s: Failed to register handler\n", __func__); + ret = -EINVAL; + } + + return ret; +} +#else +static int __init hdd_module_init(void) +{ + int ret = -EINVAL; + + ret = wlan_init_sysfs(); + if (ret) + pr_err("Failed to create sysfs entry for loading wlan"); + + return ret; +} +#endif + + +#ifdef MODULE +/** + * hdd_module_exit() - Exit function + * + * This is the driver exit point (invoked when module is unloaded using rmmod) + * + * Return: None + */ +static void __exit hdd_module_exit(void) +{ + __hdd_module_exit(); +} +#else +static void __exit hdd_module_exit(void) +{ + __hdd_module_exit(); + wlan_deinit_sysfs(); +} +#endif + +static int fwpath_changed_handler(const char *kmessage, struct kernel_param *kp) +{ + return param_set_copystring(kmessage, kp); +} + +/** + * is_con_mode_valid() check con mode is valid or not + * @mode: global con mode + * + * Return: TRUE on success FALSE on failure + */ +static bool is_con_mode_valid(enum tQDF_GLOBAL_CON_MODE mode) +{ + switch (mode) { + case QDF_GLOBAL_MONITOR_MODE: + case QDF_GLOBAL_FTM_MODE: + case QDF_GLOBAL_EPPING_MODE: + case QDF_GLOBAL_MISSION_MODE: + return true; + default: + return false; + } +} + +/** + * hdd_get_adpter_mode() - returns adapter mode based on global con mode + * @mode: global con mode + * + * Return: adapter mode + */ +static enum tQDF_ADAPTER_MODE hdd_get_adpter_mode( + enum tQDF_GLOBAL_CON_MODE mode) +{ + + switch (mode) { + case QDF_GLOBAL_MISSION_MODE: + return QDF_STA_MODE; + case QDF_GLOBAL_MONITOR_MODE: + return QDF_MONITOR_MODE; + case QDF_GLOBAL_EPPING_MODE: + return QDF_EPPING_MODE; + case QDF_GLOBAL_FTM_MODE: + return QDF_FTM_MODE; + case QDF_GLOBAL_QVIT_MODE: + return QDF_QVIT_MODE; + default: + return QDF_MAX_NO_OF_MODE; + } +} + +static void hdd_cleanup_present_mode(hdd_context_t *hdd_ctx, + enum tQDF_GLOBAL_CON_MODE curr_mode) +{ + int driver_status; + + driver_status = hdd_ctx->driver_status; + + switch (curr_mode) { + case QDF_GLOBAL_MISSION_MODE: + case QDF_GLOBAL_MONITOR_MODE: + case QDF_GLOBAL_FTM_MODE: + if (driver_status != DRIVER_MODULES_CLOSED) { + hdd_abort_mac_scan_all_adapters(hdd_ctx); + hdd_stop_all_adapters(hdd_ctx); + } + hdd_deinit_all_adapters(hdd_ctx, false); + hdd_close_all_adapters(hdd_ctx, false); + break; + case QDF_GLOBAL_EPPING_MODE: + epping_disable(); + epping_close(); + break; + default: + return; + } +} + +static int hdd_register_req_mode(hdd_context_t *hdd_ctx, + enum tQDF_GLOBAL_CON_MODE mode) +{ + hdd_adapter_t *adapter; + int ret = 0; + bool rtnl_held; + qdf_device_t qdf_dev = cds_get_context(QDF_MODULE_ID_QDF_DEVICE); + QDF_STATUS status; + + if (!qdf_dev) { + hdd_err("qdf device context is Null return!"); + return -EINVAL; + } + + rtnl_held = hdd_hold_rtnl_lock(); + switch (mode) { + case QDF_GLOBAL_MISSION_MODE: + ret = hdd_open_interfaces(hdd_ctx, rtnl_held); + if (ret) + hdd_alert("Failed to open interfaces: %d", ret); + break; + case QDF_GLOBAL_FTM_MODE: + adapter = hdd_open_adapter(hdd_ctx, QDF_FTM_MODE, "wlan%d", + wlan_hdd_get_intf_addr(hdd_ctx), + NET_NAME_UNKNOWN, rtnl_held); + if (adapter == NULL) + ret = -EINVAL; + break; + case QDF_GLOBAL_MONITOR_MODE: + adapter = hdd_open_adapter(hdd_ctx, QDF_MONITOR_MODE, "wlan%d", + wlan_hdd_get_intf_addr(hdd_ctx), + NET_NAME_UNKNOWN, rtnl_held); + if (adapter == NULL) + ret = -EINVAL; + break; + case QDF_GLOBAL_EPPING_MODE: + status = epping_open(); + if (status != QDF_STATUS_SUCCESS) { + hdd_err("Failed to open in eeping mode: %d", status); + ret = -EINVAL; + break; + } + ret = epping_enable(qdf_dev->dev); + if (ret) { + hdd_err("Failed to enable in epping mode : %d", ret); + epping_close(); + } + break; + default: + hdd_info("Mode not supported"); + ret = -ENOTSUPP; + break; + } + hdd_release_rtnl_lock(); + rtnl_held = false; + return ret; +} + +/** + * __con_mode_handler() - Handles module param con_mode change + * @kmessage: con mode name on which driver to be bring up + * @kp: The associated kernel parameter + * @hdd_ctx: Pointer to the global HDD context + * + * This function is invoked when user updates con mode using sys entry, + * to initialize and bring-up driver in that specific mode. + * + * Return - 0 on success and failure code on failure + */ +static int __con_mode_handler(const char *kmessage, struct kernel_param *kp, + hdd_context_t *hdd_ctx) +{ + int ret; + hdd_adapter_t *adapter; + enum tQDF_GLOBAL_CON_MODE curr_mode; + enum tQDF_ADAPTER_MODE adapter_mode; + + hdd_info("con_mode handler: %s", kmessage); + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return ret; + + cds_set_load_in_progress(true); + + ret = param_set_int(kmessage, kp); + + if (!(is_con_mode_valid(con_mode))) { + hdd_err("invlaid con_mode %d", con_mode); + ret = -EINVAL; + goto reset_flags; + } + + curr_mode = hdd_get_conparam(); + if (curr_mode == con_mode) { + hdd_err("curr mode: %d is same as user triggered mode %d", + curr_mode, con_mode); + ret = 0; + goto reset_flags; + } + + /* Cleanup present mode before switching to new mode */ + hdd_cleanup_present_mode(hdd_ctx, curr_mode); + + ret = hdd_wlan_stop_modules(hdd_ctx, true); + if (ret) { + hdd_err("Stop wlan modules failed"); + goto reset_flags; + } + + hdd_set_conparam(con_mode); + + /* Register for new con_mode & then kick_start modules again */ + ret = hdd_register_req_mode(hdd_ctx, con_mode); + if (ret) { + hdd_err("Failed to register for new mode"); + goto reset_flags; + } + + adapter_mode = hdd_get_adpter_mode(con_mode); + if (adapter_mode == QDF_MAX_NO_OF_MODE) { + hdd_err("invalid adapter"); + ret = -EINVAL; + goto reset_flags; + } + + adapter = hdd_get_adapter(hdd_ctx, adapter_mode); + if (!adapter) { + hdd_err("Failed to get adapter:%d", adapter_mode); + goto reset_flags; + } + + ret = hdd_wlan_start_modules(hdd_ctx, adapter, false); + if (ret) { + hdd_err("Start wlan modules failed: %d", ret); + goto reset_flags; + } + + if (con_mode == QDF_GLOBAL_MONITOR_MODE || + con_mode == QDF_GLOBAL_FTM_MODE) { + if (hdd_start_adapter(adapter)) { + hdd_err("Failed to start %s adapter", kmessage); + ret = -EINVAL; + goto reset_flags; + } + } + + hdd_info("Mode successfully changed to %s", kmessage); + ret = 0; + +reset_flags: + cds_set_load_in_progress(false); + return ret; +} + + +static int con_mode_handler(const char *kmessage, struct kernel_param *kp) +{ + int ret; + hdd_context_t *hdd_ctx; + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return ret; + + cds_ssr_protect(__func__); + ret = __con_mode_handler(kmessage, kp, hdd_ctx); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * hdd_get_conparam() - driver exit point + * + * This is the driver exit point (invoked when module is unloaded using rmmod) + * + * Return: enum tQDF_GLOBAL_CON_MODE + */ +enum tQDF_GLOBAL_CON_MODE hdd_get_conparam(void) +{ + return (enum tQDF_GLOBAL_CON_MODE) curr_con_mode; +} + +void hdd_set_conparam(uint32_t con_param) +{ + curr_con_mode = con_param; +} + +/** + * hdd_clean_up_pre_cac_interface() - Clean up the pre cac interface + * @hdd_ctx: HDD context + * + * Cleans up the pre cac interface, if it exists + * + * Return: None + */ +void hdd_clean_up_pre_cac_interface(hdd_context_t *hdd_ctx) +{ + uint8_t session_id; + QDF_STATUS status; + struct hdd_adapter_s *precac_adapter; + + status = wlan_sap_get_pre_cac_vdev_id(hdd_ctx->hHal, &session_id); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("failed to get pre cac vdev id"); + return; + } + + precac_adapter = hdd_get_adapter_by_vdev(hdd_ctx, session_id); + if (!precac_adapter) { + hdd_err("invalid pre cac adapater"); + return; + } + + qdf_create_work(0, &hdd_ctx->sap_pre_cac_work, + wlan_hdd_sap_pre_cac_failure, + (void *)precac_adapter); + qdf_sched_work(0, &hdd_ctx->sap_pre_cac_work); + +} + +/** + * hdd_update_ol_config - API to update ol configuration parameters + * @hdd_ctx: HDD context + * + * Return: void + */ +static void hdd_update_ol_config(hdd_context_t *hdd_ctx) +{ + struct ol_config_info cfg; + struct ol_context *ol_ctx = cds_get_context(QDF_MODULE_ID_BMI); + + if (!ol_ctx) + return; + + cfg.enable_self_recovery = hdd_ctx->config->enableSelfRecovery; + cfg.enable_uart_print = hdd_ctx->config->enablefwprint; + cfg.enable_fw_log = hdd_ctx->config->enable_fw_log; + cfg.enable_ramdump_collection = hdd_ctx->config->is_ramdump_enabled; + cfg.enable_lpass_support = hdd_lpass_is_supported(hdd_ctx); + + ol_init_ini_config(ol_ctx, &cfg); +} + +#ifdef FEATURE_RUNTIME_PM +/** + * hdd_populate_runtime_cfg() - populate runtime configuration + * @hdd_ctx: hdd context + * @cfg: pointer to the configuration memory being populated + * + * Return: void + */ +static void hdd_populate_runtime_cfg(hdd_context_t *hdd_ctx, + struct hif_config_info *cfg) +{ + cfg->enable_runtime_pm = hdd_ctx->config->runtime_pm; + cfg->runtime_pm_delay = hdd_ctx->config->runtime_pm_delay; +} +#else +static void hdd_populate_runtime_cfg(hdd_context_t *hdd_ctx, + struct hif_config_info *cfg) +{ +} +#endif + +/** + * hdd_update_hif_config - API to update HIF configuration parameters + * @hdd_ctx: HDD Context + * + * Return: void + */ +static void hdd_update_hif_config(hdd_context_t *hdd_ctx) +{ + struct hif_opaque_softc *scn = cds_get_context(QDF_MODULE_ID_HIF); + struct hif_config_info cfg; + + if (!scn) + return; + + cfg.enable_self_recovery = hdd_ctx->config->enableSelfRecovery; + hdd_populate_runtime_cfg(hdd_ctx, &cfg); + hif_init_ini_config(scn, &cfg); +} + +/** + * hdd_update_config() - Initialize driver per module ini parameters + * @hdd_ctx: HDD Context + * + * API is used to initialize all driver per module configuration parameters + * Return: 0 for success, errno for failure + */ +int hdd_update_config(hdd_context_t *hdd_ctx) +{ + int ret; + + hdd_update_ol_config(hdd_ctx); + hdd_update_hif_config(hdd_ctx); + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) + ret = hdd_update_cds_config_ftm(hdd_ctx); + else + ret = hdd_update_cds_config(hdd_ctx); + + return ret; +} + +/** + * wlan_hdd_get_dfs_mode() - get ACS DFS mode + * @mode : cfg80211 DFS mode + * + * Return: return SAP ACS DFS mode else return ACS_DFS_MODE_NONE + */ +enum sap_acs_dfs_mode wlan_hdd_get_dfs_mode(enum dfs_mode mode) +{ + switch (mode) { + case DFS_MODE_ENABLE: + return ACS_DFS_MODE_ENABLE; + break; + case DFS_MODE_DISABLE: + return ACS_DFS_MODE_DISABLE; + break; + case DFS_MODE_DEPRIORITIZE: + return ACS_DFS_MODE_DEPRIORITIZE; + break; + default: + hdd_err("ACS dfs mode is NONE"); + return ACS_DFS_MODE_NONE; + } +} + +/** + * hdd_enable_disable_ca_event() - enable/disable channel avoidance event + * @hddctx: pointer to hdd context + * @set_value: enable/disable + * + * When Host sends vendor command enable, FW will send *ONE* CA ind to + * Host(even though it is duplicate). When Host send vendor command + * disable,FW doesn't perform any action. Whenever any change in + * CA *and* WLAN is in SAP/P2P-GO mode, FW sends CA ind to host. + * + * return - 0 on success, appropriate error values on failure. + */ +int hdd_enable_disable_ca_event(hdd_context_t *hddctx, uint8_t set_value) +{ + QDF_STATUS status; + + if (0 != wlan_hdd_validate_context(hddctx)) { + return -EAGAIN; + } + + if (!hddctx->config->goptimize_chan_avoid_event) { + hdd_warn("goptimize_chan_avoid_event ini param disabled"); + return -EINVAL; + } + + status = sme_enable_disable_chanavoidind_event(hddctx->hHal, set_value); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("Failed to send chan avoid command to SME"); + return -EINVAL; + } + return 0; +} + +/** + * hdd_set_roaming_in_progress() - to set the roaming in progress flag + * @value: value to set + * + * This function will set the passed value to roaming in progress flag. + * + * Return: None + */ +void hdd_set_roaming_in_progress(bool value) +{ + hdd_context_t *hdd_ctx; + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (!hdd_ctx) { + hdd_err("HDD context is NULL"); + return; + } + + hdd_ctx->roaming_in_progress = value; + hdd_info("Roaming in Progress set to %d", value); +} + +/** + * hdd_is_roaming_in_progress() - check if roaming is in progress + * @adapter - HDD adapter + * + * Return: true if roaming is in progress for STA type, else false + */ +bool hdd_is_roaming_in_progress(hdd_adapter_t *adapter) +{ + hdd_context_t *hdd_ctx; + bool ret_status = false; + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (!hdd_ctx) { + hdd_err("HDD context is NULL"); + return ret_status; + } + hdd_info("dev mode = %d, roaming_in_progress = %d", + adapter->device_mode, hdd_ctx->roaming_in_progress); + ret_status = ((adapter->device_mode == QDF_STA_MODE) && + hdd_ctx->roaming_in_progress); + return ret_status; +} + +int hdd_get_rssi_snr_by_bssid(hdd_adapter_t *adapter, const uint8_t *bssid, + int8_t *rssi, int8_t *snr) +{ + QDF_STATUS status; + hdd_wext_state_t *wext_state = WLAN_HDD_GET_WEXT_STATE_PTR(adapter); + tCsrRoamProfile *profile = &wext_state->roamProfile; + + status = sme_get_rssi_snr_by_bssid(WLAN_HDD_GET_HAL_CTX(adapter), + profile, bssid, rssi, snr); + if (QDF_STATUS_SUCCESS != status) { + hdd_warn("sme_get_rssi_snr_by_bssid failed"); + return -EINVAL; + } + + return 0; +} + +/* Register the module init/exit functions */ +module_init(hdd_module_init); +module_exit(hdd_module_exit); + +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_AUTHOR("Qualcomm Atheros, Inc."); +MODULE_DESCRIPTION("WLAN HOST DEVICE DRIVER"); + +module_param_call(con_mode, con_mode_handler, param_get_int, &con_mode, + S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); + +module_param_call(fwpath, fwpath_changed_handler, param_get_string, &fwpath, + S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); + +module_param(enable_dfs_chan_scan, int, S_IRUSR | S_IRGRP | S_IROTH); + +module_param(enable_11d, int, S_IRUSR | S_IRGRP | S_IROTH); + +module_param(country_code, charp, S_IRUSR | S_IRGRP | S_IROTH); diff --git a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_memdump.c b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_memdump.c new file mode 100644 index 0000000000000000000000000000000000000000..c2fe17af28ffd1e19aed6ec3b39c03d76daf69eb --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_memdump.c @@ -0,0 +1,878 @@ +/* + * Copyright (c) 2016-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC : wlan_hdd_memdump.c + * + * WLAN Host Device Driver file for dumping firmware memory + * + */ + +#include +#include +#include "wlan_hdd_memdump.h" +#include +#include +#include +#include /* Necessary because we use the proc fs */ +#include /* for copy_to_user */ + +/** + * hdd_fw_dump_context - hdd firmware memory dump context + * + * @request_id: userspace assigned firmware memory dump request ID + * @response_event: firmware memory dump request wait event + */ +struct hdd_fw_dump_context { + uint32_t request_id; + struct completion response_event; +}; +static struct hdd_fw_dump_context fw_dump_context; + +/** + * memdump_cleanup_timer_cb() - Timer callback function for memory dump cleanup. + * + * @data: Callback data (used to stored HDD context) + * + * Callback function registered for memory dump cleanup VOS timer. + * + * Return: none + */ + +static void memdump_cleanup_timer_cb(void *data) +{ + int status; + hdd_context_t *hdd_ctx = data; + qdf_dma_addr_t paddr; + qdf_dma_addr_t dma_ctx = 0; + qdf_device_t qdf_ctx; + + status = wlan_hdd_validate_context(hdd_ctx); + if (status) + return; + + + if (!hdd_ctx->fw_dump_loc) { + hdd_notice("Memory dump already freed"); + return; + } + + qdf_ctx = cds_get_context(QDF_MODULE_ID_QDF_DEVICE); + if (!qdf_ctx) { + hdd_err("QDF context is NULL"); + return; + } + + paddr = hdd_ctx->dump_loc_paddr; + mutex_lock(&hdd_ctx->memdump_lock); + qdf_mem_free_consistent(qdf_ctx, qdf_ctx->dev, + FW_MEM_DUMP_SIZE, hdd_ctx->fw_dump_loc, paddr, dma_ctx); + hdd_ctx->fw_dump_loc = NULL; + hdd_ctx->memdump_in_progress = false; + mutex_unlock(&hdd_ctx->memdump_lock); + +} + +/** + * wlan_hdd_cfg80211_fw_mem_dump_cb() - Callback to receive FW memory dump + * @ctx: pointer to HDD context. + * @dump_rsp: pointer to fw dump copy complete response + * + * This is a callback function used to indicate user space about the + * availability for firmware memory dump via vendor event. + * + * Return: None + */ +void wlan_hdd_cfg80211_fw_mem_dump_cb(void *ctx, + struct fw_dump_rsp *dump_rsp) +{ + hdd_context_t *hdd_ctx = ctx; + struct hdd_fw_dump_context *context; + int status; + + status = wlan_hdd_validate_context(hdd_ctx); + if (status) + return; + + + spin_lock(&hdd_context_lock); + context = &fw_dump_context; + /* validate the response received */ + if (!dump_rsp->dump_complete || + context->request_id != dump_rsp->request_id) { + spin_unlock(&hdd_context_lock); + hdd_err("Error @ request_id: %d response_id: %d status: %d", + context->request_id, dump_rsp->request_id, + dump_rsp->dump_complete); + return; + } else { + complete(&context->response_event); + } + spin_unlock(&hdd_context_lock); + + return; +} + +/** + * wlan_hdd_send_memdump_rsp - send memory dump response to user space + * @hdd_ctx: Pointer to hdd context + * + * Return: 0 for success; non-zero for failure + */ +static int wlan_hdd_send_memdump_rsp(hdd_context_t *hdd_ctx) +{ + struct sk_buff *skb; + int status; + + status = wlan_hdd_validate_context(hdd_ctx); + if (status) + return status; + + + skb = cfg80211_vendor_cmd_alloc_reply_skb(hdd_ctx->wiphy, + NLMSG_HDRLEN + NLA_HDRLEN + sizeof(uint32_t)); + + if (!skb) { + hdd_err("cfg80211_vendor_cmd_alloc_reply_skb failed"); + return -ENOMEM; + } + + if (nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_MEMDUMP_SIZE, + FW_MEM_DUMP_SIZE)) { + hdd_err("nla put fail"); + goto nla_put_failure; + } + + cfg80211_vendor_cmd_reply(skb); + hdd_notice("Memdump event sent successfully to user space"); + return 0; + +nla_put_failure: + kfree_skb(skb); + return -EINVAL; +} + +/** + * __wlan_hdd_cfg80211_get_fw_mem_dump() - Get FW memory dump + * @wiphy: pointer to wireless wiphy structure. + * @wdev: pointer to wireless_dev structure. + * @data: Pointer to the NL data. + * @data_len:Length of @data + * + * This is called when wlan driver needs to get the firmware memory dump + * via vendor specific command. + * + * Return: 0 on success, error number otherwise. + */ +static int __wlan_hdd_cfg80211_get_fw_mem_dump(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + int status; + QDF_STATUS sme_status; + hdd_context_t *hdd_ctx = wiphy_priv(wiphy); + struct fw_dump_req fw_mem_dump_req; + struct fw_dump_seg_req *seg_req; + uint8_t loop; + qdf_dma_addr_t paddr; + qdf_dma_addr_t dma_ctx = 0; + qdf_device_t qdf_ctx; + unsigned long rc; + struct hdd_fw_dump_context *context; + + ENTER_DEV(wdev->netdev); + + status = wlan_hdd_validate_context(hdd_ctx); + if (status) + return status; + + if (!hdd_ctx->fw_mem_dump_enabled) { + hdd_notice("FW memory dump not supported by this FW"); + return -ENOTSUPP; + } + qdf_ctx = cds_get_context(QDF_MODULE_ID_QDF_DEVICE); + if (!qdf_ctx) { + hdd_err("QDF context is NULL"); + return -EINVAL; + } + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("memdump not supported in FTM mode"); + return -EINVAL; + } + if (hdd_ctx->memdump_in_progress) { + hdd_err("Already a memdump req in progress."); + return -EBUSY; + } + + /* + * Allocate memory for fw memory dump. Memory allocated should be + * contiguous. Physical address of the allocated memory is passed + * to the FW for copy + * + * Reuse the memory if available. + */ + mutex_lock(&hdd_ctx->memdump_lock); + if (!hdd_ctx->fw_dump_loc) { + hdd_ctx->fw_dump_loc = qdf_mem_alloc_consistent( + qdf_ctx, qdf_ctx->dev, FW_MEM_DUMP_SIZE, &paddr); + if (!hdd_ctx->fw_dump_loc) { + mutex_unlock(&hdd_ctx->memdump_lock); + hdd_err("qdf_mem_alloc_consistent failed"); + return -ENOMEM; + } + hdd_ctx->dump_loc_paddr = paddr; + } else { + paddr = hdd_ctx->dump_loc_paddr; + } + mutex_unlock(&hdd_ctx->memdump_lock); + + /* + * Currently request_id and num_seg is assumed to be default(1) + * It is assumed that firmware dump requested is for DRAM section + * only + */ + + fw_mem_dump_req.request_id = FW_MEM_DUMP_REQ_ID; + fw_mem_dump_req.num_seg = FW_MEM_DUMP_NUM_SEG; + + hdd_notice("request_id:%d num_seg:%d", + fw_mem_dump_req.request_id, fw_mem_dump_req.num_seg); + seg_req = (struct fw_dump_seg_req *) fw_mem_dump_req.segment; + for (loop = 0; loop < fw_mem_dump_req.num_seg; loop++) { + seg_req->seg_id = 1; + seg_req->seg_start_addr_lo = FW_DRAM_LOCATION; + seg_req->seg_start_addr_hi = 0; + seg_req->seg_length = FW_MEM_DUMP_SIZE; + seg_req->dst_addr_lo = hdd_ctx->dump_loc_paddr; + seg_req->dst_addr_hi = 0; + hdd_notice("seg_number:%d", loop); + hdd_notice("seg_id:%d start_addr_lo:0x%x start_addr_hi:0x%x", + seg_req->seg_id, seg_req->seg_start_addr_lo, + seg_req->seg_start_addr_hi); + hdd_notice("seg_length:%d dst_addr_lo:0x%x dst_addr_hi:0x%x", + seg_req->seg_length, seg_req->dst_addr_lo, + seg_req->dst_addr_hi); + seg_req++; + } + + /** + * Start the cleanup timer. + * Memory allocated for this request will be freed up + * once the timer expires. Memory dump request is expected to be + * completed by this time. + * + * User space will not be able to access the dump after this time. + * New request should be issued to get the dump again. + */ + qdf_mc_timer_start(&hdd_ctx->memdump_cleanup_timer, + MEMDUMP_COMPLETION_TIME_MS); + hdd_ctx->memdump_in_progress = true; + + spin_lock(&hdd_context_lock); + context = &fw_dump_context; + context->request_id = fw_mem_dump_req.request_id; + INIT_COMPLETION(context->response_event); + spin_unlock(&hdd_context_lock); + + sme_status = sme_fw_mem_dump(hdd_ctx->hHal, &fw_mem_dump_req); + if (QDF_STATUS_SUCCESS != sme_status) { + hdd_err("sme_fw_mem_dump Failed"); + mutex_lock(&hdd_ctx->memdump_lock); + qdf_mem_free_consistent(qdf_ctx, qdf_ctx->dev, + FW_MEM_DUMP_SIZE, hdd_ctx->fw_dump_loc, paddr, dma_ctx); + hdd_ctx->fw_dump_loc = NULL; + mutex_unlock(&hdd_ctx->memdump_lock); + hdd_ctx->memdump_in_progress = false; + if (QDF_TIMER_STATE_RUNNING == + qdf_mc_timer_get_current_state( + &hdd_ctx->memdump_cleanup_timer)) { + qdf_mc_timer_stop(&hdd_ctx->memdump_cleanup_timer); + } + return -EINVAL; + } + + rc = wait_for_completion_timeout(&context->response_event, + msecs_to_jiffies(MEMDUMP_COMPLETION_TIME_MS)); + if (!rc) { + hdd_err("Target response timed out for request_id: %d", + context->request_id); + return -ETIMEDOUT; + } + + status = wlan_hdd_send_memdump_rsp(hdd_ctx); + if (status) + hdd_err("Failed to send FW memory dump rsp to user space"); + + return status; +} + +/** + * wlan_hdd_cfg80211_get_fw_mem_dump() - Get FW memory dump + * @wiphy: pointer to wireless wiphy structure. + * @wdev: pointer to wireless_dev structure. + * @data: Pointer to the NL data. + * @data_len:Length of @data + * + * This is called when wlan driver needs to get the firmware memory dump + * via vendor specific command. + * + * Return: 0 on success, error number otherwise. + */ +int wlan_hdd_cfg80211_get_fw_mem_dump(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_get_fw_mem_dump(wiphy, wdev, data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +#define PROCFS_MEMDUMP_DIR "debug" +#define PROCFS_MEMDUMP_NAME "fwdump" +#define PROCFS_MEMDUMP_PERM 0444 + +static struct proc_dir_entry *proc_file, *proc_dir; + +/** memdump_get_file_data() - get data available in proc file + * + * @file - handle for the proc file. + * + * This function is used to retrieve the data passed while + * creating proc file entry. + * + * Return: void pointer to hdd_context + */ +static void *memdump_get_file_data(struct file *file) +{ + void *hdd_ctx; + + hdd_ctx = PDE_DATA(file_inode(file)); + return hdd_ctx; +} + +/** + * memdump_read() - perform read operation in memory dump proc file + * + * @file - handle for the proc file. + * @buf - pointer to user space buffer. + * @count - number of bytes to be read. + * @pos - offset in the from buffer. + * + * This function performs read operation for the memory dump proc file. + * + * Return: number of bytes read on success, error code otherwise. + */ +static ssize_t memdump_read(struct file *file, char __user *buf, + size_t count, loff_t *pos) +{ + int status; + hdd_context_t *hdd_ctx; + qdf_dma_addr_t paddr; + qdf_dma_addr_t dma_ctx = 0; + qdf_device_t qdf_ctx; + + hdd_ctx = memdump_get_file_data(file); + + hdd_notice("Read req for size:%zu pos:%llu", count, *pos); + status = wlan_hdd_validate_context(hdd_ctx); + if (status) + return status; + + qdf_ctx = cds_get_context(QDF_MODULE_ID_QDF_DEVICE); + if (!qdf_ctx) { + hdd_err("QDF context is NULL"); + return -EINVAL; + } + + mutex_lock(&hdd_ctx->memdump_lock); + + if (!hdd_ctx->memdump_in_progress) { + hdd_err("Current mem dump request timed out/failed"); + status = -EINVAL; + goto memdump_read_fail; + } + + if (*pos < 0) { + hdd_err("Invalid start offset for memdump read"); + status = -EINVAL; + goto memdump_read_fail; + } else if (*pos >= FW_MEM_DUMP_SIZE || !count) { + + hdd_warn("No more data to copy"); + status = 0; + goto memdump_read_fail; + } else if (count > FW_MEM_DUMP_SIZE - *pos) { + count = FW_MEM_DUMP_SIZE - *pos; + } + + if (!hdd_ctx->fw_dump_loc) { + hdd_err("Invalid fw mem dump location"); + status = -EINVAL; + goto memdump_read_fail; + } + + if (copy_to_user(buf, hdd_ctx->fw_dump_loc + *pos, count)) { + hdd_err("copy to user space failed"); + status = -EFAULT; + goto memdump_read_fail; + } + + /* offset(pos) should be updated here based on the copy done*/ + *pos += count; + + /* Entire FW memory dump copy completed */ + if (*pos >= FW_MEM_DUMP_SIZE) { + paddr = hdd_ctx->dump_loc_paddr; + + qdf_mem_free_consistent(qdf_ctx, qdf_ctx->dev, + FW_MEM_DUMP_SIZE, hdd_ctx->fw_dump_loc, paddr, dma_ctx); + hdd_ctx->fw_dump_loc = NULL; + hdd_ctx->memdump_in_progress = false; + if (QDF_TIMER_STATE_RUNNING == + qdf_mc_timer_get_current_state( + &hdd_ctx->memdump_cleanup_timer)) { + qdf_mc_timer_stop(&hdd_ctx->memdump_cleanup_timer); + } + + } + status = count; +memdump_read_fail: + mutex_unlock(&hdd_ctx->memdump_lock); + return status; +} + +/** + * struct memdump_fops - file operations for memory dump feature + * @read - read function for memory dump operation. + * + * This structure initialize the file operation handle for memory + * dump feature + */ +static const struct file_operations memdump_fops = { + read: memdump_read +}; + +/** + * memdump_procfs_init() - Initialize procfs for memory dump + * + * This function create file under proc file system to be used later for + * processing firmware memory dump + * + * Return: 0 on success, error code otherwise. + */ +static int memdump_procfs_init(void) +{ + hdd_context_t *hdd_ctx; + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (!hdd_ctx) { + hdd_err("Invalid HDD context"); + return -EINVAL; + } + + proc_dir = proc_mkdir(PROCFS_MEMDUMP_DIR, NULL); + if (proc_dir == NULL) { + remove_proc_entry(PROCFS_MEMDUMP_DIR, NULL); + pr_debug("Error: Could not initialize /proc/%s\n", + PROCFS_MEMDUMP_DIR); + return -ENOMEM; + } + + proc_file = proc_create_data(PROCFS_MEMDUMP_NAME, + PROCFS_MEMDUMP_PERM, proc_dir, + &memdump_fops, hdd_ctx); + if (proc_file == NULL) { + remove_proc_entry(PROCFS_MEMDUMP_NAME, proc_dir); + pr_debug("Error: Could not initialize /proc/%s\n", + PROCFS_MEMDUMP_NAME); + return -ENOMEM; + } + + pr_debug("/proc/%s/%s created\n", PROCFS_MEMDUMP_DIR, + PROCFS_MEMDUMP_NAME); + return 0; +} + +/** + * memdump_procfs_remove() - Remove file/dir under procfs for memory dump + * + * This function removes file/dir under proc file system that was + * processing firmware memory dump + * + * Return: None + */ +static void memdump_procfs_remove(void) +{ + remove_proc_entry(PROCFS_MEMDUMP_NAME, proc_dir); + pr_debug("/proc/%s/%s removed\n", PROCFS_MEMDUMP_DIR, + PROCFS_MEMDUMP_NAME); + remove_proc_entry(PROCFS_MEMDUMP_DIR, NULL); + pr_debug("/proc/%s removed\n", PROCFS_MEMDUMP_DIR); +} + +/** + * memdump_init() - Intialization function for memory dump feature + * + * This function creates proc file for memdump feature and registers + * HDD callback function with SME. + * + * Return - 0 on success, error otherwise + */ +int memdump_init(void) +{ + hdd_context_t *hdd_ctx; + int status = 0; + QDF_STATUS qdf_status; + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (!hdd_ctx) { + hdd_err("Invalid HDD context"); + return -EINVAL; + } + + status = memdump_procfs_init(); + if (status) { + hdd_err("Failed to create proc file"); + return status; + } + + init_completion(&fw_dump_context.response_event); + + qdf_status = qdf_mc_timer_init(&hdd_ctx->memdump_cleanup_timer, + QDF_TIMER_TYPE_SW, memdump_cleanup_timer_cb, + (void *)hdd_ctx); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + hdd_err("Failed to init memdump cleanup timer"); + return -EINVAL; + } + + mutex_init(&hdd_ctx->memdump_lock); + hdd_ctx->memdump_init_done = true; + + return 0; +} + +/** + * memdump_deinit() - De initialize memdump feature + * + * This function removes proc file created for memdump feature. + * + * Return: None + */ +void memdump_deinit(void) +{ + hdd_context_t *hdd_ctx; + qdf_dma_addr_t paddr; + qdf_dma_addr_t dma_ctx = 0; + qdf_device_t qdf_ctx; + QDF_STATUS qdf_status; + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (!hdd_ctx) { + hdd_err("Invalid HDD context"); + return; + } + + if (!hdd_ctx->memdump_init_done) { + hdd_err("MemDump not initialized"); + return; + } + hdd_ctx->memdump_init_done = false; + + qdf_ctx = cds_get_context(QDF_MODULE_ID_QDF_DEVICE); + if (!qdf_ctx) { + hdd_err("QDF context is NULL"); + return; + } + + memdump_procfs_remove(); + + mutex_lock(&hdd_ctx->memdump_lock); + if (hdd_ctx->fw_dump_loc) { + paddr = hdd_ctx->dump_loc_paddr; + qdf_mem_free_consistent(qdf_ctx, qdf_ctx->dev, + FW_MEM_DUMP_SIZE, hdd_ctx->fw_dump_loc, paddr, dma_ctx); + hdd_ctx->fw_dump_loc = NULL; + hdd_ctx->memdump_in_progress = false; + } + mutex_unlock(&hdd_ctx->memdump_lock); + mutex_destroy(&hdd_ctx->memdump_lock); + + if (QDF_TIMER_STATE_RUNNING == + qdf_mc_timer_get_current_state(&hdd_ctx->memdump_cleanup_timer)) { + qdf_mc_timer_stop(&hdd_ctx->memdump_cleanup_timer); + } + + qdf_status = qdf_mc_timer_destroy(&hdd_ctx->memdump_cleanup_timer); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) + hdd_err("Failed to deallocate timer"); +} + +#ifdef MULTI_IF_NAME +#define PROCFS_DRIVER_DUMP_DIR "debugdriver" MULTI_IF_NAME +#else +#define PROCFS_DRIVER_DUMP_DIR "debugdriver" +#endif +#define PROCFS_DRIVER_DUMP_NAME "driverdump" +#define PROCFS_DRIVER_DUMP_PERM 0444 + +static struct proc_dir_entry *proc_file_driver, *proc_dir_driver; + +/** + * hdd_driver_mem_cleanup() - Frees memory allocated for + * driver dump + * + * This function unallocates driver dump memory. + * + * Return: None + */ +static void hdd_driver_mem_cleanup(void) +{ + hdd_context_t *hdd_ctx; + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (!hdd_ctx) { + hdd_err("Invalid HDD context"); + return; + } + + if (hdd_ctx->driver_dump_mem) { + qdf_mem_free(hdd_ctx->driver_dump_mem); + hdd_ctx->driver_dump_mem = NULL; + } +} + + +/** + * hdd_driver_memdump_read() - perform read operation in driver + * memory dump proc file + * @file - handle for the proc file. + * @buf - pointer to user space buffer. + * @count - number of bytes to be read. + * @pos - offset in the from buffer. + * + * This function performs read operation for the driver memory dump proc file. + * + * Return: number of bytes read on success, error code otherwise. + */ +static ssize_t hdd_driver_memdump_read(struct file *file, char __user *buf, + size_t count, loff_t *pos) +{ + int status; + QDF_STATUS qdf_status; + hdd_context_t *hdd_ctx; + size_t no_of_bytes_read = 0; + + hdd_ctx = memdump_get_file_data(file); + + hdd_notice("Read req for size:%zu pos:%llu", count, *pos); + status = wlan_hdd_validate_context(hdd_ctx); + if (status != 0) + return -EINVAL; + + mutex_lock(&hdd_ctx->memdump_lock); + if (*pos < 0) { + hdd_err("Invalid start offset for memdump read"); + mutex_unlock(&hdd_ctx->memdump_lock); + return -EINVAL; + } else if (!count || (hdd_ctx->driver_dump_size && + (*pos >= hdd_ctx->driver_dump_size))) { + mutex_unlock(&hdd_ctx->memdump_lock); + hdd_warn("No more data to copy"); + return 0; + } else if ((*pos == 0) || (hdd_ctx->driver_dump_mem == NULL)) { + /* + * Allocate memory for Driver memory dump. + */ + if (!hdd_ctx->driver_dump_mem) { + hdd_ctx->driver_dump_mem = + qdf_mem_malloc(DRIVER_MEM_DUMP_SIZE); + if (!hdd_ctx->driver_dump_mem) { + hdd_err("qdf_mem_malloc failed"); + mutex_unlock(&hdd_ctx->memdump_lock); + return -ENOMEM; + } + } + + qdf_status = qdf_state_info_dump_all(hdd_ctx->driver_dump_mem, + DRIVER_MEM_DUMP_SIZE, + &hdd_ctx->driver_dump_size); + /* + * If qdf_status is QDF_STATUS_E_NOMEM, then memory allocated is + * insufficient to dump driver information. This print can give + * information to allocate more memory if more information from + * each layer is added in future. + */ + if (qdf_status != QDF_STATUS_SUCCESS) + hdd_err("Error in dump driver information, status %d", + qdf_status); + hdd_notice("driver_dump_size: %d", + hdd_ctx->driver_dump_size); + } + + if (count > hdd_ctx->driver_dump_size - *pos) + no_of_bytes_read = hdd_ctx->driver_dump_size - *pos; + else + no_of_bytes_read = count; + + if (copy_to_user(buf, hdd_ctx->driver_dump_mem + *pos, + no_of_bytes_read)) { + hdd_err("copy to user space failed"); + mutex_unlock(&hdd_ctx->memdump_lock); + return -EFAULT; + } + + /* offset(pos) should be updated here based on the copy done */ + *pos += no_of_bytes_read; + + /* Entire driver memory dump copy completed */ + if (*pos >= hdd_ctx->driver_dump_size) + hdd_driver_mem_cleanup(); + + mutex_unlock(&hdd_ctx->memdump_lock); + + return no_of_bytes_read; +} + + +/** + * struct driver_dump_fops - file operations for driver dump feature + * @read - read function for driver dump operation. + * + * This structure initialize the file operation handle for memory + * dump feature + */ +static const struct file_operations driver_dump_fops = { +read: hdd_driver_memdump_read +}; + +/** + * hdd_driver_memdump_procfs_init() - Initialize procfs for driver memory dump + * + * This function create file under proc file system to be used later for + * processing driver memory dump + * + * Return: 0 on success, error code otherwise. + */ +static int hdd_driver_memdump_procfs_init(void) +{ + hdd_context_t *hdd_ctx; + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (!hdd_ctx) { + hdd_err("Invalid HDD context"); + return -EINVAL; + } + + proc_dir_driver = proc_mkdir(PROCFS_DRIVER_DUMP_DIR, NULL); + if (proc_dir_driver == NULL) { + pr_debug("Error: Could not initialize /proc/%s\n", + PROCFS_DRIVER_DUMP_DIR); + return -ENOMEM; + } + + proc_file_driver = proc_create_data(PROCFS_DRIVER_DUMP_NAME, + PROCFS_DRIVER_DUMP_PERM, proc_dir_driver, + &driver_dump_fops, hdd_ctx); + if (proc_file_driver == NULL) { + remove_proc_entry(PROCFS_DRIVER_DUMP_NAME, proc_dir_driver); + pr_debug("Error: Could not initialize /proc/%s\n", + PROCFS_DRIVER_DUMP_NAME); + return -ENOMEM; + } + + pr_debug("/proc/%s/%s created\n", PROCFS_DRIVER_DUMP_DIR, + PROCFS_DRIVER_DUMP_NAME); + return 0; +} + +/** + * hdd_driver_memdump_procfs_remove() - Remove file/dir under procfs + * for driver memory dump + * + * This function removes file/dir under proc file system that was + * processing driver memory dump + * + * Return: None + */ +static void hdd_driver_memdump_procfs_remove(void) +{ + remove_proc_entry(PROCFS_DRIVER_DUMP_NAME, proc_dir_driver); + pr_debug("/proc/%s/%s removed\n", PROCFS_DRIVER_DUMP_DIR, + PROCFS_DRIVER_DUMP_NAME); + remove_proc_entry(PROCFS_DRIVER_DUMP_DIR, NULL); + pr_debug("/proc/%s removed\n", PROCFS_DRIVER_DUMP_DIR); +} + +/** + * hdd_driver_memdump_init() - Intialization function for driver + * memory dump feature + * + * This function creates proc file for driver memdump feature + * + * Return - 0 on success, error otherwise + */ +int hdd_driver_memdump_init(void) +{ + int status; + + if (hdd_get_conparam() == QDF_GLOBAL_FTM_MODE) { + hdd_err("Not initializing memdump in FTM mode"); + return -EINVAL; + } + + status = hdd_driver_memdump_procfs_init(); + if (status) { + hdd_err("Failed to create proc file"); + return status; + } + + return 0; +} + +/** + * hdd_driver_memdump_deinit() - De initialize driver memdump feature + * + * This function removes proc file created for driver memdump feature. + * + * Return: None + */ +void hdd_driver_memdump_deinit(void) +{ + if (hdd_get_conparam() == QDF_GLOBAL_FTM_MODE) { + hdd_err("Not deinitializing memdump in FTM mode"); + return; + } + + hdd_driver_memdump_procfs_remove(); + + hdd_driver_mem_cleanup(); +} diff --git a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_nan.c b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_nan.c new file mode 100644 index 0000000000000000000000000000000000000000..131a629baf6cf90308c9d1b5c8e717b1f0c0d00a --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_nan.c @@ -0,0 +1,173 @@ +/* + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/** + * DOC: wlan_hdd_nan.c + * + * WLAN Host Device Driver NAN API implementation + */ + +#include +#include +#include +#include +#include +#include "sme_api.h" +#include "nan_api.h" +#include "wlan_hdd_main.h" +#include "wlan_hdd_nan.h" + +/** + * __wlan_hdd_cfg80211_nan_request() - cfg80211 NAN request handler + * @wiphy: driver's wiphy struct + * @wdev: wireless device to which the request is targeted + * @data: actual request data (netlink-encapsulated) + * @data_len: length of @data + * + * This is called when userspace needs to send a nan request to + * firmware. The wlan host driver simply de-encapsulates the + * request from the netlink payload and then forwards it to + * firmware via SME. + * + * Return: 0 on success, negative errno on failure + */ +static int __wlan_hdd_cfg80211_nan_request(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + tNanRequestReq nan_req; + QDF_STATUS status; + int ret_val; + hdd_context_t *hdd_ctx = wiphy_priv(wiphy); + + ENTER_DEV(wdev->netdev); + + ret_val = wlan_hdd_validate_context(hdd_ctx); + if (ret_val) + return ret_val; + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + if (!hdd_ctx->config->enable_nan_support) { + hdd_err("NaN support is not enabled in INI"); + return -EPERM; + } + + nan_req.request_data_len = data_len; + nan_req.request_data = data; + + status = sme_nan_request(&nan_req); + if (QDF_STATUS_SUCCESS != status) { + ret_val = -EINVAL; + } + return ret_val; +} + +/** + * wlan_hdd_cfg80211_nan_request() - handle NAN request + * @wiphy: pointer to wireless wiphy structure. + * @wdev: pointer to wireless_dev structure. + * @data: Pointer to the data to be passed via vendor interface + * @data_len:Length of the data to be passed + * + * This function is called by userspace to send a NAN request to + * firmware. This is an SSR-protected wrapper function. + * + * Return: 0 on success, negative errno on failure + */ +int wlan_hdd_cfg80211_nan_request(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) + +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_nan_request(wiphy, wdev, data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * wlan_hdd_cfg80211_nan_callback() - cfg80211 NAN event handler + * @ctx: global HDD context + * @msg: NAN event message + * + * This is a callback function and it gets called when we need to report + * a nan event to userspace. The wlan host driver simply encapsulates the + * event into a netlink payload and then forwards it to userspace via a + * cfg80211 vendor event. + * + * Return: nothing + */ +void wlan_hdd_cfg80211_nan_callback(void *ctx, tSirNanEvent *msg) +{ + hdd_context_t *hdd_ctx = ctx; + struct sk_buff *vendor_event; + int status; + + if (NULL == msg) { + hdd_err("msg received here is null"); + return; + } + + status = wlan_hdd_validate_context(hdd_ctx); + if (status) + return; + + vendor_event = + cfg80211_vendor_event_alloc(hdd_ctx->wiphy, + NULL, + msg->event_data_len + NLMSG_HDRLEN, + QCA_NL80211_VENDOR_SUBCMD_NAN_INDEX, + GFP_KERNEL); + + if (!vendor_event) { + hdd_err("cfg80211_vendor_event_alloc failed"); + return; + } + if (nla_put(vendor_event, QCA_WLAN_VENDOR_ATTR_NAN, + msg->event_data_len, msg->event_data)) { + hdd_err("QCA_WLAN_VENDOR_ATTR_NAN put fail"); + kfree_skb(vendor_event); + return; + } + cfg80211_vendor_event(vendor_event, GFP_KERNEL); +} + +/** + * wlan_hdd_nan_is_supported() - HDD NAN support query function + * + * This function is called to determine if NAN is supported by the + * driver and by the firmware. + * + * Return: true if NAN is supported by the driver and firmware + */ +bool wlan_hdd_nan_is_supported(void) +{ + return sme_is_feature_supported_by_fw(NAN); +} diff --git a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_nan_datapath.c b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_nan_datapath.c new file mode 100644 index 0000000000000000000000000000000000000000..66a7f7a8ea7ebf5c0d049ea47a9fd60615b979a6 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_nan_datapath.c @@ -0,0 +1,2055 @@ +/* + * Copyright (c) 2016-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * 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. + */ + +/** + * DOC: wlan_hdd_nan_datapath.c + * + * WLAN Host Device Driver nan datapath API implementation + */ +#include +#include +#include +#include +#include +#include "wlan_hdd_includes.h" +#include "wlan_hdd_p2p.h" +#include "wma_api.h" +#include "wlan_hdd_assoc.h" +#include "sme_nan_datapath.h" + +/* NLA policy */ +static const struct nla_policy +qca_wlan_vendor_ndp_policy[QCA_WLAN_VENDOR_ATTR_NDP_PARAMS_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_NDP_SUBCMD] = { .type = NLA_U32 }, + [QCA_WLAN_VENDOR_ATTR_NDP_TRANSACTION_ID] = { .type = NLA_U16 }, + [QCA_WLAN_VENDOR_ATTR_NDP_IFACE_STR] = { .type = NLA_NUL_STRING, + .len = IFNAMSIZ - 1 }, + [QCA_WLAN_VENDOR_ATTR_NDP_SERVICE_INSTANCE_ID] = { .type = NLA_U32 }, + [QCA_WLAN_VENDOR_ATTR_NDP_CHANNEL] = { .type = NLA_U32 }, + [QCA_WLAN_VENDOR_ATTR_NDP_PEER_DISCOVERY_MAC_ADDR] = { + .type = NLA_BINARY, + .len = QDF_MAC_ADDR_SIZE }, + [QCA_WLAN_VENDOR_ATTR_NDP_CONFIG_SECURITY] = { .type = NLA_U16 }, + [QCA_WLAN_VENDOR_ATTR_NDP_CONFIG_QOS] = { .type = NLA_BINARY, + .len = NDP_QOS_INFO_LEN }, + [QCA_WLAN_VENDOR_ATTR_NDP_APP_INFO] = { .type = NLA_BINARY, + .len = NDP_APP_INFO_LEN }, + [QCA_WLAN_VENDOR_ATTR_NDP_INSTANCE_ID] = { .type = NLA_U32 }, + [QCA_WLAN_VENDOR_ATTR_NDP_RESPONSE_CODE] = { .type = NLA_U16 }, + [QCA_WLAN_VENDOR_ATTR_NDP_NDI_MAC_ADDR] = { .type = NLA_BINARY, + .len = QDF_MAC_ADDR_SIZE }, + [QCA_WLAN_VENDOR_ATTR_NDP_INSTANCE_ID_ARRAY] = { .type = NLA_BINARY, + .len = NDP_NUM_INSTANCE_ID }, + [QCA_WLAN_VENDOR_ATTR_NDP_DRV_RESPONSE_STATUS_TYPE] = { .type = + NLA_U32 }, + [QCA_WLAN_VENDOR_ATTR_NDP_DRV_RETURN_VALUE] = { .type = NLA_U32 }, + [QCA_WLAN_VENDOR_ATTR_NDP_CHANNEL_CONFIG] = { .type = NLA_U32 }, + [QCA_WLAN_VENDOR_ATTR_NDP_NCS_SK_TYPE] = { .type = NLA_U32 }, + [QCA_WLAN_VENDOR_ATTR_NDP_PMK] = { .type = NLA_BINARY, + .len = NDP_PMK_LEN }, + [QCA_WLAN_VENDOR_ATTR_NDP_SCID] = { .type = NLA_BINARY, + .len = NDP_SCID_BUF_LEN }, +}; + +/** + * hdd_ndp_print_ini_config()- Print nan datapath specific INI configuration + * @hdd_ctx: handle to hdd context + * + * Return: None + */ +void hdd_ndp_print_ini_config(hdd_context_t *hdd_ctx) +{ + hdd_info("Name = [%s] Value = [%u]", CFG_ENABLE_NAN_DATAPATH_NAME, + hdd_ctx->config->enable_nan_datapath); + hdd_info("Name = [%s] Value = [%u]", CFG_ENABLE_NAN_NDI_CHANNEL_NAME, + hdd_ctx->config->nan_datapath_ndi_channel); +} + +/** + * hdd_nan_datapath_target_config() - Configure NAN datapath features + * @hdd_ctx: Pointer to HDD context + * @cfg: Pointer to target device capability information + * + * NAN datapath functionality is enabled if it is enabled in + * .ini file and also supported on target device. + * + * Return: None + */ +void hdd_nan_datapath_target_config(hdd_context_t *hdd_ctx, + struct wma_tgt_cfg *cfg) +{ + hdd_ctx->nan_datapath_enabled = + hdd_ctx->config->enable_nan_datapath && + cfg->nan_datapath_enabled; + hdd_info("enable_nan_datapath: %d", hdd_ctx->nan_datapath_enabled); +} + +/** + * hdd_close_ndi() - close NAN Data interface + * @adapter: adapter context + * + * Close the adapter if start BSS fails + * + * Returns: 0 on success, negative error code otherwise + */ +static int hdd_close_ndi(hdd_adapter_t *adapter) +{ + int rc; + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + uint32_t timeout = WLAN_WAIT_TIME_SESSIONOPENCLOSE; + + ENTER(); + + /* check if the adapter is in NAN Data mode */ + if (QDF_NDI_MODE != adapter->device_mode) { + hdd_err("Interface is not in NDI mode"); + return -EINVAL; + } + wlan_hdd_netif_queue_control(adapter, + WLAN_STOP_ALL_NETIF_QUEUE_N_CARRIER, + WLAN_CONTROL_PATH); + +#ifdef WLAN_OPEN_SOURCE + cancel_work_sync(&adapter->ipv4NotifierWorkQueue); +#endif + hdd_deregister_tx_flow_control(adapter); + +#ifdef WLAN_NS_OFFLOAD +#ifdef WLAN_OPEN_SOURCE + cancel_work_sync(&adapter->ipv6NotifierWorkQueue); +#endif +#endif + /* check if the session is open */ + if (test_bit(SME_SESSION_OPENED, &adapter->event_flags)) { + INIT_COMPLETION(adapter->session_close_comp_var); + if (QDF_STATUS_SUCCESS == sme_close_session(hdd_ctx->hHal, + adapter->sessionId, + hdd_sme_close_session_callback, adapter)) { + /* Block on a timed completion variable */ + rc = wait_for_completion_timeout( + &adapter->session_close_comp_var, + msecs_to_jiffies(timeout)); + if (!rc) + hdd_err("session close timeout"); + } + } + + /* We are good to close the adapter */ + hdd_close_adapter(hdd_ctx, adapter, true); + + EXIT(); + return 0; +} + +/** + * hdd_is_ndp_allowed() - Indicates if NDP is allowed + * @hdd_ctx: hdd context + * + * NDP is not allowed with any other role active except STA. + * + * Return: true if allowed, false otherwise + */ +static bool hdd_is_ndp_allowed(hdd_context_t *hdd_ctx) +{ + hdd_adapter_t *adapter; + hdd_station_ctx_t *sta_ctx; + QDF_STATUS status; + hdd_adapter_list_node_t *curr = NULL, *next = NULL; + + status = hdd_get_front_adapter(hdd_ctx, &curr); + while (QDF_STATUS_SUCCESS == status) { + adapter = curr->pAdapter; + if (!adapter) + goto next_adapter; + + switch (adapter->device_mode) { + case QDF_P2P_GO_MODE: + case QDF_SAP_MODE: + if (test_bit(SOFTAP_BSS_STARTED, + &adapter->event_flags)) + return false; + break; + case QDF_P2P_CLIENT_MODE: + case QDF_IBSS_MODE: + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + if (hdd_conn_is_connected(sta_ctx) || + hdd_is_connecting(sta_ctx)) + return false; + break; + default: + break; + } +next_adapter: + status = hdd_get_next_adapter(hdd_ctx, curr, &next); + curr = next; + } + + return true; +} + +/** + * hdd_ndi_start_bss() - Start BSS on NAN data interface + * @adapter: adapter context + * @operating_channel: channel on which the BSS to be started + * + * Return: 0 on success, error value on failure + */ +static int hdd_ndi_start_bss(hdd_adapter_t *adapter, + uint8_t operating_channel) +{ + int ret; + uint32_t roam_id; + hdd_wext_state_t *wext_state = + WLAN_HDD_GET_WEXT_STATE_PTR(adapter); + tCsrRoamProfile *roam_profile = &wext_state->roamProfile; + + ENTER(); + + if (!roam_profile) { + hdd_err("No valid roam profile"); + return -EINVAL; + } + + if (HDD_WMM_USER_MODE_NO_QOS == + (WLAN_HDD_GET_CTX(adapter))->config->WmmMode) { + /* QoS not enabled in cfg file*/ + roam_profile->uapsd_mask = 0; + } else { + /* QoS enabled, update uapsd mask from cfg file*/ + roam_profile->uapsd_mask = + (WLAN_HDD_GET_CTX(adapter))->config->UapsdMask; + } + + roam_profile->csrPersona = adapter->device_mode; + + roam_profile->ChannelInfo.numOfChannels = 1; + if (operating_channel) { + roam_profile->ChannelInfo.ChannelList = &operating_channel; + } else { + roam_profile->ChannelInfo.ChannelList[0] = + NAN_SOCIAL_CHANNEL_2_4GHZ; + } + + roam_profile->SSIDs.numOfSSIDs = 1; + roam_profile->SSIDs.SSIDList->SSID.length = 0; + + roam_profile->phyMode = eCSR_DOT11_MODE_11ac; + roam_profile->BSSType = eCSR_BSS_TYPE_NDI; + roam_profile->BSSIDs.numOfBSSIDs = 1; + qdf_mem_copy((void *)(roam_profile->BSSIDs.bssid), + &adapter->macAddressCurrent.bytes[0], + QDF_MAC_ADDR_SIZE); + + roam_profile->AuthType.numEntries = 1; + roam_profile->AuthType.authType[0] = eCSR_AUTH_TYPE_OPEN_SYSTEM; + roam_profile->EncryptionType.numEntries = 1; + roam_profile->EncryptionType.encryptionType[0] = eCSR_ENCRYPT_TYPE_NONE; + + ret = sme_roam_connect(WLAN_HDD_GET_HAL_CTX(adapter), + adapter->sessionId, roam_profile, &roam_id); + if (QDF_STATUS_SUCCESS != ret) { + hdd_err("NDI sme_RoamConnect session %d failed with status %d -> NotConnected", + adapter->sessionId, ret); + /* change back to NotConnected */ + hdd_conn_set_connection_state(adapter, + eConnectionState_NotConnected); + } else { + hdd_info("sme_RoamConnect issued successfully for NDI"); + } + + roam_profile->ChannelInfo.ChannelList = NULL; + roam_profile->ChannelInfo.numOfChannels = 0; + + EXIT(); + + return ret; +} + + +/** + * hdd_ndi_create_req_handler() - NDI create request handler + * @hdd_ctx: hdd context + * @tb: parsed NL attribute list + * + * Return: 0 on success or error code on failure + */ +static int hdd_ndi_create_req_handler(hdd_context_t *hdd_ctx, + struct nlattr **tb) +{ + hdd_adapter_t *adapter; + char *iface_name; + uint16_t transaction_id; + int ret; + struct nan_datapath_ctx *ndp_ctx; + uint8_t op_channel = + hdd_ctx->config->nan_datapath_ndi_channel; + + ENTER(); + + if (!tb[QCA_WLAN_VENDOR_ATTR_NDP_IFACE_STR]) { + hdd_err("Interface name string is unavailable"); + return -EINVAL; + } + iface_name = nla_data(tb[QCA_WLAN_VENDOR_ATTR_NDP_IFACE_STR]); + + if (!tb[QCA_WLAN_VENDOR_ATTR_NDP_TRANSACTION_ID]) { + hdd_err("transaction id is unavailable"); + return -EINVAL; + } + transaction_id = + nla_get_u16(tb[QCA_WLAN_VENDOR_ATTR_NDP_TRANSACTION_ID]); + + /* Check for an existing interface of NDI type */ + adapter = hdd_get_adapter(hdd_ctx, QDF_NDI_MODE); + if (adapter) { + hdd_err("Cannot support more than one NDI"); + return -EEXIST; + } + + adapter = hdd_open_adapter(hdd_ctx, QDF_NDI_MODE, iface_name, + wlan_hdd_get_intf_addr(hdd_ctx), NET_NAME_UNKNOWN, + true); + if (!adapter) { + hdd_err("hdd_open_adapter failed"); + return -ENOMEM; + } + + /* + * Create transaction id is required to be saved since the firmware + * does not honor the transaction id for create request + */ + ndp_ctx = WLAN_HDD_GET_NDP_CTX_PTR(adapter); + ndp_ctx->ndp_create_transaction_id = transaction_id; + ndp_ctx->state = NAN_DATA_NDI_CREATING_STATE; + + /* + * The NAN data interface has been created at this point. + * Unlike traditional device modes, where the higher application + * layer initiates connect / join / start, the NAN data interface + * does not have any such formal requests. The NDI create request + * is responsible for starting the BSS as well. + */ + if (op_channel != NAN_SOCIAL_CHANNEL_2_4GHZ || + op_channel != NAN_SOCIAL_CHANNEL_5GHZ_LOWER_BAND || + op_channel != NAN_SOCIAL_CHANNEL_5GHZ_UPPER_BAND) { + /* start NDI on the default 2.4 GHz social channel */ + op_channel = NAN_SOCIAL_CHANNEL_2_4GHZ; + } + ret = hdd_ndi_start_bss(adapter, op_channel); + if (0 > ret) { + hdd_err("NDI start bss failed"); + /* Start BSS failed, delete the interface */ + hdd_close_ndi(adapter); + } + + EXIT(); + return ret; +} + +/** + * hdd_ndi_delete_req_handler() - NDI delete request handler + * @hdd_ctx: hdd context + * @tb: parsed NL attribute list + * + * Return: 0 on success or error code on failure + */ +static int hdd_ndi_delete_req_handler(hdd_context_t *hdd_ctx, + struct nlattr **tb) +{ + hdd_adapter_t *adapter; + char *iface_name; + uint16_t transaction_id; + struct nan_datapath_ctx *ndp_ctx; + int ret; + hdd_station_ctx_t *sta_ctx; + + ENTER(); + + if (!tb[QCA_WLAN_VENDOR_ATTR_NDP_IFACE_STR]) { + hdd_err("Interface name string is unavailable"); + return -EINVAL; + } + + iface_name = nla_data(tb[QCA_WLAN_VENDOR_ATTR_NDP_IFACE_STR]); + + if (!tb[QCA_WLAN_VENDOR_ATTR_NDP_TRANSACTION_ID]) { + hdd_err("Transaction id is unavailable"); + return -EINVAL; + } + + transaction_id = + nla_get_u16(tb[QCA_WLAN_VENDOR_ATTR_NDP_TRANSACTION_ID]); + + /* Check if there is already an existing inteface with the same name */ + adapter = hdd_get_adapter(hdd_ctx, QDF_NDI_MODE); + if (!adapter) { + hdd_err("NAN data interface %s is not available", iface_name); + return -EINVAL; + } + + /* check if adapter is in NDI mode */ + if (QDF_NDI_MODE != adapter->device_mode) { + hdd_err("Interface %s is not in NDI mode", iface_name); + return -EINVAL; + } + + ndp_ctx = WLAN_HDD_GET_NDP_CTX_PTR(adapter); + if (!ndp_ctx) { + hdd_err("ndp_ctx is NULL"); + return -EINVAL; + } + + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + if (!sta_ctx) { + hdd_err("sta_ctx is NULL"); + return -EINVAL; + } + + /* check if there are active peers on the adapter */ + if (ndp_ctx->active_ndp_peers > 0) { + hdd_err("NDP peers active: %d, cannot delete NDI", + ndp_ctx->active_ndp_peers); + return -EINVAL; + } + + /* + * Since, the interface is being deleted, remove the + * broadcast id. + */ + hdd_ctx->sta_to_adapter[sta_ctx->broadcast_staid] = 0; + sta_ctx->broadcast_staid = HDD_WLAN_INVALID_STA_ID; + + ndp_ctx->ndp_delete_transaction_id = transaction_id; + ndp_ctx->state = NAN_DATA_NDI_DELETING_STATE; + + /* Delete the interface */ + ret = __wlan_hdd_del_virtual_intf(hdd_ctx->wiphy, &adapter->wdev); + if (ret < 0) + hdd_err("NDI delete request failed"); + else + hdd_notice("NDI delete request successfully issued"); + + return ret; +} + +/** + * hdd_ndp_initiator_req_handler() - NDP initiator request handler + * @hdd_ctx: hdd context + * @tb: parsed NL attribute list + * + * tb will contain following vendor attributes: + * QCA_WLAN_VENDOR_ATTR_NDP_IFACE_STR + * QCA_WLAN_VENDOR_ATTR_NDP_TRANSACTION_ID + * QCA_WLAN_VENDOR_ATTR_NDP_CHANNEL - optional + * QCA_WLAN_VENDOR_ATTR_NDP_CHANNEL_CONFIG + * QCA_WLAN_VENDOR_ATTR_NDP_SERVICE_INSTANCE_ID + * QCA_WLAN_VENDOR_ATTR_NDP_PEER_DISCOVERY_MAC_ADDR + * QCA_WLAN_VENDOR_ATTR_NDP_APP_INFO - optional + * QCA_WLAN_VENDOR_ATTR_NDP_CONFIG_QOS - optional + * QCA_WLAN_VENDOR_ATTR_NDP_PMK - optional + * QCA_WLAN_VENDOR_ATTR_NDP_NCS_SK_TYPE - optional + * + * Return: 0 on success or error code on failure + */ +static int hdd_ndp_initiator_req_handler(hdd_context_t *hdd_ctx, + struct nlattr **tb) +{ + hdd_adapter_t *adapter; + char *iface_name; + struct ndp_initiator_req req = {0}; + QDF_STATUS status; + uint32_t ndp_qos_cfg; + tHalHandle hal = hdd_ctx->hHal; + struct nan_datapath_ctx *ndp_ctx; + + ENTER(); + + if (!tb[QCA_WLAN_VENDOR_ATTR_NDP_IFACE_STR]) { + hdd_err("Interface name string is unavailable"); + return -EINVAL; + } + + iface_name = nla_data(tb[QCA_WLAN_VENDOR_ATTR_NDP_IFACE_STR]); + /* Check for interface in NDI mode */ + adapter = hdd_get_adapter(hdd_ctx, QDF_NDI_MODE); + if (!adapter) { + hdd_err("NAN data interface %s not available", iface_name); + return -EINVAL; + } + + /* NAN data path coexists only with STA interface */ + if (false == hdd_is_ndp_allowed(hdd_ctx)) { + hdd_err("Unsupported concurrency for NAN datapath"); + return -EPERM; + } + + ndp_ctx = WLAN_HDD_GET_NDP_CTX_PTR(adapter); + + if (ndp_ctx->state == NAN_DATA_NDI_DELETED_STATE || + ndp_ctx->state == NAN_DATA_NDI_DELETING_STATE || + ndp_ctx->state == NAN_DATA_NDI_CREATING_STATE) { + hdd_err("Data request not allowed in NDI current state: %d", + ndp_ctx->state); + return -EINVAL; + } + + req.vdev_id = adapter->sessionId; + + if (!tb[QCA_WLAN_VENDOR_ATTR_NDP_TRANSACTION_ID]) { + hdd_err("Transaction ID is unavailable"); + return -EINVAL; + } + req.transaction_id = + nla_get_u16(tb[QCA_WLAN_VENDOR_ATTR_NDP_TRANSACTION_ID]); + + if (tb[QCA_WLAN_VENDOR_ATTR_NDP_CHANNEL]) + req.channel = + nla_get_u32(tb[QCA_WLAN_VENDOR_ATTR_NDP_CHANNEL]); + + if (tb[QCA_WLAN_VENDOR_ATTR_NDP_CHANNEL_CONFIG]) { + req.channel_cfg = + nla_get_u32(tb[QCA_WLAN_VENDOR_ATTR_NDP_CHANNEL_CONFIG]); + } else { + hdd_err("Channel config is unavailable"); + return -EINVAL; + } + + if (!tb[QCA_WLAN_VENDOR_ATTR_NDP_SERVICE_INSTANCE_ID]) { + hdd_err("NDP service instance ID is unavailable"); + return -EINVAL; + } + req.service_instance_id = + nla_get_u32(tb[QCA_WLAN_VENDOR_ATTR_NDP_SERVICE_INSTANCE_ID]); + + qdf_mem_copy(req.self_ndi_mac_addr.bytes, + adapter->macAddressCurrent.bytes, QDF_MAC_ADDR_SIZE); + + if (!tb[QCA_WLAN_VENDOR_ATTR_NDP_PEER_DISCOVERY_MAC_ADDR]) { + hdd_err("NDI peer discovery mac addr is unavailable"); + return -EINVAL; + } + qdf_mem_copy(req.peer_discovery_mac_addr.bytes, + nla_data(tb[QCA_WLAN_VENDOR_ATTR_NDP_PEER_DISCOVERY_MAC_ADDR]), + QDF_MAC_ADDR_SIZE); + + if (tb[QCA_WLAN_VENDOR_ATTR_NDP_APP_INFO]) { + req.ndp_info.ndp_app_info_len = + nla_len(tb[QCA_WLAN_VENDOR_ATTR_NDP_APP_INFO]); + req.ndp_info.ndp_app_info = + nla_data(tb[QCA_WLAN_VENDOR_ATTR_NDP_APP_INFO]); + } + + if (tb[QCA_WLAN_VENDOR_ATTR_NDP_CONFIG_QOS]) { + /* at present ndp config stores 4 bytes QOS info only */ + req.ndp_config.ndp_cfg_len = 4; + req.ndp_config.ndp_cfg = (uint8_t *)&ndp_qos_cfg; + ndp_qos_cfg = + nla_get_u32(tb[QCA_WLAN_VENDOR_ATTR_NDP_CONFIG_QOS]); + } + + if (tb[QCA_WLAN_VENDOR_ATTR_NDP_NCS_SK_TYPE] && + !tb[QCA_WLAN_VENDOR_ATTR_NDP_PMK]) { + hdd_err("PMK cannot be absent when CSID is present."); + return -EINVAL; + } + + if (tb[QCA_WLAN_VENDOR_ATTR_NDP_PMK]) { + req.pmk.pmk = nla_data(tb[QCA_WLAN_VENDOR_ATTR_NDP_PMK]); + req.pmk.pmk_len = nla_len(tb[QCA_WLAN_VENDOR_ATTR_NDP_PMK]); + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_HDD, + QDF_TRACE_LEVEL_DEBUG, + req.pmk.pmk, req.pmk.pmk_len); + } + + if (tb[QCA_WLAN_VENDOR_ATTR_NDP_NCS_SK_TYPE]) { + req.ncs_sk_type = + nla_get_u32(tb[QCA_WLAN_VENDOR_ATTR_NDP_NCS_SK_TYPE]); + + } + + hdd_info("vdev_id: %d, transaction_id: %d, channel: %d, service_instance_id: %d, ndp_app_info_len: %d, csid: %d, peer_discovery_mac_addr: %pM", + req.vdev_id, req.transaction_id, req.channel, + req.service_instance_id, req.ndp_info.ndp_app_info_len, + req.ncs_sk_type, req.peer_discovery_mac_addr.bytes); + status = sme_ndp_initiator_req_handler(hal, &req); + if (status != QDF_STATUS_SUCCESS) { + hdd_err("sme_ndp_initiator_req_handler failed, status: %d", + status); + return -ECOMM; + } + EXIT(); + return 0; +} + +/** + * hdd_ndp_responder_req_handler() - NDP responder request handler + * @hdd_ctx: hdd context + * @tb: parsed NL attribute list + * + * tb includes following vendor attributes: + * QCA_WLAN_VENDOR_ATTR_NDP_IFACE_STR + * QCA_WLAN_VENDOR_ATTR_NDP_TRANSACTION_ID + * QCA_WLAN_VENDOR_ATTR_NDP_INSTANCE_ID + * QCA_WLAN_VENDOR_ATTR_NDP_RESPONSE_CODE + * QCA_WLAN_VENDOR_ATTR_NDP_APP_INFO - optional + * QCA_WLAN_VENDOR_ATTR_NDP_CONFIG_QOS - optional + * QCA_WLAN_VENDOR_ATTR_NDP_PMK - optional + * QCA_WLAN_VENDOR_ATTR_NDP_NCS_SK_TYPE - optional + * + * Return: 0 on success or error code on failure + */ +static int hdd_ndp_responder_req_handler(hdd_context_t *hdd_ctx, + struct nlattr **tb) +{ + hdd_adapter_t *adapter; + char *iface_name; + struct ndp_responder_req req = {0}; + QDF_STATUS status; + int ret = 0; + struct nan_datapath_ctx *ndp_ctx; + uint32_t ndp_qos_cfg; + + ENTER(); + + if (!tb[QCA_WLAN_VENDOR_ATTR_NDP_IFACE_STR]) { + hdd_err("Interface name string is unavailable"); + return -EINVAL; + } + + iface_name = nla_data(tb[QCA_WLAN_VENDOR_ATTR_NDP_IFACE_STR]); + /* Check if there is already an existing NAN interface */ + adapter = hdd_get_adapter(hdd_ctx, QDF_NDI_MODE); + if (!adapter) { + hdd_err("NAN data interface %s not available", iface_name); + return -EINVAL; + } + + if (QDF_NDI_MODE != adapter->device_mode) { + hdd_err("Interface %s not in NDI mode", iface_name); + return -EINVAL; + } + + /* NAN data path coexists only with STA interface */ + if (!hdd_is_ndp_allowed(hdd_ctx)) { + hdd_err("Unsupported concurrency for NAN datapath"); + return -EINVAL; + } + + ndp_ctx = WLAN_HDD_GET_NDP_CTX_PTR(adapter); + + if (ndp_ctx->state == NAN_DATA_NDI_DELETED_STATE || + ndp_ctx->state == NAN_DATA_NDI_DELETING_STATE || + ndp_ctx->state == NAN_DATA_NDI_CREATING_STATE) { + hdd_err("Data request not allowed in current NDI state: %d", + ndp_ctx->state); + return -EAGAIN; + } + + req.vdev_id = adapter->sessionId; + + if (!tb[QCA_WLAN_VENDOR_ATTR_NDP_TRANSACTION_ID]) { + hdd_err("Transaction ID is unavailable"); + return -EINVAL; + } + req.transaction_id = + nla_get_u16(tb[QCA_WLAN_VENDOR_ATTR_NDP_TRANSACTION_ID]); + + if (!tb[QCA_WLAN_VENDOR_ATTR_NDP_INSTANCE_ID]) { + hdd_err("Instance ID is unavailable"); + return -EINVAL; + } + req.ndp_instance_id = + nla_get_u32(tb[QCA_WLAN_VENDOR_ATTR_NDP_INSTANCE_ID]); + + if (!tb[QCA_WLAN_VENDOR_ATTR_NDP_RESPONSE_CODE]) { + hdd_err("ndp_rsp is unavailable"); + return -EINVAL; + } + req.ndp_rsp = nla_get_u32(tb[QCA_WLAN_VENDOR_ATTR_NDP_RESPONSE_CODE]); + + if (tb[QCA_WLAN_VENDOR_ATTR_NDP_APP_INFO]) { + req.ndp_info.ndp_app_info_len = + nla_len(tb[QCA_WLAN_VENDOR_ATTR_NDP_APP_INFO]); + if (req.ndp_info.ndp_app_info_len) { + req.ndp_info.ndp_app_info = + nla_data(tb[QCA_WLAN_VENDOR_ATTR_NDP_APP_INFO]); + } + } else { + hdd_info("NDP app info is unavailable"); + } + if (tb[QCA_WLAN_VENDOR_ATTR_NDP_CONFIG_QOS]) { + /* at present ndp config stores 4 bytes QOS info only */ + req.ndp_config.ndp_cfg_len = 4; + ndp_qos_cfg = + nla_get_u32(tb[QCA_WLAN_VENDOR_ATTR_NDP_CONFIG_QOS]); + req.ndp_config.ndp_cfg = (uint8_t *)&ndp_qos_cfg; + } else { + hdd_info("NDP config data is unavailable"); + } + + if (tb[QCA_WLAN_VENDOR_ATTR_NDP_NCS_SK_TYPE] && + !tb[QCA_WLAN_VENDOR_ATTR_NDP_PMK]) { + hdd_err("PMK cannot be absent when CSID is present."); + return -EINVAL; + } + + if (tb[QCA_WLAN_VENDOR_ATTR_NDP_PMK]) { + req.pmk.pmk = nla_data(tb[QCA_WLAN_VENDOR_ATTR_NDP_PMK]); + req.pmk.pmk_len = nla_len(tb[QCA_WLAN_VENDOR_ATTR_NDP_PMK]); + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_HDD, + QDF_TRACE_LEVEL_DEBUG, + req.pmk.pmk, req.pmk.pmk_len); + } + + if (tb[QCA_WLAN_VENDOR_ATTR_NDP_NCS_SK_TYPE]) { + req.ncs_sk_type = + nla_get_u32(tb[QCA_WLAN_VENDOR_ATTR_NDP_NCS_SK_TYPE]); + + } + + hdd_info("vdev_id: %d, transaction_id: %d, ndp_rsp %d, ndp_instance_id: %d, ndp_app_info_len: %d, csid: %d", + req.vdev_id, req.transaction_id, req.ndp_rsp, + req.ndp_instance_id, req.ndp_info.ndp_app_info_len, + req.ncs_sk_type); + + status = sme_ndp_responder_req_handler(hdd_ctx->hHal, &req); + if (status != QDF_STATUS_SUCCESS) { + hdd_err("sme_ndp_initiator_req_handler failed, status: %d", + status); + ret = -EINVAL; + } + + EXIT(); + return ret; +} + +/** + * hdd_ndp_end_req_handler() - NDP end request handler + * @hdd_ctx: hdd context + * @tb: parsed NL attribute list + * + * Return: 0 on success or error code on failure + */ +static int hdd_ndp_end_req_handler(hdd_context_t *hdd_ctx, struct nlattr **tb) +{ + struct ndp_end_req req = {0}; + QDF_STATUS status; + tHalHandle hal = hdd_ctx->hHal; + + ENTER(); + + /* NAN data path coexists only with STA interface */ + if (!hdd_is_ndp_allowed(hdd_ctx)) { + hdd_err("Unsupported concurrency for NAN datapath"); + return -EINVAL; + } + + if (!tb[QCA_WLAN_VENDOR_ATTR_NDP_TRANSACTION_ID]) { + hdd_err("Transaction ID is unavailable"); + return -EINVAL; + } + req.transaction_id = + nla_get_u16(tb[QCA_WLAN_VENDOR_ATTR_NDP_TRANSACTION_ID]); + + if (!tb[QCA_WLAN_VENDOR_ATTR_NDP_INSTANCE_ID_ARRAY]) { + hdd_err("NDP instance ID array is unavailable"); + return -EINVAL; + } + + req.num_ndp_instances = + nla_len(tb[QCA_WLAN_VENDOR_ATTR_NDP_INSTANCE_ID_ARRAY]) / + sizeof(uint32_t); + if (0 >= req.num_ndp_instances) { + hdd_err("Num NDP instances is 0"); + return -EINVAL; + } + req.ndp_ids = nla_data(tb[QCA_WLAN_VENDOR_ATTR_NDP_INSTANCE_ID_ARRAY]); + + hdd_info("sending ndp_end_req to SME, transaction_id: %d", + req.transaction_id); + + status = sme_ndp_end_req_handler(hal, &req); + if (status != QDF_STATUS_SUCCESS) { + hdd_err("sme_ndp_end_req_handler failed, status: %d", + status); + return -ECOMM; + } + EXIT(); + return 0; +} + +/** + * hdd_ndp_iface_create_rsp_handler() - NDP iface create response handler + * @adapter: pointer to adapter context + * @rsp_params: response parameters + * + * The function is expected to send a response back to the user space + * even if the creation of BSS has failed + * + * Following vendor event is sent to cfg80211: + * QCA_WLAN_VENDOR_ATTR_NDP_SUBCMD = + * QCA_WLAN_VENDOR_ATTR_NDP_INTERFACE_CREATE (4 bytes) + * QCA_WLAN_VENDOR_ATTR_NDP_TRANSACTION_ID (2 bytes) + * QCA_WLAN_VENDOR_ATTR_NDP_DRV_RESPONSE_STATUS_TYPE (4 bytes) + * QCA_WLAN_VENDOR_ATTR_NDP_DRV_RETURN_VALUE + * + * Return: none + */ +static void hdd_ndp_iface_create_rsp_handler(hdd_adapter_t *adapter, + void *rsp_params) +{ + struct sk_buff *vendor_event; + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + struct ndi_create_rsp *ndi_rsp = (struct ndi_create_rsp *)rsp_params; + uint32_t data_len = (3 * sizeof(uint32_t)) + sizeof(uint16_t) + + NLMSG_HDRLEN + (4 * NLA_HDRLEN); + struct nan_datapath_ctx *ndp_ctx = WLAN_HDD_GET_NDP_CTX_PTR(adapter); + bool create_fail = false; + uint8_t create_transaction_id = 0; + uint32_t create_status = NDP_RSP_STATUS_ERROR; + uint32_t create_reason = NDP_NAN_DATA_IFACE_CREATE_FAILED; + hdd_station_ctx_t *sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + struct qdf_mac_addr bc_mac_addr = QDF_MAC_ADDR_BROADCAST_INITIALIZER; + tCsrRoamInfo roam_info = {0}; + tSirBssDescription tmp_bss_descp = {0}; + + ENTER(); + + if (wlan_hdd_validate_context(hdd_ctx)) + /* No way the driver can send response back to user space */ + return; + + if (ndi_rsp) { + create_status = ndi_rsp->status; + create_reason = ndi_rsp->reason; + } else { + hdd_err("Invalid ndi create response"); + create_fail = true; + } + + if (ndp_ctx) { + create_transaction_id = ndp_ctx->ndp_create_transaction_id; + } else { + hdd_err("ndp_ctx is NULL"); + create_fail = true; + } + + if (!sta_ctx) { + hdd_err("sta_ctx is NULL"); + create_fail = true; + } + + /* notify response to the upper layer */ + vendor_event = cfg80211_vendor_event_alloc(hdd_ctx->wiphy, + NULL, + data_len, + QCA_NL80211_VENDOR_SUBCMD_NDP_INDEX, + cds_get_gfp_flags()); + + if (!vendor_event) { + hdd_err("cfg80211_vendor_event_alloc failed"); + create_fail = true; + goto close_ndi; + } + + /* Sub vendor command */ + if (nla_put_u32(vendor_event, QCA_WLAN_VENDOR_ATTR_NDP_SUBCMD, + QCA_WLAN_VENDOR_ATTR_NDP_INTERFACE_CREATE)) { + hdd_err("QCA_WLAN_VENDOR_ATTR_NDP_SUBCMD put fail"); + goto nla_put_failure; + } + + /* Transaction id */ + if (nla_put_u16(vendor_event, QCA_WLAN_VENDOR_ATTR_NDP_TRANSACTION_ID, + create_transaction_id)) { + hdd_err("VENDOR_ATTR_NDP_TRANSACTION_ID put fail"); + goto nla_put_failure; + } + + /* Status code */ + if (nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_NDP_DRV_RESPONSE_STATUS_TYPE, + create_status)) { + hdd_err("VENDOR_ATTR_NDP_DRV_RETURN_TYPE put fail"); + goto nla_put_failure; + } + + /* Status return value */ + if (nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_NDP_DRV_RETURN_VALUE, + create_reason)) { + hdd_err("VENDOR_ATTR_NDP_DRV_RETURN_VALUE put fail"); + goto nla_put_failure; + } + + hdd_info("sub command: %d, value: %d", + QCA_NL80211_VENDOR_SUBCMD_NDP_INDEX, + QCA_WLAN_VENDOR_ATTR_NDP_INTERFACE_CREATE); + hdd_info("create transaction id: %d, value: %d", + QCA_WLAN_VENDOR_ATTR_NDP_TRANSACTION_ID, create_transaction_id); + hdd_info("status code: %d, value: %d", + QCA_WLAN_VENDOR_ATTR_NDP_DRV_RESPONSE_STATUS_TYPE, + create_status); + hdd_info("Return value: %d, value: %d", + QCA_WLAN_VENDOR_ATTR_NDP_DRV_RETURN_VALUE, create_reason); + + cfg80211_vendor_event(vendor_event, GFP_KERNEL); + + if (!create_fail && ndi_rsp->status == QDF_STATUS_SUCCESS) { + hdd_notice("NDI interface successfully created"); + ndp_ctx->ndp_create_transaction_id = 0; + ndp_ctx->state = NAN_DATA_NDI_CREATED_STATE; + wlan_hdd_netif_queue_control(adapter, + WLAN_START_ALL_NETIF_QUEUE_N_CARRIER, + WLAN_CONTROL_PATH); + } else { + hdd_err("NDI interface creation failed with reason %d", + create_reason); + } + + /* Something went wrong while starting the BSS */ + if (create_fail) + goto close_ndi; + + sta_ctx->broadcast_staid = ndi_rsp->sta_id; + hdd_save_peer(sta_ctx, sta_ctx->broadcast_staid, &bc_mac_addr); + hdd_roam_register_sta(adapter, &roam_info, + sta_ctx->broadcast_staid, + &bc_mac_addr, &tmp_bss_descp); + hdd_ctx->sta_to_adapter[sta_ctx->broadcast_staid] = adapter; + + + EXIT(); + return; + +nla_put_failure: + kfree_skb(vendor_event); +close_ndi: + hdd_close_ndi(adapter); + return; +} + +/** + * hdd_ndp_iface_delete_rsp_handler() - NDP iface delete response handler + * @adapter: pointer to adapter context + * @rsp_params: response parameters + * + * Return: none + */ +static void hdd_ndp_iface_delete_rsp_handler(hdd_adapter_t *adapter, + void *rsp_params) +{ + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + struct ndi_delete_rsp *ndi_rsp = rsp_params; + struct nan_datapath_ctx *ndp_ctx; + + if (wlan_hdd_validate_context(hdd_ctx)) + return; + + if (!ndi_rsp) { + hdd_err("Invalid ndi delete response"); + return; + } + + if (ndi_rsp->status == NDP_RSP_STATUS_SUCCESS) + hdd_notice("NDI BSS successfully stopped"); + else + hdd_err("NDI BSS stop failed with reason %d", ndi_rsp->reason); + + ndp_ctx = WLAN_HDD_GET_NDP_CTX_PTR(adapter); + ndp_ctx->ndi_delete_rsp_reason = ndi_rsp->reason; + ndp_ctx->ndi_delete_rsp_status = ndi_rsp->status; + wlan_hdd_netif_queue_control(adapter, + WLAN_STOP_ALL_NETIF_QUEUE_N_CARRIER, + WLAN_CONTROL_PATH); + + complete(&adapter->disconnect_comp_var); + return; +} + +/** + * hdd_ndp_session_end_handler() - NDI session termination handler + * @adapter: pointer to adapter context + * + * Following vendor event is sent to cfg80211: + * QCA_WLAN_VENDOR_ATTR_NDP_SUBCMD = + * QCA_WLAN_VENDOR_ATTR_NDP_INTERFACE_DELETE (4 bytes) + * QCA_WLAN_VENDOR_ATTR_NDP_TRANSACTION_ID (2 bytes) + * QCA_WLAN_VENDOR_ATTR_NDP_DRV_RESPONSE_STATUS_TYPE (4 bytes) + * QCA_WLAN_VENDOR_ATTR_NDP_DRV_RETURN_VALUE (4 bytes) + * + * Return: none + */ +void hdd_ndp_session_end_handler(hdd_adapter_t *adapter) +{ + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + struct sk_buff *vendor_event; + struct nan_datapath_ctx *ndp_ctx; + uint32_t data_len = sizeof(uint32_t) * (3 + sizeof(uint16_t)) + + (NLA_HDRLEN * 4) + NLMSG_HDRLEN; + + ENTER(); + + if (wlan_hdd_validate_context(hdd_ctx)) + return; + + ndp_ctx = WLAN_HDD_GET_NDP_CTX_PTR(adapter); + if (!ndp_ctx) { + hdd_err("ndp context is NULL"); + return; + } + + /* + * The virtual adapters are stopped and closed even during + * driver unload or stop, the service layer is not required + * to be informed in that case (response is not expected) + */ + if (NAN_DATA_NDI_DELETING_STATE != ndp_ctx->state) { + hdd_err("NDI interface %s deleted", adapter->dev->name); + return; + } + + /* notify response to the upper layer */ + vendor_event = cfg80211_vendor_event_alloc(hdd_ctx->wiphy, + NULL, + data_len, + QCA_NL80211_VENDOR_SUBCMD_NDP_INDEX, + GFP_KERNEL); + + if (!vendor_event) { + hdd_err("cfg80211_vendor_event_alloc failed"); + return; + } + + /* Sub vendor command goes first */ + if (nla_put_u32(vendor_event, QCA_WLAN_VENDOR_ATTR_NDP_SUBCMD, + QCA_WLAN_VENDOR_ATTR_NDP_INTERFACE_DELETE)) { + hdd_err("VENDOR_ATTR_NDP_SUBCMD put fail"); + goto failure; + } + + /* Transaction id */ + if (nla_put_u16(vendor_event, QCA_WLAN_VENDOR_ATTR_NDP_TRANSACTION_ID, + ndp_ctx->ndp_delete_transaction_id)) { + hdd_err("VENDOR_ATTR_NDP_TRANSACTION_ID put fail"); + goto failure; + } + + /* Status code */ + if (nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_NDP_DRV_RESPONSE_STATUS_TYPE, + ndp_ctx->ndi_delete_rsp_status)) { + hdd_err("VENDOR_ATTR_NDP_DRV_RETURN_TYPE put fail"); + goto failure; + } + + /* Status return value */ + if (nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_NDP_DRV_RETURN_VALUE, + ndp_ctx->ndi_delete_rsp_reason)) { + hdd_err("VENDOR_ATTR_NDP_DRV_RETURN_VALUE put fail"); + goto failure; + } + + hdd_info("sub command: %d, value: %d", QCA_WLAN_VENDOR_ATTR_NDP_SUBCMD, + QCA_WLAN_VENDOR_ATTR_NDP_INTERFACE_DELETE); + hdd_info("delete transaction id: %d, value: %d", + QCA_WLAN_VENDOR_ATTR_NDP_TRANSACTION_ID, + ndp_ctx->ndp_delete_transaction_id); + hdd_info("status code: %d, value: %d", + QCA_WLAN_VENDOR_ATTR_NDP_DRV_RESPONSE_STATUS_TYPE, + ndp_ctx->ndi_delete_rsp_status); + hdd_info("Return value: %d, value: %d", + QCA_WLAN_VENDOR_ATTR_NDP_DRV_RETURN_VALUE, + ndp_ctx->ndi_delete_rsp_reason); + + ndp_ctx->ndp_delete_transaction_id = 0; + ndp_ctx->state = NAN_DATA_NDI_DELETED_STATE; + + cfg80211_vendor_event(vendor_event, GFP_KERNEL); + + EXIT(); + return; + +failure: + kfree_skb(vendor_event); +} + + +/** + * hdd_ndp_initiator_rsp_handler() - NDP initiator response handler + * @adapter: pointer to adapter context + * @rsp_params: response parameters + * + * Following vendor event is sent to cfg80211: + * QCA_WLAN_VENDOR_ATTR_NDP_SUBCMD = + * QCA_WLAN_VENDOR_ATTR_NDP_INITIATOR_RESPONSE (4 bytes) + * QCA_WLAN_VENDOR_ATTR_NDP_TRANSACTION_ID (2 bytes) + * QCA_WLAN_VENDOR_ATTR_NDP_INSTANCE_ID (4 bytes) + * QCA_WLAN_VENDOR_ATTR_NDP_DRV_RESPONSE_STATUS_TYPE (4 bytes) + * QCA_WLAN_VENDOR_ATTR_NDP_DRV_RETURN_VALUE (4 bytes) + * + * Return: none + */ +static void hdd_ndp_initiator_rsp_handler(hdd_adapter_t *adapter, + void *rsp_params) +{ + struct sk_buff *vendor_event; + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + struct ndp_initiator_rsp *rsp = rsp_params; + uint32_t data_len = (4 * sizeof(uint32_t)) + (1 * sizeof(uint16_t)) + + NLMSG_HDRLEN + (5 * NLA_HDRLEN); + + ENTER(); + + if (!rsp) { + hdd_err("Invalid NDP Initator response"); + return; + } + + if (0 != wlan_hdd_validate_context(hdd_ctx)) + return; + + vendor_event = cfg80211_vendor_event_alloc(hdd_ctx->wiphy, NULL, + data_len, QCA_NL80211_VENDOR_SUBCMD_NDP_INDEX, + GFP_KERNEL); + if (!vendor_event) { + hdd_err("cfg80211_vendor_event_alloc failed"); + return; + } + + if (nla_put_u32(vendor_event, QCA_WLAN_VENDOR_ATTR_NDP_SUBCMD, + QCA_WLAN_VENDOR_ATTR_NDP_INITIATOR_RESPONSE)) + goto ndp_initiator_rsp_nla_failed; + + if (nla_put_u16(vendor_event, QCA_WLAN_VENDOR_ATTR_NDP_TRANSACTION_ID, + rsp->transaction_id)) + goto ndp_initiator_rsp_nla_failed; + + if (nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_NDP_INSTANCE_ID, + rsp->ndp_instance_id)) + goto ndp_initiator_rsp_nla_failed; + + if (nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_NDP_DRV_RESPONSE_STATUS_TYPE, + rsp->status)) + goto ndp_initiator_rsp_nla_failed; + + if (nla_put_u32(vendor_event, QCA_WLAN_VENDOR_ATTR_NDP_DRV_RETURN_VALUE, + rsp->reason)) + goto ndp_initiator_rsp_nla_failed; + + hdd_info("NDP Initiator rsp sent, tid:%d, instance id:%d, status:%d, reason: %d", + rsp->transaction_id, rsp->ndp_instance_id, rsp->status, + rsp->reason); + cfg80211_vendor_event(vendor_event, GFP_KERNEL); + EXIT(); + return; +ndp_initiator_rsp_nla_failed: + hdd_err("nla_put api failed"); + kfree_skb(vendor_event); + EXIT(); +} + +/** + * hdd_ndp_new_peer_ind_handler() - NDP new peer indication handler + * @adapter: pointer to adapter context + * @ind_params: indication parameters + * + * Return: none + */ +static void hdd_ndp_new_peer_ind_handler(hdd_adapter_t *adapter, + void *ind_params) +{ + struct sme_ndp_peer_ind *new_peer_ind = ind_params; + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + tSirBssDescription tmp_bss_descp = {0}; + tCsrRoamInfo roam_info = {0}; + struct nan_datapath_ctx *ndp_ctx = WLAN_HDD_GET_NDP_CTX_PTR(adapter); + hdd_station_ctx_t *sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + + ENTER(); + + if (NULL == ind_params) { + hdd_err("Invalid new NDP peer params"); + return; + } + hdd_info("session_id: %d, peer_mac: %pM, sta_id: %d", + new_peer_ind->session_id, new_peer_ind->peer_mac_addr.bytes, + new_peer_ind->sta_id); + + /* save peer in ndp ctx */ + if (false == hdd_save_peer(sta_ctx, new_peer_ind->sta_id, + &new_peer_ind->peer_mac_addr)) { + hdd_warn("Ndp peer table full. cannot save new peer"); + return; + } + + /* this function is called for each new peer */ + ndp_ctx->active_ndp_peers++; + hdd_info("vdev_id: %d, num_peers: %d", adapter->sessionId, + ndp_ctx->active_ndp_peers); + + hdd_roam_register_sta(adapter, &roam_info, new_peer_ind->sta_id, + &new_peer_ind->peer_mac_addr, &tmp_bss_descp); + hdd_ctx->sta_to_adapter[new_peer_ind->sta_id] = adapter; + /* perform following steps for first new peer ind */ + if (ndp_ctx->active_ndp_peers == 1) { + hdd_info("Set ctx connection state to connected"); + sta_ctx->conn_info.connState = eConnectionState_NdiConnected; + hdd_wmm_connect(adapter, &roam_info, eCSR_BSS_TYPE_NDI); + wlan_hdd_netif_queue_control(adapter, + WLAN_WAKE_ALL_NETIF_QUEUE, WLAN_CONTROL_PATH); + } + EXIT(); +} + +/** + * hdd_ndp_peer_departed_ind_handler() - Handle NDP peer departed indication + * @adapter: pointer to adapter context + * @ind_params: indication parameters + * + * Return: none + */ +static void hdd_ndp_peer_departed_ind_handler(hdd_adapter_t *adapter, + void *ind_params) +{ + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + struct sme_ndp_peer_ind *peer_ind = ind_params; + struct nan_datapath_ctx *ndp_ctx = WLAN_HDD_GET_NDP_CTX_PTR(adapter); + hdd_station_ctx_t *sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + + hdd_roam_deregister_sta(adapter, peer_ind->sta_id); + hdd_delete_peer(sta_ctx, peer_ind->sta_id); + hdd_ctx->sta_to_adapter[peer_ind->sta_id] = 0; + + if (--ndp_ctx->active_ndp_peers == 0) { + hdd_info("No more ndp peers."); + sta_ctx->conn_info.connState = eConnectionState_NdiDisconnected; + hdd_conn_set_connection_state(adapter, + eConnectionState_NdiDisconnected); + hdd_info("Stop netif tx queues."); + wlan_hdd_netif_queue_control(adapter, WLAN_STOP_ALL_NETIF_QUEUE, + WLAN_CONTROL_PATH); + } +} + +/** + * hdd_ndp_confirm_ind_handler() - NDP confirm indication handler + * @adapter: pointer to adapter context + * @ind_params: indication parameters + * + * Following vendor event is sent to cfg80211: + * QCA_WLAN_VENDOR_ATTR_NDP_SUBCMD = + * QCA_WLAN_VENDOR_ATTR_NDP_CONFIRM_IND (4 bytes) + * QCA_WLAN_VENDOR_ATTR_NDP_INSTANCE_ID (4 bytes) + * QCA_WLAN_VENDOR_ATTR_NDP_NDI_MAC_ADDR (6 bytes) + * QCA_WLAN_VENDOR_ATTR_NDP_IFACE_STR (IFNAMSIZ) + * QCA_WLAN_VENDOR_ATTR_NDP_APP_INFO (ndp_app_info_len size) + * QCA_WLAN_VENDOR_ATTR_NDP_RESPONSE_CODE (4 bytes) + * QCA_WLAN_VENDOR_ATTR_NDP_RETURN_VALUE (4 bytes) + * + * Return: none + */ +static void hdd_ndp_confirm_ind_handler(hdd_adapter_t *adapter, + void *ind_params) +{ + int idx; + uint32_t ndp_qos_config = 0; + struct ndp_confirm_event *ndp_confirm = ind_params; + struct sk_buff *vendor_event; + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + struct nan_datapath_ctx *ndp_ctx = WLAN_HDD_GET_NDP_CTX_PTR(adapter); + hdd_station_ctx_t *sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + uint32_t data_len; + + ENTER(); + if (!ndp_confirm) { + hdd_err("Invalid NDP Initator response"); + return; + } + + if (0 != wlan_hdd_validate_context(hdd_ctx)) + return; + + /* ndp_confirm is called each time user generated ndp req succeeds */ + idx = hdd_get_peer_idx(sta_ctx, &ndp_confirm->peer_ndi_mac_addr); + if (idx == INVALID_PEER_IDX) + hdd_warn("can't find addr: %pM in vdev_id: %d, peer table.", + &ndp_confirm->peer_ndi_mac_addr, adapter->sessionId); + else if (ndp_confirm->rsp_code == NDP_RESPONSE_ACCEPT) + ndp_ctx->active_ndp_sessions[idx]++; + + data_len = (4 * sizeof(uint32_t)) + QDF_MAC_ADDR_SIZE + IFNAMSIZ + + + NLMSG_HDRLEN + (7 * NLA_HDRLEN) + + ndp_confirm->ndp_info.ndp_app_info_len; + + if (ndp_confirm->ndp_info.ndp_app_info_len) + data_len += NLA_HDRLEN + ndp_confirm->ndp_info.ndp_app_info_len; + + vendor_event = cfg80211_vendor_event_alloc(hdd_ctx->wiphy, NULL, + data_len, QCA_NL80211_VENDOR_SUBCMD_NDP_INDEX, + GFP_KERNEL); + if (!vendor_event) { + hdd_err("cfg80211_vendor_event_alloc failed"); + return; + } + + if (nla_put_u32(vendor_event, QCA_WLAN_VENDOR_ATTR_NDP_SUBCMD, + QCA_WLAN_VENDOR_ATTR_NDP_CONFIRM_IND)) + goto ndp_confirm_nla_failed; + + if (nla_put_u32(vendor_event, QCA_WLAN_VENDOR_ATTR_NDP_INSTANCE_ID, + ndp_confirm->ndp_instance_id)) + goto ndp_confirm_nla_failed; + + if (nla_put(vendor_event, QCA_WLAN_VENDOR_ATTR_NDP_NDI_MAC_ADDR, + QDF_MAC_ADDR_SIZE, ndp_confirm->peer_ndi_mac_addr.bytes)) + goto ndp_confirm_nla_failed; + + if (nla_put(vendor_event, QCA_WLAN_VENDOR_ATTR_NDP_IFACE_STR, + IFNAMSIZ, adapter->dev->name)) + goto ndp_confirm_nla_failed; + + if (ndp_confirm->ndp_info.ndp_app_info_len && nla_put(vendor_event, + QCA_WLAN_VENDOR_ATTR_NDP_APP_INFO, + ndp_confirm->ndp_info.ndp_app_info_len, + ndp_confirm->ndp_info.ndp_app_info)) + goto ndp_confirm_nla_failed; + + if (nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_NDP_RESPONSE_CODE, + ndp_confirm->rsp_code)) + goto ndp_confirm_nla_failed; + + if (nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_NDP_DRV_RETURN_VALUE, + ndp_confirm->reason_code)) + goto ndp_confirm_nla_failed; + + cfg80211_vendor_event(vendor_event, GFP_KERNEL); + hdd_info("NDP confim sent, ndp instance id: %d, peer addr: %pM, ndp_cfg: %d, rsp_code: %d, reason_code: %d", + ndp_confirm->ndp_instance_id, + ndp_confirm->peer_ndi_mac_addr.bytes, + ndp_qos_config, ndp_confirm->rsp_code, + ndp_confirm->reason_code); + + hdd_info("NDP confim, ndp app info dump"); + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_DEBUG, + ndp_confirm->ndp_info.ndp_app_info, + ndp_confirm->ndp_info.ndp_app_info_len); + EXIT(); + return; +ndp_confirm_nla_failed: + hdd_err("nla_put api failed"); + kfree_skb(vendor_event); + EXIT(); +} + +/** + * hdd_ndp_indication_handler() - NDP indication handler + * @adapter: pointer to adapter context + * @ind_params: indication parameters + * + * Following vendor event is sent to cfg80211: + * QCA_WLAN_VENDOR_ATTR_NDP_SUBCMD = + * QCA_WLAN_VENDOR_ATTR_NDP_REQUEST_IND (4 bytes) + * QCA_WLAN_VENDOR_ATTR_NDP_IFACE_STR (IFNAMSIZ) + * QCA_WLAN_VENDOR_ATTR_NDP_SERVICE_INSTANCE_ID (4 bytes) + * QCA_WLAN_VENDOR_ATTR_NDP_NDI_MAC_ADDR (6 bytes) + * QCA_WLAN_VENDOR_ATTR_NDP_PEER_DISCOVERY_MAC_ADDR (6 bytes) + * QCA_WLAN_VENDOR_ATTR_NDP_INSTANCE_ID (4 bytes) + * QCA_WLAN_VENDOR_ATTR_NDP_APP_INFO (ndp_app_info_len size) + * QCA_WLAN_VENDOR_ATTR_NDP_CONFIG_QOS (4 bytes) + * QCA_WLAN_VENDOR_ATTR_NDP_NCS_SK_TYPE(4 bytes) + * QCA_WLAN_VENDOR_ATTR_NDP_SCID(scid_len in size) + * + * Return: none + */ +static void hdd_ndp_indication_handler(hdd_adapter_t *adapter, + void *ind_params) +{ + struct sk_buff *vendor_event; + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + struct ndp_indication_event *event = ind_params; + uint32_t ndp_qos_config; + struct nan_datapath_ctx *ndp_ctx; + uint16_t data_len; + + ENTER(); + if (!ind_params) { + hdd_err("Invalid NDP Indication"); + return; + } + + if (0 != wlan_hdd_validate_context(hdd_ctx)) + return; + + /* Handle only if adapter is in NDI mode */ + if (QDF_NDI_MODE != adapter->device_mode) { + hdd_err("Adapter is not in NDI mode"); + return; + } + + hdd_info("NDP Indication, policy: %d", event->policy); + + /* Policy check */ + if (!WLAN_HDD_IS_NDP_ENABLED(hdd_ctx)) { + hdd_err("NAN datapath is not suported"); + return; + } + + /* NAN data path coexists only with STA interface */ + if (!hdd_is_ndp_allowed(hdd_ctx)) { + hdd_err("Unsupported concurrency for NAN datapath"); + return; + } + + ndp_ctx = WLAN_HDD_GET_NDP_CTX_PTR(adapter); + + /* check if we are in middle of deleting/creating the interface */ + if (ndp_ctx->state == NAN_DATA_NDI_DELETED_STATE || + ndp_ctx->state == NAN_DATA_NDI_DELETING_STATE || + ndp_ctx->state == NAN_DATA_NDI_CREATING_STATE) { + hdd_err("Data request not allowed in current NDI state: %d", + ndp_ctx->state); + return; + } + + data_len = (5 * sizeof(uint32_t)) + (2 * QDF_MAC_ADDR_SIZE) + IFNAMSIZ + + event->ndp_info.ndp_app_info_len + event->scid.scid_len + + (10 * NLA_HDRLEN) + NLMSG_HDRLEN; + + /* notify response to the upper layer */ + vendor_event = cfg80211_vendor_event_alloc(hdd_ctx->wiphy, + NULL, data_len, + QCA_NL80211_VENDOR_SUBCMD_NDP_INDEX, + GFP_KERNEL); + if (!vendor_event) { + hdd_err("cfg80211_vendor_event_alloc failed"); + return; + } + + if (nla_put_u32(vendor_event, QCA_WLAN_VENDOR_ATTR_NDP_SUBCMD, + QCA_WLAN_VENDOR_ATTR_NDP_REQUEST_IND)) + goto ndp_indication_nla_failed; + + if (nla_put(vendor_event, QCA_WLAN_VENDOR_ATTR_NDP_IFACE_STR, + IFNAMSIZ, adapter->dev->name)) + goto ndp_indication_nla_failed; + + if (nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_NDP_SERVICE_INSTANCE_ID, + event->service_instance_id)) + goto ndp_indication_nla_failed; + + if (nla_put(vendor_event, + QCA_WLAN_VENDOR_ATTR_NDP_NDI_MAC_ADDR, + QDF_MAC_ADDR_SIZE, event->peer_mac_addr.bytes)) + goto ndp_indication_nla_failed; + + if (nla_put(vendor_event, + QCA_WLAN_VENDOR_ATTR_NDP_PEER_DISCOVERY_MAC_ADDR, + QDF_MAC_ADDR_SIZE, event->peer_discovery_mac_addr.bytes)) + goto ndp_indication_nla_failed; + + if (nla_put_u32(vendor_event, QCA_WLAN_VENDOR_ATTR_NDP_INSTANCE_ID, + event->ndp_instance_id)) + goto ndp_indication_nla_failed; + + if (event->ndp_info.ndp_app_info_len) + if (nla_put(vendor_event, QCA_WLAN_VENDOR_ATTR_NDP_APP_INFO, + event->ndp_info.ndp_app_info_len, + event->ndp_info.ndp_app_info)) + goto ndp_indication_nla_failed; + + if (event->ndp_config.ndp_cfg_len) { + ndp_qos_config = *((uint32_t *)event->ndp_config.ndp_cfg); + /* at present ndp config stores 4 bytes QOS info only */ + if (nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_NDP_CONFIG_QOS, + ndp_qos_config)) + goto ndp_indication_nla_failed; + } + + if (event->scid.scid_len) { + if (nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_NDP_NCS_SK_TYPE, + event->ncs_sk_type)) + goto ndp_indication_nla_failed; + + if (nla_put(vendor_event, QCA_WLAN_VENDOR_ATTR_NDP_SCID, + event->scid.scid_len, + event->scid.scid)) + goto ndp_indication_nla_failed; + + hdd_info("csid: %d, scid_len: %d", + event->ncs_sk_type, event->scid.scid_len); + + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_DEBUG, + event->scid.scid, event->scid.scid_len); + } + + cfg80211_vendor_event(vendor_event, GFP_KERNEL); + EXIT(); + return; +ndp_indication_nla_failed: + hdd_err("nla_put api failed"); + kfree_skb(vendor_event); + EXIT(); +} + +/** + * hdd_ndp_responder_rsp_handler() - NDP responder response handler + * @adapter: pointer to adapter context + * @rsp_params: response parameters + * + * Following vendor event is sent to cfg80211: + * QCA_WLAN_VENDOR_ATTR_NDP_SUBCMD = + * QCA_WLAN_VENDOR_ATTR_NDP_RESPONDER_RESPONSE (4 bytes) + * QCA_WLAN_VENDOR_ATTR_NDP_TRANSACTION_ID (2 bytes) + * QCA_WLAN_VENDOR_ATTR_NDP_DRV_RESPONSE_STATUS_TYPE (4 bytes) + * QCA_WLAN_VENDOR_ATTR_NDP_DRV_RETURN_VALUE (4 bytes) + * + * Return: none + */ +static void hdd_ndp_responder_rsp_handler(hdd_adapter_t *adapter, + void *rsp_params) +{ + struct sk_buff *vendor_event; + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + struct ndp_responder_rsp_event *rsp = rsp_params; + uint16_t data_len; + + ENTER(); + if (!rsp) { + hdd_err("Invalid NDP Responder response"); + return; + } + + if (0 != wlan_hdd_validate_context(hdd_ctx)) + return; + + hdd_info("NDP Responder,vdev id %d transaction_id %d status code: %d reason %d", + rsp->vdev_id, rsp->transaction_id, + rsp->status, rsp->reason); + + data_len = 3 * sizeof(uint32_t) + sizeof(uint16_t) + + 4 * NLA_HDRLEN + NLMSG_HDRLEN; + /* notify response to the upper layer */ + vendor_event = cfg80211_vendor_event_alloc(hdd_ctx->wiphy, + NULL, data_len, + QCA_NL80211_VENDOR_SUBCMD_NDP_INDEX, + GFP_KERNEL); + if (!vendor_event) { + hdd_err("cfg80211_vendor_event_alloc failed"); + return; + } + + if (nla_put_u32(vendor_event, QCA_WLAN_VENDOR_ATTR_NDP_SUBCMD, + QCA_WLAN_VENDOR_ATTR_NDP_RESPONDER_RESPONSE)) + goto ndp_responder_rsp_nla_failed; + + if (nla_put_u16(vendor_event, QCA_WLAN_VENDOR_ATTR_NDP_TRANSACTION_ID, + rsp->transaction_id)) + goto ndp_responder_rsp_nla_failed; + + if (nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_NDP_DRV_RESPONSE_STATUS_TYPE, + rsp->status)) + goto ndp_responder_rsp_nla_failed; + + if (nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_NDP_DRV_RETURN_VALUE, + rsp->reason)) + goto ndp_responder_rsp_nla_failed; + + cfg80211_vendor_event(vendor_event, GFP_KERNEL); + EXIT(); + return; +ndp_responder_rsp_nla_failed: + hdd_err("nla_put api failed"); + kfree_skb(vendor_event); + EXIT(); +} + +/** + * hdd_ndp_end_rsp_handler() - NDP end response handler + * @adapter: pointer to adapter context + * @rsp_params: response parameters + * + * Following vendor event is sent to cfg80211: + * QCA_WLAN_VENDOR_ATTR_NDP_SUBCMD = + * QCA_WLAN_VENDOR_ATTR_NDP_END_RESPONSE(4 bytest) + * QCA_WLAN_VENDOR_ATTR_NDP_DRV_RESPONSE_STATUS_TYPE (4 bytes) + * QCA_WLAN_VENDOR_ATTR_NDP_DRV_RETURN_VALUE (4 bytes) + * QCA_WLAN_VENDOR_ATTR_NDP_TRANSACTION_ID (2 bytes) + * + * Return: none + */ +static void hdd_ndp_end_rsp_handler(hdd_adapter_t *adapter, void *rsp_params) +{ + struct sk_buff *vendor_event; + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + struct ndp_end_rsp_event *rsp = rsp_params; + uint32_t data_len; + + ENTER(); + + if (!rsp) { + hdd_err("Invalid ndp end response"); + return; + } + + if (0 != wlan_hdd_validate_context(hdd_ctx)) + return; + + data_len = NLMSG_HDRLEN + (4 * NLA_HDRLEN) + (3 * sizeof(uint32_t)) + + sizeof(uint16_t); + + vendor_event = cfg80211_vendor_event_alloc(hdd_ctx->wiphy, NULL, + data_len, QCA_NL80211_VENDOR_SUBCMD_NDP_INDEX, + GFP_KERNEL); + if (!vendor_event) { + hdd_err("cfg80211_vendor_event_alloc failed"); + return; + } + + if (nla_put_u32(vendor_event, QCA_WLAN_VENDOR_ATTR_NDP_SUBCMD, + QCA_WLAN_VENDOR_ATTR_NDP_END_RESPONSE)) + goto ndp_end_rsp_nla_failed; + + if (nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_NDP_DRV_RESPONSE_STATUS_TYPE, + rsp->status)) + goto ndp_end_rsp_nla_failed; + + if (nla_put_u32(vendor_event, QCA_WLAN_VENDOR_ATTR_NDP_DRV_RETURN_VALUE, + rsp->reason)) + goto ndp_end_rsp_nla_failed; + + if (nla_put_u16(vendor_event, QCA_WLAN_VENDOR_ATTR_NDP_TRANSACTION_ID, + rsp->transaction_id)) + goto ndp_end_rsp_nla_failed; + + hdd_info("NDP End rsp sent, transaction id: %d, status: %d, reason: %d", + rsp->transaction_id, rsp->status, rsp->reason); + cfg80211_vendor_event(vendor_event, GFP_KERNEL); + EXIT(); + return; + +ndp_end_rsp_nla_failed: + hdd_err("nla_put api failed"); + kfree_skb(vendor_event); + EXIT(); +} + +/** + * hdd_ndp_end_ind_handler() - NDP end indication handler + * @adapter: pointer to adapter context + * @ind_params: indication parameters + * + * Following vendor event is sent to cfg80211: + * QCA_WLAN_VENDOR_ATTR_NDP_SUBCMD = + * QCA_WLAN_VENDOR_ATTR_NDP_END_IND (4 bytes) + * QCA_WLAN_VENDOR_ATTR_NDP_INSTANCE_ID_ARRAY (4 * num of NDP Instances) + * + * Return: none + */ +static void hdd_ndp_end_ind_handler(hdd_adapter_t *adapter, + void *ind_params) +{ + struct sk_buff *vendor_event; + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + struct ndp_end_indication_event *end_ind = ind_params; + uint32_t data_len, i; + struct nan_datapath_ctx *ndp_ctx = WLAN_HDD_GET_NDP_CTX_PTR(adapter); + hdd_station_ctx_t *sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + uint32_t *ndp_instance_array; + hdd_adapter_t *ndi_adapter; + + ENTER(); + + if (!end_ind) { + hdd_err("Invalid ndp end indication"); + return; + } + + if (0 != wlan_hdd_validate_context(hdd_ctx)) + return; + + ndp_instance_array = qdf_mem_malloc(end_ind->num_ndp_ids * + sizeof(*ndp_instance_array)); + if (!ndp_instance_array) { + hdd_err("Failed to allocate ndp_instance_array"); + return; + } + for (i = 0; i < end_ind->num_ndp_ids; i++) { + int idx; + + ndp_instance_array[i] = end_ind->ndp_map[i].ndp_instance_id; + ndi_adapter = hdd_get_adapter_by_vdev(hdd_ctx, + end_ind->ndp_map[i].vdev_id); + if (ndi_adapter == NULL) { + hdd_warn("Adapter not found for vdev_id: %d", + end_ind->ndp_map[i].vdev_id); + continue; + } + ndp_ctx = WLAN_HDD_GET_NDP_CTX_PTR(ndi_adapter); + if (!ndp_ctx) { + hdd_warn("ndp_ctx is NULL for vdev id: %d", + end_ind->ndp_map[i].vdev_id); + continue; + } + idx = hdd_get_peer_idx(sta_ctx, + &end_ind->ndp_map[i].peer_ndi_mac_addr); + if (idx == INVALID_PEER_IDX) { + hdd_warn("can't find addr: %pM in sta_ctx.", + &end_ind->ndp_map[i].peer_ndi_mac_addr); + continue; + } + /* save the value of active sessions on each peer */ + ndp_ctx->active_ndp_sessions[idx] = + end_ind->ndp_map[i].num_active_ndp_sessions; + } + + data_len = (sizeof(uint32_t)) + NLMSG_HDRLEN + (2 * NLA_HDRLEN) + + end_ind->num_ndp_ids * sizeof(*ndp_instance_array); + + vendor_event = cfg80211_vendor_event_alloc(hdd_ctx->wiphy, NULL, + data_len, QCA_NL80211_VENDOR_SUBCMD_NDP_INDEX, + GFP_KERNEL); + if (!vendor_event) { + hdd_err("cfg80211_vendor_event_alloc failed"); + return; + } + + if (nla_put_u32(vendor_event, QCA_WLAN_VENDOR_ATTR_NDP_SUBCMD, + QCA_WLAN_VENDOR_ATTR_NDP_END_IND)) + goto ndp_end_ind_nla_failed; + + if (nla_put(vendor_event, QCA_WLAN_VENDOR_ATTR_NDP_INSTANCE_ID_ARRAY, + end_ind->num_ndp_ids * sizeof(*ndp_instance_array), + ndp_instance_array)) + goto ndp_end_ind_nla_failed; + + cfg80211_vendor_event(vendor_event, GFP_KERNEL); + qdf_mem_free(ndp_instance_array); + EXIT(); + return; + +ndp_end_ind_nla_failed: + hdd_err("nla_put api failed"); + kfree_skb(vendor_event); + qdf_mem_free(ndp_instance_array); + EXIT(); +} + +/** + * hdd_ndp_event_handler() - ndp response and indication handler + * @adapter: adapter context + * @roam_info: pointer to roam_info structure + * @roam_id: roam id as indicated by SME + * @roam_status: roam status + * @roam_result: roam result + * + * Return: none + */ +void hdd_ndp_event_handler(hdd_adapter_t *adapter, + tCsrRoamInfo *roam_info, uint32_t roam_id, eRoamCmdStatus roam_status, + eCsrRoamResult roam_result) +{ + if (roam_status == eCSR_ROAM_NDP_STATUS_UPDATE) { + switch (roam_result) { + case eCSR_ROAM_RESULT_NDI_CREATE_RSP: + hdd_ndp_iface_create_rsp_handler(adapter, + &roam_info->ndp.ndi_create_params); + break; + case eCSR_ROAM_RESULT_NDI_DELETE_RSP: + hdd_ndp_iface_delete_rsp_handler(adapter, + &roam_info->ndp.ndi_delete_params); + break; + case eCSR_ROAM_RESULT_NDP_INITIATOR_RSP: + hdd_ndp_initiator_rsp_handler(adapter, + &roam_info->ndp.ndp_init_rsp_params); + break; + case eCSR_ROAM_RESULT_NDP_NEW_PEER_IND: + hdd_ndp_new_peer_ind_handler(adapter, + &roam_info->ndp.ndp_peer_ind_params); + break; + case eCSR_ROAM_RESULT_NDP_CONFIRM_IND: + hdd_ndp_confirm_ind_handler(adapter, + &roam_info->ndp.ndp_confirm_params); + break; + case eCSR_ROAM_RESULT_NDP_INDICATION: + hdd_ndp_indication_handler(adapter, + &roam_info->ndp.ndp_indication_params); + break; + case eCSR_ROAM_RESULT_NDP_RESPONDER_RSP: + hdd_ndp_responder_rsp_handler(adapter, + &roam_info->ndp.ndp_responder_rsp_params); + break; + case eCSR_ROAM_RESULT_NDP_END_RSP: + hdd_ndp_end_rsp_handler(adapter, + roam_info->ndp.ndp_end_rsp_params); + break; + case eCSR_ROAM_RESULT_NDP_PEER_DEPARTED_IND: + hdd_ndp_peer_departed_ind_handler(adapter, + &roam_info->ndp.ndp_peer_ind_params); + break; + case eCSR_ROAM_RESULT_NDP_END_IND: + hdd_ndp_end_ind_handler(adapter, + roam_info->ndp.ndp_end_ind_params); + break; + default: + hdd_err("Unknown NDP response event from SME %d", + roam_result); + break; + } + } +} + +/** + * __wlan_hdd_cfg80211_process_ndp_cmds() - handle NDP request + * @wiphy: pointer to wireless wiphy structure. + * @wdev: pointer to wireless_dev structure. + * @data: Pointer to the data to be passed via vendor interface + * @data_len:Length of the data to be passed + * + * This function is invoked to handle vendor command + * + * Return: 0 on success, negative errno on failure + */ +static int __wlan_hdd_cfg80211_process_ndp_cmd(struct wiphy *wiphy, + struct wireless_dev *wdev, const void *data, int data_len) +{ + uint32_t ndp_cmd_type; + uint16_t transaction_id; + int ret_val; + hdd_context_t *hdd_ctx = wiphy_priv(wiphy); + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_NDP_PARAMS_MAX + 1]; + char *iface_name; + + ENTER(); + + ret_val = wlan_hdd_validate_context(hdd_ctx); + if (ret_val) + return ret_val; + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + if (!WLAN_HDD_IS_NDP_ENABLED(hdd_ctx)) { + hdd_err("NAN datapath is not enabled"); + return -EPERM; + } + if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_NDP_PARAMS_MAX, + data, data_len, + qca_wlan_vendor_ndp_policy)) { + hdd_err("Invalid NDP vendor command attributes"); + return -EINVAL; + } + + /* Parse and fetch NDP Command Type*/ + if (!tb[QCA_WLAN_VENDOR_ATTR_NDP_SUBCMD]) { + hdd_err("NAN datapath cmd type failed"); + return -EINVAL; + } + ndp_cmd_type = nla_get_u32(tb[QCA_WLAN_VENDOR_ATTR_NDP_SUBCMD]); + + if (!tb[QCA_WLAN_VENDOR_ATTR_NDP_TRANSACTION_ID]) { + hdd_err("attr transaction id failed"); + return -EINVAL; + } + transaction_id = nla_get_u16( + tb[QCA_WLAN_VENDOR_ATTR_NDP_TRANSACTION_ID]); + + if (tb[QCA_WLAN_VENDOR_ATTR_NDP_IFACE_STR]) { + iface_name = nla_data(tb[QCA_WLAN_VENDOR_ATTR_NDP_IFACE_STR]); + hdd_notice("Transaction Id: %d NDP Cmd: %d iface_name: %s", + transaction_id, ndp_cmd_type, iface_name); + } else { + hdd_notice("Transaction Id: %d NDP Cmd: %d iface_name: unspecified", + transaction_id, ndp_cmd_type); + } + + switch (ndp_cmd_type) { + case QCA_WLAN_VENDOR_ATTR_NDP_INTERFACE_CREATE: + ret_val = hdd_ndi_create_req_handler(hdd_ctx, tb); + break; + case QCA_WLAN_VENDOR_ATTR_NDP_INTERFACE_DELETE: + ret_val = hdd_ndi_delete_req_handler(hdd_ctx, tb); + break; + case QCA_WLAN_VENDOR_ATTR_NDP_INITIATOR_REQUEST: + ret_val = hdd_ndp_initiator_req_handler(hdd_ctx, tb); + break; + case QCA_WLAN_VENDOR_ATTR_NDP_RESPONDER_REQUEST: + ret_val = hdd_ndp_responder_req_handler(hdd_ctx, tb); + break; + case QCA_WLAN_VENDOR_ATTR_NDP_END_REQUEST: + ret_val = hdd_ndp_end_req_handler(hdd_ctx, tb); + break; + default: + hdd_err("Unrecognized NDP vendor cmd %d", ndp_cmd_type); + ret_val = -EINVAL; + break; + } + + return ret_val; +} + +/** + * wlan_hdd_cfg80211_process_ndp_cmd() - handle NDP request + * @wiphy: pointer to wireless wiphy structure. + * @wdev: pointer to wireless_dev structure. + * @data: Pointer to the data to be passed via vendor interface + * @data_len:Length of the data to be passed + * + * This function is called to send a NAN request to + * firmware. This is an SSR-protected wrapper function. + * + * Return: 0 on success, negative errno on failure + */ +int wlan_hdd_cfg80211_process_ndp_cmd(struct wiphy *wiphy, + struct wireless_dev *wdev, const void *data, int data_len) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_process_ndp_cmd(wiphy, wdev, data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * hdd_init_nan_data_mode() - initialize nan data mode + * @adapter: adapter context + * + * Returns: 0 on success negative error code on error + */ +int hdd_init_nan_data_mode(struct hdd_adapter_s *adapter) +{ + struct net_device *wlan_dev = adapter->dev; + struct nan_datapath_ctx *ndp_ctx = WLAN_HDD_GET_NDP_CTX_PTR(adapter); + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + QDF_STATUS status; + uint32_t type, sub_type; + int32_t ret_val = 0; + unsigned long rc; + uint32_t timeout = WLAN_WAIT_TIME_SESSIONOPENCLOSE; + + INIT_COMPLETION(adapter->session_open_comp_var); + sme_set_curr_device_mode(hdd_ctx->hHal, adapter->device_mode); + status = cds_get_vdev_types(adapter->device_mode, &type, &sub_type); + if (QDF_STATUS_SUCCESS != status) { + hdd_err("failed to get vdev type"); + goto error_sme_open; + } + + /* open sme session for future use */ + status = sme_open_session(hdd_ctx->hHal, hdd_sme_roam_callback, + adapter, (uint8_t *)&adapter->macAddressCurrent, + &adapter->sessionId, type, sub_type); + if (QDF_STATUS_SUCCESS != status) { + hdd_err("sme_open_session() failed with status code %d", + status); + ret_val = -EAGAIN; + goto error_sme_open; + } + + /* Block on a completion variable. Can't wait forever though */ + rc = wait_for_completion_timeout( + &adapter->session_open_comp_var, + msecs_to_jiffies(timeout)); + if (!rc) { + hdd_err("Failed to open session, timeout code: %ld", rc); + ret_val = -ETIMEDOUT; + goto error_sme_open; + } + + /* Register wireless extensions */ + ret_val = hdd_register_wext(wlan_dev); + if (0 > ret_val) { + hdd_err("Wext registration failed with status code %d", + ret_val); + ret_val = -EAGAIN; + goto error_register_wext; + } + + status = hdd_init_tx_rx(adapter); + if (QDF_STATUS_SUCCESS != status) { + hdd_err("hdd_init_tx_rx() init failed, status %d", status); + ret_val = -EAGAIN; + goto error_init_txrx; + } + + set_bit(INIT_TX_RX_SUCCESS, &adapter->event_flags); + + status = hdd_wmm_adapter_init(adapter); + if (QDF_STATUS_SUCCESS != status) { + hdd_err("hdd_wmm_adapter_init() failed, status %d", status); + ret_val = -EAGAIN; + goto error_wmm_init; + } + + set_bit(WMM_INIT_DONE, &adapter->event_flags); + + ret_val = wma_cli_set_command((int)adapter->sessionId, + (int)WMI_PDEV_PARAM_BURST_ENABLE, + (int)hdd_ctx->config->enableSifsBurst, + PDEV_CMD); + if (0 != ret_val) { + hdd_err("WMI_PDEV_PARAM_BURST_ENABLE set failed %d", ret_val); + } + + ndp_ctx->state = NAN_DATA_NDI_CREATING_STATE; + return ret_val; + +error_wmm_init: + clear_bit(INIT_TX_RX_SUCCESS, &adapter->event_flags); + hdd_deinit_tx_rx(adapter); + +error_init_txrx: + hdd_unregister_wext(wlan_dev); + +error_register_wext: + if (test_bit(SME_SESSION_OPENED, &adapter->event_flags)) { + INIT_COMPLETION(adapter->session_close_comp_var); + if (QDF_STATUS_SUCCESS == + sme_close_session(hdd_ctx->hHal, + adapter->sessionId, + hdd_sme_close_session_callback, + adapter)) { + rc = wait_for_completion_timeout( + &adapter->session_close_comp_var, + msecs_to_jiffies(timeout)); + if (rc <= 0) { + hdd_err("Session close failed status %ld", rc); + ret_val = -ETIMEDOUT; + } + } + } + +error_sme_open: + return ret_val; +} diff --git a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_nan_datapath.h b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_nan_datapath.h new file mode 100644 index 0000000000000000000000000000000000000000..4f29c3089ead5bd2aa9547a55b62c49b8b9256c3 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_nan_datapath.h @@ -0,0 +1,246 @@ +/* + * Copyright (c) 2016-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * 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. + */ + +/** + * DOC: wlan_hdd_nan_datapath.h + * + * WLAN Host Device Driver nan datapath API specification + */ +#ifndef __WLAN_HDD_NAN_DATAPATH_H +#define __WLAN_HDD_NAN_DATAPATH_H + +struct hdd_context_s; +struct hdd_tgt_cfg; +struct hdd_config; +struct hdd_adapter_s; +struct wireless_dev; + +/* NAN Social channels */ +#define NAN_SOCIAL_CHANNEL_2_4GHZ 6 +#define NAN_SOCIAL_CHANNEL_5GHZ_LOWER_BAND 44 +#define NAN_SOCIAL_CHANNEL_5GHZ_UPPER_BAND 149 + +#define NDP_APP_INFO_LEN 255 +#define NDP_QOS_INFO_LEN 255 +#define NDP_PMK_LEN 32 +#define NDP_SCID_BUF_LEN 256 +#define NDP_NUM_INSTANCE_ID 255 + +#define NDP_BROADCAST_STAID (0) + +#ifdef WLAN_FEATURE_NAN_DATAPATH +#define WLAN_HDD_IS_NDI(adapter) ((adapter)->device_mode == QDF_NDI_MODE) + +#define WLAN_HDD_IS_NDI_CONNECTED(adapter) ( \ + eConnectionState_NdiConnected ==\ + (adapter)->sessionCtx.station.conn_info.connState) +#else +#define WLAN_HDD_IS_NDI(adapter) (false) +#define WLAN_HDD_IS_NDI_CONNECTED(adapter) (false) +#endif /* WLAN_FEATURE_NAN_DATAPATH */ + +/** + * enum qca_wlan_vendor_attr_ndp_params - vendor attribute parameters + * @QCA_WLAN_VENDOR_ATTR_NDP_SUBCMD: NDP Sub command + * @QCA_WLAN_VENDOR_ATTR_NDP_TRANSACTION_ID: Transaction id reference + * @QCA_WLAN_VENDOR_ATTR_NDP_STATUS_ID: NDP status id + * @QCA_WLAN_VENDOR_ATTR_NDP_SERVICE_INSTANCE_ID: Service instance id + * @QCA_WLAN_VENDOR_ATTR_NDP_CHANNEL: Requested channel + * @QCA_WLAN_VENDOR_ATTR_NDP_PEER_DISCOVERY_MAC_ADDR: Peer discovery mac addr + * @QCA_WLAN_VENDOR_ATTR_NDP_IFACE_STR: Iface name + * @QCA_WLAN_VENDOR_ATTR_NDP_CONFIG_SECURITY: Security configuration + * @QCA_WLAN_VENDOR_ATTR_NDP_CONFIG_QOS: Qos configuration + * @QCA_WLAN_VENDOR_ATTR_NDP_APP_INFO: Application info + * @QCA_WLAN_VENDOR_ATTR_NDP_INSTANCE_ID: NDP instance id + * @QCA_WLAN_VENDOR_ATTR_NDP_INSTANCE_ID_ARRAY: NDP instance id array + * @QCA_WLAN_VENDOR_ATTR_NDP_RESPONSE_CODE: Schedule response + * @QCA_WLAN_VENDOR_ATTR_NDP_NDI_MAC_ADDR: NDI mac address + * @QCA_WLAN_VENDOR_ATTR_NDP_DRV_RESPONSE_STATUS_TYPE: Driver return status + * @QCA_WLAN_VENDOR_ATTR_NDP_DRV_RETURN_VALUE: Driver return value + * @QCA_WLAN_VENDOR_ATTR_NDP_CHANNEL_CONFIG: Channel config request type + * @QCA_WLAN_VENDOR_ATTR_NDP_NCS_SK_TYPE: Cipher Suit ID + * @QCA_WLAN_VENDOR_ATTR_NDP_PMK: Pairwise Master Key + * @QCA_WLAN_VENDOR_ATTR_NDP_SCID: Security Context ID + */ +enum qca_wlan_vendor_attr_ndp_params { + QCA_WLAN_VENDOR_ATTR_NDP_PARAM_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_NDP_SUBCMD, + QCA_WLAN_VENDOR_ATTR_NDP_TRANSACTION_ID, + QCA_WLAN_VENDOR_ATTR_NDP_SERVICE_INSTANCE_ID, + QCA_WLAN_VENDOR_ATTR_NDP_CHANNEL, + QCA_WLAN_VENDOR_ATTR_NDP_PEER_DISCOVERY_MAC_ADDR, + QCA_WLAN_VENDOR_ATTR_NDP_IFACE_STR, + /* CONFIG_SECURITY is deprecated, use NCS_SK_TYPE/PMK/SCID instead */ + QCA_WLAN_VENDOR_ATTR_NDP_CONFIG_SECURITY, + QCA_WLAN_VENDOR_ATTR_NDP_CONFIG_QOS, + QCA_WLAN_VENDOR_ATTR_NDP_APP_INFO, + QCA_WLAN_VENDOR_ATTR_NDP_INSTANCE_ID, + QCA_WLAN_VENDOR_ATTR_NDP_INSTANCE_ID_ARRAY, + QCA_WLAN_VENDOR_ATTR_NDP_RESPONSE_CODE, + QCA_WLAN_VENDOR_ATTR_NDP_NDI_MAC_ADDR, + QCA_WLAN_VENDOR_ATTR_NDP_DRV_RESPONSE_STATUS_TYPE, + QCA_WLAN_VENDOR_ATTR_NDP_DRV_RETURN_VALUE, + QCA_WLAN_VENDOR_ATTR_NDP_CHANNEL_CONFIG, + QCA_WLAN_VENDOR_ATTR_NDP_NCS_SK_TYPE, + QCA_WLAN_VENDOR_ATTR_NDP_PMK, + QCA_WLAN_VENDOR_ATTR_NDP_SCID, + + QCA_WLAN_VENDOR_ATTR_NDP_PARAMS_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_NDP_PARAMS_MAX = + QCA_WLAN_VENDOR_ATTR_NDP_PARAMS_AFTER_LAST - 1, +}; + +/** + * enum qca_wlan_vendor_attr_ndp_cfg_security - vendor security attribute + * @QCA_WLAN_VENDOR_ATTR_NDP_SECURITY_ENABLE: Security enabled + */ +enum qca_wlan_vendor_attr_ndp_cfg_security { + QCA_WLAN_VENDOR_ATTR_NDP_SECURITY_ENABLE = 1, +}; + +/** + * enum qca_wlan_vendor_attr_ndp_qos - vendor qos attribute + * @QCA_WLAN_VENDOR_ATTR_NDP_QOS_CONFIG: NDP QoS configuration + */ +enum qca_wlan_vendor_attr_ndp_qos { + QCA_WLAN_VENDOR_ATTR_NDP_QOS_CONFIG = 1, +}; + +/** + * enum qca_wlan_vendor_attr_ndp_sub_cmd_value - NDP subcmd value + * @QCA_WLAN_VENDOR_ATTR_NDP_INVALID: Unused subcmd value + * @QCA_WLAN_VENDOR_ATTR_NDP_INTERFACE_CREATE: iface create + * @QCA_WLAN_VENDOR_ATTR_NDP_INTERFACE_DELETE: iface delete + * @QCA_WLAN_VENDOR_ATTR_NDP_INITIATOR_REQUEST: NDP initiator request + * @QCA_WLAN_VENDOR_ATTR_NDP_INITIATOR_RESPONSE: NDP initiator response + * @QCA_WLAN_VENDOR_ATTR_NDP_RESPONDER_REQUEST: NDP responder request + * @QCA_WLAN_VENDOR_ATTR_NDP_RESPONDER_RESPONSE: NDP responder response + * @QCA_WLAN_VENDOR_ATTR_NDP_END_REQUEST: NDP end request + * @QCA_WLAN_VENDOR_ATTR_NDP_END_RESPONSE: NDP end response + * @QCA_WLAN_VENDOR_ATTR_NDP_REQUEST_IND: NDP request indication + * @QCA_WLAN_VENDOR_ATTR_NDP_CONFIRM_IND: NDP confirm indication + * @QCA_WLAN_VENDOR_ATTR_NDP_END_IND: NDP End indication + */ +enum qca_wlan_vendor_attr_ndp_sub_cmd_value { + QCA_WLAN_VENDOR_ATTR_NDP_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_NDP_INTERFACE_CREATE = 1, + QCA_WLAN_VENDOR_ATTR_NDP_INTERFACE_DELETE = 2, + QCA_WLAN_VENDOR_ATTR_NDP_INITIATOR_REQUEST = 3, + QCA_WLAN_VENDOR_ATTR_NDP_INITIATOR_RESPONSE = 4, + QCA_WLAN_VENDOR_ATTR_NDP_RESPONDER_REQUEST = 5, + QCA_WLAN_VENDOR_ATTR_NDP_RESPONDER_RESPONSE = 6, + QCA_WLAN_VENDOR_ATTR_NDP_END_REQUEST = 7, + QCA_WLAN_VENDOR_ATTR_NDP_END_RESPONSE = 8, + QCA_WLAN_VENDOR_ATTR_NDP_REQUEST_IND = 9, + QCA_WLAN_VENDOR_ATTR_NDP_CONFIRM_IND = 10, + QCA_WLAN_VENDOR_ATTR_NDP_END_IND = 11 +}; + +/** enum nan_datapath_state - NAN datapath states + * @NAN_DATA_NDI_CREATING_STATE: NDI create is in progress + * @NAN_DATA_NDI_CREATED_STATE: NDI successfully crated + * @NAN_DATA_NDI_DELETING_STATE: NDI delete is in progress + * @NAN_DATA_NDI_DELETED_STATE: NDI delete is in progress + * @NAN_DATA_PEER_CREATE_STATE: Peer create is in progress + * @NAN_DATA_PEER_DELETE_STATE: Peer delete is in progrss + * @NAN_DATA_CONNECTING_STATE: Data connection in progress + * @NAN_DATA_CONNECTED_STATE: Data connection successful + * @NAN_DATA_END_STATE: NDP end is in progress + * @NAN_DATA_DISCONNECTED_STATE: NDP is in disconnected state + */ +enum nan_datapath_state { + NAN_DATA_NDI_CREATING_STATE = 0, + NAN_DATA_NDI_CREATED_STATE = 1, + NAN_DATA_NDI_DELETING_STATE = 2, + NAN_DATA_NDI_DELETED_STATE = 3, + NAN_DATA_PEER_CREATE_STATE = 4, + NAN_DATA_PEER_DELETE_STATE = 5, + NAN_DATA_CONNECTING_STATE = 6, + NAN_DATA_CONNECTED_STATE = 7, + NAN_DATA_END_STATE = 8, + NAN_DATA_DISCONNECTED_STATE = 9, +}; + +/** + * struct nan_datapath_ctx - context for nan data path + * @state: Current state of NDP + * @active_ndp_sessions: active ndp sessions per adapter + * @active_ndp_peers: number of active ndp peers + * @ndp_create_transaction_id: transaction id for create req + * @ndp_delete_transaction_id: transaction id for delete req + * @ndp_key_installed: NDP security key installed + * @ndp_enc_key: NDP encryption key info + * @ndp_debug_state: debug state info + * @ndi_delete_rsp_reason: reason code for ndi_delete rsp + * @ndi_delete_rsp_status: status for ndi_delete rsp + */ +struct nan_datapath_ctx { + enum nan_datapath_state state; + /* idx in following array should follow conn_info.peerMacAddress */ + uint32_t active_ndp_sessions[MAX_PEERS]; + uint32_t active_ndp_peers; + uint16_t ndp_create_transaction_id; + uint16_t ndp_delete_transaction_id; + bool ndp_key_installed; + tCsrRoamSetKey ndp_enc_key; + uint32_t ndp_debug_state; + uint32_t ndi_delete_rsp_reason; + uint32_t ndi_delete_rsp_status; +}; + +#ifdef WLAN_FEATURE_NAN_DATAPATH +void hdd_ndp_print_ini_config(struct hdd_context_s *hdd_ctx); +void hdd_nan_datapath_target_config(struct hdd_context_s *hdd_ctx, + struct wma_tgt_cfg *cfg); +void hdd_ndp_event_handler(struct hdd_adapter_s *adapter, + tCsrRoamInfo *roam_info, uint32_t roam_id, eRoamCmdStatus roam_status, + eCsrRoamResult roam_result); +int wlan_hdd_cfg80211_process_ndp_cmd(struct wiphy *wiphy, + struct wireless_dev *wdev, const void *data, int data_len); +int hdd_init_nan_data_mode(struct hdd_adapter_s *adapter); +void hdd_ndp_session_end_handler(hdd_adapter_t *adapter); +#else +static inline void hdd_ndp_print_ini_config(struct hdd_context_s *hdd_ctx) +{ +} +static inline void hdd_nan_datapath_target_config(struct hdd_context_s *hdd_ctx, + struct wma_tgt_cfg *cfg) +{ +} +static inline void hdd_ndp_event_handler(struct hdd_adapter_s *adapter, + tCsrRoamInfo *roam_info, uint32_t roam_id, eRoamCmdStatus roam_status, + eCsrRoamResult roam_result) +{ +} +static inline int wlan_hdd_cfg80211_process_ndp_cmd(struct wiphy *wiphy, + struct wireless_dev *wdev, const void *data, int data_len) +{ + return 0; +} +static inline int hdd_init_nan_data_mode(struct hdd_adapter_s *adapter) +{ + return 0; +} +static inline void hdd_ndp_session_end_handler(hdd_adapter_t *adapter) +{ +} +#endif /* WLAN_FEATURE_NAN_DATAPATH */ + +#endif /* __WLAN_HDD_NAN_DATAPATH_H */ diff --git a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_napi.c b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_napi.c new file mode 100644 index 0000000000000000000000000000000000000000..b4273135e39ef73bb1e8c49fa5be7cf5db48ad79 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_napi.c @@ -0,0 +1,513 @@ +/* + * Copyright (c) 2015-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: wlan_hdd_napi.c + * + * WLAN HDD NAPI interface implementation + */ +#include /* get_cpu */ + +#include "wlan_hdd_napi.h" +#include "cds_api.h" /* cds_get_context */ +#include "hif.h" /* hif_map_service...*/ +#include "wlan_hdd_main.h" /* hdd_err/warn... */ +#include "qdf_types.h" /* QDF_MODULE_ID_... */ +#include "ce_api.h" + +/* guaranteed to be initialized to zero/NULL by the standard */ +static struct qca_napi_data *hdd_napi_ctx; + +/** + * hdd_napi_get_all() - return the whole NAPI structure from HIF + * + * Gets to the data structure common to all NAPI instances. + * + * Return: + * NULL : probably NAPI not initialized yet. + * : the address of the whole NAPI structure + */ +struct qca_napi_data *hdd_napi_get_all(void) +{ + struct qca_napi_data *rp = NULL; + struct hif_opaque_softc *hif; + + NAPI_DEBUG("-->"); + + hif = cds_get_context(QDF_MODULE_ID_HIF); + if (unlikely(NULL == hif)) + QDF_ASSERT(NULL != hif); /* WARN */ + else + rp = hif_napi_get_all(hif); + + NAPI_DEBUG("<-- [addr=%p]", rp); + return rp; +} + +/** + * hdd_napi_get_map() - get a copy of napi pipe map + * + * Return: + * uint32_t : copy of pipe map + */ +static uint32_t hdd_napi_get_map(void) +{ + uint32_t map = 0; + + NAPI_DEBUG("-->"); + /* cache once, use forever */ + if (hdd_napi_ctx == NULL) + hdd_napi_ctx = hdd_napi_get_all(); + if (hdd_napi_ctx != NULL) + map = hdd_napi_ctx->ce_map; + + NAPI_DEBUG("<-- [map=0x%08x]", map); + return map; +} + +/** + * hdd_napi_create() - creates the NAPI structures for a given netdev + * + * Creates NAPI instances. This function is called + * unconditionally during initialization. It creates + * napi structures through the proper HTC/HIF calls. + * The structures are disabled on creation. + * + * Return: + * single-queue: <0: err, >0=id, 0 (should not happen) + * multi-queue: bitmap of created instances (0: none) + */ +int hdd_napi_create(void) +{ + struct hif_opaque_softc *hif_ctx; + int rc = 0; + hdd_context_t *hdd_ctx; + uint8_t feature_flags = 0; + + NAPI_DEBUG("-->"); + + hif_ctx = cds_get_context(QDF_MODULE_ID_HIF); + if (unlikely(NULL == hif_ctx)) { + QDF_ASSERT(NULL != hif_ctx); + rc = -EFAULT; + } else { + + feature_flags = QCA_NAPI_FEATURE_CPU_CORRECTION | + QCA_NAPI_FEATURE_IRQ_BLACKLISTING | + QCA_NAPI_FEATURE_CORE_CTL_BOOST; + + rc = hif_napi_create(hif_ctx, hdd_napi_poll, + QCA_NAPI_BUDGET, + QCA_NAPI_DEF_SCALE, + feature_flags); + if (rc < 0) { + hdd_err("ERR(%d) creating NAPI instances", + rc); + } else { + hdd_info("napi instances were created. Map=0x%x", rc); + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (unlikely(NULL == hdd_ctx)) { + QDF_ASSERT(0); + rc = -EFAULT; + } else { + rc = hdd_napi_event(NAPI_EVT_INI_FILE, + (void *)hdd_ctx->napi_enable); + } + } + + } + NAPI_DEBUG("<-- [rc=%d]", rc); + + return rc; +} + +/** + * hdd_napi_destroy() - destroys the NAPI structures for a given netdev + * @force: if set, will force-disable the instance before _del'ing + * + * Destroy NAPI instances. This function is called + * unconditionally during module removal. It destroy + * napi structures through the proper HTC/HIF calls. + * + * Return: + * number of NAPI instances destroyed + */ +int hdd_napi_destroy(int force) +{ + int rc = 0; + int i; + uint32_t hdd_napi_map = hdd_napi_get_map(); + + NAPI_DEBUG("--> (force=%d)", force); + if (hdd_napi_map) { + struct hif_opaque_softc *hif_ctx; + + hif_ctx = cds_get_context(QDF_MODULE_ID_HIF); + if (unlikely(NULL == hif_ctx)) + QDF_ASSERT(NULL != hif_ctx); + else + for (i = 0; i < CE_COUNT_MAX; i++) + if (hdd_napi_map & (0x01 << i)) { + if (0 <= hif_napi_destroy( + hif_ctx, + NAPI_PIPE2ID(i), force)) { + rc++; + hdd_napi_map &= ~(0x01 << i); + } else + hdd_warn("cannot destroy napi %d: (pipe:%d), f=%d\n", + i, + NAPI_PIPE2ID(i), force); + } + } + + /* if all instances are removed, it is likely that hif_context has been + * removed as well, so the cached value of the napi context also needs + * to be removed + */ + if (force) + QDF_ASSERT(hdd_napi_map == 0); + if (0 == hdd_napi_map) + hdd_napi_ctx = NULL; + + NAPI_DEBUG("<-- [rc=%d]", rc); + return rc; +} + +/** + * hdd_napi_enabled() - checks if NAPI is enabled (for a given id) + * @id: the id of the NAPI to check (any= -1) + * + * Return: + * int: 0 = false (NOT enabled) + * !0 = true (enabbled) + */ +int hdd_napi_enabled(int id) +{ + struct hif_opaque_softc *hif; + int rc = 0; /* NOT enabled */ + + hif = cds_get_context(QDF_MODULE_ID_HIF); + if (unlikely(NULL == hif)) + QDF_ASSERT(hif != NULL); /* WARN_ON; rc = 0 */ + else if (-1 == id) + rc = hif_napi_enabled(hif, id); + else + rc = hif_napi_enabled(hif, NAPI_ID2PIPE(id)); + return rc; +} + +/** + * hdd_napi_event() - relay the event detected by HDD to HIF NAPI event handler + * @event: event code + * @data : event-specific auxiliary data + * + * See function documentation in hif_napi.c::hif_napi_event for list of events + * and how each of them is handled. + * + * Return: + * < 0: error code + * = 0: event handled successfully + */ +int hdd_napi_event(enum qca_napi_event event, void *data) +{ + int rc = -EFAULT; /* assume err */ + struct hif_opaque_softc *hif; + + NAPI_DEBUG("-->(event=%d, aux=%p)", event, data); + + hif = cds_get_context(QDF_MODULE_ID_HIF); + if (unlikely(NULL == hif)) + QDF_ASSERT(hif != NULL); + else + rc = hif_napi_event(hif, event, data); + + NAPI_DEBUG("<--[rc=%d]", rc); + return rc; +} + +#ifdef HELIUMPLUS +/** + * hdd_napi_perfd_cpufreq() - set/reset min CPU freq for cores + * @req_state: high/low + * + * Send a message to cnss-daemon through netlink. cnss-daemon, + * in turn, sends a message to perf-daemon. + * If freq > 0, this is a set request. It sets the min frequency of the + * cores of the specified cluster to provided freq value (in KHz). + * If freq == 0, then the freq lock is removed (and frequency returns to + * system default). + * + * Semantical Alert: + * There can be at most one lock active at a time. Each "set" request must + * be followed by a "reset" request. Perfd behaviour is undefined otherwise. + * + * Return: == 0: netlink message sent to cnss-daemon + * < 0: failure to send the message + */ +static int hdd_napi_perfd_cpufreq(enum qca_napi_tput_state req_state) +{ + int rc = 0; + struct wlan_core_minfreq req; + struct hdd_context_s *hdd_ctx; + + NAPI_DEBUG("-> (%d)", req_state); + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (unlikely(hdd_ctx == NULL)) { + hdd_err("cannot get hdd_context"); + rc = -EFAULT; + goto hnpc_ret; + } + + switch (req_state) { + case QCA_NAPI_TPUT_LO: + req.magic = WLAN_CORE_MINFREQ_MAGIC; + req.reserved = 0; /* unused */ + req.coremask = 0; /* not valid */ + req.freq = 0; /* reset */ + break; + case QCA_NAPI_TPUT_HI: + req.magic = WLAN_CORE_MINFREQ_MAGIC; + req.reserved = 0; /* unused */ + req.coremask = 0x0f0; /* perf cluster */ + req.freq = 700; /* KHz */ + break; + default: + hdd_err("invalid req_state (%d)", req_state); + rc = -EINVAL; + goto hnpc_ret; + } /* switch */ + + NAPI_DEBUG("CPU min freq to %s %d", + (req.freq == 0)?"Resetting":"Setting", req.freq); + /* the following service function returns void */ + wlan_hdd_send_svc_nlink_msg(hdd_ctx->radio_index, + WLAN_SVC_CORE_MINFREQ, + &req, sizeof(struct wlan_core_minfreq)); +hnpc_ret: + NAPI_DEBUG("<--[rc=%d]", rc); + return rc; +} + +/** + * hdd_napi_apply_throughput_policy() - implement the throughput action policy + * @hddctx: HDD context + * @tx_packets: number of tx packets in the last interval + * @rx_packets: number of rx packets in the last interval + * + * Called by hdd_bus_bw_compute_cb, checks the number of packets in the last + * interval, and determines the desired napi throughput state (HI/LO). If + * the desired state is different from the current, then it invokes the + * event handler to switch to the desired state. + * + * The policy implementation is limited to this function and + * The current policy is: determine the NAPI mode based on the condition: + * (total number of packets > medium threshold) + * - tx packets are included because: + * a- tx-completions arrive at one of the rx CEs + * b- in TCP, a lof of TX implies ~(tx/2) rx (ACKs) + * c- so that we can use the same normalized criteria in ini file + * - medium-threshold (default: 500 packets / 10 ms), because + * we would like to be more reactive. + * + * Return: 0 : no action taken, or action return code + * !0: error, or action error code + */ +static int napi_tput_policy_delay; +int hdd_napi_apply_throughput_policy(struct hdd_context_s *hddctx, + uint64_t tx_packets, + uint64_t rx_packets) +{ + int rc = 0; + uint64_t packets = tx_packets + rx_packets; + enum qca_napi_tput_state req_state; + struct qca_napi_data *napid = hdd_napi_get_all(); + int enabled; + + NAPI_DEBUG("-->%s(tx=%lld, rx=%lld)", __func__, tx_packets, rx_packets); + + if (unlikely(napi_tput_policy_delay < 0)) + napi_tput_policy_delay = 0; + if (napi_tput_policy_delay > 0) { + NAPI_DEBUG("%s: delaying policy; delay-count=%d", + __func__, napi_tput_policy_delay); + napi_tput_policy_delay--; + + /* make sure the next timer call calls us */ + hddctx->cur_vote_level = -1; + + return rc; + } + + if (!napid) { + hdd_err("ERR: napid NULL"); + return rc; + } + + enabled = hdd_napi_enabled(HDD_NAPI_ANY); + if (!enabled) { + hdd_err("ERR: napi not enabled"); + return rc; + } + + if (packets > hddctx->config->busBandwidthHighThreshold) + req_state = QCA_NAPI_TPUT_HI; + else + req_state = QCA_NAPI_TPUT_LO; + + if (req_state != napid->napi_mode) + /* [re]set the floor frequency of high cluster */ + rc = hdd_napi_perfd_cpufreq(req_state); + /* blacklist/boost_mode on/off */ + rc = hdd_napi_event(NAPI_EVT_TPUT_STATE, (void *)req_state); + return rc; +} + +/** + * hdd_napi_serialize() - serialize all NAPI activities + * @is_on: 1="serialize" or 0="de-serialize" + * + * Start/stop "serial-NAPI-mode". + * NAPI serial mode describes a state where all NAPI operations are forced to be + * run serially. This is achieved by ensuring all NAPI instances are run on the + * same CPU, so forced to be serial. + * NAPI life-cycle: + * - Interrupt is received for a given CE. + * - In the ISR, the interrupt is masked and corresponding NAPI instance + * is scheduled, to be run as a bottom-half. + * - Bottom-half starts with a poll call (by the net_rx softirq). There may be + * one of more subsequent calls until the work is complete. + * - Once the work is complete, the poll handler enables the interrupt and + * the cycle re-starts. + * + * Return: <0: error-code (operation failed) + * =0: success + * >0: status (not used) + */ +int hdd_napi_serialize(int is_on) +{ + int rc; + hdd_context_t *hdd_ctx; +#define POLICY_DELAY_FACTOR (1) + rc = hif_napi_serialize(cds_get_context(QDF_MODULE_ID_HIF), is_on); + if ((rc == 0) && (is_on == 0)) { + /* apply throughput policy after one timeout */ + napi_tput_policy_delay = POLICY_DELAY_FACTOR; + + /* make sure that bus_bandwidth trigger is executed */ + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (hdd_ctx != NULL) + hdd_ctx->cur_vote_level = -1; + + } + return rc; +} +#endif /* HELIUMPLUS */ + +/** + * hdd_napi_poll() - NAPI poll function + * @napi : pointer to NAPI struct + * @budget: the pre-declared budget + * + * Implementation of poll function. This function is called + * by kernel during softirq processing. + * + * NOTE FOR THE MAINTAINER: + * Make sure this is very close to the ce_tasklet code. + * + * Return: + * int: the amount of work done ( <= budget ) + */ +int hdd_napi_poll(struct napi_struct *napi, int budget) +{ + return hif_napi_poll(cds_get_context(QDF_MODULE_ID_HIF), napi, budget); +} + +/** + * hdd_display_napi_stats() - print NAPI stats + * + * Return: == 0: success; !=0: failure + */ +int hdd_display_napi_stats(void) +{ + int i, j, k, n; /* NAPI, CPU, bucket indices, bucket buf write index*/ + int max; + struct qca_napi_data *napid; + struct qca_napi_info *napii; + struct qca_napi_stat *napis; + /* + * Expecting each NAPI bucket item to need at max 5 numerals + space for + * formatting. For example "10000 " Thus the array needs to have + * (5 + 1) * QCA_NAPI_NUM_BUCKETS bytes of space. Leaving one space at + * the end of the "buf" arrary for end of string char. + */ + char buf[6 * QCA_NAPI_NUM_BUCKETS + 1] = {'\0'}; + + napid = hdd_napi_get_all(); + if (NULL == napid) { + hdd_err("%s unable to retrieve napi structure", __func__); + return -EFAULT; + } + qdf_print("[NAPI %u][BL %d]: scheds polls comps done t-lim p-lim corr napi-buckets(%d)", + napid->napi_mode, + hif_napi_cpu_blacklist(napid, BLACKLIST_QUERY), + QCA_NAPI_NUM_BUCKETS); + + for (i = 0; i < CE_COUNT_MAX; i++) + if (napid->ce_map & (0x01 << i)) { + napii = napid->napis[i]; + if (!napii) + continue; + + for (j = 0; j < NR_CPUS; j++) { + napis = &(napii->stats[j]); + n = 0; + max = sizeof(buf); + for (k = 0; k < QCA_NAPI_NUM_BUCKETS; k++) { + n += scnprintf( + buf + n, max - n, + " %d", + napis->napi_budget_uses[k]); + } + + if (napis->napi_schedules != 0) + qdf_print("NAPI[%2d]CPU[%d]: %7d %7d %7d %7d %5d %5d %5d %s", + i, j, + napis->napi_schedules, + napis->napi_polls, + napis->napi_completes, + napis->napi_workdone, + napis->time_limit_reached, + napis->rxpkt_thresh_reached, + napis->cpu_corrected, + buf); + } + } + + hif_napi_stats(napid); + return 0; +} diff --git a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_ocb.c b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_ocb.c new file mode 100644 index 0000000000000000000000000000000000000000..7f1a5365c3a46f18de0337931a242f0dc3c1c99c --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_ocb.c @@ -0,0 +1,2017 @@ +/* + * Copyright (c) 2011-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: wlan_hdd_ocb.c + * + * WLAN Host Device Driver 802.11p OCB implementation + */ + +#include "cds_sched.h" +#include "wlan_hdd_assoc.h" +#include "wlan_hdd_main.h" +#include "wlan_hdd_ocb.h" +#include "wlan_hdd_trace.h" +#include "wlan_tgt_def_config.h" +#include "sch_api.h" +#include "wma_api.h" +#include "ol_txrx.h" +#include + +/* Structure definitions for WLAN_SET_DOT11P_CHANNEL_SCHED */ +#define AIFSN_MIN (2) +#define AIFSN_MAX (15) +#define CW_MIN (1) +#define CW_MAX (10) + +/* Maximum time(ms) to wait for OCB operations */ +#define WLAN_WAIT_TIME_OCB_CMD 1500 +#define HDD_OCB_MAGIC 0x489a154f + +/** + * struct hdd_ocb_ctxt - Context for OCB operations + * adapter: the ocb adapter + * completion_evt: the completion event + * status: status of the request + */ +struct hdd_ocb_ctxt { + uint32_t magic; + hdd_adapter_t *adapter; + struct completion completion_evt; + int status; +}; + +/** + * hdd_set_dot11p_config() - Set 802.11p config flag + * @hdd_ctx: HDD Context pointer + * + * TODO-OCB: This has been temporarily added to ensure this paramter + * is set in CSR when we init the channel list. This should be removed + * once the 5.9 GHz channels are added to the regulatory domain. + */ +void hdd_set_dot11p_config(hdd_context_t *hdd_ctx) +{ + sme_set_dot11p_config(hdd_ctx->hHal, + hdd_ctx->config->dot11p_mode != + WLAN_HDD_11P_DISABLED); +} + +/** + * dot11p_validate_qos_params() - Check if QoS parameters are valid + * @qos_params: Array of QoS parameters + * + * Return: 0 on success. error code on failure. + */ +static int dot11p_validate_qos_params(struct sir_qos_params qos_params[]) +{ + int i; + + for (i = 0; i < MAX_NUM_AC; i++) { + if ((!qos_params[i].aifsn) && (!qos_params[i].cwmin) + && (!qos_params[i].cwmax)) + continue; + + /* Validate AIFSN */ + if ((qos_params[i].aifsn < AIFSN_MIN) + || (qos_params[i].aifsn > AIFSN_MAX)) { + hdd_err("Invalid QoS parameter aifsn %d", + qos_params[i].aifsn); + return -EINVAL; + } + + /* Validate CWMin */ + if ((qos_params[i].cwmin < CW_MIN) + || (qos_params[i].cwmin > CW_MAX)) { + hdd_err("Invalid QoS parameter cwmin %d", + qos_params[i].cwmin); + return -EINVAL; + } + + /* Validate CWMax */ + if ((qos_params[i].cwmax < CW_MIN) + || (qos_params[i].cwmax > CW_MAX)) { + hdd_err("Invalid QoS parameter cwmax %d", + qos_params[i].cwmax); + return -EINVAL; + } + } + + return 0; +} + +/** + * dot11p_validate_channel() - validates a DSRC channel + * @center_freq: the channel's center frequency + * @bandwidth: the channel's bandwidth + * @tx_power: transmit power + * @reg_power: (output) the max tx power from the regulatory domain + * @antenna_max: (output) the max antenna gain from the regulatory domain + * + * Return: 0 if the channel is valid, error code otherwise. + */ +static int dot11p_validate_channel(struct wiphy *wiphy, + uint32_t channel_freq, uint32_t bandwidth, + uint32_t tx_power, uint8_t *reg_power, + uint8_t *antenna_max) +{ + int band_idx, channel_idx; + struct ieee80211_supported_band *current_band; + struct ieee80211_channel *current_channel; + + for (band_idx = 0; band_idx < NUM_NL80211_BANDS; band_idx++) { + current_band = wiphy->bands[band_idx]; + if (!current_band) + continue; + + for (channel_idx = 0; channel_idx < current_band->n_channels; + channel_idx++) { + current_channel = ¤t_band->channels[channel_idx]; + + if (channel_freq == current_channel->center_freq) { + if (current_channel->flags & + IEEE80211_CHAN_DISABLED) + return -EINVAL; + + if (reg_power) + *reg_power = + current_channel->max_reg_power; + if (antenna_max) + *antenna_max = + current_channel-> + max_antenna_gain; + + switch (bandwidth) { + case 0: + if (current_channel->flags & + IEEE80211_CHAN_NO_10MHZ) + bandwidth = 5; + else if (current_channel->flags & + IEEE80211_CHAN_NO_20MHZ) + bandwidth = 10; + else + bandwidth = 20; + break; + case 5: + break; + case 10: + if (current_channel->flags & + IEEE80211_CHAN_NO_10MHZ) + return -EINVAL; + break; + case 20: + if (current_channel->flags & + IEEE80211_CHAN_NO_20MHZ) + return -EINVAL; + break; + default: + return -EINVAL; + } + + if (tx_power > current_channel->max_power) + return -EINVAL; + + return 0; + } + } + } + + return -EINVAL; +} + +/** + * hdd_ocb_validate_config() - Validates the config data + * @config: configuration to be validated + * + * Return: 0 on success. + */ +static int hdd_ocb_validate_config(hdd_adapter_t *adapter, + struct sir_ocb_config *config) +{ + int i; + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + + for (i = 0; i < config->channel_count; i++) { + if (dot11p_validate_channel(hdd_ctx->wiphy, + config->channels[i].chan_freq, + config->channels[i].bandwidth, + config->channels[i].max_pwr, + &config->channels[i].reg_pwr, + &config->channels[i].antenna_max)) { + hdd_err("Invalid channel frequency %d", + config->channels[i].chan_freq); + return -EINVAL; + } + if (dot11p_validate_qos_params(config->channels[i].qos_params)) + return -EINVAL; + } + + return 0; +} + +/** + * hdd_ocb_register_sta() - Register station with Transport Layer + * @adapter: Pointer to HDD Adapter + * + * This function should be invoked in the OCB Set Schedule callback + * to enable the data path in the TL by calling RegisterSTAClient + * + * Return: 0 on success. -1 on failure. + */ +static int hdd_ocb_register_sta(hdd_adapter_t *adapter) +{ + QDF_STATUS qdf_status = QDF_STATUS_E_FAILURE; + struct ol_txrx_desc_type sta_desc = {0}; + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + uint8_t peer_id; + struct ol_txrx_ops txrx_ops; + + qdf_status = ol_txrx_register_ocb_peer(hdd_ctx->pcds_context, + adapter->macAddressCurrent.bytes, + &peer_id); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + hdd_err("Error registering OCB Self Peer!"); + return -EINVAL; + } + + hdd_ctx->sta_to_adapter[peer_id] = adapter; + + sta_desc.sta_id = peer_id; + sta_desc.is_qos_enabled = 1; + + /* Register the vdev transmit and receive functions */ + qdf_mem_zero(&txrx_ops, sizeof(txrx_ops)); + txrx_ops.rx.rx = hdd_rx_packet_cbk; + ol_txrx_vdev_register( + ol_txrx_get_vdev_from_vdev_id(adapter->sessionId), + adapter, &txrx_ops); + adapter->tx_fn = txrx_ops.tx.tx; + + qdf_status = ol_txrx_register_peer(&sta_desc); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + hdd_err("Failed to register. Status= %d [0x%08X]", + qdf_status, qdf_status); + return -EINVAL; + } + + if (pHddStaCtx->conn_info.staId[0] != 0 && + pHddStaCtx->conn_info.staId[0] != peer_id) { + hdd_warn("The ID for the OCB station has changed."); + } + + pHddStaCtx->conn_info.staId[0] = peer_id; + qdf_copy_macaddr(&pHddStaCtx->conn_info.peerMacAddress[0], + &adapter->macAddressCurrent); + + return 0; +} + +/** + * hdd_ocb_config_new() - Creates a new OCB configuration + * @num_channels: the number of channels + * @num_schedule: the schedule size + * @ndl_chan_list_len: length in bytes of the NDL chan blob + * @ndl_active_state_list_len: length in bytes of the active state blob + * + * Return: A pointer to the OCB configuration struct, NULL on failure. + */ +static +struct sir_ocb_config *hdd_ocb_config_new(uint32_t num_channels, + uint32_t num_schedule, + uint32_t ndl_chan_list_len, + uint32_t ndl_active_state_list_len) +{ + struct sir_ocb_config *ret = 0; + uint32_t len; + void *cursor; + + if (num_channels > CFG_TGT_NUM_OCB_CHANNELS || + num_schedule > CFG_TGT_NUM_OCB_SCHEDULES) + return NULL; + + len = sizeof(*ret) + + num_channels * sizeof(struct sir_ocb_config_channel) + + num_schedule * sizeof(struct sir_ocb_config_sched) + + ndl_chan_list_len + + ndl_active_state_list_len; + + cursor = qdf_mem_malloc(len); + if (!cursor) + goto fail; + + ret = cursor; + cursor += sizeof(*ret); + + ret->channel_count = num_channels; + ret->channels = cursor; + cursor += num_channels * sizeof(*ret->channels); + + ret->schedule_size = num_schedule; + ret->schedule = cursor; + cursor += num_schedule * sizeof(*ret->schedule); + + ret->dcc_ndl_chan_list = cursor; + cursor += ndl_chan_list_len; + + ret->dcc_ndl_active_state_list = cursor; + cursor += ndl_active_state_list_len; + + return ret; + +fail: + qdf_mem_free(ret); + return NULL; +} + +/** + * hdd_ocb_set_config_callback() - OCB set config callback function + * @context_ptr: OCB call context + * @response_ptr: Pointer to response structure + * + * This function is registered as a callback with the lower layers + * and is used to respond with the status of a OCB set config command. + */ +static void hdd_ocb_set_config_callback(void *context_ptr, void *response_ptr) +{ + struct hdd_ocb_ctxt *context = context_ptr; + struct sir_ocb_set_config_response *resp = response_ptr; + + if (!context) + return; + + if (resp && resp->status) + hdd_warn("Operation failed: %d", resp->status); + + spin_lock(&hdd_context_lock); + if (context->magic == HDD_OCB_MAGIC) { + hdd_adapter_t *adapter = context->adapter; + if (!resp) { + context->status = -EINVAL; + complete(&context->completion_evt); + spin_unlock(&hdd_context_lock); + return; + } + + context->adapter->ocb_set_config_resp = *resp; + spin_unlock(&hdd_context_lock); + if (!resp->status) { + /* + * OCB set config command successful. + * Open the TX data path + */ + if (!hdd_ocb_register_sta(adapter)) { + wlan_hdd_netif_queue_control(adapter, + WLAN_START_ALL_NETIF_QUEUE_N_CARRIER, + WLAN_CONTROL_PATH); + } + } + + spin_lock(&hdd_context_lock); + if (context->magic == HDD_OCB_MAGIC) + complete(&context->completion_evt); + spin_unlock(&hdd_context_lock); + } else { + spin_unlock(&hdd_context_lock); + } +} + +/** + * hdd_ocb_set_config_req() - Send an OCB set config request + * @adapter: a pointer to the adapter + * @config: a pointer to the OCB configuration + * + * Return: 0 on success. + */ +static int hdd_ocb_set_config_req(hdd_adapter_t *adapter, + struct sir_ocb_config *config) +{ + int rc; + QDF_STATUS qdf_status; + struct hdd_ocb_ctxt context = {0}; + + if (hdd_ocb_validate_config(adapter, config)) { + hdd_err("The configuration is invalid"); + return -EINVAL; + } + + init_completion(&context.completion_evt); + context.adapter = adapter; + context.magic = HDD_OCB_MAGIC; + + hdd_notice("Disabling queues"); + wlan_hdd_netif_queue_control(adapter, + WLAN_STOP_ALL_NETIF_QUEUE_N_CARRIER, + WLAN_CONTROL_PATH); + + /* Call the SME API to set the config */ + qdf_status = sme_ocb_set_config( + ((hdd_context_t *)adapter->pHddCtx)->hHal, &context, + hdd_ocb_set_config_callback, config); + if (qdf_status != QDF_STATUS_SUCCESS) { + hdd_err("Error calling SME function."); + /* Convert from qdf_status to errno */ + return -EINVAL; + } + + /* Wait for the function to complete. */ + rc = wait_for_completion_timeout(&context.completion_evt, + msecs_to_jiffies(WLAN_WAIT_TIME_OCB_CMD)); + if (rc == 0) { + rc = -ETIMEDOUT; + goto end; + } + rc = 0; + + if (context.status) { + rc = context.status; + goto end; + } + + if (adapter->ocb_set_config_resp.status) { + rc = -EINVAL; + goto end; + } + + /* fall through */ +end: + spin_lock(&hdd_context_lock); + context.magic = 0; + spin_unlock(&hdd_context_lock); + if (rc) + hdd_err("Operation failed: %d", rc); + return rc; +} + +/** + * __iw_set_dot11p_channel_sched() - Handler for WLAN_SET_DOT11P_CHANNEL_SCHED + * ioctl + * @dev: Pointer to net_device structure + * @iw_request_info: IW Request Info + * @wrqu: IW Request Userspace Data Pointer + * @extra: IW Request Kernel Data Pointer + * + * Return: 0 on success + */ +static int __iw_set_dot11p_channel_sched(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int rc = 0; + struct dot11p_channel_sched *sched; + hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct sir_ocb_config *config = NULL; + uint8_t *mac_addr; + int i, j; + struct sir_ocb_config_channel *curr_chan; + + ENTER_DEV(dev); + + if (wlan_hdd_validate_context(WLAN_HDD_GET_CTX(adapter))) + return -EINVAL; + + if (adapter->device_mode != QDF_OCB_MODE) { + hdd_err("Device not in OCB mode!"); + return -EINVAL; + } + + sched = (struct dot11p_channel_sched *)extra; + + /* Scheduled slots same as num channels for compatibility */ + config = hdd_ocb_config_new(sched->num_channels, sched->num_channels, + 0, 0); + if (config == NULL) { + hdd_err("Failed to allocate memory!"); + return -ENOMEM; + } + + /* Identify the vdev interface */ + config->session_id = adapter->sessionId; + + /* Release all the mac addresses used for OCB */ + for (i = 0; i < adapter->ocb_mac_addr_count; i++) { + wlan_hdd_release_intf_addr(adapter->pHddCtx, + adapter->ocb_mac_address[i].bytes); + } + adapter->ocb_mac_addr_count = 0; + + config->channel_count = 0; + for (i = 0; i < sched->num_channels; i++) { + if (0 == sched->channels[i].channel_freq) + continue; + + curr_chan = &(config->channels[config->channel_count]); + + curr_chan->chan_freq = sched->channels[i].channel_freq; + /* + * tx_power is divided by 2 because ocb_channel.tx_power is + * in half dB increments and sir_ocb_config_channel.max_pwr + * is in 1 dB increments. + */ + curr_chan->max_pwr = sched->channels[i].tx_power / 2; + curr_chan->bandwidth = sched->channels[i].channel_bandwidth; + /* assume 10 as default if not provided */ + if (curr_chan->bandwidth == 0) + curr_chan->bandwidth = 10; + + /* + * Setup locally administered mac addresses for each channel. + * First channel uses the adapter's address. + */ + if (i == 0) { + qdf_copy_macaddr(&curr_chan->mac_address, + &adapter->macAddressCurrent); + } else { + mac_addr = wlan_hdd_get_intf_addr(adapter->pHddCtx); + if (mac_addr == NULL) { + hdd_err("Cannot obtain mac address"); + rc = -EINVAL; + goto fail; + } + qdf_mem_copy(config->channels[ + config->channel_count].mac_address.bytes, + mac_addr, sizeof(tSirMacAddr)); + /* Save the mac address to release later */ + qdf_mem_copy(adapter->ocb_mac_address[ + adapter->ocb_mac_addr_count].bytes, + mac_addr, QDF_MAC_ADDR_SIZE); + adapter->ocb_mac_addr_count++; + } + + for (j = 0; j < MAX_NUM_AC; j++) { + curr_chan->qos_params[j].aifsn = + sched->channels[i].qos_params[j].aifsn; + curr_chan->qos_params[j].cwmin = + sched->channels[i].qos_params[j].cwmin; + curr_chan->qos_params[j].cwmax = + sched->channels[i].qos_params[j].cwmax; + } + + config->channel_count++; + } + + /* + * Scheduled slots same as num channels for compatibility with + * legacy use. + */ + for (i = 0; i < sched->num_channels; i++) { + config->schedule[i].chan_freq = sched->channels[i].channel_freq; + config->schedule[i].guard_interval = + sched->channels[i].start_guard_interval; + config->schedule[i].total_duration = + sched->channels[i].duration; + } + + rc = hdd_ocb_set_config_req(adapter, config); + if (rc) { + hdd_err("Error while setting OCB config"); + goto fail; + } + + rc = 0; + +fail: + qdf_mem_free(config); + return rc; +} + +/** + * iw_set_dot11p_channel_sched() - IOCTL interface for setting channel schedule + * @dev: Pointer to net_device structure + * @iw_request_info: IW Request Info + * @wrqu: IW Request Userspace Data Pointer + * @extra: IW Request Kernel Data Pointer + * + * Return: 0 on success. + */ +int iw_set_dot11p_channel_sched(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_set_dot11p_channel_sched(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +static const struct nla_policy qca_wlan_vendor_ocb_set_config_policy[ + QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_CHANNEL_COUNT] = { + .type = NLA_U32 + }, + [QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_SCHEDULE_SIZE] = { + .type = NLA_U32 + }, + [QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_CHANNEL_ARRAY] = { + .type = NLA_BINARY + }, + [QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_SCHEDULE_ARRAY] = { + .type = NLA_BINARY + }, + [QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_NDL_CHANNEL_ARRAY] = { + .type = NLA_BINARY + }, + [QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_NDL_ACTIVE_STATE_ARRAY] = { + .type = NLA_BINARY + }, + [QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_FLAGS] = { + .type = NLA_U32 + }, + [QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_DEF_TX_PARAM] = { + .type = NLA_BINARY + }, + +}; + +static const struct nla_policy qca_wlan_vendor_ocb_set_utc_time_policy[ + QCA_WLAN_VENDOR_ATTR_OCB_SET_UTC_TIME_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_OCB_SET_UTC_TIME_VALUE] = { + .type = NLA_BINARY, .len = SIZE_UTC_TIME + }, + [QCA_WLAN_VENDOR_ATTR_OCB_SET_UTC_TIME_ERROR] = { + .type = NLA_BINARY, .len = SIZE_UTC_TIME_ERROR + }, +}; + +static const struct nla_policy qca_wlan_vendor_ocb_start_timing_advert_policy[ + QCA_WLAN_VENDOR_ATTR_OCB_START_TIMING_ADVERT_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_OCB_START_TIMING_ADVERT_CHANNEL_FREQ] = { + .type = NLA_U32 + }, + [QCA_WLAN_VENDOR_ATTR_OCB_START_TIMING_ADVERT_REPEAT_RATE] = { + .type = NLA_U32 + }, +}; + +static const struct nla_policy qca_wlan_vendor_ocb_stop_timing_advert_policy[ + QCA_WLAN_VENDOR_ATTR_OCB_STOP_TIMING_ADVERT_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_OCB_STOP_TIMING_ADVERT_CHANNEL_FREQ] = { + .type = NLA_U32 + }, +}; + +static const struct nla_policy qca_wlan_vendor_ocb_get_tsf_timer_resp[] = { + [QCA_WLAN_VENDOR_ATTR_OCB_GET_TSF_RESP_TIMER_HIGH] = { + .type = NLA_U32 + }, + [QCA_WLAN_VENDOR_ATTR_OCB_GET_TSF_RESP_TIMER_LOW] = { + .type = NLA_U32 + }, +}; + +static const struct nla_policy qca_wlan_vendor_dcc_get_stats[] = { + [QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_CHANNEL_COUNT] = { + .type = NLA_U32 + }, + [QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_REQUEST_ARRAY] = { + .type = NLA_BINARY + }, +}; + +static const struct nla_policy qca_wlan_vendor_dcc_get_stats_resp[] = { + [QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_RESP_CHANNEL_COUNT] = { + .type = NLA_U32 + }, + [QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_RESP_STATS_ARRAY] = { + .type = NLA_BINARY + }, +}; + +static const struct nla_policy qca_wlan_vendor_dcc_clear_stats[] = { + [QCA_WLAN_VENDOR_ATTR_DCC_CLEAR_STATS_BITMAP] = { + .type = NLA_U32 + }, +}; + +static const struct nla_policy qca_wlan_vendor_dcc_update_ndl[ + QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_CHANNEL_COUNT] = { + .type = NLA_U32 + }, + [QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_CHANNEL_ARRAY] = { + .type = NLA_BINARY + }, + [QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_ACTIVE_STATE_ARRAY] = { + .type = NLA_BINARY + }, +}; + +/** + * struct wlan_hdd_ocb_config_channel + * @chan_freq: frequency of the channel + * @bandwidth: bandwidth of the channel, either 10 or 20 MHz + * @mac_address: MAC address assigned to this channel + * @qos_params: QoS parameters + * @max_pwr: maximum transmit power of the channel (1/2 dBm) + * @min_pwr: minimum transmit power of the channel (1/2 dBm) + */ +struct wlan_hdd_ocb_config_channel { + uint32_t chan_freq; + uint32_t bandwidth; + uint16_t flags; + uint8_t reserved[4]; + struct sir_qos_params qos_params[MAX_NUM_AC]; + uint32_t max_pwr; + uint32_t min_pwr; +}; + +static void wlan_hdd_ocb_config_channel_to_sir_ocb_config_channel( + struct sir_ocb_config_channel *dest, + struct wlan_hdd_ocb_config_channel *src, + uint32_t channel_count) +{ + uint32_t i; + + qdf_mem_zero(dest, channel_count * sizeof(*dest)); + + for (i = 0; i < channel_count; i++) { + dest[i].chan_freq = src[i].chan_freq; + dest[i].bandwidth = src[i].bandwidth; + qdf_mem_copy(dest[i].qos_params, src[i].qos_params, + sizeof(dest[i].qos_params)); + /* + * max_pwr and min_pwr are divided by 2 because + * wlan_hdd_ocb_config_channel.max_pwr and min_pwr + * are in 1/2 dB increments and + * sir_ocb_config_channel.max_pwr and min_pwr are in + * 1 dB increments. + */ + dest[i].max_pwr = src[i].max_pwr / 2; + dest[i].min_pwr = (src[i].min_pwr + 1) / 2; + dest[i].flags = src[i].flags; + } +} + +/** + * __wlan_hdd_cfg80211_ocb_set_config() - Interface for set config command + * @wiphy: pointer to the wiphy + * @wdev: pointer to the wdev + * @data: The netlink data + * @data_len: The length of the netlink data in bytes + * + * Return: 0 on success. + */ +static int __wlan_hdd_cfg80211_ocb_set_config(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + hdd_context_t *hdd_ctx = wiphy_priv(wiphy); + struct net_device *dev = wdev->netdev; + hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_MAX + 1]; + struct nlattr *channel_array; + struct nlattr *sched_array; + struct nlattr *ndl_chan_list; + uint32_t ndl_chan_list_len; + struct nlattr *ndl_active_state_list; + uint32_t ndl_active_state_list_len; + uint32_t flags = 0; + void *def_tx_param = NULL; + uint32_t def_tx_param_size = 0; + int i; + uint32_t channel_count, schedule_size; + struct sir_ocb_config *config; + int rc = -EINVAL; + uint8_t *mac_addr; + + ENTER_DEV(dev); + + if (wlan_hdd_validate_context(hdd_ctx)) + return -EINVAL; + + if (adapter->device_mode != QDF_OCB_MODE) { + hdd_err("Device not in OCB mode!"); + return -EINVAL; + } + + /* Parse the netlink message */ + if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_MAX, + data, + data_len, qca_wlan_vendor_ocb_set_config_policy)) { + hdd_err("Invalid ATTR"); + return -EINVAL; + } + + /* Get the number of channels in the schedule */ + if (!tb[QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_CHANNEL_COUNT]) { + hdd_err("CHANNEL_COUNT is not present"); + return -EINVAL; + } + channel_count = nla_get_u32( + tb[QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_CHANNEL_COUNT]); + + /* Get the size of the channel schedule */ + if (!tb[QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_SCHEDULE_SIZE]) { + hdd_err("SCHEDULE_SIZE is not present"); + return -EINVAL; + } + schedule_size = nla_get_u32( + tb[QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_SCHEDULE_SIZE]); + + /* Get the ndl chan array and the ndl active state array. */ + if (!tb[QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_NDL_CHANNEL_ARRAY]) { + hdd_err("NDL_CHANNEL_ARRAY is not present"); + return -EINVAL; + } + ndl_chan_list = + tb[QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_NDL_CHANNEL_ARRAY]; + ndl_chan_list_len = (ndl_chan_list ? nla_len(ndl_chan_list) : 0); + + if (!tb[QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_NDL_ACTIVE_STATE_ARRAY]) { + hdd_err("NDL_ACTIVE_STATE_ARRAY is not present"); + return -EINVAL; + } + ndl_active_state_list = + tb[QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_NDL_ACTIVE_STATE_ARRAY]; + ndl_active_state_list_len = (ndl_active_state_list ? + nla_len(ndl_active_state_list) : 0); + + /* Get the flags. This parameter is optional.*/ + if (tb[QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_FLAGS]) + flags = nla_get_u32(tb[ + QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_FLAGS]); +/* Get the default TX parameters. This parameter is optional. */ + if (tb[QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_DEF_TX_PARAM]) { + def_tx_param_size = nla_len(tb[ + QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_DEF_TX_PARAM]); + def_tx_param = nla_data(tb[ + QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_DEF_TX_PARAM]); + } + + config = hdd_ocb_config_new(channel_count, schedule_size, + ndl_chan_list_len, + ndl_active_state_list_len); + if (config == NULL) { + hdd_err("Failed to allocate memory!"); + return -ENOMEM; + } + + config->channel_count = channel_count; + config->schedule_size = schedule_size; + config->flags = flags; + config->def_tx_param = def_tx_param; + config->def_tx_param_size = def_tx_param_size; + + /* Read the channel array */ + if (!tb[QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_CHANNEL_ARRAY]) { + hdd_err("CHANNEL_ARRAY is not present"); + return -EINVAL; + } + channel_array = tb[QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_CHANNEL_ARRAY]; + if (!channel_array) { + hdd_err("No channel present"); + goto fail; + } + if (nla_len(channel_array) != channel_count * + sizeof(struct wlan_hdd_ocb_config_channel)) { + hdd_err("CHANNEL_ARRAY is not the correct size"); + goto fail; + } + wlan_hdd_ocb_config_channel_to_sir_ocb_config_channel( + config->channels, nla_data(channel_array), channel_count); + + /* Identify the vdev interface */ + config->session_id = adapter->sessionId; + + /* Release all the mac addresses used for OCB */ + for (i = 0; i < adapter->ocb_mac_addr_count; i++) { + wlan_hdd_release_intf_addr(adapter->pHddCtx, + adapter->ocb_mac_address[i].bytes); + } + adapter->ocb_mac_addr_count = 0; + + /* + * Setup locally administered mac addresses for each channel. + * First channel uses the adapter's address. + */ + for (i = 0; i < config->channel_count; i++) { + if (i == 0) { + qdf_copy_macaddr(&config->channels[i].mac_address, + &adapter->macAddressCurrent); + } else { + mac_addr = wlan_hdd_get_intf_addr(adapter->pHddCtx); + if (mac_addr == NULL) { + hdd_err("Cannot obtain mac address"); + goto fail; + } + qdf_mem_copy(config->channels[i].mac_address.bytes, + mac_addr, QDF_MAC_ADDR_SIZE); + /* Save the mac address to release later */ + qdf_copy_macaddr(&adapter->ocb_mac_address[ + adapter->ocb_mac_addr_count], + &config->channels[i].mac_address); + adapter->ocb_mac_addr_count++; + } + } + + /* Read the schedule array */ + sched_array = tb[QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_SCHEDULE_ARRAY]; + if (!sched_array) { + hdd_err("No channel present"); + goto fail; + } + if (nla_len(sched_array) != schedule_size * sizeof(*config->schedule)) { + hdd_err("SCHEDULE_ARRAY is not the correct size"); + goto fail; + } + qdf_mem_copy(config->schedule, nla_data(sched_array), + nla_len(sched_array)); + + /* Copy the NDL chan array */ + if (ndl_chan_list_len) { + config->dcc_ndl_chan_list_len = ndl_chan_list_len; + qdf_mem_copy(config->dcc_ndl_chan_list, nla_data(ndl_chan_list), + nla_len(ndl_chan_list)); + } + + /* Copy the NDL active state array */ + if (ndl_active_state_list_len) { + config->dcc_ndl_active_state_list_len = + ndl_active_state_list_len; + qdf_mem_copy(config->dcc_ndl_active_state_list, + nla_data(ndl_active_state_list), + nla_len(ndl_active_state_list)); + } + + rc = hdd_ocb_set_config_req(adapter, config); + if (rc) + hdd_err("Error while setting OCB config: %d", rc); + +fail: + qdf_mem_free(config); + return rc; +} + +/** + * wlan_hdd_cfg80211_ocb_set_config() - Interface for set config command + * @wiphy: pointer to the wiphy + * @wdev: pointer to the wdev + * @data: The netlink data + * @data_len: The length of the netlink data in bytes + * + * Return: 0 on success. + */ +int wlan_hdd_cfg80211_ocb_set_config(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_ocb_set_config(wiphy, wdev, data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __wlan_hdd_cfg80211_ocb_set_utc_time() - Interface for set UTC time command + * @wiphy: pointer to the wiphy + * @wdev: pointer to the wdev + * @data: The netlink data + * @data_len: The length of the netlink data in bytes + * + * Return: 0 on success. + */ +static int __wlan_hdd_cfg80211_ocb_set_utc_time(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + hdd_context_t *hdd_ctx = wiphy_priv(wiphy); + struct net_device *dev = wdev->netdev; + hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_OCB_SET_UTC_TIME_MAX + 1]; + struct nlattr *utc_attr; + struct nlattr *time_error_attr; + struct sir_ocb_utc *utc; + int rc = -EINVAL; + + ENTER_DEV(dev); + + if (wlan_hdd_validate_context(hdd_ctx)) + return -EINVAL; + + if (adapter->device_mode != QDF_OCB_MODE) { + hdd_err("Device not in OCB mode!"); + return -EINVAL; + } + + if (!wma_is_vdev_up(adapter->sessionId)) { + hdd_err("The device has not been started"); + return -EINVAL; + } + + /* Parse the netlink message */ + if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_OCB_SET_UTC_TIME_MAX, + data, + data_len, qca_wlan_vendor_ocb_set_utc_time_policy)) { + hdd_err("Invalid ATTR"); + return -EINVAL; + } + + /* Read the UTC time */ + utc_attr = tb[QCA_WLAN_VENDOR_ATTR_OCB_SET_UTC_TIME_VALUE]; + if (!utc_attr) { + hdd_err("UTC_TIME is not present"); + return -EINVAL; + } + if (nla_len(utc_attr) != SIZE_UTC_TIME) { + hdd_err("UTC_TIME is not the correct size"); + return -EINVAL; + } + + /* Read the time error */ + time_error_attr = tb[QCA_WLAN_VENDOR_ATTR_OCB_SET_UTC_TIME_ERROR]; + if (!time_error_attr) { + hdd_err("UTC_TIME is not present"); + return -EINVAL; + } + if (nla_len(time_error_attr) != SIZE_UTC_TIME_ERROR) { + hdd_err("UTC_TIME is not the correct size"); + return -EINVAL; + } + + utc = qdf_mem_malloc(sizeof(*utc)); + if (!utc) { + hdd_err("qdf_mem_malloc failed"); + return -ENOMEM; + } + utc->vdev_id = adapter->sessionId; + qdf_mem_copy(utc->utc_time, nla_data(utc_attr), SIZE_UTC_TIME); + qdf_mem_copy(utc->time_error, nla_data(time_error_attr), + SIZE_UTC_TIME_ERROR); + + if (sme_ocb_set_utc_time(hdd_ctx->hHal, utc) != QDF_STATUS_SUCCESS) { + hdd_err("Error while setting UTC time"); + rc = -EINVAL; + } else { + rc = 0; + } + + qdf_mem_free(utc); + return rc; +} + +/** + * wlan_hdd_cfg80211_ocb_set_utc_time() - Interface for the set UTC time command + * @wiphy: pointer to the wiphy + * @wdev: pointer to the wdev + * @data: The netlink data + * @data_len: The length of the netlink data in bytes + * + * Return: 0 on success. + */ +int wlan_hdd_cfg80211_ocb_set_utc_time(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_ocb_set_utc_time(wiphy, wdev, data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __wlan_hdd_cfg80211_ocb_start_timing_advert() - Interface for start TA cmd + * @wiphy: pointer to the wiphy + * @wdev: pointer to the wdev + * @data: The netlink data + * @data_len: The length of the netlink data in bytes + * + * Return: 0 on success. + */ +static int +__wlan_hdd_cfg80211_ocb_start_timing_advert(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + hdd_context_t *hdd_ctx = wiphy_priv(wiphy); + struct net_device *dev = wdev->netdev; + hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_OCB_START_TIMING_ADVERT_MAX + 1]; + struct sir_ocb_timing_advert *timing_advert; + int rc = -EINVAL; + + ENTER_DEV(dev); + + if (wlan_hdd_validate_context(hdd_ctx)) + return -EINVAL; + + if (adapter->device_mode != QDF_OCB_MODE) { + hdd_err("Device not in OCB mode!"); + return -EINVAL; + } + + if (!wma_is_vdev_up(adapter->sessionId)) { + hdd_err("The device has not been started"); + return -EINVAL; + } + + timing_advert = qdf_mem_malloc(sizeof(*timing_advert)); + if (!timing_advert) { + hdd_err("qdf_mem_malloc failed"); + return -ENOMEM; + } + timing_advert->vdev_id = adapter->sessionId; + + /* Parse the netlink message */ + if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_OCB_START_TIMING_ADVERT_MAX, + data, + data_len, + qca_wlan_vendor_ocb_start_timing_advert_policy)) { + hdd_err("Invalid ATTR"); + goto fail; + } + + if (!tb[QCA_WLAN_VENDOR_ATTR_OCB_START_TIMING_ADVERT_CHANNEL_FREQ]) { + hdd_err("CHANNEL_FREQ is not present"); + goto fail; + } + timing_advert->chan_freq = nla_get_u32( + tb[QCA_WLAN_VENDOR_ATTR_OCB_START_TIMING_ADVERT_CHANNEL_FREQ]); + + if (!tb[QCA_WLAN_VENDOR_ATTR_OCB_START_TIMING_ADVERT_REPEAT_RATE]) { + hdd_err("REPEAT_RATE is not present"); + goto fail; + } + timing_advert->repeat_rate = nla_get_u32( + tb[QCA_WLAN_VENDOR_ATTR_OCB_START_TIMING_ADVERT_REPEAT_RATE]); + + timing_advert->template_length = + sme_ocb_gen_timing_advert_frame(hdd_ctx->hHal, + *(tSirMacAddr *)&adapter->macAddressCurrent.bytes, + &timing_advert->template_value, + &timing_advert->timestamp_offset, + &timing_advert->time_value_offset); + if (timing_advert->template_length <= 0) { + hdd_err("Error while generating the TA frame"); + goto fail; + } + + if (sme_ocb_start_timing_advert(hdd_ctx->hHal, timing_advert) != + QDF_STATUS_SUCCESS) { + hdd_err("Error while starting timing advert"); + rc = -EINVAL; + } else { + rc = 0; + } + +fail: + if (timing_advert->template_value) + qdf_mem_free(timing_advert->template_value); + qdf_mem_free(timing_advert); + return rc; +} + +/** + * wlan_hdd_cfg80211_ocb_start_timing_advert() - Interface for the start TA cmd + * @wiphy: pointer to the wiphy + * @wdev: pointer to the wdev + * @data: The netlink data + * @data_len: The length of the netlink data in bytes + * + * Return: 0 on success. + */ +int wlan_hdd_cfg80211_ocb_start_timing_advert(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_ocb_start_timing_advert(wiphy, wdev, + data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __wlan_hdd_cfg80211_ocb_stop_timing_advert() - Interface for the stop TA cmd + * @wiphy: pointer to the wiphy + * @wdev: pointer to the wdev + * @data: The netlink data + * @data_len: The length of the netlink data in bytes + * + * Return: 0 on success. + */ +static int +__wlan_hdd_cfg80211_ocb_stop_timing_advert(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + hdd_context_t *hdd_ctx = wiphy_priv(wiphy); + struct net_device *dev = wdev->netdev; + hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_OCB_STOP_TIMING_ADVERT_MAX + 1]; + struct sir_ocb_timing_advert *timing_advert; + int rc = -EINVAL; + + ENTER_DEV(dev); + + if (wlan_hdd_validate_context(hdd_ctx)) + return -EINVAL; + + if (adapter->device_mode != QDF_OCB_MODE) { + hdd_err("Device not in OCB mode!"); + return -EINVAL; + } + + if (!wma_is_vdev_up(adapter->sessionId)) { + hdd_err("The device has not been started"); + return -EINVAL; + } + + timing_advert = qdf_mem_malloc(sizeof(*timing_advert)); + if (!timing_advert) { + hdd_err("qdf_mem_malloc failed"); + return -ENOMEM; + } + timing_advert->vdev_id = adapter->sessionId; + + /* Parse the netlink message */ + if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_OCB_STOP_TIMING_ADVERT_MAX, + data, + data_len, + qca_wlan_vendor_ocb_stop_timing_advert_policy)) { + hdd_err("Invalid ATTR"); + goto fail; + } + + if (!tb[QCA_WLAN_VENDOR_ATTR_OCB_STOP_TIMING_ADVERT_CHANNEL_FREQ]) { + hdd_err("CHANNEL_FREQ is not present"); + goto fail; + } + timing_advert->chan_freq = nla_get_u32( + tb[QCA_WLAN_VENDOR_ATTR_OCB_STOP_TIMING_ADVERT_CHANNEL_FREQ]); + + if (sme_ocb_stop_timing_advert(hdd_ctx->hHal, timing_advert) != + QDF_STATUS_SUCCESS) { + hdd_err("Error while stopping timing advert"); + rc = -EINVAL; + } else { + rc = 0; + } + +fail: + qdf_mem_free(timing_advert); + return rc; +} + +/** + * wlan_hdd_cfg80211_ocb_stop_timing_advert() - Interface for the stop TA cmd + * @wiphy: pointer to the wiphy + * @wdev: pointer to the wdev + * @data: The netlink data + * @data_len: The length of the netlink data in bytes + * + * Return: 0 on success. + */ +int wlan_hdd_cfg80211_ocb_stop_timing_advert(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_ocb_stop_timing_advert(wiphy, wdev, + data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * hdd_ocb_get_tsf_timer_callback() - Callback to get TSF command + * @context_ptr: request context + * @response_ptr: response data + */ +static void hdd_ocb_get_tsf_timer_callback(void *context_ptr, + void *response_ptr) +{ + struct hdd_ocb_ctxt *context = context_ptr; + struct sir_ocb_get_tsf_timer_response *response = response_ptr; + + if (!context) + return; + + spin_lock(&hdd_context_lock); + if (context->magic == HDD_OCB_MAGIC) { + if (response) { + context->adapter->ocb_get_tsf_timer_resp = *response; + context->status = 0; + } else { + context->status = -EINVAL; + } + complete(&context->completion_evt); + } + spin_unlock(&hdd_context_lock); +} + +/** + * __wlan_hdd_cfg80211_ocb_get_tsf_timer() - Interface for get TSF timer cmd + * @wiphy: pointer to the wiphy + * @wdev: pointer to the wdev + * @data: The netlink data + * @data_len: The length of the netlink data in bytes + * + * Return: 0 on success. + */ +static int +__wlan_hdd_cfg80211_ocb_get_tsf_timer(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + struct sk_buff *nl_resp = 0; + hdd_context_t *hdd_ctx = wiphy_priv(wiphy); + struct net_device *dev = wdev->netdev; + hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + int rc = -EINVAL; + struct sir_ocb_get_tsf_timer request = {0}; + struct hdd_ocb_ctxt context = {0}; + + ENTER_DEV(dev); + + if (wlan_hdd_validate_context(hdd_ctx)) + return -EINVAL; + + if (adapter->device_mode != QDF_OCB_MODE) { + hdd_err("Device not in OCB mode!"); + return -EINVAL; + } + + if (!wma_is_vdev_up(adapter->sessionId)) { + hdd_err("The device has not been started"); + return -EINVAL; + } + + /* Initialize the callback context */ + init_completion(&context.completion_evt); + context.adapter = adapter; + context.magic = HDD_OCB_MAGIC; + + request.vdev_id = adapter->sessionId; + /* Call the SME function */ + rc = sme_ocb_get_tsf_timer(hdd_ctx->hHal, &context, + hdd_ocb_get_tsf_timer_callback, + &request); + if (rc) { + hdd_err("Error calling SME function"); + /* Need to convert from qdf_status to errno. */ + return -EINVAL; + } + + rc = wait_for_completion_timeout(&context.completion_evt, + msecs_to_jiffies(WLAN_WAIT_TIME_OCB_CMD)); + if (rc == 0) { + hdd_err("Operation timed out"); + rc = -ETIMEDOUT; + goto end; + } + rc = 0; + + if (context.status) { + hdd_err("Operation failed: %d", context.status); + rc = context.status; + goto end; + } + + /* Allocate the buffer for the response. */ + nl_resp = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, + 2 * sizeof(uint32_t) + NLMSG_HDRLEN); + + if (!nl_resp) { + hdd_err("cfg80211_vendor_cmd_alloc_reply_skb failed"); + rc = -ENOMEM; + goto end; + } + + hdd_notice("Got TSF timer response, high=%d, low=%d", + adapter->ocb_get_tsf_timer_resp.timer_high, + adapter->ocb_get_tsf_timer_resp.timer_low); + + /* Populate the response. */ + rc = nla_put_u32(nl_resp, + QCA_WLAN_VENDOR_ATTR_OCB_GET_TSF_RESP_TIMER_HIGH, + adapter->ocb_get_tsf_timer_resp.timer_high); + if (rc) + goto end; + rc = nla_put_u32(nl_resp, + QCA_WLAN_VENDOR_ATTR_OCB_GET_TSF_RESP_TIMER_LOW, + adapter->ocb_get_tsf_timer_resp.timer_low); + if (rc) + goto end; + + /* Send the response. */ + rc = cfg80211_vendor_cmd_reply(nl_resp); + nl_resp = NULL; + if (rc) { + hdd_err("cfg80211_vendor_cmd_reply failed: %d", rc); + goto end; + } + +end: + spin_lock(&hdd_context_lock); + context.magic = 0; + spin_unlock(&hdd_context_lock); + if (nl_resp) + kfree_skb(nl_resp); + return rc; +} + +/** + * wlan_hdd_cfg80211_ocb_get_tsf_timer() - Interface for get TSF timer cmd + * @wiphy: pointer to the wiphy + * @wdev: pointer to the wdev + * @data: The netlink data + * @data_len: The length of the netlink data in bytes + * + * Return: 0 on success. + */ +int wlan_hdd_cfg80211_ocb_get_tsf_timer(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_ocb_get_tsf_timer(wiphy, wdev, + data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * hdd_dcc_get_stats_callback() - Callback to get stats command + * @context_ptr: request context + * @response_ptr: response data + */ +static void hdd_dcc_get_stats_callback(void *context_ptr, void *response_ptr) +{ + struct hdd_ocb_ctxt *context = context_ptr; + struct sir_dcc_get_stats_response *response = response_ptr; + struct sir_dcc_get_stats_response *hdd_resp; + + if (!context) + return; + + spin_lock(&hdd_context_lock); + if (context->magic == HDD_OCB_MAGIC) { + if (response) { + /* + * If the response is hanging around from the previous + * request, delete it + */ + if (context->adapter->dcc_get_stats_resp) { + qdf_mem_free( + context->adapter->dcc_get_stats_resp); + } + context->adapter->dcc_get_stats_resp = + qdf_mem_malloc(sizeof( + *context->adapter->dcc_get_stats_resp) + + response->channel_stats_array_len); + if (context->adapter->dcc_get_stats_resp) { + hdd_resp = context->adapter->dcc_get_stats_resp; + *hdd_resp = *response; + hdd_resp->channel_stats_array = + (void *)hdd_resp + sizeof(*hdd_resp); + qdf_mem_copy(hdd_resp->channel_stats_array, + response->channel_stats_array, + response->channel_stats_array_len); + context->status = 0; + } else { + context->status = -ENOMEM; + } + } else { + context->status = -EINVAL; + } + complete(&context->completion_evt); + } + spin_unlock(&hdd_context_lock); +} + +/** + * __wlan_hdd_cfg80211_dcc_get_stats() - Interface for get dcc stats + * @wiphy: pointer to the wiphy + * @wdev: pointer to the wdev + * @data: The netlink data + * @data_len: The length of the netlink data in bytes + * + * Return: 0 on success. + */ +static int __wlan_hdd_cfg80211_dcc_get_stats(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + uint32_t channel_count = 0; + uint32_t request_array_len = 0; + void *request_array = 0; + hdd_context_t *hdd_ctx = wiphy_priv(wiphy); + struct net_device *dev = wdev->netdev; + hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_MAX + 1]; + struct sk_buff *nl_resp = 0; + int rc = -EINVAL; + struct sir_dcc_get_stats request = {0}; + struct hdd_ocb_ctxt context = {0}; + + ENTER_DEV(dev); + + if (wlan_hdd_validate_context(hdd_ctx)) + return -EINVAL; + + if (adapter->device_mode != QDF_OCB_MODE) { + hdd_err("Device not in OCB mode!"); + return -EINVAL; + } + + if (!wma_is_vdev_up(adapter->sessionId)) { + hdd_err("The device has not been started"); + return -EINVAL; + } + + /* Parse the netlink message */ + if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_MAX, + data, + data_len, + qca_wlan_vendor_dcc_get_stats)) { + hdd_err("Invalid ATTR"); + return -EINVAL; + } + + /* Validate all the parameters are present */ + if (!tb[QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_CHANNEL_COUNT] || + !tb[QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_REQUEST_ARRAY]) { + hdd_err("Parameters are not present."); + return -EINVAL; + } + + channel_count = nla_get_u32( + tb[QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_CHANNEL_COUNT]); + request_array_len = nla_len( + tb[QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_REQUEST_ARRAY]); + request_array = nla_data( + tb[QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_REQUEST_ARRAY]); + + /* Initialize the callback context */ + init_completion(&context.completion_evt); + context.adapter = adapter; + context.magic = HDD_OCB_MAGIC; + + request.vdev_id = adapter->sessionId; + request.channel_count = channel_count; + request.request_array_len = request_array_len; + request.request_array = request_array; + + /* Call the SME function. */ + rc = sme_dcc_get_stats(hdd_ctx->hHal, &context, + hdd_dcc_get_stats_callback, + &request); + if (rc) { + hdd_err("Error calling SME function"); + /* Need to convert from qdf_status to errno. */ + return -EINVAL; + } + + /* Wait for the function to complete. */ + rc = wait_for_completion_timeout(&context.completion_evt, + msecs_to_jiffies(WLAN_WAIT_TIME_OCB_CMD)); + if (rc == 0) { + hdd_err("Operation failed: %d", rc); + rc = -ETIMEDOUT; + goto end; + } + + if (context.status) { + hdd_err("There was error: %d", context.status); + rc = context.status; + goto end; + } + + if (!adapter->dcc_get_stats_resp) { + hdd_err("The response was NULL"); + rc = -EINVAL; + goto end; + } + + /* Allocate the buffer for the response. */ + nl_resp = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, sizeof(uint32_t) + + adapter->dcc_get_stats_resp->channel_stats_array_len + + NLMSG_HDRLEN); + if (!nl_resp) { + hdd_err("cfg80211_vendor_cmd_alloc_reply_skb failed"); + rc = -ENOMEM; + goto end; + } + + /* Populate the response. */ + rc = nla_put_u32(nl_resp, + QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_RESP_CHANNEL_COUNT, + adapter->dcc_get_stats_resp->num_channels); + if (rc) + goto end; + rc = nla_put(nl_resp, + QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_RESP_STATS_ARRAY, + adapter->dcc_get_stats_resp->channel_stats_array_len, + adapter->dcc_get_stats_resp->channel_stats_array); + if (rc) + goto end; + + /* Send the response. */ + rc = cfg80211_vendor_cmd_reply(nl_resp); + nl_resp = NULL; + if (rc) { + hdd_err("cfg80211_vendor_cmd_reply failed: %d", rc); + goto end; + } + + /* fall through */ +end: + spin_lock(&hdd_context_lock); + context.magic = 0; + qdf_mem_free(adapter->dcc_get_stats_resp); + adapter->dcc_get_stats_resp = NULL; + spin_unlock(&hdd_context_lock); + if (nl_resp) + kfree_skb(nl_resp); + return rc; +} + +/** + * wlan_hdd_cfg80211_dcc_get_stats() - Interface for get dcc stats + * @wiphy: pointer to the wiphy + * @wdev: pointer to the wdev + * @data: The netlink data + * @data_len: The length of the netlink data in bytes + * + * Return: 0 on success. + */ +int wlan_hdd_cfg80211_dcc_get_stats(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_dcc_get_stats(wiphy, wdev, + data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __wlan_hdd_cfg80211_dcc_clear_stats() - Interface for clear dcc stats cmd + * @wiphy: pointer to the wiphy + * @wdev: pointer to the wdev + * @data: The netlink data + * @data_len: The length of the netlink data in bytes + * + * Return: 0 on success. + */ +static int __wlan_hdd_cfg80211_dcc_clear_stats(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + hdd_context_t *hdd_ctx = wiphy_priv(wiphy); + struct net_device *dev = wdev->netdev; + hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_DCC_CLEAR_STATS_MAX + 1]; + + ENTER_DEV(dev); + + if (wlan_hdd_validate_context(hdd_ctx)) + return -EINVAL; + + if (adapter->device_mode != QDF_OCB_MODE) { + hdd_err("Device not in OCB mode!"); + return -EINVAL; + } + + if (!wma_is_vdev_up(adapter->sessionId)) { + hdd_err("The device has not been started"); + return -EINVAL; + } + + /* Parse the netlink message */ + if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_DCC_CLEAR_STATS_MAX, + data, + data_len, + qca_wlan_vendor_dcc_clear_stats)) { + hdd_err("Invalid ATTR"); + return -EINVAL; + } + + /* Verify that the parameter is present */ + if (!tb[QCA_WLAN_VENDOR_ATTR_DCC_CLEAR_STATS_BITMAP]) { + hdd_err("Parameters are not present."); + return -EINVAL; + } + + /* Call the SME function */ + if (sme_dcc_clear_stats(hdd_ctx->hHal, adapter->sessionId, + nla_get_u32( + tb[QCA_WLAN_VENDOR_ATTR_DCC_CLEAR_STATS_BITMAP])) != + QDF_STATUS_SUCCESS) { + hdd_err("Error calling SME function."); + return -EINVAL; + } + + return 0; +} + +/** + * wlan_hdd_cfg80211_dcc_clear_stats() - Interface for clear dcc stats cmd + * @wiphy: pointer to the wiphy + * @wdev: pointer to the wdev + * @data: The netlink data + * @data_len: The length of the netlink data in bytes + * + * Return: 0 on success. + */ +int wlan_hdd_cfg80211_dcc_clear_stats(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_dcc_clear_stats(wiphy, wdev, + data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * hdd_dcc_update_ndl_callback() - Callback to update NDL command + * @context_ptr: request context + * @response_ptr: response data + */ +static void hdd_dcc_update_ndl_callback(void *context_ptr, void *response_ptr) +{ + struct hdd_ocb_ctxt *context = context_ptr; + struct sir_dcc_update_ndl_response *response = response_ptr; + + if (!context) + return; + + spin_lock(&hdd_context_lock); + if (context->magic == HDD_OCB_MAGIC) { + if (response) { + context->adapter->dcc_update_ndl_resp = *response; + context->status = 0; + } else { + context->status = -EINVAL; + } + complete(&context->completion_evt); + } + spin_unlock(&hdd_context_lock); +} + +/** + * __wlan_hdd_cfg80211_dcc_update_ndl() - Interface for update dcc cmd + * @wiphy: pointer to the wiphy + * @wdev: pointer to the wdev + * @data: The netlink data + * @data_len: The length of the netlink data in bytes + * + * Return: 0 on success. + */ +static int __wlan_hdd_cfg80211_dcc_update_ndl(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + hdd_context_t *hdd_ctx = wiphy_priv(wiphy); + struct net_device *dev = wdev->netdev; + hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_MAX + 1]; + struct sir_dcc_update_ndl request; + uint32_t channel_count; + uint32_t ndl_channel_array_len; + void *ndl_channel_array; + uint32_t ndl_active_state_array_len; + void *ndl_active_state_array; + int rc = -EINVAL; + struct hdd_ocb_ctxt context = {0}; + + ENTER_DEV(dev); + + if (wlan_hdd_validate_context(hdd_ctx)) + goto end; + + if (adapter->device_mode != QDF_OCB_MODE) { + hdd_err("Device not in OCB mode!"); + goto end; + } + + if (!wma_is_vdev_up(adapter->sessionId)) { + hdd_err("The device has not been started"); + return -EINVAL; + } + + /* Parse the netlink message */ + if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_MAX, + data, + data_len, + qca_wlan_vendor_dcc_update_ndl)) { + hdd_err("Invalid ATTR"); + goto end; + } + + /* Verify that the parameter is present */ + if (!tb[QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_CHANNEL_COUNT] || + !tb[QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_CHANNEL_ARRAY] || + !tb[QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_ACTIVE_STATE_ARRAY]) { + hdd_err("Parameters are not present."); + return -EINVAL; + } + + channel_count = nla_get_u32( + tb[QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_CHANNEL_COUNT]); + ndl_channel_array_len = nla_len( + tb[QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_CHANNEL_ARRAY]); + ndl_channel_array = nla_data( + tb[QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_CHANNEL_ARRAY]); + ndl_active_state_array_len = nla_len( + tb[QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_ACTIVE_STATE_ARRAY]); + ndl_active_state_array = nla_data( + tb[QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_ACTIVE_STATE_ARRAY]); + + /* Initialize the callback context */ + init_completion(&context.completion_evt); + context.adapter = adapter; + context.magic = HDD_OCB_MAGIC; + + /* Copy the parameters to the request structure. */ + request.vdev_id = adapter->sessionId; + request.channel_count = channel_count; + request.dcc_ndl_chan_list_len = ndl_channel_array_len; + request.dcc_ndl_chan_list = ndl_channel_array; + request.dcc_ndl_active_state_list_len = ndl_active_state_array_len; + request.dcc_ndl_active_state_list = ndl_active_state_array; + + /* Call the SME function */ + rc = sme_dcc_update_ndl(hdd_ctx->hHal, &context, + hdd_dcc_update_ndl_callback, + &request); + if (rc) { + hdd_err("Error calling SME function."); + /* Convert from qdf_status to errno */ + return -EINVAL; + } + + /* Wait for the function to complete. */ + rc = wait_for_completion_timeout(&context.completion_evt, + msecs_to_jiffies(WLAN_WAIT_TIME_OCB_CMD)); + if (rc == 0) { + hdd_err("Operation timed out"); + rc = -ETIMEDOUT; + goto end; + } + rc = 0; + + if (context.status) { + hdd_err("Operation failed: %d", context.status); + rc = context.status; + goto end; + } + + if (adapter->dcc_update_ndl_resp.status) { + hdd_err("Operation returned: %d", + adapter->dcc_update_ndl_resp.status); + rc = -EINVAL; + goto end; + } + + /* fall through */ +end: + spin_lock(&hdd_context_lock); + context.magic = 0; + spin_unlock(&hdd_context_lock); + return rc; +} + +/** + * wlan_hdd_cfg80211_dcc_update_ndl() - Interface for update dcc cmd + * @wiphy: pointer to the wiphy + * @wdev: pointer to the wdev + * @data: The netlink data + * @data_len: The length of the netlink data in bytes + * + * Return: 0 on success. + */ +int wlan_hdd_cfg80211_dcc_update_ndl(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_dcc_update_ndl(wiphy, wdev, + data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * wlan_hdd_dcc_stats_event_callback() - Callback to get stats event + * @context_ptr: request context + * @response_ptr: response data + */ +static void wlan_hdd_dcc_stats_event_callback(void *context_ptr, + void *response_ptr) +{ + hdd_context_t *hdd_ctx = (hdd_context_t *)context_ptr; + struct sir_dcc_get_stats_response *resp = response_ptr; + struct sk_buff *vendor_event; + + ENTER(); + + vendor_event = + cfg80211_vendor_event_alloc(hdd_ctx->wiphy, + NULL, sizeof(uint32_t) + resp->channel_stats_array_len + + NLMSG_HDRLEN, + QCA_NL80211_VENDOR_SUBCMD_DCC_STATS_EVENT_INDEX, + GFP_KERNEL); + + if (!vendor_event) { + hdd_err("cfg80211_vendor_event_alloc failed"); + return; + } + + if (nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_RESP_CHANNEL_COUNT, + resp->num_channels) || + nla_put(vendor_event, + QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_RESP_STATS_ARRAY, + resp->channel_stats_array_len, + resp->channel_stats_array)) { + hdd_err("nla put failed"); + kfree_skb(vendor_event); + return; + } + + cfg80211_vendor_event(vendor_event, GFP_KERNEL); +} + +/** + * wlan_hdd_dcc_register_for_dcc_stats_event() - Register for dcc stats events + * @hdd_ctx: hdd context + */ +void wlan_hdd_dcc_register_for_dcc_stats_event(hdd_context_t *hdd_ctx) +{ + int rc; + + rc = sme_register_for_dcc_stats_event(hdd_ctx->hHal, hdd_ctx, + wlan_hdd_dcc_stats_event_callback); + if (rc) + hdd_err("Register callback failed: %d", rc); +} diff --git a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_ocb.h b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_ocb.h new file mode 100644 index 0000000000000000000000000000000000000000..b76c7fd0c495949737b1d6413d058780305ecd67 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_ocb.h @@ -0,0 +1,391 @@ +/* + * Copyright (c) 2015-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef __WLAN_HDD_OCB_H +#define __WLAN_HDD_OCB_H + +#include +#include "sir_api.h" + +#define WLAN_OCB_CHANNEL_MAX 5 + +/** + * struct ocb_qos_params - QoS Parameters for each AC + * @aifsn: Arbitration Inter-Frame Spacing + * @cwmin: Contention Window (Min) + * @cwmax: Contention Window (Max) + */ +struct ocb_qos_params { + uint8_t aifsn; + uint8_t cwmin; + uint8_t cwmax; +}; + +/** + * struct ocb_channel - Parameters for each OCB channel + * @channel_freq: Channel Center Frequency (MHz) + * @duration: Channel Duration (ms) + * @start_guard_interval: Start Guard Interval (ms) + * @channel_bandwidth: Channel Bandwidth (MHz) + * @tx_power: Transmit Power (1/2 dBm) + * @tx_rate: Transmit Data Rate (mbit) + * @qos_params: Array of QoS Parameters + * @per_packet_rx_stats: Enable per packet RX statistics + */ +struct ocb_channel { + uint32_t channel_freq; + uint32_t duration; + uint32_t start_guard_interval; + uint32_t channel_bandwidth; + uint32_t tx_power; + uint32_t tx_rate; + struct ocb_qos_params qos_params[MAX_NUM_AC]; + uint32_t per_packet_rx_stats; +}; + +/** + * struct dot11p_channel_sched - OCB channel schedule + * @num_channels: Number of channels + * @channels: Array of channel parameters + * @off_channel_tx: Enable off channel TX + */ +struct dot11p_channel_sched { + uint32_t num_channels; + struct ocb_channel channels[WLAN_OCB_CHANNEL_MAX]; + uint32_t off_channel_tx; +}; + +/** + * enum qca_wlan_vendor_attr_ocb_set_config - vendor subcmd to set ocb config + * @QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_CHANNEL_COUNT: + * number of channels in the configuration + * @QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_SCHEDULE_SIZE: size of the schedule + * @QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_CHANNEL_ARRAY: array of channels + * @QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_SCHEDULE_ARRAY: + * array of channels to be scheduled + * @QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_NDL_CHANNEL_ARRAY: + * array of NDL channel information + * @QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_NDL_ACTIVE_STATE_ARRAY: + * array of NDL active state configuration + * @QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_FLAGS: + * flag to set the absolute expiry + * configuration flags such as OCB_CONFIG_FLAG_80211_FRAME_MODE + * @QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_DEF_TX_PARAM: + * default TX parameters to use in the case that a packet is sent without + * a TX control header + */ +enum qca_wlan_vendor_attr_ocb_set_config { + QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_CHANNEL_COUNT, + QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_SCHEDULE_SIZE, + QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_CHANNEL_ARRAY, + QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_SCHEDULE_ARRAY, + QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_NDL_CHANNEL_ARRAY, + QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_NDL_ACTIVE_STATE_ARRAY, + QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_FLAGS, + QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_DEF_TX_PARAM, + QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_MAX = + QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_AFTER_LAST - 1, +}; + +/** + * enum qca_wlan_vendor_attr_ocb_set_utc_time - vendor subcmd to set UTC time + * @QCA_WLAN_VENDOR_ATTR_OCB_SET_UTC_TIME_VALUE: + * the UTC time as an array of 10 bytes + * @QCA_WLAN_VENDOR_ATTR_OCB_SET_UTC_TIME_ERROR: + * the time error as an array of 5 bytes + */ +enum qca_wlan_vendor_attr_ocb_set_utc_time { + QCA_WLAN_VENDOR_ATTR_OCB_SET_UTC_TIME_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_OCB_SET_UTC_TIME_VALUE, + QCA_WLAN_VENDOR_ATTR_OCB_SET_UTC_TIME_ERROR, + QCA_WLAN_VENDOR_ATTR_OCB_SET_UTC_TIME_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_OCB_SET_UTC_TIME_MAX = + QCA_WLAN_VENDOR_ATTR_OCB_SET_UTC_TIME_AFTER_LAST - 1, +}; + +/** + * enum qca_wlan_vendor_attr_ocb_start_timing_advert - vendor subcmd to start + sending timing advert + frames + * @QCA_WLAN_VENDOR_ATTR_OCB_START_TIMING_ADVERT_CHANNEL_FREQ: + * channel frequency on which to send the frames + * @QCA_WLAN_VENDOR_ATTR_OCB_START_TIMING_ADVERT_REPEAT_RATE: + * number of times the frame is sent in 5 seconds + */ +enum qca_wlan_vendor_attr_ocb_start_timing_advert { + QCA_WLAN_VENDOR_ATTR_OCB_START_TIMING_ADVERT_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_OCB_START_TIMING_ADVERT_CHANNEL_FREQ, + QCA_WLAN_VENDOR_ATTR_OCB_START_TIMING_ADVERT_REPEAT_RATE, + QCA_WLAN_VENDOR_ATTR_OCB_START_TIMING_ADVERT_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_OCB_START_TIMING_ADVERT_MAX = + QCA_WLAN_VENDOR_ATTR_OCB_START_TIMING_ADVERT_AFTER_LAST - 1, +}; + +/** + * enum qca_wlan_vendor_attr_ocb_stop_timing_advert - vendor subcmd to stop + * timing advert + * @QCA_WLAN_VENDOR_ATTR_OCB_STOP_TIMING_ADVERT_CHANNEL_FREQ: + * the channel frequency on which to stop the timing advert + */ +enum qca_wlan_vendor_attr_ocb_stop_timing_advert { + QCA_WLAN_VENDOR_ATTR_OCB_STOP_TIMING_ADVERT_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_OCB_STOP_TIMING_ADVERT_CHANNEL_FREQ, + QCA_WLAN_VENDOR_ATTR_OCB_STOP_TIMING_ADVERT_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_OCB_STOP_TIMING_ADVERT_MAX = + QCA_WLAN_VENDOR_ATTR_OCB_STOP_TIMING_ADVERT_AFTER_LAST - 1, +}; + +/** + * enum qca_wlan_vendor_attr_dcc_get_tsf_response - vendor subcmd to get TSF + * timer value + * @QCA_WLAN_VENDOR_ATTR_OCB_GET_TSF_RESP_TIMER_HIGH: + * higher 32 bits of the timer + * @QCA_WLAN_VENDOR_ATTR_OCB_GET_TSF_RESP_TIMER_LOW: + * lower 32 bits of the timer + */ +enum qca_wlan_vendor_attr_ocb_get_tsf_resp { + QCA_WLAN_VENDOR_ATTR_OCB_GET_TSF_RESP_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_OCB_GET_TSF_RESP_TIMER_HIGH, + QCA_WLAN_VENDOR_ATTR_OCB_GET_TSF_RESP_TIMER_LOW, + QCA_WLAN_VENDOR_ATTR_OCB_GET_TSF_RESP_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_OCB_GET_TSF_RESP_MAX = + QCA_WLAN_VENDOR_ATTR_OCB_GET_TSF_RESP_AFTER_LAST - 1, +}; + +/** + * enum qca_wlan_vendor_attr_dcc_get_stats - vendor subcmd to get + * dcc stats + * @QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_CHANNEL_COUNT: + * the number of channels in the request array + * @QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_REQUEST_ARRAY + * array of the channel and information being requested + */ +enum qca_wlan_vendor_attr_dcc_get_stats { + QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_CHANNEL_COUNT, + QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_REQUEST_ARRAY, + QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_MAX = + QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_AFTER_LAST - 1, +}; + +/** + * enum qca_wlan_vendor_attr_dcc_get_stats_resp - response event from get + * dcc stats + * @QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_RESP_CHANNEL_COUNT: + * the number of channels in the request array + * @QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_RESP_STATS_ARRAY + * array of the information being requested + */ +enum qca_wlan_vendor_attr_dcc_get_stats_resp { + QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_RESP_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_RESP_CHANNEL_COUNT, + QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_RESP_STATS_ARRAY, + QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_RESP_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_RESP_MAX = + QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_RESP_AFTER_LAST - 1, +}; + +/** + * enum qca_wlan_vendor_attr_dcc_clear_stats - vendor subcmd to clear DCC stats + * @QCA_WLAN_VENDOR_ATTR_DCC_CLEAR_STATS_BITMAP: + * mask of the type of stats to be cleared + */ +enum qca_wlan_vendor_attr_dcc_clear_stats { + QCA_WLAN_VENDOR_ATTR_DCC_CLEAR_STATS_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_DCC_CLEAR_STATS_BITMAP, + QCA_WLAN_VENDOR_ATTR_DCC_CLEAR_STATS_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_DCC_CLEAR_STATS_MAX = + QCA_WLAN_VENDOR_ATTR_DCC_CLEAR_STATS_AFTER_LAST - 1, +}; + +/** + * enum qca_wlan_vendor_attr_ocb_set_config - vendor subcmd to update dcc + * @QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_CHANNEL_COUNT: + * number of channels in the configuration + * @QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_CHANNEL_ARRAY: the array of NDL + * channel info + * @QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_ACTIVE_STATE_ARRAY: the array of + * NDL active states + */ +enum qca_wlan_vendor_attr_dcc_update_ndl { + QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_CHANNEL_COUNT, + QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_CHANNEL_ARRAY, + QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_ACTIVE_STATE_ARRAY, + QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_MAX = + QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_AFTER_LAST - 1, +}; +#ifdef WLAN_FEATURE_DSRC +void hdd_set_dot11p_config(hdd_context_t *hdd_ctx); + +void hdd_remove_ocb_tx_header(struct sk_buff *skb); + +int iw_set_dot11p_channel_sched(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra); + +int wlan_hdd_cfg80211_ocb_set_config(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len); + +int wlan_hdd_cfg80211_ocb_set_utc_time(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len); + +int wlan_hdd_cfg80211_ocb_start_timing_advert(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len); + +int wlan_hdd_cfg80211_ocb_stop_timing_advert(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len); + +int wlan_hdd_cfg80211_ocb_get_tsf_timer(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len); + +int wlan_hdd_cfg80211_dcc_get_stats(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len); + +int wlan_hdd_cfg80211_dcc_clear_stats(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len); + +int wlan_hdd_cfg80211_dcc_update_ndl(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len); + +void wlan_hdd_dcc_register_for_dcc_stats_event(hdd_context_t *hdd_ctx); + +void wlan_hdd_dcc_stats_event(void *context_ptr, void *response_ptr); +#else +static inline void hdd_set_dot11p_config(hdd_context_t *hdd_ctx) +{ + return; +} + +static inline void hdd_remove_ocb_tx_header(struct sk_buff *skb) +{ + return; +} +static inline int iw_set_dot11p_channel_sched(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + return 0; +} + +static inline int wlan_hdd_cfg80211_ocb_set_config(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + return 0; +} + +static inline int wlan_hdd_cfg80211_ocb_set_utc_time(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + return 0; +} + +static inline int wlan_hdd_cfg80211_ocb_start_timing_advert(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + return 0; +} + +static inline int wlan_hdd_cfg80211_ocb_stop_timing_advert(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + return 0; +} + +static inline int wlan_hdd_cfg80211_ocb_get_tsf_timer(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + return 0; +} + +static inline int wlan_hdd_cfg80211_dcc_get_stats(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + return 0; +} + +static inline int wlan_hdd_cfg80211_dcc_clear_stats(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + return 0; +} + +static inline int wlan_hdd_cfg80211_dcc_update_ndl(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + return 0; +} + +static inline void wlan_hdd_dcc_register_for_dcc_stats_event( + hdd_context_t *hdd_ctx) +{ + return; +} +static inline void wlan_hdd_dcc_stats_event(void *context_ptr, + void *response_ptr) +{ + return; +} +#endif + +#endif /* __WLAN_HDD_OCB_H */ diff --git a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_oemdata.c b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_oemdata.c new file mode 100644 index 0000000000000000000000000000000000000000..378c2c1a414e97d3ae33b4fd562d22e9e40c4bee --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_oemdata.c @@ -0,0 +1,1019 @@ +/* + * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifdef FEATURE_OEM_DATA_SUPPORT + +/** + * DOC: wlan_hdd_oemdata.c + * + * Support for generic OEM Data Request handling + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include "qwlan_version.h" +#include "cds_utils.h" +#include "wma.h" +#include "sme_api.h" + +static struct hdd_context_s *p_hdd_ctx; + +/** + * populate_oem_data_cap() - populate oem capabilities + * @adapter: device adapter + * @data_cap: pointer to populate the capabilities + * + * Return: error code + */ +static int populate_oem_data_cap(hdd_adapter_t *adapter, + t_iw_oem_data_cap *data_cap) +{ + QDF_STATUS status; + struct hdd_config *config; + uint32_t num_chan; + uint8_t *chan_list; + hdd_context_t *hdd_ctx = adapter->pHddCtx; + + config = hdd_ctx->config; + if (!config) { + hdd_err("HDD configuration is null"); + return -EINVAL; + } + chan_list = qdf_mem_malloc(sizeof(uint8_t) * OEM_CAP_MAX_NUM_CHANNELS); + if (NULL == chan_list) { + hdd_err("Memory allocation failed"); + return -ENOMEM; + } + + strlcpy(data_cap->oem_target_signature, OEM_TARGET_SIGNATURE, + OEM_TARGET_SIGNATURE_LEN); + data_cap->oem_target_type = hdd_ctx->target_type; + data_cap->oem_fw_version = hdd_ctx->target_fw_version; + data_cap->driver_version.major = QWLAN_VERSION_MAJOR; + data_cap->driver_version.minor = QWLAN_VERSION_MINOR; + data_cap->driver_version.patch = QWLAN_VERSION_PATCH; + data_cap->driver_version.build = QWLAN_VERSION_BUILD; + data_cap->allowed_dwell_time_min = config->nNeighborScanMinChanTime; + data_cap->allowed_dwell_time_max = config->nNeighborScanMaxChanTime; + data_cap->curr_dwell_time_min = + sme_get_neighbor_scan_min_chan_time(hdd_ctx->hHal, + adapter->sessionId); + data_cap->curr_dwell_time_max = + sme_get_neighbor_scan_max_chan_time(hdd_ctx->hHal, + adapter->sessionId); + data_cap->supported_bands = config->nBandCapability; + + /* request for max num of channels */ + num_chan = OEM_CAP_MAX_NUM_CHANNELS; + status = sme_get_cfg_valid_channels(hdd_ctx->hHal, + &chan_list[0], &num_chan); + if (QDF_STATUS_SUCCESS != status) { + hdd_err("failed to get valid channel list, status: %d", status); + qdf_mem_free(chan_list); + return -EINVAL; + } + + /* make sure num channels is not more than chan list array */ + if (num_chan > OEM_CAP_MAX_NUM_CHANNELS) { + hdd_err("Num of channels-%d > length-%d of chan_list", + num_chan, OEM_CAP_MAX_NUM_CHANNELS); + qdf_mem_free(chan_list); + return -ENOMEM; + } + + data_cap->num_channels = num_chan; + qdf_mem_copy(data_cap->channel_list, chan_list, + sizeof(uint8_t) * num_chan); + + qdf_mem_free(chan_list); + return 0; +} + +/** + * iw_get_oem_data_cap() - Get OEM Data Capabilities + * @dev: net device upon which the request was received + * @info: ioctl request information + * @wrqu: ioctl request data + * @extra: ioctl data payload + * + * This function gets the capability information for OEM Data Request + * and Response. + * + * Return: 0 for success, negative errno value on failure + */ +int iw_get_oem_data_cap(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int status; + t_iw_oem_data_cap oemDataCap = { {0} }; + t_iw_oem_data_cap *pHddOemDataCap; + hdd_adapter_t *pAdapter = (netdev_priv(dev)); + hdd_context_t *pHddContext; + int ret; + + ENTER(); + + pHddContext = WLAN_HDD_GET_CTX(pAdapter); + ret = wlan_hdd_validate_context(pHddContext); + if (0 != ret) + return ret; + + status = populate_oem_data_cap(pAdapter, &oemDataCap); + if (0 != status) { + hdd_err("Failed to populate oem data capabilities"); + return status; + } + + pHddOemDataCap = (t_iw_oem_data_cap *) (extra); + *pHddOemDataCap = oemDataCap; + + EXIT(); + return 0; +} + +/** + * send_oem_reg_rsp_nlink_msg() - send oem registration response + * + * This function sends oem message to registered application process + * + * Return: none + */ +static void send_oem_reg_rsp_nlink_msg(void) +{ + struct sk_buff *skb; + struct nlmsghdr *nlh; + tAniMsgHdr *aniHdr; + uint8_t *buf; + uint8_t *numInterfaces; + uint8_t *deviceMode; + uint8_t *vdevId; + hdd_adapter_list_node_t *pAdapterNode = NULL; + hdd_adapter_list_node_t *pNext = NULL; + hdd_adapter_t *pAdapter = NULL; + QDF_STATUS status = 0; + + /* OEM message is always to a specific process and cannot be a broadcast */ + if (p_hdd_ctx->oem_pid == 0) { + hdd_err("invalid dest pid"); + return; + } + + skb = alloc_skb(NLMSG_SPACE(WLAN_NL_MAX_PAYLOAD), GFP_KERNEL); + if (skb == NULL) { + hdd_err("alloc_skb failed"); + return; + } + + nlh = (struct nlmsghdr *)skb->data; + nlh->nlmsg_pid = 0; /* from kernel */ + nlh->nlmsg_flags = 0; + nlh->nlmsg_seq = 0; + nlh->nlmsg_type = WLAN_NL_MSG_OEM; + aniHdr = NLMSG_DATA(nlh); + aniHdr->type = ANI_MSG_APP_REG_RSP; + + /* Fill message body: + * First byte will be number of interfaces, followed by + * two bytes for each interfaces + * - one byte for device mode + * - one byte for vdev id + */ + buf = (char *)((char *)aniHdr + sizeof(tAniMsgHdr)); + numInterfaces = buf++; + *numInterfaces = 0; + + /* Iterate through each of the adapters and fill device mode and vdev id */ + status = hdd_get_front_adapter(p_hdd_ctx, &pAdapterNode); + while ((QDF_STATUS_SUCCESS == status) && pAdapterNode) { + pAdapter = pAdapterNode->pAdapter; + if (pAdapter) { + deviceMode = buf++; + vdevId = buf++; + *deviceMode = pAdapter->device_mode; + *vdevId = pAdapter->sessionId; + (*numInterfaces)++; + hdd_notice("numInterfaces: %d, deviceMode: %d, vdevId: %d", + *numInterfaces, *deviceMode, + *vdevId); + } + status = hdd_get_next_adapter(p_hdd_ctx, pAdapterNode, &pNext); + pAdapterNode = pNext; + } + + aniHdr->length = + sizeof(uint8_t) + (*numInterfaces) * 2 * sizeof(uint8_t); + nlh->nlmsg_len = NLMSG_LENGTH((sizeof(tAniMsgHdr) + aniHdr->length)); + + skb_put(skb, NLMSG_SPACE((sizeof(tAniMsgHdr) + aniHdr->length))); + + hdd_notice("sending App Reg Response length (%d) to process pid (%d)", + aniHdr->length, p_hdd_ctx->oem_pid); + + (void)nl_srv_ucast(skb, p_hdd_ctx->oem_pid, MSG_DONTWAIT); + + return; +} + +/** + * send_oem_err_rsp_nlink_msg() - send oem error response + * @app_pid: PID of oem application process + * @error_code: response error code + * + * This function sends error response to oem app + * + * Return: none + */ +static void send_oem_err_rsp_nlink_msg(int32_t app_pid, uint8_t error_code) +{ + struct sk_buff *skb; + struct nlmsghdr *nlh; + tAniMsgHdr *aniHdr; + uint8_t *buf; + + skb = alloc_skb(NLMSG_SPACE(WLAN_NL_MAX_PAYLOAD), GFP_KERNEL); + if (skb == NULL) { + hdd_err("alloc_skb failed"); + return; + } + + nlh = (struct nlmsghdr *)skb->data; + nlh->nlmsg_pid = 0; /* from kernel */ + nlh->nlmsg_flags = 0; + nlh->nlmsg_seq = 0; + nlh->nlmsg_type = WLAN_NL_MSG_OEM; + aniHdr = NLMSG_DATA(nlh); + aniHdr->type = ANI_MSG_OEM_ERROR; + aniHdr->length = sizeof(uint8_t); + nlh->nlmsg_len = NLMSG_LENGTH(sizeof(tAniMsgHdr) + aniHdr->length); + + /* message body will contain one byte of error code */ + buf = (char *)((char *)aniHdr + sizeof(tAniMsgHdr)); + *buf = error_code; + + skb_put(skb, NLMSG_SPACE(sizeof(tAniMsgHdr) + aniHdr->length)); + + hdd_notice("sending oem error response to process pid (%d)", app_pid); + + (void)nl_srv_ucast(skb, app_pid, MSG_DONTWAIT); + + return; +} + +/** + * hdd_send_oem_data_rsp_msg() - send oem data response + * @oem_data_rsp: the actual OEM Data Response message + * + * This function sends an OEM Data Response message to a registered + * application process over the netlink socket. + * + * Return: 0 for success, non zero for failure + */ +void hdd_send_oem_data_rsp_msg(struct oem_data_rsp *oem_data_rsp) +{ + struct sk_buff *skb; + struct nlmsghdr *nlh; + tAniMsgHdr *ani_hdr; + uint8_t *oem_data; + + /* + * OEM message is always to a specific process and cannot be a broadcast + */ + if (p_hdd_ctx->oem_pid == 0) { + hdd_err("invalid dest pid"); + return; + } + + if (oem_data_rsp->rsp_len > OEM_DATA_RSP_SIZE) { + hdd_err("invalid length of Oem Data response"); + return; + } + + skb = alloc_skb(NLMSG_SPACE(sizeof(tAniMsgHdr) + OEM_DATA_RSP_SIZE), + GFP_KERNEL); + if (skb == NULL) { + hdd_err("alloc_skb failed"); + return; + } + + nlh = (struct nlmsghdr *)skb->data; + nlh->nlmsg_pid = 0; /* from kernel */ + nlh->nlmsg_flags = 0; + nlh->nlmsg_seq = 0; + nlh->nlmsg_type = WLAN_NL_MSG_OEM; + ani_hdr = NLMSG_DATA(nlh); + ani_hdr->type = ANI_MSG_OEM_DATA_RSP; + + ani_hdr->length = oem_data_rsp->rsp_len; + nlh->nlmsg_len = NLMSG_LENGTH((sizeof(tAniMsgHdr) + ani_hdr->length)); + oem_data = (uint8_t *) ((char *)ani_hdr + sizeof(tAniMsgHdr)); + qdf_mem_copy(oem_data, oem_data_rsp->data, oem_data_rsp->rsp_len); + + skb_put(skb, NLMSG_SPACE((sizeof(tAniMsgHdr) + ani_hdr->length))); + + hdd_notice("sending Oem Data Response of len (%d) to process pid (%d)", + oem_data_rsp->rsp_len, p_hdd_ctx->oem_pid); + + (void)nl_srv_ucast(skb, p_hdd_ctx->oem_pid, MSG_DONTWAIT); + + return; +} + +/** + * oem_process_data_req_msg() - process oem data request + * @oem_data_len: Length to OEM Data buffer + * @oem_data: Pointer to OEM Data buffer + * + * This function sends oem message to SME + * + * Return: QDF_STATUS enumeration + */ +static QDF_STATUS oem_process_data_req_msg(int oem_data_len, char *oem_data) +{ + hdd_adapter_t *adapter = NULL; + struct oem_data_req oem_data_req; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + /* for now, STA interface only */ + adapter = hdd_get_adapter(p_hdd_ctx, QDF_STA_MODE); + if (!adapter) { + hdd_err("No adapter for STA mode"); + return QDF_STATUS_E_FAILURE; + } + + if (!oem_data) { + hdd_err("oem_data is null"); + return QDF_STATUS_E_FAILURE; + } + + qdf_mem_zero(&oem_data_req, sizeof(oem_data_req)); + + oem_data_req.data = qdf_mem_malloc(oem_data_len); + if (!oem_data_req.data) { + hdd_err("malloc failed for data req buffer"); + return QDF_STATUS_E_NOMEM; + } + + oem_data_req.data_len = oem_data_len; + qdf_mem_copy(oem_data_req.data, oem_data, oem_data_len); + + hdd_notice("calling sme_oem_data_req"); + + status = sme_oem_data_req(p_hdd_ctx->hHal, &oem_data_req); + + qdf_mem_free(oem_data_req.data); + oem_data_req.data = NULL; + + return status; +} + +/** + * update_channel_bw_info() - set bandwidth info for the chan + * @hdd_ctx: hdd context + * @chan: channel for which info are required + * @hdd_chan_info: struct where the bandwidth info is filled + * + * This function find the maximum bandwidth allowed, secondary + * channel offset and center freq for the channel as per regulatory + * domain and using these info calculate the phy mode for the + * channel. + * + * Return: void + */ +static void hdd_update_channel_bw_info(hdd_context_t *hdd_ctx, + uint16_t chan, tHddChannelInfo *hdd_chan_info) +{ + struct ch_params_s ch_params = {0}; + uint16_t sec_ch_2g = 0; + WLAN_PHY_MODE phy_mode; + uint32_t wni_dot11_mode; + + wni_dot11_mode = sme_get_wni_dot11_mode(hdd_ctx->hHal); + + /* Passing CH_WIDTH_MAX will give the max bandwidth supported */ + ch_params.ch_width = CH_WIDTH_MAX; + + cds_set_channel_params(chan, sec_ch_2g, &ch_params); + + if (ch_params.center_freq_seg0) + hdd_chan_info->band_center_freq1 = + cds_chan_to_freq(ch_params.center_freq_seg0); + + if (ch_params.ch_width < CH_WIDTH_INVALID) + phy_mode = wma_chan_phy_mode(chan, + ch_params.ch_width, wni_dot11_mode); + else + /* + * If channel width is CH_WIDTH_INVALID, It mean channel is + * invalid and should not have been received in channel info + * req. Set invalid phymode in this case. + */ + phy_mode = MODE_UNKNOWN; + + hdd_info("chan %d dot11_mode %d ch_width %d sec offset %d freq_seg0 %d phy_mode %d", + chan, wni_dot11_mode, ch_params.ch_width, + ch_params.sec_ch_offset, + hdd_chan_info->band_center_freq1, phy_mode); + + WMI_SET_CHANNEL_MODE(hdd_chan_info, phy_mode); +} + +/** + * oem_process_channel_info_req_msg() - process oem channel_info request + * @numOfChannels: number of channels + * @chanList: list of channel information + * + * This function responds with channel info to oem process + * + * Return: 0 for success, non zero for failure + */ +static int oem_process_channel_info_req_msg(int numOfChannels, char *chanList) +{ + struct sk_buff *skb; + struct nlmsghdr *nlh; + tAniMsgHdr *aniHdr; + tHddChannelInfo *pHddChanInfo; + tHddChannelInfo hddChanInfo; + uint8_t chanId; + uint32_t reg_info_1; + uint32_t reg_info_2; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + int i; + uint8_t *buf; + + /* OEM message is always to a specific process and cannot be a broadcast */ + if (p_hdd_ctx->oem_pid == 0) { + hdd_err("invalid dest pid"); + return -EPERM; + } + + skb = alloc_skb(NLMSG_SPACE(sizeof(tAniMsgHdr) + sizeof(uint8_t) + + numOfChannels * sizeof(tHddChannelInfo)), + GFP_KERNEL); + if (skb == NULL) { + hdd_err("alloc_skb failed"); + return -ENOMEM; + } + + nlh = (struct nlmsghdr *)skb->data; + nlh->nlmsg_pid = 0; /* from kernel */ + nlh->nlmsg_flags = 0; + nlh->nlmsg_seq = 0; + nlh->nlmsg_type = WLAN_NL_MSG_OEM; + aniHdr = NLMSG_DATA(nlh); + aniHdr->type = ANI_MSG_CHANNEL_INFO_RSP; + + aniHdr->length = + sizeof(uint8_t) + numOfChannels * sizeof(tHddChannelInfo); + nlh->nlmsg_len = NLMSG_LENGTH((sizeof(tAniMsgHdr) + aniHdr->length)); + + /* First byte of message body will have num of channels */ + buf = (char *)((char *)aniHdr + sizeof(tAniMsgHdr)); + *buf++ = numOfChannels; + + /* Next follows channel info struct for each channel id. + * If chan id is wrong or SME returns failure for a channel + * then fill in 0 in channel info for that particular channel + */ + for (i = 0; i < numOfChannels; i++) { + pHddChanInfo = (tHddChannelInfo *) ((char *)buf + + i * + sizeof(tHddChannelInfo)); + + chanId = chanList[i]; + status = sme_get_reg_info(p_hdd_ctx->hHal, chanId, + ®_info_1, ®_info_2); + if (QDF_STATUS_SUCCESS == status) { + /* copy into hdd chan info struct */ + hddChanInfo.chan_id = chanId; + hddChanInfo.reserved0 = 0; + hddChanInfo.mhz = cds_chan_to_freq(chanId); + hddChanInfo.band_center_freq1 = hddChanInfo.mhz; + hddChanInfo.band_center_freq2 = 0; + + hddChanInfo.info = 0; + if (CHANNEL_STATE_DFS == + cds_get_channel_state(chanId)) + WMI_SET_CHANNEL_FLAG(&hddChanInfo, + WMI_CHAN_FLAG_DFS); + + hdd_update_channel_bw_info(p_hdd_ctx, + chanId, &hddChanInfo); + hddChanInfo.reg_info_1 = reg_info_1; + hddChanInfo.reg_info_2 = reg_info_2; + } else { + /* channel info is not returned, fill in zeros in channel + * info struct + */ + hdd_notice("sme_get_reg_info failed for chan (%d), return info 0", + chanId); + hddChanInfo.chan_id = chanId; + hddChanInfo.reserved0 = 0; + hddChanInfo.mhz = 0; + hddChanInfo.band_center_freq1 = 0; + hddChanInfo.band_center_freq2 = 0; + hddChanInfo.info = 0; + hddChanInfo.reg_info_1 = 0; + hddChanInfo.reg_info_2 = 0; + } + qdf_mem_copy(pHddChanInfo, &hddChanInfo, + sizeof(tHddChannelInfo)); + } + + skb_put(skb, NLMSG_SPACE((sizeof(tAniMsgHdr) + aniHdr->length))); + + hdd_notice("sending channel info resp for num channels (%d) to pid (%d)", + numOfChannels, p_hdd_ctx->oem_pid); + + (void)nl_srv_ucast(skb, p_hdd_ctx->oem_pid, MSG_DONTWAIT); + + return 0; +} + +/** + * oem_process_set_cap_req_msg() - process oem set capability request + * @oem_cap_len: Length of OEM capability + * @oem_cap: Pointer to OEM capability buffer + * @app_pid: process ID, to which rsp message is to be sent + * + * This function sends oem message to SME + * + * Return: error code + */ +static int oem_process_set_cap_req_msg(int oem_cap_len, + char *oem_cap, int32_t app_pid) +{ + QDF_STATUS status; + int error_code; + struct sk_buff *skb; + struct nlmsghdr *nlh; + tAniMsgHdr *ani_hdr; + uint8_t *buf; + + if (!oem_cap) { + hdd_err("oem_cap is null"); + return -EINVAL; + } + + status = sme_oem_update_capability(p_hdd_ctx->hHal, + (struct sme_oem_capability *)oem_cap); + if (!QDF_IS_STATUS_SUCCESS(status)) + hdd_err("error updating rm capability, status: %d", status); + error_code = qdf_status_to_os_return(status); + + skb = alloc_skb(NLMSG_SPACE(WLAN_NL_MAX_PAYLOAD), GFP_KERNEL); + if (skb == NULL) { + hdd_err("alloc_skb failed"); + return -ENOMEM; + } + + nlh = (struct nlmsghdr *)skb->data; + nlh->nlmsg_pid = 0; /* from kernel */ + nlh->nlmsg_flags = 0; + nlh->nlmsg_seq = 0; + nlh->nlmsg_type = WLAN_NL_MSG_OEM; + ani_hdr = NLMSG_DATA(nlh); + ani_hdr->type = ANI_MSG_SET_OEM_CAP_RSP; + /* 64 bit alignment */ + ani_hdr->length = sizeof(error_code); + nlh->nlmsg_len = NLMSG_LENGTH(sizeof(tAniMsgHdr) + ani_hdr->length); + + /* message body will contain only status code */ + buf = (char *)((char *)ani_hdr + sizeof(tAniMsgHdr)); + qdf_mem_copy(buf, &error_code, ani_hdr->length); + + skb_put(skb, NLMSG_SPACE(sizeof(tAniMsgHdr) + ani_hdr->length)); + + hdd_info("sending oem response to process pid %d", app_pid); + + (void)nl_srv_ucast(skb, app_pid, MSG_DONTWAIT); + + return error_code; +} + +/** + * oem_process_get_cap_req_msg() - process oem get capability request + * + * This function process the get capability request from OEM and responds + * with the capability. + * + * Return: error code + */ +static int oem_process_get_cap_req_msg(void) +{ + int error_code; + struct oem_get_capability_rsp *cap_rsp; + t_iw_oem_data_cap data_cap = { {0} }; + struct sme_oem_capability oem_cap; + hdd_adapter_t *adapter; + struct sk_buff *skb; + struct nlmsghdr *nlh; + tAniMsgHdr *ani_hdr; + uint8_t *buf; + + /* for now, STA interface only */ + adapter = hdd_get_adapter(p_hdd_ctx, QDF_STA_MODE); + if (!adapter) { + hdd_err("No adapter for STA mode"); + return -EINVAL; + } + + error_code = populate_oem_data_cap(adapter, &data_cap); + if (0 != error_code) + return error_code; + + skb = alloc_skb(NLMSG_SPACE(sizeof(tAniMsgHdr) + sizeof(*cap_rsp)), + GFP_KERNEL); + if (skb == NULL) { + hdd_err("alloc_skb failed"); + return -ENOMEM; + } + + nlh = (struct nlmsghdr *)skb->data; + nlh->nlmsg_pid = 0; /* from kernel */ + nlh->nlmsg_flags = 0; + nlh->nlmsg_seq = 0; + nlh->nlmsg_type = WLAN_NL_MSG_OEM; + ani_hdr = NLMSG_DATA(nlh); + ani_hdr->type = ANI_MSG_GET_OEM_CAP_RSP; + + ani_hdr->length = sizeof(*cap_rsp); + nlh->nlmsg_len = NLMSG_LENGTH((sizeof(tAniMsgHdr) + ani_hdr->length)); + + buf = (char *)((char *)ani_hdr + sizeof(tAniMsgHdr)); + qdf_mem_copy(buf, &data_cap, sizeof(data_cap)); + + buf = (char *) buf + sizeof(data_cap); + qdf_mem_zero(&oem_cap, sizeof(oem_cap)); + sme_oem_get_capability(p_hdd_ctx->hHal, &oem_cap); + qdf_mem_copy(buf, &oem_cap, sizeof(oem_cap)); + + skb_put(skb, NLMSG_SPACE((sizeof(tAniMsgHdr) + ani_hdr->length))); + hdd_info("send rsp to oem-pid:%d for get_capability", + p_hdd_ctx->oem_pid); + + (void)nl_srv_ucast(skb, p_hdd_ctx->oem_pid, MSG_DONTWAIT); + return 0; +} + +/** + * hdd_send_peer_status_ind_to_oem_app() - + * Function to send peer status to a registered application + * @peerMac: MAC address of peer + * @peerStatus: ePeerConnected or ePeerDisconnected + * @peerTimingMeasCap: 0: RTT/RTT2, 1: RTT3. Default is 0 + * @sessionId: SME session id, i.e. vdev_id + * @chan_info: operating channel information + * @dev_mode: dev mode for which indication is sent + * + * Return: none + */ +void hdd_send_peer_status_ind_to_oem_app(struct qdf_mac_addr *peerMac, + uint8_t peerStatus, + uint8_t peerTimingMeasCap, + uint8_t sessionId, + tSirSmeChanInfo *chan_info, + enum tQDF_ADAPTER_MODE dev_mode) +{ + struct sk_buff *skb; + struct nlmsghdr *nlh; + tAniMsgHdr *aniHdr; + tPeerStatusInfo *pPeerInfo; + + if (!p_hdd_ctx || !p_hdd_ctx->hHal) { + hdd_err("Either HDD Ctx is null or Hal Ctx is null"); + return; + } + + /* check if oem app has registered and pid is valid */ + if ((!p_hdd_ctx->oem_app_registered) || (p_hdd_ctx->oem_pid == 0)) { + hdd_info("OEM app is not registered(%d) or pid is invalid(%d)", + p_hdd_ctx->oem_app_registered, + p_hdd_ctx->oem_pid); + return; + } + + skb = alloc_skb(NLMSG_SPACE(sizeof(tAniMsgHdr) + + sizeof(tPeerStatusInfo)), + GFP_KERNEL); + if (skb == NULL) { + hdd_err("alloc_skb failed"); + return; + } + + nlh = (struct nlmsghdr *)skb->data; + nlh->nlmsg_pid = 0; /* from kernel */ + nlh->nlmsg_flags = 0; + nlh->nlmsg_seq = 0; + nlh->nlmsg_type = WLAN_NL_MSG_OEM; + aniHdr = NLMSG_DATA(nlh); + aniHdr->type = ANI_MSG_PEER_STATUS_IND; + + aniHdr->length = sizeof(tPeerStatusInfo); + nlh->nlmsg_len = NLMSG_LENGTH((sizeof(tAniMsgHdr) + aniHdr->length)); + + pPeerInfo = (tPeerStatusInfo *) ((char *)aniHdr + sizeof(tAniMsgHdr)); + + qdf_mem_copy(pPeerInfo->peer_mac_addr, peerMac->bytes, + sizeof(peerMac->bytes)); + pPeerInfo->peer_status = peerStatus; + pPeerInfo->vdev_id = sessionId; + pPeerInfo->peer_capability = peerTimingMeasCap; + pPeerInfo->reserved0 = 0; + /* Set 0th bit of reserved0 for STA mode */ + if (QDF_STA_MODE == dev_mode) + pPeerInfo->reserved0 |= 0x01; + + if (chan_info) { + pPeerInfo->peer_chan_info.chan_id = chan_info->chan_id; + pPeerInfo->peer_chan_info.reserved0 = 0; + pPeerInfo->peer_chan_info.mhz = chan_info->mhz; + pPeerInfo->peer_chan_info.band_center_freq1 = + chan_info->band_center_freq1; + pPeerInfo->peer_chan_info.band_center_freq2 = + chan_info->band_center_freq2; + pPeerInfo->peer_chan_info.info = chan_info->info; + pPeerInfo->peer_chan_info.reg_info_1 = chan_info->reg_info_1; + pPeerInfo->peer_chan_info.reg_info_2 = chan_info->reg_info_2; + } else { + pPeerInfo->peer_chan_info.chan_id = 0; + pPeerInfo->peer_chan_info.reserved0 = 0; + pPeerInfo->peer_chan_info.mhz = 0; + pPeerInfo->peer_chan_info.band_center_freq1 = 0; + pPeerInfo->peer_chan_info.band_center_freq2 = 0; + pPeerInfo->peer_chan_info.info = 0; + pPeerInfo->peer_chan_info.reg_info_1 = 0; + pPeerInfo->peer_chan_info.reg_info_2 = 0; + } + skb_put(skb, NLMSG_SPACE((sizeof(tAniMsgHdr) + aniHdr->length))); + + hdd_info("sending peer " MAC_ADDRESS_STR + " status(%d), peerTimingMeasCap(%d), vdevId(%d), chanId(%d)" + " to oem app pid(%d), center freq 1 (%d), center freq 2 (%d)," + " info (0x%x), frequency (%d),reg info 1 (0x%x)," + " reg info 2 (0x%x)", + MAC_ADDR_ARRAY(peerMac->bytes), + peerStatus, peerTimingMeasCap, + sessionId, pPeerInfo->peer_chan_info.chan_id, + p_hdd_ctx->oem_pid, + pPeerInfo->peer_chan_info.band_center_freq1, + pPeerInfo->peer_chan_info.band_center_freq2, + pPeerInfo->peer_chan_info.info, + pPeerInfo->peer_chan_info.mhz, + pPeerInfo->peer_chan_info.reg_info_1, + pPeerInfo->peer_chan_info.reg_info_2); + + (void)nl_srv_ucast(skb, p_hdd_ctx->oem_pid, MSG_DONTWAIT); + + return; +} + +/* + * Callback function invoked by Netlink service for all netlink + * messages (from user space) addressed to WLAN_NL_MSG_OEM + */ + +/** + * oem_msg_callback() - callback invoked by netlink service + * @skb: skb with netlink message + * + * This function gets invoked by netlink service when a message + * is received from user space addressed to WLAN_NL_MSG_OEM + * + * Return: zero on success + * On error, error number will be returned. + */ +static int oem_msg_callback(struct sk_buff *skb) +{ + struct nlmsghdr *nlh; + tAniMsgHdr *msg_hdr; + int ret; + char *sign_str = NULL; + nlh = (struct nlmsghdr *)skb->data; + + if (!nlh) { + hdd_err("Netlink header null"); + return -EPERM; + } + + ret = wlan_hdd_validate_context(p_hdd_ctx); + if (ret) + return ret; + + msg_hdr = NLMSG_DATA(nlh); + + if (!msg_hdr) { + hdd_err("Message header null"); + send_oem_err_rsp_nlink_msg(nlh->nlmsg_pid, + OEM_ERR_NULL_MESSAGE_HEADER); + return -EPERM; + } + + if (nlh->nlmsg_len < + NLMSG_LENGTH(sizeof(tAniMsgHdr) + msg_hdr->length)) { + hdd_err("Invalid nl msg len, nlh->nlmsg_len (%d), msg_hdr->len (%d)", + nlh->nlmsg_len, msg_hdr->length); + send_oem_err_rsp_nlink_msg(nlh->nlmsg_pid, + OEM_ERR_INVALID_MESSAGE_LENGTH); + return -EPERM; + } + + switch (msg_hdr->type) { + case ANI_MSG_APP_REG_REQ: + /* Registration request is only allowed for Qualcomm Application */ + hdd_notice("Received App Req Req from App process pid(%d), len(%d)", + nlh->nlmsg_pid, msg_hdr->length); + + sign_str = (char *)((char *)msg_hdr + sizeof(tAniMsgHdr)); + if ((OEM_APP_SIGNATURE_LEN == msg_hdr->length) && + (0 == strncmp(sign_str, OEM_APP_SIGNATURE_STR, + OEM_APP_SIGNATURE_LEN))) { + hdd_notice("Valid App Req Req from oem app process pid(%d)", + nlh->nlmsg_pid); + + p_hdd_ctx->oem_app_registered = true; + p_hdd_ctx->oem_pid = nlh->nlmsg_pid; + send_oem_reg_rsp_nlink_msg(); + } else { + hdd_err("Invalid signature in App Reg Request from pid(%d)", + nlh->nlmsg_pid); + send_oem_err_rsp_nlink_msg(nlh->nlmsg_pid, + OEM_ERR_INVALID_SIGNATURE); + return -EPERM; + } + break; + + case ANI_MSG_OEM_DATA_REQ: + hdd_notice("Received Oem Data Request length(%d) from pid: %d", + msg_hdr->length, nlh->nlmsg_pid); + + if ((!p_hdd_ctx->oem_app_registered) || + (nlh->nlmsg_pid != p_hdd_ctx->oem_pid)) { + /* either oem app is not registered yet or pid is different */ + hdd_err("OEM DataReq: app not registered(%d) or incorrect pid(%d)", + p_hdd_ctx->oem_app_registered, + nlh->nlmsg_pid); + send_oem_err_rsp_nlink_msg(nlh->nlmsg_pid, + OEM_ERR_APP_NOT_REGISTERED); + return -EPERM; + } + + if ((!msg_hdr->length) || (OEM_DATA_REQ_SIZE < msg_hdr->length)) { + hdd_err("Invalid length (%d) in Oem Data Request", + msg_hdr->length); + send_oem_err_rsp_nlink_msg(nlh->nlmsg_pid, + OEM_ERR_INVALID_MESSAGE_LENGTH); + return -EPERM; + } + oem_process_data_req_msg(msg_hdr->length, + (char *)((char *)msg_hdr + + sizeof(tAniMsgHdr))); + break; + + case ANI_MSG_CHANNEL_INFO_REQ: + hdd_notice("Received channel info request, num channel(%d) from pid: %d", + msg_hdr->length, nlh->nlmsg_pid); + + if ((!p_hdd_ctx->oem_app_registered) || + (nlh->nlmsg_pid != p_hdd_ctx->oem_pid)) { + /* either oem app is not registered yet or pid is different */ + hdd_err("Chan InfoReq: app not registered(%d) or incorrect pid(%d)", + p_hdd_ctx->oem_app_registered, + nlh->nlmsg_pid); + send_oem_err_rsp_nlink_msg(nlh->nlmsg_pid, + OEM_ERR_APP_NOT_REGISTERED); + return -EPERM; + } + + /* message length contains list of channel ids */ + if ((!msg_hdr->length) || + (WNI_CFG_VALID_CHANNEL_LIST_LEN < msg_hdr->length)) { + hdd_err("Invalid length (%d) in channel info request", + msg_hdr->length); + send_oem_err_rsp_nlink_msg(nlh->nlmsg_pid, + OEM_ERR_INVALID_MESSAGE_LENGTH); + return -EPERM; + } + oem_process_channel_info_req_msg(msg_hdr->length, + (char *)((char *)msg_hdr + + sizeof(tAniMsgHdr))); + break; + + case ANI_MSG_SET_OEM_CAP_REQ: + hdd_info("Received set oem capability req of length:%d from pid: %d", + msg_hdr->length, nlh->nlmsg_pid); + + if ((!p_hdd_ctx->oem_app_registered) || + (nlh->nlmsg_pid != p_hdd_ctx->oem_pid)) { + /* oem app is not registered yet or pid is different */ + hdd_err("set_oem_capability : app not registered(%d) or incorrect pid(%d)", + p_hdd_ctx->oem_app_registered, + nlh->nlmsg_pid); + send_oem_err_rsp_nlink_msg(nlh->nlmsg_pid, + OEM_ERR_APP_NOT_REGISTERED); + return -EPERM; + } + + if ((!msg_hdr->length) || + (sizeof(struct sme_oem_capability) < msg_hdr->length)) { + hdd_err("Invalid length (%d) in set_oem_capability", + msg_hdr->length); + send_oem_err_rsp_nlink_msg(nlh->nlmsg_pid, + OEM_ERR_INVALID_MESSAGE_LENGTH); + return -EPERM; + } + + oem_process_set_cap_req_msg(msg_hdr->length, + (char *)((char *)msg_hdr + + sizeof(tAniMsgHdr)), + nlh->nlmsg_pid); + break; + + case ANI_MSG_GET_OEM_CAP_REQ: + hdd_info("Rcvd get oem capability req of length:%d from pid: %d", + msg_hdr->length, nlh->nlmsg_pid); + + if ((!p_hdd_ctx->oem_app_registered) || + (nlh->nlmsg_pid != p_hdd_ctx->oem_pid)) { + /* oem app is not registered yet or pid is different */ + hdd_err("get_oem_capability : app not registered(%d) or incorrect pid(%d)", + p_hdd_ctx->oem_app_registered, + nlh->nlmsg_pid); + send_oem_err_rsp_nlink_msg(nlh->nlmsg_pid, + OEM_ERR_APP_NOT_REGISTERED); + return -EPERM; + } + + oem_process_get_cap_req_msg(); + break; + + default: + hdd_err("Received Invalid message type (%d), length (%d)", + msg_hdr->type, msg_hdr->length); + send_oem_err_rsp_nlink_msg(nlh->nlmsg_pid, + OEM_ERR_INVALID_MESSAGE_TYPE); + return -EPERM; + } + return 0; +} + +static int __oem_msg_callback(struct sk_buff *skb) +{ + int ret; + + cds_ssr_protect(__func__); + ret = oem_msg_callback(skb); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * oem_activate_service() - Activate oem message handler + * @hdd_ctx: pointer to global HDD context + * + * This function registers a handler to receive netlink message from + * an OEM application process. + * + * Return: zero on success + * On error, error number will be returned. + */ +int oem_activate_service(struct hdd_context_s *hdd_ctx) +{ + p_hdd_ctx = hdd_ctx; + + /* Register the msg handler for msgs addressed to WLAN_NL_MSG_OEM */ + return nl_srv_register(WLAN_NL_MSG_OEM, __oem_msg_callback); +} + +#endif diff --git a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_p2p.c b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_p2p.c new file mode 100644 index 0000000000000000000000000000000000000000..f85f3a227611754770409e3facca2d7aeb2f2599 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_p2p.c @@ -0,0 +1,2616 @@ +/* + * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * + * @file wlan_hdd_p2p.c + * + * @brief WLAN Host Device Driver implementation for P2P commands interface + * + */ + +#include +#include +#include +#include "sme_api.h" +#include "sme_qos_api.h" +#include "wlan_hdd_p2p.h" +#include "sap_api.h" +#include "wlan_hdd_main.h" +#include "qdf_trace.h" +#include +#include +#include +#include +#include "wlan_hdd_tdls.h" +#include "wlan_hdd_trace.h" +#include "qdf_types.h" +#include "qdf_trace.h" +#include "cds_sched.h" +#include "cds_concurrency.h" +#include "cds_utils.h" + +/* Ms to Time Unit Micro Sec */ +#define MS_TO_TU_MUS(x) ((x) * 1024) +#define MAX_MUS_VAL (INT_MAX / 1024) + +static uint8_t *hdd_get_action_string(uint16_t MsgType) +{ + switch (MsgType) { + CASE_RETURN_STRING(SIR_MAC_ACTION_SPECTRUM_MGMT); + CASE_RETURN_STRING(SIR_MAC_ACTION_QOS_MGMT); + CASE_RETURN_STRING(SIR_MAC_ACTION_DLP); + CASE_RETURN_STRING(SIR_MAC_ACTION_PUBLIC_USAGE); + CASE_RETURN_STRING(SIR_MAC_ACTION_RRM); + CASE_RETURN_STRING(SIR_MAC_ACTION_FAST_BSS_TRNST); + CASE_RETURN_STRING(SIR_MAC_ACTION_HT); + CASE_RETURN_STRING(SIR_MAC_ACTION_SA_QUERY); + CASE_RETURN_STRING(SIR_MAC_ACTION_PROT_DUAL_PUB); + CASE_RETURN_STRING(SIR_MAC_ACTION_WNM); + CASE_RETURN_STRING(SIR_MAC_ACTION_UNPROT_WNM); + CASE_RETURN_STRING(SIR_MAC_ACTION_TDLS); + CASE_RETURN_STRING(SIR_MAC_ACITON_MESH); + CASE_RETURN_STRING(SIR_MAC_ACTION_MHF); + CASE_RETURN_STRING(SIR_MAC_SELF_PROTECTED); + CASE_RETURN_STRING(SIR_MAC_ACTION_WME); + CASE_RETURN_STRING(SIR_MAC_ACTION_VHT); + default: + return "UNKNOWN"; + } +} + +#ifdef WLAN_FEATURE_P2P_DEBUG +#define MAX_P2P_ACTION_FRAME_TYPE 9 +const char *p2p_action_frame_type[] = { "GO Negotiation Request", + "GO Negotiation Response", + "GO Negotiation Confirmation", + "P2P Invitation Request", + "P2P Invitation Response", + "Device Discoverability Request", + "Device Discoverability Response", + "Provision Discovery Request", + "Provision Discovery Response"}; + +/* We no need to protect this variable since + * there is no chance of race to condition + * and also not make any complicating the code + * just for debugging log + */ +tP2PConnectionStatus global_p2p_connection_status = P2P_NOT_ACTIVE; + +#endif +#define MAX_TDLS_ACTION_FRAME_TYPE 11 +const char *tdls_action_frame_type[] = { "TDLS Setup Request", + "TDLS Setup Response", + "TDLS Setup Confirm", + "TDLS Teardown", + "TDLS Peer Traffic Indication", + "TDLS Channel Switch Request", + "TDLS Channel Switch Response", + "TDLS Peer PSM Request", + "TDLS Peer PSM Response", + "TDLS Peer Traffic Response", + "TDLS Discovery Request"}; + +static bool wlan_hdd_is_type_p2p_action(const u8 *buf) +{ + const u8 *ouiPtr; + + if (buf[WLAN_HDD_PUBLIC_ACTION_FRAME_CATEGORY_OFFSET] != + WLAN_HDD_PUBLIC_ACTION_FRAME) { + return false; + } + + if (buf[WLAN_HDD_PUBLIC_ACTION_FRAME_ACTION_OFFSET] != + WLAN_HDD_VENDOR_SPECIFIC_ACTION) { + return false; + } + + ouiPtr = &buf[WLAN_HDD_PUBLIC_ACTION_FRAME_OUI_OFFSET]; + + if (WPA_GET_BE24(ouiPtr) != WLAN_HDD_WFA_OUI) { + return false; + } + + if (buf[WLAN_HDD_PUBLIC_ACTION_FRAME_OUI_TYPE_OFFSET] != + WLAN_HDD_WFA_P2P_OUI_TYPE) { + return false; + } + + return true; +} + +static bool hdd_p2p_is_action_type_rsp(const u8 *buf) +{ + tActionFrmType actionFrmType; + + if (wlan_hdd_is_type_p2p_action(buf)) { + actionFrmType = + buf[WLAN_HDD_PUBLIC_ACTION_FRAME_SUB_TYPE_OFFSET]; + if (actionFrmType != WLAN_HDD_INVITATION_REQ + && actionFrmType != WLAN_HDD_GO_NEG_REQ + && actionFrmType != WLAN_HDD_DEV_DIS_REQ + && actionFrmType != WLAN_HDD_PROV_DIS_REQ) + return true; + } + + return false; +} + +static +QDF_STATUS wlan_hdd_remain_on_channel_callback(tHalHandle hHal, void *pCtx, + QDF_STATUS status, uint32_t scan_id) +{ + hdd_adapter_t *pAdapter = (hdd_adapter_t *) pCtx; + hdd_cfg80211_state_t *cfgState = WLAN_HDD_GET_CFG_STATE_PTR(pAdapter); + hdd_remain_on_chan_ctx_t *pRemainChanCtx; + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(pAdapter); + rem_on_channel_request_type_t req_type; + + if (!hdd_ctx) { + hdd_err("Invalid HDD context"); + return QDF_STATUS_E_FAILURE; + } + + mutex_lock(&cfgState->remain_on_chan_ctx_lock); + pRemainChanCtx = cfgState->remain_on_chan_ctx; + + if (pRemainChanCtx == NULL) { + mutex_unlock(&cfgState->remain_on_chan_ctx_lock); + hdd_warn("No Rem on channel pending for which Rsp is received"); + return QDF_STATUS_SUCCESS; + } + + hdd_notice("Received remain on channel rsp"); + if (qdf_mc_timer_stop(&pRemainChanCtx->hdd_remain_on_chan_timer) + != QDF_STATUS_SUCCESS) + hdd_warn("Failed to stop hdd_remain_on_chan_timer"); + if (qdf_mc_timer_destroy(&pRemainChanCtx->hdd_remain_on_chan_timer) + != QDF_STATUS_SUCCESS) + hdd_warn("Failed to destroy hdd_remain_on_chan_timer"); + cfgState->remain_on_chan_ctx = NULL; + /* + * Resetting the roc in progress early ensures that the subsequent + * roc requests are immediately processed without being queued + */ + pAdapter->is_roc_inprogress = false; + qdf_runtime_pm_allow_suspend(&hdd_ctx->runtime_context.roc); + /* + * If the allow suspend is done later, the scheduled roc wil prevent + * the system from going into suspend and immediately this logic + * will allow the system to go to suspend breaking the exising logic. + * Basically, the system must not go into suspend while roc is in + * progress. + */ + hdd_allow_suspend(WIFI_POWER_EVENT_WAKELOCK_ROC); + + if (REMAIN_ON_CHANNEL_REQUEST == pRemainChanCtx->rem_on_chan_request) { + if (cfgState->buf) { + hdd_info("We need to receive yet an ack from one of tx packet"); + } + cfg80211_remain_on_channel_expired( + pRemainChanCtx->dev-> + ieee80211_ptr, + pRemainChanCtx-> + cookie, + &pRemainChanCtx->chan, + GFP_KERNEL); + pAdapter->last_roc_ts = + (uint64_t)qdf_mc_timer_get_system_time(); + } + req_type = pRemainChanCtx->rem_on_chan_request; + mutex_unlock(&cfgState->remain_on_chan_ctx_lock); + + if ((QDF_STA_MODE == pAdapter->device_mode) || + (QDF_P2P_CLIENT_MODE == pAdapter->device_mode) || + (QDF_P2P_DEVICE_MODE == pAdapter->device_mode) + ) { + uint8_t sessionId = pAdapter->sessionId; + if (REMAIN_ON_CHANNEL_REQUEST == req_type) { + sme_deregister_mgmt_frame(hHal, sessionId, + (SIR_MAC_MGMT_FRAME << 2) | + (SIR_MAC_MGMT_PROBE_REQ << 4), + NULL, 0); + } + } else if ((QDF_SAP_MODE == pAdapter->device_mode) || + (QDF_P2P_GO_MODE == pAdapter->device_mode) + ) { + wlansap_de_register_mgmt_frame( + WLAN_HDD_GET_SAP_CTX_PTR(pAdapter), + (SIR_MAC_MGMT_FRAME << 2) | + (SIR_MAC_MGMT_PROBE_REQ << 4), + NULL, 0); + + } + + mutex_lock(&cfgState->remain_on_chan_ctx_lock); + if (pRemainChanCtx) { + if (pRemainChanCtx->action_pkt_buff.frame_ptr != NULL + && pRemainChanCtx->action_pkt_buff.frame_length != 0) { + qdf_mem_free(pRemainChanCtx->action_pkt_buff.frame_ptr); + pRemainChanCtx->action_pkt_buff.frame_ptr = NULL; + pRemainChanCtx->action_pkt_buff.frame_length = 0; + } + } + qdf_mem_free(pRemainChanCtx); + mutex_unlock(&cfgState->remain_on_chan_ctx_lock); + complete(&pAdapter->cancel_rem_on_chan_var); + if (QDF_STATUS_SUCCESS != status) + complete(&pAdapter->rem_on_chan_ready_event); + + /* If we schedule work queue to start new RoC before completing + * cancel_rem_on_chan_var then the work queue may immediately get + * scheduled and update cfgState->remain_on_chan_ctx which is referred + * in mgmt_tx. Due to this update the the mgmt_tx may extend the roc + * which was already completed. This will lead to mgmt tx failure. + * Always schedule below work queue only after completing the + * cancel_rem_on_chan_var event. + */ + schedule_delayed_work(&hdd_ctx->roc_req_work, 0); + + return QDF_STATUS_SUCCESS; +} + +void wlan_hdd_cancel_existing_remain_on_channel(hdd_adapter_t *pAdapter) +{ + hdd_cfg80211_state_t *cfgState = WLAN_HDD_GET_CFG_STATE_PTR(pAdapter); + hdd_remain_on_chan_ctx_t *pRemainChanCtx; + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(pAdapter); + unsigned long rc; + uint32_t roc_scan_id; + + mutex_lock(&cfgState->remain_on_chan_ctx_lock); + if (cfgState->remain_on_chan_ctx != NULL) { + hdd_notice("Cancel Existing Remain on Channel"); + + if (QDF_TIMER_STATE_RUNNING == qdf_mc_timer_get_current_state( + &cfgState->remain_on_chan_ctx->hdd_remain_on_chan_timer)) { + if (qdf_mc_timer_stop(&cfgState->remain_on_chan_ctx-> + hdd_remain_on_chan_timer) != QDF_STATUS_SUCCESS) + hdd_warn("Failed to stop hdd_remain_on_chan_timer"); + } + + pRemainChanCtx = cfgState->remain_on_chan_ctx; + if (pRemainChanCtx->hdd_remain_on_chan_cancel_in_progress == + true) { + mutex_unlock(&cfgState->remain_on_chan_ctx_lock); + hdd_warn("ROC timer cancellation in progress wait for completion"); + rc = wait_for_completion_timeout(&pAdapter-> + cancel_rem_on_chan_var, + msecs_to_jiffies + (WAIT_CANCEL_REM_CHAN)); + if (!rc) { + hdd_err("wait on cancel_rem_on_chan_var timed out"); + } + return; + } + pRemainChanCtx->hdd_remain_on_chan_cancel_in_progress = true; + roc_scan_id = pRemainChanCtx->scan_id; + mutex_unlock(&cfgState->remain_on_chan_ctx_lock); + /* Wait till remain on channel ready indication before issuing cancel + * remain on channel request, otherwise if remain on channel not + * received and if the driver issues cancel remain on channel then lim + * will be in unknown state. + */ + rc = wait_for_completion_timeout(&pAdapter-> + rem_on_chan_ready_event, + msecs_to_jiffies + (WAIT_REM_CHAN_READY)); + if (!rc) { + hdd_err("timeout waiting for remain on channel ready indication"); + cds_flush_logs(WLAN_LOG_TYPE_FATAL, + WLAN_LOG_INDICATOR_HOST_DRIVER, + WLAN_LOG_REASON_HDD_TIME_OUT, + true, false); + } + + INIT_COMPLETION(pAdapter->cancel_rem_on_chan_var); + + /* Issue abort remain on chan request to sme. + * The remain on channel callback will make sure the remain_on_chan + * expired event is sent. + */ + if ((QDF_STA_MODE == pAdapter->device_mode) || + (QDF_P2P_CLIENT_MODE == pAdapter->device_mode) || + (QDF_P2P_DEVICE_MODE == pAdapter->device_mode) + ) { + sme_cancel_remain_on_channel(WLAN_HDD_GET_HAL_CTX + (pAdapter), + pAdapter->sessionId, roc_scan_id); + } else if ((QDF_SAP_MODE == pAdapter->device_mode) + || (QDF_P2P_GO_MODE == pAdapter->device_mode) + ) { + wlansap_cancel_remain_on_channel( + WLAN_HDD_GET_SAP_CTX_PTR(pAdapter), roc_scan_id); + } + + rc = wait_for_completion_timeout(&pAdapter-> + cancel_rem_on_chan_var, + msecs_to_jiffies + (WAIT_CANCEL_REM_CHAN)); + + if (!rc) { + hdd_err("timeout waiting for cancel remain on channel ready indication"); + } + qdf_runtime_pm_allow_suspend(&hdd_ctx->runtime_context.roc); + hdd_allow_suspend(WIFI_POWER_EVENT_WAKELOCK_ROC); + } else + mutex_unlock(&cfgState->remain_on_chan_ctx_lock); +} + +int wlan_hdd_check_remain_on_channel(hdd_adapter_t *pAdapter) +{ + int status = 0; + hdd_cfg80211_state_t *cfgState = WLAN_HDD_GET_CFG_STATE_PTR(pAdapter); + + if (QDF_P2P_GO_MODE != pAdapter->device_mode) { + /* Cancel Existing Remain On Channel */ + /* If no action frame is pending */ + if (cfgState->remain_on_chan_ctx != NULL) { + /* Check whether Action Frame is pending or not */ + if (cfgState->buf == NULL) { + wlan_hdd_cancel_existing_remain_on_channel + (pAdapter); + } else { + hdd_notice("Cannot Cancel Existing Remain on Channel"); + status = -EBUSY; + } + } + } + return status; +} + +/** + * wlan_hdd_cancel_pending_roc() - Cancel pending roc + * @adapter: HDD adapter + * + * Cancels any pending remain on channel request + * + * Return: None + */ +static void wlan_hdd_cancel_pending_roc(hdd_adapter_t *adapter) +{ + hdd_remain_on_chan_ctx_t *roc_ctx; + unsigned long rc; + hdd_cfg80211_state_t *cfg_state = WLAN_HDD_GET_CFG_STATE_PTR(adapter); + uint32_t roc_scan_id; + + hdd_notice("ROC completion is not received !!!"); + + mutex_lock(&cfg_state->remain_on_chan_ctx_lock); + roc_ctx = cfg_state->remain_on_chan_ctx; + + if (roc_ctx->hdd_remain_on_chan_cancel_in_progress) { + mutex_unlock(&cfg_state->remain_on_chan_ctx_lock); + hdd_debug("roc cancel already in progress"); + /* + * Since a cancel roc is already issued and is + * in progress, we need not send another + * cancel roc again. Instead we can just wait + * for cancel roc completion + */ + goto wait; + } + roc_scan_id = roc_ctx->scan_id; + mutex_unlock(&cfg_state->remain_on_chan_ctx_lock); + + if (adapter->device_mode == QDF_P2P_GO_MODE) { + wlansap_cancel_remain_on_channel((WLAN_HDD_GET_CTX + (adapter))->pcds_context, roc_scan_id); + } else if (adapter->device_mode == QDF_P2P_CLIENT_MODE + || adapter->device_mode == + QDF_P2P_DEVICE_MODE) { + sme_cancel_remain_on_channel(WLAN_HDD_GET_HAL_CTX + (adapter), + adapter->sessionId, roc_scan_id); + } + +wait: + rc = wait_for_completion_timeout(&adapter->cancel_rem_on_chan_var, + msecs_to_jiffies + (WAIT_CANCEL_REM_CHAN)); + if (!rc) { + hdd_err("Timeout occurred while waiting for RoC Cancellation"); + mutex_lock(&cfg_state->remain_on_chan_ctx_lock); + roc_ctx = cfg_state->remain_on_chan_ctx; + if (roc_ctx != NULL) { + cfg_state->remain_on_chan_ctx = NULL; + if (qdf_mc_timer_stop(&roc_ctx-> + hdd_remain_on_chan_timer) + != QDF_STATUS_SUCCESS) + hdd_err("Failed to stop hdd_remain_on_chan_timer"); + if (qdf_mc_timer_destroy( + &roc_ctx->hdd_remain_on_chan_timer) + != QDF_STATUS_SUCCESS) + hdd_err("Failed to destroy hdd_remain_on_chan_timer"); + if (roc_ctx->action_pkt_buff.frame_ptr != NULL + && roc_ctx->action_pkt_buff.frame_length != 0) { + qdf_mem_free( + roc_ctx->action_pkt_buff.frame_ptr); + roc_ctx->action_pkt_buff.frame_ptr = NULL; + roc_ctx->action_pkt_buff.frame_length = 0; + } + qdf_mem_free(roc_ctx); + adapter->is_roc_inprogress = false; + } + mutex_unlock(&cfg_state->remain_on_chan_ctx_lock); + } +} + +/* Clean up RoC context at hdd_stop_adapter*/ +void wlan_hdd_cleanup_remain_on_channel_ctx(hdd_adapter_t *pAdapter) +{ + uint8_t retry = 0; + hdd_cfg80211_state_t *cfgState = WLAN_HDD_GET_CFG_STATE_PTR(pAdapter); + + mutex_lock(&cfgState->remain_on_chan_ctx_lock); + while (pAdapter->is_roc_inprogress) { + mutex_unlock(&cfgState->remain_on_chan_ctx_lock); + hdd_notice("ROC in progress for session %d!!!", + pAdapter->sessionId); + msleep(500); + if (retry++ > 3) { + wlan_hdd_cancel_pending_roc(pAdapter); + /* hold the lock before break from the loop */ + mutex_lock(&cfgState->remain_on_chan_ctx_lock); + break; + } + mutex_lock(&cfgState->remain_on_chan_ctx_lock); + } /* end of while */ + mutex_unlock(&cfgState->remain_on_chan_ctx_lock); + +} + +static void wlan_hdd_remain_on_chan_timeout(void *data) +{ + hdd_adapter_t *pAdapter = (hdd_adapter_t *) data; + hdd_remain_on_chan_ctx_t *pRemainChanCtx; + hdd_cfg80211_state_t *cfgState; + hdd_context_t *hdd_ctx; + uint32_t roc_scan_id; + + if ((NULL == pAdapter) || + (WLAN_HDD_ADAPTER_MAGIC != pAdapter->magic)) { + hdd_err("pAdapter is invalid %p !!!", pAdapter); + return; + } + + hdd_ctx = WLAN_HDD_GET_CTX(pAdapter); + cfgState = WLAN_HDD_GET_CFG_STATE_PTR(pAdapter); + mutex_lock(&cfgState->remain_on_chan_ctx_lock); + pRemainChanCtx = cfgState->remain_on_chan_ctx; + + if (NULL == pRemainChanCtx) { + mutex_unlock(&cfgState->remain_on_chan_ctx_lock); + hdd_err("No Remain on channel is pending"); + return; + } + + if (true == pRemainChanCtx->hdd_remain_on_chan_cancel_in_progress) { + mutex_unlock(&cfgState->remain_on_chan_ctx_lock); + hdd_err("Cancellation already in progress"); + return; + } + + pRemainChanCtx->hdd_remain_on_chan_cancel_in_progress = true; + roc_scan_id = pRemainChanCtx->scan_id; + mutex_unlock(&cfgState->remain_on_chan_ctx_lock); + hdd_notice("Cancel Remain on Channel on timeout"); + + if ((QDF_STA_MODE == pAdapter->device_mode) || + (QDF_P2P_CLIENT_MODE == pAdapter->device_mode) || + (QDF_P2P_DEVICE_MODE == pAdapter->device_mode) + ) { + sme_cancel_remain_on_channel(WLAN_HDD_GET_HAL_CTX(pAdapter), + pAdapter->sessionId, roc_scan_id); + } else if ((QDF_SAP_MODE == pAdapter->device_mode) || + (QDF_P2P_GO_MODE == pAdapter->device_mode) + ) { + wlansap_cancel_remain_on_channel( + (WLAN_HDD_GET_CTX(pAdapter))->pcds_context, + roc_scan_id); + } + + hdd_tdls_notify_p2p_roc(hdd_ctx, P2P_ROC_END); + qdf_runtime_pm_allow_suspend(&hdd_ctx->runtime_context.roc); + + hdd_allow_suspend(WIFI_POWER_EVENT_WAKELOCK_ROC); +} + +static int wlan_hdd_execute_remain_on_channel(hdd_adapter_t *pAdapter, + hdd_remain_on_chan_ctx_t *pRemainChanCtx) +{ + hdd_cfg80211_state_t *cfgState = WLAN_HDD_GET_CFG_STATE_PTR(pAdapter); + QDF_STATUS qdf_status = QDF_STATUS_E_FAILURE; + hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + hdd_adapter_list_node_t *pAdapterNode = NULL, *pNext = NULL; + hdd_adapter_t *pAdapter_temp; + QDF_STATUS status; + bool isGoPresent = false; + unsigned int duration; + + + mutex_lock(&cfgState->remain_on_chan_ctx_lock); + if (pAdapter->is_roc_inprogress == true) { + mutex_unlock(&cfgState->remain_on_chan_ctx_lock); + hdd_err("remain on channel request is in execution"); + return -EBUSY; + } + + cfgState->remain_on_chan_ctx = pRemainChanCtx; + cfgState->current_freq = pRemainChanCtx->chan.center_freq; + pAdapter->is_roc_inprogress = true; + mutex_unlock(&cfgState->remain_on_chan_ctx_lock); + + /* Initialize Remain on chan timer */ + qdf_status = + qdf_mc_timer_init(&pRemainChanCtx->hdd_remain_on_chan_timer, + QDF_TIMER_TYPE_SW, + wlan_hdd_remain_on_chan_timeout, pAdapter); + if (qdf_status != QDF_STATUS_SUCCESS) { + hdd_err("Not able to initialize remain_on_chan timer"); + mutex_lock(&cfgState->remain_on_chan_ctx_lock); + cfgState->remain_on_chan_ctx = NULL; + pAdapter->is_roc_inprogress = false; + mutex_unlock(&cfgState->remain_on_chan_ctx_lock); + qdf_mem_free(pRemainChanCtx); + return -EINVAL; + } + + status = hdd_get_front_adapter(pHddCtx, &pAdapterNode); + while (NULL != pAdapterNode && QDF_STATUS_SUCCESS == status) { + pAdapter_temp = pAdapterNode->pAdapter; + if (pAdapter_temp->device_mode == QDF_P2P_GO_MODE) + isGoPresent = true; + status = hdd_get_next_adapter(pHddCtx, pAdapterNode, &pNext); + pAdapterNode = pNext; + } + + /* Extending duration for proactive extension logic for RoC */ + duration = pRemainChanCtx->duration; + if (duration < HDD_P2P_MAX_ROC_DURATION) { + if (isGoPresent == true) + duration *= P2P_ROC_DURATION_MULTIPLIER_GO_PRESENT; + else + duration *= P2P_ROC_DURATION_MULTIPLIER_GO_ABSENT; + } + + hdd_prevent_suspend(WIFI_POWER_EVENT_WAKELOCK_ROC); + qdf_runtime_pm_prevent_suspend(&pHddCtx->runtime_context.roc); + INIT_COMPLETION(pAdapter->rem_on_chan_ready_event); + + /* call sme API to start remain on channel. */ + if ((QDF_STA_MODE == pAdapter->device_mode) || + (QDF_P2P_CLIENT_MODE == pAdapter->device_mode) || + (QDF_P2P_DEVICE_MODE == pAdapter->device_mode) + ) { + uint8_t sessionId = pAdapter->sessionId; + /* call sme API to start remain on channel. */ + + if (QDF_STATUS_SUCCESS != sme_remain_on_channel( + WLAN_HDD_GET_HAL_CTX(pAdapter), + sessionId, + pRemainChanCtx->chan.hw_value, duration, + wlan_hdd_remain_on_channel_callback, + pAdapter, + (pRemainChanCtx->rem_on_chan_request == + REMAIN_ON_CHANNEL_REQUEST) ? true : false, + &pRemainChanCtx->scan_id)) { + hdd_err("sme_remain_on_channel failed"); + mutex_lock(&cfgState->remain_on_chan_ctx_lock); + pAdapter->is_roc_inprogress = false; + pRemainChanCtx = cfgState->remain_on_chan_ctx; + hdd_info("Freeing ROC ctx cfgState->remain_on_chan_ctx=%p", + cfgState->remain_on_chan_ctx); + if (pRemainChanCtx) { + if (qdf_mc_timer_destroy( + &pRemainChanCtx-> + hdd_remain_on_chan_timer) + != QDF_STATUS_SUCCESS) + hdd_err("Failed to destroy hdd_remain_on_chan_timer"); + qdf_mem_free(pRemainChanCtx); + cfgState->remain_on_chan_ctx = NULL; + } + mutex_unlock(&cfgState->remain_on_chan_ctx_lock); + qdf_runtime_pm_allow_suspend(&pHddCtx->runtime_context. + roc); + hdd_allow_suspend(WIFI_POWER_EVENT_WAKELOCK_ROC); + return -EINVAL; + } + + if (REMAIN_ON_CHANNEL_REQUEST == + pRemainChanCtx->rem_on_chan_request) { + if (QDF_STATUS_SUCCESS != sme_register_mgmt_frame( + WLAN_HDD_GET_HAL_CTX(pAdapter), + sessionId, + (SIR_MAC_MGMT_FRAME << 2) | + (SIR_MAC_MGMT_PROBE_REQ << 4), + NULL, 0)) + hdd_err("sme_register_mgmt_frame failed"); + } + + } else if ((QDF_SAP_MODE == pAdapter->device_mode) || + (QDF_P2P_GO_MODE == pAdapter->device_mode)) { + /* call sme API to start remain on channel. */ + if (QDF_STATUS_SUCCESS != wlansap_remain_on_channel( + WLAN_HDD_GET_SAP_CTX_PTR(pAdapter), + pRemainChanCtx->chan.hw_value, + duration, wlan_hdd_remain_on_channel_callback, + pAdapter, &pRemainChanCtx->scan_id)) { + hdd_err("wlansap_remain_on_channel failed"); + mutex_lock(&cfgState->remain_on_chan_ctx_lock); + pAdapter->is_roc_inprogress = false; + pRemainChanCtx = cfgState->remain_on_chan_ctx; + hdd_info("Freeing ROC ctx cfgState->remain_on_chan_ctx=%p", + cfgState->remain_on_chan_ctx); + if (pRemainChanCtx) { + if (qdf_mc_timer_destroy( + &pRemainChanCtx-> + hdd_remain_on_chan_timer) + != QDF_STATUS_SUCCESS) + hdd_err("Failed to destroy hdd_remain_on_chan_timer"); + qdf_mem_free(pRemainChanCtx); + cfgState->remain_on_chan_ctx = NULL; + } + mutex_unlock(&cfgState->remain_on_chan_ctx_lock); + qdf_runtime_pm_allow_suspend(&pHddCtx->runtime_context. + roc); + hdd_allow_suspend(WIFI_POWER_EVENT_WAKELOCK_ROC); + return -EINVAL; + } + + if (QDF_STATUS_SUCCESS != wlansap_register_mgmt_frame( + WLAN_HDD_GET_SAP_CTX_PTR(pAdapter), + (SIR_MAC_MGMT_FRAME << 2) | + (SIR_MAC_MGMT_PROBE_REQ << 4), NULL, 0)) { + hdd_err("wlansap_register_mgmt_frame return fail"); + wlansap_cancel_remain_on_channel( + WLAN_HDD_GET_SAP_CTX_PTR(pAdapter), + pRemainChanCtx->scan_id); + qdf_runtime_pm_allow_suspend(&pHddCtx->runtime_context. + roc); + hdd_allow_suspend(WIFI_POWER_EVENT_WAKELOCK_ROC); + return -EINVAL; + } + + } + hdd_tdls_notify_p2p_roc(pHddCtx, P2P_ROC_START); + return 0; +} + +/** + * wlan_hdd_roc_request_enqueue() - enqueue remain on channel request + * @adapter: Pointer to the adapter + * @remain_chan_ctx: Pointer to the remain on channel context + * + * Return: 0 on success, error number otherwise + */ +static int wlan_hdd_roc_request_enqueue(hdd_adapter_t *adapter, + hdd_remain_on_chan_ctx_t *remain_chan_ctx) +{ + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + hdd_roc_req_t *hdd_roc_req; + QDF_STATUS status; + + /* + * "Driver is busy" OR "there is already RoC request inside the queue" + * so enqueue this RoC Request and execute sequentially later. + */ + + hdd_roc_req = qdf_mem_malloc(sizeof(*hdd_roc_req)); + + if (NULL == hdd_roc_req) { + hdd_alert("malloc failed for roc req context"); + return -ENOMEM; + } + + hdd_roc_req->pAdapter = adapter; + hdd_roc_req->pRemainChanCtx = remain_chan_ctx; + + /* Enqueue this RoC request */ + qdf_spin_lock(&hdd_ctx->hdd_roc_req_q_lock); + status = qdf_list_insert_back(&hdd_ctx->hdd_roc_req_q, + &hdd_roc_req->node); + qdf_spin_unlock(&hdd_ctx->hdd_roc_req_q_lock); + + if (QDF_STATUS_SUCCESS != status) { + hdd_alert("Not able to enqueue RoC Req context"); + qdf_mem_free(hdd_roc_req); + return -EINVAL; + } + + return 0; +} + +/** + * wlan_hdd_indicate_roc_drop() - Indicate roc drop to userspace + * @adapter: HDD adapter + * @ctx: Remain on channel context + * + * Send remain on channel ready and cancel event for the queued + * roc that is being dropped. This will ensure that the userspace + * will send more roc requests. If this drop is not indicated to + * userspace, subsequent roc will not be sent to the driver since + * the userspace times out waiting for the remain on channel ready + * event. + * + * Return: None + */ +static void wlan_hdd_indicate_roc_drop(hdd_adapter_t *adapter, + hdd_remain_on_chan_ctx_t *ctx) +{ + hdd_debug("indicate roc drop to userspace"); + cfg80211_ready_on_channel( + adapter->dev->ieee80211_ptr, + (uintptr_t)ctx, + &ctx->chan, + ctx->duration, GFP_KERNEL); + + cfg80211_remain_on_channel_expired( + ctx->dev->ieee80211_ptr, + ctx->cookie, + &ctx->chan, + GFP_KERNEL); +} + +/** + * wlan_hdd_roc_request_dequeue() - dequeue remain on channel request + * @work: Pointer to work queue struct + * + * Return: none + */ +void wlan_hdd_roc_request_dequeue(struct work_struct *work) +{ + QDF_STATUS status; + int ret = 0; + hdd_roc_req_t *hdd_roc_req; + hdd_context_t *hdd_ctx = + container_of(work, hdd_context_t, roc_req_work.work); + + hdd_debug("going to dequeue roc"); + + if (0 != (wlan_hdd_validate_context(hdd_ctx))) + return; + + /* + * The queued roc requests is dequeued and processed one at a time. + * Callback 'wlan_hdd_remain_on_channel_callback' ensures + * that any pending roc in the queue will be scheduled + * on the current roc completion by scheduling the work queue. + */ + qdf_spin_lock(&hdd_ctx->hdd_roc_req_q_lock); + if (list_empty(&hdd_ctx->hdd_roc_req_q.anchor)) { + qdf_spin_unlock(&hdd_ctx->hdd_roc_req_q_lock); + return; + } + status = qdf_list_remove_front(&hdd_ctx->hdd_roc_req_q, + (qdf_list_node_t **) &hdd_roc_req); + qdf_spin_unlock(&hdd_ctx->hdd_roc_req_q_lock); + if (QDF_STATUS_SUCCESS != status) { + hdd_debug("unable to remove roc element from list"); + return; + } + ret = wlan_hdd_execute_remain_on_channel( + hdd_roc_req->pAdapter, + hdd_roc_req->pRemainChanCtx); + if (ret == -EBUSY) { + hdd_err("dropping RoC request"); + wlan_hdd_indicate_roc_drop(hdd_roc_req->pAdapter, + hdd_roc_req->pRemainChanCtx); + qdf_mem_free(hdd_roc_req->pRemainChanCtx); + } + qdf_mem_free(hdd_roc_req); +} + +static int wlan_hdd_request_remain_on_channel(struct wiphy *wiphy, + struct net_device *dev, + struct ieee80211_channel *chan, + unsigned int duration, + u64 *cookie, + rem_on_channel_request_type_t + request_type) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *pHddCtx; + hdd_remain_on_chan_ctx_t *pRemainChanCtx; + bool isBusy = false; + uint32_t size = 0; + hdd_adapter_t *sta_adapter; + int ret; + int status = 0; + + hdd_notice("Device_mode %s(%d)", + hdd_device_mode_to_string(pAdapter->device_mode), + pAdapter->device_mode); + hdd_info("chan(hw_val)0x%x chan(centerfreq) %d, duration %d", + chan->hw_value, chan->center_freq, duration); + + pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + ret = wlan_hdd_validate_context(pHddCtx); + if (0 != ret) + return ret; + + if (cds_is_connection_in_progress(NULL, NULL)) { + hdd_notice("Connection is in progress"); + isBusy = true; + } + pRemainChanCtx = qdf_mem_malloc(sizeof(hdd_remain_on_chan_ctx_t)); + if (NULL == pRemainChanCtx) { + hdd_alert("Not able to allocate memory for Channel context"); + return -ENOMEM; + } + + qdf_mem_copy(&pRemainChanCtx->chan, chan, + sizeof(struct ieee80211_channel)); + pRemainChanCtx->duration = duration; + pRemainChanCtx->dev = dev; + *cookie = (uintptr_t) pRemainChanCtx; + pRemainChanCtx->cookie = *cookie; + pRemainChanCtx->rem_on_chan_request = request_type; + pRemainChanCtx->action_pkt_buff.freq = 0; + pRemainChanCtx->action_pkt_buff.frame_ptr = NULL; + pRemainChanCtx->action_pkt_buff.frame_length = 0; + pRemainChanCtx->hdd_remain_on_chan_cancel_in_progress = false; + if (REMAIN_ON_CHANNEL_REQUEST == request_type) { + sta_adapter = hdd_get_adapter(pHddCtx, QDF_STA_MODE); + if ((NULL != sta_adapter) && + hdd_conn_is_connected( + WLAN_HDD_GET_STATION_CTX_PTR(sta_adapter))) { + if (pAdapter->last_roc_ts != 0 && + (((uint64_t)qdf_mc_timer_get_system_time() - + pAdapter->last_roc_ts) < + pHddCtx->config->p2p_listen_defer_interval)) { + if (pRemainChanCtx->duration > HDD_P2P_MAX_ROC_DURATION) + pRemainChanCtx->duration = + HDD_P2P_MAX_ROC_DURATION; + + wlan_hdd_roc_request_enqueue(pAdapter, pRemainChanCtx); + schedule_delayed_work(&pHddCtx->roc_req_work, + msecs_to_jiffies( + pHddCtx->config->p2p_listen_defer_interval)); + hdd_info("Defer interval is %hu, pAdapter %p", + pHddCtx->config->p2p_listen_defer_interval, + pAdapter); + return 0; + } + } + } + + qdf_spin_lock(&pHddCtx->hdd_roc_req_q_lock); + size = qdf_list_size(&(pHddCtx->hdd_roc_req_q)); + qdf_spin_unlock(&pHddCtx->hdd_roc_req_q_lock); + if ((isBusy == false) && (!size)) { + status = wlan_hdd_execute_remain_on_channel(pAdapter, + pRemainChanCtx); + if (status == -EBUSY) { + if (wlan_hdd_roc_request_enqueue(pAdapter, + pRemainChanCtx)) { + qdf_mem_free(pRemainChanCtx); + return -EAGAIN; + } + } + return 0; + } else { + if (wlan_hdd_roc_request_enqueue(pAdapter, pRemainChanCtx)) { + qdf_mem_free(pRemainChanCtx); + return -EAGAIN; + } + } + + /* + * If a connection is not in progress (isBusy), before scheduling + * the work queue it is necessary to check if a roc in in progress + * or not because: if an roc is in progress, the dequeued roc + * that will be processed will be dropped. To ensure that this new + * roc request is not dropped, it is suggested to check if an roc + * is in progress or not. The existing roc completion will provide + * the trigger to dequeue the next roc request. + */ + if (isBusy == false && pAdapter->is_roc_inprogress == false) { + hdd_debug("scheduling delayed work: no connection/roc active"); + schedule_delayed_work(&pHddCtx->roc_req_work, 0); + } + return 0; +} + +static int __wlan_hdd_cfg80211_remain_on_channel(struct wiphy *wiphy, + struct wireless_dev *wdev, + struct ieee80211_channel *chan, + unsigned int duration, + u64 *cookie) +{ + struct net_device *dev = wdev->netdev; + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *hdd_ctx; + int ret; + + ENTER(); + + hdd_ctx = WLAN_HDD_GET_CTX(pAdapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EINVAL; + } + + if (wlan_hdd_validate_session_id(pAdapter->sessionId)) { + hdd_err("invalid session id: %d", pAdapter->sessionId); + return -EINVAL; + } + + MTRACE(qdf_trace(QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_REMAIN_ON_CHANNEL, + pAdapter->sessionId, REMAIN_ON_CHANNEL_REQUEST)); + + ret = wlan_hdd_request_remain_on_channel(wiphy, dev, chan, + duration, cookie, + REMAIN_ON_CHANNEL_REQUEST); + EXIT(); + return ret; +} + +int wlan_hdd_cfg80211_remain_on_channel(struct wiphy *wiphy, + struct wireless_dev *wdev, + struct ieee80211_channel *chan, + unsigned int duration, u64 *cookie) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_remain_on_channel(wiphy, + wdev, + chan, + duration, cookie); + cds_ssr_unprotect(__func__); + + return ret; +} + +void hdd_remain_chan_ready_handler(hdd_adapter_t *pAdapter, + uint32_t scan_id) +{ + hdd_cfg80211_state_t *cfgState = NULL; + hdd_remain_on_chan_ctx_t *pRemainChanCtx = NULL; + QDF_STATUS status; + + if (NULL == pAdapter) { + hdd_err("pAdapter is NULL"); + return; + } + cfgState = WLAN_HDD_GET_CFG_STATE_PTR(pAdapter); + hdd_notice("Ready on chan ind %d", scan_id); + + pAdapter->start_roc_ts = (uint64_t)qdf_mc_timer_get_system_time(); + mutex_lock(&cfgState->remain_on_chan_ctx_lock); + pRemainChanCtx = cfgState->remain_on_chan_ctx; + if (pRemainChanCtx != NULL) { + MTRACE(qdf_trace(QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_REMAINCHANREADYHANDLER, + pAdapter->sessionId, + pRemainChanCtx->duration)); + /* start timer for actual duration */ + if (QDF_TIMER_STATE_RUNNING == + qdf_mc_timer_get_current_state( + &pRemainChanCtx->hdd_remain_on_chan_timer)) { + hdd_notice("Timer Started before ready event!!!"); + if (qdf_mc_timer_stop(&pRemainChanCtx-> + hdd_remain_on_chan_timer) + != QDF_STATUS_SUCCESS) + hdd_err("Failed to stop hdd_remain_on_chan_timer"); + } + status = + qdf_mc_timer_start(&pRemainChanCtx-> + hdd_remain_on_chan_timer, + (pRemainChanCtx->duration + + COMPLETE_EVENT_PROPOGATE_TIME)); + if (status != QDF_STATUS_SUCCESS) { + hdd_err("Remain on Channel timer start failed"); + } + + if (REMAIN_ON_CHANNEL_REQUEST == + pRemainChanCtx->rem_on_chan_request) { + cfg80211_ready_on_channel( + pAdapter->dev-> + ieee80211_ptr, + (uintptr_t) + pRemainChanCtx, + &pRemainChanCtx->chan, + pRemainChanCtx-> + duration, GFP_KERNEL); + } else if (OFF_CHANNEL_ACTION_TX == + pRemainChanCtx->rem_on_chan_request) { + complete(&pAdapter->offchannel_tx_event); + } + /* Check for cached action frame */ + if (pRemainChanCtx->action_pkt_buff.frame_length != 0) { + hdd_notice("Sent cached action frame to supplicant"); +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0)) + cfg80211_rx_mgmt(pAdapter->dev->ieee80211_ptr, + pRemainChanCtx->action_pkt_buff.freq, 0, + pRemainChanCtx->action_pkt_buff.frame_ptr, + pRemainChanCtx->action_pkt_buff.frame_length, + NL80211_RXMGMT_FLAG_ANSWERED); +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)) + cfg80211_rx_mgmt(pAdapter->dev->ieee80211_ptr, + pRemainChanCtx->action_pkt_buff.freq, 0, + pRemainChanCtx->action_pkt_buff.frame_ptr, + pRemainChanCtx->action_pkt_buff.frame_length, + NL80211_RXMGMT_FLAG_ANSWERED, GFP_ATOMIC); +#else + cfg80211_rx_mgmt(pAdapter->dev->ieee80211_ptr, + pRemainChanCtx->action_pkt_buff.freq, + 0, + pRemainChanCtx->action_pkt_buff. + frame_ptr, + pRemainChanCtx->action_pkt_buff. + frame_length, GFP_ATOMIC); +#endif /* LINUX_VERSION_CODE */ + + qdf_mem_free(pRemainChanCtx->action_pkt_buff.frame_ptr); + pRemainChanCtx->action_pkt_buff.frame_length = 0; + pRemainChanCtx->action_pkt_buff.freq = 0; + pRemainChanCtx->action_pkt_buff.frame_ptr = NULL; + } + complete(&pAdapter->rem_on_chan_ready_event); + } else { + hdd_warn("No Pending Remain on channel Request"); + } + mutex_unlock(&cfgState->remain_on_chan_ctx_lock); + return; +} + +static int +__wlan_hdd_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy, + struct wireless_dev *wdev, + u64 cookie) +{ + struct net_device *dev = wdev->netdev; + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_cfg80211_state_t *cfgState = WLAN_HDD_GET_CFG_STATE_PTR(pAdapter); + hdd_remain_on_chan_ctx_t *pRemainChanCtx; + hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + int status; + int qdf_status; + unsigned long rc; + qdf_list_node_t *tmp, *q; + hdd_roc_req_t *curr_roc_req; + uint32_t roc_scan_id; + + ENTER(); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EINVAL; + } + + if (wlan_hdd_validate_session_id(pAdapter->sessionId)) { + hdd_err("invalid session id: %d", pAdapter->sessionId); + return -EINVAL; + } + + status = wlan_hdd_validate_context(pHddCtx); + + if (0 != status) + return status; + qdf_spin_lock(&pHddCtx->hdd_roc_req_q_lock); + list_for_each_safe(tmp, q, &pHddCtx->hdd_roc_req_q.anchor) { + curr_roc_req = list_entry(tmp, hdd_roc_req_t, node); + if ((uintptr_t) curr_roc_req->pRemainChanCtx == cookie) { + qdf_status = qdf_list_remove_node(&pHddCtx->hdd_roc_req_q, + (qdf_list_node_t *) + curr_roc_req); + qdf_spin_unlock(&pHddCtx->hdd_roc_req_q_lock); + if (qdf_status == QDF_STATUS_SUCCESS) { + qdf_mem_free(curr_roc_req->pRemainChanCtx); + qdf_mem_free(curr_roc_req); + } + return 0; + } + } + qdf_spin_unlock(&pHddCtx->hdd_roc_req_q_lock); + /* FIXME cancel currently running remain on chan. + * Need to check cookie and cancel accordingly + */ + mutex_lock(&cfgState->remain_on_chan_ctx_lock); + pRemainChanCtx = cfgState->remain_on_chan_ctx; + if ((cfgState->remain_on_chan_ctx == NULL) || + (cfgState->remain_on_chan_ctx->cookie != cookie)) { + mutex_unlock(&cfgState->remain_on_chan_ctx_lock); + hdd_err("No Remain on channel pending with specified cookie value"); + return -EINVAL; + } + + if (NULL != cfgState->remain_on_chan_ctx) { + if (qdf_mc_timer_stop(&cfgState->remain_on_chan_ctx-> + hdd_remain_on_chan_timer) + != QDF_STATUS_SUCCESS) + hdd_err("Failed to stop hdd_remain_on_chan_timer"); + if (true == + pRemainChanCtx->hdd_remain_on_chan_cancel_in_progress) { + mutex_unlock(&cfgState->remain_on_chan_ctx_lock); + hdd_notice("ROC timer cancellation in progress, wait for completion"); + rc = wait_for_completion_timeout(&pAdapter-> + cancel_rem_on_chan_var, + msecs_to_jiffies + (WAIT_CANCEL_REM_CHAN)); + if (!rc) { + hdd_err("wait on cancel_rem_on_chan_var timed out"); + } + return 0; + } else + pRemainChanCtx->hdd_remain_on_chan_cancel_in_progress = + true; + } + roc_scan_id = pRemainChanCtx->scan_id; + mutex_unlock(&cfgState->remain_on_chan_ctx_lock); + + /* wait until remain on channel ready event received + * for already issued remain on channel request */ + rc = wait_for_completion_timeout(&pAdapter->rem_on_chan_ready_event, + msecs_to_jiffies(WAIT_REM_CHAN_READY)); + if (!rc) { + hdd_err("timeout waiting for remain on channel ready indication"); + + if (cds_is_driver_recovering()) { + hdd_err("Recovery in Progress. State: 0x%x Ignore!!!", + cds_get_driver_state()); + return -EAGAIN; + } + cds_flush_logs(WLAN_LOG_TYPE_FATAL, + WLAN_LOG_INDICATOR_HOST_DRIVER, + WLAN_LOG_REASON_HDD_TIME_OUT, + true, false); + } + INIT_COMPLETION(pAdapter->cancel_rem_on_chan_var); + /* Issue abort remain on chan request to sme. + * The remain on channel callback will make sure the remain_on_chan + * expired event is sent. + */ + if ((QDF_STA_MODE == pAdapter->device_mode) || + (QDF_P2P_CLIENT_MODE == pAdapter->device_mode) || + (QDF_P2P_DEVICE_MODE == pAdapter->device_mode) + ) { + + uint8_t sessionId = pAdapter->sessionId; + sme_cancel_remain_on_channel(WLAN_HDD_GET_HAL_CTX(pAdapter), + sessionId, roc_scan_id); + } else if ((QDF_SAP_MODE == pAdapter->device_mode) || + (QDF_P2P_GO_MODE == pAdapter->device_mode) + ) { + wlansap_cancel_remain_on_channel( + WLAN_HDD_GET_SAP_CTX_PTR(pAdapter), roc_scan_id); + + } else { + hdd_err("Invalid device_mode %s(%d)", + hdd_device_mode_to_string(pAdapter->device_mode), + pAdapter->device_mode); + return -EIO; + } + rc = wait_for_completion_timeout(&pAdapter->cancel_rem_on_chan_var, + msecs_to_jiffies + (WAIT_CANCEL_REM_CHAN)); + if (!rc) { + hdd_err("wait on cancel_rem_on_chan_var timed out"); + } + hdd_allow_suspend(WIFI_POWER_EVENT_WAKELOCK_ROC); + EXIT(); + return 0; +} + +int wlan_hdd_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy, + struct wireless_dev *wdev, + u64 cookie) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_cancel_remain_on_channel(wiphy, + wdev, + cookie); + cds_ssr_unprotect(__func__); + + return ret; +} + +static int __wlan_hdd_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, + struct ieee80211_channel *chan, bool offchan, + unsigned int wait, + const u8 *buf, size_t len, bool no_cck, + bool dont_wait_for_ack, u64 *cookie) +{ + struct net_device *dev = wdev->netdev; + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_cfg80211_state_t *cfgState = WLAN_HDD_GET_CFG_STATE_PTR(pAdapter); + hdd_remain_on_chan_ctx_t *pRemainChanCtx; + hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + uint16_t extendedWait = 0; + uint8_t type = WLAN_HDD_GET_TYPE_FRM_FC(buf[0]); + uint8_t subType = WLAN_HDD_GET_SUBTYPE_FRM_FC(buf[0]); + tActionFrmType actionFrmType; + bool noack = 0; + int status; + unsigned long rc; + hdd_adapter_t *goAdapter; + uint16_t current_freq; + uint8_t home_ch = 0; + + ENTER(); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EINVAL; + } + + if (wlan_hdd_validate_session_id(pAdapter->sessionId)) { + hdd_err("invalid session id: %d", pAdapter->sessionId); + return -EINVAL; + } + + MTRACE(qdf_trace(QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_ACTION, pAdapter->sessionId, + pAdapter->device_mode)); + status = wlan_hdd_validate_context(pHddCtx); + + if (0 != status) + return status; + + hdd_notice("Device_mode %s(%d) type: %d, wait: %d, offchan: %d, category: %d, actionId: %d", + hdd_device_mode_to_string(pAdapter->device_mode), + pAdapter->device_mode, type, wait, offchan, + buf[WLAN_HDD_PUBLIC_ACTION_FRAME_BODY_OFFSET + + WLAN_HDD_PUBLIC_ACTION_FRAME_CATEGORY_OFFSET], + buf[WLAN_HDD_PUBLIC_ACTION_FRAME_BODY_OFFSET + + WLAN_HDD_PUBLIC_ACTION_FRAME_ACTION_OFFSET]); + +#ifdef WLAN_FEATURE_P2P_DEBUG + if ((type == SIR_MAC_MGMT_FRAME) && + (subType == SIR_MAC_MGMT_ACTION) && + wlan_hdd_is_type_p2p_action(&buf + [WLAN_HDD_PUBLIC_ACTION_FRAME_BODY_OFFSET])) { + actionFrmType = buf[WLAN_HDD_PUBLIC_ACTION_FRAME_TYPE_OFFSET]; + if (actionFrmType >= MAX_P2P_ACTION_FRAME_TYPE) { + hdd_notice("[P2P] unknown[%d] ---> OTA to " MAC_ADDRESS_STR, + actionFrmType, + MAC_ADDR_ARRAY(&buf + [WLAN_HDD_80211_FRM_DA_OFFSET])); + } else { + hdd_notice("[P2P] %s ---> OTA to " + MAC_ADDRESS_STR, + p2p_action_frame_type[actionFrmType], + MAC_ADDR_ARRAY(&buf + [WLAN_HDD_80211_FRM_DA_OFFSET])); + if ((actionFrmType == WLAN_HDD_PROV_DIS_REQ) + && (global_p2p_connection_status == P2P_NOT_ACTIVE)) { + global_p2p_connection_status = P2P_GO_NEG_PROCESS; + hdd_notice("[P2P State]Inactive state to GO negotiation progress state"); + } else if ((actionFrmType == WLAN_HDD_GO_NEG_CNF) && + (global_p2p_connection_status == + P2P_GO_NEG_PROCESS)) { + global_p2p_connection_status = + P2P_GO_NEG_COMPLETED; + hdd_notice("[P2P State]GO nego progress to GO nego completed state"); + } + } + } +#endif + + noack = dont_wait_for_ack; + + /* If the wait is coming as 0 with off channel set */ + /* then set the wait to 200 ms */ + if (offchan && !wait) { + wait = ACTION_FRAME_DEFAULT_WAIT; + mutex_lock(&cfgState->remain_on_chan_ctx_lock); + if (cfgState->remain_on_chan_ctx) { + + uint64_t current_time = + (uint64_t)qdf_mc_timer_get_system_time(); + int remaining_roc_time = + ((int) cfgState->remain_on_chan_ctx->duration - + (current_time - pAdapter->start_roc_ts)); + + if (remaining_roc_time > ACTION_FRAME_DEFAULT_WAIT) + wait = remaining_roc_time; + } + mutex_unlock(&cfgState->remain_on_chan_ctx_lock); + } + + if ((QDF_STA_MODE == pAdapter->device_mode) && + (type == SIR_MAC_MGMT_FRAME && + subType == SIR_MAC_MGMT_PROBE_RSP)) { + /* Drop Probe response received + * from supplicant in sta mode + */ + goto err_rem_channel; + } + + /* Call sme API to send out a action frame. */ + /* OR can we send it directly through data path?? */ + /* After tx completion send tx status back. */ + if ((QDF_SAP_MODE == pAdapter->device_mode) || + (QDF_P2P_GO_MODE == pAdapter->device_mode) + ) { + if (type == SIR_MAC_MGMT_FRAME) { + if (subType == SIR_MAC_MGMT_PROBE_RSP) { + /* Drop Probe response recieved from supplicant, as for GO and + SAP PE itself sends probe response + */ + goto err_rem_channel; + } else if ((subType == SIR_MAC_MGMT_DISASSOC) || + (subType == SIR_MAC_MGMT_DEAUTH)) { + /* During EAP failure or P2P Group Remove supplicant + * is sending del_station command to driver. From + * del_station function, Driver will send deauth frame to + * p2p client. No need to send disassoc frame from here. + * so Drop the frame here and send tx indication back to + * supplicant. + */ + uint8_t dstMac[ETH_ALEN] = { 0 }; + memcpy(&dstMac, + &buf[WLAN_HDD_80211_FRM_DA_OFFSET], + ETH_ALEN); + hdd_info("Deauth/Disassoc received for STA:" + MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(dstMac)); + goto err_rem_channel; + } + } + } + + if (NULL != cfgState->buf) { + if (!noack) { + hdd_warn("Previous P2P Action frame packet pending"); + hdd_cleanup_actionframe(pAdapter->pHddCtx, pAdapter); + } else { + hdd_err("Pending Action frame packet return EBUSY"); + return -EBUSY; + } + } + + if (subType == SIR_MAC_MGMT_ACTION) { + hdd_notice("Action frame tx request : %s", + hdd_get_action_string(buf + [WLAN_HDD_PUBLIC_ACTION_FRAME_OFFSET])); + } + + if ((pAdapter->device_mode == QDF_SAP_MODE) && + (test_bit(SOFTAP_BSS_STARTED, &pAdapter->event_flags))) { + home_ch = pAdapter->sessionCtx.ap.operatingChannel; + } else if ((pAdapter->device_mode == QDF_STA_MODE) && + (pAdapter->sessionCtx.station.conn_info.connState == + eConnectionState_Associated)) { + home_ch = + pAdapter->sessionCtx.station.conn_info.operationChannel; + } else { + goAdapter = hdd_get_adapter(pAdapter->pHddCtx, QDF_P2P_GO_MODE); + if (goAdapter && + (test_bit(SOFTAP_BSS_STARTED, &goAdapter->event_flags))) + home_ch = goAdapter->sessionCtx.ap.operatingChannel; + } + + if (chan && + (ieee80211_frequency_to_channel(chan->center_freq) == + home_ch)) { + /* if adapter is already on requested ch, no need for ROC */ + wait = 0; + hdd_notice("Adapter already on requested ch. No ROC needed"); + goto send_frame; + } + + if (offchan && wait && chan) { + int status; + rem_on_channel_request_type_t req_type = OFF_CHANNEL_ACTION_TX; + /* In case of P2P Client mode if we are already */ + /* on the same channel then send the frame directly */ + + mutex_lock(&cfgState->remain_on_chan_ctx_lock); + pRemainChanCtx = cfgState->remain_on_chan_ctx; + if ((type == SIR_MAC_MGMT_FRAME) && + (subType == SIR_MAC_MGMT_ACTION) && + hdd_p2p_is_action_type_rsp(&buf + [WLAN_HDD_PUBLIC_ACTION_FRAME_BODY_OFFSET]) + && cfgState->remain_on_chan_ctx + && cfgState->current_freq == chan->center_freq) { + if (QDF_TIMER_STATE_RUNNING == + qdf_mc_timer_get_current_state(&cfgState-> + remain_on_chan_ctx-> + hdd_remain_on_chan_timer)) { + + /* In the latest wpa_supplicant, the wait time + * for go negotiation response is set to 100ms, + * due to which, there could be a possibility + * that, if the go negotaition confirmation + * frame is not received within 100 msec, ROC + * would be timeout and resulting in connection + * failures as the device will not be on the + * listen channel anymore to receive the conf + * frame. Also wpa_supplicant has set the wait + * to 50msec for go negotiation confirmation, + * invitation response and prov discovery rsp + * frames. So increase the wait time for all + * these frames. + */ + actionFrmType = buf + [WLAN_HDD_PUBLIC_ACTION_FRAME_TYPE_OFFSET]; + if (actionFrmType == WLAN_HDD_GO_NEG_RESP || + actionFrmType == WLAN_HDD_PROV_DIS_RESP) + wait = wait + ACTION_FRAME_RSP_WAIT; + else if (actionFrmType == + WLAN_HDD_GO_NEG_CNF || + actionFrmType == + WLAN_HDD_INVITATION_RESP) + wait = wait + ACTION_FRAME_ACK_WAIT; + + hdd_info("Extending the wait time %d for actionFrmType=%d", + wait, actionFrmType); + + if (qdf_mc_timer_stop(&cfgState-> + remain_on_chan_ctx-> + hdd_remain_on_chan_timer) + != QDF_STATUS_SUCCESS) + hdd_warn("Failed to stop hdd_remain_on_chan_timer"); + status = + qdf_mc_timer_start(&cfgState-> + remain_on_chan_ctx-> + hdd_remain_on_chan_timer, + wait); + if (status != QDF_STATUS_SUCCESS) { + hdd_warn("Remain on Channel timer start failed"); + } + mutex_unlock(&cfgState-> + remain_on_chan_ctx_lock); + goto send_frame; + } else { + if (pRemainChanCtx-> + hdd_remain_on_chan_cancel_in_progress == + true) { + mutex_unlock(&cfgState-> + remain_on_chan_ctx_lock); + hdd_info("action frame tx: waiting for completion of ROC "); + + rc = wait_for_completion_timeout + (&pAdapter->cancel_rem_on_chan_var, + msecs_to_jiffies + (WAIT_CANCEL_REM_CHAN)); + if (!rc) { + hdd_warn("wait on cancel_rem_on_chan_var timed out"); + } + + } else + mutex_unlock(&cfgState-> + remain_on_chan_ctx_lock); + } + } else + mutex_unlock(&cfgState->remain_on_chan_ctx_lock); + + mutex_lock(&cfgState->remain_on_chan_ctx_lock); + pRemainChanCtx = cfgState->remain_on_chan_ctx; + + /* At this point if remain_on_chan_ctx exists but timer not + * running means that roc workqueue requested a new RoC and it + * is in progress. So wait for Ready on channel indication + */ + if ((pRemainChanCtx) && + (QDF_TIMER_STATE_RUNNING != + qdf_mc_timer_get_current_state( + &pRemainChanCtx->hdd_remain_on_chan_timer))) { + hdd_notice("remain_on_chan_ctx exists but RoC timer not running. wait for ready on channel"); + rc = wait_for_completion_timeout(&pAdapter-> + rem_on_chan_ready_event, + msecs_to_jiffies + (WAIT_REM_CHAN_READY)); + if (!rc) + hdd_err("timeout waiting for remain on channel ready indication"); + } + + if ((pRemainChanCtx != NULL) && + (cfgState->current_freq == chan->center_freq)) { + mutex_unlock(&cfgState->remain_on_chan_ctx_lock); + hdd_notice("action frame: extending the wait time"); + extendedWait = (uint16_t) wait; + goto send_frame; + } + + mutex_unlock(&cfgState->remain_on_chan_ctx_lock); + INIT_COMPLETION(pAdapter->offchannel_tx_event); + + status = wlan_hdd_request_remain_on_channel(wiphy, dev, chan, + wait, cookie, + req_type); + if (0 != status) { + if ((-EBUSY == status) && + (cfgState->current_freq == chan->center_freq)) { + goto send_frame; + } + goto err_rem_channel; + } + /* This will extend timer in LIM when sending Any action frame + * It will cover remain on channel timer till next action frame + * in rx direction. + */ + extendedWait = (uint16_t) wait; + /* Wait for driver to be ready on the requested channel */ + rc = wait_for_completion_timeout(&pAdapter->offchannel_tx_event, + msecs_to_jiffies + (WAIT_CHANGE_CHANNEL_FOR_OFFCHANNEL_TX)); + if (!rc) { + hdd_err("wait on offchannel_tx_event timed out"); + goto err_rem_channel; + } + } else if (offchan) { + /* Check before sending action frame + whether we already remain on channel */ + if (NULL == cfgState->remain_on_chan_ctx) { + goto err_rem_channel; + } + } +send_frame: + + if (!noack) { + cfgState->buf = qdf_mem_malloc(len); /* buf; */ + if (cfgState->buf == NULL) + return -ENOMEM; + + cfgState->len = len; + + qdf_mem_copy(cfgState->buf, buf, len); + + mutex_lock(&cfgState->remain_on_chan_ctx_lock); + + if (cfgState->remain_on_chan_ctx) { + cfgState->action_cookie = + cfgState->remain_on_chan_ctx->cookie; + *cookie = cfgState->action_cookie; + } else { + *cookie = (uintptr_t) cfgState->buf; + cfgState->action_cookie = *cookie; + } + + mutex_unlock(&cfgState->remain_on_chan_ctx_lock); + } + + /* + * Firmware needs channel information for action frames + * which are not sent on the current operating channel of VDEV + */ + if ((QDF_P2P_DEVICE_MODE == pAdapter->device_mode) || + (QDF_P2P_CLIENT_MODE == pAdapter->device_mode) || + (QDF_P2P_GO_MODE == pAdapter->device_mode)) { + if (chan && (chan->center_freq != 0)) + current_freq = chan->center_freq; + else + current_freq = cfgState->current_freq; + } else { + current_freq = 0; + } + + INIT_COMPLETION(pAdapter->tx_action_cnf_event); + + if ((QDF_STA_MODE == pAdapter->device_mode) || + (QDF_P2P_CLIENT_MODE == pAdapter->device_mode) || + (QDF_P2P_DEVICE_MODE == pAdapter->device_mode)) { + uint8_t sessionId = pAdapter->sessionId; + + if ((type == SIR_MAC_MGMT_FRAME) && + (subType == SIR_MAC_MGMT_ACTION) && + wlan_hdd_is_type_p2p_action(&buf + [WLAN_HDD_PUBLIC_ACTION_FRAME_BODY_OFFSET])) { + actionFrmType = + buf[WLAN_HDD_PUBLIC_ACTION_FRAME_TYPE_OFFSET]; + hdd_notice("Tx Action Frame %u", actionFrmType); + if (actionFrmType == WLAN_HDD_PROV_DIS_REQ) { + cfgState->actionFrmState = + HDD_PD_REQ_ACK_PENDING; + hdd_notice("HDD_PD_REQ_ACK_PENDING"); + } else if (actionFrmType == WLAN_HDD_GO_NEG_REQ) { + cfgState->actionFrmState = + HDD_GO_NEG_REQ_ACK_PENDING; + hdd_notice("HDD_GO_NEG_REQ_ACK_PENDING"); + } + } + + if (QDF_STATUS_SUCCESS != + sme_send_action(WLAN_HDD_GET_HAL_CTX(pAdapter), + sessionId, buf, len, extendedWait, noack, + current_freq)) { + hdd_err("sme_send_action returned fail"); + goto err; + } + } else if (QDF_SAP_MODE == pAdapter->device_mode || + QDF_P2P_GO_MODE == pAdapter->device_mode) { + if (QDF_STATUS_SUCCESS != + wlansap_send_action(WLAN_HDD_GET_SAP_CTX_PTR(pAdapter), + buf, len, 0, current_freq)) { + hdd_err("wlansap_send_action returned fail"); + goto err; + } + } + + return 0; +err: + if (!noack) { + hdd_send_action_cnf(pAdapter, false); + } + return 0; +err_rem_channel: + *cookie = (uintptr_t) cfgState; + cfg80211_mgmt_tx_status( + pAdapter->dev->ieee80211_ptr, + *cookie, buf, len, false, GFP_KERNEL); + EXIT(); + return 0; +} + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) +int wlan_hdd_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, + struct cfg80211_mgmt_tx_params *params, u64 *cookie) +#else +int wlan_hdd_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, + struct ieee80211_channel *chan, bool offchan, + unsigned int wait, + const u8 *buf, size_t len, bool no_cck, + bool dont_wait_for_ack, u64 *cookie) +#endif /* LINUX_VERSION_CODE */ +{ + int ret; + + cds_ssr_protect(__func__); + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) + ret = __wlan_hdd_mgmt_tx(wiphy, wdev, params->chan, params->offchan, + params->wait, params->buf, params->len, + params->no_cck, params->dont_wait_for_ack, + cookie); +#else + ret = __wlan_hdd_mgmt_tx(wiphy, wdev, chan, offchan, + wait, buf, len, no_cck, + dont_wait_for_ack, cookie); +#endif /* LINUX_VERSION_CODE */ + cds_ssr_unprotect(__func__); + + return ret; +} + +static int __wlan_hdd_cfg80211_mgmt_tx_cancel_wait(struct wiphy *wiphy, + struct wireless_dev *wdev, + u64 cookie) +{ + return wlan_hdd_cfg80211_cancel_remain_on_channel(wiphy, wdev, cookie); +} + +int wlan_hdd_cfg80211_mgmt_tx_cancel_wait(struct wiphy *wiphy, + struct wireless_dev *wdev, u64 cookie) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_mgmt_tx_cancel_wait(wiphy, wdev, cookie); + cds_ssr_unprotect(__func__); + + return ret; +} + +void hdd_send_action_cnf(hdd_adapter_t *pAdapter, bool actionSendSuccess) +{ + hdd_cfg80211_state_t *cfgState = WLAN_HDD_GET_CFG_STATE_PTR(pAdapter); + + cfgState->actionFrmState = HDD_IDLE; + + + if (NULL == cfgState->buf) { + return; + } + + if (cfgState->is_go_neg_ack_received) { + + cfgState->is_go_neg_ack_received = 0; + /* Sometimes its possible that host may receive the ack for GO + * negotiation req after sending go negotaition confirmation, + * in such case drop the ack received for the go negotiation + * request, so that supplicant waits for the confirmation ack + * from firmware. + */ + hdd_info("Drop the pending ack received in cfgState->actionFrmState %d", + cfgState->actionFrmState); + return; + } + + hdd_info("Send Action cnf, actionSendSuccess %d", + actionSendSuccess); + /* + * buf is the same pointer it passed us to send. Since we are sending + * it through control path, we use different buffers. + * In case of mac80211, they just push it to the skb and pass the same + * data while sending tx ack status. + * */ + cfg80211_mgmt_tx_status( + pAdapter->dev->ieee80211_ptr, + cfgState->action_cookie, + cfgState->buf, cfgState->len, + actionSendSuccess, GFP_KERNEL); + + qdf_mem_free(cfgState->buf); + cfgState->buf = NULL; + + complete(&pAdapter->tx_action_cnf_event); +} + +/** + * hdd_send_action_cnf_cb - action confirmation callback + * @session_id: SME session ID + * @tx_completed: ack status + * + * This function invokes hdd_sendActionCnf to update ack status to + * supplicant. + */ +void hdd_send_action_cnf_cb(uint32_t session_id, bool tx_completed) +{ + hdd_context_t *hdd_ctx; + hdd_adapter_t *adapter; + + ENTER(); + + /* Get the HDD context.*/ + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (0 != wlan_hdd_validate_context(hdd_ctx)) + return; + + adapter = hdd_get_adapter_by_sme_session_id(hdd_ctx, session_id); + if (NULL == adapter) { + hdd_err("adapter not found"); + return; + } + + if (WLAN_HDD_ADAPTER_MAGIC != adapter->magic) { + hdd_err("adapter has invalid magic"); + return; + } + + hdd_send_action_cnf(adapter, tx_completed); +} + +/** + * hdd_set_p2p_noa + * + ***FUNCTION: + * This function is called from hdd_hostapd_ioctl function when Driver + * get P2P_SET_NOA comand from wpa_supplicant using private ioctl + * + ***LOGIC: + * Fill NoA Struct According to P2P Power save Option and Pass it to SME layer + * + ***ASSUMPTIONS: + * + * + ***NOTE: + * + * @param dev Pointer to net device structure + * @param command Pointer to command + * + * @return Status + */ + +int hdd_set_p2p_noa(struct net_device *dev, uint8_t *command) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter); + tP2pPsConfig NoA; + int count, duration, interval; + char *param; + int ret; + + param = strnchr(command, strlen(command), ' '); + if (param == NULL) { + hdd_err("strnchr failed to find delimeter"); + return -EINVAL; + } + param++; + ret = sscanf(param, "%d %d %d", &count, &interval, &duration); + if (ret != 3) { + hdd_err("P2P_SET GO NoA: fail to read params, ret=%d", + ret); + return -EINVAL; + } + if (count < 0 || interval < 0 || duration < 0 || + interval > MAX_MUS_VAL || duration > MAX_MUS_VAL) { + hdd_err("Invalid NOA parameters"); + return -EINVAL; + } + hdd_info("P2P_SET GO NoA: count=%d interval=%d duration=%d", + count, interval, duration); + duration = MS_TO_TU_MUS(duration); + /* PS Selection + * Periodic NoA (2) + * Single NOA (4) + */ + NoA.opp_ps = 0; + NoA.ctWindow = 0; + if (count == 1) { + NoA.duration = 0; + NoA.single_noa_duration = duration; + NoA.psSelection = P2P_POWER_SAVE_TYPE_SINGLE_NOA; + } else { + NoA.duration = duration; + NoA.single_noa_duration = 0; + NoA.psSelection = P2P_POWER_SAVE_TYPE_PERIODIC_NOA; + } + NoA.interval = MS_TO_TU_MUS(interval); + NoA.count = count; + NoA.sessionid = pAdapter->sessionId; + + hdd_info("P2P_PS_ATTR:oppPS %d ctWindow %d duration %d " + "interval %d count %d single noa duration %d " + "PsSelection %x", NoA.opp_ps, + NoA.ctWindow, NoA.duration, NoA.interval, + NoA.count, NoA.single_noa_duration, NoA.psSelection); + + sme_p2p_set_ps(hHal, &NoA); + return 0; +} + +/** + * hdd_set_p2p_opps + * + ***FUNCTION: + * This function is called from hdd_hostapd_ioctl function when Driver + * get P2P_SET_PS comand from wpa_supplicant using private ioctl + * + ***LOGIC: + * Fill NoA Struct According to P2P Power save Option and Pass it to SME layer + * + ***ASSUMPTIONS: + * + * + ***NOTE: + * + * @param dev Pointer to net device structure + * @param command Pointer to command + * + * @return Status + */ + +int hdd_set_p2p_opps(struct net_device *dev, uint8_t *command) +{ + hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + tHalHandle handle = WLAN_HDD_GET_HAL_CTX(adapter); + tP2pPsConfig noa; + char *param; + int legacy_ps, opp_ps, ctwindow; + int ret; + + param = strnchr(command, strlen(command), ' '); + if (param == NULL) { + hdd_err("strnchr failed to find delimiter"); + return -EINVAL; + } + param++; + ret = sscanf(param, "%d %d %d", &legacy_ps, &opp_ps, &ctwindow); + if (ret != 3) { + hdd_err("P2P_SET GO PS: fail to read params, ret=%d", ret); + return -EINVAL; + } + + if ((opp_ps != -1) && (opp_ps != 0) && (opp_ps != 1)) { + hdd_err("Invalid opp_ps value:%d", opp_ps); + return -EINVAL; + } + + /* P2P spec: 3.3.2 Power Management and discovery: + * CTWindow should be at least 10 TU. + * P2P spec: Table 27 - CTWindow and OppPS Parameters field format: + * CTWindow and OppPS Parameters together is 8 bits. + * CTWindow uses 7 bits (0-6, Bit 7 is for OppPS) + * 0 indicates that there shall be no CTWindow + */ + if ((ctwindow != -1) && (ctwindow != 0) && + (!((ctwindow >= 10) && (ctwindow <= 127)))) { + hdd_err("Invalid CT window value:%d", ctwindow); + return -EINVAL; + } + + hdd_info("P2P_SET GO PS: legacy_ps=%d opp_ps=%d ctwindow=%d", + legacy_ps, opp_ps, ctwindow); + + /* PS Selection + * Opportunistic Power Save (1) + */ + + /* From wpa_cli user need to use separate command to set ctWindow and Opps + * When user want to set ctWindow during that time other parameters + * values are coming from wpa_supplicant as -1. + * Example : User want to set ctWindow with 30 then wpa_cli command : + * P2P_SET ctwindow 30 + * Command Received at hdd_hostapd_ioctl is as below: + * P2P_SET_PS -1 -1 30 (legacy_ps = -1, opp_ps = -1, ctwindow = 30) + * + * e.g., 1: P2P_SET_PS 1 1 30 + * Driver sets the Opps and CTwindow as 30 and send it to FW. + * e.g., 2: P2P_SET_PS 1 -1 15 + * Driver caches the CTwindow value but not send the command to FW. + * e.g., 3: P2P_SET_PS 1 1 -1 + * Driver sends the command to FW with Opps enabled and CT window as + * 15 (last cached CTWindow value). + * (or) : P2P_SET_PS 1 1 20 + * Driver sends the command to FW with opps enabled and CT window + * as 20. + * + * legacy_ps param remains unused until required in the future. + */ + if (ctwindow != -1) + adapter->ctw = ctwindow; + + /* Send command to FW when OppPS is either enabled(1)/disbaled(0) */ + if (opp_ps != -1) { + adapter->ops = opp_ps; + noa.opp_ps = adapter->ops; + noa.ctWindow = adapter->ctw; + noa.duration = 0; + noa.single_noa_duration = 0; + noa.interval = 0; + noa.count = 0; + noa.psSelection = P2P_POWER_SAVE_TYPE_OPPORTUNISTIC; + noa.sessionid = adapter->sessionId; + + hdd_debug("P2P_PS_ATTR: oppPS %d ctWindow %d duration %d interval %d count %d single noa duration %d PsSelection %x", + noa.opp_ps, noa.ctWindow, + noa.duration, noa.interval, noa.count, + noa.single_noa_duration, + noa.psSelection); + + sme_p2p_set_ps(handle, &noa); + } + + return 0; +} + +int hdd_set_p2p_ps(struct net_device *dev, void *msgData) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter); + QDF_STATUS status = QDF_STATUS_SUCCESS; + tP2pPsConfig NoA; + p2p_app_setP2pPs_t *pappNoA = (p2p_app_setP2pPs_t *) msgData; + + NoA.opp_ps = pappNoA->opp_ps; + NoA.ctWindow = pappNoA->ctWindow; + NoA.duration = pappNoA->duration; + NoA.interval = pappNoA->interval; + NoA.count = pappNoA->count; + NoA.single_noa_duration = pappNoA->single_noa_duration; + NoA.psSelection = pappNoA->psSelection; + NoA.sessionid = pAdapter->sessionId; + + sme_p2p_set_ps(hHal, &NoA); + return status; +} + +static uint8_t wlan_hdd_get_session_type(enum nl80211_iftype type) +{ + switch (type) { + case NL80211_IFTYPE_AP: + return QDF_SAP_MODE; + case NL80211_IFTYPE_P2P_GO: + return QDF_P2P_GO_MODE; + case NL80211_IFTYPE_P2P_CLIENT: + return QDF_P2P_CLIENT_MODE; + case NL80211_IFTYPE_STATION: + return QDF_STA_MODE; + default: + return QDF_STA_MODE; + } +} + +/** + * __wlan_hdd_add_virtual_intf() - Add virtual interface + * @wiphy: wiphy pointer + * @name: User-visible name of the interface + * @name_assign_type: the name of assign type of the netdev + * @nl80211_iftype: (virtual) interface types + * @flags: moniter configuraiton flags (not used) + * @vif_params: virtual interface parameters (not used) + * + * Return: the pointer of wireless dev, otherwise ERR_PTR. + */ +static +struct wireless_dev *__wlan_hdd_add_virtual_intf(struct wiphy *wiphy, + const char *name, + unsigned char name_assign_type, + enum nl80211_iftype type, + u32 *flags, + struct vif_params *params) +{ + hdd_context_t *pHddCtx = (hdd_context_t *) wiphy_priv(wiphy); + hdd_adapter_t *pAdapter = NULL; + hdd_scaninfo_t *scan_info = NULL; + int ret; + uint8_t session_type; + + ENTER(); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return ERR_PTR(-EINVAL); + } + + ret = wlan_hdd_validate_context(pHddCtx); + if (0 != ret) + return ERR_PTR(ret); + + MTRACE(qdf_trace(QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_ADD_VIRTUAL_INTF, NO_SESSION, type)); + /* + * Allow addition multiple interfaces for QDF_P2P_GO_MODE, + * QDF_SAP_MODE, QDF_P2P_CLIENT_MODE and QDF_STA_MODE + * session type. + */ + session_type = wlan_hdd_get_session_type(type); + if (hdd_get_adapter(pHddCtx, session_type) != NULL + && QDF_SAP_MODE != session_type + && QDF_P2P_GO_MODE != session_type + && QDF_P2P_CLIENT_MODE != session_type + && QDF_STA_MODE != session_type) { + hdd_err("Interface type %d already exists. Two interfaces of same type are not supported currently.", + type); + return ERR_PTR(-EINVAL); + } + + pAdapter = hdd_get_adapter(pHddCtx, QDF_STA_MODE); + if ((pAdapter != NULL) && + !(wlan_hdd_validate_session_id(pAdapter->sessionId))) { + scan_info = &pAdapter->scan_info; + if (scan_info->mScanPending) { + hdd_abort_mac_scan(pHddCtx, pAdapter->sessionId, + INVALID_SCAN_ID, + eCSR_SCAN_ABORT_DEFAULT); + hdd_notice("Abort Scan while adding virtual interface"); + } + } + + pAdapter = NULL; + if (pHddCtx->config->isP2pDeviceAddrAdministrated && + ((NL80211_IFTYPE_P2P_GO == type) || + (NL80211_IFTYPE_P2P_CLIENT == type))) { + /* + * Generate the P2P Interface Address. this address must be + * different from the P2P Device Address. + */ + struct qdf_mac_addr p2pDeviceAddress = + pHddCtx->p2pDeviceAddress; + p2pDeviceAddress.bytes[4] ^= 0x80; + pAdapter = hdd_open_adapter(pHddCtx, + session_type, + name, p2pDeviceAddress.bytes, + name_assign_type, + true); + } else { + pAdapter = hdd_open_adapter(pHddCtx, + session_type, + name, + wlan_hdd_get_intf_addr(pHddCtx), + name_assign_type, + true); + } + + if (NULL == pAdapter) { + hdd_err("hdd_open_adapter failed"); + return ERR_PTR(-ENOSPC); + } + + /* + * Add interface can be requested from the upper layer at any time + * check the statemachine for modules state and if they are closed + * open the modules. + */ + ret = hdd_wlan_start_modules(pHddCtx, pAdapter, false); + if (ret) { + hdd_err("Failed to start the wlan_modules"); + goto close_adapter; + } + + /* + * Once the support for session creation/deletion from + * hdd_hostapd_open/hdd_host_stop is in place. + * The support for starting adapter from here can be removed. + */ + if (NL80211_IFTYPE_AP == type || (NL80211_IFTYPE_P2P_GO == type)) { + ret = hdd_start_adapter(pAdapter); + if (ret) { + hdd_err("Failed to start %s", name); + goto stop_modules; + } + } + + if (pHddCtx->rps) + hdd_send_rps_ind(pAdapter); + + EXIT(); + return pAdapter->dev->ieee80211_ptr; + +stop_modules: + /* + * Find if any iface is up. If there is not iface which is up + * start the timer to close the modules + */ + if (hdd_check_for_opened_interfaces(pHddCtx)) { + hdd_info("Closing all modules from the add_virt_iface"); + qdf_mc_timer_start(&pHddCtx->iface_change_timer, + pHddCtx->config->iface_change_wait_time + * 50000); + } else + hdd_info("Other interfaces are still up dont close modules!"); + +close_adapter: + hdd_close_adapter(pHddCtx, pAdapter, true); + + return ERR_PTR(-EINVAL); +} + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)) || defined(WITH_BACKPORTS) +/** + * wlan_hdd_add_virtual_intf() - Add virtual interface wrapper + * @wiphy: wiphy pointer + * @name: User-visible name of the interface + * @name_assign_type: the name of assign type of the netdev + * @nl80211_iftype: (virtual) interface types + * @flags: monitor mode configuration flags (not used) + * @vif_params: virtual interface parameters (not used) + * + * Return: the pointer of wireless dev, otherwise ERR_PTR. + */ +struct wireless_dev *wlan_hdd_add_virtual_intf(struct wiphy *wiphy, + const char *name, + unsigned char name_assign_type, + enum nl80211_iftype type, + u32 *flags, + struct vif_params *params) +{ + struct wireless_dev *wdev; + + cds_ssr_protect(__func__); + wdev = __wlan_hdd_add_virtual_intf(wiphy, name, name_assign_type, + type, flags, params); + cds_ssr_unprotect(__func__); + return wdev; + +} +#else +/** + * wlan_hdd_add_virtual_intf() - Add virtual interface wrapper + * @wiphy: wiphy pointer + * @name: User-visible name of the interface + * @nl80211_iftype: (virtual) interface types + * @flags: monitor mode configuration flags (not used) + * @vif_params: virtual interface parameters (not used) + * + * Return: the pointer of wireless dev, otherwise ERR_PTR. + */ +struct wireless_dev *wlan_hdd_add_virtual_intf(struct wiphy *wiphy, + const char *name, + enum nl80211_iftype type, + u32 *flags, + struct vif_params *params) +{ + struct wireless_dev *wdev; + unsigned char name_assign_type = 0; + + cds_ssr_protect(__func__); + wdev = __wlan_hdd_add_virtual_intf(wiphy, name, name_assign_type, + type, flags, params); + cds_ssr_unprotect(__func__); + return wdev; + +} +#endif + +int __wlan_hdd_del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev) +{ + struct net_device *dev = wdev->netdev; + hdd_context_t *pHddCtx = (hdd_context_t *) wiphy_priv(wiphy); + hdd_adapter_t *pVirtAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + int status; + ENTER(); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EINVAL; + } + + MTRACE(qdf_trace(QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_DEL_VIRTUAL_INTF, + pVirtAdapter->sessionId, pVirtAdapter->device_mode)); + hdd_notice("Device_mode %s(%d)", + hdd_device_mode_to_string(pVirtAdapter->device_mode), + pVirtAdapter->device_mode); + + status = wlan_hdd_validate_context(pHddCtx); + + if (0 != status) + return status; + + /* check state machine state and kickstart modules if they are closed */ + status = hdd_wlan_start_modules(pHddCtx, pVirtAdapter, false); + if (status) + return status; + + if (pVirtAdapter->device_mode == QDF_SAP_MODE && + wlan_sap_is_pre_cac_active(pHddCtx->hHal)) { + hdd_clean_up_pre_cac_interface(pHddCtx); + } else { + wlan_hdd_release_intf_addr(pHddCtx, + pVirtAdapter->macAddressCurrent.bytes); + hdd_stop_adapter(pHddCtx, pVirtAdapter, true); + hdd_close_adapter(pHddCtx, pVirtAdapter, true); + } + + EXIT(); + + return 0; +} + +int wlan_hdd_del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_del_virtual_intf(wiphy, wdev); + cds_ssr_unprotect(__func__); + + return ret; +} + +#ifdef WLAN_FEATURE_P2P_DEBUG +/* + * wlan_hdd_p2p_action_debug() - Log P2P state and update global status + * @actionFrmType: action frame type + * @macFrom: peer mac address + * + * return: void + */ +static void wlan_hdd_p2p_action_debug(tActionFrmType actionFrmType, + uint8_t *macFrom) +{ + if (actionFrmType >= MAX_P2P_ACTION_FRAME_TYPE) { + hdd_notice("[P2P] unknown[%d] <--- OTA from " MAC_ADDRESS_STR, + actionFrmType, MAC_ADDR_ARRAY(macFrom)); + } else { + hdd_notice("[P2P] %s <--- OTA from " MAC_ADDRESS_STR, + p2p_action_frame_type[actionFrmType], + MAC_ADDR_ARRAY(macFrom)); + if ((actionFrmType == WLAN_HDD_PROV_DIS_REQ) + && (global_p2p_connection_status == P2P_NOT_ACTIVE)) { + global_p2p_connection_status = P2P_GO_NEG_PROCESS; + hdd_notice("[P2P State]Inactive state to GO negotiation progress state"); + } else + if ((actionFrmType == WLAN_HDD_GO_NEG_CNF) + && (global_p2p_connection_status == P2P_GO_NEG_PROCESS)) { + global_p2p_connection_status = P2P_GO_NEG_COMPLETED; + hdd_notice("[P2P State]GO negotiation progress to GO negotiation completed state"); + } else + if ((actionFrmType == WLAN_HDD_INVITATION_REQ) + && (global_p2p_connection_status == P2P_NOT_ACTIVE)) { + global_p2p_connection_status = P2P_GO_NEG_COMPLETED; + hdd_notice("[P2P State]Inactive state to GO negotiation completed state Autonomous GO formation"); + } + } +} +#else +/* + * wlan_hdd_p2p_action_debug() - dummy + * @actionFrmType: action frame type + * @macFrom: peer mac address + * + * return: void + */ +static void wlan_hdd_p2p_action_debug(tActionFrmType actionFrmType, + uint8_t *macFrom) +{ + +} +#endif + +void __hdd_indicate_mgmt_frame(hdd_adapter_t *pAdapter, + uint32_t nFrameLength, + uint8_t *pbFrames, + uint8_t frameType, uint32_t rxChan, int8_t rxRssi) +{ + uint16_t freq; + uint16_t extend_time; + uint8_t type = 0; + uint8_t subType = 0; + tActionFrmType actionFrmType; + hdd_cfg80211_state_t *cfgState = NULL; + QDF_STATUS status; + hdd_remain_on_chan_ctx_t *pRemainChanCtx = NULL; + hdd_context_t *pHddCtx; + uint8_t broadcast = 0; + + hdd_info("Frame Type = %d Frame Length = %d", + frameType, nFrameLength); + + if (NULL == pAdapter) { + hdd_err("pAdapter is NULL"); + return; + } + pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + + if (0 == nFrameLength) { + hdd_err("Frame Length is Invalid ZERO"); + return; + } + + if (NULL == pbFrames) { + hdd_err("pbFrames is NULL"); + return; + } + + type = WLAN_HDD_GET_TYPE_FRM_FC(pbFrames[0]); + subType = WLAN_HDD_GET_SUBTYPE_FRM_FC(pbFrames[0]); + + /* Get pAdapter from Destination mac address of the frame */ + if ((type == SIR_MAC_MGMT_FRAME) && (subType != SIR_MAC_MGMT_PROBE_REQ)) { + pAdapter = + hdd_get_adapter_by_macaddr(pHddCtx, + &pbFrames + [WLAN_HDD_80211_FRM_DA_OFFSET]); + if (NULL == pAdapter) { + /* + * Under assumtion that we don't receive any action + * frame with BCST as destination, + * we are dropping action frame + */ + hdd_alert("pAdapter for action frame is NULL Macaddr = " + MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(&pbFrames + [WLAN_HDD_80211_FRM_DA_OFFSET])); + hdd_alert("Frame Type = %d Frame Length = %d subType = %d", + frameType, nFrameLength, subType); + /* We will receive broadcast management frames + * in OCB mode */ + pAdapter = hdd_get_adapter(pHddCtx, QDF_OCB_MODE); + if (NULL == pAdapter || !qdf_is_macaddr_broadcast( + (struct qdf_mac_addr *)&pbFrames + [WLAN_HDD_80211_FRM_DA_OFFSET])) { + /* + * Under assumtion that we don't + *receive any action + * frame with BCST as destination, + * we are dropping action frame + */ + return; + } + + broadcast = 1; + + } + } + + if (NULL == pAdapter->dev) { + hdd_err("pAdapter->dev is NULL"); + return; + } + + if (WLAN_HDD_ADAPTER_MAGIC != pAdapter->magic) { + hdd_err("pAdapter has invalid magic"); + return; + } + + /* Channel indicated may be wrong. TODO */ + /* Indicate an action frame. */ + if (rxChan <= MAX_NO_OF_2_4_CHANNELS) + freq = ieee80211_channel_to_frequency(rxChan, + NL80211_BAND_2GHZ); + else + freq = ieee80211_channel_to_frequency(rxChan, + NL80211_BAND_5GHZ); + + cfgState = WLAN_HDD_GET_CFG_STATE_PTR(pAdapter); + + if ((type == SIR_MAC_MGMT_FRAME) && + (subType == SIR_MAC_MGMT_ACTION) && !broadcast) { + if (pbFrames[WLAN_HDD_PUBLIC_ACTION_FRAME_OFFSET] == + WLAN_HDD_PUBLIC_ACTION_FRAME) { + /* Public action frame */ + if ((pbFrames[WLAN_HDD_PUBLIC_ACTION_FRAME_OFFSET + 1] + == SIR_MAC_ACTION_VENDOR_SPECIFIC) && + !qdf_mem_cmp(&pbFrames + [WLAN_HDD_PUBLIC_ACTION_FRAME_OFFSET + + 2], SIR_MAC_P2P_OUI, + SIR_MAC_P2P_OUI_SIZE)) { + /* P2P action frames */ + uint8_t *macFrom = &pbFrames + [WLAN_HDD_80211_PEER_ADDR_OFFSET]; + actionFrmType = + pbFrames + [WLAN_HDD_PUBLIC_ACTION_FRAME_TYPE_OFFSET]; + hdd_info("Rx Action Frame %u", + actionFrmType); + + wlan_hdd_p2p_action_debug(actionFrmType, + macFrom); + + mutex_lock(&cfgState->remain_on_chan_ctx_lock); + pRemainChanCtx = cfgState->remain_on_chan_ctx; + if (pRemainChanCtx != NULL) { + if (actionFrmType == WLAN_HDD_GO_NEG_REQ + || actionFrmType == + WLAN_HDD_GO_NEG_RESP + || actionFrmType == + WLAN_HDD_INVITATION_REQ + || actionFrmType == + WLAN_HDD_DEV_DIS_REQ + || actionFrmType == + WLAN_HDD_PROV_DIS_REQ) { + hdd_notice("Extend RoC timer on reception of Action Frame"); + + if ((actionFrmType == + WLAN_HDD_GO_NEG_REQ) + || (actionFrmType == + WLAN_HDD_GO_NEG_RESP)) + extend_time = + 2 * + ACTION_FRAME_DEFAULT_WAIT; + else + extend_time = + ACTION_FRAME_DEFAULT_WAIT; + + if (completion_done + (&pAdapter-> + rem_on_chan_ready_event)) { + if (QDF_TIMER_STATE_RUNNING == qdf_mc_timer_get_current_state(&pRemainChanCtx->hdd_remain_on_chan_timer)) { + qdf_mc_timer_stop + (&pRemainChanCtx-> + hdd_remain_on_chan_timer); + status = + qdf_mc_timer_start + (&pRemainChanCtx-> + hdd_remain_on_chan_timer, + extend_time); + if (status != + QDF_STATUS_SUCCESS) { + hdd_err("Remain on Channel timer start failed"); + } + } else { + hdd_notice("Rcvd action frame after timer expired"); + } + } else { + /* Buffer Packet */ + if (pRemainChanCtx-> + action_pkt_buff. + frame_length == 0) { + pRemainChanCtx-> + action_pkt_buff. + frame_length + = + nFrameLength; + pRemainChanCtx-> + action_pkt_buff. + freq = freq; + pRemainChanCtx-> + action_pkt_buff. + frame_ptr = + qdf_mem_malloc + (nFrameLength); + qdf_mem_copy + (pRemainChanCtx-> + action_pkt_buff. + frame_ptr, + pbFrames, + nFrameLength); + hdd_notice("Action Pkt Cached successfully !!!"); + } else { + hdd_warn("Frames are pending. dropping frame !!!"); + } + mutex_unlock(&cfgState-> + remain_on_chan_ctx_lock); + return; + } + } + } + mutex_unlock(&cfgState-> + remain_on_chan_ctx_lock); + + if (((actionFrmType == WLAN_HDD_PROV_DIS_RESP) + && (cfgState->actionFrmState == + HDD_PD_REQ_ACK_PENDING)) + || ((actionFrmType == WLAN_HDD_GO_NEG_RESP) + && (cfgState->actionFrmState == + HDD_GO_NEG_REQ_ACK_PENDING))) { + hdd_notice("ACK_PENDING and But received RESP for Action frame "); + cfgState->is_go_neg_ack_received = 1; + hdd_send_action_cnf(pAdapter, true); + } + } +#ifdef FEATURE_WLAN_TDLS + else if (pbFrames + [WLAN_HDD_PUBLIC_ACTION_FRAME_OFFSET + 1] == + WLAN_HDD_PUBLIC_ACTION_TDLS_DISC_RESP) { + u8 *mac = &pbFrames + [WLAN_HDD_80211_PEER_ADDR_OFFSET]; + + hdd_notice("[TDLS] TDLS Discovery Response," + MAC_ADDRESS_STR " RSSI[%d] <--- OTA", + MAC_ADDR_ARRAY(mac), rxRssi); + + wlan_hdd_tdls_set_rssi(pAdapter, mac, rxRssi); + wlan_hdd_tdls_recv_discovery_resp(pAdapter, + mac); + cds_tdls_tx_rx_mgmt_event(SIR_MAC_ACTION_TDLS, + SIR_MAC_ACTION_RX, SIR_MAC_MGMT_ACTION, + WLAN_HDD_PUBLIC_ACTION_TDLS_DISC_RESP, + &pbFrames[WLAN_HDD_80211_PEER_ADDR_OFFSET]); + } +#endif + } + + if (pbFrames[WLAN_HDD_PUBLIC_ACTION_FRAME_OFFSET] == + WLAN_HDD_TDLS_ACTION_FRAME) { + actionFrmType = + pbFrames[WLAN_HDD_PUBLIC_ACTION_FRAME_OFFSET + 1]; + if (actionFrmType >= MAX_TDLS_ACTION_FRAME_TYPE) { + hdd_notice("[TDLS] unknown[%d] <--- OTA", + actionFrmType); + } else { + hdd_notice("[TDLS] %s <--- OTA", + tdls_action_frame_type[actionFrmType]); + } + cds_tdls_tx_rx_mgmt_event(SIR_MAC_ACTION_TDLS, + SIR_MAC_ACTION_RX, SIR_MAC_MGMT_ACTION, + actionFrmType, + &pbFrames[WLAN_HDD_80211_PEER_ADDR_OFFSET]); + } + + if ((pbFrames[WLAN_HDD_PUBLIC_ACTION_FRAME_OFFSET] == + WLAN_HDD_QOS_ACTION_FRAME) + && (pbFrames[WLAN_HDD_PUBLIC_ACTION_FRAME_OFFSET + 1] == + WLAN_HDD_QOS_MAP_CONFIGURE)) { + sme_update_dsc_pto_up_mapping(pHddCtx->hHal, + pAdapter->hddWmmDscpToUpMap, + pAdapter->sessionId); + } + } + /* Indicate Frame Over Normal Interface */ + hdd_notice("Indicate Frame over NL80211 sessionid : %d, idx :%d", + pAdapter->sessionId, pAdapter->dev->ifindex); + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0)) + cfg80211_rx_mgmt(pAdapter->dev->ieee80211_ptr, + freq, rxRssi * 100, pbFrames, + nFrameLength, NL80211_RXMGMT_FLAG_ANSWERED); +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)) + cfg80211_rx_mgmt(pAdapter->dev->ieee80211_ptr, + freq, rxRssi * 100, pbFrames, + nFrameLength, NL80211_RXMGMT_FLAG_ANSWERED, + GFP_ATOMIC); +#else + cfg80211_rx_mgmt(pAdapter->dev->ieee80211_ptr, freq, + rxRssi * 100, + pbFrames, nFrameLength, GFP_ATOMIC); +#endif /* LINUX_VERSION_CODE */ +} diff --git a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_packet_filter.c b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_packet_filter.c new file mode 100644 index 0000000000000000000000000000000000000000..1b0c3cfa3a8697e95faf996efcd20bbfe001f80d --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_packet_filter.c @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2017 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. + */ + +/** + * DOC: wlan_hdd_packet_filter.c + * + * WLAN Host Device Driver implementation + * + */ + +/* Include Files */ +#include "wlan_hdd_packet_filter_api.h" +#include "wlan_hdd_packet_filter_rules.h" + +int hdd_enable_default_pkt_filters(hdd_adapter_t *pAdapter) +{ + hdd_context_t *pHddCtx; + uint8_t filters = 0, i = 0, filter_id = 1; + + pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + if (NULL == pHddCtx) { + hdd_err("HDD context is Null!!!"); + return -EINVAL; + } + if (pHddCtx->user_configured_pkt_filter_rules) { + hdd_info("user has defined pkt filter run hence skipping default packet filter rule"); + return 0; + } + + filters = pHddCtx->config->packet_filters_bitmap; + + while (filters != 0) { + if (filters & 0x1) { + hdd_err("setting filter[%d], of id = %d \n", + i+1, filter_id); + packet_filter_default_rules[i].filter_id = filter_id; + wlan_hdd_set_filter(pHddCtx, + &packet_filter_default_rules[i], + pAdapter->sessionId); + filter_id++; + } + filters = filters >> 1; + i++; + } + + return 0; +} + +int hdd_disable_default_pkt_filters(hdd_adapter_t *pAdapter) +{ + hdd_context_t *pHddCtx; + uint8_t filters = 0, i = 0, filter_id = 1; + + struct pkt_filter_cfg packet_filter_default_rules; + + pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + if (NULL == pHddCtx) { + hdd_err("HDD context is Null!!!"); + return -EINVAL; + } + + if (pHddCtx->user_configured_pkt_filter_rules) { + hdd_info("user has defined pkt filter run hence skipping default packet filter rule"); + return 0; + } + + filters = pHddCtx->config->packet_filters_bitmap; + + while (filters != 0) { + if (filters & 0x1) { + hdd_err("Clearing filter[%d], of id = %d \n", + i+1, filter_id); + packet_filter_default_rules.filter_action = + HDD_RCV_FILTER_CLEAR; + packet_filter_default_rules.filter_id = filter_id; + wlan_hdd_set_filter(pHddCtx, + &packet_filter_default_rules, + pAdapter->sessionId); + filter_id++; + } + filters = filters >> 1; + i++; + } + + return 0; +} diff --git a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_power.c b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_power.c new file mode 100644 index 0000000000000000000000000000000000000000..0cb2afe8c402150b1f75017bf0948a3af93042da --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_power.c @@ -0,0 +1,2695 @@ +/* + * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: wlan_hdd_power.c + * + * WLAN power management functions + * + */ + +/* Include files */ + +#include +#include +#include +#include +#if defined(WLAN_OPEN_SOURCE) && defined(CONFIG_HAS_WAKELOCK) +#include +#endif +#include "qdf_types.h" +#include "sme_api.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include "cfg_api.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include "hif.h" +#include "sme_power_save_api.h" +#include "cds_concurrency.h" +#include "cdp_txrx_flow_ctrl_v2.h" +#include "pld_common.h" +#include "wlan_hdd_driver_ops.h" +#include +#include "cds_utils.h" +#include "wlan_hdd_packet_filter_api.h" + +/* Preprocessor definitions and constants */ +#define HDD_SSR_BRING_UP_TIME 30000 +#define HDD_WAKE_LOCK_RESUME_DURATION 1000 + +/* Type declarations */ + +#ifdef FEATURE_WLAN_DIAG_SUPPORT +/** + * hdd_wlan_suspend_resume_event()- send suspend/resume state + * @state: suspend/resume state + * + * This Function send send suspend resume state diag event + * + * Return: void. + */ +void hdd_wlan_suspend_resume_event(uint8_t state) +{ + WLAN_HOST_DIAG_EVENT_DEF(suspend_state, struct host_event_suspend); + qdf_mem_zero(&suspend_state, sizeof(suspend_state)); + + suspend_state.state = state; + WLAN_HOST_DIAG_EVENT_REPORT(&suspend_state, EVENT_WLAN_SUSPEND_RESUME); +} + +/** + * hdd_wlan_offload_event()- send offloads event + * @type: offload type + * @state: enabled or disabled + * + * This Function send offloads enable/disable diag event + * + * Return: void. + */ + +void hdd_wlan_offload_event(uint8_t type, uint8_t state) +{ + WLAN_HOST_DIAG_EVENT_DEF(host_offload, struct host_event_offload_req); + qdf_mem_zero(&host_offload, sizeof(host_offload)); + + host_offload.offload_type = type; + host_offload.state = state; + + WLAN_HOST_DIAG_EVENT_REPORT(&host_offload, EVENT_WLAN_OFFLOAD_REQ); +} +#endif + +/* Function and variables declarations */ + +extern struct notifier_block hdd_netdev_notifier; + +static struct timer_list ssr_timer; +static bool ssr_timer_started; +/** + * hdd_conf_gtk_offload() - Configure GTK offload + * @pAdapter: pointer to the adapter + * @fenable: flag set to enable (1) or disable (0) GTK offload + * + * Central function to enable or disable GTK offload. + * + * Return: nothing + */ +#ifdef WLAN_FEATURE_GTK_OFFLOAD +static void hdd_conf_gtk_offload(hdd_adapter_t *pAdapter, bool fenable) +{ + QDF_STATUS ret; + tSirGtkOffloadParams hddGtkOffloadReqParams; + hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + + if (fenable) { + if ((eConnectionState_Associated == + pHddStaCtx->conn_info.connState) + && (GTK_OFFLOAD_ENABLE == + pHddStaCtx->gtkOffloadReqParams.ulFlags)) { + qdf_mem_copy(&hddGtkOffloadReqParams, + &pHddStaCtx->gtkOffloadReqParams, + sizeof(tSirGtkOffloadParams)); + + ret = sme_set_gtk_offload(WLAN_HDD_GET_HAL_CTX(pAdapter), + &hddGtkOffloadReqParams, + pAdapter->sessionId); + if (QDF_STATUS_SUCCESS != ret) { + hdd_err("sme_set_gtk_offload failed, returned %d", ret); + return; + } + + hdd_notice("sme_set_gtk_offload successfull"); + } + + } else { + if ((eConnectionState_Associated == + pHddStaCtx->conn_info.connState) + && (qdf_is_macaddr_equal(&pHddStaCtx->gtkOffloadReqParams.bssid, + &pHddStaCtx->conn_info.bssId)) + && (GTK_OFFLOAD_ENABLE == + pHddStaCtx->gtkOffloadReqParams.ulFlags)) { + + /* Host driver has previously offloaded GTK rekey */ + ret = sme_get_gtk_offload + (WLAN_HDD_GET_HAL_CTX(pAdapter), + wlan_hdd_cfg80211_update_replay_counter_callback, + pAdapter, pAdapter->sessionId); + if (QDF_STATUS_SUCCESS != ret) { + hdd_err("sme_get_gtk_offload failed, returned %d", ret); + return; + } else { + hdd_notice("sme_get_gtk_offload successful"); + + /* Sending GTK offload dissable */ + memcpy(&hddGtkOffloadReqParams, + &pHddStaCtx->gtkOffloadReqParams, + sizeof(tSirGtkOffloadParams)); + hddGtkOffloadReqParams.ulFlags = + GTK_OFFLOAD_DISABLE; + ret = + sme_set_gtk_offload(WLAN_HDD_GET_HAL_CTX + (pAdapter), + &hddGtkOffloadReqParams, + pAdapter->sessionId); + if (QDF_STATUS_SUCCESS != ret) { + hdd_err("failed to dissable GTK offload, returned %d", ret); + return; + } + hdd_notice("successfully dissabled GTK offload request to HAL"); + } + } + } + return; +} +#else /* WLAN_FEATURE_GTK_OFFLOAD */ +static void hdd_conf_gtk_offload(hdd_adapter_t *pAdapter, bool fenable) +{ +} +#endif /*WLAN_FEATURE_GTK_OFFLOAD */ + +#ifdef WLAN_NS_OFFLOAD +/** + * __wlan_hdd_ipv6_changed() - IPv6 notifier callback function + * @nb: notifier block that was registered with the kernel + * @data: (unused) generic data that was registered with the kernel + * @arg: (unused) generic argument that was registered with the kernel + * + * This is a callback function that is registered with the kernel via + * register_inet6addr_notifier() which allows the driver to be + * notified when there is an IPv6 address change. + * + * Return: NOTIFY_DONE to indicate we don't care what happens with + * other callbacks + */ +static int __wlan_hdd_ipv6_changed(struct notifier_block *nb, + unsigned long data, void *arg) +{ + struct inet6_ifaddr *ifa = (struct inet6_ifaddr *)arg; + struct net_device *ndev = ifa->idev->dev; + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(ndev); + hdd_context_t *pHddCtx; + hdd_station_ctx_t *sta_ctx; + int status; + + ENTER_DEV(ndev); + + if ((pAdapter == NULL) || (WLAN_HDD_ADAPTER_MAGIC != pAdapter->magic)) { + hdd_err("Adapter context is invalid %p", pAdapter); + return NOTIFY_DONE; + } + + if ((pAdapter->dev == ndev) && + (pAdapter->device_mode == QDF_STA_MODE || + pAdapter->device_mode == QDF_P2P_CLIENT_MODE || + pAdapter->device_mode == QDF_NDI_MODE)) { + pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + status = wlan_hdd_validate_context(pHddCtx); + if (0 != status) + return NOTIFY_DONE; + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + hdd_debug("invoking sme_dhcp_done_ind"); + sme_dhcp_done_ind(pHddCtx->hHal, + pAdapter->sessionId); + schedule_work(&pAdapter->ipv6NotifierWorkQueue); + } + EXIT(); + return NOTIFY_DONE; +} + +/** + * wlan_hdd_ipv6_changed() - IPv6 change notifier callback + * @nb: pointer to notifier block + * @data: data + * @arg: arg + * + * This is the IPv6 notifier callback function gets invoked + * if any change in IP and then invoke the function @__wlan_hdd_ipv6_changed + * to reconfigure the offload parameters. + * + * Return: 0 on success, error number otherwise. + */ +int wlan_hdd_ipv6_changed(struct notifier_block *nb, + unsigned long data, void *arg) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_ipv6_changed(nb, data, arg); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * hdd_fill_ipv6_uc_addr() - fill IPv6 unicast addresses + * @idev: pointer to net device + * @ipv6addr: destination array to fill IPv6 addresses + * @ipv6addr_type: IPv6 Address type + * @count: number of IPv6 addresses + * + * This is the IPv6 utility function to populate unicast addresses. + * + * Return: 0 on success, error number otherwise. + */ +static int hdd_fill_ipv6_uc_addr(struct inet6_dev *idev, + uint8_t ipv6_uc_addr[][SIR_MAC_IPV6_ADDR_LEN], + uint8_t *ipv6addr_type, uint32_t *count) +{ + struct inet6_ifaddr *ifa; + struct list_head *p; + uint32_t scope; + + read_lock_bh(&idev->lock); + list_for_each(p, &idev->addr_list) { + if (*count >= SIR_MAC_NUM_TARGET_IPV6_NS_OFFLOAD_NA) { + read_unlock_bh(&idev->lock); + return -EINVAL; + } + ifa = list_entry(p, struct inet6_ifaddr, if_list); + if (ifa->flags & IFA_F_DADFAILED) + continue; + scope = ipv6_addr_src_scope(&ifa->addr); + switch (scope) { + case IPV6_ADDR_SCOPE_GLOBAL: + case IPV6_ADDR_SCOPE_LINKLOCAL: + qdf_mem_copy(ipv6_uc_addr[*count], &ifa->addr.s6_addr, + sizeof(ifa->addr.s6_addr)); + ipv6addr_type[*count] = SIR_IPV6_ADDR_UC_TYPE; + hdd_info("Index %d scope = %s UC-Address: %pI6", + *count, (scope == IPV6_ADDR_SCOPE_LINKLOCAL) ? + "LINK LOCAL" : "GLOBAL", ipv6_uc_addr[*count]); + *count += 1; + break; + default: + hdd_err("The Scope %d is not supported", scope); + } + } + + read_unlock_bh(&idev->lock); + return 0; +} + +/** + * hdd_fill_ipv6_ac_addr() - fill IPv6 anycast addresses + * @idev: pointer to net device + * @ipv6addr: destination array to fill IPv6 addresses + * @ipv6addr_type: IPv6 Address type + * @count: number of IPv6 addresses + * + * This is the IPv6 utility function to populate anycast addresses. + * + * Return: 0 on success, error number otherwise. + */ +static int hdd_fill_ipv6_ac_addr(struct inet6_dev *idev, + uint8_t ipv6_ac_addr[][SIR_MAC_IPV6_ADDR_LEN], + uint8_t *ipv6addr_type, uint32_t *count) +{ + struct ifacaddr6 *ifaca; + uint32_t scope; + + read_lock_bh(&idev->lock); + for (ifaca = idev->ac_list; ifaca; ifaca = ifaca->aca_next) { + if (*count >= SIR_MAC_NUM_TARGET_IPV6_NS_OFFLOAD_NA) { + read_unlock_bh(&idev->lock); + return -EINVAL; + } + /* For anycast addr no DAD */ + scope = ipv6_addr_src_scope(&ifaca->aca_addr); + switch (scope) { + case IPV6_ADDR_SCOPE_GLOBAL: + case IPV6_ADDR_SCOPE_LINKLOCAL: + qdf_mem_copy(ipv6_ac_addr[*count], &ifaca->aca_addr, + sizeof(ifaca->aca_addr)); + ipv6addr_type[*count] = SIR_IPV6_ADDR_AC_TYPE; + hdd_info("Index %d scope = %s AC-Address: %pI6", + *count, (scope == IPV6_ADDR_SCOPE_LINKLOCAL) ? + "LINK LOCAL" : "GLOBAL", ipv6_ac_addr[*count]); + *count += 1; + break; + default: + hdd_err("The Scope %d is not supported", scope); + } + } + + read_unlock_bh(&idev->lock); + return 0; +} + +/** + * hdd_disable_ns_offload() - Disables IPv6 NS offload + * @adapter: ponter to the adapter + * + * Return: nothing + */ +static void hdd_disable_ns_offload(hdd_adapter_t *adapter) +{ + tSirHostOffloadReq offloadReq; + QDF_STATUS status; + + qdf_mem_zero((void *)&offloadReq, sizeof(tSirHostOffloadReq)); + hdd_wlan_offload_event(SIR_IPV6_NS_OFFLOAD, SIR_OFFLOAD_DISABLE); + offloadReq.enableOrDisable = SIR_OFFLOAD_DISABLE; + offloadReq.offloadType = SIR_IPV6_NS_OFFLOAD; + status = sme_set_host_offload( + WLAN_HDD_GET_HAL_CTX(adapter), + adapter->sessionId, &offloadReq); + + if (QDF_STATUS_SUCCESS != status) + hdd_err("Failed to disable NS Offload"); +} + +/** + * hdd_enable_ns_offload() - Enables IPv6 NS offload + * @adapter: ponter to the adapter + * + * Return: nothing + */ +static void hdd_enable_ns_offload(hdd_adapter_t *adapter) +{ + struct inet6_dev *in6_dev; + uint8_t ipv6_addr[SIR_MAC_NUM_TARGET_IPV6_NS_OFFLOAD_NA] + [SIR_MAC_IPV6_ADDR_LEN] = { {0,} }; + uint8_t ipv6_addr_type[SIR_MAC_NUM_TARGET_IPV6_NS_OFFLOAD_NA] = { 0 }; + tSirHostOffloadReq offloadReq; + QDF_STATUS status; + uint32_t count = 0; + int err, i; + + in6_dev = __in6_dev_get(adapter->dev); + if (NULL == in6_dev) { + hdd_err("IPv6 dev does not exist. Failed to request NSOffload"); + return; + } + + /* Unicast Addresses */ + err = hdd_fill_ipv6_uc_addr(in6_dev, ipv6_addr, ipv6_addr_type, &count); + if (err) { + hdd_disable_ns_offload(adapter); + hdd_notice("Reached max supported addresses and not enabling " + "NS offload"); + return; + } + + /* Anycast Addresses */ + err = hdd_fill_ipv6_ac_addr(in6_dev, ipv6_addr, ipv6_addr_type, &count); + if (err) { + hdd_disable_ns_offload(adapter); + hdd_notice("Reached max supported addresses and not enabling " + "NS offload"); + return; + } + + qdf_mem_zero(&offloadReq, sizeof(offloadReq)); + for (i = 0; i < count; i++) { + /* Filling up the request structure + * Filling the selfIPv6Addr with solicited address + * A Solicited-Node multicast address is created by + * taking the last 24 bits of a unicast or anycast + * address and appending them to the prefix + * + * FF02:0000:0000:0000:0000:0001:FFXX:XXXX + * + * here XX is the unicast/anycast bits + */ + offloadReq.nsOffloadInfo.selfIPv6Addr[i][0] = 0xFF; + offloadReq.nsOffloadInfo.selfIPv6Addr[i][1] = 0x02; + offloadReq.nsOffloadInfo.selfIPv6Addr[i][11] = 0x01; + offloadReq.nsOffloadInfo.selfIPv6Addr[i][12] = 0xFF; + offloadReq.nsOffloadInfo.selfIPv6Addr[i][13] = + ipv6_addr[i][13]; + offloadReq.nsOffloadInfo.selfIPv6Addr[i][14] = + ipv6_addr[i][14]; + offloadReq.nsOffloadInfo.selfIPv6Addr[i][15] = + ipv6_addr[i][15]; + offloadReq.nsOffloadInfo.slotIdx = i; + qdf_mem_copy(&offloadReq.nsOffloadInfo.targetIPv6Addr[i], + &ipv6_addr[i][0], SIR_MAC_IPV6_ADDR_LEN); + + offloadReq.nsOffloadInfo.targetIPv6AddrValid[i] = + SIR_IPV6_ADDR_VALID; + offloadReq.nsOffloadInfo.target_ipv6_addr_ac_type[i] = + ipv6_addr_type[i]; + + qdf_mem_copy(&offloadReq.params.hostIpv6Addr, + &offloadReq.nsOffloadInfo.targetIPv6Addr[i], + SIR_MAC_IPV6_ADDR_LEN); + + hdd_info("Setting NSOffload with solicitedIp: " + "%pI6, targetIp: %pI6, Index %d", + &offloadReq.nsOffloadInfo.selfIPv6Addr[i], + &offloadReq.nsOffloadInfo.targetIPv6Addr[i], i); + } + + hdd_wlan_offload_event(SIR_IPV6_NS_OFFLOAD, SIR_OFFLOAD_ENABLE); + offloadReq.offloadType = SIR_IPV6_NS_OFFLOAD; + offloadReq.enableOrDisable = SIR_OFFLOAD_ENABLE; + qdf_copy_macaddr(&offloadReq.nsOffloadInfo.self_macaddr, + &adapter->macAddressCurrent); + + /* set number of ns offload address count */ + offloadReq.num_ns_offload_count = count; + + /* Configure the Firmware with this */ + status = sme_set_host_offload(WLAN_HDD_GET_HAL_CTX(adapter), + adapter->sessionId, &offloadReq); + if (QDF_STATUS_SUCCESS != status) { + hdd_err("Failed to enable HostOffload feature with status: %d", + status); + } +} + +/** + * hdd_conf_ns_offload() - Configure NS offload + * @adapter: pointer to the adapter + * @fenable: flag to enable or disable + * 0 - disable + * 1 - enable + * + * Return: nothing + */ +void hdd_conf_ns_offload(hdd_adapter_t *adapter, bool fenable) +{ + hdd_context_t *hdd_ctx; + + ENTER(); + hdd_notice(" fenable = %d", fenable); + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + + /* In SAP/P2PGo mode, ARP/NS offload feature capability + * is controlled by one bit. + */ + + if ((QDF_SAP_MODE == adapter->device_mode || + QDF_P2P_GO_MODE == adapter->device_mode) && + !hdd_ctx->ap_arpns_support) { + hdd_notice("NS Offload is not supported in SAP/P2PGO mode"); + return; + } + + if (QDF_IBSS_MODE == adapter->device_mode) { + hdd_debug("NS Offload is not supported in IBSS mode"); + return; + } + + if (fenable) + hdd_enable_ns_offload(adapter); + else + hdd_disable_ns_offload(adapter); + + EXIT(); + return; +} + +/** + * __hdd_ipv6_notifier_work_queue() - IPv6 notification work function + * @work: registered work item + * + * This function performs the work initially trigged by a callback + * from the IPv6 netdev notifier. Since this means there has been a + * change in IPv6 state for the interface, the NS offload is + * reconfigured. + * + * Return: None + */ +static void __hdd_ipv6_notifier_work_queue(struct work_struct *work) +{ + hdd_adapter_t *pAdapter = + container_of(work, hdd_adapter_t, ipv6NotifierWorkQueue); + hdd_context_t *pHddCtx; + int status; + bool ndi_connected = false; + + ENTER(); + + pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + status = wlan_hdd_validate_context(pHddCtx); + if (0 != status) + return; + + if (!pHddCtx->config->active_mode_offload) { + hdd_err("Active mode offload is disabled"); + return; + } + + /* check if the device is in NAN data mode */ + if (WLAN_HDD_IS_NDI(pAdapter)) + ndi_connected = WLAN_HDD_IS_NDI_CONNECTED(pAdapter); + + if (eConnectionState_Associated == + (WLAN_HDD_GET_STATION_CTX_PTR(pAdapter))->conn_info.connState || + ndi_connected) + if (pHddCtx->config->fhostNSOffload && + pHddCtx->ns_offload_enable) + hdd_conf_ns_offload(pAdapter, true); + EXIT(); +} + +/** + * hdd_ipv6_notifier_work_queue() - IP V6 change notifier work handler + * @work: Pointer to work context + * + * Return: none + */ +void hdd_ipv6_notifier_work_queue(struct work_struct *work) +{ + cds_ssr_protect(__func__); + __hdd_ipv6_notifier_work_queue(work); + cds_ssr_unprotect(__func__); +} + +/** + * hdd_conf_hostoffload() - Central function to configure the supported offloads + * @pAdapter: pointer to the adapter + * @fenable: flag set to enable (1) or disable (0) + * + * Central function to configure the supported offloads either + * enable or disable them. + * + * Return: nothing + */ +void hdd_conf_hostoffload(hdd_adapter_t *pAdapter, bool fenable) +{ + hdd_context_t *pHddCtx; + + ENTER(); + + hdd_info("Configuring offloads with flag: %d", fenable); + + /* Get the HDD context. */ + pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + + if (((QDF_STA_MODE != pAdapter->device_mode) && + (QDF_P2P_CLIENT_MODE != pAdapter->device_mode))) { + hdd_info("Offloads not supported in mode %d", + pAdapter->device_mode); + return; + } + + if (eConnectionState_Associated != + (WLAN_HDD_GET_STATION_CTX_PTR(pAdapter))->conn_info.connState) { + hdd_info("Offloads not supported in state %d", + (WLAN_HDD_GET_STATION_CTX_PTR(pAdapter))-> + conn_info.connState); + return; + } + + hdd_conf_gtk_offload(pAdapter, fenable); + + /* Configure ARP/NS offload during cfg80211 suspend/resume and + * Enable MC address filtering during cfg80211 suspend + * only if active mode offload is disabled + */ + if (!pHddCtx->config->active_mode_offload) { + hdd_info("configuring unconfigured active mode offloads"); + hdd_conf_arp_offload(pAdapter, fenable); + wlan_hdd_set_mc_addr_list(pAdapter, fenable); + + if (pHddCtx->config->fhostNSOffload && + pHddCtx->ns_offload_enable) + hdd_conf_ns_offload(pAdapter, fenable); + } + + /* Configure DTIM hardware filter rules */ + { + enum hw_filter_mode mode = pHddCtx->config->hw_filter_mode; + + if (!fenable) + mode = HW_FILTER_DISABLED; + hdd_conf_hw_filter_mode(pAdapter, mode); + } + + EXIT(); + return; +} +#endif + +/** + * hdd_lookup_ifaddr() - Lookup interface address data by name + * @adapter: the adapter whose name should be searched for + * + * return in_ifaddr pointer on success, NULL for failure + */ +static struct in_ifaddr *hdd_lookup_ifaddr(hdd_adapter_t *adapter) +{ + struct in_ifaddr *ifa; + struct in_device *in_dev; + + if (!adapter) { + hdd_err("adapter is null"); + return NULL; + } + + in_dev = __in_dev_get_rtnl(adapter->dev); + if (!in_dev) { + hdd_err("Failed to get in_device"); + return NULL; + } + + /* lookup address data by interface name */ + for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) { + if (!strcmp(adapter->dev->name, ifa->ifa_label)) + return ifa; + } + + return NULL; +} + +/** + * hdd_populate_ipv4_addr() - Populates the adapter's IPv4 address + * @adapter: the adapter whose IPv4 address is desired + * @ipv4_addr: the address of the array to copy the IPv4 address into + * + * return: zero for success; non-zero for failure + */ +static int hdd_populate_ipv4_addr(hdd_adapter_t *adapter, uint8_t *ipv4_addr) +{ + struct in_ifaddr *ifa; + int i; + + if (!adapter) { + hdd_err("adapter is null"); + return -EINVAL; + } + + if (!ipv4_addr) { + hdd_err("ipv4_addr is null"); + return -EINVAL; + } + + ifa = hdd_lookup_ifaddr(adapter); + if (!ifa || !ifa->ifa_local) { + hdd_err("ipv4 address not found"); + return -EINVAL; + } + + /* convert u32 to byte array */ + for (i = 0; i < 4; i++) + ipv4_addr[i] = (ifa->ifa_local >> i * 8) & 0xff; + + return 0; +} + +/** + * hdd_set_grat_arp_keepalive() - Enable grat APR keepalive + * @adapter: the HDD adapter to configure + * + * This configures gratuitous APR keepalive based on the adapter's current + * connection information, specifically IPv4 address and BSSID + * + * return: zero for success, non-zero for failure + */ +static int hdd_set_grat_arp_keepalive(hdd_adapter_t *adapter) +{ + QDF_STATUS status; + int exit_code; + hdd_context_t *hdd_ctx; + hdd_station_ctx_t *sta_ctx; + tSirKeepAliveReq req = { + .packetType = SIR_KEEP_ALIVE_UNSOLICIT_ARP_RSP, + .dest_macaddr = QDF_MAC_ADDR_BROADCAST_INITIALIZER, + }; + + if (!adapter) { + hdd_err("adapter is null"); + return -EINVAL; + } + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + if (!hdd_ctx) { + hdd_err("hdd_ctx is null"); + return -EINVAL; + } + + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + if (!sta_ctx) { + hdd_err("sta_ctx is null"); + return -EINVAL; + } + + exit_code = hdd_populate_ipv4_addr(adapter, req.hostIpv4Addr); + if (exit_code) { + hdd_err("Failed to populate ipv4 address"); + return exit_code; + } + + /* according to RFC5227, sender/target ip address should be the same */ + qdf_mem_copy(&req.destIpv4Addr, &req.hostIpv4Addr, + sizeof(req.destIpv4Addr)); + + qdf_copy_macaddr(&req.bssid, &sta_ctx->conn_info.bssId); + req.timePeriod = hdd_ctx->config->infraStaKeepAlivePeriod; + req.sessionId = adapter->sessionId; + + hdd_info("Setting gratuitous ARP keepalive; ipv4_addr:%u.%u.%u.%u", + req.hostIpv4Addr[0], req.hostIpv4Addr[1], + req.hostIpv4Addr[2], req.hostIpv4Addr[3]); + + status = sme_set_keep_alive(hdd_ctx->hHal, req.sessionId, &req); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to set keepalive"); + return qdf_status_to_os_return(status); + } + + return 0; +} + +/** + * __hdd_ipv4_notifier_work_queue() - IPv4 notification work function + * @work: registered work item + * + * This function performs the work initially trigged by a callback + * from the IPv4 netdev notifier. Since this means there has been a + * change in IPv4 state for the interface, the ARP offload is + * reconfigured. + * + * Return: None + */ +static void __hdd_ipv4_notifier_work_queue(struct work_struct *work) +{ + hdd_adapter_t *pAdapter = + container_of(work, hdd_adapter_t, ipv4NotifierWorkQueue); + hdd_context_t *pHddCtx; + hdd_station_ctx_t *sta_ctx; + int status; + bool ndi_connected; + bool sta_associated; + + hdd_info("Configuring ARP Offload"); + + pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + status = wlan_hdd_validate_context(pHddCtx); + if (status) + return; + + if (!pHddCtx->config->active_mode_offload) { + hdd_err("Active mode offload is disabled"); + return; + } + + ndi_connected = WLAN_HDD_IS_NDI(pAdapter) && + WLAN_HDD_IS_NDI_CONNECTED(pAdapter); + + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + sta_associated = sta_ctx->conn_info.connState == + eConnectionState_Associated; + + if (!ndi_connected && !sta_associated) + return; + + /* + * This invocation being part of the IPv4 registration callback, + * we are passing second parameter as 2 to avoid registration + * of IPv4 notifier again. + */ + hdd_conf_arp_offload(pAdapter, true); + + hdd_set_grat_arp_keepalive(pAdapter); +} + +/** + * hdd_ipv4_notifier_work_queue() - IP V4 change notifier work handler + * @work: Pointer to work context + * + * Return: none + */ +void hdd_ipv4_notifier_work_queue(struct work_struct *work) +{ + cds_ssr_protect(__func__); + __hdd_ipv4_notifier_work_queue(work); + cds_ssr_unprotect(__func__); +} + +/** + * __wlan_hdd_ipv4_changed() - IPv4 notifier callback function + * @nb: notifier block that was registered with the kernel + * @data: (unused) generic data that was registered with the kernel + * @arg: (unused) generic argument that was registered with the kernel + * + * This is a callback function that is registered with the kernel via + * register_inetaddr_notifier() which allows the driver to be + * notified when there is an IPv4 address change. + * + * Return: NOTIFY_DONE to indicate we don't care what happens with + * other callbacks + */ +static int __wlan_hdd_ipv4_changed(struct notifier_block *nb, + unsigned long data, void *arg) +{ + struct in_ifaddr *ifa = (struct in_ifaddr *)arg; + struct net_device *ndev = ifa->ifa_dev->dev; + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(ndev); + hdd_context_t *pHddCtx; + hdd_station_ctx_t *sta_ctx; + int status; + + ENTER_DEV(ndev); + + if ((pAdapter == NULL) || (WLAN_HDD_ADAPTER_MAGIC != pAdapter->magic)) { + hdd_err("Adapter context is invalid %p", pAdapter); + return NOTIFY_DONE; + } + + if ((pAdapter->dev == ndev) && + (pAdapter->device_mode == QDF_STA_MODE || + pAdapter->device_mode == QDF_P2P_CLIENT_MODE || + pAdapter->device_mode == QDF_NDI_MODE)) { + + pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + status = wlan_hdd_validate_context(pHddCtx); + if (0 != status) + return NOTIFY_DONE; + + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + hdd_debug("invoking sme_dhcp_done_ind"); + sme_dhcp_done_ind(pHddCtx->hHal, + pAdapter->sessionId); + + if (!pHddCtx->config->fhostArpOffload) { + hdd_notice("Offload not enabled ARPOffload=%d", + pHddCtx->config->fhostArpOffload); + return NOTIFY_DONE; + } + + ifa = hdd_lookup_ifaddr(pAdapter); + if (ifa && ifa->ifa_local) + schedule_work(&pAdapter->ipv4NotifierWorkQueue); + } + EXIT(); + return NOTIFY_DONE; +} + +/** + * wlan_hdd_ipv4_changed() - IPv4 change notifier callback + * @nb: pointer to notifier block + * @data: data + * @arg: arg + * + * This is the IPv4 notifier callback function gets invoked + * if any change in IP and then invoke the function @__wlan_hdd_ipv4_changed + * to reconfigure the offload parameters. + * + * Return: 0 on success, error number otherwise. + */ +int wlan_hdd_ipv4_changed(struct notifier_block *nb, + unsigned long data, void *arg) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_ipv4_changed(nb, data, arg); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * hdd_conf_arp_offload() - Configure ARP offload + * @pAdapter: Adapter context for which ARP offload is to be configured + * @fenable: true : enable ARP offload false : disable arp offload + * + * Return: + * QDF_STATUS_SUCCESS - on successful operation, + * QDF_STATUS_E_FAILURE - on failure of operation + */ +QDF_STATUS hdd_conf_arp_offload(hdd_adapter_t *pAdapter, bool fenable) +{ + struct in_ifaddr *ifa; + int i = 0; + tSirHostOffloadReq offLoadRequest; + hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + + hdd_info("fenable = %d", fenable); + + /* In SAP/P2P Go mode, ARP/NS Offload feature capability + * is controlled by one bit. + */ + if ((QDF_SAP_MODE == pAdapter->device_mode || + QDF_P2P_GO_MODE == pAdapter->device_mode) && + !pHddCtx->ap_arpns_support) { + hdd_notice("ARP Offload is not supported in SAP/P2PGO mode"); + return QDF_STATUS_SUCCESS; + } + + if (fenable) { + ifa = hdd_lookup_ifaddr(pAdapter); + if (ifa && ifa->ifa_local) { + offLoadRequest.offloadType = SIR_IPV4_ARP_REPLY_OFFLOAD; + offLoadRequest.enableOrDisable = SIR_OFFLOAD_ENABLE; + hdd_wlan_offload_event(SIR_IPV4_ARP_REPLY_OFFLOAD, + SIR_OFFLOAD_ENABLE); + + hdd_notice("Enable ARP offload: filter programmed = %d", + offLoadRequest.enableOrDisable); + + /* converting u32 to IPV4 address */ + for (i = 0; i < 4; i++) { + offLoadRequest.params.hostIpv4Addr[i] = + (ifa->ifa_local >> (i * 8)) & 0xFF; + } + hdd_notice(" Enable SME HostOffload: %d.%d.%d.%d", + offLoadRequest.params.hostIpv4Addr[0], + offLoadRequest.params.hostIpv4Addr[1], + offLoadRequest.params.hostIpv4Addr[2], + offLoadRequest.params.hostIpv4Addr[3]); + + if (QDF_STATUS_SUCCESS != + sme_set_host_offload(WLAN_HDD_GET_HAL_CTX(pAdapter), + pAdapter->sessionId, + &offLoadRequest)) { + hdd_err("Failed to enable HostOffload feature"); + return QDF_STATUS_E_FAILURE; + } + } else { + hdd_notice("IP Address is not assigned"); + } + + return QDF_STATUS_SUCCESS; + } else { + hdd_wlan_offload_event(SIR_IPV4_ARP_REPLY_OFFLOAD, + SIR_OFFLOAD_DISABLE); + qdf_mem_zero((void *)&offLoadRequest, + sizeof(tSirHostOffloadReq)); + offLoadRequest.enableOrDisable = SIR_OFFLOAD_DISABLE; + offLoadRequest.offloadType = SIR_IPV4_ARP_REPLY_OFFLOAD; + + if (QDF_STATUS_SUCCESS != + sme_set_host_offload(WLAN_HDD_GET_HAL_CTX(pAdapter), + pAdapter->sessionId, &offLoadRequest)) { + hdd_err("Failure to disable host " "offload feature"); + return QDF_STATUS_E_FAILURE; + } + return QDF_STATUS_SUCCESS; + } +} + +int hdd_conf_hw_filter_mode(hdd_adapter_t *adapter, enum hw_filter_mode mode) +{ + QDF_STATUS status; + + if (!adapter) { + hdd_err("adapter is null"); + return -EINVAL; + } + + status = sme_conf_hw_filter_mode(WLAN_HDD_GET_HAL_CTX(adapter), + adapter->sessionId, mode); + + return qdf_status_to_os_return(status); +} + +#ifdef WLAN_FEATURE_PACKET_FILTERING +/** + * wlan_hdd_set_mc_addr_list() - set MC address list in FW + * @pAdapter: adapter whose MC list is being set + * @set: flag which indicates if addresses are being set or cleared + * + * Returns: 0 on success, errno on failure + */ +int wlan_hdd_set_mc_addr_list(hdd_adapter_t *pAdapter, uint8_t set) +{ + uint8_t i; + int ret = 0; + tpSirRcvFltMcAddrList pMulticastAddrs = NULL; + tHalHandle hHal = NULL; + hdd_context_t *pHddCtx = (hdd_context_t *) pAdapter->pHddCtx; + hdd_station_ctx_t *sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + + ENTER(); + + ret = wlan_hdd_validate_context(pHddCtx); + if (0 != ret) + return ret; + + hHal = pHddCtx->hHal; + + if (NULL == hHal) { + hdd_err("HAL Handle is NULL"); + return -EINVAL; + } + + if (!sta_ctx) { + hdd_err("sta_ctx is NULL"); + return -EINVAL; + } + + /* Check if INI is enabled or not, other wise just return */ + if (!pHddCtx->config->fEnableMCAddrList) { + hdd_notice("gMCAddrListEnable is not enabled in INI"); + return -EINVAL; + } + pMulticastAddrs = qdf_mem_malloc(sizeof(tSirRcvFltMcAddrList)); + if (NULL == pMulticastAddrs) { + hdd_err("Could not allocate Memory"); + return -EINVAL; + } + pMulticastAddrs->action = set; + + if (set) { + /* + * Following pre-conditions should be satisfied before we + * configure the MC address list. + */ + if (pAdapter->mc_addr_list.mc_cnt && + (((pAdapter->device_mode == QDF_STA_MODE || + pAdapter->device_mode == QDF_P2P_CLIENT_MODE) && + hdd_conn_is_connected(sta_ctx)) || + (WLAN_HDD_IS_NDI(pAdapter) && + WLAN_HDD_IS_NDI_CONNECTED(pAdapter)))) { + + pMulticastAddrs->ulMulticastAddrCnt = + pAdapter->mc_addr_list.mc_cnt; + + for (i = 0; i < pAdapter->mc_addr_list.mc_cnt; i++) { + memcpy(pMulticastAddrs->multicastAddr[i].bytes, + pAdapter->mc_addr_list.addr[i], + sizeof(pAdapter->mc_addr_list.addr[i])); + hdd_info("%s multicast filter: addr =" + MAC_ADDRESS_STR, + set ? "setting" : "clearing", + MAC_ADDR_ARRAY(pMulticastAddrs-> + multicastAddr[i].bytes)); + } + /* Set multicast filter */ + sme_8023_multicast_list(hHal, pAdapter->sessionId, + pMulticastAddrs); + } else { + hdd_info("MC address list not sent to FW, cnt: %d", + pAdapter->mc_addr_list.mc_cnt); + } + } else { + /* Need to clear only if it was previously configured */ + if (pAdapter->mc_addr_list.isFilterApplied) { + pMulticastAddrs->ulMulticastAddrCnt = + pAdapter->mc_addr_list.mc_cnt; + for (i = 0; i < pAdapter->mc_addr_list.mc_cnt; i++) { + memcpy(pMulticastAddrs->multicastAddr[i].bytes, + pAdapter->mc_addr_list.addr[i], + sizeof(pAdapter->mc_addr_list.addr[i])); + } + sme_8023_multicast_list(hHal, pAdapter->sessionId, + pMulticastAddrs); + } + + } + /* MAddrCnt is MulticastAddrCnt */ + hdd_notice("smeSessionId:%d; set:%d; MCAdddrCnt :%d", + pAdapter->sessionId, set, + pMulticastAddrs->ulMulticastAddrCnt); + + pAdapter->mc_addr_list.isFilterApplied = set ? true : false; + qdf_mem_free(pMulticastAddrs); + + EXIT(); + + return ret; +} +#endif + +/** + * hdd_conf_suspend_ind() - Send Suspend notification + * @pHddCtx: HDD Global context + * @pAdapter: adapter being suspended + * @callback: callback function to be called upon completion + * @callbackContext: callback context to be passed back to callback function + * + * Return: None. + */ +static void hdd_send_suspend_ind(hdd_context_t *pHddCtx, + uint32_t conn_state_mask, + void (*callback)(void *callbackContext, + bool suspended), + void *callbackContext) +{ + QDF_STATUS qdf_ret_status = QDF_STATUS_E_FAILURE; + + hdd_info("send wlan suspend indication"); + + qdf_ret_status = + sme_configure_suspend_ind(pHddCtx->hHal, conn_state_mask, + callback, callbackContext); + + if (QDF_STATUS_SUCCESS != qdf_ret_status) + hdd_err("sme_configure_suspend_ind returned failure %d", + qdf_ret_status); +} + +/** + * hdd_conf_suspend_ind() - Send Resume notification + * @pAdapter: adapter being resumed + * + * Return: None. + */ +static void hdd_conf_resume_ind(hdd_adapter_t *pAdapter) +{ + hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + QDF_STATUS qdf_ret_status = QDF_STATUS_E_FAILURE; + + qdf_ret_status = sme_configure_resume_req(pHddCtx->hHal, NULL); + + if (QDF_STATUS_SUCCESS != qdf_ret_status) { + hdd_err("sme_configure_resume_req return failure %d", qdf_ret_status); + + } + + hdd_notice("send wlan resume indication"); + /* Disable supported OffLoads */ + hdd_conf_hostoffload(pAdapter, false); +} + +/** + * hdd_update_conn_state_mask(): record info needed by wma_suspend_req + * @adapter: adapter to get info from + * @conn_state_mask: mask of connection info + * + * currently only need to send connection info. + */ +static void +hdd_update_conn_state_mask(hdd_adapter_t *adapter, uint32_t *conn_state_mask) +{ + + eConnectionState connState; + hdd_station_ctx_t *sta_ctx; + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + connState = sta_ctx->conn_info.connState; + + if (connState == eConnectionState_Associated || + connState == eConnectionState_IbssConnected) + *conn_state_mask |= (1 << adapter->sessionId); +} + +/** + * hdd_suspend_wlan() - Driver suspend function + * @callback: Callback function to invoke when driver is ready to suspend + * @callbackContext: Context to pass back to @callback function + * + * Return: None. + */ +static void +hdd_suspend_wlan(void (*callback)(void *callbackContext, bool suspended), + void *callbackContext) +{ + hdd_context_t *pHddCtx; + + QDF_STATUS status; + hdd_adapter_t *pAdapter = NULL; + hdd_adapter_list_node_t *pAdapterNode = NULL, *pNext = NULL; + uint32_t conn_state_mask = 0; + + hdd_info("WLAN being suspended by OS"); + + pHddCtx = cds_get_context(QDF_MODULE_ID_HDD); + if (!pHddCtx) { + hdd_alert("HDD context is Null"); + return; + } + + if (cds_is_driver_recovering()) { + hdd_err("Recovery in Progress. State: 0x%x Ignore suspend!!!", + cds_get_driver_state()); + return; + } + + + status = hdd_get_front_adapter(pHddCtx, &pAdapterNode); + while (NULL != pAdapterNode && QDF_STATUS_SUCCESS == status) { + pAdapter = pAdapterNode->pAdapter; + + /* stop all TX queues before suspend */ + hdd_notice("Disabling queues"); + wlan_hdd_netif_queue_control(pAdapter, WLAN_STOP_ALL_NETIF_QUEUE, + WLAN_CONTROL_PATH); + + if (pAdapter->device_mode == QDF_STA_MODE) + status = hdd_enable_default_pkt_filters(pAdapter); + /* Configure supported OffLoads */ + hdd_conf_hostoffload(pAdapter, true); + + hdd_update_conn_state_mask(pAdapter, &conn_state_mask); + + status = hdd_get_next_adapter(pHddCtx, pAdapterNode, &pNext); + + pAdapterNode = pNext; + } + + hdd_send_suspend_ind(pHddCtx, conn_state_mask, callback, + callbackContext); + + pHddCtx->hdd_wlan_suspended = true; + hdd_wlan_suspend_resume_event(HDD_WLAN_EARLY_SUSPEND); + + return; +} + +/** + * hdd_resume_wlan() - Driver resume function + * + * Return: None. + */ +static void hdd_resume_wlan(void) +{ + hdd_context_t *pHddCtx; + hdd_adapter_t *pAdapter = NULL; + hdd_adapter_list_node_t *pAdapterNode = NULL, *pNext = NULL; + QDF_STATUS status; + + hdd_info("WLAN being resumed by OS"); + + pHddCtx = cds_get_context(QDF_MODULE_ID_HDD); + if (!pHddCtx) { + hdd_err("HDD context is Null"); + return; + } + + if (cds_is_driver_recovering()) { + hdd_err("Recovery in Progress. State: 0x%x Ignore resume!!!", + cds_get_driver_state()); + return; + } + + pHddCtx->hdd_wlan_suspended = false; + hdd_wlan_suspend_resume_event(HDD_WLAN_EARLY_RESUME); + + /*loop through all adapters. Concurrency */ + status = hdd_get_front_adapter(pHddCtx, &pAdapterNode); + + while (NULL != pAdapterNode && QDF_STATUS_SUCCESS == status) { + pAdapter = pAdapterNode->pAdapter; + + /* wake the tx queues */ + hdd_info("Enabling queues"); + wlan_hdd_netif_queue_control(pAdapter, + WLAN_WAKE_ALL_NETIF_QUEUE, + WLAN_CONTROL_PATH); + + if (pAdapter->device_mode == QDF_STA_MODE) + status = hdd_disable_default_pkt_filters(pAdapter); + hdd_conf_resume_ind(pAdapter); + + status = hdd_get_next_adapter(pHddCtx, pAdapterNode, &pNext); + pAdapterNode = pNext; + } + hdd_ipa_resume(pHddCtx); + + return; +} + +/** + * DOC: SSR Timer + * + * When SSR is initiated, an SSR timer is started. Under normal + * circumstances SSR should complete amd the timer should be deleted + * before it fires. If the SSR timer does fire, it indicates SSR has + * taken too long, and our only recourse is to invoke the QDF_BUG() + * API which can allow a crashdump to be captured. + */ + +/** + * hdd_ssr_timer_init() - Initialize SSR Timer + * + * Return: None. + */ +static void hdd_ssr_timer_init(void) +{ + init_timer(&ssr_timer); +} + +/** + * hdd_ssr_timer_del() - Delete SSR Timer + * + * Return: None. + */ +static void hdd_ssr_timer_del(void) +{ + del_timer(&ssr_timer); + ssr_timer_started = false; +} + +/** + * hdd_ssr_timer_cb() - SSR Timer callback function + * @data: opaque data registered with timer infrastructure + * + * Return: None. + */ +static void hdd_ssr_timer_cb(unsigned long data) +{ + hdd_alert("HDD SSR timer expired!"); + QDF_BUG(0); +} + +/** + * hdd_ssr_timer_start() - Start SSR Timer + * @msec: Timer timeout value in milliseconds + * + * Return: None. + */ +static void hdd_ssr_timer_start(int msec) +{ + if (ssr_timer_started) { + hdd_alert("Trying to start SSR timer when " "it's running!"); + } + ssr_timer.expires = jiffies + msecs_to_jiffies(msec); + ssr_timer.function = hdd_ssr_timer_cb; + add_timer(&ssr_timer); + ssr_timer_started = true; +} + +/** + * hdd_svc_fw_shutdown_ind() - API to send FW SHUTDOWN IND to Userspace + * + * @dev: Device Pointer + * + * Return: None + */ +void hdd_svc_fw_shutdown_ind(struct device *dev) +{ + hdd_context_t *hdd_ctx; + v_CONTEXT_t g_context; + + g_context = cds_get_global_context(); + + if (!g_context) + return; + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + + hdd_ctx ? wlan_hdd_send_svc_nlink_msg(hdd_ctx->radio_index, + WLAN_SVC_FW_SHUTDOWN_IND, + NULL, 0) : 0; +} + +/** + * hdd_ssr_restart_sap() - restart sap on SSR + * @hdd_ctx: hdd context + * + * Return: nothing + */ +static void hdd_ssr_restart_sap(hdd_context_t *hdd_ctx) +{ + QDF_STATUS status; + hdd_adapter_list_node_t *adapter_node = NULL, *next = NULL; + hdd_adapter_t *adapter; + + ENTER(); + + status = hdd_get_front_adapter(hdd_ctx, &adapter_node); + while (NULL != adapter_node && QDF_STATUS_SUCCESS == status) { + adapter = adapter_node->pAdapter; + if (adapter && adapter->device_mode == QDF_SAP_MODE) { + if (test_bit(SOFTAP_INIT_DONE, &adapter->event_flags)) { + hdd_notice("Restart prev SAP session"); + wlan_hdd_start_sap(adapter, true); + } + } + status = hdd_get_next_adapter(hdd_ctx, adapter_node, &next); + adapter_node = next; + } + + EXIT(); +} + +/** + * hdd_wlan_shutdown() - HDD SSR shutdown function + * + * This function is called by the HIF to shutdown the driver during SSR. + * + * Return: QDF_STATUS_SUCCESS if the driver was shut down, + * or an error status otherwise + */ +QDF_STATUS hdd_wlan_shutdown(void) +{ + v_CONTEXT_t p_cds_context = NULL; + hdd_context_t *pHddCtx; + p_cds_sched_context cds_sched_context = NULL; + QDF_STATUS qdf_status; + + hdd_alert("WLAN driver shutting down!"); + + /* If SSR never completes, then do kernel panic. */ + hdd_ssr_timer_init(); + hdd_ssr_timer_start(HDD_SSR_BRING_UP_TIME); + + /* Get the global CDS context. */ + p_cds_context = cds_get_global_context(); + if (!p_cds_context) { + hdd_alert("Global CDS context is Null"); + return QDF_STATUS_E_FAILURE; + } + + /* Get the HDD context. */ + pHddCtx = cds_get_context(QDF_MODULE_ID_HDD); + if (!pHddCtx) { + hdd_alert("HDD context is Null"); + return QDF_STATUS_E_FAILURE; + } + + cds_clear_concurrent_session_count(); + + hdd_info("Invoking packetdump deregistration API"); + wlan_deregister_txrx_packetdump(); + + hdd_cleanup_scan_queue(pHddCtx); + hdd_reset_all_adapters(pHddCtx); + + /* Flush cached rx frame queue */ + ol_txrx_flush_cache_rx_queue(); + + /* De-register the HDD callbacks */ + hdd_deregister_cb(pHddCtx); + + cds_sched_context = get_cds_sched_ctxt(); + + /* Wakeup all driver threads */ + if (true == pHddCtx->isMcThreadSuspended) { + complete(&cds_sched_context->ResumeMcEvent); + pHddCtx->isMcThreadSuspended = false; + } +#ifdef QCA_CONFIG_SMP + if (true == pHddCtx->is_ol_rx_thread_suspended) { + complete(&cds_sched_context->ol_resume_rx_event); + pHddCtx->is_ol_rx_thread_suspended = false; + } +#endif + + qdf_status = cds_sched_close(p_cds_context); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + hdd_err("Failed to close CDS Scheduler"); + QDF_ASSERT(false); + } + hdd_ipa_uc_ssr_deinit(); + + qdf_mc_timer_stop(&pHddCtx->tdls_source_timer); + + hdd_bus_bandwidth_destroy(pHddCtx); + + hdd_wlan_stop_modules(pHddCtx, false); + + hdd_lpass_notify_stop(pHddCtx); + + hdd_alert("WLAN driver shutdown complete"); + return QDF_STATUS_SUCCESS; +} + +#ifdef FEATURE_WLAN_DIAG_SUPPORT +/** +* hdd_wlan_ssr_reinit_event()- send ssr reinit state +* +* This Function send send ssr reinit state diag event +* +* Return: void. +*/ +static void hdd_wlan_ssr_reinit_event(void) +{ + WLAN_HOST_DIAG_EVENT_DEF(ssr_reinit, struct host_event_wlan_ssr_reinit); + qdf_mem_zero(&ssr_reinit, sizeof(ssr_reinit)); + ssr_reinit.status = SSR_SUB_SYSTEM_REINIT; + WLAN_HOST_DIAG_EVENT_REPORT(&ssr_reinit, + EVENT_WLAN_SSR_REINIT_SUBSYSTEM); +} +#else +static inline void hdd_wlan_ssr_reinit_event(void) +{ + +} +#endif + +/** + * hdd_wlan_re_init() - HDD SSR re-init function + * + * This function is called by the HIF to re-initialize the driver after SSR. + * + * Return: QDF_STATUS_SUCCESS if the driver was re-initialized, + * or an error status otherwise + */ +QDF_STATUS hdd_wlan_re_init(void) +{ + + v_CONTEXT_t p_cds_context = NULL; + hdd_context_t *pHddCtx = NULL; + hdd_adapter_t *pAdapter; + int ret; + bool bug_on_reinit_failure = CFG_BUG_ON_REINIT_FAILURE_DEFAULT; + + hdd_prevent_suspend(WIFI_POWER_EVENT_WAKELOCK_DRIVER_REINIT); + + /* Get the CDS context */ + p_cds_context = cds_get_global_context(); + if (p_cds_context == NULL) { + hdd_alert("Failed cds_get_global_context"); + goto err_re_init; + } + + /* Get the HDD context */ + pHddCtx = cds_get_context(QDF_MODULE_ID_HDD); + if (!pHddCtx) { + hdd_alert("HDD context is Null"); + goto err_re_init; + } + bug_on_reinit_failure = pHddCtx->config->bug_on_reinit_failure; + + /* The driver should always be initialized in STA mode after SSR */ + hdd_set_conparam(0); + /* Try to get an adapter from mode ID */ + pAdapter = hdd_get_adapter(pHddCtx, QDF_STA_MODE); + if (!pAdapter) { + pAdapter = hdd_get_adapter(pHddCtx, QDF_SAP_MODE); + if (!pAdapter) { + pAdapter = hdd_get_adapter(pHddCtx, QDF_IBSS_MODE); + if (!pAdapter) { + hdd_alert("Failed to get Adapter!"); + } + } + } + + if (pHddCtx->config->enable_dp_trace) + qdf_dp_trace_init(); + + hdd_bus_bandwidth_init(pHddCtx); + + + ret = hdd_wlan_start_modules(pHddCtx, pAdapter, true); + if (ret) { + hdd_err("Failed to start wlan after error"); + goto err_wiphy_unregister; + } + + hdd_wlan_get_version(pHddCtx, NULL, NULL); + + wlan_hdd_send_svc_nlink_msg(pHddCtx->radio_index, + WLAN_SVC_FW_CRASHED_IND, NULL, 0); + + /* Restart all adapters */ + hdd_start_all_adapters(pHddCtx); + + pHddCtx->last_scan_reject_session_id = 0xFF; + pHddCtx->last_scan_reject_reason = 0; + pHddCtx->last_scan_reject_timestamp = 0; + + hdd_set_roaming_in_progress(false); + complete(&pAdapter->roaming_comp_var); + pHddCtx->btCoexModeSet = false; + + /* Allow the phone to go to sleep */ + hdd_allow_suspend(WIFI_POWER_EVENT_WAKELOCK_DRIVER_REINIT); + + ret = hdd_register_cb(pHddCtx); + if (ret) { + hdd_err("Failed to register HDD callbacks!"); + goto err_cds_disable; + } + + hdd_lpass_notify_start(pHddCtx); + /* set chip power save failure detected callback */ + sme_set_chip_pwr_save_fail_cb(pHddCtx->hHal, + hdd_chip_pwr_save_fail_detected_cb); + + hdd_err("WLAN host driver reinitiation completed!"); + goto success; + +err_cds_disable: + hdd_wlan_stop_modules(pHddCtx, false); + +err_wiphy_unregister: + if (bug_on_reinit_failure) + QDF_BUG(0); + + if (pHddCtx) { + /* Unregister the Notifier's */ + hdd_unregister_notifiers(pHddCtx); + ptt_sock_deactivate_svc(); + nl_srv_exit(); + + hdd_close_all_adapters(pHddCtx, false); + wlan_hdd_cfg80211_deinit(pHddCtx->wiphy); + hdd_lpass_notify_stop(pHddCtx); + wlan_hdd_deinit_tx_rx_histogram(pHddCtx); + wiphy_unregister(pHddCtx->wiphy); + } + +err_re_init: + hdd_ssr_timer_del(); + /* Allow the phone to go to sleep */ + hdd_allow_suspend(WIFI_POWER_EVENT_WAKELOCK_DRIVER_REINIT); + return -EPERM; + +success: + if (pHddCtx->config->sap_internal_restart) + hdd_ssr_restart_sap(pHddCtx); + hdd_ssr_timer_del(); + hdd_wlan_ssr_reinit_event(); + return QDF_STATUS_SUCCESS; +} + +/** + * wlan_hdd_set_powersave() - Set powersave mode + * @adapter: adapter upon which the request was received + * @allow_power_save: is wlan allowed to go into power save mode + * @timeout: timeout period in ms + * + * Return: 0 on success, non-zero on any error + */ +static int wlan_hdd_set_powersave(hdd_adapter_t *adapter, + bool allow_power_save, uint32_t timeout) +{ + tHalHandle hal; + hdd_context_t *hdd_ctx; + bool force_trigger = false; + + if (NULL == adapter) { + hdd_alert("Adapter NULL"); + return -ENODEV; + } + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + if (!hdd_ctx) { + hdd_err("hdd context is NULL"); + return -EINVAL; + } + + hdd_info("Allow power save: %d", allow_power_save); + hal = WLAN_HDD_GET_HAL_CTX(adapter); + + if ((QDF_STA_MODE == adapter->device_mode) && + !adapter->sessionCtx.station.ap_supports_immediate_power_save) { + /* override user's requested flag */ + force_trigger = allow_power_save; + allow_power_save = false; + timeout = AUTO_PS_ENTRY_USER_TIMER_DEFAULT_VALUE; + hdd_debug("Defer power-save for few seconds..."); + } + + if (allow_power_save) { + if (QDF_STA_MODE == adapter->device_mode || + QDF_P2P_CLIENT_MODE == adapter->device_mode) { + hdd_notice("Disabling Auto Power save timer"); + sme_ps_disable_auto_ps_timer( + WLAN_HDD_GET_HAL_CTX(adapter), + adapter->sessionId); + } + + if (hdd_ctx->config && hdd_ctx->config->is_ps_enabled) { + hdd_notice("Wlan driver Entering Power save"); + + /* + * Enter Power Save command received from GUI + * this means DHCP is completed + */ + sme_ps_enable_disable(hal, adapter->sessionId, + SME_PS_ENABLE); + } else { + hdd_info("Power Save is not enabled in the cfg"); + } + } else { + hdd_info("Wlan driver Entering Full Power"); + + /* + * Enter Full power command received from GUI + * this means we are disconnected + */ + sme_ps_disable_auto_ps_timer(WLAN_HDD_GET_HAL_CTX(adapter), + adapter->sessionId); + sme_ps_enable_disable(hal, adapter->sessionId, SME_PS_DISABLE); + sme_ps_enable_auto_ps_timer(WLAN_HDD_GET_HAL_CTX(adapter), + adapter->sessionId, timeout, force_trigger); + } + + return 0; +} + +static void wlan_hdd_print_suspend_fail_stats(hdd_context_t *hdd_ctx) +{ + struct suspend_resume_stats *stats = &hdd_ctx->suspend_resume_stats; + hdd_err("ipa:%d, radar:%d, roam:%d, scan:%d, initial_wakeup:%d", + stats->suspend_fail[SUSPEND_FAIL_IPA], + stats->suspend_fail[SUSPEND_FAIL_RADAR], + stats->suspend_fail[SUSPEND_FAIL_ROAM], + stats->suspend_fail[SUSPEND_FAIL_SCAN], + stats->suspend_fail[SUSPEND_FAIL_INITIAL_WAKEUP]); +} + +void wlan_hdd_inc_suspend_stats(hdd_context_t *hdd_ctx, + enum suspend_fail_reason reason) +{ + wlan_hdd_print_suspend_fail_stats(hdd_ctx); + hdd_ctx->suspend_resume_stats.suspend_fail[reason]++; + wlan_hdd_print_suspend_fail_stats(hdd_ctx); +} + +/** + * __wlan_hdd_cfg80211_resume_wlan() - cfg80211 resume callback + * @wiphy: Pointer to wiphy + * + * This API is called when cfg80211 driver resumes driver updates + * latest sched_scan scan result(if any) to cfg80211 database + * + * Return: integer status + */ +static int __wlan_hdd_cfg80211_resume_wlan(struct wiphy *wiphy) +{ + hdd_context_t *pHddCtx = wiphy_priv(wiphy); + hdd_adapter_t *pAdapter; + hdd_adapter_list_node_t *pAdapterNode, *pNext; + QDF_STATUS status = QDF_STATUS_SUCCESS; + int exit_code; + p_cds_sched_context cds_sched_context = get_cds_sched_ctxt(); + + ENTER(); + + if (cds_is_driver_recovering()) { + hdd_info("Driver is recovering; Skipping resume"); + exit_code = 0; + goto exit_with_code; + } + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + exit_code = -EINVAL; + goto exit_with_code; + } + + exit_code = wlan_hdd_validate_context(pHddCtx); + if (exit_code) { + hdd_err("Invalid HDD context"); + goto exit_with_code; + } + + mutex_lock(&pHddCtx->iface_change_lock); + if (pHddCtx->driver_status != DRIVER_MODULES_ENABLED) { + mutex_unlock(&pHddCtx->iface_change_lock); + hdd_info("Driver is not enabled; Skipping resume"); + exit_code = 0; + goto exit_with_code; + } + mutex_unlock(&pHddCtx->iface_change_lock); + + pld_request_bus_bandwidth(pHddCtx->parent_dev, PLD_BUS_WIDTH_MEDIUM); + + /* Resume MC thread */ + if (pHddCtx->isMcThreadSuspended) { + complete(&cds_sched_context->ResumeMcEvent); + pHddCtx->isMcThreadSuspended = false; + } +#ifdef QCA_CONFIG_SMP + /* Resume tlshim Rx thread */ + if (pHddCtx->is_ol_rx_thread_suspended) { + complete(&cds_sched_context->ol_resume_rx_event); + pHddCtx->is_ol_rx_thread_suspended = false; + } +#endif + hdd_resume_wlan(); + + MTRACE(qdf_trace(QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_CFG80211_RESUME_WLAN, + NO_SESSION, pHddCtx->isWiphySuspended)); + qdf_spin_lock(&pHddCtx->sched_scan_lock); + pHddCtx->isWiphySuspended = false; + if (true != pHddCtx->isSchedScanUpdatePending) { + qdf_spin_unlock(&pHddCtx->sched_scan_lock); + hdd_info("Return resume is not due to PNO indication"); + goto exit_with_success; + } + /* Reset flag to avoid updatating cfg80211 data old results again */ + pHddCtx->isSchedScanUpdatePending = false; + qdf_spin_unlock(&pHddCtx->sched_scan_lock); + + status = hdd_get_front_adapter(pHddCtx, &pAdapterNode); + while (NULL != pAdapterNode && QDF_STATUS_SUCCESS == status) { + pAdapter = pAdapterNode->pAdapter; + if ((NULL != pAdapter) && + (QDF_STA_MODE == pAdapter->device_mode)) { + if (0 != + wlan_hdd_cfg80211_update_bss(pHddCtx->wiphy, + pAdapter, 0)) { + hdd_warn("NO SCAN result"); + } else { + /* Acquire wakelock to handle the case where + * APP's tries to suspend immediately after + * updating the scan results. Whis results in + * app's is in suspended state and not able to + * process the connect request to AP + */ + hdd_prevent_suspend_timeout( + HDD_WAKE_LOCK_RESUME_DURATION, + WIFI_POWER_EVENT_WAKELOCK_RESUME_WLAN); + cfg80211_sched_scan_results(pHddCtx->wiphy); + } + + hdd_info("cfg80211 scan result database updated"); + goto exit_with_success; + } + status = hdd_get_next_adapter(pHddCtx, pAdapterNode, &pNext); + pAdapterNode = pNext; + } + +exit_with_success: + pHddCtx->suspend_resume_stats.resumes++; + exit_code = 0; + +exit_with_code: + EXIT(); + return exit_code; +} + +/** + * wlan_hdd_cfg80211_ready_to_suspend() - set cfg80211 ready to suspend event + * @callbackContext: Pointer to callback context + * @suspended: Suspend flag + * + * Return: none + */ +static void wlan_hdd_cfg80211_ready_to_suspend(void *callbackContext, + bool suspended) +{ + hdd_context_t *pHddCtx = (hdd_context_t *) callbackContext; + pHddCtx->suspended = suspended; + complete(&pHddCtx->ready_to_suspend); +} + +/** + * wlan_hdd_cfg80211_resume_wlan() - cfg80211 resume callback + * @wiphy: Pointer to wiphy + * + * This API is called when cfg80211 driver resumes driver updates + * latest sched_scan scan result(if any) to cfg80211 database + * + * Return: integer status + */ +int wlan_hdd_cfg80211_resume_wlan(struct wiphy *wiphy) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_resume_wlan(wiphy); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __wlan_hdd_cfg80211_suspend_wlan() - cfg80211 suspend callback + * @wiphy: Pointer to wiphy + * @wow: Pointer to wow + * + * This API is called when cfg80211 driver suspends + * + * Return: integer status + */ +static int __wlan_hdd_cfg80211_suspend_wlan(struct wiphy *wiphy, + struct cfg80211_wowlan *wow) +{ +#ifdef QCA_CONFIG_SMP +#define RX_TLSHIM_SUSPEND_TIMEOUT 200 /* msecs */ +#endif + hdd_context_t *pHddCtx = wiphy_priv(wiphy); + p_cds_sched_context cds_sched_context = get_cds_sched_ctxt(); + hdd_adapter_list_node_t *pAdapterNode = NULL, *pNext = NULL; + hdd_adapter_t *pAdapter; + hdd_scaninfo_t *pScanInfo; + QDF_STATUS status; + int rc; + + ENTER(); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EINVAL; + } + + rc = wlan_hdd_validate_context(pHddCtx); + if (0 != rc) + return rc; + + mutex_lock(&pHddCtx->iface_change_lock); + if (pHddCtx->driver_status != DRIVER_MODULES_ENABLED) { + mutex_unlock(&pHddCtx->iface_change_lock); + hdd_info("Driver Modules not Enabled "); + return 0; + } + mutex_unlock(&pHddCtx->iface_change_lock); + + /* If RADAR detection is in progress (HDD), prevent suspend. The flag + * "dfs_cac_block_tx" is set to true when RADAR is found and stay true + * until CAC is done for a SoftAP which is in started state. + */ + status = hdd_get_front_adapter(pHddCtx, &pAdapterNode); + while (NULL != pAdapterNode && QDF_STATUS_SUCCESS == status) { + pAdapter = pAdapterNode->pAdapter; + + if (wlan_hdd_validate_session_id(pAdapter->sessionId)) { + hdd_err("invalid session id: %d", pAdapter->sessionId); + goto next_adapter; + } + + if (QDF_SAP_MODE == pAdapter->device_mode) { + if (BSS_START == + WLAN_HDD_GET_HOSTAP_STATE_PTR(pAdapter)->bssState && + true == + WLAN_HDD_GET_AP_CTX_PTR(pAdapter)-> + dfs_cac_block_tx) { + hdd_err("RADAR detection in progress, do not allow suspend"); + wlan_hdd_inc_suspend_stats(pHddCtx, + SUSPEND_FAIL_RADAR); + return -EAGAIN; + } else if (!pHddCtx->config->enableSapSuspend) { + /* return -EOPNOTSUPP if SAP does not support + * suspend + */ + hdd_err("SAP does not support suspend!!"); + return -EOPNOTSUPP; + } + } else if (QDF_P2P_GO_MODE == pAdapter->device_mode) { + if (!pHddCtx->config->enableSapSuspend) { + /* return -EOPNOTSUPP if GO does not support + * suspend + */ + hdd_err("GO does not support suspend!!"); + return -EOPNOTSUPP; + } + } + if (pAdapter->is_roc_inprogress) + wlan_hdd_cleanup_remain_on_channel_ctx(pAdapter); +next_adapter: + status = hdd_get_next_adapter(pHddCtx, pAdapterNode, &pNext); + pAdapterNode = pNext; + } + + /* Stop ongoing scan on each interface */ + status = hdd_get_front_adapter(pHddCtx, &pAdapterNode); + while (NULL != pAdapterNode && QDF_STATUS_SUCCESS == status) { + pAdapter = pAdapterNode->pAdapter; + pScanInfo = &pAdapter->scan_info; + + if (sme_neighbor_middle_of_roaming + (pHddCtx->hHal, pAdapter->sessionId)) { + hdd_err("Roaming in progress, do not allow suspend"); + wlan_hdd_inc_suspend_stats(pHddCtx, + SUSPEND_FAIL_ROAM); + return -EAGAIN; + } + + hdd_abort_mac_scan(pHddCtx, pAdapter->sessionId, + INVALID_SCAN_ID, eCSR_SCAN_ABORT_DEFAULT); + + /* for suspend case, don't wait for scan cancel completion */ + + status = hdd_get_next_adapter(pHddCtx, pAdapterNode, &pNext); + pAdapterNode = pNext; + } + + /* + * Suspend IPA early before proceeding to suspend other entities like + * firmware to avoid any race conditions. + */ + if (hdd_ipa_suspend(pHddCtx)) { + hdd_err("IPA not ready to suspend!"); + wlan_hdd_inc_suspend_stats(pHddCtx, SUSPEND_FAIL_IPA); + return -EAGAIN; + } + + /* Wait for the target to be ready for suspend */ + INIT_COMPLETION(pHddCtx->ready_to_suspend); + + hdd_suspend_wlan(&wlan_hdd_cfg80211_ready_to_suspend, pHddCtx); + + rc = wait_for_completion_timeout(&pHddCtx->ready_to_suspend, + msecs_to_jiffies(WLAN_WAIT_TIME_READY_TO_SUSPEND)); + if (!rc) { + hdd_err("Failed to get ready to suspend"); + goto resume_tx; + } + + if (!pHddCtx->suspended) { + hdd_err("Faied as suspend_status is wrong:%d", + pHddCtx->suspended); + goto resume_tx; + } + + /* Suspend MC thread */ + set_bit(MC_SUSPEND_EVENT, &cds_sched_context->mcEventFlag); + wake_up_interruptible(&cds_sched_context->mcWaitQueue); + + /* Wait for suspend confirmation from MC thread */ + rc = wait_for_completion_timeout(&pHddCtx->mc_sus_event_var, + msecs_to_jiffies(WLAN_WAIT_TIME_MCTHREAD_SUSPEND)); + if (!rc) { + clear_bit(MC_SUSPEND_EVENT, + &cds_sched_context->mcEventFlag); + hdd_err("Failed to stop mc thread"); + goto resume_tx; + } + + pHddCtx->isMcThreadSuspended = true; + +#ifdef QCA_CONFIG_SMP + /* Suspend tlshim rx thread */ + set_bit(RX_SUSPEND_EVENT, &cds_sched_context->ol_rx_event_flag); + wake_up_interruptible(&cds_sched_context->ol_rx_wait_queue); + rc = wait_for_completion_timeout(&cds_sched_context-> + ol_suspend_rx_event, + msecs_to_jiffies + (RX_TLSHIM_SUSPEND_TIMEOUT)); + if (!rc) { + clear_bit(RX_SUSPEND_EVENT, + &cds_sched_context->ol_rx_event_flag); + hdd_err("Failed to stop tl_shim rx thread"); + goto resume_all; + } + pHddCtx->is_ol_rx_thread_suspended = true; +#endif + MTRACE(qdf_trace(QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_CFG80211_SUSPEND_WLAN, + NO_SESSION, pHddCtx->isWiphySuspended)); + pHddCtx->isWiphySuspended = true; + + pld_request_bus_bandwidth(pHddCtx->parent_dev, PLD_BUS_WIDTH_NONE); + + EXIT(); + return 0; + +#ifdef QCA_CONFIG_SMP +resume_all: + + complete(&cds_sched_context->ResumeMcEvent); + pHddCtx->isMcThreadSuspended = false; +#endif + +resume_tx: + + hdd_resume_wlan(); + return -ETIME; + +} + +/** + * wlan_hdd_cfg80211_suspend_wlan() - cfg80211 suspend callback + * @wiphy: Pointer to wiphy + * @wow: Pointer to wow + * + * This API is called when cfg80211 driver suspends + * + * Return: integer status + */ +int wlan_hdd_cfg80211_suspend_wlan(struct wiphy *wiphy, + struct cfg80211_wowlan *wow) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_suspend_wlan(wiphy, wow); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * hdd_stop_dhcp_ind() - API to stop DHCP sequence + * @adapter: Adapter on which DHCP needs to be stopped + * + * Release the wakelock held for DHCP process and allow + * the runtime pm to continue + * + * Return: None + */ +static void hdd_stop_dhcp_ind(hdd_adapter_t *adapter) +{ + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + + hdd_warn("DHCP stop indicated through power save"); + sme_dhcp_stop_ind(hdd_ctx->hHal, adapter->device_mode, + adapter->macAddressCurrent.bytes, + adapter->sessionId); + hdd_allow_suspend(WIFI_POWER_EVENT_WAKELOCK_DHCP); + qdf_runtime_pm_allow_suspend(&adapter->connect_rpm_ctx.connect); +} + +/** + * hdd_start_dhcp_ind() - API to start DHCP sequence + * @adapter: Adapter on which DHCP needs to be stopped + * + * Prevent APPS suspend and the runtime suspend during + * DHCP sequence + * + * Return: None + */ +static void hdd_start_dhcp_ind(hdd_adapter_t *adapter) +{ + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + + hdd_err("DHCP start indicated through power save"); + qdf_runtime_pm_prevent_suspend(&adapter->connect_rpm_ctx.connect); + hdd_prevent_suspend_timeout(1000, WIFI_POWER_EVENT_WAKELOCK_DHCP); + sme_dhcp_start_ind(hdd_ctx->hHal, adapter->device_mode, + adapter->macAddressCurrent.bytes, + adapter->sessionId); +} + +/** + * __wlan_hdd_cfg80211_set_power_mgmt() - set cfg80211 power management config + * @wiphy: Pointer to wiphy + * @dev: Pointer to network device + * @allow_power_save: is wlan allowed to go into power save mode + * @timeout: Timeout value in ms + * + * Return: 0 for success, non-zero for failure + */ +static int __wlan_hdd_cfg80211_set_power_mgmt(struct wiphy *wiphy, + struct net_device *dev, + bool allow_power_save, + int timeout) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *pHddCtx; + QDF_STATUS qdf_status; + int status; + + ENTER(); + + if (timeout < 0) { + hdd_notice("User space timeout: %d; Using default instead: %d", + timeout, AUTO_PS_ENTRY_USER_TIMER_DEFAULT_VALUE); + timeout = AUTO_PS_ENTRY_USER_TIMER_DEFAULT_VALUE; + } + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EINVAL; + } + + if (wlan_hdd_validate_session_id(pAdapter->sessionId)) { + hdd_err("invalid session id: %d", pAdapter->sessionId); + return -EINVAL; + } + + MTRACE(qdf_trace(QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_CFG80211_SET_POWER_MGMT, + pAdapter->sessionId, timeout)); + + pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + status = wlan_hdd_validate_context(pHddCtx); + + if (0 != status) + return status; + + mutex_lock(&pHddCtx->iface_change_lock); + if (pHddCtx->driver_status != DRIVER_MODULES_ENABLED) { + mutex_unlock(&pHddCtx->iface_change_lock); + hdd_info("Driver Module not enabled return success"); + return 0; + } + mutex_unlock(&pHddCtx->iface_change_lock); + + if (allow_power_save && + pHddCtx->hdd_wlan_suspended && + pHddCtx->config->fhostArpOffload && + (eConnectionState_Associated == + (WLAN_HDD_GET_STATION_CTX_PTR(pAdapter))->conn_info.connState)) { + hdd_notice("offload: in cfg80211_set_power_mgmt, " + "calling arp offload"); + qdf_status = hdd_conf_arp_offload(pAdapter, true); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + hdd_notice("Failed to enable ARPOFFLOAD Feature %d", + qdf_status); + } + } + + status = wlan_hdd_set_powersave(pAdapter, allow_power_save, timeout); + + allow_power_save ? hdd_stop_dhcp_ind(pAdapter) : + hdd_start_dhcp_ind(pAdapter); + + EXIT(); + return status; +} + +/** + * wlan_hdd_cfg80211_set_power_mgmt() - set cfg80211 power management config + * @wiphy: Pointer to wiphy + * @dev: Pointer to network device + * @allow_power_save: is wlan allowed to go into power save mode + * @timeout: Timeout value + * + * Return: 0 for success, non-zero for failure + */ +int wlan_hdd_cfg80211_set_power_mgmt(struct wiphy *wiphy, + struct net_device *dev, + bool allow_power_save, + int timeout) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_set_power_mgmt(wiphy, dev, + allow_power_save, timeout); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __wlan_hdd_cfg80211_set_txpower() - set TX power + * @wiphy: Pointer to wiphy + * @wdev: Pointer to network device + * @type: TX power setting type + * @dbm: TX power in dbm + * + * Return: 0 for success, non-zero for failure + */ +static int __wlan_hdd_cfg80211_set_txpower(struct wiphy *wiphy, + struct wireless_dev *wdev, + enum nl80211_tx_power_setting type, + int dbm) +{ + hdd_context_t *pHddCtx = (hdd_context_t *) wiphy_priv(wiphy); + tHalHandle hHal = NULL; + struct qdf_mac_addr bssid = QDF_MAC_ADDR_BROADCAST_INITIALIZER; + struct qdf_mac_addr selfMac = QDF_MAC_ADDR_BROADCAST_INITIALIZER; + int status; + + ENTER(); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EINVAL; + } + + MTRACE(qdf_trace(QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_CFG80211_SET_TXPOWER, + NO_SESSION, type)); + + status = wlan_hdd_validate_context(pHddCtx); + if (0 != status) + return status; + + hHal = pHddCtx->hHal; + + if (0 != sme_cfg_set_int(hHal, WNI_CFG_CURRENT_TX_POWER_LEVEL, dbm)) { + hdd_err("sme_cfg_set_int failed for tx power %hu", + dbm); + return -EIO; + } + + hdd_info("Set tx power level %d dbm", dbm); + + switch (type) { + /* Automatically determine transmit power */ + case NL80211_TX_POWER_AUTOMATIC: + /* Fall through */ + case NL80211_TX_POWER_LIMITED: /* Limit TX power by the mBm parameter */ + if (sme_set_max_tx_power(hHal, bssid, selfMac, dbm) != + QDF_STATUS_SUCCESS) { + hdd_err("Setting maximum tx power failed"); + return -EIO; + } + break; + + case NL80211_TX_POWER_FIXED: /* Fix TX power to the mBm parameter */ + hdd_err("NL80211_TX_POWER_FIXED not supported"); + return -EOPNOTSUPP; + break; + + default: + hdd_err("Invalid power setting type %d", type); + return -EIO; + } + + EXIT(); + return 0; +} + +/** + * wlan_hdd_cfg80211_set_txpower() - set TX power + * @wiphy: Pointer to wiphy + * @wdev: Pointer to network device + * @type: TX power setting type + * @dbm: TX power in dbm + * + * Return: 0 for success, non-zero for failure + */ +int wlan_hdd_cfg80211_set_txpower(struct wiphy *wiphy, + struct wireless_dev *wdev, + enum nl80211_tx_power_setting type, + int dbm) +{ + int ret; + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_set_txpower(wiphy, + wdev, + type, dbm); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __wlan_hdd_cfg80211_get_txpower() - get TX power + * @wiphy: Pointer to wiphy + * @wdev: Pointer to network device + * @dbm: Pointer to TX power in dbm + * + * Return: 0 for success, non-zero for failure + */ +static int __wlan_hdd_cfg80211_get_txpower(struct wiphy *wiphy, + struct wireless_dev *wdev, + int *dbm) +{ + + hdd_context_t *pHddCtx = (hdd_context_t *) wiphy_priv(wiphy); + struct net_device *ndev = wdev->netdev; + hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(ndev); + int status; + + ENTER(); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EINVAL; + } + + status = wlan_hdd_validate_context(pHddCtx); + if (0 != status) { + *dbm = 0; + return status; + } + + /* Validate adapter sessionId */ + if (wlan_hdd_validate_session_id(adapter->sessionId)) { + return -ENOTSUPP; + } + + mutex_lock(&pHddCtx->iface_change_lock); + if (pHddCtx->driver_status != DRIVER_MODULES_ENABLED) { + mutex_unlock(&pHddCtx->iface_change_lock); + hdd_info("Driver Module not enabled return success"); + /* Send cached data to upperlayer*/ + *dbm = adapter->hdd_stats.ClassA_stat.max_pwr; + return 0; + } + mutex_unlock(&pHddCtx->iface_change_lock); + + MTRACE(qdf_trace(QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_CFG80211_GET_TXPOWER, + adapter->sessionId, adapter->device_mode)); + wlan_hdd_get_class_astats(adapter); + *dbm = adapter->hdd_stats.ClassA_stat.max_pwr; + + EXIT(); + return 0; +} + +/** + * wlan_hdd_cfg80211_get_txpower() - cfg80211 get power handler function + * @wiphy: Pointer to wiphy structure. + * @wdev: Pointer to wireless_dev structure. + * @dbm: dbm + * + * This is the cfg80211 get txpower handler function which invokes + * the internal function @__wlan_hdd_cfg80211_get_txpower with + * SSR protection. + * + * Return: 0 for success, error number on failure. + */ +int wlan_hdd_cfg80211_get_txpower(struct wiphy *wiphy, + struct wireless_dev *wdev, + int *dbm) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_get_txpower(wiphy, + wdev, + dbm); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * hdd_set_qpower_config() - set qpower config to firmware + * @adapter: HDD adapter + * @qpower: new qpower config value + * + * Return: 0 on success; Errno on failure + */ +int hdd_set_qpower_config(hdd_context_t *hddctx, hdd_adapter_t *adapter, + u8 qpower) +{ + QDF_STATUS status; + + if (!hddctx->config->enablePowersaveOffload) { + hdd_err("qpower is disabled in configuration"); + return -EINVAL; + } + if (adapter->device_mode != QDF_STA_MODE && + adapter->device_mode != QDF_P2P_CLIENT_MODE) { + hdd_info(FL("QPOWER only allowed in STA/P2P-Client modes:%d "), + adapter->device_mode); + return -EINVAL; + } + + if (qpower > PS_DUTY_CYCLING_QPOWER || + qpower < PS_LEGACY_NODEEPSLEEP) { + hdd_err("invalid qpower value: %d", qpower); + return -EINVAL; + } + + if (hddctx->config->nMaxPsPoll) { + if ((qpower == PS_QPOWER_NODEEPSLEEP) || + (qpower == PS_LEGACY_NODEEPSLEEP)) + qpower = PS_LEGACY_NODEEPSLEEP; + else + qpower = PS_LEGACY_DEEPSLEEP; + hdd_info("Qpower disabled, %d", qpower); + } + status = wma_set_qpower_config(adapter->sessionId, qpower); + if (status != QDF_STATUS_SUCCESS) { + hdd_err("failed to configure qpower: %d", status); + return -EINVAL; + } + + return 0; +} + +#ifdef WLAN_SUSPEND_RESUME_TEST +/* + * On iHelium there are 12 CE irqs and #2 is the wake irq. This may not be + * a valid assumption on future platforms. + */ +#define CE_IRQ_COUNT 12 +#define CE_WAKE_IRQ 2 +static struct net_device *g_dev; +static struct wiphy *g_wiphy; + +#define HDD_FA_SUSPENDED_BIT (0) +static unsigned long fake_apps_state; + +/** + * __hdd_wlan_fake_apps_resume() - The core logic for + * hdd_wlan_fake_apps_resume() skipping the call to hif_fake_apps_resume(), + * which is only need for non-irq resume + * @wiphy: the kernel wiphy struct for the device being resumed + * @dev: the kernel net_device struct for the device being resumed + * + * Return: none, calls QDF_BUG() on failure + */ +static void __hdd_wlan_fake_apps_resume(struct wiphy *wiphy, + struct net_device *dev) +{ + qdf_device_t qdf_dev; + int i, resume_err; + + hdd_info("Unit-test resume WLAN"); + + qdf_dev = cds_get_context(QDF_MODULE_ID_QDF_DEVICE); + if (!qdf_dev) { + hdd_err("Failed to get QDF device context"); + QDF_BUG(0); + return; + } + + if (!test_and_clear_bit(HDD_FA_SUSPENDED_BIT, &fake_apps_state)) { + hdd_info("Not unit-test suspended; Nothing to do"); + return; + } + + /* disable wake irq */ + pld_disable_irq(qdf_dev->dev, CE_WAKE_IRQ); + + resume_err = wlan_hdd_bus_resume_noirq(); + QDF_BUG(resume_err == 0); + + /* simulate kernel enable irqs */ + for (i = 0; i < CE_IRQ_COUNT; i++) + pld_enable_irq(qdf_dev->dev, i); + + resume_err = wlan_hdd_bus_resume(); + QDF_BUG(resume_err == 0); + + resume_err = wlan_hdd_cfg80211_resume_wlan(wiphy); + QDF_BUG(resume_err == 0); + + dev->watchdog_timeo = HDD_TX_TIMEOUT; + + hdd_info("Unit-test resume succeeded"); +} + +/** + * hdd_wlan_fake_apps_resume_irq_callback() - Irq callback function for resuming + * from unit-test initiated suspend from irq wakeup signal + * @val: interrupt val + * + * Resume wlan after getting very 1st CE interrupt from target + * + * Return: none + */ +static void hdd_wlan_fake_apps_resume_irq_callback(uint32_t val) +{ + hdd_info("Trigger unit-test resume WLAN; val: 0x%x", val); + + QDF_BUG(g_wiphy); + QDF_BUG(g_dev); + __hdd_wlan_fake_apps_resume(g_wiphy, g_dev); + g_wiphy = NULL; + g_dev = NULL; +} + +int hdd_wlan_fake_apps_suspend(struct wiphy *wiphy, struct net_device *dev) +{ + qdf_device_t qdf_dev; + struct hif_opaque_softc *hif_ctx; + pm_message_t state; + int i, resume_err, suspend_err; + + hdd_info("Unit-test suspend WLAN"); + + qdf_dev = cds_get_context(QDF_MODULE_ID_QDF_DEVICE); + if (!qdf_dev) { + hdd_err("Failed to get QDF device context"); + return -EINVAL; + } + + hif_ctx = cds_get_context(QDF_MODULE_ID_HIF); + if (!hif_ctx) { + hdd_err("Failed to get HIF context"); + return -EINVAL; + } + + if (test_and_set_bit(HDD_FA_SUSPENDED_BIT, &fake_apps_state)) { + hdd_info("Already unit-test suspended; Nothing to do"); + return 0; + } + + suspend_err = wlan_hdd_cfg80211_suspend_wlan(wiphy, NULL); + if (suspend_err) + goto resume_done; + + state.event = PM_EVENT_SUSPEND; + suspend_err = wlan_hdd_unit_test_bus_suspend(state); + if (suspend_err) + goto cfg80211_resume; + + /* simulate kernel disabling irqs */ + for (i = 0; i < CE_IRQ_COUNT; i++) + pld_disable_irq(qdf_dev->dev, i); + + suspend_err = wlan_hdd_bus_suspend_noirq(); + if (suspend_err) + goto enable_irqs_and_bus_resume; + + /* re-enable wake irq */ + pld_enable_irq(qdf_dev->dev, CE_WAKE_IRQ); + + /* pass wiphy/dev to callback via global variables */ + g_wiphy = wiphy; + g_dev = dev; + hif_fake_apps_suspend(hif_ctx, hdd_wlan_fake_apps_resume_irq_callback); + + /* + * Tell the kernel not to worry if TX queues aren't moving. This is + * expected since we are suspending the wifi hardware, but not APPS + */ + dev->watchdog_timeo = INT_MAX; + + hdd_info("Unit-test suspend succeeded"); + return 0; + +enable_irqs_and_bus_resume: + /* re-enable irqs */ + for (i = 0; i < CE_IRQ_COUNT; i++) + pld_enable_irq(qdf_dev->dev, i); + + resume_err = wlan_hdd_bus_resume(); + QDF_BUG(resume_err == 0); + +cfg80211_resume: + resume_err = wlan_hdd_cfg80211_resume_wlan(wiphy); + QDF_BUG(resume_err == 0); + +resume_done: + clear_bit(HDD_FA_SUSPENDED_BIT, &fake_apps_state); + hdd_err("Unit-test suspend failed: %d", suspend_err); + return suspend_err; +} + +int hdd_wlan_fake_apps_resume(struct wiphy *wiphy, struct net_device *dev) +{ + struct hif_opaque_softc *hif_ctx; + + hif_ctx = cds_get_context(QDF_MODULE_ID_HIF); + if (!hif_ctx) { + hdd_err("Failed to get HIF context"); + return -EINVAL; + } + + hif_fake_apps_resume(hif_ctx); + __hdd_wlan_fake_apps_resume(wiphy, dev); + + return 0; +} +#endif diff --git a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_regulatory.c b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_regulatory.c new file mode 100644 index 0000000000000000000000000000000000000000..f9b9d0dd0a76772ce57264acc80fef2dccb41a8f --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_regulatory.c @@ -0,0 +1,720 @@ +/* + * Copyright (c) 2014-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: wlan_hdd_regulatory.c + * + * hdd regulatory implementation + */ + +#include "qdf_types.h" +#include "qdf_trace.h" +#include "cds_reg_service.h" +#include "cds_regdomain.h" +#include "sme_api.h" +#include "wlan_hdd_main.h" +#include "wlan_hdd_regulatory.h" +#include "pld_common.h" + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) || defined(WITH_BACKPORTS) +#define IEEE80211_CHAN_PASSIVE_SCAN IEEE80211_CHAN_NO_IR +#define IEEE80211_CHAN_NO_IBSS IEEE80211_CHAN_NO_IR +#endif + +#define REG_RULE_2412_2462 REG_RULE(2412-10, 2462+10, 40, 0, 20, 0) + +#define REG_RULE_2467_2472 REG_RULE(2467-10, 2472+10, 40, 0, 20, \ + NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS) + +#define REG_RULE_2484 REG_RULE(2484-10, 2484+10, 20, 0, 20, \ + NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS | \ + NL80211_RRF_NO_OFDM) + +#define REG_RULE_5180_5320 REG_RULE(5180-10, 5320+10, 160, 0, 20, \ + NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS) + +#define REG_RULE_5500_5720 REG_RULE(5500-10, 5720+10, 160, 0, 20, \ + NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS) + +#define REG_RULE_5745_5925 REG_RULE(5745-10, 5925+10, 80, 0, 20, \ + NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS) + +static bool init_by_driver; +static bool init_by_reg_core; + +static const struct ieee80211_regdomain +hdd_world_regrules_60_61_62 = { + .n_reg_rules = 6, + .alpha2 = "00", + .reg_rules = { + REG_RULE_2412_2462, + REG_RULE_2467_2472, + REG_RULE_2484, + REG_RULE_5180_5320, + REG_RULE_5500_5720, + REG_RULE_5745_5925, + } +}; + +static const struct ieee80211_regdomain +hdd_world_regrules_63_65 = { + .n_reg_rules = 4, + .alpha2 = "00", + .reg_rules = { + REG_RULE_2412_2462, + REG_RULE_2467_2472, + REG_RULE_5180_5320, + REG_RULE_5745_5925, + } +}; + +static const struct ieee80211_regdomain +hdd_world_regrules_64 = { + .n_reg_rules = 3, + .alpha2 = "00", + .reg_rules = { + REG_RULE_2412_2462, + REG_RULE_5180_5320, + REG_RULE_5745_5925, + } +}; + +static const struct ieee80211_regdomain +hdd_world_regrules_66_69 = { + .n_reg_rules = 4, + .alpha2 = "00", + .reg_rules = { + REG_RULE_2412_2462, + REG_RULE_5180_5320, + REG_RULE_5500_5720, + REG_RULE_5745_5925, + } +}; + +static const struct ieee80211_regdomain +hdd_world_regrules_67_68_6A_6C = { + .n_reg_rules = 5, + .alpha2 = "00", + .reg_rules = { + REG_RULE_2412_2462, + REG_RULE_2467_2472, + REG_RULE_5180_5320, + REG_RULE_5500_5720, + REG_RULE_5745_5925, + } +}; + +/** + * hdd_get_world_regrules() - get the appropriate world regrules + * @reg: regulatory data + * + * Return: regulatory rules ptr + */ +static const struct ieee80211_regdomain *hdd_get_world_regrules( +struct regulatory *reg) +{ + struct reg_dmn_pair *regpair = + (struct reg_dmn_pair *)reg->regpair; + + switch (regpair->reg_dmn_pair) { + case 0x60: + case 0x61: + case 0x62: + return &hdd_world_regrules_60_61_62; + case 0x63: + case 0x65: + return &hdd_world_regrules_63_65; + case 0x64: + return &hdd_world_regrules_64; + case 0x66: + case 0x69: + return &hdd_world_regrules_66_69; + case 0x67: + case 0x68: + case 0x6A: + case 0x6C: + return &hdd_world_regrules_67_68_6A_6C; + default: + hdd_warn("invalid world mode in BDF"); + return &hdd_world_regrules_60_61_62; + } +} + +/** + * hdd_is_world_regdomain() - whether world regdomain + * @reg_domain: integer regulatory domain + * + * Return: bool + */ +static bool hdd_is_world_regdomain(uint32_t reg_domain) +{ + uint32_t temp_regd = reg_domain & ~WORLD_ROAMING_FLAG; + + return ((temp_regd & CTRY_FLAG) != CTRY_FLAG) && + ((temp_regd & WORLD_ROAMING_MASK) == + WORLD_ROAMING_PREFIX); +} + + +/** + * hdd_update_regulatory_info() - update regulatory info + * @hdd_ctx: hdd context + * + * Return: void + */ +static void hdd_update_regulatory_info(hdd_context_t *hdd_ctx) +{ + uint32_t country_code; + + country_code = cds_get_country_from_alpha2(hdd_ctx->reg.alpha2); + + hdd_ctx->reg.reg_domain = CTRY_FLAG; + hdd_ctx->reg.reg_domain |= country_code; + + cds_fill_some_regulatory_info(&hdd_ctx->reg); + +} + +/** + * hdd_reset_global_reg_params - Reset global static reg params + * + * This function is helpful in static driver to reset + * the global params. + * + * Return: void + */ +void hdd_reset_global_reg_params(void) +{ + init_by_driver = false; + init_by_reg_core = false; +} + +/** + * hdd_regulatory_wiphy_init() - regulatory wiphy init + * @hdd_ctx: hdd context + * @reg: regulatory data + * @wiphy: wiphy structure + * + * Return: void + */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) || defined(WITH_BACKPORTS) +static void hdd_regulatory_wiphy_init(hdd_context_t *hdd_ctx, + struct regulatory *reg, + struct wiphy *wiphy) +{ + const struct ieee80211_regdomain *reg_rules; + int chan_num; + struct ieee80211_channel *chan; + + if (hdd_is_world_regdomain(reg->reg_domain)) { + reg_rules = hdd_get_world_regrules(reg); + wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG; + } else if (hdd_ctx->config->fRegChangeDefCountry) { + wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG; + reg_rules = &hdd_world_regrules_60_61_62; + } else { + wiphy->regulatory_flags |= REGULATORY_STRICT_REG; + reg_rules = &hdd_world_regrules_60_61_62; + } + + /* + * save the original driver regulatory flags + */ + hdd_ctx->reg.reg_flags = wiphy->regulatory_flags; + wiphy_apply_custom_regulatory(wiphy, reg_rules); + + /* + * disable 2.4 Ghz channels that dont have 20 mhz bw + */ + for (chan_num = 0; + chan_num < wiphy->bands[NL80211_BAND_2GHZ]->n_channels; + chan_num++) { + chan = &(wiphy->bands[NL80211_BAND_2GHZ]->channels[chan_num]); + if (chan->flags & IEEE80211_CHAN_NO_20MHZ) + chan->flags |= IEEE80211_CHAN_DISABLED; + } + + /* + * restore the driver regulatory flags since + * wiphy_apply_custom_regulatory may have + * changed them + */ + wiphy->regulatory_flags = hdd_ctx->reg.reg_flags; + +} +#else +static void hdd_regulatory_wiphy_init(hdd_context_t *hdd_ctx, + struct regulatory *reg, + struct wiphy *wiphy) +{ + const struct ieee80211_regdomain *reg_rules; + + if (hdd_is_world_regdomain(reg->reg_domain)) { + reg_rules = hdd_get_world_regrules(reg); + wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY; + } else if (hdd_ctx->config->fRegChangeDefCountry) { + wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY; + reg_rules = &hdd_world_regrules_60_61_62; + } else { + wiphy->flags |= WIPHY_FLAG_STRICT_REGULATORY; + reg_rules = &hdd_world_regrules_60_61_62; + } + + /* + * save the original driver regulatory flags + */ + hdd_ctx->reg.reg_flags = wiphy->flags; + wiphy_apply_custom_regulatory(wiphy, reg_rules); + + /* + * restore the driver regulatory flags since + * wiphy_apply_custom_regulatory may have + * changed them + */ + wiphy->flags = hdd_ctx->reg.reg_flags; + +} +#endif + +/** + * is_wiphy_custom_regulatory() - is custom regulatory defined + * @wiphy: wiphy + * + * Return: int + */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) || defined(WITH_BACKPORTS) +static int is_wiphy_custom_regulatory(struct wiphy *wiphy) +{ + + return wiphy->regulatory_flags & REGULATORY_CUSTOM_REG; +} +#else +static int is_wiphy_custom_regulatory(struct wiphy *wiphy) +{ + return wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY; +} +#endif + + +/** + * hdd_modify_wiphy() - modify wiphy + * @wiphy: wiphy + * @chan: channel structure + * + * Return: void + */ +static void hdd_modify_wiphy(struct wiphy *wiphy, + struct ieee80211_channel *chan) +{ + const struct ieee80211_reg_rule *reg_rule; + + if (is_wiphy_custom_regulatory(wiphy)) { + reg_rule = freq_reg_info(wiphy, MHZ_TO_KHZ(chan->center_freq)); + if (!IS_ERR(reg_rule)) { + chan->flags &= ~IEEE80211_CHAN_DISABLED; + + if (!(reg_rule->flags & NL80211_RRF_DFS)) { + hdd_info("Remove dfs restriction for %u", + chan->center_freq); + chan->flags &= ~IEEE80211_CHAN_RADAR; + } + + if (!(reg_rule->flags & NL80211_RRF_PASSIVE_SCAN)) { + hdd_info("Remove passive restriction for %u", + chan->center_freq); + chan->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN; + } + + if (!(reg_rule->flags & NL80211_RRF_NO_IBSS)) { + hdd_info("Remove no ibss restriction for %u", + chan->center_freq); + chan->flags &= ~IEEE80211_CHAN_NO_IBSS; + } + + chan->max_power = + MBM_TO_DBM(reg_rule->power_rule.max_eirp); + } + } +} + +/** + * hdd_process_regulatory_data() - process regulatory data + * @hdd_ctx: hdd context + * @wiphy: wiphy + * @reset: whether to reset channel data + * + * Return: void + */ +static void hdd_process_regulatory_data(hdd_context_t *hdd_ctx, + struct wiphy *wiphy, + bool reset) +{ + int band_num; + int chan_num; + enum channel_enum chan_enum = CHAN_ENUM_1; + struct ieee80211_channel *wiphy_chan, *wiphy_chan_144 = NULL; + struct regulatory_channel *cds_chan; + uint8_t band_capability; + + band_capability = hdd_ctx->config->nBandCapability; + + for (band_num = 0; band_num < NUM_NL80211_BANDS; band_num++) { + + if (wiphy->bands[band_num] == NULL) + continue; + + for (chan_num = 0; + chan_num < wiphy->bands[band_num]->n_channels && + chan_enum < NUM_CHANNELS; + chan_num++) { + + wiphy_chan = + &(wiphy->bands[band_num]->channels[chan_num]); + cds_chan = &(reg_channels[chan_enum]); + if (CHAN_ENUM_144 == chan_enum) + wiphy_chan_144 = wiphy_chan; + + chan_enum++; + + if (!reset) + hdd_modify_wiphy(wiphy, wiphy_chan); + + if (wiphy_chan->flags & IEEE80211_CHAN_DISABLED) { + cds_chan->state = CHANNEL_STATE_DISABLE; + } else if ((wiphy_chan->flags & + (IEEE80211_CHAN_RADAR | + IEEE80211_CHAN_PASSIVE_SCAN)) || + ((hdd_ctx->config->indoor_channel_support + == false) && + (wiphy_chan->flags & + IEEE80211_CHAN_INDOOR_ONLY))) { + if ((wiphy_chan->flags & + IEEE80211_CHAN_INDOOR_ONLY) && + (false == + hdd_ctx->config->indoor_channel_support)) + wiphy_chan->flags |= + IEEE80211_CHAN_PASSIVE_SCAN; + cds_chan->state = CHANNEL_STATE_DFS; + } else { + cds_chan->state = CHANNEL_STATE_ENABLE; + } + cds_chan->pwr_limit = wiphy_chan->max_power; + cds_chan->flags = wiphy_chan->flags; + + } + } + + if (0 == (hdd_ctx->reg.eeprom_rd_ext & + (1 << WMI_REG_EXT_FCC_CH_144))) { + cds_chan = &(reg_channels[CHAN_ENUM_144]); + cds_chan->state = CHANNEL_STATE_DISABLE; + if (NULL != wiphy_chan_144) + wiphy_chan_144->flags |= IEEE80211_CHAN_DISABLED; + } + + wlan_hdd_cfg80211_update_band(wiphy, band_capability); +} + +/** + * hdd_set_dfs_region() - set the dfs_region + * @dfs_region: the dfs_region to set + * + * Return: void + */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) || defined(WITH_BACKPORTS) +static void hdd_set_dfs_region(hdd_context_t *hdd_ctx, + enum dfs_region dfs_reg) +{ + cds_put_dfs_region(dfs_reg); +} +#else +static void hdd_set_dfs_region(hdd_context_t *hdd_ctx, + enum dfs_region dfs_reg) +{ + + /* remap the ctl code to dfs region code */ + switch (hdd_ctx->reg.ctl_5g) { + case FCC: + cds_put_dfs_region(DFS_FCC_REGION); + break; + case ETSI: + cds_put_dfs_region(DFS_ETSI_REGION); + break; + case MKK: + cds_put_dfs_region(DFS_MKK_REGION); + break; + default: + /* set default dfs_region to FCC */ + cds_put_dfs_region(DFS_FCC_REGION); + break; + } + +} +#endif + + +/** + * hdd_regulatory_init() - regulatory_init + * @hdd_ctx: hdd context + * @wiphy: wiphy + * + * Return: int + */ +int hdd_regulatory_init(hdd_context_t *hdd_ctx, struct wiphy *wiphy) +{ + int ret_val; + struct regulatory *reg_info; + enum dfs_region dfs_reg; + + reg_info = &hdd_ctx->reg; + + ret_val = cds_fill_some_regulatory_info(reg_info); + if (ret_val) { + hdd_err("incorrect BDF regulatory data"); + return ret_val; + } + + hdd_regulatory_wiphy_init(hdd_ctx, reg_info, wiphy); + + hdd_process_regulatory_data(hdd_ctx, wiphy, true); + + reg_info->cc_src = SOURCE_DRIVER; + + cds_put_default_country(reg_info->alpha2); + + cds_fill_and_send_ctl_to_fw(reg_info); + + hdd_set_dfs_region(hdd_ctx, DFS_FCC_REGION); + cds_get_dfs_region(&dfs_reg); + cds_set_wma_dfs_region(dfs_reg); + + return 0; +} + +/** + * hdd_program_country_code() - process channel information from country code + * @hdd_ctx: hddc context + * + * Return: void + */ +void hdd_program_country_code(hdd_context_t *hdd_ctx) +{ + struct wiphy *wiphy = hdd_ctx->wiphy; + uint8_t *country_alpha2 = hdd_ctx->reg.alpha2; + + if (!init_by_reg_core && !init_by_driver) { + init_by_driver = true; + if (('0' != country_alpha2[0]) || + ('0' != country_alpha2[1])) + regulatory_hint(wiphy, country_alpha2); + } +} + + +/** + * hdd_restore_custom_reg_settings() - restore custom reg settings + * @wiphy: wiphy structure + * @country_alpha2: alpha2 of the country + * @reset: whether wiphy is reset + * + * Return: void + */ +#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 14, 0)) || defined(WITH_BACKPORTS) +static void hdd_restore_custom_reg_settings(struct wiphy *wiphy, + uint8_t *country_alpha2, + bool *reset) +{ +} +#else +static void hdd_restore_custom_reg_settings(struct wiphy *wiphy, + uint8_t *country_alpha2, + bool *reset) +{ + struct ieee80211_supported_band *sband; + enum nl80211_band band; + struct ieee80211_channel *chan; + int i; + + if ((country_alpha2[0] == '0') && + (country_alpha2[1] == '0') && + (wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY)) { + + for (band = 0; band < NUM_NL80211_BANDS; band++) { + sband = wiphy->bands[band]; + if (!sband) + continue; + for (i = 0; i < sband->n_channels; i++) { + chan = &sband->channels[i]; + chan->flags = chan->orig_flags; + chan->max_antenna_gain = chan->orig_mag; + chan->max_power = chan->orig_mpwr; + } + } + *reset = true; + } +} +#endif + + +/** + * hdd_restore_reg_flags() - restore regulatory flags + * @flags: regulatory flags + * + * Return: void + */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) || defined(WITH_BACKPORTS) +static void hdd_restore_reg_flags(struct wiphy *wiphy, uint32_t flags) +{ + wiphy->regulatory_flags = flags; +} +#else +static void hdd_restore_reg_flags(struct wiphy *wiphy, uint32_t flags) +{ + wiphy->flags = flags; +} +#endif + + +/** + * hdd_reg_notifier() - regulatory notifier + * @wiphy: wiphy + * @request: regulatory request + * + * Return: void + */ +void hdd_reg_notifier(struct wiphy *wiphy, + struct regulatory_request *request) +{ + hdd_context_t *hdd_ctx = wiphy_priv(wiphy); + bool reset = false; + enum dfs_region dfs_reg; + + hdd_info("country: %c%c, initiator %d, dfs_region: %d", + request->alpha2[0], + request->alpha2[1], + request->initiator, + request->dfs_region); + + if (NULL == hdd_ctx) { + hdd_err("invalid hdd_ctx pointer"); + return; + } + + if (cds_is_driver_unloading() || cds_is_driver_recovering()) { + hdd_err("%s: unloading or ssr in progress, ignore", + __func__); + return; + } + + if (hdd_ctx->driver_status == DRIVER_MODULES_CLOSED) { + hdd_err("Driver module is closed; dropping request"); + return; + } + + if (hdd_ctx->isWiphySuspended == true) { + hdd_err("%s: system/cfg80211 is already suspend", __func__); + return; + } + + if (('K' == request->alpha2[0]) && + ('R' == request->alpha2[1])) + request->dfs_region = DFS_KR_REGION; + + if (('C' == request->alpha2[0]) && + ('N' == request->alpha2[1])) + request->dfs_region = DFS_CN_REGION; + + /* first check if this callback is in response to the driver callback */ + + switch (request->initiator) { + case NL80211_REGDOM_SET_BY_DRIVER: + case NL80211_REGDOM_SET_BY_CORE: + case NL80211_REGDOM_SET_BY_USER: + + if ((false == init_by_driver) && + (false == init_by_reg_core)) { + /* callback during wiphy registration */ + + if ((NL80211_REGDOM_SET_BY_CORE == + request->initiator) && + (pld_get_driver_load_cnt( + + /* first time load there is + * always a default 00 cbk + */ + hdd_ctx->parent_dev) == 0)) + return; + init_by_reg_core = true; + } + + if ((NL80211_REGDOM_SET_BY_DRIVER == request->initiator) && + (true == init_by_driver)) { + + /* + * restore the driver regulatory flags since + * regulatory_hint may have + * changed them + */ + hdd_restore_reg_flags(wiphy, hdd_ctx->reg.reg_flags); + } + + if (NL80211_REGDOM_SET_BY_CORE == request->initiator) { + hdd_ctx->reg.cc_src = SOURCE_CORE; + if (is_wiphy_custom_regulatory(wiphy)) + reset = true; + } else if (NL80211_REGDOM_SET_BY_DRIVER == request->initiator) { + hdd_ctx->reg.cc_src = SOURCE_DRIVER; + sme_set_cc_src(hdd_ctx->hHal, SOURCE_DRIVER); + } else { + hdd_ctx->reg.cc_src = SOURCE_USERSPACE; + hdd_restore_custom_reg_settings(wiphy, + request->alpha2, + &reset); + } + + hdd_ctx->reg.alpha2[0] = request->alpha2[0]; + hdd_ctx->reg.alpha2[1] = request->alpha2[1]; + + hdd_update_regulatory_info(hdd_ctx); + + hdd_process_regulatory_data(hdd_ctx, wiphy, reset); + + sme_generic_change_country_code(hdd_ctx->hHal, + hdd_ctx->reg.alpha2); + + cds_fill_and_send_ctl_to_fw(&hdd_ctx->reg); + + hdd_set_dfs_region(hdd_ctx, request->dfs_region); + + cds_get_dfs_region(&dfs_reg); + cds_set_wma_dfs_region(dfs_reg); + break; + + default: + break; + } +} diff --git a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_scan.c b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_scan.c new file mode 100644 index 0000000000000000000000000000000000000000..e9218cd9070bd18164b0c513c4f2c20f702e309d --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_scan.c @@ -0,0 +1,3343 @@ +/* + * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: wlan_hdd_scan.c + * + * WLAN Host Device Driver scan implementation + */ + +#include +#include + +#include "wlan_hdd_includes.h" +#include "cds_api.h" +#include "cds_api.h" +#include "ani_global.h" +#include "dot11f.h" +#include "cds_sched.h" +#include "wlan_hdd_p2p.h" +#include "wlan_hdd_trace.h" +#include "wlan_hdd_scan.h" +#include "cds_concurrency.h" +#include "wma_api.h" +#include "cds_utils.h" + +#define MAX_RATES 12 +#define HDD_WAKE_LOCK_SCAN_DURATION (5 * 1000) /* in msec */ + +#define SCAN_DONE_EVENT_BUF_SIZE 4096 +#define RATE_MASK 0x7f + +/** + * typedef tSSIDBcastType - SSID broadcast type + * @eBCAST_UNKNOWN: Broadcast unknown + * @eBCAST_NORMAL: Broadcast normal + * @eBCAST_HIDDEN: Broadcast hidden + */ +typedef enum eSSIDBcastType { + eBCAST_UNKNOWN = 0, + eBCAST_NORMAL = 1, + eBCAST_HIDDEN = 2, +} tSSIDBcastType; + + +/** + * typedef hdd_scan_info_t - HDD scan info + * @dev: Pointer to net device + * @info: Pointer to request info + * @start: Start pointer + * @end: End pointer + */ +typedef struct hdd_scan_info { + struct net_device *dev; + struct iw_request_info *info; + char *start; + char *end; +} hdd_scan_info_t, *hdd_scan_info_tp; + +static const +struct nla_policy scan_policy[QCA_WLAN_VENDOR_ATTR_SCAN_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_SCAN_FLAGS] = {.type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_SCAN_TX_NO_CCK_RATE] = {.type = NLA_FLAG}, + [QCA_WLAN_VENDOR_ATTR_SCAN_COOKIE] = {.type = NLA_U64}, +}; + +/** + * hdd_translate_abg_rate_to_mbps_rate() - translate abg rate to Mbps rate + * @pFcRate: Rate pointer + * + * Return: Mbps rate in integer + */ +static int32_t hdd_translate_abg_rate_to_mbps_rate(uint8_t *pFcRate) +{ + /* Slightly more sophisticated processing has to take place here. + * Basic rates are rounded DOWN. HT rates are rounded UP + */ + return ((((int32_t) *pFcRate) & 0x007f) * 1000000) / 2; +} + +/** + * hdd_add_iw_stream_event() - add iw stream event + * @cmd: Command + * @length: Length + * @data: Pointer to data + * @pscanInfo: Pointer to scan info + * @last_event: Pointer to pointer to last event + * @current_event: Pointer to pointer to current event + * + * Return: 0 for success, non zero for failure + */ +static int hdd_add_iw_stream_event(int cmd, int length, char *data, + hdd_scan_info_t *pscanInfo, + char **last_event, + char **current_event) +{ + struct iw_event event; + + *last_event = *current_event; + qdf_mem_zero(&event, sizeof(struct iw_event)); + event.cmd = cmd; + event.u.data.flags = 1; + event.u.data.length = length; + *current_event = + iwe_stream_add_point(pscanInfo->info, *current_event, + pscanInfo->end, &event, data); + + if (*last_event == *current_event) { + /* no space to add event */ + hdd_err("no space left to add event"); + return -E2BIG; /* Error code, may be E2BIG */ + } + + return 0; +} + +/** + * hdd_get_wparsn_ies() - get wpa RSN IEs + * @ieFields: Pointer to the Bss Descriptor IEs + * @ie_length: IE Length + * @last_event: Points to last event + * @current_event: Points to current event + * + * This function extract the WPA/RSN IE from the Bss descriptor IEs fields + * + * Return: 0 for success, non zero for failure + */ +static int hdd_get_wparsn_ies(uint8_t *ieFields, uint16_t ie_length, + char **last_event, char **current_event, + hdd_scan_info_t *pscanInfo) +{ + uint8_t eid, elen, *element; + uint16_t tie_length = 0; + + ENTER(); + + element = ieFields; + tie_length = ie_length; + + while (tie_length > 2 && element != NULL) { + eid = element[0]; + elen = element[1]; + + /* If element length is greater than total remaining ie length, + * break the loop + */ + if ((elen + 2) > tie_length) + break; + + switch (eid) { + case DOT11F_EID_WPA: + case DOT11F_EID_RSN: +#ifdef FEATURE_WLAN_WAPI + case DOT11F_EID_WAPI: +#endif + if (hdd_add_iw_stream_event + (IWEVGENIE, elen + 2, (char *)element, pscanInfo, + last_event, current_event) < 0) + return -E2BIG; + break; + + default: + break; + } + + /* Next element */ + tie_length -= (2 + elen); + element += 2 + elen; + } + + return 0; +} + +/** + * hdd_indicate_scan_result() - indicate scan results + * @scanInfo: Pointer to the scan info structure. + * @descriptor: Pointer to the Bss Descriptor. + * + * This function returns the scan results to the wpa_supplicant + * + * @Return: 0 for success, non zero for failure + */ +#define MAX_CUSTOM_LEN 64 +static int hdd_indicate_scan_result(hdd_scan_info_t *scanInfo, + tCsrScanResultInfo *scan_result) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(scanInfo->dev); + tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter); + tSirBssDescription *descriptor = &scan_result->BssDescriptor; + struct iw_event event; + char *current_event = scanInfo->start; + char *end = scanInfo->end; + char *last_event; + char *current_pad; + uint16_t ie_length = 0; + uint16_t capabilityInfo; + char *modestr; + int error; + char custom[MAX_CUSTOM_LEN]; + char *p; + + hdd_notice(MAC_ADDRESS_STR, MAC_ADDR_ARRAY(descriptor->bssId)); + + error = 0; + last_event = current_event; + qdf_mem_zero(&event, sizeof(event)); + + /* BSSID */ + event.cmd = SIOCGIWAP; + event.u.ap_addr.sa_family = ARPHRD_ETHER; + qdf_mem_copy(event.u.ap_addr.sa_data, descriptor->bssId, + sizeof(descriptor->bssId)); + current_event = iwe_stream_add_event(scanInfo->info, current_event, end, + &event, IW_EV_ADDR_LEN); + + if (last_event == current_event) { + /* no space to add event */ + /* Error code may be E2BIG */ + hdd_err("no space for SIOCGIWAP"); + return -E2BIG; + } + + last_event = current_event; + qdf_mem_zero(&event, sizeof(struct iw_event)); + + /* Protocol Name */ + event.cmd = SIOCGIWNAME; + + switch (descriptor->nwType) { + case eSIR_11A_NW_TYPE: + modestr = "a"; + break; + case eSIR_11B_NW_TYPE: + modestr = "b"; + break; + case eSIR_11G_NW_TYPE: + modestr = "g"; + break; + case eSIR_11N_NW_TYPE: + modestr = "n"; + break; + default: + hdd_warn("Unknown network type [%d]", descriptor->nwType); + modestr = "?"; + break; + } + snprintf(event.u.name, IFNAMSIZ, "IEEE 802.11%s", modestr); + current_event = iwe_stream_add_event(scanInfo->info, current_event, end, + &event, IW_EV_CHAR_LEN); + + if (last_event == current_event) { /* no space to add event */ + hdd_err("no space for SIOCGIWNAME"); + /* Error code, may be E2BIG */ + return -E2BIG; + } + + last_event = current_event; + qdf_mem_zero(&event, sizeof(struct iw_event)); + + /*Freq */ + event.cmd = SIOCGIWFREQ; + + event.u.freq.m = descriptor->channelId; + event.u.freq.e = 0; + event.u.freq.i = 0; + current_event = iwe_stream_add_event(scanInfo->info, current_event, end, + &event, IW_EV_FREQ_LEN); + + if (last_event == current_event) { /* no space to add event */ + hdd_err("no space for SIOCGIWFREQ"); + return -E2BIG; + } + + last_event = current_event; + qdf_mem_zero(&event, sizeof(struct iw_event)); + + /* BSS Mode */ + event.cmd = SIOCGIWMODE; + + capabilityInfo = descriptor->capabilityInfo; + + if (SIR_MAC_GET_ESS(capabilityInfo)) { + event.u.mode = IW_MODE_MASTER; + } else if (SIR_MAC_GET_IBSS(capabilityInfo)) { + event.u.mode = IW_MODE_ADHOC; + } else { + /* neither ESS or IBSS */ + event.u.mode = IW_MODE_AUTO; + } + + current_event = iwe_stream_add_event(scanInfo->info, current_event, end, + &event, IW_EV_UINT_LEN); + + if (last_event == current_event) { /* no space to add event */ + hdd_err("no space for SIOCGIWMODE"); + return -E2BIG; + } + /* To extract SSID */ + ie_length = GET_IE_LEN_IN_BSS(descriptor->length); + + if (ie_length > 0) { + /* dot11BeaconIEs is a large struct, so we make it static to + avoid stack overflow. This API is only invoked via ioctl, + so it is serialized by the kernel rtnl_lock and hence does + not need to be reentrant */ + static tDot11fBeaconIEs dot11BeaconIEs; + tDot11fIESSID *pDot11SSID; + tDot11fIESuppRates *pDot11SuppRates; + tDot11fIEExtSuppRates *pDot11ExtSuppRates; + tDot11fIEHTCaps *pDot11IEHTCaps; + int numBasicRates = 0; + int maxNumRates = 0; + + pDot11IEHTCaps = NULL; + + dot11f_unpack_beacon_i_es((tpAniSirGlobal) + hHal, (uint8_t *) descriptor->ieFields, + ie_length, &dot11BeaconIEs); + + pDot11SSID = &dot11BeaconIEs.SSID; + + if (pDot11SSID->present) { + last_event = current_event; + qdf_mem_zero(&event, sizeof(struct iw_event)); + + event.cmd = SIOCGIWESSID; + event.u.data.flags = 1; + event.u.data.length = scan_result->ssId.length; + current_event = + iwe_stream_add_point(scanInfo->info, current_event, + end, &event, + (char *)scan_result->ssId. + ssId); + + if (last_event == current_event) { /* no space to add event */ + hdd_err("no space for SIOCGIWESSID"); + return -E2BIG; + } + } + + if (hdd_get_wparsn_ies + ((uint8_t *) descriptor->ieFields, ie_length, &last_event, + ¤t_event, scanInfo) < 0) { + hdd_err("no space for SIOCGIWESSID"); + return -E2BIG; + } + + last_event = current_event; + current_pad = current_event + IW_EV_LCP_LEN; + qdf_mem_zero(&event, sizeof(struct iw_event)); + + /*Rates */ + event.cmd = SIOCGIWRATE; + + pDot11SuppRates = &dot11BeaconIEs.SuppRates; + + if (pDot11SuppRates->present) { + int i; + + numBasicRates = pDot11SuppRates->num_rates; + for (i = 0; i < pDot11SuppRates->num_rates; i++) { + if (0 != (pDot11SuppRates->rates[i] & 0x7F)) { + event.u.bitrate.value = + hdd_translate_abg_rate_to_mbps_rate + (&pDot11SuppRates->rates[i]); + + current_pad = + iwe_stream_add_value(scanInfo->info, + current_event, + current_pad, + end, &event, + IW_EV_PARAM_LEN); + } + } + + } + + pDot11ExtSuppRates = &dot11BeaconIEs.ExtSuppRates; + + if (pDot11ExtSuppRates->present) { + int i, no_of_rates; + maxNumRates = + numBasicRates + pDot11ExtSuppRates->num_rates; + + /* Check to make sure the total number of rates + * doesn't exceed IW_MAX_BITRATES + */ + + maxNumRates = QDF_MIN(maxNumRates, IW_MAX_BITRATES); + + if ((maxNumRates - numBasicRates) > MAX_RATES) { + no_of_rates = MAX_RATES; + hdd_warn("Accessing array out of bound that array is pDot11ExtSuppRates->rates "); + } else { + no_of_rates = maxNumRates - numBasicRates; + } + for (i = 0; i < no_of_rates; i++) { + if (0 != (pDot11ExtSuppRates->rates[i] & 0x7F)) { + event.u.bitrate.value = + hdd_translate_abg_rate_to_mbps_rate + (&pDot11ExtSuppRates->rates[i]); + + current_pad = + iwe_stream_add_value(scanInfo->info, + current_event, + current_pad, + end, &event, + IW_EV_PARAM_LEN); + } + } + } + + if ((current_pad - current_event) >= IW_EV_LCP_LEN) { + current_event = current_pad; + } else { + if (last_event == current_event) { /* no space to add event */ + hdd_err("no space for SIOCGIWRATE"); + return -E2BIG; + } + } + + last_event = current_event; + qdf_mem_zero(&event, sizeof(struct iw_event)); + + event.cmd = SIOCGIWENCODE; + + if (SIR_MAC_GET_PRIVACY(capabilityInfo)) { + event.u.data.flags = + IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; + } else { + event.u.data.flags = IW_ENCODE_DISABLED; + } + event.u.data.length = 0; + + current_event = + iwe_stream_add_point(scanInfo->info, current_event, end, + &event, (char *)pDot11SSID->ssid); + if (last_event == current_event) { + hdd_err("no space for SIOCGIWENCODE"); + return -E2BIG; + } + } + + last_event = current_event; + qdf_mem_zero(&event, sizeof(struct iw_event)); + + /* RSSI */ + event.cmd = IWEVQUAL; + event.u.qual.qual = descriptor->rssi; + event.u.qual.noise = descriptor->sinr; + event.u.qual.level = QDF_MIN((descriptor->rssi + descriptor->sinr), 0); + + event.u.qual.updated = IW_QUAL_ALL_UPDATED; + + current_event = iwe_stream_add_event(scanInfo->info, current_event, + end, &event, IW_EV_QUAL_LEN); + + if (last_event == current_event) { /* no space to add event */ + hdd_err("no space for IWEVQUAL"); + return -E2BIG; + } + + /* AGE */ + event.cmd = IWEVCUSTOM; + p = custom; + p += scnprintf(p, MAX_CUSTOM_LEN, " Age: %llu", + qdf_mc_timer_get_system_time() - + descriptor->received_time); + event.u.data.length = p - custom; + current_event = iwe_stream_add_point(scanInfo->info, current_event, end, + &event, custom); + if (last_event == current_event) { /* no space to add event */ + hdd_err("no space for IWEVCUSTOM (age)"); + return -E2BIG; + } + + scanInfo->start = current_event; + + return 0; +} + +/** + * wlan_hdd_is_scan_pending() - Utility function to check pending scans + * @adapter: Pointer to the adapter + * + * Utility function to check pending scans on a particular adapter + * + * Return: true if scans are pending, false otherwise + */ +static bool wlan_hdd_is_scan_pending(hdd_adapter_t *adapter) +{ + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + qdf_list_node_t *pnode = NULL, *ppnode = NULL; + struct hdd_scan_req *hdd_scan_req; + + qdf_spin_lock(&hdd_ctx->hdd_scan_req_q_lock); + + if (qdf_list_empty(&hdd_ctx->hdd_scan_req_q)) { + qdf_spin_unlock(&hdd_ctx->hdd_scan_req_q_lock); + return false; + } + + if (QDF_STATUS_SUCCESS != qdf_list_peek_front(&hdd_ctx->hdd_scan_req_q, + &ppnode)) { + qdf_spin_unlock(&hdd_ctx->hdd_scan_req_q_lock); + hdd_err("Failed to remove Scan Req from queue"); + return false; + } + + do { + pnode = ppnode; + hdd_scan_req = (struct hdd_scan_req *)pnode; + /* Any scan pending on the adapter */ + if (adapter == hdd_scan_req->adapter) { + qdf_spin_unlock(&hdd_ctx->hdd_scan_req_q_lock); + hdd_info("pending scan id %d", hdd_scan_req->scan_id); + return true; + } + } while (QDF_STATUS_SUCCESS == + qdf_list_peek_next(&hdd_ctx->hdd_scan_req_q, pnode, &ppnode)); + + qdf_spin_unlock(&hdd_ctx->hdd_scan_req_q_lock); + return false; +} + +/** + * wlan_hdd_scan_request_enqueue() - enqueue Scan Request + * @adapter: Pointer to the adapter + * @scan_req: Pointer to the scan request + * + * Enqueue scan request in the global HDD scan list.This list + * stores the active scan request information. + * + * Return: 0 on success, error number otherwise + */ +static int wlan_hdd_scan_request_enqueue(hdd_adapter_t *adapter, + struct cfg80211_scan_request *scan_req, + uint8_t source, uint32_t scan_id, + uint32_t timestamp) +{ + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + struct hdd_scan_req *hdd_scan_req; + QDF_STATUS status; + + ENTER(); + hdd_scan_req = qdf_mem_malloc(sizeof(*hdd_scan_req)); + if (NULL == hdd_scan_req) { + hdd_alert("malloc failed for Scan req"); + return -ENOMEM; + } + + hdd_scan_req->adapter = adapter; + hdd_scan_req->scan_request = scan_req; + hdd_scan_req->source = source; + hdd_scan_req->scan_id = scan_id; + hdd_scan_req->timestamp = timestamp; + + qdf_spin_lock(&hdd_ctx->hdd_scan_req_q_lock); + status = qdf_list_insert_back(&hdd_ctx->hdd_scan_req_q, + &hdd_scan_req->node); + qdf_spin_unlock(&hdd_ctx->hdd_scan_req_q_lock); + + if (QDF_STATUS_SUCCESS != status) { + hdd_err("Failed to enqueue Scan Req"); + qdf_mem_free(hdd_scan_req); + return -EINVAL; + } + EXIT(); + return 0; +} + +/** + * wlan_hdd_scan_request_dequeue() - dequeue scan request + * @hdd_ctx: Global HDD context + * @scan_id: scan id + * @req: scan request + * @source : returns source of the scan request + * @timestamp: scan request timestamp + * + * Return: QDF_STATUS + */ +static QDF_STATUS wlan_hdd_scan_request_dequeue(hdd_context_t *hdd_ctx, + uint32_t scan_id, struct cfg80211_scan_request **req, uint8_t *source, + uint32_t *timestamp) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + struct hdd_scan_req *hdd_scan_req; + qdf_list_node_t *pNode = NULL, *ppNode = NULL; + + hdd_info("Dequeue Scan id: %d", scan_id); + + if ((source == NULL) || (timestamp == NULL) || (req == NULL)) + return QDF_STATUS_E_NULL_VALUE; + + qdf_spin_lock(&hdd_ctx->hdd_scan_req_q_lock); + + if (list_empty(&hdd_ctx->hdd_scan_req_q.anchor)) { + qdf_spin_unlock(&hdd_ctx->hdd_scan_req_q_lock); + return QDF_STATUS_E_FAILURE; + } + + if (QDF_STATUS_SUCCESS != + qdf_list_peek_front(&hdd_ctx->hdd_scan_req_q, &ppNode)) { + qdf_spin_unlock(&hdd_ctx->hdd_scan_req_q_lock); + hdd_err("Failed to remove Scan Req from queue"); + return QDF_STATUS_E_FAILURE; + } + + do { + pNode = ppNode; + hdd_scan_req = (struct hdd_scan_req *)pNode; + if (hdd_scan_req->scan_id == scan_id) { + status = qdf_list_remove_node(&hdd_ctx->hdd_scan_req_q, + pNode); + if (status == QDF_STATUS_SUCCESS) { + *req = hdd_scan_req->scan_request; + *source = hdd_scan_req->source; + *timestamp = hdd_scan_req->timestamp; + qdf_mem_free(hdd_scan_req); + qdf_spin_unlock(&hdd_ctx->hdd_scan_req_q_lock); + hdd_info("removed Scan id: %d, req = %p, pending scans %d", + scan_id, req, + qdf_list_size(&hdd_ctx->hdd_scan_req_q)); + return QDF_STATUS_SUCCESS; + } else { + qdf_spin_unlock(&hdd_ctx->hdd_scan_req_q_lock); + hdd_err("Failed to remove node scan id %d, pending scans %d", + scan_id, + qdf_list_size(&hdd_ctx->hdd_scan_req_q)); + return status; + } + } + } while (QDF_STATUS_SUCCESS == + qdf_list_peek_next(&hdd_ctx->hdd_scan_req_q, pNode, &ppNode)); + + qdf_spin_unlock(&hdd_ctx->hdd_scan_req_q_lock); + hdd_err("Failed to find scan id %d", scan_id); + return status; +} + +/** + * hdd_scan_request_callback() - scan complete callback from SME + * @halHandle: Pointer to the Hal Handle + * @pContext: Pointer to the data context + * @sessionId: Session identifier + * @scanId: Scan ID + * @status: CSR Status + * + * The sme module calls this callback function once it finish the scan request + * and this function notifies the scan complete event to the wpa_supplicant. + * + * Return: 0 for success, non zero for failure + */ + +static QDF_STATUS +hdd_scan_request_callback(tHalHandle halHandle, void *pContext, + uint8_t sessionId, uint32_t scanId, + eCsrScanStatus status) +{ + struct net_device *dev = (struct net_device *)pContext; + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *hddctx = WLAN_HDD_GET_CTX(pAdapter); + union iwreq_data wrqu; + int we_event; + char *msg; + uint8_t source; + struct cfg80211_scan_request *req; + uint32_t timestamp; + + ENTER(); + hdd_warn("called with halHandle = %p, pContext = %p, scanID = %d, returned status = %d", + halHandle, pContext, (int)scanId, (int)status); + + /* if there is a scan request pending when the wlan driver is unloaded + * we may be invoked as SME flushes its pending queue. If that is the + * case, the underlying net_device may have already been destroyed, so + * do some quick sanity before proceeding + */ + if (pAdapter->dev != dev) { + hdd_warn("device mismatch %p vs %p", pAdapter->dev, dev); + return QDF_STATUS_SUCCESS; + } + + wlan_hdd_scan_request_dequeue(hddctx, scanId, &req, &source, + ×tamp); + + if (req != NULL) + hdd_err("Got unexpected request struct for Scan id %d", + scanId); + + /* Scan is no longer pending */ + if (!wlan_hdd_is_scan_pending(pAdapter)) + pAdapter->scan_info.mScanPending = false; + + /* notify any applications that may be interested */ + memset(&wrqu, '\0', sizeof(wrqu)); + we_event = SIOCGIWSCAN; + msg = NULL; + wireless_send_event(dev, we_event, &wrqu, msg); + + EXIT(); + return QDF_STATUS_SUCCESS; +} + +/** + * __iw_set_scan() - set scan request + * @dev: Pointer to the net device + * @info: Pointer to the iw_request_info + * @wrqu: Pointer to the iwreq_data + * @extra: Pointer to the data + * + * This function process the scan request from the wpa_supplicant + * and set the scan request to the SME + * + * Return: 0 for success, non zero for failure + */ + +static int __iw_set_scan(struct net_device *dev, struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(pAdapter); + hdd_wext_state_t *pwextBuf = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter); + tCsrScanRequest scanRequest; + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct iw_scan_req *scanReq = (struct iw_scan_req *)extra; + hdd_adapter_t *con_sap_adapter; + uint16_t con_dfs_ch; + int ret; + + ENTER_DEV(dev); + + hdd_ctx = WLAN_HDD_GET_CTX(pAdapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + /* Block All Scan during DFS operation and send null scan result */ + con_sap_adapter = hdd_get_con_sap_adapter(pAdapter, true); + if (con_sap_adapter) { + con_dfs_ch = con_sap_adapter->sessionCtx.ap.operatingChannel; + + if (CDS_IS_DFS_CH(con_dfs_ch)) { + hdd_warn("##In DFS Master mode. Scan aborted"); + return -EOPNOTSUPP; + } + } + + qdf_mem_zero(&scanRequest, sizeof(scanRequest)); + + if (NULL != wrqu->data.pointer) { + /* set scanType, active or passive */ + if ((IW_SCAN_TYPE_ACTIVE == scanReq->scan_type) || + (eSIR_ACTIVE_SCAN == hdd_ctx->ioctl_scan_mode)) { + scanRequest.scanType = eSIR_ACTIVE_SCAN; + } else { + scanRequest.scanType = eSIR_PASSIVE_SCAN; + } + + /* set bssid using sockaddr from iw_scan_req */ + qdf_mem_copy(scanRequest.bssid.bytes, + &scanReq->bssid.sa_data, + QDF_MAC_ADDR_SIZE); + + if (wrqu->data.flags & IW_SCAN_THIS_ESSID) { + + if (scanReq->essid_len && + (scanReq->essid_len <= SIR_MAC_MAX_SSID_LENGTH)) { + scanRequest.SSIDs.numOfSSIDs = 1; + scanRequest.SSIDs.SSIDList = + (tCsrSSIDInfo *) + qdf_mem_malloc(sizeof(tCsrSSIDInfo)); + if (scanRequest.SSIDs.SSIDList) { + scanRequest.SSIDs.SSIDList->SSID. + length = scanReq->essid_len; + qdf_mem_copy(scanRequest.SSIDs. + SSIDList->SSID.ssId, + scanReq->essid, + scanReq->essid_len); + } else { + scanRequest.SSIDs.numOfSSIDs = 0; + hdd_err("Unable to allocate memory"); + QDF_ASSERT(0); + } + } else { + hdd_err("Invalid essid length : %d", + scanReq->essid_len); + } + } + + /* set min and max channel time */ + scanRequest.minChnTime = scanReq->min_channel_time; + scanRequest.maxChnTime = scanReq->max_channel_time; + + } else { + if (hdd_ctx->ioctl_scan_mode == eSIR_ACTIVE_SCAN) { + /* set the scan type to active */ + scanRequest.scanType = eSIR_ACTIVE_SCAN; + } else { + scanRequest.scanType = eSIR_PASSIVE_SCAN; + } + + qdf_set_macaddr_broadcast(&scanRequest.bssid); + + /* set min and max channel time to zero */ + scanRequest.minChnTime = 0; + scanRequest.maxChnTime = 0; + } + + /* set BSSType to default type */ + scanRequest.BSSType = eCSR_BSS_TYPE_ANY; + + /*Scan all the channels */ + scanRequest.ChannelInfo.numOfChannels = 0; + + scanRequest.ChannelInfo.ChannelList = NULL; + + /* set requestType to full scan */ + scanRequest.requestType = eCSR_SCAN_REQUEST_FULL_SCAN; + + /* if previous genIE is not NULL, update ScanIE */ + if (0 != pwextBuf->genIE.length) { + memset(&pAdapter->scan_info.scanAddIE, 0, + sizeof(pAdapter->scan_info.scanAddIE)); + memcpy(pAdapter->scan_info.scanAddIE.addIEdata, + pwextBuf->genIE.addIEdata, pwextBuf->genIE.length); + pAdapter->scan_info.scanAddIE.length = pwextBuf->genIE.length; + + pwextBuf->roamProfile.pAddIEScan = + pAdapter->scan_info.scanAddIE.addIEdata; + pwextBuf->roamProfile.nAddIEScanLength = + pAdapter->scan_info.scanAddIE.length; + + /* clear previous genIE after use it */ + memset(&pwextBuf->genIE, 0, sizeof(pwextBuf->genIE)); + } + + /* push addIEScan in scanRequset if exist */ + if (pAdapter->scan_info.scanAddIE.length && + pAdapter->scan_info.scanAddIE.length <= + sizeof(pAdapter->scan_info.scanAddIE.addIEdata)) { + scanRequest.uIEFieldLen = pAdapter->scan_info.scanAddIE.length; + scanRequest.pIEField = pAdapter->scan_info.scanAddIE.addIEdata; + } + scanRequest.timestamp = qdf_mc_timer_get_system_time(); + status = sme_scan_request((WLAN_HDD_GET_CTX(pAdapter))->hHal, + pAdapter->sessionId, &scanRequest, + &hdd_scan_request_callback, dev); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_alert("sme_scan_request fail %d!!!", status); + goto error; + } + + wlan_hdd_scan_request_enqueue(pAdapter, NULL, NL_SCAN, + scanRequest.scan_id, + scanRequest.timestamp); + + pAdapter->scan_info.mScanPending = true; +error: + if ((wrqu->data.flags & IW_SCAN_THIS_ESSID) && (scanReq->essid_len)) + qdf_mem_free(scanRequest.SSIDs.SSIDList); + EXIT(); + return status; +} + +/** + * iw_set_scan() - SSR wrapper for __iw_set_scan + * @dev: Pointer to the net device. + * @info: Pointer to the iw_request_info. + * @wrqu: Pointer to the iwreq_data. + * @extra: Pointer to the data. + * + * Return: 0 on success, error number otherwise + */ +int iw_set_scan(struct net_device *dev, struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_set_scan(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __iw_get_scan() - get scan + * @dev: Pointer to the net device. + * @info: Pointer to the iw_request_info. + * @wrqu: Pointer to the iwreq_data. + * @extra: Pointer to the data. + * + * This function returns the scan results to the wpa_supplicant + * + * Return: 0 for success, non zero for failure + */ + +static int __iw_get_scan(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *hdd_ctx; + tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter); + tCsrScanResultInfo *pScanResult; + QDF_STATUS status = QDF_STATUS_SUCCESS; + hdd_scan_info_t scanInfo; + tScanResultHandle pResult; + int i = 0; + int ret; + + ENTER_DEV(dev); + + hdd_ctx = WLAN_HDD_GET_CTX(pAdapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + hdd_notice("enter buffer length %d!!!", + (wrqu->data.length) ? wrqu->data.length : IW_SCAN_MAX_DATA); + + if (true == pAdapter->scan_info.mScanPending) { + hdd_alert("mScanPending is true !!!"); + return -EAGAIN; + } + + scanInfo.dev = dev; + scanInfo.start = extra; + scanInfo.info = info; + + if (0 == wrqu->data.length) { + scanInfo.end = extra + IW_SCAN_MAX_DATA; + } else { + scanInfo.end = extra + wrqu->data.length; + } + + status = sme_scan_get_result(hHal, pAdapter->sessionId, NULL, &pResult); + + if (NULL == pResult) { + /* no scan results */ + hdd_notice("iw_get_scan: NULL Scan Result "); + return 0; + } + + pScanResult = sme_scan_result_get_first(hHal, pResult); + + while (pScanResult) { + status = hdd_indicate_scan_result(&scanInfo, pScanResult); + if (0 != status) { + break; + } + i++; + pScanResult = sme_scan_result_get_next(hHal, pResult); + } + + sme_scan_result_purge(hHal, pResult); + + hdd_notice("exit total %d BSS reported !!!", i); + EXIT(); + return status; +} + +/** + * iw_get_scan() - SSR wrapper function for __iw_get_scan + * @dev: Pointer to the net device. + * @info: Pointer to the iw_request_info. + * @wrqu: Pointer to the iwreq_data. + * @extra: Pointer to the data. + * + * Return: 0 on success, error number otherwise + */ +int iw_get_scan(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_get_scan(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * hdd_abort_mac_scan() - aborts ongoing mac scan + * @pHddCtx: Pointer to hdd context + * @sessionId: session id + * @scan_id: scan id + * @reason: abort reason + * + * Abort any MAC scan if in progress + * + * Return: none + */ +void hdd_abort_mac_scan(hdd_context_t *pHddCtx, uint8_t sessionId, + uint32_t scan_id, eCsrAbortReason reason) +{ + sme_abort_mac_scan(pHddCtx->hHal, sessionId, scan_id, reason); +} + +/** + * hdd_vendor_scan_callback() - Scan completed callback event + * @hddctx: HDD context + * @req : Scan request + * @aborted : true scan aborted false scan success + * + * This function sends scan completed callback event to NL. + * + * Return: none + */ +static void hdd_vendor_scan_callback(hdd_adapter_t *adapter, + struct cfg80211_scan_request *req, + bool aborted) +{ + hdd_context_t *hddctx = WLAN_HDD_GET_CTX(adapter); + struct sk_buff *skb; + struct nlattr *attr; + int i; + uint8_t scan_status; + uint64_t cookie; + + ENTER(); + + if (WLAN_HDD_ADAPTER_MAGIC != adapter->magic) { + hdd_err("Invalid adapter magic"); + qdf_mem_free(req); + return; + } + skb = cfg80211_vendor_event_alloc(hddctx->wiphy, &(adapter->wdev), + SCAN_DONE_EVENT_BUF_SIZE + 4 + NLMSG_HDRLEN, + QCA_NL80211_VENDOR_SUBCMD_SCAN_DONE_INDEX, + GFP_KERNEL); + + if (!skb) { + hdd_err("skb alloc failed"); + qdf_mem_free(req); + return; + } + + cookie = (uintptr_t)req; + attr = nla_nest_start(skb, QCA_WLAN_VENDOR_ATTR_SCAN_SSIDS); + if (!attr) + goto nla_put_failure; + for (i = 0; i < req->n_ssids; i++) { + if (nla_put(skb, i, req->ssids[i].ssid_len, + req->ssids[i].ssid)) { + hdd_err("Failed to add ssid"); + goto nla_put_failure; + } + } + nla_nest_end(skb, attr); + attr = nla_nest_start(skb, QCA_WLAN_VENDOR_ATTR_SCAN_FREQUENCIES); + if (!attr) + goto nla_put_failure; + for (i = 0; i < req->n_channels; i++) { + if (nla_put_u32(skb, i, req->channels[i]->center_freq)) { + hdd_err("Failed to add channel"); + goto nla_put_failure; + } + } + nla_nest_end(skb, attr); + + if (req->ie && + nla_put(skb, QCA_WLAN_VENDOR_ATTR_SCAN_IE, req->ie_len, + req->ie)) { + hdd_err("Failed to add scan ie"); + goto nla_put_failure; + } + if (req->flags && + nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_SCAN_FLAGS, req->flags)) { + hdd_err("Failed to add scan flags"); + goto nla_put_failure; + } + if (hdd_wlan_nla_put_u64(skb, + QCA_WLAN_VENDOR_ATTR_SCAN_COOKIE, + cookie)) { + hdd_err("Failed to add scan cookie"); + goto nla_put_failure; + } + scan_status = (aborted == true) ? VENDOR_SCAN_STATUS_ABORTED : + VENDOR_SCAN_STATUS_NEW_RESULTS; + if (nla_put_u8(skb, QCA_WLAN_VENDOR_ATTR_SCAN_STATUS, scan_status)) { + hdd_err("Failed to add scan staus"); + goto nla_put_failure; + } + cfg80211_vendor_event(skb, GFP_KERNEL); + hdd_info("scan complete event sent to NL"); + qdf_mem_free(req); + return; + +nla_put_failure: + kfree_skb(skb); + qdf_mem_free(req); + return; +} + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 7, 0)) +/** + * hdd_cfg80211_scan_done() - Scan completed callback to cfg80211 + * @adapter: Pointer to the adapter + * @req : Scan request + * @aborted : true scan aborted false scan success + * + * This function notifies scan done to cfg80211 + * + * Return: none + */ +static void hdd_cfg80211_scan_done(hdd_adapter_t *adapter, + struct cfg80211_scan_request *req, + bool aborted) +{ + struct cfg80211_scan_info info = { + .aborted = aborted + }; + + if (adapter->dev->flags & IFF_UP) + cfg80211_scan_done(req, &info); +} +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) +/** + * hdd_cfg80211_scan_done() - Scan completed callback to cfg80211 + * @adapter: Pointer to the adapter + * @req : Scan request + * @aborted : true scan aborted false scan success + * + * This function notifies scan done to cfg80211 + * + * Return: none + */ +static void hdd_cfg80211_scan_done(hdd_adapter_t *adapter, + struct cfg80211_scan_request *req, + bool aborted) +{ + if (adapter->dev->flags & IFF_UP) + cfg80211_scan_done(req, aborted); +} +#else +/** + * hdd_cfg80211_scan_done() - Scan completed callback to cfg80211 + * @adapter: Pointer to the adapter + * @req : Scan request + * @aborted : true scan aborted false scan success + * + * This function notifies scan done to cfg80211 + * + * Return: none + */ +static void hdd_cfg80211_scan_done(hdd_adapter_t *adapter, + struct cfg80211_scan_request *req, + bool aborted) +{ + cfg80211_scan_done(req, aborted); +} +#endif + +/** + * hdd_cfg80211_scan_done_callback() - scan done callback function called after + * scan is finished + * @halHandle: Pointer to handle + * @pContext: Pointer to context + * @sessionId: Session Id + * @scanId: Scan Id + * @status: Scan status + * + * Return: QDF status + */ +static QDF_STATUS hdd_cfg80211_scan_done_callback(tHalHandle halHandle, + void *pContext, + uint8_t sessionId, + uint32_t scanId, + eCsrScanStatus status) +{ + struct net_device *dev = (struct net_device *)pContext; + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_scaninfo_t *pScanInfo = &pAdapter->scan_info; + struct cfg80211_scan_request *req = NULL; + bool aborted = false; + hdd_context_t *hddctx = WLAN_HDD_GET_CTX(pAdapter); + int ret = 0; + unsigned int current_timestamp, time_elapsed; + uint8_t source; + uint32_t scan_time; + uint32_t size = 0; + + ret = wlan_hdd_validate_context(hddctx); + if (ret) { + hdd_err("Invalid hdd_ctx; Drop results for scanId %d", scanId); + return QDF_STATUS_E_INVAL; + } + + hdd_notice("called with hal = %p, pContext = %p, ID = %d, status = %d", + halHandle, pContext, (int)scanId, (int)status); + + pScanInfo->mScanPendingCounter = 0; + + if (QDF_STATUS_SUCCESS != + wlan_hdd_scan_request_dequeue(hddctx, scanId, &req, &source, + &scan_time)) { + hdd_err("Dequeue of scan request failed ID: %d", scanId); + goto allow_suspend; + } + + /* + * cfg80211_scan_done informing NL80211 about completion + * of scanning + */ + if (status == eCSR_SCAN_ABORT || status == eCSR_SCAN_FAILURE) { + aborted = true; + } + + if (!aborted && !hddctx->beacon_probe_rsp_cnt_per_scan) { + hdd_notice("NO SCAN result"); + if (hddctx->config->bug_report_for_no_scan_results) { + current_timestamp = jiffies_to_msecs(jiffies); + time_elapsed = current_timestamp - + hddctx->last_nil_scan_bug_report_timestamp; + + /* + * check if we have generated bug report in + * MIN_TIME_REQUIRED_FOR_NEXT_BUG_REPORT time. + */ + if (time_elapsed > + MIN_TIME_REQUIRED_FOR_NEXT_BUG_REPORT) { + cds_flush_logs(WLAN_LOG_TYPE_FATAL, + WLAN_LOG_INDICATOR_HOST_DRIVER, + WLAN_LOG_REASON_NO_SCAN_RESULTS, + true, false); + hddctx->last_nil_scan_bug_report_timestamp = + current_timestamp; + } + } + } + hddctx->beacon_probe_rsp_cnt_per_scan = 0; + + if (!wlan_hdd_is_scan_pending(pAdapter)) { + /* Scan is no longer pending */ + pScanInfo->mScanPending = false; + complete(&pScanInfo->abortscan_event_var); + } + + /* + * Scan can be triggred from NL or vendor scan + * - If scan is triggered from NL then cfg80211 scan done should be + * called to updated scan completion to NL. + * - If scan is triggred through vendor command then + * scan done event will be posted + */ + if (NL_SCAN == source) + hdd_cfg80211_scan_done(pAdapter, req, aborted); + else + hdd_vendor_scan_callback(pAdapter, req, aborted); + +allow_suspend: + qdf_runtime_pm_allow_suspend(&hddctx->runtime_context.scan); + qdf_spin_lock(&hddctx->hdd_scan_req_q_lock); + size = qdf_list_size(&hddctx->hdd_scan_req_q); + if (!size) { + qdf_spin_unlock(&hddctx->hdd_scan_req_q_lock); + /* release the wake lock at the end of the scan */ + hdd_allow_suspend(WIFI_POWER_EVENT_WAKELOCK_SCAN); + + /* Acquire wakelock to handle the case where APP's tries + * to suspend immediatly after the driver gets connect + * request(i.e after scan) from supplicant, this result in + * app's is suspending and not ableto process the connect + * request to AP + */ + hdd_prevent_suspend_timeout(1000, + WIFI_POWER_EVENT_WAKELOCK_SCAN); + } else { + /* Release the spin lock */ + qdf_spin_unlock(&hddctx->hdd_scan_req_q_lock); + } + +#ifdef FEATURE_WLAN_TDLS + wlan_hdd_tdls_scan_done_callback(pAdapter); +#endif + + EXIT(); + return 0; +} + +#ifdef FEATURE_WLAN_AP_AP_ACS_OPTIMIZE +/** + * wlan_hdd_sap_skip_scan_check() - The function will check OBSS + * scan skip or not for SAP. + * @hdd_ctx: pointer to hdd context. + * @request: pointer to scan request. + * + * This function will check the scan request's chan list against the + * previous ACS scan chan list. If all the chan are covered by + * previous ACS scan, we can skip the scan and return scan complete + * to save the SAP starting time. + * + * Return: true to skip the scan, + * false to continue the scan + */ +static bool wlan_hdd_sap_skip_scan_check(hdd_context_t *hdd_ctx, + struct cfg80211_scan_request *request) +{ + int i, j; + bool skip; + + hdd_info("HDD_ACS_SKIP_STATUS = %d", + hdd_ctx->skip_acs_scan_status); + if (hdd_ctx->skip_acs_scan_status != eSAP_SKIP_ACS_SCAN) + return false; + qdf_spin_lock(&hdd_ctx->acs_skip_lock); + if (hdd_ctx->last_acs_channel_list == NULL || + hdd_ctx->num_of_channels == 0 || + request->n_channels == 0) { + qdf_spin_unlock(&hdd_ctx->acs_skip_lock); + return false; + } + skip = true; + for (i = 0; i < request->n_channels ; i++) { + bool find = false; + for (j = 0; j < hdd_ctx->num_of_channels; j++) { + if (hdd_ctx->last_acs_channel_list[j] == + request->channels[i]->hw_value) { + find = true; + break; + } + } + if (!find) { + skip = false; + hdd_info("Chan %d isn't in ACS chan list", + request->channels[i]->hw_value); + break; + } + } + qdf_spin_unlock(&hdd_ctx->acs_skip_lock); + return skip; +} +#else +static bool wlan_hdd_sap_skip_scan_check(hdd_context_t *hdd_ctx, + struct cfg80211_scan_request *request) +{ + return false; +} +#endif + +/** + * wlan_hdd_cfg80211_scan_block_cb() - scan block work handler + * @work: Pointer to work + * + * Return: none + */ +static void wlan_hdd_cfg80211_scan_block_cb(struct work_struct *work) +{ + hdd_adapter_t *adapter = container_of(work, + hdd_adapter_t, scan_block_work); + struct cfg80211_scan_request *request; + if (WLAN_HDD_ADAPTER_MAGIC != adapter->magic) { + hdd_err("HDD adapter context is invalid"); + return; + } + + request = adapter->request; + if (request) { + request->n_ssids = 0; + request->n_channels = 0; + + hdd_err("##In DFS Master mode. Scan aborted. Null result sent"); + hdd_cfg80211_scan_done(adapter, request, true); + adapter->request = NULL; + } +} + +/** + * wlan_hdd_copy_bssid_scan_request() - API to copy the bssid to Scan request + * @scan_req: Pointer to CSR Scan Request + * @request: scan request from Supplicant + * + * This API copies the BSSID in scan request from Supplicant and copies it to + * the CSR Scan request + * + * Return: None + */ +#if defined(CFG80211_SCAN_BSSID) || \ + (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 7, 0)) +static inline void wlan_hdd_copy_bssid_scan_request(tCsrScanRequest *scan_req, + struct cfg80211_scan_request *request) +{ + qdf_mem_copy(scan_req->bssid.bytes, request->bssid, QDF_MAC_ADDR_SIZE); +} +#else +static inline void wlan_hdd_copy_bssid_scan_request(tCsrScanRequest *scan_req, + struct cfg80211_scan_request *request) +{ +} +#endif + +/* + * wlan_hdd_update_scan_ies() - API to update the scan IEs of scan request + * with already stored default scan IEs + * + * @adapter: Pointer to HDD adapter + * @scan_info: Pointer to scan info in HDD adapter + * @scan_ie: Pointer to scan IE in scan request + * @scan_ie_len: Pointer to scan IE length in scan request + * + * Return: 0 on success; error number otherwise + */ +static int wlan_hdd_update_scan_ies(hdd_adapter_t *adapter, + hdd_scaninfo_t *scan_info, uint8_t *scan_ie, + uint8_t *scan_ie_len) +{ + uint8_t rem_len = scan_info->default_scan_ies_len; + uint8_t *temp_ie = scan_info->default_scan_ies; + uint8_t *current_ie; + uint8_t elem_id; + uint16_t elem_len; + + if (!scan_info->default_scan_ies_len || !scan_info->default_scan_ies) + return 0; + + while (rem_len >= 2) { + current_ie = temp_ie; + elem_id = *temp_ie++; + elem_len = *temp_ie++; + rem_len -= 2; + + switch (elem_id) { + case DOT11F_EID_EXTCAP: + if (!wlan_hdd_cfg80211_get_ie_ptr(scan_ie, *scan_ie_len, + DOT11F_EID_EXTCAP)) { + qdf_mem_copy(scan_ie + (*scan_ie_len), + current_ie, elem_len + 2); + (*scan_ie_len) += (elem_len + 2); + } + break; + case DOT11F_EID_WPA: + if (!wlan_hdd_get_mbo_ie_ptr(scan_ie, *scan_ie_len)) { + qdf_mem_copy(scan_ie + (*scan_ie_len), + current_ie, elem_len + 2); + (*scan_ie_len) += (elem_len + 2); + } + break; + } + temp_ie += elem_len; + rem_len -= elem_len; + } + return 0; +} + +#if defined(CFG80211_SCAN_RANDOM_MAC_ADDR) || \ + (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)) +/** + * wlan_hdd_update_scan_rand_attrs - fill the host/pno scan rand attrs + * @scan_req: pointer to scan_req containing destination mac addr and mac mask + * @cfg_scan_req: pointer to cfg scan containing to source mac addr and mac mask + * @scan_type: type of scan from enum wlan_hdd_scan_type + * + * If scan randomize flag is set in cfg scan request flags, this function + * copies mac addr and mac mask in cfg80211 scan/sched scan request to + * randomization attributes in tCsrScanRequest (normal scan) or + * tpSirPNOScanReq (sched scan). Based on the type of scan, scan_req and + * cfg_scan_req are type casted accordingly. + * + * Return: None + */ +static void wlan_hdd_update_scan_rand_attrs(void *scan_req, + void *cfg_scan_req, + uint32_t scan_type) +{ + uint32_t flags = 0; + uint8_t *cfg_mac_addr = NULL; + uint8_t *cfg_mac_addr_mask = NULL; + bool *scan_randomization = NULL; + uint8_t *scan_mac_addr = NULL; + uint8_t *scan_mac_addr_mask = NULL; + + if (scan_type == WLAN_HDD_HOST_SCAN) { + tCsrScanRequest *csr_scan_req = NULL; + struct cfg80211_scan_request *request = NULL; + + csr_scan_req = (tCsrScanRequest *)scan_req; + request = (struct cfg80211_scan_request *)cfg_scan_req; + + flags = request->flags; + if (!(flags & NL80211_SCAN_FLAG_RANDOM_ADDR)) + return; + + cfg_mac_addr = request->mac_addr; + cfg_mac_addr_mask = request->mac_addr_mask; + scan_randomization = &csr_scan_req->enable_scan_randomization; + scan_mac_addr = csr_scan_req->mac_addr; + scan_mac_addr_mask = csr_scan_req->mac_addr_mask; + } else if (scan_type == WLAN_HDD_PNO_SCAN) { + tpSirPNOScanReq pno_scan_req = NULL; + struct cfg80211_sched_scan_request *request = NULL; + + pno_scan_req = (tpSirPNOScanReq)scan_req; + request = (struct cfg80211_sched_scan_request *)cfg_scan_req; + + flags = request->flags; + if (!(flags & NL80211_SCAN_FLAG_RANDOM_ADDR)) + return; + + cfg_mac_addr = request->mac_addr; + cfg_mac_addr_mask = request->mac_addr_mask; + scan_randomization = + &pno_scan_req->enable_pno_scan_randomization; + scan_mac_addr = pno_scan_req->mac_addr; + scan_mac_addr_mask = pno_scan_req->mac_addr_mask; + } else { + hdd_err("invalid scan type for randomization"); + return; + } + + /* enable mac randomization */ + *scan_randomization = true; + memcpy(scan_mac_addr, cfg_mac_addr, QDF_MAC_ADDR_SIZE); + memcpy(scan_mac_addr_mask, cfg_mac_addr_mask, QDF_MAC_ADDR_SIZE); + + hdd_info("Mac Addr: "MAC_ADDRESS_STR " and Mac Mask: " MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(scan_mac_addr), + MAC_ADDR_ARRAY(scan_mac_addr_mask)); +} +#else +static void wlan_hdd_update_scan_rand_attrs(void *scan_req, + void *cfg_scan_req, + uint32_t scan_type) +{ +} +#endif + +/** + * __wlan_hdd_cfg80211_scan() - API to process cfg80211 scan request + * @wiphy: Pointer to wiphy + * @dev: Pointer to net device + * @request: Pointer to scan request + * @source: scan request source(NL/Vendor scan) + * + * This API responds to scan trigger and update cfg80211 scan database + * later, scan dump command can be used to recieve scan results + * + * Return: 0 for success, non zero for failure + */ +static int __wlan_hdd_cfg80211_scan(struct wiphy *wiphy, + struct cfg80211_scan_request *request, + uint8_t source) +{ + struct net_device *dev = request->wdev->netdev; + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + hdd_wext_state_t *pwextBuf = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter); + struct hdd_config *cfg_param = NULL; + tCsrScanRequest scan_req; + uint8_t *channelList = NULL, i; + int status; + hdd_scaninfo_t *pScanInfo = NULL; + uint8_t *pP2pIe = NULL; + hdd_adapter_t *con_sap_adapter; + uint16_t con_dfs_ch; + uint8_t num_chan = 0; + bool is_p2p_scan = false; + uint8_t curr_session_id; + scan_reject_states curr_reason; + + ENTER(); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EINVAL; + } + + if (wlan_hdd_validate_session_id(pAdapter->sessionId)) { + hdd_err("invalid session id: %d", pAdapter->sessionId); + return -EINVAL; + } + + status = wlan_hdd_validate_context(pHddCtx); + + if (0 != status) + return status; + + MTRACE(qdf_trace(QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_CFG80211_SCAN, + pAdapter->sessionId, request->n_channels)); + + if (!sme_is_session_id_valid(pHddCtx->hHal, pAdapter->sessionId)) + return -EINVAL; + + hdd_notice("Device_mode %s(%d)", + hdd_device_mode_to_string(pAdapter->device_mode), + pAdapter->device_mode); + + /* + * IBSS vdev does not need to scan to establish + * IBSS connection. If IBSS vdev need to support scan, + * Firmware need to make the change to add self peer + * per mac for IBSS vdev. + */ + if (QDF_IBSS_MODE == pAdapter->device_mode) { + hdd_err("Scan not supported for IBSS"); + return -EINVAL; + } + + cfg_param = pHddCtx->config; + pScanInfo = &pAdapter->scan_info; + + /* Block All Scan during DFS operation and send null scan result */ + con_sap_adapter = hdd_get_con_sap_adapter(pAdapter, true); + if (con_sap_adapter) { + con_dfs_ch = con_sap_adapter->sessionCtx.ap.sapConfig.channel; + if (con_dfs_ch == AUTO_CHANNEL_SELECT) + con_dfs_ch = + con_sap_adapter->sessionCtx.ap.operatingChannel; + + if (!wma_is_hw_dbs_capable() && CDS_IS_DFS_CH(con_dfs_ch)) { + /* Provide empty scan result during DFS operation since + * scanning not supported during DFS. Reason is + * following case: + * DFS is supported only in SCC for MBSSID Mode. + * We shall not return EBUSY or ENOTSUPP as when Primary + * AP is operating in DFS channel and secondary AP is + * started. Though we force SCC in driver, the hostapd + * issues obss scan before starting secAP. This results + * in MCC in DFS mode. Thus we return null scan result. + * If we return scan failure hostapd fails secondary AP + * startup. + */ + hdd_err("##In DFS Master mode. Scan aborted"); + pAdapter->request = request; + + INIT_WORK(&pAdapter->scan_block_work, + wlan_hdd_cfg80211_scan_block_cb); + schedule_work(&pAdapter->scan_block_work); + return 0; + } + } + if (!wma_is_hw_dbs_capable()) { + if (true == pScanInfo->mScanPending) { + if (MAX_PENDING_LOG > + pScanInfo->mScanPendingCounter++) { + hdd_err("mScanPending is true"); + } + return -EBUSY; + } + + /* Don't Allow Scan and return busy if Remain On + * Channel and action frame is pending + * Otherwise Cancel Remain On Channel and allow Scan + * If no action frame pending + */ + if (0 != wlan_hdd_check_remain_on_channel(pAdapter)) { + hdd_err("Remain On Channel Pending"); + return -EBUSY; + } + } +#ifdef FEATURE_WLAN_TDLS + /* if tdls disagree scan right now, return immediately. + * tdls will schedule the scan when scan is allowed. + * (return SUCCESS) + * or will reject the scan if any TDLS is in progress. + * (return -EBUSY) + */ + status = wlan_hdd_tdls_scan_callback(pAdapter, wiphy, + request, source); + if (status <= 0) { + if (!status) + hdd_err("TDLS in progress.scan rejected %d", + status); + else + hdd_err("TDLS teardown is ongoing %d", + status); + hdd_wlan_block_scan_by_tdls_event(); + return status; + } +#endif + + /* Check if scan is allowed at this point of time */ + if (cds_is_connection_in_progress(&curr_session_id, &curr_reason)) { + hdd_err("Scan not allowed"); + if (pHddCtx->last_scan_reject_session_id != curr_session_id || + pHddCtx->last_scan_reject_reason != curr_reason || + !pHddCtx->last_scan_reject_timestamp) { + pHddCtx->last_scan_reject_session_id = curr_session_id; + pHddCtx->last_scan_reject_reason = curr_reason; + pHddCtx->last_scan_reject_timestamp = + jiffies_to_msecs(jiffies); + } else { + hdd_err("curr_session id %d curr_reason %d time delta %lu", + curr_session_id, curr_reason, + (jiffies_to_msecs(jiffies) - + pHddCtx->last_scan_reject_timestamp)); + if ((jiffies_to_msecs(jiffies) - + pHddCtx->last_scan_reject_timestamp) >= + SCAN_REJECT_THRESHOLD_TIME) { + pHddCtx->last_scan_reject_timestamp = 0; + if (pHddCtx->config->enable_fatal_event) { + cds_flush_logs(WLAN_LOG_TYPE_FATAL, + WLAN_LOG_INDICATOR_HOST_DRIVER, + WLAN_LOG_REASON_SCAN_NOT_ALLOWED, + false, + pHddCtx->config->enableSelfRecovery); + } else if (pHddCtx->config-> + enableSelfRecovery) { + hdd_err("Triggering SSR due to scan stuck"); + cds_trigger_recovery(false); + } else { + hdd_err("QDF_BUG due to scan stuck"); + QDF_BUG(0); + } + } + } + return -EBUSY; + } + pHddCtx->last_scan_reject_timestamp = 0; + pHddCtx->last_scan_reject_session_id = 0xFF; + pHddCtx->last_scan_reject_reason = 0; + + /* Check whether SAP scan can be skipped or not */ + if (pAdapter->device_mode == QDF_SAP_MODE && + wlan_hdd_sap_skip_scan_check(pHddCtx, request)) { + hdd_err("sap scan skipped"); + pAdapter->request = request; + INIT_WORK(&pAdapter->scan_block_work, + wlan_hdd_cfg80211_scan_block_cb); + schedule_work(&pAdapter->scan_block_work); + return 0; + } + + qdf_mem_zero(&scan_req, sizeof(scan_req)); + + scan_req.timestamp = qdf_mc_timer_get_system_time(); + + /* Even though supplicant doesn't provide any SSIDs, n_ssids is + * set to 1. Because of this, driver is assuming that this is not + * wildcard scan and so is not aging out the scan results. + */ + if ((request->ssids) && (request->n_ssids == 1) && + ('\0' == request->ssids->ssid[0])) { + request->n_ssids = 0; + } + + if ((request->ssids) && (0 < request->n_ssids)) { + tCsrSSIDInfo *SsidInfo; + int j; + scan_req.SSIDs.numOfSSIDs = request->n_ssids; + /* Allocate num_ssid tCsrSSIDInfo structure */ + SsidInfo = scan_req.SSIDs.SSIDList = + qdf_mem_malloc(request->n_ssids * sizeof(tCsrSSIDInfo)); + + if (NULL == scan_req.SSIDs.SSIDList) { + hdd_err("memory alloc failed SSIDInfo buffer"); + return -ENOMEM; + } + + /* copy all the ssid's and their length */ + for (j = 0; j < request->n_ssids; j++, SsidInfo++) { + /* get the ssid length */ + SsidInfo->SSID.length = request->ssids[j].ssid_len; + qdf_mem_copy(SsidInfo->SSID.ssId, + &request->ssids[j].ssid[0], + SsidInfo->SSID.length); + SsidInfo->SSID.ssId[SsidInfo->SSID.length] = '\0'; + hdd_notice("SSID number %d: %s", j, + SsidInfo->SSID.ssId); + } + /* set the scan type to active */ + scan_req.scanType = eSIR_ACTIVE_SCAN; + } else if (QDF_P2P_GO_MODE == pAdapter->device_mode || + QDF_SAP_MODE == pAdapter->device_mode) { + /* set the scan type to active */ + scan_req.scanType = eSIR_ACTIVE_SCAN; + } else { + /* + * Set the scan type to passive if there is no ssid list + * provided else set default type configured in the driver. + */ + if (!request->ssids) + scan_req.scanType = eSIR_PASSIVE_SCAN; + else + scan_req.scanType = pHddCtx->ioctl_scan_mode; + } + if (scan_req.scanType == eSIR_PASSIVE_SCAN) { + scan_req.minChnTime = cfg_param->nPassiveMinChnTime; + scan_req.maxChnTime = cfg_param->nPassiveMaxChnTime; + } else { + scan_req.minChnTime = cfg_param->nActiveMinChnTime; + scan_req.maxChnTime = cfg_param->nActiveMaxChnTime; + } + + wlan_hdd_copy_bssid_scan_request(&scan_req, request); + + /* set BSSType to default type */ + scan_req.BSSType = eCSR_BSS_TYPE_ANY; + + if (MAX_CHANNEL < request->n_channels) { + hdd_warn("No of Scan Channels exceeded limit: %d", + request->n_channels); + request->n_channels = MAX_CHANNEL; + } + + if (request->n_channels) { + char chList[(request->n_channels * 5) + 1]; + int len; + channelList = qdf_mem_malloc(request->n_channels); + if (NULL == channelList) { + hdd_err("channelList malloc failed channelList"); + status = -ENOMEM; + goto free_mem; + } + for (i = 0, len = 0; i < request->n_channels; i++) { + if (cds_is_dsrc_channel(cds_chan_to_freq( + request->channels[i]->hw_value))) + continue; + channelList[num_chan] = request->channels[i]->hw_value; + len += snprintf(chList + len, 5, "%d ", channelList[i]); + num_chan++; + } + hdd_notice("Channel-List: %s", chList); + hdd_notice("No. of Scan Channels: %d", num_chan); + } + if (!num_chan) { + hdd_err("Received zero non-dsrc channels"); + status = -EINVAL; + goto free_mem; + } + + scan_req.ChannelInfo.numOfChannels = num_chan; + scan_req.ChannelInfo.ChannelList = channelList; + + /* set requestType to full scan */ + scan_req.requestType = eCSR_SCAN_REQUEST_FULL_SCAN; + + /* Flush the scan results(only p2p beacons) for STA scan and P2P + * search (Flush on both full scan and social scan but not on single + * channel scan).P2P search happens on 3 social channels (1, 6, 11) + */ + + /* Supplicant does single channel scan after 8-way handshake + * and in that case driver shoudnt flush scan results. If + * driver flushes the scan results here and unfortunately if + * the AP doesnt respond to our probe req then association + * fails which is not desired + */ + + if ((request->n_ssids == 1) && + (request->ssids != NULL) && + qdf_mem_cmp(&request->ssids[0], "DIRECT-", 7)) + is_p2p_scan = true; + + if (is_p2p_scan || + (request->n_channels != WLAN_HDD_P2P_SINGLE_CHANNEL_SCAN)) { + hdd_debug("Flushing P2P Results"); + sme_scan_flush_p2p_result(WLAN_HDD_GET_HAL_CTX(pAdapter), + pAdapter->sessionId); + } + if (request->ie_len) { + /* save this for future association (join requires this) */ + memset(&pScanInfo->scanAddIE, 0, sizeof(pScanInfo->scanAddIE)); + memcpy(pScanInfo->scanAddIE.addIEdata, request->ie, + request->ie_len); + pScanInfo->scanAddIE.length = request->ie_len; + + if (wlan_hdd_update_scan_ies(pAdapter, pScanInfo, + pScanInfo->scanAddIE.addIEdata, + (uint8_t *)&pScanInfo->scanAddIE.length)) + hdd_err("Update scan IEs with default Scan IEs failed"); + + if ((QDF_STA_MODE == pAdapter->device_mode) || + (QDF_P2P_CLIENT_MODE == pAdapter->device_mode) || + (QDF_P2P_DEVICE_MODE == pAdapter->device_mode) + ) { + pwextBuf->roamProfile.pAddIEScan = + pScanInfo->scanAddIE.addIEdata; + pwextBuf->roamProfile.nAddIEScanLength = + pScanInfo->scanAddIE.length; + } + + scan_req.uIEFieldLen = pScanInfo->scanAddIE.length; + scan_req.pIEField = pScanInfo->scanAddIE.addIEdata; + + pP2pIe = wlan_hdd_get_p2p_ie_ptr((uint8_t *) request->ie, + request->ie_len); + if (pP2pIe != NULL) { +#ifdef WLAN_FEATURE_P2P_DEBUG + if (((global_p2p_connection_status == P2P_GO_NEG_COMPLETED) + || (global_p2p_connection_status == + P2P_GO_NEG_PROCESS)) + && (QDF_P2P_CLIENT_MODE == pAdapter->device_mode)) { + global_p2p_connection_status = + P2P_CLIENT_CONNECTING_STATE_1; + hdd_err("[P2P State] Changing state from Go nego completed to Connection is started"); + hdd_err("[P2P]P2P Scanning is started for 8way Handshake"); + } else + if ((global_p2p_connection_status == + P2P_CLIENT_DISCONNECTED_STATE) + && (QDF_P2P_CLIENT_MODE == + pAdapter->device_mode)) { + global_p2p_connection_status = + P2P_CLIENT_CONNECTING_STATE_2; + hdd_err("[P2P State] Changing state from Disconnected state to Connection is started"); + hdd_err("[P2P]P2P Scanning is started for 4way Handshake"); + } +#endif + + /* no_cck will be set during p2p find to disable 11b rates */ + if (request->no_cck) { + hdd_notice("This is a P2P Search"); + scan_req.p2pSearch = 1; + + if (request->n_channels == + WLAN_HDD_P2P_SOCIAL_CHANNELS) { + /* set requestType to P2P Discovery */ + scan_req.requestType = + eCSR_SCAN_P2P_DISCOVERY; + } + + /* + * Skip Dfs Channel in case of P2P Search if it is set in + * ini file + */ + if (cfg_param->skipDfsChnlInP2pSearch) { + scan_req.skipDfsChnlInP2pSearch = 1; + } else { + scan_req.skipDfsChnlInP2pSearch = 0; + } + + } + } + } else { + if (pScanInfo->default_scan_ies && + pScanInfo->default_scan_ies_len) { + qdf_mem_copy(pScanInfo->scanAddIE.addIEdata, + pScanInfo->default_scan_ies, + pScanInfo->default_scan_ies_len); + pScanInfo->scanAddIE.length = + pScanInfo->default_scan_ies_len; + } + } + + /* acquire the wakelock to avoid the apps suspend during the scan. To + * address the following issues. + * 1) Disconnected scenario: we are not allowing the suspend as WLAN is not in + * BMPS/IMPS this result in android trying to suspend aggressively and backing off + * for long time, this result in apps running at full power for long time. + * 2) Connected scenario: If we allow the suspend during the scan, RIVA will + * be stuck in full power because of resume BMPS + */ + hdd_prevent_suspend_timeout(HDD_WAKE_LOCK_SCAN_DURATION, + WIFI_POWER_EVENT_WAKELOCK_SCAN); + + hdd_info("requestType %d, scanType %d, minChnTime %d, maxChnTime %d,p2pSearch %d, skipDfsChnlIn P2pSearch %d", + scan_req.requestType, scan_req.scanType, + scan_req.minChnTime, scan_req.maxChnTime, + scan_req.p2pSearch, scan_req.skipDfsChnlInP2pSearch); +#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 7, 0)) + if (request->flags & NL80211_SCAN_FLAG_FLUSH) { + hdd_debug("Kernel scan flush flag enabled"); + sme_scan_flush_result(WLAN_HDD_GET_HAL_CTX(pAdapter)); + } +#endif + wlan_hdd_update_scan_rand_attrs((void *)&scan_req, (void *)request, + WLAN_HDD_HOST_SCAN); + + qdf_runtime_pm_prevent_suspend(&pHddCtx->runtime_context.scan); + status = sme_scan_request(WLAN_HDD_GET_HAL_CTX(pAdapter), + pAdapter->sessionId, &scan_req, + &hdd_cfg80211_scan_done_callback, dev); + + if (QDF_STATUS_SUCCESS != status) { + hdd_err("sme_scan_request returned error %d", status); + if (QDF_STATUS_E_RESOURCES == status) { + hdd_err("HO is in progress.So defer the scan by informing busy"); + status = -EBUSY; + } else { + status = -EIO; + } + + qdf_runtime_pm_allow_suspend(&pHddCtx->runtime_context.scan); + hdd_allow_suspend(WIFI_POWER_EVENT_WAKELOCK_SCAN); + goto free_mem; + } + wlan_hdd_scan_request_enqueue(pAdapter, request, source, + scan_req.scan_id, scan_req.timestamp); + pAdapter->scan_info.mScanPending = true; + pHddCtx->beacon_probe_rsp_cnt_per_scan = 0; + +free_mem: + if (scan_req.SSIDs.SSIDList) + qdf_mem_free(scan_req.SSIDs.SSIDList); + + if (channelList) + qdf_mem_free(channelList); + + EXIT(); + return status; +} + +/** + * wlan_hdd_cfg80211_scan() - API to process cfg80211 scan request + * @wiphy: Pointer to wiphy + * @dev: Pointer to net device + * @request: Pointer to scan request + * + * This API responds to scan trigger and update cfg80211 scan database + * later, scan dump command can be used to recieve scan results + * + * Return: 0 for success, non zero for failure + */ +int wlan_hdd_cfg80211_scan(struct wiphy *wiphy, + struct cfg80211_scan_request *request) +{ + int ret; + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_scan(wiphy, + request, NL_SCAN); + cds_ssr_unprotect(__func__); + return ret; +} + +/** + * wlan_hdd_cfg80211_tdls_scan() - API to process cfg80211 scan request + * @wiphy: Pointer to wiphy + * @request: Pointer to scan request + * @source: scan request source(NL/Vendor scan) + * + * This API responds to scan trigger and update cfg80211 scan database + * later, scan dump command can be used to recieve scan results. This + * function gets called when tdls module queues the scan request. + * + * Return: 0 for success, non zero for failure. + */ +int wlan_hdd_cfg80211_tdls_scan(struct wiphy *wiphy, + struct cfg80211_scan_request *request, + uint8_t source) +{ + int ret; + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_scan(wiphy, + request, source); + cds_ssr_unprotect(__func__); + return ret; +} + +/** + * wlan_hdd_get_rates() -API to get the rates from scan request + * @wiphy: Pointer to wiphy + * @band: Band + * @rates: array of rates + * @rate_count: number of rates + * + * Return: o for failure, rate bitmap for success + */ +static uint32_t wlan_hdd_get_rates(struct wiphy *wiphy, + enum nl80211_band band, + const u8 *rates, unsigned int rate_count) +{ + uint32_t j, count, rate_bitmap = 0; + uint32_t rate; + bool found; + + for (count = 0; count < rate_count; count++) { + rate = ((rates[count]) & RATE_MASK) * 5; + found = false; + for (j = 0; j < wiphy->bands[band]->n_bitrates; j++) { + if (wiphy->bands[band]->bitrates[j].bitrate == rate) { + found = true; + rate_bitmap |= (1 << j); + break; + } + } + if (!found) + return 0; + } + return rate_bitmap; +} + +/** + * wlan_hdd_send_scan_start_event() -API to send the scan start event + * @wiphy: Pointer to wiphy + * @wdev: Pointer to net device + * @cookie: scan identifier + * + * Return: return 0 on success and negative error code on failure + */ +static int wlan_hdd_send_scan_start_event(struct wiphy *wiphy, + struct wireless_dev *wdev, uint64_t cookie) +{ + struct sk_buff *skb; + int ret; + + skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, sizeof(u64) + + NLA_HDRLEN + NLMSG_HDRLEN); + if (!skb) { + hdd_err(" reply skb alloc failed"); + return -ENOMEM; + } + + if (hdd_wlan_nla_put_u64(skb, QCA_WLAN_VENDOR_ATTR_SCAN_COOKIE, + cookie)) { + hdd_err("nla put fail"); + kfree_skb(skb); + return -EINVAL; + } + + ret = cfg80211_vendor_cmd_reply(skb); + + /* Send a scan started event to supplicant */ + skb = cfg80211_vendor_event_alloc(wiphy, wdev, + sizeof(u64) + 4 + NLMSG_HDRLEN, + QCA_NL80211_VENDOR_SUBCMD_SCAN_INDEX, GFP_KERNEL); + if (!skb) { + hdd_err("skb alloc failed"); + return -ENOMEM; + } + + if (hdd_wlan_nla_put_u64(skb, QCA_WLAN_VENDOR_ATTR_SCAN_COOKIE, + cookie)) { + kfree_skb(skb); + return -EINVAL; + } + cfg80211_vendor_event(skb, GFP_KERNEL); + + return ret; +} + +/** + * wlan_hdd_copy_bssid() - API to copy the bssid to vendor Scan request + * @request: Pointer to vendor scan request + * @bssid: Pointer to BSSID + * + * This API copies the specific BSSID received from Supplicant and copies it to + * the vendor Scan request + * + * Return: None + */ +#if defined(CFG80211_SCAN_BSSID) || \ + (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 7, 0)) +static inline void wlan_hdd_copy_bssid(struct cfg80211_scan_request *request, + uint8_t *bssid) +{ + qdf_mem_copy(request->bssid, bssid, QDF_MAC_ADDR_SIZE); +} +#else +static inline void wlan_hdd_copy_bssid(struct cfg80211_scan_request *request, + uint8_t *bssid) +{ +} +#endif + +#if defined(CFG80211_SCAN_RANDOM_MAC_ADDR) || \ + (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)) +/** + * wlan_hdd_vendor_scan_random_attr() - check and fill scan randomization attrs + * @wiphy: Pointer to wiphy + * @request: Pointer to scan request + * @wdev: Pointer to wireless device + * @tb: Pointer to nl attributes + * + * This function is invoked to check whether vendor scan needs + * probe req source addr , if so populates mac_addr and mac_addr_mask + * in scan request with nl attrs. + * + * Return: 0 - on success, negative value on failure + */ + +static int wlan_hdd_vendor_scan_random_attr(struct wiphy *wiphy, + struct cfg80211_scan_request *request, + struct wireless_dev *wdev, + struct nlattr **tb) +{ + uint32_t i; + + if (!(request->flags & NL80211_SCAN_FLAG_RANDOM_ADDR)) + return 0; + + if (!(wiphy->features & NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR) || + (wdev->current_bss)) { + hdd_err("SCAN RANDOMIZATION not supported"); + return -EOPNOTSUPP; + } + + if (!tb[QCA_WLAN_VENDOR_ATTR_SCAN_MAC] || + !tb[QCA_WLAN_VENDOR_ATTR_SCAN_MAC_MASK]) + return -EINVAL; + + qdf_mem_copy(request->mac_addr, + nla_data(tb[QCA_WLAN_VENDOR_ATTR_SCAN_MAC]), + QDF_MAC_ADDR_SIZE); + qdf_mem_copy(request->mac_addr_mask, + nla_data(tb[QCA_WLAN_VENDOR_ATTR_SCAN_MAC_MASK]), + QDF_MAC_ADDR_SIZE); + + /* avoid configure on multicast address */ + if (!qdf_is_group_addr(request->mac_addr_mask) || + qdf_is_group_addr(request->mac_addr)) + return -EINVAL; + + for (i = 0; i < ETH_ALEN; i++) + request->mac_addr[i] &= request->mac_addr_mask[i]; + + return 0; +} +#else +static int wlan_hdd_vendor_scan_random_attr(struct wiphy *wiphy, + struct cfg80211_scan_request *request, + struct wireless_dev *wdev, + struct nlattr **tb) +{ + return 0; +} +#endif + +/** + * __wlan_hdd_cfg80211_vendor_scan() - API to process venor scan request + * @wiphy: Pointer to wiphy + * @wdev: Pointer to net device + * @data : Pointer to the data + * @data_len : length of the data + * + * API to process venor scan request. + * + * Return: return 0 on success and negative error code on failure + */ +static int __wlan_hdd_cfg80211_vendor_scan(struct wiphy *wiphy, + struct wireless_dev *wdev, const void *data, + int data_len) +{ + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_SCAN_MAX + 1]; + struct cfg80211_scan_request *request = NULL; + struct nlattr *attr; + enum nl80211_band band; + uint8_t n_channels = 0, n_ssid = 0, ie_len = 0; + uint32_t tmp, count, j; + unsigned int len; + struct ieee80211_channel *chan; + hdd_context_t *hdd_ctx = wiphy_priv(wiphy); + int ret; + + ENTER_DEV(wdev->netdev); + + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_SCAN_MAX, data, + data_len, scan_policy)) { + hdd_err("Invalid ATTR"); + return -EINVAL; + } + + if (tb[QCA_WLAN_VENDOR_ATTR_SCAN_FREQUENCIES]) { + nla_for_each_nested(attr, + tb[QCA_WLAN_VENDOR_ATTR_SCAN_FREQUENCIES], tmp) + n_channels++; + } else { + for (band = 0; band < NUM_NL80211_BANDS; band++) + if (wiphy->bands[band]) + n_channels += wiphy->bands[band]->n_channels; + } + + if (MAX_CHANNEL < n_channels) { + hdd_err("Exceed max number of channels: %d", n_channels); + return -EINVAL; + } + if (tb[QCA_WLAN_VENDOR_ATTR_SCAN_SSIDS]) + nla_for_each_nested(attr, + tb[QCA_WLAN_VENDOR_ATTR_SCAN_SSIDS], tmp) + n_ssid++; + + if (MAX_SCAN_SSID < n_ssid) { + hdd_err("Exceed max number of SSID: %d", n_ssid); + return -EINVAL; + } + + if (tb[QCA_WLAN_VENDOR_ATTR_SCAN_IE]) + ie_len = nla_len(tb[QCA_WLAN_VENDOR_ATTR_SCAN_IE]); + else + ie_len = 0; + + len = sizeof(*request) + (sizeof(*request->ssids) * n_ssid) + + (sizeof(*request->channels) * n_channels) + ie_len; + + request = qdf_mem_malloc(len); + if (!request) + goto error; + if (n_ssid) + request->ssids = (void *)&request->channels[n_channels]; + request->n_ssids = n_ssid; + if (ie_len) { + if (request->ssids) + request->ie = (void *)(request->ssids + n_ssid); + else + request->ie = (void *)(request->channels + n_channels); + } + + count = 0; + if (tb[QCA_WLAN_VENDOR_ATTR_SCAN_FREQUENCIES]) { + nla_for_each_nested(attr, + tb[QCA_WLAN_VENDOR_ATTR_SCAN_FREQUENCIES], + tmp) { + if (nla_len(attr) != sizeof(uint32_t)) { + hdd_err("len is not correct for frequency %d", + count); + goto error; + } + chan = __ieee80211_get_channel(wiphy, + nla_get_u32(attr)); + if (!chan) + goto error; + if (chan->flags & IEEE80211_CHAN_DISABLED) + continue; + request->channels[count] = chan; + count++; + } + } else { + for (band = 0; band < NUM_NL80211_BANDS; band++) { + if (!wiphy->bands[band]) + continue; + for (j = 0; j < wiphy->bands[band]->n_channels; + j++) { + chan = &wiphy->bands[band]->channels[j]; + if (chan->flags & IEEE80211_CHAN_DISABLED) + continue; + request->channels[count] = chan; + count++; + } + } + } + + if (!count) + goto error; + + request->n_channels = count; + count = 0; + if (tb[QCA_WLAN_VENDOR_ATTR_SCAN_SSIDS]) { + nla_for_each_nested(attr, tb[QCA_WLAN_VENDOR_ATTR_SCAN_SSIDS], + tmp) { + request->ssids[count].ssid_len = nla_len(attr); + if (request->ssids[count].ssid_len > + SIR_MAC_MAX_SSID_LENGTH) { + hdd_err("SSID Len %d is not correct for network %d", + request->ssids[count].ssid_len, count); + goto error; + } + memcpy(request->ssids[count].ssid, nla_data(attr), + nla_len(attr)); + count++; + } + } + + if (tb[QCA_WLAN_VENDOR_ATTR_SCAN_IE]) { + request->ie_len = nla_len(tb[QCA_WLAN_VENDOR_ATTR_SCAN_IE]); + memcpy((void *)request->ie, + nla_data(tb[QCA_WLAN_VENDOR_ATTR_SCAN_IE]), + request->ie_len); + } + + for (count = 0; count < NUM_NL80211_BANDS; count++) + if (wiphy->bands[count]) + request->rates[count] = + (1 << wiphy->bands[count]->n_bitrates) - 1; + + if (tb[QCA_WLAN_VENDOR_ATTR_SCAN_SUPP_RATES]) { + nla_for_each_nested(attr, + tb[QCA_WLAN_VENDOR_ATTR_SCAN_SUPP_RATES], + tmp) { + band = nla_type(attr); + if (band >= NUM_NL80211_BANDS) + continue; + if (!wiphy->bands[band]) + continue; + request->rates[band] = + wlan_hdd_get_rates(wiphy, + band, nla_data(attr), + nla_len(attr)); + } + } + + if (tb[QCA_WLAN_VENDOR_ATTR_SCAN_FLAGS]) { + request->flags = + nla_get_u32(tb[QCA_WLAN_VENDOR_ATTR_SCAN_FLAGS]); + if ((request->flags & NL80211_SCAN_FLAG_LOW_PRIORITY) && + !(wiphy->features & NL80211_FEATURE_LOW_PRIORITY_SCAN)) { + hdd_err("LOW PRIORITY SCAN not supported"); + goto error; + } + + if (wlan_hdd_vendor_scan_random_attr(wiphy, request, wdev, tb)) + goto error; + } + + if (tb[QCA_WLAN_VENDOR_ATTR_SCAN_BSSID]) { + if (nla_len(tb[QCA_WLAN_VENDOR_ATTR_SCAN_BSSID]) < + QDF_MAC_ADDR_SIZE) { + hdd_err("invalid bssid length"); + goto error; + } + wlan_hdd_copy_bssid(request, + nla_data(tb[QCA_WLAN_VENDOR_ATTR_SCAN_BSSID])); + } + + if (tb[QCA_WLAN_VENDOR_ATTR_SCAN_TX_NO_CCK_RATE]) + request->no_cck = + nla_get_flag(tb[QCA_WLAN_VENDOR_ATTR_SCAN_TX_NO_CCK_RATE]); + request->wdev = wdev; + request->wiphy = wiphy; + request->scan_start = jiffies; + + ret = __wlan_hdd_cfg80211_scan(wiphy, request, VENDOR_SCAN); + if (0 != ret) { + hdd_err("Scan Failed. Ret = %d", ret); + qdf_mem_free(request); + return ret; + } + ret = wlan_hdd_send_scan_start_event(wiphy, wdev, (uintptr_t)request); + + return ret; +error: + hdd_err("Scan Request Failed"); + qdf_mem_free(request); + return -EINVAL; +} + +/** + * wlan_hdd_cfg80211_vendor_scan() -API to process venor scan request + * @wiphy: Pointer to wiphy + * @dev: Pointer to net device + * @data : Pointer to the data + * @data_len : length of the data + * + * This is called from userspace to request scan. + * + * Return: Return the Success or Failure code. + */ +int wlan_hdd_cfg80211_vendor_scan(struct wiphy *wiphy, + struct wireless_dev *wdev, const void *data, + int data_len) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_vendor_scan(wiphy, wdev, + data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} +/** + * wlan_hdd_get_scanid() - API to get the scan id + * from the scan cookie attribute. + * @hdd_ctx: Pointer to HDD context + * @scan_id: Pointer to scan id + * @cookie : Scan cookie attribute + * + * API to get the scan id from the scan cookie attribute + * sent from supplicant by matching scan request. + * + * Return: 0 for success, non zero for failure + */ +static int wlan_hdd_get_scanid(hdd_context_t *hdd_ctx, + uint32_t *scan_id, uint64_t cookie) +{ + struct hdd_scan_req *scan_req; + qdf_list_node_t *node = NULL; + qdf_list_node_t *ptr_node = NULL; + int ret = -EINVAL; + + qdf_spin_lock(&hdd_ctx->hdd_scan_req_q_lock); + if (qdf_list_empty(&hdd_ctx->hdd_scan_req_q)) { + qdf_spin_unlock(&hdd_ctx->hdd_scan_req_q_lock); + return ret; + } + + if (QDF_STATUS_SUCCESS != + qdf_list_peek_front(&hdd_ctx->hdd_scan_req_q, + &ptr_node)) { + qdf_spin_unlock(&hdd_ctx->hdd_scan_req_q_lock); + return ret; + } + + do { + node = ptr_node; + scan_req = container_of(node, struct hdd_scan_req, node); + + if (cookie == + (uintptr_t)(scan_req->scan_request)) { + *scan_id = scan_req->scan_id; + ret = 0; + break; + } + } while (QDF_STATUS_SUCCESS == + qdf_list_peek_next(&hdd_ctx->hdd_scan_req_q, + node, &ptr_node)); + + qdf_spin_unlock(&hdd_ctx->hdd_scan_req_q_lock); + + return ret; + +} +/** + * __wlan_hdd_vendor_abort_scan() - API to process vendor command for + * abort scan + * @wiphy: Pointer to wiphy + * @wdev: Pointer to net device + * @data : Pointer to the data + * @data_len : length of the data + * + * API to process vendor abort scan + * + * Return: zero for success and non zero for failure + */ +static int __wlan_hdd_vendor_abort_scan( + struct wiphy *wiphy, const void *data, + int data_len) +{ + hdd_context_t *hdd_ctx = wiphy_priv(wiphy); + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_SCAN_MAX + 1]; + uint32_t scan_id; + uint64_t cookie; + int ret; + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EINVAL; + } + + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + ret = -EINVAL; + if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_SCAN_MAX, data, + data_len, scan_policy)) { + hdd_err("Invalid ATTR"); + return ret; + } + + if (tb[QCA_WLAN_VENDOR_ATTR_SCAN_COOKIE]) { + cookie = nla_get_u64( + tb[QCA_WLAN_VENDOR_ATTR_SCAN_COOKIE]); + ret = wlan_hdd_get_scanid(hdd_ctx, + &scan_id, + cookie); + if (ret != 0) + return ret; + hdd_abort_mac_scan(hdd_ctx, + HDD_SESSION_ID_INVALID, + scan_id, + eCSR_SCAN_ABORT_DEFAULT); + } + + return ret; +} + + +/** + * wlan_hdd_vendor_abort_scan() - API to process vendor command for + * abort scan + * @wiphy: Pointer to wiphy + * @wdev: Pointer to net device + * @data : Pointer to the data + * @data_len : length of the data + * + * This is called from supplicant to abort scan + * + * Return: zero for success and non zero for failure + */ +int wlan_hdd_vendor_abort_scan( + struct wiphy *wiphy, struct wireless_dev *wdev, + const void *data, int data_len) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_vendor_abort_scan(wiphy, + data, + data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * wlan_hdd_scan_abort() - abort ongoing scan + * @pAdapter: Pointer to interface adapter + * + * Return: 0 for success, non zero for failure + */ +int wlan_hdd_scan_abort(hdd_adapter_t *pAdapter) +{ + hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + hdd_scaninfo_t *pScanInfo = NULL; + unsigned long rc; + + pScanInfo = &pAdapter->scan_info; + + if (pScanInfo->mScanPending) { + INIT_COMPLETION(pScanInfo->abortscan_event_var); + hdd_abort_mac_scan(pHddCtx, pAdapter->sessionId, + INVALID_SCAN_ID, eCSR_SCAN_ABORT_DEFAULT); + + rc = wait_for_completion_timeout( + &pScanInfo->abortscan_event_var, + msecs_to_jiffies(5000)); + if (!rc) { + hdd_err("Timeout occurred while waiting for abort scan"); + return -ETIME; + } + } + return 0; +} + +#ifdef FEATURE_WLAN_SCAN_PNO +/** + * hdd_sched_scan_callback - scheduled scan callback + * @callbackContext: Callback context + * @pPrefNetworkFoundInd: Preferred network found indication + * + * This is a callback function that is registerd with SME that is + * invoked when a preferred network is discovered by firmware. + * + * Return: none + */ +static void +hdd_sched_scan_callback(void *callbackContext, + tSirPrefNetworkFoundInd *pPrefNetworkFoundInd) +{ + int ret; + hdd_adapter_t *pAdapter = (hdd_adapter_t *) callbackContext; + hdd_context_t *pHddCtx; + + ENTER(); + + if (NULL == pAdapter) { + hdd_err("HDD adapter is Null"); + return; + } + + pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + if (NULL == pHddCtx) { + hdd_err("HDD context is Null!!!"); + return; + } + + qdf_spin_lock(&pHddCtx->sched_scan_lock); + if (true == pHddCtx->isWiphySuspended) { + pHddCtx->isSchedScanUpdatePending = true; + qdf_spin_unlock(&pHddCtx->sched_scan_lock); + hdd_notice("Update cfg80211 scan database after it resume"); + return; + } + qdf_spin_unlock(&pHddCtx->sched_scan_lock); + + ret = wlan_hdd_cfg80211_update_bss(pHddCtx->wiphy, pAdapter, 0); + + if (ret < 0) { + hdd_notice("NO SCAN result"); + } else { + /* + * Acquire wakelock to handle the case where APP's tries to + * suspend immediately after the driver gets connect + * request(i.e after pno) from supplicant, this result in + * app's is suspending and not able to process the connect + * request to AP + */ + hdd_prevent_suspend_timeout(1000, + WIFI_POWER_EVENT_WAKELOCK_SCAN); + } + + cfg80211_sched_scan_results(pHddCtx->wiphy); + hdd_notice("cfg80211 scan result database updated"); +} + +/** + * wlan_hdd_is_pno_allowed() - Check if PNO is allowed + * @adapter: HDD Device Adapter + * + * The PNO Start request is coming from upper layers. + * It is to be allowed only for Infra STA device type + * and the link should be in a disconnected state. + * + * Return: Success if PNO is allowed, Failure otherwise. + */ +static QDF_STATUS wlan_hdd_is_pno_allowed(hdd_adapter_t *adapter) +{ + hdd_notice("dev_mode=%d, conn_state=%d, session ID=%d", + adapter->device_mode, + adapter->sessionCtx.station.conn_info.connState, + adapter->sessionId); + if ((adapter->device_mode == QDF_STA_MODE) && + (eConnectionState_NotConnected == + adapter->sessionCtx.station.conn_info.connState)) + return QDF_STATUS_SUCCESS; + else + return QDF_STATUS_E_FAILURE; + +} + +#if ((LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)) || \ + defined(CFG80211_MULTI_SCAN_PLAN_BACKPORT)) && \ + defined(FEATURE_WLAN_SCAN_PNO) +/** + * hdd_config_sched_scan_plan() - configures the sched scan plans + * from the framework. + * @pno_req: pointer to PNO scan request + * @request: pointer to scan request from framework + * + * Return: None + */ +static void hdd_config_sched_scan_plan(tpSirPNOScanReq pno_req, + struct cfg80211_sched_scan_request *request, + hdd_context_t *hdd_ctx) +{ + pno_req->delay_start_time = request->delay; + /* + * As of now max 2 scan plans were supported by firmware + * if number of scan plan supported by firmware increased below logic + * must change. + */ + if (request->n_scan_plans == SIR_PNO_MAX_PLAN_REQUEST) { + pno_req->fast_scan_period = + request->scan_plans[0].interval * MSEC_PER_SEC; + pno_req->fast_scan_max_cycles = + request->scan_plans[0].iterations; + pno_req->slow_scan_period = + request->scan_plans[1].interval * MSEC_PER_SEC; + hdd_notice("Base scan interval: %d sec, scan cycles: %d, slow scan interval %d", + request->scan_plans[0].interval, + request->scan_plans[0].iterations, + request->scan_plans[1].interval); + } else if (request->n_scan_plans == 1) { + pno_req->fast_scan_period = + request->scan_plans[0].interval * MSEC_PER_SEC; + /* + * if only one scan plan is configured from framework + * then both fast and slow scan should be configured with the + * same value that is why fast scan cycles are hardcoded to one + */ + pno_req->fast_scan_max_cycles = 1; + pno_req->slow_scan_period = + request->scan_plans[0].interval * MSEC_PER_SEC; + } else { + hdd_err("Invalid number of scan plans %d !!", + request->n_scan_plans); + } +} +#else +static void hdd_config_sched_scan_plan(tpSirPNOScanReq pno_req, + struct cfg80211_sched_scan_request *request, + hdd_context_t *hdd_ctx) +{ + pno_req->fast_scan_period = request->interval; + pno_req->fast_scan_max_cycles = + hdd_ctx->config->configPNOScanTimerRepeatValue; + pno_req->slow_scan_period = + hdd_ctx->config->pno_slow_scan_multiplier * + pno_req->fast_scan_period; + hdd_notice("Base scan interval: %d sec PNOScanTimerRepeatValue: %d", + (request->interval / 1000), + hdd_ctx->config->configPNOScanTimerRepeatValue); +} +#endif + +/** + * __wlan_hdd_cfg80211_sched_scan_start() - cfg80211 scheduled scan(pno) start + * @wiphy: Pointer to wiphy + * @dev: Pointer network device + * @request: Pointer to cfg80211 scheduled scan start request + * + * Return: 0 for success, non zero for failure + */ +static int __wlan_hdd_cfg80211_sched_scan_start(struct wiphy *wiphy, + struct net_device *dev, + struct + cfg80211_sched_scan_request + *request) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + tpSirPNOScanReq pPnoRequest = NULL; + hdd_context_t *pHddCtx; + tHalHandle hHal; + uint32_t i, indx, num_ch, j; + u8 valid_ch[WNI_CFG_VALID_CHANNEL_LIST_LEN] = { 0 }; + u8 channels_allowed[WNI_CFG_VALID_CHANNEL_LIST_LEN] = { 0 }; + uint32_t num_channels_allowed = WNI_CFG_VALID_CHANNEL_LIST_LEN; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + int ret = 0; + hdd_scaninfo_t *pScanInfo = &pAdapter->scan_info; + struct hdd_config *config = NULL; + uint32_t num_ignore_dfs_ch = 0; + + ENTER(); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EINVAL; + } + + if (wlan_hdd_validate_session_id(pAdapter->sessionId)) { + hdd_err("invalid session id: %d", pAdapter->sessionId); + return -EINVAL; + } + + pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + ret = wlan_hdd_validate_context(pHddCtx); + + if (0 != ret) + return ret; + + if (!sme_is_session_id_valid(pHddCtx->hHal, pAdapter->sessionId)) + return -EINVAL; + + config = pHddCtx->config; + hHal = WLAN_HDD_GET_HAL_CTX(pAdapter); + if (NULL == hHal) { + hdd_err("HAL context is Null!!!"); + return -EINVAL; + } + + if ((QDF_STA_MODE == pAdapter->device_mode) && + (eConnectionState_Connecting == + (WLAN_HDD_GET_STATION_CTX_PTR(pAdapter))->conn_info.connState)) { + hdd_err("%p(%d) Connection in progress: sched_scan_start denied (EBUSY)", + WLAN_HDD_GET_STATION_CTX_PTR(pAdapter), + pAdapter->sessionId); + return -EBUSY; + } + + MTRACE(qdf_trace(QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_CFG80211_SCHED_SCAN_START, + pAdapter->sessionId, pAdapter->device_mode)); + /* + * The current umac is unable to handle the SCAN_PREEMPT and SCAN_DEQUEUED + * so its necessary to terminate the existing scan which is already issued + * otherwise the host won't enter into the suspend state due to the reason + * that the wlan wakelock which was held in the wlan_hdd_cfg80211_scan + * function. + */ + if (true == pScanInfo->mScanPending) { + ret = wlan_hdd_scan_abort(pAdapter); + if (ret < 0) { + hdd_err("aborting the existing scan is unsuccessful"); + return -EBUSY; + } + } + + if (QDF_STATUS_E_FAILURE == wlan_hdd_is_pno_allowed(pAdapter)) { + hdd_err("pno is not allowed"); + return -ENOTSUPP; + } + + pPnoRequest = (tpSirPNOScanReq) qdf_mem_malloc(sizeof(tSirPNOScanReq)); + if (NULL == pPnoRequest) { + hdd_err("qdf_mem_malloc failed"); + return -ENOMEM; + } + + pPnoRequest->enable = 1; /*Enable PNO */ + pPnoRequest->ucNetworksCount = request->n_match_sets; + + if ((!pPnoRequest->ucNetworksCount) || + (pPnoRequest->ucNetworksCount > SIR_PNO_MAX_SUPP_NETWORKS)) { + hdd_err("Network input is not correct %d", + pPnoRequest->ucNetworksCount); + ret = -EINVAL; + goto error; + } + + if (SIR_PNO_MAX_NETW_CHANNELS_EX < request->n_channels) { + hdd_err("Incorrect number of channels %d", + request->n_channels); + ret = -EINVAL; + goto error; + } + + /* Framework provides one set of channels(all) + * common for all saved profile */ + if (0 != sme_cfg_get_str(hHal, WNI_CFG_VALID_CHANNEL_LIST, + channels_allowed, &num_channels_allowed)) { + hdd_err("failed to get valid channel list"); + ret = -EINVAL; + goto error; + } + /* Checking each channel against allowed channel list */ + num_ch = 0; + if (request->n_channels) { + char chList[(request->n_channels * 5) + 1]; + int len; + for (i = 0, len = 0; i < request->n_channels; i++) { + for (indx = 0; indx < num_channels_allowed; indx++) { + if (request->channels[i]->hw_value == + channels_allowed[indx]) { + + if ((!config->enable_dfs_pno_chnl_scan) + && (CHANNEL_STATE_DFS == + cds_get_channel_state( + channels_allowed[indx]))) { + hdd_notice("Dropping DFS channel : %d", + channels_allowed[indx]); + num_ignore_dfs_ch++; + break; + } + if (!cds_is_dsrc_channel( + cds_chan_to_freq( + request->channels[i]->hw_value))) { + valid_ch[num_ch++] = request-> + channels[i]->hw_value; + len += snprintf(chList + len, + 5, "%d ", + request->channels[i]-> + hw_value); + } + break; + } + } + } + hdd_notice("Channel-List: %s ", chList); + + /* If all channels are DFS and dropped, + * then ignore the PNO request + */ + if (!num_ch) { + hdd_notice("Channel list empty due to filtering of DSRC,DFS channels"); + ret = -EINVAL; + goto error; + } + + } + /* Filling per profile params */ + for (i = 0; i < pPnoRequest->ucNetworksCount; i++) { + pPnoRequest->aNetworks[i].ssId.length = + request->match_sets[i].ssid.ssid_len; + + if ((0 == pPnoRequest->aNetworks[i].ssId.length) || + (pPnoRequest->aNetworks[i].ssId.length > 32)) { + hdd_err(" SSID Len %d is not correct for network %d", + pPnoRequest->aNetworks[i].ssId.length, i); + ret = -EINVAL; + goto error; + } + + memcpy(pPnoRequest->aNetworks[i].ssId.ssId, + request->match_sets[i].ssid.ssid, + request->match_sets[i].ssid.ssid_len); + pPnoRequest->aNetworks[i].authentication = 0; /*eAUTH_TYPE_ANY */ + pPnoRequest->aNetworks[i].encryption = 0; /*eED_ANY */ + pPnoRequest->aNetworks[i].bcastNetwType = 0; /*eBCAST_UNKNOWN */ + + /*Copying list of valid channel into request */ + memcpy(pPnoRequest->aNetworks[i].aChannels, valid_ch, num_ch); + pPnoRequest->aNetworks[i].ucChannelCount = num_ch; + pPnoRequest->aNetworks[i].rssiThreshold = + request->match_sets[i].rssi_thold; + } + /* set scan to passive if no SSIDs are specified in the request */ + if (0 == request->n_ssids) + pPnoRequest->do_passive_scan = true; + else + pPnoRequest->do_passive_scan = false; + + for (i = 0; i < request->n_ssids; i++) { + j = 0; + while (j < pPnoRequest->ucNetworksCount) { + if ((pPnoRequest->aNetworks[j].ssId.length == + request->ssids[i].ssid_len) && + (0 == memcmp(pPnoRequest->aNetworks[j].ssId.ssId, + request->ssids[i].ssid, + pPnoRequest->aNetworks[j].ssId. + length))) { + pPnoRequest->aNetworks[j].bcastNetwType = + eBCAST_HIDDEN; + break; + } + j++; + } + } + hdd_notice("Number of hidden networks being Configured = %d", + request->n_ssids); + + /* + * Before Kernel 4.4 + * Driver gets only one time interval which is hard coded in + * supplicant for 10000ms. + * + * After Kernel 4.4 + * User can configure multiple scan_plans, each scan would have + * separate scan cycle and interval. (interval is in unit of second.) + * For our use case, we would only have supplicant set one scan_plan, + * and firmware also support only one as well, so pick up the first + * index. + * + * Taking power consumption into account + * firmware after gPNOScanTimerRepeatValue times fast_scan_period + * switches slow_scan_period. This is less frequent scans and firmware + * shall be in slow_scan_period mode until next PNO Start. + */ + hdd_config_sched_scan_plan(pPnoRequest, request, pHddCtx); + + hdd_info("Base scan interval: %d sec PNOScanTimerRepeatValue: %d", + (pPnoRequest->fast_scan_period / 1000), + config->configPNOScanTimerRepeatValue); + + pPnoRequest->modePNO = SIR_PNO_MODE_IMMEDIATE; + + hdd_info("SessionId %d, enable %d, modePNO %d", + pAdapter->sessionId, pPnoRequest->enable, pPnoRequest->modePNO); + + wlan_hdd_update_scan_rand_attrs((void *)pPnoRequest, (void *)request, + WLAN_HDD_PNO_SCAN); + + status = sme_set_preferred_network_list(WLAN_HDD_GET_HAL_CTX(pAdapter), + pPnoRequest, + pAdapter->sessionId, + hdd_sched_scan_callback, + pAdapter); + if (QDF_STATUS_SUCCESS != status) { + hdd_err("Failed to enable PNO"); + ret = -EINVAL; + goto error; + } + + hdd_notice("PNO scanRequest offloaded"); + +error: + qdf_mem_free(pPnoRequest); + EXIT(); + return ret; +} + +/** + * wlan_hdd_cfg80211_sched_scan_start() - cfg80211 scheduled scan(pno) start + * @wiphy: Pointer to wiphy + * @dev: Pointer network device + * @request: Pointer to cfg80211 scheduled scan start request + * + * Return: 0 for success, non zero for failure + */ +int wlan_hdd_cfg80211_sched_scan_start(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_sched_scan_request + *request) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_sched_scan_start(wiphy, dev, request); + cds_ssr_unprotect(__func__); + + return ret; +} + +int wlan_hdd_sched_scan_stop(struct net_device *dev) +{ + QDF_STATUS status; + hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *hdd_ctx; + tHalHandle hHal; + tSirPNOScanReq *pno_req = NULL; + int ret = 0; + + ENTER_DEV(dev); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + ret = -EINVAL; + goto exit; + } + + if (wlan_hdd_validate_session_id(adapter->sessionId)) { + hdd_err("invalid session id: %d", adapter->sessionId); + ret = -EINVAL; + goto exit; + } + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + if (NULL == hdd_ctx) { + hdd_err("HDD context is Null"); + ret = -ENODEV; + goto exit; + } + + hHal = WLAN_HDD_GET_HAL_CTX(adapter); + if (NULL == hHal) { + hdd_err(" HAL context is Null!!!"); + ret = -EINVAL; + goto exit; + } + + pno_req = (tpSirPNOScanReq) qdf_mem_malloc(sizeof(tSirPNOScanReq)); + if (NULL == pno_req) { + hdd_err("qdf_mem_malloc failed"); + ret = -ENOMEM; + goto exit; + } + + MTRACE(qdf_trace(QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_CFG80211_SCHED_SCAN_STOP, + adapter->sessionId, adapter->device_mode)); + + /* Disable PNO */ + pno_req->enable = 0; + pno_req->ucNetworksCount = 0; + status = sme_set_preferred_network_list(hHal, pno_req, + adapter->sessionId, + NULL, adapter); + qdf_mem_free(pno_req); + + if (QDF_STATUS_SUCCESS != status) { + hdd_err("Failed to disabled PNO"); + ret = -EINVAL; + goto exit; + } + + hdd_notice("PNO scan disabled"); + +exit: + EXIT(); + return ret; +} + +/** + * __wlan_hdd_cfg80211_sched_scan_stop() - stop cfg80211 scheduled scan(pno) + * @dev: Pointer network device + * + * This is a wrapper around wlan_hdd_sched_scan_stop() that returns success + * in the event that the driver is currently recovering or unloading. This + * prevents a race condition where we get a scan stop from kernel during + * a driver unload from PLD. + * + * Return: 0 for success, non zero for failure + */ +static int __wlan_hdd_cfg80211_sched_scan_stop(struct net_device *dev) +{ + int err; + + ENTER_DEV(dev); + + /* The return 0 is intentional when Recovery and Load/Unload in + * progress. We did observe a crash due to a return of + * failure in sched_scan_stop , especially for a case where the unload + * of the happens at the same time. The function __cfg80211_stop_sched_scan + * was clearing rdev->sched_scan_req only when the sched_scan_stop returns + * success. If it returns a failure , then its next invocation due to the + * clean up of the second interface will have the dev pointer corresponding + * to the first one leading to a crash. + */ + if (cds_is_driver_recovering()) { + hdd_err("Recovery in Progress. State: 0x%x Ignore!!!", + cds_get_driver_state()); + return 0; + } + + if (cds_is_load_or_unload_in_progress()) { + hdd_err("Unload/Load in Progress, state: 0x%x. Ignore!!!", + cds_get_driver_state()); + return 0; + } + + err = wlan_hdd_sched_scan_stop(dev); + + EXIT(); + return err; +} + +int wlan_hdd_cfg80211_sched_scan_stop(struct wiphy *wiphy, + struct net_device *dev) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_sched_scan_stop(dev); + cds_ssr_unprotect(__func__); + + return ret; +} +#endif /*FEATURE_WLAN_SCAN_PNO */ + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 5, 0)) || \ + defined(CFG80211_ABORT_SCAN) +/** + * __wlan_hdd_cfg80211_abort_scan() - cfg80211 abort scan api + * @wiphy: Pointer to wiphy + * @wdev: Pointer to wireless device structure + * + * This function is used to abort an ongoing scan + * + * Return: None + */ +static void __wlan_hdd_cfg80211_abort_scan(struct wiphy *wiphy, + struct wireless_dev *wdev) +{ + struct net_device *dev = wdev->netdev; + hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *hdd_ctx = wiphy_priv(wiphy); + int ret; + + ENTER_DEV(dev); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return; + } + + if (wlan_hdd_validate_session_id(adapter->sessionId)) { + hdd_err("invalid session id: %d", adapter->sessionId); + return; + } + + ret = wlan_hdd_validate_context(hdd_ctx); + if (!ret) + return; + + wlan_hdd_scan_abort(adapter); + + EXIT(); +} + +/** + * wlan_hdd_cfg80211_abort_scan - cfg80211 abort scan api + * @wiphy: Pointer to wiphy + * @wdev: Pointer to wireless device structure + * + * Wrapper to __wlan_hdd_cfg80211_abort_scan() - + * function is used to abort an ongoing scan + * + * Return: None + */ +void wlan_hdd_cfg80211_abort_scan(struct wiphy *wiphy, + struct wireless_dev *wdev) +{ + cds_ssr_protect(__func__); + __wlan_hdd_cfg80211_abort_scan(wiphy, wdev); + cds_ssr_unprotect(__func__); +} +#endif + +/** + * hdd_cleanup_scan_queue() - remove entries in scan queue + * + * Removes entries in scan queue and sends scan complete event to NL + * Return: None + */ +void hdd_cleanup_scan_queue(hdd_context_t *hdd_ctx) +{ + struct hdd_scan_req *hdd_scan_req; + qdf_list_node_t *node = NULL; + struct cfg80211_scan_request *req; + hdd_adapter_t *adapter; + uint8_t source; + bool aborted = true; + + if (NULL == hdd_ctx) { + hdd_err("HDD context is Null"); + return; + } + + qdf_spin_lock(&hdd_ctx->hdd_scan_req_q_lock); + while (!qdf_list_empty(&hdd_ctx->hdd_scan_req_q)) { + if (QDF_STATUS_SUCCESS != + qdf_list_remove_front(&hdd_ctx->hdd_scan_req_q, + &node)) { + qdf_spin_unlock(&hdd_ctx->hdd_scan_req_q_lock); + hdd_err("Failed to remove scan request"); + return; + } + qdf_spin_unlock(&hdd_ctx->hdd_scan_req_q_lock); + hdd_scan_req = (struct hdd_scan_req *)node; + req = hdd_scan_req->scan_request; + source = hdd_scan_req->source; + adapter = hdd_scan_req->adapter; + if (WLAN_HDD_ADAPTER_MAGIC != adapter->magic) { + hdd_err("HDD adapter magic is invalid"); + } else if (!req) { + hdd_debug("pending scan is wext triggered"); + } else { + if (NL_SCAN == source) + hdd_cfg80211_scan_done(adapter, req, aborted); + else + hdd_vendor_scan_callback(adapter, req, aborted); + hdd_info("removed Scan id: %d, req = %p", + hdd_scan_req->scan_id, req); + } + qdf_mem_free(hdd_scan_req); + qdf_spin_lock(&hdd_ctx->hdd_scan_req_q_lock); + } + qdf_spin_unlock(&hdd_ctx->hdd_scan_req_q_lock); + + return; +} + +/** + * hdd_scan_context_destroy() - Destroy scan context + * @hdd_ctx: HDD context. + * + * Destroy scan context. + * + * Return: None. + */ +void hdd_scan_context_destroy(hdd_context_t *hdd_ctx) +{ + qdf_list_destroy(&hdd_ctx->hdd_scan_req_q); + qdf_spinlock_destroy(&hdd_ctx->sched_scan_lock); +} + +/** + * hdd_scan_context_init() - Initialize scan context + * @hdd_ctx: HDD context. + * + * Initialize scan related resources like spin lock and lists. + * + * Return: 0 on success and errno on failure. + */ +int hdd_scan_context_init(hdd_context_t *hdd_ctx) +{ + qdf_spinlock_create(&hdd_ctx->sched_scan_lock); + + qdf_spinlock_create(&hdd_ctx->hdd_scan_req_q_lock); + qdf_list_create(&hdd_ctx->hdd_scan_req_q, CFG_MAX_SCAN_COUNT_MAX); + + return 0; +} diff --git a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_scan.h b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_scan.h new file mode 100644 index 0000000000000000000000000000000000000000..9ffc9ac06092115d60b06afc1901e18cfe7faf82 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_scan.h @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/** + * DOC : wlan_hdd_scan.h + * + * WLAN Host Device Driver scan related implementation + * + */ + +#if !defined(WLAN_HDD_SCAN_H) +#define WLAN_HDD_SCAN_H + +#include "wlan_hdd_main.h" + +#define MAX_PENDING_LOG 5 + +/* (30 Mins) */ +#define MIN_TIME_REQUIRED_FOR_NEXT_BUG_REPORT (30 * 60 * 1000) + +/* + * enum scan_source - scan request source + * + * @NL_SCAN: Scan initiated from NL + * @VENDOR_SCAN: Scan intiated from vendor command +*/ +enum scan_source { + NL_SCAN, + VENDOR_SCAN, +}; + +/** + * enum wlan_hdd_scan_type - type of scan + * @WLAN_HDD_HOST_SCAN: refers to scan request from cfg80211_ops "scan" + * @WLAN_HDD_PNO_SCAN: refers to scan request is from "sched_scan_start" + * + * driver uses this enum to identify source of scan + * + */ +enum wlan_hdd_scan_type { + WLAN_HDD_HOST_SCAN, + WLAN_HDD_PNO_SCAN, +}; + +int iw_get_scan(struct net_device *dev, struct iw_request_info *info, + union iwreq_data *wrqu, char *extra); + +int iw_set_scan(struct net_device *dev, struct iw_request_info *info, + union iwreq_data *wrqu, char *extra); + +int hdd_scan_context_init(hdd_context_t *hdd_ctx); +void hdd_scan_context_destroy(hdd_context_t *hdd_ctx); + +int wlan_hdd_cfg80211_scan(struct wiphy *wiphy, + struct cfg80211_scan_request *request); + +#ifdef FEATURE_WLAN_SCAN_PNO +int wlan_hdd_cfg80211_sched_scan_start(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_sched_scan_request + *request); + +/** + * wlan_hdd_cfg80211_sched_scan_stop() - stop cfg80211 scheduled (PNO) scan + * @wiphy: Pointer to wiphy + * @dev: Pointer network device + * + * Note, this returns success if the driver is recovering or unloading to + * prevent race conditions between PLD initiating an unload and kernel + * initiating a scheduled scan stop via cfg80211. Unload is expected to stop + * any pending scheduled scans in this case. + * + * Return: 0 for success, non zero for failure + */ +int wlan_hdd_cfg80211_sched_scan_stop(struct wiphy *wiphy, + struct net_device *dev); + +/** + * wlan_hdd_sched_scan_stop() - stop scheduled (PNO) scans + * @dev: Pointer network device + * + * Return: 0 for success, non zero for failure + */ +int wlan_hdd_sched_scan_stop(struct net_device *dev); +#endif /* End of FEATURE_WLAN_SCAN_PNO */ + +int wlan_hdd_cfg80211_vendor_scan(struct wiphy *wiphy, + struct wireless_dev *wdev, const void *data, + int data_len); + +/** + * wlan_hdd_vendor_abort_scan() - API to process vendor command for + * abort scan + * @wiphy: Pointer to wiphy + * @wdev: Pointer to net device + * @data : Pointer to the data + * @data_len : length of the data + * + * This is called from supplicant to abort scan + * + * Return: zero for success and non zero for failure. + */ +int wlan_hdd_vendor_abort_scan( + struct wiphy *wiphy, struct wireless_dev *wdev, + const void *data, int data_len); + +void hdd_cleanup_scan_queue(hdd_context_t *hdd_ctx); + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 5, 0)) || \ + defined(CFG80211_ABORT_SCAN) +void wlan_hdd_cfg80211_abort_scan(struct wiphy *wiphy, + struct wireless_dev *wdev); +#endif +#endif /* end #if !defined(WLAN_HDD_SCAN_H) */ diff --git a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_softap_tx_rx.c b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_softap_tx_rx.c new file mode 100644 index 0000000000000000000000000000000000000000..71b0df92ca66d37b59d61bc271eddd15c5132ab1 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_softap_tx_rx.c @@ -0,0 +1,1059 @@ +/* + * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* Include files */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef IPA_OFFLOAD +#include +#endif + +/* Preprocessor definitions and constants */ +#undef QCA_HDD_SAP_DUMP_SK_BUFF + +/* Type declarations */ + +/* Function definitions and documenation */ +#ifdef QCA_HDD_SAP_DUMP_SK_BUFF +/** + * hdd_softap_dump_sk_buff() - Dump an skb + * @skb: skb to dump + * + * Return: None + */ +static void hdd_softap_dump_sk_buff(struct sk_buff *skb) +{ + QDF_TRACE(QDF_MODULE_ID_HDD_SAP_DATA, QDF_TRACE_LEVEL_INFO, + "%s: head = %p ", __func__, skb->head); + /* QDF_TRACE( QDF_MODULE_ID_HDD_SAP_DATA, QDF_TRACE_LEVEL_ERROR,"%s: data = %p ", __func__, skb->data); */ + QDF_TRACE(QDF_MODULE_ID_HDD_SAP_DATA, QDF_TRACE_LEVEL_INFO, + "%s: tail = %p ", __func__, skb->tail); + QDF_TRACE(QDF_MODULE_ID_HDD_SAP_DATA, QDF_TRACE_LEVEL_INFO, + "%s: end = %p ", __func__, skb->end); + QDF_TRACE(QDF_MODULE_ID_HDD_SAP_DATA, QDF_TRACE_LEVEL_INFO, + "%s: len = %d ", __func__, skb->len); + QDF_TRACE(QDF_MODULE_ID_HDD_SAP_DATA, QDF_TRACE_LEVEL_INFO, + "%s: data_len = %d ", __func__, skb->data_len); + QDF_TRACE(QDF_MODULE_ID_HDD_SAP_DATA, QDF_TRACE_LEVEL_INFO, + "%s: mac_len = %d", __func__, skb->mac_len); + + QDF_TRACE(QDF_MODULE_ID_HDD_SAP_DATA, QDF_TRACE_LEVEL_INFO, + "0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x ", skb->data[0], + skb->data[1], skb->data[2], skb->data[3], skb->data[4], + skb->data[5], skb->data[6], skb->data[7]); + QDF_TRACE(QDF_MODULE_ID_HDD_SAP_DATA, QDF_TRACE_LEVEL_INFO, + "0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x", skb->data[8], + skb->data[9], skb->data[10], skb->data[11], skb->data[12], + skb->data[13], skb->data[14], skb->data[15]); +} +#else +static void hdd_softap_dump_sk_buff(struct sk_buff *skb) +{ +} +#endif + +#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL +/** + * hdd_softap_tx_resume_timer_expired_handler() - TX Q resume timer handler + * @adapter_context: pointer to vdev adapter + * + * TX Q resume timer handler for SAP and P2P GO interface. If Blocked + * OS Q is not resumed during timeout period, to prevent permanent + * stall, resume OS Q forcefully for SAP and P2P GO interface. + * + * Return: None + */ +void hdd_softap_tx_resume_timer_expired_handler(void *adapter_context) +{ + hdd_adapter_t *pAdapter = (hdd_adapter_t *) adapter_context; + + if (!pAdapter) { + hdd_err("NULL adapter"); + return; + } + + hdd_notice("Enabling queues"); + wlan_hdd_netif_queue_control(pAdapter, WLAN_WAKE_ALL_NETIF_QUEUE, + WLAN_CONTROL_PATH); + return; +} + +#if defined(CONFIG_PER_VDEV_TX_DESC_POOL) + +/** + * hdd_softap_tx_resume_false() - Resume OS TX Q false leads to queue disabling + * @pAdapter: pointer to hdd adapter + * @tx_resume: TX Q resume trigger + * + * + * Return: None + */ +static void +hdd_softap_tx_resume_false(hdd_adapter_t *pAdapter, bool tx_resume) +{ + if (true == tx_resume) + return; + + hdd_notice("Disabling queues"); + wlan_hdd_netif_queue_control(pAdapter, WLAN_STOP_ALL_NETIF_QUEUE, + WLAN_DATA_FLOW_CONTROL); + + if (QDF_TIMER_STATE_STOPPED == + qdf_mc_timer_get_current_state(&pAdapter-> + tx_flow_control_timer)) { + QDF_STATUS status; + status = qdf_mc_timer_start(&pAdapter->tx_flow_control_timer, + WLAN_SAP_HDD_TX_FLOW_CONTROL_OS_Q_BLOCK_TIME); + + if (!QDF_IS_STATUS_SUCCESS(status)) + hdd_err("Failed to start tx_flow_control_timer"); + else + pAdapter->hdd_stats.hddTxRxStats.txflow_timer_cnt++; + } + return; +} +#else + +static inline void +hdd_softap_tx_resume_false(hdd_adapter_t *pAdapter, bool tx_resume) +{ + return; +} +#endif + +/** + * hdd_softap_tx_resume_cb() - Resume OS TX Q. + * @adapter_context: pointer to vdev apdapter + * @tx_resume: TX Q resume trigger + * + * Q was stopped due to WLAN TX path low resource condition + * + * Return: None + */ +void hdd_softap_tx_resume_cb(void *adapter_context, bool tx_resume) +{ + hdd_adapter_t *pAdapter = (hdd_adapter_t *) adapter_context; + + if (!pAdapter) { + hdd_err("NULL adapter"); + return; + } + + /* Resume TX */ + if (true == tx_resume) { + if (QDF_TIMER_STATE_STOPPED != + qdf_mc_timer_get_current_state(&pAdapter-> + tx_flow_control_timer)) { + qdf_mc_timer_stop(&pAdapter->tx_flow_control_timer); + } + + hdd_notice("Enabling queues"); + wlan_hdd_netif_queue_control(pAdapter, + WLAN_WAKE_ALL_NETIF_QUEUE, + WLAN_DATA_FLOW_CONTROL); + } + hdd_softap_tx_resume_false(pAdapter, tx_resume); + + return; +} + +static inline struct sk_buff *hdd_skb_orphan(hdd_adapter_t *pAdapter, + struct sk_buff *skb) +{ + if (pAdapter->tx_flow_low_watermark > 0) + skb_orphan(skb); + else { + skb = skb_unshare(skb, GFP_ATOMIC); + } + + return skb; +} + +#else +/** + * hdd_skb_orphan() - skb_unshare a cloned packed else skb_orphan + * @pAdapter: pointer to HDD adapter + * @skb: pointer to skb data packet + * + * Return: pointer to skb structure + */ +static struct sk_buff *hdd_skb_orphan(hdd_adapter_t *pAdapter, + struct sk_buff *skb) { + + struct sk_buff *nskb; + hdd_context_t *hdd_ctx = pAdapter->pHddCtx; + + nskb = skb_unshare(skb, GFP_ATOMIC); + if (unlikely(hdd_ctx->config->tx_orphan_enable) && (nskb == skb)) { + /* + * For UDP packets we want to orphan the packet to allow the app + * to send more packets. The flow would ultimately be controlled + * by the limited number of tx descriptors for the vdev. + */ + ++pAdapter->hdd_stats.hddTxRxStats.txXmitOrphaned; + skb_orphan(skb); + } + return nskb; +} +#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */ + +/** + * __hdd_softap_hard_start_xmit() - Transmit a frame + * @skb: pointer to OS packet (sk_buff) + * @dev: pointer to network device + * + * Function registered with the Linux OS for transmitting + * packets. This version of the function directly passes + * the packet to Transport Layer. + * In case of any packet drop or error, log the error with + * INFO HIGH/LOW/MEDIUM to avoid excessive logging in kmsg. + * + * Return: Always returns NETDEV_TX_OK + */ +static int __hdd_softap_hard_start_xmit(struct sk_buff *skb, + struct net_device *dev) +{ + sme_ac_enum_type ac = SME_AC_BE; + hdd_adapter_t *pAdapter = (hdd_adapter_t *) netdev_priv(dev); + hdd_ap_ctx_t *pHddApCtx = WLAN_HDD_GET_AP_CTX_PTR(pAdapter); + struct qdf_mac_addr *pDestMacAddress; + uint8_t STAId; + + ++pAdapter->hdd_stats.hddTxRxStats.txXmitCalled; + /* Prevent this function from being called during SSR since TL + * context may not be reinitialized at this time which may + * lead to a crash. + */ + if (cds_is_driver_recovering()) { + QDF_TRACE(QDF_MODULE_ID_HDD_SAP_DATA, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: Recovery in Progress. Ignore!!!", __func__); + goto drop_pkt; + } + + /* + * If the device is operating on a DFS Channel + * then check if SAP is in CAC WAIT state and + * drop the packets. In CAC WAIT state device + * is expected not to transmit any frames. + * SAP starts Tx only after the BSS START is + * done. + */ + if (pHddApCtx->dfs_cac_block_tx) { + goto drop_pkt; + } + + /* + * If a transmit function is not registered, drop packet + */ + if (!pAdapter->tx_fn) { + QDF_TRACE(QDF_MODULE_ID_HDD_SAP_DATA, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: TX function not registered by the data path", + __func__); + goto drop_pkt; + } + + wlan_hdd_classify_pkt(skb); + + pDestMacAddress = (struct qdf_mac_addr *) skb->data; + + if (QDF_NBUF_CB_GET_IS_BCAST(skb) || + QDF_NBUF_CB_GET_IS_MCAST(skb)) { + /* The BC/MC station ID is assigned during BSS + * starting phase. SAP will return the station ID + * used for BC/MC traffic. + */ + STAId = pHddApCtx->uBCStaId; + } else { + if (QDF_STATUS_SUCCESS != + hdd_softap_get_sta_id(pAdapter, + pDestMacAddress, &STAId)) { + QDF_TRACE(QDF_MODULE_ID_HDD_SAP_DATA, + QDF_TRACE_LEVEL_INFO_HIGH, + "%s: Failed to find right station", __func__); + goto drop_pkt; + } + + if (STAId >= WLAN_MAX_STA_COUNT) { + QDF_TRACE(QDF_MODULE_ID_HDD_SAP_DATA, + QDF_TRACE_LEVEL_INFO_HIGH, + "%s: Failed to find right station", __func__); + goto drop_pkt; + } else if (false == pAdapter->aStaInfo[STAId].isUsed) { + QDF_TRACE(QDF_MODULE_ID_HDD_SAP_DATA, + QDF_TRACE_LEVEL_INFO_HIGH, + "%s: STA %d is unregistered", __func__, + STAId); + goto drop_pkt; + } else if (true == pAdapter->aStaInfo[STAId]. + isDeauthInProgress) { + QDF_TRACE(QDF_MODULE_ID_HDD_SAP_DATA, + QDF_TRACE_LEVEL_INFO_HIGH, + "%s: STA %d deauth in progress", __func__, + STAId); + goto drop_pkt; + } + + if ((OL_TXRX_PEER_STATE_CONN != + pAdapter->aStaInfo[STAId].tlSTAState) + && (OL_TXRX_PEER_STATE_AUTH != + pAdapter->aStaInfo[STAId].tlSTAState)) { + QDF_TRACE(QDF_MODULE_ID_HDD_SAP_DATA, + QDF_TRACE_LEVEL_INFO_HIGH, + "%s: Station not connected yet", __func__); + goto drop_pkt; + } else if (OL_TXRX_PEER_STATE_CONN == + pAdapter->aStaInfo[STAId].tlSTAState) { + if (ntohs(skb->protocol) != HDD_ETHERTYPE_802_1_X) { + QDF_TRACE(QDF_MODULE_ID_HDD_SAP_DATA, + QDF_TRACE_LEVEL_INFO_HIGH, + "%s: NON-EAPOL packet in non-Authenticated state", + __func__); + goto drop_pkt; + } + } + } + + hdd_get_tx_resource(pAdapter, STAId, + WLAN_SAP_HDD_TX_FLOW_CONTROL_OS_Q_BLOCK_TIME); + + /* Get TL AC corresponding to Qdisc queue index/AC. */ + ac = hdd_qdisc_ac_to_tl_ac[skb->queue_mapping]; + ++pAdapter->hdd_stats.hddTxRxStats.txXmitClassifiedAC[ac]; + +#if defined (IPA_OFFLOAD) + if (!qdf_nbuf_ipa_owned_get(skb)) { +#endif + +#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 19, 0)) + /* + * The TCP TX throttling logic is changed a little after + * 3.19-rc1 kernel, the TCP sending limit will be smaller, + * which will throttle the TCP packets to the host driver. + * The TCP UP LINK throughput will drop heavily. In order to + * fix this issue, need to orphan the socket buffer asap, which + * will call skb's destructor to notify the TCP stack that the + * SKB buffer is unowned. And then the TCP stack will pump more + * packets to host driver. + * + * The TX packets might be dropped for UDP case in the iperf + * testing. So need to be protected by follow control. + */ + skb = hdd_skb_orphan(pAdapter, skb); +#else + /* Check if the buffer has enough header room */ + skb = skb_unshare(skb, GFP_ATOMIC); +#endif + + if (!skb) + goto drop_pkt_accounting; + +#if defined (IPA_OFFLOAD) + } +#endif + + pAdapter->stats.tx_bytes += skb->len; + + if (qdf_nbuf_is_tso(skb)) + pAdapter->stats.tx_packets += qdf_nbuf_get_tso_num_seg(skb); + else { + ++pAdapter->stats.tx_packets; + } + + hdd_event_eapol_log(skb, QDF_TX); + qdf_dp_trace_log_pkt(pAdapter->sessionId, skb, QDF_TX); + QDF_NBUF_CB_TX_PACKET_TRACK(skb) = QDF_NBUF_TX_PKT_DATA_TRACK; + QDF_NBUF_UPDATE_TX_PKT_COUNT(skb, QDF_NBUF_TX_PKT_HDD); + + qdf_dp_trace_set_track(skb, QDF_TX); + DPTRACE(qdf_dp_trace(skb, QDF_DP_TRACE_HDD_TX_PACKET_PTR_RECORD, + qdf_nbuf_data_addr(skb), sizeof(qdf_nbuf_data(skb)), + QDF_TX)); + DPTRACE(qdf_dp_trace(skb, QDF_DP_TRACE_HDD_TX_PACKET_RECORD, + (uint8_t *)skb->data, qdf_nbuf_len(skb), QDF_TX)); + if (qdf_nbuf_len(skb) > QDF_DP_TRACE_RECORD_SIZE) + DPTRACE(qdf_dp_trace(skb, QDF_DP_TRACE_HDD_TX_PACKET_RECORD, + (uint8_t *)&skb->data[QDF_DP_TRACE_RECORD_SIZE], + (qdf_nbuf_len(skb)-QDF_DP_TRACE_RECORD_SIZE), QDF_TX)); + + if (pAdapter->tx_fn(ol_txrx_get_vdev_by_sta_id(STAId), + (qdf_nbuf_t) skb) != NULL) { + QDF_TRACE(QDF_MODULE_ID_HDD_SAP_DATA, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: Failed to send packet to txrx for staid:%d", + __func__, STAId); + ++pAdapter->hdd_stats.hddTxRxStats.txXmitDroppedAC[ac]; + goto drop_pkt; + } + netif_trans_update(dev); + + return NETDEV_TX_OK; + +drop_pkt: + + DPTRACE(qdf_dp_trace(skb, QDF_DP_TRACE_DROP_PACKET_RECORD, + (uint8_t *)skb->data, qdf_nbuf_len(skb), QDF_TX)); + if (qdf_nbuf_len(skb) > QDF_DP_TRACE_RECORD_SIZE) + DPTRACE(qdf_dp_trace(skb, QDF_DP_TRACE_DROP_PACKET_RECORD, + (uint8_t *)&skb->data[QDF_DP_TRACE_RECORD_SIZE], + (qdf_nbuf_len(skb)-QDF_DP_TRACE_RECORD_SIZE), QDF_TX)); + kfree_skb(skb); + +drop_pkt_accounting: + ++pAdapter->stats.tx_dropped; + ++pAdapter->hdd_stats.hddTxRxStats.txXmitDropped; + + return NETDEV_TX_OK; +} + +/** + * hdd_softap_hard_start_xmit() - Wrapper function to protect + * __hdd_softap_hard_start_xmit from SSR + * @skb: pointer to OS packet + * @dev: pointer to net_device structure + * + * Function called by OS if any packet needs to transmit. + * + * Return: Always returns NETDEV_TX_OK + */ +int hdd_softap_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __hdd_softap_hard_start_xmit(skb, dev); + cds_ssr_unprotect(__func__); + + return ret; +} + +#ifdef FEATURE_WLAN_DIAG_SUPPORT +/** + * hdd_wlan_datastall_sap_event()- Send SAP datastall information + * + * This Function send send SAP datastall diag event + * + * Return: void. + */ +static void hdd_wlan_datastall_sap_event(void) +{ + WLAN_HOST_DIAG_EVENT_DEF(sap_data_stall, + struct host_event_wlan_datastall); + qdf_mem_zero(&sap_data_stall, sizeof(sap_data_stall)); + sap_data_stall.reason = SOFTAP_TX_TIMEOUT; + WLAN_HOST_DIAG_EVENT_REPORT(&sap_data_stall, + EVENT_WLAN_SOFTAP_DATASTALL); +} +#else +static inline void hdd_wlan_datastall_sap_event(void) +{ + +} +#endif + +/** + * __hdd_softap_tx_timeout() - TX timeout handler + * @dev: pointer to network device + * + * This function is registered as a netdev ndo_tx_timeout method, and + * is invoked by the kernel if the driver takes too long to transmit a + * frame. + * + * Return: None + */ +static void __hdd_softap_tx_timeout(struct net_device *dev) +{ + hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *hdd_ctx; + struct netdev_queue *txq; + int i; + + DPTRACE(qdf_dp_trace(NULL, QDF_DP_TRACE_HDD_SOFTAP_TX_TIMEOUT, + NULL, 0, QDF_TX)); + /* Getting here implies we disabled the TX queues for too + * long. Queues are disabled either because of disassociation + * or low resource scenarios. In case of disassociation it is + * ok to ignore this. But if associated, we have do possible + * recovery here + */ + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + if (cds_is_driver_recovering()) { + QDF_TRACE(QDF_MODULE_ID_HDD_SAP_DATA, QDF_TRACE_LEVEL_WARN, + "%s: Recovery in Progress. Ignore!!!", __func__); + return; + } + + TX_TIMEOUT_TRACE(dev, QDF_MODULE_ID_HDD_SAP_DATA); + + for (i = 0; i < NUM_TX_QUEUES; i++) { + txq = netdev_get_tx_queue(dev, i); + QDF_TRACE(QDF_MODULE_ID_HDD_DATA, + QDF_TRACE_LEVEL_INFO, + "Queue%d status: %d txq->trans_start %lu", + i, netif_tx_queue_stopped(txq), txq->trans_start); + } + + wlan_hdd_display_netif_queue_history(hdd_ctx); + ol_tx_dump_flow_pool_info(); + QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_INFO, + "carrier state: %d", netif_carrier_ok(dev)); + hdd_wlan_datastall_sap_event(); +} + +/** + * hdd_softap_tx_timeout() - SSR wrapper for __hdd_softap_tx_timeout + * @dev: pointer to net_device + * + * Return: none + */ +void hdd_softap_tx_timeout(struct net_device *dev) +{ + cds_ssr_protect(__func__); + __hdd_softap_tx_timeout(dev); + cds_ssr_unprotect(__func__); +} + +/** + * @hdd_softap_init_tx_rx() - Initialize Tx/RX module + * @pAdapter: pointer to adapter context + * + * Return: QDF_STATUS_E_FAILURE if any errors encountered, + * QDF_STATUS_SUCCESS otherwise + */ +QDF_STATUS hdd_softap_init_tx_rx(hdd_adapter_t *pAdapter) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + + uint8_t STAId = 0; + + qdf_mem_zero(&pAdapter->stats, sizeof(struct net_device_stats)); + + spin_lock_init(&pAdapter->staInfo_lock); + + for (STAId = 0; STAId < WLAN_MAX_STA_COUNT; STAId++) { + qdf_mem_zero(&pAdapter->aStaInfo[STAId], + sizeof(hdd_station_info_t)); + } + + return status; +} + +/** + * @hdd_softap_deinit_tx_rx() - Deinitialize Tx/RX module + * @pAdapter: pointer to adapter context + * + * Return: QDF_STATUS_E_FAILURE if any errors encountered, + * QDF_STATUS_SUCCESS otherwise + */ +QDF_STATUS hdd_softap_deinit_tx_rx(hdd_adapter_t *pAdapter) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + + return status; +} + +/** + * hdd_softap_init_tx_rx_sta() - Initialize tx/rx for a softap station + * @pAdapter: pointer to adapter context + * @STAId: Station ID to initialize + * @pmacAddrSTA: pointer to the MAC address of the station + * + * Return: QDF_STATUS_E_FAILURE if any errors encountered, + * QDF_STATUS_SUCCESS otherwise + */ +QDF_STATUS hdd_softap_init_tx_rx_sta(hdd_adapter_t *pAdapter, uint8_t STAId, + struct qdf_mac_addr *pmacAddrSTA) +{ + spin_lock_bh(&pAdapter->staInfo_lock); + if (pAdapter->aStaInfo[STAId].isUsed) { + spin_unlock_bh(&pAdapter->staInfo_lock); + hdd_err("Reinit of in use station %d", STAId); + return QDF_STATUS_E_FAILURE; + } + + qdf_mem_zero(&pAdapter->aStaInfo[STAId], sizeof(hdd_station_info_t)); + + pAdapter->aStaInfo[STAId].isUsed = true; + pAdapter->aStaInfo[STAId].isDeauthInProgress = false; + qdf_copy_macaddr(&pAdapter->aStaInfo[STAId].macAddrSTA, pmacAddrSTA); + + spin_unlock_bh(&pAdapter->staInfo_lock); + return QDF_STATUS_SUCCESS; +} + +/** + * hdd_softap_deinit_tx_rx_sta() - Deinitialize tx/rx for a softap station + * @pAdapter: pointer to adapter context + * @STAId: Station ID to deinitialize + * + * Return: QDF_STATUS_E_FAILURE if any errors encountered, + * QDF_STATUS_SUCCESS otherwise + */ +QDF_STATUS hdd_softap_deinit_tx_rx_sta(hdd_adapter_t *pAdapter, uint8_t STAId) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + hdd_hostapd_state_t *pHostapdState; + + pHostapdState = WLAN_HDD_GET_HOSTAP_STATE_PTR(pAdapter); + + spin_lock_bh(&pAdapter->staInfo_lock); + + if (false == pAdapter->aStaInfo[STAId].isUsed) { + spin_unlock_bh(&pAdapter->staInfo_lock); + hdd_err("Deinit station not inited %d", STAId); + return QDF_STATUS_E_FAILURE; + } + + pAdapter->aStaInfo[STAId].isUsed = false; + pAdapter->aStaInfo[STAId].isDeauthInProgress = false; + + spin_unlock_bh(&pAdapter->staInfo_lock); + return status; +} + +/** + * hdd_softap_rx_packet_cbk() - Receive packet handler + * @context: pointer to HDD context + * @rxBuf: pointer to rx qdf_nbuf + * + * Receive callback registered with TL. TL will call this to notify + * the HDD when one or more packets were received for a registered + * STA. + * + * Return: QDF_STATUS_E_FAILURE if any errors encountered, + * QDF_STATUS_SUCCESS otherwise + */ +QDF_STATUS hdd_softap_rx_packet_cbk(void *context, qdf_nbuf_t rxBuf) +{ + hdd_adapter_t *pAdapter = NULL; + int rxstat; + unsigned int cpu_index; + struct sk_buff *skb = NULL; + hdd_context_t *pHddCtx = NULL; + + /* Sanity check on inputs */ + if (unlikely((NULL == context) || (NULL == rxBuf))) { + QDF_TRACE(QDF_MODULE_ID_HDD_SAP_DATA, QDF_TRACE_LEVEL_ERROR, + "%s: Null params being passed", __func__); + return QDF_STATUS_E_FAILURE; + } + + pAdapter = (hdd_adapter_t *)context; + if (unlikely(WLAN_HDD_ADAPTER_MAGIC != pAdapter->magic)) { + QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_FATAL, + "Magic cookie(%x) for adapter sanity verification is invalid", + pAdapter->magic); + return QDF_STATUS_E_FAILURE; + } + + pHddCtx = pAdapter->pHddCtx; + if (unlikely(NULL == pHddCtx)) { + QDF_TRACE(QDF_MODULE_ID_HDD_SAP_DATA, QDF_TRACE_LEVEL_ERROR, + "%s: HDD context is Null", __func__); + return QDF_STATUS_E_FAILURE; + } + + /* walk the chain until all are processed */ + skb = (struct sk_buff *)rxBuf; + + hdd_softap_dump_sk_buff(skb); + + skb->dev = pAdapter->dev; + + if (unlikely(skb->dev == NULL)) { + + QDF_TRACE(QDF_MODULE_ID_HDD_SAP_DATA, QDF_TRACE_LEVEL_ERROR, + "%s: ERROR!!Invalid netdevice", __func__); + return QDF_STATUS_E_FAILURE; + } + cpu_index = wlan_hdd_get_cpu(); + ++pAdapter->hdd_stats.hddTxRxStats.rxPackets[cpu_index]; + ++pAdapter->stats.rx_packets; + pAdapter->stats.rx_bytes += skb->len; + + hdd_event_eapol_log(skb, QDF_RX); + DPTRACE(qdf_dp_trace(skb, + QDF_DP_TRACE_RX_HDD_PACKET_PTR_RECORD, + qdf_nbuf_data_addr(skb), + sizeof(qdf_nbuf_data(skb)), QDF_RX)); + DPTRACE(qdf_dp_trace(skb, QDF_DP_TRACE_HDD_RX_PACKET_RECORD, + (uint8_t *)skb->data, qdf_nbuf_len(skb), QDF_RX)); + if (qdf_nbuf_len(skb) > QDF_DP_TRACE_RECORD_SIZE) + DPTRACE(qdf_dp_trace(skb, QDF_DP_TRACE_HDD_RX_PACKET_RECORD, + (uint8_t *)&skb->data[QDF_DP_TRACE_RECORD_SIZE], + (qdf_nbuf_len(skb)-QDF_DP_TRACE_RECORD_SIZE), QDF_RX)); + + skb->protocol = eth_type_trans(skb, skb->dev); + + /* hold configurable wakelock for unicast traffic */ + if (pHddCtx->config->rx_wakelock_timeout && + skb->pkt_type != PACKET_BROADCAST && + skb->pkt_type != PACKET_MULTICAST) { + cds_host_diag_log_work(&pHddCtx->rx_wake_lock, + pHddCtx->config->rx_wakelock_timeout, + WIFI_POWER_EVENT_WAKELOCK_HOLD_RX); + qdf_wake_lock_timeout_acquire(&pHddCtx->rx_wake_lock, + pHddCtx->config-> + rx_wakelock_timeout); + } + + /* Remove SKB from internal tracking table before submitting + * it to stack + */ + qdf_net_buf_debug_release_skb(rxBuf); + if (hdd_napi_enabled(HDD_NAPI_ANY) && + !pHddCtx->enableRxThread) + rxstat = netif_receive_skb(skb); + else + rxstat = netif_rx_ni(skb); + if (NET_RX_SUCCESS == rxstat) { + ++pAdapter->hdd_stats.hddTxRxStats.rxDelivered[cpu_index]; + } else { + ++pAdapter->hdd_stats.hddTxRxStats.rxRefused[cpu_index]; + } + + pAdapter->dev->last_rx = jiffies; + + return QDF_STATUS_SUCCESS; +} + +/** + * hdd_softap_deregister_sta(hdd_adapter_t *pAdapter, uint8_t staId) + * @pAdapter: pointer to adapter context + * @staId: Station ID to deregister + * + * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_** on error + */ +QDF_STATUS hdd_softap_deregister_sta(hdd_adapter_t *pAdapter, uint8_t staId) +{ + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + hdd_context_t *pHddCtx; + + if (NULL == pAdapter) { + hdd_err("NULL adapter"); + return QDF_STATUS_E_INVAL; + } + + if (WLAN_HDD_ADAPTER_MAGIC != pAdapter->magic) { + hdd_err("Invalid adapter magic"); + return QDF_STATUS_E_INVAL; + } + + pHddCtx = (hdd_context_t *) (pAdapter->pHddCtx); + /* Clear station in TL and then update HDD data + * structures. This helps to block RX frames from other + * station to this station. + */ + qdf_status = ol_txrx_clear_peer(staId); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) + hdd_err("ol_txrx_clear_peer() failed for staID %d, Status= %d [0x%08X]", + staId, qdf_status, qdf_status); + + if (pAdapter->aStaInfo[staId].isUsed) { + spin_lock_bh(&pAdapter->staInfo_lock); + qdf_mem_zero(&pAdapter->aStaInfo[staId], + sizeof(hdd_station_info_t)); + spin_unlock_bh(&pAdapter->staInfo_lock); + } + pHddCtx->sta_to_adapter[staId] = NULL; + + return qdf_status; +} + +/** + * hdd_softap_register_sta() - Register a SoftAP STA + * @pAdapter: pointer to adapter context + * @fAuthRequired: is additional authentication required? + * @fPrivacyBit: should 802.11 privacy bit be set? + * @staId: station ID assigned to this station + * @ucastSig: unicast security signature + * @bcastSig: broadcast security signature + * @pPeerMacAddress: station MAC address + * @fWmmEnabled: is WMM enabled for this STA? + * + * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_** on error + */ +QDF_STATUS hdd_softap_register_sta(hdd_adapter_t *pAdapter, + bool fAuthRequired, + bool fPrivacyBit, + uint8_t staId, + uint8_t ucastSig, + uint8_t bcastSig, + struct qdf_mac_addr *pPeerMacAddress, + bool fWmmEnabled) +{ + QDF_STATUS qdf_status = QDF_STATUS_E_FAILURE; + struct ol_txrx_desc_type staDesc = { 0 }; + hdd_context_t *pHddCtx = pAdapter->pHddCtx; + struct ol_txrx_ops txrx_ops; + + hdd_info("STA:%u, Auth:%u, Priv:%u, WMM:%u", + staId, fAuthRequired, fPrivacyBit, fWmmEnabled); + + /* + * Clean up old entry if it is not cleaned up properly + */ + if (pAdapter->aStaInfo[staId].isUsed) { + hdd_info("clean up old entry for STA %d", staId); + hdd_softap_deregister_sta(pAdapter, staId); + } + + /* Get the Station ID from the one saved during the assocation. */ + staDesc.sta_id = staId; + + /* Save the pAdapter Pointer for this staId */ + pHddCtx->sta_to_adapter[staId] = pAdapter; + + qdf_status = + hdd_softap_init_tx_rx_sta(pAdapter, staId, + pPeerMacAddress); + + staDesc.is_qos_enabled = fWmmEnabled; + + /* Register the vdev transmit and receive functions */ + qdf_mem_zero(&txrx_ops, sizeof(txrx_ops)); + txrx_ops.rx.rx = hdd_softap_rx_packet_cbk; + ol_txrx_vdev_register( + ol_txrx_get_vdev_from_vdev_id(pAdapter->sessionId), + pAdapter, &txrx_ops); + pAdapter->tx_fn = txrx_ops.tx.tx; + + qdf_status = ol_txrx_register_peer(&staDesc); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + hdd_err("ol_txrx_register_peer() failed to register. Status= %d [0x%08X]", + qdf_status, qdf_status); + return qdf_status; + } + + /* if ( WPA ), tell TL to go to 'connected' and after keys come to the + * driver then go to 'authenticated'. For all other authentication + * types (those that do not require upper layer authentication) we can + * put TL directly into 'authenticated' state + */ + + pAdapter->aStaInfo[staId].ucSTAId = staId; + pAdapter->aStaInfo[staId].isQosEnabled = fWmmEnabled; + + if (!fAuthRequired) { + hdd_info("open/shared auth StaId= %d. Changing TL state to AUTHENTICATED at Join time", + pAdapter->aStaInfo[staId].ucSTAId); + + /* Connections that do not need Upper layer auth, + * transition TL directly to 'Authenticated' state. + */ + qdf_status = hdd_change_peer_state(pAdapter, staDesc.sta_id, + OL_TXRX_PEER_STATE_AUTH, false); + + pAdapter->aStaInfo[staId].tlSTAState = OL_TXRX_PEER_STATE_AUTH; + pAdapter->sessionCtx.ap.uIsAuthenticated = true; + } else { + + hdd_info("ULA auth StaId= %d. Changing TL state to CONNECTED at Join time", + pAdapter->aStaInfo[staId].ucSTAId); + + qdf_status = hdd_change_peer_state(pAdapter, staDesc.sta_id, + OL_TXRX_PEER_STATE_CONN, false); + pAdapter->aStaInfo[staId].tlSTAState = OL_TXRX_PEER_STATE_CONN; + + pAdapter->sessionCtx.ap.uIsAuthenticated = false; + + } + + /* Enable Tx queue */ + hdd_notice("Enabling queues"); + wlan_hdd_netif_queue_control(pAdapter, + WLAN_START_ALL_NETIF_QUEUE_N_CARRIER, + WLAN_CONTROL_PATH); + + return qdf_status; +} + +/** + * hdd_softap_register_bc_sta() - Register the SoftAP broadcast STA + * @pAdapter: pointer to adapter context + * @fPrivacyBit: should 802.11 privacy bit be set? + * + * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_** on error + */ +QDF_STATUS hdd_softap_register_bc_sta(hdd_adapter_t *pAdapter, + bool fPrivacyBit) +{ + QDF_STATUS qdf_status = QDF_STATUS_E_FAILURE; + hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + struct qdf_mac_addr broadcastMacAddr = + QDF_MAC_ADDR_BROADCAST_INITIALIZER; + hdd_ap_ctx_t *pHddApCtx; + + pHddApCtx = WLAN_HDD_GET_AP_CTX_PTR(pAdapter); + + pHddCtx->sta_to_adapter[WLAN_RX_BCMC_STA_ID] = pAdapter; + pHddCtx->sta_to_adapter[pHddApCtx->uBCStaId] = pAdapter; + qdf_status = + hdd_softap_register_sta(pAdapter, false, fPrivacyBit, + (WLAN_HDD_GET_AP_CTX_PTR(pAdapter))-> + uBCStaId, 0, 1, &broadcastMacAddr, 0); + + return qdf_status; +} + +/** + * hdd_softap_deregister_bc_sta() - Deregister the SoftAP broadcast STA + * @pAdapter: pointer to adapter context + * + * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_** on error + */ +QDF_STATUS hdd_softap_deregister_bc_sta(hdd_adapter_t *pAdapter) +{ + return hdd_softap_deregister_sta(pAdapter, + (WLAN_HDD_GET_AP_CTX_PTR(pAdapter))-> + uBCStaId); +} + +/** + * hdd_softap_stop_bss() - Stop the BSS + * @pAdapter: pointer to adapter context + * + * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_** on error + */ +QDF_STATUS hdd_softap_stop_bss(hdd_adapter_t *pAdapter) +{ + QDF_STATUS qdf_status = QDF_STATUS_E_FAILURE; + uint8_t staId = 0; + hdd_context_t *pHddCtx; + pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + + /* bss deregister is not allowed during wlan driver loading or + * unloading + */ + if (cds_is_load_or_unload_in_progress()) { + hdd_warn("Loading_unloading in Progress, state: 0x%x. Ignore!!!", + cds_get_driver_state()); + return QDF_STATUS_E_PERM; + } + + qdf_status = hdd_softap_deregister_bc_sta(pAdapter); + + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + hdd_err("Failed to deregister BC sta Id %d", + (WLAN_HDD_GET_AP_CTX_PTR(pAdapter))->uBCStaId); + } + + for (staId = 0; staId < WLAN_MAX_STA_COUNT; staId++) { + /* This excludes BC sta as it is already deregistered */ + if (pAdapter->aStaInfo[staId].isUsed) { + qdf_status = hdd_softap_deregister_sta(pAdapter, staId); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + hdd_err("Failed to deregister sta Id %d", + staId); + } + } + } + return qdf_status; +} + +/** + * hdd_softap_change_sta_state() - Change the state of a SoftAP station + * @pAdapter: pointer to adapter context + * @pDestMacAddress: MAC address of the station + * @state: new state of the station + * + * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_** on error + */ +QDF_STATUS hdd_softap_change_sta_state(hdd_adapter_t *pAdapter, + struct qdf_mac_addr *pDestMacAddress, + enum ol_txrx_peer_state state) +{ + uint8_t ucSTAId = WLAN_MAX_STA_COUNT; + QDF_STATUS qdf_status; + + ENTER_DEV(pAdapter->dev); + + qdf_status = hdd_softap_get_sta_id(pAdapter, pDestMacAddress, &ucSTAId); + if (QDF_STATUS_SUCCESS != qdf_status) { + hdd_err("Failed to find right station"); + return qdf_status; + } + + if (false == + qdf_is_macaddr_equal(&pAdapter->aStaInfo[ucSTAId].macAddrSTA, + pDestMacAddress)) { + hdd_err("Station %u MAC address not matching", ucSTAId); + return QDF_STATUS_E_FAILURE; + } + + qdf_status = + hdd_change_peer_state(pAdapter, ucSTAId, state, false); + hdd_info("Station %u changed to state %d", ucSTAId, state); + + if (QDF_STATUS_SUCCESS == qdf_status) { + pAdapter->aStaInfo[ucSTAId].tlSTAState = + OL_TXRX_PEER_STATE_AUTH; + } + + EXIT(); + return qdf_status; +} + +/* + * hdd_softap_get_sta_id() - Find station ID from MAC address + * @pAdapter: pointer to adapter context + * @pDestMacAddress: MAC address of the destination + * @staId: Station ID associated with the MAC address + * + * Return: QDF_STATUS_SUCCESS if a match was found, in which case + * staId is populated, QDF_STATUS_E_FAILURE if a match is + * not found + */ +QDF_STATUS hdd_softap_get_sta_id(hdd_adapter_t *pAdapter, + struct qdf_mac_addr *pMacAddress, + uint8_t *staId) +{ + uint8_t i; + + for (i = 0; i < WLAN_MAX_STA_COUNT; i++) { + if (!qdf_mem_cmp + (&pAdapter->aStaInfo[i].macAddrSTA, pMacAddress, + QDF_MAC_ADDR_SIZE) && pAdapter->aStaInfo[i].isUsed) { + *staId = i; + return QDF_STATUS_SUCCESS; + } + } + + return QDF_STATUS_E_FAILURE; +} diff --git a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_stats.c b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_stats.c new file mode 100644 index 0000000000000000000000000000000000000000..2a4b66b98a2dfdf175ffbd8bdcefe36b469d3b7b --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_stats.c @@ -0,0 +1,2841 @@ +/* + * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/** + * DOC : wlan_hdd_stats.c + * + * WLAN Host Device Driver statistics related implementation + * + */ + +#include "wlan_hdd_stats.h" +#include "sme_api.h" +#include "cds_sched.h" +#include "wlan_hdd_trace.h" +#include "wlan_hdd_lpass.h" +#include "hif.h" +#include "wlan_hdd_hostapd.h" + +#ifdef WLAN_FEATURE_LINK_LAYER_STATS + +/** + * struct hdd_ll_stats_context - hdd link layer stats context + * + * @request_id: userspace-assigned link layer stats request id + * @request_bitmap: userspace-assigned link layer stats request bitmap + * @response_event: LL stats request wait event + */ +struct hdd_ll_stats_context { + uint32_t request_id; + uint32_t request_bitmap; + struct completion response_event; + spinlock_t context_lock; +}; + +static struct hdd_ll_stats_context ll_stats_context; + +#endif /* End of WLAN_FEATURE_LINK_LAYER_STATS */ + +/* 11B, 11G Rate table include Basic rate and Extended rate + * The IDX field is the rate index + * The HI field is the rate when RSSI is strong or being ignored + * (in this case we report actual rate) + * The MID field is the rate when RSSI is moderate + * (in this case we cap 11b rates at 5.5 and 11g rates at 24) + * The LO field is the rate when RSSI is low + * (in this case we don't report rates, actual current rate used) + */ +static const struct { + uint8_t beacon_rate_index; + uint16_t supported_rate[4]; +} supported_data_rate[] = { +/* IDX HI HM LM LO (RSSI-based index */ + { + 2, { + 10, 10, 10, 0 + } + }, { + 4, { + 20, 20, 10, 0 + } + }, { + 11, { + 55, 20, 10, 0 + } + }, { + 12, { + 60, 55, 20, 0 + } + }, { + 18, { + 90, 55, 20, 0 + } + }, { + 22, { + 110, 55, 20, 0 + } + }, { + 24, { + 120, 90, 60, 0 + } + }, { + 36, { + 180, 120, 60, 0 + } + }, { + 44, { + 220, 180, 60, 0 + } + }, { + 48, { + 240, 180, 90, 0 + } + }, { + 66, { + 330, 180, 90, 0 + } + }, { + 72, { + 360, 240, 90, 0 + } + }, { + 96, { + 480, 240, 120, 0 + } + }, { + 108, { + 540, 240, 120, 0 + } + } +}; +/* MCS Based rate table HT MCS parameters with Nss = 1 */ +static struct index_data_rate_type supported_mcs_rate_nss1[] = { +/* MCS L20 L40 S20 S40 */ + {0, {65, 135, 72, 150} }, + {1, {130, 270, 144, 300} }, + {2, {195, 405, 217, 450} }, + {3, {260, 540, 289, 600} }, + {4, {390, 810, 433, 900} }, + {5, {520, 1080, 578, 1200} }, + {6, {585, 1215, 650, 1350} }, + {7, {650, 1350, 722, 1500} } +}; + +/* HT MCS parameters with Nss = 2 */ +static struct index_data_rate_type supported_mcs_rate_nss2[] = { +/* MCS L20 L40 S20 S40 */ + {0, {130, 270, 144, 300} }, + {1, {260, 540, 289, 600} }, + {2, {390, 810, 433, 900} }, + {3, {520, 1080, 578, 1200} }, + {4, {780, 1620, 867, 1800} }, + {5, {1040, 2160, 1156, 2400} }, + {6, {1170, 2430, 1300, 2700} }, + {7, {1300, 2700, 1444, 3000} } +}; + +/* MCS Based VHT rate table MCS parameters with Nss = 1*/ +static struct index_vht_data_rate_type supported_vht_mcs_rate_nss1[] = { +/* MCS L80 S80 L40 S40 L20 S40*/ + {0, {293, 325}, {135, 150}, {65, 72} }, + {1, {585, 650}, {270, 300}, {130, 144} }, + {2, {878, 975}, {405, 450}, {195, 217} }, + {3, {1170, 1300}, {540, 600}, {260, 289} }, + {4, {1755, 1950}, {810, 900}, {390, 433} }, + {5, {2340, 2600}, {1080, 1200}, {520, 578} }, + {6, {2633, 2925}, {1215, 1350}, {585, 650} }, + {7, {2925, 3250}, {1350, 1500}, {650, 722} }, + {8, {3510, 3900}, {1620, 1800}, {780, 867} }, + {9, {3900, 4333}, {1800, 2000}, {780, 867} } +}; + +/*MCS parameters with Nss = 2*/ +static struct index_vht_data_rate_type supported_vht_mcs_rate_nss2[] = { +/* MCS L80 S80 L40 S40 L20 S40*/ + {0, {585, 650}, {270, 300}, {130, 144} }, + {1, {1170, 1300}, {540, 600}, {260, 289} }, + {2, {1755, 1950}, {810, 900}, {390, 433} }, + {3, {2340, 2600}, {1080, 1200}, {520, 578} }, + {4, {3510, 3900}, {1620, 1800}, {780, 867} }, + {5, {4680, 5200}, {2160, 2400}, {1040, 1156} }, + {6, {5265, 5850}, {2430, 2700}, {1170, 1300} }, + {7, {5850, 6500}, {2700, 3000}, {1300, 1444} }, + {8, {7020, 7800}, {3240, 3600}, {1560, 1733} }, + {9, {7800, 8667}, {3600, 4000}, {1560, 1733} } +}; + +/*array index ponints to MCS and array value points respective rssi*/ +static int rssi_mcs_tbl[][10] = { +/*MCS 0 1 2 3 4 5 6 7 8 9*/ + {-82, -79, -77, -74, -70, -66, -65, -64, -59, -57}, /* 20 */ + {-79, -76, -74, -71, -67, -63, -62, -61, -56, -54}, /* 40 */ + {-76, -73, -71, -68, -64, -60, -59, -58, -53, -51} /* 80 */ +}; + + +#ifdef WLAN_FEATURE_LINK_LAYER_STATS + +/** + * put_wifi_rate_stat() - put wifi rate stats + * @stats: Pointer to stats context + * @vendor_event: Pointer to vendor event + * + * Return: bool + */ +static bool put_wifi_rate_stat(tpSirWifiRateStat stats, + struct sk_buff *vendor_event) +{ + if (nla_put_u8(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_PREAMBLE, + stats->rate.preamble) || + nla_put_u8(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_NSS, + stats->rate.nss) || + nla_put_u8(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_BW, + stats->rate.bw) || + nla_put_u8(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_MCS_INDEX, + stats->rate.rateMcsIdx) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_BIT_RATE, + stats->rate.bitrate) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_TX_MPDU, + stats->txMpdu) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_RX_MPDU, + stats->rxMpdu) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_MPDU_LOST, + stats->mpduLost) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_RETRIES, + stats->retries) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_RETRIES_SHORT, + stats->retriesShort) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_RETRIES_LONG, + stats->retriesLong)) { + hdd_err("QCA_WLAN_VENDOR_ATTR put fail"); + return false; + } + + return true; +} + +static tSirWifiPeerType wmi_to_sir_peer_type(enum wmi_peer_type type) +{ + switch (type) { + case WMI_PEER_TYPE_DEFAULT: + return WIFI_PEER_STA; + case WMI_PEER_TYPE_BSS: + return WIFI_PEER_AP; + case WMI_PEER_TYPE_TDLS: + return WIFI_PEER_TDLS; + case WMI_PEER_TYPE_NAN_DATA: + return WIFI_PEER_NAN; + default: + hdd_err("Cannot map wmi_peer_type %d to HAL peer type", type); + return WIFI_PEER_INVALID; + } +} + +/** + * put_wifi_peer_info() - put wifi peer info + * @stats: Pointer to stats context + * @vendor_event: Pointer to vendor event + * + * Return: bool + */ +static bool put_wifi_peer_info(tpSirWifiPeerInfo stats, + struct sk_buff *vendor_event) +{ + u32 i = 0; + tpSirWifiRateStat pRateStats; + + if (nla_put_u32 + (vendor_event, QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_TYPE, + wmi_to_sir_peer_type(stats->type)) || + nla_put(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_MAC_ADDRESS, + QDF_MAC_ADDR_SIZE, &stats->peerMacAddress.bytes[0]) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_CAPABILITIES, + stats->capabilities) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_NUM_RATES, + stats->numRate)) { + hdd_err("QCA_WLAN_VENDOR_ATTR put fail"); + goto error; + } + + if (stats->numRate) { + struct nlattr *rateInfo; + struct nlattr *rates; + + rateInfo = nla_nest_start(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_RATE_INFO); + if (rateInfo == NULL) + goto error; + + for (i = 0; i < stats->numRate; i++) { + pRateStats = (tpSirWifiRateStat) ((uint8_t *) + stats->rateStats + + (i * + sizeof + (tSirWifiRateStat))); + rates = nla_nest_start(vendor_event, i); + if (rates == NULL) + goto error; + + if (false == + put_wifi_rate_stat(pRateStats, vendor_event)) { + hdd_err("QCA_WLAN_VENDOR_ATTR put fail"); + return false; + } + nla_nest_end(vendor_event, rates); + } + nla_nest_end(vendor_event, rateInfo); + } + + return true; +error: + return false; +} + +/** + * put_wifi_wmm_ac_stat() - put wifi wmm ac stats + * @stats: Pointer to stats context + * @vendor_event: Pointer to vendor event + * + * Return: bool + */ +static bool put_wifi_wmm_ac_stat(tpSirWifiWmmAcStat stats, + struct sk_buff *vendor_event) +{ + if (nla_put_u32(vendor_event, QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_AC, + stats->ac) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_TX_MPDU, + stats->txMpdu) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RX_MPDU, + stats->rxMpdu) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_TX_MCAST, + stats->txMcast) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RX_MCAST, + stats->rxMcast) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RX_AMPDU, + stats->rxAmpdu) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_TX_AMPDU, + stats->txAmpdu) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_MPDU_LOST, + stats->mpduLost) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RETRIES, + stats->retries) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RETRIES_SHORT, + stats->retriesShort) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RETRIES_LONG, + stats->retriesLong) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_CONTENTION_TIME_MIN, + stats->contentionTimeMin) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_CONTENTION_TIME_MAX, + stats->contentionTimeMax) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_CONTENTION_TIME_AVG, + stats->contentionTimeAvg) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_CONTENTION_NUM_SAMPLES, + stats->contentionNumSamples)) { + hdd_err("QCA_WLAN_VENDOR_ATTR put fail"); + return false; + } + + return true; +} + +/** + * put_wifi_interface_info() - put wifi interface info + * @stats: Pointer to stats context + * @vendor_event: Pointer to vendor event + * + * Return: bool + */ +static bool put_wifi_interface_info(tpSirWifiInterfaceInfo stats, + struct sk_buff *vendor_event) +{ + if (nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_MODE, + stats->mode) || + nla_put(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_MAC_ADDR, + QDF_MAC_ADDR_SIZE, stats->macAddr.bytes) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_STATE, + stats->state) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_ROAMING, + stats->roaming) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_CAPABILITIES, + stats->capabilities) || + nla_put(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_SSID, + strlen(stats->ssid), stats->ssid) || + nla_put(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_BSSID, + QDF_MAC_ADDR_SIZE, stats->bssid.bytes) || + nla_put(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_AP_COUNTRY_STR, + WNI_CFG_COUNTRY_CODE_LEN, stats->apCountryStr) || + nla_put(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_COUNTRY_STR, + WNI_CFG_COUNTRY_CODE_LEN, stats->countryStr)) { + hdd_err("QCA_WLAN_VENDOR_ATTR put fail"); + return false; + } + + return true; +} + +/** + * put_wifi_iface_stats() - put wifi interface stats + * @pWifiIfaceStat: Pointer to interface stats context + * @num_peer: Number of peers + * @vendor_event: Pointer to vendor event + * + * Return: bool + */ +static bool put_wifi_iface_stats(tpSirWifiIfaceStat pWifiIfaceStat, + u32 num_peers, struct sk_buff *vendor_event) +{ + int i = 0; + struct nlattr *wmmInfo; + struct nlattr *wmmStats; + u64 average_tsf_offset; + + if (false == put_wifi_interface_info(&pWifiIfaceStat->info, + vendor_event)) { + hdd_err("QCA_WLAN_VENDOR_ATTR put fail"); + return false; + + } + + average_tsf_offset = pWifiIfaceStat->avg_bcn_spread_offset_high; + average_tsf_offset = (average_tsf_offset << 32) | + pWifiIfaceStat->avg_bcn_spread_offset_low ; + + if (nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE, + QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE_IFACE) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_NUM_PEERS, + num_peers) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_BEACON_RX, + pWifiIfaceStat->beaconRx) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_MGMT_RX, + pWifiIfaceStat->mgmtRx) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_MGMT_ACTION_RX, + pWifiIfaceStat->mgmtActionRx) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_MGMT_ACTION_TX, + pWifiIfaceStat->mgmtActionTx) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_RSSI_MGMT, + pWifiIfaceStat->rssiMgmt) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_RSSI_DATA, + pWifiIfaceStat->rssiData) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_RSSI_ACK, + pWifiIfaceStat->rssiAck) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_LEAKY_AP_DETECTED, + pWifiIfaceStat->is_leaky_ap) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_LEAKY_AP_AVG_NUM_FRAMES_LEAKED, + pWifiIfaceStat->avg_rx_frms_leaked) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_LEAKY_AP_GUARD_TIME, + pWifiIfaceStat->rx_leak_window) || + hdd_wlan_nla_put_u64(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_AVERAGE_TSF_OFFSET, + average_tsf_offset) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_RTS_SUCC_CNT, + pWifiIfaceStat->rts_succ_cnt) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_RTS_FAIL_CNT, + pWifiIfaceStat->rts_fail_cnt) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_PPDU_SUCC_CNT, + pWifiIfaceStat->ppdu_succ_cnt) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_PPDU_FAIL_CNT, + pWifiIfaceStat->ppdu_fail_cnt)) { + hdd_err("QCA_WLAN_VENDOR_ATTR put fail"); + return false; + } + + wmmInfo = nla_nest_start(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_INFO); + if (wmmInfo == NULL) + return false; + + for (i = 0; i < WIFI_AC_MAX; i++) { + wmmStats = nla_nest_start(vendor_event, i); + if (wmmStats == NULL) + return false; + + if (false == + put_wifi_wmm_ac_stat(&pWifiIfaceStat->AccessclassStats[i], + vendor_event)) { + hdd_err("put_wifi_wmm_ac_stat Fail"); + return false; + } + + nla_nest_end(vendor_event, wmmStats); + } + nla_nest_end(vendor_event, wmmInfo); + return true; +} + +/** + * hdd_map_device_to_ll_iface_mode() - map device to link layer interface mode + * @deviceMode: Device mode + * + * Return: interface mode + */ +static tSirWifiInterfaceMode hdd_map_device_to_ll_iface_mode(int deviceMode) +{ + switch (deviceMode) { + case QDF_STA_MODE: + return WIFI_INTERFACE_STA; + case QDF_SAP_MODE: + return WIFI_INTERFACE_SOFTAP; + case QDF_P2P_CLIENT_MODE: + return WIFI_INTERFACE_P2P_CLIENT; + case QDF_P2P_GO_MODE: + return WIFI_INTERFACE_P2P_GO; + case QDF_IBSS_MODE: + return WIFI_INTERFACE_IBSS; + default: + /* Return Interface Mode as STA for all the unsupported modes */ + return WIFI_INTERFACE_STA; + } +} + +/** + * hdd_get_interface_info() - get interface info + * @pAdapter: Pointer to device adapter + * @pInfo: Pointer to interface info + * + * Return: bool + */ +static bool hdd_get_interface_info(hdd_adapter_t *pAdapter, + tpSirWifiInterfaceInfo pInfo) +{ + uint8_t *staMac = NULL; + hdd_station_ctx_t *pHddStaCtx; + tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter); + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + pInfo->mode = hdd_map_device_to_ll_iface_mode(pAdapter->device_mode); + + qdf_copy_macaddr(&pInfo->macAddr, &pAdapter->macAddressCurrent); + + if (((QDF_STA_MODE == pAdapter->device_mode) || + (QDF_P2P_CLIENT_MODE == pAdapter->device_mode) || + (QDF_P2P_DEVICE_MODE == pAdapter->device_mode))) { + pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + if (eConnectionState_NotConnected == + pHddStaCtx->conn_info.connState) { + pInfo->state = WIFI_DISCONNECTED; + } + if (eConnectionState_Connecting == + pHddStaCtx->conn_info.connState) { + hdd_err("Session ID %d, Connection is in progress", + pAdapter->sessionId); + pInfo->state = WIFI_ASSOCIATING; + } + if ((eConnectionState_Associated == + pHddStaCtx->conn_info.connState) + && (false == pHddStaCtx->conn_info.uIsAuthenticated)) { + staMac = + (uint8_t *) &(pAdapter->macAddressCurrent. + bytes[0]); + hdd_warn("client " MAC_ADDRESS_STR + " is in the middle of WPS/EAPOL exchange.", + MAC_ADDR_ARRAY(staMac)); + pInfo->state = WIFI_AUTHENTICATING; + } + if (eConnectionState_Associated == + pHddStaCtx->conn_info.connState) { + pInfo->state = WIFI_ASSOCIATED; + qdf_copy_macaddr(&pInfo->bssid, + &pHddStaCtx->conn_info.bssId); + qdf_mem_copy(pInfo->ssid, + pHddStaCtx->conn_info.SSID.SSID.ssId, + pHddStaCtx->conn_info.SSID.SSID.length); + /* + * NULL Terminate the string + */ + pInfo->ssid[pHddStaCtx->conn_info.SSID.SSID.length] = 0; + } + } + + qdf_mem_copy(pInfo->countryStr, + pMac->scan.countryCodeCurrent, WNI_CFG_COUNTRY_CODE_LEN); + + qdf_mem_copy(pInfo->apCountryStr, + pMac->scan.countryCodeCurrent, WNI_CFG_COUNTRY_CODE_LEN); + + return true; +} + +/** + * hdd_link_layer_process_peer_stats() - This function is called after + * @pAdapter: Pointer to device adapter + * @more_data: More data + * @pData: Pointer to stats data + * + * Receiving Link Layer Peer statistics from FW.This function converts + * the firmware data to the NL data and sends the same to the kernel/upper + * layers. + * + * Return: None + */ +static void hdd_link_layer_process_peer_stats(hdd_adapter_t *pAdapter, + u32 more_data, + tpSirWifiPeerStat pData) +{ + hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + tpSirWifiPeerStat pWifiPeerStat; + tpSirWifiPeerInfo pWifiPeerInfo; + struct sk_buff *vendor_event; + int status, i; + struct nlattr *peers; + int numRate; + + ENTER(); + + pWifiPeerStat = pData; + + status = wlan_hdd_validate_context(pHddCtx); + if (0 != status) + return; + + hdd_notice("LL_STATS_PEER_ALL : numPeers %u, more data = %u", + pWifiPeerStat->numPeers, more_data); + + /* + * Allocate a size of 4096 for the peer stats comprising + * each of size = sizeof (tSirWifiPeerInfo) + numRate * + * sizeof (tSirWifiRateStat).Each field is put with an + * NL attribute.The size of 4096 is considered assuming + * that number of rates shall not exceed beyond 50 with + * the sizeof (tSirWifiRateStat) being 32. + */ + vendor_event = cfg80211_vendor_cmd_alloc_reply_skb(pHddCtx->wiphy, + LL_STATS_EVENT_BUF_SIZE); + + if (!vendor_event) { + hdd_err("cfg80211_vendor_cmd_alloc_reply_skb failed"); + return; + } + + if (nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE, + QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE_PEER) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_RESULTS_MORE_DATA, + more_data) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_NUM_PEERS, + pWifiPeerStat->numPeers)) { + hdd_err("QCA_WLAN_VENDOR_ATTR put fail"); + + kfree_skb(vendor_event); + return; + } + + pWifiPeerInfo = (tpSirWifiPeerInfo) ((uint8_t *) + pWifiPeerStat->peerInfo); + + if (pWifiPeerStat->numPeers) { + struct nlattr *peerInfo; + peerInfo = nla_nest_start(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO); + if (peerInfo == NULL) { + hdd_err("nla_nest_start failed"); + kfree_skb(vendor_event); + return; + } + + for (i = 1; i <= pWifiPeerStat->numPeers; i++) { + peers = nla_nest_start(vendor_event, i); + if (peers == NULL) { + hdd_err("nla_nest_start failed"); + kfree_skb(vendor_event); + return; + } + + numRate = pWifiPeerInfo->numRate; + + if (false == + put_wifi_peer_info(pWifiPeerInfo, vendor_event)) { + hdd_err("put_wifi_peer_info fail"); + kfree_skb(vendor_event); + return; + } + + pWifiPeerInfo = (tpSirWifiPeerInfo) ((uint8_t *) + pWifiPeerStat-> + peerInfo + + (i * + sizeof + (tSirWifiPeerInfo)) + + + (numRate * + sizeof + (tSirWifiRateStat))); + nla_nest_end(vendor_event, peers); + } + nla_nest_end(vendor_event, peerInfo); + } + cfg80211_vendor_cmd_reply(vendor_event); + EXIT(); + return; +} + +/** + * hdd_link_layer_process_iface_stats() - This function is called after + * @pAdapter: Pointer to device adapter + * @pData: Pointer to stats data + * @num_peers: Number of peers + * + * Receiving Link Layer Interface statistics from FW.This function converts + * the firmware data to the NL data and sends the same to the kernel/upper + * layers. + * + * Return: None + */ +static void hdd_link_layer_process_iface_stats(hdd_adapter_t *pAdapter, + tpSirWifiIfaceStat pData, + u32 num_peers) +{ + tpSirWifiIfaceStat pWifiIfaceStat; + struct sk_buff *vendor_event; + hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + int status; + + ENTER(); + + pWifiIfaceStat = pData; + + status = wlan_hdd_validate_context(pHddCtx); + if (0 != status) + return; + + /* + * Allocate a size of 4096 for the interface stats comprising + * sizeof (tpSirWifiIfaceStat).The size of 4096 is considered + * assuming that all these fit with in the limit.Please take + * a call on the limit based on the data requirements on + * interface statistics. + */ + vendor_event = cfg80211_vendor_cmd_alloc_reply_skb(pHddCtx->wiphy, + LL_STATS_EVENT_BUF_SIZE); + + if (!vendor_event) { + hdd_err("cfg80211_vendor_cmd_alloc_reply_skb failed"); + return; + } + + hdd_notice("WMI_LINK_STATS_IFACE Data"); + + if (false == hdd_get_interface_info(pAdapter, &pWifiIfaceStat->info)) { + hdd_err("hdd_get_interface_info get fail"); + kfree_skb(vendor_event); + return; + } + + if (false == + put_wifi_iface_stats(pWifiIfaceStat, num_peers, vendor_event)) { + hdd_err("put_wifi_iface_stats fail"); + kfree_skb(vendor_event); + return; + } + + cfg80211_vendor_cmd_reply(vendor_event); + EXIT(); + return; +} + +/** + * hdd_llstats_radio_fill_channels() - radio stats fill channels + * @adapter: Pointer to device adapter + * @radiostat: Pointer to stats data + * @vendor_event: vendor event + * + * Return: 0 on success; errno on failure + */ +static int hdd_llstats_radio_fill_channels(hdd_adapter_t *adapter, + tSirWifiRadioStat *radiostat, + struct sk_buff *vendor_event) +{ + tSirWifiChannelStats *channel_stats; + struct nlattr *chlist; + struct nlattr *chinfo; + int i; + + chlist = nla_nest_start(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_CH_INFO); + if (chlist == NULL) { + hdd_err("nla_nest_start failed"); + return -EINVAL; + } + + for (i = 0; i < radiostat->numChannels; i++) { + channel_stats = (tSirWifiChannelStats *) ((uint8_t *) + radiostat->channels + + (i * sizeof(tSirWifiChannelStats))); + + chinfo = nla_nest_start(vendor_event, i); + if (chinfo == NULL) { + hdd_err("nla_nest_start failed"); + return -EINVAL; + } + + if (nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_WIDTH, + channel_stats->channel.width) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_CENTER_FREQ, + channel_stats->channel.centerFreq) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_CENTER_FREQ0, + channel_stats->channel.centerFreq0) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_CENTER_FREQ1, + channel_stats->channel.centerFreq1) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_ON_TIME, + channel_stats->onTime) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_CCA_BUSY_TIME, + channel_stats->ccaBusyTime)) { + hdd_err("nla_put failed"); + return -EINVAL; + } + nla_nest_end(vendor_event, chinfo); + } + nla_nest_end(vendor_event, chlist); + + return 0; +} + +/** + * hdd_llstats_post_radio_stats() - post radio stats + * @adapter: Pointer to device adapter + * @more_data: More data + * @radiostat: Pointer to stats data + * @num_radio: Number of radios + * + * Return: 0 on success; errno on failure + */ +static int hdd_llstats_post_radio_stats(hdd_adapter_t *adapter, + u32 more_data, + tSirWifiRadioStat *radiostat, + u32 num_radio) +{ + struct sk_buff *vendor_event; + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + int ret; + + /* + * Allocate a size of 4096 for the Radio stats comprising + * sizeof (tSirWifiRadioStat) + numChannels * sizeof + * (tSirWifiChannelStats).Each channel data is put with an + * NL attribute.The size of 4096 is considered assuming that + * number of channels shall not exceed beyond 60 with the + * sizeof (tSirWifiChannelStats) being 24 bytes. + */ + + vendor_event = cfg80211_vendor_cmd_alloc_reply_skb( + hdd_ctx->wiphy, + LL_STATS_EVENT_BUF_SIZE); + + if (!vendor_event) { + hdd_err("cfg80211_vendor_cmd_alloc_reply_skb failed"); + return -ENOMEM; + } + + if (nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE, + QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE_RADIO) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_RESULTS_MORE_DATA, + more_data) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_NUM_RADIOS, + num_radio) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ID, + radiostat->radio) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME, + radiostat->onTime) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_TX_TIME, + radiostat->txTime) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_RX_TIME, + radiostat->rxTime) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_SCAN, + radiostat->onTimeScan) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_NBD, + radiostat->onTimeNbd) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_GSCAN, + radiostat->onTimeGscan) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_ROAM_SCAN, + radiostat->onTimeRoamScan) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_PNO_SCAN, + radiostat->onTimePnoScan) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_HS20, + radiostat->onTimeHs20) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_NUM_TX_LEVELS, + radiostat->total_num_tx_power_levels) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_NUM_CHANNELS, + radiostat->numChannels)) { + hdd_err("QCA_WLAN_VENDOR_ATTR put fail"); + goto failure; + } + + if (radiostat->total_num_tx_power_levels) { + if (nla_put(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_TX_TIME_PER_LEVEL, + sizeof(u32) * + radiostat->total_num_tx_power_levels, + radiostat->tx_time_per_power_level)) { + hdd_err("nla_put fail"); + goto failure; + } + } + + if (radiostat->numChannels) { + ret = hdd_llstats_radio_fill_channels(adapter, radiostat, + vendor_event); + if (ret) + goto failure; + } + + cfg80211_vendor_cmd_reply(vendor_event); + return 0; + +failure: + kfree_skb(vendor_event); + return -EINVAL; +} + +/** + * hdd_link_layer_process_radio_stats() - This function is called after + * @pAdapter: Pointer to device adapter + * @more_data: More data + * @pData: Pointer to stats data + * @num_radios: Number of radios + * + * Receiving Link Layer Radio statistics from FW.This function converts + * the firmware data to the NL data and sends the same to the kernel/upper + * layers. + * + * Return: None + */ +static void hdd_link_layer_process_radio_stats(hdd_adapter_t *pAdapter, + u32 more_data, + tpSirWifiRadioStat pData, + u32 num_radio) +{ + int status, i, nr, ret; + tSirWifiRadioStat *pWifiRadioStat = pData; + hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + + ENTER(); + + status = wlan_hdd_validate_context(pHddCtx); + if (0 != status) + return; + + hdd_notice("LL_STATS_RADIO: number of radios: %u", num_radio); + + for (i = 0; i < num_radio; i++) { + hdd_notice("LL_STATS_RADIO" + " radio: %u onTime: %u txTime: %u rxTime: %u" + " onTimeScan: %u onTimeNbd: %u" + " onTimeGscan: %u onTimeRoamScan: %u" + " onTimePnoScan: %u onTimeHs20: %u" + " numChannels: %u total_num_tx_pwr_levels: %u", + pWifiRadioStat->radio, pWifiRadioStat->onTime, + pWifiRadioStat->txTime, pWifiRadioStat->rxTime, + pWifiRadioStat->onTimeScan, pWifiRadioStat->onTimeNbd, + pWifiRadioStat->onTimeGscan, + pWifiRadioStat->onTimeRoamScan, + pWifiRadioStat->onTimePnoScan, + pWifiRadioStat->onTimeHs20, pWifiRadioStat->numChannels, + pWifiRadioStat->total_num_tx_power_levels); + pWifiRadioStat++; + } + + pWifiRadioStat = pData; + for (nr = 0; nr < num_radio; nr++) { + ret = hdd_llstats_post_radio_stats(pAdapter, more_data, + pWifiRadioStat, num_radio); + if (ret) + return; + + pWifiRadioStat++; + } + EXIT(); + return; +} + +/** + * wlan_hdd_cfg80211_link_layer_stats_callback() - This function is called + * @ctx: Pointer to hdd context + * @indType: Indication type + * @pRsp: Pointer to response + * + * After receiving Link Layer indications from FW.This callback converts the + * firmware data to the NL data and send the same to the kernel/upper layers. + * + * Return: None + */ +void wlan_hdd_cfg80211_link_layer_stats_callback(void *ctx, + int indType, void *pRsp) +{ + hdd_context_t *pHddCtx = (hdd_context_t *) ctx; + struct hdd_ll_stats_context *context; + hdd_adapter_t *pAdapter = NULL; + tpSirLLStatsResults linkLayerStatsResults = (tpSirLLStatsResults) pRsp; + int status; + + status = wlan_hdd_validate_context(pHddCtx); + if (status) + return; + + pAdapter = hdd_get_adapter_by_vdev(pHddCtx, + linkLayerStatsResults->ifaceId); + + if (NULL == pAdapter) { + hdd_err("vdev_id %d does not exist with host", + linkLayerStatsResults->ifaceId); + return; + } + + hdd_notice("Link Layer Indication indType: %d", indType); + + switch (indType) { + case SIR_HAL_LL_STATS_RESULTS_RSP: + { + hdd_notice("LL_STATS RESP paramID = 0x%x, ifaceId = %u, respId= %u , moreResultToFollow = %u, num radio = %u result = %p", + linkLayerStatsResults->paramId, + linkLayerStatsResults->ifaceId, + linkLayerStatsResults->rspId, + linkLayerStatsResults->moreResultToFollow, + linkLayerStatsResults->num_radio, + linkLayerStatsResults->results); + + context = &ll_stats_context; + spin_lock(&context->context_lock); + /* validate response received from target */ + if ((context->request_id != linkLayerStatsResults->rspId) || + !(context->request_bitmap & linkLayerStatsResults->paramId)) { + spin_unlock(&context->context_lock); + hdd_err("Error : Request id %d response id %d request bitmap 0x%x response bitmap 0x%x", + context->request_id, linkLayerStatsResults->rspId, + context->request_bitmap, linkLayerStatsResults->paramId); + return; + } + spin_unlock(&context->context_lock); + + if (linkLayerStatsResults-> + paramId & WMI_LINK_STATS_RADIO) { + hdd_link_layer_process_radio_stats(pAdapter, + linkLayerStatsResults->moreResultToFollow, + (tpSirWifiRadioStat)linkLayerStatsResults->results, + linkLayerStatsResults->num_radio); + + spin_lock(&context->context_lock); + if (!linkLayerStatsResults->moreResultToFollow) + context->request_bitmap &= ~(WMI_LINK_STATS_RADIO); + spin_unlock(&context->context_lock); + + } else if (linkLayerStatsResults-> + paramId & WMI_LINK_STATS_IFACE) { + hdd_link_layer_process_iface_stats(pAdapter, + (tpSirWifiIfaceStat)linkLayerStatsResults->results, + linkLayerStatsResults->num_peers); + + spin_lock(&context->context_lock); + /* Firmware doesn't send peerstats event if no peers are + * connected. HDD should not wait for any peerstats in + * this case and return the status to middleware after + * receiving iface stats + */ + if (!linkLayerStatsResults->num_peers) + context->request_bitmap &= + ~(WMI_LINK_STATS_ALL_PEER); + context->request_bitmap &= ~(WMI_LINK_STATS_IFACE); + spin_unlock(&context->context_lock); + + } else if (linkLayerStatsResults-> + paramId & WMI_LINK_STATS_ALL_PEER) { + hdd_link_layer_process_peer_stats(pAdapter, + linkLayerStatsResults->moreResultToFollow, + (tpSirWifiPeerStat)linkLayerStatsResults->results); + + spin_lock(&context->context_lock); + if (!linkLayerStatsResults->moreResultToFollow) + context->request_bitmap &= ~(WMI_LINK_STATS_ALL_PEER); + spin_unlock(&context->context_lock); + + } else { + hdd_err("INVALID LL_STATS_NOTIFY RESPONSE"); + } + + spin_lock(&context->context_lock); + /* complete response event if all requests are completed */ + if (0 == context->request_bitmap) + complete(&context->response_event); + spin_unlock(&context->context_lock); + + break; + } + default: + hdd_err("invalid event type %d", indType); + break; + } + + return; +} + +void hdd_lost_link_info_cb(void *context, + struct sir_lost_link_info *lost_link_info) +{ + hdd_context_t *hdd_ctx = (hdd_context_t *)context; + int status; + hdd_adapter_t *adapter; + + status = wlan_hdd_validate_context(hdd_ctx); + if (0 != status) + return; + + if (NULL == lost_link_info) { + hdd_err("lost_link_info is NULL"); + return; + } + + adapter = hdd_get_adapter_by_vdev(hdd_ctx, lost_link_info->vdev_id); + if (NULL == adapter) { + hdd_err("invalid adapter"); + return; + } + + adapter->rssi_on_disconnect = lost_link_info->rssi; + hdd_info("rssi on disconnect %d", adapter->rssi_on_disconnect); +} + +const struct +nla_policy + qca_wlan_vendor_ll_set_policy[QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_CONFIG_MPDU_SIZE_THRESHOLD] = { + .type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_CONFIG_AGGRESSIVE_STATS_GATHERING] = { + .type = NLA_U32}, +}; + +/** + * __wlan_hdd_cfg80211_ll_stats_set() - set link layer stats + * @wiphy: Pointer to wiphy + * @wdev: Pointer to wdev + * @data: Pointer to data + * @data_len: Data length + * + * Return: int + */ +static int +__wlan_hdd_cfg80211_ll_stats_set(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int status; + struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_MAX + 1]; + tSirLLStatsSetReq LinkLayerStatsSetReq; + struct net_device *dev = wdev->netdev; + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *pHddCtx = wiphy_priv(wiphy); + + ENTER_DEV(dev); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_warn("Command not allowed in FTM mode"); + return -EPERM; + } + + status = wlan_hdd_validate_context(pHddCtx); + if (0 != status) + return -EINVAL; + + if (nla_parse(tb_vendor, QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_MAX, + (struct nlattr *)data, + data_len, qca_wlan_vendor_ll_set_policy)) { + hdd_err("maximum attribute not present"); + return -EINVAL; + } + + if (!tb_vendor + [QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_CONFIG_MPDU_SIZE_THRESHOLD]) { + hdd_err("MPDU size Not present"); + return -EINVAL; + } + + if (!tb_vendor + [QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_CONFIG_AGGRESSIVE_STATS_GATHERING]) { + hdd_err("Stats Gathering Not Present"); + return -EINVAL; + } + + /* Shall take the request Id if the Upper layers pass. 1 For now. */ + LinkLayerStatsSetReq.reqId = 1; + + LinkLayerStatsSetReq.mpduSizeThreshold = + nla_get_u32(tb_vendor + [QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_CONFIG_MPDU_SIZE_THRESHOLD]); + + LinkLayerStatsSetReq.aggressiveStatisticsGathering = + nla_get_u32(tb_vendor + [QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_CONFIG_AGGRESSIVE_STATS_GATHERING]); + + LinkLayerStatsSetReq.staId = pAdapter->sessionId; + + hdd_notice("LL_STATS_SET reqId = %d, staId = %d, mpduSizeThreshold = %d, Statistics Gathering = %d", + LinkLayerStatsSetReq.reqId, LinkLayerStatsSetReq.staId, + LinkLayerStatsSetReq.mpduSizeThreshold, + LinkLayerStatsSetReq.aggressiveStatisticsGathering); + + if (QDF_STATUS_SUCCESS != sme_ll_stats_set_req(pHddCtx->hHal, + &LinkLayerStatsSetReq)) { + hdd_err("sme_ll_stats_set_req Failed"); + return -EINVAL; + } + + pAdapter->isLinkLayerStatsSet = 1; + EXIT(); + return 0; +} + +/** + * wlan_hdd_cfg80211_ll_stats_set() - set ll stats + * @wiphy: Pointer to wiphy + * @wdev: Pointer to wdev + * @data: Pointer to data + * @data_len: Data length + * + * Return: 0 if success, non-zero for failure + */ +int wlan_hdd_cfg80211_ll_stats_set(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int ret = 0; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_ll_stats_set(wiphy, wdev, data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +const struct +nla_policy + qca_wlan_vendor_ll_get_policy[QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_MAX + 1] = { + /* Unsigned 32bit value provided by the caller issuing the GET stats + * command. When reporting + * the stats results, the driver uses the same value to indicate + * which GET request the results + * correspond to. + */ + [QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_CONFIG_REQ_ID] = {.type = NLA_U32}, + + /* Unsigned 32bit value . bit mask to identify what statistics are + requested for retrieval */ + [QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_CONFIG_REQ_MASK] = {.type = NLA_U32} +}; + +/** + * __wlan_hdd_cfg80211_ll_stats_get() - get link layer stats + * @wiphy: Pointer to wiphy + * @wdev: Pointer to wdev + * @data: Pointer to data + * @data_len: Data length + * + * Return: int + */ +static int +__wlan_hdd_cfg80211_ll_stats_get(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + unsigned long rc; + struct hdd_ll_stats_context *context; + hdd_context_t *pHddCtx = wiphy_priv(wiphy); + struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_MAX + 1]; + tSirLLStatsGetReq LinkLayerStatsGetReq; + struct net_device *dev = wdev->netdev; + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_station_ctx_t *hddstactx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + int status; + + /* ENTER() intentionally not used in a frequently invoked API */ + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_warn("Command not allowed in FTM mode"); + return -EPERM; + } + + status = wlan_hdd_validate_context(pHddCtx); + if (0 != status) + return -EINVAL; + + if (!pAdapter->isLinkLayerStatsSet) { + hdd_warn("isLinkLayerStatsSet: %d", + pAdapter->isLinkLayerStatsSet); + return -EINVAL; + } + + if (hddstactx->hdd_ReassocScenario) { + hdd_err("Roaming in progress, so unable to proceed this request"); + return -EBUSY; + } + + if (nla_parse(tb_vendor, QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_MAX, + (struct nlattr *)data, + data_len, qca_wlan_vendor_ll_get_policy)) { + hdd_err("max attribute not present"); + return -EINVAL; + } + + if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_CONFIG_REQ_ID]) { + hdd_err("Request Id Not present"); + return -EINVAL; + } + + if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_CONFIG_REQ_MASK]) { + hdd_err("Req Mask Not present"); + return -EINVAL; + } + + LinkLayerStatsGetReq.reqId = + nla_get_u32(tb_vendor + [QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_CONFIG_REQ_ID]); + LinkLayerStatsGetReq.paramIdMask = + nla_get_u32(tb_vendor + [QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_CONFIG_REQ_MASK]); + + LinkLayerStatsGetReq.staId = pAdapter->sessionId; + + if (wlan_hdd_validate_session_id(pAdapter->sessionId)) { + hdd_err("invalid session id: %d", pAdapter->sessionId); + return -EINVAL; + } + + context = &ll_stats_context; + spin_lock(&context->context_lock); + context->request_id = LinkLayerStatsGetReq.reqId; + context->request_bitmap = LinkLayerStatsGetReq.paramIdMask; + INIT_COMPLETION(context->response_event); + spin_unlock(&context->context_lock); + + if (QDF_STATUS_SUCCESS != sme_ll_stats_get_req(pHddCtx->hHal, + &LinkLayerStatsGetReq)) { + hdd_err("sme_ll_stats_get_req Failed"); + return -EINVAL; + } + + rc = wait_for_completion_timeout(&context->response_event, + msecs_to_jiffies(WLAN_WAIT_TIME_LL_STATS)); + if (!rc) { + hdd_err("Target response timed out request id %d request bitmap 0x%x", + context->request_id, context->request_bitmap); + return -ETIMEDOUT; + } + EXIT(); + return 0; +} + +/** + * wlan_hdd_cfg80211_ll_stats_get() - get ll stats + * @wiphy: Pointer to wiphy + * @wdev: Pointer to wdev + * @data: Pointer to data + * @data_len: Data length + * + * Return: 0 if success, non-zero for failure + */ +int wlan_hdd_cfg80211_ll_stats_get(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int ret = 0; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_ll_stats_get(wiphy, wdev, data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +const struct +nla_policy + qca_wlan_vendor_ll_clr_policy[QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_REQ_MASK] = {.type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_STOP_REQ] = {.type = NLA_U8}, + [QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_RSP_MASK] = {.type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_STOP_RSP] = {.type = NLA_U8}, +}; + +/** + * __wlan_hdd_cfg80211_ll_stats_clear() - clear link layer stats + * @wiphy: Pointer to wiphy + * @wdev: Pointer to wdev + * @data: Pointer to data + * @data_len: Data length + * + * Return: int + */ +static int +__wlan_hdd_cfg80211_ll_stats_clear(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + hdd_context_t *pHddCtx = wiphy_priv(wiphy); + struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_MAX + 1]; + tSirLLStatsClearReq LinkLayerStatsClearReq; + struct net_device *dev = wdev->netdev; + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + u32 statsClearReqMask; + u8 stopReq; + int status; + struct sk_buff *temp_skbuff; + + ENTER_DEV(dev); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_warn("Command not allowed in FTM mode"); + return -EPERM; + } + + status = wlan_hdd_validate_context(pHddCtx); + if (0 != status) + return -EINVAL; + + if (!pAdapter->isLinkLayerStatsSet) { + hdd_alert("isLinkLayerStatsSet : %d", + pAdapter->isLinkLayerStatsSet); + return -EINVAL; + } + + if (nla_parse(tb_vendor, QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_MAX, + (struct nlattr *)data, + data_len, qca_wlan_vendor_ll_clr_policy)) { + hdd_err("STATS_CLR_MAX is not present"); + return -EINVAL; + } + + if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_REQ_MASK] || + !tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_STOP_REQ]) { + hdd_err("Error in LL_STATS CLR CONFIG PARA"); + return -EINVAL; + } + + statsClearReqMask = LinkLayerStatsClearReq.statsClearReqMask = + nla_get_u32(tb_vendor + [QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_REQ_MASK]); + + stopReq = LinkLayerStatsClearReq.stopReq = + nla_get_u8(tb_vendor + [QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_STOP_REQ]); + + /* + * Shall take the request Id if the Upper layers pass. 1 For now. + */ + LinkLayerStatsClearReq.reqId = 1; + + LinkLayerStatsClearReq.staId = pAdapter->sessionId; + + hdd_notice("LL_STATS_CLEAR reqId = %d, staId = %d, statsClearReqMask = 0x%X, stopReq = %d", + LinkLayerStatsClearReq.reqId, + LinkLayerStatsClearReq.staId, + LinkLayerStatsClearReq.statsClearReqMask, + LinkLayerStatsClearReq.stopReq); + + if (QDF_STATUS_SUCCESS == sme_ll_stats_clear_req(pHddCtx->hHal, + &LinkLayerStatsClearReq)) { + temp_skbuff = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, + 2 * + sizeof(u32) + + 2 * + NLMSG_HDRLEN); + if (temp_skbuff != NULL) { + if (nla_put_u32(temp_skbuff, + QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_RSP_MASK, + statsClearReqMask) || + nla_put_u32(temp_skbuff, + QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_STOP_RSP, + stopReq)) { + hdd_err("LL_STATS_CLR put fail"); + kfree_skb(temp_skbuff); + return -EINVAL; + } + + /* If the ask is to stop the stats collection + * as part of clear (stopReq = 1), ensure + * that no further requests of get go to the + * firmware by having isLinkLayerStatsSet set + * to 0. However it the stopReq as part of + * the clear request is 0, the request to get + * the statistics are honoured as in this case + * the firmware is just asked to clear the + * statistics. + */ + if (stopReq == 1) + pAdapter->isLinkLayerStatsSet = 0; + + return cfg80211_vendor_cmd_reply(temp_skbuff); + } + EXIT(); + return -ENOMEM; + } + + return -EINVAL; +} + +/** + * wlan_hdd_cfg80211_ll_stats_clear() - clear ll stats + * @wiphy: Pointer to wiphy + * @wdev: Pointer to wdev + * @data: Pointer to data + * @data_len: Data length + * + * Return: 0 if success, non-zero for failure + */ +int wlan_hdd_cfg80211_ll_stats_clear(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int ret = 0; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_ll_stats_clear(wiphy, wdev, data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +#endif /* WLAN_FEATURE_LINK_LAYER_STATS */ + +#ifdef WLAN_FEATURE_STATS_EXT +/** + * __wlan_hdd_cfg80211_stats_ext_request() - ext stats request + * @wiphy: Pointer to wiphy + * @wdev: Pointer to wdev + * @data: Pointer to data + * @data_len: Data length + * + * Return: int + */ +static int __wlan_hdd_cfg80211_stats_ext_request(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + tStatsExtRequestReq stats_ext_req; + struct net_device *dev = wdev->netdev; + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + int ret_val; + QDF_STATUS status; + hdd_context_t *hdd_ctx = wiphy_priv(wiphy); + + ENTER_DEV(dev); + + ret_val = wlan_hdd_validate_context(hdd_ctx); + if (ret_val) + return ret_val; + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_warn("Command not allowed in FTM mode"); + return -EPERM; + } + + stats_ext_req.request_data_len = data_len; + stats_ext_req.request_data = (void *)data; + + status = sme_stats_ext_request(pAdapter->sessionId, &stats_ext_req); + + if (QDF_STATUS_SUCCESS != status) + ret_val = -EINVAL; + + return ret_val; +} + +/** + * wlan_hdd_cfg80211_stats_ext_request() - ext stats request + * @wiphy: Pointer to wiphy + * @wdev: Pointer to wdev + * @data: Pointer to data + * @data_len: Data length + * + * Return: int + */ +int wlan_hdd_cfg80211_stats_ext_request(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_stats_ext_request(wiphy, wdev, + data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * wlan_hdd_cfg80211_stats_ext_callback() - ext stats callback + * @ctx: Pointer to HDD context + * @msg: Message received + * + * Return: nothing + */ +void wlan_hdd_cfg80211_stats_ext_callback(void *ctx, + tStatsExtEvent *msg) +{ + + hdd_context_t *pHddCtx = (hdd_context_t *) ctx; + struct sk_buff *vendor_event; + int status; + int ret_val; + tStatsExtEvent *data = msg; + hdd_adapter_t *pAdapter = NULL; + + status = wlan_hdd_validate_context(pHddCtx); + if (status) + return; + + pAdapter = hdd_get_adapter_by_vdev(pHddCtx, data->vdev_id); + + if (NULL == pAdapter) { + hdd_err("vdev_id %d does not exist with host", data->vdev_id); + return; + } + + vendor_event = cfg80211_vendor_event_alloc(pHddCtx->wiphy, + NULL, + data->event_data_len + + sizeof(uint32_t) + + NLMSG_HDRLEN + NLMSG_HDRLEN, + QCA_NL80211_VENDOR_SUBCMD_STATS_EXT_INDEX, + GFP_KERNEL); + + if (!vendor_event) { + hdd_err("cfg80211_vendor_event_alloc failed"); + return; + } + + ret_val = nla_put_u32(vendor_event, QCA_WLAN_VENDOR_ATTR_IFINDEX, + pAdapter->dev->ifindex); + if (ret_val) { + hdd_err("QCA_WLAN_VENDOR_ATTR_IFINDEX put fail"); + kfree_skb(vendor_event); + + return; + } + + ret_val = nla_put(vendor_event, QCA_WLAN_VENDOR_ATTR_STATS_EXT, + data->event_data_len, data->event_data); + + if (ret_val) { + hdd_err("QCA_WLAN_VENDOR_ATTR_STATS_EXT put fail"); + kfree_skb(vendor_event); + + return; + } + + cfg80211_vendor_event(vendor_event, GFP_KERNEL); + +} +#endif /* End of WLAN_FEATURE_STATS_EXT */ + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 0, 0)) && !defined(WITH_BACKPORTS) +static inline void wlan_hdd_fill_station_info_signal(struct station_info + *sinfo) +{ + sinfo->filled |= STATION_INFO_SIGNAL; +} +#else +static inline void wlan_hdd_fill_station_info_signal(struct station_info + *sinfo) +{ + sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL); +} +#endif + +/** + * __wlan_hdd_cfg80211_get_station() - get station statistics + * @wiphy: Pointer to wiphy + * @dev: Pointer to network device + * @mac: Pointer to mac + * @sinfo: Pointer to station info + * + * Return: 0 for success, non-zero for failure + */ +static int __wlan_hdd_cfg80211_get_station(struct wiphy *wiphy, + struct net_device *dev, + const uint8_t *mac, + struct station_info *sinfo) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + int ssidlen = pHddStaCtx->conn_info.SSID.SSID.length; + uint8_t rate_flags; + uint8_t mcs_index; + + hdd_context_t *pHddCtx = (hdd_context_t *) wiphy_priv(wiphy); + struct hdd_config *pCfg = pHddCtx->config; + + uint8_t OperationalRates[CSR_DOT11_SUPPORTED_RATES_MAX]; + uint32_t ORLeng = CSR_DOT11_SUPPORTED_RATES_MAX; + uint8_t ExtendedRates[CSR_DOT11_EXTENDED_SUPPORTED_RATES_MAX]; + uint32_t ERLeng = CSR_DOT11_EXTENDED_SUPPORTED_RATES_MAX; + uint8_t MCSRates[SIZE_OF_BASIC_MCS_SET]; + uint32_t MCSLeng = SIZE_OF_BASIC_MCS_SET; + uint16_t maxRate = 0; + int8_t snr = 0; + uint16_t myRate; + uint16_t currentRate = 0; + uint8_t maxSpeedMCS = 0; + uint8_t maxMCSIdx = 0; + uint8_t rateFlag = 1; + uint8_t i, j, rssidx; + uint8_t nss = 1; + int status, mode = 0, maxHtIdx; + struct index_vht_data_rate_type *supported_vht_mcs_rate; + struct index_data_rate_type *supported_mcs_rate; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) + bool rssi_stats_valid = false; +#endif + + uint32_t vht_mcs_map; + enum eDataRate11ACMaxMcs vhtMaxMcs; + int32_t rcpi_value; + + ENTER_DEV(dev); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_warn("Command not allowed in FTM mode"); + return -EINVAL; + } + + if (wlan_hdd_validate_session_id(pAdapter->sessionId)) { + hdd_err("invalid session id: %d", pAdapter->sessionId); + return -EINVAL; + } + + if ((eConnectionState_Associated != pHddStaCtx->conn_info.connState) || + (0 == ssidlen)) { + hdd_notice("Not associated or Invalid ssidlen, %d", + ssidlen); + /*To keep GUI happy */ + return 0; + } + + if (true == pHddStaCtx->hdd_ReassocScenario) { + hdd_notice("Roaming is in progress, cannot continue with this request"); + /* + * supplicant reports very low rssi to upper layer + * and handover happens to cellular. + * send the cached rssi when get_station + */ + sinfo->signal = pAdapter->rssi; + wlan_hdd_fill_station_info_signal(sinfo); + return 0; + } + + status = wlan_hdd_validate_context(pHddCtx); + + if (0 != status) + return status; + + if (pHddCtx->rcpi_enabled) + wlan_hdd_get_rcpi(pAdapter, (uint8_t *)mac, &rcpi_value, + RCPI_MEASUREMENT_TYPE_AVG_MGMT); + + wlan_hdd_get_station_stats(pAdapter); + + if (pAdapter->hdd_stats.summary_stat.rssi) + pAdapter->rssi = pAdapter->hdd_stats.summary_stat.rssi; + + /* for new connection there might be no valid previous RSSI */ + if (!pAdapter->rssi) { + hdd_get_rssi_snr_by_bssid(pAdapter, + pHddStaCtx->conn_info.bssId.bytes, + &pAdapter->rssi, NULL); + } + + sinfo->signal = pAdapter->rssi; + snr = pAdapter->hdd_stats.summary_stat.snr; + hdd_info("snr: %d, rssi: %d", + pAdapter->hdd_stats.summary_stat.snr, + pAdapter->hdd_stats.summary_stat.rssi); + pHddStaCtx->conn_info.signal = sinfo->signal; + pHddStaCtx->conn_info.noise = + pHddStaCtx->conn_info.signal - snr; + + wlan_hdd_fill_station_info_signal(sinfo); + + /* + * we notify connect to lpass here instead of during actual + * connect processing because rssi info is not accurate during + * actual connection. lpass will ensure the notification is + * only processed once per association. + */ + hdd_lpass_notify_connect(pAdapter); + + rate_flags = pAdapter->hdd_stats.ClassA_stat.tx_rate_flags; + mcs_index = pAdapter->hdd_stats.ClassA_stat.mcs_index; + + /* convert to the UI units of 100kbps */ + myRate = pAdapter->hdd_stats.ClassA_stat.tx_rate * 5; + if (!(rate_flags & eHAL_TX_RATE_LEGACY)) { + nss = pAdapter->hdd_stats.ClassA_stat.rx_frag_cnt; + + if (eHDD_LINK_SPEED_REPORT_ACTUAL == pCfg->reportMaxLinkSpeed) { + /* Get current rate flags if report actual */ + rate_flags = + pAdapter->hdd_stats.ClassA_stat. + promiscuous_rx_frag_cnt; + } + + if (mcs_index == INVALID_MCS_IDX) + mcs_index = 0; + } + + hdd_info("RSSI %d, RLMS %u, rate %d, rssi high %d, rssi mid %d, rssi low %d, rate_flags 0x%x, MCS %d", + sinfo->signal, pCfg->reportMaxLinkSpeed, myRate, + (int)pCfg->linkSpeedRssiHigh, (int)pCfg->linkSpeedRssiMid, + (int)pCfg->linkSpeedRssiLow, (int)rate_flags, (int)mcs_index); + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)) || defined(WITH_BACKPORTS) + /* assume basic BW. anything else will override this later */ + sinfo->txrate.bw = RATE_INFO_BW_20; +#endif + + if (eHDD_LINK_SPEED_REPORT_ACTUAL != pCfg->reportMaxLinkSpeed) { + /* we do not want to necessarily report the current speed */ + if (eHDD_LINK_SPEED_REPORT_MAX == pCfg->reportMaxLinkSpeed) { + /* report the max possible speed */ + rssidx = 0; + } else if (eHDD_LINK_SPEED_REPORT_MAX_SCALED == + pCfg->reportMaxLinkSpeed) { + /* report the max possible speed with RSSI scaling */ + if (sinfo->signal >= pCfg->linkSpeedRssiHigh) { + /* report the max possible speed */ + rssidx = 0; + } else if (sinfo->signal >= pCfg->linkSpeedRssiMid) { + /* report middle speed */ + rssidx = 1; + } else if (sinfo->signal >= pCfg->linkSpeedRssiLow) { + /* report middle speed */ + rssidx = 2; + } else { + /* report actual speed */ + rssidx = 3; + } + } else { + /* unknown, treat as eHDD_LINK_SPEED_REPORT_MAX */ + hdd_err("Invalid value for reportMaxLinkSpeed: %u", + pCfg->reportMaxLinkSpeed); + rssidx = 0; + } + + maxRate = 0; + + /* Get Basic Rate Set */ + if (0 != + sme_cfg_get_str(WLAN_HDD_GET_HAL_CTX(pAdapter), + WNI_CFG_OPERATIONAL_RATE_SET, + OperationalRates, + &ORLeng)) { + hdd_err("cfg get returned failure"); + /*To keep GUI happy */ + return 0; + } + + for (i = 0; i < ORLeng; i++) { + for (j = 0; + j < ARRAY_SIZE(supported_data_rate); j++) { + /* Validate Rate Set */ + if (supported_data_rate[j].beacon_rate_index == + (OperationalRates[i] & 0x7F)) { + currentRate = + supported_data_rate[j]. + supported_rate[rssidx]; + break; + } + } + /* Update MAX rate */ + maxRate = + (currentRate > maxRate) ? currentRate : maxRate; + } + + /* Get Extended Rate Set */ + if (0 != + sme_cfg_get_str(WLAN_HDD_GET_HAL_CTX(pAdapter), + WNI_CFG_EXTENDED_OPERATIONAL_RATE_SET, + ExtendedRates, &ERLeng)) { + hdd_err("cfg get returned failure"); + /*To keep GUI happy */ + return 0; + } + + for (i = 0; i < ERLeng; i++) { + for (j = 0; + j < ARRAY_SIZE(supported_data_rate); j++) { + if (supported_data_rate[j].beacon_rate_index == + (ExtendedRates[i] & 0x7F)) { + currentRate = + supported_data_rate[j]. + supported_rate[rssidx]; + break; + } + } + /* Update MAX rate */ + maxRate = + (currentRate > maxRate) ? currentRate : maxRate; + } + /* Get MCS Rate Set -- + Only if we are connected in non legacy mode and not reporting + actual speed */ + if ((3 != rssidx) && !(rate_flags & eHAL_TX_RATE_LEGACY)) { + if (0 != + sme_cfg_get_str(WLAN_HDD_GET_HAL_CTX(pAdapter), + WNI_CFG_CURRENT_MCS_SET, MCSRates, + &MCSLeng)) { + hdd_err("cfg get returned failure"); + /*To keep GUI happy */ + return 0; + } + rateFlag = 0; + supported_vht_mcs_rate = + (struct index_vht_data_rate_type *) + ((nss == + 1) ? &supported_vht_mcs_rate_nss1 : + &supported_vht_mcs_rate_nss2); + + if (rate_flags & eHAL_TX_RATE_VHT80) + mode = 2; + else if ((rate_flags & eHAL_TX_RATE_VHT40) || + (rate_flags & eHAL_TX_RATE_HT40)) + mode = 1; + else + mode = 0; + + /* VHT80 rate has seperate rate table */ + if (rate_flags & + (eHAL_TX_RATE_VHT20 | eHAL_TX_RATE_VHT40 | + eHAL_TX_RATE_VHT80)) { + sme_cfg_get_int(WLAN_HDD_GET_HAL_CTX(pAdapter), + WNI_CFG_VHT_TX_MCS_MAP, + &vht_mcs_map); + vhtMaxMcs = (enum eDataRate11ACMaxMcs) + (vht_mcs_map & DATA_RATE_11AC_MCS_MASK); + if (rate_flags & eHAL_TX_RATE_SGI) + rateFlag |= 1; + if (DATA_RATE_11AC_MAX_MCS_7 == vhtMaxMcs) + maxMCSIdx = 7; + else if (DATA_RATE_11AC_MAX_MCS_8 == + vhtMaxMcs) + maxMCSIdx = 8; + else if (DATA_RATE_11AC_MAX_MCS_9 == + vhtMaxMcs) { + /* + * IEEE_P802.11ac_2013.pdf page 325, 326 + * - MCS9 is valid for VHT20 when + * Nss = 3 or Nss = 6 + * - MCS9 is not valid for VHT20 when + * Nss = 1,2,4,5,7,8 + */ + if ((rate_flags & eHAL_TX_RATE_VHT20) && + (nss != 3 && nss != 6)) + maxMCSIdx = 8; + else + maxMCSIdx = 9; + } + + if (rssidx != 0) { + for (i = 0; i <= maxMCSIdx; i++) { + if (sinfo->signal <= + rssi_mcs_tbl[mode][i]) { + maxMCSIdx = i; + break; + } + } + } + + if (rate_flags & eHAL_TX_RATE_VHT80) { + currentRate = + supported_vht_mcs_rate[mcs_index]. + supported_VHT80_rate[rateFlag]; + maxRate = + supported_vht_mcs_rate[maxMCSIdx]. + supported_VHT80_rate[rateFlag]; + } else if (rate_flags & eHAL_TX_RATE_VHT40) { + currentRate = + supported_vht_mcs_rate[mcs_index]. + supported_VHT40_rate[rateFlag]; + maxRate = + supported_vht_mcs_rate[maxMCSIdx]. + supported_VHT40_rate[rateFlag]; + } else if (rate_flags & eHAL_TX_RATE_VHT20) { + currentRate = + supported_vht_mcs_rate[mcs_index]. + supported_VHT20_rate[rateFlag]; + maxRate = + supported_vht_mcs_rate[maxMCSIdx]. + supported_VHT20_rate[rateFlag]; + } + + maxSpeedMCS = 1; + if (currentRate > maxRate) + maxRate = currentRate; + + } else { + if (rate_flags & eHAL_TX_RATE_HT40) + rateFlag |= 1; + if (rate_flags & eHAL_TX_RATE_SGI) + rateFlag |= 2; + + supported_mcs_rate = + (struct index_data_rate_type *) + ((nss == + 1) ? &supported_mcs_rate_nss1 : + &supported_mcs_rate_nss2); + + maxHtIdx = MAX_HT_MCS_IDX; + if (rssidx != 0) { + for (i = 0; i < MAX_HT_MCS_IDX; i++) { + if (sinfo->signal <= + rssi_mcs_tbl[mode][i]) { + maxHtIdx = i + 1; + break; + } + } + } + + for (i = 0; i < MCSLeng; i++) { + for (j = 0; j < maxHtIdx; j++) { + if (supported_mcs_rate[j]. + beacon_rate_index == + MCSRates[i]) { + currentRate = + supported_mcs_rate[j]. + supported_rate + [rateFlag]; + maxMCSIdx = + supported_mcs_rate[j]. + beacon_rate_index; + break; + } + } + + if ((j < MAX_HT_MCS_IDX) + && (currentRate > maxRate)) { + maxRate = currentRate; + } + maxSpeedMCS = 1; + } + } + } + + else if (!(rate_flags & eHAL_TX_RATE_LEGACY)) { + maxRate = myRate; + maxSpeedMCS = 1; + maxMCSIdx = mcs_index; + } + /* report a value at least as big as current rate */ + if ((maxRate < myRate) || (0 == maxRate)) { + maxRate = myRate; + if (rate_flags & eHAL_TX_RATE_LEGACY) { + maxSpeedMCS = 0; + } else { + maxSpeedMCS = 1; + maxMCSIdx = mcs_index; + /* + * IEEE_P802.11ac_2013.pdf page 325, 326 + * - MCS9 is valid for VHT20 when + * Nss = 3 or Nss = 6 + * - MCS9 is not valid for VHT20 when + * Nss = 1,2,4,5,7,8 + */ + if ((rate_flags & eHAL_TX_RATE_VHT20) && + (maxMCSIdx > 8) && + (nss != 3 && nss != 6)) { + maxMCSIdx = 8; + } + } + } + + if (rate_flags & eHAL_TX_RATE_LEGACY) { + sinfo->txrate.legacy = maxRate; +#ifdef LINKSPEED_DEBUG_ENABLED + pr_info("Reporting legacy rate %d\n", + sinfo->txrate.legacy); +#endif /* LINKSPEED_DEBUG_ENABLED */ + } else { + sinfo->txrate.mcs = maxMCSIdx; + sinfo->txrate.nss = nss; + if (rate_flags & eHAL_TX_RATE_VHT80) { + sinfo->txrate.flags |= RATE_INFO_FLAGS_VHT_MCS; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)) || defined(WITH_BACKPORTS) + sinfo->txrate.bw = RATE_INFO_BW_80; +#else + sinfo->txrate.flags |= + RATE_INFO_FLAGS_80_MHZ_WIDTH; +#endif + } else if (rate_flags & eHAL_TX_RATE_VHT40) { + sinfo->txrate.flags |= RATE_INFO_FLAGS_VHT_MCS; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)) || defined(WITH_BACKPORTS) + sinfo->txrate.bw = RATE_INFO_BW_40; +#else + sinfo->txrate.flags |= + RATE_INFO_FLAGS_40_MHZ_WIDTH; +#endif + } else if (rate_flags & eHAL_TX_RATE_VHT20) { + sinfo->txrate.flags |= RATE_INFO_FLAGS_VHT_MCS; + } else + sinfo->txrate.flags |= RATE_INFO_FLAGS_VHT_MCS; + if (rate_flags & + (eHAL_TX_RATE_HT20 | eHAL_TX_RATE_HT40)) { + sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS; + if (rate_flags & eHAL_TX_RATE_HT40) { +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)) || defined(WITH_BACKPORTS) + sinfo->txrate.bw = RATE_INFO_BW_40; +#else + sinfo->txrate.flags |= + RATE_INFO_FLAGS_40_MHZ_WIDTH; +#endif + } + } + if (rate_flags & eHAL_TX_RATE_SGI) { + if (! + (sinfo->txrate. + flags & RATE_INFO_FLAGS_VHT_MCS)) + sinfo->txrate.flags |= + RATE_INFO_FLAGS_MCS; + sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI; + } +#ifdef LINKSPEED_DEBUG_ENABLED + pr_info("Reporting MCS rate %d flags %x\n", + sinfo->txrate.mcs, sinfo->txrate.flags); +#endif /* LINKSPEED_DEBUG_ENABLED */ + } + } else { + /* report current rate instead of max rate */ + + if (rate_flags & eHAL_TX_RATE_LEGACY) { + /* provide to the UI in units of 100kbps */ + sinfo->txrate.legacy = myRate; +#ifdef LINKSPEED_DEBUG_ENABLED + pr_info("Reporting actual legacy rate %d\n", + sinfo->txrate.legacy); +#endif /* LINKSPEED_DEBUG_ENABLED */ + } else { + /* must be MCS */ + sinfo->txrate.mcs = mcs_index; + sinfo->txrate.nss = nss; + sinfo->txrate.flags |= RATE_INFO_FLAGS_VHT_MCS; + if (rate_flags & eHAL_TX_RATE_VHT80) { +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)) || defined(WITH_BACKPORTS) + sinfo->txrate.bw = RATE_INFO_BW_80; +#else + sinfo->txrate.flags |= + RATE_INFO_FLAGS_80_MHZ_WIDTH; +#endif + } else if (rate_flags & eHAL_TX_RATE_VHT40) { +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)) || defined(WITH_BACKPORTS) + sinfo->txrate.bw = RATE_INFO_BW_40; +#else + sinfo->txrate.flags |= + RATE_INFO_FLAGS_40_MHZ_WIDTH; +#endif + } + if (rate_flags & + (eHAL_TX_RATE_HT20 | eHAL_TX_RATE_HT40)) { + sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS; + if (rate_flags & eHAL_TX_RATE_HT40) { +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)) || defined(WITH_BACKPORTS) + sinfo->txrate.bw = RATE_INFO_BW_40; +#else + sinfo->txrate.flags |= + RATE_INFO_FLAGS_40_MHZ_WIDTH; +#endif + } + } + if (rate_flags & eHAL_TX_RATE_SGI) { + sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS; + sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI; + } +#ifdef LINKSPEED_DEBUG_ENABLED + pr_info("Reporting actual MCS rate %d flags %x\n", + sinfo->txrate.mcs, sinfo->txrate.flags); +#endif /* LINKSPEED_DEBUG_ENABLED */ + } + } + + sinfo->tx_bytes = pAdapter->stats.tx_bytes; + + sinfo->tx_packets = + pAdapter->hdd_stats.summary_stat.tx_frm_cnt[0] + + pAdapter->hdd_stats.summary_stat.tx_frm_cnt[1] + + pAdapter->hdd_stats.summary_stat.tx_frm_cnt[2] + + pAdapter->hdd_stats.summary_stat.tx_frm_cnt[3]; + + sinfo->tx_retries = + pAdapter->hdd_stats.summary_stat.multiple_retry_cnt[0] + + pAdapter->hdd_stats.summary_stat.multiple_retry_cnt[1] + + pAdapter->hdd_stats.summary_stat.multiple_retry_cnt[2] + + pAdapter->hdd_stats.summary_stat.multiple_retry_cnt[3]; + + sinfo->tx_failed = + pAdapter->hdd_stats.summary_stat.fail_cnt[0] + + pAdapter->hdd_stats.summary_stat.fail_cnt[1] + + pAdapter->hdd_stats.summary_stat.fail_cnt[2] + + pAdapter->hdd_stats.summary_stat.fail_cnt[3]; + + sinfo->rx_bytes = pAdapter->stats.rx_bytes; + sinfo->rx_packets = pAdapter->stats.rx_packets; + + qdf_mem_copy(&pHddStaCtx->conn_info.txrate, + &sinfo->txrate, sizeof(sinfo->txrate)); + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 0, 0)) && !defined(WITH_BACKPORTS) + sinfo->filled |= STATION_INFO_TX_BITRATE | + STATION_INFO_TX_BYTES | + STATION_INFO_TX_PACKETS | + STATION_INFO_TX_RETRIES | + STATION_INFO_TX_FAILED | + STATION_INFO_RX_BYTES | + STATION_INFO_RX_PACKETS; +#else + sinfo->filled |= BIT(NL80211_STA_INFO_TX_BYTES) | + BIT(NL80211_STA_INFO_TX_BITRATE) | + BIT(NL80211_STA_INFO_TX_PACKETS) | + BIT(NL80211_STA_INFO_TX_RETRIES) | + BIT(NL80211_STA_INFO_TX_FAILED) | + BIT(NL80211_STA_INFO_RX_BYTES) | + BIT(NL80211_STA_INFO_RX_PACKETS); +#endif + + if (rate_flags & eHAL_TX_RATE_LEGACY) + hdd_notice("Reporting legacy rate %d pkt cnt tx %d rx %d", + sinfo->txrate.legacy, sinfo->tx_packets, + sinfo->rx_packets); + else + hdd_notice("Reporting MCS rate %d flags 0x%x pkt cnt tx %d rx %d", + sinfo->txrate.mcs, sinfo->txrate.flags, + sinfo->tx_packets, sinfo->rx_packets); + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) + sinfo->signal_avg = WLAN_HDD_TGT_NOISE_FLOOR_DBM; + for (i = 0; i < NUM_CHAINS_MAX; i++) { + sinfo->chain_signal_avg[i] = + pAdapter->hdd_stats.per_chain_rssi_stats.rssi[i]; + sinfo->chains |= 1 << i; + if (sinfo->chain_signal_avg[i] > sinfo->signal_avg && + sinfo->chain_signal_avg[i] != 0) + sinfo->signal_avg = sinfo->chain_signal_avg[i]; + + hdd_info("RSSI for chain %d, vdev_id %d is %d", + i, pAdapter->sessionId, sinfo->chain_signal_avg[i]); + + if (!rssi_stats_valid && sinfo->chain_signal_avg[i]) + rssi_stats_valid = true; + } + + if (rssi_stats_valid) { +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 0, 0)) && !defined(WITH_BACKPORTS) + sinfo->filled |= STATION_INFO_CHAIN_SIGNAL_AVG; + sinfo->filled |= STATION_INFO_SIGNAL_AVG; +#else + sinfo->filled |= BIT(NL80211_STA_INFO_CHAIN_SIGNAL_AVG); + sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL_AVG); +#endif + } +#endif + + + MTRACE(qdf_trace(QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_CFG80211_GET_STA, + pAdapter->sessionId, maxRate)); + EXIT(); + return 0; +} + +/** + * wlan_hdd_cfg80211_get_station() - get station statistics + * @wiphy: Pointer to wiphy + * @dev: Pointer to network device + * @mac: Pointer to mac + * @sinfo: Pointer to station info + * + * Return: 0 for success, non-zero for failure + */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)) +int wlan_hdd_cfg80211_get_station(struct wiphy *wiphy, + struct net_device *dev, const uint8_t *mac, + struct station_info *sinfo) +#else +int wlan_hdd_cfg80211_get_station(struct wiphy *wiphy, + struct net_device *dev, uint8_t *mac, + struct station_info *sinfo) +#endif +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_get_station(wiphy, dev, mac, sinfo); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __wlan_hdd_cfg80211_dump_station() - dump station statistics + * @wiphy: Pointer to wiphy + * @dev: Pointer to network device + * @idx: variable to determine whether to get stats or not + * @mac: Pointer to mac + * @sinfo: Pointer to station info + * + * Return: 0 for success, non-zero for failure + */ +static int __wlan_hdd_cfg80211_dump_station(struct wiphy *wiphy, + struct net_device *dev, + int idx, u8 *mac, + struct station_info *sinfo) +{ + hdd_context_t *hdd_ctx = (hdd_context_t *) wiphy_priv(wiphy); + + hdd_debug("%s: idx %d", __func__, idx); + if (idx != 0) + return -ENOENT; + qdf_mem_copy(mac, hdd_ctx->config->intfMacAddr[0].bytes, + QDF_MAC_ADDR_SIZE); + return __wlan_hdd_cfg80211_get_station(wiphy, dev, mac, sinfo); +} + +/** + * wlan_hdd_cfg80211_dump_station() - dump station statistics + * @wiphy: Pointer to wiphy + * @dev: Pointer to network device + * @idx: variable to determine whether to get stats or not + * @mac: Pointer to mac + * @sinfo: Pointer to station info + * + * Return: 0 for success, non-zero for failure + */ +int wlan_hdd_cfg80211_dump_station(struct wiphy *wiphy, + struct net_device *dev, + int idx, u8 *mac, + struct station_info *sinfo) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_dump_station(wiphy, dev, idx, mac, sinfo); + cds_ssr_unprotect(__func__); + return ret; +} + +/** + * hdd_get_stats() - Function to retrieve interface statistics + * @dev: pointer to network device + * + * This function is the ndo_get_stats method for all netdevs + * registered with the kernel + * + * Return: pointer to net_device_stats structure + */ +struct net_device_stats *hdd_get_stats(struct net_device *dev) +{ + hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + + ENTER_DEV(dev); + return &adapter->stats; +} +/** + * __wlan_hdd_cfg80211_dump_survey() - get survey related info + * @wiphy: Pointer to wiphy + * @dev: Pointer to network device + * @idx: Index + * @survey: Pointer to survey info + * + * Return: 0 for success, non-zero for failure + */ +static int __wlan_hdd_cfg80211_dump_survey(struct wiphy *wiphy, + struct net_device *dev, + int idx, struct survey_info *survey) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *pHddCtx; + hdd_station_ctx_t *pHddStaCtx; + tHalHandle halHandle; + uint32_t channel = 0, freq = 0; /* Initialization Required */ + int8_t snr, rssi; + int status, i, j, filled = 0; + + ENTER_DEV(dev); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_warn("Command not allowed in FTM mode"); + return -EINVAL; + } + + pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + status = wlan_hdd_validate_context(pHddCtx); + + if (0 != status) + return status; + + pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + + if (0 == pHddCtx->config->fEnableSNRMonitoring || + 0 != pAdapter->survey_idx || + eConnectionState_Associated != pHddStaCtx->conn_info.connState) { + /* The survey dump ops when implemented completely is expected + * to return a survey of all channels and the ops is called by + * the kernel with incremental values of the argument 'idx' + * till it returns -ENONET. But we can only support the survey + * for the operating channel for now. survey_idx is used to + * track that the ops is called only once and then return + * -ENONET for the next iteration + */ + pAdapter->survey_idx = 0; + return -ENONET; + } + + if (!pHddStaCtx->hdd_ReassocScenario) { + hdd_err("Roaming in progress, hence return"); + return -ENONET; + } + + halHandle = WLAN_HDD_GET_HAL_CTX(pAdapter); + + wlan_hdd_get_snr(pAdapter, &snr); + wlan_hdd_get_rssi(pAdapter, &rssi); + + MTRACE(qdf_trace(QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_CFG80211_DUMP_SURVEY, + pAdapter->sessionId, pAdapter->device_mode)); + + sme_get_operation_channel(halHandle, &channel, pAdapter->sessionId); + hdd_wlan_get_freq(channel, &freq); + + for (i = 0; i < NUM_NL80211_BANDS; i++) { + if (NULL == wiphy->bands[i]) + continue; + + for (j = 0; j < wiphy->bands[i]->n_channels; j++) { + struct ieee80211_supported_band *band = wiphy->bands[i]; + + if (band->channels[j].center_freq == (uint16_t) freq) { + survey->channel = &band->channels[j]; + /* The Rx BDs contain SNR values in dB for the + * received frames while the supplicant expects + * noise. So we calculate and return the value + * of noise (dBm) + * SNR (dB) = RSSI (dBm) - NOISE (dBm) + */ + survey->noise = rssi - snr; + survey->filled = SURVEY_INFO_NOISE_DBM; + filled = 1; + } + } + } + + if (filled) + pAdapter->survey_idx = 1; + else { + pAdapter->survey_idx = 0; + return -ENONET; + } + EXIT(); + return 0; +} + +/** + * wlan_hdd_cfg80211_dump_survey() - get survey related info + * @wiphy: Pointer to wiphy + * @dev: Pointer to network device + * @idx: Index + * @survey: Pointer to survey info + * + * Return: 0 for success, non-zero for failure + */ +int wlan_hdd_cfg80211_dump_survey(struct wiphy *wiphy, + struct net_device *dev, + int idx, struct survey_info *survey) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_dump_survey(wiphy, dev, idx, survey); + cds_ssr_unprotect(__func__); + + return ret; +} +/** + * hdd_init_ll_stats_ctx() - initialize link layer stats context + * + * Return: none + */ +inline void hdd_init_ll_stats_ctx(void) +{ + spin_lock_init(&ll_stats_context.context_lock); + init_completion(&ll_stats_context.response_event); + ll_stats_context.request_bitmap = 0; + + return; +} + +/** + * hdd_display_hif_stats() - display hif stats + * + * Return: none + * + */ +void hdd_display_hif_stats(void) +{ + void *hif_ctx = cds_get_context(QDF_MODULE_ID_HIF); + + if (!hif_ctx) + return; + hif_display_stats(hif_ctx); +} + +/** + * hdd_clear_hif_stats() - clear hif stats + * + * Return: none + */ +void hdd_clear_hif_stats(void) +{ + void *hif_ctx = cds_get_context(QDF_MODULE_ID_HIF); + + if (!hif_ctx) + return; + hif_clear_stats(hif_ctx); +} + +/** + * hdd_is_rcpi_applicable() - validates RCPI request + * @adapter: adapter upon which the measurement is requested + * @mac_addr: peer addr for which measurement is requested + * @rcpi_value: pointer to where the RCPI should be returned + * @reassoc: used to return cached RCPI during reassoc + * + * Return: true for success, false for failure + */ + +static bool hdd_is_rcpi_applicable(hdd_adapter_t *adapter, + struct qdf_mac_addr *mac_addr, + int32_t *rcpi_value, + bool *reassoc) +{ + hdd_station_ctx_t *hdd_sta_ctx; + + if (adapter->device_mode == QDF_STA_MODE || + adapter->device_mode == QDF_P2P_CLIENT_MODE) { + hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + if (hdd_sta_ctx->conn_info.connState != + eConnectionState_Associated) + return false; + + if (hdd_sta_ctx->hdd_ReassocScenario) { + /* return the cached rcpi, if mac addr matches */ + hdd_info("Roaming in progress, return cached RCPI"); + if (!qdf_mem_cmp(&adapter->rcpi.mac_addr, + mac_addr, sizeof(*mac_addr))) { + *rcpi_value = adapter->rcpi.rcpi; + *reassoc = true; + return true; + } + return false; + } + + if (qdf_mem_cmp(mac_addr, &hdd_sta_ctx->conn_info.bssId, + sizeof(*mac_addr))) { + hdd_err("mac addr is different from bssid connected"); + return false; + } + } else if (adapter->device_mode == QDF_SAP_MODE || + adapter->device_mode == QDF_P2P_GO_MODE) { + if (!test_bit(SOFTAP_BSS_STARTED, &adapter->event_flags)) { + hdd_err("Invalid rcpi request, softap not started"); + return false; + } + + /* check if peer mac addr is associated to softap */ + if (!hdd_is_peer_associated(adapter, mac_addr)) { + hdd_err("invalid peer mac-addr: not associated"); + return false; + } + } else { + hdd_err("Invalid rcpi request"); + return false; + } + + *reassoc = false; + return true; +} + +/** + * wlan_hdd_get_rcpi_cb() - callback function for rcpi response + * @context: Pointer to rcpi context + * @rcpi_req: Pointer to rcpi response + * + * Return: None + */ +static void wlan_hdd_get_rcpi_cb(void *context, struct qdf_mac_addr mac_addr, + int32_t rcpi, QDF_STATUS status) +{ + hdd_adapter_t *adapter; + struct statsContext *rcpi_context; + + if (!context) { + hdd_err("No rcpi context"); + return; + } + + rcpi_context = context; + adapter = rcpi_context->pAdapter; + if (adapter->magic != WLAN_HDD_ADAPTER_MAGIC) { + hdd_err("Invalid adapter magic"); + 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); + if (rcpi_context->magic != RCPI_CONTEXT_MAGIC) { + /* + * the caller presumably timed out so there is nothing + * we can do + */ + spin_unlock(&hdd_context_lock); + hdd_warn("Invalid RCPI context magic"); + return; + } + + rcpi_context->magic = 0; + adapter->rcpi.mac_addr = mac_addr; + if (status != QDF_STATUS_SUCCESS) + /* peer rcpi is not available for requested mac addr */ + adapter->rcpi.rcpi = 0; + else + adapter->rcpi.rcpi = rcpi; + + /* notify the caller */ + complete(&rcpi_context->completion); + + /* serialization is complete */ + spin_unlock(&hdd_context_lock); +} + +/** + * __wlan_hdd_get_rcpi() - local function to get RCPI + * @adapter: adapter upon which the measurement is requested + * @mac: peer addr for which measurement is requested + * @rcpi_value: pointer to where the RCPI should be returned + * @measurement_type: type of rcpi measurement + * + * Return: 0 for success, non-zero for failure + */ +static int __wlan_hdd_get_rcpi(hdd_adapter_t *adapter, + uint8_t *mac, + int32_t *rcpi_value, + enum rcpi_measurement_type measurement_type) +{ + hdd_context_t *hdd_ctx; + static struct statsContext rcpi_context; + int status = 0; + unsigned long rc; + struct qdf_mac_addr mac_addr; + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + struct sme_rcpi_req *rcpi_req; + bool reassoc; + + ENTER(); + + /* initialize the rcpi value to zero, useful in error cases */ + *rcpi_value = 0; + + if (hdd_get_conparam() == QDF_GLOBAL_FTM_MODE) { + hdd_err("Command not allowed in FTM mode"); + return -EINVAL; + } + + if (!adapter) { + hdd_warn("adapter context is NULL"); + return -EINVAL; + } + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + status = wlan_hdd_validate_context(hdd_ctx); + if (status) + return -EINVAL; + + if (!hdd_ctx->rcpi_enabled) { + hdd_info("RCPI not supported"); + return -EINVAL; + } + + if (!mac) { + hdd_warn("RCPI peer mac-addr is NULL"); + return -EINVAL; + } + + qdf_mem_copy(&mac_addr, mac, QDF_MAC_ADDR_SIZE); + + if (!hdd_is_rcpi_applicable(adapter, &mac_addr, rcpi_value, &reassoc)) + return -EINVAL; + if (reassoc) + return 0; + + rcpi_req = qdf_mem_malloc(sizeof(*rcpi_req)); + if (!rcpi_req) { + hdd_err("unable to allocate memory for RCPI req"); + return -EINVAL; + } + + init_completion(&rcpi_context.completion); + rcpi_context.pAdapter = adapter; + rcpi_context.magic = RCPI_CONTEXT_MAGIC; + + rcpi_req->mac_addr = mac_addr; + rcpi_req->session_id = adapter->sessionId; + rcpi_req->measurement_type = measurement_type; + rcpi_req->rcpi_callback = wlan_hdd_get_rcpi_cb; + rcpi_req->rcpi_context = &rcpi_context; + + qdf_status = sme_get_rcpi(hdd_ctx->hHal, rcpi_req); + if (qdf_status != QDF_STATUS_SUCCESS) { + hdd_err("Unable to retrieve RCPI"); + status = qdf_status_to_os_return(qdf_status); + } else { + /* request was sent -- wait for the response */ + rc = wait_for_completion_timeout(&rcpi_context.completion, + msecs_to_jiffies(WLAN_WAIT_TIME_RCPI)); + if (!rc) { + hdd_err("SME timed out while retrieving RCPI"); + status = -EINVAL; + } + } + qdf_mem_free(rcpi_req); + + spin_lock(&hdd_context_lock); + rcpi_context.magic = 0; + spin_unlock(&hdd_context_lock); + + if (status) { + hdd_err("rcpi computation is failed"); + } else { + if (qdf_mem_cmp(&mac_addr, &adapter->rcpi.mac_addr, + sizeof(mac_addr))) { + hdd_err("mac addr is not matching from call-back"); + status = -EINVAL; + } else { + *rcpi_value = adapter->rcpi.rcpi; + hdd_info("RCPI = %d", *rcpi_value); + } + } + + EXIT(); + return status; +} + +int wlan_hdd_get_rcpi(hdd_adapter_t *adapter, uint8_t *mac, + int32_t *rcpi_value, + enum rcpi_measurement_type measurement_type) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_get_rcpi(adapter, mac, rcpi_value, measurement_type); + cds_ssr_unprotect(__func__); + + return ret; +} diff --git a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_stats.h b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_stats.h new file mode 100644 index 0000000000000000000000000000000000000000..6c7ffcfdbbb7f6b6e53e2f06362ca18eb4328aff --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_stats.h @@ -0,0 +1,241 @@ +/* + * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/** + * DOC : wlan_hdd_stats.h + * + * WLAN Host Device Driver statistics related implementation + * + */ + +#if !defined(WLAN_HDD_STATS_H) +#define WLAN_HDD_STATS_H + +#include "wlan_hdd_main.h" + +#define INVALID_MCS_IDX 255 +#define MAX_HT_MCS_IDX 8 +#define MAX_VHT_MCS_IDX 10 + +#define DATA_RATE_11AC_MCS_MASK 0x03 + +/* LL stats get request time out value */ +#define WLAN_WAIT_TIME_LL_STATS 800 + +#define WLAN_HDD_TGT_NOISE_FLOOR_DBM (-96) + +/** + * struct index_vht_data_rate_type - vht data rate type + * @beacon_rate_index: Beacon rate index + * @supported_VHT80_rate: VHT80 rate + * @supported_VHT40_rate: VHT40 rate + * @supported_VHT20_rate: VHT20 rate + */ +struct index_vht_data_rate_type { + uint8_t beacon_rate_index; + uint16_t supported_VHT80_rate[2]; + uint16_t supported_VHT40_rate[2]; + uint16_t supported_VHT20_rate[2]; +}; + +/** + * enum - eDataRate11ACMaxMcs + * @DATA_RATE_11AC_MAX_MCS_7: MCS7 rate + * @DATA_RATE_11AC_MAX_MCS_8: MCS8 rate + * @DATA_RATE_11AC_MAX_MCS_9: MCS9 rate + * @DATA_RATE_11AC_MAX_MCS_NA:i Not applicable + */ +enum eDataRate11ACMaxMcs{ + DATA_RATE_11AC_MAX_MCS_7, + DATA_RATE_11AC_MAX_MCS_8, + DATA_RATE_11AC_MAX_MCS_9, + DATA_RATE_11AC_MAX_MCS_NA +}; + +/** + * struct index_data_rate_type - non vht data rate type + * @beacon_rate_index: Beacon rate index + * @supported_rate: Supported rate table + */ +struct index_data_rate_type { + uint8_t beacon_rate_index; + uint16_t supported_rate[4]; +}; + +#ifdef WLAN_FEATURE_LINK_LAYER_STATS +/* + * Used to allocate the size of 4096 for the link layer stats. + * The size of 4096 is considered assuming that all data per + * respective event fit with in the limit.Please take a call + * on the limit based on the data requirements on link layer + * statistics. + */ +#define LL_STATS_EVENT_BUF_SIZE 4096 + +/** + * wlan_hdd_cfg80211_ll_stats_set() - set link layer stats + * @wiphy: Pointer to wiphy + * @wdev: Pointer to wdev + * @data: Pointer to data + * @data_len: Data length + * + * Return: int + */ +int wlan_hdd_cfg80211_ll_stats_set(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len); + +/** + * wlan_hdd_cfg80211_ll_stats_get() - get link layer stats + * @wiphy: Pointer to wiphy + * @wdev: Pointer to wdev + * @data: Pointer to data + * @data_len: Data length + * + * Return: int + */ +int wlan_hdd_cfg80211_ll_stats_get(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len); + + +/** + * wlan_hdd_cfg80211_ll_stats_clear() - clear link layer stats + * @wiphy: Pointer to wiphy + * @wdev: Pointer to wdev + * @data: Pointer to data + * @data_len: Data length + * + * Return: int + */ +int wlan_hdd_cfg80211_ll_stats_clear(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len); + +void hdd_init_ll_stats_ctx(void); + +static inline bool hdd_link_layer_stats_supported(void) +{ + return true; +} + +#else + +static inline void hdd_init_ll_stats_ctx(void) +{ + return; +} + +static inline bool hdd_link_layer_stats_supported(void) +{ + return false; +} + +#endif /* End of WLAN_FEATURE_LINK_LAYER_STATS */ + +#ifdef WLAN_FEATURE_STATS_EXT +/** + * wlan_hdd_cfg80211_stats_ext_request() - ext stats request + * @wiphy: Pointer to wiphy + * @wdev: Pointer to wdev + * @data: Pointer to data + * @data_len: Data length + * + * Return: int + */ +int wlan_hdd_cfg80211_stats_ext_request(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len); + +#else +static inline void wlan_hdd_cfg80211_stats_ext_init(hdd_context_t *pHddCtx) {} +#endif /* End of WLAN_FEATURE_STATS_EXT */ + +/** + * wlan_hdd_cfg80211_get_station() - get station statistics + * @wiphy: Pointer to wiphy + * @dev: Pointer to network device + * @mac: Pointer to mac + * @sinfo: Pointer to station info + * + * Return: 0 for success, non-zero for failure + */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)) +int wlan_hdd_cfg80211_get_station(struct wiphy *wiphy, + struct net_device *dev, const uint8_t *mac, + struct station_info *sinfo); +#else +int wlan_hdd_cfg80211_get_station(struct wiphy *wiphy, + struct net_device *dev, uint8_t *mac, + struct station_info *sinfo); +#endif + +/** + * wlan_hdd_cfg80211_dump_station() - dump station statistics + * @wiphy: Pointer to wiphy + * @dev: Pointer to network device + * @idx: variable to determine whether to get stats or not + * @mac: Pointer to mac + * @sinfo: Pointer to station info + * + * Return: 0 for success, non-zero for failure + */ +int wlan_hdd_cfg80211_dump_station(struct wiphy *wiphy, + struct net_device *dev, + int idx, u8 *mac, + struct station_info *sinfo); + +struct net_device_stats *hdd_get_stats(struct net_device *dev); + +int wlan_hdd_cfg80211_dump_survey(struct wiphy *wiphy, + struct net_device *dev, + int idx, struct survey_info *survey); + +void hdd_display_hif_stats(void); +void hdd_clear_hif_stats(void); + +void wlan_hdd_cfg80211_stats_ext_callback(void *ctx, + tStatsExtEvent *msg); + +void wlan_hdd_cfg80211_link_layer_stats_callback(void *ctx, + int indType, void *pRsp); + +/** + * wlan_hdd_get_rcpi() - Wrapper to get current RCPI + * @adapter: adapter upon which the measurement is requested + * @mac: peer addr for which measurement is requested + * @rcpi_value: pointer to where the RCPI should be returned + * @measurement_type: type of rcpi measurement + * + * This is a wrapper function for getting RCPI, invoke this function only + * when rcpi support is enabled in firmware + * + * Return: 0 for success, non-zero for failure + */ +int wlan_hdd_get_rcpi(hdd_adapter_t *adapter, uint8_t *mac, + int32_t *rcpi_value, + enum rcpi_measurement_type measurement_type); + +#endif /* end #if !defined(WLAN_HDD_STATS_H) */ diff --git a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_subnet_detect.c b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_subnet_detect.c new file mode 100644 index 0000000000000000000000000000000000000000..cf9f39bbfb21e0d57387c8a647c232a1ff17fe4b --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_subnet_detect.c @@ -0,0 +1,195 @@ +/* + * Copyright (c) 2015-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/** + * DOC: wlan_hdd_subnet_detect.c + * + * WLAN Host Device Driver subnet detect API implementation + */ + +#include +#include +#include +#include +#include +#include "sme_api.h" +#include "wlan_hdd_main.h" +#include "wlan_hdd_subnet_detect.h" + +/* + * define short names for the global vendor params + * used by __wlan_hdd_cfg80211_set_gateway_params() + */ +#define PARAM_MAC_ADDR QCA_WLAN_VENDOR_ATTR_GW_PARAM_CONFIG_GW_MAC_ADDR +#define PARAM_IPV4_ADDR QCA_WLAN_VENDOR_ATTR_GW_PARAM_CONFIG_IPV4_ADDR +#define PARAM_IPV6_ADDR QCA_WLAN_VENDOR_ATTR_GW_PARAM_CONFIG_IPV6_ADDR + +static const struct nla_policy + policy[QCA_WLAN_VENDOR_ATTR_GW_PARAM_CONFIG_MAX + 1] = { + [PARAM_MAC_ADDR] = { + .type = NLA_BINARY, + .len = QDF_MAC_ADDR_SIZE + }, + [PARAM_IPV4_ADDR] = { + .type = NLA_BINARY, + .len = QDF_IPV4_ADDR_SIZE + }, + [PARAM_IPV6_ADDR] = { + .type = NLA_BINARY, + .len = QDF_IPV6_ADDR_SIZE + } +}; + +/** + * __wlan_hdd_cfg80211_set_gateway_params() - set gateway params + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Data length + * + * Return: 0 on success, negative errno on failure + */ +static int __wlan_hdd_cfg80211_set_gateway_params(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + struct net_device *dev = wdev->netdev; + hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *hdd_ctx = wiphy_priv(wiphy); + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_GW_PARAM_CONFIG_MAX + 1]; + struct gateway_param_update_req req = { 0 }; + int ret; + QDF_STATUS status; + + ENTER_DEV(dev); + + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + /* user may have disabled the feature in INI */ + if (!hdd_ctx->config->enable_lfr_subnet_detection) { + hdd_info("LFR Subnet Detection disabled in INI"); + return -ENOTSUPP; + } + + /* The gateway parameters are only valid in the STA persona + * and only in the connected state. + */ + if (QDF_STA_MODE != adapter->device_mode) { + hdd_err("Received GW param update for non-STA mode adapter"); + return -ENOTSUPP; + } + + if (!hdd_conn_is_connected(WLAN_HDD_GET_STATION_CTX_PTR(adapter))) { + hdd_err("Received GW param update in disconnected state!"); + return -ENOTSUPP; + } + + /* Extract NL parameters + * mac_addr: 6 bytes + * ipv4 addr: 4 bytes + * ipv6 addr: 16 bytes + */ + if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_GW_PARAM_CONFIG_MAX, + data, data_len, policy)) { + hdd_err("Invalid ATTR list"); + return -EINVAL; + } + + if (!tb[PARAM_MAC_ADDR]) { + hdd_err("request mac addr failed"); + return -EINVAL; + } + nla_memcpy(req.gw_mac_addr.bytes, tb[PARAM_MAC_ADDR], + QDF_MAC_ADDR_SIZE); + + /* req ipv4_addr_type and ipv6_addr_type are initially false due + * to zeroing the struct + */ + if (tb[PARAM_IPV4_ADDR]) { + nla_memcpy(req.ipv4_addr, tb[PARAM_IPV4_ADDR], + QDF_IPV4_ADDR_SIZE); + req.ipv4_addr_type = true; + } + + if (tb[PARAM_IPV6_ADDR]) { + nla_memcpy(&req.ipv6_addr, tb[PARAM_IPV6_ADDR], + QDF_IPV6_ADDR_SIZE); + req.ipv6_addr_type = true; + } + + if (!req.ipv4_addr_type && !req.ipv6_addr_type) { + hdd_err("invalid ipv4 or ipv6 gateway address"); + return -EINVAL; + } + + req.max_retries = 3; + req.timeout = 100; /* in milliseconds */ + req.session_id = adapter->sessionId; + + hdd_info("**** Gateway Parameters: ****"); + hdd_info("session id: %d", req.session_id); + hdd_info("ipv4 addr type: %d", req.ipv4_addr_type); + hdd_info("ipv6 addr type: %d", req.ipv6_addr_type); + hdd_info("gw mac addr: %pM", req.gw_mac_addr.bytes); + hdd_info("ipv4 addr: %pI4", req.ipv4_addr); + hdd_info("ipv6 addr: %pI6c", req.ipv6_addr); + + status = sme_gateway_param_update(hdd_ctx->hHal, &req); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("sme_gateway_param_update failed(err=%d)", status); + ret = -EINVAL; + } + + EXIT(); + return ret; +} + +/** + * wlan_hdd_cfg80211_set_gateway_params() - set gateway parameters + * @wiphy: wiphy structure pointer + * @wdev: Wireless device structure pointer + * @data: Pointer to the data received + * @data_len: Length of @data + * + * The API is invoked by the user space to set the gateway parameters + * such as mac address and the IP address which is used for detecting + * the IP subnet change + * + * Return: 0 on success; errno on failure + */ +int wlan_hdd_cfg80211_set_gateway_params(struct wiphy *wiphy, + struct wireless_dev *wdev, const void *data, int data_len) +{ + int ret; + + cds_ssr_protect(__func__); + + ret = __wlan_hdd_cfg80211_set_gateway_params( + wiphy, wdev, data, data_len); + cds_ssr_unprotect(__func__); + return ret; +} +#undef PARAM_MAC_ADDR +#undef PARAM_IPV4_ADDR +#undef PARAM_IPV6_ADDR diff --git a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_subnet_detect.h b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_subnet_detect.h new file mode 100644 index 0000000000000000000000000000000000000000..ffab910884cbc919e2f2214e91cfef4177520dff --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_subnet_detect.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef __WLAN_HDD_SUBNET_DETECT_H +#define __WLAN_HDD_SUBNET_DETECT_H + +/** + * DOC: wlan_hdd_subnet_detect.h + * + * WLAN Host Device Driver subnet detect API specification + */ + +#ifdef FEATURE_LFR_SUBNET_DETECTION +struct wiphy; +struct wireless_dev; + +int wlan_hdd_cfg80211_set_gateway_params(struct wiphy *wiphy, + struct wireless_dev *wdev, const void *data, int data_len); +#endif /* FEATURE_LFR_SUBNET_DETECTION */ +#endif /* __WLAN_HDD_SUBNET_DETECT_H */ diff --git a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_tdls.c b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_tdls.c new file mode 100644 index 0000000000000000000000000000000000000000..783aea2de66ce3c053fc8d45d1e55aa9095d7b6a --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_tdls.c @@ -0,0 +1,6412 @@ +/* + * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: wlan_hdd_tdls.c + * + * WLAN Host Device Driver implementation for TDLS + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "wlan_hdd_tdls.h" +#include "wlan_hdd_cfg80211.h" +#include "wlan_hdd_assoc.h" +#include "sme_api.h" +#include "cds_sched.h" +#include "wma_types.h" +#include "cds_concurrency.h" + + +static int32_t wlan_hdd_tdls_peer_reset_discovery_processed(tdlsCtx_t * + pHddTdlsCtx); +static void wlan_hdd_tdls_timers_destroy(tdlsCtx_t *pHddTdlsCtx); +int wpa_tdls_is_allowed_force_peer(tdlsCtx_t *pHddTdlsCtx, u8 *mac); +static void wlan_hdd_tdls_ct_handler(void *user_data); + +/** + * enum qca_wlan_vendor_tdls_trigger_mode_hdd_map: Maps the user space TDLS + * trigger mode in the host driver. + * @WLAN_HDD_VENDOR_TDLS_TRIGGER_MODE_EXPLICIT: TDLS Connection and + * disconnection handled by user space. + * @WLAN_HDD_VENDOR_TDLS_TRIGGER_MODE_IMPLICIT: TDLS connection and + * disconnection controlled by host driver based on data traffic. + * @WLAN_HDD_VENDOR_TDLS_TRIGGER_MODE_EXTERNAL: TDLS connection and + * disconnection jointly controlled by user space and host driver. + */ +enum qca_wlan_vendor_tdls_trigger_mode_hdd_map { + WLAN_HDD_VENDOR_TDLS_TRIGGER_MODE_EXPLICIT = + QCA_WLAN_VENDOR_TDLS_TRIGGER_MODE_EXPLICIT, + WLAN_HDD_VENDOR_TDLS_TRIGGER_MODE_IMPLICIT = + QCA_WLAN_VENDOR_TDLS_TRIGGER_MODE_IMPLICIT, + WLAN_HDD_VENDOR_TDLS_TRIGGER_MODE_EXTERNAL = + ((QCA_WLAN_VENDOR_TDLS_TRIGGER_MODE_EXPLICIT | + QCA_WLAN_VENDOR_TDLS_TRIGGER_MODE_IMPLICIT) << 1), +}; + +/* + * wlan_hdd_tdls_determine_channel_opclass() - determine channel and opclass + * @hddctx: pointer to hdd context + * @adapter: pointer to adapter + * @curr_peer: pointer to current tdls peer + * @channel: pointer to channel + * @opclass: pointer to opclass + * + * Function determines the channel and operating class + * + * Return: None + */ +static void wlan_hdd_tdls_determine_channel_opclass(hdd_context_t *hddctx, + hdd_adapter_t *adapter, hddTdlsPeer_t *curr_peer, + uint32_t *channel, uint32_t *opclass) +{ + hdd_station_ctx_t *hdd_sta_ctx; + + /* + * If tdls offchannel is not enabled then we provide base channel + * and in that case pass opclass as 0 since opclass is mainly needed + * for offchannel cases. + */ + if (!(hddctx->config->fEnableTDLSOffChannel) || + (hddctx->tdls_fw_off_chan_mode != ENABLE_CHANSWITCH)) { + hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + *channel = hdd_sta_ctx->conn_info.operationChannel; + *opclass = 0; + } else { + *channel = curr_peer->pref_off_chan_num; + *opclass = curr_peer->op_class_for_pref_off_chan; + } + hdd_info("channel:%d opclass:%d", *channel, *opclass); +} + +#ifdef FEATURE_WLAN_DIAG_SUPPORT +/** + * hdd_send_wlan_tdls_teardown_event()- send TDLS teardown event + * @reason: reason for tear down. + * @peer_mac: peer mac + * + * This Function sends TDLS teardown diag event + * + * Return: void. + */ +void hdd_send_wlan_tdls_teardown_event(uint32_t reason, + uint8_t *peer_mac) +{ + WLAN_HOST_DIAG_EVENT_DEF(tdls_tear_down, + struct host_event_tdls_teardown); + qdf_mem_zero(&tdls_tear_down, + sizeof(tdls_tear_down)); + + tdls_tear_down.reason = reason; + qdf_mem_copy(tdls_tear_down.peer_mac, peer_mac, MAC_ADDR_LEN); + WLAN_HOST_DIAG_EVENT_REPORT(&tdls_tear_down, + EVENT_WLAN_TDLS_TEARDOWN); +} + +/** + * hdd_wlan_tdls_enable_link_event()- send TDLS enable link event + * @peer_mac: peer mac + * @is_off_chan_supported: Does peer supports off chan + * @is_off_chan_configured: If off channel is configured + * @is_off_chan_established: If off chan is established + * + * This Function send TDLS enable link diag event + * + * Return: void. + */ + +void hdd_wlan_tdls_enable_link_event(const uint8_t *peer_mac, + uint8_t is_off_chan_supported, + uint8_t is_off_chan_configured, + uint8_t is_off_chan_established) +{ + WLAN_HOST_DIAG_EVENT_DEF(tdls_event, + struct host_event_tdls_enable_link); + + qdf_mem_copy(tdls_event.peer_mac, + peer_mac, MAC_ADDR_LEN); + + tdls_event.is_off_chan_supported = + is_off_chan_supported; + tdls_event.is_off_chan_configured = + is_off_chan_configured; + tdls_event.is_off_chan_established = + is_off_chan_established; + + WLAN_HOST_DIAG_EVENT_REPORT(&tdls_event, + EVENT_WLAN_TDLS_ENABLE_LINK); +} + +/** + * hdd_wlan_block_scan_by_tdls_event()- send event + * if scan is blocked by tdls + * + * This Function send send diag event if scan is + * blocked by tdls + * + * Return: void. + */ +void hdd_wlan_block_scan_by_tdls_event(void) +{ + WLAN_HOST_DIAG_EVENT_DEF(tdls_scan_block_status, + struct host_event_tdls_scan_rejected); + + tdls_scan_block_status.status = true; + WLAN_HOST_DIAG_EVENT_REPORT(&tdls_scan_block_status, + EVENT_TDLS_SCAN_BLOCK); +} + +#endif + +/** + * wlan_hdd_tdls_hash_key() - calculate tdls hash key given mac address + * @mac: mac address + * + * Return: hash key + */ +static u8 wlan_hdd_tdls_hash_key(const u8 *mac) +{ + int i; + u8 key = 0; + + for (i = 0; i < 6; i++) + key ^= mac[i]; + + return key; +} + +/** + * wlan_hdd_tdls_disable_offchan_and_teardown_links - Disable offchannel + * and teardown TDLS links + * @hddCtx : pointer to hdd context + * + * Return: None + */ +void wlan_hdd_tdls_disable_offchan_and_teardown_links(hdd_context_t *hddctx) +{ + u16 connected_tdls_peers = 0; + u8 staidx; + hddTdlsPeer_t *curr_peer = NULL; + hdd_adapter_t *adapter = NULL; + + if (eTDLS_SUPPORT_NOT_ENABLED == hddctx->tdls_mode) { + hdd_notice("TDLS mode is disabled OR not enabled in FW"); + return ; + } + + adapter = hdd_get_adapter(hddctx, QDF_STA_MODE); + + if (adapter == NULL) { + hdd_err("Station Adapter Not Found"); + return; + } + + connected_tdls_peers = wlan_hdd_tdls_connected_peers(adapter); + + if (!connected_tdls_peers) { + hdd_notice("No TDLS connected peers to delete"); + return; + } + + /* TDLS is not supported in case of concurrency. + * Disable TDLS Offchannel in FW to avoid more + * than two concurrent channels and generate TDLS + * teardown indication to supplicant. + * Below function Finds the first connected peer and + * disables TDLS offchannel for that peer. + * FW enables TDLS offchannel only when there is + * one TDLS peer. When there are more than one TDLS peer, + * there will not be TDLS offchannel in FW. + * So to avoid sending multiple request to FW, for now, + * just invoke offchannel mode functions only once + */ + hdd_set_tdls_offchannel(hddctx, hddctx->config->fTDLSPrefOffChanNum); + hdd_set_tdls_secoffchanneloffset(hddctx, + TDLS_SEC_OFFCHAN_OFFSET_40PLUS); + hdd_set_tdls_offchannelmode(adapter, DISABLE_CHANSWITCH); + + /* Send Msg to PE for deleting all the TDLS peers */ + sme_delete_all_tdls_peers(hddctx->hHal, adapter->sessionId); + + for (staidx = 0; staidx < hddctx->max_num_tdls_sta; + staidx++) { + if (!hddctx->tdlsConnInfo[staidx].staId) + continue; + + mutex_lock(&hddctx->tdls_lock); + curr_peer = wlan_hdd_tdls_find_all_peer(hddctx, + hddctx->tdlsConnInfo[staidx].peerMac.bytes); + if (!curr_peer) + continue; + + hdd_notice("indicate TDLS teardown (staId %d)", + curr_peer->staId); + + /* Indicate teardown to supplicant */ + wlan_hdd_tdls_indicate_teardown( + curr_peer->pHddTdlsCtx->pAdapter, + curr_peer, + eSIR_MAC_TDLS_TEARDOWN_UNSPEC_REASON); + + /* + * Del Sta happened already as part of sme_delete_all_tdls_peers + * Hence clear hdd data structure. + */ + wlan_hdd_tdls_reset_peer(adapter, curr_peer->peerMac); + hdd_send_wlan_tdls_teardown_event(eTDLS_TEARDOWN_CONCURRENCY, + curr_peer->peerMac); + mutex_unlock(&hddctx->tdls_lock); + + hdd_roam_deregister_tdlssta(adapter, + hddctx->tdlsConnInfo[staidx].staId); + wlan_hdd_tdls_decrement_peer_count(adapter); + hddctx->tdlsConnInfo[staidx].staId = 0; + hddctx->tdlsConnInfo[staidx].sessionId = 255; + + qdf_mem_zero(&hddctx->tdlsConnInfo[staidx].peerMac, + sizeof(struct qdf_mac_addr)); + } +} + +/** + * hdd_update_tdls_ct_and_teardown_links - Update TDLS connection tracker and + * teardown links. + * @hdd_ctx : pointer to hdd context + * + * Return: None + */ +void hdd_update_tdls_ct_and_teardown_links(hdd_context_t *hdd_ctx) +{ + /* set tdls connection tracker state */ + cds_set_tdls_ct_mode(hdd_ctx); + wlan_hdd_tdls_disable_offchan_and_teardown_links(hdd_ctx); +} + +/** + * wlan_hdd_tdls_discovery_sent_cnt() - get value of discovery counter sent + * @pHddCtx: HDD context + * + * Return: the value of the transmitted TDLS discovery counter + */ +static uint32_t wlan_hdd_tdls_discovery_sent_cnt(hdd_context_t *pHddCtx) +{ + hdd_adapter_list_node_t *pAdapterNode = NULL, *pNext = NULL; + hdd_adapter_t *pAdapter = NULL; + tdlsCtx_t *pHddTdlsCtx = NULL; + QDF_STATUS status = 0; + uint32_t count = 0; + + status = hdd_get_front_adapter(pHddCtx, &pAdapterNode); + while (NULL != pAdapterNode && QDF_STATUS_SUCCESS == status) { + pAdapter = pAdapterNode->pAdapter; + + pHddTdlsCtx = WLAN_HDD_GET_TDLS_CTX_PTR(pAdapter); + if (NULL != pHddTdlsCtx) { + count = count + pHddTdlsCtx->discovery_sent_cnt; + } + status = hdd_get_next_adapter(pHddCtx, pAdapterNode, &pNext); + pAdapterNode = pNext; + } + return count; +} + +/** + * wlan_hdd_tdls_check_power_save_prohibited() - set/clear proper TDLS power + * save probihited bit + * @pAdapter: HDD adapter handle + * + * Ensure TDLS power save probihited bit is set/cleared properly + * + * Return: None + */ +static void wlan_hdd_tdls_check_power_save_prohibited(hdd_adapter_t *pAdapter) +{ + tdlsCtx_t *pHddTdlsCtx; + hdd_context_t *pHddCtx; + + if ((NULL == pAdapter) || + (WLAN_HDD_ADAPTER_MAGIC != pAdapter->magic)) { + hdd_err("invalid pAdapter: %p", pAdapter); + return; + } + + pHddTdlsCtx = WLAN_HDD_GET_TDLS_CTX_PTR(pAdapter); + pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + + if ((NULL == pHddTdlsCtx) || (NULL == pHddCtx)) { + QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR, + FL("pHddCtx or pHddTdlsCtx points to NULL")); + return; + } + + if ((0 == pHddCtx->connected_peer_count) && + (0 == wlan_hdd_tdls_discovery_sent_cnt(pHddCtx))) { + sme_set_tdls_power_save_prohibited(WLAN_HDD_GET_HAL_CTX + (pHddTdlsCtx->pAdapter), + pAdapter->sessionId, 0); + return; + } + sme_set_tdls_power_save_prohibited(WLAN_HDD_GET_HAL_CTX + (pHddTdlsCtx->pAdapter), + pAdapter->sessionId, 1); + return; +} + +/** + * wlan_hdd_tdls_free_scan_request() - free tdls scan request + * @tdls_scan_ctx: tdls scan context + * + * Return: None + */ +static void wlan_hdd_tdls_free_scan_request(tdls_scan_context_t *tdls_scan_ctx) +{ + if (NULL == tdls_scan_ctx) { + QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR, + FL("tdls_scan_ctx is NULL")); + return; + } + + tdls_scan_ctx->attempt = 0; + tdls_scan_ctx->reject = 0; + tdls_scan_ctx->magic = 0; + tdls_scan_ctx->scan_request = NULL; + return; +} + +/** + * wlan_hdd_tdls_discovery_timeout_peer_cb() - tdls discovery timeout callback + * @userData: tdls context + * + * Return: None + */ +static void wlan_hdd_tdls_discovery_timeout_peer_cb(void *userData) +{ + int i; + struct list_head *head; + hddTdlsPeer_t *tmp; + struct list_head *pos, *q; + tdlsCtx_t *pHddTdlsCtx; + hdd_context_t *pHddCtx; + v_CONTEXT_t cds_context; + + ENTER(); + + cds_context = cds_get_global_context(); + if (NULL == cds_context) { + hdd_err("cds_context points to NULL"); + return; + } + + pHddCtx = cds_get_context(QDF_MODULE_ID_HDD); + if (0 != (wlan_hdd_validate_context(pHddCtx))) + return; + + mutex_lock(&pHddCtx->tdls_lock); + pHddTdlsCtx = (tdlsCtx_t *) userData; + + if ((NULL == pHddTdlsCtx) || (NULL == pHddTdlsCtx->pAdapter)) { + mutex_unlock(&pHddCtx->tdls_lock); + QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR, + FL("pHddTdlsCtx or pAdapter points to NULL")); + return; + } + + if (WLAN_HDD_ADAPTER_MAGIC != pHddTdlsCtx->pAdapter->magic) { + mutex_unlock(&pHddCtx->tdls_lock); + hdd_err("pAdapter has invalid magic"); + return; + } + + for (i = 0; i < TDLS_PEER_LIST_SIZE; i++) { + head = &pHddTdlsCtx->peer_list[i]; + list_for_each_safe(pos, q, head) { + tmp = list_entry(pos, hddTdlsPeer_t, node); + if (eTDLS_LINK_DISCOVERING == tmp->link_status) { + hdd_notice(MAC_ADDRESS_STR " to idle state", + MAC_ADDR_ARRAY(tmp->peerMac)); + wlan_hdd_tdls_set_peer_link_status(tmp, + eTDLS_LINK_IDLE, + eTDLS_LINK_NOT_SUPPORTED); + } + } + } + + pHddTdlsCtx->discovery_sent_cnt = 0; + wlan_hdd_tdls_check_power_save_prohibited(pHddTdlsCtx->pAdapter); + + mutex_unlock(&pHddCtx->tdls_lock); + EXIT(); + return; +} + +/** + * wlan_hdd_tdls_free_list() - free TDLS peer list + * @pHddTdlsCtx: TDLS context + * + * Return: None + */ +static void wlan_hdd_tdls_free_list(tdlsCtx_t *pHddTdlsCtx) +{ + int i; + struct list_head *head; + hddTdlsPeer_t *tmp; + struct list_head *pos, *q; + + if (NULL == pHddTdlsCtx) { + hdd_notice("pHddTdlsCtx is NULL"); + return; + } + for (i = 0; i < TDLS_PEER_LIST_SIZE; i++) { + head = &pHddTdlsCtx->peer_list[i]; + list_for_each_safe(pos, q, head) { + tmp = list_entry(pos, hddTdlsPeer_t, node); + list_del(pos); + qdf_mem_free(tmp); + tmp = NULL; + } + } +} + +/** + * wlan_hdd_tdls_schedule_scan() - schedule scan for tdls + * @work: work_struct used to find tdls scan context + * + * Return: None + */ +static void wlan_hdd_tdls_schedule_scan(struct work_struct *work) +{ + tdls_scan_context_t *scan_ctx = + container_of(work, tdls_scan_context_t, tdls_scan_work.work); + + if (NULL == scan_ctx) { + QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR, + FL("scan_ctx is NULL")); + return; + } + + if (unlikely(TDLS_CTX_MAGIC != scan_ctx->magic)) + return; + + scan_ctx->attempt++; + + wlan_hdd_cfg80211_tdls_scan(scan_ctx->wiphy, + scan_ctx->scan_request, scan_ctx->source); +} + +/** + * dump_tdls_state_param_setting() - print tdls state & parameters to send to fw + * @info: tdls setting to be sent to fw + * + * Return: void + */ +static void dump_tdls_state_param_setting(tdlsInfo_t *info) +{ + if (!info) + return; + + hdd_notice("Setting tdls state and param in fw: vdev_id: %d, tdls_state: %d, notification_interval_ms: %d, tx_discovery_threshold: %d, tx_teardown_threshold: %d, rssi_teardown_threshold: %d, rssi_delta: %d, tdls_options: 0x%x, peer_traffic_ind_window: %d, peer_traffic_response_timeout: %d, puapsd_mask: 0x%x, puapsd_inactivity_time: %d, puapsd_rx_frame_threshold: %d, teardown_notification_ms: %d, tdls_peer_kickout_threshold: %d", + info->vdev_id, + info->tdls_state, + info->notification_interval_ms, + info->tx_discovery_threshold, + info->tx_teardown_threshold, + info->rssi_teardown_threshold, + info->rssi_delta, + info->tdls_options, + info->peer_traffic_ind_window, + info->peer_traffic_response_timeout, + info->puapsd_mask, + info->puapsd_inactivity_time, + info->puapsd_rx_frame_threshold, + info->teardown_notification_ms, + info->tdls_peer_kickout_threshold); + +} + + +/** + * wlan_hdd_tdls_monitor_timers_stop() - stop all monitoring timers + * @hdd_tdls_ctx: TDLS context + * + * Return: none + */ +static void wlan_hdd_tdls_monitor_timers_stop(tdlsCtx_t *hdd_tdls_ctx) +{ + qdf_mc_timer_stop(&hdd_tdls_ctx->peerDiscoveryTimeoutTimer); +} + +/** + * wlan_hdd_tdls_peer_idle_timers_stop() - stop peer idle timers + * @hdd_tdls_ctx: TDLS context + * + * Loop through the idle peer list and stop their timers + * + * Return: None + */ +static void wlan_hdd_tdls_peer_idle_timers_stop(tdlsCtx_t *hdd_tdls_ctx) +{ + int i; + struct list_head *head; + struct list_head *pos; + hddTdlsPeer_t *curr_peer; + + for (i = 0; i < TDLS_PEER_LIST_SIZE; i++) { + head = &hdd_tdls_ctx->peer_list[i]; + list_for_each(pos, head) { + curr_peer = list_entry(pos, hddTdlsPeer_t, node); + if (curr_peer->is_peer_idle_timer_initialised) + qdf_mc_timer_stop(&curr_peer->peer_idle_timer); + } + } +} + +/** + * wlan_hdd_tdls_ct_timers_stop() - stop tdls connection tracker timers + * @hdd_tdls_ctx: TDLS context + * + * Return: None + */ +static void wlan_hdd_tdls_ct_timers_stop(tdlsCtx_t *hdd_tdls_ctx) +{ + qdf_mc_timer_stop(&hdd_tdls_ctx->peer_update_timer); + wlan_hdd_tdls_peer_idle_timers_stop(hdd_tdls_ctx); +} + +/** + * wlan_hdd_tdls_timers_stop() - stop all the tdls timers running + * @hdd_tdls_ctx: TDLS context + * + * Return: none + */ +void wlan_hdd_tdls_timers_stop(tdlsCtx_t *hdd_tdls_ctx) +{ + wlan_hdd_tdls_monitor_timers_stop(hdd_tdls_ctx); + wlan_hdd_tdls_ct_timers_stop(hdd_tdls_ctx); +} + +/** + * wlan_hdd_tdls_del_non_forced_peers() - delete non forced tdls peers + * @hdd_tdls_ctx: TDLS context + * + * Return: none + */ +static void wlan_hdd_tdls_del_non_forced_peers(tdlsCtx_t *hdd_tdls_ctx) +{ + struct list_head *head, *pos, *q; + hddTdlsPeer_t *peer = NULL; + int i; + + /* remove entries from peer list only if peer is not forced */ + for (i = 0; i < TDLS_PEER_LIST_SIZE; i++) { + head = &hdd_tdls_ctx->peer_list[i]; + list_for_each_safe(pos, q, head) { + peer = list_entry(pos, hddTdlsPeer_t, node); + if (false == peer->isForcedPeer) { + list_del(pos); + qdf_mem_free(peer); + } else { + peer->link_status = eTDLS_LINK_IDLE; + peer->reason = eTDLS_LINK_UNSPECIFIED; + peer->staId = 0; + peer->discovery_attempt = 0; + } + } + } +} + +/** + * hdd_tdls_context_init() - Init TDLS context + * @hdd_ctx: HDD context + * @ssr: SSR case + * + * Initialize TDLS global context. + * + * Return: None + */ +void hdd_tdls_context_init(hdd_context_t *hdd_ctx, bool ssr) +{ + uint8_t sta_idx; + + if (!ssr) { + mutex_init(&hdd_ctx->tdls_lock); + qdf_spinlock_create(&hdd_ctx->tdls_ct_spinlock); + } + + /* initialize TDLS global context */ + hdd_ctx->connected_peer_count = 0; + hdd_ctx->tdls_nss_switch_in_progress = false; + hdd_ctx->tdls_teardown_peers_cnt = 0; + hdd_ctx->tdls_scan_ctxt.magic = 0; + hdd_ctx->tdls_scan_ctxt.attempt = 0; + hdd_ctx->tdls_scan_ctxt.reject = 0; + hdd_ctx->tdls_scan_ctxt.source = 0; + hdd_ctx->tdls_scan_ctxt.scan_request = NULL; + hdd_ctx->set_state_info.set_state_cnt = 0; + hdd_ctx->set_state_info.vdev_id = 0; + hdd_ctx->tdls_nss_teardown_complete = false; + hdd_ctx->tdls_nss_transition_mode = TDLS_NSS_TRANSITION_UNKNOWN; + + if (false == hdd_ctx->config->fEnableTDLSImplicitTrigger) { + hdd_ctx->tdls_mode = eTDLS_SUPPORT_EXPLICIT_TRIGGER_ONLY; + hdd_notice("TDLS Implicit trigger not enabled!"); + } else if (true == hdd_ctx->config->fTDLSExternalControl) { + hdd_ctx->tdls_mode = eTDLS_SUPPORT_EXTERNAL_CONTROL; + } else { + hdd_ctx->tdls_mode = eTDLS_SUPPORT_ENABLED; + } + + hdd_ctx->tdls_mode_last = hdd_ctx->tdls_mode; + + if (hdd_ctx->config->fEnableTDLSSleepSta || + hdd_ctx->config->fEnableTDLSBufferSta || + hdd_ctx->config->fEnableTDLSOffChannel) + hdd_ctx->max_num_tdls_sta = HDD_MAX_NUM_TDLS_STA_P_UAPSD_OFFCHAN; + else + hdd_ctx->max_num_tdls_sta = HDD_MAX_NUM_TDLS_STA; + + hdd_notice("max_num_tdls_sta: %d", hdd_ctx->max_num_tdls_sta); + + for (sta_idx = 0; sta_idx < hdd_ctx->max_num_tdls_sta; sta_idx++) { + hdd_ctx->tdlsConnInfo[sta_idx].staId = 0; + hdd_ctx->tdlsConnInfo[sta_idx].sessionId = 255; + qdf_mem_zero(&hdd_ctx->tdlsConnInfo[sta_idx].peerMac, + QDF_MAC_ADDR_SIZE); + } + + /* Don't reset TDLS external peer count for SSR case */ + if (!ssr) + hdd_ctx->tdls_external_peer_count = 0; + + /* This flag will set be true, only when device operates in + * standalone STA mode + */ + hdd_ctx->enable_tdls_connection_tracker = false; + hdd_info("hdd_ctx->enable_tdls_connection_tracker: 0"); +} + +/** + * hdd_tdls_context_destroy() - Destroy TDLS context + * @hdd_ctx: HDD context + * + * Destroy TDLS global context. + * + * Return: None + */ +void hdd_tdls_context_destroy(hdd_context_t *hdd_ctx) +{ + hdd_ctx->tdls_external_peer_count = 0; + hdd_ctx->enable_tdls_connection_tracker = false; + hdd_info("hdd_ctx->enable_tdls_connection_tracker: 0"); + mutex_destroy(&hdd_ctx->tdls_lock); + qdf_spinlock_destroy(&hdd_ctx->tdls_ct_spinlock); +} + +/** + * wlan_hdd_tdls_init() - tdls initializaiton + * @pAdapter: hdd adapter + * + * Return: 0 for success or negative errno otherwise + */ +int wlan_hdd_tdls_init(hdd_adapter_t *pAdapter) +{ + hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + tdlsCtx_t *pHddTdlsCtx; + int i; + + if (NULL == pHddCtx) + return -EINVAL; + + ENTER(); + + mutex_lock(&pHddCtx->tdls_lock); + + if (false == pHddCtx->config->fEnableTDLSSupport) { + pHddCtx->tdls_mode = eTDLS_SUPPORT_NOT_ENABLED; + pAdapter->sessionCtx.station.pHddTdlsCtx = NULL; + mutex_unlock(&pHddCtx->tdls_lock); + hdd_warn("TDLS not enabled (%d) or FW doesn't support", + pHddCtx->config->fEnableTDLSSupport); + return 0; + } + /* TDLS is supported only in STA / P2P Client modes, + * hence the check for TDLS support in a specific Device mode. + * Do not return a failure rather do not continue further + * with the initialization as tdls_init would be called + * during the open adapter for a p2p interface at which point + * the device mode would be a P2P_DEVICE. The point here is to + * continue initialization for STA / P2P Client modes. + * TDLS exit also check for the device mode for clean up hence + * there is no issue even if success is returned. + */ + if (0 == WLAN_HDD_IS_TDLS_SUPPORTED_ADAPTER(pAdapter)) { + mutex_unlock(&pHddCtx->tdls_lock); + /* Check whether connection tracker can be enabled in + * the system. + */ + if (pAdapter->device_mode == QDF_P2P_DEVICE_MODE) + cds_set_tdls_ct_mode(pHddCtx); + return 0; + } + /* Check for the valid pHddTdlsCtx. If valid do not further + * allocate the memory, rather continue with the initialization. + * If tdls_initialization would get reinvoked without tdls_exit + * getting invoked (SSR) there is no point to further proceed + * with the memory allocations. + */ + if (NULL == pAdapter->sessionCtx.station.pHddTdlsCtx) { + pHddTdlsCtx = qdf_mem_malloc(sizeof(tdlsCtx_t)); + + if (NULL == pHddTdlsCtx) { + pAdapter->sessionCtx.station.pHddTdlsCtx = NULL; + mutex_unlock(&pHddCtx->tdls_lock); + hdd_err("malloc failed!"); + return -ENOMEM; + } + + /* Initialize connection tracker timer */ + qdf_mc_timer_init(&pHddTdlsCtx->peer_update_timer, + QDF_TIMER_TYPE_SW, + wlan_hdd_tdls_ct_handler, + pAdapter); + qdf_mc_timer_init(&pHddTdlsCtx->peerDiscoveryTimeoutTimer, + QDF_TIMER_TYPE_SW, + wlan_hdd_tdls_discovery_timeout_peer_cb, + pHddTdlsCtx); + + pAdapter->sessionCtx.station.pHddTdlsCtx = pHddTdlsCtx; + for (i = 0; i < TDLS_PEER_LIST_SIZE; i++) + INIT_LIST_HEAD(&pHddTdlsCtx->peer_list[i]); + } else { + pHddTdlsCtx = pAdapter->sessionCtx.station.pHddTdlsCtx; + + wlan_hdd_tdls_timers_stop(pHddTdlsCtx); + + wlan_hdd_tdls_del_non_forced_peers(pHddTdlsCtx); + + hdd_tdls_context_init(pHddCtx, true); + } + + sme_set_tdls_power_save_prohibited(WLAN_HDD_GET_HAL_CTX(pAdapter), + pAdapter->sessionId, 0); + + pHddTdlsCtx->pAdapter = pAdapter; + + pHddTdlsCtx->curr_candidate = NULL; + pHddTdlsCtx->magic = 0; + pHddCtx->valid_mac_entries = 0; + pHddTdlsCtx->last_flush_ts = 0; + + /* remember configuration even if it is not used right now. it could be used later */ + pHddTdlsCtx->threshold_config.tx_period_t = + pHddCtx->config->fTDLSTxStatsPeriod; + pHddTdlsCtx->threshold_config.tx_packet_n = + pHddCtx->config->fTDLSTxPacketThreshold; + pHddTdlsCtx->threshold_config.discovery_tries_n = + pHddCtx->config->fTDLSMaxDiscoveryAttempt; + pHddTdlsCtx->threshold_config.idle_timeout_t = + pHddCtx->config->tdls_idle_timeout; + pHddTdlsCtx->threshold_config.idle_packet_n = + pHddCtx->config->fTDLSIdlePacketThreshold; + pHddTdlsCtx->threshold_config.rssi_trigger_threshold = + pHddCtx->config->fTDLSRSSITriggerThreshold; + pHddTdlsCtx->threshold_config.rssi_teardown_threshold = + pHddCtx->config->fTDLSRSSITeardownThreshold; + pHddTdlsCtx->threshold_config.rssi_delta = + pHddCtx->config->fTDLSRSSIDelta; + + INIT_DELAYED_WORK(&pHddCtx->tdls_scan_ctxt.tdls_scan_work, + wlan_hdd_tdls_schedule_scan); + + mutex_unlock(&pHddCtx->tdls_lock); + + if (pHddCtx->config->fEnableTDLSOffChannel) + pHddCtx->tdls_fw_off_chan_mode = ENABLE_CHANSWITCH; + + EXIT(); + return 0; +} + +/** + * wlan_hdd_tdls_exit() - TDLS de-initialization + * @pAdapter: HDD adapter + * + * Return: None + */ +void wlan_hdd_tdls_exit(hdd_adapter_t *pAdapter) +{ + tdlsCtx_t *pHddTdlsCtx; + hdd_context_t *pHddCtx; + + ENTER(); + pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + if (!pHddCtx) { + QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_WARN, + FL("pHddCtx is NULL")); + return; + } + + if (!test_bit(TDLS_INIT_DONE, &pAdapter->event_flags)) { + hdd_info("TDLS init was not done, exit"); + return; + } + + cds_flush_delayed_work(&pHddCtx->tdls_scan_ctxt.tdls_scan_work); + + mutex_lock(&pHddCtx->tdls_lock); + + pHddTdlsCtx = WLAN_HDD_GET_TDLS_CTX_PTR(pAdapter); + if (NULL == pHddTdlsCtx) { + /* + * TDLS context can be null and might have been freed up during + * cleanup for STA adapter + */ + mutex_unlock(&pHddCtx->tdls_lock); + + hdd_info("pHddTdlsCtx is NULL, adapter device mode: %s(%d)", + hdd_device_mode_to_string(pAdapter->device_mode), + pAdapter->device_mode); + goto done; + } + + /* must stop timer here before freeing peer list, because peerIdleTimer is + part of peer list structure. */ + wlan_hdd_tdls_timers_destroy(pHddTdlsCtx); + wlan_hdd_tdls_free_list(pHddTdlsCtx); + + wlan_hdd_tdls_free_scan_request(&pHddCtx->tdls_scan_ctxt); + + pHddTdlsCtx->magic = 0; + pHddTdlsCtx->pAdapter = NULL; + pAdapter->sessionCtx.station.pHddTdlsCtx = NULL; + + mutex_unlock(&pHddCtx->tdls_lock); + + qdf_mem_free(pHddTdlsCtx); +done: + EXIT(); + clear_bit(TDLS_INIT_DONE, &pAdapter->event_flags); +} + +/** + * wlan_hdd_tdls_peer_idle_timers_destroy() - destroy peer idle timers + * @hdd_tdls_ctx: TDLS context + * + * Loop through the idle peer list and destroy their timers + * + * Return: None + */ +static void wlan_hdd_tdls_peer_idle_timers_destroy(tdlsCtx_t *hdd_tdls_ctx) +{ + int i; + struct list_head *head; + struct list_head *pos; + hddTdlsPeer_t *curr_peer; + + for (i = 0; i < TDLS_PEER_LIST_SIZE; i++) { + head = &hdd_tdls_ctx->peer_list[i]; + list_for_each(pos, head) { + curr_peer = list_entry(pos, hddTdlsPeer_t, node); + if (curr_peer != NULL && + curr_peer->is_peer_idle_timer_initialised) { + hdd_info(MAC_ADDRESS_STR ": destroy idle timer", + MAC_ADDR_ARRAY(curr_peer->peerMac)); + qdf_mc_timer_stop(&curr_peer->peer_idle_timer); + qdf_mc_timer_destroy(&curr_peer->peer_idle_timer); + } + } + } +} + +/** + * wlan_hdd_tdls_ct_timers_destroy() - destroy tdls connection tracker timers + * @hdd_tdls_ctx: TDLS context + * + * Return: None + */ +static void wlan_hdd_tdls_ct_timers_destroy(tdlsCtx_t *hdd_tdls_ctx) +{ + qdf_mc_timer_stop(&hdd_tdls_ctx->peer_update_timer); + qdf_mc_timer_destroy(&hdd_tdls_ctx->peer_update_timer); + wlan_hdd_tdls_peer_idle_timers_destroy(hdd_tdls_ctx); +} + +/** + * wlan_hdd_tdls_monitor_timers_destroy() - destroy all tdls monitoring timers + * @pHddTdlsCtx: TDLS context + * + * Return: Void + */ +static void wlan_hdd_tdls_monitor_timers_destroy(tdlsCtx_t *pHddTdlsCtx) +{ + qdf_mc_timer_stop(&pHddTdlsCtx->peerDiscoveryTimeoutTimer); + qdf_mc_timer_destroy(&pHddTdlsCtx->peerDiscoveryTimeoutTimer); +} + +/** + * wlan_hdd_tdls_timers_destroy() - Destroy all the tdls timers running + * @pHddTdlsCtx: TDLS Context + * + * Return: Void + */ +static void wlan_hdd_tdls_timers_destroy(tdlsCtx_t *pHddTdlsCtx) +{ + wlan_hdd_tdls_monitor_timers_destroy(pHddTdlsCtx); + wlan_hdd_tdls_ct_timers_destroy(pHddTdlsCtx); +} + +/** + * wlan_hdd_tdls_get_peer() - find or add an peer given mac address + * @pAdapter: HDD adapter + * @mac: MAC address used to find or create peer + * + * Search peer given an MAC address and create one if not found. + * + * Return: Pointer to peer if mac address exist or peer creation + * succeeds; NULL if peer creation fails + */ +hddTdlsPeer_t *wlan_hdd_tdls_get_peer(hdd_adapter_t *pAdapter, const u8 *mac) +{ + struct list_head *head; + hddTdlsPeer_t *peer; + u8 key; + tdlsCtx_t *pHddTdlsCtx; + hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + + if (0 != (wlan_hdd_validate_context(pHddCtx))) + return NULL; + + /* if already there, just update */ + peer = wlan_hdd_tdls_find_peer(pAdapter, mac); + if (peer != NULL) + return peer; + + /* not found, allocate and add the list */ + peer = qdf_mem_malloc(sizeof(hddTdlsPeer_t)); + if (NULL == peer) { + hdd_err("peer malloc failed!"); + return NULL; + } + + pHddTdlsCtx = WLAN_HDD_GET_TDLS_CTX_PTR(pAdapter); + + if (NULL == pHddTdlsCtx) { + qdf_mem_free(peer); + hdd_notice("pHddTdlsCtx is NULL"); + return NULL; + } + + key = wlan_hdd_tdls_hash_key(mac); + head = &pHddTdlsCtx->peer_list[key]; + + qdf_mem_copy(peer->peerMac, mac, sizeof(peer->peerMac)); + peer->pHddTdlsCtx = pHddTdlsCtx; + peer->pref_off_chan_num = pHddCtx->config->fTDLSPrefOffChanNum; + peer->op_class_for_pref_off_chan = + wlan_hdd_find_opclass(pHddCtx->hHal, peer->pref_off_chan_num, + pHddCtx->config->fTDLSPrefOffChanBandwidth); + + list_add_tail(&peer->node, head); + + return peer; +} + +/** + * wlan_hdd_tdls_set_cap() - set TDLS capability type + * @pAdapter: HDD adapter + * @mac: peer mac address + * @cap: TDLS capability type + * + * Return: 0 if successful or negative errno otherwise + */ +int wlan_hdd_tdls_set_cap(hdd_adapter_t *pAdapter, const uint8_t *mac, + tTDLSCapType cap) +{ + hddTdlsPeer_t *curr_peer; + hdd_context_t *hdd_ctx; + int status = 0; + + hdd_ctx = WLAN_HDD_GET_CTX(pAdapter); + if (0 != (wlan_hdd_validate_context(hdd_ctx))) { + status = -EINVAL; + goto ret_status; + } + + mutex_lock(&hdd_ctx->tdls_lock); + curr_peer = wlan_hdd_tdls_get_peer(pAdapter, mac); + if (curr_peer == NULL) { + hdd_err("curr_peer is NULL"); + status = -EINVAL; + goto rel_lock; + } + + curr_peer->tdls_support = cap; +rel_lock: + mutex_unlock(&hdd_ctx->tdls_lock); +ret_status: + return status; +} + +/** + * wlan_hdd_tdls_set_peer_link_status() - set TDLS peer link status + * @curr_peer: peer + * @status: status + * @reason: reason + * + * Return: Void + */ +void wlan_hdd_tdls_set_peer_link_status(hddTdlsPeer_t *curr_peer, + tTDLSLinkStatus status, + tTDLSLinkReason reason) +{ + uint32_t state = 0; + int32_t res = 0; + hdd_context_t *pHddCtx; + if (curr_peer == NULL) { + QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR, + FL("curr_peer is NULL")); + return; + } + + if (curr_peer->pHddTdlsCtx == NULL) { + QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR, + FL("curr_peer->pHddTdlsCtx is NULL")); + return; + } + pHddCtx = WLAN_HDD_GET_CTX(curr_peer->pHddTdlsCtx->pAdapter); + if ((wlan_hdd_validate_context(pHddCtx))) + return; + hdd_warn("tdls set peer " MAC_ADDRESS_STR " link status to %u", + MAC_ADDR_ARRAY(curr_peer->peerMac), status); + + curr_peer->link_status = status; + + /* If TDLS link status is already passed the discovery state + * then clear discovery attempt count + */ + if (status >= eTDLS_LINK_DISCOVERED) { + curr_peer->discovery_attempt = 0; + } + + if (curr_peer->isForcedPeer && curr_peer->state_change_notification) { + uint32_t opclass; + uint32_t channel; + + hdd_adapter_t *adapter = curr_peer->pHddTdlsCtx->pAdapter; + curr_peer->reason = reason; + + hdd_info("Peer is forced and the reason:%d", reason); + wlan_hdd_tdls_determine_channel_opclass(pHddCtx, adapter, + curr_peer, &channel, &opclass); + + wlan_hdd_tdls_get_wifi_hal_state(curr_peer, &state, &res); + (*curr_peer->state_change_notification)(curr_peer->peerMac, + opclass, channel, + state, res, adapter); + } + return; +} + +/** + * wlan_hdd_tdls_set_link_status() - set TDLS peer link status + * @pAdapter: HDD adapter + * @mac: mac address of TDLS peer + * @linkStatus: status + * @reason: reason + * + * Return: Void + */ +void wlan_hdd_tdls_set_link_status(hdd_adapter_t *pAdapter, + const uint8_t *mac, + tTDLSLinkStatus linkStatus, + tTDLSLinkReason reason) +{ + uint32_t state = 0; + int32_t res = 0; + hddTdlsPeer_t *curr_peer; + hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + + if (wlan_hdd_validate_context(pHddCtx)) + return; + + curr_peer = wlan_hdd_tdls_find_peer(pAdapter, mac); + if (curr_peer == NULL) { + QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR, + FL("curr_peer is NULL")); + return; + } + + curr_peer->link_status = linkStatus; + + /* If TDLS link status is already passed the discovery state + * then clear discovery attempt count + */ + if (linkStatus >= eTDLS_LINK_DISCOVERED) { + curr_peer->discovery_attempt = 0; + } + + if (curr_peer->isForcedPeer && curr_peer->state_change_notification) { + uint32_t opclass; + uint32_t channel; + hdd_adapter_t *adapter = curr_peer->pHddTdlsCtx->pAdapter; + + curr_peer->reason = reason; + + wlan_hdd_tdls_determine_channel_opclass(pHddCtx, adapter, + curr_peer, &channel, &opclass); + + wlan_hdd_tdls_get_wifi_hal_state(curr_peer, &state, &res); + (curr_peer->state_change_notification)(mac, opclass, channel, + state, res, adapter); + } + + return; +} + +/** + * wlan_hdd_tdls_recv_discovery_resp() - handling of tdls discovery response + * @pAdapter: HDD adapter + * @mac: mac address of peer from which the response was received + * + * Return: 0 for success or negative errno otherwise + */ +int wlan_hdd_tdls_recv_discovery_resp(hdd_adapter_t *pAdapter, + const uint8_t *mac) +{ + hddTdlsPeer_t *curr_peer; + tdlsCtx_t *pHddTdlsCtx; + hdd_context_t *pHddCtx; + int status = 0; + ENTER(); + + + pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + + if (0 != (wlan_hdd_validate_context(pHddCtx))) { + status = -EINVAL; + goto ret_status; + } + + mutex_lock(&pHddCtx->tdls_lock); + + pHddTdlsCtx = WLAN_HDD_GET_TDLS_CTX_PTR(pAdapter); + if (NULL == pHddTdlsCtx) { + hdd_err("pHddTdlsCtx is NULL"); + status = -EINVAL; + goto rel_lock; + } + + curr_peer = wlan_hdd_tdls_get_peer(pAdapter, mac); + if (NULL == curr_peer) { + hdd_err("curr_peer is NULL"); + status = -EINVAL; + goto rel_lock; + } + + if (pHddTdlsCtx->discovery_sent_cnt) + pHddTdlsCtx->discovery_sent_cnt--; + + wlan_hdd_tdls_check_power_save_prohibited(pAdapter); + + if (0 == pHddTdlsCtx->discovery_sent_cnt) { + qdf_mc_timer_stop(&pHddTdlsCtx->peerDiscoveryTimeoutTimer); + } + + hdd_notice("Discovery(%u) Response from " MAC_ADDRESS_STR + " link_status %d", pHddTdlsCtx->discovery_sent_cnt, + MAC_ADDR_ARRAY(curr_peer->peerMac), curr_peer->link_status); + + if (eTDLS_LINK_DISCOVERING == curr_peer->link_status) { + /* Since we are here, it means Throughput threshold is alredy met. Make sure RSSI + threshold is also met before setting up TDLS link */ + if ((int32_t) curr_peer->rssi > + (int32_t) pHddTdlsCtx->threshold_config. + rssi_trigger_threshold) { + wlan_hdd_tdls_set_peer_link_status(curr_peer, + eTDLS_LINK_DISCOVERED, + eTDLS_LINK_SUCCESS); + hdd_notice("Rssi Threshold met: " MAC_ADDRESS_STR + " rssi = %d threshold= %d", + MAC_ADDR_ARRAY(curr_peer->peerMac), + curr_peer->rssi, + pHddTdlsCtx->threshold_config.rssi_trigger_threshold); + + cfg80211_tdls_oper_request(pAdapter->dev, + curr_peer->peerMac, + NL80211_TDLS_SETUP, false, + GFP_KERNEL); + } else { + hdd_notice("Rssi Threshold not met: " MAC_ADDRESS_STR + " rssi = %d threshold = %d ", + MAC_ADDR_ARRAY(curr_peer->peerMac), + curr_peer->rssi, + pHddTdlsCtx->threshold_config.rssi_trigger_threshold); + + wlan_hdd_tdls_set_peer_link_status(curr_peer, + eTDLS_LINK_IDLE, + eTDLS_LINK_UNSPECIFIED); + + /* if RSSI threshold is not met then allow further discovery + * attempts by decrementing count for the last attempt + */ + if (curr_peer->discovery_attempt) + curr_peer->discovery_attempt--; + } + } + + curr_peer->tdls_support = eTDLS_CAP_SUPPORTED; +rel_lock: + mutex_unlock(&pHddCtx->tdls_lock); +ret_status: + EXIT(); + return status; +} + +/** + * wlan_hdd_tdls_set_peer_caps() - set TDLS peer capability + * @pAdapter: HDD adapter + * @mac: MAC address of the TDLS peer + * @StaParams: CSR Station Parameter + * @isBufSta: is peer buffer station + * @isOffChannelSupported: Is off channel supported + * @is_qos_wmm_sta: Is QoS-WMM supported + * + * Return: 0 for success or negative errno otherwise + */ +int wlan_hdd_tdls_set_peer_caps(hdd_adapter_t *pAdapter, + const uint8_t *mac, + tCsrStaParams *StaParams, + bool isBufSta, bool isOffChannelSupported, + bool is_qos_wmm_sta) +{ + hddTdlsPeer_t *curr_peer; + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(pAdapter); + int status = 0; + + if (0 != (wlan_hdd_validate_context(hdd_ctx))) { + status = -EINVAL; + goto ret_status; + } + + mutex_lock(&hdd_ctx->tdls_lock); + curr_peer = wlan_hdd_tdls_get_peer(pAdapter, mac); + if (curr_peer == NULL) { + hdd_err("curr_peer is NULL"); + status = -EINVAL; + goto rel_lock; + } + + curr_peer->uapsdQueues = StaParams->uapsd_queues; + curr_peer->maxSp = StaParams->max_sp; + curr_peer->isBufSta = isBufSta; + curr_peer->isOffChannelSupported = isOffChannelSupported; + + qdf_mem_copy(curr_peer->supported_channels, + StaParams->supported_channels, + StaParams->supported_channels_len); + + curr_peer->supported_channels_len = StaParams->supported_channels_len; + + qdf_mem_copy(curr_peer->supported_oper_classes, + StaParams->supported_oper_classes, + StaParams->supported_oper_classes_len); + + curr_peer->supported_oper_classes_len = + StaParams->supported_oper_classes_len; + curr_peer->qos = is_qos_wmm_sta; +rel_lock: + mutex_unlock(&hdd_ctx->tdls_lock); +ret_status: + return status; +} + +/** + * wlan_hdd_tdls_get_link_establish_params() - get TDLS link establish + * parameter + * @pAdapter: HDD adapter + * @mac: mac address + * @tdlsLinkEstablishParams: output parameter to store the result + * + * Return: 0 for success or negative errno otherwise + */ +int wlan_hdd_tdls_get_link_establish_params(hdd_adapter_t *pAdapter, + const u8 *mac, + tCsrTdlsLinkEstablishParams * + tdlsLinkEstablishParams) +{ + hddTdlsPeer_t *curr_peer; + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(pAdapter); + int status = 0; + + if (0 != (wlan_hdd_validate_context(hdd_ctx))) { + status = -EINVAL; + goto ret_status; + } + + mutex_lock(&hdd_ctx->tdls_lock); + curr_peer = wlan_hdd_tdls_get_peer(pAdapter, mac); + if (curr_peer == NULL) { + hdd_err("curr_peer is NULL"); + status = -EINVAL; + goto rel_lock; + } + + tdlsLinkEstablishParams->isResponder = curr_peer->is_responder; + tdlsLinkEstablishParams->uapsdQueues = curr_peer->uapsdQueues; + tdlsLinkEstablishParams->maxSp = curr_peer->maxSp; + tdlsLinkEstablishParams->isBufSta = curr_peer->isBufSta; + tdlsLinkEstablishParams->isOffChannelSupported = + curr_peer->isOffChannelSupported; + + qdf_mem_copy(tdlsLinkEstablishParams->supportedChannels, + curr_peer->supported_channels, + curr_peer->supported_channels_len); + + tdlsLinkEstablishParams->supportedChannelsLen = + curr_peer->supported_channels_len; + + qdf_mem_copy(tdlsLinkEstablishParams->supportedOperClasses, + curr_peer->supported_oper_classes, + curr_peer->supported_oper_classes_len); + + tdlsLinkEstablishParams->supportedOperClassesLen = + curr_peer->supported_oper_classes_len; + tdlsLinkEstablishParams->qos = curr_peer->qos; +rel_lock: + mutex_unlock(&hdd_ctx->tdls_lock); +ret_status: + return status; +} + +/** + * wlan_hdd_tdls_set_rssi() - Set TDLS RSSI on peer given by mac + * @pAdapter: HDD adapter + * @mac: MAC address of Peer + * @rxRssi: rssi value + * + * Set RSSI on TDSL peer + * + * Return: 0 for success or -EINVAL otherwise + */ +int wlan_hdd_tdls_set_rssi(hdd_adapter_t *pAdapter, const uint8_t *mac, + int8_t rxRssi) +{ + hddTdlsPeer_t *curr_peer; + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(pAdapter); + + if (0 != (wlan_hdd_validate_context(hdd_ctx))) + return -EINVAL; + + mutex_lock(&hdd_ctx->tdls_lock); + curr_peer = wlan_hdd_tdls_find_peer(pAdapter, mac); + if (curr_peer == NULL) { + mutex_unlock(&hdd_ctx->tdls_lock); + hdd_err("curr_peer is NULL"); + return -EINVAL; + } + + curr_peer->rssi = rxRssi; + mutex_unlock(&hdd_ctx->tdls_lock); + + return 0; +} + +/** + * wlan_hdd_tdls_set_responder() - Set/clear TDLS peer's responder role + * @pAdapter: HDD adapter + * @mac: MAC address of Peer + * @responder: flag that indicates if the TDLS peer should be responder or not + * + * Return: 0 for success or -EINVAL otherwise + */ +int wlan_hdd_tdls_set_responder(hdd_adapter_t *pAdapter, const uint8_t *mac, + uint8_t responder) +{ + hddTdlsPeer_t *curr_peer; + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(pAdapter); + int status = 0; + + if (0 != (wlan_hdd_validate_context(hdd_ctx))) { + status = -EINVAL; + goto ret_status; + } + mutex_lock(&hdd_ctx->tdls_lock); + curr_peer = wlan_hdd_tdls_get_peer(pAdapter, mac); + if (curr_peer == NULL) { + hdd_err("curr_peer is NULL"); + status = -EINVAL; + goto rel_lock; + } + + curr_peer->is_responder = responder; + +rel_lock: + mutex_unlock(&hdd_ctx->tdls_lock); +ret_status: + return status; +} + +/** + * wlan_hdd_tdls_set_signature() - Set TDLS peer's signature + * @pAdapter: HDD adapter + * @mac: MAC address of TDLS Peer + * @uSignature: signature value + * + * Return: 0 for success or -EINVAL otherwise + */ +int wlan_hdd_tdls_set_signature(hdd_adapter_t *pAdapter, const uint8_t *mac, + uint8_t uSignature) +{ + hddTdlsPeer_t *curr_peer; + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(pAdapter); + int status = 0; + + if (0 != (wlan_hdd_validate_context(hdd_ctx))) { + status = -EINVAL; + goto ret_status; + } + + mutex_lock(&hdd_ctx->tdls_lock); + curr_peer = wlan_hdd_tdls_get_peer(pAdapter, mac); + if (curr_peer == NULL) { + hdd_err("curr_peer is NULL"); + status = -EINVAL; + goto rel_lock; + } + + curr_peer->signature = uSignature; +rel_lock: + mutex_unlock(&hdd_ctx->tdls_lock); +ret_status: + return status; +} + +/** + * wlan_hdd_tdls_extract_sa() - Extract source address from socket buffer + * @skb: socket buffer + * @mac: output mac address buffer to store the source address + * + * Return: Void + */ +void wlan_hdd_tdls_extract_sa(struct sk_buff *skb, uint8_t *mac) +{ + memcpy(mac, skb->data + 6, 6); +} + +/** + * wlan_hdd_tdls_check_config() - validate tdls configuration parameters + * @config: tdls configuration parameter structure + * + * Return: 0 if all parameters are valid; -EINVAL otherwise + */ +static int wlan_hdd_tdls_check_config(tdls_config_params_t *config) +{ + if (config->tdls > 2) { + hdd_err("Invalid 1st argument %d. <0...2>", + config->tdls); + return -EINVAL; + } + if (config->tx_period_t < CFG_TDLS_TX_STATS_PERIOD_MIN || + config->tx_period_t > CFG_TDLS_TX_STATS_PERIOD_MAX) { + hdd_err("Invalid 2nd argument %d. <%d...%ld>", + config->tx_period_t, CFG_TDLS_TX_STATS_PERIOD_MIN, + CFG_TDLS_TX_STATS_PERIOD_MAX); + return -EINVAL; + } + if (config->tx_packet_n < CFG_TDLS_TX_PACKET_THRESHOLD_MIN || + config->tx_packet_n > CFG_TDLS_TX_PACKET_THRESHOLD_MAX) { + hdd_err("Invalid 3rd argument %d. <%d...%ld>", + config->tx_packet_n, CFG_TDLS_TX_PACKET_THRESHOLD_MIN, + CFG_TDLS_TX_PACKET_THRESHOLD_MAX); + return -EINVAL; + } + if (config->discovery_tries_n < CFG_TDLS_MAX_DISCOVERY_ATTEMPT_MIN || + config->discovery_tries_n > CFG_TDLS_MAX_DISCOVERY_ATTEMPT_MAX) { + hdd_err("Invalid 5th argument %d. <%d...%d>", + config->discovery_tries_n, + CFG_TDLS_MAX_DISCOVERY_ATTEMPT_MIN, + CFG_TDLS_MAX_DISCOVERY_ATTEMPT_MAX); + return -EINVAL; + } + if (config->idle_packet_n < CFG_TDLS_IDLE_PACKET_THRESHOLD_MIN || + config->idle_packet_n > CFG_TDLS_IDLE_PACKET_THRESHOLD_MAX) { + hdd_err("Invalid 7th argument %d. <%d...%d>", + config->idle_packet_n, + CFG_TDLS_IDLE_PACKET_THRESHOLD_MIN, + CFG_TDLS_IDLE_PACKET_THRESHOLD_MAX); + return -EINVAL; + } + if (config->rssi_trigger_threshold < CFG_TDLS_RSSI_TRIGGER_THRESHOLD_MIN + || config->rssi_trigger_threshold > + CFG_TDLS_RSSI_TRIGGER_THRESHOLD_MAX) { + hdd_err("Invalid 9th argument %d. <%d...%d>", + config->rssi_trigger_threshold, + CFG_TDLS_RSSI_TRIGGER_THRESHOLD_MIN, + CFG_TDLS_RSSI_TRIGGER_THRESHOLD_MAX); + return -EINVAL; + } + if (config->rssi_teardown_threshold < + CFG_TDLS_RSSI_TEARDOWN_THRESHOLD_MIN + || config->rssi_teardown_threshold > + CFG_TDLS_RSSI_TEARDOWN_THRESHOLD_MAX) { + hdd_err("Invalid 10th argument %d. <%d...%d>", + config->rssi_teardown_threshold, + CFG_TDLS_RSSI_TEARDOWN_THRESHOLD_MIN, + CFG_TDLS_RSSI_TEARDOWN_THRESHOLD_MAX); + return -EINVAL; + } + if (config->rssi_delta < CFG_TDLS_RSSI_DELTA_MIN + || config->rssi_delta > CFG_TDLS_RSSI_DELTA_MAX) { + hdd_err("Invalid 11th argument %d. <%d...%d>", + config->rssi_delta, + CFG_TDLS_RSSI_DELTA_MIN, + CFG_TDLS_RSSI_DELTA_MAX); + return -EINVAL; + } + return 0; +} + +/** + * wlan_tdd_tdls_reset_tx_rx() - reset tx/rx counters for all tdls peers + * @pHddTdlsCtx: TDLS context + * + * Caller has to take the TDLS lock before calling this function + * + * Return: Void + */ +static void wlan_tdd_tdls_reset_tx_rx(tdlsCtx_t *pHddTdlsCtx) +{ + int i; + struct list_head *head; + hddTdlsPeer_t *tmp; + struct list_head *pos, *q; + + for (i = 0; i < TDLS_PEER_LIST_SIZE; i++) { + head = &pHddTdlsCtx->peer_list[i]; + list_for_each_safe(pos, q, head) { + tmp = list_entry(pos, hddTdlsPeer_t, node); + tmp->tx_pkt = 0; + tmp->rx_pkt = 0; + } + } + + return; +} + +/** + * wlan_hdd_tdls_implicit_disable() - disable implicit tdls triggering + * @pHddTdlsCtx: TDLS context + * + * Return: Void + */ +static void wlan_hdd_tdls_implicit_disable(tdlsCtx_t *pHddTdlsCtx) +{ + hdd_info("Disable Implicit TDLS"); + wlan_hdd_tdls_timers_stop(pHddTdlsCtx); +} + +/** + * wlan_hdd_tdls_implicit_enable() - enable implicit tdls triggering + * @pHddTdlsCtx: TDLS context + * + * Return: Void + */ +static void wlan_hdd_tdls_implicit_enable(tdlsCtx_t *pHddTdlsCtx) +{ + hdd_info("Enable Implicit TDLS"); + wlan_hdd_tdls_peer_reset_discovery_processed(pHddTdlsCtx); + pHddTdlsCtx->discovery_sent_cnt = 0; + wlan_tdd_tdls_reset_tx_rx(pHddTdlsCtx); + wlan_hdd_tdls_check_power_save_prohibited(pHddTdlsCtx->pAdapter); + + /* Restart the connection tracker timer */ + wlan_hdd_tdls_timer_restart(pHddTdlsCtx->pAdapter, + &pHddTdlsCtx->peer_update_timer, + pHddTdlsCtx->threshold_config.tx_period_t); + +} + +/** + * wlan_hdd_tdls_set_mode() - set TDLS mode + * @pHddCtx: HDD context + * @tdls_mode: TDLS mode + * @bUpdateLast: Switch on if to set pHddCtx->tdls_mode_last to tdls_mode. + * If 1, set pHddCtx->tdls_mode_last to tdls_mode, otherwise + * set pHddCtx->tdls_mode_last to pHddCtx->tdls_mode + * @source: TDLS disable source enum values + * + * Return: Void + */ +static void wlan_hdd_tdls_set_mode(hdd_context_t *pHddCtx, + eTDLSSupportMode tdls_mode, + bool bUpdateLast, + enum tdls_disable_source source) +{ + hdd_adapter_list_node_t *pAdapterNode = NULL, *pNext = NULL; + QDF_STATUS status; + hdd_adapter_t *pAdapter; + tdlsCtx_t *pHddTdlsCtx; + + ENTER(); + + hdd_notice("mode %d", (int)tdls_mode); + + if (0 != (wlan_hdd_validate_context(pHddCtx))) + return; + + mutex_lock(&pHddCtx->tdls_lock); + + if (bUpdateLast) + pHddCtx->tdls_mode_last = tdls_mode; + + if (pHddCtx->tdls_mode == tdls_mode) { + mutex_unlock(&pHddCtx->tdls_lock); + hdd_notice("already in mode %d", (int)tdls_mode); + + switch (tdls_mode) { + /* TDLS is already enabled hence clear source mask, return */ + case eTDLS_SUPPORT_ENABLED: + case eTDLS_SUPPORT_EXPLICIT_TRIGGER_ONLY: + case eTDLS_SUPPORT_EXTERNAL_CONTROL: + clear_bit((unsigned long)source, + &pHddCtx->tdls_source_bitmap); + hdd_notice("clear source mask:%d", source); + return; + /* TDLS is already disabled hence set source mask, return */ + case eTDLS_SUPPORT_DISABLED: + set_bit((unsigned long)source, + &pHddCtx->tdls_source_bitmap); + hdd_notice("set source mask:%d", source); + return; + default: + return; + } + } + + status = hdd_get_front_adapter(pHddCtx, &pAdapterNode); + + while (NULL != pAdapterNode && QDF_STATUS_SUCCESS == status) { + pAdapter = pAdapterNode->pAdapter; + pHddTdlsCtx = WLAN_HDD_GET_TDLS_CTX_PTR(pAdapter); + if (NULL != pHddTdlsCtx) { + if (eTDLS_SUPPORT_ENABLED == tdls_mode || + eTDLS_SUPPORT_EXTERNAL_CONTROL == tdls_mode) { + clear_bit((unsigned long)source, + &pHddCtx->tdls_source_bitmap); + + /* + * Check if any TDLS source bit is set and if + * bitmap is not zero then we should not + * enable TDLS + */ + if (pHddCtx->tdls_source_bitmap) { + mutex_unlock(&pHddCtx->tdls_lock); + hdd_notice("Don't enable TDLS, source" + "bitmap: %lu", + pHddCtx->tdls_source_bitmap); + return; + } + wlan_hdd_tdls_implicit_enable(pHddTdlsCtx); + /* tdls implicit mode is enabled, so + * enable the connection tracker + */ + pHddCtx->enable_tdls_connection_tracker = + true; + } else if (eTDLS_SUPPORT_DISABLED == tdls_mode) { + set_bit((unsigned long)source, + &pHddCtx->tdls_source_bitmap); + wlan_hdd_tdls_implicit_disable(pHddTdlsCtx); + /* If tdls implicit mode is disabled, then + * stop the connection tracker. + */ + pHddCtx->enable_tdls_connection_tracker = + false; + } else if (eTDLS_SUPPORT_EXPLICIT_TRIGGER_ONLY == + tdls_mode) { + clear_bit((unsigned long)source, + &pHddCtx->tdls_source_bitmap); + wlan_hdd_tdls_implicit_disable(pHddTdlsCtx); + /* If tdls implicit mode is disabled, then + * stop the connection tracker. + */ + pHddCtx->enable_tdls_connection_tracker = + false; + + /* + * Check if any TDLS source bit is set and if + * bitmap is not zero then we should not + * enable TDLS + */ + if (pHddCtx->tdls_source_bitmap) { + mutex_unlock(&pHddCtx->tdls_lock); + return; + } + } + } + status = hdd_get_next_adapter(pHddCtx, pAdapterNode, &pNext); + pAdapterNode = pNext; + } + if (!bUpdateLast) + pHddCtx->tdls_mode_last = pHddCtx->tdls_mode; + + pHddCtx->tdls_mode = tdls_mode; + + mutex_unlock(&pHddCtx->tdls_lock); + EXIT(); +} + +/** + * wlan_hdd_tdls_set_params() - set TDLS parameters + * @dev: net device + * @config: TDLS configuration parameters + * + * Return: 0 if success or negative errno otherwise + */ +int wlan_hdd_tdls_set_params(struct net_device *dev, + tdls_config_params_t *config) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + tdlsCtx_t *pHddTdlsCtx; + eTDLSSupportMode req_tdls_mode; + tdlsInfo_t *tdlsParams; + QDF_STATUS qdf_ret_status = QDF_STATUS_E_FAILURE; + + if (wlan_hdd_tdls_check_config(config) != 0) { + return -EINVAL; + } + + /* config->tdls is mapped to 0->1, 1->2, 2->3 */ + req_tdls_mode = config->tdls + 1; + if (pHddCtx->tdls_mode == req_tdls_mode) { + hdd_warn("Already in mode %d", config->tdls); + return -EINVAL; + } + + mutex_lock(&pHddCtx->tdls_lock); + + pHddTdlsCtx = WLAN_HDD_GET_TDLS_CTX_PTR(pAdapter); + if (NULL == pHddTdlsCtx) { + mutex_unlock(&pHddCtx->tdls_lock); + hdd_err("pHddTdlsCtx is NULL"); + return -EINVAL; + } + + /* copy the configuration only when given tdls mode is implicit trigger enable */ + if (eTDLS_SUPPORT_ENABLED == req_tdls_mode || + eTDLS_SUPPORT_EXTERNAL_CONTROL == req_tdls_mode) { + memcpy(&pHddTdlsCtx->threshold_config, config, + sizeof(tdls_config_params_t)); + } + + mutex_unlock(&pHddCtx->tdls_lock); + + hdd_notice("iw set tdls params: %d %d %d %d %d %d %d", + config->tdls, + config->tx_period_t, + config->tx_packet_n, + config->discovery_tries_n, + config->idle_packet_n, + config->rssi_trigger_threshold, + config->rssi_teardown_threshold); + + wlan_hdd_tdls_set_mode(pHddCtx, req_tdls_mode, true, + HDD_SET_TDLS_MODE_SOURCE_USER); + + tdlsParams = qdf_mem_malloc(sizeof(tdlsInfo_t)); + if (NULL == tdlsParams) { + hdd_err("qdf_mem_malloc failed for tdlsParams"); + return -ENOMEM; + } + + tdlsParams->vdev_id = pAdapter->sessionId; + tdlsParams->tdls_state = config->tdls; + tdlsParams->notification_interval_ms = config->tx_period_t; + tdlsParams->tx_discovery_threshold = config->tx_packet_n; + tdlsParams->tx_teardown_threshold = config->idle_packet_n; + tdlsParams->rssi_teardown_threshold = config->rssi_teardown_threshold; + tdlsParams->rssi_delta = config->rssi_delta; + tdlsParams->tdls_options = 0; + if (pHddCtx->config->fEnableTDLSOffChannel) + tdlsParams->tdls_options |= ENA_TDLS_OFFCHAN; + if (pHddCtx->config->fEnableTDLSBufferSta) + tdlsParams->tdls_options |= ENA_TDLS_BUFFER_STA; + if (pHddCtx->config->fEnableTDLSSleepSta) + tdlsParams->tdls_options |= ENA_TDLS_SLEEP_STA; + tdlsParams->peer_traffic_ind_window = + pHddCtx->config->fTDLSPuapsdPTIWindow; + tdlsParams->peer_traffic_response_timeout = + pHddCtx->config->fTDLSPuapsdPTRTimeout; + tdlsParams->puapsd_mask = pHddCtx->config->fTDLSUapsdMask; + tdlsParams->puapsd_inactivity_time = + pHddCtx->config->fTDLSPuapsdInactivityTimer; + tdlsParams->puapsd_rx_frame_threshold = + pHddCtx->config->fTDLSRxFrameThreshold; + tdlsParams->teardown_notification_ms = + pHddCtx->config->tdls_idle_timeout; + tdlsParams->tdls_peer_kickout_threshold = + pHddCtx->config->tdls_peer_kickout_threshold; + + dump_tdls_state_param_setting(tdlsParams); + + qdf_ret_status = sme_update_fw_tdls_state(pHddCtx->hHal, tdlsParams, true); + if (QDF_STATUS_SUCCESS != qdf_ret_status) { + qdf_mem_free(tdlsParams); + return -EINVAL; + } + + return 0; +} + +/** + * wlan_hdd_tdls_get_adapter() - check system state and return hdd adapter + * @hdd_ctx: hdd context + * + * If TDLS possible, return the corresponding hdd adapter + * to enable TDLS in the system. + * + * Return: hdd adapter pointer or NULL. + */ +static hdd_adapter_t *wlan_hdd_tdls_get_adapter(hdd_context_t *hdd_ctx) +{ + uint32_t vdev_id; + + if (cds_get_connection_count() > 1) + return NULL; + + vdev_id = cds_mode_specific_vdev_id(QDF_STA_MODE); + if (CDS_INVALID_VDEV_ID != vdev_id) + return hdd_get_adapter_by_vdev(hdd_ctx, vdev_id); + + vdev_id = cds_mode_specific_vdev_id(QDF_P2P_CLIENT_MODE); + if (CDS_INVALID_VDEV_ID != vdev_id) + return hdd_get_adapter_by_vdev(hdd_ctx, vdev_id); + + return NULL; + +} + +/** + * wlan_hdd_update_tdls_info - update tdls status info + * @adapter: ptr to device adapter. + * @tdls_prohibited: indicates whether tdls is prohibited. + * @tdls_chan_swit_prohibited: indicates whether tdls channel switch + * is prohibited. + * + * Normally an AP does not influence TDLS connection between STAs + * associated to it. But AP may set bits for TDLS Prohibited or + * TDLS Channel Switch Prohibited in Extended Capability IE in + * Assoc/Re-assoc response to STA. So after STA is connected to + * an AP, call this function to update TDLS status as per those + * bits set in Ext Cap IE in received Assoc/Re-assoc response + * from AP. + * + * Return: None. + */ +void wlan_hdd_update_tdls_info(hdd_adapter_t *adapter, bool tdls_prohibited, + bool tdls_chan_swit_prohibited) +{ + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + tdlsCtx_t *hdd_tdls_ctx; + tdlsInfo_t *tdls_param; + QDF_STATUS qdf_ret_status = QDF_STATUS_E_FAILURE; + + /* If TDLS support is disabled then no need to update target */ + if (false == hdd_ctx->config->fEnableTDLSSupport) { + hdd_err("TDLS not enabled"); + goto done; + } + + hdd_info("tdls_prohibited: %d, tdls_chan_swit_prohibited: %d", + tdls_prohibited, tdls_chan_swit_prohibited); + + mutex_lock(&hdd_ctx->tdls_lock); + + hdd_tdls_ctx = WLAN_HDD_GET_TDLS_CTX_PTR(adapter); + if (!hdd_tdls_ctx) { + mutex_unlock(&hdd_ctx->tdls_lock); + /* may be TDLS is not applicable for this adapter */ + hdd_err("HDD TDLS context is null"); + goto done; + } + + if (hdd_ctx->set_state_info.set_state_cnt == 0 && + tdls_prohibited) { + mutex_unlock(&hdd_ctx->tdls_lock); + goto done; + } + + /* If AP or caller indicated TDLS Prohibited then disable tdls mode */ + if (tdls_prohibited) { + hdd_ctx->tdls_mode = eTDLS_SUPPORT_NOT_ENABLED; + } else { + if (false == hdd_ctx->config->fEnableTDLSImplicitTrigger) + hdd_ctx->tdls_mode = eTDLS_SUPPORT_EXPLICIT_TRIGGER_ONLY; + else if (true == hdd_ctx->config->fTDLSExternalControl) + hdd_ctx->tdls_mode = eTDLS_SUPPORT_EXTERNAL_CONTROL; + else + hdd_ctx->tdls_mode = eTDLS_SUPPORT_ENABLED; + } + tdls_param = qdf_mem_malloc(sizeof(*tdls_param)); + if (!tdls_param) { + mutex_unlock(&hdd_ctx->tdls_lock); + hdd_err("memory allocation failed for tdlsParams"); + goto done; + } + + tdls_param->notification_interval_ms = + hdd_tdls_ctx->threshold_config.tx_period_t; + tdls_param->tx_discovery_threshold = + hdd_tdls_ctx->threshold_config.tx_packet_n; + tdls_param->tx_teardown_threshold = + hdd_tdls_ctx->threshold_config.idle_packet_n; + tdls_param->rssi_teardown_threshold = + hdd_tdls_ctx->threshold_config.rssi_teardown_threshold; + tdls_param->rssi_delta = hdd_tdls_ctx->threshold_config.rssi_delta; + + mutex_unlock(&hdd_ctx->tdls_lock); + + /* If any concurrency detected, teardown all TDLS links and disable + * the tdls support + */ + hdd_warn("Concurrency check in TDLS! set state cnt %d tdls_prohibited %d", + hdd_ctx->set_state_info.set_state_cnt, tdls_prohibited); + + if (hdd_ctx->set_state_info.set_state_cnt == 1 && + !tdls_prohibited) { + hdd_warn("Concurrency not allowed in TDLS! set state cnt %d", + hdd_ctx->set_state_info.set_state_cnt); + wlan_hdd_tdls_disable_offchan_and_teardown_links(hdd_ctx); + tdls_prohibited = true; + hdd_ctx->tdls_mode = eTDLS_SUPPORT_NOT_ENABLED; + tdls_param->vdev_id = hdd_ctx->set_state_info.vdev_id; + } else { + tdls_param->vdev_id = adapter->sessionId; + } + + tdls_param->tdls_state = hdd_ctx->tdls_mode; + tdls_param->tdls_options = 0; + + /* Do not enable TDLS offchannel, if AP prohibited TDLS channel switch */ + if ((hdd_ctx->config->fEnableTDLSOffChannel) && + (!tdls_chan_swit_prohibited)) { + tdls_param->tdls_options |= ENA_TDLS_OFFCHAN; + } + + if (hdd_ctx->config->fEnableTDLSBufferSta) + tdls_param->tdls_options |= ENA_TDLS_BUFFER_STA; + + if (hdd_ctx->config->fEnableTDLSSleepSta) + tdls_param->tdls_options |= ENA_TDLS_SLEEP_STA; + + tdls_param->peer_traffic_ind_window = + hdd_ctx->config->fTDLSPuapsdPTIWindow; + tdls_param->peer_traffic_response_timeout = + hdd_ctx->config->fTDLSPuapsdPTRTimeout; + tdls_param->puapsd_mask = + hdd_ctx->config->fTDLSUapsdMask; + tdls_param->puapsd_inactivity_time = + hdd_ctx->config->fTDLSPuapsdInactivityTimer; + tdls_param->puapsd_rx_frame_threshold = + hdd_ctx->config->fTDLSRxFrameThreshold; + tdls_param->teardown_notification_ms = + hdd_ctx->config->tdls_idle_timeout; + tdls_param->tdls_peer_kickout_threshold = + hdd_ctx->config->tdls_peer_kickout_threshold; + + dump_tdls_state_param_setting(tdls_param); + + qdf_ret_status = sme_update_fw_tdls_state(hdd_ctx->hHal, + tdls_param, + true); + if (QDF_STATUS_SUCCESS != qdf_ret_status) { + qdf_mem_free(tdls_param); + goto done; + } + + mutex_lock(&hdd_ctx->tdls_lock); + + if (!tdls_prohibited) { + hdd_ctx->set_state_info.set_state_cnt++; + hdd_ctx->set_state_info.vdev_id = adapter->sessionId; + } else { + hdd_ctx->set_state_info.set_state_cnt--; + } + + hdd_info("TDLS Set state cnt %d", + hdd_ctx->set_state_info.set_state_cnt); + + mutex_unlock(&hdd_ctx->tdls_lock); +done: + cds_set_tdls_ct_mode(hdd_ctx); + return; +} + +/** + * wlan_hdd_tdls_notify_connect() - Update tdls state for every + * connect event. + * @adapter: hdd adapter + * @csr_roam_info: csr information + * + * After every connect event in the system, check whether TDLS + * can be enabled in the system. If TDLS can be enabled, update the + * TDLS state as needed. + * + * Return: None + */ +void wlan_hdd_tdls_notify_connect(hdd_adapter_t *adapter, + tCsrRoamInfo *csr_roam_info) +{ + hdd_info("Check and update TDLS state"); + + if (cds_get_connection_count() > 1) { + hdd_debug("concurrent sessions exist, TDLS can't be enabled"); + return; + } + + /* Association event */ + if (adapter->device_mode == QDF_STA_MODE || + adapter->device_mode == QDF_P2P_CLIENT_MODE) { + wlan_hdd_update_tdls_info(adapter, + csr_roam_info->tdls_prohibited, + csr_roam_info->tdls_chan_swit_prohibited); + } +} + +/** + * wlan_hdd_tdls_notify_disconnect() - Update tdls state for every + * disconnect event. + * @adapter: hdd adapter + * @lfr_roam: roaming case + * + * After every disconnect event in the system, check whether TDLS + * can be disabled/enabled in the system and update the + * TDLS state as needed. + * + * Return: None + */ +void wlan_hdd_tdls_notify_disconnect(hdd_adapter_t *adapter, bool lfr_roam) +{ + hdd_adapter_t *temp_adapter; + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + + hdd_info("Check and update TDLS state"); + + /* Disassociation event */ + if (adapter->device_mode == QDF_STA_MODE || + adapter->device_mode == QDF_P2P_CLIENT_MODE) { + wlan_hdd_update_tdls_info(adapter, true, true); + } + + /* Check TDLS could be enabled in the system + * after this disassoc event. + */ + if (!lfr_roam) { + temp_adapter = wlan_hdd_tdls_get_adapter( + hdd_ctx); + if (NULL != temp_adapter) + wlan_hdd_update_tdls_info(temp_adapter, + false, + false); + } +} + +void wlan_hdd_check_conc_and_update_tdls_state(hdd_context_t *hdd_ctx, + bool disable_tdls) +{ + hdd_adapter_t *temp_adapter; + + temp_adapter = wlan_hdd_tdls_get_adapter(hdd_ctx); + if (NULL != temp_adapter) { + if (disable_tdls) { + wlan_hdd_tdls_disable_offchan_and_teardown_links( + hdd_ctx); + wlan_hdd_update_tdls_info(temp_adapter, true, true); + } else { + wlan_hdd_update_tdls_info(temp_adapter, false, false); + } + } +} + +/** + * wlan_hdd_tdls_set_sta_id() - set station ID on a tdls peer + * @pAdapter: HDD adapter + * @mac: MAC address of a tdls peer + * @staId: station ID + * + * Return: 0 if success; negative errno otherwise + */ +int wlan_hdd_tdls_set_sta_id(hdd_adapter_t *pAdapter, const uint8_t *mac, + uint8_t staId) +{ + hddTdlsPeer_t *curr_peer; + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(pAdapter); + int status = 0; + + if (0 != (wlan_hdd_validate_context(hdd_ctx))) { + status = -EINVAL; + goto ret_status; + } + + mutex_lock(&hdd_ctx->tdls_lock); + curr_peer = wlan_hdd_tdls_get_peer(pAdapter, mac); + if (curr_peer == NULL) { + hdd_err("curr_peer is NULL"); + status = -EINVAL; + goto rel_lock; + } + + curr_peer->staId = staId; +rel_lock: + mutex_unlock(&hdd_ctx->tdls_lock); +ret_status: + return status; +} + +/** + * wlan_hdd_tdls_set_extctrl_param() - set external control parameter on a peer + * @pAdapter: HDD adapter + * @mac: MAC address of the peer + * @chan: Channel + * @max_latency: Maximum latency + * @op_class: Operation class + * @min_bandwidth: Minimal bandwidth + * + * Return: 0 for success; negative errno otherwise + */ +int wlan_hdd_tdls_set_extctrl_param(hdd_adapter_t *pAdapter, const uint8_t *mac, + uint32_t chan, uint32_t max_latency, + uint32_t op_class, uint32_t min_bandwidth) +{ + hddTdlsPeer_t *curr_peer; + hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + if (!pHddCtx) + return -EINVAL; + mutex_lock(&pHddCtx->tdls_lock); + curr_peer = wlan_hdd_tdls_find_peer(pAdapter, mac); + if (curr_peer == NULL) { + mutex_unlock(&pHddCtx->tdls_lock); + return -EINVAL; + } + curr_peer->op_class_for_pref_off_chan = (uint8_t) op_class; + curr_peer->pref_off_chan_num = (uint8_t) chan; + + mutex_unlock(&pHddCtx->tdls_lock); + return 0; +} + +/** + * wlan_hdd_tdls_update_peer_mac() - Update the peer mac information to firmware + * @adapter: hdd adapter to interface + * @mac: Mac address of the peer to be added + * @peerState: Current state of the peer + * + * This function updates TDLS peer state to firmware. Firmware will update + * connection table based on new peer state. + * + * Return:success (0) or failure (errno value) + */ +int wlan_hdd_tdls_update_peer_mac(hdd_adapter_t *adapter, const uint8_t *mac, + uint32_t peer_state) +{ + tSmeTdlsPeerStateParams sme_tdls_peer_state_params = {0}; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + + sme_tdls_peer_state_params.vdevId = adapter->sessionId; + qdf_mem_copy(&sme_tdls_peer_state_params.peerMacAddr, mac, + sizeof(sme_tdls_peer_state_params.peerMacAddr)); + sme_tdls_peer_state_params.peerState = peer_state; + status = sme_update_tdls_peer_state(hdd_ctx->hHal, + &sme_tdls_peer_state_params); + if (QDF_STATUS_SUCCESS != status) { + hdd_err("sme_UpdateTdlsPeerState failed for "MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(mac)); + return -EPERM; + } + return 0; +} + +/** + * wlan_hdd_tdls_set_force_peer() - set/clear isForcedPeer flag on a peer + * @pAdapter: HDD adapter + * @mac: MAC address of the tdls peer + * @forcePeer: value used to set isForcedPeer flag on the peer + * + * Return: 0 for success; negative errno otherwise + */ +int wlan_hdd_tdls_set_force_peer(hdd_adapter_t *pAdapter, const uint8_t *mac, + bool forcePeer) +{ + hddTdlsPeer_t *curr_peer; + hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + + if (!pHddCtx) + return -EINVAL; + + mutex_lock(&pHddCtx->tdls_lock); + curr_peer = wlan_hdd_tdls_find_peer(pAdapter, mac); + if (curr_peer == NULL) { + mutex_unlock(&pHddCtx->tdls_lock); + return -EINVAL; + } + + curr_peer->isForcedPeer = forcePeer; + mutex_unlock(&pHddCtx->tdls_lock); + return 0; +} + +/** + * wlan_hdd_tdls_find_peer() - find TDLS peer given its MAC address + * @pAdapter: HDD adapter + * @mac: MAC address of peer + * + * Return: If peerMac is found, then it returns pointer to hddTdlsPeer_t; + * otherwise, it returns NULL + */ +hddTdlsPeer_t *wlan_hdd_tdls_find_peer(hdd_adapter_t *pAdapter, + const uint8_t *mac) +{ + uint8_t key; + struct list_head *pos; + struct list_head *head; + hddTdlsPeer_t *curr_peer; + tdlsCtx_t *pHddTdlsCtx; + hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + + + if (0 != (wlan_hdd_validate_context(pHddCtx))) + return NULL; + + pHddTdlsCtx = WLAN_HDD_GET_TDLS_CTX_PTR(pAdapter); + if (NULL == pHddTdlsCtx) { + return NULL; + } + + key = wlan_hdd_tdls_hash_key(mac); + + head = &pHddTdlsCtx->peer_list[key]; + + list_for_each(pos, head) { + curr_peer = list_entry(pos, hddTdlsPeer_t, node); + if (!memcmp(mac, curr_peer->peerMac, 6)) { + QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO, + "findTdlsPeer: found staId %d", + curr_peer->staId); + return curr_peer; + } + } + + return NULL; +} + +/** + * wlan_hdd_tdls_find_all_peer() - find all peers matching the input MAC + * @pHddCtx: HDD context + * @mac: MAC address + * + * Return: TDLS peer if a matching is detected; NULL otherwise + */ +hddTdlsPeer_t *wlan_hdd_tdls_find_all_peer(hdd_context_t *pHddCtx, + const u8 *mac) +{ + hdd_adapter_list_node_t *pAdapterNode = NULL, *pNext = NULL; + hdd_adapter_t *pAdapter = NULL; + tdlsCtx_t *pHddTdlsCtx = NULL; + hddTdlsPeer_t *curr_peer = NULL; + QDF_STATUS status = 0; + + status = hdd_get_front_adapter(pHddCtx, &pAdapterNode); + while (NULL != pAdapterNode && QDF_STATUS_SUCCESS == status) { + pAdapter = pAdapterNode->pAdapter; + + pHddTdlsCtx = WLAN_HDD_GET_TDLS_CTX_PTR(pAdapter); + if (NULL != pHddTdlsCtx) { + curr_peer = + wlan_hdd_tdls_find_peer(pAdapter, mac); + if (curr_peer) { + return curr_peer; + } + } + status = hdd_get_next_adapter(pHddCtx, pAdapterNode, &pNext); + pAdapterNode = pNext; + } + return curr_peer; +} + +/** + * wlan_hdd_tdls_reset_peer() - reset TDLS peer identified by MAC address + * @pAdapter: HDD adapter + * @mac: MAC address of the peer + * + * Return: 0 for success; negative errno otherwise + */ +int wlan_hdd_tdls_reset_peer(hdd_adapter_t *pAdapter, const uint8_t *mac) +{ + hdd_context_t *pHddCtx; + hddTdlsPeer_t *curr_peer; + int status = 0; + + pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + + if (0 != (wlan_hdd_validate_context(pHddCtx))) { + status = -EINVAL; + goto ret_status; + } + + curr_peer = wlan_hdd_tdls_get_peer(pAdapter, mac); + if (curr_peer == NULL) { + hdd_err("curr_peer is NULL"); + status = -EINVAL; + goto ret_status; + } + + /* + * Reset preferred offchannel and opclass for offchannel as + * per INI configuration only if peer is not forced one. For + * forced peer, offchannel and opclass is set in HAL API at the + * time of enabling TDLS for that specific peer and so do not overwrite + * those set by user space. + */ + if (false == curr_peer->isForcedPeer) { + curr_peer->pref_off_chan_num = + pHddCtx->config->fTDLSPrefOffChanNum; + curr_peer->op_class_for_pref_off_chan = + wlan_hdd_find_opclass(WLAN_HDD_GET_HAL_CTX(pAdapter), + curr_peer->pref_off_chan_num, + pHddCtx->config->fTDLSPrefOffChanBandwidth); + } + + wlan_hdd_tdls_set_peer_link_status(curr_peer, + eTDLS_LINK_IDLE, + eTDLS_LINK_UNSPECIFIED); + curr_peer->staId = 0; +ret_status: + return status; +} + +/** + * wlan_hdd_tdls_peer_reset_discovery_processed() - reset discovery status + * @pHddTdlsCtx: TDLS context + * + * This function resets discovery processing bit for all TDLS peers + * + * Caller has to take the lock before calling this function + * + * Return: 0 + */ +static int32_t wlan_hdd_tdls_peer_reset_discovery_processed(tdlsCtx_t * + pHddTdlsCtx) +{ + int i; + struct list_head *head; + hddTdlsPeer_t *tmp; + struct list_head *pos, *q; + + pHddTdlsCtx->discovery_peer_cnt = 0; + + for (i = 0; i < TDLS_PEER_LIST_SIZE; i++) { + head = &pHddTdlsCtx->peer_list[i]; + list_for_each_safe(pos, q, head) { + tmp = list_entry(pos, hddTdlsPeer_t, node); + tmp->discovery_processed = 0; + } + } + + return 0; +} + +/** + * wlan_hdd_tdls_connected_peers() - Find the number of connected TDLS peers + * @pAdapter: HDD adapter + * + * Return: The number of connected TDLS peers or 0 if error is detected + */ +uint16_t wlan_hdd_tdls_connected_peers(hdd_adapter_t *pAdapter) +{ + hdd_context_t *pHddCtx; + + if ((NULL == pAdapter) || + (WLAN_HDD_ADAPTER_MAGIC != pAdapter->magic)) { + hdd_err("invalid pAdapter: %p", pAdapter); + return 0; + } + pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + + if (wlan_hdd_validate_context(pHddCtx)) + return 0; + + return pHddCtx->connected_peer_count; +} + +/** + * wlan_hdd_tdls_get_all_peers() - dump all TDLS peer info into output string + * @pAdapter: HDD adapter + * @buf: output string buffer to hold the peer info + * @buflen: the size of output string buffer + * + * Return: The size (in bytes) of the valid peer info in the output buffer + */ +int wlan_hdd_tdls_get_all_peers(hdd_adapter_t *pAdapter, char *buf, int buflen) +{ + int i; + int len, init_len; + struct list_head *head; + struct list_head *pos; + hddTdlsPeer_t *curr_peer; + tdlsCtx_t *pHddTdlsCtx; + hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + hdd_station_ctx_t *hdd_sta_ctx; + + ENTER(); + + if (0 != (wlan_hdd_validate_context(pHddCtx))) + return 0; + + if ((QDF_STA_MODE != pAdapter->device_mode) + && (QDF_P2P_CLIENT_MODE != pAdapter->device_mode)) { + len = scnprintf(buf, buflen, + "\nNo TDLS support for this adapter\n"); + return len; + } + + hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + if (eConnectionState_Associated != hdd_sta_ctx->conn_info.connState) { + len = scnprintf(buf, buflen, "\nSTA is not associated\n"); + return len; + } + + init_len = buflen; + len = scnprintf(buf, buflen, "\n%-18s%-3s%-4s%-3s%-5s\n", + "MAC", "Id", "cap", "up", "RSSI"); + buf += len; + buflen -= len; + /* 1234567890123456789012345678901234567 */ + len = scnprintf(buf, buflen, "---------------------------------\n"); + buf += len; + buflen -= len; + + mutex_lock(&pHddCtx->tdls_lock); + + pHddTdlsCtx = WLAN_HDD_GET_TDLS_CTX_PTR(pAdapter); + if (NULL == pHddTdlsCtx) { + mutex_unlock(&pHddCtx->tdls_lock); + len = scnprintf(buf, buflen, "TDLS not enabled\n"); + return len; + } + for (i = 0; i < TDLS_PEER_LIST_SIZE; i++) { + head = &pHddTdlsCtx->peer_list[i]; + + list_for_each(pos, head) { + curr_peer = list_entry(pos, hddTdlsPeer_t, node); + + if (buflen < 32 + 1) + break; + len = scnprintf(buf, buflen, + MAC_ADDRESS_STR "%3d%4s%3s%5d\n", + MAC_ADDR_ARRAY(curr_peer->peerMac), + curr_peer->staId, + (curr_peer->tdls_support == + eTDLS_CAP_SUPPORTED) ? "Y" : "N", + TDLS_IS_CONNECTED(curr_peer) ? "Y" : + "N", curr_peer->rssi); + buf += len; + buflen -= len; + } + } + mutex_unlock(&pHddCtx->tdls_lock); + EXIT(); + return init_len - buflen; +} + +/** + * wlan_hdd_tdls_connection_callback() - callback after tdls connection + * @pAdapter: HDD adapter + * + * Return: Void + */ +void wlan_hdd_tdls_connection_callback(hdd_adapter_t *pAdapter) +{ + tdlsCtx_t *pHddTdlsCtx; + hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + uint32_t tx_period_t; + + if (NULL == pHddCtx) { + QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR, + FL("pHddCtx points to NULL")); + return; + } + + mutex_lock(&pHddCtx->tdls_lock); + + pHddTdlsCtx = WLAN_HDD_GET_TDLS_CTX_PTR(pAdapter); + if (NULL == pHddTdlsCtx) { + mutex_unlock(&pHddCtx->tdls_lock); + QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR, + FL("pHddTdlsCtx points to NULL")); + return; + } + + tx_period_t = pHddTdlsCtx->threshold_config.tx_period_t; + + hdd_notice("update %d", pHddTdlsCtx->threshold_config.tx_period_t); + + if (eTDLS_SUPPORT_ENABLED == pHddCtx->tdls_mode || + eTDLS_SUPPORT_EXTERNAL_CONTROL == pHddCtx->tdls_mode) { + wlan_hdd_tdls_peer_reset_discovery_processed(pHddTdlsCtx); + pHddTdlsCtx->discovery_sent_cnt = 0; + wlan_hdd_tdls_check_power_save_prohibited(pHddTdlsCtx->pAdapter); + /* Start the connection tracker timer */ + wlan_hdd_tdls_timer_restart(pHddTdlsCtx->pAdapter, + &pHddTdlsCtx->peer_update_timer, + tx_period_t); + } + + mutex_unlock(&pHddCtx->tdls_lock); + +} + +/** + * wlan_hdd_tdls_disconnection_callback() - callback after tdls disconnection + * @pAdapter: HDD adapter + * + * Return: Void + */ +void wlan_hdd_tdls_disconnection_callback(hdd_adapter_t *pAdapter) +{ + tdlsCtx_t *pHddTdlsCtx; + hdd_context_t *pHddCtx; + + ENTER(); + + pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + + /* + * Use of wlan_hdd_validate_context is returning failure when + * driver load/unload in progress.so we are directly NULL + * checking context pointer + */ + if (!pHddCtx) + return; + + mutex_lock(&pHddCtx->tdls_lock); + + pHddTdlsCtx = WLAN_HDD_GET_TDLS_CTX_PTR(pAdapter); + if (NULL == pHddTdlsCtx) { + mutex_unlock(&pHddCtx->tdls_lock); + hdd_notice("pHddTdlsCtx is NULL"); + return; + } + pHddTdlsCtx->discovery_sent_cnt = 0; + wlan_hdd_tdls_check_power_save_prohibited(pHddTdlsCtx->pAdapter); + + wlan_hdd_tdls_timers_stop(pHddTdlsCtx); + + pHddTdlsCtx->curr_candidate = NULL; + + mutex_unlock(&pHddCtx->tdls_lock); +} + +/** + * wlan_hdd_tdls_mgmt_completion_callback() - callback for TDLS management + * TX completion + * @pAdapter: HDD adapter + * @statusCode: management TX completion status + * + * Return: Void + */ +void wlan_hdd_tdls_mgmt_completion_callback(hdd_adapter_t *pAdapter, + uint32_t statusCode) +{ + pAdapter->mgmtTxCompletionStatus = statusCode; + hdd_notice("Mgmt TX Completion %d", statusCode); + complete(&pAdapter->tdls_mgmt_comp); +} + +/** + * wlan_hdd_tdls_increment_peer_count() - increment connected TDLS peer counter + * @pAdapter: HDD adapter + * + * Return: Void + */ +void wlan_hdd_tdls_increment_peer_count(hdd_adapter_t *pAdapter) +{ + hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + + ENTER(); + + if (0 != (wlan_hdd_validate_context(pHddCtx))) + return; + + mutex_lock(&pHddCtx->tdls_lock); + + pHddCtx->connected_peer_count++; + wlan_hdd_tdls_check_power_save_prohibited(pAdapter); + + hdd_notice("Connected peer count %d", + pHddCtx->connected_peer_count); + + mutex_unlock(&pHddCtx->tdls_lock); + EXIT(); +} + +/** + * wlan_hdd_tdls_decrement_peer_count() - decrement connected TDLS peer counter + * @pAdapter: HDD adapter + * + * Return: Void + */ +void wlan_hdd_tdls_decrement_peer_count(hdd_adapter_t *pAdapter) +{ + hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + uint16_t connected_peer_count; + + ENTER(); + + if (0 != (wlan_hdd_validate_context(pHddCtx))) + return; + + mutex_lock(&pHddCtx->tdls_lock); + + if (pHddCtx->connected_peer_count) + pHddCtx->connected_peer_count--; + wlan_hdd_tdls_check_power_save_prohibited(pAdapter); + + connected_peer_count = pHddCtx->connected_peer_count; + mutex_unlock(&pHddCtx->tdls_lock); + + hdd_notice("Connected peer count %d", connected_peer_count); + + EXIT(); +} + + +/** + * wlan_hdd_tdls_find_progress_peer() - find peer if TDLS is ongoing + * @pAdapter: HDD adapter + * @mac: If NULL check for all the peer list, otherwise, skip this mac when + * skip_self is true + * @skip_self: If true, skip this mac. otherwise, check all the peer list. if + * mac is NULL, this argument is ignored, and check for all the peer + * list. + * + * Return: Pointer to hddTdlsPeer_t if TDLS is ongoing. Otherwise return NULL. + */ +static hddTdlsPeer_t *wlan_hdd_tdls_find_progress_peer(hdd_adapter_t *pAdapter, + const u8 *mac, + u8 skip_self) +{ + int i; + struct list_head *head; + hddTdlsPeer_t *curr_peer; + struct list_head *pos; + tdlsCtx_t *pHddTdlsCtx = WLAN_HDD_GET_TDLS_CTX_PTR(pAdapter);; + + if (NULL == pHddTdlsCtx) { + hdd_notice("pHddTdlsCtx is NULL"); + return NULL; + } + + for (i = 0; i < TDLS_PEER_LIST_SIZE; i++) { + head = &pHddTdlsCtx->peer_list[i]; + list_for_each(pos, head) { + curr_peer = list_entry(pos, hddTdlsPeer_t, node); + if (skip_self && mac + && !memcmp(mac, curr_peer->peerMac, 6)) { + continue; + } else { + if (eTDLS_LINK_CONNECTING == + curr_peer->link_status) { + hdd_notice(MAC_ADDRESS_STR + " eTDLS_LINK_CONNECTING", + MAC_ADDR_ARRAY(curr_peer->peerMac)); + return curr_peer; + } + } + } + } + return NULL; +} + +/** + * wlan_hdd_tdls_is_progress() - find the peer with ongoing TDLS progress + * @pHddCtx: HDD context + * @mac: mac address of the peer + * @skip_self: if 1, skip checking self. If 0, search includes self + * + * Return: TDLS peer if found; NULL otherwise + */ +hddTdlsPeer_t *wlan_hdd_tdls_is_progress(hdd_context_t *pHddCtx, + const uint8_t *mac, + uint8_t skip_self) +{ + hdd_adapter_list_node_t *pAdapterNode = NULL, *pNext = NULL; + hdd_adapter_t *pAdapter = NULL; + tdlsCtx_t *pHddTdlsCtx = NULL; + hddTdlsPeer_t *curr_peer = NULL; + QDF_STATUS status = 0; + + status = hdd_get_front_adapter(pHddCtx, &pAdapterNode); + while (NULL != pAdapterNode && QDF_STATUS_SUCCESS == status) { + pAdapter = pAdapterNode->pAdapter; + + pHddTdlsCtx = WLAN_HDD_GET_TDLS_CTX_PTR(pAdapter); + if (NULL != pHddTdlsCtx) { + curr_peer = + wlan_hdd_tdls_find_progress_peer(pAdapter, mac, + skip_self); + if (curr_peer) { + return curr_peer; + } + } + status = hdd_get_next_adapter(pHddCtx, pAdapterNode, &pNext); + pAdapterNode = pNext; + } + + return NULL; +} + +/** + * wlan_hdd_tdls_copy_scan_context() - Copy TDLS scan context + * @pHddCtx: HDD context + * @wiphy: wiphy pointer + * @dev: net device + * request: source scan context + * + * Copy the source scan context into the HDD context's TDLS scan context + * + * Return: 0 for success; negative errno otherwise + */ +int wlan_hdd_tdls_copy_scan_context(hdd_context_t *pHddCtx, + struct wiphy *wiphy, + struct cfg80211_scan_request *request) +{ + tdls_scan_context_t *scan_ctx; + + ENTER(); + + if (0 != (wlan_hdd_validate_context(pHddCtx))) + return -EINVAL; + + scan_ctx = &pHddCtx->tdls_scan_ctxt; + + scan_ctx->wiphy = wiphy; + + scan_ctx->scan_request = request; + EXIT(); + return 0; +} + +/** + * wlan_hdd_tdls_scan_init_work() - schedule tdls scan work + * @pHddCtx: HDD context + * @wiphy: wiphy pointer + * @dev: net device + * @request: scan request + * @delay: delay value to pass to the work scheduling + * @source: scan request source(NL/Vendor scan) + * + * Return: Void + */ +static void wlan_hdd_tdls_scan_init_work(hdd_context_t *pHddCtx, + struct wiphy *wiphy, + struct cfg80211_scan_request *request, + unsigned long delay, uint8_t source) +{ + if (TDLS_CTX_MAGIC != pHddCtx->tdls_scan_ctxt.magic) { + wlan_hdd_tdls_copy_scan_context(pHddCtx, wiphy, request); + pHddCtx->tdls_scan_ctxt.attempt = 0; + pHddCtx->tdls_scan_ctxt.magic = TDLS_CTX_MAGIC; + pHddCtx->tdls_scan_ctxt.source = source; + } + schedule_delayed_work(&pHddCtx->tdls_scan_ctxt.tdls_scan_work, delay); +} + +bool wlan_hdd_tdls_check_enable_tdls_scan(hdd_context_t *hdd_ctx) +{ + /* If TDLSScan is enabled then allow scan and maintain tdls link + * regardless if peer is buffer sta capable or not and if device + * is sleep sta capable or not. If peer is not buffer sta capable, + * then Tx would stop when device initiates scan and there will be + * loss of Rx packets since peer would not know when device moves + * away from the tdls channel. + */ + if (hdd_ctx->config->enable_tdls_scan) + return true; + else + return false; +} + +bool wlan_hdd_tdls_check_peer_buf_capable(hdd_context_t *hdd_ctx, + uint16_t connectedTdlsPeers) +{ + uint8_t staIdx; + hddTdlsPeer_t *curr_peer; + + /* Self STA is not TDLSSleepSTA capable */ + if (!(hdd_ctx->config->fEnableTDLSSleepSta)) + return false; + + if (connectedTdlsPeers > TDLS_MAX_CONNECTED_PEERS_TO_ALLOW_SCAN) + return false; + + for (staIdx = 0; staIdx < hdd_ctx->max_num_tdls_sta; staIdx++) { + if (hdd_ctx->tdlsConnInfo[staIdx].staId) { + curr_peer = wlan_hdd_tdls_find_all_peer(hdd_ctx, + hdd_ctx->tdlsConnInfo[staIdx].peerMac.bytes); + if (curr_peer) { + /* TDLS peer is not BufSta capable */ + if (!(curr_peer->isBufSta)) + return false; + } + } + } + + /* All connected peers bufStas and we can be sleepSta so allow scan */ + return true; +} + +/** + * wlan_hdd_tdls_scan_callback() - callback for TDLS scan operation + * @pAdapter: HDD adapter + * @wiphy: wiphy + * @dev: net device + * @request: scan request + * + * Return: negative = caller should stop and return error code immediately + * 0 = caller should stop and return success immediately + * 1 = caller can continue to scan + */ +int wlan_hdd_tdls_scan_callback(hdd_adapter_t *pAdapter, struct wiphy *wiphy, + struct cfg80211_scan_request *request, + uint8_t source) +{ + hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + u16 connectedTdlsPeers; + hddTdlsPeer_t *curr_peer; + unsigned long delay; + int ret; + + ENTER(); + + ret = wlan_hdd_validate_context(pHddCtx); + if (ret) + return ret; + + /* if tdls is not enabled, then continue scan */ + if (eTDLS_SUPPORT_NOT_ENABLED == pHddCtx->tdls_mode) + return 1; + + mutex_lock(&pHddCtx->tdls_lock); + curr_peer = wlan_hdd_tdls_is_progress(pHddCtx, NULL, 0); + if (NULL != curr_peer) { + if (pHddCtx->tdls_scan_ctxt.reject++ >= TDLS_MAX_SCAN_REJECT) { + pHddCtx->tdls_scan_ctxt.reject = 0; + hdd_notice(MAC_ADDRESS_STR + ". scan rejected %d. force it to idle", + MAC_ADDR_ARRAY(curr_peer->peerMac), + pHddCtx->tdls_scan_ctxt.reject); + + wlan_hdd_tdls_set_peer_link_status(curr_peer, + eTDLS_LINK_IDLE, + eTDLS_LINK_UNSPECIFIED); + mutex_unlock(&pHddCtx->tdls_lock); + return 1; + } + mutex_unlock(&pHddCtx->tdls_lock); + hdd_warn("tdls in progress. scan rejected %d", + pHddCtx->tdls_scan_ctxt.reject); + return -EBUSY; + } + mutex_unlock(&pHddCtx->tdls_lock); + + /* tdls teardown is ongoing */ + if (eTDLS_SUPPORT_DISABLED == pHddCtx->tdls_mode) { + connectedTdlsPeers = wlan_hdd_tdls_connected_peers(pAdapter); + if (connectedTdlsPeers + && (pHddCtx->tdls_scan_ctxt.attempt < + TDLS_MAX_SCAN_SCHEDULE)) { + delay = + (unsigned long)(TDLS_DELAY_SCAN_PER_CONNECTION * + connectedTdlsPeers); + hdd_notice("tdls disabled, but still connected_peers %d attempt %d. schedule scan %lu msec", + connectedTdlsPeers, + pHddCtx->tdls_scan_ctxt.attempt, delay); + + wlan_hdd_tdls_scan_init_work(pHddCtx, wiphy, + request, + msecs_to_jiffies(delay), + source); + /* scan should not continue */ + return 0; + } + /* no connected peer or max retry reached, scan continue */ + hdd_notice("tdls disabled. connected_peers %d attempt %d. scan allowed", + connectedTdlsPeers, + pHddCtx->tdls_scan_ctxt.attempt); + return 1; + } + /* while tdls is up, first time scan */ + else if (eTDLS_SUPPORT_ENABLED == pHddCtx->tdls_mode || + eTDLS_SUPPORT_EXTERNAL_CONTROL == pHddCtx->tdls_mode || + eTDLS_SUPPORT_EXPLICIT_TRIGGER_ONLY == pHddCtx->tdls_mode) { + /* disable implicit trigger logic & tdls operatoin */ + wlan_hdd_tdls_set_mode(pHddCtx, eTDLS_SUPPORT_DISABLED, false, + HDD_SET_TDLS_MODE_SOURCE_SCAN); + /* indicate the teardown all connected to peer */ + connectedTdlsPeers = wlan_hdd_tdls_connected_peers(pAdapter); + if (connectedTdlsPeers) { + uint8_t staIdx; + uint8_t num = 0; + uint8_t i; + hddTdlsPeer_t *curr_peer; + hddTdlsPeer_t *connectedPeerList[HDD_MAX_NUM_TDLS_STA]; + bool allow_scan; + + allow_scan = wlan_hdd_tdls_check_enable_tdls_scan( + pHddCtx); + if (allow_scan) { + hdd_notice("TDLSScan enabled, keep tdls link and allow scan, connectedTdlsPeers: %d", + connectedTdlsPeers); + return 1; + } + + mutex_lock(&pHddCtx->tdls_lock); + allow_scan = wlan_hdd_tdls_check_peer_buf_capable( + pHddCtx, connectedTdlsPeers); + if (allow_scan) { + mutex_unlock(&pHddCtx->tdls_lock); + hdd_notice("All peers (num %d) bufSTAs, we can be sleep sta, so allow scan, tdls mode changed to %d", + connectedTdlsPeers, + pHddCtx->tdls_mode); + return 1; + } + + for (staIdx = 0; staIdx < pHddCtx->max_num_tdls_sta; + staIdx++) { + if (pHddCtx->tdlsConnInfo[staIdx].staId) { + curr_peer = + wlan_hdd_tdls_find_all_peer(pHddCtx, + pHddCtx-> + tdlsConnInfo + [staIdx]. + peerMac. + bytes); + if (curr_peer) { + connectedPeerList[num++] = + curr_peer; + } + } + } + + for (i = 0; i < num; i++) { + hdd_notice("indicate TDLS teadown (staId %d)", + connectedPeerList[i]->staId); + wlan_hdd_tdls_indicate_teardown + (connectedPeerList[i]->pHddTdlsCtx-> + pAdapter, connectedPeerList[i], + eSIR_MAC_TDLS_TEARDOWN_UNSPEC_REASON); + hdd_send_wlan_tdls_teardown_event( + eTDLS_TEARDOWN_SCAN, + connectedPeerList[i]->peerMac); + } + mutex_unlock(&pHddCtx->tdls_lock); + /* schedule scan */ + delay = + (unsigned long)(TDLS_DELAY_SCAN_PER_CONNECTION * + connectedTdlsPeers); + + hdd_notice("tdls enabled (mode %d), connected_peers %d. schedule scan %lu msec", + pHddCtx->tdls_mode, + wlan_hdd_tdls_connected_peers(pAdapter), delay); + + wlan_hdd_tdls_scan_init_work(pHddCtx, wiphy, + request, + msecs_to_jiffies(delay), + source); + /* scan should not continue */ + return 0; + } + /* no connected peer, scan continue */ + hdd_notice("tdls_mode %d, and no tdls connection. scan allowed", + pHddCtx->tdls_mode); + } + EXIT(); + return 1; +} + +/** + * wlan_hdd_tdls_scan_done_callback() - callback for tdls scan done event + * @pAdapter: HDD adapter + * + * Return: Void + */ +void wlan_hdd_tdls_scan_done_callback(hdd_adapter_t *pAdapter) +{ + hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + + ENTER(); + + if (0 != (wlan_hdd_validate_context(pHddCtx))) + return; + + if (eTDLS_SUPPORT_NOT_ENABLED == pHddCtx->tdls_mode) { + hdd_info("TDLS mode is disabled OR not enabled"); + return; + } + + /* free allocated memory at scan time */ + wlan_hdd_tdls_free_scan_request(&pHddCtx->tdls_scan_ctxt); + + /* if tdls was enabled before scan, re-enable tdls mode */ + if (eTDLS_SUPPORT_ENABLED == pHddCtx->tdls_mode_last || + eTDLS_SUPPORT_EXTERNAL_CONTROL == pHddCtx->tdls_mode_last || + eTDLS_SUPPORT_EXPLICIT_TRIGGER_ONLY == pHddCtx->tdls_mode_last) { + hdd_notice("revert tdls mode %d", + pHddCtx->tdls_mode_last); + + wlan_hdd_tdls_set_mode(pHddCtx, pHddCtx->tdls_mode_last, false, + HDD_SET_TDLS_MODE_SOURCE_SCAN); + } + EXIT(); +} + +/** + * wlan_hdd_tdls_timer_restart() - restart TDLS timer + * @pAdapter: HDD adapter + * @timer: timer to restart + * @expirationTime: new expiration time to set for the timer + * + * Return: Void + */ +void wlan_hdd_tdls_timer_restart(hdd_adapter_t *pAdapter, + qdf_mc_timer_t *timer, + uint32_t expirationTime) +{ + hdd_station_ctx_t *pHddStaCtx; + + if (NULL == pAdapter || WLAN_HDD_ADAPTER_MAGIC != pAdapter->magic) { + hdd_err("invalid pAdapter: %p", pAdapter); + return; + } + + pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + + /* Check whether driver load unload is in progress */ + if (cds_is_load_or_unload_in_progress()) { + hdd_warn("Driver load/unload is in progress."); + return; + } + + if (hdd_conn_is_connected(pHddStaCtx)) { + qdf_mc_timer_stop(timer); + qdf_mc_timer_start(timer, expirationTime); + } +} + +/** + * wlan_hdd_tdls_indicate_teardown() - indicate tdls teardown + * @pAdapter: HDD adapter + * @curr_peer: peer tdls teardown happened + * @reason: teardown reason + * + * Return: Void + */ +void wlan_hdd_tdls_indicate_teardown(hdd_adapter_t *pAdapter, + hddTdlsPeer_t *curr_peer, uint16_t reason) +{ + if ((NULL == pAdapter || WLAN_HDD_ADAPTER_MAGIC != pAdapter->magic) || + (NULL == curr_peer)) { + hdd_err("parameters passed are invalid"); + if (!curr_peer) + hdd_err("curr_peer is NULL"); + return; + } + + if (eTDLS_LINK_CONNECTED != curr_peer->link_status) + return; + + wlan_hdd_tdls_set_peer_link_status(curr_peer, + eTDLS_LINK_TEARING, + eTDLS_LINK_UNSPECIFIED); + hdd_info("Teardown reason %d", reason); + cfg80211_tdls_oper_request(pAdapter->dev, + curr_peer->peerMac, + NL80211_TDLS_TEARDOWN, reason, GFP_KERNEL); +} + +/** + * wlan_hdd_set_callback() - set state change callback on current TDLS peer + * @curr_peer: current TDLS peer + * @callback: state change callback + * + * Return: 0 if success; negative errno otherwise + */ +int wlan_hdd_set_callback(hddTdlsPeer_t *curr_peer, + cfg80211_exttdls_callback callback) +{ + hdd_context_t *pHddCtx; + hdd_adapter_t *pAdapter; + if (!curr_peer) + return -EINVAL; + pAdapter = curr_peer->pHddTdlsCtx->pAdapter; + pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + if ((NULL == pHddCtx)) + return -EINVAL; + curr_peer->state_change_notification = callback; + return 0; +} + +/** + * wlan_hdd_tdls_get_wifi_hal_state() - get tdls wifi hal state on current peer + * @curr_peer: current TDLS peer + * @state: output parameter to store the tdls wifi hal state + * @reason: output parameter to store the reason of the current peer + * + * Return: Void + */ +void wlan_hdd_tdls_get_wifi_hal_state(hddTdlsPeer_t *curr_peer, + uint32_t *state, int32_t *reason) +{ + hdd_context_t *hddctx; + hdd_adapter_t *adapter; + + if (!curr_peer) { + hdd_err("curr_peer is NULL"); + return; + } + + adapter = curr_peer->pHddTdlsCtx->pAdapter; + hddctx = WLAN_HDD_GET_CTX(adapter); + + if (0 != (wlan_hdd_validate_context(hddctx))) + return; + + *reason = curr_peer->reason; + + switch (curr_peer->link_status) { + case eTDLS_LINK_IDLE: + case eTDLS_LINK_DISCOVERED: + *state = QCA_WIFI_HAL_TDLS_ENABLED; + break; + case eTDLS_LINK_DISCOVERING: + case eTDLS_LINK_CONNECTING: + *state = QCA_WIFI_HAL_TDLS_ENABLED; + break; + case eTDLS_LINK_CONNECTED: + if ((hddctx->config->fEnableTDLSOffChannel) && + (hddctx->tdls_fw_off_chan_mode == ENABLE_CHANSWITCH)) + *state = QCA_WIFI_HAL_TDLS_ESTABLISHED_OFF_CHANNEL; + else + *state = QCA_WIFI_HAL_TDLS_ESTABLISHED; + break; + case eTDLS_LINK_TEARING: + *state = QCA_WIFI_HAL_TDLS_DROPPED; + break; + } +} + +/** + * wlan_hdd_tdls_get_status() - get tdls status on current tdls peer + * @pAdapter: HDD adapter + * @mac: MAC address of current TDLS peer + * @state: output parameter to store the tdls wifi hal state + * @reason: output parameter to store the reason of the current peer + * + * Return: 0 if success; negative errno otherwise + */ +int wlan_hdd_tdls_get_status(hdd_adapter_t *pAdapter, + const uint8_t *mac, uint32_t *opclass, + uint32_t *channel, uint32_t *state, + int32_t *reason) +{ + hddTdlsPeer_t *curr_peer; + hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + + if (0 != (wlan_hdd_validate_context(pHddCtx))) + return -EINVAL; + + mutex_lock(&pHddCtx->tdls_lock); + curr_peer = wlan_hdd_tdls_find_peer(pAdapter, mac); + if (curr_peer == NULL) { + mutex_unlock(&pHddCtx->tdls_lock); + QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR, + FL("curr_peer is NULL")); + *state = QCA_WIFI_HAL_TDLS_DISABLED; + *reason = eTDLS_LINK_UNSPECIFIED; + return -EINVAL; + } + if (pHddCtx->config->fTDLSExternalControl && + (false == curr_peer->isForcedPeer)) { + hdd_notice("curr_peer is not Forced"); + *state = QCA_WIFI_HAL_TDLS_DISABLED; + *reason = eTDLS_LINK_UNSPECIFIED; + } else { + wlan_hdd_tdls_determine_channel_opclass(pHddCtx, pAdapter, + curr_peer, channel, opclass); + wlan_hdd_tdls_get_wifi_hal_state(curr_peer, state, reason); + } + mutex_unlock(&pHddCtx->tdls_lock); + + return 0; +} + +#ifdef FEATURE_WLAN_TDLS +static const struct nla_policy + wlan_hdd_tdls_config_enable_policy[QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_MAX + + 1] = { + [QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_MAC_ADDR] = { + .type = NLA_UNSPEC, + .len = QDF_MAC_ADDR_SIZE}, + [QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_CHANNEL] = {.type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_GLOBAL_OPERATING_CLASS] = {.type = + NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_MAX_LATENCY_MS] = {.type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_MIN_BANDWIDTH_KBPS] = {.type = + NLA_U32}, +}; +static const struct nla_policy + wlan_hdd_tdls_config_disable_policy[QCA_WLAN_VENDOR_ATTR_TDLS_DISABLE_MAX + + 1] = { + [QCA_WLAN_VENDOR_ATTR_TDLS_DISABLE_MAC_ADDR] = { + .type = NLA_UNSPEC, + .len = QDF_MAC_ADDR_SIZE}, +}; +static const struct nla_policy + wlan_hdd_tdls_config_state_change_policy[QCA_WLAN_VENDOR_ATTR_TDLS_STATE_MAX + + 1] = { + [QCA_WLAN_VENDOR_ATTR_TDLS_STATE_MAC_ADDR] = { + .type = NLA_UNSPEC, + .len = QDF_MAC_ADDR_SIZE}, + [QCA_WLAN_VENDOR_ATTR_TDLS_NEW_STATE] = {.type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_TDLS_STATE_REASON] = {.type = NLA_S32}, + [QCA_WLAN_VENDOR_ATTR_TDLS_STATE_CHANNEL] = {.type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_TDLS_STATE_GLOBAL_OPERATING_CLASS] = {.type = + NLA_U32}, +}; +static const struct nla_policy + wlan_hdd_tdls_config_get_status_policy +[QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_MAC_ADDR] = { + .type = NLA_UNSPEC, + .len = QDF_MAC_ADDR_SIZE}, + [QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_STATE] = {.type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_REASON] = {.type = NLA_S32}, + [QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_CHANNEL] = {.type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_GLOBAL_OPERATING_CLASS] = { + .type = NLA_U32}, +}; + +static const struct nla_policy + wlan_hdd_tdls_mode_configuration_policy + [QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_TRIGGER_MODE] = { + .type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_TX_STATS_PERIOD] = { + .type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_TX_THRESHOLD] = { + .type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_DISCOVERY_PERIOD] = { + .type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_MAX_DISCOVERY_ATTEMPT] = { + .type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_IDLE_TIMEOUT] = { + .type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_IDLE_PACKET_THRESHOLD] = { + .type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_SETUP_RSSI_THRESHOLD] = { + .type = NLA_S32}, + [QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_TEARDOWN_RSSI_THRESHOLD] = { + .type = NLA_S32}, +}; + +/** + * __wlan_hdd_cfg80211_exttdls_get_status() - handle get status cfg80211 command + * @wiphy: wiphy + * @wdev: wireless dev + * @data: netlink buffer with the mac address of the peer to get the status for + * @data_len: length of data in bytes + */ +static int +__wlan_hdd_cfg80211_exttdls_get_status(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + uint8_t peer[ETH_ALEN] = { 0 }; + struct net_device *dev = wdev->netdev; + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *pHddCtx = wiphy_priv(wiphy); + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_MAX + 1]; + QDF_STATUS ret; + uint32_t state; + int32_t reason; + uint32_t global_operating_class = 0; + uint32_t channel = 0; + struct sk_buff *skb = NULL; + + ENTER_DEV(dev); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_warn("Command not allowed in FTM mode"); + return -EPERM; + } + + ret = wlan_hdd_validate_context(pHddCtx); + if (0 != ret) + return -EINVAL; + if (pHddCtx->config->fTDLSExternalControl == false) { + return -ENOTSUPP; + } + if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_MAX, + data, data_len, wlan_hdd_tdls_config_get_status_policy)) { + hdd_err("Invalid attribute"); + return -EINVAL; + } + if (!tb[QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_MAC_ADDR]) { + hdd_err("attr mac addr failed"); + return -EINVAL; + } + memcpy(peer, + nla_data(tb[QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_MAC_ADDR]), + sizeof(peer)); + hdd_notice(MAC_ADDRESS_STR, MAC_ADDR_ARRAY(peer)); + ret = wlan_hdd_tdls_get_status(pAdapter, peer, &global_operating_class, + &channel, &state, &reason); + if (0 != ret) { + hdd_err("get status Failed"); + return -EINVAL; + } + skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, + 4 * sizeof(int32_t) + + NLMSG_HDRLEN); + if (!skb) { + hdd_err("cfg80211_vendor_cmd_alloc_reply_skb failed"); + return -EINVAL; + } + hdd_notice("Reason %d Status %d class %d channel %d peer " MAC_ADDRESS_STR, + reason, state, global_operating_class, channel, + MAC_ADDR_ARRAY(peer)); + if (nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_STATE, + state) || + nla_put_s32(skb, + QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_REASON, + reason) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_GLOBAL_OPERATING_CLASS, + global_operating_class) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_CHANNEL, + channel)) { + hdd_err("nla put fail"); + goto nla_put_failure; + } + ret = cfg80211_vendor_cmd_reply(skb); + EXIT(); + return ret; +nla_put_failure: + kfree_skb(skb); + return -EINVAL; +} + +/** + * __wlan_hdd_cfg80211_configure_tdls_mode() - configure the tdls mode + * @wiphy: wiphy + * @wdev: wireless dev + * @data: netlink buffer + * @data_len: length of data in bytes + * + * Return 0 for success and error code for failure + */ +static int +__wlan_hdd_cfg80211_configure_tdls_mode(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + struct net_device *dev = wdev->netdev; + hdd_context_t *hdd_ctx = wiphy_priv(wiphy); + hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_MAX + 1]; + int ret; + eTDLSSupportMode tdls_mode; + uint32_t trigger_mode; + tdlsCtx_t *hdd_tdls_ctx; + + ENTER_DEV(dev); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_warn("Command not allowed in FTM mode"); + return -EPERM; + } + + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return -EINVAL; + + if (NULL == adapter) + return -EINVAL; + + if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_MAX, + data, data_len, + wlan_hdd_tdls_mode_configuration_policy)) { + hdd_err("Invalid attribute"); + return -EINVAL; + } + + if (!tb[QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_TRIGGER_MODE]) { + hdd_err("attr tdls trigger mode failed"); + return -EINVAL; + } + trigger_mode = nla_get_u32(tb[QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_TRIGGER_MODE]); + hdd_notice("TDLS trigger mode %d", trigger_mode); + + switch (trigger_mode) { + case WLAN_HDD_VENDOR_TDLS_TRIGGER_MODE_EXPLICIT: + tdls_mode = eTDLS_SUPPORT_EXPLICIT_TRIGGER_ONLY; + break; + case WLAN_HDD_VENDOR_TDLS_TRIGGER_MODE_EXTERNAL: + tdls_mode = eTDLS_SUPPORT_EXTERNAL_CONTROL; + break; + case WLAN_HDD_VENDOR_TDLS_TRIGGER_MODE_IMPLICIT: + tdls_mode = eTDLS_SUPPORT_ENABLED; + break; + default: + hdd_err("Invalid TDLS trigger mode"); + return -EINVAL; + } + wlan_hdd_tdls_set_mode(hdd_ctx, tdls_mode, false, + HDD_SET_TDLS_MODE_SOURCE_USER); + + mutex_lock(&hdd_ctx->tdls_lock); + + hdd_tdls_ctx = adapter->sessionCtx.station.pHddTdlsCtx; + if (NULL == hdd_tdls_ctx) { + mutex_unlock(&hdd_ctx->tdls_lock); + return -EINVAL; + } + + if (tb[QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_TX_STATS_PERIOD]) { + hdd_tdls_ctx->threshold_config.tx_period_t = nla_get_u32( + tb[QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_TX_STATS_PERIOD]); + hdd_info("attr tdls tx stats period %d", + hdd_tdls_ctx->threshold_config.tx_period_t); + } + + if (tb[QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_TX_THRESHOLD]) { + hdd_tdls_ctx->threshold_config.tx_packet_n = nla_get_u32( + tb[QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_TX_THRESHOLD]); + hdd_info("attr tdls tx packet period %d", + hdd_tdls_ctx->threshold_config.tx_packet_n); + } + + if (tb[QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_MAX_DISCOVERY_ATTEMPT]) { + hdd_tdls_ctx->threshold_config.discovery_tries_n = nla_get_u32( + tb[QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_MAX_DISCOVERY_ATTEMPT]); + hdd_info("attr tdls max discovery attempt %d", + hdd_tdls_ctx->threshold_config.discovery_tries_n); + } + + if (tb[QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_IDLE_TIMEOUT]) { + hdd_tdls_ctx->threshold_config.idle_timeout_t = nla_get_u32( + tb[QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_IDLE_TIMEOUT]); + hdd_info("attr tdls idle time out period %d", + hdd_tdls_ctx->threshold_config.idle_timeout_t); + } + + if (tb[QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_IDLE_PACKET_THRESHOLD]) { + hdd_tdls_ctx->threshold_config.idle_packet_n = nla_get_u32( + tb[QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_IDLE_PACKET_THRESHOLD]); + hdd_info("attr tdls idle pkt threshold %d", + hdd_tdls_ctx->threshold_config.idle_packet_n); + } + + if (tb[QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_SETUP_RSSI_THRESHOLD]) { + hdd_tdls_ctx->threshold_config.rssi_trigger_threshold = nla_get_s32( + tb[QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_SETUP_RSSI_THRESHOLD]); + hdd_info("attr tdls rssi trigger threshold %d", + hdd_tdls_ctx->threshold_config.rssi_trigger_threshold); + } + + if (tb[QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_TEARDOWN_RSSI_THRESHOLD]) { + hdd_tdls_ctx->threshold_config.rssi_teardown_threshold = nla_get_s32( + tb[QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_TEARDOWN_RSSI_THRESHOLD]); + hdd_info("attr tdls tx stats period %d", + hdd_tdls_ctx->threshold_config.rssi_teardown_threshold); + } + + mutex_unlock(&hdd_ctx->tdls_lock); + + EXIT(); + return ret; +} + +/** + * wlan_hdd_cfg80211_configure_tdls_mode() - configure tdls mode + * @wiphy: pointer to wireless wiphy structure. + * @wdev: pointer to wireless_dev structure. + * @data: Pointer to the data to be passed via vendor interface + * @data_len:Length of the data to be passed + * + * Return: Return the Success or Failure code. + */ +int wlan_hdd_cfg80211_configure_tdls_mode(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_configure_tdls_mode(wiphy, wdev, data, + data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * wlan_hdd_cfg80211_exttdls_get_status() - get ext tdls status + * @wiphy: pointer to wireless wiphy structure. + * @wdev: pointer to wireless_dev structure. + * @data: Pointer to the data to be passed via vendor interface + * @data_len:Length of the data to be passed + * + * Return: Return the Success or Failure code. + */ +int wlan_hdd_cfg80211_exttdls_get_status(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int ret = 0; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_exttdls_get_status(wiphy, wdev, data, + data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * wlan_hdd_cfg80211_exttdls_callback() - notify cfg80211 state change + * @mac: MAC address of the peer with state change + * @state: New state + * @reason: Reason to enter new state + * @ctx: HDD adapter + * + * Return: 0 for success; negative errno otherwise + */ +static int wlan_hdd_cfg80211_exttdls_callback(const uint8_t *mac, + uint32_t global_operating_class, + uint32_t channel, + uint32_t state, + int32_t reason, void *ctx) +{ + hdd_adapter_t *pAdapter = (hdd_adapter_t *) ctx; + hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + struct sk_buff *skb = NULL; + + ENTER(); + + if (wlan_hdd_validate_context(pHddCtx)) + return -EINVAL; + if (pHddCtx->config->fTDLSExternalControl == false) { + return -ENOTSUPP; + } + skb = cfg80211_vendor_event_alloc(pHddCtx->wiphy, + NULL, + EXTTDLS_EVENT_BUF_SIZE + NLMSG_HDRLEN, + QCA_NL80211_VENDOR_SUBCMD_TDLS_STATE_CHANGE_INDEX, + GFP_KERNEL); + if (!skb) { + hdd_err("cfg80211_vendor_event_alloc failed"); + return -EINVAL; + } + hdd_notice("Reason: %d Status: %d Class: %d Channel: %d tdls peer " MAC_ADDRESS_STR, + reason, state, global_operating_class, channel, + MAC_ADDR_ARRAY(mac)); + if (nla_put(skb, QCA_WLAN_VENDOR_ATTR_TDLS_STATE_MAC_ADDR, + QDF_MAC_ADDR_SIZE, mac) || + nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_TDLS_NEW_STATE, + state) || + nla_put_s32(skb, QCA_WLAN_VENDOR_ATTR_TDLS_STATE_REASON, + reason) || + nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_TDLS_STATE_CHANNEL, + channel) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_TDLS_STATE_GLOBAL_OPERATING_CLASS, + global_operating_class)) { + hdd_err("nla put fail"); + goto nla_put_failure; + } + cfg80211_vendor_event(skb, GFP_KERNEL); + EXIT(); + return 0; +nla_put_failure: + kfree_skb(skb); + return -EINVAL; +} + +/** + * __wlan_hdd_cfg80211_exttdls_enable() - enable an externally controllable + * TDLS peer and set parameters + * wiphy: wiphy + * @wdev: wireless dev pointer + * @data: netlink buffer with peer MAC address and configuration parameters + * @data_len: size of data in bytes + * + * This function sets channel, operation class, maximum latency and minimal + * bandwidth parameters on a TDLS peer that's externally controllable. + * + * Return: 0 for success; negative errno otherwise + */ +static int +__wlan_hdd_cfg80211_exttdls_enable(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + uint8_t peer[ETH_ALEN] = { 0 }; + struct net_device *dev = wdev->netdev; + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *pHddCtx = wiphy_priv(wiphy); + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_MAX + 1]; + QDF_STATUS status; + tdls_req_params_t pReqMsg = { 0 }; + int ret; + + ENTER_DEV(dev); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_warn("Command not allowed in FTM mode"); + return -EPERM; + } + + status = wlan_hdd_validate_context(pHddCtx); + if (0 != status) + return -EINVAL; + if (pHddCtx->config->fTDLSExternalControl == false) { + hdd_err("TDLS External Control is not enabled"); + return -ENOTSUPP; + } + if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_MAX, + data, data_len, wlan_hdd_tdls_config_enable_policy)) { + hdd_err("Invalid ATTR"); + return -EINVAL; + } + if (!tb[QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_MAC_ADDR]) { + hdd_err("attr mac addr failed"); + return -EINVAL; + } + memcpy(peer, nla_data(tb[QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_MAC_ADDR]), + sizeof(peer)); + hdd_notice(MAC_ADDRESS_STR, MAC_ADDR_ARRAY(peer)); + if (!tb[QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_CHANNEL]) { + hdd_err("attr channel failed"); + return -EINVAL; + } + pReqMsg.channel = + nla_get_s32(tb[QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_CHANNEL]); + hdd_notice("Channel Num (%d)", pReqMsg.channel); + if (!tb[QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_GLOBAL_OPERATING_CLASS]) { + hdd_err("attr operating class failed"); + return -EINVAL; + } + pReqMsg.global_operating_class = + nla_get_s32(tb + [QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_GLOBAL_OPERATING_CLASS]); + hdd_notice("Operating class (%d)", + pReqMsg.global_operating_class); + if (!tb[QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_MAX_LATENCY_MS]) { + hdd_err("attr latency failed"); + return -EINVAL; + } + pReqMsg.max_latency_ms = + nla_get_s32(tb[QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_MAX_LATENCY_MS]); + + hdd_notice("Latency (%d)", pReqMsg.max_latency_ms); + + if (!tb[QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_MIN_BANDWIDTH_KBPS]) { + hdd_err("attr bandwidth failed"); + return -EINVAL; + } + pReqMsg.min_bandwidth_kbps = + nla_get_s32(tb + [QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_MIN_BANDWIDTH_KBPS]); + + hdd_notice("Bandwidth (%d)", pReqMsg.min_bandwidth_kbps); + + ret = wlan_hdd_tdls_extctrl_config_peer( + pAdapter, + peer, + wlan_hdd_cfg80211_exttdls_callback, + pReqMsg.channel, + pReqMsg.max_latency_ms, + pReqMsg. + global_operating_class, + pReqMsg.min_bandwidth_kbps); + EXIT(); + return ret; +} + +/** + * wlan_hdd_cfg80211_exttdls_enable() - enable ext tdls + * @wiphy: pointer to wireless wiphy structure. + * @wdev: pointer to wireless_dev structure. + * @data: Pointer to the data to be passed via vendor interface + * @data_len:Length of the data to be passed + * + * Return: Return the Success or Failure code. + */ +int wlan_hdd_cfg80211_exttdls_enable(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int ret = 0; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_exttdls_enable(wiphy, wdev, data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __wlan_hdd_cfg80211_exttdls_disable() - disable an externally controllable + * TDLS peer + * wiphy: wiphy + * @wdev: wireless dev pointer + * @data: netlink buffer with peer MAC address + * @data_len: size of data in bytes + * + * This function disables an externally controllable TDLS peer + * + * Return: 0 for success; negative errno otherwise + */ +static int __wlan_hdd_cfg80211_exttdls_disable(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + u8 peer[ETH_ALEN] = {0}; + struct net_device *dev = wdev->netdev; + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *pHddCtx = wiphy_priv(wiphy); + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_TDLS_DISABLE_MAX + 1]; + QDF_STATUS status; + + ENTER_DEV(dev); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_warn("Command not allowed in FTM mode"); + return -EPERM; + } + + status = wlan_hdd_validate_context(pHddCtx); + if (0 != status) + return -EINVAL; + if (pHddCtx->config->fTDLSExternalControl == false) { + return -ENOTSUPP; + } + if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_TDLS_DISABLE_MAX, + data, data_len, wlan_hdd_tdls_config_disable_policy)) { + hdd_err("Invalid ATTR"); + return -EINVAL; + } + if (!tb[QCA_WLAN_VENDOR_ATTR_TDLS_DISABLE_MAC_ADDR]) { + hdd_err("attr mac addr failed"); + return -EINVAL; + } + memcpy(peer, nla_data(tb[QCA_WLAN_VENDOR_ATTR_TDLS_DISABLE_MAC_ADDR]), + sizeof(peer)); + hdd_notice(MAC_ADDRESS_STR, MAC_ADDR_ARRAY(peer)); + status = wlan_hdd_tdls_extctrl_deconfig_peer(pAdapter, peer); + EXIT(); + return status; +} + +/** + * wlan_hdd_cfg80211_exttdls_disable() - disable ext tdls + * @wiphy: pointer to wireless wiphy structure. + * @wdev: pointer to wireless_dev structure. + * @data: Pointer to the data to be passed via vendor interface + * @data_len:Length of the data to be passed + * + * Return: Return the Success or Failure code. + */ +int wlan_hdd_cfg80211_exttdls_disable(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int ret = 0; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_exttdls_disable(wiphy, wdev, data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * wlan_hdd_tdls_add_station() - add or change a TDLS peer station + * @wiphy: wiphy + * @dev: net device + * @mac: MAC address of the TDLS peer + * @update: if non-0, modify the peer with StaParams; if 0, add new peer + * @StaParams: station parameters for the TDLS to change + * + * Return: 0 if success; negative errno otherwise + */ +int wlan_hdd_tdls_add_station(struct wiphy *wiphy, + struct net_device *dev, const uint8_t *mac, + bool update, tCsrStaParams *StaParams) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *pHddCtx = wiphy_priv(wiphy); + QDF_STATUS status; + hddTdlsPeer_t *pTdlsPeer; + tTDLSLinkStatus link_status; + uint16_t numCurrTdlsPeers; + unsigned long rc; + int ret; + int rate_idx; + + ENTER(); + + ret = wlan_hdd_validate_context(pHddCtx); + if (ret) + return ret; + + if ((eTDLS_SUPPORT_NOT_ENABLED == pHddCtx->tdls_mode) || + (eTDLS_SUPPORT_DISABLED == pHddCtx->tdls_mode)) { + hdd_notice("TDLS mode is disabled OR not enabled in FW " MAC_ADDRESS_STR "Request declined.", + MAC_ADDR_ARRAY(mac)); + return -ENOTSUPP; + } + + mutex_lock(&pHddCtx->tdls_lock); + pTdlsPeer = wlan_hdd_tdls_get_peer(pAdapter, mac); + + if (NULL == pTdlsPeer) { + mutex_unlock(&pHddCtx->tdls_lock); + hdd_err(MAC_ADDRESS_STR " update %d not exist. return invalid", + MAC_ADDR_ARRAY(mac), update); + ret = -EINVAL; + goto ret_status; + } + + link_status = pTdlsPeer->link_status; + /* in add station, we accept existing valid staId if there is */ + if ((0 == update) && + ((pTdlsPeer->link_status >= eTDLS_LINK_CONNECTING) || + (TDLS_STA_INDEX_VALID(pTdlsPeer->staId)))) { + hdd_notice(MAC_ADDRESS_STR " link_status %d. staId %d. add station ignored.", + MAC_ADDR_ARRAY(mac), pTdlsPeer->link_status, + pTdlsPeer->staId); + ret = 0; + goto rel_lock; + } + /* in change station, we accept only when staId is valid */ + if ((1 == update) && + ((pTdlsPeer->link_status > eTDLS_LINK_CONNECTING) || + (!TDLS_STA_INDEX_VALID(pTdlsPeer->staId)))) { + hdd_err(MAC_ADDRESS_STR " link status %d. staId %d. change station %s.", + MAC_ADDR_ARRAY(mac), pTdlsPeer->link_status, + pTdlsPeer->staId, + (TDLS_STA_INDEX_VALID(pTdlsPeer->staId)) ? "ignored" : + "declined"); + ret = (TDLS_STA_INDEX_VALID(pTdlsPeer->staId)) ? 0 : -EPERM; + goto rel_lock; + } + + /* when others are on-going, we want to change link_status to idle */ + if (NULL != wlan_hdd_tdls_is_progress(pHddCtx, mac, true)) { + mutex_unlock(&pHddCtx->tdls_lock); + hdd_notice(MAC_ADDRESS_STR " TDLS setup is ongoing. Request declined.", + MAC_ADDR_ARRAY(mac)); + ret = -EPERM; + goto error; + } + + /* first to check if we reached to maximum supported TDLS peer. + TODO: for now, return -EPERM looks working fine, + but need to check if any other errno fit into this category. */ + numCurrTdlsPeers = wlan_hdd_tdls_connected_peers(pAdapter); + if (pHddCtx->max_num_tdls_sta <= numCurrTdlsPeers) { + QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR, + "%s: " MAC_ADDRESS_STR + " TDLS Max peer already connected. Request declined." + " Num of peers (%d), Max allowed (%d).", + __func__, MAC_ADDR_ARRAY(mac), numCurrTdlsPeers, + pHddCtx->max_num_tdls_sta); + mutex_unlock(&pHddCtx->tdls_lock); + ret = -EPERM; + goto error; + } else { + hddTdlsPeer_t *pTdlsPeer; + pTdlsPeer = wlan_hdd_tdls_find_peer(pAdapter, mac); + if (pTdlsPeer) { + link_status = pTdlsPeer->link_status; + if (TDLS_IS_CONNECTED(pTdlsPeer)) { + mutex_unlock(&pHddCtx->tdls_lock); + QDF_TRACE(QDF_MODULE_ID_HDD, + QDF_TRACE_LEVEL_ERROR, + "%s: " MAC_ADDRESS_STR + " already connected. " + "Request declined.", + __func__, MAC_ADDR_ARRAY(mac)); + ret = -EPERM; + goto ret_status; + } + } + } + if (0 == update) + wlan_hdd_tdls_set_link_status(pAdapter, + mac, + eTDLS_LINK_CONNECTING, + eTDLS_LINK_SUCCESS); + + /* debug code */ + if (NULL != StaParams) { + hdd_notice("TDLS Peer Parameters."); + if (StaParams->htcap_present) { + hdd_notice("ht_capa->cap_info: %0x", + StaParams->HTCap.capInfo); + hdd_notice("ht_capa->extended_capabilities: %0x", + StaParams->HTCap.extendedHtCapInfo); + } + hdd_notice("params->capability: %0x", StaParams->capability); + hdd_notice("params->ext_capab_len: %0x", + StaParams->extn_capability[0]); + if (StaParams->vhtcap_present) { + hdd_notice("rxMcsMap %x rxHighest %x txMcsMap %x txHighest %x", + StaParams->VHTCap.suppMcs.rxMcsMap, + StaParams->VHTCap.suppMcs.rxHighest, + StaParams->VHTCap.suppMcs.txMcsMap, + StaParams->VHTCap.suppMcs.txHighest); + } + hdd_notice("Supported rates:"); + for (rate_idx = 0; + rate_idx < sizeof(StaParams->supported_rates); + rate_idx++) + hdd_notice("rate_idx [%d]: supported_rates %x ", + rate_idx, + StaParams->supported_rates[rate_idx]); + } /* end debug code */ + else if ((1 == update) && (NULL == StaParams)) { + mutex_unlock(&pHddCtx->tdls_lock); + hdd_err("update is true, but staParams is NULL. Error!"); + ret = -EPERM; + goto ret_status; + } + + INIT_COMPLETION(pAdapter->tdls_add_station_comp); + + /* Update the number of stream for each peer */ + if ((NULL != StaParams) && (StaParams->htcap_present)) { + hddTdlsPeer_t *tdls_peer; + + tdls_peer = wlan_hdd_tdls_find_peer(pAdapter, mac); + if (NULL != tdls_peer) + tdls_peer->spatial_streams = + StaParams->HTCap.suppMcsSet[1]; + } + mutex_unlock(&pHddCtx->tdls_lock); + + if (!update) { + status = sme_add_tdls_peer_sta(WLAN_HDD_GET_HAL_CTX(pAdapter), + pAdapter->sessionId, mac); + } else { + status = sme_change_tdls_peer_sta(WLAN_HDD_GET_HAL_CTX(pAdapter), + pAdapter->sessionId, mac, + StaParams); + } + + rc = wait_for_completion_timeout(&pAdapter->tdls_add_station_comp, + msecs_to_jiffies + (WAIT_TIME_TDLS_ADD_STA)); + + if (!rc) { + hdd_err("timeout waiting for tdls add station indication %ld peer link status %u", + rc, link_status); + ret = -EPERM; + goto error; + } + + if (QDF_STATUS_SUCCESS != pAdapter->tdlsAddStaStatus) { + QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR, + "%s: Add Station is unsuccessful", __func__); + ret = -EPERM; + goto error; + } + + goto ret_status; + +error: + wlan_hdd_tdls_set_link_status(pAdapter, + mac, + eTDLS_LINK_IDLE, eTDLS_LINK_UNSPECIFIED); + goto ret_status; +rel_lock: + mutex_unlock(&pHddCtx->tdls_lock); +ret_status: + return ret; +} + +#if TDLS_MGMT_VERSION2 +/** + * __wlan_hdd_cfg80211_tdls_mgmt() - handle management actions on a given peer + * @wiphy: wiphy + * @dev: net device + * @peer: MAC address of the TDLS peer + * @action_code: action code + * @dialog_token: dialog token + * @status_code: status code + * @peer_capability: peer capability + * @buf: additional IE to include + * @len: length of buf in bytes + * + * Return: 0 if success; negative errno otherwise + */ +static int __wlan_hdd_cfg80211_tdls_mgmt(struct wiphy *wiphy, + struct net_device *dev, u8 *peer, + u8 action_code, u8 dialog_token, + u16 status_code, u32 peer_capability, + const u8 *buf, size_t len) +#else +/** + * __wlan_hdd_cfg80211_tdls_mgmt() - handle management actions on a given peer + * @wiphy: wiphy + * @dev: net device + * @peer: MAC address of the TDLS peer + * @action_code: action code + * @dialog_token: dialog token + * @status_code: status code + * @buf: additional IE to include + * @len: length of buf in bytes + * + * Return: 0 if success; negative errno otherwise + */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 17, 0)) +static int __wlan_hdd_cfg80211_tdls_mgmt(struct wiphy *wiphy, + struct net_device *dev, const uint8_t *peer, + uint8_t action_code, uint8_t dialog_token, + uint16_t status_code, uint32_t peer_capability, + bool initiator, const uint8_t *buf, + size_t len) +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)) +static int __wlan_hdd_cfg80211_tdls_mgmt(struct wiphy *wiphy, + struct net_device *dev, const uint8_t *peer, + uint8_t action_code, uint8_t dialog_token, + uint16_t status_code, uint32_t peer_capability, + const uint8_t *buf, size_t len) +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0)) +static int __wlan_hdd_cfg80211_tdls_mgmt(struct wiphy *wiphy, + struct net_device *dev, uint8_t *peer, + uint8_t action_code, uint8_t dialog_token, + uint16_t status_code, uint32_t peer_capability, + const uint8_t *buf, size_t len) +#else +static int __wlan_hdd_cfg80211_tdls_mgmt(struct wiphy *wiphy, + struct net_device *dev, uint8_t *peer, + uint8_t action_code, uint8_t dialog_token, + uint16_t status_code, const uint8_t *buf, + size_t len) +#endif +#endif +{ + + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *pHddCtx = wiphy_priv(wiphy); + hdd_station_ctx_t *hdd_sta_ctx; + tdlsCtx_t *hdd_tdls_ctx; + u8 peerMac[QDF_MAC_ADDR_SIZE]; + QDF_STATUS status; + int max_sta_failed = 0; + int responder; + unsigned long rc; + uint16_t numCurrTdlsPeers; +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 15, 0)) +#if !(TDLS_MGMT_VERSION2) + u32 peer_capability; + peer_capability = 0; +#endif +#endif + enum sir_wifi_traffic_ac ac = WIFI_AC_VI; + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_warn("Command not allowed in FTM mode"); + return -EINVAL; + } + + if (wlan_hdd_validate_session_id(pAdapter->sessionId)) { + hdd_err("invalid session id: %d", pAdapter->sessionId); + return -EINVAL; + } + + MTRACE(qdf_trace(QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_CFG80211_TDLS_MGMT, + pAdapter->sessionId, action_code)); + + if (wlan_hdd_validate_context(pHddCtx)) + return -EINVAL; + + if (eTDLS_SUPPORT_NOT_ENABLED == pHddCtx->tdls_mode) { + hdd_notice("TDLS mode is disabled OR not enabled in FW." MAC_ADDRESS_STR " action %d declined.", + MAC_ADDR_ARRAY(peer), action_code); + return -ENOTSUPP; + } + + hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + + /* + * STA or P2P client should be connected and authenticated before + * sending any TDLS frames + */ + if ((eConnectionState_Associated != + hdd_sta_ctx->conn_info.connState) || + (false == hdd_sta_ctx->conn_info.uIsAuthenticated)) { + hdd_err("STA is not connected or not authenticated. connState %u, uIsAuthenticated %u", + hdd_sta_ctx->conn_info.connState, + hdd_sta_ctx->conn_info.uIsAuthenticated); + return -EAGAIN; + } + + /* other than teardown frame, mgmt frames are not sent if disabled */ + if (SIR_MAC_TDLS_TEARDOWN != action_code) { + if (!cds_check_is_tdls_allowed(pAdapter->device_mode)) { + hdd_err("TDLS not allowed, reject TDLS MGMT, action_code=%d", + action_code); + return -EPERM; + } + /* if tdls_mode is disabled, then decline the peer's request */ + if (eTDLS_SUPPORT_DISABLED == pHddCtx->tdls_mode) { + hdd_notice(MAC_ADDRESS_STR " TDLS mode is disabled. action %d declined.", + MAC_ADDR_ARRAY(peer), action_code); + return -ENOTSUPP; + } + if (pHddCtx->tdls_nss_switch_in_progress) { + hdd_err("TDLS antenna switch in progress, action %d declined for " + MAC_ADDRESS_STR, action_code, MAC_ADDR_ARRAY(peer)); + return -EAGAIN; + } + } + + if (WLAN_IS_TDLS_SETUP_ACTION(action_code)) { + mutex_lock(&pHddCtx->tdls_lock); + if (NULL != wlan_hdd_tdls_is_progress(pHddCtx, peer, true)) { + mutex_unlock(&pHddCtx->tdls_lock); + QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR, + "%s: " MAC_ADDRESS_STR + " TDLS setup is ongoing. action %d declined.", + __func__, MAC_ADDR_ARRAY(peer), action_code); + return -EPERM; + } + mutex_unlock(&pHddCtx->tdls_lock); + } + + if ((hdd_wmm_is_active(pAdapter)) && + !(pAdapter->hddWmmStatus.wmmAcStatus[OL_TX_WMM_AC_VI].wmmAcAccessAllowed)) { + QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_DEBUG, + "%s: Admission control is set to VI, send the frame with least AC (BK) for action %d.", + __func__, action_code); + ac = WIFI_AC_BK; + } + + if (SIR_MAC_TDLS_SETUP_REQ == action_code || + SIR_MAC_TDLS_SETUP_RSP == action_code) { + numCurrTdlsPeers = wlan_hdd_tdls_connected_peers(pAdapter); + if (pHddCtx->max_num_tdls_sta <= numCurrTdlsPeers) { + /* supplicant still sends tdls_mgmt(SETUP_REQ) even after + we return error code at 'add_station()'. Hence we have this + check again in addtion to add_station(). + Anyway, there is no hard to double-check. */ + if (SIR_MAC_TDLS_SETUP_REQ == action_code) { + QDF_TRACE(QDF_MODULE_ID_HDD, + QDF_TRACE_LEVEL_ERROR, + "%s: " MAC_ADDRESS_STR + " TDLS Max peer already connected. action (%d) declined. Num of peers (%d), Max allowed (%d).", + __func__, MAC_ADDR_ARRAY(peer), + action_code, numCurrTdlsPeers, + pHddCtx->max_num_tdls_sta); + return -EINVAL; + } else { + /* maximum reached. tweak to send error code to peer and return + error code to supplicant */ + status_code = eSIR_MAC_UNSPEC_FAILURE_STATUS; + QDF_TRACE(QDF_MODULE_ID_HDD, + QDF_TRACE_LEVEL_ERROR, + "%s: " MAC_ADDRESS_STR + " TDLS Max peer already connected, send response status (%d). Num of peers (%d), Max allowed (%d).", + __func__, MAC_ADDR_ARRAY(peer), + status_code, numCurrTdlsPeers, + pHddCtx->max_num_tdls_sta); + max_sta_failed = -EPERM; + /* fall through to send setup resp with failure status + code */ + } + } else { + hddTdlsPeer_t *pTdlsPeer; + mutex_lock(&pHddCtx->tdls_lock); + pTdlsPeer = + wlan_hdd_tdls_find_peer(pAdapter, peer); + if (pTdlsPeer) { + if (TDLS_IS_CONNECTED(pTdlsPeer)) { + mutex_unlock(&pHddCtx->tdls_lock); + QDF_TRACE(QDF_MODULE_ID_HDD, + QDF_TRACE_LEVEL_ERROR, + "%s:" MAC_ADDRESS_STR + " already connected." + " action %d declined.", + __func__, + MAC_ADDR_ARRAY(peer), + action_code); + return -EPERM; + } + } + mutex_unlock(&pHddCtx->tdls_lock); + } + } + qdf_mem_copy(peerMac, peer, 6); + + hdd_notice("tdls_mgmt" MAC_ADDRESS_STR " action %d, dialog_token %d status %d, len = %zu", + MAC_ADDR_ARRAY(peer), action_code, dialog_token, + status_code, len); + + /*Except teardown responder will not be used so just make 0 */ + responder = 0; + if (SIR_MAC_TDLS_TEARDOWN == action_code) { + + hddTdlsPeer_t *pTdlsPeer; + mutex_lock(&pHddCtx->tdls_lock); + pTdlsPeer = wlan_hdd_tdls_find_peer(pAdapter, peerMac); + if (!pTdlsPeer) { + mutex_unlock(&pHddCtx->tdls_lock); + QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR, + "%s: " MAC_ADDRESS_STR " peer doesn't exist", + __func__, MAC_ADDR_ARRAY(peer)); + return -EPERM; + } + + if (TDLS_IS_CONNECTED(pTdlsPeer)) + responder = pTdlsPeer->is_responder; + else { + QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR, + "%s: " MAC_ADDRESS_STR + " peer doesn't exist or not connected %d " + "dialog_token %d status %d, len = %zu", + __func__, MAC_ADDR_ARRAY(peer), + pTdlsPeer->link_status, + dialog_token, status_code, len); + mutex_unlock(&pHddCtx->tdls_lock); + return -EPERM; + } + mutex_unlock(&pHddCtx->tdls_lock); + } + + /* For explicit trigger of DIS_REQ come out of BMPS for + successfully receiving DIS_RSP from peer. */ + if ((SIR_MAC_TDLS_SETUP_RSP == action_code) || + (SIR_MAC_TDLS_SETUP_CNF == action_code) || + (SIR_MAC_TDLS_DIS_RSP == action_code) || + (SIR_MAC_TDLS_DIS_REQ == action_code)) { + /* Fw will take care if PS offload is enabled. */ + if (SIR_MAC_TDLS_DIS_REQ != action_code) + wlan_hdd_tdls_set_cap(pAdapter, peerMac, + eTDLS_CAP_SUPPORTED); + } + + /* make sure doesn't call send_mgmt() while it is pending */ + if (TDLS_CTX_MAGIC == pAdapter->mgmtTxCompletionStatus) { + QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR, + "%s: " MAC_ADDRESS_STR + " action %d couldn't sent, as one is pending. return EBUSY", + __func__, MAC_ADDR_ARRAY(peer), action_code); + return -EBUSY; + } + + pAdapter->mgmtTxCompletionStatus = TDLS_CTX_MAGIC; + INIT_COMPLETION(pAdapter->tdls_mgmt_comp); + + status = sme_send_tdls_mgmt_frame(WLAN_HDD_GET_HAL_CTX(pAdapter), + pAdapter->sessionId, peerMac, + action_code, dialog_token, + status_code, peer_capability, + (uint8_t *) buf, len, + !responder, + ac); + + if (QDF_STATUS_SUCCESS != status) { + QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR, + "%s: sme_send_tdls_mgmt_frame failed!", __func__); + pAdapter->mgmtTxCompletionStatus = false; + return -EINVAL; + } + + if (SIR_MAC_TDLS_TEARDOWN == action_code && + pHddCtx->tdls_nss_switch_in_progress) { + mutex_lock(&pHddCtx->tdls_lock); + if (pHddCtx->tdls_teardown_peers_cnt != 0) + pHddCtx->tdls_teardown_peers_cnt--; + if (pHddCtx->tdls_teardown_peers_cnt == 0) { + if (pHddCtx->tdls_nss_transition_mode == + TDLS_NSS_TRANSITION_1x1_to_2x2) { + /* TDLS NSS switch is fully completed, so + * reset the flags. + */ + hdd_info("TDLS NSS switch is fully completed"); + pHddCtx->tdls_nss_switch_in_progress = false; + pHddCtx->tdls_nss_teardown_complete = false; + } else { + /* TDLS NSS switch is not yet completed, but + * tdls teardown is completed for all the + * peers. + */ + hdd_info("TDLS teardown is completed and NSS switch still in progress"); + pHddCtx->tdls_nss_teardown_complete = true; + } + } + mutex_unlock(&pHddCtx->tdls_lock); + } + hdd_info("Wait for tdls_mgmt_comp. Timeout %u ms", + WAIT_TIME_TDLS_MGMT); + + rc = wait_for_completion_timeout(&pAdapter->tdls_mgmt_comp, + msecs_to_jiffies(WAIT_TIME_TDLS_MGMT)); + + if ((0 == rc) || (true != pAdapter->mgmtTxCompletionStatus)) { + hdd_err("%s rc %ld mgmtTxCompletionStatus %u", + !rc ? "Mgmt Tx Completion timed out" : "Mgmt Tx Completion failed", + rc, pAdapter->mgmtTxCompletionStatus); + + if (cds_is_driver_recovering()) { + hdd_warn("Recovery in Progress. State: 0x%x Ignore!!!", + cds_get_driver_state()); + return -EAGAIN; + } + + if (cds_is_driver_unloading()) { + hdd_warn("Unload in progress. State: 0x%x Ignore!!!", + cds_get_driver_state()); + return -EAGAIN; + } + + mutex_lock(&pHddCtx->tdls_lock); + hdd_tdls_ctx = WLAN_HDD_GET_TDLS_CTX_PTR(pAdapter); + if (hdd_tdls_ctx) { + if (rc <= 0 && + (((qdf_get_monotonic_boottime() - + hdd_tdls_ctx->last_flush_ts) > + TDLS_ENABLE_CDS_FLUSH_INTERVAL) + || !(hdd_tdls_ctx->last_flush_ts))) { + hdd_tdls_ctx->last_flush_ts = + qdf_get_monotonic_boottime(); + mutex_unlock(&pHddCtx->tdls_lock); + cds_flush_logs(WLAN_LOG_TYPE_FATAL, + WLAN_LOG_INDICATOR_HOST_DRIVER, + WLAN_LOG_REASON_HDD_TIME_OUT, + true, false); + } else + mutex_unlock(&pHddCtx->tdls_lock); + } else + mutex_unlock(&pHddCtx->tdls_lock); + + pAdapter->mgmtTxCompletionStatus = false; + return -EINVAL; + } + hdd_info("Mgmt Tx Completion status %ld TxCompletion %u", + rc, pAdapter->mgmtTxCompletionStatus); + + if (max_sta_failed) { + return max_sta_failed; + } + + if (SIR_MAC_TDLS_SETUP_RSP == action_code) { + return wlan_hdd_tdls_set_responder(pAdapter, peerMac, false); + } else if (SIR_MAC_TDLS_SETUP_CNF == action_code) { + return wlan_hdd_tdls_set_responder(pAdapter, peerMac, true); + } + + return 0; +} + +/** + * wlan_hdd_cfg80211_tdls_mgmt() - cfg80211 tdls mgmt handler function + * @wiphy: Pointer to wiphy structure. + * @dev: Pointer to net_device structure. + * @peer: peer address + * @action_code: action code + * @dialog_token: dialog token + * @status_code: status code + * @peer_capability: peer capability + * @buf: buffer + * @len: Length of @buf + * + * This is the cfg80211 tdls mgmt handler function which invokes + * the internal function @__wlan_hdd_cfg80211_tdls_mgmt with + * SSR protection. + * + * Return: 0 for success, error number on failure. + */ +#if TDLS_MGMT_VERSION2 +int wlan_hdd_cfg80211_tdls_mgmt(struct wiphy *wiphy, + struct net_device *dev, + u8 *peer, u8 action_code, + u8 dialog_token, + u16 status_code, u32 peer_capability, + const u8 *buf, size_t len) +#else /* TDLS_MGMT_VERSION2 */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 17, 0)) || defined(WITH_BACKPORTS) +int wlan_hdd_cfg80211_tdls_mgmt(struct wiphy *wiphy, + struct net_device *dev, + const u8 *peer, u8 action_code, + u8 dialog_token, u16 status_code, + u32 peer_capability, bool initiator, + const u8 *buf, size_t len) +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)) +int wlan_hdd_cfg80211_tdls_mgmt(struct wiphy *wiphy, + struct net_device *dev, + const u8 *peer, u8 action_code, + u8 dialog_token, u16 status_code, + u32 peer_capability, const u8 *buf, + size_t len) +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0)) +int wlan_hdd_cfg80211_tdls_mgmt(struct wiphy *wiphy, + struct net_device *dev, + u8 *peer, u8 action_code, + u8 dialog_token, + u16 status_code, u32 peer_capability, + const u8 *buf, size_t len) +#else +int wlan_hdd_cfg80211_tdls_mgmt(struct wiphy *wiphy, + struct net_device *dev, + u8 *peer, u8 action_code, + u8 dialog_token, + u16 status_code, const u8 *buf, + size_t len) +#endif +#endif +{ + int ret; + + cds_ssr_protect(__func__); +#if TDLS_MGMT_VERSION2 + ret = __wlan_hdd_cfg80211_tdls_mgmt(wiphy, dev, peer, action_code, + dialog_token, status_code, + peer_capability, buf, len); +#else /* TDLS_MGMT_VERSION2 */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 17, 0)) || defined(WITH_BACKPORTS) + ret = __wlan_hdd_cfg80211_tdls_mgmt(wiphy, dev, peer, action_code, + dialog_token, status_code, + peer_capability, initiator, + buf, len); +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)) + ret = __wlan_hdd_cfg80211_tdls_mgmt(wiphy, dev, peer, action_code, + dialog_token, status_code, + peer_capability, buf, len); +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0)) + ret = __wlan_hdd_cfg80211_tdls_mgmt(wiphy, dev, peer, action_code, + dialog_token, status_code, + peer_capability, buf, len); +#else + ret = __wlan_hdd_cfg80211_tdls_mgmt(wiphy, dev, peer, action_code, + dialog_token, status_code, buf, len); +#endif +#endif + + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * wlan_hdd_tdls_extctrl_config_peer() - configure an externally controllable + * TDLS peer + * @pAdapter: HDD adapter + * @peer: MAC address of the TDLS peer + * @callback: Callback to set on the peer + * @chan: Channel + * @max_latency: Maximum latency + * @op_class: Operation class + * @min_bandwidth: Minimal bandwidth + * + * Return: 0 on success; negative otherwise + */ +int wlan_hdd_tdls_extctrl_config_peer(hdd_adapter_t *pAdapter, + const uint8_t *peer, + cfg80211_exttdls_callback callback, + u32 chan, + u32 max_latency, + u32 op_class, u32 min_bandwidth) +{ + hddTdlsPeer_t *pTdlsPeer; + hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + int status = 0; + QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO, + "%s : NL80211_TDLS_SETUP for " MAC_ADDRESS_STR, + __func__, MAC_ADDR_ARRAY(peer)); + if ((false == pHddCtx->config->fTDLSExternalControl) || + (false == pHddCtx->config->fEnableTDLSImplicitTrigger)) { + QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO, + "%s TDLS External control or Implicit Trigger not enabled ", + __func__); + status = -ENOTSUPP; + goto ret_status; + } + + mutex_lock(&pHddCtx->tdls_lock); + pTdlsPeer = wlan_hdd_tdls_get_peer(pAdapter, peer); + if (pTdlsPeer == NULL) { + QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR, + "%s: peer " MAC_ADDRESS_STR " does not exist", + __func__, MAC_ADDR_ARRAY(peer)); + status = -EINVAL; + goto rel_lock; + } + mutex_unlock(&pHddCtx->tdls_lock); + + if (0 != wlan_hdd_tdls_set_force_peer(pAdapter, peer, true)) { + QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR, + "%s TDLS Add Force Peer Failed", __func__); + status = -EINVAL; + goto ret_status; + } + /* Update the peer mac to firmware, so firmware + * could update the connection table + */ + if (0 != wlan_hdd_tdls_update_peer_mac(pAdapter, peer, + eSME_TDLS_PEER_ADD_MAC_ADDR)) { + hdd_err("TDLS Peer mac update Failed " MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(peer)); + status = -EINVAL; + goto ret_status; + } + + pHddCtx->tdls_external_peer_count++; + + /* validate if off channel is DFS channel */ + if (CDS_IS_DFS_CH(chan)) { + hdd_err("Resetting TDLS off-channel from %d to %d", + chan, CFG_TDLS_PREFERRED_OFF_CHANNEL_NUM_DEFAULT); + chan = CFG_TDLS_PREFERRED_OFF_CHANNEL_NUM_DEFAULT; + } + + if (0 != wlan_hdd_tdls_set_extctrl_param(pAdapter, peer, + chan, max_latency, + op_class, min_bandwidth)) { + QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR, + "%s TDLS Set Peer's External Ctrl Parameter Failed", + __func__); + status = -EINVAL; + goto ret_status; + } + + mutex_lock(&pHddCtx->tdls_lock); + pTdlsPeer = wlan_hdd_tdls_get_peer(pAdapter, peer); + if (pTdlsPeer == NULL) { + QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR, + "%s: peer " MAC_ADDRESS_STR " does not exist", + __func__, MAC_ADDR_ARRAY(peer)); + status = -EINVAL; + goto rel_lock; + } + if (0 != wlan_hdd_set_callback(pTdlsPeer, callback)) { + QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR, + "%s TDLS set callback Failed", __func__); + status = -EINVAL; + goto rel_lock; + } + + mutex_unlock(&pHddCtx->tdls_lock); + + /* set tdls connection tracker state */ + cds_set_tdls_ct_mode(pHddCtx); + + return status; +rel_lock: + mutex_unlock(&pHddCtx->tdls_lock); +ret_status: + return status; +} + +/** + * wlan_hdd_tdls_extctrl_deconfig_peer() - de-configure an externally + * controllable TDLS peer + * @pAdapter: HDD adapter + * @peer: MAC address of the tdls peer + * + * Return: 0 if success; negative errno otherwisw + */ +int wlan_hdd_tdls_extctrl_deconfig_peer(hdd_adapter_t *pAdapter, + const uint8_t *peer) +{ + hddTdlsPeer_t *pTdlsPeer; + hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + int status = 0; + QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO, + "%s : NL80211_TDLS_TEARDOWN for " MAC_ADDRESS_STR, + __func__, MAC_ADDR_ARRAY(peer)); + if ((false == pHddCtx->config->fTDLSExternalControl) || + (false == pHddCtx->config->fEnableTDLSImplicitTrigger)) { + QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO, + "%s TDLS External control or Implicit Trigger not enabled ", + __func__); + status = -ENOTSUPP; + goto ret_status; + } + + mutex_lock(&pHddCtx->tdls_lock); + pTdlsPeer = wlan_hdd_tdls_find_peer(pAdapter, peer); + if (NULL == pTdlsPeer) { + hdd_notice("peer matching" MAC_ADDRESS_STR "not found", + MAC_ADDR_ARRAY(peer)); + status = -EINVAL; + goto rel_lock; + } else { + wlan_hdd_tdls_indicate_teardown(pAdapter, pTdlsPeer, + eSIR_MAC_TDLS_TEARDOWN_UNSPEC_REASON); + hdd_send_wlan_tdls_teardown_event( + eTDLS_TEARDOWN_EXT_CTRL, + pTdlsPeer->peerMac); + } + mutex_unlock(&pHddCtx->tdls_lock); + + if (0 != wlan_hdd_tdls_set_force_peer(pAdapter, peer, false)) { + QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR, + "%s Failed", __func__); + status = -EINVAL; + goto ret_status; + } + + if (pHddCtx->tdls_external_peer_count) + pHddCtx->tdls_external_peer_count--; + + mutex_lock(&pHddCtx->tdls_lock); + pTdlsPeer = wlan_hdd_tdls_find_peer(pAdapter, peer); + if (NULL == pTdlsPeer) { + hdd_notice("peer matching" MAC_ADDRESS_STR "not found", + MAC_ADDR_ARRAY(peer)); + status = -EINVAL; + goto rel_lock; + } + if (0 != wlan_hdd_set_callback(pTdlsPeer, NULL)) { + QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR, + "%s TDLS set callback Failed", __func__); + status = -EINVAL; + goto rel_lock; + } + + mutex_unlock(&pHddCtx->tdls_lock); + + /* Update the peer mac to firmware, so firmware + * could update the connection table + */ + if (0 != wlan_hdd_tdls_update_peer_mac(pAdapter, peer, + eSME_TDLS_PEER_REMOVE_MAC_ADDR)) { + hdd_err("TDLS Peer mac update Failed " MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(peer)); + status = -EINVAL; + goto ret_status; + } + + /* set tdls connection tracker state */ + cds_set_tdls_ct_mode(pHddCtx); + goto ret_status; + +rel_lock: + mutex_unlock(&pHddCtx->tdls_lock); +ret_status: + return status; +} + +/** + * __wlan_hdd_cfg80211_tdls_oper() - helper function to handle cfg80211 operation + * on an TDLS peer + * @wiphy: wiphy + * @dev: net device + * @peer: MAC address of the TDLS peer + * @oper: cfg80211 TDLS operation + * + * Return: 0 on success; negative errno otherwise + */ +static int __wlan_hdd_cfg80211_tdls_oper(struct wiphy *wiphy, + struct net_device *dev, + const uint8_t *peer, + enum nl80211_tdls_operation oper) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *pHddCtx = wiphy_priv(wiphy); + int status; + tSmeTdlsPeerStateParams smeTdlsPeerStateParams; + QDF_STATUS qdf_ret_status = QDF_STATUS_E_FAILURE; + hddTdlsPeer_t *pTdlsPeer; + tTDLSLinkStatus peer_status = eTDLS_LINK_IDLE; + uint16_t peer_staid; + uint8_t peer_offchannelsupp; + + ENTER(); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_warn("Command not allowed in FTM mode"); + return -EINVAL; + } + + if (wlan_hdd_validate_session_id(pAdapter->sessionId)) { + hdd_err("invalid session id: %d", pAdapter->sessionId); + return -EINVAL; + } + + MTRACE(qdf_trace(QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_CFG80211_TDLS_OPER, + pAdapter->sessionId, oper)); + if (NULL == peer) { + QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid arguments", __func__); + return -EINVAL; + } + + status = wlan_hdd_validate_context(pHddCtx); + + if (0 != status) + return status; + + /* QCA 2.0 Discrete ANDs feature capability in HDD config with that + * received from target, so HDD config gives combined intersected result + */ + if (false == pHddCtx->config->fEnableTDLSSupport) { + QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR, + "TDLS Disabled in INI OR not enabled in FW. " + "Cannot process TDLS commands"); + return -ENOTSUPP; + } + + switch (oper) { + case NL80211_TDLS_ENABLE_LINK: + { + QDF_STATUS status; + unsigned long rc; + tCsrTdlsLinkEstablishParams tdlsLinkEstablishParams = { {0}, 0, + 0, 0, 0, 0, 0, {0}, 0, {0} }; + + mutex_lock(&pHddCtx->tdls_lock); + pTdlsPeer = + wlan_hdd_tdls_find_peer(pAdapter, peer); + + if (NULL == pTdlsPeer) { + mutex_unlock(&pHddCtx->tdls_lock); + QDF_TRACE(QDF_MODULE_ID_HDD, + QDF_TRACE_LEVEL_ERROR, + "%s: peer matching " MAC_ADDRESS_STR + " not found, ignore NL80211_TDLS_ENABLE_LINK", + __func__, MAC_ADDR_ARRAY(peer)); + return -EINVAL; + } + + QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR, + "%s: NL80211_TDLS_ENABLE_LINK for peer " + MAC_ADDRESS_STR " link_status: %d", + __func__, MAC_ADDR_ARRAY(peer), + pTdlsPeer->link_status); + + if (!TDLS_STA_INDEX_VALID(pTdlsPeer->staId)) { + QDF_TRACE(QDF_MODULE_ID_HDD, + QDF_TRACE_LEVEL_ERROR, + "%s: invalid sta index %u for " + MAC_ADDRESS_STR + " TDLS_ENABLE_LINK failed", __func__, + pTdlsPeer->staId, + MAC_ADDR_ARRAY(peer)); + mutex_unlock(&pHddCtx->tdls_lock); + return -EINVAL; + } + peer_status = pTdlsPeer->link_status; + peer_offchannelsupp = pTdlsPeer->isOffChannelSupported; + mutex_unlock(&pHddCtx->tdls_lock); + + wlan_hdd_tdls_set_cap(pAdapter, peer, eTDLS_CAP_SUPPORTED); + + qdf_mem_set(&tdlsLinkEstablishParams, + sizeof(tdlsLinkEstablishParams), 0); + + if (eTDLS_LINK_CONNECTED != peer_status) { + if (IS_ADVANCE_TDLS_ENABLE) { + + hdd_info("Advance TDLS is enabled"); + if (0 != + wlan_hdd_tdls_get_link_establish_params + (pAdapter, peer, + &tdlsLinkEstablishParams)) { + return -EINVAL; + } + INIT_COMPLETION(pAdapter-> + tdls_link_establish_req_comp); + + sme_send_tdls_link_establish_params + (WLAN_HDD_GET_HAL_CTX(pAdapter), + pAdapter->sessionId, peer, + &tdlsLinkEstablishParams); + /* Send TDLS peer UAPSD capabilities to the firmware and + * register with the TL on after the response for this operation + * is received . + */ + rc = wait_for_completion_timeout + (&pAdapter-> + tdls_link_establish_req_comp, + msecs_to_jiffies + (WAIT_TIME_TDLS_LINK_ESTABLISH_REQ)); + if (!rc) { + QDF_TRACE(QDF_MODULE_ID_HDD, + QDF_TRACE_LEVEL_ERROR, + "%s: Link Establish Request timed out", + __func__); + return -EINVAL; + } + } + + mutex_lock(&pHddCtx->tdls_lock); + pTdlsPeer = + wlan_hdd_tdls_find_peer(pAdapter, peer); + + if (NULL == pTdlsPeer) { + mutex_unlock(&pHddCtx->tdls_lock); + QDF_TRACE(QDF_MODULE_ID_HDD, + QDF_TRACE_LEVEL_ERROR, + "%s: peer matching " MAC_ADDRESS_STR + " (oper %d) peer got freed in other" + "context. ignored", + __func__, MAC_ADDR_ARRAY(peer), + (int)oper); + return -EINVAL; + } + + wlan_hdd_tdls_set_peer_link_status(pTdlsPeer, + eTDLS_LINK_CONNECTED, + eTDLS_LINK_SUCCESS); + peer_staid = pTdlsPeer->staId; + + hdd_notice("%s: tdlsLinkEstablishParams of peer " + MAC_ADDRESS_STR "uapsdQueues: %d" + " qos: %d maxSp: %d isBufSta: %d" + " isOffChannelSupported: %d" + " isResponder: %d peerstaId: %d", + __func__, + MAC_ADDR_ARRAY( + tdlsLinkEstablishParams.peerMac), + tdlsLinkEstablishParams.uapsdQueues, + tdlsLinkEstablishParams.qos, + tdlsLinkEstablishParams.maxSp, + tdlsLinkEstablishParams.isBufSta, + tdlsLinkEstablishParams.isOffChannelSupported, + tdlsLinkEstablishParams.isResponder, + pTdlsPeer->staId); + /* start TDLS client registration with TL */ + status = + hdd_roam_register_tdlssta( + pAdapter, peer, + pTdlsPeer->staId, + pTdlsPeer->signature, + pTdlsPeer->qos); + if (QDF_STATUS_SUCCESS == status) { + uint8_t i; + + qdf_mem_zero(&smeTdlsPeerStateParams, + sizeof + (tSmeTdlsPeerStateParams)); + + smeTdlsPeerStateParams.vdevId = + pAdapter->sessionId; + qdf_mem_copy(&smeTdlsPeerStateParams. + peerMacAddr, + &pTdlsPeer->peerMac, + sizeof(tSirMacAddr)); + smeTdlsPeerStateParams.peerState = + eSME_TDLS_PEER_STATE_CONNECTED; + smeTdlsPeerStateParams.peerCap. + isPeerResponder = + pTdlsPeer->is_responder; + smeTdlsPeerStateParams.peerCap. + peerUapsdQueue = + pTdlsPeer->uapsdQueues; + smeTdlsPeerStateParams.peerCap. + peerMaxSp = pTdlsPeer->maxSp; + smeTdlsPeerStateParams.peerCap. + peerBuffStaSupport = + pTdlsPeer->isBufSta; + smeTdlsPeerStateParams.peerCap. + peerOffChanSupport = + pTdlsPeer->isOffChannelSupported; + smeTdlsPeerStateParams.peerCap. + peerCurrOperClass = 0; + smeTdlsPeerStateParams.peerCap. + selfCurrOperClass = 0; + smeTdlsPeerStateParams.peerCap. + peerChanLen = + pTdlsPeer->supported_channels_len; + smeTdlsPeerStateParams.peerCap. + prefOffChanNum = + pTdlsPeer->pref_off_chan_num; + smeTdlsPeerStateParams.peerCap. + prefOffChanBandwidth = + pHddCtx->config-> + fTDLSPrefOffChanBandwidth; + smeTdlsPeerStateParams.peerCap. + opClassForPrefOffChan = + pTdlsPeer-> + op_class_for_pref_off_chan; + + if (CDS_IS_DFS_CH(smeTdlsPeerStateParams. + peerCap.prefOffChanNum)) { + hdd_err("Resetting TDLS off-channel from %d to %d", + smeTdlsPeerStateParams.peerCap. + prefOffChanNum, + CFG_TDLS_PREFERRED_OFF_CHANNEL_NUM_DEFAULT); + smeTdlsPeerStateParams.peerCap.prefOffChanNum = + CFG_TDLS_PREFERRED_OFF_CHANNEL_NUM_DEFAULT; + } + + QDF_TRACE(QDF_MODULE_ID_HDD, + QDF_TRACE_LEVEL_INFO, + "%s: Peer " MAC_ADDRESS_STR + "vdevId: %d, peerState: %d, isPeerResponder: %d, uapsdQueues: 0x%x, maxSp: 0x%x, peerBuffStaSupport: %d, peerOffChanSupport: %d, peerCurrOperClass: %d, selfCurrOperClass: %d, peerChanLen: %d, peerOperClassLen: %d, prefOffChanNum: %d, prefOffChanBandwidth: %d, op_class_for_pref_off_chan: %d", + __func__, + MAC_ADDR_ARRAY(peer), + smeTdlsPeerStateParams.vdevId, + smeTdlsPeerStateParams. + peerState, + smeTdlsPeerStateParams. + peerCap.isPeerResponder, + smeTdlsPeerStateParams. + peerCap.peerUapsdQueue, + smeTdlsPeerStateParams. + peerCap.peerMaxSp, + smeTdlsPeerStateParams. + peerCap.peerBuffStaSupport, + smeTdlsPeerStateParams. + peerCap.peerOffChanSupport, + smeTdlsPeerStateParams. + peerCap.peerCurrOperClass, + smeTdlsPeerStateParams. + peerCap.selfCurrOperClass, + smeTdlsPeerStateParams. + peerCap.peerChanLen, + smeTdlsPeerStateParams. + peerCap.peerOperClassLen, + smeTdlsPeerStateParams. + peerCap.prefOffChanNum, + smeTdlsPeerStateParams. + peerCap.prefOffChanBandwidth, + pTdlsPeer-> + op_class_for_pref_off_chan); + + for (i = 0; + i < + pTdlsPeer->supported_channels_len; + i++) { + smeTdlsPeerStateParams.peerCap. + peerChan[i] = + pTdlsPeer-> + supported_channels[i]; + } + smeTdlsPeerStateParams.peerCap. + peerOperClassLen = + pTdlsPeer-> + supported_oper_classes_len; + for (i = 0; + i < + pTdlsPeer-> + supported_oper_classes_len; i++) { + smeTdlsPeerStateParams.peerCap. + peerOperClass[i] = + pTdlsPeer-> + supported_oper_classes[i]; + } + mutex_unlock(&pHddCtx->tdls_lock); + + qdf_ret_status = + sme_update_tdls_peer_state(pHddCtx-> + hHal, + &smeTdlsPeerStateParams); + if (QDF_STATUS_SUCCESS != + qdf_ret_status) { + QDF_TRACE(QDF_MODULE_ID_HDD, + QDF_TRACE_LEVEL_ERROR, + "%s: sme_update_tdls_peer_state failed for " + MAC_ADDRESS_STR, + __func__, + MAC_ADDR_ARRAY(peer)); + return -EPERM; + } + wlan_hdd_tdls_increment_peer_count + (pAdapter); + } else + mutex_unlock(&pHddCtx->tdls_lock); + + /* Update TL about the UAPSD masks , to route the packets to firmware */ + if ((true == + pHddCtx->config->fEnableTDLSBufferSta) + || pHddCtx->config->fTDLSUapsdMask) { + int ac; + uint8_t ucAc[4] = { SME_AC_VO, + SME_AC_VI, + SME_AC_BK, + SME_AC_BE}; + uint8_t tlTid[4] = { 7, 5, 2, 3 }; + hdd_info("Update TL about UAPSD masks"); + for (ac = 0; ac < 4; ac++) { + status = sme_enable_uapsd_for_ac( + (WLAN_HDD_GET_CTX(pAdapter))->pcds_context, + peer_staid, ucAc[ac], + tlTid[ac], tlTid[ac], 0, 0, + SME_BI_DIR, 1, + pAdapter->sessionId, + pHddCtx->config->DelayedTriggerFrmInt); + } + } + } + hdd_wlan_tdls_enable_link_event(peer, + peer_offchannelsupp, + 0, 0); + } + break; + case NL80211_TDLS_DISABLE_LINK: + { + mutex_lock(&pHddCtx->tdls_lock); + pTdlsPeer = + wlan_hdd_tdls_find_peer(pAdapter, peer); + + if (NULL == pTdlsPeer) { + mutex_unlock(&pHddCtx->tdls_lock); + QDF_TRACE(QDF_MODULE_ID_HDD, + QDF_TRACE_LEVEL_ERROR, + "%s: peer matching " MAC_ADDRESS_STR + " not found, ignore NL80211_TDLS_DISABLE_LINK", + __func__, MAC_ADDR_ARRAY(peer)); + return -EINVAL; + } + + QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO, + "%s: NL80211_TDLS_DISABLE_LINK for peer " + MAC_ADDRESS_STR " link_status: %d", + __func__, MAC_ADDR_ARRAY(peer), + pTdlsPeer->link_status); + peer_staid = pTdlsPeer->staId; + mutex_unlock(&pHddCtx->tdls_lock); + + if (TDLS_STA_INDEX_VALID(peer_staid)) { + unsigned long rc; + + INIT_COMPLETION(pAdapter-> + tdls_del_station_comp); + + sme_delete_tdls_peer_sta(WLAN_HDD_GET_HAL_CTX + (pAdapter), + pAdapter->sessionId, + peer); + + rc = wait_for_completion_timeout(&pAdapter-> + tdls_del_station_comp, + msecs_to_jiffies + (WAIT_TIME_TDLS_DEL_STA)); + if (!rc) { + QDF_TRACE(QDF_MODULE_ID_HDD, + QDF_TRACE_LEVEL_ERROR, + "%s: Del station timed out", + __func__); + return -EPERM; + } + + mutex_lock(&pHddCtx->tdls_lock); + pTdlsPeer = + wlan_hdd_tdls_find_peer(pAdapter, peer); + if (NULL == pTdlsPeer) { + mutex_unlock(&pHddCtx->tdls_lock); + QDF_TRACE(QDF_MODULE_ID_HDD, + QDF_TRACE_LEVEL_ERROR, + "%s: peer matching " MAC_ADDRESS_STR + " (oper %d) peer got freed in other" + " context. ignored", + __func__, MAC_ADDR_ARRAY(peer), + (int)oper); + return -EINVAL; + } + + wlan_hdd_tdls_set_peer_link_status(pTdlsPeer, + eTDLS_LINK_IDLE, + (pTdlsPeer->link_status == + eTDLS_LINK_TEARING) ? + eTDLS_LINK_UNSPECIFIED : + eTDLS_LINK_DROPPED_BY_REMOTE); + mutex_unlock(&pHddCtx->tdls_lock); + } else { + QDF_TRACE(QDF_MODULE_ID_HDD, + QDF_TRACE_LEVEL_ERROR, + "%s: TDLS Peer Station doesn't exist.", + __func__); + } + } + break; + case NL80211_TDLS_TEARDOWN: + { + status = + wlan_hdd_tdls_extctrl_deconfig_peer(pAdapter, peer); + + if (0 != status) { + QDF_TRACE(QDF_MODULE_ID_HDD, + QDF_TRACE_LEVEL_ERROR, + "%s: Error in TDLS Teardown", + __func__); + return status; + } + } + break; + case NL80211_TDLS_SETUP: + { + status = wlan_hdd_tdls_extctrl_config_peer(pAdapter, + peer, NULL, + pHddCtx->config->fTDLSPrefOffChanNum, 0, 0, 0); + if (0 != status) { + QDF_TRACE(QDF_MODULE_ID_HDD, + QDF_TRACE_LEVEL_ERROR, + "%s: Error in TDLS Setup", __func__); + return status; + } + } + break; + case NL80211_TDLS_DISCOVERY_REQ: + /* We don't support in-driver setup/teardown/discovery */ + QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_WARN, + "%s: We don't support in-driver setup/teardown/discovery", + __func__); + return -ENOTSUPP; + default: + QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR, + "%s: unsupported event %d", __func__, oper); + return -ENOTSUPP; + } + EXIT(); + return 0; +} + +/** + * wlan_hdd_cfg80211_tdls_oper() - handle cfg80211 operation on an TDLS peer + * @wiphy: wiphy + * @dev: net device + * @peer: MAC address of the TDLS peer + * @oper: cfg80211 TDLS operation + * + * Return: 0 on success; negative errno otherwise + */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)) +int wlan_hdd_cfg80211_tdls_oper(struct wiphy *wiphy, + struct net_device *dev, + const uint8_t *peer, + enum nl80211_tdls_operation oper) +#else +int wlan_hdd_cfg80211_tdls_oper(struct wiphy *wiphy, + struct net_device *dev, + uint8_t *peer, + enum nl80211_tdls_operation oper) +#endif +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_tdls_oper(wiphy, dev, peer, oper); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * wlan_hdd_cfg80211_send_tdls_discover_req() - send out TDLS discovery for + * a TDLS peer + * @wiphy: wiphy + * @dev: net device + * @peer: MAC address of the peer + * + * Return: 0 if success; negative errno otherwise + */ +int wlan_hdd_cfg80211_send_tdls_discover_req(struct wiphy *wiphy, + struct net_device *dev, u8 *peer) +{ + hdd_notice("tdls send discover req: " MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(peer)); +#if TDLS_MGMT_VERSION2 + return wlan_hdd_cfg80211_tdls_mgmt(wiphy, dev, peer, + WLAN_TDLS_DISCOVERY_REQUEST, 1, 0, 0, + NULL, 0); +#else +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 17, 0)) + return wlan_hdd_cfg80211_tdls_mgmt(wiphy, dev, peer, + WLAN_TDLS_DISCOVERY_REQUEST, 1, 0, + 0, 0, NULL, 0); +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)) + return wlan_hdd_cfg80211_tdls_mgmt(wiphy, dev, peer, + WLAN_TDLS_DISCOVERY_REQUEST, 1, 0, + 0, NULL, 0); +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0)) + return wlan_hdd_cfg80211_tdls_mgmt(wiphy, dev, peer, + WLAN_TDLS_DISCOVERY_REQUEST, 1, 0, + 0, NULL, 0); +#else + return wlan_hdd_cfg80211_tdls_mgmt(wiphy, dev, peer, + WLAN_TDLS_DISCOVERY_REQUEST, 1, 0, + NULL, 0); +#endif +#endif +} + +#endif /* End of FEATURE_WLAN_TDLS */ + +/** + * wlan_hdd_tdls_find_first_connected_peer() - find the 1st connected tdls peer + * @adapter: Pointer to the HDD adapter + * + * This function searchs for the 1st connected TDLS peer + * + * Return: The first connected TDLS peer if found; NULL otherwise + */ +hddTdlsPeer_t *wlan_hdd_tdls_find_first_connected_peer(hdd_adapter_t *adapter) +{ + int i; + struct list_head *head; + struct list_head *pos; + hddTdlsPeer_t *curr_peer = NULL; + tdlsCtx_t *hdd_tdls_ctx; + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + + if (wlan_hdd_validate_context(hdd_ctx)) + return NULL; + + hdd_tdls_ctx = WLAN_HDD_GET_TDLS_CTX_PTR(adapter); + if (NULL == hdd_tdls_ctx) { + return NULL; + } + for (i = 0; i < TDLS_PEER_LIST_SIZE; i++) { + head = &hdd_tdls_ctx->peer_list[i]; + list_for_each(pos, head) { + curr_peer = list_entry(pos, hddTdlsPeer_t, node); + if (curr_peer && (curr_peer->link_status == + eTDLS_LINK_CONNECTED)) { + hdd_notice(MAC_ADDRESS_STR" eTDLS_LINK_CONNECTED", + MAC_ADDR_ARRAY(curr_peer->peerMac)); + return curr_peer; + } + } + } + return NULL; +} + +/** + * hdd_set_tdls_offchannel() - set tdls off-channel number + * @adapter: Pointer to the HDD adapter + * @offchanmode: tdls off-channel number + * + * This function sets tdls off-channel number + * + * Return: 0 on success; negative errno otherwise + */ +int hdd_set_tdls_offchannel(hdd_context_t *hdd_ctx, int offchannel) +{ + if ((true == hdd_ctx->config->fEnableTDLSOffChannel) && + (eTDLS_SUPPORT_ENABLED == hdd_ctx->tdls_mode || + eTDLS_SUPPORT_EXTERNAL_CONTROL == hdd_ctx->tdls_mode || + eTDLS_SUPPORT_EXPLICIT_TRIGGER_ONLY == hdd_ctx->tdls_mode)) { + if (offchannel < CFG_TDLS_PREFERRED_OFF_CHANNEL_NUM_MIN || + offchannel > CFG_TDLS_PREFERRED_OFF_CHANNEL_NUM_MAX) { + hdd_err("Invalid tdls off channel %u", offchannel); + return -EINVAL; + } + } else { + hdd_warn("Either TDLS or TDLS Off-channel is not enabled"); + return -ENOTSUPP; + } + hdd_notice("change tdls off channel from %d to %d", + hdd_ctx->tdls_off_channel, offchannel); + hdd_ctx->tdls_off_channel = offchannel; + return 0; +} + +/** + * hdd_set_tdls_secoffchanneloffset() - set secondary tdls off-channel offset + * @adapter: Pointer to the HDD adapter + * @offchanmode: tdls off-channel offset + * + * This function sets 2nd tdls off-channel offset + * + * Return: 0 on success; negative errno otherwise + */ +int hdd_set_tdls_secoffchanneloffset(hdd_context_t *hdd_ctx, int offchanoffset) +{ + if ((true == hdd_ctx->config->fEnableTDLSOffChannel) && + (eTDLS_SUPPORT_ENABLED == hdd_ctx->tdls_mode || + eTDLS_SUPPORT_EXTERNAL_CONTROL == hdd_ctx->tdls_mode || + eTDLS_SUPPORT_EXPLICIT_TRIGGER_ONLY == hdd_ctx->tdls_mode)) { + hdd_ctx->tdls_channel_offset = 0; + + switch (offchanoffset) { + case TDLS_SEC_OFFCHAN_OFFSET_0: + hdd_ctx->tdls_channel_offset = (1 << BW_20_OFFSET_BIT); + break; + case TDLS_SEC_OFFCHAN_OFFSET_40PLUS: + case TDLS_SEC_OFFCHAN_OFFSET_40MINUS: + hdd_ctx->tdls_channel_offset = (1 << BW_40_OFFSET_BIT); + break; + case TDLS_SEC_OFFCHAN_OFFSET_80: + hdd_ctx->tdls_channel_offset = (1 << BW_80_OFFSET_BIT); + break; + case TDLS_SEC_OFFCHAN_OFFSET_160: + hdd_ctx->tdls_channel_offset = (1 << BW_160_OFFSET_BIT); + break; + default: + hdd_err("Invalid tdls secondary off channel offset %d", + offchanoffset); + return -EINVAL; + } /* end switch */ + } else { + hdd_warn("Either TDLS or TDLS Off-channel is not enabled"); + return -ENOTSUPP; + } + hdd_notice("change tdls secondary off channel offset to 0x%x", + hdd_ctx->tdls_channel_offset); + return 0; +} + +/** + * hdd_set_tdls_offchannelmode() - set tdls off-channel mode + * @adapter: Pointer to the HDD adapter + * @offchanmode: tdls off-channel mode + * + * This function sets tdls off-channel mode + * + * Return: 0 on success; negative errno otherwise + */ +int hdd_set_tdls_offchannelmode(hdd_adapter_t *adapter, int offchanmode) +{ + hddTdlsPeer_t *conn_peer = NULL; + hdd_station_ctx_t *hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + sme_tdls_chan_switch_params chan_switch_params; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + int ret_value = 0; + + if (offchanmode < ENABLE_CHANSWITCH || + offchanmode > DISABLE_CHANSWITCH) { + hdd_err("Invalid tdls off channel mode %d", offchanmode); + ret_value = -EINVAL; + goto ret_status; + } + if (eConnectionState_Associated != hdd_sta_ctx->conn_info.connState) { + hdd_err("tdls off channel mode req in not associated state %d", + offchanmode); + ret_value = -EPERM; + goto ret_status; + } + if ((true == hdd_ctx->config->fEnableTDLSOffChannel) && + (eTDLS_SUPPORT_ENABLED == hdd_ctx->tdls_mode || + eTDLS_SUPPORT_EXTERNAL_CONTROL == hdd_ctx->tdls_mode || + eTDLS_SUPPORT_EXPLICIT_TRIGGER_ONLY == hdd_ctx->tdls_mode)) { + mutex_lock(&hdd_ctx->tdls_lock); + conn_peer = wlan_hdd_tdls_find_first_connected_peer(adapter); + if (NULL == conn_peer) { + hdd_err("No TDLS Connected Peer"); + ret_value = -EPERM; + goto rel_lock; + } + } else { + hdd_err("TDLS Connection not supported"); + ret_value = -ENOTSUPP; + goto ret_status; + } + + hdd_notice("TDLS Channel Switch in swmode=%d tdls_off_channel %d offchanoffset %d", + offchanmode, hdd_ctx->tdls_off_channel, + hdd_ctx->tdls_channel_offset); + + switch (offchanmode) { + case ENABLE_CHANSWITCH: + if (hdd_ctx->tdls_off_channel && + hdd_ctx->tdls_channel_offset) { + chan_switch_params.tdls_off_channel = + hdd_ctx->tdls_off_channel; + chan_switch_params.tdls_off_ch_bw_offset = + hdd_ctx->tdls_channel_offset; + chan_switch_params.opclass = + wlan_hdd_find_opclass(WLAN_HDD_GET_HAL_CTX(adapter), + chan_switch_params.tdls_off_channel, + chan_switch_params.tdls_off_ch_bw_offset); + } else { + hdd_err("TDLS off-channel parameters are not set yet!!!"); + ret_value = -EINVAL; + goto rel_lock; + } + break; + case DISABLE_CHANSWITCH: + chan_switch_params.tdls_off_channel = 0; + chan_switch_params.tdls_off_ch_bw_offset = 0; + chan_switch_params.opclass = 0; + break; + default: + hdd_err("Incorrect Parameters mode: %d tdls_off_channel: %d offchanoffset: %d", + offchanmode, hdd_ctx->tdls_off_channel, + hdd_ctx->tdls_channel_offset); + ret_value = -EINVAL; + goto rel_lock; + } /* end switch */ + + chan_switch_params.vdev_id = adapter->sessionId; + chan_switch_params.tdls_off_ch_mode = offchanmode; + chan_switch_params.is_responder = + conn_peer->is_responder; + qdf_mem_copy(&chan_switch_params.peer_mac_addr, + &conn_peer->peerMac, + sizeof(tSirMacAddr)); + hdd_info("Peer " MAC_ADDRESS_STR + " vdevId: %d, off channel: %d, offset: %d, mode: %d, is_responder: %d", + MAC_ADDR_ARRAY(chan_switch_params.peer_mac_addr), + chan_switch_params.vdev_id, + chan_switch_params.tdls_off_channel, + chan_switch_params.tdls_off_ch_bw_offset, + chan_switch_params.tdls_off_ch_mode, + chan_switch_params.is_responder); + mutex_unlock(&hdd_ctx->tdls_lock); + + status = sme_send_tdls_chan_switch_req(WLAN_HDD_GET_HAL_CTX(adapter), + &chan_switch_params); + + if (status != QDF_STATUS_SUCCESS) { + hdd_err("Failed to send channel switch request to sme"); + ret_value = -EINVAL; + goto ret_status; + } + + hdd_ctx->tdls_fw_off_chan_mode = offchanmode; + + if (ENABLE_CHANSWITCH == offchanmode) { + mutex_lock(&hdd_ctx->tdls_lock); + conn_peer = wlan_hdd_tdls_find_first_connected_peer(adapter); + if (NULL == conn_peer) { + hdd_err("No TDLS Connected Peer"); + ret_value = -EPERM; + goto rel_lock; + } + conn_peer->pref_off_chan_num = + chan_switch_params.tdls_off_channel; + conn_peer->op_class_for_pref_off_chan = + chan_switch_params.opclass; + goto rel_lock; + } + goto ret_status; + +rel_lock: + mutex_unlock(&hdd_ctx->tdls_lock); +ret_status: + return ret_value; +} + +/** + * wlan_hdd_tdls_ct_sampling_tx_rx() - collect tx/rx traffic sample + * @adapter: pointer to hdd adapter + * @hdd_ctx: hdd context + * + * Function to update data traffic information in tdls connection + * tracker data structure for connection tracker operation + * + * Return: None + */ +static void wlan_hdd_tdls_ct_sampling_tx_rx(hdd_adapter_t *adapter, + hdd_context_t *hdd_ctx) +{ + hddTdlsPeer_t *curr_peer; + uint8_t mac[QDF_MAC_ADDR_SIZE]; + uint8_t mac_cnt; + uint8_t valid_mac_entries; + struct tdls_ct_mac_table ct_peer_mac_table[TDLS_CT_MAC_MAX_TABLE_SIZE]; + + qdf_spin_lock_bh(&hdd_ctx->tdls_ct_spinlock); + + if (0 == hdd_ctx->valid_mac_entries) { + qdf_spin_unlock_bh(&hdd_ctx->tdls_ct_spinlock); + return; + } + + valid_mac_entries = hdd_ctx->valid_mac_entries; + + memcpy(ct_peer_mac_table, hdd_ctx->ct_peer_mac_table, + (sizeof(struct tdls_ct_mac_table)) * valid_mac_entries); + + memset(hdd_ctx->ct_peer_mac_table, 0, + (sizeof(struct tdls_ct_mac_table)) * valid_mac_entries); + + hdd_ctx->valid_mac_entries = 0; + + qdf_spin_unlock_bh(&hdd_ctx->tdls_ct_spinlock); + mutex_lock(&hdd_ctx->tdls_lock); + for (mac_cnt = 0; mac_cnt < valid_mac_entries; mac_cnt++) { + memcpy(mac, ct_peer_mac_table[mac_cnt].mac_address.bytes, + QDF_MAC_ADDR_SIZE); + curr_peer = wlan_hdd_tdls_get_peer(adapter, mac); + if (NULL != curr_peer) { + curr_peer->tx_pkt = + ct_peer_mac_table[mac_cnt].tx_packet_cnt; + curr_peer->rx_pkt = + ct_peer_mac_table[mac_cnt].rx_packet_cnt; + } + } + mutex_unlock(&hdd_ctx->tdls_lock); +} + +/** + * wlan_hdd_tdls_update_rx_pkt_cnt() - Update rx packet count + * @adapter: pointer to hdd adapter + * @skb: pointer to sk_buff + * + * Increase the rx packet count, if the sender is not bssid and the packet is + * not broadcast and muticast packet + * + * This sampling information will be used in TDLS connection tracker + * + * This function expected to be called in an atomic context so blocking APIs + * not allowed + * + * Return: None + */ +void wlan_hdd_tdls_update_rx_pkt_cnt(hdd_adapter_t *adapter, + struct sk_buff *skb) +{ + hdd_context_t *hdd_ctx; + hdd_station_ctx_t *hdd_sta_ctx; + uint8_t mac_cnt; + uint8_t valid_mac_entries; + struct qdf_mac_addr *mac_addr; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + + if (!hdd_ctx->enable_tdls_connection_tracker) + return; + + mac_addr = (struct qdf_mac_addr *)(skb->data+QDF_MAC_ADDR_SIZE); + if (qdf_is_macaddr_group(mac_addr)) + return; + + hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + if (memcmp(hdd_sta_ctx->conn_info.bssId.bytes, + mac_addr, QDF_MAC_ADDR_SIZE) == 0) + return; + + + qdf_spin_lock_bh(&hdd_ctx->tdls_ct_spinlock); + valid_mac_entries = hdd_ctx->valid_mac_entries; + + for (mac_cnt = 0; mac_cnt < valid_mac_entries; mac_cnt++) { + if (memcmp(hdd_ctx->ct_peer_mac_table[mac_cnt].mac_address.bytes, + mac_addr, QDF_MAC_ADDR_SIZE) == 0) { + hdd_ctx->ct_peer_mac_table[mac_cnt].rx_packet_cnt++; + goto rx_cnt_return; + } + } + + /* If we have more than 8 peers within 30 mins. we will + * stop tracking till the old entries are removed + */ + if (mac_cnt < TDLS_CT_MAC_MAX_TABLE_SIZE) { + memcpy(hdd_ctx->ct_peer_mac_table[mac_cnt].mac_address.bytes, + mac_addr, QDF_MAC_ADDR_SIZE); + hdd_ctx->valid_mac_entries = mac_cnt+1; + hdd_ctx->ct_peer_mac_table[mac_cnt].rx_packet_cnt = 1; + } + +rx_cnt_return: + qdf_spin_unlock_bh(&hdd_ctx->tdls_ct_spinlock); + return; +} + +/** + * wlan_hdd_tdls_update_tx_pkt_cnt() - update tx packet + * @adapter: pointer to hdd adapter + * @skb: pointer to sk_buff + * + * Increase the tx packet count, if the sender is not bssid and the packet is + * not broadcast and muticast packet + * + * This sampling information will be used in TDLS connection tracker + * + * This function expected to be called in an atomic context so blocking APIs + * not allowed + * + * Return: None + */ +void wlan_hdd_tdls_update_tx_pkt_cnt(hdd_adapter_t *adapter, + struct sk_buff *skb) +{ + hdd_context_t *hdd_ctx; + hdd_station_ctx_t *hdd_sta_ctx; + uint8_t mac_cnt; + uint8_t valid_mac_entries; + struct qdf_mac_addr *mac_addr; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + + if (!hdd_ctx->enable_tdls_connection_tracker) + return; + + mac_addr = (struct qdf_mac_addr *)skb->data; + if (qdf_is_macaddr_group(mac_addr)) + return; + + hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + if (memcmp(hdd_sta_ctx->conn_info.bssId.bytes, mac_addr, + QDF_MAC_ADDR_SIZE) == 0) + return; + + qdf_spin_lock_bh(&hdd_ctx->tdls_ct_spinlock); + valid_mac_entries = hdd_ctx->valid_mac_entries; + + for (mac_cnt = 0; mac_cnt < valid_mac_entries; mac_cnt++) { + if (memcmp(hdd_ctx->ct_peer_mac_table[mac_cnt].mac_address.bytes, + mac_addr, QDF_MAC_ADDR_SIZE) == 0) { + hdd_ctx->ct_peer_mac_table[mac_cnt].tx_packet_cnt++; + goto tx_cnt_return; + } + } + + /* If we have more than 8 peers within 30 mins. we will + * stop tracking till the old entries are removed + */ + if (mac_cnt < TDLS_CT_MAC_MAX_TABLE_SIZE) { + memcpy(hdd_ctx->ct_peer_mac_table[mac_cnt].mac_address.bytes, + mac_addr, QDF_MAC_ADDR_SIZE); + hdd_ctx->ct_peer_mac_table[mac_cnt].tx_packet_cnt = 1; + hdd_ctx->valid_mac_entries++; + } + +tx_cnt_return: + qdf_spin_unlock_bh(&hdd_ctx->tdls_ct_spinlock); + return; +} + +/** + * wlan_hdd_tdls_implicit_send_discovery_request() - send discovery request + * @hdd_tdls_ctx: tdls context + * + * Return: None + */ +void wlan_hdd_tdls_implicit_send_discovery_request(tdlsCtx_t *hdd_tdls_ctx) +{ + hdd_context_t *hdd_ctx; + hddTdlsPeer_t *curr_peer, *temp_peer; + + ENTER(); + if (NULL == hdd_tdls_ctx) { + hdd_info("hdd_tdls_ctx is NULL"); + return; + } + + hdd_ctx = WLAN_HDD_GET_CTX(hdd_tdls_ctx->pAdapter); + + if (0 != (wlan_hdd_validate_context(hdd_ctx))) + return; + + curr_peer = hdd_tdls_ctx->curr_candidate; + if (NULL == curr_peer) { + hdd_err("curr_peer is NULL"); + return; + } + + /* This function is called in mutex_lock */ + temp_peer = wlan_hdd_tdls_is_progress(hdd_ctx, NULL, 0); + if (NULL != temp_peer) { + hdd_info(MAC_ADDRESS_STR " ongoing. pre_setup ignored", + MAC_ADDR_ARRAY(temp_peer->peerMac)); + goto done; + } + + if (eTDLS_CAP_UNKNOWN != curr_peer->tdls_support) + wlan_hdd_tdls_set_peer_link_status(curr_peer, + eTDLS_LINK_DISCOVERING, + eTDLS_LINK_SUCCESS); + + hdd_info("Implicit TDLS, Send Discovery request event"); + cfg80211_tdls_oper_request(hdd_tdls_ctx->pAdapter->dev, + curr_peer->peerMac, + NL80211_TDLS_DISCOVERY_REQ, + false, + GFP_KERNEL); + hdd_tdls_ctx->discovery_sent_cnt++; + + wlan_hdd_tdls_timer_restart(hdd_tdls_ctx->pAdapter, + &hdd_tdls_ctx->peerDiscoveryTimeoutTimer, + hdd_tdls_ctx->threshold_config.tx_period_t - + TDLS_DISCOVERY_TIMEOUT_BEFORE_UPDATE); + + hdd_info("discovery count %u timeout %u msec", + hdd_tdls_ctx->discovery_sent_cnt, + hdd_tdls_ctx->threshold_config.tx_period_t - + TDLS_DISCOVERY_TIMEOUT_BEFORE_UPDATE); +done: + hdd_tdls_ctx->curr_candidate = NULL; + hdd_tdls_ctx->magic = 0; + EXIT(); + return; +} + +/** + * wlan_hdd_get_conn_info() - get the tdls connection information. + * @hdd_ctx: hdd context + * @hdd_ctx: sta id + * + * Function to check tdls sta index + * + * Return: None + */ +static tdlsConnInfo_t *wlan_hdd_get_conn_info(hdd_context_t *hdd_ctx, + uint8_t idx) +{ + uint8_t sta_idx; + + /* check if there is available index for this new TDLS STA */ + for (sta_idx = 0; sta_idx < HDD_MAX_NUM_TDLS_STA; sta_idx++) { + if (idx == hdd_ctx->tdlsConnInfo[sta_idx].staId) { + hdd_info("tdls peer with staIdx %u exists", idx); + return &hdd_ctx->tdlsConnInfo[sta_idx]; + } + } + hdd_err("tdls peer with staIdx %u not exists", idx); + return NULL; +} + +/** + * wlan_hdd_tdls_idle_handler() - Check tdls idle traffic + * @user_data: data from tdls idle timer + * + * Function to check the tdls idle traffic and make a decision about + * tdls teardown + * + * Return: None + */ +static void wlan_hdd_tdls_idle_handler(void *user_data) +{ + tdlsConnInfo_t *tdls_info = (tdlsConnInfo_t *) user_data; + hddTdlsPeer_t *curr_peer; + tdlsCtx_t *hdd_tdls_ctx; + hdd_context_t *hdd_ctx; + v_CONTEXT_t cds_context; + hdd_adapter_t *adapter; + + if (!tdls_info->staId) { + hdd_err("peer (staidx %u) doesn't exists", tdls_info->staId); + return; + } + + cds_context = cds_get_global_context(); + if (NULL == cds_context) { + hdd_err("cds_context points to NULL"); + return; + } + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (0 != (wlan_hdd_validate_context(hdd_ctx))) + return; + + adapter = hdd_get_adapter_by_sme_session_id(hdd_ctx, + tdls_info->sessionId); + + if (!adapter) { + hdd_err("adapter is NULL"); + return; + } + + mutex_lock(&hdd_ctx->tdls_lock); + curr_peer = wlan_hdd_tdls_find_peer(adapter, + (u8 *) &tdls_info->peerMac.bytes[0]); + + if (NULL == curr_peer) { + hdd_err("Invalid tdls idle timer expired"); + goto error_idle_return; + } + + hdd_tdls_ctx = curr_peer->pHddTdlsCtx; + if (NULL == hdd_tdls_ctx) { + hdd_err("Invalid hdd_tdls_ctx context"); + goto error_idle_return; + } + + hdd_info(MAC_ADDRESS_STR " tx_pkt: %d, rx_pkt: %d, idle_packet_n: %d", + MAC_ADDR_ARRAY(curr_peer->peerMac), + curr_peer->tx_pkt, + curr_peer->rx_pkt, + curr_peer->pHddTdlsCtx->threshold_config.idle_packet_n); + + /* Check tx/rx statistics on this tdls link for recent activities and + * then decide whether to tear down the link or keep it. + */ + if ((curr_peer->tx_pkt >= + curr_peer->pHddTdlsCtx->threshold_config.idle_packet_n) || + (curr_peer->rx_pkt >= + curr_peer->pHddTdlsCtx->threshold_config.idle_packet_n)) { + /* this tdls link got back to normal, so keep it */ + hdd_info("tdls link to " MAC_ADDRESS_STR + " back to normal, will stay", + MAC_ADDR_ARRAY(curr_peer->peerMac)); + } else { + /* this tdls link needs to get torn down */ + hdd_info("trigger tdls link to "MAC_ADDRESS_STR + " down", MAC_ADDR_ARRAY(curr_peer->peerMac)); + wlan_hdd_tdls_indicate_teardown(curr_peer->pHddTdlsCtx->pAdapter, + curr_peer, + eSIR_MAC_TDLS_TEARDOWN_UNSPEC_REASON); + } +error_idle_return: + mutex_unlock(&hdd_ctx->tdls_lock); + return; +} + +/** + * tdls_ct_process_idle_and_discovery() - process the traffic data + * @curr_peer: tdls peer needs to be examined + * @hdd_ctx: hdd context + * @hdd_tdls_ctx: tdls context + * + * Function to check the peer traffic data in idle link and tdls + * discovering link + * + * Return: None + */ +static void tdls_ct_process_idle_and_discovery(hddTdlsPeer_t *curr_peer, + tdlsCtx_t *hdd_tdls_ctx) +{ + uint16_t valid_peers; + + valid_peers = wlan_hdd_tdls_connected_peers(hdd_tdls_ctx->pAdapter); + + if ((curr_peer->tx_pkt + curr_peer->rx_pkt) >= + hdd_tdls_ctx->threshold_config.tx_packet_n) { + if (HDD_MAX_NUM_TDLS_STA > valid_peers) { + hdd_info("Tput trigger TDLS pre-setup"); + hdd_tdls_ctx->curr_candidate = curr_peer; + wlan_hdd_tdls_implicit_send_discovery_request( + hdd_tdls_ctx); + } else { + hdd_info("Maximum peers connected already! %d", + valid_peers); + } + } +} + + +/** + * tdls_ct_process_connected_link() - process the traffic + * @curr_peer: tdls peer needs to be examined + * @hdd_ctx: hdd context + * @hdd_tdls_ctx: tdls context + * + * Function to check the peer traffic data in active STA + * session + * + * Return: None + */ +static void tdls_ct_process_connected_link(hddTdlsPeer_t *curr_peer, + hdd_context_t *hdd_ctx, + tdlsCtx_t *hdd_tdls_ctx) +{ + if ((int32_t)curr_peer->rssi < + (int32_t)hdd_tdls_ctx->threshold_config.rssi_teardown_threshold) { + hdd_warn("Tear down - low RSSI: " MAC_ADDRESS_STR "!", + MAC_ADDR_ARRAY(curr_peer->peerMac)); + wlan_hdd_tdls_indicate_teardown(hdd_tdls_ctx->pAdapter, + curr_peer, + eSIR_MAC_TDLS_TEARDOWN_UNSPEC_REASON); + return; + } + + /* Only teardown based on non zero idle packet threshold, to address + * a use case where this threshold does not get consider for TEAR DOWN + */ + if ((0 != hdd_tdls_ctx->threshold_config.idle_packet_n) && + ((curr_peer->tx_pkt < + hdd_tdls_ctx->threshold_config.idle_packet_n) && + (curr_peer->rx_pkt < + hdd_tdls_ctx->threshold_config.idle_packet_n))) { + if (!curr_peer->is_peer_idle_timer_initialised) { + uint8_t staId = (uint8_t)curr_peer->staId; + tdlsConnInfo_t *tdls_info; + tdls_info = wlan_hdd_get_conn_info(hdd_ctx, staId); + qdf_mc_timer_init(&curr_peer->peer_idle_timer, + QDF_TIMER_TYPE_SW, + wlan_hdd_tdls_idle_handler, + tdls_info); + curr_peer->is_peer_idle_timer_initialised = true; + } + if (QDF_TIMER_STATE_RUNNING != + curr_peer->peer_idle_timer.state) { + hdd_warn("Tx/Rx Idle timer start: " MAC_ADDRESS_STR "!", + MAC_ADDR_ARRAY(curr_peer->peerMac)); + wlan_hdd_tdls_timer_restart(hdd_tdls_ctx->pAdapter, + &curr_peer->peer_idle_timer, + hdd_tdls_ctx->threshold_config.idle_timeout_t); + } + } else if (QDF_TIMER_STATE_RUNNING == + curr_peer->peer_idle_timer.state) { + hdd_warn("Tx/Rx Idle timer stop: " MAC_ADDRESS_STR "!", + MAC_ADDR_ARRAY(curr_peer->peerMac)); + qdf_mc_timer_stop(&curr_peer->peer_idle_timer); + } +} + +/** + * wlan_hdd_tdls_ct_process_cap_supported() - process TDLS supported peer. + * @curr_peer: tdls peer needs to be examined + * @hdd_ctx: hdd context + * @hdd_tdls_ctx: tdls context + * + * Function to check the peer traffic data for tdls supported peer + * + * Return: None + */ +static void wlan_hdd_tdls_ct_process_cap_supported(hddTdlsPeer_t *curr_peer, + hdd_context_t *hdd_ctx, + tdlsCtx_t *hdd_tdls_ctx) +{ + hdd_info("tx %d, rx %d (thr.pkt %d/idle %d), rssi %d (thr.trig %d/tear %d)", + curr_peer->tx_pkt, curr_peer->rx_pkt, + hdd_tdls_ctx->threshold_config.tx_packet_n, + hdd_tdls_ctx->threshold_config.idle_packet_n, + curr_peer->rssi, + hdd_tdls_ctx->threshold_config.rssi_trigger_threshold, + hdd_tdls_ctx->threshold_config.rssi_teardown_threshold); + + switch (curr_peer->link_status) { + case eTDLS_LINK_IDLE: + case eTDLS_LINK_DISCOVERING: + if (hdd_ctx->config->fTDLSExternalControl && + (!curr_peer->isForcedPeer)) + break; + tdls_ct_process_idle_and_discovery(curr_peer, hdd_tdls_ctx); + break; + case eTDLS_LINK_CONNECTED: + tdls_ct_process_connected_link(curr_peer, hdd_ctx, + hdd_tdls_ctx); + break; + default: + break; + } +} + +/** + * wlan_hdd_tdls_ct_process_cap_unknown() - process unknown peer + * @curr_peer: tdls peer needs to be examined + * @hdd_ctx: hdd context + * @hdd_tdls_ctx: tdls context + * + * Function check the peer traffic data , when tdls capability is unknown + * + * Return: None + */ +static void wlan_hdd_tdls_ct_process_cap_unknown(hddTdlsPeer_t *curr_peer, + hdd_context_t *hdd_ctx, + tdlsCtx_t *hdd_tdls_ctx) +{ + if (hdd_ctx->config->fTDLSExternalControl && + (!curr_peer->isForcedPeer)) { + return; + } + + hdd_info("threshold_config.tx_packet_n = %d curr_peer->tx_pkt = %d curr_peer->rx_pkt = %d ", + hdd_tdls_ctx->threshold_config.tx_packet_n, curr_peer->tx_pkt, + curr_peer->rx_pkt); + + if (!TDLS_IS_CONNECTED(curr_peer) && + ((curr_peer->tx_pkt + curr_peer->rx_pkt) >= + hdd_tdls_ctx->threshold_config.tx_packet_n)) { + /* Ignore discovery attempt if External Control is enabled, that + * is, peer is forced. In that case, continue discovery attempt + * regardless attempt count + */ + hdd_info("TDLS UNKNOWN pre discover "); + if (curr_peer->isForcedPeer || curr_peer->discovery_attempt++ < + hdd_tdls_ctx->threshold_config.discovery_tries_n) { + hdd_info("TDLS UNKNOWN discover "); + hdd_tdls_ctx->curr_candidate = curr_peer; + wlan_hdd_tdls_implicit_send_discovery_request(hdd_tdls_ctx); + } else { + curr_peer->tdls_support = eTDLS_CAP_NOT_SUPPORTED; + wlan_hdd_tdls_set_peer_link_status( + curr_peer, + eTDLS_LINK_IDLE, + eTDLS_LINK_NOT_SUPPORTED); + } + } +} + + +/** + * wlan_hdd_tdls_ct_process_peers() - process the peer + * @curr_peer: tdls peer needs to be examined + * @hdd_ctx: hdd context + * @hdd_tdls_ctx: tdls context + * + * This function check the peer capability and process the metadata from + * the peer + * + * Return: None + */ +static void wlan_hdd_tdls_ct_process_peers(hddTdlsPeer_t *curr_peer, + hdd_context_t *hdd_ctx, + tdlsCtx_t *hdd_tdls_ctx) +{ + hdd_info(MAC_ADDRESS_STR " link_status %d tdls_support %d", + MAC_ADDR_ARRAY(curr_peer->peerMac), + curr_peer->link_status, curr_peer->tdls_support); + + switch (curr_peer->tdls_support) { + case eTDLS_CAP_SUPPORTED: + wlan_hdd_tdls_ct_process_cap_supported(curr_peer, hdd_ctx, + hdd_tdls_ctx); + break; + + case eTDLS_CAP_UNKNOWN: + wlan_hdd_tdls_ct_process_cap_unknown(curr_peer, hdd_ctx, + hdd_tdls_ctx); + break; + default: + break; + } + +} + +/** + * wlan_hdd_tdls_ct_handler() - TDLS connection tracker handler + * @user_data: user data from timer + * + * tdls connection tracker timer starts, when the STA connected to AP + * and it's scan the traffic between two STA peers and make TDLS + * connection and teardown, based on the traffic threshold + * + * Return: None + */ +static void wlan_hdd_tdls_ct_handler(void *user_data) +{ + int i; + hdd_adapter_t *adapter; + struct list_head *head; + struct list_head *pos; + hddTdlsPeer_t *curr_peer; + tdlsCtx_t *hdd_tdls_ctx; + hdd_context_t *hdd_ctx; + + adapter = (hdd_adapter_t *)user_data; + + if (NULL == adapter) { + hdd_err("Invalid adapter context"); + return; + } + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + + if (0 != (wlan_hdd_validate_context(hdd_ctx))) + return; + /* If any concurrency is detected */ + if (!hdd_ctx->enable_tdls_connection_tracker) { + hdd_info("Connection tracker is disabled"); + return; + } + + /* Update tx rx traffic sample in tdls data structures */ + wlan_hdd_tdls_ct_sampling_tx_rx(adapter, hdd_ctx); + + mutex_lock(&hdd_ctx->tdls_lock); + hdd_tdls_ctx = WLAN_HDD_GET_TDLS_CTX_PTR(adapter); + + if (NULL == hdd_tdls_ctx) { + mutex_unlock(&hdd_ctx->tdls_lock); + hdd_err("Invalid hdd_tdls_ctx context"); + return; + } + + for (i = 0; i < TDLS_PEER_LIST_SIZE; i++) { + head = &hdd_tdls_ctx->peer_list[i]; + list_for_each(pos, head) { + curr_peer = list_entry(pos, hddTdlsPeer_t, node); + wlan_hdd_tdls_ct_process_peers(curr_peer, hdd_ctx, + hdd_tdls_ctx); + curr_peer->tx_pkt = 0; + curr_peer->rx_pkt = 0; + } + } + + wlan_hdd_tdls_timer_restart(hdd_tdls_ctx->pAdapter, + &hdd_tdls_ctx->peer_update_timer, + hdd_tdls_ctx->threshold_config.tx_period_t); + mutex_unlock(&hdd_ctx->tdls_lock); +} + +/** + * hdd_set_tdls_scan_type - set scan during active tdls session + * @hdd_ctx: ptr to hdd context. + * @val: scan type value: 0 or 1. + * + * Set scan type during tdls session. If set to 1, that means driver + * shall maintain tdls link and allow scan regardless if tdls peer is + * buffer sta capable or not and/or if device is sleep sta capable or + * not. If tdls peer is not buffer sta capable then during scan there + * will be loss of Rx packets and Tx would stop when device moves away + * from tdls channel. If set to 0, then driver shall teardown tdls link + * before initiating scan if peer is not buffer sta capable and device + * is not sleep sta capable. By default, scan type is set to 0. + * + * Return: success (0) or failure (errno value) + */ +int hdd_set_tdls_scan_type(hdd_context_t *hdd_ctx, int val) +{ + if ((val != 0) && (val != 1)) { + hdd_err("Incorrect value of tdls scan type: %d", val); + return -EINVAL; + } else { + hdd_ctx->config->enable_tdls_scan = val; + return 0; + } +} + +/** + * wlan_hdd_tdls_teardown_links() - teardown tdls links + * @hddCtx : pointer to hdd context + * + * Return: 0 if success else non zero + */ +static int wlan_hdd_tdls_teardown_links(hdd_context_t *hddctx, + uint32_t mode) +{ + uint16_t connected_tdls_peers = 0; + uint8_t staidx; + hddTdlsPeer_t *curr_peer; + hdd_adapter_t *adapter; + int ret = 0; + + if (eTDLS_SUPPORT_NOT_ENABLED == hddctx->tdls_mode) { + hdd_info("TDLS mode is disabled OR not enabled in FW"); + return 0; + } + + adapter = hdd_get_adapter(hddctx, QDF_STA_MODE); + + if (adapter == NULL) { + hdd_info("Station Adapter Not Found"); + return 0; + } + + connected_tdls_peers = wlan_hdd_tdls_connected_peers(adapter); + + if (!connected_tdls_peers) + return 0; + + for (staidx = 0; staidx < hddctx->max_num_tdls_sta; + staidx++) { + if (!hddctx->tdlsConnInfo[staidx].staId) + continue; + + mutex_lock(&hddctx->tdls_lock); + curr_peer = wlan_hdd_tdls_find_all_peer(hddctx, + hddctx->tdlsConnInfo[staidx].peerMac.bytes); + + if (!curr_peer) { + mutex_unlock(&hddctx->tdls_lock); + continue; + } + + /* Check if connected peer supports more than one stream */ + if (curr_peer->spatial_streams == TDLS_NSS_1x1_MODE) { + mutex_unlock(&hddctx->tdls_lock); + continue; + } + + hdd_info("Indicate TDLS teardown (staId %d)", + curr_peer->staId); + + wlan_hdd_tdls_indicate_teardown( + curr_peer->pHddTdlsCtx->pAdapter, + curr_peer, + eSIR_MAC_TDLS_TEARDOWN_UNSPEC_REASON); + hddctx->tdls_teardown_peers_cnt++; + mutex_unlock(&hddctx->tdls_lock); + } + mutex_lock(&hddctx->tdls_lock); + if (hddctx->tdls_teardown_peers_cnt >= 1) { + hddctx->tdls_nss_switch_in_progress = true; + hdd_info("TDLS peers to be torn down = %d", + hddctx->tdls_teardown_peers_cnt); + /* Antenna switch 2x2 to 1x1 */ + if (mode == HDD_ANTENNA_MODE_1X1) { + hddctx->tdls_nss_transition_mode = + TDLS_NSS_TRANSITION_2x2_to_1x1; + ret = -EAGAIN; + } else { + /* Antenna switch 1x1 to 2x2 */ + hddctx->tdls_nss_transition_mode = + TDLS_NSS_TRANSITION_1x1_to_2x2; + ret = 0; + } + hdd_info("TDLS teardown for antenna switch operation starts"); + } + mutex_unlock(&hddctx->tdls_lock); + return ret; +} + +/** + * wlan_hdd_tdls_antenna_switch() - Dynamic TDLS antenna switch 1x1 <-> 2x2 + * antenna mode in standalone station + * @hdd_ctx: Pointer to hdd contex + * @adapter: Pointer to hdd adapter + * + * Return: 0 if success else non zero + */ +int wlan_hdd_tdls_antenna_switch(hdd_context_t *hdd_ctx, + hdd_adapter_t *adapter, uint32_t mode) +{ + uint8_t tdls_peer_cnt; + uint32_t vdev_nss; + hdd_station_ctx_t *sta_ctx; + + if (hdd_ctx->connected_peer_count == 0) + return 0; + + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + /* Check whether TDLS antenna switch is in progress */ + if (hdd_ctx->tdls_nss_switch_in_progress) { + if (hdd_ctx->tdls_nss_teardown_complete == false) { + hdd_err("TDLS antenna switch is in progress"); + return -EAGAIN; + } else { + goto tdls_ant_sw_done; + } + } + + /* Check whether TDLS is connected or not */ + mutex_lock(&hdd_ctx->tdls_lock); + tdls_peer_cnt = hdd_ctx->connected_peer_count; + mutex_unlock(&hdd_ctx->tdls_lock); + if (tdls_peer_cnt <= 0) { + hdd_info("No TDLS connection established"); + goto tdls_ant_sw_done; + } + + /* Check the supported nss for TDLS */ + if (IS_5G_CH(sta_ctx->conn_info.operationChannel)) + vdev_nss = CFG_TDLS_NSS( + hdd_ctx->config->vdev_type_nss_5g); + else + vdev_nss = CFG_TDLS_NSS( + hdd_ctx->config->vdev_type_nss_2g); + + if (vdev_nss == HDD_ANTENNA_MODE_1X1) { + hdd_info("Supported NSS is 1X1, no need to teardown TDLS links"); + goto tdls_ant_sw_done; + } + + /* teardown all the tdls connections */ + return wlan_hdd_tdls_teardown_links(hdd_ctx, mode); + +tdls_ant_sw_done: + return 0; +} + +/** + * wlan_hdd_change_tdls_mode - Change TDLS mode + * @data: void pointer + * + * Return: None + */ +void wlan_hdd_change_tdls_mode(void *data) +{ + hdd_context_t *hdd_ctx = (hdd_context_t *)data; + + wlan_hdd_tdls_set_mode(hdd_ctx, hdd_ctx->tdls_mode_last, false, + HDD_SET_TDLS_MODE_SOURCE_P2P); +} + +void hdd_tdls_notify_p2p_roc(hdd_context_t *hdd_ctx, + enum tdls_concerned_external_events event) +{ + eTDLSSupportMode tdls_mode; + uint16_t connectedTdlsPeers; + bool buf_sta, enable_tdls_scan; + + qdf_mc_timer_stop(&hdd_ctx->tdls_source_timer); + + if (event == P2P_ROC_START) { + tdls_mode = eTDLS_SUPPORT_DISABLED; + wlan_hdd_tdls_set_mode(hdd_ctx, tdls_mode, false, + HDD_SET_TDLS_MODE_SOURCE_P2P); + + connectedTdlsPeers = hdd_ctx->connected_peer_count; + if (!connectedTdlsPeers) + goto start_timer; + + + enable_tdls_scan = + wlan_hdd_tdls_check_enable_tdls_scan(hdd_ctx); + + hdd_debug("enable_tdls_scan %d", enable_tdls_scan); + + if (enable_tdls_scan) { + hdd_debug("Do not teardown tdls links"); + goto start_timer; + } + + mutex_lock(&hdd_ctx->tdls_lock); + buf_sta = wlan_hdd_tdls_check_peer_buf_capable(hdd_ctx, + connectedTdlsPeers); + mutex_unlock(&hdd_ctx->tdls_lock); + + hdd_debug("buf_sta %d, connected peers %d, sleep sta %d", + buf_sta, connectedTdlsPeers, + hdd_ctx->config->fEnableTDLSSleepSta); + + if (!buf_sta) { + hdd_debug("teardown tdls links"); + wlan_hdd_tdls_disable_offchan_and_teardown_links( + hdd_ctx); + } + } + +start_timer: + qdf_mc_timer_start(&hdd_ctx->tdls_source_timer, + hdd_ctx->config->tdls_enable_defer_time); + + return; +} diff --git a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_trace.c b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_trace.c new file mode 100644 index 0000000000000000000000000000000000000000..5955307a9b48df4f82dbb89c6143d8399b542b7e --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_trace.c @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2014-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifdef HDD_TRACE_RECORD + +/** + * DOC: wlan_hdd_trace.c + * + * WLAN Host Device Driver trace implementation + * + */ + +#include "qdf_trace.h" +#include "qdf_types.h" +#include "wlan_hdd_trace.h" +#include "wlan_hdd_main.h" + +/** + * hdd_trace_dump() - Dump an HDD-specific trace record + * @mac: (unused) global MAC handle + * @record: trace record that was previously recorded + * @index: index of the trace record + * + * Return: none + */ +static void +hdd_trace_dump(void *mac, tp_qdf_trace_record record, uint16_t index) +{ + if (TRACE_CODE_HDD_RX_SME_MSG == record->code) + hdd_info("%04d %012llu %s S%d %-14s %-30s(0x%x)", + index, record->qtime, record->time, record->session, + "RX SME MSG:", + get_e_roam_cmd_status_str(record->data), record->data); + else + hdd_info("%04d %012llu %s S%d %-14s %-30s(0x%x)", + index, record->qtime, record->time, record->session, + "HDD Event:", + hdd_trace_event_string(record->code), record->data); +} + +/** + * hdd_trace_init() - HDD trace subsystem initialization + * + * Registers HDD with the debug trace subsystem + * + * Return: none + */ +void hdd_trace_init(void) +{ + qdf_trace_register(QDF_MODULE_ID_HDD, hdd_trace_dump); +} + +#endif /* ifdef HDD_TRACE_RECORD */ diff --git a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_tsf.c b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_tsf.c new file mode 100644 index 0000000000000000000000000000000000000000..30a74fee78f64b00f2c8e6ff2f68fef02f521d36 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_tsf.c @@ -0,0 +1,406 @@ +/* + * Copyright (c) 2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * wlan_hdd_tsf.c - WLAN Host Device Driver tsf related implementation + */ + +#include "wlan_hdd_main.h" +#include "wlan_hdd_tsf.h" +#include "wma_api.h" + +static struct completion tsf_sync_get_completion_evt; +#define WLAN_TSF_SYNC_GET_TIMEOUT 2000 +/** + * hdd_capture_tsf() - capture tsf + * @adapter: pointer to adapter + * @buf: pointer to uplayer buf + * @len : the length of buf + * + * This function returns tsf value to uplayer. + * + * Return: 0 for success or non-zero negative failure code + */ +int hdd_capture_tsf(struct hdd_adapter_s *adapter, uint32_t *buf, int len) +{ + int ret = 0; + hdd_station_ctx_t *hdd_sta_ctx; + + if (adapter == NULL || buf == NULL) { + hdd_err("invalid pointer"); + return -EINVAL; + } + if (len != 1) + return -EINVAL; + + /* Reset TSF value for new capture */ + adapter->tsf_high = 0; + adapter->tsf_low = 0; + adapter->tsf_sync_soc_timer = 0; + + if (adapter->device_mode == QDF_STA_MODE || + adapter->device_mode == QDF_P2P_CLIENT_MODE) { + hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + if (hdd_sta_ctx->conn_info.connState != + eConnectionState_Associated) { + hdd_err("failed to cap tsf, not connect with ap"); + buf[0] = TSF_STA_NOT_CONNECTED_NO_TSF; + return ret; + } + } + if ((adapter->device_mode == QDF_SAP_MODE || + adapter->device_mode == QDF_P2P_GO_MODE) && + !(test_bit(SOFTAP_BSS_STARTED, &adapter->event_flags))) { + hdd_err("Soft AP / P2p GO not beaconing"); + buf[0] = TSF_SAP_NOT_STARTED_NO_TSF; + return ret; + } + if (adapter->tsf_state == TSF_CAP_STATE) { + hdd_err("current in capture state, pls reset"); + buf[0] = TSF_CURRENT_IN_CAP_STATE; + } else { + hdd_info("Send TSF capture to FW"); + buf[0] = TSF_RETURN; + adapter->tsf_state = TSF_CAP_STATE; + init_completion(&tsf_sync_get_completion_evt); + ret = wma_cli_set_command((int)adapter->sessionId, + (int)GEN_PARAM_CAPTURE_TSF, + adapter->sessionId, + GEN_CMD); + + if (ret != QDF_STATUS_SUCCESS) { + hdd_err("capture fail"); + buf[0] = TSF_CAPTURE_FAIL; + adapter->tsf_state = TSF_IDLE; + } + } + return ret; +} + +/** + * hdd_tsf_reset_gpio() - Reset TSF GPIO used for host timer sync + * @adapter: pointer to adapter + * + * This function send WMI command to reset GPIO configured in FW after + * TSF get operation. + * + * Return: TSF_RETURN on Success, TSF_RESET_GPIO_FAIL on failure + */ +#ifdef QCA_WIFI_3_0 +static int hdd_tsf_reset_gpio(struct hdd_adapter_s *adapter) +{ + /* No GPIO Host timer sync for integrated WIFI Device */ + return TSF_RETURN; +} +#else +static int hdd_tsf_reset_gpio(struct hdd_adapter_s *adapter) +{ + int ret; + ret = wma_cli_set_command((int)adapter->sessionId, + (int)GEN_PARAM_RESET_TSF_GPIO, adapter->sessionId, + GEN_CMD); + + if (ret != 0) { + hdd_err("tsf reset GPIO fail "); + ret = TSF_RESET_GPIO_FAIL; + } else { + ret = TSF_RETURN; + } + return ret; +} +#endif + +/** + * hdd_indicate_tsf() - return tsf to uplayer + * @adapter: pointer to adapter + * @buf: pointer to uplayer buf + * @len : the length of buf + * + * This function returns tsf value to upper layer. + * + * Return: 0 for success or non-zero negative failure code + */ +int hdd_indicate_tsf(struct hdd_adapter_s *adapter, uint32_t *buf, int len) +{ + hdd_station_ctx_t *hdd_sta_ctx; + + if (adapter == NULL || buf == NULL) { + hdd_err("invalid pointer"); + return -EINVAL; + } + + if (len != 3) + return -EINVAL; + + buf[1] = 0; + buf[2] = 0; + if (adapter->device_mode == QDF_STA_MODE || + adapter->device_mode == QDF_P2P_CLIENT_MODE) { + hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + if (hdd_sta_ctx->conn_info.connState != + eConnectionState_Associated) { + hdd_info("fail to get tsf, sta in disconnected"); + buf[0] = TSF_STA_NOT_CONNECTED_NO_TSF; + return 0; + } + } + if ((adapter->device_mode == QDF_SAP_MODE || + adapter->device_mode == QDF_P2P_GO_MODE) && + !(test_bit(SOFTAP_BSS_STARTED, + &adapter->event_flags))) { + hdd_err("Soft AP / P2p GO not beaconing"); + buf[0] = TSF_SAP_NOT_STARTED_NO_TSF; + return 0; + } + if (adapter->tsf_high == 0 && adapter->tsf_low == 0) { + hdd_info("TSF value not received"); + buf[0] = TSF_NOT_RETURNED_BY_FW; + } else { + buf[0] = hdd_tsf_reset_gpio(adapter); + buf[1] = adapter->tsf_low; + buf[2] = adapter->tsf_high; + adapter->tsf_state = TSF_IDLE; + hdd_info("get tsf cmd,status=%u, tsf_low=%u, tsf_high=%u", + buf[0], buf[1], buf[2]); + } + return 0; +} + +/** + * hdd_get_tsf_cb() - handle tsf callback + * @pcb_cxt: pointer to the hdd_contex + * @ptsf: pointer to struct stsf + * + * This function handle the event that reported by firmware at first. + * The event contains the vdev_id, current tsf value of this vdev, + * tsf value is 64bits, discripted in two varaible tsf_low and tsf_high. + * These two values each is uint32. + * + * Return: 0 for success or non-zero negative failure code + */ +int hdd_get_tsf_cb(void *pcb_cxt, struct stsf *ptsf) +{ + struct hdd_context_s *hddctx; + struct hdd_adapter_s *adapter; + int status; + + if (pcb_cxt == NULL || ptsf == NULL) { + hdd_err("HDD context is not valid"); + return -EINVAL; + } + + hddctx = (struct hdd_context_s *)pcb_cxt; + status = wlan_hdd_validate_context(hddctx); + if (0 != status) { + return -EINVAL; + } + + adapter = hdd_get_adapter_by_vdev(hddctx, ptsf->vdev_id); + + if (NULL == adapter) { + hdd_err("failed to find adapter"); + return -EINVAL; + } + hdd_info("tsf cb handle event, device_mode is %d", + adapter->device_mode); + + adapter->tsf_low = ptsf->tsf_low; + adapter->tsf_high = ptsf->tsf_high; + adapter->tsf_sync_soc_timer = ((uint64_t) ptsf->soc_timer_high << 32 | + ptsf->soc_timer_low); + + complete(&tsf_sync_get_completion_evt); + hdd_info("Vdev=%u, tsf_low=%u, tsf_high=%u soc_timer=%llu", + ptsf->vdev_id, ptsf->tsf_low, ptsf->tsf_high, + adapter->tsf_sync_soc_timer); + return 0; +} + +static const struct nla_policy tsf_policy[QCA_WLAN_VENDOR_ATTR_TSF_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_TSF_CMD] = {.type = NLA_U32}, +}; + +/** + * __wlan_hdd_cfg80211_handle_tsf_cmd(): Setup TSF operations + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Data length + * + * Handle TSF SET / GET operation from userspace + * + * Return: 0 on success, negative errno on failure + */ +static int __wlan_hdd_cfg80211_handle_tsf_cmd(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + struct net_device *dev = wdev->netdev; + hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *hdd_ctx = wiphy_priv(wiphy); + struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_TSF_MAX + 1]; + int status, ret; + struct sk_buff *reply_skb; + uint32_t tsf_op_resp[3], tsf_cmd; + + ENTER_DEV(wdev->netdev); + + status = wlan_hdd_validate_context(hdd_ctx); + if (0 != status) + return -EINVAL; + + if (nla_parse(tb_vendor, QCA_WLAN_VENDOR_ATTR_TSF_MAX, data, + data_len, tsf_policy)) { + hdd_err("Invalid TSF cmd"); + return -EINVAL; + } + + if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_TSF_CMD]) { + hdd_err("Invalid TSF cmd"); + return -EINVAL; + } + tsf_cmd = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_TSF_CMD]); + + if (tsf_cmd == QCA_TSF_CAPTURE || tsf_cmd == QCA_TSF_SYNC_GET) { + hdd_capture_tsf(adapter, tsf_op_resp, 1); + switch (tsf_op_resp[0]) { + case TSF_RETURN: + status = 0; + break; + case TSF_CURRENT_IN_CAP_STATE: + status = -EALREADY; + break; + case TSF_STA_NOT_CONNECTED_NO_TSF: + case TSF_SAP_NOT_STARTED_NO_TSF: + status = -EPERM; + break; + default: + case TSF_CAPTURE_FAIL: + status = -EINVAL; + break; + } + } + if (status < 0) + goto end; + + if (tsf_cmd == QCA_TSF_SYNC_GET) { + ret = wait_for_completion_timeout(&tsf_sync_get_completion_evt, + msecs_to_jiffies(WLAN_TSF_SYNC_GET_TIMEOUT)); + if (ret == 0) { + status = -ETIMEDOUT; + goto end; + } + } + + if (tsf_cmd == QCA_TSF_GET || tsf_cmd == QCA_TSF_SYNC_GET) { + hdd_indicate_tsf(adapter, tsf_op_resp, 3); + switch (tsf_op_resp[0]) { + case TSF_RETURN: + status = 0; + break; + case TSF_NOT_RETURNED_BY_FW: + status = -EINPROGRESS; + break; + case TSF_STA_NOT_CONNECTED_NO_TSF: + case TSF_SAP_NOT_STARTED_NO_TSF: + status = -EPERM; + break; + default: + status = -EINVAL; + break; + } + if (status != 0) + goto end; + + reply_skb = cfg80211_vendor_event_alloc(hdd_ctx->wiphy, NULL, + sizeof(uint64_t) * 2 + NLMSG_HDRLEN, + QCA_NL80211_VENDOR_SUBCMD_TSF_INDEX, + GFP_KERNEL); + if (!reply_skb) { + hdd_err("cfg80211_vendor_cmd_alloc_reply_skb failed"); + status = -ENOMEM; + goto end; + } + if (hdd_wlan_nla_put_u64(reply_skb, + QCA_WLAN_VENDOR_ATTR_TSF_TIMER_VALUE, + ((uint64_t) adapter->tsf_high << 32 | + adapter->tsf_low)) || + hdd_wlan_nla_put_u64(reply_skb, + QCA_WLAN_VENDOR_ATTR_TSF_SOC_TIMER_VALUE, + adapter->tsf_sync_soc_timer)) { + hdd_err("nla put fail"); + kfree_skb(reply_skb); + status = -EINVAL; + goto end; + } + status = cfg80211_vendor_cmd_reply(reply_skb); + } + +end: + hdd_info("TSF operation %d Status: %d", tsf_cmd, status); + return status; +} + +/** + * wlan_hdd_cfg80211_handle_tsf_cmd(): Setup TSF operations + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Data length + * + * Handle TSF SET / GET operation from userspace + * + * Return: 0 on success, negative errno on failure + */ +int wlan_hdd_cfg80211_handle_tsf_cmd(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_cfg80211_handle_tsf_cmd(wiphy, wdev, data, data_len); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * wlan_hdd_tsf_init() - set callback to handle tsf value. + * @hdd_ctx: pointer to the struct hdd_context_s + * + * This function set the callback to sme module, the callback will be + * called when a tsf event is reported by firmware + * + * Return: none + */ +void wlan_hdd_tsf_init(struct hdd_context_s *hdd_ctx) +{ + sme_set_tsfcb(hdd_ctx->hHal, hdd_get_tsf_cb, hdd_ctx); +} diff --git a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_tx_rx.c b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_tx_rx.c new file mode 100644 index 0000000000000000000000000000000000000000..033bc3b65241a131e8d18a8f956e252186cd4cf5 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_tx_rx.c @@ -0,0 +1,1706 @@ +/* + * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: wlan_hdd_tx_rx.c + * + * Linux HDD Tx/RX APIs + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include "sap_api.h" +#include "wlan_hdd_wmm.h" +#include "wlan_hdd_tdls.h" +#include +#include "wlan_hdd_ocb.h" +#include "wlan_hdd_lro.h" +#include "cdp_txrx_peer_ops.h" +#include "ol_txrx.h" +#include "wlan_hdd_nan_datapath.h" +#include "pld_common.h" + +#ifdef QCA_LL_TX_FLOW_CONTROL_V2 +/* + * Mapping Linux AC interpretation to SME AC. + * Host has 5 tx queues, 4 flow-controlled queues for regular traffic and + * one non-flow-controlled queue for high priority control traffic(EOPOL, DHCP). + * The fifth queue is mapped to AC_VO to allow for proper prioritization. + */ +const uint8_t hdd_qdisc_ac_to_tl_ac[] = { + SME_AC_VO, + SME_AC_VI, + SME_AC_BE, + SME_AC_BK, + SME_AC_VO, +}; + +#else +const uint8_t hdd_qdisc_ac_to_tl_ac[] = { + SME_AC_VO, + SME_AC_VI, + SME_AC_BE, + SME_AC_BK, +}; + +#endif + +#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL +/** + * hdd_tx_resume_timer_expired_handler() - TX Q resume timer handler + * @adapter_context: pointer to vdev adapter + * + * If Blocked OS Q is not resumed during timeout period, to prevent + * permanent stall, resume OS Q forcefully. + * + * Return: None + */ +void hdd_tx_resume_timer_expired_handler(void *adapter_context) +{ + hdd_adapter_t *pAdapter = (hdd_adapter_t *) adapter_context; + + if (!pAdapter) { + /* INVALID ARG */ + return; + } + + hdd_notice("Enabling queues"); + wlan_hdd_netif_queue_control(pAdapter, WLAN_WAKE_ALL_NETIF_QUEUE, + WLAN_CONTROL_PATH); + return; +} +#if defined(CONFIG_PER_VDEV_TX_DESC_POOL) + +/** + * hdd_tx_resume_false() - Resume OS TX Q false leads to queue disabling + * @pAdapter: pointer to hdd adapter + * @tx_resume: TX Q resume trigger + * + * + * Return: None + */ +static void +hdd_tx_resume_false(hdd_adapter_t *pAdapter, bool tx_resume) +{ + if (true == tx_resume) + return; + + /* Pause TX */ + hdd_notice("Disabling queues"); + wlan_hdd_netif_queue_control(pAdapter, WLAN_STOP_ALL_NETIF_QUEUE, + WLAN_DATA_FLOW_CONTROL); + + if (QDF_TIMER_STATE_STOPPED == + qdf_mc_timer_get_current_state(&pAdapter-> + tx_flow_control_timer)) { + QDF_STATUS status; + status = qdf_mc_timer_start(&pAdapter->tx_flow_control_timer, + WLAN_HDD_TX_FLOW_CONTROL_OS_Q_BLOCK_TIME); + + if (!QDF_IS_STATUS_SUCCESS(status)) + hdd_err("Failed to start tx_flow_control_timer"); + else + pAdapter->hdd_stats.hddTxRxStats.txflow_timer_cnt++; + } + + pAdapter->hdd_stats.hddTxRxStats.txflow_pause_cnt++; + pAdapter->hdd_stats.hddTxRxStats.is_txflow_paused = true; + + return; +} +#else + +static inline void +hdd_tx_resume_false(hdd_adapter_t *pAdapter, bool tx_resume) +{ + return; +} +#endif + +static inline struct sk_buff *hdd_skb_orphan(hdd_adapter_t *pAdapter, + struct sk_buff *skb) +{ + if (pAdapter->tx_flow_low_watermark > 0) + skb_orphan(skb); + else { + skb = skb_unshare(skb, GFP_ATOMIC); + } + + return skb; +} + +/** + * hdd_tx_resume_cb() - Resume OS TX Q. + * @adapter_context: pointer to vdev apdapter + * @tx_resume: TX Q resume trigger + * + * Q was stopped due to WLAN TX path low resource condition + * + * Return: None + */ +void hdd_tx_resume_cb(void *adapter_context, bool tx_resume) +{ + hdd_adapter_t *pAdapter = (hdd_adapter_t *) adapter_context; + hdd_station_ctx_t *hdd_sta_ctx = NULL; + + if (!pAdapter) { + /* INVALID ARG */ + return; + } + + hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + + /* Resume TX */ + if (true == tx_resume) { + if (QDF_TIMER_STATE_STOPPED != + qdf_mc_timer_get_current_state(&pAdapter-> + tx_flow_control_timer)) { + qdf_mc_timer_stop(&pAdapter->tx_flow_control_timer); + } + hdd_notice("Enabling queues"); + wlan_hdd_netif_queue_control(pAdapter, + WLAN_WAKE_ALL_NETIF_QUEUE, + WLAN_DATA_FLOW_CONTROL); + } + hdd_tx_resume_false(pAdapter, tx_resume); + + return; +} + +/** + * hdd_register_tx_flow_control() - Register TX Flow control + * @adapter: adapter handle + * @timer_callback: timer callback + * @flow_control_fp: txrx flow control + * + * Return: none + */ +void hdd_register_tx_flow_control(hdd_adapter_t *adapter, + qdf_mc_timer_callback_t timer_callback, + ol_txrx_tx_flow_control_fp flow_control_fp) +{ + if (adapter->tx_flow_timer_initialized == false) { + qdf_mc_timer_init(&adapter->tx_flow_control_timer, + QDF_TIMER_TYPE_SW, + timer_callback, + adapter); + adapter->tx_flow_timer_initialized = true; + } + ol_txrx_register_tx_flow_control(adapter->sessionId, + flow_control_fp, + adapter); + +} + +/** + * hdd_deregister_tx_flow_control() - Deregister TX Flow control + * @adapter: adapter handle + * + * Return: none + */ +void hdd_deregister_tx_flow_control(hdd_adapter_t *adapter) +{ + ol_txrx_deregister_tx_flow_control_cb(adapter->sessionId); + if (adapter->tx_flow_timer_initialized == true) { + qdf_mc_timer_stop(&adapter->tx_flow_control_timer); + qdf_mc_timer_destroy(&adapter->tx_flow_control_timer); + adapter->tx_flow_timer_initialized = false; + } +} + +/** + * hdd_get_tx_resource() - check tx resources and take action + * @adapter: adapter handle + * @STAId: station id + * @timer_value: timer value + * + * Return: none + */ +void hdd_get_tx_resource(hdd_adapter_t *adapter, + uint8_t STAId, uint16_t timer_value) +{ + if (false == + ol_txrx_get_tx_resource(STAId, + adapter->tx_flow_low_watermark, + adapter->tx_flow_high_watermark_offset)) { + hdd_info("Disabling queues lwm %d hwm offset %d", + adapter->tx_flow_low_watermark, + adapter->tx_flow_high_watermark_offset); + wlan_hdd_netif_queue_control(adapter, WLAN_STOP_ALL_NETIF_QUEUE, + WLAN_DATA_FLOW_CONTROL); + if ((adapter->tx_flow_timer_initialized == true) && + (QDF_TIMER_STATE_STOPPED == + qdf_mc_timer_get_current_state(&adapter-> + tx_flow_control_timer))) { + qdf_mc_timer_start(&adapter->tx_flow_control_timer, + timer_value); + adapter->hdd_stats.hddTxRxStats.txflow_timer_cnt++; + adapter->hdd_stats.hddTxRxStats.txflow_pause_cnt++; + adapter->hdd_stats.hddTxRxStats.is_txflow_paused = true; + } + } +} + +#else +/** + * hdd_skb_orphan() - skb_unshare a cloned packed else skb_orphan + * @pAdapter: pointer to HDD adapter + * @skb: pointer to skb data packet + * + * Return: pointer to skb structure + */ +static struct sk_buff *hdd_skb_orphan(hdd_adapter_t *pAdapter, + struct sk_buff *skb) { + + struct sk_buff *nskb; + hdd_context_t *hdd_ctx = pAdapter->pHddCtx; + + nskb = skb_unshare(skb, GFP_ATOMIC); + if (unlikely(hdd_ctx->config->tx_orphan_enable) && (nskb == skb)) { + /* + * For UDP packets we want to orphan the packet to allow the app + * to send more packets. The flow would ultimately be controlled + * by the limited number of tx descriptors for the vdev. + */ + ++pAdapter->hdd_stats.hddTxRxStats.txXmitOrphaned; + skb_orphan(skb); + } + return nskb; +} +#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */ + +/** + * qdf_event_eapol_log() - send event to wlan diag + * @skb: skb ptr + * @dir: direction + * @eapol_key_info: eapol key info + * + * Return: None + */ +void hdd_event_eapol_log(struct sk_buff *skb, enum qdf_proto_dir dir) +{ + int16_t eapol_key_info; + + WLAN_HOST_DIAG_EVENT_DEF(wlan_diag_event, struct host_event_wlan_eapol); + + if ((dir == QDF_TX && + (QDF_NBUF_CB_PACKET_TYPE_EAPOL != + QDF_NBUF_CB_GET_PACKET_TYPE(skb)))) + return; + else if (!qdf_nbuf_is_ipv4_eapol_pkt(skb)) + return; + + eapol_key_info = (uint16_t)(*(uint16_t *) + (skb->data + EAPOL_KEY_INFO_OFFSET)); + + wlan_diag_event.event_sub_type = + (dir == QDF_TX ? + WIFI_EVENT_DRIVER_EAPOL_FRAME_TRANSMIT_REQUESTED : + WIFI_EVENT_DRIVER_EAPOL_FRAME_RECEIVED); + wlan_diag_event.eapol_packet_type = (uint8_t)(*(uint8_t *) + (skb->data + EAPOL_PACKET_TYPE_OFFSET)); + wlan_diag_event.eapol_key_info = eapol_key_info; + wlan_diag_event.eapol_rate = 0; + qdf_mem_copy(wlan_diag_event.dest_addr, + (skb->data + QDF_NBUF_DEST_MAC_OFFSET), + sizeof(wlan_diag_event.dest_addr)); + qdf_mem_copy(wlan_diag_event.src_addr, + (skb->data + QDF_NBUF_SRC_MAC_OFFSET), + sizeof(wlan_diag_event.src_addr)); + + WLAN_HOST_DIAG_EVENT_REPORT(&wlan_diag_event, EVENT_WLAN_EAPOL); +} + + +/** + * wlan_hdd_classify_pkt() - classify packet + * @skb - sk buff + * + * Return: none + */ +void wlan_hdd_classify_pkt(struct sk_buff *skb) +{ + struct ethhdr *eh = (struct ethhdr *)skb->data; + + qdf_mem_set(skb->cb, sizeof(skb->cb), 0); + + /* check destination mac address is broadcast/multicast */ + if (is_broadcast_ether_addr((uint8_t *)eh)) + QDF_NBUF_CB_GET_IS_BCAST(skb) = true; + else if (is_multicast_ether_addr((uint8_t *)eh)) + QDF_NBUF_CB_GET_IS_MCAST(skb) = true; + + if (qdf_nbuf_is_ipv4_arp_pkt(skb)) + QDF_NBUF_CB_GET_PACKET_TYPE(skb) = + QDF_NBUF_CB_PACKET_TYPE_ARP; + else if (qdf_nbuf_is_ipv4_dhcp_pkt(skb)) + QDF_NBUF_CB_GET_PACKET_TYPE(skb) = + QDF_NBUF_CB_PACKET_TYPE_DHCP; + else if (qdf_nbuf_is_ipv4_eapol_pkt(skb)) + QDF_NBUF_CB_GET_PACKET_TYPE(skb) = + QDF_NBUF_CB_PACKET_TYPE_EAPOL; + else if (qdf_nbuf_is_ipv4_wapi_pkt(skb)) + QDF_NBUF_CB_GET_PACKET_TYPE(skb) = + QDF_NBUF_CB_PACKET_TYPE_WAPI; + +} + +/** + * hdd_get_transmit_sta_id() - function to retrieve station id to be used for + * sending traffic towards a particular destination address. The destination + * address can be unicast, multicast or broadcast + * + * @adapter: Handle to adapter context + * @dst_addr: Destination address + * @station_id: station id + * + * Returns: None + */ +static void hdd_get_transmit_sta_id(hdd_adapter_t *adapter, + struct sk_buff *skb, uint8_t *station_id) +{ + bool mcbc_addr = false; + hdd_station_ctx_t *sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + struct qdf_mac_addr *dst_addr = NULL; + + dst_addr = (struct qdf_mac_addr *)skb->data; + hdd_get_peer_sta_id(sta_ctx, dst_addr, station_id); + if (*station_id == HDD_WLAN_INVALID_STA_ID) { + if (QDF_NBUF_CB_GET_IS_BCAST(skb) || + QDF_NBUF_CB_GET_IS_MCAST(skb)) { + hdd_info("Received MC/BC packet for transmission"); + mcbc_addr = true; + } + } + + if (adapter->device_mode == QDF_IBSS_MODE || + adapter->device_mode == QDF_NDI_MODE) { + /* + * This check is necessary to make sure station id is not + * overwritten for UC traffic in IBSS or NDI mode + */ + if (mcbc_addr) + *station_id = sta_ctx->broadcast_staid; + } else { + /* For the rest, traffic is directed to AP/P2P GO */ + if (eConnectionState_Associated == sta_ctx->conn_info.connState) + *station_id = sta_ctx->conn_info.staId[0]; + } +} + +/** + * __hdd_hard_start_xmit() - Transmit a frame + * @skb: pointer to OS packet (sk_buff) + * @dev: pointer to network device + * + * Function registered with the Linux OS for transmitting + * packets. This version of the function directly passes + * the packet to Transport Layer. + * In case of any packet drop or error, log the error with + * INFO HIGH/LOW/MEDIUM to avoid excessive logging in kmsg. + * + * Return: Always returns NETDEV_TX_OK + */ +static int __hdd_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + QDF_STATUS status; + sme_ac_enum_type ac; + sme_QosWmmUpType up; + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + bool granted; + uint8_t STAId; + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(pAdapter); + hdd_station_ctx_t *pHddStaCtx = &pAdapter->sessionCtx.station; +#ifdef QCA_PKT_PROTO_TRACE + uint8_t proto_type = 0; +#endif /* QCA_PKT_PROTO_TRACE */ + bool is_arp = false; + +#ifdef QCA_WIFI_FTM + if (hdd_get_conparam() == QDF_GLOBAL_FTM_MODE) { + kfree_skb(skb); + return NETDEV_TX_OK; + } +#endif + + wlan_hdd_classify_pkt(skb); + + ++pAdapter->hdd_stats.hddTxRxStats.txXmitCalled; + + if (QDF_NBUF_CB_GET_PACKET_TYPE(skb) == QDF_NBUF_CB_PACKET_TYPE_ARP) { + is_arp = true; + if (qdf_nbuf_data_is_arp_req(skb) && + (hdd_ctx->track_arp_ip == qdf_nbuf_get_arp_tgt_ip(skb))) { + ++pAdapter->hdd_stats.hdd_arp_stats.tx_arp_req_count; + QDF_TRACE(QDF_MODULE_ID_HDD_DATA, + QDF_TRACE_LEVEL_INFO_HIGH, + "%s : ARP packet", __func__); + } + } + + if (cds_is_driver_recovering()) { + QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_INFO_HIGH, + "Recovery in progress, dropping the packet"); + goto drop_pkt; + } + + STAId = HDD_WLAN_INVALID_STA_ID; + + hdd_get_transmit_sta_id(pAdapter, skb, &STAId); + if (STAId >= WLAN_MAX_STA_COUNT) { + QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_INFO_HIGH, + "Invalid station id, transmit operation suspended"); + goto drop_pkt; + } + + hdd_get_tx_resource(pAdapter, STAId, + WLAN_HDD_TX_FLOW_CONTROL_OS_Q_BLOCK_TIME); + + /* Get TL AC corresponding to Qdisc queue index/AC. */ + ac = hdd_qdisc_ac_to_tl_ac[skb->queue_mapping]; + + if (!qdf_nbuf_ipa_owned_get(skb)) { +#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 19, 0)) + /* + * The TCP TX throttling logic is changed a little after + * 3.19-rc1 kernel, the TCP sending limit will be smaller, + * which will throttle the TCP packets to the host driver. + * The TCP UP LINK throughput will drop heavily. In order to + * fix this issue, need to orphan the socket buffer asap, which + * will call skb's destructor to notify the TCP stack that the + * SKB buffer is unowned. And then the TCP stack will pump more + * packets to host driver. + * + * The TX packets might be dropped for UDP case in the iperf + * testing. So need to be protected by follow control. + */ + skb = hdd_skb_orphan(pAdapter, skb); +#else + /* Check if the buffer has enough header room */ + skb = skb_unshare(skb, GFP_ATOMIC); +#endif + + if (!skb) + goto drop_pkt_accounting; + } + + /* + * user priority from IP header, which is already extracted and set from + * select_queue call back function + */ + up = skb->priority; + + ++pAdapter->hdd_stats.hddTxRxStats.txXmitClassifiedAC[ac]; +#ifdef HDD_WMM_DEBUG + QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_FATAL, + "%s: Classified as ac %d up %d", __func__, ac, up); +#endif /* HDD_WMM_DEBUG */ + + if (HDD_PSB_CHANGED == pAdapter->psbChanged) { + /* + * Function which will determine acquire admittance for a + * WMM AC is required or not based on psb configuration done + * in the framework + */ + hdd_wmm_acquire_access_required(pAdapter, ac); + } + /* + * Make sure we already have access to this access category + * or it is EAPOL or WAPI frame during initial authentication which + * can have artifically boosted higher qos priority. + */ + + if (((pAdapter->psbChanged & (1 << ac)) && + likely(pAdapter->hddWmmStatus.wmmAcStatus[ac]. + wmmAcAccessAllowed)) || + ((pHddStaCtx->conn_info.uIsAuthenticated == false) && + (QDF_NBUF_CB_PACKET_TYPE_EAPOL == + QDF_NBUF_CB_GET_PACKET_TYPE(skb) || + QDF_NBUF_CB_PACKET_TYPE_WAPI == + QDF_NBUF_CB_GET_PACKET_TYPE(skb)))) { + granted = true; + } else { + status = hdd_wmm_acquire_access(pAdapter, ac, &granted); + pAdapter->psbChanged |= (1 << ac); + } + + if (!granted) { + bool isDefaultAc = false; + /* + * ADDTS request for this AC is sent, for now + * send this packet through next avaiable lower + * Access category until ADDTS negotiation completes. + */ + while (!likely + (pAdapter->hddWmmStatus.wmmAcStatus[ac]. + wmmAcAccessAllowed)) { + switch (ac) { + case SME_AC_VO: + ac = SME_AC_VI; + up = SME_QOS_WMM_UP_VI; + break; + case SME_AC_VI: + ac = SME_AC_BE; + up = SME_QOS_WMM_UP_BE; + break; + case SME_AC_BE: + ac = SME_AC_BK; + up = SME_QOS_WMM_UP_BK; + break; + default: + ac = SME_AC_BK; + up = SME_QOS_WMM_UP_BK; + isDefaultAc = true; + break; + } + if (isDefaultAc) + break; + } + skb->priority = up; + skb->queue_mapping = hdd_linux_up_to_ac_map[up]; + } + +#ifdef QCA_PKT_PROTO_TRACE + if ((hdd_ctx->config->gEnableDebugLog & CDS_PKT_TRAC_TYPE_EAPOL) || + (hdd_ctx->config->gEnableDebugLog & CDS_PKT_TRAC_TYPE_DHCP)) { + proto_type = cds_pkt_get_proto_type(skb, + hdd_ctx->config->gEnableDebugLog, + 0); + if (CDS_PKT_TRAC_TYPE_EAPOL & proto_type) { + cds_pkt_trace_buf_update("ST:T:EPL"); + } else if (CDS_PKT_TRAC_TYPE_DHCP & proto_type) { + cds_pkt_trace_buf_update("ST:T:DHC"); + } + } +#endif /* QCA_PKT_PROTO_TRACE */ + + pAdapter->stats.tx_bytes += skb->len; + + wlan_hdd_tdls_update_tx_pkt_cnt(pAdapter, skb); + + if (qdf_nbuf_is_tso(skb)) + pAdapter->stats.tx_packets += qdf_nbuf_get_tso_num_seg(skb); + else { + ++pAdapter->stats.tx_packets; + } + + hdd_event_eapol_log(skb, QDF_TX); + qdf_dp_trace_log_pkt(pAdapter->sessionId, skb, QDF_TX); + QDF_NBUF_CB_TX_PACKET_TRACK(skb) = QDF_NBUF_TX_PKT_DATA_TRACK; + QDF_NBUF_UPDATE_TX_PKT_COUNT(skb, QDF_NBUF_TX_PKT_HDD); + + qdf_dp_trace_set_track(skb, QDF_TX); + DPTRACE(qdf_dp_trace(skb, QDF_DP_TRACE_HDD_TX_PACKET_PTR_RECORD, + qdf_nbuf_data_addr(skb), sizeof(qdf_nbuf_data(skb)), + QDF_TX)); + DPTRACE(qdf_dp_trace(skb, QDF_DP_TRACE_HDD_TX_PACKET_RECORD, + (uint8_t *)skb->data, qdf_nbuf_len(skb), QDF_TX)); + if (qdf_nbuf_len(skb) > QDF_DP_TRACE_RECORD_SIZE) { + DPTRACE(qdf_dp_trace(skb, QDF_DP_TRACE_HDD_TX_PACKET_RECORD, + (uint8_t *)&skb->data[QDF_DP_TRACE_RECORD_SIZE], + (qdf_nbuf_len(skb)-QDF_DP_TRACE_RECORD_SIZE), QDF_TX)); + } + + /* Check if station is connected */ + if (OL_TXRX_PEER_STATE_CONN == + pAdapter->aStaInfo[STAId].tlSTAState) { + QDF_TRACE(QDF_MODULE_ID_HDD_DATA, + QDF_TRACE_LEVEL_INFO_HIGH, + "%s: station is not connected..dropping pkt", + __func__); + ++pAdapter->hdd_stats.hddTxRxStats.txXmitDroppedAC[ac]; + goto drop_pkt; + } + + /* + * If a transmit function is not registered, drop packet + */ + if (!pAdapter->tx_fn) { + QDF_TRACE(QDF_MODULE_ID_HDD_SAP_DATA, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: TX function not registered by the data path", + __func__); + ++pAdapter->hdd_stats.hddTxRxStats.txXmitDroppedAC[ac]; + goto drop_pkt; + } + + if (pAdapter->tx_fn(ol_txrx_get_vdev_by_sta_id(STAId), + (qdf_nbuf_t) skb) != NULL) { + QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: Failed to send packet to txrx for staid:%d", + __func__, STAId); + ++pAdapter->hdd_stats.hddTxRxStats.txXmitDroppedAC[ac]; + goto drop_pkt; + } + + netif_trans_update(dev); + + return NETDEV_TX_OK; + +drop_pkt: + + if (skb) { + DPTRACE(qdf_dp_trace(skb, QDF_DP_TRACE_DROP_PACKET_RECORD, + (uint8_t *)skb->data, qdf_nbuf_len(skb), QDF_TX)); + if (qdf_nbuf_len(skb) > QDF_DP_TRACE_RECORD_SIZE) + DPTRACE(qdf_dp_trace(skb, + QDF_DP_TRACE_DROP_PACKET_RECORD, + (uint8_t *)&skb->data[QDF_DP_TRACE_RECORD_SIZE], + (qdf_nbuf_len(skb)-QDF_DP_TRACE_RECORD_SIZE), + QDF_TX)); + + kfree_skb(skb); + } + +drop_pkt_accounting: + + ++pAdapter->stats.tx_dropped; + ++pAdapter->hdd_stats.hddTxRxStats.txXmitDropped; + if (is_arp) { + ++pAdapter->hdd_stats.hdd_arp_stats.tx_dropped; + QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_INFO_HIGH, + "%s : ARP packet dropped", __func__); + } + + return NETDEV_TX_OK; +} + +/** + * hdd_hard_start_xmit() - Wrapper function to protect + * __hdd_hard_start_xmit from SSR + * @skb: pointer to OS packet + * @dev: pointer to net_device structure + * + * Function called by OS if any packet needs to transmit. + * + * Return: Always returns NETDEV_TX_OK + */ +int hdd_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __hdd_hard_start_xmit(skb, dev); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * hdd_get_peer_sta_id() - Get the StationID using the Peer Mac address + * @pHddStaCtx: pointer to HDD Station Context + * @pMacAddress: pointer to Peer Mac address + * @staID: pointer to returned Station Index + * + * Return: QDF_STATUS_SUCCESS/QDF_STATUS_E_FAILURE + */ + +QDF_STATUS hdd_get_peer_sta_id(hdd_station_ctx_t *pHddStaCtx, + struct qdf_mac_addr *pMacAddress, uint8_t *staId) +{ + uint8_t idx; + + for (idx = 0; idx < MAX_PEERS; idx++) { + if (!qdf_mem_cmp(&pHddStaCtx->conn_info.peerMacAddress[idx], + pMacAddress, QDF_MAC_ADDR_SIZE)) { + *staId = pHddStaCtx->conn_info.staId[idx]; + return QDF_STATUS_SUCCESS; + } + } + + return QDF_STATUS_E_FAILURE; +} + +#ifdef FEATURE_WLAN_DIAG_SUPPORT +/** +* hdd_wlan_datastall_sta_event()- send sta datastall information +* +* This Function send send sta datastall status diag event +* +* Return: void. +*/ +static void hdd_wlan_datastall_sta_event(void) +{ + WLAN_HOST_DIAG_EVENT_DEF(sta_data_stall, + struct host_event_wlan_datastall); + qdf_mem_zero(&sta_data_stall, sizeof(sta_data_stall)); + sta_data_stall.reason = STA_TX_TIMEOUT; + WLAN_HOST_DIAG_EVENT_REPORT(&sta_data_stall, EVENT_WLAN_STA_DATASTALL); +} +#else +static inline void hdd_wlan_datastall_sta_event(void) +{ + +} +#endif + +/** + * __hdd_tx_timeout() - TX timeout handler + * @dev: pointer to network device + * + * This function is registered as a netdev ndo_tx_timeout method, and + * is invoked by the kernel if the driver takes too long to transmit a + * frame. + * + * Return: None + */ +static void __hdd_tx_timeout(struct net_device *dev) +{ + hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *hdd_ctx; + struct netdev_queue *txq; + int i = 0; + + TX_TIMEOUT_TRACE(dev, QDF_MODULE_ID_HDD_DATA); + DPTRACE(qdf_dp_trace(NULL, QDF_DP_TRACE_HDD_TX_TIMEOUT, + NULL, 0, QDF_TX)); + + /* Getting here implies we disabled the TX queues for too + * long. Queues are disabled either because of disassociation + * or low resource scenarios. In case of disassociation it is + * ok to ignore this. But if associated, we have do possible + * recovery here + */ + + for (i = 0; i < NUM_TX_QUEUES; i++) { + txq = netdev_get_tx_queue(dev, i); + QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_ERROR, + "Queue%d status: %d txq->trans_start %lu", + i, netif_tx_queue_stopped(txq), txq->trans_start); + } + + QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_INFO, + "carrier state: %d", netif_carrier_ok(dev)); + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + wlan_hdd_display_netif_queue_history(hdd_ctx); + ol_tx_dump_flow_pool_info(); + hdd_wlan_datastall_sta_event(); +} + +/** + * hdd_tx_timeout() - Wrapper function to protect __hdd_tx_timeout from SSR + * @dev: pointer to net_device structure + * + * Function called by OS if there is any timeout during transmission. + * Since HDD simply enqueues packet and returns control to OS right away, + * this would never be invoked + * + * Return: none + */ +void hdd_tx_timeout(struct net_device *dev) +{ + cds_ssr_protect(__func__); + __hdd_tx_timeout(dev); + cds_ssr_unprotect(__func__); +} + +/** + * @hdd_init_tx_rx() - Initialize Tx/RX module + * @pAdapter: pointer to adapter context + * + * Return: QDF_STATUS_E_FAILURE if any errors encountered, + * QDF_STATUS_SUCCESS otherwise + */ +QDF_STATUS hdd_init_tx_rx(hdd_adapter_t *pAdapter) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + + if (NULL == pAdapter) { + hdd_err("pAdapter is NULL"); + QDF_ASSERT(0); + return QDF_STATUS_E_FAILURE; + } + + return status; +} + +/** + * @hdd_deinit_tx_rx() - Deinitialize Tx/RX module + * @pAdapter: pointer to adapter context + * + * Return: QDF_STATUS_E_FAILURE if any errors encountered, + * QDF_STATUS_SUCCESS otherwise + */ +QDF_STATUS hdd_deinit_tx_rx(hdd_adapter_t *pAdapter) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + + if (NULL == pAdapter) { + hdd_err("pAdapter is NULL"); + QDF_ASSERT(0); + return QDF_STATUS_E_FAILURE; + } + + return status; +} + +/** + * hdd_mon_rx_packet_cbk() - Receive callback registered with OL layer. + * @context: [in] pointer to qdf context + * @rxBuf: [in] pointer to rx qdf_nbuf + * + * TL will call this to notify the HDD when one or more packets were + * received for a registered STA. + * + * Return: QDF_STATUS_E_FAILURE if any errors encountered, QDF_STATUS_SUCCESS + * otherwise + */ +static QDF_STATUS hdd_mon_rx_packet_cbk(void *context, qdf_nbuf_t rxbuf) +{ + hdd_adapter_t *adapter; + int rxstat; + struct sk_buff *skb; + struct sk_buff *skb_next; + unsigned int cpu_index; + + /* Sanity check on inputs */ + if ((NULL == context) || (NULL == rxbuf)) { + QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_ERROR, + "%s: Null params being passed", __func__); + return QDF_STATUS_E_FAILURE; + } + + adapter = (hdd_adapter_t *)context; + if ((NULL == adapter) || (WLAN_HDD_ADAPTER_MAGIC != adapter->magic)) { + QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_ERROR, + "invalid adapter %p", adapter); + return QDF_STATUS_E_FAILURE; + } + + cpu_index = wlan_hdd_get_cpu(); + + /* walk the chain until all are processed */ + skb = (struct sk_buff *) rxbuf; + while (NULL != skb) { + skb_next = skb->next; + skb->dev = adapter->dev; + + ++adapter->hdd_stats.hddTxRxStats.rxPackets[cpu_index]; + ++adapter->stats.rx_packets; + adapter->stats.rx_bytes += skb->len; + + /* Remove SKB from internal tracking table before submitting + * it to stack + */ + qdf_net_buf_debug_release_skb(skb); + + /* + * If this is not a last packet on the chain + * Just put packet into backlog queue, not scheduling RX sirq + */ + if (skb->next) { + rxstat = netif_rx(skb); + } else { + /* + * This is the last packet on the chain + * Scheduling rx sirq + */ + rxstat = netif_rx_ni(skb); + } + + if (NET_RX_SUCCESS == rxstat) + ++adapter-> + hdd_stats.hddTxRxStats.rxDelivered[cpu_index]; + else + ++adapter->hdd_stats.hddTxRxStats.rxRefused[cpu_index]; + + skb = skb_next; + } + + adapter->dev->last_rx = jiffies; + + return QDF_STATUS_SUCCESS; +} + +/** + * hdd_get_peer_idx() - Get the idx for given address in peer table + * @sta_ctx: pointer to HDD Station Context + * @addr: pointer to Peer Mac address + * + * Return: index when success else INVALID_PEER_IDX + */ +int hdd_get_peer_idx(hdd_station_ctx_t *sta_ctx, struct qdf_mac_addr *addr) +{ + uint8_t idx; + + for (idx = 0; idx < MAX_PEERS; idx++) { + if (sta_ctx->conn_info.staId[idx] == 0) + continue; + if (qdf_mem_cmp(&sta_ctx->conn_info.peerMacAddress[idx], + addr, sizeof(struct qdf_mac_addr))) + continue; + return idx; + } + + return INVALID_PEER_IDX; +} + +/* + * hdd_is_mcast_replay() - checks if pkt is multicast replay + * @skb: packet skb + * + * Return: true if replayed multicast pkt, false otherwise + */ +static bool hdd_is_mcast_replay(struct sk_buff *skb) +{ + struct ethhdr *eth; + + eth = eth_hdr(skb); + if (unlikely(skb->pkt_type == PACKET_MULTICAST)) { + if (unlikely(ether_addr_equal(eth->h_source, + skb->dev->dev_addr))) + return true; + } + return false; +} + +/** + * hdd_get_arp_src_ip() - get ARP packet src IP address + * @skb: pointer to sk_buff + * + * Return: return src IP address field value of ARP packet. + */ +static uint32_t hdd_get_arp_src_ip(struct sk_buff *skb) +{ + struct arphdr *arp; + unsigned char *arp_ptr; + uint32_t src_ip; + + arp = (struct arphdr *)skb->data; + arp_ptr = (unsigned char *)(arp + 1); + arp_ptr += skb->dev->addr_len; + + memcpy(&src_ip, arp_ptr, QDF_IPV4_ADDR_SIZE); + + return src_ip; +} + +/** + * hdd_is_duplicate_ip_arp() - duplicate address detection + * @skb: pointer to sk_buff + * + * Return: true if duplicate address detected or false otherwise. + */ +static bool hdd_is_duplicate_ip_arp(struct sk_buff *skb) +{ + struct in_ifaddr **ifap = NULL; + struct in_ifaddr *ifa = NULL; + struct in_device *in_dev; + uint32_t arp_ip, if_ip; + + if (NULL == skb) + return false; + + arp_ip = hdd_get_arp_src_ip(skb); + + if (!skb->dev) + return false; + + in_dev = __in_dev_get_rtnl(skb->dev); + if (in_dev) { + for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL; + ifap = &ifa->ifa_next) { + if (!strcmp(skb->dev->name, ifa->ifa_label)) + break; + } + } + + if (ifa && ifa->ifa_local) { + if_ip = ifa->ifa_local; + if (if_ip == arp_ip) + return true; + } + + return false; +} + +/** +* hdd_is_arp_local() - check if local or non local arp +* @skb: pointer to sk_buff +* +* Return: true if local arp or false otherwise. +*/ +static bool hdd_is_arp_local(struct sk_buff *skb) +{ + struct arphdr *arp; + struct in_ifaddr **ifap = NULL; + struct in_ifaddr *ifa = NULL; + struct in_device *in_dev; + unsigned char *arp_ptr; + __be32 tip; + + arp = (struct arphdr *)skb->data; + if (arp->ar_op == htons(ARPOP_REQUEST)) { + in_dev = __in_dev_get_rtnl(skb->dev); + if (in_dev) { + for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL; + ifap = &ifa->ifa_next) { + if (!strcmp(skb->dev->name, ifa->ifa_label)) + break; + } + } + + if (ifa && ifa->ifa_local) { + arp_ptr = (unsigned char *)(arp + 1); + arp_ptr += (skb->dev->addr_len + 4 + + skb->dev->addr_len); + memcpy(&tip, arp_ptr, 4); + hdd_info("ARP packet: local IP: %x dest IP: %x", + ifa->ifa_local, tip); + if (ifa->ifa_local == tip) + return true; + } + } + + return false; +} + +/** + * hdd_is_rx_wake_lock_needed() - check if wake lock is needed + * @skb: pointer to sk_buff + * + * RX wake lock is needed for: + * 1) Unicast data packet OR + * 2) Local ARP data packet + * + * Return: true if wake lock is needed or false otherwise. + */ +static bool hdd_is_rx_wake_lock_needed(struct sk_buff *skb) +{ + if ((skb->pkt_type != PACKET_BROADCAST && + skb->pkt_type != PACKET_MULTICAST) || hdd_is_arp_local(skb)) + return true; + + return false; +} + +/** + * hdd_rx_packet_cbk() - Receive packet handler + * @context: pointer to HDD context + * @rxBuf: pointer to rx qdf_nbuf + * + * Receive callback registered with TL. TL will call this to notify + * the HDD when one or more packets were received for a registered + * STA. + * + * Return: QDF_STATUS_E_FAILURE if any errors encountered, + * QDF_STATUS_SUCCESS otherwise + */ +QDF_STATUS hdd_rx_packet_cbk(void *context, qdf_nbuf_t rxBuf) +{ + hdd_adapter_t *pAdapter = NULL; + hdd_context_t *pHddCtx = NULL; + int rxstat; + struct sk_buff *skb = NULL; + hdd_station_ctx_t *pHddStaCtx = NULL; + unsigned int cpu_index; + bool wake_lock = false; + bool is_arp = false; + bool track_arp = false; + + /* Sanity check on inputs */ + if (unlikely((NULL == context) || (NULL == rxBuf))) { + QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_ERROR, + "%s: Null params being passed", __func__); + return QDF_STATUS_E_FAILURE; + } + + pAdapter = (hdd_adapter_t *)context; + if (unlikely(WLAN_HDD_ADAPTER_MAGIC != pAdapter->magic)) { + QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_FATAL, + "Magic cookie(%x) for adapter sanity verification is invalid", + pAdapter->magic); + return QDF_STATUS_E_FAILURE; + } + + pHddCtx = pAdapter->pHddCtx; + if (unlikely(NULL == pHddCtx)) { + QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_ERROR, + "%s: HDD context is Null", __func__); + return QDF_STATUS_E_FAILURE; + } + + cpu_index = wlan_hdd_get_cpu(); + + skb = (struct sk_buff *)rxBuf; + + if (QDF_NBUF_CB_PACKET_TYPE_ARP == QDF_NBUF_CB_GET_PACKET_TYPE(skb)) { + is_arp = true; + if (qdf_nbuf_data_is_arp_rsp(skb) && + (pHddCtx->track_arp_ip == qdf_nbuf_get_arp_src_ip(skb))) { + ++pAdapter->hdd_stats.hdd_arp_stats.rx_arp_rsp_count; + QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_INFO, + "%s: ARP packet received", __func__); + track_arp = true; + } + } + + pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + if ((pHddStaCtx->conn_info.proxyARPService) && + cfg80211_is_gratuitous_arp_unsolicited_na(skb)) { + ++pAdapter->hdd_stats.hddTxRxStats.rxDropped[cpu_index]; + QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_INFO, + "%s: Dropping HS 2.0 Gratuitous ARP or Unsolicited NA", + __func__); + /* Remove SKB from internal tracking table before submitting + * it to stack + */ + qdf_nbuf_free(skb); + return QDF_STATUS_SUCCESS; + } + + hdd_event_eapol_log(skb, QDF_RX); + DPTRACE(qdf_dp_trace(skb, + QDF_DP_TRACE_RX_HDD_PACKET_PTR_RECORD, + qdf_nbuf_data_addr(skb), + sizeof(qdf_nbuf_data(skb)), QDF_RX)); + DPTRACE(qdf_dp_trace(skb, QDF_DP_TRACE_HDD_RX_PACKET_RECORD, + (uint8_t *)skb->data, qdf_nbuf_len(skb), QDF_RX)); + if (qdf_nbuf_len(skb) > QDF_DP_TRACE_RECORD_SIZE) + DPTRACE(qdf_dp_trace(skb, QDF_DP_TRACE_HDD_RX_PACKET_RECORD, + (uint8_t *)&skb->data[QDF_DP_TRACE_RECORD_SIZE], + (qdf_nbuf_len(skb)-QDF_DP_TRACE_RECORD_SIZE), QDF_RX)); + + wlan_hdd_tdls_update_rx_pkt_cnt(pAdapter, skb); + + skb->dev = pAdapter->dev; + skb->protocol = eth_type_trans(skb, skb->dev); + ++pAdapter->hdd_stats.hddTxRxStats.rxPackets[cpu_index]; + ++pAdapter->stats.rx_packets; + pAdapter->stats.rx_bytes += skb->len; + + if (is_arp) + pAdapter->dad |= hdd_is_duplicate_ip_arp(skb); + + /* Check & drop replayed mcast packets (for IPV6) */ + if (pHddCtx->config->multicast_replay_filter && + hdd_is_mcast_replay(skb)) { + ++pAdapter->hdd_stats.hddTxRxStats.rxDropped[cpu_index]; + QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_INFO, + "%s: Dropping multicast replay pkt", __func__); + qdf_nbuf_free(skb); + return QDF_STATUS_SUCCESS; + } + + /* hold configurable wakelock for unicast traffic */ + if (pHddCtx->config->rx_wakelock_timeout) + wake_lock = hdd_is_rx_wake_lock_needed(skb); + + if (wake_lock) { + cds_host_diag_log_work(&pHddCtx->rx_wake_lock, + pHddCtx->config->rx_wakelock_timeout, + WIFI_POWER_EVENT_WAKELOCK_HOLD_RX); + qdf_wake_lock_timeout_acquire(&pHddCtx->rx_wake_lock, + pHddCtx->config-> + rx_wakelock_timeout); + } + + /* Remove SKB from internal tracking table before submitting + * it to stack + */ + qdf_net_buf_debug_release_skb(rxBuf); + + if (HDD_LRO_NO_RX == + hdd_lro_rx(pHddCtx, pAdapter, skb)) { + if (hdd_napi_enabled(HDD_NAPI_ANY) && + !pHddCtx->enableRxThread && + !QDF_NBUF_CB_RX_PEER_CACHED_FRM(skb)) + rxstat = netif_receive_skb(skb); + else + rxstat = netif_rx_ni(skb); + + if (NET_RX_SUCCESS == rxstat) { + ++pAdapter->hdd_stats.hddTxRxStats. + rxDelivered[cpu_index]; + if (track_arp) + ++pAdapter->hdd_stats.hdd_arp_stats. + rx_delivered; + } else { + ++pAdapter->hdd_stats.hddTxRxStats. + rxRefused[cpu_index]; + if (track_arp) + ++pAdapter->hdd_stats.hdd_arp_stats. + rx_refused; + } + + } else { + ++pAdapter->hdd_stats.hddTxRxStats. + rxDelivered[cpu_index]; + } + + pAdapter->dev->last_rx = jiffies; + + return QDF_STATUS_SUCCESS; +} + +/** + * hdd_reason_type_to_string() - return string conversion of reason type + * @reason: reason type + * + * This utility function helps log string conversion of reason type. + * + * Return: string conversion of device mode, if match found; + * "Unknown" otherwise. + */ +const char *hdd_reason_type_to_string(enum netif_reason_type reason) +{ + switch (reason) { + CASE_RETURN_STRING(WLAN_CONTROL_PATH); + CASE_RETURN_STRING(WLAN_DATA_FLOW_CONTROL); + CASE_RETURN_STRING(WLAN_FW_PAUSE); + CASE_RETURN_STRING(WLAN_TX_ABORT); + CASE_RETURN_STRING(WLAN_VDEV_STOP); + CASE_RETURN_STRING(WLAN_PEER_UNAUTHORISED); + CASE_RETURN_STRING(WLAN_THERMAL_MITIGATION); + default: + return "Invalid"; + } +} + +/** + * hdd_action_type_to_string() - return string conversion of action type + * @action: action type + * + * This utility function helps log string conversion of action_type. + * + * Return: string conversion of device mode, if match found; + * "Unknown" otherwise. + */ +const char *hdd_action_type_to_string(enum netif_action_type action) +{ + + switch (action) { + CASE_RETURN_STRING(WLAN_STOP_ALL_NETIF_QUEUE); + CASE_RETURN_STRING(WLAN_START_ALL_NETIF_QUEUE); + CASE_RETURN_STRING(WLAN_WAKE_ALL_NETIF_QUEUE); + CASE_RETURN_STRING(WLAN_STOP_ALL_NETIF_QUEUE_N_CARRIER); + CASE_RETURN_STRING(WLAN_START_ALL_NETIF_QUEUE_N_CARRIER); + CASE_RETURN_STRING(WLAN_NETIF_CARRIER_ON); + CASE_RETURN_STRING(WLAN_NETIF_CARRIER_OFF); + default: + return "Invalid"; + } +} + +/** + * wlan_hdd_update_queue_oper_stats - update queue operation statistics + * @adapter: adapter handle + * @action: action type + * @reason: reason type + */ +static void wlan_hdd_update_queue_oper_stats(hdd_adapter_t *adapter, + enum netif_action_type action, enum netif_reason_type reason) +{ + switch (action) { + case WLAN_STOP_ALL_NETIF_QUEUE: + case WLAN_STOP_ALL_NETIF_QUEUE_N_CARRIER: + adapter->queue_oper_stats[reason].pause_count++; + break; + case WLAN_START_ALL_NETIF_QUEUE: + case WLAN_WAKE_ALL_NETIF_QUEUE: + case WLAN_START_ALL_NETIF_QUEUE_N_CARRIER: + adapter->queue_oper_stats[reason].unpause_count++; + break; + default: + break; + } + + return; +} + +/** + * wlan_hdd_update_txq_timestamp() - update txq timestamp + * @dev: net device + * + * Return: none + */ +static void wlan_hdd_update_txq_timestamp(struct net_device *dev) +{ + struct netdev_queue *txq; + int i; + bool unlock; + + for (i = 0; i < NUM_TX_QUEUES; i++) { + txq = netdev_get_tx_queue(dev, i); + unlock = __netif_tx_trylock(txq); + txq_trans_update(txq); + if (unlock == true) + __netif_tx_unlock(txq); + } +} + +/** + * wlan_hdd_update_unpause_time() - update unpause time + * @adapter: adapter handle + * + * Return: none + */ +static void wlan_hdd_update_unpause_time(hdd_adapter_t *adapter) +{ + qdf_time_t curr_time = qdf_system_ticks(); + + adapter->total_unpause_time += curr_time - adapter->last_time; + adapter->last_time = curr_time; +} + +/** + * wlan_hdd_update_pause_time() - update pause time + * @adapter: adapter handle + * + * Return: none + */ +static void wlan_hdd_update_pause_time(hdd_adapter_t *adapter, + uint32_t temp_map) +{ + qdf_time_t curr_time = qdf_system_ticks(); + uint8_t i; + qdf_time_t pause_time; + + pause_time = curr_time - adapter->last_time; + adapter->total_pause_time += pause_time; + adapter->last_time = curr_time; + + for (i = 0; i < WLAN_REASON_TYPE_MAX; i++) { + if (temp_map & (1 << i)) { + adapter->queue_oper_stats[i].total_pause_time += + pause_time; + break; + } + } + +} + +/** + * wlan_hdd_netif_queue_control() - Use for netif_queue related actions + * @adapter: adapter handle + * @action: action type + * @reason: reason type + * + * This is single function which is used for netif_queue related + * actions like start/stop of network queues and on/off carrier + * option. + * + * Return: None + */ +void wlan_hdd_netif_queue_control(hdd_adapter_t *adapter, + enum netif_action_type action, enum netif_reason_type reason) +{ + uint32_t temp_map; + + if ((!adapter) || (WLAN_HDD_ADAPTER_MAGIC != adapter->magic) || + (!adapter->dev)) { + hdd_err("adapter is invalid"); + return; + } + + switch (action) { + + case WLAN_NETIF_CARRIER_ON: + netif_carrier_on(adapter->dev); + break; + + case WLAN_NETIF_CARRIER_OFF: + netif_carrier_off(adapter->dev); + break; + + case WLAN_STOP_ALL_NETIF_QUEUE: + spin_lock_bh(&adapter->pause_map_lock); + if (!adapter->pause_map) { + netif_tx_stop_all_queues(adapter->dev); + wlan_hdd_update_txq_timestamp(adapter->dev); + wlan_hdd_update_unpause_time(adapter); + } + adapter->pause_map |= (1 << reason); + spin_unlock_bh(&adapter->pause_map_lock); + break; + + case WLAN_START_ALL_NETIF_QUEUE: + spin_lock_bh(&adapter->pause_map_lock); + temp_map = adapter->pause_map; + adapter->pause_map &= ~(1 << reason); + if (!adapter->pause_map) { + netif_tx_start_all_queues(adapter->dev); + wlan_hdd_update_pause_time(adapter, temp_map); + } + spin_unlock_bh(&adapter->pause_map_lock); + break; + + case WLAN_WAKE_ALL_NETIF_QUEUE: + spin_lock_bh(&adapter->pause_map_lock); + temp_map = adapter->pause_map; + adapter->pause_map &= ~(1 << reason); + if (!adapter->pause_map) { + netif_tx_wake_all_queues(adapter->dev); + wlan_hdd_update_pause_time(adapter, temp_map); + } + spin_unlock_bh(&adapter->pause_map_lock); + break; + + case WLAN_STOP_ALL_NETIF_QUEUE_N_CARRIER: + spin_lock_bh(&adapter->pause_map_lock); + if (!adapter->pause_map) { + netif_tx_stop_all_queues(adapter->dev); + wlan_hdd_update_txq_timestamp(adapter->dev); + wlan_hdd_update_unpause_time(adapter); + } + adapter->pause_map |= (1 << reason); + netif_carrier_off(adapter->dev); + spin_unlock_bh(&adapter->pause_map_lock); + break; + + case WLAN_START_ALL_NETIF_QUEUE_N_CARRIER: + spin_lock_bh(&adapter->pause_map_lock); + netif_carrier_on(adapter->dev); + temp_map = adapter->pause_map; + adapter->pause_map &= ~(1 << reason); + if (!adapter->pause_map) { + netif_tx_start_all_queues(adapter->dev); + wlan_hdd_update_pause_time(adapter, temp_map); + } + spin_unlock_bh(&adapter->pause_map_lock); + break; + + default: + hdd_err("unsupported action %d", action); + } + + spin_lock_bh(&adapter->pause_map_lock); + if (adapter->pause_map & (1 << WLAN_PEER_UNAUTHORISED)) + wlan_hdd_process_peer_unauthorised_pause(adapter); + spin_unlock_bh(&adapter->pause_map_lock); + + wlan_hdd_update_queue_oper_stats(adapter, action, reason); + + adapter->queue_oper_history[adapter->history_index].time = + qdf_system_ticks(); + adapter->queue_oper_history[adapter->history_index].netif_action = + action; + adapter->queue_oper_history[adapter->history_index].netif_reason = + reason; + adapter->queue_oper_history[adapter->history_index].pause_map = + adapter->pause_map; + if (++adapter->history_index == WLAN_HDD_MAX_HISTORY_ENTRY) + adapter->history_index = 0; + + return; +} + +/** + * hdd_set_mon_rx_cb() - Set Monitor mode Rx callback + * @dev: Pointer to net_device structure + * + * Return: 0 for success; non-zero for failure + */ +int hdd_set_mon_rx_cb(struct net_device *dev) +{ + hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + int ret; + QDF_STATUS qdf_status; + struct ol_txrx_desc_type sta_desc = {0}; + struct ol_txrx_ops txrx_ops; + + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + qdf_mem_zero(&txrx_ops, sizeof(txrx_ops)); + txrx_ops.rx.rx = hdd_mon_rx_packet_cbk; + ol_txrx_vdev_register( + ol_txrx_get_vdev_from_vdev_id(adapter->sessionId), + adapter, &txrx_ops); + /* peer is created wma_vdev_attach->wma_create_peer */ + qdf_status = ol_txrx_register_peer(&sta_desc); + if (QDF_STATUS_SUCCESS != qdf_status) { + hdd_err("ol_txrx_register_peer() failed to register. Status= %d [0x%08X]", + qdf_status, qdf_status); + goto exit; + } + + qdf_status = sme_create_mon_session(hdd_ctx->hHal, + adapter->macAddressCurrent.bytes); + if (QDF_STATUS_SUCCESS != qdf_status) { + hdd_err("sme_create_mon_session() failed to register. Status= %d [0x%08X]", + qdf_status, qdf_status); + } +exit: + ret = qdf_status_to_os_return(qdf_status); + return ret; +} + +/** + * hdd_send_rps_ind() - send rps indication to daemon + * @adapter: adapter context + * + * If RPS feature enabled by INI, send RPS enable indication to daemon + * Indication contents is the name of interface to find correct sysfs node + * Should send all available interfaces + * + * Return: none + */ +void hdd_send_rps_ind(hdd_adapter_t *adapter) +{ + int i; + uint8_t cpu_map_list_len = 0; + hdd_context_t *hdd_ctxt = NULL; + struct wlan_rps_data rps_data; + struct cds_config_info *cds_cfg; + + cds_cfg = cds_get_ini_config(); + + if (!adapter) { + hdd_err("adapter is NULL"); + return; + } + + if (!cds_cfg) { + hdd_err("cds_cfg is NULL"); + return; + } + + hdd_ctxt = WLAN_HDD_GET_CTX(adapter); + rps_data.num_queues = NUM_TX_QUEUES; + + hdd_info("cpu_map_list '%s'", hdd_ctxt->config->cpu_map_list); + + /* in case no cpu map list is provided, simply return */ + if (!strlen(hdd_ctxt->config->cpu_map_list)) { + hdd_err("no cpu map list found"); + goto err; + } + + if (QDF_STATUS_SUCCESS != + hdd_hex_string_to_u16_array(hdd_ctxt->config->cpu_map_list, + rps_data.cpu_map_list, + &cpu_map_list_len, + WLAN_SVC_IFACE_NUM_QUEUES)) { + hdd_err("invalid cpu map list"); + goto err; + } + + rps_data.num_queues = + (cpu_map_list_len < rps_data.num_queues) ? + cpu_map_list_len : rps_data.num_queues; + + for (i = 0; i < rps_data.num_queues; i++) { + hdd_info("cpu_map_list[%d] = 0x%x", + i, rps_data.cpu_map_list[i]); + } + + strlcpy(rps_data.ifname, adapter->dev->name, + sizeof(rps_data.ifname)); + wlan_hdd_send_svc_nlink_msg(hdd_ctxt->radio_index, + WLAN_SVC_RPS_ENABLE_IND, + &rps_data, sizeof(rps_data)); + + cds_cfg->rps_enabled = true; + + return; + +err: + hdd_err("Wrong RPS configuration. enabling rx_thread"); + cds_cfg->rps_enabled = false; +} + +/** + * hdd_send_rps_disable_ind() - send rps disable indication to daemon + * @adapter: adapter context + * + * Return: none + */ +void hdd_send_rps_disable_ind(hdd_adapter_t *adapter) +{ + uint8_t cpu_map_list_len = 0; + hdd_context_t *hdd_ctxt = NULL; + struct wlan_rps_data rps_data; + struct cds_config_info *cds_cfg; + + cds_cfg = cds_get_ini_config(); + + if (!adapter) { + hdd_err("adapter is NULL"); + return; + } + + if (!cds_cfg) { + hdd_err("cds_cfg is NULL"); + return; + } + + hdd_ctxt = WLAN_HDD_GET_CTX(adapter); + rps_data.num_queues = NUM_TX_QUEUES; + + hdd_info("Set cpu_map_list 0"); + + qdf_mem_zero(&rps_data.cpu_map_list, sizeof(rps_data.cpu_map_list)); + cpu_map_list_len = 0; + rps_data.num_queues = + (cpu_map_list_len < rps_data.num_queues) ? + cpu_map_list_len : rps_data.num_queues; + + strlcpy(rps_data.ifname, adapter->dev->name, + sizeof(rps_data.ifname)); + wlan_hdd_send_svc_nlink_msg(hdd_ctxt->radio_index, + WLAN_SVC_RPS_ENABLE_IND, + &rps_data, sizeof(rps_data)); + + cds_cfg->rps_enabled = false; +} + +#ifdef MSM_PLATFORM +/** + * hdd_reset_tcp_delack() - Reset tcp delack value to default + * @hdd_ctx: Handle to hdd context + * + * Function used to reset TCP delack value to its default value + * + * Return: None + */ +void hdd_reset_tcp_delack(hdd_context_t *hdd_ctx) +{ + enum pld_bus_width_type next_level = WLAN_SVC_TP_LOW; + struct wlan_rx_tp_data rx_tp_data = {0}; + + rx_tp_data.rx_tp_flags |= TCP_DEL_ACK_IND; + rx_tp_data.level = next_level; + hdd_ctx->rx_high_ind_cnt = 0; + wlan_hdd_send_svc_nlink_msg(hdd_ctx->radio_index, WLAN_SVC_WLAN_TP_IND, + &rx_tp_data, sizeof(rx_tp_data)); +} +#endif /* MSM_PLATFORM */ diff --git a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_wext.c b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_wext.c new file mode 100644 index 0000000000000000000000000000000000000000..081f60a2db6c7ca9d562d226600d842a175d2409 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_wext.c @@ -0,0 +1,13775 @@ +/* + * Copyright (c) 2011-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: wlan_hdd_wext.c + * + * Linux Wireless Extensions Implementation + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "sir_params.h" +#include "csr_api.h" +#include "csr_inside_api.h" +#include "sme_rrm_internal.h" +#include +#include "dot11f.h" +#include +#include +#include +#include "utils_api.h" +#include "wlan_hdd_p2p.h" +#ifdef FEATURE_WLAN_TDLS +#include "wlan_hdd_tdls.h" +#endif + +#include "cds_ieee80211_common.h" +#include "ol_if_athvar.h" +#include "dbglog_host.h" +#include "wma.h" + +#include "wlan_hdd_power.h" +#include "qwlan_version.h" +#include "wlan_hdd_host_offload.h" + +#include +#include + +#include "wlan_hdd_misc.h" + +#include "qc_sap_ioctl.h" +#include "sme_api.h" +#include "wma_types.h" +#include "qdf_trace.h" +#include "wlan_hdd_assoc.h" +#include "wlan_hdd_ioctl.h" +#include "wlan_hdd_scan.h" +#include "sme_power_save_api.h" +#include "cds_concurrency.h" +#include "wlan_hdd_conc_ut.h" +#include "wlan_hdd_tsf.h" +#include "wlan_hdd_ocb.h" +#include "wlan_hdd_napi.h" +#include "cdp_txrx_flow_ctrl_legacy.h" +#include "wlan_hdd_nan_datapath.h" +#include "wlan_hdd_stats.h" +#ifdef WLAN_SUSPEND_RESUME_TEST +#include "wlan_hdd_driver_ops.h" +#include "hif.h" +#include "pld_common.h" +#endif +#include "wlan_hdd_lro.h" +#include "cds_utils.h" +#include "wlan_hdd_packet_filter_api.h" + +#define HDD_FINISH_ULA_TIME_OUT 800 +#define HDD_SET_MCBC_FILTERS_TO_FW 1 +#define HDD_DELETE_MCBC_FILTERS_FROM_FW 0 + +static int ioctl_debug; +module_param(ioctl_debug, int, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); + +/* To Validate Channel against the Frequency and Vice-Versa */ +static const hdd_freq_chan_map_t freq_chan_map[] = { + {2412, 1}, {2417, 2}, {2422, 3}, {2427, 4}, {2432, 5}, {2437, 6}, + {2442, 7}, {2447, 8}, {2452, 9}, {2457, 10}, {2462, 11}, {2467, 12}, + {2472, 13}, {2484, 14}, {4920, 240}, {4940, 244}, {4960, 248}, + {4980, 252}, {5040, 208}, {5060, 212}, {5080, 216}, {5180, 36}, + {5200, 40}, {5220, 44}, {5240, 48}, {5260, 52}, {5280, 56}, + {5300, 60}, {5320, 64}, {5500, 100}, {5520, 104}, {5540, 108}, + {5560, 112}, {5580, 116}, {5600, 120}, {5620, 124}, {5640, 128}, + {5660, 132}, {5680, 136}, {5700, 140}, {5720, 144}, {5745, 149}, + {5765, 153}, {5785, 157}, {5805, 161}, {5825, 165}, {5852, 170}, + {5855, 171}, {5860, 172}, {5865, 173}, {5870, 174}, {5875, 175}, + {5880, 176}, {5885, 177}, {5890, 178}, {5895, 179}, {5900, 180}, + {5905, 181}, {5910, 182}, {5915, 183}, {5920, 184} }; + +#define FREQ_CHAN_MAP_TABLE_SIZE \ + (sizeof(freq_chan_map) / sizeof(freq_chan_map[0])) + +/* Private ioctls and their sub-ioctls */ +#define WLAN_PRIV_SET_INT_GET_NONE (SIOCIWFIRSTPRIV + 0) +#define WE_SET_11D_STATE 1 +#define WE_WOWL 2 +#define WE_SET_POWER 3 +/* + * + * setMaxAssoc - Sets the maximum number of associated stations + * + * @INPUT: 1 to 32 + * + * @OUTPUT: None + * + * This IOTCL sets the maximum number of associated stations + * + * @E.g: iwpriv wlan0 setMaxAssoc + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_SET_MAX_ASSOC 4 +/* + * + * scan_diable - Disable scan + * + * @INPUT: set_value + * + * @OUTPUT: None + * + * This IOCTL is used to set disable scan + * + * @E.g: iwpriv wlan0 scan_disable 1 + * + * Supported Feature: Scan + * + * Usage: Internal/External + * + * + */ +#define WE_SET_SCAN_DISABLE 5 +/* + * + * inactivityTO - sets the timeout value for inactivity data while + * in power save mode + * + * @INPUT: int1…..int255 + * + * @OUTPUT: None + * + * This IOCTL set the timeout value for inactivity data in power save mode + * + * @E.g: iwpriv wlan0 inactivityTO 20 + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_SET_DATA_INACTIVITY_TO 6 +/* + * + * setMaxTxPower - Dynamically sets the maximum transmission power + * + * @INPUT: Transmission power in dBm + * + * @OUTPUT: None + * + * This IOCTL dynamically sets the maximum transmission power + * This setting does not persist over reboots + * + * @E.g: iwpriv wlan0 setMaxTxPower + */ +#define WE_SET_MAX_TX_POWER 7 +#define WE_SET_HIGHER_DTIM_TRANSITION 8 +#define WE_SET_TM_LEVEL 9 +/* + * + * setphymode - Set the phymode dynamically + * + * @INPUT: 0 IEEE80211_MODE_AUTO to 22 IEEE80211_MODE_11AGN + * + * @OUTPUT: None + * + * This IOCTL sets the phymode dynamically + * + * @E.g: iwpriv wlan0 setphymode 10 + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_SET_PHYMODE 10 +/* + * + * nss - Set the number of spatial streams + * + * @INPUT: int1…..int3 + * + * @OUTPUT: None + * + * This IOCTL sets the number of spatial streams. Supported values are 1 and 2 + * + * @E.g: iwpriv wlan0 nss 2 + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_SET_NSS 11 +/* + * + * ldpc - Enables or disables LDPC + * + * @INPUT: 0 – Disable, 1 - Enable + * + * @OUTPUT: None + * + * This IOCTL enables or disables LDPC + * + * @E.g: iwpriv wlan0 ldpc 1 + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_SET_LDPC 12 +/* + * + * tx_stbc - Enables or disables tx_stbc + * + * @INPUT: Int 0 – Disable, 1 - Enable + * + * @OUTPUT: None + * + * This IOTCL used to enables or disables tx_stbc + * + * @E.g: iwpriv wlan0 tx_stbc + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_SET_TX_STBC 13 +/* + * + * rx_stbc - Set the rx_stbc parameter + * + * @INPUT: Int 0 – Disable, 1 - Enable + * + * @OUTPUT: None + * + * This IOTCL used to set rx_stbc parameter + * + * @E.g: iwpriv wlan0 rx_stbc + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_SET_RX_STBC 14 +/* + * + * shortgi - Enables or disables a short-guard interval + * + * @INPUT: Int 0 – Disable, 1 - Enable + * + * @OUTPUT: None + * + * This IOCTL enables or disables a short-guard interval. + * + * @E.g: iwpriv wlan0 shortgi + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_SET_SHORT_GI 15 +/* + * + * enablertscts - enables or disables rts/cts. + * + * @INPUT: 1-Enable , 0-Disable + * + * @OUTPUT: None + * + * This IOCTL enables or disables rts/cts. + * + * @E.g: iwpriv wlan0 enablertscts + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_SET_RTSCTS 16 +/* + * + * chwidth - Set the channel bandwidth + * + * @INPUT: 0-20mhz to 3-160mhz + * + * @OUTPUT: None + * + * This IOTCL used to set the channel bandwidth + * + * @E.g: iwpriv wlan0 chwidth 1 + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_SET_CHWIDTH 17 +#define WE_SET_ANI_EN_DIS 18 +#define WE_SET_ANI_POLL_PERIOD 19 +#define WE_SET_ANI_LISTEN_PERIOD 20 +#define WE_SET_ANI_OFDM_LEVEL 21 +#define WE_SET_ANI_CCK_LEVEL 22 +/* + * + * cwmenable - Enables or disables the dynamic channel bandwidth + * + * @INPUT: 0-Disable, 1-Enable + * + * @OUTPUT: None + * + * This IOTCL used to enables or disables the dynamic channel bandwidth + * + * @E.g: iwpriv wlan0 cwmenable + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_SET_DYNAMIC_BW 23 +/* + * + * txchainmask - This IOCTL sets the current Tx chain mask + * + * @INPUT: Mask Value + * + * @OUTPUT: None + * + * This IOCTL sets the current Tx chain mask + * + * @E.g: iwpriv wlan0 txchainmask 1 + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_SET_TX_CHAINMASK 24 +/* + * + * rxchainmask - Sets the current Rx chain mask + * + * @INPUT: Mask Value + * + * @OUTPUT: None + * + * This IOCTL sets the current Rx chain mask. This command is the + * equivalent to setting in gSetRxChainmask1x1 in WCNSS_qcom_cfg.ini. + * + * @E.g: iwpriv wlan0 rxchainmask + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_SET_RX_CHAINMASK 25 +/* + * + * set11NRates - Fixes the Tx data rate of the 11N mode. + * + * @INPUT: 0x1b to 0x8f + * + * @OUTPUT: None + * + * This IOCTL fixes the Tx data rate of the 11N mode. + * + * @E.g: iwpriv wlan0 set11NRates 0x85 + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_SET_11N_RATE 26 +/* + * + * ampdu - Set the the maximum subframe of ampdu + * + * @INPUT: int 1 to int 63 + * + * @OUTPUT: None + * + * This IOCTL sets the maximum subframe of ampdu. + * + * @E.g: iwpriv wlan0 ampdu 9 + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_SET_AMPDU 27 +/* + * + * amsdu - Sets the maximum subframe of amsdu. + * + * @INPUT: int 1 to int 31 + * + * @OUTPUT: None + * + * This IOCTL sets the maximum subframe of amsdu. + * + * @E.g: iwpriv wlan0 amsdu 9 + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_SET_AMSDU 28 +/* + * + * txpow2g - current 2 GHz Tx power setting + * + * @INPUT: Tx power in dBm + * + * @OUTPUT: None + * + * This IOTCL used to set 2 ghz tx power + * + * @E.g: iwpriv wlan0 txpow2g + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_SET_TXPOW_2G 29 +/* + * + * txpow5g - Current 5 GHz tx power setting + * + * @INPUT: Tx power in dBm + * + * @OUTPUT: None + * + * This IOTCL used to set the 5 ghz txpower + * + * @E.g: iwpriv wlan0 txpow5g + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_SET_TXPOW_5G 30 +/* Private ioctl for firmware debug log */ +#define WE_DBGLOG_LOG_LEVEL 31 +#define WE_DBGLOG_VAP_ENABLE 32 +#define WE_DBGLOG_VAP_DISABLE 33 +#define WE_DBGLOG_MODULE_ENABLE 34 +#define WE_DBGLOG_MODULE_DISABLE 35 +#define WE_DBGLOG_MOD_LOG_LEVEL 36 +#define WE_DBGLOG_TYPE 37 +#define WE_SET_TXRX_FWSTATS 38 +/* + * + * set11ACRates - Fixes the Tx data rate of 11AC + * + * @INPUT: 0x1 to 0x9 + * + * @OUTPUT: None + * + * This IOCTL fixes the Tx data rate of 11AC. + * + * @E.g: iwpriv wlan0 set11ACRates 0x9 + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_SET_VHT_RATE 39 +#define WE_DBGLOG_REPORT_ENABLE 40 +#define WE_TXRX_FWSTATS_RESET 41 +/* + * + * setTxMaxPower2G - Set the maximum transmit power for the 2.4-GHz band + * + * @INPUT: Transmission power in dBm + * + * @OUTPUT: None + * + * This IOCTL sets the maximum transmit power for the 2.4-GHz band + * This setting does not persist over reboots + * + * @E.g: iwpriv wlan0 setTxMaxPower2G 10 + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_SET_MAX_TX_POWER_2_4 42 +/* + * + * setTxMaxPower5G - Set the maximum transmit power for the 5-GHz band + * + * @INPUT: Transmission power in dBm + * + * @OUTPUT: None + * + * This IOCTL sets the maximum transmit power for the 5-GHz band + * This setting does not persist over reboots + * + * @E.g: iwpriv wlan0 setTxMaxPower5G 10 + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_SET_MAX_TX_POWER_5_0 43 +#define WE_SET_PKTLOG 44 +/* Private ioctl for packet powe save */ +#define WE_PPS_PAID_MATCH 45 +#define WE_PPS_GID_MATCH 46 +#define WE_PPS_EARLY_TIM_CLEAR 47 +#define WE_PPS_EARLY_DTIM_CLEAR 48 +#define WE_PPS_EOF_PAD_DELIM 49 +#define WE_PPS_MACADDR_MISMATCH 50 +#define WE_PPS_DELIM_CRC_FAIL 51 +#define WE_PPS_GID_NSTS_ZERO 52 +/* + * + * rssi_chk - Chek the rssi + * + * @INPUT: One argument as input + * + * @OUTPUT: rssi + * wlan0 rssi_chk:56 + * + * This IOTCL used to chek rssi + * + * @E.g: iwpriv wlan0 rssi_chk + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_PPS_RSSI_CHECK 53 +/* + * + * setAutoChannel - set ACS enable/disable + * + * @INPUT: None + * + * @OUTPUT: None + * + * This IOCTL is used to set SAP ACS eanble/disable + * + * @E.g: iwpriv wlan0 setAutoChannel 0 + * + * Supported Feature: SAP + * + * Usage: Internal/External + * + * + */ +#define WE_SET_SAP_AUTO_CHANNEL_SELECTION 54 +/* + * + * htsmps - Sets the htsmps + * + * @INPUT: Atleast one int argument + * + * @OUTPUT: None + * + * This IOTCL used to set htsmps + * + * @E.g: iwpriv wlan0 htsmps + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_SET_HTSMPS 55 +/* Private ioctl for QPower */ +#define WE_SET_QPOWER_MAX_PSPOLL_COUNT 56 +#define WE_SET_QPOWER_MAX_TX_BEFORE_WAKE 57 +#define WE_SET_QPOWER_SPEC_PSPOLL_WAKE_INTERVAL 58 +#define WE_SET_QPOWER_SPEC_MAX_SPEC_NODATA_PSPOLL 59 +/* + * + * burst_enable - Enables or disables the burst feature + * + * @INPUT: 0-Disable, 1-Enable + * + * @OUTPUT: None + * + * This IOCTL enables or disables the burst feature. + * + * @E.g: iwpriv wlan0 burst_enable 0 + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_SET_BURST_ENABLE 60 +/* + * + * burst_dur - Enables or disables the burst feature + * + * @INPUT: int 1…..int 8191 in microseconds + * + * @OUTPUT: None + * + * This IOCTL sets the burst duration. + * + * @E.g: iwpriv wlan0 burst_dur + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_SET_BURST_DUR 61 +/* GTX Commands */ +/* + * + * gtxHTMcs - Set the tx HTM value + * + * @INPUT: Atleast one int orgument + * + * @OUTPUT: None + * + * This IOTCL sets htm tx value + * + * @E.g: iwpriv wlan0 gtxHTMcs + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_SET_GTX_HT_MCS 62 +/* + * + * gtxVHTMcs - Set gtxVHTMcs value + * + * @INPUT: Atleast one int argument + * + * @OUTPUT: None + * + * This IOTCL used to set gtxVHTMcs value + * + * @E.g: iwpriv wlan0 gtxVHTMcs + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_SET_GTX_VHT_MCS 63 +/* + * + * gtxUsrCfg - Host request for GTX mask + * + * @INPUT: Atleast one int orgument + * + * @OUTPUT: None + * + * This IOTCL used send the host request for GTX mask + * + * @E.g: iwpriv wlan0 gtxUsrCfg + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_SET_GTX_USRCFG 64 +/* + * + * gtxThre - Set the tx threshold + * + * @INPUT: Atleast one int argument + * + * @OUTPUT: None + * + * This IOTCL used to set tx threshold + * + * @E.g: iwpriv wlan0 gtxThre + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_SET_GTX_THRE 65 +/* + * + * gtxMargin - Set the gtxMargin + * + * @INPUT: 1 to 32 + * + * @OUTPUT: None + * + * This IOTCL use dto set gtxMargin + * + * @E.g: iwpriv wlan0 gtxMargini + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_SET_GTX_MARGIN 66 +/* + * + * gtxStep - Set the gtxStep + * + * @INPUT: None + * + * @OUTPUT: None + * + * This IOTCL used to sets gtxStep + * + * @E.g: iwpriv wlan0 gtxStep + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_SET_GTX_STEP 67 +/* + * + * gtxMinTpc - Sets the gtxMinTpc + * + * @INPUT: Atleast one int argument + * + * @OUTPUT: None + * + * This IOTCL sets the tx MinTpc + * + * @E.g: iwpriv wlan0 gtxMinTpc + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_SET_GTX_MINTPC 68 +/* + * + * gtxBWMask - Sets the BW mask (20/40/80/160 Mhz) + * + * @INPUT: Mask value + * + * @OUTPUT: None + * + * This IOTCL used to set gtxBWMask + * + * @E.g: iwpriv wlan0 gtxBWMask + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ + +#define WE_SET_GTX_BWMASK 69 +/* + * + * setMccLatency - Sets the MCC latency value during STA-P2P concurrency + * + * @INPUT: set_value + * + * @OUTPUT: None + * + * This IOCTL is used to set the MCC latency value in milliseconds + * during STA-P2P concurrency. + * + * If 0ms latency is provided, then FW will set to a default. + * Otherwise, latency must be at least 30ms. + * + * @E.g: iwpriv wlan0 setMccLatency 40 + * + * + * Supported Feature: Concurrency + * + * Usage: Internal/External + * + * + */ +#define WE_MCC_CONFIG_LATENCY 70 + +/* + * + * setMccQuota- Set the quota for P2P cases + * + * @INPUT: set_value [0,100] + * + * @OUTPUT: None + * + * This IOCTL is used to set the quota in milliseconds for P2P_GO/STA. + * + * Currently used to set time quota for 2 MCC vdevs/adapters using + * (operating channel, quota) for each mode. + * The info is provided run time using iwpriv command: + * iwpriv setMccQuota . + * Note: the quota provided in command is for the same mode in cmd. + * HDD checks if MCC mode is active, gets the second mode and its + * operating chan. + * Quota for the 2nd role is calculated as 100 - quota of first mode. + * + * @E.g: iwpriv wlan0 setMccQuota 50 + * iwpriv p2p0 setMccQuota 50 + * + * Supported Feature: Concurrency + * + * Usage: Internal/External + * + * + */ +#define WE_MCC_CONFIG_QUOTA 71 +/* Private IOCTL for debug connection issues */ +#define WE_SET_DEBUG_LOG 72 +#ifdef WE_SET_TX_POWER +#undef WE_SET_TX_POWER +#endif +/* + * + * setTxPower - Set the current transmit power + * + * @INPUT: Transmission power in dBm + * + * @OUTPUT: None + * + * This IOCTL sets the current transmit power. + * This setting does not persist over reboots. + * + * @E.g: iwpriv wlan0 setTxPower 10 + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_SET_TX_POWER 74 +/* Private ioctl for earlyrx power save feature */ +#define WE_SET_EARLY_RX_ADJUST_ENABLE 75 +#define WE_SET_EARLY_RX_TGT_BMISS_NUM 76 +#define WE_SET_EARLY_RX_BMISS_SAMPLE_CYCLE 77 +#define WE_SET_EARLY_RX_SLOP_STEP 78 +#define WE_SET_EARLY_RX_INIT_SLOP 79 +#define WE_SET_EARLY_RX_ADJUST_PAUSE 80 +/* + * + * setMcRate - Set the data rate for multicast data + * + * @INPUT: 1 to 32 + * + * @OUTPUT: None + * + * This IOCTL sets the data rate for multicast data. Note that this command + * is allowed only in STA, IBSS, or QCMobileAP mode + * + * @E.g: iwpriv wlan0 setMcRate + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_SET_MC_RATE 81 +#define WE_SET_EARLY_RX_DRIFT_SAMPLE 82 +/* Private ioctl for packet power save */ +/* + * + * 5g_ebt - Sets the 5g_ebt + * + * @INPUT: + * + * @OUTPUT: None + * + * This IOTCL used to set 5g_ebt + * + * @E.g: iwpriv wlan0 5g_ebt + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_PPS_5G_EBT 83 +/* + * + * cts_cbw - Set CTS channel BW for dynamic BW adjustment + * + * @INPUT: 20 t0 160 + * + * @OUTPUT: None + * + * This IOTCL used to set CTS channel BW for dynamic BW adjustment + * + * @E.g: iwpriv wlan0 cts_cbw + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_SET_CTS_CBW 84 +#define WE_DUMP_STATS 85 +#define WE_CLEAR_STATS 86 +/* Private sub ioctl for starting/stopping the profiling */ +#define WE_START_FW_PROFILE 87 + +/* + * + * setChanChange - Initiate channel change + * + * @INPUT: channel number to switch to. + * + * @OUTPUT: None + * + * This IOCTL is used to initiate a channel change. + * If called on STA/CLI interface it will send the + * ECSA action frame to the connected SAP/GO asking to + * initiate the ECSA, if supported. + * If called on SAP/GO interface it will initiate + * ECSA and ask connected peers to move to new channel. + * + * @E.g: iwpriv wlan0 setChanChange + * iwpriv wlan0 setChanChange 1 + * + * Supported Feature: ECSA + * + * Usage: Internal/External + * + * + */ +#define WE_SET_CHANNEL 88 +#define WE_SET_CONC_SYSTEM_PREF 89 + +/* + * + * wow_ito - sets the timeout value for inactivity data while + * in power save mode during wow + * + * @INPUT: int1…..int255 + * + * @OUTPUT: None + * + * This IOCTL set the timeout value for inactivity data in power save mode + * + * @E.g: iwpriv wlan0 wow_ito 20 + * + * Supported Feature: STA + * + * Usage: External + * + * +*/ +#define WE_SET_WOW_DATA_INACTIVITY_TO 90 + + +/* Private ioctls and their sub-ioctls */ +#define WLAN_PRIV_SET_NONE_GET_INT (SIOCIWFIRSTPRIV + 1) +#define WE_GET_11D_STATE 1 +#define WE_SET_SAP_CHANNELS 3 +#define WE_GET_WLAN_DBG 4 +#define WE_GET_MAX_ASSOC 6 +/* 7 is unused */ +#define WE_GET_SAP_AUTO_CHANNEL_SELECTION 8 + +/* + * + * getconcurrency - Get concurrency mode + * + * @INPUT: None + * + * @OUTPUT: It shows concurrency value + * Bit 0:STA 1:SAP 2:P2P_Client 3:P2P_GO + * 4:FTM 5:IBSS 6:Monitor 7:P2P_Device + * 8:OCB 9:EPPING 10:QVIT 11:NDI + * + * This IOCTL is used to retrieve concurrency mode. + * + * @E.g: iwpriv wlan0 getconcurrency + * wlan0 getconcurrency:5 + * Above value shows STA+P2P_Client + * + * Supported Feature: Concurrency + * + * Usage: Internal/External + * + * + */ +#define WE_GET_CONCURRENCY_MODE 9 +/* + * + * get_nss - Get the number of spatial STBC streams (NSS) + * + * @INPUT: None + * + * @OUTPUT: NSS + * wlan0 get_nss:2 + * + * This IOTCL used to get the number of spatial STBC streams + * + * @E.g: iwpriv wlan0 get_nss + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_GET_NSS 11 +/* + * + * get_ldpc - This IOCTL gets the low density parity check (LDPC) + * + * @INPUT: None + * + * @OUTPUT: ldpc + * wlan0 get_ldpc:1 + * + * This IOTCL used to gets the low density parity check (LDPC) + * + * @E.g: iwpriv wlan0 get_ldpc + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_GET_LDPC 12 +/* + * + * get_tx_stbc - Get the value of the current Tx space time block code (STBC) + * + * @INPUT: None + * + * @OUTPUT: TXSTBC + * wlan0 get_tx_stbc:1 + * + * This IOTCL get the value of the current Tx space time block code (STBC) + * + * @E.g: iwpriv wlan0 get_tx_stbc + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_GET_TX_STBC 13 +/* + * + * get_rx_stbc - Gets the value of the current Rx STBC + * + * @INPUT: None + * + * @OUTPUT: Rx STBC + * wlan0 get_rx_stbc:1 + * + * This IOTCL used to get the value of the current Rx STBC + * + * @E.g: iwpriv wlan0 get_rx_stbc + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_GET_RX_STBC 14 +/* + * + * get_shortgi - Get the value of the current short GI setting + * + * @INPUT: None + * + * @OUTPUT: Enable/disable of shortgi + * wlan0 get_shortgi:1 + * + * This IOCTL gets the value of the current short GI setting + * + * @E.g: iwpriv wlan0 get_shortgi + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_GET_SHORT_GI 15 +/* + * + * get_rtscts - Get the value of the current RTS/CTS setting. + * + * @INPUT: None + * + * @OUTPUT: Enable/disable of RTS/CTS + * wlan0 get_rtscts:33 + * + * This IOTCL get the value of the current RTS/CTS setting. + * + * @E.g: iwpriv wlan0 get_rtscts + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_GET_RTSCTS 16 +/* + * + * get_chwidth - Get the current channel width setting + * + * @INPUT: None + * + * @OUTPUT: channel width + * wlan0 get_chwidth:0 + * + * This IOTCL get the current channel width setting. + * + * @E.g: iwpriv wlan0 get_chwidth + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_GET_CHWIDTH 17 +/* + * + * get_anienable - Get the anienable + * + * @INPUT: None + * + * @OUTPUT: + * wlan0 get_anienable:0 + * + * This IOTCL get the anienable + * + * @E.g: iwpriv wlan0 get_anienable + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_GET_ANI_EN_DIS 18 +/* + * + * get_aniplen - Get the aniplen + * + * @INPUT: None + * + * @OUTPUT: + * wlan0 get_aniplen:0 + * + * This IOTCL get the aniplen + * + * @E.g: iwpriv wlan0 get_aniplen + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_GET_ANI_POLL_PERIOD 19 +/* + * + * get_anilislen- Get the anilislen + * + * @INPUT: None + * + * @OUTPUT: + * wlan0 get_anilislen:0 + * + * This IOTCL used to get anilislen + * + * @E.g: iwpriv wlan0 get_anilislen + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_GET_ANI_LISTEN_PERIOD 20 +/* + * + * get_aniofdmlvl - Get the OFDM level + * + * @INPUT: None + * + * @OUTPUT: OFDM + * wlan0 get_aniofdmlvl:0 + * + * This IOTCL used to get ofdm level + * + * @E.g: iwpriv wlan0 get_aniofdmlvl + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_GET_ANI_OFDM_LEVEL 21 +/* + * + * get_aniccklvl - Get the cck level + * + * @INPUT: None + * + * @OUTPUT: + * wlan0 get_aniccklvl:0 + * + * This IOTCL used to get cck level + * + * @E.g: iwpriv wlan0 get_aniccklvl + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_GET_ANI_CCK_LEVEL 22 +/* + * + * get_cwmenable - Get the value of the dynamic channel bandwidth setting + * + * @INPUT: None + * + * @OUTPUT: Enable/disable dynamic channel bandwidth + * wlan0 get_cwmenable:0 + * + * This IOTCL get the value of the dynamic channel bandwidth setting + * + * @E.g: iwpriv wlan0 get_cwmenable + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_GET_DYNAMIC_BW 23 +/* + * + * get_txchainmask - Get the txchainmask that was set + * + * @INPUT: None + * + * @OUTPUT: txchainmask + * wlan0 get_txchainmask:1 + * + * This IOCTL gets the txchainmask that was set + * This command is useful if it was previously set + * + * @E.g: iwpriv wlan0 get_txchainmask + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_GET_TX_CHAINMASK 24 +/* + * + * get_rxchainmask - Get the rxchainmask that was set + * + * @INPUT: None + * + * @OUTPUT: rxchainmask + * wlan0 get_rxchainmask:1 + * + * This IOCTL gets the rxchainmask that was set + * This command is useful only if it was previously set. + * + * @E.g: iwpriv wlan0 get_rxchainmask + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_GET_RX_CHAINMASK 25 +/* + * + * get_11nrate - Get the fixed Tx data rate + * + * @INPUT: None + * + * @OUTPUT: Using this command does not return the same value as set + * wlan0 get_11nrate:0 + * + * This IOCTL gets the fixed Tx data rate + * This command is useful only if setting the fixed Tx rate. + * + * @E.g: iwpriv wlan0 get_11nrate + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_GET_11N_RATE 26 +/* + * + * get_ampdu - Get the maximum subframe of ampdu + * + * @INPUT: None + * + * @OUTPUT: Maximum subframe of ampdu + * wlan0 get_ampdu:1 + * + * This IOCTL gets the maximum subframe of ampdu + * This command is useful only if setting ampdu. + * + * @E.g: iwpriv wlan0 get_ampdu + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_GET_AMPDU 27 +/* + * + * get_amsdu - Get the maximum subframe of amsdu + * + * @INPUT: None + * + * @OUTPUT: Maximum subframe of amsdu + * wlan0 get_amsdu:1 + * + * This IOCTL gets the maximum subframe of amsdu. + * This command is useful only if setting amsdu + * + * @E.g: iwpriv wlan0 get_amsdu + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_GET_AMSDU 28 +/* + * + * get_txpow2g - Get the current 2 GHz Tx power setting + * + * @INPUT: None + * + * @OUTPUT: Tx Power in dbm + * wlan0 get_txpow2g:0 + * + * This IOCTL gets the current 2 GHz Tx power setting + * This command is useful if setting Tx power + * + * @E.g: iwpriv wlan0 get_txpow2g + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_GET_TXPOW_2G 29 +/* + * + * get_txpow5g - Get the current 5 GHz Tx power setting + * + * @INPUT: None + * + * @OUTPUT: Tx Power in dbm + * wlan0 get_txpow5g:0 + * + * This IOCTL gets the current 5 GHz Tx power setting + * This command is useful if setting Tx power + * + * @E.g: iwpriv wlan0 get_txpow5g + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_GET_TXPOW_5G 30 +/* 31 is unused */ +#define WE_GET_PPS_PAID_MATCH 32 +#define WE_GET_PPS_GID_MATCH 33 +#define WE_GET_PPS_EARLY_TIM_CLEAR 34 +#define WE_GET_PPS_EARLY_DTIM_CLEAR 35 +#define WE_GET_PPS_EOF_PAD_DELIM 36 +#define WE_GET_PPS_MACADDR_MISMATCH 37 +#define WE_GET_PPS_DELIM_CRC_FAIL 38 +#define WE_GET_PPS_GID_NSTS_ZERO 39 +#define WE_GET_PPS_RSSI_CHECK 40 +/* Private ioctl for QPower */ +#define WE_GET_QPOWER_MAX_PSPOLL_COUNT 41 +#define WE_GET_QPOWER_MAX_TX_BEFORE_WAKE 42 +#define WE_GET_QPOWER_SPEC_PSPOLL_WAKE_INTERVAL 43 +#define WE_GET_QPOWER_SPEC_MAX_SPEC_NODATA_PSPOLL 44 +/* + * + * get_burst_en - Enables or disables the burst feature + * + * @INPUT: None + * + * @OUTPUT: Enable/disable of burst feature + * wlan0 get_burst_en:1 + * + * This IOCTL enables or disables the burst feature + * + * @E.g: iwpriv wlan0 get_burst_en + * + * Supported Feature:STA + * + * Usage: Internal/External + * + * + */ +#define WE_GET_BURST_ENABLE 45 +/* + * + * get_burst_dur - Get the burst duration + * + * @INPUT: None + * + * @OUTPUT: Duration in microseconds + * wlan0 get_burst_dur:8160 + * + * This IOCTL gets the burst duration + * This command is useful if setting burst enable + * + * @E.g: iwpriv wlan0 get_burst_dur + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_GET_BURST_DUR 46 +/* GTX Commands */ +/* + * + * get_gtxHTMcs - Get the tx HTM + * + * @INPUT: None + * + * @OUTPUT: HTM + * wlan0 get_gtxHTMcs:32896 + * + * This IOTCL used to get HTM + * + * @E.g: iwpriv wlan0 get_gtxHTMcs + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_GET_GTX_HT_MCS 47 +/* + * + * get_gtxVHTMcs - Get the VHTM + * + * @INPUT: None + * + * @OUTPUT: VHTM + * wlan0 get_gtxVHTMcs:524800 + * + * This IOTCL used to get the VHTM + * + * @E.g: iwpriv wlan0 get_gtxVHTMcs + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_GET_GTX_VHT_MCS 48 +/* + * + * get_gtxUsrCfg - Get the tx cfg + * + * @INPUT: None + * + * @OUTPUT: TXCFG + * wlan0 get_gtxUsrCfg:32 + * + * This IOTCL used to get the tx cfg + * + * @E.g: iwpriv wlan0 get_gtxUsrCfg + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_GET_GTX_USRCFG 49 +/* + * + * get_gtxThre - Get the tx threshold + * + * @INPUT: None + * + * @OUTPUT: Threshold + * wlan0 get_gtxThre:3 + * + * This IOCTL is used to get tx threshold + * + * @E.g: iwpriv wlan0 get_gtxThre + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_GET_GTX_THRE 50 +/* + * + * get_gtxMargin - Get the tx margin + * + * @INPUT: None + * + * @OUTPUT: GTXMARGIN + * wlan0 get_gtxMargin:2 + * + * This IOCTL is used to set tx margin + * + * @E.g: iwpriv wlan0 get_gtxMargin + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_GET_GTX_MARGIN 51 +/* + * + * get_gtxStep - Get the tx step + * + * @INPUT: None + * + * @OUTPUT: GTXSTEP + * wlan0 get_gtxStep:0 + * + * This IOCTL is used to get the gtx step + * + * @E.g: iwpriv wlan0 get_gtxStep + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_GET_GTX_STEP 52 +/* + * + * get_gtxMinTpc - Get the tx miminum tpc + * + * @INPUT: None + * + * @OUTPUT: TPC + * wlan0 get_gtxMinTpc:0 + * + * This IOCTL is used to get tx miminum tpc + * + * @E.g: iwpriv wlan0 get_gtxMinTpc + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_GET_GTX_MINTPC 53 +/* + * + * get_gtxBWMask - Get the tx BW MASK + * + * @INPUT: None + * + * @OUTPUT: MASK + * wlan0 get_gtxBWMask:15 + * + * This IOCTL is used get gtx bw mask + * + * @E.g: iwpriv wlan0 get_gtxBWMask + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_GET_GTX_BWMASK 54 +#define WE_GET_TEMPERATURE 56 +#define WE_CAP_TSF 58 +#define WE_GET_ROAM_SYNCH_DELAY 59 + +/* Private ioctls and their sub-ioctls */ +#define WLAN_PRIV_SET_INT_GET_INT (SIOCIWFIRSTPRIV + 2) + +/* Private ioctls and their sub-ioctls */ +#define WLAN_PRIV_SET_CHAR_GET_NONE (SIOCIWFIRSTPRIV + 3) +#define WE_WOWL_ADD_PTRN 1 +#define WE_WOWL_DEL_PTRN 2 +/* + * + * neighbor - Send neighbor report request + * + * @INPUT: string + * + * @OUTPUT: None + * + * This IOCTL create a Neighbor report request and send it to peer + * + * @E.g: iwpriv wlan0 neighbor "SSID" + * + * Supported Feature: 11k + * + * Usage: Internal/External + * + * + */ +#define WE_NEIGHBOR_REPORT_REQUEST 3 +/* + * + * set_ap_wps_ie - Set the P2P IE of the probe response + * + * @INPUT: string + * + * @OUTPUT: None + * + * This IOCTL sets the P2P IE of the probe response + * + * @E.g: iwpriv wlan0 set_ap_wps_ie abcd + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_SET_AP_WPS_IE 4 /* This is called in station mode to set probe rsp ie. */ +#define WE_SET_CONFIG 5 + +/* Private ioctls and their sub-ioctls */ +#define WLAN_PRIV_SET_THREE_INT_GET_NONE (SIOCIWFIRSTPRIV + 4) +#define WE_SET_WLAN_DBG 1 +#define WE_SET_DP_TRACE 2 +#define WE_SET_SAP_CHANNELS 3 +#define WE_SET_FW_TEST 4 + +/* Private ioctls and their sub-ioctls */ +#define WLAN_PRIV_GET_CHAR_SET_NONE (SIOCIWFIRSTPRIV + 5) +#define WE_WLAN_VERSION 1 +#define WE_GET_STATS 2 +/* + * + * getConfig - gets the values of all configurations listed in WCNSS + * + * @INPUT: None + * + * @OUTPUT: Current configuration to the sys log + * wlan0 getConfig: WLAN configuration written to system log + * + * This IOCTL gets the values of all configurations listed in WCNSS + * + * @E.g: iwpriv wlan0 getConfig + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_GET_CFG 3 +#define WE_GET_WMM_STATUS 4 +/* + * + * getChannelList - Get the available channel list while in QCMobileAP + * + * @INPUT: None + * + * @OUTPUT: Channel list + * wlan0 getChannelList:36 US 1..165 + * + * This IOCTL gets the available channel list while in QCMobileAP + * + * @E.g: iwpriv wlan0 getChannelList + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_GET_CHANNEL_LIST 5 +/* + * + * getRSSI - Get the Received Signal Strength Indicator + * + * @INPUT: None + * + * @OUTPUT: RSSI + * wlan0 getRSSI:rsssi=-32 + * + * This IOCTL gets the Received Signal Strength Indicator (RSSI) + * + * @E.g: iwpriv wlan0 getRSSI + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_GET_RSSI 6 + +/* + * + * getSuspendStats - Get suspend/resume stats + * + * @INPUT: None + * + * @OUTPUT: character string containing formatted suspend/resume stats + * + * This ioctl is used to get suspend/resume stats formatted for display. + * Currently it includes suspend/resume counts, wow wake up reasons, and + * suspend fail reasons. + * + * @E.g: iwpriv wlan0 getSuspendStats + * iwpriv wlan0 getSuspendStats + * + * Supported Feature: suspend/resume + * + * Usage: Internal + * + * + */ +#define WE_GET_SUSPEND_RESUME_STATS 7 +#ifdef FEATURE_WLAN_TDLS +/* + * + * getTdlsPeers - Get all TDLS peers. + * + * @INPUT: None + * + * @OUTPUT: Returns the MAC address of all the TDLS peers + * wlan0 getTdlsPeers: + * MAC Id cap up RSSI + * --------------------------------- + * 00:0a:f5:0e:bd:18 2 Y Y -44 + * 00:0a:f5:bf:0e:12 0 N N 0 + * + * This IOCTL is used to get all TDLS peers. + * + * @E.g: iwpriv wlan0 getTdlsPeers + * + * Supported Feature: TDLS + * + * Usage: Internal/External + * + * + */ +#define WE_GET_TDLS_PEERS 8 +#endif +#ifdef WLAN_FEATURE_11W +/* + * + * getPMFInfo - get the PMF info of the connected session + * + * @INPUT: None + * + * @OUTPUT: + * wlan0 getPMFInfo: + * BSSID E4:F4:C6:0A:E0:36, Is PMF Assoc? 0 + * Number of Unprotected Disassocs 0 + * Number of Unprotected Deauths 0 + * + * This IOCTL is used to get the PMF stats/status of the current + * connection. + * + * @e.g:iwpriv wlan0 getPMFInfo + * + * Supported Feature: PMF + * + * Usage: Internal/External + * + * + */ +#define WE_GET_11W_INFO 9 +#endif +#define WE_GET_STATES 10 +/* + * + * getIbssSTAs - get ibss sta info + * + * @INPUT: None + * + * @OUTPUT: Give the MAC of the IBSS STA + * wlan0 getIbssSTAs: + * 1 .8c:fd:f0:01:9c:bf + * + * This IOCTL is used to get ibss sta info + * + * @E.g: iwpriv wlan0 getIbssSTAs + * + * Supported Feature: IBSS + * + * Usage: Internal/External + * + * + */ +#define WE_GET_IBSS_STA_INFO 11 +/* + * + * getphymode - Get the current phymode. + * + * @INPUT: None + * + * @OUTPUT: In phymode + * wlan0 getphymode:AUTO MODE + * + * This IOCTL used to gets the current phymode. + * + * @E.g: iwpriv wlan0 getphymode + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_GET_PHYMODE 12 +#ifdef FEATURE_OEM_DATA_SUPPORT +#define WE_GET_OEM_DATA_CAP 13 +#endif +/* + * + * getSNR - Enable SNR Monitoring + * + * @INPUT: None + * + * @OUTPUT: Signal strength/ratio + * wlan0 getSNR:1 + * + * This IOCTL is used to get ibss sta info + * + * @E.g: iwpriv wlan0 getSNR + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_GET_SNR 14 +#define WE_LIST_FW_PROFILE 15 + +/* Private ioctls and their sub-ioctls */ +#define WLAN_PRIV_SET_NONE_GET_NONE (SIOCIWFIRSTPRIV + 6) + +/* + * + * reassoc - Trigger STA re-association to the connected AP + * + * @INPUT: None + * + * @OUTPUT: None + * + * This IOCTL is used to trigger STA reassociation to the connected AP. + * + * @E.g: iwpriv wlan0 reassoc + * + * Supported Feature: Roaming + * + * Usage: Internal + * + * + */ +#define WE_SET_REASSOC_TRIGGER 8 +/* + * + * ibssPeerInfoAll - Print the ibss peers's MAC, rate and RSSI + * + * @INPUT: None + * + * @OUTPUT: print ibss peer in info logs + * pPeerInfo->numIBSSPeers = 1 + * PEER ADDR : 8c:fd:f0:01:9c:bf TxRate: 1 Mbps RSSI: -35 + * + * This IOCTL is used to rint the ibss peers's MAC, rate and RSSI + * in info logs + * + * @E.g: iwpriv wlan0 ibssPeerInfoAll + * + * Supported Feature: IBSS + * + * Usage: Internal/External + * + * + */ +#define WE_IBSS_GET_PEER_INFO_ALL 10 +/* Sub ioctls 11 to 16 are not used */ +#define WE_GET_RECOVERY_STAT 17 +#define WE_GET_FW_PROFILE_DATA 18 +/* + * + * stop_obss_scan - Stop obss scan + * + * @INPUT: None + * + * @OUTPUT: None + * + * This IOCTL is used to stop obss scan + * + * @E.g: iwpriv wlan0 stop_obss_scan + * + * Supported Feature: Scan + * + * Usage: Internal/External + * + * + */ +#define WE_STOP_OBSS_SCAN 19 + +/* Private ioctls and their sub-ioctls */ +#define WLAN_PRIV_SET_VAR_INT_GET_NONE (SIOCIWFIRSTPRIV + 7) + +#define WE_P2P_NOA_CMD 2 +/* subcommands 3 is unused */ + +#define WE_MAC_PWR_DEBUG_CMD 4 + +#ifdef FEATURE_WLAN_TDLS +/* + * + * setTdlsConfig - Set TDLS configuration parameters. + * + * @INPUT: 11 TDLS configuration parameters + * @args[0]: tdls: [0..2] + * @args[1]: tx_period_t: [1000..4294967295UL] + * @args[2]: tx_packet_n: [0..4294967295UL] + * @args[3]: [discovery_period is not used anymore] + * @args[4]: discovery_tries_n: [1..100] + * @args[5]: [idle_timeout is not used anymore] + * @args[6]: idle_packet_n: [0..40000] + * @args[7]: [rssi_hysteresis is not used anymore] + * @args[8]: rssi_trigger_threshold: [-120..0] + * @args[9]: rssi_teardown_threshold: [-120..0] + * @args[10]: rssi_delta: [-30..0] + * + * @OUTPUT: None + * + * This IOCTL is used to set the TDLS configuration parameters. + * + * @E.g: iwpriv wlan0 setTdlsConfig tdls tx_period_t tx_packet_n + * discovery_period discovery_tries_n idle_timeout + * idle_packet_n rssi_hysteresis rssi_trigger_threshold + * rssi_teardown_threshold rssi_delta + * iwpriv wlan0 setTdlsConfig 1 1500 40 1 5 1 5 0 -70 -70 -10 + * + * Supported Feature: TDLS + * + * Usage: Internal/External + * + * + */ + + +#define WE_TDLS_CONFIG_PARAMS 5 +#endif +/* + * + * ibssPeerInfo - Print the ibss peers's MAC, rate and RSSI + * + * @INPUT: staid + * + * @OUTPUT: print ibss peer corresponding to staid in info logs + * PEER ADDR : 8c:fd:f0:01:9c:bf TxRate: 1 Mbps RSSI: -35 + * + * This IOCTL is used to print the specific ibss peers's MAC, + * rate and RSSI in info logs + * + * @E.g: iwpriv wlan0 ibssPeerInfo + * iwpriv wlan0 ibssPeerInfo 0 + * + * Supported Feature: IBSS + * + * Usage: Internal/External + * + * + */ +#define WE_IBSS_GET_PEER_INFO 6 +#define WE_UNIT_TEST_CMD 7 + +#define WE_MTRACE_DUMP_CMD 8 +#define WE_MTRACE_SELECTIVE_MODULE_LOG_ENABLE_CMD 9 + + +#ifdef WLAN_FEATURE_GPIO_LED_FLASHING +#define WE_LED_FLASHING_PARAM 10 +#endif + +/* + * + * pm_clist - Increments the index value of the concurrent connection list + * and update with the input parameters provided. + * + * @INPUT: Following 8 arguments: + * @vdev_id: vdev id + * @tx_streams: TX streams + * @rx_streams: RX streams + * @chain_mask: Chain mask + * @type: vdev_type + * AP:1 STA:2 IBSS:3 Monitor:4 NAN:5 OCB:6 NDI:7 + * @sub_type: vdev_subtype + * P2P_Device:1 P2P_Client:2 P2P_GO:3 + * Proxy_STA:4 Mesh:5 Mesh_11s:6 + * @channel: Channel + * @mac: Mac id + * + * @OUTPUT: None + * + * This IOCTL is used to increments the index value of the concurrent connection + * list and update with the input parameters provided. + * + * @E.g: iwpriv wlan0 pm_clist vdev_id tx_streams rx_streams chain_mask type + * sub_type channel mac + * iwpriv wlan0 pm_clist 1 2 2 1 2 3 10 1 + * + * Supported Feature: DBS + * + * Usage: Internal/External + * + * + */ +#define WE_POLICY_MANAGER_CLIST_CMD 11 + +/* + * + * pm_dlist - Delete the index from the concurrent connection list that is + * present in the given vdev_id. + * + * @INPUT: delete_all, vdev_id + * @delete_all: delete all indices + * @vdev_id: vdev id + * + * @OUTPUT: None + * + * This IOCTL is used to delete the index from the concurrent connection list + * that is present in the given vdev_id. + * + * @E.g: iwpriv wlan0 pm_dlist delete_all vdev_id + * iwpriv wlan0 pm_dlist 0 1 + * + * Supported Feature: DBS + * + * Usage: Internal/External + * + * + */ +#define WE_POLICY_MANAGER_DLIST_CMD 12 + +/* + * + * pm_dbs - Set dbs capability and system preference + * + * @INPUT: dbs, system_pref + * @dbs: Value of DBS capability to be set + * @system_pref: System preference + * 0:CDS_THROUGHPUT 1: CDS_POWERSAVE 2: CDS_LATENCY + * + * @OUTPUT: None + * + * This IOCTL is used to set dbs capability and system preference. + * + * @E.g: iwpriv wlan0 pm_dbs dbs system_pref + * iwpriv wlan0 pm_dbs 1 0 + * + * Supported Feature: DBS + * + * Usage: Internal/External + * + * + */ +#define WE_POLICY_MANAGER_DBS_CMD 13 + +/* + * + * pm_pcl - Set pcl for concurrency mode. + * + * @INPUT: cds_con_mode + * @cds_con_mode: concurrency mode for PCL table + * 0:STA 1:SAP 2:P2P_Client 3:P2P_GO 4:IBSS + * + * @OUTPUT: None + * + * This IOCTL is used to set pcl for concurrency mode. + * + * @E.g: iwpriv wlan0 pm_pcl cds_con_mode + * iwpriv wlan0 pm_pcl 0 + * + * Supported Feature: DBS + * + * Usage: Internal/External + * + * + */ +#define WE_POLICY_MANAGER_PCL_CMD 14 + +/* + * + * pm_cinfo - Shows the concurrent connection list. + * + * @INPUT: None + * + * @OUTPUT: None + * + * This IOCTL is used to show the concurrent connection list. + * + * @E.g: iwpriv wlan0 pm_cinfo + * + * Supported Feature: DBS + * + * Usage: Internal/External + * + * + */ +#define WE_POLICY_MANAGER_CINFO_CMD 15 + +/* + * + * pm_ulist - Updates the index value of the concurrent connection list + * with the input parameters provided. + * + * @INPUT: Following 8 arguments: + * @vdev_id: vdev id + * @tx_streams: TX streams + * @rx_streams: RX streams + * @chain_mask: Chain mask + * @type: vdev_type + * AP:1 STA:2 IBSS:3 Monitor:4 NAN:5 OCB:6 NDI:7 + * @sub_type: vdev_subtype + * P2P_Device:1 P2P_Client:2 P2P_GO:3 + * Proxy_STA:4 Mesh:5 Mesh_11s:6 + * @channel: Channel + * @mac: Mac id + * + * @OUTPUT: None + * + * This IOCTL is used to updates the index value of the concurrent + * connection list with the input parameters provided. + * + * @E.g: iwpriv wlan0 pm_ulist vdev_id tx_streams rx_streams chain_mask type + * sub_type channel mac + * iwpriv wlan0 pm_ulist 1 2 2 1 2 3 10 1 + * + * Supported Feature: DBS + * + * Usage: Internal/External + * + * + */ +#define WE_POLICY_MANAGER_ULIST_CMD 16 + +/* + * + * pm_query_action - Initiate actions needed on current connections as + * per the channel provided. + * + * @INPUT: channel + * @channel: Channel on which new connection will be. + * + * @OUTPUT: None + * + * This IOCTL is used to initiate actions needed on current connections + * as per the channel provided. + * + * @E.g: iwpriv wlan0 pm_query_action channel + * iwpriv wlan0 pm_query_action 6 + * + * Supported Feature: DBS + * + * Usage: Internal/External + * + * + */ +#define WE_POLICY_MANAGER_QUERY_ACTION_CMD 17 + +/* + * + * pm_query_allow - Checks for allowed concurrency combination + * + * @INPUT: mode, channel, bandwidth + * @mode: new connection mode + * 0:STA 1:SAP 2:P2P_Client 3:P2P_GO 4:IBSS + * @channel: channel on which new connection is coming up + * @bandwidth: Bandwidth requested by the connection + * 0:None 1:5MHz 2:10MHz 3:20MHz + * 4:40MHz 5:80MHz 6:80+80MHz 7:160MHz + * + * @OUTPUT: None + * + * This IOCTL is used to checks for allowed concurrency combination. + * + * @E.g: iwpriv wlan0 pm_query_allow mode channel bandwidth + * iwpriv wlan0 pm_query_allow 0 6 4 + * + * Supported Feature: DBS + * + * Usage: Internal/External + * + * + */ +#define WE_POLICY_MANAGER_QUERY_ALLOW_CMD 18 + +/* + * + * pm_run_scenario - Create scenario with number of connections provided. + * + * @INPUT: num_of_conn + * @num_of_conn: the number of connections (values: 1~3) + * + * @OUTPUT: None + * + * This IOCTL is used to create scenario with the number of connections + * provided. + * + * @E.g: iwpriv wlan0 pm_run_scenario num_of_conn + * iwpriv wlan0 pm_run_scenario 1 + * + * Supported Feature: DBS + * + * Usage: Internal/External + * + * + */ +#define WE_POLICY_MANAGER_SCENARIO_CMD 19 + +/* + * + * pm_set_hw_mode - Set hardware for single/dual mac. + * + * @INPUT: hw_mode + * 0:single mac 1:dual mac + * + * @OUTPUT: None + * + * This IOCTL is used to set hardware for single/dual mac. + * + * @E.g: iwpriv wlan0 pm_set_hw_mode hw_mode + * iwpriv wlan0 pm_set_hw_mode 1 + * + * Supported Feature: DBS + * + * Usage: Internal/External + * + * + */ +#define WE_POLICY_SET_HW_MODE_CMD 20 + +/* + * + * set_scan_cfg - Set dual MAC scan config parameters. + * + * @INPUT: dbs, dbs_plus_agile_scan, single_mac_scan_with_dbs + * @dbs: Value of DBS bit + * @dbs_plus_agile_scan: Value of DBS plus agile scan bit + * @single_mac_scan_with_dbs: Value of Single MAC scan with DBS + * + * @OUTPUT: None + * + * This IOCTL is used to set the dual MAC scan config. + * + * @E.g: iwpriv wlan0 set_scan_cfg dbs dbs_plus_agile_scan + * single_mac_scan_with_dbs + * iwpriv wlan0 set_scan_cfg 1 0 1 + * + * Supported Feature: DBS + * + * Usage: Internal/External + * + * + */ +#define WE_SET_DUAL_MAC_SCAN_CONFIG 21 + +/* + * + * set_fw_mode_cfg - Sets the dual mac FW mode config + * + * @INPUT: dbs, dfs + * @dbs: DBS bit + * @dfs: Agile DFS bit + * + * @OUTPUT: None + * + * This IOCTL is used to set the dual mac FW mode config. + * + * @E.g: iwpriv wlan0 set_fw_mode_cfg dbs dfs + * iwpriv wlan0 set_fw_mode_cfg 1 1 + * + * Supported Feature: DBS + * + * Usage: Internal/External + * + * + */ +#define WE_SET_DUAL_MAC_FW_MODE_CONFIG 22 +#define WE_SET_MON_MODE_CHAN 23 + +#ifdef FEATURE_WLAN_TDLS +#undef MAX_VAR_ARGS +#define MAX_VAR_ARGS 11 +#else +#undef MAX_VAR_ARGS +#define MAX_VAR_ARGS 9 +#endif + +/* Private ioctls (with no sub-ioctls) */ +/* note that they must be odd so that they have "get" semantics */ +/* + * + * addTspec - Add TSPEC for each AC + * + * @INPUT: 19 TSPEC params + * @[arg0]: handle + * @[arg1]: tid + * @[arg2]: dir + * @[arg3]: psb + * @[arg4]: up + * @[arg5]: nomMsduSize + * @[arg6]: maxMsduSize + * @[arg7]: minDataRate + * @[arg8]: meanDataRate + * @[arg9]: peakDataRate + * @[arg10]: maxBurstSize + * @[arg11]: minPhyRate + * @[arg12]: sba + * @[arg13]: minServiceIntv + * @[arg14]: suspendIntv + * @[arg15]: burstSizeDefn + * @[arg16]: ackPolicy + * @[arg17]: inactivityPeriod + * @[arg18]: maxServiceIntv + * + * @OUTPUT: Success/Failure + * + * This IOCTL is used to add TSPEC for each AC. + * + * @E.g: iwpriv wlan0 addTspec + * + * + * + * + * + * iwpriv wlan0 addTspec 7001 6 2 1 6 0x80D0 0x80D0 0x14500 0x14500 0x14500 + * 0 0x5B8D80 0x2001 20 2000 0 0 0 2000 + * wlan0 addTspec:3 + * + * Supported Feature: WMM + * + * Usage: Internal/External + * + * + */ +#define WLAN_PRIV_ADD_TSPEC (SIOCIWFIRSTPRIV + 9) +/* + * + * delTspec - Delete TSPEC entry for each AC + * + * @INPUT: 1 TSPEC param + * @[arg0]: handle + * + * @OUTPUT: Success/Failure + * + * This IOCTL is used to delete TSPEC entry for each AC. + * + * @E.g: iwpriv wlan0 delTspec + * iwpriv wlan0 delTspec 7001 + * wlan0 delTspec:16 + * + * Supported Feature: WMM + * + * Usage: Internal/External + * + * + */ +#define WLAN_PRIV_DEL_TSPEC (SIOCIWFIRSTPRIV + 11) +/* + * + * getTspec - Get TSPEC entry for each AC + * + * @INPUT: 1 TSPEC param + * @[arg0]: handle + * + * @OUTPUT: Success/Failure + * + * This IOCTL is used to get TSPEC entry for each AC. + * + * @E.g: iwpriv wlan0 getTspec + * iwpriv wlan0 getTspec 7001 + * wlan0 delTspec:18 + * + * Supported Feature: WMM + * + * Usage: Internal/External + * + * + */ +#define WLAN_PRIV_GET_TSPEC (SIOCIWFIRSTPRIV + 13) + +/* (SIOCIWFIRSTPRIV + 8) is currently unused */ +/* (SIOCIWFIRSTPRIV + 10) is currently unused */ +/* (SIOCIWFIRSTPRIV + 12) is currently unused */ +/* (SIOCIWFIRSTPRIV + 14) is currently unused */ +#define WLAN_PRIV_SET_NONE_GET_THREE_INT (SIOCIWFIRSTPRIV + 15) +#define WE_GET_TSF 1 +/* (SIOCIWFIRSTPRIV + 16) is currently unused */ +/* (SIOCIWFIRSTPRIV + 17) is currently unused */ +/* (SIOCIWFIRSTPRIV + 19) is currently unused */ + +#define WLAN_PRIV_SET_FTIES (SIOCIWFIRSTPRIV + 20) + +/* Private ioctl for setting the host offload feature */ +#define WLAN_PRIV_SET_HOST_OFFLOAD (SIOCIWFIRSTPRIV + 18) + +/* Private ioctl to get the statistics */ +#define WLAN_GET_WLAN_STATISTICS (SIOCIWFIRSTPRIV + 21) + +/* Private ioctl to set the Keep Alive Params */ +/* + * + * setKeepAlive - Set the keep alive feature + * + * @INPUT: 28 bytes of information in the order of packet type, time period + * host IPv4 address, destination IPv4 address, destination MAC address, bssID + * + * @OUTPUT: None + * + * This IOCTL sets the keep alive feature to send either NULL + * or unsolicited ARP response packets + * + * @E.g: iwpriv wlan0 setKeepAlive + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WLAN_SET_KEEPALIVE_PARAMS (SIOCIWFIRSTPRIV + 22) + +#ifdef WLAN_FEATURE_PACKET_FILTERING +/* Private ioctl to set the packet filtering params */ +#define WLAN_SET_PACKET_FILTER_PARAMS (SIOCIWFIRSTPRIV + 23) +#endif + + +#ifdef FEATURE_WLAN_SCAN_PNO +/* Private ioctl to get the statistics */ +#define WLAN_SET_PNO (SIOCIWFIRSTPRIV + 24) +#endif +/* + * + * SETBAND - Set the operational band + * + * @INPUT: 0 to Auto, 1 to 5 GHz and 2 to 2.4 GHz + * + * @OUTPUT: None + * + * This IOCTL Set the operational band If the new band is different from the + * current operational band, it aborts the pending scan requests, flushes + * the existing scan results, and then change * the band capability + * + * @E.g: iwpriv wlan0 SETBAND + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WLAN_SET_BAND_CONFIG (SIOCIWFIRSTPRIV + 25) + +#define WLAN_PRIV_SET_MCBC_FILTER (SIOCIWFIRSTPRIV + 26) +/* (SIOCIWFIRSTPRIV + 27) is currently unused */ + +/* Private ioctls and their sub-ioctls */ +#define WLAN_PRIV_SET_TWO_INT_GET_NONE (SIOCIWFIRSTPRIV + 28) +#define WE_SET_SMPS_PARAM 1 +#ifdef WLAN_DEBUG +#define WE_SET_FW_CRASH_INJECT 2 +#endif +#define WE_DUMP_DP_TRACE_LEVEL 3 +/* Private sub ioctl for enabling and setting histogram interval of profiling */ +#define WE_ENABLE_FW_PROFILE 4 +#define WE_SET_FW_PROFILE_HIST_INTVL 5 + +/* Private sub-ioctl for initiating WoW suspend without Apps suspend */ +#define WE_SET_WLAN_SUSPEND 6 +#define WE_SET_WLAN_RESUME 7 + +/* (SIOCIWFIRSTPRIV + 29) is currently unused */ + +/* 802.11p IOCTL */ +#define WLAN_SET_DOT11P_CHANNEL_SCHED (SIOCIWFIRSTPRIV + 30) + +/* + * + * getLinkSpeed - Gets the current link speed in Mbps + * + * @INPUT: None + * + * @OUTPUT: linkspeed in mbps + * wlan0 getLinkSpeed:7 + * + * This IOCTL is used get the current link speed in Mbps + * + * @E.g: iwpriv wlan0 getLinkSpeed + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WLAN_GET_LINK_SPEED (SIOCIWFIRSTPRIV + 31) + +#define WLAN_STATS_INVALID 0 +#define WLAN_STATS_RETRY_CNT 1 +#define WLAN_STATS_MUL_RETRY_CNT 2 +#define WLAN_STATS_TX_FRM_CNT 3 +#define WLAN_STATS_RX_FRM_CNT 4 +#define WLAN_STATS_FRM_DUP_CNT 5 +#define WLAN_STATS_FAIL_CNT 6 +#define WLAN_STATS_RTS_FAIL_CNT 7 +#define WLAN_STATS_ACK_FAIL_CNT 8 +#define WLAN_STATS_RTS_SUC_CNT 9 +#define WLAN_STATS_RX_DISCARD_CNT 10 +#define WLAN_STATS_RX_ERROR_CNT 11 +#define WLAN_STATS_TX_BYTE_CNT 12 + +#define WLAN_STATS_RX_BYTE_CNT 13 +#define WLAN_STATS_RX_RATE 14 +#define WLAN_STATS_TX_RATE 15 + +#define WLAN_STATS_RX_UC_BYTE_CNT 16 +#define WLAN_STATS_RX_MC_BYTE_CNT 17 +#define WLAN_STATS_RX_BC_BYTE_CNT 18 +#define WLAN_STATS_TX_UC_BYTE_CNT 19 +#define WLAN_STATS_TX_MC_BYTE_CNT 20 +#define WLAN_STATS_TX_BC_BYTE_CNT 21 + +#define FILL_TLV(__p, __type, __size, __val, __tlen) do { \ + if ((__tlen + __size + 2) < WE_MAX_STR_LEN) { \ + *__p++ = __type; \ + *__p++ = __size; \ + memcpy(__p, __val, __size); \ + __p += __size; \ + __tlen += __size + 2; \ + } else { \ + hdd_err("FILL_TLV Failed!!!"); \ + } \ + } while (0) + +#define VERSION_VALUE_MAX_LEN 32 + +#define TX_PER_TRACKING_DEFAULT_RATIO 5 +#define TX_PER_TRACKING_MAX_RATIO 10 +#define TX_PER_TRACKING_DEFAULT_WATERMARK 5 + +#define WLAN_ADAPTER 0 +#define P2P_ADAPTER 1 + +/** + * mem_alloc_copy_from_user_helper - copy from user helper + * @wrqu_data: wireless extensions request data + * @len: length of @wrqu_data + * + * Helper function to allocate buffer and copy user data. + * + * Return: On success return a pointer to a kernel buffer containing a + * copy of the userspace data (with an additional NUL character + * appended for safety). On failure return %NULL. + */ +void *mem_alloc_copy_from_user_helper(const __user void *wrqu_data, size_t len) +{ + u8 *ptr = NULL; + + /* in order to protect the code, an extra byte is post + * appended to the buffer and the null termination is added. + * However, when allocating (len+1) byte of memory, we need to + * make sure that there is no uint overflow when doing + * addition. In theory check len < UINT_MAX protects the uint + * overflow. For wlan private ioctl, the buffer size is much + * less than UINT_MAX, as a good guess, now, it is assumed + * that the private command buffer size is no greater than 4K + * (4096 bytes). So we use 4096 as the upper boundary for now. + */ + if (len > MAX_USER_COMMAND_SIZE) { + hdd_err("Invalid length"); + return NULL; + } + + ptr = qdf_mem_malloc(len + 1); + if (NULL == ptr) { + hdd_err("unable to allocate memory"); + return NULL; + } + + if (copy_from_user(ptr, wrqu_data, len)) { + hdd_err("failed to copy data to user buffer"); + qdf_mem_free(ptr); + return NULL; + } + ptr[len] = '\0'; + return ptr; +} + +/** + * hdd_priv_get_data() - Get pointer to ioctl private data + * @p_priv_data: pointer to iw_point struct to be filled + * @wrqu: Pointer to IOCTL Data received from userspace + * + * Helper function to get compatible struct iw_point passed to ioctl + * + * Return - 0 if p_priv_data successfully filled, error otherwise + */ +int hdd_priv_get_data(struct iw_point *p_priv_data, union iwreq_data *wrqu) +{ + if ((NULL == p_priv_data) || (NULL == wrqu)) { + return -EINVAL; + } +#ifdef CONFIG_COMPAT + if (is_compat_task()) { + struct compat_iw_point *p_compat_priv_data; + + /* Compat task: + * typecast to compat structure and copy the members. + */ + p_compat_priv_data = (struct compat_iw_point *)&wrqu->data; + + p_priv_data->pointer = compat_ptr(p_compat_priv_data->pointer); + p_priv_data->length = p_compat_priv_data->length; + p_priv_data->flags = p_compat_priv_data->flags; + } else { +#endif /* #ifdef CONFIG_COMPAT */ + + /* Non compat task: directly copy the structure. */ + memcpy(p_priv_data, &wrqu->data, sizeof(struct iw_point)); + +#ifdef CONFIG_COMPAT + } +#endif /* #ifdef CONFIG_COMPAT */ + + return 0; +} + + +/** + * hdd_wlan_get_stats() - Get txrx stats in SAP mode + * @pAdapter: Pointer to the hdd adapter. + * @length: Size of the data copied + * @buffer: Pointer to char buffer. + * @buf_len: Length of the char buffer. + * + * This function called when the "iwpriv wlan0 get_stats" command is given. + * It used to collect the txrx stats when the device is configured in SAP mode. + * + * Return - none + */ +void hdd_wlan_get_stats(hdd_adapter_t *pAdapter, uint16_t *length, + char *buffer, uint16_t buf_len) +{ + hdd_tx_rx_stats_t *pStats = &pAdapter->hdd_stats.hddTxRxStats; + uint32_t len = 0; + uint32_t total_rx_pkt = 0, total_rx_dropped = 0; + uint32_t total_rx_delv = 0, total_rx_refused = 0; + int i = 0; + + for (; i < NUM_CPUS; i++) { + total_rx_pkt += pStats->rxPackets[i]; + total_rx_dropped += pStats->rxDropped[i]; + total_rx_delv += pStats->rxDelivered[i]; + total_rx_refused += pStats->rxRefused[i]; + } + + len = scnprintf(buffer, buf_len, + "\nTransmit[%lu] - " + "called %u, dropped %u orphan %u," + "\n[dropped] BK %u, BE %u, VI %u, VO %u" + "\n[classified] BK %u, BE %u, VI %u, VO %u" + "\n\nReceive[%lu] - " + "packets %u, dropped %u, delivered %u, refused %u" + "\n", + qdf_system_ticks(), + pStats->txXmitCalled, + pStats->txXmitDropped, + pStats->txXmitOrphaned, + + pStats->txXmitDroppedAC[SME_AC_BK], + pStats->txXmitDroppedAC[SME_AC_BE], + pStats->txXmitDroppedAC[SME_AC_VI], + pStats->txXmitDroppedAC[SME_AC_VO], + + pStats->txXmitClassifiedAC[SME_AC_BK], + pStats->txXmitClassifiedAC[SME_AC_BE], + pStats->txXmitClassifiedAC[SME_AC_VI], + pStats->txXmitClassifiedAC[SME_AC_VO], + qdf_system_ticks(), + total_rx_pkt, total_rx_dropped, total_rx_delv, total_rx_refused + ); + + for (i = 0; i < NUM_CPUS; i++) { + if (pStats->rxPackets[i] == 0) + continue; + len += scnprintf(buffer + len, buf_len - len, + "Rx CPU[%d]:" + "packets %u, dropped %u, delivered %u, refused %u\n", + i, pStats->rxPackets[i], pStats->rxDropped[i], + pStats->rxDelivered[i], pStats->rxRefused[i]); + } + + len += scnprintf(buffer + len, buf_len - len, + "\nTX_FLOW" + "\nCurrent status: %s" + "\ntx-flow timer start count %u" + "\npause count %u, unpause count %u", + (pStats->is_txflow_paused == true ? "PAUSED" : "UNPAUSED"), + pStats->txflow_timer_cnt, + pStats->txflow_pause_cnt, + pStats->txflow_unpause_cnt); + + len += ol_txrx_stats(pAdapter->sessionId, + &buffer[len], (buf_len - len)); + *length = len + 1; +} + +/** + * wlan_hdd_write_suspend_resume_stats() - Writes suspend/resume stats to buffer + * @hdd_ctx: The Hdd context owning the stats to be written + * @buffer: The char buffer to write to + * @max_len: The maximum number of chars to write + * + * This assumes hdd_ctx has already been validated, and buffer is not NULL. + * + * Return - length of written content, negative number on error + */ +static int wlan_hdd_write_suspend_resume_stats(hdd_context_t *hdd_ctx, + char *buffer, uint16_t max_len) +{ + QDF_STATUS status; + struct suspend_resume_stats *sr_stats; + struct sir_wake_lock_stats wow_stats; + + sr_stats = &hdd_ctx->suspend_resume_stats; + + status = wma_get_wakelock_stats(&wow_stats); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to get WoW stats"); + return qdf_status_to_os_return(status); + } + + return scnprintf(buffer, max_len, + "\n" + "Suspends: %u\n" + "Resumes: %u\n" + "\n" + "Suspend Fail Reasons\n" + "\tIPA: %u\n" + "\tRadar: %u\n" + "\tRoam: %u\n" + "\tScan: %u\n" + "\tInitial Wakeup: %u\n" + "\n" + "WoW Wake Reasons\n" + "\tunicast: %u\n" + "\tbroadcast: %u\n" + "\tIPv4 multicast: %u\n" + "\tIPv6 multicast: %u\n" + "\tIPv6 multicast RA: %u\n" + "\tIPv6 multicast NS: %u\n" + "\tIPv6 multicast NA: %u\n" + "\tICMPv4: %u\n" + "\tICMPv6: %u\n" + "\tRSSI Breach: %u\n" + "\tLow RSSI: %u\n" + "\tG-Scan: %u\n" + "\tPNO Complete: %u\n" + "\tPNO Match: %u\n", + sr_stats->suspends, + sr_stats->resumes, + sr_stats->suspend_fail[SUSPEND_FAIL_IPA], + sr_stats->suspend_fail[SUSPEND_FAIL_RADAR], + sr_stats->suspend_fail[SUSPEND_FAIL_ROAM], + sr_stats->suspend_fail[SUSPEND_FAIL_SCAN], + sr_stats->suspend_fail[SUSPEND_FAIL_INITIAL_WAKEUP], + wow_stats.wow_ucast_wake_up_count, + wow_stats.wow_bcast_wake_up_count, + wow_stats.wow_ipv4_mcast_wake_up_count, + wow_stats.wow_ipv6_mcast_wake_up_count, + wow_stats.wow_ipv6_mcast_ra_stats, + wow_stats.wow_ipv6_mcast_ns_stats, + wow_stats.wow_ipv6_mcast_na_stats, + wow_stats.wow_icmpv4_count, + wow_stats.wow_icmpv6_count, + wow_stats.wow_rssi_breach_wake_up_count, + wow_stats.wow_low_rssi_wake_up_count, + wow_stats.wow_gscan_wake_up_count, + wow_stats.wow_pno_complete_wake_up_count, + wow_stats.wow_pno_match_wake_up_count); +} + +/** + * hdd_wlan_list_fw_profile() - Get fw profiling points + * @length: Size of the data copied + * @buffer: Pointer to char buffer. + * @buf_len: Length of the char buffer. + * + * This function called when the "iwpriv wlan0 listProfile" command is given. + * It is used to get the supported profiling points in FW. + * + * Return - none + */ +void hdd_wlan_list_fw_profile(uint16_t *length, + char *buffer, uint16_t buf_len) +{ + uint32_t len = 0; + + len = scnprintf(buffer, buf_len, + "PROF_CPU_IDLE: %u\n" + "PROF_PPDU_PROC: %u\n" + "PROF_PPDU_POST: %u\n" + "PROF_HTT_TX_INPUT: %u\n" + "PROF_MSDU_ENQ: %u\n" + "PROF_PPDU_POST_HAL: %u\n" + "PROF_COMPUTE_TX_TIME: %u\n", + PROF_CPU_IDLE, + PROF_PPDU_PROC, + PROF_PPDU_POST, + PROF_HTT_TX_INPUT, + PROF_MSDU_ENQ, + PROF_PPDU_POST_HAL, + PROF_COMPUTE_TX_TIME); + + *length = len + 1; +} +/** + * hdd_display_stats_help() - print statistics help + * + * Return: none + */ +void hdd_display_stats_help(void) +{ + hdd_err("iwpriv wlan0 dumpStats [option] - dump statistics"); + hdd_err("iwpriv wlan0 clearStats [option] - clear statistics"); + hdd_err("options:"); + hdd_err(" 1 -- TXRX Layer statistics"); + hdd_err(" 2 -- Bandwidth compute timer stats"); + hdd_err(" 3 -- TSO statistics"); + hdd_err(" 4 -- Network queue statistics"); + hdd_err(" 5 -- Flow control statistics"); + hdd_err(" 6 -- Per Layer statistics"); + hdd_err(" 7 -- Copy engine interrupt statistics"); + hdd_err(" 8 -- LRO statistics"); + hdd_err(" 9 -- NAPI statistics"); +} + +/** + * hdd_wlan_dump_stats() - display dump Stats + * @adapter: adapter handle + * @value: value from user + * + * Return: 0 => success, error code on failure + */ +int hdd_wlan_dump_stats(hdd_adapter_t *adapter, int value) +{ + int ret = 0; + QDF_STATUS status; + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + + switch (value) { + case WLAN_TXRX_HIST_STATS: + wlan_hdd_display_tx_rx_histogram(hdd_ctx); + break; + case WLAN_HDD_NETIF_OPER_HISTORY: + wlan_hdd_display_netif_queue_history(hdd_ctx); + break; + case WLAN_HIF_STATS: + hdd_display_hif_stats(); + break; + case WLAN_LRO_STATS: + hdd_lro_display_stats(hdd_ctx); + case WLAN_NAPI_STATS: + if (hdd_display_napi_stats()) { + hdd_err("error displaying napi stats"); + ret = EFAULT; + } + break; + default: + status = ol_txrx_display_stats(value); + if (status == QDF_STATUS_E_INVAL) { + hdd_display_stats_help(); + ret = EINVAL; + } + break; + } + return ret; +} + +/** + * hdd_wlan_get_version() - Get driver version information + * @hdd_ctx: Global HDD context + * @wrqu: Pointer to IOCTL REQUEST Data. + * @extra: Pointer to destination buffer + * + * This function is used to get Wlan Driver, Firmware, & Hardware + * Version information. If @wrqu and @extra are specified, then the + * version string is returned. Otherwise it is simply printed to the + * kernel log. + * + * Return: none + */ +void hdd_wlan_get_version(hdd_context_t *hdd_ctx, union iwreq_data *wrqu, + char *extra) +{ + tSirVersionString wcnss_sw_version; + const char *swversion; + const char *hwversion; + uint32_t msp_id = 0, mspid = 0, siid = 0, crmid = 0, sub_id = 0; + + if (!hdd_ctx) { + hdd_err("Invalid context, HDD context is null"); + goto error; + } + + snprintf(wcnss_sw_version, sizeof(wcnss_sw_version), "%08x", + hdd_ctx->target_fw_version); + + swversion = wcnss_sw_version; + msp_id = (hdd_ctx->target_fw_version & 0xf0000000) >> 28; + mspid = (hdd_ctx->target_fw_version & 0xf000000) >> 24; + siid = (hdd_ctx->target_fw_version & 0xf00000) >> 20; + crmid = hdd_ctx->target_fw_version & 0x7fff; + sub_id = (hdd_ctx->target_fw_vers_ext & 0xf0000000) >> 28; + + hwversion = hdd_ctx->target_hw_name; + + if (wrqu && extra) { + wrqu->data.length = + scnprintf(extra, WE_MAX_STR_LEN, + "Host SW:%s, FW:%d.%d.%d.%d.%d, HW:%s", + QWLAN_VERSIONSTR, + msp_id, mspid, siid, crmid, + sub_id, hwversion); + } else { + pr_info("Host SW:%s, FW:%d.%d.%d.%d.%d, HW:%s\n", + QWLAN_VERSIONSTR, + msp_id, mspid, siid, crmid, sub_id, hwversion); + } +error: + return; +} + +/** + * hdd_wlan_get_ibss_mac_addr_from_staid() - Get IBSS MAC address + * @pAdapter: Adapter upon which the IBSS client is active + * @staIdx: Station index of the IBSS peer + * + * Return: a pointer to the MAC address of the IBSS peer if the peer is + * found, otherwise %NULL. + */ +struct qdf_mac_addr * +hdd_wlan_get_ibss_mac_addr_from_staid(hdd_adapter_t *pAdapter, + uint8_t staIdx) +{ + uint8_t idx; + hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + + for (idx = 0; idx < MAX_PEERS; idx++) { + if (0 != pHddStaCtx->conn_info.staId[idx] && + staIdx == pHddStaCtx->conn_info.staId[idx]) { + return &pHddStaCtx->conn_info.peerMacAddress[idx]; + } + } + return NULL; +} + +/** + * hdd_wlan_get_ibss_peer_info() - Print IBSS peer information + * @pAdapter: Adapter upon which the IBSS client is active + * @staIdx: Station index of the IBSS peer + * + * Return: QDF_STATUS_STATUS if the peer was found and displayed, + * otherwise an appropriate QDF_STATUS_E_* failure code. + */ +static QDF_STATUS hdd_wlan_get_ibss_peer_info(hdd_adapter_t *pAdapter, + uint8_t staIdx) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter); + hdd_station_ctx_t *pStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + tSirPeerInfoRspParams *pPeerInfo = &pStaCtx->ibss_peer_info; + + INIT_COMPLETION(pAdapter->ibss_peer_info_comp); + status = sme_request_ibss_peer_info(hHal, pAdapter, + hdd_get_ibss_peer_info_cb, + false, staIdx); + + if (QDF_STATUS_SUCCESS == status) { + unsigned long rc; + rc = wait_for_completion_timeout + (&pAdapter->ibss_peer_info_comp, + msecs_to_jiffies(IBSS_PEER_INFO_REQ_TIMOEUT)); + if (!rc) { + hdd_err("failed wait on ibss_peer_info_comp"); + return QDF_STATUS_E_FAILURE; + } + + /** Print the peer info */ + hdd_info("pPeerInfo->numIBSSPeers = %d ", pPeerInfo->numPeers); + { + uint8_t mac_addr[QDF_MAC_ADDR_SIZE]; + uint32_t tx_rate = pPeerInfo->peerInfoParams[0].txRate; + + qdf_mem_copy(mac_addr, pPeerInfo->peerInfoParams[0]. + mac_addr, sizeof(mac_addr)); + hdd_info("PEER ADDR : %pM TxRate: %d Mbps RSSI: %d", + mac_addr, (int)tx_rate, + (int)pPeerInfo->peerInfoParams[0].rssi); + } + } else { + hdd_warn("Warning: sme_request_ibss_peer_info Request failed"); + } + + return status; +} + +/** + * hdd_wlan_get_ibss_peer_info_all() - Print all IBSS peers + * @pAdapter: Adapter upon which the IBSS clients are active + * + * Return: QDF_STATUS_STATUS if the peer information was retrieved and + * displayed, otherwise an appropriate QDF_STATUS_E_* failure code. + */ +static QDF_STATUS hdd_wlan_get_ibss_peer_info_all(hdd_adapter_t *pAdapter) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter); + hdd_station_ctx_t *pStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + tSirPeerInfoRspParams *pPeerInfo = &pStaCtx->ibss_peer_info; + int i; + + INIT_COMPLETION(pAdapter->ibss_peer_info_comp); + status = sme_request_ibss_peer_info(hHal, pAdapter, + hdd_get_ibss_peer_info_cb, + true, 0xFF); + + if (QDF_STATUS_SUCCESS == status) { + unsigned long rc; + rc = wait_for_completion_timeout + (&pAdapter->ibss_peer_info_comp, + msecs_to_jiffies(IBSS_PEER_INFO_REQ_TIMOEUT)); + if (!rc) { + hdd_err("failed wait on ibss_peer_info_comp"); + return QDF_STATUS_E_FAILURE; + } + + /** Print the peer info */ + hdd_info("pPeerInfo->numIBSSPeers = %d ", + (int)pPeerInfo->numPeers); + for (i = 0; i < pPeerInfo->numPeers; i++) { + uint8_t mac_addr[QDF_MAC_ADDR_SIZE]; + uint32_t tx_rate; + + tx_rate = pPeerInfo->peerInfoParams[i].txRate; + qdf_mem_copy(mac_addr, + pPeerInfo->peerInfoParams[i].mac_addr, + sizeof(mac_addr)); + + hdd_info(" PEER ADDR : %pM TxRate: %d Mbps RSSI: %d", + mac_addr, (int)tx_rate, + (int)pPeerInfo->peerInfoParams[i].rssi); + } + } else { + hdd_warn("Warning: sme_request_ibss_peer_info Request failed"); + } + + return status; +} + +/** + * hdd_wlan_get_rts_threshold() - Get RTS threshold + * @pAdapter: adapter upon which the request was received + * @wrqu: pointer to the ioctl request + * + * This function retrieves the current RTS threshold value and stores + * it in the ioctl request structure + * + * Return: 0 if valid data was returned, non-zero on error + */ +int hdd_wlan_get_rts_threshold(hdd_adapter_t *pAdapter, union iwreq_data *wrqu) +{ + tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter); + uint32_t threshold = 0; + hdd_context_t *hdd_ctx; + int ret = 0; + + ENTER(); + + if (NULL == pAdapter) { + hdd_err("Adapter is NULL"); + return -EINVAL; + } + + hdd_ctx = WLAN_HDD_GET_CTX(pAdapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + if (QDF_STATUS_SUCCESS != + sme_cfg_get_int(hHal, WNI_CFG_RTS_THRESHOLD, &threshold)) { + hdd_warn("failed to get ini parameter, WNI_CFG_RTS_THRESHOLD"); + return -EIO; + } + wrqu->rts.value = threshold; + + hdd_notice("Rts-Threshold=%d!!", wrqu->rts.value); + + EXIT(); + + return 0; +} + +/** + * hdd_wlan_get_frag_threshold() - Get fragmentation threshold + * @pAdapter: adapter upon which the request was received + * @wrqu: pointer to the ioctl request + * + * This function retrieves the current fragmentation threshold value + * and stores it in the ioctl request structure + * + * Return: 0 if valid data was returned, non-zero on error + */ +int hdd_wlan_get_frag_threshold(hdd_adapter_t *pAdapter, + union iwreq_data *wrqu) +{ + tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter); + uint32_t threshold = 0, status = 0; + hdd_context_t *hdd_ctx; + + ENTER(); + + if (NULL == pAdapter) { + hdd_err("Adapter is NULL"); + return -EINVAL; + } + + hdd_ctx = WLAN_HDD_GET_CTX(pAdapter); + status = wlan_hdd_validate_context(hdd_ctx); + if (0 != status) + return status; + + if (sme_cfg_get_int(hHal, WNI_CFG_FRAGMENTATION_THRESHOLD, &threshold) + != QDF_STATUS_SUCCESS) { + hdd_warn("failed to get ini parameter, WNI_CFG_FRAGMENTATION_THRESHOLD"); + return -EIO; + } + wrqu->frag.value = threshold; + + hdd_notice("Frag-Threshold=%d!!", wrqu->frag.value); + + EXIT(); + + return 0; +} + +/** + * hdd_wlan_get_freq() - Convert channel to frequency + * @channel: channel to be converted + * @pfreq: where to store the frequency + * + * Return: 1 on success, otherwise a negative errno + */ +int hdd_wlan_get_freq(uint32_t channel, uint32_t *pfreq) +{ + int i; + if (channel > 0) { + for (i = 0; i < FREQ_CHAN_MAP_TABLE_SIZE; i++) { + if (channel == freq_chan_map[i].chan) { + *pfreq = freq_chan_map[i].freq; + return 1; + } + } + } + hdd_notice("Invalid channel no=%d!!", channel); + return -EINVAL; +} + +/** + * hdd_is_auth_type_rsn() - RSN authentication type check + * @authType: authentication type to be checked + * + * Return: true if @authType is an RSN authentication type, + * false if it is not + */ +static bool hdd_is_auth_type_rsn(eCsrAuthType authType) +{ + bool rsnType = false; + /* is the authType supported? */ + switch (authType) { + case eCSR_AUTH_TYPE_NONE: /* never used */ + rsnType = false; + break; + /* MAC layer authentication types */ + case eCSR_AUTH_TYPE_OPEN_SYSTEM: + rsnType = false; + break; + case eCSR_AUTH_TYPE_SHARED_KEY: + rsnType = false; + break; + case eCSR_AUTH_TYPE_AUTOSWITCH: + rsnType = false; + break; + + /* Upper layer authentication types */ + case eCSR_AUTH_TYPE_WPA: + rsnType = true; + break; + case eCSR_AUTH_TYPE_WPA_PSK: + rsnType = true; + break; + case eCSR_AUTH_TYPE_WPA_NONE: + rsnType = true; + break; + case eCSR_AUTH_TYPE_FT_RSN: + case eCSR_AUTH_TYPE_RSN: + rsnType = true; + break; + case eCSR_AUTH_TYPE_FT_RSN_PSK: + case eCSR_AUTH_TYPE_RSN_PSK: +#ifdef WLAN_FEATURE_11W + case eCSR_AUTH_TYPE_RSN_PSK_SHA256: + case eCSR_AUTH_TYPE_RSN_8021X_SHA256: +#endif + rsnType = true; + break; + /* case eCSR_AUTH_TYPE_FAILED: */ + case eCSR_AUTH_TYPE_UNKNOWN: + rsnType = false; + break; + default: + hdd_err("unknown authType %d, treat as open", + authType); + rsnType = false; + break; + } + hdd_notice("called with authType: %d, returned: %d", + authType, rsnType); + return rsnType; +} + +/** + * hdd_get_rssi_cb() - "Get RSSI" callback function + * @rssi: Current RSSI of the station + * @staId: ID of the station + * @pContext: opaque context originally passed to SME. HDD always passes + * a &struct statsContext + * + * Return: None + */ +static void hdd_get_rssi_cb(int8_t rssi, uint32_t staId, void *pContext) +{ + struct statsContext *pStatsContext; + hdd_adapter_t *pAdapter; + hdd_station_ctx_t *pHddStaCtx; + + if (ioctl_debug) { + pr_info("%s: rssi [%d] STA [%d] pContext [%p]\n", + __func__, (int)rssi, (int)staId, pContext); + } + + if (NULL == pContext) { + hdd_err("Bad param"); + return; + } + + pStatsContext = pContext; + pAdapter = pStatsContext->pAdapter; + pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(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) || + (RSSI_CONTEXT_MAGIC != pStatsContext->magic)) { + /* the caller presumably timed out so there is nothing + * we can do + */ + spin_unlock(&hdd_context_lock); + hdd_warn("Invalid context, pAdapter [%p] magic [%08x]", + pAdapter, pStatsContext->magic); + if (ioctl_debug) { + pr_info("%s: Invalid context, pAdapter [%p] magic [%08x]\n", + __func__, pAdapter, pStatsContext->magic); + } + return; + } + + /* context is valid so caller is still waiting */ + + /* paranoia: invalidate the magic */ + pStatsContext->magic = 0; + + /* update rssi only if its valid else return previous valid rssi */ + if (rssi) + pAdapter->rssi = rssi; + + /* for new connection there might be no valid previous RSSI */ + if (!pAdapter->rssi) + hdd_get_rssi_snr_by_bssid(pAdapter, + pHddStaCtx->conn_info.bssId.bytes, + &pAdapter->rssi, NULL); + + /* notify the caller */ + complete(&pStatsContext->completion); + + /* serialization is complete */ + spin_unlock(&hdd_context_lock); +} + +/** + * hdd_get_snr_cb() - "Get SNR" callback function + * @snr: Current SNR of the station + * @staId: ID of the station + * @pContext: opaque context originally passed to SME. HDD always passes + * a &struct statsContext + * + * Return: None + */ +static void hdd_get_snr_cb(int8_t snr, uint32_t staId, void *pContext) +{ + struct statsContext *pStatsContext; + hdd_adapter_t *pAdapter; + + if (ioctl_debug) { + pr_info("%s: snr [%d] STA [%d] pContext [%p]\n", + __func__, (int)snr, (int)staId, pContext); + } + + if (NULL == pContext) { + hdd_err("Bad param"); + 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) || (SNR_CONTEXT_MAGIC != pStatsContext->magic)) { + /* the caller presumably timed out so there is nothing + * we can do + */ + spin_unlock(&hdd_context_lock); + hdd_warn("Invalid context, pAdapter [%p] magic [%08x]", + pAdapter, pStatsContext->magic); + if (ioctl_debug) { + pr_info("%s: Invalid context, pAdapter [%p] magic [%08x]\n", + __func__, pAdapter, pStatsContext->magic); + } + return; + } + + /* context is valid so caller is still waiting */ + + /* paranoia: invalidate the magic */ + pStatsContext->magic = 0; + + /* copy over the snr */ + pAdapter->snr = snr; + + /* notify the caller */ + complete(&pStatsContext->completion); + + /* serialization is complete */ + spin_unlock(&hdd_context_lock); +} + +/** + * 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: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_** on error + */ +QDF_STATUS wlan_hdd_get_rssi(hdd_adapter_t *pAdapter, int8_t *rssi_value) +{ + static struct statsContext context; + hdd_context_t *pHddCtx; + hdd_station_ctx_t *pHddStaCtx; + QDF_STATUS hstatus; + unsigned long rc; + + if (NULL == pAdapter) { + hdd_warn("Invalid context, pAdapter"); + return QDF_STATUS_E_FAULT; + } + if (cds_is_driver_recovering()) { + hdd_warn("Recovery in Progress. State: 0x%x Ignore!!!", + cds_get_driver_state()); + /* return a cached value */ + *rssi_value = pAdapter->rssi; + return QDF_STATUS_SUCCESS; + } + + pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + + if (eConnectionState_Associated != pHddStaCtx->conn_info.connState) { + hdd_info("Not associated!, rssi on disconnect %d", + pAdapter->rssi_on_disconnect); + *rssi_value = pAdapter->rssi_on_disconnect; + return QDF_STATUS_SUCCESS; + } + + if (pHddStaCtx->hdd_ReassocScenario) { + hdd_info("Roaming in progress, return cached RSSI"); + *rssi_value = pAdapter->rssi; + return QDF_STATUS_SUCCESS; + } + + init_completion(&context.completion); + context.pAdapter = pAdapter; + context.magic = RSSI_CONTEXT_MAGIC; + + hstatus = sme_get_rssi(pHddCtx->hHal, hdd_get_rssi_cb, + pHddStaCtx->conn_info.staId[0], + pHddStaCtx->conn_info.bssId, pAdapter->rssi, + &context, pHddCtx->pcds_context); + if (QDF_STATUS_SUCCESS != hstatus) { + hdd_err("Unable to retrieve RSSI"); + /* 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) { + hdd_err("SME timed out while retrieving RSSI"); + /* we'll now returned a cached value below */ + } + } + + /* 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); + + *rssi_value = pAdapter->rssi; + + return QDF_STATUS_SUCCESS; +} + +/** + * 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: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_** on error + */ +QDF_STATUS wlan_hdd_get_snr(hdd_adapter_t *pAdapter, int8_t *snr) +{ + static struct statsContext context; + hdd_context_t *pHddCtx; + hdd_station_ctx_t *pHddStaCtx; + QDF_STATUS hstatus; + unsigned long rc; + int valid; + + ENTER(); + + if (NULL == pAdapter) { + hdd_err("Invalid context, pAdapter"); + return QDF_STATUS_E_FAULT; + } + + pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + + valid = wlan_hdd_validate_context(pHddCtx); + if (0 != valid) + return QDF_STATUS_E_FAULT; + + pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + + init_completion(&context.completion); + context.pAdapter = pAdapter; + context.magic = SNR_CONTEXT_MAGIC; + + hstatus = sme_get_snr(pHddCtx->hHal, hdd_get_snr_cb, + pHddStaCtx->conn_info.staId[0], + pHddStaCtx->conn_info.bssId, &context); + if (QDF_STATUS_SUCCESS != hstatus) { + hdd_err("Unable to retrieve RSSI"); + /* 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) { + hdd_err("SME timed out while retrieving SNR"); + /* we'll now returned a cached value below */ + } + } + + /* 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); + + *snr = pAdapter->snr; + EXIT(); + return QDF_STATUS_SUCCESS; +} + +/** + * hdd_get_link_speed_cb() - Get link speed callback function + * @pLinkSpeed: pointer to the link speed record + * @pContext: pointer to the user context passed to SME + * + * This function is passed as the callback function to + * sme_get_link_speed() by wlan_hdd_get_linkspeed_for_peermac(). By + * agreement a &struct linkspeedContext is passed as @pContext. If + * the context is valid, then the contents of @pLinkSpeed are copied + * into the adapter record referenced by @pContext where they can be + * subsequently retrieved. If the context is invalid, then this + * function does nothing since it is assumed the caller has already + * timed-out and destroyed the context. + * + * Return: None. + */ +static void +hdd_get_link_speed_cb(tSirLinkSpeedInfo *pLinkSpeed, void *pContext) +{ + struct linkspeedContext *pLinkSpeedContext; + hdd_adapter_t *pAdapter; + + if ((NULL == pLinkSpeed) || (NULL == pContext)) { + hdd_err("Bad param, pLinkSpeed [%p] pContext [%p]", + pLinkSpeed, pContext); + return; + } + spin_lock(&hdd_context_lock); + pLinkSpeedContext = pContext; + pAdapter = pLinkSpeedContext->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 + */ + + if ((NULL == pAdapter) || + (LINK_CONTEXT_MAGIC != pLinkSpeedContext->magic)) { + /* the caller presumably timed out so there is nothing + * we can do + */ + spin_unlock(&hdd_context_lock); + hdd_warn("Invalid context, pAdapter [%p] magic [%08x]", + pAdapter, pLinkSpeedContext->magic); + if (ioctl_debug) { + pr_info("%s: Invalid context, pAdapter [%p] magic [%08x]\n", + __func__, pAdapter, pLinkSpeedContext->magic); + } + return; + } + + /* context is valid so caller is still waiting */ + + /* paranoia: invalidate the magic */ + pLinkSpeedContext->magic = 0; + + /* copy over the stats. do so as a struct copy */ + pAdapter->ls_stats = *pLinkSpeed; + + /* notify the caller */ + complete(&pLinkSpeedContext->completion); + + /* serialization is complete */ + spin_unlock(&hdd_context_lock); +} + +/** + * wlan_hdd_get_linkspeed_for_peermac() - Get link speed for a peer + * @pAdapter: adapter upon which the peer is active + * @macAddress: MAC address of the peer + * + * This function will send a query to SME for the linkspeed of the + * given peer, and then wait for the callback to be invoked. + * + * Return: Errno + */ +int wlan_hdd_get_linkspeed_for_peermac(hdd_adapter_t *pAdapter, + struct qdf_mac_addr macAddress) +{ + QDF_STATUS status; + int errno; + unsigned long rc; + static struct linkspeedContext context; + tSirLinkSpeedInfo *linkspeed_req; + + if (NULL == pAdapter) { + hdd_err("pAdapter is NULL"); + return -EINVAL; + } + + linkspeed_req = qdf_mem_malloc(sizeof(*linkspeed_req)); + if (NULL == linkspeed_req) { + hdd_err("Request Buffer Alloc Fail"); + return -ENOMEM; + } + + init_completion(&context.completion); + context.pAdapter = pAdapter; + context.magic = LINK_CONTEXT_MAGIC; + + qdf_copy_macaddr(&linkspeed_req->peer_macaddr, &macAddress); + status = sme_get_link_speed(WLAN_HDD_GET_HAL_CTX(pAdapter), + linkspeed_req, + &context, hdd_get_link_speed_cb); + qdf_mem_free(linkspeed_req); + errno = qdf_status_to_os_return(status); + if (errno) { + hdd_err("Unable to retrieve statistics for link speed"); + } else { + rc = wait_for_completion_timeout + (&context.completion, + msecs_to_jiffies(WLAN_WAIT_TIME_STATS)); + if (!rc) { + hdd_err("SME timed out while retrieving link speed: %d", + errno); + errno = -ETIMEDOUT; + } + } + + /* 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); + + return errno; +} + +/** + * wlan_hdd_get_link_speed() - get link speed + * @pAdapter: pointer to the adapter + * @link_speed: pointer to link speed + * + * This function fetches per bssid link speed. + * + * Return: if associated, link speed shall be returned. + * if not associated, link speed of 0 is returned. + * On error, error number will be returned. + */ +int wlan_hdd_get_link_speed(hdd_adapter_t *sta_adapter, uint32_t *link_speed) +{ + hdd_context_t *hddctx = WLAN_HDD_GET_CTX(sta_adapter); + hdd_station_ctx_t *hdd_stactx = + WLAN_HDD_GET_STATION_CTX_PTR(sta_adapter); + int errno; + + errno = wlan_hdd_validate_context(hddctx); + if (errno) + return errno; + + /* Linkspeed is allowed only for P2P mode */ + if (sta_adapter->device_mode != QDF_P2P_CLIENT_MODE) { + hdd_err("Link Speed is not allowed in Device mode %s(%d)", + hdd_device_mode_to_string(sta_adapter->device_mode), + sta_adapter->device_mode); + return -ENOTSUPP; + } + + if (eConnectionState_Associated != hdd_stactx->conn_info.connState) { + /* we are not connected so we don't have a classAstats */ + *link_speed = 0; + } else { + struct qdf_mac_addr bssid; + + qdf_copy_macaddr(&bssid, &hdd_stactx->conn_info.bssId); + + errno = wlan_hdd_get_linkspeed_for_peermac(sta_adapter, bssid); + if (errno) { + hdd_err("Unable to retrieve SME linkspeed: %d", errno); + return errno; + } + *link_speed = sta_adapter->ls_stats.estLinkSpeed; + /* linkspeed in units of 500 kbps */ + *link_speed = (*link_speed) / 500; + } + + return 0; +} + +/** + * hdd_statistics_cb() - "Get statistics" callback function + * @pStats: statistics payload + * @pContext: opaque context originally passed to SME. HDD always passes + * a pointer to an adapter + * + * Return: None + */ +static void hdd_statistics_cb(void *pStats, void *pContext) +{ + hdd_adapter_t *pAdapter = (hdd_adapter_t *) pContext; + hdd_stats_t *pStatsCache = NULL; + hdd_wext_state_t *pWextState; + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + + tCsrSummaryStatsInfo *pSummaryStats = NULL; + tCsrGlobalClassAStatsInfo *pClassAStats = NULL; + tCsrGlobalClassBStatsInfo *pClassBStats = NULL; + tCsrGlobalClassCStatsInfo *pClassCStats = NULL; + tCsrGlobalClassDStatsInfo *pClassDStats = NULL; + tCsrPerStaStatsInfo *pPerStaStats = NULL; + + if (pAdapter != NULL) + pStatsCache = &pAdapter->hdd_stats; + + pSummaryStats = (tCsrSummaryStatsInfo *) pStats; + pClassAStats = (tCsrGlobalClassAStatsInfo *) (pSummaryStats + 1); + pClassBStats = (tCsrGlobalClassBStatsInfo *) (pClassAStats + 1); + pClassCStats = (tCsrGlobalClassCStatsInfo *) (pClassBStats + 1); + pClassDStats = (tCsrGlobalClassDStatsInfo *) (pClassCStats + 1); + pPerStaStats = (tCsrPerStaStatsInfo *) (pClassDStats + 1); + + if (pStatsCache != NULL) { + /* copy the stats into the cache we keep in the + * adapter instance structure + */ + qdf_mem_copy(&pStatsCache->summary_stat, pSummaryStats, + sizeof(pStatsCache->summary_stat)); + qdf_mem_copy(&pStatsCache->ClassA_stat, pClassAStats, + sizeof(pStatsCache->ClassA_stat)); + qdf_mem_copy(&pStatsCache->ClassB_stat, pClassBStats, + sizeof(pStatsCache->ClassB_stat)); + qdf_mem_copy(&pStatsCache->ClassC_stat, pClassCStats, + sizeof(pStatsCache->ClassC_stat)); + qdf_mem_copy(&pStatsCache->ClassD_stat, pClassDStats, + sizeof(pStatsCache->ClassD_stat)); + qdf_mem_copy(&pStatsCache->perStaStats, pPerStaStats, + sizeof(pStatsCache->perStaStats)); + } + + if (pAdapter) { + pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter); + qdf_status = qdf_event_set(&pWextState->hdd_qdf_event); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + hdd_err("qdf_event_set failed"); + return; + } + } +} + +/** + * hdd_clear_roam_profile_ie() - Clear Roam Profile IEs + * @pAdapter: adapter who's IEs are to be cleared + * + * Return: None + */ +void hdd_clear_roam_profile_ie(hdd_adapter_t *pAdapter) +{ + hdd_wext_state_t *pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter); + + ENTER(); + + /* clear WPA/RSN/WSC IE information in the profile */ + pWextState->roamProfile.nWPAReqIELength = 0; + pWextState->roamProfile.pWPAReqIE = (uint8_t *) NULL; + pWextState->roamProfile.nRSNReqIELength = 0; + pWextState->roamProfile.pRSNReqIE = (uint8_t *) NULL; + +#ifdef FEATURE_WLAN_WAPI + pWextState->roamProfile.nWAPIReqIELength = 0; + pWextState->roamProfile.pWAPIReqIE = (uint8_t *) NULL; +#endif + + pWextState->roamProfile.bWPSAssociation = false; + pWextState->roamProfile.bOSENAssociation = false; + pWextState->roamProfile.pAddIEScan = (uint8_t *) NULL; + pWextState->roamProfile.nAddIEScanLength = 0; + pWextState->roamProfile.pAddIEAssoc = (uint8_t *) NULL; + pWextState->roamProfile.nAddIEAssocLength = 0; + + pWextState->roamProfile.EncryptionType.numEntries = 1; + pWextState->roamProfile.EncryptionType.encryptionType[0] + = eCSR_ENCRYPT_TYPE_NONE; + + pWextState->roamProfile.mcEncryptionType.numEntries = 1; + pWextState->roamProfile.mcEncryptionType.encryptionType[0] + = eCSR_ENCRYPT_TYPE_NONE; + + pWextState->roamProfile.AuthType.numEntries = 1; + pWextState->roamProfile.AuthType.authType[0] = + eCSR_AUTH_TYPE_OPEN_SYSTEM; + + qdf_mem_zero(pWextState->roamProfile.bssid_hint.bytes, + QDF_MAC_ADDR_SIZE); + +#ifdef WLAN_FEATURE_11W + pWextState->roamProfile.MFPEnabled = false; + pWextState->roamProfile.MFPRequired = 0; + pWextState->roamProfile.MFPCapable = 0; +#endif + + pWextState->authKeyMgmt = 0; + + qdf_mem_zero(pWextState->roamProfile.Keys.KeyLength, CSR_MAX_NUM_KEY); + +#ifdef FEATURE_WLAN_WAPI + pAdapter->wapi_info.wapiAuthMode = WAPI_AUTH_MODE_OPEN; + pAdapter->wapi_info.nWapiMode = 0; +#endif + + qdf_zero_macaddr(&pWextState->req_bssId); + EXIT(); +} + +/** + * wlan_hdd_get_vendor_oui_ie_ptr() - Find a vendor OUI + * @oui: The OUI that is being searched for + * @oui_size: The length of @oui + * @ie: The set of IEs within which we're trying to find @oui + * @ie_len: The length of @ie + * + * This function will scan the IEs contained within @ie looking for @oui. + * + * Return: Pointer to @oui embedded within @ie if it is present, NULL + * if @oui is not present within @ie. + */ +uint8_t *wlan_hdd_get_vendor_oui_ie_ptr(uint8_t *oui, uint8_t oui_size, + uint8_t *ie, int ie_len) +{ + int left = ie_len; + uint8_t *ptr = ie; + uint8_t elem_id, elem_len; + uint8_t eid = 0xDD; + + if (NULL == ie || 0 == ie_len) + return NULL; + + while (left >= 2) { + elem_id = ptr[0]; + elem_len = ptr[1]; + left -= 2; + if (elem_len > left) { + hdd_alert("****Invalid IEs eid = %d elem_len=%d left=%d*****", + eid, elem_len, left); + return NULL; + } + if ((elem_id == eid) && (elem_len >= oui_size)) { + if (memcmp(&ptr[2], oui, oui_size) == 0) + return ptr; + } + + left -= elem_len; + ptr += (elem_len + 2); + } + return NULL; +} + +/** + * hdd_get_ldpc() - Get adapter LDPC + * @adapter: adapter being queried + * @value: where to store the value + * + * Return: 0 on success, negative errno on failure + */ +int hdd_get_ldpc(hdd_adapter_t *adapter, int *value) +{ + tHalHandle hal = WLAN_HDD_GET_HAL_CTX(adapter); + int ret; + + ENTER(); + ret = sme_get_ht_config(hal, adapter->sessionId, + WNI_CFG_HT_CAP_INFO_ADVANCE_CODING); + if (ret < 0) { + hdd_alert("Failed to get LDPC value"); + } else { + *value = ret; + ret = 0; + } + return ret; +} + +/** + * hdd_set_ldpc() - Set adapter LDPC + * @adapter: adapter being modified + * @value: new LDPC value + * + * Return: 0 on success, negative errno on failure + */ +int hdd_set_ldpc(hdd_adapter_t *adapter, int value) +{ + tHalHandle hal = WLAN_HDD_GET_HAL_CTX(adapter); + int ret; + + if (!hal) + return -EINVAL; + + hdd_alert("%d", value); + if (value) { + /* make sure HT capabilities allow this */ + QDF_STATUS status; + uint32_t cfg_value; + union { + uint16_t cfg_value16; + tSirMacHTCapabilityInfo ht_cap_info; + } u; + + status = sme_cfg_get_int(hal, WNI_CFG_HT_CAP_INFO, &cfg_value); + if (QDF_STATUS_SUCCESS != status) { + hdd_alert("Failed to get HT capability info"); + return -EIO; + } + u.cfg_value16 = cfg_value & 0xFFFF; + if (!u.ht_cap_info.advCodingCap) { + hdd_alert("LDCP not supported"); + return -EINVAL; + } + } + + ret = sme_update_ht_config(hal, adapter->sessionId, + WNI_CFG_HT_CAP_INFO_ADVANCE_CODING, + value); + if (ret) + hdd_alert("Failed to set LDPC value"); + + return ret; +} + +/** + * hdd_get_tx_stbc() - Get adapter TX STBC + * @adapter: adapter being queried + * @value: where to store the value + * + * Return: 0 on success, negative errno on failure + */ +int hdd_get_tx_stbc(hdd_adapter_t *adapter, int *value) +{ + tHalHandle hal = WLAN_HDD_GET_HAL_CTX(adapter); + int ret; + + ENTER(); + ret = sme_get_ht_config(hal, adapter->sessionId, + WNI_CFG_HT_CAP_INFO_TX_STBC); + if (ret < 0) { + hdd_alert("Failed to get TX STBC value"); + } else { + *value = ret; + ret = 0; + } + + return ret; +} + +/** + * hdd_set_tx_stbc() - Set adapter TX STBC + * @adapter: adapter being modified + * @value: new TX STBC value + * + * Return: 0 on success, negative errno on failure + */ +int hdd_set_tx_stbc(hdd_adapter_t *adapter, int value) +{ + tHalHandle hal = WLAN_HDD_GET_HAL_CTX(adapter); + int ret; + + if (!hal) + return -EINVAL; + + hdd_alert("%d", value); + if (value) { + /* make sure HT capabilities allow this */ + QDF_STATUS status; + uint32_t cfg_value; + union { + uint16_t cfg_value16; + tSirMacHTCapabilityInfo ht_cap_info; + } u; + + status = sme_cfg_get_int(hal, WNI_CFG_HT_CAP_INFO, &cfg_value); + if (QDF_STATUS_SUCCESS != status) { + hdd_alert("Failed to get HT capability info"); + return -EIO; + } + u.cfg_value16 = cfg_value & 0xFFFF; + if (!u.ht_cap_info.txSTBC) { + hdd_alert("TX STBC not supported"); + return -EINVAL; + } + } + ret = sme_update_ht_config(hal, adapter->sessionId, + WNI_CFG_HT_CAP_INFO_TX_STBC, + value); + if (ret) + hdd_alert("Failed to set TX STBC value"); + + return ret; +} + +/** + * hdd_get_rx_stbc() - Get adapter RX STBC + * @adapter: adapter being queried + * @value: where to store the value + * + * Return: 0 on success, negative errno on failure + */ +int hdd_get_rx_stbc(hdd_adapter_t *adapter, int *value) +{ + tHalHandle hal = WLAN_HDD_GET_HAL_CTX(adapter); + int ret; + + ENTER(); + ret = sme_get_ht_config(hal, adapter->sessionId, + WNI_CFG_HT_CAP_INFO_RX_STBC); + if (ret < 0) { + hdd_alert("Failed to get RX STBC value"); + } else { + *value = ret; + ret = 0; + } + + return ret; +} + +/** + * hdd_set_rx_stbc() - Set adapter RX STBC + * @adapter: adapter being modified + * @value: new RX STBC value + * + * Return: 0 on success, negative errno on failure + */ +int hdd_set_rx_stbc(hdd_adapter_t *adapter, int value) +{ + tHalHandle hal = WLAN_HDD_GET_HAL_CTX(adapter); + int ret; + + if (!hal) + return -EINVAL; + + hdd_alert("set rx_stbc : %d", value); + if (value) { + /* make sure HT capabilities allow this */ + QDF_STATUS status; + uint32_t cfg_value; + union { + uint16_t cfg_value16; + tSirMacHTCapabilityInfo ht_cap_info; + } u; + + status = sme_cfg_get_int(hal, WNI_CFG_HT_CAP_INFO, &cfg_value); + if (QDF_STATUS_SUCCESS != status) { + hdd_alert("Failed to get HT capability info"); + return -EIO; + } + u.cfg_value16 = cfg_value & 0xFFFF; + if (!u.ht_cap_info.rxSTBC) { + hdd_alert("RX STBC not supported"); + return -EINVAL; + } + } + ret = sme_update_ht_config(hal, adapter->sessionId, + WNI_CFG_HT_CAP_INFO_RX_STBC, + value); + if (ret) + hdd_alert("Failed to set RX STBC value"); + + return ret; +} + +/** + * __iw_set_commit() - SIOCSIWCOMMIT ioctl handler + * @dev: device upon which the ioctl was received + * @info: ioctl request information + * @wrqu: ioctl request data + * @extra: ioctl extra data + * + * Return: 0 on success, non-zero on error + */ +static int __iw_set_commit(struct net_device *dev, struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + hdd_adapter_t *adapter; + hdd_context_t *hdd_ctx; + int ret; + + ENTER_DEV(dev); + + adapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + /* Do nothing for now */ + return 0; +} + +/** + * iw_set_commit() - SSR wrapper function for __iw_set_commit + * @dev: pointer to net_device + * @info: pointer to iw_request_info + * @wrqu: pointer to iwreq_data + * @extra: extra + * + * Return: 0 on success, error number otherwise + */ +static int iw_set_commit(struct net_device *dev, struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_set_commit(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __iw_get_name() - SIOCGIWNAME ioctl handler + * @dev: device upon which the ioctl was received + * @info: ioctl request information + * @wrqu: ioctl request data + * @extra: ioctl extra data + * + * Return: 0 on success, non-zero on error + */ +static int __iw_get_name(struct net_device *dev, + struct iw_request_info *info, char *wrqu, char *extra) +{ + hdd_adapter_t *adapter; + hdd_context_t *hdd_ctx; + int ret; + + ENTER_DEV(dev); + + adapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + strlcpy(wrqu, "Qcom:802.11n", IFNAMSIZ); + EXIT(); + return 0; +} + +/** + * __iw_get_name() - SSR wrapper for __iw_get_name + * @dev: pointer to net_device + * @info: pointer to iw_request_info + * @wrqu: pointer to iwreq_data + * @extra: extra + * + * Return: 0 on success, error number otherwise + */ +static int iw_get_name(struct net_device *dev, + struct iw_request_info *info, + char *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_get_name(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __iw_set_mode() - ioctl handler + * @dev: device upon which the ioctl was received + * @info: ioctl request information + * @wrqu: ioctl request data + * @extra: ioctl extra data + * + * Return: 0 on success, non-zero on error + */ +static int __iw_set_mode(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + hdd_wext_state_t *pWextState; + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *hdd_ctx; + tCsrRoamProfile *pRoamProfile; + eCsrRoamBssType LastBSSType; + struct hdd_config *pConfig; + struct wireless_dev *wdev; + int ret; + + ENTER_DEV(dev); + + hdd_ctx = WLAN_HDD_GET_CTX(pAdapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter); + wdev = dev->ieee80211_ptr; + pRoamProfile = &pWextState->roamProfile; + LastBSSType = pRoamProfile->BSSType; + + hdd_notice("Old Bss type = %d", LastBSSType); + + switch (wrqu->mode) { + case IW_MODE_ADHOC: + hdd_notice("Setting AP Mode as IW_MODE_ADHOC"); + pRoamProfile->BSSType = eCSR_BSS_TYPE_START_IBSS; + /* Set the phymode correctly for IBSS. */ + pConfig = (WLAN_HDD_GET_CTX(pAdapter))->config; + pWextState->roamProfile.phyMode = + hdd_cfg_xlate_to_csr_phy_mode(pConfig->dot11Mode); + pAdapter->device_mode = QDF_IBSS_MODE; + wdev->iftype = NL80211_IFTYPE_ADHOC; + break; + case IW_MODE_INFRA: + hdd_notice("Setting AP Mode as IW_MODE_INFRA"); + pRoamProfile->BSSType = eCSR_BSS_TYPE_INFRASTRUCTURE; + wdev->iftype = NL80211_IFTYPE_STATION; + break; + case IW_MODE_AUTO: + hdd_notice("Setting AP Mode as IW_MODE_AUTO"); + pRoamProfile->BSSType = eCSR_BSS_TYPE_ANY; + break; + default: + hdd_err("Unknown AP Mode value %d", wrqu->mode); + return -EOPNOTSUPP; + } + + if (LastBSSType != pRoamProfile->BSSType) { + /* the BSS mode changed. We need to issue disconnect + * if connected or in IBSS disconnect state + */ + if (hdd_conn_is_connected + (WLAN_HDD_GET_STATION_CTX_PTR(pAdapter)) + || (eCSR_BSS_TYPE_START_IBSS == LastBSSType)) { + QDF_STATUS qdf_status; + /* need to issue a disconnect to CSR. */ + INIT_COMPLETION(pAdapter->disconnect_comp_var); + qdf_status = + sme_roam_disconnect(WLAN_HDD_GET_HAL_CTX(pAdapter), + pAdapter->sessionId, + eCSR_DISCONNECT_REASON_IBSS_LEAVE); + if (QDF_STATUS_SUCCESS == qdf_status) { + unsigned long rc; + rc = wait_for_completion_timeout(&pAdapter-> + disconnect_comp_var, + msecs_to_jiffies + (WLAN_WAIT_TIME_DISCONNECT)); + if (!rc) + hdd_err("failed wait on disconnect_comp_var"); + } + } + } + + EXIT(); + return 0; +} + +/** + * iw_set_mode() - SSR wrapper for __iw_set_mode() + * @dev: pointer to net_device + * @info: pointer to iw_request_info + * @wrqu: pointer to iwreq_data + * @extra: pointer to extra ioctl payload + * + * Return: 0 on success, error number otherwise + */ +static int iw_set_mode(struct net_device *dev, struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_set_mode(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __iw_get_mode() - SIOCGIWMODE ioctl handler + * @dev: device upon which the ioctl was received + * @info: ioctl request information + * @wrqu: ioctl request data + * @extra: ioctl extra data + * + * Return: 0 on success, non-zero on error + */ +static int +__iw_get_mode(struct net_device *dev, struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + hdd_wext_state_t *pWextState; + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *hdd_ctx; + int ret; + + ENTER_DEV(dev); + + hdd_ctx = WLAN_HDD_GET_CTX(pAdapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter); + + switch (pWextState->roamProfile.BSSType) { + case eCSR_BSS_TYPE_INFRASTRUCTURE: + hdd_notice("returns IW_MODE_INFRA"); + wrqu->mode = IW_MODE_INFRA; + break; + case eCSR_BSS_TYPE_IBSS: + case eCSR_BSS_TYPE_START_IBSS: + hdd_notice("returns IW_MODE_ADHOC"); + wrqu->mode = IW_MODE_ADHOC; + break; + case eCSR_BSS_TYPE_ANY: + default: + hdd_notice("returns IW_MODE_AUTO"); + wrqu->mode = IW_MODE_AUTO; + break; + } + + EXIT(); + return 0; +} + +/** + * iw_get_mode() - SSR wrapper for __iw_get_mode() + * @dev: pointer to net_device + * @info: pointer to iw_request_info + * @wrqu: pointer to iwreq_data + * @extra: pointer to extra ioctl payload + * + * Return: 0 on success, error number otherwise + */ +static int iw_get_mode(struct net_device *dev, struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_get_mode(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __iw_set_freq() - SIOCSIWFREQ ioctl handler + * @dev: device upon which the ioctl was received + * @info: ioctl request information + * @wrqu: ioctl request data + * @extra: ioctl extra data + * + * Return: 0 on success, non-zero on error + */ +static int __iw_set_freq(struct net_device *dev, struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + uint32_t numChans = 0; + uint8_t validChan[WNI_CFG_VALID_CHANNEL_LIST_LEN]; + uint32_t indx = 0; + int ret; + hdd_wext_state_t *pWextState; + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *hdd_ctx; + tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter); + hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + tCsrRoamProfile *pRoamProfile; + + ENTER_DEV(dev); + + hdd_ctx = WLAN_HDD_GET_CTX(pAdapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter); + + pRoamProfile = &pWextState->roamProfile; + + hdd_notice("setCHANNEL ioctl"); + + /* Link is up then return cant set channel */ + if (eConnectionState_IbssConnected == pHddStaCtx->conn_info.connState || + eConnectionState_Associated == pHddStaCtx->conn_info.connState) { + hdd_err("IBSS Associated"); + return -EOPNOTSUPP; + } + + /* Settings by Frequency as input */ + if ((wrqu->freq.e == 1) && (wrqu->freq.m >= (uint32_t) 2.412e8) && + (wrqu->freq.m <= (uint32_t) 5.825e8)) { + uint32_t freq = wrqu->freq.m / 100000; + + while ((indx < FREQ_CHAN_MAP_TABLE_SIZE) + && (freq != freq_chan_map[indx].freq)) + indx++; + if (indx >= FREQ_CHAN_MAP_TABLE_SIZE) { + return -EINVAL; + } + wrqu->freq.e = 0; + wrqu->freq.m = freq_chan_map[indx].chan; + + } + + if (wrqu->freq.e == 0) { + if ((wrqu->freq.m < WNI_CFG_CURRENT_CHANNEL_STAMIN) || + (wrqu->freq.m > WNI_CFG_CURRENT_CHANNEL_STAMAX)) { + hdd_notice("Channel %d is outside valid range from %d to %d", + wrqu->freq.m, + WNI_CFG_CURRENT_CHANNEL_STAMIN, + WNI_CFG_CURRENT_CHANNEL_STAMAX); + return -EINVAL; + } + + numChans = WNI_CFG_VALID_CHANNEL_LIST_LEN; + + if (sme_cfg_get_str(hHal, WNI_CFG_VALID_CHANNEL_LIST, + validChan, &numChans) != + QDF_STATUS_SUCCESS) { + hdd_warn("failed to get ini parameter, WNI_CFG_VALID_CHANNEL_LIST"); + return -EIO; + } + + for (indx = 0; indx < numChans; indx++) { + if (wrqu->freq.m == validChan[indx]) { + break; + } + } + } else { + + return -EINVAL; + } + + if (indx >= numChans) { + return -EINVAL; + } + + /* Set the Operational Channel */ + numChans = pRoamProfile->ChannelInfo.numOfChannels = 1; + pHddStaCtx->conn_info.operationChannel = wrqu->freq.m; + pRoamProfile->ChannelInfo.ChannelList = + &pHddStaCtx->conn_info.operationChannel; + + hdd_notice("pRoamProfile->operationChannel = %d", wrqu->freq.m); + + EXIT(); + + return ret; +} + +/** + * iw_set_freq() - SSR wrapper for __iw_set_freq() + * @dev: pointer to net_device + * @info: pointer to iw_request_info + * @wrqu: pointer to iwreq_data + * @extra: pointer to extra ioctl payload + * + * Return: 0 on success, error number otherwise + */ +static int iw_set_freq(struct net_device *dev, struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_set_freq(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __iw_get_freq() - SIOCGIWFREQ ioctl handler + * @dev: device upon which the ioctl was received + * @info: ioctl request information + * @wrqu: ioctl request data + * @extra: ioctl extra data + * + * Return: 0 on success, non-zero on error + */ +static int __iw_get_freq(struct net_device *dev, struct iw_request_info *info, + struct iw_freq *fwrq, char *extra) +{ + uint32_t status = false, channel = 0, freq = 0; + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + tHalHandle hHal; + hdd_wext_state_t *pWextState; + tCsrRoamProfile *pRoamProfile; + hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + hdd_context_t *hdd_ctx; + int ret; + + ENTER_DEV(dev); + + hdd_ctx = WLAN_HDD_GET_CTX(pAdapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter); + hHal = WLAN_HDD_GET_HAL_CTX(pAdapter); + + pRoamProfile = &pWextState->roamProfile; + + if (pHddStaCtx->conn_info.connState == eConnectionState_Associated) { + if (sme_get_operation_channel(hHal, &channel, pAdapter->sessionId) + != QDF_STATUS_SUCCESS) { + hdd_err("failed to get operating channel %u", + pAdapter->sessionId); + return -EIO; + } else { + status = hdd_wlan_get_freq(channel, &freq); + if (true == status) { + /* Set Exponent parameter as 6 (MHZ) + * in struct iw_freq iwlist & iwconfig + * command shows frequency into proper + * format (2.412 GHz instead of 246.2 + * MHz) + */ + fwrq->m = freq; + fwrq->e = MHZ; + } + } + } else { + /* Set Exponent parameter as 6 (MHZ) in struct iw_freq + * iwlist & iwconfig command shows frequency into proper + * format (2.412 GHz instead of 246.2 MHz) + */ + fwrq->m = 0; + fwrq->e = MHZ; + } + return 0; +} + +/** + * iw_get_freq() - SSR wrapper for __iw_get_freq() + * @dev: pointer to net_device + * @info: pointer to iw_request_info + * @fwrq: pointer to frequency data + * @extra: pointer to extra ioctl payload + * + * Return: 0 on success, error number otherwise + */ +static int iw_get_freq(struct net_device *dev, struct iw_request_info *info, + struct iw_freq *fwrq, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_get_freq(dev, info, fwrq, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __iw_get_tx_power() - SIOCGIWTXPOW ioctl handler + * @dev: device upon which the ioctl was received + * @info: ioctl request information + * @wrqu: ioctl request data + * @extra: ioctl extra data + * + * Return: 0 on success, non-zero on error + */ +static int __iw_get_tx_power(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(pAdapter); + hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + int ret; + + ENTER_DEV(dev); + + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + if (eConnectionState_Associated != pHddStaCtx->conn_info.connState) { + wrqu->txpower.value = 0; + return 0; + } + wlan_hdd_get_class_astats(pAdapter); + wrqu->txpower.value = pAdapter->hdd_stats.ClassA_stat.max_pwr; + + return 0; +} + +/** + * iw_get_tx_power() - SSR wrapper for __iw_get_tx_power() + * @dev: pointer to net_device + * @info: pointer to iw_request_info + * @wrqu: pointer to iwreq_data + * @extra: pointer to extra ioctl payload + * + * Return: 0 on success, error number otherwise + */ +static int iw_get_tx_power(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_get_tx_power(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __iw_set_tx_power() - SIOCSIWTXPOW ioctl handler + * @dev: device upon which the ioctl was received + * @info: ioctl request information + * @wrqu: ioctl request data + * @extra: ioctl extra data + * + * Return: 0 on success, non-zero on error + */ +static int __iw_set_tx_power(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter); + hdd_context_t *hdd_ctx; + int ret; + + ENTER_DEV(dev); + + hdd_ctx = WLAN_HDD_GET_CTX(pAdapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + if (sme_cfg_set_int(hHal, WNI_CFG_CURRENT_TX_POWER_LEVEL, + wrqu->txpower.value) != QDF_STATUS_SUCCESS) { + hdd_err("failed to set ini parameter, WNI_CFG_CURRENT_TX_POWER_LEVEL"); + return -EIO; + } + + EXIT(); + + return 0; +} + +/** + * iw_set_tx_power() - SSR wrapper for __iw_set_tx_power() + * @dev: pointer to net_device + * @info: pointer to iw_request_info + * @wrqu: pointer to iwreq_data + * @extra: pointer to extra ioctl payload + * + * Return: 0 on success, error number otherwise + */ +static int iw_set_tx_power(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_set_tx_power(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __iw_get_bitrate() - SIOCGIWRATE ioctl handler + * @dev: device upon which the ioctl was received + * @info: ioctl request information + * @wrqu: ioctl request data + * @extra: ioctl extra data + * + * Return: 0 on success, non-zero on error + */ +static int __iw_get_bitrate(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + QDF_STATUS status = QDF_STATUS_SUCCESS; + hdd_wext_state_t *pWextState; + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + hdd_context_t *hdd_ctx; + int ret; + + ENTER_DEV(dev); + + hdd_ctx = WLAN_HDD_GET_CTX(pAdapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + if (cds_is_driver_recovering()) { + hdd_alert("Recovery in Progress. State: 0x%x Ignore!!!", + cds_get_driver_state()); + return status; + } + + if (eConnectionState_Associated != pHddStaCtx->conn_info.connState) { + wrqu->bitrate.value = 0; + } else { + status = + sme_get_statistics(WLAN_HDD_GET_HAL_CTX(pAdapter), + eCSR_HDD, + SME_SUMMARY_STATS | + SME_GLOBAL_CLASSA_STATS | + SME_GLOBAL_CLASSB_STATS | + SME_GLOBAL_CLASSC_STATS | + SME_GLOBAL_CLASSD_STATS | + SME_PER_STA_STATS, + hdd_statistics_cb, 0, + false, + pHddStaCtx->conn_info.staId[0], + pAdapter, pAdapter->sessionId); + + if (QDF_STATUS_SUCCESS != status) { + hdd_err("Unable to retrieve statistics"); + return status; + } + + pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter); + + qdf_status = + qdf_wait_single_event(&pWextState->hdd_qdf_event, + WLAN_WAIT_TIME_STATS); + + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + hdd_err("SME timeout while retrieving statistics"); + return QDF_STATUS_E_FAILURE; + } + + wrqu->bitrate.value = + pAdapter->hdd_stats.ClassA_stat.tx_rate * 500 * 1000; + } + + EXIT(); + + return qdf_status; +} + +/** + * iw_get_bitrate() - SSR wrapper for __iw_get_bitrate() + * @dev: pointer to net_device + * @info: pointer to iw_request_info + * @wrqu: pointer to iwreq_data + * @extra: pointer to extra ioctl payload + * + * Return: 0 on success, error number otherwise + */ +static int iw_get_bitrate(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_get_bitrate(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __iw_set_bitrate() - SIOCSIWRATE ioctl handler + * @dev: device upon which the ioctl was received + * @info: ioctl request information + * @wrqu: ioctl request data + * @extra: ioctl extra data + * + * Return: 0 on success, non-zero on error + */ +static int __iw_set_bitrate(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_wext_state_t *pWextState; + hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + uint8_t supp_rates[WNI_CFG_SUPPORTED_RATES_11A_LEN]; + uint32_t a_len = WNI_CFG_SUPPORTED_RATES_11A_LEN; + uint32_t b_len = WNI_CFG_SUPPORTED_RATES_11B_LEN; + uint32_t i, rate; + uint32_t valid_rate = false, active_phy_mode = 0; + hdd_context_t *hdd_ctx; + int ret; + + ENTER_DEV(dev); + + hdd_ctx = WLAN_HDD_GET_CTX(pAdapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter); + + if (eConnectionState_Associated != pHddStaCtx->conn_info.connState) { + return -ENXIO; + } + + rate = wrqu->bitrate.value; + + if (rate == -1) { + rate = WNI_CFG_FIXED_RATE_AUTO; + valid_rate = true; + } else if (sme_cfg_get_int(WLAN_HDD_GET_HAL_CTX(pAdapter), + WNI_CFG_DOT11_MODE, + &active_phy_mode) == QDF_STATUS_SUCCESS) { + if (active_phy_mode == WNI_CFG_DOT11_MODE_11A + || active_phy_mode == WNI_CFG_DOT11_MODE_11G + || active_phy_mode == WNI_CFG_DOT11_MODE_11B) { + if ((sme_cfg_get_str(WLAN_HDD_GET_HAL_CTX(pAdapter), + WNI_CFG_SUPPORTED_RATES_11A, supp_rates, + &a_len) == QDF_STATUS_SUCCESS) + && + (sme_cfg_get_str(WLAN_HDD_GET_HAL_CTX(pAdapter), + WNI_CFG_SUPPORTED_RATES_11B, supp_rates, + &b_len) == QDF_STATUS_SUCCESS)) { + for (i = 0; i < (b_len + a_len); ++i) { + /* supported rates returned is double + * the actual rate so we divide it by 2 + */ + if ((supp_rates[i] & 0x7F) / 2 == + rate) { + valid_rate = true; + rate = i + + WNI_CFG_FIXED_RATE_1MBPS; + break; + } + } + } + } + } + if (valid_rate != true) { + return -EINVAL; + } + if (sme_cfg_set_int(WLAN_HDD_GET_HAL_CTX(pAdapter), + WNI_CFG_FIXED_RATE, rate) != QDF_STATUS_SUCCESS) { + hdd_err("failed to set ini parameter, WNI_CFG_FIXED_RATE"); + return -EIO; + } + return 0; +} + +/** + * iw_set_bitrate() - SSR wrapper for __iw_set_bitrate() + * @dev: pointer to net_device + * @info: pointer to iw_request_info + * @wrqu: pointer to iwreq_data + * @extra: pointer to extra ioctl payload + * + * Return: 0 on success, error number otherwise + */ +static int iw_set_bitrate(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_set_bitrate(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __iw_set_genie() - SIOCSIWGENIE ioctl handler + * @dev: device upon which the ioctl was received + * @info: ioctl request information + * @wrqu: ioctl request data + * @extra: ioctl extra data + * + * Return: 0 on success, non-zero on error + */ +static int __iw_set_genie(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_wext_state_t *pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter); + uint8_t *genie = NULL; + uint8_t *base_genie = NULL; + uint16_t remLen; + hdd_context_t *hdd_ctx; + int ret; + + ENTER_DEV(dev); + + hdd_ctx = WLAN_HDD_GET_CTX(pAdapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + if (!wrqu->data.length) { + hdd_clear_roam_profile_ie(pAdapter); + EXIT(); + return 0; + } + + base_genie = mem_alloc_copy_from_user_helper(wrqu->data.pointer, + wrqu->data.length); + if (NULL == base_genie) { + hdd_err("mem_alloc_copy_from_user_helper fail"); + return -ENOMEM; + } + + genie = base_genie; + + remLen = wrqu->data.length; + + hdd_notice("iw_set_genie ioctl IE[0x%X], LEN[%d]", genie[0], + genie[1]); + + /* clear any previous genIE before this call */ + memset(&pWextState->genIE, 0, sizeof(pWextState->genIE)); + + while (remLen >= 2) { + uint16_t eLen = 0; + uint8_t elementId; + elementId = *genie++; + eLen = *genie++; + remLen -= 2; + + hdd_notice("IE[0x%X], LEN[%d]", elementId, eLen); + + if (remLen < eLen) { + hdd_err("Remaining len: %u less than ie len: %u", + remLen, eLen); + ret = -EINVAL; + goto exit; + } + + switch (elementId) { + case IE_EID_VENDOR: + if ((IE_LEN_SIZE + IE_EID_SIZE + IE_VENDOR_OUI_SIZE) > eLen) { /* should have at least OUI */ + ret = -EINVAL; + goto exit; + } + + if (0 == memcmp(&genie[0], "\x00\x50\xf2\x04", 4)) { + uint16_t curGenIELen = pWextState->genIE.length; + hdd_notice("Set WPS OUI(%02x %02x %02x %02x) IE(len %d)", + genie[0], genie[1], genie[2], + genie[3], eLen + 2); + + if (SIR_MAC_MAX_IE_LENGTH < + (pWextState->genIE.length + eLen)) { + hdd_alert("Cannot accommodate genIE. Need bigger buffer space"); + QDF_ASSERT(0); + ret = -ENOMEM; + goto exit; + } + /* save to Additional IE ; it should be accumulated to handle WPS IE + other IE */ + memcpy(pWextState->genIE.addIEdata + + curGenIELen, genie - 2, eLen + 2); + pWextState->genIE.length += eLen + 2; + } else if (0 == memcmp(&genie[0], "\x00\x50\xf2", 3)) { + hdd_notice("Set WPA IE (len %d)", eLen + 2); + if ((eLen + 2) > (sizeof(pWextState->WPARSNIE))) { + hdd_warn("Cannot accommodate genIE, Need bigger buffer space"); + ret = -EINVAL; + QDF_ASSERT(0); + goto exit; + } + memset(pWextState->WPARSNIE, 0, + MAX_WPA_RSN_IE_LEN); + memcpy(pWextState->WPARSNIE, genie - 2, + (eLen + 2)); + pWextState->roamProfile.pWPAReqIE = + pWextState->WPARSNIE; + pWextState->roamProfile.nWPAReqIELength = + eLen + 2; + } else { /* any vendorId except WPA IE should be accumulated to genIE */ + + uint16_t curGenIELen = pWextState->genIE.length; + hdd_notice("Set OUI(%02x %02x %02x %02x) IE(len %d)", + genie[0], genie[1], genie[2], + genie[3], eLen + 2); + + if (SIR_MAC_MAX_IE_LENGTH < + (pWextState->genIE.length + eLen)) { + hdd_alert("Cannot accommodate genIE. Need bigger buffer space"); + QDF_ASSERT(0); + ret = -ENOMEM; + goto exit; + } + /* save to Additional IE ; it should be accumulated to handle WPS IE + other IE */ + memcpy(pWextState->genIE.addIEdata + + curGenIELen, genie - 2, eLen + 2); + pWextState->genIE.length += eLen + 2; + } + break; + case DOT11F_EID_RSN: + hdd_notice("Set RSN IE (len %d)", eLen + 2); + if ((eLen + 2) > (sizeof(pWextState->WPARSNIE))) { + hdd_warn("Cannot accommodate genIE, Need bigger buffer space"); + ret = -EINVAL; + QDF_ASSERT(0); + goto exit; + } + memset(pWextState->WPARSNIE, 0, MAX_WPA_RSN_IE_LEN); + memcpy(pWextState->WPARSNIE, genie - 2, (eLen + 2)); + pWextState->roamProfile.pRSNReqIE = + pWextState->WPARSNIE; + pWextState->roamProfile.nRSNReqIELength = eLen + 2; + break; + + default: + hdd_err("Set UNKNOWN IE %X", elementId); + goto exit; + } + remLen -= eLen; + + /* Move genie only if next element is present */ + if (remLen >= 2) + genie += eLen; + } +exit: + EXIT(); + qdf_mem_free(base_genie); + return ret; +} + +/** + * iw_set_genie() - SSR wrapper for __iw_set_genie() + * @dev: pointer to net_device + * @info: pointer to iw_request_info + * @wrqu: pointer to iwreq_data + * @extra: pointer to extra ioctl payload + * + * Return: 0 on success, error number otherwise + */ +static int iw_set_genie(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_set_genie(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __iw_get_genie() - SIOCGIWGENIE ioctl handler + * @dev: device upon which the ioctl was received + * @info: ioctl request information + * @wrqu: ioctl request data + * @extra: ioctl extra data + * + * Return: 0 on success, non-zero on error + */ +static int __iw_get_genie(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + hdd_wext_state_t *pWextState; + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + QDF_STATUS status; + uint32_t length = DOT11F_IE_RSN_MAX_LEN; + uint8_t genIeBytes[DOT11F_IE_RSN_MAX_LEN]; + hdd_context_t *hdd_ctx; + int ret; + + ENTER_DEV(dev); + + hdd_ctx = WLAN_HDD_GET_CTX(pAdapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + hdd_notice("getGEN_IE ioctl"); + + pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter); + + if (pHddStaCtx->conn_info.connState == eConnectionState_NotConnected) { + return -ENXIO; + } + + /* Return something ONLY if we are associated with an RSN or + * WPA network + */ + if (!hdd_is_auth_type_rsn(pWextState->roamProfile.negotiatedAuthType)) { + return -ENXIO; + } + + /* Actually retrieve the RSN IE from CSR. (We previously sent + * it down in the CSR Roam Profile.) + */ + status = csr_roam_get_wpa_rsn_req_ie(WLAN_HDD_GET_HAL_CTX(pAdapter), + pAdapter->sessionId, + &length, genIeBytes); + if (QDF_STATUS_SUCCESS != status) { + hdd_notice("failed to get WPA-RSN IE data"); + return -EFAULT; + } + wrqu->data.length = length; + if (length > DOT11F_IE_RSN_MAX_LEN) { + hdd_notice("invalid buffer length length:%d", length); + return -E2BIG; + } + qdf_mem_copy(extra, (void *)genIeBytes, length); + + hdd_notice("RSN IE of %d bytes returned", + wrqu->data.length); + + EXIT(); + + return 0; +} + +/** + * iw_get_genie() - SSR wrapper for __iw_get_genie() + * @dev: pointer to net_device + * @info: pointer to iw_request_info + * @wrqu: pointer to iwreq_data + * @extra: pointer to extra ioctl payload + * + * Return: 0 on success, error number otherwise + */ +static int iw_get_genie(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_get_genie(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __iw_get_encode() - SIOCGIWENCODE ioctl handler + * @dev: device upon which the ioctl was received + * @info: ioctl request information + * @wrqu: ioctl request data + * @extra: ioctl extra data + * + * Return: 0 on success, non-zero on error + */ +static int __iw_get_encode(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_wext_state_t *pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter); + tCsrRoamProfile *pRoamProfile = &(pWextState->roamProfile); + int keyId; + eCsrAuthType authType = eCSR_AUTH_TYPE_NONE; + int i; + hdd_context_t *hdd_ctx; + int ret; + + ENTER_DEV(dev); + + hdd_ctx = WLAN_HDD_GET_CTX(pAdapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + keyId = pRoamProfile->Keys.defaultIndex; + + if (keyId < 0 || keyId >= MAX_WEP_KEYS) { + hdd_notice("Invalid keyId : %d", keyId); + return -EINVAL; + } + + if (pRoamProfile->Keys.KeyLength[keyId] > 0) { + dwrq->flags |= IW_ENCODE_ENABLED; + dwrq->length = pRoamProfile->Keys.KeyLength[keyId]; + qdf_mem_copy(extra, &(pRoamProfile->Keys.KeyMaterial[keyId][0]), + pRoamProfile->Keys.KeyLength[keyId]); + + dwrq->flags |= (keyId + 1); + + } else { + dwrq->flags |= IW_ENCODE_DISABLED; + } + + for (i = 0; i < MAX_WEP_KEYS; i++) { + if (pRoamProfile->Keys.KeyLength[i] == 0) { + continue; + } else { + break; + } + } + + if (MAX_WEP_KEYS == i) { + dwrq->flags |= IW_ENCODE_NOKEY; + } + + authType = + ((hdd_station_ctx_t *) WLAN_HDD_GET_STATION_CTX_PTR(pAdapter))-> + conn_info.authType; + + if (eCSR_AUTH_TYPE_OPEN_SYSTEM == authType) { + dwrq->flags |= IW_ENCODE_OPEN; + } else { + dwrq->flags |= IW_ENCODE_RESTRICTED; + } + EXIT(); + return 0; +} + +/** + * iw_get_encode() - SSR wrapper for __iw_get_encode() + * @dev: pointer to net_device + * @info: pointer to iw_request_info + * @dwrq: pointer to encoding information + * @extra: pointer to extra ioctl payload + * + * Return: 0 on success, error number otherwise + */ +static int iw_get_encode(struct net_device *dev, struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_get_encode(dev, info, dwrq, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __iw_get_rts_threshold() - SIOCGIWRTS ioctl handler + * @dev: device upon which the ioctl was received + * @info: ioctl request information + * @wrqu: ioctl request data + * @extra: ioctl extra data + * + * Return: 0 on success, non-zero on error + */ +static int __iw_get_rts_threshold(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + uint32_t status = 0; + + ENTER_DEV(dev); + + status = hdd_wlan_get_rts_threshold(pAdapter, wrqu); + + return status; +} + +/** + * __iw_set_rts_threshold() - SIOCSIWRTS ioctl handler + * @dev: device upon which the ioctl was received + * @info: ioctl request information + * @wrqu: ioctl request data + * @extra: ioctl extra data + * + * Return: 0 on success, non-zero on error + */ +static int __iw_set_rts_threshold(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter); + hdd_context_t *hdd_ctx; + int ret; + + ENTER_DEV(dev); + + hdd_ctx = WLAN_HDD_GET_CTX(pAdapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + if (wrqu->rts.value < WNI_CFG_RTS_THRESHOLD_STAMIN + || wrqu->rts.value > WNI_CFG_RTS_THRESHOLD_STAMAX) { + return -EINVAL; + } + + if (sme_cfg_set_int(hHal, WNI_CFG_RTS_THRESHOLD, wrqu->rts.value) != + QDF_STATUS_SUCCESS) { + hdd_err("failed to set ini parameter, WNI_CFG_RTS_THRESHOLD"); + return -EIO; + } + + EXIT(); + + return 0; +} + +/** + * iw_get_rts_threshold() - SSR wrapper for __iw_get_rts_threshold() + * @dev: pointer to net_device + * @info: pointer to iw_request_info + * @wrqu: pointer to iwreq_data + * @extra: pointer to extra ioctl payload + * + * Return: 0 on success, error number otherwise + */ +static int iw_get_rts_threshold(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_get_rts_threshold(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * iw_set_rts_threshold() - SSR wrapper for __iw_set_rts_threshold() + * @dev: pointer to net_device + * @info: pointer to iw_request_info + * @wrqu: pointer to iwreq_data + * @extra: pointer to extra ioctl payload + * + * Return: 0 on success, error number otherwise + */ +static int iw_set_rts_threshold(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_set_rts_threshold(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __iw_get_frag_threshold() - SIOCGIWFRAG ioctl handler + * @dev: device upon which the ioctl was received + * @info: ioctl request information + * @wrqu: ioctl request data + * @extra: ioctl extra data + * + * Return: 0 on success, non-zero on error + */ +static int __iw_get_frag_threshold(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + uint32_t status = 0; + + ENTER_DEV(dev); + + status = hdd_wlan_get_frag_threshold(pAdapter, wrqu); + + return status; +} + +/** + * iw_get_frag_threshold() - SSR wrapper for __iw_get_frag_threshold() + * @dev: pointer to net_device + * @info: pointer to iw_request_info + * @wrqu: pointer to iwreq_data + * @extra: pointer to extra ioctl payload + * + * Return: 0 on success, error number otherwise + */ +static int iw_get_frag_threshold(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_get_frag_threshold(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __iw_set_frag_threshold() - SIOCSIWFRAG ioctl handler + * @dev: device upon which the ioctl was received + * @info: ioctl request information + * @wrqu: ioctl request data + * @extra: ioctl extra data + * + * Return: 0 on success, non-zero on error + */ +static int __iw_set_frag_threshold(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter); + hdd_context_t *hdd_ctx; + int ret; + + ENTER_DEV(dev); + + hdd_ctx = WLAN_HDD_GET_CTX(pAdapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + if (wrqu->frag.value < WNI_CFG_FRAGMENTATION_THRESHOLD_STAMIN + || wrqu->frag.value > WNI_CFG_FRAGMENTATION_THRESHOLD_STAMAX) { + return -EINVAL; + } + + if (sme_cfg_set_int + (hHal, WNI_CFG_FRAGMENTATION_THRESHOLD, wrqu->frag.value) + != QDF_STATUS_SUCCESS) { + hdd_err("failed to set ini parameter, WNI_CFG_FRAGMENTATION_THRESHOLD"); + return -EIO; + } + + EXIT(); + + return 0; +} + +/** + * iw_set_frag_threshold() - SSR wrapper for __iw_set_frag_threshold() + * @dev: pointer to net_device + * @info: pointer to iw_request_info + * @wrqu: pointer to iwreq_data + * @extra: pointer to extra ioctl payload + * + * Return: 0 on success, error number otherwise + */ +static int iw_set_frag_threshold(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_set_frag_threshold(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __iw_get_power_mode() - SIOCGIWPOWER ioctl handler + * @dev: device upon which the ioctl was received + * @info: ioctl request information + * @wrqu: ioctl request data + * @extra: ioctl extra data + * + * Return: 0 on success, non-zero on error + */ +static int __iw_get_power_mode(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + hdd_adapter_t *adapter; + hdd_context_t *hdd_ctx; + int ret; + + ENTER_DEV(dev); + + adapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + return -EOPNOTSUPP; +} + +/** + * iw_get_power_mode() - SSR wrapper function for __iw_get_power_mode + * @dev: pointer to net_device + * @info: pointer to iw_request_info + * @wrqu: pointer to iwreq_data + * @extra: extra + * + * Return: 0 on success, error number otherwise + */ +static int iw_get_power_mode(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_get_power_mode(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __iw_set_power_mode() - SIOCSIWPOWER ioctl handler + * @dev: device upon which the ioctl was received + * @info: ioctl request information + * @wrqu: ioctl request data + * @extra: ioctl extra data + * + * Return: 0 on success, non-zero on error + */ +static int __iw_set_power_mode(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + hdd_adapter_t *adapter; + hdd_context_t *hdd_ctx; + int ret; + + ENTER_DEV(dev); + + adapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + return -EOPNOTSUPP; +} + +/** + * iw_set_power_mode() - SSR wrapper function for __iw_set_power_mode + * @dev: pointer to net_device + * @info: pointer to iw_request_info + * @wrqu: pointer to iwreq_data + * @extra: extra + * + * Return: 0 on success, error number otherwise + */ +static int iw_set_power_mode(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_set_power_mode(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __iw_get_range() - SIOCGIWRANGE ioctl handler + * @dev: device upon which the ioctl was received + * @info: ioctl request information + * @wrqu: ioctl request data + * @extra: ioctl extra data + * + * Return: 0 on success, non-zero on error + */ +static int __iw_get_range(struct net_device *dev, struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter); + struct iw_range *range = (struct iw_range *)extra; + + uint8_t channels[WNI_CFG_VALID_CHANNEL_LIST_LEN]; + + uint32_t num_channels = sizeof(channels); + uint8_t supp_rates[WNI_CFG_SUPPORTED_RATES_11A_LEN]; + uint32_t a_len; + uint32_t b_len; + uint32_t active_phy_mode = 0; + uint8_t index = 0, i; + hdd_context_t *hdd_ctx; + int ret; + + ENTER_DEV(dev); + + hdd_ctx = WLAN_HDD_GET_CTX(pAdapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + wrqu->data.length = sizeof(struct iw_range); + memset(range, 0, sizeof(struct iw_range)); + + + /*Get the phy mode */ + if (sme_cfg_get_int(hHal, + WNI_CFG_DOT11_MODE, + &active_phy_mode) == QDF_STATUS_SUCCESS) { + hdd_notice("active_phy_mode = %d", active_phy_mode); + + if (active_phy_mode == WNI_CFG_DOT11_MODE_11A + || active_phy_mode == WNI_CFG_DOT11_MODE_11G) { + /*Get the supported rates for 11G band */ + a_len = WNI_CFG_SUPPORTED_RATES_11A_LEN; + if (sme_cfg_get_str(hHal, + WNI_CFG_SUPPORTED_RATES_11A, + supp_rates, + &a_len) == QDF_STATUS_SUCCESS) { + if (a_len > WNI_CFG_SUPPORTED_RATES_11A_LEN) { + a_len = WNI_CFG_SUPPORTED_RATES_11A_LEN; + } + for (i = 0; i < a_len; i++) { + range->bitrate[i] = + ((supp_rates[i] & 0x7F) / 2) * + 1000000; + } + range->num_bitrates = a_len; + } else { + return -EIO; + } + } else if (active_phy_mode == WNI_CFG_DOT11_MODE_11B) { + /*Get the supported rates for 11B band */ + b_len = WNI_CFG_SUPPORTED_RATES_11B_LEN; + if (sme_cfg_get_str(hHal, + WNI_CFG_SUPPORTED_RATES_11B, + supp_rates, + &b_len) == QDF_STATUS_SUCCESS) { + if (b_len > WNI_CFG_SUPPORTED_RATES_11B_LEN) { + b_len = WNI_CFG_SUPPORTED_RATES_11B_LEN; + } + for (i = 0; i < b_len; i++) { + range->bitrate[i] = + ((supp_rates[i] & 0x7F) / 2) * + 1000000; + } + range->num_bitrates = b_len; + } else { + return -EIO; + } + } + } + + range->max_rts = WNI_CFG_RTS_THRESHOLD_STAMAX; + range->min_frag = WNI_CFG_FRAGMENTATION_THRESHOLD_STAMIN; + range->max_frag = WNI_CFG_FRAGMENTATION_THRESHOLD_STAMAX; + + range->encoding_size[0] = 5; + range->encoding_size[1] = 13; + range->num_encoding_sizes = 2; + range->max_encoding_tokens = MAX_WEP_KEYS; + + /* we support through Wireless Extensions 22 */ + range->we_version_compiled = WIRELESS_EXT; + range->we_version_source = 22; + + /*Supported Channels and Frequencies */ + if (sme_cfg_get_str + ((hHal), WNI_CFG_VALID_CHANNEL_LIST, channels, + &num_channels) != QDF_STATUS_SUCCESS) { + hdd_warn("failed to get ini parameter, WNI_CFG_VALID_CHANNEL_LIST"); + return -EIO; + } + if (num_channels > IW_MAX_FREQUENCIES) { + num_channels = IW_MAX_FREQUENCIES; + } + + range->num_channels = num_channels; + range->num_frequency = num_channels; + + for (index = 0; index < num_channels; index++) { + uint32_t frq_indx = 0; + + range->freq[index].i = channels[index]; + while (frq_indx < FREQ_CHAN_MAP_TABLE_SIZE) { + if (channels[index] == freq_chan_map[frq_indx].chan) { + range->freq[index].m = + freq_chan_map[frq_indx].freq * 100000; + range->freq[index].e = 1; + break; + } + frq_indx++; + } + } + + /* Event capability (kernel + driver) */ + range->event_capa[0] = (IW_EVENT_CAPA_K_0 | + IW_EVENT_CAPA_MASK(SIOCGIWAP) | + IW_EVENT_CAPA_MASK(SIOCGIWSCAN)); + range->event_capa[1] = IW_EVENT_CAPA_K_1; + + /*Encryption capability */ + range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 | + IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP; + + /* Txpower capability */ + range->txpower_capa = IW_TXPOW_MWATT; + + /*Scanning capability */ +#if WIRELESS_EXT >= 22 + range->scan_capa = + IW_SCAN_CAPA_ESSID | IW_SCAN_CAPA_TYPE | IW_SCAN_CAPA_CHANNEL; +#endif + + EXIT(); + return 0; +} + +/** + * iw_get_range() - SSR wrapper for __iw_get_range() + * @dev: pointer to net_device + * @info: pointer to iw_request_info + * @wrqu: pointer to iwreq_data + * @extra: pointer to extra ioctl payload + * + * Return: 0 on success, error number otherwise + */ +static int iw_get_range(struct net_device *dev, struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_get_range(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * hdd_get_class_a_statistics_cb() - Get Class A stats callback function + * @pStats: pointer to Class A stats + * @pContext: user context originally registered with SME + * + * Return: None + */ +static void hdd_get_class_a_statistics_cb(void *pStats, void *pContext) +{ + struct statsContext *pStatsContext; + tCsrGlobalClassAStatsInfo *pClassAStats; + hdd_adapter_t *pAdapter; + + if (ioctl_debug) { + pr_info("%s: pStats [%p] pContext [%p]\n", + __func__, pStats, pContext); + } + + if ((NULL == pStats) || (NULL == pContext)) { + hdd_err("Bad param, pStats [%p] pContext [%p]", + pStats, pContext); + return; + } + + pClassAStats = pStats; + 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) || + (STATS_CONTEXT_MAGIC != pStatsContext->magic)) { + /* the caller presumably timed out so there is nothing + * we can do + */ + spin_unlock(&hdd_context_lock); + hdd_warn("Invalid context, pAdapter [%p] magic [%08x]", + pAdapter, pStatsContext->magic); + if (ioctl_debug) { + pr_info("%s: Invalid context, pAdapter [%p] magic [%08x]\n", + __func__, pAdapter, pStatsContext->magic); + } + return; + } + + /* context is valid so caller is still waiting */ + + /* paranoia: invalidate the magic */ + pStatsContext->magic = 0; + + /* copy over the stats. do so as a struct copy */ + pAdapter->hdd_stats.ClassA_stat = *pClassAStats; + + /* notify the caller */ + complete(&pStatsContext->completion); + + /* serialization is complete */ + spin_unlock(&hdd_context_lock); +} + +/** + * wlan_hdd_get_class_astats() - Get Class A statistics + * @pAdapter: adapter for which statistics are desired + * + * Return: QDF_STATUS_SUCCESS if adapter's Class A statistics were updated + */ +QDF_STATUS wlan_hdd_get_class_astats(hdd_adapter_t *pAdapter) +{ + hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + QDF_STATUS hstatus; + unsigned long rc; + static struct statsContext context; + + if (NULL == pAdapter) { + hdd_err("pAdapter is NULL"); + return QDF_STATUS_E_FAULT; + } + if (cds_is_driver_recovering()) { + hdd_warn("Recovery in Progress. State: 0x%x Ignore!!!", + cds_get_driver_state()); + return QDF_STATUS_SUCCESS; + } + + /* we are connected so prepare our callback context */ + init_completion(&context.completion); + context.pAdapter = pAdapter; + context.magic = STATS_CONTEXT_MAGIC; + /* query only for Class A statistics (which include link speed) */ + hstatus = sme_get_statistics(WLAN_HDD_GET_HAL_CTX(pAdapter), + eCSR_HDD, SME_GLOBAL_CLASSA_STATS, + hdd_get_class_a_statistics_cb, + 0, /* not periodic */ + false, /* non-cached results */ + pHddStaCtx->conn_info.staId[0], + &context, pAdapter->sessionId); + if (QDF_STATUS_SUCCESS != hstatus) { + hdd_warn("Unable to retrieve Class A statistics"); + /* 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) { + hdd_warn("SME timed out while retrieving Class A statistics"); + } + } + + /* 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 callback updated pAdapter stats or it has cached data */ + return QDF_STATUS_SUCCESS; +} + +/** + * hdd_get_station_statistics_cb() - Get stats callback function + * @pStats: pointer to Class A stats + * @pContext: user context originally registered with SME + * + * Return: None + */ +static void hdd_get_station_statistics_cb(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 [%p] pContext [%p]\n", + __func__, pStats, pContext); + } + + if ((NULL == pStats) || (NULL == pContext)) { + hdd_err("Bad param, pStats [%p] pContext [%p]", + pStats, 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); + + 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); + hdd_warn("Invalid context, pAdapter [%p] magic [%08x]", + pAdapter, pStatsContext->magic); + if (ioctl_debug) { + pr_info("%s: Invalid context, pAdapter [%p] magic [%08x]\n", + __func__, pAdapter, pStatsContext->magic); + } + return; + } + + /* context is valid so caller is still waiting */ + + /* paranoia: invalidate the magic */ + pStatsContext->magic = 0; + + /* 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; + + /* notify the caller */ + complete(&pStatsContext->completion); + + /* serialization is complete */ + spin_unlock(&hdd_context_lock); +} + +/** + * wlan_hdd_get_station_stats() - Get station statistics + * @pAdapter: adapter for which statistics are desired + * + * Return: QDF_STATUS_SUCCESS if adapter's statistics were updated + */ +QDF_STATUS wlan_hdd_get_station_stats(hdd_adapter_t *pAdapter) +{ + hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + QDF_STATUS hstatus; + unsigned long rc; + static struct statsContext context; + + if (NULL == pAdapter) { + hdd_err("pAdapter is NULL"); + return QDF_STATUS_SUCCESS; + } + + /* we are connected so 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_get_statistics(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], + &context, pAdapter->sessionId); + if (QDF_STATUS_SUCCESS != hstatus) { + hdd_err("Unable to retrieve statistics"); + /* 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)); + + if (!rc) { + hdd_err("SME timed out while retrieving statistics"); + } + } + + /* 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 callback updated pAdapter stats or it has cached data */ + return QDF_STATUS_SUCCESS; +} + +/** + * iw_get_linkspeed() - Get current link speed ioctl + * @dev: device upon which the ioctl was received + * @info: ioctl request information + * @wrqu: ioctl request data + * @extra: extra ioctl buffer + * + * Return: 0 on success, non-zero on error + */ +static int __iw_get_linkspeed(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + char *pLinkSpeed = (char *)extra; + int len = sizeof(uint32_t) + 1; + uint32_t link_speed = 0; + hdd_context_t *hdd_ctx; + int rc, valid; + + ENTER_DEV(dev); + + hdd_ctx = WLAN_HDD_GET_CTX(pAdapter); + valid = wlan_hdd_validate_context(hdd_ctx); + if (0 != valid) + return valid; + + rc = wlan_hdd_get_link_speed(pAdapter, &link_speed); + if (0 != rc) { + return rc; + } + + wrqu->data.length = len; + /* return the linkspeed as a string */ + rc = snprintf(pLinkSpeed, len, "%u", link_speed); + if ((rc < 0) || (rc >= len)) { + /* encoding or length error? */ + hdd_err("Unable to encode link speed"); + return -EIO; + } + + EXIT(); + /* a value is being successfully returned */ + return 0; +} + +static int iw_get_linkspeed(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_get_linkspeed(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * wlan_hdd_change_country_code_callback() - Change country code callback + * @context: opaque context originally passed to SME. All functions + * which use this callback pass the adapter upon which the country + * code change is active + * + * This function is registered as the callback function when + * sme_change_country_code() is invoked. Callers of + * sme_change_country_code() subsequently wait for the adapter's + * @change_country_code completion variable, so all this function + * needs to do is set that completion variable so that execution can + * continue. + * + * Return: none + */ +void wlan_hdd_change_country_code_callback(void *context) +{ + + hdd_adapter_t *adapter = context; + + if (adapter && (WLAN_HDD_ADAPTER_MAGIC == adapter->magic)) + complete(&adapter->change_country_code); + + return; +} + +/** + * __iw_set_nick() - SIOCSIWNICKN ioctl handler + * @dev: device upon which the ioctl was received + * @info: ioctl request information + * @wrqu: ioctl request data + * @extra: ioctl extra data + * + * Return: 0 on success, non-zero on error + */ +static int __iw_set_nick(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + hdd_adapter_t *adapter; + hdd_context_t *hdd_ctx; + int ret; + + ENTER_DEV(dev); + + adapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + return 0; +} + +/** + * iw_set_nick() - SSR wrapper for __iw_set_nick + * @dev: pointer to net_device + * @info: pointer to iw_request_info + * @wrqu: pointer to iwreq_data + * @extra: extra + * + * Return: 0 on success, error number otherwise + */ +static int iw_set_nick(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_set_nick(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __iw_get_nick() - SIOCGIWNICKN ioctl handler + * @dev: device upon which the ioctl was received + * @info: ioctl request information + * @wrqu: ioctl request data + * @extra: ioctl extra data + * + * Return: 0 on success, non-zero on error + */ +static int __iw_get_nick(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + hdd_adapter_t *adapter; + hdd_context_t *hdd_ctx; + int ret; + + ENTER_DEV(dev); + + adapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + return 0; +} + +/** + * iw_get_nick() - SSR wrapper for __iw_get_nick + * @dev: pointer to net_device + * @info: pointer to iw_request_info + * @wrqu: pointer to iwreq_data + * @extra: extra + * + * Return: 0 on success, error number otherwise + */ +static int iw_get_nick(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_get_nick(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __iw_set_encode() - SIOCSIWENCODE ioctl handler + * @dev: device upon which the ioctl was received + * @info: ioctl request information + * @wrqu: ioctl request data + * @extra: ioctl extra data + * + * Return: 0 on success, non-zero on error + */ +static int __iw_set_encode(struct net_device *dev, struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + hdd_wext_state_t *pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter); + hdd_context_t *hdd_ctx; + struct iw_point *encoderq = &(wrqu->encoding); + uint32_t keyId; + uint8_t key_length; + eCsrEncryptionType encryptionType = eCSR_ENCRYPT_TYPE_NONE; + bool fKeyPresent = 0; + QDF_STATUS status = QDF_STATUS_SUCCESS; + int ret; + + ENTER_DEV(dev); + + hdd_ctx = WLAN_HDD_GET_CTX(pAdapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + keyId = encoderq->flags & IW_ENCODE_INDEX; + + if (keyId) { + if (keyId > MAX_WEP_KEYS) { + return -EINVAL; + } + + fKeyPresent = 1; + keyId--; + } else { + fKeyPresent = 0; + } + + if (wrqu->data.flags & IW_ENCODE_DISABLED) { + hdd_notice("****iwconfig wlan0 key off*****"); + if (!fKeyPresent) { + qdf_mem_zero(pWextState->roamProfile.Keys.KeyLength, + CSR_MAX_NUM_KEY); + } + pHddStaCtx->conn_info.authType = eCSR_AUTH_TYPE_OPEN_SYSTEM; + pWextState->wpaVersion = IW_AUTH_WPA_VERSION_DISABLED; + pWextState->roamProfile.EncryptionType.encryptionType[0] = + eCSR_ENCRYPT_TYPE_NONE; + pWextState->roamProfile.mcEncryptionType.encryptionType[0] = + eCSR_ENCRYPT_TYPE_NONE; + + pHddStaCtx->conn_info.ucEncryptionType = eCSR_ENCRYPT_TYPE_NONE; + pHddStaCtx->conn_info.mcEncryptionType = eCSR_ENCRYPT_TYPE_NONE; + + if (eConnectionState_Associated == + pHddStaCtx->conn_info.connState) { + INIT_COMPLETION(pAdapter->disconnect_comp_var); + status = + sme_roam_disconnect(WLAN_HDD_GET_HAL_CTX(pAdapter), + pAdapter->sessionId, + eCSR_DISCONNECT_REASON_UNSPECIFIED); + if (QDF_STATUS_SUCCESS == status) { + unsigned long rc; + rc = wait_for_completion_timeout(&pAdapter-> + disconnect_comp_var, + msecs_to_jiffies + (WLAN_WAIT_TIME_DISCONNECT)); + if (!rc) + hdd_err("failed wait on disconnect_comp_var"); + } + } + + return status; + + } + + if (wrqu->data.flags & (IW_ENCODE_OPEN | IW_ENCODE_RESTRICTED)) { + hdd_notice("iwconfig wlan0 key on"); + + pHddStaCtx->conn_info.authType = + (encoderq-> + flags & IW_ENCODE_RESTRICTED) ? eCSR_AUTH_TYPE_SHARED_KEY : + eCSR_AUTH_TYPE_OPEN_SYSTEM; + + } + + if (wrqu->data.length > 0) { + hdd_notice("wrqu->data.length : %d", wrqu->data.length); + + key_length = wrqu->data.length; + + /* IW_ENCODING_TOKEN_MAX is the value that is set for wrqu->data.length by iwconfig.c when 'iwconfig wlan0 key on' is issued. */ + + if (5 == key_length) { + hdd_notice("Call with WEP40,key_len=%d", + key_length); + + if ((IW_AUTH_KEY_MGMT_802_1X == pWextState->authKeyMgmt) + && (eCSR_AUTH_TYPE_OPEN_SYSTEM == + pHddStaCtx->conn_info.authType)) { + encryptionType = eCSR_ENCRYPT_TYPE_WEP40; + } else { + encryptionType = + eCSR_ENCRYPT_TYPE_WEP40_STATICKEY; + } + } else if (13 == key_length) { + hdd_notice("Call with WEP104,key_len:%d", + key_length); + + if ((IW_AUTH_KEY_MGMT_802_1X == pWextState->authKeyMgmt) + && (eCSR_AUTH_TYPE_OPEN_SYSTEM == + pHddStaCtx->conn_info.authType)) { + encryptionType = eCSR_ENCRYPT_TYPE_WEP104; + } else { + encryptionType = + eCSR_ENCRYPT_TYPE_WEP104_STATICKEY; + } + } else { + hdd_warn("Invalid WEP key length :%d", + key_length); + return -EINVAL; + } + + pHddStaCtx->conn_info.ucEncryptionType = encryptionType; + pHddStaCtx->conn_info.mcEncryptionType = encryptionType; + pWextState->roamProfile.EncryptionType.numEntries = 1; + pWextState->roamProfile.EncryptionType.encryptionType[0] = + encryptionType; + pWextState->roamProfile.mcEncryptionType.numEntries = 1; + pWextState->roamProfile.mcEncryptionType.encryptionType[0] = + encryptionType; + + if ((eConnectionState_NotConnected == + pHddStaCtx->conn_info.connState) + && + ((eCSR_AUTH_TYPE_OPEN_SYSTEM == + pHddStaCtx->conn_info.authType) + || (eCSR_AUTH_TYPE_SHARED_KEY == + pHddStaCtx->conn_info.authType))) { + + qdf_mem_copy(&pWextState->roamProfile.Keys. + KeyMaterial[keyId][0], extra, key_length); + + pWextState->roamProfile.Keys.KeyLength[keyId] = + (uint8_t) key_length; + pWextState->roamProfile.Keys.defaultIndex = + (uint8_t) keyId; + + return status; + } + } + + return 0; +} + +/** + * iw_set_encode() - SSR wrapper for __iw_set_encode() + * @dev: pointer to net_device + * @info: pointer to iw_request_info + * @wrqu: pointer to iwreq_data + * @extra: pointer to extra ioctl payload + * + * Return: 0 on success, error number otherwise + */ +static int iw_set_encode(struct net_device *dev, struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_set_encode(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __iw_get_encodeext() - SIOCGIWENCODEEXT ioctl handler + * @dev: device upon which the ioctl was received + * @info: ioctl request information + * @wrqu: ioctl request data + * @extra: ioctl extra data + * + * Return: 0 on success, non-zero on error + */ +static int __iw_get_encodeext(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_wext_state_t *pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter); + tCsrRoamProfile *pRoamProfile = &(pWextState->roamProfile); + int keyId; + eCsrEncryptionType encryptionType = eCSR_ENCRYPT_TYPE_NONE; + eCsrAuthType authType = eCSR_AUTH_TYPE_NONE; + int i, ret; + hdd_context_t *hdd_ctx; + + ENTER_DEV(dev); + + hdd_ctx = WLAN_HDD_GET_CTX(pAdapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + keyId = pRoamProfile->Keys.defaultIndex; + + if (keyId < 0 || keyId >= MAX_WEP_KEYS) { + hdd_notice("Invalid keyId : %d", keyId); + return -EINVAL; + } + + if (pRoamProfile->Keys.KeyLength[keyId] > 0) { + dwrq->flags |= IW_ENCODE_ENABLED; + dwrq->length = pRoamProfile->Keys.KeyLength[keyId]; + qdf_mem_copy(extra, &(pRoamProfile->Keys.KeyMaterial[keyId][0]), + pRoamProfile->Keys.KeyLength[keyId]); + } else { + dwrq->flags |= IW_ENCODE_DISABLED; + } + + for (i = 0; i < MAX_WEP_KEYS; i++) { + if (pRoamProfile->Keys.KeyLength[i] == 0) { + continue; + } else { + break; + } + } + + if (MAX_WEP_KEYS == i) { + dwrq->flags |= IW_ENCODE_NOKEY; + } else { + dwrq->flags |= IW_ENCODE_ENABLED; + } + + encryptionType = pRoamProfile->EncryptionType.encryptionType[0]; + + if (eCSR_ENCRYPT_TYPE_NONE == encryptionType) { + dwrq->flags |= IW_ENCODE_DISABLED; + } + + authType = (WLAN_HDD_GET_STATION_CTX_PTR(pAdapter))->conn_info.authType; + + if (IW_AUTH_ALG_OPEN_SYSTEM == authType) { + dwrq->flags |= IW_ENCODE_OPEN; + } else { + dwrq->flags |= IW_ENCODE_RESTRICTED; + } + EXIT(); + return 0; + +} + +/** + * iw_get_encodeext() - SSR wrapper for __iw_get_encodeext() + * @dev: pointer to net_device + * @info: pointer to iw_request_info + * @dwrq: pointer to encoding information + * @extra: pointer to extra ioctl payload + * + * Return: 0 on success, error number otherwise + */ +static int iw_get_encodeext(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_get_encodeext(dev, info, dwrq, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __iw_set_encodeext() - SIOCSIWENCODEEXT ioctl handler + * @dev: device upon which the ioctl was received + * @info: ioctl request information + * @wrqu: ioctl request data + * @extra: ioctl extra data + * + * Return: 0 on success, non-zero on error + */ +static int __iw_set_encodeext(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + hdd_wext_state_t *pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter); + hdd_context_t *hdd_ctx; + QDF_STATUS qdf_ret_status = QDF_STATUS_SUCCESS; + tCsrRoamProfile *pRoamProfile = &pWextState->roamProfile; + int ret; + struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; + int key_index; + struct iw_point *encoding = &wrqu->encoding; + tCsrRoamSetKey setKey; + uint32_t roamId = 0xFF; + + ENTER_DEV(dev); + + hdd_ctx = WLAN_HDD_GET_CTX(pAdapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + key_index = encoding->flags & IW_ENCODE_INDEX; + + if (key_index > 0) { + + /*Convert from 1-based to 0-based keying */ + key_index--; + } + if (!ext->key_len) { + + /*Set the encrytion type to NONE */ + pRoamProfile->EncryptionType.encryptionType[0] = + eCSR_ENCRYPT_TYPE_NONE; + return ret; + } + + if (eConnectionState_NotConnected == pHddStaCtx->conn_info.connState && + (IW_ENCODE_ALG_WEP == ext->alg)) { + if (IW_AUTH_KEY_MGMT_802_1X == pWextState->authKeyMgmt) { + + hdd_err("Invalid Configuration"); + return -EINVAL; + } else { + /*Static wep, update the roam profile with the keys */ + if (ext->key_len + && (ext->key_len <= + eCSR_SECURITY_WEP_KEYSIZE_MAX_BYTES) + && key_index < CSR_MAX_NUM_KEY) { + qdf_mem_copy(&pRoamProfile->Keys. + KeyMaterial[key_index][0], + ext->key, ext->key_len); + pRoamProfile->Keys.KeyLength[key_index] = + (uint8_t) ext->key_len; + + if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) + pRoamProfile->Keys.defaultIndex = + (uint8_t) key_index; + + } + } + return ret; + } + + qdf_mem_zero(&setKey, sizeof(tCsrRoamSetKey)); + + setKey.keyId = key_index; + setKey.keyLength = ext->key_len; + + if (ext->key_len <= CSR_MAX_KEY_LEN) { + qdf_mem_copy(&setKey.Key[0], ext->key, ext->key_len); + } + + if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) { + /*Key direction for group is RX only */ + setKey.keyDirection = eSIR_RX_ONLY; + qdf_set_macaddr_broadcast(&setKey.peerMac); + } else { + + setKey.keyDirection = eSIR_TX_RX; + qdf_mem_copy(setKey.peerMac.bytes, ext->addr.sa_data, + QDF_MAC_ADDR_SIZE); + } + + /*For supplicant pae role is zero */ + setKey.paeRole = 0; + + switch (ext->alg) { + case IW_ENCODE_ALG_NONE: + setKey.encType = eCSR_ENCRYPT_TYPE_NONE; + break; + + case IW_ENCODE_ALG_WEP: + setKey.encType = + (ext->key_len == + 5) ? eCSR_ENCRYPT_TYPE_WEP40 : eCSR_ENCRYPT_TYPE_WEP104; + break; + + case IW_ENCODE_ALG_TKIP: + { + uint8_t *pKey = &setKey.Key[0]; + + setKey.encType = eCSR_ENCRYPT_TYPE_TKIP; + + qdf_mem_zero(pKey, CSR_MAX_KEY_LEN); + + /* Supplicant sends the 32bytes key in this order + * |--------------|----------|----------| + * | Tk1 | TX MIC | RX MIC | + * |--------------|----------|----------| + * <---16bytes---><--8bytes--><--8bytes--> + * + * + * Sme expects the 32 bytes key to be in the below order + * |--------------|----------|----------| + * | Tk1 | RX MIC | TX MIC | + * |--------------|----------|----------| + * <---16bytes---><--8bytes--><--8bytes--> + */ + + /* Copy the Temporal Key 1 (TK1) */ + qdf_mem_copy(pKey, ext->key, 16); + + /* Copy the rx mic first */ + qdf_mem_copy(&pKey[16], &ext->key[24], 8); + + /* Copy the tx mic */ + qdf_mem_copy(&pKey[24], &ext->key[16], 8); + + } + break; + + case IW_ENCODE_ALG_CCMP: + setKey.encType = eCSR_ENCRYPT_TYPE_AES; + break; + +#ifdef FEATURE_WLAN_ESE +#define IW_ENCODE_ALG_KRK 6 + case IW_ENCODE_ALG_KRK: + setKey.encType = eCSR_ENCRYPT_TYPE_KRK; + break; +#endif /* FEATURE_WLAN_ESE */ + + default: + setKey.encType = eCSR_ENCRYPT_TYPE_NONE; + break; + } + + hdd_notice("cipher_alg:%d key_len:%d EncryptionType:%d", + (int)ext->alg, (int)ext->key_len, setKey.encType); + + /* The supplicant may attempt to set the PTK once + * pre-authentication is done. Save the key in the UMAC and + * include it in the ADD BSS request + */ + qdf_ret_status = sme_ft_update_key(WLAN_HDD_GET_HAL_CTX(pAdapter), + pAdapter->sessionId, &setKey); + if (qdf_ret_status == QDF_STATUS_FT_PREAUTH_KEY_SUCCESS) { + hdd_info("Update PreAuth Key success"); + return 0; + } else if (qdf_ret_status == QDF_STATUS_FT_PREAUTH_KEY_FAILED) { + hdd_err("Update PreAuth Key failed"); + return -EINVAL; + } + + pHddStaCtx->roam_info.roamingState = HDD_ROAM_STATE_SETTING_KEY; + + qdf_ret_status = sme_roam_set_key(WLAN_HDD_GET_HAL_CTX(pAdapter), + pAdapter->sessionId, + &setKey, &roamId); + + if (qdf_ret_status != QDF_STATUS_SUCCESS) { + hdd_err("[%4d] sme_roam_set_key returned ERROR status= %d", + __LINE__, qdf_ret_status); + + pHddStaCtx->roam_info.roamingState = HDD_ROAM_STATE_NONE; + } + + return qdf_ret_status; +} + +/** + * iw_set_encodeext() - SSR wrapper for __iw_set_encodeext() + * @dev: pointer to net_device + * @info: pointer to iw_request_info + * @wrqu: pointer to iwreq_data + * @extra: pointer to extra ioctl payload + * + * Return: 0 on success, error number otherwise + */ +static int iw_set_encodeext(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_set_encodeext(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __iw_set_retry() - SIOCSIWRETRY ioctl handler + * @dev: device upon which the ioctl was received + * @info: ioctl request information + * @wrqu: ioctl request data + * @extra: ioctl extra data + * + * Return: 0 on success, non-zero on error + */ +static int __iw_set_retry(struct net_device *dev, struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter); + hdd_context_t *hdd_ctx; + int ret; + + ENTER_DEV(dev); + + hdd_ctx = WLAN_HDD_GET_CTX(pAdapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + if (wrqu->retry.value < WNI_CFG_LONG_RETRY_LIMIT_STAMIN || + wrqu->retry.value > WNI_CFG_LONG_RETRY_LIMIT_STAMAX) { + + hdd_err("Invalid Retry-Limit=%d!!", wrqu->retry.value); + + return -EINVAL; + } + + if (wrqu->retry.flags & IW_RETRY_LIMIT) { + + if ((wrqu->retry.flags & IW_RETRY_LONG)) { + if (sme_cfg_set_int (hHal, WNI_CFG_LONG_RETRY_LIMIT, + wrqu->retry.value) != + QDF_STATUS_SUCCESS) { + hdd_err("failed to set ini parameter, WNI_CFG_LONG_RETRY_LIMIT"); + return -EIO; + } + } else if ((wrqu->retry.flags & IW_RETRY_SHORT)) { + if (sme_cfg_set_int (hHal, WNI_CFG_SHORT_RETRY_LIMIT, + wrqu->retry.value) != + QDF_STATUS_SUCCESS) { + hdd_err("failed to set ini parameter, WNI_CFG_SHORT_RETRY_LIMIT"); + return -EIO; + } + } + } else { + return -EOPNOTSUPP; + } + + hdd_notice("Set Retry-Limit=%d!!", wrqu->retry.value); + + EXIT(); + + return 0; + +} + +/** + * iw_set_retry() - SSR wrapper for __iw_set_retry() + * @dev: pointer to net_device + * @info: pointer to iw_request_info + * @wrqu: pointer to iwreq_data + * @extra: pointer to extra ioctl payload + * + * Return: 0 on success, error number otherwise + */ +static int iw_set_retry(struct net_device *dev, struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_set_retry(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __iw_get_retry() - SIOCGIWRETRY ioctl handler + * @dev: device upon which the ioctl was received + * @info: ioctl request information + * @wrqu: ioctl request data + * @extra: ioctl extra data + * + * Return: 0 on success, non-zero on error + */ +static int __iw_get_retry(struct net_device *dev, struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter); + uint32_t retry = 0; + hdd_context_t *hdd_ctx; + int ret; + + ENTER_DEV(dev); + + hdd_ctx = WLAN_HDD_GET_CTX(pAdapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + if ((wrqu->retry.flags & IW_RETRY_LONG)) { + wrqu->retry.flags = IW_RETRY_LIMIT | IW_RETRY_LONG; + + if (sme_cfg_get_int(hHal, WNI_CFG_LONG_RETRY_LIMIT, &retry) != + QDF_STATUS_SUCCESS) { + hdd_warn("failed to get ini parameter, WNI_CFG_LONG_RETRY_LIMIT"); + return -EIO; + } + + wrqu->retry.value = retry; + } else if ((wrqu->retry.flags & IW_RETRY_SHORT)) { + wrqu->retry.flags = IW_RETRY_LIMIT | IW_RETRY_SHORT; + + if (sme_cfg_get_int(hHal, WNI_CFG_SHORT_RETRY_LIMIT, &retry) != + QDF_STATUS_SUCCESS) { + hdd_warn("failed to get ini parameter, WNI_CFG_SHORT_RETRY_LIMIT"); + return -EIO; + } + + wrqu->retry.value = retry; + } else { + return -EOPNOTSUPP; + } + + hdd_notice("Retry-Limit=%d!!", retry); + + EXIT(); + + return 0; +} + +/** + * iw_get_retry() - SSR wrapper for __iw_get_retry() + * @dev: pointer to net_device + * @info: pointer to iw_request_info + * @wrqu: pointer to iwreq_data + * @extra: pointer to extra ioctl payload + * + * Return: 0 on success, error number otherwise + */ +static int iw_get_retry(struct net_device *dev, struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_get_retry(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __iw_set_mlme() - SIOCSIWMLME ioctl handler + * @dev: device upon which the ioctl was received + * @info: ioctl request information + * @wrqu: ioctl request data + * @extra: ioctl extra data + * + * Return: 0 on success, non-zero on error + */ +static int __iw_set_mlme(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + struct iw_mlme *mlme = (struct iw_mlme *)extra; + QDF_STATUS status = QDF_STATUS_SUCCESS; + hdd_context_t *hdd_ctx; + int ret; + + ENTER_DEV(dev); + + hdd_ctx = WLAN_HDD_GET_CTX(pAdapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + /* reason_code is unused. By default it is set to + * eCSR_DISCONNECT_REASON_UNSPECIFIED + */ + switch (mlme->cmd) { + case IW_MLME_DISASSOC: + case IW_MLME_DEAUTH: + + if (pHddStaCtx->conn_info.connState == + eConnectionState_Associated) { + eCsrRoamDisconnectReason reason = + eCSR_DISCONNECT_REASON_UNSPECIFIED; + + if (mlme->reason_code == HDD_REASON_MICHAEL_MIC_FAILURE) + reason = eCSR_DISCONNECT_REASON_MIC_ERROR; + + INIT_COMPLETION(pAdapter->disconnect_comp_var); + status = + sme_roam_disconnect(WLAN_HDD_GET_HAL_CTX(pAdapter), + pAdapter->sessionId, reason); + + if (QDF_STATUS_SUCCESS == status) { + unsigned long rc; + rc = wait_for_completion_timeout(&pAdapter-> + disconnect_comp_var, + msecs_to_jiffies + (WLAN_WAIT_TIME_DISCONNECT)); + if (!rc) + hdd_err("failed wait on disconnect_comp_var"); + } else + hdd_err("%d Command Disassociate/Deauthenticate : csr_roam_disconnect failure returned %d", + (int)mlme->cmd, (int)status); + + /* Resetting authKeyMgmt */ + (WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter))->authKeyMgmt = + 0; + + hdd_notice("Disabling queues"); + wlan_hdd_netif_queue_control(pAdapter, + WLAN_STOP_ALL_NETIF_QUEUE_N_CARRIER, + WLAN_CONTROL_PATH); + + } else { + hdd_warn("%d Command Disassociate/Deauthenticate called but station is not in associated state", + (int)mlme->cmd); + } + break; + default: + hdd_err("%d Command should be Disassociate/Deauthenticate", + (int)mlme->cmd); + return -EINVAL; + } /* end of switch */ + + EXIT(); + + return status; + +} + +/** + * iw_set_mlme() - SSR wrapper for __iw_set_mlme() + * @dev: pointer to net_device + * @info: pointer to iw_request_info + * @wrqu: pointer to iwreq_data + * @extra: pointer to extra ioctl payload + * + * Return: 0 on success, error number otherwise + */ +static int iw_set_mlme(struct net_device *dev, struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_set_mlme(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * wlan_hdd_update_phymode() - handle change in PHY mode + * @net: device upon which PHY mode change was received + * @hal: umac handle for the driver + * @new_phymode: new PHY mode for the device + * @phddctx: pointer to the HDD context + * + * This function is called when the device is set to a new PHY mode. + * It takes a holistic look at the desired PHY mode along with the + * configured capabilities of the driver and the reported capabilities + * of the hardware in order to correctly configure all PHY-related + * parameters. + * + * Return: 0 on success, negative errno value on error + */ +int wlan_hdd_update_phymode(struct net_device *net, tHalHandle hal, + int new_phymode, hdd_context_t *phddctx) +{ +#ifdef QCA_HT_2040_COEX + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(net); + QDF_STATUS halStatus = QDF_STATUS_E_FAILURE; +#endif + bool band_24 = false, band_5g = false; + bool ch_bond24 = false, ch_bond5g = false; + tSmeConfigParams smeconfig; + uint32_t chwidth = WNI_CFG_CHANNEL_BONDING_MODE_DISABLE; + uint32_t vhtchanwidth; + eCsrPhyMode phymode = -EIO, old_phymode; + eHddDot11Mode hdd_dot11mode = phddctx->config->dot11Mode; + eCsrBand curr_band = eCSR_BAND_ALL; + + old_phymode = sme_get_phy_mode(hal); + + if (WNI_CFG_CHANNEL_BONDING_MODE_DISABLE != + sme_get_cb_phy_state_from_cb_ini_value(phddctx->config-> + nChannelBondingMode24GHz)) + ch_bond24 = true; + + if (WNI_CFG_CHANNEL_BONDING_MODE_DISABLE != + sme_get_cb_phy_state_from_cb_ini_value(phddctx->config-> + nChannelBondingMode5GHz)) + ch_bond5g = true; + + if (phddctx->config->nBandCapability == eCSR_BAND_ALL) { + band_24 = band_5g = true; + } else if (phddctx->config->nBandCapability == eCSR_BAND_24) { + band_24 = true; + } else if (phddctx->config->nBandCapability == eCSR_BAND_5G) { + band_5g = true; + } + + vhtchanwidth = phddctx->config->vhtChannelWidth; + hdd_warn("ch_bond24=%d ch_bond5g=%d band_24=%d band_5g=%d VHT_ch_width=%u", + ch_bond24, ch_bond5g, band_24, band_5g, vhtchanwidth); + + switch (new_phymode) { + case IEEE80211_MODE_AUTO: + sme_set_phy_mode(hal, eCSR_DOT11_MODE_AUTO); + if (hdd_set_band(net, WLAN_HDD_UI_BAND_AUTO) == 0) { + phymode = eCSR_DOT11_MODE_AUTO; + hdd_dot11mode = eHDD_DOT11_MODE_AUTO; + chwidth = WNI_CFG_CHANNEL_BONDING_MODE_ENABLE; + curr_band = eCSR_BAND_ALL; + vhtchanwidth = eHT_CHANNEL_WIDTH_80MHZ; + } else { + sme_set_phy_mode(hal, old_phymode); + return -EIO; + } + break; + case IEEE80211_MODE_11A: + sme_set_phy_mode(hal, eCSR_DOT11_MODE_11a); + if ((hdd_set_band(net, WLAN_HDD_UI_BAND_5_GHZ) == 0)) { + phymode = eCSR_DOT11_MODE_11a; + hdd_dot11mode = eHDD_DOT11_MODE_11a; + chwidth = WNI_CFG_CHANNEL_BONDING_MODE_DISABLE; + curr_band = eCSR_BAND_5G; + } else { + sme_set_phy_mode(hal, old_phymode); + return -EIO; + } + break; + case IEEE80211_MODE_11B: + sme_set_phy_mode(hal, eCSR_DOT11_MODE_11b); + if ((hdd_set_band(net, WLAN_HDD_UI_BAND_2_4_GHZ) == 0)) { + phymode = eCSR_DOT11_MODE_11b; + hdd_dot11mode = eHDD_DOT11_MODE_11b; + chwidth = WNI_CFG_CHANNEL_BONDING_MODE_DISABLE; + curr_band = eCSR_BAND_24; + } else { + sme_set_phy_mode(hal, old_phymode); + return -EIO; + } + break; + case IEEE80211_MODE_11G: + sme_set_phy_mode(hal, eCSR_DOT11_MODE_11g); + if ((hdd_set_band(net, WLAN_HDD_UI_BAND_2_4_GHZ) == 0)) { + phymode = eCSR_DOT11_MODE_11g; + hdd_dot11mode = eHDD_DOT11_MODE_11g; + chwidth = WNI_CFG_CHANNEL_BONDING_MODE_DISABLE; + curr_band = eCSR_BAND_24; + } else { + sme_set_phy_mode(hal, old_phymode); + return -EIO; + } + break; + /* UMAC doesnt have option to set MODE_11NA/MODE_11NG as phymode + * so setting phymode as eCSR_DOT11_MODE_11n and updating the band + * and channel bonding in configuration to reflect MODE_11NA/MODE_11NG + */ + case IEEE80211_MODE_11NA_HT20: + sme_set_phy_mode(hal, eCSR_DOT11_MODE_11n); + if ((hdd_set_band(net, WLAN_HDD_UI_BAND_5_GHZ) == 0)) { + phymode = eCSR_DOT11_MODE_11n; + hdd_dot11mode = eHDD_DOT11_MODE_11n; + chwidth = WNI_CFG_CHANNEL_BONDING_MODE_DISABLE; + curr_band = eCSR_BAND_5G; + } else { + sme_set_phy_mode(hal, old_phymode); + return -EIO; + } + break; + case IEEE80211_MODE_11NA_HT40: + sme_set_phy_mode(hal, eCSR_DOT11_MODE_11n); + if ((hdd_set_band(net, WLAN_HDD_UI_BAND_5_GHZ) == 0)) { + phymode = eCSR_DOT11_MODE_11n; + hdd_dot11mode = eHDD_DOT11_MODE_11n; + chwidth = WNI_CFG_CHANNEL_BONDING_MODE_ENABLE; + curr_band = eCSR_BAND_5G; + } else { + sme_set_phy_mode(hal, old_phymode); + return -EIO; + } + break; + case IEEE80211_MODE_11NG_HT20: + sme_set_phy_mode(hal, eCSR_DOT11_MODE_11n); + if ((hdd_set_band(net, WLAN_HDD_UI_BAND_2_4_GHZ) == 0)) { + phymode = eCSR_DOT11_MODE_11n; + hdd_dot11mode = eHDD_DOT11_MODE_11n; + chwidth = WNI_CFG_CHANNEL_BONDING_MODE_DISABLE; + curr_band = eCSR_BAND_24; + } else { + sme_set_phy_mode(hal, old_phymode); + return -EIO; + } + break; + case IEEE80211_MODE_11NG_HT40: + sme_set_phy_mode(hal, eCSR_DOT11_MODE_11n); + if ((hdd_set_band(net, WLAN_HDD_UI_BAND_2_4_GHZ) == 0)) { + phymode = eCSR_DOT11_MODE_11n; + hdd_dot11mode = eHDD_DOT11_MODE_11n; + chwidth = WNI_CFG_CHANNEL_BONDING_MODE_ENABLE; + curr_band = eCSR_BAND_24; + } else { + sme_set_phy_mode(hal, old_phymode); + return -EIO; + } + break; + case IEEE80211_MODE_11AC_VHT20: + case IEEE80211_MODE_11AC_VHT40: + case IEEE80211_MODE_11AC_VHT80: + sme_set_phy_mode(hal, eCSR_DOT11_MODE_11ac); + if ((hdd_set_band(net, WLAN_HDD_UI_BAND_5_GHZ) == 0)) { + phymode = eCSR_DOT11_MODE_11ac; + hdd_dot11mode = eHDD_DOT11_MODE_11ac; + chwidth = WNI_CFG_CHANNEL_BONDING_MODE_ENABLE; + curr_band = eCSR_BAND_5G; + } else { + sme_set_phy_mode(hal, old_phymode); + return -EIO; + } + break; + case IEEE80211_MODE_2G_AUTO: + sme_set_phy_mode(hal, eCSR_DOT11_MODE_AUTO); + if ((hdd_set_band(net, WLAN_HDD_UI_BAND_2_4_GHZ) == 0)) { + phymode = eCSR_DOT11_MODE_AUTO; + hdd_dot11mode = eHDD_DOT11_MODE_AUTO; + chwidth = WNI_CFG_CHANNEL_BONDING_MODE_ENABLE; + curr_band = eCSR_BAND_24; + } else { + sme_set_phy_mode(hal, old_phymode); + return -EIO; + } + break; + case IEEE80211_MODE_5G_AUTO: + sme_set_phy_mode(hal, eCSR_DOT11_MODE_AUTO); + if ((hdd_set_band(net, WLAN_HDD_UI_BAND_5_GHZ) == 0)) { + phymode = eCSR_DOT11_MODE_AUTO; + hdd_dot11mode = eHDD_DOT11_MODE_AUTO; + chwidth = WNI_CFG_CHANNEL_BONDING_MODE_ENABLE; + vhtchanwidth = eHT_CHANNEL_WIDTH_80MHZ; + curr_band = eCSR_BAND_5G; + } else { + sme_set_phy_mode(hal, old_phymode); + return -EIO; + } + break; + case IEEE80211_MODE_11AGN: + sme_set_phy_mode(hal, eCSR_DOT11_MODE_11n); + if ((hdd_set_band(net, WLAN_HDD_UI_BAND_AUTO) == 0)) { + phymode = eCSR_DOT11_MODE_11n; + hdd_dot11mode = eHDD_DOT11_MODE_11n; + chwidth = WNI_CFG_CHANNEL_BONDING_MODE_ENABLE; + curr_band = eCSR_BAND_ALL; + } else { + sme_set_phy_mode(hal, old_phymode); + return -EIO; + } + break; + default: + return -EIO; + } + + switch (new_phymode) { + case IEEE80211_MODE_11AC_VHT20: + chwidth = WNI_CFG_CHANNEL_BONDING_MODE_DISABLE; + vhtchanwidth = eHT_CHANNEL_WIDTH_20MHZ; + break; + case IEEE80211_MODE_11AC_VHT40: + vhtchanwidth = eHT_CHANNEL_WIDTH_40MHZ; + break; + case IEEE80211_MODE_11AC_VHT80: + vhtchanwidth = eHT_CHANNEL_WIDTH_80MHZ; + break; + default: + vhtchanwidth = phddctx->config->vhtChannelWidth; + break; + } + + if (phymode != -EIO) { + sme_get_config_param(hal, &smeconfig); + smeconfig.csrConfig.phyMode = phymode; +#ifdef QCA_HT_2040_COEX + if (phymode == eCSR_DOT11_MODE_11n && + chwidth == WNI_CFG_CHANNEL_BONDING_MODE_DISABLE) { + smeconfig.csrConfig.obssEnabled = false; + halStatus = sme_set_ht2040_mode(hal, + pAdapter->sessionId, + eHT_CHAN_HT20, false); + if (halStatus == QDF_STATUS_E_FAILURE) { + hdd_err("Failed to disable OBSS"); + return -EIO; + } + } else if (phymode == eCSR_DOT11_MODE_11n && + chwidth == WNI_CFG_CHANNEL_BONDING_MODE_ENABLE) { + smeconfig.csrConfig.obssEnabled = true; + halStatus = sme_set_ht2040_mode(hal, + pAdapter->sessionId, + eHT_CHAN_HT20, true); + if (halStatus == QDF_STATUS_E_FAILURE) { + hdd_err("Failed to enable OBSS"); + return -EIO; + } + } +#endif + smeconfig.csrConfig.eBand = curr_band; + smeconfig.csrConfig.bandCapability = curr_band; + if (curr_band == eCSR_BAND_24) + smeconfig.csrConfig.Is11hSupportEnabled = 0; + else + smeconfig.csrConfig.Is11hSupportEnabled = + phddctx->config->Is11hSupportEnabled; + if (curr_band == eCSR_BAND_24) + smeconfig.csrConfig.channelBondingMode24GHz = chwidth; + else if (curr_band == eCSR_BAND_24) + smeconfig.csrConfig.channelBondingMode5GHz = chwidth; + else { + smeconfig.csrConfig.channelBondingMode24GHz = chwidth; + smeconfig.csrConfig.channelBondingMode5GHz = chwidth; + } + smeconfig.csrConfig.nVhtChannelWidth = vhtchanwidth; + sme_update_config(hal, &smeconfig); + + phddctx->config->dot11Mode = hdd_dot11mode; + phddctx->config->nBandCapability = curr_band; + phddctx->config->nChannelBondingMode24GHz = + smeconfig.csrConfig.channelBondingMode24GHz; + phddctx->config->nChannelBondingMode5GHz = + smeconfig.csrConfig.channelBondingMode5GHz; + phddctx->config->vhtChannelWidth = vhtchanwidth; + if (hdd_update_config_cfg(phddctx) == false) { + hdd_err("could not update config_dat"); + return -EIO; + } + if (phddctx->config->nChannelBondingMode5GHz) + phddctx->wiphy->bands[NL80211_BAND_5GHZ]->ht_cap.cap + |= IEEE80211_HT_CAP_SUP_WIDTH_20_40; + else + phddctx->wiphy->bands[NL80211_BAND_5GHZ]->ht_cap.cap + &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; + + hdd_warn("New_Phymode= %d ch_bonding=%d band=%d VHT_ch_width=%u", + phymode, chwidth, curr_band, vhtchanwidth); + } + + return 0; +} + +/** + * hdd_get_temperature_cb() - "Get Temperature" callback function + * @temperature: measured temperature + * @pContext: callback context + * + * This function is passed to sme_get_temperature() as the callback + * function to be invoked when the temperature measurement is + * available. + * + * Return: None + */ +static void hdd_get_temperature_cb(int temperature, void *pContext) +{ + struct statsContext *pTempContext; + hdd_adapter_t *pAdapter; + ENTER(); + if (NULL == pContext) { + hdd_err("pContext is NULL"); + return; + } + pTempContext = pContext; + pAdapter = pTempContext->pAdapter; + spin_lock(&hdd_context_lock); + if ((NULL == pAdapter) || (TEMP_CONTEXT_MAGIC != pTempContext->magic)) { + spin_unlock(&hdd_context_lock); + hdd_warn("Invalid context, pAdapter [%p] magic [%08x]", + pAdapter, pTempContext->magic); + return; + } + if (temperature != 0) { + pAdapter->temperature = temperature; + } + complete(&pTempContext->completion); + spin_unlock(&hdd_context_lock); + EXIT(); +} + +/** + * wlan_hdd_get_temperature() - get current device temperature + * @pAdapter: device upon which the request was made + * @temperature: pointer to where the temperature is to be returned + * + * Return: 0 if a temperature value (either current or cached) was + * returned, otherwise a negative errno is returned. + * + */ +int wlan_hdd_get_temperature(hdd_adapter_t *pAdapter, int *temperature) +{ + QDF_STATUS status; + static struct statsContext tempContext; + unsigned long rc; + + ENTER(); + if (NULL == pAdapter) { + hdd_err("pAdapter is NULL"); + return -EPERM; + } + init_completion(&tempContext.completion); + tempContext.pAdapter = pAdapter; + tempContext.magic = TEMP_CONTEXT_MAGIC; + status = sme_get_temperature(WLAN_HDD_GET_HAL_CTX(pAdapter), + &tempContext, hdd_get_temperature_cb); + if (QDF_STATUS_SUCCESS != status) { + hdd_err("Unable to retrieve temperature"); + } else { + rc = wait_for_completion_timeout(&tempContext.completion, + msecs_to_jiffies + (WLAN_WAIT_TIME_STATS)); + if (!rc) { + hdd_err("SME timed out while retrieving temperature"); + } + } + spin_lock(&hdd_context_lock); + tempContext.magic = 0; + spin_unlock(&hdd_context_lock); + *temperature = pAdapter->temperature; + EXIT(); + return 0; +} + +/** + * iw_setint_getnone() - Generic "set integer" private ioctl handler + * @dev: device upon which the ioctl was received + * @info: ioctl request information + * @wrqu: ioctl request data + * @extra: ioctl extra data + * + * Return: 0 on success, non-zero on error + */ +static int __iw_setint_getnone(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter); + hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + hdd_wext_state_t *pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter); + hdd_context_t *hdd_ctx; + tSmeConfigParams smeConfig; + int *value = (int *)extra; + int sub_cmd = value[0]; + int set_value = value[1]; + int ret; + int enable_pbm, enable_mp; + QDF_STATUS status; + + ENTER_DEV(dev); + + INIT_COMPLETION(pWextState->completion_var); + memset(&smeConfig, 0x00, sizeof(smeConfig)); + + hdd_ctx = WLAN_HDD_GET_CTX(pAdapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + switch (sub_cmd) { + case WE_SET_11D_STATE: + { + if (((ENABLE_11D == set_value) + || (DISABLE_11D == set_value)) && hHal) { + + sme_get_config_param(hHal, &smeConfig); + smeConfig.csrConfig.Is11dSupportEnabled = + (bool) set_value; + + hdd_notice("11D state=%d!!", + smeConfig.csrConfig. + Is11dSupportEnabled); + + sme_update_config(hHal, &smeConfig); + } else { + return -EINVAL; + } + break; + } + + case WE_WOWL: + { + if (!hHal) + return -EINVAL; + + switch (set_value) { + case 0x00: + hdd_exit_wowl(pAdapter); + break; + case 0x01: + case 0x02: + case 0x03: + enable_mp = (set_value & 0x01) ? 1 : 0; + enable_pbm = (set_value & 0x02) ? 1 : 0; + hdd_notice("magic packet ? = %s pattern byte matching ? = %s", + (enable_mp ? "YES" : "NO"), + (enable_pbm ? "YES" : "NO")); + hdd_enter_wowl(pAdapter, enable_mp, enable_pbm); + break; + default: + hdd_err("Invalid arg %d in WE_WOWL IOCTL", + set_value); + ret = -EINVAL; + break; + } + + break; + } + case WE_SET_POWER: + { + if (!hHal) + return -EINVAL; + + switch (set_value) { + case 1: + /* Enable PowerSave */ + sme_ps_enable_disable(hHal, pAdapter->sessionId, + SME_PS_ENABLE); + break; + case 2: + /* Disable PowerSave */ + sme_ps_enable_disable(hHal, pAdapter->sessionId, + SME_PS_DISABLE); + break; + case 3: /* Enable UASPD */ + sme_ps_uapsd_enable(hHal, pAdapter->sessionId); + break; + case 4: /* Disable UASPD */ + sme_ps_uapsd_disable(hHal, pAdapter->sessionId); + break; + default: + hdd_err("Invalid arg %d in WE_SET_POWER IOCTL", + set_value); + ret = -EINVAL; + break; + } + break; + } + + case WE_SET_MAX_ASSOC: + { + if (!hHal) + return -EINVAL; + + if ((WNI_CFG_ASSOC_STA_LIMIT_STAMIN > set_value) || + (WNI_CFG_ASSOC_STA_LIMIT_STAMAX < set_value)) { + ret = -EINVAL; + } else if (sme_cfg_set_int(hHal, WNI_CFG_ASSOC_STA_LIMIT, + set_value) + != QDF_STATUS_SUCCESS) { + hdd_err("failed to set ini parameter, WNI_CFG_ASSOC_STA_LIMIT"); + ret = -EIO; + } + break; + } + + case WE_SET_SAP_AUTO_CHANNEL_SELECTION: + if (set_value == 0 || set_value == 1) + (WLAN_HDD_GET_CTX(pAdapter))->config->force_sap_acs = + set_value; + else + ret = -EINVAL; + break; + + case WE_SET_DATA_INACTIVITY_TO: + if (!hHal) + return -EINVAL; + + if ((set_value < CFG_DATA_INACTIVITY_TIMEOUT_MIN) || + (set_value > CFG_DATA_INACTIVITY_TIMEOUT_MAX) || + (sme_cfg_set_int((WLAN_HDD_GET_CTX(pAdapter))->hHal, + WNI_CFG_PS_DATA_INACTIVITY_TIMEOUT, + set_value) == QDF_STATUS_E_FAILURE)) { + hdd_err("Failure: Could not pass on WNI_CFG_PS_DATA_INACTIVITY_TIMEOUT configuration info to SME"); + ret = -EINVAL; + } + break; + case WE_SET_WOW_DATA_INACTIVITY_TO: + if (!hHal) + return -EINVAL; + + if ((set_value < CFG_WOW_DATA_INACTIVITY_TIMEOUT_MIN) || + (set_value > CFG_WOW_DATA_INACTIVITY_TIMEOUT_MAX) || + (sme_cfg_set_int((WLAN_HDD_GET_CTX(pAdapter))->hHal, + WNI_CFG_PS_WOW_DATA_INACTIVITY_TIMEOUT, + set_value) == QDF_STATUS_E_FAILURE)) { + hdd_err("WNI_CFG_PS_WOW_DATA_INACTIVITY_TIMEOUT fail"); + ret = -EINVAL; + } + break; + case WE_SET_MC_RATE: + { + if (!hHal) + return -EINVAL; + + ret = wlan_hdd_set_mc_rate(pAdapter, set_value); + break; + } + case WE_SET_TX_POWER: + { + struct qdf_mac_addr bssid; + + if (!hHal) + return -EINVAL; + + qdf_copy_macaddr(&bssid, &pHddStaCtx->conn_info.bssId); + if (sme_set_tx_power + (hHal, pAdapter->sessionId, bssid, + pAdapter->device_mode, + set_value) != QDF_STATUS_SUCCESS) { + hdd_err("Setting tx power failed"); + return -EIO; + } + break; + } + case WE_SET_MAX_TX_POWER: + { + struct qdf_mac_addr bssid; + struct qdf_mac_addr selfMac; + + if (!hHal) + return -EINVAL; + + hdd_notice("Setting maximum tx power %d dBm", + set_value); + qdf_copy_macaddr(&bssid, &pHddStaCtx->conn_info.bssId); + qdf_copy_macaddr(&selfMac, &pHddStaCtx->conn_info.bssId); + + if (sme_set_max_tx_power(hHal, bssid, selfMac, set_value) + != QDF_STATUS_SUCCESS) { + hdd_err("Setting maximum tx power failed"); + return -EIO; + } + + break; + } + case WE_SET_MAX_TX_POWER_2_4: + { + hdd_notice("Setting maximum tx power %d dBm for 2.4 GHz band", + set_value); + if (sme_set_max_tx_power_per_band(eCSR_BAND_24, set_value) != + QDF_STATUS_SUCCESS) { + hdd_err("Setting maximum tx power failed for 2.4 GHz band"); + return -EIO; + } + + break; + } + case WE_SET_MAX_TX_POWER_5_0: + { + hdd_notice("Setting maximum tx power %d dBm for 5.0 GHz band", + set_value); + if (sme_set_max_tx_power_per_band(eCSR_BAND_5G, set_value) != + QDF_STATUS_SUCCESS) { + hdd_err("Setting maximum tx power failed for 5.0 GHz band"); + return -EIO; + } + + break; + } + case WE_SET_HIGHER_DTIM_TRANSITION: + { + if (!((set_value == false) || (set_value == true))) { + hdd_err("Dynamic DTIM Incorrect data:%d", + set_value); + ret = -EINVAL; + } else { + if (pAdapter->higherDtimTransition != set_value) { + pAdapter->higherDtimTransition = + set_value; + hdd_notice("higherDtimTransition set to :%d", + pAdapter->higherDtimTransition); + } + } + + break; + } + + case WE_SET_TM_LEVEL: + { + if (!hHal) + return -EINVAL; + + hdd_notice("Set Thermal Mitigation Level %d", set_value); + (void)sme_set_thermal_level(hHal, set_value); + break; + } + + case WE_SET_PHYMODE: + { + hdd_context_t *phddctx = WLAN_HDD_GET_CTX(pAdapter); + if (!hHal) + return -EINVAL; + + ret = + wlan_hdd_update_phymode(dev, hHal, set_value, + phddctx); + break; + } + + case WE_SET_NSS: + { + if (!hHal) + return -EINVAL; + + hdd_notice("Set NSS = %d", set_value); + if ((set_value > 2) || (set_value <= 0)) { + hdd_err("NSS greater than 2 not supported"); + ret = -EINVAL; + } else { + if (QDF_STATUS_SUCCESS != + hdd_update_nss(WLAN_HDD_GET_CTX(pAdapter), + set_value)) + ret = -EINVAL; + } + break; + } + + case WE_SET_GTX_HT_MCS: + { + hdd_notice("WMI_VDEV_PARAM_GTX_HT_MCS %d", set_value); + ret = wma_cli_set_command(pAdapter->sessionId, + WMI_VDEV_PARAM_GTX_HT_MCS, + set_value, GTX_CMD); + break; + } + + case WE_SET_GTX_VHT_MCS: + { + hdd_notice("WMI_VDEV_PARAM_GTX_VHT_MCS %d", + set_value); + ret = wma_cli_set_command(pAdapter->sessionId, + WMI_VDEV_PARAM_GTX_VHT_MCS, + set_value, GTX_CMD); + break; + } + + case WE_SET_GTX_USRCFG: + { + hdd_notice("WMI_VDEV_PARAM_GTX_USR_CFG %d", + set_value); + ret = wma_cli_set_command(pAdapter->sessionId, + WMI_VDEV_PARAM_GTX_USR_CFG, + set_value, GTX_CMD); + break; + } + + case WE_SET_GTX_THRE: + { + hdd_notice("WMI_VDEV_PARAM_GTX_THRE %d", set_value); + ret = wma_cli_set_command(pAdapter->sessionId, + WMI_VDEV_PARAM_GTX_THRE, + set_value, GTX_CMD); + break; + } + + case WE_SET_GTX_MARGIN: + { + hdd_notice("WMI_VDEV_PARAM_GTX_MARGIN %d", set_value); + ret = wma_cli_set_command(pAdapter->sessionId, + WMI_VDEV_PARAM_GTX_MARGIN, + set_value, GTX_CMD); + break; + } + + case WE_SET_GTX_STEP: + { + hdd_notice("WMI_VDEV_PARAM_GTX_STEP %d", set_value); + ret = wma_cli_set_command(pAdapter->sessionId, + WMI_VDEV_PARAM_GTX_STEP, + set_value, GTX_CMD); + break; + } + + case WE_SET_GTX_MINTPC: + { + hdd_notice("WMI_VDEV_PARAM_GTX_MINTPC %d", set_value); + ret = wma_cli_set_command(pAdapter->sessionId, + WMI_VDEV_PARAM_GTX_MINTPC, + set_value, GTX_CMD); + break; + } + + case WE_SET_GTX_BWMASK: + { + hdd_notice("WMI_VDEV_PARAM_GTX_BWMASK %d", set_value); + ret = wma_cli_set_command(pAdapter->sessionId, + WMI_VDEV_PARAM_GTX_BW_MASK, + set_value, GTX_CMD); + break; + } + + case WE_SET_LDPC: + { + ret = hdd_set_ldpc(pAdapter, set_value); + break; + } + + case WE_SET_TX_STBC: + { + ret = hdd_set_tx_stbc(pAdapter, set_value); + break; + } + + case WE_SET_RX_STBC: + { + ret = hdd_set_rx_stbc(pAdapter, set_value); + break; + } + + case WE_SET_SHORT_GI: + { + if (!hHal) + return -EINVAL; + + hdd_notice("WMI_VDEV_PARAM_SGI val %d", set_value); + ret = sme_update_ht_config(hHal, pAdapter->sessionId, + WNI_CFG_HT_CAP_INFO_SHORT_GI_20MHZ, + set_value); + if (ret) + hdd_err("Failed to set ShortGI value"); + break; + } + + case WE_SET_RTSCTS: + { + uint32_t value; + + if (!hHal) + return -EINVAL; + + hdd_notice("WMI_VDEV_PARAM_ENABLE_RTSCTS val 0x%x", + set_value); + + if ((set_value & HDD_RTSCTS_EN_MASK) == + HDD_RTSCTS_ENABLE) + value = + (WLAN_HDD_GET_CTX(pAdapter))->config-> + RTSThreshold; + else if (((set_value & HDD_RTSCTS_EN_MASK) == 0) + || ((set_value & HDD_RTSCTS_EN_MASK) == + HDD_CTS_ENABLE)) + value = WNI_CFG_RTS_THRESHOLD_STAMAX; + else + return -EIO; + + ret = wma_cli_set_command(pAdapter->sessionId, + WMI_VDEV_PARAM_ENABLE_RTSCTS, + set_value, VDEV_CMD); + if (!ret) { + if (sme_cfg_set_int + (hHal, WNI_CFG_RTS_THRESHOLD, value) != + QDF_STATUS_SUCCESS) { + hdd_err("FAILED TO SET RTSCTS"); + return -EIO; + } + } + + break; + } + + case WE_SET_CHWIDTH: + { + bool chwidth = false; + hdd_context_t *phddctx = WLAN_HDD_GET_CTX(pAdapter); + if (!hHal) + return -EINVAL; + + /*updating channel bonding only on 5Ghz */ + hdd_notice("WMI_VDEV_PARAM_CHWIDTH val %d", + set_value); + if (set_value > eHT_CHANNEL_WIDTH_80MHZ) { + hdd_err("Invalid channel width 0->20 1->40 2->80"); + return -EINVAL; + } + + if ((WNI_CFG_CHANNEL_BONDING_MODE_DISABLE != + csr_convert_cb_ini_value_to_phy_cb_state(phddctx->config-> + nChannelBondingMode5GHz))) + chwidth = true; + + sme_get_config_param(hHal, &smeConfig); + switch (set_value) { + case eHT_CHANNEL_WIDTH_20MHZ: + smeConfig.csrConfig.channelBondingMode5GHz = + WNI_CFG_CHANNEL_BONDING_MODE_DISABLE; + break; + case eHT_CHANNEL_WIDTH_40MHZ: + if (chwidth) + smeConfig.csrConfig. + channelBondingMode5GHz = + phddctx->config-> + nChannelBondingMode5GHz; + else + return -EINVAL; + + break; + case eHT_CHANNEL_WIDTH_80MHZ: + if (chwidth) + smeConfig.csrConfig. + channelBondingMode5GHz = + phddctx->config-> + nChannelBondingMode5GHz; + else + return -EINVAL; + + break; + + default: + return -EINVAL; + } + + ret = wma_cli_set_command(pAdapter->sessionId, + WMI_VDEV_PARAM_CHWIDTH, + set_value, VDEV_CMD); + if (!ret) + sme_update_config(hHal, &smeConfig); + + break; + } + + case WE_SET_ANI_EN_DIS: + { + hdd_notice("WMI_PDEV_PARAM_ANI_ENABLE val %d", + set_value); + ret = wma_cli_set_command(pAdapter->sessionId, + WMI_PDEV_PARAM_ANI_ENABLE, + set_value, PDEV_CMD); + break; + } + + case WE_SET_ANI_POLL_PERIOD: + { + hdd_notice("WMI_PDEV_PARAM_ANI_POLL_PERIOD val %d", + set_value); + ret = wma_cli_set_command(pAdapter->sessionId, + WMI_PDEV_PARAM_ANI_POLL_PERIOD, + set_value, PDEV_CMD); + break; + } + + case WE_SET_ANI_LISTEN_PERIOD: + { + hdd_notice("WMI_PDEV_PARAM_ANI_LISTEN_PERIOD val %d", + set_value); + ret = wma_cli_set_command(pAdapter->sessionId, + WMI_PDEV_PARAM_ANI_LISTEN_PERIOD, + set_value, PDEV_CMD); + break; + } + + case WE_SET_ANI_OFDM_LEVEL: + { + hdd_notice("WMI_PDEV_PARAM_ANI_OFDM_LEVEL val %d", + set_value); + ret = wma_cli_set_command(pAdapter->sessionId, + WMI_PDEV_PARAM_ANI_OFDM_LEVEL, + set_value, PDEV_CMD); + break; + } + + case WE_SET_ANI_CCK_LEVEL: + { + hdd_notice("WMI_PDEV_PARAM_ANI_CCK_LEVEL val %d", + set_value); + ret = wma_cli_set_command(pAdapter->sessionId, + WMI_PDEV_PARAM_ANI_CCK_LEVEL, + set_value, PDEV_CMD); + break; + } + + case WE_SET_DYNAMIC_BW: + { + hdd_notice("WMI_PDEV_PARAM_DYNAMIC_BW val %d", + set_value); + ret = wma_cli_set_command(pAdapter->sessionId, + WMI_PDEV_PARAM_DYNAMIC_BW, + set_value, PDEV_CMD); + break; + } + + case WE_SET_CTS_CBW: + { + hdd_notice("WE_SET_CTS_CBW val %d", set_value); + ret = wma_cli_set_command(pAdapter->sessionId, + WMI_PDEV_PARAM_CTS_CBW, + set_value, PDEV_CMD); + break; + } + + case WE_SET_11N_RATE: + { + uint8_t preamble = 0, nss = 0, rix = 0; + hdd_notice("WMI_VDEV_PARAM_FIXED_RATE val %d", + set_value); + + if (set_value != 0xff) { + rix = RC_2_RATE_IDX(set_value); + if (set_value & 0x80) { + preamble = WMI_RATE_PREAMBLE_HT; + nss = HT_RC_2_STREAMS(set_value) - 1; + } else { + nss = 0; + rix = RC_2_RATE_IDX(set_value); + if (set_value & 0x10) { + preamble = + WMI_RATE_PREAMBLE_CCK; + if (rix != 0x3) + /* Enable Short + * preamble always for + * CCK except 1mbps + */ + rix |= 0x4; + } else { + preamble = + WMI_RATE_PREAMBLE_OFDM; + } + } + set_value = (preamble << 6) | (nss << 4) | rix; + } + hdd_info("WMI_VDEV_PARAM_FIXED_RATE val %d rix %d preamble %x nss %d", + set_value, rix, preamble, nss); + + ret = wma_cli_set_command(pAdapter->sessionId, + WMI_VDEV_PARAM_FIXED_RATE, + set_value, VDEV_CMD); + break; + } + + case WE_SET_VHT_RATE: + { + uint8_t preamble = 0, nss = 0, rix = 0; + + if (set_value != 0xff) { + rix = RC_2_RATE_IDX_11AC(set_value); + preamble = WMI_RATE_PREAMBLE_VHT; + nss = HT_RC_2_STREAMS_11AC(set_value) - 1; + + set_value = (preamble << 6) | (nss << 4) | rix; + } + hdd_info("WMI_VDEV_PARAM_FIXED_RATE val %d rix %d preamble %x nss %d", + set_value, rix, preamble, nss); + ret = wma_cli_set_command(pAdapter->sessionId, + WMI_VDEV_PARAM_FIXED_RATE, + set_value, VDEV_CMD); + break; + } + + case WE_SET_AMPDU: + { + hdd_notice("SET AMPDU val %d", set_value); + ret = wma_cli_set_command(pAdapter->sessionId, + GEN_VDEV_PARAM_AMPDU, + set_value, GEN_CMD); + break; + } + + case WE_SET_AMSDU: + { + hdd_notice("SET AMSDU val %d", set_value); + ret = wma_cli_set_command(pAdapter->sessionId, + GEN_VDEV_PARAM_AMSDU, + set_value, GEN_CMD); + /* Update the stored ini value */ + if (!ret) + hdd_ctx->config->max_amsdu_num = set_value; + break; + } + + case WE_SET_BURST_ENABLE: + { + hdd_notice("SET Burst enable val %d", set_value); + if ((set_value == 0) || (set_value == 1)) { + ret = wma_cli_set_command(pAdapter->sessionId, + WMI_PDEV_PARAM_BURST_ENABLE, + set_value, PDEV_CMD); + } else + ret = -EINVAL; + break; + } + case WE_SET_BURST_DUR: + { + hdd_notice("SET Burst duration val %d", set_value); + if ((set_value > 0) && (set_value <= 102400)) + ret = wma_cli_set_command(pAdapter->sessionId, + WMI_PDEV_PARAM_BURST_DUR, + set_value, PDEV_CMD); + else + ret = -EINVAL; + break; + } + + case WE_SET_TX_CHAINMASK: + { + hdd_notice("WMI_PDEV_PARAM_TX_CHAIN_MASK val %d", + set_value); + ret = wma_cli_set_command(pAdapter->sessionId, + WMI_PDEV_PARAM_TX_CHAIN_MASK, + set_value, PDEV_CMD); + break; + } + + case WE_SET_RX_CHAINMASK: + { + hdd_notice("WMI_PDEV_PARAM_RX_CHAIN_MASK val %d", + set_value); + ret = wma_cli_set_command(pAdapter->sessionId, + WMI_PDEV_PARAM_RX_CHAIN_MASK, + set_value, PDEV_CMD); + break; + } + + case WE_SET_TXPOW_2G: + { + hdd_notice("WMI_PDEV_PARAM_TXPOWER_LIMIT2G val %d", + set_value); + ret = wma_cli_set_command(pAdapter->sessionId, + WMI_PDEV_PARAM_TXPOWER_LIMIT2G, + set_value, PDEV_CMD); + break; + } + + case WE_SET_TXPOW_5G: + { + hdd_notice("WMI_PDEV_PARAM_TXPOWER_LIMIT5G val %d", + set_value); + ret = wma_cli_set_command(pAdapter->sessionId, + WMI_PDEV_PARAM_TXPOWER_LIMIT5G, + set_value, PDEV_CMD); + break; + } + + /* Firmware debug log */ + case WE_DBGLOG_LOG_LEVEL: + { + hdd_notice("WE_DBGLOG_LOG_LEVEL val %d", set_value); + hdd_ctx->fw_log_settings.dl_loglevel = set_value; + ret = wma_cli_set_command(pAdapter->sessionId, + WMI_DBGLOG_LOG_LEVEL, + set_value, DBG_CMD); + break; + } + + case WE_DBGLOG_VAP_ENABLE: + { + hdd_notice("WE_DBGLOG_VAP_ENABLE val %d", set_value); + ret = wma_cli_set_command(pAdapter->sessionId, + WMI_DBGLOG_VAP_ENABLE, + set_value, DBG_CMD); + break; + } + + case WE_DBGLOG_VAP_DISABLE: + { + hdd_notice("WE_DBGLOG_VAP_DISABLE val %d", set_value); + ret = wma_cli_set_command(pAdapter->sessionId, + WMI_DBGLOG_VAP_DISABLE, + set_value, DBG_CMD); + break; + } + + case WE_DBGLOG_MODULE_ENABLE: + { + hdd_notice("WE_DBGLOG_MODULE_ENABLE val %d", + set_value); + hdd_ctx->fw_log_settings.enable = set_value; + ret = wma_cli_set_command(pAdapter->sessionId, + WMI_DBGLOG_MODULE_ENABLE, + set_value, DBG_CMD); + break; + } + + case WE_DBGLOG_MODULE_DISABLE: + { + hdd_notice("WE_DBGLOG_MODULE_DISABLE val %d", + set_value); + hdd_ctx->fw_log_settings.enable = set_value; + ret = wma_cli_set_command(pAdapter->sessionId, + WMI_DBGLOG_MODULE_DISABLE, + set_value, DBG_CMD); + break; + } + case WE_DBGLOG_MOD_LOG_LEVEL: + { + hdd_notice("WE_DBGLOG_MOD_LOG_LEVEL val %d", + set_value); + + if (hdd_ctx->fw_log_settings.index >= MAX_MOD_LOGLEVEL) + hdd_ctx->fw_log_settings.index = 0; + + hdd_ctx->fw_log_settings. + dl_mod_loglevel[hdd_ctx->fw_log_settings.index] = + set_value; + hdd_ctx->fw_log_settings.index++; + + ret = wma_cli_set_command(pAdapter->sessionId, + WMI_DBGLOG_MOD_LOG_LEVEL, + set_value, DBG_CMD); + break; + } + + case WE_DBGLOG_TYPE: + { + hdd_notice("WE_DBGLOG_TYPE val %d", set_value); + hdd_ctx->fw_log_settings.dl_type = set_value; + ret = wma_cli_set_command(pAdapter->sessionId, + WMI_DBGLOG_TYPE, + set_value, DBG_CMD); + break; + } + case WE_DBGLOG_REPORT_ENABLE: + { + hdd_notice("WE_DBGLOG_REPORT_ENABLE val %d", + set_value); + hdd_ctx->fw_log_settings.dl_report = set_value; + ret = wma_cli_set_command(pAdapter->sessionId, + WMI_DBGLOG_REPORT_ENABLE, + set_value, DBG_CMD); + break; + } + + case WE_SET_TXRX_FWSTATS: + { + hdd_notice("WE_SET_TXRX_FWSTATS val %d", set_value); + ret = wma_cli_set_command(pAdapter->sessionId, + WMA_VDEV_TXRX_FWSTATS_ENABLE_CMDID, + set_value, VDEV_CMD); + break; + } + + case WE_TXRX_FWSTATS_RESET: + { + hdd_notice("WE_TXRX_FWSTATS_RESET val %d", set_value); + ret = wma_cli_set_command(pAdapter->sessionId, + WMA_VDEV_TXRX_FWSTATS_RESET_CMDID, + set_value, VDEV_CMD); + break; + } + + case WE_DUMP_STATS: + { + hdd_notice("WE_DUMP_STATS val %d", set_value); + ret = hdd_wlan_dump_stats(pAdapter, set_value); + break; + } + + case WE_CLEAR_STATS: + { + hdd_notice("WE_CLEAR_STATS val %d", set_value); + switch (set_value) { + case WLAN_HDD_STATS: + memset(&pAdapter->stats, 0, sizeof(pAdapter->stats)); + memset(&pAdapter->hdd_stats, 0, + sizeof(pAdapter->hdd_stats)); + break; + case WLAN_TXRX_HIST_STATS: + wlan_hdd_clear_tx_rx_histogram(hdd_ctx); + break; + case WLAN_HDD_NETIF_OPER_HISTORY: + wlan_hdd_clear_netif_queue_history(hdd_ctx); + break; + case WLAN_HIF_STATS: + hdd_clear_hif_stats(); + break; + default: + if (ol_txrx_clear_stats(set_value) == + QDF_STATUS_E_INVAL) { + hdd_display_stats_help(); + ret = EINVAL; + } + } + break; + } + + case WE_PPS_PAID_MATCH: + { + if (pAdapter->device_mode != QDF_STA_MODE) + return EINVAL; + + hdd_notice("WMI_VDEV_PPS_PAID_MATCH val %d ", + set_value); + ret = wma_cli_set_command(pAdapter->sessionId, + WMI_VDEV_PPS_PAID_MATCH, + set_value, PPS_CMD); + break; + } + + case WE_PPS_GID_MATCH: + { + if (pAdapter->device_mode != QDF_STA_MODE) + return EINVAL; + hdd_notice("WMI_VDEV_PPS_GID_MATCH val %d ", + set_value); + ret = wma_cli_set_command(pAdapter->sessionId, + WMI_VDEV_PPS_GID_MATCH, + set_value, PPS_CMD); + break; + } + + case WE_PPS_EARLY_TIM_CLEAR: + { + if (pAdapter->device_mode != QDF_STA_MODE) + return EINVAL; + hdd_notice(" WMI_VDEV_PPS_EARLY_TIM_CLEAR val %d ", + set_value); + ret = wma_cli_set_command(pAdapter->sessionId, + WMI_VDEV_PPS_EARLY_TIM_CLEAR, + set_value, PPS_CMD); + break; + } + + case WE_PPS_EARLY_DTIM_CLEAR: + { + if (pAdapter->device_mode != QDF_STA_MODE) + return EINVAL; + hdd_notice("WMI_VDEV_PPS_EARLY_DTIM_CLEAR val %d", + set_value); + ret = wma_cli_set_command(pAdapter->sessionId, + WMI_VDEV_PPS_EARLY_DTIM_CLEAR, + set_value, PPS_CMD); + break; + } + + case WE_PPS_EOF_PAD_DELIM: + { + if (pAdapter->device_mode != QDF_STA_MODE) + return EINVAL; + hdd_notice("WMI_VDEV_PPS_EOF_PAD_DELIM val %d ", + set_value); + ret = wma_cli_set_command(pAdapter->sessionId, + WMI_VDEV_PPS_EOF_PAD_DELIM, + set_value, PPS_CMD); + break; + } + + case WE_PPS_MACADDR_MISMATCH: + { + if (pAdapter->device_mode != QDF_STA_MODE) + return EINVAL; + hdd_notice("WMI_VDEV_PPS_MACADDR_MISMATCH val %d ", + set_value); + ret = wma_cli_set_command(pAdapter->sessionId, + WMI_VDEV_PPS_MACADDR_MISMATCH, + set_value, PPS_CMD); + break; + } + + case WE_PPS_DELIM_CRC_FAIL: + { + if (pAdapter->device_mode != QDF_STA_MODE) + return EINVAL; + hdd_notice("WMI_VDEV_PPS_DELIM_CRC_FAIL val %d ", + set_value); + ret = wma_cli_set_command(pAdapter->sessionId, + WMI_VDEV_PPS_DELIM_CRC_FAIL, + set_value, PPS_CMD); + break; + } + + case WE_PPS_GID_NSTS_ZERO: + { + if (pAdapter->device_mode != QDF_STA_MODE) + return EINVAL; + hdd_notice("WMI_VDEV_PPS_GID_NSTS_ZERO val %d ", + set_value); + ret = wma_cli_set_command(pAdapter->sessionId, + WMI_VDEV_PPS_GID_NSTS_ZERO, + set_value, PPS_CMD); + break; + } + + case WE_PPS_RSSI_CHECK: + { + if (pAdapter->device_mode != QDF_STA_MODE) + return EINVAL; + hdd_notice("WMI_VDEV_PPS_RSSI_CHECK val %d ", + set_value); + ret = wma_cli_set_command(pAdapter->sessionId, + WMI_VDEV_PPS_RSSI_CHECK, + set_value, PPS_CMD); + break; + } + + case WE_PPS_5G_EBT: + { + if (pAdapter->device_mode != QDF_STA_MODE) + return -EINVAL; + + hdd_notice("WMI_VDEV_PPS_5G_EBT val %d", set_value); + ret = wma_cli_set_command(pAdapter->sessionId, + WMI_VDEV_PPS_5G_EBT, + set_value, PPS_CMD); + break; + } + + case WE_SET_HTSMPS: + { + hdd_notice("WE_SET_HTSMPS val %d", set_value); + ret = wma_cli_set_command(pAdapter->sessionId, + WMI_STA_SMPS_FORCE_MODE_CMDID, + set_value, VDEV_CMD); + break; + } + + case WE_SET_QPOWER_MAX_PSPOLL_COUNT: + { + hdd_notice("WE_SET_QPOWER_MAX_PSPOLL_COUNT val %d", + set_value); + ret = wma_cli_set_command(pAdapter->sessionId, + WMI_STA_PS_PARAM_QPOWER_PSPOLL_COUNT, + set_value, QPOWER_CMD); + break; + } + + case WE_SET_QPOWER_MAX_TX_BEFORE_WAKE: + { + hdd_notice("WE_SET_QPOWER_MAX_TX_BEFORE_WAKE val %d", + set_value); + ret = wma_cli_set_command( + pAdapter->sessionId, + WMI_STA_PS_PARAM_QPOWER_MAX_TX_BEFORE_WAKE, + set_value, QPOWER_CMD); + break; + } + + case WE_SET_QPOWER_SPEC_PSPOLL_WAKE_INTERVAL: + { + hdd_notice("WE_SET_QPOWER_SPEC_PSPOLL_WAKE_INTERVAL val %d", + set_value); + ret = wma_cli_set_command( + pAdapter->sessionId, + WMI_STA_PS_PARAM_QPOWER_SPEC_PSPOLL_WAKE_INTERVAL, + set_value, QPOWER_CMD); + break; + } + + case WE_SET_QPOWER_SPEC_MAX_SPEC_NODATA_PSPOLL: + { + hdd_notice("WE_SET_QPOWER_SPEC_MAX_SPEC_NODATA_PSPOLL val %d", + set_value); + ret = wma_cli_set_command( + pAdapter->sessionId, + WMI_STA_PS_PARAM_QPOWER_SPEC_MAX_SPEC_NODATA_PSPOLL, + set_value, QPOWER_CMD); + break; + } + + case WE_MCC_CONFIG_LATENCY: + { + cds_set_mcc_latency(pAdapter, set_value); + break; + } + + case WE_MCC_CONFIG_QUOTA: + { + hdd_notice("iwpriv cmd to set MCC quota with val %dms", + set_value); + ret = cds_set_mcc_p2p_quota(pAdapter, set_value); + break; + } + case WE_SET_DEBUG_LOG: + { + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(pAdapter); + + if (!hHal) + return -EINVAL; + + hdd_ctx->config->gEnableDebugLog = set_value; + sme_update_connect_debug(hHal, set_value); + break; + } + case WE_SET_EARLY_RX_ADJUST_ENABLE: + { + hdd_notice("SET early_rx enable val %d", set_value); + if ((set_value == 0) || (set_value == 1)) + ret = wma_cli_set_command( + pAdapter->sessionId, + WMI_VDEV_PARAM_EARLY_RX_ADJUST_ENABLE, + set_value, VDEV_CMD); + else + ret = -EINVAL; + break; + } + case WE_SET_EARLY_RX_TGT_BMISS_NUM: + { + hdd_notice("SET early_rx bmiss val %d", set_value); + ret = wma_cli_set_command(pAdapter->sessionId, + WMI_VDEV_PARAM_EARLY_RX_TGT_BMISS_NUM, + set_value, VDEV_CMD); + break; + } + case WE_SET_EARLY_RX_BMISS_SAMPLE_CYCLE: + { + hdd_notice("SET early_rx bmiss sample cycle %d", + set_value); + ret = wma_cli_set_command( + pAdapter->sessionId, + WMI_VDEV_PARAM_EARLY_RX_BMISS_SAMPLE_CYCLE, + set_value, VDEV_CMD); + break; + } + case WE_SET_EARLY_RX_SLOP_STEP: + { + hdd_notice("SET early_rx bmiss slop step val %d", + set_value); + ret = wma_cli_set_command(pAdapter->sessionId, + WMI_VDEV_PARAM_EARLY_RX_SLOP_STEP, + set_value, VDEV_CMD); + break; + } + case WE_SET_EARLY_RX_INIT_SLOP: + { + hdd_notice("SET early_rx init slop step val %d", + set_value); + ret = wma_cli_set_command(pAdapter->sessionId, + WMI_VDEV_PARAM_EARLY_RX_INIT_SLOP, + set_value, VDEV_CMD); + break; + } + case WE_SET_EARLY_RX_ADJUST_PAUSE: + { + hdd_notice("SET early_rx adjust pause %d", set_value); + if ((set_value == 0) || (set_value == 1)) + ret = wma_cli_set_command( + pAdapter->sessionId, + WMI_VDEV_PARAM_EARLY_RX_ADJUST_PAUSE, + set_value, VDEV_CMD); + else + ret = -EINVAL; + break; + } + case WE_SET_EARLY_RX_DRIFT_SAMPLE: + { + hdd_notice("SET early_rx drift sample %d", set_value); + ret = wma_cli_set_command(pAdapter->sessionId, + WMI_VDEV_PARAM_EARLY_RX_DRIFT_SAMPLE, + set_value, VDEV_CMD); + break; + } + case WE_SET_SCAN_DISABLE: + { + if (!hHal) + return -EINVAL; + + hdd_notice("SET SCAN DISABLE %d", set_value); + sme_set_scan_disable(hHal, set_value); + break; + } + case WE_START_FW_PROFILE: + { + hdd_notice("WE_START_FW_PROFILE %d", set_value); + ret = wma_cli_set_command(pAdapter->sessionId, + WMI_WLAN_PROFILE_TRIGGER_CMDID, + set_value, DBG_CMD); + break; + } + case WE_SET_CHANNEL: + { + hdd_notice("Set Channel %d Session ID %d mode %d", set_value, + pAdapter->sessionId, pAdapter->device_mode); + if (!hHal) + return -EINVAL; + + + if ((QDF_STA_MODE == pAdapter->device_mode) || + (QDF_P2P_CLIENT_MODE == pAdapter->device_mode)) { + + status = sme_ext_change_channel(hHal, + set_value, pAdapter->sessionId); + if (status != QDF_STATUS_SUCCESS) { + hdd_err("Error in change channel status %d", + status); + ret = -EINVAL; + } + } else { + hdd_err("change channel not supported for device mode %d", + pAdapter->device_mode); + ret = -EINVAL; + } + break; + } + case WE_SET_CONC_SYSTEM_PREF: + { + hdd_info("New preference: %d", set_value); + if (!((set_value >= CFG_CONC_SYSTEM_PREF_MIN) && + (set_value <= CFG_CONC_SYSTEM_PREF_MAX))) { + hdd_err("Invalid system preference %d", set_value); + return -EINVAL; + } + + /* hdd_ctx, hdd_ctx->config are already checked for null */ + hdd_ctx->config->conc_system_pref = set_value; + break; + } + default: + { + hdd_err("Invalid sub command %d", + sub_cmd); + ret = -EINVAL; + break; + } + } + EXIT(); + return ret; +} + +static int iw_setint_getnone(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_setint_getnone(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __iw_setnone_get_threeint() - return three value to up layer. + * + * @dev: pointer of net_device of this wireless card + * @info: meta data about Request sent + * @wrqu: include request info + * @extra: buf used for in/Output + * + * Return: execute result + */ +static int __iw_setnone_get_threeint(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret = 0; /* success */ + uint32_t *value = (int *)extra; + hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + + ENTER_DEV(dev); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + hdd_info("param = %d", value[0]); + switch (value[0]) { + case WE_GET_TSF: + ret = hdd_indicate_tsf(adapter, value, 3); + break; + default: + hdd_err("Invalid IOCTL get_value command %d", value[0]); + break; + } + return ret; +} + +/** + * iw_setnone_get_threeint() - return three value to up layer. + * + * @dev: pointer of net_device of this wireless card + * @info: meta data about Request sent + * @wrqu: include request info + * @extra: buf used for in/Output + * + * Return: execute result + */ +static int iw_setnone_get_threeint(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_setnone_get_threeint(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * iw_setchar_getnone() - Generic "set string" private ioctl handler + * @dev: device upon which the ioctl was received + * @info: ioctl request information + * @wrqu: ioctl request data + * @extra: ioctl extra data + * + * Return: 0 on success, non-zero on error + */ +static int __iw_setchar_getnone(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + QDF_STATUS vstatus; + int sub_cmd; + int ret; + char *pBuffer = NULL; + hdd_adapter_t *pAdapter = (netdev_priv(dev)); + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(pAdapter); + struct hdd_config *pConfig = hdd_ctx->config; + struct iw_point s_priv_data; + + ENTER_DEV(dev); + + if (!capable(CAP_NET_ADMIN)) { + hdd_err("permission check failed"); + return -EPERM; + } + + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + /* helper function to get iwreq_data with compat handling. */ + if (hdd_priv_get_data(&s_priv_data, wrqu)) { + return -EINVAL; + } + + /* make sure all params are correctly passed to function */ + if ((NULL == s_priv_data.pointer) || (0 == s_priv_data.length)) { + return -EINVAL; + } + + sub_cmd = s_priv_data.flags; + + /* ODD number is used for set, copy data using copy_from_user */ + pBuffer = mem_alloc_copy_from_user_helper(s_priv_data.pointer, + s_priv_data.length); + if (NULL == pBuffer) { + hdd_err("mem_alloc_copy_from_user_helper fail"); + return -ENOMEM; + } + + hdd_notice("Received length %d", s_priv_data.length); + hdd_notice("Received data %s", pBuffer); + + switch (sub_cmd) { + case WE_WOWL_ADD_PTRN: + hdd_notice("ADD_PTRN"); + hdd_add_wowl_ptrn(pAdapter, pBuffer); + break; + case WE_WOWL_DEL_PTRN: + hdd_notice("DEL_PTRN"); + hdd_del_wowl_ptrn(pAdapter, pBuffer); + break; + case WE_NEIGHBOR_REPORT_REQUEST: + { + tRrmNeighborReq neighborReq; + tRrmNeighborRspCallbackInfo callbackInfo; + + if (pConfig->fRrmEnable) { + hdd_notice("Neighbor Request"); + neighborReq.no_ssid = + (s_priv_data.length - 1) ? false : true; + if (!neighborReq.no_ssid) { + neighborReq.ssid.length = + (s_priv_data.length - 1) > + 32 ? 32 : (s_priv_data.length - 1); + qdf_mem_copy(neighborReq.ssid.ssId, + pBuffer, + neighborReq.ssid.length); + } + + callbackInfo.neighborRspCallback = NULL; + callbackInfo.neighborRspCallbackContext = NULL; + callbackInfo.timeout = 5000; /* 5 seconds */ + sme_neighbor_report_request(WLAN_HDD_GET_HAL_CTX + (pAdapter), + pAdapter->sessionId, + &neighborReq, + &callbackInfo); + } else { + hdd_err("Ignoring neighbor request as RRM is not enabled"); + ret = -EINVAL; + } + } + break; + case WE_SET_AP_WPS_IE: + hdd_notice("Received WE_SET_AP_WPS_IE"); + sme_update_p2p_ie(WLAN_HDD_GET_HAL_CTX(pAdapter), pBuffer, + s_priv_data.length); + break; + case WE_SET_CONFIG: + vstatus = hdd_execute_global_config_command(hdd_ctx, pBuffer); + if (QDF_STATUS_SUCCESS != vstatus) { + ret = -EINVAL; + } + break; + default: + { + hdd_err("Invalid sub command %d", + sub_cmd); + ret = -EINVAL; + break; + } + } + qdf_mem_free(pBuffer); + EXIT(); + return ret; +} + +static int iw_setchar_getnone(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_setchar_getnone(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * iw_setnone_getint() - Generic "get integer" private ioctl handler + * @dev: device upon which the ioctl was received + * @info: ioctl request information + * @wrqu: ioctl request data + * @extra: ioctl extra data + * + * Return: 0 on success, non-zero on error + */ +static int __iw_setnone_getint(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter); + int *value = (int *)extra; + int ret; + tSmeConfigParams smeConfig; + hdd_context_t *hdd_ctx; + + ENTER_DEV(dev); + + hdd_ctx = WLAN_HDD_GET_CTX(pAdapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + switch (value[0]) { + case WE_GET_11D_STATE: + { + sme_get_config_param(hHal, &smeConfig); + + *value = smeConfig.csrConfig.Is11dSupportEnabled; + + hdd_notice("11D state=%d!!", *value); + + break; + } + + case WE_GET_WLAN_DBG: + { + qdf_trace_display(); + *value = 0; + break; + } + case WE_GET_MAX_ASSOC: + { + if (sme_cfg_get_int + (hHal, WNI_CFG_ASSOC_STA_LIMIT, + (uint32_t *) value) != QDF_STATUS_SUCCESS) { + hdd_warn("failed to get ini parameter, WNI_CFG_ASSOC_STA_LIMIT"); + ret = -EIO; + } + break; + } + case WE_GET_SAP_AUTO_CHANNEL_SELECTION: + *value = (WLAN_HDD_GET_CTX( + pAdapter))->config->force_sap_acs; + break; + + case WE_GET_CONCURRENCY_MODE: + { + *value = cds_get_concurrency_mode(); + + hdd_notice("concurrency mode=%d", *value); + break; + } + + case WE_GET_NSS: + { + sme_get_config_param(hHal, &smeConfig); + *value = (smeConfig.csrConfig.enable2x2 == 0) ? 1 : 2; + hdd_notice("GET_NSS: Current NSS:%d", *value); + break; + } + + case WE_GET_GTX_HT_MCS: + { + hdd_notice("GET WMI_VDEV_PARAM_GTX_HT_MCS"); + *value = wma_cli_get_command(pAdapter->sessionId, + WMI_VDEV_PARAM_GTX_HT_MCS, + GTX_CMD); + break; + } + + case WE_GET_GTX_VHT_MCS: + { + hdd_notice("GET WMI_VDEV_PARAM_GTX_VHT_MCS"); + *value = wma_cli_get_command(pAdapter->sessionId, + WMI_VDEV_PARAM_GTX_VHT_MCS, + GTX_CMD); + break; + } + + case WE_GET_GTX_USRCFG: + { + hdd_notice("GET WMI_VDEV_PARAM_GTX_USR_CFG"); + *value = wma_cli_get_command(pAdapter->sessionId, + WMI_VDEV_PARAM_GTX_USR_CFG, + GTX_CMD); + break; + } + + case WE_GET_GTX_THRE: + { + hdd_notice("GET WMI_VDEV_PARAM_GTX_THRE"); + *value = wma_cli_get_command(pAdapter->sessionId, + WMI_VDEV_PARAM_GTX_THRE, + GTX_CMD); + break; + } + + case WE_GET_GTX_MARGIN: + { + hdd_notice("GET WMI_VDEV_PARAM_GTX_MARGIN"); + *value = wma_cli_get_command(pAdapter->sessionId, + WMI_VDEV_PARAM_GTX_MARGIN, + GTX_CMD); + break; + } + + case WE_GET_GTX_STEP: + { + hdd_notice("GET WMI_VDEV_PARAM_GTX_STEP"); + *value = wma_cli_get_command(pAdapter->sessionId, + WMI_VDEV_PARAM_GTX_STEP, + GTX_CMD); + break; + } + + case WE_GET_GTX_MINTPC: + { + hdd_notice("GET WMI_VDEV_PARAM_GTX_MINTPC"); + *value = wma_cli_get_command(pAdapter->sessionId, + WMI_VDEV_PARAM_GTX_MINTPC, + GTX_CMD); + break; + } + + case WE_GET_GTX_BWMASK: + { + hdd_notice("GET WMI_VDEV_PARAM_GTX_BW_MASK"); + *value = wma_cli_get_command(pAdapter->sessionId, + WMI_VDEV_PARAM_GTX_BW_MASK, + GTX_CMD); + break; + } + + case WE_GET_LDPC: + { + ret = hdd_get_ldpc(pAdapter, value); + break; + } + + case WE_GET_TX_STBC: + { + ret = hdd_get_tx_stbc(pAdapter, value); + break; + } + + case WE_GET_RX_STBC: + { + ret = hdd_get_rx_stbc(pAdapter, value); + break; + } + + case WE_GET_SHORT_GI: + { + hdd_notice("GET WMI_VDEV_PARAM_SGI"); + *value = sme_get_ht_config(hHal, pAdapter->sessionId, + WNI_CFG_HT_CAP_INFO_SHORT_GI_20MHZ); + break; + } + + case WE_GET_RTSCTS: + { + hdd_notice("GET WMI_VDEV_PARAM_ENABLE_RTSCTS"); + *value = wma_cli_get_command(pAdapter->sessionId, + WMI_VDEV_PARAM_ENABLE_RTSCTS, + VDEV_CMD); + break; + } + + case WE_GET_CHWIDTH: + { + hdd_notice("GET WMI_VDEV_PARAM_CHWIDTH"); + *value = wma_cli_get_command(pAdapter->sessionId, + WMI_VDEV_PARAM_CHWIDTH, + VDEV_CMD); + break; + } + + case WE_GET_ANI_EN_DIS: + { + hdd_notice("GET WMI_PDEV_PARAM_ANI_ENABLE"); + *value = wma_cli_get_command(pAdapter->sessionId, + WMI_PDEV_PARAM_ANI_ENABLE, + PDEV_CMD); + break; + } + + case WE_GET_ANI_POLL_PERIOD: + { + hdd_notice("GET WMI_PDEV_PARAM_ANI_POLL_PERIOD"); + *value = wma_cli_get_command(pAdapter->sessionId, + WMI_PDEV_PARAM_ANI_POLL_PERIOD, + PDEV_CMD); + break; + } + + case WE_GET_ANI_LISTEN_PERIOD: + { + hdd_notice("GET WMI_PDEV_PARAM_ANI_LISTEN_PERIOD"); + *value = wma_cli_get_command(pAdapter->sessionId, + WMI_PDEV_PARAM_ANI_LISTEN_PERIOD, + PDEV_CMD); + break; + } + + case WE_GET_ANI_OFDM_LEVEL: + { + hdd_notice("GET WMI_PDEV_PARAM_ANI_OFDM_LEVEL"); + *value = wma_cli_get_command(pAdapter->sessionId, + WMI_PDEV_PARAM_ANI_OFDM_LEVEL, + PDEV_CMD); + break; + } + + case WE_GET_ANI_CCK_LEVEL: + { + hdd_notice("GET WMI_PDEV_PARAM_ANI_CCK_LEVEL"); + *value = wma_cli_get_command(pAdapter->sessionId, + WMI_PDEV_PARAM_ANI_CCK_LEVEL, + PDEV_CMD); + break; + } + + case WE_GET_DYNAMIC_BW: + { + hdd_notice("GET WMI_PDEV_PARAM_ANI_CCK_LEVEL"); + *value = wma_cli_get_command(pAdapter->sessionId, + WMI_PDEV_PARAM_DYNAMIC_BW, + PDEV_CMD); + break; + } + + case WE_GET_11N_RATE: + { + hdd_notice("GET WMI_VDEV_PARAM_FIXED_RATE"); + *value = wma_cli_get_command(pAdapter->sessionId, + WMI_VDEV_PARAM_FIXED_RATE, + VDEV_CMD); + break; + } + + case WE_GET_AMPDU: + { + hdd_notice("GET AMPDU"); + *value = wma_cli_get_command(pAdapter->sessionId, + GEN_VDEV_PARAM_AMPDU, + GEN_CMD); + break; + } + + case WE_GET_AMSDU: + { + hdd_notice("GET AMSDU"); + *value = wma_cli_get_command(pAdapter->sessionId, + GEN_VDEV_PARAM_AMSDU, + GEN_CMD); + break; + } + + case WE_GET_ROAM_SYNCH_DELAY: + { + hdd_notice("GET ROAM SYNCH DELAY"); + *value = wma_cli_get_command(pAdapter->sessionId, + GEN_VDEV_ROAM_SYNCH_DELAY, + GEN_CMD); + break; + } + + case WE_GET_BURST_ENABLE: + { + hdd_notice("GET Burst enable value"); + *value = wma_cli_get_command(pAdapter->sessionId, + WMI_PDEV_PARAM_BURST_ENABLE, + PDEV_CMD); + break; + } + case WE_GET_BURST_DUR: + { + hdd_notice("GET Burst Duration value"); + *value = wma_cli_get_command(pAdapter->sessionId, + WMI_PDEV_PARAM_BURST_DUR, + PDEV_CMD); + break; + } + + case WE_GET_TX_CHAINMASK: + { + hdd_notice("GET WMI_PDEV_PARAM_TX_CHAIN_MASK"); + *value = wma_cli_get_command(pAdapter->sessionId, + WMI_PDEV_PARAM_TX_CHAIN_MASK, + PDEV_CMD); + break; + } + + case WE_GET_RX_CHAINMASK: + { + hdd_notice("GET WMI_PDEV_PARAM_RX_CHAIN_MASK"); + *value = wma_cli_get_command(pAdapter->sessionId, + WMI_PDEV_PARAM_RX_CHAIN_MASK, + PDEV_CMD); + break; + } + + case WE_GET_TXPOW_2G: + { + uint32_t txpow2g = 0; + tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter); + hdd_notice("GET WMI_PDEV_PARAM_TXPOWER_LIMIT2G"); + *value = wma_cli_get_command(pAdapter->sessionId, + WMI_PDEV_PARAM_TXPOWER_LIMIT2G, + PDEV_CMD); + if (QDF_STATUS_SUCCESS != + sme_cfg_get_int(hHal, WNI_CFG_CURRENT_TX_POWER_LEVEL, + &txpow2g)) { + return -EIO; + } + hdd_notice("2G tx_power %d", txpow2g); + break; + } + + case WE_GET_TXPOW_5G: + { + uint32_t txpow5g = 0; + tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter); + hdd_notice("GET WMI_PDEV_PARAM_TXPOWER_LIMIT5G"); + *value = wma_cli_get_command(pAdapter->sessionId, + WMI_PDEV_PARAM_TXPOWER_LIMIT5G, + PDEV_CMD); + if (QDF_STATUS_SUCCESS != + sme_cfg_get_int(hHal, WNI_CFG_CURRENT_TX_POWER_LEVEL, + &txpow5g)) { + return -EIO; + } + hdd_notice("5G tx_power %d", txpow5g); + break; + } + + case WE_GET_PPS_PAID_MATCH: + { + hdd_notice("GET WMI_VDEV_PPS_PAID_MATCH"); + *value = wma_cli_get_command(pAdapter->sessionId, + WMI_VDEV_PPS_PAID_MATCH, + PPS_CMD); + break; + } + + case WE_GET_PPS_GID_MATCH: + { + hdd_notice("GET WMI_VDEV_PPS_GID_MATCH"); + *value = wma_cli_get_command(pAdapter->sessionId, + WMI_VDEV_PPS_GID_MATCH, + PPS_CMD); + break; + } + + case WE_GET_PPS_EARLY_TIM_CLEAR: + { + hdd_notice("GET WMI_VDEV_PPS_EARLY_TIM_CLEAR"); + *value = wma_cli_get_command(pAdapter->sessionId, + WMI_VDEV_PPS_EARLY_TIM_CLEAR, + PPS_CMD); + break; + } + + case WE_GET_PPS_EARLY_DTIM_CLEAR: + { + hdd_notice("GET WMI_VDEV_PPS_EARLY_DTIM_CLEAR"); + *value = wma_cli_get_command(pAdapter->sessionId, + WMI_VDEV_PPS_EARLY_DTIM_CLEAR, + PPS_CMD); + break; + } + + case WE_GET_PPS_EOF_PAD_DELIM: + { + hdd_notice("GET WMI_VDEV_PPS_EOF_PAD_DELIM"); + *value = wma_cli_get_command(pAdapter->sessionId, + WMI_VDEV_PPS_EOF_PAD_DELIM, + PPS_CMD); + break; + } + + case WE_GET_PPS_MACADDR_MISMATCH: + { + hdd_notice("GET WMI_VDEV_PPS_MACADDR_MISMATCH"); + *value = wma_cli_get_command(pAdapter->sessionId, + WMI_VDEV_PPS_MACADDR_MISMATCH, + PPS_CMD); + break; + } + + case WE_GET_PPS_DELIM_CRC_FAIL: + { + hdd_notice("GET WMI_VDEV_PPS_DELIM_CRC_FAIL"); + *value = wma_cli_get_command(pAdapter->sessionId, + WMI_VDEV_PPS_DELIM_CRC_FAIL, + PPS_CMD); + break; + } + + case WE_GET_PPS_GID_NSTS_ZERO: + { + hdd_notice("GET WMI_VDEV_PPS_GID_NSTS_ZERO"); + *value = wma_cli_get_command(pAdapter->sessionId, + WMI_VDEV_PPS_GID_NSTS_ZERO, + PPS_CMD); + break; + } + + case WE_GET_PPS_RSSI_CHECK: + { + + hdd_notice("GET WMI_VDEV_PPS_RSSI_CHECK"); + *value = wma_cli_get_command(pAdapter->sessionId, + WMI_VDEV_PPS_RSSI_CHECK, + PPS_CMD); + break; + } + + case WE_GET_QPOWER_MAX_PSPOLL_COUNT: + { + hdd_notice("WE_GET_QPOWER_MAX_PSPOLL_COUNT"); + *value = wma_cli_get_command(pAdapter->sessionId, + WMI_STA_PS_PARAM_QPOWER_PSPOLL_COUNT, + QPOWER_CMD); + break; + } + + case WE_GET_QPOWER_MAX_TX_BEFORE_WAKE: + { + hdd_notice("WE_GET_QPOWER_MAX_TX_BEFORE_WAKE"); + *value = wma_cli_get_command(pAdapter->sessionId, + WMI_STA_PS_PARAM_QPOWER_MAX_TX_BEFORE_WAKE, + QPOWER_CMD); + break; + } + + case WE_GET_QPOWER_SPEC_PSPOLL_WAKE_INTERVAL: + { + hdd_notice("WE_GET_QPOWER_SPEC_PSPOLL_WAKE_INTERVAL"); + *value = wma_cli_get_command(pAdapter->sessionId, + WMI_STA_PS_PARAM_QPOWER_SPEC_PSPOLL_WAKE_INTERVAL, + QPOWER_CMD); + break; + } + + case WE_GET_QPOWER_SPEC_MAX_SPEC_NODATA_PSPOLL: + { + hdd_notice("WE_GET_QPOWER_MAX_PSPOLL_COUNT"); + *value = wma_cli_get_command(pAdapter->sessionId, + WMI_STA_PS_PARAM_QPOWER_SPEC_MAX_SPEC_NODATA_PSPOLL, + QPOWER_CMD); + break; + } + case WE_CAP_TSF: + ret = hdd_capture_tsf(pAdapter, (uint32_t *)value, 1); + break; + case WE_GET_TEMPERATURE: + { + hdd_notice("WE_GET_TEMPERATURE"); + ret = wlan_hdd_get_temperature(pAdapter, value); + break; + } + default: + { + hdd_err("Invalid IOCTL get_value command %d", + value[0]); + break; + } + } + EXIT(); + return ret; +} + +static int iw_setnone_getint(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_setnone_getint(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +static int hdd_set_fwtest(int argc, int cmd, int value) +{ + struct set_fwtest_params *fw_test; + + /* check for max number of arguments */ + if (argc > (WMA_MAX_NUM_ARGS) || + argc != HDD_FWTEST_PARAMS) { + hdd_err("Too Many args %d", argc); + return -EINVAL; + } + /* + * check if number of arguments are 3 then, check + * then set the default value for sounding interval. + */ + if (HDD_FWTEST_PARAMS == argc) { + if (HDD_FWTEST_SU_PARAM_ID == cmd && 0 == value) + value = HDD_FWTEST_SU_DEFAULT_VALUE; + if (HDD_FWTEST_MU_PARAM_ID == cmd && 0 == value) + value = HDD_FWTEST_MU_DEFAULT_VALUE; + } + /* check sounding interval value should not exceed to max */ + if (value > HDD_FWTEST_MAX_VALUE) { + hdd_err("Invalid arguments value should not exceed max: %d", + value); + return -EINVAL; + } + fw_test = qdf_mem_malloc(sizeof(*fw_test)); + if (NULL == fw_test) { + hdd_err("qdf_mem_malloc failed for fw_test"); + return -ENOMEM; + } + fw_test->arg = cmd; + fw_test->value = value; + if (QDF_STATUS_SUCCESS != sme_set_fw_test(fw_test)) { + qdf_mem_free(fw_test); + hdd_err("Not able to post FW_TEST_CMD message to WMA"); + return -EINVAL; + } + return 0; +} + +/** + * iw_set_three_ints_getnone() - Generic "set 3 params" private ioctl handler + * @dev: device upon which the ioctl was received + * @info: ioctl request information + * @wrqu: ioctl request data + * @extra: ioctl extra data + * + * Return: 0 on success, non-zero on error + */ +static int __iw_set_three_ints_getnone(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + int *value = (int *)extra; + int sub_cmd = value[0]; + int ret; + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(pAdapter); + + ENTER_DEV(dev); + + if (!capable(CAP_NET_ADMIN)) { + hdd_err("permission check failed"); + return -EPERM; + } + + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + switch (sub_cmd) { + + case WE_SET_WLAN_DBG: + qdf_trace_set_value(value[1], value[2], value[3]); + break; + case WE_SET_DP_TRACE: + qdf_dp_trace_set_value(value[1], value[2], value[3]); + break; + + /* value[3] the acs band is not required as start and end channels are + * enough but this cmd is maintained under set three ints for historic + * reasons. + */ + case WE_SET_SAP_CHANNELS: + if (wlan_hdd_validate_operation_channel(pAdapter, value[1]) != + QDF_STATUS_SUCCESS || + wlan_hdd_validate_operation_channel(pAdapter, + value[2]) != QDF_STATUS_SUCCESS) { + ret = -EINVAL; + } else { + hdd_ctx->config->force_sap_acs_st_ch = value[1]; + hdd_ctx->config->force_sap_acs_end_ch = value[2]; + } + break; + case WE_SET_DUAL_MAC_SCAN_CONFIG: + hdd_debug("Ioctl to set dual mac scan config"); + if (hdd_ctx->config->dual_mac_feature_disable) { + hdd_err("Dual mac feature is disabled from INI"); + return -EPERM; + } + hdd_debug("%d %d %d", value[1], value[2], value[3]); + cds_set_dual_mac_scan_config(value[1], value[2], value[3]); + break; + case WE_SET_FW_TEST: + { + ret = hdd_set_fwtest(value[1], value[2], value[3]); + if (ret) { + hdd_err("Not able to set fwtest %d", ret); + return ret; + } + } + break; + default: + hdd_err("Invalid IOCTL command %d", sub_cmd); + break; + + } + EXIT(); + return ret; +} + +int iw_set_three_ints_getnone(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_set_three_ints_getnone(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * hdd_connection_state_string() - Get connection state string + * @connection_state: enum to be converted to a string + * + * Return: the string equivalent of @connection_state + */ +static const char * +hdd_connection_state_string(eConnectionState connection_state) +{ + switch (connection_state) { + CASE_RETURN_STRING(eConnectionState_NotConnected); + CASE_RETURN_STRING(eConnectionState_Connecting); + CASE_RETURN_STRING(eConnectionState_Associated); + CASE_RETURN_STRING(eConnectionState_IbssDisconnected); + CASE_RETURN_STRING(eConnectionState_IbssConnected); + CASE_RETURN_STRING(eConnectionState_Disconnecting); + default: + return "UNKNOWN"; + } +} + +/** + * iw_get_char_setnone() - Generic "get string" private ioctl handler + * @dev: device upon which the ioctl was received + * @info: ioctl request information + * @wrqu: ioctl request data + * @extra: ioctl extra data + * + * Return: 0 on success, non-zero on error + */ +static int __iw_get_char_setnone(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + int sub_cmd = wrqu->data.flags; + hdd_context_t *hdd_ctx; + int ret; +#ifdef WLAN_FEATURE_11W + hdd_wext_state_t *pWextState; +#endif + +#ifdef WLAN_FEATURE_11W + pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter); +#endif + + ENTER_DEV(dev); + + hdd_ctx = WLAN_HDD_GET_CTX(pAdapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + switch (sub_cmd) { + case WE_WLAN_VERSION: + { + hdd_wlan_get_version(hdd_ctx, wrqu, extra); + break; + } + + case WE_GET_STATS: + { + hdd_wlan_get_stats(pAdapter, &(wrqu->data.length), + extra, WE_MAX_STR_LEN); + break; + } + + case WE_GET_SUSPEND_RESUME_STATS: + { + ret = wlan_hdd_write_suspend_resume_stats(hdd_ctx, extra, + WE_MAX_STR_LEN); + if (ret >= 0) { + wrqu->data.length = ret; + ret = 0; + } + + break; + } + + case WE_LIST_FW_PROFILE: + hdd_wlan_list_fw_profile(&(wrqu->data.length), + extra, WE_MAX_STR_LEN); + break; + + /* The case prints the current state of the HDD, SME, CSR, PE, + * TL it can be extended for WDI Global State as well. And + * currently it only checks P2P_CLIENT adapter. P2P_DEVICE + * and P2P_GO have not been added as of now. + */ + case WE_GET_STATES: + { + int buf = 0, len = 0; + int adapter_num = 0; + int count = 0, check = 1; + + tHalHandle hHal = NULL; + tpAniSirGlobal pMac = NULL; + hdd_station_ctx_t *pHddStaCtx = NULL; + + hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + hdd_adapter_t *useAdapter = NULL; + + /* Print wlan0 or p2p0 states based on the adapter_num + * by using the correct adapter + */ + while (adapter_num < 2) { + if (WLAN_ADAPTER == adapter_num) { + useAdapter = pAdapter; + buf = + scnprintf(extra + len, + WE_MAX_STR_LEN - len, + "\n\n wlan0 States:-"); + len += buf; + } else if (P2P_ADAPTER == adapter_num) { + buf = + scnprintf(extra + len, + WE_MAX_STR_LEN - len, + "\n\n p2p0 States:-"); + len += buf; + + if (!pHddCtx) { + buf = + scnprintf(extra + len, + WE_MAX_STR_LEN - + len, + "\n pHddCtx is NULL"); + len += buf; + break; + } + + /* Printing p2p0 states only in the + * case when the device is configured + * as a p2p_client + */ + useAdapter = + hdd_get_adapter(pHddCtx, + QDF_P2P_CLIENT_MODE); + if (!useAdapter) { + buf = + scnprintf(extra + len, + WE_MAX_STR_LEN - + len, + "\n Device not configured as P2P_CLIENT."); + len += buf; + break; + } + } + + hHal = WLAN_HDD_GET_HAL_CTX(useAdapter); + if (!hHal) { + buf = + scnprintf(extra + len, + WE_MAX_STR_LEN - len, + "\n pMac is NULL"); + len += buf; + break; + } + pMac = PMAC_STRUCT(hHal); + if (!pMac) { + buf = + scnprintf(extra + len, + WE_MAX_STR_LEN - len, + "\n pMac is NULL"); + len += buf; + break; + } + pHddStaCtx = + WLAN_HDD_GET_STATION_CTX_PTR(useAdapter); + + + buf = + scnprintf(extra + len, WE_MAX_STR_LEN - len, + "\n HDD Conn State - %s " + "\n \n SME State:" + "\n Neighbour Roam State - %s" + "\n CSR State - %s" + "\n CSR Substate - %s", + hdd_connection_state_string + (pHddStaCtx->conn_info.connState), + mac_trace_get_neighbour_roam_state + (sme_get_neighbor_roam_state + (hHal, useAdapter->sessionId)), + mac_trace_getcsr_roam_state + (sme_get_current_roam_state + (hHal, useAdapter->sessionId)), + mac_trace_getcsr_roam_sub_state + (sme_get_current_roam_sub_state + (hHal, useAdapter->sessionId)) + ); + len += buf; + adapter_num++; + } + + if (hHal) { + /* Printing Lim State starting with global lim states */ + buf = + scnprintf(extra + len, WE_MAX_STR_LEN - len, + "\n \n LIM STATES:-" + "\n Global Sme State - %s " + "\n Global mlm State - %s " "\n", + mac_trace_get_lim_sme_state + (sme_get_lim_sme_state(hHal)), + mac_trace_get_lim_mlm_state + (sme_get_lim_sme_state(hHal)) + ); + len += buf; + + /* Printing the PE Sme and Mlm states for valid lim sessions */ + while (check < 3 && count < 255) { + if (sme_is_lim_session_valid(hHal, count)) { + buf = + scnprintf(extra + len, + WE_MAX_STR_LEN - + len, + "\n Lim Valid Session %d:-" + "\n PE Sme State - %s " + "\n PE Mlm State - %s " + "\n", check, + mac_trace_get_lim_sme_state + (sme_get_lim_sme_session_state + (hHal, count)), + mac_trace_get_lim_mlm_state + (sme_get_lim_mlm_session_state + (hHal, count)) + ); + + len += buf; + check++; + } + count++; + } + } + + wrqu->data.length = strlen(extra) + 1; + break; + } + + case WE_GET_CFG: + { + hdd_notice("Printing CLD global INI Config"); + hdd_cfg_get_global_config(WLAN_HDD_GET_CTX(pAdapter), + extra, + QCSAP_IOCTL_MAX_STR_LEN); + wrqu->data.length = strlen(extra) + 1; + break; + } + case WE_GET_RSSI: + { + int8_t s7Rssi = 0; + wlan_hdd_get_rssi(pAdapter, &s7Rssi); + snprintf(extra, WE_MAX_STR_LEN, "rssi=%d", s7Rssi); + wrqu->data.length = strlen(extra) + 1; + break; + } + + case WE_GET_WMM_STATUS: + { + snprintf(extra, WE_MAX_STR_LEN, + "\nDir: 0=up, 1=down, 3=both\n" + "|------------------------|\n" + "|AC | ACM |Admitted| Dir |\n" + "|------------------------|\n" + "|VO | %d | %3s | %d |\n" + "|VI | %d | %3s | %d |\n" + "|BE | %d | %3s | %d |\n" + "|BK | %d | %3s | %d |\n" + "|------------------------|\n", + pAdapter->hddWmmStatus. + wmmAcStatus[SME_AC_VO].wmmAcAccessRequired, + pAdapter->hddWmmStatus. + wmmAcStatus[SME_AC_VO]. + wmmAcAccessAllowed ? "YES" : "NO", + pAdapter->hddWmmStatus. + wmmAcStatus[SME_AC_VO].wmmAcTspecInfo. + ts_info.direction, + pAdapter->hddWmmStatus. + wmmAcStatus[SME_AC_VI].wmmAcAccessRequired, + pAdapter->hddWmmStatus. + wmmAcStatus[SME_AC_VI]. + wmmAcAccessAllowed ? "YES" : "NO", + pAdapter->hddWmmStatus. + wmmAcStatus[SME_AC_VI].wmmAcTspecInfo. + ts_info.direction, + pAdapter->hddWmmStatus. + wmmAcStatus[SME_AC_BE].wmmAcAccessRequired, + pAdapter->hddWmmStatus. + wmmAcStatus[SME_AC_BE]. + wmmAcAccessAllowed ? "YES" : "NO", + pAdapter->hddWmmStatus. + wmmAcStatus[SME_AC_BE].wmmAcTspecInfo. + ts_info.direction, + pAdapter->hddWmmStatus. + wmmAcStatus[SME_AC_BK].wmmAcAccessRequired, + pAdapter->hddWmmStatus. + wmmAcStatus[SME_AC_BK]. + wmmAcAccessAllowed ? "YES" : "NO", + pAdapter->hddWmmStatus. + wmmAcStatus[SME_AC_BK].wmmAcTspecInfo. + ts_info.direction); + + wrqu->data.length = strlen(extra) + 1; + break; + } + case WE_GET_CHANNEL_LIST: + { + QDF_STATUS status; + uint8_t i, len; + char *buf; + uint8_t ubuf[WNI_CFG_COUNTRY_CODE_LEN]; + uint8_t ubuf_len = WNI_CFG_COUNTRY_CODE_LEN; + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(pAdapter); + + tChannelListInfo channel_list; + + memset(&channel_list, 0, sizeof(channel_list)); + status = iw_get_channel_list(dev, info, wrqu, + (char *)&channel_list); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("GetChannelList Failed!!!"); + return -EINVAL; + } + buf = extra; + /* + * Maximum channels = WNI_CFG_VALID_CHANNEL_LIST_LEN. + * Maximum buffer needed = 5 * number of channels. + * Check ifsufficient buffer is available and then + * proceed to fill the buffer. + */ + if (WE_MAX_STR_LEN < + (5 * WNI_CFG_VALID_CHANNEL_LIST_LEN)) { + hdd_err("Insufficient Buffer to populate channel list"); + return -EINVAL; + } + len = scnprintf(buf, WE_MAX_STR_LEN, "%u ", + channel_list.num_channels); + if (QDF_STATUS_SUCCESS == sme_get_country_code(hdd_ctx->hHal, + ubuf, &ubuf_len)) { + /* Printing Country code in getChannelList */ + for (i = 0; i < (ubuf_len - 1); i++) + len += scnprintf(buf + len, + WE_MAX_STR_LEN - len, + "%c", ubuf[i]); + } + for (i = 0; i < channel_list.num_channels; i++) { + len += + scnprintf(buf + len, WE_MAX_STR_LEN - len, + " %u", channel_list.channels[i]); + } + wrqu->data.length = strlen(extra) + 1; + + break; + } +#ifdef FEATURE_WLAN_TDLS + case WE_GET_TDLS_PEERS: + { + wrqu->data.length = + wlan_hdd_tdls_get_all_peers(pAdapter, extra, + WE_MAX_STR_LEN) + 1; + break; + } +#endif +#ifdef WLAN_FEATURE_11W + case WE_GET_11W_INFO: + { + hdd_notice("WE_GET_11W_ENABLED = %d", + pWextState->roamProfile.MFPEnabled); + + snprintf(extra, WE_MAX_STR_LEN, + "\n BSSID %02X:%02X:%02X:%02X:%02X:%02X, Is PMF Assoc? %d" + "\n Number of Unprotected Disassocs %d" + "\n Number of Unprotected Deauths %d", + pWextState->roamProfile.BSSIDs.bssid->bytes[0], + pWextState->roamProfile.BSSIDs.bssid->bytes[1], + pWextState->roamProfile.BSSIDs.bssid->bytes[2], + pWextState->roamProfile.BSSIDs.bssid->bytes[3], + pWextState->roamProfile.BSSIDs.bssid->bytes[4], + pWextState->roamProfile.BSSIDs.bssid->bytes[5], + pWextState->roamProfile.MFPEnabled, + pAdapter->hdd_stats.hddPmfStats. + numUnprotDisassocRx, + pAdapter->hdd_stats.hddPmfStats. + numUnprotDeauthRx); + + wrqu->data.length = strlen(extra) + 1; + break; + } +#endif + case WE_GET_IBSS_STA_INFO: + { + hdd_station_ctx_t *pHddStaCtx = + WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + int idx = 0; + int length = 0, buf = 0; + + for (idx = 0; idx < MAX_PEERS; idx++) { + if (0 != pHddStaCtx->conn_info.staId[idx]) { + buf = snprintf + ((extra + length), + WE_MAX_STR_LEN - length, + "\n%d .%02x:%02x:%02x:%02x:%02x:%02x\n", + pHddStaCtx->conn_info.staId[idx], + pHddStaCtx->conn_info. + peerMacAddress[idx].bytes[0], + pHddStaCtx->conn_info. + peerMacAddress[idx].bytes[1], + pHddStaCtx->conn_info. + peerMacAddress[idx].bytes[2], + pHddStaCtx->conn_info. + peerMacAddress[idx].bytes[3], + pHddStaCtx->conn_info. + peerMacAddress[idx].bytes[4], + pHddStaCtx->conn_info. + peerMacAddress[idx].bytes[5] + ); + length += buf; + } + } + wrqu->data.length = strlen(extra) + 1; + break; + } + case WE_GET_PHYMODE: + { + bool ch_bond24 = false, ch_bond5g = false; + hdd_context_t *hddctx = WLAN_HDD_GET_CTX(pAdapter); + tHalHandle hal = WLAN_HDD_GET_HAL_CTX(pAdapter); + eCsrPhyMode phymode; + eCsrBand currBand; + tSmeConfigParams *sme_config; + + sme_config = qdf_mem_malloc(sizeof(*sme_config)); + if (!sme_config) { + hdd_err("Out of memory"); + ret = -ENOMEM; + break; + } + + sme_get_config_param(hal, sme_config); + if (WNI_CFG_CHANNEL_BONDING_MODE_DISABLE != + sme_config->csrConfig.channelBondingMode24GHz) + ch_bond24 = true; + + if (WNI_CFG_CHANNEL_BONDING_MODE_DISABLE != + sme_config->csrConfig.channelBondingMode5GHz) + ch_bond5g = true; + + qdf_mem_free(sme_config); + + phymode = sme_get_phy_mode(hal); + if ((QDF_STATUS_SUCCESS != + sme_get_freq_band(hal, &currBand))) { + hdd_notice("Failed to get current band config"); + return -EIO; + } + + switch (phymode) { + case eCSR_DOT11_MODE_AUTO: + snprintf(extra, WE_MAX_STR_LEN, "AUTO MODE"); + break; + case eCSR_DOT11_MODE_11n: + case eCSR_DOT11_MODE_11n_ONLY: + if (currBand == eCSR_BAND_24) { + if (ch_bond24) + snprintf(extra, WE_MAX_STR_LEN, + "11NGHT40"); + else + snprintf(extra, WE_MAX_STR_LEN, + "11NGHT20"); + } else if (currBand == eCSR_BAND_5G) { + if (ch_bond5g) + snprintf(extra, WE_MAX_STR_LEN, + "11NAHT40"); + else + snprintf(extra, WE_MAX_STR_LEN, + "11NAHT20"); + } else { + snprintf(extra, WE_MAX_STR_LEN, "11N"); + } + break; + case eCSR_DOT11_MODE_abg: + snprintf(extra, WE_MAX_STR_LEN, "11ABG"); + break; + case eCSR_DOT11_MODE_11a: + snprintf(extra, WE_MAX_STR_LEN, "11A"); + break; + case eCSR_DOT11_MODE_11b: + case eCSR_DOT11_MODE_11b_ONLY: + snprintf(extra, WE_MAX_STR_LEN, "11B"); + break; + case eCSR_DOT11_MODE_11g: + case eCSR_DOT11_MODE_11g_ONLY: + snprintf(extra, WE_MAX_STR_LEN, "11G"); + break; + case eCSR_DOT11_MODE_11ac: + case eCSR_DOT11_MODE_11ac_ONLY: + if (hddctx->config->vhtChannelWidth == + eHT_CHANNEL_WIDTH_20MHZ) + snprintf(extra, WE_MAX_STR_LEN, + "11ACVHT20"); + else if (hddctx->config->vhtChannelWidth == + eHT_CHANNEL_WIDTH_40MHZ) + snprintf(extra, WE_MAX_STR_LEN, + "11ACVHT40"); + else if (hddctx->config->vhtChannelWidth == + eHT_CHANNEL_WIDTH_80MHZ) + snprintf(extra, WE_MAX_STR_LEN, + "11ACVHT80"); + else if (hddctx->config->vhtChannelWidth == + eHT_CHANNEL_WIDTH_160MHZ) + snprintf(extra, WE_MAX_STR_LEN, + "11ACVHT160"); + break; + } + + wrqu->data.length = strlen(extra) + 1; + break; + } + +#ifdef FEATURE_OEM_DATA_SUPPORT + case WE_GET_OEM_DATA_CAP: + { + return iw_get_oem_data_cap(dev, info, wrqu, extra); + } +#endif /* FEATURE_OEM_DATA_SUPPORT */ + case WE_GET_SNR: + { + int8_t s7snr = 0; + int status = 0; + hdd_context_t *pHddCtx; + hdd_station_ctx_t *pHddStaCtx; + pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + status = wlan_hdd_validate_context(pHddCtx); + if (status) + return status; + + pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + if (0 == pHddCtx->config->fEnableSNRMonitoring || + eConnectionState_Associated != + pHddStaCtx->conn_info.connState) { + hdd_err("getSNR failed: Enable SNR Monitoring-%d, ConnectionState-%d", + pHddCtx->config->fEnableSNRMonitoring, + pHddStaCtx->conn_info.connState); + return -ENONET; + } + wlan_hdd_get_snr(pAdapter, &s7snr); + snprintf(extra, WE_MAX_STR_LEN, "snr=%d", s7snr); + wrqu->data.length = strlen(extra) + 1; + break; + } + default: + { + hdd_err("Invalid IOCTL command %d", + sub_cmd); + break; + } + } + + EXIT(); + return ret; +} + +static int iw_get_char_setnone(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_get_char_setnone(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * iw_setnone_getnone() - Generic "action" private ioctl handler + * @dev: device upon which the ioctl was received + * @info: ioctl request information + * @wrqu: ioctl request data + * @extra: ioctl extra data + * + * Return: 0 on success, non-zero on error + */ +static int __iw_setnone_getnone(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *hdd_ctx; + int ret; + int sub_cmd; + + ENTER_DEV(dev); + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + +#ifdef CONFIG_COMPAT + /* this ioctl is a special case where a sub-ioctl is used and both + * the number of get and set args is 0. in this specific case the + * logic in iwpriv places the sub_cmd in the data.flags portion of + * the iwreq. unfortunately the location of this field will be + * different between 32-bit and 64-bit userspace, and the standard + * compat support in the kernel does not handle this case. so we + * need to explicitly handle it here. + */ + if (is_compat_task()) { + struct compat_iw_point *compat_iw_point = + (struct compat_iw_point *)&wrqu->data; + sub_cmd = compat_iw_point->flags; + } else { + sub_cmd = wrqu->data.flags; + } +#else + sub_cmd = wrqu->data.flags; +#endif + + switch (sub_cmd) { + case WE_GET_RECOVERY_STAT: + { + tHalHandle hal = WLAN_HDD_GET_HAL_CTX(adapter); + sme_get_recovery_stats(hal); + break; + } + + case WE_GET_FW_PROFILE_DATA: + ret = wma_cli_set_command(adapter->sessionId, + WMI_WLAN_PROFILE_GET_PROFILE_DATA_CMDID, + 0, DBG_CMD); + break; + + case WE_IBSS_GET_PEER_INFO_ALL: + { + hdd_wlan_get_ibss_peer_info_all(adapter); + break; + } + + case WE_SET_REASSOC_TRIGGER: + { + hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(adapter); + tSirMacAddr bssid; + uint32_t roamId = 0; + uint8_t operating_ch = + adapter->sessionCtx.station.conn_info.operationChannel; + tCsrRoamModifyProfileFields modProfileFields; + + sme_get_modify_profile_fields(hHal, adapter->sessionId, + &modProfileFields); + if (roaming_offload_enabled(hdd_ctx)) { + qdf_mem_copy(bssid, + &adapter->sessionCtx.station.conn_info.bssId, + sizeof(bssid)); + hdd_wma_send_fastreassoc_cmd(adapter, + bssid, operating_ch); + } else { + sme_roam_reassoc(hdd_ctx->hHal, adapter->sessionId, + NULL, modProfileFields, &roamId, 1); + } + return 0; + } + + case WE_STOP_OBSS_SCAN: + { + /* + * 1.OBSS Scan is mandatory while operating in 2.4GHz + * 2.OBSS scan is stopped by Firmware during the disassociation + * 3.OBSS stop comamnd is added for debugging purpose + */ + tHalHandle hal; + + hal = WLAN_HDD_GET_HAL_CTX(adapter); + if (hal == NULL) { + hdd_err("hal context is NULL"); + return -EINVAL; + } + sme_ht40_stop_obss_scan(hal, adapter->sessionId); + } + break; + default: + { + hdd_err("unknown ioctl %d", sub_cmd); + break; + } + } + EXIT(); + return ret; +} + +static int iw_setnone_getnone(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_setnone_getnone(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +#ifdef MPC_UT_FRAMEWORK +static int iw_get_policy_manager_ut_ops(hdd_context_t *hdd_ctx, + hdd_adapter_t *adapter, int sub_cmd, int *apps_args) +{ + switch(sub_cmd) { + case WE_POLICY_MANAGER_CLIST_CMD: + { + hdd_notice(" is called"); + cds_incr_connection_count_utfw(apps_args[0], + apps_args[1], apps_args[2], apps_args[3], + apps_args[4], apps_args[5], apps_args[6], + apps_args[7]); + } + break; + + case WE_POLICY_MANAGER_DLIST_CMD: + { + hdd_notice(" is called"); + cds_decr_connection_count_utfw(apps_args[0], + apps_args[1]); + } + break; + + case WE_POLICY_MANAGER_ULIST_CMD: + { + hdd_notice(" is called"); + cds_update_connection_info_utfw(apps_args[0], + apps_args[1], apps_args[2], apps_args[3], + apps_args[4], apps_args[5], apps_args[6], + apps_args[7]); + } + break; + + case WE_POLICY_MANAGER_DBS_CMD: + { + hdd_notice(" is called"); + if (apps_args[0] == 0) + wma_set_dbs_capability_ut(0); + else + wma_set_dbs_capability_ut(1); + + if (apps_args[1] >= CDS_THROUGHPUT && + apps_args[1] <= CDS_LATENCY) { + pr_info("setting system pref to [%d]\n", apps_args[1]); + hdd_ctx->config->conc_system_pref = apps_args[1]; + } + } + break; + + case WE_POLICY_MANAGER_PCL_CMD: + { + uint8_t pcl[QDF_MAX_NUM_CHAN] = {0}; + uint8_t weight_list[QDF_MAX_NUM_CHAN] = {0}; + uint32_t pcl_len = 0, i = 0; + + hdd_notice(" is called"); + + cds_get_pcl(apps_args[0], + pcl, &pcl_len, + weight_list, QDF_ARRAY_SIZE(weight_list)); + pr_info("PCL list for role[%d] is {", apps_args[0]); + for (i = 0 ; i < pcl_len; i++) + pr_info(" %d, ", pcl[i]); + pr_info("}--------->\n"); + } + break; + + case WE_POLICY_SET_HW_MODE_CMD: + { + if (apps_args[0] == 0) { + hdd_err("set hw mode for single mac"); + cds_pdev_set_hw_mode( + adapter->sessionId, + HW_MODE_SS_2x2, + HW_MODE_80_MHZ, + HW_MODE_SS_0x0, HW_MODE_BW_NONE, + HW_MODE_DBS_NONE, + HW_MODE_AGILE_DFS_NONE, + HW_MODE_SBS_NONE, + SIR_UPDATE_REASON_UT); + } else if (apps_args[0] == 1) { + hdd_err("set hw mode for dual mac"); + cds_pdev_set_hw_mode( + adapter->sessionId, + HW_MODE_SS_1x1, + HW_MODE_80_MHZ, + HW_MODE_SS_1x1, HW_MODE_40_MHZ, + HW_MODE_DBS, + HW_MODE_AGILE_DFS_NONE, + HW_MODE_SBS_NONE, + SIR_UPDATE_REASON_UT); + } + } + break; + + case WE_POLICY_MANAGER_QUERY_ACTION_CMD: + { + enum cds_conc_next_action action; + hdd_notice(" is called"); + action = cds_current_connections_update(adapter->sessionId, + apps_args[0], + SIR_UPDATE_REASON_UT); + pr_info("next action is %d {HDD_NOP = 0, HDD_DBS, HDD_DBS_DOWNGRADE, HDD_MCC, HDD_MCC_UPGRADE}", action); + } + break; + + case WE_POLICY_MANAGER_QUERY_ALLOW_CMD: + { + bool allow; + hdd_notice(" is called"); + allow = cds_allow_concurrency( + apps_args[0], apps_args[1], apps_args[2]); + pr_info("allow %d {0 = don't allow, 1 = allow}", allow); + } + break; + + case WE_POLICY_MANAGER_SCENARIO_CMD: + { + clean_report(hdd_ctx); + if (apps_args[0] == 1) { + wlan_hdd_one_connection_scenario(hdd_ctx); + } else if (apps_args[0] == 2) { + wlan_hdd_two_connections_scenario(hdd_ctx, + 6, CDS_TWO_TWO); + wlan_hdd_two_connections_scenario(hdd_ctx, + 36, CDS_TWO_TWO); + wlan_hdd_two_connections_scenario(hdd_ctx, + 6, CDS_ONE_ONE); + wlan_hdd_two_connections_scenario(hdd_ctx, + 36, CDS_ONE_ONE); + } else if (apps_args[0] == 3) { + /* MCC on same band with 2x2 same mac*/ + wlan_hdd_three_connections_scenario(hdd_ctx, + 6, 11, CDS_TWO_TWO, 0); + /* MCC on diff band with 2x2 same mac*/ + wlan_hdd_three_connections_scenario(hdd_ctx, + 6, 36, CDS_TWO_TWO, 0); + /* MCC on diff band with 1x1 diff mac */ + wlan_hdd_three_connections_scenario(hdd_ctx, + 36, 6, CDS_ONE_ONE, 0); + /* MCC on diff band with 1x1 same mac */ + wlan_hdd_three_connections_scenario(hdd_ctx, + 36, 6, CDS_ONE_ONE, 1); + /* SCC on same band with 2x2 same mac */ + wlan_hdd_three_connections_scenario(hdd_ctx, + 36, 36, CDS_TWO_TWO, 0); + /* SCC on same band with 1x1 same mac */ + wlan_hdd_three_connections_scenario(hdd_ctx, + 36, 36, CDS_ONE_ONE, 1); + /* MCC on same band with 2x2 same mac */ + wlan_hdd_three_connections_scenario(hdd_ctx, + 36, 149, CDS_TWO_TWO, 0); + /* MCC on same band with 1x1 same mac */ + wlan_hdd_three_connections_scenario(hdd_ctx, + 36, 149, CDS_ONE_ONE, 1); + } + print_report(hdd_ctx); + } + break; + } + return 0; +} +#else +static int iw_get_policy_manager_ut_ops(hdd_context_t *hdd_ctx, + hdd_adapter_t *adapter, int sub_cmd, int *apps_args) +{ + return 0; +} +#endif + +/** + * __iw_set_var_ints_getnone - Generic "set many" private ioctl handler + * @dev: device upon which the ioctl was received + * @info: ioctl request information + * @wrqu: ioctl request data + * @extra: ioctl extra data + * + * This is an SSR-protected generic handler for private ioctls which + * take multiple arguments. Note that this implementation is also + * somewhat unique in that it is shared by both STA-mode and SAP-mode + * interfaces. + * + * Return: 0 on success, non-zero on error + */ +static int __iw_set_var_ints_getnone(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter); + int sub_cmd; + int *apps_args = (int *) extra; + hdd_context_t *hdd_ctx; + int ret, num_args; + + ENTER_DEV(dev); + + hdd_ctx = WLAN_HDD_GET_CTX(pAdapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + if (extra == NULL) { + hdd_err("NULL extra buffer pointer"); + return -EINVAL; + } + + sub_cmd = wrqu->data.flags; + num_args = wrqu->data.length; + + hdd_notice("Received length %d", wrqu->data.length); + + switch (sub_cmd) { + case WE_IBSS_GET_PEER_INFO: + { + pr_info("Station ID = %d\n", apps_args[0]); + hdd_wlan_get_ibss_peer_info(pAdapter, apps_args[0]); + } + break; + + case WE_P2P_NOA_CMD: + { + p2p_app_setP2pPs_t p2pNoA; + + if (pAdapter->device_mode != QDF_P2P_GO_MODE) { + hdd_err("Setting NoA is not allowed in Device mode %s(%d)", + hdd_device_mode_to_string( + pAdapter->device_mode), + pAdapter->device_mode); + return -EINVAL; + } + + p2pNoA.opp_ps = apps_args[0]; + p2pNoA.ctWindow = apps_args[1]; + p2pNoA.duration = apps_args[2]; + p2pNoA.interval = apps_args[3]; + p2pNoA.count = apps_args[4]; + p2pNoA.single_noa_duration = apps_args[5]; + p2pNoA.psSelection = apps_args[6]; + + hdd_notice("P2P_NOA_ATTR:oppPS %d ctWindow %d duration %d interval %d count %d single noa duration %d PsSelection %x", + apps_args[0], apps_args[1], apps_args[2], + apps_args[3], apps_args[4], + apps_args[5], apps_args[6]); + + hdd_set_p2p_ps(dev, &p2pNoA); + + } + break; + + case WE_MTRACE_SELECTIVE_MODULE_LOG_ENABLE_CMD: + { + hdd_notice("SELECTIVE_MODULE_LOG %d arg1 %d arg2", + apps_args[0], apps_args[1]); + qdf_trace_enable(apps_args[0], apps_args[1]); + } + break; + + case WE_MTRACE_DUMP_CMD: + { + hdd_notice("MTRACE_DUMP code %d session %d count %d bitmask_of_module %d ", + apps_args[0], apps_args[1], + apps_args[2], apps_args[3]); + qdf_trace_dump_all((void *)hHal, apps_args[0], + apps_args[1], apps_args[2], + apps_args[3]); + + } + break; + + case WE_POLICY_MANAGER_CINFO_CMD: + { + struct cds_conc_connection_info *conn_info; + uint32_t i = 0, len = 0; + + hdd_info(" is called"); + conn_info = cds_get_conn_info(&len); + pr_info("+--------------------------+\n"); + for (i = 0; i < len; i++) { + pr_info("|table_index[%d]\t\t\n", i); + pr_info("|\t|vdev_id - %-10d|\n", conn_info->vdev_id); + pr_info("|\t|chan - %-10d|\n", conn_info->chan); + pr_info("|\t|bw - %-10d|\n", conn_info->bw); + pr_info("|\t|mode - %-10d|\n", conn_info->mode); + pr_info("|\t|mac - %-10d|\n", conn_info->mac); + pr_info("|\t|in_use - %-10d|\n", conn_info->in_use); + pr_info("+--------------------------+\n"); + conn_info++; + } + } + break; + + +#ifdef FEATURE_WLAN_TDLS + case WE_TDLS_CONFIG_PARAMS: + { + tdls_config_params_t tdlsParams; + + tdlsParams.tdls = apps_args[0]; + tdlsParams.tx_period_t = apps_args[1]; + tdlsParams.tx_packet_n = apps_args[2]; + /* ignore args[3] as discovery_period is not used anymore */ + tdlsParams.discovery_tries_n = apps_args[4]; + /* ignore args[5] as idle_timeout is not used anymore */ + tdlsParams.idle_packet_n = apps_args[6]; + /* ignore args[7] as rssi_hysteresis is not used anymore */ + tdlsParams.rssi_trigger_threshold = apps_args[8]; + tdlsParams.rssi_teardown_threshold = apps_args[9]; + tdlsParams.rssi_delta = apps_args[10]; + + wlan_hdd_tdls_set_params(dev, &tdlsParams); + } + break; +#endif + case WE_UNIT_TEST_CMD: + { + t_wma_unit_test_cmd *unitTestArgs; + cds_msg_t msg = { 0 }; + int i, j; + if ((apps_args[0] < WLAN_MODULE_ID_MIN) || + (apps_args[0] >= WLAN_MODULE_ID_MAX)) { + hdd_err("Invalid MODULE ID %d", + apps_args[0]); + return -EINVAL; + } + if ((apps_args[1] > (WMA_MAX_NUM_ARGS)) || + (apps_args[1] < 0)) { + hdd_err("Too Many/Few args %d", + apps_args[1]); + return -EINVAL; + } + unitTestArgs = qdf_mem_malloc(sizeof(*unitTestArgs)); + if (NULL == unitTestArgs) { + hdd_err("qdf_mem_malloc failed for unitTestArgs"); + return -ENOMEM; + } + unitTestArgs->vdev_id = (int)pAdapter->sessionId; + unitTestArgs->module_id = apps_args[0]; + unitTestArgs->num_args = apps_args[1]; + for (i = 0, j = 2; i < unitTestArgs->num_args; i++, j++) { + unitTestArgs->args[i] = apps_args[j]; + } + msg.type = SIR_HAL_UNIT_TEST_CMD; + msg.reserved = 0; + msg.bodyptr = unitTestArgs; + if (QDF_STATUS_SUCCESS != + cds_mq_post_message(QDF_MODULE_ID_WMA, &msg)) { + qdf_mem_free(unitTestArgs); + hdd_err("Not able to post UNIT_TEST_CMD message to WMA"); + return -EINVAL; + } + } + break; +#ifdef WLAN_FEATURE_GPIO_LED_FLASHING + case WE_LED_FLASHING_PARAM: + { + int i; + if (num_args != 4) { + hdd_err("gpio_control: 4 parameters are required"); + return -EINVAL; + } + for (i = 0; i < num_args; i++) { + if (apps_args[i] >= 0x7fffffff) { + hdd_err("gpio_control: parameter should be less than 0x7fffffff"); + return -EINVAL; + } + } + sme_set_led_flashing(WLAN_HDD_GET_HAL_CTX(pAdapter), + 0, apps_args[0], apps_args[1]); + sme_set_led_flashing(WLAN_HDD_GET_HAL_CTX(pAdapter), + 1, apps_args[2], apps_args[3]); + } + break; +#endif + case WE_SET_PKTLOG: + { + int ret; + + if (num_args < 1 || num_args > 2) { + hdd_err("pktlog: either 1 or 2 parameters are required"); + return -EINVAL; + } + + ret = hdd_process_pktlog_command(hdd_ctx, apps_args[0], + apps_args[1]); + if (ret) + return ret; + break; + } + + case WE_MAC_PWR_DEBUG_CMD: + { + struct sir_mac_pwr_dbg_cmd mac_pwr_dbg_args; + tHalHandle hal = WLAN_HDD_GET_HAL_CTX(pAdapter); + int i, j; + + if (num_args < 3) { + hdd_err("number of arguments can't be null %d", + num_args); + return -EINVAL; + } + if (num_args - 3 != apps_args[2]) { + hdd_err("arg list of size %d doesn't match num_args %d", + num_args-3, apps_args[2]); + return -EINVAL; + } + if ((apps_args[1] < WLAN_MODULE_ID_MIN) || + (apps_args[1] >= WLAN_MODULE_ID_MAX)) { + hdd_err("Invalid MODULE ID %d", apps_args[1]); + return -EINVAL; + } + if (apps_args[2] > (MAX_POWER_DBG_ARGS_SUPPORTED)) { + hdd_err("Too Many args %d", apps_args[2]); + return -EINVAL; + } + mac_pwr_dbg_args.pdev_id = apps_args[0]; + mac_pwr_dbg_args.module_id = apps_args[1]; + mac_pwr_dbg_args.num_args = apps_args[2]; + + for (i = 0, j = 3; i < mac_pwr_dbg_args.num_args; i++, j++) + mac_pwr_dbg_args.args[i] = apps_args[j]; + + if (QDF_STATUS_SUCCESS != + sme_process_mac_pwr_dbg_cmd(hal, pAdapter->sessionId, + &mac_pwr_dbg_args)) { + return -EINVAL; + } + } + break; + case WE_POLICY_MANAGER_CLIST_CMD: + case WE_POLICY_MANAGER_DLIST_CMD: + case WE_POLICY_MANAGER_ULIST_CMD: + case WE_POLICY_MANAGER_DBS_CMD: + case WE_POLICY_MANAGER_PCL_CMD: + case WE_POLICY_SET_HW_MODE_CMD: + case WE_POLICY_MANAGER_QUERY_ACTION_CMD: + case WE_POLICY_MANAGER_QUERY_ALLOW_CMD: + case WE_POLICY_MANAGER_SCENARIO_CMD: + { + iw_get_policy_manager_ut_ops(hdd_ctx, pAdapter, + sub_cmd, apps_args); + } + break; + default: + { + hdd_err("Invalid IOCTL command %d", sub_cmd); + } + break; + } + EXIT(); + return 0; +} + +/** + * iw_hdd_set_var_ints_getnone() - set var ints getnone callback + * @dev: pointer to net_device structure + * @info: pointer to iw_request_info structure + * @wrqu: pointer to iwreq_data + * @extra; extra + * + * Return: 0 on success, error number otherwise + * + */ +static int iw_hdd_set_var_ints_getnone(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + union iwreq_data u_priv_wrqu; + int apps_args[MAX_VAR_ARGS] = {0}; + int ret, num_args; + + if (!capable(CAP_NET_ADMIN)) { + hdd_err("permission check failed"); + return -EPERM; + } + + /* Helper function to get iwreq_data with compat handling. */ + if (hdd_priv_get_data(&u_priv_wrqu.data, wrqu)) + return -EINVAL; + + if (NULL == u_priv_wrqu.data.pointer) { + hdd_err("NULL data pointer"); + return -EINVAL; + } + + num_args = u_priv_wrqu.data.length; + if (num_args > MAX_VAR_ARGS) + num_args = MAX_VAR_ARGS; + + if (copy_from_user(apps_args, u_priv_wrqu.data.pointer, + (sizeof(int)) * num_args)) { + hdd_err("failed to copy data from user buffer"); + return -EFAULT; + } + + cds_ssr_protect(__func__); + ret = __iw_set_var_ints_getnone(dev, info, &u_priv_wrqu, + (char *)&apps_args); + cds_ssr_unprotect(__func__); + return ret; +} + +/** + * iw_set_var_ints_getnone - Generic "set many" private ioctl handler + * @dev: device upon which the ioctl was received + * @info: ioctl request information + * @wrqu: ioctl request data + * @extra: ioctl extra data + * + * This is a generic handler for private ioctls which take multiple + * arguments. Note that this implementation is also somewhat unique + * in that it is shared by both STA-mode and SAP-mode interfaces. + * + * Return: 0 on success, non-zero on error + */ +int iw_set_var_ints_getnone(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_set_var_ints_getnone(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + return ret; +} + +/** + * iw_add_tspec - Add TSpec private ioctl handler + * @dev: device upon which the ioctl was received + * @info: ioctl request information + * @wrqu: ioctl request data + * @extra: ioctl extra data + * + * Return: 0 on success, non-zero on error + */ +static int __iw_add_tspec(struct net_device *dev, struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + hdd_wlan_wmm_status_e *pStatus = (hdd_wlan_wmm_status_e *) extra; + int params[HDD_WLAN_WMM_PARAM_COUNT]; + sme_QosWmmTspecInfo tSpec; + uint32_t handle; + struct iw_point s_priv_data; + hdd_context_t *hdd_ctx; + int ret; + + ENTER_DEV(dev); + + hdd_ctx = WLAN_HDD_GET_CTX(pAdapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + /* make sure the application is sufficiently priviledged */ + /* note that the kernel will do this for "set" ioctls, but since */ + /* this ioctl wants to return status to user space it must be */ + /* defined as a "get" ioctl */ + if (!capable(CAP_NET_ADMIN)) { + return -EPERM; + } + + /* we must be associated in order to add a tspec */ + if (eConnectionState_Associated != pHddStaCtx->conn_info.connState) { + *pStatus = HDD_WLAN_WMM_STATUS_SETUP_FAILED_BAD_PARAM; + return 0; + } + /* since we are defined to be a "get" ioctl, and since the number */ + /* of params exceeds the number of params that wireless extensions */ + /* will pass down in the iwreq_data, we must copy the "set" params. */ + /* We must handle the compat for iwreq_data in 32U/64K environment. */ + + /* helper function to get iwreq_data with compat handling. */ + if (hdd_priv_get_data(&s_priv_data, wrqu)) { + *pStatus = HDD_WLAN_WMM_STATUS_SETUP_FAILED_BAD_PARAM; + return 0; + } + /* make sure all params are correctly passed to function */ + if ((NULL == s_priv_data.pointer) || + (HDD_WLAN_WMM_PARAM_COUNT != s_priv_data.length)) { + *pStatus = HDD_WLAN_WMM_STATUS_SETUP_FAILED_BAD_PARAM; + return 0; + } + /* from user space ourselves */ + if (copy_from_user(¶ms, s_priv_data.pointer, sizeof(params))) { + /* hmmm, can't get them */ + return -EIO; + } + /* clear the tspec */ + memset(&tSpec, 0, sizeof(tSpec)); + + /* validate the handle */ + handle = params[HDD_WLAN_WMM_PARAM_HANDLE]; + if (HDD_WMM_HANDLE_IMPLICIT == handle) { + /* that one is reserved */ + *pStatus = HDD_WLAN_WMM_STATUS_SETUP_FAILED_BAD_PARAM; + return 0; + } + /* validate the TID */ + if (params[HDD_WLAN_WMM_PARAM_TID] > 7) { + /* out of range */ + *pStatus = HDD_WLAN_WMM_STATUS_SETUP_FAILED_BAD_PARAM; + return 0; + } + tSpec.ts_info.tid = params[HDD_WLAN_WMM_PARAM_TID]; + + /* validate the direction */ + switch (params[HDD_WLAN_WMM_PARAM_DIRECTION]) { + case HDD_WLAN_WMM_DIRECTION_UPSTREAM: + tSpec.ts_info.direction = SME_QOS_WMM_TS_DIR_UPLINK; + break; + + case HDD_WLAN_WMM_DIRECTION_DOWNSTREAM: + tSpec.ts_info.direction = SME_QOS_WMM_TS_DIR_DOWNLINK; + break; + + case HDD_WLAN_WMM_DIRECTION_BIDIRECTIONAL: + tSpec.ts_info.direction = SME_QOS_WMM_TS_DIR_BOTH; + break; + + default: + /* unknown */ + *pStatus = HDD_WLAN_WMM_STATUS_SETUP_FAILED_BAD_PARAM; + return 0; + } + + tSpec.ts_info.psb = params[HDD_WLAN_WMM_PARAM_APSD]; + + /* validate the user priority */ + if (params[HDD_WLAN_WMM_PARAM_USER_PRIORITY] >= SME_QOS_WMM_UP_MAX) { + /* out of range */ + *pStatus = HDD_WLAN_WMM_STATUS_SETUP_FAILED_BAD_PARAM; + return 0; + } + tSpec.ts_info.up = params[HDD_WLAN_WMM_PARAM_USER_PRIORITY]; + if (0 > tSpec.ts_info.up || SME_QOS_WMM_UP_MAX < tSpec.ts_info.up) { + hdd_err("***ts_info.up out of bounds***"); + return 0; + } + + hdd_info("TS_INFO PSB %d UP %d !!!", + tSpec.ts_info.psb, tSpec.ts_info.up); + + tSpec.nominal_msdu_size = params[HDD_WLAN_WMM_PARAM_NOMINAL_MSDU_SIZE]; + tSpec.maximum_msdu_size = params[HDD_WLAN_WMM_PARAM_MAXIMUM_MSDU_SIZE]; + tSpec.min_data_rate = params[HDD_WLAN_WMM_PARAM_MINIMUM_DATA_RATE]; + tSpec.mean_data_rate = params[HDD_WLAN_WMM_PARAM_MEAN_DATA_RATE]; + tSpec.peak_data_rate = params[HDD_WLAN_WMM_PARAM_PEAK_DATA_RATE]; + tSpec.max_burst_size = params[HDD_WLAN_WMM_PARAM_MAX_BURST_SIZE]; + tSpec.min_phy_rate = params[HDD_WLAN_WMM_PARAM_MINIMUM_PHY_RATE]; + tSpec.surplus_bw_allowance = + params[HDD_WLAN_WMM_PARAM_SURPLUS_BANDWIDTH_ALLOWANCE]; + tSpec.min_service_interval = + params[HDD_WLAN_WMM_PARAM_SERVICE_INTERVAL]; + tSpec.max_service_interval = + params[HDD_WLAN_WMM_PARAM_MAX_SERVICE_INTERVAL]; + tSpec.suspension_interval = + params[HDD_WLAN_WMM_PARAM_SUSPENSION_INTERVAL]; + tSpec.inactivity_interval = + params[HDD_WLAN_WMM_PARAM_INACTIVITY_INTERVAL]; + + tSpec.ts_info.burst_size_defn = + params[HDD_WLAN_WMM_PARAM_BURST_SIZE_DEFN]; + + /* validate the ts info ack policy */ + switch (params[HDD_WLAN_WMM_PARAM_ACK_POLICY]) { + case HDD_WLAN_WMM_TS_INFO_ACK_POLICY_NORMAL_ACK: + tSpec.ts_info.ack_policy = SME_QOS_WMM_TS_ACK_POLICY_NORMAL_ACK; + break; + + case HDD_WLAN_WMM_TS_INFO_ACK_POLICY_HT_IMMEDIATE_BLOCK_ACK: + tSpec.ts_info.ack_policy = + SME_QOS_WMM_TS_ACK_POLICY_HT_IMMEDIATE_BLOCK_ACK; + break; + + default: + /* unknown */ + *pStatus = HDD_WLAN_WMM_STATUS_SETUP_FAILED_BAD_PARAM; + return 0; + } + + *pStatus = hdd_wmm_addts(pAdapter, handle, &tSpec); + EXIT(); + return 0; +} + +static int iw_add_tspec(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_add_tspec(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * iw_del_tspec - Delete TSpec private ioctl handler + * @dev: device upon which the ioctl was received + * @info: ioctl request information + * @wrqu: ioctl request data + * @extra: ioctl extra data + * + * Return: 0 on success, non-zero on error + */ +static int __iw_del_tspec(struct net_device *dev, struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *hdd_ctx; + int *params = (int *)extra; + hdd_wlan_wmm_status_e *pStatus = (hdd_wlan_wmm_status_e *) extra; + uint32_t handle; + int ret; + + ENTER_DEV(dev); + + hdd_ctx = WLAN_HDD_GET_CTX(pAdapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + /* make sure the application is sufficiently priviledged */ + /* note that the kernel will do this for "set" ioctls, but since */ + /* this ioctl wants to return status to user space it must be */ + /* defined as a "get" ioctl */ + if (!capable(CAP_NET_ADMIN)) { + return -EPERM; + } + + /* although we are defined to be a "get" ioctl, the params we require */ + /* will fit in the iwreq_data, therefore unlike iw_add_tspec() there */ + /* is no need to copy the params from user space */ + + /* validate the handle */ + handle = params[HDD_WLAN_WMM_PARAM_HANDLE]; + if (HDD_WMM_HANDLE_IMPLICIT == handle) { + /* that one is reserved */ + *pStatus = HDD_WLAN_WMM_STATUS_SETUP_FAILED_BAD_PARAM; + return 0; + } + + *pStatus = hdd_wmm_delts(pAdapter, handle); + EXIT(); + return 0; +} + +static int iw_del_tspec(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_del_tspec(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * iw_get_tspec - Get TSpec private ioctl handler + * @dev: device upon which the ioctl was received + * @info: ioctl request information + * @wrqu: ioctl request data + * @extra: ioctl extra data + * + * Return: 0 on success, non-zero on error + */ +static int __iw_get_tspec(struct net_device *dev, struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *hdd_ctx; + int *params = (int *)extra; + hdd_wlan_wmm_status_e *pStatus = (hdd_wlan_wmm_status_e *) extra; + uint32_t handle; + int ret; + + ENTER_DEV(dev); + + hdd_ctx = WLAN_HDD_GET_CTX(pAdapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + /* although we are defined to be a "get" ioctl, the params we require */ + /* will fit in the iwreq_data, therefore unlike iw_add_tspec() there */ + /* is no need to copy the params from user space */ + + /* validate the handle */ + handle = params[HDD_WLAN_WMM_PARAM_HANDLE]; + if (HDD_WMM_HANDLE_IMPLICIT == handle) { + /* that one is reserved */ + *pStatus = HDD_WLAN_WMM_STATUS_SETUP_FAILED_BAD_PARAM; + return 0; + } + + *pStatus = hdd_wmm_checkts(pAdapter, handle); + EXIT(); + return 0; +} + +static int iw_get_tspec(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_get_tspec(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * iw_set_fties - Set FT IEs private ioctl handler + * @dev: device upon which the ioctl was received + * @info: ioctl request information + * @wrqu: ioctl request data + * @extra: ioctl extra data + * + * Each time the supplicant has the auth_request or reassoc request + * IEs ready they are pushed to the driver. The driver will in turn + * use it to send out the auth req and reassoc req for 11r FT Assoc. + * + * Return: 0 on success, non-zero on error + */ +static int __iw_set_fties(struct net_device *dev, struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + hdd_context_t *hdd_ctx; + int ret; + + ENTER_DEV(dev); + + hdd_ctx = WLAN_HDD_GET_CTX(pAdapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + if (!wrqu->data.length) { + hdd_err("called with 0 length IEs"); + return -EINVAL; + } + if (wrqu->data.pointer == NULL) { + hdd_err("called with NULL IE"); + return -EINVAL; + } + /* Added for debug on reception of Re-assoc Req. */ + if (eConnectionState_Associated != pHddStaCtx->conn_info.connState) { + hdd_err("Called with Ie of length = %d when not associated", + wrqu->data.length); + hdd_err("Should be Re-assoc Req IEs"); + } + hdd_notice("called with Ie of length = %d", wrqu->data.length); + + /* Pass the received FT IEs to SME */ + sme_set_ft_ies(WLAN_HDD_GET_HAL_CTX(pAdapter), pAdapter->sessionId, + extra, wrqu->data.length); + EXIT(); + return 0; +} + +static int iw_set_fties(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_set_fties(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * iw_set_dynamic_mcbc_filter() - Set Dynamic MCBC Filter ioctl handler + * @dev: device upon which the ioctl was received + * @info: ioctl request information + * @wrqu: ioctl request data + * @extra: ioctl extra data + * + * This IOCTL is OBSOLETE as of Jan 30, 2017. We are leaving it here for the + * time being to provide guidance in migrating to standard APIs. + * + * Return: 0 on success, non-zero on error + */ +static int iw_set_dynamic_mcbc_filter(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + hdd_err("\n" + "setMCBCFilter is obsolete. Use the following instead:\n" + "Configure multicast filtering via the ‘ip’ command.\n" + "\tip maddr add 11:22:33:44:55:66 dev wlan0 # allow traffic to address\n" + "\tip maddr del 11:22:33:44:55:66 dev wlan0 # undo allow\n" + "Configure broadcast filtering via ini item, 'g_enable_non_arp_bc_hw_filter.'\n" + "\tg_enable_non_arp_bc_hw_filter=1 # drop all non-ARP broadcast traffic\n" + "\tg_enable_non_arp_bc_hw_filter=0 # allow all broadcast traffic"); + + return -EINVAL; +} + +/** + * iw_set_host_offload - Set host offload ioctl handler + * @dev: device upon which the ioctl was received + * @info: ioctl request information + * @wrqu: ioctl request data + * @extra: ioctl extra data + * + * Return: 0 on success, non-zero on error + */ +static int __iw_set_host_offload(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + tpHostOffloadRequest pRequest = (tpHostOffloadRequest) extra; + tSirHostOffloadReq offloadRequest; + hdd_context_t *hdd_ctx; + int ret; + + ENTER_DEV(dev); + + hdd_ctx = WLAN_HDD_GET_CTX(pAdapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + if (!hdd_conn_is_connected(WLAN_HDD_GET_STATION_CTX_PTR(pAdapter))) { + hdd_err("dev is not in CONNECTED state, ignore!!!"); + return -EINVAL; + } + + /* Debug display of request components. */ + switch (pRequest->offloadType) { + case WLAN_IPV4_ARP_REPLY_OFFLOAD: + hdd_warn("Host offload request: ARP reply"); + switch (pRequest->enableOrDisable) { + case WLAN_OFFLOAD_DISABLE: + hdd_warn(" disable"); + break; + case WLAN_OFFLOAD_ARP_AND_BC_FILTER_ENABLE: + hdd_warn(" BC Filtering enable"); + case WLAN_OFFLOAD_ENABLE: + hdd_warn(" ARP offload enable"); + hdd_warn(" IP address: %d.%d.%d.%d", + pRequest->params.hostIpv4Addr[0], + pRequest->params.hostIpv4Addr[1], + pRequest->params.hostIpv4Addr[2], + pRequest->params.hostIpv4Addr[3]); + } + break; + + case WLAN_IPV6_NEIGHBOR_DISCOVERY_OFFLOAD: + hdd_info("Host offload request: neighbor discovery"); + switch (pRequest->enableOrDisable) { + case WLAN_OFFLOAD_DISABLE: + hdd_info(" disable"); + break; + case WLAN_OFFLOAD_ENABLE: + hdd_info(" enable"); + hdd_info(" IP address: %x:%x:%x:%x:%x:%x:%x:%x", + *(uint16_t *) (pRequest->params.hostIpv6Addr), + *(uint16_t *) (pRequest->params.hostIpv6Addr + + 2), + *(uint16_t *) (pRequest->params.hostIpv6Addr + + 4), + *(uint16_t *) (pRequest->params.hostIpv6Addr + + 6), + *(uint16_t *) (pRequest->params.hostIpv6Addr + + 8), + *(uint16_t *) (pRequest->params.hostIpv6Addr + + 10), + *(uint16_t *) (pRequest->params.hostIpv6Addr + + 12), + *(uint16_t *) (pRequest->params.hostIpv6Addr + + 14)); + } + } + + /* Execute offload request. The reason that we can copy the + * request information from the ioctl structure to the SME + * structure is that they are laid out exactly the same. + * Otherwise, each piece of information would have to be + * copied individually. + */ + memcpy(&offloadRequest, pRequest, wrqu->data.length); + if (QDF_STATUS_SUCCESS != + sme_set_host_offload(WLAN_HDD_GET_HAL_CTX(pAdapter), + pAdapter->sessionId, &offloadRequest)) { + hdd_err("Failure to execute host offload request"); + return -EINVAL; + } + EXIT(); + return 0; +} + +static int iw_set_host_offload(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_set_host_offload(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * iw_set_keepalive_params - Set keepalive params ioctl handler + * @dev: device upon which the ioctl was received + * @info: ioctl request information + * @wrqu: ioctl request data + * @extra: ioctl extra data + * + * Return: 0 on success, non-zero on error + */ +static int __iw_set_keepalive_params(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + tpSirKeepAliveReq request = (tpSirKeepAliveReq) extra; + hdd_context_t *hdd_ctx; + int ret; + + ENTER_DEV(dev); + + hdd_ctx = WLAN_HDD_GET_CTX(pAdapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + if (wrqu->data.length != sizeof(*request)) { + hdd_err("Invalid length %d", wrqu->data.length); + return -EINVAL; + } + + if (request->timePeriod > WNI_CFG_INFRA_STA_KEEP_ALIVE_PERIOD_STAMAX) { + hdd_err("Value of timePeriod %d exceed Max limit %d", + request->timePeriod, + WNI_CFG_INFRA_STA_KEEP_ALIVE_PERIOD_STAMAX); + return -EINVAL; + } + + /* Debug display of request components. */ + hdd_info("Set Keep Alive Request : TimePeriod %d size %zu", + request->timePeriod, sizeof(tSirKeepAliveReq)); + + switch (request->packetType) { + case WLAN_KEEP_ALIVE_NULL_PKT: + hdd_info("Keep Alive Request: Tx NULL"); + break; + + case WLAN_KEEP_ALIVE_UNSOLICIT_ARP_RSP: + hdd_info("Keep Alive Request: Tx UnSolicited ARP RSP"); + + hdd_info("Host IP address: %d.%d.%d.%d", + request->hostIpv4Addr[0], request->hostIpv4Addr[1], + request->hostIpv4Addr[2], request->hostIpv4Addr[3]); + + hdd_info("Dest IP address: %d.%d.%d.%d", + request->destIpv4Addr[0], request->destIpv4Addr[1], + request->destIpv4Addr[2], request->destIpv4Addr[3]); + + hdd_info("Dest MAC address: "MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(request->dest_macaddr.bytes)); + break; + } + + hdd_info("Keep alive period %d", request->timePeriod); + + if (QDF_STATUS_SUCCESS != + sme_set_keep_alive(WLAN_HDD_GET_HAL_CTX(pAdapter), + pAdapter->sessionId, request)) { + hdd_err("Failure to execute Keep Alive"); + return -EINVAL; + } + EXIT(); + return 0; +} + +static int iw_set_keepalive_params(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_set_keepalive_params(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +#ifdef WLAN_FEATURE_PACKET_FILTERING +/** + * wlan_hdd_set_filter() - Set packet filter + * @hdd_ctx: Global HDD context + * @request: Packet filter request struct + * @sessionId: Target session for the request + * + * Return: 0 on success, non-zero on error + */ +int wlan_hdd_set_filter(hdd_context_t *hdd_ctx, + struct pkt_filter_cfg *request, + uint8_t sessionId) +{ + tSirRcvPktFilterCfgType packetFilterSetReq = {0}; + tSirRcvFltPktClearParam packetFilterClrReq = {0}; + int i = 0; + + if (hdd_ctx->config->disablePacketFilter) { + hdd_warn("packet filtering disabled in ini returning"); + return 0; + } + + /* Debug display of request components. */ + hdd_info("Packet Filter Request : FA %d params %d", + request->filter_action, request->num_params); + + switch (request->filter_action) { + case HDD_RCV_FILTER_SET: + hdd_info("Set Packet Filter Request for Id: %d", + request->filter_id); + + packetFilterSetReq.filterId = request->filter_id; + if (request->num_params >= HDD_MAX_CMP_PER_PACKET_FILTER) { + hdd_err("Number of Params exceed Max limit %d", + request->num_params); + return -EINVAL; + } + packetFilterSetReq.numFieldParams = request->num_params; + packetFilterSetReq.coalesceTime = 0; + packetFilterSetReq.filterType = HDD_RCV_FILTER_SET; + for (i = 0; i < request->num_params; i++) { + packetFilterSetReq.paramsData[i].protocolLayer = + request->params_data[i].protocol_layer; + packetFilterSetReq.paramsData[i].cmpFlag = + request->params_data[i].compare_flag; + packetFilterSetReq.paramsData[i].dataOffset = + request->params_data[i].data_offset; + packetFilterSetReq.paramsData[i].dataLength = + request->params_data[i].data_length; + packetFilterSetReq.paramsData[i].reserved = 0; + + if (request->params_data[i].data_offset > + SIR_MAX_FILTER_TEST_DATA_OFFSET) { + hdd_err("Invalid data offset %u for param %d (max = %d)", + request->params_data[i].data_offset, + i, + SIR_MAX_FILTER_TEST_DATA_OFFSET); + return -EINVAL; + } + + if (request->params_data[i].data_length > + SIR_MAX_FILTER_TEST_DATA_LEN) { + hdd_err("Error invalid data length %d", + request->params_data[i].data_length); + return -EINVAL; + } + + hdd_info("Proto %d Comp Flag %d Filter Type %d", + request->params_data[i].protocol_layer, + request->params_data[i].compare_flag, + packetFilterSetReq.filterType); + + hdd_info("Data Offset %d Data Len %d", + request->params_data[i].data_offset, + request->params_data[i].data_length); + + if (sizeof(packetFilterSetReq.paramsData[i].compareData) + < (request->params_data[i].data_length)) { + hdd_err("Error invalid data length %d", + request->params_data[i].data_length); + return -EINVAL; + } + + memcpy(&packetFilterSetReq.paramsData[i].compareData, + request->params_data[i].compare_data, + request->params_data[i].data_length); + memcpy(&packetFilterSetReq.paramsData[i].dataMask, + request->params_data[i].data_mask, + request->params_data[i].data_length); + + hdd_info("CData %d CData %d CData %d CData %d CData %d CData %d", + request->params_data[i].compare_data[0], + request->params_data[i].compare_data[1], + request->params_data[i].compare_data[2], + request->params_data[i].compare_data[3], + request->params_data[i].compare_data[4], + request->params_data[i].compare_data[5]); + + hdd_info("MData %d MData %d MData %d MData %d MData %d MData %d", + request->params_data[i].data_mask[0], + request->params_data[i].data_mask[1], + request->params_data[i].data_mask[2], + request->params_data[i].data_mask[3], + request->params_data[i].data_mask[4], + request->params_data[i].data_mask[5]); + } + + if (QDF_STATUS_SUCCESS != + sme_receive_filter_set_filter(hdd_ctx->hHal, + &packetFilterSetReq, + sessionId)) { + hdd_err("Failure to execute Set Filter"); + return -EINVAL; + } + + break; + + case HDD_RCV_FILTER_CLEAR: + + hdd_info("Clear Packet Filter Request for Id: %d", + request->filter_id); + packetFilterClrReq.filterId = request->filter_id; + if (QDF_STATUS_SUCCESS != + sme_receive_filter_clear_filter(hdd_ctx->hHal, + &packetFilterClrReq, + sessionId)) { + hdd_err("Failure to execute Clear Filter"); + return -EINVAL; + } + break; + + default: + hdd_err("Packet Filter Request: Invalid %d", + request->filter_action); + return -EINVAL; + } + return 0; +} + +/** + * __iw_set_packet_filter_params() - set packet filter parameters in target + * @dev: Pointer to netdev + * @info: Pointer to iw request info + * @wrqu: Pointer to data + * @extra: Pointer to extra data + * + * Return: 0 on success, non-zero on error + */ +static int __iw_set_packet_filter_params(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + hdd_context_t *hdd_ctx; + struct iw_point priv_data; + hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct pkt_filter_cfg *request = NULL; + + if (!capable(CAP_NET_ADMIN)) { + hdd_err("permission check failed"); + return -EPERM; + } + + ENTER_DEV(dev); + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + if (hdd_priv_get_data(&priv_data, wrqu)) { + hdd_err("failed to get priv data"); + return -EINVAL; + } + + if ((NULL == priv_data.pointer) || (0 == priv_data.length)) { + hdd_err("invalid priv data %p or invalid priv data length %d", + priv_data.pointer, priv_data.length); + return -EINVAL; + } + + if (adapter->device_mode != QDF_STA_MODE) { + hdd_err("Packet filter not supported for this mode :%d", + adapter->device_mode); + return -ENOTSUPP; + } + + if (!hdd_conn_is_connected(WLAN_HDD_GET_STATION_CTX_PTR(adapter))) { + hdd_err("Packet filter not supported in disconnected state"); + return -ENOTSUPP; + } + + /* copy data using copy_from_user */ + request = mem_alloc_copy_from_user_helper(priv_data.pointer, + priv_data.length); + if (NULL == request) { + hdd_err("mem_alloc_copy_from_user_helper fail"); + return -ENOMEM; + } + + if (request->filter_action == HDD_RCV_FILTER_SET) + hdd_ctx->user_configured_pkt_filter_rules |= + 1 << request->filter_id; + else if (request->filter_action == HDD_RCV_FILTER_CLEAR) + hdd_ctx->user_configured_pkt_filter_rules &= + ~(1 << request->filter_id); + + ret = wlan_hdd_set_filter(hdd_ctx, request, adapter->sessionId); + + qdf_mem_free(request); + EXIT(); + return ret; +} + +/** + * iw_set_packet_filter_params() - set packet filter parameters in target + * @dev: Pointer to netdev + * @info: Pointer to iw request info + * @wrqu: Pointer to data + * @extra: Pointer to extra data + * + * Return: 0 on success, non-zero on error + */ +static int iw_set_packet_filter_params(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_set_packet_filter_params(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} +#endif + + +static int __iw_get_statistics(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + QDF_STATUS status = QDF_STATUS_SUCCESS; + hdd_wext_state_t *pWextState; + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(pAdapter); + char *p = extra; + int tlen = 0; + tCsrSummaryStatsInfo *pStats = &(pAdapter->hdd_stats.summary_stat); + tCsrGlobalClassAStatsInfo *aStats = &(pAdapter->hdd_stats.ClassA_stat); + tCsrGlobalClassDStatsInfo *dStats = &(pAdapter->hdd_stats.ClassD_stat); + int ret; + + ENTER_DEV(dev); + + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + if (eConnectionState_Associated != + (WLAN_HDD_GET_STATION_CTX_PTR(pAdapter))->conn_info.connState) { + + wrqu->txpower.value = 0; + } else { + status = sme_get_statistics(hdd_ctx->hHal, eCSR_HDD, + SME_SUMMARY_STATS | + SME_GLOBAL_CLASSA_STATS | + SME_GLOBAL_CLASSB_STATS | + SME_GLOBAL_CLASSC_STATS | + SME_GLOBAL_CLASSD_STATS | + SME_PER_STA_STATS, + hdd_statistics_cb, 0, false, + (WLAN_HDD_GET_STATION_CTX_PTR + (pAdapter))->conn_info.staId[0], + pAdapter, pAdapter->sessionId); + + if (QDF_STATUS_SUCCESS != status) { + hdd_err("Unable to retrieve SME statistics"); + return -EINVAL; + } + + pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter); + + qdf_status = + qdf_wait_single_event(&pWextState->hdd_qdf_event, + WLAN_WAIT_TIME_STATS); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + hdd_err("SME timeout while retrieving statistics"); + /*Remove the SME statistics list by passing NULL in callback argument */ + status = sme_get_statistics(hdd_ctx->hHal, eCSR_HDD, + SME_SUMMARY_STATS | + SME_GLOBAL_CLASSA_STATS | + SME_GLOBAL_CLASSB_STATS | + SME_GLOBAL_CLASSC_STATS | + SME_GLOBAL_CLASSD_STATS | + SME_PER_STA_STATS, + NULL, 0, false, + (WLAN_HDD_GET_STATION_CTX_PTR + (pAdapter))->conn_info. + staId[0], pAdapter, + pAdapter->sessionId); + + return -EINVAL; + } + FILL_TLV(p, (uint8_t) WLAN_STATS_RETRY_CNT, + (uint8_t) sizeof(pStats->retry_cnt), + (char *)&(pStats->retry_cnt[0]), tlen); + + FILL_TLV(p, (uint8_t) WLAN_STATS_MUL_RETRY_CNT, + (uint8_t) sizeof(pStats->multiple_retry_cnt), + (char *)&(pStats->multiple_retry_cnt[0]), tlen); + + FILL_TLV(p, (uint8_t) WLAN_STATS_TX_FRM_CNT, + (uint8_t) sizeof(pStats->tx_frm_cnt), + (char *)&(pStats->tx_frm_cnt[0]), tlen); + + FILL_TLV(p, (uint8_t) WLAN_STATS_RX_FRM_CNT, + (uint8_t) sizeof(pStats->rx_frm_cnt), + (char *)&(pStats->rx_frm_cnt), tlen); + + FILL_TLV(p, (uint8_t) WLAN_STATS_FRM_DUP_CNT, + (uint8_t) sizeof(pStats->frm_dup_cnt), + (char *)&(pStats->frm_dup_cnt), tlen); + + FILL_TLV(p, (uint8_t) WLAN_STATS_FAIL_CNT, + (uint8_t) sizeof(pStats->fail_cnt), + (char *)&(pStats->fail_cnt[0]), tlen); + + FILL_TLV(p, (uint8_t) WLAN_STATS_RTS_FAIL_CNT, + (uint8_t) sizeof(pStats->rts_fail_cnt), + (char *)&(pStats->rts_fail_cnt), tlen); + + FILL_TLV(p, (uint8_t) WLAN_STATS_ACK_FAIL_CNT, + (uint8_t) sizeof(pStats->ack_fail_cnt), + (char *)&(pStats->ack_fail_cnt), tlen); + + FILL_TLV(p, (uint8_t) WLAN_STATS_RTS_SUC_CNT, + (uint8_t) sizeof(pStats->rts_succ_cnt), + (char *)&(pStats->rts_succ_cnt), tlen); + + FILL_TLV(p, (uint8_t) WLAN_STATS_RX_DISCARD_CNT, + (uint8_t) sizeof(pStats->rx_discard_cnt), + (char *)&(pStats->rx_discard_cnt), tlen); + + FILL_TLV(p, (uint8_t) WLAN_STATS_RX_ERROR_CNT, + (uint8_t) sizeof(pStats->rx_error_cnt), + (char *)&(pStats->rx_error_cnt), tlen); + + FILL_TLV(p, (uint8_t) WLAN_STATS_TX_BYTE_CNT, + (uint8_t) sizeof(dStats->tx_uc_byte_cnt[0]), + (char *)&(dStats->tx_uc_byte_cnt[0]), tlen); + + FILL_TLV(p, (uint8_t) WLAN_STATS_RX_BYTE_CNT, + (uint8_t) sizeof(dStats->rx_byte_cnt), + (char *)&(dStats->rx_byte_cnt), tlen); + + FILL_TLV(p, (uint8_t) WLAN_STATS_RX_RATE, + (uint8_t) sizeof(dStats->rx_rate), + (char *)&(dStats->rx_rate), tlen); + + /* Transmit rate, in units of 500 kbit/sec */ + FILL_TLV(p, (uint8_t) WLAN_STATS_TX_RATE, + (uint8_t) sizeof(aStats->tx_rate), + (char *)&(aStats->tx_rate), tlen); + + FILL_TLV(p, (uint8_t) WLAN_STATS_RX_UC_BYTE_CNT, + (uint8_t) sizeof(dStats->rx_uc_byte_cnt[0]), + (char *)&(dStats->rx_uc_byte_cnt[0]), tlen); + FILL_TLV(p, (uint8_t) WLAN_STATS_RX_MC_BYTE_CNT, + (uint8_t) sizeof(dStats->rx_mc_byte_cnt), + (char *)&(dStats->rx_mc_byte_cnt), tlen); + FILL_TLV(p, (uint8_t) WLAN_STATS_RX_BC_BYTE_CNT, + (uint8_t) sizeof(dStats->rx_bc_byte_cnt), + (char *)&(dStats->rx_bc_byte_cnt), tlen); + FILL_TLV(p, (uint8_t) WLAN_STATS_TX_UC_BYTE_CNT, + (uint8_t) sizeof(dStats->tx_uc_byte_cnt[0]), + (char *)&(dStats->tx_uc_byte_cnt[0]), tlen); + FILL_TLV(p, (uint8_t) WLAN_STATS_TX_MC_BYTE_CNT, + (uint8_t) sizeof(dStats->tx_mc_byte_cnt), + (char *)&(dStats->tx_mc_byte_cnt), tlen); + FILL_TLV(p, (uint8_t) WLAN_STATS_TX_BC_BYTE_CNT, + (uint8_t) sizeof(dStats->tx_bc_byte_cnt), + (char *)&(dStats->tx_bc_byte_cnt), tlen); + + wrqu->data.length = tlen; + + } + + EXIT(); + + return 0; +} + +static int iw_get_statistics(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_get_statistics(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +#ifdef FEATURE_WLAN_SCAN_PNO + +/*Max Len for PNO notification*/ +#define MAX_PNO_NOTIFY_LEN 100 +static void found_pref_network_cb(void *callbackContext, + tSirPrefNetworkFoundInd *pPrefNetworkFoundInd) +{ + hdd_adapter_t *pAdapter = (hdd_adapter_t *) callbackContext; + union iwreq_data wrqu; + char buf[MAX_PNO_NOTIFY_LEN + 1]; + + hdd_warn("A preferred network was found: %s with rssi: -%d", + pPrefNetworkFoundInd->ssId.ssId, pPrefNetworkFoundInd->rssi); + + /* create the event */ + memset(&wrqu, 0, sizeof(wrqu)); + memset(buf, 0, sizeof(buf)); + + snprintf(buf, MAX_PNO_NOTIFY_LEN, + "QCOM: Found preferred network: %s with RSSI of -%u", + pPrefNetworkFoundInd->ssId.ssId, + (unsigned int)pPrefNetworkFoundInd->rssi); + + wrqu.data.pointer = buf; + wrqu.data.length = strlen(buf); + + /* send the event */ + + wireless_send_event(pAdapter->dev, IWEVCUSTOM, &wrqu, buf); + +} + +/** + * __iw_set_pno() - Preferred Network Offload ioctl handler + * @dev: device upon which the ioctl was received + * @info: ioctl request information + * @wrqu: ioctl request data + * @extra: ioctl extra data + * + * This function parses a Preferred Network Offload command + * Input is string based and expected to be of the form: + * + * + * when enabling: + * + * for each network: + * + * + * + * + * + * + * e.g: + * 1 2 4 test 0 0 3 1 6 11 2 40 5 test2 4 4 6 1 2 3 4 5 6 1 0 5 2 1 + * + * this translates into: + * ----------------------------- + * enable PNO + * 2 networks + * Network 1: + * test - with authentication type 0 and encryption type 0, + * search on 3 channels: 1 6 and 11, + * SSID bcast type is unknown (directed probe will be sent if + * AP not found) and must meet -40dBm RSSI + * Network 2: + * test2 - with authentication type 4 and encryption type 4, + * search on 6 channels 1, 2, 3, 4, 5 and 6 + * bcast type is non-bcast (directed probe will be sent) + * and must not meet any RSSI threshold + * scan every 5 seconds 2 times + * enable on suspend + */ +static int __iw_set_pno(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_context_t *hdd_ctx; + int ret; + int offset; + char *ptr, *data; + uint8_t i, j, params, mode; + size_t len; + + /* request is a large struct, so we make it static to avoid + * stack overflow. This API is only invoked via ioctl, so it + * is serialized by the kernel rtnl_lock and hence does not + * need to be reentrant + */ + static tSirPNOScanReq request; + + ENTER_DEV(dev); + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return ret; + + hdd_notice("PNO data len %d data %s", wrqu->data.length, extra); + + /* making sure argument string ends with '\0' */ + len = (wrqu->data.length + 1); + data = qdf_mem_malloc(len); + if (NULL == data) { + hdd_err("fail to allocate memory %zu", len); + return -EINVAL; + } + qdf_mem_zero(data, len); + qdf_mem_copy(data, extra, (len-1)); + ptr = data; + + request.enable = 0; + request.ucNetworksCount = 0; + + if (1 != sscanf(ptr, " %hhu%n", &(request.enable), &offset)) { + hdd_err("PNO enable input is not valid %s", ptr); + qdf_mem_free(data); + return -EINVAL; + } + + if (0 == request.enable) { + /* Disable PNO, ignore any other params */ + memset(&request, 0, sizeof(request)); + sme_set_preferred_network_list(WLAN_HDD_GET_HAL_CTX(adapter), + &request, adapter->sessionId, + found_pref_network_cb, adapter); + qdf_mem_free(data); + return 0; + } + + ptr += offset; + + if (1 != + sscanf(ptr, " %hhu %n", &(request.ucNetworksCount), &offset)) { + hdd_err("PNO count input not valid %s", ptr); + qdf_mem_free(data); + return -EINVAL; + + } + + hdd_info("PNO enable %d networks count %d offset %d", + request.enable, request.ucNetworksCount, offset); + + if ((0 == request.ucNetworksCount) || + (request.ucNetworksCount > SIR_PNO_MAX_SUPP_NETWORKS)) { + hdd_err("Network count %d invalid", + request.ucNetworksCount); + qdf_mem_free(data); + return -EINVAL; + } + + ptr += offset; + + for (i = 0; i < request.ucNetworksCount; i++) { + + request.aNetworks[i].ssId.length = 0; + + params = sscanf(ptr, " %hhu %n", + &(request.aNetworks[i].ssId.length), + &offset); + + if (1 != params) { + hdd_err("PNO ssid length input is not valid %s", ptr); + qdf_mem_free(data); + return -EINVAL; + } + + if ((0 == request.aNetworks[i].ssId.length) || + (request.aNetworks[i].ssId.length > 32)) { + hdd_err("SSID Len %d is not correct for network %d", + request.aNetworks[i].ssId.length, i); + qdf_mem_free(data); + return -EINVAL; + } + + /* Advance to SSID */ + ptr += offset; + + memcpy(request.aNetworks[i].ssId.ssId, ptr, + request.aNetworks[i].ssId.length); + ptr += request.aNetworks[i].ssId.length; + + params = sscanf(ptr, " %u %u %hhu %n", + &(request.aNetworks[i].authentication), + &(request.aNetworks[i].encryption), + &(request.aNetworks[i].ucChannelCount), + &offset); + + if (3 != params) { + hdd_warn("Incorrect cmd %s", ptr); + qdf_mem_free(data); + return -EINVAL; + } + + hdd_notice("PNO len %d ssid %.*s auth %d encry %d channel count %d offset %d", + request.aNetworks[i].ssId.length, + request.aNetworks[i].ssId.length, + request.aNetworks[i].ssId.ssId, + request.aNetworks[i].authentication, + request.aNetworks[i].encryption, + request.aNetworks[i].ucChannelCount, offset); + + /* Advance to channel list */ + ptr += offset; + + if (SIR_PNO_MAX_NETW_CHANNELS < + request.aNetworks[i].ucChannelCount) { + hdd_warn("Incorrect number of channels"); + qdf_mem_free(data); + return -EINVAL; + } + + if (0 != request.aNetworks[i].ucChannelCount) { + for (j = 0; j < request.aNetworks[i].ucChannelCount; + j++) { + if (1 != + sscanf(ptr, " %hhu %n", + &(request.aNetworks[i]. + aChannels[j]), &offset)) { + hdd_err("PNO network channel input is not valid %s", + ptr); + qdf_mem_free(data); + return -EINVAL; + } + if (!IS_CHANNEL_VALID( + request.aNetworks[i].aChannels[j])) { + hdd_err("invalid channel: %hhu", + request.aNetworks[i].aChannels[j]); + qdf_mem_free(data); + return -EINVAL; + } + /* Advance to next channel number */ + ptr += offset; + } + } + + if (1 != sscanf(ptr, " %u %n", + &(request.aNetworks[i].bcastNetwType), + &offset)) { + hdd_err("PNO broadcast network type input is not valid %s", + ptr); + qdf_mem_free(data); + return -EINVAL; + } + if (request.aNetworks[i].bcastNetwType > 2) { + hdd_err("invalid bcast nw type: %u", + request.aNetworks[i].bcastNetwType); + qdf_mem_free(data); + return -EINVAL; + } + + hdd_notice("PNO bcastNetwType %d offset %d", + request.aNetworks[i].bcastNetwType, offset); + + /* Advance to rssi Threshold */ + ptr += offset; + if (1 != sscanf(ptr, " %d %n", + &(request.aNetworks[i].rssiThreshold), + &offset)) { + hdd_err("PNO rssi threshold input is not valid %s", + ptr); + qdf_mem_free(data); + return -EINVAL; + } + hdd_notice("PNO rssi %d offset %d", + request.aNetworks[i].rssiThreshold, offset); + /* Advance to next network */ + ptr += offset; + } /* For ucNetworkCount */ + + request.fast_scan_period = 0; + if (sscanf(ptr, " %u %n", &(request.fast_scan_period), &offset) > 0) { + request.fast_scan_period *= MSEC_PER_SEC; + ptr += offset; + } + if (request.fast_scan_period == 0) { + hdd_err("invalid fast scan period %u", + request.fast_scan_period); + qdf_mem_free(data); + return -EINVAL; + } + + request.fast_scan_max_cycles = 0; + if (sscanf(ptr, " %hhu %n", &(request.fast_scan_max_cycles), + &offset) > 0) + ptr += offset; + if (request.fast_scan_max_cycles < + CFG_PNO_SCAN_TIMER_REPEAT_VALUE_MIN || + request.fast_scan_max_cycles > + CFG_PNO_SCAN_TIMER_REPEAT_VALUE_MAX) { + hdd_err("invalid fast scan max cycles %hhu", + request.fast_scan_max_cycles); + qdf_mem_free(data); + return -EINVAL; + } + + params = sscanf(ptr, " %hhu %n", &(mode), &offset); + + request.modePNO = mode; + /* for LA we just expose suspend option */ + if ((1 != params) || (mode >= SIR_PNO_MODE_MAX)) { + request.modePNO = SIR_PNO_MODE_ON_SUSPEND; + } + + sme_set_preferred_network_list(WLAN_HDD_GET_HAL_CTX(adapter), + &request, + adapter->sessionId, + found_pref_network_cb, adapter); + + qdf_mem_free(data); + return 0; +} + +static int iw_set_pno(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_set_pno(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} +#endif /* FEATURE_WLAN_SCAN_PNO */ + +/* Common function to SetBand */ +int hdd_set_band(struct net_device *dev, u8 ui_band) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter); + eCsrBand band; + + QDF_STATUS status; + hdd_context_t *pHddCtx; + hdd_adapter_list_node_t *pAdapterNode, *pNext; + eCsrBand currBand = eCSR_BAND_MAX; + eCsrBand connectedBand; + + pAdapterNode = NULL; + pNext = NULL; + pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + + switch (ui_band) { + case WLAN_HDD_UI_BAND_AUTO: + band = eCSR_BAND_ALL; + break; + case WLAN_HDD_UI_BAND_5_GHZ: + band = eCSR_BAND_5G; + break; + case WLAN_HDD_UI_BAND_2_4_GHZ: + band = eCSR_BAND_24; + break; + default: + band = eCSR_BAND_MAX; + } + + hdd_notice("change band to %u", band); + + if (band == eCSR_BAND_MAX) { + /* Received change band request with invalid band value */ + hdd_err("Invalid band value %u", ui_band); + return -EINVAL; + } + + if ((band == eCSR_BAND_24 && pHddCtx->config->nBandCapability == 2) || + (band == eCSR_BAND_5G && pHddCtx->config->nBandCapability == 1)) { + hdd_err("band value %u violate INI settings %u", + band, pHddCtx->config->nBandCapability); + return -EIO; + } + + if (band == eCSR_BAND_ALL) { + hdd_notice("Auto band received. Setting band same as ini value %d", + pHddCtx->config->nBandCapability); + band = pHddCtx->config->nBandCapability; + } + + if (QDF_STATUS_SUCCESS != sme_get_freq_band(hHal, &currBand)) { + hdd_notice("Failed to get current band config"); + return -EIO; + } + + if (currBand != band) { + /* Change band request received. + * Abort pending scan requests, flush the existing scan results, + * and change the band capability + */ + hdd_notice("Current band value = %u, new setting %u ", + currBand, band); + + status = hdd_get_front_adapter(pHddCtx, &pAdapterNode); + while (NULL != pAdapterNode && QDF_STATUS_SUCCESS == status) { + pAdapter = pAdapterNode->pAdapter; + hHal = WLAN_HDD_GET_HAL_CTX(pAdapter); + hdd_abort_mac_scan(pHddCtx, pAdapter->sessionId, + INVALID_SCAN_ID, + eCSR_SCAN_ABORT_DUE_TO_BAND_CHANGE); + connectedBand = + hdd_conn_get_connected_band + (WLAN_HDD_GET_STATION_CTX_PTR(pAdapter)); + + /* Handling is done only for STA and P2P */ + if (band != eCSR_BAND_ALL && + ((pAdapter->device_mode == QDF_STA_MODE) + || (pAdapter->device_mode == QDF_P2P_CLIENT_MODE)) + && + (hdd_conn_is_connected + (WLAN_HDD_GET_STATION_CTX_PTR(pAdapter))) + && (connectedBand != band)) { + QDF_STATUS status = QDF_STATUS_SUCCESS; + long lrc; + + /* STA already connected on current band, So issue disconnect + * first, then change the band*/ + + hdd_notice("STA (Device mode %s(%d)) connected in band %u, Changing band to %u, Issuing Disconnect", + hdd_device_mode_to_string(pAdapter->device_mode), + pAdapter->device_mode, currBand, band); + INIT_COMPLETION(pAdapter->disconnect_comp_var); + + status = + sme_roam_disconnect(WLAN_HDD_GET_HAL_CTX + (pAdapter), + pAdapter->sessionId, + eCSR_DISCONNECT_REASON_UNSPECIFIED); + + if (QDF_STATUS_SUCCESS != status) { + hdd_err("csr_roam_disconnect failure, returned %d", + (int)status); + return -EINVAL; + } + + lrc = + wait_for_completion_timeout(&pAdapter-> + disconnect_comp_var, + msecs_to_jiffies + (WLAN_WAIT_TIME_DISCONNECT)); + + if (lrc == 0) { + hdd_err("Timeout while waiting for csr_roam_disconnect"); + return -ETIMEDOUT; + } + } + + sme_scan_flush_result(hHal); + + status = + hdd_get_next_adapter(pHddCtx, pAdapterNode, &pNext); + pAdapterNode = pNext; + } + + if (QDF_STATUS_SUCCESS != + sme_set_freq_band(hHal, pAdapter->sessionId, band)) { + hdd_alert("Failed to set the band value to %u", + band); + return -EINVAL; + } + wlan_hdd_cfg80211_update_band(pHddCtx->wiphy, (eCsrBand) band); + } + return 0; +} + +int hdd_set_band_helper(struct net_device *dev, const char *command) +{ + uint8_t band; + int ret; + + /* Convert the band value from ascii to integer */ + command += WLAN_HDD_UI_SET_BAND_VALUE_OFFSET; + ret = kstrtou8(command, 10, &band); + if (ret < 0) { + hdd_err("kstrtou8 failed"); + return -EINVAL; + } + + return hdd_set_band(dev, band); +} + +static int __iw_set_band_config(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int *value = (int *)extra; + + ENTER_DEV(dev); + + if (!capable(CAP_NET_ADMIN)) { + hdd_err("permission check failed"); + return -EPERM; + } + + return hdd_set_band(dev, value[0]); +} + +static int iw_set_band_config(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_set_band_config(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * wlan_hdd_set_mon_chan() - Set capture channel on the monitor mode interface. + * @adapter: Handle to adapter + * @chan: Monitor mode channel + * @bandwidth: Capture channel bandwidth + * + * Return: 0 on success else error code. + */ +static int wlan_hdd_set_mon_chan(hdd_adapter_t *adapter, uint32_t chan, + uint32_t bandwidth) +{ + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + hdd_station_ctx_t *sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter); + struct hdd_mon_set_ch_info *ch_info = &sta_ctx->ch_info; + QDF_STATUS status; + tHalHandle hal_hdl = hdd_ctx->hHal; + struct qdf_mac_addr bssid; + tCsrRoamProfile roam_profile; + struct ch_params_s ch_params; + + if (QDF_GLOBAL_MONITOR_MODE != hdd_get_conparam()) { + hdd_err("Not supported, device is not in monitor mode"); + return -EINVAL; + } + + hdd_info("Set monitor mode Channel %d", chan); + qdf_mem_zero(&roam_profile, sizeof(roam_profile)); + roam_profile.ChannelInfo.ChannelList = &ch_info->channel; + roam_profile.ChannelInfo.numOfChannels = 1; + roam_profile.phyMode = ch_info->phy_mode; + roam_profile.ch_params.ch_width = bandwidth; + hdd_select_cbmode(adapter, chan, &roam_profile.ch_params); + + qdf_mem_copy(bssid.bytes, adapter->macAddressCurrent.bytes, + QDF_MAC_ADDR_SIZE); + + ch_params.ch_width = bandwidth; + cds_set_channel_params(chan, 0, &ch_params); + if (ch_params.ch_width == CH_WIDTH_INVALID) { + hdd_err("Invalid capture channel or bandwidth for a country"); + return -EINVAL; + } + status = sme_roam_channel_change_req(hal_hdl, bssid, &ch_params, + &roam_profile); + if (status) { + hdd_err("Status: %d Failed to set sme_roam Channel for monitor mode", + status); + } + + return qdf_status_to_os_return(status); +} + +static int __iw_set_two_ints_getnone(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + int *value = (int *)extra; + int sub_cmd = value[0]; + int ret; + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(pAdapter); + + ENTER_DEV(dev); + + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + switch (sub_cmd) { + case WE_SET_SMPS_PARAM: + hdd_notice("WE_SET_SMPS_PARAM val %d %d", value[1], value[2]); + ret = wma_cli_set_command(pAdapter->sessionId, + WMI_STA_SMPS_PARAM_CMDID, + value[1] << WMA_SMPS_PARAM_VALUE_S + | value[2], + VDEV_CMD); + break; +#ifdef WLAN_DEBUG + case WE_SET_FW_CRASH_INJECT: + hdd_notice("WE_SET_FW_CRASH_INJECT: %d %d", + value[1], value[2]); + pr_err("SSR is triggered by iwpriv CRASH_INJECT: %d %d\n", + value[1], value[2]); + if (!hdd_ctx->config->crash_inject_enabled) { + hdd_err("Crash Inject ini disabled, Ignore Crash Inject"); + return 0; + } + ret = wma_cli_set2_command(pAdapter->sessionId, + GEN_PARAM_CRASH_INJECT, + value[1], value[2], GEN_CMD); + break; +#endif + case WE_ENABLE_FW_PROFILE: + hdd_err("WE_ENABLE_FW_PROFILE: %d %d", + value[1], value[2]); + ret = wma_cli_set2_command(pAdapter->sessionId, + WMI_WLAN_PROFILE_ENABLE_PROFILE_ID_CMDID, + value[1], value[2], DBG_CMD); + break; + case WE_SET_FW_PROFILE_HIST_INTVL: + hdd_err("WE_SET_FW_PROFILE_HIST_INTVL: %d %d", + value[1], value[2]); + ret = wma_cli_set2_command(pAdapter->sessionId, + WMI_WLAN_PROFILE_SET_HIST_INTVL_CMDID, + value[1], value[2], DBG_CMD); + break; + case WE_SET_DUAL_MAC_FW_MODE_CONFIG: + hdd_debug("Ioctl to set dual fw mode config"); + if (hdd_ctx->config->dual_mac_feature_disable) { + hdd_err("Dual mac feature is disabled from INI"); + return -EPERM; + } + hdd_debug("%d %d", value[1], value[2]); + cds_set_dual_mac_fw_mode_config(value[1], value[2]); + break; + case WE_DUMP_DP_TRACE_LEVEL: + hdd_info("WE_DUMP_DP_TRACE_LEVEL: %d %d", + value[1], value[2]); + if (value[1] == DUMP_DP_TRACE) + qdf_dp_trace_dump_all(value[2]); + else if (value[1] == ENABLE_DP_TRACE_LIVE_MODE) + qdf_dp_trace_enable_live_mode(); + else if (value[1] == CLEAR_DP_TRACE_BUFFER) + qdf_dp_trace_clear_buffer(); + break; + case WE_SET_MON_MODE_CHAN: + ret = wlan_hdd_set_mon_chan(pAdapter, value[1], value[2]); + break; + case WE_SET_WLAN_SUSPEND: + ret = hdd_wlan_fake_apps_suspend(hdd_ctx->wiphy, dev); + break; + case WE_SET_WLAN_RESUME: + ret = hdd_wlan_fake_apps_resume(hdd_ctx->wiphy, dev); + break; + default: + hdd_err("Invalid IOCTL command %d", sub_cmd); + break; + } + + return ret; +} + +static int iw_set_two_ints_getnone(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __iw_set_two_ints_getnone(dev, info, wrqu, extra); + cds_ssr_unprotect(__func__); + + return ret; +} + +/* Define the Wireless Extensions to the Linux Network Device structure */ +/* A number of these routines are NULL (meaning they are not implemented.) */ + +static const iw_handler we_handler[] = { + (iw_handler) iw_set_commit, /* SIOCSIWCOMMIT */ + (iw_handler) iw_get_name, /* SIOCGIWNAME */ + (iw_handler) NULL, /* SIOCSIWNWID */ + (iw_handler) NULL, /* SIOCGIWNWID */ + (iw_handler) iw_set_freq, /* SIOCSIWFREQ */ + (iw_handler) iw_get_freq, /* SIOCGIWFREQ */ + (iw_handler) iw_set_mode, /* SIOCSIWMODE */ + (iw_handler) iw_get_mode, /* SIOCGIWMODE */ + (iw_handler) NULL, /* SIOCSIWSENS */ + (iw_handler) NULL, /* SIOCGIWSENS */ + (iw_handler) NULL, /* SIOCSIWRANGE */ + (iw_handler) iw_get_range, /* SIOCGIWRANGE */ + (iw_handler) NULL, /* SIOCSIWPRIV */ + (iw_handler) NULL, /* SIOCGIWPRIV */ + (iw_handler) NULL, /* SIOCSIWSTATS */ + (iw_handler) NULL, /* SIOCGIWSTATS */ + (iw_handler) NULL, /* SIOCSIWSPY */ + (iw_handler) NULL, /* SIOCGIWSPY */ + (iw_handler) NULL, /* SIOCSIWTHRSPY */ + (iw_handler) NULL, /* SIOCGIWTHRSPY */ + (iw_handler) iw_set_ap_address, /* SIOCSIWAP */ + (iw_handler) iw_get_ap_address, /* SIOCGIWAP */ + (iw_handler) iw_set_mlme, /* SIOCSIWMLME */ + (iw_handler) NULL, /* SIOCGIWAPLIST */ + (iw_handler) iw_set_scan, /* SIOCSIWSCAN */ + (iw_handler) iw_get_scan, /* SIOCGIWSCAN */ + (iw_handler) iw_set_essid, /* SIOCSIWESSID */ + (iw_handler) iw_get_essid, /* SIOCGIWESSID */ + (iw_handler) iw_set_nick, /* SIOCSIWNICKN */ + (iw_handler) iw_get_nick, /* SIOCGIWNICKN */ + (iw_handler) NULL, /* -- hole -- */ + (iw_handler) NULL, /* -- hole -- */ + (iw_handler) iw_set_bitrate, /* SIOCSIWRATE */ + (iw_handler) iw_get_bitrate, /* SIOCGIWRATE */ + (iw_handler) iw_set_rts_threshold, /* SIOCSIWRTS */ + (iw_handler) iw_get_rts_threshold, /* SIOCGIWRTS */ + (iw_handler) iw_set_frag_threshold, /* SIOCSIWFRAG */ + (iw_handler) iw_get_frag_threshold, /* SIOCGIWFRAG */ + (iw_handler) iw_set_tx_power, /* SIOCSIWTXPOW */ + (iw_handler) iw_get_tx_power, /* SIOCGIWTXPOW */ + (iw_handler) iw_set_retry, /* SIOCSIWRETRY */ + (iw_handler) iw_get_retry, /* SIOCGIWRETRY */ + (iw_handler) iw_set_encode, /* SIOCSIWENCODE */ + (iw_handler) iw_get_encode, /* SIOCGIWENCODE */ + (iw_handler) iw_set_power_mode, /* SIOCSIWPOWER */ + (iw_handler) iw_get_power_mode, /* SIOCGIWPOWER */ + (iw_handler) NULL, /* -- hole -- */ + (iw_handler) NULL, /* -- hole -- */ + (iw_handler) iw_set_genie, /* SIOCSIWGENIE */ + (iw_handler) iw_get_genie, /* SIOCGIWGENIE */ + (iw_handler) iw_set_auth, /* SIOCSIWAUTH */ + (iw_handler) iw_get_auth, /* SIOCGIWAUTH */ + (iw_handler) iw_set_encodeext, /* SIOCSIWENCODEEXT */ + (iw_handler) iw_get_encodeext, /* SIOCGIWENCODEEXT */ + (iw_handler) NULL, /* SIOCSIWPMKSA */ +}; + +static const iw_handler we_private[] = { + + [WLAN_PRIV_SET_INT_GET_NONE - SIOCIWFIRSTPRIV] = iw_setint_getnone, /* set priv ioctl */ + [WLAN_PRIV_SET_NONE_GET_INT - SIOCIWFIRSTPRIV] = iw_setnone_getint, /* get priv ioctl */ + [WLAN_PRIV_SET_CHAR_GET_NONE - SIOCIWFIRSTPRIV] = iw_setchar_getnone, /* get priv ioctl */ + [WLAN_PRIV_SET_THREE_INT_GET_NONE - SIOCIWFIRSTPRIV] = + iw_set_three_ints_getnone, + [WLAN_PRIV_GET_CHAR_SET_NONE - SIOCIWFIRSTPRIV] = iw_get_char_setnone, + [WLAN_PRIV_SET_NONE_GET_NONE - SIOCIWFIRSTPRIV] = iw_setnone_getnone, /* action priv ioctl */ + [WLAN_PRIV_SET_VAR_INT_GET_NONE - SIOCIWFIRSTPRIV] = + iw_hdd_set_var_ints_getnone, + [WLAN_PRIV_SET_NONE_GET_THREE_INT - SIOCIWFIRSTPRIV] = + iw_setnone_get_threeint, + [WLAN_PRIV_ADD_TSPEC - SIOCIWFIRSTPRIV] = iw_add_tspec, + [WLAN_PRIV_DEL_TSPEC - SIOCIWFIRSTPRIV] = iw_del_tspec, + [WLAN_PRIV_GET_TSPEC - SIOCIWFIRSTPRIV] = iw_get_tspec, + [WLAN_PRIV_SET_FTIES - SIOCIWFIRSTPRIV] = iw_set_fties, + [WLAN_PRIV_SET_HOST_OFFLOAD - SIOCIWFIRSTPRIV] = iw_set_host_offload, + [WLAN_GET_WLAN_STATISTICS - SIOCIWFIRSTPRIV] = iw_get_statistics, + [WLAN_SET_KEEPALIVE_PARAMS - SIOCIWFIRSTPRIV] = + iw_set_keepalive_params, +#ifdef WLAN_FEATURE_PACKET_FILTERING + [WLAN_SET_PACKET_FILTER_PARAMS - SIOCIWFIRSTPRIV] = + iw_set_packet_filter_params, +#endif +#ifdef FEATURE_WLAN_SCAN_PNO + [WLAN_SET_PNO - SIOCIWFIRSTPRIV] = iw_set_pno, +#endif + [WLAN_SET_BAND_CONFIG - SIOCIWFIRSTPRIV] = iw_set_band_config, + [WLAN_PRIV_SET_MCBC_FILTER - SIOCIWFIRSTPRIV] = + iw_set_dynamic_mcbc_filter, + [WLAN_GET_LINK_SPEED - SIOCIWFIRSTPRIV] = iw_get_linkspeed, + [WLAN_PRIV_SET_TWO_INT_GET_NONE - SIOCIWFIRSTPRIV] = + iw_set_two_ints_getnone, + [WLAN_SET_DOT11P_CHANNEL_SCHED - SIOCIWFIRSTPRIV] = + iw_set_dot11p_channel_sched, +}; + +/*Maximum command length can be only 15 */ +static const struct iw_priv_args we_private_args[] = { + + /* handlers for main ioctl */ + {WLAN_PRIV_SET_INT_GET_NONE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + ""}, + + /* handlers for sub-ioctl */ + {WE_SET_11D_STATE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "set11Dstate"}, + + {WE_WOWL, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "wowl"}, + + {WE_SET_POWER, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "setPower"}, + + {WE_SET_MAX_ASSOC, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "setMaxAssoc"}, + + {WE_SET_SAP_AUTO_CHANNEL_SELECTION, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, + "setAutoChannel" }, + + {WE_SET_SCAN_DISABLE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "scan_disable"}, + + {WE_SET_DATA_INACTIVITY_TO, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "inactivityTO"}, + + {WE_SET_WOW_DATA_INACTIVITY_TO, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "wow_ito"}, + + {WE_SET_MAX_TX_POWER, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "setMaxTxPower"}, + + {WE_SET_TX_POWER, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "setTxPower"}, + + {WE_SET_MC_RATE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "setMcRate"}, + + {WE_SET_MAX_TX_POWER_2_4, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "setTxMaxPower2G"}, + + {WE_SET_MAX_TX_POWER_5_0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "setTxMaxPower5G"}, + + {WE_SET_PKTLOG, + IW_PRIV_TYPE_INT | MAX_VAR_ARGS, + 0, + "pktlog"}, + + /* SAP has TxMax whereas STA has MaxTx, adding TxMax for STA + * as well to keep same syntax as in SAP. Now onwards, STA + * will support both */ + {WE_SET_MAX_TX_POWER, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "setTxMaxPower"}, + + /* set Higher DTIM Transition (DTIM1 to DTIM3) + * 1 = enable and 0 = disable */ + { + WE_SET_HIGHER_DTIM_TRANSITION, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "setHDtimTransn" + }, + + {WE_SET_TM_LEVEL, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "setTmLevel"}, + + {WE_SET_PHYMODE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "setphymode"}, + + {WE_SET_NSS, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "nss"}, + + {WE_SET_LDPC, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "ldpc"}, + + {WE_SET_TX_STBC, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "tx_stbc"}, + + {WE_SET_RX_STBC, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "rx_stbc"}, + + {WE_SET_SHORT_GI, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "shortgi"}, + + {WE_SET_RTSCTS, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "enablertscts"}, + + {WE_SET_CHWIDTH, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "chwidth"}, + + {WE_SET_ANI_EN_DIS, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "anienable"}, + + {WE_SET_ANI_POLL_PERIOD, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "aniplen"}, + + {WE_SET_ANI_LISTEN_PERIOD, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "anilislen"}, + + {WE_SET_ANI_OFDM_LEVEL, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "aniofdmlvl"}, + + {WE_SET_ANI_CCK_LEVEL, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "aniccklvl"}, + + {WE_SET_DYNAMIC_BW, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "cwmenable"}, + + {WE_SET_CTS_CBW, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "cts_cbw" }, + + {WE_SET_GTX_HT_MCS, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "gtxHTMcs"}, + + {WE_SET_GTX_VHT_MCS, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "gtxVHTMcs"}, + + {WE_SET_GTX_USRCFG, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "gtxUsrCfg"}, + + {WE_SET_GTX_THRE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "gtxThre"}, + + {WE_SET_GTX_MARGIN, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "gtxMargin"}, + + {WE_SET_GTX_STEP, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "gtxStep"}, + + {WE_SET_GTX_MINTPC, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "gtxMinTpc"}, + + {WE_SET_GTX_BWMASK, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "gtxBWMask"}, + + {WE_SET_TX_CHAINMASK, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "txchainmask"}, + + {WE_SET_RX_CHAINMASK, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "rxchainmask"}, + + {WE_SET_11N_RATE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "set11NRates"}, + + {WE_SET_VHT_RATE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "set11ACRates"}, + + {WE_SET_AMPDU, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "ampdu"}, + + {WE_SET_AMSDU, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "amsdu"}, + + {WE_SET_BURST_ENABLE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "burst_enable"}, + + {WE_SET_BURST_DUR, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "burst_dur"}, + + {WE_SET_TXPOW_2G, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "txpow2g"}, + + {WE_SET_TXPOW_5G, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "txpow5g"}, + + /* Sub-cmds DBGLOG specific commands */ + {WE_DBGLOG_LOG_LEVEL, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "dl_loglevel"}, + + {WE_DBGLOG_VAP_ENABLE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "dl_vapon"}, + + {WE_DBGLOG_VAP_DISABLE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "dl_vapoff"}, + + {WE_DBGLOG_MODULE_ENABLE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "dl_modon"}, + + {WE_DBGLOG_MODULE_DISABLE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "dl_modoff"}, + + {WE_DBGLOG_MOD_LOG_LEVEL, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "dl_mod_loglevel"}, + + {WE_DBGLOG_TYPE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "dl_type"}, + {WE_DBGLOG_REPORT_ENABLE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "dl_report"}, + + {WE_SET_TXRX_FWSTATS, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "txrx_fw_stats"}, + + {WE_TXRX_FWSTATS_RESET, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "txrx_fw_st_rst"}, + + {WE_PPS_PAID_MATCH, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "paid_match"}, + + {WE_PPS_GID_MATCH, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "gid_match"}, + + {WE_PPS_EARLY_TIM_CLEAR, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "tim_clear"}, + + {WE_PPS_EARLY_DTIM_CLEAR, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "dtim_clear"}, + + {WE_PPS_EOF_PAD_DELIM, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "eof_delim"}, + + {WE_PPS_MACADDR_MISMATCH, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "mac_match"}, + + {WE_PPS_DELIM_CRC_FAIL, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "delim_fail"}, + + {WE_PPS_GID_NSTS_ZERO, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "nsts_zero"}, + + {WE_PPS_RSSI_CHECK, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "rssi_chk"}, + + {WE_PPS_5G_EBT, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "5g_ebt"}, + + {WE_SET_HTSMPS, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "htsmps"}, + + {WE_SET_QPOWER_MAX_PSPOLL_COUNT, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "set_qpspollcnt"}, + + {WE_SET_QPOWER_MAX_TX_BEFORE_WAKE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "set_qtxwake"}, + + {WE_SET_QPOWER_SPEC_PSPOLL_WAKE_INTERVAL, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "set_qwakeintv"}, + + {WE_SET_QPOWER_SPEC_MAX_SPEC_NODATA_PSPOLL, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "set_qnodatapoll"}, + + /* handlers for MCC time quota and latency sub ioctls */ + {WE_MCC_CONFIG_LATENCY, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "setMccLatency"}, + + {WE_MCC_CONFIG_QUOTA, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "setMccQuota"}, + + {WE_SET_DEBUG_LOG, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "setDbgLvl"}, + + /* handlers for early_rx power save */ + {WE_SET_EARLY_RX_ADJUST_ENABLE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "erx_enable"}, + + {WE_SET_EARLY_RX_TGT_BMISS_NUM, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "erx_bmiss_val"}, + + {WE_SET_EARLY_RX_BMISS_SAMPLE_CYCLE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "erx_bmiss_smpl"}, + + {WE_SET_EARLY_RX_SLOP_STEP, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "erx_slop_step"}, + + {WE_SET_EARLY_RX_INIT_SLOP, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "erx_init_slop"}, + + {WE_SET_EARLY_RX_ADJUST_PAUSE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "erx_adj_pause"}, + + {WE_SET_EARLY_RX_DRIFT_SAMPLE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "erx_dri_sample"}, + + {WE_DUMP_STATS, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "dumpStats"}, + + {WE_CLEAR_STATS, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "clearStats"}, + + {WE_START_FW_PROFILE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "startProfile"}, + + {WE_SET_CHANNEL, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "setChanChange" }, + + {WE_SET_CONC_SYSTEM_PREF, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "setConcSysPref" }, + + {WLAN_PRIV_SET_NONE_GET_INT, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + ""}, + + /* handlers for sub-ioctl */ + {WE_GET_11D_STATE, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get11Dstate"}, + + {WE_GET_WLAN_DBG, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "getwlandbg"}, + + {WE_GET_MAX_ASSOC, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "getMaxAssoc"}, + + {WE_GET_SAP_AUTO_CHANNEL_SELECTION, + 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "getAutoChannel" }, + + {WE_GET_CONCURRENCY_MODE, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "getconcurrency"}, + + {WE_GET_NSS, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_nss"}, + + {WE_GET_LDPC, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_ldpc"}, + + {WE_GET_TX_STBC, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_tx_stbc"}, + + {WE_GET_RX_STBC, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_rx_stbc"}, + + {WE_GET_SHORT_GI, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_shortgi"}, + + {WE_GET_RTSCTS, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_rtscts"}, + + {WE_GET_CHWIDTH, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_chwidth"}, + + {WE_GET_ANI_EN_DIS, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_anienable"}, + + {WE_GET_ANI_POLL_PERIOD, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_aniplen"}, + + {WE_GET_ANI_LISTEN_PERIOD, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_anilislen"}, + + {WE_GET_ANI_OFDM_LEVEL, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_aniofdmlvl"}, + + {WE_GET_ANI_CCK_LEVEL, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_aniccklvl"}, + + {WE_GET_DYNAMIC_BW, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_cwmenable"}, + + {WE_GET_GTX_HT_MCS, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_gtxHTMcs"}, + + {WE_GET_GTX_VHT_MCS, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_gtxVHTMcs"}, + + {WE_GET_GTX_USRCFG, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_gtxUsrCfg"}, + + {WE_GET_GTX_THRE, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_gtxThre"}, + + {WE_GET_GTX_MARGIN, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_gtxMargin"}, + + {WE_GET_GTX_STEP, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_gtxStep"}, + + {WE_GET_GTX_MINTPC, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_gtxMinTpc"}, + + {WE_GET_GTX_BWMASK, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_gtxBWMask"}, + + {WE_GET_TX_CHAINMASK, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_txchainmask"}, + + {WE_GET_RX_CHAINMASK, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_rxchainmask"}, + + {WE_GET_11N_RATE, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_11nrate"}, + + {WE_GET_AMPDU, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_ampdu"}, + + {WE_GET_AMSDU, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_amsdu"}, + + {WE_GET_BURST_ENABLE, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_burst_en"}, + + {WE_GET_BURST_DUR, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_burst_dur"}, + + {WE_GET_TXPOW_2G, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_txpow2g"}, + + {WE_GET_TXPOW_5G, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_txpow5g"}, + + {WE_GET_PPS_PAID_MATCH, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_paid_match"}, + + {WE_GET_PPS_GID_MATCH, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_gid_match"}, + + {WE_GET_PPS_EARLY_TIM_CLEAR, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_tim_clear"}, + + {WE_GET_PPS_EARLY_DTIM_CLEAR, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_dtim_clear"}, + + {WE_GET_PPS_EOF_PAD_DELIM, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_eof_delim"}, + + {WE_GET_PPS_MACADDR_MISMATCH, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_mac_match"}, + + {WE_GET_PPS_DELIM_CRC_FAIL, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_delim_fail"}, + + {WE_GET_PPS_GID_NSTS_ZERO, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_nsts_zero"}, + + {WE_GET_PPS_RSSI_CHECK, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_rssi_chk"}, + + {WE_GET_QPOWER_MAX_PSPOLL_COUNT, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_qpspollcnt"}, + + {WE_GET_QPOWER_MAX_TX_BEFORE_WAKE, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_qtxwake"}, + + {WE_GET_QPOWER_SPEC_PSPOLL_WAKE_INTERVAL, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_qwakeintv"}, + + {WE_GET_QPOWER_SPEC_MAX_SPEC_NODATA_PSPOLL, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_qnodatapoll"}, + + {WE_CAP_TSF, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "cap_tsf"}, + + {WE_GET_TEMPERATURE, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_temp"}, + /* handlers for main ioctl */ + {WLAN_PRIV_SET_CHAR_GET_NONE, + IW_PRIV_TYPE_CHAR | 512, + 0, + ""}, + + /* handlers for sub-ioctl */ + {WE_WOWL_ADD_PTRN, + IW_PRIV_TYPE_CHAR | 512, + 0, + "wowlAddPtrn"}, + + {WE_WOWL_DEL_PTRN, + IW_PRIV_TYPE_CHAR | 512, + 0, + "wowlDelPtrn"}, + + /* handlers for sub-ioctl */ + {WE_NEIGHBOR_REPORT_REQUEST, + IW_PRIV_TYPE_CHAR | 512, + 0, + "neighbor"}, + + {WE_SET_AP_WPS_IE, + IW_PRIV_TYPE_CHAR | 512, + 0, + "set_ap_wps_ie"}, + + {WE_SET_CONFIG, + IW_PRIV_TYPE_CHAR | 512, + 0, + "setConfig"}, + + /* handlers for main ioctl */ + {WLAN_PRIV_SET_THREE_INT_GET_NONE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 3, + 0, + ""}, + + /* handlers for sub-ioctl */ + {WE_SET_WLAN_DBG, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 3, + 0, + "setwlandbg"}, + + /* handlers for sub-ioctl */ + {WE_SET_DP_TRACE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 3, + 0, + "set_dp_trace"}, + + {WE_SET_SAP_CHANNELS, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 3, + 0, + "setsapchannels"}, + + {WE_SET_FW_TEST, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 3, + 0, "fw_test"}, + + /* handlers for main ioctl */ + {WLAN_PRIV_SET_NONE_GET_THREE_INT, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 3, + "" }, + {WE_GET_TSF, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 3, + "get_tsf" }, + + {WE_SET_DUAL_MAC_SCAN_CONFIG, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 3, + 0, + "set_scan_cfg"}, + + /* handlers for main ioctl */ + {WLAN_PRIV_GET_CHAR_SET_NONE, + 0, + IW_PRIV_TYPE_CHAR | WE_MAX_STR_LEN, + ""}, + + /* handlers for sub-ioctl */ + {WE_WLAN_VERSION, + 0, + IW_PRIV_TYPE_CHAR | WE_MAX_STR_LEN, + "version"}, + {WE_GET_STATS, + 0, + IW_PRIV_TYPE_CHAR | WE_MAX_STR_LEN, + "getStats"}, + {WE_GET_SUSPEND_RESUME_STATS, + 0, + IW_PRIV_TYPE_CHAR | WE_MAX_STR_LEN, + "getSuspendStats"}, + {WE_LIST_FW_PROFILE, + 0, + IW_PRIV_TYPE_CHAR | WE_MAX_STR_LEN, + "listProfile"}, + {WE_GET_STATES, + 0, + IW_PRIV_TYPE_CHAR | WE_MAX_STR_LEN, + "getHostStates"}, + {WE_GET_CFG, + 0, + IW_PRIV_TYPE_CHAR | WE_MAX_STR_LEN, + "getConfig"}, + {WE_GET_RSSI, + 0, + IW_PRIV_TYPE_CHAR | WE_MAX_STR_LEN, + "getRSSI"}, + {WE_GET_WMM_STATUS, + 0, + IW_PRIV_TYPE_CHAR | WE_MAX_STR_LEN, + "getWmmStatus"}, + { + WE_GET_CHANNEL_LIST, + 0, + IW_PRIV_TYPE_CHAR | WE_MAX_STR_LEN, + "getChannelList" + }, +#ifdef FEATURE_WLAN_TDLS + { + WE_GET_TDLS_PEERS, + 0, + IW_PRIV_TYPE_CHAR | WE_MAX_STR_LEN, + "getTdlsPeers" + }, +#endif +#ifdef WLAN_FEATURE_11W + { + WE_GET_11W_INFO, + 0, + IW_PRIV_TYPE_CHAR | WE_MAX_STR_LEN, + "getPMFInfo" + }, +#endif + { + WE_GET_IBSS_STA_INFO, + 0, + IW_PRIV_TYPE_CHAR | WE_MAX_STR_LEN, + "getIbssSTAs" + }, + {WE_GET_PHYMODE, + 0, + IW_PRIV_TYPE_CHAR | WE_MAX_STR_LEN, + "getphymode"}, +#ifdef FEATURE_OEM_DATA_SUPPORT + {WE_GET_OEM_DATA_CAP, + 0, + IW_PRIV_TYPE_CHAR | WE_MAX_STR_LEN, + "getOemDataCap"}, +#endif /* FEATURE_OEM_DATA_SUPPORT */ + {WE_GET_SNR, + 0, + IW_PRIV_TYPE_CHAR | WE_MAX_STR_LEN, + "getSNR"}, + + /* handlers for main ioctl */ + {WLAN_PRIV_SET_NONE_GET_NONE, + 0, + 0, + ""}, + + /* handlers for sub-ioctl */ + { + WE_IBSS_GET_PEER_INFO_ALL, + 0, + 0, + "ibssPeerInfoAll" + }, + {WE_GET_RECOVERY_STAT, + 0, + 0, + "getRecoverStat"}, + + {WE_GET_FW_PROFILE_DATA, + 0, + 0, + "getProfileData"}, + + {WE_SET_REASSOC_TRIGGER, + 0, + 0, + "reassoc"}, + + {WE_STOP_OBSS_SCAN, + 0, + 0, + "stop_obss_scan"}, + /* handlers for main ioctl */ + {WLAN_PRIV_SET_VAR_INT_GET_NONE, + IW_PRIV_TYPE_INT | MAX_VAR_ARGS, + 0, + ""}, + + /* handlers for sub-ioctl */ + {WE_IBSS_GET_PEER_INFO, + IW_PRIV_TYPE_INT | MAX_VAR_ARGS, + 0, + "ibssPeerInfo"}, + + /* handlers for sub-ioctl */ + {WE_MTRACE_SELECTIVE_MODULE_LOG_ENABLE_CMD, + IW_PRIV_TYPE_INT | MAX_VAR_ARGS, + 0, + "setdumplog"}, + + {WE_MTRACE_DUMP_CMD, + IW_PRIV_TYPE_INT | MAX_VAR_ARGS, + 0, + "dumplog"}, + + {WE_POLICY_MANAGER_CINFO_CMD, + IW_PRIV_TYPE_INT | MAX_VAR_ARGS, + 0, + "pm_cinfo"}, + +#ifdef MPC_UT_FRAMEWORK + {WE_POLICY_MANAGER_CLIST_CMD, + IW_PRIV_TYPE_INT | MAX_VAR_ARGS, + 0, + "pm_clist"}, + + {WE_POLICY_MANAGER_DLIST_CMD, + IW_PRIV_TYPE_INT | MAX_VAR_ARGS, + 0, + "pm_dlist"}, + + {WE_POLICY_MANAGER_DBS_CMD, + IW_PRIV_TYPE_INT | MAX_VAR_ARGS, + 0, + "pm_dbs"}, + + {WE_POLICY_MANAGER_PCL_CMD, + IW_PRIV_TYPE_INT | MAX_VAR_ARGS, + 0, + "pm_pcl"}, + + {WE_POLICY_MANAGER_ULIST_CMD, + IW_PRIV_TYPE_INT | MAX_VAR_ARGS, + 0, + "pm_ulist"}, + + {WE_POLICY_MANAGER_QUERY_ACTION_CMD, + IW_PRIV_TYPE_INT | MAX_VAR_ARGS, + 0, + "pm_query_action"}, + + {WE_POLICY_MANAGER_QUERY_ALLOW_CMD, + IW_PRIV_TYPE_INT | MAX_VAR_ARGS, + 0, + "pm_query_allow"}, + + {WE_POLICY_MANAGER_SCENARIO_CMD, + IW_PRIV_TYPE_INT | MAX_VAR_ARGS, + 0, + "pm_run_scenario"}, + + {WE_POLICY_SET_HW_MODE_CMD, + IW_PRIV_TYPE_INT | MAX_VAR_ARGS, + 0, + "pm_set_hw_mode"}, +#endif +#ifdef FEATURE_WLAN_TDLS + /* handlers for sub ioctl */ + { + WE_TDLS_CONFIG_PARAMS, + IW_PRIV_TYPE_INT | MAX_VAR_ARGS, + 0, + "setTdlsConfig" + }, +#endif + { + WE_UNIT_TEST_CMD, + IW_PRIV_TYPE_INT | MAX_VAR_ARGS, + 0, + "setUnitTestCmd" + }, + { + WE_MAC_PWR_DEBUG_CMD, + IW_PRIV_TYPE_INT | MAX_VAR_ARGS, + 0, + "halPwrDebug" + }, + +#ifdef WLAN_FEATURE_GPIO_LED_FLASHING + {WE_LED_FLASHING_PARAM, + IW_PRIV_TYPE_INT | MAX_VAR_ARGS, + 0, + "gpio_control"}, +#endif + /* handlers for main ioctl */ + {WLAN_PRIV_ADD_TSPEC, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | HDD_WLAN_WMM_PARAM_COUNT, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "addTspec"}, + + /* handlers for main ioctl */ + {WLAN_PRIV_DEL_TSPEC, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "delTspec"}, + + /* handlers for main ioctl */ + {WLAN_PRIV_GET_TSPEC, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "getTspec"}, + + /* handlers for main ioctl - host offload */ + { + WLAN_PRIV_SET_HOST_OFFLOAD, + IW_PRIV_TYPE_BYTE | sizeof(tHostOffloadRequest), + 0, + "setHostOffload" + } + , + + { + WLAN_GET_WLAN_STATISTICS, + 0, + IW_PRIV_TYPE_BYTE | WE_MAX_STR_LEN, + "getWlanStats" + } + , + + { + WLAN_SET_KEEPALIVE_PARAMS, + IW_PRIV_TYPE_BYTE | sizeof(tSirKeepAliveReq) | + IW_PRIV_SIZE_FIXED, + 0, + "setKeepAlive" + } + , +#ifdef WLAN_FEATURE_PACKET_FILTERING + { + WLAN_SET_PACKET_FILTER_PARAMS, + IW_PRIV_TYPE_BYTE | + sizeof(struct pkt_filter_cfg), + 0, + "setPktFilter" + } + , +#endif +#ifdef FEATURE_WLAN_SCAN_PNO + { + WLAN_SET_PNO, + IW_PRIV_TYPE_CHAR | WE_MAX_STR_LEN, + 0, + "setpno" + } + , +#endif + { + WLAN_SET_BAND_CONFIG, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "SETBAND" + } + , + { + WLAN_PRIV_SET_MCBC_FILTER, + 0, + 0, + "setMCBCFilter" + } + , + + { + WLAN_GET_LINK_SPEED, + IW_PRIV_TYPE_CHAR | 18, + IW_PRIV_TYPE_CHAR | 5, "getLinkSpeed" + } + , + + /* handlers for main ioctl */ + {WLAN_PRIV_SET_TWO_INT_GET_NONE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, + 0, + ""} + , + {WE_SET_SMPS_PARAM, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, + 0, "set_smps_param"} + , + {WLAN_SET_DOT11P_CHANNEL_SCHED, + IW_PRIV_TYPE_BYTE | sizeof(struct dot11p_channel_sched), + 0, "set_dot11p" } + , +#ifdef WLAN_DEBUG + {WE_SET_FW_CRASH_INJECT, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, + 0, "crash_inject"} + , +#endif +#ifdef WLAN_SUSPEND_RESUME_TEST + {WE_SET_WLAN_SUSPEND, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, + 0, "wlan_suspend"} + , + {WE_SET_WLAN_RESUME, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, + 0, "wlan_resume"} + , +#endif + {WE_ENABLE_FW_PROFILE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, + 0, "enableProfile"} + , + {WE_SET_FW_PROFILE_HIST_INTVL, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, + 0, "set_hist_intvl"} + , + {WE_SET_DUAL_MAC_FW_MODE_CONFIG, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, + 0, "set_fw_mode_cfg"} + , + {WE_DUMP_DP_TRACE_LEVEL, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, + 0, "dump_dp_trace"} + , + {WE_SET_MON_MODE_CHAN, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, + 0, "setMonChan"} + , + + {WE_GET_ROAM_SYNCH_DELAY, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "hostroamdelay"} + , + + {WLAN_PRIV_SET_FTIES, + IW_PRIV_TYPE_CHAR | MAX_FTIE_SIZE, + 0, + "set_ft_ies"}, +}; + +const struct iw_handler_def we_handler_def = { + .num_standard = QDF_ARRAY_SIZE(we_handler), + .num_private = QDF_ARRAY_SIZE(we_private), + .num_private_args = QDF_ARRAY_SIZE(we_private_args), + + .standard = (iw_handler *) we_handler, + .private = (iw_handler *) we_private, + .private_args = we_private_args, + .get_wireless_stats = NULL, +}; + +/* hdd_set_wext() - configures bss parameters + * @pAdapter: handle to adapter context + * + * Returns: none + */ +static int hdd_set_wext(hdd_adapter_t *pAdapter) +{ + hdd_wext_state_t *pwextBuf = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter); + hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter); + + ENTER(); + + if (!pwextBuf) { + hdd_err("ERROR: pwextBuf is NULL"); + return QDF_STATUS_E_FAILURE; + } + + if (!pHddStaCtx) { + hdd_err("ERROR: pHddStaCtx is NULL"); + return QDF_STATUS_E_FAILURE; + } + + /* Now configure the roaming profile links. To SSID and bssid. */ + pwextBuf->roamProfile.SSIDs.numOfSSIDs = 0; + pwextBuf->roamProfile.SSIDs.SSIDList = &pHddStaCtx->conn_info.SSID; + + pwextBuf->roamProfile.BSSIDs.numOfBSSIDs = 0; + pwextBuf->roamProfile.BSSIDs.bssid = &pHddStaCtx->conn_info.bssId; + + /*Set the numOfChannels to zero to scan all the channels */ + pwextBuf->roamProfile.ChannelInfo.numOfChannels = 0; + pwextBuf->roamProfile.ChannelInfo.ChannelList = NULL; + + /* Default is no encryption */ + pwextBuf->roamProfile.EncryptionType.numEntries = 1; + pwextBuf->roamProfile.EncryptionType.encryptionType[0] = + eCSR_ENCRYPT_TYPE_NONE; + + pwextBuf->roamProfile.mcEncryptionType.numEntries = 1; + pwextBuf->roamProfile.mcEncryptionType.encryptionType[0] = + eCSR_ENCRYPT_TYPE_NONE; + + pwextBuf->roamProfile.BSSType = eCSR_BSS_TYPE_INFRASTRUCTURE; + + /* Default is no authentication */ + pwextBuf->roamProfile.AuthType.numEntries = 1; + pwextBuf->roamProfile.AuthType.authType[0] = eCSR_AUTH_TYPE_OPEN_SYSTEM; + + pwextBuf->roamProfile.phyMode = eCSR_DOT11_MODE_AUTO; + pwextBuf->wpaVersion = IW_AUTH_WPA_VERSION_DISABLED; + + /*Set the default scan mode */ + pAdapter->scan_info.scan_mode = eSIR_ACTIVE_SCAN; + + hdd_clear_roam_profile_ie(pAdapter); + + EXIT(); + return QDF_STATUS_SUCCESS; + +} + +/** + * hdd_register_wext() - register wext context + * @dev: net device handle + * + * Registers wext interface context for a given net device + * + * Returns: 0 on success, errno on failure + */ +int hdd_register_wext(struct net_device *dev) +{ + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_wext_state_t *pwextBuf = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter); + QDF_STATUS status; + + ENTER(); + + if (!pwextBuf) { + hdd_err(FL("ERROR: pwextBuf is NULL")); + return QDF_STATUS_E_FAILURE; + } + + /* Zero the memory. This zeros the profile structure */ + memset(pwextBuf, 0, sizeof(hdd_wext_state_t)); + + init_completion(&(WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter))-> + completion_var); + + status = hdd_set_wext(pAdapter); + + if (!QDF_IS_STATUS_SUCCESS(status)) { + + hdd_err("ERROR: hdd_set_wext failed!!"); + return QDF_STATUS_E_FAILURE; + } + + if (!QDF_IS_STATUS_SUCCESS(qdf_event_create(&pwextBuf->hdd_qdf_event))) { + hdd_err("ERROR: HDD qdf event init failed!!"); + return QDF_STATUS_E_FAILURE; + } + + if (!QDF_IS_STATUS_SUCCESS(qdf_event_create(&pwextBuf->scanevent))) { + hdd_err("ERROR: HDD scan event init failed!!"); + return QDF_STATUS_E_FAILURE; + } + /* Register as a wireless device */ + dev->wireless_handlers = (struct iw_handler_def *)&we_handler_def; + + EXIT(); + return 0; +} + +int hdd_unregister_wext(struct net_device *dev) +{ + hdd_notice("dev(%p)", dev); + + if (dev != NULL) { + rtnl_lock(); + dev->wireless_handlers = NULL; + rtnl_unlock(); + } + + return 0; +} diff --git a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_wmm.c b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_wmm.c new file mode 100644 index 0000000000000000000000000000000000000000..dc26b9d62fe5f42a69f97a35dacbe2ba7aedd2bc --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_wmm.c @@ -0,0 +1,2380 @@ +/* + * Copyright (c) 2013-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: HDD WMM + * + * This module (wlan_hdd_wmm.h interface + wlan_hdd_wmm.c implementation) + * houses all the logic for WMM in HDD. + * + * On the control path, it has the logic to setup QoS, modify QoS and delete + * QoS (QoS here refers to a TSPEC). The setup QoS comes in two flavors: an + * explicit application invoked and an internal HDD invoked. The implicit QoS + * is for applications that do NOT call the custom QCT WLAN OIDs for QoS but + * which DO mark their traffic for priortization. It also has logic to start, + * update and stop the U-APSD trigger frame generation. It also has logic to + * read WMM related config parameters from the registry. + * + * On the data path, it has the logic to figure out the WMM AC of an egress + * packet and when to signal TL to serve a particular AC queue. It also has the + * logic to retrieve a packet based on WMM priority in response to a fetch from + * TL. + * + * The remaining functions are utility functions for information hiding. + */ + +/* Include files */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "sme_api.h" + +#define WLAN_HDD_MAX_DSCP 0x3f + +#define HDD_WMM_UP_TO_AC_MAP_SIZE 8 + +const uint8_t hdd_wmm_up_to_ac_map[] = { + SME_AC_BE, + SME_AC_BK, + SME_AC_BK, + SME_AC_BE, + SME_AC_VI, + SME_AC_VI, + SME_AC_VO, + SME_AC_VO +}; + +/** + * enum hdd_wmm_linuxac: AC/Queue Index values for Linux Qdisc to + * operate on different traffic. + */ +#ifdef QCA_LL_TX_FLOW_CONTROL_V2 +enum hdd_wmm_linuxac { + HDD_LINUX_AC_VO = 0, + HDD_LINUX_AC_VI = 1, + HDD_LINUX_AC_BE = 2, + HDD_LINUX_AC_BK = 3, + HDD_LINUX_AC_HI_PRIO = 4, +}; + +void wlan_hdd_process_peer_unauthorised_pause(hdd_adapter_t *adapter) +{ + /* Enable HI_PRIO queue */ + netif_stop_subqueue(adapter->dev, HDD_LINUX_AC_VO); + netif_stop_subqueue(adapter->dev, HDD_LINUX_AC_VI); + netif_stop_subqueue(adapter->dev, HDD_LINUX_AC_BE); + netif_stop_subqueue(adapter->dev, HDD_LINUX_AC_BK); + netif_wake_subqueue(adapter->dev, HDD_LINUX_AC_HI_PRIO); + +} +#else +enum hdd_wmm_linuxac { + HDD_LINUX_AC_VO = 0, + HDD_LINUX_AC_VI = 1, + HDD_LINUX_AC_BE = 2, + HDD_LINUX_AC_BK = 3 +}; + +void wlan_hdd_process_peer_unauthorised_pause(hdd_adapter_t *adapter) +{ + return; +} +#endif + +/* Linux based UP -> AC Mapping */ +const uint8_t hdd_linux_up_to_ac_map[HDD_WMM_UP_TO_AC_MAP_SIZE] = { + HDD_LINUX_AC_BE, + HDD_LINUX_AC_BK, + HDD_LINUX_AC_BK, + HDD_LINUX_AC_BE, + HDD_LINUX_AC_VI, + HDD_LINUX_AC_VI, + HDD_LINUX_AC_VO, + HDD_LINUX_AC_VO +}; + +#ifndef WLAN_MDM_CODE_REDUCTION_OPT +/** + * hdd_wmm_enable_tl_uapsd() - function which decides whether and + * how to update UAPSD parameters in TL + * + * @pQosContext: [in] the pointer the QoS instance control block + * + * Return: None + */ +static void hdd_wmm_enable_tl_uapsd(hdd_wmm_qos_context_t *pQosContext) +{ + hdd_adapter_t *pAdapter = pQosContext->pAdapter; + sme_ac_enum_type acType = pQosContext->acType; + hdd_wmm_ac_status_t *pAc = &pAdapter->hddWmmStatus.wmmAcStatus[acType]; + hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + QDF_STATUS status; + uint32_t service_interval; + uint32_t suspension_interval; + sme_QosWmmDirType direction; + bool psb; + + /* The TSPEC must be valid */ + if (pAc->wmmAcTspecValid == false) { + hdd_err("Invoked with invalid TSPEC"); + return; + } + /* determine the service interval */ + if (pAc->wmmAcTspecInfo.min_service_interval) { + service_interval = pAc->wmmAcTspecInfo.min_service_interval; + } else if (pAc->wmmAcTspecInfo.max_service_interval) { + service_interval = pAc->wmmAcTspecInfo.max_service_interval; + } else { + /* no service interval is present in the TSPEC */ + /* this is OK, there just won't be U-APSD */ + hdd_notice("No service interval supplied"); + service_interval = 0; + } + + /* determine the suspension interval & direction */ + suspension_interval = pAc->wmmAcTspecInfo.suspension_interval; + direction = pAc->wmmAcTspecInfo.ts_info.direction; + psb = pAc->wmmAcTspecInfo.ts_info.psb; + + /* if we have previously enabled U-APSD, have any params changed? */ + if ((pAc->wmmAcUapsdInfoValid) && + (pAc->wmmAcUapsdServiceInterval == service_interval) && + (pAc->wmmAcUapsdSuspensionInterval == suspension_interval) && + (pAc->wmmAcUapsdDirection == direction) && + (pAc->wmmAcIsUapsdEnabled == psb)) { + hdd_notice("No change in U-APSD parameters"); + return; + } + /* everything is in place to notify TL */ + status = + sme_enable_uapsd_for_ac((WLAN_HDD_GET_CTX(pAdapter))->pcds_context, + (WLAN_HDD_GET_STATION_CTX_PTR(pAdapter))-> + conn_info.staId[0], acType, + pAc->wmmAcTspecInfo.ts_info.tid, + pAc->wmmAcTspecInfo.ts_info.up, + service_interval, suspension_interval, + direction, psb, pAdapter->sessionId, + pHddCtx->config->DelayedTriggerFrmInt); + + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("Failed to enable U-APSD for AC=%d", acType); + return; + } + /* stash away the parameters that were used */ + pAc->wmmAcUapsdInfoValid = true; + pAc->wmmAcUapsdServiceInterval = service_interval; + pAc->wmmAcUapsdSuspensionInterval = suspension_interval; + pAc->wmmAcUapsdDirection = direction; + pAc->wmmAcIsUapsdEnabled = psb; + + hdd_notice("Enabled UAPSD in TL srv_int=%d susp_int=%d dir=%d AC=%d", + service_interval, suspension_interval, direction, acType); + +} + +/** + * hdd_wmm_disable_tl_uapsd() - function which decides whether + * to disable UAPSD parameters in TL + * + * @pQosContext: [in] the pointer the QoS instance control block + * + * Return: None + */ +static void hdd_wmm_disable_tl_uapsd(hdd_wmm_qos_context_t *pQosContext) +{ + hdd_adapter_t *pAdapter = pQosContext->pAdapter; + sme_ac_enum_type acType = pQosContext->acType; + hdd_wmm_ac_status_t *pAc = &pAdapter->hddWmmStatus.wmmAcStatus[acType]; + QDF_STATUS status; + + /* have we previously enabled UAPSD? */ + if (pAc->wmmAcUapsdInfoValid == true) { + status = + sme_disable_uapsd_for_ac((WLAN_HDD_GET_CTX(pAdapter))-> + pcds_context, + (WLAN_HDD_GET_STATION_CTX_PTR + (pAdapter))->conn_info.staId[0], + acType, pAdapter->sessionId); + + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("Failed to disable U-APSD for AC=%d", acType); + } else { + /* TL no longer has valid UAPSD info */ + pAc->wmmAcUapsdInfoValid = false; + hdd_notice("Disabled UAPSD in TL for AC=%d", acType); + } + } +} + +#endif + +/** + * hdd_wmm_free_context() - function which frees a QoS context + * + * @pQosContext: [in] the pointer the QoS instance control block + * + * Return: None + */ +static void hdd_wmm_free_context(hdd_wmm_qos_context_t *pQosContext) +{ + hdd_adapter_t *pAdapter; + + hdd_info("Entered, context %p", pQosContext); + + if (unlikely((NULL == pQosContext) || + (HDD_WMM_CTX_MAGIC != pQosContext->magic))) { + /* must have been freed in another thread */ + return; + } + /* get pointer to the adapter context */ + pAdapter = pQosContext->pAdapter; + + /* take the wmmLock since we're manipulating the context list */ + mutex_lock(&pAdapter->hddWmmStatus.wmmLock); + + /* make sure nobody thinks this is a valid context */ + pQosContext->magic = 0; + + /* unlink the context */ + list_del(&pQosContext->node); + + /* done manipulating the list */ + mutex_unlock(&pAdapter->hddWmmStatus.wmmLock); + + /* reclaim memory */ + qdf_mem_free(pQosContext); + +} + +#ifndef WLAN_MDM_CODE_REDUCTION_OPT +/** + * hdd_wmm_notify_app() - function which notifies an application + * of changes in state of it flow + * + * @pQosContext: [in] the pointer the QoS instance control block + * + * Return: None + */ +#define MAX_NOTIFY_LEN 50 +static void hdd_wmm_notify_app(hdd_wmm_qos_context_t *pQosContext) +{ + hdd_adapter_t *pAdapter; + union iwreq_data wrqu; + char buf[MAX_NOTIFY_LEN + 1]; + + hdd_info("Entered, context %p", pQosContext); + + if (unlikely((NULL == pQosContext) || + (HDD_WMM_CTX_MAGIC != pQosContext->magic))) { + hdd_err("Invalid QoS Context"); + return; + } + + /* create the event */ + memset(&wrqu, 0, sizeof(wrqu)); + memset(buf, 0, sizeof(buf)); + + snprintf(buf, MAX_NOTIFY_LEN, "QCOM: TS change[%u: %u]", + (unsigned int)pQosContext->handle, + (unsigned int)pQosContext->lastStatus); + + wrqu.data.pointer = buf; + wrqu.data.length = strlen(buf); + + /* get pointer to the adapter */ + pAdapter = pQosContext->pAdapter; + + /* send the event */ + hdd_notice("Sending [%s]", buf); + wireless_send_event(pAdapter->dev, IWEVCUSTOM, &wrqu, buf); +} + +#ifdef FEATURE_WLAN_ESE +/** + * hdd_wmm_inactivity_timer_cb() - inactivity timer callback function + * + * @user_data: opaque user data registered with the timer. In the + * case of this timer, the associated wmm QoS context is registered. + * + * This timer handler function is called for every inactivity interval + * per AC. This function gets the current transmitted packets on the + * given AC, and checks if there was any TX activity from the previous + * interval. If there was no traffic then it would delete the TS that + * was negotiated on that AC. + * + * Return: None + */ +static void hdd_wmm_inactivity_timer_cb(void *user_data) +{ + hdd_wmm_qos_context_t *pQosContext = user_data; + hdd_adapter_t *pAdapter; + hdd_wmm_ac_status_t *pAc; + hdd_wlan_wmm_status_e status; + QDF_STATUS qdf_status; + uint32_t currentTrafficCnt = 0; + sme_ac_enum_type acType = pQosContext->acType; + + pAdapter = pQosContext->pAdapter; + if ((NULL == pAdapter) || + (WLAN_HDD_ADAPTER_MAGIC != pAdapter->magic)) { + hdd_err("invalid pAdapter: %p", pAdapter); + return; + } + + pAc = &pAdapter->hddWmmStatus.wmmAcStatus[acType]; + + /* Get the Tx stats for this AC. */ + currentTrafficCnt = + pAdapter->hdd_stats.hddTxRxStats.txXmitClassifiedAC[pQosContext-> + acType]; + + hdd_warn("WMM inactivity Timer for AC=%d, currentCnt=%d, prevCnt=%d", + acType, (int)currentTrafficCnt, (int)pAc->wmmPrevTrafficCnt); + if (pAc->wmmPrevTrafficCnt == currentTrafficCnt) { + /* there is no traffic activity, delete the TSPEC for this AC */ + status = hdd_wmm_delts(pAdapter, pQosContext->handle); + hdd_warn("Deleted TS on AC %d, due to inactivity with status = %d!!!", + acType, status); + } else { + pAc->wmmPrevTrafficCnt = currentTrafficCnt; + if (pAc->wmmInactivityTimer.state == QDF_TIMER_STATE_STOPPED) { + /* Restart the timer */ + qdf_status = + qdf_mc_timer_start(&pAc->wmmInactivityTimer, + pAc->wmmInactivityTime); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + hdd_err("Restarting inactivity timer failed on AC %d", + acType); + } + } else { + QDF_ASSERT(qdf_mc_timer_get_current_state + (&pAc->wmmInactivityTimer) == + QDF_TIMER_STATE_STOPPED); + } + } + + return; +} + +/** + * hdd_wmm_enable_inactivity_timer() - + * function to enable the traffic inactivity timer for the given AC + * + * @pQosContext: [in] pointer to pQosContext + * @inactivityTime: [in] value of the inactivity interval in millisecs + * + * When a QoS-Tspec is successfully setup, if the inactivity interval + * time specified in the AddTS parameters is non-zero, this function + * is invoked to start a traffic inactivity timer for the given AC. + * + * Return: QDF_STATUS enumeration + */ +static QDF_STATUS +hdd_wmm_enable_inactivity_timer(hdd_wmm_qos_context_t *pQosContext, + uint32_t inactivityTime) +{ + QDF_STATUS qdf_status = QDF_STATUS_E_FAILURE; + hdd_adapter_t *pAdapter = pQosContext->pAdapter; + sme_ac_enum_type acType = pQosContext->acType; + hdd_wmm_ac_status_t *pAc; + + pAdapter = pQosContext->pAdapter; + pAc = &pAdapter->hddWmmStatus.wmmAcStatus[acType]; + + qdf_status = qdf_mc_timer_init(&pAc->wmmInactivityTimer, + QDF_TIMER_TYPE_SW, + hdd_wmm_inactivity_timer_cb, + pQosContext); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + hdd_err("Initializing inactivity timer failed on AC %d", + acType); + return qdf_status; + } + /* Start the inactivity timer */ + qdf_status = qdf_mc_timer_start(&pAc->wmmInactivityTimer, + inactivityTime); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + hdd_err("Starting inactivity timer failed on AC %d", + acType); + qdf_status = qdf_mc_timer_destroy(&pAc->wmmInactivityTimer); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + hdd_err("Failed to destroy inactivity timer"); + } + return qdf_status; + } + pAc->wmmInactivityTime = inactivityTime; + /* Initialize the current tx traffic count on this AC */ + pAc->wmmPrevTrafficCnt = + pAdapter->hdd_stats.hddTxRxStats.txXmitClassifiedAC[pQosContext-> + acType]; + pQosContext->is_inactivity_timer_running = true; + return qdf_status; +} + +/** + * hdd_wmm_disable_inactivity_timer() - + * function to disable the traffic inactivity timer for the given AC. + * + * @pQosContext: [in] pointer to pQosContext + * + * This function is invoked to disable the traffic inactivity timer + * for the given AC. This is normally done when the TS is deleted. + * + * Return: QDF_STATUS enumeration + */ +static QDF_STATUS +hdd_wmm_disable_inactivity_timer(hdd_wmm_qos_context_t *pQosContext) +{ + hdd_adapter_t *pAdapter = pQosContext->pAdapter; + sme_ac_enum_type acType = pQosContext->acType; + hdd_wmm_ac_status_t *pAc = &pAdapter->hddWmmStatus.wmmAcStatus[acType]; + QDF_STATUS qdf_status = QDF_STATUS_E_FAILURE; + + /* Clear the timer and the counter */ + pAc->wmmInactivityTime = 0; + pAc->wmmPrevTrafficCnt = 0; + + if (pQosContext->is_inactivity_timer_running == true) { + pQosContext->is_inactivity_timer_running = false; + qdf_status = qdf_mc_timer_stop(&pAc->wmmInactivityTimer); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + hdd_err("Failed to stop inactivity timer"); + return qdf_status; + } + qdf_status = qdf_mc_timer_destroy(&pAc->wmmInactivityTimer); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) + hdd_err("Failed to destroy inactivity timer:Timer started"); + } + + return qdf_status; +} +#endif /* FEATURE_WLAN_ESE */ + +/** + * hdd_wmm_sme_callback() - callback for QoS notifications + * + * @hHal: [in] the HAL handle + * @hddCtx : [in] the HDD specified handle + * @pCurrentQosInfo : [in] the TSPEC params + * @smeStatus : [in] the QoS related SME status + * @qosFlowId: [in] the unique identifier of the flow + * + * This callback is registered by HDD with SME for receiving QoS + * notifications. Even though this function has a static scope it + * gets called externally through some function pointer magic (so + * there is a need for rigorous parameter checking). + * + * Return: QDF_STATUS enumeration + */ +static QDF_STATUS hdd_wmm_sme_callback(tHalHandle hHal, + void *hddCtx, + sme_QosWmmTspecInfo *pCurrentQosInfo, + sme_QosStatusType smeStatus, + uint32_t qosFlowId) +{ + hdd_wmm_qos_context_t *pQosContext = hddCtx; + hdd_adapter_t *pAdapter; + sme_ac_enum_type acType; + hdd_wmm_ac_status_t *pAc; + + hdd_info("Entered, context %p", pQosContext); + + if (unlikely((NULL == pQosContext) || + (HDD_WMM_CTX_MAGIC != pQosContext->magic))) { + hdd_err("Invalid QoS Context"); + return QDF_STATUS_E_FAILURE; + } + + pAdapter = pQosContext->pAdapter; + acType = pQosContext->acType; + pAc = &pAdapter->hddWmmStatus.wmmAcStatus[acType]; + + hdd_info("status %d flowid %d info %p", + smeStatus, qosFlowId, pCurrentQosInfo); + + switch (smeStatus) { + + case SME_QOS_STATUS_SETUP_SUCCESS_IND: + hdd_info("Setup is complete"); + + /* there will always be a TSPEC returned with this + * status, even if a TSPEC is not exchanged OTA + */ + if (pCurrentQosInfo) { + pAc->wmmAcTspecValid = true; + memcpy(&pAc->wmmAcTspecInfo, + pCurrentQosInfo, sizeof(pAc->wmmAcTspecInfo)); + } + pAc->wmmAcAccessAllowed = true; + pAc->wmmAcAccessGranted = true; + pAc->wmmAcAccessPending = false; + pAc->wmmAcAccessFailed = false; + + if (HDD_WMM_HANDLE_IMPLICIT != pQosContext->handle) { + + hdd_notice("Explicit Qos, notifying user space"); + + /* this was triggered by an application */ + pQosContext->lastStatus = + HDD_WLAN_WMM_STATUS_SETUP_SUCCESS; + hdd_wmm_notify_app(pQosContext); + } + +#ifdef FEATURE_WLAN_ESE + /* Check if the inactivity interval is specified */ + if (pCurrentQosInfo && pCurrentQosInfo->inactivity_interval) { + hdd_notice("Inactivity timer value = %d for AC=%d", + pCurrentQosInfo->inactivity_interval, acType); + hdd_wmm_enable_inactivity_timer(pQosContext, + pCurrentQosInfo-> + inactivity_interval); + } +#endif /* FEATURE_WLAN_ESE */ + + /* notify TL to enable trigger frames if necessary */ + hdd_wmm_enable_tl_uapsd(pQosContext); + + break; + + case SME_QOS_STATUS_SETUP_SUCCESS_APSD_SET_ALREADY: + hdd_notice("Setup is complete (U-APSD set previously)"); + + pAc->wmmAcAccessAllowed = true; + pAc->wmmAcAccessGranted = true; + pAc->wmmAcAccessPending = false; + + if (HDD_WMM_HANDLE_IMPLICIT != pQosContext->handle) { + + hdd_notice("Explicit Qos, notifying user space"); + + /* this was triggered by an application */ + pQosContext->lastStatus = + HDD_WLAN_WMM_STATUS_SETUP_SUCCESS_NO_ACM_UAPSD_EXISTING; + hdd_wmm_notify_app(pQosContext); + } + + break; + + case SME_QOS_STATUS_SETUP_FAILURE_RSP: + hdd_err("Setup failed"); + /* QoS setup failed */ + + pAc->wmmAcAccessPending = false; + pAc->wmmAcAccessFailed = true; + pAc->wmmAcAccessAllowed = false; + if (HDD_WMM_HANDLE_IMPLICIT != pQosContext->handle) { + + hdd_notice("Explicit Qos, notifying user space"); + + /* this was triggered by an application */ + pQosContext->lastStatus = + HDD_WLAN_WMM_STATUS_SETUP_FAILED; + + hdd_wmm_notify_app(pQosContext); + } + + /* Setting up QoS Failed, QoS context can be released. + * SME is releasing this flow information and if HDD + * doesn't release this context, next time if + * application uses the same handle to set-up QoS, HDD + * (as it has QoS context for this handle) will issue + * Modify QoS request to SME but SME will reject as now + * it has no information for this flow. + */ + hdd_wmm_free_context(pQosContext); + break; + + case SME_QOS_STATUS_SETUP_INVALID_PARAMS_RSP: + hdd_err("Setup Invalid Params, notify TL"); + /* QoS setup failed */ + pAc->wmmAcAccessAllowed = false; + + if (HDD_WMM_HANDLE_IMPLICIT == pQosContext->handle) { + + /* we note the failure, but we also mark + * access as allowed so that the packets will + * flow. Note that the MAC will "do the right + * thing" + */ + pAc->wmmAcAccessPending = false; + pAc->wmmAcAccessFailed = true; + pAc->wmmAcAccessAllowed = true; + + } else { + hdd_notice("Explicit Qos, notifying user space"); + + /* this was triggered by an application */ + pQosContext->lastStatus = + HDD_WLAN_WMM_STATUS_SETUP_FAILED_BAD_PARAM; + hdd_wmm_notify_app(pQosContext); + } + break; + + case SME_QOS_STATUS_SETUP_NOT_QOS_AP_RSP: + hdd_err("Setup failed, not a QoS AP"); + if (HDD_WMM_HANDLE_IMPLICIT != pQosContext->handle) { + hdd_notice("Explicit Qos, notifying user space"); + + /* this was triggered by an application */ + pQosContext->lastStatus = + HDD_WLAN_WMM_STATUS_SETUP_FAILED_NO_WMM; + hdd_wmm_notify_app(pQosContext); + } + break; + + case SME_QOS_STATUS_SETUP_REQ_PENDING_RSP: + hdd_notice("Setup pending"); + /* not a callback status -- ignore if we get it */ + break; + + case SME_QOS_STATUS_SETUP_MODIFIED_IND: + hdd_notice("Setup modified"); + if (pCurrentQosInfo) { + /* update the TSPEC */ + pAc->wmmAcTspecValid = true; + memcpy(&pAc->wmmAcTspecInfo, + pCurrentQosInfo, sizeof(pAc->wmmAcTspecInfo)); + + if (HDD_WMM_HANDLE_IMPLICIT != pQosContext->handle) { + hdd_notice("Explicit Qos, notifying user space"); + + /* this was triggered by an application */ + pQosContext->lastStatus = + HDD_WLAN_WMM_STATUS_MODIFIED; + hdd_wmm_notify_app(pQosContext); + } + /* need to tell TL to update its UAPSD handling */ + hdd_wmm_enable_tl_uapsd(pQosContext); + } + break; + + case SME_QOS_STATUS_SETUP_SUCCESS_NO_ACM_NO_APSD_RSP: + if (HDD_WMM_HANDLE_IMPLICIT == pQosContext->handle) { + + /* this was triggered by implicit QoS so we + * know packets are pending + */ + pAc->wmmAcAccessPending = false; + pAc->wmmAcAccessGranted = true; + pAc->wmmAcAccessAllowed = true; + + } else { + hdd_notice("Explicit Qos, notifying user space"); + + /* this was triggered by an application */ + pQosContext->lastStatus = + HDD_WLAN_WMM_STATUS_SETUP_SUCCESS_NO_ACM_NO_UAPSD; + hdd_wmm_notify_app(pQosContext); + } + break; + + case SME_QOS_STATUS_SETUP_SUCCESS_IND_APSD_PENDING: + /* nothing to do for now */ + break; + + case SME_QOS_STATUS_SETUP_SUCCESS_IND_APSD_SET_FAILED: + hdd_err("Setup successful but U-APSD failed"); + + if (HDD_WMM_HANDLE_IMPLICIT == pQosContext->handle) { + + /* QoS setup was successful but setting U=APSD + * failed. Since the OTA part of the request + * was successful, we don't mark this as a + * failure. the packets will flow. Note that + * the MAC will "do the right thing" */ + pAc->wmmAcAccessGranted = true; + pAc->wmmAcAccessAllowed = true; + pAc->wmmAcAccessFailed = false; + pAc->wmmAcAccessPending = false; + + } else { + hdd_notice("Explicit Qos, notifying user space"); + + /* this was triggered by an application */ + pQosContext->lastStatus = + HDD_WLAN_WMM_STATUS_SETUP_UAPSD_SET_FAILED; + hdd_wmm_notify_app(pQosContext); + } + + /* Since U-APSD portion failed disabled trigger frame + * generation + */ + hdd_wmm_disable_tl_uapsd(pQosContext); + + break; + + case SME_QOS_STATUS_RELEASE_SUCCESS_RSP: + hdd_notice("Release is complete"); + + if (pCurrentQosInfo) { + hdd_notice("flows still active"); + + /* there is still at least one flow active for + * this AC so update the AC state + */ + memcpy(&pAc->wmmAcTspecInfo, + pCurrentQosInfo, sizeof(pAc->wmmAcTspecInfo)); + + /* need to tell TL to update its UAPSD handling */ + hdd_wmm_enable_tl_uapsd(pQosContext); + } else { + hdd_notice("last flow"); + + /* this is the last flow active for this AC so + * update the AC state + */ + pAc->wmmAcTspecValid = false; + + /* DELTS is successful, do not allow */ + pAc->wmmAcAccessAllowed = false; + + /* need to tell TL to update its UAPSD handling */ + hdd_wmm_disable_tl_uapsd(pQosContext); + } + + if (HDD_WMM_HANDLE_IMPLICIT != pQosContext->handle) { + hdd_notice("Explicit Qos, notifying user space"); + + /* this was triggered by an application */ + pQosContext->lastStatus = + HDD_WLAN_WMM_STATUS_RELEASE_SUCCESS; + hdd_wmm_notify_app(pQosContext); + } + /* we are done with this flow */ + hdd_wmm_free_context(pQosContext); + break; + + case SME_QOS_STATUS_RELEASE_FAILURE_RSP: + hdd_notice("Release failure"); + + /* we don't need to update our state or TL since + * nothing has changed + */ + if (HDD_WMM_HANDLE_IMPLICIT != pQosContext->handle) { + hdd_notice("Explicit Qos, notifying user space"); + + /* this was triggered by an application */ + pQosContext->lastStatus = + HDD_WLAN_WMM_STATUS_RELEASE_FAILED; + hdd_wmm_notify_app(pQosContext); + } + + break; + + case SME_QOS_STATUS_RELEASE_QOS_LOST_IND: + hdd_notice("QOS Lost indication received"); + + /* current TSPEC is no longer valid */ + pAc->wmmAcTspecValid = false; + /* AP has sent DELTS, do not allow */ + pAc->wmmAcAccessAllowed = false; + + /* need to tell TL to update its UAPSD handling */ + hdd_wmm_disable_tl_uapsd(pQosContext); + + if (HDD_WMM_HANDLE_IMPLICIT == pQosContext->handle) { + /* we no longer have implicit access granted */ + pAc->wmmAcAccessGranted = false; + pAc->wmmAcAccessFailed = false; + } else { + hdd_info("Explicit Qos, notifying user space"); + + /* this was triggered by an application */ + pQosContext->lastStatus = HDD_WLAN_WMM_STATUS_LOST; + hdd_wmm_notify_app(pQosContext); + } + + /* we are done with this flow */ + hdd_wmm_free_context(pQosContext); + break; + + case SME_QOS_STATUS_RELEASE_REQ_PENDING_RSP: + hdd_info("Release pending"); + /* not a callback status -- ignore if we get it */ + break; + + case SME_QOS_STATUS_RELEASE_INVALID_PARAMS_RSP: + hdd_err("Release Invalid Params"); + if (HDD_WMM_HANDLE_IMPLICIT != pQosContext->handle) { + /* this was triggered by an application */ + pQosContext->lastStatus = + HDD_WLAN_WMM_STATUS_RELEASE_FAILED_BAD_PARAM; + hdd_wmm_notify_app(pQosContext); + } + break; + + case SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_IND: + hdd_info("Modification is complete, notify TL"); + + /* there will always be a TSPEC returned with this + * status, even if a TSPEC is not exchanged OTA + */ + if (pCurrentQosInfo) { + pAc->wmmAcTspecValid = true; + memcpy(&pAc->wmmAcTspecInfo, + pCurrentQosInfo, sizeof(pAc->wmmAcTspecInfo)); + } + + if (HDD_WMM_HANDLE_IMPLICIT != pQosContext->handle) { + /* this was triggered by an application */ + pQosContext->lastStatus = + HDD_WLAN_WMM_STATUS_MODIFY_SUCCESS; + hdd_wmm_notify_app(pQosContext); + } + /* notify TL to enable trigger frames if necessary */ + hdd_wmm_enable_tl_uapsd(pQosContext); + + break; + + case SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_APSD_SET_ALREADY: + if (HDD_WMM_HANDLE_IMPLICIT != pQosContext->handle) { + /* this was triggered by an application */ + pQosContext->lastStatus = + HDD_WLAN_WMM_STATUS_MODIFY_SUCCESS_NO_ACM_UAPSD_EXISTING; + hdd_wmm_notify_app(pQosContext); + } + break; + + case SME_QOS_STATUS_MODIFY_SETUP_FAILURE_RSP: + /* the flow modification failed so we'll leave in + * place whatever existed beforehand + */ + + if (HDD_WMM_HANDLE_IMPLICIT != pQosContext->handle) { + /* this was triggered by an application */ + pQosContext->lastStatus = + HDD_WLAN_WMM_STATUS_MODIFY_FAILED; + hdd_wmm_notify_app(pQosContext); + } + break; + + case SME_QOS_STATUS_MODIFY_SETUP_PENDING_RSP: + hdd_info("modification pending"); + /* not a callback status -- ignore if we get it */ + break; + + case SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_NO_ACM_NO_APSD_RSP: + /* the flow modification was successful but no QoS + * changes required + */ + + if (HDD_WMM_HANDLE_IMPLICIT != pQosContext->handle) { + /* this was triggered by an application */ + pQosContext->lastStatus = + HDD_WLAN_WMM_STATUS_MODIFY_SUCCESS_NO_ACM_NO_UAPSD; + hdd_wmm_notify_app(pQosContext); + } + break; + + case SME_QOS_STATUS_MODIFY_SETUP_INVALID_PARAMS_RSP: + /* invalid params -- notify the application */ + if (HDD_WMM_HANDLE_IMPLICIT != pQosContext->handle) { + /* this was triggered by an application */ + pQosContext->lastStatus = + HDD_WLAN_WMM_STATUS_MODIFY_FAILED_BAD_PARAM; + hdd_wmm_notify_app(pQosContext); + } + break; + + case SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_IND_APSD_PENDING: + /* nothing to do for now. when APSD is established we'll have work to do */ + break; + + case SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_IND_APSD_SET_FAILED: + hdd_err("Modify successful but U-APSD failed"); + + /* QoS modification was successful but setting U=APSD + * failed. This will always be an explicit QoS + * instance, so all we can do is notify the + * application and let it clean up. + */ + if (HDD_WMM_HANDLE_IMPLICIT != pQosContext->handle) { + /* this was triggered by an application */ + pQosContext->lastStatus = + HDD_WLAN_WMM_STATUS_MODIFY_UAPSD_SET_FAILED; + hdd_wmm_notify_app(pQosContext); + } + /* Since U-APSD portion failed disabled trigger frame + * generation + */ + hdd_wmm_disable_tl_uapsd(pQosContext); + + break; + + case SME_QOS_STATUS_HANDING_OFF: + /* no roaming so we won't see this */ + break; + + case SME_QOS_STATUS_OUT_OF_APSD_POWER_MODE_IND: + /* need to tell TL to stop trigger frame generation */ + hdd_wmm_disable_tl_uapsd(pQosContext); + break; + + case SME_QOS_STATUS_INTO_APSD_POWER_MODE_IND: + /* need to tell TL to start sending trigger frames again */ + hdd_wmm_enable_tl_uapsd(pQosContext); + break; + + default: + hdd_err("unexpected SME Status=%d", smeStatus); + QDF_ASSERT(0); + } + + /* if Tspec only allows downstream traffic then access is not + * allowed + */ + if (pAc->wmmAcTspecValid && + (pAc->wmmAcTspecInfo.ts_info.direction == + SME_QOS_WMM_TS_DIR_DOWNLINK)) { + pAc->wmmAcAccessAllowed = false; + } + /* if we have valid Tpsec or if ACM bit is not set, allow access */ + if ((pAc->wmmAcTspecValid && + (pAc->wmmAcTspecInfo.ts_info.direction != + SME_QOS_WMM_TS_DIR_DOWNLINK)) || !pAc->wmmAcAccessRequired) { + pAc->wmmAcAccessAllowed = true; + } + + hdd_notice("complete, access for TL AC %d is%sallowed", + acType, pAc->wmmAcAccessAllowed ? " " : " not "); + + return QDF_STATUS_SUCCESS; +} +#endif + +/** + * hdd_wmmps_helper() - Function to set uapsd psb dynamically + * + * @pAdapter: [in] pointer to adapter structure + * @ptr: [in] pointer to command buffer + * + * Return: Zero on success, appropriate error on failure. + */ +int hdd_wmmps_helper(hdd_adapter_t *pAdapter, uint8_t *ptr) +{ + if (NULL == pAdapter) { + hdd_err("pAdapter is NULL"); + return -EINVAL; + } + if (NULL == ptr) { + hdd_err("ptr is NULL"); + return -EINVAL; + } + /* convert ASCII to integer */ + pAdapter->configuredPsb = ptr[9] - '0'; + pAdapter->psbChanged = HDD_PSB_CHANGED; + + return 0; +} + +/** + * __hdd_wmm_do_implicit_qos() - Function which will attempt to setup + * QoS for any AC requiring it. + * @work: [in] pointer to work structure. + * + * Return: none + */ +static void __hdd_wmm_do_implicit_qos(struct work_struct *work) +{ + hdd_wmm_qos_context_t *pQosContext = + container_of(work, hdd_wmm_qos_context_t, wmmAcSetupImplicitQos); + hdd_adapter_t *pAdapter; + sme_ac_enum_type acType; + hdd_wmm_ac_status_t *pAc; +#ifndef WLAN_MDM_CODE_REDUCTION_OPT + sme_QosStatusType smeStatus; +#endif + sme_QosWmmTspecInfo qosInfo; + hdd_context_t *hdd_ctx; + + hdd_info("Entered, context %p", pQosContext); + + if (unlikely(HDD_WMM_CTX_MAGIC != pQosContext->magic)) { + hdd_err("Invalid QoS Context"); + return; + } + + pAdapter = pQosContext->pAdapter; + + hdd_ctx = WLAN_HDD_GET_CTX(pAdapter); + if (wlan_hdd_validate_context(hdd_ctx)) + return; + + acType = pQosContext->acType; + pAc = &pAdapter->hddWmmStatus.wmmAcStatus[acType]; + + hdd_info("pAdapter %p acType %d", pAdapter, acType); + + if (!pAc->wmmAcAccessNeeded) { + hdd_err("AC %d doesn't need service", acType); + pQosContext->magic = 0; + qdf_mem_free(pQosContext); + return; + } + + pAc->wmmAcAccessPending = true; + pAc->wmmAcAccessNeeded = false; + + memset(&qosInfo, 0, sizeof(qosInfo)); + + qosInfo.ts_info.psb = pAdapter->configuredPsb; + + switch (acType) { + case SME_AC_VO: + qosInfo.ts_info.up = SME_QOS_WMM_UP_VO; + /* Check if there is any valid configuration from framework */ + if (HDD_PSB_CFG_INVALID == pAdapter->configuredPsb) { + qosInfo.ts_info.psb = + ((WLAN_HDD_GET_CTX(pAdapter))->config-> + UapsdMask & SME_QOS_UAPSD_VO) ? 1 : 0; + } + qosInfo.ts_info.direction = + (WLAN_HDD_GET_CTX(pAdapter))->config->InfraDirAcVo; + qosInfo.ts_info.tid = 255; + qosInfo.mean_data_rate = + (WLAN_HDD_GET_CTX(pAdapter))->config-> + InfraMeanDataRateAcVo; + qosInfo.min_phy_rate = + (WLAN_HDD_GET_CTX(pAdapter))->config->InfraMinPhyRateAcVo; + qosInfo.min_service_interval = + (WLAN_HDD_GET_CTX(pAdapter))->config->InfraUapsdVoSrvIntv; + qosInfo.nominal_msdu_size = + (WLAN_HDD_GET_CTX(pAdapter))->config->InfraNomMsduSizeAcVo; + qosInfo.surplus_bw_allowance = + (WLAN_HDD_GET_CTX(pAdapter))->config->InfraSbaAcVo; + qosInfo.suspension_interval = + (WLAN_HDD_GET_CTX(pAdapter))->config->InfraUapsdVoSuspIntv; + break; + case SME_AC_VI: + qosInfo.ts_info.up = SME_QOS_WMM_UP_VI; + /* Check if there is any valid configuration from framework */ + if (HDD_PSB_CFG_INVALID == pAdapter->configuredPsb) { + qosInfo.ts_info.psb = + ((WLAN_HDD_GET_CTX(pAdapter))->config-> + UapsdMask & SME_QOS_UAPSD_VI) ? 1 : 0; + } + qosInfo.ts_info.direction = + (WLAN_HDD_GET_CTX(pAdapter))->config->InfraDirAcVi; + qosInfo.ts_info.tid = 255; + qosInfo.mean_data_rate = + (WLAN_HDD_GET_CTX(pAdapter))->config-> + InfraMeanDataRateAcVi; + qosInfo.min_phy_rate = + (WLAN_HDD_GET_CTX(pAdapter))->config->InfraMinPhyRateAcVi; + qosInfo.min_service_interval = + (WLAN_HDD_GET_CTX(pAdapter))->config->InfraUapsdViSrvIntv; + qosInfo.nominal_msdu_size = + (WLAN_HDD_GET_CTX(pAdapter))->config->InfraNomMsduSizeAcVi; + qosInfo.surplus_bw_allowance = + (WLAN_HDD_GET_CTX(pAdapter))->config->InfraSbaAcVi; + qosInfo.suspension_interval = + (WLAN_HDD_GET_CTX(pAdapter))->config->InfraUapsdViSuspIntv; + break; + default: + case SME_AC_BE: + qosInfo.ts_info.up = SME_QOS_WMM_UP_BE; + /* Check if there is any valid configuration from framework */ + if (HDD_PSB_CFG_INVALID == pAdapter->configuredPsb) { + qosInfo.ts_info.psb = + ((WLAN_HDD_GET_CTX(pAdapter))->config-> + UapsdMask & SME_QOS_UAPSD_BE) ? 1 : 0; + } + qosInfo.ts_info.direction = + (WLAN_HDD_GET_CTX(pAdapter))->config->InfraDirAcBe; + qosInfo.ts_info.tid = 255; + qosInfo.mean_data_rate = + (WLAN_HDD_GET_CTX(pAdapter))->config-> + InfraMeanDataRateAcBe; + qosInfo.min_phy_rate = + (WLAN_HDD_GET_CTX(pAdapter))->config->InfraMinPhyRateAcBe; + qosInfo.min_service_interval = + (WLAN_HDD_GET_CTX(pAdapter))->config->InfraUapsdBeSrvIntv; + qosInfo.nominal_msdu_size = + (WLAN_HDD_GET_CTX(pAdapter))->config->InfraNomMsduSizeAcBe; + qosInfo.surplus_bw_allowance = + (WLAN_HDD_GET_CTX(pAdapter))->config->InfraSbaAcBe; + qosInfo.suspension_interval = + (WLAN_HDD_GET_CTX(pAdapter))->config->InfraUapsdBeSuspIntv; + break; + case SME_AC_BK: + qosInfo.ts_info.up = SME_QOS_WMM_UP_BK; + /* Check if there is any valid configuration from framework */ + if (HDD_PSB_CFG_INVALID == pAdapter->configuredPsb) { + qosInfo.ts_info.psb = + ((WLAN_HDD_GET_CTX(pAdapter))->config-> + UapsdMask & SME_QOS_UAPSD_BK) ? 1 : 0; + } + qosInfo.ts_info.direction = + (WLAN_HDD_GET_CTX(pAdapter))->config->InfraDirAcBk; + qosInfo.ts_info.tid = 255; + qosInfo.mean_data_rate = + (WLAN_HDD_GET_CTX(pAdapter))->config-> + InfraMeanDataRateAcBk; + qosInfo.min_phy_rate = + (WLAN_HDD_GET_CTX(pAdapter))->config->InfraMinPhyRateAcBk; + qosInfo.min_service_interval = + (WLAN_HDD_GET_CTX(pAdapter))->config->InfraUapsdBkSrvIntv; + qosInfo.nominal_msdu_size = + (WLAN_HDD_GET_CTX(pAdapter))->config->InfraNomMsduSizeAcBk; + qosInfo.surplus_bw_allowance = + (WLAN_HDD_GET_CTX(pAdapter))->config->InfraSbaAcBk; + qosInfo.suspension_interval = + (WLAN_HDD_GET_CTX(pAdapter))->config->InfraUapsdBkSuspIntv; + break; + } +#ifdef FEATURE_WLAN_ESE + qosInfo.inactivity_interval = + (WLAN_HDD_GET_CTX(pAdapter))->config->InfraInactivityInterval; +#endif + qosInfo.ts_info.burst_size_defn = + (WLAN_HDD_GET_CTX(pAdapter))->config->burstSizeDefinition; + + switch ((WLAN_HDD_GET_CTX(pAdapter))->config->tsInfoAckPolicy) { + case HDD_WLAN_WMM_TS_INFO_ACK_POLICY_NORMAL_ACK: + qosInfo.ts_info.ack_policy = + SME_QOS_WMM_TS_ACK_POLICY_NORMAL_ACK; + break; + + case HDD_WLAN_WMM_TS_INFO_ACK_POLICY_HT_IMMEDIATE_BLOCK_ACK: + qosInfo.ts_info.ack_policy = + SME_QOS_WMM_TS_ACK_POLICY_HT_IMMEDIATE_BLOCK_ACK; + break; + + default: + /* unknown */ + qosInfo.ts_info.ack_policy = + SME_QOS_WMM_TS_ACK_POLICY_NORMAL_ACK; + } + + if (qosInfo.ts_info.ack_policy == + SME_QOS_WMM_TS_ACK_POLICY_HT_IMMEDIATE_BLOCK_ACK) { + if (!sme_qos_is_ts_info_ack_policy_valid + ((tpAniSirGlobal) WLAN_HDD_GET_HAL_CTX(pAdapter), &qosInfo, + pAdapter->sessionId)) { + qosInfo.ts_info.ack_policy = + SME_QOS_WMM_TS_ACK_POLICY_NORMAL_ACK; + } + } + + mutex_lock(&pAdapter->hddWmmStatus.wmmLock); + list_add(&pQosContext->node, &pAdapter->hddWmmStatus.wmmContextList); + mutex_unlock(&pAdapter->hddWmmStatus.wmmLock); + +#ifndef WLAN_MDM_CODE_REDUCTION_OPT + smeStatus = sme_qos_setup_req(WLAN_HDD_GET_HAL_CTX(pAdapter), + pAdapter->sessionId, + &qosInfo, + hdd_wmm_sme_callback, + pQosContext, + qosInfo.ts_info.up, + &pQosContext->qosFlowId); + + hdd_notice("sme_qos_setup_req returned %d flowid %d", + smeStatus, pQosContext->qosFlowId); + + /* need to check the return values and act appropriately */ + switch (smeStatus) { + case SME_QOS_STATUS_SETUP_REQ_PENDING_RSP: + case SME_QOS_STATUS_SETUP_SUCCESS_IND_APSD_PENDING: + /* setup is pending, so no more work to do now. all + * further work will be done in hdd_wmm_sme_callback() + */ + hdd_info("Setup is pending, no further work"); + + break; + + case SME_QOS_STATUS_SETUP_FAILURE_RSP: + /* we can't tell the difference between when a request + * fails because AP rejected it versus when SME + * encountered an internal error. in either case SME + * won't ever reference this context so free the + * record + */ + hdd_wmm_free_context(pQosContext); + + /* fall through and start packets flowing */ + case SME_QOS_STATUS_SETUP_SUCCESS_NO_ACM_NO_APSD_RSP: + /* no ACM in effect, no need to setup U-APSD */ + case SME_QOS_STATUS_SETUP_SUCCESS_APSD_SET_ALREADY: + /* no ACM in effect, U-APSD is desired but was already setup */ + + /* for these cases everything is already setup so we + * can signal TL that it has work to do + */ + hdd_info("Setup is complete, notify TL"); + + pAc->wmmAcAccessAllowed = true; + pAc->wmmAcAccessGranted = true; + pAc->wmmAcAccessPending = false; + + break; + + default: + hdd_err("unexpected SME Status=%d", smeStatus); + QDF_ASSERT(0); + } +#endif + +} + +/** + * hdd_wmm_do_implicit_qos() - SSR wraper function for hdd_wmm_do_implicit_qos + * @work: pointer to work_struct + * + * Return: none + */ +static void hdd_wmm_do_implicit_qos(struct work_struct *work) +{ + cds_ssr_protect(__func__); + __hdd_wmm_do_implicit_qos(work); + cds_ssr_unprotect(__func__); +} + +/** + * hdd_wmm_init() - initialize the WMM DSCP configuation + * @pAdapter : [in] pointer to Adapter context + * + * This function will initialize the WMM DSCP configuation of an + * adapter to an initial state. The configuration can later be + * overwritten via application APIs or via QoS Map sent OTA. + * + * Return: QDF_STATUS enumeration + */ +QDF_STATUS hdd_wmm_init(hdd_adapter_t *pAdapter) +{ + sme_QosWmmUpType *hddWmmDscpToUpMap = pAdapter->hddWmmDscpToUpMap; + uint8_t dscp; + + hdd_info("Entered"); + + /* DSCP to User Priority Lookup Table + * By default use the 3 Precedence bits of DSCP as the User Priority + */ + for (dscp = 0; dscp <= WLAN_HDD_MAX_DSCP; dscp++) { + hddWmmDscpToUpMap[dscp] = dscp >> 3; + } + + /* Special case for Expedited Forwarding (DSCP 46) */ + hddWmmDscpToUpMap[46] = SME_QOS_WMM_UP_VO; + + return QDF_STATUS_SUCCESS; +} + +/** + * hdd_wmm_adapter_init() - initialize the WMM configuration of an adapter + * @pAdapter: [in] pointer to Adapter context + * + * This function will initialize the WMM configuation and status of an + * adapter to an initial state. The configuration can later be + * overwritten via application APIs + * + * Return: QDF_STATUS enumeration + */ +QDF_STATUS hdd_wmm_adapter_init(hdd_adapter_t *pAdapter) +{ + hdd_wmm_ac_status_t *pAcStatus; + sme_ac_enum_type acType; + + hdd_info("Entered"); + + pAdapter->hddWmmStatus.wmmQap = false; + INIT_LIST_HEAD(&pAdapter->hddWmmStatus.wmmContextList); + mutex_init(&pAdapter->hddWmmStatus.wmmLock); + + for (acType = 0; acType < WLAN_MAX_AC; acType++) { + pAcStatus = &pAdapter->hddWmmStatus.wmmAcStatus[acType]; + pAcStatus->wmmAcAccessRequired = false; + pAcStatus->wmmAcAccessNeeded = false; + pAcStatus->wmmAcAccessPending = false; + pAcStatus->wmmAcAccessFailed = false; + pAcStatus->wmmAcAccessGranted = false; + pAcStatus->wmmAcAccessAllowed = false; + pAcStatus->wmmAcTspecValid = false; + pAcStatus->wmmAcUapsdInfoValid = false; + } + /* Invalid value(0xff) to indicate psb not configured through + * framework initially. + */ + pAdapter->configuredPsb = HDD_PSB_CFG_INVALID; + + return QDF_STATUS_SUCCESS; +} + +/** + * hdd_wmm_adapter_clear() - Function which will clear the WMM status + * for all the ACs + * + * @pAdapter: [in] pointer to Adapter context + * + * Return: QDF_STATUS enumeration + */ +QDF_STATUS hdd_wmm_adapter_clear(hdd_adapter_t *pAdapter) +{ + hdd_wmm_ac_status_t *pAcStatus; + sme_ac_enum_type acType; + + hdd_info("Entered"); + for (acType = 0; acType < WLAN_MAX_AC; acType++) { + pAcStatus = &pAdapter->hddWmmStatus.wmmAcStatus[acType]; + pAcStatus->wmmAcAccessRequired = false; + pAcStatus->wmmAcAccessNeeded = false; + pAcStatus->wmmAcAccessPending = false; + pAcStatus->wmmAcAccessFailed = false; + pAcStatus->wmmAcAccessGranted = false; + pAcStatus->wmmAcAccessAllowed = false; + pAcStatus->wmmAcTspecValid = false; + pAcStatus->wmmAcUapsdInfoValid = false; + } + return QDF_STATUS_SUCCESS; +} + +/** + * hdd_wmm_close() - WMM close function + * @pAdapter: [in] pointer to adapter context + * + * Function which will perform any necessary work to to clean up the + * WMM functionality prior to the kernel module unload. + * + * Return: QDF_STATUS enumeration + */ +QDF_STATUS hdd_wmm_adapter_close(hdd_adapter_t *pAdapter) +{ + hdd_wmm_qos_context_t *pQosContext; + + hdd_info("Entered"); + + /* free any context records that we still have linked */ + while (!list_empty(&pAdapter->hddWmmStatus.wmmContextList)) { + pQosContext = + list_first_entry(&pAdapter->hddWmmStatus.wmmContextList, + hdd_wmm_qos_context_t, node); +#ifdef FEATURE_WLAN_ESE + hdd_wmm_disable_inactivity_timer(pQosContext); +#endif + if (pQosContext->handle == HDD_WMM_HANDLE_IMPLICIT + && pQosContext->magic == HDD_WMM_CTX_MAGIC) + cds_flush_work(&pQosContext->wmmAcSetupImplicitQos); + + hdd_wmm_free_context(pQosContext); + } + + return QDF_STATUS_SUCCESS; +} + +/** + * hdd_wmm_classify_pkt() - Function which will classify an OS packet + * into a WMM AC based on DSCP + * + * @adapter: adapter upon which the packet is being transmitted + * @skb: pointer to network buffer + * @user_pri: user priority of the OS packet + * @is_eapol: eapol packet flag + * + * Return: None + */ +static +void hdd_wmm_classify_pkt(hdd_adapter_t *adapter, + struct sk_buff *skb, + sme_QosWmmUpType *user_pri, + bool *is_eapol) +{ + unsigned char dscp; + unsigned char tos; + union generic_ethhdr *eth_hdr; + struct iphdr *ip_hdr; + struct ipv6hdr *ipv6hdr; + unsigned char *pkt; + + /* this code is executed for every packet therefore + * all debug code is kept conditional + */ + +#ifdef HDD_WMM_DEBUG + hdd_info("Entered"); +#endif /* HDD_WMM_DEBUG */ + + pkt = skb->data; + eth_hdr = (union generic_ethhdr *)pkt; + +#ifdef HDD_WMM_DEBUG + hdd_info("proto is 0x%04x", skb->protocol); +#endif /* HDD_WMM_DEBUG */ + + if (eth_hdr->eth_II.h_proto == htons(ETH_P_IP)) { + /* case 1: Ethernet II IP packet */ + ip_hdr = (struct iphdr *)&pkt[sizeof(eth_hdr->eth_II)]; + tos = ip_hdr->tos; +#ifdef HDD_WMM_DEBUG + hdd_info("Ethernet II IP Packet, tos is %d", tos); +#endif /* HDD_WMM_DEBUG */ + + } else if (eth_hdr->eth_II.h_proto == htons(ETH_P_IPV6)) { + ipv6hdr = ipv6_hdr(skb); + tos = ntohs(*(const __be16 *)ipv6hdr) >> 4; +#ifdef HDD_WMM_DEBUG + hdd_info("Ethernet II IPv6 Packet, tos is %d", tos); +#endif /* HDD_WMM_DEBUG */ + } else if ((ntohs(eth_hdr->eth_II.h_proto) < WLAN_MIN_PROTO) && + (eth_hdr->eth_8023.h_snap.dsap == WLAN_SNAP_DSAP) && + (eth_hdr->eth_8023.h_snap.ssap == WLAN_SNAP_SSAP) && + (eth_hdr->eth_8023.h_snap.ctrl == WLAN_SNAP_CTRL) && + (eth_hdr->eth_8023.h_proto == htons(ETH_P_IP))) { + /* case 2: 802.3 LLC/SNAP IP packet */ + ip_hdr = (struct iphdr *)&pkt[sizeof(eth_hdr->eth_8023)]; + tos = ip_hdr->tos; +#ifdef HDD_WMM_DEBUG + hdd_info("802.3 LLC/SNAP IP Packet, tos is %d", tos); +#endif /* HDD_WMM_DEBUG */ + } else if (eth_hdr->eth_II.h_proto == htons(ETH_P_8021Q)) { + /* VLAN tagged */ + + if (eth_hdr->eth_IIv.h_vlan_encapsulated_proto == + htons(ETH_P_IP)) { + /* case 3: Ethernet II vlan-tagged IP packet */ + ip_hdr = + (struct iphdr *) + &pkt[sizeof(eth_hdr->eth_IIv)]; + tos = ip_hdr->tos; +#ifdef HDD_WMM_DEBUG + hdd_info("Ethernet II VLAN tagged IP Packet, tos is %d", + tos); +#endif /* HDD_WMM_DEBUG */ + } else + if ((ntohs(eth_hdr->eth_IIv.h_vlan_encapsulated_proto) + < WLAN_MIN_PROTO) + && (eth_hdr->eth_8023v.h_snap.dsap == + WLAN_SNAP_DSAP) + && (eth_hdr->eth_8023v.h_snap.ssap == + WLAN_SNAP_SSAP) + && (eth_hdr->eth_8023v.h_snap.ctrl == + WLAN_SNAP_CTRL) + && (eth_hdr->eth_8023v.h_proto == + htons(ETH_P_IP))) { + /* case 4: 802.3 LLC/SNAP vlan-tagged IP packet */ + ip_hdr = + (struct iphdr *) + &pkt[sizeof(eth_hdr->eth_8023v)]; + tos = ip_hdr->tos; +#ifdef HDD_WMM_DEBUG + hdd_info("802.3 LLC/SNAP VLAN tagged IP Packet, tos is %d", + tos); +#endif /* HDD_WMM_DEBUG */ + } else { + /* default */ +#ifdef HDD_WMM_DEBUG + hdd_warn("VLAN tagged Unhandled Protocol, using default tos"); +#endif /* HDD_WMM_DEBUG */ + tos = 0; + } + } else { + /* default */ +#ifdef HDD_WMM_DEBUG + hdd_warn("Unhandled Protocol, using default tos"); +#endif /* HDD_WMM_DEBUG */ + /* Give the highest priority to 802.1x packet */ + if (eth_hdr->eth_II.h_proto == + htons(HDD_ETHERTYPE_802_1_X)) { + tos = 0xC0; + *is_eapol = true; + } else + tos = 0; + } + + dscp = (tos >> 2) & 0x3f; + *user_pri = adapter->hddWmmDscpToUpMap[dscp]; + +#ifdef HDD_WMM_DEBUG + hdd_notice("tos is %d, dscp is %d, up is %d", tos, dscp, *user_pri); +#endif /* HDD_WMM_DEBUG */ + + return; +} + +/** + * __hdd_get_queue_index() - get queue index + * @up: user priority + * + * Return: queue_index + */ +static uint16_t __hdd_get_queue_index(uint16_t up) +{ + if (qdf_unlikely(up >= ARRAY_SIZE(hdd_linux_up_to_ac_map))) + return HDD_LINUX_AC_BE; + return hdd_linux_up_to_ac_map[up]; +} + +#ifdef QCA_LL_TX_FLOW_CONTROL_V2 +/** + * hdd_get_queue_index() - get queue index + * @up: user priority + * @is_eapol: is_eapol flag + * + * Return: queue_index + */ +static +uint16_t hdd_get_queue_index(uint16_t up, bool is_eapol) +{ + if (qdf_unlikely(is_eapol == true)) + return HDD_LINUX_AC_HI_PRIO; + return __hdd_get_queue_index(up); +} +#else +static +uint16_t hdd_get_queue_index(uint16_t up, bool is_eapol) +{ + return __hdd_get_queue_index(up); +} +#endif + + +/** + * hdd_hostapd_select_queue() - Function which will classify the packet + * according to linux qdisc expectation. + * + * @dev: [in] pointer to net_device structure + * @skb: [in] pointer to os packet + * + * Return: Qdisc queue index + */ +uint16_t hdd_hostapd_select_queue(struct net_device *dev, struct sk_buff *skb +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0)) + , void *accel_priv +#endif +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) + , select_queue_fallback_t fallback +#endif + +) +{ + sme_QosWmmUpType up = SME_QOS_WMM_UP_BE; + uint16_t queueIndex; + hdd_adapter_t *adapter = (hdd_adapter_t *) netdev_priv(dev); + hdd_context_t *hddctx = WLAN_HDD_GET_CTX(adapter); + bool is_eapol = false; + int status = 0; + status = wlan_hdd_validate_context(hddctx); + + if (status != 0) { + skb->priority = SME_QOS_WMM_UP_BE; + return HDD_LINUX_AC_BE; + } + + /* Get the user priority from IP header */ + hdd_wmm_classify_pkt(adapter, skb, &up, &is_eapol); + skb->priority = up; + queueIndex = hdd_get_queue_index(skb->priority, is_eapol); + + return queueIndex; +} + +/** + * hdd_wmm_select_queue() - Function which will classify the packet + * according to linux qdisc expectation. + * + * @dev: [in] pointer to net_device structure + * @skb: [in] pointer to os packet + * + * Return: Qdisc queue index + */ +uint16_t hdd_wmm_select_queue(struct net_device *dev, struct sk_buff *skb) +{ + sme_QosWmmUpType up = SME_QOS_WMM_UP_BE; + uint16_t queueIndex; + hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev); + bool is_eapol = false; + hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(pAdapter); + int status; + + status = wlan_hdd_validate_context(hdd_ctx); + if (status != 0) { + skb->priority = SME_QOS_WMM_UP_BE; + return HDD_LINUX_AC_BE; + } + + /* Get the user priority from IP header */ + hdd_wmm_classify_pkt(pAdapter, skb, &up, &is_eapol); + skb->priority = up; + queueIndex = hdd_get_queue_index(skb->priority, is_eapol); + + return queueIndex; +} + +/** + * hdd_wmm_acquire_access_required() - Function which will determine + * acquire admittance for a WMM AC is required or not based on psb configuration + * done in framework + * + * @pAdapter: [in] pointer to adapter structure + * @acType: [in] WMM AC type of OS packet + * + * Return: void + */ +void hdd_wmm_acquire_access_required(hdd_adapter_t *pAdapter, + sme_ac_enum_type acType) +{ + /* Each bit in the LSB nibble indicates 1 AC. + * Clearing the particular bit in LSB nibble to indicate + * access required + */ + switch (acType) { + case SME_AC_BK: + /* clear first bit */ + pAdapter->psbChanged &= ~SME_QOS_UAPSD_CFG_BK_CHANGED_MASK; + break; + case SME_AC_BE: + /* clear second bit */ + pAdapter->psbChanged &= ~SME_QOS_UAPSD_CFG_BE_CHANGED_MASK; + break; + case SME_AC_VI: + /* clear third bit */ + pAdapter->psbChanged &= ~SME_QOS_UAPSD_CFG_VI_CHANGED_MASK; + break; + case SME_AC_VO: + /* clear fourth bit */ + pAdapter->psbChanged &= ~SME_QOS_UAPSD_CFG_VO_CHANGED_MASK; + break; + default: + hdd_err("Invalid AC Type"); + break; + } +} + +/** + * hdd_wmm_acquire_access() - Function which will attempt to acquire + * admittance for a WMM AC + * + * @pAdapter: [in] pointer to adapter context + * @acType: [in] WMM AC type of OS packet + * @pGranted: [out] pointer to bool flag when indicates if access + * has been granted or not + * + * Return: QDF_STATUS enumeration + */ +QDF_STATUS hdd_wmm_acquire_access(hdd_adapter_t *pAdapter, + sme_ac_enum_type acType, bool *pGranted) +{ + hdd_wmm_qos_context_t *pQosContext; + + QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_DEBUG, + "%s: Entered for AC %d", __func__, acType); + + if (!hdd_wmm_is_active(pAdapter) || + !(WLAN_HDD_GET_CTX(pAdapter))->config->bImplicitQosEnabled || + !pAdapter->hddWmmStatus.wmmAcStatus[acType].wmmAcAccessRequired) { + /* either we don't want QoS or the AP doesn't support + * QoS or we don't want to do implicit QoS + */ + QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_DEBUG, + "%s: QoS not configured on both ends ", __func__); + + *pGranted = + pAdapter->hddWmmStatus.wmmAcStatus[acType]. + wmmAcAccessAllowed; + + return QDF_STATUS_SUCCESS; + } + /* do we already have an implicit QoS request pending for this AC? */ + if ((pAdapter->hddWmmStatus.wmmAcStatus[acType].wmmAcAccessNeeded) || + (pAdapter->hddWmmStatus.wmmAcStatus[acType].wmmAcAccessPending)) { + /* request already pending so we need to wait for that + * response + */ + QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_DEBUG, + "%s: Implicit QoS for TL AC %d already scheduled", + __func__, acType); + + *pGranted = false; + return QDF_STATUS_SUCCESS; + } + /* did we already fail to establish implicit QoS for this AC? + * (if so, access should have been granted when the failure + * was handled) + */ + if (pAdapter->hddWmmStatus.wmmAcStatus[acType].wmmAcAccessFailed) { + /* request previously failed + * allow access, but we'll be downgraded + */ + QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_DEBUG, + "%s: Implicit QoS for TL AC %d previously failed", + __func__, acType); + + if (!pAdapter->hddWmmStatus.wmmAcStatus[acType]. + wmmAcAccessRequired) { + pAdapter->hddWmmStatus.wmmAcStatus[acType]. + wmmAcAccessAllowed = true; + *pGranted = true; + } else { + pAdapter->hddWmmStatus.wmmAcStatus[acType]. + wmmAcAccessAllowed = false; + *pGranted = false; + } + + return QDF_STATUS_SUCCESS; + } + /* we need to establish implicit QoS */ + QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_DEBUG, + "%s: Need to schedule implicit QoS for TL AC %d, pAdapter is %p", + __func__, acType, pAdapter); + + pAdapter->hddWmmStatus.wmmAcStatus[acType].wmmAcAccessNeeded = true; + + pQosContext = qdf_mem_malloc(sizeof(*pQosContext)); + if (NULL == pQosContext) { + /* no memory for QoS context. Nothing we can do but + * let data flow + */ + QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_ERROR, + "%s: Unable to allocate context", __func__); + pAdapter->hddWmmStatus.wmmAcStatus[acType].wmmAcAccessAllowed = + true; + *pGranted = true; + return QDF_STATUS_SUCCESS; + } + + pQosContext->acType = acType; + pQosContext->pAdapter = pAdapter; + pQosContext->qosFlowId = 0; + pQosContext->handle = HDD_WMM_HANDLE_IMPLICIT; + pQosContext->magic = HDD_WMM_CTX_MAGIC; + pQosContext->is_inactivity_timer_running = false; + + INIT_WORK(&pQosContext->wmmAcSetupImplicitQos, hdd_wmm_do_implicit_qos); + + QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_DEBUG, + "%s: Scheduling work for AC %d, context %p", + __func__, acType, pQosContext); + + schedule_work(&pQosContext->wmmAcSetupImplicitQos); + + /* caller will need to wait until the work takes place and + * TSPEC negotiation completes + */ + *pGranted = false; + return QDF_STATUS_SUCCESS; +} + +/** + * hdd_wmm_assoc() - Function which will handle the housekeeping + * required by WMM when association takes place + * + * @pAdapter: [in] pointer to adapter context + * @pRoamInfo: [in] pointer to roam information + * @eBssType: [in] type of BSS + * + * Return: QDF_STATUS enumeration + */ +QDF_STATUS hdd_wmm_assoc(hdd_adapter_t *pAdapter, + tCsrRoamInfo *pRoamInfo, eCsrRoamBssType eBssType) +{ + uint8_t uapsdMask; + QDF_STATUS status; + hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter); + + /* when we associate we need to notify TL if it needs to + * enable UAPSD for any access categories + */ + + hdd_info("Entered"); + + if (pRoamInfo->fReassocReq) { + /* when we reassociate we should continue to use + * whatever parameters were previously established. + * if we are reassociating due to a U-APSD change for + * a particular Access Category, then the change will + * be communicated to HDD via the QoS callback + * associated with the given flow, and U-APSD + * parameters will be updated there + */ + + hdd_info("Reassoc so no work, Exiting"); + + return QDF_STATUS_SUCCESS; + } + /* get the negotiated UAPSD Mask */ + uapsdMask = + pRoamInfo->u.pConnectedProfile->modifyProfileFields.uapsd_mask; + + hdd_info("U-APSD mask is 0x%02x", (int)uapsdMask); + + if (uapsdMask & HDD_AC_VO) { + status = + sme_enable_uapsd_for_ac((WLAN_HDD_GET_CTX(pAdapter))-> + pcds_context, + (WLAN_HDD_GET_STATION_CTX_PTR + (pAdapter))->conn_info.staId[0], + SME_AC_VO, 7, 7, + pHddCtx->config->InfraUapsdVoSrvIntv, + pHddCtx->config->InfraUapsdVoSuspIntv, + SME_BI_DIR, 1, + pAdapter->sessionId, + pHddCtx->config->DelayedTriggerFrmInt); + + QDF_ASSERT(QDF_IS_STATUS_SUCCESS(status)); + } + + if (uapsdMask & HDD_AC_VI) { + status = + sme_enable_uapsd_for_ac((WLAN_HDD_GET_CTX(pAdapter))-> + pcds_context, + (WLAN_HDD_GET_STATION_CTX_PTR + (pAdapter))->conn_info.staId[0], + SME_AC_VI, 5, 5, + pHddCtx->config->InfraUapsdViSrvIntv, + pHddCtx->config->InfraUapsdViSuspIntv, + SME_BI_DIR, 1, + pAdapter->sessionId, + pHddCtx->config->DelayedTriggerFrmInt); + + QDF_ASSERT(QDF_IS_STATUS_SUCCESS(status)); + } + + if (uapsdMask & HDD_AC_BK) { + status = + sme_enable_uapsd_for_ac((WLAN_HDD_GET_CTX(pAdapter))-> + pcds_context, + (WLAN_HDD_GET_STATION_CTX_PTR + (pAdapter))->conn_info.staId[0], + SME_AC_BK, 2, 2, + pHddCtx->config->InfraUapsdBkSrvIntv, + pHddCtx->config->InfraUapsdBkSuspIntv, + SME_BI_DIR, 1, + pAdapter->sessionId, + pHddCtx->config->DelayedTriggerFrmInt); + + QDF_ASSERT(QDF_IS_STATUS_SUCCESS(status)); + } + + if (uapsdMask & HDD_AC_BE) { + status = + sme_enable_uapsd_for_ac((WLAN_HDD_GET_CTX(pAdapter))-> + pcds_context, + (WLAN_HDD_GET_STATION_CTX_PTR + (pAdapter))->conn_info.staId[0], + SME_AC_BE, 3, 3, + pHddCtx->config->InfraUapsdBeSrvIntv, + pHddCtx->config->InfraUapsdBeSuspIntv, + SME_BI_DIR, 1, + pAdapter->sessionId, + pHddCtx->config->DelayedTriggerFrmInt); + + QDF_ASSERT(QDF_IS_STATUS_SUCCESS(status)); + } + + status = sme_update_dsc_pto_up_mapping(pHddCtx->hHal, + pAdapter->hddWmmDscpToUpMap, + pAdapter->sessionId); + + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_wmm_init(pAdapter); + } + + hdd_info("Exiting"); + + return QDF_STATUS_SUCCESS; +} + +static const uint8_t acm_mask_bit[WLAN_MAX_AC] = { + 0x4, /* SME_AC_BK */ + 0x8, /* SME_AC_BE */ + 0x2, /* SME_AC_VI */ + 0x1 /* SME_AC_VO */ +}; + +/** + * hdd_wmm_connect() - Function which will handle the housekeeping + * required by WMM when a connection is established + * + * @pAdapter : [in] pointer to adapter context + * @pRoamInfo: [in] pointer to roam information + * @eBssType : [in] type of BSS + * + * Return: QDF_STATUS enumeration + */ +QDF_STATUS hdd_wmm_connect(hdd_adapter_t *pAdapter, + tCsrRoamInfo *pRoamInfo, eCsrRoamBssType eBssType) +{ + int ac; + bool qap; + bool qosConnection; + uint8_t acmMask; + + hdd_info("Entered"); + + if ((eCSR_BSS_TYPE_INFRASTRUCTURE == eBssType) && + pRoamInfo && pRoamInfo->u.pConnectedProfile) { + qap = pRoamInfo->u.pConnectedProfile->qap; + qosConnection = pRoamInfo->u.pConnectedProfile->qosConnection; + acmMask = pRoamInfo->u.pConnectedProfile->acm_mask; + } else { + qap = true; + qosConnection = true; + acmMask = 0x0; + } + + hdd_info("qap is %d, qosConnection is %d, acmMask is 0x%x", + qap, qosConnection, acmMask); + + pAdapter->hddWmmStatus.wmmQap = qap; + pAdapter->hddWmmStatus.wmmQosConnection = qosConnection; + + for (ac = 0; ac < WLAN_MAX_AC; ac++) { + if (qap && qosConnection && (acmMask & acm_mask_bit[ac])) { + hdd_info("ac %d on", ac); + + /* admission is required */ + pAdapter->hddWmmStatus.wmmAcStatus[ac]. + wmmAcAccessRequired = true; + pAdapter->hddWmmStatus.wmmAcStatus[ac]. + wmmAcAccessAllowed = false; + pAdapter->hddWmmStatus.wmmAcStatus[ac]. + wmmAcAccessGranted = false; + /* after reassoc if we have valid tspec, allow access */ + if (pAdapter->hddWmmStatus.wmmAcStatus[ac]. + wmmAcTspecValid + && (pAdapter->hddWmmStatus.wmmAcStatus[ac]. + wmmAcTspecInfo.ts_info.direction != + SME_QOS_WMM_TS_DIR_DOWNLINK)) { + pAdapter->hddWmmStatus.wmmAcStatus[ac]. + wmmAcAccessAllowed = true; + } + if (!pRoamInfo->fReassocReq && + !sme_neighbor_roam_is11r_assoc( + WLAN_HDD_GET_HAL_CTX(pAdapter), + pAdapter->sessionId) && + !sme_roam_is_ese_assoc(pRoamInfo) + ) { + pAdapter->hddWmmStatus.wmmAcStatus[ac]. + wmmAcTspecValid = false; + pAdapter->hddWmmStatus.wmmAcStatus[ac]. + wmmAcAccessAllowed = false; + } + } else { + hdd_info("ac %d off", ac); + /* admission is not required so access is allowed */ + pAdapter->hddWmmStatus.wmmAcStatus[ac]. + wmmAcAccessRequired = false; + pAdapter->hddWmmStatus.wmmAcStatus[ac]. + wmmAcAccessAllowed = true; + } + + } + + hdd_info("Exiting"); + + return QDF_STATUS_SUCCESS; +} + +/** + * hdd_wmm_get_uapsd_mask() - Function which will calculate the + * initial value of the UAPSD mask based upon the device configuration + * + * @pAdapter : [in] pointer to adapter context + * @pUapsdMask: [out] pointer to where the UAPSD Mask is to be stored + * + * Return: QDF_STATUS enumeration + */ +QDF_STATUS hdd_wmm_get_uapsd_mask(hdd_adapter_t *pAdapter, + uint8_t *pUapsdMask) +{ + uint8_t uapsdMask; + + if (HDD_WMM_USER_MODE_NO_QOS == + (WLAN_HDD_GET_CTX(pAdapter))->config->WmmMode) { + /* no QOS then no UAPSD */ + uapsdMask = 0; + } else { + /* start with the default mask */ + uapsdMask = (WLAN_HDD_GET_CTX(pAdapter))->config->UapsdMask; + + /* disable UAPSD for any ACs with a 0 Service Interval */ + if ((WLAN_HDD_GET_CTX(pAdapter))->config-> + InfraUapsdVoSrvIntv == 0) { + uapsdMask &= ~HDD_AC_VO; + } + + if ((WLAN_HDD_GET_CTX(pAdapter))->config-> + InfraUapsdViSrvIntv == 0) { + uapsdMask &= ~HDD_AC_VI; + } + + if ((WLAN_HDD_GET_CTX(pAdapter))->config-> + InfraUapsdBkSrvIntv == 0) { + uapsdMask &= ~HDD_AC_BK; + } + + if ((WLAN_HDD_GET_CTX(pAdapter))->config-> + InfraUapsdBeSrvIntv == 0) { + uapsdMask &= ~HDD_AC_BE; + } + } + + /* return calculated mask */ + *pUapsdMask = uapsdMask; + return QDF_STATUS_SUCCESS; +} + +/** + * hdd_wmm_is_active() - Function which will determine if WMM is + * active on the current connection + * + * @pAdapter: [in] pointer to adapter context + * + * Return: true if WMM is enabled, false if WMM is not enabled + */ +bool hdd_wmm_is_active(hdd_adapter_t *pAdapter) +{ + if ((!pAdapter->hddWmmStatus.wmmQosConnection) || + (!pAdapter->hddWmmStatus.wmmQap)) { + return false; + } else { + return true; + } +} + +/** + * hdd_wmm_addts() - Function which will add a traffic spec at the + * request of an application + * + * @pAdapter : [in] pointer to adapter context + * @handle : [in] handle to uniquely identify a TS + * @pTspec : [in] pointer to the traffic spec + * + * Return: HDD_WLAN_WMM_STATUS_* + */ +hdd_wlan_wmm_status_e hdd_wmm_addts(hdd_adapter_t *pAdapter, + uint32_t handle, + sme_QosWmmTspecInfo *pTspec) +{ + hdd_wmm_qos_context_t *pQosContext; + hdd_wlan_wmm_status_e status = HDD_WLAN_WMM_STATUS_SETUP_SUCCESS; +#ifndef WLAN_MDM_CODE_REDUCTION_OPT + sme_QosStatusType smeStatus; +#endif + bool found = false; + + hdd_info("Entered with handle 0x%x", handle); + + /* see if a context already exists with the given handle */ + mutex_lock(&pAdapter->hddWmmStatus.wmmLock); + list_for_each_entry(pQosContext, + &pAdapter->hddWmmStatus.wmmContextList, node) { + if (pQosContext->handle == handle) { + found = true; + break; + } + } + mutex_unlock(&pAdapter->hddWmmStatus.wmmLock); + if (found) { + /* record with that handle already exists */ + hdd_err("Record already exists with handle 0x%x", handle); + + /* Application is trying to modify some of the Tspec + * params. Allow it + */ + smeStatus = sme_qos_modify_req(WLAN_HDD_GET_HAL_CTX(pAdapter), + pTspec, pQosContext->qosFlowId); + + /* need to check the return value and act appropriately */ + switch (smeStatus) { + case SME_QOS_STATUS_MODIFY_SETUP_PENDING_RSP: + status = HDD_WLAN_WMM_STATUS_MODIFY_PENDING; + break; + case SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_NO_ACM_NO_APSD_RSP: + status = + HDD_WLAN_WMM_STATUS_MODIFY_SUCCESS_NO_ACM_NO_UAPSD; + break; + case SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_APSD_SET_ALREADY: + status = + HDD_WLAN_WMM_STATUS_MODIFY_SUCCESS_NO_ACM_UAPSD_EXISTING; + break; + case SME_QOS_STATUS_MODIFY_SETUP_INVALID_PARAMS_RSP: + status = HDD_WLAN_WMM_STATUS_MODIFY_FAILED_BAD_PARAM; + break; + case SME_QOS_STATUS_MODIFY_SETUP_FAILURE_RSP: + status = HDD_WLAN_WMM_STATUS_MODIFY_FAILED; + break; + case SME_QOS_STATUS_SETUP_NOT_QOS_AP_RSP: + status = HDD_WLAN_WMM_STATUS_SETUP_FAILED_NO_WMM; + break; + default: + /* we didn't get back one of the + * SME_QOS_STATUS_MODIFY_* status codes + */ + hdd_err("unexpected SME Status=%d", + smeStatus); + QDF_ASSERT(0); + return HDD_WLAN_WMM_STATUS_MODIFY_FAILED; + } + + /* we were successful, save the status */ + mutex_lock(&pAdapter->hddWmmStatus.wmmLock); + if (pQosContext->magic == HDD_WMM_CTX_MAGIC) + pQosContext->lastStatus = status; + mutex_unlock(&pAdapter->hddWmmStatus.wmmLock); + + return status; + } + + pQosContext = qdf_mem_malloc(sizeof(*pQosContext)); + if (NULL == pQosContext) { + /* no memory for QoS context. Nothing we can do */ + hdd_err("Unable to allocate QoS context"); + return HDD_WLAN_WMM_STATUS_INTERNAL_FAILURE; + } + /* we assume the tspec has already been validated by the caller */ + + pQosContext->handle = handle; + if (pTspec->ts_info.up < HDD_WMM_UP_TO_AC_MAP_SIZE) + pQosContext->acType = hdd_wmm_up_to_ac_map[pTspec->ts_info.up]; + else { + hdd_err("ts_info.up (%d) larger than max value (%d), use default acType (%d)", + pTspec->ts_info.up, + HDD_WMM_UP_TO_AC_MAP_SIZE - 1, hdd_wmm_up_to_ac_map[0]); + pQosContext->acType = hdd_wmm_up_to_ac_map[0]; + } + pQosContext->pAdapter = pAdapter; + pQosContext->qosFlowId = 0; + pQosContext->magic = HDD_WMM_CTX_MAGIC; + pQosContext->is_inactivity_timer_running = false; + + hdd_notice("Setting up QoS, context %p", pQosContext); + + mutex_lock(&pAdapter->hddWmmStatus.wmmLock); + list_add(&pQosContext->node, &pAdapter->hddWmmStatus.wmmContextList); + mutex_unlock(&pAdapter->hddWmmStatus.wmmLock); + +#ifndef WLAN_MDM_CODE_REDUCTION_OPT + smeStatus = sme_qos_setup_req(WLAN_HDD_GET_HAL_CTX(pAdapter), + pAdapter->sessionId, + pTspec, + hdd_wmm_sme_callback, + pQosContext, + pTspec->ts_info.up, + &pQosContext->qosFlowId); + + hdd_notice("sme_qos_setup_req returned %d flowid %d", + smeStatus, pQosContext->qosFlowId); + + /* need to check the return value and act appropriately */ + switch (smeStatus) { + case SME_QOS_STATUS_SETUP_REQ_PENDING_RSP: + status = HDD_WLAN_WMM_STATUS_SETUP_PENDING; + break; + case SME_QOS_STATUS_SETUP_SUCCESS_NO_ACM_NO_APSD_RSP: + status = HDD_WLAN_WMM_STATUS_SETUP_SUCCESS_NO_ACM_NO_UAPSD; + break; + case SME_QOS_STATUS_SETUP_SUCCESS_APSD_SET_ALREADY: + status = + HDD_WLAN_WMM_STATUS_SETUP_SUCCESS_NO_ACM_UAPSD_EXISTING; + break; + case SME_QOS_STATUS_SETUP_SUCCESS_IND_APSD_PENDING: + status = HDD_WLAN_WMM_STATUS_SETUP_PENDING; + break; + case SME_QOS_STATUS_SETUP_INVALID_PARAMS_RSP: + hdd_wmm_free_context(pQosContext); + return HDD_WLAN_WMM_STATUS_SETUP_FAILED_BAD_PARAM; + case SME_QOS_STATUS_SETUP_FAILURE_RSP: + /* we can't tell the difference between when a request + * fails because AP rejected it versus when SME + * encounterd an internal error + */ + hdd_wmm_free_context(pQosContext); + return HDD_WLAN_WMM_STATUS_SETUP_FAILED; + case SME_QOS_STATUS_SETUP_NOT_QOS_AP_RSP: + hdd_wmm_free_context(pQosContext); + return HDD_WLAN_WMM_STATUS_SETUP_FAILED_NO_WMM; + default: + /* we didn't get back one of the + * SME_QOS_STATUS_SETUP_* status codes + */ + hdd_wmm_free_context(pQosContext); + hdd_err("unexpected SME Status=%d", smeStatus); + QDF_ASSERT(0); + return HDD_WLAN_WMM_STATUS_SETUP_FAILED; + } +#endif + + /* we were successful, save the status */ + mutex_lock(&pAdapter->hddWmmStatus.wmmLock); + if (pQosContext->magic == HDD_WMM_CTX_MAGIC) + pQosContext->lastStatus = status; + mutex_unlock(&pAdapter->hddWmmStatus.wmmLock); + + return status; +} + +/** + * hdd_wmm_delts() - Function which will delete a traffic spec at the + * request of an application + * + * @pAdapter: [in] pointer to adapter context + * @handle: [in] handle to uniquely identify a TS + * + * Return: HDD_WLAN_WMM_STATUS_* + */ +hdd_wlan_wmm_status_e hdd_wmm_delts(hdd_adapter_t *pAdapter, uint32_t handle) +{ + hdd_wmm_qos_context_t *pQosContext; + bool found = false; + sme_ac_enum_type acType = 0; + uint32_t qosFlowId = 0; + hdd_wlan_wmm_status_e status = HDD_WLAN_WMM_STATUS_SETUP_SUCCESS; +#ifndef WLAN_MDM_CODE_REDUCTION_OPT + sme_QosStatusType smeStatus; +#endif + + hdd_info("Entered with handle 0x%x", handle); + + /* locate the context with the given handle */ + mutex_lock(&pAdapter->hddWmmStatus.wmmLock); + list_for_each_entry(pQosContext, + &pAdapter->hddWmmStatus.wmmContextList, node) { + if (pQosContext->handle == handle) { + found = true; + acType = pQosContext->acType; + qosFlowId = pQosContext->qosFlowId; + break; + } + } + mutex_unlock(&pAdapter->hddWmmStatus.wmmLock); + + if (false == found) { + /* we didn't find the handle */ + hdd_info("handle 0x%x not found", handle); + return HDD_WLAN_WMM_STATUS_RELEASE_FAILED_BAD_PARAM; + } + + hdd_info("found handle 0x%x, flow %d, AC %d, context %p", + handle, qosFlowId, acType, pQosContext); + +#ifndef WLAN_MDM_CODE_REDUCTION_OPT + smeStatus = + sme_qos_release_req(WLAN_HDD_GET_HAL_CTX(pAdapter), + pAdapter->sessionId, qosFlowId); + + hdd_info("SME flow %d released, SME status %d", qosFlowId, smeStatus); + + switch (smeStatus) { + case SME_QOS_STATUS_RELEASE_SUCCESS_RSP: + /* this flow is the only one on that AC, so go ahead + * and update our TSPEC state for the AC + */ + pAdapter->hddWmmStatus.wmmAcStatus[acType].wmmAcTspecValid = + false; + pAdapter->hddWmmStatus.wmmAcStatus[acType].wmmAcAccessAllowed = + false; + + /* need to tell TL to stop trigger timer, etc */ + hdd_wmm_disable_tl_uapsd(pQosContext); + +#ifdef FEATURE_WLAN_ESE + /* disable the inactivity timer */ + hdd_wmm_disable_inactivity_timer(pQosContext); +#endif + /* we are done with this context */ + hdd_wmm_free_context(pQosContext); + + /* SME must not fire any more callbacks for this flow + * since the context is no longer valid + */ + + return HDD_WLAN_WMM_STATUS_RELEASE_SUCCESS; + + case SME_QOS_STATUS_RELEASE_REQ_PENDING_RSP: + /* do nothing as we will get a response from SME */ + status = HDD_WLAN_WMM_STATUS_RELEASE_PENDING; + break; + + case SME_QOS_STATUS_RELEASE_INVALID_PARAMS_RSP: + /* nothing we can do with the existing flow except leave it */ + status = HDD_WLAN_WMM_STATUS_RELEASE_FAILED_BAD_PARAM; + break; + + case SME_QOS_STATUS_RELEASE_FAILURE_RSP: + /* nothing we can do with the existing flow except leave it */ + status = HDD_WLAN_WMM_STATUS_RELEASE_FAILED; + break; + + default: + /* we didn't get back one of the + * SME_QOS_STATUS_RELEASE_* status codes + */ + hdd_err("unexpected SME Status=%d", smeStatus); + QDF_ASSERT(0); + status = HDD_WLAN_WMM_STATUS_RELEASE_FAILED; + } + +#endif + mutex_lock(&pAdapter->hddWmmStatus.wmmLock); + if (pQosContext->magic == HDD_WMM_CTX_MAGIC) + pQosContext->lastStatus = status; + mutex_unlock(&pAdapter->hddWmmStatus.wmmLock); + + return status; +} + +/** + * hdd_wmm_checkts() - Function which will return the status of a traffic + * spec at the request of an application + * + * @pAdapter: [in] pointer to adapter context + * @handle: [in] handle to uniquely identify a TS + * + * Return: HDD_WLAN_WMM_STATUS_* + */ +hdd_wlan_wmm_status_e hdd_wmm_checkts(hdd_adapter_t *pAdapter, uint32_t handle) +{ + hdd_wmm_qos_context_t *pQosContext; + hdd_wlan_wmm_status_e status = HDD_WLAN_WMM_STATUS_LOST; + + hdd_info("Entered with handle 0x%x", handle); + + /* locate the context with the given handle */ + mutex_lock(&pAdapter->hddWmmStatus.wmmLock); + list_for_each_entry(pQosContext, + &pAdapter->hddWmmStatus.wmmContextList, node) { + if (pQosContext->handle == handle) { + hdd_info("found handle 0x%x, context %p", + handle, pQosContext); + + status = pQosContext->lastStatus; + break; + } + } + mutex_unlock(&pAdapter->hddWmmStatus.wmmLock); + return status; +} diff --git a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_wowl.c b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_wowl.c new file mode 100644 index 0000000000000000000000000000000000000000..4f7dd5ed59df4f14e21f59680a0f05cdd1814ce7 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_wowl.c @@ -0,0 +1,552 @@ +/* + * Copyright (c) 2013-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * @file wlan_hdd_wowl.c + * + * @brief wake up on WLAN API file + */ + +/* Include Files */ + +#include +#include + +/* Preprocessor Definitions and Constants */ +#define WOWL_INTER_PTRN_TOKENIZER ';' +#define WOWL_INTRA_PTRN_TOKENIZER ':' + +/* Type Declarations */ + +static char *g_hdd_wowl_ptrns[WOWL_MAX_PTRNS_ALLOWED]; +static bool g_hdd_wowl_ptrns_debugfs[WOWL_MAX_PTRNS_ALLOWED] = { 0 }; + +static uint8_t g_hdd_wowl_ptrns_count; + +static inline int find_ptrn_len(const char *ptrn) +{ + int len = 0; + while (*ptrn != '\0' && *ptrn != WOWL_INTER_PTRN_TOKENIZER) { + len++; + ptrn++; + } + return len; +} + +static void hdd_wowl_callback(void *pContext, QDF_STATUS qdf_ret_status) +{ + hdd_info("Return code = (%d)", qdf_ret_status); +} + +#ifdef WLAN_WAKEUP_EVENTS +static void hdd_wowl_wake_indication_callback(void *pContext, + tpSirWakeReasonInd wake_reason_ind) +{ + hdd_info("Wake Reason %d", wake_reason_ind->ulReason); + hdd_exit_wowl((hdd_adapter_t *) pContext); +} +#endif + +/** + * dump_hdd_wowl_ptrn() - log wow patterns + * @ptrn: pointer to wow pattern + * + * Return: none + */ +static void dump_hdd_wowl_ptrn(struct wow_add_pattern *ptrn) +{ + int i; + + hdd_info("Pattern Id = 0x%x", ptrn->pattern_id); + hdd_info("Pattern Byte Offset = 0x%x", ptrn->pattern_byte_offset); + hdd_info("Pattern_size = 0x%x", ptrn->pattern_size); + hdd_info("Pattern_mask_size = 0x%x", ptrn->pattern_mask_size); + hdd_info("Pattern: "); + for (i = 0; i < ptrn->pattern_size; i++) + hdd_info(" %02X", ptrn->pattern[i]); + hdd_info("pattern_mask: "); + for (i = 0; i < ptrn->pattern_mask_size; i++) + hdd_info("%02X", ptrn->pattern_mask[i]); +} + +/** + * hdd_add_wowl_ptrn() - Function which will add the WoWL pattern to be + * used when PBM filtering is enabled + * @pAdapter: pointer to the adapter + * @ptrn: pointer to the pattern string to be added + * + * Return: false if any errors encountered, true otherwise + */ +bool hdd_add_wowl_ptrn(hdd_adapter_t *pAdapter, const char *ptrn) +{ + struct wow_add_pattern localPattern; + int i, first_empty_slot, len, offset; + QDF_STATUS qdf_ret_status; + const char *temp; + tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter); + uint8_t sessionId = pAdapter->sessionId; + hdd_context_t *pHddCtx = pAdapter->pHddCtx; + + len = find_ptrn_len(ptrn); + + /* There has to have at least 1 byte for each field (pattern + * size, mask size, pattern, mask) e.g. PP:QQ:RR:SS ==> 11 + * chars + */ + while (len >= 11) { + /* Detect duplicate pattern */ + for (i = 0; i < pHddCtx->config->maxWoWFilters; i++) { + if (g_hdd_wowl_ptrns[i] == NULL) + continue; + + if (!memcmp(ptrn, g_hdd_wowl_ptrns[i], len)) { + /* Pattern Already configured, skip to + * next pattern + */ + hdd_err("Trying to add duplicate WoWL pattern. Skip it!"); + ptrn += len; + goto next_ptrn; + } + } + + first_empty_slot = -1; + + /* Find an empty slot to store the pattern */ + for (i = 0; i < pHddCtx->config->maxWoWFilters; i++) { + if (g_hdd_wowl_ptrns[i] == NULL) { + first_empty_slot = i; + break; + } + } + + /* Maximum number of patterns have been configured already */ + if (first_empty_slot == -1) { + hdd_err("Cannot add anymore patterns. No free slot!"); + return false; + } + /* Validate the pattern */ + if (ptrn[2] != WOWL_INTRA_PTRN_TOKENIZER || + ptrn[5] != WOWL_INTRA_PTRN_TOKENIZER) { + hdd_err("Malformed pattern string. Skip!"); + ptrn += len; + goto next_ptrn; + } + /* Extract the pattern size */ + localPattern.pattern_size = + (hex_to_bin(ptrn[0]) * 0x10) + + hex_to_bin(ptrn[1]); + + /* Extract the pattern mask size */ + localPattern.pattern_mask_size = + (hex_to_bin(ptrn[3]) * 0x10) + + hex_to_bin(ptrn[4]); + + if (localPattern.pattern_size > SIR_WOWL_BCAST_PATTERN_MAX_SIZE + || localPattern.pattern_mask_size > + WOWL_PTRN_MASK_MAX_SIZE) { + hdd_err("Invalid length specified. Skip!"); + ptrn += len; + goto next_ptrn; + } + /* compute the offset of tokenizer after the pattern */ + offset = 5 + 2 * localPattern.pattern_size + 1; + if ((offset >= len) || + (ptrn[offset] != WOWL_INTRA_PTRN_TOKENIZER)) { + hdd_err("Malformed pattern string..skip!"); + ptrn += len; + goto next_ptrn; + } + /* compute the end of pattern sring */ + offset = offset + 2 * localPattern.pattern_mask_size; + if (offset + 1 != len) { + /* offset begins with 0 */ + hdd_err("Malformed pattern string...skip!"); + ptrn += len; + goto next_ptrn; + } + + temp = ptrn; + + /* Now advance to where pattern begins */ + ptrn += 6; + + /* Extract the pattern */ + for (i = 0; i < localPattern.pattern_size; i++) { + localPattern.pattern[i] = + (hex_to_bin(ptrn[0]) * 0x10) + + hex_to_bin(ptrn[1]); + ptrn += 2; /* skip to next byte */ + } + + /* Skip over the ':' seperator after the pattern */ + ptrn++; + + /* Extract the pattern Mask */ + for (i = 0; i < localPattern.pattern_mask_size; i++) { + localPattern.pattern_mask[i] = + (hex_to_bin(ptrn[0]) * 0x10) + + hex_to_bin(ptrn[1]); + ptrn += 2; /* skip to next byte */ + } + + /* All is good. Store the pattern locally */ + g_hdd_wowl_ptrns[first_empty_slot] = + qdf_mem_malloc(len + 1); + if (g_hdd_wowl_ptrns[first_empty_slot] == NULL) { + hdd_err("memory allocation failure"); + return false; + } + + memcpy(g_hdd_wowl_ptrns[first_empty_slot], temp, len); + g_hdd_wowl_ptrns[first_empty_slot][len] = '\0'; + localPattern.pattern_id = first_empty_slot; + localPattern.pattern_byte_offset = 0; + localPattern.session_id = sessionId; + + /* Register the pattern downstream */ + qdf_ret_status = + sme_wow_add_pattern(hHal, &localPattern, + sessionId); + if (!QDF_IS_STATUS_SUCCESS(qdf_ret_status)) { + /* Add failed, so invalidate the local storage */ + hdd_err("sme_wowl_add_bcast_pattern failed with error code (%d)", + qdf_ret_status); + qdf_mem_free(g_hdd_wowl_ptrns[first_empty_slot]); + g_hdd_wowl_ptrns[first_empty_slot] = NULL; + } + + dump_hdd_wowl_ptrn(&localPattern); + +next_ptrn: + if (*ptrn == WOWL_INTER_PTRN_TOKENIZER) { + /* move past the tokenizer */ + ptrn += 1; + len = find_ptrn_len(ptrn); + continue; + } else + break; + } + + return true; +} + +/** + * hdd_del_wowl_ptrn() - Function which will remove a WoWL pattern + * @pAdapter: pointer to the adapter + * @ptrn: pointer to the pattern string to be removed + * + * Return: false if any errors encountered, true otherwise + */ +bool hdd_del_wowl_ptrn(hdd_adapter_t *pAdapter, const char *ptrn) +{ + struct wow_delete_pattern delPattern; + unsigned char id; + tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter); + bool patternFound = false; + QDF_STATUS qdf_ret_status; + uint8_t sessionId = pAdapter->sessionId; + hdd_context_t *pHddCtx = pAdapter->pHddCtx; + + /* Detect pattern */ + for (id = 0; + id < pHddCtx->config->maxWoWFilters + && g_hdd_wowl_ptrns[id] != NULL; id++) { + if (!strcmp(ptrn, g_hdd_wowl_ptrns[id])) { + patternFound = true; + break; + } + } + + /* If pattern present, remove it from downstream */ + if (patternFound) { + delPattern.pattern_id = id; + delPattern.session_id = sessionId; + qdf_ret_status = + sme_wow_delete_pattern(hHal, &delPattern, + sessionId); + if (QDF_IS_STATUS_SUCCESS(qdf_ret_status)) { + /* Remove from local storage as well */ + hdd_err("Deleted pattern with id %d [%s]", id, + g_hdd_wowl_ptrns[id]); + + qdf_mem_free(g_hdd_wowl_ptrns[id]); + g_hdd_wowl_ptrns[id] = NULL; + return true; + } + } + return false; +} + +/** + * hdd_add_wowl_ptrn_debugfs() - Function which will add a WoW pattern + * sent from debugfs interface + * @pAdapter: pointer to the adapter + * @pattern_idx: index of the pattern to be added + * @pattern_offset: offset of the pattern in the frame payload + * @pattern_buf: pointer to the pattern hex string to be added + * @pattern_mask: pointer to the pattern mask hex string + * + * Return: false if any errors encountered, true otherwise + */ +bool hdd_add_wowl_ptrn_debugfs(hdd_adapter_t *pAdapter, uint8_t pattern_idx, + uint8_t pattern_offset, char *pattern_buf, + char *pattern_mask) +{ + struct wow_add_pattern localPattern; + QDF_STATUS qdf_ret_status; + tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter); + uint8_t session_id = pAdapter->sessionId; + uint16_t pattern_len, mask_len, i; + + if (pattern_idx > (WOWL_MAX_PTRNS_ALLOWED - 1)) { + hdd_err("WoW pattern index %d is out of range (0 ~ %d)", + pattern_idx, WOWL_MAX_PTRNS_ALLOWED - 1); + + return false; + } + + pattern_len = strlen(pattern_buf); + + /* Since the pattern is a hex string, 2 characters represent 1 byte. */ + if (pattern_len % 2) { + hdd_err("Malformed WoW pattern!"); + + return false; + } else + pattern_len >>= 1; + + if (!pattern_len || pattern_len > WOWL_PTRN_MAX_SIZE) { + hdd_err("WoW pattern length %d is out of range (1 ~ %d).", + pattern_len, WOWL_PTRN_MAX_SIZE); + + return false; + } + + localPattern.pattern_id = pattern_idx; + localPattern.pattern_byte_offset = pattern_offset; + localPattern.pattern_size = pattern_len; + localPattern.session_id = session_id; + + if (localPattern.pattern_size > SIR_WOWL_BCAST_PATTERN_MAX_SIZE) { + hdd_err("WoW pattern size (%d) greater than max (%d)", + localPattern.pattern_size, + SIR_WOWL_BCAST_PATTERN_MAX_SIZE); + return false; + } + /* Extract the pattern */ + for (i = 0; i < localPattern.pattern_size; i++) { + localPattern.pattern[i] = + (hex_to_bin(pattern_buf[0]) << 4) + + hex_to_bin(pattern_buf[1]); + + /* Skip to next byte */ + pattern_buf += 2; + } + + /* Get pattern mask size by pattern length */ + localPattern.pattern_mask_size = pattern_len >> 3; + if (pattern_len % 8) + localPattern.pattern_mask_size += 1; + + mask_len = strlen(pattern_mask); + if ((mask_len % 2) + || (localPattern.pattern_mask_size != (mask_len >> 1))) { + hdd_err("Malformed WoW pattern mask!"); + + return false; + } + if (localPattern.pattern_mask_size > WOWL_PTRN_MASK_MAX_SIZE) { + hdd_err("WoW pattern mask size (%d) greater than max (%d)", + localPattern.pattern_mask_size, + WOWL_PTRN_MASK_MAX_SIZE); + return false; + } + /* Extract the pattern mask */ + for (i = 0; i < localPattern.pattern_mask_size; i++) { + localPattern.pattern_mask[i] = + (hex_to_bin(pattern_mask[0]) << 4) + + hex_to_bin(pattern_mask[1]); + + /* Skip to next byte */ + pattern_mask += 2; + } + + /* Register the pattern downstream */ + qdf_ret_status = + sme_wow_add_pattern(hHal, &localPattern, session_id); + + if (!QDF_IS_STATUS_SUCCESS(qdf_ret_status)) { + hdd_err("sme_wowl_add_bcast_pattern failed with error code (%d).", + qdf_ret_status); + + return false; + } + + /* All is good. */ + if (!g_hdd_wowl_ptrns_debugfs[pattern_idx]) { + g_hdd_wowl_ptrns_debugfs[pattern_idx] = 1; + g_hdd_wowl_ptrns_count++; + } + + dump_hdd_wowl_ptrn(&localPattern); + + return true; +} + +/** + * hdd_del_wowl_ptrn_debugfs() - Function which will remove a WoW pattern + * sent from debugfs interface + * @pAdapter: pointer to the adapter + * @pattern_idx: index of the pattern to be removed + * + * Return: false if any errors encountered, true otherwise + */ +bool hdd_del_wowl_ptrn_debugfs(hdd_adapter_t *pAdapter, uint8_t pattern_idx) +{ + struct wow_delete_pattern delPattern; + tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter); + QDF_STATUS qdf_ret_status; + uint8_t sessionId = pAdapter->sessionId; + + if (pattern_idx > (WOWL_MAX_PTRNS_ALLOWED - 1)) { + hdd_err("WoW pattern index %d is not in the range (0 ~ %d).", + pattern_idx, WOWL_MAX_PTRNS_ALLOWED - 1); + + return false; + } + + if (!g_hdd_wowl_ptrns_debugfs[pattern_idx]) { + hdd_err("WoW pattern %d is not in the table.", + pattern_idx); + + return false; + } + + delPattern.pattern_id = pattern_idx; + delPattern.session_id = sessionId; + qdf_ret_status = sme_wow_delete_pattern(hHal, &delPattern, + sessionId); + + if (!QDF_IS_STATUS_SUCCESS(qdf_ret_status)) { + hdd_err("sme_wowl_del_bcast_pattern failed with error code (%d).", + qdf_ret_status); + + return false; + } + + g_hdd_wowl_ptrns_debugfs[pattern_idx] = 0; + g_hdd_wowl_ptrns_count--; + + return true; +} + +/** + * hdd_enter_wowl() - Function which will enable WoWL. At least one + * of MP and PBM must be enabled + * @pAdapter: pointer to the adapter + * @enable_mp: Whether to enable magic packet WoWL mode + * @enable_pbm: Whether to enable pattern byte matching WoWL mode + * + * Return: false if any errors encountered, true otherwise + */ +bool hdd_enter_wowl(hdd_adapter_t *pAdapter, bool enable_mp, bool enable_pbm) +{ + tSirSmeWowlEnterParams wowParams; + QDF_STATUS qdf_ret_status; + tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter); + + qdf_mem_zero(&wowParams, sizeof(tSirSmeWowlEnterParams)); + + wowParams.ucPatternFilteringEnable = enable_pbm; + wowParams.ucMagicPktEnable = enable_mp; + wowParams.sessionId = pAdapter->sessionId; + if (enable_mp) { + qdf_copy_macaddr(&wowParams.magic_ptrn, + &pAdapter->macAddressCurrent); + } +#ifdef WLAN_WAKEUP_EVENTS + wowParams.ucWoWEAPIDRequestEnable = true; + wowParams.ucWoWEAPOL4WayEnable = true; + wowParams.ucWowNetScanOffloadMatch = true; + wowParams.ucWowGTKRekeyError = true; + wowParams.ucWoWBSSConnLoss = true; +#endif /* WLAN_WAKEUP_EVENTS */ + + /* Request to put FW into WoWL */ + qdf_ret_status = sme_enter_wowl(hHal, hdd_wowl_callback, pAdapter, +#ifdef WLAN_WAKEUP_EVENTS + hdd_wowl_wake_indication_callback, + pAdapter, +#endif /* WLAN_WAKEUP_EVENTS */ + &wowParams, pAdapter->sessionId); + + if (!QDF_IS_STATUS_SUCCESS(qdf_ret_status)) { + if (QDF_STATUS_PMC_PENDING != qdf_ret_status) { + /* We failed to enter WoWL */ + hdd_err("sme_enter_wowl failed with error code (%d)", + qdf_ret_status); + return false; + } + } + return true; +} + +/** + * hdd_exit_wowl() - Function which will disable WoWL + * @pAdapter: pointer to the adapter + * + * Return: false if any errors encountered, true otherwise + */ +bool hdd_exit_wowl(hdd_adapter_t *pAdapter) +{ + tSirSmeWowlExitParams wowParams; + tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter); + QDF_STATUS qdf_ret_status; + + wowParams.sessionId = pAdapter->sessionId; + + qdf_ret_status = sme_exit_wowl(hHal, &wowParams); + if (!QDF_IS_STATUS_SUCCESS(qdf_ret_status)) { + hdd_err("sme_exit_wowl failed with error code (%d)", + qdf_ret_status); + return false; + } + + return true; +} + +void hdd_deinit_wowl(void) +{ + int i; + + for (i = 0; i < WOWL_MAX_PTRNS_ALLOWED; ++i) { + if (g_hdd_wowl_ptrns[i]) { + qdf_mem_free(g_hdd_wowl_ptrns[i]); + g_hdd_wowl_ptrns[i] = NULL; + } + } +} diff --git a/drivers/staging/qcacld-3.0/core/mac/inc/ani_global.h b/drivers/staging/qcacld-3.0/core/mac/inc/ani_global.h new file mode 100644 index 0000000000000000000000000000000000000000..bd95ed7ab600b19bffd7d4df59a4d35ea42b1dae --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/inc/ani_global.h @@ -0,0 +1,1003 @@ +/* + * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef _ANIGLOBAL_H +#define _ANIGLOBAL_H + +#include "qdf_types.h" +#include "sir_common.h" +#include "ani_system_defs.h" +#include "sys_def.h" +#include "dph_global.h" +#include "lim_global.h" +#include "sch_global.h" +#include "sys_global.h" +#include "cfg_global.h" +#include "utils_global.h" +#include "sir_api.h" + +#include "csr_api.h" +#include "sme_ft_api.h" +#include "csr_support.h" +#include "sme_internal.h" +#include "sap_api.h" +#include "csr_internal.h" + +#include "sme_rrm_internal.h" +#include "rrm_global.h" +#include "p2p_api.h" + +#include + +/* Check if this definition can actually move here from halInternal.h even for Volans. In that case */ +/* this featurization can be removed. */ +#define PMAC_STRUCT(_hHal) ((tpAniSirGlobal)_hHal) + +#define ANI_DRIVER_TYPE(pMac) (((tpAniSirGlobal)(pMac))->gDriverType) + +#define IS_MIRACAST_SESSION_PRESENT(pMac) (((tpAniSirGlobal)(pMac))->fMiracastSessionPresent ? 1 : 0) +/* ------------------------------------------------------------------- */ +/* Bss Qos Caps bit map definition */ +#define LIM_BSS_CAPS_OFFSET_HCF 0 +#define LIM_BSS_CAPS_OFFSET_WME 1 +#define LIM_BSS_CAPS_OFFSET_WSM 2 + +#define LIM_BSS_CAPS_HCF (1 << LIM_BSS_CAPS_OFFSET_HCF) +#define LIM_BSS_CAPS_WME (1 << LIM_BSS_CAPS_OFFSET_WME) +#define LIM_BSS_CAPS_WSM (1 << LIM_BSS_CAPS_OFFSET_WSM) + +/* cap should be one of HCF/WME/WSM */ +#define LIM_BSS_CAPS_GET(cap, val) (((val) & (LIM_BSS_CAPS_ ## cap)) >> LIM_BSS_CAPS_OFFSET_ ## cap) +#define LIM_BSS_CAPS_SET(cap, val) ((val) |= (LIM_BSS_CAPS_ ## cap)) +#define LIM_BSS_CAPS_CLR(cap, val) ((val) &= (~(LIM_BSS_CAPS_ ## cap))) + +/* 40 beacons per heart beat interval is the default + 1 to count the rest */ +#define MAX_NO_BEACONS_PER_HEART_BEAT_INTERVAL 41 + +/* max number of legacy bssid we can store during scan on one channel */ +#define MAX_NUM_LEGACY_BSSID_PER_CHANNEL 10 + +#define P2P_WILDCARD_SSID "DIRECT-" /* TODO Put it in proper place; */ +#define P2P_WILDCARD_SSID_LEN 7 + +/* Flags for processing single BSS */ +#define WLAN_SKIP_RSSI_UPDATE 0x01 + +#ifdef WLAN_FEATURE_CONCURRENT_P2P +#define MAX_NO_OF_P2P_SESSIONS 5 +#endif /* WLAN_FEATURE_CONCURRENT_P2P */ + +#define SPACE_ASCII_VALUE 32 + +#define WLAN_HOST_SEQ_NUM_MIN 2048 +#define WLAN_HOST_SEQ_NUM_MAX 4095 +#define LOW_SEQ_NUM_MASK 0x000F +#define HIGH_SEQ_NUM_MASK 0x0FF0 +#define HIGH_SEQ_NUM_OFFSET 4 + +/* vendor element ID */ +#define IE_EID_VENDOR (221) /* 0xDD */ +#define IE_LEN_SIZE (1) +#define IE_EID_SIZE (1) +/* Minimum size of vendor IE = 3 bytes of oui_data + 1 byte of data */ +#define IE_VENDOR_OUI_SIZE (4) + +/* + * NSS cfg bit definition. + * STA BIT[0:1] + * SAP BIT[2:3] + * P2P_GO BIT[4:5] + * P2P_CLIENT BIT[6:7] + * IBSS BIT[8:9] + * TDLS BIT[10:11] + * P2P_DEVICE BIT[12:13] + * OCB BIT[14:15] + */ + +#define CFG_STA_NSS(_x) ((((_x) >> 0) & 0x3) ? (((_x) >> 0) & 0x3) : 1) +#define CFG_SAP_NSS(_x) ((((_x) >> 2) & 0x3) ? (((_x) >> 2) & 0x3) : 1) +#define CFG_P2P_GO_NSS(_x) ((((_x) >> 4) & 0x3) ? (((_x) >> 4) & 0x3) : 1) +#define CFG_P2P_CLI_NSS(_x) ((((_x) >> 6) & 0x3) ? (((_x) >> 6) & 0x3) : 1) +#define CFG_IBSS_NSS(_x) ((((_x) >> 8) & 0x3) ? (((_x) >> 8) & 0x3) : 1) +#define CFG_TDLS_NSS(_x) ((((_x) >> 10) & 0x3) ? (((_x) >> 10) & 0x3) : 1) +#define CFG_P2P_DEV_NSS(_x) ((((_x) >> 12) & 0x3) ? (((_x) >> 12) & 0x3) : 1) +#define CFG_OCB_NSS(_x) ((((_x) >> 14) & 0x3) ? (((_x) >> 14) & 0x3) : 1) + +/** + * enum log_event_type - Type of event initiating bug report + * @WLAN_LOG_TYPE_NON_FATAL: Non fatal event + * @WLAN_LOG_TYPE_FATAL: Fatal event + * + * Enum indicating the type of event that is initiating the bug report + */ +enum log_event_type { + WLAN_LOG_TYPE_NON_FATAL, + WLAN_LOG_TYPE_FATAL, +}; + +/** + * enum log_event_indicator - Module triggering bug report + * @WLAN_LOG_INDICATOR_UNUSED: Unused + * @WLAN_LOG_INDICATOR_FRAMEWORK: Framework triggers bug report + * @WLAN_LOG_INDICATOR_HOST_DRIVER: Host driver triggers bug report + * @WLAN_LOG_INDICATOR_FIRMWARE: FW initiates bug report + * @WLAN_LOG_INDICATOR_HOST_ONLY: Host triggers fatal event bug report + * + * Enum indicating the module that triggered the bug report + */ +enum log_event_indicator { + WLAN_LOG_INDICATOR_UNUSED, + WLAN_LOG_INDICATOR_FRAMEWORK, + WLAN_LOG_INDICATOR_HOST_DRIVER, + WLAN_LOG_INDICATOR_FIRMWARE, + WLAN_LOG_INDICATOR_HOST_ONLY, +}; + +/** + * enum log_event_host_reason_code - Reason code for bug report + * @WLAN_LOG_REASON_CODE_UNUSED: Unused + * @WLAN_LOG_REASON_ROAM_FAIL: Driver initiated roam has failed + * @WLAN_LOG_REASON_DATA_STALL: Unable to send/receive data due to low resource + * scenario for a prolonged period + * @WLAN_LOG_REASON_SME_COMMAND_STUCK: SME command is stuck in SME active queue + * @WLAN_LOG_REASON_QUEUE_FULL: Defer queue becomes full for a prolonged period + * @WLAN_LOG_REASON_POWER_COLLAPSE_FAIL: Unable to allow apps power collapse + * for a prolonged period + * @WLAN_LOG_REASON_MALLOC_FAIL: Memory allocation Fails + * @WLAN_LOG_REASON_VOS_MSG_UNDER_RUN: VOS Core runs out of message wrapper + * @WLAN_LOG_REASON_HDD_TIME_OUT: Wait for event Timeout in HDD layer + @WLAN_LOG_REASON_SME_OUT_OF_CMD_BUFL sme out of cmd buffer + * @WLAN_LOG_REASON_NO_SCAN_RESULTS: no scan results to report from HDD + * This enum contains the different reason codes for bug report + * @WLAN_LOG_REASON_SCAN_NOT_ALLOWED: scan not allowed due to connection states + * @WLAN_LOG_REASON_HB_FAILURE: station triggered heart beat failure with AP + * @WLAN_LOG_REASON_ROAM_HO_FAILURE: Handover failed during LFR3 roaming + */ +enum log_event_host_reason_code { + WLAN_LOG_REASON_CODE_UNUSED, + WLAN_LOG_REASON_ROAM_FAIL, + WLAN_LOG_REASON_DATA_STALL, + WLAN_LOG_REASON_SME_COMMAND_STUCK, + WLAN_LOG_REASON_QUEUE_FULL, + WLAN_LOG_REASON_POWER_COLLAPSE_FAIL, + WLAN_LOG_REASON_MALLOC_FAIL, + WLAN_LOG_REASON_VOS_MSG_UNDER_RUN, + WLAN_LOG_REASON_HDD_TIME_OUT, + WLAN_LOG_REASON_SME_OUT_OF_CMD_BUF, + WLAN_LOG_REASON_NO_SCAN_RESULTS, + WLAN_LOG_REASON_SCAN_NOT_ALLOWED, + WLAN_LOG_REASON_HB_FAILURE, + WLAN_LOG_REASON_ROAM_HO_FAILURE +}; + + +/** + * enum userspace_log_level - Log level at userspace + * @LOG_LEVEL_NO_COLLECTION: verbose_level 0 corresponds to no collection + * @LOG_LEVEL_NORMAL_COLLECT: verbose_level 1 correspond to normal log level, + * with minimal user impact. this is the default value + * @LOG_LEVEL_ISSUE_REPRO: verbose_level 2 are enabled when user is lazily + * trying to reproduce a problem, wifi performances and power can be impacted + * but device should not otherwise be significantly impacted + * @LOG_LEVEL_ACTIVE: verbose_level 3+ are used when trying to + * actively debug a problem + * + * Various log levels defined in the userspace for logging applications + */ +enum userspace_log_level { + LOG_LEVEL_NO_COLLECTION, + LOG_LEVEL_NORMAL_COLLECT, + LOG_LEVEL_ISSUE_REPRO, + LOG_LEVEL_ACTIVE, +}; + +/** + * enum wifi_driver_log_level - Log level defined in the driver for logging + * @WLAN_LOG_LEVEL_OFF: No logging + * @WLAN_LOG_LEVEL_NORMAL: Default logging + * @WLAN_LOG_LEVEL_REPRO: Normal debug level + * @WLAN_LOG_LEVEL_ACTIVE: Active debug level + * + * Log levels defined for logging by the wifi driver + */ +enum wifi_driver_log_level { + WLAN_LOG_LEVEL_OFF, + WLAN_LOG_LEVEL_NORMAL, + WLAN_LOG_LEVEL_REPRO, + WLAN_LOG_LEVEL_ACTIVE, +}; + +/** + * enum wifi_logging_ring_id - Ring id of logging entities + * @RING_ID_WAKELOCK: Power events ring id + * @RING_ID_CONNECTIVITY: Connectivity event ring id + * @RING_ID_PER_PACKET_STATS: Per packet statistic ring id + * @RING_ID_DRIVER_DEBUG: Driver debug messages ring id + * @RING_ID_FIRMWARE_DEBUG: Firmware debug messages ring id + * + * This enum has the ring id values of logging rings + */ +enum wifi_logging_ring_id { + RING_ID_WAKELOCK, + RING_ID_CONNECTIVITY, + RING_ID_PER_PACKET_STATS, + RING_ID_DRIVER_DEBUG, + RING_ID_FIRMWARE_DEBUG, +}; + +/* ------------------------------------------------------------------- */ +/* Change channel generic scheme */ +typedef void (*CHANGE_CHANNEL_CALLBACK)(tpAniSirGlobal pMac, QDF_STATUS status, + uint32_t *data, + tpPESession psessionEntry); + +/* / LIM global definitions */ +typedef struct sAniSirLimIbss { + void *pHdr; + void *pBeacon; +} tAniSirLimIbss; + +typedef struct sDialogueToken { + /* bytes 0-3 */ + uint16_t assocId; + uint8_t token; + uint8_t rsvd1; + /* Bytes 4-7 */ + uint16_t tid; + uint8_t rsvd2[2]; + + struct sDialogueToken *next; +} tDialogueToken, *tpDialogueToken; + +typedef struct sLimTimers { + /* TIMERS IN LIM ARE NOT SUPPOSED TO BE ZEROED OUT DURING RESET. */ + /* DURING lim_initialize DONOT ZERO THEM OUT. */ + +/* STA SPECIFIC TIMERS */ + + TX_TIMER gLimPreAuthClnupTimer; + + /* Association related timers */ + TX_TIMER gLimAssocFailureTimer; + TX_TIMER gLimReassocFailureTimer; + + /* / Wait for Probe after Heartbeat failure timer on STA */ + TX_TIMER gLimProbeAfterHBTimer; + + /* Authentication related timers */ + TX_TIMER gLimAuthFailureTimer; + + /* Join Failure timeout on STA */ + TX_TIMER gLimJoinFailureTimer; + + TX_TIMER gLimPeriodicProbeReqTimer; + + /* CNF_WAIT timer */ + TX_TIMER *gpLimCnfWaitTimer; + + TX_TIMER gLimAddtsRspTimer; /* max wait for a response */ + + /* Update OLBC Cache Timer */ + TX_TIMER gLimUpdateOlbcCacheTimer; + + TX_TIMER gLimChannelSwitchTimer; + /* This TIMER is started on the STA, as indicated by the */ + /* AP in its Quiet BSS IE, for the specified interval */ + TX_TIMER gLimQuietTimer; + /* This TIMER is started on the AP, prior to the AP going */ + /* into LEARN mode */ + /* This TIMER is started on the STA, for the specified */ + /* quiet duration */ + TX_TIMER gLimQuietBssTimer; + + TX_TIMER gLimFTPreAuthRspTimer; + +#ifdef FEATURE_WLAN_ESE + TX_TIMER gLimEseTsmTimer; +#endif + TX_TIMER gLimRemainOnChannelTimer; + + TX_TIMER gLimPeriodicJoinProbeReqTimer; + TX_TIMER gLimDisassocAckTimer; + TX_TIMER gLimDeauthAckTimer; + /* This timer is started when single shot NOA insert msg is sent to FW for scan in P2P GO mode */ + TX_TIMER gLimP2pSingleShotNoaInsertTimer; + /* This timer is used to convert active channel to + * passive channel when there is no beacon + * for a period of time on a particular DFS channel + */ + TX_TIMER gLimActiveToPassiveChannelTimer; + TX_TIMER g_lim_periodic_auth_retry_timer; + +/* ********************TIMER SECTION ENDS************************************************** */ +/* ALL THE FIELDS BELOW THIS CAN BE ZEROED OUT in lim_initialize */ +/* **************************************************************************************** */ + +} tLimTimers; + +typedef struct { + void *pMlmDisassocReq; + void *pMlmDeauthReq; +} tLimDisassocDeauthCnfReq; + +typedef struct sAniSirLim { + /* //////////////////////////////////// TIMER RELATED START /////////////////////////////////////////// */ + + tLimTimers limTimers; + /* / Flag to track if LIM timers are created or not */ + uint32_t gLimTimersCreated; + + /* //////////////////////////////////// TIMER RELATED END /////////////////////////////////////////// */ + + /* //////////////////////////////////// SCAN/LEARN RELATED START /////////////////////////////////////////// */ + /** + * This flag when set, will use scan mode instead of + * Learn mode on BP/AP. By default this flag is set + * to true until HIF getting stuck in 0x800 state is + * debugged. + */ + uint32_t gLimUseScanModeForLearnMode; + + /** + * This is useful for modules other than LIM + * to see if system is in scan/learn mode or not + */ + uint32_t gLimSystemInScanLearnMode; + + /* Scan related globals on STA */ + uint8_t gLimReturnAfterFirstMatch; + uint8_t gLim24Band11dScanDone; + uint8_t gLim50Band11dScanDone; + uint8_t gLimReturnUniqueResults; + + /* / Place holder for current channel ID */ + /* / being scanned */ + uint32_t gLimCurrentScanChannelId; + + /* Hold onto SCAN criteria */ + /* The below is used in P2P GO case when we need to defer processing SME Req + * to LIM and insert NOA first and process SME req once SNOA is started + */ + uint16_t gDeferMsgTypeForNOA; + uint32_t *gpDefdSmeMsgForNOA; + + tLimMlmScanReq *gpLimMlmScanReq; + + + /* Used to store the list of legacy bss sta detected during scan on one channel */ + uint16_t gLimRestoreCBNumScanInterval; + uint16_t gLimRestoreCBCount; + tSirMacAddr gLimLegacyBssidList[MAX_NUM_LEGACY_BSSID_PER_CHANNEL]; + + /* abort scan is used to abort an on-going scan */ + uint8_t abortScan; + tLimScanChnInfo scanChnInfo; + + /* //////////////////////////////////// SCAN/LEARN RELATED START /////////////////////////////////////////// */ + tSirMacAddr gSelfMacAddr; /* added for BT-AMP Support */ + + /* //////////////////////////////////////// BSS RELATED END /////////////////////////////////////////// */ + /* Place holder for StartBssReq message */ + /* received by SME state machine */ + + uint8_t gLimCurrentBssUapsd; + + /* This is used for testing sta legacy bss detect feature */ + uint8_t gLimForceNoPropIE; + + /* */ + /* Store the BSS Index returned by HAL during */ + /* WMA_ADD_BSS_RSP here. */ + /* */ + + /* For now: */ + /* This will be used during WMA_SET_BSSKEY_REQ in */ + /* order to set the GTK */ + /* Later: */ + /* There could be other interfaces needing this info */ + /* */ + + /* */ + /* Due to the asynchronous nature of the interface */ + /* between PE <-> HAL, some transient information */ + /* like this needs to be cached. */ + /* This is cached upon receipt of eWNI_SME_SETCONTEXT_REQ. */ + /* This is released while posting LIM_MLM_SETKEYS_CNF */ + /* */ + void *gpLimMlmSetKeysReq; + + /* //////////////////////////////////////// BSS RELATED END /////////////////////////////////////////// */ + + /* //////////////////////////////////////// IBSS RELATED START /////////////////////////////////////////// */ + /* This indicates whether this STA coalesced and adapter to peer's capabilities or not. */ + uint8_t gLimIbssCoalescingHappened; + + /* / Definition for storing IBSS peers BSS description */ + tLimIbssPeerNode *gLimIbssPeerList; + uint32_t gLimNumIbssPeers; + uint32_t ibss_retry_cnt; + + /* ibss info - params for which ibss to join while coalescing */ + tAniSirLimIbss ibssInfo; + + /* //////////////////////////////////////// IBSS RELATED END /////////////////////////////////////////// */ + + /* //////////////////////////////////////// STATS/COUNTER RELATED START /////////////////////////////////////////// */ + + uint16_t maxStation; + uint16_t maxBssId; + + uint32_t gLimNumBeaconsRcvd; + uint32_t gLimNumBeaconsIgnored; + + uint32_t gLimNumDeferredMsgs; + + /* / Variable to keep track of number of currently associated STAs */ + uint16_t gLimNumOfAniSTAs; /* count of ANI peers */ + uint16_t gLimAssocStaLimit; + + /* Heart-Beat interval value */ + uint32_t gLimHeartBeatCount; + tSirMacAddr gLimHeartBeatApMac[2]; + uint8_t gLimHeartBeatApMacIndex; + + /* Statistics to keep track of no. beacons rcvd in heart beat interval */ + uint16_t + gLimHeartBeatBeaconStats[MAX_NO_BEACONS_PER_HEART_BEAT_INTERVAL]; + +#ifdef WLAN_DEBUG + /* Debug counters */ + uint32_t numTot, numBbt, numProtErr, numLearn, numLearnIgnore; + uint32_t numSme, numMAC[4][16]; + + /* Debug counter to track number of Assoc Req frame drops */ + /* when received in pStaDs->mlmState other than LINK_ESTABLISED */ + uint32_t gLimNumAssocReqDropInvldState; + /* counters to track rejection of Assoc Req due to Admission Control */ + uint32_t gLimNumAssocReqDropACRejectTS; + uint32_t gLimNumAssocReqDropACRejectSta; + /* Debug counter to track number of Reassoc Req frame drops */ + /* when received in pStaDs->mlmState other than LINK_ESTABLISED */ + uint32_t gLimNumReassocReqDropInvldState; + /* Debug counter to track number of Hash Miss event that */ + /* will not cause a sending of de-auth/de-associate frame */ + uint32_t gLimNumHashMissIgnored; + + /* Debug counter to track number of Beacon frames */ + /* received in unexpected state */ + uint32_t gLimUnexpBcnCnt; + + /* Debug counter to track number of Beacon frames */ + /* received in wt-join-state that do have SSID mismatch */ + uint32_t gLimBcnSSIDMismatchCnt; + + /* Debug counter to track number of Link establishments on STA/BP */ + uint32_t gLimNumLinkEsts; + + /* Debug counter to track number of Rx cleanup */ + uint32_t gLimNumRxCleanup; + + /* Debug counter to track different parse problem */ + uint32_t gLim11bStaAssocRejectCount; + +#endif + + /* Time stamp of the last beacon received from the BSS to which STA is connected. */ + uint64_t gLastBeaconTimeStamp; + /* RX Beacon count for the current BSS to which STA is connected. */ + uint32_t gCurrentBssBeaconCnt; + uint8_t gLastBeaconDtimCount; + uint8_t gLastBeaconDtimPeriod; + + /* //////////////////////////////////////// STATS/COUNTER RELATED END /////////////////////////////////////////// */ + + /* //////////////////////////////////////// STATES RELATED START /////////////////////////////////////////// */ + /* Counts Heartbeat failures */ + uint8_t gLimHBfailureCntInLinkEstState; + uint8_t gLimProbeFailureAfterHBfailedCnt; + uint8_t gLimHBfailureCntInOtherStates; + + /** + * This variable indicates whether LIM module need to + * send response to host. Used to identify whether a request + * is generated internally within LIM module or by host + */ + uint8_t gLimRspReqd; + + /* / Previous SME State */ + tLimSmeStates gLimPrevSmeState; + + /* / MLM State visible across all Sirius modules */ + tLimMlmStates gLimMlmState; + + /* / Previous MLM State */ + tLimMlmStates gLimPrevMlmState; + + /* LIM to HAL SCAN Management Message Interface states */ + tLimLimHalScanState gLimHalScanState; +/* WLAN_SUSPEND_LINK Related */ + SUSPEND_RESUME_LINK_CALLBACK gpLimSuspendCallback; + uint32_t *gpLimSuspendData; + SUSPEND_RESUME_LINK_CALLBACK gpLimResumeCallback; + uint32_t *gpLimResumeData; +/* end WLAN_SUSPEND_LINK Related */ + /* Can be set to invalid channel. If it is invalid, HAL */ + /* should move to previous valid channel or stay in the */ + /* current channel. CB state goes along with channel to resume to */ + uint16_t gResumeChannel; + ePhyChanBondState gResumePhyCbState; + + /* Change channel generic scheme */ + CHANGE_CHANNEL_CALLBACK gpchangeChannelCallback; + uint32_t *gpchangeChannelData; + + /* / SME State visible across all Sirius modules */ + tLimSmeStates gLimSmeState; + /* / This indicates whether we're an AP, STA in BSS/IBSS */ + tLimSystemRole gLimSystemRole; + + /* Number of STAs that do not support short preamble */ + tLimNoShortParams gLimNoShortParams; + + /* Number of STAs that do not support short slot time */ + tLimNoShortSlotParams gLimNoShortSlotParams; + + /* OLBC parameters */ + tLimProtStaParams gLimOverlap11gParams; + + tLimProtStaParams gLimOverlap11aParams; + tLimProtStaParams gLimOverlapHt20Params; + tLimProtStaParams gLimOverlapNonGfParams; + + /* */ + /* ---------------- DPH ----------------------- */ + /* these used to live in DPH but are now moved here (where they belong) */ + uint32_t gLimPhyMode; + uint32_t propRateAdjustPeriod; + uint32_t scanStartTime; /* used to measure scan time */ + + uint8_t gLimMyMacAddr[6]; + uint8_t ackPolicy; + + uint8_t gLimQosEnabled:1; /* 11E */ + uint8_t gLimWmeEnabled:1; /* WME */ + uint8_t gLimWsmEnabled:1; /* WSM */ + uint8_t gLimHcfEnabled:1; + uint8_t gLim11dEnabled:1; + uint8_t gLimProbeRespDisableFlag:1; /* control over probe response */ + /* ---------------- DPH ----------------------- */ + + /* //////////////////////////////////////// STATES RELATED END /////////////////////////////////////////// */ + + /* //////////////////////////////////////// MISC RELATED START /////////////////////////////////////////// */ + + /* Deferred Queue Parameters */ + tLimDeferredMsgQParams gLimDeferredMsgQ; + + /* addts request if any - only one can be outstanding at any time */ + tSirAddtsReq gLimAddtsReq; + uint8_t gLimAddtsSent; + uint8_t gLimAddtsRspTimerCount; + + /* protection related config cache */ + tCfgProtection cfgProtection; + + uint8_t gLimProtectionControl; + /* This flag will remain to be set except while LIM is waiting for specific response messages */ + /* from HAL. e.g when LIM issues ADD_STA req it will clear this flag and when it will receive */ + /* the response the flag will be set. */ + uint8_t gLimProcessDefdMsgs; + + /* UAPSD flag used on AP */ + uint8_t gUapsdEnable; + + /* Used on STA for AC downgrade. This is a dynamic mask + * setting which keep tracks of ACs being admitted. + * If bit is set to 0: That partiular AC is not admitted + * If bit is set to 1: That particular AC is admitted + */ + uint8_t gAcAdmitMask[SIR_MAC_DIRECTION_DIRECT]; + + /* dialogue token List head/tail for Action frames request sent. */ + tpDialogueToken pDialogueTokenHead; + tpDialogueToken pDialogueTokenTail; + + tLimTspecInfo tspecInfo[LIM_NUM_TSPEC_MAX]; + + /* admission control policy information */ + tLimAdmitPolicyInfo admitPolicyInfo; + qdf_mutex_t lkPeGlobalLock; + uint8_t disableLDPCWithTxbfAP; +#ifdef FEATURE_WLAN_TDLS + uint8_t gLimTDLSBufStaEnabled; + uint8_t gLimTDLSUapsdMask; + uint8_t gLimTDLSOffChannelEnabled; + uint8_t gLimTDLSWmmMode; +#endif + /* //////////////////////////////////////// MISC RELATED END /////////////////////////////////////////// */ + + /* //////////////////////////////////////// ASSOC RELATED START /////////////////////////////////////////// */ + /* Place holder for JoinReq message */ + /* received by SME state machine */ + /* tpSirSmeJoinReq gpLimJoinReq; */ + + /* Place holder for ReassocReq message */ + /* received by SME state machine */ + /* tpSirSmeReassocReq gpLimReassocReq; sep23 review */ + + /* Current Authentication type used at STA */ + /* tAniAuthType gLimCurrentAuthType; */ + + /* Place holder for current authentication request */ + /* being handled */ + tLimMlmAuthReq *gpLimMlmAuthReq; + + /* Reason code to determine the channel change context while sending */ + /* WMA_CHNL_SWITCH_REQ message to HAL */ + uint32_t channelChangeReasonCode; + + /* / MAC level Pre-authentication related globals */ + tSirMacChanNum gLimPreAuthChannelNumber; + tAniAuthType gLimPreAuthType; + tSirMacAddr gLimPreAuthPeerAddr; + uint32_t gLimNumPreAuthContexts; + tLimPreAuthTable gLimPreAuthTimerTable; + + /* Placed holder to deauth reason */ + uint16_t gLimDeauthReasonCode; + + /* Place holder for Pre-authentication node list */ + struct tLimPreAuthNode *pLimPreAuthList; + + /* Assoc or ReAssoc Response Data/Frame */ + void *gLimAssocResponseData; + + /* One cache for each overlap and associated case. */ + tCacheParams protStaOverlapCache[LIM_PROT_STA_OVERLAP_CACHE_SIZE]; + tCacheParams protStaCache[LIM_PROT_STA_CACHE_SIZE]; + + /* //////////////////////////////////////// ASSOC RELATED END /////////////////////////////////////////// */ + + /* ////////////////////////////// HT RELATED ////////////////////////////////////////// */ + /* */ + /* The following global LIM variables maintain/manage */ + /* the runtime configurations related to 802.11n */ + + /* 802.11n Station detected HT capability in Beacon Frame */ + uint8_t htCapabilityPresentInBeacon; + + /* 802.11 HT capability: Enabled or Disabled */ + uint8_t htCapability; + + uint8_t gHTGreenfield; + + uint8_t gHTShortGI40Mhz; + uint8_t gHTShortGI20Mhz; + + /* Set to 0 for 3839 octets */ + /* Set to 1 for 7935 octets */ + uint8_t gHTMaxAmsduLength; + + /* DSSS/CCK at 40 MHz: Enabled 1 or Disabled */ + uint8_t gHTDsssCckRate40MHzSupport; + + /* PSMP Support: Enabled 1 or Disabled 0 */ + uint8_t gHTPSMPSupport; + + /* L-SIG TXOP Protection used only if peer support available */ + uint8_t gHTLsigTXOPProtection; + + /* MIMO Power Save */ + tSirMacHTMIMOPowerSaveState gHTMIMOPSState; + + /* Scan In Power Save */ + uint8_t gScanInPowersave; + + /* */ + /* A-MPDU Density */ + /* 000 - No restriction */ + /* 001 - 1/8 usec */ + /* 010 - 1/4 usec */ + /* 011 - 1/2 usec */ + /* 100 - 1 usec */ + /* 101 - 2 usec */ + /* 110 - 4 usec */ + /* 111 - 8 usec */ + /* */ + uint8_t gHTAMpduDensity; + + bool gMaxAmsduSizeEnabled; + /* Maximum Tx/Rx A-MPDU factor */ + uint8_t gHTMaxRxAMpduFactor; + + /* */ + /* Scheduled PSMP related - Service Interval Granularity */ + /* 000 - 5 ms */ + /* 001 - 10 ms */ + /* 010 - 15 ms */ + /* 011 - 20 ms */ + /* 100 - 25 ms */ + /* 101 - 30 ms */ + /* 110 - 35 ms */ + /* 111 - 40 ms */ + /* */ + uint8_t gHTServiceIntervalGranularity; + + /* Indicates whether an AP wants to associate PSMP enabled Stations */ + uint8_t gHTControlledAccessOnly; + + /* RIFS Mode. Set if no APSD legacy devices associated */ + uint8_t gHTRifsMode; + /* OBss Mode . set when we have Non HT STA is associated or with in overlap bss */ + uint8_t gHTObssMode; + + /* Identifies the current Operating Mode */ + tSirMacHTOperatingMode gHTOperMode; + + /* Indicates if PCO is activated in the BSS */ + uint8_t gHTPCOActive; + + /* */ + /* If PCO is active, indicates which PCO phase to use */ + /* 0 - switch to 20 MHz phase */ + /* 1 - switch to 40 MHz phase */ + /* */ + uint8_t gHTPCOPhase; + + /* */ + /* Used only in beacons. For PR, this is set to 0 */ + /* 0 - Primary beacon */ + /* 1 - Secondary beacon */ + /* */ + uint8_t gHTSecondaryBeacon; + + /* */ + /* Dual CTS Protection */ + /* 0 - Use RTS/CTS */ + /* 1 - Dual CTS Protection is used */ + /* */ + uint8_t gHTDualCTSProtection; + + /* */ + /* Identifies a single STBC MCS that shall ne used for */ + /* STBC control frames and STBC beacons */ + /* */ + uint8_t gHTSTBCBasicMCS; + + uint8_t gHTNonGFDevicesPresent; + + /* ////////////////////////////// HT RELATED ////////////////////////////////////////// */ + +#ifdef FEATURE_WLAN_TDLS + uint8_t gLimAddStaTdls; + uint8_t gLimTdlsLinkMode; + /* ////////////////////////////// TDLS RELATED ////////////////////////////////////////// */ +#endif + + /* wsc info required to form the wsc IE */ + tLimWscIeInfo wscIeInfo; + tpPESession gpSession; /* Pointer to session table */ + /* + * sessionID and transactionID from SME is stored here for those messages, for which + * there is no session context in PE, e.g. Scan related messages. + **/ + uint8_t gSmeSessionId; + uint16_t gTransactionId; + + tSirRemainOnChnReq *gpLimRemainOnChanReq; /* hold remain on chan request in this buf */ + qdf_mutex_t lim_frame_register_lock; + qdf_list_t gLimMgmtFrameRegistratinQueue; + uint32_t mgmtFrameSessionId; + uint32_t tdls_frm_session_id; + + tpPESession pSessionEntry; + uint8_t reAssocRetryAttempt; + tLimDisassocDeauthCnfReq limDisassocDeauthCnfReq; + uint8_t deferredMsgCnt; + tSirDFSChannelList dfschannelList; + uint8_t gLimIbssStaLimit; + + /* Number of channel switch IEs sent so far */ + uint8_t gLimDfsChanSwTxCount; + uint8_t gLimDfsTargetChanNum; + uint8_t probeCounter; + uint8_t maxProbe; + QDF_STATUS(*add_bssdescr_callback) + (tpAniSirGlobal pMac, tpSirBssDescription buf, + uint32_t scan_id, uint32_t flags); + QDF_STATUS(*sme_msg_callback) + (tHalHandle hal, cds_msg_t *msg); + uint8_t retry_packet_cnt; + uint8_t scan_disabled; + uint8_t beacon_probe_rsp_cnt_per_scan; +} tAniSirLim, *tpAniSirLim; + +struct mgmt_frm_reg_info { + qdf_list_node_t node; /* MUST be first element */ + uint16_t frameType; + uint16_t matchLen; + uint16_t sessionId; + uint8_t matchData[1]; +}; + +typedef struct sRrmContext { + tRrmSMEContext rrmSmeContext; + tRrmPEContext rrmPEContext; +} tRrmContext, *tpRrmContext; + +/** + * enum tDriverType - Indicate the driver type to the mac, and based on this + * do appropriate initialization. + * + * @eDRIVER_TYPE_PRODUCTION: + * @eDRIVER_TYPE_MFG: + * + */ +typedef enum { + eDRIVER_TYPE_PRODUCTION = 0, + eDRIVER_TYPE_MFG = 1, +} tDriverType; + +typedef struct sHalMacStartParameters { + /* parametes for the Firmware */ + tDriverType driverType; + +} tHalMacStartParameters; + +/** + * enum auth_tx_ack_status - Indicate TX status of AUTH + * @LIM_AUTH_ACK_NOT_RCD : Default status while waiting for ack status. + * @LIM_AUTH_ACK_RCD_SUCCESS : Ack is received. + * @LIM_AUTH_ACK_RCD_FAILURE : No Ack received. + * + * Indicate if driver is waiting for ACK status of auth or ACK received for AUTH + * OR NO ACK is received for the auth sent. + */ +enum auth_tx_ack_status { + LIM_AUTH_ACK_NOT_RCD, + LIM_AUTH_ACK_RCD_SUCCESS, + LIM_AUTH_ACK_RCD_FAILURE, +}; +/** + * struct vdev_type_nss - vdev type nss structure + * @sta: STA Nss value. + * @sap: SAP Nss value. + * @p2p_go: P2P GO Nss value. + * @p2p_cli: P2P CLI Nss value. + * @p2p_dev: P2P device Nss value. + * @ibss: IBSS Nss value. + * @tdls: TDLS Nss value. + * @ocb: OCB Nss value. + * + * Holds the Nss values of different vdev types. + */ +struct vdev_type_nss { + uint8_t sta; + uint8_t sap; + uint8_t p2p_go; + uint8_t p2p_cli; + uint8_t p2p_dev; + uint8_t ibss; + uint8_t tdls; + uint8_t ocb; +}; + +/* ------------------------------------------------------------------- */ +/* / MAC Sirius parameter structure */ +typedef struct sAniSirGlobal { + tDriverType gDriverType; + + tAniSirCfg cfg; + tAniSirLim lim; + tAniSirSch sch; + tAniSirSys sys; + tAniSirUtils utils; + + /* PAL/HDD handle */ + tHddHandle hHdd; + + + tSmeStruct sme; + tSapStruct sap; + tCsrScanStruct scan; + tCsrRoamStruct roam; + + tRrmContext rrm; +#ifdef WLAN_FEATURE_CONCURRENT_P2P + tp2pContext p2pContext[MAX_NO_OF_P2P_SESSIONS]; +#else + tp2pContext p2pContext; +#endif + +#ifdef FEATURE_WLAN_TDLS + bool is_tdls_power_save_prohibited; +#endif + + uint8_t isCoalesingInIBSSAllowed; + + /* PNO offload */ + bool pnoOffload; + + csr_readyToSuspendCallback readyToSuspendCallback; + void *readyToSuspendContext; + uint8_t lteCoexAntShare; + uint8_t beacon_offload; + bool pmf_offload; + uint32_t fEnableDebugLog; + uint16_t mgmtSeqNum; + bool enable5gEBT; + /* Miracast session 0-Disabled, 1-Source, 2-sink */ + uint8_t fMiracastSessionPresent; +#ifdef WLAN_FEATURE_EXTWOW_SUPPORT + csr_readyToExtWoWCallback readyToExtWoWCallback; + void *readyToExtWoWContext; +#endif + uint32_t f_sta_miracast_mcc_rest_time_val; + uint8_t f_prefer_non_dfs_on_radar; + hdd_ftm_msg_processor ftm_msg_processor_callback; + uint32_t fine_time_meas_cap; + struct vdev_type_nss vdev_type_nss_2g; + struct vdev_type_nss vdev_type_nss_5g; + + /* 802.11p enable */ + bool enable_dot11p; + + bool allow_adj_ch_bcn; + /* DBS capability based on INI and FW capability */ + uint8_t hw_dbs_capable; + /* Based on INI parameter */ + uint32_t dual_mac_feature_disable; + sir_mgmt_frame_ind_callback mgmt_frame_ind_cb; + sir_p2p_ack_ind_callback p2p_ack_ind_cb; + bool first_scan_done; + int8_t first_scan_bucket_threshold; + enum auth_tx_ack_status auth_ack_status; + uint8_t user_configured_nss; + bool sta_prefer_80MHz_over_160MHz; + enum country_src reg_hint_src; + uint32_t rx_packet_drop_counter; + struct candidate_chan_info candidate_channel_info[QDF_MAX_NUM_CHAN]; +} tAniSirGlobal; + +typedef enum { + eHIDDEN_SSID_NOT_IN_USE, + eHIDDEN_SSID_ZERO_LEN, + eHIDDEN_SSID_ZERO_CONTENTS +} tHiddenssId; + +#ifdef FEATURE_WLAN_TDLS + +#define RFC1042_HDR_LENGTH (6) +#define GET_BE16(x) ((uint16_t) (((x)[0] << 8) | (x)[1])) +#define ETH_TYPE_89_0d (0x890d) +#define ETH_TYPE_LEN (2) +#define PAYLOAD_TYPE_TDLS_SIZE (1) +#define PAYLOAD_TYPE_TDLS (2) + +#endif + +#endif /* _ANIGLOBAL_H */ diff --git a/drivers/staging/qcacld-3.0/core/mac/inc/ani_system_defs.h b/drivers/staging/qcacld-3.0/core/mac/inc/ani_system_defs.h new file mode 100644 index 0000000000000000000000000000000000000000..4d5796ec82d40ff569e78328bf8a6b38261a270d --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/inc/ani_system_defs.h @@ -0,0 +1,214 @@ +/* + * Copyright (c) 2011-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * + * This file ani_system_defs.h contains definitions used by + * various ANI entities + * Author: Chandra Modumudi + * Date: 09/18/2002 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + */ + +#ifndef __ANI_SYSTEM_DEFS_H +#define __ANI_SYSTEM_DEFS_H + +#include "sir_types.h" +#include "sir_mac_prot_def.h" + +#define ANI_OUI 0x000AF5 + +/* / Max WDS info length. */ +#define ANI_WDS_INFO_MAX_LENGTH 64 + +/* This is to force compiler to use the maximum of an int for enum */ +#define SIR_MAX_ENUM_SIZE 0x7FFFFFFF + +/* Max key size including the WAPI and TKIP */ +#define WLAN_MAX_KEY_RSC_LEN 16 +#define WLAN_WAPI_KEY_RSC_LEN 16 + +#ifndef false +#undef false +#define false 0 +#endif +#ifndef true +#undef true +#define true 1 +#endif + +typedef enum eAniBool { + eSIR_FALSE, + eSIR_TRUE, + eSIR_DONOT_USE_BOOL = SIR_MAX_ENUM_SIZE +} tAniBool; + +/* / Authentication type enum used with peer */ +typedef enum eAniAuthType { + eSIR_OPEN_SYSTEM, + eSIR_SHARED_KEY, + eSIR_FT_AUTH, +#if defined FEATURE_WLAN_ESE + eSIR_LEAP_AUTH = 0x80, +#endif + eSIR_AUTO_SWITCH, + eSIR_DONOT_USE_AUTH_TYPE = SIR_MAX_ENUM_SIZE +} tAniAuthType; + +/* / Encryption type enum used with peer */ +typedef enum eAniEdType { + eSIR_ED_NONE, + eSIR_ED_WEP40, + eSIR_ED_WEP104, + eSIR_ED_TKIP, + eSIR_ED_CCMP, +#if defined(FEATURE_WLAN_WAPI) + eSIR_ED_WPI, +#endif + /*DPU HW treats encryption mode 4 plus RMF bit set in TX BD as BIP. + Thus while setting BIP encryption mode in corresponding DPU Desc + eSIR_ED_AES_128_CMAC should be set to eSIR_ED_CCMP */ + eSIR_ED_AES_128_CMAC, + eSIR_ED_NOT_IMPLEMENTED = SIR_MAX_ENUM_SIZE +} tAniEdType; + +typedef enum eAniWepType { + eSIR_WEP_STATIC, + eSIR_WEP_DYNAMIC, +} tAniWepType; + +/* / Enum to specify whether key is used */ +/* / for TX only, RX only or both */ +typedef enum eAniKeyDirection { + eSIR_TX_ONLY, + eSIR_RX_ONLY, + eSIR_TX_RX, + eSIR_TX_DEFAULT, + eSIR_DONOT_USE_KEY_DIRECTION = SIR_MAX_ENUM_SIZE +} tAniKeyDirection; + +typedef struct sAniSSID { + uint8_t length; + uint8_t ssId[SIR_MAC_MAX_SSID_LENGTH]; +} tAniSSID, *tpAniSSID; + +typedef struct sAniApName { + uint8_t length; + uint8_t name[SIR_MAC_MAX_SSID_LENGTH]; +} tAniApName, *tpAniApName; + +/* / RSN IE information */ +typedef struct sSirRSNie { + uint16_t length; + uint8_t rsnIEdata[SIR_MAC_MAX_IE_LENGTH + 2]; +} tSirRSNie, *tpSirRSNie; + +typedef struct sSirWAPIie { + uint16_t length; + uint8_t wapiIEdata[SIR_MAC_MAX_IE_LENGTH + 2]; +} tSirWAPIie, *tpSirWAPIie; +/* / Additional IE information : */ +/* / This can include WSC IE, P2P IE, and/or FTIE from upper layer. */ +/* / MAC layer transparently convey these IE info between peer STA and upper layer, */ +/* / but never requires to parse it. */ +typedef struct sSirAddie { + uint16_t length; + uint8_t addIEdata[SIR_MAC_MAX_ADD_IE_LENGTH + 2]; +} tSirAddie, *tpSirAddie; + +#ifdef FEATURE_WLAN_ESE + +/* The CCKM IE needs to be in the */ +/* Join and Reassoc Req. */ +typedef struct sSirCCKMie { + uint16_t length; + uint8_t cckmIEdata[SIR_MAC_MAX_IE_LENGTH + 2]; +} tSirCCKMie, *tpSirCCKMie; + +#endif + +/* / Definition for Encryption Keys */ +typedef struct sSirKeys { + uint8_t keyId; + uint8_t unicast; /* 0 for multicast */ + tAniKeyDirection keyDirection; + uint8_t keyRsc[WLAN_MAX_KEY_RSC_LEN]; /* Usage is unknown */ + uint8_t paeRole; /* =1 for authenticator, */ + /* =0 for supplicant */ + uint16_t keyLength; + uint8_t key[SIR_MAC_MAX_KEY_LENGTH]; +} tSirKeys, *tpSirKeys; + +/* / Definition for Keying material */ +typedef struct sSirKeyMaterial { + uint16_t length; /* This is the length of all */ + /* data that follows */ + tAniEdType edType; /* Encryption/Decryption type */ + uint8_t numKeys; + tSirKeys key[1]; +} tSirKeyMaterial, *tpSirKeyMaterial; + +#define SIR_CIPHER_SEQ_CTR_SIZE 6 +/* / Definition for MIC failure indication */ +typedef struct sSirMicFailureInfo { + tSirMacAddr srcMacAddr; /* address used to compute MIC */ + tSirMacAddr taMacAddr; /* transmitter address */ + tSirMacAddr dstMacAddr; + tAniBool multicast; + uint8_t IV1; /* first byte of IV */ + uint8_t keyId; /* second byte of IV */ + uint8_t TSC[SIR_CIPHER_SEQ_CTR_SIZE]; /* sequence number */ + tSirMacAddr rxMacAddr; /* receive address */ + +} tSirMicFailureInfo, *tpSirMicFailureInfo; + +typedef struct sTrafStrmMetrics { + uint16_t UplinkPktQueueDly; + uint16_t UplinkPktQueueDlyHist[4]; + uint32_t UplinkPktTxDly; + uint16_t UplinkPktLoss; + uint16_t UplinkPktCount; + uint8_t RoamingCount; + uint16_t RoamingDly; +} qdf_packed tTrafStrmMetrics, *tpTrafStrmMetrics; + +typedef struct sBcnReportFields { + uint8_t ChanNum; + uint8_t Spare; + uint16_t MeasDuration; + uint8_t PhyType; + uint8_t RecvSigPower; + tSirMacAddr Bssid; + uint32_t ParentTsf; + uint32_t TargetTsf[2]; + uint16_t BcnInterval; + uint16_t CapabilityInfo; +} qdf_packed tBcnReportFields, *tpBcnReportFields; + +#endif /* __ANI_SYSTEM_DEFS_H */ diff --git a/drivers/staging/qcacld-3.0/core/mac/inc/mac_init_api.h b/drivers/staging/qcacld-3.0/core/mac/inc/mac_init_api.h new file mode 100644 index 0000000000000000000000000000000000000000..1a231d43f4e996a2f4a68a21d0b3a48c5f0b730a --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/inc/mac_init_api.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2011-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * + * mac_init_api.c - Header file for mac level init functions + * Author: Dinesh Upadhyay + * Date: 04/23/2007 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------------- + * + */ +#ifndef __MAC_INIT_API_H +#define __MAC_INIT_API_H + +#include "ani_global.h" +#include "sir_types.h" + +tSirRetStatus mac_start(tHalHandle hHal, void *pHalMacStartParams); +tSirRetStatus mac_stop(tHalHandle hHal, tHalStopType stopType); +tSirRetStatus mac_open(tHalHandle *pHalHandle, tHddHandle hHdd, + struct cds_config_info *cds_cfg); +tSirRetStatus mac_close(tHalHandle hHal); + +#endif /* __MAC_INIT_API_H */ diff --git a/drivers/staging/qcacld-3.0/core/mac/inc/mac_trace.h b/drivers/staging/qcacld-3.0/core/mac/inc/mac_trace.h new file mode 100644 index 0000000000000000000000000000000000000000..919b0f5bf96bf75f99fe3e7dcd0043cfb6c44913 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/inc/mac_trace.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2013-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/**========================================================================= + + * \file mac_trace.h + + * \brief definition for trace related APIs + + \author Sunit Bhatia + + ========================================================================*/ + +#ifndef __MAC_TRACE_H +#define __MAC_TRACE_H + +#include "ani_global.h" + +#ifdef TRACE_RECORD + +#define MAC_TRACE_GET_MODULE_ID(data) ((data >> 8) & 0xff) +#define MAC_TRACE_GET_MSG_ID(data) (data & 0xffff) + +#define eLOG_NODROP_MISSED_BEACON_SCENARIO 0 +#define eLOG_PROC_DEAUTH_FRAME_SCENARIO 1 + +void mac_trace(tpAniSirGlobal pMac, uint8_t code, uint16_t session, + uint32_t data); +void mac_trace_new(tpAniSirGlobal pMac, uint8_t module, uint8_t code, + uint16_t session, uint32_t data); +uint8_t *mac_trace_get_cfg_msg_string(uint16_t cfgMsg); +uint8_t *mac_trace_get_lim_msg_string(uint16_t limMsg); +uint8_t *mac_trace_get_wma_msg_string(uint16_t wmaMsg); +uint8_t *mac_trace_get_sme_msg_string(uint16_t smeMsg); +uint8_t *mac_trace_get_info_log_string(uint16_t infoLog); +QDF_STATUS pe_acquire_global_lock(tAniSirLim *psPe); +QDF_STATUS pe_release_global_lock(tAniSirLim *psPe); + +uint8_t *mac_trace_get_neighbour_roam_state(uint16_t neighbourRoamState); +uint8_t *mac_trace_getcsr_roam_state(uint16_t csr_roamState); +uint8_t *mac_trace_getcsr_roam_sub_state(uint16_t csr_roamSubState); +uint8_t *mac_trace_get_lim_sme_state(uint16_t limState); +uint8_t *mac_trace_get_lim_mlm_state(uint16_t mlmState); +uint8_t *mac_trace_get_tl_state(uint16_t tlState); + +#endif + +#endif diff --git a/drivers/staging/qcacld-3.0/core/mac/inc/qwlan_version.h b/drivers/staging/qcacld-3.0/core/mac/inc/qwlan_version.h new file mode 100644 index 0000000000000000000000000000000000000000..df34f590582ecc66eb983ad6408cf1ab69ba0d5a --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/inc/qwlan_version.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef QWLAN_VERSION_H +#define QWLAN_VERSION_H +/*=========================================================================== + + FILE: + qwlan_version.h + + BRIEF DESCRIPTION: + WLAN Host Version file. + Build number automaticly updated by build scripts. + + ===========================================================================*/ + +#define QWLAN_VERSION_MAJOR 5 +#define QWLAN_VERSION_MINOR 1 +#define QWLAN_VERSION_PATCH 0 +#define QWLAN_VERSION_EXTRA "S" +#define QWLAN_VERSION_BUILD 64 + +#define QWLAN_VERSIONSTR "5.1.0.64S" + +#endif /* QWLAN_VERSION_H */ diff --git a/drivers/staging/qcacld-3.0/core/mac/inc/sir_api.h b/drivers/staging/qcacld-3.0/core/mac/inc/sir_api.h new file mode 100644 index 0000000000000000000000000000000000000000..200dce2d76068baaa6304cc9679eaddefc467da8 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/inc/sir_api.h @@ -0,0 +1,7076 @@ +/* + * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * This file sir_api.h contains definitions exported by + * Sirius software. + * Author: Chandra Modumudi + * Date: 04/16/2002 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + */ + +#ifndef __SIR_API_H +#define __SIR_API_H + + +/* Take care to avoid redefinition of this type, if it is */ +/* already defined in "halWmmApi.h" */ +#if !defined(_HALMAC_WMM_API_H) +typedef struct sAniSirGlobal *tpAniSirGlobal; +#endif + +#include "qdf_types.h" +#include "cds_reg_service.h" +#include "cds_regdomain.h" +#include "sir_types.h" +#include "sir_mac_prot_def.h" +#include "ani_system_defs.h" +#include "sir_params.h" +#include "cds_regdomain.h" +#include "wmi_unified.h" +#include "wmi_unified_param.h" +#include + +#define MAX_PEERS 32 + +#define OFFSET_OF(structType, fldName) (&((structType *)0)->fldName) + +/* / Max supported channel list */ +#define SIR_MAX_SUPPORTED_CHANNEL_LIST 96 + +#define SIR_MDIE_ELEMENT_ID 54 +#define SIR_MDIE_SIZE 3 /* MD ID(2 bytes), Capability(1 byte) */ + +/* Increase dwell time for P2P search in ms */ +#define P2P_SEARCH_DWELL_TIME_INCREASE 20 +#define P2P_SOCIAL_CHANNELS 3 + +/* Max number of channels are 165, but to access 165th element of array, + *array of 166 is required. + */ +#define SIR_MAX_24G_5G_CHANNEL_RANGE 166 +#define SIR_BCN_REPORT_MAX_BSS_DESC 4 + +#define SIR_NUM_11B_RATES 4 /* 1,2,5.5,11 */ +#define SIR_NUM_11A_RATES 8 /* 6,9,12,18,24,36,48,54 */ + +#define SIR_PM_SLEEP_MODE 0 +#define SIR_PM_ACTIVE_MODE 1 + +/* hidden SSID options */ +#define SIR_SCAN_NO_HIDDEN_SSID 0 +#define SIR_SCAN_HIDDEN_SSID_PE_DECISION 1 + +#define SIR_IPV4_ADDR_LEN 4 + +typedef uint8_t tSirIpv4Addr[SIR_IPV4_ADDR_LEN]; + +#define SIR_VERSION_STRING_LEN 64 +typedef uint8_t tSirVersionString[SIR_VERSION_STRING_LEN]; + +/* Periodic Tx pattern offload feature */ +#define PERIODIC_TX_PTRN_MAX_SIZE 1536 +#define MAXNUM_PERIODIC_TX_PTRNS 6 +#define WIFI_SCANNING_MAC_OUI_LENGTH 3 + +#ifdef FEATURE_WLAN_EXTSCAN + +#define WLAN_EXTSCAN_MAX_CHANNELS 36 +#define WLAN_EXTSCAN_MAX_BUCKETS 16 +#define WLAN_EXTSCAN_MAX_HOTLIST_APS 128 +#define WLAN_EXTSCAN_MAX_SIGNIFICANT_CHANGE_APS 64 + +/* This should not be greater than MAX_NUMBER_OF_CONC_CONNECTIONS */ +#define MAX_VDEV_SUPPORTED 4 + +#define MAX_POWER_DBG_ARGS_SUPPORTED 8 +#define QOS_MAP_MAX_EX 21 +#define QOS_MAP_LEN_MIN 16 +#define QOS_MAP_LEN_MAX \ + (QOS_MAP_LEN_MIN + 2 * QOS_MAP_MAX_EX) +#define NUM_CHAINS_MAX 2 + +#define MAX_LEN_UDP_RESP_OFFLOAD 128 + +/** + * enum sir_conn_update_reason: Reason for conc connection update + * @SIR_UPDATE_REASON_SET_OPER_CHAN: Set probable operating channel + * @SIR_UPDATE_REASON_JOIN_IBSS: Join IBSS + * @SIR_UPDATE_REASON_UT: Unit test related + * @SIR_UPDATE_REASON_START_AP: Start AP + * @SIR_UPDATE_REASON_NORMAL_STA: Connection to Normal STA + * @SIR_UPDATE_REASON_HIDDEN_STA: Connection to Hidden STA + * @SIR_UPDATE_REASON_OPPORTUNISTIC: Opportunistic HW mode update + * @SIR_UPDATE_REASON_NSS_UPDATE: NSS update + * @SIR_UPDATE_REASON_CHANNEL_SWITCH: Channel switch + * @SIR_UPDATE_REASON_CHANNEL_SWITCH_STA: Channel switch for STA + */ +enum sir_conn_update_reason { + SIR_UPDATE_REASON_SET_OPER_CHAN, + SIR_UPDATE_REASON_JOIN_IBSS, + SIR_UPDATE_REASON_UT, + SIR_UPDATE_REASON_START_AP, + SIR_UPDATE_REASON_NORMAL_STA, + SIR_UPDATE_REASON_HIDDEN_STA, + SIR_UPDATE_REASON_OPPORTUNISTIC, + SIR_UPDATE_REASON_NSS_UPDATE, + SIR_UPDATE_REASON_CHANNEL_SWITCH, + SIR_UPDATE_REASON_CHANNEL_SWITCH_STA, + SIR_UPDATE_REASON_PRE_CAC, +}; + +typedef enum { + eSIR_EXTSCAN_INVALID, + eSIR_EXTSCAN_START_RSP, + eSIR_EXTSCAN_STOP_RSP, + eSIR_EXTSCAN_CACHED_RESULTS_RSP, + eSIR_EXTSCAN_SET_BSSID_HOTLIST_RSP, + eSIR_EXTSCAN_RESET_BSSID_HOTLIST_RSP, + eSIR_EXTSCAN_SET_SIGNIFICANT_WIFI_CHANGE_RSP, + eSIR_EXTSCAN_RESET_SIGNIFICANT_WIFI_CHANGE_RSP, + + eSIR_EXTSCAN_GET_CAPABILITIES_IND, + eSIR_EXTSCAN_HOTLIST_MATCH_IND, + eSIR_EXTSCAN_SIGNIFICANT_WIFI_CHANGE_RESULTS_IND, + eSIR_EXTSCAN_CACHED_RESULTS_IND, + eSIR_EXTSCAN_SCAN_RES_AVAILABLE_IND, + eSIR_EXTSCAN_SCAN_PROGRESS_EVENT_IND, + eSIR_EXTSCAN_FULL_SCAN_RESULT_IND, + eSIR_EPNO_NETWORK_FOUND_IND, + eSIR_PASSPOINT_NETWORK_FOUND_IND, + eSIR_EXTSCAN_SET_SSID_HOTLIST_RSP, + eSIR_EXTSCAN_RESET_SSID_HOTLIST_RSP, + + /* Keep this last */ + eSIR_EXTSCAN_CALLBACK_TYPE_MAX, +} tSirExtScanCallbackType; + +#endif /* FEATURE_WLAN_EXTSCAN */ + +#define SIR_KRK_KEY_LEN 16 +#define SIR_BTK_KEY_LEN 32 +#define SIR_KCK_KEY_LEN 16 +#define SIR_KEK_KEY_LEN 16 +#define SIR_REPLAY_CTR_LEN 8 +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +#define SIR_UAPSD_BITOFFSET_ACVO 0 +#define SIR_UAPSD_BITOFFSET_ACVI 1 +#define SIR_UAPSD_BITOFFSET_ACBK 2 +#define SIR_UAPSD_BITOFFSET_ACBE 3 + +#define SIR_UAPSD_FLAG_ACVO (1 << SIR_UAPSD_BITOFFSET_ACVO) +#define SIR_UAPSD_FLAG_ACVI (1 << SIR_UAPSD_BITOFFSET_ACVI) +#define SIR_UAPSD_FLAG_ACBK (1 << SIR_UAPSD_BITOFFSET_ACBK) +#define SIR_UAPSD_FLAG_ACBE (1 << SIR_UAPSD_BITOFFSET_ACBE) +#define SIR_UAPSD_GET(ac, mask) (((mask) & (SIR_UAPSD_FLAG_ ## ac)) >> SIR_UAPSD_BITOFFSET_ ## ac) + +#endif + +/** + * enum sir_roam_op_code - Operation to be done by the callback. + * @SIR_ROAM_SYNCH_PROPAGATION: Propagate the new BSS info after roaming. + * @SIR_ROAMING_DEREGISTER_STA: Deregister the old STA after roaming. + * @SIR_ROAMING_START: Firmware started roaming operation + * @SIR_ROAMING_ABORT: Firmware aborted roaming operation, still connected. + * @SIR_ROAM_SYNCH_COMPLETE: Roam sync propagation is complete. + * @SIR_ROAMING_INVOKE_FAIL: Firmware roaming failed. + */ +enum sir_roam_op_code { + SIR_ROAM_SYNCH_PROPAGATION = 1, + SIR_ROAMING_DEREGISTER_STA, + SIR_ROAMING_START, + SIR_ROAMING_ABORT, + SIR_ROAM_SYNCH_COMPLETE, + SIR_ROAM_SYNCH_NAPI_OFF, + SIR_ROAMING_INVOKE_FAIL, +}; +/** + * Module ID definitions. + */ +enum { + SIR_BOOT_MODULE_ID = 1, + SIR_HAL_MODULE_ID = 0x10, + SIR_CFG_MODULE_ID = 0x12, + SIR_LIM_MODULE_ID, + SIR_ARQ_MODULE_ID, + SIR_SCH_MODULE_ID, + SIR_PMM_MODULE_ID, + SIR_MNT_MODULE_ID, + SIR_DBG_MODULE_ID, + SIR_DPH_MODULE_ID, + SIR_SYS_MODULE_ID, + SIR_SMS_MODULE_ID, +}; + +#define SIR_WMA_MODULE_ID SIR_HAL_MODULE_ID + +/** + * First and last module definition for logging utility + * + * NOTE: The following definitions need to be updated if + * the above list is changed. + */ +#define SIR_FIRST_MODULE_ID SIR_HAL_MODULE_ID +#define SIR_LAST_MODULE_ID SIR_SMS_MODULE_ID + +/* Type declarations used by Firmware and Host software */ + +/* Scan type enum used in scan request */ +typedef enum eSirScanType { + eSIR_PASSIVE_SCAN, + eSIR_ACTIVE_SCAN, + eSIR_BEACON_TABLE, +} tSirScanType; + +/* / Result codes Firmware return to Host SW */ +typedef enum eSirResultCodes { + eSIR_SME_SUCCESS, + eSIR_LOGP_EXCEPTION, + eSIR_SME_INVALID_PARAMETERS = 500, + eSIR_SME_UNEXPECTED_REQ_RESULT_CODE, + eSIR_SME_RESOURCES_UNAVAILABLE, + /* Unable to find a BssDescription */ + eSIR_SME_SCAN_FAILED, + /* matching requested scan criteria */ + eSIR_SME_BSS_ALREADY_STARTED_OR_JOINED, + eSIR_SME_LOST_LINK_WITH_PEER_RESULT_CODE, + eSIR_SME_REFUSED, + eSIR_SME_JOIN_DEAUTH_FROM_AP_DURING_ADD_STA, + eSIR_SME_JOIN_TIMEOUT_RESULT_CODE, + eSIR_SME_AUTH_TIMEOUT_RESULT_CODE, + eSIR_SME_ASSOC_TIMEOUT_RESULT_CODE, + eSIR_SME_REASSOC_TIMEOUT_RESULT_CODE, + eSIR_SME_MAX_NUM_OF_PRE_AUTH_REACHED, + eSIR_SME_AUTH_REFUSED, + eSIR_SME_INVALID_WEP_DEFAULT_KEY, + eSIR_SME_NO_KEY_MAPPING_KEY_FOR_PEER, + eSIR_SME_ASSOC_REFUSED, + eSIR_SME_REASSOC_REFUSED, + /* Recvd Deauth while join/pre-auth */ + eSIR_SME_DEAUTH_WHILE_JOIN, + eSIR_SME_STA_NOT_AUTHENTICATED, + eSIR_SME_STA_NOT_ASSOCIATED, + eSIR_SME_ALREADY_JOINED_A_BSS, + /* Given in SME_SCAN_RSP msg */ + eSIR_SME_MORE_SCAN_RESULTS_FOLLOW, + /* that more SME_SCAN_RSP */ + /* messages are following. */ + /* SME_SCAN_RSP message with */ + /* eSIR_SME_SUCCESS status */ + /* code is the last one. */ + /* Sent in SME_JOIN/REASSOC_RSP */ + eSIR_SME_INVALID_ASSOC_RSP_RXED, + /* messages upon receiving */ + /* invalid Re/Assoc Rsp frame. */ + /* STOP BSS triggered by MIC failures: MAC software to + * disassoc all stations + */ + eSIR_SME_MIC_COUNTER_MEASURES, + /* with MIC_FAILURE reason code and perform the stop bss operation */ + /* didn't get rsp from peer within timeout interval */ + eSIR_SME_ADDTS_RSP_TIMEOUT, + /* didn't get success rsp from HAL */ + eSIR_SME_ADDTS_RSP_FAILED, + /* failed to send ch switch act frm */ + eSIR_SME_CHANNEL_SWITCH_FAIL, + eSIR_SME_INVALID_STATE, + /* SIR_HAL_SIR_HAL_INIT_SCAN_RSP returned failed status */ + eSIR_SME_HAL_SCAN_INIT_FAILED, + /* SIR_HAL_END_SCAN_RSP returned failed status */ + eSIR_SME_HAL_SCAN_END_FAILED, + /* SIR_HAL_FINISH_SCAN_RSP returned failed status */ + eSIR_SME_HAL_SCAN_FINISH_FAILED, + /* Failed to send a message to HAL */ + eSIR_SME_HAL_SEND_MESSAGE_FAIL, + /* Failed to stop the bss */ + eSIR_SME_STOP_BSS_FAILURE, + eSIR_SME_WOWL_ENTER_REQ_FAILED, + eSIR_SME_WOWL_EXIT_REQ_FAILED, + eSIR_SME_FT_REASSOC_TIMEOUT_FAILURE, + eSIR_SME_FT_REASSOC_FAILURE, + eSIR_SME_SEND_ACTION_FAIL, + eSIR_SME_DEAUTH_STATUS, + eSIR_PNO_SCAN_SUCCESS, + eSIR_DONOT_USE_RESULT_CODE = SIR_MAX_ENUM_SIZE +} tSirResultCodes; + +#define RMENABLEDCAP_MAX_LEN 5 + +struct rrm_config_param { + uint8_t rrm_enabled; + uint8_t max_randn_interval; + uint8_t rm_capability[RMENABLEDCAP_MAX_LEN]; +}; + +/* + * although in tSirSupportedRates each IE is 16bit but PE only passes IEs in 8 + * bits with MSB=1 for basic rates. change the mask for bit0-7 only so HAL gets + * correct basic rates for setting response rates. + */ +#define IERATE_BASICRATE_MASK 0x80 +#define IERATE_RATE_MASK 0x7f +#define IERATE_IS_BASICRATE(x) ((x) & IERATE_BASICRATE_MASK) + +const char *lim_bss_type_to_string(const uint16_t bss_type); +const char *lim_scan_type_to_string(const uint8_t scan_type); + +typedef struct sSirSupportedRates { + /* + * 11b, 11a and aniLegacyRates are IE rates which gives rate in unit + * of 500Kbps + */ + uint16_t llbRates[SIR_NUM_11B_RATES]; + uint16_t llaRates[SIR_NUM_11A_RATES]; + /* + * 0-76 bits used, remaining reserved + * bits 0-15 and 32 should be set. + */ + uint8_t supportedMCSSet[SIR_MAC_MAX_SUPPORTED_MCS_SET]; + + /* + * RX Highest Supported Data Rate defines the highest data + * rate that the STA is able to receive, in unites of 1Mbps. + * This value is derived from "Supported MCS Set field" inside + * the HT capability element. + */ + uint16_t rxHighestDataRate; + + /*Indicates the Maximum MCS that can be received for each number + of spacial streams */ + uint16_t vhtRxMCSMap; + /*Indicate the highest VHT data rate that the STA is able to receive */ + uint16_t vhtRxHighestDataRate; + /*Indicates the Maximum MCS that can be transmitted for each number + of spacial streams */ + uint16_t vhtTxMCSMap; + /*Indicate the highest VHT data rate that the STA is able to transmit */ + uint16_t vhtTxHighestDataRate; +} tSirSupportedRates, *tpSirSupportedRates; + +typedef enum eSirRFBand { + SIR_BAND_UNKNOWN, + SIR_BAND_2_4_GHZ, + SIR_BAND_5_GHZ, +} tSirRFBand; + +typedef struct sSirRemainOnChnReq { + uint16_t messageType; + uint16_t length; + uint8_t sessionId; + struct qdf_mac_addr selfMacAddr; + uint8_t chnNum; + uint8_t phyMode; + uint32_t duration; + uint8_t isProbeRequestAllowed; + uint32_t scan_id; + uint8_t probeRspIe[1]; +} tSirRemainOnChnReq, *tpSirRemainOnChnReq; + +/** + * struct sir_roc_rsp - Structure to store the remain on channel response + * @message_type: Message Type + * @length: Message Length + * @session_id: SME session Id + * @scan_id : scan identifier + * @status: result status + */ +struct sir_roc_rsp { + uint16_t message_type; + uint16_t length; + uint8_t session_id; + uint32_t scan_id; + tSirResultCodes status; +}; + +typedef struct sSirRegisterMgmtFrame { + uint16_t messageType; + uint16_t length; + uint8_t sessionId; + bool registerFrame; + uint16_t frameType; + uint16_t matchLen; + uint8_t matchData[1]; +} tSirRegisterMgmtFrame, *tpSirRegisterMgmtFrame; + +/* / Generic type for sending a response message */ +/* / with result code to host software */ +typedef struct sSirSmeRsp { + uint16_t messageType; /* eWNI_SME_*_RSP */ + uint16_t length; + uint8_t sessionId; /* To support BT-AMP */ + uint16_t transactionId; /* To support BT-AMP */ + tSirResultCodes statusCode; +} tSirSmeRsp, *tpSirSmeRsp; + +/* / Definition for indicating all modules ready on STA */ +typedef struct sSirSmeReadyReq { + uint16_t messageType; /* eWNI_SME_SYS_READY_IND */ + uint16_t length; + uint16_t transactionId; + void *add_bssdescr_cb; + void *csr_roam_synch_cb; + void *pe_roam_synch_cb; + void *sme_msg_cb; +} tSirSmeReadyReq, *tpSirSmeReadyReq; + +/** + * struct sir_hw_mode - Format of set HW mode + * @hw_mode_index: Index of HW mode to be set + * @set_hw_mode_cb: HDD set HW mode callback + * @reason: Reason for HW mode change + * @session_id: Session id + */ +struct sir_hw_mode { + uint32_t hw_mode_index; + void *set_hw_mode_cb; + enum sir_conn_update_reason reason; + uint32_t session_id; +}; + +/** + * struct s_sir_set_hw_mode - Set HW mode request + * @messageType: Message type + * @length: Length of the message + * @set_hw: Params containing the HW mode index and callback + */ +struct s_sir_set_hw_mode { + uint16_t messageType; + uint16_t length; + struct sir_hw_mode set_hw; +}; + +/** + * struct sir_dual_mac_config - Dual MAC configuration + * @scan_config: Scan configuration + * @fw_mode_config: FW mode configuration + * @set_dual_mac_cb: Callback function to be executed on response to the command + */ +struct sir_dual_mac_config { + uint32_t scan_config; + uint32_t fw_mode_config; + void *set_dual_mac_cb; +}; + +/** + * struct sir_set_dual_mac_cfg - Set Dual mac config request + * @message_type: Message type + * @length: Length of the message + * @set_dual_mac: Params containing the dual mac config and callback + */ +struct sir_set_dual_mac_cfg { + uint16_t message_type; + uint16_t length; + struct sir_dual_mac_config set_dual_mac; +}; + +/** + * struct sir_antenna_mode_param - antenna mode param + * @num_tx_chains: Number of TX chains + * @num_rx_chains: Number of RX chains + * @reason: Reason for setting antenna mode + * @set_antenna_mode_resp: callback to set antenna mode command + */ +struct sir_antenna_mode_param { + uint32_t num_tx_chains; + uint32_t num_rx_chains; + void *set_antenna_mode_resp; +}; + +/** + * struct sir_set_antenna_mode - Set antenna mode request + * @message_type: Message type + * @length: Length of the message + * @set_antenna_mode: Params containing antenna mode params + */ +struct sir_set_antenna_mode { + uint16_t message_type; + uint16_t length; + struct sir_antenna_mode_param set_antenna_mode; +}; + +/** + * enum tSirBssType - Enum for BSS type used in scanning/joining etc. + * + * @eSIR_INFRASTRUCTURE_MODE: Infrastructure station + * @eSIR_INFRA_AP_MODE: softAP mode + * @eSIR_IBSS_MODE: IBSS mode + * @eSIR_AUTO_MODE: Auto role + * @eSIR_MONITOR_MODE: Monitor mode + * @eSIR_NDI_MODE: NAN datapath mode + */ +typedef enum eSirBssType { + eSIR_INFRASTRUCTURE_MODE, + eSIR_INFRA_AP_MODE, + eSIR_IBSS_MODE, + eSIR_AUTO_MODE, + eSIR_MONITOR_MODE, + eSIR_NDI_MODE, + eSIR_DONOT_USE_BSS_TYPE = SIR_MAX_ENUM_SIZE +} tSirBssType; + +/* / Power Capability info used in 11H */ +typedef struct sSirMacPowerCapInfo { + uint8_t minTxPower; + uint8_t maxTxPower; +} tSirMacPowerCapInfo, *tpSirMacPowerCapInfo; + +/* / Supported Channel info used in 11H */ +typedef struct sSirSupChnl { + uint8_t numChnl; + uint8_t channelList[SIR_MAX_SUPPORTED_CHANNEL_LIST]; +} tSirSupChnl, *tpSirSupChnl; + +typedef enum eSirNwType { + eSIR_11A_NW_TYPE, + eSIR_11B_NW_TYPE, + eSIR_11G_NW_TYPE, + eSIR_11N_NW_TYPE, + eSIR_11AC_NW_TYPE, + eSIR_DONOT_USE_NW_TYPE = SIR_MAX_ENUM_SIZE +} tSirNwType; + +/* / Definition for new iBss peer info */ +typedef struct sSirNewIbssPeerInfo { + struct qdf_mac_addr peerAddr; + uint16_t aid; +} tSirNewIbssPeerInfo, *tpSirNewIbssPeerInfo; + +/* HT configuration values */ +typedef struct sSirHtConfig { + /* Enable/Disable receiving LDPC coded packets */ + uint32_t ht_rx_ldpc:1; + /* Enable/Disable TX STBC */ + uint32_t ht_tx_stbc:1; + /* Enable/Disable RX STBC */ + uint32_t ht_rx_stbc:2; + /* Enable/Disable SGI */ + uint32_t ht_sgi20:1; + uint32_t ht_sgi40:1; + uint32_t unused:27; +} qdf_packed tSirHTConfig, *tpSirHTConfig; + +/** + * struct sir_vht_config - VHT capabilites + * @max_mpdu_len: MPDU length + * @supported_channel_widthset: channel width set + * @ldpc_coding: LDPC coding capability + * @shortgi80: short GI 80 support + * @shortgi160and80plus80: short Gi 160 & 80+80 support + * @tx_stbc; Tx STBC cap + * @tx_stbc: Rx STBC cap + * @su_beam_former: SU beam former cap + * @su_beam_formee: SU beam formee cap + * @csnof_beamformer_antSup: Antenna support for beamforming + * @num_soundingdim: Sound dimensions + * @mu_beam_former: MU beam former cap + * @mu_beam_formee: MU beam formee cap + * @vht_txops: TXOP power save + * @htc_vhtcap: HTC VHT capability + * @max_ampdu_lenexp: AMPDU length + * @vht_link_adapt: VHT link adapatation capable + * @rx_antpattern: Rx Antenna pattern + * @tx_antpattern: Tx Antenna pattern + */ +struct sir_vht_config { + uint32_t max_mpdu_len:2; + uint32_t supported_channel_widthset:2; + uint32_t ldpc_coding:1; + uint32_t shortgi80:1; + uint32_t shortgi160and80plus80:1; + uint32_t tx_stbc:1; + uint32_t rx_stbc:3; + uint32_t su_beam_former:1; + uint32_t su_beam_formee:1; + uint32_t csnof_beamformer_antSup:3; + uint32_t num_soundingdim:3; + uint32_t mu_beam_former:1; + uint32_t mu_beam_formee:1; + uint32_t vht_txops:1; + uint32_t htc_vhtcap:1; + uint32_t max_ampdu_lenexp:3; + uint32_t vht_link_adapt:2; + uint32_t rx_antpattern:1; + uint32_t tx_antpattern:1; + uint32_t unused:2; +}; + + +typedef struct sSirAddIeParams { + uint16_t probeRespDataLen; + uint8_t *probeRespData_buff; + uint16_t assocRespDataLen; + uint8_t *assocRespData_buff; + uint16_t probeRespBCNDataLen; + uint8_t *probeRespBCNData_buff; +} tSirAddIeParams, *tpSirAddIeParams; + +/* / Definition for kick starting BSS */ +/* / ---> MAC */ +/** + * Usage of ssId, numSSID & ssIdList: + * --------------------------------- + * 1. ssId.length of zero indicates that Broadcast/Suppress SSID + * feature is enabled. + * 2. If ssId.length is zero, MAC SW will advertise NULL SSID + * and interpret the SSID list from numSSID & ssIdList. + * 3. If ssId.length is non-zero, MAC SW will advertise the SSID + * specified in the ssId field and it is expected that + * application will set numSSID to one (only one SSID present + * in the list) and SSID in the list is same as ssId field. + * 4. Application will always set numSSID >= 1. + */ +/* ***** NOTE: Please make sure all codes are updated if inserting field into + * this structure..********** */ +typedef struct sSirSmeStartBssReq { + uint16_t messageType; /* eWNI_SME_START_BSS_REQ */ + uint16_t length; + uint8_t sessionId; /* Added for BT-AMP Support */ + uint16_t transactionId; /* Added for BT-AMP Support */ + struct qdf_mac_addr bssid; /* Added for BT-AMP Support */ + struct qdf_mac_addr self_macaddr; /* Added for BT-AMP Support */ + uint16_t beaconInterval; /* Added for BT-AMP Support */ + uint8_t dot11mode; +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH + uint8_t cc_switch_mode; +#endif + tSirBssType bssType; + tSirMacSSid ssId; + uint8_t channelId; + ePhyChanBondState cbMode; + uint8_t vht_channel_width; + uint8_t center_freq_seg0; + uint8_t center_freq_seg1; + uint8_t sec_ch_offset; + + uint8_t privacy; + uint8_t apUapsdEnable; + uint8_t ssidHidden; + bool fwdWPSPBCProbeReq; + bool protEnabled; + bool obssProtEnabled; + uint16_t ht_capab; + tAniAuthType authType; + uint32_t dtimPeriod; + uint8_t wps_state; + uint8_t isCoalesingInIBSSAllowed; /* Coalesing on/off knob */ + enum tQDF_ADAPTER_MODE bssPersona; + + uint8_t txLdpcIniFeatureEnabled; + + tSirRSNie rsnIE; /* RSN IE to be sent in */ + /* Beacon and Probe */ + /* Response frames */ + tSirNwType nwType; /* Indicates 11a/b/g */ + tSirMacRateSet operationalRateSet; /* Has 11a or 11b rates */ + tSirMacRateSet extendedRateSet; /* Has 11g rates */ + tSirHTConfig htConfig; + struct sir_vht_config vht_config; + +#ifdef WLAN_FEATURE_11W + bool pmfCapable; + bool pmfRequired; +#endif + + tSirAddIeParams addIeParams; + + bool obssEnabled; + uint8_t sap_dot11mc; + uint8_t beacon_tx_rate; + bool vendor_vht_sap; + +} tSirSmeStartBssReq, *tpSirSmeStartBssReq; + +#define GET_IE_LEN_IN_BSS(lenInBss) (lenInBss + sizeof(lenInBss) - \ + ((uintptr_t)OFFSET_OF(tSirBssDescription,\ + ieFields))) + +#define WSCIE_PROBE_RSP_LEN (317 + 2) + +typedef struct sSirBssDescription { + /* offset of the ieFields from bssId. */ + uint16_t length; + tSirMacAddr bssId; + unsigned long scansystimensec; + uint32_t timeStamp[2]; + uint16_t beaconInterval; + uint16_t capabilityInfo; + tSirNwType nwType; /* Indicates 11a/b/g */ + int8_t rssi; + int8_t rssi_raw; + int8_t sinr; + /* channelId what peer sent in beacon/probersp. */ + uint8_t channelId; + /* channelId on which we are parked at. */ + /* used only in scan case. */ + uint8_t channelIdSelf; + uint8_t sSirBssDescriptionRsvd[3]; + /* Based on system time, not a relative time. */ + uint64_t received_time; + uint32_t parentTSF; + uint32_t startTSF[2]; + uint8_t mdiePresent; + /* MDIE for 11r, picked from the beacons */ + uint8_t mdie[SIR_MDIE_SIZE]; + uint8_t QBSSLoad_present; + uint8_t qbss_chan_load; + uint16_t QBSSLoad_avail; + /* To achieve 8-byte alignment with ESE enabled */ + uint32_t reservedPadding5; + /* Please keep the structure 4 bytes aligned above the ieFields */ + + /* whether it is from a probe rsp */ + uint8_t fProbeRsp; + /* Actual channel the beacon/probe response was received on */ + uint8_t rx_channel; + tSirMacSeqCtl seq_ctrl; + uint32_t WscIeLen; + uint8_t WscIeProbeRsp[WSCIE_PROBE_RSP_LEN]; + uint8_t reservedPadding4; + uint32_t tsf_delta; + + uint8_t ht_caps_present; + uint8_t vht_caps_present; + uint8_t beacomforming_capable; + uint8_t chan_width; + uint32_t ieFields[1]; + +} tSirBssDescription, *tpSirBssDescription; + +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH +typedef struct sSirSmeHTProfile { + uint8_t dot11mode; + uint8_t htCapability; + uint8_t htSupportedChannelWidthSet; + uint8_t htRecommendedTxWidthSet; + ePhyChanBondState htSecondaryChannelOffset; + uint8_t vhtCapability; + uint8_t apCenterChan; + uint8_t apChanWidth; +} tSirSmeHTProfile; +#endif +/* / Definition for response message to previously */ +/* / issued start BSS request */ +/* / MAC ---> */ +typedef struct sSirSmeStartBssRsp { + uint16_t messageType; /* eWNI_SME_START_BSS_RSP */ + uint16_t length; + uint8_t sessionId; + uint16_t transactionId; /* transaction ID for cmd */ + tSirResultCodes statusCode; + tSirBssType bssType; /* Add new type for WDS mode */ + uint16_t beaconInterval; /* Beacon Interval for both type */ + uint32_t staId; /* Staion ID for Self */ +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH + tSirSmeHTProfile HTProfile; +#endif + tSirBssDescription bssDescription; /* Peer BSS description */ +} tSirSmeStartBssRsp, *tpSirSmeStartBssRsp; + +typedef struct sSirChannelList { + uint8_t numChannels; + uint8_t channelNumber[SIR_ESE_MAX_MEAS_IE_REQS]; +} tSirChannelList, *tpSirChannelList; + +typedef struct sSirDFSChannelList { + uint32_t timeStamp[SIR_MAX_24G_5G_CHANNEL_RANGE]; + +} tSirDFSChannelList, *tpSirDFSChannelList; + +/* / Two Background Scan mode */ +typedef enum eSirBackgroundScanMode { + eSIR_ROAMING_SCAN = 2, +} tSirBackgroundScanMode; + +/* / Two types of traffic check */ +typedef enum eSirLinkTrafficCheck { + eSIR_DONT_CHECK_LINK_TRAFFIC_BEFORE_SCAN = 0, + eSIR_CHECK_LINK_TRAFFIC_BEFORE_SCAN = 1, + eSIR_CHECK_ROAMING_SCAN = 2, +} tSirLinkTrafficCheck; + +#define SIR_BG_SCAN_RETURN_CACHED_RESULTS 0x0 +#define SIR_BG_SCAN_PURGE_RESUTLS 0x80 +#define SIR_BG_SCAN_RETURN_FRESH_RESULTS 0x01 +#define SIR_SCAN_MAX_NUM_SSID 0x0A +#define SIR_BG_SCAN_RETURN_LFR_CACHED_RESULTS 0x02 +#define SIR_BG_SCAN_PURGE_LFR_RESULTS 0x40 + +/* / Definition for scan request */ +typedef struct sSirSmeScanReq { + uint16_t messageType; /* eWNI_SME_SCAN_REQ */ + uint16_t length; + uint8_t sessionId; /* Session ID */ + uint16_t transactionId; /* Transaction ID for cmd */ + struct qdf_mac_addr bssId; + tSirMacSSid ssId[SIR_SCAN_MAX_NUM_SSID]; + struct qdf_mac_addr selfMacAddr; /* Added For BT-AMP Support */ + tSirBssType bssType; + uint8_t dot11mode; + tSirScanType scanType; + uint32_t scan_id; + /** + * minChannelTime. Not used if scanType is passive. + * 0x0 - Dont Use min channel timer. Only max channel timeout will used. + * 11k measurements set this to 0 to user only single duration for scan. + * - Timeout value used for min channel timeout. + */ + uint32_t minChannelTime; + /** + * maxChannelTime. + * 0x0 - Invalid. In case of active scan. + * In case of passive scan, MAX( maxChannelTime, + * WNI_CFG_PASSIVE_MAXIMUM_CHANNEL_TIME) is used. + */ + uint32_t maxChannelTime; + uint32_t scan_probe_repeat_time; + uint32_t scan_num_probes; + enum wmi_dwelltime_adaptive_mode scan_adaptive_dwell_mode; + /** + * returnAfterFirstMatch can take following values: + * 0x00 - Return SCAN_RSP message after complete channel scan + * 0x01 - Return SCAN_RSP message after collecting BSS description + * that matches scan criteria. + * 0xC0 - Return after collecting first 11d IE from 2.4 GHz & + * 5 GHz band channels + * 0x80 - Return after collecting first 11d IE from 5 GHz band + * channels + * 0x40 - Return after collecting first 11d IE from 2.4 GHz + * band channels + * + * Values of 0xC0, 0x80 & 0x40 are to be used by + * Roaming/application when 11d is enabled. + */ + /* in units of milliseconds, ignored when not connected */ + uint32_t restTime; + /*in units of milliseconds, ignored when not connected*/ + uint32_t min_rest_time; + /*in units of milliseconds, ignored when not connected*/ + uint32_t idle_time; + uint8_t returnAfterFirstMatch; + + /** + * returnUniqueResults can take following values: + * 0 - Collect & report all received BSS descriptions from same BSS. + * 1 - Collect & report unique BSS description from same BSS. + */ + uint8_t returnUniqueResults; + + /** + * returnFreshResults can take following values: + * 0x00 - Return background scan results. + * 0x80 - Return & purge background scan results + * 0x01 - Trigger fresh scan instead of returning background scan + * results. + * 0x81 - Trigger fresh scan instead of returning background scan + * results and purge background scan results. + */ + uint8_t returnFreshResults; + + /* backgroundScanMode can take following values: + * 0x0 - agressive scan + * 0x1 - normal scan where HAL will check for link traffic + * prior to proceeding with the scan + */ + tSirBackgroundScanMode backgroundScanMode; + + uint8_t hiddenSsid; + + /* Number of SSIDs to scan */ + uint8_t numSsid; + + /* channelList has to be the last member of this structure. Check + * tSirChannelList for the reason. This MUST be the last field of the + * structure + */ + + bool p2pSearch; + uint16_t uIEFieldLen; + uint16_t uIEFieldOffset; + + /* mac address randomization attributes */ + bool enable_scan_randomization; + uint8_t mac_addr[QDF_MAC_ADDR_SIZE]; + uint8_t mac_addr_mask[QDF_MAC_ADDR_SIZE]; + + /* channelList MUST be the last field of this structure */ + tSirChannelList channelList; + /*----------------------------- + tSirSmeScanReq.... + ----------------------------- + uIEFiledLen + ----------------------------- + uIEFiledOffset ----+ + ----------------------------- | + channelList.numChannels | + ----------------------------- | + ... variable size up to | + channelNumber[numChannels-1] | + This can be zero, if | + numChannel is zero. | + ----------------------------- <--+ + ... variable size uIEFiled + up to uIEFieldLen (can be 0) + -----------------------------*/ +} tSirSmeScanReq, *tpSirSmeScanReq; + +typedef struct sSirSmeScanAbortReq { + uint16_t type; + uint16_t msgLen; + uint8_t sessionId; + uint32_t scan_id; +} tSirSmeScanAbortReq, *tpSirSmeScanAbortReq; + +typedef struct sSirSmeScanChanReq { + uint16_t type; + uint16_t msgLen; + uint8_t sessionId; + uint16_t transcationId; +} tSirSmeGetScanChanReq, *tpSirSmeGetScanChanReq; + +#ifdef FEATURE_OEM_DATA_SUPPORT +struct oem_data_req { + uint32_t data_len; + uint8_t *data; +}; + +struct oem_data_rsp { + uint32_t rsp_len; + uint8_t *data; +}; +#endif /* FEATURE_OEM_DATA_SUPPORT */ + +#ifdef FEATURE_WLAN_ESE +typedef struct ese_wmm_tspec_ie { + uint16_t traffic_type:1; + uint16_t tsid:4; + uint16_t direction:2; + uint16_t access_policy:2; + uint16_t aggregation:1; + uint16_t psb:1; + uint16_t user_priority:3; + uint16_t tsinfo_ack_pol:2; + uint8_t tsinfo_rsvd:7; + uint8_t burst_size_defn:1; + uint16_t size:15; + uint16_t fixed:1; + uint16_t max_msdu_size; + uint32_t min_service_int; + uint32_t max_service_int; + uint32_t inactivity_int; + uint32_t suspension_int; + uint32_t service_start_time; + uint32_t min_data_rate; + uint32_t mean_data_rate; + uint32_t peak_data_rate; + uint32_t burst_size; + uint32_t delay_bound; + uint32_t min_phy_rate; + uint16_t surplus_bw_allowance; + uint16_t medium_time; +} qdf_packed ese_wmm_tspec_ie; + +typedef struct sTspecInfo { + uint8_t valid; + tSirMacTspecIE tspec; +} tTspecInfo; + +#define SIR_ESE_MAX_TSPEC_IES 4 +typedef struct sESETspecTspecInfo { + uint8_t numTspecs; + tTspecInfo tspec[SIR_ESE_MAX_TSPEC_IES]; +} tESETspecInfo; + +typedef struct sSirTsmIE { + uint8_t tsid; + uint8_t state; + uint16_t msmt_interval; +} tSirTsmIE, *tpSirTsmIE; +typedef struct sSirSmeTsmIEInd { + tSirTsmIE tsmIe; + uint8_t sessionId; +} tSirSmeTsmIEInd, *tpSirSmeTsmIEInd; +typedef struct sAniTrafStrmMetrics { + uint16_t UplinkPktQueueDly; + uint16_t UplinkPktQueueDlyHist[4]; + uint32_t UplinkPktTxDly; + uint16_t UplinkPktLoss; + uint16_t UplinkPktCount; + uint8_t RoamingCount; + uint16_t RoamingDly; +} tAniTrafStrmMetrics, *tpAniTrafStrmMetrics; + +typedef struct sAniGetTsmStatsReq { + /* Common for all types are requests */ + uint16_t msgType; /* message type is same as the request type */ + uint16_t msgLen; /* length of the entire request */ + uint8_t staId; + uint8_t tid; /* traffic id */ + struct qdf_mac_addr bssId; + void *tsmStatsCallback; + void *pDevContext; /* device context */ + void *p_cds_context; /* cds context */ +} tAniGetTsmStatsReq, *tpAniGetTsmStatsReq; + +typedef struct sAniGetTsmStatsRsp { + /* Common for all types are responses */ + uint16_t msgType; /* + * message type is same as + * the request type + */ + uint16_t msgLen; /* + * length of the entire request, + * includes the pStatsBuf length too + */ + uint8_t sessionId; + uint32_t rc; /* success/failure */ + uint32_t staId; /* + * Per STA stats request must + * contain valid + */ + tAniTrafStrmMetrics tsmMetrics; + void *tsmStatsReq; /* tsm stats request backup */ +} tAniGetTsmStatsRsp, *tpAniGetTsmStatsRsp; + +typedef struct sSirEseBcnReportBssInfo { + tBcnReportFields bcnReportFields; + uint8_t ieLen; + uint8_t *pBuf; +} tSirEseBcnReportBssInfo, *tpSirEseBcnReportBssInfo; + +typedef struct sSirEseBcnReportRsp { + uint16_t measurementToken; + uint8_t flag; /* Flag to report measurement done and more data */ + uint8_t numBss; + tSirEseBcnReportBssInfo bcnRepBssInfo[SIR_BCN_REPORT_MAX_BSS_DESC]; +} tSirEseBcnReportRsp, *tpSirEseBcnReportRsp; + +#define TSRS_11AG_RATE_6MBPS 0xC +#define TSRS_11B_RATE_5_5MBPS 0xB +typedef struct sSirMacESETSRSIE { + uint8_t tsid; + uint8_t rates[8]; +} tSirMacESETSRSIE; +typedef struct sSirMacESETSMIE { + uint8_t tsid; + uint8_t state; + uint16_t msmt_interval; +} tSirMacESETSMIE; +typedef struct sTSMStats { + uint8_t tid; + struct qdf_mac_addr bssid; + tTrafStrmMetrics tsmMetrics; +} tTSMStats, *tpTSMStats; +typedef struct sEseTSMContext { + uint8_t tid; + tSirMacESETSMIE tsmInfo; + tTrafStrmMetrics tsmMetrics; +} tEseTSMContext, *tpEseTSMContext; +typedef struct sEsePEContext { + tEseTSMContext tsm; +} tEsePEContext, *tpEsePEContext; + +typedef struct sSirPlmReq { + uint16_t diag_token; /* Dialog token */ + uint16_t meas_token; /* measurement token */ + uint16_t numBursts; /* total number of bursts */ + uint16_t burstInt; /* burst interval in seconds */ + uint16_t measDuration; /* in TU's,STA goes off-ch */ + /* no of times the STA should cycle through PLM ch list */ + uint8_t burstLen; + int8_t desiredTxPwr; /* desired tx power */ + struct qdf_mac_addr mac_addr; /* MC dest addr */ + /* no of channels */ + uint8_t plmNumCh; + /* channel numbers */ + uint8_t plmChList[WNI_CFG_VALID_CHANNEL_LIST_LEN]; + uint8_t sessionId; + bool enable; +} tSirPlmReq, *tpSirPlmReq; + +#endif /* FEATURE_WLAN_ESE */ + +/* / Definition for response message to previously issued scan request */ +typedef struct sSirSmeScanRsp { + uint16_t messageType; /* eWNI_SME_SCAN_RSP */ + uint16_t length; + uint8_t sessionId; + tSirResultCodes statusCode; + uint16_t transcationId; + uint32_t scan_id; +} tSirSmeScanRsp, *tpSirSmeScanRsp; + +/* / Definition for join request */ +/* / ---> MAC */ +/* / WARNING! If you add a field in JOIN REQ. */ +/* / Make sure to add it in REASSOC REQ */ +/* / The Serdes function is the same and its */ +/* / shared with REASSOC. So if we add a field */ +/* here and dont add it in REASSOC REQ. It will BREAK!!! REASSOC. */ +typedef struct sSirSmeJoinReq { + uint16_t messageType; /* eWNI_SME_JOIN_REQ */ + uint16_t length; + uint8_t sessionId; + uint16_t transactionId; + tSirMacSSid ssId; + tSirMacAddr selfMacAddr; /* self Mac address */ + tSirBssType bsstype; /* add new type for BT-AMP STA and AP Modules */ + uint8_t dot11mode; /* to support BT-AMP */ +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH + uint8_t cc_switch_mode; +#endif + enum tQDF_ADAPTER_MODE staPersona; /* Persona */ + bool wps_registration; + ePhyChanBondState cbMode; /* Pass CB mode value in Join. */ + + /*This contains the UAPSD Flag for all 4 AC + * B0: AC_VO UAPSD FLAG + * B1: AC_VI UAPSD FLAG + * B2: AC_BK UAPSD FLAG + * B3: AC_BE UASPD FLAG + */ + uint8_t uapsdPerAcBitmask; + + tSirMacRateSet operationalRateSet; /* Has 11a or 11b rates */ + tSirMacRateSet extendedRateSet; /* Has 11g rates */ + tSirRSNie rsnIE; /* RSN IE to be sent in */ + /* (Re) Association Request */ +#ifdef FEATURE_WLAN_ESE + /* CCMK IE to be included as handler for join and reassoc is */ + tSirCCKMie cckmIE; + /* the same. The join will never carry cckm, but will be set to */ + /* 0. */ +#endif + + tSirAddie addIEScan; /* Additional IE to be sent in */ + /* (unicast) Probe Request at the time of join */ + + tSirAddie addIEAssoc; /* Additional IE to be sent in */ + /* (Re) Association Request */ + + tAniEdType UCEncryptionType; + + tAniEdType MCEncryptionType; + +#ifdef WLAN_FEATURE_11W + tAniEdType MgmtEncryptionType; +#endif + + tAniBool is11Rconnection; +#ifdef FEATURE_WLAN_ESE + tAniBool isESEFeatureIniEnabled; + tAniBool isESEconnection; + tESETspecInfo eseTspecInfo; +#endif + + tAniBool isFastTransitionEnabled; + tAniBool isFastRoamIniFeatureEnabled; + + uint8_t txLdpcIniFeatureEnabled; + tSirHTConfig htConfig; + struct sir_vht_config vht_config; + uint8_t enableVhtpAid; + uint8_t enableVhtGid; + uint8_t enableAmpduPs; + uint8_t enableHtSmps; + uint8_t htSmps; + bool send_smps_action; + + uint8_t max_amsdu_num; + tAniBool isWMEenabled; + tAniBool isQosEnabled; + tAniBool isOSENConnection; + struct rrm_config_param rrm_config; + tAniBool spectrumMgtIndicator; + tSirMacPowerCapInfo powerCap; + tSirSupChnl supportedChannels; + bool enable_bcast_probe_rsp; + bool ignore_assoc_disallowed; + tSirBssDescription bssDescription; + /* + * WARNING: Pls make bssDescription as last variable in struct + * tSirSmeJoinReq as it has ieFields followed after this bss + * description. Adding a variable after this corrupts the ieFields + */ +} tSirSmeJoinReq, *tpSirSmeJoinReq; + +/* / Definition for reponse message to previously issued join request */ +/* / MAC ---> */ +typedef struct sSirSmeJoinRsp { + uint16_t messageType; /* eWNI_SME_JOIN_RSP */ + uint16_t length; + uint8_t sessionId; /* Session ID */ + uint16_t transactionId; /* Transaction ID for cmd */ + tSirResultCodes statusCode; + tAniAuthType authType; + uint32_t vht_channel_width; + /* It holds reasonCode when join fails due to deauth/disassoc frame. + * Otherwise it holds status code. + */ + uint16_t protStatusCode; + uint16_t aid; + uint32_t beaconLength; + uint32_t assocReqLength; + uint32_t assocRspLength; + uint32_t parsedRicRspLen; +#ifdef FEATURE_WLAN_ESE + uint32_t tspecIeLen; +#endif + uint32_t staId; /* Station ID for peer */ + + /* The DPU signatures will be sent eventually to TL to help it determine + * the association to which a packet belongs to + * Unicast DPU signature + */ + uint8_t ucastSig; + + /*Broadcast DPU signature */ + uint8_t bcastSig; + + /*Timing measurement capability */ + uint8_t timingMeasCap; + +#ifdef FEATURE_WLAN_TDLS + /* TDLS prohibited and TDLS channel switch prohibited are set as + * per ExtCap IE in received assoc/re-assoc response from AP + */ + bool tdls_prohibited; + bool tdls_chan_swit_prohibited; +#endif + uint8_t nss; + uint32_t max_rate_flags; + +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH + tSirSmeHTProfile HTProfile; +#endif + bool supported_nss_1x1; + tDot11fIEHTCaps ht_caps; + tDot11fIEVHTCaps vht_caps; + tDot11fIEHTInfo ht_operation; + tDot11fIEVHTOperation vht_operation; + tDot11fIEhs20vendor_ie hs20vendor_ie; + uint8_t frames[1]; +} tSirSmeJoinRsp, *tpSirSmeJoinRsp; + +/* / probereq from peer, when wsc is enabled */ +typedef struct sSirSmeProbereq { + uint16_t messageType; + uint16_t length; + uint8_t sessionId; + struct qdf_mac_addr peer_macaddr; + uint16_t devicePasswdId; +} tSirSmeProbeReq, *tpSirSmeProbeReq; + +typedef struct sSirSmeChanInfo { + uint8_t chan_id; + uint32_t mhz; + uint32_t band_center_freq1; + uint32_t band_center_freq2; + uint32_t info; + uint32_t reg_info_1; + uint32_t reg_info_2; + uint8_t nss; + uint32_t rate_flags; + uint8_t sec_ch_offset; + enum phy_ch_width ch_width; +} tSirSmeChanInfo, *tpSirSmeChanInfo; + +/* / Definition for Association indication from peer */ +/* / MAC ---> */ +typedef struct sSirSmeAssocInd { + uint16_t messageType; /* eWNI_SME_ASSOC_IND */ + uint16_t length; + uint8_t sessionId; + tSirMacAddr peerMacAddr; + uint16_t aid; + tSirMacAddr bssId; /* Self BSSID */ + uint16_t staId; /* Station ID for peer */ + uint8_t uniSig; /* DPU signature for unicast packets */ + uint8_t bcastSig; /* DPU signature for broadcast packets */ + tAniAuthType authType; + tAniSSID ssId; /* SSID used by STA to associate */ + tSirWAPIie wapiIE; /* WAPI IE received from peer */ + tSirRSNie rsnIE; /* RSN IE received from peer */ + /* Additional IE received from peer, which possibly include + * WSC IE and/or P2P IE + */ + tSirAddie addIE; + + /* powerCap & supportedChannels are present only when */ + /* spectrumMgtIndicator flag is set */ + tAniBool spectrumMgtIndicator; + tSirMacPowerCapInfo powerCap; + tSirSupChnl supportedChannels; + tAniBool wmmEnabledSta; /* if present - STA is WMM enabled */ + tAniBool reassocReq; + /* Required for indicating the frames to upper layer */ + uint32_t beaconLength; + uint8_t *beaconPtr; + uint32_t assocReqLength; + uint8_t *assocReqPtr; + + /* Timing measurement capability */ + uint8_t timingMeasCap; + tSirSmeChanInfo chan_info; +} tSirSmeAssocInd, *tpSirSmeAssocInd; + +/* / Definition for Association confirm */ +/* / ---> MAC */ +typedef struct sSirSmeAssocCnf { + uint16_t messageType; /* eWNI_SME_ASSOC_CNF */ + uint16_t length; + tSirResultCodes statusCode; + struct qdf_mac_addr bssid; /* Self BSSID */ + struct qdf_mac_addr peer_macaddr; + uint16_t aid; + struct qdf_mac_addr alternate_bssid; + uint8_t alternateChannelId; +} tSirSmeAssocCnf, *tpSirSmeAssocCnf; + +/* / Enum definition for Wireless medium status change codes */ +typedef enum eSirSmeStatusChangeCode { + eSIR_SME_DEAUTH_FROM_PEER, + eSIR_SME_DISASSOC_FROM_PEER, + eSIR_SME_LOST_LINK_WITH_PEER, + eSIR_SME_CHANNEL_SWITCH, + eSIR_SME_JOINED_NEW_BSS, + eSIR_SME_LEAVING_BSS, + eSIR_SME_IBSS_ACTIVE, + eSIR_SME_IBSS_INACTIVE, + eSIR_SME_IBSS_PEER_DEPARTED, + eSIR_SME_RADAR_DETECTED, + eSIR_SME_IBSS_NEW_PEER, + eSIR_SME_AP_CAPS_CHANGED, +} tSirSmeStatusChangeCode; + +typedef struct sSirSmeNewBssInfo { + struct qdf_mac_addr bssId; + uint8_t channelNumber; + uint8_t reserved; + tSirMacSSid ssId; +} tSirSmeNewBssInfo, *tpSirSmeNewBssInfo; + +typedef struct sSirSmeApNewCaps { + uint16_t capabilityInfo; + struct qdf_mac_addr bssId; + uint8_t channelId; + uint8_t reserved[3]; + tSirMacSSid ssId; +} tSirSmeApNewCaps, *tpSirSmeApNewCaps; + +/** + * Table below indicates what information is passed for each of + * the Wireless Media status change notifications: + * + * Status Change code Status change info + * ---------------------------------------------------------------------- + * eSIR_SME_DEAUTH_FROM_PEER Reason code received in DEAUTH frame + * eSIR_SME_DISASSOC_FROM_PEER Reason code received in DISASSOC frame + * eSIR_SME_LOST_LINK_WITH_PEER None + * eSIR_SME_CHANNEL_SWITCH New channel number + * eSIR_SME_JOINED_NEW_BSS BSSID, SSID and channel number + * eSIR_SME_LEAVING_BSS None + * eSIR_SME_IBSS_ACTIVE Indicates that another STA joined + * IBSS apart from this STA that + * started IBSS + * eSIR_SME_IBSS_INACTIVE Indicates that only this STA is left + * in IBSS + * eSIR_SME_RADAR_DETECTED Indicates that radar is detected + * eSIR_SME_IBSS_NEW_PEER Indicates that a new peer is detected + * eSIR_SME_AP_CAPS_CHANGED Indicates that capabilities of the AP + * that STA is currently associated with + * have changed. + */ + +/* / Definition for Wireless medium status change notification */ +typedef struct sSirSmeWmStatusChangeNtf { + uint16_t messageType; /* eWNI_SME_WM_STATUS_CHANGE_NTF */ + uint16_t length; + uint8_t sessionId; /* Session ID */ + tSirSmeStatusChangeCode statusChangeCode; + struct qdf_mac_addr bssid; /* Self BSSID */ + union { + uint16_t deAuthReasonCode; /* eSIR_SME_DEAUTH_FROM_PEER */ + /* eSIR_SME_DISASSOC_FROM_PEER */ + uint16_t disassocReasonCode; + /* none for eSIR_SME_LOST_LINK_WITH_PEER */ + uint8_t newChannelId; /* eSIR_SME_CHANNEL_SWITCH */ + tSirSmeNewBssInfo newBssInfo; /* eSIR_SME_JOINED_NEW_BSS */ + /* none for eSIR_SME_LEAVING_BSS */ + /* none for eSIR_SME_IBSS_ACTIVE */ + /* none for eSIR_SME_IBSS_INACTIVE */ + /* eSIR_SME_IBSS_NEW_PEER */ + tSirNewIbssPeerInfo newIbssPeerInfo; + tSirSmeApNewCaps apNewCaps; /* eSIR_SME_AP_CAPS_CHANGED */ + } statusChangeInfo; +} tSirSmeWmStatusChangeNtf, *tpSirSmeWmStatusChangeNtf; + +/* Definition for Disassociation request */ +typedef struct sSirSmeDisassocReq { + uint16_t messageType; /* eWNI_SME_DISASSOC_REQ */ + uint16_t length; + uint8_t sessionId; /* Session ID */ + uint16_t transactionId; /* Transaction ID for cmd */ + struct qdf_mac_addr bssid; /* Peer BSSID */ + struct qdf_mac_addr peer_macaddr; + uint16_t reasonCode; + /* This flag tells LIM whether to send the disassoc OTA or not */ + /* This will be set in while handing off from one AP to other */ + uint8_t doNotSendOverTheAir; + bool process_ho_fail; +} qdf_packed tSirSmeDisassocReq, *tpSirSmeDisassocReq; + +/* / Definition for Tkip countermeasures request */ +typedef struct sSirSmeTkipCntrMeasReq { + uint16_t messageType; /* eWNI_SME_DISASSOC_REQ */ + uint16_t length; + uint8_t sessionId; /* Session ID */ + uint16_t transactionId; /* Transaction ID for cmd */ + struct qdf_mac_addr bssId; /* Peer BSSID */ + bool bEnable; /* Start/stop countermeasures */ +} qdf_packed tSirSmeTkipCntrMeasReq, *tpSirSmeTkipCntrMeasReq; + +typedef struct sAni64BitCounters { + uint32_t Hi; + uint32_t Lo; +} tAni64BitCounters, *tpAni64BitCounters; + +typedef struct sAniSecurityStat { + tAni64BitCounters txBlks; + tAni64BitCounters rxBlks; + tAni64BitCounters formatErrorCnt; + tAni64BitCounters decryptErr; + tAni64BitCounters protExclCnt; + tAni64BitCounters unDecryptableCnt; + tAni64BitCounters decryptOkCnt; + +} tAniSecurityStat, *tpAniSecurityStat; + +typedef struct sAniTxRxStats { + tAni64BitCounters txFrames; + tAni64BitCounters rxFrames; + tAni64BitCounters nRcvBytes; + tAni64BitCounters nXmitBytes; + +} tAniTxRxStats, *tpAniTxRxStats; + +typedef struct sAniSecStats { + tAniSecurityStat aes; + tAni64BitCounters aesReplays; + tAniSecurityStat tkip; + tAni64BitCounters tkipReplays; + tAni64BitCounters tkipMicError; + + tAniSecurityStat wep; +#if defined(FEATURE_WLAN_WAPI) && !defined(LIBRA_WAPI_SUPPORT) + tAniSecurityStat wpi; + tAni64BitCounters wpiReplays; + tAni64BitCounters wpiMicError; +#endif +} tAniSecStats, *tpAniSecStats; + +#define SIR_MAX_RX_CHAINS 3 + +typedef struct sAniStaStatStruct { + /* following statistic elements till expandPktRxCntLo are not filled + * with valid data. These are kept as it is, since WSM is using this + * structure. These elements can be removed whenever WSM is updated. + * Phystats is used to hold phystats from BD. + */ + uint32_t sentAesBlksUcastHi; + uint32_t sentAesBlksUcastLo; + uint32_t recvAesBlksUcastHi; + uint32_t recvAesBlksUcastLo; + uint32_t aesFormatErrorUcastCnts; + uint32_t aesReplaysUcast; + uint32_t aesDecryptErrUcast; + uint32_t singleRetryPkts; + uint32_t failedTxPkts; + uint32_t ackTimeouts; + uint32_t multiRetryPkts; + uint32_t fragTxCntsHi; + uint32_t fragTxCntsLo; + uint32_t transmittedPktsHi; + uint32_t transmittedPktsLo; + uint32_t phyStatHi; /* These are used to fill in the phystats. */ + uint32_t phyStatLo; /* This is only for private use. */ + + uint32_t uplinkRssi; + uint32_t uplinkSinr; + uint32_t uplinkRate; + uint32_t downlinkRssi; + uint32_t downlinkSinr; + uint32_t downlinkRate; + uint32_t nRcvBytes; + uint32_t nXmitBytes; + + /* + * Following elements are valid and filled in correctly. They have + * valid values. + */ + + /* Unicast frames and bytes. */ + tAniTxRxStats ucStats; + + /* Broadcast frames and bytes. */ + tAniTxRxStats bcStats; + + /* Multicast frames and bytes. */ + tAniTxRxStats mcStats; + + uint32_t currentTxRate; + uint32_t currentRxRate; /* Rate in 100Kbps */ + + uint32_t maxTxRate; + uint32_t maxRxRate; + + int8_t rssi[SIR_MAX_RX_CHAINS]; + + tAniSecStats securityStats; + + uint8_t currentRxRateIdx; /* This the softmac rate Index. */ + uint8_t currentTxRateIdx; + +} tAniStaStatStruct, *tpAniStaStatStruct; + +typedef enum sPacketType { + ePACKET_TYPE_UNKNOWN, + ePACKET_TYPE_11A, + ePACKET_TYPE_11G, + ePACKET_TYPE_11B, + ePACKET_TYPE_11N +} tPacketType, *tpPacketType; + +/* / Definition for Disassociation response */ +typedef struct sSirSmeDisassocRsp { + uint16_t messageType; /* eWNI_SME_DISASSOC_RSP */ + uint16_t length; + uint8_t sessionId; /* Session ID */ + uint16_t transactionId; /* Transaction ID for cmd */ + tSirResultCodes statusCode; + struct qdf_mac_addr peer_macaddr; + tAniStaStatStruct perStaStats; /* STA stats */ + uint16_t staId; +} qdf_packed tSirSmeDisassocRsp, *tpSirSmeDisassocRsp; + +/* / Definition for Disassociation indication from peer */ +typedef struct sSirSmeDisassocInd { + uint16_t messageType; /* eWNI_SME_DISASSOC_IND */ + uint16_t length; + uint8_t sessionId; /* Session Identifier */ + uint16_t transactionId; /* Transaction Identifier with PE */ + tSirResultCodes statusCode; + struct qdf_mac_addr bssid; + struct qdf_mac_addr peer_macaddr; + tAniStaStatStruct perStaStats; /* STA stats */ + uint16_t staId; + uint32_t reasonCode; +} tSirSmeDisassocInd, *tpSirSmeDisassocInd; + +/* / Definition for Disassociation confirm */ +/* / MAC ---> */ +typedef struct sSirSmeDisassocCnf { + uint16_t messageType; /* eWNI_SME_DISASSOC_CNF */ + uint16_t length; + tSirResultCodes statusCode; + struct qdf_mac_addr bssid; + struct qdf_mac_addr peer_macaddr; +} tSirSmeDisassocCnf, *tpSirSmeDisassocCnf, + tSirSmeDeauthCnf, *tpSirSmeDeauthCnf; + +/** + * struct sir_sme_discon_done_ind - disconnect done indiaction + * @message_type: msg type + * @length: length of msg + * @session_id: session id of the indication + * @reason_code: reason for disconnect indication + * @peer_mac: peer mac + */ +struct sir_sme_discon_done_ind { + uint16_t message_type; + uint16_t length; + uint8_t session_id; + tSirResultCodes reason_code; + tSirMacAddr peer_mac; +}; + + +/* / Definition for Deauthetication request */ +typedef struct sSirSmeDeauthReq { + uint16_t messageType; /* eWNI_SME_DEAUTH_REQ */ + uint16_t length; + uint8_t sessionId; /* Session ID */ + uint16_t transactionId; /* Transaction ID for cmd */ + struct qdf_mac_addr bssid; /* AP BSSID */ + struct qdf_mac_addr peer_macaddr; + uint16_t reasonCode; +} tSirSmeDeauthReq, *tpSirSmeDeauthReq; + +/* / Definition for Deauthetication response */ +typedef struct sSirSmeDeauthRsp { + uint16_t messageType; /* eWNI_SME_DEAUTH_RSP */ + uint16_t length; + uint8_t sessionId; /* Session ID */ + uint16_t transactionId; /* Transaction ID for cmd */ + tSirResultCodes statusCode; + struct qdf_mac_addr peer_macaddr; +} tSirSmeDeauthRsp, *tpSirSmeDeauthRsp; + +/* / Definition for Deauthetication indication from peer */ +typedef struct sSirSmeDeauthInd { + uint16_t messageType; /* eWNI_SME_DEAUTH_IND */ + uint16_t length; + uint8_t sessionId; /* Added for BT-AMP */ + uint16_t transactionId; /* Added for BT-AMP */ + tSirResultCodes statusCode; + struct qdf_mac_addr bssid; /* AP BSSID */ + struct qdf_mac_addr peer_macaddr; + + uint16_t staId; + uint32_t reasonCode; + int8_t rssi; +} tSirSmeDeauthInd, *tpSirSmeDeauthInd; + +/* / Definition for stop BSS request message */ +typedef struct sSirSmeStopBssReq { + uint16_t messageType; /* eWNI_SME_STOP_BSS_REQ */ + uint16_t length; + uint8_t sessionId; /* Session ID */ + uint16_t transactionId; /* tranSaction ID for cmd */ + tSirResultCodes reasonCode; + struct qdf_mac_addr bssid; /* Self BSSID */ +} tSirSmeStopBssReq, *tpSirSmeStopBssReq; + +/* / Definition for stop BSS response message */ +typedef struct sSirSmeStopBssRsp { + uint16_t messageType; /* eWNI_SME_STOP_BSS_RSP */ + uint16_t length; + tSirResultCodes statusCode; + uint8_t sessionId; /* Session ID */ + uint16_t transactionId; /* Transaction ID for cmd */ +} tSirSmeStopBssRsp, *tpSirSmeStopBssRsp; + +/* / Definition for Channel Switch indication for station */ +/* / MAC ---> */ +typedef struct sSirSmeSwitchChannelInd { + uint16_t messageType; /* eWNI_SME_SWITCH_CHL_IND */ + uint16_t length; + uint8_t sessionId; + uint16_t newChannelId; + struct ch_params_s chan_params; + struct qdf_mac_addr bssid; /* BSSID */ +} tSirSmeSwitchChannelInd, *tpSirSmeSwitchChannelInd; + +/* / Definition for Neighbor BSS indication */ +/* / MAC ---> */ +/* / MAC reports this each time a new I/BSS is detected */ +typedef struct sSirSmeNeighborBssInd { + uint16_t messageType; /* eWNI_SME_NEIGHBOR_BSS_IND */ + uint16_t length; + uint8_t sessionId; + tSirBssDescription bssDescription[1]; +} tSirSmeNeighborBssInd, *tpSirSmeNeighborBssInd; + +/* / Definition for MIC failure indication */ +/* / MAC ---> */ +/* / MAC reports this each time a MIC failure occures on Rx TKIP packet */ +typedef struct sSirSmeMicFailureInd { + uint16_t messageType; /* eWNI_SME_MIC_FAILURE_IND */ + uint16_t length; + uint8_t sessionId; + struct qdf_mac_addr bssId; + tSirMicFailureInfo info; +} tSirSmeMicFailureInd, *tpSirSmeMicFailureInd; + +typedef struct sSirSmeMissedBeaconInd { + uint16_t messageType; /* eWNI_SME_MISSED_BEACON_IND */ + uint16_t length; + uint8_t bssIdx; +} tSirSmeMissedBeaconInd, *tpSirSmeMissedBeaconInd; + +/* / Definition for Set Context request */ +/* / ---> MAC */ +typedef struct sSirSmeSetContextReq { + uint16_t messageType; /* eWNI_SME_SET_CONTEXT_REQ */ + uint16_t length; + uint8_t sessionId; /* Session ID */ + uint16_t transactionId; /* Transaction ID for cmd */ + struct qdf_mac_addr peer_macaddr; + struct qdf_mac_addr bssid; /* BSSID */ + tSirKeyMaterial keyMaterial; +} tSirSmeSetContextReq, *tpSirSmeSetContextReq; + +/* / Definition for Set Context response */ +/* / MAC ---> */ +typedef struct sSirSmeSetContextRsp { + uint16_t messageType; /* eWNI_SME_SET_CONTEXT_RSP */ + uint16_t length; + uint8_t sessionId; /* Session ID */ + uint16_t transactionId; /* Transaction ID for cmd */ + tSirResultCodes statusCode; + struct qdf_mac_addr peer_macaddr; +} tSirSmeSetContextRsp, *tpSirSmeSetContextRsp; + +/* / Statistic definitions */ +/* ============================================================= */ +/* Per STA statistic structure; This same struct will be used for Aggregate */ +/* STA stats as well. */ + +/* Clear radio stats and clear per sta stats */ +typedef enum { + eANI_CLEAR_ALL_STATS, /* Clears all stats */ + eANI_CLEAR_RX_STATS, /* Clears RX stats of the radio interface */ + eANI_CLEAR_TX_STATS, /* Clears TX stats of the radio interface */ + eANI_CLEAR_RADIO_STATS, /* Clears all the radio stats */ + eANI_CLEAR_PER_STA_STATS, /* Clears Per STA stats */ + eANI_CLEAR_AGGR_PER_STA_STATS, /* Clears aggregate stats */ + + /* Used to distinguish between per sta to security stats. */ + /* Used only by AP, FW just returns the same param as it received. */ + eANI_LINK_STATS, /* Get Per STA stats */ + eANI_SECURITY_STATS, /* Get Per STA security stats */ + + eANI_CLEAR_STAT_TYPES_END +} tAniStatSubTypes; + +typedef struct sAniTxCtrs { + /* add the rate counters here */ + uint32_t tx1Mbps; + uint32_t tx2Mbps; + uint32_t tx5_5Mbps; + uint32_t tx6Mbps; + uint32_t tx9Mbps; + uint32_t tx11Mbps; + uint32_t tx12Mbps; + uint32_t tx18Mbps; + uint32_t tx24Mbps; + uint32_t tx36Mbps; + uint32_t tx48Mbps; + uint32_t tx54Mbps; + uint32_t tx72Mbps; + uint32_t tx96Mbps; + uint32_t tx108Mbps; + + /* tx path radio counts */ + uint32_t txFragHi; + uint32_t txFragLo; + uint32_t txFrameHi; + uint32_t txFrameLo; + uint32_t txMulticastFrameHi; + uint32_t txMulticastFrameLo; + uint32_t txFailedHi; + uint32_t txFailedLo; + uint32_t multipleRetryHi; + uint32_t multipleRetryLo; + uint32_t singleRetryHi; + uint32_t singleRetryLo; + uint32_t ackFailureHi; + uint32_t ackFailureLo; + uint32_t xmitBeacons; +} tAniTxCtrs, *tpAniTxCtrs; + +typedef struct sAniRxCtrs { + /* receive frame rate counters */ + uint32_t rx1Mbps; + uint32_t rx2Mbps; + uint32_t rx5_5Mbps; + uint32_t rx6Mbps; + uint32_t rx9Mbps; + uint32_t rx11Mbps; + uint32_t rx12Mbps; + uint32_t rx18Mbps; + uint32_t rx24Mbps; + uint32_t rx36Mbps; + uint32_t rx48Mbps; + uint32_t rx54Mbps; + uint32_t rx72Mbps; + uint32_t rx96Mbps; + uint32_t rx108Mbps; + + /* receive size counters; 'Lte' = Less than or equal to */ + uint32_t rxLte64; + uint32_t rxLte128Gt64; + uint32_t rxLte256Gt128; + uint32_t rxLte512Gt256; + uint32_t rxLte1kGt512; + uint32_t rxLte1518Gt1k; + uint32_t rxLte2kGt1518; + uint32_t rxLte4kGt2k; + + /* rx radio stats */ + uint32_t rxFrag; + uint32_t rxFrame; + uint32_t fcsError; + uint32_t rxMulticast; + uint32_t duplicate; + uint32_t rtsSuccess; + uint32_t rtsFailed; + uint32_t wepUndecryptables; + uint32_t drops; + uint32_t aesFormatErrorUcastCnts; + uint32_t aesReplaysUcast; + uint32_t aesDecryptErrUcast; +} tAniRxCtrs, *tpAniRxCtrs; + +/* *************************************************************** */ + +/*******************PE Statistics*************************/ + +/* + * tpAniGetPEStatsReq is tied to + * for SME ==> PE eWNI_SME_GET_STATISTICS_REQ msgId and + * for PE ==> HAL SIR_HAL_GET_STATISTICS_REQ msgId + */ +typedef struct sAniGetPEStatsReq { + /* Common for all types are requests */ + uint16_t msgType; /* message type is same as the request type */ + uint16_t msgLen; /* length of the entire request */ + uint32_t staId; /* Per STA stats request must contain valid */ + /* categories of stats requested. look at ePEStatsMask */ + uint32_t statsMask; + uint8_t sessionId; +} tAniGetPEStatsReq, *tpAniGetPEStatsReq; + +/* + * tpAniGetPEStatsRsp is tied to + * for PE ==> SME eWNI_SME_GET_STATISTICS_RSP msgId and + * for HAL ==> PE SIR_HAL_GET_STATISTICS_RSP msgId + */ +typedef struct sAniGetPEStatsRsp { + /* Common for all types are responses */ + uint16_t msgType; /* message type is same as the request type */ + /* length of the entire request, includes the pStatsBuf length too */ + uint16_t msgLen; + uint8_t sessionId; + uint32_t rc; /* success/failure */ + uint32_t staId; /* Per STA stats request must contain valid */ + /* categories of stats requested. look at ePEStatsMask */ + uint32_t statsMask; + /* void *pStatsBuf; */ + /* + * The Stats buffer starts here and can be an aggregate of more than one + * statistics structure depending on statsMask. The void pointer + * "pStatsBuf" is commented out intentionally and the src code that uses + * this structure should take that into account. + */ +} tAniGetPEStatsRsp, *tpAniGetPEStatsRsp; + +typedef struct sAniGetRssiReq { + /* Common for all types are requests */ + uint16_t msgType; /* message type is same as the request type */ + uint16_t msgLen; /* length of the entire request */ + uint8_t sessionId; + uint8_t staId; + int8_t lastRSSI; /* in case of error, return last RSSI */ + void *rssiCallback; + void *pDevContext; /* device context */ + void *p_cds_context; /* cds context */ + +} tAniGetRssiReq, *tpAniGetRssiReq; + +typedef struct sAniGetSnrReq { + /* Common for all types are requests */ + uint16_t msgType; /* message type is same as the request type */ + uint16_t msgLen; /* length of the entire request */ + uint8_t sessionId; + uint8_t staId; + void *snrCallback; + void *pDevContext; /* device context */ + int8_t snr; +} tAniGetSnrReq, *tpAniGetSnrReq; + +/* Change country code request MSG structure */ +typedef struct sAniChangeCountryCodeReq { + /* Common for all types are requests */ + uint16_t msgType; /* message type is same as the request type */ + uint16_t msgLen; /* length of the entire request */ + uint8_t countryCode[WNI_CFG_COUNTRY_CODE_LEN]; /* 3 char country code */ + tAniBool countryFromUserSpace; + tAniBool sendRegHint; /* true if we want to send hint to NL80211 */ + void *changeCCCallback; + void *pDevContext; /* device context */ + void *p_cds_context; /* cds context */ + +} tAniChangeCountryCodeReq, *tpAniChangeCountryCodeReq; + +/** + * struct ani_scan_req - Scan request + * @msg_type: Message type + * @msg_len: Message Length + * @session_id: SME session Id + * @scan_param: scan request parameter + * @callback: call back function for scan result + * @ctx: Global context + * + * Scan request message structure + */ +struct ani_scan_req { + /* message type is same as the request type */ + uint16_t msg_type; + /* length of the entire request */ + uint16_t msg_len; + uint16_t session_id; + void *scan_param; + void *callback; + void *ctx; +}; + +/** + * struct ani_roc_req - Remain on channel request + * @msg_type: Message type + * @msg_len: Message Length + * @session_id: SME session Id + * @channel: channel number + * @callback: call back function for scan result + * @duration: Roc duration + * @is_p2pprobe_allowed : flag for p2p probe request + * @ctx: Global context + * @scan_id: Scan Identifier + * + * Remain on channel request message structure + */ +struct ani_roc_req { + /* message type is same as the request type */ + uint16_t msg_type; + /* length of the entire request */ + uint16_t msg_len; + uint16_t session_id; + uint8_t channel; + uint32_t duration; + uint8_t is_p2pprobe_allowed; + void *callback; + void *ctx; + uint32_t scan_id; +}; + +/* generic country code change request MSG structure */ +typedef struct sAniGenericChangeCountryCodeReq { + uint16_t msgType; /* message type is same as the request type */ + uint16_t msgLen; /* length of the entire request */ + uint8_t countryCode[WNI_CFG_COUNTRY_CODE_LEN]; /* 3 char country code */ +} tAniGenericChangeCountryCodeReq, *tpAniGenericChangeCountryCodeReq; + +/** + * struct sAniDHCPStopInd - DHCP Stop indication message + * @msgType: message type is same as the request type + * @msgLen: length of the entire request + * @device_mode: Mode of the device(ex:STA, AP) + * @adapterMacAddr: MAC address of the adapter + * @peerMacAddr: MAC address of the connected peer + */ +typedef struct sAniDHCPStopInd { + uint16_t msgType; + uint16_t msgLen; + uint8_t device_mode; + struct qdf_mac_addr adapterMacAddr; + struct qdf_mac_addr peerMacAddr; +} tAniDHCPInd, *tpAniDHCPInd; + +typedef struct sAniTXFailMonitorInd { + uint16_t msgType; /* message type is same as the request type */ + uint16_t msgLen; /* length of the entire request */ + uint8_t tx_fail_count; + void *txFailIndCallback; +} tAniTXFailMonitorInd, *tpAniTXFailMonitorInd; + +typedef enum eTxRateInfo { + eHAL_TX_RATE_LEGACY = 0x1, /* Legacy rates */ + eHAL_TX_RATE_HT20 = 0x2, /* HT20 rates */ + eHAL_TX_RATE_HT40 = 0x4, /* HT40 rates */ + eHAL_TX_RATE_SGI = 0x8, /* Rate with Short guard interval */ + eHAL_TX_RATE_LGI = 0x10, /* Rate with Long guard interval */ + eHAL_TX_RATE_VHT20 = 0x20, /* VHT 20 rates */ + eHAL_TX_RATE_VHT40 = 0x40, /* VHT 40 rates */ + eHAL_TX_RATE_VHT80 = 0x80 /* VHT 80 rates */ +} tTxrateinfoflags; + +/**********************PE Statistics end*************************/ + +typedef struct sSirP2PNoaStart { + uint32_t status; + uint32_t bssIdx; +} tSirP2PNoaStart, *tpSirP2PNoaStart; + +typedef struct sSirTdlsInd { + uint16_t status; + uint16_t assocId; + uint16_t staIdx; + uint16_t reasonCode; +} tSirTdlsInd, *tpSirTdlsInd; + +typedef struct sSirP2PNoaAttr { +#ifdef ANI_BIG_BYTE_ENDIAN + uint32_t index:8; + uint32_t oppPsFlag:1; + uint32_t ctWin:7; + uint32_t rsvd1:16; +#else + uint32_t rsvd1:16; + uint32_t ctWin:7; + uint32_t oppPsFlag:1; + uint32_t index:8; +#endif + +#ifdef ANI_BIG_BYTE_ENDIAN + uint32_t uNoa1IntervalCnt:8; + uint32_t rsvd2:24; +#else + uint32_t rsvd2:24; + uint32_t uNoa1IntervalCnt:8; +#endif + uint32_t uNoa1Duration; + uint32_t uNoa1Interval; + uint32_t uNoa1StartTime; + +#ifdef ANI_BIG_BYTE_ENDIAN + uint32_t uNoa2IntervalCnt:8; + uint32_t rsvd3:24; +#else + uint32_t rsvd3:24; + uint32_t uNoa2IntervalCnt:8; +#endif + uint32_t uNoa2Duration; + uint32_t uNoa2Interval; + uint32_t uNoa2StartTime; +} tSirP2PNoaAttr, *tpSirP2PNoaAttr; + +typedef struct sSirTclasInfo { + tSirMacTclasIE tclas; + uint8_t version; /* applies only for classifier type ip */ + union { + tSirMacTclasParamEthernet eth; + tSirMacTclasParamIPv4 ipv4; + tSirMacTclasParamIPv6 ipv6; + tSirMacTclasParam8021dq t8021dq; + } qdf_packed tclasParams; +} qdf_packed tSirTclasInfo; + +typedef struct sSirAddtsReqInfo { + uint8_t dialogToken; + tSirMacTspecIE tspec; + + uint8_t numTclas; /* number of Tclas elements */ + tSirTclasInfo tclasInfo[SIR_MAC_TCLASIE_MAXNUM]; + uint8_t tclasProc; +#if defined(FEATURE_WLAN_ESE) + tSirMacESETSRSIE tsrsIE; + uint8_t tsrsPresent:1; +#endif + uint8_t wmeTspecPresent:1; + uint8_t wsmTspecPresent:1; + uint8_t lleTspecPresent:1; + uint8_t tclasProcPresent:1; +} tSirAddtsReqInfo, *tpSirAddtsReqInfo; + +typedef struct sSirAddtsRspInfo { + uint8_t dialogToken; + tSirMacStatusCodes status; + tSirMacTsDelayIE delay; + + tSirMacTspecIE tspec; + uint8_t numTclas; /* number of Tclas elements */ + tSirTclasInfo tclasInfo[SIR_MAC_TCLASIE_MAXNUM]; + uint8_t tclasProc; + tSirMacScheduleIE schedule; +#ifdef FEATURE_WLAN_ESE + tSirMacESETSMIE tsmIE; + uint8_t tsmPresent:1; +#endif + uint8_t wmeTspecPresent:1; + uint8_t wsmTspecPresent:1; + uint8_t lleTspecPresent:1; + uint8_t tclasProcPresent:1; + uint8_t schedulePresent:1; +} tSirAddtsRspInfo, *tpSirAddtsRspInfo; + +typedef struct sSirDeltsReqInfo { + tSirMacTSInfo tsinfo; + tSirMacTspecIE tspec; + uint8_t wmeTspecPresent:1; + uint8_t wsmTspecPresent:1; + uint8_t lleTspecPresent:1; +} tSirDeltsReqInfo, *tpSirDeltsReqInfo; + +/* / Add a tspec as defined */ +typedef struct sSirAddtsReq { + uint16_t messageType; /* eWNI_SME_ADDTS_REQ */ + uint16_t length; + uint8_t sessionId; /* Session ID */ + uint16_t transactionId; + struct qdf_mac_addr bssid; /* BSSID */ + uint32_t timeout; /* in ms */ + uint8_t rspReqd; + tSirAddtsReqInfo req; +} tSirAddtsReq, *tpSirAddtsReq; + +typedef struct sSirAddtsRsp { + uint16_t messageType; /* eWNI_SME_ADDTS_RSP */ + uint16_t length; + uint8_t sessionId; /* sme sessionId Added for BT-AMP support */ + uint16_t transactionId; /* sme transaction Id - for BT-AMP Support */ + uint32_t rc; /* return code */ + tSirAddtsRspInfo rsp; +} tSirAddtsRsp, *tpSirAddtsRsp; + +typedef struct sSirDeltsReq { + uint16_t messageType; /* eWNI_SME_DELTS_REQ */ + uint16_t length; + uint8_t sessionId; /* Session ID */ + uint16_t transactionId; + struct qdf_mac_addr bssid; /* BSSID */ + uint16_t aid; /* use 0 if macAddr is being specified */ + struct qdf_mac_addr macaddr; /* only on AP to specify the STA */ + uint8_t rspReqd; + tSirDeltsReqInfo req; +} tSirDeltsReq, *tpSirDeltsReq; + +typedef struct sSirDeltsRsp { + uint16_t messageType; /* eWNI_SME_DELTS_RSP */ + uint16_t length; + uint8_t sessionId; /* sme sessionId Added for BT-AMP support */ + uint16_t transactionId; /* sme transaction Id - for BT-AMP Support */ + uint32_t rc; + uint16_t aid; /* use 0 if macAddr is being specified */ + struct qdf_mac_addr macaddr; /* only on AP to specify the STA */ + tSirDeltsReqInfo rsp; +} tSirDeltsRsp, *tpSirDeltsRsp; + +#define SIR_QOS_NUM_AC_MAX 4 + +typedef struct sSirAggrQosReqInfo { + uint16_t tspecIdx; + tSirAddtsReqInfo aggrAddTsInfo[SIR_QOS_NUM_AC_MAX]; +} tSirAggrQosReqInfo, *tpSirAggrQosReqInfo; + +typedef struct sSirAggrQosReq { + uint16_t messageType; /* eWNI_SME_ADDTS_REQ */ + uint16_t length; + uint8_t sessionId; /* Session ID */ + uint16_t transactionId; + struct qdf_mac_addr bssid; /* BSSID */ + uint32_t timeout; /* in ms */ + uint8_t rspReqd; + tSirAggrQosReqInfo aggrInfo; +} tSirAggrQosReq, *tpSirAggrQosReq; + +typedef struct sSirAggrQosRspInfo { + uint16_t tspecIdx; + tSirAddtsRspInfo aggrRsp[SIR_QOS_NUM_AC_MAX]; +} tSirAggrQosRspInfo, *tpSirAggrQosRspInfo; + +typedef struct sSirAggrQosRsp { + uint16_t messageType; + uint16_t length; + uint8_t sessionId; + tSirAggrQosRspInfo aggrInfo; +} tSirAggrQosRsp, *tpSirAggrQosRsp; + + +typedef struct sSirQosMapSet { + uint8_t present; + uint8_t num_dscp_exceptions; + uint8_t dscp_exceptions[21][2]; + uint8_t dscp_range[8][2]; +} tSirQosMapSet, *tpSirQosMapSet; + +typedef struct sSmeIbssPeerInd { + uint16_t mesgType; + uint16_t mesgLen; + uint8_t sessionId; + + struct qdf_mac_addr peer_addr; + uint16_t staId; + + /* + * The DPU signatures will be sent eventually to TL to help it determine + * the association to which a packet belongs to + */ + /* Unicast DPU signature */ + uint8_t ucastSig; + + /*Broadcast DPU signature */ + uint8_t bcastSig; + + /* Beacon will be appended for new Peer indication. */ +} tSmeIbssPeerInd, *tpSmeIbssPeerInd; + +typedef struct sSirIbssPeerInactivityInd { + uint8_t bssIdx; + uint8_t staIdx; + struct qdf_mac_addr peer_addr; +} tSirIbssPeerInactivityInd, *tpSirIbssPeerInactivityInd; + +typedef struct sLimScanChn { + uint16_t numTimeScan; /* how many time this channel is scan */ + uint8_t channelId; +} tLimScanChn; + +typedef struct sSmeGetScanChnRsp { + /* Message Type */ + uint16_t mesgType; + /* Message Length */ + uint16_t mesgLen; + uint8_t sessionId; + uint8_t numChn; + tLimScanChn scanChn[1]; +} tSmeGetScanChnRsp, *tpSmeGetScanChnRsp; + +typedef struct sLimScanChnInfo { + uint8_t numChnInfo; /* number of channels in scanChn */ + tLimScanChn scanChn[SIR_MAX_SUPPORTED_CHANNEL_LIST]; +} tLimScanChnInfo; + +typedef struct sSirSmeGetAssocSTAsReq { + uint16_t messageType; /* eWNI_SME_GET_ASSOC_STAS_REQ */ + uint16_t length; + struct qdf_mac_addr bssid; /* BSSID */ + uint16_t modId; + void *pUsrContext; + void *pSapEventCallback; + /* Pointer to allocated mem passed in wlansap_get_assoc_stations API */ + void *pAssocStasArray; +} tSirSmeGetAssocSTAsReq, *tpSirSmeGetAssocSTAsReq; + +typedef struct sSmeMaxAssocInd { + uint16_t mesgType; /* eWNI_SME_MAX_ASSOC_EXCEEDED */ + uint16_t mesgLen; + uint8_t sessionId; + /* the new peer that got rejected max assoc limit reached */ + struct qdf_mac_addr peer_mac; +} tSmeMaxAssocInd, *tpSmeMaxAssocInd; + +typedef struct sSmeCsaOffloadInd { + uint16_t mesgType; /* eWNI_SME_CSA_OFFLOAD_EVENT */ + uint16_t mesgLen; + struct qdf_mac_addr bssid; /* BSSID */ +} tSmeCsaOffloadInd, *tpSmeCsaOffloadInd; + +/* WOW related structures */ +#define SIR_WOWL_BCAST_PATTERN_MAX_SIZE 146 + +/** + * struct wow_add_pattern - wow pattern add structure + * @pattern_id: pattern id + * @pattern_byte_offset: pattern byte offset from beginning of the 802.11 + * packet to start of the wake-up pattern + * @pattern_size: pattern size + * @pattern: pattern byte stream + * @pattern_mask_size: pattern mask size + * @pattern_mask: pattern mask + * @session_id: session id + */ +struct wow_add_pattern { + uint8_t pattern_id; + uint8_t pattern_byte_offset; + uint8_t pattern_size; + uint8_t pattern[SIR_WOWL_BCAST_PATTERN_MAX_SIZE]; + uint8_t pattern_mask_size; + uint8_t pattern_mask[SIR_WOWL_BCAST_PATTERN_MAX_SIZE]; + uint8_t session_id; +}; + +/** + * struct wow_delete_patern - wow pattern delete structure + * @pattern_id: pattern id of wake up pattern to be deleted + * @session_id: session id + */ +struct wow_delete_pattern { + uint8_t pattern_id; + uint8_t session_id; +}; + +/* SME->PE: Enter WOWLAN parameters */ +typedef struct sSirSmeWowlEnterParams { + uint8_t sessionId; + + /* Enables/disables magic packet filtering */ + uint8_t ucMagicPktEnable; + + /* Magic pattern */ + struct qdf_mac_addr magic_ptrn; + + /* Enables/disables packet pattern filtering */ + uint8_t ucPatternFilteringEnable; + +#ifdef WLAN_WAKEUP_EVENTS + /* + * This configuration directs the WoW packet filtering to look at EAP-ID + * requests embedded in EAPOL frames and use this as a wake source. + */ + uint8_t ucWoWEAPIDRequestEnable; + + /* + * This configuration directs the WoW packet filtering to look for + * EAPOL-4WAY requests and use this as a wake source. + */ + uint8_t ucWoWEAPOL4WayEnable; + + /* + * This configuration allows a host wakeup on an network scan + * offload match. + */ + uint8_t ucWowNetScanOffloadMatch; + + /* This configuration allows a host wakeup on any GTK rekeying error. + */ + uint8_t ucWowGTKRekeyError; + + /* This configuration allows a host wakeup on BSS connection loss. + */ + uint8_t ucWoWBSSConnLoss; +#endif /* WLAN_WAKEUP_EVENTS */ + + struct qdf_mac_addr bssid; +} tSirSmeWowlEnterParams, *tpSirSmeWowlEnterParams; + +/* PE<->HAL: Enter WOWLAN parameters */ +typedef struct sSirHalWowlEnterParams { + uint8_t sessionId; + + /* Enables/disables magic packet filtering */ + uint8_t ucMagicPktEnable; + + /* Magic pattern */ + struct qdf_mac_addr magic_ptrn; + + /* Enables/disables packet pattern filtering in firmware. + Enabling this flag enables broadcast pattern matching + in Firmware. If unicast pattern matching is also desired, + ucUcastPatternFilteringEnable flag must be set tot true + as well + */ + uint8_t ucPatternFilteringEnable; + + /* Enables/disables unicast packet pattern filtering. + This flag specifies whether we want to do pattern match + on unicast packets as well and not just broadcast packets. + This flag has no effect if the ucPatternFilteringEnable + (main controlling flag) is set to false + */ + uint8_t ucUcastPatternFilteringEnable; + + /* This configuration is valid only when magicPktEnable=1. + * It requests hardware to wake up when it receives the + * Channel Switch Action Frame. + */ + uint8_t ucWowChnlSwitchRcv; + + /* This configuration is valid only when magicPktEnable=1. + * It requests hardware to wake up when it receives the + * Deauthentication Frame. + */ + uint8_t ucWowDeauthRcv; + + /* This configuration is valid only when magicPktEnable=1. + * It requests hardware to wake up when it receives the + * Disassociation Frame. + */ + uint8_t ucWowDisassocRcv; + + /* This configuration is valid only when magicPktEnable=1. + * It requests hardware to wake up when it has missed + * consecutive beacons. This is a hardware register + * configuration (NOT a firmware configuration). + */ + uint8_t ucWowMaxMissedBeacons; + + /* This configuration is valid only when magicPktEnable=1. + * This is a timeout value in units of microsec. It requests + * hardware to unconditionally wake up after it has stayed + * in WoWLAN mode for some time. Set 0 to disable this feature. + */ + uint8_t ucWowMaxSleepUsec; + +#ifdef WLAN_WAKEUP_EVENTS + /* This config directs the WoW pkt filtering to look for EAP-ID + * requests embedded in EAPOL frames and use this as a wake source. + */ + uint8_t ucWoWEAPIDRequestEnable; + + /* This config directs the WoW pkt filtering to look for EAPOL-4WAY + * requests and use this as a wake source. + */ + uint8_t ucWoWEAPOL4WayEnable; + + /* This config allows a host wakeup on an network scan offload match. + */ + uint8_t ucWowNetScanOffloadMatch; + + /* This configuration allows a host wakeup on any GTK rekeying error. + */ + uint8_t ucWowGTKRekeyError; + + /* This configuration allows a host wakeup on BSS connection loss. + */ + uint8_t ucWoWBSSConnLoss; +#endif /* WLAN_WAKEUP_EVENTS */ + + /* Status code to be filled by HAL when it sends + * SIR_HAL_WOWL_ENTER_RSP to PE. + */ + QDF_STATUS status; + + /*BSSID to find the current session + */ + uint8_t bssIdx; +} tSirHalWowlEnterParams, *tpSirHalWowlEnterParams; + +/* SME->PE: Exit WOWLAN parameters */ +typedef struct sSirSmeWowlExitParams { + uint8_t sessionId; + +} tSirSmeWowlExitParams, *tpSirSmeWowlExitParams; + +/* PE<->HAL: Exit WOWLAN parameters */ +typedef struct sSirHalWowlExitParams { + uint8_t sessionId; + + /* Status code to be filled by HAL when it sends + * SIR_HAL_WOWL_EXIT_RSP to PE. + */ + QDF_STATUS status; + + /*BSSIDX to find the current session + */ + uint8_t bssIdx; +} tSirHalWowlExitParams, *tpSirHalWowlExitParams; + +#define SIR_MAX_NAME_SIZE 64 +#define SIR_MAX_TEXT_SIZE 32 + +typedef struct sSirName { + uint8_t num_name; + uint8_t name[SIR_MAX_NAME_SIZE]; +} tSirName; + +typedef struct sSirText { + uint8_t num_text; + uint8_t text[SIR_MAX_TEXT_SIZE]; +} tSirText; + +#define SIR_WPS_PROBRSP_VER_PRESENT 0x00000001 +#define SIR_WPS_PROBRSP_STATE_PRESENT 0x00000002 +#define SIR_WPS_PROBRSP_APSETUPLOCK_PRESENT 0x00000004 +#define SIR_WPS_PROBRSP_SELECTEDREGISTRA_PRESENT 0x00000008 +#define SIR_WPS_PROBRSP_DEVICEPASSWORDID_PRESENT 0x00000010 +#define SIR_WPS_PROBRSP_SELECTEDREGISTRACFGMETHOD_PRESENT 0x00000020 +#define SIR_WPS_PROBRSP_RESPONSETYPE_PRESENT 0x00000040 +#define SIR_WPS_PROBRSP_UUIDE_PRESENT 0x00000080 +#define SIR_WPS_PROBRSP_MANUFACTURE_PRESENT 0x00000100 +#define SIR_WPS_PROBRSP_MODELNAME_PRESENT 0x00000200 +#define SIR_WPS_PROBRSP_MODELNUMBER_PRESENT 0x00000400 +#define SIR_WPS_PROBRSP_SERIALNUMBER_PRESENT 0x00000800 +#define SIR_WPS_PROBRSP_PRIMARYDEVICETYPE_PRESENT 0x00001000 +#define SIR_WPS_PROBRSP_DEVICENAME_PRESENT 0x00002000 +#define SIR_WPS_PROBRSP_CONFIGMETHODS_PRESENT 0x00004000 +#define SIR_WPS_PROBRSP_RF_BANDS_PRESENT 0x00008000 + +typedef struct sSirWPSProbeRspIE { + uint32_t FieldPresent; + uint32_t Version; /* Version. 0x10 = version 1.0, 0x11 = etc. */ + uint32_t wpsState; /* 1 = unconfigured, 2 = configured. */ + bool APSetupLocked; /* Must be included if value is true */ + /* + * BOOL: indicates if the user has recently activated a Registrar to + * add an Enrollee. + */ + bool SelectedRegistra; + uint16_t DevicePasswordID; /* Device Password ID */ + /* Selected Registrar config method */ + uint16_t SelectedRegistraCfgMethod; + uint8_t ResponseType; /* Response type */ + uint8_t UUID_E[16]; /* Unique identifier of the AP. */ + tSirName Manufacture; + tSirText ModelName; + tSirText ModelNumber; + tSirText SerialNumber; + /* Device Category ID: 1Computer, 2Input Device, ... */ + uint32_t PrimaryDeviceCategory; + /* Vendor specific OUI for Device Sub Category */ + uint8_t PrimaryDeviceOUI[4]; + /* + Device Sub Category ID: 1-PC, 2-Server if Device Category ID + * is computer + */ + uint32_t DeviceSubCategory; + tSirText DeviceName; + uint16_t ConfigMethod; /* Configuaration method */ + uint8_t RFBand; /* RF bands available on the AP */ +} tSirWPSProbeRspIE; + +#define SIR_WPS_BEACON_VER_PRESENT 0x00000001 +#define SIR_WPS_BEACON_STATE_PRESENT 0x00000002 +#define SIR_WPS_BEACON_APSETUPLOCK_PRESENT 0x00000004 +#define SIR_WPS_BEACON_SELECTEDREGISTRA_PRESENT 0x00000008 +#define SIR_WPS_BEACON_DEVICEPASSWORDID_PRESENT 0x00000010 +#define SIR_WPS_BEACON_SELECTEDREGISTRACFGMETHOD_PRESENT 0x00000020 +#define SIR_WPS_BEACON_UUIDE_PRESENT 0x00000080 +#define SIR_WPS_BEACON_RF_BANDS_PRESENT 0x00000100 +#define SIR_WPS_UUID_LEN 16 + +typedef struct sSirWPSBeaconIE { + uint32_t FieldPresent; + uint32_t Version; /* Version. 0x10 = version 1.0, 0x11 = etc. */ + uint32_t wpsState; /* 1 = unconfigured, 2 = configured. */ + bool APSetupLocked; /* Must be included if value is true */ + /* + * BOOL: indicates if the user has recently activated a Registrar to + * add an Enrollee. + */ + bool SelectedRegistra; + uint16_t DevicePasswordID; /* Device Password ID */ + /* Selected Registrar config method */ + uint16_t SelectedRegistraCfgMethod; + uint8_t UUID_E[SIR_WPS_UUID_LEN]; /* Unique identifier of the AP. */ + uint8_t RFBand; /* RF bands available on the AP */ +} tSirWPSBeaconIE; + +#define SIR_WPS_ASSOCRSP_VER_PRESENT 0x00000001 +#define SIR_WPS_ASSOCRSP_RESPONSETYPE_PRESENT 0x00000002 + +typedef struct sSirWPSAssocRspIE { + uint32_t FieldPresent; + uint32_t Version; + uint8_t ResposeType; +} tSirWPSAssocRspIE; + +typedef struct sSirAPWPSIEs { + tSirWPSProbeRspIE SirWPSProbeRspIE; /*WPS Set Probe Respose IE */ + tSirWPSBeaconIE SirWPSBeaconIE; /*WPS Set Beacon IE */ + tSirWPSAssocRspIE SirWPSAssocRspIE; /*WPS Set Assoc Response IE */ +} tSirAPWPSIEs, *tpSiriAPWPSIEs; + +typedef struct sSirUpdateAPWPSIEsReq { + uint16_t messageType; /* eWNI_SME_UPDATE_APWPSIE_REQ */ + uint16_t length; + uint16_t transactionId; /* Transaction ID for cmd */ + struct qdf_mac_addr bssid; /* BSSID */ + uint8_t sessionId; /* Session ID */ + tSirAPWPSIEs APWPSIEs; +} tSirUpdateAPWPSIEsReq, *tpSirUpdateAPWPSIEsReq; + +struct update_config { + uint16_t messageType; /* eWNI_SME_UPDATE_CONFIG */ + uint16_t length; + uint8_t sme_session_id; + uint16_t capab; + uint32_t value; +}; + +/* + * enum sir_update_session_param_type - session param type + * @SIR_PARAM_SSID_HIDDEN: ssidHidden parameter + * @SIR_PARAM_IGNORE_ASSOC_DISALLOWED: ignore_assoc_disallowed parameter + */ +enum sir_update_session_param_type { + SIR_PARAM_SSID_HIDDEN, + SIR_PARAM_IGNORE_ASSOC_DISALLOWED, +}; + +/* + * struct sir_update_session_param + * @message_type: SME message type + * @length: size of struct sir_update_session_param + * @session_id: Session ID + * @param_type: parameter to be updated + * @param_val: Parameter value to update + */ +struct sir_update_session_param { + uint16_t message_type; + uint16_t length; + uint8_t session_id; + uint32_t param_type; + uint32_t param_val; +}; + +/** + * struct sir_create_session - Used for creating session in monitor mode + * @type: SME host message type. + * @msg_len: Length of the message. + * @bss_id: bss_id for creating the session. + */ +struct sir_create_session { + uint16_t type; + uint16_t msg_len; + struct qdf_mac_addr bss_id; +}; + +/* Beacon Interval */ +typedef struct sSirChangeBIParams { + uint16_t messageType; + uint16_t length; + uint16_t beaconInterval; /* Beacon Interval */ + struct qdf_mac_addr bssid; + uint8_t sessionId; /* Session ID */ +} tSirChangeBIParams, *tpSirChangeBIParams; + +#ifdef QCA_HT_2040_COEX +typedef struct sSirSetHT2040Mode { + uint16_t messageType; + uint16_t length; + uint8_t cbMode; + bool obssEnabled; + struct qdf_mac_addr bssid; + uint8_t sessionId; /* Session ID */ +} tSirSetHT2040Mode, *tpSirSetHT2040Mode; +#endif + +#define SIR_WPS_PBC_WALK_TIME 120 /* 120 Second */ + +typedef struct sSirWPSPBCSession { + struct sSirWPSPBCSession *next; + struct qdf_mac_addr addr; + uint8_t uuid_e[SIR_WPS_UUID_LEN]; + uint32_t timestamp; +} tSirWPSPBCSession; + +typedef struct sSirSmeGetWPSPBCSessionsReq { + uint16_t messageType; /* eWNI_SME_GET_WPSPBC_SESSION_REQ */ + uint16_t length; + void *pUsrContext; + void *pSapEventCallback; + struct qdf_mac_addr bssid; /* BSSID */ + /* MAC Address of STA in WPS Session to be removed */ + struct qdf_mac_addr remove_mac; +} tSirSmeGetWPSPBCSessionsReq, *tpSirSmeGetWPSPBCSessionsReq; + +typedef struct sSirWPSPBCProbeReq { + struct qdf_mac_addr peer_macaddr; + uint16_t probeReqIELen; + uint8_t probeReqIE[512]; +} tSirWPSPBCProbeReq, *tpSirWPSPBCProbeReq; + +/* probereq from peer, when wsc is enabled */ +typedef struct sSirSmeProbeReqInd { + uint16_t messageType; /* eWNI_SME_WPS_PBC_PROBE_REQ_IND */ + uint16_t length; + uint8_t sessionId; + struct qdf_mac_addr bssid; + tSirWPSPBCProbeReq WPSPBCProbeReq; +} tSirSmeProbeReqInd, *tpSirSmeProbeReqInd; + +typedef struct sSirUpdateAPWPARSNIEsReq { + uint16_t messageType; /* eWNI_SME_SET_APWPARSNIEs_REQ */ + uint16_t length; + uint16_t transactionId; /* Transaction ID for cmd */ + struct qdf_mac_addr bssid; /* BSSID */ + uint8_t sessionId; /* Session ID */ + tSirRSNie APWPARSNIEs; +} tSirUpdateAPWPARSNIEsReq, *tpSirUpdateAPWPARSNIEsReq; + +#define SIR_ROAM_MAX_CHANNELS 80 +#define SIR_ROAM_SCAN_MAX_PB_REQ_SIZE 450 +/* Occupied channel list remains static */ +#define CHANNEL_LIST_STATIC 1 +/* Occupied channel list can be learnt after init */ +#define CHANNEL_LIST_DYNAMIC_INIT 2 +/* Occupied channel list can be learnt after flush */ +#define CHANNEL_LIST_DYNAMIC_FLUSH 3 +/* Occupied channel list can be learnt after update */ +#define CHANNEL_LIST_DYNAMIC_UPDATE 4 +#define SIR_ROAM_SCAN_24G_DEFAULT_CH 1 +#define SIR_ROAM_SCAN_5G_DEFAULT_CH 36 +#define SIR_ROAM_SCAN_RESERVED_BYTES 61 + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +#define SIR_ROAM_SCAN_PSK_SIZE 32 +#define SIR_ROAM_R0KH_ID_MAX_LEN 48 +#endif +/* SME -> HAL - This is the host offload request. */ +#define SIR_IPV4_ARP_REPLY_OFFLOAD 0 +#define SIR_IPV6_NEIGHBOR_DISCOVERY_OFFLOAD 1 +#define SIR_IPV6_NS_OFFLOAD 2 +#define SIR_OFFLOAD_DISABLE 0 +#define SIR_OFFLOAD_ENABLE 1 + +#ifdef WLAN_NS_OFFLOAD +typedef struct sSirNsOffloadReq { + uint8_t srcIPv6Addr[SIR_MAC_IPV6_ADDR_LEN]; + uint8_t selfIPv6Addr[SIR_MAC_NUM_TARGET_IPV6_NS_OFFLOAD_NA][SIR_MAC_IPV6_ADDR_LEN]; + uint8_t targetIPv6Addr[SIR_MAC_NUM_TARGET_IPV6_NS_OFFLOAD_NA][SIR_MAC_IPV6_ADDR_LEN]; + struct qdf_mac_addr self_macaddr; + uint8_t srcIPv6AddrValid; + uint8_t targetIPv6AddrValid[SIR_MAC_NUM_TARGET_IPV6_NS_OFFLOAD_NA]; + uint8_t target_ipv6_addr_ac_type[SIR_MAC_NUM_TARGET_IPV6_NS_OFFLOAD_NA]; + uint8_t slotIdx; +} tSirNsOffloadReq, *tpSirNsOffloadReq; +#endif /* WLAN_NS_OFFLOAD */ + +/** + * struct hw_filter_request - For enable/disable HW Filter + * @mode_bitmap: the hardware filter mode to configure + * @bssid: bss_id for get session. + */ +struct hw_filter_request { + uint8_t mode_bitmap; + struct qdf_mac_addr bssid; +}; + +typedef struct sSirHostOffloadReq { + uint8_t offloadType; + uint8_t enableOrDisable; + uint32_t num_ns_offload_count; + union { + uint8_t hostIpv4Addr[SIR_IPV4_ADDR_LEN]; + uint8_t hostIpv6Addr[SIR_MAC_IPV6_ADDR_LEN]; + } params; +#ifdef WLAN_NS_OFFLOAD + tSirNsOffloadReq nsOffloadInfo; +#endif /* WLAN_NS_OFFLOAD */ + struct qdf_mac_addr bssid; +} tSirHostOffloadReq, *tpSirHostOffloadReq; + +/* Packet Types. */ +#define SIR_KEEP_ALIVE_NULL_PKT 1 +#define SIR_KEEP_ALIVE_UNSOLICIT_ARP_RSP 2 + +/* Keep Alive request. */ +typedef struct sSirKeepAliveReq { + uint8_t packetType; + uint32_t timePeriod; + tSirIpv4Addr hostIpv4Addr; + tSirIpv4Addr destIpv4Addr; + struct qdf_mac_addr dest_macaddr; + struct qdf_mac_addr bssid; + uint8_t sessionId; +} tSirKeepAliveReq, *tpSirKeepAliveReq; + +typedef struct sSirSmeMgmtFrameInd { + uint16_t frame_len; + uint32_t rxChan; + uint8_t sessionId; + uint8_t frameType; + int8_t rxRssi; + uint8_t frameBuf[1]; /* variable */ +} tSirSmeMgmtFrameInd, *tpSirSmeMgmtFrameInd; + +typedef void (*sir_mgmt_frame_ind_callback)(tSirSmeMgmtFrameInd *frame_ind); +/** + * struct sir_sme_mgmt_frame_cb_req - Register a + * management frame callback req + * + * @message_type: message id + * @length: msg length + * @callback: callback for management frame indication + */ +struct sir_sme_mgmt_frame_cb_req { + uint16_t message_type; + uint16_t length; + sir_mgmt_frame_ind_callback callback; +}; + +typedef void (*sir_p2p_ack_ind_callback)(uint32_t session_id, + bool tx_completion_status); + +/** + * struct sir_p2p_ack_ind_cb_req - Register a p2p ack ind callback req + * @message_type: message id + * @length: msg length + * @callback: callback for p2p ack indication + */ +struct sir_sme_p2p_ack_ind_cb_req { + uint16_t message_type; + uint16_t length; + sir_p2p_ack_ind_callback callback; +}; + +#ifdef WLAN_FEATURE_11W +typedef struct sSirSmeUnprotMgmtFrameInd { + uint8_t sessionId; + uint8_t frameType; + uint8_t frameLen; + uint8_t frameBuf[1]; /* variable */ +} tSirSmeUnprotMgmtFrameInd, *tpSirSmeUnprotMgmtFrameInd; +#endif + +#define SIR_IS_FULL_POWER_REASON_DISCONNECTED(eReason) \ + ((eSME_LINK_DISCONNECTED_BY_HDD == (eReason)) || \ + (eSME_LINK_DISCONNECTED_BY_OTHER == (eReason))) +#define SIR_IS_FULL_POWER_NEEDED_BY_HDD(eReason) \ + ((eSME_LINK_DISCONNECTED_BY_HDD == (eReason)) || \ + (eSME_FULL_PWR_NEEDED_BY_HDD == (eReason))) + +/* P2P Power Save Related */ +typedef struct sSirNoAParam { + uint8_t ctWindow:7; + uint8_t OppPS:1; + uint8_t count; + uint32_t duration; + uint32_t interval; + uint32_t singleNoADuration; + uint8_t psSelection; +} tSirNoAParam, *tpSirNoAParam; + +typedef struct sSirWlanResumeParam { + uint8_t configuredMcstBcstFilterSetting; +} tSirWlanResumeParam, *tpSirWlanResumeParam; + +#ifdef WLAN_FEATURE_EXTWOW_SUPPORT + +typedef enum ext_wow_type { + EXT_WOW_TYPE_APP_TYPE1, /* wow type: only enable wakeup for app type1 */ + EXT_WOW_TYPE_APP_TYPE2, /* wow type: only enable wakeup for app type2 */ + EXT_WOW_TYPE_APP_TYPE1_2, /* wow type: enable wakeup for app type1&2 */ +} EXT_WOW_TYPE; + +typedef struct { + uint8_t vdev_id; + EXT_WOW_TYPE type; + uint32_t wakeup_pin_num; +} tSirExtWoWParams, *tpSirExtWoWParams; + +typedef struct { + uint8_t vdev_id; + struct qdf_mac_addr wakee_mac_addr; + uint8_t identification_id[8]; + uint8_t password[16]; + uint32_t id_length; + uint32_t pass_length; +} tSirAppType1Params, *tpSirAppType1Params; + +typedef struct { + uint8_t vdev_id; + + uint8_t rc4_key[16]; + uint32_t rc4_key_len; + + /** ip header parameter */ + uint32_t ip_id; /* NC id */ + uint32_t ip_device_ip; /* NC IP address */ + uint32_t ip_server_ip; /* Push server IP address */ + + /** tcp header parameter */ + uint16_t tcp_src_port; /* NC TCP port */ + uint16_t tcp_dst_port; /* Push server TCP port */ + uint32_t tcp_seq; + uint32_t tcp_ack_seq; + + uint32_t keepalive_init; /* Initial ping interval */ + uint32_t keepalive_min; /* Minimum ping interval */ + uint32_t keepalive_max; /* Maximum ping interval */ + uint32_t keepalive_inc; /* Increment of ping interval */ + + struct qdf_mac_addr gateway_mac; + uint32_t tcp_tx_timeout_val; + uint32_t tcp_rx_timeout_val; +} tSirAppType2Params, *tpSirAppType2Params; +#endif + +#define ANI_MAX_IBSS_ROUTE_TABLE_ENTRY 100 + +typedef struct sAniDestIpNextHopMacPair { + uint8_t destIpv4Addr[QDF_IPV4_ADDR_SIZE]; + uint8_t nextHopMacAddr[QDF_MAC_ADDR_SIZE]; +} tAniDestIpNextHopMacPair; + +typedef struct sAniIbssRouteTable { + uint8_t sessionId; + uint16_t numEntries; + tAniDestIpNextHopMacPair destIpNextHopPair[1]; +} tAniIbssRouteTable; + +#ifdef FEATURE_WLAN_SCAN_PNO +/* */ +/* PNO Messages */ +/* */ + + +/* Set PNO */ +#define SIR_PNO_MAX_PLAN_REQUEST 2 +#define SIR_PNO_MAX_NETW_CHANNELS 26 +#define SIR_PNO_MAX_NETW_CHANNELS_EX 60 +#define SIR_PNO_MAX_SUPP_NETWORKS 16 + +/* + * size based of dot11 declaration without extra IEs as we will not carry those + * for PNO + */ +#define SIR_PNO_MAX_PB_REQ_SIZE 450 + +#define SIR_PNO_24G_DEFAULT_CH 1 +#define SIR_PNO_5G_DEFAULT_CH 36 + +typedef enum { + SIR_PNO_MODE_IMMEDIATE, + SIR_PNO_MODE_ON_SUSPEND, + SIR_PNO_MODE_ON_RESUME, + SIR_PNO_MODE_MAX +} eSirPNOMode; + +typedef struct { + tSirMacSSid ssId; + uint32_t authentication; + uint32_t encryption; + uint32_t bcastNetwType; + uint8_t ucChannelCount; + uint8_t aChannels[SIR_PNO_MAX_NETW_CHANNELS_EX]; + int32_t rssiThreshold; +} tSirNetworkType; + +/** + * struct sSirPNOScanReq - PNO Scan request structure + * @enable: flag to enable or disable + * @modePNO: PNO Mode + * @do_passive_scan: Flag to request passive scan to fw + * @ucNetworksCount: Number of networks + * @aNetworks: Preferred network list + * @sessionId: Session identifier + * @fast_scan_period: Fast Scan period + * @slow_scan_period: Slow scan period + * @delay_start_time: delay in seconds to use before starting the first scan + * @fast_scan_max_cycles: Fast scan max cycles + * @us24GProbeTemplateLen: 2.4G probe template length + * @p24GProbeTemplate: 2.4G probe template + * @us5GProbeTemplateLen: 5G probe template length + * @p5GProbeTemplate: 5G probe template + */ +typedef struct sSirPNOScanReq { + uint8_t enable; + eSirPNOMode modePNO; + bool do_passive_scan; + uint8_t ucNetworksCount; + tSirNetworkType aNetworks[SIR_PNO_MAX_SUPP_NETWORKS]; + uint8_t sessionId; + uint32_t fast_scan_period; + uint32_t slow_scan_period; + uint32_t delay_start_time; + uint8_t fast_scan_max_cycles; + + uint32_t active_min_time; + uint32_t active_max_time; + uint32_t passive_min_time; + uint32_t passive_max_time; + +#ifdef FEATURE_WLAN_SCAN_PNO + bool pno_channel_prediction; + uint8_t top_k_num_of_channels; + uint8_t stationary_thresh; + enum wmi_dwelltime_adaptive_mode pnoscan_adaptive_dwell_mode; + uint32_t channel_prediction_full_scan; +#endif + + /* mac address randomization attributes */ + bool enable_pno_scan_randomization; + uint8_t mac_addr[QDF_MAC_ADDR_SIZE]; + uint8_t mac_addr_mask[QDF_MAC_ADDR_SIZE]; +} tSirPNOScanReq, *tpSirPNOScanReq; + +/* Preferred Network Found Indication */ +typedef struct { + uint16_t mesgType; + uint16_t mesgLen; + /* Network that was found with the highest RSSI */ + tSirMacSSid ssId; + /* Indicates the RSSI */ + uint8_t rssi; + /* Length of the beacon or probe response + * corresponding to the candidate found by PNO */ + uint32_t frameLength; + uint8_t sessionId; + /* Index to memory location where the contents of + * beacon or probe response frame will be copied */ + uint8_t data[1]; +} tSirPrefNetworkFoundInd, *tpSirPrefNetworkFoundInd; +#endif /* FEATURE_WLAN_SCAN_PNO */ + + +/** + * struct candidate_chan_info - channel information for candidate + * @channel_num: channel number. + * @other_ap_count: other ap count on candidate channel. + * @max_rssi_on_channel: Max best rssi on candiate channel + */ +struct candidate_chan_info { + uint8_t channel_num; + uint8_t other_ap_count; + int8_t max_rssi_on_channel; +}; + +/* + * ALLOWED_ACTION_FRAMES_BITMAP + * + * Bitmask is based on the below. The frames with 0's + * set to their corresponding bit can be dropped in FW. + * + * -----------------------------+-----+-------+ + * Type | Bit | Allow | + * -----------------------------+-----+-------+ + * SIR_MAC_ACTION_SPECTRUM_MGMT 0 1 + * SIR_MAC_ACTION_QOS_MGMT 1 1 + * SIR_MAC_ACTION_DLP 2 0 + * SIR_MAC_ACTION_BLKACK 3 0 + * SIR_MAC_ACTION_PUBLIC_USAGE 4 1 + * SIR_MAC_ACTION_RRM 5 1 + * SIR_MAC_ACTION_FAST_BSS_TRNST 6 0 + * SIR_MAC_ACTION_HT 7 0 + * SIR_MAC_ACTION_SA_QUERY 8 1 + * SIR_MAC_ACTION_PROT_DUAL_PUB 9 1 + * SIR_MAC_ACTION_WNM 10 1 + * SIR_MAC_ACTION_UNPROT_WNM 11 0 + * SIR_MAC_ACTION_TDLS 12 0 + * SIR_MAC_ACITON_MESH 13 0 + * SIR_MAC_ACTION_MHF 14 0 + * SIR_MAC_SELF_PROTECTED 15 0 + * SIR_MAC_ACTION_WME 17 1 + * SIR_MAC_ACTION_FST 18 1 + * SIR_MAC_ACTION_VHT 21 1 + * ----------------------------+------+-------+ + */ +#define ALLOWED_ACTION_FRAMES_BITMAP0 \ + ((1 << SIR_MAC_ACTION_SPECTRUM_MGMT) | \ + (1 << SIR_MAC_ACTION_QOS_MGMT) | \ + (1 << SIR_MAC_ACTION_PUBLIC_USAGE) | \ + (1 << SIR_MAC_ACTION_RRM) | \ + (1 << SIR_MAC_ACTION_SA_QUERY) | \ + (1 << SIR_MAC_ACTION_PROT_DUAL_PUB) | \ + (1 << SIR_MAC_ACTION_WNM) | \ + (1 << SIR_MAC_ACTION_WME) | \ + (1 << SIR_MAC_ACTION_FST) | \ + (1 << SIR_MAC_ACTION_VHT)) + +#define ALLOWED_ACTION_FRAMES_BITMAP1 0x0 +#define ALLOWED_ACTION_FRAMES_BITMAP2 0x0 +#define ALLOWED_ACTION_FRAMES_BITMAP3 0x0 +#define ALLOWED_ACTION_FRAMES_BITMAP4 0x0 +#define ALLOWED_ACTION_FRAMES_BITMAP5 0x0 +#define ALLOWED_ACTION_FRAMES_BITMAP6 0x0 +#define ALLOWED_ACTION_FRAMES_BITMAP7 0x0 + +#define ALLOWED_ACTION_FRAME_MAP_WORDS (SIR_MAC_ACTION_MAX / 32) + + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +typedef struct { + uint8_t acvo_uapsd:1; + uint8_t acvi_uapsd:1; + uint8_t acbk_uapsd:1; + uint8_t acbe_uapsd:1; + uint8_t reserved:4; +} tSirAcUapsd, *tpSirAcUapsd; +#endif + +typedef struct { + tSirMacSSid ssId; + uint8_t currAPbssid[QDF_MAC_ADDR_SIZE]; + uint32_t authentication; + uint8_t encryption; + uint8_t mcencryption; + uint8_t ChannelCount; + uint8_t ChannelCache[SIR_ROAM_MAX_CHANNELS]; +#ifdef WLAN_FEATURE_11W + bool mfp_enabled; +#endif + +} tSirRoamNetworkType; + +typedef struct SirMobilityDomainInfo { + uint8_t mdiePresent; + uint16_t mobilityDomain; +} tSirMobilityDomainInfo; + +typedef enum { + SIR_ROAMING_DFS_CHANNEL_DISABLED = 0, + SIR_ROAMING_DFS_CHANNEL_ENABLED_NORMAL = 1, + SIR_ROAMING_DFS_CHANNEL_ENABLED_ACTIVE = 2 +} eSirDFSRoamScanMode; +#define MAX_SSID_ALLOWED_LIST 4 +#define MAX_BSSID_AVOID_LIST 16 +#define MAX_BSSID_FAVORED 16 +/** + * struct roam_ext_params - Structure holding roaming parameters + * @num_bssid_avoid_list: The number of BSSID's that we should + * avoid connecting to. It is like a + * blacklist of BSSID's. + * @num_ssid_allowed_list: The number of SSID profiles that are + * in the Whitelist. When roaming, we + * consider the BSSID's with this SSID + * also for roaming apart from the connected one's + * @num_bssid_favored: Number of BSSID's which have a preference over + * others + * @ssid_allowed_list: Whitelist SSID's + * @bssid_avoid_list: Blacklist SSID's + * @bssid_favored: Favorable BSSID's + * @bssid_favored_factor: RSSI to be added to this BSSID to prefer it + * @raise_rssi_thresh_5g: The RSSI threshold below which the + * raise_factor_5g (boost factor) should be + * applied. + * @drop_rssi_thresh_5g: The RSSI threshold beyond which the + * drop_factor_5g (penalty factor) should be + * applied + * @raise_rssi_type_5g: Algorithm to apply the boost factor + * @raise_factor_5g: Boost factor + * @drop_rssi_type_5g: Algorithm to apply the penalty factor + * @drop_factor_5g: Penalty factor + * @max_raise_rssi_5g: Maximum amount of Boost that can added + * @max_drop_rssi_5g: Maximum amount of penalty that can be subtracted + * @good_rssi_threshold: The Lookup UP threshold beyond which roaming + * scan should be performed. + * @rssi_diff: RSSI difference for the AP to be better over the + * current AP to avoid ping pong effects + * @good_rssi_roam: Lazy Roam + * @is_5g_pref_enabled: 5GHz BSSID preference feature enable/disable. + * + * This structure holds all the key parameters related to + * initial connection and also roaming connections. + * */ +struct roam_ext_params { + uint8_t num_bssid_avoid_list; + uint8_t num_ssid_allowed_list; + uint8_t num_bssid_favored; + tSirMacSSid ssid_allowed_list[MAX_SSID_ALLOWED_LIST]; + struct qdf_mac_addr bssid_avoid_list[MAX_BSSID_AVOID_LIST]; + struct qdf_mac_addr bssid_favored[MAX_BSSID_FAVORED]; + uint8_t bssid_favored_factor[MAX_BSSID_FAVORED]; + int raise_rssi_thresh_5g; + int drop_rssi_thresh_5g; + uint8_t raise_rssi_type_5g; + uint8_t raise_factor_5g; + uint8_t drop_rssi_type_5g; + uint8_t drop_factor_5g; + int max_raise_rssi_5g; + int max_drop_rssi_5g; + int alert_rssi_threshold; + int rssi_diff; + int good_rssi_roam; + bool is_5g_pref_enabled; + int dense_rssi_thresh_offset; + int dense_min_aps_cnt; + int initial_dense_status; + int traffic_threshold; +}; + +/** + * struct pmkid_mode_bits - Bit flags for PMKID usage in RSN IE + * @fw_okc: Opportunistic key caching enable in firmware + * @fw_pmksa_cache: PMKSA caching enable in firmware, remember previously + * visited BSSID/PMK pairs + */ +struct pmkid_mode_bits { + uint32_t fw_okc:1; + uint32_t fw_pmksa_cache:1; + uint32_t unused:30; +}; + +typedef struct sSirRoamOffloadScanReq { + uint16_t message_type; + uint16_t length; + bool RoamScanOffloadEnabled; + bool MAWCEnabled; + int8_t LookupThreshold; + uint8_t delay_before_vdev_stop; + uint8_t OpportunisticScanThresholdDiff; + uint8_t RoamRescanRssiDiff; + uint8_t RoamRssiDiff; + uint8_t ChannelCacheType; + uint8_t Command; + uint8_t reason; + uint16_t NeighborScanTimerPeriod; + uint16_t NeighborRoamScanRefreshPeriod; + uint16_t NeighborScanChannelMinTime; + uint16_t NeighborScanChannelMaxTime; + uint16_t EmptyRefreshScanPeriod; + uint8_t ValidChannelCount; + uint8_t ValidChannelList[SIR_ROAM_MAX_CHANNELS]; + bool IsESEAssoc; + uint8_t nProbes; + uint16_t HomeAwayTime; + tSirRoamNetworkType ConnectedNetwork; + tSirMobilityDomainInfo MDID; + uint8_t sessionId; + uint8_t RoamBmissFirstBcnt; + uint8_t RoamBmissFinalBcnt; + uint8_t RoamBeaconRssiWeight; + eSirDFSRoamScanMode allowDFSChannelRoam; +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + uint8_t RoamOffloadEnabled; + uint8_t PSK_PMK[SIR_ROAM_SCAN_PSK_SIZE]; + uint32_t pmk_len; + uint8_t Prefer5GHz; + uint8_t RoamRssiCatGap; + uint8_t Select5GHzMargin; + uint8_t KRK[SIR_KRK_KEY_LEN]; + uint8_t BTK[SIR_BTK_KEY_LEN]; + uint32_t ReassocFailureTimeout; + tSirAcUapsd AcUapsd; + uint8_t R0KH_ID[SIR_ROAM_R0KH_ID_MAX_LEN]; + uint32_t R0KH_ID_Length; + uint8_t RoamKeyMgmtOffloadEnabled; + struct pmkid_mode_bits pmkid_modes; +#endif + struct roam_ext_params roam_params; + uint8_t middle_of_roaming; + uint32_t hi_rssi_scan_max_count; + uint32_t hi_rssi_scan_rssi_delta; + uint32_t hi_rssi_scan_delay; + int32_t hi_rssi_scan_rssi_ub; + uint8_t early_stop_scan_enable; + int8_t early_stop_scan_min_threshold; + int8_t early_stop_scan_max_threshold; + enum wmi_dwelltime_adaptive_mode roamscan_adaptive_dwell_mode; + tSirAddie assoc_ie; +} tSirRoamOffloadScanReq, *tpSirRoamOffloadScanReq; + +typedef struct sSirRoamOffloadScanRsp { + uint8_t sessionId; + uint32_t reason; +} tSirRoamOffloadScanRsp, *tpSirRoamOffloadScanRsp; + + +#ifdef WLAN_FEATURE_PACKET_FILTERING +/*--------------------------------------------------------------------------- + Packet Filtering Parameters + ---------------------------------------------------------------------------*/ +#define SIR_MAX_FILTER_TEST_DATA_LEN 8 +#define SIR_MAX_FILTER_TEST_DATA_OFFSET 200 +#define SIR_MAX_NUM_MULTICAST_ADDRESS 240 +#define SIR_MAX_NUM_FILTERS 20 +#define SIR_MAX_NUM_TESTS_PER_FILTER 10 + +/* */ +/* Receive Filter Parameters */ +/* */ +typedef enum { + SIR_RCV_FILTER_TYPE_INVALID, + SIR_RCV_FILTER_TYPE_FILTER_PKT, + SIR_RCV_FILTER_TYPE_BUFFER_PKT, + SIR_RCV_FILTER_TYPE_MAX_ENUM_SIZE +} eSirReceivePacketFilterType; + +typedef enum { + SIR_FILTER_HDR_TYPE_INVALID, + SIR_FILTER_HDR_TYPE_MAC, + SIR_FILTER_HDR_TYPE_ARP, + SIR_FILTER_HDR_TYPE_IPV4, + SIR_FILTER_HDR_TYPE_IPV6, + SIR_FILTER_HDR_TYPE_UDP, + SIR_FILTER_HDR_TYPE_MAX +} eSirRcvPktFltProtocolType; + +typedef enum { + SIR_FILTER_CMP_TYPE_INVALID, + SIR_FILTER_CMP_TYPE_EQUAL, + SIR_FILTER_CMP_TYPE_MASK_EQUAL, + SIR_FILTER_CMP_TYPE_NOT_EQUAL, + SIR_FILTER_CMP_TYPE_MASK_NOT_EQUAL, + SIR_FILTER_CMP_TYPE_MAX +} eSirRcvPktFltCmpFlagType; + +typedef struct sSirRcvPktFilterFieldParams { + eSirRcvPktFltProtocolType protocolLayer; + eSirRcvPktFltCmpFlagType cmpFlag; + /* Length of the data to compare */ + uint16_t dataLength; + /* from start of the respective frame header */ + uint8_t dataOffset; + /* Reserved field */ + uint8_t reserved; + /* Data to compare */ + uint8_t compareData[SIR_MAX_FILTER_TEST_DATA_LEN]; + /* Mask to be applied on the received packet data before compare */ + uint8_t dataMask[SIR_MAX_FILTER_TEST_DATA_LEN]; +} tSirRcvPktFilterFieldParams, *tpSirRcvPktFilterFieldParams; + +typedef struct sSirRcvPktFilterCfg { + uint8_t filterId; + eSirReceivePacketFilterType filterType; + uint32_t numFieldParams; + uint32_t coalesceTime; + struct qdf_mac_addr self_macaddr; + struct qdf_mac_addr bssid; /* Bssid of the connected AP */ + tSirRcvPktFilterFieldParams paramsData[SIR_MAX_NUM_TESTS_PER_FILTER]; +} tSirRcvPktFilterCfgType, *tpSirRcvPktFilterCfgType; + +/* */ +/* Filter Packet Match Count Parameters */ +/* */ +typedef struct sSirRcvFltPktMatchCnt { + uint8_t filterId; + uint32_t matchCnt; +} tSirRcvFltPktMatchCnt, tpSirRcvFltPktMatchCnt; + +typedef struct sSirRcvFltPktMatchRsp { + uint16_t mesgType; + uint16_t mesgLen; + + /* Success or Failure */ + uint32_t status; + tSirRcvFltPktMatchCnt filterMatchCnt[SIR_MAX_NUM_FILTERS]; + struct qdf_mac_addr bssid; +} tSirRcvFltPktMatchRsp, *tpSirRcvFltPktMatchRsp; + +/* */ +/* Receive Filter Clear Parameters */ +/* */ +typedef struct sSirRcvFltPktClearParam { + uint32_t status; /* only valid for response message */ + uint8_t filterId; + struct qdf_mac_addr self_macaddr; + struct qdf_mac_addr bssid; +} tSirRcvFltPktClearParam, *tpSirRcvFltPktClearParam; + +/* */ +/* Multicast Address List Parameters */ +/* */ +typedef struct sSirRcvFltMcAddrList { + uint32_t ulMulticastAddrCnt; + struct qdf_mac_addr multicastAddr[SIR_MAX_NUM_MULTICAST_ADDRESS]; + struct qdf_mac_addr self_macaddr; + struct qdf_mac_addr bssid; + uint8_t action; +} tSirRcvFltMcAddrList, *tpSirRcvFltMcAddrList; +#endif /* WLAN_FEATURE_PACKET_FILTERING */ + +/* */ +/* Generic version information */ +/* */ +typedef struct { + uint8_t revision; + uint8_t version; + uint8_t minor; + uint8_t major; +} tSirVersionType; + +#ifdef WLAN_FEATURE_GTK_OFFLOAD +/*--------------------------------------------------------------------------- +* WMA_GTK_OFFLOAD_REQ +*--------------------------------------------------------------------------*/ +typedef struct { + uint32_t ulFlags; /* optional flags */ + uint8_t aKCK[16]; /* Key confirmation key */ + uint8_t aKEK[16]; /* key encryption key */ + uint64_t ullKeyReplayCounter; /* replay counter */ + struct qdf_mac_addr bssid; +} tSirGtkOffloadParams, *tpSirGtkOffloadParams; + +/*--------------------------------------------------------------------------- +* WMA_GTK_OFFLOAD_GETINFO_REQ +*--------------------------------------------------------------------------*/ +typedef struct { + uint16_t mesgType; + uint16_t mesgLen; + + uint32_t ulStatus; /* success or failure */ + uint64_t ullKeyReplayCounter; /* current replay counter value */ + uint32_t ulTotalRekeyCount; /* total rekey attempts */ + uint32_t ulGTKRekeyCount; /* successful GTK rekeys */ + uint32_t ulIGTKRekeyCount; /* successful iGTK rekeys */ + struct qdf_mac_addr bssid; +} tSirGtkOffloadGetInfoRspParams, *tpSirGtkOffloadGetInfoRspParams; +#endif /* WLAN_FEATURE_GTK_OFFLOAD */ + +/** + * struct sir_wifi_start_log - Structure to store the params sent to start/ + * stop logging + * @name: Attribute which indicates the type of logging like per packet + * statistics, connectivity etc. + * @verbose_level: Verbose level which can be 0,1,2,3 + * @is_iwpriv_command: Set 1 for iwpriv command + * @ini_triggered: triggered using ini + * @user_triggered: triggered by user + * @size: pktlog buffer size + * @is_pktlog_buff_clear: clear the pktlog buffer + */ +struct sir_wifi_start_log { + uint32_t ring_id; + uint32_t verbose_level; + uint32_t is_iwpriv_command; + bool ini_triggered; + uint8_t user_triggered; + int size; + bool is_pktlog_buff_clear; +}; + + +/** + * enum hw_mode_bandwidth - bandwidth of wifi channel. + * + * @HW_MODE_5_MHZ: 5 Mhz bandwidth + * @HW_MODE_10_MHZ: 10 Mhz bandwidth + * @HW_MODE_20_MHZ: 20 Mhz bandwidth + * @HW_MODE_40_MHZ: 40 Mhz bandwidth + * @HW_MODE_80_MHZ: 80 Mhz bandwidth + * @HW_MODE_80_PLUS_80_MHZ: 80 Mhz plus 80 Mhz bandwidth + * @HW_MODE_160_MHZ: 160 Mhz bandwidth + * @HW_MODE_MAX_BANDWIDTH: Max place holder + * + * These are generic IDs that identify the various roles + * in the software system + */ +enum hw_mode_bandwidth { + HW_MODE_BW_NONE, + HW_MODE_5_MHZ, + HW_MODE_10_MHZ, + HW_MODE_20_MHZ, + HW_MODE_40_MHZ, + HW_MODE_80_MHZ, + HW_MODE_80_PLUS_80_MHZ, + HW_MODE_160_MHZ, + HW_MODE_MAX_BANDWIDTH +}; + +/** + * enum set_hw_mode_status - Status of set HW mode command + * @SET_HW_MODE_STATUS_OK: command successful + * @SET_HW_MODE_STATUS_EINVAL: Requested invalid hw_mode + * @SET_HW_MODE_STATUS_ECANCELED: HW mode change cancelled + * @SET_HW_MODE_STATUS_ENOTSUP: HW mode not supported + * @SET_HW_MODE_STATUS_EHARDWARE: HW mode change prevented by hardware + * @SET_HW_MODE_STATUS_EPENDING: HW mode change is pending + * @SET_HW_MODE_STATUS_ECOEX: HW mode change conflict with Coex + */ +enum set_hw_mode_status { + SET_HW_MODE_STATUS_OK, + SET_HW_MODE_STATUS_EINVAL, + SET_HW_MODE_STATUS_ECANCELED, + SET_HW_MODE_STATUS_ENOTSUP, + SET_HW_MODE_STATUS_EHARDWARE, + SET_HW_MODE_STATUS_EPENDING, + SET_HW_MODE_STATUS_ECOEX, +}; + +/** + * struct sir_pcl_list - Format of PCL + * @pcl_list: List of preferred channels + * @weight_list: Weights of the PCL + * @pcl_len: Number of channels in the PCL + */ +struct sir_pcl_list { + uint8_t pcl_list[128]; + uint8_t weight_list[128]; + uint32_t pcl_len; +}; + +/** + * struct sir_pcl_chan_weights - Params to get the valid weighed list + * @pcl_list: Preferred channel list already sorted in the order of preference + * @pcl_len: Length of the PCL + * @saved_chan_list: Valid channel list updated as part of + * WMA_UPDATE_CHAN_LIST_REQ + * @saved_num_chan: Length of the valid channel list + * @weighed_valid_list: Weights of the valid channel list. This will have one + * to one mapping with valid_chan_list. FW expects channel order and size to be + * as per the list provided in WMI_SCAN_CHAN_LIST_CMDID. + * @weight_list: Weights assigned by policy manager + */ +struct sir_pcl_chan_weights { + uint8_t pcl_list[128]; + uint32_t pcl_len; + uint8_t saved_chan_list[128]; + uint32_t saved_num_chan; + uint8_t weighed_valid_list[128]; + uint8_t weight_list[128]; +}; + +/** + * struct sir_hw_mode_params - HW mode params + * @mac0_tx_ss: MAC0 Tx spatial stream + * @mac0_rx_ss: MAC0 Rx spatial stream + * @mac1_tx_ss: MAC1 Tx spatial stream + * @mac1_rx_ss: MAC1 Rx spatial stream + * @mac0_bw: MAC0 bandwidth + * @mac1_bw: MAC1 bandwidth + * @dbs_cap: DBS capabality + * @agile_dfs_cap: Agile DFS capabality + */ +struct sir_hw_mode_params { + uint8_t mac0_tx_ss; + uint8_t mac0_rx_ss; + uint8_t mac1_tx_ss; + uint8_t mac1_rx_ss; + uint8_t mac0_bw; + uint8_t mac1_bw; + uint8_t dbs_cap; + uint8_t agile_dfs_cap; + uint8_t sbs_cap; +}; + +/** + * struct sir_vdev_mac_map - vdev id-mac id map + * @vdev_id: VDEV id + * @mac_id: MAC id + */ +struct sir_vdev_mac_map { + uint32_t vdev_id; + uint32_t mac_id; +}; + +/** + * struct sir_set_hw_mode_resp - HW mode response + * @status: Status + * @cfgd_hw_mode_index: Configured HW mode index + * @num_vdev_mac_entries: Number of vdev-mac id entries + * @vdev_mac_map: vdev id-mac id map + */ +struct sir_set_hw_mode_resp { + uint32_t status; + uint32_t cfgd_hw_mode_index; + uint32_t num_vdev_mac_entries; + struct sir_vdev_mac_map vdev_mac_map[MAX_VDEV_SUPPORTED]; +}; + +/** + * struct sir_hw_mode_trans_ind - HW mode transition indication + * @old_hw_mode_index: Index of old HW mode + * @new_hw_mode_index: Index of new HW mode + * @num_vdev_mac_entries: Number of vdev-mac id entries + * @vdev_mac_map: vdev id-mac id map + */ +struct sir_hw_mode_trans_ind { + uint32_t old_hw_mode_index; + uint32_t new_hw_mode_index; + uint32_t num_vdev_mac_entries; + struct sir_vdev_mac_map vdev_mac_map[MAX_VDEV_SUPPORTED]; +}; + +/** + * struct sir_dual_mac_config_resp - Dual MAC config response + * @status: Status of setting the dual mac configuration + */ +struct sir_dual_mac_config_resp { + uint32_t status; +}; + +/** + * enum set_antenna_mode_status - Status of set antenna mode + * command + * @SET_ANTENNA_MODE_STATUS_OK: command successful + * @SET_ANTENNA_MODE_STATUS_EINVAL: invalid antenna mode + * @SET_ANTENNA_MODE_STATUS_ECANCELED: mode change cancelled + * @SET_ANTENNA_MODE_STATUS_ENOTSUP: mode not supported + */ +enum set_antenna_mode_status { + SET_ANTENNA_MODE_STATUS_OK, + SET_ANTENNA_MODE_STATUS_EINVAL, + SET_ANTENNA_MODE_STATUS_ECANCELED, + SET_ANTENNA_MODE_STATUS_ENOTSUP, +}; + +/** + * struct sir_antenna_mode_resp - set antenna mode response + * @status: Status of setting the antenna mode + */ +struct sir_antenna_mode_resp { + enum set_antenna_mode_status status; +}; + +#ifdef WLAN_WAKEUP_EVENTS +/*--------------------------------------------------------------------------- + tSirWakeReasonInd + ---------------------------------------------------------------------------*/ +typedef struct { + uint16_t mesgType; + uint16_t mesgLen; + uint32_t ulReason; /* see tWakeReasonType */ + uint32_t ulReasonArg; /* argument specific to the reason type */ + /* length of optional data stored in this message, in case + * HAL truncates the data (i.e. data packets) this length + * will be less than the actual length + */ + uint32_t ulStoredDataLen; + uint32_t ulActualDataLen; /* actual length of data */ + /* variable length start of data (length == storedDataLen) + * see specific wake type + */ + uint8_t aDataStart[1]; +} tSirWakeReasonInd, *tpSirWakeReasonInd; +#endif /* WLAN_WAKEUP_EVENTS */ + +/*--------------------------------------------------------------------------- + sAniSetTmLevelReq + ---------------------------------------------------------------------------*/ +typedef struct sAniSetTmLevelReq { + uint16_t tmMode; + uint16_t newTmLevel; +} tAniSetTmLevelReq, *tpAniSetTmLevelReq; + +/* access categories */ +enum sir_wifi_traffic_ac { + WIFI_AC_VO = 0, + WIFI_AC_VI = 1, + WIFI_AC_BE = 2, + WIFI_AC_BK = 3, + WIFI_AC_MAX = 4, +}; + +#ifdef FEATURE_WLAN_TDLS +/* TDLS Request struct SME-->PE */ +typedef struct sSirTdlsSendMgmtReq { + uint16_t messageType; /* eWNI_SME_TDLS_DISCOVERY_START_REQ */ + uint16_t length; + uint8_t sessionId; /* Session ID */ + uint16_t transactionId; /* Transaction ID for cmd */ + uint8_t reqType; + uint8_t dialog; + uint16_t statusCode; + uint8_t responder; + uint32_t peerCapability; + /* For multi-session, for PE to locate peSession ID */ + struct qdf_mac_addr bssid; + struct qdf_mac_addr peer_mac; + enum sir_wifi_traffic_ac ac; + /* Variable length. Dont add any field after this. */ + uint8_t addIe[1]; +} tSirTdlsSendMgmtReq, *tpSirSmeTdlsSendMgmtReq; + +typedef enum TdlsAddOper { + TDLS_OPER_NONE, + TDLS_OPER_ADD, + TDLS_OPER_UPDATE +} eTdlsAddOper; + +/* TDLS Request struct SME-->PE */ +typedef struct sSirTdlsAddStaReq { + uint16_t messageType; /* eWNI_SME_TDLS_DISCOVERY_START_REQ */ + uint16_t length; + uint8_t sessionId; /* Session ID */ + uint16_t transactionId; /* Transaction ID for cmd */ + /* For multi-session, for PE to locate peSession ID */ + struct qdf_mac_addr bssid; + eTdlsAddOper tdlsAddOper; + struct qdf_mac_addr peermac; + uint16_t capability; + uint8_t extn_capability[SIR_MAC_MAX_EXTN_CAP]; + uint8_t supported_rates_length; + uint8_t supported_rates[SIR_MAC_MAX_SUPP_RATES]; + uint8_t htcap_present; + tSirHTCap htCap; + uint8_t vhtcap_present; + tSirVHTCap vhtCap; + uint8_t uapsd_queues; + uint8_t max_sp; +} tSirTdlsAddStaReq, *tpSirSmeTdlsAddStaReq; + +/* TDLS Response struct PE-->SME */ +typedef struct sSirTdlsAddStaRsp { + uint16_t messageType; + uint16_t length; + tSirResultCodes statusCode; + struct qdf_mac_addr peermac; + uint8_t sessionId; /* Session ID */ + uint16_t staId; + uint16_t staType; + uint8_t ucastSig; + uint8_t bcastSig; + eTdlsAddOper tdlsAddOper; +} tSirTdlsAddStaRsp; + +/* TDLS Request struct SME-->PE */ +typedef struct { + uint16_t messageType; /* eWNI_SME_TDLS_LINK_ESTABLISH_REQ */ + uint16_t length; + uint8_t sessionId; /* Session ID */ + uint16_t transactionId; /* Transaction ID for cmd */ + uint8_t uapsdQueues; /* Peer's uapsd Queues Information */ + uint8_t maxSp; /* Peer's Supported Maximum Service Period */ + uint8_t isBufSta; /* Does Peer Support as Buffer Station. */ + /* Does Peer Support as TDLS Off Channel. */ + uint8_t isOffChannelSupported; + uint8_t isResponder; /* Is Peer a responder. */ + /* For multi-session, for PE to locate peSession ID */ + struct qdf_mac_addr bssid; + struct qdf_mac_addr peermac; + uint8_t supportedChannelsLen; + uint8_t supportedChannels[SIR_MAC_MAX_SUPP_CHANNELS]; + uint8_t supportedOperClassesLen; + uint8_t supportedOperClasses[CDS_MAX_SUPP_OPER_CLASSES]; +} tSirTdlsLinkEstablishReq, *tpSirTdlsLinkEstablishReq; + +/* TDLS Request struct SME-->PE */ +typedef struct { + uint16_t messageType; /* eWNI_SME_TDLS_LINK_ESTABLISH_RSP */ + uint16_t length; + uint8_t sessionId; /* Session ID */ + uint16_t transactionId; /* Transaction ID for cmd */ + tSirResultCodes statusCode; + struct qdf_mac_addr peermac; +} tSirTdlsLinkEstablishReqRsp, *tpSirTdlsLinkEstablishReqRsp; + +/* TDLS Request struct SME-->PE */ +typedef struct sSirTdlsDelStaReq { + uint16_t messageType; /* eWNI_SME_TDLS_DISCOVERY_START_REQ */ + uint16_t length; + uint8_t sessionId; /* Session ID */ + uint16_t transactionId; /* Transaction ID for cmd */ + /* For multi-session, for PE to locate peSession ID */ + struct qdf_mac_addr bssid; + struct qdf_mac_addr peermac; +} tSirTdlsDelStaReq, *tpSirSmeTdlsDelStaReq; +/* TDLS Response struct PE-->SME */ +typedef struct sSirTdlsDelStaRsp { + uint16_t messageType; + uint16_t length; + uint8_t sessionId; /* Session ID */ + tSirResultCodes statusCode; + struct qdf_mac_addr peermac; + uint16_t staId; +} tSirTdlsDelStaRsp, *tpSirTdlsDelStaRsp; +/* TDLS Delete Indication struct PE-->SME */ +typedef struct sSirTdlsDelStaInd { + uint16_t messageType; + uint16_t length; + uint8_t sessionId; /* Session ID */ + struct qdf_mac_addr peermac; + uint16_t staId; + uint16_t reasonCode; +} tSirTdlsDelStaInd, *tpSirTdlsDelStaInd; +typedef struct sSirTdlsDelAllPeerInd { + uint16_t messageType; + uint16_t length; + uint8_t sessionId; /* Session ID */ +} tSirTdlsDelAllPeerInd, *tpSirTdlsDelAllPeerInd; +typedef struct sSirMgmtTxCompletionInd { + uint16_t messageType; + uint16_t length; + uint8_t sessionId; /* Session ID */ + uint32_t txCompleteStatus; +} tSirMgmtTxCompletionInd, *tpSirMgmtTxCompletionInd; + +typedef struct sSirTdlsEventnotify { + uint8_t sessionId; + struct qdf_mac_addr peermac; + uint16_t messageType; + uint32_t peer_reason; +} tSirTdlsEventnotify; +#endif /* FEATURE_WLAN_TDLS */ + +typedef struct sSirActiveModeSetBcnFilterReq { + uint16_t messageType; + uint16_t length; + uint8_t seesionId; + struct qdf_mac_addr bssid; +} tSirSetActiveModeSetBncFilterReq, *tpSirSetActiveModeSetBncFilterReq; + +/* Reset AP Caps Changed */ +typedef struct sSirResetAPCapsChange { + uint16_t messageType; + uint16_t length; + struct qdf_mac_addr bssId; +} tSirResetAPCapsChange, *tpSirResetAPCapsChange; + +/* / Definition for Candidate found indication from FW */ +typedef struct sSirSmeCandidateFoundInd { + uint16_t messageType; /* eWNI_SME_CANDIDATE_FOUND_IND */ + uint16_t length; + uint8_t sessionId; /* Session Identifier */ +} tSirSmeCandidateFoundInd, *tpSirSmeCandidateFoundInd; + +#ifdef WLAN_FEATURE_11W +typedef struct sSirWlanExcludeUnencryptParam { + bool excludeUnencrypt; + struct qdf_mac_addr bssid; +} tSirWlanExcludeUnencryptParam, *tpSirWlanExcludeUnencryptParam; +#endif + +typedef enum { + P2P_SCAN_TYPE_SEARCH = 1, /* P2P Search */ + P2P_SCAN_TYPE_LISTEN /* P2P Listen */ +} tSirP2pScanType; + +typedef struct sAniHandoffReq { + /* Common for all types are requests */ + uint16_t msgType; /* message type is same as the request type */ + uint16_t msgLen; /* length of the entire request */ + uint8_t sessionId; + uint8_t bssid[QDF_MAC_ADDR_SIZE]; + uint8_t channel; + uint8_t handoff_src; +} tAniHandoffReq, *tpAniHandoffReq; + +/* + * @scan_id: + * @scan_requestor_id: + * Scan id and scan requestor id are used by firmware to track each scan + * request. A new scan id is generated for each request. Requestor id + * shows the purpose of scan. + * + * @USER_SCAN_REQUESTOR_ID: Normal scan request from supplicant to HDD/SME. + * @ROC_SCAN_REQUESTOR_ID: Remain on channel usage for P2P action frames. + * @PREAUTH_REQUESTOR_ID: Used by LIM for preauth operation. + * + */ + +#define USER_SCAN_REQUESTOR_ID 0xA000 +#define ROC_SCAN_REQUESTOR_ID 0xB000 +#define PREAUTH_REQUESTOR_ID 0xC000 + +typedef struct sSirScanOffloadReq { + uint8_t sessionId; + struct qdf_mac_addr bssId; + uint8_t numSsid; + tSirMacSSid ssId[SIR_SCAN_MAX_NUM_SSID]; + uint8_t hiddenSsid; + struct qdf_mac_addr selfMacAddr; + tSirBssType bssType; + uint8_t dot11mode; + tSirScanType scanType; + uint32_t minChannelTime; + uint32_t maxChannelTime; + uint32_t scan_probe_repeat_time; + uint32_t scan_num_probes; + uint32_t scan_id; + uint32_t scan_requestor_id; + /* in units of milliseconds, ignored when not connected */ + uint32_t restTime; + /*in units of milliseconds, ignored when not connected*/ + uint32_t min_rest_time; + /*in units of milliseconds, ignored when not connected*/ + uint32_t idle_time; + tSirP2pScanType p2pScanType; + enum wmi_dwelltime_adaptive_mode scan_adaptive_dwell_mode; + uint16_t uIEFieldLen; + uint16_t uIEFieldOffset; + + uint32_t burst_scan_duration; + /* mac address randomization attributes */ + bool enable_scan_randomization; + uint8_t mac_addr[QDF_MAC_ADDR_SIZE]; + uint8_t mac_addr_mask[QDF_MAC_ADDR_SIZE]; + + tSirChannelList channelList; + /*----------------------------- + sSirScanOffloadReq.... + ----------------------------- + uIEFieldLen + ----------------------------- + uIEFieldOffset ----+ + ----------------------------- | + channelList.numChannels | + ----------------------------- | + ... variable size up to | + channelNumber[numChannels-1] | + This can be zero, if | + numChannel is zero. | + ----------------------------- <--+ + ... variable size uIEField + up to uIEFieldLen (can be 0) + -----------------------------*/ +} tSirScanOffloadReq, *tpSirScanOffloadReq; + +/** + * sir_scan_event_type - scan event types used in LIM + * @SIR_SCAN_EVENT_STARTED - scan command accepted by FW + * @SIR_SCAN_EVENT_COMPLETED - scan has been completed by FW + * @SIR_SCAN_EVENT_BSS_CHANNEL - FW is going to move to HOME channel + * @SIR_SCAN_EVENT_FOREIGN_CHANNEL - FW is going to move to FORIEGN channel + * @SIR_SCAN_EVENT_DEQUEUED - scan request got dequeued + * @SIR_SCAN_EVENT_PREEMPTED - preempted by other high priority scan + * @SIR_SCAN_EVENT_START_FAILED - scan start failed + * @SIR_SCAN_EVENT_RESTARTED - scan restarted + * @SIR_SCAN_EVENT_MAX - max value for event type +*/ +enum sir_scan_event_type { + SIR_SCAN_EVENT_STARTED = 0x1, + SIR_SCAN_EVENT_COMPLETED = 0x2, + SIR_SCAN_EVENT_BSS_CHANNEL = 0x4, + SIR_SCAN_EVENT_FOREIGN_CHANNEL = 0x8, + SIR_SCAN_EVENT_DEQUEUED = 0x10, + SIR_SCAN_EVENT_PREEMPTED = 0x20, + SIR_SCAN_EVENT_START_FAILED = 0x40, + SIR_SCAN_EVENT_RESTARTED = 0x80, + SIR_SCAN_EVENT_MAX = 0x8000 +}; + +typedef struct sSirScanOffloadEvent { + enum sir_scan_event_type event; + tSirResultCodes reasonCode; + uint32_t chanFreq; + uint32_t requestor; + uint32_t scanId; + tSirP2pScanType p2pScanType; + uint8_t sessionId; +} tSirScanOffloadEvent, *tpSirScanOffloadEvent; + +/** + * struct sSirUpdateChanParam - channel parameters + * @chanId: ID of the channel + * @pwr: power level + * @dfsSet: is dfs supported or not + * @half_rate: is the channel operating at 10MHz + * @quarter_rate: is the channel operating at 5MHz + */ +typedef struct sSirUpdateChanParam { + uint8_t chanId; + uint8_t pwr; + bool dfsSet; + bool half_rate; + bool quarter_rate; +} tSirUpdateChanParam, *tpSirUpdateChanParam; + +typedef struct sSirUpdateChan { + uint8_t numChan; + uint8_t ht_en; + uint8_t vht_en; + uint8_t vht_24_en; + tSirUpdateChanParam chanParam[1]; +} tSirUpdateChanList, *tpSirUpdateChanList; + +typedef enum eSirAddonPsReq { + eSIR_ADDON_NOTHING, + eSIR_ADDON_ENABLE_UAPSD, + eSIR_ADDON_DISABLE_UAPSD +} tSirAddonPsReq; + +#ifdef FEATURE_WLAN_LPHB +#define SIR_LPHB_FILTER_LEN 64 + +typedef enum { + LPHB_SET_EN_PARAMS_INDID, + LPHB_SET_TCP_PARAMS_INDID, + LPHB_SET_TCP_PKT_FILTER_INDID, + LPHB_SET_UDP_PARAMS_INDID, + LPHB_SET_UDP_PKT_FILTER_INDID, + LPHB_SET_NETWORK_INFO_INDID, +} LPHBIndType; + +typedef struct sSirLPHBEnableStruct { + uint8_t enable; + uint8_t item; + uint8_t session; +} tSirLPHBEnableStruct; + +typedef struct sSirLPHBTcpParamStruct { + uint32_t srv_ip; + uint32_t dev_ip; + uint16_t src_port; + uint16_t dst_port; + uint16_t timeout; + uint8_t session; + struct qdf_mac_addr gateway_mac; + uint16_t timePeriodSec; /* in seconds */ + uint32_t tcpSn; +} tSirLPHBTcpParamStruct; + +typedef struct sSirLPHBTcpFilterStruct { + uint16_t length; + uint8_t offset; + uint8_t session; + uint8_t filter[SIR_LPHB_FILTER_LEN]; +} tSirLPHBTcpFilterStruct; + +typedef struct sSirLPHBUdpParamStruct { + uint32_t srv_ip; + uint32_t dev_ip; + uint16_t src_port; + uint16_t dst_port; + uint16_t interval; + uint16_t timeout; + uint8_t session; + struct qdf_mac_addr gateway_mac; +} tSirLPHBUdpParamStruct; + +typedef struct sSirLPHBUdpFilterStruct { + uint16_t length; + uint8_t offset; + uint8_t session; + uint8_t filter[SIR_LPHB_FILTER_LEN]; +} tSirLPHBUdpFilterStruct; + +typedef struct sSirLPHBReq { + uint16_t cmd; + uint16_t dummy; + union { + tSirLPHBEnableStruct lphbEnableReq; + tSirLPHBTcpParamStruct lphbTcpParamReq; + tSirLPHBTcpFilterStruct lphbTcpFilterReq; + tSirLPHBUdpParamStruct lphbUdpParamReq; + tSirLPHBUdpFilterStruct lphbUdpFilterReq; + } params; +} tSirLPHBReq; + +typedef struct sSirLPHBInd { + uint8_t sessionIdx; + uint8_t protocolType; /*TCP or UDP */ + uint8_t eventReason; +} tSirLPHBInd; +#endif /* FEATURE_WLAN_LPHB */ + +#ifdef FEATURE_WLAN_CH_AVOID +typedef struct sSirChAvoidUpdateReq { + uint32_t reserved_param; +} tSirChAvoidUpdateReq; +#endif /* FEATURE_WLAN_CH_AVOID */ + +typedef struct sSirLinkSpeedInfo { + /* MAC Address for the peer */ + struct qdf_mac_addr peer_macaddr; + uint32_t estLinkSpeed; /* Linkspeed from firmware */ +} tSirLinkSpeedInfo, *tpSirLinkSpeedInfo; + +typedef struct sSirAddPeriodicTxPtrn { + /* MAC Address for the adapter */ + struct qdf_mac_addr mac_address; + uint8_t ucPtrnId; /* Pattern ID */ + uint16_t ucPtrnSize; /* Pattern size */ + uint32_t usPtrnIntervalMs; /* In msec */ + uint8_t ucPattern[PERIODIC_TX_PTRN_MAX_SIZE]; /* Pattern buffer */ +} tSirAddPeriodicTxPtrn, *tpSirAddPeriodicTxPtrn; + +typedef struct sSirDelPeriodicTxPtrn { + /* MAC Address for the adapter */ + struct qdf_mac_addr mac_address; + /* Bitmap of pattern IDs that need to be deleted */ + uint32_t ucPatternIdBitmap; + uint8_t ucPtrnId; /* Pattern ID */ +} tSirDelPeriodicTxPtrn, *tpSirDelPeriodicTxPtrn; + +/*--------------------------------------------------------------------------- +* tSirIbssGetPeerInfoReqParams +*--------------------------------------------------------------------------*/ +typedef struct { + bool allPeerInfoReqd; /* If set, all IBSS peers stats are reported */ + uint8_t staIdx; /* If allPeerInfoReqd is not set, only stats */ + /* of peer with staIdx is reported */ +} tSirIbssGetPeerInfoReqParams, *tpSirIbssGetPeerInfoReqParams; + +/** + * typedef struct - tSirIbssGetPeerInfoParams + * @mac_addr: mac address received from target + * @txRate: TX rate + * @mcsIndex: MCS index + * @txRateFlags: TX rate flags + * @rssi: RSSI + */ +typedef struct { + uint8_t mac_addr[QDF_MAC_ADDR_SIZE]; + uint32_t txRate; + uint32_t mcsIndex; + uint32_t txRateFlags; + int8_t rssi; +} tSirIbssPeerInfoParams; + +typedef struct { + uint32_t status; + uint8_t numPeers; + tSirIbssPeerInfoParams peerInfoParams[32]; +} tSirPeerInfoRspParams, *tpSirIbssPeerInfoRspParams; + +/*--------------------------------------------------------------------------- +* tSirIbssGetPeerInfoRspParams +*--------------------------------------------------------------------------*/ +typedef struct { + uint16_t mesgType; + uint16_t mesgLen; + tSirPeerInfoRspParams ibssPeerInfoRspParams; +} tSirIbssGetPeerInfoRspParams, *tpSirIbssGetPeerInfoRspParams; + +typedef struct { + uint16_t mesgType; + uint16_t mesgLen; + bool suspended; +} tSirReadyToSuspendInd, *tpSirReadyToSuspendInd; +#ifdef WLAN_FEATURE_EXTWOW_SUPPORT +typedef struct { + uint16_t mesgType; + uint16_t mesgLen; + bool status; +} tSirReadyToExtWoWInd, *tpSirReadyToExtWoWInd; +#endif +typedef struct sSirRateUpdateInd { + uint8_t nss; /* 0: 1x1, 1: 2x2 */ + struct qdf_mac_addr bssid; + enum tQDF_ADAPTER_MODE dev_mode; + int32_t bcastDataRate; /* bcast rate unit Mbpsx10, -1:not used */ + /* + * 0 implies RA, positive value implies fixed rate, -1 implies ignore + * this param. + */ + int32_t ucastDataRate; + + /* TX flag to differentiate between HT20, HT40 etc */ + tTxrateinfoflags ucastDataRateTxFlag; + + /* + * 0 implies MCAST RA, positive value implies fixed rate, + * -1 implies ignore this param + */ + int32_t reliableMcastDataRate; /* unit Mbpsx10 */ + + /* TX flag to differentiate between HT20, HT40 etc */ + tTxrateinfoflags reliableMcastDataRateTxFlag; + + /* + * MCAST(or BCAST) fixed data rate in 2.4 GHz, unit Mbpsx10, + * 0 implies ignore + */ + uint32_t mcastDataRate24GHz; + + /* TX flag to differentiate between HT20, HT40 etc */ + tTxrateinfoflags mcastDataRate24GHzTxFlag; + + /* + * MCAST(or BCAST) fixed data rate in 5 GHz, + * unit Mbpsx10, 0 implies ignore + */ + uint32_t mcastDataRate5GHz; + + /* TX flag to differentiate between HT20, HT40 etc */ + tTxrateinfoflags mcastDataRate5GHzTxFlag; + +} tSirRateUpdateInd, *tpSirRateUpdateInd; + +#if defined(FEATURE_WLAN_CH_AVOID) || defined(FEATURE_WLAN_FORCE_SAP_SCC) +#define SIR_CH_AVOID_MAX_RANGE 4 + +typedef struct sSirChAvoidFreqType { + uint32_t start_freq; + uint32_t end_freq; +} tSirChAvoidFreqType; + +typedef struct sSirChAvoidIndType { + uint32_t avoid_range_count; + tSirChAvoidFreqType avoid_freq_range[SIR_CH_AVOID_MAX_RANGE]; +} tSirChAvoidIndType; +#endif /* FEATURE_WLAN_CH_AVOID || FEATURE_WLAN_FORCE_SAP_SCC */ + +#define SIR_DFS_MAX_20M_SUB_CH 8 +#define SIR_80MHZ_START_CENTER_CH_DIFF 6 + +typedef struct sSirSmeDfsChannelList { + uint32_t nchannels; + /* Ch num including bonded channels on which the RADAR is present */ + uint8_t channels[SIR_DFS_MAX_20M_SUB_CH]; +} tSirSmeDfsChannelList, *tpSirSmeDfsChannelList; + +typedef struct sSirSmeDfsEventInd { + uint32_t sessionId; + tSirSmeDfsChannelList chan_list; + uint32_t dfs_radar_status; + int use_nol; +} tSirSmeDfsEventInd, *tpSirSmeDfsEventInd; + +typedef struct sSirChanChangeRequest { + uint16_t messageType; + uint16_t messageLen; + uint8_t targetChannel; + uint8_t sec_ch_offset; + enum phy_ch_width ch_width; + uint8_t center_freq_seg_0; + uint8_t center_freq_seg_1; + uint8_t bssid[QDF_MAC_ADDR_SIZE]; + uint32_t dot11mode; + tSirMacRateSet operational_rateset; + tSirMacRateSet extended_rateset; +} tSirChanChangeRequest, *tpSirChanChangeRequest; + +typedef struct sSirChanChangeResponse { + uint8_t sessionId; + uint8_t newChannelNumber; + uint8_t channelChangeStatus; + ePhyChanBondState secondaryChannelOffset; +} tSirChanChangeResponse, *tpSirChanChangeResponse; + +typedef struct sSirStartBeaconIndication { + uint16_t messageType; + uint16_t messageLen; + uint8_t beaconStartStatus; + uint8_t bssid[QDF_MAC_ADDR_SIZE]; +} tSirStartBeaconIndication, *tpSirStartBeaconIndication; + +/* additional IE type */ +typedef enum tUpdateIEsType { + eUPDATE_IE_NONE, + eUPDATE_IE_PROBE_BCN, + eUPDATE_IE_PROBE_RESP, + eUPDATE_IE_ASSOC_RESP, + + /* Add type above this line */ + /* this is used to reset all buffer */ + eUPDATE_IE_ALL, + eUPDATE_IE_MAX +} eUpdateIEsType; + +/* Modify particular IE in addition IE for prob resp Bcn */ +typedef struct sSirModifyIE { + struct qdf_mac_addr bssid; + uint16_t smeSessionId; + bool notify; + uint8_t ieID; + uint8_t ieIDLen; /*ie length as per spec */ + uint16_t ieBufferlength; + uint8_t *pIEBuffer; + int32_t oui_length; + +} tSirModifyIE, *tpSirModifyIE; + +/* Message format for Update IE message sent to PE */ +typedef struct sSirModifyIEsInd { + uint16_t msgType; + uint16_t msgLen; + tSirModifyIE modifyIE; + eUpdateIEsType updateType; +} tSirModifyIEsInd, *tpSirModifyIEsInd; + +/* Message format for Update IE message sent to PE */ +typedef struct sSirUpdateIE { + struct qdf_mac_addr bssid; + uint16_t smeSessionId; + bool append; + bool notify; + uint16_t ieBufferlength; + uint8_t *pAdditionIEBuffer; +} tSirUpdateIE, *tpSirUpdateIE; + +/* Message format for Update IE message sent to PE */ +typedef struct sSirUpdateIEsInd { + uint16_t msgType; + uint16_t msgLen; + tSirUpdateIE updateIE; + eUpdateIEsType updateType; +} tSirUpdateIEsInd, *tpSirUpdateIEsInd; + +/* Message format for requesting channel switch announcement to lower layers */ +typedef struct sSirDfsCsaIeRequest { + uint16_t msgType; + uint16_t msgLen; + uint8_t targetChannel; + uint8_t csaIeRequired; + uint8_t bssid[QDF_MAC_ADDR_SIZE]; + struct ch_params_s ch_params; +} tSirDfsCsaIeRequest, *tpSirDfsCsaIeRequest; + +/* Indication from lower layer indicating the completion of first beacon send + * after the beacon template update + */ +typedef struct sSirFirstBeaconTxCompleteInd { + uint16_t messageType; /* eWNI_SME_MISSED_BEACON_IND */ + uint16_t length; + uint8_t bssIdx; +} tSirFirstBeaconTxCompleteInd, *tpSirFirstBeaconTxCompleteInd; + +typedef struct sSirSmeCSAIeTxCompleteRsp { + uint8_t sessionId; + uint8_t chanSwIeTxStatus; +} tSirSmeCSAIeTxCompleteRsp, *tpSirSmeCSAIeTxCompleteRsp; + +/* Thermal Mitigation*/ + +typedef struct { + uint16_t minTempThreshold; + uint16_t maxTempThreshold; +} t_thermal_level_info, *tp_thermal_level_info; + +typedef enum { + WLAN_WMA_THERMAL_LEVEL_0, + WLAN_WMA_THERMAL_LEVEL_1, + WLAN_WMA_THERMAL_LEVEL_2, + WLAN_WMA_THERMAL_LEVEL_3, + WLAN_WMA_MAX_THERMAL_LEVELS +} t_thermal_level; + +#define WLAN_THROTTLE_DUTY_CYCLE_LEVEL_MAX (4) + +typedef struct { + /* Array of thermal levels */ + t_thermal_level_info thermalLevels[WLAN_WMA_MAX_THERMAL_LEVELS]; + uint8_t thermalCurrLevel; + uint8_t thermalMgmtEnabled; + uint32_t throttlePeriod; + uint8_t throttle_duty_cycle_tbl[WLAN_THROTTLE_DUTY_CYCLE_LEVEL_MAX]; +} t_thermal_mgmt, *tp_thermal_mgmt; + +typedef struct sSirTxPowerLimit { + /* Thermal limits for 2g and 5g */ + uint32_t txPower2g; + uint32_t txPower5g; +} tSirTxPowerLimit; + +enum bad_peer_thresh_levels { + WLAN_WMA_IEEE80211_B_LEVEL = 0, + WLAN_WMA_IEEE80211_AG_LEVEL, + WLAN_WMA_IEEE80211_N_LEVEL, + WLAN_WMA_IEEE80211_AC_LEVEL, + WLAN_WMA_IEEE80211_AX_LEVEL, + WLAN_WMA_IEEE80211_MAX_LEVEL, +}; + +#define NUM_OF_RATE_THRESH_MAX (4) +struct t_bad_peer_info { + uint32_t cond; + uint32_t delta; + uint32_t percentage; + uint32_t thresh[NUM_OF_RATE_THRESH_MAX]; + uint32_t txlimit; +}; + +struct t_bad_peer_txtcl_config { + /* Array of thermal levels */ + struct t_bad_peer_info threshold[WLAN_WMA_IEEE80211_MAX_LEVEL]; + uint32_t enable; + uint32_t period; + uint32_t txq_limit; + uint32_t tgt_backoff; + uint32_t tgt_report_prd; +}; + +/* notify MODEM power state to FW */ +typedef struct { + uint32_t param; +} tSirModemPowerStateInd, *tpSirModemPowerStateInd; + +#ifdef WLAN_FEATURE_STATS_EXT +typedef struct { + uint32_t vdev_id; + uint32_t event_data_len; + uint8_t event_data[]; +} tSirStatsExtEvent, *tpSirStatsExtEvent; +#endif + +typedef struct { + uint32_t event_data_len; + uint8_t event_data[]; +} tSirNanEvent, *tpSirNanEvent; + +typedef struct sSirSmeRoamOffloadSynchInd { + uint16_t messageType; /*eWNI_SME_ROAM_OFFLOAD_SYNCH_IND */ + uint16_t length; + uint16_t beaconProbeRespOffset; + uint16_t beaconProbeRespLength; + uint16_t reassocRespOffset; + uint16_t reassocRespLength; + uint16_t reassoc_req_offset; + uint16_t reassoc_req_length; + uint8_t isBeacon; + uint8_t roamedVdevId; + struct qdf_mac_addr bssid; + struct qdf_mac_addr self_mac; + int8_t txMgmtPower; + uint32_t authStatus; + uint8_t rssi; + uint8_t roamReason; + uint32_t chan_freq; + uint8_t kck[SIR_KCK_KEY_LEN]; + uint8_t kek[SIR_KEK_KEY_LEN]; + uint8_t replay_ctr[SIR_REPLAY_CTR_LEN]; + void *add_bss_params; + tpSirSmeJoinRsp join_rsp; + uint16_t aid; + struct sir_hw_mode_trans_ind hw_mode_trans_ind; + uint8_t nss; +} roam_offload_synch_ind; + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +typedef struct sSirSmeRoamOffloadSynchCnf { + uint8_t sessionId; +} tSirSmeRoamOffloadSynchCnf, *tpSirSmeRoamOffloadSynchCnf; + +typedef struct sSirSmeHOFailureInd { + uint8_t sessionId; +} tSirSmeHOFailureInd, *tpSirSmeHOFailureInd; + +struct roam_offload_synch_fail { + uint8_t session_id; +}; + +#endif + +#ifdef FEATURE_WLAN_EXTSCAN + +/** + * typedef enum wifi_scan_flags - wifi scan flags + * @WIFI_SCAN_FLAG_INTERRUPTED: Indicates that scan results are not complete + * because probes were not sent on some channels + */ +typedef enum { + WIFI_SCAN_FLAG_INTERRUPTED = 1, +} wifi_scan_flags; + +typedef enum { + WIFI_BAND_UNSPECIFIED, + WIFI_BAND_BG = 1, /* 2.4 GHz */ + WIFI_BAND_A = 2, /* 5 GHz without DFS */ + WIFI_BAND_ABG = 3, /* 2.4 GHz + 5 GHz; no DFS */ + WIFI_BAND_A_DFS_ONLY = 4, /* 5 GHz DFS only */ + /* 5 is reserved */ + WIFI_BAND_A_WITH_DFS = 6, /* 5 GHz with DFS */ + WIFI_BAND_ABG_WITH_DFS = 7, /* 2.4 GHz + 5 GHz with DFS */ + + /* Keep it last */ + WIFI_BAND_MAX +} tWifiBand; + +/** + * enum wifi_extscan_event_type - extscan event type + * @WIFI_EXTSCAN_RESULTS_AVAILABLE: reported when REPORT_EVENTS_EACH_SCAN is set + * and a scan cycle completes. WIFI_SCAN_THRESHOLD_NUM_SCANS or + * WIFI_SCAN_THRESHOLD_PERCENT can be reported instead if the + * reason for the event is available; however, at most one of + * these events should be reported per scan. + * @WIFI_EXTSCAN_THRESHOLD_NUM_SCANS: can be reported when + * REPORT_EVENTS_EACH_SCAN is not set and + * report_threshold_num_scans is reached. + * @WIFI_EXTSCAN_THRESHOLD_PERCENT: can be reported when REPORT_EVENTS_EACH_SCAN + * is not set and report_threshold_percent is reached. + * @WIFI_SCAN_DISABLED: reported when currently executing gscans are disabled + * start_gscan will need to be called again in order to continue + * scanning. + * @WIFI_EXTSCAN_BUCKET_STARTED_EVENT: Bucket started event + * This event is consumed in driver only. + * @WIFI_EXTSCAN_CYCLE_STARTED_EVENT: Cycle started event. + * This event is consumed in driver only. + * @WIFI_EXTSCAN_CYCLE_COMPLETED_EVENT: Cycle complete event. This event + * triggers @WIFI_EXTSCAN_RESULTS_AVAILABLE to the user space. + */ +enum wifi_extscan_event_type { + WIFI_EXTSCAN_RESULTS_AVAILABLE, + WIFI_EXTSCAN_THRESHOLD_NUM_SCANS, + WIFI_EXTSCAN_THRESHOLD_PERCENT, + WIFI_SCAN_DISABLED, + + WIFI_EXTSCAN_BUCKET_STARTED_EVENT = 0x10, + WIFI_EXTSCAN_CYCLE_STARTED_EVENT, + WIFI_EXTSCAN_CYCLE_COMPLETED_EVENT, +}; + +/** + * enum extscan_configuration_flags - extscan config flags + * @EXTSCAN_LP_EXTENDED_BATCHING: extended batching + */ +enum extscan_configuration_flags { + EXTSCAN_LP_EXTENDED_BATCHING = 0x00000001, +}; + +typedef struct { + struct qdf_mac_addr bssid; + + /* Low threshold */ + int32_t low; + + /* High threshold */ + int32_t high; +} tSirAPThresholdParam, *tpSirAPThresholdParam; + +typedef struct { + uint32_t requestId; + uint8_t sessionId; +} tSirGetExtScanCapabilitiesReqParams, *tpSirGetExtScanCapabilitiesReqParams; + +/** + * struct ext_scan_capabilities_response - extscan capabilities response data + * @requestId: request identifier + * @status: status + * @max_scan_cache_size: total space allocated for scan (in bytes) + * @max_scan_buckets: maximum number of channel buckets + * @max_ap_cache_per_scan: maximum number of APs that can be stored per scan + * @max_rssi_sample_size: number of RSSI samples used for averaging RSSI + * @ax_scan_reporting_threshold: max possible report_threshold + * @max_hotlist_bssids: maximum number of entries for hotlist APs + * @max_significant_wifi_change_aps: maximum number of entries for + * significant wifi change APs + * @max_bssid_history_entries: number of BSSID/RSSI entries that device can hold + * @max_hotlist_ssids: maximum number of entries for hotlist SSIDs + * @max_number_epno_networks: max number of epno entries + * @max_number_epno_networks_by_ssid: max number of epno entries + * if ssid is specified, that is, epno entries for + * which an exact match is required, + * or entries corresponding to hidden ssids + * @max_number_of_white_listed_ssid: max number of white listed SSIDs + * @max_number_of_black_listed_bssid: max number of black listed BSSIDs + */ +struct ext_scan_capabilities_response { + uint32_t requestId; + uint32_t status; + + uint32_t max_scan_cache_size; + uint32_t max_scan_buckets; + uint32_t max_ap_cache_per_scan; + uint32_t max_rssi_sample_size; + uint32_t max_scan_reporting_threshold; + + uint32_t max_hotlist_bssids; + uint32_t max_significant_wifi_change_aps; + + uint32_t max_bssid_history_entries; + uint32_t max_hotlist_ssids; + uint32_t max_number_epno_networks; + uint32_t max_number_epno_networks_by_ssid; + uint32_t max_number_of_white_listed_ssid; + uint32_t max_number_of_black_listed_bssid; +}; + +typedef struct { + uint32_t requestId; + uint8_t sessionId; + + /* + * 1 - return cached results and flush it + * 0 - return cached results and do not flush + */ + bool flush; +} tSirExtScanGetCachedResultsReqParams, *tpSirExtScanGetCachedResultsReqParams; + +typedef struct { + uint32_t requestId; + uint32_t status; +} tSirExtScanGetCachedResultsRspParams, *tpSirExtScanGetCachedResultsRspParams; + +typedef struct { + /* Time of discovery */ + uint64_t ts; + + /* Null terminated SSID */ + uint8_t ssid[SIR_MAC_MAX_SSID_LENGTH + 1]; + + struct qdf_mac_addr bssid; + + /* Frequency in MHz */ + uint32_t channel; + + /* RSSI in dBm */ + int32_t rssi; + + /* RTT in nanoseconds */ + uint32_t rtt; + + /* Standard deviation in rtt */ + uint32_t rtt_sd; + + /* Period advertised in the beacon */ + uint16_t beaconPeriod; + + /* Capabilities advertised in the beacon */ + uint16_t capability; + + uint16_t ieLength; + + uint8_t ieData[]; +} tSirWifiScanResult, *tpSirWifiScanResult; + +/** + * struct extscan_hotlist_match - extscan hotlist match + * @requestId: request identifier + * @numOfAps: number of bssids retrieved by the scan + * @moreData: 0 - for last fragment + * 1 - still more fragment(s) coming + * @ap: wifi scan result + */ +struct extscan_hotlist_match { + uint32_t requestId; + bool moreData; + bool ap_found; + uint32_t numOfAps; + tSirWifiScanResult ap[]; +}; + +/** + * struct extscan_cached_scan_result - extscan cached scan result + * @scan_id: a unique identifier for the scan unit + * @flags: a bitmask with additional information about scan + * @num_results: number of bssids retrieved by the scan + * @buckets_scanned: bitmask of buckets scanned in current extscan cycle + * @ap: wifi scan bssid results info + */ +struct extscan_cached_scan_result { + uint32_t scan_id; + uint32_t flags; + uint32_t num_results; + uint32_t buckets_scanned; + tSirWifiScanResult *ap; +}; + +/** + * struct tSirWifiScanResultEvent - wifi scan result event + * @requestId: request identifier + * @ap_found: flag to indicate ap found or not + * true: AP was found + * false: AP was lost + * @numOfAps: number of aps + * @moreData: more data + * @ap: bssid information + * + */ +typedef struct { + uint32_t requestId; + bool ap_found; + uint32_t numOfAps; + bool moreData; + tSirWifiScanResult ap[]; +} tSirWifiScanResultEvent, *tpSirWifiScanResultEvent; + +/** + * struct extscan_cached_scan_results - extscan cached scan results + * @request_id: request identifier + * @more_data: 0 - for last fragment + * 1 - still more fragment(s) coming + * @num_scan_ids: number of scan ids + * @result: wifi scan result + */ +struct extscan_cached_scan_results { + uint32_t request_id; + bool more_data; + uint32_t num_scan_ids; + struct extscan_cached_scan_result *result; +}; + + +/** + * struct tSirWifiFullScanResultEvent - extscan full scan event + * @request_id: request identifier + * @moreData: 0 - for last fragment + * 1 - still more fragment(s) coming + * @ap: bssid info + * + * Reported when each probe response is received, if reportEvents + * enabled in tSirWifiScanCmdReqParams + */ +typedef struct { + uint32_t requestId; + bool moreData; + tSirWifiScanResult ap; +} tSirWifiFullScanResultEvent, *tpSirWifiFullScanResultEvent; + +/** + * struct pno_match_found - epno match found + * @request_id: request identifier + * @moreData: 0 - for last fragment + * 1 - still more fragment(s) coming + * @num_results: number of bssids, driver sends this event to upper layer + * for every beacon, hence %num_results is always set to 1. + * @ap: bssid info + * + * Reported when each beacon probe response is received with + * epno match found tag. + */ +struct pno_match_found { + uint32_t request_id; + bool more_data; + uint32_t num_results; + tSirWifiScanResult ap[]; +}; + +typedef struct { + /* Frequency in MHz */ + uint32_t channel; + + uint32_t dwellTimeMs; + + /* 0 => active + 1 => passive scan; ignored for DFS */ + bool passive; + + uint8_t chnlClass; +} tSirWifiScanChannelSpec, *tpSirWifiScanChannelSpec; + +/** + * struct tSirWifiScanBucketSpec - wifi scan bucket spec + * @bucket: bucket identifier + * @band: wifi band + * @period: Desired period, in millisecond; if this is too + * low, the firmware should choose to generate results as fast as + * it can instead of failing the command byte + * for exponential backoff bucket this is the min_period + * @reportEvents: 0 => normal reporting (reporting rssi history + * only, when rssi history buffer is % full) + * 1 => same as 0 + report a scan completion event after scanning + * this bucket + * 2 => same as 1 + forward scan results + * (beacons/probe responses + IEs) in real time to HAL + * @max_period: if max_period is non zero or different than period, + * then this bucket is an exponential backoff bucket and + * the scan period will grow exponentially as per formula: + * actual_period(N) = period ^ (N/(step_count+1)) to a + * maximum period of max_period + * @exponent: for exponential back off bucket: multiplier: + * new_period = old_period * exponent + * @step_count: for exponential back off bucket, number of scans performed + * at a given period and until the exponent is applied + * @numChannels: channels to scan; these may include DFS channels + * Note that a given channel may appear in multiple buckets + * @min_dwell_time_active: per bucket minimum active dwell time + * @max_dwell_time_active: per bucket maximum active dwell time + * @min_dwell_time_passive: per bucket minimum passive dwell time + * @max_dwell_time_passive: per bucket maximum passive dwell time + * @channels: Channel list + */ +typedef struct { + uint8_t bucket; + tWifiBand band; + uint32_t period; + uint32_t reportEvents; + uint32_t max_period; + uint32_t exponent; + uint32_t step_count; + uint32_t numChannels; + + uint32_t min_dwell_time_active; + uint32_t max_dwell_time_active; + uint32_t min_dwell_time_passive; + uint32_t max_dwell_time_passive; + tSirWifiScanChannelSpec channels[WLAN_EXTSCAN_MAX_CHANNELS]; +} tSirWifiScanBucketSpec, *tpSirWifiScanBucketSpec; + +/** + * struct tSirWifiScanCmdReqParams - wifi scan command request params + * @basePeriod: base timer period + * @maxAPperScan: max ap per scan + * @report_threshold_percent: report threshold + * in %, when buffer is this much full, wake up host + * @report_threshold_num_scans: report threshold number of scans + * in number of scans, wake up host after these many scans + * @requestId: request id + * @sessionId: session id + * @numBuckets: number of buckets + * @min_dwell_time_active: per bucket minimum active dwell time + * @max_dwell_time_active: per bucket maximum active dwell time + * @min_dwell_time_passive: per bucket minimum passive dwell time + * @max_dwell_time_passive: per bucket maximum passive dwell time + * @configuration_flags: configuration flags + * @buckets: buckets array + */ +typedef struct { + uint32_t basePeriod; + uint32_t maxAPperScan; + + uint32_t report_threshold_percent; + uint32_t report_threshold_num_scans; + + uint32_t requestId; + uint8_t sessionId; + uint32_t numBuckets; + + uint32_t min_dwell_time_active; + uint32_t max_dwell_time_active; + uint32_t min_dwell_time_passive; + uint32_t max_dwell_time_passive; + uint32_t configuration_flags; + enum wmi_dwelltime_adaptive_mode extscan_adaptive_dwell_mode; + tSirWifiScanBucketSpec buckets[WLAN_EXTSCAN_MAX_BUCKETS]; +} tSirWifiScanCmdReqParams, *tpSirWifiScanCmdReqParams; + +/** + * struct sir_extscan_generic_response - + * Generic ExtScan Response structure + * @request_id: ID of the request + * @status: operation status returned by firmware + */ +struct sir_extscan_generic_response { + uint32_t request_id; + uint32_t status; +}; + +typedef struct { + uint32_t requestId; + uint8_t sessionId; +} tSirExtScanStopReqParams, *tpSirExtScanStopReqParams; + +/** + * struct tSirExtScanSetBssidHotListReqParams - set hotlist request + * @requestId: request identifier + * @sessionId: session identifier + * @lost_ap_sample_size: number of samples to confirm AP loss + * @numAp: Number of hotlist APs + * @ap: hotlist APs + */ +typedef struct { + uint32_t requestId; + uint8_t sessionId; + + uint32_t lost_ap_sample_size; + uint32_t numAp; + tSirAPThresholdParam ap[WLAN_EXTSCAN_MAX_HOTLIST_APS]; +} tSirExtScanSetBssidHotListReqParams, *tpSirExtScanSetBssidHotListReqParams; + +typedef struct { + uint32_t requestId; + uint8_t sessionId; +} tSirExtScanResetBssidHotlistReqParams, +*tpSirExtScanResetBssidHotlistReqParams; + +/** + * struct sir_wisa_params - WISA Mode Parameters + * @mode: WISA mode + * @session_id: Session ID of vdev + */ +struct sir_wisa_params { + bool mode; + uint8_t vdev_id; +}; + +typedef struct { + uint32_t requestId; + uint8_t sessionId; + + /* Number of samples for averaging RSSI */ + uint32_t rssiSampleSize; + + /* Number of missed samples to confirm AP loss */ + uint32_t lostApSampleSize; + + /* Number of APs breaching threshold required for firmware + * to generate event + */ + uint32_t minBreaching; + + uint32_t numAp; + tSirAPThresholdParam ap[WLAN_EXTSCAN_MAX_SIGNIFICANT_CHANGE_APS]; +} tSirExtScanSetSigChangeReqParams, *tpSirExtScanSetSigChangeReqParams; + +typedef struct { + struct qdf_mac_addr bssid; + uint32_t channel; + uint32_t numOfRssi; + + /* Rssi history in db */ + int32_t rssi[]; +} tSirWifiSignificantChange, *tpSirWifiSignificantChange; + +typedef struct { + uint32_t requestId; + + bool moreData; + uint32_t numResults; + tSirWifiSignificantChange ap[]; +} tSirWifiSignificantChangeEvent, *tpSirWifiSignificantChangeEvent; + +typedef struct { + uint32_t requestId; + uint8_t sessionId; +} tSirExtScanResetSignificantChangeReqParams, +*tpSirExtScanResetSignificantChangeReqParams; + +typedef struct { + uint32_t requestId; + uint32_t numResultsAvailable; +} tSirExtScanResultsAvailableIndParams, *tpSirExtScanResultsAvailableIndParams; + +typedef struct { + uint32_t requestId; + uint32_t status; + uint8_t scanEventType; + uint32_t buckets_scanned; +} tSirExtScanOnScanEventIndParams, *tpSirExtScanOnScanEventIndParams; + +#define MAX_EPNO_NETWORKS 64 + +/** + * struct wifi_epno_network - enhanced pno network block + * @ssid: ssid + * @flags: WIFI_PNO_FLAG_XXX + * @auth_bit_field: auth bit field for matching WPA IE + */ +struct wifi_epno_network { + tSirMacSSid ssid; + uint8_t flags; + uint8_t auth_bit_field; +}; + +/** + * struct wifi_epno_params - enhanced pno network params + * @request_id: request id number + * @session_id: session_id number + * @min_5ghz_rssi: minimum 5GHz RSSI for a BSSID to be considered + * @min_24ghz_rssi: minimum 2.4GHz RSSI for a BSSID to be considered + * @initial_score_max: maximum score that a network can have before bonuses + * @current_connection_bonus: only report when there is a network's score this + * much higher than the current connection + * @same_network_bonus: score bonus for all n/w with the same network flag + * @secure_bonus: score bonus for networks that are not open + * @band_5ghz_bonus: 5GHz RSSI score bonus (applied to all 5GHz networks) + * @num_networks: number of ssids + * @networks: EPNO networks + */ +struct wifi_epno_params { + uint32_t request_id; + uint32_t session_id; + uint32_t min_5ghz_rssi; + uint32_t min_24ghz_rssi; + uint32_t initial_score_max; + uint32_t current_connection_bonus; + uint32_t same_network_bonus; + uint32_t secure_bonus; + uint32_t band_5ghz_bonus; + uint32_t num_networks; + struct wifi_epno_network networks[]; +}; + +#define SIR_PASSPOINT_LIST_MAX_NETWORKS 8 +#define SIR_PASSPOINT_REALM_LEN 256 +#define SIR_PASSPOINT_ROAMING_CONSORTIUM_ID_NUM 16 +#define SIR_PASSPOINT_PLMN_LEN 3 +/** + * struct wifi_passpoint_network - passpoint network block + * @id: identifier of this network block + * @realm: null terminated UTF8 encoded realm, 0 if unspecified + * @roaming_consortium_ids: roaming consortium ids to match, 0s if unspecified + * @plmn: mcc/mnc combination as per rules, 0s if unspecified + */ +struct wifi_passpoint_network { + uint32_t id; + uint8_t realm[SIR_PASSPOINT_REALM_LEN]; + int64_t roaming_consortium_ids[SIR_PASSPOINT_ROAMING_CONSORTIUM_ID_NUM]; + uint8_t plmn[SIR_PASSPOINT_PLMN_LEN]; +}; + +/** + * struct wifi_passpoint_req - passpoint request + * @request_id: request identifier + * @num_networks: number of networks + * @networks: passpoint networks + */ +struct wifi_passpoint_req { + uint32_t request_id; + uint32_t session_id; + uint32_t num_networks; + struct wifi_passpoint_network networks[]; +}; + +/** + * struct wifi_passpoint_match - wifi passpoint network match + * @id: network block identifier for the matched network + * @anqp_len: length of ANQP blob + * @ap: scan result, with channel and beacon information + * @anqp: ANQP data, in the information_element format + */ +struct wifi_passpoint_match { + uint32_t request_id; + uint32_t id; + uint32_t anqp_len; + tSirWifiScanResult ap; + uint8_t anqp[]; +}; +#endif /* FEATURE_WLAN_EXTSCAN */ + +#ifdef FEATURE_WLAN_AUTO_SHUTDOWN +typedef struct { + uint32_t timer_val; +} tSirAutoShutdownCmdParams; + +typedef struct { + uint32_t shutdown_reason; +} tSirAutoShutdownEvtParams; +#endif + +#ifdef WLAN_FEATURE_LINK_LAYER_STATS + +typedef struct { + uint32_t reqId; + uint8_t staId; + uint32_t mpduSizeThreshold; + uint32_t aggressiveStatisticsGathering; +} tSirLLStatsSetReq, *tpSirLLStatsSetReq; + +typedef struct { + uint32_t reqId; + uint8_t staId; + uint32_t paramIdMask; +} tSirLLStatsGetReq, *tpSirLLStatsGetReq; + +typedef struct { + uint32_t reqId; + uint8_t staId; + uint32_t statsClearReqMask; + uint8_t stopReq; +} tSirLLStatsClearReq, *tpSirLLStatsClearReq; + +#ifdef WLAN_POWER_DEBUGFS +/** + * struct power_stats_response - Power stats response + * @cumulative_sleep_time_ms: cumulative sleep time in ms + * @cumulative_total_on_time_ms: total awake time in ms + * @deep_sleep_enter_counter: deep sleep enter counter + * @last_deep_sleep_enter_tstamp_ms: last deep sleep enter timestamp + * @debug_register_fmt: debug registers format + * @num_debug_register: number of debug registers + * @debug_registers: Pointer to the debug registers buffer + */ +struct power_stats_response { + uint32_t cumulative_sleep_time_ms; + uint32_t cumulative_total_on_time_ms; + uint32_t deep_sleep_enter_counter; + uint32_t last_deep_sleep_enter_tstamp_ms; + uint32_t debug_register_fmt; + uint32_t num_debug_register; + uint32_t *debug_registers; +}; +#endif + +/** + * struct lfr_firmware_status - LFR status in firmware + * @is_disabled: Is LFR disabled in FW + * @disable_lfr_event: Disable attempt done in FW + */ +struct lfr_firmware_status { + uint32_t is_disabled; + struct completion disable_lfr_event; +}; + +/** + * struct rso_cmd_status - RSO Command status + * @vdev_id: Vdev ID for which RSO command sent + * @status: Status of RSO command sent to FW + */ +struct rso_cmd_status { + uint32_t vdev_id; + bool status; +}; + +typedef struct { + uint8_t oui[WIFI_SCANNING_MAC_OUI_LENGTH]; + uint32_t vdev_id; + bool enb_probe_req_sno_randomization; +} tSirScanMacOui, *tpSirScanMacOui; + +enum { + SIR_AP_RX_DATA_OFFLOAD = 0x00, + SIR_STA_RX_DATA_OFFLOAD = 0x01, +}; + +struct sir_ipa_offload_enable_disable { + uint32_t offload_type; + uint32_t vdev_id; + uint32_t enable; +}; + +/** + * struct sir_set_vdev_ies_per_band + * @msg_type: message type + * @len: message length + * @vdev_id: vdev id + * + * Message wrapper structure for eWNI_SME_SET_VDEV_IES_PER_BAND. + */ +struct sir_set_vdev_ies_per_band { + uint16_t msg_type; + uint16_t len; + uint32_t vdev_id; +}; + +/** + * struct sir_set_ht_vht_cfg - ht, vht IE config + * @msg_type: message type + * @len: message length + * @pdev_id: pdev id + * @nss: Nss value + * @dot11mode: Dot11 mode. + * + * Message wrapper structure for set HT/VHT IE req. + */ +struct sir_set_ht_vht_cfg { + uint16_t msg_type; + uint16_t len; + uint32_t pdev_id; + uint32_t nss; + uint32_t dot11mode; +}; + +/*--------------------------------------------------------------------------- + WLAN_HAL_LL_NOTIFY_STATS + ---------------------------------------------------------------------------*/ + +/******************************LINK LAYER Statistics**********************/ + +typedef int tSirWifiRadio; +typedef int tSirWifiChannel; +typedef int tSirwifiTxRate; + +/* channel operating width */ +typedef enum { + WIFI_CHAN_WIDTH_20 = 0, + WIFI_CHAN_WIDTH_40 = 1, + WIFI_CHAN_WIDTH_80 = 2, + WIFI_CHAN_WIDTH_160 = 3, + WIFI_CHAN_WIDTH_80P80 = 4, + WIFI_CHAN_WIDTH_5 = 5, + WIFI_CHAN_WIDTH_10 = 6, +} tSirWifiChannelWidth; + +typedef enum { + WIFI_DISCONNECTED = 0, + WIFI_AUTHENTICATING = 1, + WIFI_ASSOCIATING = 2, + WIFI_ASSOCIATED = 3, + WIFI_EAPOL_STARTED = 4, /* if done by firmware/driver */ + WIFI_EAPOL_COMPLETED = 5, /* if done by firmware/driver */ +} tSirWifiConnectionState; + +typedef enum { + WIFI_ROAMING_IDLE = 0, + WIFI_ROAMING_ACTIVE = 1, +} tSirWifiRoamState; + +typedef enum { + WIFI_INTERFACE_STA = 0, + WIFI_INTERFACE_SOFTAP = 1, + WIFI_INTERFACE_IBSS = 2, + WIFI_INTERFACE_P2P_CLIENT = 3, + WIFI_INTERFACE_P2P_GO = 4, + WIFI_INTERFACE_NAN = 5, + WIFI_INTERFACE_MESH = 6, + WIFI_INTERFACE_NDI = 7, +} tSirWifiInterfaceMode; + +/* set for QOS association */ +#define WIFI_CAPABILITY_QOS 0x00000001 +/* set for protected assoc (802.11 beacon frame control protected bit set) */ +#define WIFI_CAPABILITY_PROTECTED 0x00000002 +/* set if 802.11 Extended Capabilities element interworking bit is set */ +#define WIFI_CAPABILITY_INTERWORKING 0x00000004 +/* set for HS20 association */ +#define WIFI_CAPABILITY_HS20 0x00000008 +/* set is 802.11 Extended Capabilities element UTF-8 SSID bit is set */ +#define WIFI_CAPABILITY_SSID_UTF8 0x00000010 +/* set is 802.11 Country Element is present */ +#define WIFI_CAPABILITY_COUNTRY 0x00000020 + +typedef struct { + /* tSirWifiInterfaceMode */ + /* interface mode */ + uint8_t mode; + /* interface mac address (self) */ + struct qdf_mac_addr macAddr; + /* tSirWifiConnectionState */ + /* connection state (valid for STA, CLI only) */ + uint8_t state; + /* tSirWifiRoamState */ + /* roaming state */ + uint32_t roaming; + /* WIFI_CAPABILITY_XXX (self) */ + uint32_t capabilities; + /* null terminated SSID */ + uint8_t ssid[33]; + /* bssid */ + struct qdf_mac_addr bssid; + /* country string advertised by AP */ + uint8_t apCountryStr[WNI_CFG_COUNTRY_CODE_LEN]; + /* country string for this association */ + uint8_t countryStr[WNI_CFG_COUNTRY_CODE_LEN]; +} tSirWifiInterfaceInfo, *tpSirWifiInterfaceInfo; + +/* channel information */ +typedef struct { + /* channel width (20, 40, 80, 80+80, 160) */ + tSirWifiChannelWidth width; + /* primary 20 MHz channel */ + tSirWifiChannel centerFreq; + /* center frequency (MHz) first segment */ + tSirWifiChannel centerFreq0; + /* center frequency (MHz) second segment */ + tSirWifiChannel centerFreq1; +} tSirWifiChannelInfo, *tpSirWifiChannelInfo; + +/* wifi rate info */ +typedef struct { + /* 0: OFDM, 1:CCK, 2:HT 3:VHT 4..7 reserved */ + uint32_t preamble:3; + /* 0:1x1, 1:2x2, 3:3x3, 4:4x4 */ + uint32_t nss:2; + /* 0:20MHz, 1:40Mhz, 2:80Mhz, 3:160Mhz */ + uint32_t bw:3; + /* OFDM/CCK rate code would be as per ieee std in units of 0.5mbps */ + /* HT/VHT it would be mcs index */ + uint32_t rateMcsIdx:8; + /* reserved */ + uint32_t reserved:16; + /* units of 100 Kbps */ + uint32_t bitrate; +} tSirWifiRate, *tpSirWifiRate; + +/* channel statistics */ +typedef struct { + /* channel */ + tSirWifiChannelInfo channel; + /* msecs the radio is awake (32 bits number accruing over time) */ + uint32_t onTime; + /* msecs the CCA register is busy (32 bits number accruing over time) */ + uint32_t ccaBusyTime; +} tSirWifiChannelStats, *tpSirWifiChannelStats; + +#define MAX_TPC_LEVELS 64 +/* radio statistics */ +typedef struct { + /* wifi radio (if multiple radio supported) */ + tSirWifiRadio radio; + /* msecs the radio is awake (32 bits number accruing over time) */ + uint32_t onTime; + /* msecs the radio is transmitting + * (32 bits number accruing over time) + */ + uint32_t txTime; + /* msecs the radio is in active receive + *(32 bits number accruing over time) + */ + uint32_t rxTime; + /* msecs the radio is awake due to all scan + * (32 bits number accruing over time) + */ + uint32_t onTimeScan; + /* msecs the radio is awake due to NAN + * (32 bits number accruing over time) + */ + uint32_t onTimeNbd; + /* msecs the radio is awake due to Gscan + * (32 bits number accruing over time) + */ + uint32_t onTimeGscan; + /* msecs the radio is awake due to roam?scan + * (32 bits number accruing over time) + */ + uint32_t onTimeRoamScan; + /* msecs the radio is awake due to PNO scan + * (32 bits number accruing over time) + */ + uint32_t onTimePnoScan; + /* msecs the radio is awake due to HS2.0 scans and GAS exchange + * (32 bits number accruing over time) + */ + uint32_t onTimeHs20; + + /* tx time (in milliseconds) per TPC level (0.5 dBm) */ + uint32_t total_num_tx_power_levels; + uint32_t *tx_time_per_power_level; + + /* number of channels */ + uint32_t numChannels; + + /* tx time (in milliseconds) per TPC level (0.5 dBm) */ + uint32_t tx_time_per_tpc[MAX_TPC_LEVELS]; + + /* channel statistics tSirWifiChannelStats */ + tSirWifiChannelStats *channels; +} tSirWifiRadioStat, *tpSirWifiRadioStat; + +/* per rate statistics */ +typedef struct { + /* rate information */ + tSirWifiRate rate; + /* number of successfully transmitted data pkts (ACK rcvd) */ + uint32_t txMpdu; + /* number of received data pkts */ + uint32_t rxMpdu; + /* number of data packet losses (no ACK) */ + uint32_t mpduLost; + /* total number of data pkt retries * */ + uint32_t retries; + /* number of short data pkt retries */ + uint32_t retriesShort; + /* number of long data pkt retries */ + uint32_t retriesLong; +} tSirWifiRateStat, *tpSirWifiRateStat; + +/* wifi peer type */ +typedef enum { + WIFI_PEER_STA, + WIFI_PEER_AP, + WIFI_PEER_P2P_GO, + WIFI_PEER_P2P_CLIENT, + WIFI_PEER_NAN, + WIFI_PEER_TDLS, + WIFI_PEER_INVALID, +} tSirWifiPeerType; + +/* per peer statistics */ +typedef struct { + /* peer type (AP, TDLS, GO etc.) */ + enum wmi_peer_type type; + /* mac address */ + struct qdf_mac_addr peerMacAddress; + /* peer WIFI_CAPABILITY_XXX */ + uint32_t capabilities; + /* number of rates */ + uint32_t numRate; + /* per rate statistics, number of entries = num_rate */ + tSirWifiRateStat rateStats[0]; +} tSirWifiPeerInfo, *tpSirWifiPeerInfo; + +/* per access category statistics */ +typedef struct { + /* tSirWifiTrafficAc */ + /* access category (VI, VO, BE, BK) */ + uint32_t ac; + /* number of successfully transmitted unicast data pkts (ACK rcvd) */ + uint32_t txMpdu; + /* number of received unicast mpdus */ + uint32_t rxMpdu; + /* number of succesfully transmitted multicast data packets */ + /* STA case: implies ACK received from AP for the unicast */ + /* packet in which mcast pkt was sent */ + uint32_t txMcast; + /* number of received multicast data packets */ + uint32_t rxMcast; + /* number of received unicast a-mpdus */ + uint32_t rxAmpdu; + /* number of transmitted unicast a-mpdus */ + uint32_t txAmpdu; + /* number of data pkt losses (no ACK) */ + uint32_t mpduLost; + /* total number of data pkt retries */ + uint32_t retries; + /* number of short data pkt retries */ + uint32_t retriesShort; + /* number of long data pkt retries */ + uint32_t retriesLong; + /* data pkt min contention time (usecs) */ + uint32_t contentionTimeMin; + /* data pkt max contention time (usecs) */ + uint32_t contentionTimeMax; + /* data pkt avg contention time (usecs) */ + uint32_t contentionTimeAvg; + /* num of data pkts used for contention statistics */ + uint32_t contentionNumSamples; +} tSirWifiWmmAcStat, *tpSirWifiWmmAcStat; + +/* Interface statistics - corresponding to 2nd most + * LSB in wifi statistics bitmap for getting statistics + */ +typedef struct { + /* current state of the interface */ + tSirWifiInterfaceInfo info; + /* access point beacon received count from connected AP */ + uint32_t beaconRx; + /* access point mgmt frames received count from */ + /* connected AP (including Beacon) */ + uint32_t mgmtRx; + /* action frames received count */ + uint32_t mgmtActionRx; + /* action frames transmit count */ + uint32_t mgmtActionTx; + /* access Point Beacon and Management frames RSSI (averaged) */ + uint32_t rssiMgmt; + /* access Point Data Frames RSSI (averaged) from connected AP */ + uint32_t rssiData; + /* access Point ACK RSSI (averaged) from connected AP */ + uint32_t rssiAck; + /* number of peers */ + uint32_t num_peers; + /* + * Indicates how many peer_stats events will be sent depending on the + * num_peers. + */ + uint32_t num_peer_events; + /* number of ac */ + uint32_t num_ac; + /* Roaming Stat */ + uint32_t roam_state; + /* + * Average Beacon spread offset is the averaged time delay between TBTT + * and beacon TSF. Upper 32 bits of averaged 64 bit beacon spread offset + */ + uint32_t avg_bcn_spread_offset_high; + /* Lower 32 bits of averaged 64 bit beacon spread offset */ + uint32_t avg_bcn_spread_offset_low; + /* + * Takes value of 1 if AP leaks packets after sending an ACK for PM=1 + * otherwise 0 + */ + uint32_t is_leaky_ap; + /* + * Average number of frames received from AP after receiving the ACK + * for a frame with PM = 1 + */ + uint32_t avg_rx_frms_leaked; + /* + * Rx leak watch window currently in force to minimize data loss + * because of leaky AP. Rx leak window is the + * time driver waits before shutting down the radio or switching + * the channel and after receiving an ACK for + * a data frame with PM bit set. + */ + uint32_t rx_leak_window; + uint32_t rts_succ_cnt; + uint32_t rts_fail_cnt; + uint32_t ppdu_succ_cnt; + uint32_t ppdu_fail_cnt; + /* per ac data packet statistics */ + tSirWifiWmmAcStat AccessclassStats[WIFI_AC_MAX]; +} tSirWifiIfaceStat, *tpSirWifiIfaceStat; + +/* Peer statistics - corresponding to 3rd most LSB in + * wifi statistics bitmap for getting statistics + */ +typedef struct { + /* number of peers */ + uint32_t numPeers; + /* per peer statistics */ + tSirWifiPeerInfo peerInfo[0]; +} tSirWifiPeerStat, *tpSirWifiPeerStat; + +/* wifi statistics bitmap for getting statistics */ +#define WMI_LINK_STATS_RADIO 0x00000001 +#define WMI_LINK_STATS_IFACE 0x00000002 +#define WMI_LINK_STATS_ALL_PEER 0x00000004 +#define WMI_LINK_STATS_PER_PEER 0x00000008 + +/* wifi statistics bitmap for clearing statistics */ +/* all radio statistics */ +#define WIFI_STATS_RADIO 0x00000001 +/* cca_busy_time (within radio statistics) */ +#define WIFI_STATS_RADIO_CCA 0x00000002 +/* all channel statistics (within radio statistics) */ +#define WIFI_STATS_RADIO_CHANNELS 0x00000004 +/* all scan statistics (within radio statistics) */ +#define WIFI_STATS_RADIO_SCAN 0x00000008 +/* all interface statistics */ +#define WIFI_STATS_IFACE 0x00000010 +/* all tx rate statistics (within interface statistics) */ +#define WIFI_STATS_IFACE_TXRATE 0x00000020 +/* all ac statistics (within interface statistics) */ +#define WIFI_STATS_IFACE_AC 0x00000040 +/* all contention (min, max, avg) statistics (within ac statistics) */ +#define WIFI_STATS_IFACE_CONTENTION 0x00000080 +/* All peer stats on this interface */ +#define WIFI_STATS_IFACE_ALL_PEER 0x00000100 +/* Clear particular peer stats depending on the peer_mac */ +#define WIFI_STATS_IFACE_PER_PEER 0x00000200 + +typedef struct { + uint32_t paramId; + uint8_t ifaceId; + uint32_t rspId; + uint32_t moreResultToFollow; + uint32_t nr_received; + union { + uint32_t num_peers; + uint32_t num_radio; + }; + + uint32_t peer_event_number; + /* Variable length field - Do not add anything after this */ + uint8_t results[0]; +} tSirLLStatsResults, *tpSirLLStatsResults; + +#endif /* WLAN_FEATURE_LINK_LAYER_STATS */ + +typedef struct sAniGetLinkStatus { + uint16_t msgType; /* message type is same as the request type */ + uint16_t msgLen; /* length of the entire request */ + uint8_t linkStatus; + uint8_t sessionId; +} tAniGetLinkStatus, *tpAniGetLinkStatus; + +#ifdef DHCP_SERVER_OFFLOAD +typedef struct { + uint32_t vdev_id; + uint32_t dhcpSrvOffloadEnabled; + uint32_t dhcpClientNum; + uint32_t dhcpSrvIP; +} tSirDhcpSrvOffloadInfo, *tpSirDhcpSrvOffloadInfo; +#endif /* DHCP_SERVER_OFFLOAD */ +#ifdef WLAN_FEATURE_GPIO_LED_FLASHING +typedef struct { + uint32_t reqId; + /* pattern identifier. 0: disconnected 1: connected */ + uint32_t pattern_id; + uint32_t led_x0; /* led flashing parameter0 */ + uint32_t led_x1; /* led flashing parameter1 */ +} tSirLedFlashingReq, *tpSirLedFlashingReq; +#endif + +/** + * struct sir_lost_link_info - lost link information structure. + * + * @vdev_id: vdev_id from WMA. some modules call sessionId. + * @rssi: rssi at disconnection time. + * + * driver uses this structure to communicate information collected at + * disconnection time. + */ +struct sir_lost_link_info { + uint32_t vdev_id; + int32_t rssi; +}; + +/* find the size of given member within a structure */ +#ifndef member_size +#define member_size(type, member) (sizeof(((type *)0)->member)) +#endif + +#define RTT_INVALID 0x00 +#define RTT_TIMING_MEAS_CAPABILITY 0x01 +#define RTT_FINE_TIME_MEAS_INITIATOR_CAPABILITY 0x02 +#define RTT_FINE_TIME_MEAS_RESPONDER_CAPABILITY 0x03 + +/** + * enum fine_time_meas_mask - bit mask to identify device's + * fine timing measurement capability + * @FINE_TIME_MEAS_STA_INITIATOR - STA role, Initiator capability is supported + * @FINE_TIME_MEAS_STA_RESPONDER - STA role, Responder capability is supported + * @FINE_TIME_MEAS_P2PCLI_INITIATOR - P2P-CLI supports initiator capability + * @FINE_TIME_MEAS_P2PCLI_RESPONDER - P2P-CLI supports responder capability + * @FINE_TIME_MEAS_P2PGO_INITIATOR - P2P-GO supports initiator capability + * @FINE_TIME_MEAS_P2PGO_RESPONDER - P2P-GO supports responder capability + * @FINE_TIME_MEAS_SAP_INITIATOR - SAP role, Initiator capability is supported + * @FINE_TIME_MEAS_SAP_RESPONDER - SAP role, Responder capability is supported + */ +enum fine_time_meas_mask { + FINE_TIME_MEAS_STA_INITIATOR = (1 << (0)), + FINE_TIME_MEAS_STA_RESPONDER = (1 << (1)), + FINE_TIME_MEAS_P2PCLI_INITIATOR = (1 << (2)), + FINE_TIME_MEAS_P2PCLI_RESPONDER = (1 << (3)), + FINE_TIME_MEAS_P2PGO_INITIATOR = (1 << (4)), + FINE_TIME_MEAS_P2PGO_RESPONDER = (1 << (5)), + FINE_TIME_MEAS_SAP_INITIATOR = (1 << (6)), + FINE_TIME_MEAS_SAP_RESPONDER = (1 << (7)), +}; + +/* number of neighbor reports that we can handle in Neighbor Report Response */ +#define MAX_SUPPORTED_NEIGHBOR_RPT 15 + +/** + * struct sir_stats_avg_factor + * @vdev_id: session id + * @stats_avg_factor: average factor + */ +struct sir_stats_avg_factor { + uint8_t vdev_id; + uint16_t stats_avg_factor; +}; + +/** + * struct sir_guard_time_request + * @vdev_id: session id + * @guard_time: guard time + */ +struct sir_guard_time_request { + uint8_t vdev_id; + uint32_t guard_time; +}; + +/* Max number of rates allowed in Supported Rates IE */ +#define MAX_NUM_SUPPORTED_RATES (8) + +/* + * struct rssi_monitor_req - rssi monitoring + * @request_id: request id + * @session_id: session id + * @min_rssi: minimum rssi + * @max_rssi: maximum rssi + * @control: flag to indicate start or stop + */ +struct rssi_monitor_req { + uint32_t request_id; + uint32_t session_id; + int8_t min_rssi; + int8_t max_rssi; + bool control; +}; + +/** + * struct rssi_breach_event - rssi breached event structure + * @request_id: request id + * @session_id: session id + * @curr_rssi: current rssi + * @curr_bssid: current bssid + */ +struct rssi_breach_event { + uint32_t request_id; + uint32_t session_id; + int8_t curr_rssi; + struct qdf_mac_addr curr_bssid; +}; + +/** + * struct chip_pwr_save_fail_detected_params - chip power save failure detected + * event params + * @failure_reason_code:failure reason code + * @wake_lock_bitmap:bitmap for modules voting against sleep for long duration. + */ +struct chip_pwr_save_fail_detected_params { + uint32_t failure_reason_code; + uint32_t wake_lock_bitmap[4]; +}; + +#define MAX_NUM_FW_SEGMENTS 4 + +/** + * struct fw_dump_seg_req - individual segment details + * @seg_id - segment id. + * @seg_start_addr_lo - lower address of the segment. + * @seg_start_addr_hi - higher address of the segment. + * @seg_length - length of the segment. + * @dst_addr_lo - lower address of the destination buffer. + * @dst_addr_hi - higher address of the destination buffer. + * + * This structure carries the information to firmware about the + * individual segments. This structure is part of firmware memory + * dump request. + */ +struct fw_dump_seg_req { + uint8_t seg_id; + uint32_t seg_start_addr_lo; + uint32_t seg_start_addr_hi; + uint32_t seg_length; + uint32_t dst_addr_lo; + uint32_t dst_addr_hi; +}; + +/** + * struct fw_dump_req - firmware memory dump request details. + * @request_id - request id. + * @num_seg - requested number of segments. + * @fw_dump_seg_req - individual segment information. + * + * This structure carries information about the firmware + * memory dump request. + */ +struct fw_dump_req { + uint32_t request_id; + uint32_t num_seg; + struct fw_dump_seg_req segment[MAX_NUM_FW_SEGMENTS]; +}; + +/** + * struct fw_dump_rsp - firmware dump response details. + * @request_id - request id. + * @dump_complete - copy completion status. + * + * This structure is used to store the firmware dump copy complete + * response from the firmware. + */ +struct fw_dump_rsp { + uint32_t request_id; + uint32_t dump_complete; +}; + +/** + * DEFAULT_SCAN_IE_ID - Identifier for the collection of IE's added + * by default to the probe request + */ +#define DEFAULT_SCAN_IE_ID 256 + + /* MAX_DEFAULT_SCAN_IE_LEN - Maxmimum length of Default Scan IE's */ +#define MAX_DEFAULT_SCAN_IE_LEN 1024 + + /* Extended Capabilities IE header(IE Id + IE Length) length */ +#define EXT_CAP_IE_HDR_LEN 2 + +/** + * struct hdd_default_scan_ie - HDD default scan IE structure + * @message_type: message type to be set with eWNI_SME_DEFAULT_SCAN_IE + * @length: length of the struct hdd_default_scan_ie + * @session_id: Session Id + * @ie_len: Default scan IE length + * @ie_data: Pointer to default scan IE data + */ +struct hdd_default_scan_ie { + uint16_t message_type; + uint16_t length; + uint16_t session_id; + uint16_t ie_len; + uint8_t ie_data[MAX_DEFAULT_SCAN_IE_LEN]; +}; + +/** + * struct vdev_ie_info - IE info + * @vdev_id - vdev for which the IE is being sent + * @ie_id - ID of the IE + * @length - length of the IE data + * @band - indicates IE is intended for which band + * @data - IE data + * + * This structure is used to store the IE information. + */ +struct vdev_ie_info { + uint32_t vdev_id; + uint32_t ie_id; + uint32_t length; + uint32_t band; + uint8_t *data; +}; + +/** + * struct send_extcap_ie - used to pass send_extcap_ie msg from SME to PE + * @type - MSG type + * @length - length of the message + * @seesion_id - session_id for which the message is intended for + * + * This structure is used to pass send_extcap_ie msg from SME to PE + */ +struct send_extcap_ie { + uint16_t msg_type; /* eWNI_SME_SET_IE_REQ */ + uint16_t length; + uint8_t session_id; +}; + +typedef void (*hw_mode_cb)(uint32_t status, uint32_t cfgd_hw_mode_index, + uint32_t num_vdev_mac_entries, + struct sir_vdev_mac_map *vdev_mac_map); +typedef void (*hw_mode_transition_cb)(uint32_t old_hw_mode_index, + uint32_t new_hw_mode_index, + uint32_t num_vdev_mac_entries, + struct sir_vdev_mac_map *vdev_mac_map); +typedef void (*dual_mac_cb)(uint32_t status, uint32_t scan_config, + uint32_t fw_mode_config); +typedef void (*antenna_mode_cb)(uint32_t status); + +/** + * struct sir_nss_update_request + * @msgType: nss update msg type + * @msgLen: length of the msg + * @new_nss: new spatial stream value + * @vdev_id: session id + */ +struct sir_nss_update_request { + uint16_t msgType; + uint16_t msgLen; + uint8_t new_nss; + uint32_t vdev_id; +}; + +/** + * struct sir_beacon_tx_complete_rsp + * + * @session_id: session for which beacon update happened + * @tx_status: status of the beacon tx from FW + */ +struct sir_beacon_tx_complete_rsp { + uint8_t session_id; + uint8_t tx_status; +}; + +typedef void (*nss_update_cb)(void *context, uint8_t tx_status, uint8_t vdev_id, + uint8_t next_action, enum sir_conn_update_reason reason); + +/** + * OCB structures + */ + +#define NUM_AC (4) +#define OCB_CHANNEL_MAX (5) + +struct sir_qos_params { + uint8_t aifsn; + uint8_t cwmin; + uint8_t cwmax; +}; + +/** + * struct sir_ocb_set_config_response + * @status: response status + */ +struct sir_ocb_set_config_response { + uint8_t status; +}; + +/** Callback for the dcc_stats_event */ +typedef void (*dcc_stats_event_callback_t)(void *hdd_ctx, uint32_t vdev_id, + uint32_t num_channels, uint32_t stats_per_channel_array_len, + const void *stats_per_channel_array); + +/** + * struct sir_ocb_config_channel + * @chan_freq: frequency of the channel + * @bandwidth: bandwidth of the channel, either 10 or 20 MHz + * @mac_address: MAC address assigned to this channel + * @qos_params: QoS parameters + * @max_pwr: maximum transmit power of the channel (dBm) + * @min_pwr: minimum transmit power of the channel (dBm) + * @reg_pwr: maximum transmit power specified by the regulatory domain (dBm) + * @antenna_max: maximum antenna gain specified by the regulatory domain (dB) + */ +struct sir_ocb_config_channel { + uint32_t chan_freq; + uint32_t bandwidth; + struct qdf_mac_addr mac_address; + struct sir_qos_params qos_params[MAX_NUM_AC]; + uint32_t max_pwr; + uint32_t min_pwr; + uint8_t reg_pwr; + uint8_t antenna_max; + uint16_t flags; +}; + +/** + * OCB_CHANNEL_FLAG_NO_RX_HDR - Don't add the RX stats header to packets + * received on this channel. + */ +#define OCB_CHANNEL_FLAG_DISABLE_RX_STATS_HDR (1 << 0) + +/** + * struct sir_ocb_config_sched + * @chan_freq: frequency of the channel + * @total_duration: duration of the schedule + * @guard_interval: guard interval on the start of the schedule + */ +struct sir_ocb_config_sched { + uint32_t chan_freq; + uint32_t total_duration; + uint32_t guard_interval; +}; + +/** + * struct sir_ocb_config + * @session_id: session id + * @channel_count: number of channels + * @schedule_size: size of the channel schedule + * @flags: reserved + * @channels: array of OCB channels + * @schedule: array of OCB schedule elements + * @dcc_ndl_chan_list_len: size of the ndl_chan array + * @dcc_ndl_chan_list: array of dcc channel info + * @dcc_ndl_active_state_list_len: size of the active state array + * @dcc_ndl_active_state_list: array of active states + * @def_tx_param: default TX parameters + * @def_tx_param_size: size of the default TX parameters + */ +struct sir_ocb_config { + uint8_t session_id; + uint32_t channel_count; + uint32_t schedule_size; + uint32_t flags; + struct sir_ocb_config_channel *channels; + struct sir_ocb_config_sched *schedule; + uint32_t dcc_ndl_chan_list_len; + void *dcc_ndl_chan_list; + uint32_t dcc_ndl_active_state_list_len; + void *dcc_ndl_active_state_list; + void *def_tx_param; + uint32_t def_tx_param_size; +}; + +/* The size of the utc time in bytes. */ +#define SIZE_UTC_TIME (10) +/* The size of the utc time error in bytes. */ +#define SIZE_UTC_TIME_ERROR (5) + +/** + * struct sir_ocb_utc + * @vdev_id: session id + * @utc_time: number of nanoseconds from Jan 1st 1958 + * @time_error: the error in the UTC time. All 1's for unknown + */ +struct sir_ocb_utc { + uint32_t vdev_id; + uint8_t utc_time[SIZE_UTC_TIME]; + uint8_t time_error[SIZE_UTC_TIME_ERROR]; +}; + +/** + * struct sir_ocb_timing_advert + * @vdev_id: session id + * @chan_freq: frequency on which to advertise + * @repeat_rate: the number of times it will send TA in 5 seconds + * @timestamp_offset: offset of the timestamp field in the TA frame + * @time_value_offset: offset of the time_value field in the TA frame + * @template_length: size in bytes of the TA frame + * @template_value: the TA frame + */ +struct sir_ocb_timing_advert { + uint32_t vdev_id; + uint32_t chan_freq; + uint32_t repeat_rate; + uint32_t timestamp_offset; + uint32_t time_value_offset; + uint32_t template_length; + uint8_t *template_value; +}; + +/** + * struct sir_ocb_get_tsf_timer_response + * @vdev_id: session id + * @timer_high: higher 32-bits of the timer + * @timer_low: lower 32-bits of the timer + */ +struct sir_ocb_get_tsf_timer_response { + uint32_t vdev_id; + uint32_t timer_high; + uint32_t timer_low; +}; + +/** + * struct sir_ocb_get_tsf_timer + * @vdev_id: session id + */ +struct sir_ocb_get_tsf_timer { + uint32_t vdev_id; +}; + +/** + * struct sir_dcc_get_stats_response + * @vdev_id: session id + * @num_channels: number of dcc channels + * @channel_stats_array_len: size in bytes of the stats array + * @channel_stats_array: the stats array + */ +struct sir_dcc_get_stats_response { + uint32_t vdev_id; + uint32_t num_channels; + uint32_t channel_stats_array_len; + void *channel_stats_array; +}; + +/** + * struct sir_dcc_get_stats + * @vdev_id: session id + * @channel_count: number of dcc channels + * @request_array_len: size in bytes of the request array + * @request_array: the request array + */ +struct sir_dcc_get_stats { + uint32_t vdev_id; + uint32_t channel_count; + uint32_t request_array_len; + void *request_array; +}; + +/** + * struct sir_dcc_clear_stats + * @vdev_id: session id + * @dcc_stats_bitmap: bitmap of clear option + */ +struct sir_dcc_clear_stats { + uint32_t vdev_id; + uint32_t dcc_stats_bitmap; +}; + +/** + * struct sir_dcc_update_ndl_response + * @vdev_id: session id + * @status: response status + */ +struct sir_dcc_update_ndl_response { + uint32_t vdev_id; + uint32_t status; +}; + +/** + * struct sir_dcc_update_ndl + * @vdev_id: session id + * @channel_count: number of channels to be updated + * @dcc_ndl_chan_list_len: size in bytes of the ndl_chan array + * @dcc_ndl_chan_list: the ndl_chan array + * @dcc_ndl_active_state_list_len: size in bytes of the active_state array + * @dcc_ndl_active_state_list: the active state array + */ +struct sir_dcc_update_ndl { + uint32_t vdev_id; + uint32_t channel_count; + uint32_t dcc_ndl_chan_list_len; + void *dcc_ndl_chan_list; + uint32_t dcc_ndl_active_state_list_len; + void *dcc_ndl_active_state_list; +}; + +/** + * enum powersave_qpower_mode: QPOWER modes + * @QPOWER_DISABLED: Qpower is disabled + * @QPOWER_ENABLED: Qpower is enabled + * @QPOWER_DUTY_CYCLING: Qpower is enabled with duty cycling + */ +enum powersave_qpower_mode { + QPOWER_DISABLED = 0, + QPOWER_ENABLED = 1, + QPOWER_DUTY_CYCLING = 2 +}; + +/** + * enum powersave_qpower_mode: powersave_mode + * @PS_NOT_SUPPORTED: Power save is not supported + * @PS_LEGACY_NODEEPSLEEP: Legacy power save enabled and deep sleep disabled + * @PS_QPOWER_NODEEPSLEEP: QPOWER enabled and deep sleep disabled + * @PS_LEGACY_DEEPSLEEP: Legacy power save enabled and deep sleep enabled + * @PS_QPOWER_DEEPSLEEP: QPOWER enabled and deep sleep enabled + * @PS_DUTY_CYCLING_QPOWER: QPOWER enabled in duty cycling mode + */ +enum powersave_mode { + PS_NOT_SUPPORTED = 0, + PS_LEGACY_NODEEPSLEEP = 1, + PS_QPOWER_NODEEPSLEEP = 2, + PS_LEGACY_DEEPSLEEP = 3, + PS_QPOWER_DEEPSLEEP = 4, + PS_DUTY_CYCLING_QPOWER = 5 +}; +#ifdef FEATURE_LFR_SUBNET_DETECTION +/** + * struct gateway_param_update_req - gateway parameter update request + * @request_id: request id + * @session_id: session id + * @max_retries: Max ARP/NS retry attempts + * @timeout: Retry interval + * @ipv4_addr_type: on ipv4 network + * @ipv6_addr_type: on ipv6 network + * @gw_mac_addr: gateway mac addr + * @ipv4_addr: ipv4 addr + * @ipv6_addr: ipv6 addr + */ +struct gateway_param_update_req { + uint32_t request_id; + uint32_t session_id; + uint32_t max_retries; + uint32_t timeout; + uint32_t ipv4_addr_type; + uint32_t ipv6_addr_type; + struct qdf_mac_addr gw_mac_addr; + uint8_t ipv4_addr[QDF_IPV4_ADDR_SIZE]; + uint8_t ipv6_addr[QDF_IPV6_ADDR_SIZE]; +}; +#else +struct gateway_param_update_req; +#endif /* FEATURE_LFR_SUBNET_DETECTION */ + +/** + * struct sir_sme_ext_change_chan_req - channel change request + * @message_type: message id + * @length: msg length + * @new_channel: new channel + * @session_id: session id + */ +struct sir_sme_ext_cng_chan_req { + uint16_t message_type; /* eWNI_SME_EXT_CHANGE_CHANNEL */ + uint16_t length; + uint32_t new_channel; + uint8_t session_id; +}; + +/** + * struct sir_sme_ext_change_chan_ind. + * @session_id: session id + * @new_channel: new channel to change + */ +struct sir_sme_ext_cng_chan_ind { + uint8_t session_id; + uint8_t new_channel; +}; + +/** + * struct stsf - the basic stsf structure + * + * @vdev_id: vdev id + * @tsf_low: low 32bits of tsf + * @tsf_high: high 32bits of tsf + * @soc_timer_low: low 32bits of synced SOC timer value + * @soc_timer_high: high 32bits of synced SOC timer value + * + * driver use this struct to store the tsf info + */ +struct stsf { + uint32_t vdev_id; + uint32_t tsf_low; + uint32_t tsf_high; + uint32_t soc_timer_low; + uint32_t soc_timer_high; +}; + +/** + * struct egap_params - the enhanced green ap params + * @vdev_id: vdev id + * @enable: enable or disable the enhance green ap in firmware + * @inactivity_time: inactivity timeout value + * @wait_time: wait timeout value + * @flags: feature flag in bitmask + * + */ +struct egap_conf_params { + uint32_t vdev_id; + bool enable; + uint32_t inactivity_time; + uint32_t wait_time; + uint32_t flags; +}; + +#define SIR_BCN_FLT_MAX_ELEMS_IE_LIST 8 +/** + * struct beacon_filter_param - parameters for beacon filtering + * @vdev_id: vdev id + * @ie_map: bitwise map of IEs that needs to be filtered + * + */ +struct beacon_filter_param { + uint32_t vdev_id; + uint32_t ie_map[SIR_BCN_FLT_MAX_ELEMS_IE_LIST]; +}; + +/** + * struct adaptive_dwelltime_params - the adaptive dwelltime params + * @vdev_id: vdev id + * @is_enabled: Adaptive dwell time is enabled/disabled + * @dwelltime_mode: global default adaptive dwell mode + * @lpf_weight: weight to calculate the average low pass + * filter for channel congestion + * @passive_mon_intval: intval to monitor wifi activity in passive scan in msec + * @wifi_act_threshold: % of wifi activity used in passive scan 0-100 + * + */ +struct adaptive_dwelltime_params { + uint32_t vdev_id; + bool is_enabled; + uint8_t dwelltime_mode; + uint8_t lpf_weight; + uint8_t passive_mon_intval; + uint8_t wifi_act_threshold; +}; + +/** + * struct csa_offload_params - CSA offload request parameters + * @channel: channel + * @switch_mode: switch mode + * @sec_chan_offset: second channel offset + * @new_ch_width: new channel width + * @new_ch_freq_seg1: channel center freq 1 + * @new_ch_freq_seg2: channel center freq 2 + * @ies_present_flag: IE present flag + */ +struct csa_offload_params { + uint8_t channel; + uint8_t switch_mode; + uint8_t sec_chan_offset; + uint8_t new_ch_width; + uint8_t new_op_class; + uint8_t new_ch_freq_seg1; + uint8_t new_ch_freq_seg2; + uint32_t ies_present_flag; + tSirMacAddr bssId; +}; + +/** + * enum obss_ht40_scancmd_type - obss scan command type + * @HT40_OBSS_SCAN_PARAM_START: OBSS scan start + * @HT40_OBSS_SCAN_PARAM_UPDATE: OBSS scan param update + */ +enum obss_ht40_scancmd_type { + HT40_OBSS_SCAN_PARAM_START, + HT40_OBSS_SCAN_PARAM_UPDATE +}; + +/** + * struct sme_obss_ht40_scanind_msg - sme obss scan params + * @msg_type: message type + * @length: message length + * @mac_addr: mac address + */ +struct sme_obss_ht40_scanind_msg { + uint16_t msg_type; + uint16_t length; + struct qdf_mac_addr mac_addr; +}; + +/** + * struct obss_ht40_scanind - ht40 obss scan request + * @cmd: message type + * @scan_type: message length + * @obss_passive_dwelltime: obss passive dwelltime + * @obss_active_dwelltime: obss active dwelltime + * @obss_width_trigger_interval: scan interval + * @obss_passive_total_per_channel: total passive scan time per channel + * @obss_active_total_per_channel: total active scan time per channel + * @bsswidth_ch_trans_delay: OBSS transition delay time + * @obss_activity_threshold: OBSS activity threshold + * @self_sta_id: self sta identification + * @bss_id: BSS index + * @fortymhz_intolerent: Ht40mhz intolerance + * @channel_count: channel count + * @channels: channel information + * @current_operatingclass: operating class + * @iefield_len: ie's length + * @iefiled: ie's information + */ +struct obss_ht40_scanind { + enum obss_ht40_scancmd_type cmd; + enum eSirScanType scan_type; + /* In TUs */ + uint16_t obss_passive_dwelltime; + uint16_t obss_active_dwelltime; + /* In seconds */ + uint16_t obss_width_trigger_interval; + /* In TU's */ + uint16_t obss_passive_total_per_channel; + uint16_t obss_active_total_per_channel; + uint16_t bsswidth_ch_trans_delay; + uint16_t obss_activity_threshold; + uint8_t self_sta_idx; + uint8_t bss_id; + uint8_t fortymhz_intolerent; + uint8_t channel_count; + uint8_t channels[SIR_ROAM_MAX_CHANNELS]; + uint8_t current_operatingclass; + uint16_t iefield_len; + uint8_t iefield[SIR_ROAM_SCAN_MAX_PB_REQ_SIZE]; +}; + +/** + * struct obss_scanparam - OBSS scan parameters + * @obss_passive_dwelltime: message type + * @obss_active_dwelltime: message length + * @obss_width_trigger_interval: obss passive dwelltime + * @obss_passive_total_per_channel: obss passive total scan time + * @obss_active_total_per_channel: obss active total scan time + * @bsswidth_ch_trans_delay: OBSS transition delay time + * @obss_activity_threshold: OBSS activity threshold + */ +struct obss_scanparam { + uint16_t obss_passive_dwelltime; + uint16_t obss_active_dwelltime; + uint16_t obss_width_trigger_interval; + uint16_t obss_passive_total_per_channel; + uint16_t obss_active_total_per_channel; + uint16_t bsswidth_ch_trans_delay; + uint16_t obss_activity_threshold; +}; + +/** + * struct sir_bpf_set_offload - set bpf filter instructions + * @session_id: session identifier + * @version: host bpf version + * @filter_id: Filter ID for BPF filter + * @total_length: The total length of the full instruction + * total_length equal to 0 means reset + * @current_offset: current offset, 0 means start a new setting + * @current_length: Length of current @program + * @program: BPF instructions + */ +struct sir_bpf_set_offload { + uint8_t session_id; + uint32_t version; + uint32_t filter_id; + uint32_t total_length; + uint32_t current_offset; + uint32_t current_length; + uint8_t *program; +}; + +/** + * struct sir_bpf_offload_capabilities - get bpf Capabilities + * @bpf_version: fw's implement version + * @max_bpf_filters: max filters that fw supports + * @max_bytes_for_bpf_inst: the max bytes that can be used as bpf instructions + * @remaining_bytes_for_bpf_inst: remaining bytes for bpf instructions + * + */ +struct sir_bpf_get_offload { + uint32_t bpf_version; + uint32_t max_bpf_filters; + uint32_t max_bytes_for_bpf_inst; + uint32_t remaining_bytes_for_bpf_inst; +}; + +/** + * struct sir_wake_lock_stats - wake lock stats structure + * @wow_unspecified_wake_up_count: number of non-wow related wake ups + * @wow_ucast_wake_up_count: Unicast wakeup count + * @wow_bcast_wake_up_count: Broadcast wakeup count + * @wow_ipv4_mcast_wake_up_count: ipv4 multicast wakeup count + * @wow_ipv6_mcast_wake_up_count: ipv6 multicast wakeup count + * @wow_ipv6_mcast_ra_stats: ipv6 multicast ra stats + * @wow_ipv6_mcast_ns_stats: ipv6 multicast ns stats + * @wow_ipv6_mcast_na_stats: ipv6 multicast na stats + * @wow_icmpv4_count: ipv4 icmp packet count + * @wow_icmpv6_count: ipv6 icmp packet count + * @wow_rssi_breach_wake_up_count: rssi breach wakeup count + * @wow_low_rssi_wake_up_count: low rssi wakeup count + * @wow_gscan_wake_up_count: gscan wakeup count + * @wow_pno_complete_wake_up_count: pno complete wakeup count + * @wow_pno_match_wake_up_count: pno match wakeup count + * @wow_oem_response_wake_up_count: oem response wakeup count + */ +struct sir_wake_lock_stats { + uint32_t wow_unspecified_wake_up_count; + uint32_t wow_ucast_wake_up_count; + uint32_t wow_bcast_wake_up_count; + uint32_t wow_ipv4_mcast_wake_up_count; + uint32_t wow_ipv6_mcast_wake_up_count; + uint32_t wow_ipv6_mcast_ra_stats; + uint32_t wow_ipv6_mcast_ns_stats; + uint32_t wow_ipv6_mcast_na_stats; + uint32_t wow_icmpv4_count; + uint32_t wow_icmpv6_count; + uint32_t wow_rssi_breach_wake_up_count; + uint32_t wow_low_rssi_wake_up_count; + uint32_t wow_gscan_wake_up_count; + uint32_t wow_pno_complete_wake_up_count; + uint32_t wow_pno_match_wake_up_count; + uint32_t wow_oem_response_wake_up_count; +}; + +/** + * struct sir_vdev_wow_stats - container for per vdev wow related stat counters + * @ucast: Unicast wakeup count + * @bcast: Broadcast wakeup count + * @ipv4_mcast: ipv4 multicast wakeup count + * @ipv6_mcast: ipv6 multicast wakeup count + * @ipv6_mcast_ra: ipv6 multicast ra stats + * @ipv6_mcast_ns: ipv6 multicast ns stats + * @ipv6_mcast_na: ipv6 multicast na stats + * @icmpv4: ipv4 icmp packet count + * @icmpv6: ipv6 icmp packet count + * @rssi_breach: rssi breach wakeup count + * @low_rssi: low rssi wakeup count + * @gscan: gscan wakeup count + * @pno_complete: pno complete wakeup count + * @pno_match: pno match wakeup count + * @oem_response: oem response wakeup count + * @pwr_save_fail_detected: pwr save fail detected wakeup count + */ +struct sir_vdev_wow_stats { + uint32_t ucast; + uint32_t bcast; + uint32_t ipv4_mcast; + uint32_t ipv6_mcast; + uint32_t ipv6_mcast_ra; + uint32_t ipv6_mcast_ns; + uint32_t ipv6_mcast_na; + uint32_t icmpv4; + uint32_t icmpv6; + uint32_t rssi_breach; + uint32_t low_rssi; + uint32_t gscan; + uint32_t pno_complete; + uint32_t pno_match; + uint32_t oem_response; + uint32_t pwr_save_fail_detected; +}; + +/** + * enum ht_capability_fields - HT Capabilities bit fields + * @HT_CAPS_LDPC: ldpc coding capability bit field + * @HT_CAPS_SUPPORTED_CHANNEL_SET: channel width set bit field + * @HT_CAPS_SM_PWR_SAVE: SM power save bit field + * @HT_CAPS_GREENFIELD: greenfield capability bit field + * @HT_CAPS_SHORT_GI20: short GI 20 bit field + * @HT_CAPS_SHORT_GI40: short GI 40 bit field + * @HT_CAPS_TX_STBC: Tx STBC bit field + * @HT_CAPS_RX_STBC: Rx STBC bit fields + */ +enum ht_capability_fields { + HT_CAPS_LDPC = 0x0001, + HT_CAPS_SUPPORTED_CHANNEL_SET = 0x0002, + HT_CAPS_SM_PWR_SAVE = 0x000c, + HT_CAPS_GREENFIELD = 0x0010, + HT_CAPS_SHORT_GI20 = 0x0020, + HT_CAPS_SHORT_GI40 = 0x0040, + HT_CAPS_TX_STBC = 0x0080, + HT_CAPS_RX_STBC = 0x0300 +}; + +#ifdef WLAN_FEATURE_NAN_DATAPATH + +#define IFACE_NAME_SIZE 64 + +/** + * enum ndp_accept_policy - nan data path accept policy + * @NDP_ACCEPT_POLICY_NONE: the framework will decide the policy + * @NDP_ACCEPT_POLICY_ALL: accept policy offloaded to fw + * + */ +enum ndp_accept_policy { + NDP_ACCEPT_POLICY_NONE = 0, + NDP_ACCEPT_POLICY_ALL = 1, +}; + +/** + * enum ndp_self_role - nan data path role + * @NDP_ROLE_INITIATOR: initiator of nan data path request + * @NDP_ROLE_RESPONDER: responder to nan data path request + * + */ +enum ndp_self_role { + NDP_ROLE_INITIATOR = 0, + NDP_ROLE_RESPONDER = 1, +}; + +/** + * enum ndp_response_code - responder's response code to nan data path request + * @NDP_RESPONSE_ACCEPT: ndp request accepted + * @NDP_RESPONSE_REJECT: ndp request rejected + * @NDP_RESPONSE_DEFER: ndp request deferred until later (response to follow + * any time later) + * + */ +enum ndp_response_code { + NDP_RESPONSE_ACCEPT = 0, + NDP_RESPONSE_REJECT = 1, + NDP_RESPONSE_DEFER = 2, +}; + +/** + * enum ndp_end_type - NDP end type + * @NDP_END_TYPE_UNSPECIFIED: type is unspecified + * @NDP_END_TYPE_PEER_UNAVAILABLE: type is peer unavailable + * @NDP_END_TYPE_OTA_FRAME: NDP end frame received from peer + * + */ +enum ndp_end_type { + NDP_END_TYPE_UNSPECIFIED = 0x00, + NDP_END_TYPE_PEER_UNAVAILABLE = 0x01, + NDP_END_TYPE_OTA_FRAME = 0x02, +}; + +/** + * enum ndp_end_reason_code - NDP end reason code + * @NDP_END_REASON_UNSPECIFIED: reason is unspecified + * @NDP_END_REASON_INACTIVITY: reason is peer inactivity + * @NDP_END_REASON_PEER_DATA_END: data end indication received from peer + * + */ +enum ndp_end_reason_code { + NDP_END_REASON_UNSPECIFIED = 0x00, + NDP_END_REASON_INACTIVITY = 0x01, + NDP_END_REASON_PEER_DATA_END = 0x02, +}; + +/** + * enum nan_status_type - NDP status type + * @NDP_RSP_STATUS_SUCCESS: request was successful + * @NDP_RSP_STATUS_ERROR: request failed + */ +enum nan_status_type { + NDP_RSP_STATUS_SUCCESS = 0x00, + NDP_RSP_STATUS_ERROR = 0x01, +}; + +/** + * enum nan_reason_code - NDP command rsp reason code value + * @NDP_UNSUPPORTED_CONCURRENCY: Will be used in unsupported concurrency cases + * @NDP_NAN_DATA_IFACE_CREATE_FAILED: ndi create failed + * @NDP_NAN_DATA_IFACE_DELETE_FAILED: ndi delete failed + * @NDP_DATA_INITIATOR_REQ_FAILED: data initiator request failed + * @NDP_DATA_RESPONDER_REQ_FAILED: data responder request failed + * @NDP_INVALID_SERVICE_INSTANCE_ID: invalid service instance id + * @NDP_INVALID_NDP_INSTANCE_ID: invalid ndp instance id + * @NDP_INVALID_RSP_CODE: invalid response code in ndp responder request + * @NDP_INVALID_APP_INFO_LEN: invalid app info length + * @NDP_NMF_REQ_FAIL: OTA nan mgmt frame failure for data request + * @NDP_NMF_RSP_FAIL: OTA nan mgmt frame failure for data response + * @NDP_NMF_CNF_FAIL: OTA nan mgmt frame failure for confirm + * @NDP_END_FAILED: ndp end failed + * @NDP_NMF_END_REQ_FAIL: OTA nan mgmt frame failure for data end + * @NDP_VENDOR_SPECIFIC_ERROR: other vendor specific failures + */ +enum nan_reason_code { + NDP_UNSUPPORTED_CONCURRENCY = 9000, + NDP_NAN_DATA_IFACE_CREATE_FAILED = 9001, + NDP_NAN_DATA_IFACE_DELETE_FAILED = 9002, + NDP_DATA_INITIATOR_REQ_FAILED = 9003, + NDP_DATA_RESPONDER_REQ_FAILED = 9004, + NDP_INVALID_SERVICE_INSTANCE_ID = 9005, + NDP_INVALID_NDP_INSTANCE_ID = 9006, + NDP_INVALID_RSP_CODE = 9007, + NDP_INVALID_APP_INFO_LEN = 9008, + NDP_NMF_REQ_FAIL = 9009, + NDP_NMF_RSP_FAIL = 9010, + NDP_NMF_CNF_FAIL = 9011, + NDP_END_FAILED = 9012, + NDP_NMF_END_REQ_FAIL = 9013, + /* 9500 onwards vendor specific error codes */ + NDP_VENDOR_SPECIFIC_ERROR = 9500, +}; + +/** + * struct ndp_cfg - ndp configuration + * @tag: unique identifier + * @ndp_cfg_len: ndp configuration length + * @ndp_cfg: variable length ndp configuration + * + */ +struct ndp_cfg { + uint32_t tag; + uint32_t ndp_cfg_len; + uint8_t *ndp_cfg; +}; + +/** + * struct ndp_qos_cfg - ndp qos configuration + * @tag: unique identifier + * @ndp_qos_cfg_len: ndp qos configuration length + * @ndp_qos_cfg: variable length ndp qos configuration + * + */ +struct ndp_qos_cfg { + uint32_t tag; + uint32_t ndp_qos_cfg_len; + uint8_t ndp_qos_cfg[]; +}; + +/** + * struct ndp_app_info - application info shared during ndp setup + * @tag: unique identifier + * @ndp_app_info_len: ndp app info length + * @ndp_app_info: variable length application information + * + */ +struct ndp_app_info { + uint32_t tag; + uint32_t ndp_app_info_len; + uint8_t *ndp_app_info; +}; + +/** + * struct ndp_scid - structure to hold sceurity context identifier + * @scid_len: length of scid + * @scid: scid + * + */ +struct ndp_scid { + uint32_t scid_len; + uint8_t *scid; +}; + +/** + * struct ndp_pmk - structure to hold pairwise master key + * @pmk_len: length of pairwise master key + * @pmk: buffer containing pairwise master key + * + */ +struct ndp_pmk { + uint32_t pmk_len; + uint8_t *pmk; +}; + +/** + * struct ndi_create_req - ndi create request params + * @transaction_id: unique identifier + * @iface_name: interface name + * + */ +struct ndi_create_req { + uint32_t transaction_id; + char iface_name[IFACE_NAME_SIZE]; +}; + +/** + * struct ndi_create_rsp - ndi create response params + * @status: request status + * @reason: reason if any + * + */ +struct ndi_create_rsp { + uint32_t status; + uint32_t reason; + uint8_t sta_id; +}; + +/** + * struct ndi_delete_rsp - ndi delete response params + * @status: request status + * @reason: reason if any + * + */ +struct ndi_delete_rsp { + uint32_t status; + uint32_t reason; +}; + +/** + * struct ndp_initiator_req - ndp initiator request params + * @transaction_id: unique identifier + * @vdev_id: session id of the interface over which ndp is being created + * @channel: suggested channel for ndp creation + * @channel_cfg: channel config, 0=no channel, 1=optional, 2=mandatory + * @service_instance_id: Service identifier + * @peer_discovery_mac_addr: Peer's discovery mac address + * @self_ndi_mac_addr: self NDI mac address + * @ndp_config: ndp configuration params + * @ndp_info: ndp application info + * @ncs_sk_type: indicates NCS_SK_128 or NCS_SK_256 + * @pmk: pairwise master key + * + */ +struct ndp_initiator_req { + uint32_t transaction_id; + uint32_t vdev_id; + uint32_t channel; + uint32_t channel_cfg; + uint32_t service_instance_id; + struct qdf_mac_addr peer_discovery_mac_addr; + struct qdf_mac_addr self_ndi_mac_addr; + struct ndp_cfg ndp_config; + struct ndp_app_info ndp_info; + uint32_t ncs_sk_type; + struct ndp_pmk pmk; +}; + +/** + * struct ndp_initiator_rsp - response event from FW + * @transaction_id: unique identifier + * @vdev_id: session id of the interface over which ndp is being created + * @ndp_instance_id: locally created NDP instance ID + * @status: status of the ndp request + * @reason: reason for failure if any + * + */ +struct ndp_initiator_rsp { + uint32_t transaction_id; + uint32_t vdev_id; + uint32_t ndp_instance_id; + uint32_t status; + uint32_t reason; +}; + +/** + * struct ndp_indication_event - create ndp indication on the responder + * @vdev_id: session id of the interface over which ndp is being created + * @service_instance_id: Service identifier + * @peer_discovery_mac_addr: Peer's discovery mac address + * @peer_mac_addr: Peer's NDI mac address + * @ndp_initiator_mac_addr: NDI mac address of the peer initiating NDP + * @ndp_instance_id: locally created NDP instance ID + * @role: self role for NDP + * @ndp_accept_policy: accept policy configured by the upper layer + * @ndp_config: ndp configuration params + * @ndp_info: ndp application info + * @ncs_sk_type: indicates NCS_SK_128 or NCS_SK_256 + * @scid: security context identifier + * + */ +struct ndp_indication_event { + uint32_t vdev_id; + uint32_t service_instance_id; + struct qdf_mac_addr peer_discovery_mac_addr; + struct qdf_mac_addr peer_mac_addr; + uint32_t ndp_instance_id; + enum ndp_self_role role; + enum ndp_accept_policy policy; + struct ndp_cfg ndp_config; + struct ndp_app_info ndp_info; + uint32_t ncs_sk_type; + struct ndp_scid scid; +}; + +/** + * struct ndp_responder_req - responder's response to ndp create request + * @transaction_id: unique identifier + * @vdev_id: session id of the interface over which ndp is being created + * @ndp_instance_id: locally created NDP instance ID + * @ndp_rsp: response to the ndp create request + * @ndp_config: ndp configuration params + * @ndp_info: ndp application info + * @pmk: pairwise master key + * @ncs_sk_type: indicates NCS_SK_128 or NCS_SK_256 + * + */ +struct ndp_responder_req { + uint32_t transaction_id; + uint32_t vdev_id; + uint32_t ndp_instance_id; + enum ndp_response_code ndp_rsp; + struct ndp_cfg ndp_config; + struct ndp_app_info ndp_info; + struct ndp_pmk pmk; + uint32_t ncs_sk_type; +}; + +/** + * struct ndp_responder_rsp_event - response to responder's request + * @transaction_id: unique identifier + * @vdev_id: session id of the interface over which ndp is being created + * @status: command status + * @reason: reason for failure if any + * @peer_mac_addr: Peer's mac address + * + */ +struct ndp_responder_rsp_event { + uint32_t transaction_id; + uint32_t vdev_id; + uint32_t status; + uint32_t reason; + struct qdf_mac_addr peer_mac_addr; + bool create_peer; +}; + +/** + * struct ndp_confirm_event - ndp confirmation event from FW + * @vdev_id: session id of the interface over which ndp is being created + * @ndp_instance_id: ndp instance id for which confirm is being generated + * @reason_code : reason code(opaque to driver) + * @num_active_ndps_on_peer: number of ndp instances on peer + * @peer_ndi_mac_addr: peer NDI mac address + * @rsp_code: ndp response code + * @ndp_info: ndp application info + * + */ +struct ndp_confirm_event { + uint32_t vdev_id; + uint32_t ndp_instance_id; + uint32_t reason_code; + uint32_t num_active_ndps_on_peer; + struct qdf_mac_addr peer_ndi_mac_addr; + enum ndp_response_code rsp_code; + struct ndp_app_info ndp_info; +}; + +/** + * struct ndp_end_req - ndp end request + * @transaction_id: unique transaction identifier + * @num_ndp_instances: number of ndp instances to be terminated + * @ndp_ids: pointer to array of ndp_instance_id to be terminated + * + */ +struct ndp_end_req { + uint32_t transaction_id; + uint32_t num_ndp_instances; + uint32_t *ndp_ids; +}; + +/** + * struct peer_ndp_map - mapping of NDP instances to peer to VDEV + * @vdev_id: session id of the interface over which ndp is being created + * @peer_ndi_mac_addr: peer NDI mac address + * @num_active_ndp_sessions: number of active NDP sessions on the peer + * @type: NDP end indication type + * @reason_code: NDP end indication reason code + * @ndp_instance_id: NDP instance ID + * + */ +struct peer_ndp_map { + uint32_t vdev_id; + struct qdf_mac_addr peer_ndi_mac_addr; + uint32_t num_active_ndp_sessions; + enum ndp_end_type type; + enum ndp_end_reason_code reason_code; + uint32_t ndp_instance_id; +}; + +/** + * struct ndp_end_rsp_event - firmware response to ndp end request + * @transaction_id: unique identifier for the request + * @status: status of operation + * @reason: reason(opaque to host driver) + * + */ +struct ndp_end_rsp_event { + uint32_t transaction_id; + uint32_t status; + uint32_t reason; +}; + +/** + * struct ndp_end_indication_event - ndp termination notification from FW + * @num_ndp_ids: number of NDP ids + * @ndp_map: mapping of NDP instances to peer and vdev + * + */ +struct ndp_end_indication_event { + uint32_t num_ndp_ids; + struct peer_ndp_map ndp_map[]; +}; + +/** + * struct ndp_schedule_update_req - ndp schedule update request + * @transaction_id: unique identifier + * @vdev_id: session id of the interface over which ndp is being created + * @ndp_instance_id: ndp instance id for which schedule update is requested + * @ndp_qos: new set of qos parameters + * + */ +struct ndp_schedule_update_req { + uint32_t transaction_id; + uint32_t vdev_id; + uint32_t ndp_instance_id; + struct ndp_qos_cfg ndp_qos; +}; + +/** + * struct ndp_schedule_update_rsp - ndp schedule update response + * @transaction_id: unique identifier + * @vdev_id: session id of the interface over which ndp is being created + * @status: status of the request + * @reason: reason code for failure if any + * + */ +struct ndp_schedule_update_rsp { + uint32_t transaction_id; + uint32_t vdev_id; + uint32_t status; + uint32_t reason; +}; + +/** + * struct sme_ndp_peer_ind - ndp peer indication + * @msg_type: message id + * @msg_len: message length + * @session_id: session id + * @peer_mac_addr: peer mac address + * @sta_id: station id + * + */ +struct sme_ndp_peer_ind { + uint16_t msg_type; + uint16_t msg_len; + uint8_t session_id; + struct qdf_mac_addr peer_mac_addr; + uint16_t sta_id; +}; + +#endif /* WLAN_FEATURE_NAN_DATAPATH */ + +/** + * struct sir_set_tx_rx_aggregation_size - sets tx rx aggregation size + * @vdev_id: vdev id of the session + * @tx_aggregation_size: Tx aggregation size + * @rx_aggregation_size: Rx aggregation size + */ +struct sir_set_tx_rx_aggregation_size { + uint8_t vdev_id; + uint32_t tx_aggregation_size; + uint32_t rx_aggregation_size; +}; + +/** + * struct sir_p2p_lo_start - p2p listen offload start + * @vdev_id: vdev identifier + * @ctl_flags: control flag + * @freq: p2p listen frequency + * @period: listen offload period + * @interval: listen offload interval + * @count: number listen offload intervals + * @device_types: device types + * @dev_types_len: device types length + * @probe_resp_tmplt: probe response template + * @probe_resp_len: probe response template length + */ +struct sir_p2p_lo_start { + uint32_t vdev_id; + uint32_t ctl_flags; + uint32_t freq; + uint32_t period; + uint32_t interval; + uint32_t count; + uint8_t *device_types; + uint32_t dev_types_len; + uint8_t *probe_resp_tmplt; + uint32_t probe_resp_len; +}; + +/** + * struct sir_p2p_lo_event - P2P listen offload stop event + * @vdev_id: vdev identifier + * @reason_code: P2P listen offload stop reason + */ +struct sir_p2p_lo_event { + uint32_t vdev_id; + uint32_t reason_code; +}; + +/** + * struct sir_hal_pwr_dbg_cmd - unit test command parameters + * @pdev_id: pdev id + * @module_id: module id + * @num_args: number of arguments + * @args: arguments + */ +struct sir_mac_pwr_dbg_cmd { + uint32_t pdev_id; + uint32_t module_id; + uint32_t num_args; + uint32_t args[MAX_POWER_DBG_ARGS_SUPPORTED]; +}; + +/** + * struct sme_send_disassoc_frm_req - send disassoc request frame + * @msg_type: message type + * @length: length of message + * @session_id: session id + * @trans_id: transaction id + * @peer_mac: peer mac address + * @reason: reason for disassoc + * @wait_for_ack: wait for acknowledgment + **/ + struct sme_send_disassoc_frm_req { + uint16_t msg_type; + uint16_t length; + uint8_t session_id; + uint16_t trans_id; + uint8_t peer_mac[6]; + uint16_t reason; + uint8_t wait_for_ack; + }; + +/** + * struct sme_update_access_policy_vendor_ie - update vendor ie and access + * policy + * @msg_type: message id + * @msg_len: message length + * @sme_session_id: sme session id + * @ie: vendor ie + * @access_policy: access policy for vendor ie + */ +struct sme_update_access_policy_vendor_ie { + uint16_t msg_type; + uint16_t length; + uint32_t sme_session_id; + uint8_t ie[SIR_MAC_MAX_IE_LENGTH]; + uint8_t access_policy; +}; + +/** + * struct sir_encrypt_decrypt_rsp_params - encrypt/decrypt rsp params + * @vdev_id: vdev id + * @status: status + * @data_length: data length + * @data: data pointer + */ +struct sir_encrypt_decrypt_rsp_params { + uint32_t vdev_id; + int32_t status; + uint32_t data_length; + uint8_t *data; +}; + +/** + * struct sme_tx_fail_cnt_threshold - tx failure count for disconnect to fw + * @session_id: Session id + * @tx_fail_cnt_threshold: Tx failure count to do disconnect + */ +struct sme_tx_fail_cnt_threshold { + uint8_t session_id; + uint32_t tx_fail_cnt_threshold; +}; + +/** + * struct sme_short_retry_limit - transmission retry limit for short frames. + * @session_id: Session id + * @short_retry_limit: tranmission retry limit for short frame. + * + */ +struct sme_short_retry_limit { + uint8_t session_id; + uint32_t short_retry_limit; +}; + +/** + * struct sme_long_retry_limit - tranmission retry limit for long frames + * @session_id: Session id + * @short_retry_limit: tranmission retry limit for long frames. + * + */ +struct sme_long_retry_limit { + uint8_t session_id; + uint32_t long_retry_limit; +}; + +/** + * struct sme_sta_inactivity_timeout - set sta_inactivity_timeout + * @session_id: session Id. + * @sta_inactivity_timeout: Timeout to disconnect STA after there + * is no activity. + */ +struct sme_sta_inactivity_timeout { + uint8_t session_id; + uint32_t sta_inactivity_timeout; +}; + +/* + * struct wow_pulse_mode - WoW Pulse set cmd struct + * @wow_pulse_enable: enable or disable this feature + * @wow_pulse_pin: GPIO PIN for Pulse + * @wow_pulse_interval_low: Pulse interval low + * @wow_pulse_interval_high: Pulse interval high + * + * SME uses this structure to configure wow pulse info + * and send it to WMA + */ +struct wow_pulse_mode { + bool wow_pulse_enable; + uint8_t wow_pulse_pin; + uint16_t wow_pulse_interval_high; + uint16_t wow_pulse_interval_low; +}; + +/* + * struct udp_resp_offload - the basic info structure + * @vdev_id: vdev id + * @dest_port: specific UDP dest port + * @udp_payload_filter: specific UDP payload filter + * @udp_response_payload: response UDP oayload + * + * driver use this structure to configure fw specific + * udp offload filter and response udp info + */ +struct udp_resp_offload { + uint32_t vdev_id; + uint32_t enable; + uint32_t dest_port; + char udp_payload_filter[MAX_LEN_UDP_RESP_OFFLOAD]; + char udp_response_payload[MAX_LEN_UDP_RESP_OFFLOAD]; +}; + +typedef void (*sme_rcpi_callback)(void *context, struct qdf_mac_addr mac_addr, + int32_t rcpi, QDF_STATUS status); +/** + * struct sme_rcpi_req - structure for querying rcpi info + * @session_id: session for which rcpi is required + * @measurement_type: type of measurement from enum rcpi_measurement_type + * @rcpi_callback: callback function to be invoked for rcpi response + * @rcpi_context: context info for rcpi callback + * @mac_addr: peer addr for which rcpi is required + */ +struct sme_rcpi_req { + uint32_t session_id; + enum rcpi_measurement_type measurement_type; + sme_rcpi_callback rcpi_callback; + void *rcpi_context; + struct qdf_mac_addr mac_addr; +}; + +/** + * struct rsp_stats - arp packet stats + * @arp_req_enqueue: fw tx count + * @arp_req_tx_success: tx ack count + * @arp_req_tx_failure: tx ack fail count + * @arp_rsp_recvd: rx fw count + * @out_of_order_arp_rsp_drop_cnt: out of order count + * @dad_detected: dad detected + * @connect_status: connection status + * @ba_session_establishment_status: BA session status + */ +struct rsp_stats { + uint32_t vdev_id; + uint32_t arp_req_enqueue; + uint32_t arp_req_tx_success; + uint32_t arp_req_tx_failure; + uint32_t arp_rsp_recvd; + uint32_t out_of_order_arp_rsp_drop_cnt; + uint32_t dad_detected; + uint32_t connect_status; + uint32_t ba_session_establishment_status; +}; + +/** + * struct set_arp_stats_params - set/reset arp stats + * @vdev_id: session id + * @flag: enable/disable stats + * @pkt_type: type of packet(1 - arp) + * @ip_addr: subnet ipv4 address in case of encrypted packets + */ +struct set_arp_stats_params { + uint32_t vdev_id; + uint8_t flag; + uint8_t pkt_type; + uint32_t ip_addr; +}; + +/** + * struct get_arp_stats_params - get arp stats from firmware + * @pkt_type: packet type(1 - ARP) + * @vdev_id: session id + */ +struct get_arp_stats_params { + uint8_t pkt_type; + uint32_t vdev_id; +}; + +/** + * struct sir_del_all_tdls_peers - delete all tdls peers + * @msg_type: type of message + * @msg_len: length of message + * @bssid: bssid of peer device + */ +struct sir_del_all_tdls_peers { + uint16_t msg_type; + uint16_t msg_len; + struct qdf_mac_addr bssid; +}; + +#endif /* __SIR_API_H */ diff --git a/drivers/staging/qcacld-3.0/core/mac/inc/sir_mac_prop_exts.h b/drivers/staging/qcacld-3.0/core/mac/inc/sir_mac_prop_exts.h new file mode 100644 index 0000000000000000000000000000000000000000..260e081be46cb7d4afd56a45e8e72ce5d74aa99f --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/inc/sir_mac_prop_exts.h @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2011-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * + * This file sir_mac_prop_exts.h contains the MAC protocol + * extensions to support ANI feature set. + * Author: Chandra Modumudi + * Date: 11/27/02 + */ +#ifndef __MAC_PROP_EXTS_H +#define __MAC_PROP_EXTS_H + +#include "sir_types.h" +#include "sir_api.h" +#include "ani_system_defs.h" + +/* / EID (Element ID) definitions */ + +#define PROP_CAPABILITY_GET(bitname, value) \ + (((value) >> SIR_MAC_PROP_CAPABILITY_ ## bitname) & 1) + +#define IS_DOT11_MODE_HT(dot11Mode) \ + (((dot11Mode == WNI_CFG_DOT11_MODE_11N) || \ + (dot11Mode == WNI_CFG_DOT11_MODE_11N_ONLY) || \ + (dot11Mode == WNI_CFG_DOT11_MODE_11AC) || \ + (dot11Mode == WNI_CFG_DOT11_MODE_11AC_ONLY) || \ + (dot11Mode == WNI_CFG_DOT11_MODE_ALL)) ? true:false) + +#define IS_DOT11_MODE_VHT(dot11Mode) \ + (((dot11Mode == WNI_CFG_DOT11_MODE_11AC) || \ + (dot11Mode == WNI_CFG_DOT11_MODE_11AC_ONLY) || \ + (dot11Mode == WNI_CFG_DOT11_MODE_ALL)) ? true:false) + +#define IS_DOT11_MODE_11B(dot11Mode) \ + ((dot11Mode == WNI_CFG_DOT11_MODE_11B) ? true:false) + +#define IS_BSS_VHT_CAPABLE(vhtCaps) \ + ((vhtCaps).present && \ + ((vhtCaps).rxMCSMap != 0xFFFF) && \ + ((vhtCaps).txMCSMap != 0xFFFF)) + +#define WNI_CFG_VHT_CHANNEL_WIDTH_20_40MHZ 0 +#define WNI_CFG_VHT_CHANNEL_WIDTH_80MHZ 1 +#define WNI_CFG_VHT_CHANNEL_WIDTH_160MHZ 2 +#define WNI_CFG_VHT_CHANNEL_WIDTH_80_PLUS_80MHZ 3 + +/* / Proprietary IE definition */ +typedef struct sSirMacPropIE { + uint8_t elementID; /* SIR_MAC_ANI_PROP_IE_EID */ + uint8_t length; + uint8_t oui[3]; /* ANI_OUI for Airgo products */ + uint8_t info[1]; +} tSirMacPropIE, *tpSirMacPropIE; + +typedef struct sSirMacPropRateSet { + uint8_t numPropRates; + uint8_t propRate[8]; +} tSirMacPropRateSet, *tpSirMacPropRateSet; + +#define SIR_PROP_VERSION_STR_MAX 20 +typedef struct sSirMacPropVersion { + uint32_t chip_rev; /* board, chipset info */ + uint8_t card_type; /* Type of Card */ + /* build version string */ + uint8_t build_version[SIR_PROP_VERSION_STR_MAX]; +} tSirMacPropVersion, *tpSirMacPropVersion; + +/* Default value for gLimRestoreCBNumScanInterval */ +#define LIM_RESTORE_CB_NUM_SCAN_INTERVAL_DEFAULT 2 + +/* generic proprietary IE structure definition */ +typedef struct sSirPropIEStruct { + uint8_t propRatesPresent:1; + uint8_t apNamePresent:1; + uint8_t loadBalanceInfoPresent:1; + uint8_t versionPresent:1; + uint8_t edcaParamPresent:1; + uint8_t capabilityPresent:1; + uint8_t propChannelSwitchPresent:1; + uint8_t triggerStaScanPresent:1; + uint8_t rsvd:8; + + tSirMacPropRateSet propRates; + tAniApName apName; /* used in beacon/probe only */ + uint16_t capability; /* capability bit map */ + tSirMacPropVersion version; + tSirMacEdcaParamSetIE edca; + uint8_t triggerStaScanEnable; + +} tSirPropIEStruct, *tpSirPropIEStruct; + +#endif /* __MAC_PROP_EXTS_H */ diff --git a/drivers/staging/qcacld-3.0/core/mac/inc/sir_mac_prot_def.h b/drivers/staging/qcacld-3.0/core/mac/inc/sir_mac_prot_def.h new file mode 100644 index 0000000000000000000000000000000000000000..be47e13d7ba3bf9bb614f3f5760cf2a8f239c2f1 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/inc/sir_mac_prot_def.h @@ -0,0 +1,2177 @@ +/* + * Copyright (c) 2011-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + + +/* + * This file sir_mac_prot_def.h contains the MAC/PHY protocol + * definitions used across various projects. + */ + +#ifndef __MAC_PROT_DEFS_H +#define __MAC_PROT_DEFS_H + +#include + +#include "cds_api.h" +#include "sir_types.h" +#include "wni_cfg.h" + +/* /Capability information related */ +#define CAPABILITY_INFO_DELAYED_BA_BIT 14 +#define CAPABILITY_INFO_IMMEDIATE_BA_BIT 15 + +/* / 11h MAC defaults */ +#define SIR_11A_CHANNEL_BEGIN 34 +#define SIR_11A_CHANNEL_END 165 +#define SIR_11B_CHANNEL_BEGIN 1 +#define SIR_11B_CHANNEL_END 14 +#define SIR_11A_FREQUENCY_OFFSET 4 +#define SIR_11B_FREQUENCY_OFFSET 1 +#define SIR_11P_CHANNEL_BEGIN 170 +#define SIR_11P_CHANNEL_END 184 + +/* / Current version of 802.11 */ +#define SIR_MAC_PROTOCOL_VERSION 0 + +/* Frame Type definitions */ + +#define SIR_MAC_MGMT_FRAME 0x0 +#define SIR_MAC_CTRL_FRAME 0x1 +#define SIR_MAC_DATA_FRAME 0x2 + +#define SIR_MAC_FRAME_TYPE_START 0x0 +#define SIR_MAC_FRAME_TYPE_END 0x3 + +/* Control frame subtype definitions */ + +#define SIR_MAC_CTRL_RR 4 +#define SIR_MAC_CTRL_BAR 8 +#define SIR_MAC_CTRL_BA 9 +#define SIR_MAC_CTRL_PS_POLL 10 +#define SIR_MAC_CTRL_RTS 11 +#define SIR_MAC_CTRL_CTS 12 +#define SIR_MAC_CTRL_ACK 13 +#define SIR_MAC_CTRL_CF_END 14 +#define SIR_MAC_CTRL_CF_END_ACK 15 + +#define SIR_MAC_MAX_DURATION_MICRO_SECONDS 32767 + +/* Data frame subtype definitions */ +#define SIR_MAC_DATA_DATA 0 +#define SIR_MAC_DATA_DATA_ACK 1 +#define SIR_MAC_DATA_DATA_POLL 2 +#define SIR_MAC_DATA_DATA_ACK_POLL 3 +#define SIR_MAC_DATA_NULL 4 +#define SIR_MAC_DATA_NULL_ACK 5 +#define SIR_MAC_DATA_NULL_POLL 6 +#define SIR_MAC_DATA_NULL_ACK_POLL 7 +#define SIR_MAC_DATA_QOS_DATA 8 +#define SIR_MAC_DATA_QOS_DATA_ACK 9 +#define SIR_MAC_DATA_QOS_DATA_POLL 10 +#define SIR_MAC_DATA_QOS_DATA_ACK_POLL 11 +#define SIR_MAC_DATA_QOS_NULL 12 +#define SIR_MAC_DATA_QOS_NULL_ACK 13 +#define SIR_MAC_DATA_QOS_NULL_POLL 14 +#define SIR_MAC_DATA_QOS_NULL_ACK_POLL 15 + +#define SIR_MAC_FRAME_SUBTYPE_START 0 +#define SIR_MAC_FRAME_SUBTYPE_END 16 + +#define SIR_MAC_DATA_QOS_MASK 8 +#define SIR_MAC_DATA_NULL_MASK 4 +#define SIR_MAC_DATA_POLL_MASK 2 +#define SIR_MAC_DATA_ACK_MASK 1 + +/* Management frame subtype definitions */ + +#define SIR_MAC_MGMT_ASSOC_REQ 0x0 +#define SIR_MAC_MGMT_ASSOC_RSP 0x1 +#define SIR_MAC_MGMT_REASSOC_REQ 0x2 +#define SIR_MAC_MGMT_REASSOC_RSP 0x3 +#define SIR_MAC_MGMT_PROBE_REQ 0x4 +#define SIR_MAC_MGMT_PROBE_RSP 0x5 +#define SIR_MAC_MGMT_TIME_ADVERT 0x6 +#define SIR_MAC_MGMT_BEACON 0x8 +#define SIR_MAC_MGMT_ATIM 0x9 +#define SIR_MAC_MGMT_DISASSOC 0xA +#define SIR_MAC_MGMT_AUTH 0xB +#define SIR_MAC_MGMT_DEAUTH 0xC +#define SIR_MAC_MGMT_ACTION 0xD +#define SIR_MAC_MGMT_RESERVED15 0xF + +/* Action frame categories */ + +#define SIR_MAC_ACTION_SPECTRUM_MGMT 0 +#define SIR_MAC_ACTION_QOS_MGMT 1 +#define SIR_MAC_ACTION_DLP 2 +#define SIR_MAC_ACTION_BLKACK 3 +#define SIR_MAC_ACTION_PUBLIC_USAGE 4 +#define SIR_MAC_ACTION_RRM 5 +#define SIR_MAC_ACTION_FAST_BSS_TRNST 6 +#define SIR_MAC_ACTION_HT 7 +#define SIR_MAC_ACTION_SA_QUERY 8 +#define SIR_MAC_ACTION_PROT_DUAL_PUB 9 +#define SIR_MAC_ACTION_WNM 10 +#define SIR_MAC_ACTION_UNPROT_WNM 11 +#define SIR_MAC_ACTION_TDLS 12 +#define SIR_MAC_ACITON_MESH 13 +#define SIR_MAC_ACTION_MHF 14 +#define SIR_MAC_SELF_PROTECTED 15 +#define SIR_MAC_ACTION_WME 17 +#define SIR_MAC_ACTION_FST 18 +#define SIR_MAC_ACTION_VHT 21 +#define SIR_MAC_ACTION_MAX 256 + +#define SIR_MAC_ACTION_TX 1 +#define SIR_MAC_ACTION_RX 2 + +/* QoS management action codes */ + +#define SIR_MAC_QOS_ADD_TS_REQ 0 +#define SIR_MAC_QOS_ADD_TS_RSP 1 +#define SIR_MAC_QOS_DEL_TS_REQ 2 +#define SIR_MAC_QOS_SCHEDULE 3 +#define SIR_MAC_QOS_MAP_CONFIGURE 4 +/* and these are proprietary */ +#define SIR_MAC_QOS_DEF_BA_REQ 4 +#define SIR_MAC_QOS_DEF_BA_RSP 5 + +#ifdef ANI_SUPPORT_11H +#define SIR_MAC_ACTION_MEASURE_REQUEST_ID 0 +#define SIR_MAC_ACTION_MEASURE_REPORT_ID 1 +#define SIR_MAC_ACTION_TPC_REQUEST_ID 2 +#define SIR_MAC_ACTION_TPC_REPORT_ID 3 +#endif /* ANI_SUPPORT_11H */ +#define SIR_MAC_ACTION_CHANNEL_SWITCH_ID 4 + +#ifdef ANI_SUPPORT_11H +#define SIR_MAC_BASIC_MEASUREMENT_TYPE 0 +#define SIR_MAC_CCA_MEASUREMENT_TYPE 1 +#define SIR_MAC_RPI_MEASUREMENT_TYPE 2 +#endif /* ANI_SUPPORT_11H */ + +/* RRM related. */ +/* Refer IEEE Std 802.11k-2008, Section 7.3.2.21, table 7.29 */ + +#define SIR_MAC_RRM_CHANNEL_LOAD_TYPE 3 +#define SIR_MAC_RRM_NOISE_HISTOGRAM_BEACON 4 +#define SIR_MAC_RRM_BEACON_TYPE 5 +#define SIR_MAC_RRM_FRAME_TYPE 6 +#define SIR_MAC_RRM_STA_STATISTICS_TYPE 7 +#define SIR_MAC_RRM_LCI_TYPE 8 +#define SIR_MAC_RRM_TSM_TYPE 9 +#define SIR_MAC_RRM_LOCATION_CIVIC_TYPE 11 +#define SIR_MAC_RRM_FINE_TIME_MEAS_TYPE 16 + +/* RRM action codes */ +#define SIR_MAC_RRM_RADIO_MEASURE_REQ 0 +#define SIR_MAC_RRM_RADIO_MEASURE_RPT 1 +#define SIR_MAC_RRM_LINK_MEASUREMENT_REQ 2 +#define SIR_MAC_RRM_LINK_MEASUREMENT_RPT 3 +#define SIR_MAC_RRM_NEIGHBOR_REQ 4 +#define SIR_MAC_RRM_NEIGHBOR_RPT 5 + +/* VHT Action Field */ +#define SIR_MAC_VHT_GID_NOTIFICATION 1 +#define SIR_MAC_VHT_OPMODE_NOTIFICATION 2 + +#define NUM_OF_SOUNDING_DIMENSIONS 1 /*Nss - 1, (Nss = 2 for 2x2)*/ +/* HT Action Field Codes */ +#define SIR_MAC_SM_POWER_SAVE 1 + +/* DLP action frame types */ +#define SIR_MAC_DLP_REQ 0 +#define SIR_MAC_DLP_RSP 1 +#define SIR_MAC_DLP_TEARDOWN 2 + +/* block acknowledgement action frame types */ +#define SIR_MAC_ACTION_VENDOR_SPECIFIC 9 +#define SIR_MAC_ACTION_VENDOR_SPECIFIC_CATEGORY 0x7F +#define SIR_MAC_ACTION_P2P_SUBTYPE_PRESENCE_RSP 2 + +/* Public Action for 20/40 BSS Coexistence */ +#define SIR_MAC_ACTION_2040_BSS_COEXISTENCE 0 +#define SIR_MAC_ACTION_EXT_CHANNEL_SWITCH_ID 4 + + +#ifdef WLAN_FEATURE_11W +/* 11w SA query request/response action frame category code */ +#define SIR_MAC_SA_QUERY_REQ 0 +#define SIR_MAC_SA_QUERY_RSP 1 +#endif + +#ifdef FEATURE_WLAN_TDLS +#define SIR_MAC_TDLS_SETUP_REQ 0 +#define SIR_MAC_TDLS_SETUP_RSP 1 +#define SIR_MAC_TDLS_SETUP_CNF 2 +#define SIR_MAC_TDLS_TEARDOWN 3 +#define SIR_MAC_TDLS_PEER_TRAFFIC_IND 4 +#define SIR_MAC_TDLS_CH_SWITCH_REQ 5 +#define SIR_MAC_TDLS_CH_SWITCH_RSP 6 +#define SIR_MAC_TDLS_PEER_TRAFFIC_RSP 9 +#define SIR_MAC_TDLS_DIS_REQ 10 +#define SIR_MAC_TDLS_DIS_RSP 14 +#endif + +/* WNM Action field values; IEEE Std 802.11-2012, 8.5.14.1, Table 8-250 */ +#define SIR_MAC_WNM_BSS_TM_QUERY 6 +#define SIR_MAC_WNM_BSS_TM_REQUEST 7 +#define SIR_MAC_WNM_BSS_TM_RESPONSE 8 +#define SIR_MAC_WNM_NOTIF_REQUEST 26 +#define SIR_MAC_WNM_NOTIF_RESPONSE 27 + +/* Protected Dual of Public Action(PDPA) frames Action field */ +#define SIR_MAC_PDPA_GAS_INIT_REQ 10 +#define SIR_MAC_PDPA_GAS_INIT_RSP 11 +#define SIR_MAC_PDPA_GAS_COMEBACK_REQ 12 +#define SIR_MAC_PDPA_GAS_COMEBACK_RSP 13 + +#define SIR_MAC_MAX_RANDOM_LENGTH 2306 + +/* ----------------------------------------------------------------------------- */ +/* EID (Element ID) definitions */ +/* and their min/max lengths */ +/* ----------------------------------------------------------------------------- */ + +#define SIR_MAC_SSID_EID 0 +#define SIR_MAC_SSID_EID_MIN 0 +#define SIR_MAC_SSID_EID_MAX 32 +#define SIR_MAC_RATESET_EID 1 +#define SIR_MAC_RATESET_EID_MIN 1 +#define SIR_MAC_RATESET_EID_MAX 12 +#define SIR_MAC_FH_PARAM_SET_EID 2 +#define SIR_MAC_FH_PARAM_SET_EID_MIN 5 +#define SIR_MAC_FH_PARAM_SET_EID_MAX 5 +#define SIR_MAC_DS_PARAM_SET_EID 3 +#define SIR_MAC_DS_PARAM_SET_EID_MIN 1 +#define SIR_MAC_DS_PARAM_SET_EID_MAX 1 +#define SIR_MAC_CF_PARAM_SET_EID 4 +#define SIR_MAC_CF_PARAM_SET_EID_MIN 6 +#define SIR_MAC_CF_PARAM_SET_EID_MAX 6 +#define SIR_MAC_TIM_EID 5 +#define SIR_MAC_TIM_EID_MIN 3 +#define SIR_MAC_TIM_EID_MAX 254 +#define SIR_MAC_IBSS_PARAM_SET_EID 6 +#define SIR_MAC_IBSS_PARAM_SET_EID_MIN 2 +#define SIR_MAC_IBSS_PARAM_SET_EID_MAX 2 +#define SIR_MAC_COUNTRY_EID 7 +#define SIR_MAC_COUNTRY_EID_MIN 6 +#define SIR_MAC_COUNTRY_EID_MAX 254 +#define SIR_MAC_FH_PARAMS_EID 8 +#define SIR_MAC_FH_PARAMS_EID_MIN 4 +#define SIR_MAC_FH_PARAMS_EID_MAX 4 +#define SIR_MAC_FH_PATTERN_EID 9 +#define SIR_MAC_FH_PATTERN_EID_MIN 4 +#define SIR_MAC_FH_PATTERN_EID_MAX 254 +#define SIR_MAC_REQUEST_EID 10 +#define SIR_MAC_REQUEST_EID_MIN 1 +#define SIR_MAC_REQUEST_EID_MAX 255 +#define SIR_MAC_QBSS_LOAD_EID 11 +#define SIR_MAC_QBSS_LOAD_EID_MIN 5 +#define SIR_MAC_QBSS_LOAD_EID_MAX 5 +#define SIR_MAC_EDCA_PARAM_SET_EID 12 /* EDCA parameter set */ +#define SIR_MAC_EDCA_PARAM_SET_EID_MIN 18 +#define SIR_MAC_EDCA_PARAM_SET_EID_MAX 20 /* TBD temp - change backto 18 */ +#define SIR_MAC_TSPEC_EID 13 +#define SIR_MAC_TSPEC_EID_MIN 55 +#define SIR_MAC_TSPEC_EID_MAX 55 +#define SIR_MAC_TCLAS_EID 14 +#define SIR_MAC_TCLAS_EID_MIN 4 +#define SIR_MAC_TCLAS_EID_MAX 255 +#define SIR_MAC_QOS_SCHEDULE_EID 15 +#define SIR_MAC_QOS_SCHEDULE_EID_MIN 14 +#define SIR_MAC_QOS_SCHEDULE_EID_MAX 14 +#define SIR_MAC_CHALLENGE_TEXT_EID 16 +#define SIR_MAC_CHALLENGE_TEXT_EID_MIN 1 +#define SIR_MAC_CHALLENGE_TEXT_EID_MAX 253 +/* reserved 17-31 */ +#define SIR_MAC_PWR_CONSTRAINT_EID 32 +#define SIR_MAC_PWR_CONSTRAINT_EID_MIN 1 +#define SIR_MAC_PWR_CONSTRAINT_EID_MAX 1 +#define SIR_MAC_PWR_CAPABILITY_EID 33 +#define SIR_MAC_PWR_CAPABILITY_EID_MIN 2 +#define SIR_MAC_PWR_CAPABILITY_EID_MAX 2 +#define SIR_MAC_TPC_REQ_EID 34 +#define SIR_MAC_TPC_REQ_EID_MIN 0 +#define SIR_MAC_TPC_REQ_EID_MAX 255 +/* SIR_MAC_EXTENDED_CAP_EID 35 */ +#define SIR_MAC_TPC_RPT_EID 35 +#define SIR_MAC_TPC_RPT_EID_MIN 2 +#define SIR_MAC_TPC_RPT_EID_MAX 2 +#define SIR_MAC_SPRTD_CHNLS_EID 36 +#define SIR_MAC_SPRTD_CHNLS_EID_MIN 2 +#define SIR_MAC_SPRTD_CHNLS_EID_MAX 254 +#define SIR_MAC_CHNL_SWITCH_ANN_EID 37 +#define SIR_MAC_CHNL_SWITCH_ANN_EID_MIN 3 +#define SIR_MAC_CHNL_SWITCH_ANN_EID_MAX 3 +#define SIR_MAC_MEAS_REQ_EID 38 +#define SIR_MAC_MEAS_REQ_EID_MIN 3 +#define SIR_MAC_MEAS_REQ_EID_MAX 255 +#define SIR_MAC_MEAS_RPT_EID 39 +#define SIR_MAC_MEAS_RPT_EID_MIN 3 +#define SIR_MAC_MEAS_RPT_EID_MAX 255 +#define SIR_MAC_QUIET_EID 40 +#define SIR_MAC_QUIET_EID_MIN 6 +#define SIR_MAC_QUIET_EID_MAX 6 +#define SIR_MAC_IBSS_DFS_EID 41 +#define SIR_MAC_IBSS_DFS_EID_MIN 7 +#define SIR_MAC_IBSS_DFS_EID_MAX 255 +#define SIR_MAC_ERP_INFO_EID 42 +#define SIR_MAC_ERP_INFO_EID_MIN 0 +#define SIR_MAC_ERP_INFO_EID_MAX 255 +#define SIR_MAC_TS_DELAY_EID 43 +#define SIR_MAC_TS_DELAY_EID_MIN 4 +#define SIR_MAC_TS_DELAY_EID_MAX 4 +#define SIR_MAC_TCLAS_PROC_EID 44 +#define SIR_MAC_TCLAS_PROC_EID_MIN 1 +#define SIR_MAC_TCLAS_PROC_EID_MAX 1 +#define SIR_MAC_QOS_CAPABILITY_EID 46 +#define SIR_MAC_QOS_CAPABILITY_EID_MIN 1 +#define SIR_MAC_QOS_CAPABILITY_EID_MAX 1 +#define SIR_MAC_RSN_EID 48 +#define SIR_MAC_RSN_EID_MIN 4 +#define SIR_MAC_RSN_EID_MAX 254 + +/* using reserved EID for Qos Action IE for now, */ +/* need to check 11e spec for the actual EID */ +#define SIR_MAC_QOS_ACTION_EID 49 +#define SIR_MAC_QOS_ACTION_EID_MIN 4 +#define SIR_MAC_QOS_ACTION_EID_MAX 255 +#define SIR_MAC_EXTENDED_RATE_EID 50 +#define SIR_MAC_EXTENDED_RATE_EID_MIN 0 +#define SIR_MAC_EXTENDED_RATE_EID_MAX 255 +#define SIR_MAC_CHNL_EXTENDED_SWITCH_ANN_EID 60 +#define SIR_MAC_CHNL_EXTENDED_SWITCH_ANN_EID_MIN 0 +#define SIR_MAC_CHNL_EXTENDED_SWITCH_ANN_EID_MAX 255 + +#define SIR_MAC_OPERATING_CLASS_EID 59 +#define SIR_MAC_OPERATING_CLASS_EID_MIN 2 +#define SIR_MAC_OPERATING_CLASS_EID_MAX 253 +/* reserved 51-69 */ +#define SIR_MAC_RM_ENABLED_CAPABILITY_EID 70 +#define SIR_MAC_RM_ENABLED_CAPABILITY_EID_MIN 5 +#define SIR_MAC_RM_ENABLED_CAPABILITY_EID_MAX 5 +/* reserved 71-220 */ +#define SIR_MAC_WPA_EID 221 +#define SIR_MAC_WPA_EID_MIN 0 +#define SIR_MAC_WPA_EID_MAX 255 + +#define SIR_MAC_EID_VENDOR 221 + +#define SIR_MAC_WAPI_EID 68 +/* reserved 222-254 */ +#define SIR_MAC_HT_CAPABILITIES_EID 45 +#define SIR_MAC_HT_CAPABILITIES_EID_MIN 0 +#define SIR_MAC_HT_CAPABILITIES_EID_MAX 255 +#define SIR_MAC_HT_INFO_EID 61 +#define SIR_MAC_HT_INFO_EID_MIN 0 +#define SIR_MAC_HT_INFO_EID_MAX 255 + +#define SIR_MAC_VHT_CAPABILITIES_EID 191 +#define SIR_MAC_VHT_OPERATION_EID 192 +#define SIR_MAC_VHT_EXT_BSS_LOAD_EID 193 +#define SIR_MAC_VHT_OPMODE_EID 199 +#define SIR_MAC_MAX_SUPPORTED_MCS_SET 16 + +#define VHT_RX_HIGHEST_SUPPORTED_DATA_RATE_1_1 390 +#define VHT_TX_HIGHEST_SUPPORTED_DATA_RATE_1_1 390 +#define VHT_RX_HIGHEST_SUPPORTED_DATA_RATE_2_2 780 +#define VHT_TX_HIGHEST_SUPPORTED_DATA_RATE_2_2 780 + +#define VHT_CAP_80_SUPP 0 +#define VHT_CAP_160_SUPP 1 +#define VHT_CAP_160_AND_80P80_SUPP 2 + +#define VHT_MCS_1x1 0xFFFC +#define VHT_MCS_2x2 0xFFF3 + +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE +#define SIR_MAC_QCOM_VENDOR_EID 200 +#define SIR_MAC_QCOM_VENDOR_OUI "\x00\xA0\xC6" +#define SIR_MAC_QCOM_VENDOR_SIZE 3 +#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ + +/* / Workaround IE to change beacon length when it is 4*n+1 */ +#define SIR_MAC_ANI_WORKAROUND_EID 255 +#define SIR_MAC_ANI_WORKAROUND_EID_MIN 0 +#define SIR_MAC_ANI_WORKAROUND_EID_MAX 255 + +#define SIR_MAC_MAX_ADD_IE_LENGTH 500 + +/* / Maximum length of each IE */ +#define SIR_MAC_MAX_IE_LENGTH 255 + +/* / Maximum length of each IE */ +#define SIR_MAC_RSN_IE_MAX_LENGTH 255 +/* / Minimum length of each IE */ +#define SIR_MAC_RSN_IE_MIN_LENGTH 2 +#define SIR_MAC_WPA_IE_MIN_LENGTH 6 + +#ifdef FEATURE_WLAN_ESE +#define ESE_VERSION_4 4 +#define ESE_VERSION_SUPPORTED ESE_VERSION_4 + +/* When station sends Radio Management Cap. */ +/* State should be normal=1 */ +/* Mbssid Mask should be 0 */ +#define RM_STATE_NORMAL 1 +#endif + +#define SIR_MAC_OUI_VERSION_1 1 + +/* OUI and type definition for WPA IE in network byte order */ +#define SIR_MAC_WPA_OUI 0x01F25000 +#define SIR_MAC_WME_OUI 0x02F25000 +#define SIR_MAC_WSM_OUI SIR_MAC_WME_OUI +#define SIR_MAC_WSC_OUI "\x00\x50\xf2\x04" +#define SIR_MAC_WSC_OUI_SIZE 4 +#define SIR_MAC_P2P_OUI "\x50\x6f\x9a\x09" +#define SIR_MAC_P2P_OUI_SIZE 4 +#define SIR_P2P_NOA_ATTR 12 +#define SIR_MAX_NOA_ATTR_LEN 31 +#define SIR_MAX_NOA_DESCR 2 +#define SIR_P2P_IE_HEADER_LEN 6 + +#define SIR_MAC_CISCO_OUI "\x00\x40\x96" +#define SIR_MAC_CISCO_OUI_SIZE 3 + +/* min size of wme oui header: oui(3) + type + subtype + version */ +#define SIR_MAC_OUI_WME_HDR_MIN 6 + +/* OUI subtype and their lengths */ +#define SIR_MAC_OUI_SUBTYPE_WME_INFO 0 +#define SIR_MAC_OUI_WME_INFO_MIN 7 +#define SIR_MAC_OUI_WME_INFO_MAX 7 + +#define SIR_MAC_OUI_SUBTYPE_WME_PARAM 1 +#define SIR_MAC_OUI_WME_PARAM_MIN 24 +#define SIR_MAC_OUI_WME_PARAM_MAX 24 + +#define SIR_MAC_OUI_SUBTYPE_WME_TSPEC 2 +#define SIR_MAC_OUI_WME_TSPEC_MIN 61 +#define SIR_MAC_OUI_WME_TSPEC_MAX 61 + +#define SIR_MAC_OUI_SUBTYPE_WSM_TSPEC 2 /* same as WME TSPEC */ +#define SIR_MAC_OUI_WSM_TSPEC_MIN 61 +#define SIR_MAC_OUI_WSM_TSPEC_MAX 61 + +/* reserved subtypes 3-4 */ +/* WSM capability */ +#define SIR_MAC_OUI_SUBTYPE_WSM_CAPABLE 5 +#define SIR_MAC_OUI_WSM_CAPABLE_MIN 7 +#define SIR_MAC_OUI_WSM_CAPABLE_MAX 7 +/* WSM classifier */ +#define SIR_MAC_OUI_SUBTYPE_WSM_TCLAS 6 +#define SIR_MAC_OUI_WSM_TCLAS_MIN 10 +#define SIR_MAC_OUI_WSM_TCLAS_MAX 255 +/* classifier processing element */ +#define SIR_MAC_OUI_SUBTYPE_WSM_TCLASPROC 7 +#define SIR_MAC_OUI_WSM_TCLASPROC_MIN 7 +#define SIR_MAC_OUI_WSM_TCLASPROC_MAX 7 +/* tspec delay element */ +#define SIR_MAC_OUI_SUBTYPE_WSM_TSDELAY 8 +#define SIR_MAC_OUI_WSM_TSDELAY_MIN 10 +#define SIR_MAC_OUI_WSM_TSDELAY_MAX 10 +/* schedule element */ +#define SIR_MAC_OUI_SUBTYPE_WSM_SCHEDULE 9 +#define SIR_MAC_OUI_WSM_SCHEDULE_MIN 20 +#define SIR_MAC_OUI_WSM_SCHEDULE_MAX 20 + +#ifdef WLAN_NS_OFFLOAD +#define SIR_MAC_NS_OFFLOAD_SIZE 1 /* support only one IPv6 offload */ +/* Number of target IP V6 addresses for NS offload */ +#define SIR_MAC_NUM_TARGET_IPV6_NS_OFFLOAD_NA 16 +#define SIR_MAC_IPV6_ADDR_LEN 16 +#define SIR_IPV6_ADDR_VALID 1 +#define SIR_IPV6_ADDR_UC_TYPE 0 +#define SIR_IPV6_ADDR_AC_TYPE 1 +#endif /* WLAN_NS_OFFLOAD */ + +/* ----------------------------------------------------------------------------- */ + +/* OFFSET definitions for fixed fields in Management frames */ + +/* Beacon/Probe Response offsets */ +#define SIR_MAC_TS_OFFSET 0 +#define SIR_MAC_BEACON_INT_OFFSET 8 /* Beacon Interval offset */ +#define SIR_MAC_B_PR_CAPAB_OFFSET 10 +#define SIR_MAC_B_PR_SSID_OFFSET 12 + +/* Association/Reassociation offsets */ +#define SIR_MAC_ASSOC_CAPAB_OFFSET 0 +#define SIR_MAC_LISTEN_INT_OFFSET 2 /* Listen Interval offset */ +#define SIR_MAC_ASSOC_SSID_OFFSET 4 +#define SIR_MAC_CURRENT_AP_OFFSET 4 +#define SIR_MAC_REASSOC_SSID_OFFSET 10 +#define SIR_MAC_ASSOC_STATUS_CODE_OFFSET 2 +#define SIR_MAC_ASSOC_AID_OFFSET 4 +#define SIR_MAC_ASSOC_RSP_RATE_OFFSET 6 + +/* Disassociation/Deauthentication offsets */ +#define SIR_MAC_REASON_CODE_OFFSET 0 + +/* Probe Request offset */ +#define SIR_MAC_PROBE_REQ_SSID_OFFSET 0 + +/* Authentication offsets */ +#define SIR_MAC_AUTH_ALGO_OFFSET 0 +#define SIR_MAC_AUTH_XACT_SEQNUM_OFFSET 2 +#define SIR_MAC_AUTH_STATUS_CODE_OFFSET 4 +#define SIR_MAC_AUTH_CHALLENGE_OFFSET 6 + +/* / Transaction sequence number definitions (used in Authentication frames) */ +#define SIR_MAC_AUTH_FRAME_1 1 +#define SIR_MAC_AUTH_FRAME_2 2 +#define SIR_MAC_AUTH_FRAME_3 3 +#define SIR_MAC_AUTH_FRAME_4 4 + +/* / Protocol defined MAX definitions */ +#define SIR_MAC_MAX_SSID_LENGTH 32 +#define SIR_MAC_MAX_NUMBER_OF_RATES 12 +#define SIR_MAC_MAX_NUM_OF_DEFAULT_KEYS 4 +#define SIR_MAC_KEY_LENGTH 13 /* WEP Maximum key length size */ +#define SIR_MAC_AUTH_CHALLENGE_LENGTH 253 +#define SIR_MAC_WEP_IV_LENGTH 4 +#define SIR_MAC_WEP_ICV_LENGTH 4 + +/* / MAX key length when ULA is used */ +#define SIR_MAC_MAX_KEY_LENGTH 32 + +/* / Macro definitions for get/set on FC fields */ +#define SIR_MAC_GET_PROT_VERSION(x) ((((uint16_t) x) & 0x0300) >> 8) +#define SIR_MAC_GET_FRAME_TYPE(x) ((((uint16_t) x) & 0x0C00) >> 8) +#define SIR_MAC_GET_FRAME_SUB_TYPE(x) ((((uint16_t) x) & 0xF000) >> 12) +#define SIR_MAC_GET_WEP_BIT_IN_FC(x) (((uint16_t) x) & 0x0040) +#define SIR_MAC_SET_PROT_VERSION(x) ((uint16_t) x) +#define SIR_MAC_SET_FRAME_TYPE(x) (((uint16_t) x) << 2) +#define SIR_MAC_SET_FRAME_SUB_TYPE(x) (((uint16_t) x) << 4) +#define SIR_MAC_SET_WEP_BIT_IN_FC(x) (((uint16_t) x) << 14) + +/* / Macro definitions for get/set on capabilityInfo bits */ +#define SIR_MAC_GET_ESS(x) (((uint16_t) x) & 0x0001) +#define SIR_MAC_GET_IBSS(x) ((((uint16_t) x) & 0x0002) >> 1) +#define SIR_MAC_GET_CF_POLLABLE(x) ((((uint16_t) x) & 0x0004) >> 2) +#define SIR_MAC_GET_CF_POLL_REQ(x) ((((uint16_t) x) & 0x0008) >> 3) +#define SIR_MAC_GET_PRIVACY(x) ((((uint16_t) x) & 0x0010) >> 4) +#define SIR_MAC_GET_SHORT_PREAMBLE(x) ((((uint16_t) x) & 0x0020) >> 5) +#define SIR_MAC_GET_SPECTRUM_MGMT(x) ((((uint16_t) x) & 0x0100) >> 8) +#define SIR_MAC_GET_QOS(x) ((((uint16_t) x) & 0x0200) >> 9) +#define SIR_MAC_GET_SHORT_SLOT_TIME(x) ((((uint16_t) x) & 0x0400) >> 10) +#define SIR_MAC_GET_APSD(x) ((((uint16_t) x) & 0x0800) >> 11) +#define SIR_MAC_GET_RRM(x) ((((uint16_t) x) & 0x1000) >> 12) +#define SIR_MAC_GET_BLOCK_ACK(x) ((((uint16_t) x) & 0xc000) >> CAPABILITY_INFO_DELAYED_BA_BIT) +#define SIR_MAC_SET_ESS(x) (((uint16_t) x) | 0x0001) +#define SIR_MAC_SET_IBSS(x) (((uint16_t) x) | 0x0002) +#define SIR_MAC_SET_CF_POLLABLE(x) (((uint16_t) x) | 0x0004) +#define SIR_MAC_SET_CF_POLL_REQ(x) (((uint16_t) x) | 0x0008) +#define SIR_MAC_SET_PRIVACY(x) (((uint16_t) x) | 0x0010) +#define SIR_MAC_SET_SHORT_PREAMBLE(x) (((uint16_t) x) | 0x0020) +#define SIR_MAC_SET_SPECTRUM_MGMT(x) (((uint16_t) x) | 0x0100) +#define SIR_MAC_SET_QOS(x) (((uint16_t) x) | 0x0200) +#define SIR_MAC_SET_SHORT_SLOT_TIME(x) (((uint16_t) x) | 0x0400) +#define SIR_MAC_SET_APSD(x) (((uint16_t) x) | 0x0800) +#define SIR_MAC_SET_RRM(x) (((uint16_t) x) | 0x1000) +#define SIR_MAC_SET_GROUP_ACK(x) (((uint16_t) x) | 0x4000) + +#define SIR_MAC_GET_VHT_MAX_AMPDU_EXPO(x) ((((uint32_t) x) & 0x03800000) >> 23) + +/* bitname must be one of the above, eg ESS, CF_POLLABLE, etc. */ +#define SIR_MAC_CLEAR_CAPABILITY(u16value, bitname) \ + ((u16value) &= (~(SIR_MAC_SET_ ## bitname(0)))) + +#define IS_WES_MODE_ENABLED(x) \ + ((x)->roam.configParam.isWESModeEnabled) + +#define BA_RECIPIENT 1 +#define BA_INITIATOR 2 +#define BA_BOTH_DIRECTIONS 3 + +#define SIR_MAC_VENDOR_AP_1_OUI "\x00\x0C\x43" +#define SIR_MAC_VENDOR_AP_1_OUI_LEN 3 +/* / Status Code (present in Management response frames) enum */ + +typedef enum eSirMacStatusCodes { + eSIR_MAC_SUCCESS_STATUS = 0, /* Reserved */ + eSIR_MAC_UNSPEC_FAILURE_STATUS = 1, /* Unspecified reason */ + /* 802.11 reserved 2-9 */ + /* + WMM status codes(standard 1.1 table 9) + Table 9 ADDTS Response Status Codes + Value Operation + 0 Admission accepted + 1 Invalid parameters + 2 Reserved + 3 Refused + 4-255 Reserved + */ + eSIR_MAC_WME_INVALID_PARAMS_STATUS = 1, /* ?? */ + eSIR_MAC_WME_REFUSED_STATUS = 3, /* ?? */ + eSIR_MAC_CAPABILITIES_NOT_SUPPORTED_STATUS = 10, /* Cannot support all requested capabilities in the Capability Information field */ + eSIR_MAC_INABLITY_TO_CONFIRM_ASSOC_STATUS = 11, /* Reassociation denied due to inability to confirm that association exists */ + eSIR_MAC_OUTSIDE_SCOPE_OF_SPEC_STATUS = 12, /* Association denied due to reason outside the scope of this standard */ + eSIR_MAC_AUTH_ALGO_NOT_SUPPORTED_STATUS = 13, /* Responding station does not support the specified authentication algorithm */ + eSIR_MAC_AUTH_FRAME_OUT_OF_SEQ_STATUS = 14, /* Received an Authentication frame with authentication transaction sequence number */ + /* out of expected sequence */ + eSIR_MAC_CHALLENGE_FAILURE_STATUS = 15, /* Authentication rejected because of challenge failure */ + eSIR_MAC_AUTH_RSP_TIMEOUT_STATUS = 16, /* Authentication rejected due to timeout waiting for next frame in sequence */ + eSIR_MAC_MAX_ASSOC_STA_REACHED_STATUS = 17, /* Association denied because AP is unable to handle additional associated stations */ + eSIR_MAC_BASIC_RATES_NOT_SUPPORTED_STATUS = 18, /* Association denied due to requesting station not supporting all of the data rates in the */ + /* BSSBasicRateSet parameter */ + eSIR_MAC_SHORT_PREAMBLE_NOT_SUPPORTED_STATUS = 19, /* Association denied due to requesting station not supporting the short preamble */ + /* option */ + eSIR_MAC_PBCC_NOT_SUPPORTED_STATUS = 20, /* Association denied due to requesting station not supporting the PBCC modulation */ + /* option */ + eSIR_MAC_CHANNEL_AGILITY_NOT_SUPPORTED_STATUS = 21, /* Association denied due to requesting station not supporting the Channel Agility */ + /* option */ + eSIR_MAC_SPECTRUM_MGMT_REQD_STATUS = 22, /* Association request rejected because Spectrum Management capability is required */ + eSIR_MAC_PWR_CAPABILITY_BAD_STATUS = 23, /* Association request rejected because the information in the Power Capability */ + /* element is unacceptable */ + eSIR_MAC_SPRTD_CHANNELS_BAD_STATUS = 24, /* Association request rejected because the information in the Supported Channels */ + /* element is unacceptable */ + eSIR_MAC_SHORT_SLOT_NOT_SUPORTED_STATUS = 25, /* Association denied due to requesting station not supporting the Short Slot Time */ + /* option */ + eSIR_MAC_DSSS_OFDM_NOT_SUPPORTED_STATUS = 26, /* Association denied due to requesting station not supporting the DSSS-OFDM option */ + /* reserved 27-29 */ + eSIR_MAC_TRY_AGAIN_LATER = 30, /* Association request rejected temporarily, try again later */ + /* reserved 31 */ + eSIR_MAC_QOS_UNSPECIFIED_FAILURE_STATUS = 32, /* Unspecified, QoS-related failure */ + eSIR_MAC_QAP_NO_BANDWIDTH_STATUS = 33, /* Association denied because QoS AP has insufficient bandwidth to handle another */ + /* QoS STA */ + eSIR_MAC_XS_FRAME_LOSS_STATUS = 34, /* Association denied due to excessive frame loss rates and/or poor conditions on cur- */ + /* rent operating channel */ + eSIR_MAC_STA_QOS_NOT_SUPPORTED_STATUS = 35, /* Association (with QoS BSS) denied because the requesting STA does not support the */ + /* QoS facility */ + eSIR_MAC_STA_BLK_ACK_NOT_SUPPORTED_STATUS = 36, /* Reserved */ + eSIR_MAC_REQ_DECLINED_STATUS = 37, /* The request has been declined */ + eSIR_MAC_INVALID_PARAM_STATUS = 38, /* The request has not been successful as one or more parameters have invalid values */ + eSIR_MAC_TS_NOT_HONOURED_STATUS = 39, /* The TS has not been created because the request cannot be honored; however, a suggested */ + /* TSPEC is provided so that the initiating STA may attempt to set another TS */ + /* with the suggested changes to the TSPEC */ + eSIR_MAC_INVALID_INFORMATION_ELEMENT_STATUS = 40, /* Invalid information element, i.e., an information element defined in this standard for */ + /* which the content does not meet the specifications in Clause 7 */ + eSIR_MAC_INVALID_GROUP_CIPHER_STATUS = 41, /* Invalid group cipher */ + eSIR_MAC_INVALID_PAIRWISE_CIPHER_STATUS = 42, /* Invalid pairwise cipher */ + eSIR_MAC_INVALID_AKMP_STATUS = 43, /* Invalid AKMP */ + eSIR_MAC_UNSUPPORTED_RSN_IE_VERSION_STATUS = 44, /* Unsupported RSN information element version */ + eSIR_MAC_INVALID_RSN_IE_CAPABILITIES_STATUS = 45, /* Invalid RSN information element capabilities */ + eSIR_MAC_CIPHER_SUITE_REJECTED_STATUS = 46, /* Cipher suite rejected because of security policy */ + eSIR_MAC_TS_NOT_CREATED_STATUS = 47, /* The TS has not been created; however, the HC may be capable of creating a TS, in */ + /* response to a request, after the time indicated in the TS Delay element */ + eSIR_MAC_DL_NOT_ALLOWED_STATUS = 48, /* Direct link is not allowed in the BSS by policy */ + eSIR_MAC_DEST_STA_NOT_KNOWN_STATUS = 49, /* The Destination STA is not present within this BSS */ + eSIR_MAC_DEST_STA_NOT_QSTA_STATUS = 50, /* The Destination STA is not a QoS STA */ + eSIR_MAC_INVALID_LISTEN_INTERVAL_STATUS = 51, /* Association denied because the ListenInterval is too large */ + + eSIR_MAC_DSSS_CCK_RATE_MUST_SUPPORT_STATUS = 52, /* FIXME: */ + eSIR_MAC_DSSS_CCK_RATE_NOT_SUPPORT_STATUS = 53, + eSIR_MAC_PSMP_CONTROLLED_ACCESS_ONLY_STATUS = 54, +#ifdef FEATURE_WLAN_ESE + eSIR_MAC_ESE_UNSPECIFIED_QOS_FAILURE_STATUS = 200, /* ESE-Unspecified, QoS related failure in (Re)Assoc response frames */ + eSIR_MAC_ESE_TSPEC_REQ_REFUSED_STATUS = 201, /* ESE-TSPEC request refused due to AP's policy configuration in AddTs Rsp, (Re)Assoc Rsp. */ + eSIR_MAC_ESE_ASSOC_DENIED_INSUFF_BW_STATUS = 202, /* ESE-Assoc denied due to insufficient bandwidth to handle new TS in (Re)Assoc Rsp. */ + eSIR_MAC_ESE_INVALID_PARAMETERS_STATUS = 203, /* ESE-Invalid parameters. (Re)Assoc request had one or more TSPEC parameters with */ + /* invalid values. */ +#endif + +} tSirMacStatusCodes; + +/** + * Reason Code (present in Deauthentication/Disassociation + * Management frames) enum + */ +typedef enum eSirMacReasonCodes { + eSIR_MAC_UNSPEC_FAILURE_REASON = 1, /* Unspecified reason */ + eSIR_MAC_PREV_AUTH_NOT_VALID_REASON = 2, /* Previous authentication no longer valid */ + eSIR_MAC_DEAUTH_LEAVING_BSS_REASON = 3, /* Deauthenticated because sending station is leaving (or has left) IBSS or ESS */ + eSIR_MAC_DISASSOC_DUE_TO_INACTIVITY_REASON = 4, /* Disassociated due to inactivity */ + eSIR_MAC_DISASSOC_DUE_TO_DISABILITY_REASON = 5, /* Disassociated because AP is unable to handle all currently associated stations */ + eSIR_MAC_CLASS2_FRAME_FROM_NON_AUTH_STA_REASON = 6, /* Class 2 frame received from nonauthenticated station */ + eSIR_MAC_CLASS3_FRAME_FROM_NON_ASSOC_STA_REASON = 7, /* Class 3 frame received from nonassociated station */ + eSIR_MAC_DISASSOC_LEAVING_BSS_REASON = 8, /* Disassociated because sending station is leaving (or has left) BSS */ + eSIR_MAC_STA_NOT_PRE_AUTHENTICATED_REASON = 9, /* Station requesting (re)association is not authenticated with responding station */ + eSIR_MAC_PWR_CAPABILITY_BAD_REASON = 10, /* Disassociated because the information in the Power Capability element is unacceptable */ + eSIR_MAC_SPRTD_CHANNELS_BAD_REASON = 11, /* Disassociated because the information in the Supported Channels element is unacceptable */ + /* reserved 12 */ + eSIR_MAC_INVALID_IE_REASON = 13, /* Invalid information element, i.e., an information element defined in this standard for */ + /* which the content does not meet the specifications in Clause 7 */ + eSIR_MAC_MIC_FAILURE_REASON = 14, /* Message integrity code (MIC) failure */ + eSIR_MAC_4WAY_HANDSHAKE_TIMEOUT_REASON = 15, /* 4-Way Handshake timeout */ + eSIR_MAC_GR_KEY_UPDATE_TIMEOUT_REASON = 16, /* Group Key Handshake timeout */ + eSIR_MAC_RSN_IE_MISMATCH_REASON = 17, /* Information element in 4-Way Handshake different from (Re)Association Request/Probe */ + /* Response/Beacon frame */ + eSIR_MAC_INVALID_MC_CIPHER_REASON = 18, /* Invalid group cipher */ + eSIR_MAC_INVALID_UC_CIPHER_REASON = 19, /* Invalid pairwise cipher */ + eSIR_MAC_INVALID_AKMP_REASON = 20, /* Invalid AKMP */ + eSIR_MAC_UNSUPPORTED_RSN_IE_VER_REASON = 21, /* Unsupported RSN information element version */ + eSIR_MAC_INVALID_RSN_CAPABILITIES_REASON = 22, /* Invalid RSN information element capabilities */ + eSIR_MAC_1X_AUTH_FAILURE_REASON = 23, /* IEEE 802.1X authentication failed */ + eSIR_MAC_CIPHER_SUITE_REJECTED_REASON = 24, /* Cipher suite rejected because of the security policy */ +#ifdef FEATURE_WLAN_TDLS + eSIR_MAC_TDLS_TEARDOWN_PEER_UNREACHABLE = 25, /* TDLS direct link teardown due to TDLS peer STA unreachable via the TDLS direct link */ + eSIR_MAC_TDLS_TEARDOWN_UNSPEC_REASON = 26, /* TDLS direct link teardown for unspecified reason */ +#endif + /* reserved 27 - 30 */ +#ifdef WLAN_FEATURE_11W + eSIR_MAC_ROBUST_MGMT_FRAMES_POLICY_VIOLATION = 31, /* Robust management frames policy violation */ +#endif + eSIR_MAC_QOS_UNSPECIFIED_REASON = 32, /* Disassociated for unspecified, QoS-related reason */ + eSIR_MAC_QAP_NO_BANDWIDTH_REASON = 33, /* Disassociated because QoS AP lacks sufficient bandwidth for this QoS STA */ + eSIR_MAC_XS_UNACKED_FRAMES_REASON = 34, /* Disassociated because excessive number of frames need to be acknowledged, but are not */ + /* acknowledged due to AP transmissions and/or poor channel conditions */ + eSIR_MAC_BAD_TXOP_USE_REASON = 35, /* Disassociated because STA is transmitting outside the limits of its TXOPs */ + eSIR_MAC_PEER_STA_REQ_LEAVING_BSS_REASON = 36, /* Requested from peer STA as the STA is leaving the BSS (or resetting) */ + eSIR_MAC_PEER_REJECT_MECHANISIM_REASON = 37, /* Requested from peer STA as it does not want to use the mechanism */ + eSIR_MAC_MECHANISM_NOT_SETUP_REASON = 38, /* Requested from peer STA as the STA received frames using the mechanism for which a */ + /* setup is required */ + eSIR_MAC_PEER_TIMEDOUT_REASON = 39, /* Requested from peer STA due to timeout */ + eSIR_MAC_CIPHER_NOT_SUPPORTED_REASON = 45, /* Peer STA does not support the requested cipher suite */ + eSIR_MAC_DISASSOC_DUE_TO_FTHANDOFF_REASON = 46, /* FT reason */ + /* reserved 47 - 65535. */ + eSIR_BEACON_MISSED = 65534, /* We invented this to tell beacon missed case */ +} tSirMacReasonCodes; + +/* BA Initiator v/s Recipient */ +typedef enum eBADirection { + eBA_RECIPIENT, + eBA_INITIATOR +} tBADirection; + +/* A-MPDU/BA Enable/Disable in Tx/Rx direction */ +typedef enum eBAEnable { + eBA_DISABLE, + eBA_ENABLE +} tBAEnable; + +/* A-MPDU/BA Policy */ +typedef enum eBAPolicy { + eBA_UNCOMPRESSED, + eBA_COMPRESSED +} tBAPolicy; + +/* A-MPDU/BA Policy */ +typedef enum eBAPolicyType { + eBA_POLICY_DELAYED, + eBA_POLICY_IMMEDIATE +} tBAPolicyType; + +/* / Frame control field format (2 bytes) */ +typedef struct sSirMacFrameCtl { + +#ifndef ANI_LITTLE_BIT_ENDIAN + + uint8_t subType:4; + uint8_t type:2; + uint8_t protVer:2; + + uint8_t order:1; + uint8_t wep:1; + uint8_t moreData:1; + uint8_t powerMgmt:1; + uint8_t retry:1; + uint8_t moreFrag:1; + uint8_t fromDS:1; + uint8_t toDS:1; + +#else + + uint8_t protVer:2; + uint8_t type:2; + uint8_t subType:4; + + uint8_t toDS:1; + uint8_t fromDS:1; + uint8_t moreFrag:1; + uint8_t retry:1; + uint8_t powerMgmt:1; + uint8_t moreData:1; + uint8_t wep:1; + uint8_t order:1; + +#endif + +} qdf_packed tSirMacFrameCtl, *tpSirMacFrameCtl; + +/* / Sequence control field */ +typedef struct sSirMacSeqCtl { + +#ifndef ANI_LITTLE_BIT_ENDIAN + + uint8_t seqNumLo:4; + uint8_t fragNum:4; + + uint8_t seqNumHi:8; + +#else + + uint8_t fragNum:4; + uint8_t seqNumLo:4; + uint8_t seqNumHi:8; + +#endif +} qdf_packed tSirMacSeqCtl, *tpSirMacSeqCtl; + +/* / QoS control field */ +typedef struct sSirMacQosCtl { + +#ifndef ANI_LITTLE_BIT_ENDIAN + + uint8_t rsvd:1; + uint8_t ackPolicy:2; + uint8_t esop_txopUnit:1; + uint8_t tid:4; + + uint8_t txop:8; + +#else + + uint8_t tid:4; + uint8_t esop_txopUnit:1; + uint8_t ackPolicy:2; + uint8_t rsvd:1; + + uint8_t txop:8; + +#endif +} qdf_packed tSirMacQosCtl, *tpSirMacQosCtl; + +/* / Length (in bytes) of MAC header in 3 address format */ +#define SIR_MAC_HDR_LEN_3A 24 + +typedef uint8_t tSirMacAddr[ETH_ALEN]; + +/* / 3 address MAC data header format (24/26 bytes) */ +typedef struct sSirMacDot3Hdr { + tSirMacAddr da; + tSirMacAddr sa; + uint16_t length; +} qdf_packed tSirMacDot3Hdr, *tpSirMacDot3Hdr; + +/* / 3 address MAC data header format (24/26 bytes) */ +typedef struct sSirMacDataHdr3a { + tSirMacFrameCtl fc; + uint8_t durationLo; + uint8_t durationHi; + tSirMacAddr addr1; + tSirMacAddr addr2; + tSirMacAddr addr3; + tSirMacSeqCtl seqControl; + tSirMacQosCtl qosControl; +} qdf_packed tSirMacDataHdr3a, *tpSirMacDataHdr3a; + +/* / Management header format */ +typedef struct sSirMacMgmtHdr { + tSirMacFrameCtl fc; + uint8_t durationLo; + uint8_t durationHi; + tSirMacAddr da; + tSirMacAddr sa; + tSirMacAddr bssId; + tSirMacSeqCtl seqControl; +} qdf_packed tSirMacMgmtHdr, *tpSirMacMgmtHdr; + +/* / ERP information field */ +typedef struct sSirMacErpInfo { +#ifndef ANI_LITTLE_BIT_ENDIAN + uint8_t reserved:5; + uint8_t barkerPreambleMode:1; + uint8_t useProtection:1; + uint8_t nonErpPresent:1; +#else + uint8_t nonErpPresent:1; + uint8_t useProtection:1; + uint8_t barkerPreambleMode:1; + uint8_t reserved:5; +#endif +} qdf_packed tSirMacErpInfo, *tpSirMacErpInfo; + +/* / Capability information field */ +typedef struct sSirMacCapabilityInfo { +#ifndef ANI_LITTLE_BIT_ENDIAN + uint16_t immediateBA:1; + uint16_t delayedBA:1; + uint16_t dsssOfdm:1; + uint16_t rrm:1; + uint16_t apsd:1; + uint16_t shortSlotTime:1; + uint16_t qos:1; + uint16_t spectrumMgt:1; + uint16_t channelAgility:1; + uint16_t pbcc:1; + uint16_t shortPreamble:1; + uint16_t privacy:1; + uint16_t cfPollReq:1; + uint16_t cfPollable:1; + uint16_t ibss:1; + uint16_t ess:1; +#else + uint16_t ess:1; + uint16_t ibss:1; + uint16_t cfPollable:1; + uint16_t cfPollReq:1; + uint16_t privacy:1; + uint16_t shortPreamble:1; + uint16_t pbcc:1; + uint16_t channelAgility:1; + uint16_t spectrumMgt:1; + uint16_t qos:1; + uint16_t shortSlotTime:1; + uint16_t apsd:1; + uint16_t rrm:1; + uint16_t dsssOfdm:1; + uint16_t delayedBA:1; + uint16_t immediateBA:1; +#endif +} qdf_packed tSirMacCapabilityInfo, *tpSirMacCapabilityInfo; + +typedef struct sSirMacCfParamSet { + uint8_t cfpCount; + uint8_t cfpPeriod; + uint16_t cfpMaxDuration; + uint16_t cfpDurRemaining; +} qdf_packed tSirMacCfParamSet; + +typedef struct sSirMacTim { + uint8_t dtimCount; + uint8_t dtimPeriod; + uint8_t bitmapControl; + uint8_t bitmapLength; + uint8_t bitmap[251]; +} qdf_packed tSirMacTim; + +/* 12 Bytes long because this structure can be used to represent rate */ +/* and extended rate set IEs */ +/* The parser assume this to be at least 12 */ +typedef struct sSirMacRateSet { + uint8_t numRates; + uint8_t rate[SIR_MAC_RATESET_EID_MAX]; +} qdf_packed tSirMacRateSet; + +typedef struct sSirMacSSid { + uint8_t length; + uint8_t ssId[SIR_MAC_MAX_SSID_LENGTH]; +} qdf_packed tSirMacSSid; + +typedef struct sSirMacWpaInfo { + uint8_t length; + uint8_t info[SIR_MAC_MAX_IE_LENGTH]; +} qdf_packed tSirMacWpaInfo, *tpSirMacWpaInfo, +tSirMacRsnInfo, *tpSirMacRsnInfo; +typedef struct sSirMacWapiInfo { + uint8_t length; + uint8_t info[SIR_MAC_MAX_IE_LENGTH]; +} qdf_packed tSirMacWapiInfo, *tpSirMacWapiInfo, +tSirMacWapiInfo, *tpSirMacWapiInfo; + +typedef struct sSirMacFHParamSet { + uint16_t dwellTime; + uint8_t hopSet; + uint8_t hopPattern; + uint8_t hopIndex; +} tSirMacFHParamSet, *tpSirMacFHParamSet; + +typedef struct sSirMacIBSSParams { + uint16_t atim; +} tSirMacIBSSParams, *tpSirMacIBSSParams; + +typedef struct sSirMacRRMEnabledCap { +#ifndef ANI_LITTLE_BIT_ENDIAN + uint8_t reserved:6; + uint8_t AntennaInformation:1; + uint8_t BSSAvailAdmission:1; + uint8_t BssAvgAccessDelay:1; + uint8_t RSNIMeasurement:1; + uint8_t RCPIMeasurement:1; + uint8_t NeighborTSFOffset:1; + uint8_t MeasurementPilotEnabled:1; + uint8_t MeasurementPilot:3; + uint8_t nonOperatinChanMax:3; + uint8_t operatingChanMax:3; + uint8_t RRMMIBEnabled:1; + uint8_t APChanReport:1; + uint8_t triggeredTCM:1; + uint8_t TCMCapability:1; + uint8_t LCIAzimuth:1; + uint8_t LCIMeasurement:1; + uint8_t statistics:1; + uint8_t NoiseHistogram:1; + uint8_t ChannelLoad:1; + uint8_t FrameMeasurement:1; + uint8_t BeaconRepCond:1; + uint8_t BeaconTable:1; + uint8_t BeaconActive:1; + uint8_t BeaconPassive:1; + uint8_t repeated:1; + uint8_t parallel:1; + uint8_t NeighborRpt:1; + uint8_t LinkMeasurement:1; + uint8_t present; +#else + uint8_t present; + uint8_t LinkMeasurement:1; + uint8_t NeighborRpt:1; + uint8_t parallel:1; + uint8_t repeated:1; + uint8_t BeaconPassive:1; + uint8_t BeaconActive:1; + uint8_t BeaconTable:1; + uint8_t BeaconRepCond:1; + uint8_t FrameMeasurement:1; + uint8_t ChannelLoad:1; + uint8_t NoiseHistogram:1; + uint8_t statistics:1; + uint8_t LCIMeasurement:1; + uint8_t LCIAzimuth:1; + uint8_t TCMCapability:1; + uint8_t triggeredTCM:1; + uint8_t APChanReport:1; + uint8_t RRMMIBEnabled:1; + uint8_t operatingChanMax:3; + uint8_t nonOperatinChanMax:3; + uint8_t MeasurementPilot:3; + uint8_t MeasurementPilotEnabled:1; + uint8_t NeighborTSFOffset:1; + uint8_t RCPIMeasurement:1; + uint8_t RSNIMeasurement:1; + uint8_t BssAvgAccessDelay:1; + uint8_t BSSAvailAdmission:1; + uint8_t AntennaInformation:1; + uint8_t reserved:6; +#endif +} tSirMacRRMEnabledCap, *tpSirMacRRMEnabledCap; + +/* ---------------- + * EDCA Profiles + * --------------- + */ + +#define EDCA_AC_BE 0 +#define EDCA_AC_BK 1 +#define EDCA_AC_VI 2 +#define EDCA_AC_VO 3 +#define AC_MGMT_LO 4 +#define AC_MGMT_HI 5 +#define MAX_NUM_AC 4 + +/* access categories */ +#define SIR_MAC_EDCAACI_BESTEFFORT (EDCA_AC_BE) +#define SIR_MAC_EDCAACI_BACKGROUND (EDCA_AC_BK) +#define SIR_MAC_EDCAACI_VIDEO (EDCA_AC_VI) +#define SIR_MAC_EDCAACI_VOICE (EDCA_AC_VO) + +/* access category record */ +typedef struct sSirMacAciAifsn { +#ifndef ANI_LITTLE_BIT_ENDIAN + uint8_t rsvd:1; + uint8_t aci:2; + uint8_t acm:1; + uint8_t aifsn:4; +#else + uint8_t aifsn:4; + uint8_t acm:1; + uint8_t aci:2; + uint8_t rsvd:1; +#endif +} qdf_packed tSirMacAciAifsn; + +/* contention window size */ +typedef struct sSirMacCW { +#ifndef ANI_LITTLE_BIT_ENDIAN + uint8_t max:4; + uint8_t min:4; +#else + uint8_t min:4; + uint8_t max:4; +#endif +} qdf_packed tSirMacCW; + +typedef struct sSirMacEdcaParamRecord { + tSirMacAciAifsn aci; + tSirMacCW cw; + uint16_t txoplimit; +} qdf_packed tSirMacEdcaParamRecord; + +typedef struct sSirMacQosInfo { +#ifndef ANI_LITTLE_BIT_ENDIAN + uint8_t uapsd:1; + uint8_t txopreq:1; + uint8_t qreq:1; + uint8_t qack:1; + uint8_t count:4; +#else + uint8_t count:4; + uint8_t qack:1; + uint8_t qreq:1; + uint8_t txopreq:1; + uint8_t uapsd:1; +#endif +} qdf_packed tSirMacQosInfo; + +typedef struct sSirMacQosInfoStation { +#ifdef ANI_LITTLE_BIT_ENDIAN + uint8_t acvo_uapsd:1; + uint8_t acvi_uapsd:1; + uint8_t acbk_uapsd:1; + uint8_t acbe_uapsd:1; + uint8_t qack:1; + uint8_t maxSpLen:2; + uint8_t moreDataAck:1; +#else + uint8_t moreDataAck:1; + uint8_t maxSpLen:2; + uint8_t qack:1; + uint8_t acbe_uapsd:1; + uint8_t acbk_uapsd:1; + uint8_t acvi_uapsd:1; + uint8_t acvo_uapsd:1; +#endif +} qdf_packed tSirMacQosInfoStation, *tpSirMacQosInfoStation; + +typedef struct sSirMacEdcaParamSetIE { + uint8_t type; + uint8_t length; + tSirMacQosInfo qosInfo; + uint8_t rsvd; + tSirMacEdcaParamRecord acbe; /* best effort */ + tSirMacEdcaParamRecord acbk; /* background */ + tSirMacEdcaParamRecord acvi; /* video */ + tSirMacEdcaParamRecord acvo; /* voice */ +} qdf_packed tSirMacEdcaParamSetIE; + +typedef struct sSirMacQoSParams { + uint8_t count; + uint16_t limit; + uint8_t CWmin[8]; + uint8_t AIFS[8]; +} qdf_packed tSirMacQoSParams; + +/* ts info direction field can take any of these values */ +#define SIR_MAC_DIRECTION_UPLINK 0 +#define SIR_MAC_DIRECTION_DNLINK 1 +#define SIR_MAC_DIRECTION_DIRECT 2 +#define SIR_MAC_DIRECTION_BIDIR 3 + +/* access policy */ +/* reserved 0 */ +#define SIR_MAC_ACCESSPOLICY_EDCA 1 +#define SIR_MAC_ACCESSPOLICY_HCCA 2 +#define SIR_MAC_ACCESSPOLICY_BOTH 3 + +typedef struct sSirMacTSInfoTfc { +#ifndef ANI_LITTLE_BIT_ENDIAN + uint8_t burstSizeDefn:1; + uint8_t reserved:7; +#else + uint8_t reserved:7; + uint8_t burstSizeDefn:1; +#endif + +#ifndef ANI_LITTLE_BIT_ENDIAN + uint16_t ackPolicy:2; + uint16_t userPrio:3; + uint16_t psb:1; + uint16_t aggregation:1; + uint16_t accessPolicy:2; + uint16_t direction:2; + uint16_t tsid:4; + uint16_t trafficType:1; +#else + uint16_t trafficType:1; + uint16_t tsid:4; + uint16_t direction:2; + uint16_t accessPolicy:2; + uint16_t aggregation:1; + uint16_t psb:1; + uint16_t userPrio:3; + uint16_t ackPolicy:2; +#endif +} qdf_packed tSirMacTSInfoTfc; + +typedef struct sSirMacTSInfoSch { +#ifndef ANI_LITTLE_BIT_ENDIAN + uint8_t rsvd:7; + uint8_t schedule:1; +#else + uint8_t schedule:1; + uint8_t rsvd:7; +#endif +} qdf_packed tSirMacTSInfoSch; + +typedef struct sSirMacTSInfo { + tSirMacTSInfoTfc traffic; + tSirMacTSInfoSch schedule; +} qdf_packed tSirMacTSInfo; + +typedef struct sSirMacTspecIE { + uint8_t type; + uint8_t length; + tSirMacTSInfo tsinfo; + uint16_t nomMsduSz; + uint16_t maxMsduSz; + uint32_t minSvcInterval; + uint32_t maxSvcInterval; + uint32_t inactInterval; + uint32_t suspendInterval; + uint32_t svcStartTime; + uint32_t minDataRate; + uint32_t meanDataRate; + uint32_t peakDataRate; + uint32_t maxBurstSz; + uint32_t delayBound; + uint32_t minPhyRate; + uint16_t surplusBw; + uint16_t mediumTime; +} qdf_packed tSirMacTspecIE; + +/* frame classifier types */ +#define SIR_MAC_TCLASTYPE_ETHERNET 0 +#define SIR_MAC_TCLASTYPE_TCPUDPIP 1 +#define SIR_MAC_TCLASTYPE_8021DQ 2 +/* reserved 3-255 */ + +typedef struct sSirMacTclasParamEthernet { + tSirMacAddr srcAddr; + tSirMacAddr dstAddr; + uint16_t type; +} qdf_packed tSirMacTclasParamEthernet; + +typedef struct sSirMacTclasParamIPv4 { + uint8_t version; + uint8_t srcIpAddr[4]; + uint8_t dstIpAddr[4]; + uint16_t srcPort; + uint16_t dstPort; + uint8_t dscp; + uint8_t protocol; + uint8_t rsvd; +} qdf_packed tSirMacTclasParamIPv4; + +#define SIR_MAC_TCLAS_IPV4 4 +#define SIR_MAC_TCLAS_IPV6 6 + +typedef struct sSirMacTclasParamIPv6 { + uint8_t version; + uint8_t srcIpAddr[16]; + uint8_t dstIpAddr[16]; + uint16_t srcPort; + uint16_t dstPort; + uint8_t flowLabel[3]; +} qdf_packed tSirMacTclasParamIPv6; + +typedef struct sSirMacTclasParam8021dq { + uint16_t tag; +} qdf_packed tSirMacTclasParam8021dq; + +typedef struct sSirMacTclasIE { + uint8_t type; + uint8_t length; + uint8_t userPrio; + uint8_t classifierType; + uint8_t classifierMask; +} qdf_packed tSirMacTclasIE; + +typedef struct sSirMacTsDelayIE { + uint8_t type; + uint8_t length; + uint32_t delay; +} qdf_packed tSirMacTsDelayIE; + +typedef struct sSirMacScheduleInfo { +#ifndef ANI_LITTLE_BIT_ENDIAN + uint16_t rsvd:9; + uint16_t direction:2; + uint16_t tsid:4; + uint16_t aggregation:1; +#else + uint16_t aggregation:1; + uint16_t tsid:4; + uint16_t direction:2; + uint16_t rsvd:9; +#endif +} qdf_packed tSirMacScheduleInfo; + +typedef struct sSirMacScheduleIE { + uint8_t type; + uint8_t length; + tSirMacScheduleInfo info; + uint32_t svcStartTime; + uint32_t svcInterval; + uint16_t maxSvcDuration; + uint16_t specInterval; +} qdf_packed tSirMacScheduleIE; + +typedef struct sSirMacQosCapabilityIE { + uint8_t type; + uint8_t length; + tSirMacQosInfo qosInfo; +} qdf_packed tSirMacQosCapabilityIE; + +typedef struct sSirMacQosCapabilityStaIE { + uint8_t type; + uint8_t length; + tSirMacQosInfoStation qosInfo; +} qdf_packed tSirMacQosCapabilityStaIE; + +typedef uint32_t tSirMacTimeStamp[2]; + +typedef uint16_t tSirMacBeaconInterval; + +typedef uint16_t tSirMacListenInterval; + +typedef uint8_t tSirMacChanNum; + +/* IE definitions */ +typedef struct sSirMacSSidIE { + uint8_t type; + tSirMacSSid ssId; +} qdf_packed tSirMacSSidIE; + +typedef struct sSirMacRateSetIE { + uint8_t type; + tSirMacRateSet supportedRateSet; +} qdf_packed tSirMacRateSetIE; + +typedef struct sSirMacDsParamSetIE { + uint8_t type; + uint8_t length; + tSirMacChanNum channelNumber; +} qdf_packed tSirMacDsParamSetIE; + +typedef struct sSirMacCfParamSetIE { + uint8_t type; + uint8_t length; + tSirMacCfParamSet cfParams; +} qdf_packed tSirMacCfParamSetIE; + +typedef struct sSirMacChanInfo { + tSirMacChanNum firstChanNum; + uint8_t numChannels; + int8_t maxTxPower; +} qdf_packed tSirMacChanInfo; + +typedef struct sSirMacNonErpPresentIE { + uint8_t type; + uint8_t length; + uint8_t erp; +} qdf_packed tSirMacNonErpPresentIE; + +typedef struct sSirMacPowerCapabilityIE { + uint8_t type; + uint8_t length; + uint8_t minTxPower; + uint8_t maxTxPower; +} tSirMacPowerCapabilityIE; + +typedef struct sSirMacSupportedChannelIE { + uint8_t type; + uint8_t length; + uint8_t supportedChannels[96]; +} tSirMacSupportedChannelIE; + +typedef struct sSirMacMeasReqField { + uint8_t channelNumber; + uint8_t measStartTime[8]; + uint16_t measDuration; +} tSirMacMeasReqField, *tpSirMacMeasReqField; + +typedef struct sSirMacMeasReqIE { + uint8_t type; + uint8_t length; + uint8_t measToken; + uint8_t measReqMode; + uint8_t measType; + tSirMacMeasReqField measReqField; +} tSirMacMeasReqIE, *tpSirMacMeasReqIE; + +#define SIR_MAC_MAX_SUPP_RATES 32 + +#define SIR_MAC_MAX_SUPP_CHANNELS 100 +#define SIR_MAC_MAX_EXTN_CAP 8 + +/* VHT Capabilities Info */ +typedef struct sSirMacVHTCapabilityInfo { +#ifndef ANI_LITTLE_BIT_ENDIAN + uint32_t reserved1:2; + uint32_t txAntPattern:1; + uint32_t rxAntPattern:1; + uint32_t vhtLinkAdaptCap:2; + uint32_t maxAMPDULenExp:3; + uint32_t htcVHTCap:1; + uint32_t vhtTXOPPS:1; + uint32_t muBeamformeeCap:1; + uint32_t muBeamformerCap:1; + uint32_t numSoundingDim:3; + uint32_t csnofBeamformerAntSup:3; + uint32_t suBeamformeeCap:1; + uint32_t suBeamFormerCap:1; + uint32_t rxSTBC:3; + uint32_t txSTBC:1; + uint32_t shortGI160and80plus80MHz:1; + uint32_t shortGI80MHz:1; + uint32_t ldpcCodingCap:1; + uint32_t supportedChannelWidthSet:2; + uint32_t maxMPDULen:2; +#else + uint32_t maxMPDULen:2; + uint32_t supportedChannelWidthSet:2; + uint32_t ldpcCodingCap:1; + uint32_t shortGI80MHz:1; + uint32_t shortGI160and80plus80MHz:1; + uint32_t txSTBC:1; + uint32_t rxSTBC:3; + uint32_t suBeamFormerCap:1; + uint32_t suBeamformeeCap:1; + uint32_t csnofBeamformerAntSup:3; + uint32_t numSoundingDim:3; + uint32_t muBeamformerCap:1; + uint32_t muBeamformeeCap:1; + uint32_t vhtTXOPPS:1; + uint32_t htcVHTCap:1; + uint32_t maxAMPDULenExp:3; + uint32_t vhtLinkAdaptCap:2; + uint32_t rxAntPattern:1; + uint32_t txAntPattern:1; + uint32_t reserved1:2; +#endif +} qdf_packed tSirMacVHTCapabilityInfo; + +typedef struct sSirMacVHTTxSupDataRateInfo { +#ifndef ANI_LITTLE_BIT_ENDIAN + uint16_t reserved:3; + uint16_t txSupDataRate:13; +#else + uint16_t txSupDataRate:13; + uint16_t reserved:3; +#endif +} qdf_packed tSirMacVHTTxSupDataRateInfo; + +typedef struct sSirMacVHTRxSupDataRateInfo { +#ifndef ANI_LITTLE_BIT_ENDIAN + uint16_t reserved:3; + uint16_t rxSupDataRate:13; +#else + uint16_t rxSupDataRate:13; + uint16_t reserved:3; +#endif +} qdf_packed tSirMacVHTRxSupDataRateInfo; + +/** + * struct sSirVhtMcsInfo - VHT MCS information + * @rx_mcs_map: RX MCS map 2 bits for each stream, total 8 streams + * @rx_highest: Indicates highest long GI VHT PPDU data rate + * STA can receive. Rate expressed in units of 1 Mbps. + * If this field is 0 this value should not be used to + * consider the highest RX data rate supported. + * @tx_mcs_map: TX MCS map 2 bits for each stream, total 8 streams + * @tx_highest: Indicates highest long GI VHT PPDU data rate + * STA can transmit. Rate expressed in units of 1 Mbps. + * If this field is 0 this value should not be used to + * consider the highest TX data rate supported. + */ +typedef struct sSirVhtMcsInfo { + uint16_t rxMcsMap; + uint16_t rxHighest; + uint16_t txMcsMap; + uint16_t txHighest; +} tSirVhtMcsInfo; + +/** + * struct sSirVHtCap - VHT capabilities + * + * This structure is the "VHT capabilities element" as + * described in 802.11ac D3.0 8.4.2.160 + * @vht_cap_info: VHT capability info + * @supp_mcs: VHT MCS supported rates + */ +typedef struct sSirVHtCap { + uint32_t vhtCapInfo; + tSirVhtMcsInfo suppMcs; +} tSirVHTCap; + +/** + * struct sSirHtCap - HT capabilities + * + * This structure refers to "HT capabilities element" as + * described in 802.11n draft section 7.3.2.52 + */ + +typedef struct sSirHtCap { + uint16_t capInfo; + uint8_t ampduParamsInfo; + uint8_t suppMcsSet[16]; + uint16_t extendedHtCapInfo; + uint32_t txBFCapInfo; + uint8_t antennaSelectionInfo; +} tSirHTCap; + +/* HT Cap and HT IE Size defines */ +#define HT_CAPABILITY_IE_SIZE 28 +#define HT_INFO_IE_SIZE 24 + +/* */ +/* Determines the current operating mode of the 802.11n STA */ +/* */ + +typedef enum eSirMacHTOperatingMode { + eSIR_HT_OP_MODE_PURE, /* No Protection */ + eSIR_HT_OP_MODE_OVERLAP_LEGACY, /* Overlap Legacy device present, protection is optional */ + eSIR_HT_OP_MODE_NO_LEGACY_20MHZ_HT, /* No legacy device, but 20 MHz HT present */ + eSIR_HT_OP_MODE_MIXED /* Protetion is required */ +} tSirMacHTOperatingMode; + +/* Spatial Multiplexing(SM) Power Save mode */ +typedef enum eSirMacHTMIMOPowerSaveState { + eSIR_HT_MIMO_PS_STATIC = 0, /* Static SM Power Save mode */ + eSIR_HT_MIMO_PS_DYNAMIC = 1, /* Dynamic SM Power Save mode */ + eSIR_HT_MIMO_PS_NA = 2, /* reserved */ + eSIR_HT_MIMO_PS_NO_LIMIT = 3 /* SM Power Save disabled */ +} tSirMacHTMIMOPowerSaveState; + +typedef enum eSirMacHTChannelWidth { + eHT_CHANNEL_WIDTH_20MHZ = 0, + eHT_CHANNEL_WIDTH_40MHZ = 1, + eHT_CHANNEL_WIDTH_80MHZ = 2, + eHT_CHANNEL_WIDTH_160MHZ = 3, + eHT_CHANNEL_WIDTH_80P80MHZ = 4, + eHT_MAX_CHANNEL_WIDTH +} tSirMacHTChannelWidth; + +typedef enum eSirMacHTChannelType { + eHT_CHAN_NO_HT = 0, + eHT_CHAN_HT20 = 1, + eHT_CHAN_HT40MINUS = 2, + eHT_CHAN_HT40PLUS = 3 +} tSirMacHTChannelType; + +/* Packet struct for HT capability */ +typedef struct sHtCaps { + uint16_t advCodingCap:1; + uint16_t supportedChannelWidthSet:1; + uint16_t mimoPowerSave:2; + uint16_t greenField:1; + uint16_t shortGI20MHz:1; + uint16_t shortGI40MHz:1; + uint16_t txSTBC:1; + uint16_t rxSTBC:2; + uint16_t delayedBA:1; + uint16_t maximalAMSDUsize:1; + uint16_t dsssCckMode40MHz:1; + uint16_t psmp:1; + uint16_t stbcControlFrame:1; + uint16_t lsigTXOPProtection:1; + uint8_t maxRxAMPDUFactor:2; + uint8_t mpduDensity:3; + uint8_t reserved1:3; + uint8_t supportedMCSSet[16]; + uint16_t pco:1; + uint16_t transitionTime:2; + uint16_t reserved2:5; + uint16_t mcsFeedback:2; + uint16_t reserved3:6; + uint32_t txBF:1; + uint32_t rxStaggeredSounding:1; + uint32_t txStaggeredSounding:1; + uint32_t rxZLF:1; + uint32_t txZLF:1; + uint32_t implicitTxBF:1; + uint32_t calibration:2; + uint32_t explicitCSITxBF:1; + uint32_t explicitUncompressedSteeringMatrix:1; + uint32_t explicitBFCSIFeedback:3; + uint32_t explicitUncompressedSteeringMatrixFeedback:3; + uint32_t explicitCompressedSteeringMatrixFeedback:3; + uint32_t csiNumBFAntennae:2; + uint32_t uncompressedSteeringMatrixBFAntennae:2; + uint32_t compressedSteeringMatrixBFAntennae:2; + uint32_t reserved4:7; + uint8_t antennaSelection:1; + uint8_t explicitCSIFeedbackTx:1; + uint8_t antennaIndicesFeedbackTx:1; + uint8_t explicitCSIFeedback:1; + uint8_t antennaIndicesFeedback:1; + uint8_t rxAS:1; + uint8_t txSoundingPPDUs:1; + uint8_t reserved5:1; + +} qdf_packed tHtCaps; + +/* During 11h channel switch, the AP can indicate if the + * STA needs to stop the transmission or continue until the + * channel-switch. + * eSIR_CHANSW_MODE_NORMAL - STA can continue transmission + * eSIR_CHANSW_MODE_SILENT - STA should stop transmission + */ +typedef enum eSirMacChanSwMode { + eSIR_CHANSW_MODE_NORMAL = 0, + eSIR_CHANSW_MODE_SILENT = 1 +} tSirMacChanSwitchMode; + +typedef struct _BarControl { + +#ifndef ANI_BIG_BYTE_ENDIAN + + uint16_t barAckPolicy:1; + uint16_t multiTID:1; + uint16_t bitMap:1; + uint16_t rsvd:9; + uint16_t numTID:4; + +#else + uint16_t numTID:4; + uint16_t rsvd:9; + uint16_t bitMap:1; + uint16_t multiTID:1; + uint16_t barAckPolicy:1; + +#endif + +} qdf_packed barCtrlType; + +typedef struct _BARFrmStruct { + tSirMacFrameCtl fc; + uint16_t duration; + tSirMacAddr rxAddr; + tSirMacAddr txAddr; + barCtrlType barControl; + tSirMacSeqCtl ssnCtrl; +} qdf_packed BARFrmType; + +/* Supported MCS set */ +#define SIZE_OF_SUPPORTED_MCS_SET 16 +#define SIZE_OF_BASIC_MCS_SET 16 +#define VALID_MCS_SIZE 77 /* 0-76 */ +#define MCS_RX_HIGHEST_SUPPORTED_RATE_BYTE_OFFSET 10 +#define VALID_MAX_MCS_INDEX 8 + +/* */ +/* The following enums will be used to get the "current" HT Capabilities of */ +/* the local STA in a generic fashion. In other words, the following enums */ +/* identify the HT capabilities that can be queried or set. */ +/* */ +typedef enum eHTCapability { + eHT_LSIG_TXOP_PROTECTION, + eHT_STBC_CONTROL_FRAME, + eHT_PSMP, + eHT_DSSS_CCK_MODE_40MHZ, + eHT_MAX_AMSDU_LENGTH, + eHT_MAX_AMSDU_NUM, + eHT_RX_STBC, + eHT_TX_STBC, + eHT_SHORT_GI_40MHZ, + eHT_SHORT_GI_20MHZ, + eHT_GREENFIELD, + eHT_MIMO_POWER_SAVE, + eHT_SUPPORTED_CHANNEL_WIDTH_SET, + eHT_ADVANCED_CODING, + eHT_MAX_RX_AMPDU_FACTOR, + eHT_MPDU_DENSITY, + eHT_PCO, + eHT_TRANSITION_TIME, + eHT_MCS_FEEDBACK, + eHT_TX_BEAMFORMING, + eHT_ANTENNA_SELECTION, + /* The following come under Additional HT Capabilities */ + eHT_SI_GRANULARITY, + eHT_CONTROLLED_ACCESS, + eHT_RIFS_MODE, + eHT_RECOMMENDED_TX_WIDTH_SET, + eHT_EXTENSION_CHANNEL_OFFSET, + eHT_OP_MODE, + eHT_BASIC_STBC_MCS, + eHT_DUAL_CTS_PROTECTION, + eHT_LSIG_TXOP_PROTECTION_FULL_SUPPORT, + eHT_PCO_ACTIVE, + eHT_PCO_PHASE +} tHTCapability; + +/* HT Capabilities Info */ +typedef struct sSirMacHTCapabilityInfo { +#ifndef ANI_LITTLE_BIT_ENDIAN + uint16_t lsigTXOPProtection:1; /* Dynamic state */ + uint16_t stbcControlFrame:1; /* Static via CFG */ + uint16_t psmp:1; /* Static via CFG */ + uint16_t dsssCckMode40MHz:1; /* Static via CFG */ + uint16_t maximalAMSDUsize:1; /* Static via CFG */ + uint16_t delayedBA:1; /* Static via CFG */ + uint16_t rxSTBC:2; /* Static via CFG */ + uint16_t txSTBC:1; /* Static via CFG */ + uint16_t shortGI40MHz:1; /* Static via CFG */ + uint16_t shortGI20MHz:1; /* Static via CFG */ + uint16_t greenField:1; /* Static via CFG */ + uint16_t mimoPowerSave:2; /* Dynamic state */ + uint16_t supportedChannelWidthSet:1; /* Static via CFG */ + uint16_t advCodingCap:1; /* Static via CFG */ +#else + uint16_t advCodingCap:1; + uint16_t supportedChannelWidthSet:1; + uint16_t mimoPowerSave:2; + uint16_t greenField:1; + uint16_t shortGI20MHz:1; + uint16_t shortGI40MHz:1; + uint16_t txSTBC:1; + uint16_t rxSTBC:2; + uint16_t delayedBA:1; + uint16_t maximalAMSDUsize:1; + uint16_t dsssCckMode40MHz:1; + uint16_t psmp:1; + uint16_t stbcControlFrame:1; + uint16_t lsigTXOPProtection:1; +#endif +} qdf_packed tSirMacHTCapabilityInfo; + +/* HT Parameters Info */ +typedef struct sSirMacHTParametersInfo { +#ifndef ANI_LITTLE_BIT_ENDIAN + uint8_t reserved:3; + uint8_t mpduDensity:3; /* Dynamic state */ + uint8_t maxRxAMPDUFactor:2; /* Dynamic state */ +#else + uint8_t maxRxAMPDUFactor:2; + uint8_t mpduDensity:3; + uint8_t reserved:3; +#endif +} qdf_packed tSirMacHTParametersInfo; + +/* Extended HT Capabilities Info */ +typedef struct sSirMacExtendedHTCapabilityInfo { +#ifndef ANI_LITTLE_BIT_ENDIAN + uint16_t reserved2:6; + uint16_t mcsFeedback:2; /* Static via CFG */ + uint16_t reserved1:5; + uint16_t transitionTime:2; /* Static via CFG */ + uint16_t pco:1; /* Static via CFG */ +#else + uint16_t pco:1; + uint16_t transitionTime:2; + uint16_t reserved1:5; + uint16_t mcsFeedback:2; + uint16_t reserved2:6; +#endif +} qdf_packed tSirMacExtendedHTCapabilityInfo; + +/* IEEE 802.11n/D7.0 - 7.3.2.57.4 */ +/* Part of the "supported MCS set field" */ +typedef struct sSirMacRxHighestSupportRate { +#ifndef ANI_LITTLE_BIT_ENDIAN + uint16_t reserved:6; + uint16_t rate:10; +#else + uint16_t rate:10; + uint16_t reserved:6; +#endif +} qdf_packed tSirMacRxHighestSupportRate, *tpSirMacRxHighestSupportRate; + +/* Transmit Beam Forming Capabilities Info */ +typedef struct sSirMacTxBFCapabilityInfo { +#ifndef ANI_LITTLE_BIT_ENDIAN + uint32_t reserved:7; + uint32_t compressedSteeringMatrixBFAntennae:2; /* Static via CFG */ + /* Static via CFG */ + uint32_t uncompressedSteeringMatrixBFAntennae:2; + uint32_t csiNumBFAntennae:2; /* Static via CFG */ + /* Static via CFG */ + uint32_t explicitCompressedSteeringMatrixFeedback:3; + /* Static via CFG */ + uint32_t explicitUncompressedSteeringMatrixFeedback:3; + uint32_t explicitBFCSIFeedback:3; /* Static via CFG */ + uint32_t explicitUncompressedSteeringMatrix:1; /* Static via CFG */ + uint32_t explicitCSITxBF:1; /* Static via CFG */ + uint32_t calibration:2; /* Static via CFG */ + uint32_t implicitTxBF:1; /* Static via CFG */ + uint32_t txZLF:1; /* Static via CFG */ + uint32_t rxZLF:1; /* Static via CFG */ + uint32_t txStaggeredSounding:1; /* Static via CFG */ + uint32_t rxStaggeredSounding:1; /* Static via CFG */ + uint32_t txBF:1; /* Static via CFG */ +#else + uint32_t txBF:1; + uint32_t rxStaggeredSounding:1; + uint32_t txStaggeredSounding:1; + uint32_t rxZLF:1; + uint32_t txZLF:1; + uint32_t implicitTxBF:1; + uint32_t calibration:2; + uint32_t explicitCSITxBF:1; + uint32_t explicitUncompressedSteeringMatrix:1; + uint32_t explicitBFCSIFeedback:3; + uint32_t explicitUncompressedSteeringMatrixFeedback:3; + uint32_t explicitCompressedSteeringMatrixFeedback:3; + uint32_t csiNumBFAntennae:2; + uint32_t uncompressedSteeringMatrixBFAntennae:2; + uint32_t compressedSteeringMatrixBFAntennae:2; + uint32_t reserved:7; +#endif +} qdf_packed tSirMacTxBFCapabilityInfo; + +/* Antenna Selection Capability Info */ +typedef struct sSirMacASCapabilityInfo { +#ifndef ANI_LITTLE_BIT_ENDIAN + uint8_t reserved2:1; + uint8_t txSoundingPPDUs:1; /* Static via CFG */ + uint8_t rxAS:1; /* Static via CFG */ + uint8_t antennaIndicesFeedback:1; /* Static via CFG */ + uint8_t explicitCSIFeedback:1; /* Static via CFG */ + uint8_t antennaIndicesFeedbackTx:1; /* Static via CFG */ + uint8_t explicitCSIFeedbackTx:1; /* Static via CFG */ + uint8_t antennaSelection:1; /* Static via CFG */ +#else + uint8_t antennaSelection:1; + uint8_t explicitCSIFeedbackTx:1; + uint8_t antennaIndicesFeedbackTx:1; + uint8_t explicitCSIFeedback:1; + uint8_t antennaIndicesFeedback:1; + uint8_t rxAS:1; + uint8_t txSoundingPPDUs:1; + uint8_t reserved2:1; +#endif +} qdf_packed tSirMacASCapabilityInfo; + +/* Additional HT IE Field1 */ +typedef struct sSirMacHTInfoField1 { +#ifndef ANI_LITTLE_BIT_ENDIAN + uint8_t serviceIntervalGranularity:3; /* Dynamic state */ + uint8_t controlledAccessOnly:1; /* Static via CFG */ + uint8_t rifsMode:1; /* Dynamic state */ + uint8_t recommendedTxWidthSet:1; /* Dynamic state */ + uint8_t secondaryChannelOffset:2; /* Dynamic state */ +#else + uint8_t secondaryChannelOffset:2; + uint8_t recommendedTxWidthSet:1; + uint8_t rifsMode:1; + uint8_t controlledAccessOnly:1; + uint8_t serviceIntervalGranularity:3; +#endif +} qdf_packed tSirMacHTInfoField1; + +/* Additional HT IE Field2 */ +typedef struct sSirMacHTInfoField2 { +#ifndef ANI_LITTLE_BIT_ENDIAN + uint16_t reserved:11; + uint16_t obssNonHTStaPresent:1; /*added for Obss */ + uint16_t transmitBurstLimit:1; + uint16_t nonGFDevicesPresent:1; + uint16_t opMode:2; /* Dynamic state */ +#else + uint16_t opMode:2; + uint16_t nonGFDevicesPresent:1; + uint16_t transmitBurstLimit:1; + uint16_t obssNonHTStaPresent:1; /*added for Obss */ + uint16_t reserved:11; +#endif +} qdf_packed tSirMacHTInfoField2; + +/* Additional HT IE Field3 */ +typedef struct sSirMacHTInfoField3 { +#ifndef ANI_LITTLE_BIT_ENDIAN + uint16_t reserved:4; + uint16_t pcoPhase:1; /* Dynamic state */ + uint16_t pcoActive:1; /* Dynamic state */ + uint16_t lsigTXOPProtectionFullSupport:1; /* Dynamic state */ + uint16_t secondaryBeacon:1; /* Dynamic state */ + uint16_t dualCTSProtection:1; /* Dynamic state */ + uint16_t basicSTBCMCS:7; /* Dynamic state */ +#else + uint16_t basicSTBCMCS:7; + uint16_t dualCTSProtection:1; + uint16_t secondaryBeacon:1; + uint16_t lsigTXOPProtectionFullSupport:1; + uint16_t pcoActive:1; + uint16_t pcoPhase:1; + uint16_t reserved:4; +#endif +} qdf_packed tSirMacHTInfoField3; + +typedef struct sSirMacProbeReqFrame { + tSirMacSSidIE ssIdIE; + tSirMacRateSetIE rateSetIE; + tSirMacRateSetIE extendedRateSetIE; +} qdf_packed tSirMacProbeReqFrame, *tpSirMacProbeReqFrame; + +typedef struct sSirMacProbeRspFrame { + tSirMacTimeStamp ts; + tSirMacBeaconInterval beaconInterval; + tSirMacCapabilityInfo capabilityInfo; + tSirMacSSidIE ssIdIE; + tSirMacRateSetIE rateSetIE; + tSirMacRateSetIE extendedRateSetIE; + tSirMacNonErpPresentIE nonErpPresent; + tSirMacDsParamSetIE dsParamsIE; + tSirMacCfParamSetIE cfParamsIE; +} qdf_packed tSirMacProbeRspFrame, *tpSirMacProbeRspFrame; + +typedef struct sSirMacAuthFrameBody { + uint16_t authAlgoNumber; + uint16_t authTransactionSeqNumber; + uint16_t authStatusCode; + uint8_t type; /* = SIR_MAC_CHALLENGE_TEXT_EID */ + uint8_t length; /* = SIR_MAC_AUTH_CHALLENGE_LENGTH */ + uint8_t challengeText[SIR_MAC_AUTH_CHALLENGE_LENGTH]; +} qdf_packed tSirMacAuthFrameBody, *tpSirMacAuthFrameBody; + +typedef struct sSirMacAuthenticationFrame { + tSirMacAuthFrameBody authFrameBody; +} qdf_packed tSirMacAuthFrame, *tpSirMacAuthFrame; + +typedef struct sSirMacAssocReqFrame { + tSirMacCapabilityInfo capabilityInfo; + uint16_t listenInterval; + tSirMacSSidIE ssIdIE; + tSirMacRateSetIE rateSetIE; + tSirMacRateSetIE extendedRateSetIE; +} qdf_packed tSirMacAssocReqFrame, *tpSirMacAssocReqFrame; + +typedef struct sSirMacAssocRspFrame { + tSirMacCapabilityInfo capabilityInfo; + uint16_t statusCode; + uint16_t aid; + tSirMacRateSetIE supportedRates; + tSirMacRateSetIE extendedRateSetIE; +} qdf_packed tSirMacAssocRspFrame, *tpSirMacAssocRspFrame; + +typedef struct sSirMacDisassocFrame { + uint16_t reasonCode; +} qdf_packed tSirMacDisassocFrame, *tpSirMacDisassocFrame; + +typedef struct sDSirMacDeauthFrame { + uint16_t reasonCode; +} qdf_packed tSirMacDeauthFrame, *tpSirMacDeauthFrame; + +/* / Common header for all action frames */ +typedef struct sSirMacActionFrameHdr { + uint8_t category; + uint8_t actionID; +} qdf_packed tSirMacActionFrameHdr, *tpSirMacActionFrameHdr; + +typedef struct sSirMacVendorSpecificFrameHdr { + uint8_t category; + uint8_t Oui[4]; +} qdf_packed tSirMacVendorSpecificFrameHdr, +*tpSirMacVendorSpecificFrameHdr; + +typedef struct sSirMacVendorSpecificPublicActionFrameHdr { + uint8_t category; + uint8_t actionID; + uint8_t Oui[4]; + uint8_t OuiSubType; + uint8_t dialogToken; +} qdf_packed tSirMacVendorSpecificPublicActionFrameHdr, +*tpSirMacVendorSpecificPublicActionFrameHdr; + +typedef struct sSirMacP2PActionFrameHdr { + uint8_t category; + uint8_t Oui[4]; + uint8_t OuiSubType; + uint8_t dialogToken; +} qdf_packed tSirMacP2PActionFrameHdr, *tpSirMacP2PActionFrameHdr; + +typedef struct sSirMacMeasActionFrameHdr { + uint8_t category; + uint8_t actionID; + uint8_t dialogToken; +} tSirMacMeasActionFrameHdr, *tpSirMacMeasActionFrameHdr; + +#ifdef ANI_SUPPORT_11H +typedef struct sSirMacTpcReqActionFrame { + tSirMacMeasActionFrameHdr actionHeader; + uint8_t type; + uint8_t length; +} tSirMacTpcReqActionFrame, *tpSirMacTpcReqActionFrame; +typedef struct sSirMacMeasReqActionFrame { + tSirMacMeasActionFrameHdr actionHeader; + tSirMacMeasReqIE measReqIE; +} tSirMacMeasReqActionFrame, *tpSirMacMeasReqActionFrame; +#endif + +typedef struct sSirMacNeighborReportReq { + uint8_t dialogToken; + uint8_t ssid_present; + tSirMacSSid ssid; +} tSirMacNeighborReportReq, *tpSirMacNeighborReportReq; + +typedef struct sSirMacLinkReport { + uint8_t dialogToken; + uint8_t txPower; + uint8_t rxAntenna; + uint8_t txAntenna; + uint8_t rcpi; + uint8_t rsni; +} tSirMacLinkReport, *tpSirMacLinkReport; + +#define BEACON_REPORT_MAX_IES 224 /* Refer IEEE 802.11k-2008, Table 7-31d */ +typedef struct sSirMacBeaconReport { + uint8_t regClass; + uint8_t channel; + uint8_t measStartTime[8]; + uint8_t measDuration; + uint8_t phyType; + uint8_t bcnProbeRsp; + uint8_t rsni; + uint8_t rcpi; + tSirMacAddr bssid; + uint8_t antennaId; + uint32_t parentTSF; + uint8_t numIes; + uint8_t Ies[BEACON_REPORT_MAX_IES]; + +} tSirMacBeaconReport, *tpSirMacBeaconReport; + +#define RADIO_REPORTS_MAX_IN_A_FRAME 4 +typedef struct sSirMacRadioMeasureReport { + uint8_t token; + uint8_t refused; + uint8_t incapable; + uint8_t type; + union { + tSirMacBeaconReport beaconReport; + } report; + +} tSirMacRadioMeasureReport, *tpSirMacRadioMeasureReport; + +/* QOS action frame definitions */ + +/* max number of possible tclas elements in any frame */ +#define SIR_MAC_TCLASIE_MAXNUM 2 + +/* 11b rate encoding in MAC format */ + +#define SIR_MAC_RATE_1 0x02 +#define SIR_MAC_RATE_2 0x04 +#define SIR_MAC_RATE_5_5 0x0B +#define SIR_MAC_RATE_11 0x16 + +/* 11a/g rate encoding in MAC format */ + +#define SIR_MAC_RATE_6 0x0C +#define SIR_MAC_RATE_9 0x12 +#define SIR_MAC_RATE_12 0x18 +#define SIR_MAC_RATE_18 0x24 +#define SIR_MAC_RATE_24 0x30 +#define SIR_MAC_RATE_36 0x48 +#define SIR_MAC_RATE_48 0x60 +#define SIR_MAC_RATE_54 0x6C + +/* ANI legacy supported rates */ +#define SIR_MAC_RATE_72 0x01 +#define SIR_MAC_RATE_96 0x03 +#define SIR_MAC_RATE_108 0x05 + +/* ANI enhanced rates */ +#define SIR_MAC_RATE_42 1000 +#define SIR_MAC_RATE_84 1001 +#define SIR_MAC_RATE_126 1002 +#define SIR_MAC_RATE_144 1003 +#define SIR_MAC_RATE_168 1004 +#define SIR_MAC_RATE_192 1005 +#define SIR_MAC_RATE_216 1006 +#define SIR_MAC_RATE_240 1007 + +#define SIR_MAC_RATE_1_BITMAP (1<<0) +#define SIR_MAC_RATE_2_BITMAP (1<<1) +#define SIR_MAC_RATE_5_5_BITMAP (1<<2) +#define SIR_MAC_RATE_11_BITMAP (1<<3) +#define SIR_MAC_RATE_6_BITMAP (1<<4) +#define SIR_MAC_RATE_9_BITMAP (1<<5) +#define SIR_MAC_RATE_12_BITMAP (1<<6) +#define SIR_MAC_RATE_18_BITMAP (1<<7) +#define SIR_MAC_RATE_24_BITMAP (1<<8) +#define SIR_MAC_RATE_36_BITMAP (1<<9) +#define SIR_MAC_RATE_48_BITMAP (1<<10) +#define SIR_MAC_RATE_54_BITMAP (1<<11) + +#define sirIsArate(x) ((((uint8_t)x) == SIR_MAC_RATE_6) || \ + (((uint8_t)x) == SIR_MAC_RATE_9) || \ + (((uint8_t)x) == SIR_MAC_RATE_12) || \ + (((uint8_t)x) == SIR_MAC_RATE_18) || \ + (((uint8_t)x) == SIR_MAC_RATE_24) || \ + (((uint8_t)x) == SIR_MAC_RATE_36) || \ + (((uint8_t)x) == SIR_MAC_RATE_48) || \ + (((uint8_t)x) == SIR_MAC_RATE_54)) + +#define sirIsBrate(x) ((((uint8_t)x) == SIR_MAC_RATE_1) || \ + (((uint8_t)x) == SIR_MAC_RATE_2) || \ + (((uint8_t)x) == SIR_MAC_RATE_5_5) || \ + (((uint8_t)x) == SIR_MAC_RATE_11)) + +#define sirIsGrate(x) ((((uint8_t)x) == SIR_MAC_RATE_1) || \ + (((uint8_t)x) == SIR_MAC_RATE_2) || \ + (((uint8_t)x) == SIR_MAC_RATE_5_5) || \ + (((uint8_t)x) == SIR_MAC_RATE_11) || \ + (((uint8_t)x) == SIR_MAC_RATE_6) || \ + (((uint8_t)x) == SIR_MAC_RATE_9) || \ + (((uint8_t)x) == SIR_MAC_RATE_12) || \ + (((uint8_t)x) == SIR_MAC_RATE_18) || \ + (((uint8_t)x) == SIR_MAC_RATE_24) || \ + (((uint8_t)x) == SIR_MAC_RATE_36) || \ + (((uint8_t)x) == SIR_MAC_RATE_48) || \ + (((uint8_t)x) == SIR_MAC_RATE_54)) + +#define SIR_MAC_MIN_IE_LEN 2 /* Minimum IE length for IE validation */ + +#define SIR_MAC_TI_TYPE_REASSOC_DEADLINE 1 +#define SIR_MAC_TI_TYPE_KEY_LIFETIME 2 +#define SIR_MAC_TI_TYPE_ASSOC_COMEBACK 3 + +#define SIR_MAC_VHT_CAP_MAX_MPDU_LEN 0 +#define SIR_MAC_VHT_CAP_SUPP_CH_WIDTH_SET 2 +#define SIR_MAC_VHT_CAP_LDPC_CODING_CAP 4 +#define SIR_MAC_VHT_CAP_SHORTGI_80MHZ 5 +#define SIR_MAC_VHT_CAP_SHORTGI_160_80_80MHZ 6 +#define SIR_MAC_VHT_CAP_TXSTBC 7 +#define SIR_MAC_VHT_CAP_RXSTBC 8 +#define SIR_MAC_VHT_CAP_SU_BEAMFORMER_CAP 11 +#define SIR_MAC_VHT_CAP_SU_BEAMFORMEE_CAP 12 +#define SIR_MAC_VHT_CAP_CSN_BEAMORMER_ANT_SUP 13 +#define SIR_MAC_VHT_CAP_NUM_SOUNDING_DIM 16 +#define SIR_MAC_VHT_CAP_NUM_BEAM_FORMER_CAP 19 +#define SIR_MAC_VHT_CAP_NUM_BEAM_FORMEE_CAP 20 +#define SIR_MAC_VHT_CAP_TXOPPS 21 +#define SIR_MAC_VHT_CAP_HTC_CAP 22 +#define SIR_MAC_VHT_CAP_MAX_AMDU_LEN_EXPO 23 +#define SIR_MAC_VHT_CAP_LINK_ADAPT_CAP 26 +#define SIR_MAC_VHT_CAP_RX_ANTENNA_PATTERN 28 +#define SIR_MAC_VHT_CAP_TX_ANTENNA_PATTERN 29 +#define SIR_MAC_VHT_CAP_RESERVED2 30 + +#define SIR_MAC_HT_CAP_ADVCODING_S 0 +#define SIR_MAC_HT_CAP_CHWIDTH40_S 1 +#define SIR_MAC_HT_CAP_SMPOWERSAVE_DYNAMIC_S 2 +#define SIR_MAC_HT_CAP_SM_RESERVED_S 3 +#define SIR_MAC_HT_CAP_GREENFIELD_S 4 +#define SIR_MAC_HT_CAP_SHORTGI20MHZ_S 5 +#define SIR_MAC_HT_CAP_SHORTGI40MHZ_S 6 +#define SIR_MAC_HT_CAP_TXSTBC_S 7 +#define SIR_MAC_HT_CAP_RXSTBC_S 8 +#define SIR_MAC_HT_CAP_DELAYEDBLKACK_S 10 +#define SIR_MAC_HT_CAP_MAXAMSDUSIZE_S 11 +#define SIR_MAC_HT_CAP_DSSSCCK40_S 12 +#define SIR_MAC_HT_CAP_PSMP_S 13 +#define SIR_MAC_HT_CAP_INTOLERANT40_S 14 +#define SIR_MAC_HT_CAP_LSIGTXOPPROT_S 15 + +#define SIR_MAC_TXSTBC 1 +#define SIR_MAC_RXSTBC 1 + +#endif /* __MAC_PROT_DEFS_H */ diff --git a/drivers/staging/qcacld-3.0/core/mac/inc/sir_types.h b/drivers/staging/qcacld-3.0/core/mac/inc/sir_types.h new file mode 100644 index 0000000000000000000000000000000000000000..9580745ebb5fb17bce283925a7408056361b77c4 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/inc/sir_types.h @@ -0,0 +1,236 @@ +/* + * Copyright (c) 2011-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * + * This file sir_types.h contains the common types + * + * Author: V. K. Kandarpa + * Date: 04/12/2002 + */ + +#ifndef __SIR_TYPES_H +#define __SIR_TYPES_H + +#include + + +/** ------------------------------------------------------------------------ * + + \typedef tHalHandle + + \brief Handle to the HAL. The HAL handle is returned by the HAL after it + is opened (by calling halOpen). + + ------------------------------------------------------------------------- */ +typedef void *tHalHandle; + +/** ------------------------------------------------------------------------ * + + \typedef tHddHandle + + \brief Handle to the HDD. The HDD handle is given to the HAL from + the HDD on halOpen. The HDD handle is an input to all HDD/PAL function + calls and represents an opaque handle to the HDD instance that is tied + to the HAL instance, opened through halOpen. + + The HDD must be able to derive it's internal instance structure pointer + through this handle. hint hint... + + ------------------------------------------------------------------------- */ +typedef void *tHddHandle; + +/* ********************************************** * +* * +* SIRIUS ERROR Codes / Return Codes * +* * +* ********************************************** */ + +/* / Return status type */ +typedef enum eSirRetStatus { + eSIR_SUCCESS, + eSIR_FAILURE, + + /* / System Errors */ + eSIR_SYS_ERROR_BASE = 0x100, + eSIR_SYS_TX_THREAD_CREATE_FAILED, + eSIR_SYS_TX_THREAD_RESUME_FAILED, + eSIR_SYS_TX_MSG_Q_CREATE_FAILED, + eSIR_SYS_TX_Q_SEND_FAILED, + eSIR_SYS_TX_Q_RECV_FAILED, + eSIR_SYS_TX_TIMER_ACTIVATE_FAILED, + eSIR_SYS_TX_TIMER_CHANGE_FAILED, + eSIR_SYS_TX_TIMER_CREATE_FAILED, + eSIR_MEM_ALLOC_FAILED, + eSIR_PCI_ERROR, + + /* Driver Return Codes */ + eSIR_HAL_ERROR_BASE = 0x1000, + eSIR_HAL_STAID_INVALID, /* 1 */ + eSIR_HAL_TCDESC_INVALID, /* 2 */ + eSIR_HAL_TX_WQ_NOT_VALID, /* 3 */ + eSIR_HAL_PREV_BMU_CMD_INCOMPLETE, /* 4 */ + eSIR_HAL_EEPROM_CRC_FAILED, /* 5 */ + eSIR_HAL_PCI_REVID_INVALID, /* 6 */ + eSIR_HAL_STA_TC_ID_INVALID, /* 7 */ + eSIR_HAL_TXWQ_EMPTY, /* 8 */ + eSIR_HAL_ROUT_TBL_TYPE_STYPE_INVALID, /* 9 */ + eSIR_HAL_TFP_ENABLE_FAILED, /* a */ + eSIR_HAL_TFP_ABORT_CMD_FAILED, /* b */ + eSIR_HAL_TFP_TEMPL_BCNLEN_INVALID, /* c */ + eSIR_HAL_TFP_TEMPL_SCHLEN_INVALID, /* d */ + eSIR_HAL_TFP_TEMPL_CFENDLEN_INVALID, /* e */ + eSIR_HAL_TFP_TEMPL_RRLEN_INVALID, /* f */ + eSIR_HAL_TFP_TEMPL_PSPOLLLEN_INVALID, /* 10 */ + eSIR_HAL_TFP_TEMPL_CTSLEN_INVALID, /* 11 */ + eSIR_HAL_TFP_TEMPL_CFPOLLLEN_INVALID, /* 12 */ + eSIR_HAL_TFP_TEMPL_BACKLEN_INVALID, /* 13 */ + eSIR_HAL_INPUT_INVALID, /* 14 */ + eSIR_HAL_GET_PDU_FAILED, /* 15 */ + eSIR_HAL_ADD_STA_ACK_POLICY_INVALID, /* 16 */ + eSIR_HAL_STA_EXISTS, /* 17 */ + eSIR_HAL_STA_DOES_NOT_EXIST, /* 18 */ + eSIR_HAL_MASTER_WQ_ID_INVALID, /* 19 */ + eSIR_HAL_WQ_NOT_EMPTY, /* 1a */ + eSIR_HAL_WQ_EMPTY, /* 1b */ + eSIR_HAL_PDUCNT_AND_NEXTPTR_MISMATCH, /* 1c */ + eSIR_HAL_ERR_NUM_BYTES_TO_BE_SET_TOO_BIG, /* 1d */ + eSIR_HAL_GET_PKT_LENGTH_INVALID, /* 1e */ + eSIR_HAL_AS_CNT_INVALID, /* 1f */ + eSIR_HAL_RFP_AGE_CMD_SEQFAIL, /* 20 */ + eSIR_HAL_RFP_AGE_CMD_AGE_CMD_TCFAIL, /* 21 */ + eSIR_HAL_RFP_AGE_CMD_PASS, /* 22 */ + eSIR_HAL_RFP_AGE_CMD_TIMEDOUT, /* 23 */ + eSIR_HAL_RHP_HASH_CMD_TIMEOUT, /* 24 */ + eSIR_HAL_RHP_ROUTING_TBL_SET_FAILED, /* 25 */ + eSIR_HAL_RHP_ROUTING_TBL_GET_FAILED, /* 26 */ + + eSIR_HAL_CAL_STATUS_CHK_FAILED, + + eSIR_HAL_SYS_ARM_DBG_MODE_SET_FAILED, + eSIR_HAL_TFP_BCN_SENT, + eSIR_HAL_TFP_BCN_NOT_SENT, + eSIR_HAL_TFP_BKOF_ID_INVALID, + eSIR_HAL_TFP_CFB_ENABLE_INPUT_INVALID, + eSIR_HAL_TFP_EDCF_TXOP_INVALID, + eSIR_HAL_TFP_TEMPL_LEN_INVALID, + eSIR_HAL_KEY_ID_INVALID, + eSIR_HAL_KEY_LEN_INVALID, + eSIR_HAL_CHID_INVALID, + eSIR_HAL_HIF_BURST_READ_FAILED, + eSIR_HAL_HIF_BURST_WRITE_FAILED, + eSIR_HAL_HIF_BURST_LEN_REQ_INVALID, + eSIR_HAL_HIF_TX_NO_FRAG_DESC, + + eSIR_HAL_INVALID_PRODUCT_ID, /* 44 */ + + eSIR_HAL_INVALID_CAPABILITY, /* 48 */ + eSIR_HAL_CB_NOT_ENABLED, /* 49 */ + eSIR_HAL_MAC_RATE_INVALID, /* 4a */ + eSIR_HAL_RHP_HANG, /* 4b */ + eSIR_HAL_UNSUPPORTED, /* 4c */ + eSIR_HAL_TSPEC_INVALID, /* 4d */ + + /* NIM Return Codes */ + eSIR_NIM_ERROR_BASE = 0x2000, + eSIR_NIM_ERR_INVALID_EVENT, + + /* MMH Return Codes */ + eSIR_NIM_MMH_ERROR_BASE = 0x2100, + eSIR_NIM_MMH_ERR_INV_EVENT, + eSIR_NIM_MMH_ERR_MSG_LEN, + eSIR_NIM_MMH_ERR_IN_Q_TYPE, + + /* MNT Return Codes */ + eSIR_NIM_MNT_ERROR_BASE = 0x2140, + + /* WDT Errors */ + eSIR_NIM_WDT_ERROR_BASE = 0x2180, + + /* LIM Return Codes */ + eSIR_LIM_ERROR_BASE = 0x2200, + eSIR_LIM_IGNORE_BEACON, + eSIR_LIM_INVALID_STA, + eSIR_LIM_MAX_STA_REACHED_ERROR, + + /* SCH Return Codes */ + eSIR_SCH_ERROR_BASE = 0x2300, + + /* PMM Return Codes */ + eSIR_PMM_ERROR_BASE = 0x2400, + eSIR_PMM_INVALID_MODE, + eSIR_PMM_INVALID_STATE, + eSIR_PMM_INVALID_ROLE, + eSIR_PMM_STA_NOT_ASSOCIATED, + eSIR_PMM_HEART_BEAT_TMOUT, + eSIR_PMM_NTH_BEACON_DELIVERY, + + /* ARQ Return Codes */ + eSIR_ARQ_ERROR_BASE = 0x2500, + + /* CFG Return Codes */ + eSIR_CFG_ERROR_BASE = 2600, + eSIR_CFG_INVALID_ID, + eSIR_CFG_INVALID_LEN, + + /* parser Return Codes */ + eSIR_PRS_ERROR_BASE = 0x2700, + eSIR_IGNORE_IE, + + /* Put all your return codes above this line */ + eSIR_ERROR_LAST +} tSirRetStatus; + +#define IS_SIR_STATUS_SUCCESS(status) (eSIR_SUCCESS == status) +typedef enum { + HAL_STOP_TYPE_SYS_RESET, + HAL_STOP_TYPE_SYS_DEEP_SLEEP, + HAL_STOP_TYPE_RF_KILL, +} tHalStopType; + +#ifdef WLAN_SOFTAP_VSTA_FEATURE +#define HAL_NUM_ASSOC_STA 32 +#define HAL_NUM_STA 41 +#define HAL_NUM_HW_STA 16 +#define HAL_NUM_GPSTA 4 + +/* is the STA a HW STA (excluding GP STAs) */ +#define IS_HWSTA_IDX(__x) \ + ((__x) < (HAL_NUM_HW_STA-HAL_NUM_GPSTA)) + +#else +/*In prima 12 HW stations are supported including BCAST STA(staId 0) + and SELF STA(staId 1) so total ASSOC stations which can connect to Prima + SoftAP = 12 - 1(Self STa) - 1(Bcast Sta) = 10 Stations. */ +#define HAL_NUM_STA 12 +#define HAL_NUM_ASSOC_STA 10 +#define HAL_NUM_HW_STA 12 +#endif + +#define STACFG_MAX_TC 8 + +#endif /* __SIR_TYPES_H */ diff --git a/drivers/staging/qcacld-3.0/core/mac/inc/wni_api.h b/drivers/staging/qcacld-3.0/core/mac/inc/wni_api.h new file mode 100644 index 0000000000000000000000000000000000000000..3804fdc64a4dc7dc80d6672adee9be7f22ff368e --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/inc/wni_api.h @@ -0,0 +1,575 @@ +/* + * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * This file wni_api.h contains message definitions exported by + * Sirius software modules. + * NOTE: See projects/sirius/include/sir_api.h for structure + * definitions of the host/FW messages. + * + * Author: Chandra Modumudi + * Date: 04/11/2002 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + */ + +#ifndef __WNI_API_H +#define __WNI_API_H + +#define SIR_SME_MODULE_ID 0x16 + +/* / Start of Sirius/Host message types */ +#define WNI_HOST_MSG_START 0x1500 + +enum eWniMsgTypes { + /* / CFG message types */ + eWNI_CFG_MSG_TYPES_BEGIN = WNI_HOST_MSG_START, + eWNI_CFG_MSG_TYPES_END = eWNI_CFG_MSG_TYPES_BEGIN + 0xFF, + + /* / SME message types */ + eWNI_SME_MSG_TYPES_BEGIN = eWNI_CFG_MSG_TYPES_END, + eWNI_SME_SYS_READY_IND, + eWNI_SME_SCAN_REQ, + eWNI_SME_SCAN_ABORT_IND, + eWNI_SME_SCAN_RSP, + eWNI_SME_JOIN_REQ, + eWNI_SME_JOIN_RSP, + eWNI_SME_SETCONTEXT_REQ, + eWNI_SME_SETCONTEXT_RSP, + eWNI_SME_REASSOC_REQ, + eWNI_SME_REASSOC_RSP, + eWNI_SME_DISASSOC_REQ, + eWNI_SME_DISASSOC_RSP, + eWNI_SME_DISASSOC_IND, + eWNI_SME_DISASSOC_CNF, + eWNI_SME_DEAUTH_REQ, + eWNI_SME_DEAUTH_RSP, + eWNI_SME_DEAUTH_IND, + eWNI_SME_DISCONNECT_DONE_IND, + eWNI_SME_WM_STATUS_CHANGE_NTF, + eWNI_SME_IBSS_NEW_PEER_IND, + eWNI_SME_IBSS_PEER_DEPARTED_IND, + eWNI_SME_START_BSS_REQ, + eWNI_SME_START_BSS_RSP, + eWNI_SME_ASSOC_IND, + eWNI_SME_ASSOC_CNF, + eWNI_SME_SWITCH_CHL_IND, + eWNI_SME_STOP_BSS_REQ, + eWNI_SME_STOP_BSS_RSP, + eWNI_SME_NEIGHBOR_BSS_IND, + eWNI_SME_DEAUTH_CNF, + eWNI_SME_MIC_FAILURE_IND, + eWNI_SME_ADDTS_REQ, + eWNI_SME_ADDTS_RSP, + eWNI_SME_DELTS_REQ, + eWNI_SME_DELTS_RSP, + eWNI_SME_DELTS_IND, + eWNI_SME_GET_STATISTICS_REQ, + eWNI_SME_GET_STATISTICS_RSP, + eWNI_SME_GET_RSSI_REQ, + eWNI_SME_GET_ASSOC_STAS_REQ, + eWNI_SME_TKIP_CNTR_MEAS_REQ, + eWNI_SME_UPDATE_APWPSIE_REQ, + eWNI_SME_GET_WPSPBC_SESSION_REQ, + eWNI_SME_WPS_PBC_PROBE_REQ_IND, + eWNI_SME_SET_APWPARSNIEs_REQ, + eWNI_SME_UPPER_LAYER_ASSOC_CNF, + eWNI_SME_SESSION_UPDATE_PARAM, + eWNI_SME_CHNG_MCC_BEACON_INTERVAL, + eWNI_SME_REMAIN_ON_CHANNEL_REQ, + eWNI_SME_REMAIN_ON_CHN_RSP, + eWNI_SME_REMAIN_ON_CHN_RDY_IND, + eWNI_SME_SEND_ACTION_FRAME_IND, + eWNI_SME_ABORT_REMAIN_ON_CHAN_IND, + eWNI_SME_UPDATE_NOA, + eWNI_SME_CLEAR_DFS_CHANNEL_LIST, + eWNI_SME_GET_SNR_REQ, + + eWNI_SME_RRM_MSG_TYPE_BEGIN, + + eWNI_SME_NEIGHBOR_REPORT_REQ_IND, + eWNI_SME_NEIGHBOR_REPORT_IND, + eWNI_SME_BEACON_REPORT_REQ_IND, + eWNI_SME_BEACON_REPORT_RESP_XMIT_IND, + + eWNI_SME_ADD_STA_SELF_RSP, + eWNI_SME_DEL_STA_SELF_RSP, + + eWNI_SME_FT_PRE_AUTH_REQ, + eWNI_SME_FT_PRE_AUTH_RSP, + eWNI_SME_FT_UPDATE_KEY, + eWNI_SME_FT_AGGR_QOS_REQ, + eWNI_SME_FT_AGGR_QOS_RSP, + +#if defined FEATURE_WLAN_ESE + eWNI_SME_ESE_ADJACENT_AP_REPORT, +#endif + + eWNI_SME_REGISTER_MGMT_FRAME_REQ, +#ifdef FEATURE_WLAN_SCAN_PNO + eWNI_SME_PREF_NETWORK_FOUND_IND, +#endif /* FEATURE_WLAN_SCAN_PNO */ + + eWNI_SME_CHANGE_COUNTRY_CODE, + eWNI_SME_GENERIC_CHANGE_COUNTRY_CODE, + eWNI_SME_MAX_ASSOC_EXCEEDED, +#ifdef FEATURE_WLAN_TDLS + eWNI_SME_TDLS_SEND_MGMT_REQ, + eWNI_SME_TDLS_SEND_MGMT_RSP, + eWNI_SME_TDLS_ADD_STA_REQ, + eWNI_SME_TDLS_ADD_STA_RSP, + eWNI_SME_TDLS_DEL_STA_REQ, + eWNI_SME_TDLS_DEL_STA_RSP, + eWNI_SME_TDLS_DEL_STA_IND, + eWNI_SME_TDLS_DEL_ALL_PEER_IND, + eWNI_SME_MGMT_FRM_TX_COMPLETION_IND, + eWNI_SME_TDLS_LINK_ESTABLISH_REQ, + eWNI_SME_TDLS_LINK_ESTABLISH_RSP, + eWNI_SME_TDLS_SHOULD_DISCOVER, + eWNI_SME_TDLS_SHOULD_TEARDOWN, + eWNI_SME_TDLS_PEER_DISCONNECTED, + eWNI_SME_TDLS_CONNECTION_TRACKER_NOTIFICATION, +#endif + /* NOTE: If you are planning to add more mesages, please make sure that */ + /* SIR_LIM_ITC_MSG_TYPES_BEGIN is moved appropriately. It is set as */ + /* SIR_LIM_MSG_TYPES_BEGIN+0xB0 = 12B0 (which means max of 176 messages and */ + /* eWNI_SME_TDLS_DEL_STA_RSP = 175. */ + /* Should fix above issue to enable TDLS_INTERNAL */ + eWNI_SME_SET_BCN_FILTER_REQ, + eWNI_SME_RESET_AP_CAPS_CHANGED, +#ifdef WLAN_FEATURE_11W + eWNI_SME_UNPROT_MGMT_FRM_IND, +#endif +#ifdef WLAN_FEATURE_GTK_OFFLOAD + eWNI_PMC_GTK_OFFLOAD_GETINFO_RSP, +#endif /* WLAN_FEATURE_GTK_OFFLOAD */ + eWNI_SME_CANDIDATE_FOUND_IND, /*ROAM candidate indication from FW */ + eWNI_SME_HANDOFF_REQ, /*upper layer requested handoff to driver in STA mode */ + eWNI_SME_ROAM_SCAN_OFFLOAD_RSP, /*Fwd the LFR scan offload rsp from FW to SME */ +#ifdef FEATURE_WLAN_LPHB + eWNI_SME_LPHB_IND, +#endif /* FEATURE_WLAN_LPHB */ + + eWNI_SME_IBSS_PEER_INFO_RSP, + eWNI_SME_GET_TSM_STATS_REQ, + eWNI_SME_GET_TSM_STATS_RSP, + eWNI_SME_TSM_IE_IND, + + eWNI_SME_READY_TO_SUSPEND_IND, +#ifdef FEATURE_WLAN_CH_AVOID + eWNI_SME_CH_AVOID_IND, +#endif /* FEATURE_WLAN_CH_AVOID */ + /* DFS EVENTS */ + eWNI_SME_DFS_RADAR_FOUND, /* RADAR found indication from DFS */ + eWNI_SME_CHANNEL_CHANGE_REQ, /* Channel Change Request from SAP */ + eWNI_SME_CHANNEL_CHANGE_RSP, /* Channel Change Response from WMA */ + eWNI_SME_START_BEACON_REQ, /* Start Beacon Transmission. */ + eWNI_SME_DFS_BEACON_CHAN_SW_IE_REQ, /* Transmit CSA IE in beacons */ + eWNI_SME_DFS_CSAIE_TX_COMPLETE_IND, /* To indicate completion of CSA IE */ + /* update in beacons/probe rsp */ + eWNI_SME_STATS_EXT_EVENT, + eWNI_SME_CSA_OFFLOAD_EVENT, + eWNI_SME_UPDATE_ADDITIONAL_IES, /* indicates Additional IE from hdd to PE */ + eWNI_SME_MODIFY_ADDITIONAL_IES, /* To indicate IE modify from hdd to PE */ +#ifdef FEATURE_WLAN_AUTO_SHUTDOWN + eWNI_SME_AUTO_SHUTDOWN_IND, +#endif +#ifdef QCA_HT_2040_COEX + eWNI_SME_SET_HT_2040_MODE, +#endif +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + eWNI_SME_HO_FAIL_IND, /* Hand Off Failure Ind from WMA to SME */ +#endif +#ifdef WLAN_FEATURE_NAN + eWNI_SME_NAN_EVENT, +#endif + eWNI_SME_LINK_STATUS_IND, +#ifdef WLAN_FEATURE_EXTWOW_SUPPORT + eWNI_SME_READY_TO_EXTWOW_IND, +#endif + eWNI_SME_MSG_GET_TEMPERATURE_IND, + eWNI_SME_SNR_IND, +#ifdef FEATURE_WLAN_EXTSCAN + eWNI_SME_EXTSCAN_FULL_SCAN_RESULT_IND, + eWNI_SME_EPNO_NETWORK_FOUND_IND, +#endif + eWNI_SME_FW_DUMP_IND, + eWNI_SME_SET_HW_MODE_REQ, + eWNI_SME_SET_HW_MODE_RESP, + eWNI_SME_HW_MODE_TRANS_IND, + eWNI_SME_NSS_UPDATE_REQ, + eWNI_SME_NSS_UPDATE_RSP, + eWNI_SME_SCAN_CMD, + eWNI_SME_OCB_SET_CONFIG_RSP, + eWNI_SME_OCB_GET_TSF_TIMER_RSP, + eWNI_SME_DCC_GET_STATS_RSP, + eWNI_SME_DCC_UPDATE_NDL_RSP, + eWNI_SME_DCC_STATS_EVENT, + eWNI_SME_SET_DUAL_MAC_CFG_REQ, + eWNI_SME_SET_DUAL_MAC_CFG_RESP, + eWNI_SME_ROC_CMD, + eWNI_SME_SET_THERMAL_LEVEL_IND, + eWNI_SME_SET_IE_REQ, + eWNI_SME_EXT_CHANGE_CHANNEL, + eWNI_SME_EXT_CHANGE_CHANNEL_IND, + eWNI_SME_REGISTER_MGMT_FRAME_CB, + eWNI_SME_HT40_OBSS_SCAN_IND, /* START and UPDATE OBSS SCAN Indication*/ + eWNI_SME_SET_ANTENNA_MODE_REQ, + eWNI_SME_SET_ANTENNA_MODE_RESP, + eWNI_SME_TSF_EVENT, + eWNI_SME_MON_INIT_SESSION, + eWNI_SME_PDEV_SET_HT_VHT_IE, + eWNI_SME_SET_VDEV_IES_PER_BAND, + eWNI_SME_NDP_INITIATOR_REQ, + eWNI_SME_NDP_INITIATOR_RSP, + eWNI_SME_NDP_NEW_PEER_IND, + eWNI_SME_NDP_CONFIRM_IND, + eWNI_SME_NDP_INDICATION, + eWNI_SME_NDP_RESPONDER_REQ, + eWNI_SME_NDP_RESPONDER_RSP, + eWNI_SME_NDP_END_REQ, + eWNI_SME_NDP_END_RSP, + eWNI_SME_NDP_PEER_DEPARTED_IND, + eWNI_SME_NDP_END_IND, + eWNI_SME_REGISTER_P2P_ACK_CB, + eWNI_SME_SEND_DISASSOC_FRAME, + eWNI_SME_UPDATE_ACCESS_POLICY_VENDOR_IE, + eWNI_SME_DEFAULT_SCAN_IE, + eWNI_SME_ROAM_SCAN_OFFLOAD_REQ, + eWNI_SME_LOST_LINK_INFO_IND, + eWNI_SME_RSO_CMD_STATUS_IND, + eWNI_SME_DEL_ALL_TDLS_PEERS, + eWNI_SME_UPDATE_CONFIG, + eWNI_SME_MSG_TYPES_END +}; + +typedef enum { + eWNI_TDLS_TEARDOWN_REASON_TX, + eWNI_TDLS_TEARDOWN_REASON_RSSI, + eWNI_TDLS_TEARDOWN_REASON_SCAN, + eWNI_TDLS_DISCONNECTED_REASON_PEER_DELETE, + eWNI_TDLS_TEARDOWN_REASON_PTR_TIMEOUT, + eWNI_TDLS_TEARDOWN_REASON_BAD_PTR, + eWNI_TDLS_TEARDOWN_REASON_NO_RESPONSE, +} eWniTdlsTeardownReason; + +/** + * enum ewni_tdls_connection_tracker_notification - connection tracker events + * @eWNI_TDLS_PEER_ENTER_BUF_STA: TDLS peer enters buff sta + * @eWNI_TDLS_PEER_EXIT_BUF_STA: TDLS peer exit buff sta + * @eWNI_TDLS_ENTER_BT_BUSY_MODE: Enter BT busy event + * @eWNI_TDLS_EXIT_BT_BUSY_MODE: Exit BT busy event + * @eWMI_TDLS_SCAN_STARTED_EVENT: offload scan start event + * @eWMI_TDLS_SCAN_COMPLETED_EVENT: offload scan end event + */ +enum ewni_tdls_connection_tracker_notification { + eWNI_TDLS_PEER_ENTER_BUF_STA, + eWNI_TDLS_PEER_EXIT_BUF_STA, + eWNI_TDLS_ENTER_BT_BUSY_MODE, + eWNI_TDLS_EXIT_BT_BUSY_MODE, + eWMI_TDLS_SCAN_STARTED_EVENT, + eWMI_TDLS_SCAN_COMPLETED_EVENT, +}; + +#define WNI_CFG_MSG_TYPES_BEGIN 0x1200 + +/*---------------------------------------------------------------------*/ +/* CFG Module Definitions */ +/*---------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------*/ +/* CFG message definitions */ +/*---------------------------------------------------------------------*/ +#define WNI_CFG_MSG_HDR_MASK 0xffff0000 +#define WNI_CFG_MSG_LEN_MASK 0x0000ffff +#define WNI_CFG_MB_HDR_LEN 4 +#define WNI_CFG_MAX_PARAM_NUM 32 + +/*---------------------------------------------------------------------*/ +/* CFG to HDD message types */ +/*---------------------------------------------------------------------*/ +#define WNI_CFG_PARAM_UPDATE_IND (WNI_CFG_MSG_TYPES_BEGIN | 0x00) +#define WNI_CFG_DNLD_REQ (WNI_CFG_MSG_TYPES_BEGIN | 0x01) +#define WNI_CFG_DNLD_CNF (WNI_CFG_MSG_TYPES_BEGIN | 0x02) +#define WNI_CFG_GET_RSP (WNI_CFG_MSG_TYPES_BEGIN | 0x03) +#define WNI_CFG_SET_CNF (WNI_CFG_MSG_TYPES_BEGIN | 0x04) +#define WNI_CFG_GET_ATTRIB_RSP (WNI_CFG_MSG_TYPES_BEGIN | 0x05) +#define WNI_CFG_ADD_GRP_ADDR_CNF (WNI_CFG_MSG_TYPES_BEGIN | 0x06) +#define WNI_CFG_DEL_GRP_ADDR_CNF (WNI_CFG_MSG_TYPES_BEGIN | 0x07) + +#define ANI_CFG_GET_RADIO_STAT_RSP (WNI_CFG_MSG_TYPES_BEGIN | 0x08) +#define ANI_CFG_GET_PER_STA_STAT_RSP (WNI_CFG_MSG_TYPES_BEGIN | 0x09) +#define ANI_CFG_GET_AGG_STA_STAT_RSP (WNI_CFG_MSG_TYPES_BEGIN | 0x0a) +#define ANI_CFG_CLEAR_STAT_RSP (WNI_CFG_MSG_TYPES_BEGIN | 0x0b) + +/*---------------------------------------------------------------------*/ +/* CFG to HDD message paramter indices */ + +/* The followings are word indices starting from the message body */ + +/* WNI_CFG_xxxx_xxxx_xxxx: index of parameter */ +/* WNI_CFG_xxxx_xxxx_NUM: number of parameters in message */ + +/* WNI_CFG_xxxx_xxxx_LEN: byte length of message including */ +/* MB header */ +/* */ +/* WNI_CFG_xxxx_xxxx_PARTIAL_LEN: byte length of message including */ +/* parameters and MB header but */ +/* excluding variable data length */ +/*---------------------------------------------------------------------*/ + +/* Parameter update indication */ +#define WNI_CFG_PARAM_UPDATE_IND_PID 0 + +#define WNI_CFG_PARAM_UPDATE_IND_NUM 1 +#define WNI_CFG_PARAM_UPDATE_IND_LEN (WNI_CFG_MB_HDR_LEN + \ + (WNI_CFG_PARAM_UPDATE_IND_NUM << 2)) + +/* Configuration download request */ +#define WNI_CFG_DNLD_REQ_NUM 0 +#define WNI_CFG_DNLD_REQ_LEN WNI_CFG_MB_HDR_LEN + +/* Configuration download confirm */ +#define WNI_CFG_DNLD_CNF_RES 0 + +#define WNI_CFG_DNLD_CNF_NUM 1 +#define WNI_CFG_DNLD_CNF_LEN (WNI_CFG_MB_HDR_LEN + \ + (WNI_CFG_DNLD_CNF_NUM << 2)) +/* Get response */ +#define WNI_CFG_GET_RSP_RES 0 +#define WNI_CFG_GET_RSP_PID 1 +#define WNI_CFG_GET_RSP_PLEN 2 + +#define WNI_CFG_GET_RSP_NUM 3 +#define WNI_CFG_GET_RSP_PARTIAL_LEN (WNI_CFG_MB_HDR_LEN + \ + (WNI_CFG_GET_RSP_NUM << 2)) +/* Set confirm */ +#define WNI_CFG_SET_CNF_RES 0 +#define WNI_CFG_SET_CNF_PID 1 + +#define WNI_CFG_SET_CNF_NUM 2 +#define WNI_CFG_SET_CNF_LEN (WNI_CFG_MB_HDR_LEN + \ + (WNI_CFG_SET_CNF_NUM << 2)) +/* Get attribute response */ +#define WNI_CFG_GET_ATTRIB_RSP_RES 0 +#define WNI_CFG_GET_ATTRIB_RSP_PID 1 +#define WNI_CFG_GET_ATTRIB_RSP_TYPE 2 +#define WNI_CFG_GET_ATTRIB_RSP_PLEN 3 +#define WNI_CFG_GET_ATTRIB_RSP_RW 4 + +#define WNI_CFG_GET_ATTRIB_RSP_NUM 5 +#define WNI_CFG_GET_ATTRIB_RSP_LEN (WNI_CFG_MB_HDR_LEN + \ + (WNI_CFG_GET_ATTRIB_RSP_NUM << 2)) + +/* Add group address confirm */ +#define WNI_CFG_ADD_GRP_ADDR_CNF_RES 0 + +#define WNI_CFG_ADD_GRP_ADDR_CNF_NUM 1 +#define WNI_CFG_ADD_GRP_ADDR_CNF_LEN (WNI_CFG_MB_HDR_LEN + \ + (WNI_CFG_ADD_GRP_ADDR_CNF_NUM << 2)) + +/* Delete group address confirm */ +#define WNI_CFG_DEL_GRP_ADDR_CNF_RES 0 + +#define WNI_CFG_DEL_GRP_ADDR_CNF_NUM 1 +#define WNI_CFG_DEL_GRP_ADDR_CNF_LEN (WNI_CFG_MB_HDR_LEN + \ + (WNI_CFG_DEL_GRP_ADDR_CNF_NUM << 2)) + +#define IS_CFG_MSG(msg) ((msg & 0xff00) == WNI_CFG_MSG_TYPES_BEGIN) + +/* Clear stats types. */ +#define ANI_CLEAR_ALL_STATS 0 +#define ANI_CLEAR_RX_STATS 1 +#define ANI_CLEAR_TX_STATS 2 +#define ANI_CLEAR_PER_STA_STATS 3 +#define ANI_CLEAR_AGGR_PER_STA_STATS 4 +#define ANI_CLEAR_STAT_TYPES_END 5 + +/*---------------------------------------------------------------------*/ +/* HDD to CFG message types */ +/*---------------------------------------------------------------------*/ +#define WNI_CFG_DNLD_RSP (WNI_CFG_MSG_TYPES_BEGIN | 0x80) +#define WNI_CFG_GET_REQ (WNI_CFG_MSG_TYPES_BEGIN | 0x81) +#define WNI_CFG_SET_REQ (WNI_CFG_MSG_TYPES_BEGIN | 0x82) +#define WNI_CFG_SET_REQ_NO_RSP (WNI_CFG_MSG_TYPES_BEGIN | 0x83) /* No RSP for this set */ + +/* Shall be removed after stats integration */ + +/*---------------------------------------------------------------------*/ +/* HDD to CFG message paramter indices */ +/* */ +/* The followings are word indices starting from the message body */ +/* */ +/* WNI_CFG_xxxx_xxxx_xxxx: index of parameter */ +/* */ +/* WNI_CFG_xxxx_xxxx_NUM: number of parameters in message */ +/* */ +/* WNI_CFG_xxxx_xxxx_LEN: byte length of message including */ +/* MB header */ +/* */ +/* WNI_CFG_xxxx_xxxx_PARTIAL_LEN: byte length of message including */ +/* parameters and MB header but */ +/* excluding variable data length */ +/*---------------------------------------------------------------------*/ + +/* Download response */ +#define WNI_CFG_DNLD_RSP_BIN_LEN 0 + +#define WNI_CFG_DNLD_RSP_NUM 1 +#define WNI_CFG_DNLD_RSP_PARTIAL_LEN (WNI_CFG_MB_HDR_LEN + \ + (WNI_CFG_DNLD_RSP_NUM << 2)) + +/* Set parameter request */ +#define WNI_CFG_SET_REQ_PID 0 +#define WNI_CFG_SET_REQ_PLEN 1 + +/*---------------------------------------------------------------------*/ +/* CFG return values */ +/*---------------------------------------------------------------------*/ +#define WNI_CFG_SUCCESS 1 +#define WNI_CFG_NOT_READY 2 +#define WNI_CFG_INVALID_PID 3 +#define WNI_CFG_INVALID_LEN 4 +#define WNI_CFG_RO_PARAM 5 +#define WNI_CFG_WO_PARAM 6 +#define WNI_CFG_INVALID_STAID 7 +#define WNI_CFG_OTHER_ERROR 8 +#define WNI_CFG_NEED_RESTART 9 +#define WNI_CFG_NEED_RELOAD 10 + +/*---------------------------------------------------------------------*/ +/* CFG definitions */ +/*---------------------------------------------------------------------*/ + +/* Shall be removed after integration of stats. */ +/* Get statistic response */ +#define WNI_CFG_GET_STAT_RSP_RES 0 +#define WNI_CFG_GET_STAT_RSP_PARAMID 1 +#define WNI_CFG_GET_STAT_RSP_VALUE 2 + +#define WNI_CFG_GET_STAT_RSP_NUM 3 +#define WNI_CFG_GET_STAT_RSP_LEN (WNI_CFG_MB_HDR_LEN + \ + (WNI_CFG_GET_STAT_RSP_NUM << 2)) +/* Get per station statistic response */ +#define WNI_CFG_GET_PER_STA_STAT_RSP_RES 0 +#define WNI_CFG_GET_PER_STA_STAT_RSP_STAID 1 +#define WNI_CFG_GET_PER_STA_STAT_RSP_FIRST_PARAM 2 + +/* Per STA statistic structure */ +typedef struct sAniCfgPerStaStatStruct { + unsigned long sentAesBlksUcastHi; + unsigned long sentAesBlksUcastLo; + + unsigned long recvAesBlksUcastHi; + unsigned long recvAesBlksUcastLo; + + unsigned long aesFormatErrorUcastCnts; + + unsigned long aesReplaysUcast; + + unsigned long aesDecryptErrUcast; + + unsigned long singleRetryPkts; + + unsigned long failedTxPkts; + + unsigned long ackTimeouts; + + unsigned long multiRetryPkts; + + unsigned long fragTxCntsHi; + unsigned long fragTxCntsLo; + + unsigned long transmittedPktsHi; + unsigned long transmittedPktsLo; + + unsigned long phyStatHi; + unsigned long phyStatLo; +} tCfgPerStaStatStruct, *tpAniCfgPerStaStatStruct; + +#define WNI_CFG_GET_PER_STA_STAT_RSP_NUM 23 +#define WNI_CFG_GET_PER_STA_STAT_RSP_LEN (WNI_CFG_MB_HDR_LEN + \ + (WNI_CFG_GET_PER_STA_STAT_RSP_NUM << 2)) + +/* Shall be removed after integrating stats. */ +#define WNI_CFG_GET_STAT_RSP (WNI_CFG_MSG_TYPES_BEGIN | 0x08) +#define WNI_CFG_GET_PER_STA_STAT_RSP (WNI_CFG_MSG_TYPES_BEGIN | 0x09) +#define WNI_CFG_GET_AGG_STA_STAT_RSP (WNI_CFG_MSG_TYPES_BEGIN | 0x0a) +#define WNI_CFG_GET_TX_RATE_CTR_RSP (WNI_CFG_MSG_TYPES_BEGIN | 0x0b) + +#define WNI_CFG_GET_AGG_STA_STAT_RSP_NUM 21 +#define WNI_CFG_GET_AGG_STA_STAT_RSP_LEN (WNI_CFG_MB_HDR_LEN + \ + (WNI_CFG_GET_AGG_STA_STAT_RSP_NUM << 2)) +#define WNI_CFG_GET_AGG_STA_STAT_RSP_RES 0 + +/* Get TX rate based stats */ +#define WNI_CFG_GET_TX_RATE_CTR_RSP_RES 0 + +typedef struct sAniCfgTxRateCtrs { +/* add the rate counters here */ + unsigned long TxFrames_1Mbps; + unsigned long TxFrames_2Mbps; + unsigned long TxFrames_5_5Mbps; + unsigned long TxFrames_6Mbps; + unsigned long TxFrames_9Mbps; + unsigned long TxFrames_11Mbps; + unsigned long TxFrames_12Mbps; + unsigned long TxFrames_18Mbps; + unsigned long TxFrames_24Mbps; + unsigned long TxFrames_36Mbps; + unsigned long TxFrames_48Mbps; + unsigned long TxFrames_54Mbps; + unsigned long TxFrames_72Mbps; + unsigned long TxFrames_96Mbps; + unsigned long TxFrames_108Mbps; + +} tAniCfgTxRateCtrs, *tpAniCfgTxRateCtrs; + +#define WNI_CFG_GET_STAT_REQ (WNI_CFG_MSG_TYPES_BEGIN | 0x86) +#define WNI_CFG_GET_PER_STA_STAT_REQ (WNI_CFG_MSG_TYPES_BEGIN | 0x87) +#define WNI_CFG_GET_AGG_STA_STAT_REQ (WNI_CFG_MSG_TYPES_BEGIN | 0x88) +#define WNI_CFG_GET_TX_RATE_CTR_REQ (WNI_CFG_MSG_TYPES_BEGIN | 0x89) + +/* Get statistic request */ +#define WNI_CFG_GET_STAT_REQ_PARAMID 0 + +#define WNI_CFG_GET_STAT_REQ_NUM 1 +#define WNI_CFG_GET_STAT_REQ_LEN (WNI_CFG_MB_HDR_LEN + \ + (WNI_CFG_GET_STAT_REQ_NUM << 2)) + +/* Get per station statistic request */ +#define WNI_CFG_GET_PER_STA_STAT_REQ_STAID 0 + +#define WNI_CFG_GET_PER_STA_STAT_REQ_NUM 1 +#define WNI_CFG_GET_PER_STA_STAT_REQ_LEN (WNI_CFG_MB_HDR_LEN + \ + (WNI_CFG_GET_PER_STA_STAT_REQ_NUM << 2)) + +#define DYNAMIC_CFG_TYPE_SELECTED_REGISTRAR (0) +#define DYNAMIC_CFG_TYPE_WPS_STATE (1) + +#endif /* __WNI_API_H */ diff --git a/drivers/staging/qcacld-3.0/core/mac/inc/wni_cfg.h b/drivers/staging/qcacld-3.0/core/mac/inc/wni_cfg.h new file mode 100644 index 0000000000000000000000000000000000000000..909fd0fa0371255363def7f25fd24c62888fc525 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/inc/wni_cfg.h @@ -0,0 +1,1294 @@ +/* + * Copyright (c) 2011-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef __WNICFG_H +#define __WNICFG_H + +/* + * Configuration Parameter ID for STA + */ + +enum { + WNI_CFG_STA_ID, + WNI_CFG_CFP_PERIOD, + WNI_CFG_CFP_MAX_DURATION, + WNI_CFG_SSID, + WNI_CFG_BEACON_INTERVAL, + WNI_CFG_DTIM_PERIOD, + WNI_CFG_WEP_KEY_LENGTH, + WNI_CFG_WEP_DEFAULT_KEY_1, + WNI_CFG_WEP_DEFAULT_KEY_2, + WNI_CFG_WEP_DEFAULT_KEY_3, + WNI_CFG_WEP_DEFAULT_KEY_4, + WNI_CFG_WEP_DEFAULT_KEYID, + WNI_CFG_EXCLUDE_UNENCRYPTED, + WNI_CFG_RTS_THRESHOLD, + WNI_CFG_SHORT_RETRY_LIMIT, + WNI_CFG_LONG_RETRY_LIMIT, + WNI_CFG_FRAGMENTATION_THRESHOLD, + WNI_CFG_ACTIVE_MINIMUM_CHANNEL_TIME, + WNI_CFG_ACTIVE_MAXIMUM_CHANNEL_TIME, + WNI_CFG_PASSIVE_MINIMUM_CHANNEL_TIME, + WNI_CFG_PASSIVE_MAXIMUM_CHANNEL_TIME, + WNI_CFG_JOIN_FAILURE_TIMEOUT, + WNI_CFG_AUTHENTICATE_FAILURE_TIMEOUT, + WNI_CFG_AUTHENTICATE_RSP_TIMEOUT, + WNI_CFG_ASSOCIATION_FAILURE_TIMEOUT, + WNI_CFG_REASSOCIATION_FAILURE_TIMEOUT, + WNI_CFG_PS_ENABLE_BCN_FILTER, + WNI_CFG_PS_ENABLE_HEART_BEAT, + WNI_CFG_PS_ENABLE_RSSI_MONITOR, + WNI_CFG_PS_DATA_INACTIVITY_TIMEOUT, + WNI_CFG_RF_SETTLING_TIME_CLK, + WNI_CFG_SUPPORTED_RATES_11B, + WNI_CFG_SUPPORTED_RATES_11A, + WNI_CFG_PHY_MODE, + WNI_CFG_DOT11_MODE, + WNI_CFG_OPERATIONAL_RATE_SET, + WNI_CFG_EXTENDED_OPERATIONAL_RATE_SET, + WNI_CFG_PROPRIETARY_OPERATIONAL_RATE_SET, + WNI_CFG_LISTEN_INTERVAL, + WNI_CFG_VALID_CHANNEL_LIST, + WNI_CFG_CURRENT_CHANNEL, + WNI_CFG_DEFAULT_RATE_INDEX_24GHZ, + WNI_CFG_FIXED_RATE, + WNI_CFG_APSD_ENABLED, + WNI_CFG_SHARED_KEY_AUTH_ENABLE, + WNI_CFG_OPEN_SYSTEM_AUTH_ENABLE, + WNI_CFG_AUTHENTICATION_TYPE, + WNI_CFG_PRIVACY_ENABLED, + WNI_CFG_SHORT_PREAMBLE, + WNI_CFG_ACCEPT_SHORT_SLOT_ASSOC_ONLY, + WNI_CFG_QOS_ENABLED, + WNI_CFG_HCF_ENABLED, + WNI_CFG_RSN_ENABLED, + WNI_CFG_MAX_NUM_PRE_AUTH, + WNI_CFG_HEART_BEAT_THRESHOLD, + WNI_CFG_PROBE_AFTER_HB_FAIL_TIMEOUT, + WNI_CFG_MANUFACTURER_NAME, + WNI_CFG_MODEL_NUMBER, + WNI_CFG_MODEL_NAME, + WNI_CFG_MANUFACTURER_PRODUCT_NAME, + WNI_CFG_MANUFACTURER_PRODUCT_VERSION, + WNI_CFG_11D_ENABLED, + WNI_CFG_MAX_TX_POWER_2_4, + WNI_CFG_MAX_TX_POWER_5, + WNI_CFG_CURRENT_TX_POWER_LEVEL, + WNI_CFG_NEW_BSS_FOUND_IND, + WNI_CFG_COUNTRY_CODE, + WNI_CFG_11H_ENABLED, + WNI_CFG_WT_CNF_TIMEOUT, + WNI_CFG_LOG_LEVEL, + WNI_CFG_OLBC_DETECT_TIMEOUT, + WNI_CFG_PROTECTION_ENABLED, + WNI_CFG_11G_PROTECTION_ALWAYS, + WNI_CFG_FORCE_POLICY_PROTECTION, + WNI_CFG_11G_SHORT_PREAMBLE_ENABLED, + WNI_CFG_11G_SHORT_SLOT_TIME_ENABLED, + WNI_CFG_11G_ONLY_POLICY, + WNI_CFG_WME_ENABLED, + WNI_CFG_ADDTS_RSP_TIMEOUT, + WNI_CFG_MAX_SP_LENGTH, + WNI_CFG_WSM_ENABLED, + WNI_CFG_EDCA_PROFILE, + WNI_CFG_EDCA_ANI_ACBK_LOCAL, + WNI_CFG_EDCA_ANI_ACBE_LOCAL, + WNI_CFG_EDCA_ANI_ACVI_LOCAL, + WNI_CFG_EDCA_ANI_ACVO_LOCAL, + WNI_CFG_EDCA_ANI_ACBK, + WNI_CFG_EDCA_ANI_ACBE, + WNI_CFG_EDCA_ANI_ACVI, + WNI_CFG_EDCA_ANI_ACVO, + WNI_CFG_EDCA_WME_ACBK_LOCAL, + WNI_CFG_EDCA_WME_ACBE_LOCAL, + WNI_CFG_EDCA_WME_ACVI_LOCAL, + WNI_CFG_EDCA_WME_ACVO_LOCAL, + WNI_CFG_EDCA_WME_ACBK, + WNI_CFG_EDCA_WME_ACBE, + WNI_CFG_EDCA_WME_ACVI, + WNI_CFG_EDCA_WME_ACVO, + WNI_CFG_LOCAL_POWER_CONSTRAINT, + WNI_CFG_ADMIT_POLICY, + WNI_CFG_ADMIT_BWFACTOR, + WNI_CFG_CHANNEL_BONDING_MODE, + WNI_CFG_DYNAMIC_THRESHOLD_ZERO, + WNI_CFG_DYNAMIC_THRESHOLD_ONE, + WNI_CFG_DYNAMIC_THRESHOLD_TWO, + WNI_CFG_SCAN_CONTROL_LIST, + WNI_CFG_BLOCK_ACK_ENABLED, + WNI_CFG_HT_CAP_INFO, + WNI_CFG_HT_AMPDU_PARAMS, + WNI_CFG_SUPPORTED_MCS_SET, + WNI_CFG_EXT_HT_CAP_INFO, + WNI_CFG_TX_BF_CAP, + WNI_CFG_AS_CAP, + WNI_CFG_HT_INFO_FIELD1, + WNI_CFG_HT_INFO_FIELD2, + WNI_CFG_HT_INFO_FIELD3, + WNI_CFG_BASIC_MCS_SET, + WNI_CFG_CURRENT_MCS_SET, + WNI_CFG_VHT_MAX_MPDU_LENGTH, + WNI_CFG_VHT_SUPPORTED_CHAN_WIDTH_SET, + WNI_CFG_VHT_LDPC_CODING_CAP, + WNI_CFG_VHT_SHORT_GI_80MHZ, + WNI_CFG_VHT_SHORT_GI_160_AND_80_PLUS_80MHZ, + WNI_CFG_VHT_TXSTBC, + WNI_CFG_VHT_RXSTBC, + WNI_CFG_VHT_SU_BEAMFORMER_CAP, + WNI_CFG_VHT_SU_BEAMFORMEE_CAP, + WNI_CFG_VHT_CSN_BEAMFORMEE_ANT_SUPPORTED, + WNI_CFG_VHT_NUM_SOUNDING_DIMENSIONS, + WNI_CFG_VHT_MU_BEAMFORMER_CAP, + WNI_CFG_VHT_MU_BEAMFORMEE_CAP, + WNI_CFG_VHT_TXOP_PS, + WNI_CFG_VHT_HTC_VHTC_CAP, + WNI_CFG_VHT_AMPDU_LEN_EXPONENT, + WNI_CFG_VHT_LINK_ADAPTATION_CAP, + WNI_CFG_VHT_RX_ANT_PATTERN, + WNI_CFG_VHT_TX_ANT_PATTERN, + WNI_CFG_VHT_RX_MCS_MAP, + WNI_CFG_VHT_TX_MCS_MAP, + WNI_CFG_VHT_RX_HIGHEST_SUPPORTED_DATA_RATE, + WNI_CFG_VHT_TX_HIGHEST_SUPPORTED_DATA_RATE, + WNI_CFG_VHT_BASIC_MCS_SET, + WNI_CFG_VHT_MU_MIMO_CAP_STA_COUNT, + WNI_CFG_VHT_SS_UNDER_UTIL, + WNI_CFG_VHT_40MHZ_UTILIZATION, + WNI_CFG_VHT_80MHZ_UTILIZATION, + WNI_CFG_VHT_160MHZ_UTILIZATION, + WNI_CFG_MPDU_DENSITY, + WNI_CFG_MAX_RX_AMPDU_FACTOR, + WNI_CFG_MAX_PS_POLL, + WNI_CFG_RSSI_FILTER_PERIOD, + WNI_CFG_SCAN_IN_POWERSAVE, + WNI_CFG_IGNORE_DTIM, + WNI_CFG_WOWLAN_UCAST_PATTERN_FILTER_ENABLE, + WNI_CFG_WOWLAN_CHANNEL_SWITCH_ENABLE, + WNI_CFG_WOWLAN_DEAUTH_ENABLE, + WNI_CFG_WOWLAN_DISASSOC_ENABLE, + WNI_CFG_WOWLAN_MAX_MISSED_BEACON, + WNI_CFG_WOWLAN_MAX_SLEEP_PERIOD, + WNI_CFG_MAX_MEDIUM_TIME, + WNI_CFG_IBSS_AUTO_BSSID, + WNI_CFG_PROBE_RSP_BCN_ADDNIE_FLAG, + WNI_CFG_WPS_ENABLE, + WNI_CFG_WPS_STATE, + WNI_CFG_WPS_VERSION, + WNI_CFG_WPS_CFG_METHOD, + WNI_CFG_WPS_UUID, + WNI_CFG_WPS_PRIMARY_DEVICE_CATEGORY, + WNI_CFG_WPS_PIMARY_DEVICE_OUI, + WNI_CFG_WPS_DEVICE_SUB_CATEGORY, + WNI_CFG_WPS_DEVICE_PASSWORD_ID, + WNI_CFG_LOW_GAIN_OVERRIDE, + WNI_CFG_SINGLE_TID_RC, + WNI_CFG_MCAST_BCAST_FILTER_SETTING, + WNI_CFG_DYNAMIC_PS_POLL_VALUE, + WNI_CFG_PS_NULLDATA_AP_RESP_TIMEOUT, + WNI_CFG_TELE_BCN_WAKEUP_EN, + WNI_CFG_TELE_BCN_TRANS_LI, + WNI_CFG_TELE_BCN_TRANS_LI_IDLE_BCNS, + WNI_CFG_TELE_BCN_MAX_LI, + WNI_CFG_TELE_BCN_MAX_LI_IDLE_BCNS, + WNI_CFG_INFRA_STA_KEEP_ALIVE_PERIOD, + WNI_CFG_ASSOC_STA_LIMIT, + WNI_CFG_AP_DATA_AVAIL_POLL_PERIOD, + WNI_CFG_ENABLE_LTE_COEX, + WNI_CFG_AP_KEEP_ALIVE_TIMEOUT, + WNI_CFG_GO_KEEP_ALIVE_TIMEOUT, + WNI_CFG_ENABLE_MC_ADDR_LIST, + WNI_CFG_ENABLE_LPWR_IMG_TRANSITION, + WNI_CFG_ENABLE_MCC_ADAPTIVE_SCHED, + WNI_CFG_DISABLE_LDPC_WITH_TXBF_AP, + WNI_CFG_AP_LINK_MONITOR_TIMEOUT, + WNI_CFG_TDLS_QOS_WMM_UAPSD_MASK, + WNI_CFG_TDLS_BUF_STA_ENABLED, + WNI_CFG_TDLS_PUAPSD_INACT_TIME, + WNI_CFG_TDLS_RX_FRAME_THRESHOLD, + WNI_CFG_PMF_SA_QUERY_MAX_RETRIES, + WNI_CFG_PMF_SA_QUERY_RETRY_INTERVAL, + WNI_CFG_ENABLE_ADAPT_RX_DRAIN, + WNI_CFG_ANTENNA_DIVESITY, + WNI_CFG_GO_LINK_MONITOR_TIMEOUT, + WNI_CFG_RMC_ACTION_PERIOD_FREQUENCY, + WNI_CFG_CURRENT_RSSI, + WNI_CFG_RTT3_ENABLE, + WNI_CFG_DEBUG_P2P_REMAIN_ON_CHANNEL, + WNI_CFG_TDLS_OFF_CHANNEL_ENABLED, + WNI_CFG_IBSS_ATIM_WIN_SIZE, + WNI_CFG_DFS_MASTER_ENABLED, + WNI_CFG_VHT_ENABLE_TXBF_20MHZ, + WNI_CFG_TDLS_WMM_MODE_ENABLED, + WNI_CFG_OBSS_HT40_SCAN_PASSIVE_DWELL_TIME, + WNI_CFG_OBSS_HT40_SCAN_ACTIVE_DWELL_TIME, + WNI_CFG_OBSS_HT40_SCAN_WIDTH_TRIGGER_INTERVAL, + WNI_CFG_OBSS_HT40_SCAN_PASSIVE_TOTAL_PER_CHANNEL, + WNI_CFG_OBSS_HT40_SCAN_ACTIVE_TOTAL_PER_CHANNEL, + WNI_CFG_OBSS_HT40_WIDTH_CH_TRANSITION_DELAY, + WNI_CFG_OBSS_HT40_SCAN_ACTIVITY_THRESHOLD, + WNI_CFG_TGT_GTX_USR_CFG, + WNI_CFG_MAX_HT_MCS_TX_DATA, + WNI_CFG_DISABLE_ABG_RATE_FOR_TX_DATA, + WNI_CFG_RATE_FOR_TX_MGMT, + WNI_CFG_PS_WOW_DATA_INACTIVITY_TIMEOUT, + /* Any new items to be added should be above this strictly */ + CFG_PARAM_MAX_NUM +}; +/* + * String parameter lengths + */ + +#define WNI_CFG_STA_ID_LEN 6 +#define WNI_CFG_SSID_LEN 32 +#define WNI_CFG_WEP_DEFAULT_KEY_1_LEN 13 +#define WNI_CFG_WEP_DEFAULT_KEY_2_LEN 13 +#define WNI_CFG_WEP_DEFAULT_KEY_3_LEN 13 +#define WNI_CFG_WEP_DEFAULT_KEY_4_LEN 13 +#define WNI_CFG_SUPPORTED_RATES_11B_LEN 4 +#define WNI_CFG_SUPPORTED_RATES_11A_LEN 8 +#define WNI_CFG_OPERATIONAL_RATE_SET_LEN 12 +#define WNI_CFG_EXTENDED_OPERATIONAL_RATE_SET_LEN 8 +#define WNI_CFG_PROPRIETARY_OPERATIONAL_RATE_SET_LEN 4 +#define WNI_CFG_VALID_CHANNEL_LIST_LEN 100 +#define WNI_CFG_MANUFACTURER_NAME_LEN 64 +#define WNI_CFG_MODEL_NUMBER_LEN 32 +#define WNI_CFG_MODEL_NAME_LEN 32 +#define WNI_CFG_MANUFACTURER_PRODUCT_NAME_LEN 32 +#define WNI_CFG_MANUFACTURER_PRODUCT_VERSION_LEN 32 +#define WNI_CFG_MAX_TX_POWER_2_4_LEN 128 +#define WNI_CFG_MAX_TX_POWER_5_LEN 128 +#define WNI_CFG_COUNTRY_CODE_LEN 3 +#define WNI_CFG_EDCA_ANI_ACBK_LOCAL_LEN 20 +#define WNI_CFG_EDCA_ANI_ACBE_LOCAL_LEN 20 +#define WNI_CFG_EDCA_ANI_ACVI_LOCAL_LEN 20 +#define WNI_CFG_EDCA_ANI_ACVO_LOCAL_LEN 20 +#define WNI_CFG_EDCA_ANI_ACBK_LEN 20 +#define WNI_CFG_EDCA_ANI_ACBE_LEN 20 +#define WNI_CFG_EDCA_ANI_ACVI_LEN 20 +#define WNI_CFG_EDCA_ANI_ACVO_LEN 20 +#define WNI_CFG_EDCA_WME_ACBK_LOCAL_LEN 20 +#define WNI_CFG_EDCA_WME_ACBE_LOCAL_LEN 20 +#define WNI_CFG_EDCA_WME_ACVI_LOCAL_LEN 20 +#define WNI_CFG_EDCA_WME_ACVO_LOCAL_LEN 20 +#define WNI_CFG_EDCA_WME_ACBK_LEN 20 +#define WNI_CFG_EDCA_WME_ACBE_LEN 20 +#define WNI_CFG_EDCA_WME_ACVI_LEN 20 +#define WNI_CFG_EDCA_WME_ACVO_LEN 20 +#define WNI_CFG_SCAN_CONTROL_LIST_LEN 128 +#define WNI_CFG_SUPPORTED_MCS_SET_LEN 16 +#define WNI_CFG_BASIC_MCS_SET_LEN 16 +#define WNI_CFG_CURRENT_MCS_SET_LEN 16 +#define WNI_CFG_PROBE_RSP_ADDNIE_DATA1_LEN 255 +#define WNI_CFG_ASSOC_RSP_ADDNIE_DATA_LEN 255 +#define WNI_CFG_PROBE_RSP_BCN_ADDNIE_DATA_LEN 255 +#define WNI_CFG_WPS_UUID_LEN 16 + +/* + * Integer parameter min/max/default values + */ + +#define WNI_CFG_CFP_PERIOD_STAMIN 0 +#define WNI_CFG_CFP_PERIOD_STAMAX 255 +#define WNI_CFG_CFP_PERIOD_STADEF 1 + +#define WNI_CFG_CFP_MAX_DURATION_STAMIN 0 +#define WNI_CFG_CFP_MAX_DURATION_STAMAX 65535 +#define WNI_CFG_CFP_MAX_DURATION_STADEF 30000 + +#define WNI_CFG_BEACON_INTERVAL_STAMIN 0 +#define WNI_CFG_BEACON_INTERVAL_STAMAX 65535 +#define WNI_CFG_BEACON_INTERVAL_STADEF 100 + +#define WNI_CFG_DTIM_PERIOD_STAMIN 0 +#define WNI_CFG_DTIM_PERIOD_STAMAX 65535 +#define WNI_CFG_DTIM_PERIOD_STADEF 1 + +#define WNI_CFG_WEP_KEY_LENGTH_STAMIN 5 +#define WNI_CFG_WEP_KEY_LENGTH_STAMAX 13 +#define WNI_CFG_WEP_KEY_LENGTH_STADEF 5 + +#define WNI_CFG_WEP_KEY_LENGTH_5 5 +#define WNI_CFG_WEP_KEY_LENGTH_13 13 + +#define WNI_CFG_WEP_DEFAULT_KEYID_STAMIN 0 +#define WNI_CFG_WEP_DEFAULT_KEYID_STAMAX 3 +#define WNI_CFG_WEP_DEFAULT_KEYID_STADEF 0 + +#define WNI_CFG_WEP_DEFAULT_KEYID_0 0 +#define WNI_CFG_WEP_DEFAULT_KEYID_1 1 +#define WNI_CFG_WEP_DEFAULT_KEYID_2 2 +#define WNI_CFG_WEP_DEFAULT_KEYID_3 3 + +#define WNI_CFG_EXCLUDE_UNENCRYPTED_STAMIN 0 +#define WNI_CFG_EXCLUDE_UNENCRYPTED_STAMAX 1 +#define WNI_CFG_EXCLUDE_UNENCRYPTED_STADEF 0 + +#define WNI_CFG_RTS_THRESHOLD_STAMIN 0 +#define WNI_CFG_RTS_THRESHOLD_STAMAX 1048576 +#define WNI_CFG_RTS_THRESHOLD_STADEF 2347 + +#define WNI_CFG_SHORT_RETRY_LIMIT_STAMIN 0 +#define WNI_CFG_SHORT_RETRY_LIMIT_STAMAX 255 +#define WNI_CFG_SHORT_RETRY_LIMIT_STADEF 6 + +#define WNI_CFG_LONG_RETRY_LIMIT_STAMIN 0 +#define WNI_CFG_LONG_RETRY_LIMIT_STAMAX 255 +#define WNI_CFG_LONG_RETRY_LIMIT_STADEF 6 + +#define WNI_CFG_FRAGMENTATION_THRESHOLD_STAMIN 256 +#define WNI_CFG_FRAGMENTATION_THRESHOLD_STAMAX 8000 +#define WNI_CFG_FRAGMENTATION_THRESHOLD_STADEF 8000 + +#define WNI_CFG_ACTIVE_MINIMUM_CHANNEL_TIME_STAMIN 0 +#define WNI_CFG_ACTIVE_MINIMUM_CHANNEL_TIME_STAMAX 65535 +#define WNI_CFG_ACTIVE_MINIMUM_CHANNEL_TIME_STADEF 20 + +#define WNI_CFG_ACTIVE_MAXIMUM_CHANNEL_TIME_STAMIN 0 +#define WNI_CFG_ACTIVE_MAXIMUM_CHANNEL_TIME_STAMAX 65535 +#define WNI_CFG_ACTIVE_MAXIMUM_CHANNEL_TIME_STADEF 40 + +#define WNI_CFG_PASSIVE_MINIMUM_CHANNEL_TIME_STAMIN 0 +#define WNI_CFG_PASSIVE_MINIMUM_CHANNEL_TIME_STAMAX 65535 +#define WNI_CFG_PASSIVE_MINIMUM_CHANNEL_TIME_STADEF 60 + +#define WNI_CFG_PASSIVE_MAXIMUM_CHANNEL_TIME_STAMIN 0 +#define WNI_CFG_PASSIVE_MAXIMUM_CHANNEL_TIME_STAMAX 65535 +#define WNI_CFG_PASSIVE_MAXIMUM_CHANNEL_TIME_STADEF 110 + +#define WNI_CFG_JOIN_FAILURE_TIMEOUT_STAMIN 0 +#define WNI_CFG_JOIN_FAILURE_TIMEOUT_STAMAX 65535 +#define WNI_CFG_JOIN_FAILURE_TIMEOUT_STADEF 3000 + +#define WNI_CFG_AUTHENTICATE_FAILURE_TIMEOUT_STAMIN 0 +#define WNI_CFG_AUTHENTICATE_FAILURE_TIMEOUT_STAMAX 65535 +#define WNI_CFG_AUTHENTICATE_FAILURE_TIMEOUT_STADEF 1000 + +#define WNI_CFG_AUTHENTICATE_RSP_TIMEOUT_STAMIN 0 +#define WNI_CFG_AUTHENTICATE_RSP_TIMEOUT_STAMAX 65535 +#define WNI_CFG_AUTHENTICATE_RSP_TIMEOUT_STADEF 1000 + +#define WNI_CFG_ASSOCIATION_FAILURE_TIMEOUT_STAMIN 0 +#define WNI_CFG_ASSOCIATION_FAILURE_TIMEOUT_STAMAX 65535 +#define WNI_CFG_ASSOCIATION_FAILURE_TIMEOUT_STADEF 2000 + +#define WNI_CFG_REASSOCIATION_FAILURE_TIMEOUT_STAMIN 0 +#define WNI_CFG_REASSOCIATION_FAILURE_TIMEOUT_STAMAX 65535 +#define WNI_CFG_REASSOCIATION_FAILURE_TIMEOUT_STADEF 1000 + +#define WNI_CFG_PS_ENABLE_BCN_FILTER_STAMIN 0 +#define WNI_CFG_PS_ENABLE_BCN_FILTER_STAMAX 1 +#define WNI_CFG_PS_ENABLE_BCN_FILTER_STADEF 1 + +#define WNI_CFG_PS_ENABLE_HEART_BEAT_STAMIN 0 +#define WNI_CFG_PS_ENABLE_HEART_BEAT_STAMAX 1 +#define WNI_CFG_PS_ENABLE_HEART_BEAT_STADEF 1 + +#define WNI_CFG_PS_ENABLE_RSSI_MONITOR_STAMIN 0 +#define WNI_CFG_PS_ENABLE_RSSI_MONITOR_STAMAX 1 +#define WNI_CFG_PS_ENABLE_RSSI_MONITOR_STADEF 0 + +#define WNI_CFG_PS_DATA_INACTIVITY_TIMEOUT_STAMIN 1 +#define WNI_CFG_PS_DATA_INACTIVITY_TIMEOUT_STAMAX 255 +#define WNI_CFG_PS_DATA_INACTIVITY_TIMEOUT_STADEF 200 + +#define WNI_CFG_RF_SETTLING_TIME_CLK_STAMIN 0 +#define WNI_CFG_RF_SETTLING_TIME_CLK_STAMAX 60000 +#define WNI_CFG_RF_SETTLING_TIME_CLK_STADEF 1500 + +#define WNI_CFG_PHY_MODE_STAMIN 0 +#define WNI_CFG_PHY_MODE_STAMAX 3 +#define WNI_CFG_PHY_MODE_STADEF 0 + +#define WNI_CFG_PHY_MODE_11A 0 +#define WNI_CFG_PHY_MODE_11B 1 +#define WNI_CFG_PHY_MODE_11G 2 +#define WNI_CFG_PHY_MODE_NONE 3 + +#define WNI_CFG_DOT11_MODE_STAMIN 0 +#define WNI_CFG_DOT11_MODE_STAMAX 11 +#define WNI_CFG_DOT11_MODE_STADEF 0 + +#define WNI_CFG_DOT11_MODE_ALL 0 +#define WNI_CFG_DOT11_MODE_11A 1 +#define WNI_CFG_DOT11_MODE_11B 2 +#define WNI_CFG_DOT11_MODE_11G 3 +#define WNI_CFG_DOT11_MODE_11N 4 +#define WNI_CFG_DOT11_MODE_11G_ONLY 5 +#define WNI_CFG_DOT11_MODE_11N_ONLY 6 +#define WNI_CFG_DOT11_MODE_11AC 7 +#define WNI_CFG_DOT11_MODE_11AC_ONLY 8 + +#define WNI_CFG_LISTEN_INTERVAL_STAMIN 0 +#define WNI_CFG_LISTEN_INTERVAL_STAMAX 65535 +#define WNI_CFG_LISTEN_INTERVAL_STADEF 1 + +#define WNI_CFG_CURRENT_CHANNEL_STAMIN 0 +#define WNI_CFG_CURRENT_CHANNEL_STAMAX 165 +#define WNI_CFG_CURRENT_CHANNEL_STADEF 1 + +#define WNI_CFG_DEFAULT_RATE_INDEX_24GHZ_STAMIN 0 +#define WNI_CFG_DEFAULT_RATE_INDEX_24GHZ_STAMAX 31 +#define WNI_CFG_DEFAULT_RATE_INDEX_24GHZ_STADEF 1 + +#define WNI_CFG_RATE_ADAPTATION_TYPE_FIXED 0 +#define WNI_CFG_RATE_ADAPTATION_TYPE_AUTO 1 +#define WNI_CFG_RATE_ADAPTATION_TYPE_SNR_BASED 2 + +#define WNI_CFG_FIXED_RATE_STAMIN 0 +#define WNI_CFG_FIXED_RATE_STAMAX 44 +#define WNI_CFG_FIXED_RATE_STADEF 0 + +#define WNI_CFG_FIXED_RATE_AUTO 0 +#define WNI_CFG_FIXED_RATE_1MBPS 1 +#define WNI_CFG_FIXED_RATE_2MBPS 2 +#define WNI_CFG_FIXED_RATE_5_5MBPS 3 +#define WNI_CFG_FIXED_RATE_11MBPS 4 +#define WNI_CFG_FIXED_RATE_6MBPS 5 +#define WNI_CFG_FIXED_RATE_9MBPS 6 +#define WNI_CFG_FIXED_RATE_12MBPS 7 +#define WNI_CFG_FIXED_RATE_18MBPS 8 +#define WNI_CFG_FIXED_RATE_24MBPS 9 +#define WNI_CFG_FIXED_RATE_36MBPS 10 +#define WNI_CFG_FIXED_RATE_48MBPS 11 +#define WNI_CFG_FIXED_RATE_54MBPS 12 +#define WNI_CFG_FIXED_RATE_6_5MBPS_MCS0_20MHZ_SIMO 13 +#define WNI_CFG_FIXED_RATE_13MBPS_MCS1_20MHZ_SIMO 14 +#define WNI_CFG_FIXED_RATE_19_5MBPS_MCS2_20MHZ_SIMO 15 +#define WNI_CFG_FIXED_RATE_26MBPS_MCS3_20MHZ_SIMO 16 +#define WNI_CFG_FIXED_RATE_39MBPS_MCS4_20MHZ_SIMO 17 +#define WNI_CFG_FIXED_RATE_52MBPS_MCS5_20MHZ_SIMO 18 +#define WNI_CFG_FIXED_RATE_58_5MBPS_MCS6_20MHZ_SIMO 19 +#define WNI_CFG_FIXED_RATE_65MBPS_MCS7_20MHZ_SIMO 20 +#define WNI_CFG_FIXED_RATE_7_2MBPS_MCS0_20MHZ_SIMO_SGI 21 +#define WNI_CFG_FIXED_RATE_14_4MBPS_MCS1_20MHZ_SIMO_SGI 22 +#define WNI_CFG_FIXED_RATE_21_7MBPS_MCS2_20MHZ_SIMO_SGI 23 +#define WNI_CFG_FIXED_RATE_28_9MBPS_MCS3_20MHZ_SIMO_SGI 24 +#define WNI_CFG_FIXED_RATE_43_3MBPS_MCS4_20MHZ_SIMO_SGI 25 +#define WNI_CFG_FIXED_RATE_57_8MBPS_MCS5_20MHZ_SIMO_SGI 26 +#define WNI_CFG_FIXED_RATE_65MBPS_MCS6_20MHZ_SIMO_SGI 27 +#define WNI_CFG_FIXED_RATE_72_2MBPS_MCS7_20MHZ_SIMO_SGI 28 +#define WNI_CFG_FIXED_RATE_0_25MBPS_SLR_20MHZ_SIMO 29 +#define WNI_CFG_FIXED_RATE_0_5MBPS_SLR_20MHZ_SIMO 30 +#define WNI_CFG_FIXED_RATE_68_25MBPS_QC_PROP_20MHZ_SIMO 31 +#define WNI_CFG_FIXED_RATE_54MBPS_MCS3_40MHZ_SIMO 32 +#define WNI_CFG_FIXED_RATE_81MBPS_MCS4_40MHZ_SIMO 33 +#define WNI_CFG_FIXED_RATE_108MBPS_MCS5_40MHZ_SIMO 34 +#define WNI_CFG_FIXED_RATE_121_5MBPS_MCS6_40MHZ_SIMO 35 +#define WNI_CFG_FIXED_RATE_135MBPS_MCS7_40MHZ_SIMO 36 +#define WNI_CFG_FIXED_RATE_15MBPS_MCS0_40MHZ_SIMO_SGI 37 +#define WNI_CFG_FIXED_RATE_30MBPS_MCS1_40MHZ_SIMO_SGI 38 +#define WNI_CFG_FIXED_RATE_45MBPS_MCS2_40MHZ_SIMO_SGI 39 +#define WNI_CFG_FIXED_RATE_60MBPS_MCS3_40MHZ_SIMO_SGI 40 +#define WNI_CFG_FIXED_RATE_90MBPS_MCS4_40MHZ_SIMO_SGI 41 +#define WNI_CFG_FIXED_RATE_120MBPS_MCS5_40MHZ_SIMO_SGI 42 +#define WNI_CFG_FIXED_RATE_135MBPS_MCS6_40MHZ_SIMO_SGI 43 +#define WNI_CFG_FIXED_RATE_150MBPS_MCS7_40MHZ_SIMO_SGI 44 + +#define WNI_CFG_RETRYRATE_POLICY_MIN_SUPPORTED 0 +#define WNI_CFG_RETRYRATE_POLICY_PRIMARY 1 +#define WNI_CFG_RETRYRATE_POLICY_RESERVED 2 +#define WNI_CFG_RETRYRATE_POLICY_CLOSEST 3 +#define WNI_CFG_RETRYRATE_POLICY_AUTOSELECT 4 +#define WNI_CFG_RETRYRATE_POLICY_MAX 5 + +#define WNI_CFG_APSD_ENABLED_STAMIN 0 +#define WNI_CFG_APSD_ENABLED_STAMAX 1 +#define WNI_CFG_APSD_ENABLED_STADEF 0 + +#define WNI_CFG_SHARED_KEY_AUTH_ENABLE_STAMIN 0 +#define WNI_CFG_SHARED_KEY_AUTH_ENABLE_STAMAX 1 +#define WNI_CFG_SHARED_KEY_AUTH_ENABLE_STADEF 1 + +#define WNI_CFG_OPEN_SYSTEM_AUTH_ENABLE_STAMIN 0 +#define WNI_CFG_OPEN_SYSTEM_AUTH_ENABLE_STAMAX 1 +#define WNI_CFG_OPEN_SYSTEM_AUTH_ENABLE_STADEF 1 + +#define WNI_CFG_AUTHENTICATION_TYPE_STAMIN 0 +#define WNI_CFG_AUTHENTICATION_TYPE_STAMAX 65535 +#define WNI_CFG_AUTHENTICATION_TYPE_STADEF 0 + +#define WNI_CFG_PRIVACY_ENABLED_STAMIN 0 +#define WNI_CFG_PRIVACY_ENABLED_STAMAX 1 +#define WNI_CFG_PRIVACY_ENABLED_STADEF 0 + +#define WNI_CFG_SHORT_PREAMBLE_STAMIN 0 +#define WNI_CFG_SHORT_PREAMBLE_STAMAX 1 +#define WNI_CFG_SHORT_PREAMBLE_STADEF 1 + +#define WNI_CFG_SHORT_SLOT_TIME_STAMIN 0 +#define WNI_CFG_SHORT_SLOT_TIME_STAMAX 1 +#define WNI_CFG_SHORT_SLOT_TIME_STADEF 1 + +#define WNI_CFG_ACCEPT_SHORT_SLOT_ASSOC_ONLY_STAMIN 0 +#define WNI_CFG_ACCEPT_SHORT_SLOT_ASSOC_ONLY_STAMAX 1 +#define WNI_CFG_ACCEPT_SHORT_SLOT_ASSOC_ONLY_STADEF 0 + +#define WNI_CFG_QOS_ENABLED_STAMIN 0 +#define WNI_CFG_QOS_ENABLED_STAMAX 1 +#define WNI_CFG_QOS_ENABLED_STADEF 0 + +#define WNI_CFG_HCF_ENABLED_STAMIN 0 +#define WNI_CFG_HCF_ENABLED_STAMAX 1 +#define WNI_CFG_HCF_ENABLED_STADEF 0 + +#define WNI_CFG_RSN_ENABLED_STAMIN 0 +#define WNI_CFG_RSN_ENABLED_STAMAX 1 +#define WNI_CFG_RSN_ENABLED_STADEF 0 + +#define WNI_CFG_BACKGROUND_SCAN_PERIOD_STAMIN 0 +#define WNI_CFG_BACKGROUND_SCAN_PERIOD_STAMAX 180000 +#define WNI_CFG_BACKGROUND_SCAN_PERIOD_STADEF 5000 + +#define WNI_CFG_MAX_NUM_PRE_AUTH_STAMIN 0 +#define WNI_CFG_MAX_NUM_PRE_AUTH_STAMAX 256 +#define WNI_CFG_MAX_NUM_PRE_AUTH_STADEF 64 + +#define WNI_CFG_HEART_BEAT_THRESHOLD_STAMIN 0 +#define WNI_CFG_HEART_BEAT_THRESHOLD_STAMAX 65535 +#define WNI_CFG_HEART_BEAT_THRESHOLD_STADEF 40 + +#define WNI_CFG_PROBE_AFTER_HB_FAIL_TIMEOUT_STAMIN 10 +#define WNI_CFG_PROBE_AFTER_HB_FAIL_TIMEOUT_STAMAX 10000 +#define WNI_CFG_PROBE_AFTER_HB_FAIL_TIMEOUT_STADEF 40 + +#define WNI_CFG_11D_ENABLED_STAMIN 0 +#define WNI_CFG_11D_ENABLED_STAMAX 1 +#define WNI_CFG_11D_ENABLED_STADEF 1 + +#define WNI_CFG_NETWORK_DENSITY_LOW 0 +#define WNI_CFG_NETWORK_DENSITY_MEDIUM 1 +#define WNI_CFG_NETWORK_DENSITY_HIGH 2 +#define WNI_CFG_NETWORK_DENSITY_ADAPTIVE 3 + +#define WNI_CFG_ADAPTIVE_THRESHOLD_ALGORITHM_CARRIER 1 +#define WNI_CFG_ADAPTIVE_THRESHOLD_ALGORITHM_CORRELATION 2 + +#define WNI_CFG_CURRENT_TX_POWER_LEVEL_STAMIN 0 +#define WNI_CFG_CURRENT_TX_POWER_LEVEL_STAMAX 128 +#define WNI_CFG_CURRENT_TX_POWER_LEVEL_STADEF 27 + + + +#define WNI_CFG_NEW_BSS_FOUND_IND_STAMIN 0 +#define WNI_CFG_NEW_BSS_FOUND_IND_STAMAX 1 +#define WNI_CFG_NEW_BSS_FOUND_IND_STADEF 0 + + +#define WNI_CFG_11H_ENABLED_STAMIN 0 +#define WNI_CFG_11H_ENABLED_STAMAX 1 +#define WNI_CFG_11H_ENABLED_STADEF 1 + +#define WNI_CFG_WT_CNF_TIMEOUT_STAMIN 10 +#define WNI_CFG_WT_CNF_TIMEOUT_STAMAX 3000 +#define WNI_CFG_WT_CNF_TIMEOUT_STADEF 1000 + +#define WNI_CFG_LOG_LEVEL_STAMIN 0 +#define WNI_CFG_LOG_LEVEL_STAMAX 7 +#define WNI_CFG_LOG_LEVEL_STADEF 4 + +#define WNI_CFG_OLBC_DETECT_TIMEOUT_STAMIN 1000 +#define WNI_CFG_OLBC_DETECT_TIMEOUT_STAMAX 30000 +#define WNI_CFG_OLBC_DETECT_TIMEOUT_STADEF 10000 + +#define WNI_CFG_PROTECTION_ENABLED_STAMIN 0 +#define WNI_CFG_PROTECTION_ENABLED_STAMAX 65535 +#define WNI_CFG_PROTECTION_ENABLED_STADEF 65535 + +#define WNI_CFG_PROTECTION_ENABLED_FROM_llA 0 +#define WNI_CFG_PROTECTION_ENABLED_FROM_llB 1 +#define WNI_CFG_PROTECTION_ENABLED_FROM_llG 2 +#define WNI_CFG_PROTECTION_ENABLED_HT_20 3 +#define WNI_CFG_PROTECTION_ENABLED_NON_GF 4 +#define WNI_CFG_PROTECTION_ENABLED_LSIG_TXOP 5 +#define WNI_CFG_PROTECTION_ENABLED_RIFS 6 +#define WNI_CFG_PROTECTION_ENABLED_OBSS 7 +#define WNI_CFG_PROTECTION_ENABLED_OLBC_FROM_llA 8 +#define WNI_CFG_PROTECTION_ENABLED_OLBC_FROM_llB 9 +#define WNI_CFG_PROTECTION_ENABLED_OLBC_FROM_llG 10 +#define WNI_CFG_PROTECTION_ENABLED_OLBC_HT20 11 +#define WNI_CFG_PROTECTION_ENABLED_OLBC_NON_GF 12 +#define WNI_CFG_PROTECTION_ENABLED_OLBC_LSIG_TXOP 13 +#define WNI_CFG_PROTECTION_ENABLED_OLBC_RIFS 14 +#define WNI_CFG_PROTECTION_ENABLED_OLBC_OBSS 15 + +#define WNI_CFG_11G_PROTECTION_ALWAYS_STAMIN 0 +#define WNI_CFG_11G_PROTECTION_ALWAYS_STAMAX 1 +#define WNI_CFG_11G_PROTECTION_ALWAYS_STADEF 0 + +#define WNI_CFG_FORCE_POLICY_PROTECTION_STAMIN 0 +#define WNI_CFG_FORCE_POLICY_PROTECTION_STAMAX 5 +#define WNI_CFG_FORCE_POLICY_PROTECTION_STADEF 5 + +#define WNI_CFG_FORCE_POLICY_PROTECTION_DISABLE 0 +#define WNI_CFG_FORCE_POLICY_PROTECTION_CTS 1 +#define WNI_CFG_FORCE_POLICY_PROTECTION_RTS 2 +#define WNI_CFG_FORCE_POLICY_PROTECTION_DUAL_CTS 3 +#define WNI_CFG_FORCE_POLICY_PROTECTION_RTS_ALWAYS 4 +#define WNI_CFG_FORCE_POLICY_PROTECTION_AUTO 5 + +#define WNI_CFG_11G_SHORT_PREAMBLE_ENABLED_STAMIN 0 +#define WNI_CFG_11G_SHORT_PREAMBLE_ENABLED_STAMAX 1 +#define WNI_CFG_11G_SHORT_PREAMBLE_ENABLED_STADEF 0 + +#define WNI_CFG_11G_SHORT_SLOT_TIME_ENABLED_STAMIN 0 +#define WNI_CFG_11G_SHORT_SLOT_TIME_ENABLED_STAMAX 1 +#define WNI_CFG_11G_SHORT_SLOT_TIME_ENABLED_STADEF 1 + +#define WNI_CFG_11G_ONLY_POLICY_STAMIN 0 +#define WNI_CFG_11G_ONLY_POLICY_STAMAX 1 +#define WNI_CFG_11G_ONLY_POLICY_STADEF 0 + +#define WNI_CFG_WME_ENABLED_STAMIN 0 +#define WNI_CFG_WME_ENABLED_STAMAX 1 +#define WNI_CFG_WME_ENABLED_STADEF 1 + +#define WNI_CFG_ADDTS_RSP_TIMEOUT_STAMIN 0 +#define WNI_CFG_ADDTS_RSP_TIMEOUT_STAMAX 65535 +#define WNI_CFG_ADDTS_RSP_TIMEOUT_STADEF 1000 + +#define WNI_CFG_MAX_SP_LENGTH_STAMIN 0 +#define WNI_CFG_MAX_SP_LENGTH_STAMAX 3 +#define WNI_CFG_MAX_SP_LENGTH_STADEF 0 + +#define WNI_CFG_WSM_ENABLED_STAMIN 0 +#define WNI_CFG_WSM_ENABLED_STAMAX 1 +#define WNI_CFG_WSM_ENABLED_STADEF 0 + +#define WNI_CFG_EDCA_PROFILE_STAMIN 0 +#define WNI_CFG_EDCA_PROFILE_STAMAX 255 +#define WNI_CFG_EDCA_PROFILE_STADEF 1 + +#define WNI_CFG_EDCA_PROFILE_ANI 0 +#define WNI_CFG_EDCA_PROFILE_WMM 1 +#define WNI_CFG_EDCA_PROFILE_TIT_DEMO 2 +#define WNI_CFG_EDCA_PROFILE_MAX 3 +#define WNI_CFG_EDCA_PROFILE_ACM_IDX 0 +#define WNI_CFG_EDCA_PROFILE_AIFSN_IDX 1 +#define WNI_CFG_EDCA_PROFILE_CWMINA_IDX 2 +#define WNI_CFG_EDCA_PROFILE_CWMAXA_IDX 4 +#define WNI_CFG_EDCA_PROFILE_TXOPA_IDX 6 +#define WNI_CFG_EDCA_PROFILE_CWMINB_IDX 7 +#define WNI_CFG_EDCA_PROFILE_CWMAXB_IDX 9 +#define WNI_CFG_EDCA_PROFILE_TXOPB_IDX 11 +#define WNI_CFG_EDCA_PROFILE_CWMING_IDX 12 +#define WNI_CFG_EDCA_PROFILE_CWMAXG_IDX 14 +#define WNI_CFG_EDCA_PROFILE_TXOPG_IDX 16 + +#define WNI_CFG_LOCAL_POWER_CONSTRAINT_STAMIN 0 +#define WNI_CFG_LOCAL_POWER_CONSTRAINT_STAMAX 255 +#define WNI_CFG_LOCAL_POWER_CONSTRAINT_STADEF 0 + +#define WNI_CFG_ADMIT_POLICY_STAMIN 0 +#define WNI_CFG_ADMIT_POLICY_STAMAX 2 +#define WNI_CFG_ADMIT_POLICY_STADEF 0 + +#define WNI_CFG_ADMIT_POLICY_ADMIT_ALL 0 +#define WNI_CFG_ADMIT_POLICY_REJECT_ALL 1 +#define WNI_CFG_ADMIT_POLICY_BW_FACTOR 2 + +#define WNI_CFG_ADMIT_BWFACTOR_STAMIN 0 +#define WNI_CFG_ADMIT_BWFACTOR_STAMAX 100 +#define WNI_CFG_ADMIT_BWFACTOR_STADEF 20 + +#define WNI_CFG_CHANNEL_BONDING_MODE_STAMIN 0 +#define WNI_CFG_CHANNEL_BONDING_MODE_STAMAX 10 +#define WNI_CFG_CHANNEL_BONDING_MODE_STADEF 0 + +#define WNI_CFG_CHANNEL_BONDING_MODE_DISABLE 0 +#define WNI_CFG_CHANNEL_BONDING_MODE_ENABLE 1 +#define WNI_CFG_CHANNEL_BONDING_MODE_IF_NO_LEGACY_BSS 2 +#define WNI_CFG_CHANNEL_BONDING_MODE_IF_NO_LEGACY_ALL 3 +#define WNI_CFG_CHANNEL_BONDING_MODE_INTELLIGENT 4 + +#define WNI_CFG_DYNAMIC_THRESHOLD_ZERO_STAMIN 0 +#define WNI_CFG_DYNAMIC_THRESHOLD_ZERO_STAMAX 255 +#define WNI_CFG_DYNAMIC_THRESHOLD_ZERO_STADEF 2 + +#define WNI_CFG_DYNAMIC_THRESHOLD_ONE_STAMIN 0 +#define WNI_CFG_DYNAMIC_THRESHOLD_ONE_STAMAX 255 +#define WNI_CFG_DYNAMIC_THRESHOLD_ONE_STADEF 4 + +#define WNI_CFG_DYNAMIC_THRESHOLD_TWO_STAMIN 0 +#define WNI_CFG_DYNAMIC_THRESHOLD_TWO_STAMAX 255 +#define WNI_CFG_DYNAMIC_THRESHOLD_TWO_STADEF 6 + +#define WNI_CFG_BLOCK_ACK_ENABLED_STAMIN 0 +#define WNI_CFG_BLOCK_ACK_ENABLED_STAMAX 3 +#define WNI_CFG_BLOCK_ACK_ENABLED_STADEF 0 + +#define WNI_CFG_BLOCK_ACK_ENABLED_DELAYED 0 +#define WNI_CFG_BLOCK_ACK_ENABLED_IMMEDIATE 1 + +#define WNI_CFG_HT_RX_STBC_STAMIN 0 +#define WNI_CFG_HT_RX_STBC_STAMAX 3 +#define WNI_CFG_HT_RX_STBC_STADEF 1 + +#define WNI_CFG_HT_CAP_INFO_STAMIN 0 +#define WNI_CFG_HT_CAP_INFO_STAMAX 65535 +#define WNI_CFG_HT_CAP_INFO_STADEF 364 + +#define WNI_CFG_HT_CAP_INFO_ADVANCE_CODING 0 +#define WNI_CFG_HT_CAP_INFO_SUPPORTED_CHAN_WIDTH_SET 1 +#define WNI_CFG_HT_CAP_INFO_SM_POWER_SAVE 2 +#define WNI_CFG_HT_CAP_INFO_GREEN_FIELD 4 +#define WNI_CFG_HT_CAP_INFO_SHORT_GI_20MHZ 5 +#define WNI_CFG_HT_CAP_INFO_SHORT_GI_40MHZ 6 +#define WNI_CFG_HT_CAP_INFO_TX_STBC 7 +#define WNI_CFG_HT_CAP_INFO_RX_STBC 8 +#define WNI_CFG_HT_CAP_INFO_DELAYED_BA 10 +#define WNI_CFG_HT_CAP_INFO_MAX_AMSDU_SIZE 11 +#define WNI_CFG_HT_CAP_INFO_DSSS_CCK_MODE_40MHZ 12 +#define WNI_CFG_HT_CAP_INFO_PSMP 13 +#define WNI_CFG_HT_CAP_INFO_STBC_CONTROL_FRAME 14 +#define WNI_CFG_HT_CAP_INFO_LSIG_TXOP_PROTECTION 15 + +#define WNI_CFG_HT_AMPDU_PARAMS_STAMIN 0 +#define WNI_CFG_HT_AMPDU_PARAMS_STAMAX 255 +#define WNI_CFG_HT_AMPDU_PARAMS_STADEF 0 + +#define WNI_CFG_HT_AMPDU_PARAMS_MAX_RX_AMPDU_FACTOR 0 +#define WNI_CFG_HT_AMPDU_PARAMS_MPDU_DENSITY 2 +#define WNI_CFG_HT_AMPDU_PARAMS_RESERVED 5 + +#define WNI_CFG_EXT_HT_CAP_INFO_STAMIN 0 +#define WNI_CFG_EXT_HT_CAP_INFO_STAMAX 65535 +#define WNI_CFG_EXT_HT_CAP_INFO_STADEF 1024 + +#define WNI_CFG_EXT_HT_CAP_INFO_PCO 0 +#define WNI_CFG_EXT_HT_CAP_INFO_TRANSITION_TIME 1 +#define WNI_CFG_EXT_HT_CAP_INFO_RESERVED1 3 +#define WNI_CFG_EXT_HT_CAP_INFO_MCS_FEEDBACK 8 +#define WNI_CFG_EXT_HT_CAP_INFO_HTC_SUPPORT 10 +#define WNI_CFG_EXT_HT_CAP_INFO_RD_RESPONDER 11 +#define WNI_CFG_EXT_HT_CAP_INFO_RESERVED2 12 + +#define WNI_CFG_TX_BF_CAP_STAMIN 0 +#define WNI_CFG_TX_BF_CAP_STAMAX 4294967295 +#define WNI_CFG_TX_BF_CAP_STADEF 0 + +#define WNI_CFG_AS_CAP_STAMIN 0 +#define WNI_CFG_AS_CAP_STAMAX 255 +#define WNI_CFG_AS_CAP_STADEF 0 + +#define WNI_CFG_AS_CAP_ANTENNA_SELECTION 0 +#define WNI_CFG_AS_CAP_EXPLICIT_CSI_FEEDBACK_TX 1 +#define WNI_CFG_AS_CAP_ANTENNA_INDICES_FEEDBACK_TX 2 +#define WNI_CFG_AS_CAP_EXPLICIT_CSI_FEEDBACK 3 +#define WNI_CFG_AS_CAP_ANTENNA_INDICES_FEEDBACK 4 +#define WNI_CFG_AS_CAP_RX_AS 5 +#define WNI_CFG_AS_CAP_TX_SOUNDING_PPDUS 6 +#define WNI_CFG_AS_CAP_RESERVED 7 + +#define WNI_CFG_HT_INFO_FIELD1_STAMIN 0 +#define WNI_CFG_HT_INFO_FIELD1_STAMAX 255 +#define WNI_CFG_HT_INFO_FIELD1_STADEF 15 + +#define WNI_CFG_HT_INFO_FIELD1_SECONDARY_CHANNEL_OFFSET 0 +#define WNI_CFG_HT_INFO_FIELD1_RECOMMENDED_CHANNEL_WIDTH 2 +#define WNI_CFG_HT_INFO_FIELD1_RIFS_MODE 3 +#define WNI_CFG_HT_INFO_FIELD1_PSMP_ACCESS_ONLY 4 +#define WNI_CFG_HT_INFO_FIELD1_SERVICE_INTERVAL_GRANULARITY 5 + +#define WNI_CFG_HT_INFO_FIELD2_STAMIN 0 +#define WNI_CFG_HT_INFO_FIELD2_STAMAX 65535 +#define WNI_CFG_HT_INFO_FIELD2_STADEF 0 + +#define WNI_CFG_HT_INFO_FIELD2_OP_MODE 0 +#define WNI_CFG_HT_INFO_FIELD2_NON_GF_DEVICES_PRESENT 2 +#define WNI_CFG_HT_INFO_FIELD2_RESERVED 3 + +#define WNI_CFG_HT_INFO_FIELD3_STAMIN 0 +#define WNI_CFG_HT_INFO_FIELD3_STAMAX 65535 +#define WNI_CFG_HT_INFO_FIELD3_STADEF 0 + +#define WNI_CFG_HT_INFO_FIELD3_BASIC_STBC_MCS 0 +#define WNI_CFG_HT_INFO_FIELD3_DUAL_STBC_PROTECTION 7 +#define WNI_CFG_HT_INFO_FIELD3_SECONDARY_BEACON 8 +#define WNI_CFG_HT_INFO_FIELD3_LSIG_TXOP_PROTECTION_FULL_SUPPORT 9 +#define WNI_CFG_HT_INFO_FIELD3_PCO_ACTIVE 10 +#define WNI_CFG_HT_INFO_FIELD3_PCO_PHASE 11 +#define WNI_CFG_HT_INFO_FIELD3_RESERVED 12 + +#define WNI_CFG_GREENFIELD_CAPABILITY_STAMIN 0 +#define WNI_CFG_GREENFIELD_CAPABILITY_STAMAX 1 +#define WNI_CFG_GREENFIELD_CAPABILITY_STADEF 0 + +#define WNI_CFG_GREENFIELD_CAPABILITY_ENABLE 1 +#define WNI_CFG_GREENFIELD_CAPABILITY_DISABLE 0 + +#define WNI_CFG_VHT_MAX_MPDU_LENGTH_STAMIN 0 +#define WNI_CFG_VHT_MAX_MPDU_LENGTH_STAMAX 2 +#define WNI_CFG_VHT_MAX_MPDU_LENGTH_STADEF 0 + +#define WNI_CFG_VHT_SUPPORTED_CHAN_WIDTH_SET_STAMIN 0 +#define WNI_CFG_VHT_SUPPORTED_CHAN_WIDTH_SET_STAMAX 2 +#define WNI_CFG_VHT_SUPPORTED_CHAN_WIDTH_SET_STADEF 2 + +#define WNI_CFG_VHT_LDPC_CODING_CAP_STAMIN 0 +#define WNI_CFG_VHT_LDPC_CODING_CAP_STAMAX 1 +#define WNI_CFG_VHT_LDPC_CODING_CAP_STADEF 0 + +#define WNI_CFG_VHT_SHORT_GI_80MHZ_STAMIN 0 +#define WNI_CFG_VHT_SHORT_GI_80MHZ_STAMAX 1 +#define WNI_CFG_VHT_SHORT_GI_80MHZ_STADEF 1 + +#define WNI_CFG_VHT_SHORT_GI_160_AND_80_PLUS_80MHZ_STAMIN 0 +#define WNI_CFG_VHT_SHORT_GI_160_AND_80_PLUS_80MHZ_STAMAX 1 +#define WNI_CFG_VHT_SHORT_GI_160_AND_80_PLUS_80MHZ_STADEF 1 + +#define WNI_CFG_VHT_TXSTBC_STAMIN 0 +#define WNI_CFG_VHT_TXSTBC_STAMAX 1 +#define WNI_CFG_VHT_TXSTBC_STADEF 0 + +#define WNI_CFG_VHT_RXSTBC_STAMIN 0 +#define WNI_CFG_VHT_RXSTBC_STAMAX 1 +#define WNI_CFG_VHT_RXSTBC_STADEF 1 + +#define WNI_CFG_VHT_SU_BEAMFORMER_CAP_STAMIN 0 +#define WNI_CFG_VHT_SU_BEAMFORMER_CAP_STAMAX 1 +#define WNI_CFG_VHT_SU_BEAMFORMER_CAP_STADEF 0 + +#define WNI_CFG_VHT_SU_BEAMFORMEE_CAP_STAMIN 0 +#define WNI_CFG_VHT_SU_BEAMFORMEE_CAP_STAMAX 1 +#define WNI_CFG_VHT_SU_BEAMFORMEE_CAP_STADEF 1 + +#define WNI_CFG_VHT_CSN_BEAMFORMEE_ANT_SUPPORTED_STAMIN 0 +#define WNI_CFG_VHT_CSN_BEAMFORMEE_ANT_SUPPORTED_STAMAX 8 +#define WNI_CFG_VHT_CSN_BEAMFORMEE_ANT_SUPPORTED_STADEF 8 +/* + * WNI_CFG_VHT_CSN_BEAMFORMEE_ANT_SUPPORTED_FW_DEF + 1 is + * assumed to be the default fw supported BF antennas, if fw + * says it supports 8 antennas in rx ready event and if + * gTxBFCsnValue INI value is configured above 3, set + * the same to WNI_CFG_VHT_CSN_BEAMFORMEE_ANT_SUPPORTED. + * Otherwise, fall back and set fw default value[3]. + */ +#define WNI_CFG_VHT_CSN_BEAMFORMEE_ANT_SUPPORTED_FW_DEF 3 + +#define WNI_CFG_VHT_NUM_SOUNDING_DIMENSIONS_STAMIN 0 +#define WNI_CFG_VHT_NUM_SOUNDING_DIMENSIONS_STAMAX 3 +#define WNI_CFG_VHT_NUM_SOUNDING_DIMENSIONS_STADEF 0 + +#define WNI_CFG_VHT_MU_BEAMFORMER_CAP_STAMIN 0 +#define WNI_CFG_VHT_MU_BEAMFORMER_CAP_STAMAX 1 +#define WNI_CFG_VHT_MU_BEAMFORMER_CAP_STADEF 0 + +#define WNI_CFG_VHT_MU_BEAMFORMEE_CAP_STAMIN 0 +#define WNI_CFG_VHT_MU_BEAMFORMEE_CAP_STAMAX 1 +#define WNI_CFG_VHT_MU_BEAMFORMEE_CAP_STADEF 0 + +#define WNI_CFG_VHT_TXOP_PS_STAMIN 0 +#define WNI_CFG_VHT_TXOP_PS_STAMAX 1 +#define WNI_CFG_VHT_TXOP_PS_STADEF 0 + +#define WNI_CFG_VHT_HTC_VHTC_CAP_STAMIN 0 +#define WNI_CFG_VHT_HTC_VHTC_CAP_STAMAX 1 +#define WNI_CFG_VHT_HTC_VHTC_CAP_STADEF 0 + +#define WNI_CFG_VHT_AMPDU_LEN_EXPONENT_STAMIN 0 +#define WNI_CFG_VHT_AMPDU_LEN_EXPONENT_STAMAX 7 +#define WNI_CFG_VHT_AMPDU_LEN_EXPONENT_STADEF 3 + +#define WNI_CFG_VHT_LINK_ADAPTATION_CAP_STAMIN 0 +#define WNI_CFG_VHT_LINK_ADAPTATION_CAP_STAMAX 3 +#define WNI_CFG_VHT_LINK_ADAPTATION_CAP_STADEF 0 + +#define WNI_CFG_VHT_RX_ANT_PATTERN_STAMIN 0 +#define WNI_CFG_VHT_RX_ANT_PATTERN_STAMAX 1 +#define WNI_CFG_VHT_RX_ANT_PATTERN_STADEF 1 + +#define WNI_CFG_VHT_TX_ANT_PATTERN_STAMIN 0 +#define WNI_CFG_VHT_TX_ANT_PATTERN_STAMAX 1 +#define WNI_CFG_VHT_TX_ANT_PATTERN_STADEF 1 + +#define WNI_CFG_VHT_RX_MCS_MAP_STAMIN 0 +#define WNI_CFG_VHT_RX_MCS_MAP_STAMAX 65535 +#define WNI_CFG_VHT_RX_MCS_MAP_STADEF 65534 + +#define WNI_CFG_VHT_TX_MCS_MAP_STAMIN 0 +#define WNI_CFG_VHT_TX_MCS_MAP_STAMAX 65535 +#define WNI_CFG_VHT_TX_MCS_MAP_STADEF 65534 + +#define WNI_CFG_VHT_RX_HIGHEST_SUPPORTED_DATA_RATE_STAMIN 0 +#define WNI_CFG_VHT_RX_HIGHEST_SUPPORTED_DATA_RATE_STAMAX 780 +#define WNI_CFG_VHT_RX_HIGHEST_SUPPORTED_DATA_RATE_STADEF 780 + +#define WNI_CFG_VHT_TX_HIGHEST_SUPPORTED_DATA_RATE_STAMIN 0 +#define WNI_CFG_VHT_TX_HIGHEST_SUPPORTED_DATA_RATE_STAMAX 780 +#define WNI_CFG_VHT_TX_HIGHEST_SUPPORTED_DATA_RATE_STADEF 780 + +#define WNI_CFG_VHT_BASIC_MCS_SET_STAMIN 0 +#define WNI_CFG_VHT_BASIC_MCS_SET_STAMAX 65535 +#define WNI_CFG_VHT_BASIC_MCS_SET_STADEF 65534 + +#define WNI_CFG_VHT_MU_MIMO_CAP_STA_COUNT_STAMIN 0 +#define WNI_CFG_VHT_MU_MIMO_CAP_STA_COUNT_STAMAX 4 +#define WNI_CFG_VHT_MU_MIMO_CAP_STA_COUNT_STADEF 0 + +#define WNI_CFG_VHT_SS_UNDER_UTIL_STAMIN 0 +#define WNI_CFG_VHT_SS_UNDER_UTIL_STAMAX 0 +#define WNI_CFG_VHT_SS_UNDER_UTIL_STADEF 0 + +#define WNI_CFG_VHT_40MHZ_UTILIZATION_STAMIN 0 +#define WNI_CFG_VHT_40MHZ_UTILIZATION_STAMAX 0 +#define WNI_CFG_VHT_40MHZ_UTILIZATION_STADEF 0 + +#define WNI_CFG_VHT_80MHZ_UTILIZATION_STAMIN 0 +#define WNI_CFG_VHT_80MHZ_UTILIZATION_STAMAX 0 +#define WNI_CFG_VHT_80MHZ_UTILIZATION_STADEF 0 + +#define WNI_CFG_VHT_160MHZ_UTILIZATION_STAMIN 0 +#define WNI_CFG_VHT_160MHZ_UTILIZATION_STAMAX 0 +#define WNI_CFG_VHT_160MHZ_UTILIZATION_STADEF 0 + +#define WNI_CFG_MAX_AMSDU_LENGTH_STAMIN 0 +#define WNI_CFG_MAX_AMSDU_LENGTH_STAMAX 1 +#define WNI_CFG_MAX_AMSDU_LENGTH_STADEF 0 + +#define WNI_CFG_MAX_AMSDU_LENGTH_SHORT_3839_BYTES 0 +#define WNI_CFG_MAX_AMSDU_LENGTH_LONG_7935__BYTES 1 + +#define WNI_CFG_MPDU_DENSITY_STAMIN 0 +#define WNI_CFG_MPDU_DENSITY_STAMAX 7 +#define WNI_CFG_MPDU_DENSITY_STADEF 7 + +#define WNI_CFG_NUM_BUFF_ADVERT_STAMIN 0 +#define WNI_CFG_NUM_BUFF_ADVERT_STAMAX 128 +#define WNI_CFG_NUM_BUFF_ADVERT_STADEF 64 + +#define WNI_CFG_MAX_RX_AMPDU_FACTOR_STAMIN 0 +#define WNI_CFG_MAX_RX_AMPDU_FACTOR_STAMAX 3 +#define WNI_CFG_MAX_RX_AMPDU_FACTOR_STADEF 3 + +#define WNI_CFG_SHORT_GI_20MHZ_STAMIN 0 +#define WNI_CFG_SHORT_GI_20MHZ_STAMAX 1 +#define WNI_CFG_SHORT_GI_20MHZ_STADEF 1 + +#define WNI_CFG_SHORT_GI_20MHZ_ENABLE 1 +#define WNI_CFG_SHORT_GI_20MHZ_DISABLE 0 + +#define WNI_CFG_SHORT_GI_40MHZ_STAMIN 0 +#define WNI_CFG_SHORT_GI_40MHZ_STAMAX 1 +#define WNI_CFG_SHORT_GI_40MHZ_STADEF 0 + +#define WNI_CFG_SHORT_GI_40MHZ_ENABLE 1 +#define WNI_CFG_SHORT_GI_40MHZ_DISABLE 0 + +#define WNI_CFG_MAX_PS_POLL_STAMIN 0 +#define WNI_CFG_MAX_PS_POLL_STAMAX 255 +#define WNI_CFG_MAX_PS_POLL_STADEF 0 + +#define WNI_CFG_RSSI_FILTER_PERIOD_STAMIN 0 +#define WNI_CFG_RSSI_FILTER_PERIOD_STAMAX 255 +#define WNI_CFG_RSSI_FILTER_PERIOD_STADEF 5 + +#define WNI_CFG_SCAN_IN_POWERSAVE_STAMIN 0 +#define WNI_CFG_SCAN_IN_POWERSAVE_STAMAX 1 +#define WNI_CFG_SCAN_IN_POWERSAVE_STADEF 1 + +#define WNI_CFG_IGNORE_DTIM_STAMIN 0 +#define WNI_CFG_IGNORE_DTIM_STAMAX 1 +#define WNI_CFG_IGNORE_DTIM_STADEF 0 + +#define WNI_CFG_WOWLAN_UCAST_PATTERN_FILTER_ENABLE_STAMIN 0 +#define WNI_CFG_WOWLAN_UCAST_PATTERN_FILTER_ENABLE_STAMAX 1 +#define WNI_CFG_WOWLAN_UCAST_PATTERN_FILTER_ENABLE_STADEF 1 + +#define WNI_CFG_WOWLAN_CHANNEL_SWITCH_ENABLE_STAMIN 0 +#define WNI_CFG_WOWLAN_CHANNEL_SWITCH_ENABLE_STAMAX 1 +#define WNI_CFG_WOWLAN_CHANNEL_SWITCH_ENABLE_STADEF 1 + +#define WNI_CFG_WOWLAN_DEAUTH_ENABLE_STAMIN 0 +#define WNI_CFG_WOWLAN_DEAUTH_ENABLE_STAMAX 1 +#define WNI_CFG_WOWLAN_DEAUTH_ENABLE_STADEF 1 + +#define WNI_CFG_WOWLAN_DISASSOC_ENABLE_STAMIN 0 +#define WNI_CFG_WOWLAN_DISASSOC_ENABLE_STAMAX 1 +#define WNI_CFG_WOWLAN_DISASSOC_ENABLE_STADEF 1 + +#define WNI_CFG_WOWLAN_MAX_MISSED_BEACON_STAMIN 0 +#define WNI_CFG_WOWLAN_MAX_MISSED_BEACON_STAMAX 65535 +#define WNI_CFG_WOWLAN_MAX_MISSED_BEACON_STADEF 40 + +#define WNI_CFG_WOWLAN_MAX_SLEEP_PERIOD_STAMIN 0 +#define WNI_CFG_WOWLAN_MAX_SLEEP_PERIOD_STAMAX 65535 +#define WNI_CFG_WOWLAN_MAX_SLEEP_PERIOD_STADEF 65535 + +#define WNI_CFG_MAX_MEDIUM_TIME_STAMIN 0 +#define WNI_CFG_MAX_MEDIUM_TIME_STAMAX 65535 +#define WNI_CFG_MAX_MEDIUM_TIME_STADEF 2048 + +#define WNI_CFG_IBSS_AUTO_BSSID_STAMIN 0 +#define WNI_CFG_IBSS_AUTO_BSSID_STAMAX 1 +#define WNI_CFG_IBSS_AUTO_BSSID_STADEF 1 + +#define WNI_CFG_PROBE_RSP_BCN_ADDNIE_FLAG_STAMIN 0 +#define WNI_CFG_PROBE_RSP_BCN_ADDNIE_FLAG_STAMAX 1 +#define WNI_CFG_PROBE_RSP_BCN_ADDNIE_FLAG_STADEF 0 + +#define WNI_CFG_WPS_ENABLE_STAMIN 0 +#define WNI_CFG_WPS_ENABLE_STAMAX 255 +#define WNI_CFG_WPS_ENABLE_STADEF 0 + +#define WNI_CFG_WPS_ENABLE_AP 1 +#define WNI_CFG_WPS_ENABLE_STA 2 + +#define WNI_CFG_WPS_STATE_STAMIN 0 +#define WNI_CFG_WPS_STATE_STAMAX 255 +#define WNI_CFG_WPS_STATE_STADEF 1 + +#define WNI_CFG_WPS_VERSION_STAMIN 0 +#define WNI_CFG_WPS_VERSION_STAMAX 255 +#define WNI_CFG_WPS_VERSION_STADEF 16 + +#define WNI_CFG_WPS_CFG_METHOD_STAMIN 0 +#define WNI_CFG_WPS_CFG_METHOD_STAMAX 4294967295 +#define WNI_CFG_WPS_CFG_METHOD_STADEF 8 + +#define WNI_CFG_WPS_PRIMARY_DEVICE_CATEGORY_STAMIN 0 +#define WNI_CFG_WPS_PRIMARY_DEVICE_CATEGORY_STAMAX 65535 +#define WNI_CFG_WPS_PRIMARY_DEVICE_CATEGORY_STADEF 1 + +#define WNI_CFG_WPS_PIMARY_DEVICE_OUI_STAMIN 0 +#define WNI_CFG_WPS_PIMARY_DEVICE_OUI_STAMAX 4294967295 +#define WNI_CFG_WPS_PIMARY_DEVICE_OUI_STADEF 5304836 + +#define WNI_CFG_WPS_DEVICE_SUB_CATEGORY_STAMIN 0 +#define WNI_CFG_WPS_DEVICE_SUB_CATEGORY_STAMAX 65535 +#define WNI_CFG_WPS_DEVICE_SUB_CATEGORY_STADEF 1 + +#define WNI_CFG_WPS_DEVICE_PASSWORD_ID_STAMIN 0 +#define WNI_CFG_WPS_DEVICE_PASSWORD_ID_STAMAX 4294967295 +#define WNI_CFG_WPS_DEVICE_PASSWORD_ID_STADEF 0 + +#define WNI_CFG_LOW_GAIN_OVERRIDE_STAMIN 0 +#define WNI_CFG_LOW_GAIN_OVERRIDE_STAMAX 1 +#define WNI_CFG_LOW_GAIN_OVERRIDE_STADEF 0 + +#define WNI_CFG_SINGLE_TID_RC_STAMIN 0 +#define WNI_CFG_SINGLE_TID_RC_STAMAX 1 +#define WNI_CFG_SINGLE_TID_RC_STADEF 1 + +#define WNI_CFG_MCAST_BCAST_FILTER_SETTING_STAMIN 0 +#define WNI_CFG_MCAST_BCAST_FILTER_SETTING_STAMAX 3 +#define WNI_CFG_MCAST_BCAST_FILTER_SETTING_STADEF 0 + +#define WNI_CFG_DYNAMIC_PS_POLL_VALUE_STAMIN 0 +#define WNI_CFG_DYNAMIC_PS_POLL_VALUE_STAMAX 255 +#define WNI_CFG_DYNAMIC_PS_POLL_VALUE_STADEF 0 + +#define WNI_CFG_PS_NULLDATA_AP_RESP_TIMEOUT_STAMIN 0 +#define WNI_CFG_PS_NULLDATA_AP_RESP_TIMEOUT_STAMAX 80 +#define WNI_CFG_PS_NULLDATA_AP_RESP_TIMEOUT_STADEF 0 + +#define WNI_CFG_TELE_BCN_WAKEUP_EN_STAMIN 0 +#define WNI_CFG_TELE_BCN_WAKEUP_EN_STAMAX 1 +#define WNI_CFG_TELE_BCN_WAKEUP_EN_STADEF 0 + +#define WNI_CFG_TELE_BCN_TRANS_LI_STAMIN 0 +#define WNI_CFG_TELE_BCN_TRANS_LI_STAMAX 7 +#define WNI_CFG_TELE_BCN_TRANS_LI_STADEF 3 + +#define WNI_CFG_TELE_BCN_TRANS_LI_IDLE_BCNS_STAMIN 5 +#define WNI_CFG_TELE_BCN_TRANS_LI_IDLE_BCNS_STAMAX 255 +#define WNI_CFG_TELE_BCN_TRANS_LI_IDLE_BCNS_STADEF 10 + +#define WNI_CFG_TELE_BCN_MAX_LI_STAMIN 0 +#define WNI_CFG_TELE_BCN_MAX_LI_STAMAX 7 +#define WNI_CFG_TELE_BCN_MAX_LI_STADEF 5 + +#define WNI_CFG_TELE_BCN_MAX_LI_IDLE_BCNS_STAMIN 5 +#define WNI_CFG_TELE_BCN_MAX_LI_IDLE_BCNS_STAMAX 255 +#define WNI_CFG_TELE_BCN_MAX_LI_IDLE_BCNS_STADEF 15 + +#define WNI_CFG_INFRA_STA_KEEP_ALIVE_PERIOD_STAMIN 0 +#define WNI_CFG_INFRA_STA_KEEP_ALIVE_PERIOD_STAMAX 1000 +#define WNI_CFG_INFRA_STA_KEEP_ALIVE_PERIOD_STADEF 0 + +#define WNI_CFG_ASSOC_STA_LIMIT_STAMIN 1 +#define WNI_CFG_ASSOC_STA_LIMIT_STAMAX 32 +#define WNI_CFG_ASSOC_STA_LIMIT_STADEF 10 + +#define WNI_CFG_AP_DATA_AVAIL_POLL_PERIOD_STAMIN 0 +#define WNI_CFG_AP_DATA_AVAIL_POLL_PERIOD_STAMAX 65535 +#define WNI_CFG_AP_DATA_AVAIL_POLL_PERIOD_STADEF 5 + +#define WNI_CFG_ENABLE_LTE_COEX_STAMIN 0 +#define WNI_CFG_ENABLE_LTE_COEX_STAMAX 1 +#define WNI_CFG_ENABLE_LTE_COEX_STADEF 0 + +#define WNI_CFG_AP_KEEP_ALIVE_TIMEOUT_STAMIN 1 +#define WNI_CFG_AP_KEEP_ALIVE_TIMEOUT_STAMAX 65535 +#define WNI_CFG_AP_KEEP_ALIVE_TIMEOUT_STADEF 20 + +#define WNI_CFG_GO_KEEP_ALIVE_TIMEOUT_STAMIN 1 +#define WNI_CFG_GO_KEEP_ALIVE_TIMEOUT_STAMAX 65535 +#define WNI_CFG_GO_KEEP_ALIVE_TIMEOUT_STADEF 20 + +#define WNI_CFG_ENABLE_MC_ADDR_LIST_STAMIN 0 +#define WNI_CFG_ENABLE_MC_ADDR_LIST_STAMAX 1 +#define WNI_CFG_ENABLE_MC_ADDR_LIST_STADEF 0 + +#define WNI_CFG_ENABLE_LPWR_IMG_TRANSITION_STAMIN 0 +#define WNI_CFG_ENABLE_LPWR_IMG_TRANSITION_STAMAX 1 +#define WNI_CFG_ENABLE_LPWR_IMG_TRANSITION_STADEF 0 + +#define WNI_CFG_ENABLE_MCC_ADAPTIVE_SCHED_STAMIN 0 +#define WNI_CFG_ENABLE_MCC_ADAPTIVE_SCHED_STAMAX 1 +#define WNI_CFG_ENABLE_MCC_ADAPTIVE_SCHED_STADEF 0 + +#define WNI_CFG_DISABLE_LDPC_WITH_TXBF_AP_STAMIN 0 +#define WNI_CFG_DISABLE_LDPC_WITH_TXBF_AP_STAMAX 1 +#define WNI_CFG_DISABLE_LDPC_WITH_TXBF_AP_STADEF 0 + +#define WNI_CFG_AP_LINK_MONITOR_TIMEOUT_STAMIN 1 +#define WNI_CFG_AP_LINK_MONITOR_TIMEOUT_STAMAX 255 +#define WNI_CFG_AP_LINK_MONITOR_TIMEOUT_STADEF 3 + +#define WNI_CFG_TDLS_QOS_WMM_UAPSD_MASK_STAMIN 0 +#define WNI_CFG_TDLS_QOS_WMM_UAPSD_MASK_STAMAX 15 +#define WNI_CFG_TDLS_QOS_WMM_UAPSD_MASK_STADEF 0 + +#define WNI_CFG_TDLS_BUF_STA_ENABLED_STAMIN 0 +#define WNI_CFG_TDLS_BUF_STA_ENABLED_STAMAX 1 +#define WNI_CFG_TDLS_BUF_STA_ENABLED_STADEF 0 + +#define WNI_CFG_TDLS_PUAPSD_INACT_TIME_STAMIN 0 +#define WNI_CFG_TDLS_PUAPSD_INACT_TIME_STAMAX 10 +#define WNI_CFG_TDLS_PUAPSD_INACT_TIME_STADEF 0 + +#define WNI_CFG_TDLS_RX_FRAME_THRESHOLD_STAMIN 10 +#define WNI_CFG_TDLS_RX_FRAME_THRESHOLD_STAMAX 20 +#define WNI_CFG_TDLS_RX_FRAME_THRESHOLD_STADEF 10 + +#define WNI_CFG_PMF_SA_QUERY_MAX_RETRIES_STAMIN 0 +#define WNI_CFG_PMF_SA_QUERY_MAX_RETRIES_STAMAX 20 +#define WNI_CFG_PMF_SA_QUERY_MAX_RETRIES_STADEF 5 + +#define WNI_CFG_PMF_SA_QUERY_RETRY_INTERVAL_STAMIN 10 +#define WNI_CFG_PMF_SA_QUERY_RETRY_INTERVAL_STAMAX 2000 +#define WNI_CFG_PMF_SA_QUERY_RETRY_INTERVAL_STADEF 200 + +#define WNI_CFG_ENABLE_ADAPT_RX_DRAIN_STAMIN 0 +#define WNI_CFG_ENABLE_ADAPT_RX_DRAIN_STAMAX 1 +#define WNI_CFG_ENABLE_ADAPT_RX_DRAIN_STADEF 1 + +#define WNI_CFG_ANTENNA_DIVESITY_STAMIN 0 +#define WNI_CFG_ANTENNA_DIVESITY_STAMAX 3 +#define WNI_CFG_ANTENNA_DIVESITY_STADEF 0 + +#define WNI_CFG_GO_LINK_MONITOR_TIMEOUT_STAMIN 3 +#define WNI_CFG_GO_LINK_MONITOR_TIMEOUT_STAMAX 50 +#define WNI_CFG_GO_LINK_MONITOR_TIMEOUT_STADEF 10 + +#define WNI_CFG_RMC_ACTION_PERIOD_FREQUENCY_STAMIN 100 +#define WNI_CFG_RMC_ACTION_PERIOD_FREQUENCY_STAMAX 1000 +#define WNI_CFG_RMC_ACTION_PERIOD_FREQUENCY_STADEF 300 + +#define WNI_CFG_CURRENT_RSSI_STAMIN 0 +#define WNI_CFG_CURRENT_RSSI_STAMAX 127 +#define WNI_CFG_CURRENT_RSSI_STADEF 0 + +#define WNI_CFG_RTT3_ENABLE_STAMIN 0 +#define WNI_CFG_RTT3_ENABLE_STAMAX 1 +#define WNI_CFG_RTT3_ENABLE_STADEF 1 + +#define WNI_CFG_DEBUG_P2P_REMAIN_ON_CHANNEL_STAMIN 0 +#define WNI_CFG_DEBUG_P2P_REMAIN_ON_CHANNEL_STAMAX 1 +#define WNI_CFG_DEBUG_P2P_REMAIN_ON_CHANNEL_STADEF 0 + +#define WNI_CFG_TDLS_OFF_CHANNEL_ENABLED_STAMIN 0 +#define WNI_CFG_TDLS_OFF_CHANNEL_ENABLED_STAMAX 1 +#define WNI_CFG_TDLS_OFF_CHANNEL_ENABLED_STADEF 0 + +#define WNI_CFG_IBSS_ATIM_WIN_SIZE_STAMIN 0 +#define WNI_CFG_IBSS_ATIM_WIN_SIZE_STAMAX 100 +#define WNI_CFG_IBSS_ATIM_WIN_SIZE_STADEF 0 + +#define WNI_CFG_DFS_MASTER_ENABLED_STAMIN 0 +#define WNI_CFG_DFS_MASTER_ENABLED_STAMAX 1 +#define WNI_CFG_DFS_MASTER_ENABLED_STADEF 0 + +#define WNI_CFG_VHT_ENABLE_TXBF_20MHZ_STAMIN 0 +#define WNI_CFG_VHT_ENABLE_TXBF_20MHZ_STAMAX 1 +#define WNI_CFG_VHT_ENABLE_TXBF_20MHZ_STADEF 0 + +#define WNI_CFG_TDLS_WMM_MODE_ENABLED_STAMIN 0 +#define WNI_CFG_TDLS_WMM_MODE_ENABLED_STAMAX 1 +#define WNI_CFG_TDLS_WMM_MODE_ENABLED_STADEF 0 + +#define WNI_CFG_OBSS_HT40_SCAN_PASSIVE_DWELL_TIME_STAMIN 5 +#define WNI_CFG_OBSS_HT40_SCAN_PASSIVE_DWELL_TIME_STAMAX 1000 +#define WNI_CFG_OBSS_HT40_SCAN_PASSIVE_DWELL_TIME_STADEF 20 + +#define WNI_CFG_OBSS_HT40_SCAN_ACTIVE_DWELL_TIME_STAMIN 10 +#define WNI_CFG_OBSS_HT40_SCAN_ACTIVE_DWELL_TIME_STAMAX 1000 +#define WNI_CFG_OBSS_HT40_SCAN_ACTIVE_DWELL_TIME_STADEF 10 + +#define WNI_CFG_OBSS_HT40_SCAN_WIDTH_TRIGGER_INTERVAL_STAMIN 10 +#define WNI_CFG_OBSS_HT40_SCAN_WIDTH_TRIGGER_INTERVAL_STAMAX 900 +#define WNI_CFG_OBSS_HT40_SCAN_WIDTH_TRIGGER_INTERVAL_STADEF 200 + +#define WNI_CFG_OBSS_HT40_SCAN_PASSIVE_TOTAL_PER_CHANNEL_STAMIN 200 +#define WNI_CFG_OBSS_HT40_SCAN_PASSIVE_TOTAL_PER_CHANNEL_STAMAX 10000 +#define WNI_CFG_OBSS_HT40_SCAN_PASSIVE_TOTAL_PER_CHANNEL_STADEF 200 + +#define WNI_CFG_OBSS_HT40_SCAN_ACTIVE_TOTAL_PER_CHANNEL_STAMIN 20 +#define WNI_CFG_OBSS_HT40_SCAN_ACTIVE_TOTAL_PER_CHANNEL_STAMAX 10000 +#define WNI_CFG_OBSS_HT40_SCAN_ACTIVE_TOTAL_PER_CHANNEL_STADEF 20 + +#define WNI_CFG_OBSS_HT40_WIDTH_CH_TRANSITION_DELAY_STAMIN 5 +#define WNI_CFG_OBSS_HT40_WIDTH_CH_TRANSITION_DELAY_STAMAX 100 +#define WNI_CFG_OBSS_HT40_WIDTH_CH_TRANSITION_DELAY_STADEF 5 + +#define WNI_CFG_OBSS_HT40_SCAN_ACTIVITY_THRESHOLD_STAMIN 0 +#define WNI_CFG_OBSS_HT40_SCAN_ACTIVITY_THRESHOLD_STAMAX 100 +#define WNI_CFG_OBSS_HT40_SCAN_ACTIVITY_THRESHOLD_STADEF 25 + +#define WNI_CFG_TGT_GTX_USR_CFG_STAMIN 0 +#define WNI_CFG_TGT_GTX_USR_CFG_STAMAX 32 +#define WNI_CFG_TGT_GTX_USR_CFG_STADEF 32 + +#define WNI_CFG_MAX_HT_MCS_TX_DATA_STAMIN 0x0 +#define WNI_CFG_MAX_HT_MCS_TX_DATA_STAMAX 0x17f +#define WNI_CFG_MAX_HT_MCS_TX_DATA_STADEF 0x0 + +#define WNI_CFG_DISABLE_ABG_RATE_FOR_TX_DATA_STAMIN 0 +#define WNI_CFG_DISABLE_ABG_RATE_FOR_TX_DATA_STAMAX 1 +#define WNI_CFG_DISABLE_ABG_RATE_FOR_TX_DATA_STADEF 0 + +#define WNI_CFG_RATE_FOR_TX_MGMT_STAMIN 0x0 +#define WNI_CFG_RATE_FOR_TX_MGMT_STAMAX 0xFF +#define WNI_CFG_RATE_FOR_TX_MGMT_STADEF 0xFF + +#define WNI_CFG_PS_WOW_DATA_INACTIVITY_TIMEOUT_STAMIN 1 +#define WNI_CFG_PS_WOW_DATA_INACTIVITY_TIMEOUT_STAMAX 255 +#define WNI_CFG_PS_WOW_DATA_INACTIVITY_TIMEOUT_STADEF 50 + +#define CFG_STA_MAGIC_DWORD 0xbeefbeef + +#endif diff --git a/drivers/staging/qcacld-3.0/core/mac/src/cfg/cfgUtil/cfg.txt b/drivers/staging/qcacld-3.0/core/mac/src/cfg/cfgUtil/cfg.txt new file mode 100644 index 0000000000000000000000000000000000000000..85071b968781a7641b8a576355647a6ed1c6d990 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/cfg/cfgUtil/cfg.txt @@ -0,0 +1,4474 @@ +* Copyright (c) 2014-2015 The Linux Foundation. All rights reserved. +* +* Previously licensed under the ISC license by Qualcomm Atheros, Inc. +* +* +* 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. + +* This file was originally distributed by Qualcomm Atheros, Inc. +* under proprietary terms before Copyright ownership was assigned +* to the Linux Foundation. + +* +* This is the data definition file for the CFG module. +* Author: Kevin Nguyen +* Date: 03/18/02 +* History:- +* 03/18/02 Created. +* 08/10/05 ww: add maoe channels to have a complete channel listing: (see WNI_CFG_VALID_CHANNEL_LIST) +* 08/10/05 ww: WNI_CFG_SCAN_CONTROL_LIST has a new contents +* -------------------------------------------------------------------- + +********************************************************************** +* +* This file contains the descriptions of all configuration parameters +* for both STA and AP. +* +* OUTPUT: +* ------- +* The output files are: +* wniCfgSta.h - C header file for STA mode only +* wniCfgAp.h - C header file for both STA and AP +* wniCfgSta.bin - Control and default values for STA system +* wniCfgAp.bin - Control and default values for AP system +* +* PARAMETER DESCRIPTION: +* ---------------------- +* For each parameter, the description must be on separate lines and +* exactly as specified below. [] are comments and should not be included. +* +* [Common info] parameter_name type maxLen semIndx +* [STA flags] valid RW P/NP RESTART/RELOAD +* [STA_NTF] notification_mask +* [STA values] min max value [for integer] +* length byte1 byte2 ... [for string] +* [AP flags] valid RW/RO/WO P/NP RESTART/RELOAD +* [AP_NTF] notification_mask +* [AP values] min max value [for integer] +* length byte1 byte2 ... [for string] +* +* parameter_name: +* This will be used as the base name for C macro definition. +* Therefore, C syntax rule must be observed. +* +* type: +* Specifies parameter type +* S - variable-length string +* I - integer +* +* maxLen: +* Specifies maximum parameter length in bytes. +* +* semIndx: +* Specifies semaphore index to use for locking this parameter. +* More than one parameters (those belonging to the same group) +* can share the same semaphore index. +* +* valid: +* Specifies if this parameter will be valid in current mode. +* V - Valid +* NV - Not valid +* +* RW: +* Specifies Read/Write mode. +* RO - Read only +* RW - Read/Write +* WO - Write only +* XX - Not accessible from host +* +* P: +* Specifies persistent memory option +* P - Save to persistent memory +* NP - No save +* +* RELOAD: +* Specifies whether setting this requires reloading the MAC module +* This attribute can be changed only when SME is in OFFLINE or SUSPEND(OFFLINE) state +* +* RESTART: +* Specifies whether setting this requires (re)assoc at STA and restart at AP +* This attribute can be changed only when SME is in OFFLINE, SUSPEND(OFFLINE), +* IDLE or SUSPEND(IDLE) states +* +* STA_notification: +* Lists modules to be notified in STA mode. Valid modules are: +* HDD, LIM, SCH, ARQ, DPH, NIM, SP, RFP, RHP, TFP. More than one +* modules can be listed on the same line using space or tab as the +* separator. If no notification is required, 'NONE' must be specified. +* +* AP_notification: +* Lists module to be notified in AP mode. Valid modules are: +* HDD, LIM, SCH, ARQ, DPH, NIM, SP, RFP, RHP, TFP. More than one +* modules can be listed on the same line using space or tab as the +* separator. If no notification is required, 'NONE' must be specified. +* +* STA/AP integer values: +* min: +* Specifies minimum value for an integer parameter. This field is +* ignored if the parameter type is string. However, this field must +* not be omitted. +* +* max: +* Specifies maximum value for an integer parameter. This field is +* ignored if the parameter type is string. However, this field must +* not be omitted. +* +* default: +* Specifies default value for an integer parameter. This field is +* ignored if the parameter type is string. However, this field must +* not be omitted. +* +* STA/AP string values: +* len: +* The actual length of the string +* +* bytei: +* byte i of the string where i varies from 1 to len +* +* TABLE GENERATION: +* ----------------- +* Table can be generated using keywords '#TABLE' and '#END' as below: +* +* #TABLE table_name number_of_row +* WNI_CFG_xxxx +* ....... +* ....... +* #END +* +* The CFG utility will generate the following output: +* WNI_CFG_table_xxx_ID xxx +* WNI_CFG_table_xxx_ROW number_of_rows +* WNI_CFG_table_xxx_COL number_of_columns +* +* These will be followed by the parameter definition for each entry in +* the table. Table is organized in column-major order. +* +* #ENTRY_VALUES 1 +* 0 4 1 +* 0 0 0 +* #ENTRY_VALUES 2 +* 0 4 2 +* 0 0 0 +* #ENTRY_VALUES 3 +* 0 4 3 +* 0 0 0 +* #ENTRY_VALUES 4 +* 0 4 4 +* 0 0 0 +* +* +* ENUMERATION +* ----------- +* Enumerations can be define using keyword '#ENUM' +* +* #ENUM xxx val +* +* The cfg utility will generate the following output in the header file +* #define paramname_xxx val +* + + +* +* Station ID (changing requires restart) +* + +WNI_CFG_STA_ID S 6 1 +V RW NP RELOAD +HAL +6 0x22 0x22 0x44 0x44 0x33 0x33 +V RW NP RELOAD +HAL +6 0x22 0x22 0x11 0x11 0x33 0x33 + +* +* CF Pollable +* + +WNI_CFG_CF_POLLABLE I 4 1 +NV RO NP RESTART +NONE +0 0 0 +V RO NP RESTART +NONE +0 1 0 + +* +* CFP Period +* + +WNI_CFG_CFP_PERIOD I 4 1 +V RO NP +NONE +0 255 1 +V RW NP +SCH +0 255 1 + +* +* CFP Max Duration +* + +WNI_CFG_CFP_MAX_DURATION I 4 1 +V RO NP +NONE +0 65535 30000 +V RW NP +HAL +0 65535 30000 + +* +* SSID (changing requires restart) +* + +WNI_CFG_SSID S 32 1 +V RW NP RESTART +NONE +10 1 2 3 4 5 6 7 8 9 0 +V RW NP RESTART +NONE +10 1 2 3 4 5 6 7 8 9 0 + +* +* Beacon Period +* Can't be changed on STA in infrastructure, ignore notification at SCH +* + +WNI_CFG_BEACON_INTERVAL I 4 2 +V RW NP +SCH +0 65535 100 +V RW NP +SCH +0 65535 100 + +* +* DTIM Period +* + +WNI_CFG_DTIM_PERIOD I 4 2 +V RO NP +NONE +0 65535 1 +V RW NP +SCH +0 65535 1 + + +* +* WEP Key Length (5 or 13 bytes) +* + +WNI_CFG_WEP_KEY_LENGTH I 4 5 +V RW NP RESTART +NONE +5 13 5 +V RW NP RESTART +NONE +5 13 5 + +#ENUM 5 5 +#ENUM 13 13 + +* +* Default Key Table +* + +#TABLE WNI_CFG_WEP_DEFAULT_KEY_TABLE 4 + +WNI_CFG_WEP_DEFAULT_KEY S 13 4 +V WO NP RESTART +NONE +0 +V WO NP RESTART +NONE +0 + +#END + +* +* WEP Default Key id +* + +WNI_CFG_WEP_DEFAULT_KEYID I 4 5 +V RW NP +LIM +0 3 0 +V RW NP +LIM +0 3 0 + +#ENUM 0 0 +#ENUM 1 1 +#ENUM 2 2 +#ENUM 3 3 + +* +* Exclude unencrypted frames (WEP) +* + +WNI_CFG_EXCLUDE_UNENCRYPTED I 4 5 +V RW NP +LIM +0 1 0 +V RW NP +LIM +0 1 0 + +* +* RTS Threshold +* + +WNI_CFG_RTS_THRESHOLD I 4 6 +V RW NP +HAL +0 1048576 2347 +V RW NP +HAL +0 1048576 2347 + +* +* Short Retry Limit +* + +WNI_CFG_SHORT_RETRY_LIMIT I 4 6 +V RW NP +HAL +0 255 6 +V RW NP +HAL +0 255 6 + +* +* Long Retry Limit +* + +WNI_CFG_LONG_RETRY_LIMIT I 4 6 +V RW NP +HAL +0 255 6 +V RW NP +HAL +0 255 6 + + +* +* Fragmentation Threshold +* + +WNI_CFG_FRAGMENTATION_THRESHOLD I 4 6 +V RW NP +HAL +256 8000 8000 +V RW NP +HAL +256 8000 8000 + + +* +* Minimum Channel Time (TU) +* + +WNI_CFG_ACTIVE_MINIMUM_CHANNEL_TIME I 4 9 +V RW NP +NONE +0 65535 20 +V RW NP +NONE +0 65535 20 + +* +* Maximum Channel Time (TU) +* + +WNI_CFG_ACTIVE_MAXIMUM_CHANNEL_TIME I 4 9 +V RW NP +NONE +0 65535 40 +V RW NP +NONE +0 65535 40 +* +* Minimum Channel Time (TU) +* + +WNI_CFG_PASSIVE_MINIMUM_CHANNEL_TIME I 4 9 +V RW NP +NONE +0 65535 60 +V RW NP +NONE +0 65535 60 + +* +* Maximum Channel Time (TU) +* + +WNI_CFG_PASSIVE_MAXIMUM_CHANNEL_TIME I 4 9 +V RW NP +NONE +0 65535 110 +V RW NP +NONE +0 65535 110 + +* +* Join Failure Timeout (TU) +* + +WNI_CFG_JOIN_FAILURE_TIMEOUT I 4 7 +V RW NP +NONE +0 65535 3000 +V RW NP +NONE +0 65535 3000 + +* +* Authenticate Failure Timeout (TU) +* + +WNI_CFG_AUTHENTICATE_FAILURE_TIMEOUT I 4 7 +V RW NP +NONE +0 65535 1000 +V RW NP +NONE +0 65535 1000 + +* +* Authenticate Response Timeout (TU) +* + +WNI_CFG_AUTHENTICATE_RSP_TIMEOUT I 4 7 +V RW NP +NONE +0 65535 1000 +V RW NP +NONE +0 65535 1000 + +* +* Assocation Failure Timeout (TU) +* + +WNI_CFG_ASSOCIATION_FAILURE_TIMEOUT I 4 8 +V RW NP +LIM +0 65535 2000 +V RW NP +LIM +0 65535 3000 + +* +* Reassociation Failure Timeout (TU) +* + +WNI_CFG_REASSOCIATION_FAILURE_TIMEOUT I 4 7 +V RW NP +NONE +0 65535 1000 +V RW NP +NONE +0 65535 3000 + + +* +* RA periodicity Timeout (TU) +* + +WNI_CFG_RA_PERIODICITY_TIMEOUT_IN_PS I 4 7 +V RW NP +HAL +0 65535 1000 +NV RW NP +NONE +0 0 0 + +* +* Beacon Filter Enable/Disable (TU) +* + +WNI_CFG_PS_ENABLE_BCN_FILTER I 4 7 +V RW NP +HAL +0 1 1 +NV RW NP +NONE +0 1 1 + +* +* Heart Beat Enable/Disable (TU) +* + +WNI_CFG_PS_ENABLE_HEART_BEAT I 4 7 +V RW NP +HAL +0 1 1 +NV RW NP +NONE +0 1 1 + +* +* RSSI Monitor Enable/Disable (TU) +* + +WNI_CFG_PS_ENABLE_RSSI_MONITOR I 4 7 +V RW NP +HAL +0 1 0 +NV RW NP +NONE +0 1 0 + + +* +* PS Data InActivity Timeout (TU) +* + +WNI_CFG_PS_DATA_INACTIVITY_TIMEOUT I 4 7 +V RW NP +HAL +1 255 20 +NV RW NP +NONE +1 255 20 + + +* +* RF Settling Time Clk (In US) +* + +WNI_CFG_RF_SETTLING_TIME_CLK I 4 7 +V RW NP +HAL +0 60000 1500 +NV RW NP +NONE +0 60000 1500 + +* +* Supported Rate Set for 11b +* + +WNI_CFG_SUPPORTED_RATES_11B S 4 2 +V RO NP +NONE +4 2 4 11 22 +V RO NP +NONE +4 2 4 11 22 + +* +* Supported Rate Set for 11a +* + +WNI_CFG_SUPPORTED_RATES_11A S 8 7 +V RO NP +NONE +8 12 18 24 36 48 72 96 108 +V RO NP +NONE +8 12 18 24 36 48 72 96 108 + + +* +* PHY Mode +* + +WNI_CFG_PHY_MODE I 4 9 +V RW NP RESTART +NONE +0 3 0 +V RW NP RESTART +NONE +0 3 0 + +#ENUM 11A 0 +#ENUM 11B 1 +#ENUM 11G 2 +#ENUM NONE 3 + + +* +*The Dot11 mode can change dynamically on STA +* +WNI_CFG_DOT11_MODE I 4 9 +V RW NP RESTART +LIM +0 11 0 +V RW NP RESTART +LIM +0 11 0 + +#ENUM ALL 0 +#ENUM 11A 1 +#ENUM 11B 2 +#ENUM 11G 3 +#ENUM 11N 4 +#ENUM 11G_ONLY 5 +#ENUM 11N_ONLY 6 +#ENUM 11AC 7 +#ENUM 11AC_ONLY 8 + + + + + + +* +* Operational Rate Set (goes in beacon, probe rsp and assoc req) +* + +WNI_CFG_OPERATIONAL_RATE_SET S 12 2 +V RW NP RESTART +NONE +0 +V RW NP RESTART +NONE +4 0x82 0x84 11 22 +* 8 0x8c 18 24 36 48 72 96 108 + +* +* Extended Operational Rate Set (goes in beacon, assoc req) +* required for 11g +* + +WNI_CFG_EXTENDED_OPERATIONAL_RATE_SET S 8 7 +V RW NP RESTART +NONE +0 +V RW NP RESTART +NONE +0 + +* +* Proprietary Operational Rate Set +* + +WNI_CFG_PROPRIETARY_OPERATIONAL_RATE_SET S 4 7 +V RW NP RESTART +NONE +4 1 3 5 7 +V RW NP RESTART +NONE +4 1 3 5 7 + +* +* BSSID +* In IBSS, this can be changed for coalescing, should SME go into IDLE state? +* + +* +* Listen Interval +* + +WNI_CFG_LISTEN_INTERVAL I 4 7 +V RW NP RESTART +NONE +0 65535 1 +V RO NP +NONE +0 65535 1 + +* +* Valid Channel List +* + +WNI_CFG_VALID_CHANNEL_LIST S 100 8 +V RW NP RESTART +LIM +55 36 40 44 48 52 56 60 64 1 6 11 34 38 42 46 2 3 4 5 7 8 9 10 12 13 14 100 104 108 112 116 120 124 128 132 136 140 149 151 153 155 157 159 161 50 54 58 62 240 242 244 246 248 250 252 +V RW NP RESTART +LIM +55 36 40 44 48 52 56 60 64 1 6 11 34 38 42 46 2 3 4 5 7 8 9 10 12 13 14 100 104 108 112 116 120 124 128 132 136 140 149 151 153 155 157 159 161 50 54 58 62 240 242 244 246 248 250 252 + +* +* Current Channel +* + +WNI_CFG_CURRENT_CHANNEL I 4 9 +V RO NP +NONE +0 165 1 +V RO NP +NONE +0 165 1 + + +* +* For 11a or pure 11g, use 6Mbps(rateindex 11) +* as the default beaconRateIndex and +* nonBeaconRateIndex. +* +WNI_CFG_DEFAULT_RATE_INDEX_5GHZ I 4 9 +V RW NP +NONE +0 11 5 +V RW NP +NONE +0 11 5 + +* +* For 11b/g, use 1Mbps +* as the default beaconRateIndex and +* nonBeaconRateIndex. +* +WNI_CFG_DEFAULT_RATE_INDEX_24GHZ I 4 9 +V RW NP +NONE +0 31 1 +V RW NP +NONE +0 31 1 + + +* ********************************************************* +* +* Rate adaptation type +* + +WNI_CFG_RATE_ADAPTATION_TYPE I 4 0 +V RW NP +SCH +0 2 1 +V RW NP +SCH +0 2 1 + +#ENUM FIXED 0 +#ENUM AUTO 1 +#ENUM SNR_BASED 2 + +* +* Rate adaptation fixed rate +* Used to determine the rate for all peer stations +* +* + +WNI_CFG_FIXED_RATE I 4 0 +V RW NP +HAL +0 44 0 +V RW NP +HAL +0 44 0 + +#ENUM AUTO 0 + +#ENUM 1MBPS 1 +#ENUM 2MBPS 2 +#ENUM 5_5MBPS 3 +#ENUM 11MBPS 4 + +#ENUM 6MBPS 5 +#ENUM 9MBPS 6 +#ENUM 12MBPS 7 +#ENUM 18MBPS 8 +#ENUM 24MBPS 9 +#ENUM 36MBPS 10 +#ENUM 48MBPS 11 +#ENUM 54MBPS 12 + +#ENUM 6_5MBPS_MCS0_20MHZ_SIMO 13 +#ENUM 13MBPS_MCS1_20MHZ_SIMO 14 +#ENUM 19_5MBPS_MCS2_20MHZ_SIMO 15 +#ENUM 26MBPS_MCS3_20MHZ_SIMO 16 +#ENUM 39MBPS_MCS4_20MHZ_SIMO 17 +#ENUM 52MBPS_MCS5_20MHZ_SIMO 18 +#ENUM 58_5MBPS_MCS6_20MHZ_SIMO 19 +#ENUM 65MBPS_MCS7_20MHZ_SIMO 20 + +#ENUM 7_2MBPS_MCS0_20MHZ_SIMO_SGI 21 +#ENUM 14_4MBPS_MCS1_20MHZ_SIMO_SGI 22 +#ENUM 21_7MBPS_MCS2_20MHZ_SIMO_SGI 23 +#ENUM 28_9MBPS_MCS3_20MHZ_SIMO_SGI 24 +#ENUM 43_3MBPS_MCS4_20MHZ_SIMO_SGI 25 +#ENUM 57_8MBPS_MCS5_20MHZ_SIMO_SGI 26 +#ENUM 65MBPS_MCS6_20MHZ_SIMO_SGI 27 +#ENUM 72_2MBPS_MCS7_20MHZ_SIMO_SGI 28 + +#ENUM 0_25MBPS_SLR_20MHZ_SIMO 29 +#ENUM 0_5MBPS_SLR_20MHZ_SIMO 30 + +#ENUM 68_25MBPS_QC_PROP_20MHZ_SIMO 31 +#ENUM 54MBPS_MCS3_40MHZ_SIMO 32 +#ENUM 81MBPS_MCS4_40MHZ_SIMO 33 +#ENUM 108MBPS_MCS5_40MHZ_SIMO 34 +#ENUM 121_5MBPS_MCS6_40MHZ_SIMO 35 +#ENUM 135MBPS_MCS7_40MHZ_SIMO 36 +#ENUM 15MBPS_MCS0_40MHZ_SIMO_SGI 37 +#ENUM 30MBPS_MCS1_40MHZ_SIMO_SGI 38 +#ENUM 45MBPS_MCS2_40MHZ_SIMO_SGI 39 +#ENUM 60MBPS_MCS3_40MHZ_SIMO_SGI 40 +#ENUM 90MBPS_MCS4_40MHZ_SIMO_SGI 41 +#ENUM 120MBPS_MCS5_40MHZ_SIMO_SGI 42 +#ENUM 135MBPS_MCS6_40MHZ_SIMO_SGI 43 +#ENUM 150MBPS_MCS7_40MHZ_SIMO_SGI 44 + +* ********************************************************* +* +* Broadcast/mutlicast rates for 2.4GHZ +* uses the same rate indices definition as WNI_CFG_FIXED_RATE +* default value corresponds to 1M + +WNI_CFG_FIXED_RATE_MULTICAST_24GHZ I 4 8 +V RW NP +HAL +0 31 1 +V RW NP +HAL +0 31 1 + +* ********************************************************* +* +* Broadcast/mutlicast rates for 5 GHZ +* uses the same rate indices definition as WNI_CFG_FIXED_RATE +* default value corresponds to 6M + +WNI_CFG_FIXED_RATE_MULTICAST_5GHZ I 4 8 +V RW NP +HAL +0 31 5 +V RW NP +HAL +0 31 5 + +* +* retry rate selection policy +* 0 => use the minimum supported rate +* 1 => use the same rate as the chosen primary rate +* 2 => use the rate specified in RETRYRATE_SECONDARY +* 3 => use the rate closest to the primary +* 4 => autoselect the retry rate based on RA algorithm +* + +WNI_CFG_RETRYRATE_POLICY I 4 0 +V RW NP +HAL +0 255 4 +V RW NP +HAL +0 255 4 + +#ENUM MIN_SUPPORTED 0 +#ENUM PRIMARY 1 +#ENUM RESERVED 2 +#ENUM CLOSEST 3 +#ENUM AUTOSELECT 4 +#ENUM MAX 5 + +* +* the following two CFG's are +* used only if the retryrate policy == 2 +* These should be set to one of the values used +* for configuring fixed rates (see enumerated rates) +* + +WNI_CFG_RETRYRATE_SECONDARY I 4 0 +V RW NP +HAL +0 255 0 +V RW NP +HAL +0 255 0 + +WNI_CFG_RETRYRATE_TERTIARY I 4 0 +V RW NP +HAL +0 255 0 +V RW NP +HAL +0 255 0 + +* ********************************************************* +* +* Automatic Power Save Delivery capability +* + +WNI_CFG_APSD_ENABLED I 4 0 +V RW NP +NONE +0 1 0 +V RW NP +NONE +0 1 0 + +* +* Shared key authentication supported +* + +WNI_CFG_SHARED_KEY_AUTH_ENABLE I 4 8 +V RW NP +NONE +0 1 1 +V RW NP +NONE +0 1 1 + +* +* Open system authentication supported +* + +WNI_CFG_OPEN_SYSTEM_AUTH_ENABLE I 4 8 +V RW NP +NONE +0 1 1 +V RW NP +NONE +0 1 1 + +* +* Authentication Type (change requires restart) +* + +WNI_CFG_AUTHENTICATION_TYPE I 4 8 +V RW NP RESTART +NONE +0 65535 0 +V RW NP RESTART +NONE +0 65535 0 + +* +* CF Poll Request (change requires restart) +* + +WNI_CFG_CF_POLL_REQUEST I 4 8 +NV RW NP RESTART +NONE +0 1 0 +V RW NP RESTART +NONE +0 1 0 + +* +* Privacy Enabled (change requires restart) +* + +WNI_CFG_PRIVACY_ENABLED I 4 8 +V RW NP RESTART +NONE +0 1 0 +V RW NP RESTART +NONE +0 1 0 + +* +* Short Preamble (change requires restart) +* + +WNI_CFG_SHORT_PREAMBLE I 4 8 +V RW NP RESTART +NONE +0 1 1 +V RW NP RESTART +NONE +0 1 1 + +* +* Short Slot time +* This is the operational state of the BSS + +WNI_CFG_SHORT_SLOT_TIME I 4 8 +V RW NP +NONE +0 1 1 +V RW NP +NONE +0 1 0 + + +* +* ACCEPT Short Slot Association only +* +* 1: If AP supports shortSlot, then AP will accept +* association only from stations that supports +* supports short slot +* 0: AP supports shortSlot, but AP will accept association +* from stations regardless of whether station supports +* short slot or long slot +* +WNI_CFG_ACCEPT_SHORT_SLOT_ASSOC_ONLY I 4 9 +V RW NP RESTART +NONE +0 1 0 +V RW NP RESTART +NONE +0 1 0 + + +* +* QOS Enabled (change requires restart) +* + +WNI_CFG_QOS_ENABLED I 4 8 +V RW NP RESTART +NONE +0 1 0 +V RW NP RESTART +NONE +0 1 0 + +* +* HCF Enabled (change requires restart) +* + +WNI_CFG_HCF_ENABLED I 4 8 +V RW NP RESTART +NONE +0 1 0 +V RW NP RESTART +NONE +0 1 0 + +* +* RSN (11i/WPA) Enabled +* + +WNI_CFG_RSN_ENABLED I 4 8 +V RW NP RESTART +NONE +0 1 0 +V RW NP RESTART +NONE +0 1 0 + +* +* Background scanning periodicity (kilo usec) +* + +WNI_CFG_BACKGROUND_SCAN_PERIOD I 4 8 +V RW NP +LIM +0 180000 5000 +V RW NP +LIM +0 18000 5000 + +* +* Max number of Preauthentication +* + +WNI_CFG_MAX_NUM_PRE_AUTH I 4 8 +V RW NP RESTART +NONE +0 256 64 +V RW NP RESTART +NONE +0 256 64 + +* +* Preauthentication Cleanup Timeout (kilo usec) +* + +WNI_CFG_PREAUTH_CLNUP_TIMEOUT I 4 8 +NV XX NP +NONE +0 0 0 +V RW NP +LIM +0 120000 30000 + +* +* Release AID Timeout +* + +WNI_CFG_RELEASE_AID_TIMEOUT I 4 8 +NV XX NP +NONE +0 0 0 +V RW NP +LIM +0 100000 1000 +* +* Heartbeat Threshold +* + +WNI_CFG_HEART_BEAT_THRESHOLD I 4 8 +V RW NP +LIM +0 65535 40 +NV RW NP +NONE +0 65535 40 + +* +* Probe response wait time out after heartbeat failure +* + +WNI_CFG_PROBE_AFTER_HB_FAIL_TIMEOUT I 4 8 +V RW NP +NONE +10 10000 40 +V RW NP +NONE +10 10000 40 + +* +* Manufacturer OUI (from eeprom) +* + +WNI_CFG_MANUFACTURER_OUI S 3 8 +V RO NP +NONE +3 0x0 0xa 0xf5 +V RO NP +NONE +3 0x0 0xa 0xf5 + +* +* Manufacture Name (from eeprom) +* + +WNI_CFG_MANUFACTURER_NAME S 65 8 +V RO NP +NONE +8 0x51 0x75 0x61 0x6c 0x63 0x6f 0x6D 0x6D +V RO NP +NONE +8 0x51 0x75 0x61 0x6c 0x63 0x6f 0x6D 0x6D + +* +* Model Number (from eeprom) +* + +WNI_CFG_MODEL_NUMBER S 33 8 +V RO NP +NONE +6 0x4d 0x4e 0x31 0x32 0x33 0x34 +V RO NP +NONE +6 0x4d 0x4e 0x31 0x32 0x33 0x34 + + + +* +* Model Name (from eeprom) +* WFR4031 +* + +WNI_CFG_MODEL_NAME S 33 8 +V RO NP +NONE +7 0x57 0x46 0x52 0x34 0x30 0x33 0x31 +V RO NP +NONE +7 0x57 0x46 0x52 0x34 0x30 0x33 0x31 + + + + +* +* Manufacture Product Name (from eeprom) +* + +WNI_CFG_MANUFACTURER_PRODUCT_NAME S 33 8 +V RO NP +NONE +6 0x31 0x31 0x6e 0x2D 0x41 0x50 +V RO NP +NONE +6 0x31 0x31 0x6e 0x2D 0x41 0x50 + + +* +* Manufacture Product Version (from eeprom) +* + +WNI_CFG_MANUFACTURER_PRODUCT_VERSION S 33 8 +V RO NP +NONE +6 0x53 0x4e 0x31 0x32 0x33 0x34 +V RO NP +NONE +6 0x53 0x4e 0x31 0x32 0x33 0x34 + +* +* Multi Domain Capability (11d) Enable +* + +WNI_CFG_11D_ENABLED I 4 9 +V RW NP RESTART +NONE +0 1 1 +V RW NP RESTART +NONE +0 1 0 + +* +* per channel Max power transmit (in dBm) +* this parameter correspond to the MAX_COUNTRY_EID +* table of (Channel Number/num channel/max tx power) +* +* There is one table for 5GHz channels and one table for 2.4GHz channels +* + +WNI_CFG_MAX_TX_POWER_2_4 S 128 8 +V RW NP +NONE +3 1 14 20 +V RW NP +NONE +3 1 14 20 + +WNI_CFG_MAX_TX_POWER_5 S 128 8 +V RW NP +NONE +3 36 126 20 +V RW NP +NONE +3 36 126 20 + +* +* Cell size configurations. These are canned configurations for a specified +* cell size. +* +WNI_CFG_NETWORK_DENSITY I 4 9 +V RW NP +HAL +0 3 3 +V RW NP +HAL +0 3 0 + +#ENUM LOW 0 +#ENUM MEDIUM 1 +#ENUM HIGH 2 +#ENUM ADAPTIVE 3 + + +* +* Adaptive Threshold Algorithm +* +WNI_CFG_ADAPTIVE_THRESHOLD_ALGORITHM I 4 9 +V RW NP +HAL +1 2 2 +V RW NP +HAL +1 2 2 + +#ENUM CARRIER 1 +#ENUM CORRELATION 2 + + + +* +* Current TX Antenna +* + +WNI_CFG_CURRENT_TX_ANTENNA I 4 9 +V RW NP +HAL +1 1 1 +V RW NP +HAL +1 2 2 + +* +* Current RX Antenna +* + +WNI_CFG_CURRENT_RX_ANTENNA I 4 9 +V RW NP +HAL +1 2 2 +V RW NP +HAL +1 3 3 + +* +* Current TX Power Level +* + +WNI_CFG_CURRENT_TX_POWER_LEVEL I 4 9 +V RW NP +NONE +0 128 27 +V RW NP +NONE +0 128 27 + + +* + + + + +* Parameter to indicate or not new BSS found +* + +WNI_CFG_NEW_BSS_FOUND_IND I 4 9 +V RW NP +NONE +0 1 0 +V RW NP +NONE +0 1 0 + + +* +* Qualcomm Prop Rates are disabled by default +* +WNI_CFG_PROPRIETARY_RATES_ENABLED I 4 12 +V RW NP RESTART +NONE +0 1 0 +V RW NP RESTART +NONE +0 1 0 + + +* +* AP node Name +* + +WNI_CFG_AP_NODE_NAME S 32 8 +NV RO NP +NONE +0 +V RW NP RESTART +NONE +0 + +* +* Country code (from EEPROM) +* + +WNI_CFG_COUNTRY_CODE S 3 8 +V RW NP +NONE +0 +V RW NP +NONE +3 0x11 0x22 0x33 + +* +* Spectrum Management (11h) enable/disable +* + +WNI_CFG_11H_ENABLED I 4 12 +V RW NP RESTART +NONE +0 1 1 +V RW NP RESTART +NONE +0 1 1 + +* +* Wait for CNF Timeout. CNF include (RE)ASSOC, DISASSOC, AUTH, DEAUTH, +* DUMMY packet +* + +WNI_CFG_WT_CNF_TIMEOUT I 4 12 +V RW NP +NONE +10 3000 1000 +V RW NP +NONE +10 3000 1000 + +* +* Proximity, set it for very short distances +* Proxmity setting is applied via halPhySetNwDensity() +* +* close proximity off = densityOn is true. network density config applies. +* close proximity on = densityOn is false. Don't care about network density config. +* + +WNI_CFG_PROXIMITY I 4 12 +V RW NP +HAL +0 1 0 +V RW NP +HAL +0 1 0 + +#ENUM OFF 0 +#ENUM ON 1 + +* +* Default LOG level +* + +WNI_CFG_LOG_LEVEL I 4 12 +V RW NP +NONE +0 7 4 +V RW NP +NONE +0 7 4 + +* +* OLBC detection timeout +* + +WNI_CFG_OLBC_DETECT_TIMEOUT I 4 12 +V RW NP +NONE +1000 30000 10000 +V RW NP +NONE +1000 30000 10000 + +********************************** +* Protection Enable +* +*LOWER byte for associated stations +*UPPER byte for overlapping stations. +*11g ==> protection from 11g +*11b ==> protection from 11b +*each byte will have the following info +*bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0 +*reserved reserved RIFS Lsig n-GF ht20 11g 11b +********************************** +WNI_CFG_PROTECTION_ENABLED I 4 9 +V RW NP RESTART +LIM +0 0xffff 0xffff +V RW NP RESTART +LIM +0 0xffff 0xffff + +#ENUM FROM_llA 0 +#ENUM FROM_llB 1 +#ENUM FROM_llG 2 +#ENUM HT_20 3 +#ENUM NON_GF 4 +#ENUM LSIG_TXOP 5 +#ENUM RIFS 6 +#ENUM OBSS 7 +#ENUM OLBC_FROM_llA 8 +#ENUM OLBC_FROM_llB 9 +#ENUM OLBC_FROM_llG 10 +#ENUM OLBC_HT20 11 +#ENUM OLBC_NON_GF 12 +#ENUM OLBC_LSIG_TXOP 13 +#ENUM OLBC_RIFS 14 +#ENUM OLBC_OBSS 15 + + +* **************************************** +* +* 11G Protection Enable Always +* Valid only if protection is enabled +* forces uses of protection regardless of legacy stations +* + +WNI_CFG_11G_PROTECTION_ALWAYS I 4 9 +V RW NP RESTART +NONE +0 1 0 +V RW NP RESTART +NONE +0 1 0 + +********************************************* +* Force protection +* 0 : disable protection +* 1 : CTS +* 2 : RTS by threshold (threshold nonzero) +* 3 : dual CTS (not supported right now) +* 4 : RTS (threshold 0) +* 5 : auto + +WNI_CFG_FORCE_POLICY_PROTECTION I 4 9 +V RW NP RESTART +HAL +0 5 5 +V RW NP RESTART +HAL +0 5 5 + +#ENUM DISABLE 0 +#ENUM CTS 1 +#ENUM RTS 2 +#ENUM DUAL_CTS 3 +#ENUM RTS_ALWAYS 4 +#ENUM AUTO 5 + + + + + + +******************************************** +* 11G Short Preamble Enable +* + +WNI_CFG_11G_SHORT_PREAMBLE_ENABLED I 4 9 +V RW NP RESTART +NONE +0 1 0 +V RW NP RESTART +NONE +0 1 0 + +* +* 11G Short Slot Time Enable (change requires restart) +* This is the admin state of short slot support. + +WNI_CFG_11G_SHORT_SLOT_TIME_ENABLED I 4 9 +V RW NP RESTART +NONE +0 1 1 +V RW NP RESTART +NONE +0 1 1 + +* +* Calibration periodicity (minutes) +* + +WNI_CFG_CAL_PERIOD I 4 12 +V RW NP +HAL +2 10 5 +V RW NP +HAL +2 10 5 + +* +* Statistics collection periodicity (seconds) +* + +WNI_CFG_STATS_PERIOD I 4 12 +V RW NP +HAL +1 10 10 +V RW NP +HAL +1 10 10 + +* +* Calibration on/off control +* + +WNI_CFG_CAL_CONTROL I 4 12 +V RW NP +HAL +0 1 0 +V RW NP +HAL +0 1 0 + +#ENUM CAL_ON 0 +#ENUM CAL_OFF 1 + + +* +* Parameter to allow 11g only STAs while operating in 11g mode +* + +WNI_CFG_11G_ONLY_POLICY I 4 12 +V RW NP +NONE +0 1 0 +V RW NP +NONE +0 1 0 + +* +* Packet Classification +* This flag is a bitmask used to indicate which +* frame classifier to be enabled: +* b0: DSCP +* b1: 802.1P +* + +WNI_CFG_PACKET_CLASSIFICATION I 4 12 +V RW NP +HAL +0 3 0 +V RW NP +HAL +0 3 0 + +#ENUM DISABLED 0 +#ENUM DSCP 1 +#ENUM 8021P 2 +#ENUM ALL 3 + +* +* WME Enabled (change requires restart) +* + +WNI_CFG_WME_ENABLED I 4 8 +V RW NP RESTART +NONE +0 1 1 +V RW NP RESTART +NONE +0 1 1 + +* +* ADDTS response timeout (in ms) +* + +WNI_CFG_ADDTS_RSP_TIMEOUT I 4 8 +V RW NP +NONE +0 65535 1000 +V RW NP +NONE +0 65535 1000 + + + * Max SP Length indicates the max number of + * total buffered MSDUs and MMPDUs the WMM AP + * may deliver to WMM STA during any service period + * triggered by WMM STA. + * 1) If AP sends WMM IE with the UAPSD bit 0, max_sp_length=0 + * 2) If WMM STA's all 4 UAPSD flag are set to 0, max_sp_length=0 + * 3) If AP sends WMM IE with UAPSD=1, and at least one of stations + * UAPSD flag is set to 1, then max_sp_length can be set to: + * [b5:b6]=0x00: WMM AP may deliver all buffered frames + * [b5:b6]=0x10: WMM AP may deliver max 2 buffered frames + * [b5:b6]=0x01: WMM AP may deliver max 4 buffered frames + * [b5:b6]=0x11: WMM AP may deliver max 6 buffered frames + +WNI_CFG_MAX_SP_LENGTH I 4 8 +V RW NP +NONE +0 3 0 +V RW NP +NONE +0 3 0 + + +* +* KEEP ALIVE STA Limit Threshold , used in AP to delete the STA +* from Station Table which didn't respond to Probe Response Messages +* + +WNI_CFG_KEEP_ALIVE_STA_LIMIT_THRESHOLD I 4 8 +NV RW NP +NONE +0 32 0 +V RW NP +NONE +0 32 0 + +* +* Parameter that specifies whether to send SSID +* in Probe Response when SSID is suppressed +* + +WNI_CFG_SEND_SINGLE_SSID_ALWAYS I 4 12 +V RW NP +NONE +0 1 0 +V RW NP +NONE +0 1 0 + +* +* WSM Enabled (change requires restart) +* Takes effect only if WME is also enabled +* + +WNI_CFG_WSM_ENABLED I 4 8 +V RW NP +NONE +0 1 0 +V RW NP +NONE +0 1 0 + +* **************************************** +* + + + +* Background Channel List +* Contains pairs of {channelNumber, scanType} +* where scanType = 0 indicates active scan and +* = 1 indicates passive scan +* +* +*WNI_CFG_BACKGROUND_SCAN_LIST S 128 8 +*V RW NP RESTART +*LIM +*60 36 0 40 0 44 0 48 0 52 0 56 0 60 0 64 0 1 0 6 0 11 0 34 0 38 0 42 0 46 0 2 0 3 0 4 0 5 0 7 0 8 0 9 0 10 0 12 0 13 0 14 0 149 0 153 0 157 0 161 0 +*V RW NP RESTART +*LIM +*60 1 0 2 0 3 0 4 0 5 0 6 0 7 0 8 0 9 0 10 0 11 0 12 0 13 0 14 0 34 0 36 0 38 0 40 0 42 0 44 0 46 0 48 0 52 0 56 0 60 0 64 0 149 0 153 0 157 0 161 0 +* + +* **************************************** +* EDCA paramters are contained in profiles - each profile contains +* the parameters [ACM, AIFSN, CWmin, CWmax, TxOp] for four +* access categories (i.e., four sets). Two such sets of four parameters +* make a single profile: One set is used locally by the AP, the other set +* is broadcast for use by stations. +* +* Cwmin and Cwmax are two bytes each, MSB first. So Cwmin of [3 255] is +* equivalent to 0x3ff, i.e. 3*256+255=1023 +* +* The profile to use is selected based on the valus of the profile select param +* See ENUMs below for definitions of profile values +* + +WNI_CFG_EDCA_PROFILE I 4 8 +V RW NP +SCH +0 255 1 +V RW NP +SCH +0 255 1 + +#ENUM ANI 0 +#ENUM WMM 1 +#ENUM TIT_DEMO 2 +#ENUM MAX 3 + +#ENUM ACM_IDX 0 +#ENUM AIFSN_IDX 1 +#ENUM CWMINA_IDX 2 +#ENUM CWMAXA_IDX 4 +#ENUM TXOPA_IDX 6 +#ENUM CWMINB_IDX 7 +#ENUM CWMAXB_IDX 9 +#ENUM TXOPB_IDX 11 +#ENUM CWMING_IDX 12 +#ENUM CWMAXG_IDX 14 +#ENUM TXOPG_IDX 16 + + +* **************************************** +* Profile 0 (Airgo) parameters - AC_BK Local +* ACM, AIFSN, [CWminH, CWminL, CWmaxH, CWmaxL, TxOp]-11A/11B/11G +* + +WNI_CFG_EDCA_ANI_ACBK_LOCAL S 20 8 +V RW NP RESTART +NONE +17 0 7 0 15 3 255 0 0 31 3 255 0 0 15 3 255 0 +V RW NP RESTART +NONE +17 0 7 0 15 3 255 0 0 31 3 255 0 0 15 3 255 0 + +* +* Profile 0 (Airgo) parameters AC_BE Local +* ACM, AIFSN, [CWmin, CWmax, TxOp]-11A/11B/11G +* + +WNI_CFG_EDCA_ANI_ACBE_LOCAL S 20 8 +V RW NP RESTART +NONE +17 0 2 0 15 3 255 100 0 31 3 255 100 0 15 3 255 100 +V RW NP RESTART +NONE +17 0 2 0 15 3 255 100 0 31 3 255 100 0 15 3 255 100 + +* +* Profile 0 (Airgo) parameters AC_VI Local +* ACM, AIFSN, [CWmin, CWmax, TxOp]-11A/11B/11G +* + +WNI_CFG_EDCA_ANI_ACVI_LOCAL S 20 8 +V RW NP RESTART +NONE +17 0 2 0 7 0 15 200 0 15 0 31 188 0 7 0 15 200 +V RW NP RESTART +NONE +17 0 2 0 7 0 15 200 0 15 0 31 188 0 7 0 15 200 + +* +* Profile 0 (Airgo) parameters AC_VO Local +* ACM, AIFSN, [CWmin, CWmax, TxOp]-11A/11B/11G +* + +WNI_CFG_EDCA_ANI_ACVO_LOCAL S 20 8 +V RW NP RESTART +NONE +17 0 2 0 3 0 7 100 0 7 0 15 102 0 3 0 7 100 +V RW NP RESTART +NONE +17 0 2 0 3 0 7 100 0 7 0 15 102 0 3 0 7 100 + +* +* Profile 0 (Airgo) parameters - AC_BK Broadcast +* ACM, AIFSN, [CWmin, CWmax, TxOp]-11A/11B/11G +* + +WNI_CFG_EDCA_ANI_ACBK S 20 8 +V RW NP RESTART +NONE +17 0 7 0 15 3 255 0 0 31 3 255 0 0 15 3 255 0 +V RW NP RESTART +NONE +17 0 7 0 15 3 255 0 0 31 3 255 0 0 15 3 255 0 + +* +* Profile 0 (Airgo) parameters AC_BE Broadcast +* ACM, AIFSN, [CWmin, CWmax, TxOp]-11A/11B/11G +* + +WNI_CFG_EDCA_ANI_ACBE S 20 8 +V RW NP RESTART +NONE +17 0 2 0 15 3 255 100 0 31 3 255 100 0 15 3 255 100 +V RW NP RESTART +NONE +17 0 2 0 15 3 255 100 0 31 3 255 100 0 15 3 255 100 + +* +* Profile 0 (Airgo) parameters AC_VI Broadcast +* ACM, AIFSN, [CWmin, CWmax, TxOp]-11A/11B/11G +* + +WNI_CFG_EDCA_ANI_ACVI S 20 8 +V RW NP RESTART +NONE +17 0 2 0 7 0 15 200 0 15 0 31 188 0 7 0 15 200 +V RW NP RESTART +NONE +17 0 2 0 7 0 15 200 0 15 0 31 188 0 7 0 15 200 + +* +* Profile 0 (Airgo) parameters AC_VO Broadcast +* ACM, AIFSN, [CWmin, CWmax, TxOp]-11A/11B/11G +* + +WNI_CFG_EDCA_ANI_ACVO S 20 8 +V RW NP RESTART +NONE +17 0 2 0 3 0 7 100 0 7 0 15 102 0 3 0 7 100 +V RW NP RESTART +NONE +17 0 2 0 3 0 7 100 0 7 0 15 102 0 3 0 7 100 + + +* **************************************** +* Profile 1 (WME) parameters - AC_BK Local +* ACM, AIFSN, [CWmin, CWmax, TxOp]-11A/11B/11G +* + +WNI_CFG_EDCA_WME_ACBK_LOCAL S 20 8 +V RW NP RESTART +NONE +17 0 7 0 15 3 255 0 0 31 3 255 0 0 15 3 255 0 +V RW NP RESTART +NONE +17 0 7 0 15 3 255 0 0 15 3 255 0 0 15 3 255 0 + + +* +* Profile 1 (WME) parameters AC_BE Local +* ACM, AIFSN, [CWmin, CWmax, TxOp]-11A/11B/11G +* + +WNI_CFG_EDCA_WME_ACBE_LOCAL S 20 8 +V RW NP RESTART +NONE +17 0 3 0 15 0 63 0 0 31 3 255 0 0 15 0 63 0 +V RW NP RESTART +NONE +17 0 3 0 15 0 63 0 0 15 0 63 0 0 15 0 63 0 + +* +* Profile 1 (WME) parameters AC_VI Local +* ACM, AIFSN, [CWmin, CWmax, TxOp]-11A/11B/11G +* + +WNI_CFG_EDCA_WME_ACVI_LOCAL S 20 8 +V RW NP RESTART +NONE +17 0 1 0 7 0 15 94 0 7 0 15 188 0 7 0 15 94 +V RW NP RESTART +NONE +17 0 1 0 7 0 15 94 0 7 0 15 188 0 7 0 15 94 + +* +* Profile 1 (WME) parameters AC_VO Local +* ACM, AIFSN, [CWmin, CWmax, TxOp]-11A/11B/11G +* + +WNI_CFG_EDCA_WME_ACVO_LOCAL S 20 8 +V RW NP RESTART +NONE +17 0 1 0 3 0 7 47 0 3 0 7 102 0 3 0 7 47 +V RW NP RESTART +NONE +17 0 1 0 3 0 7 47 0 3 0 7 102 0 3 0 7 47 + +* +* Profile 1 (WME) parameters - AC_BK Broadcast +* ACM, AIFSN, [CWmin, CWmax, TxOp]-11A/11B/11G +* + +WNI_CFG_EDCA_WME_ACBK S 20 8 +V RW NP RESTART +NONE +17 0 7 0 15 3 255 0 0 15 3 255 0 0 15 3 255 0 +V RW NP RESTART +NONE +17 0 7 0 15 3 255 0 0 15 3 255 0 0 15 3 255 0 + +* +* Profile 1 (WME) parameters AC_BE Broadcast +* ACM, AIFSN, [CWmin, CWmax, TxOp]-11A/11B/11G +* + +WNI_CFG_EDCA_WME_ACBE S 20 8 +V RW NP RESTART +NONE +17 0 3 0 15 3 255 0 0 15 3 255 0 0 15 3 255 0 +V RW NP RESTART +NONE +17 0 3 0 15 3 255 0 0 15 3 255 0 0 15 3 255 0 + +* +* Profile 1 (WME) parameters AC_VI Broadcast +* ACM, AIFSN, [CWmin, CWmax, TxOp]-11A/11B/11G +* + +WNI_CFG_EDCA_WME_ACVI S 20 8 +V RW NP RESTART +NONE +17 0 2 0 7 0 15 94 0 7 0 15 188 0 7 0 15 94 +V RW NP RESTART +NONE +17 0 2 0 7 0 15 94 0 7 0 15 188 0 7 0 15 94 + +* +* Profile 1 (WME) parameters AC_VO Broadcast +* ACM, AIFSN, [CWmin, CWmax, TxOp]-11A/11B/11G +* + +WNI_CFG_EDCA_WME_ACVO S 20 8 +V RW NP RESTART +NONE +17 0 2 0 3 0 7 47 0 3 0 7 102 0 3 0 7 47 +V RW NP RESTART +NONE +17 0 2 0 3 0 7 47 0 3 0 7 102 0 3 0 7 47 + +* +* Radar detector flag enable/disable +* + +WNI_CFG_RDET_FLAG I 4 9 +V RW NP +NONE +0 1 0 +V RW NP +NONE +0 1 0 + +#ENUM ENABLE 1 +#ENUM DISABLE 0 + +WNI_CFG_RADAR_CHANNEL_LIST S 20 8 +V RW NP RESTART +NONE +15 52 56 60 64 100 104 108 112 116 120 124 128 132 136 140 +V RW NP RESTART +NONE +15 52 56 60 64 100 104 108 112 116 120 124 128 132 136 140 + +* +* Local Power Constraint (dBm) +* + +WNI_CFG_LOCAL_POWER_CONSTRAINT I 4 12 +V RW NP RESTART +NONE +0 255 0 +V RW NP RESTART +NONE +0 255 0 + +* ********************************************************* +* +* Admission Control Policy +* used for admitting tspec's when either edca or hcca are in use +* + +WNI_CFG_ADMIT_POLICY I 4 8 +V RW NP RESTART +NONE +0 2 0 +V RW NP +SCH +0 2 0 + +#ENUM ADMIT_ALL 0 +#ENUM REJECT_ALL 1 +#ENUM BW_FACTOR 2 + +* +* Oversubscription factor for admission control +* valid only when admit policy is set to BW_FACTOR +* units are in terms of 1/10th of available bandwidth +* + +WNI_CFG_ADMIT_BWFACTOR I 4 8 +V RW NP RESTART +NONE +0 100 20 +V RW NP +SCH +0 100 20 + +* ********************************************************* +* +* Number of "consecutive" Background Scan Failure needed +* before LIM is forced to perform 1 aggressive background scan +* +WNI_CFG_MAX_CONSECUTIVE_BACKGROUND_SCAN_FAILURE I 4 8 +V RW NP RESTART +NONE +0 256 60 +V RW NP RESTART +NONE +0 256 60 + + +************************************* +* Feature: Channel Bonding +************************************* +* +* Global flag to enable/disable Channel Bonding +* 0 - Disable: Force disable channel bonding for all TC-ids +* 1 - Enable: Force enable channel bonding for all TC-ids +* 2 - no legacy bss: Enable channel bonding if no legacy BSS are present +* 3 - no legacy all: Enable channel bonding if no legacy BSS or devices are present +* 4 - intelligent: Enable channel bonding depending on load level on secondary channel +* +WNI_CFG_CHANNEL_BONDING_MODE I 4 12 +V RW NP RESTART +LIM +0 10 0 +V RW NP RESTART +LIM +0 10 0 + +#ENUM DISABLE 0 +#ENUM ENABLE 1 +#ENUM IF_NO_LEGACY_BSS 2 +#ENUM IF_NO_LEGACY_ALL 3 +#ENUM INTELLIGENT 4 + + +* +* When the channel is 40MHz wide, this CFG indicates +* if the secondary channel is located above (at +* a higher frequency), or located below (at a +* lower frequency). +* +* 0 - There is no secondary channel. The channel is 20Mhz +* 1 - LOWER: Secondary channel 40MHZ is located below the primary channel +* 2 - CENTERED:Secondary channel and primary located at centered +* 3 - HIGHER: Secondary channel 40 MHZ is located above the primary channel +* 4 - 80MHZ_LOW_CENTERED : 20/40MHZ offset LOW 40/80MHZ offset CENTERED +* 5 - 80MHZ_CENTERED_CENTERED : 20/40MHZ offset CENTERED 40/80MHZ offset CENTERED +* 6 - 80MHZ_HIGH_CENTERED : 20/40MHZ offset HIGH 40/80MHZ offset CENTERED +* 7 - 80MHZ_LOW_LOW: 20/40MHZ offset LOW 40/80MHZ offset LOW +* 8 - 80MHZ_HIGH_LOW: 20/40MHZ offset HIGH 40/80MHZ offset LOW +* 9 - 80MHZ_LOW_HIGH: 20/40MHZ offset LOW 40/80MHZ offset HIGH +* 10 - 80MHZ_HIGH_HIGH: 20/40MHZ offset HIGH 40/80MHZ offset HIGH +* +WNI_CFG_CB_SECONDARY_CHANNEL_STATE I 4 12 +V RW NP +NONE +0 10 0 +V RW NP +NONE +0 10 0 + +#ENUM NONE 0 +#ENUM LOWER 1 +#ENUM HIGHER 2 +#ENUM 11AC_20MHZ_LOW_40MHZ_CENTERED 3 +#ENUM 11AC_20MHZ_CENTERED_40MHZ_CENTERED 4 +#ENUM 11AC_20MHZ_HIGH_40MHZ_CENTERED 5 +#ENUM 11AC_20MHZ_LOW_40MHZ_LOW 6 +#ENUM 11AC_20MHZ_HIGH_40MHZ_LOW 7 +#ENUM 11AC_20MHZ_LOW_40MHZ_HIGH 8 +#ENUM 11AC_20MHZ_HIGH_40MHZ_HIGH 9 + +************************************* +* Feature: Dynamic Retry Rates +************************************* +* +* When the short/long retry count reach the +* adaptive_retry_threshold(0), then the retry0 +* template shall be used +* +WNI_CFG_DYNAMIC_THRESHOLD_ZERO I 4 12 +V RW NP +HAL +0 255 2 +V RW NP +HAL +0 255 2 + +* +* When the short/long retry count reach the +* adaptive_retry_threshold(1), then the retry1 +* template shall be used +* +WNI_CFG_DYNAMIC_THRESHOLD_ONE I 4 12 +V RW NP +HAL +0 255 4 +V RW NP +HAL +0 255 4 + +* +* When the short/long retry count reach the +* adaptive_retry_threshold(2), then the retry2 +* template shall be used +* +WNI_CFG_DYNAMIC_THRESHOLD_TWO I 4 12 +V RW NP +HAL +0 255 6 +V RW NP +HAL +0 255 6 + + +* +* Trigger Station Background Scan Flag +* +WNI_CFG_TRIG_STA_BK_SCAN I 4 12 +V RW NP +LIM +0 1 0 +V RW NP +LIM +0 1 1 + +* ********************************************************* +* control of dynamic EDCA parameter profile switching +* +* OOB, we would like to support WMM standard edca profile +* However, when Airgo STA's join the BSS, we would like +* to switch the profile to Airgo high-performance edca parameters +* +* This cfg supports that behaviour. It is used only if 11e qos +* has been enabled and is ignored otherwise. +* +* When set to any value (other than unused), it determines the +* edca profile to switch to when an Airgo STA joins the BSS. +* +* By default, we choose to switch to Airgo profile. +* +* NOTE: This parameter applies only to an AP +* + +WNI_CFG_DYNAMIC_PROFILE_SWITCHING I 4 8 +V RW NP RESTART +NONE +0 255 255 +V RW NP RESTART +NONE +0 255 1 + +#ENUM UNUSED 255 + +* ********************************************************* +* +* Scan control list +* Contains pairs of {channelNumber, activeScanAllowedFlag} +* where scanType = 1 indicates active scan is allowed, and +* = 0 indicates passive scan is used +* If a channel is not on this list, active scan is NOT allowed. So it is +* sufficient to inlude only those channels where active scan is allowed +* on this list. +* +* The list determines only whether active scan is allowed or not; it does not +* determine which type of scan is actually performed. +* + +WNI_CFG_SCAN_CONTROL_LIST S 128 8 +V RW NP RESTART +LIM +112 1 1 2 1 3 1 4 1 5 1 6 1 7 1 8 1 9 1 10 1 11 1 12 1 13 1 14 1 34 1 36 1 38 1 40 1 42 1 44 1 46 1 48 1 50 1 52 0 54 0 56 0 58 0 60 0 62 0 64 0 100 0 104 0 108 0 112 0 116 0 120 0 124 0 128 0 132 0 136 0 140 0 149 1 151 1 153 1 155 1 157 1 159 1 161 1 165 1 240 1 242 1 244 1 246 1 248 1 250 1 252 1 +V RW NP RESTART +LIM +112 1 1 2 1 3 1 4 1 5 1 6 1 7 1 8 1 9 1 10 1 11 1 12 1 13 1 14 1 34 1 36 1 38 1 40 1 42 1 44 1 46 1 48 1 50 1 52 0 54 0 56 0 58 0 60 0 62 0 64 0 100 0 104 0 108 0 112 0 116 0 120 0 124 0 128 0 132 0 136 0 140 0 149 1 151 1 153 1 155 1 157 1 159 1 161 1 165 1 240 1 242 1 244 1 246 1 248 1 250 1 252 1 + + +* **************************************** +* +* MIMO rates enabled (for rate adaptation, to start) +* + +WNI_CFG_MIMO_ENABLED I 4 9 +V RW NP RELOAD +NONE +0 1 1 +V RW NP RELOAD +NIM +0 1 1 + +#ENUM ENABLE 1 +#ENUM DISABLE 0 + + + +* +* BLOCK ACK Enabled (change requires restart) +* change default to ON +* bit 0 ==> delayed BA +* bit 1 ==> immediate BA +WNI_CFG_BLOCK_ACK_ENABLED I 4 8 +V RW NP RESTART +LIM +0 3 0 +V RW NP RESTART +LIM +0 3 0 + +#ENUM DELAYED 0 +#ENUM IMMEDIATE 1 + + +* +*BA Activity check global timer +* +WNI_CFG_BA_ACTIVITY_CHECK_TIMEOUT I 4 7 +V RW NP +HAL +0 65535 1000 +V RW NP +HAL +0 65535 1000 + + +* +* Rx STBC support +* +WNI_CFG_HT_RX_STBC I 4 7 +V RW NP RESTART +LIM +0 3 1 +V RW NP RESTART +LIM +0 3 1 + + +* +* 1. HT capabilities Info: 2 bytes size +* +* Supported channel Width is set to 1 (40 Mhz) +* SM Power Save is disabled. +* GreenField support is enabled. +* Short GI for 20 and 40Mhz is enabled. +* Max AMSDU Size is set to 0(3839 Octets) +* DSSS-CCK Mode is enabled. +* LSIG TXOP Protection is disabled +* Rest of the features are not supported at this moment. +* +* fedc ba98 7654 3210 +* 0000 0001 0010 0000 +* +WNI_CFG_HT_CAP_INFO I 4 10 +V RW NP RESTART +LIM +0 0xffff 0x016c +V RW NP RESTART +LIM +0 0xffff 0x106e + +#ENUM ADVANCE_CODING 0 +#ENUM SUPPORTED_CHAN_WIDTH_SET 1 +#ENUM SM_POWER_SAVE 2 +#ENUM GREEN_FIELD 4 +#ENUM SHORT_GI_20MHZ 5 +#ENUM SHORT_GI_40MHZ 6 +#ENUM TX_STBC 7 +#ENUM RX_STBC 8 +#ENUM DELAYED_BA 10 +#ENUM MAX_AMSDU_SIZE 11 +#ENUM DSSS_CCK_MODE_40MHZ 12 +#ENUM PSMP 13 +#ENUM STBC_CONTROL_FRAME 14 +#ENUM LSIG_TXOP_PROTECTION 15 + +* +* 2. HT Parameters Info: 1 byte size +* +* Max AMPDU Rx Factor is defined using bit #0 and #1 +* MPDU Density is defined using bit #2 thru #4. +* The default values are, +* 7654 3210 +* 0000 0010 --> 2 for RX AMPDU Factor, 0 for MPDU density +* +WNI_CFG_HT_AMPDU_PARAMS I 4 7 +V RW NP RESTART +LIM +0 0xff 0x00 +V RW NP RESTART +LIM +0 0xff 0x02 + +#ENUM MAX_RX_AMPDU_FACTOR 0 +#ENUM MPDU_DENSITY 2 +#ENUM RESERVED 5 + +* +* 3. Supported MCS Set: 16 bytes size +* +* MCS #0-15 and #32 is supported. +* +WNI_CFG_SUPPORTED_MCS_SET S 16 7 +V RW P RESTART +LIM +16 255 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +V RW P RESTART +LIM +16 255 255 0 0 1 0 0 0 0 0 0 0 0 0 0 0 + +* +* 4. Extended HT Capabilities Info: 2 bytes size +* +* Only HTC Support is enabled, rest all features are not +* supported at this moment. +* +* fedc ba98 7654 3210 +* 0000 0100 0000 0000 +* +WNI_CFG_EXT_HT_CAP_INFO I 4 10 +V RW P RESTART +LIM +0 0xffff 0x0400 +V RW P RESTART +LIM +0 0xffff 0x0400 + +#ENUM PCO 0 +#ENUM TRANSITION_TIME 1 +#ENUM RESERVED1 3 +#ENUM MCS_FEEDBACK 8 +#ENUM HTC_SUPPORT 10 +#ENUM RD_RESPONDER 11 +#ENUM RESERVED2 12 + + +* +* 5. Transmit Beam Forming Capabiliries Info: 4 bytes size +* +WNI_CFG_TX_BF_CAP I 4 7 +V RO NP RESTART +LIM +0 0xffffffff 0x00000000 +V RO NP RESTART +LIM +0 0xffffffff 0x00000000 + +* +* 6. Antenna Selection Capabilities: 1 byte size +* +WNI_CFG_AS_CAP I 4 7 +V RW P RESTART +LIM +0 0xff 0x00 +V RW P RESTART +LIM +0 0xff 0x00 + +#ENUM ANTENNA_SELECTION 0 +#ENUM EXPLICIT_CSI_FEEDBACK_TX 1 +#ENUM ANTENNA_INDICES_FEEDBACK_TX 2 +#ENUM EXPLICIT_CSI_FEEDBACK 3 +#ENUM ANTENNA_INDICES_FEEDBACK 4 +#ENUM RX_AS 5 +#ENUM TX_SOUNDING_PPDUS 6 +#ENUM RESERVED 7 + +************************************************** +* Beacon HT (High Through) Info IE +*************************************************** +* +* 3. HT Info Field1: 1 byte size. +* +* Secondary Channel Offset is set to 3 (Down) by default and will +* be updated dynamically by DFS algorithm. +* Channel Width is set to 1 (40 Mhz) +* RIFS Mode is enabled +* Rest of the features are not supported at this moment. +* +* 7654 3210 +* 0000 1111 +* +WNI_CFG_HT_INFO_FIELD1 I 4 10 +V RW NP RESTART +LIM +0 0xff 0x0f +V RW NP RESTART +LIM +0 0xff 0x0f + +#ENUM SECONDARY_CHANNEL_OFFSET 0 +#ENUM RECOMMENDED_CHANNEL_WIDTH 2 +#ENUM RIFS_MODE 3 +#ENUM PSMP_ACCESS_ONLY 4 +#ENUM SERVICE_INTERVAL_GRANULARITY 5 + +* +* 4. HT Info Field2: 2 bytes +* +* Operation mode is set to 0(Pure, GF) to begin with and +* will be updated dynamically. +* 'NonGF Devices present is also set to zero and +* will be updated dynamically. +* +* fedc ba98 7654 3210 +* 0000 0000 0000 0000 +* +WNI_CFG_HT_INFO_FIELD2 I 4 10 +V RW P +LIM +0 0xffff 0x00 +V RW P +LIM +0 0xffff 0x00 + +#ENUM OP_MODE 0 +#ENUM NON_GF_DEVICES_PRESENT 2 +#ENUM RESERVED 3 + +* +* 5. HT Info Field3: 2 bytes +* +* fedc ba98 7654 3210 +* 0000 0000 0000 0000 +* +* LSIG TXOP Full Protection will be zero to begin with and +* updated dynamically. +* Everything else is not supported at this moment. +* +WNI_CFG_HT_INFO_FIELD3 I 4 10 +V RW P +LIM +0 0xffff 0x0000 +V RW P +LIM +0 0xffff 0x0000 + +#ENUM BASIC_STBC_MCS 0 +#ENUM DUAL_STBC_PROTECTION 7 +#ENUM SECONDARY_BEACON 8 +#ENUM LSIG_TXOP_PROTECTION_FULL_SUPPORT 9 +#ENUM PCO_ACTIVE 10 +#ENUM PCO_PHASE 11 +#ENUM RESERVED 12 + +* +* 6. Basic MCS Set: 16 bytes size +* +* For now set this to zero and don't put any restrictions. +* +WNI_CFG_BASIC_MCS_SET S 16 7 +V RW P RESTART +LIM +16 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +V RW P RESTART +LIM +16 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + +* +* 7. Current supported MCS Set: 16 bytes size +* +* For now set this to zero and don't put any restrictions. +* +WNI_CFG_CURRENT_MCS_SET S 16 7 +V RW P RESTART +LIM +16 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +V RW P RESTART +LIM +16 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + + + +* +* Greenfield Capability +* By default Greenfield is enabled +* +WNI_CFG_GREENFIELD_CAPABILITY I 4 7 +V RW NP RESTART +LIM +0 1 0 +V RW NP RESTART +LIM +0 1 0 + +#ENUM ENABLE 1 +#ENUM DISABLE 0 + +* +* Maximum AMPDU Length +* By default set to zero for 3895 octets +* +WNI_CFG_VHT_MAX_MPDU_LENGTH I 4 19 +V RW NP +LIM +0 2 0 +V RW NP +LIM +0 2 0 + +* +* Supported Channel Width Set +* By default set to zero for +* STAs does not support either 160 or 80+80MHz +* +WNI_CFG_VHT_SUPPORTED_CHAN_WIDTH_SET I 4 19 +V RW NP +LIM +0 0 0 +V RW NP +LIM +0 0 0 + +* +* LDPC Coding Capability +* Riva/Pronto supports, default set to 1 +* +WNI_CFG_VHT_LDPC_CODING_CAP I 4 19 +V RW NP +LIM +0 1 0 +V RW NP +LIM +0 1 0 + +* +* Short GI for 80MHz +* Riva/Pronto supports, default set to 1 +* +WNI_CFG_VHT_SHORT_GI_80MHZ I 4 19 +V RW NP +LIM +0 1 1 +V RW NP +LIM +0 1 1 + +* +* Short GI for 160MHz and 80+80MHz +* Riva/Pronto does not supports, default set to 0 +* +WNI_CFG_VHT_SHORT_GI_160_AND_80_PLUS_80MHZ I 4 19 +V RW NP +LIM +0 1 0 +V RW NP +LIM +0 1 0 + +* +* Support for Transmission of 2x1 STBC +* Riva/Pronto does not supports, default set to 0 +* +WNI_CFG_VHT_TXSTBC I 4 19 +V RW NP +LIM +0 1 0 +V RW NP +LIM +0 1 0 + +* +* Support for Reception of PPDUs using STBC +* Riva/Pronto supports, default set to 1 +* +WNI_CFG_VHT_RXSTBC I 4 19 +V RW NP +LIM +0 1 1 +V RW NP +LIM +0 1 1 + +* +* Support for Operating as SU Beamformer +* Riva/Pronto does not supports, default set to 0 +* +WNI_CFG_VHT_SU_BEAMFORMER_CAP I 4 19 +V RW NP +LIM +0 1 0 +V RW NP +LIM +0 1 0 + +* +* Support for Operating as SU Beamformee +* Riva does not support, But Pronto supports, default set to 0 +* +WNI_CFG_VHT_SU_BEAMFORMEE_CAP I 4 19 +V RW NP +LIM +0 1 0 +V RW NP +LIM +0 1 0 + +* +* Compressed Steering Number of Beamformer Antennas Supported +* Riva does not support,Pronto supports, default set to 0 +* +WNI_CFG_VHT_CSN_BEAMFORMEE_ANT_SUPPORTED I 4 19 +V RW NP +LIM +0 4 0 +V RW NP +LIM +0 4 0 + +* +* Number of Sounding Dimensions indicates Number +* of antennas used by the beamformer when sending beamformed transmissions +* Riva/Pronto does not support beamformer, default set to 0 +* +WNI_CFG_VHT_NUM_SOUNDING_DIMENSIONS I 4 19 +V RW NP +LIM +0 3 0 +V RW NP +LIM +0 3 0 + +* +* MU Beamformer Capable +* Riva/Pronto does not support, default set to 0 +* +WNI_CFG_VHT_MU_BEAMFORMER_CAP I 4 19 +V RW NP +LIM +0 1 0 +V RW NP +LIM +0 1 0 + +* +* MU Beamformee Capable +* Riva does not support but pronto supports, default set to 0 +* +WNI_CFG_VHT_MU_BEAMFORMEE_CAP I 4 19 +V RW NP +LIM +0 1 0 +V RW NP +LIM +0 1 0 + +* +* VHT TXOP PS +* Riva does not support but pronto supports, default set to 0 +* +WNI_CFG_VHT_TXOP_PS I 4 19 +V RW NP +LIM +0 1 0 +V RW NP +LIM +0 1 0 + +* +* +HTC-VHT Capable +* Riva does not support but pronto supports, default set to 0 +* +WNI_CFG_VHT_HTC_VHTC_CAP I 4 19 +V RW NP +LIM +0 1 0 +V RW NP +LIM +0 1 0 + +* +* Maximum AMPDU Length exponent range 0-7 +* 2^(13+Max AMPDU Length)-1, default set to 0 +* +WNI_CFG_VHT_AMPDU_LEN_EXPONENT I 4 19 +V RW NP +LIM +0 7 3 +V RW NP +LIM +0 7 3 + +* +* VHT Link Adaptation Capable +* Riva does not support but pronto supports, default set to 0 +* +WNI_CFG_VHT_LINK_ADAPTATION_CAP I 4 19 +V RW NP +LIM +0 3 0 +V RW NP +LIM +0 3 0 + +* +* VHT Rx Antenna Pattern Consistency +* +WNI_CFG_VHT_RX_ANT_PATTERN I 4 19 +V RW NP +LIM +0 1 1 +V RW NP +LIM +0 1 1 + +* +* VHT Tx Antenna Pattern Consistency +* +WNI_CFG_VHT_TX_ANT_PATTERN I 4 19 +V RW NP +LIM +0 1 1 +V RW NP +LIM +0 1 1 + +* +* RxMCS Map is 16 bits, The 2bit Max MCS for n SS field. +* Indicates the maximum MCS that can be received for each +* number of spacial streams. Riva supports MCS 0-9 +* +WNI_CFG_VHT_RX_MCS_MAP I 4 19 +V RW NP +LIM +0 0xFFFF 0xFFFE +V RW NP +LIM +0 0xFFFF 0xFFFE + +* TxMCS Map is 16 bits, The 2bit Max MCS for n SS field. +* Indicates the maximum MCS that can be transmitted for each +* number of spacial streams. +* +WNI_CFG_VHT_TX_MCS_MAP I 4 19 +V RW NP +LIM +0 0xFFFF 0xFFFE +V RW NP +LIM +0 0xFFFF 0xFFFE + +* +* Rx Highest supported data rate. +* +WNI_CFG_VHT_RX_HIGHEST_SUPPORTED_DATA_RATE I 4 19 +V RW NP +LIM +0 780 780 +V RW NP +LIM +0 780 780 + +* +* Tx Highest supported data rate. +* +WNI_CFG_VHT_TX_HIGHEST_SUPPORTED_DATA_RATE I 4 19 +V RW NP +LIM +0 780 780 +V RW NP +LIM +0 780 780 + +* +* Channel center freq Seg1 +* +WNI_CFG_VHT_CHANNEL_CENTER_FREQ_SEGMENT1 I 4 19 +V RW NP +LIM +0 256 0 +V RW NP +LIM +0 256 0 + +* +* Channel center freq Seg2 for 80+80 Mhz +* +WNI_CFG_VHT_CHANNEL_CENTER_FREQ_SEGMENT2 I 4 19 +V RW NP +LIM +0 0 0 +V RW NP +LIM +0 0 0 + +* +* Basic MCS Set +* +WNI_CFG_VHT_BASIC_MCS_SET I 4 19 +V RW NP +LIM +0 0xFFFF 0xFFFE +V RW NP +LIM +0 0xFFFF 0xFFFE + +* +* MU-MIMO Capable STA Count +* +WNI_CFG_VHT_MU_MIMO_CAP_STA_COUNT I 4 19 +V RW NP +LIM +0 4 0 +V RW NP +LIM +0 4 0 + +* +* Spatial Stream Under-Utilization +* +WNI_CFG_VHT_SS_UNDER_UTIL I 4 19 +V RW NP +LIM +0 0 0 +V RW NP +LIM +0 0 0 + +* +* Forty MHZ Utilization +* +WNI_CFG_VHT_40MHZ_UTILIZATION I 4 19 +V RW NP +LIM +0 0 0 +V RW NP +LIM +0 0 0 + +* +* Eighty MHz Utilization +* +WNI_CFG_VHT_80MHZ_UTILIZATION I 4 19 +V RW NP +LIM +0 0 0 +V RW NP +LIM +0 0 0 + +* +* Hundred Sixty MHz Utilization +* +WNI_CFG_VHT_160MHZ_UTILIZATION I 4 19 +V RW NP +LIM +0 0 0 +V RW NP +LIM +0 0 0 + +* +* Maximum AMSDU length +* User can set it to either 3839 or 7935 bytes. +* +WNI_CFG_MAX_AMSDU_LENGTH I 4 7 +V RW NP RESTART +LIM +0 1 0 +V RW NP RESTART +LIM +0 1 0 + +#ENUM SHORT_3839_BYTES 0 +#ENUM LONG_7935__BYTES 1 + + +* +* Minimum MPDU Start Spacing +* Determines the minimum time between the start of adjacent MPDUs within an AMPDU. +* Set to 0 for no restriction +* Set to 1 for 1/4 s +* Set to 2 for 1/2 s +* Set to 3 for 1 s +* Set to 4 for 2 s +* Set to 5 for 4 s +* Set to 6 for 8 s +* Set to 7 for 16 s +* default is set to 0 +WNI_CFG_MPDU_DENSITY I 4 7 +V RW NP RESTART +LIM +0 7 0 +V RW NP RESTART +LIM +0 7 0 + +* +* NUM BUFFERS ADVERTISED +* Defines number of buffers advertised in ADDBA +* +WNI_CFG_NUM_BUFF_ADVERT I 4 7 +V RW NP +LIM +0 128 64 +V RW NP +LIM +0 128 64 + +* +* Maximum Rx AMPDU Factor +* Indicates the maximum length of A-MPDU +* that the STA can receive. +* The Maximum Rx A-MPDU defined by this field is equal to (2 ^ (13 + MAX RX AMPDU FActor))-1 octets. +* Maximum Rx A-MPDU Factor is an integer in the range 0 to 3. +* default is set to 2 for 32K max RX side. +* +WNI_CFG_MAX_RX_AMPDU_FACTOR I 4 7 +V RW NP RESTART +LIM +0 3 3 +V RW NP RESTART +LIM +0 3 3 + + +* +* Short GI support for the reception of 20Mhz packets +* By default it is enabled +* +WNI_CFG_SHORT_GI_20MHZ I 4 7 +V RW NP RESTART +LIM +0 1 1 +V RW NP RESTART +LIM +0 1 1 + + +#ENUM ENABLE 1 +#ENUM DISABLE 0 + + +* +* Short GI support for the reception of 40Mhz packets +* By default it is enabled +* +WNI_CFG_SHORT_GI_40MHZ I 4 7 +V RW NP RESTART +LIM +0 1 0 +V RW NP RESTART +LIM +0 1 1 + + +#ENUM ENABLE 1 +#ENUM DISABLE 0 + + +* +* RIFS support on TX Side +* on RX side it is always supported, it is mandatory +* +WNI_CFG_RIFS_ENABLED I 4 7 +V RW NP RESTART +NONE +0 1 1 +V RW NP RESTART +NONE +0 1 1 + +#ENUM ENABLE 1 +#ENUM DISABLE 0 + + +* ********************************************************* +* +* Power Save Configuration +* +WNI_CFG_MAX_PS_POLL I 4 5 +V RW NP +LIM +0 255 0 +NV RW NP +LIM +0 255 0 + + +WNI_CFG_NUM_BEACON_PER_RSSI_AVERAGE I 4 5 +V RW NP +LIM +1 20 20 +NV RW NP +LIM +1 20 20 + + +* +* Period for which Firmware will collect the +* RSSI stats. Its in units of beacon interval. +* Rssi Filter period should always be >= +* the num_beacon_per_rssi_average. +* +WNI_CFG_RSSI_FILTER_PERIOD I 4 5 +V RW NP +LIM +0 255 5 +NV RW NP +LIM +0 255 5 + + +WNI_CFG_MIN_RSSI_THRESHOLD I 4 5 +V RW NP +LIM +0 10 10 +NV RW NP +LIM +0 10 10 + + +WNI_CFG_NTH_BEACON_FILTER I 4 5 +V RW NP +LIM +0 255 10 +NV RW NP +LIM +0 255 10 + + +WNI_CFG_BROADCAST_FRAME_FILTER_ENABLE I 4 5 +V RW NP +LIM +0 1 0 +NV RW NP +LIM +0 1 0 + + +WNI_CFG_SCAN_IN_POWERSAVE I 4 5 +V RW NP +LIM +0 1 1 +V RW NP +LIM +0 1 1 + + +* +* Ignore DTIM support - If disabled(value=0), HAL will +* try to align the Listen Interval to the DTIM +* period and the following rules will be applied: +* 1) If LI=DTIM, then set LI=DTIM +* 2) If LIDTIM, then set LI=DTIM +* +WNI_CFG_IGNORE_DTIM I 4 5 +V RW NP +NONE +0 1 0 +V RW NP +NONE +0 1 0 + +* ********************************************************* +* +* WoWLAN Configuration The following configurations +* are valid only when magicPktEnable = 1. +* +WNI_CFG_WOWLAN_UCAST_PATTERN_FILTER_ENABLE I 4 5 +V RW NP +NONE +0 1 1 +NV RW NP +NONE +0 1 0 + + +WNI_CFG_WOWLAN_CHANNEL_SWITCH_ENABLE I 4 5 +V RW NP +NONE +0 1 1 +NV RW NP +NONE +0 1 0 + + +WNI_CFG_WOWLAN_DEAUTH_ENABLE I 4 5 +V RW NP +NONE +0 1 1 +NV RW NP +NONE +0 1 0 + + +WNI_CFG_WOWLAN_DISASSOC_ENABLE I 4 5 +V RW NP +NONE +0 1 1 +NV RW NP +NONE +0 1 0 + + +WNI_CFG_WOWLAN_MAX_MISSED_BEACON I 4 5 +V RW NP +NONE +0 65535 40 +NV RW NP +NONE +0 65535 40 + +* +* Timeout value in units of us. It requests +* hardware to unconditionally wake up after +* it has stayed in WoWLAN mode for some time. +* +WNI_CFG_WOWLAN_MAX_SLEEP_PERIOD I 4 5 +V RW NP +NONE +0 65535 65535 +NV RW NP +NONE +0 65535 65535 + + +* +* BA timeout in TUs, set to 1 minute = approx 58593 TUs +* 16 bit wide +* +WNI_CFG_BA_TIMEOUT I 4 7 +V RW NP RESTART +HAL +0 0xffff 0 +V RW NP +HAL +0 0xffff 0 + + +* +* This threshold is registered with a traffic monitoring interface (probably HAL), +* on a per-STA, per-TID basis. Once this threshold has been reached, +* HAL will indicate to PE that the threshold has been reached for that TID. +* PE is then free to negotiate a BA session for that peer +* defaults to 128 +* 16 bit wide +* +WNI_CFG_BA_THRESHOLD_HIGH I 4 7 +V RW NP RESTART +HAL +0 0xffff 0x80 +V RW NP +HAL +0 0xffff 0x80 + + +* +* MAX BA Buffers to be allocated. +* This count is system wide. +* 16 bit wide +* +WNI_CFG_MAX_BA_BUFFERS I 4 7 +V RW NP RESTART +HAL +0 2560 2560 +V RW NP +HAL +0 2560 2560 + + +* +* MAX BA Sessions. +* This count is system wide. +* 16 bit wide +* +WNI_CFG_MAX_BA_SESSIONS I 4 7 +V RW NP RESTART +HAL +0 64 40 +V RW NP +HAL +0 64 40 + + +* +* BA setup based on Traffic +* +WNI_CFG_BA_AUTO_SETUP I 4 7 +V RW NP RESTART +HAL +0 1 1 +V RW NP RESTART +HAL +0 1 1 + +#ENUM ENABLE 1 +#ENUM DISABLE 0 + +* +* Decline an ADDBA Request +* +WNI_CFG_ADDBA_REQ_DECLINE I 4 7 +V RW NP RESTART +LIM +0 0xff 0 +V RW NP RESTART +LIM +0 0xff 0 + +* +* Valid Channel List +* + +WNI_CFG_BG_SCAN_CHANNEL_LIST S 100 8 +V RW NP +LIM +55 36 40 44 48 52 56 60 64 1 6 11 34 38 42 46 2 3 4 5 7 8 9 10 12 13 14 100 104 108 112 116 120 124 128 132 136 140 149 151 153 155 157 159 161 50 54 58 62 240 242 244 246 248 250 252 +V RW NP +LIM +55 36 40 44 48 52 56 60 64 1 6 11 34 38 42 46 2 3 4 5 7 8 9 10 12 13 14 100 104 108 112 116 120 124 128 132 136 140 149 151 153 155 157 159 161 50 54 58 62 240 242 244 246 248 250 252 + + +* +* AMPDU default TX medium Time (in us) +* +WNI_CFG_MAX_MEDIUM_TIME I 4 8 +V RW NP +HAL +0 65535 2048 +V RW NP +HAL +0 65535 2048 + + +* +* Maximum number of MPDUs in single A-MPDU. +* +WNI_CFG_MAX_MPDUS_IN_AMPDU I 4 8 +V RW NP +HAL +0 65535 64 +V RW NP +HAL +0 65535 64 + + +* +* Auto BSSID - When set, BSSID is generated automatically in IBSS, else BSSID in cfg will be used. +* + +WNI_CFG_IBSS_AUTO_BSSID I 4 0 +V RW NP +NONE +0 1 1 +NV RW NP +NONE +0 1 1 + +* +* Include Additional IEs in probe request. +* +WNI_CFG_PROBE_REQ_ADDNIE_FLAG I 4 0 +V RW NP +NONE +0 1 0 +V RW NP +NONE +0 1 0 + +* +* Include Additional IE in probe request. +* +WNI_CFG_PROBE_REQ_ADDNIE_DATA S 255 0 +V RW NP +NONE +0 0 +V RW NP +NONE +0 0 + +* +* Include Additional IEs in probe response. +* +WNI_CFG_PROBE_RSP_ADDNIE_FLAG I 4 0 +V RW NP +NONE +0 1 0 +V RW NP +NONE +0 1 0 + +* +* Include Additional IE in probe response. +* +WNI_CFG_PROBE_RSP_ADDNIE_DATA1 S 255 0 +V RW NP +NONE +0 0 +V RW NP +NONE +0 0 + +* +* Include Additional IE in probe response. +* +WNI_CFG_PROBE_RSP_ADDNIE_DATA2 S 255 0 +V RW NP +NONE +0 0 +V RW NP +NONE +0 0 + +* +* Include Additional IE in probe response. +* +WNI_CFG_PROBE_RSP_ADDNIE_DATA3 S 255 0 +V RW NP +NONE +0 0 +V RW NP +NONE +0 0 + +* +* Include Additional IEs in assoc response. +* +WNI_CFG_ASSOC_RSP_ADDNIE_FLAG I 4 0 +V RW NP +NONE +0 1 0 +V RW NP +NONE +0 1 0 + +* +* Include Additional IE in assoc response. +* +WNI_CFG_ASSOC_RSP_ADDNIE_DATA S 255 0 +V RW NP +NONE +0 0 +V RW NP +NONE +0 0 + +* +* Include Additional P2P IEs in probe request. +* +WNI_CFG_PROBE_REQ_ADDNP2PIE_FLAG I 4 0 +V RW NP +NONE +0 1 0 +V RW NP +NONE +0 1 0 + +* +* Include Additional P2P IE in probe request. +* +WNI_CFG_PROBE_REQ_ADDNP2PIE_DATA S 255 0 +V RW NP +NONE +0 0 +V RW NP +NONE +0 0 + + +* +* Include Additional IEs in probe response/beacon. +* +WNI_CFG_PROBE_RSP_BCN_ADDNIE_FLAG I 4 0 +V RW NP +LIM +0 1 0 +V RW NP +LIM +0 1 0 + + +* +* Include Additional IEs in probe response/beacon. +* +WNI_CFG_PROBE_RSP_BCN_ADDNIE_DATA S 255 0 +V RW NP +LIM +0 0 +V RW NP +LIM +0 0 + + +* +* wpsApEnable and wpsStaEnable is specified in here +* wpsApEnable is bit #0 and wpsStaEnable is bit #1 +* +WNI_CFG_WPS_ENABLE I 4 7 +V RW NP +LIM +0 0xff 0 +V RW NP +LIM +0 0xff 0 + +#ENUM AP 1 +#ENUM STA 2 + +WNI_CFG_WPS_STATE I 4 7 +V RW NP +LIM +0 0xff 1 +V RW NP +LIM +0 0xff 1 + +* +* TRUE => include this information in Probe Requests, FALSE => omit it +* + +WNI_CFG_WPS_PROBE_REQ_FLAG I 4 7 +V RW NP +LIM +0 1 0 +V RW NP +LIM +0 1 0 + +* +* Wi-Fi Protected Setup Version +* +* This one-byte field is broken into a four-bit major +* part using the top MSBs and four-bit minor part +* using the LSBs. As an example, version 3.2 would be 0x32. +* + +WNI_CFG_WPS_VERSION I 4 7 +V RW NP +LIM +0 0xff 0x10 +V RW NP +LIM +0 0xff 0x10 + +* +* Wi-Fi Protected Setup Request type +* 0x00: Enrollee, Info only +* 0x01: Enrollee, open 802.1X +* 0x02: Registrar +* 0x03: WLAN Manager Registrar + +WNI_CFG_WPS_REQUEST_TYPE I 4 7 +V RW NP +LIM +0 0xff 0x00 +V RW NP +LIM +0 0xff 0x03 + +* Configuration Method(s) +* +* The Config Methods Data component lists the configuration methods +* the Enrollee or Registrar supports. The list is a bitwise OR of +* values from the table below. In addition to Config Methods, APs and +* STAs that support the UPnP Management Interface must support the +* Permitted Config Methods attribute, which is used to control the +* Config Methods that are enabled on that AP. +* +* Value Hardware Interface +* 0x0001 USBA (Flash Drive) +* 0x0002 Ethernet +* 0x0004 Label +* 0x0008 Display +* 0x0010 External NFC Token +* 0x0020 Integrated NFC Token +* 0x0040 NFC Interface +* 0x0080 PushButton +* 0x0100 Keypad +* +* The bottom 16 bits contain the configuration method(s) when acting +* as an Enrollee, and the top 16 when acting as a Registrar. +* +* QNE-TODO: Merge this with the inappropriately named +* 'WNI_CFG_WSC_AP_CFG_METHOD'-- this one can serve both puposes. +* + +WNI_CFG_WPS_CFG_METHOD I 4 7 +V RW NP +LIM +0 0xFFFFFFFF 0x00000008 +V RW NP +LIM +0 0xFFFFFFFF 0x018c018e + +* UUID +* The universally unique identifier (UUID) element is a unique +* GUID generated by the Enrollee or Registrar. It uniquely identifies +* an operational device and should survive reboots and resets. The +* UUID is provided in binary format. If the device also supports UPnP, +* then the UUID corresponds to the UPnP UUID. +* +* QNE-TODO: Re-name their cfg from 'WNI_CFG_UUID' + +WNI_CFG_WPS_UUID S 16 8 +V RW NP +LIM +6 0xa 0xb 0xc 0xd 0xe 0xf +V RW NP +LIM +6 0xa 0xb 0xc 0xd 0xe 0xf + +************************************************************************ +* The following cfgs contains the primary type of the device. Its format +* follows: +* +* 0 1 2 3 +* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +* | Attribute ID | Length | +* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +* | Category ID | OUI (1-2) | +* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +* | OUI (3-4) | Sub Category ID | +* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +* +* Vendor-specific sub-categories are designated by setting the OUI to the +* value associated with that vendor. Note that a four-byte subdivided OUI +* is used. For the predefined values, the Wi-Fi Alliance OUI of 00 50 F2 04 +* is used. The predefined values for Category ID and Sub Category ID are +* provided in the next table. There is no way to indicate a vendor-specific +* main device category. The OUI applies only to the interpretation of the +* Sub Category. If a vendor does not use sub categories for their OUI, the +* three-byte OUI occupies the first three bytes of the OUI field and the +* fourth byte is set to zero. +* +* Category ID Value Sub Category ID Value +* Computer 1 PC 1 +* Server 2 +* Media Center 3 +* Input Device 2 +* Printers, Scanners, Printer 1 +* Faxes and Copiers 3 Scanner 2 +* Camera 4 Digital Still Camera 1 +* Storage 5 NAS 1 +* Network AP 1 +* Infrastructure 6 Router 2 +* Switch 3 +* Displays 7 Television 1 +* Electronic Picture Frame 2 +* Projector 3 +* Multimedia Devices 8 DAR 1 +* PVR 2 +* MCX 3 +* Gaming Devices 9 Xbox 1 +* Xbox360 2 +* Playstation 3 +* Telephone 10 Windows Mobile 1 +* +************************************************************************ + +* QNE-TODO: Rename their cfg from 'WNI_CFG_PRIM_DEVICE_CATEGORY' +WNI_CFG_WPS_PRIMARY_DEVICE_CATEGORY I 4 7 +V RW NP +LIM +0 0xffff 1 +V RW NP +LIM +0 0xffff 6 + +* QNE-TODO: Rename their cfg from 'WNI_CFG_PRIM_DEVICE_OUI' +WNI_CFG_WPS_PIMARY_DEVICE_OUI I 4 7 +V RW NP +LIM +0 0xffffffff 0x0050f204 +V RW NP +LIM +0 0xffffffff 0x0050f204 + +* QNE-TODO: Rename their cfg from 'WNI_CFG_PRIM_DEVICE_SUB_CATEGORY' +WNI_CFG_WPS_DEVICE_SUB_CATEGORY I 4 7 +V RW NP +LIM +0 0xffff 1 +V RW NP +LIM +0 0xffff 1 + +* Association State +* + +* The Association State component shows the configuration and previous +* association state of the wireless station when sending a Discovery +* request. +* +* Association State Description +* 0 Not Associated +* 1 Connection Success +* 2 Configuration Failure +* 3 Association Failure +* 4 IP Failure + +WNI_CFG_WPS_ASSOCIATION_STATE I 4 7 +V RW NP +LIM +0 0xffff 0 +V RW NP +LIM +0 0xffff 0 + +* Configuration Error +* +* The Configuration Error component shows the result of the device +* attempting to configure itself and to associate with the WLAN. +* +* Configuration Error Description +* 0 No Error +* 1 OOB Interface Read Error +* 2 Decryption CRC Failure +* 3 2.4 channel not supported +* 4 5.0 channel not supported +* 5 Signal too weak +* 6 Network auth failure +* 7 Network association failure +* 8 No DHCP response +* 9 Failed DHCP config +* 10 IP address conflict +* 11 Couldnt connect to Registrar +* 12 Multiple PBC sessions detected +* 13 Rogue activity suspected +* 14 Device busy +* 15 Setup locked +* 16 Message Timeout +* 17 Registration Session Timeout +* 18 Device Password Auth Failure +* +* The Device busy error is returned if the sending device is unable to +* respond to the request due to some internal conflict or resource +* contention issue. For example, if a device is only capable of +* performing a single instance of the Registration Protocol at a time, +* it may return this error in response to attempts to start another +* instance in the middle of an active session. + +WNI_CFG_WPS_CONFIGURATION_ERROR I 4 7 +V RW NP +LIM +0 0xffff 0 +V RW NP +LIM +0 0xffff 0 + +* Device Password ID +* + +* This attribute is used to identify a device password. There are six +* predefined values and ten reserved values. If the Device Password ID is +* Default, the Enrollee should use its PIN password (from the label or +* display). This password may correspond to the label, display, or a +* user-defined password that has been configured to replace the original +* device password. +* +* User-specified indicates that the user has overridden the password with a +* manually selected value. Machine-specified indicates that the original +* PIN password has been overridden by a strong, machinegenerated device +* password value. The Rekey value indicates that the device's 256-bit +* rekeying password will be used. The PushButton value indicates that the +* PIN is the all-zero value reserved for the PushButton Configuration +* method. +* +* The Registrar-specified value indicates a PIN that has been obtained from +* the Registrar (via a display or other out-of-band method). This value may +* be further augmented with the optional 'Identity' attribute in M1. This +* augmentation is useful when multiple predefined UserID/PIN pairs have been +* established by a Registrar such as an authenticator used for Hotspot +* access. If the Device Password ID in M1 is not one of the predefined or +* reserved values, it corresponds to a password given to the Registrar as an +* OOB Device Password. +* +* Value Description +* 0x0000 Default (PIN) +* 0x0001 User-specified +* 0x0002 Machine-specified +* 0x0003 Rekey +* 0x0004 PushButton +* 0x0005 Registrar-specified +* 0x0006 - 0x000F Reserved' +* + +WNI_CFG_WPS_DEVICE_PASSWORD_ID I 4 7 +V RW NP +LIM +0 0xffffffff 0 +V RW NP +LIM +0 0xffffffff 0 + +* +* WPS Association +* +* Wi-Fi Protected Setup requires a prospective enrollee to associate to +* an AP in the network in which the STA would like to enroll. Once +* associated, the enrollment takes place over an EAPOL conversation +* (there's actually a new EAP method: EAP-WSC). The STA would +* presumably send an EAPOL-Start over his new link, to which the AP +* would respond with an EAP Identity Request. When the STA sends back +* "WSC-Enrollee-1" as his EAP Identity, the AP knows that he's got a WPS +* supplicant on his hands, and proceeds to talk EAP-WSC. +* +* Toward the end of the specification's development, a problem came up. +* Microsoft's EAP supplicant on XP SP1 & SP2 will send an EAPOL-Start, +* no matter what. Even if the AP is beaconing WPA-PSK, say, the MS +* supplicant will send an EAPOL-Start. If it receives an EAP Identity +* Request in return, it decides that the AP is really using 802.1x +* authentication, and proceeds on that assumption. +* +* Now, imagine an AP that is configured for WPA-PSK, and is WPS-capable. +* It receives an association request from some STA, and then sees an +* EAPOL-Start from the newly joined STA. It naturally sends back an EAP +* Identity Request to see if the new STA wants to talk EAP-WSC. On +* Windows XP SP1 & SP2, the supplicant will take that to mean that this +* AP is using 802.1x authentication, and will never let the user provide +* the PSK. Consequently, WZC will never be able to associate with this +* AP. +* +* Naturally, Microsoft's solution was to have the world change to +* accommodate them. After a lot of back & forth, the WFA decided on the +* following change to the WPS spec: when associating for purposes of WPS +* enrollment, "A client that intends to use the EAP-WSC method with a +* WSC enabled AP may include a WSC IE in its 802.11 (re)association +* request. If a WSC IE is present in the (re)association request, the AP +* shall engage in EAP-WSC with the station and must not attempt other +* security handshake. If the client does not include a WSC IE in its +* 802.11 (re)association request, it must send its 802.11 Authentication +* frame with Authentication set to open and an 802.11 Association +* Request frame without an RSN IE or SSN IE, regardless of the network +* type that is hosted by the AP. On successful association, the client +* will then send an EAPOL-Start to the AP and wait for +* EAP-Request/Identity. When the client receives an EAP Request/ +* Identity, it will respond with EAP-Response/Identity and the +* appropriate WSC string to indicate if it is an Enrollee or Registrar. +* ' +* +* This configuration variable contains a bitvector: +* +* 0x0001 Incldue the WPS Information Element in Assoc Request frames +* 0x0002 Elide the the WPA and RSN Information Elements from the +* Assoc Request frame +* + +WNI_CFG_WPS_ASSOC_METHOD I 4 7 +V RW NP +LIM +0 0xffff 0 +V RW NP +LIM +0 0xffff 0 + +* +* Low gain override +* + +WNI_CFG_LOW_GAIN_OVERRIDE I 4 9 +V RW NP +HAL +0 1 0 +V RW NP +HAL +0 1 0 + +* +* Listen Mode Enable/Disable +* + +WNI_CFG_ENABLE_PHY_AGC_LISTEN_MODE I 4 7 +V RW NP +HAL +0 128 128 +V RW NP +HAL +0 128 128 + +* +* On chip reodering polling threshold +* + +WNI_CFG_RPE_POLLING_THRESHOLD I 4 2 +V RW NP +HAL +0 65535 10 +V RW NP +HAL +0 65535 10 + +* +* On chip reodering aging threshold for AC0 +* + +WNI_CFG_RPE_AGING_THRESHOLD_FOR_AC0_REG I 4 2 +V RW NP +HAL +0 65535 30 +V RW NP +HAL +0 65535 30 + +* +* On chip reodering aging threshold for AC1 +* + +WNI_CFG_RPE_AGING_THRESHOLD_FOR_AC1_REG I 4 2 +V RW NP +HAL +0 65535 30 +V RW NP +HAL +0 65535 30 + +* +* On chip reodering aging threshold for AC2 +* + +WNI_CFG_RPE_AGING_THRESHOLD_FOR_AC2_REG I 4 2 +V RW NP +HAL +0 65535 30 +V RW NP +HAL +0 65535 30 + +* +* On chip reodering aging threshold for AC3 +* + +WNI_CFG_RPE_AGING_THRESHOLD_FOR_AC3_REG I 4 2 +V RW NP +HAL +0 65535 30 +V RW NP +HAL +0 65535 30 + +* +* Number of On-Chip reorder sessions +* + +WNI_CFG_NO_OF_ONCHIP_REORDER_SESSIONS I 4 2 +V RW NP +HAL +0 2 1 +V RW NP +HAL +0 2 1 + + +* +* Single RC for all TID +* + +WNI_CFG_SINGLE_TID_RC I 4 7 +V RW NP +NONE +0 1 1 +V RW NP +NONE +0 1 1 + +* +* RRM Enabled +* + +WNI_CFG_RRM_ENABLED I 4 8 +V RW NP +NONE +0 1 0 +V RW NP +NONE +0 1 0 + +* +* RRM measurement max duration. Section 11.10.3 802.11k-2008. +* Max Duration represented as maxDuration inTUs = 2^(*WNI_CFG_RRM_IN_CHAN_MAX - 4) * bcnIntvl +* Operating channel max measurement duration. +* + +WNI_CFG_RRM_OPERATING_CHAN_MAX I 4 8 +V RW NP +NONE +0 8 0 +V RW NP +NONE +0 8 0 + +* +* Non-Operating channel max measurement duration. +* + +WNI_CFG_RRM_NON_OPERATING_CHAN_MAX I 4 8 +V RW NP +NONE +0 8 0 +V RW NP +NONE +0 8 0 + +* +* TX power control feature +* + +WNI_CFG_TX_PWR_CTRL_ENABLE I 4 8 +V RW NP +NONE +0 1 1 +V RW NP +NONE +0 1 1 + +* +* MCAST BCAST filter Setting +* 0: No filter, 1: Block Mcast, 2: Block Bcast, 3: Block Mcast and Bcast +* + +WNI_CFG_MCAST_BCAST_FILTER_SETTING I 4 7 +V RW NP +HAL +0 3 0 +V RW NP +HAL +0 3 0 + +* +* BTC DHCP No of Bt slots to block +* +WNI_CFG_BTC_DHCP_BT_SLOTS_TO_BLOCK I 4 7 +V RW NP +HAL +0 0xFF 0 +V RW NP +HAL +0 0xFF 0 + +* +* Config parameter to Enable/Disable Dynamic PS-Poll mechanism +* 0: Disable, x: FW will send x number of NULL frames before switching to PS-Poll mexhanism +* +WNI_CFG_DYNAMIC_PS_POLL_VALUE I 4 7 +V RW NP +HAL +0 0xFF 0 +V RW NP +HAL +0 0xFF 0 + +* +* PS Data InActivity Timeout (TU) +* + +WNI_CFG_PS_NULLDATA_AP_RESP_TIMEOUT I 4 7 +V RW NP +HAL +0 80 0 +NV RW NP +NONE +0 80 0 + +* +* Config parameter to Enable/Disable Telescopic Bcn Wakeups +* 0: Disable, 1: Enable +* + +WNI_CFG_TELE_BCN_WAKEUP_EN I 4 7 +V RW NP +HAL +0 1 0 +V RW NP +HAL +0 1 0 + + +* +* Config parameter for Transient LI +* 0: Disable, x: Transient LI +* + +WNI_CFG_TELE_BCN_TRANS_LI I 4 7 +V RW NP +HAL +0 7 3 +V RW NP +HAL +0 7 3 + +* +* Config parameter for Idle bcns for Transient LI +* x: Num Idle bcns before switch to trans LI +* + +WNI_CFG_TELE_BCN_TRANS_LI_IDLE_BCNS I 4 7 +V RW NP +HAL +5 255 10 +V RW NP +HAL +5 255 10 + +* +* Config parameter for Max LI +* 0: Disable, x: Max LI +* + +WNI_CFG_TELE_BCN_MAX_LI I 4 7 +V RW NP +HAL +0 7 5 +V RW NP +HAL +0 7 5 + +* +* Config parameter for Idle bcns for max LI +* x: Num Idle bcns before switch to max LI +* + +WNI_CFG_TELE_BCN_MAX_LI_IDLE_BCNS I 4 7 +V RW NP +HAL +5 255 15 +V RW NP +HAL +5 255 15 + +* +* BTC DHCP No of Bt sub interval during DHCP +* +WNI_CFG_BTC_A2DP_DHCP_BT_SUB_INTERVALS I 4 7 +V RW NP +HAL +0 0xFF 7 +V RW NP +HAL +0 0xFF 7 + +* +* Infra STA mode Keep alive period (in secs) for +* sending keep alive (Qos)Null frames to the AP. +* 0 = disabled. Recommended values is 30 secs +* +WNI_CFG_INFRA_STA_KEEP_ALIVE_PERIOD I 4 7 +V RW NP +HAL +0 1000 0 +V RW NP +HAL +0 1000 0 + +* Limit on number of associated stations +* (applies to peer stations in IBSS, SoftAP, BT-AMP AP, & P2P-GO modes) +* + +WNI_CFG_ASSOC_STA_LIMIT I 4 8 +V RW NP +LIM +1 32 10 +V RW NP +LIM +1 32 10 + +* +* SAP channel select start channel number +* +WNI_CFG_SAP_CHANNEL_SELECT_START_CHANNEL I 4 7 +V RW NP +NONE +1 0xFC 1 +V RW NP +NONE +1 0xFC 1 + +* +* SAP channel select end channel number +* +WNI_CFG_SAP_CHANNEL_SELECT_END_CHANNEL I 4 7 +V RW NP +NONE +1 0xFC 11 +V RW NP +NONE +1 0xFC 11 + +* +* SAP channel select operating band +* 0- 2.4GHZ / 1- Low 5GHZ /2-MID /3-HIGH/4-Japan4.9GHZ +* +WNI_CFG_SAP_CHANNEL_SELECT_OPERATING_BAND I 4 7 +V RW NP +NONE +0 0x5 0 +V RW NP +NONE +0 0x5 0 + +* +* Softap data available poll period (in milliseconds) for +* queueing (Qos)Null frames to the station if there +* is no data available and PS-Poll/Trigger frame is pending. +* 0 = disabled. Recommended values is 5ms +* +WNI_CFG_AP_DATA_AVAIL_POLL_PERIOD I 4 8 +V RW NP +NONE +0 65535 5 +V RW NP +NONE +0 65535 5 + +* +* Close loop power control will be enabled if value is set to 1 +* +* +* +WNI_CFG_ENABLE_CLOSE_LOOP I 4 0 +V RW NP +NONE +0 1 0 +V RW NP +NONE +0 1 0 + +* +* LTE Coexistence will be enabled if value is set to 1 +* +* +* +WNI_CFG_ENABLE_LTE_COEX I 4 0 +V RW NP +NONE +0 1 0 +V RW NP +NONE +0 1 0 + +* +* AP Keep Alive Timeout (TU) +* +WNI_CFG_AP_KEEP_ALIVE_TIMEOUT I 4 7 +V RW NP +HAL +1 65535 20 +V RW NP +HAL +1 65535 20 + +* +* GO Keep Alive Timeout (TU) +* +WNI_CFG_GO_KEEP_ALIVE_TIMEOUT I 4 7 +V RW NP +HAL +1 65535 20 +V RW NP +HAL +1 65535 20 + +* +* MC Addr List power control will be enabled if value is set to 1 +* +* +* +WNI_CFG_ENABLE_MC_ADDR_LIST I 4 0 +V RW NP +HAL +0 1 0 +V RW NP +HAL +0 1 0 + +* +* UC Filter will be enabled if value is set to 1 +* +* +* +WNI_CFG_ENABLE_UC_FILTER I 4 0 +V RW NP +HAL +0 1 0 +V RW NP +HAL +0 1 0 + +* +* Low Power Image Transition will be enabled if value is set to 1 +* +* +* +WNI_CFG_ENABLE_LPWR_IMG_TRANSITION I 4 0 +V RW NP +NONE +0 1 0 +V RW NP +NONE +0 1 0 + +* +* MCC Adaptive Scheduler will be enabled if value is set to 1 +* +* +* +WNI_CFG_ENABLE_MCC_ADAPTIVE_SCHED I 4 0 +V RW NP +NONE +0 1 0 +V RW NP +NONE +0 1 0 +* +*Disable LDPC in STA mode when AP is TXBF capable +* +* +* +WNI_CFG_DISABLE_LDPC_WITH_TXBF_AP I 4 0 +V RW NP +NONE +0 1 0 +V RW NP +NONE +0 1 0 + +* +* AP Link Monitor Timeout (TU) +* +WNI_CFG_AP_LINK_MONITOR_TIMEOUT I 4 7 +V RW NP +HAL +1 255 3 +V RW NP +HAL +1 255 3 + +* +*TDLS Station's UAPSD MASK Configuration +* +* +* +WNI_CFG_TDLS_QOS_WMM_UAPSD_MASK I 4 7 +V RW NP +LIM +0 15 0 +V RW NP +LIM +0 15 0 +* +*TDLS Stations Buffer STA Capability +* +* +* +WNI_CFG_TDLS_BUF_STA_ENABLED I 4 7 +V RW NP +LIM +0 1 0 +V RW NP +LIM +0 1 0 +*TDLS Stations PUAPSD Inactivity Timer +* +* +* +WNI_CFG_TDLS_PUAPSD_INACT_TIME I 4 7 +V RW NP +LIM +0 10 0 +V RW NP +LIM +0 10 0 +*TDLS Stations PUAPSD RX Frame Threshold +* +* +* +WNI_CFG_TDLS_RX_FRAME_THRESHOLD I 4 7 +V RW NP +LIM +10 20 10 +V RW NP +LIM +10 20 10 + +* +* PMF SA Query Maximum Retries +* + +WNI_CFG_PMF_SA_QUERY_MAX_RETRIES I 4 1 +V RW NP RESTART +NONE +0 20 5 +V RW NP RESTART +NONE +0 20 5 + +* +* PMF SA Query Retry Interval (in TUs) +* + +WNI_CFG_PMF_SA_QUERY_RETRY_INTERVAL I 4 1 +V RW NP RESTART +NONE +10 2000 200 +V RW NP RESTART +NONE +10 2000 200 + + +* +*MCC ENABLE/DISABLE ADAPTIVE RX Drain feature +* +* +* +WNI_CFG_ENABLE_ADAPT_RX_DRAIN I 4 7 +V RW NP +HAL +0 1 1 +NV RW NP +HAL +0 1 1 + +* +* FlexConnect Power Factor +* Default is set to 0 (disable) +* +* +WNI_CFG_FLEX_CONNECT_POWER_FACTOR I 4 0 +V RW NP +NONE +0 9 0 +V RW NP +NONE +0 9 0 + +* +* Antenna Diversity +* +* 0 = disabled +* 1 = Ant 1 +* 2 = Ant 2 +* 3 = Adaptive +* +WNI_CFG_ANTENNA_DIVESITY I 4 7 +V RW NP +HAL +0 3 0 +V RW NP +HAL +0 3 0 + +* GO Link Monitor Timeout (TU) +* +WNI_CFG_GO_LINK_MONITOR_TIMEOUT I 4 7 +V RW NP +HAL +3 50 10 +V RW NP +HAL +3 50 10 +* +* + +* RMC action period frequency (milli seconds) +* +WNI_CFG_RMC_ACTION_PERIOD_FREQUENCY I 4 7 +V RW NP +HAL +100 1000 300 +V RW NP +HAL +100 1000 300 +* +* + +* Current RSSI value (of connected AP) +* +WNI_CFG_CURRENT_RSSI I 4 7 +V RW NP +NONE +0 127 0 +V RW NP +NONE +0 127 0 + +* RTT3 Bit Value +* +WNI_CFG_RTT3_ENABLE I 1 1 +V RW NP +NONE +0 1 1 +V RW NP +NONE +0 1 1 + +* Debug p2p remain on channel +* +WNI_CFG_DEBUG_P2P_REMAIN_ON_CHANNEL I 4 7 +V RW NP +NONE +0 1 0 +V RW NP +NONE +0 1 0 + +* +* TDLS Off Channel Implementation +* +WNI_CFG_TDLS_OFF_CHANNEL_ENABLED I 4 7 +V RW NP +LIM +0 1 0 +V RW NP +LIM +0 1 0 + +WNI_CFG_IBSS_ATIM_WIN_SIZE I 4 7 +V RW NP +NONE +0 100 0 +V RW NP +NONE +0 100 0 + +* +* DFS Master capability (11h) enable/disable +* + +WNI_CFG_DFS_MASTER_ENABLED I 4 7 +V RW NP +NONE +0 1 0 +V RW NP +NONE +0 1 0 + +WNI_CFG_VHT_ENABLE_TXBF_20MHZ I 4 7 +V RW NP +NONE +0 1 0 +V RW NP +NONE +0 1 0 +* +*TDLS WMM Mode +* +* +WNI_CFG_TDLS_WMM_MODE_ENABLED I 4 7 +V RW NP +LIM +0 1 0 +V RW NP +LIM +0 1 0 diff --git a/drivers/staging/qcacld-3.0/core/mac/src/cfg/cfgUtil/dot11f.frms b/drivers/staging/qcacld-3.0/core/mac/src/cfg/cfgUtil/dot11f.frms new file mode 100644 index 0000000000000000000000000000000000000000..4457c9f040abd490e6faf9ed992145e0b0766075 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/cfg/cfgUtil/dot11f.frms @@ -0,0 +1,3782 @@ +/* + * Copyright (c) 2006-2007, 2014-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * \file dot11f.frms + * + * \brief Primary 'frames' file for the MAC parser + * + * + * This file defines several 802.11 frames (along with their associated + * constituents) in a little language called "frames". When run through the + * 'framesc' program, it will generate C code for working with these frames: + * C structs representing the 802.11 frame together with functions for + * packing & unpacking them. + * + * For more information on the "frames" language, run 'framesc --help'... + * + * + */ + + +// Tell framesc what types to use for... +%8-bit-type uint8_t // 8, +%16-bit-type uint16_t // 16, +%32-bit-type uint32_t // & 32-bit unsigned integral types. These can also + // be specified on the command line. + +// Define some mnemonic constants; these are just for our use with the frames +// files we're compiling. IOW, they won't result in any C code being +// emitted. + +const EID_SSID = 0; +const EID_SUPP_RATES = 1; +const EID_FH_PARAM_SET = 2; +const EID_DS_PARAM_SET = 3; +const EID_CF_PARAM_SET = 4; +const EID_TIM = 5; +const EID_IBSS_PARAM_SET = 6; +const EID_COUNTRY = 7; +const EID_FH_PATTERN = 8; +const EID_FH_PATT_TABLE = 9; +const EID_REQUEST = 10; +const EID_QBSS_LOAD = 11; +const EID_EDCA_PARAM_SET = 12; +const EID_TSPEC = 13; +const EID_TCLAS = 14; +const EID_SCHEDULE = 15; +const EID_CHALLENGE_TEXT = 16; +const EID_POWER_CONSTRAINTS = 32; +const EID_POWER_CAPABILITY = 33; +const EID_TPC_REQUEST = 34; +const EID_TPC_REPORT = 35; +const EID_SUPPORTED_CHANNELS = 36; +const EID_CHANNEL_SWITCH_ANN = 37; +const EID_MEAS_REQUEST = 38; +const EID_MEAS_REPORT = 39; +const EID_QUIET = 40; +const EID_ERP_INFO = 42; +const EID_TS_DELAY = 43; +const EID_TCLASS_PROC = 44; +const EID_HT_CAPABILITIES = 45; +const EID_QOS_CAPABILITY = 46; +const EID_RSN = 48; +const EID_EXT_SUPP_RATES = 50; +const EID_AP_CHAN_REPORT = 51; +const EID_NEIGHBOR_REPORT = 52; +const EID_RCPI = 53; +const EID_FT_MOBILITY_DOMAIN = 54; +const EID_FT_INFO = 55; +const EID_TIMEOUT_INTERVAL = 56; +const EID_FT_RIC_DATA = 57; +const EID_SUPPORTED_OPER_CLASSES = 59; +const EID_EXT_CHAN_SWITCH = 60; +const EID_HT_INFO = 61; +const EID_SEC_CHAN_OFFSET = 62; +const EID_RSNI = 65; +const EID_RRM_MEAS_PILOT_TX_INFO = 66; +const EID_WAPI = 68; +const EID_TIME_ADVERTISEMENT = 69; +const EID_RRM_ENABLED_CAPS = 70; +const EID_MULTIPLE_BSSID = 71; +const EID_20_40_BSS_COEXISTENCE = 72; +const EID_20_40_BSS_INTOLERANT_REPORT= 73; +const EID_OBSS_SCAN_PARAMETERS = 74; +const EID_FT_RIC_DESCRIPTOR = 75; +const EID_LINK_IDENTIFIER = 101; +const EID_PTI_CONTROL = 105; +const EID_PU_BUFFER_STATUS = 106; +const EID_QOS_MAP_SET = 110; +const EID_ESE_SPECIFIC = 150; +const EID_ESE_CCKM_SPECIFIC = 156; +const EID_VHT_CAPABILITIES = 191; +const EID_VHT_OPERATION_ELEMENT = 192; +const EID_VHT_EXT_BSS_LOAD = 193; +const EID_AID = 197; +const EID_EXT_CAP = 127; +const EID_OPERATING_MODE = 199; +const EID_WIDER_BW_CHANNEL_SWITCH_ANN= 194; +const VHT_TRANSMIT_POWER_ENVELOPE = 195; +const EID_CHANNEL_SWITCH_WRAPPER = 196; +const EID_VENDOR_SPECIFIC = 221; + +const SIR_MAC_PROP_EXT_RATES_TYPE = 0; +const SIR_MAC_PROP_AP_NAME_TYPE = 1; +const SIR_MAC_PROP_HCF_TYPE = 2; +const SIR_MAC_PROP_WDS_TYPE = 3; +const SIR_MAC_PROP_BP_IND_TYPE = 4; +const SIR_MAC_PROP_NEIGHBOR_BSS_TYPE = 5; +const SIR_MAC_PROP_LOAD_INFO_TYPE = 6; +const SIR_MAC_PROP_ASSOC_TYPE = 7; +const SIR_MAC_PROP_LOAD_BALANCE_TYPE = 8; +const SIR_MAC_PROP_LL_ATTR_TYPE = 9; +const SIR_MAC_PROP_CAPABILITY = 10; +const SIR_MAC_PROP_VERSION = 11; +const SIR_MAC_PROP_EDCAPARAMS = 12; +const SIR_MAC_PROP_CHANNEL_SWITCH = 15; +const SIR_MAC_PROP_QUIET_BSS = 16; +const SIR_MAC_PROP_TRIG_STA_BK_SCAN = 17; + +const ANI_WDS_INFO_MAX_LENGTH = 64; +const SIR_MAC_MAX_NUMBER_OF_RATES = 12; +const HT_MAX_SUPPORTED_MCS_SET = 16; +const MAX_SUPPORTED_NEIGHBOR_RPT = 15; + +///////////////////////////////////////////////////////////////////////////// +// Wi-Fi Protected Setup TLV Identifiers // +// WSC Version 2.0.0 Table 28 // +///////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////// +// Wi-Fi Simple Configuration TLV Identifiers // +// WFA Vendor Extension Subelements // +///////////////////////////////////////////////////////////////////////////// +const TLV_VERSION2 = 0; +const TLV_AUTHORIZED_MAC = 1; +const TLV_NETWORK_KEY_SHAREABLE = 2; +const TLV_REQUEST_TO_ENROLL = 3; +const TLV_SETTINGS_DELAY_TIME = 4; + +const TLV_VERSION = 0x104A; +const TLV_WI_FI_SIMPLE_CONFIG_STATE = 0x1044; +const TLV_AP_SETUP_LOCKED = 0x1057; +const TLV_SELECTED_REGISTRAR_CONFIG_METHODS = 0x1053; +const TLV_DEVICE_PASSWORD_ID = 0x1012; +const TLV_UUID_E = 0x1047; +const TLV_UUID_R = 0x1048; +const TLV_RF_BANDS = 0x103C; +const TLV_REQUEST_TYPE = 0x103A; +const TLV_RESPONSE_TYPE = 0x103B; +const TLV_CONFIG_METHODS = 0x1008; +const TLV_PRIMARY_DEVICE_TYPE = 0x1054; +const TLV_ASSOCIATION_STATE = 0x1002; +const TLV_CONFIGURATION_ERROR = 0x1009; +const TLV_MANUFACTURER = 0x1021; +const TLV_MODEL_NAME = 0x1023; +const TLV_MODEL_NUMBER = 0x1024; +const TLV_SERIAL_NUMBER = 0x1042; +const TLV_DEVICE_NAME = 0x1011; +const TLV_SELECTED_REGISTRAR = 0x1041; +const TLV_VENDOR_EXTENSION = 0x1049; +const TLV_REQUESTED_DEVICE_TYPE = 0x106A; + +///////////////////////////////////////////////////////////////////////////// +// Wi-Fi Direct/P2P TLV Identifiers // +///////////////////////////////////////////////////////////////////////////// +const TLV_P2P_STATUS = 0; +const TLV_MINOR_REASON_CODE = 1; +const TLV_P2P_CAPABILITY = 2; +const TLV_P2P_DEVICE_ID = 3; +const TLV_P2P_GROUP_OWNER_INTENT = 4; +const TLV_CONFIGURATION_TIMEOUT = 5; +const TLV_LISTEN_CHANNEL = 6; +const TLV_P2P_GROUP_BSSID = 7; +const TLV_EXTENDED_LISTEN_TIMING = 8; +const TLV_INTENDED_P2P_INTERFACE_ADDRESS = 9; +const TLV_P2P_MANAGEABILITY = 10; +const TLV_CHANNEL_LIST = 11; +const TLV_NOTICE_OF_ABSENCE = 12; +const TLV_P2P_DEVICE_INFO = 13; +const TLV_P2P_GROUP_INFO = 14; +const TLV_P2P_GROUP_ID = 15; +const TLV_P2P_INTERFACE = 16; +const TLV_OPERATING_CHANNEL = 17; +const TLV_INVITATION_FLAGS = 18; +const TLV_P2P_VENDOR_SPECIFIC = 221; + +///////////////////////////////////////////////////////////////////////////// +// Fixed Fields + +FF AuthAlgo (2) // C.f. Sec. 7.3.1.1 +{ + algo, 2; +} + +FF AuthSeqNo (2) // 7.3.1.2 +{ + no, 2; +} + +FF BeaconInterval (2) // 7.3.1.3 +{ + interval, 2; +} + +FF Capabilities (2) // 7.3.1.4 +{ + { + ess: 1; + ibss: 1; + cfPollable: 1; + cfPollReq: 1; + privacy: 1; + shortPreamble: 1; + pbcc: 1; + channelAgility: 1; + spectrumMgt: 1; + qos: 1; + shortSlotTime: 1; + apsd: 1; + rrm: 1; + dsssOfdm: 1; + delayedBA: 1; + immediateBA: 1; + } +} + +FF CurrentAPAddress(6) // 7.3.1.5 +{ + mac[6]; +} + +FF ListenInterval (2) // 7.3.1.6 +{ + interval, 2; +} + +FF Reason (2) // 7.3.1.7 +{ + code, 2; +} + +FF AID (2) // 7.3.1.8 +{ + associd, 2; +} + +FF Status (2) // 7.3.1.9 +{ + status, 2; +} + +FF TimeStamp (8) // 7.3.1.10 +{ + timestamp, 8; +} + +FF Category (1) // 7.3.1.11 +{ + category, 1; +} + +FF Action (1) // 7.3.1.11 +{ + action, 1; +} + +FF TransactionId (2) // 7.3.1.11 +{ + transId[2]; +} + +FF DialogToken (1) // 7.3.1.12 +{ + token, 1; +} + +FF StatusCode (1) // WMM Spec 2.2.10 +{ + statusCode, 1; +} + +FF p2p_action_oui (4) +{ + oui_data[4]; +} + +FF p2p_action_subtype (1) +{ + subtype, 1; +} + +FF OperatingMode (1) +{ + { + //Operating Mode field + chanWidth: 2; + reserved: 2; + rxNSS: 3; + rxNSSType: 1; + } +} + +FF SMPowerModeSet (1) //7.3.1.25 +{ + { + PowerSave_En: 1; + Mode: 1; + reserved: 6; + } +} + +FF TSInfo (3) // 7.3.2.30 +{ + { + traffic_type: 1; + tsid: 4; + direction: 2; + access_policy: 2; + aggregation: 1; + psb: 1; + user_priority: 3; + tsinfo_ack_pol: 2; + schedule: 1; + unused: 15; + } +} + +FF NumOfRepetitions (2) +{ + repetitions, 2; +} + +FF TxPower (1) +{ + txPower, 1; +} + +FF MaxTxPower (1) +{ + maxTxPower, 1; +} +FF TPCEleID (1) +{ + TPCId, 1; +} +FF TPCEleLen (1) +{ + TPCLen, 1; +} +FF LinkMargin (1) +{ + linkMargin, 1; +} +FF RxAntennaId (1) +{ + antennaId, 1; +} +FF TxAntennaId (1) +{ + antennaId, 1; +} +FF RCPI (1) +{ + rcpi, 1; +} +FF RSNI (1) +{ + rsni, 1; +} + +FF VhtMembershipStatusArray(8) // 8.4.1.51 +{ + membershipStatusArray[8]; +} + +FF VhtUserPositionArray(16) // 8.4.1.52 +{ + userPositionArray[16]; +} + +FF ext_chan_switch_ann_action(4) +{ + { + switch_mode: 8; + op_class: 8; + new_channel: 8; + switch_count: 8; + } +} + +///////////////////////////////////////////////////////////////////////////// +// TLVs // +///////////////////////////////////////////////////////////////////////////// + +/** + * \brief Version + * + * WPS 1.0h + * Version specifies the Easy Setup version. The one-byte field is broken + * into a four-bit major part using the top MSBs and four-bit minor part + * using the LSBs. As an example, version 3.2 would be 0x32. + * + * WSC 2.0.0 + * Deprecated Version mechanism. This attribute is always set to value 0x10 + * (version 1.0) for backwards compatibility. Version 1.0h of the specification + * did not fully describe the version negotiation mechanism and version 2.0 + * introduced a new subelement (Version2) for indicating the version number + * to avoid potential interoperability issues with deployed 1.0h-based devices. + * + */ + +TLV Version( TLV_VERSION ) ( 2 : 2 ) MSB +{ + { + minor: 4; + major: 4; + } +} + +/// Wi-Fi Protected Setup State +TLV WPSState( TLV_WI_FI_SIMPLE_CONFIG_STATE ) ( 2 : 2 ) MSB +{ + state, 1; +} + +/** + * \brief AP Setup Locked + * + * + * This variable indicates that the AP has entered a state in which it will + * refuse to allow an external Registrar to attempt to run the Registration + * Protocol using the AP?s PIN (with the AP acting as Enrollee). The AP + * should enter this state if it believes a brute force attack is underway + * against the AP?s PIN. + * + * When the AP is in this state, it MUST continue to allow other Enrollees to + * connect and run the Registration Protocol with any external Registrars or + * the AP's built-in Registrar (if any). It is only the use of the AP' PIN + * for adding external Registrars that is disabled in this state. + * + * The AP Setup Locked state can be reset to FALSE through an authenticated + * call to SetAPSettings. APs may provide other implementation-specific + * methods of resetting the AP Setup Locked state as well. + * + * + */ + +TLV APSetupLocked( TLV_AP_SETUP_LOCKED ) ( 2 : 2 ) MSB +{ + fLocked, 1; +} + +/** + * \brief Selected Registrar Config Methods + * + * + * This attribute has the same values that Config Methods have. It is used in + * Probe Response messages to convey the Config Methods of the selected + * Registrar. + * + * + */ + +TLV SelectedRegistrarConfigMethods ( TLV_SELECTED_REGISTRAR_CONFIG_METHODS ) ( 2 : 2 ) MSB +{ + methods, 2; +} + +/** + * \brief UUID-E + * + * + * The universally unique identifier (UUID) element is a unique GUID + * generated by the Enrollee. It uniquely identifies an operational device + * and should survive reboots and resets. The UUID is provided in binary + * format. If the device also supports UPnP, then the UUID corresponds to the + * UPnP UUID. + * + * + */ + +TLV UUID_E ( TLV_UUID_E ) ( 2 : 2 ) MSB +{ + uuid[ 16 ]; +} + +/** + * \brief UUID-R + * + * + * The universally unique identifier (UUID) element is a unique GUID + * generated by the Registrar. It uniquely identifies an operational device + * and should survive reboots and resets. The UUID is provided in binary + * format. If the device also supports UPnP, then the UUID corresponds to the + * UPnP UUID. + * + * + */ + +TLV UUID_R ( TLV_UUID_R ) ( 2 : 2 ) MSB +{ + uuid[ 16 ]; +} + +/** + * \brief RF Bands + * + * + \code + + 0x01 2.4GHz + 0x02 5.0GHz + + \endcode + * + * + */ + +TLV RFBands ( TLV_RF_BANDS ) ( 2 : 2 ) MSB +{ + bands, 1; +} + + +/** + * \brief Selected Registrar + * + * + * This field indicates that a Registrar has been selected by a user and that + * an Enrollee should proceed with setting up an 802.1X uncontrolled data + * port with the Registrar. + * + * + */ + +TLV SelectedRegistrar ( TLV_SELECTED_REGISTRAR ) ( 2 : 2 ) MSB +{ + selected, 1; +} + +/** + * \brief Config Methods + * + * + * The Config Methods Data component lists the configuration methods the + * Enrollee or Registrar supports. The list is a bitwise OR of values from + * the table below. In addition to Config Methods, APs and STAs that support + * the UPnP Management Interface must support the Permitted Config Methods + * attribute, which is used to control the Config Methods that are enabled on + * that AP. + * + \code + + Value Hardware Interface + 0x0001 USBA (Flash Drive) + 0x0002 Ethernet + 0x0004 Label + 0x0008 Display + 0x0010 External NFC Token + 0x0020 Integrated NFC Token + 0x0040 NFC Interface + 0x0080 PushButton + 0x0100 Keypad + + \endcode + * + * + */ + +TLV ConfigMethods ( TLV_CONFIG_METHODS ) ( 2 : 2 ) MSB +{ + methods, 2; +} + +/** + * \brief Association State + * + * + * The Association State component shows the configuration and previous + * association state of the wireless station when sending a Discovery + * request. + * + \code + + Association State Description + 0 Not Associated + 1 Connection Success + 2 Configuration Failure + 3 Association Failure + 4 IP Failure + + \endcode + * + * + */ + +TLV AssociationState ( TLV_ASSOCIATION_STATE ) ( 2 : 2 ) MSB +{ + state, 2; +} + +/** + * \brief Configuration Error + * + * + * The Configuration Error component shows the result of the device + * attempting to configure itself and to associate with the WLAN. + * + \code + + Configuration Error Description + 0 No Error + 1 OOB Interface Read Error + 2 Decryption CRC Failure + 3 2.4 channel not supported + 4 5.0 channel not supported + 5 Signal too weak + 6 Network auth failure + 7 Network association failure + 8 No DHCP response + 9 Failed DHCP config + 10 IP address conflict + 11 Couldn't connect to Registrar + 12 Multiple PBC sessions detected + 13 Rogue activity suspected + 14 Device busy + 15 Setup locked + 16 Message Timeout + 17 Registration Session Timeout + 18 Device Password Auth Failure + + \endcode + * + * The Device busy error is returned if the sending device is unable to + * respond to the request due to some internal conflict or resource + * contention issue. For example, if a device is only capable of performing a + * single instance of the Registration Protocol at a time, it may return this + * error in response to attempts to start another instance in the middle of + * an active session. + * + * + */ + +TLV ConfigurationError ( TLV_CONFIGURATION_ERROR ) ( 2 : 2 ) MSB +{ + error, 2; +} + +TLV Manufacturer ( TLV_MANUFACTURER ) ( 2 : 2 ) MSB +{ + name[ 0..64 ]; +} + +TLV ModelName ( TLV_MODEL_NAME ) ( 2 : 2 ) MSB +{ + text[ 0..32 ]; +} + +TLV ModelNumber ( TLV_MODEL_NUMBER ) ( 2 : 2 ) MSB +{ + text[ 0..32 ]; +} + +TLV SerialNumber ( TLV_SERIAL_NUMBER ) ( 2 : 2 ) MSB +{ + text[ 0..32 ]; +} + +TLV DeviceName ( TLV_DEVICE_NAME ) ( 2 : 2 ) MSB +{ + text[ 0..32 ]; +} + +/** + * \brief Device Password ID + * + * + * This attribute is used to identify a device password. There are six + * predefined values and ten reserved values. If the Device Password ID is + * Default, the Enrollee should use its PIN password (from the label or + * display). This password may correspond to the label, display, or a + * user-defined password that has been configured to replace the original + * device password. + * + * User-specified indicates that the user has overridden the password with a + * manually selected value. Machine-specified indicates that the original + * PIN password has been overridden by a strong, machinegenerated device + * password value. The Rekey value indicates that the device's 256-bit + * rekeying password will be used. The PushButton value indicates that the + * PIN is the all-zero value reserved for the PushButton Configuration + * method. + * + * The Registrar-specified value indicates a PIN that has been obtained from + * the Registrar (via a display or other out-of-band method). This value may + * be further augmented with the optional 'Identity' attribute in M1. This + * augmentation is useful when multiple predefined UserID/PIN pairs have been + * established by a Registrar such as an authenticator used for Hotspot + * access. If the Device Password ID in M1 is not one of the predefined or + * reserved values, it corresponds to a password given to the Registrar as an + * OOB Device Password. + * + \code + + Value Description + + 0x0000 Default (PIN) + 0x0001 User-specified + 0x0002 Machine-specified + 0x0003 Rekey + 0x0004 PushButton + 0x0005 Registrar-specified + 0x0006 - 0x000F Reserved + + \endcode + * + * + */ + +TLV DevicePasswordID ( TLV_DEVICE_PASSWORD_ID ) ( 2 : 2 ) MSB +{ + id, 2; +} + + +/** + * \brief Primary Device Type + * + * + * This attribute contains the primary type of the device. Its format + * follows: + * + \code + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Attribute ID | Length | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Category ID | OUI (1-2) | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | OUI (3-4) | Sub Category ID | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + \endcode + * + * Vendor-specific sub-categories are designated by setting the OUI to the + * value associated with that vendor. Note that a four-byte subdivided OUI + * is used. For the predefined values, the Wi-Fi Alliance OUI of 00 50 F2 04 + * is used. The predefined values for Category ID and Sub Category ID are + * provided in the next table. There is no way to indicate a vendor-specific + * main device category. The OUI applies only to the interpretation of the + * Sub Category. If a vendor does not use sub categories for their OUI, the + * three-byte OUI occupies the first three bytes of the OUI field and the + * fourth byte is set to zero. + * + * + \code + + Category ID Value Sub Category ID Value + Computer 1 PC 1 + Server 2 + Media Center 3 + Input Device 2 + Printers, Scanners, Printer 1 + Faxes and Copiers 3 Scanner 2 + Camera 4 Digital Still Camera 1 + Storage 5 NAS 1 + Network AP 1 + Infrastructure 6 Router 2 + Switch 3 + Displays 7 Television 1 + Electronic Picture Frame 2 + Projector 3 + Multimedia Devices 8 DAR 1 + PVR 2 + MCX 3 + Gaming Devices 9 Xbox 1 + Xbox360 2 + Playstation 3 + Telephone 10 Windows Mobile 1 + + \endcode + * + * + */ + +TLV PrimaryDeviceType ( TLV_PRIMARY_DEVICE_TYPE ) ( 2 : 2 ) MSB +{ + primary_category, 2; + oui[ 4 ]; + sub_category, 2; +} + + +/** + * \brief Request Type + * + * + * The Request Type component specifies the mode in which the device will + * operate in for this setup exchange. If the device is an Enrollee, it may + * send only discovery messages or it may also request that the Registrar + * proceed with opening a data connection. This protocol allows Enrollees to + * more efficiently discover devices on the network. + + * If the device indicates that it intends to engage setup either as a + * Registrar or an Enrollee, the Access Point continues to indicate that it + * will operate as an AP in the response. The Request Type attribute is + * carried throughout the 802.1X data channel setup process in the Wi-Fi + * Protected Setup IE. There are two sub-types of Registrars: WLAN Manager + * Registrar indicates that this Registrar intends to manage the AP or STA + * settings using UPnP. It will derive a UPnP AP or STA Management key. The + * ordinary Registrar type indicates that this Registrar does not intend to + * subsequently manage the Enrollee's settings. APs must not derive AP + * Management Keys for an ordinary Registrar. If a Registrar does not intend + * to be a WLAN Manager Registrar, it should set the Request Type to + * Registrar. Doing so avoids needlessly consuming resources on the AP. + + \code + + Request Type Value Description + 0x00 Enrollee, Info only + 0x01 Enrollee, open 802.1X + 0x02 Registrar + 0x03 WLAN Manager Registrar + + \endcode + * + * + */ + +TLV RequestType ( TLV_REQUEST_TYPE ) ( 2 : 2 ) MSB +{ + reqType, 1; +} + +/** + * \brief Response Type + * + * + * The Response Type component specifies the operational mode of the + * device for this setup exchange. The Response Type IE is carried + * throughout the 802.1X data channel setup process. + + \code + + Response Type Value Description + 0x00 Enrollee, Info only + 0x01 Enrollee, open 802.1X + 0x02 Registrar + 0x03 AP + +\endcode + * + * + */ + +TLV ResponseType ( TLV_RESPONSE_TYPE ) ( 2 : 2 ) MSB +{ + resType, 1; +} + + +/////////////////////////////////////////////////////////////////////////// +// WiFi Direct/P2P TLVs // +/////////////////////////////////////////////////////////////////////////// + +/** + * \brief P2P Status Attribute + */ + +TLV P2PStatus ( TLV_P2P_STATUS ) ( 1 : 2 ) LSB +{ + status, 1; +} + + +/** + * \brief Minor Reason Code Attribute + */ + +TLV MinorReasonCode ( TLV_MINOR_REASON_CODE ) ( 1 : 2 ) LSB +{ + minorReasonCode, 1; +} + + +/** + * \brief P2P Capability Attribute + */ + +TLV P2PCapability ( TLV_P2P_CAPABILITY ) ( 1 : 2 ) LSB +{ + deviceCapability, 1; + groupCapability, 1; +} + + +/** + * \brief P2P Device Id Attribute + */ + +TLV P2PDeviceId ( TLV_P2P_DEVICE_ID ) ( 1 : 2 ) LSB +{ + P2PDeviceAddress[6]; +} + +/** + * \brief Listen Channel Attribute + */ + +TLV ListenChannel ( TLV_LISTEN_CHANNEL ) ( 1 : 2 ) LSB +{ + countryString[3]; + regulatoryClass, 1; + channel, 1; +} + +/** + * \brief Extended Listen Attribute + */ + +TLV ExtendedListenTiming ( TLV_EXTENDED_LISTEN_TIMING ) ( 1 : 2 ) LSB +{ + availibilityPeriod, 2; + availibilityInterval, 2; +} + + +/** + * \brief P2P Manageability Attribute + */ + +TLV P2PManageability ( TLV_P2P_MANAGEABILITY ) ( 1 : 2 ) LSB +{ + manageability, 1; +} + + +/** + * \brief Notice of Absence + */ + +TLV NoticeOfAbsence ( TLV_NOTICE_OF_ABSENCE ) ( 1 : 2 ) LSB +{ + index, 1; + CTSWindowOppPS, 1; + NoADesc[0..36]; +} + +/** + * \brief P2P Device Info Attribute + */ + +TLV P2PDeviceInfo ( TLV_P2P_DEVICE_INFO ) ( 1 : 2 ) LSB +{ + P2PDeviceAddress[6]; + configMethod, 2 , FLIPBYTEORDER; + primaryDeviceType[8]; + MANDATORYTLV DeviceName; +} + + +/** + * \brief P2P Group Info Attribute + */ + +TLV P2PGroupInfo ( TLV_P2P_GROUP_INFO ) ( 1 : 2 ) LSB +{ + P2PClientInfoDesc[0..1024]; +} + + +/** + * \brief P2P Interface Attribute + */ + +TLV P2PInterface ( TLV_P2P_INTERFACE ) ( 1 : 2 ) LSB +{ + P2PDeviceAddress[6]; +} + + +/** + * \brief Operating Channel Attribute + */ + +TLV OperatingChannel ( TLV_OPERATING_CHANNEL ) ( 1 : 2 ) LSB +{ + countryString[3]; + regulatoryClass, 1; + channel, 1; +} + + +/** + * \brief Vendor Extension + * + * This variable permits vendor extensions in the Wi-Fi Simple + * Configuration TLV framework. The Vendor Extension figure + * illustrates the implementation of vendor extensions. Vendor + * ID is the SMI network management private enterprise code + * + * +-----------+----------------------+ + * | Vendor ID | Vendor Data | + * +-----------+----------------------+ + * |<--- 3 --->|<----- 1 - 1021 ----->| + * + */ + +TLV VendorExtension ( TLV_VENDOR_EXTENSION ) ( 2 : 2 ) MSB +{ + /* + * vendorId is the SMI network management private enterprise code. + * WFA Vendor ID 0x00372A + * + */ + vendorId[ 3 ]; + + /** + * \breif Version2 + * + * The Version2 field specifies the version Wi-Fi Simple + * Configuration implemented by the device sending this attribute. + * The one-byte field is broken into a four-bit major part using + * the top MSBs and four-bit minor part using the LSBs. As an example, + * version 3.2 would be 0x32. This subelement was added in the + * specification version 2.0 and if the subelement is not included + * in a message, the transmitter of the message is assumed to + * use version 1.0. + * + */ + OPTIONALTLV TLV Version2 ( TLV_VERSION2 ) ( 1 : 1 ) MSB + { + { + minor: 4; + major: 4; + } + } + /** + * \brief AuthorizedMACs + * + * This subelement contains a list of Enrollee MAC addresses (each + * being six bytes in length) that have been registered to start WSC. + * The AP includes this field in Beacon and Probe Response frames so + * Enrollees can tell if they have been registered to start WSC. There + * may be multiple Enrollees active on the network, but not all of them have + * been registered to start WSC. This element allows an Enrollee to detect + * if they should start WSC with the AP. The AuthorizedMACs field augments + * the use of the Selected Registrar. + * + */ + OPTIONALTLV TLV AuthorizedMACs ( TLV_AUTHORIZED_MAC ) ( 1 : 1 ) MSB + { + mac[6]; + } + + /** + * \brief Request to Enroll + * + * This optional subelement in the WSC IE in Probe Request or M1 indicates + * the desire to enroll in the network by setting its value to TRUE. If the + * Registrar gets this subelement it can use this as a trigger that a device + * wants to enroll (maybe an indication can be shown to the user). The device + * must set it to FALSE after the registration protocol completion. + * + */ + OPTIONALTLV TLV RequestToEnroll( TLV_REQUEST_TO_ENROLL ) ( 1 : 1 ) MSB + { + req, 1; + } +} + +/** + * \brief Requested Device Type + * + * This attribute contains the requested device type of a Wi-Fi + * Direct device. + * + * This attribute allows a device to specify the Primary Device Type + * or the Secondary Device Type of other devices it is interested in. + * Only a device that receives a Probe Request containing a WSC IE with + * this attribute and with a Primary Device Type or Secondary Device Type + * that matches the Requested Device Type will respond with a Probe Response. + * + * Its format and contents is identical to the 'Primary Device Type'. + * + * Both the Category ID and Sub Category ID can be used as a filter. If only + * looking for devices with a certain Category ID, the OUI and Sub Category ID + * fields will have to be set to zero. + * + */ +TLV RequestDeviceType ( TLV_REQUESTED_DEVICE_TYPE ) ( 2 : 2 ) MSB +{ + primary_category, 2; + oui[ 4 ]; + sub_category, 2; +} + +///////////////////////////////////////////////////////////////////////////// +// Information Elements + +IE SSID (EID_SSID) // C.f. Sec. 7.3.2.1 +{ + ssid[0..32]; +} + +IE SuppRates (EID_SUPP_RATES) // 7.3.2.2 +{ + rates[0..SIR_MAC_MAX_NUMBER_OF_RATES]; +} + +IE FHParamSet (EID_FH_PARAM_SET) // 7.3.2.3 +{ + dwell_time, 2; + hop_set, 1; + hop_pattern, 1; + hop_index, 1; +} + +IE DSParams (EID_DS_PARAM_SET) // 7.3.2.4 +{ + curr_channel, 1; +} + +IE CFParams (EID_CF_PARAM_SET) // 7.3.2.5 +{ + cfp_count, 1; + cfp_period, 1; + cfp_maxduration, 2; + cfp_durremaining, 2; +} + +IE TIM (EID_TIM) // 7.3.2.6 +{ + dtim_count, 1; + dtim_period, 1; + bmpctl, 1; + vbmp[1..251]; +} + +IE IBSSParams (EID_IBSS_PARAM_SET) // 7.3.2.7 +{ + atim, 2; +} + +IE ChallengeText (EID_CHALLENGE_TEXT) // 7.3.2.8 +{ + text[1..253]; +} + +IE RequestedInfo (EID_REQUEST) // 7.3.2.12 +{ + requested_eids[0..255]; +} + +IE Country (EID_COUNTRY) // 7.3.2.9 +{ + country[3]; + OPTIONAL triplets[3][0..84]; +} + +IE FHParams (EID_FH_PATTERN) // 7.3.2.10 +{ + radix, 1; + nchannels, 1; +} + +IE FHPattTable (EID_FH_PATT_TABLE) // 7.3.2.11 +{ + flag, 1; + nsets, 1; + modulus, 1; + offset, 1; + randtable[0..251]; +} + +IE ERPInfo (EID_ERP_INFO) // 7.3.2.13 +{ + { + non_erp_present : 1; + use_prot: 1; + barker_preamble: 1; + unused: 5; + } +} + +IE ExtSuppRates (EID_EXT_SUPP_RATES) // 7.3.2.14 +{ + rates[1..SIR_MAC_MAX_NUMBER_OF_RATES]; +} + +IE PowerConstraints (EID_POWER_CONSTRAINTS) // 7.3.2.15 +{ + localPowerConstraints, 1; +} + +IE PowerCaps (EID_POWER_CAPABILITY) // 7.3.2.16 +{ + minTxPower, 1; + maxTxPower, 1; +} + +IE TPCRequest (EID_TPC_REQUEST) // 7.3.2.17 +{ } + +IE TPCReport (EID_TPC_REPORT) // 7.3.2.18 +{ + tx_power, 1; + link_margin, 1; +} + +IE SuppChannels (EID_SUPPORTED_CHANNELS) // 7.2.3.19 +{ + bands[2][1..48]; +} + +IE SuppOperatingClasses (EID_SUPPORTED_OPER_CLASSES) +{ + classes[1..32]; +} + +IE ChanSwitchAnn (EID_CHANNEL_SWITCH_ANN) // 7.3.2.20 +{ + switchMode, 1; + newChannel, 1; + switchCount, 1; +} + +IE ext_chan_switch_ann (EID_EXT_CHAN_SWITCH) // 8.4.2.55 +{ + switch_mode, 1; + new_reg_class, 1; + new_channel, 1; + switch_count, 1; +} + +IE sec_chan_offset_ele (EID_SEC_CHAN_OFFSET) // 7.3.2.20a +{ + secondaryChannelOffset, 1; +} + +IE Quiet (EID_QUIET) // 7.3.2.23 +{ + count, 1; + period, 1; + duration, 2; + offset, 2; +} + +IE RSN (EID_RSN) // 7.3.2.25 +{ + // The version is 2 octets, and we only support version 1. + version, 2 MUSTBE 1; + // The next four octets will be the Group Cipher Suite + gp_cipher_suite[4]; + // The IE *may* stop here; if there's any more, we should see two more + // octets giving the number of Pairwise Cipher Suites + OPTIONAL pwise_cipher_suite_count, 2; + // I don't see anything in the Standard limiting the number of Pairwise + // Cypher Suites, other than the maximum length of an IE, which limits us + // to 61. However, that seems needlessly wasteful of space. + pwise_cipher_suites[4][0..4] COUNTIS pwise_cipher_suite_count; + // Optional count of AKM suite selectors + OPTIONAL akm_suite_count, 2; + // Again, I see nothing in the Standard explicitly limiting the number of + // AKM suite selectors other than the maximum size of an IE. + akm_suites[4][0..4] COUNTIS akm_suite_count; + OPTIONAL RSN_Cap[2]; + // Finally, the IE may contain zero or more PMKIDs: + OPTIONAL pmkid_count, 2; + pmkid[16][0..4] COUNTIS pmkid_count; + OPTIONAL gp_mgmt_cipher_suite[4]; +} + +IE RSNOpaque (EID_RSN) // 7.3.2.25 +{ + data[ 6..253 ]; +} + +IE WAPI (EID_WAPI) // 7.3.2.25 +{ + // The version is 2 octets, and we only support version 1. + version, 2 MUSTBE 1; + // count of AKM suite selectors + akm_suite_count, 2; + // Again, I see nothing in the Standard explicitly limiting the number of + // AKM suite selectors other than the maximum size of an IE. + akm_suites[4][0..4] COUNTIS akm_suite_count; + // we should see two more + // octets giving the number of Unicast Cipher Suites + unicast_cipher_suite_count, 2; + // I don't see anything in the Standard limiting the number of Pairwise + // Cypher Suites, other than the maximum length of an IE, which limits us + // to 61. However, that seems needlessly wasteful of space. + unicast_cipher_suites[4][0..4] COUNTIS unicast_cipher_suite_count; + // The next four octets will be the Multicast Cipher Suite + multicast_cipher_suite[4]; + // WAPI capabilities + { + preauth: 1; + reserved: 15; + } + // Finally, the IE may contain zero or more BKIDs: + OPTIONAL bkid_count, 2; + bkid[16][0..4] COUNTIS bkid_count; +} + +IE WAPIOpaque (EID_WAPI) // 7.3.2.25 +{ + data[ 6..253 ]; +} + +IE QBSSLoad (EID_QBSS_LOAD) // 7.3.2.28 +{ + stacount, 2; + chautil, 1; + avail, 2; +} + +IE EDCAParamSet (EID_EDCA_PARAM_SET) // 7.3.2.29 +{ + qos, 1; // ToDo: This is a bitfield whose format + // depends on whether this is from an AP + // or a STA, information which I'm not + // sure we have at parse time... + reserved, 1; + { + acbe_aifsn: 4; + acbe_acm: 1; + acbe_aci: 2; + unused1: 1; + } + { + acbe_acwmin: 4; + acbe_acwmax: 4; + } + acbe_txoplimit, 2; + { + acbk_aifsn: 4; + acbk_acm: 1; + acbk_aci: 2; + unused2: 1; + } + { + acbk_acwmin: 4; + acbk_acwmax: 4; + } + acbk_txoplimit, 2; + { + acvi_aifsn: 4; + acvi_acm: 1; + acvi_aci: 2; + unused3: 1; + } + { + acvi_acwmin: 4; + acvi_acwmax: 4; + } + acvi_txoplimit, 2; + { + acvo_aifsn: 4; + acvo_acm: 1; + acvo_aci: 2; + unused4: 1; + } + { + acvo_acwmin: 4; + acvo_acwmax: 4; + } + acvo_txoplimit, 2; +} + +IE TSPEC (EID_TSPEC) // 7.3.2.30 +{ + + // TS Info + { + traffic_type: 1; + tsid: 4; + direction: 2; + access_policy: 2; + aggregation: 1; + psb: 1; + user_priority: 3; + tsinfo_ack_pol: 2; + } + { + schedule: 1; + unused: 7; + } + + // Nominal MSDU Size + { + size: 15; + fixed: 1; + } + + max_msdu_size, 2; + min_service_int, 4; + max_service_int, 4; + inactivity_int, 4; + suspension_int, 4; + service_start_time, 4; + min_data_rate, 4; + mean_data_rate, 4; + peak_data_rate, 4; + burst_size, 4; + delay_bound, 4; + min_phy_rate, 4; + surplus_bw_allowance, 2; + medium_time, 2; + +} // End IE TSPEC. + +IE TCLAS (EID_TCLAS) // 7.3.2.31 +{ + user_priority, 1; + classifier_type, 1; + classifier_mask, 1; + UNION info (DISCRIMINATOR classifier_type) + { + EthParams (classifier_type IS 0) + { + source[6]; + dest[6]; + type, 2; + } + IpParams (classifier_type IS 1) + { + version, 1; + UNION params (DISCRIMINATOR version) + { + IpV4Params (version IS 4) + { + source[4]; + dest[4]; + src_port, 2; + dest_port, 2; + DSCP, 1; + proto, 1; + reserved, 1; + } + IpV6Params (version IS 6) + { + source[16]; + dest[16]; + src_port, 2; + dest_port, 2; + flow_label[3]; + } + }; + } + Params8021dq (classifier_type IS 2) + { + tag_type, 2; + } + }; +} // End IE TCLASS + +const EID_BCN_REPORT_FRAME_BODY = 1; +IE BeaconReportFrmBody (EID_BCN_REPORT_FRAME_BODY) +{ + reportedFields[0..224]; +} + +IE MeasurementReport (EID_MEAS_REPORT) // 7.3.2.22 +{ + token, 1; + // Measurement Report Mode + { + late: 1; + incapable: 1; + refused: 1; + unused: 5; + } + type, 1; + OPTIONAL UNION report (DISCRIMINATOR type) + { + Basic (type IS 0) // 7.3.2.22.1 + { + channel, 1; + meas_start_time, 8; + meas_duration, 2; + // Map + { + bss: 1; + ofdm_preamble: 1; + unid_signal: 1; + rader: 1; + unmeasured: 1; + unused: 3; + } + } + CCA (type IS 1) + { + channel, 1; + meas_start_time, 8; + meas_duration, 2; + cca_busy_fraction, 1; + } + RPIHistogram (type IS 2) + { + channel, 1; + meas_start_time, 8; + meas_duration, 2; + rpi0_density, 1; + rpi1_density, 1; + rpi2_density, 1; + rpi3_density, 1; + rpi4_density, 1; + rpi5_density, 1; + rpi6_density, 1; + rpi7_density, 1; + } + Beacon (type IS 5) + { + regClass, 1; + channel, 1; + meas_start_time, 8; + meas_duration, 2; + // reported_frame_info, + { + condensed_PHY: 7; + reported_frame_type: 1; + } + RCPI, 1; + RSNI, 1; + BSSID[6]; + antenna_id, 1; + parent_TSF, 4; + OPTIE BeaconReportFrmBody; + //IE vendor_specific + } + }; +} + +IE TSDelay (EID_TS_DELAY) // 7.3.2.32 +{ + delay, 4; +} + +IE TCLASSPROC (EID_TCLASS_PROC) // 7.3.2.33 +{ + processing, 1; +} + +IE Schedule (EID_SCHEDULE) // 7.3.2.34 +{ + { + aggregation: 1; + tsid: 4; + direction: 2; + reserved: 9; + } + service_start_time, 4; + service_interval, 4; + max_service_dur, 2; + spec_interval, 2; +} + +IE QOSCapsAp (EID_QOS_CAPABILITY) // 7.3.2.35 +{ + { + count: 4; + qack: 1; + qreq: 1; + txopreq: 1; + reserved: 1; + } +} + +IE QOSCapsStation (EID_QOS_CAPABILITY) // 7.3.2.35 +{ + { + acvo_uapsd: 1; + acvi_uapsd: 1; + acbk_uapsd: 1; + acbe_uapsd: 1; + qack: 1; + max_sp_length: 2; + more_data_ack: 1; + } +} + +IE LinkIdentifier (EID_LINK_IDENTIFIER) // 7.3.2.62 +{ + bssid[6]; + InitStaAddr[6]; + RespStaAddr[6]; +} + +IE WPA (EID_VENDOR_SPECIFIC) OUI (0x00, 0x50, 0xF2, 0x01) +{ + // This IE's first two octets should be interpreted as a version number; + // we only support version 1. + version, 2 MUSTBE 1; + // A four-octet Multicast Cipher may or may not appear next (hence the + // OPTIONAL keyword) + OPTIONAL multicast_cipher[4]; + // Optional Unicast Cipher count + OPTIONAL unicast_cipher_count, 2; + // Next comes an array of four-octet Cipher Suite selectors; the COUNTIS + // clause indicates that the actual number of selectors seen is in the + // member 'unicast_cipher_count'. + unicast_ciphers[4][0..4] COUNTIS unicast_cipher_count; + // (Optional) Authentication suites: + OPTIONAL auth_suite_count, 2; + auth_suites[4][0..4] COUNTIS auth_suite_count; + // This field is declared optional as per bugs 15234, 14755, & 14991. + OPTIONAL caps, 2; +} + +IE WPAOpaque (EID_VENDOR_SPECIFIC) OUI (0x00, 0x50, 0xF2, 0x01) +{ + data[ 2..249 ]; +} + +IE WMMInfoStation (EID_VENDOR_SPECIFIC) OUI(0x00, 0x50, 0xF2, 0x02, 0x00) +{ + // This IE contains the QoS Info field when sent from WMM Station + version, 1; + { + acvo_uapsd: 1; + acvi_uapsd: 1; + acbk_uapsd: 1; + acbe_uapsd: 1; + reserved1: 1; + max_sp_length: 2; + reserved2: 1; + } +} + +IE WMMInfoAp (EID_VENDOR_SPECIFIC) OUI(0x00, 0x50, 0xF2, 0x02, 0x00) +{ + // This IE contains the QoS Info field when sent from WMM AP + version, 1; + { + param_set_count: 4; + reserved: 3; + uapsd: 1; + } +} + + +IE WMMParams (EID_VENDOR_SPECIFIC) OUI(0x00, 0x50, 0xF2, 0x02, 0x01) +{ + version, 1 MUSTBE 1; + qosInfo, 1; // ToDo: This is actually a + // bitfield, but it's format + // varies depending on whether + // the sender is a STA or AP... + reserved2, 1; + { + acbe_aifsn: 4; + acbe_acm: 1; + acbe_aci: 2; + unused1: 1; + } + { + acbe_acwmin: 4; + acbe_acwmax: 4; + } + acbe_txoplimit, 2; + { + acbk_aifsn: 4; + acbk_acm: 1; + acbk_aci: 2; + unused2: 1; + } + { + acbk_acwmin: 4; + acbk_acwmax: 4; + } + acbk_txoplimit, 2; + { + acvi_aifsn: 4; + acvi_acm: 1; + acvi_aci: 2; + unused3: 1; + } + { + acvi_acwmin: 4; + acvi_acwmax: 4; + } + acvi_txoplimit, 2; + { + acvo_aifsn: 4; + acvo_acm: 1; + acvo_aci: 2; + unused4: 1; + } + { + acvo_acwmin: 4; + acvo_acwmax: 4; + } + acvo_txoplimit, 2; +} + +IE WMMTSPEC (EID_VENDOR_SPECIFIC) OUI (0x00, 0x50, 0xf2, 0x02, 0x02) +{ + version, 1 MUSTBE 1; + + // TS Info + { + traffic_type: 1; + tsid: 4; + direction: 2; + access_policy: 2; + aggregation: 1; + psb: 1; + user_priority: 3; + tsinfo_ack_pol: 2; + } + { + tsinfo_rsvd: 7; + burst_size_defn: 1; + } + + // Nominal MSDU Size + { + size: 15; + fixed: 1; + } + + max_msdu_size, 2; + min_service_int, 4; + max_service_int, 4; + inactivity_int, 4; + suspension_int, 4; + service_start_time, 4; + min_data_rate, 4; + mean_data_rate, 4; + peak_data_rate, 4; + burst_size, 4; + delay_bound, 4; + min_phy_rate, 4; + surplus_bw_allowance, 2; + medium_time, 2; + +} // End IE WMMTSpec. + +IE WMMCaps (EID_VENDOR_SPECIFIC) OUI (0x00, 0x50, 0xF2, 0x02, 0x05) +{ + version, 1 MUSTBE 1; + { + reserved: 4; + qack: 1; + queue_request: 1; + txop_request: 1; + more_ack: 1; + } +} + +IE WMMTCLAS (EID_VENDOR_SPECIFIC) OUI (0x00, 0x50, 0xF2, 0x02, 0x06) +{ + version, 1 MUSTBE 1; + + user_priority, 1; + classifier_type, 1; + classifier_mask, 1; + UNION info (DISCRIMINATOR classifier_type) + { + EthParams (classifier_type IS 0) + { + source[6]; + dest[6]; + type, 2; + } + IpParams (classifier_type IS 1) + { + version, 1; + UNION params (DISCRIMINATOR version) + { + IpV4Params (version IS 4) + { + source[4]; + dest[4]; + src_port, 2; + dest_port, 2; + DSCP, 1; + proto, 1; + reserved, 1; + } + IpV6Params (version IS 6) + { + source[16]; + dest[16]; + src_port, 2; + dest_port, 2; + flow_label[3]; + } + }; + } + Params8021dq (classifier_type IS 2) + { + tag_type, 2; + } + }; + +} + +IE WMMTCLASPROC (EID_VENDOR_SPECIFIC) OUI (0x00, 0x50, 0xF2, 0x02, 0x07) +{ + version, 1 MUSTBE 1; + processing, 1; +} + +IE WMMTSDelay (EID_VENDOR_SPECIFIC) OUI (0x00, 0x50, 0xF2, 0x02, 0x08) +{ + version, 1 MUSTBE 1; + delay, 4; +} + +IE WMMSchedule (EID_VENDOR_SPECIFIC) OUI (0x00, 0x50, 0xF2, 0x02, 0x09) +{ + version, 1 MUSTBE 1; + + { + aggregation: 1; + tsid: 4; + direction: 2; + reserved: 9; + } + + service_start_time, 4; + service_interval, 4; + max_service_dur, 2; + spec_interval, 2; +} + +IE ESERadMgmtCap (EID_VENDOR_SPECIFIC) OUI (0x00, 0x40, 0x96, 0x01) +{ + + mgmt_state, 1; + + { + mbssid_mask: 3; + reserved: 5; + } + +} + +IE Vendor1IE (EID_VENDOR_SPECIFIC) OUI (0x00, 0x10, 0x18) +{ +} + +IE Vendor3IE (EID_VENDOR_SPECIFIC) OUI (0x00, 0x16, 0x32) +{ +} + +IE hs20vendor_ie (EID_VENDOR_SPECIFIC) OUI (0x50, 0x6F, 0x9A, 0x10) +{ + /* hotspot_configurations */ + { + dgaf_dis: 1; + hs_id_present: 2; + reserved: 1; + release_num: 4; + } + OPTIONAL UNION hs_id (DISCRIMINATOR hs_id_present) + { + pps_mo (hs_id_present IS 1) + { + pps_mo_id, 2; + } + anqp_domain (hs_id_present IS 2) + { + anqp_domain_id, 2; + } + }; +} + +IE QComVendorIE (EID_VENDOR_SPECIFIC) OUI (0x00, 0xA0, 0xC6) +{ + type, 1; + channel, 1; +} + +IE ESETrafStrmMet (EID_VENDOR_SPECIFIC) OUI (0x00, 0x40, 0x96, 0x07) +{ + tsid, 1; + state, 1; + msmt_interval, 2; +} + +IE ESETrafStrmRateSet (EID_VENDOR_SPECIFIC) OUI (0x00, 0x40, 0x96, 0x08) +{ + tsid, 1; + tsrates[0..8]; +} + +IE ESEVersion (EID_VENDOR_SPECIFIC) OUI (0x00, 0x40, 0x96, 0x03) +{ + version, 1; +} + +IE ESETxmitPower (EID_ESE_SPECIFIC) OUI (0x00, 0x40, 0x96, 0x00) +{ + power_limit, 1; + reserved, 1; +} + +IE ESECckmOpaque (EID_ESE_CCKM_SPECIFIC) OUI (0x00, 0x40, 0x96, 0x00) +{ + data[ 6..20 ]; +} + +IE RRMEnabledCap (EID_RRM_ENABLED_CAPS) +{ + //Capability bitmap + { + LinkMeasurement: 1; + NeighborRpt: 1; + parallel: 1; + repeated: 1; + BeaconPassive: 1; + BeaconActive: 1; + BeaconTable: 1; + BeaconRepCond: 1; + } + { + FrameMeasurement: 1; + ChannelLoad: 1; + NoiseHistogram: 1; + statistics: 1; + LCIMeasurement: 1; + LCIAzimuth: 1; + TCMCapability: 1; + triggeredTCM: 1; + } + { + APChanReport: 1; + RRMMIBEnabled: 1; + operatingChanMax: 3; + nonOperatinChanMax: 3; + } + { + MeasurementPilot: 3; + MeasurementPilotEnabled: 1; + NeighborTSFOffset: 1; + RCPIMeasurement: 1; + RSNIMeasurement: 1; + BssAvgAccessDelay: 1; + } + { + BSSAvailAdmission: 1; + AntennaInformation: 1; + fine_time_meas_rpt: 1; + lci_capability: 1; + reserved: 4; + } +} + +IE MeasurementPilot (EID_RRM_MEAS_PILOT_TX_INFO) +{ + measurementPilot, 1; + vendorSpecific[0..255]; //Should be an IE. But currently only one level of nesting allowed. Can ignore for now. +} + +IE MultiBssid (EID_MULTIPLE_BSSID) +{ + maxBSSIDIndicator, 1; + vendorSpecific[0..255]; +} + +IE OBSSScanParameters (EID_OBSS_SCAN_PARAMETERS) +{ + obssScanPassiveDwell, 2; + obssScanActiveDwell, 2; + bssChannelWidthTriggerScanInterval, 2; + obssScanPassiveTotalPerChannel, 2; + obssScanActiveTotalPerChannel, 2; + bssWidthChannelTransitionDelayFactor, 2; + obssScanActivityThreshold, 2; +} + +IE ht2040_bss_coexistence (EID_20_40_BSS_COEXISTENCE) +{ + // 20/40 BSS Coexistence Information + { + info_request: 1; + forty_mhz_intolerant: 1; + twenty_mhz_bsswidth_req: 1; + obss_scan_exemption_req: 1; + obss_scan_exemption_grant: 1; + unused: 3; + } +} + +IE ht2040_bss_intolerant_report (EID_20_40_BSS_INTOLERANT_REPORT) +{ + operating_class, 1; + channel_list[0..50]; +} + +const EID_RRM_NBR_RPT_TSF = 1; +const EID_RRM_NBR_CD_COUNTRY = 2; + +IE TSFInfo (EID_RRM_NBR_RPT_TSF) +{ + TsfOffset, 2; + BeaconIntvl, 2; +} +IE CondensedCountryStr (EID_RRM_NBR_CD_COUNTRY) +{ + countryStr[2]; +} + +IE NeighborReport (EID_NEIGHBOR_REPORT) +{ + bssid[6]; + //Bssid Info + { + APReachability: 2; + Security: 1; + KeyScope: 1; + //Capabilities + SpecMgmtCap: 1; + QosCap: 1; + apsd: 1; + rrm: 1; + } + //Capabilities contd. + { + DelayedBA: 1; + ImmBA: 1; + //Capabilities end. + MobilityDomain: 1; + reserved: 5; + } + + reserved1, 2; //part of BSSID Info. + + regulatoryClass, 1; + channel, 1; + PhyType, 1; + OPTIE IE TSFInfo; + OPTIE IE CondensedCountryStr; + OPTIE IE MeasurementPilot; + OPTIE IE RRMEnabledCap; + OPTIE IE MultiBssid; + //Ignoring vendor specific. +} + +IE RCPIIE (EID_RCPI) +{ + rcpi, 1; +} + +IE RSNIIE (EID_RSNI) +{ + rsni, 1; +} + +IE WFATPC (EID_VENDOR_SPECIFIC) OUI (0x00, 0x50, 0xF2, 0x08, 0x00) +{ + txPower, 1; + linkMargin, 1; +} + +IE MobilityDomain (EID_FT_MOBILITY_DOMAIN) +{ + MDID, 2; + //FT Capability and policy + { + overDSCap: 1; + resourceReqCap: 1; + reserved: 6; + } +} +const SUB_EID_FT_R1KH_ID = 1; +const SUB_EID_FT_GTK = 2; +const SUB_EID_FT_R0KH_ID = 3; +const SUB_EID_FT_IGTK = 4; +IE FTInfo (EID_FT_INFO) +{ + // MicControl, 2; + { + reserved: 8; + IECount: 8; + } + MIC[16]; + Anonce[32]; + Snonce[32]; + + OPTIE IE R1KH_ID (SUB_EID_FT_R1KH_ID) + { + PMK_R1_ID[6]; + } + + OPTIE IE GTK (SUB_EID_FT_GTK) + { + //Key Info + { + keyId: 2; + reserved: 14; + } + keyLength, 1; + RSC[8]; + key[5..32]; + } + + OPTIE IE R0KH_ID (SUB_EID_FT_R0KH_ID) + { + PMK_R0_ID[1..48]; + } + + OPTIE IE IGTK (SUB_EID_FT_IGTK) + { + //Key Info + keyID[2]; + IPN[6]; + keyLength, 1; + key[24]; + } +} + +IE TimeoutInterval (EID_TIMEOUT_INTERVAL) +{ + timeoutType, 1; + timeoutValue, 4; +} + +//TODO: need to define this properly. +IE RICData (EID_FT_RIC_DATA) +{ + Identifier, 1; + resourceDescCount, 1; + statusCode, 2; +} + +IE RICDescriptor (EID_FT_RIC_DESCRIPTOR) +{ + resourceType, 1; + variableData[0..255]; //Block ack param set...TODO: +} + +IE WscIEOpaque (EID_VENDOR_SPECIFIC) OUI ( 0x00, 0x50, 0xF2, 0x04 ) +{ + data[ 2..249 ]; +} + +IE P2PIEOpaque (EID_VENDOR_SPECIFIC) OUI ( 0x50, 0x6F, 0x9A, 0x09 ) +{ + data[ 2..249 ]; +} + +IE WFDIEOpaque (EID_VENDOR_SPECIFIC) OUI ( 0x50, 0x6F, 0x9A, 0x0A ) +{ + data[ 2..249 ]; +} + +IE PTIControl (EID_PTI_CONTROL) // 7.3.2.65 +{ + tid, 1; + sequence_control, 2; +} + +IE PUBufferStatus (EID_PU_BUFFER_STATUS) // 7.3.2.66 +{ + { + ac_bk_traffic_aval: 1; + ac_be_traffic_aval: 1; + ac_vi_traffic_aval: 1; + ac_vo_traffic_aval: 1; + reserved: 4; + } +} + + + +IE VHTCaps (EID_VHT_CAPABILITIES) +{ + //VHT Capability Info + { + maxMPDULen: 2; + supportedChannelWidthSet: 2; + ldpcCodingCap: 1; + shortGI80MHz: 1; + shortGI160and80plus80MHz: 1; + txSTBC: 1; + rxSTBC: 3; + suBeamFormerCap: 1; + suBeamformeeCap: 1; + csnofBeamformerAntSup: 3; + numSoundingDim: 3; + muBeamformerCap: 1; + muBeamformeeCap: 1; + vhtTXOPPS: 1; + htcVHTCap: 1; + maxAMPDULenExp: 3; + vhtLinkAdaptCap: 2; + rxAntPattern: 1; + txAntPattern: 1; + reserved1: 2; + } + rxMCSMap, 2; + { + rxHighSupDataRate: 13; + reserved2: 3; + } + txMCSMap, 2; + { + txSupDataRate: 13; + reserved3: 3; + } +} + +IE VHTOperation (EID_VHT_OPERATION_ELEMENT) +{ + chanWidth, 1; + chanCenterFreqSeg1, 1; + chanCenterFreqSeg2, 1; + basicMCSSet, 2; +} + +IE VHTExtBssLoad (EID_VHT_EXT_BSS_LOAD) +{ + muMIMOCapStaCount, 1; + ssUnderUtil, 1; + FortyMHzUtil, 1; + EightyMHzUtil, 1; + OneSixtyMHzUtil, 1; +} + +IE AID (EID_AID) +{ + assocId, 2; +} + +IE WiderBWChanSwitchAnn (EID_WIDER_BW_CHANNEL_SWITCH_ANN) +{ + newChanWidth, 1; + newCenterChanFreq0, 1; + newCenterChanFreq1, 1; +} + +IE vht_transmit_power_env (VHT_TRANSMIT_POWER_ENVELOPE) +{ + bytes[2..5]; +} + +IE ChannelSwitchWrapper (EID_CHANNEL_SWITCH_WRAPPER) +{ + OPTIE IE WiderBWChanSwitchAnn; + OPTIE IE vht_transmit_power_env; +} +IE ExtCap (EID_EXT_CAP) +{ + bytes[1..15]; +} + +IE HTCaps (EID_HT_CAPABILITIES) +{ + // HT Capability Info + { + advCodingCap: 1; + supportedChannelWidthSet: 1; + mimoPowerSave: 2; + greenField: 1; + shortGI20MHz: 1; + shortGI40MHz: 1; + txSTBC: 1; + rxSTBC: 2; + delayedBA: 1; + maximalAMSDUsize: 1; + dsssCckMode40MHz: 1; + psmp: 1; + stbcControlFrame: 1; + lsigTXOPProtection: 1; + } + // HT Parameters Info; + { + maxRxAMPDUFactor: 2; + mpduDensity: 3; + reserved1: 3; + } + + supportedMCSSet[ HT_MAX_SUPPORTED_MCS_SET ]; + + // Extended HT Capability Info + { + pco: 1; + transitionTime: 2; + reserved2: 5; + mcsFeedback: 2; + reserved3: 6; + } + // TXBF Capability Info + { + txBF: 1; + rxStaggeredSounding: 1; + txStaggeredSounding: 1; + rxZLF: 1; + txZLF: 1; + implicitTxBF: 1; + calibration: 2; + explicitCSITxBF: 1; + explicitUncompressedSteeringMatrix: 1; + explicitBFCSIFeedback: 3; + explicitUncompressedSteeringMatrixFeedback: 3; + explicitCompressedSteeringMatrixFeedback: 3; + csiNumBFAntennae: 2; + uncompressedSteeringMatrixBFAntennae: 2; + compressedSteeringMatrixBFAntennae: 2; + reserved4: 7; + } + // AS Capability Info + { + antennaSelection: 1; + explicitCSIFeedbackTx: 1; + antennaIndicesFeedbackTx: 1; + explicitCSIFeedback: 1; + antennaIndicesFeedback: 1; + rxAS: 1; + txSoundingPPDUs: 1; + reserved5: 1; + } + //TODO: take it out when generic fix to remove extra bytes in IE is available. + //This is required to interop with Dlink AP which is sending 2 bytes extra in HTInfo IE. + rsvd[0..32]; + +} // End IE HTCaps. + +IE HTInfo (EID_HT_INFO) +{ + primaryChannel, 1; + + // ahtInfoField1 + { + secondaryChannelOffset: 2; + recommendedTxWidthSet: 1; + rifsMode: 1; + controlledAccessOnly: 1; + serviceIntervalGranularity: 3; + } + + // ahtInfoField2 + + + // ahtInfoField2 + { + opMode: 2; + nonGFDevicesPresent: 1; + transmitBurstLimit: 1; + obssNonHTStaPresent:1; + reserved: 11; + } + + + // ahtInfoField3 + { + basicSTBCMCS: 7; + dualCTSProtection: 1; + secondaryBeacon: 1; + lsigTXOPProtectionFullSupport: 1; + pcoActive: 1; + pcoPhase: 1; + reserved2: 4; + } + + basicMCSSet[ HT_MAX_SUPPORTED_MCS_SET ]; + + //TODO: take it out when generic fix to remove extra bytes in IE is available. + //This is required to interop with Dlink AP which is sending 2 bytes extra in HTInfo IE. + rsvd[0..32]; + +} // End IE HTInfo. + + +IE OperatingMode (EID_OPERATING_MODE) +{ + { //Operating Mode field + chanWidth: 2; + reserved: 2; + rxNSS: 3; + rxNSSType: 1; + } +} + +IE QosMapSet (EID_QOS_MAP_SET) +{ + dscp_exceptions[0..60]; +} + +CONTAINERIE RICDataDesc +{ + MANDIE RICData; + OPTIE RICDescriptor; + OPTIE TSPEC; + OPTIE TCLAS[0..2]; + OPTIE TCLASSPROC; + OPTIE TSDelay; + OPTIE Schedule; + OPTIE WMMTSPEC; + OPTIE WMMTCLAS[0..2]; + OPTIE WMMTCLASPROC; + OPTIE WMMTSDelay; + OPTIE WMMSchedule; +} + +IE TimeAdvertisement (EID_TIME_ADVERTISEMENT) // 8.4.2.63 +{ + timing_capabilities, 1; + time_value[10]; + time_error[5]; +} + +IE MBO_IE (EID_VENDOR_SPECIFIC) OUI ( 0x50, 0x6F, 0x9A, 0x16 ) +{ + mbo_cap[3]; + assoc_disallowed[0..3]; +} + +IE QCN_IE (EID_VENDOR_SPECIFIC) OUI ( 0x8C, 0xFD, 0xF0, 0x01 ) +{ + version[4]; +} + +const EID_RRM_BEACON_REPORTING = 1; +const EID_RRM_BCN_REPORTING_DETAIL = 2; + +const SUB_EID_AZIMUTH_REQ = 1; +const SUB_EID_REQ_MAC_ADDR = 2; +const SUB_EID_TGT_MAC_ADDR = 3; +const SUB_EID_MAX_AGE = 4; +const SUB_EID_NEIGHBOR_RPT = 52; + +IE BeaconReporting (EID_RRM_BEACON_REPORTING) +{ + reportingCondition, 1; + threshold, 1; +} + +IE BcnReportingDetail (EID_RRM_BCN_REPORTING_DETAIL) +{ + reportingDetail, 1; +} + +IE APChannelReport (EID_AP_CHAN_REPORT) +{ + regulatoryClass, 1; + channelList[0..50]; +} + +IE azimuth_req (SUB_EID_AZIMUTH_REQ) +{ + request, 1; +} + +IE req_mac_addr (SUB_EID_REQ_MAC_ADDR) +{ + addr[6]; +} + +IE tgt_mac_addr (SUB_EID_TGT_MAC_ADDR) +{ + addr[6]; +} + +IE max_age (SUB_EID_MAX_AGE) +{ + max_age, 2; +} + +IE neighbor_rpt (SUB_EID_NEIGHBOR_RPT) +{ + bssid[6]; + //Bssid Info + { + APReachability: 2; + Security: 1; + KeyScope: 1; + //Capabilities + SpecMgmtCap: 1; + QosCap: 1; + apsd: 1; + rrm: 1; + } + //Capabilities contd. + { + DelayedBA: 1; + ImmBA: 1; + //Capabilities end. + MobilityDomain: 1; + reserved: 5; + } + reserved1, 2; //part of BSSID Info. + regulatoryClass, 1; + channel, 1; + PhyType, 1; + OPTIE IE TSFInfo; + OPTIE IE CondensedCountryStr; + OPTIE IE MeasurementPilot; + OPTIE IE RRMEnabledCap; + OPTIE IE MultiBssid; +} + +IE MeasurementRequest (EID_MEAS_REQUEST) // 7.3.2.21 +{ + measurement_token, 1; + + // Measurement Request Mode + { + parallel: 1; + enable: 1; + request: 1; + report: 1; + durationMandatory: 1; + unused: 3; + } + + measurement_type, 1; + UNION measurement_request (DISCRIMINATOR measurement_type) + { + Basic (measurement_type IS 0) + { + channel_no, 1; + meas_start_time[8]; + meas_duration, 2; + } + CCA (measurement_type IS 1) + { + channel_no, 1; + meas_start_time[8]; + meas_duration, 2; + } + RPIHistogram (measurement_type IS 2) + { + channel_no, 1; + meas_start_time[8]; + meas_duration, 2; + } + Beacon (measurement_type IS 5) + { + regClass, 1; + channel, 1; + randomization, 2; + meas_duration, 2; + meas_mode, 1; + BSSID[6]; + OPTIE SSID; + OPTIE BeaconReporting; + OPTIE BcnReportingDetail; + OPTIE RequestedInfo; + OPTIE APChannelReport[0..2]; + //OPTIONAL vendor_specific[1..239]; + } + lci (measurement_type IS 8) + { + loc_subject, 1; + OPTIE azimuth_req; + OPTIE req_mac_addr; + OPTIE tgt_mac_addr; + OPTIE max_age; + } + ftmrr (measurement_type IS 16) + { + random_interval, 2; + min_ap_count, 1; + + OPTIE neighbor_rpt; + OPTIE max_age; + } + + }; +} + +///////////////////////////////////////////////////////////////////////////// +// MULTIIEs // +///////////////////////////////////////////////////////////////////////////// + +MULTIIE WSC ( EID_VENDOR_SPECIFIC ) OUI( 0x00, 0x50, 0xF2, 0x04 ) +{ + MANDATORYTLV Version; // Must be 0x10 + OPTIONALTLV WPSState; + OPTIONALTLV APSetupLocked; + OPTIONALTLV SelectedRegistrarConfigMethods; + OPTIONALTLV UUID_E; + OPTIONALTLV UUID_R; + OPTIONALTLV RFBands; + OPTIONALTLV SelectedRegistrar; + OPTIONALTLV ConfigMethods; + OPTIONALTLV AssociationState; + OPTIONALTLV ConfigurationError; + OPTIONALTLV Manufacturer; + OPTIONALTLV ModelName; + OPTIONALTLV ModelNumber; + OPTIONALTLV SerialNumber; + OPTIONALTLV DeviceName; + OPTIONALTLV DevicePasswordID; + OPTIONALTLV PrimaryDeviceType; + OPTIONALTLV RequestType; + OPTIONALTLV ResponseType; + OPTIONALTLV VendorExtension; + OPTIONALTLV RequestDeviceType; +} + +MULTIIE WscBeacon ( EID_VENDOR_SPECIFIC ) OUI( 0x00, 0x50, 0xF2, 0x04 ) +{ + MANDATORYTLV Version; // 0x10 = version 1.0, 0x11 + // = version 1.1, etc. + MANDATORYTLV WPSState; // 1 = unconfigured, 2 = + // configured + OPTIONALTLV APSetupLocked; // Must be included if value + // is TRUE + OPTIONALTLV SelectedRegistrar; // BOOL: indicates if the + // user has recently + // activated a Registrar to + // add an Enrollee. + OPTIONALTLV DevicePasswordID; // Device Password ID + // indicates the method or + // identifies the specific + // password that the + // selected Registrar + // intends to use. + OPTIONALTLV SelectedRegistrarConfigMethods; // This attribute contains + // the config methods active + // on the selected + // Registrar. + OPTIONALTLV UUID_E; // The AP's UUID is provided + // only when the AP is a + // dual-band AP in push + // button mode and + // indicating push button + // mode on both radios + OPTIONALTLV RFBands; // Indicates all RF bands + // available on the AP. A + // dual-band AP must provide + // this attribute. + // WSC 2.0 + OPTIONALTLV VendorExtension; // Version2 and AuthorizedMACs + +} // End Multi-IE WscBeacon. + +MULTIIE WscAssocReq ( EID_VENDOR_SPECIFIC ) OUI( 0x00, 0x50, 0xF2, 0x04 ) +{ + MANDATORYTLV Version; // 0x10 = version 1.0, 0x11 + // = version 1.1, etc. + MANDATORYTLV RequestType; // + // + // WSC 2.0 + OPTIONALTLV VendorExtension; // Version2 + +} // End Multi-IE WscAssocReq. + + +MULTIIE WscAssocRes ( EID_VENDOR_SPECIFIC ) OUI( 0x00, 0x50, 0xF2, 0x04 ) +{ + MANDATORYTLV Version; // 0x10 = version 1.0, 0x11 + // = version 1.1, etc. + MANDATORYTLV ResponseType; // + // + // WSC 2.0 + OPTIONALTLV VendorExtension; // Version2 + +} // End Multi-IE WscAssocRes. + +MULTIIE WscReassocRes ( 221 ) OUI( 0x00, 0x50, 0xF2, 0x04 ) +{ + MANDATORYTLV Version; // 0x10 = version 1.0, 0x11 + // = version 1.1, etc. + MANDATORYTLV ResponseType; // + // + // WSC 2.0 + OPTIONALTLV VendorExtension; // Version2 + +} // End Multi-IE WscReassocRes + +MULTIIE WscProbeReq ( EID_VENDOR_SPECIFIC ) OUI( 0x00, 0x50, 0xF2, 0x04 ) +{ + MANDATORYTLV Version; // 0x10 = version 1.0, 0x11 + // = version 1.1, etc. + MANDATORYTLV RequestType; // + // + MANDATORYTLV ConfigMethods; // Configuration methods the + // Enrollee or Registrar + // supports + MANDATORYTLV UUID_E; // unique GUID generated by + // the Enrollee. + MANDATORYTLV PrimaryDeviceType; + MANDATORYTLV RFBands; // Specific RF bands used + // for this message + MANDATORYTLV AssociationState; // Configuration and previous + // association state + MANDATORYTLV ConfigurationError; + MANDATORYTLV DevicePasswordID; + + // WSC 2.0 + OPTIONALTLV Manufacturer; // Must be included in ver 2.0 + // or higher. + OPTIONALTLV ModelName; // Must be included in ver 2.0 + // or higher. + OPTIONALTLV ModelNumber; // Must be included in ver 2.0 + // or higher. + OPTIONALTLV DeviceName; // Must be included in ver 2.0 + // or higher. + OPTIONALTLV VendorExtension; // Version2 and RequestToEntroll + + OPTIONALTLV RequestDeviceType; // When a device receives a Probe + // Request containing this type, + // It will only reponse if Primary + // or Secondary Device Type matches. + +} // End Multi-IE WscProbeReq. + +MULTIIE WscProbeRes ( EID_VENDOR_SPECIFIC ) OUI( 0x00, 0x50, 0xF2, 0x04 ) +{ + MANDATORYTLV Version; // 0x10 = version 1.0, 0x11 + // = version 1.1, etc. + MANDATORYTLV WPSState; // 1 = unconfigured, 2 = + // configured + OPTIONALTLV APSetupLocked; // Must be included if value + // is TRUE + OPTIONALTLV SelectedRegistrar; // BOOL: indicates if the + // user has recently + // activated a Registrar to + // add an Enrollee. + OPTIONALTLV DevicePasswordID; // Device Password ID + // indicates the method or + // identifies the specific + // password that the + // selected Registrar + // intends to use. + OPTIONALTLV SelectedRegistrarConfigMethods; // This attribute contains + // the config methods active + // on the selected + // Registrar. + MANDATORYTLV ResponseType; + MANDATORYTLV UUID_E; // unique identifier of AP + MANDATORYTLV Manufacturer; + MANDATORYTLV ModelName; + MANDATORYTLV ModelNumber; + MANDATORYTLV SerialNumber; + MANDATORYTLV PrimaryDeviceType; + MANDATORYTLV DeviceName; // User-friendly description + // of device + MANDATORYTLV ConfigMethods; // Config Methods corresponds + // to the methods the AP + // supports as an Enrollee + // for adding external + // Registrars. + OPTIONALTLV RFBands; // Indicates all RF bands + // available on the AP. A + // dual-band AP must provide + // this attribute. + // WSC 2.0 + OPTIONALTLV VendorExtension; // Version2 and AuthorizedMACs + +} // WscProbeRes. + +// This MULTIIE combines the fields from the WSC IEs as they appear in +// Beacons *and* in Probe Responses, with the difference that they're all +// optional. In our device drivers, we combine Probe Responses and Beacons +// into one list, and parse their IEs later (c.f. frame BeaconIEs). Because +// the WSC IE differs in those two frames, we'd often see warning messages +// about either unexpected fields showing up (if we thought we were parsing a +// Beacon, and we in fact had data from a Probe Response) or mandatory fields +// missing (if we thought we were parsing a Probe Response, and in fact had +// data from a Beacon). + +// I created this MULTIIE to stuff into the BeaconIEs frames to avoid this. +// It's intended to be used on unpack only, and to do so in a very forgiving +// way. + +MULTIIE WscBeaconProbeRes ( EID_VENDOR_SPECIFIC ) OUI( 0x00, 0x50, 0xF2, 0x04 ) +{ + OPTIONALTLV Version; // 0x10 = version 1.0, 0x11 + // = version 1.1, etc. + OPTIONALTLV WPSState; // 1 = unconfigured, 2 = + // configured + OPTIONALTLV APSetupLocked; // Must be included if value + // is TRUE + OPTIONALTLV SelectedRegistrar; // BOOL: indicates if the + // user has recently + // activated a Registrar to + // add an Enrollee. + OPTIONALTLV DevicePasswordID; // Device Password ID + // indicates the method or + // identifies the specific + // password that the + // selected Registrar + // intends to use. + OPTIONALTLV SelectedRegistrarConfigMethods; // This attribute contains + // the config methods active + // on the selected + // Registrar. + OPTIONALTLV ResponseType; + OPTIONALTLV UUID_E; // unique identifier of AP + OPTIONALTLV Manufacturer; + OPTIONALTLV ModelName; + OPTIONALTLV ModelNumber; + OPTIONALTLV SerialNumber; + OPTIONALTLV PrimaryDeviceType; + OPTIONALTLV DeviceName; // User-friendly description + // of device + OPTIONALTLV ConfigMethods; // Config Methods corresponds + // to the methods the AP + // supports as an Enrollee + // for adding external + // Registrars. + OPTIONALTLV RFBands; // Indicates all RF bands + // available on the AP. A + // dual-band AP must provide + // this attribute. + // WSC 2.0 + OPTIONALTLV VendorExtension; // Version2 and AuthorizedMACs + +} // WscProbeRes. +///////////////////////////////////////////////////////////////////////////// +// MULTIIEs // +///////////////////////////////////////////////////////////////////////////// + +MULTIIE P2PBeacon ( EID_VENDOR_SPECIFIC ) OUI( 0x50, 0x6F, 0x9A, 0x09 ) +{ + MANDATORYTLV P2PCapability; // Contains P2P Device + // and P2P Group Capability + MANDATORYTLV P2PDeviceId; // Contains P2P Device + // Address + OPTIONALTLV NoticeOfAbsence; // Indicates Notice of + // Absence schedule and + // CT Window + +} // End P2PBeacon + + +MULTIIE P2PAssocReq ( EID_VENDOR_SPECIFIC ) OUI( 0x50, 0x6F, 0x9A, 0x09 ) +{ + MANDATORYTLV P2PCapability; // Contains P2P Device + // and P2P Group Capability + OPTIONALTLV ExtendedListenTiming; + MANDATORYTLV P2PDeviceInfo; + +} // End P2PAssocReq + + +MULTIIE P2PAssocRes ( EID_VENDOR_SPECIFIC ) OUI( 0x50, 0x6F, 0x9A, 0x09 ) +{ + MANDATORYTLV P2PStatus; + OPTIONALTLV ExtendedListenTiming; + +} // End P2PAssocRes + + +MULTIIE P2PProbeReq ( EID_VENDOR_SPECIFIC ) OUI( 0x50, 0x6F, 0x9A, 0x09 ) +{ + MANDATORYTLV P2PCapability; + OPTIONALTLV P2PDeviceId; + MANDATORYTLV ListenChannel; + OPTIONALTLV ExtendedListenTiming; + OPTIONALTLV OperatingChannel; +} // End P2PProbeReq + + +MULTIIE P2PProbeRes ( EID_VENDOR_SPECIFIC ) OUI( 0x50, 0x6F, 0x9A, 0x09 ) +{ + MANDATORYTLV P2PCapability; + OPTIONALTLV ExtendedListenTiming; + OPTIONALTLV NoticeOfAbsence; + MANDATORYTLV P2PDeviceInfo; + OPTIONALTLV P2PGroupInfo; + +} // End P2PProbeRes + + +MULTIIE P2PBeaconProbeRes ( EID_VENDOR_SPECIFIC ) OUI( 0x50, 0x6F, 0x9A, 0x09 ) +{ + OPTIONALTLV P2PCapability; + OPTIONALTLV P2PDeviceId; + OPTIONALTLV ExtendedListenTiming; + OPTIONALTLV NoticeOfAbsence; + OPTIONALTLV P2PDeviceInfo; + OPTIONALTLV P2PGroupInfo; + +} // End P2PBeaconProbeRes + + +MULTIIE P2PDeAuth ( EID_VENDOR_SPECIFIC ) OUI( 0x50, 0x6F, 0x9A, 0x09 ) +{ + MANDATORYTLV MinorReasonCode; +} + + +MULTIIE P2PDisAssoc ( EID_VENDOR_SPECIFIC ) OUI( 0x50, 0x6F, 0x9A, 0x09 ) +{ + MANDATORYTLV MinorReasonCode; +} + +IE vendor_vht_ie (EID_VENDOR_SPECIFIC) OUI (0x00, 0x90, 0x4c) +{ + type, 1; + sub_type, 1; + OPTIE IE VHTCaps; + OPTIE IE VHTOperation; +} + +///////////////////////////////////////////////////////////////////////////// +// Frames + +FRAME Beacon // C.f. Sec. 7.2.3.1 +{ + FF TimeStamp; + FF BeaconInterval; + FF Capabilities; + MANDIE SSID; + MANDIE SuppRates; + OPTIE FHParamSet; + OPTIE DSParams; + OPTIE CFParams; + OPTIE IBSSParams; + OPTIE TIM; + OPTIE Country; + OPTIE FHParams; + OPTIE FHPattTable; + OPTIE PowerConstraints; + OPTIE ChanSwitchAnn; + OPTIE ext_chan_switch_ann; + OPTIE SuppOperatingClasses; + OPTIE Quiet; + OPTIE TPCReport; + OPTIE ERPInfo; + OPTIE ExtSuppRates; + OPTIE RSN; + OPTIE QBSSLoad; + OPTIE EDCAParamSet; + OPTIE QOSCapsAp; + OPTIE APChannelReport; + OPTIE RRMEnabledCap; + OPTIE MobilityDomain; + OPTIE WPA; + OPTIE HTCaps; + OPTIE HTInfo; + OPTIE sec_chan_offset_ele; + OPTIE WMMInfoAp; + OPTIE WMMParams; + OPTIE WMMCaps; + OPTIE WAPI; + OPTIE ESERadMgmtCap; + OPTIE ESETrafStrmMet; + OPTIE ESETxmitPower; + + OPTIE WscBeacon; + OPTIE P2PBeacon; + OPTIE VHTCaps; + OPTIE VHTOperation; + OPTIE VHTExtBssLoad; + OPTIE ExtCap; + OPTIE OperatingMode; + OPTIE WiderBWChanSwitchAnn; + OPTIE OBSSScanParameters; + OPTIE Vendor1IE; + OPTIE vendor_vht_ie; + OPTIE Vendor3IE; + OPTIE hs20vendor_ie; + OPTIE ChannelSwitchWrapper; + OPTIE QComVendorIE; + OPTIE ESEVersion; + OPTIE MBO_IE; + OPTIE QCN_IE; +} // End frame Beacon. + +// Ok, here's the story on Beacon1 & Beacon2. We presumably beacon a lot +// more than we change configuration. So it makes sense to keep the beacon +// we plan to send next in serialized format. We do this in struct schMisc. +// Whenever our config changes in a way that would affect our beacons, we +// just update our internal datastructures & re-generate the serialized +// beacon. + +// The problem is that there are *some* fields that need to be updated at +// send time, specifically the CF Param Set & the TIM. So, what we do is +// this: whenever our config changes, call schSetFixedBeaconFields. There, +// we serialize the following Beacon fields into gSchBeaconFrameBegin (after +// the power template & MAC header): TimeStamp, BeaconInterval, Capabilities, +// SSID, SuppRates, DSParams, & IBSSParams. It sets gSchBeaconOffsetBegin to +// the length of this buffer (incl. power template & MAC header). + +// Next, it serializes the following fields into gSchBeaconFrameEnd: Country, +// EDCAParamSet, PowerConstraints, TPCReport, ChannelSwitchAnn, Quiet, +// ERPInfo, HTCaps, HTInfo, ExtSuppRates, WPA, RSN, WMMInfo, +// WMMParams, WMMCaps. +// The length of *this* buffer is kept in gSchBeaconOffsetEnd. + +// Then, in 'schBeaconInterruptHandler', we write CFParams & TIM at the end +// of gSchBeaconFrameBegin, keeping track of the (new) size of this buffer in +// the local 'beaconSize'. + +// After that, we call 'specialBeaconProcessing'. Note that this may +// actually call schSetFixedBeaconFields repeatedly! The comments say they +// try to avoid this, but... + +// Finally, we call writeBeaconToTFP, where the first thing we do is copy the +// gSchBeaconFrameEnd buffer after the end of gSchBeaconFrameBegin. + +FRAME Beacon1 +{ + FF TimeStamp; + FF BeaconInterval; + FF Capabilities; + MANDIE SSID; + MANDIE SuppRates; + OPTIE DSParams; + OPTIE IBSSParams; +} + +FRAME Beacon2 +{ + OPTIE Country; + OPTIE PowerConstraints; + OPTIE ChanSwitchAnn; + OPTIE ext_chan_switch_ann; + OPTIE SuppOperatingClasses; + OPTIE Quiet; + OPTIE TPCReport; + OPTIE ERPInfo; + OPTIE ExtSuppRates; + OPTIE RSNOpaque; + OPTIE EDCAParamSet; + OPTIE APChannelReport; + OPTIE RRMEnabledCap; + OPTIE MobilityDomain; + OPTIE WPA; + OPTIE HTCaps; + OPTIE HTInfo; + OPTIE sec_chan_offset_ele; + OPTIE WMMInfoAp; + OPTIE WMMParams; + OPTIE WMMCaps; + OPTIE WscBeacon; + OPTIE WAPI; + OPTIE ESERadMgmtCap; + OPTIE ESETrafStrmMet; + OPTIE ESETxmitPower; + OPTIE P2PBeacon; + OPTIE VHTCaps; + OPTIE VHTOperation; + OPTIE VHTExtBssLoad; + OPTIE ExtCap; + OPTIE OperatingMode; + OPTIE WiderBWChanSwitchAnn; + OPTIE OBSSScanParameters; + OPTIE Vendor1IE; + OPTIE vendor_vht_ie; + OPTIE Vendor3IE; + OPTIE hs20vendor_ie; + OPTIE ChannelSwitchWrapper; + OPTIE QComVendorIE; + OPTIE ESEVersion; + OPTIE QCN_IE; +} + +// This frame is just Beacon with its Fixed Fields stripped out. It's handy +// for use with struct 'tSirBssDescription', which has members corresponding +// to some fixed fields, but keeps its IEs in un-parsed format. + +// Note that it also includes the IE 'WscBeaconProbeRes'. + +FRAME BeaconIEs +{ + + MANDIE SSID; + MANDIE SuppRates; + OPTIE FHParamSet; + OPTIE DSParams; + OPTIE CFParams; + OPTIE IBSSParams; + OPTIE TIM; + OPTIE Country; + OPTIE FHParams; + OPTIE FHPattTable; + OPTIE PowerConstraints; + OPTIE ChanSwitchAnn; + OPTIE ext_chan_switch_ann; + OPTIE SuppOperatingClasses; + OPTIE Quiet; + OPTIE TPCReport; + OPTIE ERPInfo; + OPTIE ExtSuppRates; + OPTIE RSN; + OPTIE QBSSLoad; + OPTIE EDCAParamSet; + OPTIE QOSCapsAp; + OPTIE APChannelReport; + OPTIE RRMEnabledCap; + OPTIE MobilityDomain; + OPTIE WPA; + OPTIE HTCaps; + OPTIE HTInfo; + OPTIE sec_chan_offset_ele; + OPTIE WMMInfoAp; + OPTIE WMMParams; + OPTIE WMMCaps; + OPTIE WAPI; + OPTIE ESEVersion; + OPTIE ESERadMgmtCap; + OPTIE ESETrafStrmMet; + OPTIE ESETxmitPower; + + OPTIE WscBeaconProbeRes; + OPTIE P2PBeaconProbeRes; + OPTIE VHTCaps; + OPTIE VHTOperation; + OPTIE VHTExtBssLoad; + OPTIE ExtCap; + OPTIE OperatingMode; + OPTIE WiderBWChanSwitchAnn; + OPTIE OBSSScanParameters; + OPTIE Vendor1IE; + OPTIE vendor_vht_ie; + OPTIE Vendor3IE; + OPTIE hs20vendor_ie; + OPTIE ChannelSwitchWrapper; + OPTIE QComVendorIE; + OPTIE MBO_IE; + OPTIE QCN_IE; +} // End frame BeaconIEs. + +FRAME Disassociation // 7.3.3.3 +{ + FF Reason; + OPTIE P2PDisAssoc; +} + +FRAME AssocRequest // 7.2.3.4 +{ + FF Capabilities; + FF ListenInterval; + MANDIE SSID; + MANDIE SuppRates; + OPTIE OperatingMode; + OPTIE PowerCaps; + OPTIE SuppChannels; + OPTIE HTCaps; + OPTIE QOSCapsStation; + OPTIE RSNOpaque; + OPTIE ExtSuppRates; + OPTIE MobilityDomain; + OPTIE SuppOperatingClasses; + OPTIE WAPIOpaque; + OPTIE WAPI; + OPTIE RRMEnabledCap; + OPTIE QosMapSet; + OPTIE ExtCap; + OPTIE VHTCaps; + OPTIE WPAOpaque; + OPTIE WMMCaps; + OPTIE WMMInfoStation; + OPTIE WscIEOpaque; + OPTIE ESERadMgmtCap; + OPTIE ESEVersion; + OPTIE P2PIEOpaque; + OPTIE WFDIEOpaque; + OPTIE vendor_vht_ie; + OPTIE hs20vendor_ie; + OPTIE QCN_IE; +} // End frame AssocRequest. + +FRAME AssocResponse // 7.2.3.5 +{ + FF Capabilities; + FF Status; + FF AID; + MANDIE SuppRates; + OPTIE ExtSuppRates; + OPTIE EDCAParamSet; + OPTIE RCPIIE; + OPTIE RSNIIE; + OPTIE RRMEnabledCap; + OPTIE MobilityDomain; + OPTIE FTInfo; + OPTIE RICDataDesc[2]; + OPTIE WPA; + OPTIE TimeoutInterval; + OPTIE HTCaps; + OPTIE HTInfo; + OPTIE WMMParams; + OPTIE WMMCaps; + OPTIE ESERadMgmtCap; + OPTIE ESETrafStrmMet; + OPTIE ESETxmitPower; + OPTIE WMMTSPEC[0..4]; + OPTIE WscAssocRes; + OPTIE P2PAssocRes; + OPTIE VHTCaps; + OPTIE VHTOperation; + OPTIE ExtCap; + OPTIE OBSSScanParameters; + OPTIE QosMapSet; + OPTIE vendor_vht_ie; + OPTIE QCN_IE; +} // End frame AssocResponse. + +FRAME ReAssocRequest // 7.2.3.6 +{ + FF Capabilities; + FF ListenInterval; + FF CurrentAPAddress; + MANDIE SSID; + MANDIE SuppRates; + OPTIE ExtSuppRates; + OPTIE PowerCaps; + OPTIE SuppChannels; + OPTIE RSNOpaque; + OPTIE QOSCapsStation; + OPTIE RRMEnabledCap; + OPTIE MobilityDomain; + OPTIE FTInfo; + OPTIE RICDataDesc[2]; + OPTIE WPAOpaque; + OPTIE HTCaps; + OPTIE WMMCaps; + OPTIE WMMInfoStation; + OPTIE WscIEOpaque; + OPTIE WAPIOpaque; + OPTIE WAPI; + OPTIE ESERadMgmtCap; + OPTIE ESEVersion; + OPTIE ESECckmOpaque; + OPTIE WMMTSPEC[0..4]; + OPTIE ESETrafStrmRateSet; + OPTIE P2PIEOpaque; + OPTIE WFDIEOpaque; + OPTIE VHTCaps; + OPTIE ExtCap; + OPTIE OperatingMode; + OPTIE QosMapSet; + OPTIE vendor_vht_ie; + OPTIE hs20vendor_ie; +} // End frame ReAssocRequest. + +FRAME ReAssocResponse // 7.2.3.7 +{ + FF Capabilities; + FF Status; + FF AID; + MANDIE SuppRates; + OPTIE ExtSuppRates; + OPTIE EDCAParamSet; + OPTIE RCPIIE; + OPTIE RSNIIE; + OPTIE RRMEnabledCap; + OPTIE RSNOpaque; + OPTIE MobilityDomain; + OPTIE FTInfo; + OPTIE RICDataDesc[2]; + OPTIE WPA; + OPTIE TimeoutInterval; + OPTIE HTCaps; + OPTIE HTInfo; + OPTIE WMMParams; + OPTIE ESERadMgmtCap; + OPTIE ESETrafStrmMet; + OPTIE ESETxmitPower; + OPTIE WMMTSPEC[0..4]; + OPTIE ESETrafStrmRateSet; + OPTIE WscReassocRes; + OPTIE P2PAssocRes; + OPTIE VHTCaps; + OPTIE VHTOperation; + OPTIE ExtCap; + OPTIE OBSSScanParameters; + OPTIE QosMapSet; + OPTIE vendor_vht_ie; +} // End frame ReAssocResponse. + +FRAME ProbeRequest // 7.2.3.8 +{ + MANDIE SSID; + MANDIE SuppRates; + OPTIE RequestedInfo; + OPTIE ExtSuppRates; + OPTIE DSParams; + OPTIE HTCaps; + OPTIE WscProbeReq; + OPTIE WFATPC; + OPTIE P2PProbeReq; + OPTIE VHTCaps; + OPTIE ExtCap; + OPTIE QCN_IE; +} // End frame ProbeRequest. + +FRAME ProbeResponse // 7.2.3.9 +{ + FF TimeStamp; + FF BeaconInterval; + FF Capabilities; + MANDIE SSID; + MANDIE SuppRates; + OPTIE FHParamSet; + OPTIE DSParams; + OPTIE CFParams; + OPTIE IBSSParams; + OPTIE Country; + OPTIE FHParams; + OPTIE FHPattTable; + OPTIE PowerConstraints; + OPTIE ChanSwitchAnn; + OPTIE ext_chan_switch_ann; + OPTIE SuppOperatingClasses; + OPTIE Quiet; + OPTIE TPCReport; + OPTIE ERPInfo; + OPTIE ExtSuppRates; + OPTIE RSNOpaque; + OPTIE QBSSLoad; + OPTIE EDCAParamSet; + OPTIE RRMEnabledCap; + OPTIE APChannelReport; + OPTIE MobilityDomain; + OPTIE WPA; + OPTIE HTCaps; + OPTIE HTInfo; + OPTIE sec_chan_offset_ele; + OPTIE WMMInfoAp; + OPTIE WMMParams; + OPTIE WMMCaps; + OPTIE WAPI; + OPTIE ESERadMgmtCap; + OPTIE ESETrafStrmMet; + OPTIE ESETxmitPower; + + OPTIE WscProbeRes; + OPTIE P2PProbeRes; + + OPTIE VHTCaps; + OPTIE VHTOperation; + OPTIE VHTExtBssLoad; + OPTIE ExtCap; + OPTIE OBSSScanParameters; + OPTIE Vendor1IE; + OPTIE vendor_vht_ie; + OPTIE Vendor3IE; + OPTIE hs20vendor_ie; + OPTIE ChannelSwitchWrapper; + OPTIE QComVendorIE; + OPTIE ESEVersion; + OPTIE MBO_IE; + OPTIE QCN_IE; +} // End frame ProbeResponse. + +FRAME Authentication // 7.2.3.10 +{ + FF AuthAlgo; + FF AuthSeqNo; + FF Status; + OPTIE ChallengeText; + OPTIE RSNOpaque; + OPTIE MobilityDomain; + OPTIE FTInfo; + OPTIE TimeoutInterval; + OPTIE RICDataDesc[2]; +} // End frame Auth. + +FRAME DeAuth // 7.2.3.11 +{ + FF Reason; + OPTIE P2PDeAuth; +} + +FRAME AddTSRequest // 7.4.2.1 +{ + + FF Category; + FF Action; + FF DialogToken; + MANDIE TSPEC; + OPTIE TCLAS[0..2]; + OPTIE TCLASSPROC; + + // These IEs aren't in the spec, but our extant code *will* parse them if + // they're present. I included them to preserve that capability + + OPTIE WMMTSPEC; + OPTIE WMMTCLAS[0..2]; + OPTIE WMMTCLASPROC; + OPTIE ESETrafStrmRateSet; + +} // End frame AddTSRequest. + +FRAME WMMAddTSRequest +{ + FF Category; + FF Action; + FF DialogToken; + FF StatusCode; + MANDIE WMMTSPEC; + OPTIE ESETrafStrmRateSet; +} // End Frame WMMAddTSRequest + +FRAME AddTSResponse // 7.4.2.2 +{ + + FF Category; + FF Action; + FF DialogToken; + FF Status; + MANDIE TSDelay; + MANDIE TSPEC; + OPTIE TCLAS[0..2]; + OPTIE TCLASSPROC; + OPTIE Schedule; + + // These IEs aren't in the spec, but our extant code *will* parse them if + // they're present. I included them to preserve that capability + OPTIE WMMTSDelay; + OPTIE WMMSchedule; + OPTIE WMMTSPEC; + OPTIE WMMTCLAS[0..2]; + OPTIE WMMTCLASPROC; + OPTIE ESETrafStrmMet; + +} // End frame AddTSResponse. + +FRAME WMMAddTSResponse +{ + + FF Category; + FF Action; + FF DialogToken; + FF StatusCode; + OPTIE WMMTSPEC; + OPTIE ESETrafStrmMet; + +} // End frame WMMAddTSResponse. + +FRAME DelTS // 7.4.2.3 +{ + FF Category; + FF Action; + FF TSInfo; + FF Reason; +} + +FRAME WMMDelTS +{ + FF Category; + FF Action; + FF DialogToken; + FF StatusCode; + MANDIE WMMTSPEC; +} + +FRAME TPCRequest +{ + FF Category; + FF Action; + FF DialogToken; + MANDIE TPCRequest; +} + +FRAME TPCReport +{ + FF Category; + FF Action; + FF DialogToken; + MANDIE TPCReport; +} + +FRAME ChannelSwitch +{ + FF Category; + FF Action; + MANDIE ChanSwitchAnn; + OPTIE sec_chan_offset_ele; + OPTIE WiderBWChanSwitchAnn; +} + +FRAME MeasurementRequest +{ + FF Category; + FF Action; + FF DialogToken; + MANDIE MeasurementRequest[1..4]; +} + +FRAME MeasurementReport +{ + FF Category; + FF Action; + FF DialogToken; + MANDIE MeasurementReport; +} + +FRAME SMPowerSave +{ + FF Category; + FF Action; + FF SMPowerModeSet; +} + +FRAME RadioMeasurementRequest +{ + FF Category; + FF Action; + FF DialogToken; + FF NumOfRepetitions; + //Measurement Request IE. + MANDIE MeasurementRequest[1..2]; +} + +FRAME RadioMeasurementReport +{ + FF Category; + FF Action; + FF DialogToken; + //Measurement Report elements. + MANDIE MeasurementReport[1..4]; +} + +FRAME LinkMeasurementRequest +{ + FF Category; + FF Action; + FF DialogToken; + FF TxPower; + FF MaxTxPower; + //Optional Sub Ies +} + +FRAME LinkMeasurementReport +{ + FF Category; + FF Action; + FF DialogToken; + FF TPCEleID; + FF TPCEleLen; + FF TxPower; + FF LinkMargin; + FF RxAntennaId; + FF TxAntennaId; + FF RCPI; + FF RSNI; + //Optional Vendor specific IEs ... ignoring +} + +FRAME NeighborReportRequest +{ + FF Category; + FF Action; + FF DialogToken; + OPTIE SSID; + //Optional vendor specific IE...ignoring. +} + +FRAME NeighborReportResponse +{ + FF Category; + FF Action; + FF DialogToken; + OPTIE NeighborReport[1..MAX_SUPPORTED_NEIGHBOR_RPT]; +} + +FRAME OperatingMode +{ + FF Category; + FF Action; + //Operating Mode field + FF OperatingMode; +} + +FRAME TDLSDisReq +{ + FF Category; + FF Action; + FF DialogToken; + MANDIE LinkIdentifier; +} + +FRAME TDLSDisRsp +{ + FF Category; + FF Action; + FF DialogToken; + FF Capabilities; + MANDIE SuppRates; + OPTIE ExtSuppRates; + OPTIE SuppChannels; + OPTIE SuppOperatingClasses; + OPTIE RSN; + OPTIE ExtCap; + OPTIE FTInfo; + OPTIE TimeoutInterval; + OPTIE RICData; + OPTIE HTCaps; + OPTIE ht2040_bss_coexistence; + MANDIE LinkIdentifier; + OPTIE VHTCaps; +} + +FRAME TDLSSetupReq +{ + FF Category; + FF Action; + FF DialogToken; + FF Capabilities; + MANDIE SuppRates; + OPTIE Country; + OPTIE ExtSuppRates; + OPTIE SuppChannels; + OPTIE RSN; + OPTIE ExtCap; + OPTIE SuppOperatingClasses; + OPTIE QOSCapsStation; + OPTIE FTInfo; + OPTIE TimeoutInterval; + OPTIE RICData; + OPTIE HTCaps; + OPTIE ht2040_bss_coexistence; + MANDIE LinkIdentifier; + OPTIE WMMInfoStation; + OPTIE AID; + OPTIE VHTCaps; +} + +FRAME TDLSSetupRsp +{ + FF Category; + FF Action; + FF Status; + FF DialogToken; + FF Capabilities ; + OPTIE SuppRates; + OPTIE Country; + OPTIE ExtSuppRates; + OPTIE SuppChannels; + OPTIE RSN; + OPTIE ExtCap; + OPTIE SuppOperatingClasses; + OPTIE QOSCapsStation; + OPTIE FTInfo; + OPTIE TimeoutInterval; + OPTIE RICData; + OPTIE HTCaps; + OPTIE ht2040_bss_coexistence; + OPTIE LinkIdentifier; + OPTIE WMMInfoStation; + OPTIE AID; + OPTIE VHTCaps; + OPTIE OperatingMode; +} + +FRAME TDLSSetupCnf +{ + FF Category; + FF Action; + FF Status; + FF DialogToken; + OPTIE RSN; + OPTIE EDCAParamSet; + OPTIE FTInfo; + OPTIE TimeoutInterval; + OPTIE HTInfo; + OPTIE LinkIdentifier; + OPTIE WMMParams; + OPTIE VHTOperation; + OPTIE OperatingMode; +} +FRAME TDLSTeardown +{ + FF Category; + FF Action; + FF Reason; + OPTIE FTInfo; + MANDIE LinkIdentifier; +} + +FRAME TDLSPeerTrafficInd +{ + FF Category; + FF Action; + FF DialogToken; + MANDIE LinkIdentifier; + OPTIE PTIControl; + MANDIE PUBufferStatus; +} + +FRAME TDLSPeerTrafficRsp +{ + FF Category; + FF Action; + FF DialogToken; + MANDIE LinkIdentifier; +} + +FRAME SaQueryReq +{ + FF Category; + FF Action; + FF TransactionId; +} + +FRAME SaQueryRsp +{ + FF Category; + FF Action; + FF TransactionId; +} + +FRAME QosMapConfigure +{ + FF Category; + FF Action; + MANDIE QosMapSet; +} + +FRAME VHTGidManagementActionFrame +{ + FF Category; + FF Action; + FF VhtMembershipStatusArray; + FF VhtUserPositionArray; +} + +FRAME ht2040_bss_coexistence_mgmt_action_frame +{ + FF Category; + FF Action; + MANDIE ht2040_bss_coexistence; + MANDIE ht2040_bss_intolerant_report; +} + +FRAME TimingAdvertisementFrame // 8.3.3.15 +{ + FF TimeStamp; + FF Capabilities; + OPTIE Country; + OPTIE PowerConstraints; + OPTIE TimeAdvertisement; + OPTIE ExtCap; + OPTIE Vendor1IE; + OPTIE Vendor3IE; +} + +FRAME ext_channel_switch_action_frame +{ + FF Category; + FF Action; + FF ext_chan_switch_ann_action; +} + +FRAME p2p_oper_chan_change_confirm +{ + FF Category; + FF p2p_action_oui; + FF p2p_action_subtype; + FF DialogToken; + OPTIE HTCaps; + OPTIE VHTCaps; + OPTIE OperatingMode; +} + +// Local Variables: +// mode: c++ +// fill-column: 77 +// comment-column: 42 +// indent-tabs-mode: nil +// show-trailing-whitespace: t +// End: + +// parser.frms ends here. diff --git a/drivers/staging/qcacld-3.0/core/mac/src/cfg/cfg_api.c b/drivers/staging/qcacld-3.0/core/mac/src/cfg/cfg_api.c new file mode 100644 index 0000000000000000000000000000000000000000..2d347853fdd4a867625ef1e1a4b93263bececf7f --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/cfg/cfg_api.c @@ -0,0 +1,981 @@ +/* + * Copyright (c) 2011-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * + * This file contains the source code for CFG API functions. + * + * Author: Kevin Nguyen + * Date: 04/09/02 + * History:- + * 04/09/02 Created. + * -------------------------------------------------------------------- + */ + +#include "cds_api.h" +#include "cfg_priv.h" +#include "cfg_debug.h" +#include "wma_types.h" +#include "cfg_api.h" + +/* --------------------------------------------------------------------- */ +/* Static Variables */ +/* ---------------------------------------------------------------------- */ +static tCfgCtl __g_cfg_entry[CFG_PARAM_MAX_NUM]; +static uint8_t __g_s_buffer[CFG_MAX_STR_LEN]; +static uint32_t __g_param_list[WNI_CFG_MAX_PARAM_NUM + + WNI_CFG_GET_PER_STA_STAT_RSP_NUM]; + +static void notify(tpAniSirGlobal, uint16_t, uint32_t); + +typedef enum { + eRF_BAND_UNKNOWN = 0, + eRF_BAND_2_4_GHZ = 1, + eRF_BAND_5_GHZ = 2 +} eRfBandMode; + +extern cfgstatic_string cfg_static_string[CFG_MAX_STATIC_STRING]; +extern cgstatic cfg_static[CFG_PARAM_MAX_NUM] ; + +/* --------------------------------------------------------------------- */ +uint32_t cfg_need_restart(tpAniSirGlobal pMac, uint16_t cfgId) +{ + if (!pMac->cfg.gCfgEntry) { + PELOGE(cfg_log(pMac, LOGE, FL("gCfgEntry is NULL"));) + return 0; + } + return !!(pMac->cfg.gCfgEntry[cfgId].control & CFG_CTL_RESTART); +} + +static void cfg_get_strindex(tpAniSirGlobal pMac, uint16_t cfgId) +{ + uint16_t i = 0; + + for (i = 0; i < CFG_MAX_STATIC_STRING; i++) { + if (cfgId == cfg_static_string[i].cfgId) + break; + } + if (i == CFG_MAX_STATIC_STRING) { + PELOGE(cfg_log(pMac, LOGE, FL("Entry not found for cfg id :%d"), cfgId);) + cfg_static[cfgId].pStrData = NULL; + return; + } + cfg_static[cfgId].pStrData = &cfg_static_string[i]; +} +/* --------------------------------------------------------------------- */ +uint32_t cfg_need_reload(tpAniSirGlobal pMac, uint16_t cfgId) +{ + if (!pMac->cfg.gCfgEntry) { + PELOGE(cfg_log(pMac, LOGE, FL("gCfgEntry is NULL"));) + return 0; + } + return !!(pMac->cfg.gCfgEntry[cfgId].control & CFG_CTL_RELOAD); +} + +/* --------------------------------------------------------------------- */ +tSirRetStatus cfg_init(tpAniSirGlobal pMac) +{ + uint16_t i = 0; + uint16_t combined_buff_size = 0; + uint32_t max_i_count = 0; + uint32_t max_s_count = 0; + cfgstatic_string *str_cfg; + + pMac->cfg.gSBuffer = __g_s_buffer; + pMac->cfg.gCfgEntry = __g_cfg_entry; + pMac->cfg.gParamList = __g_param_list; + + for (i = 0; i < CFG_PARAM_MAX_NUM; i++) { + if (!(cfg_static[i].control & CFG_CTL_INT)) { + cfg_get_strindex(pMac, i); + } else { + cfg_static[i].pStrData = NULL; + } + } + + for (i = 0; i < CFG_PARAM_MAX_NUM ; i++) { + if (cfg_static[i].control & CFG_CTL_INT) { + max_i_count++; + } else { + str_cfg = (cfgstatic_string *)cfg_static[i].pStrData; + if (str_cfg == NULL) { + cfg_log(pMac, LOGE, + FL("pStrCfg is NULL for CfigID : %d"), + i); + continue; + } + /* + 2 to include len field and max len field */ + max_s_count += str_cfg->maxLen + 2; + } + } + + pMac->cfg.gCfgMaxIBufSize = max_i_count; + pMac->cfg.gCfgMaxSBufSize = max_s_count; + + /* Allocate a combined memory */ + combined_buff_size = max_s_count + (3 * sizeof(uint32_t) * max_i_count); + + cfg_log(pMac, LOGE, FL("Size of cfg I buffer:%d S buffer: %d"), + max_i_count, max_s_count); + + cfg_log(pMac, LOGE, FL("Allocation for cfg buffers: %d bytes"), + combined_buff_size); + + if (combined_buff_size > 4 * PAGE_SIZE) { + cfg_log(pMac, LOGE, FL("Mem alloc request too big")); + return eSIR_MEM_ALLOC_FAILED; + } + /* at this point pMac->cfg.gCfgSBuf starts */ + pMac->cfg.gCfgSBuf = qdf_mem_malloc(combined_buff_size); + if (NULL == pMac->cfg.gCfgSBuf) { + cfg_log(pMac, LOGE, + FL("Failed to allocate memory for cfg array")); + return eSIR_MEM_ALLOC_FAILED; + } + /* at offset max_s_count, pMac->cfg.gCfgIBuf starts */ + pMac->cfg.gCfgIBuf = (uint32_t *)&pMac->cfg.gCfgSBuf[max_s_count]; + /* after max_i_count integers, pMac->cfg.gCfgIBufMin starts */ + pMac->cfg.gCfgIBufMin = &pMac->cfg.gCfgIBuf[max_i_count]; + /* after max_i_count integers, pMac->cfg.gCfgIBufMax starts */ + pMac->cfg.gCfgIBufMax = &pMac->cfg.gCfgIBufMin[max_i_count]; + + return eSIR_SUCCESS; +} + +/* ---------------------------------------------------------------------- */ +void cfg_de_init(tpAniSirGlobal pMac) +{ + qdf_mem_free(pMac->cfg.gCfgSBuf); + pMac->cfg.gCfgIBufMin = NULL; + pMac->cfg.gCfgIBufMax = NULL; + pMac->cfg.gCfgIBuf = NULL; + pMac->cfg.gCfgSBuf = NULL; + pMac->cfg.gSBuffer = NULL; + pMac->cfg.gCfgEntry = NULL; + pMac->cfg.gParamList = NULL; +} + +/* --------------------------------------------------------------------- */ +/** + * cfg_check_valid() + * + * FUNCTION: + * This function is called to check if a parameter is valid + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param cfgId: 16-bit CFG parameter ID + * + * @return eSIR_SUCCESS: request completed successfully + * @return eSIR_CFG_INVALID_ID: invalid CFG parameter ID + */ +tSirRetStatus cfg_check_valid(tpAniSirGlobal pMac, uint16_t cfgId, + uint32_t *index) +{ + uint32_t control; + + if (cfgId >= CFG_PARAM_MAX_NUM) { + PELOGE(cfg_log(pMac, LOG3, FL("Invalid cfg id %d"), cfgId);) + return eSIR_CFG_INVALID_ID; + } + if (!pMac->cfg.gCfgEntry) { + PELOGE(cfg_log(pMac, LOGE, FL("gCfgEntry is NULL"));) + return eSIR_CFG_INVALID_ID; + } + + control = pMac->cfg.gCfgEntry[cfgId].control; + + /* Check if parameter is valid */ + if ((control & CFG_CTL_VALID) == 0) { + PELOGE(cfg_log(pMac, LOGE, FL("Not valid cfg id %d"), cfgId);) + return eSIR_CFG_INVALID_ID; + } + + *index = control & CFG_BUF_INDX_MASK; + + if (*index >= pMac->cfg.gCfgMaxSBufSize) { + PELOGE(cfg_log(pMac, LOGE, FL("cfg index out of bounds %d"), + *index);) + return eSIR_CFG_INVALID_ID; + } + + return eSIR_SUCCESS; + +} /*** end cfg_check_valid() ***/ + +/* --------------------------------------------------------------------- */ +/** + * cfg_set_int() + * + * FUNCTION: + * This function is called to update an integer parameter. + * + * LOGIC: + * + * ASSUMPTIONS: + * - Range checking is performed by the calling function. In case this + * function call is being triggered by a request from host, then host + * is responsible for performing range checking before sending the + * request. + * + * - Host RW permission checking should already be done prior to calling + * this function by the message processing function. + * + * NOTE: + * + * @param cfgId: 16-bit CFG parameter ID + * @param value: 32-bit unsigned value + * + * @return eSIR_SUCCESS: request completed successfully + * @return eSIR_CFG_INVALID_ID: invalid CFG parameter ID + */ + +tSirRetStatus cfg_set_int(tpAniSirGlobal pMac, uint16_t cfgId, uint32_t value) +{ + uint32_t index; + uint32_t control; + uint32_t mask; + tSirRetStatus status; + + status = cfg_check_valid(pMac, cfgId, &index); + + if (eSIR_SUCCESS != status) + return status; + + if ((pMac->cfg.gCfgIBufMin[index] > value) || + (pMac->cfg.gCfgIBufMax[index] < value)) { + PELOGE(cfg_log (pMac, LOGE, FL( + "Value %d out of range [%d,%d] cfg id %d"), value, + pMac->cfg.gCfgIBufMin[index], + pMac->cfg.gCfgIBufMax[index], cfgId);) + return eSIR_CFG_INVALID_ID; + } else { + /* Write integer value */ + pMac->cfg.gCfgIBuf[index] = value; + + control = pMac->cfg.gCfgEntry[cfgId].control; + /* Update hardware if necessary */ + mask = control & CFG_CTL_NTF_MASK; + if ((mask & CFG_CTL_NTF_HW) != 0) + PELOGE(cfg_log(pMac, LOGE, FL( + "CFG notify HW not supported!!!"));) + /* notify other modules if necessary */ + if ((mask & CFG_CTL_NTF_MASK) != 0) + notify(pMac, cfgId, mask); + } + return status; +} /*** end cfg_set_int ***/ + +/* --------------------------------------------------------------------- */ +/** + * wlan_cfg_get_int() + * + * FUNCTION: + * This function is called to read an integer parameter. + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param cfgId: 16-bit CFG parameter ID + * @param pVal: address where parameter value will be written + * + * @return eSIR_SUCCESS: request completed successfully + * @return eSIR_CFG_INVALID_ID: invalid CFG parameter ID + */ + +tSirRetStatus wlan_cfg_get_int(tpAniSirGlobal pMac, uint16_t cfgId, + uint32_t *pValue) +{ + uint32_t index; + tSirRetStatus status; + + status = cfg_check_valid(pMac, cfgId, &index); + + if (eSIR_SUCCESS != status) + return status; + + /* Get integer value */ + *pValue = pMac->cfg.gCfgIBuf[index]; + + return eSIR_SUCCESS; +} /*** end wlan_cfg_get_int() ***/ + +/* --------------------------------------------------------------------- */ +/** + * cfg_set_str() + * + * FUNCTION: + * This function is called to set a string parameter. + * + * LOGIC: + * This function invokes the cfg_set_str_notify function passing the notify + * bool value set to true. This basically means that HAL needs to be + * notified. This is true in the case of non-integrated SOC's or Libra/Volans. + * In the case of Prima the cfg_set_str_notify is invoked with the bool value + * set to false. + * + * ASSUMPTIONS: + * - always notify has to be called + * + * NOTE: + * + * @param cfgId: 16-bit CFG parameter ID + * @param pStr: address of string data + * @param len: string length + * + * @return eSIR_SUCCESS: request completed successfully + * @return eSIR_CFG_INVALID_ID: invalid CFG parameter ID + * @return eSIR_CFG_INVALID_LEN: invalid CFG parameter length + * + */ + +tSirRetStatus cfg_set_str(tpAniSirGlobal pMac, uint16_t cfgId, uint8_t *pStr, + uint32_t length) +{ + return cfg_set_str_notify(pMac, cfgId, pStr, length, true); +} + +/* --------------------------------------------------------------------- */ +/** + * cfg_set_str_notify() + * + * FUNCTION: + * This function is called to set a string parameter. + * + * LOGIC: + * + * ASSUMPTIONS: + * - No length checking will be performed. Should be done by calling + * module. + * - Host RW permission should be checked prior to calling this + * function. + * + * NOTE: + * + * @param cfgId: 16-bit CFG parameter ID + * @param pStr: address of string data + * @param len: string length + * @param notifyMod. notify respective Module + * + * @return eSIR_SUCCESS: request completed successfully + * @return eSIR_CFG_INVALID_ID: invalid CFG parameter ID + * @return eSIR_CFG_INVALID_LEN: invalid CFG parameter length + * + */ + +tSirRetStatus cfg_set_str_notify(tpAniSirGlobal pMac, uint16_t cfgId, + uint8_t *pStr, uint32_t length, + int notifyMod) +{ + uint8_t *pDst, *pDstEnd; + uint32_t index, paramLen, mask; + uint32_t control; + tSirRetStatus status; + + status = cfg_check_valid(pMac, cfgId, &index); + + if (eSIR_SUCCESS != status) + return status; + + pDst = &pMac->cfg.gCfgSBuf[index]; + paramLen = *pDst++; + control = pMac->cfg.gCfgEntry[cfgId].control; + if (length > paramLen) { + PELOGE(cfg_log(pMac, LOGE, FL( + "Invalid length %d (>%d) cfg id %d"), + length, paramLen, cfgId);) + return eSIR_CFG_INVALID_LEN; + } else { + *pDst++ = (uint8_t) length; + pDstEnd = pDst + length; + while (pDst < pDstEnd) { + *pDst++ = *pStr++; + } + if (notifyMod) { + /* Update hardware if necessary */ + mask = control & CFG_CTL_NTF_MASK; + if ((mask & CFG_CTL_NTF_HW) != 0) { + PELOGE(cfg_log(pMac, LOGE, FL( + "CFG notify HW not supported!"));) + } + /* notify other modules if necessary */ + if ((mask & CFG_CTL_NTF_MASK) != 0) { + notify(pMac, cfgId, mask); + } + } + } + return eSIR_SUCCESS; +} /*** end cfg_set_str_notify() ***/ + +/* --------------------------------------------------------------------- */ +/** + * wlan_cfg_get_str() + * + * FUNCTION: + * This function is called to get a string parameter. + * + * LOGIC: + * + * ASSUMPTIONS: + * - Host RW permission should be checked prior to calling this + * function. + * + * NOTE: + * + * @param cfgId: 16-bit CFG parameter ID + * @param pBuf: address of string buffer + * @param pLen: address of max buffer length + * actual length will be returned at this address + * + * @return eSIR_SUCCESS: request completed successfully + * @return eSIR_CFG_INVALID_ID: invalid CFG parameter ID + * @return eSIR_CFG_INVALID_LEN: invalid CFG parameter length + * + */ + +tSirRetStatus wlan_cfg_get_str(tpAniSirGlobal pMac, uint16_t cfgId, + uint8_t *pBuf, uint32_t *pLength) +{ + uint8_t *pSrc, *pSrcEnd; + uint32_t index; + tSirRetStatus status; + + status = cfg_check_valid(pMac, cfgId, &index); + + if (eSIR_SUCCESS != status) + return status; + + /* Get string */ + pSrc = &pMac->cfg.gCfgSBuf[index]; + pSrc++; /* skip over max length */ + if (*pLength < *pSrc) { + PELOGE(cfg_log(pMac, LOGE, FL( + "Invalid length %d (<%d) cfg id %d"), + *pLength, *pSrc, cfgId);) + return eSIR_CFG_INVALID_LEN; + } else { + *pLength = *pSrc++; /* save parameter length */ + pSrcEnd = pSrc + *pLength; + while (pSrc < pSrcEnd) + *pBuf++ = *pSrc++; + } + return eSIR_SUCCESS; +} /*** end wlan_cfg_get_str() ***/ + +/* --------------------------------------------------------------------- */ +/** + * wlan_cfg_get_str_max_len() + * + * FUNCTION: + * This function is called to get a string maximum length. + * + * LOGIC: + * + * ASSUMPTIONS: + * - Host RW permission should be checked prior to calling this + * function. + * + * NOTE: + * + * @param cfgId: 16-bit CFG parameter ID + * @param pLen: maximum length will be returned at this address + * + * @return eSIR_SUCCESS: request completed successfully + * @return eSIR_CFG_INVALID_ID: invalid CFG parameter ID + * + */ + +tSirRetStatus wlan_cfg_get_str_max_len(tpAniSirGlobal pMac, uint16_t cfgId, + uint32_t *pLength) +{ + uint32_t index; + tSirRetStatus status; + + status = cfg_check_valid(pMac, cfgId, &index); + + if (eSIR_SUCCESS != status) + return status; + + *pLength = pMac->cfg.gCfgSBuf[index]; + + return status; +} /*** end wlan_cfg_get_str_max_len() ***/ + +/* --------------------------------------------------------------------- */ +/** + * wlan_cfg_get_str_len() + * + * FUNCTION: + * This function is called to get a string length. + * + * LOGIC: + * + * ASSUMPTIONS: + * - Host RW permission should be checked prior to calling this + * function. + * + * NOTE: + * + * @param cfgId: 16-bit CFG parameter ID + * @param pLen: current length will be returned at this address + * + * @return eSIR_SUCCESS: request completed successfully + * @return eSIR_CFG_INVALID_ID: invalid CFG parameter ID + * + */ + +tSirRetStatus wlan_cfg_get_str_len(tpAniSirGlobal pMac, uint16_t cfgId, + uint32_t *pLength) +{ + uint32_t index; + tSirRetStatus status; + + status = cfg_check_valid(pMac, cfgId, &index); + + if (eSIR_SUCCESS != status) + return status; + + *pLength = pMac->cfg.gCfgSBuf[index + 1]; + + return status; + +} /*** end wlan_cfg_get_str_len() ***/ + +/** + * cfg_get_dot11d_transmit_power() - regulatory max transmit power + * @pMac: pointer to mac data + * @cfgId: configuration ID + * @cfgLength: configuration length + * @channel: channel number + * + * Return: int8_t - power + */ +static int8_t +cfg_get_dot11d_transmit_power(tpAniSirGlobal pMac, uint16_t cfgId, + uint32_t cfgLength, uint8_t channel) +{ + uint8_t *pCountryInfo = NULL; + uint8_t count = 0; + int8_t maxTxPwr = WMA_MAX_TXPOWER_INVALID; + + /* At least one element is present */ + if (cfgLength < sizeof(tSirMacChanInfo)) { + PELOGE(cfg_log + (pMac, LOGE, + FL("Invalid CFGLENGTH %d while getting 11d txpower"), + cfgLength); + ) + goto error; + } + + pCountryInfo = qdf_mem_malloc(cfgLength); + if (NULL == pCountryInfo) { + cfg_log(pMac, LOGP, FL(" failed to allocate memory")); + goto error; + } + /* The CSR will always update this CFG. The contents will be from country IE if regulatory domain + * is enabled on AP else will contain EEPROM contents + */ + if (wlan_cfg_get_str(pMac, cfgId, pCountryInfo, &cfgLength) != + eSIR_SUCCESS) { + qdf_mem_free(pCountryInfo); + pCountryInfo = NULL; + + cfg_log(pMac, LOGP, + FL + ("Failed to retrieve 11d configuration parameters while retrieving 11d tuples")); + goto error; + } + /* Identify the channel and maxtxpower */ + while (count <= (cfgLength - (sizeof(tSirMacChanInfo)))) { + uint8_t firstChannel, maxChannels; + + firstChannel = pCountryInfo[count++]; + maxChannels = pCountryInfo[count++]; + maxTxPwr = pCountryInfo[count++]; + + if ((channel >= firstChannel) && + (channel < (firstChannel + maxChannels))) { + break; + } + } + +error: + if (NULL != pCountryInfo) + qdf_mem_free(pCountryInfo); + + return maxTxPwr; +} + +/**---------------------------------------------------------------------- + \fn cfg_get_regulatory_max_transmit_power + + \brief Gets regulatory tx power on the current channel. + + \param pMac + \param channel + \param rfBand + -----------------------------------------------------------------------*/ +int8_t cfg_get_regulatory_max_transmit_power(tpAniSirGlobal pMac, + uint8_t channel) +{ + uint32_t cfgLength = 0; + uint16_t cfgId = 0; + int8_t maxTxPwr; + eRfBandMode rfBand = eRF_BAND_UNKNOWN; + + if ((channel >= SIR_11A_CHANNEL_BEGIN) && + (channel <= SIR_11A_CHANNEL_END)) + rfBand = eRF_BAND_5_GHZ; + else + rfBand = eRF_BAND_2_4_GHZ; + + /* Get the max transmit power for current channel for the current regulatory domain */ + switch (rfBand) { + case eRF_BAND_2_4_GHZ: + cfgId = WNI_CFG_MAX_TX_POWER_2_4; + cfgLength = WNI_CFG_MAX_TX_POWER_2_4_LEN; + PELOG2(cfg_log + (pMac, LOG2, + FL + ("HAL: Reading CFG for 2.4 GHz channels to get regulatory max tx power")); + ) + break; + + case eRF_BAND_5_GHZ: + cfgId = WNI_CFG_MAX_TX_POWER_5; + cfgLength = WNI_CFG_MAX_TX_POWER_5_LEN; + PELOG2(cfg_log + (pMac, LOG2, + FL + ("HAL: Reading CFG for 5.0 GHz channels to get regulatory max tx power")); + ) + break; + + case eRF_BAND_UNKNOWN: + default: + PELOG2(cfg_log + (pMac, LOG2, + FL("HAL: Invalid current working band for the device")); + ) + return WMA_MAX_TXPOWER_INVALID; /* Its return, not break. */ + } + + maxTxPwr = cfg_get_dot11d_transmit_power(pMac, cfgId, cfgLength, channel); + + return maxTxPwr; +} + +/* --------------------------------------------------------------------- */ +/** + * cfg_get_capability_info + * + * FUNCTION: + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param None + * @return None + */ + +tSirRetStatus cfg_get_capability_info(tpAniSirGlobal pMac, uint16_t *pCap, + tpPESession sessionEntry) +{ + uint32_t val = 0; + tpSirMacCapabilityInfo pCapInfo; + + *pCap = 0; + pCapInfo = (tpSirMacCapabilityInfo) pCap; + + if (LIM_IS_IBSS_ROLE(sessionEntry)) + pCapInfo->ibss = 1; /* IBSS bit */ + else if (LIM_IS_AP_ROLE(sessionEntry) || + LIM_IS_STA_ROLE(sessionEntry)) + pCapInfo->ess = 1; /* ESS bit */ + else if (LIM_IS_P2P_DEVICE_ROLE(sessionEntry) || + LIM_IS_NDI_ROLE(sessionEntry)) { + pCapInfo->ess = 0; + pCapInfo->ibss = 0; + } else + cfg_log(pMac, LOGP, + FL("can't get capability, role is UNKNOWN!!")); + + if (LIM_IS_AP_ROLE(sessionEntry)) { + val = sessionEntry->privacy; + } else { + /* PRIVACY bit */ + if (wlan_cfg_get_int(pMac, WNI_CFG_PRIVACY_ENABLED, &val) != + eSIR_SUCCESS) { + cfg_log(pMac, LOGP, + FL("cfg get WNI_CFG_PRIVACY_ENABLED failed")); + return eSIR_FAILURE; + } + } + if (val) + pCapInfo->privacy = 1; + + /* Short preamble bit */ + if (wlan_cfg_get_int(pMac, WNI_CFG_SHORT_PREAMBLE, &val) != eSIR_SUCCESS) { + cfg_log(pMac, LOGP, FL("cfg get WNI_CFG_SHORT_PREAMBLE failed")); + return eSIR_FAILURE; + } + if (val) + pCapInfo->shortPreamble = 1; + + /* PBCC bit */ + pCapInfo->pbcc = 0; + + /* Channel agility bit */ + pCapInfo->channelAgility = 0; + /* If STA/AP operating in 11B mode, don't set rest of the capability info bits. */ + if (sessionEntry->dot11mode == WNI_CFG_DOT11_MODE_11B) + return eSIR_SUCCESS; + + /* Short slot time bit */ + if (LIM_IS_AP_ROLE(sessionEntry)) { + pCapInfo->shortSlotTime = sessionEntry->shortSlotTimeSupported; + } else { + if (wlan_cfg_get_int + (pMac, WNI_CFG_11G_SHORT_SLOT_TIME_ENABLED, &val) + != eSIR_SUCCESS) { + cfg_log(pMac, LOGP, + FL + ("cfg get WNI_CFG_11G_SHORT_SLOT_TIME failed")); + return eSIR_FAILURE; + } + /* When in STA mode, we need to check if short slot is enabled as well as check if the current operating + * mode is short slot time and then decide whether to enable short slot or not. It is safe to check both + * cfg values to determine short slot value in this funcn since this funcn is always used after assoc when + * these cfg values are already set based on peer's capability. Even in case of IBSS, its value is set to + * correct value either in delBSS as part of deleting the previous IBSS or in start BSS as part of coalescing + */ + if (val) { + pCapInfo->shortSlotTime = + sessionEntry->shortSlotTimeSupported; + } + } + + /* Spectrum Management bit */ + if (!LIM_IS_IBSS_ROLE(sessionEntry) && sessionEntry->lim11hEnable) { + if (wlan_cfg_get_int(pMac, WNI_CFG_11H_ENABLED, &val) != + eSIR_SUCCESS) { + cfg_log(pMac, LOGP, + FL("cfg get WNI_CFG_11H_ENABLED failed")); + return eSIR_FAILURE; + } + if (val) + pCapInfo->spectrumMgt = 1; + } + /* QoS bit */ + if (wlan_cfg_get_int(pMac, WNI_CFG_QOS_ENABLED, &val) != eSIR_SUCCESS) { + cfg_log(pMac, LOGP, FL("cfg get WNI_CFG_QOS_ENABLED failed")); + return eSIR_FAILURE; + } + if (val) + pCapInfo->qos = 1; + + /* APSD bit */ + if (wlan_cfg_get_int(pMac, WNI_CFG_APSD_ENABLED, &val) != eSIR_SUCCESS) { + cfg_log(pMac, LOGP, FL("cfg get WNI_CFG_APSD_ENABLED failed")); + return eSIR_FAILURE; + } + if (val) + pCapInfo->apsd = 1; + + pCapInfo->rrm = pMac->rrm.rrmSmeContext.rrmConfig.rrm_enabled; + cfg_log(pMac, LOG1, FL("RRM = %d"), pCapInfo->rrm); + /* DSSS-OFDM */ + /* FIXME : no config defined yet. */ + + /* Block ack bit */ + if (wlan_cfg_get_int(pMac, WNI_CFG_BLOCK_ACK_ENABLED, &val) != + eSIR_SUCCESS) { + cfg_log(pMac, LOGP, + FL("cfg get WNI_CFG_BLOCK_ACK_ENABLED failed")); + return eSIR_FAILURE; + } + pCapInfo->delayedBA = + (uint16_t) ((val >> WNI_CFG_BLOCK_ACK_ENABLED_DELAYED) & 1); + pCapInfo->immediateBA = + (uint16_t) ((val >> WNI_CFG_BLOCK_ACK_ENABLED_IMMEDIATE) & 1); + + return eSIR_SUCCESS; +} + +/* -------------------------------------------------------------------- */ +/** + * cfg_set_capability_info + * + * FUNCTION: + * This function is called on BP based on the capabilities + * received in SME_JOIN/REASSOC_REQ message. + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: 1. ESS/IBSS capabilities are based on system role. + * 2. Since PBCC, Channel agility and Extended capabilities + * are not supported, they're not set at CFG + * + * @param pMac Pointer to global MAC structure + * @param caps 16-bit Capability Info field + * @return None + */ + +void cfg_set_capability_info(tpAniSirGlobal pMac, uint16_t caps) +{ +} + +/* --------------------------------------------------------------------- */ +/** + * cfg_cleanup() + * + * FUNCTION: + * CFG cleanup function. + * + * LOGIC: + * + * ASSUMPTIONS: + * None. + * + * NOTE: + * This function must be called during system shutdown. + * + * @param None + * + * @return None. + * + */ + +void cfg_cleanup(tpAniSirGlobal pMac) +{ + /* Set status to not-ready */ + pMac->cfg.gCfgStatus = CFG_INCOMPLETE; + +} /*** end CfgCleanup() ***/ + +/* --------------------------------------------------------------------- */ +/** + * notify() + * + * FUNCTION: + * This function is called to notify other modules of parameter update. + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param cfgId: configuration parameter ID + * @param mask: notification mask + * + * @return None. + * + */ + +static void notify(tpAniSirGlobal pMac, uint16_t cfgId, uint32_t ntfMask) +{ + + tSirMsgQ mmhMsg; + + mmhMsg.type = SIR_CFG_PARAM_UPDATE_IND; + mmhMsg.bodyval = (uint32_t) cfgId; + mmhMsg.bodyptr = NULL; + + if ((ntfMask & CFG_CTL_NTF_SCH) != 0) + sch_post_message(pMac, &mmhMsg); + + if ((ntfMask & CFG_CTL_NTF_LIM) != 0) + lim_post_msg_api(pMac, &mmhMsg); + + if ((ntfMask & CFG_CTL_NTF_HAL) != 0) + wma_post_ctrl_msg(pMac, &mmhMsg); + + /* notify ARQ */ + +} /*** end notify() ***/ + +/** + * cfg_get_vendor_ie_ptr_from_oui() - returns IE pointer in IE buffer given its + * OUI and OUI size + * @mac_ctx: mac context. + * @oui: OUI string. + * @oui_size: length of OUI string + * One can provide multiple line descriptions + * for arguments. + * @ie: ie buffer + * @ie_len: length of ie buffer + * + * This function parses the IE buffer and finds the given OUI and returns its + * pointer + * + * Return: pointer of given OUI IE else NULL + */ +uint8_t *cfg_get_vendor_ie_ptr_from_oui(tpAniSirGlobal mac_ctx, + uint8_t *oui, + uint8_t oui_size, + uint8_t *ie, + uint16_t ie_len) +{ + int32_t left = ie_len; + uint8_t *ptr = ie; + uint8_t elem_id, elem_len; + + while (left >= 2) { + elem_id = ptr[0]; + elem_len = ptr[1]; + left -= 2; + if (elem_len > left) { + cfg_log(mac_ctx, LOGE, + FL("Invalid IEs eid = %d elem_len=%d left=%d"), + elem_id, elem_len, left); + return NULL; + } + if (SIR_MAC_EID_VENDOR == elem_id) { + if (memcmp(&ptr[2], oui, oui_size) == 0) + return ptr; + } + + left -= elem_len; + ptr += (elem_len + 2); + } + return NULL; +} +/* --------------------------------------------------------------------- */ diff --git a/drivers/staging/qcacld-3.0/core/mac/src/cfg/cfg_debug.c b/drivers/staging/qcacld-3.0/core/mac/src/cfg/cfg_debug.c new file mode 100644 index 0000000000000000000000000000000000000000..7d09c91763d1479744aabd3875e5fbb8f1fb824c --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/cfg/cfg_debug.c @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/**========================================================================= + + \file cfg_debug.c + + \brief implementation for log Debug related APIs + + \author Sunit Bhatia + + ========================================================================*/ + +#include "cfg_debug.h" + +void cfg_log(tpAniSirGlobal pMac, uint32_t loglevel, const char *pString, ...) +{ +#ifdef WLAN_DEBUG + /* Verify against current log level */ + if (loglevel > + pMac->utils.gLogDbgLevel[LOG_INDEX_FOR_MODULE(SIR_CFG_MODULE_ID)]) + return; + else { + va_list marker; + + va_start(marker, pString); /* Initialize variable arguments. */ + + log_debug(pMac, SIR_CFG_MODULE_ID, loglevel, pString, marker); + + va_end(marker); /* Reset variable arguments. */ + } +#endif +} diff --git a/drivers/staging/qcacld-3.0/core/mac/src/cfg/cfg_debug.h b/drivers/staging/qcacld-3.0/core/mac/src/cfg/cfg_debug.h new file mode 100644 index 0000000000000000000000000000000000000000..424152e6e9e0e42228c7e9afc0d4644887fb5349 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/cfg/cfg_debug.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2011-2012, 2014-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * + * Author: Kevin Nguyen + * Date: 04/09/02 + * History:- + * 04/09/02 Created. + * -------------------------------------------------------------------- + */ + +#ifndef __CFG_DEBUG_H__ +#define __CFG_DEBUG_H__ + +#include "sir_debug.h" +#include "utils_api.h" +#include "lim_trace.h" + +#if !defined(__printf) +#define __printf(a, b) +#endif + +void __printf(3, 4) cfg_log(tpAniSirGlobal pMac, uint32_t loglevel, + const char *pString, ...); + +#endif diff --git a/drivers/staging/qcacld-3.0/core/mac/src/cfg/cfg_def.h b/drivers/staging/qcacld-3.0/core/mac/src/cfg/cfg_def.h new file mode 100644 index 0000000000000000000000000000000000000000..6239538ebceca9719cb30ac96b580c7a77f503fd --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/cfg/cfg_def.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2011-2012, 2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * + * This is the private header file for CFG module. + * + * Author: Kevin Nguyen + * Date: 03/20/02 + * History:- + * 03/20/02 Created. + * -------------------------------------------------------------------- + * + */ + +#ifndef __CFGDEF_H +#define __CFGDEF_H + +/* + * CFG Control Flag definitions + */ +#define CFG_CTL_VALID 0x00010000 +#define CFG_CTL_RE 0x00020000 +#define CFG_CTL_WE 0x00040000 +#define CFG_CTL_INT 0x00080000 +#define CFG_CTL_SAVE 0x00100000 +#define CFG_CTL_RESTART 0x00200000 +#define CFG_CTL_RELOAD 0x00400000 +#define CFG_CTL_NTF_PHY 0x00800000 +#define CFG_CTL_NTF_MAC 0x01000000 +#define CFG_CTL_NTF_LOG 0x02000000 +#define CFG_CTL_NTF_HAL 0x04000000 +#define CFG_CTL_NTF_DPH 0x08000000 +#define CFG_CTL_NTF_ARQ 0x10000000 +#define CFG_CTL_NTF_SCH 0x20000000 +#define CFG_CTL_NTF_LIM 0x40000000 +#define CFG_CTL_NTF_HDD 0x80000000 +#define CFG_CTL_NTF_MASK 0xFFE00000 + +#define CFG_CTL_NTF_TFP CFG_CTL_NTF_MAC +#define CFG_CTL_NTF_RHP CFG_CTL_NTF_MAC +#define CFG_CTL_NTF_RFP CFG_CTL_NTF_MAC +#define CFG_CTL_NTF_SP CFG_CTL_NTF_MAC +#define CFG_CTL_NTF_HW (CFG_CTL_NTF_MAC | CFG_CTL_NTF_PHY) + +#define CFG_BUF_INDX_MASK 0x00000fff + +#endif /* __CFGDEF_H */ diff --git a/drivers/staging/qcacld-3.0/core/mac/src/cfg/cfg_param_name.c b/drivers/staging/qcacld-3.0/core/mac/src/cfg/cfg_param_name.c new file mode 100644 index 0000000000000000000000000000000000000000..0e67f6bbf00f4ab9bab82674e8c73c6a9b6a04cf --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/cfg/cfg_param_name.c @@ -0,0 +1,329 @@ +/* + * Copyright (c) 2011-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * DO NOT EDIT - This file is generated automatically + */ + +/* + * IMPORTANT: This file is for system that supports STA mode ONLY. + */ +#include "cfg_priv.h" + +unsigned char *g_cfg_param_name[] = { + (unsigned char *)"STA_ID", + (unsigned char *)"CF_POLLABLE", + (unsigned char *)"CFP_PERIOD", + (unsigned char *)"CFP_MAX_DURATION", + (unsigned char *)"SSID", + (unsigned char *)"BEACON_INTERVAL", + (unsigned char *)"DTIM_PERIOD", + (unsigned char *)"WEP_KEY_LENGTH", + (unsigned char *)"WEP_DEFAULT_KEY_1", + (unsigned char *)"WEP_DEFAULT_KEY_2", + (unsigned char *)"WEP_DEFAULT_KEY_3", + (unsigned char *)"WEP_DEFAULT_KEY_4", + (unsigned char *)"WEP_DEFAULT_KEYID", + (unsigned char *)"EXCLUDE_UNENCRYPTED", + (unsigned char *)"RTS_THRESHOLD", + (unsigned char *)"SHORT_RETRY_LIMIT", + (unsigned char *)"LONG_RETRY_LIMIT", + (unsigned char *)"FRAGMENTATION_THRESHOLD", + (unsigned char *)"ACTIVE_MINIMUM_CHANNEL_TIME", + (unsigned char *)"ACTIVE_MAXIMUM_CHANNEL_TIME", + (unsigned char *)"PASSIVE_MINIMUM_CHANNEL_TIME", + (unsigned char *)"PASSIVE_MAXIMUM_CHANNEL_TIME", + (unsigned char *)"JOIN_FAILURE_TIMEOUT", + (unsigned char *)"AUTHENTICATE_FAILURE_TIMEOUT", + (unsigned char *)"AUTHENTICATE_RSP_TIMEOUT", + (unsigned char *)"ASSOCIATION_FAILURE_TIMEOUT", + (unsigned char *)"REASSOCIATION_FAILURE_TIMEOUT", + (unsigned char *)"RA_PERIODICITY_TIMEOUT_IN_PS", + (unsigned char *)"PS_ENABLE_BCN_FILTER", + (unsigned char *)"PS_ENABLE_HEART_BEAT", + (unsigned char *)"PS_ENABLE_RSSI_MONITOR", + (unsigned char *)"PS_DATA_INACTIVITY_TIMEOUT", + (unsigned char *)"RF_SETTLING_TIME_CLK", + (unsigned char *)"SUPPORTED_RATES_11B", + (unsigned char *)"SUPPORTED_RATES_11A", + (unsigned char *)"PHY_MODE", + (unsigned char *)"DOT11_MODE", + (unsigned char *)"OPERATIONAL_RATE_SET", + (unsigned char *)"EXTENDED_OPERATIONAL_RATE_SET", + (unsigned char *)"PROPRIETARY_OPERATIONAL_RATE_SET", + (unsigned char *)"LISTEN_INTERVAL", + (unsigned char *)"VALID_CHANNEL_LIST", + (unsigned char *)"CURRENT_CHANNEL", + (unsigned char *)"DEFAULT_RATE_INDEX_5GHZ", + (unsigned char *)"DEFAULT_RATE_INDEX_24GHZ", + (unsigned char *)"RATE_ADAPTATION_TYPE", + (unsigned char *)"FIXED_RATE", + (unsigned char *)"FIXED_RATE_MULTICAST_24GHZ", + (unsigned char *)"FIXED_RATE_MULTICAST_5GHZ", + (unsigned char *)"RETRYRATE_POLICY", + (unsigned char *)"RETRYRATE_SECONDARY", + (unsigned char *)"RETRYRATE_TERTIARY", + (unsigned char *)"APSD_ENABLED", + (unsigned char *)"SHARED_KEY_AUTH_ENABLE", + (unsigned char *)"OPEN_SYSTEM_AUTH_ENABLE", + (unsigned char *)"AUTHENTICATION_TYPE", + (unsigned char *)"CF_POLL_REQUEST", + (unsigned char *)"PRIVACY_ENABLED", + (unsigned char *)"SHORT_PREAMBLE", + (unsigned char *)"SHORT_SLOT_TIME", + (unsigned char *)"ACCEPT_SHORT_SLOT_ASSOC_ONLY", + (unsigned char *)"QOS_ENABLED", + (unsigned char *)"HCF_ENABLED", + (unsigned char *)"RSN_ENABLED", + (unsigned char *)"BACKGROUND_SCAN_PERIOD", + (unsigned char *)"MAX_NUM_PRE_AUTH", + (unsigned char *)"PREAUTH_CLNUP_TIMEOUT", + (unsigned char *)"RELEASE_AID_TIMEOUT", + (unsigned char *)"HEART_BEAT_THRESHOLD", + (unsigned char *)"PROBE_AFTER_HB_FAIL_TIMEOUT", + (unsigned char *)"MANUFACTURER_OUI", + (unsigned char *)"MANUFACTURER_NAME", + (unsigned char *)"MODEL_NUMBER", + (unsigned char *)"MODEL_NAME", + (unsigned char *)"MANUFACTURER_PRODUCT_NAME", + (unsigned char *)"MANUFACTURER_PRODUCT_VERSION", + (unsigned char *)"11D_ENABLED", + (unsigned char *)"MAX_TX_POWER_2_4", + (unsigned char *)"MAX_TX_POWER_5", + (unsigned char *)"NETWORK_DENSITY", + (unsigned char *)"ADAPTIVE_THRESHOLD_ALGORITHM", + (unsigned char *)"CURRENT_TX_ANTENNA", + (unsigned char *)"CURRENT_TX_POWER_LEVEL", + (unsigned char *)"NEW_BSS_FOUND_IND", + (unsigned char *)"PROPRIETARY_RATES_ENABLED", + (unsigned char *)"AP_NODE_NAME", + (unsigned char *)"COUNTRY_CODE", + (unsigned char *)"11H_ENABLED", + (unsigned char *)"WT_CNF_TIMEOUT", + (unsigned char *)"KEEPALIVE_TIMEOUT", + (unsigned char *)"PROXIMITY", + (unsigned char *)"LOG_LEVEL", + (unsigned char *)"OLBC_DETECT_TIMEOUT", + (unsigned char *)"PROTECTION_ENABLED", + (unsigned char *)"11G_PROTECTION_ALWAYS", + (unsigned char *)"FORCE_POLICY_PROTECTION", + (unsigned char *)"11G_SHORT_PREAMBLE_ENABLED", + (unsigned char *)"11G_SHORT_SLOT_TIME_ENABLED", + (unsigned char *)"11G_ONLY_POLICY", + (unsigned char *)"PACKET_CLASSIFICATION", + (unsigned char *)"WME_ENABLED", + (unsigned char *)"ADDTS_RSP_TIMEOUT", + (unsigned char *)"MAX_SP_LENGTH", + (unsigned char *)"KEEP_ALIVE_STA_LIMIT_THRESHOLD", + (unsigned char *)"SEND_SINGLE_SSID_ALWAYS", + (unsigned char *)"WSM_ENABLED", + (unsigned char *)"EDCA_PROFILE", + (unsigned char *)"EDCA_ANI_ACBK_LOCAL", + (unsigned char *)"EDCA_ANI_ACBE_LOCAL", + (unsigned char *)"EDCA_ANI_ACVI_LOCAL", + (unsigned char *)"EDCA_ANI_ACVO_LOCAL", + (unsigned char *)"EDCA_ANI_ACBK", + (unsigned char *)"EDCA_ANI_ACBE", + (unsigned char *)"EDCA_ANI_ACVI", + (unsigned char *)"EDCA_ANI_ACVO", + (unsigned char *)"EDCA_WME_ACBK_LOCAL", + (unsigned char *)"EDCA_WME_ACBE_LOCAL", + (unsigned char *)"EDCA_WME_ACVI_LOCAL", + (unsigned char *)"EDCA_WME_ACVO_LOCAL", + (unsigned char *)"EDCA_WME_ACBK", + (unsigned char *)"EDCA_WME_ACBE", + (unsigned char *)"EDCA_WME_ACVI", + (unsigned char *)"EDCA_WME_ACVO", + (unsigned char *)"RDET_FLAG", + (unsigned char *)"RADAR_CHANNEL_LIST", + (unsigned char *)"LOCAL_POWER_CONSTRAINT", + (unsigned char *)"ADMIT_POLICY", + (unsigned char *)"ADMIT_BWFACTOR", + (unsigned char *)"MAX_CONSECUTIVE_BACKGROUND_SCAN_FAILURE", + (unsigned char *)"CHANNEL_BONDING_MODE", + (unsigned char *)"CB_SECONDARY_CHANNEL_STATE", + (unsigned char *)"DYNAMIC_THRESHOLD_ZERO", + (unsigned char *)"DYNAMIC_THRESHOLD_ONE", + (unsigned char *)"DYNAMIC_THRESHOLD_TWO", + (unsigned char *)"TRIG_STA_BK_SCAN", + (unsigned char *)"DYNAMIC_PROFILE_SWITCHING", + (unsigned char *)"SCAN_CONTROL_LIST", + (unsigned char *)"MIMO_ENABLED", + (unsigned char *)"BLOCK_ACK_ENABLED", + (unsigned char *)"HT_RX_STBC", + (unsigned char *)"HT_CAP_INFO", + (unsigned char *)"HT_AMPDU_PARAMS", + (unsigned char *)"SUPPORTED_MCS_SET", + (unsigned char *)"EXT_HT_CAP_INFO", + (unsigned char *)"TX_BF_CAP", + (unsigned char *)"AS_CAP", + (unsigned char *)"HT_INFO_FIELD1", + (unsigned char *)"HT_INFO_FIELD2", + (unsigned char *)"HT_INFO_FIELD3", + (unsigned char *)"BASIC_MCS_SET", + (unsigned char *)"CURRENT_MCS_SET", + (unsigned char *)"GREENFIELD_CAPABILITY", + (unsigned char *)"VHT_MAX_MPDU_LENGTH", + (unsigned char *)"VHT_SUPPORTED_CHAN_WIDTH_SET", + (unsigned char *)"VHT_LDPC_CODING_CAP", + (unsigned char *)"VHT_SHORT_GI_80MHZ", + (unsigned char *)"VHT_SHORT_GI_160_AND_80_PLUS_80MHZ", + (unsigned char *)"VHT_TXSTBC", + (unsigned char *)"VHT_RXSTBC", + (unsigned char *)"VHT_SU_BEAMFORMER_CAP", + (unsigned char *)"VHT_SU_BEAMFORMEE_CAP", + (unsigned char *)"VHT_CSN_BEAMFORMEE_ANT_SUPPORTED", + (unsigned char *)"VHT_NUM_SOUNDING_DIMENSIONS", + (unsigned char *)"VHT_MU_BEAMFORMER_CAP", + (unsigned char *)"VHT_MU_BEAMFORMEE_CAP", + (unsigned char *)"VHT_TXOP_PS", + (unsigned char *)"VHT_HTC_VHTC_CAP", + (unsigned char *)"VHT_AMPDU_LEN_EXPONENT", + (unsigned char *)"VHT_LINK_ADAPTATION_CAP", + (unsigned char *)"VHT_RX_ANT_PATTERN", + (unsigned char *)"VHT_TX_ANT_PATTERN", + (unsigned char *)"VHT_RX_MCS_MAP", + (unsigned char *)"VHT_TX_MCS_MAP", + (unsigned char *)"VHT_RX_HIGHEST_SUPPORTED_DATA_RATE", + (unsigned char *)"VHT_TX_HIGHEST_SUPPORTED_DATA_RATE", + (unsigned char *)"VHT_CHANNEL_CENTER_FREQ_SEGMENT1", + (unsigned char *)"VHT_CHANNEL_CENTER_FREQ_SEGMENT2", + (unsigned char *)"VHT_BASIC_MCS_SET", + (unsigned char *)"VHT_MU_MIMO_CAP_STA_COUNT", + (unsigned char *)"VHT_SS_UNDER_UTIL", + (unsigned char *)"VHT_40MHZ_UTILIZATION", + (unsigned char *)"VHT_80MHZ_UTILIZATION", + (unsigned char *)"VHT_160MHZ_UTILIZATION", + (unsigned char *)"MAX_AMSDU_LENGTH", + (unsigned char *)"MPDU_DENSITY", + (unsigned char *)"NUM_BUFF_ADVERT", + (unsigned char *)"MAX_RX_AMPDU_FACTOR", + (unsigned char *)"SHORT_GI_20MHZ", + (unsigned char *)"SHORT_GI_40MHZ", + (unsigned char *)"RIFS_ENABLED", + (unsigned char *)"MAX_PS_POLL", + (unsigned char *)"NUM_BEACON_PER_RSSI_AVERAGE", + (unsigned char *)"RSSI_FILTER_PERIOD", + (unsigned char *)"MIN_RSSI_THRESHOLD", + (unsigned char *)"NTH_BEACON_FILTER", + (unsigned char *)"BROADCAST_FRAME_FILTER_ENABLE", + (unsigned char *)"SCAN_IN_POWERSAVE", + (unsigned char *)"IGNORE_DTIM", + (unsigned char *)"WOWLAN_UCAST_PATTERN_FILTER_ENABLE", + (unsigned char *)"WOWLAN_CHANNEL_SWITCH_ENABLE", + (unsigned char *)"WOWLAN_DEAUTH_ENABLE", + (unsigned char *)"WOWLAN_DISASSOC_ENABLE", + (unsigned char *)"WOWLAN_MAX_MISSED_BEACON", + (unsigned char *)"WOWLAN_MAX_SLEEP_PERIOD", + (unsigned char *)"BA_THRESHOLD_HIGH", + (unsigned char *)"BG_SCAN_CHANNEL_LIST", + (unsigned char *)"MAX_MEDIUM_TIME", + (unsigned char *)"MAX_MPDUS_IN_AMPDU", + (unsigned char *)"IBSS_AUTO_BSSID", + (unsigned char *)"PROBE_REQ_ADDNIE_FLAG", + (unsigned char *)"PROBE_REQ_ADDNIE_DATA", + (unsigned char *)"PROBE_RSP_ADDNIE_FLAG", + (unsigned char *)"PROBE_RSP_ADDNIE_DATA1", + (unsigned char *)"PROBE_RSP_ADDNIE_DATA2", + (unsigned char *)"PROBE_RSP_ADDNIE_DATA3", + (unsigned char *)"ASSOC_RSP_ADDNIE_FLAG", + (unsigned char *)"ASSOC_RSP_ADDNIE_DATA", + (unsigned char *)"PROBE_REQ_ADDNP2PIE_FLAG", + (unsigned char *)"PROBE_REQ_ADDNP2PIE_DATA", + (unsigned char *)"PROBE_RSP_BCN_ADDNIE_FLAG", + (unsigned char *)"PROBE_RSP_BCN_ADDNIE_DATA", + (unsigned char *)"WPS_ENABLE", + (unsigned char *)"WPS_STATE", + (unsigned char *)"WPS_PROBE_REQ_FLAG", + (unsigned char *)"WPS_VERSION", + (unsigned char *)"WPS_REQUEST_TYPE", + (unsigned char *)"WPS_CFG_METHOD", + (unsigned char *)"WPS_UUID", + (unsigned char *)"WPS_PRIMARY_DEVICE_CATEGORY", + (unsigned char *)"WPS_PIMARY_DEVICE_OUI", + (unsigned char *)"WPS_DEVICE_SUB_CATEGORY", + (unsigned char *)"WPS_ASSOCIATION_STATE", + (unsigned char *)"WPS_CONFIGURATION_ERROR", + (unsigned char *)"WPS_DEVICE_PASSWORD_ID", + (unsigned char *)"WPS_ASSOC_METHOD", + (unsigned char *)"LOW_GAIN_OVERRIDE", + (unsigned char *)"RPE_POLLING_THRESHOLD", + (unsigned char *)"RPE_AGING_THRESHOLD_FOR_AC0_REG", + (unsigned char *)"RPE_AGING_THRESHOLD_FOR_AC1_REG", + (unsigned char *)"RPE_AGING_THRESHOLD_FOR_AC2_REG", + (unsigned char *)"RPE_AGING_THRESHOLD_FOR_AC3_REG", + (unsigned char *)"NO_OF_ONCHIP_REORDER_SESSIONS", + (unsigned char *)"SINGLE_TID_RC", + (unsigned char *)"MCAST_BCAST_FILTER_SETTING", + (unsigned char *)"BTC_DHCP_BT_SLOTS_TO_BLOCK", + (unsigned char *)"DYNAMIC_PS_POLL_VALUE", + (unsigned char *)"PS_NULLDATA_AP_RESP_TIMEOUT", + (unsigned char *)"TELE_BCN_WAKEUP_EN", + (unsigned char *)"TELE_BCN_TRANS_LI", + (unsigned char *)"TELE_BCN_TRANS_LI_IDLE_BCNS", + (unsigned char *)"TELE_BCN_MAX_LI", + (unsigned char *)"TELE_BCN_MAX_LI_IDLE_BCNS", + (unsigned char *)"BTC_A2DP_DHCP_BT_SUB_INTERVALS", + (unsigned char *)"INFRA_STA_KEEP_ALIVE_PERIOD", + (unsigned char *)"ASSOC_STA_LIMIT", + (unsigned char *)"SAP_CHANNEL_SELECT_START_CHANNEL", + (unsigned char *)"SAP_CHANNEL_SELECT_END_CHANNEL", + (unsigned char *)"SAP_CHANNEL_SELECT_OPERATING_BAND", + (unsigned char *)"AP_DATA_AVAIL_POLL_PERIOD", + (unsigned char *)"ENABLE_LTE_COEX", + (unsigned char *)"AP_KEEP_ALIVE_TIMEOUT", + (unsigned char *)"GO_KEEP_ALIVE_TIMEOUT", + (unsigned char *)"ENABLE_MC_ADDR_LIST", + (unsigned char *)"ENABLE_UC_FILTER", + (unsigned char *)"ENABLE_LPWR_IMG_TRANSITION", + (unsigned char *)"ENABLE_MCC_ADAPTIVE_SCHED", + (unsigned char *)"DISABLE_LDPC_WITH_TXBF_AP", + (unsigned char *)"AP_LINK_MONITOR_TIMEOUT", + (unsigned char *)"TDLS_QOS_WMM_UAPSD_MASK", + (unsigned char *)"TDLS_BUF_STA_ENABLED", + (unsigned char *)"TDLS_PUAPSD_INACT_TIME", + (unsigned char *)"TDLS_RX_FRAME_THRESHOLD", + (unsigned char *)"PMF_SA_QUERY_MAX_RETRIES", + (unsigned char *)"PMF_SA_QUERY_RETRY_INTERVAL", + (unsigned char *)"ENABLE_ADAPT_RX_DRAIN", + (unsigned char *)"ANTENNA_DIVESITY", + (unsigned char *)"GO_LINK_MONITOR_TIMEOUT", + (unsigned char *)"RMC_ACTION_PERIOD_FREQUENCY", + (unsigned char *)"CURRENT_RSSI", + (unsigned char *)"RTT3_ENABLE", + (unsigned char *)"DEBUG_P2P_REMAIN_ON_CHANNEL", + (unsigned char *)"TDLS_OFF_CHANNEL_ENABLED", + (unsigned char *)"IBSS_ATIM_WIN_SIZE", + (unsigned char *)"DFS_MASTER_ENABLED", + (unsigned char *)"VHT_ENABLE_TXBF_20MHZ", + (unsigned char *)"TDLS_WMM_MODE_ENABLED", + (unsigned char *)"OBSS_HT40_SCAN_PASSIVE_DWELL_TIME", + (unsigned char *)"OBSS_HT40_SCAN_ACTIVE_DWELL_TIME", + (unsigned char *)"OBSS_HT40_SCAN_WIDTH_TRIGGER_INTERVAL", + (unsigned char *)"OBSS_HT40_SCAN_PASSIVE_TOTAL_PER_CHANNEL", + (unsigned char *)"OBSS_HT40_SCAN_ACTIVE_TOTAL_PER_CHANNEL", + (unsigned char *)"OBSS_HT40_WIDTH_CH_TRANSITION_DELAY", + (unsigned char *)"OBSS_HT40_SCAN_ACTIVITY_THRESHOLD", + (unsigned char *)"TGT_GTX_USR_CFG", + (unsigned char *)"MAX_HT_MCS_TX_DATA", + (unsigned char *)"DISABLE_ABG_RATE_TX_DATA", + (unsigned char *)"RATE_FOR_TX_MGMT", +}; diff --git a/drivers/staging/qcacld-3.0/core/mac/src/cfg/cfg_priv.h b/drivers/staging/qcacld-3.0/core/mac/src/cfg/cfg_priv.h new file mode 100644 index 0000000000000000000000000000000000000000..78769f59c229d8e18bc037748717acd2e53fa763 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/cfg/cfg_priv.h @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2011-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * + * This is the private header file for CFG module. + * + * Author: Kevin Nguyen + * Date: 03/20/02 + * History:- + * 03/20/02 Created. + * -------------------------------------------------------------------- + * + */ + +#ifndef __CFGPRIV_H +#define __CFGPRIV_H + +#include +#include +#include +#include +#include +#include +#include +#include "cfg_def.h" + +#include + +/*--------------------------------------------------------------------*/ +/* CFG miscellaneous definition */ +/*--------------------------------------------------------------------*/ + +/* Function index bit mask */ +#define CFG_FUNC_INDX_MASK 0x7f +#define CFG_GET_FUNC_INDX(val) (val & CFG_FUNC_INDX_MASK) + +/* Macro to convert return code to debug string index */ +#define CFG_GET_DBG_INDX(val) (val - eCFG_SUCCESS - 1) + +/*--------------------------------------------------------------------*/ +/* Binary header structure */ +/*--------------------------------------------------------------------*/ +typedef struct sCfgBinHdr { + uint32_t hdrInfo; + uint32_t controlSize; + uint32_t iBufSize; + uint32_t sBufSize; +} tCfgBinHdr, *tpCfgBinHdr; + +/*--------------------------------------------------------------------*/ +/* Polaris HW counter access structure */ +/*--------------------------------------------------------------------*/ + +#define CFG_STAT_CNT_LO_MASK 0x0000ffff +#define CFG_STAT_CNT_HI_MASK 0xffff0000 +#define CFG_STAT_CNT_HI_INCR 0x00010000 + +/*--------------------------------------------------------------------*/ +/* CFG function prototypes */ +/*--------------------------------------------------------------------*/ + +extern void cfg_send_host_msg(tpAniSirGlobal, uint16_t, uint32_t, uint32_t, + uint32_t *, uint32_t, uint32_t *); + +#endif /* __CFGPRIV_H */ diff --git a/drivers/staging/qcacld-3.0/core/mac/src/cfg/cfg_proc_msg.c b/drivers/staging/qcacld-3.0/core/mac/src/cfg/cfg_proc_msg.c new file mode 100644 index 0000000000000000000000000000000000000000..ac3d769d1a67e631ed09cce533f220a779c8042f --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/cfg/cfg_proc_msg.c @@ -0,0 +1,2212 @@ +/* + * Copyright (c) 2011-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * This file contains CFG functions for processing host messages. + */ +#include "cds_api.h" +#include "ani_global.h" +#include "cfg_priv.h" +#include "cfg_debug.h" +#include "wma_types.h" + +cgstatic cfg_static[CFG_PARAM_MAX_NUM] = { + {WNI_CFG_STA_ID, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_RELOAD | + CFG_CTL_NTF_HAL, + 0, 255, 1}, + {WNI_CFG_CFP_PERIOD, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_INT, + WNI_CFG_CFP_PERIOD_STAMIN, + WNI_CFG_CFP_PERIOD_STAMAX, + WNI_CFG_CFP_PERIOD_STADEF}, + {WNI_CFG_CFP_MAX_DURATION, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_INT, + WNI_CFG_CFP_MAX_DURATION_STAMIN, + WNI_CFG_CFP_MAX_DURATION_STAMAX, + WNI_CFG_CFP_MAX_DURATION_STADEF}, + {WNI_CFG_SSID, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_RESTART, + 0, 255, 6}, + {WNI_CFG_BEACON_INTERVAL, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_SCH, + WNI_CFG_BEACON_INTERVAL_STAMIN, + WNI_CFG_BEACON_INTERVAL_STAMAX, + WNI_CFG_BEACON_INTERVAL_STADEF}, + {WNI_CFG_DTIM_PERIOD, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_INT, + WNI_CFG_DTIM_PERIOD_STAMIN, + WNI_CFG_DTIM_PERIOD_STAMAX, + WNI_CFG_DTIM_PERIOD_STADEF}, + {WNI_CFG_WEP_KEY_LENGTH, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_RESTART, + WNI_CFG_WEP_KEY_LENGTH_STAMIN, + WNI_CFG_WEP_KEY_LENGTH_STAMAX, + WNI_CFG_WEP_KEY_LENGTH_STADEF}, + {WNI_CFG_WEP_DEFAULT_KEY_1, + CFG_CTL_VALID | CFG_CTL_WE | CFG_CTL_RESTART, + 0, 65535, 0}, + {WNI_CFG_WEP_DEFAULT_KEY_2, + CFG_CTL_VALID | CFG_CTL_WE | CFG_CTL_RESTART, + 1, 1, 1}, + {WNI_CFG_WEP_DEFAULT_KEY_3, + CFG_CTL_VALID | CFG_CTL_WE | CFG_CTL_RESTART, + 0, 5, 5}, + {WNI_CFG_WEP_DEFAULT_KEY_4, + CFG_CTL_VALID | CFG_CTL_WE | CFG_CTL_RESTART, + 0, 1, 0}, + {WNI_CFG_WEP_DEFAULT_KEYID, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_WEP_DEFAULT_KEYID_STAMIN, + WNI_CFG_WEP_DEFAULT_KEYID_STAMAX, + WNI_CFG_WEP_DEFAULT_KEYID_STADEF}, + {WNI_CFG_EXCLUDE_UNENCRYPTED, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_EXCLUDE_UNENCRYPTED_STAMIN, + WNI_CFG_EXCLUDE_UNENCRYPTED_STAMAX, + WNI_CFG_EXCLUDE_UNENCRYPTED_STADEF}, + {WNI_CFG_RTS_THRESHOLD, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_HAL, + WNI_CFG_RTS_THRESHOLD_STAMIN, + WNI_CFG_RTS_THRESHOLD_STAMAX, + WNI_CFG_RTS_THRESHOLD_STADEF}, + {WNI_CFG_SHORT_RETRY_LIMIT, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_HAL, + WNI_CFG_SHORT_RETRY_LIMIT_STAMIN, + WNI_CFG_SHORT_RETRY_LIMIT_STAMAX, + WNI_CFG_SHORT_RETRY_LIMIT_STADEF}, + {WNI_CFG_LONG_RETRY_LIMIT, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_HAL, + WNI_CFG_LONG_RETRY_LIMIT_STAMIN, + WNI_CFG_LONG_RETRY_LIMIT_STAMAX, + WNI_CFG_LONG_RETRY_LIMIT_STADEF}, + {WNI_CFG_FRAGMENTATION_THRESHOLD, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_HAL, + WNI_CFG_FRAGMENTATION_THRESHOLD_STAMIN, + WNI_CFG_FRAGMENTATION_THRESHOLD_STAMAX, + WNI_CFG_FRAGMENTATION_THRESHOLD_STADEF}, + {WNI_CFG_ACTIVE_MINIMUM_CHANNEL_TIME, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_ACTIVE_MINIMUM_CHANNEL_TIME_STAMIN, + WNI_CFG_ACTIVE_MINIMUM_CHANNEL_TIME_STAMAX, + WNI_CFG_ACTIVE_MINIMUM_CHANNEL_TIME_STADEF}, + {WNI_CFG_ACTIVE_MAXIMUM_CHANNEL_TIME, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_ACTIVE_MAXIMUM_CHANNEL_TIME_STAMIN, + WNI_CFG_ACTIVE_MAXIMUM_CHANNEL_TIME_STAMAX, + WNI_CFG_ACTIVE_MAXIMUM_CHANNEL_TIME_STADEF}, + {WNI_CFG_PASSIVE_MINIMUM_CHANNEL_TIME, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_PASSIVE_MINIMUM_CHANNEL_TIME_STAMIN, + WNI_CFG_PASSIVE_MINIMUM_CHANNEL_TIME_STAMAX, + WNI_CFG_PASSIVE_MINIMUM_CHANNEL_TIME_STADEF}, + {WNI_CFG_PASSIVE_MAXIMUM_CHANNEL_TIME, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_PASSIVE_MAXIMUM_CHANNEL_TIME_STAMIN, + WNI_CFG_PASSIVE_MAXIMUM_CHANNEL_TIME_STAMAX, + WNI_CFG_PASSIVE_MAXIMUM_CHANNEL_TIME_STADEF}, + {WNI_CFG_JOIN_FAILURE_TIMEOUT, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_JOIN_FAILURE_TIMEOUT_STAMIN, + WNI_CFG_JOIN_FAILURE_TIMEOUT_STAMAX, + WNI_CFG_JOIN_FAILURE_TIMEOUT_STADEF}, + {WNI_CFG_AUTHENTICATE_FAILURE_TIMEOUT, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_AUTHENTICATE_FAILURE_TIMEOUT_STAMIN, + WNI_CFG_AUTHENTICATE_FAILURE_TIMEOUT_STAMAX, + WNI_CFG_AUTHENTICATE_FAILURE_TIMEOUT_STADEF}, + {WNI_CFG_AUTHENTICATE_RSP_TIMEOUT, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_AUTHENTICATE_RSP_TIMEOUT_STAMIN, + WNI_CFG_AUTHENTICATE_RSP_TIMEOUT_STAMAX, + WNI_CFG_AUTHENTICATE_RSP_TIMEOUT_STADEF}, + {WNI_CFG_ASSOCIATION_FAILURE_TIMEOUT, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_ASSOCIATION_FAILURE_TIMEOUT_STAMIN, + WNI_CFG_ASSOCIATION_FAILURE_TIMEOUT_STAMAX, + WNI_CFG_ASSOCIATION_FAILURE_TIMEOUT_STADEF}, + {WNI_CFG_REASSOCIATION_FAILURE_TIMEOUT, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_REASSOCIATION_FAILURE_TIMEOUT_STAMIN, + WNI_CFG_REASSOCIATION_FAILURE_TIMEOUT_STAMAX, + WNI_CFG_REASSOCIATION_FAILURE_TIMEOUT_STADEF}, + {WNI_CFG_PS_ENABLE_BCN_FILTER, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_HAL, + WNI_CFG_PS_ENABLE_BCN_FILTER_STAMIN, + WNI_CFG_PS_ENABLE_BCN_FILTER_STAMAX, + WNI_CFG_PS_ENABLE_BCN_FILTER_STADEF}, + {WNI_CFG_PS_ENABLE_HEART_BEAT, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_HAL, + WNI_CFG_PS_ENABLE_HEART_BEAT_STAMIN, + WNI_CFG_PS_ENABLE_HEART_BEAT_STAMAX, + WNI_CFG_PS_ENABLE_HEART_BEAT_STADEF}, + {WNI_CFG_PS_ENABLE_RSSI_MONITOR, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_HAL, + WNI_CFG_PS_ENABLE_RSSI_MONITOR_STAMIN, + WNI_CFG_PS_ENABLE_RSSI_MONITOR_STAMAX, + WNI_CFG_PS_ENABLE_RSSI_MONITOR_STADEF}, + {WNI_CFG_PS_DATA_INACTIVITY_TIMEOUT, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_HAL, + WNI_CFG_PS_DATA_INACTIVITY_TIMEOUT_STAMIN, + WNI_CFG_PS_DATA_INACTIVITY_TIMEOUT_STAMAX, + WNI_CFG_PS_DATA_INACTIVITY_TIMEOUT_STADEF}, + {WNI_CFG_RF_SETTLING_TIME_CLK, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_HAL, + WNI_CFG_RF_SETTLING_TIME_CLK_STAMIN, + WNI_CFG_RF_SETTLING_TIME_CLK_STAMAX, + WNI_CFG_RF_SETTLING_TIME_CLK_STADEF}, + {WNI_CFG_SUPPORTED_RATES_11B, + CFG_CTL_VALID | CFG_CTL_RE, + 0, 3, 1}, + {WNI_CFG_SUPPORTED_RATES_11A, CFG_CTL_VALID | CFG_CTL_RE, + 0, 255, 15}, + {WNI_CFG_PHY_MODE, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_RESTART, + WNI_CFG_PHY_MODE_STAMIN, + WNI_CFG_PHY_MODE_STAMAX, + WNI_CFG_PHY_MODE_STADEF}, + {WNI_CFG_DOT11_MODE, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | CFG_CTL_RESTART | + CFG_CTL_NTF_LIM, + WNI_CFG_DOT11_MODE_STAMIN, + WNI_CFG_DOT11_MODE_STAMAX, + WNI_CFG_DOT11_MODE_STADEF}, + {WNI_CFG_OPERATIONAL_RATE_SET, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_RESTART, + 0, 1, 1}, + {WNI_CFG_EXTENDED_OPERATIONAL_RATE_SET, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_RESTART, + 0, 65535, 65534}, + {WNI_CFG_PROPRIETARY_OPERATIONAL_RATE_SET, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_RESTART, + 0, 0, 0}, + {WNI_CFG_LISTEN_INTERVAL, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_RESTART, + WNI_CFG_LISTEN_INTERVAL_STAMIN, + WNI_CFG_LISTEN_INTERVAL_STAMAX, + WNI_CFG_LISTEN_INTERVAL_STADEF}, + {WNI_CFG_VALID_CHANNEL_LIST, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_RESTART | + CFG_CTL_NTF_LIM, + 0, 1, 1}, + {WNI_CFG_CURRENT_CHANNEL, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_INT, + WNI_CFG_CURRENT_CHANNEL_STAMIN, + WNI_CFG_CURRENT_CHANNEL_STAMAX, + WNI_CFG_CURRENT_CHANNEL_STADEF}, + {WNI_CFG_DEFAULT_RATE_INDEX_24GHZ, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_DEFAULT_RATE_INDEX_24GHZ_STAMIN, + WNI_CFG_DEFAULT_RATE_INDEX_24GHZ_STAMAX, + WNI_CFG_DEFAULT_RATE_INDEX_24GHZ_STADEF}, + {WNI_CFG_FIXED_RATE, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_HAL, + WNI_CFG_FIXED_RATE_STAMIN, + WNI_CFG_FIXED_RATE_STAMAX, + WNI_CFG_FIXED_RATE_STADEF}, + {WNI_CFG_APSD_ENABLED, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_APSD_ENABLED_STAMIN, + WNI_CFG_APSD_ENABLED_STAMAX, + WNI_CFG_APSD_ENABLED_STADEF}, + {WNI_CFG_SHARED_KEY_AUTH_ENABLE, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_SHARED_KEY_AUTH_ENABLE_STAMIN, + WNI_CFG_SHARED_KEY_AUTH_ENABLE_STAMAX, + WNI_CFG_SHARED_KEY_AUTH_ENABLE_STADEF}, + {WNI_CFG_OPEN_SYSTEM_AUTH_ENABLE, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_OPEN_SYSTEM_AUTH_ENABLE_STAMIN, + WNI_CFG_OPEN_SYSTEM_AUTH_ENABLE_STAMAX, + WNI_CFG_OPEN_SYSTEM_AUTH_ENABLE_STADEF}, + {WNI_CFG_AUTHENTICATION_TYPE, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_RESTART, + WNI_CFG_AUTHENTICATION_TYPE_STAMIN, + WNI_CFG_AUTHENTICATION_TYPE_STAMAX, + WNI_CFG_AUTHENTICATION_TYPE_STADEF}, + {WNI_CFG_PRIVACY_ENABLED, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_RESTART, + WNI_CFG_PRIVACY_ENABLED_STAMIN, + WNI_CFG_PRIVACY_ENABLED_STAMAX, + WNI_CFG_PRIVACY_ENABLED_STADEF}, + {WNI_CFG_SHORT_PREAMBLE, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_RESTART, + WNI_CFG_SHORT_PREAMBLE_STAMIN, + WNI_CFG_SHORT_PREAMBLE_STAMAX, + WNI_CFG_SHORT_PREAMBLE_STADEF}, + {WNI_CFG_ACCEPT_SHORT_SLOT_ASSOC_ONLY, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_RESTART, + WNI_CFG_ACCEPT_SHORT_SLOT_ASSOC_ONLY_STAMIN, + WNI_CFG_ACCEPT_SHORT_SLOT_ASSOC_ONLY_STAMAX, + WNI_CFG_ACCEPT_SHORT_SLOT_ASSOC_ONLY_STADEF}, + {WNI_CFG_QOS_ENABLED, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_RESTART, + WNI_CFG_QOS_ENABLED_STAMIN, + WNI_CFG_QOS_ENABLED_STAMAX, + WNI_CFG_QOS_ENABLED_STADEF}, + {WNI_CFG_HCF_ENABLED, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_RESTART, + WNI_CFG_HCF_ENABLED_STAMIN, + WNI_CFG_HCF_ENABLED_STAMAX, + WNI_CFG_HCF_ENABLED_STADEF}, + {WNI_CFG_RSN_ENABLED, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_RESTART, + WNI_CFG_RSN_ENABLED_STAMIN, + WNI_CFG_RSN_ENABLED_STAMAX, + WNI_CFG_RSN_ENABLED_STADEF}, + {WNI_CFG_MAX_NUM_PRE_AUTH, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_RESTART, + WNI_CFG_MAX_NUM_PRE_AUTH_STAMIN, + WNI_CFG_MAX_NUM_PRE_AUTH_STAMAX, + WNI_CFG_MAX_NUM_PRE_AUTH_STADEF}, + {WNI_CFG_HEART_BEAT_THRESHOLD, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_HEART_BEAT_THRESHOLD_STAMIN, + WNI_CFG_HEART_BEAT_THRESHOLD_STAMAX, + WNI_CFG_HEART_BEAT_THRESHOLD_STADEF}, + {WNI_CFG_PROBE_AFTER_HB_FAIL_TIMEOUT, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | + CFG_CTL_INT, + WNI_CFG_PROBE_AFTER_HB_FAIL_TIMEOUT_STAMIN, + WNI_CFG_PROBE_AFTER_HB_FAIL_TIMEOUT_STAMAX, + WNI_CFG_PROBE_AFTER_HB_FAIL_TIMEOUT_STADEF}, + {WNI_CFG_MANUFACTURER_NAME, + CFG_CTL_VALID | CFG_CTL_RE, + 0, 0, 0}, + {WNI_CFG_MODEL_NUMBER, + CFG_CTL_VALID | CFG_CTL_RE, + 0, 0, 0}, + {WNI_CFG_MODEL_NAME, + CFG_CTL_VALID | CFG_CTL_RE, + 0, 0, 0}, + {WNI_CFG_MANUFACTURER_PRODUCT_NAME, + CFG_CTL_VALID | CFG_CTL_RE, + 0, 0, 0}, + {WNI_CFG_MANUFACTURER_PRODUCT_VERSION, + CFG_CTL_VALID | CFG_CTL_RE, + 0, 0, 0}, + {WNI_CFG_11D_ENABLED, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_RESTART, + WNI_CFG_11D_ENABLED_STAMIN, + WNI_CFG_11D_ENABLED_STAMAX, + WNI_CFG_11D_ENABLED_STADEF}, + {WNI_CFG_MAX_TX_POWER_2_4, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE, + 0, 0, 0}, + {WNI_CFG_MAX_TX_POWER_5, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE, + 0, 0, 0}, + {WNI_CFG_CURRENT_TX_POWER_LEVEL, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_CURRENT_TX_POWER_LEVEL_STAMIN, + WNI_CFG_CURRENT_TX_POWER_LEVEL_STAMAX, + WNI_CFG_CURRENT_TX_POWER_LEVEL_STADEF}, + {WNI_CFG_NEW_BSS_FOUND_IND, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_NEW_BSS_FOUND_IND_STAMIN, + WNI_CFG_NEW_BSS_FOUND_IND_STAMAX, + WNI_CFG_NEW_BSS_FOUND_IND_STADEF}, + {WNI_CFG_COUNTRY_CODE, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE, + 0, 0, 0}, + {WNI_CFG_11H_ENABLED, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_RESTART, + WNI_CFG_11H_ENABLED_STAMIN, + WNI_CFG_11H_ENABLED_STAMAX, + WNI_CFG_11H_ENABLED_STADEF}, + {WNI_CFG_WT_CNF_TIMEOUT, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_WT_CNF_TIMEOUT_STAMIN, + WNI_CFG_WT_CNF_TIMEOUT_STAMAX, + WNI_CFG_WT_CNF_TIMEOUT_STADEF}, + {WNI_CFG_LOG_LEVEL, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_LOG_LEVEL_STAMIN, + WNI_CFG_LOG_LEVEL_STAMAX, + WNI_CFG_LOG_LEVEL_STADEF}, + {WNI_CFG_OLBC_DETECT_TIMEOUT, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_OLBC_DETECT_TIMEOUT_STAMIN, + WNI_CFG_OLBC_DETECT_TIMEOUT_STAMAX, + WNI_CFG_OLBC_DETECT_TIMEOUT_STADEF}, + {WNI_CFG_PROTECTION_ENABLED, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_RESTART | CFG_CTL_NTF_LIM, + WNI_CFG_PROTECTION_ENABLED_STAMIN, + WNI_CFG_PROTECTION_ENABLED_STAMAX, + WNI_CFG_PROTECTION_ENABLED_STADEF}, + {WNI_CFG_11G_PROTECTION_ALWAYS, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_RESTART, + WNI_CFG_11G_PROTECTION_ALWAYS_STAMIN, + WNI_CFG_11G_PROTECTION_ALWAYS_STAMAX, + WNI_CFG_11G_PROTECTION_ALWAYS_STADEF}, + {WNI_CFG_FORCE_POLICY_PROTECTION, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_RESTART | CFG_CTL_NTF_HAL, + WNI_CFG_FORCE_POLICY_PROTECTION_STAMIN, + WNI_CFG_FORCE_POLICY_PROTECTION_STAMAX, + WNI_CFG_FORCE_POLICY_PROTECTION_STADEF}, + {WNI_CFG_11G_SHORT_PREAMBLE_ENABLED, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_RESTART, + WNI_CFG_11G_SHORT_PREAMBLE_ENABLED_STAMIN, + WNI_CFG_11G_SHORT_PREAMBLE_ENABLED_STAMAX, + WNI_CFG_11G_SHORT_PREAMBLE_ENABLED_STADEF}, + {WNI_CFG_11G_SHORT_SLOT_TIME_ENABLED, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_RESTART, + WNI_CFG_11G_SHORT_SLOT_TIME_ENABLED_STAMIN, + WNI_CFG_11G_SHORT_SLOT_TIME_ENABLED_STAMAX, + WNI_CFG_11G_SHORT_SLOT_TIME_ENABLED_STADEF}, + {WNI_CFG_11G_ONLY_POLICY, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_11G_ONLY_POLICY_STAMIN, + WNI_CFG_11G_ONLY_POLICY_STAMAX, + WNI_CFG_11G_ONLY_POLICY_STADEF}, + {WNI_CFG_WME_ENABLED, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_RESTART, + WNI_CFG_WME_ENABLED_STAMIN, + WNI_CFG_WME_ENABLED_STAMAX, + WNI_CFG_WME_ENABLED_STADEF}, + {WNI_CFG_ADDTS_RSP_TIMEOUT, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_ADDTS_RSP_TIMEOUT_STAMIN, + WNI_CFG_ADDTS_RSP_TIMEOUT_STAMAX, + WNI_CFG_ADDTS_RSP_TIMEOUT_STADEF}, + {WNI_CFG_MAX_SP_LENGTH, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_MAX_SP_LENGTH_STAMIN, + WNI_CFG_MAX_SP_LENGTH_STAMAX, + WNI_CFG_MAX_SP_LENGTH_STADEF}, + {WNI_CFG_WSM_ENABLED, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_WSM_ENABLED_STAMIN, + WNI_CFG_WSM_ENABLED_STAMAX, + WNI_CFG_WSM_ENABLED_STADEF}, + {WNI_CFG_EDCA_PROFILE, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_SCH, + WNI_CFG_EDCA_PROFILE_STAMIN, + WNI_CFG_EDCA_PROFILE_STAMAX, + WNI_CFG_EDCA_PROFILE_STADEF}, + {WNI_CFG_EDCA_ANI_ACBK_LOCAL, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_RESTART, + 0, 0, 0}, + {WNI_CFG_EDCA_ANI_ACBE_LOCAL, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_RESTART, + 0, 0, 0}, + {WNI_CFG_EDCA_ANI_ACVI_LOCAL, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_RESTART, + 0, 0, 0}, + {WNI_CFG_EDCA_ANI_ACVO_LOCAL, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_RESTART, + 0, 0, 0}, + {WNI_CFG_EDCA_ANI_ACBK, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_RESTART, + 0, 0, 0}, + {WNI_CFG_EDCA_ANI_ACBE, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_RESTART, + 0, 0, 0}, + {WNI_CFG_EDCA_ANI_ACVI, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_RESTART, + 0, 0, 0}, + {WNI_CFG_EDCA_ANI_ACVO, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_RESTART, + 0, 0, 0}, + {WNI_CFG_EDCA_WME_ACBK_LOCAL, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_RESTART, + 0, 0, 0}, + {WNI_CFG_EDCA_WME_ACBE_LOCAL, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_RESTART, + 0, 0, 0}, + {WNI_CFG_EDCA_WME_ACVI_LOCAL, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_RESTART, + 0, 0, 0}, + {WNI_CFG_EDCA_WME_ACVO_LOCAL, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_RESTART, + 0, 0, 0}, + {WNI_CFG_EDCA_WME_ACBK, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_RESTART, + 0, 0, 0}, + {WNI_CFG_EDCA_WME_ACBE, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_RESTART, + 0, 0, 0}, + {WNI_CFG_EDCA_WME_ACVI, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_RESTART, + 0, 0, 0}, + {WNI_CFG_EDCA_WME_ACVO, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_RESTART, + 0, 0, 0}, + {WNI_CFG_LOCAL_POWER_CONSTRAINT, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_RESTART, + WNI_CFG_LOCAL_POWER_CONSTRAINT_STAMIN, + WNI_CFG_LOCAL_POWER_CONSTRAINT_STAMAX, + WNI_CFG_LOCAL_POWER_CONSTRAINT_STADEF}, + {WNI_CFG_ADMIT_POLICY, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_RESTART, + WNI_CFG_ADMIT_POLICY_STAMIN, + WNI_CFG_ADMIT_POLICY_STAMAX, + WNI_CFG_ADMIT_POLICY_STADEF}, + {WNI_CFG_ADMIT_BWFACTOR, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_RESTART, + WNI_CFG_ADMIT_BWFACTOR_STAMIN, + WNI_CFG_ADMIT_BWFACTOR_STAMAX, + WNI_CFG_ADMIT_BWFACTOR_STADEF}, + {WNI_CFG_CHANNEL_BONDING_MODE, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_RESTART | CFG_CTL_NTF_LIM, + WNI_CFG_CHANNEL_BONDING_MODE_STAMIN, + WNI_CFG_CHANNEL_BONDING_MODE_STAMAX, + WNI_CFG_CHANNEL_BONDING_MODE_STADEF}, + {WNI_CFG_DYNAMIC_THRESHOLD_ZERO, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_HAL, + WNI_CFG_DYNAMIC_THRESHOLD_ZERO_STAMIN, + WNI_CFG_DYNAMIC_THRESHOLD_ZERO_STAMAX, + WNI_CFG_DYNAMIC_THRESHOLD_ZERO_STADEF}, + {WNI_CFG_DYNAMIC_THRESHOLD_ONE, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_HAL, + WNI_CFG_DYNAMIC_THRESHOLD_ONE_STAMIN, + WNI_CFG_DYNAMIC_THRESHOLD_ONE_STAMAX, + WNI_CFG_DYNAMIC_THRESHOLD_ONE_STADEF}, + {WNI_CFG_DYNAMIC_THRESHOLD_TWO, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_HAL, + WNI_CFG_DYNAMIC_THRESHOLD_TWO_STAMIN, + WNI_CFG_DYNAMIC_THRESHOLD_TWO_STAMAX, + WNI_CFG_DYNAMIC_THRESHOLD_TWO_STADEF}, + {WNI_CFG_SCAN_CONTROL_LIST, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_RESTART | + CFG_CTL_NTF_LIM, + 0, 0, 0}, + {WNI_CFG_BLOCK_ACK_ENABLED, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_RESTART | CFG_CTL_NTF_LIM, + WNI_CFG_BLOCK_ACK_ENABLED_STAMIN, + WNI_CFG_BLOCK_ACK_ENABLED_STAMAX, + WNI_CFG_BLOCK_ACK_ENABLED_STADEF}, + {WNI_CFG_HT_CAP_INFO, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_RESTART | CFG_CTL_NTF_LIM, + WNI_CFG_HT_CAP_INFO_STAMIN, + WNI_CFG_HT_CAP_INFO_STAMAX, + WNI_CFG_HT_CAP_INFO_STADEF}, + {WNI_CFG_HT_AMPDU_PARAMS, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_RESTART | CFG_CTL_NTF_LIM, + WNI_CFG_HT_AMPDU_PARAMS_STAMIN, + WNI_CFG_HT_AMPDU_PARAMS_STAMAX, + WNI_CFG_HT_AMPDU_PARAMS_STADEF}, + {WNI_CFG_SUPPORTED_MCS_SET, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_SAVE | + CFG_CTL_RESTART | CFG_CTL_NTF_LIM, + 0, 0, 0}, + {WNI_CFG_EXT_HT_CAP_INFO, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | CFG_CTL_SAVE | + CFG_CTL_RESTART | CFG_CTL_NTF_LIM, + WNI_CFG_EXT_HT_CAP_INFO_STAMIN, + WNI_CFG_EXT_HT_CAP_INFO_STAMAX, + WNI_CFG_EXT_HT_CAP_INFO_STADEF}, + {WNI_CFG_TX_BF_CAP, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_INT | CFG_CTL_RESTART | + CFG_CTL_NTF_LIM, + WNI_CFG_TX_BF_CAP_STAMIN, + 4294967295u, + WNI_CFG_TX_BF_CAP_STADEF}, + {WNI_CFG_AS_CAP, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | CFG_CTL_SAVE | + CFG_CTL_RESTART | CFG_CTL_NTF_LIM, + WNI_CFG_AS_CAP_STAMIN, + WNI_CFG_AS_CAP_STAMAX, + WNI_CFG_AS_CAP_STADEF}, + {WNI_CFG_HT_INFO_FIELD1, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_RESTART | CFG_CTL_NTF_LIM, + WNI_CFG_HT_INFO_FIELD1_STAMIN, + WNI_CFG_HT_INFO_FIELD1_STAMAX, + WNI_CFG_HT_INFO_FIELD1_STADEF}, + {WNI_CFG_HT_INFO_FIELD2, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | CFG_CTL_SAVE | + CFG_CTL_NTF_LIM, + WNI_CFG_HT_INFO_FIELD2_STAMIN, + WNI_CFG_HT_INFO_FIELD2_STAMAX, + WNI_CFG_HT_INFO_FIELD2_STADEF}, + {WNI_CFG_HT_INFO_FIELD3, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | CFG_CTL_SAVE | + CFG_CTL_NTF_LIM, + WNI_CFG_HT_INFO_FIELD3_STAMIN, + WNI_CFG_HT_INFO_FIELD3_STAMAX, + WNI_CFG_HT_INFO_FIELD3_STADEF}, + {WNI_CFG_BASIC_MCS_SET, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_SAVE | + CFG_CTL_RESTART | CFG_CTL_NTF_LIM, + 0, 0, 0}, + {WNI_CFG_CURRENT_MCS_SET, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_SAVE | + CFG_CTL_RESTART | CFG_CTL_NTF_LIM, + 0, 0, 0}, + {WNI_CFG_VHT_MAX_MPDU_LENGTH, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_VHT_MAX_MPDU_LENGTH_STAMIN, + WNI_CFG_VHT_MAX_MPDU_LENGTH_STAMAX, + WNI_CFG_VHT_MAX_MPDU_LENGTH_STADEF}, + {WNI_CFG_VHT_SUPPORTED_CHAN_WIDTH_SET, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_VHT_SUPPORTED_CHAN_WIDTH_SET_STAMIN, + WNI_CFG_VHT_SUPPORTED_CHAN_WIDTH_SET_STAMAX, + WNI_CFG_VHT_SUPPORTED_CHAN_WIDTH_SET_STADEF}, + {WNI_CFG_VHT_LDPC_CODING_CAP, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_VHT_LDPC_CODING_CAP_STAMIN, + WNI_CFG_VHT_LDPC_CODING_CAP_STAMAX, + WNI_CFG_VHT_LDPC_CODING_CAP_STADEF}, + {WNI_CFG_VHT_SHORT_GI_80MHZ, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_VHT_SHORT_GI_80MHZ_STAMIN, + WNI_CFG_VHT_SHORT_GI_80MHZ_STAMAX, + WNI_CFG_VHT_SHORT_GI_80MHZ_STADEF}, + {WNI_CFG_VHT_SHORT_GI_160_AND_80_PLUS_80MHZ, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_VHT_SHORT_GI_160_AND_80_PLUS_80MHZ_STAMIN, + WNI_CFG_VHT_SHORT_GI_160_AND_80_PLUS_80MHZ_STAMAX, + WNI_CFG_VHT_SHORT_GI_160_AND_80_PLUS_80MHZ_STADEF}, + {WNI_CFG_VHT_TXSTBC, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_VHT_TXSTBC_STAMIN, + WNI_CFG_VHT_TXSTBC_STAMAX, + WNI_CFG_VHT_TXSTBC_STADEF}, + {WNI_CFG_VHT_RXSTBC, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_VHT_RXSTBC_STAMIN, + WNI_CFG_VHT_RXSTBC_STAMAX, + WNI_CFG_VHT_RXSTBC_STADEF}, + {WNI_CFG_VHT_SU_BEAMFORMER_CAP, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_VHT_SU_BEAMFORMER_CAP_STAMIN, + WNI_CFG_VHT_SU_BEAMFORMER_CAP_STAMAX, + WNI_CFG_VHT_SU_BEAMFORMER_CAP_STADEF}, + {WNI_CFG_VHT_SU_BEAMFORMEE_CAP, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_VHT_SU_BEAMFORMEE_CAP_STAMIN, + WNI_CFG_VHT_SU_BEAMFORMEE_CAP_STAMAX, + WNI_CFG_VHT_SU_BEAMFORMEE_CAP_STADEF}, + {WNI_CFG_VHT_CSN_BEAMFORMEE_ANT_SUPPORTED, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_VHT_CSN_BEAMFORMEE_ANT_SUPPORTED_STAMIN, + WNI_CFG_VHT_CSN_BEAMFORMEE_ANT_SUPPORTED_STAMAX, + WNI_CFG_VHT_CSN_BEAMFORMEE_ANT_SUPPORTED_STADEF}, + {WNI_CFG_VHT_NUM_SOUNDING_DIMENSIONS, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_VHT_NUM_SOUNDING_DIMENSIONS_STAMIN, + WNI_CFG_VHT_NUM_SOUNDING_DIMENSIONS_STAMAX, + WNI_CFG_VHT_NUM_SOUNDING_DIMENSIONS_STADEF}, + {WNI_CFG_VHT_MU_BEAMFORMER_CAP, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_VHT_MU_BEAMFORMER_CAP_STAMIN, + WNI_CFG_VHT_MU_BEAMFORMER_CAP_STAMAX, + WNI_CFG_VHT_MU_BEAMFORMER_CAP_STADEF}, + {WNI_CFG_VHT_MU_BEAMFORMEE_CAP, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_VHT_MU_BEAMFORMEE_CAP_STAMIN, + WNI_CFG_VHT_MU_BEAMFORMEE_CAP_STAMAX, + WNI_CFG_VHT_MU_BEAMFORMEE_CAP_STADEF}, + {WNI_CFG_VHT_TXOP_PS, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_VHT_TXOP_PS_STAMIN, + WNI_CFG_VHT_TXOP_PS_STAMAX, + WNI_CFG_VHT_TXOP_PS_STADEF}, + {WNI_CFG_VHT_HTC_VHTC_CAP, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_VHT_HTC_VHTC_CAP_STAMIN, + WNI_CFG_VHT_HTC_VHTC_CAP_STAMAX, + WNI_CFG_VHT_HTC_VHTC_CAP_STADEF}, + {WNI_CFG_VHT_AMPDU_LEN_EXPONENT, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_VHT_AMPDU_LEN_EXPONENT_STAMIN, + WNI_CFG_VHT_AMPDU_LEN_EXPONENT_STAMAX, + WNI_CFG_VHT_AMPDU_LEN_EXPONENT_STADEF}, + {WNI_CFG_VHT_LINK_ADAPTATION_CAP, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_VHT_LINK_ADAPTATION_CAP_STAMIN, + WNI_CFG_VHT_LINK_ADAPTATION_CAP_STAMAX, + WNI_CFG_VHT_LINK_ADAPTATION_CAP_STADEF}, + {WNI_CFG_VHT_RX_ANT_PATTERN, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_VHT_RX_ANT_PATTERN_STAMIN, + WNI_CFG_VHT_RX_ANT_PATTERN_STAMAX, + WNI_CFG_VHT_RX_ANT_PATTERN_STADEF}, + {WNI_CFG_VHT_TX_ANT_PATTERN, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_VHT_TX_ANT_PATTERN_STAMIN, + WNI_CFG_VHT_TX_ANT_PATTERN_STAMAX, + WNI_CFG_VHT_TX_ANT_PATTERN_STADEF}, + {WNI_CFG_VHT_RX_MCS_MAP, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_VHT_RX_MCS_MAP_STAMIN, + WNI_CFG_VHT_RX_MCS_MAP_STAMAX, + WNI_CFG_VHT_RX_MCS_MAP_STADEF}, + {WNI_CFG_VHT_TX_MCS_MAP, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_VHT_TX_MCS_MAP_STAMIN, + WNI_CFG_VHT_TX_MCS_MAP_STAMAX, + WNI_CFG_VHT_TX_MCS_MAP_STADEF}, + {WNI_CFG_VHT_RX_HIGHEST_SUPPORTED_DATA_RATE, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_VHT_RX_HIGHEST_SUPPORTED_DATA_RATE_STAMIN, + WNI_CFG_VHT_RX_HIGHEST_SUPPORTED_DATA_RATE_STAMAX, + WNI_CFG_VHT_RX_HIGHEST_SUPPORTED_DATA_RATE_STADEF}, + {WNI_CFG_VHT_TX_HIGHEST_SUPPORTED_DATA_RATE, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_VHT_TX_HIGHEST_SUPPORTED_DATA_RATE_STAMIN, + WNI_CFG_VHT_TX_HIGHEST_SUPPORTED_DATA_RATE_STAMAX, + WNI_CFG_VHT_TX_HIGHEST_SUPPORTED_DATA_RATE_STADEF}, + {WNI_CFG_VHT_BASIC_MCS_SET, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_VHT_BASIC_MCS_SET_STAMIN, + WNI_CFG_VHT_BASIC_MCS_SET_STAMAX, + WNI_CFG_VHT_BASIC_MCS_SET_STADEF}, + {WNI_CFG_VHT_MU_MIMO_CAP_STA_COUNT, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_VHT_MU_MIMO_CAP_STA_COUNT_STAMIN, + WNI_CFG_VHT_MU_MIMO_CAP_STA_COUNT_STAMAX, + WNI_CFG_VHT_MU_MIMO_CAP_STA_COUNT_STADEF}, + {WNI_CFG_VHT_SS_UNDER_UTIL, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_VHT_SS_UNDER_UTIL_STAMIN, + WNI_CFG_VHT_SS_UNDER_UTIL_STAMAX, + WNI_CFG_VHT_SS_UNDER_UTIL_STADEF}, + {WNI_CFG_VHT_40MHZ_UTILIZATION, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_VHT_40MHZ_UTILIZATION_STAMIN, + WNI_CFG_VHT_40MHZ_UTILIZATION_STAMAX, + WNI_CFG_VHT_40MHZ_UTILIZATION_STADEF}, + {WNI_CFG_VHT_80MHZ_UTILIZATION, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_VHT_80MHZ_UTILIZATION_STAMIN, + WNI_CFG_VHT_80MHZ_UTILIZATION_STAMAX, + WNI_CFG_VHT_80MHZ_UTILIZATION_STADEF}, + {WNI_CFG_VHT_160MHZ_UTILIZATION, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_VHT_80MHZ_UTILIZATION_STADEF, + WNI_CFG_VHT_160MHZ_UTILIZATION_STAMAX, + WNI_CFG_VHT_160MHZ_UTILIZATION_STADEF}, + {WNI_CFG_MPDU_DENSITY, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_RESTART | CFG_CTL_NTF_LIM, + WNI_CFG_MPDU_DENSITY_STAMIN, + WNI_CFG_MPDU_DENSITY_STAMAX, + WNI_CFG_MPDU_DENSITY_STADEF}, + {WNI_CFG_MAX_RX_AMPDU_FACTOR, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_RESTART | CFG_CTL_NTF_LIM, + WNI_CFG_MAX_RX_AMPDU_FACTOR_STAMIN, + WNI_CFG_MAX_RX_AMPDU_FACTOR_STAMAX, + WNI_CFG_MAX_RX_AMPDU_FACTOR_STAMAX}, + {WNI_CFG_MAX_PS_POLL, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_MAX_PS_POLL_STAMIN, + WNI_CFG_MAX_PS_POLL_STAMAX, + WNI_CFG_MAX_PS_POLL_STADEF}, + {WNI_CFG_RSSI_FILTER_PERIOD, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_RSSI_FILTER_PERIOD_STAMIN, + WNI_CFG_RSSI_FILTER_PERIOD_STAMAX, + WNI_CFG_RSSI_FILTER_PERIOD_STADEF}, + {WNI_CFG_SCAN_IN_POWERSAVE, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_SCAN_IN_POWERSAVE_STAMIN, + WNI_CFG_SCAN_IN_POWERSAVE_STAMAX, + WNI_CFG_SCAN_IN_POWERSAVE_STADEF}, + {WNI_CFG_IGNORE_DTIM, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_IGNORE_DTIM_STAMIN, + WNI_CFG_IGNORE_DTIM_STAMAX, + WNI_CFG_IGNORE_DTIM_STADEF}, + {WNI_CFG_WOWLAN_UCAST_PATTERN_FILTER_ENABLE, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_WOWLAN_UCAST_PATTERN_FILTER_ENABLE_STAMIN, + WNI_CFG_WOWLAN_UCAST_PATTERN_FILTER_ENABLE_STAMAX, + WNI_CFG_WOWLAN_UCAST_PATTERN_FILTER_ENABLE_STADEF}, + {WNI_CFG_WOWLAN_CHANNEL_SWITCH_ENABLE, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_WOWLAN_CHANNEL_SWITCH_ENABLE_STAMIN, + WNI_CFG_WOWLAN_CHANNEL_SWITCH_ENABLE_STAMAX, + WNI_CFG_WOWLAN_CHANNEL_SWITCH_ENABLE_STADEF}, + {WNI_CFG_WOWLAN_DEAUTH_ENABLE, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_WOWLAN_DEAUTH_ENABLE_STAMIN, + WNI_CFG_WOWLAN_DEAUTH_ENABLE_STAMAX, + WNI_CFG_WOWLAN_DEAUTH_ENABLE_STADEF}, + {WNI_CFG_WOWLAN_DISASSOC_ENABLE, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_WOWLAN_DISASSOC_ENABLE_STAMIN, + WNI_CFG_WOWLAN_DISASSOC_ENABLE_STAMAX, + WNI_CFG_WOWLAN_DISASSOC_ENABLE_STADEF}, + {WNI_CFG_WOWLAN_MAX_MISSED_BEACON, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_WOWLAN_MAX_MISSED_BEACON_STAMIN, + WNI_CFG_WOWLAN_MAX_MISSED_BEACON_STAMAX, + WNI_CFG_WOWLAN_MAX_MISSED_BEACON_STADEF}, + {WNI_CFG_WOWLAN_MAX_SLEEP_PERIOD, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_WOWLAN_MAX_SLEEP_PERIOD_STAMIN, + WNI_CFG_WOWLAN_MAX_SLEEP_PERIOD_STAMAX, + WNI_CFG_WOWLAN_MAX_SLEEP_PERIOD_STADEF}, + {WNI_CFG_MAX_MEDIUM_TIME, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_HAL, + WNI_CFG_MAX_MEDIUM_TIME_STAMIN, + WNI_CFG_MAX_MEDIUM_TIME_STAMAX, + WNI_CFG_MAX_MEDIUM_TIME_STADEF}, + {WNI_CFG_IBSS_AUTO_BSSID, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_IBSS_AUTO_BSSID_STAMIN, + WNI_CFG_IBSS_AUTO_BSSID_STAMAX, + WNI_CFG_IBSS_AUTO_BSSID_STADEF}, + {WNI_CFG_PROBE_RSP_BCN_ADDNIE_FLAG, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_PROBE_RSP_BCN_ADDNIE_FLAG_STAMIN, + WNI_CFG_PROBE_RSP_BCN_ADDNIE_FLAG_STAMAX, + WNI_CFG_PROBE_RSP_BCN_ADDNIE_FLAG_STADEF}, + {WNI_CFG_WPS_ENABLE, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_WPS_ENABLE_STAMIN, + WNI_CFG_WPS_ENABLE_STAMAX, + WNI_CFG_WPS_ENABLE_STADEF}, + {WNI_CFG_WPS_STATE, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_WPS_STATE_STAMIN, + WNI_CFG_WPS_STATE_STAMAX, + WNI_CFG_WPS_STATE_STADEF}, + {WNI_CFG_WPS_VERSION, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_WPS_VERSION_STAMIN, + WNI_CFG_WPS_VERSION_STAMAX, + WNI_CFG_WPS_VERSION_STADEF}, + {WNI_CFG_WPS_CFG_METHOD, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_WPS_CFG_METHOD_STAMIN, + 4294967295u, + WNI_CFG_WPS_CFG_METHOD_STADEF}, + {WNI_CFG_WPS_UUID, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_NTF_LIM, + 0, 0, 0}, + {WNI_CFG_WPS_PRIMARY_DEVICE_CATEGORY, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_WPS_PRIMARY_DEVICE_CATEGORY_STAMIN, + WNI_CFG_WPS_PRIMARY_DEVICE_CATEGORY_STAMAX, + WNI_CFG_WPS_PRIMARY_DEVICE_CATEGORY_STADEF}, + {WNI_CFG_WPS_PIMARY_DEVICE_OUI, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_WPS_PIMARY_DEVICE_OUI_STAMIN, + 4294967295u, + WNI_CFG_WPS_PIMARY_DEVICE_OUI_STADEF}, + {WNI_CFG_WPS_DEVICE_SUB_CATEGORY, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_WPS_DEVICE_SUB_CATEGORY_STAMIN, + WNI_CFG_WPS_DEVICE_SUB_CATEGORY_STAMAX, + WNI_CFG_WPS_DEVICE_SUB_CATEGORY_STADEF}, + {WNI_CFG_WPS_DEVICE_PASSWORD_ID, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_WPS_DEVICE_PASSWORD_ID_STAMIN, + 4294967295u, + WNI_CFG_WPS_DEVICE_PASSWORD_ID_STADEF}, + {WNI_CFG_LOW_GAIN_OVERRIDE, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_HAL, + WNI_CFG_LOW_GAIN_OVERRIDE_STAMIN, + WNI_CFG_LOW_GAIN_OVERRIDE_STAMAX, + WNI_CFG_LOW_GAIN_OVERRIDE_STADEF}, + {WNI_CFG_SINGLE_TID_RC, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_SINGLE_TID_RC_STAMIN, + WNI_CFG_SINGLE_TID_RC_STAMAX, + WNI_CFG_SINGLE_TID_RC_STADEF}, + {WNI_CFG_MCAST_BCAST_FILTER_SETTING, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_HAL, + WNI_CFG_MCAST_BCAST_FILTER_SETTING_STAMIN, + WNI_CFG_MCAST_BCAST_FILTER_SETTING_STAMAX, + WNI_CFG_MCAST_BCAST_FILTER_SETTING_STADEF}, + {WNI_CFG_DYNAMIC_PS_POLL_VALUE, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_HAL, + WNI_CFG_DYNAMIC_PS_POLL_VALUE_STAMIN, + WNI_CFG_DYNAMIC_PS_POLL_VALUE_STAMAX, + WNI_CFG_DYNAMIC_PS_POLL_VALUE_STADEF}, + {WNI_CFG_PS_NULLDATA_AP_RESP_TIMEOUT, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_HAL, + WNI_CFG_PS_NULLDATA_AP_RESP_TIMEOUT_STAMIN, + WNI_CFG_PS_NULLDATA_AP_RESP_TIMEOUT_STAMAX, + WNI_CFG_PS_NULLDATA_AP_RESP_TIMEOUT_STADEF}, + {WNI_CFG_TELE_BCN_WAKEUP_EN, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_HAL, + WNI_CFG_TELE_BCN_WAKEUP_EN_STAMIN, + WNI_CFG_TELE_BCN_WAKEUP_EN_STAMAX, + WNI_CFG_TELE_BCN_WAKEUP_EN_STADEF}, + {WNI_CFG_TELE_BCN_TRANS_LI, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_HAL, + WNI_CFG_TELE_BCN_TRANS_LI_STAMIN, + WNI_CFG_TELE_BCN_TRANS_LI_STAMAX, + WNI_CFG_TELE_BCN_TRANS_LI_STADEF}, + {WNI_CFG_TELE_BCN_TRANS_LI_IDLE_BCNS, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_HAL, + WNI_CFG_TELE_BCN_TRANS_LI_IDLE_BCNS_STAMIN, + WNI_CFG_TELE_BCN_TRANS_LI_IDLE_BCNS_STAMAX, + WNI_CFG_TELE_BCN_TRANS_LI_IDLE_BCNS_STADEF}, + {WNI_CFG_TELE_BCN_MAX_LI, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_HAL, + WNI_CFG_TELE_BCN_MAX_LI_STAMIN, + WNI_CFG_TELE_BCN_MAX_LI_STAMAX, + WNI_CFG_TELE_BCN_MAX_LI_STADEF}, + {WNI_CFG_TELE_BCN_MAX_LI_IDLE_BCNS, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_HAL, + WNI_CFG_TELE_BCN_MAX_LI_IDLE_BCNS_STAMIN, + WNI_CFG_TELE_BCN_MAX_LI_IDLE_BCNS_STAMAX, + WNI_CFG_TELE_BCN_MAX_LI_IDLE_BCNS_STADEF}, + {WNI_CFG_INFRA_STA_KEEP_ALIVE_PERIOD, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_HAL, + WNI_CFG_INFRA_STA_KEEP_ALIVE_PERIOD_STAMIN, + WNI_CFG_INFRA_STA_KEEP_ALIVE_PERIOD_STAMAX, + WNI_CFG_INFRA_STA_KEEP_ALIVE_PERIOD_STADEF}, + {WNI_CFG_ASSOC_STA_LIMIT, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_ASSOC_STA_LIMIT_STAMIN, + WNI_CFG_ASSOC_STA_LIMIT_STAMAX, + WNI_CFG_ASSOC_STA_LIMIT_STADEF}, + {WNI_CFG_AP_DATA_AVAIL_POLL_PERIOD, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_AP_DATA_AVAIL_POLL_PERIOD_STAMIN, + WNI_CFG_AP_DATA_AVAIL_POLL_PERIOD_STAMAX, + WNI_CFG_AP_DATA_AVAIL_POLL_PERIOD_STADEF}, + {WNI_CFG_ENABLE_LTE_COEX, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_ENABLE_LTE_COEX_STAMIN, + WNI_CFG_ENABLE_LTE_COEX_STAMAX, + WNI_CFG_ENABLE_LTE_COEX_STADEF}, + {WNI_CFG_AP_KEEP_ALIVE_TIMEOUT, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_HAL, + WNI_CFG_AP_KEEP_ALIVE_TIMEOUT_STAMIN, + WNI_CFG_AP_KEEP_ALIVE_TIMEOUT_STAMAX, + WNI_CFG_AP_KEEP_ALIVE_TIMEOUT_STADEF}, + {WNI_CFG_GO_KEEP_ALIVE_TIMEOUT, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_HAL, + WNI_CFG_GO_KEEP_ALIVE_TIMEOUT_STAMIN, + WNI_CFG_GO_KEEP_ALIVE_TIMEOUT_STAMAX, + WNI_CFG_GO_KEEP_ALIVE_TIMEOUT_STADEF}, + {WNI_CFG_ENABLE_MC_ADDR_LIST, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_HAL, + WNI_CFG_ENABLE_MC_ADDR_LIST_STAMIN, + WNI_CFG_ENABLE_MC_ADDR_LIST_STAMAX, + WNI_CFG_ENABLE_MC_ADDR_LIST_STADEF}, + {WNI_CFG_ENABLE_LPWR_IMG_TRANSITION, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_ENABLE_LPWR_IMG_TRANSITION_STAMIN, + WNI_CFG_ENABLE_LPWR_IMG_TRANSITION_STAMAX, + WNI_CFG_ENABLE_LPWR_IMG_TRANSITION_STADEF}, + {WNI_CFG_ENABLE_MCC_ADAPTIVE_SCHED, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_ENABLE_MCC_ADAPTIVE_SCHED_STAMIN, + WNI_CFG_ENABLE_MCC_ADAPTIVE_SCHED_STAMAX, + WNI_CFG_ENABLE_MCC_ADAPTIVE_SCHED_STADEF}, + {WNI_CFG_DISABLE_LDPC_WITH_TXBF_AP, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_DISABLE_LDPC_WITH_TXBF_AP_STAMIN, + WNI_CFG_DISABLE_LDPC_WITH_TXBF_AP_STAMAX, + WNI_CFG_DISABLE_LDPC_WITH_TXBF_AP_STADEF}, + {WNI_CFG_AP_LINK_MONITOR_TIMEOUT, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_HAL, + WNI_CFG_AP_LINK_MONITOR_TIMEOUT_STAMIN, + WNI_CFG_AP_LINK_MONITOR_TIMEOUT_STAMAX, + WNI_CFG_AP_LINK_MONITOR_TIMEOUT_STADEF}, + {WNI_CFG_TDLS_QOS_WMM_UAPSD_MASK, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_TDLS_QOS_WMM_UAPSD_MASK_STAMIN, + WNI_CFG_TDLS_QOS_WMM_UAPSD_MASK_STAMAX, + WNI_CFG_TDLS_QOS_WMM_UAPSD_MASK_STADEF}, + {WNI_CFG_TDLS_BUF_STA_ENABLED, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_TDLS_BUF_STA_ENABLED_STAMIN, + WNI_CFG_TDLS_BUF_STA_ENABLED_STAMAX, + WNI_CFG_TDLS_BUF_STA_ENABLED_STADEF}, + {WNI_CFG_TDLS_PUAPSD_INACT_TIME, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_TDLS_PUAPSD_INACT_TIME_STAMIN, + WNI_CFG_TDLS_PUAPSD_INACT_TIME_STAMAX, + WNI_CFG_TDLS_PUAPSD_INACT_TIME_STADEF}, + {WNI_CFG_TDLS_RX_FRAME_THRESHOLD, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_TDLS_RX_FRAME_THRESHOLD_STAMIN, + WNI_CFG_TDLS_RX_FRAME_THRESHOLD_STAMAX, + WNI_CFG_TDLS_RX_FRAME_THRESHOLD_STADEF}, + {WNI_CFG_PMF_SA_QUERY_MAX_RETRIES, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_RESTART, + WNI_CFG_PMF_SA_QUERY_MAX_RETRIES_STAMIN, + WNI_CFG_PMF_SA_QUERY_MAX_RETRIES_STAMAX, + WNI_CFG_PMF_SA_QUERY_MAX_RETRIES_STADEF}, + {WNI_CFG_PMF_SA_QUERY_RETRY_INTERVAL, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_RESTART, + WNI_CFG_PMF_SA_QUERY_RETRY_INTERVAL_STAMIN, + WNI_CFG_PMF_SA_QUERY_RETRY_INTERVAL_STAMAX, + WNI_CFG_PMF_SA_QUERY_RETRY_INTERVAL_STADEF}, + {WNI_CFG_ENABLE_ADAPT_RX_DRAIN, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_HAL, + WNI_CFG_ENABLE_ADAPT_RX_DRAIN_STAMIN, + WNI_CFG_ENABLE_ADAPT_RX_DRAIN_STAMAX, + WNI_CFG_ENABLE_ADAPT_RX_DRAIN_STADEF}, + {WNI_CFG_ANTENNA_DIVESITY, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_HAL, + WNI_CFG_ANTENNA_DIVESITY_STAMIN, + WNI_CFG_ANTENNA_DIVESITY_STAMAX, + WNI_CFG_ANTENNA_DIVESITY_STADEF}, + {WNI_CFG_GO_LINK_MONITOR_TIMEOUT, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_HAL, + WNI_CFG_GO_LINK_MONITOR_TIMEOUT_STAMIN, + WNI_CFG_GO_LINK_MONITOR_TIMEOUT_STAMAX, + WNI_CFG_GO_LINK_MONITOR_TIMEOUT_STADEF}, + {WNI_CFG_RMC_ACTION_PERIOD_FREQUENCY, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_HAL, + WNI_CFG_RMC_ACTION_PERIOD_FREQUENCY_STAMIN, + WNI_CFG_RMC_ACTION_PERIOD_FREQUENCY_STAMAX, + WNI_CFG_RMC_ACTION_PERIOD_FREQUENCY_STADEF}, + {WNI_CFG_CURRENT_RSSI, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_CURRENT_RSSI_STAMIN, + WNI_CFG_CURRENT_RSSI_STAMAX, + WNI_CFG_CURRENT_RSSI_STADEF}, + {WNI_CFG_RTT3_ENABLE, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_RTT3_ENABLE_STAMIN, + WNI_CFG_RTT3_ENABLE_STAMAX, + WNI_CFG_RTT3_ENABLE_STADEF}, + {WNI_CFG_DEBUG_P2P_REMAIN_ON_CHANNEL, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_DEBUG_P2P_REMAIN_ON_CHANNEL_STAMIN, + WNI_CFG_DEBUG_P2P_REMAIN_ON_CHANNEL_STAMAX, + WNI_CFG_DEBUG_P2P_REMAIN_ON_CHANNEL_STADEF}, + {WNI_CFG_TDLS_OFF_CHANNEL_ENABLED, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_TDLS_OFF_CHANNEL_ENABLED_STAMIN, + WNI_CFG_TDLS_OFF_CHANNEL_ENABLED_STAMAX, + WNI_CFG_TDLS_OFF_CHANNEL_ENABLED_STADEF}, + {WNI_CFG_IBSS_ATIM_WIN_SIZE, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_IBSS_ATIM_WIN_SIZE_STAMIN, + WNI_CFG_IBSS_ATIM_WIN_SIZE_STAMAX, + WNI_CFG_IBSS_ATIM_WIN_SIZE_STADEF}, + {WNI_CFG_DFS_MASTER_ENABLED, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_DFS_MASTER_ENABLED_STAMIN, + WNI_CFG_DFS_MASTER_ENABLED_STAMAX, + WNI_CFG_DFS_MASTER_ENABLED_STADEF}, + {WNI_CFG_VHT_ENABLE_TXBF_20MHZ, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_VHT_ENABLE_TXBF_20MHZ_STAMIN, + WNI_CFG_VHT_ENABLE_TXBF_20MHZ_STAMAX, + WNI_CFG_VHT_ENABLE_TXBF_20MHZ_STADEF}, + {WNI_CFG_TDLS_WMM_MODE_ENABLED, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_TDLS_WMM_MODE_ENABLED_STAMIN, + WNI_CFG_TDLS_WMM_MODE_ENABLED_STAMAX, + WNI_CFG_TDLS_WMM_MODE_ENABLED_STADEF}, + {WNI_CFG_OBSS_HT40_SCAN_PASSIVE_DWELL_TIME, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_OBSS_HT40_SCAN_PASSIVE_DWELL_TIME_STAMIN, + WNI_CFG_OBSS_HT40_SCAN_PASSIVE_DWELL_TIME_STAMAX, + WNI_CFG_OBSS_HT40_SCAN_PASSIVE_DWELL_TIME_STADEF}, + {WNI_CFG_OBSS_HT40_SCAN_ACTIVE_DWELL_TIME, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_OBSS_HT40_SCAN_ACTIVE_DWELL_TIME_STAMIN, + WNI_CFG_OBSS_HT40_SCAN_ACTIVE_DWELL_TIME_STAMAX, + WNI_CFG_OBSS_HT40_SCAN_ACTIVE_DWELL_TIME_STADEF}, + {WNI_CFG_OBSS_HT40_SCAN_WIDTH_TRIGGER_INTERVAL, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_OBSS_HT40_SCAN_WIDTH_TRIGGER_INTERVAL_STAMIN, + WNI_CFG_OBSS_HT40_SCAN_WIDTH_TRIGGER_INTERVAL_STAMAX, + WNI_CFG_OBSS_HT40_SCAN_WIDTH_TRIGGER_INTERVAL_STADEF}, + {WNI_CFG_OBSS_HT40_SCAN_PASSIVE_TOTAL_PER_CHANNEL, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_OBSS_HT40_SCAN_PASSIVE_TOTAL_PER_CHANNEL_STAMIN, + WNI_CFG_OBSS_HT40_SCAN_PASSIVE_TOTAL_PER_CHANNEL_STAMAX, + WNI_CFG_OBSS_HT40_SCAN_PASSIVE_TOTAL_PER_CHANNEL_STADEF}, + {WNI_CFG_OBSS_HT40_SCAN_ACTIVE_TOTAL_PER_CHANNEL, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_OBSS_HT40_SCAN_ACTIVE_TOTAL_PER_CHANNEL_STAMIN, + WNI_CFG_OBSS_HT40_SCAN_ACTIVE_TOTAL_PER_CHANNEL_STAMAX, + WNI_CFG_OBSS_HT40_SCAN_ACTIVE_TOTAL_PER_CHANNEL_STADEF}, + {WNI_CFG_OBSS_HT40_WIDTH_CH_TRANSITION_DELAY, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_OBSS_HT40_WIDTH_CH_TRANSITION_DELAY_STAMIN, + WNI_CFG_OBSS_HT40_WIDTH_CH_TRANSITION_DELAY_STAMAX, + WNI_CFG_OBSS_HT40_WIDTH_CH_TRANSITION_DELAY_STADEF}, + {WNI_CFG_OBSS_HT40_SCAN_ACTIVITY_THRESHOLD, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_LIM, + WNI_CFG_OBSS_HT40_SCAN_ACTIVITY_THRESHOLD_STAMIN, + WNI_CFG_OBSS_HT40_SCAN_ACTIVITY_THRESHOLD_STAMAX, + WNI_CFG_OBSS_HT40_SCAN_ACTIVITY_THRESHOLD_STADEF}, + {WNI_CFG_TGT_GTX_USR_CFG, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_TGT_GTX_USR_CFG_STAMIN, + WNI_CFG_TGT_GTX_USR_CFG_STAMAX, + WNI_CFG_TGT_GTX_USR_CFG_STADEF}, + {WNI_CFG_MAX_HT_MCS_TX_DATA, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_MAX_HT_MCS_TX_DATA_STAMIN, + WNI_CFG_MAX_HT_MCS_TX_DATA_STAMAX, + WNI_CFG_MAX_HT_MCS_TX_DATA_STADEF}, + {WNI_CFG_DISABLE_ABG_RATE_FOR_TX_DATA, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_DISABLE_ABG_RATE_FOR_TX_DATA_STAMIN, + WNI_CFG_DISABLE_ABG_RATE_FOR_TX_DATA_STAMAX, + WNI_CFG_DISABLE_ABG_RATE_FOR_TX_DATA_STADEF}, + {WNI_CFG_RATE_FOR_TX_MGMT, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT, + WNI_CFG_RATE_FOR_TX_MGMT_STAMIN, + WNI_CFG_RATE_FOR_TX_MGMT_STAMAX, + WNI_CFG_RATE_FOR_TX_MGMT_STADEF}, + {WNI_CFG_PS_WOW_DATA_INACTIVITY_TIMEOUT, + CFG_CTL_VALID | CFG_CTL_RE | CFG_CTL_WE | CFG_CTL_INT | + CFG_CTL_NTF_HAL, + WNI_CFG_PS_WOW_DATA_INACTIVITY_TIMEOUT_STAMIN, + WNI_CFG_PS_WOW_DATA_INACTIVITY_TIMEOUT_STAMAX, + WNI_CFG_PS_WOW_DATA_INACTIVITY_TIMEOUT_STADEF} +}; + + +cfgstatic_string cfg_static_string[CFG_MAX_STATIC_STRING] = { + + {WNI_CFG_STA_ID, + WNI_CFG_STA_ID_LEN, + 6, + {0x22, 0x22, 0x44, 0x44, 0x33, 0x33} }, + {WNI_CFG_SSID, + WNI_CFG_SSID_LEN, + 10, + {1, 2, 3, 4, 5, 6, 7, 8, 9, 0} }, + {WNI_CFG_WEP_DEFAULT_KEY_1, + WNI_CFG_WEP_DEFAULT_KEY_1_LEN, + 0, + {0} }, + {WNI_CFG_WEP_DEFAULT_KEY_2, + WNI_CFG_WEP_DEFAULT_KEY_2_LEN, + 0, + {0} }, + {WNI_CFG_WEP_DEFAULT_KEY_3, + WNI_CFG_WEP_DEFAULT_KEY_3_LEN, + 0, + {0} }, + {WNI_CFG_WEP_DEFAULT_KEY_4, + WNI_CFG_WEP_DEFAULT_KEY_4_LEN, + 0, + {0} }, + {WNI_CFG_SUPPORTED_RATES_11B, + WNI_CFG_SUPPORTED_RATES_11B_LEN, + 4, + {2, 4, 11, 22} }, + {WNI_CFG_SUPPORTED_RATES_11A, + WNI_CFG_SUPPORTED_RATES_11A_LEN, + 8, + {12, 18, 24, 36, 48, 72, 96, 108} }, + {WNI_CFG_OPERATIONAL_RATE_SET, + WNI_CFG_OPERATIONAL_RATE_SET_LEN, + 0, + {0} }, + {WNI_CFG_EXTENDED_OPERATIONAL_RATE_SET, + WNI_CFG_EXTENDED_OPERATIONAL_RATE_SET_LEN, + 0, + {0} }, + {WNI_CFG_PROPRIETARY_OPERATIONAL_RATE_SET, + WNI_CFG_PROPRIETARY_OPERATIONAL_RATE_SET_LEN, + 4, + {1, 3, 5, 7} }, + {WNI_CFG_VALID_CHANNEL_LIST, + WNI_CFG_VALID_CHANNEL_LIST_LEN, + 55, + {36, 40, 44, 48, 52, 56, 60, 64, 1, 6, 11, 34, 38, 42, 46, 2, 3, 4, + 5, 7, 8, 9, 10, 12, 13, 14, 100, 104, 108, 112, 116, 120, 124, 128, + 132, 136, 140, 149, 151, 153, 155, 157, 159, 161, 50, 54, 58, 62, 240, + 242, 244, 246, 248, 250, 252} }, + + {WNI_CFG_MANUFACTURER_NAME, + WNI_CFG_MANUFACTURER_NAME_LEN, + 8, + {0x51, 0x75, 0x61, 0x6c, 0x63, 0x6f, 0x6d, 0x6d} }, + {WNI_CFG_MODEL_NUMBER, + WNI_CFG_MODEL_NUMBER_LEN, + 6, + {0x4d, 0x4e, 0x31, 0x32, 0x33, 0x34} }, + {WNI_CFG_MODEL_NAME, + WNI_CFG_MODEL_NAME_LEN, + 7, + {0x57, 0x46, 0x52, 0x34, 0x30, 0x33, 0x31} }, + {WNI_CFG_MANUFACTURER_PRODUCT_NAME, + WNI_CFG_MANUFACTURER_PRODUCT_NAME_LEN, + 6, + {0x31, 0x31, 0x6e, 0x2d, 0x41, 0x50} }, + {WNI_CFG_MANUFACTURER_PRODUCT_VERSION, + WNI_CFG_MANUFACTURER_PRODUCT_VERSION_LEN, + 6, + {0x53, 0x4e, 0x31, 0x32, 0x33, 0x34} }, + {WNI_CFG_MAX_TX_POWER_2_4, + WNI_CFG_MAX_TX_POWER_2_4_LEN, + 3, + {0x1, 0xe, 0x14} }, + {WNI_CFG_MAX_TX_POWER_5, + WNI_CFG_MAX_TX_POWER_5_LEN, + 3, + {0x24, 0x7e, 0x14} }, + {WNI_CFG_COUNTRY_CODE, + WNI_CFG_COUNTRY_CODE_LEN, + 0, + {0} }, + {WNI_CFG_EDCA_ANI_ACBK_LOCAL, + WNI_CFG_EDCA_ANI_ACBK_LOCAL_LEN, + 17, + {0x0, 0x7, 0x0, 0xf, 0x3, 0xff, 0x0, 0x0, 0x1f, 0x3, 0xff, 0x0, 0x0, + 0xf, 0x3, 0xff, 0x0} }, + {WNI_CFG_EDCA_ANI_ACBE_LOCAL, + WNI_CFG_EDCA_ANI_ACBE_LOCAL_LEN, + 17, + {0x0, 0x2, 0x0, 0xf, 0x3, 0xff, 0x64, 0x0, 0x1f, 0x3, 0xff, 0x64, 0x0, + 0xf, 0x3, 0xff, 0x64} }, + {WNI_CFG_EDCA_ANI_ACVI_LOCAL, + WNI_CFG_EDCA_ANI_ACVI_LOCAL_LEN, + 17, + {0x0, 0x2, 0x0, 0x7, 0x0, 0xf, 0xc8, 0x0, 0xf, 0x0, 0x1f, 0xbc, 0x0, + 0x7, 0x0, 0xf, 0xc8} }, + {WNI_CFG_EDCA_ANI_ACVO_LOCAL, + WNI_CFG_EDCA_ANI_ACVO_LOCAL_LEN, + 17, + {0x0, 0x2, 0x0, 0x3, 0x0, 0x7, 0x64, 0x0, 0x7, 0x0, 0xf, 0x66, 0x0, + 0x3, 0x0, 0x7, 0x64} }, + {WNI_CFG_EDCA_ANI_ACBK, + WNI_CFG_EDCA_ANI_ACBK_LEN, + 17, + {0x0, 0x7, 0x0, 0xf, 0x3, 0xff, 0x0, 0x0, 0x1f, 0x3, 0xff, 0x0, 0x0, + 0xf, 0x3, 0xff, 0x0} }, + {WNI_CFG_EDCA_ANI_ACBE, + WNI_CFG_EDCA_ANI_ACBE_LEN, + 17, + {0x0, 0x2, 0x0, 0xf, 0x3, 0xff, 0x64, 0x0, 0x1f, 0x3, 0xff, 0x64, 0x0, + 0xf, 0x3, 0xff, 0x64} }, + {WNI_CFG_EDCA_ANI_ACVI, + WNI_CFG_EDCA_ANI_ACVI_LEN, + 17, {0x0, 0x2, 0x0, 0x7, 0x0, 0xf, 0xc8, 0x0, 0xf, 0x0, 0x1f, + 0xbc, 0x0, 0x7, 0x0, 0xf, 0xc8} }, + {WNI_CFG_EDCA_ANI_ACVO, + WNI_CFG_EDCA_ANI_ACVO_LEN, + 17, + {0x0, 0x2, 0x0, 0x3, 0x0, 0x7, 0x64, 0x0, 0x7, 0x0, 0xf, 0x66, 0x0, 0x3, + 0x0, 0x7, 0x64} }, + {WNI_CFG_EDCA_WME_ACBK_LOCAL, + WNI_CFG_EDCA_WME_ACBK_LOCAL_LEN, + 17, {0x0, 0x7, 0x0, 0xf, 0x3, 0xff, 0x0, 0x0, 0x1f, 0x3, 0xff, + 0x0, 0x0, 0xf, 0x3, 0xff, 0x0} }, + {WNI_CFG_EDCA_WME_ACBE_LOCAL, + WNI_CFG_EDCA_WME_ACBE_LOCAL_LEN, + 17, {0x0, 0x3, 0x0, 0xf, 0x0, 0x3f, 0x0, 0x0, 0x1f, 0x3, 0xff, + 0x0, 0x0, 0xf, 0x0, 0x3f, 0x0} }, + {WNI_CFG_EDCA_WME_ACVI_LOCAL, + WNI_CFG_EDCA_WME_ACVI_LOCAL_LEN, + 17, + {0x0, 0x1, 0x0, 0x7, 0x0, 0xf, 0x5e, 0x0, 0x7, 0x0, 0xf, 0xbc, 0x0, 0x7, + 0x0, 0xf, 0x5e} }, + {WNI_CFG_EDCA_WME_ACVO_LOCAL, + WNI_CFG_EDCA_WME_ACVO_LOCAL_LEN, + 17, + {0x0, 0x1, 0x0, 0x3, 0x0, 0x7, 0x2f, 0x0, 0x3, 0x0, 0x7, 0x66, 0x0, 0x3, + 0x0, 0x7, 0x2f} }, + {WNI_CFG_EDCA_WME_ACBK, + WNI_CFG_EDCA_WME_ACBK_LEN, + 17, + {0x0, 0x7, 0x0, 0xf, 0x3, 0xff, 0x0, 0x0, 0xf, 0x3, 0xff, 0x0, 0x0, 0xf, + 0x3, 0xff, 0x0} }, + {WNI_CFG_EDCA_WME_ACBE, + WNI_CFG_EDCA_WME_ACBE_LEN, + 17, + {0x0, 0x3, 0x0, 0xf, 0x3, 0xff, 0x0, 0x0, 0xf, 0x3, 0xff, 0x0, 0x0, 0xf, + 0x3, 0xff, 0x0} }, + {WNI_CFG_EDCA_WME_ACVI, + WNI_CFG_EDCA_WME_ACVI_LEN, + 17, + {0x0, 0x2, 0x0, 0x7, 0x0, 0xf, 0x5e, 0x0, 0x7, 0x0, 0xf, 0xbc, 0x0, 0x7, + 0x0, 0xf, 0x5e} }, + {WNI_CFG_EDCA_WME_ACVO, + WNI_CFG_EDCA_WME_ACVO_LEN, + 17, + {0x0, 0x2, 0x0, 0x3, 0x0, 0x7, 0x2f, 0x0, 0x3, 0x0, 0x7, 0x66, 0x0, 0x3, + 0x0, 0x7, 0x2f} }, + {WNI_CFG_SCAN_CONTROL_LIST, + WNI_CFG_SCAN_CONTROL_LIST_LEN, + 114, + {0x1, 0x1, 0x2, 0x1, 0x3, 0x1, 0x4, 0x1, 0x5, 0x1, 0x6, 0x1, 0x7, 0x1, + 0x8, 0x1, 0x9, 0x1, 0xa, 0x1, 0xb, 0x1, 0xc, 0x1, 0xd, 0x1, 0xe, 0x1, + 0x22, 0x1, 0x24, 0x1, 0x26, 0x1, 0x28, 0x1, 0x2a, 0x1, 0x2c, 0x1, 0x2e, + 0x1, 0x30, 0x1, 0x32, 0x1, 0x34, 0x0, 0x36, 0x0, 0x38, 0x0, 0x3a, 0x0, + 0x3c, 0x0, 0x3e, 0x0, 0x40, 0x0, 0x64, 0x0, 0x68, 0x0, 0x6c, 0x0, 0x70, + 0x0, 0x74, 0x0, 0x78, 0x0, 0x7c, 0x0, 0x80, 0x0, 0x84, 0x0, 0x88, 0x0, + 0x8c, 0x0, 0x90, 0x0, 0x95, 0x1, 0x97, 0x1, 0x99, 0x1, 0x9b, 0x1, 0x9d, + 0x1, 0x9f, 0x1, 0xa1, 0x1, 0xa5, 0x1, 0xf0, 0x1, 0xf2, 0x1, 0xf4, 0x1, + 0xf6, 0x1, 0xf8, 0x1, 0xfa, 0x1, 0xfc, 0x1} }, + {WNI_CFG_SUPPORTED_MCS_SET, + WNI_CFG_SUPPORTED_MCS_SET_LEN, + 16, + {0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0} }, + {WNI_CFG_BASIC_MCS_SET, + WNI_CFG_BASIC_MCS_SET_LEN, + 16, + {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0} }, + {WNI_CFG_CURRENT_MCS_SET, + WNI_CFG_CURRENT_MCS_SET_LEN, + 16, + {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0} }, + {WNI_CFG_WPS_UUID, + WNI_CFG_WPS_UUID_LEN, + 6, + {0xa, 0xb, 0xc, 0xd, 0xe, 0xf} } +}; + +/*--------------------------------------------------------------------*/ +/* Static function prototypes */ +/*--------------------------------------------------------------------*/ +static void proc_dnld_rsp(tpAniSirGlobal, uint16_t, uint32_t *); +static void proc_get_req(tpAniSirGlobal, uint16_t, uint32_t *); +static void proc_set_req(tpAniSirGlobal, uint16_t, uint32_t *); +static void proc_set_req_no_rsp(tpAniSirGlobal, uint16_t, uint32_t *); + +static uint8_t check_param(tpAniSirGlobal, uint16_t, uint32_t, uint32_t, + uint32_t *); +static void get_str_value(uint8_t *, uint8_t *, uint32_t); + +/*--------------------------------------------------------------------*/ +/* Module global variables */ +/*--------------------------------------------------------------------*/ + +/* CFG function table */ +void (*g_cfg_func[])(tpAniSirGlobal, uint16_t, uint32_t *) = { + proc_dnld_rsp, proc_get_req, proc_set_req, proc_set_req_no_rsp +}; + +/**--------------------------------------------------------------------- + * cfg_process_mb_msg() + * + ***FUNCTION: + * CFG mailbox message processing function. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * None. + * + ***NOTE: + * + * @param pMsg Message pointer + * + * @return None. + * + */ +void cfg_process_mb_msg(tpAniSirGlobal pMac, tSirMbMsg *pMsg) +{ + uint16_t index; + uint16_t len; + uint32_t *pParam; + + /* Use type[7:0] as index to function table */ + index = CFG_GET_FUNC_INDX(pMsg->type); + + if (index >= QDF_ARRAY_SIZE(g_cfg_func)) { + qdf_mem_free(pMsg); + return; + } + len = pMsg->msgLen - WNI_CFG_MB_HDR_LEN; + pParam = ((uint32_t *) pMsg) + 1; + + /* Call processing function */ + g_cfg_func[index] (pMac, len, pParam); + + /* Free up buffer */ + qdf_mem_free(pMsg); + +} /*** end cfg_process_mb_msg() ***/ + +/**--------------------------------------------------------------------- + * proc_dnld_rsp() + * + * FUNCTION: + * This function processes CFG_DNLD_RSP message from host. + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param length: message length + * @param pParam: parameter list pointer + * + * @return None + * + */ +static void proc_dnld_rsp(tpAniSirGlobal pMac, uint16_t length, uint32_t *pParam) +{ + int32_t i; + + uint32_t expLen, retVal, bufStart, bufEnd; + uint32_t *pSrc, *pDst, *pDstEnd; + uint32_t strSize, j; + uint8_t pStr[CFG_MAX_STR_LEN]; + tpCfgBinHdr pHdr; + uint32_t logLevel; + tSirMsgQ mmhMsg; + + /* First Dword must contain the AP or STA magic dword */ + PELOGW(cfg_log(pMac, LOGW, FL("CFG size %d bytes MAGIC dword is 0x%x"), + length, sir_read_u32_n((uint8_t *) pParam)); + ) + /* if the string is not correct, return failure */ + if (*pParam == CFG_STA_MAGIC_DWORD) { + } + + else { + PELOGE(cfg_log + (pMac, LOGE, FL("Invalid magic dword 0x%x"), + sir_read_u32_n((uint8_t *) pParam)); + ) + retVal = WNI_CFG_INVALID_LEN; + goto end; + } + + pParam++; + length -= 4; + + /* Parse the Cfg header */ + pHdr = (tpCfgBinHdr) pParam; + pParam += (sizeof(tCfgBinHdr) >> 2); + PELOGW(cfg_log + (pMac, LOGW, + FL("CFG hdr totParams %d intParams %d strBufSize %d/%d"), + pHdr->controlSize, pHdr->iBufSize, pHdr->sBufSize, + pMac->cfg.gCfgMaxSBufSize); + ) + + expLen = + ((CFG_PARAM_MAX_NUM + 3 * pMac->cfg.gCfgMaxIBufSize) << 2) + + pHdr->sBufSize + sizeof(tCfgBinHdr); + + if (length != expLen) { + PELOGE(cfg_log + (pMac, LOGE, + FL(" DNLD_RSP invalid length %d (exp %d)"), length, + expLen); + ) + retVal = WNI_CFG_INVALID_LEN; + goto end; + } + + if (pHdr->controlSize != CFG_PARAM_MAX_NUM) { + PELOGE(cfg_log + (pMac, LOGE, FL(" Total parameter count mismatch")); + ) + retVal = WNI_CFG_INVALID_LEN; + goto end; + } + + if (pHdr->iBufSize != pMac->cfg.gCfgMaxIBufSize) { + PELOGE(cfg_log + (pMac, LOGE, + FL(" Integer parameter count mismatch")); + ) + retVal = WNI_CFG_INVALID_LEN; + goto end; + } + /* Copy control array */ + pDst = (uint32_t *) pMac->cfg.gCfgEntry; + pDstEnd = pDst + CFG_PARAM_MAX_NUM; + pSrc = pParam; + while (pDst < pDstEnd) { + *pDst++ = *pSrc++; + } + /* Copy default values */ + pDst = pMac->cfg.gCfgIBuf; + pDstEnd = pDst + pMac->cfg.gCfgMaxIBufSize; + while (pDst < pDstEnd) { + *pDst++ = *pSrc++; + } + + /* Copy min values */ + pDst = pMac->cfg.gCfgIBufMin; + pDstEnd = pDst + pMac->cfg.gCfgMaxIBufSize; + while (pDst < pDstEnd) { + *pDst++ = *pSrc++; + } + + /* Copy max values */ + pDst = pMac->cfg.gCfgIBufMax; + pDstEnd = pDst + pMac->cfg.gCfgMaxIBufSize; + while (pDst < pDstEnd) { + *pDst++ = *pSrc++; + } + + for (i = 0; i < pMac->cfg.gCfgMaxIBufSize; i++) + if (pMac->cfg.gCfgIBuf[i] < pMac->cfg.gCfgIBufMin[i] || + pMac->cfg.gCfgIBuf[i] > pMac->cfg.gCfgIBufMax[i]) { + PELOGE(cfg_log + (pMac, LOGE, + FL("cfg id %d Invalid def value %d " + "min %d max %d"), i, pMac->cfg.gCfgIBuf[i], + pMac->cfg.gCfgIBufMin[i], + pMac->cfg.gCfgIBufMax[i]); + ) + } + /* Calculate max string buffer lengths for all string parameters */ + bufEnd = pMac->cfg.gCfgMaxSBufSize; + for (i = CFG_PARAM_MAX_NUM - 1; i >= 0; i--) { + if ((pMac->cfg.gCfgEntry[i].control & CFG_CTL_INT) != 0) + continue; + + if ((pMac->cfg.gCfgEntry[i].control & CFG_CTL_VALID) == 0) + continue; + + bufStart = pMac->cfg.gCfgEntry[i].control & CFG_BUF_INDX_MASK; + pMac->cfg.gCfgSBuf[bufStart] = + (uint8_t) (bufEnd - bufStart - 2); + + PELOG1(cfg_log + (pMac, LOG1, FL("id %d max %d bufStart %d bufEnd %d"), i, + pMac->cfg.gCfgSBuf[bufStart], bufStart, bufEnd); + ) + + bufEnd = bufStart; + } + + /* Initialize string defaults */ + strSize = pHdr->sBufSize; + while (strSize) { + uint32_t paramId, paramLen, paramLenCeil4; + + if (strSize < 4) { + PELOGE(cfg_log + (pMac, LOGE, + FL("Error parsing str defaults, rem %d bytes"), + strSize); + ) + retVal = WNI_CFG_INVALID_LEN; + goto end; + } + paramId = *pSrc >> 16; + paramLen = *pSrc & 0xff; + pSrc++; + strSize -= 4; + + paramLenCeil4 = ((paramLen + 3) >> 2); + if (strSize < paramLenCeil4 << 2) { + PELOGE(cfg_log + (pMac, LOGE, + FL("Error parsing str defaults, rem %d bytes"), + strSize); + ) + PELOGE(cfg_log + (pMac, LOGE, FL("param id %d len %d bytes"), + paramId, paramLen); + ) + retVal = WNI_CFG_INVALID_LEN; + goto end; + } + for (j = 0; j < paramLenCeil4; j++) { + pStr[4 * j] = (uint8_t) (*pSrc >> 24) & 0xff; + pStr[4 * j + 1] = (uint8_t) (*pSrc >> 16) & 0xff; + pStr[4 * j + 2] = (uint8_t) (*pSrc >> 8) & 0xff; + pStr[4 * j + 3] = (uint8_t) (*pSrc) & 0xff; + + pSrc++; + strSize -= 4; + } + + PELOG1(cfg_log + (pMac, LOG1, FL("set str id %d len %d"), paramId, + paramLen); + ) + + if (cfg_set_str(pMac, (uint16_t) paramId, pStr, paramLen) != + eSIR_SUCCESS) { + PELOGE(cfg_log + (pMac, LOGE, + FL("Error setting str default param %d len %d"), + paramId, paramLen); + ) + retVal = WNI_CFG_INVALID_LEN; + goto end; + } + } + + /* Set the default log level based on config */ + wlan_cfg_get_int(pMac, WNI_CFG_LOG_LEVEL, &logLevel); + for (i = 0; i < LOG_ENTRY_NUM; i++) + pMac->utils.gLogEvtLevel[i] = pMac->utils.gLogDbgLevel[i] = + logLevel; + + /* Set status to READY */ + pMac->cfg.gCfgStatus = CFG_SUCCESS; + retVal = WNI_CFG_SUCCESS; + PELOG1(cfg_log(pMac, LOG1, " Completed successfully");) + +end : + + if (retVal != WNI_CFG_SUCCESS) + pMac->cfg.gCfgStatus = CFG_FAILURE; + + /* Send response message to host */ + pMac->cfg.gParamList[WNI_CFG_DNLD_CNF_RES] = retVal; + cfg_send_host_msg(pMac, WNI_CFG_DNLD_CNF, WNI_CFG_DNLD_CNF_LEN, + WNI_CFG_DNLD_CNF_NUM, pMac->cfg.gParamList, 0, 0); + + /* notify WMA that the config has downloaded */ + mmhMsg.type = SIR_CFG_DOWNLOAD_COMPLETE_IND; + mmhMsg.bodyptr = NULL; + mmhMsg.bodyval = 0; + + MTRACE(mac_trace_msg_tx(pMac, NO_SESSION, mmhMsg.type)); + if (wma_post_ctrl_msg(pMac, &mmhMsg) != eSIR_SUCCESS) { + PELOGE(cfg_log(pMac, LOGE, FL("WMAPostMsgApi failed!"));) + } + +} /*** end procDnldRsp() ***/ + +/**--------------------------------------------------------------------- + * proc_get_req() + * + * FUNCTION: + * This function processes CFG_GET_REQ message from host. + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * For every parameter ID specified on the list, CFG will send a separate + * CFG_GET_RSP back to host. + * + * @param length: message length + * @param pParam: parameter list pointer + * + * @return None + * + */ +static void proc_get_req(tpAniSirGlobal pMac, uint16_t length, uint32_t *pParam) +{ + uint16_t cfgId, i; + uint32_t value, valueLen, result; + uint32_t *pValue; + + PELOG1(cfg_log(pMac, LOG1, FL("Rcvd cfg get request %d bytes"), length);) + for (i = 0; i < length / 4; i++) + PELOG2(cfg_log(pMac, LOG2, FL("[%2d] 0x%08x"), i, pParam[i]);) + + if (!pMac->cfg.gCfgStatus) { + cfgId = (uint16_t) sir_read_u32_n((uint8_t *) pParam); + PELOGE(cfg_log(pMac, LOGE, FL("CFG not ready, param %d"), cfgId);) + pMac->cfg.gParamList[WNI_CFG_GET_RSP_RES] = + WNI_CFG_NOT_READY; + pMac->cfg.gParamList[WNI_CFG_GET_RSP_PID] = cfgId; + pMac->cfg.gParamList[WNI_CFG_GET_RSP_PLEN] = 0; + cfg_send_host_msg(pMac, WNI_CFG_GET_RSP, + WNI_CFG_GET_RSP_PARTIAL_LEN, WNI_CFG_GET_RSP_NUM, + pMac->cfg.gParamList, 0, 0); + } else { + /* Process all parameter ID's on the list */ + while (length >= sizeof(uint32_t)) { + cfgId = (uint16_t) *pParam++; + pValue = 0; + valueLen = 0; + + PELOG1(cfg_log + (pMac, LOG1, FL("Cfg get param %d"), cfgId); + ) + /* Check for valid parameter ID, etc... */ + if (check_param + (pMac, cfgId, CFG_CTL_RE, WNI_CFG_WO_PARAM, + &result)) { + if ((pMac->cfg.gCfgEntry[cfgId]. + control & CFG_CTL_INT) != 0) { + /* Get integer parameter */ + result = + (wlan_cfg_get_int(pMac, cfgId, &value) + == + eSIR_SUCCESS ? WNI_CFG_SUCCESS : + WNI_CFG_OTHER_ERROR); + pValue = &value; + valueLen = sizeof(uint32_t); + } else { + /* Get string parameter */ + valueLen = sizeof(pMac->cfg.gSBuffer); + result = + (wlan_cfg_get_str + (pMac, cfgId, pMac->cfg.gSBuffer, + &valueLen) + == eSIR_SUCCESS ? WNI_CFG_SUCCESS : + WNI_CFG_OTHER_ERROR); + pValue = + (uint32_t *) pMac->cfg.gSBuffer; + } + } else { + PELOGE(cfg_log + (pMac, LOGE, + FL("Check param failed, param %d"), + cfgId); + ) + result = WNI_CFG_INVALID_LEN; + } + + /* Send response message to host */ + pMac->cfg.gParamList[WNI_CFG_GET_RSP_RES] = result; + pMac->cfg.gParamList[WNI_CFG_GET_RSP_PID] = cfgId; + pMac->cfg.gParamList[WNI_CFG_GET_RSP_PLEN] = valueLen; + + /* We need to round up buffer length to word-increment */ + valueLen = (((valueLen + 3) >> 2) << 2); + cfg_send_host_msg(pMac, WNI_CFG_GET_RSP, + WNI_CFG_GET_RSP_PARTIAL_LEN + valueLen, + WNI_CFG_GET_RSP_NUM, + pMac->cfg.gParamList, valueLen, pValue); + + /* Decrement length */ + length -= sizeof(uint32_t); + } + } + +} /*** end procGetReq() ***/ + +/**--------------------------------------------------------------------- + * proc_set_req_internal() + * + * FUNCTION: + * This function processes CFG_SET_REQ message from host. + * + * LOGIC: + * + * ASSUMPTIONS: + * - The message content is coded in TLV format. + * - For string parameter, the length field is byte accurate. However, + * the next TLV set will begin on the next word boundary. + * + * NOTE: + * - For every parameter ID specified on the list, CFG will send a separate + * CFG_SET_RSP back to host. + * + * @param length: message length + * @param pParam: parameter list pointer + * @param fRsp: whether to send response to host. true means sending. + * @return None + * + */ +static void +proc_set_req_internal(tpAniSirGlobal pMac, uint16_t length, uint32_t *pParam, + bool fRsp) +{ + uint16_t cfgId, valueLen, valueLenRoundedUp4; + uint32_t value, result; + + PELOG1(cfg_log(pMac, LOGl, FL("Rcvd cfg set request %d bytes"), length);) + + if (!pMac->cfg.gCfgStatus) { + cfgId = (uint16_t) sir_read_u32_n((uint8_t *) pParam); + PELOG1(cfg_log(pMac, LOGW, FL("CFG not ready, param %d"), cfgId);) + pMac->cfg.gParamList[WNI_CFG_SET_CNF_RES] = + WNI_CFG_NOT_READY; + pMac->cfg.gParamList[WNI_CFG_SET_CNF_PID] = cfgId; + if (fRsp) { + cfg_send_host_msg(pMac, WNI_CFG_SET_CNF, + WNI_CFG_SET_CNF_LEN, WNI_CFG_SET_CNF_NUM, + pMac->cfg.gParamList, 0, 0); + } + } else { + /* Process all TLVs in buffer */ + while (length >= (sizeof(uint32_t) * 2)) { + cfgId = (uint16_t) *pParam++; + valueLen = (uint16_t) *pParam++; + length -= (sizeof(uint32_t) * 2); + /* value length rounded up to a 4 byte multiple */ + valueLenRoundedUp4 = (((valueLen + 3) >> 2) << 2); + + /* Check for valid request before proceeding */ + if (check_param + (pMac, cfgId, CFG_CTL_WE, WNI_CFG_RO_PARAM, + &result)) { + PELOG1(cfg_log + (pMac, LOGW, + (char *)g_cfg_param_name[cfgId]); + ) + /* Process integer parameter */ + if ((pMac->cfg.gCfgEntry[cfgId]. + control & CFG_CTL_INT) != 0) { + /* Set VALUE */ + if (valueLen != sizeof(uint32_t)) { + PELOGE(cfg_log + (pMac, LOGE, + FL + ("Invalid value length %d in set param %d (tot %d)"), + valueLen, cfgId, + length); + ) + result = + WNI_CFG_INVALID_LEN; + } else { + value = *pParam; + PELOG1(cfg_log + (pMac, LOGW, + FL + ("Cfg set int %d len %d(%d) val %d"), + cfgId, valueLen, + valueLenRoundedUp4, + value); + ) + result = + (cfg_set_int + (pMac, cfgId, + value) == + eSIR_SUCCESS ? + WNI_CFG_SUCCESS : + WNI_CFG_OTHER_ERROR); + if (result == WNI_CFG_SUCCESS) { + if (cfg_need_restart + (pMac, cfgId)) { + result = + WNI_CFG_NEED_RESTART; + } else + if (cfg_need_reload + (pMac, cfgId)) { + result = + WNI_CFG_NEED_RELOAD; + } + } + } + } + /* Process string parameter */ + else { + if (valueLenRoundedUp4 > length) { + PELOGE(cfg_log + (pMac, LOGE, + FL + ("Invalid string length %d" + "in set param %d (tot %d)"), + valueLen, cfgId, + length); + ) + result = + WNI_CFG_INVALID_LEN; + } else { + get_str_value((uint8_t *) pParam, + pMac->cfg.gSBuffer, + valueLen); + PELOG1(cfg_log + (pMac, LOGW, + FL + ("Cfg set str %d len %d(%d) bytes"), + cfgId, valueLen, + valueLenRoundedUp4); + ) + result = + (cfg_set_str + (pMac, cfgId, + pMac->cfg.gSBuffer, + valueLen) == + eSIR_SUCCESS ? + WNI_CFG_SUCCESS : + WNI_CFG_OTHER_ERROR); + if (result == WNI_CFG_SUCCESS) { + if (cfg_need_restart + (pMac, cfgId)) { + result = + WNI_CFG_NEED_RESTART; + } else + if (cfg_need_reload + (pMac, cfgId)) { + result = + WNI_CFG_NEED_RELOAD; + } + } + } + } + } else { + PELOGE(cfg_log + (pMac, LOGE, + FL("Check param failed, param %d"), + cfgId); + ) + result = WNI_CFG_INVALID_LEN; + } + + /* Send confirm message to host */ + pMac->cfg.gParamList[WNI_CFG_SET_CNF_RES] = result; + pMac->cfg.gParamList[WNI_CFG_SET_CNF_PID] = cfgId; + if (fRsp) { + cfg_send_host_msg(pMac, WNI_CFG_SET_CNF, + WNI_CFG_SET_CNF_LEN, + WNI_CFG_SET_CNF_NUM, + pMac->cfg.gParamList, 0, 0); + } else { + PELOGW(cfg_log + (pMac, LOG2, " CFGID %d no rsp", cfgId); + ) + } + + if (valueLenRoundedUp4 > length) + length = 0; + else { + length -= valueLenRoundedUp4; + pParam += (valueLenRoundedUp4 >> 2); + } + } + } +} + +static void proc_set_req(tpAniSirGlobal pMac, uint16_t length, uint32_t *pParam) +{ + proc_set_req_internal(pMac, length, pParam, true); +} + +static void +proc_set_req_no_rsp(tpAniSirGlobal pMac, uint16_t length, uint32_t *pParam) +{ + proc_set_req_internal(pMac, length, pParam, false); +} + +/**--------------------------------------------------------------------- + * check_param() + * + * FUNCTION: + * This function is called to perform various check on a parameter. + * + * LOGIC: + * - If cfgId is out of bound or parameter is not valid, result + * WNI_CFG_INVALID_PID is returned at address specified in pResult. + * + * - If specified 'flag' is not set in the parameter control entry, + * 'failedResult' is returned at address specified in pResult. + * + * ASSUMPTIONS: + * Since this function is used internally, 'pResult' is always valid. + * + * NOTE: + * + * @param None + * + * @return true: Parameter is valid and matches checked condition \n + * @return false: Parameter either is not valid or does not match + * checked condition. + * + */ +static uint8_t +check_param(tpAniSirGlobal pMac, uint16_t cfgId, uint32_t flag, + uint32_t failedResult, uint32_t *pResult) +{ + /* Check if parameter ID is out of bound */ + if (cfgId >= CFG_PARAM_MAX_NUM) { + PELOGE(cfg_log(pMac, LOGE, FL("Invalid param id %d"), cfgId);) + * pResult = WNI_CFG_INVALID_PID; + } else { + /* Check if parameter is valid */ + if ((pMac->cfg.gCfgEntry[cfgId].control & CFG_CTL_VALID) == 0) { + PELOGE(cfg_log + (pMac, LOGE, FL("Param id %d not valid"), cfgId); + ) + * pResult = WNI_CFG_INVALID_PID; + } else { + /* Check control field against flag */ + if ((pMac->cfg.gCfgEntry[cfgId].control & flag) == 0) { + PELOGE(cfg_log + (pMac, LOGE, + FL("Param id %d wrong permissions %x"), + cfgId, + pMac->cfg.gCfgEntry[cfgId].control); + ) + * pResult = failedResult; + } else + return true; + } + } + return false; + +} /*** cfgParamCheck() ***/ + +/**--------------------------------------------------------------------- + * get_str_value() + * + * FUNCTION: + * This function copies a string value from the specified buffer. + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param pBuf: input data buffer + * @param pValue: address where data is returned + * @param length: number of bytes to copy + * + * @return None + * + */ +static void get_str_value(uint8_t *pBuf, uint8_t *pValue, uint32_t length) +{ + uint8_t *pEnd; + + pEnd = pValue + length; + while (pValue < pEnd) + *pValue++ = *pBuf++; +} /*** end get_str_value() ***/ + +/**--------------------------------------------------------------------- + * process_cfg_download_req() + * + * FUNCTION: This function does the Cfg Download and is invoked + * only in the case of Prima or the Integrated SOC + * solutions. Not applicable to Volans or Libra + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param pMac: Pointer to Mac Structure + * + * @return None + * + */ + +void +process_cfg_download_req(tpAniSirGlobal pMac) +{ + int32_t i; + uint32_t index; + uint8_t *pDstTest, *pSrcTest; + uint8_t len; + cfgstatic_string * pStrCfg; + uint32_t bufStart, bufEnd; + uint32_t logLevel, retVal; + uint32_t iCount = 0; + uint32_t sCount = 0; + + for (i = 0; i < CFG_PARAM_MAX_NUM ; i++) { + if ((cfg_static[i].control & CFG_CTL_VALID) != 0) { + if (!(cfg_static[i].control & CFG_CTL_INT)) { + pStrCfg = (cfgstatic_string*)cfg_static[i]. + pStrData; + if (pStrCfg == NULL) { + PELOGE(cfg_log(pMac, LOGE, + FL("pStrCfg is NULL for CfigID : %d"), + i);) + continue; + } + index = sCount & CFG_BUF_INDX_MASK; + sCount += pStrCfg->maxLen + 1 + 1; + } else { + index = iCount & CFG_BUF_INDX_MASK; + iCount++; + } + } else { + index = 0; + } + pMac->cfg.gCfgEntry[i].control = cfg_static[i].control | index; + } + + /*Fill the SBUF wih maxLength*/ + bufEnd = pMac->cfg.gCfgMaxSBufSize; + for (i = CFG_PARAM_MAX_NUM - 1; i >= 0; i--) { + if ((pMac->cfg.gCfgEntry[i].control & CFG_CTL_INT) != 0) + continue; + + if ((pMac->cfg.gCfgEntry[i].control & CFG_CTL_VALID) == 0) + continue; + + bufStart = pMac->cfg.gCfgEntry[i].control & CFG_BUF_INDX_MASK; + pMac->cfg.gCfgSBuf[bufStart] = (uint8_t)(bufEnd - bufStart - 2); + + PELOG1(cfgLog(pMac, LOG1, FL("id %d max %d bufStart %d bufEnd %d"), + i, pMac->cfg.gCfgSBuf[bufStart], + bufStart, bufEnd);) + bufEnd = bufStart; + } + + for (i = 0; i < CFG_PARAM_MAX_NUM ; i++) { + index = pMac->cfg.gCfgEntry[i].control & CFG_BUF_INDX_MASK; + + if ((pMac->cfg.gCfgEntry[i].control & CFG_CTL_INT) != 0) { + pMac->cfg.gCfgIBufMin[index] = cfg_static[i].cfgIMin; + pMac->cfg.gCfgIBufMax[index] = cfg_static[i].cfgIMax; + pMac->cfg.gCfgIBuf[index] = cfg_static[i].cfgIVal; + } else { + uint8_t maxSavedLen; + if ((pMac->cfg.gCfgEntry[i].control & CFG_CTL_VALID) == 0) + continue; + if (index >= pMac->cfg.gCfgMaxSBufSize) + continue; + + pDstTest = &pMac->cfg.gCfgSBuf[index]; + pStrCfg = (cfgstatic_string*)cfg_static[i].pStrData; + pSrcTest = pStrCfg->data; + if ((pDstTest == NULL) || (pStrCfg == NULL) || + (pSrcTest == NULL)) + continue; + maxSavedLen = *pDstTest; + len = pStrCfg->length; + if (len > maxSavedLen) + continue; + *pDstTest++ = pStrCfg->maxLen; + *pDstTest++ = len; + while (len) { + *pDstTest++ = *pSrcTest++; + len--; + } + } + } + + /* Set the default log level based on config */ + wlan_cfg_get_int(pMac, WNI_CFG_LOG_LEVEL, &logLevel); + for (i = 0; i < LOG_ENTRY_NUM; i++) + pMac->utils.gLogEvtLevel[i] = pMac->utils.gLogDbgLevel[i] = + logLevel; + + /* Set status to READY */ + pMac->cfg.gCfgStatus = CFG_SUCCESS; + retVal = WNI_CFG_SUCCESS; + PELOG1(cfg_log(pMac, LOG1, " Completed successfully");) + + pMac->cfg.gParamList[WNI_CFG_DNLD_CNF_RES] = retVal; + +} /*** end ProcessDownloadReq() ***/ diff --git a/drivers/staging/qcacld-3.0/core/mac/src/cfg/cfg_send_msg.c b/drivers/staging/qcacld-3.0/core/mac/src/cfg/cfg_send_msg.c new file mode 100644 index 0000000000000000000000000000000000000000..a50652c063db12a8f5ab17e4d7adefaec1d01a73 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/cfg/cfg_send_msg.c @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2012, 2014-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * This file contains the source code for composing and sending messages + * to host. + * + * Author: Kevin Nguyen + * Date: 04/09/02 + * History:- + * 04/09/02 Created. + * -------------------------------------------------------------------- + */ +#include "cds_api.h" +#include "cfg_priv.h" +#include "lim_trace.h" +#include "cfg_debug.h" + +/*--------------------------------------------------------------------*/ +/* ATTENTION: The functions contained in this module are to be used */ +/* by CFG module ONLY. */ +/*--------------------------------------------------------------------*/ + +/**--------------------------------------------------------------------- + * cfg_send_host_msg() + * + * FUNCTION: + * Send CNF/RSP to host. + * + * LOGIC: + * Please see Configuration & Statistic Collection Micro-Architecture + * specification for details. + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param msgType: message type + * @param msgLen: message length + * @param paramNum: number of parameters + * @param pParamList: pointer to parameter list + * @param dataLen: data length + * @param pData: pointer to additional data + * + * @return None. + * + */ +void +cfg_send_host_msg(tpAniSirGlobal pMac, uint16_t msgType, uint32_t msgLen, + uint32_t paramNum, uint32_t *pParamList, uint32_t dataLen, + uint32_t *pData) +{ + uint32_t *pMsg, *pEnd; + tSirMsgQ mmhMsg; + + /* sanity */ + if ((paramNum > 0) && (NULL == pParamList)) { + PELOGE(cfg_log(pMac, LOGE, + FL + ("pParamList NULL when paramNum greater than 0!")); + ) + return; + } + if ((dataLen > 0) && (NULL == pData)) { + PELOGE(cfg_log(pMac, LOGE, + FL("pData NULL when dataLen greater than 0!")); + ) + return; + } + /* Allocate message buffer */ + pMsg = qdf_mem_malloc(msgLen); + if (NULL == pMsg) { + PELOGE(cfg_log(pMac, LOGE, FL("Memory allocation failure!"));) + return; + } + /* Fill in message details */ + mmhMsg.type = msgType; + mmhMsg.bodyptr = pMsg; + mmhMsg.bodyval = 0; + ((tSirMbMsg *) pMsg)->type = msgType; + ((tSirMbMsg *) pMsg)->msgLen = (uint16_t) msgLen; + + switch (msgType) { + case WNI_CFG_GET_RSP: + case WNI_CFG_PARAM_UPDATE_IND: + case WNI_CFG_DNLD_REQ: + case WNI_CFG_DNLD_CNF: + case WNI_CFG_SET_CNF: + /* Fill in parameters */ + pMsg++; + if (NULL != pParamList) { + pEnd = pMsg + paramNum; + while (pMsg < pEnd) { + *pMsg++ = *pParamList++; + } + } + /* Copy data if there is any */ + if (NULL != pData) { + pEnd = pMsg + (dataLen >> 2); + while (pMsg < pEnd) { + *pMsg++ = *pData++; + } + } + break; + + default: + PELOGE(cfg_log(pMac, LOGE, FL("Unknown msg %d!"), (int)msgType);) + qdf_mem_free(pMsg); + return; + } + + /* Ship it */ + MTRACE(mac_trace_msg_tx(pMac, NO_SESSION, mmhMsg.type)); + sys_process_mmh_msg(pMac, &mmhMsg); + +} /*** end cfg_send_host_msg() ***/ diff --git a/drivers/staging/qcacld-3.0/core/mac/src/dph/dph_hash_table.c b/drivers/staging/qcacld-3.0/core/mac/src/dph/dph_hash_table.c new file mode 100644 index 0000000000000000000000000000000000000000..f70f298c218afc171cce15d33d1b0b87a5b0fd8e --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/dph/dph_hash_table.c @@ -0,0 +1,466 @@ +/* + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * + * This file dph_hash_table.cc implements the member functions of + * DPH hash table class. + * + * Author: Sandesh Goel + * Date: 02/25/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + * + */ +#include "cds_api.h" +#include "cfg_api.h" +#include "sch_api.h" +#include "dph_global.h" +#include "lim_debug.h" + +#include "wma_if.h" + +/* --------------------------------------------------------------------- */ +/** + * dphHashTableClass() + * + * FUNCTION: + * Constructor function + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param None + * @return None + */ + +void dph_hash_table_class_init(tpAniSirGlobal pMac, + dphHashTableClass *pDphHashTable) +{ + uint16_t i; + + for (i = 0; i < pDphHashTable->size; i++) { + pDphHashTable->pHashTable[i] = 0; + } + + for (i = 0; i < pDphHashTable->size; i++) { + pDphHashTable->pDphNodeArray[i].valid = 0; + pDphHashTable->pDphNodeArray[i].added = 0; + pDphHashTable->pDphNodeArray[i].assocId = i; + } + +} + +/* --------------------------------------------------------------------- */ +/** + * hash_function + * + * FUNCTION: + * Hashing function + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param staAddr MAC address of the station + * @return None + */ + +static uint16_t hash_function(tpAniSirGlobal pMac, uint8_t staAddr[], + uint16_t numSta) +{ + int i; + uint16_t sum = 0; + + for (i = 0; i < 6; i++) + sum += staAddr[i]; + + return sum % numSta; +} + +/* --------------------------------------------------------------------- */ +/** + * dph_lookup_hash_entry + * + * FUNCTION: + * Look up an entry in hash table + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param staAddr MAC address of the station + * @param pStaId pointer to the Station ID assigned to the station + * @return pointer to STA hash entry if lookup was a success \n + * NULL if lookup was a failure + */ + +tpDphHashNode dph_lookup_hash_entry(tpAniSirGlobal pMac, uint8_t staAddr[], + uint16_t *pAssocId, + dphHashTableClass *pDphHashTable) +{ + tpDphHashNode ptr = NULL; + uint16_t index = hash_function(pMac, staAddr, pDphHashTable->size); + + if (!pDphHashTable->pHashTable) { + lim_log(pMac, LOGE, FL("pHashTable is NULL")); + return ptr; + } + + for (ptr = pDphHashTable->pHashTable[index]; ptr; ptr = ptr->next) { + if (dph_compare_mac_addr(staAddr, ptr->staAddr)) { + *pAssocId = ptr->assocId; + break; + } + } + return ptr; +} + +/* --------------------------------------------------------------------- */ +/** + * dph_get_hash_entry + * + * FUNCTION: + * Get a pointer to the hash node + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param staId Station ID + * @return pointer to STA hash entry if lookup was a success \n + * NULL if lookup was a failure + */ + +tpDphHashNode dph_get_hash_entry(tpAniSirGlobal pMac, uint16_t peerIdx, + dphHashTableClass *pDphHashTable) +{ + if (peerIdx < pDphHashTable->size) { + if (pDphHashTable->pDphNodeArray[peerIdx].added) + return &pDphHashTable->pDphNodeArray[peerIdx]; + else + return NULL; + } else + return NULL; + +} + +static inline tpDphHashNode get_node(tpAniSirGlobal pMac, uint8_t assocId, + dphHashTableClass *pDphHashTable) +{ + return &pDphHashTable->pDphNodeArray[assocId]; +} + +/* --------------------------------------------------------------------- */ +/** + * dph_lookup_assoc_id + * + * FUNCTION: + * This function looks up assocID given the station Id. It traverses the complete table to do this. + * Need to find an efficient way to do this. + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param pMac pointer to global Mac structure. + * @param staIdx station ID + * @param *assocId pointer to associd to be returned by this function. + * @return pointer to the dph node. + */ +tpDphHashNode dph_lookup_assoc_id(tpAniSirGlobal pMac, uint16_t staIdx, + uint16_t *assocId, + dphHashTableClass *pDphHashTable) +{ + uint8_t i; + + for (i = 0; i < pDphHashTable->size; i++) { + if ((pDphHashTable->pDphNodeArray[i].added) && + (pDphHashTable->pDphNodeArray[i].staIndex == staIdx)) { + *assocId = i; + break; + } + + } + if (i == pDphHashTable->size) + return NULL; + return &pDphHashTable->pDphNodeArray[i]; + +} + +/** ------------------------------------------------------------- + \fn dph_init_sta_state + \brief Initialize STA state. this function saves the staId from the current entry in the DPH table with given assocId + \ if validStaIdx flag is set. Otherwise it sets the staId to invalid. + \param tpAniSirGlobal pMac + \param tSirMacAddr staAddr + \param uint16_t assocId + \param uint8_t validStaIdx - true ==> the staId in the DPH entry with given assocId is valid and restore it back. + \ false ==> set the staId to invalid. + \return tpDphHashNode - DPH hash node if found. + -------------------------------------------------------------*/ + +tpDphHashNode dph_init_sta_state(tpAniSirGlobal pMac, tSirMacAddr staAddr, + uint16_t assocId, uint8_t validStaIdx, + dphHashTableClass *pDphHashTable) +{ + uint32_t val; + + tpDphHashNode pStaDs; + uint16_t staIdx = STA_INVALID_IDX; + + if (assocId >= pDphHashTable->size) { + PELOGE(lim_log(pMac, LOGE, FL("Invalid Assoc Id %d"), assocId);) + return NULL; + } + + pStaDs = get_node(pMac, (uint8_t) assocId, pDphHashTable); + staIdx = pStaDs->staIndex; + + PELOG1(lim_log + (pMac, LOG1, FL("Assoc Id %d, Addr %08X"), assocId, pStaDs); + ) + /* Clear the STA node except for the next pointer (last 4 bytes) */ + qdf_mem_set((uint8_t *) pStaDs, + sizeof(tDphHashNode) - sizeof(tpDphHashNode), 0); + + /* Initialize the assocId */ + pStaDs->assocId = assocId; + if (true == validStaIdx) + pStaDs->staIndex = staIdx; + else + pStaDs->staIndex = STA_INVALID_IDX; + + /* Initialize STA mac address */ + qdf_mem_copy(pStaDs->staAddr, staAddr, sizeof(tSirMacAddr)); + + /* Initialize fragmentation threshold */ + if (wlan_cfg_get_int(pMac, WNI_CFG_FRAGMENTATION_THRESHOLD, &val) != + eSIR_SUCCESS) + lim_log(pMac, LOGP, + FL("could not retrieve fragmentation threshold")); + else + pStaDs->fragSize = (uint16_t) val; + + pStaDs->added = 1; + pStaDs->encPolicy = ENC_POLICY_NULL; + pStaDs->is_disassoc_deauth_in_progress = 0; +#ifdef WLAN_FEATURE_11W + pStaDs->last_assoc_received_time = 0; +#endif + pStaDs->sta_deletion_in_progress = false; + pStaDs->valid = 1; + return pStaDs; +} + +/* --------------------------------------------------------------------- */ +/** + * dph_add_hash_entry + * + * FUNCTION: + * Add entry to hash table + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param staAddr MAC address of the station + * @param staId Station ID assigned to the station + * @return Pointer to STA hash entry + */ + +tpDphHashNode dph_add_hash_entry(tpAniSirGlobal pMac, tSirMacAddr staAddr, + uint16_t assocId, + dphHashTableClass *pDphHashTable) +{ + tpDphHashNode ptr, node; + uint16_t index = hash_function(pMac, staAddr, pDphHashTable->size); + + PELOG1(lim_log(pMac, LOG1, FL("assocId %d index %d STA addr"), + assocId, index); dph_print_mac_addr(pMac, staAddr, LOG1); + ) + + if (assocId >= pDphHashTable->size) { + PELOGE(lim_log(pMac, LOGE, FL("invalid STA id %d"), assocId);) + return NULL; + } + + if (pDphHashTable->pDphNodeArray[assocId].added) { + PELOGE(lim_log(pMac, LOGE, FL("already added STA %d"), assocId);) + return NULL; + } + + for (ptr = pDphHashTable->pHashTable[index]; ptr; ptr = ptr->next) { + if (ptr == ptr->next) { + PELOGE(lim_log(pMac, LOGE, FL("Infinite Loop"));) + return NULL; + } + + if (dph_compare_mac_addr(staAddr, ptr->staAddr) + || ptr->assocId == assocId) + break; + } + + if (ptr) { + /* Duplicate entry */ + lim_log(pMac, LOGE, FL("assocId %d hashIndex %d entry exists"), + assocId, index); + return NULL; + } else { + if (dph_init_sta_state + (pMac, staAddr, assocId, false, pDphHashTable) == NULL) { + PELOGE(lim_log + (pMac, LOGE, FL("could not Init STAid=%d"), + assocId); + ) + return NULL; + } + /* Add the node to the link list */ + pDphHashTable->pDphNodeArray[assocId].next = + pDphHashTable->pHashTable[index]; + pDphHashTable->pHashTable[index] = + &pDphHashTable->pDphNodeArray[assocId]; + + node = pDphHashTable->pHashTable[index]; + return node; + } +} + +/* --------------------------------------------------------------------- */ +/** + * dph_delete_hash_entry + * + * FUNCTION: + * Delete entry from hash table + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param staAddr MAC address of the station + * @param staId Station ID assigned to the station + * @return eSIR_SUCCESS if successful,\n + * eSIR_FAILURE otherwise + */ + +tSirRetStatus dph_delete_hash_entry(tpAniSirGlobal pMac, tSirMacAddr staAddr, + uint16_t assocId, + dphHashTableClass *pDphHashTable) +{ + tpDphHashNode ptr, prev; + uint16_t index = hash_function(pMac, staAddr, pDphHashTable->size); + + PELOG1(lim_log(pMac, LOG1, FL("assocId %d index %d STA addr"), + assocId, index); dph_print_mac_addr(pMac, staAddr, LOG1); + ) + + if (assocId >= pDphHashTable->size) { + PELOGE(lim_log(pMac, LOGE, FL("invalid STA id %d"), assocId);) + return eSIR_FAILURE; + } + + if (pDphHashTable->pDphNodeArray[assocId].added == 0) { + PELOGE(lim_log(pMac, LOGE, FL("STA %d never added"), assocId);) + return eSIR_FAILURE; + } + + for (prev = 0, ptr = pDphHashTable->pHashTable[index]; + ptr; prev = ptr, ptr = ptr->next) { + if (dph_compare_mac_addr(staAddr, ptr->staAddr)) + break; + if (prev == ptr) { + PELOGE(lim_log(pMac, LOGE, FL("Infinite Loop"));) + return eSIR_FAILURE; + } + } + + if (ptr) { + /* / Delete the entry after invalidating it */ + ptr->valid = 0; + memset(ptr->staAddr, 0, sizeof(ptr->staAddr)); + if (prev == 0) + pDphHashTable->pHashTable[index] = ptr->next; + else + prev->next = ptr->next; + ptr->added = 0; + ptr->is_disassoc_deauth_in_progress = 0; +#ifdef WLAN_FEATURE_11W + ptr->last_assoc_received_time = 0; +#endif + ptr->sta_deletion_in_progress = false; + ptr->next = 0; + } else { + /* / Entry not present */ + PELOGE(lim_log(pMac, LOGE, FL("Entry not present STA addr")); + dph_print_mac_addr(pMac, staAddr, LOGE); + ) + return eSIR_FAILURE; + } + + return eSIR_SUCCESS; +} + +/* --------------------------------------------------------------------- */ +/** + * dph_print_mac_addr + * + * FUNCTION: + * Print a MAC address + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param addr MAC address + * @return None + */ + +void dph_print_mac_addr(tpAniSirGlobal pMac, uint8_t addr[], uint32_t level) +{ + lim_log(pMac, (uint16_t) level, + FL("MAC ADDR = %02x:%02x:%02x:%02x:%02x:%02x"), + addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]); +} + +/* --------------------------------------------------------------------- */ diff --git a/drivers/staging/qcacld-3.0/core/mac/src/dph/dph_hash_table.h b/drivers/staging/qcacld-3.0/core/mac/src/dph/dph_hash_table.h new file mode 100644 index 0000000000000000000000000000000000000000..1a55f586a8380a6f32ff1b61000bd011f2beeaa6 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/dph/dph_hash_table.h @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2011-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * + * This file dph_hash_table.h contains the definition of the scheduler class. + * + * Author: Sandesh Goel + * Date: 02/25/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + * + */ + +#ifndef __DPH_HASH_TABLE_H__ +#define __DPH_HASH_TABLE_H__ + +#include "ani_global.h" +/* Compare MAC addresses, return true if same */ +static inline uint8_t dph_compare_mac_addr(uint8_t addr1[], uint8_t addr2[]) +{ + return (addr1[0] == addr2[0]) && + (addr1[1] == addr2[1]) && + (addr1[2] == addr2[2]) && + (addr1[3] == addr2[3]) && + (addr1[4] == addr2[4]) && (addr1[5] == addr2[5]); +} + +/* Hash table class */ +typedef struct { + + /* The hash table itself */ + tpDphHashNode *pHashTable; + + /* The state array */ + tDphHashNode *pDphNodeArray; + uint16_t size; +} dphHashTableClass; + +/* The hash table object */ +extern dphHashTableClass dphHashTable; + +/* Print MAC addresse */ +extern void dph_print_mac_addr(struct sAniSirGlobal *pMac, uint8_t addr[], + uint32_t); + +tpDphHashNode dph_lookup_hash_entry(tpAniSirGlobal pMac, uint8_t staAddr[], + uint16_t *pStaId, + dphHashTableClass *pDphHashTable); +tpDphHashNode dph_lookup_assoc_id(tpAniSirGlobal pMac, uint16_t staIdx, + uint16_t *assocId, + dphHashTableClass *pDphHashTable); + +/* Get a pointer to the hash node */ +extern tpDphHashNode dph_get_hash_entry(tpAniSirGlobal pMac, uint16_t staId, + dphHashTableClass *pDphHashTable); + +/* Add an entry to the hash table */ +extern tpDphHashNode dph_add_hash_entry(tpAniSirGlobal pMac, + tSirMacAddr staAddr, + uint16_t staId, + dphHashTableClass *pDphHashTable); + +/* Delete an entry from the hash table */ +extern tSirRetStatus dph_delete_hash_entry(tpAniSirGlobal pMac, + tSirMacAddr staAddr, uint16_t staId, + dphHashTableClass *pDphHashTable); + +void dph_hash_table_class_init(tpAniSirGlobal pMac, + dphHashTableClass *pDphHashTable); +/* Initialize STA state */ +extern tpDphHashNode dph_init_sta_state(tpAniSirGlobal pMac, + tSirMacAddr staAddr, + uint16_t staId, uint8_t validStaIdx, + dphHashTableClass *pDphHashTable); + +#endif diff --git a/drivers/staging/qcacld-3.0/core/mac/src/include/cfg_api.h b/drivers/staging/qcacld-3.0/core/mac/src/include/cfg_api.h new file mode 100644 index 0000000000000000000000000000000000000000..2240dd48229319319c0a27987b4159c1ff0116d5 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/include/cfg_api.h @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2011-2012, 2015-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * + * Author: Kevin Nguyen + * Date: 04/09/02 + * History:- + * 04/09/02 Created. + * -------------------------------------------------------------------- + * + */ + +#ifndef __CFGAPI_H +#define __CFGAPI_H + +#include +#include +#include +#include +#include + +/*---------------------------------------------------------------------*/ +/* CFG definitions */ +/*---------------------------------------------------------------------*/ + +/* CFG status */ +typedef enum eCfgStatusTypes { + CFG_INCOMPLETE, + CFG_SUCCESS, + CFG_FAILURE +} tCfgStatusTypes; + +/* WEP key mapping table row structure */ +typedef struct { + uint8_t keyMappingAddr[QDF_MAC_ADDR_SIZE]; + uint32_t wepOn; + uint8_t key[SIR_MAC_KEY_LENGTH]; + uint32_t status; +} tCfgWepKeyEntry; + +/*---------------------------------------------------------------------*/ +/* CFG function prototypes */ +/*---------------------------------------------------------------------*/ + +uint32_t cfg_need_restart(tpAniSirGlobal pMac, uint16_t cfgId); +uint32_t cfg_need_reload(tpAniSirGlobal pMac, uint16_t cfgId); + +/* / Process host message */ +void cfg_process_mb_msg(tpAniSirGlobal, tSirMbMsg *); + +/* / Set integer parameter value */ +tSirRetStatus cfg_set_int(tpAniSirGlobal, uint16_t, uint32_t); + +/* / Check if the parameter is valid */ +tSirRetStatus cfg_check_valid(tpAniSirGlobal, uint16_t, uint32_t *); + +/* / Get integer parameter value */ +tSirRetStatus wlan_cfg_get_int(tpAniSirGlobal, uint16_t, uint32_t *); + +/* / Set string parameter value */ +tSirRetStatus cfg_set_str(tpAniSirGlobal, uint16_t, uint8_t *, uint32_t); + +tSirRetStatus cfg_set_str_notify(tpAniSirGlobal, uint16_t, uint8_t *, uint32_t, + int); + +/* Cfg Download function for Prima or Integrated solutions. */ +void process_cfg_download_req(tpAniSirGlobal); + +/* / Get string parameter value */ +tSirRetStatus wlan_cfg_get_str(tpAniSirGlobal, uint16_t, uint8_t *, uint32_t *); + +/* / Get string parameter maximum length */ +tSirRetStatus wlan_cfg_get_str_max_len(tpAniSirGlobal, uint16_t, uint32_t *); + +/* / Get string parameter maximum length */ +tSirRetStatus wlan_cfg_get_str_len(tpAniSirGlobal, uint16_t, uint32_t *); + +/* / Get the regulatory tx power on given channel */ +int8_t cfg_get_regulatory_max_transmit_power(tpAniSirGlobal pMac, + uint8_t channel); + +/* / Dump CFG data to memory */ +void cfgDump(uint32_t *); + +/* / Save parameters with P flag set */ +void cfgSave(void); + +/* / Get capability info */ +extern tSirRetStatus cfg_get_capability_info(tpAniSirGlobal pMac, uint16_t *pCap, + tpPESession psessionEntry); + +/* / Set capability info */ +extern void cfg_set_capability_info(tpAniSirGlobal, uint16_t); + +/* / Cleanup CFG module */ +void cfg_cleanup(tpAniSirGlobal pMac); + +extern uint8_t *g_cfg_param_name[]; + +uint8_t *cfg_get_vendor_ie_ptr_from_oui(tpAniSirGlobal mac_ctx, + uint8_t *oui, + uint8_t oui_size, + uint8_t *ie, + uint16_t ie_len); + +#endif /* __CFGAPI_H */ diff --git a/drivers/staging/qcacld-3.0/core/mac/src/include/cfg_global.h b/drivers/staging/qcacld-3.0/core/mac/src/include/cfg_global.h new file mode 100644 index 0000000000000000000000000000000000000000..960efac0bf5bdd032196b60dd0c99ab0efda81f9 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/include/cfg_global.h @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2011-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * + * Author: Sandesh Goel + * Date: 02/09/03 + * History:- + * 04/09/02 Created. + * -------------------------------------------------------------------- + * + */ + +#ifndef __CFGGLOBAL_H +#define __CFGGLOBAL_H + +#include "sir_common.h" +#include "sir_types.h" +#include "wni_cfg.h" + +#define CFG_MAX_NUM_STA SIR_MAX_NUM_STA_IN_IBSS + +#define CFG_MAX_STATIC_STRING 70 +/* as the number of channels grows, 128 is not big enough */ +#define CFG_MAX_STR_LEN 256 + +/*--------------------------------------------------------------------*/ +/* Configuration Control Structure */ +/*--------------------------------------------------------------------*/ +typedef struct { + uint32_t control; +} tCfgCtl; + + +typedef struct sAniSirCfgStaticString { + uint16_t cfgId; + uint8_t maxLen; + uint8_t length; + uint8_t data[255]; +} cfgstatic_string; + +typedef struct sAniSirCfgStatic { + uint16_t cfgId; + uint32_t control; + uint32_t cfgIMin; + uint32_t cfgIMax; + uint32_t cfgIVal; + void *pStrData; +} cgstatic; + +typedef struct sAniSirCfg { + /* CFG module status */ + uint8_t gCfgStatus; + + tCfgCtl *gCfgEntry; + + uint8_t *gCfgSBuf; + uint32_t *gCfgIBuf; + uint32_t *gCfgIBufMin; + uint32_t *gCfgIBufMax; + + uint16_t gCfgMaxIBufSize; + uint16_t gCfgMaxSBufSize; + + /* Static buffer for string parameter (must be word-aligned) */ + uint8_t *gSBuffer; + + /* Message param list buffer (enough for largest possible response) */ + uint32_t *gParamList; +} tAniSirCfg, *tpAniSirCfg; + +#endif diff --git a/drivers/staging/qcacld-3.0/core/mac/src/include/dot11f.h b/drivers/staging/qcacld-3.0/core/mac/src/include/dot11f.h new file mode 100644 index 0000000000000000000000000000000000000000..c5be2fdc247478de3fd9f4f63edafb06182db350 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/include/dot11f.h @@ -0,0 +1,9439 @@ +/* + * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef DOT11F_H +#define DOT11F_H +/* + * \file dot11f.h + * + * \brief Structures, function prototypes & definitions + * for working with 802.11 Frames + * + * + * This file was automatically generated by 'framesc' + * Fri Jun 9 14:23:47 2017 from the following file(s): + * + * dot11f.frms + * + * PLEASE DON'T EDIT THIS FILE BY HAND! + * + * Instead, please update the input files & re-run + * 'framesc' For more information on 'framesc' & the + * frames language, run 'framesc --help'. + * + */ + +typedef uint32_t tDOT11F_U64[2]; + +#if defined (_MSC_VER) +#pragma warning (disable:4214) /* nonstandard extension used */ +#endif /* Microsoft C/C++ bit field types other than int */ + +/* + * Frames Return Codes: + * + * Success is indicated by a return value of zero. Failure is indicated + * by the presence of the high bit. Warnings encountered in the course + * of a successful parse are indicated by various bits in the lower 31 + * being turned on. + * + * For instance, a return value of 0x0000000a would indicate that the + * parse succeeded, but that a mandatory IE wasn't present, and some IE + * was found to be corrupt. + * + * + */ + +#define DOT11F_PARSE_SUCCESS (0x00000000) +#define DOT11F_UNKNOWN_IES (0x00000001) +#define DOT11F_MANDATORY_IE_MISSING (0x00000002) +#define DOT11F_INCOMPLETE_IE (0x00000004) +#define DOT11F_SKIPPED_BAD_IE (0x00000008) +#define DOT11F_LAST_IE_TOO_LONG (0x00000010) +#define DOT11F_DUPLICATE_IE (0x00000020) +#define DOT11F_BAD_FIXED_VALUE (0x00000040) +#define DOT11F_INCOMPLETE_TLV (0x00000080) +#define DOT11F_INVALID_TLV_LENGTH (0x00000100) +#define DOT11F_SKIPPED_BAD_TLV (0x00000200) +#define DOT11F_UNKNOWN_TLVS (0x00000400) +#define DOT11F_LAST_TLV_TOO_LONG (0x00000800) +#define DOT11F_INTERNAL_ERROR (0x10000001) +#define DOT11F_MISSING_FIXED_FIELD (0x10000002) +#define DOT11F_BAD_INPUT_BUFFER (0x10000003) +#define DOT11F_BAD_OUTPUT_BUFFER (0x10000004) +#define DOT11F_BUFFER_OVERFLOW (0x10000005) +#define DOT11F_MANDATORY_TLV_MISSING (0x00001000) +#define DOT11F_FAILED(code) ((code) & 0x10000000) +#define DOT11F_SUCCEEDED(code) ((code) == 0) +#define DOT11F_WARNED(code) (!DOT11F_SUCCEEDED(code) && !DOT11F_FAILED(code)) + +/********************************************************************* + * Fixed Fields * + ********************************************************************/ + +typedef struct sDot11fFfAID { + uint16_t associd; +} tDot11fFfAID; + +#define DOT11F_FF_AID_LEN (2) + +void dot11f_unpack_ff_AID(tpAniSirGlobal, uint8_t *, tDot11fFfAID *); + +void dot11f_pack_ff_aid(tpAniSirGlobal, tDot11fFfAID *, uint8_t *); + +typedef struct sDot11fFfAction { + uint8_t action; +} tDot11fFfAction; + +#define DOT11F_FF_ACTION_LEN (1) + +void dot11f_unpack_ff_action(tpAniSirGlobal, uint8_t *, tDot11fFfAction *); + +void dot11f_pack_ff_action(tpAniSirGlobal, tDot11fFfAction *, uint8_t *); + +typedef struct sDot11fFfAuthAlgo { + uint16_t algo; +} tDot11fFfAuthAlgo; + +#define DOT11F_FF_AUTHALGO_LEN (2) + +void dot11f_unpack_ff_AuthAlgo(tpAniSirGlobal, uint8_t *, + tDot11fFfAuthAlgo *); + +void dot11f_pack_ff_auth_algo(tpAniSirGlobal, tDot11fFfAuthAlgo *, uint8_t *); + +typedef struct sDot11fFfAuthSeqNo { + uint16_t no; +} tDot11fFfAuthSeqNo; + +#define DOT11F_FF_AUTHSEQNO_LEN (2) + +void dot11f_unpack_ff_AuthSeqNo(tpAniSirGlobal, uint8_t *, + tDot11fFfAuthSeqNo *); + +void dot11f_pack_ff_auth_seq_no(tpAniSirGlobal, tDot11fFfAuthSeqNo *, + uint8_t *); + +typedef struct sDot11fFfBeaconInterval { + uint16_t interval; +} tDot11fFfBeaconInterval; + +#define DOT11F_FF_BEACONINTERVAL_LEN (2) + +void dot11f_unpack_ff_BeaconInterval(tpAniSirGlobal, uint8_t *, + tDot11fFfBeaconInterval *); + +void dot11f_pack_ff_beacon_interval(tpAniSirGlobal, tDot11fFfBeaconInterval *, + uint8_t *); + +typedef struct sDot11fFfCapabilities { + uint16_t ess:1; + uint16_t ibss:1; + uint16_t cfPollable:1; + uint16_t cfPollReq:1; + uint16_t privacy:1; + uint16_t shortPreamble:1; + uint16_t pbcc:1; + uint16_t channelAgility:1; + uint16_t spectrumMgt:1; + uint16_t qos:1; + uint16_t shortSlotTime:1; + uint16_t apsd:1; + uint16_t rrm:1; + uint16_t dsssOfdm:1; + uint16_t delayedBA:1; + uint16_t immediateBA:1; +} tDot11fFfCapabilities; + +#define DOT11F_FF_CAPABILITIES_LEN (2) + +void dot11f_unpack_ff_capabilities(tpAniSirGlobal, uint8_t *, + tDot11fFfCapabilities *); + +void dot11f_pack_ff_capabilities(tpAniSirGlobal, tDot11fFfCapabilities *, + uint8_t *); + +#define CAPABILITIES_ESS_OFFSET 0 +#define CAPABILITIES_ESS_WIDTH 1 +#define CAPABILITIES_IBSS_OFFSET 1 +#define CAPABILITIES_IBSS_WIDTH 1 +#define CAPABILITIES_CFPOLLABLE_OFFSET 2 +#define CAPABILITIES_CFPOLLABLE_WIDTH 1 +#define CAPABILITIES_CFPOLLREQ_OFFSET 3 +#define CAPABILITIES_CFPOLLREQ_WIDTH 1 +#define CAPABILITIES_PRIVACY_OFFSET 4 +#define CAPABILITIES_PRIVACY_WIDTH 1 +#define CAPABILITIES_SHORTPREAMBLE_OFFSET 5 +#define CAPABILITIES_SHORTPREAMBLE_WIDTH 1 +#define CAPABILITIES_PBCC_OFFSET 6 +#define CAPABILITIES_PBCC_WIDTH 1 +#define CAPABILITIES_CHANNELAGILITY_OFFSET 7 +#define CAPABILITIES_CHANNELAGILITY_WIDTH 1 +#define CAPABILITIES_SPECTRUMMGT_OFFSET 8 +#define CAPABILITIES_SPECTRUMMGT_WIDTH 1 +#define CAPABILITIES_QOS_OFFSET 9 +#define CAPABILITIES_QOS_WIDTH 1 +#define CAPABILITIES_SHORTSLOTTIME_OFFSET 10 +#define CAPABILITIES_SHORTSLOTTIME_WIDTH 1 +#define CAPABILITIES_APSD_OFFSET 11 +#define CAPABILITIES_APSD_WIDTH 1 +#define CAPABILITIES_RRM_OFFSET 12 +#define CAPABILITIES_RRM_WIDTH 1 +#define CAPABILITIES_DSSSOFDM_OFFSET 13 +#define CAPABILITIES_DSSSOFDM_WIDTH 1 +#define CAPABILITIES_DELAYEDBA_OFFSET 14 +#define CAPABILITIES_DELAYEDBA_WIDTH 1 +#define CAPABILITIES_IMMEDIATEBA_OFFSET 15 +#define CAPABILITIES_IMMEDIATEBA_WIDTH 1 + +typedef struct sDot11fFfCategory { + uint8_t category; +} tDot11fFfCategory; + +#define DOT11F_FF_CATEGORY_LEN (1) + +void dot11f_unpack_ff_category(tpAniSirGlobal, uint8_t *, + tDot11fFfCategory *); + +void dot11f_pack_ff_category(tpAniSirGlobal, tDot11fFfCategory *, uint8_t *); + +typedef struct sDot11fFfCurrentAPAddress { + uint8_t mac[6]; +} tDot11fFfCurrentAPAddress; + +#define DOT11F_FF_CURRENTAPADDRESS_LEN (6) + +void dot11f_unpack_ff_current_ap_address(tpAniSirGlobal, uint8_t *, + tDot11fFfCurrentAPAddress *); + +void dot11f_pack_ff_current_ap_address(tpAniSirGlobal, + tDot11fFfCurrentAPAddress *, + uint8_t *); + + +typedef struct sDot11fFfDialogToken { + uint8_t token; +} tDot11fFfDialogToken; + +#define DOT11F_FF_DIALOGTOKEN_LEN (1) + +void dot11f_unpack_ff_dialog_token(tpAniSirGlobal, uint8_t *, + tDot11fFfDialogToken *); + +void dot11f_pack_ff_dialog_token(tpAniSirGlobal, tDot11fFfDialogToken *, + uint8_t *); + +typedef struct sDot11fFfLinkMargin { + uint8_t linkMargin; +} tDot11fFfLinkMargin; + +#define DOT11F_FF_LINKMARGIN_LEN (1) + +void dot11f_unpack_ff_link_margin(tpAniSirGlobal, uint8_t *, + tDot11fFfLinkMargin *); + +void dot11f_pack_ff_link_margin(tpAniSirGlobal, tDot11fFfLinkMargin *, + uint8_t *); + +typedef struct sDot11fFfListenInterval { + uint16_t interval; +} tDot11fFfListenInterval; + +#define DOT11F_FF_LISTENINTERVAL_LEN (2) + +void dot11f_unpack_ff_ListenInterval(tpAniSirGlobal, uint8_t *, + tDot11fFfListenInterval *); + +void dot11f_pack_ff_listen_interval(tpAniSirGlobal, tDot11fFfListenInterval *, + uint8_t *); + +typedef struct sDot11fFfMaxTxPower { + uint8_t maxTxPower; +} tDot11fFfMaxTxPower; + +#define DOT11F_FF_MAXTXPOWER_LEN (1) + +void dot11f_unpack_ff_max_tx_power(tpAniSirGlobal, uint8_t *, + tDot11fFfMaxTxPower *); + +void dot11f_pack_ff_max_tx_power(tpAniSirGlobal, tDot11fFfMaxTxPower *, + uint8_t *); + +typedef struct sDot11fFfNumOfRepetitions { + uint16_t repetitions; +} tDot11fFfNumOfRepetitions; + +#define DOT11F_FF_NUMOFREPETITIONS_LEN (2) + +void dot11f_unpack_ff_num_of_repetitions(tpAniSirGlobal, uint8_t *, + tDot11fFfNumOfRepetitions *); + +void dot11f_pack_ff_num_of_repetitions(tpAniSirGlobal, + tDot11fFfNumOfRepetitions *, + uint8_t *); + + +typedef struct sDot11fFfOperatingMode { + uint8_t chanWidth:2; + uint8_t reserved:2; + uint8_t rxNSS:3; + uint8_t rxNSSType:1; +} tDot11fFfOperatingMode; + +#define DOT11F_FF_OPERATINGMODE_LEN (1) + +void dot11f_unpack_ff_operating_mode(tpAniSirGlobal, uint8_t *, + tDot11fFfOperatingMode *); + +void dot11f_pack_ff_operating_mode(tpAniSirGlobal, tDot11fFfOperatingMode *, + uint8_t *); + +#define OPERATINGMODE_CHANWIDTH_OFFSET 0 +#define OPERATINGMODE_CHANWIDTH_WIDTH 2 +#define OPERATINGMODE_RESERVED_OFFSET 2 +#define OPERATINGMODE_RESERVED_WIDTH 2 +#define OPERATINGMODE_RXNSS_OFFSET 4 +#define OPERATINGMODE_RXNSS_WIDTH 3 +#define OPERATINGMODE_RXNSSTYPE_OFFSET 7 +#define OPERATINGMODE_RXNSSTYPE_WIDTH 1 + +typedef struct sDot11fFfRCPI { + uint8_t rcpi; +} tDot11fFfRCPI; + +#define DOT11F_FF_RCPI_LEN (1) + +void dot11f_unpack_ff_rcpi(tpAniSirGlobal, uint8_t *, tDot11fFfRCPI *); + +void dot11f_pack_ff_rcpi(tpAniSirGlobal, tDot11fFfRCPI *, uint8_t *); + +typedef struct sDot11fFfRSNI { + uint8_t rsni; +} tDot11fFfRSNI; + +#define DOT11F_FF_RSNI_LEN (1) + +void dot11f_unpack_ff_rsni(tpAniSirGlobal, uint8_t *, tDot11fFfRSNI *); + +void dot11f_pack_ff_rsni(tpAniSirGlobal, tDot11fFfRSNI *, uint8_t *); + +typedef struct sDot11fFfReason { + uint16_t code; +} tDot11fFfReason; + +#define DOT11F_FF_REASON_LEN (2) + +void dot11f_unpack_ff_Reason(tpAniSirGlobal, uint8_t *, tDot11fFfReason *); + +void dot11f_pack_ff_reason(tpAniSirGlobal, tDot11fFfReason *, uint8_t *); + +typedef struct sDot11fFfRxAntennaId { + uint8_t antennaId; +} tDot11fFfRxAntennaId; + +#define DOT11F_FF_RXANTENNAID_LEN (1) + +void dot11f_unpack_ff_rx_antenna_id(tpAniSirGlobal, uint8_t *, + tDot11fFfRxAntennaId *); + +void dot11f_pack_ff_rx_antenna_id(tpAniSirGlobal, tDot11fFfRxAntennaId *, + uint8_t *); + +typedef struct sDot11fFfSMPowerModeSet { + uint8_t PowerSave_En:1; + uint8_t Mode:1; + uint8_t reserved:6; +} tDot11fFfSMPowerModeSet; + +#define DOT11F_FF_SMPOWERMODESET_LEN (1) + +void dot11f_unpack_ff_sm_power_mode_set(tpAniSirGlobal, uint8_t *, + tDot11fFfSMPowerModeSet *); + +void dot11f_pack_ff_sm_power_mode_set(tpAniSirGlobal, tDot11fFfSMPowerModeSet *, + uint8_t *); + +#define SMPOWERMODESET_POWERSAVE_EN_OFFSET 0 +#define SMPOWERMODESET_POWERSAVE_EN_WIDTH 1 +#define SMPOWERMODESET_MODE_OFFSET 1 +#define SMPOWERMODESET_MODE_WIDTH 1 +#define SMPOWERMODESET_RESERVED_OFFSET 2 +#define SMPOWERMODESET_RESERVED_WIDTH 6 + +typedef struct sDot11fFfStatus { + uint16_t status; +} tDot11fFfStatus; + +#define DOT11F_FF_STATUS_LEN (2) + +void dot11f_unpack_ff_Status(tpAniSirGlobal, uint8_t *, tDot11fFfStatus *); + +void dot11f_pack_ff_status(tpAniSirGlobal, tDot11fFfStatus *, uint8_t *); + +typedef struct sDot11fFfStatusCode { + uint8_t statusCode; +} tDot11fFfStatusCode; + +#define DOT11F_FF_STATUSCODE_LEN (1) + +void dot11f_unpack_ff_status_code(tpAniSirGlobal, uint8_t *, + tDot11fFfStatusCode *); + +void dot11f_pack_ff_status_code(tpAniSirGlobal, tDot11fFfStatusCode *, + uint8_t *); + +typedef struct sDot11fFfTPCEleID { + uint8_t TPCId; +} tDot11fFfTPCEleID; + +#define DOT11F_FF_TPCELEID_LEN (1) + +void dot11f_unpack_ff_tpc_ele_id(tpAniSirGlobal, uint8_t *, + tDot11fFfTPCEleID *); + +void dot11f_pack_ff_tpc_ele_id(tpAniSirGlobal, tDot11fFfTPCEleID *, uint8_t *); + +typedef struct sDot11fFfTPCEleLen { + uint8_t TPCLen; +} tDot11fFfTPCEleLen; + +#define DOT11F_FF_TPCELELEN_LEN (1) + +void dot11f_unpack_ff_tpc_ele_len(tpAniSirGlobal, uint8_t *, + tDot11fFfTPCEleLen *); + +void dot11f_pack_ff_tpc_ele_len(tpAniSirGlobal, tDot11fFfTPCEleLen *, + uint8_t *); + +typedef struct sDot11fFfTSInfo { + uint32_t traffic_type:1; + uint32_t tsid:4; + uint32_t direction:2; + uint32_t access_policy:2; + uint32_t aggregation:1; + uint32_t psb:1; + uint32_t user_priority:3; + uint32_t tsinfo_ack_pol:2; + uint32_t schedule:1; + uint32_t unused:15; +} tDot11fFfTSInfo; + +#define DOT11F_FF_TSINFO_LEN (3) + +void dot11f_unpack_ff_ts_info(tpAniSirGlobal, uint8_t *, tDot11fFfTSInfo *); + +void dot11f_pack_ff_ts_info(tpAniSirGlobal, tDot11fFfTSInfo *, uint8_t *); + +#define TSINFO_TRAFFIC_TYPE_OFFSET 0 +#define TSINFO_TRAFFIC_TYPE_WIDTH 1 +#define TSINFO_TSID_OFFSET 1 +#define TSINFO_TSID_WIDTH 4 +#define TSINFO_DIRECTION_OFFSET 5 +#define TSINFO_DIRECTION_WIDTH 2 +#define TSINFO_ACCESS_POLICY_OFFSET 7 +#define TSINFO_ACCESS_POLICY_WIDTH 2 +#define TSINFO_AGGREGATION_OFFSET 9 +#define TSINFO_AGGREGATION_WIDTH 1 +#define TSINFO_PSB_OFFSET 10 +#define TSINFO_PSB_WIDTH 1 +#define TSINFO_USER_PRIORITY_OFFSET 11 +#define TSINFO_USER_PRIORITY_WIDTH 3 +#define TSINFO_TSINFO_ACK_POL_OFFSET 14 +#define TSINFO_TSINFO_ACK_POL_WIDTH 2 +#define TSINFO_SCHEDULE_OFFSET 16 +#define TSINFO_SCHEDULE_WIDTH 1 +#define TSINFO_UNUSED_OFFSET 17 +#define TSINFO_UNUSED_WIDTH 15 + +typedef struct sDot11fFfTimeStamp { + tDOT11F_U64 timestamp; +} tDot11fFfTimeStamp; + +#define DOT11F_FF_TIMESTAMP_LEN (8) + +void dot11f_unpack_ff_time_stamp(tpAniSirGlobal, uint8_t *, + tDot11fFfTimeStamp *); + +void dot11f_pack_ff_time_stamp(tpAniSirGlobal, tDot11fFfTimeStamp *, + uint8_t *); + +typedef struct sDot11fFfTransactionId { + uint8_t transId[2]; +} tDot11fFfTransactionId; + +#define DOT11F_FF_TRANSACTIONID_LEN (2) + +void dot11f_unpack_ff_transaction_id(tpAniSirGlobal, uint8_t *, + tDot11fFfTransactionId *); + +void dot11f_pack_ff_transaction_id(tpAniSirGlobal, tDot11fFfTransactionId *, + uint8_t *); + +typedef struct sDot11fFfTxAntennaId { + uint8_t antennaId; +} tDot11fFfTxAntennaId; + +#define DOT11F_FF_TXANTENNAID_LEN (1) + +void dot11f_unpack_ff_tx_antenna_id(tpAniSirGlobal, uint8_t *, + tDot11fFfTxAntennaId *); + +void dot11f_pack_ff_tx_antenna_id(tpAniSirGlobal, tDot11fFfTxAntennaId *, + uint8_t *); + +typedef struct sDot11fFfTxPower { + uint8_t txPower; +} tDot11fFfTxPower; + +#define DOT11F_FF_TXPOWER_LEN (1) + +void dot11f_unpack_ff_tx_power(tpAniSirGlobal, uint8_t *, + tDot11fFfTxPower *); + +void dot11f_pack_ff_tx_power(tpAniSirGlobal, tDot11fFfTxPower *, uint8_t *); + +typedef struct sDot11fFfVhtMembershipStatusArray { + uint8_t membershipStatusArray[8]; +} tDot11fFfVhtMembershipStatusArray; + +#define DOT11F_FF_VHTMEMBERSHIPSTATUSARRAY_LEN (8) + +void dot11f_unpack_ff_vht_membership_status_array(tpAniSirGlobal, uint8_t *, + tDot11fFfVhtMembershipStatusArray *); + +void dot11f_pack_ff_vht_membership_status_array(tpAniSirGlobal, + tDot11fFfVhtMembershipStatusArray *, + uint8_t *); + + +typedef struct sDot11fFfVhtUserPositionArray { + uint8_t userPositionArray[16]; +} tDot11fFfVhtUserPositionArray; + +#define DOT11F_FF_VHTUSERPOSITIONARRAY_LEN (16) + +void dot11f_unpack_ff_vht_user_position_array(tpAniSirGlobal, uint8_t *, + tDot11fFfVhtUserPositionArray *); + +void dot11f_pack_ff_vht_user_position_array(tpAniSirGlobal, + tDot11fFfVhtUserPositionArray *, + uint8_t *); + + +typedef struct sDot11fFfext_chan_switch_ann_action { + uint32_t switch_mode:8; + uint32_t op_class:8; + uint32_t new_channel:8; + uint32_t switch_count:8; +} tDot11fFfext_chan_switch_ann_action; + +#define DOT11F_FF_EXT_CHAN_SWITCH_ANN_ACTION_LEN (4) + +void dot11f_unpack_ff_ext_chan_switch_ann_action(tpAniSirGlobal, uint8_t *, + tDot11fFfext_chan_switch_ann_action *); + +void dot11f_pack_ff_ext_chan_switch_ann_action(tpAniSirGlobal, + tDot11fFfext_chan_switch_ann_action *, + uint8_t *); + + +#define EXT_CHAN_SWITCH_ANN_ACTION_SWITCH_MODE_OFFSET 0 +#define EXT_CHAN_SWITCH_ANN_ACTION_SWITCH_MODE_WIDTH 8 +#define EXT_CHAN_SWITCH_ANN_ACTION_OP_CLASS_OFFSET 8 +#define EXT_CHAN_SWITCH_ANN_ACTION_OP_CLASS_WIDTH 8 +#define EXT_CHAN_SWITCH_ANN_ACTION_NEW_CHANNEL_OFFSET 16 +#define EXT_CHAN_SWITCH_ANN_ACTION_NEW_CHANNEL_WIDTH 8 +#define EXT_CHAN_SWITCH_ANN_ACTION_SWITCH_COUNT_OFFSET 24 +#define EXT_CHAN_SWITCH_ANN_ACTION_SWITCH_COUNT_WIDTH 8 + +typedef struct sDot11fFfp2p_action_oui { + uint8_t oui_data[4]; +} tDot11fFfp2p_action_oui; + +#define DOT11F_FF_P2P_ACTION_OUI_LEN (4) + +void dot11f_unpack_ff_p2p_action_oui(tpAniSirGlobal, uint8_t *, + tDot11fFfp2p_action_oui *); + +void dot11f_pack_ff_p2p_action_oui(tpAniSirGlobal, tDot11fFfp2p_action_oui *, + uint8_t *); + +typedef struct sDot11fFfp2p_action_subtype { + uint8_t subtype; +} tDot11fFfp2p_action_subtype; + +#define DOT11F_FF_P2P_ACTION_SUBTYPE_LEN (1) + +void dot11f_unpack_ff_p2p_action_subtype(tpAniSirGlobal, uint8_t *, + tDot11fFfp2p_action_subtype *); + +void dot11f_pack_ff_p2p_action_subtype(tpAniSirGlobal, + tDot11fFfp2p_action_subtype *, + uint8_t *); + + +/********************************************************************* + * TLVs * + ********************************************************************/ + + +/* ID 1 (0x0001) */ +typedef struct sDot11fTLVAuthorizedMACs { + uint8_t present; + uint8_t mac[6]; +} tDot11fTLVAuthorizedMACs; + +#define DOT11F_TLV_AUTHORIZEDMACS (1) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_AUTHORIZEDMACS_MIN_LEN (6) + +#define DOT11F_TLV_AUTHORIZEDMACS_MAX_LEN (6) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_authorized_ma_cs( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVAuthorizedMACs*); + +uint32_t dot11f_pack_tlv_authorized_ma_cs( + tpAniSirGlobal, + tDot11fTLVAuthorizedMACs *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_AuthorizedMACs( + tpAniSirGlobal, + tDot11fTLVAuthorizedMACs *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* ID 3 (0x0003) */ +typedef struct sDot11fTLVRequestToEnroll { + uint8_t present; + uint8_t req; +} tDot11fTLVRequestToEnroll; + +#define DOT11F_TLV_REQUESTTOENROLL (3) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_REQUESTTOENROLL_MIN_LEN (1) + +#define DOT11F_TLV_REQUESTTOENROLL_MAX_LEN (1) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_RequestToEnroll( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVRequestToEnroll*); + +uint32_t dot11f_pack_tlv_request_to_enroll( + tpAniSirGlobal, + tDot11fTLVRequestToEnroll *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_RequestToEnroll( + tpAniSirGlobal, + tDot11fTLVRequestToEnroll *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* ID 0 (0x0000) */ +typedef struct sDot11fTLVVersion2 { + uint8_t present; + uint8_t minor:4; + uint8_t major:4; +} tDot11fTLVVersion2; + +#define DOT11F_TLV_VERSION2 (0) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_VERSION2_MIN_LEN (1) + +#define DOT11F_TLV_VERSION2_MAX_LEN (1) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_version2( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVVersion2*); + +uint32_t dot11f_pack_tlv_version2( + tpAniSirGlobal, + tDot11fTLVVersion2 *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_Version2( + tpAniSirGlobal, + tDot11fTLVVersion2 *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* ID 4183 (0x1057) */ +typedef struct sDot11fTLVAPSetupLocked { + uint8_t present; + uint8_t fLocked; +} tDot11fTLVAPSetupLocked; + +#define DOT11F_TLV_APSETUPLOCKED (4183) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_APSETUPLOCKED_MIN_LEN (3) + +#define DOT11F_TLV_APSETUPLOCKED_MAX_LEN (3) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_APSetupLocked( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVAPSetupLocked*); + +uint32_t dot11f_pack_tlv_ap_setup_locked( + tpAniSirGlobal, + tDot11fTLVAPSetupLocked *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_APSetupLocked( + tpAniSirGlobal, + tDot11fTLVAPSetupLocked *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* ID 4098 (0x1002) */ +typedef struct sDot11fTLVAssociationState { + uint8_t present; + uint16_t state; +} tDot11fTLVAssociationState; + +#define DOT11F_TLV_ASSOCIATIONSTATE (4098) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_ASSOCIATIONSTATE_MIN_LEN (4) + +#define DOT11F_TLV_ASSOCIATIONSTATE_MAX_LEN (4) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_AssociationState( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVAssociationState*); + +uint32_t dot11f_pack_tlv_association_state( + tpAniSirGlobal, + tDot11fTLVAssociationState *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_AssociationState( + tpAniSirGlobal, + tDot11fTLVAssociationState *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* ID 4104 (0x1008) */ +typedef struct sDot11fTLVConfigMethods { + uint8_t present; + uint16_t methods; +} tDot11fTLVConfigMethods; + +#define DOT11F_TLV_CONFIGMETHODS (4104) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_CONFIGMETHODS_MIN_LEN (4) + +#define DOT11F_TLV_CONFIGMETHODS_MAX_LEN (4) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_ConfigMethods( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVConfigMethods*); + +uint32_t dot11f_pack_tlv_config_methods( + tpAniSirGlobal, + tDot11fTLVConfigMethods *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_ConfigMethods( + tpAniSirGlobal, + tDot11fTLVConfigMethods *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* ID 4105 (0x1009) */ +typedef struct sDot11fTLVConfigurationError { + uint8_t present; + uint16_t error; +} tDot11fTLVConfigurationError; + +#define DOT11F_TLV_CONFIGURATIONERROR (4105) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_CONFIGURATIONERROR_MIN_LEN (4) + +#define DOT11F_TLV_CONFIGURATIONERROR_MAX_LEN (4) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_ConfigurationError( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVConfigurationError*); + +uint32_t dot11f_pack_tlv_configuration_error( + tpAniSirGlobal, + tDot11fTLVConfigurationError *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_ConfigurationError( + tpAniSirGlobal, + tDot11fTLVConfigurationError *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* ID 4113 (0x1011) */ +typedef struct sDot11fTLVDeviceName { + uint8_t present; + uint8_t num_text; + uint8_t text[32]; +} tDot11fTLVDeviceName; + +#define DOT11F_TLV_DEVICENAME (4113) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_DEVICENAME_MIN_LEN (2) + +#define DOT11F_TLV_DEVICENAME_MAX_LEN (34) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_device_name( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVDeviceName*); + +uint32_t dot11f_pack_tlv_device_name( + tpAniSirGlobal, + tDot11fTLVDeviceName *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_DeviceName( + tpAniSirGlobal, + tDot11fTLVDeviceName *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* ID 4114 (0x1012) */ +typedef struct sDot11fTLVDevicePasswordID { + uint8_t present; + uint16_t id; +} tDot11fTLVDevicePasswordID; + +#define DOT11F_TLV_DEVICEPASSWORDID (4114) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_DEVICEPASSWORDID_MIN_LEN (4) + +#define DOT11F_TLV_DEVICEPASSWORDID_MAX_LEN (4) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_DevicePasswordID( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVDevicePasswordID*); + +uint32_t dot11f_pack_tlv_device_password_id( + tpAniSirGlobal, + tDot11fTLVDevicePasswordID *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_DevicePasswordID( + tpAniSirGlobal, + tDot11fTLVDevicePasswordID *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* ID 8 (0x0008) */ +typedef struct sDot11fTLVExtendedListenTiming { + uint8_t present; + uint16_t availibilityPeriod; + uint16_t availibilityInterval; +} tDot11fTLVExtendedListenTiming; + +#define DOT11F_TLV_EXTENDEDLISTENTIMING (8) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_EXTENDEDLISTENTIMING_MIN_LEN (5) + +#define DOT11F_TLV_EXTENDEDLISTENTIMING_MAX_LEN (5) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_extended_listen_timing( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVExtendedListenTiming*); + +uint32_t dot11f_pack_tlv_extended_listen_timing( + tpAniSirGlobal, + tDot11fTLVExtendedListenTiming *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_ExtendedListenTiming( + tpAniSirGlobal, + tDot11fTLVExtendedListenTiming *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* ID 6 (0x0006) */ +typedef struct sDot11fTLVListenChannel { + uint8_t present; + uint8_t countryString[3]; + uint8_t regulatoryClass; + uint8_t channel; +} tDot11fTLVListenChannel; + +#define DOT11F_TLV_LISTENCHANNEL (6) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_LISTENCHANNEL_MIN_LEN (6) + +#define DOT11F_TLV_LISTENCHANNEL_MAX_LEN (6) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_listen_channel( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVListenChannel*); + +uint32_t dot11f_pack_tlv_listen_channel( + tpAniSirGlobal, + tDot11fTLVListenChannel *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_ListenChannel( + tpAniSirGlobal, + tDot11fTLVListenChannel *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* ID 4129 (0x1021) */ +typedef struct sDot11fTLVManufacturer { + uint8_t present; + uint8_t num_name; + uint8_t name[64]; +} tDot11fTLVManufacturer; + +#define DOT11F_TLV_MANUFACTURER (4129) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_MANUFACTURER_MIN_LEN (2) + +#define DOT11F_TLV_MANUFACTURER_MAX_LEN (66) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_manufacturer( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVManufacturer*); + +uint32_t dot11f_pack_tlv_manufacturer( + tpAniSirGlobal, + tDot11fTLVManufacturer *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_Manufacturer( + tpAniSirGlobal, + tDot11fTLVManufacturer *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* ID 1 (0x0001) */ +typedef struct sDot11fTLVMinorReasonCode { + uint8_t present; + uint8_t minorReasonCode; +} tDot11fTLVMinorReasonCode; + +#define DOT11F_TLV_MINORREASONCODE (1) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_MINORREASONCODE_MIN_LEN (2) + +#define DOT11F_TLV_MINORREASONCODE_MAX_LEN (2) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_MinorReasonCode( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVMinorReasonCode*); + +uint32_t dot11f_pack_tlv_minor_reason_code( + tpAniSirGlobal, + tDot11fTLVMinorReasonCode *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_MinorReasonCode( + tpAniSirGlobal, + tDot11fTLVMinorReasonCode *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* ID 4131 (0x1023) */ +typedef struct sDot11fTLVModelName { + uint8_t present; + uint8_t num_text; + uint8_t text[32]; +} tDot11fTLVModelName; + +#define DOT11F_TLV_MODELNAME (4131) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_MODELNAME_MIN_LEN (2) + +#define DOT11F_TLV_MODELNAME_MAX_LEN (34) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_model_name( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVModelName*); + +uint32_t dot11f_pack_tlv_model_name( + tpAniSirGlobal, + tDot11fTLVModelName *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_ModelName( + tpAniSirGlobal, + tDot11fTLVModelName *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* ID 4132 (0x1024) */ +typedef struct sDot11fTLVModelNumber { + uint8_t present; + uint8_t num_text; + uint8_t text[32]; +} tDot11fTLVModelNumber; + +#define DOT11F_TLV_MODELNUMBER (4132) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_MODELNUMBER_MIN_LEN (2) + +#define DOT11F_TLV_MODELNUMBER_MAX_LEN (34) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_model_number( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVModelNumber*); + +uint32_t dot11f_pack_tlv_model_number( + tpAniSirGlobal, + tDot11fTLVModelNumber *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_ModelNumber( + tpAniSirGlobal, + tDot11fTLVModelNumber *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* ID 12 (0x000c) */ +typedef struct sDot11fTLVNoticeOfAbsence { + uint8_t present; + uint8_t index; + uint8_t CTSWindowOppPS; + uint8_t num_NoADesc; + uint8_t NoADesc[36]; +} tDot11fTLVNoticeOfAbsence; + +#define DOT11F_TLV_NOTICEOFABSENCE (12) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_NOTICEOFABSENCE_MIN_LEN (3) + +#define DOT11F_TLV_NOTICEOFABSENCE_MAX_LEN (39) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_notice_of_absence( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVNoticeOfAbsence*); + +uint32_t dot11f_pack_tlv_notice_of_absence( + tpAniSirGlobal, + tDot11fTLVNoticeOfAbsence *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_NoticeOfAbsence( + tpAniSirGlobal, + tDot11fTLVNoticeOfAbsence *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* ID 17 (0x0011) */ +typedef struct sDot11fTLVOperatingChannel { + uint8_t present; + uint8_t countryString[3]; + uint8_t regulatoryClass; + uint8_t channel; +} tDot11fTLVOperatingChannel; + +#define DOT11F_TLV_OPERATINGCHANNEL (17) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_OPERATINGCHANNEL_MIN_LEN (6) + +#define DOT11F_TLV_OPERATINGCHANNEL_MAX_LEN (6) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_operating_channel( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVOperatingChannel*); + +uint32_t dot11f_pack_tlv_operating_channel( + tpAniSirGlobal, + tDot11fTLVOperatingChannel *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_OperatingChannel( + tpAniSirGlobal, + tDot11fTLVOperatingChannel *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* ID 2 (0x0002) */ +typedef struct sDot11fTLVP2PCapability { + uint8_t present; + uint8_t deviceCapability; + uint8_t groupCapability; +} tDot11fTLVP2PCapability; + +#define DOT11F_TLV_P2PCAPABILITY (2) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_P2PCAPABILITY_MIN_LEN (3) + +#define DOT11F_TLV_P2PCAPABILITY_MAX_LEN (3) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_p2_p_capability( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVP2PCapability*); + +uint32_t dot11f_pack_tlv_p2_p_capability( + tpAniSirGlobal, + tDot11fTLVP2PCapability *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_P2PCapability( + tpAniSirGlobal, + tDot11fTLVP2PCapability *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* ID 3 (0x0003) */ +typedef struct sDot11fTLVP2PDeviceId { + uint8_t present; + uint8_t P2PDeviceAddress[6]; +} tDot11fTLVP2PDeviceId; + +#define DOT11F_TLV_P2PDEVICEID (3) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_P2PDEVICEID_MIN_LEN (7) + +#define DOT11F_TLV_P2PDEVICEID_MAX_LEN (7) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_p2_p_device_id( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVP2PDeviceId*); + +uint32_t dot11f_pack_tlv_p2_p_device_id( + tpAniSirGlobal, + tDot11fTLVP2PDeviceId *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_P2PDeviceId( + tpAniSirGlobal, + tDot11fTLVP2PDeviceId *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* ID 13 (0x000d) */ +typedef struct sDot11fTLVP2PDeviceInfo { + uint8_t present; + uint8_t P2PDeviceAddress[6]; + uint16_t configMethod; + uint8_t primaryDeviceType[8]; + tDot11fTLVDeviceName DeviceName; +} tDot11fTLVP2PDeviceInfo; + +#define DOT11F_TLV_P2PDEVICEINFO (13) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_P2PDEVICEINFO_MIN_LEN (17) + +#define DOT11F_TLV_P2PDEVICEINFO_MAX_LEN (53) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_p2_p_device_info( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVP2PDeviceInfo*); + +uint32_t dot11f_pack_tlv_p2_p_device_info( + tpAniSirGlobal, + tDot11fTLVP2PDeviceInfo *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_P2PDeviceInfo( + tpAniSirGlobal, + tDot11fTLVP2PDeviceInfo *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* ID 14 (0x000e) */ +typedef struct sDot11fTLVP2PGroupInfo { + uint8_t present; + uint8_t num_P2PClientInfoDesc; + uint8_t P2PClientInfoDesc[1024]; +} tDot11fTLVP2PGroupInfo; + +#define DOT11F_TLV_P2PGROUPINFO (14) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_P2PGROUPINFO_MIN_LEN (1) + +#define DOT11F_TLV_P2PGROUPINFO_MAX_LEN (1025) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_p2_p_group_info( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVP2PGroupInfo*); + +uint32_t dot11f_pack_tlv_p2_p_group_info( + tpAniSirGlobal, + tDot11fTLVP2PGroupInfo *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_P2PGroupInfo( + tpAniSirGlobal, + tDot11fTLVP2PGroupInfo *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* ID 0 (0x0000) */ +typedef struct sDot11fTLVP2PStatus { + uint8_t present; + uint8_t status; +} tDot11fTLVP2PStatus; + +#define DOT11F_TLV_P2PSTATUS (0) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_P2PSTATUS_MIN_LEN (2) + +#define DOT11F_TLV_P2PSTATUS_MAX_LEN (2) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_P2PStatus( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVP2PStatus*); + +uint32_t dot11f_pack_tlv_p2_p_status( + tpAniSirGlobal, + tDot11fTLVP2PStatus *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_P2PStatus( + tpAniSirGlobal, + tDot11fTLVP2PStatus *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* ID 4180 (0x1054) */ +typedef struct sDot11fTLVPrimaryDeviceType { + uint8_t present; + uint16_t primary_category; + uint8_t oui[4]; + uint16_t sub_category; +} tDot11fTLVPrimaryDeviceType; + +#define DOT11F_TLV_PRIMARYDEVICETYPE (4180) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_PRIMARYDEVICETYPE_MIN_LEN (10) + +#define DOT11F_TLV_PRIMARYDEVICETYPE_MAX_LEN (10) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_primary_device_type( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVPrimaryDeviceType*); + +uint32_t dot11f_pack_tlv_primary_device_type( + tpAniSirGlobal, + tDot11fTLVPrimaryDeviceType *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_PrimaryDeviceType( + tpAniSirGlobal, + tDot11fTLVPrimaryDeviceType *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* ID 4156 (0x103c) */ +typedef struct sDot11fTLVRFBands { + uint8_t present; + uint8_t bands; +} tDot11fTLVRFBands; + +#define DOT11F_TLV_RFBANDS (4156) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_RFBANDS_MIN_LEN (3) + +#define DOT11F_TLV_RFBANDS_MAX_LEN (3) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_RFBands( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVRFBands*); + +uint32_t dot11f_pack_tlv_rf_bands( + tpAniSirGlobal, + tDot11fTLVRFBands *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_RFBands( + tpAniSirGlobal, + tDot11fTLVRFBands *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* ID 4202 (0x106a) */ +typedef struct sDot11fTLVRequestDeviceType { + uint8_t present; + uint16_t primary_category; + uint8_t oui[4]; + uint16_t sub_category; +} tDot11fTLVRequestDeviceType; + +#define DOT11F_TLV_REQUESTDEVICETYPE (4202) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_REQUESTDEVICETYPE_MIN_LEN (10) + +#define DOT11F_TLV_REQUESTDEVICETYPE_MAX_LEN (10) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_request_device_type( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVRequestDeviceType*); + +uint32_t dot11f_pack_tlv_request_device_type( + tpAniSirGlobal, + tDot11fTLVRequestDeviceType *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_RequestDeviceType( + tpAniSirGlobal, + tDot11fTLVRequestDeviceType *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* ID 4154 (0x103a) */ +typedef struct sDot11fTLVRequestType { + uint8_t present; + uint8_t reqType; +} tDot11fTLVRequestType; + +#define DOT11F_TLV_REQUESTTYPE (4154) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_REQUESTTYPE_MIN_LEN (3) + +#define DOT11F_TLV_REQUESTTYPE_MAX_LEN (3) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_RequestType( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVRequestType*); + +uint32_t dot11f_pack_tlv_request_type( + tpAniSirGlobal, + tDot11fTLVRequestType *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_RequestType( + tpAniSirGlobal, + tDot11fTLVRequestType *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* ID 4155 (0x103b) */ +typedef struct sDot11fTLVResponseType { + uint8_t present; + uint8_t resType; +} tDot11fTLVResponseType; + +#define DOT11F_TLV_RESPONSETYPE (4155) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_RESPONSETYPE_MIN_LEN (3) + +#define DOT11F_TLV_RESPONSETYPE_MAX_LEN (3) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_ResponseType( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVResponseType*); + +uint32_t dot11f_pack_tlv_response_type( + tpAniSirGlobal, + tDot11fTLVResponseType *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_ResponseType( + tpAniSirGlobal, + tDot11fTLVResponseType *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* ID 4161 (0x1041) */ +typedef struct sDot11fTLVSelectedRegistrar { + uint8_t present; + uint8_t selected; +} tDot11fTLVSelectedRegistrar; + +#define DOT11F_TLV_SELECTEDREGISTRAR (4161) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_SELECTEDREGISTRAR_MIN_LEN (3) + +#define DOT11F_TLV_SELECTEDREGISTRAR_MAX_LEN (3) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_SelectedRegistrar( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVSelectedRegistrar*); + +uint32_t dot11f_pack_tlv_selected_registrar( + tpAniSirGlobal, + tDot11fTLVSelectedRegistrar *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_SelectedRegistrar( + tpAniSirGlobal, + tDot11fTLVSelectedRegistrar *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* ID 4179 (0x1053) */ +typedef struct sDot11fTLVSelectedRegistrarConfigMethods { + uint8_t present; + uint16_t methods; +} tDot11fTLVSelectedRegistrarConfigMethods; + +#define DOT11F_TLV_SELECTEDREGISTRARCONFIGMETHODS (4179) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_SELECTEDREGISTRARCONFIGMETHODS_MIN_LEN (4) + +#define DOT11F_TLV_SELECTEDREGISTRARCONFIGMETHODS_MAX_LEN (4) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_SelectedRegistrarConfigMethods( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVSelectedRegistrarConfigMethods*); + +uint32_t dot11f_pack_tlv_selected_registrar_config_methods( + tpAniSirGlobal, + tDot11fTLVSelectedRegistrarConfigMethods *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_SelectedRegistrarConfigMethods( + tpAniSirGlobal, + tDot11fTLVSelectedRegistrarConfigMethods *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* ID 4162 (0x1042) */ +typedef struct sDot11fTLVSerialNumber { + uint8_t present; + uint8_t num_text; + uint8_t text[32]; +} tDot11fTLVSerialNumber; + +#define DOT11F_TLV_SERIALNUMBER (4162) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_SERIALNUMBER_MIN_LEN (2) + +#define DOT11F_TLV_SERIALNUMBER_MAX_LEN (34) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_serial_number( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVSerialNumber*); + +uint32_t dot11f_pack_tlv_serial_number( + tpAniSirGlobal, + tDot11fTLVSerialNumber *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_SerialNumber( + tpAniSirGlobal, + tDot11fTLVSerialNumber *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* ID 4167 (0x1047) */ +typedef struct sDot11fTLVUUID_E { + uint8_t present; + uint8_t uuid[16]; +} tDot11fTLVUUID_E; + +#define DOT11F_TLV_UUID_E (4167) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_UUID_E_MIN_LEN (18) + +#define DOT11F_TLV_UUID_E_MAX_LEN (18) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_uuid_e( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVUUID_E*); + +uint32_t dot11f_pack_tlv_uuid_e( + tpAniSirGlobal, + tDot11fTLVUUID_E *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_UUID_E( + tpAniSirGlobal, + tDot11fTLVUUID_E *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* ID 4168 (0x1048) */ +typedef struct sDot11fTLVUUID_R { + uint8_t present; + uint8_t uuid[16]; +} tDot11fTLVUUID_R; + +#define DOT11F_TLV_UUID_R (4168) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_UUID_R_MIN_LEN (18) + +#define DOT11F_TLV_UUID_R_MAX_LEN (18) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_uuid_r( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVUUID_R*); + +uint32_t dot11f_pack_tlv_uuid_r( + tpAniSirGlobal, + tDot11fTLVUUID_R *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_UUID_R( + tpAniSirGlobal, + tDot11fTLVUUID_R *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* ID 4169 (0x1049) */ +typedef struct sDot11fTLVVendorExtension { + uint8_t present; + uint8_t vendorId[3]; + tDot11fTLVVersion2 Version2; + tDot11fTLVAuthorizedMACs AuthorizedMACs; + tDot11fTLVRequestToEnroll RequestToEnroll; +} tDot11fTLVVendorExtension; + +#define DOT11F_TLV_VENDOREXTENSION (4169) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_VENDOREXTENSION_MIN_LEN (5) + +#define DOT11F_TLV_VENDOREXTENSION_MAX_LEN (19) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_vendor_extension( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVVendorExtension*); + +uint32_t dot11f_pack_tlv_vendor_extension( + tpAniSirGlobal, + tDot11fTLVVendorExtension *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_VendorExtension( + tpAniSirGlobal, + tDot11fTLVVendorExtension *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* ID 4170 (0x104a) */ +typedef struct sDot11fTLVVersion { + uint8_t present; + uint8_t minor:4; + uint8_t major:4; +} tDot11fTLVVersion; + +#define DOT11F_TLV_VERSION (4170) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_VERSION_MIN_LEN (3) + +#define DOT11F_TLV_VERSION_MAX_LEN (3) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_version( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVVersion*); + +uint32_t dot11f_pack_tlv_version( + tpAniSirGlobal, + tDot11fTLVVersion *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_Version( + tpAniSirGlobal, + tDot11fTLVVersion *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* ID 4164 (0x1044) */ +typedef struct sDot11fTLVWPSState { + uint8_t present; + uint8_t state; +} tDot11fTLVWPSState; + +#define DOT11F_TLV_WPSSTATE (4164) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_WPSSTATE_MIN_LEN (3) + +#define DOT11F_TLV_WPSSTATE_MAX_LEN (3) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_WPSState( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVWPSState*); + +uint32_t dot11f_pack_tlv_wps_state( + tpAniSirGlobal, + tDot11fTLVWPSState *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_WPSState( + tpAniSirGlobal, + tDot11fTLVWPSState *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* ID 16 (0x0010) */ +typedef struct sDot11fTLVP2PInterface { + uint8_t present; + uint8_t P2PDeviceAddress[6]; +} tDot11fTLVP2PInterface; + +#define DOT11F_TLV_P2PINTERFACE (16) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_P2PINTERFACE_MIN_LEN (7) + +#define DOT11F_TLV_P2PINTERFACE_MAX_LEN (7) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_p2_p_interface( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVP2PInterface*); + +uint32_t dot11f_pack_tlv_p2_p_interface( + tpAniSirGlobal, + tDot11fTLVP2PInterface *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_P2PInterface( + tpAniSirGlobal, + tDot11fTLVP2PInterface *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* ID 10 (0x000a) */ +typedef struct sDot11fTLVP2PManageability { + uint8_t present; + uint8_t manageability; +} tDot11fTLVP2PManageability; + +#define DOT11F_TLV_P2PMANAGEABILITY (10) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_P2PMANAGEABILITY_MIN_LEN (2) + +#define DOT11F_TLV_P2PMANAGEABILITY_MAX_LEN (2) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_P2PManageability( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVP2PManageability*); + +uint32_t dot11f_pack_tlv_p2_p_manageability( + tpAniSirGlobal, + tDot11fTLVP2PManageability *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_P2PManageability( + tpAniSirGlobal, + tDot11fTLVP2PManageability *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ +/********************************************************************* + * Information Elements * + ********************************************************************/ + + +/* EID 2 (0x02) */ +typedef struct sDot11fIEGTK { + uint8_t present; + uint16_t keyId:2; + uint16_t reserved:14; + uint8_t keyLength; + uint8_t RSC[8]; + uint8_t num_key; + uint8_t key[32]; +} tDot11fIEGTK; + +#define DOT11F_EID_GTK (2) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_GTK_MIN_LEN (16) + +#define DOT11F_IE_GTK_MAX_LEN (43) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_gtk( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEGTK*); + +uint32_t dot11f_pack_ie_gtk( + tpAniSirGlobal, + tDot11fIEGTK *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_GTK( + tpAniSirGlobal, + tDot11fIEGTK *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 4 (0x04) */ +typedef struct sDot11fIEIGTK { + uint8_t present; + uint8_t keyID[2]; + uint8_t IPN[6]; + uint8_t keyLength; + uint8_t key[24]; +} tDot11fIEIGTK; + +#define DOT11F_EID_IGTK (4) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_IGTK_MIN_LEN (33) + +#define DOT11F_IE_IGTK_MAX_LEN (33) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_igtk( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEIGTK*); + +uint32_t dot11f_pack_ie_igtk( + tpAniSirGlobal, + tDot11fIEIGTK *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_IGTK( + tpAniSirGlobal, + tDot11fIEIGTK *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 3 (0x03) */ +typedef struct sDot11fIER0KH_ID { + uint8_t present; + uint8_t num_PMK_R0_ID; + uint8_t PMK_R0_ID[48]; +} tDot11fIER0KH_ID; + +#define DOT11F_EID_R0KH_ID (3) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_R0KH_ID_MIN_LEN (1) + +#define DOT11F_IE_R0KH_ID_MAX_LEN (48) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_r0_kh_id( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIER0KH_ID*); + +uint32_t dot11f_pack_ie_r0_kh_id( + tpAniSirGlobal, + tDot11fIER0KH_ID *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_R0KH_ID( + tpAniSirGlobal, + tDot11fIER0KH_ID *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 1 (0x01) */ +typedef struct sDot11fIER1KH_ID { + uint8_t present; + uint8_t PMK_R1_ID[6]; +} tDot11fIER1KH_ID; + +#define DOT11F_EID_R1KH_ID (1) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_R1KH_ID_MIN_LEN (6) + +#define DOT11F_IE_R1KH_ID_MAX_LEN (6) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_r1_kh_id( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIER1KH_ID*); + +uint32_t dot11f_pack_ie_r1_kh_id( + tpAniSirGlobal, + tDot11fIER1KH_ID *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_R1KH_ID( + tpAniSirGlobal, + tDot11fIER1KH_ID *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 51 (0x33) */ +typedef struct sDot11fIEAPChannelReport { + uint8_t present; + uint8_t regulatoryClass; + uint8_t num_channelList; + uint8_t channelList[50]; +} tDot11fIEAPChannelReport; + +#define DOT11F_EID_APCHANNELREPORT (51) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_APCHANNELREPORT_MIN_LEN (1) + +#define DOT11F_IE_APCHANNELREPORT_MAX_LEN (51) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_ap_channel_report( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEAPChannelReport*); + +uint32_t dot11f_pack_ie_ap_channel_report( + tpAniSirGlobal, + tDot11fIEAPChannelReport *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_APChannelReport( + tpAniSirGlobal, + tDot11fIEAPChannelReport *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 2 (0x02) */ +typedef struct sDot11fIEBcnReportingDetail { + uint8_t present; + uint8_t reportingDetail; +} tDot11fIEBcnReportingDetail; + +#define DOT11F_EID_BCNREPORTINGDETAIL (2) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_BCNREPORTINGDETAIL_MIN_LEN (1) + +#define DOT11F_IE_BCNREPORTINGDETAIL_MAX_LEN (1) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_bcn_reporting_detail( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEBcnReportingDetail*); + +uint32_t dot11f_pack_ie_bcn_reporting_detail( + tpAniSirGlobal, + tDot11fIEBcnReportingDetail *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_BcnReportingDetail( + tpAniSirGlobal, + tDot11fIEBcnReportingDetail *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 1 (0x01) */ +typedef struct sDot11fIEBeaconReportFrmBody { + uint8_t present; + uint8_t num_reportedFields; + uint8_t reportedFields[224]; +} tDot11fIEBeaconReportFrmBody; + +#define DOT11F_EID_BEACONREPORTFRMBODY (1) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_BEACONREPORTFRMBODY_MIN_LEN (0) + +#define DOT11F_IE_BEACONREPORTFRMBODY_MAX_LEN (224) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_beacon_report_frm_body( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEBeaconReportFrmBody*); + +uint32_t dot11f_pack_ie_beacon_report_frm_body( + tpAniSirGlobal, + tDot11fIEBeaconReportFrmBody *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_BeaconReportFrmBody( + tpAniSirGlobal, + tDot11fIEBeaconReportFrmBody *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 1 (0x01) */ +typedef struct sDot11fIEBeaconReporting { + uint8_t present; + uint8_t reportingCondition; + uint8_t threshold; +} tDot11fIEBeaconReporting; + +#define DOT11F_EID_BEACONREPORTING (1) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_BEACONREPORTING_MIN_LEN (2) + +#define DOT11F_IE_BEACONREPORTING_MAX_LEN (2) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_beacon_reporting( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEBeaconReporting*); + +uint32_t dot11f_pack_ie_beacon_reporting( + tpAniSirGlobal, + tDot11fIEBeaconReporting *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_BeaconReporting( + tpAniSirGlobal, + tDot11fIEBeaconReporting *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 2 (0x02) */ +typedef struct sDot11fIECondensedCountryStr { + uint8_t present; + uint8_t countryStr[2]; +} tDot11fIECondensedCountryStr; + +#define DOT11F_EID_CONDENSEDCOUNTRYSTR (2) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_CONDENSEDCOUNTRYSTR_MIN_LEN (2) + +#define DOT11F_IE_CONDENSEDCOUNTRYSTR_MAX_LEN (2) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_condensed_country_str( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIECondensedCountryStr*); + +uint32_t dot11f_pack_ie_condensed_country_str( + tpAniSirGlobal, + tDot11fIECondensedCountryStr *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_CondensedCountryStr( + tpAniSirGlobal, + tDot11fIECondensedCountryStr *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 66 (0x42) */ +typedef struct sDot11fIEMeasurementPilot { + uint8_t present; + uint8_t measurementPilot; + uint8_t num_vendorSpecific; + uint8_t vendorSpecific[255]; +} tDot11fIEMeasurementPilot; + +#define DOT11F_EID_MEASUREMENTPILOT (66) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_MEASUREMENTPILOT_MIN_LEN (1) + +#define DOT11F_IE_MEASUREMENTPILOT_MAX_LEN (256) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_measurement_pilot( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEMeasurementPilot*); + +uint32_t dot11f_pack_ie_measurement_pilot( + tpAniSirGlobal, + tDot11fIEMeasurementPilot *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_MeasurementPilot( + tpAniSirGlobal, + tDot11fIEMeasurementPilot *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 71 (0x47) */ +typedef struct sDot11fIEMultiBssid { + uint8_t present; + uint8_t maxBSSIDIndicator; + uint8_t num_vendorSpecific; + uint8_t vendorSpecific[255]; +} tDot11fIEMultiBssid; + +#define DOT11F_EID_MULTIBSSID (71) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_MULTIBSSID_MIN_LEN (1) + +#define DOT11F_IE_MULTIBSSID_MAX_LEN (256) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_multi_bssid( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEMultiBssid*); + +uint32_t dot11f_pack_ie_multi_bssid( + tpAniSirGlobal, + tDot11fIEMultiBssid *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_MultiBssid( + tpAniSirGlobal, + tDot11fIEMultiBssid *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 57 (0x39) */ +typedef struct sDot11fIERICData { + uint8_t present; + uint8_t Identifier; + uint8_t resourceDescCount; + uint16_t statusCode; +} tDot11fIERICData; + +#define DOT11F_EID_RICDATA (57) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_RICDATA_MIN_LEN (4) + +#define DOT11F_IE_RICDATA_MAX_LEN (4) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_ric_data( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIERICData*); + +uint32_t dot11f_pack_ie_ric_data( + tpAniSirGlobal, + tDot11fIERICData *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_RICData( + tpAniSirGlobal, + tDot11fIERICData *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 75 (0x4b) */ +typedef struct sDot11fIERICDescriptor { + uint8_t present; + uint8_t resourceType; + uint8_t num_variableData; + uint8_t variableData[255]; +} tDot11fIERICDescriptor; + +#define DOT11F_EID_RICDESCRIPTOR (75) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_RICDESCRIPTOR_MIN_LEN (1) + +#define DOT11F_IE_RICDESCRIPTOR_MAX_LEN (256) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_ric_descriptor( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIERICDescriptor*); + +uint32_t dot11f_pack_ie_ric_descriptor( + tpAniSirGlobal, + tDot11fIERICDescriptor *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_RICDescriptor( + tpAniSirGlobal, + tDot11fIERICDescriptor *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 70 (0x46) */ +typedef struct sDot11fIERRMEnabledCap { + uint8_t present; + uint8_t LinkMeasurement:1; + uint8_t NeighborRpt:1; + uint8_t parallel:1; + uint8_t repeated:1; + uint8_t BeaconPassive:1; + uint8_t BeaconActive:1; + uint8_t BeaconTable:1; + uint8_t BeaconRepCond:1; + uint8_t FrameMeasurement:1; + uint8_t ChannelLoad:1; + uint8_t NoiseHistogram:1; + uint8_t statistics:1; + uint8_t LCIMeasurement:1; + uint8_t LCIAzimuth:1; + uint8_t TCMCapability:1; + uint8_t triggeredTCM:1; + uint8_t APChanReport:1; + uint8_t RRMMIBEnabled:1; + uint8_t operatingChanMax:3; + uint8_t nonOperatinChanMax:3; + uint8_t MeasurementPilot:3; + uint8_t MeasurementPilotEnabled:1; + uint8_t NeighborTSFOffset:1; + uint8_t RCPIMeasurement:1; + uint8_t RSNIMeasurement:1; + uint8_t BssAvgAccessDelay:1; + uint8_t BSSAvailAdmission:1; + uint8_t AntennaInformation:1; + uint8_t fine_time_meas_rpt:1; + uint8_t lci_capability:1; + uint8_t reserved:4; +} tDot11fIERRMEnabledCap; + +#define DOT11F_EID_RRMENABLEDCAP (70) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_RRMENABLEDCAP_MIN_LEN (5) + +#define DOT11F_IE_RRMENABLEDCAP_MAX_LEN (5) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_rrm_enabled_cap( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIERRMEnabledCap*); + +uint32_t dot11f_pack_ie_rrm_enabled_cap( + tpAniSirGlobal, + tDot11fIERRMEnabledCap *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_RRMEnabledCap( + tpAniSirGlobal, + tDot11fIERRMEnabledCap *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 10 (0x0a) */ +typedef struct sDot11fIERequestedInfo { + uint8_t present; + uint8_t num_requested_eids; + uint8_t requested_eids[255]; +} tDot11fIERequestedInfo; + +#define DOT11F_EID_REQUESTEDINFO (10) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_REQUESTEDINFO_MIN_LEN (0) + +#define DOT11F_IE_REQUESTEDINFO_MAX_LEN (255) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_requested_info( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIERequestedInfo*); + +uint32_t dot11f_pack_ie_requested_info( + tpAniSirGlobal, + tDot11fIERequestedInfo *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_RequestedInfo( + tpAniSirGlobal, + tDot11fIERequestedInfo *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 0 (0x00) */ +typedef struct sDot11fIESSID { + uint8_t present; + uint8_t num_ssid; + uint8_t ssid[32]; +} tDot11fIESSID; + +#define DOT11F_EID_SSID (0) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_SSID_MIN_LEN (0) + +#define DOT11F_IE_SSID_MAX_LEN (32) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_ssid( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIESSID*); + +uint32_t dot11f_pack_ie_ssid( + tpAniSirGlobal, + tDot11fIESSID *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_SSID( + tpAniSirGlobal, + tDot11fIESSID *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 15 (0x0f) */ +typedef struct sDot11fIESchedule { + uint8_t present; + uint16_t aggregation:1; + uint16_t tsid:4; + uint16_t direction:2; + uint16_t reserved:9; + uint32_t service_start_time; + uint32_t service_interval; + uint16_t max_service_dur; + uint16_t spec_interval; +} tDot11fIESchedule; + +#define DOT11F_EID_SCHEDULE (15) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_SCHEDULE_MIN_LEN (14) + +#define DOT11F_IE_SCHEDULE_MAX_LEN (14) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_schedule( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIESchedule*); + +uint32_t dot11f_pack_ie_schedule( + tpAniSirGlobal, + tDot11fIESchedule *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_Schedule( + tpAniSirGlobal, + tDot11fIESchedule *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 14 (0x0e) */ +typedef struct sDot11fIETCLAS { + uint8_t present; + uint8_t user_priority; + uint8_t classifier_type; + uint8_t classifier_mask; + union { + struct { + uint8_t source[6]; + uint8_t dest[6]; + uint16_t type; + } EthParams; /* classifier_type = 0 */ + struct { + uint8_t version; + union { + struct { + uint8_t source[4]; + uint8_t dest[4]; + uint16_t src_port; + uint16_t dest_port; + uint8_t DSCP; + uint8_t proto; + uint8_t reserved; + } IpV4Params; /* version = 4 */ + struct { + uint8_t source[16]; + uint8_t dest[16]; + uint16_t src_port; + uint16_t dest_port; + uint8_t flow_label[3]; + } IpV6Params; /* version = 6 */ + } params; + } IpParams; /* classifier_type = 1 */ + struct { + uint16_t tag_type; + } Params8021dq; /* classifier_type = 2 */ + } info; +} tDot11fIETCLAS; + +#define DOT11F_EID_TCLAS (14) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_TCLAS_MIN_LEN (5) + +#define DOT11F_IE_TCLAS_MAX_LEN (43) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_tclas( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIETCLAS*); + +uint32_t dot11f_pack_ie_tclas( + tpAniSirGlobal, + tDot11fIETCLAS *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ietclas( + tpAniSirGlobal, + tDot11fIETCLAS *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 44 (0x2c) */ +typedef struct sDot11fIETCLASSPROC { + uint8_t present; + uint8_t processing; +} tDot11fIETCLASSPROC; + +#define DOT11F_EID_TCLASSPROC (44) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_TCLASSPROC_MIN_LEN (1) + +#define DOT11F_IE_TCLASSPROC_MAX_LEN (1) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_tclasSPROC( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIETCLASSPROC*); + +uint32_t dot11f_pack_ie_tclassproc( + tpAniSirGlobal, + tDot11fIETCLASSPROC *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ietclasSPROC( + tpAniSirGlobal, + tDot11fIETCLASSPROC *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 43 (0x2b) */ +typedef struct sDot11fIETSDelay { + uint8_t present; + uint32_t delay; +} tDot11fIETSDelay; + +#define DOT11F_EID_TSDELAY (43) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_TSDELAY_MIN_LEN (4) + +#define DOT11F_IE_TSDELAY_MAX_LEN (4) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_ts_delay( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIETSDelay*); + +uint32_t dot11f_pack_ie_ts_delay( + tpAniSirGlobal, + tDot11fIETSDelay *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_TSDelay( + tpAniSirGlobal, + tDot11fIETSDelay *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 1 (0x01) */ +typedef struct sDot11fIETSFInfo { + uint8_t present; + uint16_t TsfOffset; + uint16_t BeaconIntvl; +} tDot11fIETSFInfo; + +#define DOT11F_EID_TSFINFO (1) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_TSFINFO_MIN_LEN (4) + +#define DOT11F_IE_TSFINFO_MAX_LEN (4) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_tsf_info( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIETSFInfo*); + +uint32_t dot11f_pack_ie_tsf_info( + tpAniSirGlobal, + tDot11fIETSFInfo *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_TSFInfo( + tpAniSirGlobal, + tDot11fIETSFInfo *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 13 (0x0d) */ +typedef struct sDot11fIETSPEC { + uint8_t present; + uint16_t traffic_type:1; + uint16_t tsid:4; + uint16_t direction:2; + uint16_t access_policy:2; + uint16_t aggregation:1; + uint16_t psb:1; + uint16_t user_priority:3; + uint16_t tsinfo_ack_pol:2; + uint8_t schedule:1; + uint8_t unused:7; + uint16_t size:15; + uint16_t fixed:1; + uint16_t max_msdu_size; + uint32_t min_service_int; + uint32_t max_service_int; + uint32_t inactivity_int; + uint32_t suspension_int; + uint32_t service_start_time; + uint32_t min_data_rate; + uint32_t mean_data_rate; + uint32_t peak_data_rate; + uint32_t burst_size; + uint32_t delay_bound; + uint32_t min_phy_rate; + uint16_t surplus_bw_allowance; + uint16_t medium_time; +} tDot11fIETSPEC; + +#define DOT11F_EID_TSPEC (13) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_TSPEC_MIN_LEN (55) + +#define DOT11F_IE_TSPEC_MAX_LEN (55) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_tspec( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIETSPEC*); + +uint32_t dot11f_pack_ie_tspec( + tpAniSirGlobal, + tDot11fIETSPEC *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_TSPEC( + tpAniSirGlobal, + tDot11fIETSPEC *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 191 (0xbf) */ +typedef struct sDot11fIEVHTCaps { + uint8_t present; + uint32_t maxMPDULen:2; + uint32_t supportedChannelWidthSet:2; + uint32_t ldpcCodingCap:1; + uint32_t shortGI80MHz:1; + uint32_t shortGI160and80plus80MHz:1; + uint32_t txSTBC:1; + uint32_t rxSTBC:3; + uint32_t suBeamFormerCap:1; + uint32_t suBeamformeeCap:1; + uint32_t csnofBeamformerAntSup:3; + uint32_t numSoundingDim:3; + uint32_t muBeamformerCap:1; + uint32_t muBeamformeeCap:1; + uint32_t vhtTXOPPS:1; + uint32_t htcVHTCap:1; + uint32_t maxAMPDULenExp:3; + uint32_t vhtLinkAdaptCap:2; + uint32_t rxAntPattern:1; + uint32_t txAntPattern:1; + uint32_t reserved1:2; + uint16_t rxMCSMap; + uint16_t rxHighSupDataRate:13; + uint16_t reserved2:3; + uint16_t txMCSMap; + uint16_t txSupDataRate:13; + uint16_t reserved3:3; +} tDot11fIEVHTCaps; + +#define DOT11F_EID_VHTCAPS (191) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_VHTCAPS_MIN_LEN (12) + +#define DOT11F_IE_VHTCAPS_MAX_LEN (12) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_vht_caps( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEVHTCaps*); + +uint32_t dot11f_pack_ie_vht_caps( + tpAniSirGlobal, + tDot11fIEVHTCaps *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_VHTCaps( + tpAniSirGlobal, + tDot11fIEVHTCaps *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 192 (0xc0) */ +typedef struct sDot11fIEVHTOperation { + uint8_t present; + uint8_t chanWidth; + uint8_t chanCenterFreqSeg1; + uint8_t chanCenterFreqSeg2; + uint16_t basicMCSSet; +} tDot11fIEVHTOperation; + +#define DOT11F_EID_VHTOPERATION (192) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_VHTOPERATION_MIN_LEN (5) + +#define DOT11F_IE_VHTOPERATION_MAX_LEN (5) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_vht_operation( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEVHTOperation*); + +uint32_t dot11f_pack_ie_vht_operation( + tpAniSirGlobal, + tDot11fIEVHTOperation *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_VHTOperation( + tpAniSirGlobal, + tDot11fIEVHTOperation *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 221 (0xdd) {OUI 0x00, 0x50, 0xf2, 0x02, 0x09} */ +typedef struct sDot11fIEWMMSchedule { + uint8_t present; + uint8_t version /* Must be 1! */; + uint16_t aggregation:1; + uint16_t tsid:4; + uint16_t direction:2; + uint16_t reserved:9; + uint32_t service_start_time; + uint32_t service_interval; + uint16_t max_service_dur; + uint16_t spec_interval; +} tDot11fIEWMMSchedule; + +#define DOT11F_EID_WMMSCHEDULE (221) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_WMMSCHEDULE_MIN_LEN (20) + +#define DOT11F_IE_WMMSCHEDULE_MAX_LEN (20) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_wmm_schedule( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEWMMSchedule*); + +uint32_t dot11f_pack_ie_wmm_schedule( + tpAniSirGlobal, + tDot11fIEWMMSchedule *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_WMMSchedule( + tpAniSirGlobal, + tDot11fIEWMMSchedule *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 221 (0xdd) {OUI 0x00, 0x50, 0xf2, 0x02, 0x06} */ +typedef struct sDot11fIEWMMTCLAS { + uint8_t present; + uint8_t version /* Must be 1! */; + uint8_t user_priority; + uint8_t classifier_type; + uint8_t classifier_mask; + union { + struct { + uint8_t source[6]; + uint8_t dest[6]; + uint16_t type; + } EthParams; /* classifier_type = 0 */ + struct { + uint8_t version; + union { + struct { + uint8_t source[4]; + uint8_t dest[4]; + uint16_t src_port; + uint16_t dest_port; + uint8_t DSCP; + uint8_t proto; + uint8_t reserved; + } IpV4Params; /* version = 4 */ + struct { + uint8_t source[16]; + uint8_t dest[16]; + uint16_t src_port; + uint16_t dest_port; + uint8_t flow_label[3]; + } IpV6Params; /* version = 6 */ + } params; + } IpParams; /* classifier_type = 1 */ + struct { + uint16_t tag_type; + } Params8021dq; /* classifier_type = 2 */ + } info; +} tDot11fIEWMMTCLAS; + +#define DOT11F_EID_WMMTCLAS (221) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_WMMTCLAS_MIN_LEN (11) + +#define DOT11F_IE_WMMTCLAS_MAX_LEN (49) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_wmmtclas( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEWMMTCLAS*); + +uint32_t dot11f_pack_ie_wmmtclas( + tpAniSirGlobal, + tDot11fIEWMMTCLAS *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_iewmmtclas( + tpAniSirGlobal, + tDot11fIEWMMTCLAS *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 221 (0xdd) {OUI 0x00, 0x50, 0xf2, 0x02, 0x07} */ +typedef struct sDot11fIEWMMTCLASPROC { + uint8_t present; + uint8_t version /* Must be 1! */; + uint8_t processing; +} tDot11fIEWMMTCLASPROC; + +#define DOT11F_EID_WMMTCLASPROC (221) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_WMMTCLASPROC_MIN_LEN (7) + +#define DOT11F_IE_WMMTCLASPROC_MAX_LEN (7) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_wmmtclasproc( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEWMMTCLASPROC*); + +uint32_t dot11f_pack_ie_wmmtclasproc( + tpAniSirGlobal, + tDot11fIEWMMTCLASPROC *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_iewmmtclasPROC( + tpAniSirGlobal, + tDot11fIEWMMTCLASPROC *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 221 (0xdd) {OUI 0x00, 0x50, 0xf2, 0x02, 0x08} */ +typedef struct sDot11fIEWMMTSDelay { + uint8_t present; + uint8_t version /* Must be 1! */; + uint32_t delay; +} tDot11fIEWMMTSDelay; + +#define DOT11F_EID_WMMTSDELAY (221) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_WMMTSDELAY_MIN_LEN (10) + +#define DOT11F_IE_WMMTSDELAY_MAX_LEN (10) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_wmmts_delay( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEWMMTSDelay*); + +uint32_t dot11f_pack_ie_wmmts_delay( + tpAniSirGlobal, + tDot11fIEWMMTSDelay *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_WMMTSDelay( + tpAniSirGlobal, + tDot11fIEWMMTSDelay *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 221 (0xdd) {OUI 0x00, 0x50, 0xf2, 0x02, 0x02} */ +typedef struct sDot11fIEWMMTSPEC { + uint8_t present; + uint8_t version /* Must be 1! */; + uint16_t traffic_type:1; + uint16_t tsid:4; + uint16_t direction:2; + uint16_t access_policy:2; + uint16_t aggregation:1; + uint16_t psb:1; + uint16_t user_priority:3; + uint16_t tsinfo_ack_pol:2; + uint8_t tsinfo_rsvd:7; + uint8_t burst_size_defn:1; + uint16_t size:15; + uint16_t fixed:1; + uint16_t max_msdu_size; + uint32_t min_service_int; + uint32_t max_service_int; + uint32_t inactivity_int; + uint32_t suspension_int; + uint32_t service_start_time; + uint32_t min_data_rate; + uint32_t mean_data_rate; + uint32_t peak_data_rate; + uint32_t burst_size; + uint32_t delay_bound; + uint32_t min_phy_rate; + uint16_t surplus_bw_allowance; + uint16_t medium_time; +} tDot11fIEWMMTSPEC; + +#define DOT11F_EID_WMMTSPEC (221) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_WMMTSPEC_MIN_LEN (61) + +#define DOT11F_IE_WMMTSPEC_MAX_LEN (61) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_wmmtspec( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEWMMTSPEC*); + +uint32_t dot11f_pack_ie_wmmtspec( + tpAniSirGlobal, + tDot11fIEWMMTSPEC *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_WMMTSPEC( + tpAniSirGlobal, + tDot11fIEWMMTSPEC *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 194 (0xc2) */ +typedef struct sDot11fIEWiderBWChanSwitchAnn { + uint8_t present; + uint8_t newChanWidth; + uint8_t newCenterChanFreq0; + uint8_t newCenterChanFreq1; +} tDot11fIEWiderBWChanSwitchAnn; + +#define DOT11F_EID_WIDERBWCHANSWITCHANN (194) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_WIDERBWCHANSWITCHANN_MIN_LEN (3) + +#define DOT11F_IE_WIDERBWCHANSWITCHANN_MAX_LEN (3) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_wider_bw_chan_switch_ann( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEWiderBWChanSwitchAnn*); + +uint32_t dot11f_pack_ie_wider_bw_chan_switch_ann( + tpAniSirGlobal, + tDot11fIEWiderBWChanSwitchAnn *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_WiderBWChanSwitchAnn( + tpAniSirGlobal, + tDot11fIEWiderBWChanSwitchAnn *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 1 (0x01) */ +typedef struct sDot11fIEazimuth_req { + uint8_t present; + uint8_t request; +} tDot11fIEazimuth_req; + +#define DOT11F_EID_AZIMUTH_REQ (1) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_AZIMUTH_REQ_MIN_LEN (1) + +#define DOT11F_IE_AZIMUTH_REQ_MAX_LEN (1) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_azimuth_req( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEazimuth_req*); + +uint32_t dot11f_pack_ie_azimuth_req( + tpAniSirGlobal, + tDot11fIEazimuth_req *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_azimuth_req( + tpAniSirGlobal, + tDot11fIEazimuth_req *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 4 (0x04) */ +typedef struct sDot11fIEmax_age { + uint8_t present; + uint16_t max_age; +} tDot11fIEmax_age; + +#define DOT11F_EID_MAX_AGE (4) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_MAX_AGE_MIN_LEN (2) + +#define DOT11F_IE_MAX_AGE_MAX_LEN (2) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_max_age( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEmax_age*); + +uint32_t dot11f_pack_ie_max_age( + tpAniSirGlobal, + tDot11fIEmax_age *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_max_age( + tpAniSirGlobal, + tDot11fIEmax_age *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 52 (0x34) */ +typedef struct sDot11fIEneighbor_rpt { + uint8_t present; + uint8_t bssid[6]; + uint8_t APReachability:2; + uint8_t Security:1; + uint8_t KeyScope:1; + uint8_t SpecMgmtCap:1; + uint8_t QosCap:1; + uint8_t apsd:1; + uint8_t rrm:1; + uint8_t DelayedBA:1; + uint8_t ImmBA:1; + uint8_t MobilityDomain:1; + uint8_t reserved:5; + uint16_t reserved1; + uint8_t regulatoryClass; + uint8_t channel; + uint8_t PhyType; + tDot11fIETSFInfo TSFInfo; + tDot11fIECondensedCountryStr CondensedCountryStr; + tDot11fIEMeasurementPilot MeasurementPilot; + tDot11fIERRMEnabledCap RRMEnabledCap; + tDot11fIEMultiBssid MultiBssid; +} tDot11fIEneighbor_rpt; + +#define DOT11F_EID_NEIGHBOR_RPT (52) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_NEIGHBOR_RPT_MIN_LEN (13) + +#define DOT11F_IE_NEIGHBOR_RPT_MAX_LEN (546) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_neighbor_rpt( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEneighbor_rpt*); + +uint32_t dot11f_pack_ie_neighbor_rpt( + tpAniSirGlobal, + tDot11fIEneighbor_rpt *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_neighbor_rpt( + tpAniSirGlobal, + tDot11fIEneighbor_rpt *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 2 (0x02) */ +typedef struct sDot11fIEreq_mac_addr { + uint8_t present; + uint8_t addr[6]; +} tDot11fIEreq_mac_addr; + +#define DOT11F_EID_REQ_MAC_ADDR (2) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_REQ_MAC_ADDR_MIN_LEN (6) + +#define DOT11F_IE_REQ_MAC_ADDR_MAX_LEN (6) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_req_mac_addr( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEreq_mac_addr*); + +uint32_t dot11f_pack_ie_req_mac_addr( + tpAniSirGlobal, + tDot11fIEreq_mac_addr *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_req_mac_addr( + tpAniSirGlobal, + tDot11fIEreq_mac_addr *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 3 (0x03) */ +typedef struct sDot11fIEtgt_mac_addr { + uint8_t present; + uint8_t addr[6]; +} tDot11fIEtgt_mac_addr; + +#define DOT11F_EID_TGT_MAC_ADDR (3) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_TGT_MAC_ADDR_MIN_LEN (6) + +#define DOT11F_IE_TGT_MAC_ADDR_MAX_LEN (6) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_tgt_mac_addr( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEtgt_mac_addr*); + +uint32_t dot11f_pack_ie_tgt_mac_addr( + tpAniSirGlobal, + tDot11fIEtgt_mac_addr *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_tgt_mac_addr( + tpAniSirGlobal, + tDot11fIEtgt_mac_addr *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 195 (0xc3) */ +typedef struct sDot11fIEvht_transmit_power_env { + uint8_t present; + uint8_t num_bytes; + uint8_t bytes[5]; +} tDot11fIEvht_transmit_power_env; + +#define DOT11F_EID_VHT_TRANSMIT_POWER_ENV (195) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_VHT_TRANSMIT_POWER_ENV_MIN_LEN (2) + +#define DOT11F_IE_VHT_TRANSMIT_POWER_ENV_MAX_LEN (5) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_vht_transmit_power_env( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEvht_transmit_power_env*); + +uint32_t dot11f_pack_ie_vht_transmit_power_env( + tpAniSirGlobal, + tDot11fIEvht_transmit_power_env *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_vht_transmit_power_env( + tpAniSirGlobal, + tDot11fIEvht_transmit_power_env *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 197 (0xc5) */ +typedef struct sDot11fIEAID { + uint8_t present; + uint16_t assocId; +} tDot11fIEAID; + +#define DOT11F_EID_AID (197) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_AID_MIN_LEN (2) + +#define DOT11F_IE_AID_MAX_LEN (2) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_aid( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEAID*); + +uint32_t dot11f_pack_ie_aid( + tpAniSirGlobal, + tDot11fIEAID *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_AID( + tpAniSirGlobal, + tDot11fIEAID *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 4 (0x04) */ +typedef struct sDot11fIECFParams { + uint8_t present; + uint8_t cfp_count; + uint8_t cfp_period; + uint16_t cfp_maxduration; + uint16_t cfp_durremaining; +} tDot11fIECFParams; + +#define DOT11F_EID_CFPARAMS (4) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_CFPARAMS_MIN_LEN (6) + +#define DOT11F_IE_CFPARAMS_MAX_LEN (6) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_cf_params( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIECFParams*); + +uint32_t dot11f_pack_ie_cf_params( + tpAniSirGlobal, + tDot11fIECFParams *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_CFParams( + tpAniSirGlobal, + tDot11fIECFParams *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 16 (0x10) */ +typedef struct sDot11fIEChallengeText { + uint8_t present; + uint8_t num_text; + uint8_t text[253]; +} tDot11fIEChallengeText; + +#define DOT11F_EID_CHALLENGETEXT (16) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_CHALLENGETEXT_MIN_LEN (1) + +#define DOT11F_IE_CHALLENGETEXT_MAX_LEN (253) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_challenge_text( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEChallengeText*); + +uint32_t dot11f_pack_ie_challenge_text( + tpAniSirGlobal, + tDot11fIEChallengeText *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_ChallengeText( + tpAniSirGlobal, + tDot11fIEChallengeText *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 37 (0x25) */ +typedef struct sDot11fIEChanSwitchAnn { + uint8_t present; + uint8_t switchMode; + uint8_t newChannel; + uint8_t switchCount; +} tDot11fIEChanSwitchAnn; + +#define DOT11F_EID_CHANSWITCHANN (37) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_CHANSWITCHANN_MIN_LEN (3) + +#define DOT11F_IE_CHANSWITCHANN_MAX_LEN (3) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_chan_switch_ann( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEChanSwitchAnn*); + +uint32_t dot11f_pack_ie_chan_switch_ann( + tpAniSirGlobal, + tDot11fIEChanSwitchAnn *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_ChanSwitchAnn( + tpAniSirGlobal, + tDot11fIEChanSwitchAnn *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 196 (0xc4) */ +typedef struct sDot11fIEChannelSwitchWrapper { + uint8_t present; + tDot11fIEWiderBWChanSwitchAnn WiderBWChanSwitchAnn; + tDot11fIEvht_transmit_power_env vht_transmit_power_env; +} tDot11fIEChannelSwitchWrapper; + +#define DOT11F_EID_CHANNELSWITCHWRAPPER (196) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_CHANNELSWITCHWRAPPER_MIN_LEN (0) + +#define DOT11F_IE_CHANNELSWITCHWRAPPER_MAX_LEN (12) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_channel_switch_wrapper( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEChannelSwitchWrapper*); + +uint32_t dot11f_pack_ie_channel_switch_wrapper( + tpAniSirGlobal, + tDot11fIEChannelSwitchWrapper *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_channel_switch_wrapper( + tpAniSirGlobal, + tDot11fIEChannelSwitchWrapper *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 7 (0x07) */ +typedef struct sDot11fIECountry { + uint8_t present; + uint8_t country[3]; + uint8_t num_triplets; + uint8_t triplets[84][3]; +} tDot11fIECountry; + +#define DOT11F_EID_COUNTRY (7) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_COUNTRY_MIN_LEN (3) + +#define DOT11F_IE_COUNTRY_MAX_LEN (255) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_country( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIECountry*); + +uint32_t dot11f_pack_ie_country( + tpAniSirGlobal, + tDot11fIECountry *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_country( + tpAniSirGlobal, + tDot11fIECountry *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 3 (0x03) */ +typedef struct sDot11fIEDSParams { + uint8_t present; + uint8_t curr_channel; +} tDot11fIEDSParams; + +#define DOT11F_EID_DSPARAMS (3) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_DSPARAMS_MIN_LEN (1) + +#define DOT11F_IE_DSPARAMS_MAX_LEN (1) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_DSParams( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEDSParams*); + +uint32_t dot11f_pack_ie_ds_params( + tpAniSirGlobal, + tDot11fIEDSParams *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_DSParams( + tpAniSirGlobal, + tDot11fIEDSParams *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 12 (0x0c) */ +typedef struct sDot11fIEEDCAParamSet { + uint8_t present; + uint8_t qos; + uint8_t reserved; + uint8_t acbe_aifsn:4; + uint8_t acbe_acm:1; + uint8_t acbe_aci:2; + uint8_t unused1:1; + uint8_t acbe_acwmin:4; + uint8_t acbe_acwmax:4; + uint16_t acbe_txoplimit; + uint8_t acbk_aifsn:4; + uint8_t acbk_acm:1; + uint8_t acbk_aci:2; + uint8_t unused2:1; + uint8_t acbk_acwmin:4; + uint8_t acbk_acwmax:4; + uint16_t acbk_txoplimit; + uint8_t acvi_aifsn:4; + uint8_t acvi_acm:1; + uint8_t acvi_aci:2; + uint8_t unused3:1; + uint8_t acvi_acwmin:4; + uint8_t acvi_acwmax:4; + uint16_t acvi_txoplimit; + uint8_t acvo_aifsn:4; + uint8_t acvo_acm:1; + uint8_t acvo_aci:2; + uint8_t unused4:1; + uint8_t acvo_acwmin:4; + uint8_t acvo_acwmax:4; + uint16_t acvo_txoplimit; +} tDot11fIEEDCAParamSet; + +#define DOT11F_EID_EDCAPARAMSET (12) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_EDCAPARAMSET_MIN_LEN (18) + +#define DOT11F_IE_EDCAPARAMSET_MAX_LEN (18) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_edca_param_set( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEEDCAParamSet*); + +uint32_t dot11f_pack_ie_edca_param_set( + tpAniSirGlobal, + tDot11fIEEDCAParamSet *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_EDCAParamSet( + tpAniSirGlobal, + tDot11fIEEDCAParamSet *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 42 (0x2a) */ +typedef struct sDot11fIEERPInfo { + uint8_t present; + uint8_t non_erp_present:1; + uint8_t use_prot:1; + uint8_t barker_preamble:1; + uint8_t unused:5; +} tDot11fIEERPInfo; + +#define DOT11F_EID_ERPINFO (42) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_ERPINFO_MIN_LEN (1) + +#define DOT11F_IE_ERPINFO_MAX_LEN (1) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_erp_info( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEERPInfo*); + +uint32_t dot11f_pack_ie_erp_info( + tpAniSirGlobal, + tDot11fIEERPInfo *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_ERPInfo( + tpAniSirGlobal, + tDot11fIEERPInfo *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 156 (0x9c) {OUI 0x00, 0x40, 0x96, 0x00} */ +typedef struct sDot11fIEESECckmOpaque { + uint8_t present; + uint8_t num_data; + uint8_t data[20]; +} tDot11fIEESECckmOpaque; + +#define DOT11F_EID_ESECCKMOPAQUE (156) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_ESECCKMOPAQUE_MIN_LEN (10) + +#define DOT11F_IE_ESECCKMOPAQUE_MAX_LEN (24) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_ese_cckm_opaque( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEESECckmOpaque*); + +uint32_t dot11f_pack_ie_ese_cckm_opaque( + tpAniSirGlobal, + tDot11fIEESECckmOpaque *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_ESECckmOpaque( + tpAniSirGlobal, + tDot11fIEESECckmOpaque *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 221 (0xdd) {OUI 0x00, 0x40, 0x96, 0x01} */ +typedef struct sDot11fIEESERadMgmtCap { + uint8_t present; + uint8_t mgmt_state; + uint8_t mbssid_mask:3; + uint8_t reserved:5; +} tDot11fIEESERadMgmtCap; + +#define DOT11F_EID_ESERADMGMTCAP (221) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_ESERADMGMTCAP_MIN_LEN (6) + +#define DOT11F_IE_ESERADMGMTCAP_MAX_LEN (6) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_ese_rad_mgmt_cap( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEESERadMgmtCap*); + +uint32_t dot11f_pack_ie_ese_rad_mgmt_cap( + tpAniSirGlobal, + tDot11fIEESERadMgmtCap *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_ESERadMgmtCap( + tpAniSirGlobal, + tDot11fIEESERadMgmtCap *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 221 (0xdd) {OUI 0x00, 0x40, 0x96, 0x07} */ +typedef struct sDot11fIEESETrafStrmMet { + uint8_t present; + uint8_t tsid; + uint8_t state; + uint16_t msmt_interval; +} tDot11fIEESETrafStrmMet; + +#define DOT11F_EID_ESETRAFSTRMMET (221) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_ESETRAFSTRMMET_MIN_LEN (8) + +#define DOT11F_IE_ESETRAFSTRMMET_MAX_LEN (8) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_ese_traf_strm_met( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEESETrafStrmMet*); + +uint32_t dot11f_pack_ie_ese_traf_strm_met( + tpAniSirGlobal, + tDot11fIEESETrafStrmMet *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_ESETrafStrmMet( + tpAniSirGlobal, + tDot11fIEESETrafStrmMet *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 221 (0xdd) {OUI 0x00, 0x40, 0x96, 0x08} */ +typedef struct sDot11fIEESETrafStrmRateSet { + uint8_t present; + uint8_t tsid; + uint8_t num_tsrates; + uint8_t tsrates[8]; +} tDot11fIEESETrafStrmRateSet; + +#define DOT11F_EID_ESETRAFSTRMRATESET (221) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_ESETRAFSTRMRATESET_MIN_LEN (5) + +#define DOT11F_IE_ESETRAFSTRMRATESET_MAX_LEN (13) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_ese_traf_strm_rate_set( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEESETrafStrmRateSet*); + +uint32_t dot11f_pack_ie_ese_traf_strm_rate_set( + tpAniSirGlobal, + tDot11fIEESETrafStrmRateSet *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_ESETrafStrmRateSet( + tpAniSirGlobal, + tDot11fIEESETrafStrmRateSet *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 150 (0x96) {OUI 0x00, 0x40, 0x96, 0x00} */ +typedef struct sDot11fIEESETxmitPower { + uint8_t present; + uint8_t power_limit; + uint8_t reserved; +} tDot11fIEESETxmitPower; + +#define DOT11F_EID_ESETXMITPOWER (150) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_ESETXMITPOWER_MIN_LEN (6) + +#define DOT11F_IE_ESETXMITPOWER_MAX_LEN (6) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_ese_txmit_power( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEESETxmitPower*); + +uint32_t dot11f_pack_ie_ese_txmit_power( + tpAniSirGlobal, + tDot11fIEESETxmitPower *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_ESETxmitPower( + tpAniSirGlobal, + tDot11fIEESETxmitPower *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 221 (0xdd) {OUI 0x00, 0x40, 0x96, 0x03} */ +typedef struct sDot11fIEESEVersion { + uint8_t present; + uint8_t version; +} tDot11fIEESEVersion; + +#define DOT11F_EID_ESEVERSION (221) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_ESEVERSION_MIN_LEN (5) + +#define DOT11F_IE_ESEVERSION_MAX_LEN (5) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_ese_version( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEESEVersion*); + +uint32_t dot11f_pack_ie_ese_version( + tpAniSirGlobal, + tDot11fIEESEVersion *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_ESEVersion( + tpAniSirGlobal, + tDot11fIEESEVersion *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 127 (0x7f) */ +typedef struct sDot11fIEExtCap { + uint8_t present; + uint8_t num_bytes; + uint8_t bytes[15]; +} tDot11fIEExtCap; + +#define DOT11F_EID_EXTCAP (127) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_EXTCAP_MIN_LEN (1) + +#define DOT11F_IE_EXTCAP_MAX_LEN (15) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_ext_cap( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEExtCap*); + +uint32_t dot11f_pack_ie_ext_cap( + tpAniSirGlobal, + tDot11fIEExtCap *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_ExtCap( + tpAniSirGlobal, + tDot11fIEExtCap *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 50 (0x32) */ +typedef struct sDot11fIEExtSuppRates { + uint8_t present; + uint8_t num_rates; + uint8_t rates[12]; +} tDot11fIEExtSuppRates; + +#define DOT11F_EID_EXTSUPPRATES (50) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_EXTSUPPRATES_MIN_LEN (1) + +#define DOT11F_IE_EXTSUPPRATES_MAX_LEN (12) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_ext_supp_rates( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEExtSuppRates*); + +uint32_t dot11f_pack_ie_ext_supp_rates( + tpAniSirGlobal, + tDot11fIEExtSuppRates *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_ExtSuppRates( + tpAniSirGlobal, + tDot11fIEExtSuppRates *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 2 (0x02) */ +typedef struct sDot11fIEFHParamSet { + uint8_t present; + uint16_t dwell_time; + uint8_t hop_set; + uint8_t hop_pattern; + uint8_t hop_index; +} tDot11fIEFHParamSet; + +#define DOT11F_EID_FHPARAMSET (2) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_FHPARAMSET_MIN_LEN (5) + +#define DOT11F_IE_FHPARAMSET_MAX_LEN (5) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_fh_param_set( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEFHParamSet*); + +uint32_t dot11f_pack_ie_fh_param_set( + tpAniSirGlobal, + tDot11fIEFHParamSet *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_FHParamSet( + tpAniSirGlobal, + tDot11fIEFHParamSet *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 8 (0x08) */ +typedef struct sDot11fIEFHParams { + uint8_t present; + uint8_t radix; + uint8_t nchannels; +} tDot11fIEFHParams; + +#define DOT11F_EID_FHPARAMS (8) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_FHPARAMS_MIN_LEN (2) + +#define DOT11F_IE_FHPARAMS_MAX_LEN (2) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_fh_params( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEFHParams*); + +uint32_t dot11f_pack_ie_fh_params( + tpAniSirGlobal, + tDot11fIEFHParams *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_FHParams( + tpAniSirGlobal, + tDot11fIEFHParams *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 9 (0x09) */ +typedef struct sDot11fIEFHPattTable { + uint8_t present; + uint8_t flag; + uint8_t nsets; + uint8_t modulus; + uint8_t offset; + uint8_t num_randtable; + uint8_t randtable[251]; +} tDot11fIEFHPattTable; + +#define DOT11F_EID_FHPATTTABLE (9) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_FHPATTTABLE_MIN_LEN (4) + +#define DOT11F_IE_FHPATTTABLE_MAX_LEN (255) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_fh_patt_table( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEFHPattTable*); + +uint32_t dot11f_pack_ie_fh_patt_table( + tpAniSirGlobal, + tDot11fIEFHPattTable *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_FHPattTable( + tpAniSirGlobal, + tDot11fIEFHPattTable *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 55 (0x37) */ +typedef struct sDot11fIEFTInfo { + uint8_t present; + uint16_t reserved:8; + uint16_t IECount:8; + uint8_t MIC[16]; + uint8_t Anonce[32]; + uint8_t Snonce[32]; + tDot11fIER1KH_ID R1KH_ID; + tDot11fIEGTK GTK; + tDot11fIER0KH_ID R0KH_ID; + tDot11fIEIGTK IGTK; +} tDot11fIEFTInfo; + +#define DOT11F_EID_FTINFO (55) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_FTINFO_MIN_LEN (82) + +#define DOT11F_IE_FTINFO_MAX_LEN (220) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_ft_info( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEFTInfo*); + +uint32_t dot11f_pack_ie_ft_info( + tpAniSirGlobal, + tDot11fIEFTInfo *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ieft_info( + tpAniSirGlobal, + tDot11fIEFTInfo *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 45 (0x2d) */ +typedef struct sDot11fIEHTCaps { + uint8_t present; + uint16_t advCodingCap:1; + uint16_t supportedChannelWidthSet:1; + uint16_t mimoPowerSave:2; + uint16_t greenField:1; + uint16_t shortGI20MHz:1; + uint16_t shortGI40MHz:1; + uint16_t txSTBC:1; + uint16_t rxSTBC:2; + uint16_t delayedBA:1; + uint16_t maximalAMSDUsize:1; + uint16_t dsssCckMode40MHz:1; + uint16_t psmp:1; + uint16_t stbcControlFrame:1; + uint16_t lsigTXOPProtection:1; + uint8_t maxRxAMPDUFactor:2; + uint8_t mpduDensity:3; + uint8_t reserved1:3; + uint8_t supportedMCSSet[16]; + uint16_t pco:1; + uint16_t transitionTime:2; + uint16_t reserved2:5; + uint16_t mcsFeedback:2; + uint16_t reserved3:6; + uint32_t txBF:1; + uint32_t rxStaggeredSounding:1; + uint32_t txStaggeredSounding:1; + uint32_t rxZLF:1; + uint32_t txZLF:1; + uint32_t implicitTxBF:1; + uint32_t calibration:2; + uint32_t explicitCSITxBF:1; + uint32_t explicitUncompressedSteeringMatrix:1; + uint32_t explicitBFCSIFeedback:3; + uint32_t explicitUncompressedSteeringMatrixFeedback:3; + uint32_t explicitCompressedSteeringMatrixFeedback:3; + uint32_t csiNumBFAntennae:2; + uint32_t uncompressedSteeringMatrixBFAntennae:2; + uint32_t compressedSteeringMatrixBFAntennae:2; + uint32_t reserved4:7; + uint8_t antennaSelection:1; + uint8_t explicitCSIFeedbackTx:1; + uint8_t antennaIndicesFeedbackTx:1; + uint8_t explicitCSIFeedback:1; + uint8_t antennaIndicesFeedback:1; + uint8_t rxAS:1; + uint8_t txSoundingPPDUs:1; + uint8_t reserved5:1; + uint8_t num_rsvd; + uint8_t rsvd[32]; +} tDot11fIEHTCaps; + +#define DOT11F_EID_HTCAPS (45) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_HTCAPS_MIN_LEN (26) + +#define DOT11F_IE_HTCAPS_MAX_LEN (58) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_ht_caps( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEHTCaps*); + +uint32_t dot11f_pack_ie_ht_caps( + tpAniSirGlobal, + tDot11fIEHTCaps *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_HTCaps( + tpAniSirGlobal, + tDot11fIEHTCaps *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 61 (0x3d) */ +typedef struct sDot11fIEHTInfo { + uint8_t present; + uint8_t primaryChannel; + uint8_t secondaryChannelOffset:2; + uint8_t recommendedTxWidthSet:1; + uint8_t rifsMode:1; + uint8_t controlledAccessOnly:1; + uint8_t serviceIntervalGranularity:3; + uint16_t opMode:2; + uint16_t nonGFDevicesPresent:1; + uint16_t transmitBurstLimit:1; + uint16_t obssNonHTStaPresent:1; + uint16_t reserved:11; + uint16_t basicSTBCMCS:7; + uint16_t dualCTSProtection:1; + uint16_t secondaryBeacon:1; + uint16_t lsigTXOPProtectionFullSupport:1; + uint16_t pcoActive:1; + uint16_t pcoPhase:1; + uint16_t reserved2:4; + uint8_t basicMCSSet[16]; + uint8_t num_rsvd; + uint8_t rsvd[32]; +} tDot11fIEHTInfo; + +#define DOT11F_EID_HTINFO (61) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_HTINFO_MIN_LEN (22) + +#define DOT11F_IE_HTINFO_MAX_LEN (54) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_ht_info( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEHTInfo*); + +uint32_t dot11f_pack_ie_ht_info( + tpAniSirGlobal, + tDot11fIEHTInfo *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_HTInfo( + tpAniSirGlobal, + tDot11fIEHTInfo *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 6 (0x06) */ +typedef struct sDot11fIEIBSSParams { + uint8_t present; + uint16_t atim; +} tDot11fIEIBSSParams; + +#define DOT11F_EID_IBSSPARAMS (6) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_IBSSPARAMS_MIN_LEN (2) + +#define DOT11F_IE_IBSSPARAMS_MAX_LEN (2) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_ibss_params( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEIBSSParams*); + +uint32_t dot11f_pack_ie_ibss_params( + tpAniSirGlobal, + tDot11fIEIBSSParams *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_IBSSParams( + tpAniSirGlobal, + tDot11fIEIBSSParams *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 101 (0x65) */ +typedef struct sDot11fIELinkIdentifier { + uint8_t present; + uint8_t bssid[6]; + uint8_t InitStaAddr[6]; + uint8_t RespStaAddr[6]; +} tDot11fIELinkIdentifier; + +#define DOT11F_EID_LINKIDENTIFIER (101) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_LINKIDENTIFIER_MIN_LEN (18) + +#define DOT11F_IE_LINKIDENTIFIER_MAX_LEN (18) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_link_identifier( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIELinkIdentifier*); + +uint32_t dot11f_pack_ie_link_identifier( + tpAniSirGlobal, + tDot11fIELinkIdentifier *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_LinkIdentifier( + tpAniSirGlobal, + tDot11fIELinkIdentifier *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 221 (0xdd) {OUI 0x50, 0x6f, 0x9a, 0x16} */ +typedef struct sDot11fIEMBO_IE { + uint8_t present; + uint8_t mbo_cap[3]; + uint8_t num_assoc_disallowed; + uint8_t assoc_disallowed[3]; +} tDot11fIEMBO_IE; + +#define DOT11F_EID_MBO_IE (221) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_MBO_IE_MIN_LEN (7) + +#define DOT11F_IE_MBO_IE_MAX_LEN (10) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_MBO_IE( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEMBO_IE*); + +uint32_t dot11f_pack_ie_MBO_IE( + tpAniSirGlobal, + tDot11fIEMBO_IE *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_MBO_IE( + tpAniSirGlobal, + tDot11fIEMBO_IE *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 39 (0x27) */ +typedef struct sDot11fIEMeasurementReport { + uint8_t present; + uint8_t token; + uint8_t late:1; + uint8_t incapable:1; + uint8_t refused:1; + uint8_t unused:5; + uint8_t type; + union { + struct { + uint8_t channel; + tDOT11F_U64 meas_start_time; + uint16_t meas_duration; + uint8_t bss:1; + uint8_t ofdm_preamble:1; + uint8_t unid_signal:1; + uint8_t rader:1; + uint8_t unmeasured:1; + uint8_t unused:3; + } Basic; /* type = 0 */ + struct { + uint8_t channel; + tDOT11F_U64 meas_start_time; + uint16_t meas_duration; + uint8_t cca_busy_fraction; + } CCA; /* type = 1 */ + struct { + uint8_t channel; + tDOT11F_U64 meas_start_time; + uint16_t meas_duration; + uint8_t rpi0_density; + uint8_t rpi1_density; + uint8_t rpi2_density; + uint8_t rpi3_density; + uint8_t rpi4_density; + uint8_t rpi5_density; + uint8_t rpi6_density; + uint8_t rpi7_density; + } RPIHistogram; /* type = 2 */ + struct { + uint8_t regClass; + uint8_t channel; + tDOT11F_U64 meas_start_time; + uint16_t meas_duration; + uint8_t condensed_PHY:7; + uint8_t reported_frame_type:1; + uint8_t RCPI; + uint8_t RSNI; + uint8_t BSSID[6]; + uint8_t antenna_id; + uint32_t parent_TSF; + tDot11fIEBeaconReportFrmBody BeaconReportFrmBody; + } Beacon; /* type = 5 */ + } report; +} tDot11fIEMeasurementReport; + +#define DOT11F_EID_MEASUREMENTREPORT (39) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_MEASUREMENTREPORT_MIN_LEN (3) + +#define DOT11F_IE_MEASUREMENTREPORT_MAX_LEN (29) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_measurement_report( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEMeasurementReport*); + +uint32_t dot11f_pack_ie_measurement_report( + tpAniSirGlobal, + tDot11fIEMeasurementReport *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_measurement_report( + tpAniSirGlobal, + tDot11fIEMeasurementReport *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 38 (0x26) */ +typedef struct sDot11fIEMeasurementRequest { + uint8_t present; + uint8_t measurement_token; + uint8_t parallel:1; + uint8_t enable:1; + uint8_t request:1; + uint8_t report:1; + uint8_t durationMandatory:1; + uint8_t unused:3; + uint8_t measurement_type; + union { + struct { + uint8_t channel_no; + uint8_t meas_start_time[8]; + uint16_t meas_duration; + } Basic; /* measurement_type = 0 */ + struct { + uint8_t channel_no; + uint8_t meas_start_time[8]; + uint16_t meas_duration; + } CCA; /* measurement_type = 1 */ + struct { + uint8_t channel_no; + uint8_t meas_start_time[8]; + uint16_t meas_duration; + } RPIHistogram; /* measurement_type = 2 */ + struct { + uint8_t regClass; + uint8_t channel; + uint16_t randomization; + uint16_t meas_duration; + uint8_t meas_mode; + uint8_t BSSID[6]; + tDot11fIESSID SSID; + tDot11fIEBeaconReporting BeaconReporting; + tDot11fIEBcnReportingDetail BcnReportingDetail; + tDot11fIERequestedInfo RequestedInfo; + uint16_t num_APChannelReport; + tDot11fIEAPChannelReport APChannelReport[2]; + } Beacon; /* measurement_type = 5 */ + struct { + uint8_t loc_subject; + tDot11fIEazimuth_req azimuth_req; + tDot11fIEreq_mac_addr req_mac_addr; + tDot11fIEtgt_mac_addr tgt_mac_addr; + tDot11fIEmax_age max_age; + } lci; /* measurement_type = 8 */ + struct { + uint16_t random_interval; + uint8_t min_ap_count; + tDot11fIEneighbor_rpt neighbor_rpt; + tDot11fIEmax_age max_age; + } ftmrr; /* measurement_type = 16 */ + } measurement_request; +} tDot11fIEMeasurementRequest; + +#define DOT11F_EID_MEASUREMENTREQUEST (38) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_MEASUREMENTREQUEST_MIN_LEN (4) + +#define DOT11F_IE_MEASUREMENTREQUEST_MAX_LEN (16) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_measurement_request( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEMeasurementRequest*); + +uint32_t dot11f_pack_ie_measurement_request( + tpAniSirGlobal, + tDot11fIEMeasurementRequest *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_measurement_request( + tpAniSirGlobal, + tDot11fIEMeasurementRequest *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 54 (0x36) */ +typedef struct sDot11fIEMobilityDomain { + uint8_t present; + uint16_t MDID; + uint8_t overDSCap:1; + uint8_t resourceReqCap:1; + uint8_t reserved:6; +} tDot11fIEMobilityDomain; + +#define DOT11F_EID_MOBILITYDOMAIN (54) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_MOBILITYDOMAIN_MIN_LEN (3) + +#define DOT11F_IE_MOBILITYDOMAIN_MAX_LEN (3) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_mobility_domain( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEMobilityDomain*); + +uint32_t dot11f_pack_ie_mobility_domain( + tpAniSirGlobal, + tDot11fIEMobilityDomain *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_MobilityDomain( + tpAniSirGlobal, + tDot11fIEMobilityDomain *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 52 (0x34) */ +typedef struct sDot11fIENeighborReport { + uint8_t present; + uint8_t bssid[6]; + uint8_t APReachability:2; + uint8_t Security:1; + uint8_t KeyScope:1; + uint8_t SpecMgmtCap:1; + uint8_t QosCap:1; + uint8_t apsd:1; + uint8_t rrm:1; + uint8_t DelayedBA:1; + uint8_t ImmBA:1; + uint8_t MobilityDomain:1; + uint8_t reserved:5; + uint16_t reserved1; + uint8_t regulatoryClass; + uint8_t channel; + uint8_t PhyType; + tDot11fIETSFInfo TSFInfo; + tDot11fIECondensedCountryStr CondensedCountryStr; + tDot11fIEMeasurementPilot MeasurementPilot; + tDot11fIERRMEnabledCap RRMEnabledCap; + tDot11fIEMultiBssid MultiBssid; +} tDot11fIENeighborReport; + +#define DOT11F_EID_NEIGHBORREPORT (52) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_NEIGHBORREPORT_MIN_LEN (13) + +#define DOT11F_IE_NEIGHBORREPORT_MAX_LEN (546) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_neighbor_report( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIENeighborReport*); + +uint32_t dot11f_pack_ie_neighbor_report( + tpAniSirGlobal, + tDot11fIENeighborReport *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_neighbor_report( + tpAniSirGlobal, + tDot11fIENeighborReport *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 74 (0x4a) */ +typedef struct sDot11fIEOBSSScanParameters { + uint8_t present; + uint16_t obssScanPassiveDwell; + uint16_t obssScanActiveDwell; + uint16_t bssChannelWidthTriggerScanInterval; + uint16_t obssScanPassiveTotalPerChannel; + uint16_t obssScanActiveTotalPerChannel; + uint16_t bssWidthChannelTransitionDelayFactor; + uint16_t obssScanActivityThreshold; +} tDot11fIEOBSSScanParameters; + +#define DOT11F_EID_OBSSSCANPARAMETERS (74) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_OBSSSCANPARAMETERS_MIN_LEN (14) + +#define DOT11F_IE_OBSSSCANPARAMETERS_MAX_LEN (14) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_obss_scan_parameters( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEOBSSScanParameters*); + +uint32_t dot11f_pack_ie_obss_scan_parameters( + tpAniSirGlobal, + tDot11fIEOBSSScanParameters *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_OBSSScanParameters( + tpAniSirGlobal, + tDot11fIEOBSSScanParameters *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 199 (0xc7) */ +typedef struct sDot11fIEOperatingMode { + uint8_t present; + uint8_t chanWidth:2; + uint8_t reserved:2; + uint8_t rxNSS:3; + uint8_t rxNSSType:1; +} tDot11fIEOperatingMode; + +#define DOT11F_EID_OPERATINGMODE (199) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_OPERATINGMODE_MIN_LEN (1) + +#define DOT11F_IE_OPERATINGMODE_MAX_LEN (1) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_operating_mode( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEOperatingMode*); + +uint32_t dot11f_pack_ie_operating_mode( + tpAniSirGlobal, + tDot11fIEOperatingMode *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_OperatingMode( + tpAniSirGlobal, + tDot11fIEOperatingMode *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 221 (0xdd) {OUI 0x50, 0x6f, 0x9a, 0x09} (Multi-IE) */ +typedef struct sDot11fIEP2PAssocReq { + uint8_t present; + tDot11fTLVP2PCapability P2PCapability; + tDot11fTLVExtendedListenTiming ExtendedListenTiming; + tDot11fTLVP2PDeviceInfo P2PDeviceInfo; +} tDot11fIEP2PAssocReq; + +#define DOT11F_EID_P2PASSOCREQ (221) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_P2PASSOCREQ_MIN_LEN (4) + +#define DOT11F_IE_P2PASSOCREQ_MAX_LEN (71) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_p2_p_assoc_req( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEP2PAssocReq*); + +uint32_t dot11f_pack_ie_p2_p_assoc_req( + tpAniSirGlobal, + tDot11fIEP2PAssocReq *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_iep2_p_assoc_req( + tpAniSirGlobal, + tDot11fIEP2PAssocReq *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 221 (0xdd) {OUI 0x50, 0x6f, 0x9a, 0x09} (Multi-IE) */ +typedef struct sDot11fIEP2PAssocRes { + uint8_t present; + tDot11fTLVP2PStatus P2PStatus; + tDot11fTLVExtendedListenTiming ExtendedListenTiming; +} tDot11fIEP2PAssocRes; + +#define DOT11F_EID_P2PASSOCRES (221) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_P2PASSOCRES_MIN_LEN (4) + +#define DOT11F_IE_P2PASSOCRES_MAX_LEN (15) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_p2_p_assoc_res( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEP2PAssocRes*); + +uint32_t dot11f_pack_ie_p2_p_assoc_res( + tpAniSirGlobal, + tDot11fIEP2PAssocRes *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_iep2_p_assoc_res( + tpAniSirGlobal, + tDot11fIEP2PAssocRes *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 221 (0xdd) {OUI 0x50, 0x6f, 0x9a, 0x09} (Multi-IE) */ +typedef struct sDot11fIEP2PBeacon { + uint8_t present; + tDot11fTLVP2PCapability P2PCapability; + tDot11fTLVP2PDeviceId P2PDeviceId; + tDot11fTLVNoticeOfAbsence NoticeOfAbsence; +} tDot11fIEP2PBeacon; + +#define DOT11F_EID_P2PBEACON (221) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_P2PBEACON_MIN_LEN (4) + +#define DOT11F_IE_P2PBEACON_MAX_LEN (59) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_p2_p_beacon( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEP2PBeacon*); + +uint32_t dot11f_pack_ie_p2_p_beacon( + tpAniSirGlobal, + tDot11fIEP2PBeacon *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_iep2_p_beacon( + tpAniSirGlobal, + tDot11fIEP2PBeacon *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 221 (0xdd) {OUI 0x50, 0x6f, 0x9a, 0x09} (Multi-IE) */ +typedef struct sDot11fIEP2PBeaconProbeRes { + uint8_t present; + tDot11fTLVP2PCapability P2PCapability; + tDot11fTLVP2PDeviceId P2PDeviceId; + tDot11fTLVExtendedListenTiming ExtendedListenTiming; + tDot11fTLVNoticeOfAbsence NoticeOfAbsence; + tDot11fTLVP2PDeviceInfo P2PDeviceInfo; + tDot11fTLVP2PGroupInfo P2PGroupInfo; +} tDot11fIEP2PBeaconProbeRes; + +#define DOT11F_EID_P2PBEACONPROBERES (221) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_P2PBEACONPROBERES_MIN_LEN (4) + +#define DOT11F_IE_P2PBEACONPROBERES_MAX_LEN (1148) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_p2_p_beacon_probe_res( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEP2PBeaconProbeRes*); + +uint32_t dot11f_pack_ie_p2_p_beacon_probe_res( + tpAniSirGlobal, + tDot11fIEP2PBeaconProbeRes *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_iep2_p_beacon_probe_res( + tpAniSirGlobal, + tDot11fIEP2PBeaconProbeRes *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 221 (0xdd) {OUI 0x50, 0x6f, 0x9a, 0x09} (Multi-IE) */ +typedef struct sDot11fIEP2PDeAuth { + uint8_t present; + tDot11fTLVMinorReasonCode MinorReasonCode; +} tDot11fIEP2PDeAuth; + +#define DOT11F_EID_P2PDEAUTH (221) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_P2PDEAUTH_MIN_LEN (4) + +#define DOT11F_IE_P2PDEAUTH_MAX_LEN (8) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_p2_p_de_auth( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEP2PDeAuth*); + +uint32_t dot11f_pack_ie_p2_p_de_auth( + tpAniSirGlobal, + tDot11fIEP2PDeAuth *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_iep2_p_de_auth( + tpAniSirGlobal, + tDot11fIEP2PDeAuth *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 221 (0xdd) {OUI 0x50, 0x6f, 0x9a, 0x09} (Multi-IE) */ +typedef struct sDot11fIEP2PDisAssoc { + uint8_t present; + tDot11fTLVMinorReasonCode MinorReasonCode; +} tDot11fIEP2PDisAssoc; + +#define DOT11F_EID_P2PDISASSOC (221) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_P2PDISASSOC_MIN_LEN (4) + +#define DOT11F_IE_P2PDISASSOC_MAX_LEN (8) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_p2_p_dis_assoc( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEP2PDisAssoc*); + +uint32_t dot11f_pack_ie_p2_p_dis_assoc( + tpAniSirGlobal, + tDot11fIEP2PDisAssoc *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_iep2_p_dis_assoc( + tpAniSirGlobal, + tDot11fIEP2PDisAssoc *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 221 (0xdd) {OUI 0x50, 0x6f, 0x9a, 0x09} */ +typedef struct sDot11fIEP2PIEOpaque { + uint8_t present; + uint8_t num_data; + uint8_t data[249]; +} tDot11fIEP2PIEOpaque; + +#define DOT11F_EID_P2PIEOPAQUE (221) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_P2PIEOPAQUE_MIN_LEN (6) + +#define DOT11F_IE_P2PIEOPAQUE_MAX_LEN (253) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_p2_pie_opaque( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEP2PIEOpaque*); + +uint32_t dot11f_pack_ie_p2_pie_opaque( + tpAniSirGlobal, + tDot11fIEP2PIEOpaque *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_P2PIEOpaque( + tpAniSirGlobal, + tDot11fIEP2PIEOpaque *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 221 (0xdd) {OUI 0x50, 0x6f, 0x9a, 0x09} (Multi-IE) */ +typedef struct sDot11fIEP2PProbeReq { + uint8_t present; + tDot11fTLVP2PCapability P2PCapability; + tDot11fTLVP2PDeviceId P2PDeviceId; + tDot11fTLVListenChannel ListenChannel; + tDot11fTLVExtendedListenTiming ExtendedListenTiming; + tDot11fTLVOperatingChannel OperatingChannel; +} tDot11fIEP2PProbeReq; + +#define DOT11F_EID_P2PPROBEREQ (221) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_P2PPROBEREQ_MIN_LEN (4) + +#define DOT11F_IE_P2PPROBEREQ_MAX_LEN (41) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_p2_p_probe_req( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEP2PProbeReq*); + +uint32_t dot11f_pack_ie_p2_p_probe_req( + tpAniSirGlobal, + tDot11fIEP2PProbeReq *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_iep2_p_probe_req( + tpAniSirGlobal, + tDot11fIEP2PProbeReq *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 221 (0xdd) {OUI 0x50, 0x6f, 0x9a, 0x09} (Multi-IE) */ +typedef struct sDot11fIEP2PProbeRes { + uint8_t present; + tDot11fTLVP2PCapability P2PCapability; + tDot11fTLVExtendedListenTiming ExtendedListenTiming; + tDot11fTLVNoticeOfAbsence NoticeOfAbsence; + tDot11fTLVP2PDeviceInfo P2PDeviceInfo; + tDot11fTLVP2PGroupInfo P2PGroupInfo; +} tDot11fIEP2PProbeRes; + +#define DOT11F_EID_P2PPROBERES (221) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_P2PPROBERES_MIN_LEN (4) + +#define DOT11F_IE_P2PPROBERES_MAX_LEN (1139) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_p2_p_probe_res( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEP2PProbeRes*); + +uint32_t dot11f_pack_ie_p2_p_probe_res( + tpAniSirGlobal, + tDot11fIEP2PProbeRes *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_iep2_p_probe_res( + tpAniSirGlobal, + tDot11fIEP2PProbeRes *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 105 (0x69) */ +typedef struct sDot11fIEPTIControl { + uint8_t present; + uint8_t tid; + uint16_t sequence_control; +} tDot11fIEPTIControl; + +#define DOT11F_EID_PTICONTROL (105) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_PTICONTROL_MIN_LEN (3) + +#define DOT11F_IE_PTICONTROL_MAX_LEN (3) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_pti_control( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEPTIControl*); + +uint32_t dot11f_pack_ie_pti_control( + tpAniSirGlobal, + tDot11fIEPTIControl *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_PTIControl( + tpAniSirGlobal, + tDot11fIEPTIControl *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 106 (0x6a) */ +typedef struct sDot11fIEPUBufferStatus { + uint8_t present; + uint8_t ac_bk_traffic_aval:1; + uint8_t ac_be_traffic_aval:1; + uint8_t ac_vi_traffic_aval:1; + uint8_t ac_vo_traffic_aval:1; + uint8_t reserved:4; +} tDot11fIEPUBufferStatus; + +#define DOT11F_EID_PUBUFFERSTATUS (106) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_PUBUFFERSTATUS_MIN_LEN (1) + +#define DOT11F_IE_PUBUFFERSTATUS_MAX_LEN (1) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_pu_buffer_status( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEPUBufferStatus*); + +uint32_t dot11f_pack_ie_pu_buffer_status( + tpAniSirGlobal, + tDot11fIEPUBufferStatus *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_PUBufferStatus( + tpAniSirGlobal, + tDot11fIEPUBufferStatus *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 33 (0x21) */ +typedef struct sDot11fIEPowerCaps { + uint8_t present; + uint8_t minTxPower; + uint8_t maxTxPower; +} tDot11fIEPowerCaps; + +#define DOT11F_EID_POWERCAPS (33) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_POWERCAPS_MIN_LEN (2) + +#define DOT11F_IE_POWERCAPS_MAX_LEN (2) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_power_caps( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEPowerCaps*); + +uint32_t dot11f_pack_ie_power_caps( + tpAniSirGlobal, + tDot11fIEPowerCaps *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_PowerCaps( + tpAniSirGlobal, + tDot11fIEPowerCaps *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 32 (0x20) */ +typedef struct sDot11fIEPowerConstraints { + uint8_t present; + uint8_t localPowerConstraints; +} tDot11fIEPowerConstraints; + +#define DOT11F_EID_POWERCONSTRAINTS (32) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_POWERCONSTRAINTS_MIN_LEN (1) + +#define DOT11F_IE_POWERCONSTRAINTS_MAX_LEN (1) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_power_constraints( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEPowerConstraints*); + +uint32_t dot11f_pack_ie_power_constraints( + tpAniSirGlobal, + tDot11fIEPowerConstraints *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_PowerConstraints( + tpAniSirGlobal, + tDot11fIEPowerConstraints *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 11 (0x0b) */ +typedef struct sDot11fIEQBSSLoad { + uint8_t present; + uint16_t stacount; + uint8_t chautil; + uint16_t avail; +} tDot11fIEQBSSLoad; + +#define DOT11F_EID_QBSSLOAD (11) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_QBSSLOAD_MIN_LEN (5) + +#define DOT11F_IE_QBSSLOAD_MAX_LEN (5) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_qbss_load( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEQBSSLoad*); + +uint32_t dot11f_pack_ie_qbss_load( + tpAniSirGlobal, + tDot11fIEQBSSLoad *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_QBSSLoad( + tpAniSirGlobal, + tDot11fIEQBSSLoad *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 221 (0xdd) {OUI 0x8c, 0xfd, 0xf0, 0x01} */ +typedef struct sDot11fIEQCN_IE { + uint8_t present; + uint8_t version[4]; +} tDot11fIEQCN_IE; + +#define DOT11F_EID_QCN_IE (221) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_QCN_IE_MIN_LEN (8) + +#define DOT11F_IE_QCN_IE_MAX_LEN (8) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_QCN_IE( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEQCN_IE*); + +uint32_t dot11f_pack_ie_QCN_IE( + tpAniSirGlobal, + tDot11fIEQCN_IE *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_QCN_IE( + tpAniSirGlobal, + tDot11fIEQCN_IE *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 221 (0xdd) {OUI 0x00, 0xa0, 0xc6} */ +typedef struct sDot11fIEQComVendorIE { + uint8_t present; + uint8_t type; + uint8_t channel; +} tDot11fIEQComVendorIE; + +#define DOT11F_EID_QCOMVENDORIE (221) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_QCOMVENDORIE_MIN_LEN (5) + +#define DOT11F_IE_QCOMVENDORIE_MAX_LEN (5) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_QComVendorIE( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEQComVendorIE*); + +uint32_t dot11f_pack_ie_QComVendorIE( + tpAniSirGlobal, + tDot11fIEQComVendorIE *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_QComVendorIE( + tpAniSirGlobal, + tDot11fIEQComVendorIE *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 46 (0x2e) */ +typedef struct sDot11fIEQOSCapsAp { + uint8_t present; + uint8_t count:4; + uint8_t qack:1; + uint8_t qreq:1; + uint8_t txopreq:1; + uint8_t reserved:1; +} tDot11fIEQOSCapsAp; + +#define DOT11F_EID_QOSCAPSAP (46) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_QOSCAPSAP_MIN_LEN (1) + +#define DOT11F_IE_QOSCAPSAP_MAX_LEN (1) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_qos_caps_ap( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEQOSCapsAp*); + +uint32_t dot11f_pack_ie_qos_caps_ap( + tpAniSirGlobal, + tDot11fIEQOSCapsAp *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_QOSCapsAp( + tpAniSirGlobal, + tDot11fIEQOSCapsAp *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 46 (0x2e) */ +typedef struct sDot11fIEQOSCapsStation { + uint8_t present; + uint8_t acvo_uapsd:1; + uint8_t acvi_uapsd:1; + uint8_t acbk_uapsd:1; + uint8_t acbe_uapsd:1; + uint8_t qack:1; + uint8_t max_sp_length:2; + uint8_t more_data_ack:1; +} tDot11fIEQOSCapsStation; + +#define DOT11F_EID_QOSCAPSSTATION (46) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_QOSCAPSSTATION_MIN_LEN (1) + +#define DOT11F_IE_QOSCAPSSTATION_MAX_LEN (1) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_qos_caps_station( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEQOSCapsStation*); + +uint32_t dot11f_pack_ie_qos_caps_station( + tpAniSirGlobal, + tDot11fIEQOSCapsStation *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_QOSCapsStation( + tpAniSirGlobal, + tDot11fIEQOSCapsStation *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 110 (0x6e) */ +typedef struct sDot11fIEQosMapSet { + uint8_t present; + uint8_t num_dscp_exceptions; + uint8_t dscp_exceptions[60]; +} tDot11fIEQosMapSet; + +#define DOT11F_EID_QOSMAPSET (110) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_QOSMAPSET_MIN_LEN (0) + +#define DOT11F_IE_QOSMAPSET_MAX_LEN (60) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_qos_map_set( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEQosMapSet*); + +uint32_t dot11f_pack_ie_qos_map_set( + tpAniSirGlobal, + tDot11fIEQosMapSet *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_QosMapSet( + tpAniSirGlobal, + tDot11fIEQosMapSet *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 40 (0x28) */ +typedef struct sDot11fIEQuiet { + uint8_t present; + uint8_t count; + uint8_t period; + uint16_t duration; + uint16_t offset; +} tDot11fIEQuiet; + +#define DOT11F_EID_QUIET (40) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_QUIET_MIN_LEN (6) + +#define DOT11F_IE_QUIET_MAX_LEN (6) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_quiet( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEQuiet*); + +uint32_t dot11f_pack_ie_quiet( + tpAniSirGlobal, + tDot11fIEQuiet *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_Quiet( + tpAniSirGlobal, + tDot11fIEQuiet *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 53 (0x35) */ +typedef struct sDot11fIERCPIIE { + uint8_t present; + uint8_t rcpi; +} tDot11fIERCPIIE; + +#define DOT11F_EID_RCPIIE (53) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_RCPIIE_MIN_LEN (1) + +#define DOT11F_IE_RCPIIE_MAX_LEN (1) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_rcpiie( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIERCPIIE*); + +uint32_t dot11f_pack_ie_rcpiie( + tpAniSirGlobal, + tDot11fIERCPIIE *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_RCPIIE( + tpAniSirGlobal, + tDot11fIERCPIIE *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 57 (0x39) */ +typedef struct sDot11fIERICDataDesc { + uint8_t present; + tDot11fIERICData RICData; + tDot11fIERICDescriptor RICDescriptor; + tDot11fIETSPEC TSPEC; + uint16_t num_TCLAS; + tDot11fIETCLAS TCLAS[2]; + tDot11fIETCLASSPROC TCLASSPROC; + tDot11fIETSDelay TSDelay; + tDot11fIESchedule Schedule; + tDot11fIEWMMTSPEC WMMTSPEC; + uint16_t num_WMMTCLAS; + tDot11fIEWMMTCLAS WMMTCLAS[2]; + tDot11fIEWMMTCLASPROC WMMTCLASPROC; + tDot11fIEWMMTSDelay WMMTSDelay; + tDot11fIEWMMSchedule WMMSchedule; +} tDot11fIERICDataDesc; + +#define DOT11F_EID_RICDATADESC (57) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_RICDATADESC_MIN_LEN (0) + +#define DOT11F_IE_RICDATADESC_MAX_LEN (548) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_ric_data_desc( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIERICDataDesc*); + +uint32_t dot11f_pack_ie_ric_data_desc( + tpAniSirGlobal, + tDot11fIERICDataDesc *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ieric_data_desc( + tpAniSirGlobal, + tDot11fIERICDataDesc *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 48 (0x30) */ +typedef struct sDot11fIERSN { + uint8_t present; + uint16_t version /* Must be 1! */; + uint8_t gp_cipher_suite[4]; + uint16_t pwise_cipher_suite_count; + uint8_t pwise_cipher_suites[4][4]; + uint16_t akm_suite_count; + uint8_t akm_suites[4][4]; + uint8_t RSN_Cap[2]; + uint16_t pmkid_count; + uint8_t pmkid[4][16]; + uint8_t gp_mgmt_cipher_suite[4]; +} tDot11fIERSN; + +#define DOT11F_EID_RSN (48) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_RSN_MIN_LEN (6) + +#define DOT11F_IE_RSN_MAX_LEN (114) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_rsn( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIERSN*); + +uint32_t dot11f_pack_ie_rsn( + tpAniSirGlobal, + tDot11fIERSN *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_iersn( + tpAniSirGlobal, + tDot11fIERSN *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 65 (0x41) */ +typedef struct sDot11fIERSNIIE { + uint8_t present; + uint8_t rsni; +} tDot11fIERSNIIE; + +#define DOT11F_EID_RSNIIE (65) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_RSNIIE_MIN_LEN (1) + +#define DOT11F_IE_RSNIIE_MAX_LEN (1) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_rsniie( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIERSNIIE*); + +uint32_t dot11f_pack_ie_rsniie( + tpAniSirGlobal, + tDot11fIERSNIIE *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_iersnIIE( + tpAniSirGlobal, + tDot11fIERSNIIE *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 48 (0x30) */ +typedef struct sDot11fIERSNOpaque { + uint8_t present; + uint8_t num_data; + uint8_t data[253]; +} tDot11fIERSNOpaque; + +#define DOT11F_EID_RSNOPAQUE (48) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_RSNOPAQUE_MIN_LEN (6) + +#define DOT11F_IE_RSNOPAQUE_MAX_LEN (253) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_rsn_opaque( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIERSNOpaque*); + +uint32_t dot11f_pack_ie_rsn_opaque( + tpAniSirGlobal, + tDot11fIERSNOpaque *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_iersnOpaque( + tpAniSirGlobal, + tDot11fIERSNOpaque *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 36 (0x24) */ +typedef struct sDot11fIESuppChannels { + uint8_t present; + uint8_t num_bands; + uint8_t bands[48][2]; +} tDot11fIESuppChannels; + +#define DOT11F_EID_SUPPCHANNELS (36) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_SUPPCHANNELS_MIN_LEN (2) + +#define DOT11F_IE_SUPPCHANNELS_MAX_LEN (96) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_supp_channels( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIESuppChannels*); + +uint32_t dot11f_pack_ie_supp_channels( + tpAniSirGlobal, + tDot11fIESuppChannels *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_SuppChannels( + tpAniSirGlobal, + tDot11fIESuppChannels *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 59 (0x3b) */ +typedef struct sDot11fIESuppOperatingClasses { + uint8_t present; + uint8_t num_classes; + uint8_t classes[32]; +} tDot11fIESuppOperatingClasses; + +#define DOT11F_EID_SUPPOPERATINGCLASSES (59) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_SUPPOPERATINGCLASSES_MIN_LEN (1) + +#define DOT11F_IE_SUPPOPERATINGCLASSES_MAX_LEN (32) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_supp_operating_classes( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIESuppOperatingClasses*); + +uint32_t dot11f_pack_ie_supp_operating_classes( + tpAniSirGlobal, + tDot11fIESuppOperatingClasses *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_SuppOperatingClasses( + tpAniSirGlobal, + tDot11fIESuppOperatingClasses *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 1 (0x01) */ +typedef struct sDot11fIESuppRates { + uint8_t present; + uint8_t num_rates; + uint8_t rates[12]; +} tDot11fIESuppRates; + +#define DOT11F_EID_SUPPRATES (1) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_SUPPRATES_MIN_LEN (0) + +#define DOT11F_IE_SUPPRATES_MAX_LEN (12) + +#define DOT11F_IS_BG_RATE(_x) (((_x) == 02) || \ + ((_x) == 04) || \ + ((_x) == 11) || \ + ((_x) == 22) || \ + ((_x) == 12) || \ + ((_x) == 18) || \ + ((_x) == 24) || \ + ((_x) == 36) || \ + ((_x) == 48) || \ + ((_x) == 72) || \ + ((_x) == 96) || \ + ((_x) == 108)) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_supp_rates( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIESuppRates*); + +uint32_t dot11f_pack_ie_supp_rates( + tpAniSirGlobal, + tDot11fIESuppRates *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_SuppRates( + tpAniSirGlobal, + tDot11fIESuppRates *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 5 (0x05) */ +typedef struct sDot11fIETIM { + uint8_t present; + uint8_t dtim_count; + uint8_t dtim_period; + uint8_t bmpctl; + uint8_t num_vbmp; + uint8_t vbmp[251]; +} tDot11fIETIM; + +#define DOT11F_EID_TIM (5) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_TIM_MIN_LEN (4) + +#define DOT11F_IE_TIM_MAX_LEN (254) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_tim( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIETIM*); + +uint32_t dot11f_pack_ie_tim( + tpAniSirGlobal, + tDot11fIETIM *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_TIM( + tpAniSirGlobal, + tDot11fIETIM *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 35 (0x23) */ +typedef struct sDot11fIETPCReport { + uint8_t present; + uint8_t tx_power; + uint8_t link_margin; +} tDot11fIETPCReport; + +#define DOT11F_EID_TPCREPORT (35) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_TPCREPORT_MIN_LEN (2) + +#define DOT11F_IE_TPCREPORT_MAX_LEN (2) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_tpc_report( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIETPCReport*); + +uint32_t dot11f_pack_ie_tpc_report( + tpAniSirGlobal, + tDot11fIETPCReport *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_TPCReport( + tpAniSirGlobal, + tDot11fIETPCReport *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 34 (0x22) */ +typedef struct sDot11fIETPCRequest { + uint8_t present; +} tDot11fIETPCRequest; + +#define DOT11F_EID_TPCREQUEST (34) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_TPCREQUEST_MIN_LEN (0) + +#define DOT11F_IE_TPCREQUEST_MAX_LEN (0) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_tpc_request( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIETPCRequest*); + +uint32_t dot11f_pack_ie_tpc_request( + tpAniSirGlobal, + tDot11fIETPCRequest *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_TPCRequest( + tpAniSirGlobal, + tDot11fIETPCRequest *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 69 (0x45) */ +typedef struct sDot11fIETimeAdvertisement { + uint8_t present; + uint8_t timing_capabilities; + uint8_t time_value[10]; + uint8_t time_error[5]; +} tDot11fIETimeAdvertisement; + +#define DOT11F_EID_TIMEADVERTISEMENT (69) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_TIMEADVERTISEMENT_MIN_LEN (16) + +#define DOT11F_IE_TIMEADVERTISEMENT_MAX_LEN (16) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_time_advertisement( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIETimeAdvertisement*); + +uint32_t dot11f_pack_ie_time_advertisement( + tpAniSirGlobal, + tDot11fIETimeAdvertisement *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_time_advertisement( + tpAniSirGlobal, + tDot11fIETimeAdvertisement *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 56 (0x38) */ +typedef struct sDot11fIETimeoutInterval { + uint8_t present; + uint8_t timeoutType; + uint32_t timeoutValue; +} tDot11fIETimeoutInterval; + +#define DOT11F_EID_TIMEOUTINTERVAL (56) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_TIMEOUTINTERVAL_MIN_LEN (5) + +#define DOT11F_IE_TIMEOUTINTERVAL_MAX_LEN (5) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_timeout_interval( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIETimeoutInterval*); + +uint32_t dot11f_pack_ie_timeout_interval( + tpAniSirGlobal, + tDot11fIETimeoutInterval *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_TimeoutInterval( + tpAniSirGlobal, + tDot11fIETimeoutInterval *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 193 (0xc1) */ +typedef struct sDot11fIEVHTExtBssLoad { + uint8_t present; + uint8_t muMIMOCapStaCount; + uint8_t ssUnderUtil; + uint8_t FortyMHzUtil; + uint8_t EightyMHzUtil; + uint8_t OneSixtyMHzUtil; +} tDot11fIEVHTExtBssLoad; + +#define DOT11F_EID_VHTEXTBSSLOAD (193) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_VHTEXTBSSLOAD_MIN_LEN (5) + +#define DOT11F_IE_VHTEXTBSSLOAD_MAX_LEN (5) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_vht_ext_bss_load( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEVHTExtBssLoad*); + +uint32_t dot11f_pack_ie_vht_ext_bss_load( + tpAniSirGlobal, + tDot11fIEVHTExtBssLoad *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_VHTExtBssLoad( + tpAniSirGlobal, + tDot11fIEVHTExtBssLoad *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 221 (0xdd) {OUI 0x00, 0x10, 0x18} */ +typedef struct sDot11fIEVendor1IE { + uint8_t present; +} tDot11fIEVendor1IE; + +#define DOT11F_EID_VENDOR1IE (221) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_VENDOR1IE_MIN_LEN (3) + +#define DOT11F_IE_VENDOR1IE_MAX_LEN (3) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_vendor1_ie( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEVendor1IE*); + +uint32_t dot11f_pack_ie_vendor1_ie( + tpAniSirGlobal, + tDot11fIEVendor1IE *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_Vendor1IE( + tpAniSirGlobal, + tDot11fIEVendor1IE *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 221 (0xdd) {OUI 0x00, 0x16, 0x32} */ +typedef struct sDot11fIEVendor3IE { + uint8_t present; +} tDot11fIEVendor3IE; + +#define DOT11F_EID_VENDOR3IE (221) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_VENDOR3IE_MIN_LEN (3) + +#define DOT11F_IE_VENDOR3IE_MAX_LEN (3) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_vendor3_ie( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEVendor3IE*); + +uint32_t dot11f_pack_ie_vendor3_ie( + tpAniSirGlobal, + tDot11fIEVendor3IE *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_Vendor3IE( + tpAniSirGlobal, + tDot11fIEVendor3IE *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 68 (0x44) */ +typedef struct sDot11fIEWAPI { + uint8_t present; + uint16_t version /* Must be 1! */; + uint16_t akm_suite_count; + uint8_t akm_suites[4][4]; + uint16_t unicast_cipher_suite_count; + uint8_t unicast_cipher_suites[4][4]; + uint8_t multicast_cipher_suite[4]; + uint16_t preauth:1; + uint16_t reserved:15; + uint16_t bkid_count; + uint8_t bkid[4][16]; +} tDot11fIEWAPI; + +#define DOT11F_EID_WAPI (68) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_WAPI_MIN_LEN (12) + +#define DOT11F_IE_WAPI_MAX_LEN (110) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_wapi( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEWAPI*); + +uint32_t dot11f_pack_ie_wapi( + tpAniSirGlobal, + tDot11fIEWAPI *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_iewapi( + tpAniSirGlobal, + tDot11fIEWAPI *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 68 (0x44) */ +typedef struct sDot11fIEWAPIOpaque { + uint8_t present; + uint8_t num_data; + uint8_t data[253]; +} tDot11fIEWAPIOpaque; + +#define DOT11F_EID_WAPIOPAQUE (68) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_WAPIOPAQUE_MIN_LEN (6) + +#define DOT11F_IE_WAPIOPAQUE_MAX_LEN (253) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_wapi_opaque( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEWAPIOpaque*); + +uint32_t dot11f_pack_ie_wapi_opaque( + tpAniSirGlobal, + tDot11fIEWAPIOpaque *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_iewapiOpaque( + tpAniSirGlobal, + tDot11fIEWAPIOpaque *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 221 (0xdd) {OUI 0x00, 0x50, 0xf2, 0x08, 0x00} */ +typedef struct sDot11fIEWFATPC { + uint8_t present; + uint8_t txPower; + uint8_t linkMargin; +} tDot11fIEWFATPC; + +#define DOT11F_EID_WFATPC (221) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_WFATPC_MIN_LEN (7) + +#define DOT11F_IE_WFATPC_MAX_LEN (7) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_wfatpc( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEWFATPC*); + +uint32_t dot11f_pack_ie_wfatpc( + tpAniSirGlobal, + tDot11fIEWFATPC *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_WFATPC( + tpAniSirGlobal, + tDot11fIEWFATPC *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 221 (0xdd) {OUI 0x50, 0x6f, 0x9a, 0x0a} */ +typedef struct sDot11fIEWFDIEOpaque { + uint8_t present; + uint8_t num_data; + uint8_t data[249]; +} tDot11fIEWFDIEOpaque; + +#define DOT11F_EID_WFDIEOPAQUE (221) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_WFDIEOPAQUE_MIN_LEN (6) + +#define DOT11F_IE_WFDIEOPAQUE_MAX_LEN (253) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_wfdie_opaque( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEWFDIEOpaque*); + +uint32_t dot11f_pack_ie_wfdie_opaque( + tpAniSirGlobal, + tDot11fIEWFDIEOpaque *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_WFDIEOpaque( + tpAniSirGlobal, + tDot11fIEWFDIEOpaque *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 221 (0xdd) {OUI 0x00, 0x50, 0xf2, 0x02, 0x05} */ +typedef struct sDot11fIEWMMCaps { + uint8_t present; + uint8_t version /* Must be 1! */; + uint8_t reserved:4; + uint8_t qack:1; + uint8_t queue_request:1; + uint8_t txop_request:1; + uint8_t more_ack:1; +} tDot11fIEWMMCaps; + +#define DOT11F_EID_WMMCAPS (221) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_WMMCAPS_MIN_LEN (7) + +#define DOT11F_IE_WMMCAPS_MAX_LEN (7) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_wmm_caps( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEWMMCaps*); + +uint32_t dot11f_pack_ie_wmm_caps( + tpAniSirGlobal, + tDot11fIEWMMCaps *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_WMMCaps( + tpAniSirGlobal, + tDot11fIEWMMCaps *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 221 (0xdd) {OUI 0x00, 0x50, 0xf2, 0x02, 0x00} */ +typedef struct sDot11fIEWMMInfoAp { + uint8_t present; + uint8_t version; + uint8_t param_set_count:4; + uint8_t reserved:3; + uint8_t uapsd:1; +} tDot11fIEWMMInfoAp; + +#define DOT11F_EID_WMMINFOAP (221) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_WMMINFOAP_MIN_LEN (7) + +#define DOT11F_IE_WMMINFOAP_MAX_LEN (7) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_wmm_info_ap( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEWMMInfoAp*); + +uint32_t dot11f_pack_ie_wmm_info_ap( + tpAniSirGlobal, + tDot11fIEWMMInfoAp *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_WMMInfoAp( + tpAniSirGlobal, + tDot11fIEWMMInfoAp *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 221 (0xdd) {OUI 0x00, 0x50, 0xf2, 0x02, 0x00} */ +typedef struct sDot11fIEWMMInfoStation { + uint8_t present; + uint8_t version; + uint8_t acvo_uapsd:1; + uint8_t acvi_uapsd:1; + uint8_t acbk_uapsd:1; + uint8_t acbe_uapsd:1; + uint8_t reserved1:1; + uint8_t max_sp_length:2; + uint8_t reserved2:1; +} tDot11fIEWMMInfoStation; + +#define DOT11F_EID_WMMINFOSTATION (221) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_WMMINFOSTATION_MIN_LEN (7) + +#define DOT11F_IE_WMMINFOSTATION_MAX_LEN (7) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_wmm_info_station( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEWMMInfoStation*); + +uint32_t dot11f_pack_ie_wmm_info_station( + tpAniSirGlobal, + tDot11fIEWMMInfoStation *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_WMMInfoStation( + tpAniSirGlobal, + tDot11fIEWMMInfoStation *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 221 (0xdd) {OUI 0x00, 0x50, 0xf2, 0x02, 0x01} */ +typedef struct sDot11fIEWMMParams { + uint8_t present; + uint8_t version /* Must be 1! */; + uint8_t qosInfo; + uint8_t reserved2; + uint8_t acbe_aifsn:4; + uint8_t acbe_acm:1; + uint8_t acbe_aci:2; + uint8_t unused1:1; + uint8_t acbe_acwmin:4; + uint8_t acbe_acwmax:4; + uint16_t acbe_txoplimit; + uint8_t acbk_aifsn:4; + uint8_t acbk_acm:1; + uint8_t acbk_aci:2; + uint8_t unused2:1; + uint8_t acbk_acwmin:4; + uint8_t acbk_acwmax:4; + uint16_t acbk_txoplimit; + uint8_t acvi_aifsn:4; + uint8_t acvi_acm:1; + uint8_t acvi_aci:2; + uint8_t unused3:1; + uint8_t acvi_acwmin:4; + uint8_t acvi_acwmax:4; + uint16_t acvi_txoplimit; + uint8_t acvo_aifsn:4; + uint8_t acvo_acm:1; + uint8_t acvo_aci:2; + uint8_t unused4:1; + uint8_t acvo_acwmin:4; + uint8_t acvo_acwmax:4; + uint16_t acvo_txoplimit; +} tDot11fIEWMMParams; + +#define DOT11F_EID_WMMPARAMS (221) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_WMMPARAMS_MIN_LEN (24) + +#define DOT11F_IE_WMMPARAMS_MAX_LEN (24) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_wmm_params( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEWMMParams*); + +uint32_t dot11f_pack_ie_wmm_params( + tpAniSirGlobal, + tDot11fIEWMMParams *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_WMMParams( + tpAniSirGlobal, + tDot11fIEWMMParams *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 221 (0xdd) {OUI 0x00, 0x50, 0xf2, 0x01} */ +typedef struct sDot11fIEWPA { + uint8_t present; + uint16_t version /* Must be 1! */; + /* field added to fix the bug in dot11fPackIEWPA */ + uint8_t multicast_cipher_present; + uint8_t multicast_cipher[4]; + uint16_t unicast_cipher_count; + uint8_t unicast_ciphers[4][4]; + uint16_t auth_suite_count; + uint8_t auth_suites[4][4]; + uint16_t caps; +} tDot11fIEWPA; + +#define DOT11F_EID_WPA (221) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_WPA_MIN_LEN (6) + +#define DOT11F_IE_WPA_MAX_LEN (48) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_wpa( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEWPA*); + +uint32_t dot11f_pack_ie_wpa( + tpAniSirGlobal, + tDot11fIEWPA *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_iewpa( + tpAniSirGlobal, + tDot11fIEWPA *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 221 (0xdd) {OUI 0x00, 0x50, 0xf2, 0x01} */ +typedef struct sDot11fIEWPAOpaque { + uint8_t present; + uint8_t num_data; + uint8_t data[249]; +} tDot11fIEWPAOpaque; + +#define DOT11F_EID_WPAOPAQUE (221) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_WPAOPAQUE_MIN_LEN (6) + +#define DOT11F_IE_WPAOPAQUE_MAX_LEN (253) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_wpa_opaque( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEWPAOpaque*); + +uint32_t dot11f_pack_ie_wpa_opaque( + tpAniSirGlobal, + tDot11fIEWPAOpaque *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_iewpaOpaque( + tpAniSirGlobal, + tDot11fIEWPAOpaque *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 221 (0xdd) {OUI 0x00, 0x50, 0xf2, 0x04} (Multi-IE) */ +typedef struct sDot11fIEWSC { + uint8_t present; + tDot11fTLVVersion Version; + tDot11fTLVWPSState WPSState; + tDot11fTLVAPSetupLocked APSetupLocked; + tDot11fTLVSelectedRegistrarConfigMethods SelectedRegistrarConfigMethods; + tDot11fTLVUUID_E UUID_E; + tDot11fTLVUUID_R UUID_R; + tDot11fTLVRFBands RFBands; + tDot11fTLVSelectedRegistrar SelectedRegistrar; + tDot11fTLVConfigMethods ConfigMethods; + tDot11fTLVAssociationState AssociationState; + tDot11fTLVConfigurationError ConfigurationError; + tDot11fTLVManufacturer Manufacturer; + tDot11fTLVModelName ModelName; + tDot11fTLVModelNumber ModelNumber; + tDot11fTLVSerialNumber SerialNumber; + tDot11fTLVDeviceName DeviceName; + tDot11fTLVDevicePasswordID DevicePasswordID; + tDot11fTLVPrimaryDeviceType PrimaryDeviceType; + tDot11fTLVRequestType RequestType; + tDot11fTLVResponseType ResponseType; + tDot11fTLVVendorExtension VendorExtension; + tDot11fTLVRequestDeviceType RequestDeviceType; +} tDot11fIEWSC; + +#define DOT11F_EID_WSC (221) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_WSC_MIN_LEN (4) + +#define DOT11F_IE_WSC_MAX_LEN (366) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_wsc( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEWSC*); + +uint32_t dot11f_pack_ie_wsc( + tpAniSirGlobal, + tDot11fIEWSC *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_iewsc( + tpAniSirGlobal, + tDot11fIEWSC *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 221 (0xdd) {OUI 0x00, 0x50, 0xf2, 0x04} (Multi-IE) */ +typedef struct sDot11fIEWscAssocReq { + uint8_t present; + tDot11fTLVVersion Version; + tDot11fTLVRequestType RequestType; + tDot11fTLVVendorExtension VendorExtension; +} tDot11fIEWscAssocReq; + +#define DOT11F_EID_WSCASSOCREQ (221) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_WSCASSOCREQ_MIN_LEN (4) + +#define DOT11F_IE_WSCASSOCREQ_MAX_LEN (35) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_wsc_assoc_req( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEWscAssocReq*); + +uint32_t dot11f_pack_ie_wsc_assoc_req( + tpAniSirGlobal, + tDot11fIEWscAssocReq *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_wsc_assoc_req( + tpAniSirGlobal, + tDot11fIEWscAssocReq *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 221 (0xdd) {OUI 0x00, 0x50, 0xf2, 0x04} (Multi-IE) */ +typedef struct sDot11fIEWscAssocRes { + uint8_t present; + tDot11fTLVVersion Version; + tDot11fTLVResponseType ResponseType; + tDot11fTLVVendorExtension VendorExtension; +} tDot11fIEWscAssocRes; + +#define DOT11F_EID_WSCASSOCRES (221) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_WSCASSOCRES_MIN_LEN (4) + +#define DOT11F_IE_WSCASSOCRES_MAX_LEN (35) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_wsc_assoc_res( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEWscAssocRes*); + +uint32_t dot11f_pack_ie_wsc_assoc_res( + tpAniSirGlobal, + tDot11fIEWscAssocRes *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_wsc_assoc_res( + tpAniSirGlobal, + tDot11fIEWscAssocRes *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 221 (0xdd) {OUI 0x00, 0x50, 0xf2, 0x04} (Multi-IE) */ +typedef struct sDot11fIEWscBeacon { + uint8_t present; + tDot11fTLVVersion Version; + tDot11fTLVWPSState WPSState; + tDot11fTLVAPSetupLocked APSetupLocked; + tDot11fTLVSelectedRegistrar SelectedRegistrar; + tDot11fTLVDevicePasswordID DevicePasswordID; + tDot11fTLVSelectedRegistrarConfigMethods SelectedRegistrarConfigMethods; + tDot11fTLVUUID_E UUID_E; + tDot11fTLVRFBands RFBands; + tDot11fTLVVendorExtension VendorExtension; +} tDot11fIEWscBeacon; + +#define DOT11F_EID_WSCBEACON (221) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_WSCBEACON_MIN_LEN (4) + +#define DOT11F_IE_WSCBEACON_MAX_LEN (82) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_wsc_beacon( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEWscBeacon*); + +uint32_t dot11f_pack_ie_wsc_beacon( + tpAniSirGlobal, + tDot11fIEWscBeacon *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_wsc_beacon( + tpAniSirGlobal, + tDot11fIEWscBeacon *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 221 (0xdd) {OUI 0x00, 0x50, 0xf2, 0x04} (Multi-IE) */ +typedef struct sDot11fIEWscBeaconProbeRes { + uint8_t present; + tDot11fTLVVersion Version; + tDot11fTLVWPSState WPSState; + tDot11fTLVAPSetupLocked APSetupLocked; + tDot11fTLVSelectedRegistrar SelectedRegistrar; + tDot11fTLVDevicePasswordID DevicePasswordID; + tDot11fTLVSelectedRegistrarConfigMethods SelectedRegistrarConfigMethods; + tDot11fTLVResponseType ResponseType; + tDot11fTLVUUID_E UUID_E; + tDot11fTLVManufacturer Manufacturer; + tDot11fTLVModelName ModelName; + tDot11fTLVModelNumber ModelNumber; + tDot11fTLVSerialNumber SerialNumber; + tDot11fTLVPrimaryDeviceType PrimaryDeviceType; + tDot11fTLVDeviceName DeviceName; + tDot11fTLVConfigMethods ConfigMethods; + tDot11fTLVRFBands RFBands; + tDot11fTLVVendorExtension VendorExtension; +} tDot11fIEWscBeaconProbeRes; + +#define DOT11F_EID_WSCBEACONPROBERES (221) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_WSCBEACONPROBERES_MIN_LEN (4) + +#define DOT11F_IE_WSCBEACONPROBERES_MAX_LEN (317) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_wsc_beacon_probe_res( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEWscBeaconProbeRes*); + +uint32_t dot11f_pack_ie_wsc_beacon_probe_res( + tpAniSirGlobal, + tDot11fIEWscBeaconProbeRes *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_wsc_beacon_probe_res( + tpAniSirGlobal, + tDot11fIEWscBeaconProbeRes *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 221 (0xdd) {OUI 0x00, 0x50, 0xf2, 0x04} */ +typedef struct sDot11fIEWscIEOpaque { + uint8_t present; + uint8_t num_data; + uint8_t data[249]; +} tDot11fIEWscIEOpaque; + +#define DOT11F_EID_WSCIEOPAQUE (221) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_WSCIEOPAQUE_MIN_LEN (6) + +#define DOT11F_IE_WSCIEOPAQUE_MAX_LEN (253) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_wsc_ie_opaque( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEWscIEOpaque*); + +uint32_t dot11f_pack_ie_wsc_ie_opaque( + tpAniSirGlobal, + tDot11fIEWscIEOpaque *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_WscIEOpaque( + tpAniSirGlobal, + tDot11fIEWscIEOpaque *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 221 (0xdd) {OUI 0x00, 0x50, 0xf2, 0x04} (Multi-IE) */ +typedef struct sDot11fIEWscProbeReq { + uint8_t present; + tDot11fTLVVersion Version; + tDot11fTLVRequestType RequestType; + tDot11fTLVConfigMethods ConfigMethods; + tDot11fTLVUUID_E UUID_E; + tDot11fTLVPrimaryDeviceType PrimaryDeviceType; + tDot11fTLVRFBands RFBands; + tDot11fTLVAssociationState AssociationState; + tDot11fTLVConfigurationError ConfigurationError; + tDot11fTLVDevicePasswordID DevicePasswordID; + tDot11fTLVManufacturer Manufacturer; + tDot11fTLVModelName ModelName; + tDot11fTLVModelNumber ModelNumber; + tDot11fTLVDeviceName DeviceName; + tDot11fTLVVendorExtension VendorExtension; + tDot11fTLVRequestDeviceType RequestDeviceType; +} tDot11fIEWscProbeReq; + +#define DOT11F_EID_WSCPROBEREQ (221) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_WSCPROBEREQ_MIN_LEN (4) + +#define DOT11F_IE_WSCPROBEREQ_MAX_LEN (284) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_wsc_probe_req( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEWscProbeReq*); + +uint32_t dot11f_pack_ie_wsc_probe_req( + tpAniSirGlobal, + tDot11fIEWscProbeReq *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_wsc_probe_req( + tpAniSirGlobal, + tDot11fIEWscProbeReq *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 221 (0xdd) {OUI 0x00, 0x50, 0xf2, 0x04} (Multi-IE) */ +typedef struct sDot11fIEWscProbeRes { + uint8_t present; + tDot11fTLVVersion Version; + tDot11fTLVWPSState WPSState; + tDot11fTLVAPSetupLocked APSetupLocked; + tDot11fTLVSelectedRegistrar SelectedRegistrar; + tDot11fTLVDevicePasswordID DevicePasswordID; + tDot11fTLVSelectedRegistrarConfigMethods SelectedRegistrarConfigMethods; + tDot11fTLVResponseType ResponseType; + tDot11fTLVUUID_E UUID_E; + tDot11fTLVManufacturer Manufacturer; + tDot11fTLVModelName ModelName; + tDot11fTLVModelNumber ModelNumber; + tDot11fTLVSerialNumber SerialNumber; + tDot11fTLVPrimaryDeviceType PrimaryDeviceType; + tDot11fTLVDeviceName DeviceName; + tDot11fTLVConfigMethods ConfigMethods; + tDot11fTLVRFBands RFBands; + tDot11fTLVVendorExtension VendorExtension; +} tDot11fIEWscProbeRes; + +#define DOT11F_EID_WSCPROBERES (221) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_WSCPROBERES_MIN_LEN (4) + +#define DOT11F_IE_WSCPROBERES_MAX_LEN (317) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_wsc_probe_res( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEWscProbeRes*); + +uint32_t dot11f_pack_ie_wsc_probe_res( + tpAniSirGlobal, + tDot11fIEWscProbeRes *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_wsc_probe_res( + tpAniSirGlobal, + tDot11fIEWscProbeRes *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 221 (0xdd) {OUI 0x00, 0x50, 0xf2, 0x04} (Multi-IE) */ +typedef struct sDot11fIEWscReassocRes { + uint8_t present; + tDot11fTLVVersion Version; + tDot11fTLVResponseType ResponseType; + tDot11fTLVVendorExtension VendorExtension; +} tDot11fIEWscReassocRes; + +#define DOT11F_EID_WSCREASSOCRES (221) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_WSCREASSOCRES_MIN_LEN (4) + +#define DOT11F_IE_WSCREASSOCRES_MAX_LEN (35) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_wsc_reassoc_res( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEWscReassocRes*); + +uint32_t dot11f_pack_ie_wsc_reassoc_res( + tpAniSirGlobal, + tDot11fIEWscReassocRes *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_wsc_reassoc_res( + tpAniSirGlobal, + tDot11fIEWscReassocRes *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 60 (0x3c) */ +typedef struct sDot11fIEext_chan_switch_ann { + uint8_t present; + uint8_t switch_mode; + uint8_t new_reg_class; + uint8_t new_channel; + uint8_t switch_count; +} tDot11fIEext_chan_switch_ann; + +#define DOT11F_EID_EXT_CHAN_SWITCH_ANN (60) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_EXT_CHAN_SWITCH_ANN_MIN_LEN (4) + +#define DOT11F_IE_EXT_CHAN_SWITCH_ANN_MAX_LEN (4) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_ext_chan_switch_ann( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEext_chan_switch_ann*); + +uint32_t dot11f_pack_ie_ext_chan_switch_ann( + tpAniSirGlobal, + tDot11fIEext_chan_switch_ann *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_ext_chan_switch_ann( + tpAniSirGlobal, + tDot11fIEext_chan_switch_ann *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 221 (0xdd) {OUI 0x50, 0x6f, 0x9a, 0x10} */ +typedef struct sDot11fIEhs20vendor_ie { + uint8_t present; + uint8_t dgaf_dis:1; + uint8_t hs_id_present:2; + uint8_t reserved:1; + uint8_t release_num:4; + union { + struct { + uint16_t pps_mo_id; + } pps_mo; /* hs_id_present = 1 */ + struct { + uint16_t anqp_domain_id; + } anqp_domain; /* hs_id_present = 2 */ + } hs_id; +} tDot11fIEhs20vendor_ie; + +#define DOT11F_EID_HS20VENDOR_IE (221) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_HS20VENDOR_IE_MIN_LEN (5) + +#define DOT11F_IE_HS20VENDOR_IE_MAX_LEN (7) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_hs20vendor_ie( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEhs20vendor_ie*); + +uint32_t dot11f_pack_ie_hs20vendor_ie( + tpAniSirGlobal, + tDot11fIEhs20vendor_ie *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_hs20vendor_ie( + tpAniSirGlobal, + tDot11fIEhs20vendor_ie *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 72 (0x48) */ +typedef struct sDot11fIEht2040_bss_coexistence { + uint8_t present; + uint8_t info_request:1; + uint8_t forty_mhz_intolerant:1; + uint8_t twenty_mhz_bsswidth_req:1; + uint8_t obss_scan_exemption_req:1; + uint8_t obss_scan_exemption_grant:1; + uint8_t unused:3; +} tDot11fIEht2040_bss_coexistence; + +#define DOT11F_EID_HT2040_BSS_COEXISTENCE (72) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_HT2040_BSS_COEXISTENCE_MIN_LEN (1) + +#define DOT11F_IE_HT2040_BSS_COEXISTENCE_MAX_LEN (1) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_ht2040_bss_coexistence( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEht2040_bss_coexistence*); + +uint32_t dot11f_pack_ie_ht2040_bss_coexistence( + tpAniSirGlobal, + tDot11fIEht2040_bss_coexistence *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_ht2040_bss_coexistence( + tpAniSirGlobal, + tDot11fIEht2040_bss_coexistence *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 73 (0x49) */ +typedef struct sDot11fIEht2040_bss_intolerant_report { + uint8_t present; + uint8_t operating_class; + uint8_t num_channel_list; + uint8_t channel_list[50]; +} tDot11fIEht2040_bss_intolerant_report; + +#define DOT11F_EID_HT2040_BSS_INTOLERANT_REPORT (73) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_HT2040_BSS_INTOLERANT_REPORT_MIN_LEN (1) + +#define DOT11F_IE_HT2040_BSS_INTOLERANT_REPORT_MAX_LEN (51) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_ht2040_bss_intolerant_report( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEht2040_bss_intolerant_report*); + +uint32_t dot11f_pack_ie_ht2040_bss_intolerant_report( + tpAniSirGlobal, + tDot11fIEht2040_bss_intolerant_report *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_ht2040_bss_intolerant_report( + tpAniSirGlobal, + tDot11fIEht2040_bss_intolerant_report *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 62 (0x3e) */ +typedef struct sDot11fIEsec_chan_offset_ele { + uint8_t present; + uint8_t secondaryChannelOffset; +} tDot11fIEsec_chan_offset_ele; + +#define DOT11F_EID_SEC_CHAN_OFFSET_ELE (62) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_SEC_CHAN_OFFSET_ELE_MIN_LEN (1) + +#define DOT11F_IE_SEC_CHAN_OFFSET_ELE_MAX_LEN (1) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_sec_chan_offset_ele( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEsec_chan_offset_ele*); + +uint32_t dot11f_pack_ie_sec_chan_offset_ele( + tpAniSirGlobal, + tDot11fIEsec_chan_offset_ele *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_sec_chan_offset_ele( + tpAniSirGlobal, + tDot11fIEsec_chan_offset_ele *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 221 (0xdd) {OUI 0x00, 0x90, 0x4c} */ +typedef struct sDot11fIEvendor_vht_ie { + uint8_t present; + uint8_t type; + uint8_t sub_type; + tDot11fIEVHTCaps VHTCaps; + tDot11fIEVHTOperation VHTOperation; +} tDot11fIEvendor_vht_ie; + +#define DOT11F_EID_VENDOR_VHT_IE (221) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_VENDOR_VHT_IE_MIN_LEN (5) + +#define DOT11F_IE_VENDOR_VHT_IE_MAX_LEN (26) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_ie_vendor_vht_ie( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEvendor_vht_ie*); + +uint32_t dot11f_pack_ie_vendor_vht_ie( + tpAniSirGlobal, + tDot11fIEvendor_vht_ie *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_vendor_vht_ie( + tpAniSirGlobal, + tDot11fIEvendor_vht_ie *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ +/************************************************************************ + * Frames + **********************************************************************/ + +typedef struct sDot11fAddTSRequest{ + tDot11fFfCategory Category; + tDot11fFfAction Action; + tDot11fFfDialogToken DialogToken; + tDot11fIETSPEC TSPEC; + uint16_t num_TCLAS; + tDot11fIETCLAS TCLAS[2]; + tDot11fIETCLASSPROC TCLASSPROC; + tDot11fIEWMMTSPEC WMMTSPEC; + uint16_t num_WMMTCLAS; + tDot11fIEWMMTCLAS WMMTCLAS[2]; + tDot11fIEWMMTCLASPROC WMMTCLASPROC; + tDot11fIEESETrafStrmRateSet ESETrafStrmRateSet; +} tDot11fAddTSRequest; + +#define DOT11F_ADDTSREQUEST (1) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_add_ts_request(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fAddTSRequest * pFrm); +uint32_t dot11f_pack_add_ts_request(tpAniSirGlobal pCtx, + tDot11fAddTSRequest *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_add_ts_request_size(tpAniSirGlobal pCtx, + tDot11fAddTSRequest *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fAddTSResponse{ + tDot11fFfCategory Category; + tDot11fFfAction Action; + tDot11fFfDialogToken DialogToken; + tDot11fFfStatus Status; + tDot11fIETSDelay TSDelay; + tDot11fIETSPEC TSPEC; + uint16_t num_TCLAS; + tDot11fIETCLAS TCLAS[2]; + tDot11fIETCLASSPROC TCLASSPROC; + tDot11fIESchedule Schedule; + tDot11fIEWMMTSDelay WMMTSDelay; + tDot11fIEWMMSchedule WMMSchedule; + tDot11fIEWMMTSPEC WMMTSPEC; + uint16_t num_WMMTCLAS; + tDot11fIEWMMTCLAS WMMTCLAS[2]; + tDot11fIEWMMTCLASPROC WMMTCLASPROC; + tDot11fIEESETrafStrmMet ESETrafStrmMet; +} tDot11fAddTSResponse; + +#define DOT11F_ADDTSRESPONSE (2) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_add_ts_response(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fAddTSResponse * pFrm); +uint32_t dot11f_pack_add_ts_response(tpAniSirGlobal pCtx, + tDot11fAddTSResponse *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_add_ts_response_size(tpAniSirGlobal pCtx, + tDot11fAddTSResponse *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fAssocRequest{ + tDot11fFfCapabilities Capabilities; + tDot11fFfListenInterval ListenInterval; + tDot11fIESSID SSID; + tDot11fIESuppRates SuppRates; + tDot11fIEOperatingMode OperatingMode; + tDot11fIEPowerCaps PowerCaps; + tDot11fIESuppChannels SuppChannels; + tDot11fIEHTCaps HTCaps; + tDot11fIEQOSCapsStation QOSCapsStation; + tDot11fIERSNOpaque RSNOpaque; + tDot11fIEExtSuppRates ExtSuppRates; + tDot11fIEMobilityDomain MobilityDomain; + tDot11fIESuppOperatingClasses SuppOperatingClasses; + tDot11fIEWAPIOpaque WAPIOpaque; + tDot11fIEWAPI WAPI; + tDot11fIERRMEnabledCap RRMEnabledCap; + tDot11fIEQosMapSet QosMapSet; + tDot11fIEExtCap ExtCap; + tDot11fIEVHTCaps VHTCaps; + tDot11fIEWPAOpaque WPAOpaque; + tDot11fIEWMMCaps WMMCaps; + tDot11fIEWMMInfoStation WMMInfoStation; + tDot11fIEWscIEOpaque WscIEOpaque; + tDot11fIEESERadMgmtCap ESERadMgmtCap; + tDot11fIEESEVersion ESEVersion; + tDot11fIEP2PIEOpaque P2PIEOpaque; + tDot11fIEWFDIEOpaque WFDIEOpaque; + tDot11fIEvendor_vht_ie vendor_vht_ie; + tDot11fIEhs20vendor_ie hs20vendor_ie; + tDot11fIEQCN_IE QCN_IE; +} tDot11fAssocRequest; + +#define DOT11F_ASSOCREQUEST (3) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_assoc_request(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fAssocRequest * pFrm); +uint32_t dot11f_pack_assoc_request(tpAniSirGlobal pCtx, + tDot11fAssocRequest *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_assoc_request_size(tpAniSirGlobal pCtx, + tDot11fAssocRequest *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fAssocResponse{ + tDot11fFfCapabilities Capabilities; + tDot11fFfStatus Status; + tDot11fFfAID AID; + tDot11fIESuppRates SuppRates; + tDot11fIEExtSuppRates ExtSuppRates; + tDot11fIEEDCAParamSet EDCAParamSet; + tDot11fIERCPIIE RCPIIE; + tDot11fIERSNIIE RSNIIE; + tDot11fIERRMEnabledCap RRMEnabledCap; + tDot11fIEMobilityDomain MobilityDomain; + tDot11fIEFTInfo FTInfo; + uint16_t num_RICDataDesc; + tDot11fIERICDataDesc RICDataDesc[2]; + tDot11fIEWPA WPA; + tDot11fIETimeoutInterval TimeoutInterval; + tDot11fIEHTCaps HTCaps; + tDot11fIEHTInfo HTInfo; + tDot11fIEWMMParams WMMParams; + tDot11fIEWMMCaps WMMCaps; + tDot11fIEESERadMgmtCap ESERadMgmtCap; + tDot11fIEESETrafStrmMet ESETrafStrmMet; + tDot11fIEESETxmitPower ESETxmitPower; + uint16_t num_WMMTSPEC; + tDot11fIEWMMTSPEC WMMTSPEC[4]; + tDot11fIEWscAssocRes WscAssocRes; + tDot11fIEP2PAssocRes P2PAssocRes; + tDot11fIEVHTCaps VHTCaps; + tDot11fIEVHTOperation VHTOperation; + tDot11fIEExtCap ExtCap; + tDot11fIEOBSSScanParameters OBSSScanParameters; + tDot11fIEQosMapSet QosMapSet; + tDot11fIEvendor_vht_ie vendor_vht_ie; + tDot11fIEQCN_IE QCN_IE; +} tDot11fAssocResponse; + +#define DOT11F_ASSOCRESPONSE (4) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_assoc_response(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fAssocResponse * pFrm); +uint32_t dot11f_pack_assoc_response(tpAniSirGlobal pCtx, + tDot11fAssocResponse *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_assoc_response_size(tpAniSirGlobal pCtx, + tDot11fAssocResponse *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fAuthentication{ + tDot11fFfAuthAlgo AuthAlgo; + tDot11fFfAuthSeqNo AuthSeqNo; + tDot11fFfStatus Status; + tDot11fIEChallengeText ChallengeText; + tDot11fIERSNOpaque RSNOpaque; + tDot11fIEMobilityDomain MobilityDomain; + tDot11fIEFTInfo FTInfo; + tDot11fIETimeoutInterval TimeoutInterval; + uint16_t num_RICDataDesc; + tDot11fIERICDataDesc RICDataDesc[2]; +} tDot11fAuthentication; + +#define DOT11F_AUTHENTICATION (5) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_authentication(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fAuthentication * pFrm); +uint32_t dot11f_pack_authentication(tpAniSirGlobal pCtx, + tDot11fAuthentication *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_authentication_size(tpAniSirGlobal pCtx, + tDot11fAuthentication *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fBeacon{ + tDot11fFfTimeStamp TimeStamp; + tDot11fFfBeaconInterval BeaconInterval; + tDot11fFfCapabilities Capabilities; + tDot11fIESSID SSID; + tDot11fIESuppRates SuppRates; + tDot11fIEFHParamSet FHParamSet; + tDot11fIEDSParams DSParams; + tDot11fIECFParams CFParams; + tDot11fIEIBSSParams IBSSParams; + tDot11fIETIM TIM; + tDot11fIECountry Country; + tDot11fIEFHParams FHParams; + tDot11fIEFHPattTable FHPattTable; + tDot11fIEPowerConstraints PowerConstraints; + tDot11fIEChanSwitchAnn ChanSwitchAnn; + tDot11fIEext_chan_switch_ann ext_chan_switch_ann; + tDot11fIESuppOperatingClasses SuppOperatingClasses; + tDot11fIEQuiet Quiet; + tDot11fIETPCReport TPCReport; + tDot11fIEERPInfo ERPInfo; + tDot11fIEExtSuppRates ExtSuppRates; + tDot11fIERSN RSN; + tDot11fIEQBSSLoad QBSSLoad; + tDot11fIEEDCAParamSet EDCAParamSet; + tDot11fIEQOSCapsAp QOSCapsAp; + tDot11fIEAPChannelReport APChannelReport; + tDot11fIERRMEnabledCap RRMEnabledCap; + tDot11fIEMobilityDomain MobilityDomain; + tDot11fIEWPA WPA; + tDot11fIEHTCaps HTCaps; + tDot11fIEHTInfo HTInfo; + tDot11fIEsec_chan_offset_ele sec_chan_offset_ele; + tDot11fIEWMMInfoAp WMMInfoAp; + tDot11fIEWMMParams WMMParams; + tDot11fIEWMMCaps WMMCaps; + tDot11fIEWAPI WAPI; + tDot11fIEESERadMgmtCap ESERadMgmtCap; + tDot11fIEESETrafStrmMet ESETrafStrmMet; + tDot11fIEESETxmitPower ESETxmitPower; + tDot11fIEWscBeacon WscBeacon; + tDot11fIEP2PBeacon P2PBeacon; + tDot11fIEVHTCaps VHTCaps; + tDot11fIEVHTOperation VHTOperation; + tDot11fIEVHTExtBssLoad VHTExtBssLoad; + tDot11fIEExtCap ExtCap; + tDot11fIEOperatingMode OperatingMode; + tDot11fIEWiderBWChanSwitchAnn WiderBWChanSwitchAnn; + tDot11fIEOBSSScanParameters OBSSScanParameters; + tDot11fIEVendor1IE Vendor1IE; + tDot11fIEvendor_vht_ie vendor_vht_ie; + tDot11fIEVendor3IE Vendor3IE; + tDot11fIEhs20vendor_ie hs20vendor_ie; + tDot11fIEChannelSwitchWrapper ChannelSwitchWrapper; + tDot11fIEQComVendorIE QComVendorIE; + tDot11fIEESEVersion ESEVersion; + tDot11fIEMBO_IE MBO_IE; + tDot11fIEQCN_IE QCN_IE; +} tDot11fBeacon; + +#define DOT11F_BEACON (6) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_beacon(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fBeacon * pFrm); +uint32_t dot11f_pack_beacon(tpAniSirGlobal pCtx, + tDot11fBeacon *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_beacon_size(tpAniSirGlobal pCtx, + tDot11fBeacon *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fBeacon1{ + tDot11fFfTimeStamp TimeStamp; + tDot11fFfBeaconInterval BeaconInterval; + tDot11fFfCapabilities Capabilities; + tDot11fIESSID SSID; + tDot11fIESuppRates SuppRates; + tDot11fIEDSParams DSParams; + tDot11fIEIBSSParams IBSSParams; +} tDot11fBeacon1; + +#define DOT11F_BEACON1 (7) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_beacon1(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fBeacon1 * pFrm); +uint32_t dot11f_pack_beacon1(tpAniSirGlobal pCtx, + tDot11fBeacon1 *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_beacon1_size(tpAniSirGlobal pCtx, + tDot11fBeacon1 *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fBeacon2{ + tDot11fIECountry Country; + tDot11fIEPowerConstraints PowerConstraints; + tDot11fIEChanSwitchAnn ChanSwitchAnn; + tDot11fIEext_chan_switch_ann ext_chan_switch_ann; + tDot11fIESuppOperatingClasses SuppOperatingClasses; + tDot11fIEQuiet Quiet; + tDot11fIETPCReport TPCReport; + tDot11fIEERPInfo ERPInfo; + tDot11fIEExtSuppRates ExtSuppRates; + tDot11fIERSNOpaque RSNOpaque; + tDot11fIEEDCAParamSet EDCAParamSet; + tDot11fIEAPChannelReport APChannelReport; + tDot11fIERRMEnabledCap RRMEnabledCap; + tDot11fIEMobilityDomain MobilityDomain; + tDot11fIEWPA WPA; + tDot11fIEHTCaps HTCaps; + tDot11fIEHTInfo HTInfo; + tDot11fIEsec_chan_offset_ele sec_chan_offset_ele; + tDot11fIEWMMInfoAp WMMInfoAp; + tDot11fIEWMMParams WMMParams; + tDot11fIEWMMCaps WMMCaps; + tDot11fIEWscBeacon WscBeacon; + tDot11fIEWAPI WAPI; + tDot11fIEESERadMgmtCap ESERadMgmtCap; + tDot11fIEESETrafStrmMet ESETrafStrmMet; + tDot11fIEESETxmitPower ESETxmitPower; + tDot11fIEP2PBeacon P2PBeacon; + tDot11fIEVHTCaps VHTCaps; + tDot11fIEVHTOperation VHTOperation; + tDot11fIEVHTExtBssLoad VHTExtBssLoad; + tDot11fIEExtCap ExtCap; + tDot11fIEOperatingMode OperatingMode; + tDot11fIEWiderBWChanSwitchAnn WiderBWChanSwitchAnn; + tDot11fIEOBSSScanParameters OBSSScanParameters; + tDot11fIEVendor1IE Vendor1IE; + tDot11fIEvendor_vht_ie vendor_vht_ie; + tDot11fIEVendor3IE Vendor3IE; + tDot11fIEhs20vendor_ie hs20vendor_ie; + tDot11fIEChannelSwitchWrapper ChannelSwitchWrapper; + tDot11fIEQComVendorIE QComVendorIE; + tDot11fIEESEVersion ESEVersion; + tDot11fIEQCN_IE QCN_IE; +} tDot11fBeacon2; + +#define DOT11F_BEACON2 (8) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_beacon2(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fBeacon2 * pFrm); +uint32_t dot11f_pack_beacon2(tpAniSirGlobal pCtx, + tDot11fBeacon2 *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_beacon2_size(tpAniSirGlobal pCtx, + tDot11fBeacon2 *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fBeaconIEs{ + tDot11fIESSID SSID; + tDot11fIESuppRates SuppRates; + tDot11fIEFHParamSet FHParamSet; + tDot11fIEDSParams DSParams; + tDot11fIECFParams CFParams; + tDot11fIEIBSSParams IBSSParams; + tDot11fIETIM TIM; + tDot11fIECountry Country; + tDot11fIEFHParams FHParams; + tDot11fIEFHPattTable FHPattTable; + tDot11fIEPowerConstraints PowerConstraints; + tDot11fIEChanSwitchAnn ChanSwitchAnn; + tDot11fIEext_chan_switch_ann ext_chan_switch_ann; + tDot11fIESuppOperatingClasses SuppOperatingClasses; + tDot11fIEQuiet Quiet; + tDot11fIETPCReport TPCReport; + tDot11fIEERPInfo ERPInfo; + tDot11fIEExtSuppRates ExtSuppRates; + tDot11fIERSN RSN; + tDot11fIEQBSSLoad QBSSLoad; + tDot11fIEEDCAParamSet EDCAParamSet; + tDot11fIEQOSCapsAp QOSCapsAp; + tDot11fIEAPChannelReport APChannelReport; + tDot11fIERRMEnabledCap RRMEnabledCap; + tDot11fIEMobilityDomain MobilityDomain; + tDot11fIEWPA WPA; + tDot11fIEHTCaps HTCaps; + tDot11fIEHTInfo HTInfo; + tDot11fIEsec_chan_offset_ele sec_chan_offset_ele; + tDot11fIEWMMInfoAp WMMInfoAp; + tDot11fIEWMMParams WMMParams; + tDot11fIEWMMCaps WMMCaps; + tDot11fIEWAPI WAPI; + tDot11fIEESEVersion ESEVersion; + tDot11fIEESERadMgmtCap ESERadMgmtCap; + tDot11fIEESETrafStrmMet ESETrafStrmMet; + tDot11fIEESETxmitPower ESETxmitPower; + tDot11fIEWscBeaconProbeRes WscBeaconProbeRes; + tDot11fIEP2PBeaconProbeRes P2PBeaconProbeRes; + tDot11fIEVHTCaps VHTCaps; + tDot11fIEVHTOperation VHTOperation; + tDot11fIEVHTExtBssLoad VHTExtBssLoad; + tDot11fIEExtCap ExtCap; + tDot11fIEOperatingMode OperatingMode; + tDot11fIEWiderBWChanSwitchAnn WiderBWChanSwitchAnn; + tDot11fIEOBSSScanParameters OBSSScanParameters; + tDot11fIEVendor1IE Vendor1IE; + tDot11fIEvendor_vht_ie vendor_vht_ie; + tDot11fIEVendor3IE Vendor3IE; + tDot11fIEhs20vendor_ie hs20vendor_ie; + tDot11fIEChannelSwitchWrapper ChannelSwitchWrapper; + tDot11fIEQComVendorIE QComVendorIE; + tDot11fIEMBO_IE MBO_IE; + tDot11fIEQCN_IE QCN_IE; +} tDot11fBeaconIEs; + +#define DOT11F_BEACONIES (9) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_beacon_i_es(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fBeaconIEs * pFrm); +uint32_t dot11f_pack_beacon_i_es(tpAniSirGlobal pCtx, + tDot11fBeaconIEs *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_beacon_i_es_size(tpAniSirGlobal pCtx, + tDot11fBeaconIEs *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fChannelSwitch{ + tDot11fFfCategory Category; + tDot11fFfAction Action; + tDot11fIEChanSwitchAnn ChanSwitchAnn; + tDot11fIEsec_chan_offset_ele sec_chan_offset_ele; + tDot11fIEWiderBWChanSwitchAnn WiderBWChanSwitchAnn; +} tDot11fChannelSwitch; + +#define DOT11F_CHANNELSWITCH (10) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_channel_switch(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fChannelSwitch * pFrm); +uint32_t dot11f_pack_channel_switch(tpAniSirGlobal pCtx, + tDot11fChannelSwitch *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_channel_switch_size(tpAniSirGlobal pCtx, + tDot11fChannelSwitch *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fDeAuth{ + tDot11fFfReason Reason; + tDot11fIEP2PDeAuth P2PDeAuth; +} tDot11fDeAuth; + +#define DOT11F_DEAUTH (11) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_de_auth(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fDeAuth * pFrm); +uint32_t dot11f_pack_de_auth(tpAniSirGlobal pCtx, + tDot11fDeAuth *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_de_auth_size(tpAniSirGlobal pCtx, + tDot11fDeAuth *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fDelTS{ + tDot11fFfCategory Category; + tDot11fFfAction Action; + tDot11fFfTSInfo TSInfo; + tDot11fFfReason Reason; +} tDot11fDelTS; + +#define DOT11F_DELTS (12) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_del_ts(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fDelTS * pFrm); +uint32_t dot11f_pack_del_ts(tpAniSirGlobal pCtx, + tDot11fDelTS *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_del_ts_size(tpAniSirGlobal pCtx, + tDot11fDelTS *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fDisassociation{ + tDot11fFfReason Reason; + tDot11fIEP2PDisAssoc P2PDisAssoc; +} tDot11fDisassociation; + +#define DOT11F_DISASSOCIATION (13) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_disassociation(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fDisassociation * pFrm); +uint32_t dot11f_pack_disassociation(tpAniSirGlobal pCtx, + tDot11fDisassociation *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_disassociation_size(tpAniSirGlobal pCtx, + tDot11fDisassociation *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fLinkMeasurementReport{ + tDot11fFfCategory Category; + tDot11fFfAction Action; + tDot11fFfDialogToken DialogToken; + tDot11fFfTPCEleID TPCEleID; + tDot11fFfTPCEleLen TPCEleLen; + tDot11fFfTxPower TxPower; + tDot11fFfLinkMargin LinkMargin; + tDot11fFfRxAntennaId RxAntennaId; + tDot11fFfTxAntennaId TxAntennaId; + tDot11fFfRCPI RCPI; + tDot11fFfRSNI RSNI; +} tDot11fLinkMeasurementReport; + +#define DOT11F_LINKMEASUREMENTREPORT (14) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_link_measurement_report(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fLinkMeasurementReport * pFrm); +uint32_t dot11f_pack_link_measurement_report(tpAniSirGlobal pCtx, + tDot11fLinkMeasurementReport *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_link_measurement_report_size(tpAniSirGlobal pCtx, + tDot11fLinkMeasurementReport *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fLinkMeasurementRequest{ + tDot11fFfCategory Category; + tDot11fFfAction Action; + tDot11fFfDialogToken DialogToken; + tDot11fFfTxPower TxPower; + tDot11fFfMaxTxPower MaxTxPower; +} tDot11fLinkMeasurementRequest; + +#define DOT11F_LINKMEASUREMENTREQUEST (15) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_link_measurement_request(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fLinkMeasurementRequest * pFrm); +uint32_t dot11f_pack_link_measurement_request(tpAniSirGlobal pCtx, + tDot11fLinkMeasurementRequest *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_link_measurement_request_size(tpAniSirGlobal pCtx, + tDot11fLinkMeasurementRequest *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fMeasurementReport{ + tDot11fFfCategory Category; + tDot11fFfAction Action; + tDot11fFfDialogToken DialogToken; + tDot11fIEMeasurementReport MeasurementReport; +} tDot11fMeasurementReport; + +#define DOT11F_MEASUREMENTREPORT (16) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_measurement_report(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fMeasurementReport * pFrm); +uint32_t dot11f_pack_measurement_report(tpAniSirGlobal pCtx, + tDot11fMeasurementReport *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_measurement_report_size(tpAniSirGlobal pCtx, + tDot11fMeasurementReport *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fMeasurementRequest{ + tDot11fFfCategory Category; + tDot11fFfAction Action; + tDot11fFfDialogToken DialogToken; + uint16_t num_MeasurementRequest; + tDot11fIEMeasurementRequest MeasurementRequest[4]; +} tDot11fMeasurementRequest; + +#define DOT11F_MEASUREMENTREQUEST (17) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_measurement_request(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fMeasurementRequest * pFrm); +uint32_t dot11f_pack_measurement_request(tpAniSirGlobal pCtx, + tDot11fMeasurementRequest *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_measurement_request_size(tpAniSirGlobal pCtx, + tDot11fMeasurementRequest *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fNeighborReportRequest{ + tDot11fFfCategory Category; + tDot11fFfAction Action; + tDot11fFfDialogToken DialogToken; + tDot11fIESSID SSID; +} tDot11fNeighborReportRequest; + +#define DOT11F_NEIGHBORREPORTREQUEST (18) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_neighbor_report_request(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fNeighborReportRequest * pFrm); +uint32_t dot11f_pack_neighbor_report_request(tpAniSirGlobal pCtx, + tDot11fNeighborReportRequest *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_neighbor_report_request_size(tpAniSirGlobal pCtx, + tDot11fNeighborReportRequest *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fNeighborReportResponse{ + tDot11fFfCategory Category; + tDot11fFfAction Action; + tDot11fFfDialogToken DialogToken; + uint16_t num_NeighborReport; + tDot11fIENeighborReport NeighborReport[15]; +} tDot11fNeighborReportResponse; + +#define DOT11F_NEIGHBORREPORTRESPONSE (19) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_neighbor_report_response(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fNeighborReportResponse * pFrm); +uint32_t dot11f_pack_neighbor_report_response(tpAniSirGlobal pCtx, + tDot11fNeighborReportResponse *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_neighbor_report_response_size(tpAniSirGlobal pCtx, + tDot11fNeighborReportResponse *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fOperatingMode{ + tDot11fFfCategory Category; + tDot11fFfAction Action; + tDot11fFfOperatingMode OperatingMode; +} tDot11fOperatingMode; + +#define DOT11F_OPERATINGMODE (20) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_operating_mode(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fOperatingMode * pFrm); +uint32_t dot11f_pack_operating_mode(tpAniSirGlobal pCtx, + tDot11fOperatingMode *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_operating_mode_size(tpAniSirGlobal pCtx, + tDot11fOperatingMode *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fProbeRequest{ + tDot11fIESSID SSID; + tDot11fIESuppRates SuppRates; + tDot11fIERequestedInfo RequestedInfo; + tDot11fIEExtSuppRates ExtSuppRates; + tDot11fIEDSParams DSParams; + tDot11fIEHTCaps HTCaps; + tDot11fIEWscProbeReq WscProbeReq; + tDot11fIEWFATPC WFATPC; + tDot11fIEP2PProbeReq P2PProbeReq; + tDot11fIEVHTCaps VHTCaps; + tDot11fIEExtCap ExtCap; + tDot11fIEQCN_IE QCN_IE; +} tDot11fProbeRequest; + +#define DOT11F_PROBEREQUEST (21) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_probe_request(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fProbeRequest * pFrm); +uint32_t dot11f_pack_probe_request(tpAniSirGlobal pCtx, + tDot11fProbeRequest *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_probe_request_size(tpAniSirGlobal pCtx, + tDot11fProbeRequest *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fProbeResponse{ + tDot11fFfTimeStamp TimeStamp; + tDot11fFfBeaconInterval BeaconInterval; + tDot11fFfCapabilities Capabilities; + tDot11fIESSID SSID; + tDot11fIESuppRates SuppRates; + tDot11fIEFHParamSet FHParamSet; + tDot11fIEDSParams DSParams; + tDot11fIECFParams CFParams; + tDot11fIEIBSSParams IBSSParams; + tDot11fIECountry Country; + tDot11fIEFHParams FHParams; + tDot11fIEFHPattTable FHPattTable; + tDot11fIEPowerConstraints PowerConstraints; + tDot11fIEChanSwitchAnn ChanSwitchAnn; + tDot11fIEext_chan_switch_ann ext_chan_switch_ann; + tDot11fIESuppOperatingClasses SuppOperatingClasses; + tDot11fIEQuiet Quiet; + tDot11fIETPCReport TPCReport; + tDot11fIEERPInfo ERPInfo; + tDot11fIEExtSuppRates ExtSuppRates; + tDot11fIERSNOpaque RSNOpaque; + tDot11fIEQBSSLoad QBSSLoad; + tDot11fIEEDCAParamSet EDCAParamSet; + tDot11fIERRMEnabledCap RRMEnabledCap; + tDot11fIEAPChannelReport APChannelReport; + tDot11fIEMobilityDomain MobilityDomain; + tDot11fIEWPA WPA; + tDot11fIEHTCaps HTCaps; + tDot11fIEHTInfo HTInfo; + tDot11fIEsec_chan_offset_ele sec_chan_offset_ele; + tDot11fIEWMMInfoAp WMMInfoAp; + tDot11fIEWMMParams WMMParams; + tDot11fIEWMMCaps WMMCaps; + tDot11fIEWAPI WAPI; + tDot11fIEESERadMgmtCap ESERadMgmtCap; + tDot11fIEESETrafStrmMet ESETrafStrmMet; + tDot11fIEESETxmitPower ESETxmitPower; + tDot11fIEWscProbeRes WscProbeRes; + tDot11fIEP2PProbeRes P2PProbeRes; + tDot11fIEVHTCaps VHTCaps; + tDot11fIEVHTOperation VHTOperation; + tDot11fIEVHTExtBssLoad VHTExtBssLoad; + tDot11fIEExtCap ExtCap; + tDot11fIEOBSSScanParameters OBSSScanParameters; + tDot11fIEVendor1IE Vendor1IE; + tDot11fIEvendor_vht_ie vendor_vht_ie; + tDot11fIEVendor3IE Vendor3IE; + tDot11fIEhs20vendor_ie hs20vendor_ie; + tDot11fIEChannelSwitchWrapper ChannelSwitchWrapper; + tDot11fIEQComVendorIE QComVendorIE; + tDot11fIEESEVersion ESEVersion; + tDot11fIEMBO_IE MBO_IE; + tDot11fIEQCN_IE QCN_IE; +} tDot11fProbeResponse; + +#define DOT11F_PROBERESPONSE (22) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_probe_response(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fProbeResponse * pFrm); +uint32_t dot11f_pack_probe_response(tpAniSirGlobal pCtx, + tDot11fProbeResponse *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_probe_response_size(tpAniSirGlobal pCtx, + tDot11fProbeResponse *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fQosMapConfigure{ + tDot11fFfCategory Category; + tDot11fFfAction Action; + tDot11fIEQosMapSet QosMapSet; +} tDot11fQosMapConfigure; + +#define DOT11F_QOSMAPCONFIGURE (23) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_qos_map_configure(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fQosMapConfigure * pFrm); +uint32_t dot11f_pack_qos_map_configure(tpAniSirGlobal pCtx, + tDot11fQosMapConfigure *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_qos_map_configure_size(tpAniSirGlobal pCtx, + tDot11fQosMapConfigure *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fRadioMeasurementReport{ + tDot11fFfCategory Category; + tDot11fFfAction Action; + tDot11fFfDialogToken DialogToken; + uint16_t num_MeasurementReport; + tDot11fIEMeasurementReport MeasurementReport[4]; +} tDot11fRadioMeasurementReport; + +#define DOT11F_RADIOMEASUREMENTREPORT (24) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_radio_measurement_report(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fRadioMeasurementReport * pFrm); +uint32_t dot11f_pack_radio_measurement_report(tpAniSirGlobal pCtx, + tDot11fRadioMeasurementReport *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_radio_measurement_report_size(tpAniSirGlobal pCtx, + tDot11fRadioMeasurementReport *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fRadioMeasurementRequest{ + tDot11fFfCategory Category; + tDot11fFfAction Action; + tDot11fFfDialogToken DialogToken; + tDot11fFfNumOfRepetitions NumOfRepetitions; + uint16_t num_MeasurementRequest; + tDot11fIEMeasurementRequest MeasurementRequest[2]; +} tDot11fRadioMeasurementRequest; + +#define DOT11F_RADIOMEASUREMENTREQUEST (25) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_radio_measurement_request(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fRadioMeasurementRequest * pFrm); +uint32_t dot11f_pack_radio_measurement_request(tpAniSirGlobal pCtx, + tDot11fRadioMeasurementRequest *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_radio_measurement_request_size(tpAniSirGlobal pCtx, + tDot11fRadioMeasurementRequest *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fReAssocRequest{ + tDot11fFfCapabilities Capabilities; + tDot11fFfListenInterval ListenInterval; + tDot11fFfCurrentAPAddress CurrentAPAddress; + tDot11fIESSID SSID; + tDot11fIESuppRates SuppRates; + tDot11fIEExtSuppRates ExtSuppRates; + tDot11fIEPowerCaps PowerCaps; + tDot11fIESuppChannels SuppChannels; + tDot11fIERSNOpaque RSNOpaque; + tDot11fIEQOSCapsStation QOSCapsStation; + tDot11fIERRMEnabledCap RRMEnabledCap; + tDot11fIEMobilityDomain MobilityDomain; + tDot11fIEFTInfo FTInfo; + uint16_t num_RICDataDesc; + tDot11fIERICDataDesc RICDataDesc[2]; + tDot11fIEWPAOpaque WPAOpaque; + tDot11fIEHTCaps HTCaps; + tDot11fIEWMMCaps WMMCaps; + tDot11fIEWMMInfoStation WMMInfoStation; + tDot11fIEWscIEOpaque WscIEOpaque; + tDot11fIEWAPIOpaque WAPIOpaque; + tDot11fIEWAPI WAPI; + tDot11fIEESERadMgmtCap ESERadMgmtCap; + tDot11fIEESEVersion ESEVersion; + tDot11fIEESECckmOpaque ESECckmOpaque; + uint16_t num_WMMTSPEC; + tDot11fIEWMMTSPEC WMMTSPEC[4]; + tDot11fIEESETrafStrmRateSet ESETrafStrmRateSet; + tDot11fIEP2PIEOpaque P2PIEOpaque; + tDot11fIEWFDIEOpaque WFDIEOpaque; + tDot11fIEVHTCaps VHTCaps; + tDot11fIEExtCap ExtCap; + tDot11fIEOperatingMode OperatingMode; + tDot11fIEQosMapSet QosMapSet; + tDot11fIEvendor_vht_ie vendor_vht_ie; + tDot11fIEhs20vendor_ie hs20vendor_ie; +} tDot11fReAssocRequest; + +#define DOT11F_REASSOCREQUEST (26) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_re_assoc_request(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fReAssocRequest * pFrm); +uint32_t dot11f_pack_re_assoc_request(tpAniSirGlobal pCtx, + tDot11fReAssocRequest *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_re_assoc_request_size(tpAniSirGlobal pCtx, + tDot11fReAssocRequest *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fReAssocResponse{ + tDot11fFfCapabilities Capabilities; + tDot11fFfStatus Status; + tDot11fFfAID AID; + tDot11fIESuppRates SuppRates; + tDot11fIEExtSuppRates ExtSuppRates; + tDot11fIEEDCAParamSet EDCAParamSet; + tDot11fIERCPIIE RCPIIE; + tDot11fIERSNIIE RSNIIE; + tDot11fIERRMEnabledCap RRMEnabledCap; + tDot11fIERSNOpaque RSNOpaque; + tDot11fIEMobilityDomain MobilityDomain; + tDot11fIEFTInfo FTInfo; + uint16_t num_RICDataDesc; + tDot11fIERICDataDesc RICDataDesc[2]; + tDot11fIEWPA WPA; + tDot11fIETimeoutInterval TimeoutInterval; + tDot11fIEHTCaps HTCaps; + tDot11fIEHTInfo HTInfo; + tDot11fIEWMMParams WMMParams; + tDot11fIEESERadMgmtCap ESERadMgmtCap; + tDot11fIEESETrafStrmMet ESETrafStrmMet; + tDot11fIEESETxmitPower ESETxmitPower; + uint16_t num_WMMTSPEC; + tDot11fIEWMMTSPEC WMMTSPEC[4]; + tDot11fIEESETrafStrmRateSet ESETrafStrmRateSet; + tDot11fIEWscReassocRes WscReassocRes; + tDot11fIEP2PAssocRes P2PAssocRes; + tDot11fIEVHTCaps VHTCaps; + tDot11fIEVHTOperation VHTOperation; + tDot11fIEExtCap ExtCap; + tDot11fIEOBSSScanParameters OBSSScanParameters; + tDot11fIEQosMapSet QosMapSet; + tDot11fIEvendor_vht_ie vendor_vht_ie; +} tDot11fReAssocResponse; + +#define DOT11F_REASSOCRESPONSE (27) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_re_assoc_response(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fReAssocResponse * pFrm); +uint32_t dot11f_pack_re_assoc_response(tpAniSirGlobal pCtx, + tDot11fReAssocResponse *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_re_assoc_response_size(tpAniSirGlobal pCtx, + tDot11fReAssocResponse *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fSMPowerSave{ + tDot11fFfCategory Category; + tDot11fFfAction Action; + tDot11fFfSMPowerModeSet SMPowerModeSet; +} tDot11fSMPowerSave; + +#define DOT11F_SMPOWERSAVE (28) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_sm_power_save(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fSMPowerSave * pFrm); +uint32_t dot11f_pack_sm_power_save(tpAniSirGlobal pCtx, + tDot11fSMPowerSave *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_sm_power_save_size(tpAniSirGlobal pCtx, + tDot11fSMPowerSave *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fSaQueryReq{ + tDot11fFfCategory Category; + tDot11fFfAction Action; + tDot11fFfTransactionId TransactionId; +} tDot11fSaQueryReq; + +#define DOT11F_SAQUERYREQ (29) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_sa_query_req(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fSaQueryReq * pFrm); +uint32_t dot11f_pack_sa_query_req(tpAniSirGlobal pCtx, + tDot11fSaQueryReq *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_sa_query_req_size(tpAniSirGlobal pCtx, + tDot11fSaQueryReq *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fSaQueryRsp{ + tDot11fFfCategory Category; + tDot11fFfAction Action; + tDot11fFfTransactionId TransactionId; +} tDot11fSaQueryRsp; + +#define DOT11F_SAQUERYRSP (30) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_sa_query_rsp(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fSaQueryRsp * pFrm); +uint32_t dot11f_pack_sa_query_rsp(tpAniSirGlobal pCtx, + tDot11fSaQueryRsp *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_sa_query_rsp_size(tpAniSirGlobal pCtx, + tDot11fSaQueryRsp *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fTDLSDisReq{ + tDot11fFfCategory Category; + tDot11fFfAction Action; + tDot11fFfDialogToken DialogToken; + tDot11fIELinkIdentifier LinkIdentifier; +} tDot11fTDLSDisReq; + +#define DOT11F_TDLSDISREQ (31) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_tdls_dis_req(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fTDLSDisReq * pFrm); +uint32_t dot11f_pack_tdls_dis_req(tpAniSirGlobal pCtx, + tDot11fTDLSDisReq *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_tdls_dis_req_size(tpAniSirGlobal pCtx, + tDot11fTDLSDisReq *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fTDLSDisRsp{ + tDot11fFfCategory Category; + tDot11fFfAction Action; + tDot11fFfDialogToken DialogToken; + tDot11fFfCapabilities Capabilities; + tDot11fIESuppRates SuppRates; + tDot11fIEExtSuppRates ExtSuppRates; + tDot11fIESuppChannels SuppChannels; + tDot11fIESuppOperatingClasses SuppOperatingClasses; + tDot11fIERSN RSN; + tDot11fIEExtCap ExtCap; + tDot11fIEFTInfo FTInfo; + tDot11fIETimeoutInterval TimeoutInterval; + tDot11fIERICData RICData; + tDot11fIEHTCaps HTCaps; + tDot11fIEht2040_bss_coexistence ht2040_bss_coexistence; + tDot11fIELinkIdentifier LinkIdentifier; + tDot11fIEVHTCaps VHTCaps; +} tDot11fTDLSDisRsp; + +#define DOT11F_TDLSDISRSP (32) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_tdls_dis_rsp(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fTDLSDisRsp * pFrm); +uint32_t dot11f_pack_tdls_dis_rsp(tpAniSirGlobal pCtx, + tDot11fTDLSDisRsp *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_tdls_dis_rsp_size(tpAniSirGlobal pCtx, + tDot11fTDLSDisRsp *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fTDLSPeerTrafficInd{ + tDot11fFfCategory Category; + tDot11fFfAction Action; + tDot11fFfDialogToken DialogToken; + tDot11fIELinkIdentifier LinkIdentifier; + tDot11fIEPTIControl PTIControl; + tDot11fIEPUBufferStatus PUBufferStatus; +} tDot11fTDLSPeerTrafficInd; + +#define DOT11F_TDLSPEERTRAFFICIND (33) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_tdls_peer_traffic_ind(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fTDLSPeerTrafficInd * pFrm); +uint32_t dot11f_pack_tdls_peer_traffic_ind(tpAniSirGlobal pCtx, + tDot11fTDLSPeerTrafficInd *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_tdls_peer_traffic_ind_size(tpAniSirGlobal pCtx, + tDot11fTDLSPeerTrafficInd *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fTDLSPeerTrafficRsp{ + tDot11fFfCategory Category; + tDot11fFfAction Action; + tDot11fFfDialogToken DialogToken; + tDot11fIELinkIdentifier LinkIdentifier; +} tDot11fTDLSPeerTrafficRsp; + +#define DOT11F_TDLSPEERTRAFFICRSP (34) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_tdls_peer_traffic_rsp(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fTDLSPeerTrafficRsp * pFrm); +uint32_t dot11f_pack_tdls_peer_traffic_rsp(tpAniSirGlobal pCtx, + tDot11fTDLSPeerTrafficRsp *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_tdls_peer_traffic_rsp_size(tpAniSirGlobal pCtx, + tDot11fTDLSPeerTrafficRsp *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fTDLSSetupCnf{ + tDot11fFfCategory Category; + tDot11fFfAction Action; + tDot11fFfStatus Status; + tDot11fFfDialogToken DialogToken; + tDot11fIERSN RSN; + tDot11fIEEDCAParamSet EDCAParamSet; + tDot11fIEFTInfo FTInfo; + tDot11fIETimeoutInterval TimeoutInterval; + tDot11fIEHTInfo HTInfo; + tDot11fIELinkIdentifier LinkIdentifier; + tDot11fIEWMMParams WMMParams; + tDot11fIEVHTOperation VHTOperation; + tDot11fIEOperatingMode OperatingMode; +} tDot11fTDLSSetupCnf; + +#define DOT11F_TDLSSETUPCNF (35) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_tdls_setup_cnf(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fTDLSSetupCnf * pFrm); +uint32_t dot11f_pack_tdls_setup_cnf(tpAniSirGlobal pCtx, + tDot11fTDLSSetupCnf *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_tdls_setup_cnf_size(tpAniSirGlobal pCtx, + tDot11fTDLSSetupCnf *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fTDLSSetupReq{ + tDot11fFfCategory Category; + tDot11fFfAction Action; + tDot11fFfDialogToken DialogToken; + tDot11fFfCapabilities Capabilities; + tDot11fIESuppRates SuppRates; + tDot11fIECountry Country; + tDot11fIEExtSuppRates ExtSuppRates; + tDot11fIESuppChannels SuppChannels; + tDot11fIERSN RSN; + tDot11fIEExtCap ExtCap; + tDot11fIESuppOperatingClasses SuppOperatingClasses; + tDot11fIEQOSCapsStation QOSCapsStation; + tDot11fIEFTInfo FTInfo; + tDot11fIETimeoutInterval TimeoutInterval; + tDot11fIERICData RICData; + tDot11fIEHTCaps HTCaps; + tDot11fIEht2040_bss_coexistence ht2040_bss_coexistence; + tDot11fIELinkIdentifier LinkIdentifier; + tDot11fIEWMMInfoStation WMMInfoStation; + tDot11fIEAID AID; + tDot11fIEVHTCaps VHTCaps; +} tDot11fTDLSSetupReq; + +#define DOT11F_TDLSSETUPREQ (36) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_tdls_setup_req(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fTDLSSetupReq * pFrm); +uint32_t dot11f_pack_tdls_setup_req(tpAniSirGlobal pCtx, + tDot11fTDLSSetupReq *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_tdls_setup_req_size(tpAniSirGlobal pCtx, + tDot11fTDLSSetupReq *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fTDLSSetupRsp{ + tDot11fFfCategory Category; + tDot11fFfAction Action; + tDot11fFfStatus Status; + tDot11fFfDialogToken DialogToken; + tDot11fFfCapabilities Capabilities; + tDot11fIESuppRates SuppRates; + tDot11fIECountry Country; + tDot11fIEExtSuppRates ExtSuppRates; + tDot11fIESuppChannels SuppChannels; + tDot11fIERSN RSN; + tDot11fIEExtCap ExtCap; + tDot11fIESuppOperatingClasses SuppOperatingClasses; + tDot11fIEQOSCapsStation QOSCapsStation; + tDot11fIEFTInfo FTInfo; + tDot11fIETimeoutInterval TimeoutInterval; + tDot11fIERICData RICData; + tDot11fIEHTCaps HTCaps; + tDot11fIEht2040_bss_coexistence ht2040_bss_coexistence; + tDot11fIELinkIdentifier LinkIdentifier; + tDot11fIEWMMInfoStation WMMInfoStation; + tDot11fIEAID AID; + tDot11fIEVHTCaps VHTCaps; + tDot11fIEOperatingMode OperatingMode; +} tDot11fTDLSSetupRsp; + +#define DOT11F_TDLSSETUPRSP (37) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_tdls_setup_rsp(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fTDLSSetupRsp * pFrm); +uint32_t dot11f_pack_tdls_setup_rsp(tpAniSirGlobal pCtx, + tDot11fTDLSSetupRsp *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_tdls_setup_rsp_size(tpAniSirGlobal pCtx, + tDot11fTDLSSetupRsp *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fTDLSTeardown{ + tDot11fFfCategory Category; + tDot11fFfAction Action; + tDot11fFfReason Reason; + tDot11fIEFTInfo FTInfo; + tDot11fIELinkIdentifier LinkIdentifier; +} tDot11fTDLSTeardown; + +#define DOT11F_TDLSTEARDOWN (38) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_tdls_teardown(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fTDLSTeardown * pFrm); +uint32_t dot11f_pack_tdls_teardown(tpAniSirGlobal pCtx, + tDot11fTDLSTeardown *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_tdls_teardown_size(tpAniSirGlobal pCtx, + tDot11fTDLSTeardown *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fTPCReport{ + tDot11fFfCategory Category; + tDot11fFfAction Action; + tDot11fFfDialogToken DialogToken; + tDot11fIETPCReport TPCReport; +} tDot11fTPCReport; + +#define DOT11F_TPCREPORT (39) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_tpc_report(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fTPCReport * pFrm); +uint32_t dot11f_pack_tpc_report(tpAniSirGlobal pCtx, + tDot11fTPCReport *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_tpc_report_size(tpAniSirGlobal pCtx, + tDot11fTPCReport *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fTPCRequest{ + tDot11fFfCategory Category; + tDot11fFfAction Action; + tDot11fFfDialogToken DialogToken; + tDot11fIETPCRequest TPCRequest; +} tDot11fTPCRequest; + +#define DOT11F_TPCREQUEST (40) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_tpc_request(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fTPCRequest * pFrm); +uint32_t dot11f_pack_tpc_request(tpAniSirGlobal pCtx, + tDot11fTPCRequest *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_tpc_request_size(tpAniSirGlobal pCtx, + tDot11fTPCRequest *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fTimingAdvertisementFrame{ + tDot11fFfTimeStamp TimeStamp; + tDot11fFfCapabilities Capabilities; + tDot11fIECountry Country; + tDot11fIEPowerConstraints PowerConstraints; + tDot11fIETimeAdvertisement TimeAdvertisement; + tDot11fIEExtCap ExtCap; + tDot11fIEVendor1IE Vendor1IE; + tDot11fIEVendor3IE Vendor3IE; +} tDot11fTimingAdvertisementFrame; + +#define DOT11F_TIMINGADVERTISEMENTFRAME (41) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_timing_advertisement_frame(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fTimingAdvertisementFrame * pFrm); +uint32_t dot11f_pack_timing_advertisement_frame(tpAniSirGlobal pCtx, + tDot11fTimingAdvertisementFrame *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_timing_advertisement_frame_size(tpAniSirGlobal pCtx, + tDot11fTimingAdvertisementFrame *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fVHTGidManagementActionFrame{ + tDot11fFfCategory Category; + tDot11fFfAction Action; + tDot11fFfVhtMembershipStatusArray VhtMembershipStatusArray; + tDot11fFfVhtUserPositionArray VhtUserPositionArray; +} tDot11fVHTGidManagementActionFrame; + +#define DOT11F_VHTGIDMANAGEMENTACTIONFRAME (42) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_vht_gid_management_action_frame(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fVHTGidManagementActionFrame * pFrm); +uint32_t dot11f_pack_vht_gid_management_action_frame(tpAniSirGlobal pCtx, + tDot11fVHTGidManagementActionFrame *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_vht_gid_management_action_frame_size(tpAniSirGlobal pCtx, + tDot11fVHTGidManagementActionFrame *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fWMMAddTSRequest{ + tDot11fFfCategory Category; + tDot11fFfAction Action; + tDot11fFfDialogToken DialogToken; + tDot11fFfStatusCode StatusCode; + tDot11fIEWMMTSPEC WMMTSPEC; + tDot11fIEESETrafStrmRateSet ESETrafStrmRateSet; +} tDot11fWMMAddTSRequest; + +#define DOT11F_WMMADDTSREQUEST (43) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_wmm_add_ts_request(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fWMMAddTSRequest * pFrm); +uint32_t dot11f_pack_wmm_add_ts_request(tpAniSirGlobal pCtx, + tDot11fWMMAddTSRequest *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_wmm_add_ts_request_size(tpAniSirGlobal pCtx, + tDot11fWMMAddTSRequest *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fWMMAddTSResponse{ + tDot11fFfCategory Category; + tDot11fFfAction Action; + tDot11fFfDialogToken DialogToken; + tDot11fFfStatusCode StatusCode; + tDot11fIEWMMTSPEC WMMTSPEC; + tDot11fIEESETrafStrmMet ESETrafStrmMet; +} tDot11fWMMAddTSResponse; + +#define DOT11F_WMMADDTSRESPONSE (44) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_wmm_add_ts_response(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fWMMAddTSResponse * pFrm); +uint32_t dot11f_pack_wmm_add_ts_response(tpAniSirGlobal pCtx, + tDot11fWMMAddTSResponse *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_wmm_add_ts_response_size(tpAniSirGlobal pCtx, + tDot11fWMMAddTSResponse *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fWMMDelTS{ + tDot11fFfCategory Category; + tDot11fFfAction Action; + tDot11fFfDialogToken DialogToken; + tDot11fFfStatusCode StatusCode; + tDot11fIEWMMTSPEC WMMTSPEC; +} tDot11fWMMDelTS; + +#define DOT11F_WMMDELTS (45) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_wmm_del_ts(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fWMMDelTS * pFrm); +uint32_t dot11f_pack_wmm_del_ts(tpAniSirGlobal pCtx, + tDot11fWMMDelTS *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_wmm_del_ts_size(tpAniSirGlobal pCtx, + tDot11fWMMDelTS *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fext_channel_switch_action_frame{ + tDot11fFfCategory Category; + tDot11fFfAction Action; + tDot11fFfext_chan_switch_ann_action ext_chan_switch_ann_action; +} tDot11fext_channel_switch_action_frame; + +#define DOT11F_EXT_CHANNEL_SWITCH_ACTION_FRAME (46) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_ext_channel_switch_action_frame(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fext_channel_switch_action_frame * pFrm); +uint32_t dot11f_pack_ext_channel_switch_action_frame(tpAniSirGlobal pCtx, + tDot11fext_channel_switch_action_frame *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_ext_channel_switch_action_frame_size(tpAniSirGlobal pCtx, + tDot11fext_channel_switch_action_frame *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fht2040_bss_coexistence_mgmt_action_frame{ + tDot11fFfCategory Category; + tDot11fFfAction Action; + tDot11fIEht2040_bss_coexistence ht2040_bss_coexistence; + tDot11fIEht2040_bss_intolerant_report ht2040_bss_intolerant_report; +} tDot11fht2040_bss_coexistence_mgmt_action_frame; + +#define DOT11F_HT2040_BSS_COEXISTENCE_MGMT_ACTION_FRAME (47) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_ht2040_bss_coexistence_mgmt_action_frame(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fht2040_bss_coexistence_mgmt_action_frame * pFrm); +uint32_t dot11f_pack_ht2040_bss_coexistence_mgmt_action_frame(tpAniSirGlobal pCtx, + tDot11fht2040_bss_coexistence_mgmt_action_frame *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_ht2040_bss_coexistence_mgmt_action_frameSize(tpAniSirGlobal pCtx, + tDot11fht2040_bss_coexistence_mgmt_action_frame *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fp2p_oper_chan_change_confirm{ + tDot11fFfCategory Category; + tDot11fFfp2p_action_oui p2p_action_oui; + tDot11fFfp2p_action_subtype p2p_action_subtype; + tDot11fFfDialogToken DialogToken; + tDot11fIEHTCaps HTCaps; + tDot11fIEVHTCaps VHTCaps; + tDot11fIEOperatingMode OperatingMode; +} tDot11fp2p_oper_chan_change_confirm; + +#define DOT11F_P2P_OPER_CHAN_CHANGE_CONFIRM (48) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_p2p_oper_chan_change_confirm(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fp2p_oper_chan_change_confirm * pFrm); +uint32_t dot11f_pack_p2p_oper_chan_change_confirm(tpAniSirGlobal pCtx, + tDot11fp2p_oper_chan_change_confirm *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_p2p_oper_chan_change_confirmSize(tpAniSirGlobal pCtx, + tDot11fp2p_oper_chan_change_confirm *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +#endif /* DOT11F_H */ diff --git a/drivers/staging/qcacld-3.0/core/mac/src/include/dph_global.h b/drivers/staging/qcacld-3.0/core/mac/src/include/dph_global.h new file mode 100644 index 0000000000000000000000000000000000000000..63236b9be124df3ba1f997301fe8e3284f1ddc85 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/include/dph_global.h @@ -0,0 +1,286 @@ +/* + * Copyright (c) 2011-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + + * + + * Author: Sandesh Goel + + * Date: 02/25/02 + + * History:- + + * Date Modified by Modification Information + + * -------------------------------------------------------------------- + + * + + */ + +#ifndef __DPH_GLOBAL_H__ +#define __DPH_GLOBAL_H__ + +#include "lim_global.h" +#include "sir_mac_prot_def.h" +#include "sir_mac_prop_exts.h" +#include "sir_api.h" + +/* Following determines whether statistics are maintained or not */ +#define DPH_STATS + +/* STAID for Management frames */ +#define DPH_USE_MGMT_STAID -1 + +/* Keep Alive frames */ +#define DPH_NON_KEEPALIVE_FRAME 0 +#define DPH_KEEPALIVE_FRAME 1 + +/* DPH Hash Index for BSS(STA's Peer) on station. */ +#define DPH_STA_HASH_INDEX_PEER 1 + +#ifdef WLAN_FEATURE_11W +/* DPH PMF SA Query state for station */ +#define DPH_SA_QUERY_NOT_IN_PROGRESS 1 +#define DPH_SA_QUERY_IN_PROGRESS 2 +#define DPH_SA_QUERY_TIMED_OUT 3 +#endif + +typedef struct sDphRateBasedCtr { + uint32_t hi; + uint32_t lo; +} tDphRateBasedCtr; + +typedef struct sDphPhyRates { + uint8_t dataRateX2; + uint8_t ackRateX2; + uint8_t rtsRateX2; +} tDphPhyRates; + +typedef struct sDphIFSValues { + uint8_t sifs; + uint8_t pifs; + uint8_t difs; + uint8_t preamble; +} tDphIFSValues; + +typedef struct sDphQosParams { + uint8_t addtsPresent; + tSirAddtsReqInfo addts; + tSirMacQosCapabilityStaIE capability; +} tDphQosParams; + +/* Queue attribute structure */ +typedef struct sDphQueueAttr { + uint16_t valid:1; + uint16_t seqNum:12; + uint16_t ackPolicy:2; + uint16_t rsvd:1; +} tDphQueueAttr, *tpDphQueueAttr; + +/** + * struct parsed_ies: Parsed IE's of BSS capability + * @ht_caps: HT caps IE + * @vht_caps: VHT caps IE + * @ht_operation: HT operation IE + * @vht_operation: VHT operation IE + * @hs20vendor_ie: HS2.0 vendor IE + * + * This structure holds the parsed IE of connected BSS + * and this is not the intersection of BSS and STA + * capability. For example, if BSS supports 80 MHz + * and STA connects to BSS in 20 MHz, this structure + * holds 80 MHz as peer capability. + */ +struct parsed_ies { + tDot11fIEHTCaps ht_caps; + tDot11fIEVHTCaps vht_caps; + tDot11fIEHTInfo ht_operation; + tDot11fIEVHTOperation vht_operation; + tDot11fIEhs20vendor_ie hs20vendor_ie; +}; + +/* STA state node */ +typedef struct sDphHashNode { + /* + * BYTE 0 + * HASH ENTRY FIELDS NOT NEEDED IN HAL. + * This STA valid or not + */ + uint8_t valid:1; + uint8_t encPolicy:3; + uint8_t defaultKey:1; + uint8_t defaultKeyId:2; + uint8_t qosMode:1; + /* BYTE 1 */ + uint8_t erpEnabled:1; + /* This has been added to the dph hash table */ + uint8_t added:1; + uint8_t linkTestOn:1; + uint8_t shortPreambleEnabled:1; + uint8_t shortSlotTimeEnabled:1; + uint8_t stopTx:1; + /* set if both ap and sta are wme capable */ + uint8_t wmeEnabled:1; + /* set if both ap and sta are 11e capable */ + uint8_t lleEnabled:1; + /* BYTE 2 */ + /* set if both ap and sta are wsm capable */ + uint8_t wsmEnabled:1; + /* station gave version info */ + uint8_t versionPresent:1; + /* allow bursting regardless of qosMode */ + uint8_t burstEnableForce:1; + uint8_t staAuthenticated:1; + uint8_t fAniCount:1; + uint8_t rmfEnabled:1; + /* Fragmentation size */ + uint16_t fragSize; + /* LIM state */ + tLimMlmStaContext mlmStaContext; + /* Number of Tim to wait if the STA doesn't respond / fetch data */ + uint8_t timWaitCount; + /* Number of Successful MPDU's being sent */ + uint32_t curTxMpduCnt; + /* number of consecutive TIMs sent without response */ + uint8_t numTimSent; + /* qos parameter info */ + tDphQosParams qos; + /* station version info - valid only if versionPresent is set */ + tSirMacPropVersion version; +#ifdef PLM_WDS + uint8_t wdsIndex; + uint8_t wdsPeerBeaconSeen; +#endif + /* Taurus capabilities */ + uint16_t baPolicyFlag; /* BA Policy for each TID. */ + /* + * All the legacy and airgo supported rates. + */ + tSirSupportedRates supportedRates; + uint8_t htGreenfield:1; + uint8_t htShortGI40Mhz:1; + uint8_t htShortGI20Mhz:1; + /* DSSS/CCK at 40 MHz: Enabled 1 or Disabled */ + uint8_t htDsssCckRate40MHzSupport:1; + /* L-SIG TXOP Protection used only if peer support available */ + uint8_t htLsigTXOPProtection:1; + /* + * A-MPDU Density + * 000 - No restriction + * 001 - 1/8 usec + * 010 - 1/4 usec + * 011 - 1/2 usec + * 100 - 1 usec + * 101 - 2 usec + * 110 - 4 usec + * 111 - 8 usec + */ + uint8_t htAMpduDensity:3; + /* Set to 0 for 3839 octets */ + /* Set to 1 for 7935 octets */ + uint8_t htMaxAmsduLength; + /* MIMO Power Save */ + tSirMacHTMIMOPowerSaveState htMIMOPSState; + /* */ + /* Maximum Rx A-MPDU factor */ + uint8_t htMaxRxAMpduFactor:3; + /* + * Recommended Tx Width Set + * 0 - use 20 MHz channel (control channel) + * 1 - use 40 Mhz channel + */ + uint8_t htSupportedChannelWidthSet:1; + uint8_t htSecondaryChannelOffset:2; + uint8_t rsvd1:2; + /* DPH HASH ENTRY FIELDS NEEDED IN HAL ONLY */ + uint8_t dpuSig:4; /* DPU signiture */ + uint8_t staSig:4; /* STA signature */ + uint8_t staType; + uint16_t bssId; /* BSSID */ + uint16_t assocId; /* Association ID */ + /* This is the real sta index generated by HAL */ + uint16_t staIndex; + uint8_t staAddr[6]; + /* + * The DPU signatures will be sent eventually to TL to help + * it determine the association to which a packet belongs to + */ + /*Unicast DPU signature */ + uint8_t ucUcastSig; + /*Broadcast DPU signature */ + uint8_t ucBcastSig; + + uint8_t vhtSupportedChannelWidthSet; + uint8_t vhtSupportedRxNss; + uint8_t vhtBeamFormerCapable; + uint8_t vht_su_bfee_capable; +#ifdef WLAN_FEATURE_11W + uint8_t pmfSaQueryState; + uint8_t pmfSaQueryRetryCount; + uint16_t pmfSaQueryCurrentTransId; + uint16_t pmfSaQueryStartTransId; + TX_TIMER pmfSaQueryTimer; + unsigned long last_unprot_deauth_disassoc; + uint8_t proct_deauh_disassoc_cnt; + unsigned long last_assoc_received_time; +#endif + uint8_t htLdpcCapable; + uint8_t vhtLdpcCapable; +#ifdef FEATURE_WLAN_TDLS + uint16_t ht_caps; + uint32_t vht_caps; +#endif + uint8_t timingMeasCap; + /* key installed for this STA or not in the firmware */ + uint8_t is_key_installed; + uint8_t is_disassoc_deauth_in_progress; + + uint8_t nss; + int8_t del_sta_ctx_rssi; + bool sta_deletion_in_progress; + struct parsed_ies parsed_ies; + + /* + * When a station with already an existing dph entry tries to + * associate again, the old dph entry will be zeroed out except + * for the next pointer. The next pointer must be defined at the + * end of the structure. + */ + struct sDphHashNode *next; +} tDphHashNode, *tpDphHashNode; + +#include "dph_hash_table.h" + +/* ------------------------------------------------------------------- */ +typedef struct sAniSirDph { + /* The hash table object */ + dphHashTableClass dphHashTable; +} tAniSirDph, *tpAniSirDph; + +#endif diff --git a/drivers/staging/qcacld-3.0/core/mac/src/include/parser_api.h b/drivers/staging/qcacld-3.0/core/mac/src/include/parser_api.h new file mode 100644 index 0000000000000000000000000000000000000000..75e9463fa1a98ae82adc201030236ecf510e7610 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/include/parser_api.h @@ -0,0 +1,1006 @@ +/* + * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * This file parser_api.h contains the definitions used + * for parsing received 802.11 frames + * Author: Chandra Modumudi + * Date: 02/11/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + * + */ +#ifndef __PARSE_H__ +#define __PARSE_H__ + +#include +#include "sir_mac_prop_exts.h" +#include "dot11f.h" +#include "lim_ft_defs.h" +#include "lim_session.h" + +#define COUNTRY_STRING_LENGTH (3) +#define COUNTRY_INFO_MAX_CHANNEL (84) +#define MAX_SIZE_OF_TRIPLETS_IN_COUNTRY_IE (COUNTRY_STRING_LENGTH * \ + COUNTRY_INFO_MAX_CHANNEL) +#define HIGHEST_24GHZ_CHANNEL_NUM (14) + +#define IS_24G_CH(__chNum) ((__chNum > 0) && (__chNum < 15)) +#define IS_5G_CH(__chNum) ((__chNum >= 36) && (__chNum <= 165)) +#define IS_2X2_CHAIN(__chain) ((__chain & 0x3) == 0x3) +#define DISABLE_NSS2_MCS 0xC + +#define NSS_1x1_MODE 1 +#define NSS_2x2_MODE 2 +#define MBO_IE_ASSOC_DISALLOWED_SUBATTR_ID 0x04 + +/* QCN IE definitions */ +#define QCN_IE_HDR_LEN 6 + +#define QCN_IE_VERSION_SUBATTR_ID 1 +#define QCN_IE_VERSION_SUBATTR_DATA_LEN 2 +#define QCN_IE_VERSION_SUBATTR_LEN 4 +#define QCN_IE_VERSION_SUPPORTED 1 +#define QCN_IE_SUBVERSION_SUPPORTED 0 + +#define SIZE_OF_FIXED_PARAM 12 +#define SIZE_OF_TAG_PARAM_NUM 1 +#define SIZE_OF_TAG_PARAM_LEN 1 +#define RSNIEID 0x30 +#define RSNIE_CAPABILITY_LEN 2 +#define DEFAULT_RSNIE_CAP_VAL 0x00 + +#define SIZE_MASK 0x7FFF +#define FIXED_MASK 0x8000 + +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE +#define QCOM_VENDOR_IE_MCC_AVOID_CH 0x01 + +struct sAvoidChannelIE { + /* following must be 0xDD (221) */ + uint8_t tag_number; + uint8_t length; + /* following must be 00-A0-C6 */ + uint8_t oui[3]; + /* following must be 0x01 */ + uint8_t type; + uint8_t channel; +}; +#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ + +typedef struct sSirCountryInformation { + uint8_t countryString[COUNTRY_STRING_LENGTH]; + uint8_t numIntervals; /* number of channel intervals */ + struct channelPowerLim { + uint8_t channelNumber; + uint8_t numChannel; + uint8_t maxTransmitPower; + } channelTransmitPower[COUNTRY_INFO_MAX_CHANNEL]; +} tSirCountryInformation, *tpSirCountryInformation; + +typedef struct sSirQCNIE { + bool is_present; + uint8_t version; + uint8_t sub_version; +} tSirQCNIE, *tpSirQCNIE; + +/* Structure common to Beacons & Probe Responses */ +typedef struct sSirProbeRespBeacon { + tSirMacTimeStamp timeStamp; + uint16_t beaconInterval; + tSirMacCapabilityInfo capabilityInfo; + + tSirMacSSid ssId; + tSirMacRateSet supportedRates; + tSirMacRateSet extendedRates; + tSirMacChanNum channelNumber; + tSirMacCfParamSet cfParamSet; + tSirMacTim tim; + tSirMacEdcaParamSetIE edcaParams; + tSirMacQosCapabilityIE qosCapability; + + tSirCountryInformation countryInfoParam; + tSirMacWpaInfo wpa; + tSirMacRsnInfo rsn; + + tSirMacErpInfo erpIEInfo; + + tSirPropIEStruct propIEinfo; + tDot11fIEPowerConstraints localPowerConstraint; + tDot11fIETPCReport tpcReport; + tDot11fIEChanSwitchAnn channelSwitchIE; + tDot11fIEsec_chan_offset_ele sec_chan_offset; + tDot11fIEext_chan_switch_ann ext_chan_switch; + tDot11fIESuppOperatingClasses supp_operating_classes; + tSirMacAddr bssid; + tDot11fIEQuiet quietIE; + tDot11fIEHTCaps HTCaps; + tDot11fIEHTInfo HTInfo; + tDot11fIEP2PProbeRes P2PProbeRes; + uint8_t mdie[SIR_MDIE_SIZE]; +#ifdef FEATURE_WLAN_ESE + tDot11fIEESETxmitPower eseTxPwr; + tDot11fIEQBSSLoad QBSSLoad; +#endif + uint8_t ssidPresent; + uint8_t suppRatesPresent; + uint8_t extendedRatesPresent; + uint8_t supp_operating_class_present; + uint8_t cfPresent; + uint8_t dsParamsPresent; + uint8_t timPresent; + + uint8_t edcaPresent; + uint8_t qosCapabilityPresent; + uint8_t wmeEdcaPresent; + uint8_t wmeInfoPresent; + uint8_t wsmCapablePresent; + + uint8_t countryInfoPresent; + uint8_t wpaPresent; + uint8_t rsnPresent; + uint8_t erpPresent; + uint8_t channelSwitchPresent; + uint8_t sec_chan_offset_present; + uint8_t ext_chan_switch_present; + uint8_t quietIEPresent; + uint8_t tpcReportPresent; + uint8_t powerConstraintPresent; + + uint8_t mdiePresent; + + tDot11fIEVHTCaps VHTCaps; + tDot11fIEVHTOperation VHTOperation; + tDot11fIEVHTExtBssLoad VHTExtBssLoad; + tDot11fIEExtCap ext_cap; + tDot11fIEOperatingMode OperatingMode; + uint8_t WiderBWChanSwitchAnnPresent; + tDot11fIEWiderBWChanSwitchAnn WiderBWChanSwitchAnn; + uint8_t Vendor1IEPresent; + tDot11fIEvendor_vht_ie vendor_vht_ie; + uint8_t Vendor3IEPresent; + tDot11fIEhs20vendor_ie hs20vendor_ie; + tDot11fIEIBSSParams IBSSParams; +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE + tDot11fIEQComVendorIE AvoidChannelIE; +#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ +#ifdef FEATURE_WLAN_ESE + uint8_t is_ese_ver_ie_present; +#endif + tDot11fIEOBSSScanParameters obss_scanparams; + bool MBO_IE_present; + uint8_t MBO_capability; + bool assoc_disallowed; + uint8_t assoc_disallowed_reason; + tSirQCNIE QCN_IE; +} tSirProbeRespBeacon, *tpSirProbeRespBeacon; + +/* probe Request structure */ +typedef struct sSirProbeReq { + tSirMacSSid ssId; + tSirMacRateSet supportedRates; + tSirMacRateSet extendedRates; + tDot11fIEWscProbeReq probeReqWscIeInfo; + tDot11fIEHTCaps HTCaps; + uint8_t ssidPresent; + uint8_t suppRatesPresent; + uint8_t extendedRatesPresent; + uint8_t wscIePresent; + uint8_t p2pIePresent; + tDot11fIEVHTCaps VHTCaps; +} tSirProbeReq, *tpSirProbeReq; + +/* / Association Request structure (one day to be replaced by */ +/* / tDot11fAssocRequest) */ +typedef struct sSirAssocReq { + + tSirMacCapabilityInfo capabilityInfo; + uint16_t listenInterval; + tSirMacAddr currentApAddr; /* only in reassoc frames */ + tSirMacSSid ssId; + tSirMacRateSet supportedRates; + tSirMacRateSet extendedRates; + + tSirAddtsReqInfo addtsReq; + tSirMacQosCapabilityStaIE qosCapability; + + tSirMacWapiInfo wapi; + tSirMacWpaInfo wpa; + tSirMacRsnInfo rsn; + tSirAddie addIE; + + tSirPropIEStruct propIEinfo; + tSirMacPowerCapabilityIE powerCapability; + tSirMacSupportedChannelIE supportedChannels; + tDot11fIEHTCaps HTCaps; + tDot11fIEWMMInfoStation WMMInfoStation; + /* / This is set if the frame is a reassoc request: */ + uint8_t reassocRequest; + uint8_t ssidPresent; + uint8_t suppRatesPresent; + uint8_t extendedRatesPresent; + + uint8_t wmeInfoPresent; + uint8_t qosCapabilityPresent; + uint8_t addtsPresent; + uint8_t wsmCapablePresent; + + uint8_t wapiPresent; + uint8_t wpaPresent; + uint8_t rsnPresent; + uint8_t addIEPresent; + + uint8_t powerCapabilityPresent; + uint8_t supportedChannelsPresent; + /* keeping copy of association request received, this is + required for indicating the frame to upper layers */ + uint32_t assocReqFrameLength; + uint8_t *assocReqFrame; + tDot11fIEVHTCaps VHTCaps; + tDot11fIEOperatingMode operMode; + tDot11fIEExtCap ExtCap; + tDot11fIEvendor_vht_ie vendor_vht_ie; + tDot11fIEhs20vendor_ie hs20vendor_ie; +} tSirAssocReq, *tpSirAssocReq; + +/* / Association Response structure (one day to be replaced by */ +/* / tDot11fAssocRequest) */ +typedef struct sSirAssocRsp { + + tSirMacCapabilityInfo capabilityInfo; + uint16_t aid; + uint16_t statusCode; + tSirMacRateSet supportedRates; + tSirMacRateSet extendedRates; + tSirPropIEStruct propIEinfo; + tSirMacEdcaParamSetIE edca; + tSirAddtsRspInfo addtsRsp; + tDot11fIEHTCaps HTCaps; + tDot11fIEHTInfo HTInfo; + tDot11fIEFTInfo FTInfo; + uint8_t mdie[SIR_MDIE_SIZE]; + uint8_t num_RICData; + tDot11fIERICDataDesc RICData[2]; + +#ifdef FEATURE_WLAN_ESE + uint8_t num_tspecs; + tDot11fIEWMMTSPEC TSPECInfo[SIR_ESE_MAX_TSPEC_IES]; + tSirMacESETSMIE tsmIE; +#endif + + uint8_t suppRatesPresent; + uint8_t extendedRatesPresent; + + uint8_t edcaPresent; + uint8_t wmeEdcaPresent; + uint8_t addtsPresent; + uint8_t wsmCapablePresent; + uint8_t ftinfoPresent; + uint8_t mdiePresent; + uint8_t ricPresent; +#ifdef FEATURE_WLAN_ESE + uint8_t tspecPresent; + uint8_t tsmPresent; +#endif + tDot11fIEVHTCaps VHTCaps; + tDot11fIEVHTOperation VHTOperation; + tDot11fIEExtCap ExtCap; + tSirQosMapSet QosMapSet; +#ifdef WLAN_FEATURE_11W + tDot11fIETimeoutInterval TimeoutInterval; +#endif + tDot11fIEvendor_vht_ie vendor_vht_ie; + tDot11fIEOBSSScanParameters obss_scanparams; + tSirQCNIE QCN_IE; +} tSirAssocRsp, *tpSirAssocRsp; + +#ifdef FEATURE_WLAN_ESE +/* Structure to hold ESE Beacon report mandatory IEs */ +typedef struct sSirEseBcnReportMandatoryIe { + tSirMacSSid ssId; + tSirMacRateSet supportedRates; + tSirMacFHParamSet fhParamSet; + tSirMacDsParamSetIE dsParamSet; + tSirMacCfParamSet cfParamSet; + tSirMacIBSSParams ibssParamSet; + tSirMacTim tim; + tSirMacRRMEnabledCap rmEnabledCapabilities; + + uint8_t ssidPresent; + uint8_t suppRatesPresent; + uint8_t fhParamPresent; + uint8_t dsParamsPresent; + uint8_t cfPresent; + uint8_t ibssParamPresent; + uint8_t timPresent; + uint8_t rrmPresent; +} tSirEseBcnReportMandatoryIe, *tpSirEseBcnReportMandatoryIe; +#endif /* FEATURE_WLAN_ESE */ + +/** + * struct s_ext_cap - holds bitfields of extended capability IE + * + * s_ext_cap holds bitfields of extended capability IE. In dot11f files + * extended capability IE information is stored as an array of bytes. + * This structure is used to encode/decode the byte array present in + * dot11f IE structure. + */ + +struct s_ext_cap { + uint8_t bss_coexist_mgmt_support:1; + uint8_t reserved1:1; + uint8_t ext_chan_switch:1; + uint8_t reserved2:1; + uint8_t psmp_cap:1; + uint8_t reserved3:1; + uint8_t spsmp_cap:1; + uint8_t event:1; + uint8_t diagnostics:1; + uint8_t multi_diagnostics:1; + uint8_t loc_tracking:1; + uint8_t fms:1; + uint8_t proxy_arp_service:1; + uint8_t co_loc_intf_reporting:1; + uint8_t civic_loc:1; + uint8_t geospatial_loc:1; + uint8_t tfs:1; + uint8_t wnm_sleep_mode:1; + uint8_t tim_broadcast:1; + uint8_t bss_transition:1; + uint8_t qos_traffic_cap:1; + uint8_t ac_sta_cnt:1; + uint8_t multi_bssid:1; + uint8_t timing_meas:1; + uint8_t chan_usage:1; + uint8_t ssid_list:1; + uint8_t dms:1; + uint8_t utctsf_offset:1; + uint8_t tdls_peer_uapsd_buffer_sta:1; + uint8_t tdls_peer_psm_supp:1; + uint8_t tdls_channel_switching:1; + uint8_t interworking_service:1; + uint8_t qos_map:1; + uint8_t ebr:1; + uint8_t sspn_interface:1; + uint8_t reserved4:1; + uint8_t msg_cf_cap:1; + uint8_t tdls_support:1; + uint8_t tdls_prohibited:1; + uint8_t tdls_chan_swit_prohibited:1; + uint8_t reject_unadmitted_traffic:1; + uint8_t service_interval_granularity:3; + uint8_t identifier_loc:1; + uint8_t uapsd_coexistence:1; + uint8_t wnm_notification:1; + uint8_t qa_bcapbility:1; + uint8_t utf8_ssid:1; + uint8_t qmf_activated:1; + uint8_t qm_frecon_act:1; + uint8_t robust_av_streaming:1; + uint8_t advanced_gcr:1; + uint8_t mesh_gcr:1; + uint8_t scs:1; + uint8_t q_load_report:1; + uint8_t alternate_edca:1; + uint8_t unprot_txo_pneg:1; + uint8_t prot_txo_pneg:1; + uint8_t reserved6:1; + uint8_t prot_q_load_report:1; + uint8_t tdls_wider_bw:1; + uint8_t oper_mode_notification:1; + uint8_t max_num_of_msdu_bit1:1; + uint8_t max_num_of_msdu_bit2:1; + uint8_t chan_sch_mgmt:1; + uint8_t geo_db_inband_en_signal:1; + uint8_t nw_chan_control:1; + uint8_t white_space_map:1; + uint8_t chan_avail_query:1; + uint8_t fine_time_meas_responder:1; + uint8_t fine_time_meas_initiator:1; + uint8_t fils_capability:1; +}; + +uint8_t sirIsPropCapabilityEnabled(struct sAniSirGlobal *pMac, uint32_t bitnum); + +void dot11f_log(tpAniSirGlobal pMac, int nSev, const char *lpszFormat, ...); + +#define CFG_GET_INT(nStatus, pMac, nItem, cfg) do { \ + (nStatus) = wlan_cfg_get_int((pMac), (nItem), &(cfg)); \ + if (eSIR_SUCCESS != (nStatus)) { \ + dot11f_log((pMac), LOGP, FL("Failed to retrieve nItem from CFG (%d)."), (nStatus)); \ + return nStatus; \ + } \ +} while (0) + +#define CFG_GET_INT_NO_STATUS(nStatus, pMac, nItem, cfg) do { \ + (nStatus) = wlan_cfg_get_int((pMac), (nItem), &(cfg)); \ + if (eSIR_SUCCESS != (nStatus)) { \ + dot11f_log((pMac), LOGP, FL("Failed to retrieve nItem from CFG (%d)."), (nStatus)); \ + return; \ + } \ +} while (0) + +#define CFG_GET_STR(nStatus, pMac, nItem, cfg, nCfg, nMaxCfg) do { \ + (nCfg) = (nMaxCfg); \ + (nStatus) = wlan_cfg_get_str((pMac), (nItem), (cfg), &(nCfg)); \ + if (eSIR_SUCCESS != (nStatus)) { \ + dot11f_log((pMac), LOGP, FL("Failed to retrieve nItem from CFG (%d)."), (nStatus)); \ + return nStatus; \ + } \ +} while (0) + +#define CFG_GET_STR_NO_STATUS(nStatus, pMac, nItem, cfg, nCfg, nMaxCfg) do { \ + (nCfg) = (nMaxCfg); \ + (nStatus) = wlan_cfg_get_str((pMac), (nItem), (cfg), &(nCfg)); \ + if (eSIR_SUCCESS != (nStatus)) { \ + dot11f_log((pMac), LOGP, FL("Failed to retrieve nItem from CFG (%d)."), (nStatus)); \ + return; \ + } \ +} while (0) + +void swap_bit_field16(uint16_t in, uint16_t *out); + +/* Currently implemented as "shims" between callers & the new framesc- */ +/* generated code: */ + +tSirRetStatus +sir_convert_probe_req_frame2_struct(struct sAniSirGlobal *pMac, + uint8_t *frame, uint32_t len, + tpSirProbeReq probe); + +tSirRetStatus +sir_convert_probe_frame2_struct(struct sAniSirGlobal *pMac, uint8_t *frame, + uint32_t len, tpSirProbeRespBeacon probe); + +tSirRetStatus +sir_convert_assoc_req_frame2_struct(struct sAniSirGlobal *pMac, + uint8_t *frame, uint32_t len, + tpSirAssocReq assoc); + +tSirRetStatus +sir_convert_assoc_resp_frame2_struct(struct sAniSirGlobal *pMac, + uint8_t *frame, uint32_t len, + tpSirAssocRsp assoc); + +tSirRetStatus +sir_convert_reassoc_req_frame2_struct(struct sAniSirGlobal *pMac, + uint8_t *frame, uint32_t len, + tpSirAssocReq assoc); + +tSirRetStatus +sir_parse_beacon_ie(struct sAniSirGlobal *pMac, + tpSirProbeRespBeacon pBeaconStruct, + uint8_t *pPayload, uint32_t payloadLength); + +tSirRetStatus +sir_convert_beacon_frame2_struct(struct sAniSirGlobal *pMac, + uint8_t *pBeaconFrame, + tpSirProbeRespBeacon pBeaconStruct); + +tSirRetStatus +sir_convert_auth_frame2_struct(struct sAniSirGlobal *pMac, + uint8_t *frame, uint32_t len, + tpSirMacAuthFrameBody auth); + +tSirRetStatus +sir_convert_addts_req2_struct(struct sAniSirGlobal *pMac, + uint8_t *frame, uint32_t len, + tSirAddtsReqInfo *addTs); + +tSirRetStatus +sir_convert_addts_rsp2_struct(struct sAniSirGlobal *pMac, + uint8_t *frame, uint32_t len, + tSirAddtsRspInfo *addts); + +tSirRetStatus +sir_convert_delts_req2_struct(struct sAniSirGlobal *pMac, + uint8_t *frame, uint32_t len, + tSirDeltsReqInfo *delTs); +tSirRetStatus +sir_convert_qos_map_configure_frame2_struct(tpAniSirGlobal pMac, + uint8_t *pFrame, uint32_t nFrame, + tSirQosMapSet *pQosMapSet); + +#ifdef ANI_SUPPORT_11H +tSirRetStatus +sir_convert_tpc_req_frame2_struct(struct sAniSirGlobal *, uint8_t *, + tpSirMacTpcReqActionFrame, uint32_t); + +tSirRetStatus +sir_convert_meas_req_frame2_struct(struct sAniSirGlobal *, uint8_t *, + tpSirMacMeasReqActionFrame, uint32_t); +#endif + +/** + * \brief Populated a tDot11fFfCapabilities + * + * \sa PopulatedDot11fCapabilities2 + * + * + * \param pMac Pointer to the global MAC data structure + * + * \param pDot11f Address of a tDot11fFfCapabilities to be filled in + * + * + * \note If SIR_MAC_PROP_CAPABILITY_11EQOS is enabled, we'll clear the QOS + * bit in pDot11f + * + * + */ + +tSirRetStatus +populate_dot11f_capabilities(tpAniSirGlobal pMac, + tDot11fFfCapabilities *pDot11f, + tpPESession psessionEntry); + +/** + * \brief Populated a tDot11fFfCapabilities + * + * \sa PopulatedDot11fCapabilities2 + * + * + * \param pMac Pointer to the global MAC data structure + * + * \param pDot11f Address of a tDot11fFfCapabilities to be filled in + * + * \param pSta Pointer to a tDphHashNode representing a peer + * + * + * \note If SIR_MAC_PROP_CAPABILITY_11EQOS is enabled on our peer, we'll + * clear the QOS bit in pDot11f + * + * + */ + +struct sDphHashNode; + +tSirRetStatus +populate_dot11f_capabilities2(tpAniSirGlobal pMac, + tDot11fFfCapabilities *pDot11f, + struct sDphHashNode *pSta, + tpPESession psessionEntry); + +/* / Populate a tDot11fIEChanSwitchAnn */ +void +populate_dot11f_chan_switch_ann(tpAniSirGlobal pMac, + tDot11fIEChanSwitchAnn *pDot11f, + tpPESession psessionEntry); + +void +populate_dot_11_f_ext_chann_switch_ann(tpAniSirGlobal mac_ptr, + tDot11fIEext_chan_switch_ann *dot_11_ptr, + tpPESession session_entry); + +/* / Populate a tDot11fIEChannelSwitchWrapper */ +void +populate_dot11f_chan_switch_wrapper(tpAniSirGlobal pMac, + tDot11fIEChannelSwitchWrapper *pDot11f, + tpPESession psessionEntry); + +/* / Populate a tDot11fIECountry */ +tSirRetStatus +populate_dot11f_country(tpAniSirGlobal pMac, + tDot11fIECountry *pDot11f, tpPESession psessionEntry); + +/* Populated a populate_dot11f_ds_params */ +tSirRetStatus +populate_dot11f_ds_params(tpAniSirGlobal pMac, + tDot11fIEDSParams *pDot11f, uint8_t channel); + +/* / Populated a tDot11fIEEDCAParamSet */ +void +populate_dot11f_edca_param_set(tpAniSirGlobal pMac, + tDot11fIEEDCAParamSet *pDot11f, + tpPESession psessionEntry); + +tSirRetStatus +populate_dot11f_erp_info(tpAniSirGlobal pMac, + tDot11fIEERPInfo *pDot11f, tpPESession psessionEntry); + +tSirRetStatus +populate_dot11f_ext_supp_rates(tpAniSirGlobal pMac, + uint8_t nChannelNum, tDot11fIEExtSuppRates *pDot11f, + tpPESession psessionEntry); + +tSirRetStatus +populate_dot11f_beacon_report(tpAniSirGlobal pMac, + tDot11fIEMeasurementReport *pDot11f, + tSirMacBeaconReport *pBeaconReport); + +/** + * \brief Populate a tDot11fIEExtSuppRates + * + * + * \param pMac Pointer to the global MAC data structure + * + * \param nChannelNum Channel on which the enclosing frame will be going out + * + * \param pDot11f Address of a tDot11fIEExtSuppRates struct to be filled in. + * + * + * This method is a NOP if the channel is greater than 14. + * + * + */ + +tSirRetStatus +populate_dot11f_ext_supp_rates1(tpAniSirGlobal pMac, + uint8_t nChannelNum, + tDot11fIEExtSuppRates *pDot11f); + +tSirRetStatus +populate_dot11f_ht_caps(tpAniSirGlobal pMac, + tpPESession psessionEntry, tDot11fIEHTCaps *pDot11f); + +tSirRetStatus +populate_dot11f_ht_info(tpAniSirGlobal pMac, + tDot11fIEHTInfo *pDot11f, tpPESession psessionEntry); + +void populate_dot11f_ibss_params(tpAniSirGlobal pMac, + tDot11fIEIBSSParams *pDot11f, + tpPESession psessionEntry); + +#ifdef ANI_SUPPORT_11H +tSirRetStatus +populate_dot11f_measurement_report0(tpAniSirGlobal pMac, + tpSirMacMeasReqActionFrame pReq, + tDot11fIEMeasurementReport *pDot11f); + +/* / Populate a tDot11fIEMeasurementReport when the report type is CCA */ +tSirRetStatus +populate_dot11f_measurement_report1(tpAniSirGlobal pMac, + tpSirMacMeasReqActionFrame pReq, + tDot11fIEMeasurementReport *pDot11f); + +/* / Populate a tDot11fIEMeasurementReport when the report type is RPI Hist */ +tSirRetStatus +populate_dot11f_measurement_report2(tpAniSirGlobal pMac, + tpSirMacMeasReqActionFrame pReq, + tDot11fIEMeasurementReport *pDot11f); +#endif /* ANI_SUPPORT_11H */ + +/* / Populate a tDot11fIEPowerCaps */ +void +populate_dot11f_power_caps(tpAniSirGlobal pMac, + tDot11fIEPowerCaps *pCaps, + uint8_t nAssocType, tpPESession psessionEntry); + +/* / Populate a tDot11fIEPowerConstraints */ +tSirRetStatus +populate_dot11f_power_constraints(tpAniSirGlobal pMac, + tDot11fIEPowerConstraints *pDot11f); + +void +populate_dot11f_qos_caps_ap(tpAniSirGlobal pMac, + tDot11fIEQOSCapsAp *pDot11f, + tpPESession psessionEntry); + +void +populate_dot11f_qos_caps_station(tpAniSirGlobal pMac, tpPESession session, + tDot11fIEQOSCapsStation *pDot11f); + +tSirRetStatus +populate_dot11f_rsn(tpAniSirGlobal pMac, + tpSirRSNie pRsnIe, tDot11fIERSN *pDot11f); + +tSirRetStatus +populate_dot11f_rsn_opaque(tpAniSirGlobal pMac, + tpSirRSNie pRsnIe, tDot11fIERSNOpaque *pDot11f); + +#if defined(FEATURE_WLAN_WAPI) + +tSirRetStatus +populate_dot11f_wapi(tpAniSirGlobal pMac, + tpSirRSNie pRsnIe, tDot11fIEWAPI *pDot11f); + +tSirRetStatus populate_dot11f_wapi_opaque(tpAniSirGlobal pMac, + tpSirRSNie pRsnIe, + tDot11fIEWAPIOpaque *pDot11f); + +#endif /* defined(FEATURE_WLAN_WAPI) */ + +/* / Populate a tDot11fIESSID given a tSirMacSSid */ +void +populate_dot11f_ssid(tpAniSirGlobal pMac, + tSirMacSSid *pInternal, tDot11fIESSID *pDot11f); + +/* / Populate a tDot11fIESSID from CFG */ +tSirRetStatus populate_dot11f_ssid2(tpAniSirGlobal pMac, + tDot11fIESSID *pDot11f); + +/** + * \brief Populate a tDot11fIESchedule + * + * \sa populate_dot11f_wmm_schedule + * + * + * \param pSchedule Address of a tSirMacScheduleIE struct + * + * \param pDot11f Address of a tDot11fIESchedule to be filled in + * + * + */ + +void +populate_dot11f_schedule(tSirMacScheduleIE *pSchedule, + tDot11fIESchedule *pDot11f); + +void +populate_dot11f_supp_channels(tpAniSirGlobal pMac, + tDot11fIESuppChannels *pDot11f, + uint8_t nAssocType, tpPESession psessionEntry); + +/** + * \brief Populated a tDot11fIESuppRates + * + * + * \param pMac Pointer to the global MAC data structure + * + * \param nChannelNum Channel the enclosing frame will be going out on; see + * below + * + * \param pDot11f Address of a tDot11fIESuppRates struct to be filled in. + * + * + * If nChannelNum is greater than 13, the supported rates will be + * WNI_CFG_SUPPORTED_RATES_11B. If it is less than or equal to 13, the + * supported rates will be WNI_CFG_SUPPORTED_RATES_11A. If nChannelNum is + * set to the sentinel value POPULATE_DOT11F_RATES_OPERATIONAL, the struct + * will be populated with WNI_CFG_OPERATIONAL_RATE_SET. + * + * + */ + +#define POPULATE_DOT11F_RATES_OPERATIONAL (0xff) + +tSirRetStatus +populate_dot11f_supp_rates(tpAniSirGlobal pMac, + uint8_t nChannelNum, + tDot11fIESuppRates *pDot11f, tpPESession); + +tSirRetStatus +populate_dot11f_rates_tdls(tpAniSirGlobal p_mac, + tDot11fIESuppRates *p_supp_rates, + tDot11fIEExtSuppRates *p_ext_supp_rates, + uint8_t curr_oper_channel); + +tSirRetStatus populate_dot11f_tpc_report(tpAniSirGlobal pMac, + tDot11fIETPCReport *pDot11f, + tpPESession psessionEntry); + +/* / Populate a tDot11FfTSInfo */ +void populate_dot11f_ts_info(tSirMacTSInfo *pInfo, tDot11fFfTSInfo *pDot11f); + +void populate_dot11f_wmm(tpAniSirGlobal pMac, + tDot11fIEWMMInfoAp *pInfo, + tDot11fIEWMMParams *pParams, + tDot11fIEWMMCaps *pCaps, tpPESession psessionEntry); + +void populate_dot11f_wmm_caps(tDot11fIEWMMCaps *pCaps); + +#if defined(FEATURE_WLAN_ESE) +/* Fill the ESE version IE */ +void populate_dot11f_ese_version(tDot11fIEESEVersion *pESEVersion); +/* Fill the Radio Management Capability */ +void populate_dot11f_ese_rad_mgmt_cap(tDot11fIEESERadMgmtCap *pESERadMgmtCap); +/* Fill the CCKM IE */ +tSirRetStatus populate_dot11f_ese_cckm_opaque(tpAniSirGlobal pMac, + tpSirCCKMie pCCKMie, + tDot11fIEESECckmOpaque *pDot11f); + +void populate_dot11_tsrsie(tpAniSirGlobal pMac, + tSirMacESETSRSIE *pOld, + tDot11fIEESETrafStrmRateSet *pDot11f, + uint8_t rate_length); +void populate_dot11f_re_assoc_tspec(tpAniSirGlobal pMac, + tDot11fReAssocRequest *pReassoc, + tpPESession psessionEntry); +tSirRetStatus +sir_beacon_ie_ese_bcn_report(tpAniSirGlobal pMac, + uint8_t *pPayload, const uint32_t payloadLength, + uint8_t **outIeBuf, uint32_t *pOutIeLen); + +/** + * ese_populate_wmm_tspec() - Populates TSPEC info for + * reassoc + * @source: source structure + * @dest: destination structure + * + * This function copies TSPEC parameters from source + * structure to destination structure. + * + * Return: None + */ +void ese_populate_wmm_tspec(tSirMacTspecIE *source, ese_wmm_tspec_ie *dest); + +#endif + +void populate_dot11f_wmm_info_ap(tpAniSirGlobal pMac, + tDot11fIEWMMInfoAp *pInfo, + tpPESession psessionEntry); + +void populate_dot11f_wmm_info_station_per_session(tpAniSirGlobal pMac, + tpPESession psessionEntry, + tDot11fIEWMMInfoStation *pInfo); + +void populate_dot11f_wmm_params(tpAniSirGlobal pMac, + tDot11fIEWMMParams *pParams, + tpPESession psessionEntry); + +/** + * \brief Populate a tDot11fIEWMMSchedule + * + * \sa PopulatedDot11fSchedule + * + * + * \param pSchedule Address of a tSirMacScheduleIE struct + * + * \param pDot11f Address of a tDot11fIEWMMSchedule to be filled in + * + * + */ + +void +populate_dot11f_wmm_schedule(tSirMacScheduleIE *pSchedule, + tDot11fIEWMMSchedule *pDot11f); + +tSirRetStatus +populate_dot11f_wpa(tpAniSirGlobal pMac, + tpSirRSNie pRsnIe, tDot11fIEWPA *pDot11f); + +tSirRetStatus +populate_dot11f_wpa_opaque(tpAniSirGlobal pMac, + tpSirRSNie pRsnIe, tDot11fIEWPAOpaque *pDot11f); + +void populate_dot11f_tspec(tSirMacTspecIE *pOld, tDot11fIETSPEC *pDot11f); + +void populate_dot11f_wmmtspec(tSirMacTspecIE *pOld, tDot11fIEWMMTSPEC *pDot11f); + +tSirRetStatus +populate_dot11f_tclas(tpAniSirGlobal pMac, + tSirTclasInfo *pOld, tDot11fIETCLAS *pDot11f); + +tSirRetStatus +populate_dot11f_wmmtclas(tpAniSirGlobal pMac, + tSirTclasInfo *pOld, tDot11fIEWMMTCLAS *pDot11f); + +tSirRetStatus populate_dot11f_wsc(tpAniSirGlobal pMac, + tDot11fIEWscBeacon *pDot11f); + +tSirRetStatus populate_dot11f_wsc_registrar_info(tpAniSirGlobal pMac, + tDot11fIEWscBeacon *pDot11f); + +tSirRetStatus de_populate_dot11f_wsc_registrar_info(tpAniSirGlobal pMac, + tDot11fIEWscBeacon *pDot11f); + +tSirRetStatus populate_dot11f_probe_res_wpsi_es(tpAniSirGlobal pMac, + tDot11fIEWscProbeRes *pDot11f, + tpPESession psessionEntry); +tSirRetStatus populate_dot11f_assoc_res_wpsi_es(tpAniSirGlobal pMac, + tDot11fIEWscAssocRes *pDot11f, + tpPESession psessionEntry); +tSirRetStatus populate_dot11f_beacon_wpsi_es(tpAniSirGlobal pMac, + tDot11fIEWscBeacon *pDot11f, + tpPESession psessionEntry); + +tSirRetStatus populate_dot11f_wsc_in_probe_res(tpAniSirGlobal pMac, + tDot11fIEWscProbeRes *pDot11f); + +tSirRetStatus +populate_dot11f_wsc_registrar_info_in_probe_res(tpAniSirGlobal pMac, + tDot11fIEWscProbeRes *pDot11f); + +tSirRetStatus +de_populate_dot11f_wsc_registrar_info_in_probe_res(tpAniSirGlobal pMac, + tDot11fIEWscProbeRes *pDot11f); + +tSirRetStatus populate_dot11f_assoc_res_wsc_ie(tpAniSirGlobal pMac, + tDot11fIEWscAssocRes *pDot11f, + tpSirAssocReq pRcvdAssocReq); + +tSirRetStatus populate_dot11_assoc_res_p2p_ie(tpAniSirGlobal pMac, + tDot11fIEP2PAssocRes *pDot11f, + tpSirAssocReq pRcvdAssocReq); + +tSirRetStatus populate_dot11f_wscInAssocRes(tpAniSirGlobal pMac, + tDot11fIEWscAssocRes *pDot11f); + +tSirRetStatus populate_dot11f_wfatpc(tpAniSirGlobal pMac, + tDot11fIEWFATPC *pDot11f, uint8_t txPower, + uint8_t linkMargin); + +tSirRetStatus populate_dot11f_rrm_ie(tpAniSirGlobal pMac, + tDot11fIERRMEnabledCap *pDot11f, + tpPESession psessionEntry); + +void populate_mdie(tpAniSirGlobal pMac, + tDot11fIEMobilityDomain * pDot11f, uint8_t mdie[]); +void populate_ft_info(tpAniSirGlobal pMac, tDot11fIEFTInfo *pDot11f); + +void populate_dot11f_assoc_rsp_rates(tpAniSirGlobal pMac, + tDot11fIESuppRates *pSupp, + tDot11fIEExtSuppRates *pExt, + uint16_t *_11bRates, uint16_t *_11aRates); + +int find_ie_location(tpAniSirGlobal pMac, tpSirRSNie pRsnIe, uint8_t EID); + +void lim_log_vht_cap(tpAniSirGlobal pMac, tDot11fIEVHTCaps *pDot11f); + +tSirRetStatus +populate_dot11f_vht_caps(tpAniSirGlobal pMac, tpPESession psessionEntry, + tDot11fIEVHTCaps *pDot11f); + +tSirRetStatus +populate_dot11f_vht_operation(tpAniSirGlobal pMac, + tpPESession psessionEntry, + tDot11fIEVHTOperation *pDot11f); + +tSirRetStatus +populate_dot11f_vht_ext_bss_load(tpAniSirGlobal pMac, + tDot11fIEVHTExtBssLoad *pDot11f); + +tSirRetStatus +populate_dot11f_ext_cap(tpAniSirGlobal pMac, bool isVHTEnabled, + tDot11fIEExtCap *pDot11f, tpPESession psessionEntry); + +void populate_dot11f_qcn_ie(tDot11fIEQCN_IE *pDot11f); + +tSirRetStatus +populate_dot11f_operating_mode(tpAniSirGlobal pMac, + tDot11fIEOperatingMode *pDot11f, + tpPESession psessionEntry); + +void +populate_dot11f_wider_bw_chan_switch_ann(tpAniSirGlobal pMac, + tDot11fIEWiderBWChanSwitchAnn *pDot11f, + tpPESession psessionEntry); + +void populate_dot11f_timeout_interval(tpAniSirGlobal pMac, + tDot11fIETimeoutInterval *pDot11f, + uint8_t type, uint32_t value); + +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE +/* Populate a tDot11fIEQComVendorIE */ +void +populate_dot11f_avoid_channel_ie(tpAniSirGlobal mac_ctx, + tDot11fIEQComVendorIE *dot11f, + tpPESession session_entry); +#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ + +tSirRetStatus populate_dot11f_timing_advert_frame(tpAniSirGlobal pMac, + tDot11fTimingAdvertisementFrame *frame); +void populate_dot11_supp_operating_classes(tpAniSirGlobal mac_ptr, + tDot11fIESuppOperatingClasses *dot_11_ptr, tpPESession session_entry); + +tSirRetStatus +sir_validate_and_rectify_ies(tpAniSirGlobal mac_ctx, + uint8_t *mgmt_frame, + uint32_t frame_bytes, + uint32_t *missing_rsn_bytes); + +#endif /* __PARSE_H__ */ diff --git a/drivers/staging/qcacld-3.0/core/mac/src/include/sir_common.h b/drivers/staging/qcacld-3.0/core/mac/src/include/sir_common.h new file mode 100644 index 0000000000000000000000000000000000000000..f6997725d52ef8913c63d6300a3b08561e7f449c --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/include/sir_common.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2011-2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * + * This file sir_common.h contains the common definitions used by all + * Firmware modules. + * + * Author: V. K. Kandarpa + * Date: 04/12/2002 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + */ + +#ifndef __SIRCOMMON_H +#define __SIRCOMMON_H + +#include "sir_api.h" +#include "sir_params.h" +#include "sys_wrapper.h" + +/* ********************************************* * +* * +* SIRIUS SYSTEM EXTERNAL GLOBALS * +* * +* ********************************************* */ + +/* All the following are resource definitions */ + +#endif /* __SIRCOMMON_H */ diff --git a/drivers/staging/qcacld-3.0/core/mac/src/include/sir_debug.h b/drivers/staging/qcacld-3.0/core/mac/src/include/sir_debug.h new file mode 100644 index 0000000000000000000000000000000000000000..28b5165cf763f41c0f2c043dd84af7de259927d1 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/include/sir_debug.h @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2011-2012, 2014-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * Author: Sandesh Goel + * Date: 02/25/02 + */ + +#ifndef __POL_DEBUG_H__ +#define __POL_DEBUG_H__ + +#define LOGOFF 0 +#define LOGP 1 +#define LOGE 2 +#define LOGW 3 +#define LOG1 4 +#define LOG2 5 +#define LOG3 6 +#define LOG4 7 + +#ifdef WLAN_MDM_CODE_REDUCTION_OPT +#ifdef PE_DEBUG_LOGE +#define PELOGE(p) { p } +#else +#define PELOGE(p) { } +#endif + +#ifdef PE_DEBUG_LOGW +#define PELOGW(p) { p } +#else +#define PELOGW(p) { } +#endif + +#define PELOG1(p) { } +#define PELOG2(p) { } +#define PELOG3(p) { } +#define PELOG4(p) { } + +#else /* WLAN_MDM_CODE_REDUCTION_OPT */ + +#ifdef PE_DEBUG_LOGE +#define PELOGE(p) { p } +#else +#define PELOGE(p) { } +#endif + +#ifdef PE_DEBUG_LOGW +#define PELOGW(p) { p } +#else +#define PELOGW(p) { } +#endif + +#ifdef PE_DEBUG_LOG1 +#define PELOG1(p) { p } +#else +#define PELOG1(p) { } +#endif + +#ifdef PE_DEBUG_LOG2 +#define PELOG2(p) { p } +#else +#define PELOG2(p) { } +#endif + +#ifdef PE_DEBUG_LOG3 +#define PELOG3(p) { p } +#else +#define PELOG3(p) { } +#endif + +#ifdef PE_DEBUG_LOG4 +#define PELOG4(p) { p } +#else +#define PELOG4(p) { } +#endif + +#endif /* WLAN_MDM_CODE_REDUCTION_OPT */ + +#define MAC_ADDR_ARRAY(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5] +#define MAC_ADDRESS_STR "%02x:%02x:%02x:%02x:%02x:%02x" + +#define pe_log(level, args...) QDF_TRACE(QDF_MODULE_ID_PE, level, ## args) +#define pe_logfl(level, format, args...) pe_log(level, FL(format), ## args) + +#define pe_alert(format, args...) \ + pe_logfl(QDF_TRACE_LEVEL_FATAL, format, ## args) +#define pe_err(format, args...) \ + pe_logfl(QDF_TRACE_LEVEL_ERROR, format, ## args) +#define pe_warn(format, args...) \ + pe_logfl(QDF_TRACE_LEVEL_WARN, format, ## args) +#define pe_info(format, args...) \ + pe_logfl(QDF_TRACE_LEVEL_INFO, format, ## args) +#define pe_debug(format, args...) \ + pe_logfl(QDF_TRACE_LEVEL_DEBUG, format, ## args) + +#define PE_ENTER() pe_logfl(QDF_TRACE_LEVEL_DEBUG, "enter") +#define PE_EXIT() pe_logfl(QDF_TRACE_LEVEL_DEBUG, "exit") + +#endif diff --git a/drivers/staging/qcacld-3.0/core/mac/src/include/sir_params.h b/drivers/staging/qcacld-3.0/core/mac/src/include/sir_params.h new file mode 100644 index 0000000000000000000000000000000000000000..b0e9c73237d167b5e6cd6ac3c027fb6e7ab26286 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/include/sir_params.h @@ -0,0 +1,800 @@ +/* + * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * This file sir_params.h contains the common parameter definitions, which + * are not dependent on threadX API. These can be used by all Firmware + * modules. + * + * Author: Sandesh Goel + * Date: 04/13/2002 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + */ + +#ifndef __SIRPARAMS_H +#define __SIRPARAMS_H + +#include "sir_types.h" + +/* defines for WPS config states */ +#define SAP_WPS_DISABLED 0 +#define SAP_WPS_ENABLED_UNCONFIGURED 1 +#define SAP_WPS_ENABLED_CONFIGURED 2 + + +/* Firmware wide constants */ + +#define SIR_MAX_PACKET_SIZE 512 +#define SIR_MAX_NUM_CHANNELS 64 +#define SIR_MAX_NUM_STA_IN_IBSS 16 +#define SIR_ESE_MAX_MEAS_IE_REQS 8 + +typedef enum { + PHY_SINGLE_CHANNEL_CENTERED = 0, /* 20MHz IF bandwidth centered on IF carrier */ + PHY_DOUBLE_CHANNEL_LOW_PRIMARY = 1, /* 40MHz IF bandwidth with lower 20MHz supporting the primary channel */ + PHY_DOUBLE_CHANNEL_HIGH_PRIMARY = 3, /* 40MHz IF bandwidth with higher 20MHz supporting the primary channel */ + PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_CENTERED = 4, /* 20/40MHZ offset LOW 40/80MHZ offset CENTERED */ + PHY_QUADRUPLE_CHANNEL_20MHZ_CENTERED_40MHZ_CENTERED = 5, /* 20/40MHZ offset CENTERED 40/80MHZ offset CENTERED */ + PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_CENTERED = 6, /* 20/40MHZ offset HIGH 40/80MHZ offset CENTERED */ + PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_LOW = 7, /* 20/40MHZ offset LOW 40/80MHZ offset LOW */ + PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_LOW = 8, /* 20/40MHZ offset HIGH 40/80MHZ offset LOW */ + PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_HIGH = 9, /* 20/40MHZ offset LOW 40/80MHZ offset HIGH */ + PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_HIGH = 10, /* 20/40MHZ offset-HIGH 40/80MHZ offset HIGH */ + PHY_CHANNEL_BONDING_STATE_MAX = 11 +} ePhyChanBondState; + +#define MAX_BONDED_CHANNELS 8 + +typedef enum { + MCC = 0, + P2P = 1, + DOT11AC = 2, + SLM_SESSIONIZATION = 3, + DOT11AC_OPMODE = 4, + SAP32STA = 5, + TDLS = 6, + P2P_GO_NOA_DECOUPLE_INIT_SCAN = 7, + WLANACTIVE_OFFLOAD = 8, +#ifdef FEATURE_WLAN_EXTSCAN + EXTENDED_SCAN = 9, +#endif +#ifdef FEATURE_WLAN_SCAN_PNO + PNO = 10, +#endif +#ifdef WLAN_FEATURE_NAN + NAN = 11, +#endif + RTT = 12, + WOW = 22, + WLAN_ROAM_SCAN_OFFLOAD = 23, + IBSS_HEARTBEAT_OFFLOAD = 26, + WLAN_PERIODIC_TX_PTRN = 28, +#ifdef FEATURE_WLAN_TDLS + ADVANCE_TDLS = 29, + TDLS_OFF_CHANNEL = 30, +#endif + /* MAX_FEATURE_SUPPORTED = 128 */ +} placeHolderInCapBitmap; + +typedef enum eSriLinkState { + eSIR_LINK_IDLE_STATE = 0, + eSIR_LINK_PREASSOC_STATE = 1, + eSIR_LINK_POSTASSOC_STATE = 2, + eSIR_LINK_AP_STATE = 3, + eSIR_LINK_IBSS_STATE = 4, + eSIR_LINK_DOWN_STATE = 5, +} tSirLinkState; + +/* / Message queue structure used across Sirius project. */ +/* / NOTE: this structure should be multiples of a word size (4bytes) */ +/* / as this is used in tx_queue where it expects to be multiples of 4 bytes. */ +typedef struct sSirMsgQ { + uint16_t type; + /* + * This field can be used as sequence number/dialog token for matching + * requests and responses. + */ + uint16_t reserved; + /** + * Based on the type either a bodyptr pointer into + * memory or bodyval as a 32 bit data is used. + * bodyptr: is always a freeable pointer, one should always + * make sure that bodyptr is always freeable. + * + * Messages should use either bodyptr or bodyval; not both !!!. + */ + void *bodyptr; + uint32_t bodyval; + + /* + * Some messages provide a callback function. The function signature + * must be agreed upon between the two entities exchanging the message + */ + void *callback; + +} tSirMsgQ, *tpSirMsgQ; + +/* / Mailbox Message Structure Define */ +typedef struct sSirMbMsg { + uint16_t type; + + /** + * This length includes 4 bytes of header, that is, + * 2 bytes type + 2 bytes msgLen + n*4 bytes of data. + * This field is byte length. + */ + uint16_t msgLen; + + /** + * This is the first data word in the mailbox message. + * It is followed by n words of data. + * NOTE: data[1] is not a place holder to store data + * instead to dereference the message body. + */ + uint32_t data[1]; +} tSirMbMsg, *tpSirMbMsg; + +/* / Mailbox Message Structure for P2P */ +typedef struct sSirMbMsgP2p { + uint16_t type; + + /** + * This length includes 4 bytes of header, that is, + * 2 bytes type + 2 bytes msgLen + n*4 bytes of data. + * This field is byte length. + */ + uint16_t msgLen; + + uint8_t sessionId; + uint8_t noack; + uint16_t wait; + uint16_t channel_freq; + uint32_t scan_id; + + /** + * This is the first data word in the mailbox message. + * It is followed by n words of data. + * NOTE: data[1] is not a place holder to store data + * instead to dereference the message body. + */ + uint32_t data[1]; +} tSirMbMsgP2p, *tpSirMbMsgP2p; + +/* ******************************************* * +* * +* SIRIUS MESSAGE TYPES * +* * +* ******************************************* */ + +/* + * The following message types have bounds defined for each module for + * inter thread/module communications. + * Each module will get 256 message types in total. + * Note that message type definitions for mailbox messages for + * communication with Host are in wni_api.h file. + * + * Any addition/deletion to this message list should also be + * reflected in the halUtil_getMsgString() routine. + */ + +/* HAL message types */ +#define SIR_HAL_MSG_TYPES_BEGIN (SIR_HAL_MODULE_ID << 8) +#define SIR_HAL_ITC_MSG_TYPES_BEGIN (SIR_HAL_MSG_TYPES_BEGIN+0x20) +#define SIR_HAL_RADAR_DETECTED_IND SIR_HAL_ITC_MSG_TYPES_BEGIN + +/* + * New Taurus related messages + */ +#define SIR_HAL_ADD_STA_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 1) +#define SIR_HAL_ADD_STA_RSP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 2) +#define SIR_HAL_DELETE_STA_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 3) +#define SIR_HAL_DELETE_STA_RSP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 4) +#define SIR_HAL_ADD_BSS_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 5) +#define SIR_HAL_ADD_BSS_RSP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 6) +#define SIR_HAL_DELETE_BSS_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 7) +#define SIR_HAL_DELETE_BSS_RSP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 8) +#define SIR_HAL_INIT_SCAN_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 9) +#define SIR_HAL_INIT_SCAN_RSP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 10) +#define SIR_HAL_START_SCAN_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 11) +#define SIR_HAL_START_SCAN_RSP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 12) +#define SIR_HAL_END_SCAN_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 13) +#define SIR_HAL_END_SCAN_RSP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 14) +#define SIR_HAL_FINISH_SCAN_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 15) +#define SIR_HAL_FINISH_SCAN_RSP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 16) +#define SIR_HAL_SEND_BEACON_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 17) + +#define SIR_HAL_SET_BSSKEY_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 18) +#define SIR_HAL_SET_BSSKEY_RSP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 19) +#define SIR_HAL_SET_STAKEY_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 20) +#define SIR_HAL_SET_STAKEY_RSP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 21) +#define SIR_HAL_UPDATE_EDCA_PROFILE_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 22) + +#define SIR_HAL_UPDATE_BEACON_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 23) +#define SIR_HAL_UPDATE_CF_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 24) +#define SIR_HAL_CHNL_SWITCH_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 25) +#define SIR_HAL_ADD_TS_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 26) +#define SIR_HAL_DEL_TS_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 27) + +#define SIR_HAL_MISSED_BEACON_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 34) + +#define SIR_HAL_SWITCH_CHANNEL_RSP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 35) +#define SIR_HAL_PWR_SAVE_CFG (SIR_HAL_ITC_MSG_TYPES_BEGIN + 36) + +#define SIR_HAL_REGISTER_PE_CALLBACK (SIR_HAL_ITC_MSG_TYPES_BEGIN + 37) + +#define SIR_HAL_IBSS_STA_ADD (SIR_HAL_ITC_MSG_TYPES_BEGIN + 43) +#define SIR_HAL_TIMER_ADJUST_ADAPTIVE_THRESHOLD_IND \ + (SIR_HAL_ITC_MSG_TYPES_BEGIN + 44) +#define SIR_HAL_SET_LINK_STATE (SIR_HAL_ITC_MSG_TYPES_BEGIN + 45) +#define SIR_HAL_DELETE_BSS_HO_FAIL_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 46) +#define SIR_HAL_DELETE_BSS_HO_FAIL_RSP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 47) + +/* + * (SIR_HAL_ITC_MSG_TYPES_BEGIN + 48) to + * (SIR_HAL_ITC_MSG_TYPES_BEGIN + 57) are unused + */ + +#define SIR_HAL_SET_STA_BCASTKEY_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 58) +#define SIR_HAL_SET_STA_BCASTKEY_RSP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 59) +#define SIR_HAL_ADD_TS_RSP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 60) +#define SIR_HAL_DPU_MIC_ERROR (SIR_HAL_ITC_MSG_TYPES_BEGIN + 61) +#define SIR_HAL_TIMER_CHIP_MONITOR_TIMEOUT (SIR_HAL_ITC_MSG_TYPES_BEGIN + 63) +#define SIR_HAL_TIMER_TRAFFIC_ACTIVITY_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 64) +#define SIR_HAL_TIMER_ADC_RSSI_STATS (SIR_HAL_ITC_MSG_TYPES_BEGIN + 65) +/* (SIR_HAL_ITC_MSG_TYPES_BEGIN + 66) is unused */ +#define SIR_HAL_SET_MIMOPS_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 67) +#define SIR_HAL_SET_MIMOPS_RSP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 68) +#define SIR_HAL_SYS_READY_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 69) +#define SIR_HAL_SET_TX_POWER_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 70) +#define SIR_HAL_SET_TX_POWER_RSP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 71) +#define SIR_HAL_GET_TX_POWER_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 72) +#define SIR_HAL_GET_TX_POWER_RSP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 73) +#define SIR_HAL_GET_NOISE_RSP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 74) + +/* Messages to support transmit_halt and transmit_resume */ +#define SIR_HAL_TRANSMISSION_CONTROL_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 75) + +#define SIR_HAL_LOW_RSSI_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 80) +#define SIR_HAL_BEACON_FILTER_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 81) +/* / PE <-> HAL WOWL messages */ +#define SIR_HAL_WOW_ADD_PTRN (SIR_HAL_ITC_MSG_TYPES_BEGIN + 82) +#define SIR_HAL_WOW_DEL_PTRN (SIR_HAL_ITC_MSG_TYPES_BEGIN + 83) +#define SIR_HAL_WOWL_ENTER_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 84) +#define SIR_HAL_WOWL_ENTER_RSP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 85) +#define SIR_HAL_WOWL_EXIT_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 86) +#define SIR_HAL_WOWL_EXIT_RSP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 87) +/* / PE <-> HAL statistics messages */ +#define SIR_HAL_GET_STATISTICS_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 88) +#define SIR_HAL_GET_STATISTICS_RSP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 89) +#define SIR_HAL_SET_KEY_DONE (SIR_HAL_ITC_MSG_TYPES_BEGIN + 90) + +/* / PE <-> HAL BTC messages */ +#define SIR_HAL_BTC_SET_CFG (SIR_HAL_ITC_MSG_TYPES_BEGIN + 91) +/* (SIR_HAL_ITC_MSG_TYPES_BEGIN + 92) is unused */ +#define SIR_HAL_HANDLE_FW_MBOX_RSP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 93) +#define SIR_HAL_SEND_PROBE_RSP_TMPL (SIR_HAL_ITC_MSG_TYPES_BEGIN + 94) + +/* PE <-> HAL addr2 mismatch message */ +#define SIR_LIM_ADDR2_MISS_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 95) +#ifdef FEATURE_OEM_DATA_SUPPORT +/* PE <-> HAL OEM_DATA RELATED MESSAGES */ +#define SIR_HAL_START_OEM_DATA_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 96) +#define SIR_HAL_START_OEM_DATA_RSP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 97) +#endif + +#define SIR_HAL_SET_MAX_TX_POWER_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 98) +#define SIR_HAL_SET_MAX_TX_POWER_RSP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 99) + +/* / PE <-> HAL Host Offload message */ +#define SIR_HAL_SET_HOST_OFFLOAD (SIR_HAL_ITC_MSG_TYPES_BEGIN + 100) + +#define SIR_HAL_ADD_STA_SELF_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 101) +#define SIR_HAL_ADD_STA_SELF_RSP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 102) +#define SIR_HAL_DEL_STA_SELF_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 103) +#define SIR_HAL_DEL_STA_SELF_RSP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 104) + +#define SIR_HAL_CFG_RXP_FILTER_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 106) + +#define SIR_HAL_AGGR_ADD_TS_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 107) +#define SIR_HAL_AGGR_ADD_TS_RSP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 108) +#define SIR_HAL_AGGR_QOS_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 109) +#define SIR_HAL_AGGR_QOS_RSP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 110) + +/* P2P <-> HAL P2P msg */ +#define SIR_HAL_SET_P2P_GO_NOA_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 111) +#define SIR_HAL_P2P_NOA_ATTR_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 112) +#define SIR_HAL_P2P_NOA_START_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 113) + +#define SIR_HAL_SET_LINK_STATE_RSP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 114) + +#define SIR_HAL_WLAN_SUSPEND_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 115) +#define SIR_HAL_WLAN_RESUME_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 116) + +/* / PE <-> HAL Keep Alive message */ +#define SIR_HAL_SET_KEEP_ALIVE (SIR_HAL_ITC_MSG_TYPES_BEGIN + 117) + +#ifdef WLAN_NS_OFFLOAD +#define SIR_HAL_SET_NS_OFFLOAD (SIR_HAL_ITC_MSG_TYPES_BEGIN + 118) +#endif /* WLAN_NS_OFFLOAD */ + +#ifdef FEATURE_WLAN_SCAN_PNO +#define SIR_HAL_SET_PNO_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 119) +#endif /* FEATURE_WLAN_SCAN_PNO */ + +#define SIR_HAL_SOC_ANTENNA_MODE_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 120) +#define SIR_HAL_SOC_ANTENNA_MODE_RESP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 121) + +/* (SIR_HAL_ITC_MSG_TYPES_BEGIN + 122) is unused */ + +#ifdef WLAN_FEATURE_PACKET_FILTERING +#define SIR_HAL_8023_MULTICAST_LIST_REQ \ + (SIR_HAL_ITC_MSG_TYPES_BEGIN + 123) +#define SIR_HAL_RECEIVE_FILTER_SET_FILTER_REQ \ + (SIR_HAL_ITC_MSG_TYPES_BEGIN + 124) +#define SIR_HAL_PACKET_COALESCING_FILTER_MATCH_COUNT_REQ \ + (SIR_HAL_ITC_MSG_TYPES_BEGIN + 125) +#define SIR_HAL_PACKET_COALESCING_FILTER_MATCH_COUNT_RSP \ + (SIR_HAL_ITC_MSG_TYPES_BEGIN + 126) +#define SIR_HAL_RECEIVE_FILTER_CLEAR_FILTER_REQ \ + (SIR_HAL_ITC_MSG_TYPES_BEGIN + 127) +#endif /* WLAN_FEATURE_PACKET_FILTERING */ + +/* (SIR_HAL_ITC_MSG_TYPES_BEGIN + 128) is unused */ + +#ifdef WLAN_FEATURE_GTK_OFFLOAD +#define SIR_HAL_GTK_OFFLOAD_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 129) +#define SIR_HAL_GTK_OFFLOAD_GETINFO_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 130) +#define SIR_HAL_GTK_OFFLOAD_GETINFO_RSP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 131) +#endif /* WLAN_FEATURE_GTK_OFFLOAD */ + +#ifdef FEATURE_WLAN_ESE +#define SIR_HAL_TSM_STATS_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 132) +#define SIR_HAL_TSM_STATS_RSP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 133) +#endif + +#define SIR_HAL_SET_TM_LEVEL_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 134) + +#define SIR_HAL_UPDATE_OP_MODE (SIR_HAL_ITC_MSG_TYPES_BEGIN + 135) + +#ifdef FEATURE_WLAN_TDLS +/* / PE <-> HAL TDLS messages */ +#define SIR_HAL_TDLS_LINK_ESTABLISH (SIR_HAL_ITC_MSG_TYPES_BEGIN + 136) +#define SIR_HAL_TDLS_LINK_TEARDOWN (SIR_HAL_ITC_MSG_TYPES_BEGIN + 137) +#endif +#define SIR_HAL_ROAM_SCAN_OFFLOAD_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 138) + +#define SIR_HAL_TRAFFIC_STATS_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 141) + +#ifdef WLAN_FEATURE_11W +#define SIR_HAL_EXCLUDE_UNENCRYPTED_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 142) +#endif +#ifdef FEATURE_WLAN_TDLS +/* / PE <-> HAL TDLS messages */ +#define SIR_HAL_TDLS_LINK_ESTABLISH_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 143) +#define SIR_HAL_TDLS_LINK_ESTABLISH_REQ_RSP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 144) +#define SIR_HAL_TDLS_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 145) +#endif + +#define SIR_HAL_STOP_SCAN_OFFLOAD_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 146) +#define SIR_HAL_RX_SCAN_EVENT (SIR_HAL_ITC_MSG_TYPES_BEGIN + 147) +#define SIR_HAL_DHCP_START_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 148) +#define SIR_HAL_DHCP_STOP_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 149) +#define SIR_HAL_IBSS_PEER_INACTIVITY_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 150) + +#define SIR_HAL_LPHB_CONF_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 151) + +#define SIR_HAL_ADD_PERIODIC_TX_PTRN_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 152) +#define SIR_HAL_DEL_PERIODIC_TX_PTRN_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 153) + +/* Messages between 156 to 157 are not used */ +#define SIR_HAL_PDEV_DUAL_MAC_CFG_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 154) +#define SIR_HAL_PDEV_MAC_CFG_RESP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 155) + +/* For IBSS peer info related messages */ +#define SIR_HAL_IBSS_PEER_INFO_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 158) + +#define SIR_HAL_RATE_UPDATE_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 159) + +#define SIR_HAL_FLUSH_LOG_TO_FW (SIR_HAL_ITC_MSG_TYPES_BEGIN + 160) + +#define SIR_HAL_PDEV_SET_PCL_TO_FW (SIR_HAL_ITC_MSG_TYPES_BEGIN + 161) + +/* 162 unused */ + +#define SIR_HAL_CLI_SET_CMD (SIR_HAL_ITC_MSG_TYPES_BEGIN + 163) +#ifndef REMOVE_PKT_LOG +#define SIR_HAL_PKTLOG_ENABLE_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 164) +#endif +#ifdef FEATURE_WLAN_SCAN_PNO +#define SIR_HAL_SME_SCAN_CACHE_UPDATED (SIR_HAL_ITC_MSG_TYPES_BEGIN + 165) +#endif +#define SIR_HAL_START_SCAN_OFFLOAD_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 166) +#define SIR_HAL_UPDATE_CHAN_LIST_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 167) +#define SIR_CSA_OFFLOAD_EVENT (SIR_HAL_ITC_MSG_TYPES_BEGIN + 169) + +#define SIR_HAL_SET_MAX_TX_POWER_PER_BAND_REQ \ + (SIR_HAL_ITC_MSG_TYPES_BEGIN + 170) + +#define SIR_HAL_TX_FAIL_MONITOR_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 171) + +#define SIR_HAL_UPDATE_MEMBERSHIP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 172) +#define SIR_HAL_UPDATE_USERPOS (SIR_HAL_ITC_MSG_TYPES_BEGIN + 173) + +#ifdef FEATURE_WLAN_TDLS +#define SIR_HAL_UPDATE_FW_TDLS_STATE (SIR_HAL_ITC_MSG_TYPES_BEGIN + 174) +#define SIR_HAL_UPDATE_TDLS_PEER_STATE (SIR_HAL_ITC_MSG_TYPES_BEGIN + 175) +#define SIR_HAL_TDLS_SHOULD_DISCOVER (SIR_HAL_ITC_MSG_TYPES_BEGIN + 176) +#define SIR_HAL_TDLS_SHOULD_TEARDOWN (SIR_HAL_ITC_MSG_TYPES_BEGIN + 177) +#define SIR_HAL_TDLS_PEER_DISCONNECTED (SIR_HAL_ITC_MSG_TYPES_BEGIN + 178) +#endif + +/* Handling of beacon tx indication from FW */ +#define SIR_HAL_BEACON_TX_SUCCESS_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 179) +#define SIR_HAL_DFS_RADAR_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 180) + +#define SIR_HAL_IBSS_CESIUM_ENABLE_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 181) + +#define SIR_HAL_RMC_ENABLE_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 182) +#define SIR_HAL_RMC_DISABLE_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 183) +#define SIR_HAL_RMC_ACTION_PERIOD_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 184) +#define SIR_HAL_INIT_THERMAL_INFO_CMD (SIR_HAL_ITC_MSG_TYPES_BEGIN + 185) +#define SIR_HAL_SET_THERMAL_LEVEL (SIR_HAL_ITC_MSG_TYPES_BEGIN + 186) + +#ifdef FEATURE_WLAN_ESE +#define SIR_HAL_SET_PLM_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 187) +#endif + +#define SIR_HAL_SET_TX_POWER_LIMIT (SIR_HAL_ITC_MSG_TYPES_BEGIN + 188) +#define SIR_HAL_SET_SAP_INTRABSS_DIS (SIR_HAL_ITC_MSG_TYPES_BEGIN + 189) + +#define SIR_HAL_MODEM_POWER_STATE_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 190) + +#define SIR_HAL_DISASSOC_TX_COMP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 191) +#define SIR_HAL_DEAUTH_TX_COMP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 192) + +#define SIR_HAL_UPDATE_RX_NSS (SIR_HAL_ITC_MSG_TYPES_BEGIN + 193) + +#ifdef WLAN_FEATURE_STATS_EXT +#define SIR_HAL_STATS_EXT_REQUEST (SIR_HAL_ITC_MSG_TYPES_BEGIN + 194) +#define SIR_HAL_STATS_EXT_EVENT (SIR_HAL_ITC_MSG_TYPES_BEGIN + 195) +#endif /* WLAN_FEATURE_STATS_EXT */ + +#define SIR_HAL_HIDE_SSID_VDEV_RESTART (SIR_HAL_ITC_MSG_TYPES_BEGIN + 196) + +#define SIR_HAL_GET_LINK_SPEED (SIR_HAL_ITC_MSG_TYPES_BEGIN + 197) + +#ifdef FEATURE_WLAN_EXTSCAN +#define SIR_HAL_EXTSCAN_GET_CAPABILITIES_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 198) +#define SIR_HAL_EXTSCAN_START_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 199) +#define SIR_HAL_EXTSCAN_STOP_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 200) +#define SIR_HAL_EXTSCAN_SET_BSS_HOTLIST_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 201) +#define SIR_HAL_EXTSCAN_RESET_BSS_HOTLIST_REQ \ + (SIR_HAL_ITC_MSG_TYPES_BEGIN + 202) +#define SIR_HAL_EXTSCAN_SET_SIGNF_CHANGE_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 203) +#define SIR_HAL_EXTSCAN_RESET_SIGNF_CHANGE_REQ \ + (SIR_HAL_ITC_MSG_TYPES_BEGIN + 204) +#define SIR_HAL_EXTSCAN_GET_CACHED_RESULTS_REQ \ + (SIR_HAL_ITC_MSG_TYPES_BEGIN + 205) +#endif /* FEATURE_WLAN_EXTSCAN */ + +#ifdef FEATURE_WLAN_CH_AVOID +#define SIR_HAL_CH_AVOID_UPDATE_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 206) +#endif + +#ifdef WLAN_FEATURE_LINK_LAYER_STATS +#define SIR_HAL_LL_STATS_CLEAR_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 207) +#define SIR_HAL_LL_STATS_SET_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 208) +#define SIR_HAL_LL_STATS_GET_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 209) +#define SIR_HAL_LL_STATS_RESULTS_RSP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 210) +#endif /* WLAN_FEATURE_LINK_LAYER_STATS */ + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +#define SIR_HAL_ROAM_OFFLOAD_SYNCH_CNF (SIR_HAL_ITC_MSG_TYPES_BEGIN + 211) +#endif +#ifdef WLAN_FEATURE_NAN +#define SIR_HAL_NAN_REQUEST (SIR_HAL_ITC_MSG_TYPES_BEGIN + 212) +#endif /* WLAN_FEATURE_NAN */ + +#ifdef FEATURE_WLAN_AUTO_SHUTDOWN +#define SIR_HAL_SET_AUTO_SHUTDOWN_TIMER_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 213) +#endif + +#define SIR_HAL_SET_BASE_MACADDR_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 214) + +#define SIR_HAL_UNIT_TEST_CMD (SIR_HAL_ITC_MSG_TYPES_BEGIN + 215) + +#define SIR_HAL_LINK_STATUS_GET_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 216) + +#ifdef WLAN_FEATURE_EXTWOW_SUPPORT +#define SIR_HAL_CONFIG_EXT_WOW (SIR_HAL_ITC_MSG_TYPES_BEGIN + 217) +#define SIR_HAL_CONFIG_APP_TYPE1_PARAMS (SIR_HAL_ITC_MSG_TYPES_BEGIN + 218) +#define SIR_HAL_CONFIG_APP_TYPE2_PARAMS (SIR_HAL_ITC_MSG_TYPES_BEGIN + 219) +#endif + +#define SIR_HAL_GET_TEMPERATURE_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 220) +#define SIR_HAL_SET_SCAN_MAC_OUI_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 221) +#ifdef DHCP_SERVER_OFFLOAD +#define SIR_HAL_SET_DHCP_SERVER_OFFLOAD (SIR_HAL_ITC_MSG_TYPES_BEGIN + 222) +#endif /* DHCP_SERVER_OFFLOAD */ +#define SIR_HAL_LED_FLASHING_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 223) +#define SIR_HAL_PROCESS_FW_EVENT (SIR_HAL_ITC_MSG_TYPES_BEGIN + 224) + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +#define SIR_HAL_ROAM_OFFLOAD_SYNCH_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 225) +#define SIR_HAL_ROAM_OFFLOAD_SYNCH_FAIL (SIR_HAL_ITC_MSG_TYPES_BEGIN + 226) +#define SIR_HAL_ROAM_INVOKE (SIR_HAL_ITC_MSG_TYPES_BEGIN + 227) +#endif + +#ifdef FEATURE_WLAN_TDLS +#define SIR_HAL_TDLS_SET_OFFCHAN_MODE (SIR_HAL_ITC_MSG_TYPES_BEGIN + 228) +#endif + +#define SIR_HAL_SET_MAS (SIR_HAL_ITC_MSG_TYPES_BEGIN + 229) +#define SIR_HAL_SET_MIRACAST (SIR_HAL_ITC_MSG_TYPES_BEGIN + 230) +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE +#define SIR_HAL_UPDATE_Q2Q_IE_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 231) +#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ +#define SIR_HAL_CONFIG_STATS_FACTOR (SIR_HAL_ITC_MSG_TYPES_BEGIN + 232) +#define SIR_HAL_CONFIG_GUARD_TIME (SIR_HAL_ITC_MSG_TYPES_BEGIN + 233) +#define SIR_HAL_IPA_OFFLOAD_ENABLE_DISABLE (SIR_HAL_ITC_MSG_TYPES_BEGIN + 234) + +#define SIR_HAL_ENTER_PS_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 235) +#define SIR_HAL_EXIT_PS_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 236) +#define SIR_HAL_ENABLE_UAPSD_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 237) +#define SIR_HAL_DISABLE_UAPSD_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 238) +#define SIR_HAL_GATEWAY_PARAM_UPDATE_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 239) + +#define SIR_HAL_RUNTIME_PM_SUSPEND_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 308) +#define SIR_HAL_RUNTIME_PM_RESUME_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 309) + +#define SIR_HAL_SET_EPNO_LIST_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 313) +#define SIR_HAL_SET_PASSPOINT_LIST_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 316) +#define SIR_HAL_RESET_PASSPOINT_LIST_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 317) +/* 318 unused */ + +#define SIR_HAL_OCB_SET_CONFIG_CMD (SIR_HAL_ITC_MSG_TYPES_BEGIN + 319) +#define SIR_HAL_OCB_SET_UTC_TIME_CMD (SIR_HAL_ITC_MSG_TYPES_BEGIN + 320) +#define SIR_HAL_OCB_START_TIMING_ADVERT_CMD (SIR_HAL_ITC_MSG_TYPES_BEGIN + 321) +#define SIR_HAL_OCB_STOP_TIMING_ADVERT_CMD (SIR_HAL_ITC_MSG_TYPES_BEGIN + 322) +#define SIR_HAL_OCB_GET_TSF_TIMER_CMD (SIR_HAL_ITC_MSG_TYPES_BEGIN + 323) +#define SIR_HAL_DCC_GET_STATS_CMD (SIR_HAL_ITC_MSG_TYPES_BEGIN + 324) +#define SIR_HAL_DCC_CLEAR_STATS_CMD (SIR_HAL_ITC_MSG_TYPES_BEGIN + 325) +#define SIR_HAL_DCC_UPDATE_NDL_CMD (SIR_HAL_ITC_MSG_TYPES_BEGIN + 326) + +#define SIR_HAL_FW_MEM_DUMP_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 327) +#define SIR_HAL_START_STOP_LOGGING (SIR_HAL_ITC_MSG_TYPES_BEGIN + 328) +#define SIR_HAL_PDEV_SET_HW_MODE (SIR_HAL_ITC_MSG_TYPES_BEGIN + 329) +#define SIR_HAL_PDEV_SET_HW_MODE_RESP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 330) +#define SIR_HAL_PDEV_HW_MODE_TRANS_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 331) + +#define SIR_HAL_BAD_PEER_TX_CTL_INI_CMD (SIR_HAL_ITC_MSG_TYPES_BEGIN + 332) +#define SIR_HAL_SET_RSSI_MONITOR_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 333) +#define SIR_HAL_SET_IE_INFO (SIR_HAL_ITC_MSG_TYPES_BEGIN + 334) + +#define SIR_HAL_LRO_CONFIG_CMD (SIR_HAL_ITC_MSG_TYPES_BEGIN + 335) + +#define SIR_HAL_SET_EGAP_CONF_PARAMS (SIR_HAL_ITC_MSG_TYPES_BEGIN + 336) +#define SIR_HAL_HT40_OBSS_SCAN_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 337) + +#define SIR_HAL_TSF_GPIO_PIN_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 338) + +#define SIR_HAL_ADD_BCN_FILTER_CMDID (SIR_HAL_ITC_MSG_TYPES_BEGIN + 339) +#define SIR_HAL_REMOVE_BCN_FILTER_CMDID (SIR_HAL_ITC_MSG_TYPES_BEGIN + 340) + + +#define SIR_HAL_BPF_GET_CAPABILITIES_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 341) +#define SIR_HAL_BPF_SET_INSTRUCTIONS_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 342) + +#define SIR_HAL_SET_WISA_PARAMS (SIR_HAL_ITC_MSG_TYPES_BEGIN + 343) +#define SIR_HAL_SET_ADAPT_DWELLTIME_PARAMS (SIR_HAL_ITC_MSG_TYPES_BEGIN + 344) +#define SIR_HAL_SET_PDEV_IE_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 345) + +#ifdef FEATURE_WLAN_TDLS +#define SIR_HAL_TDLS_CONNECTION_TRACKER_NOTIFICATION (SIR_HAL_ITC_MSG_TYPES_BEGIN + 346) +#endif + +#define SIR_HAL_NDP_GET_CAP_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 347) +#define SIR_HAL_NDP_INITIATOR_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 348) +#define SIR_HAL_NDP_RESPONDER_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 349) +#define SIR_HAL_NDP_END_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 350) +#define SIR_HAL_NDI_CAP_RSP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 351) +#define SIR_HAL_NDP_INITIATOR_RSP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 352) +#define SIR_HAL_NDP_RESPONDER_RSP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 353) +#define SIR_HAL_NDP_END_RSP (SIR_HAL_ITC_MSG_TYPES_BEGIN + 354) +#define SIR_HAL_NDP_INDICATION (SIR_HAL_ITC_MSG_TYPES_BEGIN + 355) +#define SIR_HAL_NDP_CONFIRM (SIR_HAL_ITC_MSG_TYPES_BEGIN + 356) +#define SIR_HAL_NDP_END_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 357) +#define SIR_HAL_UPDATE_WEP_DEFAULT_KEY (SIR_HAL_ITC_MSG_TYPES_BEGIN + 358) + +#define SIR_HAL_SEND_FREQ_RANGE_CONTROL_IND (SIR_HAL_ITC_MSG_TYPES_BEGIN + 360) +#define SIR_HAL_POWER_DBG_CMD (SIR_HAL_ITC_MSG_TYPES_BEGIN + 362) +#define SIR_HAL_SET_DTIM_PERIOD (SIR_HAL_ITC_MSG_TYPES_BEGIN + 363) +#define SIR_HAL_ENCRYPT_DECRYPT_MSG (SIR_HAL_ITC_MSG_TYPES_BEGIN + 364) +#define SIR_HAL_SHORT_RETRY_LIMIT_CNT (SIR_HAL_ITC_MSG_TYPES_BEGIN + 365) +#define SIR_HAL_LONG_RETRY_LIMIT_CNT (SIR_HAL_ITC_MSG_TYPES_BEGIN + 366) +#define SIR_HAL_UPDATE_TX_FAIL_CNT_TH (SIR_HAL_ITC_MSG_TYPES_BEGIN + 367) +#define SIR_HAL_POWER_DEBUG_STATS_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 368) + +#define SIR_HAL_SET_WOW_PULSE_CMD (SIR_HAL_ITC_MSG_TYPES_BEGIN + 369) + +#define SIR_HAL_SET_UDP_RESP_OFFLOAD (SIR_HAL_ITC_MSG_TYPES_BEGIN + 370) + +#define SIR_HAL_SET_PER_ROAM_CONFIG_CMD (SIR_HAL_ITC_MSG_TYPES_BEGIN + 371) + +#define SIR_HAL_GET_RCPI_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 372) + +#define SIR_HAL_CONF_HW_FILTER (SIR_HAL_ITC_MSG_TYPES_BEGIN + 373) +/* (SIR_HAL_ITC_MSG_TYPES_BEGIN + 374) is unused */ +/* ARP Debug stats */ +#define SIR_HAL_SET_ARP_STATS_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 375) +#define SIR_HAL_GET_ARP_STATS_REQ (SIR_HAL_ITC_MSG_TYPES_BEGIN + 376) + +#define SIR_HAL_MSG_TYPES_END (SIR_HAL_MSG_TYPES_BEGIN + 0x1FF) + +/* CFG message types */ +#define SIR_CFG_MSG_TYPES_BEGIN (SIR_CFG_MODULE_ID << 8) +#define SIR_CFG_ITC_MSG_TYPES_BEGIN (SIR_CFG_MSG_TYPES_BEGIN+0xB0) +#define SIR_CFG_PARAM_UPDATE_IND (SIR_CFG_ITC_MSG_TYPES_BEGIN) +#define SIR_CFG_DOWNLOAD_COMPLETE_IND (SIR_CFG_ITC_MSG_TYPES_BEGIN + 1) +#define SIR_CFG_MSG_TYPES_END (SIR_CFG_MSG_TYPES_BEGIN+0xFF) + +/* LIM message types */ +#define SIR_LIM_MSG_TYPES_BEGIN (SIR_LIM_MODULE_ID << 8) +#define SIR_LIM_ITC_MSG_TYPES_BEGIN (SIR_LIM_MSG_TYPES_BEGIN+0xB0) + +/* Messages to/from HAL */ +/* Removed as part of moving HAL down to FW */ + +/* Message from ISR upon TFP retry interrupt */ +#define SIR_LIM_RETRY_INTERRUPT_MSG (SIR_LIM_ITC_MSG_TYPES_BEGIN + 3) +/* Message from BB Transport */ +#define SIR_BB_XPORT_MGMT_MSG (SIR_LIM_ITC_MSG_TYPES_BEGIN + 4) +/* UNUSED SIR_LIM_ITC_MSG_TYPES_BEGIN + 6 */ +/* Message from ISR upon SP's Invalid session key interrupt */ +#define SIR_LIM_INV_KEY_INTERRUPT_MSG (SIR_LIM_ITC_MSG_TYPES_BEGIN + 7) +/* Message from ISR upon SP's Invalid key ID interrupt */ +#define SIR_LIM_KEY_ID_INTERRUPT_MSG (SIR_LIM_ITC_MSG_TYPES_BEGIN + 8) +/* Message from ISR upon SP's Replay threshold reached interrupt */ +#define SIR_LIM_REPLAY_THRES_INTERRUPT_MSG (SIR_LIM_ITC_MSG_TYPES_BEGIN + 9) +/* Message from HDD after the TD dummy packet is cleaned up */ +#define SIR_LIM_TD_DUMMY_CALLBACK_MSG (SIR_LIM_ITC_MSG_TYPES_BEGIN + 0xA) +/* Message from SCH when the STA is ready to be deleted */ +#define SIR_LIM_SCH_CLEAN_MSG (SIR_LIM_ITC_MSG_TYPES_BEGIN + 0xB) +/* Message from ISR upon Radar Detection */ +#define SIR_LIM_RADAR_DETECT_IND (SIR_LIM_ITC_MSG_TYPES_BEGIN + 0xC) +/* Message id 0xD available */ + +/* Message from Hal to send out a DEL-TS indication */ +#define SIR_LIM_DEL_TS_IND (SIR_LIM_ITC_MSG_TYPES_BEGIN + 0xE) +/* Indication from HAL to delete Station context */ +#define SIR_LIM_DELETE_STA_CONTEXT_IND (SIR_LIM_ITC_MSG_TYPES_BEGIN + 0x11) +/* Indication from HAL to delete BA */ +#define SIR_LIM_UPDATE_BEACON (SIR_LIM_ITC_MSG_TYPES_BEGIN + 0x13) + +/* LIM Timeout messages */ +#define SIR_LIM_TIMEOUT_MSG_START ((SIR_LIM_MODULE_ID << 8) + 0xD0) +#define SIR_LIM_JOIN_FAIL_TIMEOUT (SIR_LIM_TIMEOUT_MSG_START + 2) +#define SIR_LIM_AUTH_FAIL_TIMEOUT (SIR_LIM_TIMEOUT_MSG_START + 3) +#define SIR_LIM_AUTH_RSP_TIMEOUT (SIR_LIM_TIMEOUT_MSG_START + 4) +#define SIR_LIM_ASSOC_FAIL_TIMEOUT (SIR_LIM_TIMEOUT_MSG_START + 5) +#define SIR_LIM_REASSOC_FAIL_TIMEOUT (SIR_LIM_TIMEOUT_MSG_START + 6) +#define SIR_LIM_HEART_BEAT_TIMEOUT (SIR_LIM_TIMEOUT_MSG_START + 7) +/* currently unused SIR_LIM_TIMEOUT_MSG_START + 0x8 */ +/* Link Monitoring Messages */ +#define SIR_LIM_PROBE_HB_FAILURE_TIMEOUT (SIR_LIM_TIMEOUT_MSG_START + 0xB) +#define SIR_LIM_ADDTS_RSP_TIMEOUT (SIR_LIM_TIMEOUT_MSG_START + 0xC) +#define SIR_LIM_LINK_TEST_DURATION_TIMEOUT (SIR_LIM_TIMEOUT_MSG_START + 0x13) +#define SIR_LIM_CNF_WAIT_TIMEOUT (SIR_LIM_TIMEOUT_MSG_START + 0x17) +/* currently unused (SIR_LIM_TIMEOUT_MSG_START + 0x18) */ +#define SIR_LIM_UPDATE_OLBC_CACHEL_TIMEOUT (SIR_LIM_TIMEOUT_MSG_START + 0x19) +#define SIR_LIM_CHANNEL_SWITCH_TIMEOUT (SIR_LIM_TIMEOUT_MSG_START + 0x1A) +#define SIR_LIM_QUIET_TIMEOUT (SIR_LIM_TIMEOUT_MSG_START + 0x1B) +#define SIR_LIM_QUIET_BSS_TIMEOUT (SIR_LIM_TIMEOUT_MSG_START + 0x1C) + +#define SIR_LIM_WPS_OVERLAP_TIMEOUT (SIR_LIM_TIMEOUT_MSG_START + 0x1D) +#define SIR_LIM_FT_PREAUTH_RSP_TIMEOUT (SIR_LIM_TIMEOUT_MSG_START + 0x1E) +#define SIR_LIM_REMAIN_CHN_TIMEOUT (SIR_LIM_TIMEOUT_MSG_START + 0x1F) +#define SIR_LIM_INSERT_SINGLESHOT_NOA_TIMEOUT (SIR_LIM_TIMEOUT_MSG_START + 0x20) + +#define SIR_LIM_BEACON_GEN_IND (SIR_LIM_TIMEOUT_MSG_START + 0x23) +#define SIR_LIM_PERIODIC_PROBE_REQ_TIMEOUT (SIR_LIM_TIMEOUT_MSG_START + 0x24) + +/* currently unused (SIR_LIM_TIMEOUT_MSG_START + 0x25) */ + +#define SIR_LIM_DISASSOC_ACK_TIMEOUT (SIR_LIM_TIMEOUT_MSG_START + 0x26) +#define SIR_LIM_DEAUTH_ACK_TIMEOUT (SIR_LIM_TIMEOUT_MSG_START + 0x27) +#define SIR_LIM_PERIODIC_JOIN_PROBE_REQ_TIMEOUT \ + (SIR_LIM_TIMEOUT_MSG_START + 0x28) + +#define SIR_LIM_CONVERT_ACTIVE_CHANNEL_TO_PASSIVE \ + (SIR_LIM_TIMEOUT_MSG_START + 0x2C) +#define SIR_LIM_AUTH_RETRY_TIMEOUT (SIR_LIM_TIMEOUT_MSG_START + 0x2D) + +#define SIR_LIM_MSG_TYPES_END (SIR_LIM_MSG_TYPES_BEGIN+0xFF) + +/* SCH message types */ +#define SIR_SCH_MSG_TYPES_BEGIN (SIR_SCH_MODULE_ID << 8) +#define SIR_SCH_CHANNEL_SWITCH_REQUEST (SIR_SCH_MSG_TYPES_BEGIN) +#define SIR_SCH_START_SCAN_REQ (SIR_SCH_MSG_TYPES_BEGIN + 1) +#define SIR_SCH_START_SCAN_RSP (SIR_SCH_MSG_TYPES_BEGIN + 2) +#define SIR_SCH_END_SCAN_NTF (SIR_SCH_MSG_TYPES_BEGIN + 3) +#define SIR_SCH_MSG_TYPES_END (SIR_SCH_MSG_TYPES_BEGIN+0xFF) + +/* PMM message types */ +#define SIR_PMM_MSG_TYPES_BEGIN (SIR_PMM_MODULE_ID << 8) +#define SIR_PMM_CHANGE_PM_MODE (SIR_PMM_MSG_TYPES_BEGIN) +#define SIR_PMM_MSG_TYPES_END (SIR_PMM_MSG_TYPES_BEGIN+0xFF) + +/* MNT message types */ +#define SIR_MNT_MSG_TYPES_BEGIN (SIR_MNT_MODULE_ID << 8) +#define SIR_MNT_RELEASE_BD (SIR_MNT_MSG_TYPES_BEGIN + 0) +#define SIR_MNT_MSG_TYPES_END (SIR_MNT_MSG_TYPES_BEGIN + 0xFF) + +/* PTT message types */ +#define SIR_PTT_MSG_TYPES_BEGIN 0x3000 +#define SIR_PTT_MSG_TYPES_END 0x3300 + +/* ****************************************** * +* * +* EVENT TYPE Defintions * +* * +* ****************************************** */ + +/* MMH Events that are used in other modules to post events to MMH */ +#define SIR_HSTEMUL_TXMB_DONE_EVT 0x00000100 +#define SIR_HSTEMUL_RXMB_READY_EVT 0x00000200 +#define SIR_HSTEMUL_MSGQ_NE_EVT 0x00000400 + +#define SIR_TST_XMIT_MSG_QS_EMPTY_EVT 0x00000080 + +/* Param Change Bitmap sent to HAL */ +#define PARAM_BCN_INTERVAL_CHANGED (1 << 0) +#define PARAM_SHORT_PREAMBLE_CHANGED (1 << 1) +#define PARAM_SHORT_SLOT_TIME_CHANGED (1 << 2) +#define PARAM_llACOEXIST_CHANGED (1 << 3) +#define PARAM_llBCOEXIST_CHANGED (1 << 4) +#define PARAM_llGCOEXIST_CHANGED (1 << 5) +#define PARAM_HT20MHZCOEXIST_CHANGED (1<<6) +#define PARAM_NON_GF_DEVICES_PRESENT_CHANGED (1<<7) +#define PARAM_RIFS_MODE_CHANGED (1<<8) +#define PARAM_LSIG_TXOP_FULL_SUPPORT_CHANGED (1<<9) +#define PARAM_OBSS_MODE_CHANGED (1<<10) +#define PARAM_BEACON_UPDATE_MASK (PARAM_BCN_INTERVAL_CHANGED | \ + PARAM_SHORT_PREAMBLE_CHANGED | \ + PARAM_SHORT_SLOT_TIME_CHANGED | \ + PARAM_llACOEXIST_CHANGED | \ + PARAM_llBCOEXIST_CHANGED | \ + PARAM_llGCOEXIST_CHANGED | \ + PARAM_HT20MHZCOEXIST_CHANGED | \ + PARAM_NON_GF_DEVICES_PRESENT_CHANGED | \ + PARAM_RIFS_MODE_CHANGED | \ + PARAM_LSIG_TXOP_FULL_SUPPORT_CHANGED | \ + PARAM_OBSS_MODE_CHANGED) + +#endif diff --git a/drivers/staging/qcacld-3.0/core/mac/src/include/sys_global.h b/drivers/staging/qcacld-3.0/core/mac/src/include/sys_global.h new file mode 100644 index 0000000000000000000000000000000000000000..b3c09d7911feb4fa5af640578670ba428fb4e6ad --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/include/sys_global.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2013-2014, 2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef __SYS_GLOBAL_H__ +#define __SYS_GLOBAL_H__ + +typedef struct sAniSirSys { + + uint32_t gSysFrameCount[4][16]; + uint32_t gSysBbtReceived; + uint32_t sys_bbt_pending_mgmt_count; + uint32_t gSysBbtPostedToLim; + uint32_t gSysBbtPostedToSch; + uint32_t gSysBbtPostedToPmm; + uint32_t gSysBbtPostedToHal; + uint32_t gSysBbtDropped; + uint32_t gSysBbtNonLearnFrameInv; + uint32_t gSysBbtLearnFrameInv; + uint32_t gSysBbtCrcFail; + uint32_t gSysBbtDuplicates; + uint32_t gSysReleaseCount; + uint32_t probeError, probeBadSsid, probeIgnore, probeRespond; + + uint32_t gSysEnableLearnMode; + uint32_t gSysEnableScanMode; + uint32_t gSysEnableLinkMonitorMode; + qdf_spinlock_t bbt_mgmt_lock; +} tAniSirSys, *tpAniSirSys; + +#endif diff --git a/drivers/staging/qcacld-3.0/core/mac/src/include/utils_api.h b/drivers/staging/qcacld-3.0/core/mac/src/include/utils_api.h new file mode 100644 index 0000000000000000000000000000000000000000..445b545c2eee2686fcc42cf1f53db9ece2f0a7a5 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/include/utils_api.h @@ -0,0 +1,669 @@ +/* + * Copyright (c) 2011-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef __UTILSAPI_H +#define __UTILSAPI_H + +#include +#include +#include "ani_global.h" +#include "utils_global.h" +#include "sys_wrapper.h" + +/* / System role definition on a per BSS */ +typedef enum eBssSystemRole { + eSYSTEM_UNKNOWN_ROLE, + eSYSTEM_AP_ROLE, + eSYSTEM_STA_IN_IBSS_ROLE, + eSYSTEM_STA_ROLE, + eSYSTEM_BTAMP_STA_ROLE, + eSYSTEM_BTAMP_AP_ROLE, + + eSYSTEM_LAST_ROLE, + eSYSTEM_MULTI_BSS_ROLE = eSYSTEM_LAST_ROLE +} tBssSystemRole; + +#define LOG_INDEX_FOR_MODULE(modId) ((modId) - LOG_FIRST_MODULE_ID) +#define GET_MIN_VALUE(__val1, __val2) ((__val1 < __val2) ? __val1 : __val2) + +/* The caller must check loglevel. This API assumes loglevel is good */ +extern void log_debug(tpAniSirGlobal pMac, uint8_t modId, uint32_t debugLevel, + const char *pStr, va_list marker); + +extern void log_dbg(tpAniSirGlobal pMac, uint8_t modId, uint32_t debugLevel, + const char *pStr, ...); + +extern uint32_t gPktAllocCnt, gPktFreeCnt; + +extern QDF_TRACE_LEVEL get_vos_debug_level(uint32_t debugLevel); + +/* / Log initialization */ +extern tSirRetStatus log_init(tpAniSirGlobal); + +extern void log_deinit(tpAniSirGlobal); + +extern tSirRetStatus cfg_init(tpAniSirGlobal); +extern void cfg_de_init(tpAniSirGlobal); + +void sir_dump_buf(tpAniSirGlobal pMac, uint8_t modId, uint32_t level, + uint8_t *buf, uint32_t size); + +/** + * sir_swap_u16() + * + * FUNCTION: + * This function is called to swap two U8s of an uint16_t value + * + * LOGIC: + * + * ASSUMPTIONS: + * None. + * + * NOTE: + * + * @param val uint16_t value to be uint8_t swapped + * @return Swapped uint16_t value + */ + +static inline uint16_t sir_swap_u16(uint16_t val) +{ + return ((val & 0x00FF) << 8) | ((val & 0xFF00) >> 8); +} /*** end sir_swap_u16() ***/ + +/** + * sir_swap_u16if_needed() + * + * FUNCTION: + * This function is called to swap two U8s of an uint16_t value depending + * on endiannes of the target processor/compiler the software is + * running on + * + * LOGIC: + * + * ASSUMPTIONS: + * None. + * + * NOTE: + * + * @param val uint16_t value to be uint8_t swapped + * @return Swapped uint16_t value + */ + +static inline uint16_t sir_swap_u16if_needed(uint16_t val) +{ +#ifndef ANI_LITTLE_BYTE_ENDIAN + return sir_swap_u16(val); +#else + return val; +#endif +} /*** end sir_swap_u16if_needed() ***/ + +/** + * sir_swap_u32() + * + * FUNCTION: + * This function is called to swap four U8s of an uint32_t value + * + * LOGIC: + * + * ASSUMPTIONS: + * None. + * + * NOTE: + * + * @param val uint32_t value to be uint8_t swapped + * @return Swapped uint32_t value + */ + +static inline uint32_t sir_swap_u32(uint32_t val) +{ + return (val << 24) | + (val >> 24) | + ((val & 0x0000FF00) << 8) | ((val & 0x00FF0000) >> 8); +} /*** end sir_swap_u32() ***/ + +/** + * sir_swap_u32if_needed() + * + * FUNCTION: + * This function is called to swap U8s of an uint32_t value depending + * on endiannes of the target processor/compiler the software is + * running on + * + * LOGIC: + * + * ASSUMPTIONS: + * None. + * + * NOTE: + * + * @param val uint32_t value to be uint8_t swapped + * @return Swapped uint32_t value + */ + +static inline uint32_t sir_swap_u32if_needed(uint32_t val) +{ +#ifndef ANI_LITTLE_BYTE_ENDIAN + return sir_swap_u32(val); +#else + return val; +#endif +} /*** end sir_swap_u32if_needed() ***/ + +/** + * sir_swap_u32_buf + * + * FUNCTION: + * It swaps N dwords into the same buffer + * + * LOGIC: + * + * ASSUMPTIONS: + * None. + * + * NOTE: + * + * @param ptr address of uint32_t array + * @return void + * + */ + +static inline void sir_swap_u32_buf(uint32_t *ptr, uint32_t nWords) +{ + uint32_t i; + + for (i = 0; i < nWords; i++) + ptr[i] = sir_swap_u32(ptr[i]); +} + +/** + * sir_swap_u32_buf_if_needed() + * + * FUNCTION: + * This function is called to swap U8s of U32s in the buffer depending + * on endiannes of the target processor/compiler the software is + * running on + * + * LOGIC: + * + * ASSUMPTIONS: + * None. + * + * NOTE: + * + * @param pBuf Buffer that will get swapped + * @param nWords Number DWORDS will be swapped + * @return void + */ + +static inline void sir_swap_u32_buf_if_needed(uint32_t *pBuf, uint32_t nWords) +{ +#ifdef ANI_LITTLE_BYTE_ENDIAN + sir_swap_u32_buf(pBuf, nWords); +#endif +} /*** end sir_swap_u32if_needed() ***/ + +/** + * sir_swap_bd_if_needed + * + * FUNCTION: + * Byte swap all the dwords in the BD, except the PHY/MAC headers + * + * LOGIC: + * + * ASSUMPTIONS: + * None. + * + * NOTE: + * + * @param pBd BD that will get swapped + * @return void + */ + +static inline void sir_swap_bd_if_needed(uint32_t *pBd) +{ + sir_swap_u32_buf_if_needed(pBd, 6); + sir_swap_u32_buf_if_needed(pBd + 18, 14); +} + +/** + * sir_store_u16_n + * + * FUNCTION: + * It stores a 16 bit number into the byte array in network byte order + * i.e. the least significant byte first + * + * LOGIC: + * + * ASSUMPTIONS: + * None. + * + * NOTE: + * + * @param ptr address of destination byte array + * @param val value to store + * @return None + */ + +static inline void sir_store_u16_n(uint8_t *ptr, uint16_t val) +{ + *ptr++ = (val >> 8) & 0xff; + *ptr = val & 0xff; +} + +/** + * sir_store_u32_n + * + * FUNCTION: + * It stores a 32 bit number into the byte array in network byte order + * i.e. the least significant byte first + * + * LOGIC: + * + * ASSUMPTIONS: + * None. + * + * NOTE: + * + * @param ptr address of destination byte array + * @param val value to store + * @return None + */ + +static inline void sir_store_u32_n(uint8_t *ptr, uint32_t val) +{ + *ptr++ = (uint8_t) (val >> 24) & 0xff; + *ptr++ = (uint8_t) (val >> 16) & 0xff; + *ptr++ = (uint8_t) (val >> 8) & 0xff; + *ptr = (uint8_t) (val) & 0xff; +} + +/** + * sir_store_u16 + * + * FUNCTION: + * It stores a 16 bit number into the byte array in NON-network byte order + * i.e. the least significant byte first + * + * LOGIC: + * + * ASSUMPTIONS: + * None. + * + * NOTE: + * + * @param ptr address of destination byte array + * @param val value to store + * @return None + */ + +static inline void sir_store_u16(uint8_t *ptr, uint16_t val) +{ + *ptr++ = val & 0xff; + *ptr = (val >> 8) & 0xff; +} + +/** + * sir_store_u32 + * + * FUNCTION: + * It stores a 32 bit number into the byte array in NON-network byte order + * i.e. the least significant byte first + * + * LOGIC: + * + * ASSUMPTIONS: + * None. + * + * NOTE: + * + * @param ptr address of destination byte array + * @param val value to store + * @return None + */ + +static inline void sir_store_u32(uint8_t *ptr, uint32_t val) +{ + *ptr++ = (uint8_t) val & 0xff; + *ptr++ = (uint8_t) (val >> 8) & 0xff; + *ptr++ = (uint8_t) (val >> 16) & 0xff; + *ptr = (uint8_t) (val >> 24) & 0xff; +} + +/** + * sir_store_u32BufN + * + * FUNCTION: + * It stores a 32 bit number into the byte array in network byte order + * i.e. the least significant byte first. It performs the above operation + * on entire buffer and writes to the dst buffer + * + * LOGIC: + * + * ASSUMPTIONS: + * Assumes that the pSrc buffer is of all uint32_t data type fields. + * + * NOTE: + * Must be used if all the fields in the buffer must be of uint32_t types. + * + * @param pDst address of destination byte array + * @param pSrc address of the source DWORD array + * @param length number of DWORDs + * @return None + */ + +static inline void +sir_store_buf_n(uint8_t *pDst, uint32_t *pSrc, uint32_t length) +{ + while (length) { + sir_store_u32_n(pDst, *pSrc); + pDst += 4; + pSrc++; + length--; + } +} + +/** + * sir_read_u16_n + * + * FUNCTION: + * It reads a 16 bit number from the byte array in network byte order + * i.e. the least significant byte first + * + * LOGIC: + * + * ASSUMPTIONS: + * None. + * + * NOTE: + * + * @param ptr address of byte array + * @return 16 bit value + */ + +static inline uint16_t sir_read_u16_n(uint8_t *ptr) +{ + return ((*ptr) << 8) | (*(ptr + 1)); +} + +/** + * sir_swap_u32_buf + * + * FUNCTION: + * It swaps N dwords into the same buffer + * + * LOGIC: + * + * ASSUMPTIONS: + * None. + * + * NOTE: + * + * @param ptr address of uint32_t array + * @return void + * + */ + +static inline void +sir_swap_n_store(uint32_t *src, uint32_t *dst, uint32_t nWords) +{ + uint32_t i; + + for (i = 0; i < nWords; i++) + dst[i] = sir_swap_u32(src[i]); +} + +/** + * sir_read_u32_n + * + * FUNCTION: + * It reads a 32 bit number from the byte array in network byte order + * i.e. the least significant byte first + * + * LOGIC: + * + * ASSUMPTIONS: + * None. + * + * NOTE: + * + * @param ptr address of byte array + * @return 32 bit value + */ + +static inline uint32_t sir_read_u32_n(uint8_t *ptr) +{ + return (*(ptr) << 24) | + (*(ptr + 1) << 16) | (*(ptr + 2) << 8) | (*(ptr + 3)); +} + +/** + * sir_read_u16 + * + * FUNCTION: + * It reads a 16 bit number from the byte array in NON-network byte order + * i.e. the least significant byte first + * + * LOGIC: + * + * ASSUMPTIONS: + * None. + * + * NOTE: + * + * @param ptr address of byte array + * @return 16 bit value + */ + +static inline uint16_t sir_read_u16(uint8_t *ptr) +{ + return (*ptr) | (*(ptr + 1) << 8); +} + +/** + * sir_read_u32 + * + * FUNCTION: + * It reads a 32 bit number from the byte array in NON-network byte order + * i.e. the least significant byte first + * + * LOGIC: + * + * ASSUMPTIONS: + * None. + * + * NOTE: + * + * @param ptr address of byte array + * @return 32 bit value + */ + +static inline uint32_t sir_read_u32(uint8_t *ptr) +{ + return (*(ptr)) | + (*(ptr + 1) << 8) | (*(ptr + 2) << 16) | (*(ptr + 3) << 24); +} + +/* / Copy a MAC address from 'from' to 'to' */ +static inline void sir_copy_mac_addr(uint8_t to[], uint8_t from[]) +{ +#if defined(_X86_) + uint32_t align = (0x3 & ((uint32_t) to | (uint32_t) from)); + if (align == 0) { + *((uint16_t *) &(to[4])) = *((uint16_t *) &(from[4])); + *((uint32_t *) to) = *((uint32_t *) from); + } else if (align == 2) { + *((uint16_t *) &to[4]) = *((uint16_t *) &from[4]); + *((uint16_t *) &to[2]) = *((uint16_t *) &from[2]); + *((uint16_t *) &to[0]) = *((uint16_t *) &from[0]); + } else { + to[5] = from[5]; + to[4] = from[4]; + to[3] = from[3]; + to[2] = from[2]; + to[1] = from[1]; + to[0] = from[0]; + } +#else + to[0] = from[0]; + to[1] = from[1]; + to[2] = from[2]; + to[3] = from[3]; + to[4] = from[4]; + to[5] = from[5]; +#endif +} + +static inline uint8_t sir_compare_mac_addr(uint8_t addr1[], uint8_t addr2[]) +{ +#if defined(_X86_) + uint32_t align = (0x3 & ((uint32_t) addr1 | (uint32_t) addr2)); + + if (align == 0) { + return (*((uint16_t *) &(addr1[4])) == + *((uint16_t *) &(addr2[4]))) + && (*((uint32_t *) addr1) == *((uint32_t *) addr2)); + } else if (align == 2) { + return (*((uint16_t *) &addr1[4]) == + *((uint16_t *) &addr2[4])) + && (*((uint16_t *) &addr1[2]) == + *((uint16_t *) &addr2[2])) + && (*((uint16_t *) &addr1[0]) == + *((uint16_t *) &addr2[0])); + } else { + return (addr1[5] == addr2[5]) && + (addr1[4] == addr2[4]) && + (addr1[3] == addr2[3]) && + (addr1[2] == addr2[2]) && + (addr1[1] == addr2[1]) && (addr1[0] == addr2[0]); + } +#else + return (addr1[0] == addr2[0]) && + (addr1[1] == addr2[1]) && + (addr1[2] == addr2[2]) && + (addr1[3] == addr2[3]) && + (addr1[4] == addr2[4]) && (addr1[5] == addr2[5]); +#endif +} + +/* + * converts uint16_t CW value to 4 bit value to be inserted in IE + */ +static inline uint8_t convert_cw(uint16_t cw) +{ + uint8_t val = 0; + while (cw > 0) { + val++; + cw >>= 1; + } + if (val > 15) + return 0xF; + return val; +} + +/* The user priority to AC mapping is such: + * UP(1, 2) ---> AC_BK(1) + * UP(0, 3) ---> AC_BE(0) + * UP(4, 5) ---> AC_VI(2) + * UP(6, 7) ---> AC_VO(3) + */ +#define WLAN_UP_TO_AC_MAP 0x33220110 +#define upToAc(up) ((WLAN_UP_TO_AC_MAP >> ((up) << 2)) & 0x03) + +/* ------------------------------------------------------------------- */ + +/* / Parse the next IE in a message */ +extern tSirRetStatus sirParseNextIE(tpAniSirGlobal, uint8_t *pPayload, + uint16_t payloadLength, int16_t lastType, + uint8_t *pType, uint8_t *pLength); + +/* / Check if the given channel is 11b channel */ +#define SIR_IS_CHANNEL_11B(chId) (chId <= 14) + +/** + * hal_round_s32 + * + * FUNCTION: + * Performs integer rounding like returns 12346 for 123456 or -12346 for -123456 + * Note that a decimal place is lost. + * + * LOGIC: + * + * ASSUMPTIONS: + * None. + * + * NOTE: + * + * @param int32_t input + * @return rounded number + */ +static inline int32_t hal_round_s32(int32_t p) +{ + int32_t k, i, j; + + i = p / 10; + j = p % 10; + if (p > 0) + k = i + (j > 4 ? 1 : 0); + else if (p < 0) + k = i + (j < -5 ? -1 : 0); + else + k = p; + + return k; +} + +/* New functions for endianess conversion */ +#ifdef ANI_LITTLE_BYTE_ENDIAN +#define ani_cpu_to_be16(x) sir_swap_u16((x)) +#define ani_cpu_to_le16(x) (x) +#define ani_cpu_to_be32(x) sir_swap_u32((x)) +#define ani_cpu_to_le32(x) (x) +#else /* ANI_LITTLE_BYTE_ENDIAN */ +#define ani_cpu_to_be16(x) (x) +#define ani_cpu_to_le16(x) sir_swap_u16((x)) +#define ani_cpu_to_be32(x) (x) +#define ani_cpu_to_le32(x) sir_swap_u32((x)) +#endif /* ANI_LITTLE_BYTE_ENDIAN */ + +#define ani_le16_to_cpu(x) ani_cpu_to_le16(x) +#define ani_le32_to_cpu(x) ani_cpu_to_le32(x) +#define ani_be16_to_cpu(x) ani_cpu_to_be16(x) +#define ani_be32_to_cpu(x) ani_cpu_to_be32(x) + +void convertto_big_endian(void *ptr, uint16_t size); +void create_scan_cts_frame(tpAniSirGlobal pMac, tSirMacMgmtHdr *macMgmtHdr, + tSirMacAddr selfMac); +void create_scan_data_null_frame(tpAniSirGlobal pMac, + tSirMacMgmtHdr *macMgmtHdr, uint8_t pwrMgmt, tSirMacAddr bssid, + tSirMacAddr selfMacAddr); +void create_init_scan_raw_frame(tpAniSirGlobal pMac, tSirMacMgmtHdr *macMgmtHdr, + tBssSystemRole role); +void create_finish_scan_raw_frame(tpAniSirGlobal pMac, + tSirMacMgmtHdr *macMgmtHdr, tBssSystemRole role); + +#endif /* __UTILSAPI_H */ diff --git a/drivers/staging/qcacld-3.0/core/mac/src/include/utils_global.h b/drivers/staging/qcacld-3.0/core/mac/src/include/utils_global.h new file mode 100644 index 0000000000000000000000000000000000000000..db2f8547dcacc25544ed3fda893752afaa0d6dd1 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/include/utils_global.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2011-2012, 2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * + * Author: Sandesh Goel + * Date: 02/25/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + * + */ + +#ifndef __UTILS_GLOBAL_H__ +#define __UTILS_GLOBAL_H__ + +#include "sir_params.h" + +/* + * Current debug and event log level + */ +#define LOG_FIRST_MODULE_ID SIR_FIRST_MODULE_ID +#define LOG_LAST_MODULE_ID SIR_LAST_MODULE_ID +#define LOG_ENTRY_NUM (LOG_LAST_MODULE_ID - LOG_FIRST_MODULE_ID + 1) + +typedef struct sAniSirUtils { + uint32_t gLogEvtLevel[LOG_ENTRY_NUM]; + uint32_t gLogDbgLevel[LOG_ENTRY_NUM]; + +} tAniSirUtils, *tpAniSirUtils; + +#endif diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/include/lim_admit_control.h b/drivers/staging/qcacld-3.0/core/mac/src/pe/include/lim_admit_control.h new file mode 100644 index 0000000000000000000000000000000000000000..90eae86ee5f8a7d10034a139ff5ea216f0602418 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/include/lim_admit_control.h @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2011-2012, 2014-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * + * Author: Dinesh Upadhyay + * Date: 10/24/06 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + * + */ + +#ifndef __LIM_ADMIT_CONTROL_H__ +#define __LIM_ADMIT_CONTROL_H__ + +#include "sir_common.h" +#include "sir_mac_prot_def.h" + +#include "ani_global.h" + +tSirRetStatus +lim_tspec_find_by_assoc_id(tpAniSirGlobal, uint16_t, tSirMacTspecIE *, + tpLimTspecInfo, tpLimTspecInfo *); + +/* Add TSPEC in lim local table */ +tSirRetStatus lim_tspec_add(tpAniSirGlobal pMac, + uint8_t *pAddr, + uint16_t assocId, + tSirMacTspecIE *pTspec, + uint32_t interval, tpLimTspecInfo *ppInfo); + +/* admit control interface */ +extern tSirRetStatus lim_admit_control_add_ts(tpAniSirGlobal pMac, + uint8_t *pAddr, tSirAddtsReqInfo *addts, + tSirMacQosCapabilityStaIE *qos, + uint16_t assocId, uint8_t alloc, + tSirMacScheduleIE *pSch, + /* index to the lim tspec table. */ + uint8_t *pTspecIdx, + tpPESession psessionEntry); + +static inline tSirRetStatus +lim_admit_control_add_sta(tpAniSirGlobal pMac, uint8_t *staAddr, uint8_t alloc) +{ + return eSIR_SUCCESS; +} + +extern tSirRetStatus +lim_admit_control_delete_sta(tpAniSirGlobal pMac, uint16_t assocId); + +extern tSirRetStatus +lim_admit_control_delete_ts(tpAniSirGlobal pMac, + uint16_t assocId, + tSirMacTSInfo *tsinfo, + uint8_t *tsStatus, uint8_t *tspecIdx); + +extern tSirRetStatus lim_update_admit_policy(tpAniSirGlobal pMac); + +tSirRetStatus lim_admit_control_init(tpAniSirGlobal pMac); +#ifdef FEATURE_WLAN_ESE +tSirRetStatus lim_send_hal_msg_add_ts(tpAniSirGlobal pMac, + uint16_t staIdx, + uint8_t tspecIdx, + tSirMacTspecIE tspecIE, + uint8_t sessionId, uint16_t tsm_interval); +#else +tSirRetStatus lim_send_hal_msg_add_ts(tpAniSirGlobal pMac, + uint16_t staIdx, + uint8_t tspecIdx, + tSirMacTspecIE tspecIE, + uint8_t sessionId); +#endif + +tSirRetStatus lim_send_hal_msg_del_ts(tpAniSirGlobal pMac, + uint16_t staIdx, + uint8_t tspecIdx, + tSirDeltsReqInfo delts, + uint8_t sessionId, uint8_t *bssId); +void lim_process_hal_add_ts_rsp(tpAniSirGlobal pMac, tpSirMsgQ limMsg); + +#endif diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/include/lim_api.h b/drivers/staging/qcacld-3.0/core/mac/src/pe/include/lim_api.h new file mode 100644 index 0000000000000000000000000000000000000000..af828f72456a884238b6d6e342d8637d3bf4f063 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/include/lim_api.h @@ -0,0 +1,335 @@ +/* + * Copyright (c) 2011-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * + * This file lim_api.h contains the definitions exported by + * LIM module. + * Author: Chandra Modumudi + * Date: 02/11/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + * + */ +#ifndef __LIM_API_H +#define __LIM_API_H +#include "wni_api.h" +#include "sir_api.h" +#include "ani_global.h" +#include "sir_mac_prot_def.h" +#include "sir_common.h" +#include "sir_debug.h" +#include "sch_global.h" +#include "utils_api.h" +#include "lim_global.h" +#include "wma_if.h" +#include "wma_types.h" + +/* Macro to count heartbeat */ +#define limResetHBPktCount(psessionEntry) (psessionEntry->LimRxedBeaconCntDuringHB = 0) + +/* Useful macros for fetching various states in pMac->lim */ +/* gLimSystemRole */ +#define GET_LIM_SYSTEM_ROLE(psessionEntry) (psessionEntry->limSystemRole) +#define LIM_IS_AP_ROLE(psessionEntry) (GET_LIM_SYSTEM_ROLE(psessionEntry) == eLIM_AP_ROLE) +#define LIM_IS_STA_ROLE(psessionEntry) (GET_LIM_SYSTEM_ROLE(psessionEntry) == eLIM_STA_ROLE) +#define LIM_IS_IBSS_ROLE(psessionEntry) (GET_LIM_SYSTEM_ROLE(psessionEntry) == eLIM_STA_IN_IBSS_ROLE) +#define LIM_IS_UNKNOWN_ROLE(psessionEntry) (GET_LIM_SYSTEM_ROLE(psessionEntry) == eLIM_UNKNOWN_ROLE) +#define LIM_IS_P2P_DEVICE_ROLE(psessionEntry) (GET_LIM_SYSTEM_ROLE(psessionEntry) == eLIM_P2P_DEVICE_ROLE) +#define LIM_IS_P2P_DEVICE_GO(psessionEntry) (GET_LIM_SYSTEM_ROLE(psessionEntry) == eLIM_P2P_DEVICE_GO) +#define LIM_IS_NDI_ROLE(psessionEntry) \ + (GET_LIM_SYSTEM_ROLE(psessionEntry) == eLIM_NDI_ROLE) +/* gLimSmeState */ +#define GET_LIM_SME_STATE(pMac) (pMac->lim.gLimSmeState) +#define SET_LIM_SME_STATE(pMac, state) (pMac->lim.gLimSmeState = state) +/* gLimMlmState */ +#define GET_LIM_MLM_STATE(pMac) (pMac->lim.gLimMlmState) +#define SET_LIM_MLM_STATE(pMac, state) (pMac->lim.gLimMlmState = state) +/*tpdphHashNode mlmStaContext*/ +#define GET_LIM_STA_CONTEXT_MLM_STATE(pStaDs) (pStaDs->mlmStaContext.mlmState) +#define SET_LIM_STA_CONTEXT_MLM_STATE(pStaDs, state) (pStaDs->mlmStaContext.mlmState = state) +/* gLimQuietState */ +#define GET_LIM_QUIET_STATE(pMac) (pMac->lim.gLimSpecMgmt.quietState) +#define SET_LIM_QUIET_STATE(pMac, state) (pMac->lim.gLimSpecMgmt.quietState = state) +#define LIM_IS_CONNECTION_ACTIVE(psessionEntry) (psessionEntry->LimRxedBeaconCntDuringHB) +/*pMac->lim.gLimProcessDefdMsgs*/ +#define GET_LIM_PROCESS_DEFD_MESGS(pMac) (pMac->lim.gLimProcessDefdMsgs) +#define SET_LIM_PROCESS_DEFD_MESGS(pMac, val) \ + pMac->lim.gLimProcessDefdMsgs = val; \ + pe_debug("%s Defer LIM messages - value %d", __func__, val); +/* LIM exported function templates */ +#define LIM_MIN_BCN_PR_LENGTH 12 +#define LIM_BCN_PR_CAPABILITY_OFFSET 10 +#define LIM_ASSOC_REQ_IE_OFFSET 4 + +/** + * enum lim_vendor_ie_access_policy - vendor ie access policy + * @LIM_ACCESS_POLICY_NONE: access policy not valid + * @LIM_ACCESS_POLICY_RESPOND_IF_IE_IS_PRESENT: respond only if vendor ie + * is present in probe request and assoc request frames + * @LIM_ACCESS_POLICY_DONOT_RESPOND_IF_IE_IS_PRESENT: do not respond if vendor + * ie is present in probe request or assoc request frames + */ +enum lim_vendor_ie_access_policy { + LIM_ACCESS_POLICY_NONE, + LIM_ACCESS_POLICY_RESPOND_IF_IE_IS_PRESENT, + LIM_ACCESS_POLICY_DONOT_RESPOND_IF_IE_IS_PRESENT, +}; + +typedef enum eMgmtFrmDropReason { + eMGMT_DROP_NO_DROP, + eMGMT_DROP_NOT_LAST_IBSS_BCN, + eMGMT_DROP_INFRA_BCN_IN_IBSS, + eMGMT_DROP_SCAN_MODE_FRAME, + eMGMT_DROP_NON_SCAN_MODE_FRAME, + eMGMT_DROP_INVALID_SIZE, + eMGMT_DROP_SPURIOUS_FRAME, +} tMgmtFrmDropReason; + +/** + * Function to initialize LIM state machines. + * This called upon LIM thread creation. + */ +extern tSirRetStatus lim_initialize(tpAniSirGlobal); +tSirRetStatus pe_open(tpAniSirGlobal pMac, struct cds_config_info *cds_cfg); +tSirRetStatus pe_close(tpAniSirGlobal pMac); +void pe_register_tl_handle(tpAniSirGlobal pMac); +tSirRetStatus lim_start(tpAniSirGlobal pMac); +tSirRetStatus pe_start(tpAniSirGlobal pMac); +void pe_stop(tpAniSirGlobal pMac); +tSirRetStatus pe_post_msg_api(tpAniSirGlobal pMac, tSirMsgQ *pMsg); +tSirRetStatus peProcessMsg(tpAniSirGlobal pMac, tSirMsgQ *limMsg); + +/** + * pe_register_callbacks_with_wma() - register SME and PE callback functions to + * WMA. + * @pMac: mac global ctx + * @ready_req: Ready request parameters, containing callback pointers + * + * Return: None + */ +void pe_register_callbacks_with_wma(tpAniSirGlobal pMac, + tSirSmeReadyReq *ready_req); + +/** + * Function to cleanup LIM state. + * This called upon reset/persona change etc + */ +extern void lim_cleanup(tpAniSirGlobal); +/* / Function to post messages to LIM thread */ +extern uint32_t lim_post_msg_api(tpAniSirGlobal, tSirMsgQ *); +uint32_t lim_post_msg_high_priority(tpAniSirGlobal mac, tSirMsgQ *msg); + +/** + * Function to process messages posted to LIM thread + * and dispatch to various sub modules within LIM module. + */ +extern void lim_message_processor(tpAniSirGlobal, tpSirMsgQ); +/** + * Function to check the LIM state if system is in Scan/Learn state. + */ +extern uint8_t lim_is_system_in_scan_state(tpAniSirGlobal); +/** + * Function to handle IBSS coalescing. + * Beacon Processing module to call this. + */ +extern tSirRetStatus lim_handle_ibss_coalescing(tpAniSirGlobal, + tpSchBeaconStruct, + uint8_t *, tpPESession); +/* / Function used by other Sirius modules to read global SME state */ +static inline tLimSmeStates lim_get_sme_state(tpAniSirGlobal pMac) +{ + return pMac->lim.gLimSmeState; +} + +extern void lim_received_hb_handler(tpAniSirGlobal, uint8_t, tpPESession); +extern void limCheckAndQuietBSS(tpAniSirGlobal); +/* / Function that triggers STA context deletion */ +extern void lim_trigger_sta_deletion(tpAniSirGlobal pMac, tpDphHashNode pStaDs, + tpPESession psessionEntry); + +#ifdef FEATURE_WLAN_TDLS +/* Function that sends TDLS Del Sta indication to SME */ +extern void lim_send_sme_tdls_del_sta_ind(tpAniSirGlobal pMac, tpDphHashNode pStaDs, + tpPESession psessionEntry, + uint16_t reasonCode); +/** + * lim_set_tdls_flags() - update tdls flags based on newer STA connection + * information + * @roam_sync_ind_ptr: pointer to roam offload structure + * @ft_session_ptr: pointer to PE session + * + * Set TDLS flags as per new STA connection capabilities. + * + * Return: None + */ +void lim_set_tdls_flags(roam_offload_synch_ind *roam_sync_ind_ptr, + tpPESession ft_session_ptr); +#else +static inline void lim_set_tdls_flags(roam_offload_synch_ind *roam_sync_ind_ptr, + tpPESession ft_session_ptr) +{ +} +#endif + +/* / Function that checks for change in AP's capabilties on STA */ +extern void lim_detect_change_in_ap_capabilities(tpAniSirGlobal, + tpSirProbeRespBeacon, tpPESession); +tSirRetStatus lim_update_short_slot(tpAniSirGlobal pMac, + tpSirProbeRespBeacon pBeacon, + tpUpdateBeaconParams pBeaconParams, + tpPESession); + +void lim_ps_offload_handle_missed_beacon_ind(tpAniSirGlobal pMac, tpSirMsgQ pMsg); +void lim_send_heart_beat_timeout_ind(tpAniSirGlobal pMac, tpPESession psessionEntry); +tMgmtFrmDropReason lim_is_pkt_candidate_for_drop(tpAniSirGlobal pMac, + uint8_t *pRxPacketInfo, + uint32_t subType); +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +QDF_STATUS pe_roam_synch_callback(tpAniSirGlobal mac_ctx, + struct sSirSmeRoamOffloadSynchInd *roam_sync_ind_ptr, + tpSirBssDescription bss_desc_ptr); +#else +static inline QDF_STATUS pe_roam_synch_callback(tpAniSirGlobal mac_ctx, + struct sSirSmeRoamOffloadSynchInd *roam_sync_ind_ptr, + tpSirBssDescription bss_desc_ptr) +{ + return QDF_STATUS_E_NOSUPPORT; +} +#endif + +/** + * lim_update_lost_link_info() - update lost link information to SME + * @mac: global MAC handle + * @session: PE session + * @rssi: rssi value from the received frame + * + * Return: None + */ +void lim_update_lost_link_info(tpAniSirGlobal mac, tpPESession session, + int32_t rssi); + +/** + * lim_mon_init_session() - create PE session for monitor mode operation + * @mac_ptr: mac pointer + * @msg: Pointer to struct sir_create_session type. + * + * Return: NONE + */ +void lim_mon_init_session(tpAniSirGlobal mac_ptr, + struct sir_create_session *msg); + +#define limGetQosMode(psessionEntry, pVal) (*(pVal) = (psessionEntry)->limQosEnabled) +#define limGetWmeMode(psessionEntry, pVal) (*(pVal) = (psessionEntry)->limWmeEnabled) +#define limGetWsmMode(psessionEntry, pVal) (*(pVal) = (psessionEntry)->limWsmEnabled) +#define limGet11dMode(psessionEntry, pVal) (*(pVal) = (psessionEntry)->lim11dEnabled) +#define limGetAckPolicy(pMac, pVal) (*(pVal) = pMac->lim.ackPolicy) +/* ----------------------------------------------------------------------- */ +static inline void lim_get_phy_mode(tpAniSirGlobal pMac, uint32_t *phyMode, + tpPESession psessionEntry) +{ + *phyMode = + psessionEntry ? psessionEntry->gLimPhyMode : pMac->lim.gLimPhyMode; +} + +/* ----------------------------------------------------------------------- */ +static inline void lim_get_rf_band_new(tpAniSirGlobal pMac, tSirRFBand *band, + tpPESession psessionEntry) +{ + *band = psessionEntry ? psessionEntry->limRFBand : SIR_BAND_UNKNOWN; +} + +/*-------------------------------------------------------------------------- + + \brief pe_process_messages() - Message Processor for PE + + Voss calls this function to dispatch the message to PE + + \param pMac - Pointer to Global MAC structure + \param pMsg - Pointer to the message structure + + \return uint32_t - TX_SUCCESS for success. + + --------------------------------------------------------------------------*/ +tSirRetStatus pe_process_messages(tpAniSirGlobal pMac, tSirMsgQ *pMsg); +/** ------------------------------------------------------------- + \fn pe_free_msg + \brief Called by CDS scheduler (function cds_sched_flush_mc_mqs) + \ to free a given PE message on the TX and MC thread. + \ This happens when there are messages pending in the PE + \ queue when system is being stopped and reset. + \param tpAniSirGlobal pMac + \param tSirMsgQ pMsg + \return none + -----------------------------------------------------------------*/ +void pe_free_msg(tpAniSirGlobal pMac, tSirMsgQ *pMsg); + +/*-------------------------------------------------------------------------- + + \brief lim_remain_on_chn_rsp() - API for sending remain on channel response. + + LIM calls this api to send the remain on channel response to SME. + + \param pMac - Pointer to Global MAC structure + \param status - status of the response + \param data - pointer to msg + + \return void + + --------------------------------------------------------------------------*/ +void lim_remain_on_chn_rsp(tpAniSirGlobal pMac, QDF_STATUS status, uint32_t *data); + +void lim_process_abort_scan_ind(tpAniSirGlobal pMac, uint8_t sessionId, + uint32_t scan_id, uint32_t scan_requestor_id); + +void __lim_process_sme_assoc_cnf_new(tpAniSirGlobal, uint32_t, uint32_t *); + +/** + * lim_process_sme_addts_rsp_timeout(): Send addts rsp timeout to SME + * @pMac: Pointer to Global MAC structure + * @param: Addts rsp timer count + * + * This function is used to reset the addts sent flag and + * send addts rsp timeout to SME + * + * Return: None + */ +void lim_process_sme_addts_rsp_timeout(tpAniSirGlobal pMac, uint32_t param); +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH +void lim_fill_join_rsp_ht_caps(tpPESession session, tpSirSmeJoinRsp rsp); +#else +static inline void lim_fill_join_rsp_ht_caps(tpPESession session, + tpSirSmeJoinRsp rsp) +{} +#endif +QDF_STATUS lim_update_ext_cap_ie(tpAniSirGlobal mac_ctx, + uint8_t *ie_data, uint8_t *local_ie_buf, uint16_t *local_ie_len); +QDF_STATUS lim_add_qcn_ie(tpAniSirGlobal mac_ctx, uint8_t *ie_data, + uint16_t *ie_len); +/************************************************************/ +#endif /* __LIM_API_H */ diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/include/lim_ft.h b/drivers/staging/qcacld-3.0/core/mac/src/pe/include/lim_ft.h new file mode 100644 index 0000000000000000000000000000000000000000..e4751139a6f26886ed3230e97670141b93085f0f --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/include/lim_ft.h @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2011-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/**========================================================================= + + Macros and Function prototypes FT and 802.11R purposes + + ========================================================================*/ + +#ifndef __LIMFT_H__ +#define __LIMFT_H__ + +#include +#include +#include +#include +#include + +/*------------------------------------------------------------------------- + Function declarations and documenation + ------------------------------------------------------------------------*/ +void lim_ft_open(tpAniSirGlobal pMac, tpPESession psessionEntry); +void lim_ft_cleanup(tpAniSirGlobal pMac, tpPESession psessionEntry); +#ifdef WLAN_FEATURE_HOST_ROAM +void lim_ft_cleanup_pre_auth_info(tpAniSirGlobal pMac, + tpPESession psessionEntry); +int lim_process_ft_pre_auth_req(tpAniSirGlobal pMac, tpSirMsgQ pMsg); +void lim_process_ft_preauth_rsp_timeout(tpAniSirGlobal pMac); +void lim_process_mlm_ft_reassoc_req(tpAniSirGlobal pMac, uint32_t *pMsgBuf, + tpPESession psessionEntry); +void lim_perform_ft_pre_auth(tpAniSirGlobal pMac, QDF_STATUS status, + uint32_t *data, tpPESession psessionEntry); +void lim_post_ft_pre_auth_rsp(tpAniSirGlobal pMac, tSirRetStatus status, + uint8_t *auth_rsp, uint16_t auth_rsp_length, + tpPESession psessionEntry); +void lim_handle_ft_pre_auth_rsp(tpAniSirGlobal pMac, tSirRetStatus status, + uint8_t *auth_rsp, uint16_t auth_rsp_len, + tpPESession psessionEntry); +tSirRetStatus lim_ft_setup_auth_session(tpAniSirGlobal pMac, + tpPESession psessionEntry); +void lim_process_mlm_reassoc_cnf(tpAniSirGlobal mac_ctx, uint32_t *msg); +void lim_process_sta_mlm_add_bss_rsp_ft(tpAniSirGlobal pMac, + tpSirMsgQ limMsgQ, tpPESession psessionEntry); +void lim_process_mlm_reassoc_req(tpAniSirGlobal mac_ctx, uint32_t *msg); +void lim_preauth_scan_event_handler(tpAniSirGlobal mac_ctx, + enum sir_scan_event_type event, + uint8_t session_id, + uint32_t scan_id); +QDF_STATUS lim_send_preauth_scan_offload(tpAniSirGlobal mac_ctx, + uint8_t session_id, tSirFTPreAuthReq *ft_preauth_req); +#else +static inline void lim_ft_cleanup_pre_auth_info(tpAniSirGlobal pMac, + tpPESession psessionEntry) +{} +static inline void lim_process_ft_preauth_rsp_timeout(tpAniSirGlobal pMac) +{} +static inline void lim_process_mlm_ft_reassoc_req(tpAniSirGlobal pMac, + uint32_t *pMsgBuf, tpPESession psessionEntry) +{} +static inline void lim_handle_ft_pre_auth_rsp(tpAniSirGlobal pMac, + tSirRetStatus status, uint8_t *auth_rsp, + uint16_t auth_rsp_len, tpPESession psessionEntry) +{} +static inline void lim_process_mlm_reassoc_cnf(tpAniSirGlobal mac_ctx, + uint32_t *msg) +{} +static inline void lim_process_sta_mlm_add_bss_rsp_ft(tpAniSirGlobal pMac, + tpSirMsgQ limMsgQ, tpPESession psessionEntry) +{} +static inline void lim_process_mlm_reassoc_req(tpAniSirGlobal mac_ctx, + uint32_t *msg) +{} +static inline void lim_preauth_scan_event_handler(tpAniSirGlobal mac_ctx, + enum sir_scan_event_type event, + uint8_t session_id, uint32_t scan_id) +{} +static inline int lim_process_ft_pre_auth_req(tpAniSirGlobal pMac, + tpSirMsgQ pMsg) +{ + return 0; +} +#endif + +#if defined(WLAN_FEATURE_HOST_ROAM) || defined(WLAN_FEATURE_ROAM_OFFLOAD) +void lim_fill_ft_session(tpAniSirGlobal pMac, + tpSirBssDescription pbssDescription, + tpPESession pftSessionEntry, + tpPESession psessionEntry); +void lim_ft_prepare_add_bss_req(tpAniSirGlobal pMac, uint8_t updateEntry, + tpPESession pftSessionEntry, + tpSirBssDescription bssDescription); +QDF_STATUS lim_send_preauth_scan_offload(tpAniSirGlobal mac_ctx, + uint8_t session_id, tSirFTPreAuthReq *ft_preauth_req); +#else +static inline void lim_fill_ft_session(tpAniSirGlobal pMac, + tpSirBssDescription pbssDescription, + tpPESession pftSessionEntry, + tpPESession psessionEntry) +{} +static inline void lim_ft_prepare_add_bss_req(tpAniSirGlobal pMac, + uint8_t updateEntry, tpPESession pftSessionEntry, + tpSirBssDescription bssDescription) +{} +#endif + +bool lim_process_ft_update_key(tpAniSirGlobal pMac, uint32_t *pMsgBuf); +tSirRetStatus lim_process_ft_aggr_qos_req(tpAniSirGlobal pMac, + uint32_t *pMsgBuf); +void lim_process_ft_aggr_qo_s_rsp(tpAniSirGlobal pMac, tpSirMsgQ limMsg); +void lim_ft_cleanup_all_ft_sessions(tpAniSirGlobal pMac); +#endif /* __LIMFT_H__ */ diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/include/lim_ft_defs.h b/drivers/staging/qcacld-3.0/core/mac/src/pe/include/lim_ft_defs.h new file mode 100644 index 0000000000000000000000000000000000000000..476d1d35616c8e763d592ae1d13cff7037aac602 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/include/lim_ft_defs.h @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2013-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/**========================================================================= + + Macros and Function prototypes FT and 802.11R purposes + + ========================================================================*/ + +#ifndef __LIMFTDEFS_H__ +#define __LIMFTDEFS_H__ + +#include +#include "wma_if.h" + +/*-------------------------------------------------------------------------- + Preprocessor definitions and constants + ------------------------------------------------------------------------*/ +#define MAX_FTIE_SIZE 384 /* Max size limited to 384, on acct. of IW custom events */ + +/* Time to dwell on preauth channel during roaming, in milliseconds */ +#define LIM_FT_PREAUTH_SCAN_TIME 50 + +/*-------------------------------------------------------------------------- + Type declarations + ------------------------------------------------------------------------*/ +/*-------------------------------------------------------------------------- + FT Pre Auth Req SME<->PE + ------------------------------------------------------------------------*/ +typedef struct sSirFTPreAuthReq { + uint16_t messageType; /* eWNI_SME_FT_PRE_AUTH_REQ */ + uint16_t length; + /* + * Track if response is processed for this request + * We expect only one response per request. + */ + bool bPreAuthRspProcessed; + uint8_t preAuthchannelNum; + /* BSSID currently associated to suspend the link */ + tSirMacAddr currbssId; + tSirMacAddr preAuthbssId; /* BSSID to preauth to */ + tSirMacAddr self_mac_addr; + uint32_t scan_id; + uint16_t ft_ies_length; + uint8_t ft_ies[MAX_FTIE_SIZE]; + tpSirBssDescription pbssDescription; +} tSirFTPreAuthReq, *tpSirFTPreAuthReq; + +/*------------------------------------------------------------------------- + FT Pre Auth Rsp PE<->SME + ------------------------------------------------------------------------*/ +typedef struct sSirFTPreAuthRsp { + uint16_t messageType; /* eWNI_SME_FT_PRE_AUTH_RSP */ + uint16_t length; + uint8_t smeSessionId; + tSirMacAddr preAuthbssId; /* BSSID to preauth to */ + tSirRetStatus status; + uint16_t ft_ies_length; + uint8_t ft_ies[MAX_FTIE_SIZE]; + uint16_t ric_ies_length; + uint8_t ric_ies[MAX_FTIE_SIZE]; +} tSirFTPreAuthRsp, *tpSirFTPreAuthRsp; + +/*-------------------------------------------------------------------------- + FT Pre Auth Rsp Key SME<->PE + ------------------------------------------------------------------------*/ +typedef struct sSirFTUpdateKeyInfo { + uint16_t messageType; + uint16_t length; + uint32_t smeSessionId; + struct qdf_mac_addr bssid; + tSirKeyMaterial keyMaterial; +} tSirFTUpdateKeyInfo, *tpSirFTUpdateKeyInfo; + +/*-------------------------------------------------------------------------- + FT Pre Auth Rsp Key SME<->PE + ------------------------------------------------------------------------*/ +typedef struct sSirFTPreAuthKeyInfo { + uint8_t extSetStaKeyParamValid; /* Ext Bss Config Msg if set */ + /* SetStaKeyParams for ext bss msg */ + tLimMlmSetKeysReq extSetStaKeyParam; +} tSirFTPreAuthKeyInfo, *tpSirFTPreAuthKeyInfo; + +/*------------------------------------------------------------------------- + Global FT Information + ------------------------------------------------------------------------*/ +typedef struct sFTPEContext { + tpSirFTPreAuthReq pFTPreAuthReq; /* Saved FT Pre Auth Req */ + tSirRetStatus ftPreAuthStatus; + uint16_t saved_auth_rsp_length; + uint8_t saved_auth_rsp[MAX_FTIE_SIZE]; + tSirFTPreAuthKeyInfo PreAuthKeyInfo; + /* Items created for the new FT, session */ + void *pAddBssReq; /* Save add bss req */ + void *pAddStaReq; /*Save add sta req */ + uint32_t peSessionId; + uint32_t smeSessionId; + + /* This flag is required to indicate on which session the preauth + * has taken place, since the auth reponse for preauth will come + * for a new BSSID for which there is no session yet. This flag + * will be used to extract the session from the session preauth + * has been initiated + */ + bool ftPreAuthSession; +} tftPEContext, *tpftPEContext; + +#endif /* __LIMFTDEFS_H__ */ diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/include/lim_global.h b/drivers/staging/qcacld-3.0/core/mac/src/pe/include/lim_global.h new file mode 100644 index 0000000000000000000000000000000000000000..02ef242dd314cd58965b6fb3ea24d0fec4a898c0 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/include/lim_global.h @@ -0,0 +1,653 @@ +/* + * Copyright (c) 2011-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * + * This file lim_global.h contains the definitions exported by + * LIM module. + * Author: Chandra Modumudi + * Date: 02/11/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + * + */ +#ifndef __LIM_GLOBAL_H +#define __LIM_GLOBAL_H + +#include "wni_api.h" +#include "sir_api.h" +#include "sir_mac_prot_def.h" +#include "sir_mac_prop_exts.h" +#include "sir_common.h" +#include "sir_debug.h" +#include "wni_cfg.h" +#include "csr_api.h" +#include "sap_api.h" +#include "dot11f.h" +#include "wma_if.h" + +/* Deferred Message Queue Length */ +#define MAX_DEFERRED_QUEUE_LEN 80 + +/* Maximum number of PS - TIM's to be sent with out wakeup from STA */ +#define LIM_TIM_WAIT_COUNT_FACTOR 5 + +/* + * Use this count if (LIM_TIM_WAIT_FACTOR * ListenInterval) + * is less than LIM_MIN_TIM_WAIT_CNT + */ +#define LIM_MIN_TIM_WAIT_COUNT 50 + +#define GET_TIM_WAIT_COUNT(LIntrvl) \ + ((LIntrvl * LIM_TIM_WAIT_COUNT_FACTOR) > LIM_MIN_TIM_WAIT_COUNT ? \ + (LIntrvl * LIM_TIM_WAIT_COUNT_FACTOR) : LIM_MIN_TIM_WAIT_COUNT) + +#define LIM_MAX_CSA_IE_UPDATES (5) + +/* enums exported by LIM are as follows */ + +/*System role definition */ +typedef enum eLimSystemRole { + eLIM_UNKNOWN_ROLE, + eLIM_AP_ROLE, + eLIM_STA_IN_IBSS_ROLE, + eLIM_STA_ROLE, + eLIM_P2P_DEVICE_ROLE, + eLIM_P2P_DEVICE_GO, + eLIM_P2P_DEVICE_CLIENT, + eLIM_NDI_ROLE +} tLimSystemRole; + +/* + * SME state definition accessible across all Sirius modules. + * AP only states are LIM_SME_CHANNEL_SCAN_STATE & + * LIM_SME_NORMAL_CHANNEL_SCAN_STATE. + * Note that these states may also be present in STA + * side too when DFS support is present for a STA in IBSS mode. + */ +typedef enum eLimSmeStates { + eLIM_SME_OFFLINE_STATE, + eLIM_SME_IDLE_STATE, + eLIM_SME_SUSPEND_STATE, + eLIM_SME_WT_SCAN_STATE, + eLIM_SME_WT_JOIN_STATE, + eLIM_SME_WT_AUTH_STATE, + eLIM_SME_WT_ASSOC_STATE, + eLIM_SME_WT_REASSOC_STATE, + eLIM_SME_WT_REASSOC_LINK_FAIL_STATE, + eLIM_SME_JOIN_FAILURE_STATE, + eLIM_SME_ASSOCIATED_STATE, + eLIM_SME_REASSOCIATED_STATE, + eLIM_SME_LINK_EST_STATE, + eLIM_SME_LINK_EST_WT_SCAN_STATE, + eLIM_SME_WT_PRE_AUTH_STATE, + eLIM_SME_WT_DISASSOC_STATE, + eLIM_SME_WT_DEAUTH_STATE, + eLIM_SME_WT_START_BSS_STATE, + eLIM_SME_WT_STOP_BSS_STATE, + eLIM_SME_NORMAL_STATE, + eLIM_SME_CHANNEL_SCAN_STATE, + eLIM_SME_NORMAL_CHANNEL_SCAN_STATE +} tLimSmeStates; + +/* + * MLM state definition. + * While these states are present on AP too when it is + * STA mode, per-STA MLM state exclusive to AP is: + * eLIM_MLM_WT_AUTH_FRAME3. + */ +typedef enum eLimMlmStates { + eLIM_MLM_OFFLINE_STATE, + eLIM_MLM_IDLE_STATE, + eLIM_MLM_WT_PROBE_RESP_STATE, + eLIM_MLM_PASSIVE_SCAN_STATE, + eLIM_MLM_WT_JOIN_BEACON_STATE, + eLIM_MLM_JOINED_STATE, + eLIM_MLM_BSS_STARTED_STATE, + eLIM_MLM_WT_AUTH_FRAME2_STATE, + eLIM_MLM_WT_AUTH_FRAME3_STATE, + eLIM_MLM_WT_AUTH_FRAME4_STATE, + eLIM_MLM_AUTH_RSP_TIMEOUT_STATE, + eLIM_MLM_AUTHENTICATED_STATE, + eLIM_MLM_WT_ASSOC_RSP_STATE, + eLIM_MLM_WT_REASSOC_RSP_STATE, + eLIM_MLM_ASSOCIATED_STATE, + eLIM_MLM_REASSOCIATED_STATE, + eLIM_MLM_LINK_ESTABLISHED_STATE, + eLIM_MLM_WT_ASSOC_CNF_STATE, + eLIM_MLM_LEARN_STATE, + eLIM_MLM_WT_ADD_BSS_RSP_STATE, + eLIM_MLM_WT_DEL_BSS_RSP_STATE, + eLIM_MLM_WT_ADD_BSS_RSP_ASSOC_STATE, + eLIM_MLM_WT_ADD_BSS_RSP_REASSOC_STATE, + eLIM_MLM_WT_ADD_BSS_RSP_PREASSOC_STATE, + eLIM_MLM_WT_ADD_STA_RSP_STATE, + eLIM_MLM_WT_DEL_STA_RSP_STATE, + /* + * MLM goes to this state when LIM initiates DELETE_STA + * as processing of Assoc req because the entry already exists. + * LIM comes out of this state when DELETE_STA response from + * HAL is received. LIM needs to maintain this state so that ADD_STA + * can be issued while processing DELETE_STA response from HAL. + */ + eLIM_MLM_WT_ASSOC_DEL_STA_RSP_STATE, + eLIM_MLM_WT_SET_BSS_KEY_STATE, + eLIM_MLM_WT_SET_STA_KEY_STATE, + eLIM_MLM_WT_SET_STA_BCASTKEY_STATE, + eLIM_MLM_WT_SET_MIMOPS_STATE, + eLIM_MLM_WT_ADD_BSS_RSP_FT_REASSOC_STATE, + eLIM_MLM_WT_FT_REASSOC_RSP_STATE, + eLIM_MLM_P2P_LISTEN_STATE, +} tLimMlmStates; + +/* 11h channel quiet states */ + +/* + * This enum indicates in which state the device is in + * when it receives quiet element in beacon or probe-response. + * The default quiet state of the device is always INIT + * eLIM_QUIET_BEGIN - When Quiet period is started + * eLIM_QUIET_CHANGED - When Quiet period is updated + * eLIM_QUIET_RUNNING - Between two successive Quiet updates + * eLIM_QUIET_END - When quiet period ends + */ +typedef enum eLimQuietStates { + eLIM_QUIET_INIT, + eLIM_QUIET_BEGIN, + eLIM_QUIET_CHANGED, + eLIM_QUIET_RUNNING, + eLIM_QUIET_END +} tLimQuietStates; + +/* 11h channel switch states */ + +/* + * This enum indicates in which state the channel-swith + * is presently operating. + * eLIM_11H_CHANSW_INIT - Default state + * eLIM_11H_CHANSW_RUNNING - When channel switch is running + * eLIM_11H_CHANSW_END - After channel switch is complete + */ +typedef enum eLimDot11hChanSwStates { + eLIM_11H_CHANSW_INIT, + eLIM_11H_CHANSW_RUNNING, + eLIM_11H_CHANSW_END +} tLimDot11hChanSwStates; + + +/* WLAN_SUSPEND_LINK Related */ +typedef void (*SUSPEND_RESUME_LINK_CALLBACK)(tpAniSirGlobal pMac, + QDF_STATUS status, + uint32_t *data); + +/* LIM to HAL SCAN Management Message Interface states */ +typedef enum eLimHalScanState { + eLIM_HAL_IDLE_SCAN_STATE, + eLIM_HAL_INIT_SCAN_WAIT_STATE, + eLIM_HAL_START_SCAN_WAIT_STATE, + eLIM_HAL_END_SCAN_WAIT_STATE, + eLIM_HAL_FINISH_SCAN_WAIT_STATE, + eLIM_HAL_INIT_LEARN_WAIT_STATE, + eLIM_HAL_START_LEARN_WAIT_STATE, + eLIM_HAL_END_LEARN_WAIT_STATE, + eLIM_HAL_FINISH_LEARN_WAIT_STATE, + eLIM_HAL_SCANNING_STATE, +/* WLAN_SUSPEND_LINK Related */ + eLIM_HAL_SUSPEND_LINK_WAIT_STATE, + eLIM_HAL_SUSPEND_LINK_STATE, + eLIM_HAL_RESUME_LINK_WAIT_STATE, +/* end WLAN_SUSPEND_LINK Related */ +} tLimLimHalScanState; + +/* MLM Req/Cnf structure definitions */ +typedef struct sLimMlmAuthReq { + tSirMacAddr peerMacAddr; + tAniAuthType authType; + uint32_t authFailureTimeout; + uint8_t sessionId; +} tLimMlmAuthReq, *tpLimMlmAuthReq; + +typedef struct sLimMlmJoinReq { + uint32_t joinFailureTimeout; + tSirMacRateSet operationalRateSet; + uint8_t sessionId; + tSirBssDescription bssDescription; + /* + * WARNING: Pls make bssDescription as last variable in struct + * tLimMlmJoinReq as it has ieFields followed after this bss + * description. Adding a variable after this corrupts the ieFields + */ +} tLimMlmJoinReq, *tpLimMlmJoinReq; + +typedef struct sLimMlmScanReq { + tSirBssType bssType; + tSirMacAddr bssId; + tSirMacSSid ssId[SIR_SCAN_MAX_NUM_SSID]; + tSirScanType scanType; + uint32_t minChannelTime; + uint32_t maxChannelTime; + uint32_t dot11mode; + /* Number of SSIDs to scan(send Probe request) */ + uint8_t numSsid; + + bool p2pSearch; + uint16_t uIEFieldLen; + uint16_t uIEFieldOffset; + + uint8_t sessionId; + /* channelList MUST be the last field of this structure */ + tSirChannelList channelList; + /*----------------------------- + tLimMlmScanReq.... + ----------------------------- + uIEFiledLen + ----------------------------- + uIEFiledOffset ----+ + ----------------------------- | + channelList.numChannels | + ----------------------------- | + ... variable size up to | + channelNumber[numChannels-1] | + This can be zero, if | + numChannel is zero. | + ----------------------------- <--+ + ... variable size uIEFiled + up to uIEFieldLen (can be 0) + -----------------------------*/ +} tLimMlmScanReq, *tpLimMlmScanReq; + +typedef struct tLimScanResultNode tLimScanResultNode; +struct tLimScanResultNode { + tLimScanResultNode *next; + tSirBssDescription bssDescription; +}; + +#ifdef FEATURE_OEM_DATA_SUPPORT + +/* OEM Data related structure definitions */ +typedef struct sLimMlmOemDataReq { + struct qdf_mac_addr selfMacAddr; + uint32_t data_len; + uint8_t *data; +} tLimMlmOemDataReq, *tpLimMlmOemDataReq; + +typedef struct sLimMlmOemDataRsp { + bool target_rsp; + uint32_t rsp_len; + uint8_t *oem_data_rsp; +} tLimMlmOemDataRsp, *tpLimMlmOemDataRsp; +#endif + +/* Pre-authentication structure definition */ +typedef struct tLimPreAuthNode { + struct tLimPreAuthNode *next; + tSirMacAddr peerMacAddr; + tAniAuthType authType; + tLimMlmStates mlmState; + uint8_t authNodeIdx; + uint8_t challengeText[SIR_MAC_AUTH_CHALLENGE_LENGTH]; + uint8_t fTimerStarted:1; + uint8_t fSeen:1; + uint8_t fFree:1; + uint8_t rsvd:5; + TX_TIMER timer; + uint16_t seq_num; + unsigned long timestamp; +} tLimPreAuthNode, *tpLimPreAuthNode; + +/* Pre-authentication table definition */ +typedef struct tLimPreAuthTable { + uint32_t numEntry; + tLimPreAuthNode **pTable; +} tLimPreAuthTable, *tpLimPreAuthTable; + +/* / Per STA context structure definition */ +typedef struct sLimMlmStaContext { + tLimMlmStates mlmState; + tAniAuthType authType; + uint16_t listenInterval; + tSirMacCapabilityInfo capabilityInfo; + tSirMacPropRateSet propRateSet; + tSirMacReasonCodes disassocReason; + uint16_t cleanupTrigger; + + tSirResultCodes resultCode; + uint16_t protStatusCode; + + uint8_t subType:1; /* Indicates ASSOC (0) or REASSOC (1) */ + uint8_t updateContext:1; + uint8_t schClean:1; + /* 802.11n HT Capability in Station: Enabled 1 or DIsabled 0 */ + uint8_t htCapability:1; + uint8_t vhtCapability:1; +} tLimMlmStaContext, *tpLimMlmStaContext; + +/* Structure definition to hold deferred messages queue parameters */ +typedef struct sLimDeferredMsgQParams { + tSirMsgQ deferredQueue[MAX_DEFERRED_QUEUE_LEN]; + uint16_t size; + uint16_t read; + uint16_t write; +} tLimDeferredMsgQParams, *tpLimDeferredMsgQParams; + +typedef struct sCfgProtection { + uint32_t overlapFromlla:1; + uint32_t overlapFromllb:1; + uint32_t overlapFromllg:1; + uint32_t overlapHt20:1; + uint32_t overlapNonGf:1; + uint32_t overlapLsigTxop:1; + uint32_t overlapRifs:1; + uint32_t overlapOBSS:1; /* added for obss */ + uint32_t fromlla:1; + uint32_t fromllb:1; + uint32_t fromllg:1; + uint32_t ht20:1; + uint32_t nonGf:1; + uint32_t lsigTxop:1; + uint32_t rifs:1; + uint32_t obss:1; /* added for Obss */ +} tCfgProtection, *tpCfgProtection; + +typedef enum eLimProtStaCacheType { + eLIM_PROT_STA_CACHE_TYPE_INVALID, + eLIM_PROT_STA_CACHE_TYPE_llB, + eLIM_PROT_STA_CACHE_TYPE_llG, + eLIM_PROT_STA_CACHE_TYPE_HT20 +} tLimProtStaCacheType; + +typedef struct sCacheParams { + uint8_t active; + tSirMacAddr addr; + tLimProtStaCacheType protStaCacheType; + +} tCacheParams, *tpCacheParams; + +#define LIM_PROT_STA_OVERLAP_CACHE_SIZE HAL_NUM_ASSOC_STA +#define LIM_PROT_STA_CACHE_SIZE HAL_NUM_ASSOC_STA + +typedef struct sLimProtStaParams { + uint8_t numSta; + uint8_t protectionEnabled; +} tLimProtStaParams, *tpLimProtStaParams; + +typedef struct sLimNoShortParams { + uint8_t numNonShortPreambleSta; + tCacheParams staNoShortCache[LIM_PROT_STA_CACHE_SIZE]; +} tLimNoShortParams, *tpLimNoShortParams; + +typedef struct sLimNoShortSlotParams { + uint8_t numNonShortSlotSta; + tCacheParams staNoShortSlotCache[LIM_PROT_STA_CACHE_SIZE]; +} tLimNoShortSlotParams, *tpLimNoShortSlotParams; + +typedef struct tLimIbssPeerNode tLimIbssPeerNode; +struct tLimIbssPeerNode { + tLimIbssPeerNode *next; + tSirMacAddr peerMacAddr; + uint8_t extendedRatesPresent:1; + uint8_t edcaPresent:1; + uint8_t wmeEdcaPresent:1; + uint8_t wmeInfoPresent:1; + uint8_t htCapable:1; + uint8_t vhtCapable:1; + uint8_t rsvd:2; + uint8_t htSecondaryChannelOffset; + tSirMacCapabilityInfo capabilityInfo; + tSirMacRateSet supportedRates; + tSirMacRateSet extendedRates; + uint8_t supportedMCSSet[SIZE_OF_SUPPORTED_MCS_SET]; + tSirMacEdcaParamSetIE edcaParams; + uint8_t erpIePresent; + + /* HT Capabilities of IBSS Peer */ + uint8_t htGreenfield; + uint8_t htShortGI40Mhz; + uint8_t htShortGI20Mhz; + + /* DSSS/CCK at 40 MHz: Enabled 1 or Disabled */ + uint8_t htDsssCckRate40MHzSupport; + + /* MIMO Power Save */ + tSirMacHTMIMOPowerSaveState htMIMOPSState; + + /* */ + /* A-MPDU Density */ + /* 000 - No restriction */ + /* 001 - 1/8 usec */ + /* 010 - 1/4 usec */ + /* 011 - 1/2 usec */ + /* 100 - 1 usec */ + /* 101 - 2 usec */ + /* 110 - 4 usec */ + /* 111 - 8 usec */ + /* */ + uint8_t htAMpduDensity; + + /* Maximum Rx A-MPDU factor */ + uint8_t htMaxRxAMpduFactor; + + /* Set to 0 for 3839 octets */ + /* Set to 1 for 7935 octets */ + uint8_t htMaxAmsduLength; + + /* */ + /* Recommended Tx Width Set */ + /* 0 - use 20 MHz channel (control channel) */ + /* 1 - use 40 Mhz channel */ + /* */ + uint8_t htSupportedChannelWidthSet; + + uint8_t htLdpcCapable; + + uint8_t beaconHBCount; + uint8_t heartbeatFailure; + + uint8_t *beacon; /* Hold beacon to be sent to HDD/CSR */ + uint16_t beaconLen; + + tDot11fIEVHTCaps VHTCaps; + uint8_t vhtSupportedChannelWidthSet; + uint8_t vhtBeamFormerCapable; + /* + * Peer Atim Info + */ + uint8_t atimIePresent; + uint32_t peerAtimWindowLength; +}; + +/* Enums used for channel switching. */ +typedef enum eLimChannelSwitchState { + eLIM_CHANNEL_SWITCH_IDLE, + eLIM_CHANNEL_SWITCH_PRIMARY_ONLY, + eLIM_CHANNEL_SWITCH_PRIMARY_AND_SECONDARY +} tLimChannelSwitchState; + +/* Channel Switch Info */ +typedef struct sLimChannelSwitchInfo { + tLimChannelSwitchState state; + uint8_t primaryChannel; + uint8_t ch_center_freq_seg0; + uint8_t ch_center_freq_seg1; + uint8_t sec_ch_offset; + enum phy_ch_width ch_width; + int8_t switchCount; + uint32_t switchTimeoutValue; + uint8_t switchMode; +} tLimChannelSwitchInfo, *tpLimChannelSwitchInfo; + +typedef struct sLimOperatingModeInfo { + uint8_t present; + uint8_t chanWidth:2; + uint8_t reserved:2; + uint8_t rxNSS:3; + uint8_t rxNSSType:1; +} tLimOperatingModeInfo, *tpLimOperatingModeInfo; + +typedef struct sLimWiderBWChannelSwitch { + uint8_t newChanWidth; + uint8_t newCenterChanFreq0; + uint8_t newCenterChanFreq1; +} tLimWiderBWChannelSwitchInfo, *tpLimWiderBWChannelSwitchInfo; + +/* Enums used when stopping the Tx. */ +typedef enum eLimQuietTxMode { + /* Stop/resume transmission of all stations,Uses the global flag */ + eLIM_TX_ALL = 0, + /* + * Stops/resumes the transmission of specific stations identified + * by staId. + */ + eLIM_TX_STA, + /* Stops/resumes the transmission of all the packets in BSS */ + eLIM_TX_BSS, + /* + * Stops/resumes the transmission of all packets except beacons in BSS + * This is used when radar is detected in the current operating channel. + * Beacon has to be sent to notify the stations associated about the + * scheduled channel switch + */ + eLIM_TX_BSS_BUT_BEACON +} tLimQuietTxMode; + +typedef enum eLimControlTx { + eLIM_RESUME_TX = 0, + eLIM_STOP_TX +} tLimControlTx; + +/* -------------------------------------------------------------------- */ + +typedef struct sLimTspecInfo { + /* 0==free, else used */ + uint8_t inuse; + /* index in list */ + uint8_t idx; + tSirMacAddr staAddr; + uint16_t assocId; + tSirMacTspecIE tspec; + /* number of Tclas elements */ + uint8_t numTclas; + tSirTclasInfo tclasInfo[SIR_MAC_TCLASIE_MAXNUM]; + uint8_t tclasProc; + /* tclassProc is valid only if this is set to 1. */ + uint8_t tclasProcPresent:1; +} qdf_packed tLimTspecInfo, *tpLimTspecInfo; + +typedef struct sLimAdmitPolicyInfo { + /* admit control policy type */ + uint8_t type; + /* oversubscription factor : 0 means nothing is allowed */ + uint8_t bw_factor; + /* valid only when 'type' is set BW_FACTOR */ +} tLimAdmitPolicyInfo, *tpLimAdmitPolicyInfo; + +typedef enum eLimWscEnrollState { + eLIM_WSC_ENROLL_NOOP, + eLIM_WSC_ENROLL_BEGIN, + eLIM_WSC_ENROLL_IN_PROGRESS, + eLIM_WSC_ENROLL_END +} tLimWscEnrollState; + +#define WSC_PASSWD_ID_PUSH_BUTTON (0x0004) + +typedef struct sLimWscIeInfo { + bool apSetupLocked; + bool selectedRegistrar; + uint16_t selectedRegistrarConfigMethods; + tLimWscEnrollState wscEnrollmentState; + tLimWscEnrollState probeRespWscEnrollmentState; + uint8_t reqType; + uint8_t respType; +} tLimWscIeInfo, *tpLimWscIeInfo; + +/* maximum number of tspec's supported */ +#define LIM_NUM_TSPEC_MAX 15 + +/* structure to hold all 11h specific data */ +typedef struct sLimSpecMgmtInfo { + tLimQuietStates quietState; + uint32_t quietCount; + /* This is in units of system TICKS */ + uint32_t quietDuration; + /* This is in units of TU, for over the air transmission */ + uint32_t quietDuration_TU; + /* After this timeout, actual quiet starts */ + uint32_t quietTimeoutValue; + /* Used on AP, if quiet is enabled during learning */ + bool fQuietEnabled; + tLimDot11hChanSwStates dot11hChanSwState; + /* Radar detected in cur oper chan on AP */ + bool fRadarDetCurOperChan; + /* Whether radar interrupt has been configured */ + bool fRadarIntrConfigured; +} tLimSpecMgmtInfo, *tpLimSpecMgmtInfo; + +#ifdef FEATURE_WLAN_TDLS +/* + * Peer info needed for TDLS setup.. + */ +typedef struct tLimTDLSPeerSta { + struct tLimTDLSPeerSta *next; + uint8_t dialog; + tSirMacAddr peerMac; + tSirMacCapabilityInfo capabilityInfo; + tSirMacRateSet supportedRates; + tSirMacRateSet extendedRates; + tSirMacQosCapabilityStaIE qosCaps; + tSirMacEdcaParamSetIE edcaParams; + uint8_t mcsSet[SIZE_OF_SUPPORTED_MCS_SET]; + uint8_t tdls_bIsResponder; + /* HT Capabilties */ + tDot11fIEHTCaps tdlsPeerHTCaps; + tDot11fIEExtCap tdlsPeerExtCaps; + uint8_t tdls_flags; + uint8_t tdls_link_state; + uint8_t tdls_prev_link_state; + uint8_t tdls_sessionId; + uint8_t ExtRatesPresent; + TX_TIMER gLimTdlsLinkSetupRspTimeoutTimer; + TX_TIMER gLimTdlsLinkSetupCnfTimeoutTimer; +} tLimTdlsLinkSetupPeer, *tpLimTdlsLinkSetupPeer; + +typedef struct tLimTdlsLinkSetupInfo { + tLimTdlsLinkSetupPeer *tdlsLinkSetupList; + uint8_t num_tdls_peers; + uint8_t tdls_flags; + uint8_t tdls_state; + uint8_t tdls_prev_state; +} tLimTdlsLinkSetupInfo, *tpLimTdlsLinkSetupInfo; + +typedef enum tdlsLinkMode { + TDLS_LINK_MODE_BG, + TDLS_LINK_MODE_N, + TDLS_LINK_MODE_AC, + TDLS_LINK_MODE_NONE +} eLimTdlsLinkMode; +#endif /* FEATURE_WLAN_TDLS */ + +#endif diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/include/lim_session.h b/drivers/staging/qcacld-3.0/core/mac/src/pe/include/lim_session.h new file mode 100644 index 0000000000000000000000000000000000000000..6472fce557c0e06d90f8587281ca044554acda1f --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/include/lim_session.h @@ -0,0 +1,625 @@ +/* + * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#if !defined(__LIM_SESSION_H) +#define __LIM_SESSION_H + +/**========================================================================= + + \file lim_session.h + + \brief prototype for lim Session related APIs + + \author Sunit Bhatia + + ========================================================================*/ + +/* Powersave Offload Implementation */ +typedef enum ePowersaveState { + PMM_FULL_POWER, + PMM_POWER_SAVE +} tPowersaveState; + +/* Master Structure: This will be part of PE Session Entry */ +typedef struct sPowersaveoffloadInfo { + tPowersaveState psstate; + uint8_t bcnmiss; +} tPowersaveoffloadInfo, tpPowersaveoffloadInfo; + +#ifdef WLAN_FEATURE_11W +typedef struct tagComebackTimerInfo { + tpAniSirGlobal pMac; + uint8_t sessionID; + tLimMlmStates limPrevMlmState; /* Previous MLM State */ + tLimSmeStates limMlmState; /* MLM State */ +} tComebackTimerInfo; +#endif /* WLAN_FEATURE_11W */ +/*-------------------------------------------------------------------------- + Include Files + ------------------------------------------------------------------------*/ + +/*-------------------------------------------------------------------------- + Preprocessor definitions and constants + ------------------------------------------------------------------------*/ +/* Maximum Number of WEP KEYS */ +#define MAX_WEP_KEYS 4 + +/* Maximum allowable size of a beacon frame */ +#define SCH_MAX_BEACON_SIZE 512 + +#define SCH_MAX_PROBE_RESP_SIZE 512 +#define SCH_PROTECTION_RESET_TIME 4000 + +/*-------------------------------------------------------------------------- + Type declarations + ------------------------------------------------------------------------*/ +typedef struct { + tSirMacBeaconInterval beaconInterval; + uint8_t fShortPreamble; + uint8_t llaCoexist; + uint8_t llbCoexist; + uint8_t llgCoexist; + uint8_t ht20Coexist; + uint8_t llnNonGFCoexist; + uint8_t fRIFSMode; + uint8_t fLsigTXOPProtectionFullSupport; + uint8_t gHTObssMode; +} tBeaconParams, *tpBeaconParams; + +typedef struct join_params { + uint16_t prot_status_code; + uint16_t pe_session_id; + tSirResultCodes result_code; +} join_params; + +typedef struct sPESession /* Added to Support BT-AMP */ +{ + /* To check session table is in use or free */ + uint8_t available; + uint16_t peSessionId; + uint8_t smeSessionId; + uint16_t transactionId; + + /* In AP role: BSSID and selfMacAddr will be the same. */ + /* In STA role: they will be different */ + tSirMacAddr bssId; + tSirMacAddr selfMacAddr; + tSirMacSSid ssId; + uint8_t bssIdx; + uint8_t valid; + tLimMlmStates limMlmState; /* MLM State */ + tLimMlmStates limPrevMlmState; /* Previous MLM State */ + tLimSmeStates limSmeState; /* SME State */ + tLimSmeStates limPrevSmeState; /* Previous SME State */ + tLimSystemRole limSystemRole; + tSirBssType bssType; + uint8_t operMode; /* AP - 0; STA - 1 ; */ + tSirNwType nwType; + tpSirSmeStartBssReq pLimStartBssReq; /* handle to smestart bss req */ + tpSirSmeJoinReq pLimJoinReq; /* handle to sme join req */ + tpSirSmeJoinReq pLimReAssocReq; /* handle to sme reassoc req */ + tpLimMlmJoinReq pLimMlmJoinReq; /* handle to MLM join Req */ + void *pLimMlmReassocRetryReq; /* keep reasoc req for retry */ + void *pLimMlmReassocReq; /* handle to MLM reassoc Req */ + uint16_t channelChangeReasonCode; + uint8_t dot11mode; + uint8_t htCapability; + /* Supported Channel Width Set: 0-20MHz 1 - 40MHz */ + uint8_t htSupportedChannelWidthSet; + /* Recommended Tx Width Set + * 0 - use 20 MHz channel (control channel) + * 1 - use channel width enabled under Supported Channel Width Set + */ + uint8_t htRecommendedTxWidthSet; + /* Identifies the 40 MHz extension channel */ + ePhyChanBondState htSecondaryChannelOffset; + tSirRFBand limRFBand; + uint8_t limIbssActive; /* TO SUPPORT CONCURRENCY */ + + /* These global varibales moved to session Table to support BT-AMP : Oct 9th review */ + tAniAuthType limCurrentAuthType; + uint16_t limCurrentBssCaps; + uint8_t limCurrentBssQosCaps; + uint16_t limCurrentBssPropCap; + uint8_t limSentCapsChangeNtf; + uint16_t limAID; + + /* Parameters For Reassociation */ + tSirMacAddr limReAssocbssId; + tSirMacChanNum limReassocChannelId; + /* CB paramaters required/duplicated for Reassoc since re-assoc mantains its own params in lim */ + uint8_t reAssocHtSupportedChannelWidthSet; + uint8_t reAssocHtRecommendedTxWidthSet; + ePhyChanBondState reAssocHtSecondaryChannelOffset; + tSirMacSSid limReassocSSID; + uint16_t limReassocBssCaps; + uint8_t limReassocBssQosCaps; + uint16_t limReassocBssPropCap; + + /* Assoc or ReAssoc Response Data/Frame */ + void *limAssocResponseData; + + /** BSS Table parameters **/ + + /* + * staId: Start BSS: this is the Sta Id for the BSS. + * Join: this is the selfStaId + * In both cases above, the peer STA ID wll be stored in dph hash table. + */ + uint16_t staId; + uint16_t statypeForBss; /* to know session is for PEER or SELF */ + uint8_t shortSlotTimeSupported; + uint8_t dtimPeriod; + tSirMacRateSet rateSet; + tSirMacRateSet extRateSet; + tSirMacHTOperatingMode htOperMode; + uint8_t currentOperChannel; + uint8_t currentReqChannel; + uint8_t LimRxedBeaconCntDuringHB; + + /* Time stamp of the last beacon received from the BSS to which STA is connected. */ + uint64_t lastBeaconTimeStamp; + /* RX Beacon count for the current BSS to which STA is connected. */ + uint32_t currentBssBeaconCnt; + uint8_t lastBeaconDtimCount; + uint8_t lastBeaconDtimPeriod; + + uint32_t bcnLen; + uint8_t *beacon; /* Used to store last beacon / probe response before assoc. */ + + uint32_t assocReqLen; + uint8_t *assocReq; /* Used to store association request frame sent out while associating. */ + + uint32_t assocRspLen; + uint8_t *assocRsp; /* Used to store association response received while associating */ + tAniSirDph dph; + void **parsedAssocReq; /* Used to store parsed assoc req from various requesting station */ + uint32_t RICDataLen; /* Used to store the Ric data received in the assoc response */ + uint8_t *ricData; +#ifdef FEATURE_WLAN_ESE + uint32_t tspecLen; /* Used to store the TSPEC IEs received in the assoc response */ + uint8_t *tspecIes; +#endif + uint32_t encryptType; + + bool bTkipCntrMeasActive; /* Used to keep record of TKIP counter measures start/stop */ + + uint8_t gLimProtectionControl; /* used for 11n protection */ + + uint8_t gHTNonGFDevicesPresent; + + /* protection related config cache */ + tCfgProtection cfgProtection; + + /* Number of legacy STAs associated */ + tLimProtStaParams gLim11bParams; + + /* Number of 11A STAs associated */ + tLimProtStaParams gLim11aParams; + + /* Number of non-ht non-legacy STAs associated */ + tLimProtStaParams gLim11gParams; + + /* Number of nonGf STA associated */ + tLimProtStaParams gLimNonGfParams; + + /* Number of HT 20 STAs associated */ + tLimProtStaParams gLimHt20Params; + + /* Number of Lsig Txop not supported STAs associated */ + tLimProtStaParams gLimLsigTxopParams; + + /* Number of STAs that do not support short preamble */ + tLimNoShortParams gLimNoShortParams; + + /* Number of STAs that do not support short slot time */ + tLimNoShortSlotParams gLimNoShortSlotParams; + + /* OLBC parameters */ + tLimProtStaParams gLimOlbcParams; + + /* OLBC parameters */ + tLimProtStaParams gLimOverlap11gParams; + + tLimProtStaParams gLimOverlap11aParams; + tLimProtStaParams gLimOverlapHt20Params; + tLimProtStaParams gLimOverlapNonGfParams; + + /* cache for each overlap */ + tCacheParams protStaCache[LIM_PROT_STA_CACHE_SIZE]; + + uint8_t privacy; + tAniAuthType authType; + tSirKeyMaterial WEPKeyMaterial[MAX_WEP_KEYS]; + + tDot11fIERSN gStartBssRSNIe; + tDot11fIEWPA gStartBssWPAIe; + tSirAPWPSIEs APWPSIEs; + uint8_t apUapsdEnable; + tSirWPSPBCSession *pAPWPSPBCSession; + uint32_t DefProbeRspIeBitmap[8]; + uint32_t proxyProbeRspEn; + tDot11fProbeResponse probeRespFrame; + uint8_t ssidHidden; + bool fwdWPSPBCProbeReq; + uint8_t wps_state; + bool wps_registration; + + uint8_t limQosEnabled:1; /* 11E */ + uint8_t limWmeEnabled:1; /* WME */ + uint8_t limWsmEnabled:1; /* WSM */ + uint8_t limHcfEnabled:1; + uint8_t lim11dEnabled:1; +#ifdef WLAN_FEATURE_11W + uint8_t limRmfEnabled:1; /* 11W */ +#endif + uint32_t lim11hEnable; + + int8_t maxTxPower; /* MIN (Regulatory and local power constraint) */ + enum tQDF_ADAPTER_MODE pePersona; + int8_t txMgmtPower; + tAniBool is11Rconnection; + +#ifdef FEATURE_WLAN_ESE + tAniBool isESEconnection; + tEsePEContext eseContext; +#endif + tAniBool isFastTransitionEnabled; + tAniBool isFastRoamIniFeatureEnabled; + tSirNoAParam p2pNoA; + tSirP2PNoaAttr p2pGoPsUpdate; + uint32_t defaultAuthFailureTimeout; + tSirP2PNoaStart p2pGoPsNoaStartInd; + + /* EDCA QoS parameters + * gLimEdcaParams - These EDCA parameters are used locally on AP or STA. + * If STA, then these are values taken from the Assoc Rsp when associating, + * or Beacons/Probe Response after association. If AP, then these are + * values originally set locally on AP. + * + * gLimEdcaParamsBC - These EDCA parameters are use by AP to broadcast + * to other STATIONs in the BSS. + * + * gLimEdcaParamsActive: These EDCA parameters are what's actively being + * used on station. Specific AC values may be downgraded depending on + * admission control for that particular AC. + */ + tSirMacEdcaParamRecord gLimEdcaParams[MAX_NUM_AC]; /* used locally */ + tSirMacEdcaParamRecord gLimEdcaParamsBC[MAX_NUM_AC]; /* used for broadcast */ + tSirMacEdcaParamRecord gLimEdcaParamsActive[MAX_NUM_AC]; + + uint8_t gLimEdcaParamSetCount; + + tBeaconParams beaconParams; + uint8_t vhtCapability; + tLimOperatingModeInfo gLimOperatingMode; + uint8_t vhtCapabilityPresentInBeacon; + uint8_t ch_center_freq_seg0; + enum phy_ch_width ch_width; + uint8_t ch_center_freq_seg1; + uint8_t enableVhtpAid; + uint8_t enableVhtGid; + tLimWiderBWChannelSwitchInfo gLimWiderBWChannelSwitch; + uint8_t enableAmpduPs; + uint8_t enableHtSmps; + uint8_t htSmpsvalue; + bool send_smps_action; + uint8_t spectrumMgtEnabled; + /* *********************11H related**************************** */ + tLimSpecMgmtInfo gLimSpecMgmt; + /* CB Primary/Secondary Channel Switch Info */ + tLimChannelSwitchInfo gLimChannelSwitch; + /* *********************End 11H related**************************** */ + + /*Flag to Track Status/Indicate HBFailure on this session */ + bool LimHBFailureStatus; + uint32_t gLimPhyMode; + uint8_t amsduSupportedInBA; + uint8_t txLdpcIniFeatureEnabled; + /** + * Following is the place holder for free peer index pool. + * A non-zero value indicates that peer index is available + * for assignment. + */ + uint8_t *gpLimPeerIdxpool; + uint8_t freePeerIdxHead; + uint8_t freePeerIdxTail; + uint16_t gLimNumOfCurrentSTAs; +#ifdef FEATURE_WLAN_TDLS + /* TDLS parameters to check whether TDLS + * and TDLS channel switch is allowed in the + * AP network + */ + uint32_t peerAIDBitmap[2]; + bool tdls_prohibited; + bool tdls_chan_swit_prohibited; +#endif + bool fWaitForProbeRsp; + bool fIgnoreCapsChange; + bool fDeauthReceived; +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM + int8_t rssi; +#endif + uint8_t max_amsdu_num; + uint8_t isCoalesingInIBSSAllowed; + + tSirHTConfig htConfig; + struct sir_vht_config vht_config; + /* + * Place holder for StartBssReq message + * received by SME state machine + */ + uint8_t gLimCurrentBssUapsd; + + /* Used on STA, this is a static UAPSD mask setting + * derived from SME_JOIN_REQ and SME_REASSOC_REQ. If a + * particular AC bit is set, it means the AC is both + * trigger enabled and delivery enabled. + */ + uint8_t gUapsdPerAcBitmask; + + /* Used on STA, this is a dynamic UPASD mask setting + * derived from AddTS Rsp and DelTS frame. If a + * particular AC bit is set, it means AC is trigger + * enabled. + */ + uint8_t gUapsdPerAcTriggerEnableMask; + + /* Used on STA, dynamic UPASD mask setting + * derived from AddTS Rsp and DelTs frame. If + * a particular AC bit is set, it means AC is + * delivery enabled. + */ + uint8_t gUapsdPerAcDeliveryEnableMask; + + /* Flag to skip CSA IE processing when CSA + * offload is enabled. + */ + uint8_t csaOffloadEnable; + + /* Used on STA for AC downgrade. This is a dynamic mask + * setting which keep tracks of ACs being admitted. + * If bit is set to 0: That partiular AC is not admitted + * If bit is set to 1: That particular AC is admitted + */ + uint8_t gAcAdmitMask[SIR_MAC_DIRECTION_DIRECT]; + + /* Power Save Off load Parameters */ + tPowersaveoffloadInfo pmmOffloadInfo; + /* SMPS mode */ + uint8_t smpsMode; + + uint8_t chainMask; + + /* Flag to indicate Chan Sw announcement is required */ + uint8_t dfsIncludeChanSwIe; + + /* Flag to indicate Chan Wrapper Element is required */ + uint8_t dfsIncludeChanWrapperIe; + +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH + uint8_t cc_switch_mode; +#endif + + bool isCiscoVendorAP; + + tSirAddIeParams addIeParams; + + uint8_t *pSchProbeRspTemplate; + /* Beginning portion of the beacon frame to be written to TFP */ + uint8_t *pSchBeaconFrameBegin; + /* Trailing portion of the beacon frame to be written to TFP */ + uint8_t *pSchBeaconFrameEnd; + /* Size of the beginning portion */ + uint16_t schBeaconOffsetBegin; + /* Size of the trailing portion */ + uint16_t schBeaconOffsetEnd; + bool isOSENConnection; + /* DSCP to UP mapping for HS 2.0 */ + tSirQosMapSet QosMapSet; + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + bool bRoamSynchInProgress; +#endif + + /* Fast Transition (FT) */ + tftPEContext ftPEContext; + bool isNonRoamReassoc; +#ifdef WLAN_FEATURE_11W + qdf_mc_timer_t pmfComebackTimer; + tComebackTimerInfo pmfComebackTimerInfo; +#endif /* WLAN_FEATURE_11W */ + uint8_t is_key_installed; + /* timer for reseting protection fileds at regular intervals */ + qdf_mc_timer_t protection_fields_reset_timer; + void *mac_ctx; + /* + * variable to store state of various protection struct like + * gLimOlbcParams, gLimOverlap11gParams, gLimOverlapHt20Params etc + */ + uint16_t old_protection_state; + tSirMacAddr prev_ap_bssid; +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE + /* tells if Q2Q IE, from another MDM device in AP MCC mode was recvd */ + bool sap_advertise_avoid_ch_ie; +#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ +#ifdef FEATURE_WLAN_ESE + uint8_t is_ese_version_ie_present; +#endif + uint8_t sap_dot11mc; + bool is_vendor_specific_vhtcaps; + uint8_t vendor_specific_vht_ie_type; + uint8_t vendor_specific_vht_ie_sub_type; + bool vendor_vht_sap; + /* HS 2.0 Indication */ + tDot11fIEhs20vendor_ie hs20vendor_ie; + /* flag to indicate country code in beacon */ + uint8_t country_info_present; + uint8_t nss; + bool add_bss_failed; + /* To hold OBSS Scan IE Parameters */ + struct obss_scanparam obss_ht40_scanparam; + uint8_t vdev_nss; + /* Supported NSS is intersection of self and peer NSS */ + bool supported_nss_1x1; + bool is_ext_caps_present; + uint8_t beacon_tx_rate; + uint8_t *access_policy_vendor_ie; + uint8_t access_policy; + bool ignore_assoc_disallowed; + bool send_p2p_conf_frame; + bool process_ho_fail; + uint8_t deauthmsgcnt; + uint8_t disassocmsgcnt; + bool enable_bcast_probe_rsp; + uint8_t ht_client_cnt; + bool ch_switch_in_progress; +} tPESession, *tpPESession; + +/*------------------------------------------------------------------------- + Function declarations and documenation + ------------------------------------------------------------------------*/ + +/** + * pe_create_session() - creates a new PE session given the BSSID + * + * @pMac: pointer to global adapter context + * @bssid: BSSID of the new session + * @sessionId: session ID is returned here, if session is created. + * @numSta: number of stations + * @bssType: bss type of new session to do conditional memory allocation. + * + * This function returns the session context and the session ID if the session + * corresponding to the passed BSSID is found in the PE session table. + * + * Return: ptr to the session context or NULL if session can not be created. + */ +tpPESession pe_create_session(tpAniSirGlobal pMac, + uint8_t *bssid, + uint8_t *sessionId, + uint16_t numSta, tSirBssType bssType); + +/** + * pe_find_session_by_bssid() - looks up the PE session given the BSSID. + * + * @pMac: pointer to global adapter context + * @bssid: BSSID of the new session + * @sessionId: session ID is returned here, if session is created. + * + * This function returns the session context and the session ID if the session + * corresponding to the given BSSID is found in the PE session table. + * + * Return: pointer to the session context or NULL if session is not found. + */ +tpPESession pe_find_session_by_bssid(tpAniSirGlobal pMac, uint8_t *bssid, + uint8_t *sessionId); + +/** + * pe_find_session_by_bss_idx() - looks up the PE session given the bssIdx. + * + * @pMac: pointer to global adapter context + * @bssIdx: bss index of the session + * + * This function returns the session context if the session + * corresponding to the given bssIdx is found in the PE session table. + * + * Return: pointer to the session context or NULL if session is not found. + */ +tpPESession pe_find_session_by_bss_idx(tpAniSirGlobal pMac, uint8_t bssIdx); + +/** + * pe_find_session_by_peer_sta() - looks up the PE session given the Peer + * Station Address. + * + * @pMac: pointer to global adapter context + * @sa: Peer STA Address of the session + * @sessionId: session ID is returned here, if session is found. + * + * This function returns the session context and the session ID if the session + * corresponding to the given destination address is found in the PE session + * table. + * + * Return: pointer to the session context or NULL if session is not found. + */ +tpPESession pe_find_session_by_peer_sta(tpAniSirGlobal pMac, uint8_t *sa, + uint8_t *sessionId); + +/** + * pe_find_session_by_session_id() - looks up the PE session given the session + * ID. + * + * @pMac: pointer to global adapter context + * @sessionId: session ID for which session context needs to be looked up. + * + * This function returns the session context if the session corresponding to + * the given session ID is found in the PE session table. + * + * Return: pointer to the session context or NULL if session is not found. + */ +tpPESession pe_find_session_by_session_id(tpAniSirGlobal pMac, + uint8_t sessionId); + +/** + * pe_find_session_by_bssid() - looks up the PE session given staid. + * + * @pMac: pointer to global adapter context + * @staid: StaId of the session + * @sessionId: session ID is returned here, if session is found. + * + * This function returns the session context and the session ID if the session + * corresponding to the given StaId is found in the PE session table. + * + * Return: pointer to the session context or NULL if session is not found. + */ +tpPESession pe_find_session_by_sta_id(tpAniSirGlobal pMac, uint8_t staid, + uint8_t *sessionId); + +/** + * pe_delete_session() - deletes the PE session given the session ID. + * + * @pMac: pointer to global adapter context + * @sessionId: session ID to delete. + * + * Return: void + */ +void pe_delete_session(tpAniSirGlobal pMac, tpPESession psessionEntry); + + +/** + * pe_find_session_by_sme_session_id() - looks up the PE session for given sme + * session id + * @mac_ctx: pointer to global adapter context + * @sme_session_id: sme session id + * + * looks up the PE session for given sme session id + * + * Return: pe session entry for given sme session if found else NULL + */ +tpPESession pe_find_session_by_sme_session_id(tpAniSirGlobal mac_ctx, + uint8_t sme_session_id); +uint8_t pe_get_active_session_count(tpAniSirGlobal mac_ctx); +#endif /* #if !defined( __LIM_SESSION_H ) */ diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/include/lim_trace.h b/drivers/staging/qcacld-3.0/core/mac/src/pe/include/lim_trace.h new file mode 100644 index 0000000000000000000000000000000000000000..dbd4ed714e4f5a639356e0ba93f3f1bab53df4b9 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/include/lim_trace.h @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2013-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/**========================================================================= + + * \file lim_trace.h + + * \brief definition for trace related APIs + + * \author Sunit Bhatia + + ========================================================================*/ + +#ifndef __LIM_TRACE_H +#define __LIM_TRACE_H + +#include "lim_global.h" +#include "mac_trace.h" +#include "qdf_trace.h" +#ifdef LIM_TRACE_RECORD + +#define LIM_TRACE_GET_SSN(data) (((data) >> 16) & 0xff) +#define LIM_TRACE_GET_SUBTYPE(data) (data & 0xff) +#define LIM_TRACE_GET_DEFERRED(data) (data & 0x80000000) +#define LIM_TRACE_GET_DEFRD_OR_DROPPED(data) (data & 0xc0000000) + +#define LIM_MSG_PROCESSED 0 +#define LIM_MSG_DEFERRED 1 +#define LIM_MSG_DROPPED 2 + +#define LIM_TRACE_MAKE_RXMGMT(type, ssn) \ + ((ssn << 16) | (type)) +#define LIM_TRACE_MAKE_RXMSG(msg, action) \ + ((msg) | (action << 30)) + +enum { + TRACE_CODE_MLM_STATE, + TRACE_CODE_SME_STATE, + TRACE_CODE_TX_MGMT, + TRACE_CODE_RX_MGMT, + TRACE_CODE_RX_MGMT_TSF, + TRACE_CODE_TX_COMPLETE, + TRACE_CODE_TX_SME_MSG, + TRACE_CODE_RX_SME_MSG, + TRACE_CODE_TX_WMA_MSG, + TRACE_CODE_RX_WMA_MSG, + TRACE_CODE_TX_LIM_MSG, + TRACE_CODE_RX_LIM_MSG, + TRACE_CODE_TX_CFG_MSG, + TRACE_CODE_RX_CFG_MSG, + TRACE_CODE_RX_MGMT_DROP, + + TRACE_CODE_TIMER_ACTIVATE, + TRACE_CODE_TIMER_DEACTIVATE, + TRACE_CODE_INFO_LOG +}; + +void lim_trace_init(tpAniSirGlobal pMac); +void limTraceReset(tpAniSirGlobal pMac); +void limTraceUpdateMgmtStat(tpAniSirGlobal pMac, uint8_t subtype); +void lim_trace_dumpMgmtStat(tpAniSirGlobal pMac, uint8_t subtype); +uint8_t *lim_trace_get_mlm_state_string(uint32_t mlmState); +uint8_t *lim_trace_get_sme_state_string(uint32_t smeState); +void lim_trace_dump(tpAniSirGlobal pMac, tp_qdf_trace_record pRecord, + uint16_t recIndex); +void mac_trace_msg_tx(tpAniSirGlobal pMac, uint8_t session, uint32_t data); +void mac_trace_msg_rx(tpAniSirGlobal pMac, uint8_t session, uint32_t data); + +void mac_trace_msg_rx_new(tpAniSirGlobal pMac, uint8_t module, uint8_t session, + uint32_t data); +void mac_trace_msg_tx_new(tpAniSirGlobal pMac, uint8_t module, uint8_t session, + uint32_t data); +#endif /* endof LIM_TRACE_RECORD MACRO */ + +#endif diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/include/rrm_api.h b/drivers/staging/qcacld-3.0/core/mac/src/pe/include/rrm_api.h new file mode 100644 index 0000000000000000000000000000000000000000..7f599c3a2ca40543ecbae58dfb490cd84eb3d23b --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/include/rrm_api.h @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2011-2012, 2014-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/**========================================================================= + + \file rrm_api.h + + \brief RRM APIs + + ========================================================================*/ + +/* $Header$ */ + +#ifndef __RRM_API_H__ +#define __RRM_API_H__ + +#define RRM_MIN_TX_PWR_CAP 13 +#define RRM_MAX_TX_PWR_CAP 19 + +#define RRM_BCN_RPT_NO_BSS_INFO 0 +#define RRM_BCN_RPT_MIN_RPT 1 + +uint8_t rrm_get_min_of_max_tx_power(tpAniSirGlobal pMac, int8_t regMax, + int8_t apTxPower); + +extern tSirRetStatus rrm_initialize(tpAniSirGlobal pMac); + +extern tSirRetStatus rrm_cleanup(tpAniSirGlobal pMac); + +extern tSirRetStatus rrm_process_link_measurement_request(tpAniSirGlobal pMac, + uint8_t *pRxPacketInfo, + tDot11fLinkMeasurementRequest + *pLinkReq, + tpPESession + pSessionEntry); + +extern tSirRetStatus rrm_process_radio_measurement_request(tpAniSirGlobal pMac, + tSirMacAddr peer, + tDot11fRadioMeasurementRequest + *pRRMReq, + tpPESession + pSessionEntry); + +extern tSirRetStatus rrm_process_neighbor_report_response(tpAniSirGlobal pMac, + tDot11fNeighborReportResponse + *pNeighborRep, + tpPESession + pSessionEntry); + +extern tSirRetStatus rrm_send_set_max_tx_power_req(tpAniSirGlobal pMac, + int8_t txPower, + tpPESession pSessionEntry); + +extern int8_t rrm_get_mgmt_tx_power(tpAniSirGlobal pMac, + tpPESession pSessionEntry); + +extern void rrm_cache_mgmt_tx_power(tpAniSirGlobal pMac, + int8_t txPower, tpPESession pSessionEntry); + +extern tpRRMCaps rrm_get_capabilities(tpAniSirGlobal pMac, + tpPESession pSessionEntry); + +extern void rrm_get_start_tsf(tpAniSirGlobal pMac, uint32_t *pStartTSF); + +extern void rrm_update_start_tsf(tpAniSirGlobal pMac, uint32_t startTSF[2]); + +extern tSirRetStatus rrm_set_max_tx_power_rsp(tpAniSirGlobal pMac, + tpSirMsgQ limMsgQ); + +extern tSirRetStatus +rrm_process_neighbor_report_req(tpAniSirGlobal pMac, + tpSirNeighborReportReqInd pNeighborReq); +extern tSirRetStatus +rrm_process_beacon_report_xmit(tpAniSirGlobal pMac, + tpSirBeaconReportXmitInd pBcnReport); +extern void lim_update_rrm_capability(tpAniSirGlobal mac_ctx, + tpSirSmeJoinReq join_req); +#endif diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/include/rrm_global.h b/drivers/staging/qcacld-3.0/core/mac/src/pe/include/rrm_global.h new file mode 100644 index 0000000000000000000000000000000000000000..6d829fffa999eea53ebe1d86a9f04bb1353d2b6f --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/include/rrm_global.h @@ -0,0 +1,351 @@ +/* + * Copyright (c) 2011-2012, 2014-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#if !defined(__RRMGLOBAL_H) +#define __RRMGLOBAL_H + +/**========================================================================= + + \file rrm_global.h + + \brief Definitions for SME APIs + + ========================================================================*/ + +typedef enum eRrmRetStatus { + eRRM_SUCCESS, + eRRM_INCAPABLE, + eRRM_REFUSED, + eRRM_FAILURE +} tRrmRetStatus; + +typedef enum eRrmMsgReqSource { + eRRM_MSG_SOURCE_LEGACY_ESE = 1, /* legacy ese */ + eRRM_MSG_SOURCE_11K = 2, /* 11k */ + eRRM_MSG_SOURCE_ESE_UPLOAD = 3, /* ese upload approach */ +} tRrmMsgReqSource; + +typedef struct sSirChannelInfo { + uint8_t regulatoryClass; + uint8_t channelNum; +} tSirChannelInfo, *tpSirChannelInfo; + +typedef struct sSirBeaconReportReqInd { + uint16_t messageType; /* eWNI_SME_BEACON_REPORT_REQ_IND */ + uint16_t length; + tSirMacAddr bssId; + uint16_t measurementDuration[SIR_ESE_MAX_MEAS_IE_REQS]; /* ms */ + uint16_t randomizationInterval; /* ms */ + tSirChannelInfo channelInfo; + /* 0: wildcard */ + tSirMacAddr macaddrBssid; + /* 0:Passive, 1: Active, 2: table mode */ + uint8_t fMeasurementtype[SIR_ESE_MAX_MEAS_IE_REQS]; + tAniSSID ssId; /* May be wilcard. */ + uint16_t uDialogToken; + tSirChannelList channelList; /* From AP channel report. */ + tRrmMsgReqSource msgSource; +} tSirBeaconReportReqInd, *tpSirBeaconReportReqInd; + +typedef struct sSirBeaconReportXmitInd { + uint16_t messageType; /* eWNI_SME_BEACON_REPORT_RESP_XMIT_IND */ + uint16_t length; + tSirMacAddr bssId; + uint16_t uDialogToken; + uint8_t fMeasureDone; + uint16_t duration; + uint8_t regClass; + uint8_t numBssDesc; + tpSirBssDescription pBssDescription[SIR_BCN_REPORT_MAX_BSS_DESC]; +} tSirBeaconReportXmitInd, *tpSirBeaconReportXmitInd; + +typedef struct sSirNeighborReportReqInd { + /* eWNI_SME_NEIGHBOR_REPORT_REQ_IND */ + uint16_t messageType; + uint16_t length; + /* For the session. */ + tSirMacAddr bssId; + /* true - dont include SSID in the request. */ + uint16_t noSSID; + /* false include the SSID. It may be null (wildcard) */ + tSirMacSSid ucSSID; +} tSirNeighborReportReqInd, *tpSirNeighborReportReqInd; + +typedef struct sSirNeighborBssDescription { + uint16_t length; + tSirMacAddr bssId; + uint8_t regClass; + uint8_t channel; + uint8_t phyType; + union sSirNeighborBssidInfo { + struct _rrmInfo { + /* see IEEE 802.11k Table 7-43a */ + uint32_t fApPreauthReachable:2; + uint32_t fSameSecurityMode:1; + uint32_t fSameAuthenticator:1; + /* see IEEE 802.11k Table 7-95d */ + uint32_t fCapSpectrumMeasurement:1; + uint32_t fCapQos:1; + uint32_t fCapApsd:1; + uint32_t fCapRadioMeasurement:1; + uint32_t fCapDelayedBlockAck:1; + uint32_t fCapImmediateBlockAck:1; + uint32_t fMobilityDomain:1; + uint32_t reserved:21; + } rrmInfo; + struct _eseInfo { + uint32_t channelBand:8; + uint32_t minRecvSigPower:8; + uint32_t apTxPower:8; + uint32_t roamHysteresis:8; + uint32_t adaptScanThres:8; + + uint32_t transitionTime:8; + uint32_t tsfOffset:16; + + uint32_t beaconInterval:16; + uint32_t reserved:16; + } eseInfo; + } bssidInfo; + + /* Optional sub IEs....ignoring for now. */ +} tSirNeighborBssDescription, *tpSirNeighborBssDescripton; + +typedef struct sSirNeighborReportInd { + uint16_t messageType; /* eWNI_SME_NEIGHBOR_REPORT_IND */ + uint16_t length; + uint8_t sessionId; + uint16_t numNeighborReports; + tSirMacAddr bssId; /* For the session. */ + tSirNeighborBssDescription sNeighborBssDescription[1]; +} tSirNeighborReportInd, *tpSirNeighborReportInd; + +typedef struct sRRMBeaconReportRequestedIes { + uint8_t num; + uint8_t *pElementIds; +} tRRMBeaconReportRequestedIes, *tpRRMBeaconReportRequestedIes; + +/* Reporting detail defines. */ +/* Reference - IEEE Std 802.11k-2008 section 7.3.2.21.6 Table 7-29h */ +#define BEACON_REPORTING_DETAIL_NO_FF_IE 0 +#define BEACON_REPORTING_DETAIL_ALL_FF_REQ_IE 1 +#define BEACON_REPORTING_DETAIL_ALL_FF_IE 2 + +typedef struct sRRMReq { + uint8_t dialog_token; /* In action frame; */ + uint8_t token; /* Within individual request; */ + uint8_t type; + union { + struct { + uint8_t reportingDetail; + tRRMBeaconReportRequestedIes reqIes; + } Beacon; + } request; + uint8_t sendEmptyBcnRpt; +} tRRMReq, *tpRRMReq; + +typedef struct sRRMCaps { + uint8_t LinkMeasurement:1; + uint8_t NeighborRpt:1; + uint8_t parallel:1; + uint8_t repeated:1; + uint8_t BeaconPassive:1; + uint8_t BeaconActive:1; + uint8_t BeaconTable:1; + uint8_t BeaconRepCond:1; + uint8_t FrameMeasurement:1; + uint8_t ChannelLoad:1; + uint8_t NoiseHistogram:1; + uint8_t statistics:1; + uint8_t LCIMeasurement:1; + uint8_t LCIAzimuth:1; + uint8_t TCMCapability:1; + uint8_t triggeredTCM:1; + uint8_t APChanReport:1; + uint8_t RRMMIBEnabled:1; + uint8_t operatingChanMax:3; + uint8_t nonOperatingChanMax:3; + uint8_t MeasurementPilot:3; + uint8_t MeasurementPilotEnabled:1; + uint8_t NeighborTSFOffset:1; + uint8_t RCPIMeasurement:1; + uint8_t RSNIMeasurement:1; + uint8_t BssAvgAccessDelay:1; + uint8_t BSSAvailAdmission:1; + uint8_t AntennaInformation:1; + uint8_t fine_time_meas_rpt:1; + uint8_t lci_capability:1; + uint8_t reserved:4; +} tRRMCaps, *tpRRMCaps; + +typedef struct sRrmPEContext { + uint8_t rrmEnable; + /* + * Used during scan/measurement to store the start TSF. + * this is not used directly in beacon reports. + */ + uint32_t startTSF[2]; + /* + * This value is stored into bssdescription and beacon report + * gets it from bss decsription. + */ + tRRMCaps rrmEnabledCaps; + int8_t txMgmtPower; + /* Dialog token for the request initiated from station. */ + uint8_t DialogToken; + tpRRMReq pCurrentReq; +} tRrmPEContext, *tpRrmPEContext; + +/* 2008 11k spec reference: 18.4.8.5 RCPI Measurement */ +#define RCPI_LOW_RSSI_VALUE (-110) +#define RCPI_MAX_VALUE (220) +#define CALCULATE_RCPI(rssi) (((rssi) + 110) * 2) + +/* Bit mask are defined as per Draft P802.11REVmc_D4.2 */ + +/** + * enum mask_rm_capability_byte1 - mask for supported capability + * @RM_CAP_LINK_MEASUREMENT: Link Measurement capability + * @RM_CAP_NEIGHBOR_REPORT: Neighbor report capability + * @RM_CAP_PARALLEL_MEASUREMENT: Parallel Measurement capability + * @RM_CAP_REPEATED_MEASUREMENT: Repeated Measurement capability + * @RM_CAP_BCN_PASSIVE_MEASUREMENT: Beacon passive measurement capability + * @RM_CAP_BCN_ACTIVE_MEASUREMENT: Beacon active measurement capability + * @RM_CAP_BCN_TABLE_MEASUREMENT: Beacon table measurement capability + * @RM_CAP_BCN_MEAS_REPORTING_COND: Beacon measurement reporting conditions + */ +enum mask_rm_capability_byte1 { + RM_CAP_LINK_MEASUREMENT = (1 << (0)), + RM_CAP_NEIGHBOR_REPORT = (1 << (1)), + RM_CAP_PARALLEL_MEASUREMENT = (1 << (2)), + RM_CAP_REPEATED_MEASUREMENT = (1 << (3)), + RM_CAP_BCN_PASSIVE_MEASUREMENT = (1 << (4)), + RM_CAP_BCN_ACTIVE_MEASUREMENT = (1 << (5)), + RM_CAP_BCN_TABLE_MEASUREMENT = (1 << (6)), + RM_CAP_BCN_MEAS_REPORTING_COND = (1 << (7)), +}; + +/** + * enum mask_rm_capability_byte2 - mask for supported capability + * @RM_CAP_FRAME_MEASUREMENT: Frame Measurement capability + * @RM_CAP_CHAN_LOAD_MEASUREMENT: Channel load measurement capability + * @RM_CAP_NOISE_HIST_MEASUREMENT: Noise Histogram Measurement capability + * @RM_CAP_STATISTICS_MEASUREMENT: Statistics Measurement capability + * @RM_CAP_LCI_MEASUREMENT: LCI measurement capability + * @RM_CAP_LCI_AZIMUTH: LCI Azimuth capability + * @RM_CAP_TX_CATEGORY_MEASUREMENT: Transmit category measurement capability + * @RM_CAP_TRIG_TX_CATEGORY_MEASUREMENT: + * Triggered Transmit category measurement capability + */ +enum mask_rm_capability_byte2 { + RM_CAP_FRAME_MEASUREMENT = (1 << (0)), + RM_CAP_CHAN_LOAD_MEASUREMENT = (1 << (1)), + RM_CAP_NOISE_HIST_MEASUREMENT = (1 << (2)), + RM_CAP_STATISTICS_MEASUREMENT = (1 << (3)), + RM_CAP_LCI_MEASUREMENT = (1 << (4)), + RM_CAP_LCI_AZIMUTH = (1 << (5)), + RM_CAP_TX_CATEGORY_MEASUREMENT = (1 << (6)), + RM_CAP_TRIG_TX_CATEGORY_MEASUREMENT = (1 << (7)), +}; + +/** + * enum mask_rm_capability_byte3 - mask for supported capability + * @RM_CAP_AP_CHAN_REPORT: AP channel report capability + * @RM_CAP_RM_MIB: RM MIB capability + * @RM_CAP_OPER_CHAN_MAX_DURATION_1: OPER_CHAN_MAX_DURATION bit1 + * @RM_CAP_OPER_CHAN_MAX_DURATION_2: OPER_CHAN_MAX_DURATION bit2 + * @RM_CAP_OPER_CHAN_MAX_DURATION_3: OPER_CHAN_MAX_DURATION bit3 + * @RM_CAP_NONOPER_CHAN_MAX_DURATION_1: NONOPER_CHAN_MAX bit1 + * @RM_CAP_NONOPER_CHAN_MAX_DURATION_2: NONOPER_CHAN_MAX bit2 + * @RM_CAP_NONOPER_CHAN_MAX_DURATION_3: NONOPER_CHAN_MAX bit3 + * @RM_CAP_OPER_CHAN_MAX_DURATION: Operating Channel Max Measurement Duration + * @RM_CAP_NONOPER_CHAN_MAX_DURATION: + * Nonoperating Channel Max Measurement Duration + */ + +enum mask_rm_capability_byte3 { + RM_CAP_AP_CHAN_REPORT = (1 << (0)), + RM_CAP_RM_MIB = (1 << (1)), + RM_CAP_OPER_CHAN_MAX_DURATION_1 = (1 << (2)), + RM_CAP_OPER_CHAN_MAX_DURATION_2 = (1 << (3)), + RM_CAP_OPER_CHAN_MAX_DURATION_3 = (1 << (4)), + RM_CAP_NONOPER_CHAN_MAX_DURATION_1 = (1 << (5)), + RM_CAP_NONOPER_CHAN_MAX_DURATION_2 = (1 << (6)), + RM_CAP_NONOPER_CHAN_MAX_DURATION_3 = (1 << (7)), + RM_CAP_OPER_CHAN_MAX_DURATION = (RM_CAP_OPER_CHAN_MAX_DURATION_1 || + RM_CAP_OPER_CHAN_MAX_DURATION_2 || + RM_CAP_OPER_CHAN_MAX_DURATION_3), + RM_CAP_NONOPER_CHAN_MAX_DURATION = + (RM_CAP_NONOPER_CHAN_MAX_DURATION_1 || + RM_CAP_NONOPER_CHAN_MAX_DURATION_2 || + RM_CAP_NONOPER_CHAN_MAX_DURATION_3), +}; + +/** + * enum mask_rm_capability_byte4 - mask for supported capability + * @RM_CAP_MEASUREMENT_PILOT_1: MEASUREMENT_PILOT bit1 + * @RM_CAP_MEASUREMENT_PILOT_2: MEASUREMENT_PILOT bit2 + * @RM_CAP_MEASUREMENT_PILOT_3: MEASUREMENT_PILOT bit3 + * @RM_CAP_MEAS_PILOT_TX_INFO: Measurement Pilot Transmission Capability + * @RM_CAP_NEIGHBOR_RPT_TSF_OFFSET: Neighbor Report TSF Offset Capability + * @RM_CAP_RCPI_MEASUREMENT: RCPI Measurement Capability + * @RM_CAP_RSNI_MEASUREMENT: RSNI Measurement Capability + * @RM_CAP_BSS_AVG_ACCESS_DELAY: BSS Average Access Delay Capability + * @RM_CAP_MEASUREMENT_PILOT: Measurement pilot capability + */ + +enum mask_rm_capability_byte4 { + RM_CAP_MEASUREMENT_PILOT_1 = (1 << (0)), + RM_CAP_MEASUREMENT_PILOT_2 = (1 << (1)), + RM_CAP_MEASUREMENT_PILOT_3 = (1 << (2)), + RM_CAP_MEAS_PILOT_TX_INFO = (1 << (3)), + RM_CAP_NEIGHBOR_RPT_TSF_OFFSET = (1 << (4)), + RM_CAP_RCPI_MEASUREMENT1 = (1 << (5)), + RM_CAP_RSNI_MEASUREMENT = (1 << (6)), + RM_CAP_BSS_AVG_ACCESS_DELAY = (1 << (7)), + RM_CAP_MEASUREMENT_PILOT = (RM_CAP_MEASUREMENT_PILOT_1 || + RM_CAP_MEASUREMENT_PILOT_2 || + RM_CAP_MEASUREMENT_PILOT_3), +}; + +/** + * enum mask_rm_capability_byte5 - mask for supported capability + * @RM_CAP_BSS_AVAIL_ADMISSION: BSS Available Admission Capacity Capability + * @RM_CAP_ANTENNA: Antenna Capability + * @RM_CAP_FTM_RANGE_REPORT: FTM Range Report Capability + * @RM_CAP_CIVIC_LOC_MEASUREMENT: Civic Location Measurement capability + * + * 4 bits are reserved + */ +enum mask_rm_capability_byte5 { + RM_CAP_BSS_AVAIL_ADMISSION = (1 << (0)), + RM_CAP_ANTENNA = (1 << (1)), + RM_CAP_FTM_RANGE_REPORT = (1 << (2)), + RM_CAP_CIVIC_LOC_MEASUREMENT = (1 << (3)), +}; + +#endif /* #if defined __RRMGLOBAL_H */ diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/include/sch_api.h b/drivers/staging/qcacld-3.0/core/mac/src/pe/include/sch_api.h new file mode 100644 index 0000000000000000000000000000000000000000..04db805e19f82087e5e5600e4106904e9b3159a2 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/include/sch_api.h @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2011-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * + * Author: Sandesh Goel + * Date: 02/25/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + * + */ + +#ifndef __SCH_API_H__ +#define __SCH_API_H__ + +#include "sir_common.h" +#include "sir_mac_prot_def.h" + +#include "ani_global.h" + +/* / Send start scan response message */ +extern void sch_send_start_scan_rsp(tpAniSirGlobal pMac); + +/* update only the broadcast qos params */ +extern void sch_qos_update_broadcast(tpAniSirGlobal pMac, + tpPESession psessionEntry); + +/* fill in the default local edca parameter into gLimEdcaParams[] */ +extern void sch_set_default_edca_params(tpAniSirGlobal pMac, tpPESession psessionE); + +/* update only local qos params */ +extern void sch_qos_update_local(tpAniSirGlobal pMac, tpPESession psessionEntry); + +/* update the edca profile parameters */ +extern void sch_edca_profile_update(tpAniSirGlobal pMac, + tpPESession psessionEntry); + +/* / Set the fixed fields in a beacon frame */ +extern tSirRetStatus sch_set_fixed_beacon_fields(tpAniSirGlobal pMac, + tpPESession psessionEntry); + +/* / Initialize globals */ +extern void sch_init_globals(tpAniSirGlobal pMac); + +/* / Initialize CF Poll template */ +extern void sch_initializeCfPollTemplate(tpAniSirGlobal pMac); + +/* / Initialize CF End template */ +extern void sch_initializeCfEndTemplate(tpAniSirGlobal pMac); + +/* / Process the scheduler messages */ +extern void sch_process_message(tpAniSirGlobal pMac, tpSirMsgQ pSchMsg); + +/* / The beacon Indication handler function */ +extern void sch_process_pre_beacon_ind(tpAniSirGlobal pMac, tpSirMsgQ limMsg); + +/* / Post a message to the scheduler message queue */ +extern tSirRetStatus sch_post_message(tpAniSirGlobal pMac, tpSirMsgQ pMsg); + +extern void sch_beacon_process(tpAniSirGlobal pMac, uint8_t *pRxPacketInfo, + tpPESession psessionEntry); +extern tSirRetStatus sch_beacon_edca_process(tpAniSirGlobal pMac, + tSirMacEdcaParamSetIE *edca, + tpPESession psessionEntry); + +void sch_generate_tim(tpAniSirGlobal, uint8_t **, uint16_t *, uint8_t); +#define SCH_RR_TIMEOUT (SCH_RR_TIMEOUT_MS / SYS_TICK_DUR_MS) + +void sch_set_beacon_interval(tpAniSirGlobal pMac, tpPESession psessionEntry); + +tSirRetStatus sch_send_beacon_req(tpAniSirGlobal, uint8_t *, uint16_t, + tpPESession psessionEntry); + +tSirRetStatus lim_update_probe_rsp_template_ie_bitmap_beacon1(tpAniSirGlobal, + tDot11fBeacon1 *, + tpPESession + psessionEntry); +void lim_update_probe_rsp_template_ie_bitmap_beacon2(tpAniSirGlobal, tDot11fBeacon2 *, + uint32_t *, + tDot11fProbeResponse *); +void set_probe_rsp_ie_bitmap(uint32_t *, uint32_t); +uint32_t lim_send_probe_rsp_template_to_hal(tpAniSirGlobal, tpPESession, uint32_t *); + +int sch_gen_timing_advert_frame(tpAniSirGlobal pMac, tSirMacAddr self_addr, + uint8_t **buf, uint32_t *timestamp_offset, uint32_t *time_value_offset); + +#endif diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/include/sch_global.h b/drivers/staging/qcacld-3.0/core/mac/src/pe/include/sch_global.h new file mode 100644 index 0000000000000000000000000000000000000000..baebe98f96de9793c64674aa2089711f82fd2c2c --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/include/sch_global.h @@ -0,0 +1,176 @@ +/* + * Copyright (c) 2013-2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * + * + * Author: Sandesh Goel + * Date: 02/25/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + * + */ + +#ifndef __SCH_GLOBAL_H__ +#define __SCH_GLOBAL_H__ + +#include "sir_mac_prop_exts.h" +#include "lim_global.h" + +#include "parser_api.h" + +#ifdef WLAN_SOFTAP_VSTA_FEATURE +#define TIM_IE_SIZE 0xB +#else +#define TIM_IE_SIZE 0x7 +#endif + +/* ----------------------- Beacon processing ------------------------ */ + +/* / Beacon structure */ +#define tSchBeaconStruct tSirProbeRespBeacon +#define tpSchBeaconStruct struct sSirProbeRespBeacon * + +/* ------------------------------------------------------------------- */ + +/* ****************** MISC defs ********************************* */ + +struct schMisc { + uint16_t gSchBeaconInterval; + + /* / Current CFP count */ + uint8_t gSchCFPCount; + + /* / CFP Duration remaining */ + uint8_t gSchCFPDurRemaining; + + /* / CFP Maximum Duration */ + uint8_t gSchCFPMaxDuration; + + /* / Current DTIM count */ + uint8_t gSchDTIMCount; + + /* / Whether we have initiated a CFP or not */ + uint8_t gSchCFPInitiated; + + /* / Whether we have initiated a CFB or not */ + uint8_t gSchCFBInitiated; + + /* / CFP is enabled and AP is configured as HCF */ + uint8_t gSchCFPEnabled; + + /* / CFB is enabled and AP is configured as HCF */ + uint8_t gSchCFBEnabled; + + /* --------- STA ONLY state ----------- */ + + /* / Indicates whether RR timer is running or not */ + uint8_t rrTimer[8]; + + /* / Indicates the remaining RR timeout value if the RR timer is running */ + uint16_t rrTimeout[8]; + + /* / Number of RRs transmitted */ + uint16_t numRR[8]; + uint16_t numRRtimeouts[8]; + + /* / flag to indicate that beacon template has been updated */ + uint8_t fBeaconChanged; + + uint16_t p2pIeOffset; + +}; + +/* ****************** MISC defs ********************************* */ + +typedef struct schStaWaitList { + uint16_t staId; + uint16_t count; +} tStaWaitList, *tpStaWaitList; + +/* / Global SCH structure */ +typedef struct sAniSirSch { + /* / The scheduler object */ + struct schMisc schObject; + + /* schQoSClass unsolicited; */ + + /* / Whether HCF is enabled or not */ + uint8_t gSchHcfEnabled; + + /* / Whether scan is requested by LIM or not */ + uint8_t gSchScanRequested; + + /* / Whether scan request is received by SCH or not */ + uint8_t gSchScanReqRcvd; + + /* / Debug flag to disable beacon generation */ + uint32_t gSchGenBeacon; + +#define SCH_MAX_ARR 100 + uint32_t gSchBeaconsWritten; + uint32_t gSchBeaconsSent; + uint32_t gSchBBXportRcvCnt; + uint32_t gSchRRRcvCnt, qosNullCnt; + uint32_t gSchBcnRcvCnt; + uint32_t gSchUnknownRcvCnt; + + uint32_t gSchBcnParseErrorCnt; + uint32_t gSchBcnIgnored; + + uint32_t numPoll, numData, numCorrupt; + uint32_t numBogusInt, numTxAct0; + +#define SCH_MAX_NUM_SCH 21 + uint32_t lastBeaconLength; + uint16_t rrTimeout; + uint32_t pollPeriod; + uint32_t multipleSched; + uint32_t pollFeedbackHist[8]; + uint32_t dataFeedbackHist[8]; + uint32_t maxPollTimeouts; + uint32_t checkCfbFlagStuck; + + /* / Sta Wait list */ + tpStaWaitList pStaWaitList; + + /* / Pointer to next available entry in sta wait list */ + uint16_t staWaitListIn; + /* / Pointer to first waiting sta in sta wait list */ + uint16_t staWaitListOut; + /* / Total number of waiting STAs in sta wait list */ + uint16_t staWaitListCount; + /* / Total number of schedules to be waited */ + uint16_t staWaitListTotalWait; + + /* / Number of entries in DPH activity queue that were ignored */ + uint32_t ignoreDph; + +} tAniSirSch, *tpAniSirSch; + +#endif diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/include/wmm_apsd.h b/drivers/staging/qcacld-3.0/core/mac/src/pe/include/wmm_apsd.h new file mode 100644 index 0000000000000000000000000000000000000000..9b5d5d4affd83cb00ff95ea79390b7827477fcac --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/include/wmm_apsd.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2013-2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef __WMMAPSD_H__ +#define __WMMAPSD_H__ + +#include "ani_global.h" + +/* UAPSD Flag for each AC (WMM spec 2.2.1) */ +#define LIM_UAPSD_BITOFFSET_ACVO 0 +#define LIM_UAPSD_BITOFFSET_ACVI 1 +#define LIM_UAPSD_BITOFFSET_ACBK 2 +#define LIM_UAPSD_BITOFFSET_ACBE 3 + +#define LIM_UAPSD_FLAG_ACVO (1 << LIM_UAPSD_BITOFFSET_ACVO) +#define LIM_UAPSD_FLAG_ACVI (1 << LIM_UAPSD_BITOFFSET_ACVI) +#define LIM_UAPSD_FLAG_ACBK (1 << LIM_UAPSD_BITOFFSET_ACBK) +#define LIM_UAPSD_FLAG_ACBE (1 << LIM_UAPSD_BITOFFSET_ACBE) + +#define LIM_UAPSD_GET(ac, mask) (((mask) & (LIM_UAPSD_FLAG_ ## ac)) >> LIM_UAPSD_BITOFFSET_ ## ac) + +/* Definition for setting/clearing Uapsd Mask */ +#define SET_UAPSD_MASK 1 +#define CLEAR_UAPSD_MASK 0 + +#endif /* __WMMAPSD_H__ */ diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_admit_control.c b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_admit_control.c new file mode 100644 index 0000000000000000000000000000000000000000..7c361f37ece2882f5145ae61297373dd4a12a60b --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_admit_control.c @@ -0,0 +1,1139 @@ +/* + * Copyright (c) 2011-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * This file contains TSPEC and STA admit control related functions + * NOTE: applies only to AP builds + * + * Author: Sandesh Goel + * Date: 02/25/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + * + */ +#include "lim_debug.h" +#include "sys_def.h" +#include "lim_api.h" +#include "cfg_api.h" /* wlan_cfg_get_int() */ +#include "lim_trace.h" +#include "lim_send_sme_rsp_messages.h" +#include "lim_types.h" +#include "lim_admit_control.h" + +#define ADMIT_CONTROL_LOGLEVEL LOG1 +#define ADMIT_CONTROL_POLICY_LOGLEVEL LOG1 + +/* total available bandwidth in bps in each phy mode + * these should be defined in hal or dph - replace these later + */ +#define LIM_TOTAL_BW_11A 54000000 +#define LIM_MIN_BW_11A 6000000 +#define LIM_TOTAL_BW_11B 11000000 +#define LIM_MIN_BW_11B 1000000 +#define LIM_TOTAL_BW_11G LIM_TOTAL_BW_11A +#define LIM_MIN_BW_11G LIM_MIN_BW_11B + +/* conversion factors */ +#define LIM_CONVERT_SIZE_BITS(numBytes) ((numBytes) * 8) +#define LIM_CONVERT_RATE_MBPS(rate) ((rate)/1000000) + +/* ------------------------------------------------------------------------------ */ +/* local protos */ + +static tSirRetStatus +lim_calculate_svc_int(tpAniSirGlobal, tSirMacTspecIE *, uint32_t *); +static tSirRetStatus +lim_validate_tspec_edca(tpAniSirGlobal, tSirMacTspecIE *, tpPESession); +static tSirRetStatus +lim_validate_tspec(tpAniSirGlobal, tSirMacTspecIE *, tpPESession); +static void +lim_compute_mean_bw_used(tpAniSirGlobal, uint32_t *, uint32_t, tpLimTspecInfo, + tpPESession); +static void lim_get_available_bw(tpAniSirGlobal, uint32_t *, uint32_t *, uint32_t, + uint32_t); +static tSirRetStatus lim_admit_policy_oversubscription(tpAniSirGlobal, + tSirMacTspecIE *, + tpLimAdmitPolicyInfo, + tpLimTspecInfo, + tpPESession); +static tSirRetStatus lim_tspec_find_by_sta_addr(tpAniSirGlobal, uint8_t *, + tSirMacTspecIE *, tpLimTspecInfo, + tpLimTspecInfo *); +static tSirRetStatus lim_validate_access_policy(tpAniSirGlobal, uint8_t, uint16_t, + tpPESession); + +/** ------------------------------------------------------------- + \fn lim_calculate_svc_int + \brief TSPEC validation and servcie interval determination + \param tpAniSirGlobal pMac + \param tSirMacTspecIE *pTspec + \param uint32_t *pSvcInt + \return eSirRetStatus - status of the comparison + -------------------------------------------------------------*/ + +static tSirRetStatus +lim_calculate_svc_int(tpAniSirGlobal pMac, + tSirMacTspecIE *pTspec, uint32_t *pSvcInt) +{ + uint32_t msduSz, dataRate; + *pSvcInt = 0; + + /* if a service interval is already specified, we are done */ + if ((pTspec->minSvcInterval != 0) || (pTspec->maxSvcInterval != 0)) { + *pSvcInt = (pTspec->maxSvcInterval != 0) + ? pTspec->maxSvcInterval : pTspec->minSvcInterval; + return eSIR_SUCCESS; + } + + /* Masking off the fixed bits according to definition of MSDU size + * in IEEE 802.11-2007 spec (section 7.3.2.30). Nominal MSDU size + * is defined as: Bit[0:14]=Size, Bit[15]=Fixed + */ + if (pTspec->nomMsduSz != 0) + msduSz = (pTspec->nomMsduSz & 0x7fff); + else if (pTspec->maxMsduSz != 0) + msduSz = pTspec->maxMsduSz; + else { + PELOGE(lim_log(pMac, LOGE, FL("MsduSize not specified"));) + return eSIR_FAILURE; + } + + /* need to calculate a reasonable service interval + * this is simply the msduSz/meanDataRate + */ + if (pTspec->meanDataRate != 0) + dataRate = pTspec->meanDataRate; + else if (pTspec->peakDataRate != 0) + dataRate = pTspec->peakDataRate; + else if (pTspec->minDataRate != 0) + dataRate = pTspec->minDataRate; + else { + PELOGE(lim_log(pMac, LOGE, FL("DataRate not specified"));) + return eSIR_FAILURE; + } + + *pSvcInt = + LIM_CONVERT_SIZE_BITS(msduSz) / LIM_CONVERT_RATE_MBPS(dataRate); + return eSIR_FAILURE; +} + +/** + * lim_validate_tspec_edca() - Validate the parameters + * @mac_ctx: Global MAC context + * @tspec: Pointer to the TSPEC + * @session_entry: Session Entry + * + * validate the parameters in the edca tspec + * mandatory fields are derived from 11e Annex I (Table I.1) + * + * Return: Status + **/ +static tSirRetStatus +lim_validate_tspec_edca(tpAniSirGlobal mac_ctx, + tSirMacTspecIE *tspec, tpPESession session_entry) +{ + uint32_t max_phy_rate, min_phy_rate; + uint32_t phy_mode; + tSirRetStatus retval = eSIR_SUCCESS; + + lim_get_phy_mode(mac_ctx, &phy_mode, session_entry); + + lim_get_available_bw(mac_ctx, &max_phy_rate, &min_phy_rate, phy_mode, + 1 /* bandwidth mult factor */); + /* mandatory fields are derived from 11e Annex I (Table I.1) */ + if ((tspec->nomMsduSz == 0) || + (tspec->meanDataRate == 0) || + (tspec->surplusBw == 0) || + (tspec->minPhyRate == 0) || + (tspec->minPhyRate > max_phy_rate)) { + lim_log(mac_ctx, LOGW, + FL + ("Invalid EDCA Tspec: NomMsdu %d, meanDataRate %d, surplusBw %d, min_phy_rate %d"), + tspec->nomMsduSz, tspec->meanDataRate, + tspec->surplusBw, tspec->minPhyRate); + retval = eSIR_FAILURE; + } + + lim_log(mac_ctx, ADMIT_CONTROL_LOGLEVEL, + FL("return status %d"), retval); + return retval; +} + +/** ------------------------------------------------------------- + \fn lim_validate_tspec + \brief validate the offered tspec + \param tpAniSirGlobal pMac + \param tSirMacTspecIE *pTspec + \return eSirRetStatus - status + -------------------------------------------------------------*/ + +static tSirRetStatus +lim_validate_tspec(tpAniSirGlobal pMac, + tSirMacTspecIE *pTspec, tpPESession psessionEntry) +{ + tSirRetStatus retval = eSIR_SUCCESS; + switch (pTspec->tsinfo.traffic.accessPolicy) { + case SIR_MAC_ACCESSPOLICY_EDCA: + retval = lim_validate_tspec_edca(pMac, pTspec, psessionEntry); + if (retval != eSIR_SUCCESS) + PELOGW(lim_log(pMac, LOGW, FL("EDCA tspec invalid"));) + break; + + case SIR_MAC_ACCESSPOLICY_HCCA: + case SIR_MAC_ACCESSPOLICY_BOTH: + /* TBD: should we support hybrid tspec as well?? for now, just fall through */ + default: + lim_log(pMac, LOGW, FL("AccessType %d not supported"), + pTspec->tsinfo.traffic.accessPolicy); + retval = eSIR_FAILURE; + break; + } + return retval; +} + +/* ----------------------------------------------------------------------------- */ +/* Admit Control Policy */ + +/** ------------------------------------------------------------- + \fn lim_compute_mean_bw_used + \brief determime the used/allocated bandwidth + \param tpAniSirGlobal pMac + \param uint32_t *pBw + \param uint32_t phyMode + \param tpLimTspecInfo pTspecInfo + \return eSirRetStatus - status + -------------------------------------------------------------*/ + +static void +lim_compute_mean_bw_used(tpAniSirGlobal pMac, + uint32_t *pBw, + uint32_t phyMode, + tpLimTspecInfo pTspecInfo, tpPESession psessionEntry) +{ + uint32_t ctspec; + *pBw = 0; + for (ctspec = 0; ctspec < LIM_NUM_TSPEC_MAX; ctspec++, pTspecInfo++) { + if (pTspecInfo->inuse) { + tpDphHashNode pSta = + dph_get_hash_entry(pMac, pTspecInfo->assocId, + &psessionEntry->dph.dphHashTable); + if (pSta == NULL) { + /* maybe we should delete the tspec?? */ + lim_log(pMac, LOGE, + FL + ("Tspec %d (assocId %d): dphNode not found"), + ctspec, pTspecInfo->assocId); + continue; + } + *pBw += pTspecInfo->tspec.meanDataRate; + } + } +} + +/** ------------------------------------------------------------- + \fn lim_get_available_bw + \brief based on the phy mode and the bw_factor, determine the total bandwidth that + can be supported + \param tpAniSirGlobal pMac + \param uint32_t *pMaxBw + \param uint32_t *pMinBw + \param uint32_t phyMode + \param uint32_t bw_factor + \return eSirRetStatus - status + -------------------------------------------------------------*/ + +static void +lim_get_available_bw(tpAniSirGlobal pMac, + uint32_t *pMaxBw, + uint32_t *pMinBw, uint32_t phyMode, uint32_t bw_factor) +{ + switch (phyMode) { + case WNI_CFG_PHY_MODE_11B: + *pMaxBw = LIM_TOTAL_BW_11B; + *pMinBw = LIM_MIN_BW_11B; + break; + + case WNI_CFG_PHY_MODE_11A: + *pMaxBw = LIM_TOTAL_BW_11A; + *pMinBw = LIM_MIN_BW_11A; + break; + + case WNI_CFG_PHY_MODE_11G: + case WNI_CFG_PHY_MODE_NONE: + default: + *pMaxBw = LIM_TOTAL_BW_11G; + *pMinBw = LIM_MIN_BW_11G; + break; + } + *pMaxBw *= bw_factor; +} + +/** + * lim_admit_policy_oversubscription() - Admission control policy + * @mac_ctx: Global MAC Context + * @tspec: Pointer to the tspec + * @admit_policy: Admission policy + * @tspec_info: TSPEC information + * @session_entry: Session Entry + * + * simple admission control policy based on oversubscription + * if the total bandwidth of all admitted tspec's exceeds (factor * phy-bw) then + * reject the tspec, else admit it. The phy-bw is the peak available bw in the + * current phy mode. The 'factor' is the configured oversubscription factor. + * + * Return: Status + **/ +static tSirRetStatus +lim_admit_policy_oversubscription(tpAniSirGlobal mac_ctx, + tSirMacTspecIE *tspec, + tpLimAdmitPolicyInfo admit_policy, + tpLimTspecInfo tspec_info, + tpPESession session_entry) +{ + uint32_t totalbw, minbw, usedbw; + uint32_t phy_mode; + + /* determine total bandwidth used so far */ + lim_get_phy_mode(mac_ctx, &phy_mode, session_entry); + + lim_compute_mean_bw_used(mac_ctx, &usedbw, phy_mode, + tspec_info, session_entry); + + /* determine how much bw is available based on the current phy mode */ + lim_get_available_bw(mac_ctx, &totalbw, &minbw, phy_mode, + admit_policy->bw_factor); + + if (usedbw > totalbw) /* this can't possibly happen */ + return eSIR_FAILURE; + + if ((totalbw - usedbw) < tspec->meanDataRate) { + lim_log(mac_ctx, ADMIT_CONTROL_POLICY_LOGLEVEL, + FL + ("Total BW %d, Used %d, Tspec request %d not possible"), + totalbw, usedbw, tspec->meanDataRate); + return eSIR_FAILURE; + } + return eSIR_SUCCESS; +} + +/** ------------------------------------------------------------- + \fn lim_admit_policy + \brief determine the current admit control policy and apply it for the offered tspec + \param tpAniSirGlobal pMac + \param tSirMacTspecIE *pTspec + \return eSirRetStatus - status + -------------------------------------------------------------*/ + +static tSirRetStatus lim_admit_policy(tpAniSirGlobal pMac, + tSirMacTspecIE *pTspec, + tpPESession psessionEntry) +{ + tSirRetStatus retval = eSIR_FAILURE; + tpLimAdmitPolicyInfo pAdmitPolicy = &pMac->lim.admitPolicyInfo; + + switch (pAdmitPolicy->type) { + case WNI_CFG_ADMIT_POLICY_ADMIT_ALL: + retval = eSIR_SUCCESS; + break; + + case WNI_CFG_ADMIT_POLICY_BW_FACTOR: + retval = lim_admit_policy_oversubscription(pMac, pTspec, + &pMac->lim. + admitPolicyInfo, + &pMac->lim.tspecInfo[0], + psessionEntry); + if (retval != eSIR_SUCCESS) + PELOGE(lim_log + (pMac, LOGE, FL("rejected by BWFactor policy")); + ) + break; + + case WNI_CFG_ADMIT_POLICY_REJECT_ALL: + retval = eSIR_FAILURE; + break; + + default: + retval = eSIR_SUCCESS; + lim_log(pMac, LOGE, + FL("Admit Policy %d unknown, admitting all traffic"), + pAdmitPolicy->type); + break; + } + return retval; +} + +/** ------------------------------------------------------------- + \fn lim_tspec_delete + \brief delete the specified tspec + \param tpAniSirGlobal pMac + \param tpLimTspecInfo pInfo + \return eSirRetStatus - status + -------------------------------------------------------------*/ + +/* ----------------------------------------------------------------------------- */ +/* delete the specified tspec */ +static void lim_tspec_delete(tpAniSirGlobal pMac, tpLimTspecInfo pInfo) +{ + if (pInfo == NULL) + return; + /* pierre */ + lim_log(pMac, ADMIT_CONTROL_LOGLEVEL, FL("tspec entry = %d"), + pInfo->idx); + lim_log(pMac, ADMIT_CONTROL_LOGLEVEL, FL("delete tspec %p"), pInfo); + pInfo->inuse = 0; + + return; +} + +/** ------------------------------------------------------------- + \fn lim_tspec_find_by_sta_addr + \brief Send halMsg_AddTs to HAL + \param tpAniSirGlobal pMac + \param \param uint8_t *pAddr + \param tSirMacTspecIE *pTspecIE + \param tpLimTspecInfo pTspecList + \param tpLimTspecInfo *ppInfo + \return eSirRetStatus - status + -------------------------------------------------------------*/ + +/* find the specified tspec in the list */ +static tSirRetStatus +lim_tspec_find_by_sta_addr(tpAniSirGlobal pMac, + uint8_t *pAddr, + tSirMacTspecIE *pTspecIE, + tpLimTspecInfo pTspecList, tpLimTspecInfo *ppInfo) +{ + int ctspec; + + *ppInfo = NULL; + + for (ctspec = 0; ctspec < LIM_NUM_TSPEC_MAX; ctspec++, pTspecList++) { + if ((pTspecList->inuse) + && + (!qdf_mem_cmp + (pAddr, pTspecList->staAddr, sizeof(pTspecList->staAddr))) + && + (!qdf_mem_cmp + ((uint8_t *) pTspecIE, (uint8_t *) &pTspecList->tspec, + sizeof(tSirMacTspecIE)))) { + *ppInfo = pTspecList; + return eSIR_SUCCESS; + } + } + return eSIR_FAILURE; +} + +/** ------------------------------------------------------------- + \fn lim_tspec_find_by_assoc_id + \brief find tspec with matchin staid and Tspec + \param tpAniSirGlobal pMac + \param uint32_t staid + \param tSirMacTspecIE *pTspecIE + \param tpLimTspecInfo pTspecList + \param tpLimTspecInfo *ppInfo + \return eSirRetStatus - status + -------------------------------------------------------------*/ + +tSirRetStatus +lim_tspec_find_by_assoc_id(tpAniSirGlobal pMac, + uint16_t assocId, + tSirMacTspecIE *pTspecIE, + tpLimTspecInfo pTspecList, tpLimTspecInfo *ppInfo) +{ + int ctspec; + + *ppInfo = NULL; + + lim_log(pMac, ADMIT_CONTROL_LOGLEVEL, + FL("Trying to find tspec entry for assocId = %d"), assocId); + lim_log(pMac, ADMIT_CONTROL_LOGLEVEL, + FL + ("pTsInfo->traffic.direction = %d, pTsInfo->traffic.tsid = %d"), + pTspecIE->tsinfo.traffic.direction, + pTspecIE->tsinfo.traffic.tsid); + + for (ctspec = 0; ctspec < LIM_NUM_TSPEC_MAX; ctspec++, pTspecList++) { + if ((pTspecList->inuse) + && (assocId == pTspecList->assocId) + && + (!qdf_mem_cmp + ((uint8_t *) pTspecIE, (uint8_t *) &pTspecList->tspec, + sizeof(tSirMacTspecIE)))) { + *ppInfo = pTspecList; + return eSIR_SUCCESS; + } + } + return eSIR_FAILURE; +} + +/** ------------------------------------------------------------- + \fn lim_find_tspec + \brief finding a TSPEC entry with assocId, tsinfo.direction and tsinfo.tsid + \param uint16_t assocId + \param tpAniSirGlobal pMac + \param tSirMacTSInfo *pTsInfo + \param tpLimTspecInfo pTspecList + \param tpLimTspecInfo *ppInfo + \return eSirRetStatus - status of the comparison + -------------------------------------------------------------*/ + +static tSirRetStatus +lim_find_tspec(tpAniSirGlobal pMac, + uint16_t assocId, + tSirMacTSInfo *pTsInfo, + tpLimTspecInfo pTspecList, tpLimTspecInfo *ppInfo) +{ + int ctspec; + + *ppInfo = NULL; + + lim_log(pMac, ADMIT_CONTROL_LOGLEVEL, + FL("Trying to find tspec entry for assocId = %d"), assocId); + lim_log(pMac, ADMIT_CONTROL_LOGLEVEL, + FL + ("pTsInfo->traffic.direction = %d, pTsInfo->traffic.tsid = %d"), + pTsInfo->traffic.direction, pTsInfo->traffic.tsid); + + for (ctspec = 0; ctspec < LIM_NUM_TSPEC_MAX; ctspec++, pTspecList++) { + if ((pTspecList->inuse) + && (assocId == pTspecList->assocId) + && (pTsInfo->traffic.direction == + pTspecList->tspec.tsinfo.traffic.direction) + && (pTsInfo->traffic.tsid == + pTspecList->tspec.tsinfo.traffic.tsid)) { + *ppInfo = pTspecList; + return eSIR_SUCCESS; + } + } + return eSIR_FAILURE; +} + +/** ------------------------------------------------------------- + \fn lim_tspec_add + \brief add or update the specified tspec to the tspec list + \param tpAniSirGlobal pMac + \param uint8_t *pAddr + \param uint16_t assocId + \param tSirMacTspecIE *pTspec + \param uint32_t interval + \param tpLimTspecInfo *ppInfo + + \return eSirRetStatus - status of the comparison + -------------------------------------------------------------*/ + +tSirRetStatus lim_tspec_add(tpAniSirGlobal pMac, + uint8_t *pAddr, + uint16_t assocId, + tSirMacTspecIE *pTspec, + uint32_t interval, tpLimTspecInfo *ppInfo) +{ + tpLimTspecInfo pTspecList = &pMac->lim.tspecInfo[0]; + *ppInfo = NULL; + + /* validate the assocId */ + if (assocId >= pMac->lim.maxStation) { + PELOGE(lim_log(pMac, LOGE, FL("Invalid assocId 0x%x"), assocId);) + return eSIR_FAILURE; + } + /* decide whether to add/update */ + { + *ppInfo = NULL; + + if (eSIR_SUCCESS == + lim_find_tspec(pMac, assocId, &pTspec->tsinfo, pTspecList, + ppInfo)) { + /* update this entry. */ + lim_log(pMac, ADMIT_CONTROL_LOGLEVEL, + FL("updating TSPEC table entry = %d"), + (*ppInfo)->idx); + } else { + /* We didn't find one to update. So find a free slot in the + * LIM TSPEC list and add this new entry + */ + uint8_t ctspec = 0; + for (ctspec = 0, pTspecList = &pMac->lim.tspecInfo[0]; + ctspec < LIM_NUM_TSPEC_MAX; + ctspec++, pTspecList++) { + if (!pTspecList->inuse) { + lim_log(pMac, LOG1, + FL + ("Found free slot in TSPEC list. Add to TSPEC table entry %d"), + ctspec); + break; + } + } + + if (ctspec >= LIM_NUM_TSPEC_MAX) + return eSIR_FAILURE; + + /* Record the new index entry */ + pTspecList->idx = ctspec; + } + } + + /* update the tspec info */ + pTspecList->tspec = *pTspec; + pTspecList->assocId = assocId; + qdf_mem_copy(pTspecList->staAddr, pAddr, sizeof(pTspecList->staAddr)); + + /* for edca tspec's, we are all done */ + if (pTspec->tsinfo.traffic.accessPolicy == SIR_MAC_ACCESSPOLICY_EDCA) { + pTspecList->inuse = 1; + *ppInfo = pTspecList; + lim_log(pMac, ADMIT_CONTROL_LOGLEVEL, + FL("added entry for EDCA AccessPolicy")); + return eSIR_SUCCESS; + } + + /* + * for hcca tspec's, must set the parameterized bit in the queues + * the 'ts' bit in the queue data structure indicates that the queue is + * parameterized (hcca). When the schedule is written this bit is used + * in the tsid field (bit 3) and the other three bits (0-2) are simply + * filled in as the user priority (or qid). This applies only to uplink + * polls where the qos control field must contain the tsid specified in the + * tspec. + */ + pTspecList->inuse = 1; + *ppInfo = pTspecList; + lim_log(pMac, ADMIT_CONTROL_LOGLEVEL, + FL("added entry for HCCA AccessPolicy")); + return eSIR_SUCCESS; +} + +/** ------------------------------------------------------------- + \fn lim_validate_access_policy + \brief Validates Access policy + \param tpAniSirGlobal pMac + \param uint8_t accessPolicy + \param uint16_t assocId + \return eSirRetStatus - status + -------------------------------------------------------------*/ + +static tSirRetStatus +lim_validate_access_policy(tpAniSirGlobal pMac, + uint8_t accessPolicy, + uint16_t assocId, tpPESession psessionEntry) +{ + tSirRetStatus retval = eSIR_FAILURE; + tpDphHashNode pSta = + dph_get_hash_entry(pMac, assocId, &psessionEntry->dph.dphHashTable); + + if ((pSta == NULL) || (!pSta->valid)) { + PELOGE(lim_log(pMac, LOGE, FL("invalid station address passed"));) + return eSIR_FAILURE; + } + + switch (accessPolicy) { + case SIR_MAC_ACCESSPOLICY_EDCA: + if (pSta->wmeEnabled || pSta->lleEnabled) + retval = eSIR_SUCCESS; + break; + + case SIR_MAC_ACCESSPOLICY_HCCA: + case SIR_MAC_ACCESSPOLICY_BOTH: + default: + PELOGE(lim_log + (pMac, LOGE, FL("Invalid accessPolicy %d"), + accessPolicy); + ) + break; + } + + if (retval != eSIR_SUCCESS) + lim_log(pMac, LOGW, + FL + ("failed (accPol %d, staId %d, lle %d, wme %d, wsm %d)"), + accessPolicy, pSta->staIndex, pSta->lleEnabled, + pSta->wmeEnabled, pSta->wsmEnabled); + + return retval; +} + +/** + * lim_admit_control_add_ts() - Check if STA can be admitted + * @pMac: Global MAC context + * @pAddr: Address + * @pAddts: ADD TS + * @pQos: QOS fields + * @assocId: Association ID + * @alloc: Allocate bandwidth for this tspec + * @pSch: Schedule IE + * @pTspecIdx: TSPEC index + * @psessionEntry: PE Session Entry + * + * Determine if STA with the specified TSPEC can be admitted. If it can, + * a schedule element is provided + * + * Return: status + **/ +tSirRetStatus lim_admit_control_add_ts(tpAniSirGlobal pMac, uint8_t *pAddr, + tSirAddtsReqInfo *pAddts, tSirMacQosCapabilityStaIE *pQos, + uint16_t assocId, uint8_t alloc, tSirMacScheduleIE *pSch, + uint8_t *pTspecIdx, tpPESession psessionEntry) +{ + tpLimTspecInfo pTspecInfo; + tSirRetStatus retval; + uint32_t svcInterval; + (void)pQos; + + /* TBD: modify tspec as needed */ + /* EDCA: need to fill in the medium time and the minimum phy rate */ + /* to be consistent with the desired traffic parameters. */ + + lim_log(pMac, ADMIT_CONTROL_LOGLEVEL, + FL + ("tsid %d, directn %d, start %d, intvl %d, accPolicy %d, up %d"), + pAddts->tspec.tsinfo.traffic.tsid, + pAddts->tspec.tsinfo.traffic.direction, + pAddts->tspec.svcStartTime, pAddts->tspec.minSvcInterval, + pAddts->tspec.tsinfo.traffic.accessPolicy, + pAddts->tspec.tsinfo.traffic.userPrio); + + /* check for duplicate tspec */ + retval = (alloc) + ? lim_tspec_find_by_assoc_id(pMac, assocId, &pAddts->tspec, + &pMac->lim.tspecInfo[0], &pTspecInfo) + : lim_tspec_find_by_sta_addr(pMac, pAddr, &pAddts->tspec, + &pMac->lim.tspecInfo[0], &pTspecInfo); + + if (retval == eSIR_SUCCESS) { + lim_log(pMac, ADMIT_CONTROL_LOGLEVEL, + FL("duplicate tspec (index %d)!"), pTspecInfo->idx); + return eSIR_FAILURE; + } + /* check that the tspec's are well formed and acceptable */ + if (lim_validate_tspec(pMac, &pAddts->tspec, psessionEntry) != + eSIR_SUCCESS) { + PELOGW(lim_log(pMac, LOGW, FL("tspec validation failed"));) + return eSIR_FAILURE; + } + /* determine a service interval for the tspec */ + if (lim_calculate_svc_int(pMac, &pAddts->tspec, &svcInterval) != + eSIR_SUCCESS) { + PELOGW(lim_log(pMac, LOGW, FL("SvcInt calculate failed"));) + return eSIR_FAILURE; + } + /* determine if the tspec can be admitted or not based on current policy */ + if (lim_admit_policy(pMac, &pAddts->tspec, psessionEntry) != eSIR_SUCCESS) { + PELOGW(lim_log + (pMac, LOGW, + FL("tspec rejected by admit control policy")); + ) + return eSIR_FAILURE; + } + /* fill in a schedule if requested */ + if (pSch != NULL) { + qdf_mem_set((uint8_t *) pSch, sizeof(*pSch), 0); + pSch->svcStartTime = pAddts->tspec.svcStartTime; + pSch->svcInterval = svcInterval; + pSch->maxSvcDuration = (uint16_t) pSch->svcInterval; /* use SP = SI */ + pSch->specInterval = 0x1000; /* fixed for now: TBD */ + + pSch->info.direction = pAddts->tspec.tsinfo.traffic.direction; + pSch->info.tsid = pAddts->tspec.tsinfo.traffic.tsid; + pSch->info.aggregation = 0; /* no support for aggregation for now: TBD */ + } + /* if no allocation is requested, done */ + if (!alloc) + return eSIR_SUCCESS; + + /* check that we are in the proper mode to deal with the tspec type */ + if (lim_validate_access_policy + (pMac, (uint8_t) pAddts->tspec.tsinfo.traffic.accessPolicy, assocId, + psessionEntry) != eSIR_SUCCESS) { + lim_log(pMac, LOGW, + FL("AccessPolicy %d is not valid in current mode"), + pAddts->tspec.tsinfo.traffic.accessPolicy); + return eSIR_FAILURE; + } + /* add tspec to list */ + if (lim_tspec_add + (pMac, pAddr, assocId, &pAddts->tspec, svcInterval, &pTspecInfo) + != eSIR_SUCCESS) { + PELOGE(lim_log(pMac, LOGE, FL("no space in tspec list"));) + return eSIR_FAILURE; + } + /* passing lim tspec table index to the caller */ + *pTspecIdx = pTspecInfo->idx; + + return eSIR_SUCCESS; +} + +/** ------------------------------------------------------------- + \fn lim_admit_control_delete_ts + \brief Delete the specified Tspec for the specified STA + \param tpAniSirGlobal pMac + \param uint16_t assocId + \param tSirMacTSInfo *pTsInfo + \param uint8_t *pTsStatus + \param uint8_t *ptspecIdx + \return eSirRetStatus - status + -------------------------------------------------------------*/ + +tSirRetStatus +lim_admit_control_delete_ts(tpAniSirGlobal pMac, + uint16_t assocId, + tSirMacTSInfo *pTsInfo, + uint8_t *pTsStatus, uint8_t *ptspecIdx) +{ + tpLimTspecInfo pTspecInfo = NULL; + + if (pTsStatus != NULL) + *pTsStatus = 0; + + if (lim_find_tspec + (pMac, assocId, pTsInfo, &pMac->lim.tspecInfo[0], + &pTspecInfo) == eSIR_SUCCESS) { + if (pTspecInfo != NULL) { + lim_log(pMac, ADMIT_CONTROL_LOGLEVEL, + FL("Tspec entry %d found"), pTspecInfo->idx); + + *ptspecIdx = pTspecInfo->idx; + lim_tspec_delete(pMac, pTspecInfo); + return eSIR_SUCCESS; + } + } + return eSIR_FAILURE; +} + +/** ------------------------------------------------------------- + \fn lim_admit_control_delete_sta + \brief Delete all TSPEC for the specified STA + \param tpAniSirGlobal pMac + \param uint16_t assocId + \return eSirRetStatus - status + -------------------------------------------------------------*/ + +tSirRetStatus lim_admit_control_delete_sta(tpAniSirGlobal pMac, uint16_t assocId) +{ + tpLimTspecInfo pTspecInfo = &pMac->lim.tspecInfo[0]; + int ctspec; + + for (ctspec = 0; ctspec < LIM_NUM_TSPEC_MAX; ctspec++, pTspecInfo++) { + if (assocId == pTspecInfo->assocId) { + lim_tspec_delete(pMac, pTspecInfo); + lim_log(pMac, ADMIT_CONTROL_LOGLEVEL, + FL("Deleting TSPEC %d for assocId %d"), ctspec, + assocId); + } + } + lim_log(pMac, ADMIT_CONTROL_LOGLEVEL, FL("assocId %d done"), assocId); + + return eSIR_SUCCESS; +} + +/** ------------------------------------------------------------- + \fn lim_admit_control_init + \brief init tspec table + \param tpAniSirGlobal pMac + \return eSirRetStatus - status + -------------------------------------------------------------*/ +tSirRetStatus lim_admit_control_init(tpAniSirGlobal pMac) +{ + qdf_mem_set(pMac->lim.tspecInfo, + LIM_NUM_TSPEC_MAX * sizeof(tLimTspecInfo), 0); + return eSIR_SUCCESS; +} + +/** ------------------------------------------------------------- + \fn lim_update_admit_policy + \brief Set the admit control policy based on CFG parameters + \param tpAniSirGlobal pMac + \return eSirRetStatus - status + -------------------------------------------------------------*/ + +tSirRetStatus lim_update_admit_policy(tpAniSirGlobal pMac) +{ + uint32_t val; + if (wlan_cfg_get_int(pMac, WNI_CFG_ADMIT_POLICY, &val) != eSIR_SUCCESS) { + lim_log(pMac, LOGP, FL("Unable to get CFG_ADMIT_POLICY")); + return eSIR_FAILURE; + } + pMac->lim.admitPolicyInfo.type = (uint8_t) val; + if (wlan_cfg_get_int(pMac, WNI_CFG_ADMIT_BWFACTOR, &val) != eSIR_SUCCESS) { + lim_log(pMac, LOGP, FL("Unable to get CFG_ADMIT_BWFACTOR")); + return eSIR_FAILURE; + } + pMac->lim.admitPolicyInfo.bw_factor = (uint8_t) val; + + PELOG1(lim_log(pMac, LOG1, FL("LIM: AdmitPolicy %d, bw_factor %d"), + pMac->lim.admitPolicyInfo.type, + pMac->lim.admitPolicyInfo.bw_factor); + ) + + return eSIR_SUCCESS; +} + +/** ------------------------------------------------------------- + \fn lim_send_hal_msg_add_ts + \brief Send halMsg_AddTs to HAL + \param tpAniSirGlobal pMac + \param uint16_t staIdx + \param uint8_t tspecIdx + \param tSirMacTspecIE tspecIE + \param tSirTclasInfo *tclasInfo + \param uint8_t tclasProc + \param uint16_t tsm_interval + \return eSirRetStatus - status + -------------------------------------------------------------*/ +#ifdef FEATURE_WLAN_ESE +tSirRetStatus +lim_send_hal_msg_add_ts(tpAniSirGlobal pMac, + uint16_t staIdx, + uint8_t tspecIdx, + tSirMacTspecIE tspecIE, + uint8_t sessionId, uint16_t tsm_interval) +#else +tSirRetStatus +lim_send_hal_msg_add_ts(tpAniSirGlobal pMac, + uint16_t staIdx, + uint8_t tspecIdx, tSirMacTspecIE tspecIE, uint8_t sessionId) +#endif +{ + tSirMsgQ msg; + tpAddTsParams pAddTsParam; + + tpPESession psessionEntry = pe_find_session_by_session_id(pMac, sessionId); + if (psessionEntry == NULL) { + lim_log(pMac, LOGP, + FL("Unable to get Session for session Id %d"), + sessionId); + return eSIR_FAILURE; + } + + pAddTsParam = qdf_mem_malloc(sizeof(tAddTsParams)); + if (NULL == pAddTsParam) { + PELOGW(lim_log(pMac, LOGW, FL("AllocateMemory() failed"));) + return eSIR_MEM_ALLOC_FAILED; + } + + pAddTsParam->staIdx = staIdx; + pAddTsParam->tspecIdx = tspecIdx; + qdf_mem_copy(&pAddTsParam->tspec, &tspecIE, sizeof(tSirMacTspecIE)); + pAddTsParam->sessionId = sessionId; + pAddTsParam->sme_session_id = psessionEntry->smeSessionId; + +#ifdef FEATURE_WLAN_ESE + pAddTsParam->tsm_interval = tsm_interval; +#endif +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + if (pMac->roam.configParam.isRoamOffloadEnabled && + psessionEntry->is11Rconnection) + pAddTsParam->setRICparams = 1; +#endif + + msg.type = WMA_ADD_TS_REQ; + msg.bodyptr = pAddTsParam; + msg.bodyval = 0; + + /* We need to defer any incoming messages until we get a + * WMA_ADD_TS_RSP from HAL. + */ + SET_LIM_PROCESS_DEFD_MESGS(pMac, false); + MTRACE(mac_trace_msg_tx(pMac, sessionId, msg.type)); + + if (eSIR_SUCCESS != wma_post_ctrl_msg(pMac, &msg)) { + lim_log(pMac, LOGW, FL("wma_post_ctrl_msg() failed")); + SET_LIM_PROCESS_DEFD_MESGS(pMac, true); + qdf_mem_free(pAddTsParam); + return eSIR_FAILURE; + } + return eSIR_SUCCESS; +} + +/** ------------------------------------------------------------- + \fn lim_send_hal_msg_del_ts + \brief Send halMsg_AddTs to HAL + \param tpAniSirGlobal pMac + \param uint16_t staIdx + \param uint8_t tspecIdx + \param tSirAddtsReqInfo addts + \return eSirRetStatus - status + -------------------------------------------------------------*/ + +tSirRetStatus +lim_send_hal_msg_del_ts(tpAniSirGlobal pMac, + uint16_t staIdx, + uint8_t tspecIdx, + tSirDeltsReqInfo delts, uint8_t sessionId, uint8_t *bssId) +{ + tSirMsgQ msg; + tpDelTsParams pDelTsParam; + tpPESession psessionEntry = NULL; + + pDelTsParam = qdf_mem_malloc(sizeof(tDelTsParams)); + if (NULL == pDelTsParam) { + lim_log(pMac, LOGP, FL("AllocateMemory() failed")); + return eSIR_MEM_ALLOC_FAILED; + } + + msg.type = WMA_DEL_TS_REQ; + msg.bodyptr = pDelTsParam; + msg.bodyval = 0; + + /* filling message parameters. */ + pDelTsParam->staIdx = staIdx; + pDelTsParam->tspecIdx = tspecIdx; + qdf_mem_copy(&pDelTsParam->bssId, bssId, sizeof(tSirMacAddr)); + + psessionEntry = pe_find_session_by_session_id(pMac, sessionId); + if (psessionEntry == NULL) { + PELOGE(lim_log(pMac, LOGE, + FL + ("Session does Not exist with given sessionId :%d "), + sessionId); + ) + goto err; + } + pDelTsParam->sessionId = psessionEntry->smeSessionId; + pDelTsParam->userPrio = delts.wmeTspecPresent ? + delts.tspec.tsinfo.traffic.userPrio : + delts.tsinfo.traffic.userPrio; + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + if (pMac->roam.configParam.isRoamOffloadEnabled && + psessionEntry->is11Rconnection) { + qdf_mem_copy(&pDelTsParam->delTsInfo, &delts, + sizeof(tSirDeltsReqInfo)); + pDelTsParam->setRICparams = 1; + } +#endif + + lim_log(pMac, LOGW, FL("calling wma_post_ctrl_msg()")); + MTRACE(mac_trace_msg_tx(pMac, sessionId, msg.type)); + + if (eSIR_SUCCESS != wma_post_ctrl_msg(pMac, &msg)) { + lim_log(pMac, LOGW, FL("wma_post_ctrl_msg() failed")); + goto err; + } + return eSIR_SUCCESS; + +err: + qdf_mem_free(pDelTsParam); + return eSIR_FAILURE; +} + +/** ------------------------------------------------------------- + \fn lim_process_hal_add_ts_rsp + \brief This function process the WMA_ADD_TS_RSP from HAL. + \ If response is successful, then send back SME_ADDTS_RSP. + \ Otherwise, send DELTS action frame to peer and then + \ then send back SME_ADDTS_RSP. + \ + \param tpAniSirGlobal pMac + \param tpSirMsgQ limMsg + -------------------------------------------------------------*/ +void lim_process_hal_add_ts_rsp(tpAniSirGlobal pMac, tpSirMsgQ limMsg) +{ + tpAddTsParams pAddTsRspMsg = NULL; + tpDphHashNode pSta = NULL; + uint16_t assocId = 0; + tSirMacAddr peerMacAddr; + uint8_t rspReqd = 1; + tpPESession psessionEntry = NULL; + + /* Need to process all the deferred messages enqueued + * since sending the WMA_ADD_TS_REQ. + */ + SET_LIM_PROCESS_DEFD_MESGS(pMac, true); + + if (NULL == limMsg->bodyptr) { + lim_log(pMac, LOGP, FL("Received WMA_ADD_TS_RSP with NULL ")); + goto end; + } + + pAddTsRspMsg = (tpAddTsParams) (limMsg->bodyptr); + + /* 090803: Use pe_find_session_by_session_id() to obtain the PE session context */ + /* from the sessionId in the Rsp Msg from HAL */ + psessionEntry = pe_find_session_by_session_id(pMac, pAddTsRspMsg->sessionId); + + if (psessionEntry == NULL) { + PELOGE(lim_log + (pMac, LOGE, + FL("Session does Not exist with given sessionId :%d "), + pAddTsRspMsg->sessionId); + ) + lim_send_sme_addts_rsp(pMac, rspReqd, eSIR_SME_ADDTS_RSP_FAILED, + psessionEntry, pAddTsRspMsg->tspec, + pMac->lim.gLimAddtsReq.sessionId, + pMac->lim.gLimAddtsReq.transactionId); + goto end; + } + + if (pAddTsRspMsg->status == QDF_STATUS_SUCCESS) { + PELOG1(lim_log + (pMac, LOG1, + FL("Received successful ADDTS response from HAL ")); + ) + /* Use the smesessionId and smetransactionId from the PE session context */ + lim_send_sme_addts_rsp(pMac, rspReqd, eSIR_SME_SUCCESS, + psessionEntry, pAddTsRspMsg->tspec, + psessionEntry->smeSessionId, + psessionEntry->transactionId); + goto end; + } else { + PELOG1(lim_log + (pMac, LOG1, + FL("Received failure ADDTS response from HAL ")); + ) + /* Send DELTS action frame to AP */ + /* 090803: Get peer MAC addr from session */ + sir_copy_mac_addr(peerMacAddr, psessionEntry->bssId); + + /* 090803: Add the SME Session ID */ + lim_send_delts_req_action_frame(pMac, peerMacAddr, rspReqd, + &pAddTsRspMsg->tspec.tsinfo, + &pAddTsRspMsg->tspec, psessionEntry); + + /* Delete TSPEC */ + /* 090803: Pull the hash table from the session */ + pSta = dph_lookup_assoc_id(pMac, pAddTsRspMsg->staIdx, &assocId, + &psessionEntry->dph.dphHashTable); + if (pSta != NULL) + lim_admit_control_delete_ts(pMac, assocId, + &pAddTsRspMsg->tspec.tsinfo, + NULL, + (uint8_t *) &pAddTsRspMsg-> + tspecIdx); + + /* Send SME_ADDTS_RSP */ + /* 090803: Use the smesessionId and smetransactionId from the PE session context */ + lim_send_sme_addts_rsp(pMac, rspReqd, eSIR_SME_ADDTS_RSP_FAILED, + psessionEntry, pAddTsRspMsg->tspec, + psessionEntry->smeSessionId, + psessionEntry->transactionId); + goto end; + } + +end: + if (pAddTsRspMsg != NULL) + qdf_mem_free(pAddTsRspMsg); + return; +} diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_aid_mgmt.c b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_aid_mgmt.c new file mode 100644 index 0000000000000000000000000000000000000000..c1c0b48398d3680bf96dfd7f27892d611340e5d1 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_aid_mgmt.c @@ -0,0 +1,186 @@ +/* + * Copyright (c) 2011-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * + * This file lim_aid_mgmt.c contains the functions related to + * AID pool management like initialization, assignment etc. + * Author: Chandra Modumudi + * Date: 03/20/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + */ + +#include "cds_api.h" +#include "wni_cfg.h" +#include "ani_global.h" +#include "cfg_api.h" +#include "sir_params.h" +#include "lim_utils.h" +#include "lim_timer_utils.h" +#include "lim_ft_defs.h" +#include "lim_session.h" +#include "lim_session_utils.h" + +#define LIM_START_PEER_IDX 1 + +/** + * lim_init_peer_idxpool() -- initializes peer index pool + * @pMac: mac context + * @pSessionEntry: session entry + * + * This function is called while starting a BSS at AP + * to initialize AID pool. This may also be called while + * starting/joining an IBSS if 'Association' is allowed + * in IBSS. + * + * Return: None + */ + +void lim_init_peer_idxpool(tpAniSirGlobal pMac, tpPESession pSessionEntry) +{ + uint8_t i; + uint8_t maxAssocSta = pMac->lim.maxStation; + + pSessionEntry->gpLimPeerIdxpool[0] = 0; + +#ifdef FEATURE_WLAN_TDLS + /* + * In station role, DPH_STA_HASH_INDEX_PEER (index 1) is reserved + * for peer station index corresponding to AP. Avoid choosing that index + * and get index starting from (DPH_STA_HASH_INDEX_PEER + 1) + * (index 2) for TDLS stations; + */ + if (LIM_IS_STA_ROLE(pSessionEntry)) { + pSessionEntry->freePeerIdxHead = DPH_STA_HASH_INDEX_PEER + 1; + } else +#endif +#ifdef QCA_IBSS_SUPPORT + if (LIM_IS_IBSS_ROLE(pSessionEntry)) { + pSessionEntry->freePeerIdxHead = LIM_START_PEER_IDX; + } else +#endif + { + pSessionEntry->freePeerIdxHead = LIM_START_PEER_IDX; + } + + for (i = pSessionEntry->freePeerIdxHead; i < maxAssocSta; i++) { + pSessionEntry->gpLimPeerIdxpool[i] = i + 1; + } + pSessionEntry->gpLimPeerIdxpool[i] = 0; + + pSessionEntry->freePeerIdxTail = i; + +} + +/** + * lim_assign_peer_idx() + * + ***FUNCTION: + * This function is called to get a peer station index. This index is + * used during Association/Reassociation + * frame handling to assign association ID (aid) to a STA. + * In case of TDLS, this is used to assign a index into the Dph hash entry. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * + * @param pMac - Pointer to Global MAC structure + * @return peerIdx - assigned peer Station IDx for STA + */ + +uint16_t lim_assign_peer_idx(tpAniSirGlobal pMac, tpPESession pSessionEntry) +{ + uint16_t peerId; + + /* make sure we haven't exceeded the configurable limit on associations */ + /* This count is global to ensure that it doesnt exceed the hardware limits. */ + if (pe_get_current_stas_count(pMac) >= pMac->lim.gLimAssocStaLimit) { + /* too many associations already active */ + return 0; + } + + /* return head of free list */ + + if (pSessionEntry->freePeerIdxHead) { + peerId = pSessionEntry->freePeerIdxHead; + pSessionEntry->freePeerIdxHead = + pSessionEntry->gpLimPeerIdxpool[pSessionEntry-> + freePeerIdxHead]; + if (pSessionEntry->freePeerIdxHead == 0) + pSessionEntry->freePeerIdxTail = 0; + pSessionEntry->gLimNumOfCurrentSTAs++; + return peerId; + } + + return 0; /* no more free peer index */ +} + +/** + * lim_release_peer_idx() + * + ***FUNCTION: + * This function is called when a STA context is removed + * at AP (or at a STA in IBSS mode or TDLS) to return peer Index + * to free pool. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * + * @param pMac - Pointer to Global MAC structure + * @param peerIdx - peer station index that need to return to free pool + * + * @return None + */ + +void +lim_release_peer_idx(tpAniSirGlobal pMac, uint16_t peerIdx, + tpPESession pSessionEntry) +{ + pSessionEntry->gLimNumOfCurrentSTAs--; + + /* insert at tail of free list */ + if (pSessionEntry->freePeerIdxTail) { + pSessionEntry->gpLimPeerIdxpool[pSessionEntry-> + freePeerIdxTail] = + (uint8_t) peerIdx; + pSessionEntry->freePeerIdxTail = (uint8_t) peerIdx; + } else { + pSessionEntry->freePeerIdxTail = + pSessionEntry->freePeerIdxHead = (uint8_t) peerIdx; + } + pSessionEntry->gpLimPeerIdxpool[(uint8_t) peerIdx] = 0; +} diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_api.c b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_api.c new file mode 100644 index 0000000000000000000000000000000000000000..039ae3e2a01081dbb3573b1ef9ec9e18e94e88d9 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_api.c @@ -0,0 +1,2474 @@ +/* + * Copyright (c) 2011-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * This file lim_api.cc contains the functions that are + * exported by LIM to other modules. + * + * Author: Chandra Modumudi + * Date: 02/11/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + * + */ +#include "cds_api.h" +#include "wni_cfg.h" +#include "wni_api.h" +#include "sir_common.h" +#include "sir_debug.h" +#include "cfg_api.h" + +#include "sch_api.h" +#include "utils_api.h" +#include "lim_api.h" +#include "lim_global.h" +#include "lim_types.h" +#include "lim_utils.h" +#include "lim_assoc_utils.h" +#include "lim_prop_exts_utils.h" +#include "lim_ser_des_utils.h" +#include "lim_ibss_peer_mgmt.h" +#include "lim_admit_control.h" +#include "lim_send_sme_rsp_messages.h" +#include "wmm_apsd.h" +#include "lim_trace.h" +#include "lim_ft_defs.h" +#include "lim_session.h" +#include "wma_types.h" + +#include "rrm_api.h" + +#include +#include "qdf_types.h" +#include "cds_packet.h" +#include "cds_utils.h" +#include "sys_startup.h" +#include "cds_concurrency.h" +#include "nan_datapath.h" + +static void __lim_init_scan_vars(tpAniSirGlobal pMac) +{ + pMac->lim.gLimUseScanModeForLearnMode = 1; + + pMac->lim.gLimSystemInScanLearnMode = 0; + + /* Scan related globals on STA */ + pMac->lim.gLimReturnAfterFirstMatch = 0; + pMac->lim.gLim24Band11dScanDone = 0; + pMac->lim.gLim50Band11dScanDone = 0; + pMac->lim.gLimReturnUniqueResults = 0; + + pMac->lim.gLimCurrentScanChannelId = 0; + pMac->lim.gpLimMlmScanReq = NULL; + pMac->lim.gDeferMsgTypeForNOA = 0; + pMac->lim.gpDefdSmeMsgForNOA = NULL; + + pMac->lim.gLimRestoreCBNumScanInterval = + LIM_RESTORE_CB_NUM_SCAN_INTERVAL_DEFAULT; + pMac->lim.gLimRestoreCBCount = 0; + qdf_mem_set(pMac->lim.gLimLegacyBssidList, + sizeof(pMac->lim.gLimLegacyBssidList), 0); + + /* Fill in default values */ + + /* abort scan is used to abort an on-going scan */ + pMac->lim.abortScan = 0; + qdf_mem_set(&pMac->lim.scanChnInfo, sizeof(tLimScanChnInfo), 0); + qdf_mem_set(&pMac->lim.dfschannelList, sizeof(tSirDFSChannelList), 0); + +/* WLAN_SUSPEND_LINK Related */ + pMac->lim.gpLimSuspendCallback = NULL; + pMac->lim.gpLimResumeCallback = NULL; +/* end WLAN_SUSPEND_LINK Related */ +} + +static void __lim_init_bss_vars(tpAniSirGlobal pMac) +{ + qdf_mem_set((void *)pMac->lim.gpSession, + sizeof(*pMac->lim.gpSession) * pMac->lim.maxBssId, 0); + + /* This is for testing purposes only, be default should always be off */ + pMac->lim.gLimForceNoPropIE = 0; + pMac->lim.gpLimMlmSetKeysReq = NULL; +} + +static void __lim_init_stats_vars(tpAniSirGlobal pMac) +{ + pMac->lim.gLimNumBeaconsRcvd = 0; + pMac->lim.gLimNumBeaconsIgnored = 0; + + pMac->lim.gLimNumDeferredMsgs = 0; + + /* / Variable to keep track of number of currently associated STAs */ + pMac->lim.gLimNumOfAniSTAs = 0; /* count of ANI peers */ + + /* Heart-Beat interval value */ + pMac->lim.gLimHeartBeatCount = 0; + + qdf_mem_zero(pMac->lim.gLimHeartBeatApMac[0], + sizeof(tSirMacAddr)); + qdf_mem_zero(pMac->lim.gLimHeartBeatApMac[1], + sizeof(tSirMacAddr)); + pMac->lim.gLimHeartBeatApMacIndex = 0; + + /* Statistics to keep track of no. beacons rcvd in heart beat interval */ + qdf_mem_set(pMac->lim.gLimHeartBeatBeaconStats, + sizeof(pMac->lim.gLimHeartBeatBeaconStats), 0); + +#ifdef WLAN_DEBUG + /* Debug counters */ + pMac->lim.numTot = 0; + pMac->lim.numBbt = 0; + pMac->lim.numProtErr = 0; + pMac->lim.numLearn = 0; + pMac->lim.numLearnIgnore = 0; + pMac->lim.numSme = 0; + qdf_mem_set(pMac->lim.numMAC, sizeof(pMac->lim.numMAC), 0); + pMac->lim.gLimNumAssocReqDropInvldState = 0; + pMac->lim.gLimNumAssocReqDropACRejectTS = 0; + pMac->lim.gLimNumAssocReqDropACRejectSta = 0; + pMac->lim.gLimNumReassocReqDropInvldState = 0; + pMac->lim.gLimNumHashMissIgnored = 0; + pMac->lim.gLimUnexpBcnCnt = 0; + pMac->lim.gLimBcnSSIDMismatchCnt = 0; + pMac->lim.gLimNumLinkEsts = 0; + pMac->lim.gLimNumRxCleanup = 0; + pMac->lim.gLim11bStaAssocRejectCount = 0; +#endif +} + +static void __lim_init_states(tpAniSirGlobal pMac) +{ + /* Counts Heartbeat failures */ + pMac->lim.gLimHBfailureCntInLinkEstState = 0; + pMac->lim.gLimProbeFailureAfterHBfailedCnt = 0; + pMac->lim.gLimHBfailureCntInOtherStates = 0; + pMac->lim.gLimRspReqd = 0; + pMac->lim.gLimPrevSmeState = eLIM_SME_OFFLINE_STATE; + + /* / MLM State visible across all Sirius modules */ + MTRACE(mac_trace + (pMac, TRACE_CODE_MLM_STATE, NO_SESSION, eLIM_MLM_IDLE_STATE)); + pMac->lim.gLimMlmState = eLIM_MLM_IDLE_STATE; + + /* / Previous MLM State */ + pMac->lim.gLimPrevMlmState = eLIM_MLM_OFFLINE_STATE; + + /* LIM to HAL SCAN Management Message Interface states */ + pMac->lim.gLimHalScanState = eLIM_HAL_IDLE_SCAN_STATE; + + /** + * Initialize state to eLIM_SME_OFFLINE_STATE + */ + pMac->lim.gLimSmeState = eLIM_SME_OFFLINE_STATE; + + /** + * By default assume 'unknown' role. This will be updated + * when SME_START_BSS_REQ is received. + */ + + qdf_mem_set(&pMac->lim.gLimOverlap11gParams, sizeof(tLimProtStaParams), + 0); + qdf_mem_set(&pMac->lim.gLimOverlap11aParams, sizeof(tLimProtStaParams), + 0); + qdf_mem_set(&pMac->lim.gLimOverlapHt20Params, sizeof(tLimProtStaParams), + 0); + qdf_mem_set(&pMac->lim.gLimOverlapNonGfParams, + sizeof(tLimProtStaParams), 0); + qdf_mem_set(&pMac->lim.gLimNoShortParams, sizeof(tLimNoShortParams), 0); + qdf_mem_set(&pMac->lim.gLimNoShortSlotParams, + sizeof(tLimNoShortSlotParams), 0); + + pMac->lim.gLimPhyMode = 0; + pMac->lim.scanStartTime = 0; /* used to measure scan time */ + + qdf_mem_set(pMac->lim.gLimMyMacAddr, sizeof(pMac->lim.gLimMyMacAddr), + 0); + pMac->lim.ackPolicy = 0; + + pMac->lim.gLimProbeRespDisableFlag = 0; /* control over probe resp */ +} + +static void __lim_init_vars(tpAniSirGlobal pMac) +{ + /* Place holder for Measurement Req/Rsp/Ind related info */ + + + /* Deferred Queue Paramters */ + qdf_mem_set(&pMac->lim.gLimDeferredMsgQ, sizeof(tSirAddtsReq), 0); + + /* addts request if any - only one can be outstanding at any time */ + qdf_mem_set(&pMac->lim.gLimAddtsReq, sizeof(tSirAddtsReq), 0); + pMac->lim.gLimAddtsSent = 0; + pMac->lim.gLimAddtsRspTimerCount = 0; + + /* protection related config cache */ + qdf_mem_set(&pMac->lim.cfgProtection, sizeof(tCfgProtection), 0); + pMac->lim.gLimProtectionControl = 0; + SET_LIM_PROCESS_DEFD_MESGS(pMac, true); + + /* WMM Related Flag */ + pMac->lim.gUapsdEnable = 0; + + /* QoS-AC Downgrade: Initially, no AC is admitted */ + pMac->lim.gAcAdmitMask[SIR_MAC_DIRECTION_UPLINK] = 0; + pMac->lim.gAcAdmitMask[SIR_MAC_DIRECTION_DNLINK] = 0; + + /* dialogue token List head/tail for Action frames request sent. */ + pMac->lim.pDialogueTokenHead = NULL; + pMac->lim.pDialogueTokenTail = NULL; + + qdf_mem_set(&pMac->lim.tspecInfo, + sizeof(tLimTspecInfo) * LIM_NUM_TSPEC_MAX, 0); + + /* admission control policy information */ + qdf_mem_set(&pMac->lim.admitPolicyInfo, sizeof(tLimAdmitPolicyInfo), 0); + + pMac->lim.gLastBeaconDtimCount = 0; + pMac->lim.gLastBeaconDtimPeriod = 0; + + /* Scan in Power Save Flag */ + pMac->lim.gScanInPowersave = 0; + pMac->lim.probeCounter = 0; + pMac->lim.maxProbe = 0; +} + +static void __lim_init_assoc_vars(tpAniSirGlobal pMac) +{ + uint32_t val; + if (wlan_cfg_get_int(pMac, WNI_CFG_ASSOC_STA_LIMIT, &val) + != eSIR_SUCCESS) + lim_log(pMac, LOGP, FL("cfg get assoc sta limit failed")); + pMac->lim.gLimAssocStaLimit = val; + pMac->lim.gLimIbssStaLimit = val; + /* Place holder for current authentication request */ + /* being handled */ + pMac->lim.gpLimMlmAuthReq = NULL; + + /* / MAC level Pre-authentication related globals */ + pMac->lim.gLimPreAuthChannelNumber = 0; + pMac->lim.gLimPreAuthType = eSIR_OPEN_SYSTEM; + qdf_mem_set(&pMac->lim.gLimPreAuthPeerAddr, sizeof(tSirMacAddr), 0); + pMac->lim.gLimNumPreAuthContexts = 0; + qdf_mem_set(&pMac->lim.gLimPreAuthTimerTable, sizeof(tLimPreAuthTable), + 0); + + /* Placed holder to deauth reason */ + pMac->lim.gLimDeauthReasonCode = 0; + + /* Place holder for Pre-authentication node list */ + pMac->lim.pLimPreAuthList = NULL; + + /* One cache for each overlap and associated case. */ + qdf_mem_set(pMac->lim.protStaOverlapCache, + sizeof(tCacheParams) * LIM_PROT_STA_OVERLAP_CACHE_SIZE, 0); + qdf_mem_set(pMac->lim.protStaCache, + sizeof(tCacheParams) * LIM_PROT_STA_CACHE_SIZE, 0); + + pMac->lim.pSessionEntry = NULL; + pMac->lim.reAssocRetryAttempt = 0; + +} + +static void __lim_init_ht_vars(tpAniSirGlobal pMac) +{ + pMac->lim.htCapabilityPresentInBeacon = 0; + pMac->lim.gHTGreenfield = 0; + pMac->lim.gHTShortGI40Mhz = 0; + pMac->lim.gHTShortGI20Mhz = 0; + pMac->lim.gHTMaxAmsduLength = 0; + pMac->lim.gHTDsssCckRate40MHzSupport = 0; + pMac->lim.gHTPSMPSupport = 0; + pMac->lim.gHTLsigTXOPProtection = 0; + pMac->lim.gHTMIMOPSState = eSIR_HT_MIMO_PS_STATIC; + pMac->lim.gHTAMpduDensity = 0; + + pMac->lim.gMaxAmsduSizeEnabled = false; + pMac->lim.gHTMaxRxAMpduFactor = 0; + pMac->lim.gHTServiceIntervalGranularity = 0; + pMac->lim.gHTControlledAccessOnly = 0; + pMac->lim.gHTOperMode = eSIR_HT_OP_MODE_PURE; + pMac->lim.gHTPCOActive = 0; + + pMac->lim.gHTPCOPhase = 0; + pMac->lim.gHTSecondaryBeacon = 0; + pMac->lim.gHTDualCTSProtection = 0; + pMac->lim.gHTSTBCBasicMCS = 0; +} + +static tSirRetStatus __lim_init_config(tpAniSirGlobal pMac) +{ + uint32_t val1, val2, val3; + uint16_t val16; + uint8_t val8; + tSirMacHTCapabilityInfo *pHTCapabilityInfo; + tSirMacHTInfoField1 *pHTInfoField1; + tSirMacHTParametersInfo *pAmpduParamInfo; + + /* Read all the CFGs here that were updated before pe_start is called */ + /* All these CFG READS/WRITES are only allowed in init, at start when there is no session + * and they will be used throughout when there is no session + */ + + if (wlan_cfg_get_int(pMac, WNI_CFG_HT_CAP_INFO, &val1) != eSIR_SUCCESS) { + PELOGE(lim_log(pMac, LOGE, FL("could not retrieve HT Cap CFG"));) + return eSIR_FAILURE; + } + + if (wlan_cfg_get_int(pMac, WNI_CFG_CHANNEL_BONDING_MODE, &val2) != + eSIR_SUCCESS) { + PELOGE(lim_log + (pMac, LOGE, + FL("could not retrieve Channel Bonding CFG")); + ) + return eSIR_FAILURE; + } + val16 = (uint16_t) val1; + pHTCapabilityInfo = (tSirMacHTCapabilityInfo *) &val16; + + /* channel bonding mode could be set to anything from 0 to 4(Titan had these */ + /* modes But for Taurus we have only two modes: enable(>0) or disable(=0) */ + pHTCapabilityInfo->supportedChannelWidthSet = val2 ? + WNI_CFG_CHANNEL_BONDING_MODE_ENABLE : + WNI_CFG_CHANNEL_BONDING_MODE_DISABLE; + if (cfg_set_int + (pMac, WNI_CFG_HT_CAP_INFO, *(uint16_t *) pHTCapabilityInfo) + != eSIR_SUCCESS) { + PELOGE(lim_log + (pMac, LOGE, FL("could not update HT Cap Info CFG")); + ) + return eSIR_FAILURE; + } + + if (wlan_cfg_get_int(pMac, WNI_CFG_HT_INFO_FIELD1, &val1) != eSIR_SUCCESS) { + PELOGE(lim_log + (pMac, LOGE, + FL("could not retrieve HT INFO Field1 CFG")); + ) + return eSIR_FAILURE; + } + + val8 = (uint8_t) val1; + pHTInfoField1 = (tSirMacHTInfoField1 *) &val8; + pHTInfoField1->recommendedTxWidthSet = + (uint8_t) pHTCapabilityInfo->supportedChannelWidthSet; + if (cfg_set_int(pMac, WNI_CFG_HT_INFO_FIELD1, *(uint8_t *) pHTInfoField1) + != eSIR_SUCCESS) { + PELOGE(lim_log(pMac, LOGE, FL("could not update HT Info Field"));) + return eSIR_FAILURE; + } + + /* WNI_CFG_HEART_BEAT_THRESHOLD */ + + if (wlan_cfg_get_int(pMac, WNI_CFG_HEART_BEAT_THRESHOLD, &val1) != + eSIR_SUCCESS) { + PELOGE(lim_log + (pMac, LOGE, + FL + ("could not retrieve WNI_CFG_HEART_BEAT_THRESHOLD CFG")); + ) + return eSIR_FAILURE; + } + if (!val1) { + pMac->sys.gSysEnableLinkMonitorMode = 0; + } else { + /* No need to activate the timer during init time. */ + pMac->sys.gSysEnableLinkMonitorMode = 1; + } + + /* WNI_CFG_MAX_RX_AMPDU_FACTOR */ + + if (wlan_cfg_get_int(pMac, WNI_CFG_HT_AMPDU_PARAMS, &val1) != + eSIR_SUCCESS) { + lim_log(pMac, LOGE, FL("could not retrieve HT AMPDU Param")); + return eSIR_FAILURE; + } + if (wlan_cfg_get_int(pMac, WNI_CFG_MAX_RX_AMPDU_FACTOR, &val2) != + eSIR_SUCCESS) { + lim_log(pMac, LOGE, FL("could not retrieve AMPDU Factor CFG")); + return eSIR_FAILURE; + } + if (wlan_cfg_get_int(pMac, WNI_CFG_MPDU_DENSITY, &val3) != + eSIR_SUCCESS) { + lim_log(pMac, LOGE, FL("could not retrieve MPDU Density CFG")); + return eSIR_FAILURE; + } + + val16 = (uint16_t) val1; + pAmpduParamInfo = (tSirMacHTParametersInfo *) &val16; + pAmpduParamInfo->maxRxAMPDUFactor = (uint8_t) val2; + pAmpduParamInfo->mpduDensity = (uint8_t)val3; + if (cfg_set_int + (pMac, WNI_CFG_HT_AMPDU_PARAMS, + *(uint8_t *) pAmpduParamInfo) != eSIR_SUCCESS) { + lim_log(pMac, LOGE, FL("cfg get short preamble failed")); + return eSIR_FAILURE; + } + + /* WNI_CFG_SHORT_PREAMBLE - this one is not updated in + lim_handle_cf_gparam_update do we want to update this? */ + if (wlan_cfg_get_int(pMac, WNI_CFG_SHORT_PREAMBLE, &val1) != eSIR_SUCCESS) { + lim_log(pMac, LOGP, FL("cfg get short preamble failed")); + return eSIR_FAILURE; + } + + /* WNI_CFG_PROBE_RSP_BCN_ADDNIE_DATA - not needed */ + + /* This was initially done after resume notification from HAL. Now, DAL is + started before PE so this can be done here */ + handle_ht_capabilityand_ht_info(pMac, NULL); + if (eSIR_SUCCESS != + wlan_cfg_get_int(pMac, WNI_CFG_DISABLE_LDPC_WITH_TXBF_AP, + (uint32_t *) &pMac->lim.disableLDPCWithTxbfAP)) { + lim_log(pMac, LOGP, FL("cfg get disableLDPCWithTxbfAP failed")); + return eSIR_FAILURE; + } +#ifdef FEATURE_WLAN_TDLS + if (eSIR_SUCCESS != wlan_cfg_get_int(pMac, WNI_CFG_TDLS_BUF_STA_ENABLED, + (uint32_t *) &pMac->lim. + gLimTDLSBufStaEnabled)) { + lim_log(pMac, LOGP, FL("cfg get LimTDLSBufStaEnabled failed")); + return eSIR_FAILURE; + } + if (eSIR_SUCCESS != + wlan_cfg_get_int(pMac, WNI_CFG_TDLS_QOS_WMM_UAPSD_MASK, + (uint32_t *) &pMac->lim.gLimTDLSUapsdMask)) { + lim_log(pMac, LOGP, FL("cfg get LimTDLSUapsdMask failed")); + return eSIR_FAILURE; + } + if (eSIR_SUCCESS != + wlan_cfg_get_int(pMac, WNI_CFG_TDLS_OFF_CHANNEL_ENABLED, + (uint32_t *) &pMac->lim. + gLimTDLSOffChannelEnabled)) { + lim_log(pMac, LOGP, FL("cfg get LimTDLSUapsdMask failed")); + return eSIR_FAILURE; + } + + if (eSIR_SUCCESS != wlan_cfg_get_int(pMac, WNI_CFG_TDLS_WMM_MODE_ENABLED, + (uint32_t *) &pMac->lim. + gLimTDLSWmmMode)) { + lim_log(pMac, LOGP, FL("cfg get LimTDLSWmmMode failed")); + return eSIR_FAILURE; + } +#endif + return eSIR_SUCCESS; +} + +/* + lim_start + This function is to replace the __lim_process_sme_start_req since there is no + eWNI_SME_START_REQ post to PE. + */ +tSirRetStatus lim_start(tpAniSirGlobal pMac) +{ + tSirResultCodes retCode = eSIR_SUCCESS; + + PELOG1(lim_log(pMac, LOG1, FL(" enter"));) + + if (pMac->lim.gLimSmeState == eLIM_SME_OFFLINE_STATE) { + pMac->lim.gLimSmeState = eLIM_SME_IDLE_STATE; + + MTRACE(mac_trace + (pMac, TRACE_CODE_SME_STATE, NO_SESSION, + pMac->lim.gLimSmeState)); + + /* By default do not return after first scan match */ + pMac->lim.gLimReturnAfterFirstMatch = 0; + + /* Initialize MLM state machine */ + if (eSIR_SUCCESS != lim_init_mlm(pMac)) { + lim_log(pMac, LOGE, FL("Init MLM failed.")); + return eSIR_FAILURE; + } + + /* By default return unique scan results */ + pMac->lim.gLimReturnUniqueResults = true; + } else { + /** + * Should not have received eWNI_SME_START_REQ in states + * other than OFFLINE. Return response to host and + * log error + */ + lim_log(pMac, LOGE, FL("Invalid SME state %X"), + pMac->lim.gLimSmeState); + retCode = eSIR_FAILURE; + } + + return retCode; +} + +/** + * lim_initialize() + * + ***FUNCTION: + * This function is called from LIM thread entry function. + * LIM related global data structures are initialized in this function. + * + ***LOGIC: + * NA + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param pMac - Pointer to global MAC structure + * @return None + */ + +tSirRetStatus lim_initialize(tpAniSirGlobal pMac) +{ + tSirRetStatus status = eSIR_SUCCESS; + + __lim_init_assoc_vars(pMac); + __lim_init_vars(pMac); + __lim_init_states(pMac); + __lim_init_stats_vars(pMac); + __lim_init_bss_vars(pMac); + __lim_init_scan_vars(pMac); + __lim_init_ht_vars(pMac); + + status = lim_start(pMac); + if (eSIR_SUCCESS != status) { + return status; + } + /* Initializations for maintaining peers in IBSS */ + lim_ibss_init(pMac); + + rrm_initialize(pMac); + + qdf_mutex_create(&pMac->lim.lim_frame_register_lock); + qdf_list_create(&pMac->lim.gLimMgmtFrameRegistratinQueue, 0); + + /* Initialize the configurations needed by PE */ + if (eSIR_FAILURE == __lim_init_config(pMac)) { + /* We need to undo everything in lim_start */ + lim_cleanup_mlm(pMac); + return eSIR_FAILURE; + } + /* initialize the TSPEC admission control table. */ + /* Note that this was initially done after resume notification from HAL. */ + /* Now, DAL is started before PE so this can be done here */ + lim_admit_control_init(pMac); + lim_register_hal_ind_call_back(pMac); + + return status; + +} /*** end lim_initialize() ***/ + +/** + * lim_cleanup() + * + ***FUNCTION: + * This function is called upon reset or persona change + * to cleanup LIM state + * + ***LOGIC: + * NA + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param pMac - Pointer to Global MAC structure + * @return None + */ + +void lim_cleanup(tpAniSirGlobal pMac) +{ + uint8_t i; + /* + * Before destroying the list making sure all the nodes have been + * deleted Which should be the normal case, but a memory leak has been + * reported + */ + + struct mgmt_frm_reg_info *pLimMgmtRegistration = NULL; + + qdf_mutex_acquire(&pMac->lim.lim_frame_register_lock); + while (qdf_list_remove_front( + &pMac->lim.gLimMgmtFrameRegistratinQueue, + (qdf_list_node_t **) &pLimMgmtRegistration) == + QDF_STATUS_SUCCESS) { + qdf_mem_free(pLimMgmtRegistration); + } + qdf_mutex_release(&pMac->lim.lim_frame_register_lock); + qdf_list_destroy(&pMac->lim.gLimMgmtFrameRegistratinQueue); + qdf_mutex_destroy(&pMac->lim.lim_frame_register_lock); + qdf_mem_free(pMac->lim.gpLimRemainOnChanReq); + pMac->lim.gpLimRemainOnChanReq = NULL; + lim_cleanup_mlm(pMac); + + /* free up preAuth table */ + if (pMac->lim.gLimPreAuthTimerTable.pTable != NULL) { + for (i = 0; i < pMac->lim.gLimPreAuthTimerTable.numEntry; i++) + qdf_mem_free(pMac->lim.gLimPreAuthTimerTable.pTable[i]); + qdf_mem_free(pMac->lim.gLimPreAuthTimerTable.pTable); + pMac->lim.gLimPreAuthTimerTable.pTable = NULL; + pMac->lim.gLimPreAuthTimerTable.numEntry = 0; + } + + if (NULL != pMac->lim.pDialogueTokenHead) { + lim_delete_dialogue_token_list(pMac); + } + + if (NULL != pMac->lim.pDialogueTokenTail) { + qdf_mem_free(pMac->lim.pDialogueTokenTail); + pMac->lim.pDialogueTokenTail = NULL; + } + + if (pMac->lim.gpLimMlmSetKeysReq != NULL) { + qdf_mem_free(pMac->lim.gpLimMlmSetKeysReq); + pMac->lim.gpLimMlmSetKeysReq = NULL; + } + + if (pMac->lim.gpLimMlmAuthReq != NULL) { + qdf_mem_free(pMac->lim.gpLimMlmAuthReq); + pMac->lim.gpLimMlmAuthReq = NULL; + } + + if (pMac->lim.gpDefdSmeMsgForNOA != NULL) { + qdf_mem_free(pMac->lim.gpDefdSmeMsgForNOA); + pMac->lim.gpDefdSmeMsgForNOA = NULL; + } + + if (pMac->lim.gpLimMlmScanReq != NULL) { + qdf_mem_free(pMac->lim.gpLimMlmScanReq); + pMac->lim.gpLimMlmScanReq = NULL; + } + /* Now, finally reset the deferred message queue pointers */ + lim_reset_deferred_msg_q(pMac); + + rrm_cleanup(pMac); + + lim_ft_cleanup_all_ft_sessions(pMac); + +} /*** end lim_cleanup() ***/ + +/** + * lim_state_info_dump() - print state information of lim layer + * @buf: buffer pointer + * @size: size of buffer to be filled + * + * This function is used to print state information of lim layer + * + * Return: None + */ +static void lim_state_info_dump(char **buf_ptr, uint16_t *size) +{ + tHalHandle hal; + tpAniSirGlobal mac; + uint16_t len = 0; + char *buf = *buf_ptr; + + hal = cds_get_context(QDF_MODULE_ID_PE); + if (hal == NULL) { + QDF_ASSERT(0); + return; + } + + mac = PMAC_STRUCT(hal); + + lim_log(mac, LOG1, FL("size of buffer: %d"), *size); + + len += qdf_scnprintf(buf + len, *size - len, + "\n SmeState: %d", mac->lim.gLimSmeState); + len += qdf_scnprintf(buf + len, *size - len, + "\n PrevSmeState: %d", mac->lim.gLimPrevSmeState); + len += qdf_scnprintf(buf + len, *size - len, + "\n MlmState: %d", mac->lim.gLimMlmState); + len += qdf_scnprintf(buf + len, *size - len, + "\n PrevMlmState: %d", mac->lim.gLimPrevMlmState); + len += qdf_scnprintf(buf + len, *size - len, + "\n SystemInScanLearnMode: %d", + mac->lim.gLimSystemInScanLearnMode); + len += qdf_scnprintf(buf + len, *size - len, + "\n ProcessDefdMsgs: %d", mac->lim.gLimProcessDefdMsgs); + len += qdf_scnprintf(buf + len, *size - len, + "\n gLimHalScanState: %d", mac->lim.gLimHalScanState); + + *size -= len; + *buf_ptr += len; +} + +/** + * lim_register_debug_callback() - registration function for lim layer + * to print lim state information + * + * Return: None + */ +static void lim_register_debug_callback(void) +{ + qdf_register_debug_callback(QDF_MODULE_ID_PE, &lim_state_info_dump); +} + +/** ------------------------------------------------------------- + \fn pe_open + \brief will be called in Open sequence from mac_open + \param tpAniSirGlobal pMac + \param tHalOpenParameters *pHalOpenParam + \return tSirRetStatus + -------------------------------------------------------------*/ + +tSirRetStatus pe_open(tpAniSirGlobal pMac, struct cds_config_info *cds_cfg) +{ + tSirRetStatus status = eSIR_SUCCESS; + + if (DRIVER_TYPE_MFG == cds_cfg->driver_type) + return eSIR_SUCCESS; + + pMac->lim.maxBssId = cds_cfg->max_bssid; + pMac->lim.maxStation = cds_cfg->max_station; + qdf_spinlock_create(&pMac->sys.bbt_mgmt_lock); + + if ((pMac->lim.maxBssId == 0) || (pMac->lim.maxStation == 0)) { + PELOGE(lim_log(pMac, LOGE, + FL("max number of Bssid or Stations cannot be zero!"));) + return eSIR_FAILURE; + } + + pMac->lim.limTimers.gpLimCnfWaitTimer = + qdf_mem_malloc(sizeof(TX_TIMER) * (pMac->lim.maxStation + 1)); + if (NULL == pMac->lim.limTimers.gpLimCnfWaitTimer) { + PELOGE(lim_log(pMac, LOGE, + FL("gpLimCnfWaitTimer memory allocate failed!"));) + return eSIR_MEM_ALLOC_FAILED; + } + + pMac->lim.gpSession = + qdf_mem_malloc(sizeof(tPESession) * pMac->lim.maxBssId); + if (NULL == pMac->lim.gpSession) { + lim_log(pMac, LOGE, + FL("gpSession memory allocate failed!")); + status = eSIR_MEM_ALLOC_FAILED; + goto pe_open_psession_fail; + } + + pMac->lim.mgmtFrameSessionId = 0xff; + pMac->lim.tdls_frm_session_id = NO_SESSION; + pMac->lim.deferredMsgCnt = 0; + + if (!QDF_IS_STATUS_SUCCESS(qdf_mutex_create(&pMac->lim.lkPeGlobalLock))) { + PELOGE(lim_log(pMac, LOGE, FL("pe lock init failed!"));) + status = eSIR_FAILURE; + goto pe_open_lock_fail; + } + pMac->lim.retry_packet_cnt = 0; + pMac->lim.ibss_retry_cnt = 0; + + /* + * pe_open is successful by now, so it is right time to initialize + * MTRACE for PE module. if LIM_TRACE_RECORD is not defined in build + * file then nothing will be logged for PE module. + */ +#ifdef LIM_TRACE_RECORD + MTRACE(lim_trace_init(pMac)); +#endif + lim_register_debug_callback(); + + return status; /* status here will be eSIR_SUCCESS */ + +pe_open_lock_fail: + qdf_mem_free(pMac->lim.gpSession); + pMac->lim.gpSession = NULL; +pe_open_psession_fail: + qdf_mem_free(pMac->lim.limTimers.gpLimCnfWaitTimer); + pMac->lim.limTimers.gpLimCnfWaitTimer = NULL; + + return status; +} + +/** ------------------------------------------------------------- + \fn pe_close + \brief will be called in close sequence from mac_close + \param tpAniSirGlobal pMac + \return tSirRetStatus + -------------------------------------------------------------*/ + +tSirRetStatus pe_close(tpAniSirGlobal pMac) +{ + uint8_t i; + + if (ANI_DRIVER_TYPE(pMac) == eDRIVER_TYPE_MFG) + return eSIR_SUCCESS; + + qdf_spinlock_destroy(&pMac->sys.bbt_mgmt_lock); + for (i = 0; i < pMac->lim.maxBssId; i++) { + if (pMac->lim.gpSession[i].valid == true) { + pe_delete_session(pMac, &pMac->lim.gpSession[i]); + } + } + qdf_mem_free(pMac->lim.limTimers.gpLimCnfWaitTimer); + pMac->lim.limTimers.gpLimCnfWaitTimer = NULL; + + qdf_mem_free(pMac->lim.gpSession); + pMac->lim.gpSession = NULL; + if (!QDF_IS_STATUS_SUCCESS + (qdf_mutex_destroy(&pMac->lim.lkPeGlobalLock))) { + return eSIR_FAILURE; + } + return eSIR_SUCCESS; +} + +/** ------------------------------------------------------------- + \fn pe_start + \brief will be called in start sequence from mac_start + \param tpAniSirGlobal pMac + \return none + -------------------------------------------------------------*/ + +tSirRetStatus pe_start(tpAniSirGlobal pMac) +{ + tSirRetStatus status = eSIR_SUCCESS; + + status = lim_initialize(pMac); + return status; +} + +/** ------------------------------------------------------------- + \fn pe_stop + \brief will be called in stop sequence from mac_stop + \param tpAniSirGlobal pMac + \return none + -------------------------------------------------------------*/ + +void pe_stop(tpAniSirGlobal pMac) +{ + lim_cleanup(pMac); + SET_LIM_MLM_STATE(pMac, eLIM_MLM_OFFLINE_STATE); + return; +} + +/** ------------------------------------------------------------- + \fn pe_free_msg + \brief Called by CDS scheduler (function cds_sched_flush_mc_mqs) + \ to free a given PE message on the TX and MC thread. + \ This happens when there are messages pending in the PE + \ queue when system is being stopped and reset. + \param tpAniSirGlobal pMac + \param tSirMsgQ pMsg + \return none + -----------------------------------------------------------------*/ +void pe_free_msg(tpAniSirGlobal pMac, tSirMsgQ *pMsg) +{ + if (pMsg != NULL) { + if (NULL != pMsg->bodyptr) { + if (SIR_BB_XPORT_MGMT_MSG == pMsg->type) { + cds_pkt_return_packet((cds_pkt_t *) pMsg-> + bodyptr); + } else { + qdf_mem_free((void *)pMsg->bodyptr); + } + } + pMsg->bodyptr = 0; + pMsg->bodyval = 0; + pMsg->type = 0; + } + return; +} + +/** + * lim_post_msg_api() + * + ***FUNCTION: + * This function is called from other thread while posting a + * message to LIM message Queue gSirLimMsgQ. + * + ***LOGIC: + * NA + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param pMac - Pointer to Global MAC structure + * @param pMsg - Pointer to the message structure + * @return None + */ + +uint32_t lim_post_msg_api(tpAniSirGlobal pMac, tSirMsgQ *pMsg) +{ + return cds_mq_post_message(CDS_MQ_ID_PE, (cds_msg_t *) pMsg); + +} /*** end lim_post_msg_api() ***/ + +/** + * lim_post_msg_high_priority() - posts high priority pe message + * @mac: mac context + * @msg: message to be posted + * + * This function is used to post high priority pe message + * + * Return: returns value returned by vos_mq_post_message_by_priority + */ +uint32_t lim_post_msg_high_priority(tpAniSirGlobal mac, tSirMsgQ *msg) +{ + return cds_mq_post_message_by_priority(CDS_MQ_ID_PE, (cds_msg_t *)msg, + HIGH_PRIORITY); +} + +/*-------------------------------------------------------------------------- + + \brief pe_post_msg_api() - A wrapper function to post message to Voss msg queues + + This function can be called by legacy code to post message to cds queues OR + legacy code may keep on invoking 'lim_post_msg_api' to post the message to cds queue + for dispatching it later. + + \param pMac - Pointer to Global MAC structure + \param pMsg - Pointer to the message structure + + \return uint32_t - TX_SUCCESS for success. + + --------------------------------------------------------------------------*/ + +tSirRetStatus pe_post_msg_api(tpAniSirGlobal pMac, tSirMsgQ *pMsg) +{ + return (tSirRetStatus) lim_post_msg_api(pMac, pMsg); +} + +/*-------------------------------------------------------------------------- + + \brief pe_process_messages() - Message Processor for PE + + Voss calls this function to dispatch the message to PE + + \param pMac - Pointer to Global MAC structure + \param pMsg - Pointer to the message structure + + \return uint32_t - TX_SUCCESS for success. + + --------------------------------------------------------------------------*/ + +tSirRetStatus pe_process_messages(tpAniSirGlobal pMac, tSirMsgQ *pMsg) +{ + if (ANI_DRIVER_TYPE(pMac) == eDRIVER_TYPE_MFG) { + return eSIR_SUCCESS; + } + /** + * If the Message to be handled is for CFG Module call the CFG Msg + * Handler and for all the other cases post it to LIM + */ + if (SIR_CFG_PARAM_UPDATE_IND != pMsg->type && IS_CFG_MSG(pMsg->type)) + cfg_process_mb_msg(pMac, (tSirMbMsg *) pMsg->bodyptr); + else + lim_message_processor(pMac, pMsg); + return eSIR_SUCCESS; +} + +/** + * pe_drop_pending_rx_mgmt_frames: To drop pending RX mgmt frames + * @mac_ctx: Pointer to global MAC structure + * @hdr: Management header + * @cds_pkt: Packet + * + * This function is used to drop RX pending mgmt frames if pe mgmt queue + * reaches threshold + * + * Return: QDF_STATUS_SUCCESS on success or QDF_STATUS_E_FAILURE on failure + */ +static QDF_STATUS pe_drop_pending_rx_mgmt_frames(tpAniSirGlobal mac_ctx, + tpSirMacMgmtHdr hdr, cds_pkt_t *cds_pkt) +{ + qdf_spin_lock(&mac_ctx->sys.bbt_mgmt_lock); + if (mac_ctx->sys.sys_bbt_pending_mgmt_count >= + MGMT_RX_PACKETS_THRESHOLD) { + qdf_spin_unlock(&mac_ctx->sys.bbt_mgmt_lock); + lim_log(mac_ctx, LOG1, + FL("No.of pending RX management frames reaches to threshold, dropping management frames")); + cds_pkt_return_packet(cds_pkt); + cds_pkt = NULL; + mac_ctx->rx_packet_drop_counter++; + return QDF_STATUS_E_FAILURE; + } else if (mac_ctx->sys.sys_bbt_pending_mgmt_count > + (MGMT_RX_PACKETS_THRESHOLD / 2)) { + /* drop all probereq, proberesp and beacons */ + if (hdr->fc.subType == SIR_MAC_MGMT_BEACON || + hdr->fc.subType == SIR_MAC_MGMT_PROBE_REQ || + hdr->fc.subType == SIR_MAC_MGMT_PROBE_RSP) { + qdf_spin_unlock(&mac_ctx->sys.bbt_mgmt_lock); + if (!(mac_ctx->rx_packet_drop_counter % 100)) + lim_log(mac_ctx, LOG1, + FL("No.of pending RX mgmt frames reaches 1/2 thresh, dropping frame subtype: %d rx_packet_drop_counter: %d"), + hdr->fc.subType, + mac_ctx->rx_packet_drop_counter); + mac_ctx->rx_packet_drop_counter++; + cds_pkt_return_packet(cds_pkt); + cds_pkt = NULL; + return QDF_STATUS_E_FAILURE; + } + } + mac_ctx->sys.sys_bbt_pending_mgmt_count++; + qdf_spin_unlock(&mac_ctx->sys.bbt_mgmt_lock); + if (mac_ctx->sys.sys_bbt_pending_mgmt_count == + (MGMT_RX_PACKETS_THRESHOLD / 4)) { + if (!(mac_ctx->rx_packet_drop_counter % 100)) + lim_log(mac_ctx, LOG1, + FL("No.of pending RX management frames reaches to 1/4th of threshold, rx_packet_drop_counter: %d"), + mac_ctx->rx_packet_drop_counter); + mac_ctx->rx_packet_drop_counter++; + } + return QDF_STATUS_SUCCESS; +} + +/* --------------------------------------------------------------------------- */ +/** + * pe_handle_mgmt_frame + * + * FUNCTION: + * Process the Management frames from TL + * + * LOGIC: + * + * ASSUMPTIONS: TL sends the packet along with the CDS GlobalContext + * + * NOTE: + * + * @param p_cds_gctx Global Vos Context + * @param cds_buff Packet + * @return None + */ + +static QDF_STATUS pe_handle_mgmt_frame(void *p_cds_gctx, void *cds_buff) +{ + tpAniSirGlobal pMac; + tpSirMacMgmtHdr mHdr; + tSirMsgQ msg; + cds_pkt_t *pVosPkt; + QDF_STATUS qdf_status; + uint8_t *pRxPacketInfo; + + pVosPkt = (cds_pkt_t *) cds_buff; + if (NULL == pVosPkt) { + return QDF_STATUS_E_FAILURE; + } + + pMac = cds_get_context(QDF_MODULE_ID_PE); + if (NULL == pMac) { + /* cannot log a failure without a valid pMac */ + cds_pkt_return_packet(pVosPkt); + pVosPkt = NULL; + return QDF_STATUS_E_FAILURE; + } + + qdf_status = + wma_ds_peek_rx_packet_info(pVosPkt, (void *)&pRxPacketInfo, false); + + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + cds_pkt_return_packet(pVosPkt); + pVosPkt = NULL; + return QDF_STATUS_E_FAILURE; + } + + /* + * The MPDU header is now present at a certain "offset" in + * the BD and is specified in the BD itself + */ + + mHdr = WMA_GET_RX_MAC_HEADER(pRxPacketInfo); + if (mHdr->fc.type == SIR_MAC_MGMT_FRAME) { + lim_log(pMac, LOG2, FL + ("RxBd=%p mHdr=%p Type: %d Subtype: %d Sizes:FC%zu Mgmt%zu"), + pRxPacketInfo, mHdr, mHdr->fc.type, mHdr->fc.subType, + sizeof(tSirMacFrameCtl), sizeof(tSirMacMgmtHdr)); + + lim_log(pMac, LOG2, FL("mpdu_len:%d hdr_len:%d data_len:%d"), + WMA_GET_RX_MPDU_LEN(pRxPacketInfo), + WMA_GET_RX_MPDU_HEADER_LEN(pRxPacketInfo), + WMA_GET_RX_PAYLOAD_LEN(pRxPacketInfo)); + + if (WMA_GET_ROAMCANDIDATEIND(pRxPacketInfo)) + lim_log(pMac, LOG1, FL("roamCandidateInd %d"), + WMA_GET_ROAMCANDIDATEIND(pRxPacketInfo)); + + if (WMA_GET_OFFLOADSCANLEARN(pRxPacketInfo)) + lim_log(pMac, LOG1, FL("offloadScanLearn %d"), + WMA_GET_OFFLOADSCANLEARN(pRxPacketInfo)); + } + + if (QDF_STATUS_SUCCESS != + pe_drop_pending_rx_mgmt_frames(pMac, mHdr, pVosPkt)) + return QDF_STATUS_E_FAILURE; + + /* Forward to MAC via mesg = SIR_BB_XPORT_MGMT_MSG */ + msg.type = SIR_BB_XPORT_MGMT_MSG; + msg.bodyptr = cds_buff; + msg.bodyval = 0; + + if (eSIR_SUCCESS != sys_bbt_process_message_core(pMac, + &msg, + mHdr->fc.type, + mHdr->fc.subType)) { + cds_pkt_return_packet(pVosPkt); + pVosPkt = NULL; + /* + * Decrement sys_bbt_pending_mgmt_count if packet + * is dropped before posting to LIM + */ + lim_decrement_pending_mgmt_count(pMac); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * pe_register_callbacks_with_wma() - register SME and PE callback functions to + * WMA. + * (function documentation in lim_api.h) + */ +void pe_register_callbacks_with_wma(tpAniSirGlobal pMac, + tSirSmeReadyReq *ready_req) +{ + void *p_cds_gctx; + QDF_STATUS retStatus; + + p_cds_gctx = cds_get_global_context(); + + retStatus = wma_register_mgmt_frm_client(p_cds_gctx, + pe_handle_mgmt_frame); + if (retStatus != QDF_STATUS_SUCCESS) + lim_log(pMac, LOGP, + FL("Registering the PE Handle with WMA has failed")); + + retStatus = wma_register_roaming_callbacks(p_cds_gctx, + ready_req->csr_roam_synch_cb, + ready_req->pe_roam_synch_cb); + if (retStatus != QDF_STATUS_SUCCESS) + lim_log(pMac, LOGP, + FL("Registering roaming callbacks with WMA failed")); + + retStatus = wma_register_ndp_cb(lim_handle_ndp_event_message); + if (retStatus != QDF_STATUS_SUCCESS) + lim_log(pMac, LOGE, + FL("Registering NDP callbacks with WMA failed")); +} + +/** + * lim_is_system_in_scan_state() + * + ***FUNCTION: + * This function is called by various MAC software modules to + * determine if System is in Scan/Learn state + * + ***LOGIC: + * NA + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * + * @param pMac - Pointer to Global MAC structure + * @return true - System is in Scan/Learn state + * false - System is NOT in Scan/Learn state + */ + +uint8_t lim_is_system_in_scan_state(tpAniSirGlobal pMac) +{ + switch (pMac->lim.gLimSmeState) { + case eLIM_SME_CHANNEL_SCAN_STATE: + case eLIM_SME_NORMAL_CHANNEL_SCAN_STATE: + case eLIM_SME_LINK_EST_WT_SCAN_STATE: + case eLIM_SME_WT_SCAN_STATE: + /* System is in Learn mode */ + return true; + + default: + /* System is NOT in Learn mode */ + return false; + } +} /*** end lim_is_system_in_scan_state() ***/ + +/** + *\brief lim_received_hb_handler() + * + * This function is called by sch_beacon_process() upon + * receiving a Beacon on STA. This also gets called upon + * receiving Probe Response after heat beat failure is + * detected. + * + * param pMac - global mac structure + * param channel - channel number indicated in Beacon, Probe Response + * return - none + */ + +void +lim_received_hb_handler(tpAniSirGlobal pMac, uint8_t channelId, + tpPESession psessionEntry) +{ + if ((channelId == 0) + || (channelId == psessionEntry->currentOperChannel)) + psessionEntry->LimRxedBeaconCntDuringHB++; + + psessionEntry->pmmOffloadInfo.bcnmiss = false; +} /*** lim_init_wds_info_params() ***/ + +/** ------------------------------------------------------------- + \fn lim_update_overlap_sta_param + \brief Updates overlap cache and param data structure + \param tpAniSirGlobal pMac + \param tSirMacAddr bssId + \param tpLimProtStaParams pStaParams + \return None + -------------------------------------------------------------*/ +void +lim_update_overlap_sta_param(tpAniSirGlobal pMac, tSirMacAddr bssId, + tpLimProtStaParams pStaParams) +{ + int i; + if (!pStaParams->numSta) { + qdf_mem_copy(pMac->lim.protStaOverlapCache[0].addr, + bssId, sizeof(tSirMacAddr)); + pMac->lim.protStaOverlapCache[0].active = true; + + pStaParams->numSta = 1; + + return; + } + + for (i = 0; i < LIM_PROT_STA_OVERLAP_CACHE_SIZE; i++) { + if (pMac->lim.protStaOverlapCache[i].active) { + if (!qdf_mem_cmp + (pMac->lim.protStaOverlapCache[i].addr, bssId, + sizeof(tSirMacAddr))) { + return; + } + } else + break; + } + + if (i == LIM_PROT_STA_OVERLAP_CACHE_SIZE) { + PELOG1(lim_log(pMac, LOGW, FL("Overlap cache is full"));) + } else { + qdf_mem_copy(pMac->lim.protStaOverlapCache[i].addr, + bssId, sizeof(tSirMacAddr)); + pMac->lim.protStaOverlapCache[i].active = true; + + pStaParams->numSta++; + } +} + +/** + * lim_ibss_enc_type_matched + * + ***FUNCTION: + * This function compares the encryption type of the peer with self + * while operating in IBSS mode and detects mismatch. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param pBeacon - Parsed Beacon Frame structure + * @param pSession - Pointer to the PE session + * + * @return eSIR_TRUE if encryption type is matched; eSIR_FALSE otherwise + */ +static tAniBool lim_ibss_enc_type_matched(tpSchBeaconStruct pBeacon, + tpPESession pSession) +{ + if (!pBeacon || !pSession) + return eSIR_FALSE; + + /* Open case */ + if (pBeacon->capabilityInfo.privacy == 0 + && pSession->encryptType == eSIR_ED_NONE) + return eSIR_TRUE; + + /* WEP case */ + if (pBeacon->capabilityInfo.privacy == 1 && pBeacon->wpaPresent == 0 + && pBeacon->rsnPresent == 0 + && (pSession->encryptType == eSIR_ED_WEP40 + || pSession->encryptType == eSIR_ED_WEP104)) + return eSIR_TRUE; + + /* WPA-None case */ + if (pBeacon->capabilityInfo.privacy == 1 && pBeacon->wpaPresent == 1 + && pBeacon->rsnPresent == 0 + && ((pSession->encryptType == eSIR_ED_CCMP) || + (pSession->encryptType == eSIR_ED_TKIP))) + return eSIR_TRUE; + + return eSIR_FALSE; +} + +/** + * lim_handle_ibs_scoalescing() + * + ***FUNCTION: + * This function is called upon receiving Beacon/Probe Response + * while operating in IBSS mode. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param pMac - Pointer to Global MAC structure + * @param pBeacon - Parsed Beacon Frame structure + * @param pRxPacketInfo - Pointer to RX packet info structure + * + * @return Status whether to process or ignore received Beacon Frame + */ + +tSirRetStatus +lim_handle_ibss_coalescing(tpAniSirGlobal pMac, + tpSchBeaconStruct pBeacon, + uint8_t *pRxPacketInfo, tpPESession psessionEntry) +{ + tpSirMacMgmtHdr pHdr; + tSirRetStatus retCode; + + pHdr = WMA_GET_RX_MAC_HEADER(pRxPacketInfo); + + /* Ignore the beacon when any of the conditions below is met: + 1. The beacon claims no IBSS network + 2. SSID in the beacon does not match SSID of self station + 3. Operational channel in the beacon does not match self station + 4. Encyption type in the beacon does not match with self station + */ + if ((!pBeacon->capabilityInfo.ibss) || + lim_cmp_ssid(&pBeacon->ssId, psessionEntry) || + (psessionEntry->currentOperChannel != pBeacon->channelNumber)) + retCode = eSIR_LIM_IGNORE_BEACON; + else if (lim_ibss_enc_type_matched(pBeacon, psessionEntry) != eSIR_TRUE) { + PELOG3(lim_log(pMac, LOG3, + FL + ("peer privacy %d peer wpa %d peer rsn %d self encType %d"), + pBeacon->capabilityInfo.privacy, + pBeacon->wpaPresent, pBeacon->rsnPresent, + psessionEntry->encryptType); + ) + retCode = eSIR_LIM_IGNORE_BEACON; + } else { + uint32_t ieLen; + uint16_t tsfLater; + uint8_t *pIEs; + ieLen = WMA_GET_RX_PAYLOAD_LEN(pRxPacketInfo); + tsfLater = WMA_GET_RX_TSF_LATER(pRxPacketInfo); + pIEs = WMA_GET_RX_MPDU_DATA(pRxPacketInfo); + PELOG3(lim_log + (pMac, LOG3, FL("BEFORE Coalescing tsfLater val :%d"), + tsfLater); + ) + retCode = + lim_ibss_coalesce(pMac, pHdr, pBeacon, pIEs, ieLen, tsfLater, + psessionEntry); + } + return retCode; +} /*** end lim_handle_ibs_scoalescing() ***/ + +/** + * lim_enc_type_matched() - matches security type of incoming beracon with + * current + * @mac_ctx Pointer to Global MAC structure + * @bcn Pointer to parsed Beacon structure + * @session PE session entry + * + * This function matches security type of incoming beracon with current + * + * @return true if matched, false otherwise + */ +static bool +lim_enc_type_matched(tpAniSirGlobal mac_ctx, + tpSchBeaconStruct bcn, + tpPESession session) +{ + if (!bcn || !session) + return false; + + lim_log(mac_ctx, LOG1, + FL("Beacon/Probe:: Privacy :%d WPA Present:%d RSN Present: %d"), + bcn->capabilityInfo.privacy, bcn->wpaPresent, bcn->rsnPresent); + lim_log(mac_ctx, LOG1, + FL("session:: Privacy :%d EncyptionType: %d OSEN %d WPS %d"), + SIR_MAC_GET_PRIVACY(session->limCurrentBssCaps), + session->encryptType, session->isOSENConnection, + session->wps_registration); + + /* + * This is handled by sending probe req due to IOT issues so + * return TRUE + */ + if ((bcn->capabilityInfo.privacy) != + SIR_MAC_GET_PRIVACY(session->limCurrentBssCaps)) { + lim_log(mac_ctx, LOGW, FL("Privacy bit miss match\n")); + return true; + } + + /* Open */ + if ((bcn->capabilityInfo.privacy == 0) && + (session->encryptType == eSIR_ED_NONE)) + return true; + + /* WEP */ + if ((bcn->capabilityInfo.privacy == 1) && + (bcn->wpaPresent == 0) && (bcn->rsnPresent == 0) && + ((session->encryptType == eSIR_ED_WEP40) || + (session->encryptType == eSIR_ED_WEP104) +#ifdef FEATURE_WLAN_WAPI + || (session->encryptType == eSIR_ED_WPI) +#endif + )) + return true; + + /* WPA OR RSN*/ + if ((bcn->capabilityInfo.privacy == 1) && + ((bcn->wpaPresent == 1) || (bcn->rsnPresent == 1)) && + ((session->encryptType == eSIR_ED_TKIP) || + (session->encryptType == eSIR_ED_CCMP) || + (session->encryptType == eSIR_ED_AES_128_CMAC))) + return true; + + /* + * For HS2.0, RSN ie is not present + * in beacon. Therefore no need to + * check for security type in case + * OSEN session. + * For WPS registration session no need to detect + * detect security mismatch as it wont match and + * driver may end up sending probe request without + * WPS IE during WPS registration process. + */ + if (session->isOSENConnection || + session->wps_registration) + return true; + + return false; +} + +/** + * lim_detect_change_in_ap_capabilities() + * + ***FUNCTION: + * This function is called while SCH is processing + * received Beacon from AP on STA to detect any + * change in AP's capabilities. If there any change + * is detected, Roaming is informed of such change + * so that it can trigger reassociation. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * + ***NOTE: + * Notification is enabled for STA product only since + * it is not a requirement on BP side. + * + * @param pMac Pointer to Global MAC structure + * @param pBeacon Pointer to parsed Beacon structure + * @return None + */ + +void +lim_detect_change_in_ap_capabilities(tpAniSirGlobal pMac, + tpSirProbeRespBeacon pBeacon, + tpPESession psessionEntry) +{ + uint8_t len; + tSirSmeApNewCaps apNewCaps; + uint8_t newChannel; + tSirRetStatus status = eSIR_SUCCESS; + bool security_caps_matched = true; + + apNewCaps.capabilityInfo = + lim_get_u16((uint8_t *) &pBeacon->capabilityInfo); + newChannel = (uint8_t) pBeacon->channelNumber; + + security_caps_matched = lim_enc_type_matched(pMac, pBeacon, + psessionEntry); + if ((false == psessionEntry->limSentCapsChangeNtf) && + (((!lim_is_null_ssid(&pBeacon->ssId)) && + lim_cmp_ssid(&pBeacon->ssId, psessionEntry)) || + ((SIR_MAC_GET_ESS(apNewCaps.capabilityInfo) != + SIR_MAC_GET_ESS(psessionEntry->limCurrentBssCaps)) || + (SIR_MAC_GET_PRIVACY(apNewCaps.capabilityInfo) != + SIR_MAC_GET_PRIVACY(psessionEntry->limCurrentBssCaps)) || + (SIR_MAC_GET_SHORT_PREAMBLE(apNewCaps.capabilityInfo) != + SIR_MAC_GET_SHORT_PREAMBLE(psessionEntry->limCurrentBssCaps)) || + (SIR_MAC_GET_QOS(apNewCaps.capabilityInfo) != + SIR_MAC_GET_QOS(psessionEntry->limCurrentBssCaps)) || + ((newChannel != psessionEntry->currentOperChannel) && + (newChannel != 0)) || + (false == security_caps_matched) + ))) { + if (false == psessionEntry->fWaitForProbeRsp) { + /* If Beacon capabilities is not matching with the current capability, + * then send unicast probe request to AP and take decision after + * receiving probe response */ + if (true == psessionEntry->fIgnoreCapsChange) { + lim_log(pMac, LOGW, + FL + ("Ignoring the Capability change as it is false alarm")); + return; + } + psessionEntry->fWaitForProbeRsp = true; + lim_log(pMac, LOGW, + FL("AP capabilities are not matching," + "sending directed probe request.. ")); + status = + lim_send_probe_req_mgmt_frame(pMac, &psessionEntry->ssId, + psessionEntry->bssId, + psessionEntry-> + currentOperChannel, + psessionEntry->selfMacAddr, + psessionEntry->dot11mode, + 0, NULL); + + if (eSIR_SUCCESS != status) { + lim_log(pMac, LOGE, FL("send ProbeReq failed")); + psessionEntry->fWaitForProbeRsp = false; + } + return; + } + /** + * BSS capabilities have changed. + * Inform Roaming. + */ + len = sizeof(tSirMacCapabilityInfo) + sizeof(tSirMacAddr) + sizeof(uint8_t) + 3 * sizeof(uint8_t) + /* reserved fields */ + pBeacon->ssId.length + 1; + + qdf_mem_copy(apNewCaps.bssId.bytes, + psessionEntry->bssId, QDF_MAC_ADDR_SIZE); + if (newChannel != psessionEntry->currentOperChannel) { + PELOGE(lim_log + (pMac, LOGE, + FL("Channel Change from %d --> %d - " + "Ignoring beacon!"), + psessionEntry->currentOperChannel, newChannel); + ) + return; + } + + /** + * When Cisco 1262 Enterprise APs are configured with WPA2-PSK with + * AES+TKIP Pairwise ciphers and WEP-40 Group cipher, they do not set + * the privacy bit in Beacons (wpa/rsnie is still present in beacons), + * the privacy bit is set in Probe and association responses. + * Due to this anomaly, we detect a change in + * AP capabilities when we receive a beacon after association and + * disconnect from the AP. The following check makes sure that we can + * connect to such APs + */ + else if ((SIR_MAC_GET_PRIVACY(apNewCaps.capabilityInfo) == 0) && + (pBeacon->rsnPresent || pBeacon->wpaPresent)) { + PELOGE(lim_log + (pMac, LOGE, + FL("BSS Caps (Privacy) bit 0 in beacon," + " but WPA or RSN IE present, Ignore Beacon!")); + ) + return; + } else + apNewCaps.channelId = psessionEntry->currentOperChannel; + qdf_mem_copy((uint8_t *) &apNewCaps.ssId, + (uint8_t *) &pBeacon->ssId, + pBeacon->ssId.length + 1); + + psessionEntry->fIgnoreCapsChange = false; + psessionEntry->fWaitForProbeRsp = false; + psessionEntry->limSentCapsChangeNtf = true; + lim_send_sme_wm_status_change_ntf(pMac, eSIR_SME_AP_CAPS_CHANGED, + (uint32_t *) &apNewCaps, + len, psessionEntry->smeSessionId); + } else if (true == psessionEntry->fWaitForProbeRsp) { + /* Only for probe response frames and matching capabilities the control + * will come here. If beacon is with broadcast ssid then fWaitForProbeRsp + * will be false, the control will not come here*/ + + lim_log(pMac, LOG1, FL("capabilities in probe response are" + "matching with the current setting," + "Ignoring subsequent capability" + "mismatch")); + psessionEntry->fIgnoreCapsChange = true; + psessionEntry->fWaitForProbeRsp = false; + } + +} /*** lim_detect_change_in_ap_capabilities() ***/ + +/* --------------------------------------------------------------------- */ +/** + * lim_update_short_slot + * + * FUNCTION: + * Enable/Disable short slot + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param enable Flag to enable/disable short slot + * @return None + */ + +tSirRetStatus lim_update_short_slot(tpAniSirGlobal pMac, + tpSirProbeRespBeacon pBeacon, + tpUpdateBeaconParams pBeaconParams, + tpPESession psessionEntry) +{ + + tSirSmeApNewCaps apNewCaps; + uint32_t nShortSlot; + uint32_t val = 0; + uint32_t phyMode; + + /* Check Admin mode first. If it is disabled just return */ + if (wlan_cfg_get_int(pMac, WNI_CFG_11G_SHORT_SLOT_TIME_ENABLED, &val) + != eSIR_SUCCESS) { + lim_log(pMac, LOGP, + FL("cfg get WNI_CFG_11G_SHORT_SLOT_TIME failed")); + return eSIR_FAILURE; + } + if (val == false) + return eSIR_SUCCESS; + + /* Check for 11a mode or 11b mode. In both cases return since slot time is constant and cannot/should not change in beacon */ + lim_get_phy_mode(pMac, &phyMode, psessionEntry); + if ((phyMode == WNI_CFG_PHY_MODE_11A) + || (phyMode == WNI_CFG_PHY_MODE_11B)) + return eSIR_SUCCESS; + + apNewCaps.capabilityInfo = + lim_get_u16((uint8_t *) &pBeacon->capabilityInfo); + + /* Earlier implementation: determine the appropriate short slot mode based on AP advertised modes */ + /* when erp is present, apply short slot always unless, prot=on && shortSlot=off */ + /* if no erp present, use short slot based on current ap caps */ + + /* Issue with earlier implementation : Cisco 1231 BG has shortSlot = 0, erpIEPresent and useProtection = 0 (Case4); */ + + /* Resolution : always use the shortSlot setting the capability info to decide slot time. */ + /* The difference between the earlier implementation and the new one is only Case4. */ + /* + ERP IE Present | useProtection | shortSlot = QC STA Short Slot + Case1 1 1 1 1 //AP should not advertise this combination. + Case2 1 1 0 0 + Case3 1 0 1 1 + Case4 1 0 0 0 + Case5 0 1 1 1 + Case6 0 1 0 0 + Case7 0 0 1 1 + Case8 0 0 0 0 + */ + nShortSlot = SIR_MAC_GET_SHORT_SLOT_TIME(apNewCaps.capabilityInfo); + + if (nShortSlot != psessionEntry->shortSlotTimeSupported) { + /* Short slot time capability of AP has changed. Adopt to it. */ + PELOG1(lim_log + (pMac, LOG1, + FL("Shortslot capability of AP changed: %d"), + nShortSlot); + ) + ((tpSirMacCapabilityInfo) & psessionEntry-> + limCurrentBssCaps)->shortSlotTime = (uint16_t) nShortSlot; + psessionEntry->shortSlotTimeSupported = nShortSlot; + pBeaconParams->fShortSlotTime = (uint8_t) nShortSlot; + pBeaconParams->paramChangeBitmap |= + PARAM_SHORT_SLOT_TIME_CHANGED; + } + return eSIR_SUCCESS; +} + + +void lim_send_heart_beat_timeout_ind(tpAniSirGlobal pMac, tpPESession psessionEntry) +{ + uint32_t statusCode; + tSirMsgQ msg; + + /* Prepare and post message to LIM Message Queue */ + msg.type = (uint16_t) SIR_LIM_HEART_BEAT_TIMEOUT; + msg.bodyptr = psessionEntry; + msg.bodyval = 0; + lim_log(pMac, LOGE, FL("Heartbeat failure from Fw")); + + statusCode = lim_post_msg_api(pMac, &msg); + + if (statusCode != eSIR_SUCCESS) { + lim_log(pMac, LOGE, + FL("posting message %X to LIM failed, reason=%d"), + msg.type, statusCode); + } +} + +/** + * lim_ps_offload_handle_missed_beacon_ind(): handles missed beacon indication + * @pMac : global mac context + * @pMsg: message + * + * This function process the SIR_HAL_MISSED_BEACON_IND + * message from HAL, to do active AP probing. + * + * Return: void + */ +void lim_ps_offload_handle_missed_beacon_ind(tpAniSirGlobal pMac, tpSirMsgQ pMsg) +{ + tpSirSmeMissedBeaconInd pSirMissedBeaconInd = + (tpSirSmeMissedBeaconInd) pMsg->bodyptr; + tpPESession psessionEntry = + pe_find_session_by_bss_idx(pMac, pSirMissedBeaconInd->bssIdx); + + if (!psessionEntry) { + lim_log(pMac, LOGE, + FL("session does not exist for given BSSId")); + return; + } + + /* Set Beacon Miss in Powersave Offload */ + psessionEntry->pmmOffloadInfo.bcnmiss = true; + PELOGE(lim_log(pMac, LOGE, + FL("Received Heart Beat Failure"));) + + /* Do AP probing immediately */ + lim_send_heart_beat_timeout_ind(pMac, psessionEntry); + return; +} + +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH +/** + * lim_fill_join_rsp_ht_caps() - Fill the HT caps in join response + * @session: PE Session + * @join_rsp: Join response buffer to be filled up. + * + * Return: None + */ +void lim_fill_join_rsp_ht_caps(tpPESession session, tpSirSmeJoinRsp join_rsp) +{ + tSirSmeHTProfile *ht_profile; + if (session == NULL) { + QDF_TRACE(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_ERROR, + "Invalid Session"); + return; + } + if (join_rsp == NULL) { + QDF_TRACE(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_ERROR, + "Invalid Join Response"); + return; + } + + if (session->cc_switch_mode == QDF_MCC_TO_SCC_SWITCH_DISABLE) + return; + + ht_profile = &join_rsp->HTProfile; + ht_profile->htSupportedChannelWidthSet = + session->htSupportedChannelWidthSet; + ht_profile->htRecommendedTxWidthSet = + session->htRecommendedTxWidthSet; + ht_profile->htSecondaryChannelOffset = + session->htSecondaryChannelOffset; + ht_profile->dot11mode = session->dot11mode; + ht_profile->htCapability = session->htCapability; + ht_profile->vhtCapability = session->vhtCapability; + ht_profile->apCenterChan = session->ch_center_freq_seg0; + ht_profile->apChanWidth = session->ch_width; +} +#endif + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +static QDF_STATUS +lim_roam_fill_bss_descr(tpAniSirGlobal pMac, + roam_offload_synch_ind *roam_offload_synch_ind_ptr, + tpSirBssDescription bss_desc_ptr) +{ + uint32_t ie_len = 0; + tpSirProbeRespBeacon parsed_frm_ptr; + tpSirMacMgmtHdr mac_hdr; + uint8_t *bcn_proberesp_ptr; + + bcn_proberesp_ptr = (uint8_t *)roam_offload_synch_ind_ptr + + roam_offload_synch_ind_ptr->beaconProbeRespOffset; + mac_hdr = (tpSirMacMgmtHdr)bcn_proberesp_ptr; + parsed_frm_ptr = + (tpSirProbeRespBeacon) qdf_mem_malloc(sizeof(tSirProbeRespBeacon)); + if (NULL == parsed_frm_ptr) { + lim_log(pMac, LOGE, "fail to allocate memory for frame"); + return QDF_STATUS_E_NOMEM; + } + + if (roam_offload_synch_ind_ptr->beaconProbeRespLength <= + SIR_MAC_HDR_LEN_3A) { + QDF_TRACE(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_ERROR, "%s: very" + "few bytes in synchInd beacon / probe resp frame! length=%d", + __func__, roam_offload_synch_ind_ptr->beaconProbeRespLength); + qdf_mem_free(parsed_frm_ptr); + return QDF_STATUS_E_FAILURE; + } + + QDF_TRACE(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_INFO, + "LFR3:Beacon/Prb Rsp:%d", roam_offload_synch_ind_ptr->isBeacon); + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_INFO, + bcn_proberesp_ptr, roam_offload_synch_ind_ptr->beaconProbeRespLength); + if (roam_offload_synch_ind_ptr->isBeacon) { + if (sir_parse_beacon_ie(pMac, parsed_frm_ptr, + &bcn_proberesp_ptr[SIR_MAC_HDR_LEN_3A + + SIR_MAC_B_PR_SSID_OFFSET], + roam_offload_synch_ind_ptr->beaconProbeRespLength - + SIR_MAC_HDR_LEN_3A) != eSIR_SUCCESS || + !parsed_frm_ptr->ssidPresent) { + QDF_TRACE(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_ERROR, + "Parse error Beacon, length=%d", + roam_offload_synch_ind_ptr->beaconProbeRespLength); + qdf_mem_free(parsed_frm_ptr); + return QDF_STATUS_E_FAILURE; + } + } else { + if (sir_convert_probe_frame2_struct(pMac, + &bcn_proberesp_ptr[SIR_MAC_HDR_LEN_3A], + roam_offload_synch_ind_ptr->beaconProbeRespLength - + SIR_MAC_HDR_LEN_3A, parsed_frm_ptr) != eSIR_SUCCESS || + !parsed_frm_ptr->ssidPresent) { + QDF_TRACE(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_ERROR, + "Parse error ProbeResponse, length=%d", + roam_offload_synch_ind_ptr->beaconProbeRespLength); + qdf_mem_free(parsed_frm_ptr); + return QDF_STATUS_E_FAILURE; + } + } + /* 24 byte MAC header and 12 byte to ssid IE */ + if (roam_offload_synch_ind_ptr->beaconProbeRespLength > + (SIR_MAC_HDR_LEN_3A + SIR_MAC_B_PR_SSID_OFFSET)) { + ie_len = roam_offload_synch_ind_ptr->beaconProbeRespLength - + (SIR_MAC_HDR_LEN_3A + SIR_MAC_B_PR_SSID_OFFSET); + } + /* + * Length of BSS desription is without length of + * length itself and length of pointer + * that holds ieFields + * + * tSirBssDescription + * +--------+---------------------------------+---------------+ + * | length | other fields | pointer to IEs| + * +--------+---------------------------------+---------------+ + * ^ + * ieFields + */ + bss_desc_ptr->length = (uint16_t) (offsetof(tSirBssDescription, + ieFields[0]) - + sizeof(bss_desc_ptr->length) + ie_len); + + bss_desc_ptr->fProbeRsp = !roam_offload_synch_ind_ptr->isBeacon; + /* Copy Timestamp */ + bss_desc_ptr->scansystimensec = qdf_get_monotonic_boottime_ns(); + if (parsed_frm_ptr->dsParamsPresent) { + bss_desc_ptr->channelId = parsed_frm_ptr->channelNumber; + } else if (parsed_frm_ptr->HTInfo.present) { + bss_desc_ptr->channelId = parsed_frm_ptr->HTInfo.primaryChannel; + } else { + /* + * If DS Params or HTIE is not present in the probe resp or + * beacon, then use the channel frequency provided by firmware + * to fill the channel in the BSS descriptor.*/ + bss_desc_ptr->channelId = + cds_freq_to_chan(roam_offload_synch_ind_ptr->chan_freq); + } + bss_desc_ptr->channelIdSelf = bss_desc_ptr->channelId; + + if ((bss_desc_ptr->channelId > 0) && (bss_desc_ptr->channelId < 15)) { + int i; + /* * + * 11b or 11g packet + * 11g if extended Rate IE is present or + * if there is an A rate in suppRate IE + * */ + for (i = 0; i < parsed_frm_ptr->supportedRates.numRates; i++) { + if (sirIsArate(parsed_frm_ptr->supportedRates.rate[i] & + 0x7f)) { + bss_desc_ptr->nwType = eSIR_11G_NW_TYPE; + break; + } + } + if (parsed_frm_ptr->extendedRatesPresent) { + bss_desc_ptr->nwType = eSIR_11G_NW_TYPE; + } + } else { + /* 11a packet */ + bss_desc_ptr->nwType = eSIR_11A_NW_TYPE; + } + + bss_desc_ptr->sinr = 0; + bss_desc_ptr->beaconInterval = parsed_frm_ptr->beaconInterval; + bss_desc_ptr->timeStamp[0] = parsed_frm_ptr->timeStamp[0]; + bss_desc_ptr->timeStamp[1] = parsed_frm_ptr->timeStamp[1]; + qdf_mem_copy(&bss_desc_ptr->capabilityInfo, + &bcn_proberesp_ptr[SIR_MAC_HDR_LEN_3A + SIR_MAC_B_PR_CAPAB_OFFSET], 2); + + if (qdf_is_macaddr_zero((struct qdf_mac_addr *)mac_hdr->bssId)) { + pe_debug("bssid is 0 in beacon/probe update it with bssId %pM in sync ind", + roam_offload_synch_ind_ptr->bssid.bytes); + qdf_mem_copy(mac_hdr->bssId, + roam_offload_synch_ind_ptr->bssid.bytes, + sizeof(tSirMacAddr)); + } + + qdf_mem_copy((uint8_t *) &bss_desc_ptr->bssId, + (uint8_t *) mac_hdr->bssId, + sizeof(tSirMacAddr)); + bss_desc_ptr->received_time = + (uint64_t)qdf_mc_timer_get_system_time(); + if (parsed_frm_ptr->mdiePresent) { + bss_desc_ptr->mdiePresent = parsed_frm_ptr->mdiePresent; + qdf_mem_copy((uint8_t *)bss_desc_ptr->mdie, + (uint8_t *)parsed_frm_ptr->mdie, + SIR_MDIE_SIZE); + } + QDF_TRACE(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_DEBUG, + "LFR3:%s:BssDescr Info:", __func__); + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_DEBUG, + bss_desc_ptr->bssId, sizeof(tSirMacAddr)); + QDF_TRACE(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_DEBUG, + "chan=%d, rssi=%d", bss_desc_ptr->channelId, + bss_desc_ptr->rssi); + if (ie_len) { + qdf_mem_copy(&bss_desc_ptr->ieFields, + bcn_proberesp_ptr + + (SIR_MAC_HDR_LEN_3A + SIR_MAC_B_PR_SSID_OFFSET), + ie_len); + } + qdf_mem_free(parsed_frm_ptr); + return QDF_STATUS_SUCCESS; +} +/** + * pe_roam_synch_callback() - PE level callback for roam synch propagation + * @mac_ctx: MAC Context + * @roam_sync_ind_ptr: Roam synch indication buffer pointer + * @bss_desc: BSS Descriptor pointer + * + * This is a PE level callback called from WMA to complete the roam synch + * propagation at PE level and also fill the BSS descriptor which will be + * helpful further to complete the roam synch propagation. + * + * Return: Success or Failure status + */ +QDF_STATUS pe_roam_synch_callback(tpAniSirGlobal mac_ctx, + roam_offload_synch_ind *roam_sync_ind_ptr, + tpSirBssDescription bss_desc) +{ + tpPESession session_ptr; + tpPESession ft_session_ptr; + uint8_t session_id; + tpDphHashNode curr_sta_ds; + uint16_t aid; + tpAddBssParams add_bss_params; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + uint16_t join_rsp_len; + + if (!roam_sync_ind_ptr) { + lim_log(mac_ctx, LOGE, FL("LFR3:roam_sync_ind_ptr is NULL")); + return status; + } + lim_log(mac_ctx, LOG1, FL("LFR3:Received WMA_ROAM_OFFLOAD_SYNCH_IND")); + lim_log(mac_ctx, QDF_TRACE_LEVEL_DEBUG, FL("LFR3:auth=%d, vdevId=%d"), + roam_sync_ind_ptr->authStatus, roam_sync_ind_ptr->roamedVdevId); + lim_print_mac_addr(mac_ctx, roam_sync_ind_ptr->bssid.bytes, + QDF_TRACE_LEVEL_DEBUG); + session_ptr = pe_find_session_by_sme_session_id(mac_ctx, + roam_sync_ind_ptr->roamedVdevId); + if (session_ptr == NULL) { + lim_log(mac_ctx, LOGE, FL("LFR3:Unable to find session")); + return status; + } + if (!LIM_IS_STA_ROLE(session_ptr)) { + lim_log(mac_ctx, LOGE, FL("LFR3:session is not in STA mode")); + return status; + } + /* + * If deauth from AP already in progress, ignore Roam Synch Indication + * from firmware. + */ + if (session_ptr->limSmeState != eLIM_SME_LINK_EST_STATE) { + lim_log(mac_ctx, LOGE, FL("LFR3: Not in Link est state")); + return status; + } + status = lim_roam_fill_bss_descr(mac_ctx, roam_sync_ind_ptr, bss_desc); + if (!QDF_IS_STATUS_SUCCESS(status)) { + lim_log(mac_ctx, LOGE, FL("LFR3:Failed to fill Bss Descr")); + return status; + } + status = QDF_STATUS_E_FAILURE; + ft_session_ptr = pe_create_session(mac_ctx, bss_desc->bssId, + &session_id, mac_ctx->lim.maxStation, + eSIR_INFRASTRUCTURE_MODE); + if (ft_session_ptr == NULL) { + lim_log(mac_ctx, LOGE, FL("LFR3:Cannot create PE Session")); + lim_print_mac_addr(mac_ctx, bss_desc->bssId, LOGE); + return status; + } + ft_session_ptr->peSessionId = session_id; + sir_copy_mac_addr(ft_session_ptr->selfMacAddr, session_ptr->selfMacAddr); + sir_copy_mac_addr(roam_sync_ind_ptr->self_mac.bytes, + session_ptr->selfMacAddr); + sir_copy_mac_addr(ft_session_ptr->limReAssocbssId, bss_desc->bssId); + ft_session_ptr->bssType = eSIR_INFRASTRUCTURE_MODE; + session_ptr->bRoamSynchInProgress = true; + ft_session_ptr->bRoamSynchInProgress = true; + ft_session_ptr->limSystemRole = eLIM_STA_ROLE; + sir_copy_mac_addr(session_ptr->limReAssocbssId, bss_desc->bssId); + ft_session_ptr->csaOffloadEnable = session_ptr->csaOffloadEnable; + + lim_fill_ft_session(mac_ctx, bss_desc, ft_session_ptr, session_ptr); + + if (IS_5G_CH(ft_session_ptr->currentOperChannel)) + ft_session_ptr->vdev_nss = mac_ctx->vdev_type_nss_5g.sta; + else + ft_session_ptr->vdev_nss = mac_ctx->vdev_type_nss_2g.sta; + + ft_session_ptr->nss = ft_session_ptr->vdev_nss; + + lim_ft_prepare_add_bss_req(mac_ctx, false, ft_session_ptr, bss_desc); + roam_sync_ind_ptr->add_bss_params = + (tpAddBssParams) ft_session_ptr->ftPEContext.pAddBssReq; + add_bss_params = ft_session_ptr->ftPEContext.pAddBssReq; + lim_delete_tdls_peers(mac_ctx, session_ptr); + curr_sta_ds = dph_lookup_hash_entry(mac_ctx, session_ptr->bssId, + &aid, &session_ptr->dph.dphHashTable); + if (curr_sta_ds == NULL) { + lim_log(mac_ctx, LOGE, FL("LFR3:failed to lookup hash entry")); + ft_session_ptr->bRoamSynchInProgress = false; + return status; + } + session_ptr->limSmeState = eLIM_SME_IDLE_STATE; + lim_cleanup_rx_path(mac_ctx, curr_sta_ds, session_ptr); + lim_delete_dph_hash_entry(mac_ctx, curr_sta_ds->staAddr, + aid, session_ptr); + pe_delete_session(mac_ctx, session_ptr); + session_ptr = NULL; + curr_sta_ds = dph_add_hash_entry(mac_ctx, + roam_sync_ind_ptr->bssid.bytes, DPH_STA_HASH_INDEX_PEER, + &ft_session_ptr->dph.dphHashTable); + if (curr_sta_ds == NULL) { + lim_log(mac_ctx, LOGE, FL("LFR3:failed to add hash entry for")); + lim_print_mac_addr(mac_ctx, + add_bss_params->staContext.staMac, LOGE); + ft_session_ptr->bRoamSynchInProgress = false; + return status; + } + ft_session_ptr->bssIdx = (uint8_t) add_bss_params->bssIdx; + + curr_sta_ds->bssId = add_bss_params->bssIdx; + curr_sta_ds->staIndex = + add_bss_params->staContext.staIdx; + curr_sta_ds->ucUcastSig = + add_bss_params->staContext.ucUcastSig; + curr_sta_ds->ucBcastSig = + add_bss_params->staContext.ucBcastSig; + rrm_cache_mgmt_tx_power(mac_ctx, + add_bss_params->txMgmtPower, ft_session_ptr); + mac_ctx->roam.reassocRespLen = roam_sync_ind_ptr->reassocRespLength; + mac_ctx->roam.pReassocResp = + qdf_mem_malloc(mac_ctx->roam.reassocRespLen); + if (NULL == mac_ctx->roam.pReassocResp) { + lim_log(mac_ctx, LOGE, FL("LFR3:assoc resp mem alloc failed")); + ft_session_ptr->bRoamSynchInProgress = false; + return QDF_STATUS_E_NOMEM; + } + qdf_mem_copy(mac_ctx->roam.pReassocResp, + (uint8_t *)roam_sync_ind_ptr + + roam_sync_ind_ptr->reassocRespOffset, + mac_ctx->roam.reassocRespLen); + + lim_log(mac_ctx, LOG1, FL("LFR3:the reassoc resp frame data:")); + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO, + mac_ctx->roam.pReassocResp, + mac_ctx->roam.reassocRespLen); + ft_session_ptr->bRoamSynchInProgress = true; + lim_process_assoc_rsp_frame(mac_ctx, mac_ctx->roam.pReassocResp, + LIM_REASSOC, ft_session_ptr); + roam_sync_ind_ptr->aid = ft_session_ptr->limAID; + curr_sta_ds->mlmStaContext.mlmState = + eLIM_MLM_LINK_ESTABLISHED_STATE; + curr_sta_ds->nss = ft_session_ptr->nss; + roam_sync_ind_ptr->nss = ft_session_ptr->nss; + ft_session_ptr->limMlmState = eLIM_MLM_LINK_ESTABLISHED_STATE; + lim_init_tdls_data(mac_ctx, ft_session_ptr); + join_rsp_len = ft_session_ptr->RICDataLen + + sizeof(tSirSmeJoinRsp) - sizeof(uint8_t); + +#ifdef FEATURE_WLAN_ESE + join_rsp_len += ft_session_ptr->tspecLen; + lim_log(mac_ctx, LOG1, FL("tspecLen = %d"), + ft_session_ptr->tspecLen); +#endif + + roam_sync_ind_ptr->join_rsp = qdf_mem_malloc(join_rsp_len); + if (NULL == roam_sync_ind_ptr->join_rsp) { + lim_log(mac_ctx, LOGE, FL("LFR3:mem alloc failed")); + ft_session_ptr->bRoamSynchInProgress = false; + if (mac_ctx->roam.pReassocResp) + qdf_mem_free(mac_ctx->roam.pReassocResp); + mac_ctx->roam.pReassocResp = NULL; + return QDF_STATUS_E_NOMEM; + } + + lim_log(mac_ctx, LOG1, FL("Session RicLength = %d"), + ft_session_ptr->RICDataLen); + if (ft_session_ptr->ricData != NULL) { + roam_sync_ind_ptr->join_rsp->parsedRicRspLen = + ft_session_ptr->RICDataLen; + qdf_mem_copy(roam_sync_ind_ptr->join_rsp->frames, + ft_session_ptr->ricData, + roam_sync_ind_ptr->join_rsp->parsedRicRspLen); + qdf_mem_free(ft_session_ptr->ricData); + ft_session_ptr->ricData = NULL; + ft_session_ptr->RICDataLen = 0; + } + +#ifdef FEATURE_WLAN_ESE + if (ft_session_ptr->tspecIes != NULL) { + roam_sync_ind_ptr->join_rsp->tspecIeLen = + ft_session_ptr->tspecLen; + qdf_mem_copy(roam_sync_ind_ptr->join_rsp->frames + + roam_sync_ind_ptr->join_rsp->parsedRicRspLen, + ft_session_ptr->tspecIes, + roam_sync_ind_ptr->join_rsp->tspecIeLen); + qdf_mem_free(ft_session_ptr->tspecIes); + ft_session_ptr->tspecIes = NULL; + ft_session_ptr->tspecLen = 0; + } +#endif + + roam_sync_ind_ptr->join_rsp->vht_channel_width = + ft_session_ptr->ch_width; + roam_sync_ind_ptr->join_rsp->staId = curr_sta_ds->staIndex; + roam_sync_ind_ptr->join_rsp->ucastSig = curr_sta_ds->ucUcastSig; + roam_sync_ind_ptr->join_rsp->bcastSig = curr_sta_ds->ucBcastSig; + roam_sync_ind_ptr->join_rsp->timingMeasCap = curr_sta_ds->timingMeasCap; + roam_sync_ind_ptr->join_rsp->nss = curr_sta_ds->nss; + roam_sync_ind_ptr->join_rsp->max_rate_flags = + lim_get_max_rate_flags(mac_ctx, curr_sta_ds); + lim_set_tdls_flags(roam_sync_ind_ptr, ft_session_ptr); + roam_sync_ind_ptr->join_rsp->aid = ft_session_ptr->limAID; + lim_fill_join_rsp_ht_caps(ft_session_ptr, roam_sync_ind_ptr->join_rsp); + ft_session_ptr->limPrevSmeState = ft_session_ptr->limSmeState; + ft_session_ptr->limSmeState = eLIM_SME_LINK_EST_STATE; + ft_session_ptr->bRoamSynchInProgress = false; + if (mac_ctx->roam.pReassocResp) + qdf_mem_free(mac_ctx->roam.pReassocResp); + mac_ctx->roam.pReassocResp = NULL; + + if (roam_sync_ind_ptr->authStatus == CSR_ROAM_AUTH_STATUS_AUTHENTICATED) + ft_session_ptr->is_key_installed = true; + + return QDF_STATUS_SUCCESS; +} +#endif + +static bool lim_is_beacon_miss_scenario(tpAniSirGlobal pMac, + uint8_t *pRxPacketInfo) +{ + tpSirMacMgmtHdr pHdr = WMA_GET_RX_MAC_HEADER(pRxPacketInfo); + uint8_t sessionId; + tpPESession psessionEntry = + pe_find_session_by_bssid(pMac, pHdr->bssId, &sessionId); + + if (psessionEntry && psessionEntry->pmmOffloadInfo.bcnmiss) + return true; + return false; +} + +/** ----------------------------------------------------------------- + \brief lim_is_pkt_candidate_for_drop() - decides whether to drop the frame or not + + This function is called before enqueuing the frame to PE queue for further processing. + This prevents unnecessary frames getting into PE Queue and drops them right away. + Frames will be droped in the following scenarios: + + - In Scan State, drop the frames which are not marked as scan frames + - In non-Scan state, drop the frames which are marked as scan frames. + - Drop INFRA Beacons and Probe Responses in IBSS Mode + - Drop the Probe Request in IBSS mode, if STA did not send out the last beacon + + \param pMac - global mac structure + \return - none + \sa + ----------------------------------------------------------------- */ + +tMgmtFrmDropReason lim_is_pkt_candidate_for_drop(tpAniSirGlobal pMac, + uint8_t *pRxPacketInfo, + uint32_t subType) +{ + uint32_t framelen; + uint8_t *pBody; + tSirMacCapabilityInfo capabilityInfo; + tpSirMacMgmtHdr pHdr = NULL; + tpPESession psessionEntry = NULL; + uint8_t sessionId; + + /* + * + * In scan mode, drop only Beacon/Probe Response which are NOT marked as scan-frames. + * In non-scan mode, drop only Beacon/Probe Response which are marked as scan frames. + * Allow other mgmt frames, they must be from our own AP, as we don't allow + * other than beacons or probe responses in scan state. + */ + if ((subType == SIR_MAC_MGMT_BEACON) || + (subType == SIR_MAC_MGMT_PROBE_RSP)) { + if (lim_is_beacon_miss_scenario(pMac, pRxPacketInfo)) { + MTRACE(mac_trace + (pMac, TRACE_CODE_INFO_LOG, 0, + eLOG_NODROP_MISSED_BEACON_SCENARIO)); + return eMGMT_DROP_NO_DROP; + } + if (lim_is_system_in_scan_state(pMac)) { + return eMGMT_DROP_NO_DROP; + } else if (WMA_IS_RX_IN_SCAN(pRxPacketInfo)) { + return eMGMT_DROP_SCAN_MODE_FRAME; + } else { + /* Beacons and probe responses can come in any time + * because of parallel scans. Don't drop them. + */ + return eMGMT_DROP_NO_DROP; + } + } + + framelen = WMA_GET_RX_PAYLOAD_LEN(pRxPacketInfo); + pBody = WMA_GET_RX_MPDU_DATA(pRxPacketInfo); + + /* Drop INFRA Beacons and Probe Responses in IBSS Mode */ + if ((subType == SIR_MAC_MGMT_BEACON) || + (subType == SIR_MAC_MGMT_PROBE_RSP)) { + /* drop the frame if length is less than 12 */ + if (framelen < LIM_MIN_BCN_PR_LENGTH) + return eMGMT_DROP_INVALID_SIZE; + + *((uint16_t *) &capabilityInfo) = + sir_read_u16(pBody + LIM_BCN_PR_CAPABILITY_OFFSET); + + /* Note sure if this is sufficient, basically this condition allows all probe responses and + * beacons from an infrastructure network + */ + if (!capabilityInfo.ibss) + return eMGMT_DROP_NO_DROP; + + /* This can be enhanced to even check the SSID before deciding to enque the frame. */ + if (capabilityInfo.ess) + return eMGMT_DROP_INFRA_BCN_IN_IBSS; + } else if ((subType == SIR_MAC_MGMT_PROBE_REQ) && + (!WMA_GET_RX_BEACON_SENT(pRxPacketInfo))) { + pHdr = WMA_GET_RX_MAC_HEADER(pRxPacketInfo); + psessionEntry = + pe_find_session_by_bssid(pMac, pHdr->bssId, &sessionId); + if ((psessionEntry && !LIM_IS_IBSS_ROLE(psessionEntry)) || + (!psessionEntry)) + return eMGMT_DROP_NO_DROP; + + /* Drop the Probe Request in IBSS mode, if STA did not send out the last beacon */ + /* In IBSS, the node which sends out the beacon, is supposed to respond to ProbeReq */ + return eMGMT_DROP_NOT_LAST_IBSS_BCN; + } + + return eMGMT_DROP_NO_DROP; +} + +void lim_update_lost_link_info(tpAniSirGlobal mac, tpPESession session, + int32_t rssi) +{ + struct sir_lost_link_info *lost_link_info; + tSirMsgQ mmh_msg; + + if ((NULL == mac) || (NULL == session)) { + QDF_TRACE(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_ERROR, + FL("parameter NULL")); + return; + } + if (!LIM_IS_STA_ROLE(session)) { + lim_log(mac, LOGE, FL("not STA mode, do nothing")); + return; + } + + lost_link_info = qdf_mem_malloc(sizeof(*lost_link_info)); + if (NULL == lost_link_info) { + lim_log(mac, LOGE, FL("lost_link_info allocation failure")); + return; + } + + lost_link_info->vdev_id = session->smeSessionId; + lost_link_info->rssi = rssi; + mmh_msg.type = eWNI_SME_LOST_LINK_INFO_IND; + mmh_msg.bodyptr = lost_link_info; + mmh_msg.bodyval = 0; + lim_log(mac, LOG1, + FL("post eWNI_SME_LOST_LINK_INFO_IND, bss_idx %d, rssi %d"), + lost_link_info->vdev_id, lost_link_info->rssi); + + lim_sys_process_mmh_msg_api(mac, &mmh_msg, ePROT); +} + +QDF_STATUS pe_acquire_global_lock(tAniSirLim *psPe) +{ + QDF_STATUS status = QDF_STATUS_E_INVAL; + + if (psPe) { + if (QDF_IS_STATUS_SUCCESS + (qdf_mutex_acquire(&psPe->lkPeGlobalLock))) { + status = QDF_STATUS_SUCCESS; + } + } + return status; +} + +QDF_STATUS pe_release_global_lock(tAniSirLim *psPe) +{ + QDF_STATUS status = QDF_STATUS_E_INVAL; + if (psPe) { + if (QDF_IS_STATUS_SUCCESS + (qdf_mutex_release(&psPe->lkPeGlobalLock))) { + status = QDF_STATUS_SUCCESS; + } + } + return status; +} + +/** + * lim_mon_init_session() - create PE session for monitor mode operation + * @mac_ptr: mac pointer + * @msg: Pointer to struct sir_create_session type. + * + * Return: NONE + */ +void lim_mon_init_session(tpAniSirGlobal mac_ptr, + struct sir_create_session *msg) +{ + tpPESession psession_entry; + uint8_t session_id; + + lim_print_mac_addr(mac_ptr, msg->bss_id.bytes, LOGE); + psession_entry = pe_create_session(mac_ptr, msg->bss_id.bytes, + &session_id, + mac_ptr->lim.maxStation, + eSIR_MONITOR_MODE); + if (psession_entry == NULL) { + QDF_TRACE(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_ERROR, + ("Monitor mode: Session Can not be created")); + lim_print_mac_addr(mac_ptr, msg->bss_id.bytes, LOGE); + return; + } + psession_entry->vhtCapability = 1; +} + +/** + * lim_update_ext_cap_ie() - Update Extended capabilities IE(if present) + * with capabilities of Fine Time measurements(FTM) if set in driver + * + * @mac_ctx: Pointer to Global MAC structure + * @ie_data: Default Scan IE data + * @local_ie_buf: Local Scan IE data + * @local_ie_len: Pointer to length of @ie_data + * + * Return: QDF_STATUS + */ +QDF_STATUS lim_update_ext_cap_ie(tpAniSirGlobal mac_ctx, + uint8_t *ie_data, uint8_t *local_ie_buf, uint16_t *local_ie_len) +{ + uint32_t dot11mode; + bool vht_enabled = false; + tDot11fIEExtCap default_scan_ext_cap = {0}, driver_ext_cap = {0}; + tSirRetStatus status; + + status = lim_strip_extcap_update_struct(mac_ctx, ie_data, + local_ie_len, &default_scan_ext_cap); + if (eSIR_SUCCESS != status) { + lim_log(mac_ctx, LOGE, FL("Strip ext cap fails(%d)"), status); + return QDF_STATUS_E_FAILURE; + } + + /* copy ie prior to ext cap to local buffer */ + qdf_mem_copy(local_ie_buf, ie_data, (*local_ie_len)); + + /* from here ext cap ie starts, set EID */ + local_ie_buf[*local_ie_len] = DOT11F_EID_EXTCAP; + + wlan_cfg_get_int(mac_ctx, WNI_CFG_DOT11_MODE, &dot11mode); + if (IS_DOT11_MODE_VHT(dot11mode)) + vht_enabled = true; + + status = populate_dot11f_ext_cap(mac_ctx, vht_enabled, + &driver_ext_cap, NULL); + if (eSIR_SUCCESS != status) { + lim_log(mac_ctx, LOGE, FL("Failed(%d) to create ext cap IE. Use default value instead"), + status); + local_ie_buf[*local_ie_len + 1] = DOT11F_IE_EXTCAP_MAX_LEN; + (*local_ie_len) += EXT_CAP_IE_HDR_LEN; + qdf_mem_copy(local_ie_buf + (*local_ie_len), + default_scan_ext_cap.bytes, + DOT11F_IE_EXTCAP_MAX_LEN); + (*local_ie_len) += DOT11F_IE_EXTCAP_MAX_LEN; + return QDF_STATUS_SUCCESS; + } + lim_merge_extcap_struct(&driver_ext_cap, &default_scan_ext_cap, true); + local_ie_buf[*local_ie_len + 1] = driver_ext_cap.num_bytes; + (*local_ie_len) += EXT_CAP_IE_HDR_LEN; + qdf_mem_copy(local_ie_buf + (*local_ie_len), + driver_ext_cap.bytes, driver_ext_cap.num_bytes); + (*local_ie_len) += driver_ext_cap.num_bytes; + return QDF_STATUS_SUCCESS; +} + +/** + * lim_add_qcn_ie() - Add QCN IE to a given IE buffer + * + * @mac_ctx: Pointer to Global MAC structure + * @ie_data: IE buffer + * @ie_len: length of the @ie_data + * + * Return: QDF_STATUS + */ +QDF_STATUS lim_add_qcn_ie(tpAniSirGlobal mac_ctx, uint8_t *ie_data, + uint16_t *ie_len) +{ + tDot11fIEQCN_IE qcn_ie; + uint8_t qcn_ie_hdr[QCN_IE_HDR_LEN] + = {IE_EID_VENDOR, DOT11F_IE_QCN_IE_MAX_LEN, + 0x8C, 0xFD, 0xF0, 0x1}; + + if (((*ie_len) + DOT11F_IE_QCN_IE_MAX_LEN) > MAX_DEFAULT_SCAN_IE_LEN) { + lim_log(mac_ctx, LOGE, FL("IE buffer not enough for QCN IE")); + return QDF_STATUS_E_FAILURE; + } + + /* Add QCN IE header */ + qdf_mem_copy(ie_data + (*ie_len), qcn_ie_hdr, QCN_IE_HDR_LEN); + (*ie_len) += QCN_IE_HDR_LEN; + + /* Retrieve Version sub-attribute data */ + populate_dot11f_qcn_ie(&qcn_ie); + + /* Add QCN IE data[version sub attribute] */ + qdf_mem_copy(ie_data + (*ie_len), qcn_ie.version, + (QCN_IE_VERSION_SUBATTR_LEN)); + (*ie_len) += (QCN_IE_VERSION_SUBATTR_LEN); + return QDF_STATUS_SUCCESS; +} diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_assoc_utils.c b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_assoc_utils.c new file mode 100644 index 0000000000000000000000000000000000000000..75df55126cb488a52ca6e893fa7f3909b1aa5bc9 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_assoc_utils.c @@ -0,0 +1,4923 @@ +/* + * Copyright (c) 2011-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * This file lim_assoc_utils.cc contains the utility functions + * LIM uses while processing (Re) Association messages. + * Author: Chandra Modumudi + * Date: 02/13/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + * 05/26/10 js WPA handling in (Re)Assoc frames + * + */ + +#include "cds_api.h" +#include "ani_global.h" +#include "wni_api.h" +#include "sir_common.h" + +#include "wni_cfg.h" +#include "cfg_api.h" + +#include "sch_api.h" +#include "utils_api.h" +#include "lim_utils.h" +#include "lim_assoc_utils.h" +#include "lim_security_utils.h" +#include "lim_ser_des_utils.h" +#include "lim_sta_hash_api.h" +#include "lim_admit_control.h" +#include "lim_send_messages.h" +#include "lim_ibss_peer_mgmt.h" +#include "lim_ft_defs.h" +#include "lim_session.h" + +#include "qdf_types.h" +#include "wma_types.h" +#include "lim_types.h" + +/** + * lim_cmp_ssid() - utility function to compare SSIDs + * @rx_ssid: Received SSID + * @session_entry: Session entry + * + * This function is called in various places within LIM code + * to determine whether received SSID is same as SSID in use. + * + * Return: zero if SSID matched, non-zero otherwise. + */ +uint32_t lim_cmp_ssid(tSirMacSSid *rx_ssid, tpPESession session_entry) +{ + return qdf_mem_cmp(rx_ssid, &session_entry->ssId, + session_entry->ssId.length); +} + +/** + * lim_compare_capabilities() + * + ***FUNCTION: + * This function is called during Association/Reassociation + * frame handling to determine whether received capabilities + * match with local capabilities or not. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param pMac - Pointer to Global MAC structure + * @param pAssocReq - Pointer to received Assoc Req frame + * @param pLocalCapabs - Pointer to local capabilities + * + * @return status - true for Capabilitity match else false. + */ + +uint8_t +lim_compare_capabilities(tpAniSirGlobal pMac, + tSirAssocReq *pAssocReq, + tSirMacCapabilityInfo *pLocalCapabs, + tpPESession psessionEntry) +{ + uint32_t val; + + if (LIM_IS_AP_ROLE(psessionEntry) && + (pAssocReq->capabilityInfo.ibss)) { + /* Requesting STA asserting IBSS capability. */ + lim_log(pMac, LOG1, + FL("Requesting STA asserting IBSS capability")); + return false; + } + /* Compare CF capabilities */ + if (pAssocReq->capabilityInfo.cfPollable || + pAssocReq->capabilityInfo.cfPollReq) { + /* AP does not support PCF functionality */ + lim_log(pMac, LOG1, + FL(" AP does not support PCF functionality")); + return false; + } + /* Compare short preamble capability */ + if (pAssocReq->capabilityInfo.shortPreamble && + (pAssocReq->capabilityInfo.shortPreamble != + pLocalCapabs->shortPreamble)) { + /* Allowing a STA requesting short preamble while */ + /* AP does not support it */ + } + + lim_log(pMac, LOG1, "QoS in AssocReq: %d, local capabs qos: %d", + pAssocReq->capabilityInfo.qos, pLocalCapabs->qos); + + /* Compare QoS capability */ + if (pAssocReq->capabilityInfo.qos && + (pAssocReq->capabilityInfo.qos != pLocalCapabs->qos)) { + /*Temporary hack for UPF to skip 11e capability check in order to interop with + CSR - proper fix needs to be put in place */ + lim_log(pMac, LOG1, + FL + ("Received unmatched QOS but cfg to suppress - continuing")); + } + + /* + * If AP supports shortSlot and if apple user has + * enforced association only from shortSlot station, + * then AP must reject any station that does not support + * shortSlot + */ + if (LIM_IS_AP_ROLE(psessionEntry) && + (pLocalCapabs->shortSlotTime == 1)) { + if (wlan_cfg_get_int + (pMac, WNI_CFG_ACCEPT_SHORT_SLOT_ASSOC_ONLY, + &val) != eSIR_SUCCESS) { + lim_log(pMac, LOGP, + FL + ("error getting WNI_CFG_FORCE_SHORT_SLOT_ASSOC_ONLY ")); + return false; + } + if (val) { + if (pAssocReq->capabilityInfo.shortSlotTime != + pLocalCapabs->shortSlotTime) { + lim_log(pMac, LOGE, + FL + ("AP rejects association as station doesnt support shortslot time")); + return false; + } + return false; + } + } + + return true; +} /****** end lim_compare_capabilities() ******/ + +/** + * lim_check_rx_basic_rates() + * + ***FUNCTION: + * This function is called during Association/Reassociation + * frame handling to determine whether received rates in + * Assoc/Reassoc request frames include all BSS basic rates + * or not. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param rxRateSet - pointer to SSID structure + * + * @return status - true if ALL BSS basic rates are present in the + * received rateset else false. + */ + +uint8_t +lim_check_rx_basic_rates(tpAniSirGlobal pMac, tSirMacRateSet rxRateSet, + tpPESession psessionEntry) +{ + tSirMacRateSet *pRateSet, basicRate; + uint8_t i, j, k, match; + + pRateSet = qdf_mem_malloc(sizeof(tSirMacRateSet)); + if (NULL == pRateSet) { + lim_log(pMac, LOGP, + FL("call to AllocateMemory failed for RATESET")); + + return false; + } + + /* Copy operational rate set from session Entry */ + qdf_mem_copy(pRateSet->rate, (psessionEntry->rateSet.rate), + psessionEntry->rateSet.numRates); + + pRateSet->numRates = psessionEntry->rateSet.numRates; + + /* Extract BSS basic rateset from operational rateset */ + for (i = 0, j = 0; + ((i < pRateSet->numRates) && (i < SIR_MAC_RATESET_EID_MAX)); i++) { + if ((pRateSet->rate[i] & 0x80) == 0x80) { + /* msb is set, so this is a basic rate */ + basicRate.rate[j++] = pRateSet->rate[i]; + } + } + + /* + * For each BSS basic rate, find if it is present in the + * received rateset. + */ + for (k = 0; k < j; k++) { + match = 0; + for (i = 0; + ((i < rxRateSet.numRates) + && (i < SIR_MAC_RATESET_EID_MAX)); i++) { + if ((rxRateSet.rate[i] | 0x80) == basicRate.rate[k]) + match = 1; + } + + if (!match) { + /* Free up memory allocated for rateset */ + qdf_mem_free((uint8_t *) pRateSet); + + return false; + } + } + + /* Free up memory allocated for rateset */ + qdf_mem_free((uint8_t *) pRateSet); + + return true; +} /****** end lim_check_rx_basic_rates() ******/ + +/** + * lim_check_mcs_set() + * + ***FUNCTION: + * This function is called during Association/Reassociation + * frame handling to determine whether received MCS rates in + * Assoc/Reassoc request frames includes all Basic MCS Rate Set or not. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param supportedMCSSet - pointer to Supported MCS Rate Set + * + * @return status - true if ALL MCS Basic Rate Set rates are present in the + * received rateset else false. + */ + +uint8_t lim_check_mcs_set(tpAniSirGlobal pMac, uint8_t *supportedMCSSet) +{ + uint8_t basicMCSSet[SIZE_OF_BASIC_MCS_SET] = { 0 }; + uint32_t cfgLen = 0; + uint8_t i; + uint8_t validBytes; + uint8_t lastByteMCSMask = 0x1f; + + cfgLen = WNI_CFG_BASIC_MCS_SET_LEN; + if (wlan_cfg_get_str(pMac, WNI_CFG_BASIC_MCS_SET, + (uint8_t *) basicMCSSet, + (uint32_t *) &cfgLen) != eSIR_SUCCESS) { + /* / Could not get Basic MCS rateset from CFG. Log error. */ + lim_log(pMac, LOGP, FL("could not retrieve Basic MCS rateset")); + return false; + } + + validBytes = VALID_MCS_SIZE / 8; + + /* check if all the Basic MCS Bits are set in supported MCS bitmap */ + for (i = 0; i < validBytes; i++) { + if ((basicMCSSet[i] & supportedMCSSet[i]) != basicMCSSet[i]) { + /* Log is avaiable in calling function in file lim_process_assoc_req_frame.c */ + lim_log(pMac, LOGW, + FL + ("One of Basic MCS Set Rates is not supported by the Station.")); + return false; + } + } + + /* check the last 5 bits of the valid MCS bitmap */ + if (((basicMCSSet[i] & lastByteMCSMask) & + (supportedMCSSet[i] & lastByteMCSMask)) != + (basicMCSSet[i] & lastByteMCSMask)) { + lim_log(pMac, LOGW, + FL + ("One of Basic MCS Set Rates is not supported by the Station.")); + return false; + } + + return true; +} + +#define SECURITY_SUITE_TYPE_MASK 0xFF +#define SECURITY_SUITE_TYPE_WEP40 0x1 +#define SECURITY_SUITE_TYPE_TKIP 0x2 +#define SECURITY_SUITE_TYPE_CCMP 0x4 +#define SECURITY_SUITE_TYPE_WEP104 0x4 + +/** + * lim_check_rx_rsn_ie_match()- validate received rsn ie with supported cipher + * suites. + * @mac_ctx: pointer to global mac structure + * @rx_rsn_ie: received rsn IE + * @session_entry: pe session entry + * @sta_is_ht: peer station HT capability + * @pmf_connection: set to true if this is pmf connection + * + * This function is called during Association/Reassociation + * frame handling to determine whether received RSN in + * Assoc/Reassoc request frames include supported cipher suites or not. + * + * Return: eSIR_SUCCESS if ALL BSS basic rates are present in the + * received rateset else failure status. + */ + +uint8_t +lim_check_rx_rsn_ie_match(tpAniSirGlobal mac_ctx, tDot11fIERSN rx_rsn_ie, + tpPESession session_entry, uint8_t sta_is_ht, + bool *pmf_connection) +{ + tDot11fIERSN *rsn_ie; + uint8_t i, j, match, only_non_ht_cipher = 1; +#ifdef WLAN_FEATURE_11W + bool we_are_pmf_capable; + bool we_require_pmf; + bool they_are_pmf_capable; + bool they_require_pmf; +#endif + + /* RSN IE should be received from PE */ + rsn_ie = &session_entry->gStartBssRSNIe; + + /* Check groupwise cipher suite */ + for (i = 0; i < sizeof(rx_rsn_ie.gp_cipher_suite); i++) + if (rsn_ie->gp_cipher_suite[i] != + rx_rsn_ie.gp_cipher_suite[i]) { + lim_log(mac_ctx, LOG3, + FL("Invalid groupwise cipher suite")); + return eSIR_MAC_INVALID_GROUP_CIPHER_STATUS; + } + + /* + * For each Pairwise cipher suite check whether we support + * received pairwise + */ + match = 0; + for (i = 0; i < rx_rsn_ie.pwise_cipher_suite_count; i++) { + for (j = 0; j < rsn_ie->pwise_cipher_suite_count; j++) { + if (!qdf_mem_cmp(&rx_rsn_ie.pwise_cipher_suites[i], + &rsn_ie->pwise_cipher_suites[j], + sizeof(rsn_ie->pwise_cipher_suites[j]))) { + match = 1; + break; + } + } + + if ((sta_is_ht) +#ifdef ANI_LITTLE_BYTE_ENDIAN + && + ((rx_rsn_ie.pwise_cipher_suites[i][3] & + SECURITY_SUITE_TYPE_MASK) == + SECURITY_SUITE_TYPE_CCMP)) +#else + && + ((rx_rsn_ie.pwise_cipher_suites[i][0] & + SECURITY_SUITE_TYPE_MASK) == + SECURITY_SUITE_TYPE_CCMP)) +#endif + only_non_ht_cipher = 0; + + } + + if ((!match) || ((sta_is_ht) && only_non_ht_cipher)) { + lim_log(mac_ctx, LOG1, FL("Invalid pairwise cipher suite")); + return eSIR_MAC_INVALID_PAIRWISE_CIPHER_STATUS; + } + /* + * Check RSN capabilities + * Bit 0 of First Byte - PreAuthentication Capability + */ + if (((rx_rsn_ie.RSN_Cap[0] >> 0) & 0x1) == true) { + /* this is supported by AP only */ + lim_log(mac_ctx, LOG1, + FL("Invalid RSN information element capabilities")); + return eSIR_MAC_INVALID_RSN_IE_CAPABILITIES_STATUS; + } + + *pmf_connection = false; + +#ifdef WLAN_FEATURE_11W + we_are_pmf_capable = session_entry->pLimStartBssReq->pmfCapable; + we_require_pmf = session_entry->pLimStartBssReq->pmfRequired; + they_are_pmf_capable = (rx_rsn_ie.RSN_Cap[0] >> 7) & 0x1; + they_require_pmf = (rx_rsn_ie.RSN_Cap[0] >> 6) & 0x1; + + if ((they_require_pmf && they_are_pmf_capable && !we_are_pmf_capable) || + (we_require_pmf && !they_are_pmf_capable)) { + lim_log(mac_ctx, LOG1, + FL("Association fail, robust management frames policy" + " violation they_require_pmf =%d" + " theyArePMFCapable %d weArePMFCapable %d" + " weRequirePMF %d theyArePMFCapable %d"), + they_require_pmf, they_are_pmf_capable, + we_are_pmf_capable, we_require_pmf, + they_are_pmf_capable); + return eSIR_MAC_ROBUST_MGMT_FRAMES_POLICY_VIOLATION; + } + + if (they_are_pmf_capable && we_are_pmf_capable) + *pmf_connection = true; + + lim_log(mac_ctx, LOG1, + FL("weAreCapable %d, weRequire %d, theyAreCapable %d," + " theyRequire %d, PMFconnection %d"), + we_are_pmf_capable, we_require_pmf, they_are_pmf_capable, + they_require_pmf, *pmf_connection); +#endif + + return eSIR_SUCCESS; +} + +/** + * lim_check_rx_wpa_ie_match() - to check supported cipher suites + * + * @mac: pointer to global mac structure + * @rx_wpaie: Received WPA IE in (Re)Assco req + * @session_entry: pointer to PE session + * @sta_is_ht: peer station is HT + * + * This function is called during Association/Reassociation + * frame handling to determine whether received RSN in + * Assoc/Reassoc request frames include supported cipher suites or not. + * + * Return: Success if ALL BSS basic rates are present in the + * received rateset else failure status. + */ + +uint8_t +lim_check_rx_wpa_ie_match(tpAniSirGlobal mac, tDot11fIEWPA rx_wpaie, + tpPESession session_entry, uint8_t sta_is_ht) +{ + tDot11fIEWPA *wpa_ie; + uint8_t i, j, match, only_non_ht_cipher = 1; + + /* WPA IE should be received from PE */ + wpa_ie = &session_entry->gStartBssWPAIe; + + /* Check groupwise cipher suite */ + for (i = 0; i < 4; i++) { + if (wpa_ie->multicast_cipher[i] != rx_wpaie.multicast_cipher[i]) { + lim_log(mac, LOG1, + FL("Invalid groupwise cipher suite")); + return eSIR_MAC_INVALID_GROUP_CIPHER_STATUS; + } + } + + /* + * For each Pairwise cipher suite check whether we support + * received pairwise + */ + match = 0; + for (i = 0; i < rx_wpaie.unicast_cipher_count; i++) { + for (j = 0; j < wpa_ie->unicast_cipher_count; j++) { + if (!qdf_mem_cmp(rx_wpaie.unicast_ciphers[i], + wpa_ie->unicast_ciphers[j], 4)) { + match = 1; + break; + } + } + + if ((sta_is_ht) +#ifdef ANI_LITTLE_BYTE_ENDIAN + && + ((rx_wpaie. + unicast_ciphers[i][3] & SECURITY_SUITE_TYPE_MASK) == + SECURITY_SUITE_TYPE_CCMP)) +#else + && + ((rx_wpaie. + unicast_ciphers[i][0] & SECURITY_SUITE_TYPE_MASK) == + SECURITY_SUITE_TYPE_CCMP)) +#endif + { + only_non_ht_cipher = 0; + } + + } + + if ((!match) || ((sta_is_ht) && only_non_ht_cipher)) { + lim_log(mac, LOG1, FL("Invalid pairwise cipher suite")); + return eSIR_MAC_CIPHER_SUITE_REJECTED_STATUS; + } + + return eSIR_SUCCESS; +} + +/** + * lim_cleanup_rx_path() + * + ***FUNCTION: + * This function is called to cleanup STA state at SP & RFP. + * + ***LOGIC: + * To circumvent RFP's handling of dummy packet when it does not + * have an incomplete packet for the STA to be deleted, a packet + * with 'more framgents' bit set will be queued to RFP's WQ before + * queuing 'dummy packet'. + * A 'dummy' BD is pushed into RFP's WQ with type=00, subtype=1010 + * (Disassociation frame) and routing flags in BD set to eCPU's + * Low Priority WQ. + * RFP cleans up its local context for the STA id mentioned in the + * BD and then pushes BD to eCPU's low priority WQ. + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param pMac Pointer to Global MAC structure + * @param pStaDs Pointer to the per STA data structure + * initialized by LIM and maintained at DPH + * + * @return None + */ + +tSirRetStatus +lim_cleanup_rx_path(tpAniSirGlobal pMac, tpDphHashNode pStaDs, + tpPESession psessionEntry) +{ + tSirRetStatus retCode = eSIR_SUCCESS; + + lim_log(pMac, LOG1, FL("Cleanup Rx Path for AID : %d" + "psessionEntry->limSmeState : %d, mlmState : %d"), + pStaDs->assocId, psessionEntry->limSmeState, + pStaDs->mlmStaContext.mlmState); + + psessionEntry->isCiscoVendorAP = false; + + if (pMac->lim.gLimAddtsSent) { + MTRACE(mac_trace + (pMac, TRACE_CODE_TIMER_DEACTIVATE, + psessionEntry->peSessionId, eLIM_ADDTS_RSP_TIMER)); + tx_timer_deactivate(&pMac->lim.limTimers.gLimAddtsRspTimer); + lim_log(pMac, LOG1, + FL("Reset gLimAddtsSent flag and send addts timeout to SME")); + lim_process_sme_addts_rsp_timeout(pMac, + pMac->lim.gLimAddtsRspTimerCount); + } + + if (pStaDs->mlmStaContext.mlmState == eLIM_MLM_WT_ASSOC_CNF_STATE) { + lim_deactivate_and_change_per_sta_id_timer(pMac, eLIM_CNF_WAIT_TIMER, + pStaDs->assocId); + + if (!pStaDs->mlmStaContext.updateContext) { + /** + * There is no context at Polaris to delete. + * Release our assigned AID back to the free pool + */ + if (LIM_IS_AP_ROLE(psessionEntry)) { + lim_del_sta(pMac, pStaDs, false, psessionEntry); + lim_release_peer_idx(pMac, pStaDs->assocId, + psessionEntry); + } + lim_delete_dph_hash_entry(pMac, pStaDs->staAddr, + pStaDs->assocId, psessionEntry); + + return retCode; + } + } + /* delete all tspecs associated with this sta. */ + lim_admit_control_delete_sta(pMac, pStaDs->assocId); + + /** + * Make STA hash entry invalid at eCPU so that DPH + * does not process any more data packets and + * releases those BDs + */ + pStaDs->valid = 0; + lim_send_sme_tsm_ie_ind(pMac, psessionEntry, 0, 0, 0); + /* Any roaming related changes should be above this line */ + if (lim_is_roam_synch_in_progress(psessionEntry)) + return eSIR_SUCCESS; + pStaDs->mlmStaContext.mlmState = eLIM_MLM_WT_DEL_STA_RSP_STATE; + + if (LIM_IS_STA_ROLE(psessionEntry)) { + MTRACE(mac_trace + (pMac, TRACE_CODE_MLM_STATE, psessionEntry->peSessionId, + eLIM_MLM_WT_DEL_STA_RSP_STATE)); + psessionEntry->limMlmState = eLIM_MLM_WT_DEL_STA_RSP_STATE; + /* Deactivating probe after heart beat timer */ + lim_deactivate_and_change_timer(pMac, eLIM_PROBE_AFTER_HB_TIMER); + lim_deactivate_and_change_timer(pMac, eLIM_JOIN_FAIL_TIMER); + pMac->lim.gLastBeaconDtimCount = 0; + pMac->lim.gLastBeaconDtimPeriod = 0; + } +#ifdef WLAN_DEBUG + /* increment a debug count */ + pMac->lim.gLimNumRxCleanup++; +#endif + /* Do DEL BSS or DEL STA only if ADD BSS was success */ + if (!psessionEntry->add_bss_failed) { + if (psessionEntry->limSmeState == eLIM_SME_JOIN_FAILURE_STATE) { + retCode = + lim_del_bss(pMac, pStaDs, psessionEntry->bssIdx, + psessionEntry); + } else + retCode = lim_del_sta(pMac, + pStaDs, true, psessionEntry); + } + + return retCode; + +} /*** end lim_cleanup_rx_path() ***/ + +/** + * lim_send_del_sta_cnf() - Send Del sta confirmation + * @pMac: Pointer to Global MAC structure + * @sta_dsaddr: sta ds address + * @staDsAssocId: sta ds association id + * @mlmStaContext: MLM station context + * @statusCode: Status code + * @psessionEntry: Session entry + * + * This function is called to send appropriate CNF message to SME. + * + * Return: None + */ +void +lim_send_del_sta_cnf(tpAniSirGlobal pMac, struct qdf_mac_addr sta_dsaddr, + uint16_t staDsAssocId, tLimMlmStaContext mlmStaContext, + tSirResultCodes statusCode, tpPESession psessionEntry) +{ + tLimMlmDisassocCnf mlmDisassocCnf; + tLimMlmDeauthCnf mlmDeauthCnf; + tLimMlmPurgeStaInd mlmPurgeStaInd; + + lim_log(pMac, LOG1, + FL("Sessionid: %d staDsAssocId: %d Trigger: %d statusCode: %d sta_dsaddr: "MAC_ADDRESS_STR), + psessionEntry->peSessionId, staDsAssocId, + mlmStaContext.cleanupTrigger, statusCode, + MAC_ADDR_ARRAY(sta_dsaddr.bytes)); + + if (LIM_IS_STA_ROLE(psessionEntry)) { + /* Set BSSID at CFG to null */ + tSirMacAddr nullAddr = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + + sir_copy_mac_addr(nullAddr, psessionEntry->bssId); + + /* Free up buffer allocated for JoinReq held by */ + /* MLM state machine */ + if (psessionEntry->pLimMlmJoinReq) { + qdf_mem_free(psessionEntry->pLimMlmJoinReq); + psessionEntry->pLimMlmJoinReq = NULL; + } + + psessionEntry->limAID = 0; + } + + if ((mlmStaContext.cleanupTrigger == + eLIM_HOST_DISASSOC) || + (mlmStaContext.cleanupTrigger == + eLIM_LINK_MONITORING_DISASSOC) || + (mlmStaContext.cleanupTrigger == + eLIM_PROMISCUOUS_MODE_DISASSOC)) { + /** + * Host or LMM driven Disassociation. + * Issue Disassoc Confirm to SME. + */ + lim_log(pMac, LOGW, + FL("Lim Posting DISASSOC_CNF to Sme. Trigger: %d"), + mlmStaContext.cleanupTrigger); + + qdf_mem_copy((uint8_t *) &mlmDisassocCnf.peerMacAddr, + (uint8_t *) sta_dsaddr.bytes, QDF_MAC_ADDR_SIZE); + mlmDisassocCnf.resultCode = statusCode; + mlmDisassocCnf.disassocTrigger = mlmStaContext.cleanupTrigger; + /* Update PE session Id */ + mlmDisassocCnf.sessionId = psessionEntry->peSessionId; + + lim_post_sme_message(pMac, + LIM_MLM_DISASSOC_CNF, + (uint32_t *) &mlmDisassocCnf); + } else if ((mlmStaContext.cleanupTrigger == + eLIM_HOST_DEAUTH) || + (mlmStaContext.cleanupTrigger == + eLIM_LINK_MONITORING_DEAUTH)) { + /** + * Host or LMM driven Deauthentication. + * Issue Deauth Confirm to SME. + */ + lim_log(pMac, LOGW, + FL("Lim Posting DEAUTH_CNF to Sme. Trigger: %d"), + mlmStaContext.cleanupTrigger); + qdf_copy_macaddr(&mlmDeauthCnf.peer_macaddr, &sta_dsaddr); + mlmDeauthCnf.resultCode = statusCode; + mlmDeauthCnf.deauthTrigger = mlmStaContext.cleanupTrigger; + /* PE session Id */ + mlmDeauthCnf.sessionId = psessionEntry->peSessionId; + + lim_post_sme_message(pMac, + LIM_MLM_DEAUTH_CNF, + (uint32_t *) &mlmDeauthCnf); + } else if ((mlmStaContext.cleanupTrigger == + eLIM_PEER_ENTITY_DISASSOC) || + (mlmStaContext.cleanupTrigger == eLIM_PEER_ENTITY_DEAUTH)) { + /** + * Received Disassociation/Deauthentication from peer. + * Issue Purge Ind to SME. + */ + lim_log(pMac, LOGW, + FL("Lim Posting PURGE_STA_IND to Sme. Trigger: %d"), + mlmStaContext.cleanupTrigger); + qdf_mem_copy((uint8_t *) &mlmPurgeStaInd.peerMacAddr, + (uint8_t *) sta_dsaddr.bytes, QDF_MAC_ADDR_SIZE); + mlmPurgeStaInd.reasonCode = + (uint8_t) mlmStaContext.disassocReason; + mlmPurgeStaInd.aid = staDsAssocId; + mlmPurgeStaInd.purgeTrigger = mlmStaContext.cleanupTrigger; + mlmPurgeStaInd.sessionId = psessionEntry->peSessionId; + + lim_post_sme_message(pMac, + LIM_MLM_PURGE_STA_IND, + (uint32_t *) &mlmPurgeStaInd); + } else if (mlmStaContext.cleanupTrigger == eLIM_JOIN_FAILURE) { + /* PE setup the peer entry in HW upfront, right after join is completed. */ + /* If there is a failure during rest of the assoc sequence, this context needs to be cleaned up. */ + uint8_t smesessionId; + uint16_t smetransactionId; + + smesessionId = psessionEntry->smeSessionId; + smetransactionId = psessionEntry->transactionId; + + psessionEntry->limSmeState = eLIM_SME_JOIN_FAILURE_STATE; + MTRACE(mac_trace + (pMac, TRACE_CODE_SME_STATE, psessionEntry->peSessionId, + psessionEntry->limSmeState)); + + /* if it is a reassoc failure to join new AP */ + if ((mlmStaContext.resultCode == + eSIR_SME_FT_REASSOC_TIMEOUT_FAILURE) + || (mlmStaContext.resultCode == eSIR_SME_FT_REASSOC_FAILURE) + || (mlmStaContext.resultCode == + eSIR_SME_REASSOC_TIMEOUT_RESULT_CODE)) { + lim_log(pMac, LOG1, + FL("Lim Posting eWNI_SME_REASSOC_RSP to SME" + "resultCode: %d, statusCode: %d," + "sessionId: %d"), + mlmStaContext.resultCode, + mlmStaContext.protStatusCode, + psessionEntry->peSessionId); + + if (mlmStaContext.resultCode != eSIR_SME_SUCCESS) { + pe_delete_session(pMac, psessionEntry); + psessionEntry = NULL; + } + + lim_send_sme_join_reassoc_rsp(pMac, eWNI_SME_REASSOC_RSP, + mlmStaContext.resultCode, + mlmStaContext.protStatusCode, + psessionEntry, smesessionId, + smetransactionId); + } else { + qdf_mem_free(psessionEntry->pLimJoinReq); + psessionEntry->pLimJoinReq = NULL; + + lim_log(pMac, LOG1, + FL("Lim Posting eWNI_SME_JOIN_RSP to SME." + "resultCode: %d,statusCode: %d," + "sessionId: %d"), + mlmStaContext.resultCode, + mlmStaContext.protStatusCode, + psessionEntry->peSessionId); + + if (mlmStaContext.resultCode != eSIR_SME_SUCCESS) { + pe_delete_session(pMac, psessionEntry); + psessionEntry = NULL; + } + + lim_send_sme_join_reassoc_rsp(pMac, eWNI_SME_JOIN_RSP, + mlmStaContext.resultCode, + mlmStaContext.protStatusCode, + psessionEntry, smesessionId, + smetransactionId); + } + + } else if (mlmStaContext.cleanupTrigger == eLIM_DUPLICATE_ENTRY) { + /** + * LIM driven Disassociation. + * Issue Disassoc Confirm to SME. + */ + lim_log(pMac, LOGW, + FL("Lim Posting DISASSOC_CNF to Sme. Trigger: %d"), + mlmStaContext.cleanupTrigger); + + qdf_mem_copy((uint8_t *) &mlmDisassocCnf.peerMacAddr, + (uint8_t *) sta_dsaddr.bytes, QDF_MAC_ADDR_SIZE); + mlmDisassocCnf.resultCode = statusCode; + mlmDisassocCnf.disassocTrigger = eLIM_DUPLICATE_ENTRY; + /* Update PE session Id */ + mlmDisassocCnf.sessionId = psessionEntry->peSessionId; + + lim_post_sme_message(pMac, + LIM_MLM_DISASSOC_CNF, + (uint32_t *) &mlmDisassocCnf); + } + + if (NULL != psessionEntry && !LIM_IS_AP_ROLE(psessionEntry)) { + pe_delete_session(pMac, psessionEntry); + psessionEntry = NULL; + } +} + +/** + * lim_reject_association() - function to reject Re/Association Request + * + * @mac_ctx: pointer to global mac structure + * @peer_addr: mac address of the peer + * @sub_type: Indicates whether it is Association Request (=0) or + * Reassociation Request (=1) frame + * @add_pre_auth_context:Indicates whether pre-auth context + * to be added for this STA + * @auth_type: Indicates auth type to be added + * @sta_id: Indicates staId of the STA being rejected + * association + * @delete_sta: Indicates whether to delete STA context + * at Polaris + * @result_code: Indicates what reasonCode to be sent in + * Re/Assoc response to STA + * @session_entry: pointer to PE session + * + * This function is called whenever Re/Association Request need + * to be rejected due to failure in assigning an AID or failure + * in adding STA context at Polaris or reject by applications. + * Resources allocated if any are freedup and (Re) Association + * Response frame is sent to requesting STA. Pre-Auth context + * will be added for this STA if it does not exist already + * + * Return: none + */ + +void +lim_reject_association(tpAniSirGlobal mac_ctx, tSirMacAddr peer_addr, + uint8_t sub_type, uint8_t add_pre_auth_context, + tAniAuthType auth_type, uint16_t sta_id, + uint8_t delete_sta, tSirResultCodes result_code, + tpPESession session_entry) +{ + tpDphHashNode sta_ds; + + lim_log(mac_ctx, LOG1, + FL("Sessionid: %d auth_type: %d sub_type: %d add_pre_auth_context: %d sta_id: %d delete_sta: %d result_code : %d peer_addr: " MAC_ADDRESS_STR), + session_entry->peSessionId, auth_type, sub_type, + add_pre_auth_context, sta_id, delete_sta, result_code, + MAC_ADDR_ARRAY(peer_addr)); + + if (add_pre_auth_context) { + /* Create entry for this STA in pre-auth list */ + struct tLimPreAuthNode *auth_node; + + auth_node = lim_acquire_free_pre_auth_node(mac_ctx, + &mac_ctx->lim.gLimPreAuthTimerTable); + + if (auth_node) { + qdf_mem_copy((uint8_t *) auth_node->peerMacAddr, + peer_addr, sizeof(tSirMacAddr)); + auth_node->fTimerStarted = 0; + auth_node->mlmState = eLIM_MLM_AUTHENTICATED_STATE; + auth_node->authType = (tAniAuthType) auth_type; + auth_node->timestamp = qdf_mc_timer_get_system_ticks(); + lim_add_pre_auth_node(mac_ctx, auth_node); + } + } + + if (delete_sta == false) { + lim_send_assoc_rsp_mgmt_frame(mac_ctx, + eSIR_MAC_MAX_ASSOC_STA_REACHED_STATUS, + 1, peer_addr, sub_type, 0, session_entry); + /* Log error */ + lim_log(mac_ctx, LOGW, + FL("received Re/Assoc req when max associated STAs reached from ")); + lim_print_mac_addr(mac_ctx, peer_addr, LOGW); + lim_send_sme_max_assoc_exceeded_ntf(mac_ctx, peer_addr, + session_entry->smeSessionId); + return; + } + + sta_ds = dph_get_hash_entry(mac_ctx, sta_id, + &session_entry->dph.dphHashTable); + + if (sta_ds == NULL) { + lim_log(mac_ctx, LOGW, + FL("No STA context, yet rejecting Association")); + return; + } + + /* + * Polaris has state for this STA. + * Trigger cleanup. + */ + sta_ds->mlmStaContext.cleanupTrigger = eLIM_REASSOC_REJECT; + + /* Receive path cleanup */ + lim_cleanup_rx_path(mac_ctx, sta_ds, session_entry); + + /* + * Send Re/Association Response with + * status code to requesting STA. + */ + lim_send_assoc_rsp_mgmt_frame(mac_ctx, result_code, 0, peer_addr, + sub_type, 0, session_entry); + + if (session_entry->parsedAssocReq[sta_ds->assocId] != NULL) { + uint8_t *assoc_req_frame; + + assoc_req_frame = (uint8_t *)((tpSirAssocReq) (session_entry-> + parsedAssocReq[sta_ds->assocId]))->assocReqFrame; + /* + *Assoction confirmation is complete, + *free the copy of association request frame. + */ + if (assoc_req_frame) { + qdf_mem_free(assoc_req_frame); + assoc_req_frame = NULL; + } + + qdf_mem_free(session_entry->parsedAssocReq[sta_ds->assocId]); + session_entry->parsedAssocReq[sta_ds->assocId] = NULL; + } +} + +/** + * lim_decide_ap_protection_on_ht20_delete() - function to update protection + * parameters. + * @mac_ctx: pointer to global mac structure + * @sta_ds: station node + * @beacon_params: ap beacon parameters + * @session_entry: pe session entry + * + * protection related function while HT20 station is getting deleted. + * + * Return: none + */ +static void +lim_decide_ap_protection_on_ht20_delete(tpAniSirGlobal mac_ctx, + tpDphHashNode sta_ds, + tpUpdateBeaconParams beacon_params, + tpPESession session_entry) +{ + uint32_t i = 0; + + lim_log(mac_ctx, LOG1, + FL("(%d) A HT 20 STA is disassociated. Addr is %pM"), + session_entry->gLimHt20Params.numSta, sta_ds->staAddr); + + if (session_entry->gLimHt20Params.numSta > 0) { + for (i = 0; i < LIM_PROT_STA_CACHE_SIZE; i++) { + if (!session_entry->protStaCache[i].active) + continue; + + if (!qdf_mem_cmp(session_entry->protStaCache[i].addr, + sta_ds->staAddr, sizeof(tSirMacAddr))) { + session_entry->gLimHt20Params.numSta--; + session_entry->protStaCache[i].active = + false; + break; + } + } + } + + if (session_entry->gLimHt20Params.numSta == 0) { + /* disable protection */ + lim_log(mac_ctx, LOG1, FL("No 11B STA exists, PESessionID %d"), + session_entry->peSessionId); + lim_enable_ht20_protection(mac_ctx, false, false, beacon_params, + session_entry); + } +} + +/** + * lim_decide_ap_protection_on_delete() - update SAP protection on station + * deletion. + * @mac_ctx: pointer to global mac structure + * @sta_ds: station node + * @beacon_params: ap beacon parameters + * @session_entry: pe session entry + * + * Decides about protection related settings when a station is getting deleted. + * + * Return: none + */ +void +lim_decide_ap_protection_on_delete(tpAniSirGlobal mac_ctx, + tpDphHashNode sta_ds, + tpUpdateBeaconParams beacon_params, + tpPESession session_entry) +{ + uint32_t phy_mode; + tHalBitVal erp_enabled = eHAL_CLEAR; + tSirRFBand rf_band = SIR_BAND_UNKNOWN; + uint32_t i; + + if (NULL == sta_ds) + return; + + lim_get_rf_band_new(mac_ctx, &rf_band, session_entry); + lim_get_phy_mode(mac_ctx, &phy_mode, session_entry); + erp_enabled = sta_ds->erpEnabled; + + if ((SIR_BAND_5_GHZ == rf_band) && + (true == session_entry->htCapability) && + (session_entry->beaconParams.llaCoexist) && + (false == sta_ds->mlmStaContext.htCapability)) { + /* + * we are HT. if we are 11A, then protection is not required or + * we are HT and 11A station is leaving. + * protection consideration required. + * HT station leaving ==> this case is commonly handled + * between both the bands below. + */ + lim_log(mac_ctx, LOG1, + FL("(%d) A 11A STA is disassociated. Addr is %pM"), + session_entry->gLim11aParams.numSta, sta_ds->staAddr); + for (i = 0; i < LIM_PROT_STA_CACHE_SIZE; i++) { + if (session_entry->protStaCache[i].active && + (!qdf_mem_cmp( + session_entry->protStaCache[i].addr, + sta_ds->staAddr, + sizeof(tSirMacAddr)))) { + session_entry->protStaCache[i].active = false; + break; + } + } + + if (session_entry->gLim11aParams.numSta == 0) { + /* disable protection */ + lim_update_11a_protection(mac_ctx, false, false, + beacon_params, session_entry); + } + } + + /* we are HT or 11G and 11B station is getting deleted */ + if ((SIR_BAND_2_4_GHZ == rf_band) && + (phy_mode == WNI_CFG_PHY_MODE_11G || + session_entry->htCapability) && + (erp_enabled == eHAL_CLEAR)) { + lim_log(mac_ctx, LOG1, + FL("(%d) A legacy STA is disassociated. Addr is %pM"), + session_entry->gLim11bParams.numSta, sta_ds->staAddr); + for (i = 0; i < LIM_PROT_STA_CACHE_SIZE; i++) { + if (session_entry->protStaCache[i].active && + (!qdf_mem_cmp( + session_entry->protStaCache[i].addr, + sta_ds->staAddr, + sizeof(tSirMacAddr)))) { + session_entry->gLim11bParams.numSta--; + session_entry->protStaCache[i].active = + false; + break; + } + } + + if (session_entry->gLim11bParams.numSta == 0) { + /* disable protection */ + lim_enable11g_protection(mac_ctx, false, false, + beacon_params, session_entry); + } + } + + /* + * we are HT AP and non-11B station is leaving. + * 11g station is leaving + */ + if ((SIR_BAND_2_4_GHZ == rf_band) && + session_entry->htCapability && + !sta_ds->mlmStaContext.htCapability) { + lim_log(mac_ctx, LOG1, + FL("(%d) A 11g STA is disassociated. Addr is %pM"), + session_entry->gLim11bParams.numSta, sta_ds->staAddr); + for (i = 0; i < LIM_PROT_STA_CACHE_SIZE; i++) { + if (session_entry->protStaCache[i].active && + (!qdf_mem_cmp( + session_entry->protStaCache[i].addr, + sta_ds->staAddr, + sizeof(tSirMacAddr)))) { + session_entry->gLim11gParams.numSta--; + session_entry->protStaCache[i].active = false; + break; + } + } + + if (session_entry->gLim11gParams.numSta == 0) { + /* disable protection */ + lim_enable_ht_protection_from11g(mac_ctx, false, false, + beacon_params, + session_entry); + } + } + + if (!((true == session_entry->htCapability) && + (true == sta_ds->mlmStaContext.htCapability))) + return; + + /* + * Applies to 2.4 as well as 5 GHZ. + * HT non-GF leaving + */ + if (!sta_ds->htGreenfield) { + lim_log(mac_ctx, LOG1, + FL("(%d) A non-GF STA is disassociated. Addr is %pM"), + session_entry->gLimNonGfParams.numSta, sta_ds->staAddr); + for (i = 0; i < LIM_PROT_STA_CACHE_SIZE; i++) { + if (session_entry->protStaCache[i].active && + (!qdf_mem_cmp( + session_entry->protStaCache[i].addr, + sta_ds->staAddr, + sizeof(tSirMacAddr)))) { + session_entry->protStaCache[i].active = false; + break; + } + } + + if (session_entry->gLimNonGfParams.numSta == 0) { + /* disable protection */ + lim_enable_ht_non_gf_protection(mac_ctx, false, false, + beacon_params, session_entry); + } + } + + /* + * Applies to 2.4 as well as 5 GHZ. + * HT 20Mhz station leaving + */ + if (session_entry->beaconParams.ht20Coexist && + (eHT_CHANNEL_WIDTH_20MHZ == + sta_ds->htSupportedChannelWidthSet)) { + lim_decide_ap_protection_on_ht20_delete(mac_ctx, sta_ds, + beacon_params, session_entry); + } + + /* + * Applies to 2.4 as well as 5 GHZ. + * LSIG TXOP not supporting staiton leaving + */ + if ((false == session_entry->beaconParams. + fLsigTXOPProtectionFullSupport) && + (false == sta_ds->htLsigTXOPProtection)) { + lim_log(mac_ctx, LOG1, + FL("(%d) A HT LSIG not supporting STA is disassociated. Addr is %pM"), + session_entry->gLimLsigTxopParams.numSta, + sta_ds->staAddr); + for (i = 0; i < LIM_PROT_STA_CACHE_SIZE; i++) { + if (session_entry->protStaCache[i].active && + (!qdf_mem_cmp( + session_entry->protStaCache[i].addr, + sta_ds->staAddr, + sizeof(tSirMacAddr)))) { + session_entry->protStaCache[i].active = false; + break; + } + } + + if (session_entry->gLimLsigTxopParams.numSta == 0) { + /* disable protection */ + lim_enable_ht_lsig_txop_protection(mac_ctx, true, + false, beacon_params, session_entry); + } + } +} + +/** + * lim_decide_short_preamble() - update short preamble parameters + * @mac_ctx: pointer to global mac structure + * @sta_ds: station node + * @beacon_params: ap beacon parameters + * @session_entry: pe session entry + * + * Decides about any short preamble related change because of new station + * joining. + * + * Return: None + */ +static void lim_decide_short_preamble(tpAniSirGlobal mac_ctx, + tpDphHashNode sta_ds, + tpUpdateBeaconParams beacon_params, + tpPESession session_entry) +{ + uint32_t i; + + if (sta_ds->shortPreambleEnabled == eHAL_CLEAR) { + lim_log(mac_ctx, LOG1, + FL("(%d) A non-short preamble STA is disassociated. Addr is %pM"), + session_entry->gLimNoShortParams.numNonShortPreambleSta, + sta_ds->staAddr); + for (i = 0; i < LIM_PROT_STA_CACHE_SIZE; i++) { + if (session_entry->gLimNoShortParams. + staNoShortCache[i].active && + (!qdf_mem_cmp(session_entry-> + gLimNoShortParams. + staNoShortCache[i].addr, + sta_ds->staAddr, + sizeof(tSirMacAddr)))) { + session_entry->gLimNoShortParams. + numNonShortPreambleSta--; + session_entry->gLimNoShortParams. + staNoShortCache[i].active = false; + break; + } + } + + if (session_entry->gLimNoShortParams.numNonShortPreambleSta) + return; + + /* + * enable short preamble + * reset the cache + */ + qdf_mem_set((uint8_t *) &session_entry->gLimNoShortParams, + sizeof(tLimNoShortParams), 0); + if (lim_enable_short_preamble(mac_ctx, true, + beacon_params, session_entry) != eSIR_SUCCESS) { + lim_log(mac_ctx, LOGE, + FL("Cannot enable short preamble")); + } + } +} + +/** + * lim_decide_short_slot() - update short slot time related parameters + * @mac_ctx: pointer to global mac structure + * @sta_ds: station node + * @beacon_params: ap beacon parameters + * @session_entry: pe session entry + * + * Decides about any short slot time related change because of station leaving + * the BSS. + * Return: None + */ +static void +lim_decide_short_slot(tpAniSirGlobal mac_ctx, tpDphHashNode sta_ds, + tpUpdateBeaconParams beacon_params, + tpPESession session_entry) +{ + uint32_t i, val, non_short_slot_sta_count; + + if (sta_ds->shortSlotTimeEnabled != eHAL_CLEAR) + return; + + lim_log(mac_ctx, LOG1, + FL("(%d) A non-short slottime STA is disassociated. Addr is %pM"), + mac_ctx->lim.gLimNoShortSlotParams.numNonShortSlotSta, + sta_ds->staAddr); + + wlan_cfg_get_int(mac_ctx, WNI_CFG_11G_SHORT_SLOT_TIME_ENABLED, + &val); + + if (LIM_IS_AP_ROLE(session_entry)) { + non_short_slot_sta_count = + session_entry->gLimNoShortSlotParams.numNonShortSlotSta; + for (i = 0; i < LIM_PROT_STA_CACHE_SIZE; i++) { + if (session_entry->gLimNoShortSlotParams. + staNoShortSlotCache[i].active && + (!qdf_mem_cmp(session_entry-> + gLimNoShortSlotParams. + staNoShortSlotCache[i].addr, + sta_ds->staAddr, + sizeof(tSirMacAddr)))) { + non_short_slot_sta_count--; + session_entry->gLimNoShortSlotParams. + staNoShortSlotCache[i].active = false; + break; + } + } + + if (non_short_slot_sta_count == 0 && val) { + /* + * enable short slot time + * reset the cache + */ + qdf_mem_set((uint8_t *) &session_entry-> + gLimNoShortSlotParams, + sizeof(tLimNoShortSlotParams), 0); + beacon_params->fShortSlotTime = true; + beacon_params->paramChangeBitmap |= + PARAM_SHORT_SLOT_TIME_CHANGED; + session_entry->shortSlotTimeSupported = true; + } + session_entry->gLimNoShortSlotParams.numNonShortSlotSta = + non_short_slot_sta_count; + } else { + non_short_slot_sta_count = + mac_ctx->lim.gLimNoShortSlotParams.numNonShortSlotSta; + for (i = 0; i < LIM_PROT_STA_CACHE_SIZE; i++) { + if (mac_ctx->lim.gLimNoShortSlotParams. + staNoShortSlotCache[i].active && + (!qdf_mem_cmp( + mac_ctx->lim.gLimNoShortSlotParams. + staNoShortSlotCache[i].addr, + sta_ds->staAddr, + sizeof(tSirMacAddr)))) { + non_short_slot_sta_count--; + mac_ctx->lim.gLimNoShortSlotParams. + staNoShortSlotCache[i].active = false; + break; + } + } + + if (val && !non_short_slot_sta_count) { + /* + * enable short slot time + * reset the cache + */ + qdf_mem_set( + (uint8_t *) &mac_ctx->lim.gLimNoShortSlotParams, + sizeof(tLimNoShortSlotParams), 0); + /*in case of AP set SHORT_SLOT_TIME to enable*/ + if (LIM_IS_AP_ROLE(session_entry)) { + beacon_params->fShortSlotTime = true; + beacon_params->paramChangeBitmap |= + PARAM_SHORT_SLOT_TIME_CHANGED; + session_entry->shortSlotTimeSupported = true; + } + } + mac_ctx->lim.gLimNoShortSlotParams.numNonShortSlotSta = + non_short_slot_sta_count; + } +} + +/** + * lim_populate_vht_mcs_set - function to populate vht mcs rate set + * @mac_ctx: pointer to global mac structure + * @rates: pointer to supported rate set + * @peer_vht_caps: pointer to peer vht capabilities + * @session_entry: pe session entry + * + * Populates vht mcs rate set based on peer and self capabilities + * + * Return: eSIR_SUCCESS on success else eSIR_FAILURE + */ +tSirRetStatus lim_populate_vht_mcs_set(tpAniSirGlobal mac_ctx, + tpSirSupportedRates rates, + tDot11fIEVHTCaps *peer_vht_caps, + tpPESession session_entry, + uint8_t nss) +{ + uint32_t val; + uint32_t self_sta_dot11mode = 0; + uint16_t mcs_map_mask = MCSMAPMASK1x1; + uint16_t mcs_map_mask2x2 = 0; + + wlan_cfg_get_int(mac_ctx, WNI_CFG_DOT11_MODE, &self_sta_dot11mode); + + if (!IS_DOT11_MODE_VHT(self_sta_dot11mode)) + return eSIR_SUCCESS; + + if (wlan_cfg_get_int(mac_ctx, WNI_CFG_VHT_RX_MCS_MAP, &val) != + eSIR_SUCCESS) { + lim_log(mac_ctx, LOGE, FL("could not retrieve VHT RX MCS MAP")); + goto error; + } + rates->vhtRxMCSMap = (uint16_t) val; + + if (wlan_cfg_get_int(mac_ctx, WNI_CFG_VHT_TX_MCS_MAP, &val) != + eSIR_SUCCESS) { + lim_log(mac_ctx, LOGE, FL("could not retrieve VHT TX MCS MAP")); + goto error; + } + rates->vhtTxMCSMap = (uint16_t) val; + + if (wlan_cfg_get_int(mac_ctx, + WNI_CFG_VHT_RX_HIGHEST_SUPPORTED_DATA_RATE, + &val) != eSIR_SUCCESS) { + lim_log(mac_ctx, LOGE, + FL("couldn't retrieve VHT RX Supported data rate MAP")); + goto error; + } + rates->vhtRxHighestDataRate = (uint16_t) val; + + if (wlan_cfg_get_int(mac_ctx, + WNI_CFG_VHT_TX_HIGHEST_SUPPORTED_DATA_RATE, + &val) != eSIR_SUCCESS) { + lim_log(mac_ctx, LOGE, + FL("couldn't retrieve VHT RX Supported data rate MAP")); + goto error; + } + rates->vhtTxHighestDataRate = (uint16_t) val; + + if (NSS_1x1_MODE == nss) { + rates->vhtRxMCSMap |= VHT_MCS_1x1; + rates->vhtTxMCSMap |= VHT_MCS_1x1; + rates->vhtTxHighestDataRate = + VHT_TX_HIGHEST_SUPPORTED_DATA_RATE_1_1; + rates->vhtRxHighestDataRate = + VHT_RX_HIGHEST_SUPPORTED_DATA_RATE_1_1; + } + + if ((peer_vht_caps == NULL) || (!peer_vht_caps->present)) + return eSIR_SUCCESS; + + rates->vhtTxHighestDataRate = + QDF_MIN(rates->vhtTxHighestDataRate, + peer_vht_caps->txSupDataRate); + rates->vhtRxHighestDataRate = + QDF_MIN(rates->vhtRxHighestDataRate, + peer_vht_caps->rxHighSupDataRate); + + if (session_entry && session_entry->nss == NSS_2x2_MODE) { + if (mac_ctx->lteCoexAntShare && + IS_24G_CH(session_entry->currentOperChannel)) { + if (IS_2X2_CHAIN(session_entry->chainMask)) + mcs_map_mask2x2 = MCSMAPMASK2x2; + else + lim_log(mac_ctx, LOGE, FL("2x2 not enabled %d"), + session_entry->chainMask); + } else { + mcs_map_mask2x2 = MCSMAPMASK2x2; + } + } + + if ((peer_vht_caps->txMCSMap & mcs_map_mask) < + (rates->vhtRxMCSMap & mcs_map_mask)) { + rates->vhtRxMCSMap &= ~(mcs_map_mask); + rates->vhtRxMCSMap |= + (peer_vht_caps->txMCSMap & mcs_map_mask); + } + if ((peer_vht_caps->rxMCSMap & mcs_map_mask) < + (rates->vhtTxMCSMap & mcs_map_mask)) { + rates->vhtTxMCSMap &= ~(mcs_map_mask); + rates->vhtTxMCSMap |= + (peer_vht_caps->rxMCSMap & mcs_map_mask); + } + + if (mcs_map_mask2x2) { + + uint16_t peer_mcs_map, self_mcs_map; + + peer_mcs_map = + peer_vht_caps->txMCSMap & mcs_map_mask2x2; + self_mcs_map = + rates->vhtRxMCSMap & mcs_map_mask2x2; + + if ((self_mcs_map != mcs_map_mask2x2) && + ((peer_mcs_map == mcs_map_mask2x2) || + (peer_mcs_map < self_mcs_map))) { + rates->vhtRxMCSMap &= ~mcs_map_mask2x2; + rates->vhtRxMCSMap |= peer_mcs_map; + } + + peer_mcs_map = + (peer_vht_caps->rxMCSMap & mcs_map_mask2x2); + self_mcs_map = + (rates->vhtTxMCSMap & mcs_map_mask2x2); + + if ((self_mcs_map != mcs_map_mask2x2) && + ((peer_mcs_map == mcs_map_mask2x2) || + (peer_mcs_map < self_mcs_map))) { + rates->vhtTxMCSMap &= ~mcs_map_mask2x2; + rates->vhtTxMCSMap |= peer_mcs_map; + } + } + + lim_log(mac_ctx, LOG1, + FL("enable2x2 - %d nss %d vhtRxMCSMap - %x vhtTxMCSMap - %x"), + mac_ctx->roam.configParam.enable2x2, nss, + rates->vhtRxMCSMap, rates->vhtTxMCSMap); + + if (NULL != session_entry) { + session_entry->supported_nss_1x1 = + ((rates->vhtTxMCSMap & VHT_MCS_1x1) == + VHT_MCS_1x1) ? true : false; + lim_log(mac_ctx, LOG1, + FL("VHT supported nss 1x1: %d"), + session_entry->supported_nss_1x1); + } + + return eSIR_SUCCESS; +error: + + return eSIR_FAILURE; +} + +/** + * lim_populate_own_rate_set() - comprises the basic and extended rates read + * from CFG + * @mac_ctx: pointer to global mac structure + * @rates: pointer to supported rates + * @supported_mcs_set: pointer to supported mcs rates + * @basic_only: update only basic rates if set true + * @session_entry: pe session entry + * @vht_caps: pointer to vht capability + * + * This function is called by limProcessAssocRsp() or + * lim_add_staInIBSS() + * - It creates a combined rate set of 12 rates max which + * comprises the basic and extended rates read from CFG + * - It sorts the combined rate Set and copy it in the + * rate array of the pSTA descriptor + * - It sets the erpEnabled bit of the STA descriptor + * ERP bit is set iff the dph PHY mode is 11G and there is at least + * an A rate in the supported or extended rate sets + * + * Return: eSIR_SUCCESS or eSIR_FAILURE. + */ +tSirRetStatus +lim_populate_own_rate_set(tpAniSirGlobal mac_ctx, + tpSirSupportedRates rates, uint8_t *supported_mcs_set, + uint8_t basic_only, tpPESession session_entry, + tDot11fIEVHTCaps *vht_caps) +{ + tSirMacRateSet temp_rate_set; + tSirMacRateSet temp_rate_set2; + uint32_t i, j, val, min, is_arate; + uint32_t phy_mode = 0; + uint32_t self_sta_dot11mode = 0; + uint8_t a_rate_index = 0; + uint8_t b_rate_index = 0; + + is_arate = 0; + + wlan_cfg_get_int(mac_ctx, WNI_CFG_DOT11_MODE, &self_sta_dot11mode); + lim_get_phy_mode(mac_ctx, &phy_mode, session_entry); + + /* + * Include 11b rates only when the device configured in + * auto, 11a/b/g or 11b_only + */ + if ((self_sta_dot11mode == WNI_CFG_DOT11_MODE_ALL) || + (self_sta_dot11mode == WNI_CFG_DOT11_MODE_11A) || + (self_sta_dot11mode == WNI_CFG_DOT11_MODE_11AC) || + (self_sta_dot11mode == WNI_CFG_DOT11_MODE_11N) || + (self_sta_dot11mode == WNI_CFG_DOT11_MODE_11G) || + (self_sta_dot11mode == WNI_CFG_DOT11_MODE_11B)) { + val = WNI_CFG_SUPPORTED_RATES_11B_LEN; + wlan_cfg_get_str(mac_ctx, WNI_CFG_SUPPORTED_RATES_11B, + (uint8_t *) &temp_rate_set.rate, &val); + temp_rate_set.numRates = (uint8_t) val; + } else { + temp_rate_set.numRates = 0; + } + + /* Include 11a rates when the device configured in non-11b mode */ + if (!IS_DOT11_MODE_11B(self_sta_dot11mode)) { + val = WNI_CFG_SUPPORTED_RATES_11A_LEN; + wlan_cfg_get_str(mac_ctx, WNI_CFG_SUPPORTED_RATES_11A, + (uint8_t *) &temp_rate_set2.rate, &val); + temp_rate_set2.numRates = (uint8_t) val; + } else { + temp_rate_set2.numRates = 0; + } + + if ((temp_rate_set.numRates + temp_rate_set2.numRates) > 12) { + /* we are in big trouble */ + lim_log(mac_ctx, LOGP, FL("more than 12 rates in CFG")); + /* panic */ + return eSIR_FAILURE; + } + /* copy all rates in temp_rate_set, there are 12 rates max */ + for (i = 0; i < temp_rate_set2.numRates; i++) + temp_rate_set.rate[i + temp_rate_set.numRates] = + temp_rate_set2.rate[i]; + + temp_rate_set.numRates += temp_rate_set2.numRates; + + /** + * Sort rates in temp_rate_set (they are likely to be already sorted) + * put the result in pSupportedRates + */ + + qdf_mem_set((uint8_t *) rates, sizeof(tSirSupportedRates), 0); + for (i = 0; i < temp_rate_set.numRates; i++) { + min = 0; + val = 0xff; + is_arate = 0; + + for (j = 0; (j < temp_rate_set.numRates) && + (j < SIR_MAC_RATESET_EID_MAX); j++) { + if ((uint32_t) (temp_rate_set.rate[j] & 0x7f) < + val) { + val = temp_rate_set.rate[j] & 0x7f; + min = j; + } + } + + if (sirIsArate(temp_rate_set.rate[min] & 0x7f)) + is_arate = 1; + + /* + * HAL needs to know whether the rate is basic rate or + * not, as it needs to update the response rate table + * accordingly. e.g. if one of the 11a rates is + * basic rate, then that rate can be used for sending + * control frames. + * HAL updates the response rate table whenever basic + * rate set is changed. + */ + if (basic_only && temp_rate_set.rate[min] & 0x80) { + if (is_arate) + rates->llaRates[a_rate_index++] = + temp_rate_set.rate[min]; + else + rates->llbRates[b_rate_index++] = + temp_rate_set.rate[min]; + } else { + if (is_arate) + rates->llaRates[a_rate_index++] = + temp_rate_set.rate[min]; + else + rates->llbRates[b_rate_index++] = + temp_rate_set.rate[min]; + } + temp_rate_set.rate[min] = 0xff; + } + + if (IS_DOT11_MODE_HT(self_sta_dot11mode)) { + val = SIZE_OF_SUPPORTED_MCS_SET; + if (wlan_cfg_get_str(mac_ctx, WNI_CFG_SUPPORTED_MCS_SET, + rates->supportedMCSSet, + &val) != eSIR_SUCCESS) { + /* Could not get rateset from CFG. Log error. */ + lim_log(mac_ctx, LOGE, + FL("could not retrieve supportedMCSSet")); + return eSIR_FAILURE; + } + + if (session_entry->nss == NSS_1x1_MODE) + rates->supportedMCSSet[1] = 0; + /* + * if supported MCS Set of the peer is passed in, + * then do the intersection + * else use the MCS set from local CFG. + */ + + if (supported_mcs_set != NULL) { + for (i = 0; i < SIR_MAC_MAX_SUPPORTED_MCS_SET; i++) + rates->supportedMCSSet[i] &= + supported_mcs_set[i]; + } + + lim_log(mac_ctx, LOG2, FL("MCS Rate Set Bitmap: ")); + for (i = 0; i < SIR_MAC_MAX_SUPPORTED_MCS_SET; i++) + lim_log(mac_ctx, LOG2, FL("%x "), + rates->supportedMCSSet[i]); + } + lim_populate_vht_mcs_set(mac_ctx, rates, vht_caps, + session_entry, session_entry->nss); + + return eSIR_SUCCESS; +} + +tSirRetStatus +lim_populate_peer_rate_set(tpAniSirGlobal pMac, + tpSirSupportedRates pRates, + uint8_t *pSupportedMCSSet, + uint8_t basicOnly, + tpPESession psessionEntry, tDot11fIEVHTCaps *pVHTCaps) +{ + tSirMacRateSet tempRateSet; + tSirMacRateSet tempRateSet2; + uint32_t i, j, val, min, isArate; + isArate = 0; + + /* copy operational rate set from psessionEntry */ + if (psessionEntry->rateSet.numRates <= SIR_MAC_RATESET_EID_MAX) { + qdf_mem_copy((uint8_t *) tempRateSet.rate, + (uint8_t *) (psessionEntry->rateSet.rate), + psessionEntry->rateSet.numRates); + tempRateSet.numRates = psessionEntry->rateSet.numRates; + } else { + lim_log(pMac, LOGE, + FL("more than SIR_MAC_RATESET_EID_MAX rates\n")); + return eSIR_FAILURE; + } + if ((psessionEntry->dot11mode == WNI_CFG_DOT11_MODE_11G) || + (psessionEntry->dot11mode == WNI_CFG_DOT11_MODE_11A) || + (psessionEntry->dot11mode == WNI_CFG_DOT11_MODE_11AC) || + (psessionEntry->dot11mode == WNI_CFG_DOT11_MODE_11N)) { + if (psessionEntry->extRateSet.numRates <= + SIR_MAC_RATESET_EID_MAX) { + qdf_mem_copy((uint8_t *) tempRateSet2.rate, + (uint8_t *) (psessionEntry->extRateSet. + rate), + psessionEntry->extRateSet.numRates); + tempRateSet2.numRates = + psessionEntry->extRateSet.numRates; + } else { + lim_log(pMac, LOGE, + FL + ("psessionEntry->extRateSet.numRates more than SIR_MAC_RATESET_EID_MAX rates\n")); + return eSIR_FAILURE; + } + } else + tempRateSet2.numRates = 0; + if ((tempRateSet.numRates + tempRateSet2.numRates) > + SIR_MAC_RATESET_EID_MAX) { + /* we are in big trouble */ + lim_log(pMac, LOGP, FL("more than 12 rates in CFG")); + return eSIR_FAILURE; + } + + /* copy all rates in tempRateSet, there are 12 rates max */ + for (i = 0; i < tempRateSet2.numRates; i++) + tempRateSet.rate[i + tempRateSet.numRates] = + tempRateSet2.rate[i]; + tempRateSet.numRates += tempRateSet2.numRates; + /** + * Sort rates in tempRateSet (they are likely to be already sorted) + * put the result in pSupportedRates + */ + { + uint8_t aRateIndex = 0; + uint8_t bRateIndex = 0; + qdf_mem_set((uint8_t *) pRates, sizeof(tSirSupportedRates), 0); + for (i = 0; i < tempRateSet.numRates; i++) { + min = 0; + val = 0xff; + isArate = 0; + for (j = 0; + (j < tempRateSet.numRates) + && (j < SIR_MAC_RATESET_EID_MAX); j++) { + if ((uint32_t) (tempRateSet.rate[j] & 0x7f) < + val) { + val = tempRateSet.rate[j] & 0x7f; + min = j; + } + } + if (sirIsArate(tempRateSet.rate[min] & 0x7f)) + isArate = 1; + /* + * HAL needs to know whether the rate is basic rate or not, as it needs to + * update the response rate table accordingly. e.g. if one of the 11a rates is + * basic rate, then that rate can be used for sending control frames. + * HAL updates the response rate table whenever basic rate set is changed. + */ + if (basicOnly) { + if (tempRateSet.rate[min] & 0x80) { + if (isArate) + pRates->llaRates[aRateIndex++] = + tempRateSet.rate[min]; + else + pRates->llbRates[bRateIndex++] = + tempRateSet.rate[min]; + } + } else { + if (isArate) + pRates->llaRates[aRateIndex++] = + tempRateSet.rate[min]; + else + pRates->llbRates[bRateIndex++] = + tempRateSet.rate[min]; + } + tempRateSet.rate[min] = 0xff; + } + } + + if (IS_DOT11_MODE_HT(psessionEntry->dot11mode)) { + val = SIZE_OF_SUPPORTED_MCS_SET; + if (wlan_cfg_get_str(pMac, WNI_CFG_SUPPORTED_MCS_SET, + pRates->supportedMCSSet, + &val) != eSIR_SUCCESS) { + /* / Could not get rateset from CFG. Log error. */ + PELOGE(lim_log + (pMac, LOGE, + FL("could not retrieve supportedMCSSet")); + ) + return eSIR_FAILURE; + } + if (psessionEntry->nss == NSS_1x1_MODE) + pRates->supportedMCSSet[1] = 0; + + /* if supported MCS Set of the peer is passed in, then do the + * intersection, else use the MCS set from local CFG. + */ + if (pSupportedMCSSet != NULL) { + for (i = 0; i < SIR_MAC_MAX_SUPPORTED_MCS_SET; i++) + pRates->supportedMCSSet[i] &= + pSupportedMCSSet[i]; + } + lim_log(pMac, LOG2, FL("MCS Rate Set Bitmap: ")); + for (i = 0; i < SIR_MAC_MAX_SUPPORTED_MCS_SET; i++) + lim_log(pMac, LOG2, FL("%x "), + pRates->supportedMCSSet[i]); + + if (pRates->supportedMCSSet[0] == 0) { + pe_debug("Incorrect MCS 0 - 7. They must be supported"); + pRates->supportedMCSSet[0] = 0xFF; + } + + psessionEntry->supported_nss_1x1 = + ((pRates->supportedMCSSet[1] != 0) ? false : true); + lim_log(pMac, LOG1, FL("HT supported nss 1x1: %d"), + psessionEntry->supported_nss_1x1); + } + lim_populate_vht_mcs_set(pMac, pRates, pVHTCaps, + psessionEntry, psessionEntry->nss); + + if (IS_DOT11_MODE_VHT(psessionEntry->dot11mode)) { + if ((pRates->vhtRxMCSMap & MCSMAPMASK2x2) == MCSMAPMASK2x2) + psessionEntry->nss = NSS_1x1_MODE; + } else if (pRates->supportedMCSSet[1] == 0) { + psessionEntry->nss = NSS_1x1_MODE; + } + + return eSIR_SUCCESS; +} /*** lim_populate_peer_rate_set() ***/ + +/** + * lim_populate_matching_rate_set() -process the CFG rate sets and + * the rate sets received in the Assoc request on AP. + * @mac_ctx: pointer to global mac structure + * @sta_ds: station node + * @oper_rate_set: pointer to operating rate set + * @ext_rate_set: pointer to extended rate set + * @supported_mcs_set: pointer to supported rate set + * @session_entry: pointer to pe session entry + * @vht_caps: pointer to vht capabilities + * + * This is called at the time of Association Request + * processing on AP and while adding peer's context + * in IBSS role to process the CFG rate sets and + * the rate sets received in the Assoc request on AP + * or Beacon/Probe Response from peer in IBSS. + * + * 1. It makes the intersection between our own rate Sat + * and extemcded rate set and the ones received in the + * association request. + * 2. It creates a combined rate set of 12 rates max which + * comprised the basic and extended rates + * 3. It sorts the combined rate Set and copy it in the + * rate array of the pSTA descriptor + * + * The parser has already ensured unicity of the rates in the + * association request structure + * + * Return: eSIR_SUCCESS on success else eSIR_FAILURE + */ +tSirRetStatus lim_populate_matching_rate_set(tpAniSirGlobal mac_ctx, + tpDphHashNode sta_ds, + tSirMacRateSet *oper_rate_set, + tSirMacRateSet *ext_rate_set, + uint8_t *supported_mcs_set, + tpPESession session_entry, + tDot11fIEVHTCaps *vht_caps) +{ + tSirMacRateSet temp_rate_set; + tSirMacRateSet temp_rate_set2; + uint32_t i, j, val, min, is_arate; + uint32_t phy_mode; + uint8_t mcs_set[SIZE_OF_SUPPORTED_MCS_SET]; + tpSirSupportedRates rates; + uint8_t a_rate_index = 0; + uint8_t b_rate_index = 0; + + is_arate = 0; + + lim_get_phy_mode(mac_ctx, &phy_mode, session_entry); + + /* copy operational rate set from session_entry */ + qdf_mem_copy((temp_rate_set.rate), (session_entry->rateSet.rate), + session_entry->rateSet.numRates); + temp_rate_set.numRates = (uint8_t) session_entry->rateSet.numRates; + + if (phy_mode == WNI_CFG_PHY_MODE_11G) { + qdf_mem_copy((temp_rate_set2.rate), + (session_entry->extRateSet.rate), + session_entry->extRateSet.numRates); + temp_rate_set2.numRates = + (uint8_t) session_entry->extRateSet.numRates; + } else { + temp_rate_set2.numRates = 0; + } + + /* + * absolute sum of both num_rates should be less than 12. following + * 16-bit sum avoids false codition where 8-bit arthematic overflow + * might have caused total sum to be less than 12 + */ + if (((uint16_t)temp_rate_set.numRates + + (uint16_t)temp_rate_set2.numRates) > 12) { + lim_log(mac_ctx, LOGE, FL("more than 12 rates in CFG")); + return eSIR_FAILURE; + } + + /* + * Handling of the rate set IEs is the following: + * - keep only rates that we support and that the station supports + * - sort and the rates into the pSta->rate array + */ + + /* Copy all rates in temp_rate_set, there are 12 rates max */ + for (i = 0; i < temp_rate_set2.numRates; i++) + temp_rate_set.rate[i + temp_rate_set.numRates] = + temp_rate_set2.rate[i]; + + temp_rate_set.numRates += temp_rate_set2.numRates; + + /* + * Sort rates in temp_rate_set (they are likely to be already sorted) + * put the result in temp_rate_set2 + */ + temp_rate_set2.numRates = 0; + + for (i = 0; i < temp_rate_set.numRates; i++) { + min = 0; + val = 0xff; + + for (j = 0; j < temp_rate_set.numRates; j++) + if ((uint32_t) (temp_rate_set.rate[j] & 0x7f) < val) { + val = temp_rate_set.rate[j] & 0x7f; + min = j; + } + + temp_rate_set2.rate[temp_rate_set2.numRates++] = + temp_rate_set.rate[min]; + temp_rate_set.rate[min] = 0xff; + } + + /* + * Copy received rates in temp_rate_set, the parser has ensured + * unicity of the rates so there cannot be more than 12 + */ + for (i = 0; (i < oper_rate_set->numRates && + i < SIR_MAC_RATESET_EID_MAX); i++) + temp_rate_set.rate[i] = oper_rate_set->rate[i]; + + temp_rate_set.numRates = oper_rate_set->numRates; + + lim_log(mac_ctx, LOG2, + "Sum of SUPPORTED and EXTENDED Rate Set (%1d)", + temp_rate_set.numRates + ext_rate_set->numRates); + + if (ext_rate_set->numRates && + ((temp_rate_set.numRates + ext_rate_set->numRates) > 12) && + temp_rate_set.numRates < 12) { + int found = 0; + int tail = temp_rate_set.numRates; + + for (i = 0; (i < ext_rate_set->numRates && + i < SIR_MAC_RATESET_EID_MAX); i++) { + found = 0; + for (j = 0; j < (uint32_t) tail; j++) { + if ((temp_rate_set.rate[j] & 0x7F) == + (ext_rate_set->rate[i] & 0x7F)) { + found = 1; + break; + } + } + + if (!found) { + temp_rate_set.rate[temp_rate_set.numRates++] = + ext_rate_set->rate[i]; + if (temp_rate_set.numRates >= 12) + break; + } + } + } else if (ext_rate_set->numRates && + ((temp_rate_set.numRates + ext_rate_set->numRates) <= 12)) { + for (j = 0; ((j < ext_rate_set->numRates) && + (j < SIR_MAC_RATESET_EID_MAX) && + ((i + j) < SIR_MAC_RATESET_EID_MAX)); j++) + temp_rate_set.rate[i + j] = ext_rate_set->rate[j]; + + temp_rate_set.numRates += ext_rate_set->numRates; + } else if (ext_rate_set->numRates) { + lim_log(mac_ctx, LOG2, + "Relying only on the SUPPORTED Rate Set IE..."); + } + + + rates = &sta_ds->supportedRates; + qdf_mem_set((uint8_t *) rates, sizeof(tSirSupportedRates), 0); + for (i = 0; (i < temp_rate_set2.numRates && + i < SIR_MAC_RATESET_EID_MAX); i++) { + for (j = 0; (j < temp_rate_set.numRates && + j < SIR_MAC_RATESET_EID_MAX); j++) { + if ((temp_rate_set2.rate[i] & 0x7F) != + (temp_rate_set.rate[j] & 0x7F)) + continue; + + if (sirIsArate(temp_rate_set2.rate[i] & 0x7f) && + a_rate_index < SIR_NUM_11A_RATES) { + is_arate = 1; + rates->llaRates[a_rate_index++] = + temp_rate_set2.rate[i]; + } else if ((b_rate_index < SIR_NUM_11B_RATES) && + !(sirIsArate(temp_rate_set2.rate[i] & 0x7f))) { + rates->llbRates[b_rate_index++] = + temp_rate_set2.rate[i]; + } + break; + } + } + + /* + * Now add the Polaris rates only when Proprietary rates are enabled. + * compute the matching MCS rate set, if peer is 11n capable and self + * mode is 11n + */ +#ifdef FEATURE_WLAN_TDLS + if (sta_ds->mlmStaContext.htCapability) +#else + if (IS_DOT11_MODE_HT(session_entry->dot11mode) && + (sta_ds->mlmStaContext.htCapability)) +#endif + { + val = SIZE_OF_SUPPORTED_MCS_SET; + if (wlan_cfg_get_str(mac_ctx, WNI_CFG_SUPPORTED_MCS_SET, + mcs_set, &val) != eSIR_SUCCESS) { + /* Could not get rateset from CFG. Log error. */ + lim_log(mac_ctx, LOGP, + FL("could not retrieve supportedMCSet")); + return eSIR_FAILURE; + } + + if (session_entry->nss == NSS_1x1_MODE) + mcs_set[1] = 0; + + for (i = 0; i < val; i++) + sta_ds->supportedRates.supportedMCSSet[i] = + mcs_set[i] & supported_mcs_set[i]; + + lim_log(mac_ctx, LOG2, + FL("lim_populate_matching_rate_set: MCS Rate Set Bitmap" + " from CFG and DPH : ")); + for (i = 0; i < SIR_MAC_MAX_SUPPORTED_MCS_SET; i++) { + lim_log(mac_ctx, LOG2, FL("%x %x "), mcs_set[i], + sta_ds->supportedRates.supportedMCSSet[i]); + } + } + lim_populate_vht_mcs_set(mac_ctx, &sta_ds->supportedRates, vht_caps, + session_entry, session_entry->nss); + /* + * Set the erpEnabled bit if the phy is in G mode and at least + * one A rate is supported + */ + if ((phy_mode == WNI_CFG_PHY_MODE_11G) && is_arate) + sta_ds->erpEnabled = eHAL_SET; + + return eSIR_SUCCESS; +} + +/** + * lim_populate_vht_caps() - populates vht capabilities based on input + * capabilities + * @input_caps: input capabilities based on which we format the vht + * capabilities + * + * function to populate the supported vht capabilities. + * + * Return: vht capabilities derived based on input parameters. + */ +static uint32_t lim_populate_vht_caps(tDot11fIEVHTCaps input_caps) +{ + uint32_t vht_caps; + + vht_caps = ((input_caps.maxMPDULen << SIR_MAC_VHT_CAP_MAX_MPDU_LEN) | + (input_caps.supportedChannelWidthSet << + SIR_MAC_VHT_CAP_SUPP_CH_WIDTH_SET) | + (input_caps.ldpcCodingCap << + SIR_MAC_VHT_CAP_LDPC_CODING_CAP) | + (input_caps.shortGI80MHz << + SIR_MAC_VHT_CAP_SHORTGI_80MHZ) | + (input_caps.shortGI160and80plus80MHz << + SIR_MAC_VHT_CAP_SHORTGI_160_80_80MHZ) | + (input_caps.txSTBC << SIR_MAC_VHT_CAP_TXSTBC) | + (input_caps.rxSTBC << SIR_MAC_VHT_CAP_RXSTBC) | + (input_caps.suBeamFormerCap << + SIR_MAC_VHT_CAP_SU_BEAMFORMER_CAP) | + (input_caps.suBeamformeeCap << + SIR_MAC_VHT_CAP_SU_BEAMFORMEE_CAP) | + (input_caps.csnofBeamformerAntSup << + SIR_MAC_VHT_CAP_CSN_BEAMORMER_ANT_SUP) | + (input_caps.numSoundingDim << + SIR_MAC_VHT_CAP_NUM_SOUNDING_DIM) | + (input_caps.muBeamformerCap << + SIR_MAC_VHT_CAP_NUM_BEAM_FORMER_CAP) | + (input_caps.muBeamformeeCap << + SIR_MAC_VHT_CAP_NUM_BEAM_FORMEE_CAP) | + (input_caps.vhtTXOPPS << + SIR_MAC_VHT_CAP_TXOPPS) | + (input_caps.htcVHTCap << + SIR_MAC_VHT_CAP_HTC_CAP) | + (input_caps.maxAMPDULenExp << + SIR_MAC_VHT_CAP_MAX_AMDU_LEN_EXPO) | + (input_caps.vhtLinkAdaptCap << + SIR_MAC_VHT_CAP_LINK_ADAPT_CAP) | + (input_caps.rxAntPattern << + SIR_MAC_VHT_CAP_RX_ANTENNA_PATTERN) | + (input_caps.txAntPattern << + SIR_MAC_VHT_CAP_TX_ANTENNA_PATTERN) | + (input_caps.reserved1 << + SIR_MAC_VHT_CAP_RESERVED2)); + + return vht_caps; +} +/** + * lim_add_sta()- called to add an STA context at hardware + * @mac_ctx: pointer to global mac structure + * @sta_ds: station node + * @update_entry: set to true for updating the entry + * @session_entry: pe session entry + * + * This function is called to add an STA context at hardware + * whenever a STA is (Re) Associated. + * + * Return: eSIR_SUCCESS on success else eSirRetStatus failure codes + */ + +tSirRetStatus +lim_add_sta(tpAniSirGlobal mac_ctx, + tpDphHashNode sta_ds, uint8_t update_entry, tpPESession session_entry) +{ + tpAddStaParams add_sta_params = NULL; + tSirMsgQ msg_q; + tSirRetStatus ret_code = eSIR_SUCCESS; + tSirMacAddr sta_mac, *sta_Addr; + tpSirAssocReq assoc_req; + uint8_t i, nw_type_11b = 0; + tLimIbssPeerNode *peer_node; /* for IBSS mode */ + uint8_t *p2p_ie = NULL; + + sir_copy_mac_addr(sta_mac, session_entry->selfMacAddr); + + lim_log(mac_ctx, LOG1, + FL("sessionid: %d update_entry = %d limsystemrole = %d "), + session_entry->smeSessionId, update_entry, + GET_LIM_SYSTEM_ROLE(session_entry)); + + add_sta_params = qdf_mem_malloc(sizeof(tAddStaParams)); + if (NULL == add_sta_params) { + lim_log(mac_ctx, LOGP, + FL("Unable to allocate memory during ADD_STA")); + return eSIR_MEM_ALLOC_FAILED; + } + + if (LIM_IS_AP_ROLE(session_entry) || LIM_IS_IBSS_ROLE(session_entry) || + LIM_IS_NDI_ROLE(session_entry)) + sta_Addr = &sta_ds->staAddr; +#ifdef FEATURE_WLAN_TDLS + /* SystemRole shouldn't be matter if staType is TDLS peer */ + else if (STA_ENTRY_TDLS_PEER == sta_ds->staType) + sta_Addr = &sta_ds->staAddr; +#endif + else + sta_Addr = &sta_mac; + + lim_log(mac_ctx, LOG1, + FL(MAC_ADDRESS_STR ": Subtype(Assoc/Reassoc): %d"), + MAC_ADDR_ARRAY(*sta_Addr), sta_ds->mlmStaContext.subType); + + qdf_mem_copy((uint8_t *) add_sta_params->staMac, + (uint8_t *) *sta_Addr, sizeof(tSirMacAddr)); + qdf_mem_copy((uint8_t *) add_sta_params->bssId, + session_entry->bssId, sizeof(tSirMacAddr)); + qdf_mem_copy(&add_sta_params->capab_info, + &sta_ds->mlmStaContext.capabilityInfo, + sizeof(add_sta_params->capab_info)); + + /* Copy legacy rates */ + qdf_mem_copy((uint8_t *) &add_sta_params->supportedRates, + (uint8_t *) &sta_ds->supportedRates, + sizeof(tSirSupportedRates)); + + add_sta_params->assocId = sta_ds->assocId; + + add_sta_params->wmmEnabled = sta_ds->qosMode; + add_sta_params->listenInterval = sta_ds->mlmStaContext.listenInterval; + add_sta_params->shortPreambleSupported = sta_ds->shortPreambleEnabled; + if (LIM_IS_AP_ROLE(session_entry) && + (sta_ds->mlmStaContext.subType == LIM_REASSOC)) { + /* + * TBD - need to remove this REASSOC check + * after fixinf rmmod issue + */ + add_sta_params->updateSta = sta_ds->mlmStaContext.updateContext; + } + sta_ds->valid = 0; + sta_ds->mlmStaContext.mlmState = eLIM_MLM_WT_ADD_STA_RSP_STATE; + + lim_log(mac_ctx, LOG2, + FL(" Assoc ID: %d wmmEnabled = %d listenInterval = %d" + " shortPreambleSupported: %d "), add_sta_params->assocId, + add_sta_params->wmmEnabled, add_sta_params->listenInterval, + add_sta_params->shortPreambleSupported); + /* This will indicate HAL to "allocate" a new STA index */ +#ifdef FEATURE_WLAN_TDLS + /* + * As there is corner case in-between add_sta and change_sta,if del_sta + * for other staIdx happened, firmware return wrong staIdx + * (recently removed staIdx). Until we get a confirmation from the + * firmware team it is now return correct staIdx for same sta_mac_addr + * for update case, we want to get around it by passing valid staIdx + * given by add_sta time. + */ + if ((STA_ENTRY_TDLS_PEER == sta_ds->staType) && (true == update_entry)) + add_sta_params->staIdx = sta_ds->staIndex; + else +#endif + add_sta_params->staIdx = STA_INVALID_IDX; + add_sta_params->staType = sta_ds->staType; + + add_sta_params->updateSta = update_entry; + + add_sta_params->status = QDF_STATUS_SUCCESS; + add_sta_params->respReqd = 1; + /* Update HT Capability */ + + if (LIM_IS_AP_ROLE(session_entry) || + LIM_IS_IBSS_ROLE(session_entry)) { + add_sta_params->htCapable = sta_ds->mlmStaContext.htCapability; + add_sta_params->vhtCapable = + sta_ds->mlmStaContext.vhtCapability; + } + /* + * 2G-AS platform: SAP associates with HT (11n)clients as 2x1 in 2G and + * 2X2 in 5G + * Non-2G-AS platform: SAP associates with HT (11n) clients as 2X2 in 2G + * and 5G; and disable async dbs scan when HT client connects + * 5G-AS: Don't care + */ + if (LIM_IS_AP_ROLE(session_entry) && + (STA_ENTRY_PEER == sta_ds->staType) && + !add_sta_params->vhtCapable && + (session_entry->nss == 2)) { + session_entry->ht_client_cnt++; + if ((session_entry->ht_client_cnt == 1) && + !(mac_ctx->lteCoexAntShare && + IS_24G_CH(session_entry->currentOperChannel))) { + pe_debug("setting SMPS intolrent vdev_param"); + wma_cli_set_command(session_entry->smeSessionId, + (int)WMI_VDEV_PARAM_SMPS_INTOLERANT, + 1, VDEV_CMD); + } + } + +#ifdef FEATURE_WLAN_TDLS + /* SystemRole shouldn't be matter if staType is TDLS peer */ + else if (STA_ENTRY_TDLS_PEER == sta_ds->staType) { + add_sta_params->htCapable = sta_ds->mlmStaContext.htCapability; + add_sta_params->vhtCapable = + sta_ds->mlmStaContext.vhtCapability; + } +#endif + else { + add_sta_params->htCapable = session_entry->htCapability; + add_sta_params->vhtCapable = session_entry->vhtCapability; + + } + lim_log(mac_ctx, LOG2, FL("vhtCapable: %d "), + add_sta_params->vhtCapable); + lim_log(mac_ctx, LOG2, FL(" StaIdx: %d updateSta = %d htcapable = %d "), + add_sta_params->staIdx, add_sta_params->updateSta, + add_sta_params->htCapable); + + add_sta_params->greenFieldCapable = sta_ds->htGreenfield; + add_sta_params->maxAmpduDensity = sta_ds->htAMpduDensity; + add_sta_params->maxAmpduSize = sta_ds->htMaxRxAMpduFactor; + add_sta_params->fDsssCckMode40Mhz = sta_ds->htDsssCckRate40MHzSupport; + add_sta_params->fShortGI20Mhz = sta_ds->htShortGI20Mhz; + add_sta_params->fShortGI40Mhz = sta_ds->htShortGI40Mhz; + add_sta_params->lsigTxopProtection = sta_ds->htLsigTXOPProtection; + add_sta_params->maxAmsduSize = sta_ds->htMaxAmsduLength; + add_sta_params->ch_width = sta_ds->htSupportedChannelWidthSet; + add_sta_params->mimoPS = sta_ds->htMIMOPSState; + + lim_log(mac_ctx, LOG2, + FL("greenFieldCapable: %d maxAmpduDensity = %d maxAmpduDensity = %d"), + add_sta_params->greenFieldCapable, + add_sta_params->maxAmpduDensity, add_sta_params->maxAmpduSize); + + lim_log(mac_ctx, LOG2, + FL("fDsssCckMode40Mhz: %d fShortGI20Mhz: %d fShortGI40Mhz: %d"), + add_sta_params->fDsssCckMode40Mhz, + add_sta_params->fShortGI20Mhz, add_sta_params->fShortGI40Mhz); + + lim_log(mac_ctx, LOG2, + FL("lsigTxopProtection: %d maxAmsduSize: %d txChannelWidth: %d mimoPS: %d "), + add_sta_params->lsigTxopProtection, + add_sta_params->maxAmsduSize, add_sta_params->ch_width, + add_sta_params->mimoPS); + + if (add_sta_params->vhtCapable) { + if (sta_ds->vhtSupportedChannelWidthSet) + add_sta_params->ch_width = + sta_ds->vhtSupportedChannelWidthSet + 1; + + add_sta_params->vhtSupportedRxNss = sta_ds->vhtSupportedRxNss; + if (LIM_IS_AP_ROLE(session_entry) || + LIM_IS_P2P_DEVICE_GO(session_entry)) + add_sta_params->vhtSupportedRxNss = QDF_MIN( + add_sta_params->vhtSupportedRxNss, + session_entry->nss); + add_sta_params->vhtTxBFCapable = +#ifdef FEATURE_WLAN_TDLS + ((STA_ENTRY_PEER == sta_ds->staType) + || (STA_ENTRY_TDLS_PEER == sta_ds->staType)) ? + sta_ds->vhtBeamFormerCapable : + session_entry->vht_config.su_beam_formee; +#else + (STA_ENTRY_PEER == sta_ds->staType) ? + sta_ds->vhtBeamFormerCapable : + session_entry->vht_config.su_beam_formee; +#endif + add_sta_params->enable_su_tx_bformer = + sta_ds->vht_su_bfee_capable; + } + + lim_log(mac_ctx, LOGE, FL("TxChWidth %d vhtTxBFCap %d, su_bfer %d"), + add_sta_params->ch_width, add_sta_params->vhtTxBFCapable, + add_sta_params->enable_su_tx_bformer); +#ifdef FEATURE_WLAN_TDLS + if ((STA_ENTRY_PEER == sta_ds->staType) || + (STA_ENTRY_TDLS_PEER == sta_ds->staType)) +#else + if (STA_ENTRY_PEER == sta_ds->staType) +#endif + { + /* + * peer STA get the LDPC capability from sta_ds, + * which populated from + * HT/VHT capability + */ + if (add_sta_params->vhtTxBFCapable + && mac_ctx->lim.disableLDPCWithTxbfAP) { + add_sta_params->htLdpcCapable = 0; + add_sta_params->vhtLdpcCapable = 0; + } else { + if (session_entry->txLdpcIniFeatureEnabled & 0x1) + add_sta_params->htLdpcCapable = + sta_ds->htLdpcCapable; + else + add_sta_params->htLdpcCapable = 0; + + if (session_entry->txLdpcIniFeatureEnabled & 0x2) + add_sta_params->vhtLdpcCapable = + sta_ds->vhtLdpcCapable; + else + add_sta_params->vhtLdpcCapable = 0; + } + } else if (STA_ENTRY_SELF == sta_ds->staType) { + /* For Self STA get the LDPC capability from config.ini */ + add_sta_params->htLdpcCapable = + (session_entry->txLdpcIniFeatureEnabled & 0x01); + add_sta_params->vhtLdpcCapable = + ((session_entry->txLdpcIniFeatureEnabled >> 1) & 0x01); + } + + /* Update PE session ID */ + add_sta_params->sessionId = session_entry->peSessionId; + + /* Update SME session ID */ + add_sta_params->smesessionId = session_entry->smeSessionId; + + add_sta_params->maxTxPower = session_entry->maxTxPower; + + if (session_entry->parsedAssocReq != NULL) { + uint16_t aid = sta_ds->assocId; + /* Get a copy of the already parsed Assoc Request */ + assoc_req = + (tpSirAssocReq) session_entry->parsedAssocReq[aid]; + if (assoc_req && assoc_req->addIEPresent + && assoc_req->addIE.length) { + p2p_ie = limGetP2pIEPtr(mac_ctx, + assoc_req->addIE.addIEdata, + assoc_req->addIE.length); + } + + add_sta_params->p2pCapableSta = (p2p_ie != NULL); + if (assoc_req && add_sta_params->htCapable) { + qdf_mem_copy(&add_sta_params->ht_caps, + ((uint8_t *) &assoc_req->HTCaps) + 1, + sizeof(add_sta_params->ht_caps)); + } + + if (assoc_req && add_sta_params->vhtCapable) + add_sta_params->vht_caps = + lim_populate_vht_caps(assoc_req->VHTCaps); + } else if (LIM_IS_IBSS_ROLE(session_entry)) { + + /* + * in IBSS mode, use peer node as the source of ht_caps + * and vht_caps + */ + peer_node = lim_ibss_peer_find(mac_ctx, *sta_Addr); + if (!peer_node) { + lim_log(mac_ctx, LOGP, + FL("Can't find IBSS peer node for ADD_STA")); + return eSIR_HAL_STA_DOES_NOT_EXIST; + } + + if (peer_node->atimIePresent) { + add_sta_params->atimIePresent = + peer_node->atimIePresent; + add_sta_params->peerAtimWindowLength = + peer_node->peerAtimWindowLength; + } + + add_sta_params->ht_caps = + (peer_node->htSupportedChannelWidthSet << + SIR_MAC_HT_CAP_CHWIDTH40_S) | + (peer_node->htGreenfield << + SIR_MAC_HT_CAP_GREENFIELD_S) | + (peer_node->htShortGI20Mhz << + SIR_MAC_HT_CAP_SHORTGI20MHZ_S) | + (peer_node->htShortGI40Mhz << + SIR_MAC_HT_CAP_SHORTGI40MHZ_S) | + (SIR_MAC_TXSTBC << + SIR_MAC_HT_CAP_TXSTBC_S) | + (SIR_MAC_RXSTBC << + SIR_MAC_HT_CAP_RXSTBC_S) | + (peer_node->htMaxAmsduLength << + SIR_MAC_HT_CAP_MAXAMSDUSIZE_S) | + (peer_node->htDsssCckRate40MHzSupport << + SIR_MAC_HT_CAP_DSSSCCK40_S); + + add_sta_params->vht_caps = + lim_populate_vht_caps(peer_node->VHTCaps); + } +#ifdef FEATURE_WLAN_TDLS + if (STA_ENTRY_TDLS_PEER == sta_ds->staType) { + add_sta_params->ht_caps = sta_ds->ht_caps; + add_sta_params->vht_caps = sta_ds->vht_caps; + + lim_log(mac_ctx, LOG1, + FL("Sta type is TDLS_PEER, ht_caps: 0x%x, vht_caps: 0x%x"), + add_sta_params->ht_caps, + add_sta_params->vht_caps); + } +#endif + +#ifdef FEATURE_WLAN_TDLS + if (sta_ds->wmeEnabled && + (LIM_IS_AP_ROLE(session_entry) || + (STA_ENTRY_TDLS_PEER == sta_ds->staType))) +#else + if (sta_ds->wmeEnabled && LIM_IS_AP_ROLE(session_entry)) +#endif + { + add_sta_params->uAPSD = 0; + /* + * update UAPSD and send it to LIM to add STA + * bitmap MSB <- LSB MSB 4 bits are for + * trigger enabled AC setting and LSB 4 bits + * are for delivery enabled AC setting + * 7 6 5 4 3 2 1 0 + * BE BK VI VO BE BK VI VO + */ + add_sta_params->uAPSD |= + sta_ds->qos.capability.qosInfo.acvo_uapsd; + add_sta_params->uAPSD |= + (sta_ds->qos.capability.qosInfo.acvi_uapsd << 1); + add_sta_params->uAPSD |= + (sta_ds->qos.capability.qosInfo.acbk_uapsd << 2); + add_sta_params->uAPSD |= + (sta_ds->qos.capability.qosInfo.acbe_uapsd << 3); + /* + * making delivery enabled and + * trigger enabled setting the same. + */ + add_sta_params->uAPSD |= add_sta_params->uAPSD << 4; + + add_sta_params->maxSPLen = + sta_ds->qos.capability.qosInfo.maxSpLen; + lim_log(mac_ctx, LOG1, FL("uAPSD = 0x%x, maxSpLen = %d"), + add_sta_params->uAPSD, add_sta_params->maxSPLen); + } +#ifdef WLAN_FEATURE_11W + add_sta_params->rmfEnabled = sta_ds->rmfEnabled; + lim_log(mac_ctx, LOG1, FL("PMF enabled %d"), + add_sta_params->rmfEnabled); +#endif + + lim_log(mac_ctx, LOG2, FL("htLdpcCapable: %d vhtLdpcCapable: %d " + "p2pCapableSta: %d"), + add_sta_params->htLdpcCapable, add_sta_params->vhtLdpcCapable, + add_sta_params->p2pCapableSta); + + if (!add_sta_params->htLdpcCapable) + add_sta_params->ht_caps &= ~(1 << SIR_MAC_HT_CAP_ADVCODING_S); + if (!add_sta_params->vhtLdpcCapable) + add_sta_params->vht_caps &= + ~(1 << SIR_MAC_VHT_CAP_LDPC_CODING_CAP); + + /* + * we need to defer the message until we get the + * response back from HAL. + */ + if (add_sta_params->respReqd) + SET_LIM_PROCESS_DEFD_MESGS(mac_ctx, false); + + add_sta_params->nwType = session_entry->nwType; + + if (!(add_sta_params->htCapable || add_sta_params->vhtCapable)) { + nw_type_11b = 1; + for (i = 0; i < SIR_NUM_11A_RATES; i++) { + if (sirIsArate(sta_ds->supportedRates.llaRates[i] & + 0x7F)) { + nw_type_11b = 0; + break; + } + } + if (nw_type_11b) + add_sta_params->nwType = eSIR_11B_NW_TYPE; + } + + msg_q.type = WMA_ADD_STA_REQ; + + msg_q.reserved = 0; + msg_q.bodyptr = add_sta_params; + msg_q.bodyval = 0; + + lim_log(mac_ctx, LOG1, FL("Sending WMA_ADD_STA_REQ for assocId %d"), + sta_ds->assocId); + MTRACE(mac_trace_msg_tx(mac_ctx, session_entry->peSessionId, + msg_q.type)); + + ret_code = wma_post_ctrl_msg(mac_ctx, &msg_q); + if (eSIR_SUCCESS != ret_code) { + if (add_sta_params->respReqd) + SET_LIM_PROCESS_DEFD_MESGS(mac_ctx, true); + lim_log(mac_ctx, LOGE, + FL("ADD_STA_REQ for aId %d failed (reason %X)"), + sta_ds->assocId, ret_code); + qdf_mem_free(add_sta_params); + } + + return ret_code; +} + +/** + * lim_del_sta() + * + ***FUNCTION: + * This function is called to delete an STA context at hardware + * whenever a STA is disassociated + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param pMac - Pointer to Global MAC structure + * @param pStaDs - Pointer to the STA datastructure created by + * LIM and maintained by DPH + * @param fRespReqd - flag to indicate whether the delete is synchronous (true) + * or not (false) + * @return retCode - Indicates success or failure return code + */ + +tSirRetStatus +lim_del_sta(tpAniSirGlobal pMac, + tpDphHashNode pStaDs, bool fRespReqd, tpPESession psessionEntry) +{ + tpDeleteStaParams pDelStaParams = NULL; + tSirMsgQ msgQ; + tSirRetStatus retCode = eSIR_SUCCESS; + + pDelStaParams = qdf_mem_malloc(sizeof(tDeleteStaParams)); + if (NULL == pDelStaParams) { + lim_log(pMac, LOGP, + FL("Unable to allocate memory during ADD_STA")); + return eSIR_MEM_ALLOC_FAILED; + } + + /* + * 2G-AS platform: SAP associates with HT (11n)clients as 2x1 in 2G and + * 2X2 in 5G + * Non-2G-AS platform: SAP associates with HT (11n) clients as 2X2 in 2G + * and 5G; and enable async dbs scan when all HT clients are gone + * 5G-AS: Don't care + */ + if (LIM_IS_AP_ROLE(psessionEntry) && + (pStaDs->staType == STA_ENTRY_PEER) && + !pStaDs->mlmStaContext.vhtCapability && + (psessionEntry->nss == 2)) { + psessionEntry->ht_client_cnt--; + if (psessionEntry->ht_client_cnt == 0) { + pe_debug("clearing SMPS intolrent vdev_param"); + wma_cli_set_command(psessionEntry->smeSessionId, + (int)WMI_VDEV_PARAM_SMPS_INTOLERANT, + 0, VDEV_CMD); + } + } + + /* */ + /* DPH contains the STA index only for "peer" STA entries. */ + /* LIM global contains "self" STA index */ + /* Thus, */ + /* if( STA role ) */ + /* get STA index from LIM global */ + /* else */ + /* get STA index from DPH */ + /* */ + +#ifdef FEATURE_WLAN_TDLS + if (LIM_IS_STA_ROLE(psessionEntry) && + (pStaDs->staType != STA_ENTRY_TDLS_PEER)) +#else + if (LIM_IS_STA_ROLE(psessionEntry)) +#endif + pDelStaParams->staIdx = psessionEntry->staId; + + else + pDelStaParams->staIdx = pStaDs->staIndex; + + pDelStaParams->assocId = pStaDs->assocId; + pStaDs->valid = 0; + + if (!fRespReqd) + pDelStaParams->respReqd = 0; + else { + if (pStaDs->staType != STA_ENTRY_TDLS_PEER) { + /* when lim_del_sta is called from processSmeAssocCnf + * then mlmState is already set properly. */ + if (eLIM_MLM_WT_ASSOC_DEL_STA_RSP_STATE != + GET_LIM_STA_CONTEXT_MLM_STATE(pStaDs)) { + MTRACE(mac_trace + (pMac, TRACE_CODE_MLM_STATE, + psessionEntry->peSessionId, + eLIM_MLM_WT_DEL_STA_RSP_STATE)); + SET_LIM_STA_CONTEXT_MLM_STATE(pStaDs, + eLIM_MLM_WT_DEL_STA_RSP_STATE); + } + if (LIM_IS_STA_ROLE(psessionEntry)) { + MTRACE(mac_trace + (pMac, TRACE_CODE_MLM_STATE, + psessionEntry->peSessionId, + eLIM_MLM_WT_DEL_STA_RSP_STATE)); + + psessionEntry->limMlmState = + eLIM_MLM_WT_DEL_STA_RSP_STATE; + + } + } + + /* we need to defer the message until we get the + * response back from HAL. */ + SET_LIM_PROCESS_DEFD_MESGS(pMac, false); + + pDelStaParams->respReqd = 1; + } + + /* Update PE session ID */ + pDelStaParams->sessionId = psessionEntry->peSessionId; + pDelStaParams->smesessionId = psessionEntry->smeSessionId; + + pDelStaParams->staType = pStaDs->staType; + qdf_mem_copy((uint8_t *) pDelStaParams->staMac, + (uint8_t *) pStaDs->staAddr, sizeof(tSirMacAddr)); + + pDelStaParams->status = QDF_STATUS_SUCCESS; + msgQ.type = WMA_DELETE_STA_REQ; + msgQ.reserved = 0; + msgQ.bodyptr = pDelStaParams; + msgQ.bodyval = 0; + + lim_log(pMac, LOG1, FL("Sessionid %d :Sending SIR_HAL_DELETE_STA_REQ " + "for STAID: %X and AssocID: %d MAC : " + MAC_ADDRESS_STR), pDelStaParams->sessionId, + pDelStaParams->staIdx, pDelStaParams->assocId, + MAC_ADDR_ARRAY(pStaDs->staAddr)); + + MTRACE(mac_trace_msg_tx(pMac, psessionEntry->peSessionId, msgQ.type)); + retCode = wma_post_ctrl_msg(pMac, &msgQ); + if (eSIR_SUCCESS != retCode) { + if (fRespReqd) + SET_LIM_PROCESS_DEFD_MESGS(pMac, true); + lim_log(pMac, LOGE, + FL("Posting DELETE_STA_REQ to HAL failed, reason=%X"), + retCode); + qdf_mem_free(pDelStaParams); + } + + return retCode; +} + + +/** + * lim_add_sta_self() + * + ***FUNCTION: + * This function is called to add an STA context at hardware + * whenever a STA is (Re) Associated. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param pMac - Pointer to Global MAC structure + * @param pStaDs - Pointer to the STA datastructure created by + * LIM and maintained by DPH + * @return retCode - Indicates success or failure return code + */ + +tSirRetStatus +lim_add_sta_self(tpAniSirGlobal pMac, uint16_t staIdx, uint8_t updateSta, + tpPESession psessionEntry) +{ + tpAddStaParams pAddStaParams = NULL; + tSirMsgQ msgQ; + tSirRetStatus retCode = eSIR_SUCCESS; + tSirMacAddr staMac; + uint32_t listenInterval = WNI_CFG_LISTEN_INTERVAL_STADEF; + uint32_t ampduLenExponent = 0; + /*This self Sta dot 11 mode comes from the cfg and the expectation here is + * that cfg carries the systemwide capability that device under + * consideration can support. This capability gets plumbed into the cfg + * cache at system initialization time via the .dat and .ini file override + * mechanisms and will not change. If it does change, it is the + * responsibility of SME to evict the selfSta and reissue a new AddStaSelf + * command.*/ + uint32_t selfStaDot11Mode = 0, selfTxWidth = 0; + uint32_t val; + wlan_cfg_get_int(pMac, WNI_CFG_DOT11_MODE, &selfStaDot11Mode); + lim_log(pMac, LOG1, FL("cfgDot11Mode %d"), (int)selfStaDot11Mode); + wlan_cfg_get_int(pMac, WNI_CFG_HT_CAP_INFO_SUPPORTED_CHAN_WIDTH_SET, + &selfTxWidth); + lim_log(pMac, LOG1, FL("SGI 20 %d"), (int)selfTxWidth); + lim_log(pMac, LOG1, FL("Roam Channel Bonding Mode %d"), + (int)pMac->roam.configParam.uCfgDot11Mode); + + sir_copy_mac_addr(staMac, psessionEntry->selfMacAddr); + lim_log(pMac, LOG1, FL(MAC_ADDRESS_STR ": "), MAC_ADDR_ARRAY(staMac)); + pAddStaParams = qdf_mem_malloc(sizeof(tAddStaParams)); + if (NULL == pAddStaParams) { + lim_log(pMac, LOGP, + FL("Unable to allocate memory during ADD_STA")); + return eSIR_MEM_ALLOC_FAILED; + } + + /* / Add STA context at MAC HW (BMU, RHP & TFP) */ + qdf_mem_copy((uint8_t *) pAddStaParams->staMac, + (uint8_t *) staMac, sizeof(tSirMacAddr)); + + qdf_mem_copy((uint8_t *) pAddStaParams->bssId, + psessionEntry->bssId, sizeof(tSirMacAddr)); + + pAddStaParams->assocId = psessionEntry->limAID; + pAddStaParams->staType = STA_ENTRY_SELF; + pAddStaParams->status = QDF_STATUS_SUCCESS; + pAddStaParams->respReqd = 1; + + /* Update PE session ID */ + pAddStaParams->sessionId = psessionEntry->peSessionId; + + /* Update SME session ID */ + pAddStaParams->smesessionId = psessionEntry->smeSessionId; + + pAddStaParams->maxTxPower = psessionEntry->maxTxPower; + + /* This will indicate HAL to "allocate" a new STA index */ + pAddStaParams->staIdx = staIdx; + pAddStaParams->updateSta = updateSta; + + if (wlan_cfg_get_int(pMac, WNI_CFG_SHORT_PREAMBLE, &val) != + eSIR_SUCCESS) { + lim_log(pMac, LOGE, FL( + "Couldn't get SHORT_PREAMBLE, set default")); + pAddStaParams->shortPreambleSupported = 1; + } else { + pAddStaParams->shortPreambleSupported = val; + } + + lim_populate_own_rate_set(pMac, &pAddStaParams->supportedRates, NULL, false, + psessionEntry, NULL); + if (IS_DOT11_MODE_HT(selfStaDot11Mode)) { + pAddStaParams->htCapable = true; +#ifdef DISABLE_GF_FOR_INTEROP + if ((psessionEntry->pLimJoinReq != NULL) + && (!psessionEntry->pLimJoinReq->bssDescription. + aniIndicator)) { + lim_log(pMac, LOGE, + FL + (" Turning off Greenfield, when adding self entry")); + pAddStaParams->greenFieldCapable = + WNI_CFG_GREENFIELD_CAPABILITY_DISABLE; + } else +#endif + { + pAddStaParams->greenFieldCapable = + lim_get_ht_capability(pMac, eHT_GREENFIELD, + psessionEntry); + pAddStaParams->ch_width = + pMac->roam.configParam.channelBondingMode5GHz; + pAddStaParams->mimoPS = + lim_get_ht_capability(pMac, eHT_MIMO_POWER_SAVE, + psessionEntry); + pAddStaParams->rifsMode = + lim_get_ht_capability(pMac, eHT_RIFS_MODE, + psessionEntry); + pAddStaParams->lsigTxopProtection = + lim_get_ht_capability(pMac, eHT_LSIG_TXOP_PROTECTION, + psessionEntry); + pAddStaParams->maxAmpduDensity = + lim_get_ht_capability(pMac, eHT_MPDU_DENSITY, + psessionEntry); + pAddStaParams->maxAmpduSize = + lim_get_ht_capability(pMac, eHT_MAX_RX_AMPDU_FACTOR, + psessionEntry); + pAddStaParams->maxAmsduSize = + lim_get_ht_capability(pMac, eHT_MAX_AMSDU_LENGTH, + psessionEntry); + pAddStaParams->max_amsdu_num = + lim_get_ht_capability(pMac, eHT_MAX_AMSDU_NUM, + psessionEntry); + pAddStaParams->fDsssCckMode40Mhz = + lim_get_ht_capability(pMac, eHT_DSSS_CCK_MODE_40MHZ, + psessionEntry); + pAddStaParams->fShortGI20Mhz = + psessionEntry->htConfig.ht_sgi20; + pAddStaParams->fShortGI40Mhz = + psessionEntry->htConfig.ht_sgi40; + lim_log(pMac, LOG2, + FL(" greenFieldCapable: %d maxAmpduDensity = %d " + "maxAmpduSize = %d"), + pAddStaParams->greenFieldCapable, + pAddStaParams->maxAmpduDensity, + pAddStaParams->maxAmpduSize); + + lim_log(pMac, LOG2, + FL("fDsssCckMode40Mhz: %d fShortGI20Mhz: %d " + "fShortGI40Mhz: %d lsigTxopProtection: %d"), + pAddStaParams->fDsssCckMode40Mhz, + pAddStaParams->fShortGI20Mhz, + pAddStaParams->fShortGI40Mhz, + pAddStaParams->lsigTxopProtection); + + lim_log(pMac, LOG2, + FL("maxAmsduSize: %d txChannelWidth: %d mimoPS: %d rifsMode %d"), + pAddStaParams->maxAmsduSize, + pAddStaParams->ch_width, + pAddStaParams->mimoPS, pAddStaParams->rifsMode); + } + } + pAddStaParams->vhtCapable = IS_DOT11_MODE_VHT(selfStaDot11Mode); + if (pAddStaParams->vhtCapable) { + pAddStaParams->ch_width = + psessionEntry->ch_width; + lim_log(pMac, LOG1, FL("VHT WIDTH SET %d"), + pAddStaParams->ch_width); + } + pAddStaParams->vhtTxBFCapable = + psessionEntry->vht_config.su_beam_formee; + pAddStaParams->enable_su_tx_bformer = + psessionEntry->vht_config.su_beam_former; + lim_log(pMac, LOG2, FL("vhtCapable: %d vhtTxBFCapable %d, su_bfer %d"), + pAddStaParams->vhtCapable, pAddStaParams->vhtTxBFCapable, + pAddStaParams->enable_su_tx_bformer); + + /* In 11ac mode, the hardware is capable of supporting 128K AMPDU size */ + if (IS_DOT11_MODE_VHT(selfStaDot11Mode)) { + if (wlan_cfg_get_int + (pMac, WNI_CFG_VHT_AMPDU_LEN_EXPONENT, &duLenExponent) + != eSIR_SUCCESS) { + lim_log(pMac, LOGP, + FL + ("Couldn't get WNI_CFG_VHT_AMPDU_LEN_EXPONENT")); + } + pAddStaParams->maxAmpduSize = (uint8_t) ampduLenExponent; + } + pAddStaParams->vhtTxMUBformeeCapable = + psessionEntry->vht_config.mu_beam_formee; + pAddStaParams->enableVhtpAid = psessionEntry->enableVhtpAid; + pAddStaParams->enableAmpduPs = psessionEntry->enableAmpduPs; + pAddStaParams->enableHtSmps = (psessionEntry->enableHtSmps && + (!psessionEntry->supported_nss_1x1)); + pAddStaParams->htSmpsconfig = psessionEntry->htSmpsvalue; + pAddStaParams->send_smps_action = + psessionEntry->send_smps_action; + + /* For Self STA get the LDPC capability from session i.e config.ini */ + pAddStaParams->htLdpcCapable = + (psessionEntry->txLdpcIniFeatureEnabled & 0x01); + pAddStaParams->vhtLdpcCapable = + ((psessionEntry->txLdpcIniFeatureEnabled >> 1) & 0x01); + + if (wlan_cfg_get_int(pMac, WNI_CFG_LISTEN_INTERVAL, &listenInterval) != + eSIR_SUCCESS) + lim_log(pMac, LOGP, FL("Couldn't get LISTEN_INTERVAL")); + pAddStaParams->listenInterval = (uint16_t) listenInterval; + + if (QDF_P2P_CLIENT_MODE == psessionEntry->pePersona) { + pAddStaParams->p2pCapableSta = 1; + } + + lim_log(pMac, LOG2, FL(" StaIdx: %d updateSta = %d htcapable = %d "), + pAddStaParams->staIdx, pAddStaParams->updateSta, + pAddStaParams->htCapable); + + lim_log(pMac, LOG2, FL("htLdpcCapable: %d vhtLdpcCapable: %d " + "p2pCapableSta: %d"), + pAddStaParams->htLdpcCapable, pAddStaParams->vhtLdpcCapable, + pAddStaParams->p2pCapableSta); + + if (psessionEntry->isNonRoamReassoc) { + pAddStaParams->nonRoamReassoc = 1; + psessionEntry->isNonRoamReassoc = 0; + } + lim_log(pMac, LOG2, FL("sessionid: %d Assoc ID: %d listenInterval = %d " + "shortPreambleSupported: %d"), + psessionEntry->smeSessionId, pAddStaParams->assocId, + pAddStaParams->listenInterval, + pAddStaParams->shortPreambleSupported); + + msgQ.type = WMA_ADD_STA_REQ; + msgQ.reserved = 0; + msgQ.bodyptr = pAddStaParams; + msgQ.bodyval = 0; + + lim_log(pMac, LOG1, FL(MAC_ADDRESS_STR ":Sessionid %d : " + "Sending WMA_ADD_STA_REQ. (aid %d)"), + MAC_ADDR_ARRAY(pAddStaParams->staMac), + pAddStaParams->sessionId, pAddStaParams->assocId); + MTRACE(mac_trace_msg_tx(pMac, psessionEntry->peSessionId, msgQ.type)); + + retCode = wma_post_ctrl_msg(pMac, &msgQ); + if (eSIR_SUCCESS != retCode) { + lim_log(pMac, LOGE, + FL("Posting WMA_ADD_STA_REQ to HAL failed, reason=%X"), + retCode); + qdf_mem_free(pAddStaParams); + } + return retCode; +} + +/** + * limTeardownInfraBSS() + * + ***FUNCTION: + * This function is called by various LIM functions to teardown + * an established Infrastructure BSS + * + ***LOGIC: + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param pMac - Pointer to Global MAC structure + * @return None + */ + +void lim_teardown_infra_bss(tpAniSirGlobal pMac, tpPESession psessionEntry) +{ + tSirMacAddr bcAddr = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; + + /** + * Send Broadcast Disassociate frame with + * 'leaving BSS' reason. + */ + lim_send_disassoc_mgmt_frame(pMac, + eSIR_MAC_DISASSOC_LEAVING_BSS_REASON, + bcAddr, psessionEntry, false); +} /*** end lim_teardown_infra_bss() ***/ + +/** + * lim_handle_cnf_wait_timeout() + * + ***FUNCTION: + * This function is called by limProcessMessageQueue to handle + * various confirmation failure cases. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param pMac - Pointer to Global MAC structure + * @param pStaDs - Pointer to a sta descriptor + * @return None + */ + +void lim_handle_cnf_wait_timeout(tpAniSirGlobal pMac, uint16_t staId) +{ + tpDphHashNode pStaDs; + tpPESession psessionEntry = NULL; + + psessionEntry = pe_find_session_by_session_id(pMac, + pMac->lim.limTimers.gpLimCnfWaitTimer[staId].sessionId); + if (psessionEntry == NULL) { + lim_log(pMac, LOGP, + FL("Session Does not exist for given sessionID")); + return; + } + pStaDs = dph_get_hash_entry(pMac, staId, &psessionEntry->dph.dphHashTable); + + if (pStaDs == NULL) { + PELOGW(lim_log + (pMac, LOGW, + FL("No STA context in SIR_LIM_CNF_WAIT_TIMEOUT.")); + ) + return; + } + + switch (pStaDs->mlmStaContext.mlmState) { + case eLIM_MLM_WT_ASSOC_CNF_STATE: + PELOGW(lim_log + (pMac, LOGW, + FL + ("Did not receive Assoc Cnf in eLIM_MLM_WT_ASSOC_CNF_STATE sta Assoc id %d"), + pStaDs->assocId); + ) + lim_print_mac_addr(pMac, pStaDs->staAddr, LOGW); + + if (LIM_IS_AP_ROLE(psessionEntry)) { + lim_reject_association(pMac, pStaDs->staAddr, + pStaDs->mlmStaContext.subType, + true, + pStaDs->mlmStaContext.authType, + pStaDs->assocId, true, + (tSirResultCodes) + eSIR_MAC_UNSPEC_FAILURE_STATUS, + psessionEntry); + } + break; + + default: + lim_log(pMac, LOGW, FL("Received CNF_WAIT_TIMEOUT in state %d"), + pStaDs->mlmStaContext.mlmState); + } +} + +/** + * lim_delete_dph_hash_entry()- function to delete dph hash entry + * @mac_ctx: pointer to global mac structure + * @sta_addr: peer station address + * @sta_id: id assigned to peer station + * @session_entry: pe session entry + * + * This function is called whenever we need to delete + * the dph hash entry + * + * Return: none + */ + +void +lim_delete_dph_hash_entry(tpAniSirGlobal mac_ctx, tSirMacAddr sta_addr, + uint16_t sta_id, tpPESession session_entry) +{ + uint16_t aid; + tpDphHashNode sta_ds; + tUpdateBeaconParams beacon_params; + + qdf_mem_zero(&beacon_params, sizeof(tUpdateBeaconParams)); + beacon_params.paramChangeBitmap = 0; + lim_deactivate_and_change_per_sta_id_timer(mac_ctx, eLIM_CNF_WAIT_TIMER, + sta_id); + if (NULL == session_entry) { + lim_log(mac_ctx, LOGE, FL("NULL session_entry")); + return; + } + + beacon_params.bssIdx = session_entry->bssIdx; + sta_ds = dph_lookup_hash_entry(mac_ctx, sta_addr, &aid, + &session_entry->dph.dphHashTable); + + if (sta_ds == NULL) { + lim_log(mac_ctx, LOGE, FL("sta_ds is NULL")); + return; + } + + lim_log(mac_ctx, LOGW, FL("Deleting DPH Hash entry for STAID: %X"), + sta_id); + /* + * update the station count and perform associated actions + * do this before deleting the dph hash entry + */ + lim_util_count_sta_del(mac_ctx, sta_ds, session_entry); + + if (LIM_IS_AP_ROLE(session_entry) || LIM_IS_IBSS_ROLE(session_entry)) { + if (LIM_IS_AP_ROLE(session_entry)) { + if (session_entry->gLimProtectionControl != + WNI_CFG_FORCE_POLICY_PROTECTION_DISABLE) + lim_decide_ap_protection_on_delete(mac_ctx, + sta_ds, &beacon_params, session_entry); + } + + if (LIM_IS_IBSS_ROLE(session_entry)) + lim_ibss_decide_protection_on_delete(mac_ctx, sta_ds, + &beacon_params, session_entry); + + lim_decide_short_preamble(mac_ctx, sta_ds, &beacon_params, + session_entry); + lim_decide_short_slot(mac_ctx, sta_ds, &beacon_params, + session_entry); + + /* Send message to HAL about beacon parameter change. */ + lim_log(mac_ctx, LOGW, FL("param bitmap = %d "), + beacon_params.paramChangeBitmap); + if (beacon_params.paramChangeBitmap && + (false == + mac_ctx->sap.SapDfsInfo.is_dfs_cac_timer_running)) { + sch_set_fixed_beacon_fields(mac_ctx, session_entry); + lim_send_beacon_params(mac_ctx, &beacon_params, + session_entry); + } +#ifdef WLAN_FEATURE_11W + tx_timer_delete(&sta_ds->pmfSaQueryTimer); +#endif + } + + if (dph_delete_hash_entry(mac_ctx, sta_addr, sta_id, + &session_entry->dph.dphHashTable) != eSIR_SUCCESS) + lim_log(mac_ctx, LOGP, FL("error deleting hash entry")); +} + +/** + * lim_check_and_announce_join_success()- function to check if the received + * Beacon/Probe Response is from the BSS that we're attempting to join. + * @mac: pointer to global mac structure + * @beacon_probe_rsp: pointer to reveived beacon/probe response frame + * @header: pointer to received management frame header + * @session_entry: pe session entry + * + * This function is called upon receiving Beacon/Probe Response + * frame in WT_JOIN_BEACON_STATE to check if the received + * Beacon/Probe Response is from the BSS that we're attempting + * to join. + * If the Beacon/Probe Response is indeed from the BSS we're + * attempting to join, join success is sent to SME. + * + * Return: none + */ + +void +lim_check_and_announce_join_success(tpAniSirGlobal mac_ctx, + tSirProbeRespBeacon *beacon_probe_rsp, tpSirMacMgmtHdr header, + tpPESession session_entry) +{ + tSirMacSSid current_ssid; + tLimMlmJoinCnf mlm_join_cnf; + uint32_t val = 0; + uint32_t *noa_duration_from_beacon = NULL; + uint32_t *noa2_duration_from_beacon = NULL; + uint32_t noa; + uint32_t total_num_noa_desc = 0; + + qdf_mem_copy(current_ssid.ssId, + session_entry->ssId.ssId, session_entry->ssId.length); + + current_ssid.length = (uint8_t) session_entry->ssId.length; + + /* + * Check for SSID only in probe response. Beacons may not carry + * SSID information in hidden SSID case + */ + if (((SIR_MAC_MGMT_FRAME == header->fc.type) && + (SIR_MAC_MGMT_PROBE_RSP == header->fc.subType)) && + current_ssid.length && + (qdf_mem_cmp((uint8_t *) &beacon_probe_rsp->ssId, + (uint8_t *) ¤t_ssid, + (uint8_t) (1 + current_ssid.length)))) { + /* + * Received SSID does not match with the one we've. + * Ignore received Beacon frame + */ + lim_log(mac_ctx, LOG1, + FL("SSID received in Beacon does not match")); +#ifdef WLAN_DEBUG + mac_ctx->lim.gLimBcnSSIDMismatchCnt++; +#endif + return; + } + + if (!LIM_IS_STA_ROLE(session_entry)) + return; + + lim_log(mac_ctx, LOG1, + FL("Received Beacon/PR with matching BSSID:%pM PESessionID %d"), + session_entry->bssId, session_entry->peSessionId); + + /* Deactivate Join Failure timer */ + lim_deactivate_and_change_timer(mac_ctx, eLIM_JOIN_FAIL_TIMER); + /* Deactivate Periodic Join timer */ + lim_deactivate_and_change_timer(mac_ctx, + eLIM_PERIODIC_JOIN_PROBE_REQ_TIMER); + + if (QDF_P2P_CLIENT_MODE == session_entry->pePersona && + beacon_probe_rsp->P2PProbeRes.NoticeOfAbsence.present) { + + noa_duration_from_beacon = (uint32_t *) + (beacon_probe_rsp->P2PProbeRes.NoticeOfAbsence.NoADesc + 1); + + if (beacon_probe_rsp->P2PProbeRes.NoticeOfAbsence.num_NoADesc) + total_num_noa_desc = + beacon_probe_rsp->P2PProbeRes.NoticeOfAbsence. + num_NoADesc / SIZE_OF_NOA_DESCRIPTOR; + + noa = *noa_duration_from_beacon; + + if (total_num_noa_desc > 1) { + noa2_duration_from_beacon = (uint32_t *) + (beacon_probe_rsp->P2PProbeRes.NoticeOfAbsence.NoADesc + + SIZE_OF_NOA_DESCRIPTOR + 1); + noa += *noa2_duration_from_beacon; + } + + /* + * If MAX Noa exceeds 3 secs we will consider only 3 secs to + * avoid arbitary values in noa duration field + */ + noa = noa > MAX_NOA_PERIOD_IN_MICROSECS ? + MAX_NOA_PERIOD_IN_MICROSECS : noa; + noa = noa / 1000; /* Convert to ms */ + + if (wlan_cfg_get_int(mac_ctx, + WNI_CFG_AUTHENTICATE_FAILURE_TIMEOUT, &val) == + eSIR_SUCCESS) { + session_entry->defaultAuthFailureTimeout = val; + cfg_set_int(mac_ctx, + WNI_CFG_AUTHENTICATE_FAILURE_TIMEOUT, + val + noa); + } + } else { + session_entry->defaultAuthFailureTimeout = 0; + } + + + /* + * Check if MBO Association disallowed subattr is present and post + * failure status to LIM if present + */ + if (!session_entry->ignore_assoc_disallowed && + beacon_probe_rsp->assoc_disallowed) { + lim_log(mac_ctx, LOGW, + FL("Connection fails due to assoc disallowed reason(%d):%pM PESessionID %d"), + beacon_probe_rsp->assoc_disallowed_reason, + session_entry->bssId, + session_entry->peSessionId); + mlm_join_cnf.resultCode = eSIR_SME_ASSOC_REFUSED; + mlm_join_cnf.protStatusCode = eSIR_MAC_UNSPEC_FAILURE_STATUS; + session_entry->limMlmState = eLIM_MLM_IDLE_STATE; + mlm_join_cnf.sessionId = session_entry->peSessionId; + if (session_entry->pLimMlmJoinReq) { + qdf_mem_free(session_entry->pLimMlmJoinReq); + session_entry->pLimMlmJoinReq = NULL; + } + lim_post_sme_message(mac_ctx, LIM_MLM_JOIN_CNF, + (uint32_t *) &mlm_join_cnf); + return; + } + + /* Update Beacon Interval at CFG database */ + + if (beacon_probe_rsp->HTCaps.present) + lim_update_sta_run_time_ht_capability(mac_ctx, + &beacon_probe_rsp->HTCaps); + if (beacon_probe_rsp->HTInfo.present) + lim_update_sta_run_time_ht_info(mac_ctx, + &beacon_probe_rsp->HTInfo, session_entry); + session_entry->limMlmState = eLIM_MLM_JOINED_STATE; + MTRACE(mac_trace(mac_ctx, TRACE_CODE_MLM_STATE, + session_entry->peSessionId, eLIM_MLM_JOINED_STATE)); + + /* + * update the capability info based on recently received beacon/probe + * response frame + */ + session_entry->limCurrentBssCaps = + lim_get_u16((uint8_t *)&beacon_probe_rsp->capabilityInfo); + + /* + * Announce join success by sending + * Join confirm to SME. + */ + mlm_join_cnf.resultCode = eSIR_SME_SUCCESS; + mlm_join_cnf.protStatusCode = eSIR_MAC_SUCCESS_STATUS; + /* Update PE sessionId */ + mlm_join_cnf.sessionId = session_entry->peSessionId; + lim_post_sme_message(mac_ctx, LIM_MLM_JOIN_CNF, + (uint32_t *) &mlm_join_cnf); + + if ((IS_DOT11_MODE_VHT(session_entry->dot11mode)) && + beacon_probe_rsp->vendor_vht_ie.VHTCaps.present) { + session_entry->is_vendor_specific_vhtcaps = true; + session_entry->vendor_specific_vht_ie_type = + beacon_probe_rsp->vendor_vht_ie.type; + session_entry->vendor_specific_vht_ie_sub_type = + beacon_probe_rsp->vendor_vht_ie.sub_type; + lim_log(mac_ctx, LOG1, FL( + "VHT caps are present in vendor specific IE")); + } + + /* Update HS 2.0 Information Element */ + if (beacon_probe_rsp->hs20vendor_ie.present) { + lim_log(mac_ctx, LOG1, + FL("HS20 Indication Element Present, rel#:%u, id:%u\n"), + beacon_probe_rsp->hs20vendor_ie.release_num, + beacon_probe_rsp->hs20vendor_ie.hs_id_present); + qdf_mem_copy(&session_entry->hs20vendor_ie, + &beacon_probe_rsp->hs20vendor_ie, + sizeof(tDot11fIEhs20vendor_ie) - + sizeof(beacon_probe_rsp->hs20vendor_ie.hs_id)); + if (beacon_probe_rsp->hs20vendor_ie.hs_id_present) + qdf_mem_copy(&session_entry->hs20vendor_ie.hs_id, + &beacon_probe_rsp->hs20vendor_ie.hs_id, + sizeof(beacon_probe_rsp->hs20vendor_ie.hs_id)); + } +} + +/** + * lim_extract_ap_capabilities() + * + ***FUNCTION: + * This function is called to extract all of the AP's capabilities + * from the IEs received from it in Beacon/Probe Response frames + * + ***LOGIC: + * This routine mimics the lim_extract_ap_capability() API. The difference here + * is that this API returns the entire tSirProbeRespBeacon info as is. It is + * left to the caller of this API to use this info as required + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * + * @param pMac Pointer to Global MAC structure + * @param pIE Pointer to starting IE in Beacon/Probe Response + * @param ieLen Length of all IEs combined + * @param beaconStruct A pointer to tSirProbeRespBeacon that needs to be + * populated + * @return status A status reporting eSIR_SUCCESS or eSIR_FAILURE + */ +tSirRetStatus lim_extract_ap_capabilities(tpAniSirGlobal pMac, + uint8_t *pIE, + uint16_t ieLen, + tpSirProbeRespBeacon beaconStruct) +{ + qdf_mem_set((uint8_t *) beaconStruct, sizeof(tSirProbeRespBeacon), 0); + + PELOG3(lim_log(pMac, LOG3, + FL + ("In lim_extract_ap_capabilities: The IE's being received are:")); + sir_dump_buf(pMac, SIR_LIM_MODULE_ID, LOG3, pIE, ieLen); + ) + /* Parse the Beacon IE's, Don't try to parse if we dont have anything in IE */ + if (ieLen > 0) { + if (eSIR_SUCCESS != + sir_parse_beacon_ie(pMac, beaconStruct, pIE, + (uint32_t) ieLen)) { + lim_log(pMac, LOGE, + FL("APCapExtract: Beacon parsing error!")); + return eSIR_FAILURE; + } + } + + return eSIR_SUCCESS; +} + +/** + * lim_del_bss() + * + ***FUNCTION: + * This function is called to delete BSS context at hardware + * whenever a STA is disassociated + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param pMac - Pointer to Global MAC structure + * @param pStaDs - Pointer to the STA datastructure created by + * LIM and maintained by DPH + * @return retCode - Indicates success or failure return code + */ + +tSirRetStatus +lim_del_bss(tpAniSirGlobal pMac, tpDphHashNode pStaDs, uint16_t bssIdx, + tpPESession psessionEntry) +{ + tpDeleteBssParams pDelBssParams = NULL; + tSirMsgQ msgQ; + tSirRetStatus retCode = eSIR_SUCCESS; + + pDelBssParams = qdf_mem_malloc(sizeof(tDeleteBssParams)); + if (NULL == pDelBssParams) { + lim_log(pMac, LOGP, + FL("Unable to allocate memory during ADD_BSS")); + return eSIR_MEM_ALLOC_FAILED; + } + + pDelBssParams->sessionId = psessionEntry->peSessionId; /* update PE session Id */ + + /* DPH was storing the AssocID in staID field, */ + /* staID is actually assigned by HAL when AddSTA message is sent. */ + if (pStaDs != NULL) { + pDelBssParams->bssIdx = pStaDs->bssId; + pStaDs->valid = 0; + pStaDs->mlmStaContext.mlmState = eLIM_MLM_WT_DEL_BSS_RSP_STATE; + } else + pDelBssParams->bssIdx = bssIdx; + psessionEntry->limMlmState = eLIM_MLM_WT_DEL_BSS_RSP_STATE; + MTRACE(mac_trace + (pMac, TRACE_CODE_MLM_STATE, psessionEntry->peSessionId, + eLIM_MLM_WT_DEL_BSS_RSP_STATE)); + + if ((psessionEntry->peSessionId == + pMac->lim.limTimers.gLimJoinFailureTimer.sessionId) + && (true == + tx_timer_running(&pMac->lim.limTimers.gLimJoinFailureTimer))) { + lim_deactivate_and_change_timer(pMac, eLIM_JOIN_FAIL_TIMER); + } + + pDelBssParams->status = QDF_STATUS_SUCCESS; + pDelBssParams->respReqd = 1; + qdf_mem_copy(pDelBssParams->bssid, psessionEntry->bssId, + sizeof(tSirMacAddr)); + pDelBssParams->smesessionId = psessionEntry->smeSessionId; + PELOGW(lim_log + (pMac, LOGW, + FL("Sessionid %d : Sending HAL_DELETE_BSS_REQ " + "for bss idx: %X BSSID:" MAC_ADDRESS_STR), + pDelBssParams->sessionId, pDelBssParams->bssIdx, + MAC_ADDR_ARRAY(psessionEntry->bssId)); + ) + /* we need to defer the message until we get the response back from HAL. */ + SET_LIM_PROCESS_DEFD_MESGS(pMac, false); + + lim_log(pMac, LOGW, FL("process_ho_fail = %d"), + psessionEntry->process_ho_fail); + if (psessionEntry->process_ho_fail) + msgQ.type = WMA_DELETE_BSS_HO_FAIL_REQ; + else + msgQ.type = WMA_DELETE_BSS_REQ; + msgQ.reserved = 0; + msgQ.bodyptr = pDelBssParams; + msgQ.bodyval = 0; + + MTRACE(mac_trace_msg_tx(pMac, psessionEntry->peSessionId, msgQ.type)); + + retCode = wma_post_ctrl_msg(pMac, &msgQ); + if (eSIR_SUCCESS != retCode) { + SET_LIM_PROCESS_DEFD_MESGS(pMac, true); + lim_log(pMac, LOGE, + FL("Posting DELETE_BSS_REQ to HAL failed, reason=%X"), + retCode); + qdf_mem_free(pDelBssParams); + } + + return retCode; +} + +/** + * lim_update_vhtcaps_assoc_resp : Update VHT caps in assoc response. + * @mac_ctx Pointer to Global MAC structure + * @pAddBssParams: parameters required for add bss params. + * @vht_caps: VHT capabilities. + * @psessionEntry : session entry. + * + * Return : void + */ +static void lim_update_vhtcaps_assoc_resp(tpAniSirGlobal mac_ctx, + tpAddBssParams pAddBssParams, + tDot11fIEVHTCaps *vht_caps, tpPESession psessionEntry) +{ + pAddBssParams->staContext.vht_caps = + ((vht_caps->maxMPDULen << + SIR_MAC_VHT_CAP_MAX_MPDU_LEN) | + (vht_caps->supportedChannelWidthSet << + SIR_MAC_VHT_CAP_SUPP_CH_WIDTH_SET) | + (vht_caps->ldpcCodingCap << + SIR_MAC_VHT_CAP_LDPC_CODING_CAP) | + (vht_caps->shortGI80MHz << + SIR_MAC_VHT_CAP_SHORTGI_80MHZ) | + (vht_caps->shortGI160and80plus80MHz << + SIR_MAC_VHT_CAP_SHORTGI_160_80_80MHZ) | + (vht_caps->txSTBC << + SIR_MAC_VHT_CAP_TXSTBC) | + (vht_caps->rxSTBC << + SIR_MAC_VHT_CAP_RXSTBC) | + (vht_caps->suBeamFormerCap << + SIR_MAC_VHT_CAP_SU_BEAMFORMER_CAP) | + (vht_caps->suBeamformeeCap << + SIR_MAC_VHT_CAP_SU_BEAMFORMEE_CAP) | + (vht_caps->csnofBeamformerAntSup << + SIR_MAC_VHT_CAP_CSN_BEAMORMER_ANT_SUP) | + (vht_caps->numSoundingDim << + SIR_MAC_VHT_CAP_NUM_SOUNDING_DIM) | + (vht_caps->muBeamformerCap << + SIR_MAC_VHT_CAP_NUM_BEAM_FORMER_CAP) | + (vht_caps->muBeamformeeCap << + SIR_MAC_VHT_CAP_NUM_BEAM_FORMEE_CAP) | + (vht_caps->vhtTXOPPS << + SIR_MAC_VHT_CAP_TXOPPS) | + (vht_caps->htcVHTCap << + SIR_MAC_VHT_CAP_HTC_CAP) | + (vht_caps->maxAMPDULenExp << + SIR_MAC_VHT_CAP_MAX_AMDU_LEN_EXPO) | + (vht_caps->vhtLinkAdaptCap << + SIR_MAC_VHT_CAP_LINK_ADAPT_CAP) | + (vht_caps->rxAntPattern << + SIR_MAC_VHT_CAP_RX_ANTENNA_PATTERN) | + (vht_caps->txAntPattern << + SIR_MAC_VHT_CAP_TX_ANTENNA_PATTERN) | + (vht_caps->reserved1 << + SIR_MAC_VHT_CAP_RESERVED2)); + + pAddBssParams->staContext.maxAmpduSize = + SIR_MAC_GET_VHT_MAX_AMPDU_EXPO( + pAddBssParams->staContext.vht_caps); + + lim_log(mac_ctx, LOG1, + FL("Updating VHT caps in assoc Response")); +} + +/** + * lim_update_vht_oper_assoc_resp : Update VHT Operations in assoc response. + * @mac_ctx Pointer to Global MAC structure + * @pAddBssParams: parameters required for add bss params. + * @vht_oper: VHT Operations to update. + * @psessionEntry : session entry. + * + * Return : void + */ +static void lim_update_vht_oper_assoc_resp(tpAniSirGlobal mac_ctx, + tpAddBssParams pAddBssParams, + tDot11fIEVHTOperation *vht_oper, tpPESession psessionEntry) +{ + if (vht_oper->chanWidth && + psessionEntry->ch_width) { + pAddBssParams->ch_width = vht_oper->chanWidth + 1; + + pAddBssParams->ch_center_freq_seg0 = + vht_oper->chanCenterFreqSeg1; + + pAddBssParams->ch_center_freq_seg1 = + vht_oper->chanCenterFreqSeg2; + } + lim_log(mac_ctx, LOG1, + FL("Updating VHT Operation in assoc Response")); +} + + +/** + * limSendAddBss() + * + ***FUNCTION: + * + ***LOGIC: + * 1) LIM receives eWNI_SME_JOIN_REQ + * 2) For a valid eWNI_SME_JOIN_REQ, LIM sends + * SIR_HAL_ADD_BSS_REQ to HAL + * + ***ASSUMPTIONS: + * JOIN REQ parameters are saved in pMac->lim.gLimMlmJoinReq + * ADD BSS parameters can be obtained from two sources: + * 1) pMac->lim.gLimMlmJoinReq + * 2) beaconStruct, passed as paramter + * So, if a reqd parameter is found in bssDescriptions + * then it is given preference over beaconStruct + * + ***NOTE: + * + * @param pMac Pointer to Global MAC structure + * pAssocRsp contains the structured assoc/reassoc Response got from AP + * beaconstruct Has the ProbeRsp/Beacon structured details + * bssDescription bssDescription passed to PE from the SME + * @return None + */ + +tSirRetStatus lim_sta_send_add_bss(tpAniSirGlobal pMac, tpSirAssocRsp pAssocRsp, + tpSchBeaconStruct pBeaconStruct, + tpSirBssDescription bssDescription, + uint8_t updateEntry, tpPESession psessionEntry) +{ + tSirMsgQ msgQ; + tpAddBssParams pAddBssParams = NULL; + uint32_t retCode; + tpDphHashNode pStaDs = NULL; + uint8_t chanWidthSupp = 0; + uint32_t enableTxBF20MHz; + tDot11fIEVHTCaps *vht_caps = NULL; + tDot11fIEVHTOperation *vht_oper = NULL; + tAddStaParams *sta_context; + + /* Package SIR_HAL_ADD_BSS_REQ message parameters */ + pAddBssParams = qdf_mem_malloc(sizeof(tAddBssParams)); + if (NULL == pAddBssParams) { + lim_log(pMac, LOGP, + FL("Unable to allocate memory during ADD_BSS")); + retCode = eSIR_MEM_ALLOC_FAILED; + goto returnFailure; + } + + qdf_mem_copy(pAddBssParams->bssId, bssDescription->bssId, + sizeof(tSirMacAddr)); + /* Fill in tAddBssParams selfMacAddr */ + qdf_mem_copy(pAddBssParams->selfMacAddr, + psessionEntry->selfMacAddr, sizeof(tSirMacAddr)); + + lim_log(pMac, LOG1, + FL("sessionid: %d updateEntry = %d limsystemrole = %d "), + psessionEntry->smeSessionId, updateEntry, + GET_LIM_SYSTEM_ROLE(psessionEntry)); + + lim_log(pMac, LOG1, FL("BSSID: " MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(pAddBssParams->bssId)); + + pAddBssParams->bssType = eSIR_INFRASTRUCTURE_MODE; + + pAddBssParams->operMode = BSS_OPERATIONAL_MODE_STA; + + /* Update PE session ID */ + pAddBssParams->sessionId = psessionEntry->peSessionId; + + pAddBssParams->beaconInterval = bssDescription->beaconInterval; + + pAddBssParams->dtimPeriod = pBeaconStruct->tim.dtimPeriod; + pAddBssParams->updateBss = updateEntry; + + pAddBssParams->cfParamSet.cfpCount = pBeaconStruct->cfParamSet.cfpCount; + pAddBssParams->cfParamSet.cfpPeriod = + pBeaconStruct->cfParamSet.cfpPeriod; + pAddBssParams->cfParamSet.cfpMaxDuration = + pBeaconStruct->cfParamSet.cfpMaxDuration; + pAddBssParams->cfParamSet.cfpDurRemaining = + pBeaconStruct->cfParamSet.cfpDurRemaining; + + pAddBssParams->rateSet.numRates = pAssocRsp->supportedRates.numRates; + qdf_mem_copy(pAddBssParams->rateSet.rate, + pAssocRsp->supportedRates.rate, + pAssocRsp->supportedRates.numRates); + + if (IS_DOT11_MODE_11B(psessionEntry->dot11mode) && + bssDescription->nwType != eSIR_11B_NW_TYPE) { + pAddBssParams->nwType = eSIR_11B_NW_TYPE; + } else { + pAddBssParams->nwType = bssDescription->nwType; + } + + pAddBssParams->shortSlotTimeSupported = + (uint8_t) pAssocRsp->capabilityInfo.shortSlotTime; + pAddBssParams->llaCoexist = + (uint8_t) psessionEntry->beaconParams.llaCoexist; + pAddBssParams->llbCoexist = + (uint8_t) psessionEntry->beaconParams.llbCoexist; + pAddBssParams->llgCoexist = + (uint8_t) psessionEntry->beaconParams.llgCoexist; + pAddBssParams->ht20Coexist = + (uint8_t) psessionEntry->beaconParams.ht20Coexist; + + lim_log(pMac, LOG2, FL(" BSS Type %d Beacon Interval: %d dtimPeriod: %d " + "cfpCount: %d"), pAddBssParams->bssType, + pAddBssParams->beaconInterval, pAddBssParams->dtimPeriod, + pAddBssParams->cfParamSet.cfpCount); + + lim_log(pMac, LOG2, + FL(" cfpPeriod: %d cfpMaxDuration: %d cfpDurRemaining:" + " %d numRates: %d "), pAddBssParams->cfParamSet.cfpPeriod, + pAddBssParams->cfParamSet.cfpMaxDuration, + pAddBssParams->cfParamSet.cfpDurRemaining, + pAddBssParams->rateSet.numRates); + + lim_log(pMac, LOG2, FL("nwType:%d shortSlotTimeSupported: %d" + "llaCoexist: %d llbCoexist: %d llgCoexist: %d ht20Coexist: %d"), + pAddBssParams->nwType, pAddBssParams->shortSlotTimeSupported, + pAddBssParams->llaCoexist, pAddBssParams->llbCoexist, + pAddBssParams->llgCoexist, pAddBssParams->ht20Coexist); + + pAddBssParams->dot11_mode = psessionEntry->dot11mode; + lim_log(pMac, LOG2, FL("dot11_mode:%d"), pAddBssParams->dot11_mode); + + /* Use the advertised capabilities from the received beacon/PR */ + + if (IS_DOT11_MODE_HT(psessionEntry->dot11mode) + && (pAssocRsp->HTCaps.present)) { + pAddBssParams->htCapable = pAssocRsp->HTCaps.present; + lim_log(pMac, LOG2, FL("htCapable: %d"), + pAddBssParams->htCapable); + if (pBeaconStruct->HTInfo.present) { + pAddBssParams->htOperMode = + (tSirMacHTOperatingMode) pAssocRsp->HTInfo.opMode; + pAddBssParams->dualCTSProtection = + (uint8_t) pAssocRsp->HTInfo.dualCTSProtection; + chanWidthSupp = + lim_get_ht_capability(pMac, + eHT_SUPPORTED_CHANNEL_WIDTH_SET, + psessionEntry); + if ((pAssocRsp->HTCaps.supportedChannelWidthSet) + && (chanWidthSupp)) { + pAddBssParams->ch_width = (uint8_t) + pAssocRsp->HTInfo.recommendedTxWidthSet; + if (pAssocRsp->HTInfo.secondaryChannelOffset == + PHY_DOUBLE_CHANNEL_LOW_PRIMARY) + pAddBssParams->ch_center_freq_seg0 = + bssDescription->channelId + 2; + else if (pAssocRsp->HTInfo.secondaryChannelOffset == + PHY_DOUBLE_CHANNEL_HIGH_PRIMARY) + pAddBssParams->ch_center_freq_seg0 = + bssDescription->channelId - 2; + } else { + pAddBssParams->ch_width = CH_WIDTH_20MHZ; + pAddBssParams->ch_center_freq_seg0 = 0; + } + pAddBssParams->llnNonGFCoexist = + (uint8_t) pAssocRsp->HTInfo.nonGFDevicesPresent; + pAddBssParams->fLsigTXOPProtectionFullSupport = + (uint8_t) pAssocRsp->HTInfo. + lsigTXOPProtectionFullSupport; + pAddBssParams->fRIFSMode = pAssocRsp->HTInfo.rifsMode; + + lim_log(pMac, LOG1, + FL("htOperMode: %d dualCTSProtection: %d txChannelWidth: %d center_freq_0: %d "), + pAddBssParams->htOperMode, + pAddBssParams->dualCTSProtection, + pAddBssParams->ch_width, + pAddBssParams->ch_center_freq_seg0); + + lim_log(pMac, LOG2, FL("llnNonGFCoexist: %d " + "fLsigTXOPProtectionFullSupport: %d fRIFSMode %d"), + pAddBssParams->llnNonGFCoexist, + pAddBssParams->fLsigTXOPProtectionFullSupport, + pAddBssParams->fRIFSMode); + } + } + + pAddBssParams->currentOperChannel = bssDescription->channelId; + lim_log(pMac, LOG1, FL("currentOperChannel %d"), + pAddBssParams->currentOperChannel); + if (psessionEntry->vhtCapability && (pAssocRsp->VHTCaps.present)) { + pAddBssParams->vhtCapable = pAssocRsp->VHTCaps.present; + vht_caps = &pAssocRsp->VHTCaps; + vht_oper = &pAssocRsp->VHTOperation; + } else if (psessionEntry->vhtCapability && + pAssocRsp->vendor_vht_ie.VHTCaps.present){ + pAddBssParams->vhtCapable = + pAssocRsp->vendor_vht_ie.VHTCaps.present; + lim_log(pMac, LOG1, + FL("VHT Caps and Operation are present in vendor Specfic IE")); + vht_caps = &pAssocRsp->vendor_vht_ie.VHTCaps; + vht_oper = &pAssocRsp->vendor_vht_ie.VHTOperation; + } else { + pAddBssParams->vhtCapable = 0; + } + if (pAddBssParams->vhtCapable) { + if (vht_oper != NULL) + lim_update_vht_oper_assoc_resp(pMac, pAddBssParams, + vht_oper, psessionEntry); + if (vht_caps != NULL) + lim_update_vhtcaps_assoc_resp(pMac, pAddBssParams, + vht_caps, psessionEntry); + } + + lim_log(pMac, LOG1, FL("vhtCapable %d TxChannelWidth %d center_freq_0 %d center_freq_1 %d"), + pAddBssParams->vhtCapable, pAddBssParams->ch_width, + pAddBssParams->ch_center_freq_seg0, + pAddBssParams->ch_center_freq_seg1); + + /* + * Populate the STA-related parameters here + * Note that the STA here refers to the AP + * staType = PEER + */ + sta_context = &pAddBssParams->staContext; + /* Identifying AP as an STA */ + pAddBssParams->staContext.staType = STA_ENTRY_OTHER; + + qdf_mem_copy(pAddBssParams->staContext.bssId, + bssDescription->bssId, sizeof(tSirMacAddr)); + pAddBssParams->staContext.listenInterval = + bssDescription->beaconInterval; + + /* Fill Assoc id from the dph table */ + pStaDs = dph_lookup_hash_entry(pMac, pAddBssParams->staContext.bssId, + &pAddBssParams->staContext.assocId, + &psessionEntry->dph.dphHashTable); + if (pStaDs == NULL) { + lim_log(pMac, LOGE, FL( + "Couldn't get assoc id for " "MAC ADDR: " + MAC_ADDRESS_STR), + MAC_ADDR_ARRAY( + pAddBssParams->staContext.staMac)); + return eSIR_FAILURE; + } + + pAddBssParams->staContext.uAPSD = + psessionEntry->gUapsdPerAcBitmask; + + pAddBssParams->staContext.maxSPLen = 0; + pAddBssParams->staContext.shortPreambleSupported = + (uint8_t) pAssocRsp->capabilityInfo.shortPreamble; + pAddBssParams->staContext.updateSta = updateEntry; + + lim_log(pMac, LOG2, FL("StaContext: " MAC_ADDRESS_STR + " shortPreambleSupported: %d"), + MAC_ADDR_ARRAY(pAddBssParams->staContext.staMac), + pAddBssParams->staContext.shortPreambleSupported); + + if (IS_DOT11_MODE_HT(psessionEntry->dot11mode) + && pBeaconStruct->HTCaps.present) { + pAddBssParams->staContext.us32MaxAmpduDuration = 0; + pAddBssParams->staContext.htCapable = 1; + pAddBssParams->staContext.greenFieldCapable = + (uint8_t) pAssocRsp->HTCaps.greenField; + pAddBssParams->staContext.lsigTxopProtection = + (uint8_t) pAssocRsp->HTCaps.lsigTXOPProtection; + lim_log(pMac, LOG2, FL( + "StaCtx: htCap %d GFcap %d lsigTxopProtn %d"), + pAddBssParams->staContext.htCapable, + pAddBssParams->staContext.greenFieldCapable, + pAddBssParams->staContext.lsigTxopProtection); + if (psessionEntry->vhtCapability && + (IS_BSS_VHT_CAPABLE(pBeaconStruct->VHTCaps) || + IS_BSS_VHT_CAPABLE(pBeaconStruct-> + vendor_vht_ie.VHTCaps))) { + pAddBssParams->staContext.vhtCapable = 1; + pAddBssParams->staContext.vhtSupportedRxNss = + pStaDs->vhtSupportedRxNss; + if (pAssocRsp->VHTCaps.present) + vht_caps = &pAssocRsp->VHTCaps; + else if (pAssocRsp->vendor_vht_ie.VHTCaps.present) { + vht_caps = &pAssocRsp->vendor_vht_ie.VHTCaps; + lim_log(pMac, LOG1, FL( + "VHT Caps are in vendor Specfic IE")); + } + + if ((vht_caps != NULL) && (vht_caps->suBeamFormerCap || + vht_caps->muBeamformerCap) && + psessionEntry->vht_config.su_beam_formee) + sta_context->vhtTxBFCapable = 1; + + if ((vht_caps != NULL) && vht_caps->muBeamformerCap && + psessionEntry->vht_config.mu_beam_formee) + sta_context->vhtTxMUBformeeCapable = 1; + + if ((vht_caps != NULL) && vht_caps->suBeamformeeCap && + psessionEntry->vht_config.su_beam_former) + sta_context->enable_su_tx_bformer = 1; + } + + if ((pAssocRsp->HTCaps.supportedChannelWidthSet) && + (chanWidthSupp)) { + pAddBssParams->staContext.ch_width = (uint8_t) + pAssocRsp->HTInfo.recommendedTxWidthSet; + if (pAssocRsp->VHTCaps.present) + vht_oper = &pAssocRsp->VHTOperation; + else if (pAssocRsp->vendor_vht_ie.VHTCaps.present) { + vht_oper = &pAssocRsp-> + vendor_vht_ie.VHTOperation; + lim_log(pMac, LOG1, FL( + "VHT Op IE is in vendor Specfic IE")); + } + /* + * in limExtractApCapability function intersection of FW + * advertised channel width and AP advertised channel + * width has been taken into account for calculating + * psessionEntry->ch_width + */ + pAddBssParams->staContext.ch_width = + psessionEntry->ch_width; + + lim_log(pMac, LOG1, FL( + "StaCtx: vhtCap %d ChBW %d TxBF %d"), + pAddBssParams->staContext.vhtCapable, + pAddBssParams->staContext.ch_width, + sta_context->vhtTxBFCapable); + lim_log(pMac, LOG1, FL("StaContext su_tx_bfer %d"), + sta_context->enable_su_tx_bformer); + } else { + sta_context->ch_width = CH_WIDTH_20MHZ; + if ((IS_SIR_STATUS_SUCCESS( + wlan_cfg_get_int(pMac, + WNI_CFG_VHT_ENABLE_TXBF_20MHZ, + &enableTxBF20MHz))) && + (false == enableTxBF20MHz)) + sta_context->vhtTxBFCapable = 0; + } + pAddBssParams->staContext.mimoPS = + (tSirMacHTMIMOPowerSaveState) + pAssocRsp->HTCaps.mimoPowerSave; + pAddBssParams->staContext.maxAmsduSize = + (uint8_t) pAssocRsp->HTCaps.maximalAMSDUsize; + pAddBssParams->staContext.maxAmpduDensity = + pAssocRsp->HTCaps.mpduDensity; + pAddBssParams->staContext.fDsssCckMode40Mhz = + (uint8_t) pAssocRsp->HTCaps.dsssCckMode40MHz; + /* + * We will check gShortGI20Mhz and gShortGI40Mhz from + * session entry if they are set then we will use what ever + * Assoc response coming from AP supports. If these + * values are set as 0 in session entry then we will + * hardcode this values to 0. + */ + if (psessionEntry->htConfig.ht_sgi20) { + pAddBssParams->staContext.fShortGI20Mhz = + (uint8_t)pAssocRsp->HTCaps.shortGI20MHz; + } else { + pAddBssParams->staContext.fShortGI20Mhz = false; + } + + if (psessionEntry->htConfig.ht_sgi40) { + pAddBssParams->staContext.fShortGI40Mhz = + (uint8_t) pAssocRsp->HTCaps.shortGI40MHz; + } else { + pAddBssParams->staContext.fShortGI40Mhz = false; + } + + if (!pAddBssParams->staContext.vhtCapable) + /* Use max ampd factor advertised in + * HTCAP for non-vht connection */ + { + pAddBssParams->staContext.maxAmpduSize = + pAssocRsp->HTCaps.maxRxAMPDUFactor; + } else if (pAddBssParams->staContext.maxAmpduSize < + pAssocRsp->HTCaps.maxRxAMPDUFactor) { + pAddBssParams->staContext.maxAmpduSize = + pAssocRsp->HTCaps.maxRxAMPDUFactor; + } + if (pAddBssParams->staContext.vhtTxBFCapable + && pMac->lim.disableLDPCWithTxbfAP) { + pAddBssParams->staContext.htLdpcCapable = 0; + pAddBssParams->staContext.vhtLdpcCapable = 0; + } else { + if (psessionEntry->txLdpcIniFeatureEnabled & 0x1) + pAddBssParams->staContext.htLdpcCapable = + (uint8_t) pAssocRsp->HTCaps.advCodingCap; + else + pAddBssParams->staContext.htLdpcCapable = 0; + + if (pAssocRsp->VHTCaps.present) + vht_caps = &pAssocRsp->VHTCaps; + else if (pAssocRsp->vendor_vht_ie.VHTCaps.present) { + vht_caps = &pAssocRsp->vendor_vht_ie.VHTCaps; + lim_log(pMac, LOG1, FL( + "VHT Caps is in vendor Specfic IE")); + } + if (vht_caps != NULL && + (psessionEntry->txLdpcIniFeatureEnabled & 0x2)) + pAddBssParams->staContext.vhtLdpcCapable = + (uint8_t) vht_caps->ldpcCodingCap; + else + pAddBssParams->staContext.vhtLdpcCapable = 0; + } + + if (pBeaconStruct->HTInfo.present) + pAddBssParams->staContext.rifsMode = + pAssocRsp->HTInfo.rifsMode; + + lim_log(pMac, LOG2, FL( + "StaCtx: ChBW %d mimoPS %d maxAmsduSize %d"), + pAddBssParams->staContext.ch_width, + pAddBssParams->staContext.mimoPS, + pAddBssParams->staContext.maxAmsduSize); + + lim_log(pMac, LOG2, FL( + "maxAmpduDens %d CckMode40Mhz %d SGI20Mhz %d"), + pAddBssParams->staContext.maxAmpduDensity, + pAddBssParams->staContext.fDsssCckMode40Mhz, + pAddBssParams->staContext.fShortGI20Mhz); + + lim_log(pMac, LOG2, FL( + "SGI40M %d maxAmpdu %d htLdpc %d vhtLdpc %d"), + pAddBssParams->staContext.fShortGI40Mhz, + pAddBssParams->staContext.maxAmpduSize, + pAddBssParams->staContext.htLdpcCapable, + pAddBssParams->staContext.vhtLdpcCapable); + } + pAddBssParams->staContext.smesessionId = + psessionEntry->smeSessionId; + pAddBssParams->staContext.wpa_rsn = pBeaconStruct->rsnPresent; + pAddBssParams->staContext.wpa_rsn |= + (pBeaconStruct->wpaPresent << 1); + /* For OSEN Connection AP does not advertise RSN or WPA IE + * so from the IEs we get from supplicant we get this info + * so for FW to transmit EAPOL message 4 we shall set + * wpa_rsn + */ + if ((!pAddBssParams->staContext.wpa_rsn) + && (psessionEntry->isOSENConnection)) + pAddBssParams->staContext.wpa_rsn = 1; + qdf_mem_copy(&pAddBssParams->staContext.capab_info, + &pAssocRsp->capabilityInfo, + sizeof(pAddBssParams->staContext.capab_info)); + qdf_mem_copy(&pAddBssParams->staContext.ht_caps, + (uint8_t *) &pAssocRsp->HTCaps + sizeof(uint8_t), + sizeof(pAddBssParams->staContext.ht_caps)); + + /* If WMM IE or 802.11E IE is present then enable WMM */ + if ((psessionEntry->limWmeEnabled && pAssocRsp->wmeEdcaPresent) || + (psessionEntry->limQosEnabled && pAssocRsp->edcaPresent)) + pAddBssParams->staContext.wmmEnabled = 1; + else + pAddBssParams->staContext.wmmEnabled = 0; + + /* Update the rates */ + pStaDs = dph_get_hash_entry(pMac, DPH_STA_HASH_INDEX_PEER, + &psessionEntry->dph.dphHashTable); + if (pStaDs != NULL) { + qdf_mem_copy((uint8_t *) &pAddBssParams->staContext. + supportedRates, + (uint8_t *)&pStaDs->supportedRates, + sizeof(tSirSupportedRates)); + } else + lim_log(pMac, LOGE, FL( + "could not Update the supported rates")); + pAddBssParams->staContext.encryptType = psessionEntry->encryptType; + + pAddBssParams->maxTxPower = psessionEntry->maxTxPower; + lim_log(pMac, LOG2, FL("maxTxPower: %d"), pAddBssParams->maxTxPower); + /* FIXME_GEN4 - Any other value that can be used for initialization? */ + pAddBssParams->status = QDF_STATUS_SUCCESS; + pAddBssParams->respReqd = true; + /* update persona */ + pAddBssParams->halPersona = (uint8_t) psessionEntry->pePersona; + + if (QDF_P2P_CLIENT_MODE == psessionEntry->pePersona) + pAddBssParams->staContext.p2pCapableSta = 1; + + pAddBssParams->bSpectrumMgtEnabled = psessionEntry->spectrumMgtEnabled; + + pAddBssParams->extSetStaKeyParamValid = 0; + lim_log(pMac, LOG2, FL("extSetStaKeyParamValid: %d"), + pAddBssParams->extSetStaKeyParamValid); + +#ifdef WLAN_FEATURE_11W + if (psessionEntry->limRmfEnabled) { + pAddBssParams->rmfEnabled = 1; + pAddBssParams->staContext.rmfEnabled = 1; + } +#endif + + /* Set a new state for MLME */ + if (eLIM_MLM_WT_ASSOC_RSP_STATE == psessionEntry->limMlmState) + psessionEntry->limMlmState = + eLIM_MLM_WT_ADD_BSS_RSP_ASSOC_STATE; + else + psessionEntry->limMlmState = + eLIM_MLM_WT_ADD_BSS_RSP_REASSOC_STATE; + MTRACE(mac_trace + (pMac, TRACE_CODE_MLM_STATE, psessionEntry->peSessionId, + psessionEntry->limMlmState)); + + if (!pAddBssParams->staContext.htLdpcCapable) + pAddBssParams->staContext.ht_caps &= + ~(1 << SIR_MAC_HT_CAP_ADVCODING_S); + if (!pAddBssParams->staContext.vhtLdpcCapable) + pAddBssParams->staContext.vht_caps &= + ~(1 << SIR_MAC_VHT_CAP_LDPC_CODING_CAP); + + lim_log(pMac, LOG2, FL("staContext wmmEnabled: %d encryptType: %d " + "p2pCapableSta: %d"), + pAddBssParams->staContext.wmmEnabled, + pAddBssParams->staContext.encryptType, + pAddBssParams->staContext.p2pCapableSta); + + lim_log(pMac, LOG2, FL("bSpectrumMgtEnabled: %d halPersona: %d setting " + "LimMlm state to %d"), + pAddBssParams->bSpectrumMgtEnabled, pAddBssParams->halPersona, + psessionEntry->limMlmState); + if (psessionEntry->isNonRoamReassoc) + pAddBssParams->nonRoamReassoc = 1; + pAddBssParams->nss = psessionEntry->nss; + lim_log(pMac, LOG2, FL("nss value: %d"), pAddBssParams->nss); + + /* we need to defer the message until we get the response back from HAL. */ + SET_LIM_PROCESS_DEFD_MESGS(pMac, false); + + if (cds_is_5_mhz_enabled()) { + pAddBssParams->ch_width = CH_WIDTH_5MHZ; + pAddBssParams->staContext.ch_width = CH_WIDTH_5MHZ; + } else if (cds_is_10_mhz_enabled()) { + pAddBssParams->ch_width = CH_WIDTH_10MHZ; + pAddBssParams->staContext.ch_width = CH_WIDTH_10MHZ; + } + + msgQ.type = WMA_ADD_BSS_REQ; + /** @ToDo : Update the Global counter to keeptrack of the PE <--> HAL messages*/ + msgQ.reserved = 0; + msgQ.bodyptr = pAddBssParams; + msgQ.bodyval = 0; + + lim_log(pMac, LOG1, FL("SessionId:%d Sending WMA_ADD_BSS_REQ"), + psessionEntry->peSessionId); + MTRACE(mac_trace_msg_tx(pMac, psessionEntry->peSessionId, msgQ.type)); + + retCode = wma_post_ctrl_msg(pMac, &msgQ); + if (eSIR_SUCCESS != retCode) { + SET_LIM_PROCESS_DEFD_MESGS(pMac, true); + qdf_mem_free(pAddBssParams); + lim_log(pMac, LOGE, + FL("Posting ADD_BSS_REQ to HAL failed, reason=%X"), + retCode); + goto returnFailure; + + } else + return retCode; + +returnFailure: + /* Clean-up will be done by the caller... */ + return retCode; +} + +tSirRetStatus lim_sta_send_add_bss_pre_assoc(tpAniSirGlobal pMac, uint8_t updateEntry, + tpPESession psessionEntry) +{ + tSirMsgQ msgQ; + tpAddBssParams pAddBssParams = NULL; + uint32_t retCode; + tSchBeaconStruct *pBeaconStruct; + uint8_t chanWidthSupp = 0; + tDot11fIEVHTOperation *vht_oper = NULL; + tDot11fIEVHTCaps *vht_caps = NULL; + + tpSirBssDescription bssDescription = + &psessionEntry->pLimJoinReq->bssDescription; + + pBeaconStruct = qdf_mem_malloc(sizeof(tSchBeaconStruct)); + if (NULL == pBeaconStruct) { + lim_log(pMac, LOGE, + FL("Unable to allocate memory during ADD_BSS")); + return eSIR_MEM_ALLOC_FAILED; + } + + /* Package SIR_HAL_ADD_BSS_REQ message parameters */ + pAddBssParams = qdf_mem_malloc(sizeof(tAddBssParams)); + if (NULL == pAddBssParams) { + lim_log(pMac, LOGP, + FL("Unable to allocate memory during ADD_BSS")); + retCode = eSIR_MEM_ALLOC_FAILED; + goto returnFailure; + } + + lim_extract_ap_capabilities(pMac, (uint8_t *) bssDescription->ieFields, + lim_get_ielen_from_bss_description(bssDescription), + pBeaconStruct); + + if (pMac->lim.gLimProtectionControl != + WNI_CFG_FORCE_POLICY_PROTECTION_DISABLE) + lim_decide_sta_protection_on_assoc(pMac, pBeaconStruct, + psessionEntry); + qdf_mem_copy(pAddBssParams->bssId, bssDescription->bssId, + sizeof(tSirMacAddr)); + + /* Fill in tAddBssParams selfMacAddr */ + qdf_mem_copy(pAddBssParams->selfMacAddr, + psessionEntry->selfMacAddr, sizeof(tSirMacAddr)); + lim_log(pMac, LOG1, + FL("sessionid: %d updateEntry = %d limsystemrole = %d "), + psessionEntry->smeSessionId, updateEntry, + GET_LIM_SYSTEM_ROLE(psessionEntry)); + + lim_log(pMac, LOG1, FL("BSSID: " MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(pAddBssParams->bssId)); + /* Incorrect BSS Type which caused UMA Descriptor to be overwritten on + * top of an already established Infra link. This lead to issues in + * concurrent data transfer. + */ + + pAddBssParams->bssType = psessionEntry->bssType; /* eSIR_INFRASTRUCTURE_MODE; */ + pAddBssParams->operMode = BSS_OPERATIONAL_MODE_STA; + + pAddBssParams->beaconInterval = bssDescription->beaconInterval; + + pAddBssParams->dtimPeriod = pBeaconStruct->tim.dtimPeriod; + pAddBssParams->updateBss = updateEntry; + + pAddBssParams->cfParamSet.cfpCount = pBeaconStruct->cfParamSet.cfpCount; + pAddBssParams->cfParamSet.cfpPeriod = + pBeaconStruct->cfParamSet.cfpPeriod; + pAddBssParams->cfParamSet.cfpMaxDuration = + pBeaconStruct->cfParamSet.cfpMaxDuration; + pAddBssParams->cfParamSet.cfpDurRemaining = + pBeaconStruct->cfParamSet.cfpDurRemaining; + + pAddBssParams->rateSet.numRates = + pBeaconStruct->supportedRates.numRates; + qdf_mem_copy(pAddBssParams->rateSet.rate, + pBeaconStruct->supportedRates.rate, + pBeaconStruct->supportedRates.numRates); + + pAddBssParams->nwType = bssDescription->nwType; + + pAddBssParams->shortSlotTimeSupported = + (uint8_t) pBeaconStruct->capabilityInfo.shortSlotTime; + pAddBssParams->llaCoexist = + (uint8_t) psessionEntry->beaconParams.llaCoexist; + pAddBssParams->llbCoexist = + (uint8_t) psessionEntry->beaconParams.llbCoexist; + pAddBssParams->llgCoexist = + (uint8_t) psessionEntry->beaconParams.llgCoexist; + pAddBssParams->ht20Coexist = + (uint8_t) psessionEntry->beaconParams.ht20Coexist; + + lim_log(pMac, LOG2, FL(" BSS Type %d Beacon Interval: %d dtimPeriod: %d " + "cfpCount: %d"), pAddBssParams->bssType, + pAddBssParams->beaconInterval, pAddBssParams->dtimPeriod, + pAddBssParams->cfParamSet.cfpCount); + + lim_log(pMac, LOG2, + FL(" cfpPeriod: %d cfpMaxDuration: %d cfpDurRemaining:" + " %d numRates: %d "), pAddBssParams->cfParamSet.cfpPeriod, + pAddBssParams->cfParamSet.cfpMaxDuration, + pAddBssParams->cfParamSet.cfpDurRemaining, + pAddBssParams->rateSet.numRates); + + lim_log(pMac, LOG2, FL("nwType:%d shortSlotTimeSupported: %d" + "llaCoexist: %d llbCoexist: %d llgCoexist: %d ht20Coexist: %d"), + pAddBssParams->nwType, pAddBssParams->shortSlotTimeSupported, + pAddBssParams->llaCoexist, pAddBssParams->llbCoexist, + pAddBssParams->llgCoexist, pAddBssParams->ht20Coexist); + /* Use the advertised capabilities from the received beacon/PR */ + if (IS_DOT11_MODE_HT(psessionEntry->dot11mode) + && (pBeaconStruct->HTCaps.present)) { + pAddBssParams->htCapable = pBeaconStruct->HTCaps.present; + lim_log(pMac, LOG2, FL("htCapable: %d"), + pAddBssParams->htCapable); + if (pBeaconStruct->HTInfo.present) { + pAddBssParams->htOperMode = + (tSirMacHTOperatingMode) pBeaconStruct->HTInfo. + opMode; + pAddBssParams->dualCTSProtection = + (uint8_t) pBeaconStruct->HTInfo.dualCTSProtection; + + chanWidthSupp = + lim_get_ht_capability(pMac, + eHT_SUPPORTED_CHANNEL_WIDTH_SET, + psessionEntry); + if ((pBeaconStruct->HTCaps.supportedChannelWidthSet) + && (chanWidthSupp)) { + pAddBssParams->ch_width = + (uint8_t) pBeaconStruct->HTInfo. + recommendedTxWidthSet; + if (pBeaconStruct->HTInfo.secondaryChannelOffset == + PHY_DOUBLE_CHANNEL_LOW_PRIMARY) + pAddBssParams->ch_center_freq_seg0 = + bssDescription->channelId + 2; + + if (pBeaconStruct->HTInfo.secondaryChannelOffset == + PHY_DOUBLE_CHANNEL_HIGH_PRIMARY) + pAddBssParams->ch_center_freq_seg0 = + bssDescription->channelId - 2; + } else { + pAddBssParams->ch_width = CH_WIDTH_20MHZ; + pAddBssParams->ch_center_freq_seg0 = 0; + } + pAddBssParams->llnNonGFCoexist = + (uint8_t) pBeaconStruct->HTInfo.nonGFDevicesPresent; + pAddBssParams->fLsigTXOPProtectionFullSupport = + (uint8_t) pBeaconStruct->HTInfo. + lsigTXOPProtectionFullSupport; + pAddBssParams->fRIFSMode = + pBeaconStruct->HTInfo.rifsMode; + + lim_log(pMac, LOG2, + FL("htOperMode: %d dualCTSProtection: %d txChannelWidthSet: %d center_freq_seg0: %d "), + pAddBssParams->htOperMode, + pAddBssParams->dualCTSProtection, + pAddBssParams->txChannelWidthSet, + pAddBssParams->ch_center_freq_seg0); + + lim_log(pMac, LOG2, FL("llnNonGFCoexist: %d " + "fLsigTXOPProtectionFullSupport: %d fRIFSMode %d"), + pAddBssParams->llnNonGFCoexist, + pAddBssParams->fLsigTXOPProtectionFullSupport, + pAddBssParams->fRIFSMode); + } + } + + pAddBssParams->currentOperChannel = bssDescription->channelId; + lim_log(pMac, LOG2, FL("currentOperChannel %d"), + pAddBssParams->currentOperChannel); + + if (psessionEntry->vhtCapability && + (IS_BSS_VHT_CAPABLE(pBeaconStruct->VHTCaps) || + IS_BSS_VHT_CAPABLE(pBeaconStruct->vendor_vht_ie.VHTCaps))) { + + pAddBssParams->vhtCapable = 1; + if (pBeaconStruct->VHTOperation.present) + vht_oper = &pBeaconStruct->VHTOperation; + else if (pBeaconStruct->vendor_vht_ie.VHTOperation.present) { + vht_oper = &pBeaconStruct->vendor_vht_ie.VHTOperation; + lim_log(pMac, LOG1, + FL("VHT Operation is present in vendor Specfic IE")); + } + + + if ((vht_oper != NULL) && + vht_oper->chanWidth && + chanWidthSupp) { + pAddBssParams->ch_center_freq_seg0 = + vht_oper->chanCenterFreqSeg1; + pAddBssParams->ch_center_freq_seg1 = + vht_oper->chanCenterFreqSeg2; + } + /* + * in limExtractApCapability function intersection of FW + * advertised channel width and AP advertised channel width has + * been taken into account for calculating + * psessionEntry->ch_width + */ + pAddBssParams->ch_width = + psessionEntry->ch_width; + pAddBssParams->staContext.maxAmpduSize = + SIR_MAC_GET_VHT_MAX_AMPDU_EXPO( + pAddBssParams->staContext.vht_caps); + } else { + pAddBssParams->vhtCapable = 0; + } + lim_log(pMac, LOG1, FL("vhtCapable %d vhtTxChannelWidthSet %d center_freq_seg0 - %d, center_freq_seg1 - %d"), + pAddBssParams->vhtCapable, pAddBssParams->ch_width, + pAddBssParams->ch_center_freq_seg0, + pAddBssParams->ch_center_freq_seg1); + + /* + * Populate the STA-related parameters here + * Note that the STA here refers to the AP + */ + /* Identifying AP as an STA */ + pAddBssParams->staContext.staType = STA_ENTRY_OTHER; + + qdf_mem_copy(pAddBssParams->staContext.bssId, + bssDescription->bssId, sizeof(tSirMacAddr)); + pAddBssParams->staContext.listenInterval = + bssDescription->beaconInterval; + + pAddBssParams->staContext.assocId = 0; + pAddBssParams->staContext.uAPSD = 0; + pAddBssParams->staContext.maxSPLen = 0; + pAddBssParams->staContext.shortPreambleSupported = + (uint8_t) pBeaconStruct->capabilityInfo.shortPreamble; + pAddBssParams->staContext.updateSta = updateEntry; + + lim_log(pMac, LOG2, FL( + "StaCtx: " MAC_ADDRESS_STR " shortPreamble: %d"), + MAC_ADDR_ARRAY(pAddBssParams->staContext.staMac), + pAddBssParams->staContext.shortPreambleSupported); + + pAddBssParams->dot11_mode = psessionEntry->dot11mode; + lim_log(pMac, LOG2, FL("dot11_mode:%d"), + pAddBssParams->dot11_mode); + + if (IS_DOT11_MODE_HT(psessionEntry->dot11mode) + && (pBeaconStruct->HTCaps.present)) { + pAddBssParams->staContext.us32MaxAmpduDuration = 0; + pAddBssParams->staContext.htCapable = 1; + pAddBssParams->staContext.greenFieldCapable = + (uint8_t) pBeaconStruct->HTCaps.greenField; + pAddBssParams->staContext.lsigTxopProtection = + (uint8_t) pBeaconStruct->HTCaps.lsigTXOPProtection; + lim_log(pMac, LOG2, FL( + "StaCtx: htCap %d GFCap %d lsigTxopProtn %d"), + pAddBssParams->staContext.htCapable, + pAddBssParams->staContext.greenFieldCapable, + pAddBssParams->staContext.lsigTxopProtection); + if (psessionEntry->vhtCapability && + (IS_BSS_VHT_CAPABLE(pBeaconStruct->VHTCaps) || + IS_BSS_VHT_CAPABLE( + pBeaconStruct->vendor_vht_ie.VHTCaps))) { + pAddBssParams->staContext.vhtCapable = 1; + if (pBeaconStruct->VHTCaps.present) + vht_caps = &pBeaconStruct->VHTCaps; + else if (pBeaconStruct->vendor_vht_ie.VHTCaps.present) + vht_caps = &pBeaconStruct-> + vendor_vht_ie.VHTCaps; + + if ((vht_caps != NULL) && (vht_caps->suBeamFormerCap || + vht_caps->muBeamformerCap) && + psessionEntry->vht_config.su_beam_formee) + pAddBssParams->staContext.vhtTxBFCapable = 1; + + if ((vht_caps != NULL) && vht_caps->muBeamformerCap && + psessionEntry->vht_config.mu_beam_formee) + pAddBssParams->staContext.vhtTxMUBformeeCapable + = 1; + + if ((vht_caps != NULL) && vht_caps->suBeamformeeCap && + psessionEntry->vht_config.su_beam_former) + pAddBssParams->staContext.enable_su_tx_bformer + = 1; + + lim_log(pMac, LOG2, FL("StaContext: su_tx_bfer %d"), + pAddBssParams->staContext.enable_su_tx_bformer); + } + if ((pBeaconStruct->HTCaps.supportedChannelWidthSet) && + (chanWidthSupp)) { + pAddBssParams->staContext.ch_width = + (uint8_t) pBeaconStruct->HTInfo. + recommendedTxWidthSet; + if ((vht_oper != NULL) && + pAddBssParams->staContext.vhtCapable && + vht_oper->chanWidth) + pAddBssParams->staContext.ch_width = + vht_oper->chanWidth + 1; + lim_log(pMac, LOG2, + FL("StaCtx: vhtCap %d ch_bw %d TxBF %d"), + pAddBssParams->staContext.vhtCapable, + pAddBssParams->staContext.ch_width, + pAddBssParams->staContext.vhtTxBFCapable); + } else { + pAddBssParams->staContext.ch_width = + CH_WIDTH_20MHZ; + } + pAddBssParams->staContext.mimoPS = + (tSirMacHTMIMOPowerSaveState) pBeaconStruct->HTCaps. + mimoPowerSave; + pAddBssParams->staContext.maxAmsduSize = + (uint8_t) pBeaconStruct->HTCaps.maximalAMSDUsize; + pAddBssParams->staContext.maxAmpduDensity = + pBeaconStruct->HTCaps.mpduDensity; + pAddBssParams->staContext.fDsssCckMode40Mhz = + (uint8_t) pBeaconStruct->HTCaps.dsssCckMode40MHz; + /* + * We will check gShortGI20Mhz and gShortGI40Mhz from ini file. + * if they are set then we will use what ever Beacon coming + * from AP supports. If these values are set as 0 in ini file + * then we will hardcode this values to 0. + */ + if (true == psessionEntry->htConfig.ht_sgi20) + pAddBssParams->staContext.fShortGI20Mhz = + (uint8_t)pBeaconStruct->HTCaps.shortGI20MHz; + else + pAddBssParams->staContext.fShortGI20Mhz = + false; + + if (true == psessionEntry->htConfig.ht_sgi40) + pAddBssParams->staContext.fShortGI40Mhz = + (uint8_t) pBeaconStruct->HTCaps.shortGI40MHz; + else + pAddBssParams->staContext.fShortGI40Mhz = false; + + pAddBssParams->staContext.maxAmpduSize = + pBeaconStruct->HTCaps.maxRxAMPDUFactor; + if (pAddBssParams->staContext.vhtTxBFCapable + && pMac->lim.disableLDPCWithTxbfAP) { + pAddBssParams->staContext.htLdpcCapable = 0; + pAddBssParams->staContext.vhtLdpcCapable = 0; + } else { + if (psessionEntry->txLdpcIniFeatureEnabled & 0x1) + pAddBssParams->staContext.htLdpcCapable = + (uint8_t) pBeaconStruct->HTCaps. + advCodingCap; + else + pAddBssParams->staContext.htLdpcCapable = 0; + + if (pBeaconStruct->VHTCaps.present) + vht_caps = &pBeaconStruct->VHTCaps; + else if (pBeaconStruct->vendor_vht_ie.VHTCaps.present) { + vht_caps = + &pBeaconStruct->vendor_vht_ie.VHTCaps; + lim_log(pMac, LOG1, FL( + "VHT Caps are in vendor Specfic IE")); + } + if (vht_caps != NULL && + (psessionEntry->txLdpcIniFeatureEnabled & 0x2)) + pAddBssParams->staContext.vhtLdpcCapable = + (uint8_t) vht_caps->ldpcCodingCap; + else + pAddBssParams->staContext.vhtLdpcCapable = 0; + } + + if (pBeaconStruct->HTInfo.present) + pAddBssParams->staContext.rifsMode = + pBeaconStruct->HTInfo.rifsMode; + lim_log(pMac, LOG2, + FL("StaContext ChannelWidth: %d mimoPS: %d maxAmsduSize: %d"), + pAddBssParams->staContext.ch_width, + pAddBssParams->staContext.mimoPS, + pAddBssParams->staContext.maxAmsduSize); + + lim_log(pMac, LOG2, FL( + "maxAmpduDensity %d Cck40Mhz %d SGI20Mhz %d"), + pAddBssParams->staContext.maxAmpduDensity, + pAddBssParams->staContext.fDsssCckMode40Mhz, + pAddBssParams->staContext.fShortGI20Mhz); + + lim_log(pMac, LOG2, FL( + "SGI40M %d maxAmpdu %d htLdpc %d vhtLdpc %d"), + pAddBssParams->staContext.fShortGI40Mhz, + pAddBssParams->staContext.maxAmpduSize, + pAddBssParams->staContext.htLdpcCapable, + pAddBssParams->staContext.vhtLdpcCapable); + } + /* + * If WMM IE or 802.11E IE is not present + * and AP is HT AP then enable WMM + */ + if ((psessionEntry->limWmeEnabled && (pBeaconStruct->wmeEdcaPresent || + pAddBssParams->staContext.htCapable)) || + (psessionEntry->limQosEnabled && + (pBeaconStruct->edcaPresent || + pAddBssParams->staContext.htCapable))) + pAddBssParams->staContext.wmmEnabled = 1; + else + pAddBssParams->staContext.wmmEnabled = 0; + + /* Update the rates */ + lim_populate_peer_rate_set(pMac, + &pAddBssParams->staContext. + supportedRates, + pBeaconStruct->HTCaps.supportedMCSSet, + false, psessionEntry, + &pBeaconStruct->VHTCaps); + + pAddBssParams->staContext.encryptType = psessionEntry->encryptType; + + pAddBssParams->maxTxPower = psessionEntry->maxTxPower; + lim_log(pMac, LOG2, FL("maxTxPower: %d"), pAddBssParams->maxTxPower); + + pAddBssParams->status = QDF_STATUS_SUCCESS; + pAddBssParams->respReqd = true; + + pAddBssParams->staContext.smesessionId = psessionEntry->smeSessionId; + pAddBssParams->staContext.sessionId = psessionEntry->peSessionId; + pAddBssParams->sessionId = psessionEntry->peSessionId; + + pAddBssParams->halPersona = (uint8_t) psessionEntry->pePersona; /* update persona */ + + pAddBssParams->bSpectrumMgtEnabled = psessionEntry->spectrumMgtEnabled; + + pAddBssParams->extSetStaKeyParamValid = 0; + lim_log(pMac, LOG2, FL("extSetStaKeyParamValid: %d"), + pAddBssParams->extSetStaKeyParamValid); + +#ifdef WLAN_FEATURE_11W + if (psessionEntry->limRmfEnabled) { + pAddBssParams->rmfEnabled = 1; + pAddBssParams->staContext.rmfEnabled = 1; + } +#endif + + pAddBssParams->nss = psessionEntry->nss; + lim_log(pMac, LOG2, FL("nss value: %d"), pAddBssParams->nss); + + /* Set a new state for MLME */ + psessionEntry->limMlmState = eLIM_MLM_WT_ADD_BSS_RSP_PREASSOC_STATE; + + MTRACE(mac_trace + (pMac, TRACE_CODE_MLM_STATE, psessionEntry->peSessionId, + psessionEntry->limMlmState)); + + lim_log(pMac, LOG2, FL("staContext wmmEnabled: %d encryptType: %d " + "p2pCapableSta: %d"), + pAddBssParams->staContext.wmmEnabled, + pAddBssParams->staContext.encryptType, + pAddBssParams->staContext.p2pCapableSta); + + lim_log(pMac, LOG2, FL("bSpectrumMgtEnabled: %d halPersona: %d setting " + "LimMlm state to %d"), + pAddBssParams->bSpectrumMgtEnabled, pAddBssParams->halPersona, + psessionEntry->limMlmState); + + /* we need to defer the message until we get the response back from HAL. */ + SET_LIM_PROCESS_DEFD_MESGS(pMac, false); + + if (cds_is_5_mhz_enabled()) { + pAddBssParams->ch_width = CH_WIDTH_5MHZ; + pAddBssParams->staContext.ch_width = CH_WIDTH_5MHZ; + } else if (cds_is_10_mhz_enabled()) { + pAddBssParams->ch_width = CH_WIDTH_10MHZ; + pAddBssParams->staContext.ch_width = CH_WIDTH_10MHZ; + } + + msgQ.type = WMA_ADD_BSS_REQ; + /** @ToDo : Update the Global counter to keeptrack of the PE <--> HAL messages*/ + msgQ.reserved = 0; + msgQ.bodyptr = pAddBssParams; + msgQ.bodyval = 0; + + lim_log(pMac, LOG1, FL("SessionId:%d Sending WMA_ADD_BSS_REQ"), + psessionEntry->peSessionId); + MTRACE(mac_trace_msg_tx(pMac, psessionEntry->peSessionId, msgQ.type)); + + retCode = wma_post_ctrl_msg(pMac, &msgQ); + if (eSIR_SUCCESS != retCode) { + SET_LIM_PROCESS_DEFD_MESGS(pMac, true); + qdf_mem_free(pAddBssParams); + lim_log(pMac, LOGE, + FL("Posting ADD_BSS_REQ to HAL failed, reason=%X"), + retCode); + goto returnFailure; + + } else { + qdf_mem_free(pBeaconStruct); + return retCode; + } + +returnFailure: + /* Clean-up will be done by the caller... */ + qdf_mem_free(pBeaconStruct); + return retCode; +} + +/** + * lim_prepare_and_send_del_sta_cnf() - prepares and send del sta cnf + * + * @pMac: mac global context + * @pStaDs: sta dph node + * @statusCode: status code + * @psessionEntry: session context + * + * deletes DPH entry, changes the MLM mode for station, calls + * lim_send_del_sta_cnf + * + * Return: void + */ +void +lim_prepare_and_send_del_sta_cnf(tpAniSirGlobal pMac, tpDphHashNode pStaDs, + tSirResultCodes statusCode, + tpPESession psessionEntry) +{ + uint16_t staDsAssocId = 0; + struct qdf_mac_addr sta_dsaddr; + tLimMlmStaContext mlmStaContext; + + if (pStaDs == NULL) { + PELOGW(lim_log(pMac, LOGW, FL("pStaDs is NULL"));) + return; + } + staDsAssocId = pStaDs->assocId; + qdf_mem_copy((uint8_t *) sta_dsaddr.bytes, + pStaDs->staAddr, QDF_MAC_ADDR_SIZE); + + mlmStaContext = pStaDs->mlmStaContext; + if (LIM_IS_AP_ROLE(psessionEntry)) + lim_release_peer_idx(pMac, pStaDs->assocId, psessionEntry); + + lim_delete_dph_hash_entry(pMac, pStaDs->staAddr, pStaDs->assocId, + psessionEntry); + + if (LIM_IS_STA_ROLE(psessionEntry)) { + psessionEntry->limMlmState = eLIM_MLM_IDLE_STATE; + MTRACE(mac_trace(pMac, TRACE_CODE_MLM_STATE, + psessionEntry->peSessionId, + psessionEntry->limMlmState)); + } + lim_send_del_sta_cnf(pMac, sta_dsaddr, staDsAssocId, mlmStaContext, + statusCode, psessionEntry); +} + +/** ------------------------------------------------------------- + \fn lim_init_pre_auth_timer_table + \brief Initialize the Pre Auth Tanle and creates the timer for + each node for the timeout value got from cfg. + \param tpAniSirGlobal pMac + \param tpLimPreAuthTable pPreAuthTimerTable + \return none + -------------------------------------------------------------*/ +void lim_init_pre_auth_timer_table(tpAniSirGlobal pMac, + tpLimPreAuthTable pPreAuthTimerTable) +{ + uint32_t cfgValue; + uint32_t authNodeIdx; + tLimPreAuthNode **pAuthNode = pPreAuthTimerTable->pTable; + + /* Get AUTH_RSP Timers value */ + + if (wlan_cfg_get_int(pMac, WNI_CFG_AUTHENTICATE_RSP_TIMEOUT, + &cfgValue) != eSIR_SUCCESS) { + /* + ** Could not get AUTH_RSP timeout value + ** from CFG. Log error. + **/ + lim_log(pMac, LOGP, + FL("could not retrieve AUTH_RSP timeout value")); + return; + } + + cfgValue = SYS_MS_TO_TICKS(cfgValue); + for (authNodeIdx = 0; authNodeIdx < pPreAuthTimerTable->numEntry; + authNodeIdx++) { + if (tx_timer_create(pMac, &(pAuthNode[authNodeIdx]->timer), + "AUTH RESPONSE TIMEOUT", + lim_auth_response_timer_handler, authNodeIdx, + cfgValue, 0, TX_NO_ACTIVATE) != TX_SUCCESS) { + /* Cannot create timer. Log error. */ + lim_log(pMac, LOGP, + FL("Cannot create Auth Rsp timer of Index :%d."), + authNodeIdx); + return; + } + pAuthNode[authNodeIdx]->authNodeIdx = (uint8_t) authNodeIdx; + pAuthNode[authNodeIdx]->fFree = 1; + } +} + +/** ------------------------------------------------------------- + \fn lim_acquire_free_pre_auth_node + \brief Retrives a free Pre Auth node from Pre Auth Table. + \param tpAniSirGlobal pMac + \param tpLimPreAuthTable pPreAuthTimerTable + \return none + -------------------------------------------------------------*/ +tLimPreAuthNode *lim_acquire_free_pre_auth_node(tpAniSirGlobal pMac, + tpLimPreAuthTable pPreAuthTimerTable) +{ + uint32_t i; + tLimPreAuthNode **pTempNode = pPreAuthTimerTable->pTable; + for (i = 0; i < pPreAuthTimerTable->numEntry; i++) { + if (pTempNode[i]->fFree == 1) { + pTempNode[i]->fFree = 0; + return pTempNode[i]; + } + } + + return NULL; +} + +/** ------------------------------------------------------------- + \fn lim_get_pre_auth_node_from_index + \brief Depending on the Index this retrives the pre auth node. + \param tpAniSirGlobal pMac + \param tpLimPreAuthTable pAuthTable + \param uint32_t authNodeIdx + \return none + -------------------------------------------------------------*/ +tLimPreAuthNode *lim_get_pre_auth_node_from_index(tpAniSirGlobal pMac, + tpLimPreAuthTable pAuthTable, + uint32_t authNodeIdx) +{ + if ((authNodeIdx >= pAuthTable->numEntry) + || (pAuthTable->pTable == NULL)) { + lim_log(pMac, LOGE, + FL("Invalid Auth Timer Index : %d NumEntry : %d"), + authNodeIdx, pAuthTable->numEntry); + return NULL; + } + + return pAuthTable->pTable[authNodeIdx]; +} + +/* Util API to check if the channels supported by STA is within range */ +tSirRetStatus lim_is_dot11h_supported_channels_valid(tpAniSirGlobal pMac, + tSirAssocReq *assoc) +{ + /* + * Allow all the stations to join with us. + * 802.11h-2003 11.6.1 => An AP may use the supported channels list for associated STAs + * as an input into an algorithm used to select a new channel for the BSS. + * The specification of the algorithm is beyond the scope of this amendment. + */ + + return eSIR_SUCCESS; +} + +/* Util API to check if the txpower supported by STA is within range */ +tSirRetStatus lim_is_dot11h_power_capabilities_in_range(tpAniSirGlobal pMac, + tSirAssocReq *assoc, + tpPESession psessionEntry) +{ + int8_t localMaxTxPower; + uint32_t localPwrConstraint; + + localMaxTxPower = + cfg_get_regulatory_max_transmit_power(pMac, + psessionEntry->currentOperChannel); + + if (wlan_cfg_get_int + (pMac, WNI_CFG_LOCAL_POWER_CONSTRAINT, + &localPwrConstraint) != eSIR_SUCCESS) { + lim_log(pMac, LOGP, + FL("Unable to get Local Power Constraint from cfg")); + return eSIR_FAILURE; + } + localMaxTxPower -= (int8_t) localPwrConstraint; + + /** + * The min Tx Power of the associating station should not be greater than (regulatory + * max tx power - local power constraint configured on AP). + */ + if (assoc->powerCapability.minTxPower > localMaxTxPower) { + lim_log(pMac, LOGW, + FL("minTxPower (STA) = %d, localMaxTxPower (AP) = %d"), + assoc->powerCapability.minTxPower, localMaxTxPower); + return eSIR_FAILURE; + } + + return eSIR_SUCCESS; +} + +/** ------------------------------------------------------------- + \fn lim_fill_rx_highest_supported_rate + \brief Fills in the Rx Highest Supported Data Rate field from + \ the 'supported MCS set' field in HT capability element. + \param tpAniSirGlobal pMac + \param tpSirSupportedRates pRates + \param uint8_t* pSupportedMCSSet + \return none + -------------------------------------------------------------*/ +void lim_fill_rx_highest_supported_rate(tpAniSirGlobal pMac, + uint16_t *rxHighestRate, + uint8_t *pSupportedMCSSet) +{ + tSirMacRxHighestSupportRate *pRxHighestRate; + uint8_t *pBuf; + uint16_t rate = 0; + + pBuf = pSupportedMCSSet + MCS_RX_HIGHEST_SUPPORTED_RATE_BYTE_OFFSET; + rate = lim_get_u16(pBuf); + + pRxHighestRate = (tSirMacRxHighestSupportRate *) &rate; + *rxHighestRate = pRxHighestRate->rate; + + return; +} + +#ifdef WLAN_FEATURE_11W +/** ------------------------------------------------------------- + \fn lim_send_sme_unprotected_mgmt_frame_ind + \brief Forwards the unprotected management frame to SME. + \param tpAniSirGlobal pMac + \param frameType - 802.11 frame type + \param frame - frame buffer + \param sessionId - id for the current session + \param psessionEntry - PE session context + \return none + -------------------------------------------------------------*/ +void lim_send_sme_unprotected_mgmt_frame_ind(tpAniSirGlobal pMac, uint8_t frameType, + uint8_t *frame, uint32_t frameLen, + uint16_t sessionId, + tpPESession psessionEntry) +{ + tSirMsgQ mmhMsg; + tSirSmeUnprotMgmtFrameInd *pSirSmeMgmtFrame = NULL; + uint16_t length; + + length = sizeof(tSirSmeUnprotMgmtFrameInd) + frameLen; + + pSirSmeMgmtFrame = qdf_mem_malloc(length); + if (NULL == pSirSmeMgmtFrame) { + lim_log(pMac, LOGP, + FL + ("AllocateMemory failed for tSirSmeUnprotectedMgmtFrameInd")); + return; + } + + pSirSmeMgmtFrame->sessionId = sessionId; + pSirSmeMgmtFrame->frameType = frameType; + + qdf_mem_copy(pSirSmeMgmtFrame->frameBuf, frame, frameLen); + pSirSmeMgmtFrame->frameLen = frameLen; + + mmhMsg.type = eWNI_SME_UNPROT_MGMT_FRM_IND; + mmhMsg.bodyptr = pSirSmeMgmtFrame; + mmhMsg.bodyval = 0; + + lim_sys_process_mmh_msg_api(pMac, &mmhMsg, ePROT); + return; +} +#endif + +#ifdef FEATURE_WLAN_ESE +/** ------------------------------------------------------------- + \fn lim_send_sme_tsm_ie_ind + \brief Forwards the TSM IE information to SME. + \param tpAniSirGlobal pMac + \param psessionEntry - PE session context + \param tid - traffic id + \param state - tsm state (enabled/disabled) + \param measurementInterval - measurement interval + \return none + -------------------------------------------------------------*/ +void lim_send_sme_tsm_ie_ind(tpAniSirGlobal pMac, tpPESession psessionEntry, + uint8_t tid, uint8_t state, uint16_t measInterval) +{ + tSirMsgQ mmhMsg; + tpSirSmeTsmIEInd pSirSmeTsmIeInd = NULL; + + if (!pMac || !psessionEntry) + return; + + pSirSmeTsmIeInd = qdf_mem_malloc(sizeof(tSirSmeTsmIEInd)); + if (NULL == pSirSmeTsmIeInd) { + lim_log(pMac, LOGP, + FL("AllocateMemory failed for tSirSmeTsmIEInd")); + return; + } + + pSirSmeTsmIeInd->sessionId = psessionEntry->smeSessionId; + pSirSmeTsmIeInd->tsmIe.tsid = tid; + pSirSmeTsmIeInd->tsmIe.state = state; + pSirSmeTsmIeInd->tsmIe.msmt_interval = measInterval; + + mmhMsg.type = eWNI_SME_TSM_IE_IND; + mmhMsg.bodyptr = pSirSmeTsmIeInd; + mmhMsg.bodyval = 0; + + lim_sys_process_mmh_msg_api(pMac, &mmhMsg, ePROT); + return; +} +#endif /* FEATURE_WLAN_ESE */ diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_assoc_utils.h b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_assoc_utils.h new file mode 100644 index 0000000000000000000000000000000000000000..80f12be984a0fa4bd99c5f77d37afa8f5ad21348 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_assoc_utils.h @@ -0,0 +1,228 @@ +/* + * Copyright (c) 2011-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * This file lim_assoc_utils.h contains the utility definitions + * LIM uses while processing Re/Association messages. + * Author: Chandra Modumudi + * Date: 02/13/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + * 05/26/10 js WPA handling in (Re)Assoc frames + * + */ +#ifndef __LIM_ASSOC_UTILS_H +#define __LIM_ASSOC_UTILS_H + +#include "sir_api.h" +#include "sir_debug.h" +#include "cfg_api.h" + +#include "lim_types.h" + +uint32_t lim_cmp_ssid(tSirMacSSid *, tpPESession); +uint8_t lim_compare_capabilities(tpAniSirGlobal, + tSirAssocReq *, + tSirMacCapabilityInfo *, tpPESession); +uint8_t lim_check_rx_basic_rates(tpAniSirGlobal, tSirMacRateSet, tpPESession); +uint8_t lim_check_rx_rsn_ie_match(tpAniSirGlobal, tDot11fIERSN, tpPESession, uint8_t, + bool *); +uint8_t lim_check_rx_wpa_ie_match(tpAniSirGlobal, tDot11fIEWPA, tpPESession, + uint8_t); +uint8_t lim_check_mcs_set(tpAniSirGlobal pMac, uint8_t *supportedMCSSet); +void limPostDummyToTmRing(tpAniSirGlobal, tpDphHashNode); +void limPostPacketToTdRing(tpAniSirGlobal, tpDphHashNode, uint8_t); +tSirRetStatus lim_cleanup_rx_path(tpAniSirGlobal, tpDphHashNode, tpPESession); +void lim_reject_association(tpAniSirGlobal, tSirMacAddr, uint8_t, + uint8_t, tAniAuthType, + uint16_t, uint8_t, tSirResultCodes, tpPESession); + +tSirRetStatus lim_populate_peer_rate_set(tpAniSirGlobal pMac, + tpSirSupportedRates pRates, + uint8_t *pSupportedMCSSet, + uint8_t basicOnly, + tpPESession psessionEntry, + tDot11fIEVHTCaps * pVHTCaps); + +tSirRetStatus lim_populate_own_rate_set(tpAniSirGlobal pMac, + tpSirSupportedRates pRates, + uint8_t *pSupportedMCSSet, + uint8_t basicOnly, + tpPESession psessionEntry, + tDot11fIEVHTCaps * pVHTCaps); + +tSirRetStatus +lim_populate_matching_rate_set(tpAniSirGlobal pMac, + tpDphHashNode pStaDs, + tSirMacRateSet *pOperRateSet, + tSirMacRateSet *pExtRateSet, + uint8_t *pSupportedMCSSet, + tpPESession psessionEntry, + tDot11fIEVHTCaps * pVHTCaps); + +#define MCSMAPMASK1x1 0x3 +#define MCSMAPMASK2x2 0xC + +tSirRetStatus lim_add_sta(tpAniSirGlobal, tpDphHashNode, uint8_t, tpPESession); +tSirRetStatus lim_del_bss(tpAniSirGlobal, tpDphHashNode, uint16_t, tpPESession); +tSirRetStatus lim_del_sta(tpAniSirGlobal, tpDphHashNode, bool, tpPESession); +tSirRetStatus lim_add_sta_self(tpAniSirGlobal, uint16_t, uint8_t, tpPESession); + +void lim_teardown_infra_bss(tpAniSirGlobal, tpPESession); +#ifdef WLAN_FEATURE_HOST_ROAM +void lim_restore_pre_reassoc_state(tpAniSirGlobal, + tSirResultCodes, uint16_t, tpPESession); +void lim_post_reassoc_failure(tpAniSirGlobal, + tSirResultCodes, uint16_t, tpPESession); +bool lim_is_reassoc_in_progress(tpAniSirGlobal, tpPESession); + +void lim_handle_add_bss_in_re_assoc_context(tpAniSirGlobal pMac, + tpDphHashNode pStaDs, tpPESession psessionEntry); +void lim_handle_del_bss_in_re_assoc_context(tpAniSirGlobal pMac, + tpDphHashNode pStaDs, tpPESession psessionEntry); +void lim_send_retry_reassoc_req_frame(tpAniSirGlobal pMac, + tLimMlmReassocReq *pMlmReassocReq, tpPESession psessionEntry); +tSirRetStatus lim_add_ft_sta_self(tpAniSirGlobal pMac, uint16_t assocId, + tpPESession psessionEntry); +#else +static inline void lim_restore_pre_reassoc_state(tpAniSirGlobal mac_ctx, + tSirResultCodes res_code, uint16_t prot_status, + tpPESession pe_session) +{} +static inline void lim_post_reassoc_failure(tpAniSirGlobal mac_ctx, + tSirResultCodes res_code, uint16_t prot_status, + tpPESession pe_session) +{} +static inline void lim_handle_add_bss_in_re_assoc_context(tpAniSirGlobal pMac, + tpDphHashNode pStaDs, tpPESession psessionEntry) +{} +static inline void lim_handle_del_bss_in_re_assoc_context(tpAniSirGlobal pMac, + tpDphHashNode pStaDs, tpPESession psessionEntry) +{} +static inline void lim_send_retry_reassoc_req_frame(tpAniSirGlobal pMac, + tLimMlmReassocReq *pMlmReassocReq, tpPESession psessionEntry) +{} +static inline bool lim_is_reassoc_in_progress(tpAniSirGlobal mac_ctx, + tpPESession pe_session) +{ + return false; +} +static inline tSirRetStatus lim_add_ft_sta_self(tpAniSirGlobal pMac, + uint16_t assocId, tpPESession psessionEntry) +{ + return eSIR_SUCCESS; +} +#endif + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +static inline bool lim_is_roam_synch_in_progress(tpPESession pe_session) +{ + return pe_session->bRoamSynchInProgress; +} +#else +static inline bool lim_is_roam_synch_in_progress(tpPESession pe_session) +{ + return false; +} +#endif + +void +lim_send_del_sta_cnf(tpAniSirGlobal pMac, struct qdf_mac_addr sta_dsaddr, + uint16_t staDsAssocId, tLimMlmStaContext mlmStaContext, + tSirResultCodes statusCode, tpPESession psessionEntry); + +void lim_handle_cnf_wait_timeout(tpAniSirGlobal pMac, uint16_t staId); +void lim_delete_dph_hash_entry(tpAniSirGlobal, tSirMacAddr, uint16_t, tpPESession); +void lim_check_and_announce_join_success(tpAniSirGlobal, + tSirProbeRespBeacon *, + tpSirMacMgmtHdr, tpPESession); +void lim_update_re_assoc_globals(tpAniSirGlobal pMac, + tpSirAssocRsp pAssocRsp, + tpPESession psessionEntry); + +void lim_update_assoc_sta_datas(tpAniSirGlobal pMac, + tpDphHashNode pStaDs, tpSirAssocRsp pAssocRsp, + tpPESession psessionEntry); + +tSirRetStatus lim_sta_send_add_bss(tpAniSirGlobal pMac, tpSirAssocRsp pAssocRsp, + tpSchBeaconStruct pBeaconStruct, + tpSirBssDescription bssDescription, + uint8_t updateEntry, tpPESession psessionEntry); +tSirRetStatus lim_sta_send_add_bss_pre_assoc(tpAniSirGlobal pMac, uint8_t updateEntry, + tpPESession psessionEntry); + +void lim_prepare_and_send_del_sta_cnf(tpAniSirGlobal pMac, tpDphHashNode pStaDs, + tSirResultCodes statusCode, tpPESession); +tSirRetStatus lim_extract_ap_capabilities(tpAniSirGlobal pMac, uint8_t *pIE, + uint16_t ieLen, + tpSirProbeRespBeacon beaconStruct); +void lim_init_pre_auth_timer_table(tpAniSirGlobal pMac, + tpLimPreAuthTable pPreAuthTimerTable); +tpLimPreAuthNode lim_acquire_free_pre_auth_node(tpAniSirGlobal pMac, + tpLimPreAuthTable + pPreAuthTimerTable); +tpLimPreAuthNode lim_get_pre_auth_node_from_index(tpAniSirGlobal pMac, + tpLimPreAuthTable pAuthTable, + uint32_t authNodeIdx); + +/* Util API to check if the channels supported by STA is within range */ +tSirRetStatus lim_is_dot11h_supported_channels_valid(tpAniSirGlobal pMac, + tSirAssocReq *assoc); + +/* Util API to check if the txpower supported by STA is within range */ +tSirRetStatus lim_is_dot11h_power_capabilities_in_range(tpAniSirGlobal pMac, + tSirAssocReq *assoc, + tpPESession); +/* API to fill in RX Highest Supported data Rate */ +void lim_fill_rx_highest_supported_rate(tpAniSirGlobal pMac, + uint16_t *rxHighestRate, + uint8_t *pSupportedMCSSet); +#ifdef WLAN_FEATURE_11W +void lim_send_sme_unprotected_mgmt_frame_ind(tpAniSirGlobal pMac, uint8_t frameType, + uint8_t *frame, uint32_t frameLen, + uint16_t sessionId, + tpPESession psessionEntry); +#endif + +#ifdef FEATURE_WLAN_ESE +void lim_send_sme_tsm_ie_ind(tpAniSirGlobal pMac, tpPESession psessionEntry, + uint8_t tid, uint8_t state, uint16_t measInterval); +#else +static inline void lim_send_sme_tsm_ie_ind(tpAniSirGlobal pMac, + tpPESession psessionEntry, uint8_t tid, + uint8_t state, uint16_t measInterval) +{} +#endif /* FEATURE_WLAN_ESE */ + +tSirRetStatus lim_populate_vht_mcs_set(tpAniSirGlobal pMac, + tpSirSupportedRates pRates, + tDot11fIEVHTCaps *pPeerVHTCaps, + tpPESession psessionEntry, + uint8_t nss); + +#endif /* __LIM_ASSOC_UTILS_H */ diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_debug.c b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_debug.c new file mode 100644 index 0000000000000000000000000000000000000000..51620d78bf9dcc3ef10681b4dd7676b08fe5183d --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_debug.c @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/**========================================================================= + + \file lim_debug.c + + \brief implementation for log Debug related APIs + + \author Sunit Bhatia + + ========================================================================*/ + +#include "lim_debug.h" + +void lim_log(tpAniSirGlobal pMac, uint32_t loglevel, const char *pString, ...) +{ +#ifdef WLAN_DEBUG + /* Verify against current log level */ + if (loglevel > + pMac->utils.gLogDbgLevel[LOG_INDEX_FOR_MODULE(SIR_LIM_MODULE_ID)]) + return; + else { + va_list marker; + + va_start(marker, pString); /* Initialize variable arguments. */ + + log_debug(pMac, SIR_LIM_MODULE_ID, loglevel, pString, marker); + + va_end(marker); /* Reset variable arguments. */ + } +#endif +} diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_debug.h b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_debug.h new file mode 100644 index 0000000000000000000000000000000000000000..e0ab7f6251f199df443431bcfb5a7e350a0ba4ad --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_debug.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2011-2012, 2014-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * This file lim_debug.h contains log function called by LIM module. + * + * Author: Chandra Modumudi + * Date: 02/11/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + * + */ + +#ifndef __LIM_DEBUG_H__ +#define __LIM_DEBUG_H__ + +#include "utils_api.h" +#include "sir_debug.h" + +#if !defined(__printf) +#define __printf(a, b) +#endif + +void __printf(3, 4) lim_log(tpAniSirGlobal pMac, uint32_t loglevel, + const char *pString, ...); + +/* define this to show more message in the LIM during TDLS development */ +#define LIM_DEBUG_TDLS + +#ifdef LIM_DEBUG_TDLS +#define LIM_LOG_TDLS(x0) x0 +#else +#define LIM_LOG_TDLS(x0) +#endif + +#endif diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_ft.c b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_ft.c new file mode 100644 index 0000000000000000000000000000000000000000..89626c7d1026ecd90713b11aae37fa6671118648 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_ft.c @@ -0,0 +1,1080 @@ +/* + * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/**========================================================================= + + \brief implementation for PE 11r VoWiFi FT Protocol + + ========================================================================*/ + +/* $Header$ */ + +/*-------------------------------------------------------------------------- + Include Files + ------------------------------------------------------------------------*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "wmm_apsd.h" +#include "wma.h" + +extern void lim_send_set_sta_key_req(tpAniSirGlobal pMac, + tLimMlmSetKeysReq * pMlmSetKeysReq, + uint16_t staIdx, + uint8_t defWEPIdx, + tpPESession sessionEntry, bool sendRsp); + +/*-------------------------------------------------------------------------- + Initialize the FT variables. + ------------------------------------------------------------------------*/ +void lim_ft_open(tpAniSirGlobal pMac, tpPESession psessionEntry) +{ + if (psessionEntry) + qdf_mem_set(&psessionEntry->ftPEContext, sizeof(tftPEContext), + 0); +} + +void lim_ft_cleanup_all_ft_sessions(tpAniSirGlobal pMac) +{ + /* Wrapper function to cleanup all FT sessions */ + int i; + + for (i = 0; i < pMac->lim.maxBssId; i++) { + if (true == pMac->lim.gpSession[i].valid) { + /* The session is valid, may have FT data */ + lim_ft_cleanup(pMac, &pMac->lim.gpSession[i]); + } + } +} + +void lim_ft_cleanup(tpAniSirGlobal pMac, tpPESession psessionEntry) +{ + if (NULL == psessionEntry) { + PELOGE(lim_log(pMac, LOGE, FL("psessionEntry is NULL"));) + return; + } + + /* Nothing to be done if the session is not in STA mode */ + if (!LIM_IS_STA_ROLE(psessionEntry)) { + lim_log(pMac, LOGE, FL("psessionEntry is not in STA mode")); + return; + } + + if (NULL != psessionEntry->ftPEContext.pFTPreAuthReq) { + lim_log(pMac, LOG1, FL("Freeing pFTPreAuthReq= %p"), + psessionEntry->ftPEContext.pFTPreAuthReq); + if (NULL != + psessionEntry->ftPEContext.pFTPreAuthReq-> + pbssDescription) { + qdf_mem_free(psessionEntry->ftPEContext.pFTPreAuthReq-> + pbssDescription); + psessionEntry->ftPEContext.pFTPreAuthReq-> + pbssDescription = NULL; + } + qdf_mem_free(psessionEntry->ftPEContext.pFTPreAuthReq); + psessionEntry->ftPEContext.pFTPreAuthReq = NULL; + } + + if (psessionEntry->ftPEContext.pAddBssReq) { + qdf_mem_free(psessionEntry->ftPEContext.pAddBssReq); + psessionEntry->ftPEContext.pAddBssReq = NULL; + } + + if (psessionEntry->ftPEContext.pAddStaReq) { + qdf_mem_free(psessionEntry->ftPEContext.pAddStaReq); + psessionEntry->ftPEContext.pAddStaReq = NULL; + } + + /* The session is being deleted, cleanup the contents */ + qdf_mem_set(&psessionEntry->ftPEContext, sizeof(tftPEContext), 0); +} + +#if defined(WLAN_FEATURE_HOST_ROAM) || defined(WLAN_FEATURE_ROAM_OFFLOAD) +/*------------------------------------------------------------------ + * + * Create the new Add Bss Req to the new AP. + * This will be used when we are ready to FT to the new AP. + * The newly created ft Session entry is passed to this function + * + *------------------------------------------------------------------*/ +void lim_ft_prepare_add_bss_req(tpAniSirGlobal pMac, + uint8_t updateEntry, tpPESession pftSessionEntry, + tpSirBssDescription bssDescription) +{ + tpAddBssParams pAddBssParams = NULL; + tAddStaParams *sta_ctx; + uint8_t chanWidthSupp = 0; + tSchBeaconStruct *pBeaconStruct; + + /* Nothing to be done if the session is not in STA mode */ + if (!LIM_IS_STA_ROLE(pftSessionEntry)) { + lim_log(pMac, LOGE, FL("psessionEntry is not in STA mode")); + return; + } + + pBeaconStruct = qdf_mem_malloc(sizeof(tSchBeaconStruct)); + if (NULL == pBeaconStruct) { + lim_log(pMac, LOGE, + FL("Unable to allocate memory for creating ADD_BSS")); + return; + } + /* Package SIR_HAL_ADD_BSS_REQ message parameters */ + pAddBssParams = qdf_mem_malloc(sizeof(tAddBssParams)); + if (NULL == pAddBssParams) { + qdf_mem_free(pBeaconStruct); + lim_log(pMac, LOGP, + FL("Unable to allocate memory for creating ADD_BSS")); + return; + } + + lim_extract_ap_capabilities(pMac, (uint8_t *) bssDescription->ieFields, + lim_get_ielen_from_bss_description(bssDescription), + pBeaconStruct); + + if (pMac->lim.gLimProtectionControl != + WNI_CFG_FORCE_POLICY_PROTECTION_DISABLE) + lim_decide_sta_protection_on_assoc(pMac, pBeaconStruct, + pftSessionEntry); + + qdf_mem_copy(pAddBssParams->bssId, bssDescription->bssId, + sizeof(tSirMacAddr)); + + /* Fill in tAddBssParams selfMacAddr */ + qdf_mem_copy(pAddBssParams->selfMacAddr, pftSessionEntry->selfMacAddr, + sizeof(tSirMacAddr)); + + pAddBssParams->bssType = pftSessionEntry->bssType; + pAddBssParams->operMode = BSS_OPERATIONAL_MODE_STA; + + pAddBssParams->beaconInterval = bssDescription->beaconInterval; + + pAddBssParams->dtimPeriod = pBeaconStruct->tim.dtimPeriod; + pAddBssParams->updateBss = updateEntry; + + pAddBssParams->reassocReq = true; + + pAddBssParams->cfParamSet.cfpCount = pBeaconStruct->cfParamSet.cfpCount; + pAddBssParams->cfParamSet.cfpPeriod = + pBeaconStruct->cfParamSet.cfpPeriod; + pAddBssParams->cfParamSet.cfpMaxDuration = + pBeaconStruct->cfParamSet.cfpMaxDuration; + pAddBssParams->cfParamSet.cfpDurRemaining = + pBeaconStruct->cfParamSet.cfpDurRemaining; + + pAddBssParams->rateSet.numRates = + pBeaconStruct->supportedRates.numRates; + qdf_mem_copy(pAddBssParams->rateSet.rate, + pBeaconStruct->supportedRates.rate, + pBeaconStruct->supportedRates.numRates); + + pAddBssParams->nwType = bssDescription->nwType; + + pAddBssParams->shortSlotTimeSupported = + (uint8_t) pBeaconStruct->capabilityInfo.shortSlotTime; + pAddBssParams->llaCoexist = + (uint8_t) pftSessionEntry->beaconParams.llaCoexist; + pAddBssParams->llbCoexist = + (uint8_t) pftSessionEntry->beaconParams.llbCoexist; + pAddBssParams->llgCoexist = + (uint8_t) pftSessionEntry->beaconParams.llgCoexist; + pAddBssParams->ht20Coexist = + (uint8_t) pftSessionEntry->beaconParams.ht20Coexist; +#ifdef WLAN_FEATURE_11W + pAddBssParams->rmfEnabled = pftSessionEntry->limRmfEnabled; +#endif + + /* Use the advertised capabilities from the received beacon/PR */ + if (IS_DOT11_MODE_HT(pftSessionEntry->dot11mode) && + (pBeaconStruct->HTCaps.present)) { + pAddBssParams->htCapable = pBeaconStruct->HTCaps.present; + qdf_mem_copy(&pAddBssParams->staContext.capab_info, + &pBeaconStruct->capabilityInfo, + sizeof(pAddBssParams->staContext.capab_info)); + qdf_mem_copy(&pAddBssParams->staContext.ht_caps, + (uint8_t *) &pBeaconStruct->HTCaps + + sizeof(uint8_t), + sizeof(pAddBssParams->staContext.ht_caps)); + + if (pBeaconStruct->HTInfo.present) { + pAddBssParams->htOperMode = + (tSirMacHTOperatingMode) pBeaconStruct->HTInfo. + opMode; + pAddBssParams->dualCTSProtection = + (uint8_t) pBeaconStruct->HTInfo.dualCTSProtection; + + chanWidthSupp = lim_get_ht_capability(pMac, + eHT_SUPPORTED_CHANNEL_WIDTH_SET, + pftSessionEntry); + if ((pBeaconStruct->HTCaps.supportedChannelWidthSet) && + (chanWidthSupp)) { + pAddBssParams->ch_width = (uint8_t) + pBeaconStruct->HTInfo.recommendedTxWidthSet; + if (pBeaconStruct->HTInfo.secondaryChannelOffset == + PHY_DOUBLE_CHANNEL_LOW_PRIMARY) + pAddBssParams->ch_center_freq_seg0 = + bssDescription->channelId + 2; + else if (pBeaconStruct->HTInfo.secondaryChannelOffset == + PHY_DOUBLE_CHANNEL_HIGH_PRIMARY) + pAddBssParams->ch_center_freq_seg0 = + bssDescription->channelId - 2; + } else { + pAddBssParams->ch_width = CH_WIDTH_20MHZ; + pAddBssParams->ch_center_freq_seg0 = 0; + } + pAddBssParams->llnNonGFCoexist = + (uint8_t) pBeaconStruct->HTInfo.nonGFDevicesPresent; + pAddBssParams->fLsigTXOPProtectionFullSupport = + (uint8_t) pBeaconStruct->HTInfo. + lsigTXOPProtectionFullSupport; + pAddBssParams->fRIFSMode = + pBeaconStruct->HTInfo.rifsMode; + } + } + + pAddBssParams->currentOperChannel = bssDescription->channelId; + pftSessionEntry->htSecondaryChannelOffset = + pBeaconStruct->HTInfo.secondaryChannelOffset; + sta_ctx = &pAddBssParams->staContext; + + if (pftSessionEntry->vhtCapability && + pftSessionEntry->vhtCapabilityPresentInBeacon) { + pAddBssParams->vhtCapable = pBeaconStruct->VHTCaps.present; + if (pBeaconStruct->VHTOperation.chanWidth && chanWidthSupp) { + pAddBssParams->ch_width = + pBeaconStruct->VHTOperation.chanWidth + 1; + pAddBssParams->ch_center_freq_seg0 = + pBeaconStruct->VHTOperation.chanCenterFreqSeg1; + pAddBssParams->ch_center_freq_seg1 = + pBeaconStruct->VHTOperation.chanCenterFreqSeg2; + } + pAddBssParams->staContext.vht_caps = + ((pBeaconStruct->VHTCaps.maxMPDULen << + SIR_MAC_VHT_CAP_MAX_MPDU_LEN) | + (pBeaconStruct->VHTCaps.supportedChannelWidthSet << + SIR_MAC_VHT_CAP_SUPP_CH_WIDTH_SET) | + (pBeaconStruct->VHTCaps.ldpcCodingCap << + SIR_MAC_VHT_CAP_LDPC_CODING_CAP) | + (pBeaconStruct->VHTCaps.shortGI80MHz << + SIR_MAC_VHT_CAP_SHORTGI_80MHZ) | + (pBeaconStruct->VHTCaps.shortGI160and80plus80MHz << + SIR_MAC_VHT_CAP_SHORTGI_160_80_80MHZ) | + (pBeaconStruct->VHTCaps.txSTBC << + SIR_MAC_VHT_CAP_TXSTBC) | + (pBeaconStruct->VHTCaps.rxSTBC << + SIR_MAC_VHT_CAP_RXSTBC) | + (pBeaconStruct->VHTCaps.suBeamFormerCap << + SIR_MAC_VHT_CAP_SU_BEAMFORMER_CAP) | + (pBeaconStruct->VHTCaps.suBeamformeeCap << + SIR_MAC_VHT_CAP_SU_BEAMFORMEE_CAP) | + (pBeaconStruct->VHTCaps.csnofBeamformerAntSup << + SIR_MAC_VHT_CAP_CSN_BEAMORMER_ANT_SUP) | + (pBeaconStruct->VHTCaps.numSoundingDim << + SIR_MAC_VHT_CAP_NUM_SOUNDING_DIM) | + (pBeaconStruct->VHTCaps.muBeamformerCap << + SIR_MAC_VHT_CAP_NUM_BEAM_FORMER_CAP) | + (pBeaconStruct->VHTCaps.muBeamformeeCap << + SIR_MAC_VHT_CAP_NUM_BEAM_FORMEE_CAP) | + (pBeaconStruct->VHTCaps.vhtTXOPPS << + SIR_MAC_VHT_CAP_TXOPPS) | + (pBeaconStruct->VHTCaps.htcVHTCap << + SIR_MAC_VHT_CAP_HTC_CAP) | + (pBeaconStruct->VHTCaps.maxAMPDULenExp << + SIR_MAC_VHT_CAP_MAX_AMDU_LEN_EXPO) | + (pBeaconStruct->VHTCaps.vhtLinkAdaptCap << + SIR_MAC_VHT_CAP_LINK_ADAPT_CAP) | + (pBeaconStruct->VHTCaps.rxAntPattern << + SIR_MAC_VHT_CAP_RX_ANTENNA_PATTERN) | + (pBeaconStruct->VHTCaps.txAntPattern << + SIR_MAC_VHT_CAP_TX_ANTENNA_PATTERN) | + (pBeaconStruct->VHTCaps.reserved1 << + SIR_MAC_VHT_CAP_RESERVED2)); + } else { + pAddBssParams->vhtCapable = 0; + } + + lim_log(pMac, LOG1, FL("SIR_HAL_ADD_BSS_REQ with channel = %d..."), + pAddBssParams->currentOperChannel); + + /* Populate the STA-related parameters here */ + /* Note that the STA here refers to the AP */ + { + pAddBssParams->staContext.staType = STA_ENTRY_OTHER; + + qdf_mem_copy(pAddBssParams->staContext.bssId, + bssDescription->bssId, sizeof(tSirMacAddr)); + pAddBssParams->staContext.listenInterval = + bssDescription->beaconInterval; + + pAddBssParams->staContext.assocId = 0; + pAddBssParams->staContext.uAPSD = 0; + pAddBssParams->staContext.maxSPLen = 0; + pAddBssParams->staContext.shortPreambleSupported = + (uint8_t) pBeaconStruct->capabilityInfo.shortPreamble; + pAddBssParams->staContext.updateSta = updateEntry; + pAddBssParams->staContext.encryptType = + pftSessionEntry->encryptType; +#ifdef WLAN_FEATURE_11W + pAddBssParams->staContext.rmfEnabled = + pftSessionEntry->limRmfEnabled; +#endif + + if (IS_DOT11_MODE_HT(pftSessionEntry->dot11mode) && + (pBeaconStruct->HTCaps.present)) { + pAddBssParams->staContext.us32MaxAmpduDuration = 0; + pAddBssParams->staContext.htCapable = 1; + pAddBssParams->staContext.greenFieldCapable = + (uint8_t) pBeaconStruct->HTCaps.greenField; + pAddBssParams->staContext.lsigTxopProtection = + (uint8_t) pBeaconStruct->HTCaps.lsigTXOPProtection; + if ((pBeaconStruct->HTCaps.supportedChannelWidthSet) && + (chanWidthSupp)) { + pAddBssParams->staContext.ch_width = (uint8_t) + pBeaconStruct->HTInfo.recommendedTxWidthSet; + } else { + pAddBssParams->staContext.ch_width = + CH_WIDTH_20MHZ; + } + if (pftSessionEntry->vhtCapability && + IS_BSS_VHT_CAPABLE(pBeaconStruct->VHTCaps)) { + pAddBssParams->staContext.vhtCapable = 1; + if ((pBeaconStruct->VHTCaps.suBeamFormerCap || + pBeaconStruct->VHTCaps.muBeamformerCap) && + pftSessionEntry->vht_config.su_beam_formee) + sta_ctx->vhtTxBFCapable + = 1; + if (pBeaconStruct->VHTCaps.suBeamformeeCap && + pftSessionEntry->vht_config.su_beam_former) + sta_ctx->enable_su_tx_bformer = 1; + } + if ((pBeaconStruct->HTCaps.supportedChannelWidthSet) && + (chanWidthSupp)) { + sta_ctx->ch_width = (uint8_t) + pBeaconStruct->HTInfo.recommendedTxWidthSet; + if (pAddBssParams->staContext.vhtCapable && + pBeaconStruct->VHTOperation.chanWidth) + sta_ctx->ch_width = + pBeaconStruct->VHTOperation.chanWidth + + 1; + } else { + pAddBssParams->staContext.ch_width = + CH_WIDTH_20MHZ; + } + pAddBssParams->staContext.mimoPS = + (tSirMacHTMIMOPowerSaveState) pBeaconStruct->HTCaps. + mimoPowerSave; + pAddBssParams->staContext.maxAmsduSize = + (uint8_t) pBeaconStruct->HTCaps.maximalAMSDUsize; + pAddBssParams->staContext.maxAmpduDensity = + pBeaconStruct->HTCaps.mpduDensity; + pAddBssParams->staContext.fDsssCckMode40Mhz = + (uint8_t) pBeaconStruct->HTCaps.dsssCckMode40MHz; + pAddBssParams->staContext.fShortGI20Mhz = + (uint8_t) pBeaconStruct->HTCaps.shortGI20MHz; + pAddBssParams->staContext.fShortGI40Mhz = + (uint8_t) pBeaconStruct->HTCaps.shortGI40MHz; + pAddBssParams->staContext.maxAmpduSize = + pBeaconStruct->HTCaps.maxRxAMPDUFactor; + + if (pBeaconStruct->HTInfo.present) + pAddBssParams->staContext.rifsMode = + pBeaconStruct->HTInfo.rifsMode; + } + + if ((pftSessionEntry->limWmeEnabled + && pBeaconStruct->wmeEdcaPresent) + || (pftSessionEntry->limQosEnabled + && pBeaconStruct->edcaPresent)) + pAddBssParams->staContext.wmmEnabled = 1; + else + pAddBssParams->staContext.wmmEnabled = 0; + + pAddBssParams->staContext.wpa_rsn = pBeaconStruct->rsnPresent; + /* For OSEN Connection AP does not advertise RSN or WPA IE + * so from the IEs we get from supplicant we get this info + * so for FW to transmit EAPOL message 4 we shall set + * wpa_rsn + */ + pAddBssParams->staContext.wpa_rsn |= + (pBeaconStruct->wpaPresent << 1); + if ((!pAddBssParams->staContext.wpa_rsn) + && (pftSessionEntry->isOSENConnection)) + pAddBssParams->staContext.wpa_rsn = 1; + /* Update the rates */ + lim_populate_peer_rate_set(pMac, + &pAddBssParams->staContext. + supportedRates, + pBeaconStruct->HTCaps.supportedMCSSet, + false, pftSessionEntry, + &pBeaconStruct->VHTCaps); + } + + pAddBssParams->maxTxPower = pftSessionEntry->maxTxPower; + +#ifdef WLAN_FEATURE_11W + if (pftSessionEntry->limRmfEnabled) { + pAddBssParams->rmfEnabled = 1; + pAddBssParams->staContext.rmfEnabled = 1; + } +#endif + + pAddBssParams->status = QDF_STATUS_SUCCESS; + pAddBssParams->respReqd = true; + + pAddBssParams->staContext.sessionId = pftSessionEntry->peSessionId; + pAddBssParams->staContext.smesessionId = pftSessionEntry->smeSessionId; + pAddBssParams->sessionId = pftSessionEntry->peSessionId; + + /* Set a new state for MLME */ + if (!lim_is_roam_synch_in_progress(pftSessionEntry)) { + pftSessionEntry->limMlmState = + eLIM_MLM_WT_ADD_BSS_RSP_FT_REASSOC_STATE; + MTRACE(mac_trace + (pMac, TRACE_CODE_MLM_STATE, + pftSessionEntry->peSessionId, + eLIM_MLM_WT_ADD_BSS_RSP_FT_REASSOC_STATE)); + } + pAddBssParams->halPersona = (uint8_t) pftSessionEntry->pePersona; + + pftSessionEntry->ftPEContext.pAddBssReq = pAddBssParams; + + lim_log(pMac, LOG1, FL("Saving SIR_HAL_ADD_BSS_REQ for pre-auth ap.")); + + qdf_mem_free(pBeaconStruct); + return; +} +#endif + +#if defined(WLAN_FEATURE_HOST_ROAM) || defined(WLAN_FEATURE_ROAM_OFFLOAD) +/*------------------------------------------------------------------ + * + * Setup the new session for the pre-auth AP. + * Return the newly created session entry. + * + *------------------------------------------------------------------*/ +void lim_fill_ft_session(tpAniSirGlobal pMac, + tpSirBssDescription pbssDescription, + tpPESession pftSessionEntry, tpPESession psessionEntry) +{ + uint8_t currentBssUapsd; + int8_t localPowerConstraint; + int8_t regMax; + tSchBeaconStruct *pBeaconStruct; + uint32_t selfDot11Mode; + ePhyChanBondState cbEnabledMode; + + pBeaconStruct = qdf_mem_malloc(sizeof(tSchBeaconStruct)); + if (NULL == pBeaconStruct) { + lim_log(pMac, LOGE, + FL("No memory for creating lim_fill_ft_session")); + return; + } + + /* Retrieve the session that was already created and update the entry */ + lim_print_mac_addr(pMac, pbssDescription->bssId, LOG1); + pftSessionEntry->limWmeEnabled = psessionEntry->limWmeEnabled; + pftSessionEntry->limQosEnabled = psessionEntry->limQosEnabled; + pftSessionEntry->limWsmEnabled = psessionEntry->limWsmEnabled; + pftSessionEntry->lim11hEnable = psessionEntry->lim11hEnable; + pftSessionEntry->isOSENConnection = psessionEntry->isOSENConnection; + + /* Fields to be filled later */ + pftSessionEntry->pLimJoinReq = NULL; + pftSessionEntry->smeSessionId = psessionEntry->smeSessionId; + pftSessionEntry->transactionId = 0; + + lim_extract_ap_capabilities(pMac, (uint8_t *) pbssDescription->ieFields, + lim_get_ielen_from_bss_description(pbssDescription), + pBeaconStruct); + + pftSessionEntry->rateSet.numRates = + pBeaconStruct->supportedRates.numRates; + qdf_mem_copy(pftSessionEntry->rateSet.rate, + pBeaconStruct->supportedRates.rate, + pBeaconStruct->supportedRates.numRates); + + pftSessionEntry->extRateSet.numRates = + pBeaconStruct->extendedRates.numRates; + qdf_mem_copy(pftSessionEntry->extRateSet.rate, + pBeaconStruct->extendedRates.rate, + pftSessionEntry->extRateSet.numRates); + + pftSessionEntry->ssId.length = pBeaconStruct->ssId.length; + qdf_mem_copy(pftSessionEntry->ssId.ssId, pBeaconStruct->ssId.ssId, + pftSessionEntry->ssId.length); + + wlan_cfg_get_int(pMac, WNI_CFG_DOT11_MODE, &selfDot11Mode); + lim_log(pMac, LOG1, FL("selfDot11Mode %d"), selfDot11Mode); + pftSessionEntry->dot11mode = selfDot11Mode; + pftSessionEntry->vhtCapability = + (IS_DOT11_MODE_VHT(pftSessionEntry->dot11mode) + && IS_BSS_VHT_CAPABLE(pBeaconStruct->VHTCaps)); + pftSessionEntry->htCapability = + (IS_DOT11_MODE_HT(pftSessionEntry->dot11mode) + && pBeaconStruct->HTCaps.present); + + /* Copy The channel Id to the session Table */ + pftSessionEntry->limReassocChannelId = pbssDescription->channelId; + pftSessionEntry->currentOperChannel = pbssDescription->channelId; + + pftSessionEntry->limRFBand = lim_get_rf_band( + pftSessionEntry->currentOperChannel); + + if (pftSessionEntry->limRFBand == SIR_BAND_2_4_GHZ) { + cbEnabledMode = pMac->roam.configParam.channelBondingMode24GHz; + } else { + cbEnabledMode = pMac->roam.configParam.channelBondingMode5GHz; + } + pftSessionEntry->htSupportedChannelWidthSet = + (pBeaconStruct->HTInfo.present) ? + (cbEnabledMode && pBeaconStruct->HTInfo.recommendedTxWidthSet) : 0; + pftSessionEntry->htRecommendedTxWidthSet = + pftSessionEntry->htSupportedChannelWidthSet; + + if (IS_BSS_VHT_CAPABLE(pBeaconStruct->VHTCaps) && + pBeaconStruct->VHTOperation.present && + pftSessionEntry->vhtCapability) { + pftSessionEntry->vhtCapabilityPresentInBeacon = 1; + } else { + pftSessionEntry->vhtCapabilityPresentInBeacon = 0; + } + if (pftSessionEntry->htRecommendedTxWidthSet) { + pftSessionEntry->ch_width = CH_WIDTH_40MHZ; + if (pftSessionEntry->vhtCapabilityPresentInBeacon && + pBeaconStruct->VHTOperation.chanWidth) { + pftSessionEntry->ch_width = + pBeaconStruct->VHTOperation.chanWidth + 1; + pftSessionEntry->ch_center_freq_seg0 = + pBeaconStruct->VHTOperation.chanCenterFreqSeg1; + pftSessionEntry->ch_center_freq_seg1 = + pBeaconStruct->VHTOperation.chanCenterFreqSeg2; + } else { + if (pBeaconStruct->HTInfo.secondaryChannelOffset == + PHY_DOUBLE_CHANNEL_LOW_PRIMARY) + pftSessionEntry->ch_center_freq_seg0 = + pbssDescription->channelId + 2; + else if (pBeaconStruct->HTInfo.secondaryChannelOffset == + PHY_DOUBLE_CHANNEL_HIGH_PRIMARY) + pftSessionEntry->ch_center_freq_seg0 = + pbssDescription->channelId - 2; + else + lim_log(pMac, LOGE, FL("Invalid sec ch offset")); + } + } else { + pftSessionEntry->ch_width = CH_WIDTH_20MHZ; + pftSessionEntry->ch_center_freq_seg0 = 0; + pftSessionEntry->ch_center_freq_seg1 = 0; + } + + sir_copy_mac_addr(pftSessionEntry->selfMacAddr, + psessionEntry->selfMacAddr); + sir_copy_mac_addr(pftSessionEntry->limReAssocbssId, + pbssDescription->bssId); + sir_copy_mac_addr(pftSessionEntry->prev_ap_bssid, psessionEntry->bssId); + lim_print_mac_addr(pMac, pftSessionEntry->limReAssocbssId, LOG1); + + /* Store beaconInterval */ + pftSessionEntry->beaconParams.beaconInterval = + pbssDescription->beaconInterval; + pftSessionEntry->bssType = psessionEntry->bssType; + + pftSessionEntry->statypeForBss = STA_ENTRY_PEER; + pftSessionEntry->nwType = pbssDescription->nwType; + + + if (pftSessionEntry->bssType == eSIR_INFRASTRUCTURE_MODE) { + pftSessionEntry->limSystemRole = eLIM_STA_ROLE; + } else { + /* Throw an error & return & make sure to delete the session */ + lim_log(pMac, LOGE, FL("Invalid bss type")); + } + + pftSessionEntry->limCurrentBssCaps = pbssDescription->capabilityInfo; + pftSessionEntry->limReassocBssCaps = pbssDescription->capabilityInfo; + if (pMac->roam.configParam.shortSlotTime && + SIR_MAC_GET_SHORT_SLOT_TIME(pftSessionEntry->limReassocBssCaps)) { + pftSessionEntry->shortSlotTimeSupported = true; + } + + regMax = cfg_get_regulatory_max_transmit_power(pMac, + pftSessionEntry-> + currentOperChannel); + localPowerConstraint = regMax; + lim_extract_ap_capability(pMac, (uint8_t *) pbssDescription->ieFields, + lim_get_ielen_from_bss_description(pbssDescription), + &pftSessionEntry->limCurrentBssQosCaps, + &pftSessionEntry->limCurrentBssPropCap, ¤tBssUapsd, + &localPowerConstraint, pftSessionEntry); + + pftSessionEntry->limReassocBssQosCaps = + pftSessionEntry->limCurrentBssQosCaps; + pftSessionEntry->limReassocBssPropCap = + pftSessionEntry->limCurrentBssPropCap; + + pftSessionEntry->is11Rconnection = psessionEntry->is11Rconnection; +#ifdef FEATURE_WLAN_ESE + pftSessionEntry->isESEconnection = psessionEntry->isESEconnection; + pftSessionEntry->is_ese_version_ie_present = + pBeaconStruct->is_ese_ver_ie_present; +#endif + pftSessionEntry->isFastTransitionEnabled = + psessionEntry->isFastTransitionEnabled; + + pftSessionEntry->isFastRoamIniFeatureEnabled = + psessionEntry->isFastRoamIniFeatureEnabled; + +#ifdef FEATURE_WLAN_ESE + pftSessionEntry->maxTxPower = + lim_get_max_tx_power(regMax, localPowerConstraint, + pMac->roam.configParam.nTxPowerCap); +#else + pftSessionEntry->maxTxPower = QDF_MIN(regMax, (localPowerConstraint)); +#endif + + lim_log(pMac, LOG1, + FL("Reg max=%d, local pwr=%d, ini tx pwr=%d, max tx pwr = %d"), + regMax, localPowerConstraint, + pMac->roam.configParam.nTxPowerCap, + pftSessionEntry->maxTxPower); + if (!lim_is_roam_synch_in_progress(psessionEntry)) { + pftSessionEntry->limPrevSmeState = pftSessionEntry->limSmeState; + pftSessionEntry->limSmeState = eLIM_SME_WT_REASSOC_STATE; + MTRACE(mac_trace(pMac, + TRACE_CODE_SME_STATE, + pftSessionEntry->peSessionId, + pftSessionEntry->limSmeState)); + } + pftSessionEntry->encryptType = psessionEntry->encryptType; +#ifdef WLAN_FEATURE_11W + pftSessionEntry->limRmfEnabled = psessionEntry->limRmfEnabled; +#endif + if ((pftSessionEntry->limRFBand == SIR_BAND_2_4_GHZ) && + (pftSessionEntry->htSupportedChannelWidthSet == + eHT_CHANNEL_WIDTH_40MHZ)) + lim_init_obss_params(pMac, pftSessionEntry); + + pftSessionEntry->enableHtSmps = psessionEntry->enableHtSmps; + pftSessionEntry->htSmpsvalue = psessionEntry->htSmpsvalue; + /* + * By default supported NSS 1x1 is set to true + * and later on updated while determining session + * supported rates which is the intersection of + * self and peer rates + */ + pftSessionEntry->supported_nss_1x1 = true; + lim_log(pMac, LOG1, + FL("FT enable smps: %d mode: %d supported nss 1x1: %d"), + pftSessionEntry->enableHtSmps, + pftSessionEntry->htSmpsvalue, + pftSessionEntry->supported_nss_1x1); + + + qdf_mem_free(pBeaconStruct); +} +#endif + +/*------------------------------------------------------------------ + * + * This function is called to process the update key request from SME + * + *------------------------------------------------------------------*/ +bool lim_process_ft_update_key(tpAniSirGlobal pMac, uint32_t *pMsgBuf) +{ + tAddBssParams *pAddBssParams; + tSirFTUpdateKeyInfo *pKeyInfo; + uint32_t val = 0; + tpPESession psessionEntry; + uint8_t sessionId; + + /* Sanity Check */ + if (pMac == NULL || pMsgBuf == NULL) { + return false; + } + + pKeyInfo = (tSirFTUpdateKeyInfo *) pMsgBuf; + + psessionEntry = pe_find_session_by_bssid(pMac, pKeyInfo->bssid.bytes, + &sessionId); + if (NULL == psessionEntry) { + PELOGE(lim_log(pMac, LOGE, + "%s: Unable to find session for the following bssid", + __func__); + ) + lim_print_mac_addr(pMac, pKeyInfo->bssid.bytes, LOGE); + return false; + } + + /* Nothing to be done if the session is not in STA mode */ + if (!LIM_IS_STA_ROLE(psessionEntry)) { + lim_log(pMac, LOGE, FL("psessionEntry is not in STA mode")); + return false; + } + + if (NULL == psessionEntry->ftPEContext.pAddBssReq) { + /* AddBss Req is NULL, save the keys to configure them later. */ + tpLimMlmSetKeysReq pMlmSetKeysReq = + &psessionEntry->ftPEContext.PreAuthKeyInfo. + extSetStaKeyParam; + + qdf_mem_zero(pMlmSetKeysReq, sizeof(tLimMlmSetKeysReq)); + qdf_copy_macaddr(&pMlmSetKeysReq->peer_macaddr, + &pKeyInfo->bssid); + pMlmSetKeysReq->sessionId = psessionEntry->peSessionId; + pMlmSetKeysReq->smesessionId = psessionEntry->smeSessionId; + pMlmSetKeysReq->edType = pKeyInfo->keyMaterial.edType; + pMlmSetKeysReq->numKeys = pKeyInfo->keyMaterial.numKeys; + qdf_mem_copy((uint8_t *) &pMlmSetKeysReq->key, + (uint8_t *) &pKeyInfo->keyMaterial.key, + sizeof(tSirKeys)); + + psessionEntry->ftPEContext.PreAuthKeyInfo. + extSetStaKeyParamValid = true; + + lim_log(pMac, LOGE, FL("pAddBssReq is NULL")); + + if (psessionEntry->ftPEContext.pAddStaReq == NULL) { + lim_log(pMac, LOGE, FL("pAddStaReq is NULL")); + lim_send_set_sta_key_req(pMac, pMlmSetKeysReq, 0, 0, + psessionEntry, false); + psessionEntry->ftPEContext.PreAuthKeyInfo. + extSetStaKeyParamValid = false; + } + } else { + pAddBssParams = psessionEntry->ftPEContext.pAddBssReq; + + /* Store the key information in the ADD BSS parameters */ + pAddBssParams->extSetStaKeyParamValid = 1; + pAddBssParams->extSetStaKeyParam.encType = + pKeyInfo->keyMaterial.edType; + qdf_mem_copy((uint8_t *) &pAddBssParams->extSetStaKeyParam.key, + (uint8_t *) &pKeyInfo->keyMaterial.key, + sizeof(tSirKeys)); + if (eSIR_SUCCESS != + wlan_cfg_get_int(pMac, WNI_CFG_SINGLE_TID_RC, &val)) { + lim_log(pMac, LOGP, + FL("Unable to read WNI_CFG_SINGLE_TID_RC")); + } + + pAddBssParams->extSetStaKeyParam.singleTidRc = val; + PELOG1(lim_log(pMac, LOG1, FL("Key valid %d"), + pAddBssParams->extSetStaKeyParamValid, + pAddBssParams->extSetStaKeyParam.key[0]. + keyLength); + ) + + pAddBssParams->extSetStaKeyParam.staIdx = 0; + + PELOG1(lim_log(pMac, LOG1, + FL("BSSID = " MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(pKeyInfo->bssid.bytes));) + + qdf_copy_macaddr(&pAddBssParams->extSetStaKeyParam.peer_macaddr, + &pKeyInfo->bssid); + + pAddBssParams->extSetStaKeyParam.sendRsp = false; + } + return true; +} + +static void +lim_ft_send_aggr_qos_rsp(tpAniSirGlobal pMac, uint8_t rspReqd, + tpAggrAddTsParams aggrQosRsp, uint8_t smesessionId) +{ + tpSirAggrQosRsp rsp; + int i = 0; + if (!rspReqd) { + return; + } + rsp = qdf_mem_malloc(sizeof(tSirAggrQosRsp)); + if (NULL == rsp) { + lim_log(pMac, LOGP, + FL("AllocateMemory failed for tSirAggrQosRsp")); + return; + } + rsp->messageType = eWNI_SME_FT_AGGR_QOS_RSP; + rsp->sessionId = smesessionId; + rsp->length = sizeof(*rsp); + rsp->aggrInfo.tspecIdx = aggrQosRsp->tspecIdx; + for (i = 0; i < SIR_QOS_NUM_AC_MAX; i++) { + if ((1 << i) & aggrQosRsp->tspecIdx) { + rsp->aggrInfo.aggrRsp[i].status = aggrQosRsp->status[i]; + rsp->aggrInfo.aggrRsp[i].tspec = aggrQosRsp->tspec[i]; + } + } + lim_send_sme_aggr_qos_rsp(pMac, rsp, smesessionId); + return; +} + +void lim_process_ft_aggr_qo_s_rsp(tpAniSirGlobal pMac, tpSirMsgQ limMsg) +{ + tpAggrAddTsParams pAggrQosRspMsg = NULL; + tAddTsParams addTsParam = { 0 }; + tpDphHashNode pSta = NULL; + uint16_t assocId = 0; + tSirMacAddr peerMacAddr; + uint8_t rspReqd = 1; + tpPESession psessionEntry = NULL; + int i = 0; + PELOG1(lim_log(pMac, LOG1, FL(" Received AGGR_QOS_RSP from HAL"));) + SET_LIM_PROCESS_DEFD_MESGS(pMac, true); + pAggrQosRspMsg = (tpAggrAddTsParams) (limMsg->bodyptr); + if (NULL == pAggrQosRspMsg) { + PELOGE(lim_log(pMac, LOGE, FL("NULL pAggrQosRspMsg"));) + return; + } + psessionEntry = + pe_find_session_by_session_id(pMac, pAggrQosRspMsg->sessionId); + if (NULL == psessionEntry) { + PELOGE(lim_log(pMac, LOGE, + FL("Cant find session entry for %s"), __func__); + ) + if (pAggrQosRspMsg != NULL) { + qdf_mem_free(pAggrQosRspMsg); + } + return; + } + if (!LIM_IS_STA_ROLE(psessionEntry)) { + lim_log(pMac, LOGE, FL("psessionEntry is not in STA mode")); + return; + } + for (i = 0; i < HAL_QOS_NUM_AC_MAX; i++) { + if ((((1 << i) & pAggrQosRspMsg->tspecIdx)) && + (pAggrQosRspMsg->status[i] != QDF_STATUS_SUCCESS)) { + sir_copy_mac_addr(peerMacAddr, psessionEntry->bssId); + addTsParam.staIdx = pAggrQosRspMsg->staIdx; + addTsParam.sessionId = pAggrQosRspMsg->sessionId; + addTsParam.tspec = pAggrQosRspMsg->tspec[i]; + addTsParam.tspecIdx = pAggrQosRspMsg->tspecIdx; + lim_send_delts_req_action_frame(pMac, peerMacAddr, rspReqd, + &addTsParam.tspec.tsinfo, + &addTsParam.tspec, + psessionEntry); + pSta = + dph_lookup_assoc_id(pMac, addTsParam.staIdx, &assocId, + &psessionEntry->dph.dphHashTable); + if (pSta != NULL) { + lim_admit_control_delete_ts(pMac, assocId, + &addTsParam.tspec. + tsinfo, NULL, + (uint8_t *) & + addTsParam.tspecIdx); + } + } + } + lim_ft_send_aggr_qos_rsp(pMac, rspReqd, pAggrQosRspMsg, + psessionEntry->smeSessionId); + if (pAggrQosRspMsg != NULL) { + qdf_mem_free(pAggrQosRspMsg); + } + return; +} + +tSirRetStatus lim_process_ft_aggr_qos_req(tpAniSirGlobal pMac, uint32_t *pMsgBuf) +{ + tSirMsgQ msg; + tSirAggrQosReq *aggrQosReq = (tSirAggrQosReq *) pMsgBuf; + tpAggrAddTsParams pAggrAddTsParam; + tpPESession psessionEntry = NULL; + tpLimTspecInfo tspecInfo; + uint8_t ac; + tpDphHashNode pSta; + uint16_t aid; + uint8_t sessionId; + int i; + + pAggrAddTsParam = qdf_mem_malloc(sizeof(tAggrAddTsParams)); + if (NULL == pAggrAddTsParam) { + PELOGE(lim_log(pMac, LOGE, FL("AllocateMemory() failed"));) + return eSIR_MEM_ALLOC_FAILED; + } + + psessionEntry = pe_find_session_by_bssid(pMac, aggrQosReq->bssid.bytes, + &sessionId); + + if (psessionEntry == NULL) { + PELOGE(lim_log + (pMac, LOGE, + FL("psession Entry Null for sessionId = %d"), + aggrQosReq->sessionId); + ) + qdf_mem_free(pAggrAddTsParam); + return eSIR_FAILURE; + } + + /* Nothing to be done if the session is not in STA mode */ + if (!LIM_IS_STA_ROLE(psessionEntry)) { + lim_log(pMac, LOGE, FL("psessionEntry is not in STA mode")); + qdf_mem_free(pAggrAddTsParam); + return eSIR_FAILURE; + } + + pSta = dph_lookup_hash_entry(pMac, aggrQosReq->bssid.bytes, &aid, + &psessionEntry->dph.dphHashTable); + if (pSta == NULL) { + PELOGE(lim_log(pMac, LOGE, + FL + ("Station context not found - ignoring AddTsRsp")); + ) + qdf_mem_free(pAggrAddTsParam); + return eSIR_FAILURE; + } + + pAggrAddTsParam->staIdx = psessionEntry->staId; + /* Fill in the sessionId specific to PE */ + pAggrAddTsParam->sessionId = sessionId; + pAggrAddTsParam->tspecIdx = aggrQosReq->aggrInfo.tspecIdx; + + for (i = 0; i < HAL_QOS_NUM_AC_MAX; i++) { + if (aggrQosReq->aggrInfo.tspecIdx & (1 << i)) { + tSirMacTspecIE *pTspec = + &aggrQosReq->aggrInfo.aggrAddTsInfo[i].tspec; + /* Since AddTS response was successful, check for the PSB flag + * and directional flag inside the TS Info field. + * An AC is trigger enabled AC if the PSB subfield is set to 1 + * in the uplink direction. + * An AC is delivery enabled AC if the PSB subfield is set to 1 + * in the downlink direction. + * An AC is trigger and delivery enabled AC if the PSB subfield + * is set to 1 in the bi-direction field. + */ + if (pTspec->tsinfo.traffic.psb == 1) { + lim_set_tspec_uapsd_mask_per_session(pMac, + psessionEntry, + &pTspec-> + tsinfo, + SET_UAPSD_MASK); + } else { + lim_set_tspec_uapsd_mask_per_session(pMac, + psessionEntry, + &pTspec-> + tsinfo, + CLEAR_UAPSD_MASK); + } + /* + * ADDTS success, so AC is now admitted. + * We shall now use the default + * EDCA parameters as advertised by AP and + * send the updated EDCA params + * to HAL. + */ + ac = upToAc(pTspec->tsinfo.traffic.userPrio); + if (pTspec->tsinfo.traffic.direction == + SIR_MAC_DIRECTION_UPLINK) { + psessionEntry-> + gAcAdmitMask + [SIR_MAC_DIRECTION_UPLINK] |= + (1 << ac); + } else if (pTspec->tsinfo.traffic.direction == + SIR_MAC_DIRECTION_DNLINK) { + psessionEntry-> + gAcAdmitMask + [SIR_MAC_DIRECTION_DNLINK] |= + (1 << ac); + } else if (pTspec->tsinfo.traffic.direction == + SIR_MAC_DIRECTION_BIDIR) { + psessionEntry-> + gAcAdmitMask + [SIR_MAC_DIRECTION_UPLINK] |= + (1 << ac); + psessionEntry-> + gAcAdmitMask + [SIR_MAC_DIRECTION_DNLINK] |= + (1 << ac); + } + lim_set_active_edca_params(pMac, + psessionEntry->gLimEdcaParams, + psessionEntry); + + lim_send_edca_params(pMac, + psessionEntry->gLimEdcaParamsActive, + pSta->bssId); + + if (eSIR_SUCCESS != + lim_tspec_add(pMac, pSta->staAddr, pSta->assocId, + pTspec, 0, &tspecInfo)) { + PELOGE(lim_log + (pMac, LOGE, + FL + ("Adding entry in lim Tspec Table failed ")); + ) + pMac->lim.gLimAddtsSent = false; + qdf_mem_free(pAggrAddTsParam); + return eSIR_FAILURE; + } + + pAggrAddTsParam->tspec[i] = + aggrQosReq->aggrInfo.aggrAddTsInfo[i].tspec; + } + } + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + if (!pMac->roam.configParam.isRoamOffloadEnabled || + (pMac->roam.configParam.isRoamOffloadEnabled && + !psessionEntry->is11Rconnection)) +#endif + { + msg.type = WMA_AGGR_QOS_REQ; + msg.bodyptr = pAggrAddTsParam; + msg.bodyval = 0; + + /* We need to defer any incoming messages until we get a + * WMA_AGGR_QOS_RSP from HAL. + */ + SET_LIM_PROCESS_DEFD_MESGS(pMac, false); + MTRACE(mac_trace_msg_tx(pMac, psessionEntry->peSessionId, msg.type)); + + if (eSIR_SUCCESS != wma_post_ctrl_msg(pMac, &msg)) { + PELOGW(lim_log + (pMac, LOGW, FL("wma_post_ctrl_msg() failed")); + ) + SET_LIM_PROCESS_DEFD_MESGS(pMac, true); + qdf_mem_free(pAggrAddTsParam); + return eSIR_FAILURE; + } + } +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + else { + /* Implies it is a LFR3.0 based 11r connection + * so donot send add ts request to fimware since it + * already has the RIC IEs */ + + /* Send the Aggr QoS response to SME */ + lim_ft_send_aggr_qos_rsp(pMac, true, pAggrAddTsParam, + psessionEntry->smeSessionId); + if (pAggrAddTsParam != NULL) { + qdf_mem_free(pAggrAddTsParam); + } + } +#endif + + return eSIR_SUCCESS; +} diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_ft_preauth.c b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_ft_preauth.c new file mode 100644 index 0000000000000000000000000000000000000000..29ef6ad5e00d9324c7b920366f7390bd9d44a46e --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_ft_preauth.c @@ -0,0 +1,795 @@ +/* + * Copyright (c) 2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * 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. + */ + +/** + * DOC: lim_ft_preauth.c + * + * Pre-Authentication implementation for host based roaming + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "wma.h" + +/** + * lim_ft_cleanup_pre_auth_info() - Cleanup preauth related information + * @pMac: Global MAC Context + * @psessionEntry: PE Session + * + * This routine is called to free the FT context, session and other + * information used during preauth operation. + * + * Return: None + */ +void lim_ft_cleanup_pre_auth_info(tpAniSirGlobal pMac, + tpPESession psessionEntry) +{ + tpPESession pReAssocSessionEntry = NULL; + uint8_t sessionId = 0; + + if (!psessionEntry) { + lim_log(pMac, LOGE, FL("psessionEntry is NULL")); + return; + } + + /* Nothing to be done if the session is not in STA mode */ + if (!LIM_IS_STA_ROLE(psessionEntry)) { + lim_log(pMac, LOGE, FL("psessionEntry is not in STA mode")); + return; + } + + if (psessionEntry->ftPEContext.pFTPreAuthReq) { + pReAssocSessionEntry = + pe_find_session_by_bssid(pMac, + psessionEntry->ftPEContext. + pFTPreAuthReq->preAuthbssId, + &sessionId); + + lim_log(pMac, LOG1, FL("Freeing pFTPreAuthReq= %p"), + psessionEntry->ftPEContext.pFTPreAuthReq); + if (psessionEntry->ftPEContext.pFTPreAuthReq-> + pbssDescription) { + qdf_mem_free(psessionEntry->ftPEContext.pFTPreAuthReq-> + pbssDescription); + psessionEntry->ftPEContext.pFTPreAuthReq-> + pbssDescription = NULL; + } + qdf_mem_free(psessionEntry->ftPEContext.pFTPreAuthReq); + psessionEntry->ftPEContext.pFTPreAuthReq = NULL; + } + + if (psessionEntry->ftPEContext.pAddBssReq) { + qdf_mem_free(psessionEntry->ftPEContext.pAddBssReq); + psessionEntry->ftPEContext.pAddBssReq = NULL; + } + + if (psessionEntry->ftPEContext.pAddStaReq) { + qdf_mem_free(psessionEntry->ftPEContext.pAddStaReq); + psessionEntry->ftPEContext.pAddStaReq = NULL; + } + + /* The session is being deleted, cleanup the contents */ + qdf_mem_set(&psessionEntry->ftPEContext, sizeof(tftPEContext), 0); + + /* Delete the session created while handling pre-auth response */ + if (pReAssocSessionEntry) { + /* If we have successful pre-auth response, then we would have + * created a session on which reassoc request will be sent + */ + if (pReAssocSessionEntry->valid && + pReAssocSessionEntry->limSmeState == + eLIM_SME_WT_REASSOC_STATE) { + QDF_TRACE(QDF_MODULE_ID_PE, + QDF_TRACE_LEVEL_DEBUG, + FL("Deleting Preauth session(%d)"), + pReAssocSessionEntry->peSessionId); + pe_delete_session(pMac, pReAssocSessionEntry); + } + } +} + +/* + * lim_process_ft_pre_auth_req() - process ft pre auth req + * + * @mac_ctx: global mac ctx + * @msg: pointer to message + * + * In this function, we process the FT Pre Auth Req: + * We receive Pre-Auth, suspend link, register a call back. In the call back, + * we will need to accept frames from the new bssid. Send out the auth req to + * new AP. Start timer and when the timer is done or if we receive the Auth + * response. We change channel. Resume link + * + * Return: value to indicate if buffer was consumed + */ +int lim_process_ft_pre_auth_req(tpAniSirGlobal mac_ctx, tpSirMsgQ msg) +{ + int buf_consumed = false; + tpPESession session; + uint8_t session_id; + tpSirFTPreAuthReq ft_pre_auth_req = (tSirFTPreAuthReq *) msg->bodyptr; + + if (NULL == ft_pre_auth_req) { + lim_log(mac_ctx, LOGE, FL("tSirFTPreAuthReq is NULL")); + return buf_consumed; + } + + /* Get the current session entry */ + session = pe_find_session_by_bssid(mac_ctx, + ft_pre_auth_req->currbssId, + &session_id); + if (session == NULL) { + lim_log(mac_ctx, LOGE, + FL("Unable to find session for the bssid" + MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(ft_pre_auth_req->currbssId)); + /* Post the FT Pre Auth Response to SME */ + lim_post_ft_pre_auth_rsp(mac_ctx, eSIR_FAILURE, NULL, 0, + session); + buf_consumed = true; + return buf_consumed; + } + + /* Nothing to be done if the session is not in STA mode */ + if (!LIM_IS_STA_ROLE(session)) { + lim_log(mac_ctx, LOGE, FL("session is not in STA mode")); + buf_consumed = true; + return buf_consumed; + } + + /* Can set it only after sending auth */ + session->ftPEContext.ftPreAuthStatus = eSIR_FAILURE; + session->ftPEContext.ftPreAuthSession = true; + + /* Indicate that this is the session on which preauth is being done */ + if (session->ftPEContext.pFTPreAuthReq) { + if (session->ftPEContext.pFTPreAuthReq->pbssDescription) { + qdf_mem_free( + session->ftPEContext.pFTPreAuthReq->pbssDescription); + session->ftPEContext.pFTPreAuthReq->pbssDescription = + NULL; + } + qdf_mem_free(session->ftPEContext.pFTPreAuthReq); + session->ftPEContext.pFTPreAuthReq = NULL; + } + + /* We need information from the Pre-Auth Req. Lets save that */ + session->ftPEContext.pFTPreAuthReq = ft_pre_auth_req; + + lim_log(mac_ctx, LOG1, FL("PRE Auth ft_ies_length=%02x%02x%02x"), + session->ftPEContext.pFTPreAuthReq->ft_ies[0], + session->ftPEContext.pFTPreAuthReq->ft_ies[1], + session->ftPEContext.pFTPreAuthReq->ft_ies[2]); +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM /* FEATURE_WLAN_DIAG_SUPPORT */ + lim_diag_event_report(mac_ctx, WLAN_PE_DIAG_PRE_AUTH_REQ_EVENT, + session, 0, 0); +#endif + + /* + * Dont need to suspend if APs are in same channel and DUT + * is not in MCC state + */ + if ((session->currentOperChannel != + session->ftPEContext.pFTPreAuthReq->preAuthchannelNum) + || lim_is_in_mcc(mac_ctx)) { + /* Need to suspend link only if the channels are different */ + lim_log(mac_ctx, LOG2, + FL("Performing pre-auth on diff channel(session %p)"), + session); + lim_send_preauth_scan_offload(mac_ctx, session->peSessionId, + session->ftPEContext.pFTPreAuthReq); + } else { + lim_log(mac_ctx, LOG2, + FL("Performing pre-auth on same channel (session %p)"), + session); + /* We are in the same channel. Perform pre-auth */ + lim_perform_ft_pre_auth(mac_ctx, QDF_STATUS_SUCCESS, NULL, + session); + } + + return buf_consumed; +} + +/** + * lim_perform_ft_pre_auth() - Perform preauthentication + * @pMac: Global MAC Context + * @status: Status Code + * @data: pre-auth data + * @psessionEntry: PE Session + * + * This routine will trigger the sending of authentication frame + * to the peer. + * + * Return: None + */ +void lim_perform_ft_pre_auth(tpAniSirGlobal pMac, QDF_STATUS status, + uint32_t *data, tpPESession psessionEntry) +{ + tSirMacAuthFrameBody authFrame; + unsigned int session_id; + eCsrAuthType auth_type; + + if (NULL == psessionEntry) { + PELOGE(lim_log(pMac, LOGE, FL("psessionEntry is NULL"));) + return; + } + session_id = psessionEntry->smeSessionId; + auth_type = + pMac->roam.roamSession[session_id].connectedProfile.AuthType; + + if (psessionEntry->is11Rconnection && + psessionEntry->ftPEContext.pFTPreAuthReq) { + /* Only 11r assoc has FT IEs */ + if ((auth_type != eCSR_AUTH_TYPE_OPEN_SYSTEM) && + (psessionEntry->ftPEContext.pFTPreAuthReq->ft_ies_length + == 0)) { + lim_log(pMac, LOGE, + FL("FTIEs for Auth Req Seq 1 is absent")); + goto preauth_fail; + } + } + + if (status != QDF_STATUS_SUCCESS) { + lim_log(pMac, LOGE, + FL(" Change channel not successful for FT pre-auth")); + goto preauth_fail; + } + + /* Nothing to be done if the session is not in STA mode */ + if (!LIM_IS_STA_ROLE(psessionEntry)) { + lim_log(pMac, LOGE, FL("psessionEntry is not in STA mode")); + return; + } + lim_log(pMac, LOG2, "Entered wait auth2 state for FT (old session %p)", + psessionEntry); + if (psessionEntry->is11Rconnection) { + /* Now we are on the right channel and need to send out Auth1 + * and receive Auth2 + */ + authFrame.authAlgoNumber = eSIR_FT_AUTH; + } else { + /* Will need to make isESEconnection a enum may be for further + * improvements to this to match this algorithm number + */ + authFrame.authAlgoNumber = eSIR_OPEN_SYSTEM; + } + authFrame.authTransactionSeqNumber = SIR_MAC_AUTH_FRAME_1; + authFrame.authStatusCode = 0; + + pMac->lim.limTimers.g_lim_periodic_auth_retry_timer.sessionId = + psessionEntry->peSessionId; + + /* Start timer here to come back to operating channel */ + pMac->lim.limTimers.gLimFTPreAuthRspTimer.sessionId = + psessionEntry->peSessionId; + if (TX_SUCCESS != + tx_timer_activate(&pMac->lim.limTimers.gLimFTPreAuthRspTimer)) { + lim_log(pMac, LOGE, FL("FT Auth Rsp Timer Start Failed")); + goto preauth_fail; + } + MTRACE(mac_trace(pMac, TRACE_CODE_TIMER_ACTIVATE, + psessionEntry->peSessionId, eLIM_FT_PREAUTH_RSP_TIMER)); + + lim_log(pMac, LOG1, FL("FT Auth Rsp Timer Started")); +#ifdef FEATURE_WLAN_DIAG_SUPPORT + lim_diag_event_report(pMac, WLAN_PE_DIAG_ROAM_AUTH_START_EVENT, + pMac->lim.pSessionEntry, eSIR_SUCCESS, eSIR_SUCCESS); +#endif + + lim_send_auth_mgmt_frame(pMac, &authFrame, + psessionEntry->ftPEContext.pFTPreAuthReq->preAuthbssId, + LIM_NO_WEP_IN_FC, psessionEntry); + + return; + +preauth_fail: + lim_handle_ft_pre_auth_rsp(pMac, eSIR_FAILURE, NULL, 0, psessionEntry); + return; +} + +/** + * lim_ft_setup_auth_session() - Fill the FT Session + * @pMac: Global MAC Context + * @psessionEntry: PE Session + * + * Setup the session and the add bss req for the pre-auth AP. + * + * Return: Success or Failure Status + */ +tSirRetStatus lim_ft_setup_auth_session(tpAniSirGlobal pMac, + tpPESession psessionEntry) +{ + tpPESession pftSessionEntry = NULL; + uint8_t sessionId = 0; + + pftSessionEntry = + pe_find_session_by_bssid(pMac, psessionEntry->limReAssocbssId, + &sessionId); + if (pftSessionEntry == NULL) { + lim_log(pMac, LOGE, FL("No session found for bssid")); + lim_print_mac_addr(pMac, psessionEntry->limReAssocbssId, LOGE); + return eSIR_FAILURE; + } + + /* Nothing to be done if the session is not in STA mode */ + if (!LIM_IS_STA_ROLE(psessionEntry)) { + lim_log(pMac, LOGE, FL("psessionEntry is not in STA mode")); + return eSIR_FAILURE; + } + + if (psessionEntry->ftPEContext.pFTPreAuthReq && + psessionEntry->ftPEContext.pFTPreAuthReq->pbssDescription) { + lim_fill_ft_session(pMac, + psessionEntry->ftPEContext.pFTPreAuthReq-> + pbssDescription, pftSessionEntry, + psessionEntry); + + lim_ft_prepare_add_bss_req(pMac, false, pftSessionEntry, + psessionEntry->ftPEContext.pFTPreAuthReq->pbssDescription); + } + + return eSIR_SUCCESS; +} + +/** + * lim_ft_process_pre_auth_result() - Process the Auth frame + * @pMac: Global MAC context + * @status: Status code + * @psessionEntry: PE Session + * + * Return: None + */ +static void lim_ft_process_pre_auth_result(tpAniSirGlobal pMac, + QDF_STATUS status, + tpPESession psessionEntry) +{ + if (NULL == psessionEntry || + NULL == psessionEntry->ftPEContext.pFTPreAuthReq) + return; + + /* Nothing to be done if the session is not in STA mode */ + if (!LIM_IS_STA_ROLE(psessionEntry)) { + lim_log(pMac, LOGE, FL("psessionEntry is not in STA mode")); + return; + } + + if (psessionEntry->ftPEContext.ftPreAuthStatus == eSIR_SUCCESS) { + psessionEntry->ftPEContext.ftPreAuthStatus = + lim_ft_setup_auth_session(pMac, psessionEntry); + } + /* Post the FT Pre Auth Response to SME */ + lim_post_ft_pre_auth_rsp(pMac, + psessionEntry->ftPEContext.ftPreAuthStatus, + psessionEntry->ftPEContext.saved_auth_rsp, + psessionEntry->ftPEContext.saved_auth_rsp_length, + psessionEntry); +} + +/** + * lim_handle_ft_pre_auth_rsp() - Handle the Auth response + * @pMac: Global MAC Context + * @status: Status Code + * @auth_rsp: Auth Response + * @auth_rsp_length: Auth response length + * @psessionEntry: PE Session + * + * Send the FT Pre Auth Response to SME whenever we have a status + * ready to be sent to SME + * + * SME will be the one to send it up to the supplicant to receive + * FTIEs which will be required for Reassoc Req. + * + * @Return: None + */ +void lim_handle_ft_pre_auth_rsp(tpAniSirGlobal pMac, tSirRetStatus status, + uint8_t *auth_rsp, uint16_t auth_rsp_length, + tpPESession psessionEntry) +{ + tpPESession pftSessionEntry = NULL; + uint8_t sessionId = 0; + tpSirBssDescription pbssDescription = NULL; +#ifdef FEATURE_WLAN_DIAG_SUPPORT + lim_diag_event_report(pMac, WLAN_PE_DIAG_PRE_AUTH_RSP_EVENT, + psessionEntry, (uint16_t) status, 0); +#endif + + /* Nothing to be done if the session is not in STA mode */ + if (!LIM_IS_STA_ROLE(psessionEntry)) { + lim_log(pMac, LOGE, FL("psessionEntry is not in STA mode")); + return; + } + + /* Save the status of pre-auth */ + psessionEntry->ftPEContext.ftPreAuthStatus = status; + + /* Save the auth rsp, so we can send it to + * SME once we resume link + */ + psessionEntry->ftPEContext.saved_auth_rsp_length = 0; + if ((auth_rsp != NULL) && (auth_rsp_length < MAX_FTIE_SIZE)) { + qdf_mem_copy(psessionEntry->ftPEContext.saved_auth_rsp, + auth_rsp, auth_rsp_length); + psessionEntry->ftPEContext.saved_auth_rsp_length = + auth_rsp_length; + } + + if (!psessionEntry->ftPEContext.pFTPreAuthReq || + !psessionEntry->ftPEContext.pFTPreAuthReq->pbssDescription) { + lim_log(pMac, LOGE, + FL("pFTPreAuthReq or pbssDescription is NULL")); + return; + } + + /* Create FT session for the re-association at this point */ + if (psessionEntry->ftPEContext.ftPreAuthStatus == eSIR_SUCCESS) { + pbssDescription = + psessionEntry->ftPEContext.pFTPreAuthReq->pbssDescription; + lim_print_mac_addr(pMac, pbssDescription->bssId, LOG1); + pftSessionEntry = + pe_create_session(pMac, pbssDescription->bssId, + &sessionId, pMac->lim.maxStation, + psessionEntry->bssType); + if (pftSessionEntry == NULL) { + lim_log(pMac, LOGE, FL( + "Session not created for pre-auth 11R AP")); + status = eSIR_FAILURE; + psessionEntry->ftPEContext.ftPreAuthStatus = status; + goto send_rsp; + } + pftSessionEntry->peSessionId = sessionId; + pftSessionEntry->smeSessionId = psessionEntry->smeSessionId; + sir_copy_mac_addr(pftSessionEntry->selfMacAddr, + psessionEntry->selfMacAddr); + sir_copy_mac_addr(pftSessionEntry->limReAssocbssId, + pbssDescription->bssId); + pftSessionEntry->bssType = psessionEntry->bssType; + + if (pftSessionEntry->bssType == eSIR_INFRASTRUCTURE_MODE) + pftSessionEntry->limSystemRole = eLIM_STA_ROLE; + else + lim_log(pMac, LOGE, FL("Invalid bss type")); + pftSessionEntry->limPrevSmeState = pftSessionEntry->limSmeState; + qdf_mem_copy(&(pftSessionEntry->htConfig), + &(psessionEntry->htConfig), + sizeof(psessionEntry->htConfig)); + pftSessionEntry->limSmeState = eLIM_SME_WT_REASSOC_STATE; + + if (IS_5G_CH(psessionEntry->ftPEContext.pFTPreAuthReq-> + preAuthchannelNum)) + pftSessionEntry->vdev_nss = pMac->vdev_type_nss_5g.sta; + else + pftSessionEntry->vdev_nss = pMac->vdev_type_nss_2g.sta; + + lim_log(pMac, LOG1, FL("created session (%p) with id = %d"), + pftSessionEntry, pftSessionEntry->peSessionId); + + /* Update the ReAssoc BSSID of the current session */ + sir_copy_mac_addr(psessionEntry->limReAssocbssId, + pbssDescription->bssId); + lim_print_mac_addr(pMac, psessionEntry->limReAssocbssId, LOG1); + } +send_rsp: + if (psessionEntry->currentOperChannel != + psessionEntry->ftPEContext.pFTPreAuthReq->preAuthchannelNum) { + /* Need to move to the original AP channel */ + lim_process_abort_scan_ind(pMac, psessionEntry->peSessionId, + psessionEntry->ftPEContext.pFTPreAuthReq->scan_id, + PREAUTH_REQUESTOR_ID); + } else { + lim_log(pMac, LOG1, + "Pre auth on same channel as connected AP channel %d", + psessionEntry->ftPEContext.pFTPreAuthReq-> + preAuthchannelNum); + lim_ft_process_pre_auth_result(pMac, status, psessionEntry); + } +} + +/* + * lim_process_ft_preauth_rsp_timeout() - process ft preauth rsp timeout + * + * @mac_ctx: global mac ctx + * + * This function is called if preauth response is not received from the AP + * within this timeout while FT in progress + * + * Return: void + */ +void lim_process_ft_preauth_rsp_timeout(tpAniSirGlobal mac_ctx) +{ + tpPESession session; + + /* + * We have failed pre auth. We need to resume link and get back on + * home channel + */ + lim_log(mac_ctx, LOGE, FL("FT Pre-Auth Time Out!!!!")); + session = pe_find_session_by_session_id(mac_ctx, + mac_ctx->lim.limTimers.gLimFTPreAuthRspTimer.sessionId); + if (NULL == session) { + lim_log(mac_ctx, LOGE, + FL("Session Does not exist for given sessionID")); + return; + } + + /* Nothing to be done if the session is not in STA mode */ + if (!LIM_IS_STA_ROLE(session)) { + lim_log(mac_ctx, LOGE, FL("session is not in STA mode")); + return; + } + + /* Reset the flag to indicate preauth request session */ + session->ftPEContext.ftPreAuthSession = false; + + if (NULL == session->ftPEContext.pFTPreAuthReq) { + /* Auth Rsp might already be posted to SME and ftcleanup done */ + lim_log(mac_ctx, LOGE, FL("pFTPreAuthReq is NULL sessionId:%d"), + mac_ctx->lim.limTimers.gLimFTPreAuthRspTimer.sessionId); + return; + } + + /* + * To handle the race condition where we recieve preauth rsp after + * timer has expired. + */ + if (true == + session->ftPEContext.pFTPreAuthReq->bPreAuthRspProcessed) { + lim_log(mac_ctx, LOGE, + FL("Auth rsp already posted to SME (session %p)"), + session); + return; + } else { + /* + * Here we are sending preauth rsp with failure state + * and which is forwarded to SME. Now, if we receive an preauth + * resp from AP with success it would create a FT pesession, but + * will be dropped in SME leaving behind the pesession. Mark + * Preauth rsp processed so that any rsp from AP is dropped in + * lim_process_auth_frame_no_session. + */ + lim_log(mac_ctx, LOG1, + FL("Auth rsp not yet posted to SME (session %p)"), + session); + session->ftPEContext.pFTPreAuthReq->bPreAuthRspProcessed = true; + } + + /* + * Attempted at Pre-Auth and failed. If we are off channel. We need + * to get back to home channel + */ + lim_handle_ft_pre_auth_rsp(mac_ctx, eSIR_FAILURE, NULL, 0, session); +} + +/* + * lim_post_ft_pre_auth_rsp() - post ft pre auth response to SME. + * + * @mac_ctx: global mac ctx + * @status: status code to post in auth rsp + * @auth_rsp: pointer to auth rsp FT ie + * @auth_rsp_length: len of the IE field + * @session: pe session + * + * post pre auth response to SME. + * + * Return: void + */ +void lim_post_ft_pre_auth_rsp(tpAniSirGlobal mac_ctx, + tSirRetStatus status, + uint8_t *auth_rsp, + uint16_t auth_rsp_length, + tpPESession session) +{ + tpSirFTPreAuthRsp ft_pre_auth_rsp; + tSirMsgQ mmh_msg; + uint16_t rsp_len = sizeof(tSirFTPreAuthRsp); + + ft_pre_auth_rsp = (tpSirFTPreAuthRsp) qdf_mem_malloc(rsp_len); + if (NULL == ft_pre_auth_rsp) { + lim_log(mac_ctx, LOGE, "Failed to allocate memory"); + QDF_ASSERT(ft_pre_auth_rsp != NULL); + return; + } + + lim_log(mac_ctx, LOG1, FL("Auth Rsp = %p"), ft_pre_auth_rsp); + if (session) { + /* Nothing to be done if the session is not in STA mode */ + if (!LIM_IS_STA_ROLE(session)) { + lim_log(mac_ctx, LOGE, + FL("session is not in STA mode")); + qdf_mem_free(ft_pre_auth_rsp); + return; + } + ft_pre_auth_rsp->smeSessionId = session->smeSessionId; + /* The bssid of the AP we are sending Auth1 to. */ + if (session->ftPEContext.pFTPreAuthReq) + sir_copy_mac_addr(ft_pre_auth_rsp->preAuthbssId, + session->ftPEContext.pFTPreAuthReq->preAuthbssId); + } + + ft_pre_auth_rsp->messageType = eWNI_SME_FT_PRE_AUTH_RSP; + ft_pre_auth_rsp->length = (uint16_t) rsp_len; + ft_pre_auth_rsp->status = status; + + /* Attach the auth response now back to SME */ + ft_pre_auth_rsp->ft_ies_length = 0; + if ((auth_rsp != NULL) && (auth_rsp_length < MAX_FTIE_SIZE)) { + /* Only 11r assoc has FT IEs */ + qdf_mem_copy(ft_pre_auth_rsp->ft_ies, + auth_rsp, auth_rsp_length); + ft_pre_auth_rsp->ft_ies_length = auth_rsp_length; + } + + if (status != eSIR_SUCCESS) { + /* + * Ensure that on Pre-Auth failure the cached Pre-Auth Req and + * other allocated memory is freed up before returning. + */ + lim_log(mac_ctx, LOG1, "Pre-Auth Failed, Cleanup!"); + lim_ft_cleanup(mac_ctx, session); + } + + mmh_msg.type = ft_pre_auth_rsp->messageType; + mmh_msg.bodyptr = ft_pre_auth_rsp; + mmh_msg.bodyval = 0; + + lim_log(mac_ctx, LOG1, FL("Posted Auth Rsp to SME with status of 0x%x"), + status); +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM /* FEATURE_WLAN_DIAG_SUPPORT */ + if (status == eSIR_SUCCESS) + lim_diag_event_report(mac_ctx, WLAN_PE_DIAG_PREAUTH_DONE, + session, status, 0); +#endif + lim_sys_process_mmh_msg_api(mac_ctx, &mmh_msg, ePROT); +} + +/** + * lim_send_preauth_scan_offload() - Send scan command to handle preauth. + * + * @mac_ctx: Pointer to Global MAC structure + * @session_id: pe session id + * @ft_preauth_req: Preauth request with parameters + * + * Builds a single channel scan request and sends it to WMA. + * Scan dwell time is the time allocated to go to preauth candidate + * channel for auth frame exchange. + * + * Return: Status of sending message to WMA. + */ +QDF_STATUS lim_send_preauth_scan_offload(tpAniSirGlobal mac_ctx, + uint8_t session_id, + tSirFTPreAuthReq *ft_preauth_req) +{ + tSirScanOffloadReq *scan_offload_req; + tSirRetStatus rc = eSIR_SUCCESS; + tSirMsgQ msg; + + scan_offload_req = qdf_mem_malloc(sizeof(tSirScanOffloadReq)); + if (NULL == scan_offload_req) { + lim_log(mac_ctx, LOGE, + FL("Memory allocation failed for pScanOffloadReq")); + return QDF_STATUS_E_NOMEM; + } + + msg.type = WMA_START_SCAN_OFFLOAD_REQ; + msg.bodyptr = scan_offload_req; + msg.bodyval = 0; + + qdf_mem_copy((uint8_t *) &scan_offload_req->selfMacAddr.bytes, + (uint8_t *) ft_preauth_req->self_mac_addr, + sizeof(tSirMacAddr)); + + qdf_mem_copy((uint8_t *) &scan_offload_req->bssId.bytes, + (uint8_t *) ft_preauth_req->currbssId, + sizeof(tSirMacAddr)); + scan_offload_req->scanType = eSIR_PASSIVE_SCAN; + /* + * P2P_SCAN_TYPE_LISTEN tells firmware to allow mgt frames to/from + * mac address that is not of connected AP. + */ + scan_offload_req->p2pScanType = P2P_SCAN_TYPE_LISTEN; + scan_offload_req->restTime = 0; + scan_offload_req->minChannelTime = LIM_FT_PREAUTH_SCAN_TIME; + scan_offload_req->maxChannelTime = LIM_FT_PREAUTH_SCAN_TIME; + scan_offload_req->sessionId = session_id; + scan_offload_req->channelList.numChannels = 1; + scan_offload_req->channelList.channelNumber[0] = + ft_preauth_req->preAuthchannelNum; + wma_get_scan_id(&ft_preauth_req->scan_id); + scan_offload_req->scan_id = ft_preauth_req->scan_id; + scan_offload_req->scan_requestor_id = PREAUTH_REQUESTOR_ID; + + lim_log(mac_ctx, LOG1, + FL("Scan request: duration %u, session %hu, chan %hu"), + scan_offload_req->maxChannelTime, session_id, + ft_preauth_req->preAuthchannelNum); + + rc = wma_post_ctrl_msg(mac_ctx, &msg); + if (rc != eSIR_SUCCESS) { + lim_log(mac_ctx, LOGE, FL("START_SCAN_OFFLOAD failed %u"), rc); + qdf_mem_free(scan_offload_req); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * lim_preauth_scan_event_handler() - Process firmware preauth scan events + * + * @mac_ctx:Pointer to global MAC structure + * @event: Scan event + * @session_id: session entry + * @scan_id: scan id from WMA scan event. + * + * If scan event signifies failure or successful completion, operation + * is complete. + * If scan event signifies that STA is on foreign channel, send auth frame + * + * Return: void + */ + +void lim_preauth_scan_event_handler(tpAniSirGlobal mac_ctx, + enum sir_scan_event_type event, + uint8_t session_id, + uint32_t scan_id) +{ + tpPESession session_entry; + + session_entry = pe_find_session_by_session_id(mac_ctx, session_id); + if (session_entry == NULL) { + lim_log(mac_ctx, LOGE, + FL("SessionId:%d Session Does not exist"), session_id); + return; + } + + switch (event) { + case SIR_SCAN_EVENT_START_FAILED: + /* Scan command is rejected by firmware */ + lim_log(mac_ctx, LOGE, FL("Failed to start preauth scan")); + lim_post_ft_pre_auth_rsp(mac_ctx, eSIR_FAILURE, NULL, 0, + session_entry); + return; + + case SIR_SCAN_EVENT_COMPLETED: + /* + * Scan either completed succesfully or or got terminated + * after successful auth, or timed out. Either way, STA + * is back to home channel. Data traffic can continue. + */ + lim_ft_process_pre_auth_result(mac_ctx, QDF_STATUS_SUCCESS, + session_entry); + break; + + case SIR_SCAN_EVENT_FOREIGN_CHANNEL: + /* Sta is on candidate channel. Send auth */ + lim_perform_ft_pre_auth(mac_ctx, QDF_STATUS_SUCCESS, NULL, + session_entry); + break; + default: + /* Don't print message for scan events that are ignored */ + break; + } +} diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_ibss_peer_mgmt.c b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_ibss_peer_mgmt.c new file mode 100644 index 0000000000000000000000000000000000000000..4e5f6fe96c4a3d8c82c2095e97fdc02ea23f9a83 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_ibss_peer_mgmt.c @@ -0,0 +1,1846 @@ +/* + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#include "cds_api.h" +#include "ani_global.h" +#include "sir_common.h" +#include "wni_cfg.h" +#include "lim_utils.h" +#include "lim_assoc_utils.h" +#include "lim_sta_hash_api.h" +#include "sch_api.h" /* sch_set_fixed_beacon_fields for IBSS coalesce */ +#include "lim_security_utils.h" +#include "lim_send_messages.h" +#include "lim_ft_defs.h" +#include "lim_session.h" +#include "lim_ibss_peer_mgmt.h" +#include "lim_types.h" + +/** + * ibss_peer_find + * + ***FUNCTION: + * This function is called while adding a context at + * DPH & Polaris for a peer in IBSS. + * If peer is found in the list, capabilities from the + * returned BSS description are used at DPH node & Polaris. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param macAddr - MAC address of the peer + * + * @return Pointer to peer node if found, else NULL + */ + +static tLimIbssPeerNode *ibss_peer_find(tpAniSirGlobal pMac, + tSirMacAddr macAddr) +{ + tLimIbssPeerNode *pTempNode = pMac->lim.gLimIbssPeerList; + + while (pTempNode != NULL) { + if (!qdf_mem_cmp((uint8_t *) macAddr, + (uint8_t *) &pTempNode->peerMacAddr, + sizeof(tSirMacAddr))) + break; + pTempNode = pTempNode->next; + } + return pTempNode; +} /*** end ibss_peer_find() ***/ + +/** + * ibss_peer_add + * + ***FUNCTION: + * This is called on a STA in IBSS upon receiving Beacon/ + * Probe Response from a peer. + * + ***LOGIC: + * Node is always added to the front of the list + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param pMac - Pointer to Global MAC structure + * @param pPeerNode - Pointer to peer node to be added to the list. + * + * @return None + */ + +static tSirRetStatus +ibss_peer_add(tpAniSirGlobal pMac, tLimIbssPeerNode *pPeerNode) +{ +#ifdef ANI_SIR_IBSS_PEER_CACHING + uint32_t numIbssPeers = (2 * pMac->lim.maxStation); + + if (pMac->lim.gLimNumIbssPeers >= numIbssPeers) { + /** + * Reached max number of peers to be maintained. + * Delete last entry & add new entry at the beginning. + */ + tLimIbssPeerNode *pTemp, *pPrev; + pTemp = pPrev = pMac->lim.gLimIbssPeerList; + while (pTemp->next != NULL) { + pPrev = pTemp; + pTemp = pTemp->next; + } + if (pTemp->beacon) { + qdf_mem_free(pTemp->beacon); + } + + qdf_mem_free(pTemp); + pPrev->next = NULL; + } else +#endif + pMac->lim.gLimNumIbssPeers++; + + pPeerNode->next = pMac->lim.gLimIbssPeerList; + pMac->lim.gLimIbssPeerList = pPeerNode; + + return eSIR_SUCCESS; + +} /*** end limAddIbssPeerToList() ***/ + +/** + * ibss_peer_collect + * + ***FUNCTION: + * This is called to collect IBSS peer information + * from received Beacon/Probe Response frame from it. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param pMac - Pointer to Global MAC structure + * @param pBeacon - Parsed Beacon Frame structure + * @param pBD - Pointer to received BD + * @param pPeer - Pointer to IBSS peer node + * + * @return None + */ + +static void +ibss_peer_collect(tpAniSirGlobal pMac, + tpSchBeaconStruct pBeacon, + tpSirMacMgmtHdr pHdr, + tLimIbssPeerNode *pPeer, tpPESession psessionEntry) +{ + qdf_mem_copy(pPeer->peerMacAddr, pHdr->sa, sizeof(tSirMacAddr)); + + pPeer->capabilityInfo = pBeacon->capabilityInfo; + pPeer->extendedRatesPresent = pBeacon->extendedRatesPresent; + pPeer->edcaPresent = pBeacon->edcaPresent; + pPeer->wmeEdcaPresent = pBeacon->wmeEdcaPresent; + pPeer->wmeInfoPresent = pBeacon->wmeInfoPresent; + + if (pBeacon->IBSSParams.present) { + pPeer->atimIePresent = pBeacon->IBSSParams.present; + pPeer->peerAtimWindowLength = pBeacon->IBSSParams.atim; + } + + if (IS_DOT11_MODE_HT(psessionEntry->dot11mode) && + (pBeacon->HTCaps.present)) { + pPeer->htCapable = pBeacon->HTCaps.present; + qdf_mem_copy((uint8_t *) pPeer->supportedMCSSet, + (uint8_t *) pBeacon->HTCaps.supportedMCSSet, + sizeof(pPeer->supportedMCSSet)); + pPeer->htGreenfield = (uint8_t) pBeacon->HTCaps.greenField; + pPeer->htSupportedChannelWidthSet = + (uint8_t) pBeacon->HTCaps.supportedChannelWidthSet; + pPeer->htMIMOPSState = + (tSirMacHTMIMOPowerSaveState) pBeacon->HTCaps.mimoPowerSave; + pPeer->htMaxAmsduLength = + (uint8_t) pBeacon->HTCaps.maximalAMSDUsize; + pPeer->htAMpduDensity = pBeacon->HTCaps.mpduDensity; + pPeer->htDsssCckRate40MHzSupport = + (uint8_t) pBeacon->HTCaps.dsssCckMode40MHz; + pPeer->htShortGI20Mhz = (uint8_t) pBeacon->HTCaps.shortGI20MHz; + pPeer->htShortGI40Mhz = (uint8_t) pBeacon->HTCaps.shortGI40MHz; + pPeer->htMaxRxAMpduFactor = pBeacon->HTCaps.maxRxAMPDUFactor; + pPeer->htSecondaryChannelOffset = + pBeacon->HTInfo.secondaryChannelOffset; + pPeer->htLdpcCapable = (uint8_t) pBeacon->HTCaps.advCodingCap; + } + + /* Collect peer VHT capabilities based on the received beacon from the peer */ + if (pBeacon->VHTCaps.present) { + pPeer->vhtSupportedChannelWidthSet = + pBeacon->VHTOperation.chanWidth; + pPeer->vhtCapable = pBeacon->VHTCaps.present; + + /* Collect VHT capabilities from beacon */ + qdf_mem_copy((uint8_t *) &pPeer->VHTCaps, + (uint8_t *) &pBeacon->VHTCaps, + sizeof(tDot11fIEVHTCaps)); + } + pPeer->erpIePresent = pBeacon->erpPresent; + + qdf_mem_copy((uint8_t *) &pPeer->supportedRates, + (uint8_t *) &pBeacon->supportedRates, + pBeacon->supportedRates.numRates + 1); + if (pPeer->extendedRatesPresent) + qdf_mem_copy((uint8_t *) &pPeer->extendedRates, + (uint8_t *) &pBeacon->extendedRates, + pBeacon->extendedRates.numRates + 1); + else + pPeer->extendedRates.numRates = 0; + + pPeer->next = NULL; +} /*** end ibss_peer_collect() ***/ + +/* handle change in peer qos/wme capabilities */ +static void +ibss_sta_caps_update(tpAniSirGlobal pMac, + tLimIbssPeerNode *pPeerNode, tpPESession psessionEntry) +{ + uint16_t peerIdx; + tpDphHashNode pStaDs; + + pPeerNode->beaconHBCount++; /* Update beacon count. */ + + /* if the peer node exists, update its qos capabilities */ + pStaDs = dph_lookup_hash_entry(pMac, pPeerNode->peerMacAddr, &peerIdx, + &psessionEntry->dph.dphHashTable); + if (pStaDs == NULL) + return; + + /* Update HT Capabilities */ + if (IS_DOT11_MODE_HT(psessionEntry->dot11mode)) { + pStaDs->mlmStaContext.htCapability = pPeerNode->htCapable; + if (pPeerNode->htCapable) { + pStaDs->htGreenfield = pPeerNode->htGreenfield; + pStaDs->htSupportedChannelWidthSet = + pPeerNode->htSupportedChannelWidthSet; + pStaDs->htSecondaryChannelOffset = + pPeerNode->htSecondaryChannelOffset; + pStaDs->htMIMOPSState = pPeerNode->htMIMOPSState; + pStaDs->htMaxAmsduLength = pPeerNode->htMaxAmsduLength; + pStaDs->htAMpduDensity = pPeerNode->htAMpduDensity; + pStaDs->htDsssCckRate40MHzSupport = + pPeerNode->htDsssCckRate40MHzSupport; + pStaDs->htShortGI20Mhz = pPeerNode->htShortGI20Mhz; + pStaDs->htShortGI40Mhz = pPeerNode->htShortGI40Mhz; + pStaDs->htMaxRxAMpduFactor = + pPeerNode->htMaxRxAMpduFactor; + /* In the future, may need to check for "delayedBA" */ + /* For now, it is IMMEDIATE BA only on ALL TID's */ + pStaDs->baPolicyFlag = 0xFF; + pStaDs->htLdpcCapable = pPeerNode->htLdpcCapable; + } + } + if (IS_DOT11_MODE_VHT(psessionEntry->dot11mode)) { + pStaDs->mlmStaContext.vhtCapability = pPeerNode->vhtCapable; + if (pPeerNode->vhtCapable) { + pStaDs->vhtSupportedChannelWidthSet = + pPeerNode->vhtSupportedChannelWidthSet; + + /* If in 11AC mode and if session requires 11AC mode, consider peer's */ + /* max AMPDU length factor */ + pStaDs->htMaxRxAMpduFactor = + pPeerNode->VHTCaps.maxAMPDULenExp; + pStaDs->vhtLdpcCapable = + (uint8_t) pPeerNode->VHTCaps.ldpcCodingCap; + } + } + /* peer is 11e capable but is not 11e enabled yet */ + /* some STA's when joining Airgo IBSS, assert qos capability even when */ + /* they don't suport qos. however, they do not include the edca parameter */ + /* set. so let's check for edcaParam in addition to the qos capability */ + if (pPeerNode->capabilityInfo.qos && (psessionEntry->limQosEnabled) + && pPeerNode->edcaPresent) { + pStaDs->qosMode = 1; + pStaDs->wmeEnabled = 0; + if (!pStaDs->lleEnabled) { + pStaDs->lleEnabled = 1; + /* dphSetACM(pMac, pStaDs); */ + } + return; + } + /* peer is not 11e capable now but was 11e enabled earlier */ + else if (pStaDs->lleEnabled) { + pStaDs->qosMode = 0; + pStaDs->lleEnabled = 0; + } + /* peer is wme capable but is not wme enabled yet */ + if (pPeerNode->wmeInfoPresent && psessionEntry->limWmeEnabled) { + pStaDs->qosMode = 1; + pStaDs->lleEnabled = 0; + if (!pStaDs->wmeEnabled) { + pStaDs->wmeEnabled = 1; + } + return; + } + /* When the peer device supports EDCA parameters, then we were not + considering. Added this code when we saw that one of the Peer Device + was advertising WMM param where we were not honouring that. CR# 210756 + */ + if (pPeerNode->wmeEdcaPresent && psessionEntry->limWmeEnabled) { + pStaDs->qosMode = 1; + pStaDs->lleEnabled = 0; + if (!pStaDs->wmeEnabled) { + pStaDs->wmeEnabled = 1; + } + return; + } + /* peer is not wme capable now but was wme enabled earlier */ + else if (pStaDs->wmeEnabled) { + pStaDs->qosMode = 0; + pStaDs->wmeEnabled = 0; + } + +} + +static void +ibss_sta_rates_update(tpAniSirGlobal pMac, + tpDphHashNode pStaDs, + tLimIbssPeerNode *pPeer, tpPESession psessionEntry) +{ + lim_populate_matching_rate_set(pMac, pStaDs, &pPeer->supportedRates, + &pPeer->extendedRates, + pPeer->supportedMCSSet, psessionEntry, + &pPeer->VHTCaps); + pStaDs->mlmStaContext.capabilityInfo = pPeer->capabilityInfo; +} /*** end ibss_sta_info_update() ***/ + +/** + * ibss_sta_info_update + * + ***FUNCTION: + * This is called to program both SW & Polaris context + * for peer in IBSS. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param pMac - Pointer to Global MAC structure + * @param pStaDs - Pointer to DPH node + * @param pPeer - Pointer to IBSS peer node + * + * @return None + */ + +static void +ibss_sta_info_update(tpAniSirGlobal pMac, + tpDphHashNode pStaDs, + tLimIbssPeerNode *pPeer, tpPESession psessionEntry) +{ + pStaDs->staType = STA_ENTRY_PEER; + ibss_sta_caps_update(pMac, pPeer, psessionEntry); + ibss_sta_rates_update(pMac, pStaDs, pPeer, psessionEntry); +} /*** end ibss_sta_info_update() ***/ + +static void ibss_coalesce_free(tpAniSirGlobal pMac) +{ + if (pMac->lim.ibssInfo.pHdr != NULL) + qdf_mem_free(pMac->lim.ibssInfo.pHdr); + if (pMac->lim.ibssInfo.pBeacon != NULL) + qdf_mem_free(pMac->lim.ibssInfo.pBeacon); + + pMac->lim.ibssInfo.pHdr = NULL; + pMac->lim.ibssInfo.pBeacon = NULL; +} + +/* + * save the beacon params for use when adding the bss + */ +static void +ibss_coalesce_save(tpAniSirGlobal pMac, + tpSirMacMgmtHdr pHdr, tpSchBeaconStruct pBeacon) +{ + /* get rid of any saved info */ + ibss_coalesce_free(pMac); + + pMac->lim.ibssInfo.pHdr = qdf_mem_malloc(sizeof(*pHdr)); + if (NULL == pMac->lim.ibssInfo.pHdr) { + PELOGE(lim_log(pMac, LOGE, FL("ibbs-save: Failed malloc pHdr"));) + return; + } + pMac->lim.ibssInfo.pBeacon = qdf_mem_malloc(sizeof(*pBeacon)); + if (NULL == pMac->lim.ibssInfo.pBeacon) { + PELOGE(lim_log + (pMac, LOGE, FL("ibbs-save: Failed malloc pBeacon")); + ) + ibss_coalesce_free(pMac); + return; + } + + qdf_mem_copy(pMac->lim.ibssInfo.pHdr, pHdr, sizeof(*pHdr)); + qdf_mem_copy(pMac->lim.ibssInfo.pBeacon, pBeacon, sizeof(*pBeacon)); +} + +/* + * tries to add a new entry to dph hash node + * if necessary, an existing entry is eliminated + */ +static tSirRetStatus +ibss_dph_entry_add(tpAniSirGlobal pMac, + tSirMacAddr peerAddr, + tpDphHashNode *ppSta, tpPESession psessionEntry) +{ + uint16_t peerIdx; + tpDphHashNode pStaDs; + + *ppSta = NULL; + + pStaDs = + dph_lookup_hash_entry(pMac, peerAddr, &peerIdx, + &psessionEntry->dph.dphHashTable); + if (pStaDs != NULL) { + /* Trying to add context for already existing STA in IBSS */ + PELOGE(lim_log(pMac, LOGE, FL("STA exists already "));) + lim_print_mac_addr(pMac, peerAddr, LOGE); + return eSIR_FAILURE; + } + + /** + * Assign an AID, delete context existing with that + * AID and then add an entry to hash table maintained + * by DPH module. + */ + peerIdx = lim_assign_peer_idx(pMac, psessionEntry); + + pStaDs = + dph_get_hash_entry(pMac, peerIdx, &psessionEntry->dph.dphHashTable); + if (pStaDs) { + (void)lim_del_sta(pMac, pStaDs, false /*asynchronous */, + psessionEntry); + lim_delete_dph_hash_entry(pMac, pStaDs->staAddr, peerIdx, + psessionEntry); + } + + pStaDs = + dph_add_hash_entry(pMac, peerAddr, peerIdx, + &psessionEntry->dph.dphHashTable); + if (pStaDs == NULL) { + /* Could not add hash table entry */ + PELOGE(lim_log + (pMac, LOGE, + FL + ("could not add hash entry at DPH for peerIdx/aid=%d MACaddr:"), + peerIdx); + ) + lim_print_mac_addr(pMac, peerAddr, LOGE); + return eSIR_FAILURE; + } + + *ppSta = pStaDs; + return eSIR_SUCCESS; +} + +/* send a status change notification */ +static void +ibss_status_chg_notify(tpAniSirGlobal pMac, + tSirMacAddr peerAddr, + uint16_t staIndex, + uint8_t ucastSig, + uint8_t bcastSig, uint16_t status, uint8_t sessionId) +{ + + tLimIbssPeerNode *peerNode; + uint8_t *beacon = NULL; + uint16_t bcnLen = 0; + + peerNode = ibss_peer_find(pMac, peerAddr); + if (peerNode != NULL) { + if (peerNode->beacon == NULL) + peerNode->beaconLen = 0; + beacon = peerNode->beacon; + bcnLen = peerNode->beaconLen; + peerNode->beacon = NULL; + peerNode->beaconLen = 0; + } + + lim_send_sme_ibss_peer_ind(pMac, peerAddr, staIndex, ucastSig, bcastSig, + beacon, bcnLen, status, sessionId); + + if (beacon != NULL) { + qdf_mem_free(beacon); + } +} + +static void ibss_bss_add(tpAniSirGlobal pMac, tpPESession psessionEntry) +{ + tLimMlmStartReq mlmStartReq; + uint32_t cfg; + tpSirMacMgmtHdr pHdr = (tpSirMacMgmtHdr) pMac->lim.ibssInfo.pHdr; + tpSchBeaconStruct pBeacon = + (tpSchBeaconStruct) pMac->lim.ibssInfo.pBeacon; + uint8_t numExtRates = 0; + + if ((pHdr == NULL) || (pBeacon == NULL)) { + PELOGE(lim_log + (pMac, LOGE, + FL("Unable to add BSS (no cached BSS info)")); + ) + return; + } + + qdf_mem_copy(psessionEntry->bssId, pHdr->bssId, sizeof(tSirMacAddr)); + + sir_copy_mac_addr(pHdr->bssId, psessionEntry->bssId); + + /* Copy beacon interval from sessionTable */ + cfg = psessionEntry->beaconParams.beaconInterval; + if (cfg != pBeacon->beaconInterval) + psessionEntry->beaconParams.beaconInterval = + pBeacon->beaconInterval; + + /* This function ibss_bss_add (and hence the below code) is only called during ibss coalescing. We need to + * adapt to peer's capability with respect to short slot time. Changes have been made to lim_apply_configuration() + * so that the IBSS doesnt blindly start with short slot = 1. If IBSS start is part of coalescing then it will adapt + * to peer's short slot using code below. + */ + /* If cfg is already set to current peer's capability then no need to set it again */ + if (psessionEntry->shortSlotTimeSupported != + pBeacon->capabilityInfo.shortSlotTime) { + psessionEntry->shortSlotTimeSupported = + pBeacon->capabilityInfo.shortSlotTime; + } + qdf_mem_copy((uint8_t *) &psessionEntry->pLimStartBssReq-> + operationalRateSet, (uint8_t *) &pBeacon->supportedRates, + pBeacon->supportedRates.numRates); + + /** + * WNI_CFG_EXTENDED_OPERATIONAL_RATE_SET CFG needs to be reset, when + * there is no extended rate IE present in beacon. This is especially important when + * supportedRateSet IE contains all the extended rates as well and STA decides to coalesce. + * In this IBSS coalescing scenario LIM will tear down the BSS and Add a new one. So LIM needs to + * reset this CFG, just in case CSR originally had set this CFG when IBSS was started from the local profile. + * If IBSS was started by CSR from the BssDescription, then it would reset this CFG before StartBss is issued. + * The idea is that the count of OpRateSet and ExtendedOpRateSet rates should not be more than 12. + */ + + if (pBeacon->extendedRatesPresent) + numExtRates = pBeacon->extendedRates.numRates; + if (cfg_set_str(pMac, WNI_CFG_EXTENDED_OPERATIONAL_RATE_SET, + (uint8_t *) &pBeacon->extendedRates.rate, + numExtRates) != eSIR_SUCCESS) { + lim_log(pMac, LOGP, + FL("could not update ExtendedOperRateset at CFG")); + return; + } + + /* + * Each IBSS node will advertise its own HT Capabilities instead of adapting to the Peer's capabilities + * If we don't do this then IBSS may not go back to full capabilities when the STA with lower capabilities + * leaves the IBSS. e.g. when non-CB STA joins an IBSS and then leaves, the IBSS will be stuck at non-CB mode + * even though all the nodes are capable of doing CB. + * so it is decided to leave the self HT capabilties intact. This may change if some issues are found in interop. + */ + qdf_mem_set((void *)&mlmStartReq, sizeof(mlmStartReq), 0); + + qdf_mem_copy(mlmStartReq.bssId, pHdr->bssId, sizeof(tSirMacAddr)); + mlmStartReq.rateSet.numRates = + psessionEntry->pLimStartBssReq->operationalRateSet.numRates; + qdf_mem_copy(&mlmStartReq.rateSet.rate[0], + &psessionEntry->pLimStartBssReq->operationalRateSet. + rate[0], mlmStartReq.rateSet.numRates); + mlmStartReq.bssType = eSIR_IBSS_MODE; + mlmStartReq.beaconPeriod = pBeacon->beaconInterval; + mlmStartReq.nwType = psessionEntry->pLimStartBssReq->nwType; /* psessionEntry->nwType is also OK???? */ + mlmStartReq.htCapable = psessionEntry->htCapability; + mlmStartReq.htOperMode = pMac->lim.gHTOperMode; + mlmStartReq.dualCTSProtection = pMac->lim.gHTDualCTSProtection; + mlmStartReq.txChannelWidthSet = psessionEntry->htRecommendedTxWidthSet; + + /* reading the channel num from session Table */ + mlmStartReq.channelNumber = psessionEntry->currentOperChannel; + + mlmStartReq.cbMode = psessionEntry->pLimStartBssReq->cbMode; + + /* Copy the SSID for RxP filtering based on SSID. */ + qdf_mem_copy((uint8_t *) &mlmStartReq.ssId, + (uint8_t *) &psessionEntry->pLimStartBssReq->ssId, + psessionEntry->pLimStartBssReq->ssId.length + 1); + + PELOG1(lim_log + (pMac, LOG1, FL("invoking ADD_BSS as part of coalescing!")); + ) + if (lim_mlm_add_bss(pMac, &mlmStartReq, psessionEntry) != + eSIR_SME_SUCCESS) { + PELOGE(lim_log(pMac, LOGE, FL("AddBss failure"));) + return; + } + /* Update fields in Beacon */ + if (sch_set_fixed_beacon_fields(pMac, psessionEntry) != eSIR_SUCCESS) { + PELOGE(lim_log + (pMac, LOGE, + FL("*** Unable to set fixed Beacon fields ***")); + ) + return; + } + +} + +/* delete the current BSS */ +static void ibss_bss_delete(tpAniSirGlobal pMac, tpPESession psessionEntry) +{ + tSirRetStatus status; + PELOGW(lim_log(pMac, LOGW, FL("Initiating IBSS Delete BSS"));) + if (psessionEntry->limMlmState != eLIM_MLM_BSS_STARTED_STATE) { + lim_log(pMac, LOGW, + FL("Incorrect LIM MLM state for delBss (%d)"), + psessionEntry->limMlmState); + return; + } + status = lim_del_bss(pMac, NULL, psessionEntry->bssIdx, psessionEntry); + if (status != eSIR_SUCCESS) + PELOGE(lim_log + (pMac, LOGE, FL("delBss failed for bss %d"), + psessionEntry->bssIdx); + ) +} + +/** + * lim_ibss_init + * + ***FUNCTION: + * This function is called while starting an IBSS + * to initialize list used to maintain IBSS peers. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param pMac - Pointer to Global MAC structure + * @return None + */ + +void lim_ibss_init(tpAniSirGlobal pMac) +{ + pMac->lim.gLimIbssCoalescingHappened = 0; + pMac->lim.gLimIbssPeerList = NULL; + pMac->lim.gLimNumIbssPeers = 0; + + /* ibss info - params for which ibss to join while coalescing */ + qdf_mem_set(&pMac->lim.ibssInfo, sizeof(tAniSirLimIbss), 0); +} /*** end lim_ibss_init() ***/ + +/** + * lim_ibss_delete_all_peers + * + ***FUNCTION: + * This function is called to delete all peers. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param pMac - Pointer to Global MAC structure + * @return None + */ + +static void lim_ibss_delete_all_peers(tpAniSirGlobal pMac, + tpPESession psessionEntry) +{ + tLimIbssPeerNode *pCurrNode, *pTempNode; + tpDphHashNode pStaDs; + uint16_t peerIdx; + + pCurrNode = pTempNode = pMac->lim.gLimIbssPeerList; + + while (pCurrNode != NULL) { + if (!pMac->lim.gLimNumIbssPeers) { + lim_log(pMac, LOGP, + FL + ("Number of peers in the list is zero and node present")); + return; + } + /* Delete the dph entry for the station + * Since it is called to remove all peers, just delete from dph, + * no need to do any beacon related params i.e., dont call lim_delete_dph_hash_entry + */ + pStaDs = + dph_lookup_hash_entry(pMac, pCurrNode->peerMacAddr, &peerIdx, + &psessionEntry->dph.dphHashTable); + if (pStaDs) { + + ibss_status_chg_notify(pMac, pCurrNode->peerMacAddr, + pStaDs->staIndex, + pStaDs->ucUcastSig, + pStaDs->ucBcastSig, + eWNI_SME_IBSS_PEER_DEPARTED_IND, + psessionEntry->smeSessionId); + lim_release_peer_idx(pMac, peerIdx, psessionEntry); + dph_delete_hash_entry(pMac, pStaDs->staAddr, peerIdx, + &psessionEntry->dph.dphHashTable); + } + + pTempNode = pCurrNode->next; + + /* TODO :Sessionize this code */ + /* Fix CR 227642: PeerList should point to the next node since the current node is being + * freed in the next line. In ibss_peerfind in ibss_status_chg_notify above, we use this + * peer list to find the next peer. So this list needs to be updated with the no of peers left + * after each iteration in this while loop since one by one peers are deleted (freed) in this + * loop causing the lim.gLimIbssPeerList to point to some freed memory. + */ + pMac->lim.gLimIbssPeerList = pTempNode; + + if (pCurrNode->beacon) { + qdf_mem_free(pCurrNode->beacon); + } + qdf_mem_free(pCurrNode); + if (pMac->lim.gLimNumIbssPeers > 0) /* be paranoid */ + pMac->lim.gLimNumIbssPeers--; + pCurrNode = pTempNode; + } + + if (pMac->lim.gLimNumIbssPeers) + lim_log(pMac, LOGP, + FL("Number of peers[%d] in the list is non-zero"), + pMac->lim.gLimNumIbssPeers); + + pMac->lim.gLimNumIbssPeers = 0; + pMac->lim.gLimIbssPeerList = NULL; + +} + +/** + * lim_ibss_delete() - This function is called while tearing down an IBSS + * + * @pMac: Pointer to Global MAC structure + * @psessionEntry: Pointer to session entry + * + * Return: none + */ + +void lim_ibss_delete(tpAniSirGlobal pMac, tpPESession psessionEntry) +{ + lim_ibss_delete_all_peers(pMac, psessionEntry); + ibss_coalesce_free(pMac); +} + +/** ------------------------------------------------------------- + \fn lim_ibss_set_protection + \brief Decides all the protection related information. + \ + \param tpAniSirGlobal pMac + \param tSirMacAddr peerMacAddr + \param tpUpdateBeaconParams pBeaconParams + \return None + -------------------------------------------------------------*/ +static void +lim_ibss_set_protection(tpAniSirGlobal pMac, uint8_t enable, + tpUpdateBeaconParams pBeaconParams, + tpPESession psessionEntry) +{ + + if (!pMac->lim.cfgProtection.fromllb) { + PELOG1(lim_log + (pMac, LOG1, FL("protection from 11b is disabled")); + ) + return; + } + + if (enable) { + psessionEntry->gLim11bParams.protectionEnabled = true; + if (false == + psessionEntry->beaconParams. + llbCoexist /*pMac->lim.llbCoexist */) { + PELOGE(lim_log + (pMac, LOGE, FL("=> IBSS: Enable Protection ")); + ) + pBeaconParams->llbCoexist = + psessionEntry->beaconParams.llbCoexist = true; + pBeaconParams->paramChangeBitmap |= + PARAM_llBCOEXIST_CHANGED; + } + } else if (true == + psessionEntry->beaconParams. + llbCoexist /*pMac->lim.llbCoexist */) { + psessionEntry->gLim11bParams.protectionEnabled = false; + PELOGE(lim_log(pMac, LOGE, FL("===> IBSS: Disable protection "));) + pBeaconParams->llbCoexist = + psessionEntry->beaconParams.llbCoexist = false; + pBeaconParams->paramChangeBitmap |= PARAM_llBCOEXIST_CHANGED; + } + return; +} + +/** ------------------------------------------------------------- + \fn lim_ibss_update_protection_params + \brief Decides all the protection related information. + \ + \param tpAniSirGlobal pMac + \param tSirMacAddr peerMacAddr + \param tpUpdateBeaconParams pBeaconParams + \return None + -------------------------------------------------------------*/ +static void +lim_ibss_update_protection_params(tpAniSirGlobal pMac, + tSirMacAddr peerMacAddr, + tLimProtStaCacheType protStaCacheType, + tpPESession psessionEntry) +{ + uint32_t i; + + PELOG1(lim_log(pMac, LOG1, FL("A STA is associated:")); + lim_log(pMac, LOG1, FL("Addr : ")); + lim_print_mac_addr(pMac, peerMacAddr, LOG1); + ) + + for (i = 0; i < LIM_PROT_STA_CACHE_SIZE; i++) { + if (pMac->lim.protStaCache[i].active) { + PELOG1(lim_log(pMac, LOG1, FL("Addr: "));) + PELOG1(lim_print_mac_addr + (pMac, pMac->lim.protStaCache[i].addr, LOG1); + ) + + if (!qdf_mem_cmp(pMac->lim.protStaCache[i].addr, + peerMacAddr, + sizeof(tSirMacAddr))) { + PELOG1(lim_log + (pMac, LOG1, + FL + ("matching cache entry at %d already active."), + i); + ) + return; + } + } + } + + for (i = 0; i < LIM_PROT_STA_CACHE_SIZE; i++) { + if (!pMac->lim.protStaCache[i].active) + break; + } + + if (i >= LIM_PROT_STA_CACHE_SIZE) { + PELOGE(lim_log(pMac, LOGE, FL("No space in ProtStaCache"));) + return; + } + + qdf_mem_copy(pMac->lim.protStaCache[i].addr, + peerMacAddr, sizeof(tSirMacAddr)); + + pMac->lim.protStaCache[i].protStaCacheType = protStaCacheType; + pMac->lim.protStaCache[i].active = true; + if (eLIM_PROT_STA_CACHE_TYPE_llB == protStaCacheType) { + psessionEntry->gLim11bParams.numSta++; + } else if (eLIM_PROT_STA_CACHE_TYPE_llG == protStaCacheType) { + psessionEntry->gLim11gParams.numSta++; + } +} + +/** ------------------------------------------------------------- + \fn lim_ibss_decide_protection + \brief Decides all the protection related information. + \ + \param tpAniSirGlobal pMac + \param tSirMacAddr peerMacAddr + \param tpUpdateBeaconParams pBeaconParams + \return None + -------------------------------------------------------------*/ +static void +lim_ibss_decide_protection(tpAniSirGlobal pMac, tpDphHashNode pStaDs, + tpUpdateBeaconParams pBeaconParams, + tpPESession psessionEntry) +{ + tSirRFBand rfBand = SIR_BAND_UNKNOWN; + uint32_t phyMode; + tLimProtStaCacheType protStaCacheType = + eLIM_PROT_STA_CACHE_TYPE_INVALID; + + pBeaconParams->paramChangeBitmap = 0; + + if (NULL == pStaDs) { + PELOGE(lim_log(pMac, LOGE, FL("pStaDs is NULL"));) + return; + } + + lim_get_rf_band_new(pMac, &rfBand, psessionEntry); + if (SIR_BAND_2_4_GHZ == rfBand) { + lim_get_phy_mode(pMac, &phyMode, psessionEntry); + + /* We are 11G or 11n. Check if we need protection from 11b Stations. */ + if ((phyMode == WNI_CFG_PHY_MODE_11G) + || (psessionEntry->htCapability)) { + /* As we found in the past, it is possible that a 11n STA sends + * Beacon with HT IE but not ERP IE. So the absense of ERP IE + * in the Beacon is not enough to conclude that STA is 11b. + */ + if ((pStaDs->erpEnabled == eHAL_CLEAR) && + (!pStaDs->mlmStaContext.htCapability)) { + protStaCacheType = eLIM_PROT_STA_CACHE_TYPE_llB; + PELOGE(lim_log + (pMac, LOGE, + FL("Enable protection from 11B")); + ) + lim_ibss_set_protection(pMac, true, + pBeaconParams, + psessionEntry); + } + } + } + lim_ibss_update_protection_params(pMac, pStaDs->staAddr, protStaCacheType, + psessionEntry); + return; +} + +/** + * lim_ibss_peer_find() + * + ***FUNCTION: + * This function is called while adding a context at + * DPH & Polaris for a peer in IBSS. + * If peer is found in the list, capabilities from the + * returned BSS description are used at DPH node & Polaris. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param macAddr - MAC address of the peer + * + * @return Pointer to peer node if found, else NULL + */ +tLimIbssPeerNode *lim_ibss_peer_find(tpAniSirGlobal pMac, tSirMacAddr macAddr) +{ + return ibss_peer_find(pMac, macAddr); +} + +/** + * lim_ibss_sta_add() + * + ***FUNCTION: + * This function is called to add an STA context in IBSS role + * whenever a data frame is received from/for a STA that failed + * hash lookup at DPH. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param pMac Pointer to Global MAC structure + * @param peerAdddr MAC address of the peer being added + * @return retCode Indicates success or failure return code + * @return + */ + +tSirRetStatus +lim_ibss_sta_add(tpAniSirGlobal pMac, void *pBody, tpPESession psessionEntry) +{ + tSirRetStatus retCode = eSIR_SUCCESS; + tpDphHashNode pStaDs; + tLimIbssPeerNode *pPeerNode; + tLimMlmStates prevState; + tSirMacAddr *pPeerAddr = (tSirMacAddr *) pBody; + tUpdateBeaconParams beaconParams; + + qdf_mem_set((uint8_t *) &beaconParams, sizeof(tUpdateBeaconParams), 0); + + if (pBody == 0) { + PELOGE(lim_log(pMac, LOGE, FL("Invalid IBSS AddSta"));) + return eSIR_FAILURE; + } + + PELOGE(lim_log(pMac, LOGE, FL("Rx Add-Ibss-Sta for MAC:"));) + lim_print_mac_addr(pMac, *pPeerAddr, LOGE); + + pPeerNode = ibss_peer_find(pMac, *pPeerAddr); + if (NULL != pPeerNode) { + retCode = + ibss_dph_entry_add(pMac, *pPeerAddr, &pStaDs, + psessionEntry); + if (eSIR_SUCCESS == retCode) { + prevState = pStaDs->mlmStaContext.mlmState; + pStaDs->erpEnabled = pPeerNode->erpIePresent; + + ibss_sta_info_update(pMac, pStaDs, pPeerNode, + psessionEntry); + PELOGW(lim_log + (pMac, LOGW, + FL("initiating ADD STA for the IBSS peer.")); + ) + retCode = + lim_add_sta(pMac, pStaDs, false, psessionEntry); + if (retCode != eSIR_SUCCESS) { + PELOGE(lim_log + (pMac, LOGE, + FL("ibss-sta-add failed (reason %x)"), + retCode); + ) + lim_print_mac_addr(pMac, *pPeerAddr, LOGE); + pStaDs->mlmStaContext.mlmState = prevState; + dph_delete_hash_entry(pMac, pStaDs->staAddr, + pStaDs->assocId, + &psessionEntry->dph. + dphHashTable); + } else { + if (pMac->lim.gLimProtectionControl != + WNI_CFG_FORCE_POLICY_PROTECTION_DISABLE) + lim_ibss_decide_protection(pMac, pStaDs, + &beaconParams, + psessionEntry); + + if (beaconParams.paramChangeBitmap) { + PELOGE(lim_log + (pMac, LOGE, + FL + ("---> Update Beacon Params ")); + ) + sch_set_fixed_beacon_fields(pMac, + psessionEntry); + beaconParams.bssIdx = + psessionEntry->bssIdx; + lim_send_beacon_params(pMac, &beaconParams, + psessionEntry); + } + } + } else { + PELOGE(lim_log + (pMac, LOGE, FL("hashTblAdd failed (reason %x)"), + retCode); + ) + lim_print_mac_addr(pMac, *pPeerAddr, LOGE); + } + } else { + retCode = eSIR_FAILURE; + } + + return retCode; +} +/** + * __lim_ibss_search_and_delete_peer()- to cleanup the IBSS peer + * + * @mac_ptr: Pointer to Global MAC structure + * @session_entry: Session entry + * @mac_addr: Mac Address of the IBSS peer + * + * This function is called to cleanup the IBSS peer while + * operating in IBSS mode. + * + * Return: None + * + */ +static void +__lim_ibss_search_and_delete_peer(tpAniSirGlobal mac_ptr, + tpPESession session_entry, tSirMacAddr mac_addr) +{ + tLimIbssPeerNode *temp_node, *prev_node; + tLimIbssPeerNode *temp_next_node = NULL; + tpDphHashNode sta = NULL; + uint16_t peer_idx = 0; + uint16_t sta_index = 0; + uint8_t uc_ucast_sig; + uint8_t uc_bcast_sig; + + prev_node = temp_node = mac_ptr->lim.gLimIbssPeerList; + + lim_log(mac_ptr, LOG1, FL(" PEER ADDR :" MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(mac_addr)); + + /** Compare Peer */ + while (NULL != temp_node) { + temp_next_node = temp_node->next; + + /* Delete the STA with MAC address */ + if (!qdf_mem_cmp((uint8_t *) mac_addr, + (uint8_t *) &temp_node->peerMacAddr, + sizeof(tSirMacAddr))) { + sta = dph_lookup_hash_entry(mac_ptr, mac_addr, + &peer_idx, + &session_entry->dph. + dphHashTable); + if (sta) { + sta_index = sta->staIndex; + uc_ucast_sig = sta->ucUcastSig; + uc_bcast_sig = sta->ucBcastSig; + /* + * Send DEL STA only if ADD STA + * was success i.e staid is Valid. + */ + if (STA_INVALID_IDX != sta_index) + lim_del_sta(mac_ptr, sta, + false /*asynchronous */, + session_entry); + lim_delete_dph_hash_entry(mac_ptr, sta->staAddr, + peer_idx, session_entry); + lim_release_peer_idx(mac_ptr, + peer_idx, session_entry); + + /* + * Send indication to upper layers only if ADD + * STA was success i.e staid is Valid. + */ + if (STA_INVALID_IDX != sta_index) + ibss_status_chg_notify(mac_ptr, + mac_addr, sta_index, + uc_ucast_sig, uc_bcast_sig, + eWNI_SME_IBSS_PEER_DEPARTED_IND, + session_entry-> + smeSessionId); + if (temp_node == + mac_ptr->lim.gLimIbssPeerList) { + mac_ptr->lim.gLimIbssPeerList = + temp_node->next; + prev_node = + mac_ptr->lim.gLimIbssPeerList; + } else + prev_node->next = temp_node->next; + if (temp_node->beacon) + qdf_mem_free(temp_node->beacon); + + qdf_mem_free(temp_node); + mac_ptr->lim.gLimNumIbssPeers--; + + temp_node = temp_next_node; + break; + } + } + prev_node = temp_node; + temp_node = temp_next_node; + } + /* + * if it is the last peer walking out, we better + * we set IBSS state to inactive. + */ + if (0 == mac_ptr->lim.gLimNumIbssPeers) { + QDF_TRACE(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_INFO, + "Last STA from IBSS walked out"); + session_entry->limIbssActive = false; + } +} + +/* handle the response from HAL for an ADD STA request */ +tSirRetStatus +lim_ibss_add_sta_rsp(tpAniSirGlobal pMac, void *msg, tpPESession psessionEntry) +{ + tpDphHashNode pStaDs; + uint16_t peerIdx; + tpAddStaParams pAddStaParams = (tpAddStaParams) msg; + + SET_LIM_PROCESS_DEFD_MESGS(pMac, true); + if (pAddStaParams == NULL) { + lim_log(pMac, LOGE, FL("IBSS: ADD_STA_RSP with no body!")); + return eSIR_FAILURE; + } + + pStaDs = + dph_lookup_hash_entry(pMac, pAddStaParams->staMac, &peerIdx, + &psessionEntry->dph.dphHashTable); + if (pStaDs == NULL) { + lim_log(pMac, LOGE, + FL("IBSS: ADD_STA_RSP for unknown MAC addr: " + MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(pAddStaParams->staMac)); + qdf_mem_free(pAddStaParams); + return eSIR_FAILURE; + } + + if (pAddStaParams->status != QDF_STATUS_SUCCESS) { + lim_log(pMac, LOGE, + FL("IBSS: ADD_STA_RSP error (%x) for MAC: " + MAC_ADDRESS_STR), + pAddStaParams->status, + MAC_ADDR_ARRAY(pAddStaParams->staMac)); + __lim_ibss_search_and_delete_peer(pMac, + psessionEntry, pAddStaParams->staMac); + qdf_mem_free(pAddStaParams); + return eSIR_FAILURE; + } + + pStaDs->bssId = pAddStaParams->bssIdx; + pStaDs->staIndex = pAddStaParams->staIdx; + pStaDs->ucUcastSig = pAddStaParams->ucUcastSig; + pStaDs->ucBcastSig = pAddStaParams->ucBcastSig; + pStaDs->valid = 1; + pStaDs->mlmStaContext.mlmState = eLIM_MLM_LINK_ESTABLISHED_STATE; + + lim_log(pMac, LOGW, FL("IBSS: sending IBSS_NEW_PEER msg to SME!")); + + ibss_status_chg_notify(pMac, pAddStaParams->staMac, + pStaDs->staIndex, pStaDs->ucUcastSig, + pStaDs->ucBcastSig, + eWNI_SME_IBSS_NEW_PEER_IND, + psessionEntry->smeSessionId); + + qdf_mem_free(pAddStaParams); + + return eSIR_SUCCESS; +} + +void lim_ibss_del_bss_rsp_when_coalescing(tpAniSirGlobal pMac, void *msg, + tpPESession psessionEntry) +{ + tpDeleteBssParams pDelBss = (tpDeleteBssParams) msg; + + PELOGW(lim_log + (pMac, LOGW, FL("IBSS: DEL_BSS_RSP Rcvd during coalescing!")); + ) + + if (pDelBss == NULL) { + PELOGE(lim_log + (pMac, LOGE, + FL("IBSS: DEL_BSS_RSP(coalesce) with no body!")); + ) + goto end; + } + + if (pDelBss->status != QDF_STATUS_SUCCESS) { + lim_log(pMac, LOGE, + FL("IBSS: DEL_BSS_RSP(coalesce) error (%x) Bss %d "), + pDelBss->status, pDelBss->bssIdx); + goto end; + } + /* Delete peer entries. */ + lim_ibss_delete_all_peers(pMac, psessionEntry); + + /* add the new bss */ + ibss_bss_add(pMac, psessionEntry); + +end: + if (pDelBss != NULL) + qdf_mem_free(pDelBss); +} + +void lim_ibss_add_bss_rsp_when_coalescing(tpAniSirGlobal pMac, void *msg, + tpPESession pSessionEntry) +{ + uint8_t infoLen; + tSirSmeNewBssInfo newBssInfo; + + tpAddBssParams pAddBss = (tpAddBssParams) msg; + + tpSirMacMgmtHdr pHdr = (tpSirMacMgmtHdr) pMac->lim.ibssInfo.pHdr; + tpSchBeaconStruct pBeacon = + (tpSchBeaconStruct) pMac->lim.ibssInfo.pBeacon; + + if ((pHdr == NULL) || (pBeacon == NULL)) { + PELOGE(lim_log + (pMac, LOGE, + FL + ("Unable to handle AddBssRspWhenCoalescing (no cached BSS info)")); + ) + goto end; + } + /* Inform Host of IBSS coalescing */ + infoLen = sizeof(tSirMacAddr) + sizeof(tSirMacChanNum) + + sizeof(uint8_t) + pBeacon->ssId.length + 1; + + qdf_mem_set((void *)&newBssInfo, sizeof(newBssInfo), 0); + qdf_mem_copy(newBssInfo.bssId.bytes, pHdr->bssId, QDF_MAC_ADDR_SIZE); + newBssInfo.channelNumber = (tSirMacChanNum) pAddBss->currentOperChannel; + qdf_mem_copy((uint8_t *) &newBssInfo.ssId, + (uint8_t *) &pBeacon->ssId, pBeacon->ssId.length + 1); + + PELOGW(lim_log + (pMac, LOGW, FL("Sending JOINED_NEW_BSS notification to SME.")); + ) + + lim_send_sme_wm_status_change_ntf(pMac, eSIR_SME_JOINED_NEW_BSS, + (uint32_t *) &newBssInfo, + infoLen, pSessionEntry->smeSessionId); + { + /* Configure beacon and send beacons to HAL */ + lim_send_beacon_ind(pMac, pSessionEntry); + } + +end: + ibss_coalesce_free(pMac); +} + +void lim_ibss_del_bss_rsp(tpAniSirGlobal pMac, void *msg, tpPESession psessionEntry) +{ + tSirResultCodes rc = eSIR_SME_SUCCESS; + tpDeleteBssParams pDelBss = (tpDeleteBssParams) msg; + tSirMacAddr nullBssid = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + + SET_LIM_PROCESS_DEFD_MESGS(pMac, true); + if (pDelBss == NULL) { + PELOGE(lim_log + (pMac, LOGE, FL("IBSS: DEL_BSS_RSP with no body!")); + ) + rc = eSIR_SME_REFUSED; + goto end; + } + + psessionEntry = pe_find_session_by_session_id(pMac, pDelBss->sessionId); + if (psessionEntry == NULL) { + lim_log(pMac, LOGP, + FL("Session Does not exist for given sessionID")); + goto end; + } + + /* + * If delBss was issued as part of IBSS Coalescing, gLimIbssCoalescingHappened flag will be true. + * BSS has to be added again in this scenario, so this case needs to be handled separately. + * If delBss was issued as a result of trigger from SME_STOP_BSS Request, then limSme state changes to + * 'IDLE' and gLimIbssCoalescingHappened flag will be false. In this case STOP BSS RSP has to be sent to SME. + */ + if (true == pMac->lim.gLimIbssCoalescingHappened) { + + lim_ibss_del_bss_rsp_when_coalescing(pMac, msg, psessionEntry); + return; + } + + if (pDelBss->status != QDF_STATUS_SUCCESS) { + PELOGE(lim_log + (pMac, LOGE, FL("IBSS: DEL_BSS_RSP error (%x) Bss %d "), + pDelBss->status, pDelBss->bssIdx); + ) + rc = eSIR_SME_STOP_BSS_FAILURE; + goto end; + } + + if (lim_set_link_state(pMac, eSIR_LINK_IDLE_STATE, nullBssid, + psessionEntry->selfMacAddr, NULL, + NULL) != eSIR_SUCCESS) { + PELOGE(lim_log + (pMac, LOGE, + FL("IBSS: DEL_BSS_RSP setLinkState failed")); + ) + rc = eSIR_SME_REFUSED; + goto end; + } + + lim_ibss_delete(pMac, psessionEntry); + + dph_hash_table_class_init(pMac, &psessionEntry->dph.dphHashTable); + lim_delete_pre_auth_list(pMac); + + psessionEntry->limMlmState = eLIM_MLM_IDLE_STATE; + + MTRACE(mac_trace + (pMac, TRACE_CODE_MLM_STATE, psessionEntry->peSessionId, + psessionEntry->limMlmState)); + + psessionEntry->limSystemRole = eLIM_STA_ROLE; + + /* Change the short slot operating mode to Default (which is 1 for now) so that when IBSS starts next time with Libra + * as originator, it picks up the default. This enables us to remove hard coding of short slot = 1 from lim_apply_configuration + */ + psessionEntry->shortSlotTimeSupported = WNI_CFG_SHORT_SLOT_TIME_STADEF; + +end: + if (pDelBss != NULL) + qdf_mem_free(pDelBss); + /* Delete PE session once BSS is deleted */ + if (NULL != psessionEntry) { + lim_send_sme_rsp(pMac, eWNI_SME_STOP_BSS_RSP, rc, + psessionEntry->smeSessionId, + psessionEntry->transactionId); + pe_delete_session(pMac, psessionEntry); + psessionEntry = NULL; + } +} + +/** + * lim_ibss_coalesce() + * + ***FUNCTION: + * This function is called upon receiving Beacon/Probe Response + * while operating in IBSS mode. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param pMac - Pointer to Global MAC structure + * @param pBeacon - Parsed Beacon Frame structure + * @param pBD - Pointer to received BD + * + * @return Status whether to process or ignore received Beacon Frame + */ + +tSirRetStatus +lim_ibss_coalesce(tpAniSirGlobal pMac, + tpSirMacMgmtHdr pHdr, + tpSchBeaconStruct pBeacon, + uint8_t *pIEs, + uint32_t ieLen, uint16_t fTsfLater, tpPESession psessionEntry) +{ + uint16_t peerIdx; + tSirMacAddr currentBssId; + tLimIbssPeerNode *pPeerNode; + tpDphHashNode pStaDs; + tUpdateBeaconParams beaconParams; + + qdf_mem_set((uint8_t *) &beaconParams, sizeof(tUpdateBeaconParams), 0); + + sir_copy_mac_addr(currentBssId, psessionEntry->bssId); + + lim_log(pMac, LOG1, + FL("Current BSSID :" MAC_ADDRESS_STR " Received BSSID :" + MAC_ADDRESS_STR), MAC_ADDR_ARRAY(currentBssId), + MAC_ADDR_ARRAY(pHdr->bssId)); + + /* Check for IBSS Coalescing only if Beacon is from different BSS */ + if (qdf_mem_cmp(currentBssId, pHdr->bssId, sizeof(tSirMacAddr)) + && psessionEntry->isCoalesingInIBSSAllowed) { + /* + * If STA entry is already available in the LIM hash table, then it is + * possible that the peer may have left and rejoined within the heartbeat + * timeout. In the offloaded case with 32 peers, the HB timeout is whopping + * 128 seconds. In that case, the FW will not let any frames come in until + * atleast the last sequence number is received before the peer is left + * Hence, if the coalescing peer is already there in the peer list and if + * the BSSID matches then, invoke delSta() to cleanup the entries. We will + * let the peer coalesce when we receive next beacon from the peer + */ + pPeerNode = ibss_peer_find(pMac, pHdr->sa); + if (NULL != pPeerNode) { + __lim_ibss_search_and_delete_peer(pMac, psessionEntry, + pHdr->sa); + PELOGW(lim_log + (pMac, LOGW, + FL + ("** Peer attempting to reconnect before HB timeout, deleted **")); + ) + return eSIR_LIM_IGNORE_BEACON; + } + + if (!fTsfLater) { /* No Coalescing happened. */ + PELOGW(lim_log(pMac, LOGW, FL("No Coalescing happened"));) + return eSIR_LIM_IGNORE_BEACON; + } + /* + * IBSS Coalescing happened. + * save the received beacon, and delete the current BSS. The rest of the + * processing will be done in the delBss response processing + */ + pMac->lim.gLimIbssCoalescingHappened = true; + PELOGW(lim_log(pMac, LOGW, FL("IBSS Coalescing happened"));) + ibss_coalesce_save(pMac, pHdr, pBeacon); + lim_log(pMac, LOGW, FL("Delete BSSID :" MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(currentBssId)); + ibss_bss_delete(pMac, psessionEntry); + return eSIR_SUCCESS; + } else { + if (qdf_mem_cmp + (currentBssId, pHdr->bssId, sizeof(tSirMacAddr))) + return eSIR_LIM_IGNORE_BEACON; + } + + /* STA in IBSS mode and SSID matches with ours */ + pPeerNode = ibss_peer_find(pMac, pHdr->sa); + if (pPeerNode == NULL) { + /* Peer not in the list - Collect BSS description & add to the list */ + uint32_t frameLen; + tSirRetStatus retCode; + + /* + * Limit the Max number of IBSS Peers allowed as the max + * number of STA's allowed + * pMac->lim.gLimNumIbssPeers will be increamented after exiting + * this function. so we will add additional 1 to compare against + * pMac->lim.gLimIbssStaLimit + */ + if ((pMac->lim.gLimNumIbssPeers + 1) >= + pMac->lim.gLimIbssStaLimit) { + /*Print every 100th time */ + if (pMac->lim.ibss_retry_cnt % 100 == 0) { + PELOGE(lim_log(pMac, LOG1, + FL("**** MAX STA LIMIT HAS REACHED ****"));) + } + pMac->lim.ibss_retry_cnt++; + return eSIR_LIM_MAX_STA_REACHED_ERROR; + } + PELOGW(lim_log + (pMac, LOGW, + FL("IBSS Peer node does not exist, adding it***")); + ) + frameLen = + sizeof(tLimIbssPeerNode) + ieLen - sizeof(uint32_t); + + pPeerNode = qdf_mem_malloc((uint16_t) frameLen); + if (NULL == pPeerNode) { + lim_log(pMac, LOGP, + FL + ("alloc fail (%d bytes) storing IBSS peer info"), + frameLen); + return eSIR_MEM_ALLOC_FAILED; + } + + pPeerNode->beacon = NULL; + pPeerNode->beaconLen = 0; + + ibss_peer_collect(pMac, pBeacon, pHdr, pPeerNode, + psessionEntry); + pPeerNode->beacon = qdf_mem_malloc(ieLen); + if (NULL == pPeerNode->beacon) { + PELOGE(lim_log + (pMac, LOGE, + FL + ("Unable to allocate memory to store beacon")); + ) + } else { + qdf_mem_copy(pPeerNode->beacon, pIEs, ieLen); + pPeerNode->beaconLen = (uint16_t) ieLen; + } + ibss_peer_add(pMac, pPeerNode); + + pStaDs = + dph_lookup_hash_entry(pMac, pPeerNode->peerMacAddr, &peerIdx, + &psessionEntry->dph.dphHashTable); + if (pStaDs != NULL) { + /* / DPH node already exists for the peer */ + PELOGW(lim_log + (pMac, LOGW, + FL("DPH Node present for just learned peer")); + ) + PELOG1(lim_print_mac_addr + (pMac, pPeerNode->peerMacAddr, LOG1); + ) + ibss_sta_info_update(pMac, pStaDs, pPeerNode, + psessionEntry); + return eSIR_SUCCESS; + } + retCode = + lim_ibss_sta_add(pMac, pPeerNode->peerMacAddr, psessionEntry); + if (retCode != eSIR_SUCCESS) { + PELOGE(lim_log + (pMac, LOGE, + FL("lim-ibss-sta-add failed (reason %x)"), + retCode); + ) + lim_print_mac_addr(pMac, pPeerNode->peerMacAddr, LOGE); + return retCode; + } + /* Decide protection mode */ + pStaDs = + dph_lookup_hash_entry(pMac, pPeerNode->peerMacAddr, &peerIdx, + &psessionEntry->dph.dphHashTable); + if (pMac->lim.gLimProtectionControl != + WNI_CFG_FORCE_POLICY_PROTECTION_DISABLE) + lim_ibss_decide_protection(pMac, pStaDs, &beaconParams, + psessionEntry); + + if (beaconParams.paramChangeBitmap) { + PELOGE(lim_log + (pMac, LOGE, + FL + ("beaconParams.paramChangeBitmap=1 ---> Update Beacon Params ")); + ) + sch_set_fixed_beacon_fields(pMac, psessionEntry); + beaconParams.bssIdx = psessionEntry->bssIdx; + lim_send_beacon_params(pMac, &beaconParams, psessionEntry); + } + } else + ibss_sta_caps_update(pMac, pPeerNode, psessionEntry); + + if (psessionEntry->limSmeState != eLIM_SME_NORMAL_STATE) + return eSIR_SUCCESS; + + /* Received Beacon from same IBSS we're */ + /* currently part of. Inform Roaming algorithm */ + /* if not already that IBSS is active. */ + if (psessionEntry->limIbssActive == false) { + limResetHBPktCount(psessionEntry); + PELOGW(lim_log + (pMac, LOGW, + FL + ("Partner joined our IBSS, Sending IBSS_ACTIVE Notification to SME")); + ) + psessionEntry->limIbssActive = true; + lim_send_sme_wm_status_change_ntf(pMac, eSIR_SME_IBSS_ACTIVE, NULL, 0, + psessionEntry->smeSessionId); + } + + return eSIR_SUCCESS; +} /*** end lim_handle_ibs_scoalescing() ***/ + +/** + * lim_ibss_heart_beat_handle() - handle IBSS hearbeat failure + * + * @mac_ctx: global mac context + * @session: PE session entry + * + * Hanlde IBSS hearbeat failure. + * + * Return: None. + */ +void lim_ibss_heart_beat_handle(tpAniSirGlobal mac_ctx, tpPESession session) +{ + tLimIbssPeerNode *tempnode, *prevnode; + tLimIbssPeerNode *temp_next = NULL; + uint16_t peer_idx = 0; + tpDphHashNode stads = 0; + uint32_t threshold = 0; + uint16_t sta_idx = 0; + uint8_t ucast_sig = 0; + uint8_t bcast_sig = 0; + + /* + * MLM BSS is started and if PE in scanmode then MLM state will be + * waiting for probe resp. If Heart beat timeout triggers during this + * corner case then we need to reactivate HeartBeat timer. + */ + if (session->limMlmState != eLIM_MLM_BSS_STARTED_STATE) + return; + + /* If LinkMonitor is Disabled */ + if (!mac_ctx->sys.gSysEnableLinkMonitorMode) + return; + + prevnode = tempnode = mac_ctx->lim.gLimIbssPeerList; + threshold = (mac_ctx->lim.gLimNumIbssPeers / 4) + 1; + + /* Monitor the HeartBeat with the Individual PEERS in the IBSS */ + while (tempnode != NULL) { + temp_next = tempnode->next; + if (tempnode->beaconHBCount) { + /* There was a beacon for this peer during heart beat */ + tempnode->beaconHBCount = 0; + tempnode->heartbeatFailure = 0; + prevnode = tempnode; + tempnode = temp_next; + continue; + } + + /* There wasnt any beacon received during heartbeat timer. */ + tempnode->heartbeatFailure++; + lim_log(mac_ctx, LOGE, FL("Heartbeat fail = %d thres = %d"), + tempnode->heartbeatFailure, mac_ctx->lim.gLimNumIbssPeers); + if (tempnode->heartbeatFailure >= threshold) { + /* Remove this entry from the list. */ + stads = dph_lookup_hash_entry(mac_ctx, + tempnode->peerMacAddr, &peer_idx, + &session->dph.dphHashTable); + if (stads) { + sta_idx = stads->staIndex; + ucast_sig = stads->ucUcastSig; + bcast_sig = stads->ucBcastSig; + + (void)lim_del_sta(mac_ctx, stads, false, + session); + lim_delete_dph_hash_entry(mac_ctx, + stads->staAddr, peer_idx, session); + lim_release_peer_idx(mac_ctx, peer_idx, + session); + /* Send indication. */ + ibss_status_chg_notify(mac_ctx, + tempnode->peerMacAddr, sta_idx, + ucast_sig, bcast_sig, + eWNI_SME_IBSS_PEER_DEPARTED_IND, + session->smeSessionId); + } + if (tempnode == mac_ctx->lim.gLimIbssPeerList) { + mac_ctx->lim.gLimIbssPeerList = tempnode->next; + prevnode = mac_ctx->lim.gLimIbssPeerList; + } else { + prevnode->next = tempnode->next; + } + + if (tempnode->beacon) + qdf_mem_free(tempnode->beacon); + qdf_mem_free(tempnode); + mac_ctx->lim.gLimNumIbssPeers--; + + /* we deleted current node, so prevNode remains same. */ + tempnode = temp_next; + continue; + } + prevnode = tempnode; + tempnode = temp_next; + } + + /* + * General IBSS Activity Monitor, + * check if in IBSS Mode we are received any Beacons + */ + if (mac_ctx->lim.gLimNumIbssPeers) { + if (session->LimRxedBeaconCntDuringHB < + MAX_NO_BEACONS_PER_HEART_BEAT_INTERVAL) + mac_ctx->lim.gLimHeartBeatBeaconStats[ + session->LimRxedBeaconCntDuringHB]++; + else + mac_ctx->lim.gLimHeartBeatBeaconStats[0]++; + + /* Reset number of beacons received */ + limResetHBPktCount(session); + return; + } else { + lim_log(mac_ctx, LOGW, FL("Heartbeat Failure")); + mac_ctx->lim.gLimHBfailureCntInLinkEstState++; + + if (session->limIbssActive == true) { + /* + * We don't receive Beacon frames from any + * other STA in IBSS. Announce IBSS inactive + * to Roaming algorithm + */ + lim_log(mac_ctx, LOGW, FL("Alone in IBSS")); + session->limIbssActive = false; + + lim_send_sme_wm_status_change_ntf(mac_ctx, + eSIR_SME_IBSS_INACTIVE, NULL, 0, + session->smeSessionId); + } + } +} + +/** + * lim_ibss_decide_protection_on_delete() - decides protection related info. + * + * @mac_ctx: global mac context + * @stads: station hash node + * @bcn_param: beacon parameters + * @session: PE session entry + * + * Decides all the protection related information. + * + * Return: None + */ +void lim_ibss_decide_protection_on_delete(tpAniSirGlobal mac_ctx, + tpDphHashNode stads, + tpUpdateBeaconParams bcn_param, + tpPESession session) +{ + uint32_t phymode; + tHalBitVal erpenabled = eHAL_CLEAR; + tSirRFBand rfband = SIR_BAND_UNKNOWN; + uint32_t i; + + if (NULL == stads) + return; + + lim_get_rf_band_new(mac_ctx, &rfband, session); + if (SIR_BAND_2_4_GHZ != rfband) + return; + + lim_get_phy_mode(mac_ctx, &phymode, session); + erpenabled = stads->erpEnabled; + /* we are HT or 11G and 11B station is getting deleted. */ + if (((phymode == WNI_CFG_PHY_MODE_11G) || + session->htCapability) && (erpenabled == eHAL_CLEAR)) { + lim_log(mac_ctx, LOGE, + FL("(%d) A legacy STA is disassociated. Addr is "), + session->gLim11bParams.numSta); + lim_print_mac_addr(mac_ctx, stads->staAddr, LOGE); + if (session->gLim11bParams.numSta == 0) { + lim_log(mac_ctx, LOGE, + FL("No 11B STA exists. Disable protection.")); + lim_ibss_set_protection(mac_ctx, false, + bcn_param, session); + } + + for (i = 0; i < LIM_PROT_STA_CACHE_SIZE; i++) { + if (!mac_ctx->lim.protStaCache[i].active) + continue; + if (!qdf_mem_cmp(mac_ctx->lim.protStaCache[i].addr, + stads->staAddr, sizeof(tSirMacAddr))) { + session->gLim11bParams.numSta--; + mac_ctx->lim.protStaCache[i].active = false; + break; + } + } + + } +} + +/** ----------------------------------------------------------------- + \fn __lim_ibss_peer_inactivity_handler + \brief Internal function. Deletes FW indicated peer which is inactive + \ + \param tpAniSirGlobal pMac + \param tpPESession psessionEntry + \param tpSirIbssPeerInactivityInd peerInactivityInd + \return None + -----------------------------------------------------------------*/ +static void +__lim_ibss_peer_inactivity_handler(tpAniSirGlobal pMac, + tpPESession psessionEntry, + tpSirIbssPeerInactivityInd peerInactivityInd) +{ + if (psessionEntry->limMlmState != eLIM_MLM_BSS_STARTED_STATE) { + return; + } + + /* delete the peer for which heartbeat is observed */ + __lim_ibss_search_and_delete_peer(pMac, psessionEntry, + peerInactivityInd->peer_addr.bytes); +} + +/** ------------------------------------------------------------- + \fn lim_process_ibss_peer_inactivity + \brief Peer inactivity message handler + \ + \param tpAniSirGlobal pMac + \param void* buf + \return None + -------------------------------------------------------------*/ +void lim_process_ibss_peer_inactivity(tpAniSirGlobal pMac, void *buf) +{ + /* + * --------------- HEARTBEAT OFFLOAD CASE ------------------ + * This message handler is executed when the firmware identifies + * inactivity from one or more peer devices. We will come here + * for every inactive peer device + */ + uint8_t i; + + tSirIbssPeerInactivityInd *peerInactivityInd = + (tSirIbssPeerInactivityInd *) buf; + + /* + * If IBSS is not started or heartbeat offload is not enabled + * we should not handle this request + */ + if (eLIM_STA_IN_IBSS_ROLE != pMac->lim.gLimSystemRole && + !IS_IBSS_HEARTBEAT_OFFLOAD_FEATURE_ENABLE) { + return; + } + + /** If LinkMonitor is Disabled */ + if (!pMac->sys.gSysEnableLinkMonitorMode) { + return; + } + + for (i = 0; i < pMac->lim.maxBssId; i++) { + if (true == pMac->lim.gpSession[i].valid && + eSIR_IBSS_MODE == pMac->lim.gpSession[i].bssType) { + __lim_ibss_peer_inactivity_handler(pMac, + &pMac->lim.gpSession[i], + peerInactivityInd); + break; + } + } +} diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_ibss_peer_mgmt.h b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_ibss_peer_mgmt.h new file mode 100644 index 0000000000000000000000000000000000000000..9051fa2ddde9c81a28e8ef20db074894a293887e --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_ibss_peer_mgmt.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2011-2012, 2014, 2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * + * This file lim_ibss_peer_mgmt.h contains prototypes for + * the utility functions LIM uses to maintain peers in IBSS. + * Author: Chandra Modumudi + * Date: 03/12/04 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + */ + +#include "sir_common.h" +#include "lim_utils.h" + +void lim_ibss_init(tpAniSirGlobal); +void lim_ibss_delete(tpAniSirGlobal, tpPESession psessionEntry); +tSirRetStatus lim_ibss_coalesce(tpAniSirGlobal, tpSirMacMgmtHdr, + tpSchBeaconStruct, uint8_t *, uint32_t, uint16_t, + tpPESession); +tSirRetStatus lim_ibss_sta_add(tpAniSirGlobal, void *, tpPESession); +tSirRetStatus lim_ibss_add_sta_rsp(tpAniSirGlobal, void *, tpPESession); +tLimIbssPeerNode *lim_ibss_peer_find(tpAniSirGlobal pMac, tSirMacAddr macAddr); +void lim_ibss_del_bss_rsp(tpAniSirGlobal, void *, tpPESession); +void lim_ibss_del_bss_rsp_when_coalescing(tpAniSirGlobal, void *, tpPESession); +void lim_ibss_add_bss_rsp_when_coalescing(tpAniSirGlobal pMac, void *msg, + tpPESession pSessionEntry); +void lim_ibss_decide_protection_on_delete(tpAniSirGlobal pMac, tpDphHashNode pStaDs, + tpUpdateBeaconParams pBeaconParams, + tpPESession pSessionEntry); +void lim_ibss_heart_beat_handle(tpAniSirGlobal pMac, tpPESession psessionEntry); +void lim_process_ibss_peer_inactivity(tpAniSirGlobal pMac, void *buf); diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_link_monitoring_algo.c b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_link_monitoring_algo.c new file mode 100644 index 0000000000000000000000000000000000000000..b263037dd93ef8fb0fc4da092f77346d399bd79b --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_link_monitoring_algo.c @@ -0,0 +1,563 @@ +/* + * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * This file lim_link_monitoring_algo.cc contains the code for + * Link monitoring algorithm on AP and heart beat failure + * handling on STA. + * Author: Chandra Modumudi + * Date: 03/01/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + * + */ + +#include "ani_global.h" +#include "wni_cfg.h" +#include "cfg_api.h" + +#include "sch_api.h" +#include "utils_api.h" +#include "lim_assoc_utils.h" +#include "lim_types.h" +#include "lim_utils.h" +#include "lim_prop_exts_utils.h" + +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM /* FEATURE_WLAN_DIAG_SUPPORT */ +#include "host_diag_core_log.h" +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ +#include "lim_ft_defs.h" +#include "lim_session.h" +#include "lim_ser_des_utils.h" + +/** + * lim_delete_sta_util - utility function for deleting station context + * + * @mac_ctx: global MAC context + * @msg: pointer to delte station context + * @session_entry: PE session entry + * + * utility function called to clear up station context. + * + * Return: None. + */ +static void lim_delete_sta_util(tpAniSirGlobal mac_ctx, tpDeleteStaContext msg, + tpPESession session_entry) +{ + tpDphHashNode stads; + + lim_log(mac_ctx, LOGE, + FL("Deleting station: staId = %d, reasonCode = %d"), + msg->staId, msg->reasonCode); + + if (LIM_IS_IBSS_ROLE(session_entry)) { + return; + } + + stads = dph_lookup_assoc_id(mac_ctx, msg->staId, &msg->assocId, + &session_entry->dph.dphHashTable); + + if (!stads) { + lim_log(mac_ctx, LOGE, + FL("Invalid STA limSystemRole=%d"), + GET_LIM_SYSTEM_ROLE(session_entry)); + return; + } + stads->del_sta_ctx_rssi = msg->rssi; + + /* check and see if same staId. This is to avoid the scenario + * where we're trying to delete a staId we just added. + */ + if (stads->staIndex != msg->staId) { + lim_log(mac_ctx, LOGE, FL("staid mismatch: %d vs %d "), + stads->staIndex, msg->staId); + return; + } + + if (LIM_IS_AP_ROLE(session_entry)) { + lim_log(mac_ctx, LOG1, + FL("Delete Station staId: %d, assocId: %d"), + msg->staId, msg->assocId); + /* + * Check if Deauth/Disassoc is triggered from Host. + * If mlmState is in some transient state then + * don't trigger STA deletion to avoid the race + * condition. + */ + if ((stads && + ((stads->mlmStaContext.mlmState != + eLIM_MLM_LINK_ESTABLISHED_STATE) && + (stads->mlmStaContext.mlmState != + eLIM_MLM_WT_ASSOC_CNF_STATE) && + (stads->mlmStaContext.mlmState != + eLIM_MLM_ASSOCIATED_STATE)))) { + lim_log(mac_ctx, LOGE, + FL("Inv Del STA staId:%d, assocId:%d"), + msg->staId, msg->assocId); + return; + } else { + lim_send_disassoc_mgmt_frame(mac_ctx, + eSIR_MAC_DISASSOC_DUE_TO_INACTIVITY_REASON, + stads->staAddr, session_entry, false); + lim_trigger_sta_deletion(mac_ctx, stads, session_entry); + } + } else { +#ifdef FEATURE_WLAN_TDLS + if (LIM_IS_STA_ROLE(session_entry) && + STA_ENTRY_TDLS_PEER == stads->staType) { + /* + * TeardownLink with PEER reason code + * HAL_DEL_STA_REASON_CODE_KEEP_ALIVE means + * eSIR_MAC_TDLS_TEARDOWN_PEER_UNREACHABLE + */ + lim_send_sme_tdls_del_sta_ind(mac_ctx, stads, + session_entry, + eSIR_MAC_TDLS_TEARDOWN_PEER_UNREACHABLE); + } else { +#endif + /* TearDownLink with AP */ + tLimMlmDeauthInd mlm_deauth_ind; + lim_log(mac_ctx, LOGW, + FL("Delete Station (staId: %d, assocId: %d) "), + msg->staId, msg->assocId); + + if ((stads && + ((stads->mlmStaContext.mlmState != + eLIM_MLM_LINK_ESTABLISHED_STATE) && + (stads->mlmStaContext.mlmState != + eLIM_MLM_WT_ASSOC_CNF_STATE) && + (stads->mlmStaContext.mlmState != + eLIM_MLM_ASSOCIATED_STATE)))) { + + /* + * Received SIR_LIM_DELETE_STA_CONTEXT_IND for STA that + * does not have context or in some transit state. + * Log error + */ + lim_log(mac_ctx, LOGE, + FL("Received SIR_LIM_DELETE_STA_CONTEXT_IND for " + "STA that either has no context or " + "in some transit state, Addr = " + MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(msg->bssId)); + return; + } + + stads->mlmStaContext.disassocReason = + eSIR_MAC_DISASSOC_DUE_TO_INACTIVITY_REASON; + stads->mlmStaContext.cleanupTrigger = + eLIM_LINK_MONITORING_DEAUTH; + + /* Issue Deauth Indication to SME. */ + qdf_mem_copy((uint8_t *) &mlm_deauth_ind.peerMacAddr, + stads->staAddr, sizeof(tSirMacAddr)); + mlm_deauth_ind.reasonCode = + (uint8_t) stads->mlmStaContext.disassocReason; + mlm_deauth_ind.deauthTrigger = + stads->mlmStaContext.cleanupTrigger; + +#ifdef FEATURE_WLAN_TDLS + /* Delete all TDLS peers connected before leaving BSS */ + lim_delete_tdls_peers(mac_ctx, session_entry); +#endif + if (LIM_IS_STA_ROLE(session_entry)) + lim_post_sme_message(mac_ctx, LIM_MLM_DEAUTH_IND, + (uint32_t *) &mlm_deauth_ind); + + lim_send_sme_deauth_ind(mac_ctx, stads, session_entry); +#ifdef FEATURE_WLAN_TDLS + } +#endif + } +} + +/** + * lim_delete_sta_context() - delete sta context. + * + * @mac_ctx: global mac_ctx context + * @lim_msg: lim message. + * + * This function handles the message from HAL: WMA_DELETE_STA_CONTEXT_IND. + * This function validates that the given station id exist, and if so, + * deletes the station by calling lim_trigger_sta_deletion. + * + * Return: none + */ +void lim_delete_sta_context(tpAniSirGlobal mac_ctx, tpSirMsgQ lim_msg) +{ + tpDeleteStaContext msg = (tpDeleteStaContext) lim_msg->bodyptr; + tpPESession session_entry; + tpDphHashNode sta_ds; + + if (NULL == msg) { + lim_log(mac_ctx, LOGE, FL("Invalid body pointer in message")); + return; + } + session_entry = pe_find_session_by_sme_session_id(mac_ctx, msg->vdev_id); + if (NULL == session_entry) { + lim_log(mac_ctx, LOGE, + FL("session not found for given sme session")); + qdf_mem_free(msg); + return; + } + + switch (msg->reasonCode) { + case HAL_DEL_STA_REASON_CODE_KEEP_ALIVE: + if (LIM_IS_STA_ROLE(session_entry) && !msg->is_tdls) { + if (!((session_entry->limMlmState == + eLIM_MLM_LINK_ESTABLISHED_STATE) && + (session_entry->limSmeState != + eLIM_SME_WT_DISASSOC_STATE) && + (session_entry->limSmeState != + eLIM_SME_WT_DEAUTH_STATE))) { + lim_log(mac_ctx, LOGE, + FL("Do not process in limMlmState %s(%x) limSmeState %s(%x)"), + lim_mlm_state_str(session_entry->limMlmState), + session_entry->limMlmState, + lim_mlm_state_str(session_entry->limSmeState), + session_entry->limSmeState); + qdf_mem_free(msg); + return; + } + sta_ds = dph_get_hash_entry(mac_ctx, + DPH_STA_HASH_INDEX_PEER, + &session_entry->dph.dphHashTable); + if (NULL == sta_ds) { + lim_log(mac_ctx, LOGE, + FL("Dph entry not found.")); + qdf_mem_free(msg); + return; + } + lim_send_deauth_mgmt_frame(mac_ctx, + eSIR_MAC_DISASSOC_DUE_TO_INACTIVITY_REASON, + msg->addr2, session_entry, false); + lim_tear_down_link_with_ap(mac_ctx, + session_entry->peSessionId, + eSIR_MAC_UNSPEC_FAILURE_REASON); + /* only break for STA role (non TDLS) */ + break; + } + lim_delete_sta_util(mac_ctx, msg, session_entry); + break; + + case HAL_DEL_STA_REASON_CODE_UNKNOWN_A2: + lim_log(mac_ctx, LOGE, FL("Deleting Unknown station ")); + lim_print_mac_addr(mac_ctx, msg->addr2, LOGE); + lim_send_deauth_mgmt_frame(mac_ctx, + eSIR_MAC_CLASS3_FRAME_FROM_NON_ASSOC_STA_REASON, + msg->addr2, session_entry, false); + break; + + default: + lim_log(mac_ctx, LOGE, FL(" Unknown reason code ")); + break; + } + qdf_mem_free(msg); + lim_msg->bodyptr = NULL; + return; +} + +/** + * lim_trigger_sta_deletion() - + * This function is called to trigger STA context deletion. + * + * @param mac_ctx - Pointer to global MAC structure + * @param sta_ds - Pointer to internal STA Datastructure + * @session_entry: PE session entry + + * @return None + */ +void +lim_trigger_sta_deletion(tpAniSirGlobal mac_ctx, tpDphHashNode sta_ds, + tpPESession session_entry) +{ + tLimMlmDisassocInd mlm_disassoc_ind; + + if (!sta_ds) { + lim_log(mac_ctx, LOGW, FL("Skip STA deletion (invalid STA)")); + return; + } + + if ((sta_ds->mlmStaContext.mlmState == eLIM_MLM_WT_DEL_STA_RSP_STATE) || + (sta_ds->mlmStaContext.mlmState == + eLIM_MLM_WT_DEL_BSS_RSP_STATE) || + sta_ds->sta_deletion_in_progress) { + /* Already in the process of deleting context for the peer */ + lim_log(mac_ctx, LOG1, + FL("Deletion is in progress (%d) for peer:%p in mlmState %d"), + sta_ds->sta_deletion_in_progress, sta_ds->staAddr, + sta_ds->mlmStaContext.mlmState); + return; + } + sta_ds->sta_deletion_in_progress = true; + + sta_ds->mlmStaContext.disassocReason = + eSIR_MAC_DISASSOC_DUE_TO_INACTIVITY_REASON; + sta_ds->mlmStaContext.cleanupTrigger = eLIM_LINK_MONITORING_DISASSOC; + qdf_mem_copy(&mlm_disassoc_ind.peerMacAddr, sta_ds->staAddr, + sizeof(tSirMacAddr)); + mlm_disassoc_ind.reasonCode = + eSIR_MAC_DISASSOC_DUE_TO_INACTIVITY_REASON; + mlm_disassoc_ind.disassocTrigger = eLIM_LINK_MONITORING_DISASSOC; + + /* Update PE session Id */ + mlm_disassoc_ind.sessionId = session_entry->peSessionId; + lim_post_sme_message(mac_ctx, LIM_MLM_DISASSOC_IND, + (uint32_t *) &mlm_disassoc_ind); + if (mac_ctx->roam.configParam.enable_fatal_event) + cds_flush_logs(WLAN_LOG_TYPE_FATAL, + WLAN_LOG_INDICATOR_HOST_DRIVER, + WLAN_LOG_REASON_HB_FAILURE, + false, false); + /* Issue Disassoc Indication to SME */ + lim_send_sme_disassoc_ind(mac_ctx, sta_ds, session_entry); +} /*** end lim_trigger_st_adeletion() ***/ + +/** + * lim_tear_down_link_with_ap() + * + ***FUNCTION: + * This function is called when heartbeat (beacon reception) + * fails on STA + * + ***LOGIC: + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param pMac - Pointer to Global MAC structure + * @return None + */ + +void +lim_tear_down_link_with_ap(tpAniSirGlobal pMac, uint8_t sessionId, + tSirMacReasonCodes reasonCode) +{ + tpDphHashNode pStaDs = NULL; + + /* tear down the following sessionEntry */ + tpPESession psessionEntry; + + psessionEntry = pe_find_session_by_session_id(pMac, sessionId); + if (psessionEntry == NULL) { + lim_log(pMac, LOGP, + FL("Session Does not exist for given sessionID")); + return; + } + /** + * Heart beat failed for upto threshold value + * and AP did not respond for Probe request. + * Trigger link tear down. + */ + psessionEntry->pmmOffloadInfo.bcnmiss = false; + + lim_log(pMac, LOGW, + FL("No ProbeRsp from AP after HB failure. Tearing down link")); + + /* Announce loss of link to Roaming algorithm */ + /* and cleanup by sending SME_DISASSOC_REQ to SME */ + + pStaDs = + dph_get_hash_entry(pMac, DPH_STA_HASH_INDEX_PEER, + &psessionEntry->dph.dphHashTable); + + if (pStaDs != NULL) { + tLimMlmDeauthInd mlmDeauthInd; + +#ifdef FEATURE_WLAN_TDLS + /* Delete all TDLS peers connected before leaving BSS */ + lim_delete_tdls_peers(pMac, psessionEntry); +#endif + + pStaDs->mlmStaContext.disassocReason = reasonCode; + pStaDs->mlmStaContext.cleanupTrigger = + eLIM_LINK_MONITORING_DEAUTH; + /* / Issue Deauth Indication to SME. */ + qdf_mem_copy((uint8_t *) &mlmDeauthInd.peerMacAddr, + pStaDs->staAddr, sizeof(tSirMacAddr)); + + /* + * if sendDeauthBeforeCon is enabled and reasoncode is + * Beacon Missed Store the MAC of AP in the flip flop + * buffer. This MAC will be used to send Deauth before + * connection, if we connect to same AP after HB failure. + */ + if (pMac->roam.configParam.sendDeauthBeforeCon && + eSIR_BEACON_MISSED == reasonCode) { + int apCount = pMac->lim.gLimHeartBeatApMacIndex; + + if (pMac->lim.gLimHeartBeatApMacIndex) + pMac->lim.gLimHeartBeatApMacIndex = 0; + else + pMac->lim.gLimHeartBeatApMacIndex = 1; + + lim_log(pMac, LOGE, FL("HB Failure on MAC " + MAC_ADDRESS_STR" Store it on Index %d"), + MAC_ADDR_ARRAY(pStaDs->staAddr), apCount); + + sir_copy_mac_addr(pMac->lim.gLimHeartBeatApMac[apCount], + pStaDs->staAddr); + } + + mlmDeauthInd.reasonCode = + (uint8_t) pStaDs->mlmStaContext.disassocReason; + mlmDeauthInd.deauthTrigger = + pStaDs->mlmStaContext.cleanupTrigger; + + if (LIM_IS_STA_ROLE(psessionEntry)) + lim_post_sme_message(pMac, LIM_MLM_DEAUTH_IND, + (uint32_t *) &mlmDeauthInd); + if (pMac->roam.configParam.enable_fatal_event) + cds_flush_logs(WLAN_LOG_TYPE_FATAL, + WLAN_LOG_INDICATOR_HOST_DRIVER, + WLAN_LOG_REASON_HB_FAILURE, + false, false); + + lim_send_sme_deauth_ind(pMac, pStaDs, psessionEntry); + } +} /*** lim_tear_down_link_with_ap() ***/ + +/** + * lim_handle_heart_beat_failure() - handle hear beat failure in STA + * + * @mac_ctx: global MAC context + * @session: PE session entry + * + * This function is called when heartbeat (beacon reception) + * fails on STA + * + * Return: None + */ + +void lim_handle_heart_beat_failure(tpAniSirGlobal mac_ctx, + tpPESession session) +{ + uint8_t curr_chan; + tpSirAddie scan_ie = NULL; + +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM /* FEATURE_WLAN_DIAG_SUPPORT */ + host_log_beacon_update_pkt_type *log_ptr = NULL; +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM /* FEATURE_WLAN_DIAG_SUPPORT */ + WLAN_HOST_DIAG_LOG_ALLOC(log_ptr, host_log_beacon_update_pkt_type, + LOG_WLAN_BEACON_UPDATE_C); + if (log_ptr) + log_ptr->bcn_rx_cnt = session->LimRxedBeaconCntDuringHB; + WLAN_HOST_DIAG_LOG_REPORT(log_ptr); +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + + /* Ensure HB Status for the session has been reseted */ + session->LimHBFailureStatus = false; + + if (LIM_IS_STA_ROLE(session) && + (session->limMlmState == eLIM_MLM_LINK_ESTABLISHED_STATE) && + (session->limSmeState != eLIM_SME_WT_DISASSOC_STATE) && + (session->limSmeState != eLIM_SME_WT_DEAUTH_STATE)) { + if (!mac_ctx->sys.gSysEnableLinkMonitorMode) + return; + + /* Ignore HB if channel switch is in progress */ + if (session->gLimSpecMgmt.dot11hChanSwState == + eLIM_11H_CHANSW_RUNNING) { + lim_log(mac_ctx, LOGE, + FL("Ignore Heartbeat failure as Channel switch is in progress")); + session->pmmOffloadInfo.bcnmiss = false; + return; + } + /* Beacon frame not received within heartbeat timeout. */ + lim_log(mac_ctx, LOGW, FL("Heartbeat Failure")); + mac_ctx->lim.gLimHBfailureCntInLinkEstState++; + + /* + * Check if connected on the DFS channel, if not connected on + * DFS channel then only send the probe request otherwise tear + * down the link + */ + curr_chan = session->currentOperChannel; + if (!lim_isconnected_on_dfs_channel(curr_chan)) { + /* Detected continuous Beacon Misses */ + session->LimHBFailureStatus = true; + + /*Reset the HB packet count before sending probe*/ + limResetHBPktCount(session); + /** + * Send Probe Request frame to AP to see if + * it is still around. Wait until certain + * timeout for Probe Response from AP. + */ + lim_log(mac_ctx, LOGW, + FL("HB missed from AP. Sending Probe Req")); + /* for searching AP, we don't include any more IE */ + if (session->pLimJoinReq != NULL) { + scan_ie = &session->pLimJoinReq->addIEScan; + lim_send_probe_req_mgmt_frame(mac_ctx, + &session->ssId, + session->bssId, curr_chan, + session->selfMacAddr, + session->dot11mode, + scan_ie->length, scan_ie->addIEdata); + } else { + lim_send_probe_req_mgmt_frame(mac_ctx, + &session->ssId, + session->bssId, curr_chan, + session->selfMacAddr, + session->dot11mode, 0, NULL); + } + } else { + lim_log(mac_ctx, LOGW, + FL("HB missed from AP on DFS chanel moving to passive")); + if (curr_chan < SIR_MAX_24G_5G_CHANNEL_RANGE) { + lim_covert_channel_scan_type(mac_ctx, curr_chan, + false); + mac_ctx->lim.dfschannelList. + timeStamp[curr_chan] = 0; + } + /* + * Connected on DFS channel so should not send the + * probe request tear down the link directly + */ + lim_tear_down_link_with_ap(mac_ctx, + session->peSessionId, + eSIR_BEACON_MISSED); + } + } else { + /** + * Heartbeat timer may have timed out + * while we're doing background scanning/learning + * or in states other than link-established state. + * Log error. + */ + lim_log(mac_ctx, LOG1, + FL("received heartbeat timeout in state %X"), + session->limMlmState); + lim_print_mlm_state(mac_ctx, LOG1, session->limMlmState); + mac_ctx->lim.gLimHBfailureCntInOtherStates++; + } +} diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_p2p.c b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_p2p.c new file mode 100644 index 0000000000000000000000000000000000000000..33696820b099e3fc3ef7fd3068a58520a76a2f9d --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_p2p.c @@ -0,0 +1,768 @@ +/* + * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/*=========================================================================== + L I M _ P 2 P . C + + OVERVIEW: + + This software unit holds the implementation of the WLAN Protocol Engine for + P2P. + ===========================================================================*/ + +/*=========================================================================== + + EDIT HISTORY FOR FILE + + This section contains comments describing changes made to the module. + Notice that changes are listed in reverse chronological order. + + $Header$$DateTime$$Author$ + + when who what, where, why + ---------- --- -------------------------------------------------------- + 2011-05-02 djindal Corrected file indentation and changed remain on channel + handling for concurrency. + ===========================================================================*/ + +#include "lim_utils.h" +#include "lim_session_utils.h" +#include "wma_types.h" +#include "lim_types.h" + +#define PROBE_RSP_IE_OFFSET 36 +#define BSSID_OFFSET 16 +#define ADDR2_OFFSET 10 +#define ACTION_OFFSET 24 + +/* A DFS channel can be ACTIVE for max 9000 msec, from the last + received Beacon/Prpbe Resp. */ +#define MAX_TIME_TO_BE_ACTIVE_CHANNEL 9000 + +void lim_exit_remain_on_channel(tpAniSirGlobal pMac, QDF_STATUS status, + uint32_t *data, tpPESession psessionEntry); +extern tSirRetStatus lim_set_link_state(tpAniSirGlobal pMac, tSirLinkState state, + tSirMacAddr bssId, tSirMacAddr selfMacAddr, + tpSetLinkStateCallback callback, + void *callbackArg); + +/*------------------------------------------------------------------ + * + * Below function is called if hdd requests a remain on channel. + * + *------------------------------------------------------------------*/ +static QDF_STATUS lim_send_hal_req_remain_on_chan_offload(tpAniSirGlobal pMac, + tSirRemainOnChnReq * + pRemOnChnReq) +{ + tSirScanOffloadReq *pScanOffloadReq; + tSirMsgQ msg; + tSirRetStatus rc = eSIR_SUCCESS; + + pScanOffloadReq = qdf_mem_malloc(sizeof(tSirScanOffloadReq)); + if (NULL == pScanOffloadReq) { + lim_log(pMac, LOGE, + FL("Memory allocation failed for pScanOffloadReq")); + return QDF_STATUS_E_NOMEM; + } + + msg.type = WMA_START_SCAN_OFFLOAD_REQ; + msg.bodyptr = pScanOffloadReq; + msg.bodyval = 0; + + qdf_copy_macaddr(&pScanOffloadReq->selfMacAddr, + &pRemOnChnReq->selfMacAddr); + + qdf_set_macaddr_broadcast(&pScanOffloadReq->bssId); + pScanOffloadReq->scanType = eSIR_PASSIVE_SCAN; + pScanOffloadReq->p2pScanType = P2P_SCAN_TYPE_LISTEN; + pScanOffloadReq->minChannelTime = pRemOnChnReq->duration; + pScanOffloadReq->maxChannelTime = pRemOnChnReq->duration; + pScanOffloadReq->sessionId = pRemOnChnReq->sessionId; + pScanOffloadReq->channelList.numChannels = 1; + pScanOffloadReq->channelList.channelNumber[0] = pRemOnChnReq->chnNum; + pScanOffloadReq->scan_id = pRemOnChnReq->scan_id; + pScanOffloadReq->scan_requestor_id = ROC_SCAN_REQUESTOR_ID; + + lim_log(pMac, LOG1, + FL("Req-rem-on-channel: duration %u, session %hu, chan %hu"), + pRemOnChnReq->duration, pRemOnChnReq->sessionId, + pRemOnChnReq->chnNum); + + rc = wma_post_ctrl_msg(pMac, &msg); + if (rc != eSIR_SUCCESS) { + lim_log(pMac, LOGE, FL("wma_post_ctrl_msg() return failure %u"), + rc); + qdf_mem_free(pScanOffloadReq); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/*------------------------------------------------------------------ + * + * Remain on channel req handler. Initiate the INIT_SCAN, CHN_CHANGE + * and SET_LINK Request from SME, chnNum and duration to remain on channel. + * + *------------------------------------------------------------------*/ +int lim_process_remain_on_chnl_req(tpAniSirGlobal pMac, uint32_t *pMsg) +{ + tSirRemainOnChnReq *msgbuff = (tSirRemainOnChnReq *) pMsg; + QDF_STATUS status; + + pMac->lim.gpLimRemainOnChanReq = msgbuff; + status = lim_send_hal_req_remain_on_chan_offload(pMac, msgbuff); + if (status != QDF_STATUS_SUCCESS) { + /* Post the meessage to Sme */ + lim_send_sme_rsp(pMac, eWNI_SME_REMAIN_ON_CHN_RSP, + status, msgbuff->sessionId, msgbuff->scan_id); + qdf_mem_free(pMac->lim.gpLimRemainOnChanReq); + pMac->lim.gpLimRemainOnChanReq = NULL; + } + return false; +} + +/*------------------------------------------------------------------ + * + * lim Insert NOA timer timeout callback - when timer fires, deactivate it and send + * scan rsp to csr/hdd + * + *------------------------------------------------------------------*/ +void lim_process_insert_single_shot_noa_timeout(tpAniSirGlobal pMac) +{ + /* timeout means start NOA did not arrive; we need to deactivate and change the timer for + * future activations + */ + lim_deactivate_and_change_timer(pMac, eLIM_INSERT_SINGLESHOT_NOA_TIMER); + + /* Even if insert NOA timedout, go ahead and process/send stored SME request */ + lim_process_regd_defd_sme_req_after_noa_start(pMac); + + return; +} + +/*----------------------------------------------------------------- + * lim Insert Timer callback function to check active DFS channels + * and convert them to passive channels if there was no + * beacon/proberesp for MAX_TIME_TO_BE_ACTIVE_CHANNEL time + *------------------------------------------------------------------*/ +void lim_convert_active_channel_to_passive_channel(tpAniSirGlobal pMac) +{ + uint64_t currentTime; + uint64_t lastTime = 0; + uint64_t timeDiff; + uint8_t i; + currentTime = (uint64_t)qdf_mc_timer_get_system_time(); + for (i = 1; i < SIR_MAX_24G_5G_CHANNEL_RANGE; i++) { + if ((pMac->lim.dfschannelList.timeStamp[i]) != 0) { + lastTime = pMac->lim.dfschannelList.timeStamp[i]; + if (currentTime >= lastTime) { + timeDiff = (currentTime - lastTime); + } else { + timeDiff = + (0xFFFFFFFF - lastTime) + currentTime; + } + + if (timeDiff >= MAX_TIME_TO_BE_ACTIVE_CHANNEL) { + lim_covert_channel_scan_type(pMac, i, false); + pMac->lim.dfschannelList.timeStamp[i] = 0; + } + } + } + /* lastTime is zero if there is no DFS active channels in the list. + * If this is non zero then we have active DFS channels so restart the timer. + */ + if (lastTime != 0) { + if (tx_timer_activate + (&pMac->lim.limTimers.gLimActiveToPassiveChannelTimer) + != TX_SUCCESS) { + lim_log(pMac, LOGE, + FL + ("Could not activate Active to Passive Channel timer")); + } + } + + return; + +} + +/** + * lim_process_remain_on_chn_timeout() - ROC timeout handler + * + * @mac_ctx: MAC context + * + * limchannelchange callback, on success channel change, set the + * link_state to LISTEN + * + * Return: NULL + */ +void lim_process_remain_on_chn_timeout(tpAniSirGlobal mac_ctx) +{ + tpPESession session; + tSirMacAddr null_bssid = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + TX_TIMER *roc_timer; + + roc_timer = &mac_ctx->lim.limTimers.gLimRemainOnChannelTimer; + /* + * Timer might get extended while Sending Action Frame + * In that case don't process Channel Timeout + */ + if (tx_timer_running(roc_timer)) { + lim_log(mac_ctx, LOGE, + FL("already timer is running and not processing ")); + return; + } + + lim_deactivate_and_change_timer(mac_ctx, eLIM_REMAIN_CHN_TIMER); + if (NULL == mac_ctx->lim.gpLimRemainOnChanReq) { + lim_log(mac_ctx, LOGE, FL("No Remain on channel pending")); + return; + } + + /* get the previous valid LINK state */ + if (lim_set_link_state(mac_ctx, eSIR_LINK_IDLE_STATE, null_bssid, + mac_ctx->lim.gSelfMacAddr, NULL, NULL) != eSIR_SUCCESS) { + lim_log(mac_ctx, LOGE, FL("Unable to change link state")); + return; + } + + if (mac_ctx->lim.gLimMlmState != eLIM_MLM_P2P_LISTEN_STATE) { + lim_remain_on_chn_rsp(mac_ctx, QDF_STATUS_SUCCESS, NULL); + } else { + session = pe_find_session_by_session_id(mac_ctx, + roc_timer->sessionId); + /* get the session */ + if (session == NULL) { + lim_log(mac_ctx, LOGE, + FL("Session Does not exist sessionID %d"), + roc_timer->sessionId); + goto error; + } + + lim_exit_remain_on_channel(mac_ctx, QDF_STATUS_SUCCESS, NULL, + session); + return; +error: + lim_remain_on_chn_rsp(mac_ctx, QDF_STATUS_E_FAILURE, NULL); + } + return; +} + +/*------------------------------------------------------------------ + * + * limchannelchange callback, on success channel change, set the link_state + * to LISTEN + * + *------------------------------------------------------------------*/ + +void lim_exit_remain_on_channel(tpAniSirGlobal pMac, QDF_STATUS status, + uint32_t *data, tpPESession psessionEntry) +{ + + if (status != QDF_STATUS_SUCCESS) { + PELOGE(lim_log(pMac, LOGE, "Remain on Channel Failed");) + goto error; + } + /* Set the resume channel to Any valid channel (invalid). */ + /* This will instruct HAL to set it to any previous valid channel. */ + pe_set_resume_channel(pMac, 0, 0); + lim_remain_on_chn_rsp(pMac, QDF_STATUS_SUCCESS, NULL); + return; +error: + lim_remain_on_chn_rsp(pMac, QDF_STATUS_E_FAILURE, NULL); + return; +} + +/*------------------------------------------------------------------ + * + * Send remain on channel respone: Success/ Failure + * + *------------------------------------------------------------------*/ +void lim_remain_on_chn_rsp(tpAniSirGlobal pMac, QDF_STATUS status, uint32_t *data) +{ + tpPESession psessionEntry; + uint8_t sessionId; + tSirRemainOnChnReq *MsgRemainonChannel = pMac->lim.gpLimRemainOnChanReq; + tSirMacAddr nullBssid = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + + if (NULL == MsgRemainonChannel) { + PELOGE(lim_log(pMac, LOGP, + "%s: No Pointer for Remain on Channel Req", + __func__); + ) + return; + } + /* Incase of the Remain on Channel Failure Case */ + /* Cleanup Everything */ + if (QDF_STATUS_E_FAILURE == status) { + /* Deactivate Remain on Channel Timer */ + lim_deactivate_and_change_timer(pMac, eLIM_REMAIN_CHN_TIMER); + + /* Set the Link State to Idle */ + /* get the previous valid LINK state */ + if (lim_set_link_state(pMac, eSIR_LINK_IDLE_STATE, nullBssid, + pMac->lim.gSelfMacAddr, NULL, + NULL) != eSIR_SUCCESS) { + lim_log(pMac, LOGE, "Unable to change link state"); + } + + pMac->lim.gLimSystemInScanLearnMode = 0; + pMac->lim.gLimHalScanState = eLIM_HAL_IDLE_SCAN_STATE; + SET_LIM_PROCESS_DEFD_MESGS(pMac, true); + } + + /* delete the session */ + psessionEntry = pe_find_session_by_bssid(pMac, + MsgRemainonChannel-> + selfMacAddr.bytes, + &sessionId); + if (psessionEntry != NULL) { + if (LIM_IS_P2P_DEVICE_ROLE(psessionEntry)) { + pe_delete_session(pMac, psessionEntry); + } + } + + /* Post the meessage to Sme */ + lim_send_sme_rsp(pMac, eWNI_SME_REMAIN_ON_CHN_RSP, + status, + MsgRemainonChannel->sessionId, 0); + + qdf_mem_free(pMac->lim.gpLimRemainOnChanReq); + pMac->lim.gpLimRemainOnChanReq = NULL; + + pMac->lim.gLimMlmState = pMac->lim.gLimPrevMlmState; + + /* If remain on channel timer expired and action frame is pending then + * indicaiton confirmation with status failure */ + if (pMac->lim.mgmtFrameSessionId != 0xff) { + lim_p2p_action_cnf(pMac, false); + } + + return; +} + +/*------------------------------------------------------------------ + * + * Indicate the Mgmt Frame received to SME to HDD callback + * handle Probe_req/Action frame currently + * + *------------------------------------------------------------------*/ +void lim_send_sme_mgmt_frame_ind(tpAniSirGlobal pMac, uint8_t frameType, + uint8_t *frame, uint32_t frameLen, + uint16_t sessionId, uint32_t rxChannel, + tpPESession psessionEntry, int8_t rxRssi) +{ + tpSirSmeMgmtFrameInd pSirSmeMgmtFrame = NULL; + uint16_t length; + + length = sizeof(tSirSmeMgmtFrameInd) + frameLen; + + pSirSmeMgmtFrame = qdf_mem_malloc(length); + if (NULL == pSirSmeMgmtFrame) { + lim_log(pMac, LOGP, + FL("AllocateMemory failed for eWNI_SME_LISTEN_RSP")); + return; + } + + pSirSmeMgmtFrame->frame_len = frameLen; + pSirSmeMgmtFrame->sessionId = sessionId; + pSirSmeMgmtFrame->frameType = frameType; + pSirSmeMgmtFrame->rxRssi = rxRssi; + pSirSmeMgmtFrame->rxChan = rxChannel; + + qdf_mem_zero(pSirSmeMgmtFrame->frameBuf, frameLen); + qdf_mem_copy(pSirSmeMgmtFrame->frameBuf, frame, frameLen); + + if (pMac->mgmt_frame_ind_cb) + pMac->mgmt_frame_ind_cb(pSirSmeMgmtFrame); + else + lim_log(pMac, LOGW, + FL("Management indication callback not registered!!")); + qdf_mem_free(pSirSmeMgmtFrame); + return; +} + +QDF_STATUS lim_p2p_action_cnf(tpAniSirGlobal pMac, uint32_t tx_status) +{ + QDF_STATUS status; + uint32_t mgmt_frame_sessionId; + bool tx_complete_ack = (tx_status) ? true : false; + + status = pe_acquire_global_lock(&pMac->lim); + if (QDF_IS_STATUS_SUCCESS(status)) { + mgmt_frame_sessionId = pMac->lim.mgmtFrameSessionId; + pMac->lim.mgmtFrameSessionId = 0xff; + pe_release_global_lock(&pMac->lim); + + if (mgmt_frame_sessionId != 0xff) { + /* + * The session entry might be invalid(0xff) + * action confirmation received after + * remain on channel timer expired. + */ + lim_log(pMac, LOG1, + FL("mgmt_frame_sessionId %d"), + mgmt_frame_sessionId); + if (pMac->p2p_ack_ind_cb) + pMac->p2p_ack_ind_cb(mgmt_frame_sessionId, + tx_complete_ack); + } + } + + return status; +} + +/** + * lim_tx_action_frame() - Handles action frame transmission request + * @mac_ctx: Pointer to mac context + * @mb_msg: message sent from SME + * @msg_len: Message length + * @packet: network buffer for TX + * @frame: frame buffer + * + * This function processes the action frame transmission request and + * posts message to WMA. + * + * Return: NULL + */ +static void lim_tx_action_frame(tpAniSirGlobal mac_ctx, + tSirMbMsgP2p *mb_msg, uint32_t msg_len, void *packet, uint8_t *frame) +{ + uint8_t tx_flag = 0; + tpSirMacFrameCtl fc = (tpSirMacFrameCtl) mb_msg->data; + QDF_STATUS qdf_status; + uint8_t sme_session_id = 0; + uint16_t channel_freq; + + sme_session_id = mb_msg->sessionId; + channel_freq = mb_msg->channel_freq; + /* + * Use BD rate 2 for all P2P related frames. As these frames + * need to go at OFDM rates. And BD rate2 we configured at 6Mbps. + */ + tx_flag |= HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME; + mac_ctx->lim.mgmtFrameSessionId = sme_session_id; + + if ((SIR_MAC_MGMT_PROBE_RSP == fc->subType) || + (mb_msg->noack)) { + qdf_status = wma_tx_frame(mac_ctx, packet, (uint16_t) msg_len, + TXRX_FRM_802_11_MGMT, + ANI_TXDIR_TODS, 7, lim_tx_complete, + frame, tx_flag, sme_session_id, + channel_freq); + + if (!mb_msg->noack) + lim_p2p_action_cnf(mac_ctx, + (QDF_IS_STATUS_SUCCESS(qdf_status)) ? + true : false); + mac_ctx->lim.mgmtFrameSessionId = 0xff; + } else { + qdf_status = + wma_tx_frameWithTxComplete(mac_ctx, packet, + (uint16_t) msg_len, + TXRX_FRM_802_11_MGMT, + ANI_TXDIR_TODS, 7, lim_tx_complete, + frame, lim_p2p_action_cnf, tx_flag, + sme_session_id, false, + channel_freq); + + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + lim_log(mac_ctx, LOGE, + FL("couldn't send action frame")); + lim_p2p_action_cnf(mac_ctx, false); + mac_ctx->lim.mgmtFrameSessionId = 0xff; + } else { + mac_ctx->lim.mgmtFrameSessionId = mb_msg->sessionId; + lim_log(mac_ctx, LOG2, + FL("lim.actionFrameSessionId = %u"), + mac_ctx->lim.mgmtFrameSessionId); + } + } + + return; +} + +/** + * lim_send_p2p_action_frame() - Process action frame request + * @mac_ctx: Pointer to mac context + * @msg: message sent from SME + * + * This function processes the action frame request sent from the + * SME and generates the ACTION frame. + * + * Return: NULL + */ +void lim_send_p2p_action_frame(tpAniSirGlobal mac_ctx, + tpSirMsgQ msg) +{ + tSirMbMsgP2p *mb_msg = (tSirMbMsgP2p *) msg->bodyptr; + uint32_t msg_len; + uint8_t *frame; + void *packet; + QDF_STATUS qdf_status; + tpSirMacFrameCtl fc = (tpSirMacFrameCtl) mb_msg->data; + uint8_t noa_len = 0; + uint8_t noa_stream[SIR_MAX_NOA_ATTR_LEN + (2 * SIR_P2P_IE_HEADER_LEN)]; + uint8_t orig_len = 0; + uint8_t session_id = 0; + uint8_t *p2p_ie = NULL; + tpPESession session_entry = NULL; + uint8_t *presence_noa_attr = NULL; + uint8_t *tmp_p2p_ie = NULL; + uint16_t remain_len = 0; + uint8_t sme_session_id = 0; +#ifdef WLAN_FEATURE_11W + tpSirMacMgmtHdr mac_hdr; + tpSirMacActionFrameHdr action_hdr; +#endif + + msg_len = mb_msg->msgLen - sizeof(tSirMbMsgP2p); + lim_log(mac_ctx, LOG1, FL("sending fc->type=%d fc->subType=%d"), + fc->type, fc->subType); + + if ((!mac_ctx->lim.gpLimRemainOnChanReq) && (0 != mb_msg->wait)) { + lim_log(mac_ctx, LOGE, + FL("RemainOnChannel is not running")); + mac_ctx->lim.mgmtFrameSessionId = mb_msg->sessionId; + lim_p2p_action_cnf(mac_ctx, false); + mac_ctx->lim.mgmtFrameSessionId = 0xff; + return; + } + sme_session_id = mb_msg->sessionId; + + if ((SIR_MAC_MGMT_FRAME == fc->type) && + (SIR_MAC_MGMT_PROBE_RSP == fc->subType)) { + /* get proper offset for Probe RSP */ + p2p_ie = limGetP2pIEPtr(mac_ctx, + (uint8_t *) mb_msg->data + + PROBE_RSP_IE_OFFSET, + msg_len - PROBE_RSP_IE_OFFSET); + while ((NULL != p2p_ie) + && (SIR_MAC_MAX_IE_LENGTH == p2p_ie[1])) { + remain_len = + msg_len - (p2p_ie - + (uint8_t *) mb_msg->data); + if (remain_len > 2) { + tmp_p2p_ie = limGetP2pIEPtr(mac_ctx, + p2p_ie + SIR_MAC_MAX_IE_LENGTH + 2, + remain_len); + } + if (tmp_p2p_ie) { + p2p_ie = tmp_p2p_ie; + tmp_p2p_ie = NULL; + } else { + break; + } + } /* end of while */ + } else if ((SIR_MAC_MGMT_FRAME == fc->type) && + (SIR_MAC_MGMT_ACTION == fc->subType) && + (SIR_MAC_ACTION_VENDOR_SPECIFIC_CATEGORY == + *((uint8_t *) mb_msg->data + ACTION_OFFSET))) { + tpSirMacP2PActionFrameHdr action_hdr = + (tpSirMacP2PActionFrameHdr) ((uint8_t *) + mb_msg->data + ACTION_OFFSET); + if ((!qdf_mem_cmp(action_hdr->Oui, SIR_MAC_P2P_OUI, + SIR_MAC_P2P_OUI_SIZE)) && + (SIR_MAC_ACTION_P2P_SUBTYPE_PRESENCE_RSP == + action_hdr->OuiSubType)) { + + /* In case of Presence RSP response */ + p2p_ie = limGetP2pIEPtr(mac_ctx, + (uint8_t *)mb_msg->data + + ACTION_OFFSET + + sizeof(tSirMacP2PActionFrameHdr), + (msg_len - ACTION_OFFSET + - sizeof(tSirMacP2PActionFrameHdr))); + if (NULL != p2p_ie) { + /* extract the presence of NoA attribute inside + * P2P IE */ + presence_noa_attr = lim_get_ie_ptr_new(mac_ctx, + p2p_ie + SIR_P2P_IE_HEADER_LEN, + p2p_ie[1], SIR_P2P_NOA_ATTR, TWO_BYTE); + } + } + } + + if ((SIR_MAC_MGMT_FRAME == fc->type) && + (SIR_MAC_MGMT_PROBE_RSP == fc->subType || + SIR_MAC_MGMT_ACTION == fc->subType) && p2p_ie != NULL) { + /* get NoA attribute stream P2P IE */ + noa_len = + lim_get_noa_attr_stream(mac_ctx, noa_stream, + session_entry); + /* need to append NoA attribute in P2P IE */ + if (noa_len > 0) { + orig_len = p2p_ie[1]; + /* if Presence Rsp has NoAttr */ + if (presence_noa_attr) { + uint16_t noa_len = + presence_noa_attr[1] | + (presence_noa_attr[2] << 8); + /*One byte for attribute, 2bytes for length */ + orig_len -= (noa_len + 1 + 2); + /* remove those bytes to copy */ + msg_len -= (noa_len + 1 + 2); + /* remove NoA from original Len */ + p2p_ie[1] = orig_len; + } + if ((p2p_ie[1] + (uint16_t) noa_len) > + SIR_MAC_MAX_IE_LENGTH) { + /* + * Form the new NoA Byte array in multiple + * P2P IEs + */ + noa_len = + lim_get_noa_attr_stream_in_mult_p2p_ies + (mac_ctx, noa_stream, noa_len, + ((p2p_ie[1] + (uint16_t)noa_len) + - SIR_MAC_MAX_IE_LENGTH)); + p2p_ie[1] = SIR_MAC_MAX_IE_LENGTH; + } else { + /* increment the length of P2P IE */ + p2p_ie[1] += noa_len; + } + msg_len += noa_len; + lim_log(mac_ctx, LOGE, + FL("noa_len=%d orig_len=%d p2p_ie=%p" + " msg_len=%d nBytesToCopy=%zu "), + noa_len, orig_len, p2p_ie, msg_len, + ((p2p_ie + orig_len + 2) - + (uint8_t *) mb_msg->data)); + } + } + + if (SIR_MAC_MGMT_PROBE_RSP == fc->subType) + lim_set_ht_caps(mac_ctx, session_entry, + (uint8_t *) mb_msg->data + PROBE_RSP_IE_OFFSET, + msg_len - PROBE_RSP_IE_OFFSET); + + /* Ok-- try to allocate some memory: */ + qdf_status = cds_packet_alloc((uint16_t) msg_len, (void **)&frame, + (void **)&packet); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + lim_log(mac_ctx, LOGE, + FL("Failed to allocate %d bytes for a Probe Request."), + msg_len); + return; + } + /* Paranoia: */ + qdf_mem_set(frame, msg_len, 0); + + /* + * Add sequence number to action frames + * Frames are handed over in .11 format by supplicant already + */ + lim_populate_p2p_mac_header(mac_ctx, (uint8_t *) mb_msg->data); + + if ((noa_len > 0) + && (noa_len < (SIR_MAX_NOA_ATTR_LEN + SIR_P2P_IE_HEADER_LEN))) { + /* Add 2 bytes for length and Arribute field */ + uint32_t nBytesToCopy = ((p2p_ie + orig_len + 2) - + (uint8_t *) mb_msg->data); + qdf_mem_copy(frame, mb_msg->data, nBytesToCopy); + qdf_mem_copy((frame + nBytesToCopy), noa_stream, noa_len); + qdf_mem_copy((frame + nBytesToCopy + noa_len), + mb_msg->data + nBytesToCopy, + msg_len - nBytesToCopy - noa_len); + + } else { + qdf_mem_copy(frame, mb_msg->data, msg_len); + } + +#ifdef WLAN_FEATURE_11W + action_hdr = (tpSirMacActionFrameHdr) + (frame + sizeof(tSirMacMgmtHdr)); + mac_hdr = (tpSirMacMgmtHdr) frame; + session_entry = pe_find_session_by_bssid(mac_ctx, + (uint8_t *) mb_msg->data + BSSID_OFFSET, + &session_id); + + /* + * Check for session corresponding to ADDR2 as supplicant + * is filling ADDR2 with BSSID + */ + if (NULL == session_entry) { + session_entry = pe_find_session_by_bssid(mac_ctx, + (uint8_t *) mb_msg->data + ADDR2_OFFSET, + &session_id); + } + /* + * Setting Protected bit only for Robust Action Frames + * This has to be based on the current Connection with the + * station. lim_set_protected_bit API will set the protected + * bit if connection is PMF + */ + if (session_entry && (SIR_MAC_MGMT_ACTION == fc->subType) && + session_entry->limRmfEnabled && + (!lim_is_group_addr(mac_hdr->da)) && + lim_is_robust_mgmt_action_frame(action_hdr->category)) + lim_set_protected_bit(mac_ctx, session_entry, + mac_hdr->da, mac_hdr); +#endif + + lim_tx_action_frame(mac_ctx, mb_msg, msg_len, packet, frame); + return; +} + +/* Power Save Related Functions */ +tSirRetStatus __lim_process_sme_no_a_update(tpAniSirGlobal pMac, uint32_t *pMsgBuf) +{ + tpP2pPsConfig pNoA; + tpP2pPsParams pMsgNoA; + tSirMsgQ msg; + + pNoA = (tpP2pPsConfig) pMsgBuf; + + pMsgNoA = qdf_mem_malloc(sizeof(tP2pPsConfig)); + if (NULL == pMsgNoA) { + lim_log(pMac, LOGE, + FL("Unable to allocate memory during NoA Update")); + return eSIR_MEM_ALLOC_FAILED; + } + + pMsgNoA->opp_ps = pNoA->opp_ps; + pMsgNoA->ctWindow = pNoA->ctWindow; + pMsgNoA->duration = pNoA->duration; + pMsgNoA->interval = pNoA->interval; + pMsgNoA->count = pNoA->count; + pMsgNoA->single_noa_duration = pNoA->single_noa_duration; + pMsgNoA->psSelection = pNoA->psSelection; + pMsgNoA->sessionId = pNoA->sessionid; + + msg.type = WMA_SET_P2P_GO_NOA_REQ; + msg.reserved = 0; + msg.bodyptr = pMsgNoA; + msg.bodyval = 0; + + if (eSIR_SUCCESS != wma_post_ctrl_msg(pMac, &msg)) { + lim_log(pMac, LOGE, FL("halPostMsgApi failed")); + return eSIR_FAILURE; + } + + return eSIR_SUCCESS; +} /*** end __limProcessSmeGoNegReq() ***/ diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_process_action_frame.c b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_process_action_frame.c new file mode 100644 index 0000000000000000000000000000000000000000..1b54d510e09ee275675fd407aa89c8cc8f59d2ef --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_process_action_frame.c @@ -0,0 +1,2253 @@ +/* + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * This file lim_process_action_frame.cc contains the code + * for processing Action Frame. + * Author: Michael Lui + * Date: 05/23/03 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + * + */ +#include "cds_api.h" +#include "wni_api.h" +#include "sir_api.h" +#include "ani_global.h" +#include "wni_cfg.h" +#include "sch_api.h" +#include "utils_api.h" +#include "lim_types.h" +#include "lim_utils.h" +#include "lim_assoc_utils.h" +#include "lim_security_utils.h" +#include "lim_ser_des_utils.h" +#include "lim_send_sme_rsp_messages.h" +#include "parser_api.h" +#include "lim_admit_control.h" +#include "wmm_apsd.h" +#include "lim_send_messages.h" +#include "rrm_api.h" +#include "lim_session_utils.h" +#include "cds_concurrency.h" +#include "wma_types.h" +#include "wma.h" + +#define BA_DEFAULT_TX_BUFFER_SIZE 64 + +static last_processed_msg rrm_link_action_frm; + +/* Note: The test passes if the STAUT stops sending any frames, and no further + frames are transmitted on this channel by the station when the AP has sent + the last 6 beacons, with the channel switch information elements as seen + with the sniffer.*/ +#define SIR_CHANSW_TX_STOP_MAX_COUNT 6 +/**----------------------------------------------------------------- + \fn lim_stop_tx_and_switch_channel + \brief Stops the transmission if channel switch mode is silent and + starts the channel switch timer. + + \param pMac + \return NONE + -----------------------------------------------------------------*/ +void lim_stop_tx_and_switch_channel(tpAniSirGlobal pMac, uint8_t sessionId) +{ + tpPESession psessionEntry; + + psessionEntry = pe_find_session_by_session_id(pMac, sessionId); + + if (NULL == psessionEntry) { + lim_log(pMac, LOGE, FL("Session %d not active"), sessionId); + return; + } + + PELOG1(lim_log(pMac, LOG1, FL("Channel switch Mode == %d"), + psessionEntry->gLimChannelSwitch.switchMode); + ) + + if (psessionEntry->gLimChannelSwitch.switchMode == + eSIR_CHANSW_MODE_SILENT + || psessionEntry->gLimChannelSwitch.switchCount <= + SIR_CHANSW_TX_STOP_MAX_COUNT) { + /* Freeze the transmission */ + lim_frame_transmission_control(pMac, eLIM_TX_ALL, eLIM_STOP_TX); + + } else { + /* Resume the transmission */ + lim_frame_transmission_control(pMac, eLIM_TX_ALL, eLIM_RESUME_TX); + } + + pMac->lim.limTimers.gLimChannelSwitchTimer.sessionId = sessionId; + /* change the channel immediatly only if + * the channel switch count is 0 + */ + if (psessionEntry->gLimChannelSwitch.switchCount == 0) { + lim_process_channel_switch_timeout(pMac); + return; + } + MTRACE(mac_trace + (pMac, TRACE_CODE_TIMER_ACTIVATE, sessionId, + eLIM_CHANNEL_SWITCH_TIMER)); + + if (tx_timer_activate(&pMac->lim.limTimers.gLimChannelSwitchTimer) != + TX_SUCCESS) { + lim_log(pMac, LOGP, FL("tx_timer_activate failed")); + } + return; +} + +/**------------------------------------------------------------ + \fn lim_start_channel_switch + \brief Switches the channel if switch count == 0, otherwise + starts the timer for channel switch and stops BG scan + and heartbeat timer tempororily. + + \param pMac + \param psessionEntry + \return NONE + ------------------------------------------------------------*/ +tSirRetStatus lim_start_channel_switch(tpAniSirGlobal pMac, + tpPESession psessionEntry) +{ + PELOG1(lim_log(pMac, LOG1, FL("Starting the channel switch"));) + + /*If channel switch is already running and it is on a different session, just return */ + /*This need to be removed for MCC */ + if ((lim_is_chan_switch_running(pMac) && + psessionEntry->gLimSpecMgmt.dot11hChanSwState != + eLIM_11H_CHANSW_RUNNING) || psessionEntry->csaOffloadEnable) { + lim_log(pMac, LOGW, FL("Ignoring channel switch on session %d"), + psessionEntry->peSessionId); + return eSIR_SUCCESS; + } + + /* Deactivate and change reconfigure the timeout value */ + /* lim_deactivate_and_change_timer(pMac, eLIM_CHANNEL_SWITCH_TIMER); */ + MTRACE(mac_trace + (pMac, TRACE_CODE_TIMER_DEACTIVATE, psessionEntry->peSessionId, + eLIM_CHANNEL_SWITCH_TIMER)); + if (tx_timer_deactivate(&pMac->lim.limTimers.gLimChannelSwitchTimer) != + eSIR_SUCCESS) { + lim_log(pMac, LOGP, FL("tx_timer_deactivate failed!")); + return eSIR_FAILURE; + } + + if (tx_timer_change(&pMac->lim.limTimers.gLimChannelSwitchTimer, + psessionEntry->gLimChannelSwitch.switchTimeoutValue, + 0) != TX_SUCCESS) { + lim_log(pMac, LOGP, FL("tx_timer_change failed ")); + return eSIR_FAILURE; + } + + /* Follow the channel switch, forget about the previous quiet. */ + /* If quiet is running, chance is there to resume tx on its timeout. */ + /* so stop timer for a safer side. */ + if (psessionEntry->gLimSpecMgmt.quietState == eLIM_QUIET_BEGIN) { + MTRACE(mac_trace + (pMac, TRACE_CODE_TIMER_DEACTIVATE, + psessionEntry->peSessionId, eLIM_QUIET_TIMER)); + if (tx_timer_deactivate(&pMac->lim.limTimers.gLimQuietTimer) != + TX_SUCCESS) { + lim_log(pMac, LOGP, FL("tx_timer_deactivate failed")); + return eSIR_FAILURE; + } + } else if (psessionEntry->gLimSpecMgmt.quietState == eLIM_QUIET_RUNNING) { + MTRACE(mac_trace + (pMac, TRACE_CODE_TIMER_DEACTIVATE, + psessionEntry->peSessionId, eLIM_QUIET_BSS_TIMER)); + if (tx_timer_deactivate(&pMac->lim.limTimers.gLimQuietBssTimer) + != TX_SUCCESS) { + lim_log(pMac, LOGP, FL("tx_timer_deactivate failed")); + return eSIR_FAILURE; + } + } + psessionEntry->gLimSpecMgmt.quietState = eLIM_QUIET_INIT; + + /* Prepare for 11h channel switch */ + lim_prepare_for11h_channel_switch(pMac, psessionEntry); + + /** Dont add any more statements here as we posted finish scan request + * to HAL, wait till we get the response + */ + return eSIR_SUCCESS; +} + +/** + * __lim_process_channel_switch_action_frame() - to process channel switch + * @mac_ctx: Pointer to Global MAC structure + * @rx_pkt_info: A pointer to packet info structure + * + * This routine will be called to process channel switch action frame + * + * Return: None + */ + +static void __lim_process_channel_switch_action_frame(tpAniSirGlobal mac_ctx, + uint8_t *rx_pkt_info, tpPESession session) +{ + tpSirMacMgmtHdr mac_hdr; + uint8_t *body_ptr; + tDot11fChannelSwitch *chnl_switch_frame; + uint16_t bcn_period; + uint32_t val, frame_len, status; + tLimChannelSwitchInfo *ch_switch_params; + struct sDot11fIEWiderBWChanSwitchAnn *wbw_chnlswitch_ie = NULL; + struct sLimWiderBWChannelSwitch *lim_wbw_chnlswitch_info = NULL; + struct sDot11fIEsec_chan_offset_ele *sec_chnl_offset = NULL; + + mac_hdr = WMA_GET_RX_MAC_HEADER(rx_pkt_info); + body_ptr = WMA_GET_RX_MPDU_DATA(rx_pkt_info); + frame_len = WMA_GET_RX_PAYLOAD_LEN(rx_pkt_info); + + PELOG3(lim_log(mac_ctx, LOG3, + FL("Received Channel switch action frame"));) + if (!session->lim11hEnable) + return; + + chnl_switch_frame = qdf_mem_malloc(sizeof(*chnl_switch_frame)); + if (NULL == chnl_switch_frame) { + lim_log(mac_ctx, LOGE, FL("AllocateMemory failed")); + return; + } + + /* Unpack channel switch frame */ + status = dot11f_unpack_channel_switch(mac_ctx, body_ptr, frame_len, + chnl_switch_frame); + + if (DOT11F_FAILED(status)) { + lim_log(mac_ctx, LOGE, + FL("Failed to unpack and parse (0x%08x, %d bytes)"), + status, frame_len); + qdf_mem_free(chnl_switch_frame); + return; + } else if (DOT11F_WARNED(status)) { + lim_log(mac_ctx, LOGW, + FL("warning: unpack 11h-CHANSW Req(0x%08x, %d bytes)"), + status, frame_len); + } + + if (qdf_mem_cmp((uint8_t *) &session->bssId, + (uint8_t *) &mac_hdr->sa, sizeof(tSirMacAddr))) { + lim_log(mac_ctx, LOG1, + FL("Rcvd action frame not from our BSS, dropping...")); + qdf_mem_free(chnl_switch_frame); + return; + } + /* copy the beacon interval from session */ + val = session->beaconParams.beaconInterval; + ch_switch_params = &session->gLimChannelSwitch; + bcn_period = (uint16_t)val; + ch_switch_params->primaryChannel = + chnl_switch_frame->ChanSwitchAnn.newChannel; + ch_switch_params->switchCount = + chnl_switch_frame->ChanSwitchAnn.switchCount; + ch_switch_params->switchTimeoutValue = + SYS_MS_TO_TICKS(bcn_period) * + session->gLimChannelSwitch.switchCount; + ch_switch_params->switchMode = + chnl_switch_frame->ChanSwitchAnn.switchMode; + + /* Only primary channel switch element is present */ + ch_switch_params->state = eLIM_CHANNEL_SWITCH_PRIMARY_ONLY; + ch_switch_params->ch_width = CH_WIDTH_20MHZ; + + if (chnl_switch_frame->WiderBWChanSwitchAnn.present + && session->vhtCapability) { + wbw_chnlswitch_ie = &chnl_switch_frame->WiderBWChanSwitchAnn; + session->gLimWiderBWChannelSwitch.newChanWidth = + wbw_chnlswitch_ie->newChanWidth; + session->gLimWiderBWChannelSwitch.newCenterChanFreq0 = + wbw_chnlswitch_ie->newCenterChanFreq0; + session->gLimWiderBWChannelSwitch.newCenterChanFreq1 = + wbw_chnlswitch_ie->newCenterChanFreq1; + } + lim_log(mac_ctx, LOG3, + FL("Rcv Chnl Swtch Frame: Timeout in %d ticks"), + session->gLimChannelSwitch.switchTimeoutValue); + if (session->htSupportedChannelWidthSet) { + sec_chnl_offset = &chnl_switch_frame->sec_chan_offset_ele; + if (sec_chnl_offset->secondaryChannelOffset == + PHY_DOUBLE_CHANNEL_LOW_PRIMARY) { + ch_switch_params->state = + eLIM_CHANNEL_SWITCH_PRIMARY_AND_SECONDARY; + ch_switch_params->ch_width = CH_WIDTH_40MHZ; + ch_switch_params->ch_center_freq_seg0 = + ch_switch_params->primaryChannel + 2; + } else if (sec_chnl_offset->secondaryChannelOffset == + PHY_DOUBLE_CHANNEL_HIGH_PRIMARY) { + ch_switch_params->state = + eLIM_CHANNEL_SWITCH_PRIMARY_AND_SECONDARY; + ch_switch_params->ch_width = CH_WIDTH_40MHZ; + ch_switch_params->ch_center_freq_seg0 = + ch_switch_params->primaryChannel - 2; + + } + if (session->vhtCapability && + chnl_switch_frame->WiderBWChanSwitchAnn.present) { + wbw_chnlswitch_ie = + &chnl_switch_frame->WiderBWChanSwitchAnn; + ch_switch_params->ch_width = + wbw_chnlswitch_ie->newChanWidth + 1; + lim_wbw_chnlswitch_info = + &session->gLimWiderBWChannelSwitch; + ch_switch_params->ch_center_freq_seg0 = + lim_wbw_chnlswitch_info->newCenterChanFreq0; + ch_switch_params->ch_center_freq_seg1 = + lim_wbw_chnlswitch_info->newCenterChanFreq1; + + } + } + + if (CH_WIDTH_20MHZ == ch_switch_params->ch_width) { + session->htSupportedChannelWidthSet = + WNI_CFG_CHANNEL_BONDING_MODE_DISABLE; + session->htRecommendedTxWidthSet = + session->htSupportedChannelWidthSet; + } + + if (eSIR_SUCCESS != lim_start_channel_switch(mac_ctx, session)) + lim_log(mac_ctx, LOG1, + FL("Could not start channel switch")); + + qdf_mem_free(chnl_switch_frame); + return; +} + +/** + * lim_process_ext_channel_switch_action_frame()- Process ECSA Action + * Frames. + * @mac_ctx: pointer to global mac structure + * @rx_packet_info: rx packet meta information + * @session_entry: Session entry. + * + * This function is called when ECSA action frame is received. + * + * Return: void + */ +static void +lim_process_ext_channel_switch_action_frame(tpAniSirGlobal mac_ctx, + uint8_t *rx_packet_info, tpPESession session_entry) +{ + + tpSirMacMgmtHdr hdr; + uint8_t *body; + tDot11fext_channel_switch_action_frame *ext_channel_switch_frame; + uint32_t frame_len; + uint32_t status; + uint8_t target_channel; + + hdr = WMA_GET_RX_MAC_HEADER(rx_packet_info); + body = WMA_GET_RX_MPDU_DATA(rx_packet_info); + frame_len = WMA_GET_RX_PAYLOAD_LEN(rx_packet_info); + + lim_log(mac_ctx, LOG1, FL("Received EXT Channel switch action frame")); + + ext_channel_switch_frame = + qdf_mem_malloc(sizeof(*ext_channel_switch_frame)); + if (NULL == ext_channel_switch_frame) { + lim_log(mac_ctx, LOGE, FL("AllocateMemory failed")); + return; + } + + /* Unpack channel switch frame */ + status = dot11f_unpack_ext_channel_switch_action_frame(mac_ctx, + body, frame_len, ext_channel_switch_frame); + + if (DOT11F_FAILED(status)) { + + lim_log(mac_ctx, LOGE, + FL("Failed to parse CHANSW action frame (0x%08x, len %d):"), + status, frame_len); + qdf_mem_free(ext_channel_switch_frame); + return; + } else if (DOT11F_WARNED(status)) { + + lim_log(mac_ctx, LOGW, + FL("There were warnings while unpacking CHANSW Request (0x%08x, %d bytes):"), + status, frame_len); + } + + target_channel = + ext_channel_switch_frame->ext_chan_switch_ann_action.new_channel; + + /* Free ext_channel_switch_frame here as its no longer needed */ + qdf_mem_free(ext_channel_switch_frame); + /* + * Now, validate if channel change is required for the passed + * channel and if is valid in the current regulatory domain, + * and no concurrent session is running. + */ + if (!((session_entry->currentOperChannel != target_channel) && + ((cds_get_channel_state(target_channel) + == CHANNEL_STATE_ENABLE) || + (cds_get_channel_state(target_channel) == CHANNEL_STATE_DFS && + !cds_concurrent_open_sessions_running())))) { + lim_log(mac_ctx, LOGE, FL("Channel %d is not valid"), + target_channel); + return; + } + + if (eLIM_AP_ROLE == session_entry->limSystemRole) { + + struct sir_sme_ext_cng_chan_ind *ext_cng_chan_ind; + tSirMsgQ mmh_msg; + + ext_cng_chan_ind = qdf_mem_malloc(sizeof(*ext_cng_chan_ind)); + if (NULL == ext_cng_chan_ind) { + lim_log(mac_ctx, LOGP, + FL("AllocateMemory failed for ext_cng_chan_ind")); + return; + } + + ext_cng_chan_ind->session_id = + session_entry->smeSessionId; + + /* No need to extract op mode as BW will be decided in + * in SAP FSM depending on previous BW. + */ + ext_cng_chan_ind->new_channel = target_channel; + + mmh_msg.type = eWNI_SME_EXT_CHANGE_CHANNEL_IND; + mmh_msg.bodyptr = ext_cng_chan_ind; + mmh_msg.bodyval = 0; + lim_sys_process_mmh_msg_api(mac_ctx, &mmh_msg, ePROT); + } + return; +} /*** end lim_process_ext_channel_switch_action_frame() ***/ + +/** + * __lim_process_operating_mode_action_frame() - To process op mode frames + * @mac_ctx: pointer to mac context + * @rx_pkt_info: pointer to received packet info + * @session: pointer to session + * + * This routine is called to process operating mode action frames + * + * Return: None + */ +static void __lim_process_operating_mode_action_frame(tpAniSirGlobal mac_ctx, + uint8_t *rx_pkt_info, tpPESession session) +{ + + tpSirMacMgmtHdr mac_hdr; + uint8_t *body_ptr; + tDot11fOperatingMode *operating_mode_frm; + uint32_t frame_len; + uint32_t status; + tpDphHashNode sta_ptr; + uint16_t aid; + uint8_t oper_mode; + uint8_t cb_mode; + uint8_t ch_bw = 0; + uint8_t skip_opmode_update = false; + + mac_hdr = WMA_GET_RX_MAC_HEADER(rx_pkt_info); + body_ptr = WMA_GET_RX_MPDU_DATA(rx_pkt_info); + frame_len = WMA_GET_RX_PAYLOAD_LEN(rx_pkt_info); + + lim_log(mac_ctx, LOG1, + FL("Received Operating Mode action frame")); + if (CHAN_ENUM_14 >= session->currentOperChannel) + cb_mode = mac_ctx->roam.configParam.channelBondingMode24GHz; + else + cb_mode = mac_ctx->roam.configParam.channelBondingMode5GHz; + /* Do not update the channel bonding mode if channel bonding + * mode is disabled in INI. + */ + if (WNI_CFG_CHANNEL_BONDING_MODE_DISABLE == cb_mode) { + lim_log(mac_ctx, LOGW, FL("channel bonding disabled")); + return; + } + operating_mode_frm = qdf_mem_malloc(sizeof(*operating_mode_frm)); + if (NULL == operating_mode_frm) { + lim_log(mac_ctx, LOGE, FL("AllocateMemory failed")); + return; + } + /* Unpack channel switch frame */ + status = dot11f_unpack_operating_mode(mac_ctx, body_ptr, frame_len, + operating_mode_frm); + if (DOT11F_FAILED(status)) { + lim_log(mac_ctx, LOGE, + FL("Failed to unpack and parse (0x%08x, %d bytes)"), + status, frame_len); + qdf_mem_free(operating_mode_frm); + return; + } else if (DOT11F_WARNED(status)) { + lim_log(mac_ctx, LOGW, + FL("warnings while unpacking (0x%08x, %d bytes):"), + status, frame_len); + } + sta_ptr = dph_lookup_hash_entry(mac_ctx, mac_hdr->sa, &aid, + &session->dph.dphHashTable); + + if (sta_ptr == NULL) { + lim_log(mac_ctx, LOGE, FL("Station context not found")); + goto end; + } + + if (sta_ptr->htSupportedChannelWidthSet) { + if (WNI_CFG_VHT_CHANNEL_WIDTH_80MHZ < + sta_ptr->vhtSupportedChannelWidthSet) + oper_mode = eHT_CHANNEL_WIDTH_160MHZ; + else + oper_mode = sta_ptr->vhtSupportedChannelWidthSet + 1; + } else { + oper_mode = eHT_CHANNEL_WIDTH_20MHZ; + } + + if ((oper_mode == eHT_CHANNEL_WIDTH_80MHZ) && + (operating_mode_frm->OperatingMode.chanWidth > + eHT_CHANNEL_WIDTH_80MHZ)) + skip_opmode_update = true; + + if (!skip_opmode_update && (oper_mode != + operating_mode_frm->OperatingMode.chanWidth)) { + uint32_t fw_vht_ch_wd = wma_get_vht_ch_width(); + + lim_log(mac_ctx, LOGE, + FL(" received Chanwidth %d, staIdx = %d"), + (operating_mode_frm->OperatingMode.chanWidth), + sta_ptr->staIndex); + + lim_log(mac_ctx, LOGE, + FL(" MAC - %0x:%0x:%0x:%0x:%0x:%0x"), + mac_hdr->sa[0], mac_hdr->sa[1], mac_hdr->sa[2], + mac_hdr->sa[3], mac_hdr->sa[4], mac_hdr->sa[5]); + + if (operating_mode_frm->OperatingMode.chanWidth >= + eHT_CHANNEL_WIDTH_160MHZ + && (fw_vht_ch_wd >= eHT_CHANNEL_WIDTH_160MHZ)) { + sta_ptr->vhtSupportedChannelWidthSet = + WNI_CFG_VHT_CHANNEL_WIDTH_160MHZ; + sta_ptr->htSupportedChannelWidthSet = + eHT_CHANNEL_WIDTH_40MHZ; + ch_bw = eHT_CHANNEL_WIDTH_160MHZ; + } else if (operating_mode_frm->OperatingMode.chanWidth >= + eHT_CHANNEL_WIDTH_80MHZ) { + sta_ptr->vhtSupportedChannelWidthSet = + WNI_CFG_VHT_CHANNEL_WIDTH_80MHZ; + sta_ptr->htSupportedChannelWidthSet = + eHT_CHANNEL_WIDTH_40MHZ; + ch_bw = eHT_CHANNEL_WIDTH_80MHZ; + } else if (operating_mode_frm->OperatingMode.chanWidth == + eHT_CHANNEL_WIDTH_40MHZ) { + sta_ptr->vhtSupportedChannelWidthSet = + WNI_CFG_VHT_CHANNEL_WIDTH_20_40MHZ; + sta_ptr->htSupportedChannelWidthSet = + eHT_CHANNEL_WIDTH_40MHZ; + ch_bw = eHT_CHANNEL_WIDTH_40MHZ; + } else if (operating_mode_frm->OperatingMode.chanWidth == + eHT_CHANNEL_WIDTH_20MHZ) { + sta_ptr->vhtSupportedChannelWidthSet = + WNI_CFG_VHT_CHANNEL_WIDTH_20_40MHZ; + sta_ptr->htSupportedChannelWidthSet = + eHT_CHANNEL_WIDTH_20MHZ; + ch_bw = eHT_CHANNEL_WIDTH_20MHZ; + } + + lim_check_vht_op_mode_change(mac_ctx, session, ch_bw, + session->dot11mode, sta_ptr->staIndex, mac_hdr->sa); + } + + if (sta_ptr->vhtSupportedRxNss != + (operating_mode_frm->OperatingMode.rxNSS + 1)) { + sta_ptr->vhtSupportedRxNss = + operating_mode_frm->OperatingMode.rxNSS + 1; + lim_set_nss_change(mac_ctx, session, sta_ptr->vhtSupportedRxNss, + sta_ptr->staIndex, mac_hdr->sa); + } + +end: + qdf_mem_free(operating_mode_frm); + return; +} + +/** + * __lim_process_gid_management_action_frame() - To process group-id mgmt frames + * @mac_ctx: Pointer to mac context + * @rx_pkt_info: Rx packet info + * @session: pointer to session + * + * This routine will be called to process group id management frames + * + * Return: none + */ +static void __lim_process_gid_management_action_frame(tpAniSirGlobal mac_ctx, + uint8_t *rx_pkt_info, tpPESession session) +{ + + uint8_t *body_ptr; + uint16_t aid; + uint32_t frame_len, status, membership = 0, usr_position = 0; + uint32_t *mem_lower, *mem_upper, *mem_cur; + tpSirMacMgmtHdr mac_hdr; + tDot11fVHTGidManagementActionFrame *gid_mgmt_frame; + tpDphHashNode sta_ptr; + struct sDot11fFfVhtMembershipStatusArray *vht_member_status = NULL; + struct sDot11fFfVhtUserPositionArray *vht_user_position = NULL; + + mac_hdr = WMA_GET_RX_MAC_HEADER(rx_pkt_info); + body_ptr = WMA_GET_RX_MPDU_DATA(rx_pkt_info); + frame_len = WMA_GET_RX_PAYLOAD_LEN(rx_pkt_info); + + lim_log(mac_ctx, LOG3, FL("Received GID Management action frame")); + gid_mgmt_frame = qdf_mem_malloc(sizeof(*gid_mgmt_frame)); + if (NULL == gid_mgmt_frame) { + lim_log(mac_ctx, LOGE, FL("AllocateMemory failed")); + return; + } + + /* Unpack Gid Mangement Action frame */ + status = dot11f_unpack_vht_gid_management_action_frame(mac_ctx, + body_ptr, frame_len, gid_mgmt_frame); + if (DOT11F_FAILED(status)) { + lim_log(mac_ctx, LOGE, + FL("Fail to parse an Grp id frame (0x%08x, %d bytes):"), + status, frame_len); + qdf_mem_free(gid_mgmt_frame); + return; + } else if (DOT11F_WARNED(status)) { + lim_log(mac_ctx, LOGW, + FL("warnings while unpacking Grp id frm (0x%08x, %d bytes):"), + status, frame_len); + } + sta_ptr = dph_lookup_hash_entry(mac_ctx, mac_hdr->sa, &aid, + &session->dph.dphHashTable); + if (!sta_ptr) { + lim_log(mac_ctx, LOGE, + FL("Failed to get STA entry from hash table")); + goto out; + } + lim_log(mac_ctx, LOGE, + FL("received Gid Management Action Frame , staIdx = %d"), + sta_ptr->staIndex); + + lim_log(mac_ctx, LOGE, + FL(" MAC - %0x:%0x:%0x:%0x:%0x:%0x"), + mac_hdr->sa[0], mac_hdr->sa[1], mac_hdr->sa[2], + mac_hdr->sa[3], mac_hdr->sa[4], mac_hdr->sa[5]); + vht_member_status = &gid_mgmt_frame->VhtMembershipStatusArray; + mem_lower = (uint32_t *) vht_member_status->membershipStatusArray; + mem_upper = (uint32_t *) &vht_member_status->membershipStatusArray[4]; + + if (*mem_lower && *mem_upper) { + lim_log(mac_ctx, LOGE, + FL("rcved frame with mult group ID set, staIdx = %d"), + sta_ptr->staIndex); + goto out; + } + if (*mem_lower) { + mem_cur = mem_lower; + } else if (*mem_upper) { + mem_cur = mem_upper; + membership += sizeof(uint32_t); + } else { + lim_log(mac_ctx, LOGE, + FL("rcved Gid frame with no group ID set, staIdx = %d"), + sta_ptr->staIndex); + goto out; + } + while (!(*mem_cur & 1)) { + *mem_cur >>= 1; + ++membership; + } + if (*mem_cur) { + lim_log(mac_ctx, LOGE, + FL("rcved frame with mult group ID set, staIdx = %d"), + sta_ptr->staIndex); + goto out; + } + + /*Just read the last two bits */ + vht_user_position = &gid_mgmt_frame->VhtUserPositionArray; + usr_position = vht_user_position->userPositionArray[membership] & 0x3; + lim_check_membership_user_position(mac_ctx, session, membership, + usr_position, sta_ptr->staIndex); +out: + qdf_mem_free(gid_mgmt_frame); + return; +} + +static void +__lim_process_add_ts_req(tpAniSirGlobal pMac, uint8_t *pRxPacketInfo, + tpPESession psessionEntry) +{ +} + +/** + * __lim_process_add_ts_rsp() - To process add ts response frame + * @mac_ctx: pointer to mac context + * @rx_pkt_info: Received packet info + * @session: pointer to session + * + * This routine is to handle add ts response frame + * + * Return: none + */ +static void __lim_process_add_ts_rsp(tpAniSirGlobal mac_ctx, + uint8_t *rx_pkt_info, tpPESession session) +{ + tSirAddtsRspInfo addts; + tSirRetStatus retval; + tpSirMacMgmtHdr mac_hdr; + tpDphHashNode sta_ptr; + uint16_t aid; + uint32_t frameLen; + uint8_t *body_ptr; + tpLimTspecInfo tspec_info; + uint8_t ac; + tpDphHashNode sta_ds_ptr = NULL; + uint8_t rsp_reqd = 1; + uint32_t cfg_len; + tSirMacAddr peer_macaddr; + + mac_hdr = WMA_GET_RX_MAC_HEADER(rx_pkt_info); + body_ptr = WMA_GET_RX_MPDU_DATA(rx_pkt_info); + frameLen = WMA_GET_RX_PAYLOAD_LEN(rx_pkt_info); + + lim_log(mac_ctx, LOGW, "Recv AddTs Response"); + if (LIM_IS_AP_ROLE(session)) { + lim_log(mac_ctx, LOGW, + FL("AddTsRsp recvd at AP: ignoring")); + return; + } + + sta_ptr = dph_lookup_hash_entry(mac_ctx, mac_hdr->sa, &aid, + &session->dph.dphHashTable); + if (sta_ptr == NULL) { + lim_log(mac_ctx, LOGE, + FL("Station context not found - ignoring AddTsRsp")); + return; + } + + retval = sir_convert_addts_rsp2_struct(mac_ctx, body_ptr, + frameLen, &addts); + if (retval != eSIR_SUCCESS) { + lim_log(mac_ctx, LOGW, + FL("AddTsRsp parsing failed (error %d)"), retval); + return; + } + /* + * don't have to check for qos/wme capabilities since we wouldn't have + * this flag set otherwise + */ + if (!mac_ctx->lim.gLimAddtsSent) { + /* we never sent an addts request! */ + lim_log(mac_ctx, LOGW, + FL("rx AddTsRsp but no req was ever sent-ignoring")); + return; + } + + if (mac_ctx->lim.gLimAddtsReq.req.dialogToken != addts.dialogToken) { + lim_log(mac_ctx, LOGW, + FL("token mismatch (got %d, exp %d) - ignoring"), + addts.dialogToken, + mac_ctx->lim.gLimAddtsReq.req.dialogToken); + return; + } + + /* + * for successful addts reponse, try to add the classifier. + * if this fails for any reason, we should send a delts request to the + * ap for now, its ok not to send a delts since we are going to add + * support for multiple tclas soon and until then we won't send any + * addts requests with multiple tclas elements anyway. + * In case of addClassifier failure, we just let the addts timer run out + */ + if (((addts.tspec.tsinfo.traffic.accessPolicy == + SIR_MAC_ACCESSPOLICY_HCCA) || + (addts.tspec.tsinfo.traffic.accessPolicy == + SIR_MAC_ACCESSPOLICY_BOTH)) && + (addts.status == eSIR_MAC_SUCCESS_STATUS)) { + /* add the classifier - this should always succeed */ + if (addts.numTclas > 1) { + /* currently no support for multiple tclas elements */ + lim_log(mac_ctx, LOGE, + FL("Sta %d: Too many Tclas (%d), 1 supported"), + aid, addts.numTclas); + return; + } else if (addts.numTclas == 1) { + lim_log(mac_ctx, LOGW, + FL("Response from STA %d: tsid %d, UP %d, OK!"), + aid, addts.tspec.tsinfo.traffic.tsid, + addts.tspec.tsinfo.traffic.userPrio); + } + } + lim_log(mac_ctx, LOGW, FL("Recv AddTsRsp: tsid %d, UP %d, status %d "), + addts.tspec.tsinfo.traffic.tsid, + addts.tspec.tsinfo.traffic.userPrio, addts.status); + + /* deactivate the response timer */ + lim_deactivate_and_change_timer(mac_ctx, eLIM_ADDTS_RSP_TIMER); + + if (addts.status != eSIR_MAC_SUCCESS_STATUS) { + lim_log(mac_ctx, LOGW, + FL("Recv AddTsRsp: tsid %d, UP %d, status %d "), + addts.tspec.tsinfo.traffic.tsid, + addts.tspec.tsinfo.traffic.userPrio, addts.status); + lim_send_sme_addts_rsp(mac_ctx, true, addts.status, session, + addts.tspec, session->smeSessionId, + session->transactionId); + + /* clear the addts flag */ + mac_ctx->lim.gLimAddtsSent = false; + + return; + } +#ifdef FEATURE_WLAN_ESE + if (addts.tsmPresent) { + lim_log(mac_ctx, LOGW, "TSM IE Present"); + session->eseContext.tsm.tid = + addts.tspec.tsinfo.traffic.userPrio; + qdf_mem_copy(&session->eseContext.tsm.tsmInfo, + &addts.tsmIE, sizeof(tSirMacESETSMIE)); + lim_send_sme_tsm_ie_ind(mac_ctx, session, addts.tsmIE.tsid, + addts.tsmIE.state, + addts.tsmIE.msmt_interval); + } +#endif + /* + * Since AddTS response was successful, check for the PSB flag + * and directional flag inside the TS Info field. + * An AC is trigger enabled AC if the PSB subfield is set to 1 + * in the uplink direction. + * An AC is delivery enabled AC if the PSB subfield is set to 1 + * in the downlink direction. + * An AC is trigger and delivery enabled AC if the PSB subfield + * is set to 1 in the bi-direction field. + */ + if (addts.tspec.tsinfo.traffic.psb == 1) + lim_set_tspec_uapsd_mask_per_session(mac_ctx, session, + &addts.tspec.tsinfo, + SET_UAPSD_MASK); + else + lim_set_tspec_uapsd_mask_per_session(mac_ctx, session, + &addts.tspec.tsinfo, + CLEAR_UAPSD_MASK); + + /* + * ADDTS success, so AC is now admitted. We shall now use the default + * EDCA parameters as advertised by AP and send the updated EDCA params + * to HAL. + */ + ac = upToAc(addts.tspec.tsinfo.traffic.userPrio); + if (addts.tspec.tsinfo.traffic.direction == + SIR_MAC_DIRECTION_UPLINK) { + session->gAcAdmitMask[SIR_MAC_DIRECTION_UPLINK] |= + (1 << ac); + } else if (addts.tspec.tsinfo.traffic.direction == + SIR_MAC_DIRECTION_DNLINK) { + session->gAcAdmitMask[SIR_MAC_DIRECTION_DNLINK] |= + (1 << ac); + } else if (addts.tspec.tsinfo.traffic.direction == + SIR_MAC_DIRECTION_BIDIR) { + session->gAcAdmitMask[SIR_MAC_DIRECTION_UPLINK] |= + (1 << ac); + session->gAcAdmitMask[SIR_MAC_DIRECTION_DNLINK] |= + (1 << ac); + } + lim_set_active_edca_params(mac_ctx, session->gLimEdcaParams, + session); + sta_ds_ptr = dph_get_hash_entry(mac_ctx, DPH_STA_HASH_INDEX_PEER, + &session->dph.dphHashTable); + if (sta_ds_ptr != NULL) + lim_send_edca_params(mac_ctx, session->gLimEdcaParamsActive, + sta_ds_ptr->bssId); + else + lim_log(mac_ctx, LOGE, FL("Self entry missing in Hash Table ")); + sir_copy_mac_addr(peer_macaddr, session->bssId); + /* if schedule is not present then add TSPEC with svcInterval as 0. */ + if (!addts.schedulePresent) + addts.schedule.svcInterval = 0; + if (eSIR_SUCCESS != + lim_tspec_add(mac_ctx, sta_ptr->staAddr, sta_ptr->assocId, + &addts.tspec, addts.schedule.svcInterval, &tspec_info)) { + lim_log(mac_ctx, LOGE, + FL("Adding entry in lim Tspec Table failed ")); + lim_send_delts_req_action_frame(mac_ctx, peer_macaddr, rsp_reqd, + &addts.tspec.tsinfo, + &addts.tspec, session); + mac_ctx->lim.gLimAddtsSent = false; + return; + /* + * Error handling. send the response with error status. + * need to send DelTS to tear down the TSPEC status. + */ + } + if ((addts.tspec.tsinfo.traffic.accessPolicy != + SIR_MAC_ACCESSPOLICY_EDCA) || + ((upToAc(addts.tspec.tsinfo.traffic.userPrio) < MAX_NUM_AC))) { +#ifdef FEATURE_WLAN_ESE + retval = lim_send_hal_msg_add_ts(mac_ctx, + sta_ptr->staIndex, tspec_info->idx, + addts.tspec, session->peSessionId, + addts.tsmIE.msmt_interval); +#else + retval = lim_send_hal_msg_add_ts(mac_ctx, + sta_ptr->staIndex, tspec_info->idx, + addts.tspec, session->peSessionId); +#endif + if (eSIR_SUCCESS != retval) { + lim_admit_control_delete_ts(mac_ctx, sta_ptr->assocId, + &addts.tspec.tsinfo, NULL, &tspec_info->idx); + + /* Send DELTS action frame to AP */ + cfg_len = sizeof(tSirMacAddr); + lim_send_delts_req_action_frame(mac_ctx, peer_macaddr, + rsp_reqd, &addts.tspec.tsinfo, + &addts.tspec, session); + lim_send_sme_addts_rsp(mac_ctx, true, retval, + session, addts.tspec, + session->smeSessionId, + session->transactionId); + mac_ctx->lim.gLimAddtsSent = false; + return; + } + lim_log(mac_ctx, LOGW, + FL("AddTsRsp received successfully(UP %d, TSID %d)"), + addts.tspec.tsinfo.traffic.userPrio, + addts.tspec.tsinfo.traffic.tsid); + } else { + lim_log(mac_ctx, LOGW, + FL("AddTsRsp received successfully(UP %d, TSID %d)"), + addts.tspec.tsinfo.traffic.userPrio, + addts.tspec.tsinfo.traffic.tsid); + lim_log(mac_ctx, LOGW, + FL("no ACM: Bypass sending WMA_ADD_TS_REQ to HAL ")); + /* + * Use the smesessionId and smetransactionId from the PE + * session context + */ + lim_send_sme_addts_rsp(mac_ctx, true, eSIR_SME_SUCCESS, + session, addts.tspec, session->smeSessionId, + session->transactionId); + } + /* clear the addts flag */ + mac_ctx->lim.gLimAddtsSent = false; + return; +} + +/** + * __lim_process_del_ts_req() - To process del ts response frame + * @mac_ctx: pointer to mac context + * @rx_pkt_info: Received packet info + * @session: pointer to session + * + * This routine is to handle del ts request frame + * + * Return: none + */ +static void __lim_process_del_ts_req(tpAniSirGlobal mac_ctx, + uint8_t *rx_pkt_info, tpPESession session) +{ + tSirRetStatus retval; + tSirDeltsReqInfo delts; + tpSirMacMgmtHdr mac_hdr; + tpDphHashNode sta_ptr; + uint32_t frame_len; + uint16_t aid; + uint8_t *body_ptr; + uint8_t ts_status; + tSirMacTSInfo *tsinfo; + uint8_t tspec_idx; + uint8_t ac; + tpDphHashNode sta_ds_ptr = NULL; + + mac_hdr = WMA_GET_RX_MAC_HEADER(rx_pkt_info); + body_ptr = WMA_GET_RX_MPDU_DATA(rx_pkt_info); + frame_len = WMA_GET_RX_PAYLOAD_LEN(rx_pkt_info); + + sta_ptr = dph_lookup_hash_entry(mac_ctx, mac_hdr->sa, &aid, + &session->dph.dphHashTable); + if (sta_ptr == NULL) { + lim_log(mac_ctx, LOGE, + FL("Station context not found - ignoring DelTs")); + return; + } + /* parse the delts request */ + retval = sir_convert_delts_req2_struct(mac_ctx, body_ptr, + frame_len, &delts); + if (retval != eSIR_SUCCESS) { + lim_log(mac_ctx, LOGW, + FL("DelTs parsing failed (error %d)"), retval); + return; + } + + if (delts.wmeTspecPresent) { + if ((!session->limWmeEnabled) || (!sta_ptr->wmeEnabled)) { + lim_log(mac_ctx, LOGW, + FL("Ignore delts req: wme not enabled")); + return; + } + lim_log(mac_ctx, LOG2, FL("WME Delts received")); + } else if ((session->limQosEnabled) && sta_ptr->lleEnabled) { + lim_log(mac_ctx, LOG2, FL("11e QoS Delts received")); + } else if ((session->limWsmEnabled) && sta_ptr->wsmEnabled) { + lim_log(mac_ctx, LOG2, FL("WSM Delts received")); + } else { + lim_log(mac_ctx, LOGW, + FL("Ignoring delts request: qos not enabled/capable")); + return; + } + + tsinfo = delts.wmeTspecPresent ? &delts.tspec.tsinfo : &delts.tsinfo; + + /* if no Admit Control, ignore the request */ + if ((tsinfo->traffic.accessPolicy == SIR_MAC_ACCESSPOLICY_EDCA)) { + + if (upToAc(tsinfo->traffic.userPrio) >= MAX_NUM_AC) { + lim_log(mac_ctx, LOGW, + FL("DelTs with UP %d has no AC - ignoring req"), + tsinfo->traffic.userPrio); + return; + } + } + + if (!LIM_IS_AP_ROLE(session)) + lim_send_sme_delts_ind(mac_ctx, &delts, aid, session); + + /* try to delete the TS */ + if (eSIR_SUCCESS != + lim_admit_control_delete_ts(mac_ctx, sta_ptr->assocId, tsinfo, + &ts_status, &tspec_idx)) { + lim_log(mac_ctx, LOGW, FL("Unable to Delete TS")); + return; + } else if (!((tsinfo->traffic.accessPolicy == SIR_MAC_ACCESSPOLICY_HCCA) + || (tsinfo->traffic.accessPolicy == + SIR_MAC_ACCESSPOLICY_BOTH))){ + /* send message to HAL to delete TS */ + if (eSIR_SUCCESS != lim_send_hal_msg_del_ts(mac_ctx, + sta_ptr->staIndex, tspec_idx, + delts, session->peSessionId, + session->bssId)) { + lim_log(mac_ctx, LOGW, + FL("DelTs with UP %d failed ignoring request"), + tsinfo->traffic.userPrio); + return; + } + } + /* + * We successfully deleted the TSPEC. Update the dynamic UAPSD Mask. + * The AC for this TSPEC is no longer trigger enabled if this Tspec + * was set-up in uplink direction only. + * The AC for this TSPEC is no longer delivery enabled if this Tspec + * was set-up in downlink direction only. + * The AC for this TSPEC is no longer triiger enabled and delivery + * enabled if this Tspec was a bidirectional TSPEC. + */ + lim_set_tspec_uapsd_mask_per_session(mac_ctx, session, + tsinfo, CLEAR_UAPSD_MASK); + /* + * We're deleting the TSPEC. + * The AC for this TSPEC is no longer admitted in uplink/downlink + * direction if this TSPEC was set-up in uplink/downlink direction only. + * The AC for this TSPEC is no longer admitted in both uplink and + * downlink directions if this TSPEC was a bi-directional TSPEC. + * If ACM is set for this AC and this AC is admitted only in downlink + * direction, PE needs to downgrade the EDCA parameter + * (for the AC for which TS is being deleted) to the + * next best AC for which ACM is not enabled, and send the + * updated values to HAL. + */ + ac = upToAc(tsinfo->traffic.userPrio); + if (tsinfo->traffic.direction == SIR_MAC_DIRECTION_UPLINK) { + session->gAcAdmitMask[SIR_MAC_DIRECTION_UPLINK] &= + ~(1 << ac); + } else if (tsinfo->traffic.direction == + SIR_MAC_DIRECTION_DNLINK) { + session->gAcAdmitMask[SIR_MAC_DIRECTION_DNLINK] &= + ~(1 << ac); + } else if (tsinfo->traffic.direction == SIR_MAC_DIRECTION_BIDIR) { + session->gAcAdmitMask[SIR_MAC_DIRECTION_UPLINK] &= + ~(1 << ac); + session->gAcAdmitMask[SIR_MAC_DIRECTION_DNLINK] &= + ~(1 << ac); + } + lim_set_active_edca_params(mac_ctx, session->gLimEdcaParams, + session); + sta_ds_ptr = dph_get_hash_entry(mac_ctx, DPH_STA_HASH_INDEX_PEER, + &session->dph.dphHashTable); + if (sta_ds_ptr != NULL) + lim_send_edca_params(mac_ctx, session->gLimEdcaParamsActive, + sta_ds_ptr->bssId); + else + lim_log(mac_ctx, LOGE, FL("Self entry missing in Hash Table ")); + + lim_log(mac_ctx, LOG1, FL("DeleteTS succeeded")); +#ifdef FEATURE_WLAN_ESE + lim_send_sme_tsm_ie_ind(mac_ctx, session, 0, 0, 0); +#endif +} + +/** + * __lim_process_qos_map_configure_frame() - to process QoS map configure frame + * @mac_ctx: pointer to mac context + * @rx_pkt_info: pointer to received packet info + * @session: pointer to session + * + * This routine will called to process qos map configure frame + * + * Return: none + */ +static void __lim_process_qos_map_configure_frame(tpAniSirGlobal mac_ctx, + uint8_t *rx_pkt_info, tpPESession session) +{ + tpSirMacMgmtHdr mac_hdr; + uint32_t frame_len; + uint8_t *body_ptr; + tSirRetStatus retval; + mac_hdr = WMA_GET_RX_MAC_HEADER(rx_pkt_info); + body_ptr = WMA_GET_RX_MPDU_DATA(rx_pkt_info); + frame_len = WMA_GET_RX_PAYLOAD_LEN(rx_pkt_info); + retval = sir_convert_qos_map_configure_frame2_struct(mac_ctx, + body_ptr, frame_len, &session->QosMapSet); + if (retval != eSIR_SUCCESS) { + lim_log(mac_ctx, LOGE, + FL("QosMapConfigure frame parsing fail(error %d)"), + retval); + return; + } + lim_send_sme_mgmt_frame_ind(mac_ctx, mac_hdr->fc.subType, + (uint8_t *) mac_hdr, + frame_len + sizeof(tSirMacMgmtHdr), 0, + WMA_GET_RX_CH(rx_pkt_info), session, 0); +} + +#ifdef ANI_SUPPORT_11H +static void +__lim_process_basic_meas_req(tpAniSirGlobal pMac, + tpSirMacMeasReqActionFrame pMeasReqFrame, + tSirMacAddr peerMacAddr, tpPESession psessionEntry) +{ + if (lim_send_meas_report_frame(pMac, pMeasReqFrame, + peerMacAddr, psessionEntry) != + eSIR_SUCCESS) { + PELOGE(lim_log + (pMac, LOGE, FL("fail to send Basic Meas report ")); + ) + return; + } +} +static void +__lim_process_cca_meas_req(tpAniSirGlobal pMac, + tpSirMacMeasReqActionFrame pMeasReqFrame, + tSirMacAddr peerMacAddr, tpPESession psessionEntry) +{ + if (lim_send_meas_report_frame(pMac, pMeasReqFrame, + peerMacAddr, psessionEntry) != + eSIR_SUCCESS) { + PELOGE(lim_log(pMac, LOGE, FL("fail to send CCA Meas report "));) + return; + } +} +static void +__lim_process_rpi_meas_req(tpAniSirGlobal pMac, + tpSirMacMeasReqActionFrame pMeasReqFrame, + tSirMacAddr peerMacAddr, tpPESession psessionEntry) +{ + if (lim_send_meas_report_frame(pMac, pMeasReqFrame, + peerMacAddr, psessionEntry) != + eSIR_SUCCESS) { + PELOGE(lim_log(pMac, LOGE, FL("fail to send RPI Meas report "));) + return; + } +} +static void +__lim_process_measurement_request_frame(tpAniSirGlobal pMac, + uint8_t *pRxPacketInfo, + tpPESession psessionEntry) +{ + tpSirMacMgmtHdr pHdr; + uint8_t *pBody; + tpSirMacMeasReqActionFrame pMeasReqFrame; + uint32_t frameLen; + + pHdr = WMA_GET_RX_MAC_HEADER(pRxPacketInfo); + pBody = WMA_GET_RX_MPDU_DATA(pRxPacketInfo); + frameLen = WMA_GET_RX_PAYLOAD_LEN(pRxPacketInfo); + + pMeasReqFrame = qdf_mem_malloc(sizeof(tSirMacMeasReqActionFrame)); + if (NULL == pMeasReqFrame) { + lim_log(pMac, LOGE, + FL + ("limProcessMeasurementRequestFrame: AllocateMemory failed ")); + return; + } + + if (sir_convert_meas_req_frame2_struct(pMac, pBody, pMeasReqFrame, frameLen) + != eSIR_SUCCESS) { + PELOGW(lim_log + (pMac, LOGW, + FL("Rcv invalid Measurement Request Action Frame ")); + ) + return; + } + switch (pMeasReqFrame->measReqIE.measType) { + case SIR_MAC_BASIC_MEASUREMENT_TYPE: + __lim_process_basic_meas_req(pMac, pMeasReqFrame, pHdr->sa, + psessionEntry); + break; + case SIR_MAC_CCA_MEASUREMENT_TYPE: + __lim_process_cca_meas_req(pMac, pMeasReqFrame, pHdr->sa, + psessionEntry); + break; + case SIR_MAC_RPI_MEASUREMENT_TYPE: + __lim_process_rpi_meas_req(pMac, pMeasReqFrame, pHdr->sa, + psessionEntry); + break; + default: + PELOG1(lim_log(pMac, LOG1, FL("Unknown Measurement Type %d "), + pMeasReqFrame->measReqIE.measType); + ) + break; + } +} /*** end limProcessMeasurementRequestFrame ***/ +static void +__lim_process_tpc_request_frame(tpAniSirGlobal pMac, uint8_t *pRxPacketInfo, + tpPESession psessionEntry) +{ + tpSirMacMgmtHdr pHdr; + uint8_t *pBody; + tpSirMacTpcReqActionFrame pTpcReqFrame; + uint32_t frameLen; + pHdr = WMA_GET_RX_MAC_HEADER(pRxPacketInfo); + pBody = WMA_GET_RX_MPDU_DATA(pRxPacketInfo); + frameLen = WMA_GET_RX_PAYLOAD_LEN(pRxPacketInfo); + PELOG1(lim_log + (pMac, LOG1, + FL("****LIM: Processing TPC Request from peer ****")); + ) + pTpcReqFrame = qdf_mem_malloc(sizeof(tSirMacTpcReqActionFrame)); + if (NULL == pTpcReqFrame) { + PELOGE(lim_log(pMac, LOGE, FL("AllocateMemory failed "));) + return; + } + if (sir_convert_tpc_req_frame2_struct(pMac, pBody, pTpcReqFrame, frameLen) != + eSIR_SUCCESS) { + PELOGW(lim_log + (pMac, LOGW, FL("Rcv invalid TPC Req Action Frame ")); + ) + return; + } + if (lim_send_tpc_report_frame(pMac, + pTpcReqFrame, + pHdr->sa, psessionEntry) != eSIR_SUCCESS) { + PELOGE(lim_log + (pMac, LOGE, FL("fail to send TPC Report Frame. ")); + ) + return; + } +} +#endif + +static void +__lim_process_sm_power_save_update(tpAniSirGlobal pMac, uint8_t *pRxPacketInfo, + tpPESession psessionEntry) +{ + + tpSirMacMgmtHdr pHdr; + tDot11fSMPowerSave frmSMPower; + tSirMacHTMIMOPowerSaveState state; + tpDphHashNode pSta; + uint16_t aid; + uint32_t frameLen, nStatus; + uint8_t *pBody; + + pHdr = WMA_GET_RX_MAC_HEADER(pRxPacketInfo); + pBody = WMA_GET_RX_MPDU_DATA(pRxPacketInfo); + frameLen = WMA_GET_RX_PAYLOAD_LEN(pRxPacketInfo); + + pSta = + dph_lookup_hash_entry(pMac, pHdr->sa, &aid, + &psessionEntry->dph.dphHashTable); + if (pSta == NULL) { + lim_log(pMac, LOGE, + FL + ("STA context not found - ignoring UpdateSM PSave Mode from ")); + lim_print_mac_addr(pMac, pHdr->sa, LOGW); + return; + } + + /**Unpack the received frame */ + nStatus = dot11f_unpack_sm_power_save(pMac, pBody, frameLen, &frmSMPower); + + if (DOT11F_FAILED(nStatus)) { + lim_log(pMac, LOGE, + FL + ("Failed to unpack and parse a Update SM Power (0x%08x, %d bytes):"), + nStatus, frameLen); + PELOG2(sir_dump_buf + (pMac, SIR_DBG_MODULE_ID, LOG2, pBody, frameLen); + ) + return; + } else if (DOT11F_WARNED(nStatus)) { + lim_log(pMac, LOGW, + FL + ("There were warnings while unpacking a SMPower Save update (0x%08x, %d bytes):"), + nStatus, frameLen); + } + + lim_log(pMac, LOGW, + FL("Received SM Power save Mode update Frame with PS_Enable:%d" + "PS Mode: %d"), frmSMPower.SMPowerModeSet.PowerSave_En, + frmSMPower.SMPowerModeSet.Mode); + + /** Update in the DPH Table about the Update in the SM Power Save mode*/ + if (frmSMPower.SMPowerModeSet.PowerSave_En + && frmSMPower.SMPowerModeSet.Mode) + state = eSIR_HT_MIMO_PS_DYNAMIC; + else if ((frmSMPower.SMPowerModeSet.PowerSave_En) + && (frmSMPower.SMPowerModeSet.Mode == 0)) + state = eSIR_HT_MIMO_PS_STATIC; + else if ((frmSMPower.SMPowerModeSet.PowerSave_En == 0) + && (frmSMPower.SMPowerModeSet.Mode == 0)) + state = eSIR_HT_MIMO_PS_NO_LIMIT; + else { + PELOGW(lim_log + (pMac, LOGW, + FL + ("Received SM Power save Mode update Frame with invalid mode")); + ) + return; + } + + if (state == pSta->htMIMOPSState) { + PELOGE(lim_log + (pMac, LOGE, + FL("The PEER is already set in the same mode")); + ) + return; + } + + /** Update in the HAL Station Table for the Update of the Protection Mode */ + pSta->htMIMOPSState = state; + lim_post_sm_state_update(pMac, pSta->staIndex, pSta->htMIMOPSState, + pSta->staAddr, psessionEntry->smeSessionId); +} + + +static void +__lim_process_radio_measure_request(tpAniSirGlobal pMac, uint8_t *pRxPacketInfo, + tpPESession psessionEntry) +{ + tpSirMacMgmtHdr pHdr; + tDot11fRadioMeasurementRequest *frm; + uint32_t frameLen, nStatus; + uint8_t *pBody; + + pHdr = WMA_GET_RX_MAC_HEADER(pRxPacketInfo); + pBody = WMA_GET_RX_MPDU_DATA(pRxPacketInfo); + frameLen = WMA_GET_RX_PAYLOAD_LEN(pRxPacketInfo); + + if (psessionEntry == NULL) { + return; + } + + lim_send_sme_mgmt_frame_ind(pMac, pHdr->fc.subType, (uint8_t *)pHdr, + frameLen + sizeof(tSirMacMgmtHdr), 0, + WMA_GET_RX_CH(pRxPacketInfo), psessionEntry, 0); + + frm = qdf_mem_malloc(sizeof(*frm)); + if (frm == NULL) { + lim_log(pMac, LOGE, + FL("Failed to alloc memory for tDot11fRadioMeasurementRequest")); + return; + } + + /**Unpack the received frame */ + nStatus = dot11f_unpack_radio_measurement_request(pMac, + pBody, + frameLen, frm); + + if (DOT11F_FAILED(nStatus)) { + lim_log(pMac, LOGE, + FL("Failed to unpack and parse a Radio Measure request (0x%08x, %d bytes):"), + nStatus, frameLen); + PELOG2(sir_dump_buf + (pMac, SIR_DBG_MODULE_ID, LOG2, pBody, frameLen);) + goto err; + } else if (DOT11F_WARNED(nStatus)) { + lim_log(pMac, LOGW, + FL("There were warnings while unpacking a Radio Measure request (0x%08x, %d bytes):"), + nStatus, frameLen); + } + /* Call rrm function to handle the request. */ + + rrm_process_radio_measurement_request(pMac, pHdr->sa, frm, + psessionEntry); +err: + qdf_mem_free(frm); +} + +static tSirRetStatus +__lim_process_link_measurement_req(tpAniSirGlobal pMac, uint8_t *pRxPacketInfo, + tpPESession psessionEntry) +{ + tpSirMacMgmtHdr pHdr; + tDot11fLinkMeasurementRequest frm; + uint32_t frameLen, nStatus; + uint8_t *pBody; + + pHdr = WMA_GET_RX_MAC_HEADER(pRxPacketInfo); + pBody = WMA_GET_RX_MPDU_DATA(pRxPacketInfo); + frameLen = WMA_GET_RX_PAYLOAD_LEN(pRxPacketInfo); + + if (psessionEntry == NULL) { + return eSIR_FAILURE; + } + + /**Unpack the received frame */ + nStatus = + dot11f_unpack_link_measurement_request(pMac, pBody, frameLen, &frm); + + if (DOT11F_FAILED(nStatus)) { + lim_log(pMac, LOGE, + FL + ("Failed to unpack and parse a Link Measure request (0x%08x, %d bytes):"), + nStatus, frameLen); + PELOG2(sir_dump_buf + (pMac, SIR_DBG_MODULE_ID, LOG2, pBody, frameLen); + ) + return eSIR_FAILURE; + } else if (DOT11F_WARNED(nStatus)) { + lim_log(pMac, LOGW, + FL + ("There were warnings while unpacking a Link Measure request (0x%08x, %d bytes):"), + nStatus, frameLen); + } + /* Call rrm function to handle the request. */ + + return rrm_process_link_measurement_request(pMac, pRxPacketInfo, &frm, + psessionEntry); + +} + +static void +__lim_process_neighbor_report(tpAniSirGlobal pMac, uint8_t *pRxPacketInfo, + tpPESession psessionEntry) +{ + tpSirMacMgmtHdr pHdr; + tDot11fNeighborReportResponse *pFrm; + uint32_t frameLen, nStatus; + uint8_t *pBody; + + pHdr = WMA_GET_RX_MAC_HEADER(pRxPacketInfo); + pBody = WMA_GET_RX_MPDU_DATA(pRxPacketInfo); + frameLen = WMA_GET_RX_PAYLOAD_LEN(pRxPacketInfo); + + pFrm = qdf_mem_malloc(sizeof(tDot11fNeighborReportResponse)); + if (NULL == pFrm) { + lim_log(pMac, LOGE, + FL + ("Unable to allocate memory in __lim_process_neighbor_report")); + return; + } + + if (psessionEntry == NULL) { + qdf_mem_free(pFrm); + return; + } + + /**Unpack the received frame */ + nStatus = + dot11f_unpack_neighbor_report_response(pMac, pBody, frameLen, pFrm); + + if (DOT11F_FAILED(nStatus)) { + lim_log(pMac, LOGE, + FL + ("Failed to unpack and parse a Neighbor report response (0x%08x, %d bytes):"), + nStatus, frameLen); + PELOG2(sir_dump_buf + (pMac, SIR_DBG_MODULE_ID, LOG2, pBody, frameLen); + ) + qdf_mem_free(pFrm); + return; + } else if (DOT11F_WARNED(nStatus)) { + lim_log(pMac, LOGW, + FL + ("There were warnings while unpacking a Neighbor report response (0x%08x, %d bytes):"), + nStatus, frameLen); + } + /* Call rrm function to handle the request. */ + rrm_process_neighbor_report_response(pMac, pFrm, psessionEntry); + + qdf_mem_free(pFrm); +} + + +#ifdef WLAN_FEATURE_11W +/** + * limProcessSAQueryRequestActionFrame + * + ***FUNCTION: + * This function is called by lim_process_action_frame() upon + * SA query request Action frame reception. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param pMac - Pointer to Global MAC structure + * @param *pRxPacketInfo - Handle to the Rx packet info + * @param psessionEntry - PE session entry + * + * @return None + */ +static void __lim_process_sa_query_request_action_frame(tpAniSirGlobal pMac, + uint8_t *pRxPacketInfo, + tpPESession psessionEntry) +{ + tpSirMacMgmtHdr pHdr; + uint8_t *pBody; + uint8_t transId[2]; + + /* Prima --- Below Macro not available in prima + pHdr = SIR_MAC_BD_TO_MPDUHEADER(pBd); + pBody = SIR_MAC_BD_TO_MPDUDATA(pBd); */ + + pHdr = WMA_GET_RX_MAC_HEADER(pRxPacketInfo); + pBody = WMA_GET_RX_MPDU_DATA(pRxPacketInfo); + + /* If this is an unprotected SA Query Request, then ignore it. */ + if (pHdr->fc.wep == 0) + return; + + /* 11w offload is enabled then firmware should not fwd this frame */ + if (LIM_IS_STA_ROLE(psessionEntry) && pMac->pmf_offload) { + lim_log(pMac, LOGE, + FL("11w offload enabled, SA Query req isn't expected")); + return; + } + + /*Extract 11w trsansId from SA query request action frame + In SA query response action frame we will send same transId + In SA query request action frame: + Category : 1 byte + Action : 1 byte + Transaction ID : 2 bytes */ + qdf_mem_copy(&transId[0], &pBody[2], 2); + + /* Send 11w SA query response action frame */ + if (lim_send_sa_query_response_frame(pMac, + transId, + pHdr->sa, + psessionEntry) != eSIR_SUCCESS) { + PELOGE(lim_log + (pMac, LOGE, + FL("fail to send SA query response action frame.")); + ) + return; + } +} + +/** + * __lim_process_sa_query_response_action_frame + * + ***FUNCTION: + * This function is called by lim_process_action_frame() upon + * SA query response Action frame reception. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param pMac - Pointer to Global MAC structure + * @param *pRxPacketInfo - Handle to the Rx packet info + * @param psessionEntry - PE session entry + * @return None + */ +static void __lim_process_sa_query_response_action_frame(tpAniSirGlobal pMac, + uint8_t *pRxPacketInfo, + tpPESession psessionEntry) +{ + tpSirMacMgmtHdr pHdr; + uint32_t frameLen; + uint8_t *pBody; + tpDphHashNode pSta; + uint16_t aid; + uint16_t transId; + uint8_t retryNum; + + pHdr = WMA_GET_RX_MAC_HEADER(pRxPacketInfo); + frameLen = WMA_GET_RX_PAYLOAD_LEN(pRxPacketInfo); + pBody = WMA_GET_RX_MPDU_DATA(pRxPacketInfo); + QDF_TRACE(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_INFO, + ("SA Query Response received...")); + + /* When a station, supplicant handles SA Query Response. + * Forward to SME to HDD to wpa_supplicant. + */ + if (LIM_IS_STA_ROLE(psessionEntry)) { + lim_send_sme_mgmt_frame_ind(pMac, pHdr->fc.subType, (uint8_t *) pHdr, + frameLen + sizeof(tSirMacMgmtHdr), 0, + WMA_GET_RX_CH(pRxPacketInfo), + psessionEntry, 0); + return; + } + + /* If this is an unprotected SA Query Response, then ignore it. */ + if (pHdr->fc.wep == 0) + return; + + pSta = + dph_lookup_hash_entry(pMac, pHdr->sa, &aid, + &psessionEntry->dph.dphHashTable); + if (NULL == pSta) + return; + + lim_log(pMac, LOG1, + FL("SA Query Response source addr - %0x:%0x:%0x:%0x:%0x:%0x"), + pHdr->sa[0], pHdr->sa[1], pHdr->sa[2], pHdr->sa[3], + pHdr->sa[4], pHdr->sa[5]); + lim_log(pMac, LOG1, + FL("SA Query state for station - %d"), pSta->pmfSaQueryState); + + if (DPH_SA_QUERY_IN_PROGRESS != pSta->pmfSaQueryState) + return; + + /* Extract 11w trsansId from SA query reponse action frame + In SA query response action frame: + Category : 1 byte + Action : 1 byte + Transaction ID : 2 bytes */ + qdf_mem_copy(&transId, &pBody[2], 2); + + /* If SA Query is in progress with the station and the station + responds then the association request that triggered the SA + query is from a rogue station, just go back to initial state. */ + for (retryNum = 0; retryNum <= pSta->pmfSaQueryRetryCount; retryNum++) + if (transId == pSta->pmfSaQueryStartTransId + retryNum) { + lim_log(pMac, LOG1, + FL + ("Found matching SA Query Request - transaction ID %d"), + transId); + tx_timer_deactivate(&pSta->pmfSaQueryTimer); + pSta->pmfSaQueryState = DPH_SA_QUERY_NOT_IN_PROGRESS; + break; + } +} +#endif + +#ifdef WLAN_FEATURE_11W +/** + * lim_drop_unprotected_action_frame + * + ***FUNCTION: + * This function checks if an Action frame should be dropped since it is + * a Robust Managment Frame, it is unprotected, and it is received on a + * connection where PMF is enabled. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param pMac - Global MAC structure + * @param psessionEntry - PE session entry + * @param pHdr - Frame header + * @param category - Action frame category + * @return true if frame should be dropped + */ + +static bool +lim_drop_unprotected_action_frame(tpAniSirGlobal pMac, tpPESession psessionEntry, + tpSirMacMgmtHdr pHdr, uint8_t category) +{ + uint16_t aid; + tpDphHashNode pStaDs; + bool rmfConnection = false; + + if (LIM_IS_AP_ROLE(psessionEntry)) { + pStaDs = + dph_lookup_hash_entry(pMac, pHdr->sa, &aid, + &psessionEntry->dph.dphHashTable); + if (pStaDs != NULL) + if (pStaDs->rmfEnabled) + rmfConnection = true; + } else if (psessionEntry->limRmfEnabled) + rmfConnection = true; + + if (rmfConnection && (pHdr->fc.wep == 0)) { + lim_log(pMac, LOGE, + FL("Dropping unprotected Action category %d frame since RMF is enabled."), category); + return true; + } else + return false; +} +#endif + +/** + * lim_process_action_frame() - to process action frames + * @mac_ctx: Pointer to Global MAC structure + * @rx_pkt_info: A pointer to packet info structure + * + * This function is called by limProcessMessageQueue() upon + * Action frame reception. + * + * Return: none + */ + +void lim_process_action_frame(tpAniSirGlobal mac_ctx, + uint8_t *rx_pkt_info, tpPESession session) +{ + uint8_t *body_ptr = WMA_GET_RX_MPDU_DATA(rx_pkt_info); + tpSirMacActionFrameHdr action_hdr = (tpSirMacActionFrameHdr) body_ptr; +#ifdef WLAN_FEATURE_11W + tpSirMacMgmtHdr mac_hdr_11w = WMA_GET_RX_MAC_HEADER(rx_pkt_info); +#endif + tpSirMacMgmtHdr mac_hdr = NULL; + int8_t rssi; + uint32_t frame_len; + tpSirMacVendorSpecificFrameHdr vendor_specific; + uint8_t oui[] = { 0x00, 0x00, 0xf0 }; + tpSirMacVendorSpecificPublicActionFrameHdr pub_action; + uint8_t p2p_oui[] = { 0x50, 0x6F, 0x9A, 0x09 }; + +#ifdef WLAN_FEATURE_11W + if (lim_is_robust_mgmt_action_frame(action_hdr->category) && + lim_drop_unprotected_action_frame(mac_ctx, session, + mac_hdr_11w, action_hdr->category)) + return; +#endif + + frame_len = WMA_GET_RX_PAYLOAD_LEN(rx_pkt_info); + + switch (action_hdr->category) { + case SIR_MAC_ACTION_QOS_MGMT: + if ((session->limQosEnabled) || + (action_hdr->actionID == SIR_MAC_QOS_MAP_CONFIGURE)) { + switch (action_hdr->actionID) { + case SIR_MAC_QOS_ADD_TS_REQ: + __lim_process_add_ts_req(mac_ctx, + (uint8_t *) rx_pkt_info, + session); + break; + + case SIR_MAC_QOS_ADD_TS_RSP: + __lim_process_add_ts_rsp(mac_ctx, + (uint8_t *) rx_pkt_info, + session); + break; + + case SIR_MAC_QOS_DEL_TS_REQ: + __lim_process_del_ts_req(mac_ctx, + (uint8_t *) rx_pkt_info, + session); + break; + + case SIR_MAC_QOS_MAP_CONFIGURE: + __lim_process_qos_map_configure_frame(mac_ctx, + (uint8_t *)rx_pkt_info, + session); + break; + default: + lim_log(mac_ctx, LOG1, + FL("Qos action %d not handled"), + action_hdr->actionID); + break; + } + break; + } + break; + + case SIR_MAC_ACTION_SPECTRUM_MGMT: + switch (action_hdr->actionID) { +#ifdef ANI_SUPPORT_11H + case SIR_MAC_ACTION_MEASURE_REQUEST_ID: + if (session->lim11hEnable) + __lim_process_measurement_request_frame(mac_ctx, + rx_pkt_info, + session); + break; + case SIR_MAC_ACTION_TPC_REQUEST_ID: + if ((LIM_IS_STA_ROLE(session) || + LIM_IS_AP_ROLE(session)) && + session->lim11hEnable) + __lim_process_tpc_request_frame(mac_ctx, + rx_pkt_info, session); + break; +#endif + case SIR_MAC_ACTION_CHANNEL_SWITCH_ID: + if (LIM_IS_STA_ROLE(session)) + __lim_process_channel_switch_action_frame( + mac_ctx, rx_pkt_info, session); + break; + default: + lim_log(mac_ctx, LOG1, + FL("Spectrum mgmt action id %d not handled"), + action_hdr->actionID); + break; + } + break; + + case SIR_MAC_ACTION_WME: + if (!session->limWmeEnabled) { + lim_log(mac_ctx, LOGW, + FL("WME mode disabled - dropping frame %d"), + action_hdr->actionID); + break; + } + switch (action_hdr->actionID) { + case SIR_MAC_QOS_ADD_TS_REQ: + __lim_process_add_ts_req(mac_ctx, + (uint8_t *) rx_pkt_info, session); + break; + + case SIR_MAC_QOS_ADD_TS_RSP: + __lim_process_add_ts_rsp(mac_ctx, + (uint8_t *) rx_pkt_info, session); + break; + + case SIR_MAC_QOS_DEL_TS_REQ: + __lim_process_del_ts_req(mac_ctx, + (uint8_t *) rx_pkt_info, session); + break; + + case SIR_MAC_QOS_MAP_CONFIGURE: + __lim_process_qos_map_configure_frame(mac_ctx, + (uint8_t *)rx_pkt_info, session); + break; + + default: + lim_log(mac_ctx, LOG1, + FL("WME action %d not handled"), + action_hdr->actionID); + break; + } + break; + + case SIR_MAC_ACTION_HT: + /** Type of HT Action to be performed*/ + switch (action_hdr->actionID) { + case SIR_MAC_SM_POWER_SAVE: + if (LIM_IS_AP_ROLE(session)) + __lim_process_sm_power_save_update(mac_ctx, + (uint8_t *)rx_pkt_info, + session); + break; + default: + lim_log(mac_ctx, LOG1, + FL("Action ID %d not handled in HT category"), + action_hdr->actionID); + break; + } + break; + + case SIR_MAC_ACTION_WNM: + lim_log(mac_ctx, LOG1, + FL("WNM Action category %d action %d."), + action_hdr->category, action_hdr->actionID); + switch (action_hdr->actionID) { + case SIR_MAC_WNM_BSS_TM_QUERY: + case SIR_MAC_WNM_BSS_TM_REQUEST: + case SIR_MAC_WNM_BSS_TM_RESPONSE: + case SIR_MAC_WNM_NOTIF_REQUEST: + case SIR_MAC_WNM_NOTIF_RESPONSE: + rssi = WMA_GET_RX_RSSI_NORMALIZED(rx_pkt_info); + mac_hdr = WMA_GET_RX_MAC_HEADER(rx_pkt_info); + /* Forward to the SME to HDD to wpa_supplicant */ + lim_send_sme_mgmt_frame_ind(mac_ctx, + mac_hdr->fc.subType, + (uint8_t *) mac_hdr, + frame_len + sizeof(tSirMacMgmtHdr), + session->smeSessionId, + WMA_GET_RX_CH(rx_pkt_info), + session, rssi); + break; + default: + lim_log(mac_ctx, LOG1, + FL("Action ID %d not handled in WNM category"), + action_hdr->actionID); + break; + } + break; + + case SIR_MAC_ACTION_RRM: + /* Ignore RRM measurement request until DHCP is set */ + if (mac_ctx->rrm.rrmPEContext.rrmEnable && + mac_ctx->roam.roamSession + [session->smeSessionId].dhcp_done) { + switch (action_hdr->actionID) { + case SIR_MAC_RRM_RADIO_MEASURE_REQ: + __lim_process_radio_measure_request(mac_ctx, + (uint8_t *)rx_pkt_info, + session); + break; + case SIR_MAC_RRM_LINK_MEASUREMENT_REQ: + if (!lim_is_valid_frame( + &rrm_link_action_frm, + rx_pkt_info)) + break; + + if (__lim_process_link_measurement_req( + mac_ctx, + (uint8_t *)rx_pkt_info, + session) == eSIR_SUCCESS) + lim_update_last_processed_frame( + &rrm_link_action_frm, + rx_pkt_info); + + break; + case SIR_MAC_RRM_NEIGHBOR_RPT: + __lim_process_neighbor_report(mac_ctx, + (uint8_t *)rx_pkt_info, + session); + break; + default: + lim_log(mac_ctx, LOG1, + FL("Action ID %d not handled in RRM"), + action_hdr->actionID); + break; + + } + } else { + /* Else we will just ignore the RRM messages. */ + lim_log(mac_ctx, LOG1, + FL("RRM frm ignored, it is disabled in cfg %d or DHCP not completed %d"), + mac_ctx->rrm.rrmPEContext.rrmEnable, + mac_ctx->roam.roamSession + [session->smeSessionId].dhcp_done); + } + break; + + case SIR_MAC_ACTION_VENDOR_SPECIFIC_CATEGORY: + vendor_specific = (tpSirMacVendorSpecificFrameHdr) action_hdr; + mac_hdr = NULL; + frame_len = 0; + + mac_hdr = WMA_GET_RX_MAC_HEADER(rx_pkt_info); + frame_len = WMA_GET_RX_PAYLOAD_LEN(rx_pkt_info); + + /* Check if it is a vendor specific action frame. */ + if (LIM_IS_STA_ROLE(session) && + (!qdf_mem_cmp(session->selfMacAddr, + &mac_hdr->da[0], sizeof(tSirMacAddr))) + && IS_WES_MODE_ENABLED(mac_ctx) + && !qdf_mem_cmp(vendor_specific->Oui, oui, 3)) { + lim_log(mac_ctx, LOGW, + FL("Rcvd Vendor specific frame, OUI %x %x %x"), + vendor_specific->Oui[0], + vendor_specific->Oui[1], + vendor_specific->Oui[2]); + /* + * Forward to the SME to HDD to wpa_supplicant + * type is ACTION + */ + lim_send_sme_mgmt_frame_ind(mac_ctx, + mac_hdr->fc.subType, + (uint8_t *) mac_hdr, + frame_len + + sizeof(tSirMacMgmtHdr), + session->smeSessionId, + WMA_GET_RX_CH(rx_pkt_info), + session, 0); + } else { + lim_log(mac_ctx, LOG1, + FL("Dropping the vendor specific action frame" + "beacause of (WES Mode not enabled " + "(WESMODE = %d) or OUI mismatch " + "(%02x %02x %02x) or not received with" + "SelfSta address) system role = %d"), + IS_WES_MODE_ENABLED(mac_ctx), + vendor_specific->Oui[0], + vendor_specific->Oui[1], + vendor_specific->Oui[2], + GET_LIM_SYSTEM_ROLE(session)); + } + break; + case SIR_MAC_ACTION_PUBLIC_USAGE: + switch (action_hdr->actionID) { + case SIR_MAC_ACTION_VENDOR_SPECIFIC: + pub_action = + (tpSirMacVendorSpecificPublicActionFrameHdr) + action_hdr; + mac_hdr = NULL; + frame_len = 0; + + mac_hdr = WMA_GET_RX_MAC_HEADER(rx_pkt_info); + frame_len = WMA_GET_RX_PAYLOAD_LEN(rx_pkt_info); + /* Check if it is a P2P public action frame. */ + if (!qdf_mem_cmp(pub_action->Oui, p2p_oui, 4)) { + /* + * Forward to the SME to HDD to wpa_supplicant + * type is ACTION + */ + lim_send_sme_mgmt_frame_ind(mac_ctx, + mac_hdr->fc.subType, + (uint8_t *) mac_hdr, + frame_len + + sizeof(tSirMacMgmtHdr), + session->smeSessionId, + WMA_GET_RX_CH(rx_pkt_info), + session, WMA_GET_RX_RSSI_RAW(rx_pkt_info)); + } else { + lim_log(mac_ctx, LOG1, + FL("Unhandled public action frame (Vendor specific). OUI %x %x %x %x"), + pub_action->Oui[0], pub_action->Oui[1], + pub_action->Oui[2], pub_action->Oui[3]); + } + break; + /* Handle vendor specific action */ + case SIR_MAC_ACTION_VENDOR_SPECIFIC_CATEGORY: + { + tpSirMacMgmtHdr header; + uint32_t frame_len; + + header = WMA_GET_RX_MAC_HEADER(rx_pkt_info); + frame_len = WMA_GET_RX_PAYLOAD_LEN(rx_pkt_info); + lim_send_sme_mgmt_frame_ind(mac_ctx, header->fc.subType, + (uint8_t *)header, frame_len + sizeof(tSirMacMgmtHdr), 0, + WMA_GET_RX_CH(rx_pkt_info), NULL, + WMA_GET_RX_RSSI_RAW(rx_pkt_info)); + break; + } + + case SIR_MAC_ACTION_2040_BSS_COEXISTENCE: + mac_hdr = NULL; + frame_len = 0; + + mac_hdr = WMA_GET_RX_MAC_HEADER(rx_pkt_info); + frame_len = WMA_GET_RX_PAYLOAD_LEN(rx_pkt_info); + + lim_send_sme_mgmt_frame_ind(mac_ctx, + mac_hdr->fc.subType, + (uint8_t *) mac_hdr, + frame_len + sizeof(tSirMacMgmtHdr), + session->smeSessionId, + WMA_GET_RX_CH(rx_pkt_info), session, 0); + break; +#ifdef FEATURE_WLAN_TDLS + case SIR_MAC_TDLS_DIS_RSP: + mac_hdr = NULL; + frame_len = 0; + rssi = 0; + + mac_hdr = WMA_GET_RX_MAC_HEADER(rx_pkt_info); + frame_len = WMA_GET_RX_PAYLOAD_LEN(rx_pkt_info); + rssi = WMA_GET_RX_RSSI_NORMALIZED(rx_pkt_info); + QDF_TRACE(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_INFO, + ("Public Action TDLS Discovery RSP ..")); + lim_send_sme_mgmt_frame_ind(mac_ctx, + mac_hdr->fc.subType, (uint8_t *) mac_hdr, + frame_len + sizeof(tSirMacMgmtHdr), + session->smeSessionId, + WMA_GET_RX_CH(rx_pkt_info), session, rssi); + break; +#endif + case SIR_MAC_ACTION_EXT_CHANNEL_SWITCH_ID: + lim_process_ext_channel_switch_action_frame(mac_ctx, + rx_pkt_info, session); + break; + default: + lim_log(mac_ctx, LOG1, + FL("Unhandled public action frame -- %x "), + action_hdr->actionID); + break; + } + break; + +#ifdef WLAN_FEATURE_11W + case SIR_MAC_ACTION_SA_QUERY: + lim_log(mac_ctx, LOG1, + FL("SA Query Action category %d action %d."), + action_hdr->category, action_hdr->actionID); + switch (action_hdr->actionID) { + case SIR_MAC_SA_QUERY_REQ: + /**11w SA query request action frame received**/ + /* Respond directly to the incoming request in LIM */ + __lim_process_sa_query_request_action_frame(mac_ctx, + (uint8_t *)rx_pkt_info, + session); + break; + case SIR_MAC_SA_QUERY_RSP: + /**11w SA query response action frame received**/ + /* Handle based on the current SA Query state */ + __lim_process_sa_query_response_action_frame(mac_ctx, + (uint8_t *)rx_pkt_info, + session); + break; + default: + break; + } + break; +#endif + case SIR_MAC_ACTION_VHT: + if (!session->vhtCapability) + break; + switch (action_hdr->actionID) { + case SIR_MAC_VHT_OPMODE_NOTIFICATION: + __lim_process_operating_mode_action_frame(mac_ctx, + rx_pkt_info, session); + break; + case SIR_MAC_VHT_GID_NOTIFICATION: + /* Only if ini supports it */ + if (session->enableVhtGid) + __lim_process_gid_management_action_frame( + mac_ctx, rx_pkt_info, session); + break; + default: + break; + } + break; + case SIR_MAC_ACTION_FST: { + tpSirMacMgmtHdr hdr; + uint32_t frame_len; + + hdr = WMA_GET_RX_MAC_HEADER(rx_pkt_info); + frame_len = WMA_GET_RX_PAYLOAD_LEN(rx_pkt_info); + + lim_log(mac_ctx, LOG1, FL("Received FST MGMT action frame")); + /* Forward to the SME to HDD */ + lim_send_sme_mgmt_frame_ind(mac_ctx, hdr->fc.subType, + (uint8_t *)hdr, + frame_len + sizeof(tSirMacMgmtHdr), + session->smeSessionId, + WMA_GET_RX_CH(rx_pkt_info), + session, 0); + break; + } + case SIR_MAC_ACTION_PROT_DUAL_PUB: + lim_log(mac_ctx, LOG1, + FL("Rcvd Protected Dual of Public Action; action %d."), + action_hdr->actionID); + switch (action_hdr->actionID) { + case SIR_MAC_PDPA_GAS_INIT_REQ: + case SIR_MAC_PDPA_GAS_INIT_RSP: + case SIR_MAC_PDPA_GAS_COMEBACK_REQ: + case SIR_MAC_PDPA_GAS_COMEBACK_RSP: + mac_hdr = WMA_GET_RX_MAC_HEADER(rx_pkt_info); + frame_len = WMA_GET_RX_PAYLOAD_LEN(rx_pkt_info); + rssi = WMA_GET_RX_RSSI_NORMALIZED(rx_pkt_info); + lim_send_sme_mgmt_frame_ind(mac_ctx, + mac_hdr->fc.subType, (uint8_t *) mac_hdr, + frame_len + sizeof(tSirMacMgmtHdr), + session->smeSessionId, + WMA_GET_RX_CH(rx_pkt_info), session, rssi); + break; + default: + lim_log(mac_ctx, LOG1, + FL("Unhandled - Protected Dual Public Action")); + break; + } + break; + default: + lim_log(mac_ctx, LOG1, + FL("Action category %d not handled"), + action_hdr->category); + break; + } +} + +/** + * lim_process_action_frame_no_session + * + ***FUNCTION: + * This function is called by limProcessMessageQueue() upon + * Action frame reception and no session. + * Currently only public action frames can be received from + * a non-associated station. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param pMac - Pointer to Global MAC structure + * @param *pBd - A pointer to Buffer descriptor + associated PDUs + * @return None + */ + +void lim_process_action_frame_no_session(tpAniSirGlobal pMac, uint8_t *pBd) +{ + uint8_t *pBody = WMA_GET_RX_MPDU_DATA(pBd); + tpSirMacVendorSpecificPublicActionFrameHdr pActionHdr = + (tpSirMacVendorSpecificPublicActionFrameHdr) pBody; + + lim_log(pMac, LOG1, "Received a Action frame -- no session"); + + switch (pActionHdr->category) { + case SIR_MAC_ACTION_PUBLIC_USAGE: + switch (pActionHdr->actionID) { + case SIR_MAC_ACTION_VENDOR_SPECIFIC: + { + tpSirMacMgmtHdr pHdr; + uint32_t frameLen; + uint8_t P2POui[] = { 0x50, 0x6F, 0x9A, 0x09 }; + + pHdr = WMA_GET_RX_MAC_HEADER(pBd); + frameLen = WMA_GET_RX_PAYLOAD_LEN(pBd); + + /* Check if it is a P2P public action frame. */ + if (!qdf_mem_cmp(pActionHdr->Oui, P2POui, 4)) { + /* Forward to the SME to HDD to wpa_supplicant */ + /* type is ACTION */ + lim_send_sme_mgmt_frame_ind(pMac, + pHdr->fc.subType, + (uint8_t *) pHdr, + frameLen + + sizeof + (tSirMacMgmtHdr), + 0, + WMA_GET_RX_CH + (pBd), NULL, 0); + } else { + lim_log(pMac, LOG1, + FL + ("Unhandled public action frame (Vendor specific). OUI %x %x %x %x"), + pActionHdr->Oui[0], + pActionHdr->Oui[1], + pActionHdr->Oui[2], + pActionHdr->Oui[3]); + } + } + break; + default: + PELOGE(lim_log + (pMac, LOG1, + FL("Unhandled public action frame -- %x "), + pActionHdr->actionID); + ) + break; + } + break; + default: + PELOGE(lim_log + (pMac, LOG1, + FL("Unhandled action frame without session -- %x "), + pActionHdr->category); + ) + break; + + } +} diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_process_assoc_req_frame.c b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_process_assoc_req_frame.c new file mode 100644 index 0000000000000000000000000000000000000000..4e572002e856670e5fb8a4986b05a7fcfa6f1356 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_process_assoc_req_frame.c @@ -0,0 +1,2366 @@ +/* + * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * This file lim_process_assoc_req_frame.c contains the code + * for processing Re/Association Request Frame. + */ +#include "cds_api.h" +#include "ani_global.h" +#include "wni_cfg.h" +#include "sir_api.h" +#include "cfg_api.h" + +#include "sch_api.h" +#include "utils_api.h" +#include "lim_types.h" +#include "lim_utils.h" +#include "lim_assoc_utils.h" +#include "lim_security_utils.h" +#include "lim_ser_des_utils.h" +#include "lim_sta_hash_api.h" +#include "lim_admit_control.h" +#include "cds_packet.h" +#include "lim_session_utils.h" + +#include "qdf_types.h" +#include "cds_utils.h" + +/** + * lim_convert_supported_channels - Parses channel support IE + * @mac_ctx: A pointer to Global MAC structure + * @assoc_ind: A pointer to SME ASSOC/REASSOC IND + * @assoc_req: A pointer to ASSOC/REASSOC Request frame + * + * This function is called by lim_process_assoc_req_frame() to + * parse the channel support IE in the Assoc/Reassoc Request + * frame, and send relevant information in the SME_ASSOC_IND + * + * Return: None + */ +static void lim_convert_supported_channels(tpAniSirGlobal mac_ctx, + tpLimMlmAssocInd assoc_ind, + tSirAssocReq *assoc_req) +{ + uint16_t i, j, index = 0; + uint8_t first_ch_no; + uint8_t chn_count; + uint8_t next_ch_no; + uint8_t channel_offset = 0; + + if (assoc_req->supportedChannels.length >= + SIR_MAX_SUPPORTED_CHANNEL_LIST) { + lim_log(mac_ctx, LOG1, + FL("Number of supported channels:%d is more than MAX"), + assoc_req->supportedChannels.length); + assoc_ind->supportedChannels.numChnl = 0; + return; + } + + for (i = 0; i < (assoc_req->supportedChannels.length); i++) { + /* Get First Channel Number */ + first_ch_no = assoc_req->supportedChannels.supportedChannels[i]; + assoc_ind->supportedChannels.channelList[index] = first_ch_no; + i++; + index++; + + /* Get Number of Channels in a Subband */ + chn_count = assoc_req->supportedChannels.supportedChannels[i]; + lim_log(mac_ctx, LOG2, + FL("Rcv assoc_req: chnl=%d, numOfChnl=%d "), + first_ch_no, chn_count); + if (index >= SIR_MAX_SUPPORTED_CHANNEL_LIST) { + lim_log(mac_ctx, LOGW, + FL("Ch count > max supported =%d "), + chn_count); + assoc_ind->supportedChannels.numChnl = 0; + return; + } + if (chn_count <= 1) + continue; + next_ch_no = first_ch_no; + if (SIR_BAND_5_GHZ == lim_get_rf_band(first_ch_no)) + channel_offset = SIR_11A_FREQUENCY_OFFSET; + else if (SIR_BAND_2_4_GHZ == lim_get_rf_band(first_ch_no)) + channel_offset = SIR_11B_FREQUENCY_OFFSET; + else + continue; + + for (j = 1; j < chn_count; j++) { + next_ch_no += channel_offset; + assoc_ind->supportedChannels.channelList[index] + = next_ch_no; + index++; + if (index >= SIR_MAX_SUPPORTED_CHANNEL_LIST) { + lim_log(mac_ctx, LOGW, + FL("Ch count > supported =%d "), + chn_count); + assoc_ind->supportedChannels.numChnl = 0; + return; + } + } + } + + assoc_ind->supportedChannels.numChnl = (uint8_t) index; + lim_log(mac_ctx, LOG2, + FL("Send AssocInd to WSM: minPwr %d, maxPwr %d, numChnl %d"), + assoc_ind->powerCap.minTxPower, + assoc_ind->powerCap.maxTxPower, + assoc_ind->supportedChannels.numChnl); +} + +/** + * lim_check_sta_in_pe_entries() - checks if sta exists in any dph tables. + * @mac_ctx: Pointer to Global MAC structure + * @hdr: A pointer to the MAC header + * @sessionid - session id for which session is initiated + * + * This function is called by lim_process_assoc_req_frame() to check if STA + * entry already exists in any of the PE entries of the AP. If it exists, deauth + * will be sent on that session and the STA deletion will happen. After this, + * the ASSOC request will be processed + * + * Return: True if duplicate entry found; FALSE otherwise. + */ +static bool lim_check_sta_in_pe_entries(tpAniSirGlobal mac_ctx, tpSirMacMgmtHdr hdr, + uint16_t sessionid) +{ + uint8_t i; + uint16_t assoc_id = 0; + tpDphHashNode sta_ds = NULL; + tpPESession session = NULL; + bool dup_entry = false; + + for (i = 0; i < mac_ctx->lim.maxBssId; i++) { + if ((&mac_ctx->lim.gpSession[i] != NULL) && + (mac_ctx->lim.gpSession[i].valid) && + (mac_ctx->lim.gpSession[i].pePersona == QDF_SAP_MODE)) { + session = &mac_ctx->lim.gpSession[i]; + sta_ds = dph_lookup_hash_entry(mac_ctx, hdr->sa, + &assoc_id, &session->dph.dphHashTable); + if (sta_ds +#ifdef WLAN_FEATURE_11W + && (!sta_ds->rmfEnabled || + (sessionid != session->peSessionId)) +#endif + ) { + lim_log(mac_ctx, LOGE, + FL("Sending Disassoc and Deleting existing STA entry: " + MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(session->selfMacAddr)); + lim_send_disassoc_mgmt_frame(mac_ctx, + eSIR_MAC_UNSPEC_FAILURE_REASON, + (uint8_t *) hdr->sa, session, false); + /* + * Cleanup Rx path posts eWNI_SME_DISASSOC_RSP + * msg to SME after delete sta which will update + * the userspace with disconnect + */ + sta_ds->mlmStaContext.cleanupTrigger = + eLIM_DUPLICATE_ENTRY; + sta_ds->mlmStaContext.disassocReason = + eSIR_MAC_DISASSOC_DUE_TO_INACTIVITY_REASON; + lim_send_sme_disassoc_ind(mac_ctx, sta_ds, + session); + dup_entry = true; + break; + } + } + } + return dup_entry; +} + +/** + * lim_chk_sa_da() - checks source addr to destination addr of assoc req frame + * @mac_ctx: pointer to Global MAC structure + * @hdr: pointer to the MAC head + * @session: pointer to pe session entry + * @sub_type: Assoc(=0) or Reassoc(=1) Requestframe + * + * Checks source addr to destination addr of assoc req frame + * + * Return: true if source and destination address are different + */ +static bool lim_chk_sa_da(tpAniSirGlobal mac_ctx, tpSirMacMgmtHdr hdr, + tpPESession session, uint8_t sub_type) +{ + if (qdf_mem_cmp((uint8_t *) hdr->sa, + (uint8_t *) hdr->da, + (uint8_t) (sizeof(tSirMacAddr)))) + return true; + + lim_log(mac_ctx, LOGE, FL("Assoc Req rejected: wlan.sa = wlan.da")); + lim_send_assoc_rsp_mgmt_frame(mac_ctx, eSIR_MAC_UNSPEC_FAILURE_STATUS, + 1, hdr->sa, sub_type, 0, session); + return false; +} + +/** + * lim_chk_tkip() - checks TKIP counter measure is active + * @mac_ctx: pointer to Global MAC structure + * @hdr: pointer to the MAC head + * @session: pointer to pe session entry + * @sub_type: Assoc(=0) or Reassoc(=1) Requestframe + * + * Checks TKIP counter measure is active + * + * Return: true of no error, false otherwise + */ +static bool lim_chk_tkip(tpAniSirGlobal mac_ctx, tpSirMacMgmtHdr hdr, + tpPESession session, uint8_t sub_type) +{ + /* + * If TKIP counter measures active send Assoc Rsp frame to station + * with eSIR_MAC_MIC_FAILURE_REASON + */ + if (!(session->bTkipCntrMeasActive && LIM_IS_AP_ROLE(session))) + return true; + + lim_log(mac_ctx, LOGE, + FL("Assoc Req rejected: TKIP counter measure is active")); + lim_send_assoc_rsp_mgmt_frame(mac_ctx, eSIR_MAC_MIC_FAILURE_REASON, 1, + hdr->sa, sub_type, 0, session); + return false; +} + +/** + * lim_chk_assoc_req_parse_error() - checks for error in frame parsing + * @mac_ctx: pointer to Global MAC structure + * @hdr: pointer to the MAC head + * @session: pointer to pe session entry + * @assoc_req: pointer to ASSOC/REASSOC Request frame + * @sub_type: Assoc(=0) or Reassoc(=1) Requestframe + * @frm_body: frame body + * @frame_len: frame len + * + * Checks for error in frame parsing + * + * Return: true of no error, false otherwise + */ +static bool lim_chk_assoc_req_parse_error(tpAniSirGlobal mac_ctx, + tpSirMacMgmtHdr hdr, + tpPESession session, + tpSirAssocReq assoc_req, + uint8_t sub_type, uint8_t *frm_body, + uint32_t frame_len) +{ + tSirRetStatus status; + + if (sub_type == LIM_ASSOC) + status = sir_convert_assoc_req_frame2_struct(mac_ctx, frm_body, + frame_len, assoc_req); + else + status = sir_convert_reassoc_req_frame2_struct(mac_ctx, + frm_body, frame_len, assoc_req); + + if (status == eSIR_SUCCESS) + return true; + + lim_log(mac_ctx, LOGW, + FL("Assoc Req rejected: frame parsing error. source addr:" + MAC_ADDRESS_STR), MAC_ADDR_ARRAY(hdr->sa)); + lim_send_assoc_rsp_mgmt_frame(mac_ctx, eSIR_MAC_UNSPEC_FAILURE_STATUS, + 1, hdr->sa, sub_type, 0, session); + return false; +} + +/** + * lim_chk_capab() - checks for capab match + * @mac_ctx: pointer to Global MAC structure + * @hdr: pointer to the MAC head + * @session: pointer to pe session entry + * @assoc_req: pointer to ASSOC/REASSOC Request frame + * @sub_type: Assoc(=0) or Reassoc(=1) Requestframe + * @local_cap: local capabilities of SAP + * + * Checks for capab match + * + * Return: true of no error, false otherwise + */ +static bool lim_chk_capab(tpAniSirGlobal mac_ctx, tpSirMacMgmtHdr hdr, + tpPESession session, tpSirAssocReq assoc_req, + uint8_t sub_type, tSirMacCapabilityInfo *local_cap) +{ + uint16_t temp; + + if (cfg_get_capability_info(mac_ctx, &temp, session) != eSIR_SUCCESS) { + lim_log(mac_ctx, LOGP, FL("could not retrieve Capabilities")); + return false; + } + + lim_copy_u16((uint8_t *) local_cap, temp); + + if (lim_compare_capabilities(mac_ctx, assoc_req, + local_cap, session) == false) { + lim_log(mac_ctx, LOGW, + FL("Rcvd %s Req with unsupported capab from" + MAC_ADDRESS_STR), + (LIM_ASSOC == sub_type) ? "Assoc" : "ReAssoc", + MAC_ADDR_ARRAY(hdr->sa)); + /* + * Capabilities of requesting STA does not match with + * local capabilities. Respond with 'unsupported capabilities' + * status code. + */ + lim_send_assoc_rsp_mgmt_frame(mac_ctx, + eSIR_MAC_CAPABILITIES_NOT_SUPPORTED_STATUS, + 1, hdr->sa, sub_type, 0, session); + return false; + } + return true; +} + +/** + * lim_chk_ssid() - checks for SSID match + * @mac_ctx: pointer to Global MAC structure + * @hdr: pointer to the MAC head + * @session: pointer to pe session entry + * @assoc_req: pointer to ASSOC/REASSOC Request frame + * @sub_type: Assoc(=0) or Reassoc(=1) Requestframe + * + * Checks for SSID match + * + * Return: true of no error, false otherwise + */ +static bool lim_chk_ssid(tpAniSirGlobal mac_ctx, tpSirMacMgmtHdr hdr, + tpPESession session, tpSirAssocReq assoc_req, + uint8_t sub_type) +{ + if (lim_cmp_ssid(&assoc_req->ssId, session) != true) + return true; + + lim_log(mac_ctx, LOGE, + FL("%s Req with ssid wrong(Rcvd: %.*s self: %.*s) from " + MAC_ADDRESS_STR), + (LIM_ASSOC == sub_type) ? "Assoc" : "ReAssoc", + assoc_req->ssId.length, assoc_req->ssId.ssId, + session->ssId.length, session->ssId.ssId, + MAC_ADDR_ARRAY(hdr->sa)); + + /* + * Received Re/Association Request with either Broadcast SSID OR with + * SSID that does not match with local one. Respond with unspecified + * status code. + */ + lim_send_assoc_rsp_mgmt_frame(mac_ctx, eSIR_MAC_UNSPEC_FAILURE_STATUS, + 1, hdr->sa, sub_type, 0, session); + return false; +} + +/** + * lim_chk_rates() - checks for supported rates + * @mac_ctx: pointer to Global MAC structure + * @hdr: pointer to the MAC head + * @session: pointer to pe session entry + * @assoc_req: pointer to ASSOC/REASSOC Request frame + * @sub_type: Assoc(=0) or Reassoc(=1) Requestframe + * + * Checks for supported rates + * + * Return: true of no error, false otherwise + */ +static bool lim_chk_rates(tpAniSirGlobal mac_ctx, tpSirMacMgmtHdr hdr, + tpPESession session, tpSirAssocReq assoc_req, + uint8_t sub_type) +{ + uint8_t i = 0, j = 0; + tSirMacRateSet basic_rates; + /* + * Verify if the requested rates are available in supported rate + * set or Extended rate set. Some APs are adding basic rates in + * Extended rateset IE + */ + basic_rates.numRates = 0; + + for (i = 0; i < assoc_req->supportedRates.numRates + && (i < SIR_MAC_RATESET_EID_MAX); i++) { + basic_rates.rate[i] = assoc_req->supportedRates.rate[i]; + basic_rates.numRates++; + } + + for (j = 0; (j < assoc_req->extendedRates.numRates) + && (i < SIR_MAC_RATESET_EID_MAX); i++, j++) { + basic_rates.rate[i] = assoc_req->extendedRates.rate[j]; + basic_rates.numRates++; + } + + if (lim_check_rx_basic_rates(mac_ctx, basic_rates, session) == true) + return true; + + lim_log(mac_ctx, LOGW, + FL("Assoc Req rejected: unsupported rates, soruce addr: %s" + MAC_ADDRESS_STR), + (LIM_ASSOC == sub_type) ? "Assoc" : "ReAssoc", + MAC_ADDR_ARRAY(hdr->sa)); + /* + * Requesting STA does not support ALL BSS basic rates. Respond with + * 'basic rates not supported' status code. + */ + lim_send_assoc_rsp_mgmt_frame(mac_ctx, + eSIR_MAC_BASIC_RATES_NOT_SUPPORTED_STATUS, 1, + hdr->sa, sub_type, 0, session); + return false; +} + +/** + * lim_chk_11g_only() - checks for non 11g STA + * @mac_ctx: pointer to Global MAC structure + * @hdr: pointer to the MAC head + * @session: pointer to pe session entry + * @assoc_req: pointer to ASSOC/REASSOC Request frame + * @sub_type: Assoc(=0) or Reassoc(=1) Requestframe + * + * Checks for non 11g STA + * + * Return: true of no error, false otherwise + */ +static bool lim_chk_11g_only(tpAniSirGlobal mac_ctx, tpSirMacMgmtHdr hdr, + tpPESession session, tpSirAssocReq assoc_req, + uint8_t sub_type) +{ + if (LIM_IS_AP_ROLE(session) && + (session->dot11mode == WNI_CFG_DOT11_MODE_11G_ONLY) && + (assoc_req->HTCaps.present)) { + lim_log(mac_ctx, LOGE, + FL("SOFTAP was in 11G only mode, rejecting legacy STA: " + MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(hdr->sa)); + lim_send_assoc_rsp_mgmt_frame(mac_ctx, + eSIR_MAC_CAPABILITIES_NOT_SUPPORTED_STATUS, + 1, hdr->sa, sub_type, 0, session); + return false; + } + return true; +} + +/** + * lim_chk_11n_only() - checks for non 11n STA + * @mac_ctx: pointer to Global MAC structure + * @hdr: pointer to the MAC head + * @session: pointer to pe session entry + * @assoc_req: pointer to ASSOC/REASSOC Request frame + * @sub_type: Assoc(=0) or Reassoc(=1) Requestframe + * + * Checks for non 11n STA + * + * Return: true of no error, false otherwise + */ +static bool lim_chk_11n_only(tpAniSirGlobal mac_ctx, tpSirMacMgmtHdr hdr, + tpPESession session, tpSirAssocReq assoc_req, + uint8_t sub_type) +{ + if (LIM_IS_AP_ROLE(session) && + (session->dot11mode == WNI_CFG_DOT11_MODE_11N_ONLY) && + (!assoc_req->HTCaps.present)) { + lim_log(mac_ctx, LOGE, + FL("SOFTAP was in 11N only mode, rejecting legacy STA: " + MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(hdr->sa)); + lim_send_assoc_rsp_mgmt_frame(mac_ctx, + eSIR_MAC_CAPABILITIES_NOT_SUPPORTED_STATUS, + 1, hdr->sa, sub_type, 0, session); + return false; + } + return true; +} + +/** + * lim_chk_11ac_only() - checks for non 11ac STA + * @mac_ctx: pointer to Global MAC structure + * @hdr: pointer to the MAC head + * @session: pointer to pe session entry + * @assoc_req: pointer to ASSOC/REASSOC Request frame + * @sub_type: Assoc(=0) or Reassoc(=1) Requestframe + * + * Checks for non 11ac STA + * + * Return: true of no error, false otherwise + */ +static bool lim_chk_11ac_only(tpAniSirGlobal mac_ctx, tpSirMacMgmtHdr hdr, + tpPESession session, tpSirAssocReq assoc_req, + uint8_t sub_type) +{ + tDot11fIEVHTCaps *vht_caps; + + if (assoc_req->VHTCaps.present) + vht_caps = &assoc_req->VHTCaps; + else if (assoc_req->vendor_vht_ie.VHTCaps.present && + session->vendor_vht_sap) + vht_caps = &assoc_req->vendor_vht_ie.VHTCaps; + else + vht_caps = NULL; + + if (LIM_IS_AP_ROLE(session) && + (session->dot11mode == WNI_CFG_DOT11_MODE_11AC_ONLY) && + ((vht_caps == NULL) || ((vht_caps != NULL) && (!vht_caps->present)))) { + lim_send_assoc_rsp_mgmt_frame(mac_ctx, + eSIR_MAC_CAPABILITIES_NOT_SUPPORTED_STATUS, + 1, hdr->sa, sub_type, 0, session); + lim_log(mac_ctx, LOGE, + FL("SOFTAP was in 11AC only mode, reject")); + return false; + } + return true; +} + +/** + * lim_process_for_spectrum_mgmt() - process assoc req for spectrum mgmt + * @mac_ctx: pointer to Global MAC structure + * @hdr: pointer to the MAC head + * @session: pointer to pe session entry + * @assoc_req: pointer to ASSOC/REASSOC Request frame + * @sub_type: Assoc(=0) or Reassoc(=1) Requestframe + * @local_cap: local capabilities of SAP + * + * Checks for SSID match + * + * process assoc req for spectrum mgmt + */ +static void +lim_process_for_spectrum_mgmt(tpAniSirGlobal mac_ctx, tpSirMacMgmtHdr hdr, + tpPESession session, tpSirAssocReq assoc_req, + uint8_t sub_type, tSirMacCapabilityInfo local_cap) +{ + if (local_cap.spectrumMgt) { + tSirRetStatus status = eSIR_SUCCESS; + /* + * If station is 11h capable, then it SHOULD send all mandatory + * IEs in assoc request frame. Let us verify that + */ + if (assoc_req->capabilityInfo.spectrumMgt) { + if (!((assoc_req->powerCapabilityPresent) + && (assoc_req->supportedChannelsPresent))) { + /* + * One or more required information elements are + * missing, log the peers error + */ + if (!assoc_req->powerCapabilityPresent) { + lim_log(mac_ctx, LOG1, + FL("LIM Info: Missing Power capability IE in %s Req from " + MAC_ADDRESS_STR), + (LIM_ASSOC == sub_type) ? + "Assoc" : "ReAssoc", + MAC_ADDR_ARRAY(hdr->sa)); + } + if (!assoc_req->supportedChannelsPresent) { + lim_log(mac_ctx, LOGW, + FL("LIM Info: Missing Supported channel IE in %s Req from " + MAC_ADDRESS_STR), + (LIM_ASSOC == sub_type) ? + "Assoc" : "ReAssoc", + MAC_ADDR_ARRAY(hdr->sa)); + } + } else { + /* Assoc request has mandatory fields */ + status = + lim_is_dot11h_power_capabilities_in_range( + mac_ctx, assoc_req, session); + if (eSIR_SUCCESS != status) { + lim_log(mac_ctx, LOGW, + FL("LIM Info: MinTxPower(STA) > MaxTxPower(AP) in %s Req from " + MAC_ADDRESS_STR), + (LIM_ASSOC == sub_type) ? + "Assoc" : "ReAssoc", + MAC_ADDR_ARRAY(hdr->sa)); + } + status = lim_is_dot11h_supported_channels_valid( + mac_ctx, assoc_req); + if (eSIR_SUCCESS != status) { + lim_log(mac_ctx, LOGW, + FL("LIM Info: wrong supported channels (STA) in %s Req from " + MAC_ADDRESS_STR), + (LIM_ASSOC == sub_type) ? + "Assoc" : "ReAssoc", + MAC_ADDR_ARRAY(hdr->sa)); + } + /* IEs are valid, use them if needed */ + } + } /* if(assoc.capabilityInfo.spectrumMgt) */ + else { + /* + * As per the capabiities, the spectrum management is + * not enabled on the station. The AP may allow the + * associations to happen even if spectrum management + * is not allowed, if the transmit power of station is + * below the regulatory maximum + */ + + /* + * TODO: presently, this is not handled. In the current + * implemetation, the AP would allow the station to + * associate even if it doesn't support spectrum + * management. + */ + } + } /* end of spectrum management related processing */ +} + +/** + * lim_chk_mcs() - checks for supported MCS + * @mac_ctx: pointer to Global MAC structure + * @hdr: pointer to the MAC head + * @session: pointer to pe session entry + * @assoc_req: pointer to ASSOC/REASSOC Request frame + * @sub_type: Assoc(=0) or Reassoc(=1) Requestframe + * + * Checks for supported MCS + * + * Return: true of no error, false otherwise + */ +static bool lim_chk_mcs(tpAniSirGlobal mac_ctx, tpSirMacMgmtHdr hdr, + tpPESession session, tpSirAssocReq assoc_req, + uint8_t sub_type) +{ + if ((assoc_req->HTCaps.present) && (lim_check_mcs_set(mac_ctx, + assoc_req->HTCaps.supportedMCSSet) == false)) { + lim_log(mac_ctx, LOGW, + FL("rcvd %s req with unsupported MCS Rate Set from " + MAC_ADDRESS_STR), + (LIM_ASSOC == sub_type) ? "Assoc" : "ReAssoc", + MAC_ADDR_ARRAY(hdr->sa)); + /* + * Requesting STA does not support ALL BSS MCS basic Rate set + * rates. Spec does not define any status code for this + * scenario. + */ + lim_send_assoc_rsp_mgmt_frame(mac_ctx, + eSIR_MAC_OUTSIDE_SCOPE_OF_SPEC_STATUS, + 1, hdr->sa, sub_type, 0, session); + return false; + } + return true; +} + +/** + * lim_chk_is_11b_sta_supported() - checks if STA is 11b + * @mac_ctx: pointer to Global MAC structure + * @hdr: pointer to the MAC head + * @session: pointer to pe session entry + * @assoc_req: pointer to ASSOC/REASSOC Request frame + * @sub_type: Assoc(=0) or Reassoc(=1) Requestframe + * @phy_mode: phy mode + * + * Checks if STA is 11b + * + * Return: true of no error, false otherwise + */ +static bool lim_chk_is_11b_sta_supported(tpAniSirGlobal mac_ctx, + tpSirMacMgmtHdr hdr, + tpPESession session, + tpSirAssocReq assoc_req, + uint8_t sub_type, uint32_t phy_mode) +{ + uint32_t cfg_11g_only; + + if (phy_mode == WNI_CFG_PHY_MODE_11G) { + if (wlan_cfg_get_int(mac_ctx, WNI_CFG_11G_ONLY_POLICY, + &cfg_11g_only) != eSIR_SUCCESS) { + lim_log(mac_ctx, LOGP, + FL("couldn't get 11g-only flag")); + return false; + } + + if (!assoc_req->extendedRatesPresent && cfg_11g_only) { + /* + * Received Re/Association Request from 11b STA when 11g + * only policy option is set. Reject with unspecified + * status code. + */ + lim_send_assoc_rsp_mgmt_frame(mac_ctx, + eSIR_MAC_BASIC_RATES_NOT_SUPPORTED_STATUS, + 1, hdr->sa, sub_type, 0, session); + + lim_log(mac_ctx, LOGW, + FL("Rejecting Re/Assoc req from 11b STA: ")); + lim_print_mac_addr(mac_ctx, hdr->sa, LOGW); + +#ifdef WLAN_DEBUG + mac_ctx->lim.gLim11bStaAssocRejectCount++; +#endif + return false; + } + } + return true; +} + +/** + * lim_print_ht_cap() - prints HT caps + * @mac_ctx: pointer to Global MAC structure + * @session: pointer to pe session entry + * @assoc_req: pointer to ASSOC/REASSOC Request frame + * + * Prints HT caps + * + * Return: void + */ +static void lim_print_ht_cap(tpAniSirGlobal mac_ctx, tpPESession session, + tpSirAssocReq assoc_req) +{ + if (!session->htCapability) + return; + + /* There are; are they turned on in the STA? */ + if (assoc_req->HTCaps.present) { + /* The station *does* support 802.11n HT capability... */ + lim_log(mac_ctx, LOG1, + FL("AdvCodingCap:%d ChaWidthSet:%d PowerSave:%d greenField:%d shortGI20:%d shortGI40:%d txSTBC:%d rxSTBC:%d delayBA:%d maxAMSDUsize:%d DSSS/CCK:%d PSMP:%d stbcCntl:%d lsigTXProt:%d"), + assoc_req->HTCaps.advCodingCap, + assoc_req->HTCaps.supportedChannelWidthSet, + assoc_req->HTCaps.mimoPowerSave, + assoc_req->HTCaps.greenField, + assoc_req->HTCaps.shortGI20MHz, + assoc_req->HTCaps.shortGI40MHz, + assoc_req->HTCaps.txSTBC, + assoc_req->HTCaps.rxSTBC, + assoc_req->HTCaps.delayedBA, + assoc_req->HTCaps.maximalAMSDUsize, + assoc_req->HTCaps.dsssCckMode40MHz, + assoc_req->HTCaps.psmp, + assoc_req->HTCaps.stbcControlFrame, + assoc_req->HTCaps.lsigTXOPProtection); + /* + * Make sure the STA's caps are compatible with our own: + * 11.15.2 Support of DSSS/CCK in 40 MHz the AP shall refuse + * association requests from an HT STA that has the DSSS/CCK + * Mode in 40 MHz subfield set to 1; + */ + } +} + +/** + * lim_chk_n_process_wpa_rsn_ie() - wpa ie related checks + * @mac_ctx: pointer to Global MAC structure + * @hdr: pointer to the MAC head + * @session: pointer to pe session entry + * @assoc_req: pointer to ASSOC/REASSOC Request frame + * @sub_type: Assoc(=0) or Reassoc(=1) Requestframe + * @pmf_connection: flag indicating pmf connection + * + * wpa ie related checks + * + * Return: true of no error, false otherwise + */ +static bool lim_chk_n_process_wpa_rsn_ie(tpAniSirGlobal mac_ctx, + tpSirMacMgmtHdr hdr, + tpPESession session, + tpSirAssocReq assoc_req, + uint8_t sub_type, bool *pmf_connection) +{ + uint8_t *wps_ie = NULL; + tDot11fIEWPA dot11f_ie_wpa; + tDot11fIERSN dot11f_ie_rsn; + tSirRetStatus status = eSIR_SUCCESS; + /* + * Clear the buffers so that frame parser knows that there isn't a + * previously decoded IE in these buffers + */ + qdf_mem_set((uint8_t *) &dot11f_ie_rsn, sizeof(dot11f_ie_rsn), 0); + qdf_mem_set((uint8_t *) &dot11f_ie_wpa, sizeof(dot11f_ie_wpa), 0); + + /* if additional IE is present, check if it has WscIE */ + if (assoc_req->addIEPresent && assoc_req->addIE.length) + wps_ie = limGetWscIEPtr(mac_ctx, assoc_req->addIE.addIEdata, + assoc_req->addIE.length); + else + lim_log(mac_ctx, LOG1, + FL("Assoc req addIEPresent = %d addIE length = %d"), + assoc_req->addIEPresent, assoc_req->addIE.length); + + /* when wps_ie is present, RSN/WPA IE is ignored */ + if (wps_ie == NULL) { + /* check whether as RSN IE is present */ + if (LIM_IS_AP_ROLE(session) && + session->pLimStartBssReq->privacy && + session->pLimStartBssReq->rsnIE.length) { + lim_log(mac_ctx, LOGE, + FL("RSN enabled auth, Re/Assoc req from STA: " + MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(hdr->sa)); + if (assoc_req->rsnPresent) { + if (assoc_req->rsn.length) { + /* Unpack the RSN IE */ + if (dot11f_unpack_ie_rsn(mac_ctx, + &assoc_req->rsn.info[0], + assoc_req->rsn.length, + &dot11f_ie_rsn) != + DOT11F_PARSE_SUCCESS) { + pe_err("Invalid RSN ie"); + return false; + } + + /* Check RSN version is supported */ + if (SIR_MAC_OUI_VERSION_1 == + dot11f_ie_rsn.version) { + /* + * check the groupwise and + * pairwise cipher suites + */ + status = + lim_check_rx_rsn_ie_match( + mac_ctx, dot11f_ie_rsn, + session, + assoc_req->HTCaps.present, + pmf_connection); + if (eSIR_SUCCESS != status) { + lim_log(mac_ctx, LOGW, + FL("Re/Assoc rejected from: " MAC_ADDRESS_STR), + MAC_ADDR_ARRAY( + hdr->sa)); + + /* + * some IE is not + * properly sent + * received Association + * req frame with RSN IE + * but length is 0 + */ + lim_send_assoc_rsp_mgmt_frame( + mac_ctx, + status, 1, + hdr->sa, + sub_type, 0, + session); + return false; + } + } else { + lim_log(mac_ctx, LOGW, + FL("Re/Assoc rejected from: " MAC_ADDRESS_STR), + MAC_ADDR_ARRAY( + hdr->sa)); + /* + * rcvd Assoc req frame with RSN + * IE version wrong + */ + lim_send_assoc_rsp_mgmt_frame( + mac_ctx, + eSIR_MAC_UNSUPPORTED_RSN_IE_VERSION_STATUS, + 1, hdr->sa, sub_type, 0, + session); + return false; + } + } else { + lim_log(mac_ctx, LOGW, + FL("Re/Assoc rejected from: " + MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(hdr->sa)); + /* + * rcvd Assoc req frame with RSN IE but + * length is 0 + */ + lim_send_assoc_rsp_mgmt_frame(mac_ctx, + eSIR_MAC_INVALID_INFORMATION_ELEMENT_STATUS, + 1, hdr->sa, sub_type, 0, + session); + return false; + } + } /* end - if(assoc_req->rsnPresent) */ + if ((!assoc_req->rsnPresent) && assoc_req->wpaPresent) { + /* Unpack the WPA IE */ + if (assoc_req->wpa.length) { + /* OUI is not taken care */ + if (dot11f_unpack_ie_wpa(mac_ctx, + &assoc_req->wpa.info[4], + assoc_req->wpa.length, + &dot11f_ie_wpa) != + DOT11F_PARSE_SUCCESS) { + pe_err("Invalid WPA IE"); + return false; + } + /* + * check the groupwise and pairwise + * cipher suites + */ + status = lim_check_rx_wpa_ie_match( + mac_ctx, dot11f_ie_wpa, + session, + assoc_req->HTCaps.present); + if (eSIR_SUCCESS != status) { + lim_log(mac_ctx, LOGW, + FL("Re/Assoc rejected from: " + MAC_ADDRESS_STR), + MAC_ADDR_ARRAY( + hdr->sa)); + /* + * rcvd Assoc req frame with WPA + * IE but mismatch + */ + lim_send_assoc_rsp_mgmt_frame( + mac_ctx, status, 1, + hdr->sa, sub_type, 0, + session); + return false; + } + } else { + lim_log(mac_ctx, LOGW, + FL("Re/Assoc rejected from: " + MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(hdr->sa)); + /* + * rcvd Assoc req frame with invalid WPA + * IE + */ + lim_send_assoc_rsp_mgmt_frame(mac_ctx, + eSIR_MAC_INVALID_INFORMATION_ELEMENT_STATUS, + 1, hdr->sa, sub_type, 0, + session); + return false; + } /* end - if(assoc_req->wpa.length) */ + } /* end - if(assoc_req->wpaPresent) */ + } + /* + * end of if(session->pLimStartBssReq->privacy + * && session->pLimStartBssReq->rsnIE->length) + */ + } /* end of if( ! assoc_req->wscInfo.present ) */ + else { + lim_log(mac_ctx, LOG1, FL("Assoc req WSE IE is present")); + } + return true; +} + +/** + * lim_process_assoc_req_no_sta_ctx() - process assoc req for no sta ctx present + * @mac_ctx: pointer to Global MAC structure + * @hdr: pointer to the MAC head + * @session: pointer to pe session entry + * @assoc_req: pointer to ASSOC/REASSOC Request frame + * @sub_type: Assoc(=0) or Reassoc(=1) Requestframe + * @sta_pre_auth_ctx: sta pre auth context + * @sta_ds: station dph entry + * @auth_type: indicates security type + * + * Process assoc req for no sta ctx present + * + * Return: true of no error, false otherwise + */ +static bool lim_process_assoc_req_no_sta_ctx(tpAniSirGlobal mac_ctx, + tpSirMacMgmtHdr hdr, tpPESession session, + tpSirAssocReq assoc_req, uint8_t sub_type, + struct tLimPreAuthNode *sta_pre_auth_ctx, + tpDphHashNode sta_ds, tAniAuthType *auth_type) +{ + /* Requesting STA is not currently associated */ + if (pe_get_current_stas_count(mac_ctx) == + mac_ctx->lim.gLimAssocStaLimit) { + /* + * Maximum number of STAs that AP can handle reached. + * Send Association response to peer MAC entity + */ + lim_log(mac_ctx, LOGE, FL("Max Sta count reached : %d"), + mac_ctx->lim.maxStation); + lim_reject_association(mac_ctx, hdr->sa, sub_type, false, + (tAniAuthType) 0, 0, false, + (tSirResultCodes) eSIR_MAC_UNSPEC_FAILURE_STATUS, + session); + return false; + } + /* Check if STA is pre-authenticated. */ + if ((sta_pre_auth_ctx == NULL) || (sta_pre_auth_ctx && + (sta_pre_auth_ctx->mlmState != eLIM_MLM_AUTHENTICATED_STATE))) { + /* + * STA is not pre-authenticated yet requesting Re/Association + * before Authentication. OR STA is in the process of getting + * authenticated and sent Re/Association request. Send + * Deauthentication frame with 'prior authentication required' + * reason code. + */ + lim_send_deauth_mgmt_frame(mac_ctx, + eSIR_MAC_STA_NOT_PRE_AUTHENTICATED_REASON, + hdr->sa, session, false); + + lim_log(mac_ctx, LOGW, + FL("rcvd %s req, sessionid: %d, without pre-auth ctx" + MAC_ADDRESS_STR), + (LIM_ASSOC == sub_type) ? "Assoc" : "ReAssoc", + session->peSessionId, MAC_ADDR_ARRAY(hdr->sa)); + return false; + } + /* Delete 'pre-auth' context of STA */ + *auth_type = sta_pre_auth_ctx->authType; + lim_delete_pre_auth_node(mac_ctx, hdr->sa); + /* All is well. Assign AID (after else part) */ + return true; +} + +/** + * lim_process_assoc_req_sta_ctx() - process assoc req for sta context present + * @mac_ctx: pointer to Global MAC structure + * @hdr: pointer to the MAC head + * @session: pointer to pe session entry + * @assoc_req: pointer to ASSOC/REASSOC Request frame + * @sub_type: Assoc(=0) or Reassoc(=1) Requestframe + * @sta_pre_auth_ctx: sta pre auth context + * @sta_ds: station dph entry + * @peer_idx: peer index + * @auth_type: indicates security type + * @update_ctx: indicates if STA context already exist + * + * Process assoc req for sta context present + * + * Return: true of no error, false otherwise + */ +static bool lim_process_assoc_req_sta_ctx(tpAniSirGlobal mac_ctx, + tpSirMacMgmtHdr hdr, tpPESession session, + tpSirAssocReq assoc_req, uint8_t sub_type, + struct tLimPreAuthNode *sta_pre_auth_ctx, + tpDphHashNode sta_ds, uint16_t peer_idx, + tAniAuthType *auth_type, uint8_t *update_ctx) +{ + /* STA context does exist for this STA */ + if (sta_ds->mlmStaContext.mlmState != eLIM_MLM_LINK_ESTABLISHED_STATE) { + /* + * Requesting STA is in some 'transient' state? Ignore the + * Re/Assoc Req frame by incrementing debug counter & logging + * error. + */ + if (sub_type == LIM_ASSOC) { +#ifdef WLAN_DEBUG + mac_ctx->lim.gLimNumAssocReqDropInvldState++; +#endif + lim_log(mac_ctx, LOG1, + FL("received Assoc req in state %X from "), + sta_ds->mlmStaContext.mlmState); + } else { +#ifdef WLAN_DEBUG + mac_ctx->lim.gLimNumReassocReqDropInvldState++; +#endif + lim_log(mac_ctx, LOG1, + FL("received ReAssoc req in state %X from "), + sta_ds->mlmStaContext.mlmState); + } + lim_print_mac_addr(mac_ctx, hdr->sa, LOG1); + lim_print_mlm_state(mac_ctx, LOG1, + (tLimMlmStates) sta_ds->mlmStaContext.mlmState); + return false; + } + + /* STA sent assoc req frame while already in 'associated' state */ + +#ifdef WLAN_FEATURE_11W + lim_log(mac_ctx, LOG1, + FL("Re/Assoc request from station that is already associated")); + lim_log(mac_ctx, LOG1, FL("PMF enabled %d, SA Query state %d"), + sta_ds->rmfEnabled, sta_ds->pmfSaQueryState); + if (sta_ds->rmfEnabled) { + switch (sta_ds->pmfSaQueryState) { + /* + * start SA Query procedure, respond to Association Request with + * try again later + */ + case DPH_SA_QUERY_NOT_IN_PROGRESS: + /* + * We should reset the retry counter before we start + * the SA query procedure, otherwise in next set of SA + * query procedure we will end up using the stale value. + */ + sta_ds->pmfSaQueryRetryCount = 0; + lim_send_assoc_rsp_mgmt_frame(mac_ctx, + eSIR_MAC_TRY_AGAIN_LATER, 1, hdr->sa, + sub_type, sta_ds, session); + lim_send_sa_query_request_frame(mac_ctx, + (uint8_t *) &(sta_ds->pmfSaQueryCurrentTransId), + hdr->sa, session); + sta_ds->pmfSaQueryStartTransId = + sta_ds->pmfSaQueryCurrentTransId; + sta_ds->pmfSaQueryCurrentTransId++; + + /* start timer for SA Query retry */ + if (tx_timer_activate(&sta_ds->pmfSaQueryTimer) + != TX_SUCCESS) { + lim_log(mac_ctx, LOGE, + FL("PMF SA Query timer start failed!")); + return false; + } + sta_ds->pmfSaQueryState = DPH_SA_QUERY_IN_PROGRESS; + return false; + /* + * SA Query procedure still going, respond to Association + * Request with try again later + */ + case DPH_SA_QUERY_IN_PROGRESS: + lim_send_assoc_rsp_mgmt_frame(mac_ctx, + eSIR_MAC_TRY_AGAIN_LATER, 1, + hdr->sa, sub_type, 0, session); + return false; + + /* + * SA Query procedure timed out, accept Association + * Request normally + */ + case DPH_SA_QUERY_TIMED_OUT: + sta_ds->pmfSaQueryState = DPH_SA_QUERY_NOT_IN_PROGRESS; + break; + } + } +#endif + + /* no change in the capability so drop the frame */ + if ((sub_type == LIM_ASSOC) && + (!qdf_mem_cmp(&sta_ds->mlmStaContext.capabilityInfo, + &assoc_req->capabilityInfo, + sizeof(tSirMacCapabilityInfo)))) { + lim_log(mac_ctx, LOGE, + FL(" Received Assoc req in state %X STAid=%d"), + sta_ds->mlmStaContext.mlmState, peer_idx); + return false; + } else { + /* + * STA sent Re/association Request frame while already in + * 'associated' state. Update STA capabilities and send + * Association response frame with same AID + */ + lim_log(mac_ctx, LOG1, + FL("Rcvd Assoc req from STA already connected")); + sta_ds->mlmStaContext.capabilityInfo = + assoc_req->capabilityInfo; + if (sta_pre_auth_ctx && (sta_pre_auth_ctx->mlmState == + eLIM_MLM_AUTHENTICATED_STATE)) { + /* STA has triggered pre-auth again */ + *auth_type = sta_pre_auth_ctx->authType; + lim_delete_pre_auth_node(mac_ctx, hdr->sa); + } else { + *auth_type = sta_ds->mlmStaContext.authType; + } + + *update_ctx = true; + if (dph_init_sta_state(mac_ctx, hdr->sa, peer_idx, true, + &session->dph.dphHashTable) == NULL) { + lim_log(mac_ctx, LOGE, + FL("could not Init STAid=%d"), peer_idx); + return false; + } + } + return true; +} + +/** + * lim_chk_wmm() - wmm related checks + * @mac_ctx: pointer to Global MAC structure + * @hdr: pointer to the MAC head + * @session: pointer to pe session entry + * @assoc_req: pointer to ASSOC/REASSOC Request frame + * @sub_type: Assoc(=0) or Reassoc(=1) Requestframe + * @qos_mode: qos mode + * + * wmm related checks + * + * Return: true of no error, false otherwise + */ +static bool lim_chk_wmm(tpAniSirGlobal mac_ctx, tpSirMacMgmtHdr hdr, + tpPESession session, tpSirAssocReq assoc_req, + uint8_t sub_type, tHalBitVal qos_mode) +{ + tHalBitVal wme_mode; + limGetWmeMode(session, &wme_mode); + if ((qos_mode == eHAL_SET) || (wme_mode == eHAL_SET)) { + /* + * for a qsta, check if the requested Traffic spec is admissible + * for a non-qsta check if the sta can be admitted + */ + if (assoc_req->addtsPresent) { + uint8_t tspecIdx = 0; + if (lim_admit_control_add_ts(mac_ctx, hdr->sa, + &(assoc_req->addtsReq), + &(assoc_req->qosCapability), + 0, false, NULL, &tspecIdx, session) != + eSIR_SUCCESS) { + lim_log(mac_ctx, LOGW, + FL("AdmitControl: TSPEC rejected")); + lim_send_assoc_rsp_mgmt_frame(mac_ctx, + eSIR_MAC_QAP_NO_BANDWIDTH_REASON, + 1, hdr->sa, sub_type, 0, session); +#ifdef WLAN_DEBUG + mac_ctx->lim.gLimNumAssocReqDropACRejectTS++; +#endif + return false; + } + } else if (lim_admit_control_add_sta(mac_ctx, hdr->sa, false) + != eSIR_SUCCESS) { + lim_log(mac_ctx, LOGW, + FL("AdmitControl: Sta rejected")); + lim_send_assoc_rsp_mgmt_frame(mac_ctx, + eSIR_MAC_QAP_NO_BANDWIDTH_REASON, 1, + hdr->sa, sub_type, 0, session); +#ifdef WLAN_DEBUG + mac_ctx->lim.gLimNumAssocReqDropACRejectSta++; +#endif + return false; + } + /* else all ok */ + lim_log(mac_ctx, LOG1, FL("AdmitControl: Sta OK!")); + } + return true; +} + +/** + * lim_update_sta_ds() - updates ds dph entry + * @mac_ctx: pointer to Global MAC structure + * @hdr: pointer to the MAC head + * @session: pointer to pe session entry + * @assoc_req: pointer to ASSOC/REASSOC Request frame pointer + * @sub_type: Assoc(=0) or Reassoc(=1) Requestframe + * @sta_ds: station dph entry + * @auth_type: indicates security type + * @assoc_req_copied: boolean to indicate if assoc req was copied to tmp above + * @peer_idx: peer index + * @qos_mode: qos mode + * @pmf_connection: flag indicating pmf connection + * + * Updates ds dph entry + * + * Return: true of no error, false otherwise + */ +static bool lim_update_sta_ds(tpAniSirGlobal mac_ctx, tpSirMacMgmtHdr hdr, + tpPESession session, tpSirAssocReq assoc_req, + uint8_t sub_type, tpDphHashNode sta_ds, + tAniAuthType auth_type, + bool *assoc_req_copied, uint16_t peer_idx, + tHalBitVal qos_mode, bool pmf_connection) +{ + tHalBitVal wme_mode, wsm_mode; + uint8_t *ht_cap_ie = NULL; +#ifdef WLAN_FEATURE_11W + tPmfSaQueryTimerId timer_id; + uint32_t retry_interval; +#endif + tDot11fIEVHTCaps *vht_caps; + tpSirAssocReq tmp_assoc_req; + + if (assoc_req->VHTCaps.present) + vht_caps = &assoc_req->VHTCaps; + else if (assoc_req->vendor_vht_ie.VHTCaps.present && + session->vendor_vht_sap) + vht_caps = &assoc_req->vendor_vht_ie.VHTCaps; + else + vht_caps = NULL; + + /* + * check here if the parsedAssocReq already pointing to the assoc_req + * and free it before assigning this new assoc_req + */ + if (session->parsedAssocReq != NULL) { + tmp_assoc_req = session->parsedAssocReq[sta_ds->assocId]; + if (tmp_assoc_req != NULL) { + if (tmp_assoc_req->assocReqFrame) { + qdf_mem_free(tmp_assoc_req->assocReqFrame); + tmp_assoc_req->assocReqFrame = NULL; + tmp_assoc_req->assocReqFrameLength = 0; + } + qdf_mem_free(tmp_assoc_req); + tmp_assoc_req = NULL; + } + + session->parsedAssocReq[sta_ds->assocId] = assoc_req; + *assoc_req_copied = true; + } + + sta_ds->mlmStaContext.htCapability = assoc_req->HTCaps.present; + if ((vht_caps != NULL) && vht_caps->present) + sta_ds->mlmStaContext.vhtCapability = vht_caps->present; + else + sta_ds->mlmStaContext.vhtCapability = false; + sta_ds->qos.addtsPresent = + (assoc_req->addtsPresent == 0) ? false : true; + sta_ds->qos.addts = assoc_req->addtsReq; + sta_ds->qos.capability = assoc_req->qosCapability; + sta_ds->versionPresent = 0; + /* + * short slot and short preamble should be updated before doing + * limaddsta + */ + sta_ds->shortPreambleEnabled = + (uint8_t) assoc_req->capabilityInfo.shortPreamble; + sta_ds->shortSlotTimeEnabled = + (uint8_t) assoc_req->capabilityInfo.shortSlotTime; + + sta_ds->valid = 0; + sta_ds->mlmStaContext.authType = auth_type; + sta_ds->staType = STA_ENTRY_PEER; + + /* + * TODO: If listen interval is more than certain limit, reject the + * association. Need to check customer requirements and then implement. + */ + sta_ds->mlmStaContext.listenInterval = assoc_req->listenInterval; + sta_ds->mlmStaContext.capabilityInfo = assoc_req->capabilityInfo; + + /* + * The following count will be used to knock-off the station if it + * doesn't come back to receive the buffered data. The AP will wait + * for numTimSent number of beacons after sending TIM information for + * the station, before assuming that the station is no more associated + * and disassociates it + */ + + /* timWaitCount used by PMM for monitoring the STA's in PS for LINK */ + sta_ds->timWaitCount = + (uint8_t) GET_TIM_WAIT_COUNT(assoc_req->listenInterval); + + /* Init the Current successful MPDU's tranfered to this STA count = 0 */ + sta_ds->curTxMpduCnt = 0; + + if (IS_DOT11_MODE_HT(session->dot11mode) && + assoc_req->HTCaps.present && assoc_req->wmeInfoPresent) { + sta_ds->htGreenfield = (uint8_t) assoc_req->HTCaps.greenField; + sta_ds->htAMpduDensity = assoc_req->HTCaps.mpduDensity; + sta_ds->htDsssCckRate40MHzSupport = + (uint8_t) assoc_req->HTCaps.dsssCckMode40MHz; + sta_ds->htLsigTXOPProtection = + (uint8_t) assoc_req->HTCaps.lsigTXOPProtection; + sta_ds->htMaxAmsduLength = + (uint8_t) assoc_req->HTCaps.maximalAMSDUsize; + sta_ds->htMaxRxAMpduFactor = assoc_req->HTCaps.maxRxAMPDUFactor; + sta_ds->htMIMOPSState = assoc_req->HTCaps.mimoPowerSave; + + /* assoc_req will be copied to session->parsedAssocReq later */ + ht_cap_ie = ((uint8_t *) &assoc_req->HTCaps) + 1; + + if (session->htConfig.ht_sgi20) { + sta_ds->htShortGI20Mhz = + (uint8_t)assoc_req->HTCaps.shortGI20MHz; + } else { + /* Unset htShortGI20Mhz in ht_caps*/ + *ht_cap_ie &= ~(1 << SIR_MAC_HT_CAP_SHORTGI20MHZ_S); + sta_ds->htShortGI20Mhz = 0; + } + + if (session->htConfig.ht_sgi40) { + sta_ds->htShortGI40Mhz = + (uint8_t)assoc_req->HTCaps.shortGI40MHz; + } else { + /* Unset htShortGI40Mhz in ht_caps */ + *ht_cap_ie &= ~(1 << SIR_MAC_HT_CAP_SHORTGI40MHZ_S); + sta_ds->htShortGI40Mhz = 0; + } + + sta_ds->htSupportedChannelWidthSet = + (uint8_t) assoc_req->HTCaps.supportedChannelWidthSet; + /* + * peer just follows AP; so when we are softAP/GO, + * we just store our session entry's secondary channel offset + * here in peer INFRA STA. However, if peer's 40MHz channel + * width support is disabled then secondary channel will be zero + */ + sta_ds->htSecondaryChannelOffset = + (sta_ds->htSupportedChannelWidthSet) ? + session->htSecondaryChannelOffset : 0; + if (assoc_req->operMode.present) { + sta_ds->vhtSupportedChannelWidthSet = + (uint8_t) ((assoc_req->operMode.chanWidth == + eHT_CHANNEL_WIDTH_80MHZ) ? + WNI_CFG_VHT_CHANNEL_WIDTH_80MHZ : + WNI_CFG_VHT_CHANNEL_WIDTH_20_40MHZ); + sta_ds->htSupportedChannelWidthSet = + (uint8_t) (assoc_req->operMode.chanWidth ? + eHT_CHANNEL_WIDTH_40MHZ : + eHT_CHANNEL_WIDTH_20MHZ); + } else if ((vht_caps != NULL) && vht_caps->present) { + /* + * Check if STA has enabled it's channel bonding mode. + * If channel bonding mode is enabled, we decide based + * on SAP's current configuration. else, we set it to + * VHT20. */ + sta_ds->vhtSupportedChannelWidthSet = + (uint8_t) ((sta_ds->htSupportedChannelWidthSet + == eHT_CHANNEL_WIDTH_20MHZ) ? + WNI_CFG_VHT_CHANNEL_WIDTH_20_40MHZ : + session->ch_width - 1); + sta_ds->htMaxRxAMpduFactor = + vht_caps->maxAMPDULenExp; + } + /* Lesser among the AP and STA bandwidth of operation. */ + sta_ds->htSupportedChannelWidthSet = + (sta_ds->htSupportedChannelWidthSet < + session->htSupportedChannelWidthSet) ? + sta_ds->htSupportedChannelWidthSet : + session->htSupportedChannelWidthSet; + sta_ds->baPolicyFlag = 0xFF; + sta_ds->htLdpcCapable = + (uint8_t) assoc_req->HTCaps.advCodingCap; + } + + if ((vht_caps != NULL) && vht_caps->present && + assoc_req->wmeInfoPresent) { + sta_ds->vhtLdpcCapable = + (uint8_t) vht_caps->ldpcCodingCap; + } + + if (!assoc_req->wmeInfoPresent) { + sta_ds->mlmStaContext.htCapability = 0; + sta_ds->mlmStaContext.vhtCapability = 0; + } + if (sta_ds->mlmStaContext.vhtCapability) { + if (session->vht_config.su_beam_formee && + assoc_req->VHTCaps.suBeamFormerCap) + sta_ds->vhtBeamFormerCapable = 1; + else + sta_ds->vhtBeamFormerCapable = 0; + if (session->vht_config.su_beam_former && + assoc_req->VHTCaps.suBeamformeeCap) + sta_ds->vht_su_bfee_capable = 1; + else + sta_ds->vht_su_bfee_capable = 0; + } + if (lim_populate_matching_rate_set(mac_ctx, sta_ds, + &(assoc_req->supportedRates), + &(assoc_req->extendedRates), + assoc_req->HTCaps.supportedMCSSet, + session, vht_caps) != eSIR_SUCCESS) { + /* Could not update hash table entry at DPH with rateset */ + lim_log(mac_ctx, LOGE, + FL("Couldn't update hash entry for aid=%d, MacAddr: " + MAC_ADDRESS_STR), + peer_idx, MAC_ADDR_ARRAY(hdr->sa)); + + /* Release AID */ + lim_release_peer_idx(mac_ctx, peer_idx, session); + + lim_reject_association(mac_ctx, hdr->sa, + sub_type, true, auth_type, peer_idx, false, + (tSirResultCodes)eSIR_MAC_UNSPEC_FAILURE_STATUS, + session); + lim_log(mac_ctx, LOGE, + FL(" Delete dph hash entry")); + if (dph_delete_hash_entry(mac_ctx, hdr->sa, sta_ds->assocId, + &session->dph.dphHashTable) != eSIR_SUCCESS) + lim_log(mac_ctx, LOGE, FL("error deleting hash entry")); + return false; + } + if (assoc_req->operMode.present) { + sta_ds->vhtSupportedRxNss = assoc_req->operMode.rxNSS + 1; + } else { + sta_ds->vhtSupportedRxNss = + ((sta_ds->supportedRates.vhtRxMCSMap & MCSMAPMASK2x2) + == MCSMAPMASK2x2) ? 1 : 2; + } + + /* Add STA context at MAC HW (BMU, RHP & TFP) */ + sta_ds->qosMode = false; + sta_ds->lleEnabled = false; + if (assoc_req->capabilityInfo.qos && (qos_mode == eHAL_SET)) { + sta_ds->lleEnabled = true; + sta_ds->qosMode = true; + } + + sta_ds->wmeEnabled = false; + sta_ds->wsmEnabled = false; + limGetWmeMode(session, &wme_mode); + if ((!sta_ds->lleEnabled) && assoc_req->wmeInfoPresent + && (wme_mode == eHAL_SET)) { + sta_ds->wmeEnabled = true; + sta_ds->qosMode = true; + limGetWsmMode(session, &wsm_mode); + /* + * WMM_APSD - WMM_SA related processing should be separate; + * WMM_SA and WMM_APSD can coexist + */ + if (assoc_req->WMMInfoStation.present) { + /* check whether AP supports or not */ + if (LIM_IS_AP_ROLE(session) && + (session->apUapsdEnable == 0) && + (assoc_req->WMMInfoStation.acbe_uapsd || + assoc_req->WMMInfoStation.acbk_uapsd || + assoc_req->WMMInfoStation.acvo_uapsd || + assoc_req->WMMInfoStation.acvi_uapsd)) { + /* + * Rcvd Re/Assoc Req from STA when UPASD is + * not supported. + */ + lim_log(mac_ctx, LOGE, + FL("UAPSD not supported, reply accordingly")); + /* update UAPSD and send it to LIM to add STA */ + sta_ds->qos.capability.qosInfo.acbe_uapsd = 0; + sta_ds->qos.capability.qosInfo.acbk_uapsd = 0; + sta_ds->qos.capability.qosInfo.acvo_uapsd = 0; + sta_ds->qos.capability.qosInfo.acvi_uapsd = 0; + sta_ds->qos.capability.qosInfo.maxSpLen = 0; + } else { + /* update UAPSD and send it to LIM to add STA */ + sta_ds->qos.capability.qosInfo.acbe_uapsd = + assoc_req->WMMInfoStation.acbe_uapsd; + sta_ds->qos.capability.qosInfo.acbk_uapsd = + assoc_req->WMMInfoStation.acbk_uapsd; + sta_ds->qos.capability.qosInfo.acvo_uapsd = + assoc_req->WMMInfoStation.acvo_uapsd; + sta_ds->qos.capability.qosInfo.acvi_uapsd = + assoc_req->WMMInfoStation.acvi_uapsd; + sta_ds->qos.capability.qosInfo.maxSpLen = + assoc_req->WMMInfoStation.max_sp_length; + } + } + if (assoc_req->wsmCapablePresent && (wsm_mode == eHAL_SET)) + sta_ds->wsmEnabled = true; + } + /* Re/Assoc Response frame to requesting STA */ + sta_ds->mlmStaContext.subType = sub_type; + +#ifdef WLAN_FEATURE_11W + sta_ds->rmfEnabled = (pmf_connection) ? 1 : 0; + sta_ds->pmfSaQueryState = DPH_SA_QUERY_NOT_IN_PROGRESS; + timer_id.fields.sessionId = session->peSessionId; + timer_id.fields.peerIdx = peer_idx; + if (wlan_cfg_get_int(mac_ctx, WNI_CFG_PMF_SA_QUERY_RETRY_INTERVAL, + &retry_interval) != eSIR_SUCCESS) { + lim_log(mac_ctx, LOGE, + FL("Couldn't get PMF SA Query retry interval value")); + lim_reject_association(mac_ctx, hdr->sa, sub_type, true, + auth_type, peer_idx, false, + (tSirResultCodes) eSIR_MAC_UNSPEC_FAILURE_STATUS, + session); + return false; + } + if (WNI_CFG_PMF_SA_QUERY_RETRY_INTERVAL_STAMIN > retry_interval) { + retry_interval = WNI_CFG_PMF_SA_QUERY_RETRY_INTERVAL_STADEF; + } + if (tx_timer_create(mac_ctx, &sta_ds->pmfSaQueryTimer, + "PMF SA Query timer", lim_pmf_sa_query_timer_handler, + timer_id.value, + SYS_MS_TO_TICKS((retry_interval * 1024) / 1000), + 0, TX_NO_ACTIVATE) != TX_SUCCESS) { + lim_log(mac_ctx, LOGE, + FL("could not create PMF SA Query timer")); + lim_reject_association(mac_ctx, hdr->sa, sub_type, + true, auth_type, peer_idx, false, + (tSirResultCodes)eSIR_MAC_UNSPEC_FAILURE_STATUS, + session); + return false; + } +#endif + + if (assoc_req->ExtCap.present) { + lim_set_stads_rtt_cap(sta_ds, + (struct s_ext_cap *) assoc_req->ExtCap.bytes, mac_ctx); + } else { + sta_ds->timingMeasCap = 0; + PELOG1(lim_log(mac_ctx, LOG1, FL("ExtCap not present"));) + } + return true; +} + +/** + * lim_update_sta_ctx() - add/del sta depending on connection state machine + * @mac_ctx: pointer to Global MAC structure + * @session: pointer to pe session entry + * @assoc_req: pointer to ASSOC/REASSOC Request frame + * @sub_type: Assoc(=0) or Reassoc(=1) Requestframe + * @sta_ds: station dph entry + * @update_ctx: indicates if STA context already exist + * + * Checks for SSID match + * + * Return: true of no error, false otherwise + */ +static bool lim_update_sta_ctx(tpAniSirGlobal mac_ctx, tpPESession session, + tpSirAssocReq assoc_req, uint8_t sub_type, + tpDphHashNode sta_ds, uint8_t update_ctx) +{ + tLimMlmStates mlm_prev_state; + /* + * BTAMP: If STA context already exist (ie. update_ctx = 1) for this STA + * then we should delete the old one, and add the new STA. This is taken + * care of in the lim_del_sta() routine. + * + * Prior to BTAMP, we were setting this flag so that when PE receives + * SME_ASSOC_CNF, and if this flag is set, then PE shall delete the old + * station and then add. But now in BTAMP, we're directly adding station + * before waiting for SME_ASSOC_CNF, so we can do this now. + */ + if (!(update_ctx)) { + sta_ds->mlmStaContext.updateContext = 0; + + /* + * BTAMP: Add STA context at HW - issue WMA_ADD_STA_REQ to HAL + */ + if (lim_add_sta(mac_ctx, sta_ds, false, session) != + eSIR_SUCCESS) { + lim_log(mac_ctx, LOGE, + FL("could not Add STA with assocId=%d"), + sta_ds->assocId); + lim_reject_association(mac_ctx, sta_ds->staAddr, + sta_ds->mlmStaContext.subType, true, + sta_ds->mlmStaContext.authType, + sta_ds->assocId, true, + (tSirResultCodes)eSIR_MAC_UNSPEC_FAILURE_STATUS, + session); + + if (session->parsedAssocReq) + assoc_req = + session->parsedAssocReq[sta_ds->assocId]; + return false; + } + } else { + sta_ds->mlmStaContext.updateContext = 1; + mlm_prev_state = sta_ds->mlmStaContext.mlmState; + + /* + * As per the HAL/FW needs the reassoc req need not be calling + * lim_del_sta + */ + if (sub_type != LIM_REASSOC) { + /* + * we need to set the mlmState here in order + * differentiate in lim_del_sta. + */ + sta_ds->mlmStaContext.mlmState = + eLIM_MLM_WT_ASSOC_DEL_STA_RSP_STATE; + if (lim_del_sta(mac_ctx, sta_ds, true, session) + != eSIR_SUCCESS) { + lim_log(mac_ctx, LOGE, + FL("Couldn't DEL STA, assocId=%d staId %d"), + sta_ds->assocId, sta_ds->staIndex); + lim_reject_association(mac_ctx, sta_ds->staAddr, + sta_ds->mlmStaContext.subType, true, + sta_ds->mlmStaContext.authType, + sta_ds->assocId, true, + (tSirResultCodes) + eSIR_MAC_UNSPEC_FAILURE_STATUS, + session); + + /* Restoring the state back. */ + sta_ds->mlmStaContext.mlmState = mlm_prev_state; + if (session->parsedAssocReq) + assoc_req = session->parsedAssocReq[ + sta_ds->assocId]; + return false; + } + } else { + /* + * mlmState is changed in lim_add_sta context use the + * same AID, already allocated + */ + if (lim_add_sta(mac_ctx, sta_ds, false, session) + != eSIR_SUCCESS) { + lim_log(mac_ctx, LOGE, + FL("UPASD not supported, REASSOC Failed")); + lim_reject_association(mac_ctx, sta_ds->staAddr, + sta_ds->mlmStaContext.subType, true, + sta_ds->mlmStaContext.authType, + sta_ds->assocId, true, + (tSirResultCodes) + eSIR_MAC_WME_REFUSED_STATUS, + session); + + /* Restoring the state back. */ + sta_ds->mlmStaContext.mlmState = mlm_prev_state; + if (session->parsedAssocReq) + assoc_req = session->parsedAssocReq[ + sta_ds->assocId]; + return false; + } + } + } + return true; +} + +/** + * lim_process_assoc_cleanup() - frees up resources used in function + * lim_process_assoc_req_frame() + * @mac_ctx: pointer to Global MAC structure + * @session: pointer to pe session entry + * @assoc_req: pointer to ASSOC/REASSOC Request frame + * @sta_ds: station dph entry + * @tmp_assoc_req: pointer to tmp ASSOC/REASSOC Request frame + * @assoc_req_copied: boolean to indicate if assoc req was copied to tmp above + * + * Frees up resources used in function lim_process_assoc_req_frame + * + * Return: void + */ +static void lim_process_assoc_cleanup(tpAniSirGlobal mac_ctx, + tpPESession session, + tpSirAssocReq assoc_req, + tpDphHashNode sta_ds, + bool *assoc_req_copied) +{ + tpSirAssocReq tmp_assoc_req; + + if (assoc_req != NULL) { + if (assoc_req->assocReqFrame) { + qdf_mem_free(assoc_req->assocReqFrame); + assoc_req->assocReqFrame = NULL; + assoc_req->assocReqFrameLength = 0; + } + + qdf_mem_free(assoc_req); + /* to avoid double free */ + if (*assoc_req_copied && session->parsedAssocReq) + session->parsedAssocReq[sta_ds->assocId] = NULL; + } + + /* If it is not duplicate Assoc request then only make to Null */ + if ((sta_ds != NULL) && + (sta_ds->mlmStaContext.mlmState != eLIM_MLM_WT_ADD_STA_RSP_STATE)) { + if (session->parsedAssocReq != NULL) { + tmp_assoc_req = + session->parsedAssocReq[sta_ds->assocId]; + if (tmp_assoc_req != NULL) { + if (tmp_assoc_req->assocReqFrame) { + qdf_mem_free( + tmp_assoc_req->assocReqFrame); + tmp_assoc_req->assocReqFrame = NULL; + tmp_assoc_req->assocReqFrameLength = 0; + } + qdf_mem_free(tmp_assoc_req); + session->parsedAssocReq[sta_ds->assocId] = NULL; + } + } + } +} + +/** + * lim_process_assoc_req_frame() - Process RE/ASSOC Request frame. + * @mac_ctx: Pointer to Global MAC structure + * @rx_pkt_info: A pointer to Buffer descriptor + associated PDUs + * @sub_type: Indicates whether it is Association Request(=0) or Reassociation + * Request(=1) frame + * @session: pe session entry + * + * This function is called to process RE/ASSOC Request frame. + * + * @Return: void + */ +void lim_process_assoc_req_frame(tpAniSirGlobal mac_ctx, uint8_t *rx_pkt_info, + uint8_t sub_type, tpPESession session) +{ + bool pmf_connection = false, assoc_req_copied = false; + uint8_t update_ctx, *frm_body; + uint16_t peer_idx, assoc_id = 0; + uint32_t frame_len; + uint32_t phy_mode; + tHalBitVal qos_mode; + tpSirMacMgmtHdr hdr; + struct tLimPreAuthNode *sta_pre_auth_ctx; + tAniAuthType auth_type; + tSirMacCapabilityInfo local_cap; + tpDphHashNode sta_ds = NULL; + tpSirAssocReq assoc_req; + bool dup_entry = false; + + lim_get_phy_mode(mac_ctx, &phy_mode, session); + + limGetQosMode(session, &qos_mode); + + hdr = WMA_GET_RX_MAC_HEADER(rx_pkt_info); + frame_len = WMA_GET_RX_PAYLOAD_LEN(rx_pkt_info); + + lim_log(mac_ctx, LOG1, + FL("Rcvd %s Req Frame, sessionid: %d systemrole %d MlmState %d from: " + MAC_ADDRESS_STR), + (LIM_ASSOC == sub_type) ? "Assoc" : "ReAssoc", + session->peSessionId, GET_LIM_SYSTEM_ROLE(session), + session->limMlmState, MAC_ADDR_ARRAY(hdr->sa)); + + if (LIM_IS_STA_ROLE(session)) { + lim_log(mac_ctx, LOGE, + FL("Rcvd unexpected ASSOC REQ, sessionid: %d sys sub_type=%d for role=%d from: " + MAC_ADDRESS_STR), + session->peSessionId, sub_type, + GET_LIM_SYSTEM_ROLE(session), + MAC_ADDR_ARRAY(hdr->sa)); + sir_dump_buf(mac_ctx, SIR_LIM_MODULE_ID, LOG3, + WMA_GET_RX_MPDU_DATA(rx_pkt_info), frame_len); + return; + } + if (session->limMlmState == eLIM_MLM_WT_DEL_BSS_RSP_STATE) { + lim_log(mac_ctx, LOGE, FL("drop ASSOC REQ on sessionid: %d " + "role=%d from: "MAC_ADDRESS_STR" in limMlmState %d"), + session->peSessionId, + GET_LIM_SYSTEM_ROLE(session), + MAC_ADDR_ARRAY(hdr->sa), + eLIM_MLM_WT_DEL_BSS_RSP_STATE); + return; + } + + /* + * If a STA is already present in DPH and it is initiating a Assoc + * re-transmit, do not process it. This can happen when first Assoc Req + * frame is received but ACK lost at STA side. The ACK for this dropped + * Assoc Req frame should be sent by HW. Host simply does not process it + * once the entry for the STA is already present in DPH. + */ + sta_ds = dph_lookup_hash_entry(mac_ctx, hdr->sa, &assoc_id, + &session->dph.dphHashTable); + if (NULL != sta_ds) { + if (hdr->fc.retry > 0) { + lim_log(mac_ctx, LOGE, + FL("STA is initiating Assoc Req after ACK lost. Do not process sessionid: %d sys sub_type=%d for role=%d from: " + MAC_ADDRESS_STR), session->peSessionId, + sub_type, GET_LIM_SYSTEM_ROLE(session), + MAC_ADDR_ARRAY(hdr->sa)); + return; + } else if (!sta_ds->rmfEnabled) { + /* + * Do this only for non PMF case. + * STA might have missed the assoc response, so it is + * sending assoc request frame again. + */ + lim_send_assoc_rsp_mgmt_frame(mac_ctx, eSIR_SUCCESS, + sta_ds->assocId, sta_ds->staAddr, + sub_type, + sta_ds, session); + lim_log(mac_ctx, LOGE, + FL("DUT already received an assoc request frame and STA is sending another assoc req.So, do not Process sessionid: %d sys sub_type=%d for role=%d from: " + MAC_ADDRESS_STR), + session->peSessionId, sub_type, + session->limSystemRole, + MAC_ADDR_ARRAY(hdr->sa)); + return; + } + } + + dup_entry = lim_check_sta_in_pe_entries(mac_ctx, hdr, + session->peSessionId); + + /* Get pointer to Re/Association Request frame body */ + frm_body = WMA_GET_RX_MPDU_DATA(rx_pkt_info); + + if (lim_is_group_addr(hdr->sa)) { + /* + * Rcvd Re/Assoc Req frame from BC/MC address Log error and + * ignore it + */ + lim_log(mac_ctx, LOGE, + FL("Rcvd %s Req, sessionid: %d from a BC/MC address" + MAC_ADDRESS_STR), + (LIM_ASSOC == sub_type) ? "Assoc" : "ReAssoc", + session->peSessionId, MAC_ADDR_ARRAY(hdr->sa)); + return; + } + + sir_dump_buf(mac_ctx, SIR_LIM_MODULE_ID, LOG2, + (uint8_t *) frm_body, frame_len); + + if (false == lim_chk_sa_da(mac_ctx, hdr, session, sub_type)) + return; + + if (false == lim_chk_tkip(mac_ctx, hdr, session, sub_type)) + return; + + /* check for the presence of vendor IE */ + if ((session->access_policy_vendor_ie) && + (session->access_policy == + LIM_ACCESS_POLICY_RESPOND_IF_IE_IS_PRESENT)) { + if (!cfg_get_vendor_ie_ptr_from_oui(mac_ctx, + &session->access_policy_vendor_ie[2], + 3, frm_body + LIM_ASSOC_REQ_IE_OFFSET, frame_len)) { + lim_log(mac_ctx, LOGE, + FL("Vendor ie not present and access policy is %x, Rejected association"), + session->access_policy); + lim_send_assoc_rsp_mgmt_frame(mac_ctx, + eSIR_MAC_UNSPEC_FAILURE_STATUS, 1, hdr->sa, + sub_type, 0, session); + return; + } + } + /* Allocate memory for the Assoc Request frame */ + assoc_req = qdf_mem_malloc(sizeof(*assoc_req)); + if (NULL == assoc_req) { + lim_log(mac_ctx, LOGP, + FL("Allocate Memory failed in assoc_req")); + return; + } + + /* Parse Assoc Request frame */ + if (false == lim_chk_assoc_req_parse_error(mac_ctx, hdr, session, + assoc_req, sub_type, frm_body, frame_len)) + goto error; + + assoc_req->assocReqFrame = qdf_mem_malloc(frame_len); + if (NULL == assoc_req->assocReqFrame) { + lim_log(mac_ctx, LOGE, + FL("Memory alloc failed for the assoc req, len=%d"), + frame_len); + goto error; + } + + qdf_mem_copy((uint8_t *) assoc_req->assocReqFrame, + (uint8_t *) frm_body, frame_len); + assoc_req->assocReqFrameLength = frame_len; + + if (false == lim_chk_capab(mac_ctx, hdr, session, assoc_req, + sub_type, &local_cap)) + goto error; + + update_ctx = false; + + if (false == lim_chk_ssid(mac_ctx, hdr, session, assoc_req, sub_type)) + goto error; + + if (false == lim_chk_rates(mac_ctx, hdr, session, assoc_req, sub_type)) + goto error; + + if (false == lim_chk_11g_only(mac_ctx, hdr, session, assoc_req, + sub_type)) + goto error; + + if (false == lim_chk_11n_only(mac_ctx, hdr, session, assoc_req, + sub_type)) + goto error; + + if (false == lim_chk_11ac_only(mac_ctx, hdr, session, assoc_req, + sub_type)) + goto error; + + /* Spectrum Management (11h) specific checks */ + lim_process_for_spectrum_mgmt(mac_ctx, hdr, session, + assoc_req, sub_type, local_cap); + + if (false == lim_chk_mcs(mac_ctx, hdr, session, assoc_req, sub_type)) + goto error; + + if (false == lim_chk_is_11b_sta_supported(mac_ctx, hdr, session, + assoc_req, sub_type, phy_mode)) + goto error; + + /* + * Check for 802.11n HT caps compatibility; are HT Capabilities + * turned on in lim? + */ + lim_print_ht_cap(mac_ctx, session, assoc_req); + + if (false == lim_chk_n_process_wpa_rsn_ie(mac_ctx, hdr, session, + assoc_req, sub_type, &pmf_connection)) + goto error; + + /* Extract 'associated' context for STA, if any. */ + sta_ds = dph_lookup_hash_entry(mac_ctx, hdr->sa, &peer_idx, + &session->dph.dphHashTable); + + /* Extract pre-auth context for the STA, if any. */ + sta_pre_auth_ctx = lim_search_pre_auth_list(mac_ctx, hdr->sa); + + if (sta_ds == NULL) { + if (false == lim_process_assoc_req_no_sta_ctx(mac_ctx, hdr, + session, assoc_req, sub_type, sta_pre_auth_ctx, + sta_ds, &auth_type)) + goto error; + } else { + if (false == lim_process_assoc_req_sta_ctx(mac_ctx, hdr, + session, assoc_req, sub_type, sta_pre_auth_ctx, + sta_ds, peer_idx, &auth_type, &update_ctx)) + goto error; + goto sendIndToSme; + } + + /* check if sta is allowed per QoS AC rules */ + if (false == lim_chk_wmm(mac_ctx, hdr, session, + assoc_req, sub_type, qos_mode)) + goto error; + + /* STA is Associated ! */ + lim_log(mac_ctx, LOGE, + FL("Received %s Req successful from " MAC_ADDRESS_STR), + (LIM_ASSOC == sub_type) ? "Assoc" : "ReAssoc", + MAC_ADDR_ARRAY(hdr->sa)); + + /* + * AID for this association will be same as the peer Index used in DPH + * table. Assign unused/least recently used peer Index from perStaDs. + * NOTE: lim_assign_peer_idx() assigns AID values ranging between + * 1 - cfg_item(WNI_CFG_ASSOC_STA_LIMIT) + */ + + peer_idx = lim_assign_peer_idx(mac_ctx, session); + + if (!peer_idx) { + /* Could not assign AID. Reject association */ + lim_log(mac_ctx, LOGE, + FL("PeerIdx not avaialble. Reject associaton")); + lim_reject_association(mac_ctx, hdr->sa, sub_type, + true, auth_type, peer_idx, false, + (tSirResultCodes)eSIR_MAC_UNSPEC_FAILURE_STATUS, + session); + goto error; + } + + /* Add an entry to hash table maintained by DPH module */ + + sta_ds = dph_add_hash_entry(mac_ctx, hdr->sa, peer_idx, + &session->dph.dphHashTable); + + if (sta_ds == NULL) { + /* Could not add hash table entry at DPH */ + lim_log(mac_ctx, LOGE, + FL("couldn't add hash entry at DPH for aid=%d, MacAddr:" + MAC_ADDRESS_STR), peer_idx, MAC_ADDR_ARRAY(hdr->sa)); + + /* Release AID */ + lim_release_peer_idx(mac_ctx, peer_idx, session); + + lim_reject_association(mac_ctx, hdr->sa, sub_type, + true, auth_type, peer_idx, false, + (tSirResultCodes) eSIR_MAC_UNSPEC_FAILURE_STATUS, + session); + goto error; + } + +sendIndToSme: + if (false == lim_update_sta_ds(mac_ctx, hdr, session, assoc_req, + sub_type, sta_ds, auth_type, + &assoc_req_copied, peer_idx, qos_mode, + pmf_connection)) + goto error; + + + /* BTAMP: Storing the parsed assoc request in the session array */ + if (session->parsedAssocReq) + session->parsedAssocReq[sta_ds->assocId] = assoc_req; + assoc_req_copied = true; + + /* If it is duplicate entry wait till the peer is deleted */ + if (dup_entry != true) { + if (false == lim_update_sta_ctx(mac_ctx, session, assoc_req, + sub_type, sta_ds, update_ctx)) + goto error; + } + + /* AddSta is sucess here */ + if (LIM_IS_AP_ROLE(session) && IS_DOT11_MODE_HT(session->dot11mode) && + assoc_req->HTCaps.present && assoc_req->wmeInfoPresent) { + /* + * Update in the HAL Sta Table for the Update of the Protection + * Mode + */ + lim_post_sm_state_update(mac_ctx, sta_ds->staIndex, + sta_ds->htMIMOPSState, sta_ds->staAddr, + session->smeSessionId); + } + + return; + +error: + lim_process_assoc_cleanup(mac_ctx, session, assoc_req, sta_ds, + &assoc_req_copied); + return; +} + +#ifdef FEATURE_WLAN_WAPI +/** + * lim_fill_assoc_ind_wapi_info()- Updates WAPI data in assoc indication + * @mac_ctx: Global Mac context + * @assoc_req: pointer to association request + * @assoc_ind: Pointer to association indication + * @wpsie: WPS IE + * + * This function updates WAPI meta data in association indication message + * sent to SME. + * + * Return: None + */ +static void lim_fill_assoc_ind_wapi_info(tpAniSirGlobal mac_ctx, + tpSirAssocReq assoc_req, tpLimMlmAssocInd assoc_ind, + uint8_t *wpsie) +{ + if (assoc_req->wapiPresent && (NULL == wpsie)) { + lim_log(mac_ctx, LOG2, + FL("Received WAPI IE length in Assoc Req is %d"), + assoc_req->wapi.length); + assoc_ind->wapiIE.wapiIEdata[0] = SIR_MAC_WAPI_EID; + assoc_ind->wapiIE.wapiIEdata[1] = assoc_req->wapi.length; + qdf_mem_copy(&assoc_ind->wapiIE.wapiIEdata[2], + assoc_req->wapi.info, assoc_req->wapi.length); + assoc_ind->wapiIE.length = + 2 + assoc_req->wapi.length; + } + return; +} +#endif + +/** + * lim_fill_assoc_ind_vht_info() - Updates VHT information in assoc indication + * @mac_ctx: Global Mac context + * @assoc_req: pointer to association request + * @session_entry: PE session entry + * @assoc_ind: Pointer to association indication + * + * This function updates VHT information in association indication message + * sent to SME. + * + * Return: None + */ +static void lim_fill_assoc_ind_vht_info(tpAniSirGlobal mac_ctx, + tpPESession session_entry, + tpSirAssocReq assoc_req, + tpLimMlmAssocInd assoc_ind) +{ + uint8_t chan; + + if (session_entry->limRFBand == SIR_BAND_2_4_GHZ) { + if (session_entry->vhtCapability && assoc_req->VHTCaps.present) + assoc_ind->chan_info.info = MODE_11AC_VHT20_2G; + else if (session_entry->htCapability + && assoc_req->HTCaps.present) + assoc_ind->chan_info.info = MODE_11NG_HT20; + else + assoc_ind->chan_info.info = MODE_11G; + return; + } + + if (session_entry->vhtCapability && assoc_req->VHTCaps.present) { + if ((session_entry->ch_width > CH_WIDTH_40MHZ) + && assoc_req->HTCaps.supportedChannelWidthSet) { + chan = session_entry->ch_center_freq_seg0; + assoc_ind->chan_info.band_center_freq1 = + cds_chan_to_freq(chan); + assoc_ind->chan_info.info = MODE_11AC_VHT80; + return; + } + + if ((session_entry->ch_width == CH_WIDTH_40MHZ) + && assoc_req->HTCaps.supportedChannelWidthSet) { + assoc_ind->chan_info.info = MODE_11AC_VHT40; + if (session_entry->htSecondaryChannelOffset == + PHY_DOUBLE_CHANNEL_LOW_PRIMARY) + assoc_ind->chan_info.band_center_freq1 += 10; + else + assoc_ind->chan_info.band_center_freq1 -= 10; + return; + } + + assoc_ind->chan_info.info = MODE_11AC_VHT20; + return; + } + + if (session_entry->htCapability && assoc_req->HTCaps.present) { + if ((session_entry->ch_width == CH_WIDTH_40MHZ) + && assoc_req->HTCaps.supportedChannelWidthSet) { + assoc_ind->chan_info.info = MODE_11NA_HT40; + if (session_entry->htSecondaryChannelOffset == + PHY_DOUBLE_CHANNEL_LOW_PRIMARY) + assoc_ind->chan_info.band_center_freq1 += 10; + else + assoc_ind->chan_info.band_center_freq1 -= 10; + return; + } + + assoc_ind->chan_info.info = MODE_11NA_HT20; + return; + } + + assoc_ind->chan_info.info = MODE_11A; + return; +} + +/** + * lim_send_mlm_assoc_ind() - Sends assoc indication to SME + * @mac_ctx: Global Mac context + * @sta_ds: Station DPH hash entry + * @session_entry: PE session entry + * + * This function sends either LIM_MLM_ASSOC_IND + * or LIM_MLM_REASSOC_IND to SME. + * + * Return: None + */ +void lim_send_mlm_assoc_ind(tpAniSirGlobal mac_ctx, + tpDphHashNode sta_ds, tpPESession session_entry) +{ + tpLimMlmAssocInd assoc_ind = NULL; + tpSirAssocReq assoc_req; + uint16_t temp, rsn_len; + uint32_t phy_mode; + uint8_t sub_type; + uint8_t *wpsie = NULL; + uint32_t tmp; + + /* Get a copy of the already parsed Assoc Request */ + assoc_req = + (tpSirAssocReq) session_entry->parsedAssocReq[sta_ds->assocId]; + + /* Get the phy_mode */ + lim_get_phy_mode(mac_ctx, &phy_mode, session_entry); + + /* Determine if its Assoc or ReAssoc Request */ + if (assoc_req->reassocRequest == 1) + sub_type = LIM_REASSOC; + else + sub_type = LIM_ASSOC; + + lim_log(mac_ctx, LOG1, + FL("Sessionid %d ssid %s sub_type %d Associd %d staAddr " + MAC_ADDRESS_STR), session_entry->peSessionId, + assoc_req->ssId.ssId, sub_type, sta_ds->assocId, + MAC_ADDR_ARRAY(sta_ds->staAddr)); + + if (sub_type == LIM_ASSOC || sub_type == LIM_REASSOC) { + temp = sizeof(tLimMlmAssocInd); + + assoc_ind = qdf_mem_malloc(temp); + if (NULL == assoc_ind) { + lim_release_peer_idx(mac_ctx, sta_ds->assocId, + session_entry); + lim_log(mac_ctx, LOGP, + FL("AllocateMemory failed for assoc_ind")); + return; + } + qdf_mem_copy((uint8_t *) assoc_ind->peerMacAddr, + (uint8_t *) sta_ds->staAddr, sizeof(tSirMacAddr)); + assoc_ind->aid = sta_ds->assocId; + qdf_mem_copy((uint8_t *) &assoc_ind->ssId, + (uint8_t *) &(assoc_req->ssId), + assoc_req->ssId.length + 1); + assoc_ind->sessionId = session_entry->peSessionId; + assoc_ind->authType = sta_ds->mlmStaContext.authType; + assoc_ind->capabilityInfo = assoc_req->capabilityInfo; + + /* Fill in RSN IE information */ + assoc_ind->rsnIE.length = 0; + /* if WPS IE is present, ignore RSN IE */ + if (assoc_req->addIEPresent && assoc_req->addIE.length) { + wpsie = limGetWscIEPtr(mac_ctx, + assoc_req->addIE.addIEdata, + assoc_req->addIE.length); + } + if (assoc_req->rsnPresent && (NULL == wpsie)) { + lim_log(mac_ctx, LOG2, FL("Assoc Req RSN IE len = %d"), + assoc_req->rsn.length); + assoc_ind->rsnIE.length = 2 + assoc_req->rsn.length; + assoc_ind->rsnIE.rsnIEdata[0] = SIR_MAC_RSN_EID; + assoc_ind->rsnIE.rsnIEdata[1] = + assoc_req->rsn.length; + qdf_mem_copy(&assoc_ind->rsnIE.rsnIEdata[2], + assoc_req->rsn.info, + assoc_req->rsn.length); + } + /* Fill in 802.11h related info */ + if (assoc_req->powerCapabilityPresent + && assoc_req->supportedChannelsPresent) { + assoc_ind->spectrumMgtIndicator = eSIR_TRUE; + assoc_ind->powerCap.minTxPower = + assoc_req->powerCapability.minTxPower; + assoc_ind->powerCap.maxTxPower = + assoc_req->powerCapability.maxTxPower; + lim_convert_supported_channels(mac_ctx, assoc_ind, + assoc_req); + } else { + assoc_ind->spectrumMgtIndicator = eSIR_FALSE; + } + + /* This check is to avoid extra Sec IEs present incase of WPS */ + if (assoc_req->wpaPresent && (NULL == wpsie)) { + rsn_len = assoc_ind->rsnIE.length; + if ((rsn_len + assoc_req->wpa.length) + >= SIR_MAC_MAX_IE_LENGTH) { + lim_log(mac_ctx, LOGE, + FL("rsnIEdata index out of bounds %d"), + rsn_len); + qdf_mem_free(assoc_ind); + return; + } + assoc_ind->rsnIE.rsnIEdata[rsn_len] = + SIR_MAC_WPA_EID; + assoc_ind->rsnIE.rsnIEdata[rsn_len + 1] + = assoc_req->wpa.length; + qdf_mem_copy( + &assoc_ind->rsnIE.rsnIEdata[rsn_len + 2], + assoc_req->wpa.info, assoc_req->wpa.length); + assoc_ind->rsnIE.length += 2 + assoc_req->wpa.length; + } +#ifdef FEATURE_WLAN_WAPI + lim_fill_assoc_ind_wapi_info(mac_ctx, assoc_req, assoc_ind, + wpsie); +#endif + + assoc_ind->addIE.length = 0; + if (assoc_req->addIEPresent) { + qdf_mem_copy(&assoc_ind->addIE.addIEdata, + assoc_req->addIE.addIEdata, + assoc_req->addIE.length); + assoc_ind->addIE.length = assoc_req->addIE.length; + } + /* + * Add HT Capabilities into addIE for OBSS + * processing in hostapd + */ + if (assoc_req->HTCaps.present) { + rsn_len = assoc_ind->addIE.length; + if (assoc_ind->addIE.length + DOT11F_IE_HTCAPS_MIN_LEN + + 2 < SIR_MAC_MAX_IE_LENGTH) { + assoc_ind->addIE.addIEdata[rsn_len] = + SIR_MAC_HT_CAPABILITIES_EID; + assoc_ind->addIE.addIEdata[rsn_len + 1] = + DOT11F_IE_HTCAPS_MIN_LEN; + qdf_mem_copy( + &assoc_ind->addIE.addIEdata[rsn_len+2], + ((uint8_t *)&assoc_req->HTCaps) + 1, + DOT11F_IE_HTCAPS_MIN_LEN); + assoc_ind->addIE.length += + 2 + DOT11F_IE_HTCAPS_MIN_LEN; + } else { + lim_log(mac_ctx, LOGP, + FL("Fail:HT capabilities IE to addIE")); + } + } + + if (assoc_req->wmeInfoPresent) { + if (wlan_cfg_get_int (mac_ctx, + (uint16_t) WNI_CFG_WME_ENABLED, &tmp) + != eSIR_SUCCESS) + lim_log(mac_ctx, LOGP, + FL("wlan_cfg_get_int failed for id %d"), + WNI_CFG_WME_ENABLED); + + /* check whether AP is enabled with WMM */ + if (tmp) + assoc_ind->WmmStaInfoPresent = 1; + else + assoc_ind->WmmStaInfoPresent = 0; + /* + * Note: we are not rejecting association here + * because IOT will fail + */ + } + /* Required for indicating the frames to upper layer */ + assoc_ind->assocReqLength = assoc_req->assocReqFrameLength; + assoc_ind->assocReqPtr = assoc_req->assocReqFrame; + + assoc_ind->beaconPtr = session_entry->beacon; + assoc_ind->beaconLength = session_entry->bcnLen; + + assoc_ind->chan_info.chan_id = + session_entry->currentOperChannel; + assoc_ind->chan_info.mhz = + cds_chan_to_freq(session_entry->currentOperChannel); + assoc_ind->chan_info.band_center_freq1 = + cds_chan_to_freq(session_entry->currentOperChannel); + assoc_ind->chan_info.band_center_freq2 = 0; + assoc_ind->chan_info.reg_info_1 = + (session_entry->maxTxPower << 16); + assoc_ind->chan_info.reg_info_2 = + (session_entry->maxTxPower << 8); + assoc_ind->chan_info.nss = sta_ds->nss; + assoc_ind->chan_info.rate_flags = + lim_get_max_rate_flags(mac_ctx, sta_ds); + /* updates VHT information in assoc indication */ + lim_fill_assoc_ind_vht_info(mac_ctx, session_entry, assoc_req, + assoc_ind); + lim_post_sme_message(mac_ctx, LIM_MLM_ASSOC_IND, + (uint32_t *) assoc_ind); + qdf_mem_free(assoc_ind); + } + return; +} diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_process_assoc_rsp_frame.c b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_process_assoc_rsp_frame.c new file mode 100644 index 0000000000000000000000000000000000000000..ab211a1adc80a466c5279050479d6f591bd97298 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_process_assoc_rsp_frame.c @@ -0,0 +1,1087 @@ +/* + * Copyright (c) 2011-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * + * This file lim_process_assoc_rsp_frame.cc contains the code + * for processing Re/Association Response Frame. + * Author: Chandra Modumudi + * Date: 03/18/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + * + */ + +#include "wni_api.h" +#include "wni_cfg.h" +#include "ani_global.h" +#include "cfg_api.h" +#include "sch_api.h" + +#include "utils_api.h" +#include "lim_types.h" +#include "lim_utils.h" +#include "lim_assoc_utils.h" +#include "lim_security_utils.h" +#include "lim_ser_des_utils.h" +#include "lim_sta_hash_api.h" +#include "lim_send_messages.h" + + +extern tSirRetStatus sch_beacon_edca_process(tpAniSirGlobal pMac, + tSirMacEdcaParamSetIE *edca, tpPESession psessionEntry); + +/** + * lim_update_stads_htcap() - Updates station Descriptor HT capability + * @mac_ctx: Pointer to Global MAC structure + * @sta_ds: Station Descriptor in DPH + * @assoc_rsp: Pointer to Association Response Structure + * @session_entry : PE session Entry + * + * This function is called to Update the HT capabilities in + * Station Descriptor (dph) Details from + * Association / ReAssociation Response Frame + * + * Return: None + */ +static void lim_update_stads_htcap(tpAniSirGlobal mac_ctx, + tpDphHashNode sta_ds, tpSirAssocRsp assoc_rsp, + tpPESession session_entry) +{ + uint16_t highest_rxrate = 0; + tDot11fIEHTCaps *ht_caps; + + ht_caps = &assoc_rsp->HTCaps; + sta_ds->mlmStaContext.htCapability = assoc_rsp->HTCaps.present; + if (assoc_rsp->HTCaps.present) { + sta_ds->htGreenfield = + (uint8_t) ht_caps->greenField; + if (session_entry->htSupportedChannelWidthSet) { + sta_ds->htSupportedChannelWidthSet = + (uint8_t) (ht_caps->supportedChannelWidthSet ? + assoc_rsp->HTInfo.recommendedTxWidthSet : + ht_caps->supportedChannelWidthSet); + } else + sta_ds->htSupportedChannelWidthSet = + eHT_CHANNEL_WIDTH_20MHZ; + sta_ds->htLsigTXOPProtection = + (uint8_t) ht_caps->lsigTXOPProtection; + sta_ds->htMIMOPSState = + (tSirMacHTMIMOPowerSaveState)ht_caps->mimoPowerSave; + sta_ds->htMaxAmsduLength = + (uint8_t) ht_caps->maximalAMSDUsize; + sta_ds->htAMpduDensity = ht_caps->mpduDensity; + sta_ds->htDsssCckRate40MHzSupport = + (uint8_t) ht_caps->dsssCckMode40MHz; + sta_ds->htMaxRxAMpduFactor = + ht_caps->maxRxAMPDUFactor; + lim_fill_rx_highest_supported_rate(mac_ctx, &highest_rxrate, + ht_caps->supportedMCSSet); + sta_ds->supportedRates.rxHighestDataRate = + highest_rxrate; + /* + * This is for AP as peer STA and we are INFRA STA + *.We will put APs offset in dph node which is peer STA + */ + sta_ds->htSecondaryChannelOffset = + (uint8_t) assoc_rsp->HTInfo.secondaryChannelOffset; + /* + * FIXME_AMPDU + * In the future, may need to check for + * "assoc.HTCaps.delayedBA" + * For now, it is IMMEDIATE BA only on ALL TID's + */ + sta_ds->baPolicyFlag = 0xFF; + + /* Check if we have support for gShortGI20Mhz and + * gShortGI40Mhz from ini file + */ + if (session_entry->htConfig.ht_sgi20) + sta_ds->htShortGI20Mhz = + (uint8_t)assoc_rsp->HTCaps.shortGI20MHz; + else + sta_ds->htShortGI20Mhz = false; + + if (session_entry->htConfig.ht_sgi40) + sta_ds->htShortGI40Mhz = + (uint8_t)assoc_rsp->HTCaps.shortGI40MHz; + else + sta_ds->htShortGI40Mhz = false; + } +} + +/** + * lim_update_assoc_sta_datas() - Updates station Descriptor + * mac_ctx: Pointer to Global MAC structure + * sta_ds: Station Descriptor in DPH + * assoc_rsp: Pointer to Association Response Structure + * session_entry : PE session Entry + * + * This function is called to Update the Station Descriptor (dph) Details from + * Association / ReAssociation Response Frame + * + * Return: None + */ +void lim_update_assoc_sta_datas(tpAniSirGlobal mac_ctx, + tpDphHashNode sta_ds, tpSirAssocRsp assoc_rsp, + tpPESession session_entry) +{ + uint32_t phy_mode; + bool qos_mode; + tDot11fIEVHTCaps *vht_caps = NULL; + + lim_get_phy_mode(mac_ctx, &phy_mode, session_entry); + sta_ds->staType = STA_ENTRY_SELF; + limGetQosMode(session_entry, &qos_mode); + sta_ds->mlmStaContext.authType = session_entry->limCurrentAuthType; + + /* Add capabilities information, rates and AID */ + sta_ds->mlmStaContext.capabilityInfo = assoc_rsp->capabilityInfo; + sta_ds->shortPreambleEnabled = + (uint8_t) assoc_rsp->capabilityInfo.shortPreamble; + + /* Update HT Capabilites only when the self mode supports HT */ + if (IS_DOT11_MODE_HT(session_entry->dot11mode)) + lim_update_stads_htcap(mac_ctx, sta_ds, assoc_rsp, + session_entry); + + if (assoc_rsp->VHTCaps.present) + vht_caps = &assoc_rsp->VHTCaps; + else if (assoc_rsp->vendor_vht_ie.VHTCaps.present) + vht_caps = &assoc_rsp->vendor_vht_ie.VHTCaps; + + if (IS_DOT11_MODE_VHT(session_entry->dot11mode)) { + if ((vht_caps != NULL) && vht_caps->present) { + sta_ds->mlmStaContext.vhtCapability = + vht_caps->present; + /* + * If 11ac is supported and if the peer is + * sending VHT capabilities, + * then htMaxRxAMpduFactor should be + * overloaded with VHT maxAMPDULenExp + */ + sta_ds->htMaxRxAMpduFactor = vht_caps->maxAMPDULenExp; + if (session_entry->htSupportedChannelWidthSet) { + if (assoc_rsp->VHTOperation.present) + sta_ds->vhtSupportedChannelWidthSet = + assoc_rsp->VHTOperation.chanWidth; + else + sta_ds->vhtSupportedChannelWidthSet = + eHT_CHANNEL_WIDTH_40MHZ; + } + } + } + if (lim_populate_peer_rate_set(mac_ctx, &sta_ds->supportedRates, + assoc_rsp->HTCaps.supportedMCSSet, + false, session_entry, + vht_caps) != eSIR_SUCCESS) { + lim_log(mac_ctx, LOGP, + FL("could not get rateset and extended rate set")); + return; + } + sta_ds->vhtSupportedRxNss = + ((sta_ds->supportedRates.vhtRxMCSMap & MCSMAPMASK2x2) + == MCSMAPMASK2x2) ? 1 : 2; + /* If one of the rates is 11g rates, set the ERP mode. */ + if ((phy_mode == WNI_CFG_PHY_MODE_11G) && + sirIsArate(sta_ds->supportedRates.llaRates[0] & 0x7f)) + sta_ds->erpEnabled = eHAL_SET; + + /* Could not get prop rateset from CFG. Log error. */ + sta_ds->qosMode = 0; + sta_ds->lleEnabled = 0; + + /* update TSID to UP mapping */ + if (qos_mode) { + if (assoc_rsp->edcaPresent) { + tSirRetStatus status; + status = + sch_beacon_edca_process(mac_ctx, + &assoc_rsp->edca, session_entry); + lim_log(mac_ctx, LOG2, + "Edca set update based on AssocRsp: status %d", + status); + if (status != eSIR_SUCCESS) { + lim_log(mac_ctx, LOGE, + FL("Edca error in AssocResp ")); + } else { + /* update default tidmap based on ACM */ + sta_ds->qosMode = 1; + sta_ds->lleEnabled = 1; + } + } + } + + sta_ds->wmeEnabled = 0; + sta_ds->wsmEnabled = 0; + if (session_entry->limWmeEnabled && assoc_rsp->wmeEdcaPresent) { + tSirRetStatus status; + status = sch_beacon_edca_process(mac_ctx, &assoc_rsp->edca, + session_entry); + lim_log(mac_ctx, LOGW, + "WME Edca set update based on AssocRsp: status %d", + status); + + if (status != eSIR_SUCCESS) + lim_log(mac_ctx, LOGE, + FL("WME Edca error in AssocResp - ignoring")); + + else { + /* update default tidmap based on HashACM */ + sta_ds->qosMode = 1; + sta_ds->wmeEnabled = 1; + } + } else { + /* + * We received assoc rsp from a legacy AP. + * So fill in the default local EDCA params. + * This is needed (refer to bug #14989) as we'll + * be passing the gLimEdcaParams to HAL in + * lim_process_sta_mlm_add_bss_rsp(). + */ + sch_set_default_edca_params(mac_ctx, session_entry); + } + + if (qos_mode && (!sta_ds->qosMode) && + sta_ds->mlmStaContext.htCapability) { + /* + * Enable QOS for all HT AP's even though WMM + * or 802.11E IE is not present + */ + sta_ds->qosMode = 1; + sta_ds->wmeEnabled = 1; + } +#ifdef WLAN_FEATURE_11W + if (session_entry->limRmfEnabled) + sta_ds->rmfEnabled = 1; +#endif +} + +/** + * lim_update_ric_data() - update session with ric data + * @mac_ctx: Pointer to Global MAC structure + * @session_entry: PE session handle + * @assoc_rsp: pointer to assoc response + * + * This function is called by lim_process_assoc_rsp_frame() to + * update PE session context with RIC data. + * + * Return: None + */ +static void lim_update_ric_data(tpAniSirGlobal mac_ctx, + tpPESession session_entry, tpSirAssocRsp assoc_rsp) +{ + if (session_entry->ricData != NULL) { + qdf_mem_free(session_entry->ricData); + session_entry->ricData = NULL; + session_entry->RICDataLen = 0; + } + if (assoc_rsp->ricPresent) { + session_entry->RICDataLen = + assoc_rsp->num_RICData * sizeof(tDot11fIERICDataDesc); + if (session_entry->RICDataLen) { + session_entry->ricData = + qdf_mem_malloc(session_entry->RICDataLen); + if (NULL == session_entry->ricData) { + lim_log(mac_ctx, LOGE, + FL("No memory for RIC data")); + session_entry->RICDataLen = 0; + } else { + qdf_mem_copy(session_entry->ricData, + &assoc_rsp->RICData[0], + session_entry->RICDataLen); + } + } else { + lim_log(mac_ctx, LOGE, FL("RIC data not present")); + } + } else { + lim_log(mac_ctx, LOG1, + FL("Ric is not present")); + session_entry->RICDataLen = 0; + session_entry->ricData = NULL; + } + return; +} + +#ifdef FEATURE_WLAN_ESE +/** + * lim_update_ese_tspec() - update session with Tspec info. + * @mac_ctx: Pointer to Global MAC structure + * @session_entry: PE session handle + * @assoc_rsp: pointer to assoc response + * + * This function is called by lim_process_assoc_rsp_frame() to + * update PE session context with Tspec data. + * + * Return: None + */ +static void lim_update_ese_tspec(tpAniSirGlobal mac_ctx, + tpPESession session_entry, tpSirAssocRsp assoc_rsp) +{ + if (session_entry->tspecIes != NULL) { + qdf_mem_free(session_entry->tspecIes); + session_entry->tspecIes = NULL; + session_entry->tspecLen = 0; + } + if (assoc_rsp->tspecPresent) { + lim_log(mac_ctx, LOG1, FL("Tspec EID present in assoc rsp")); + session_entry->tspecLen = + assoc_rsp->num_tspecs * sizeof(tDot11fIEWMMTSPEC); + if (session_entry->tspecLen) { + session_entry->tspecIes = + qdf_mem_malloc(session_entry->tspecLen); + if (NULL == session_entry->tspecIes) { + lim_log(mac_ctx, LOGE, + FL("Tspec IE:Fail to allocate memory")); + session_entry->tspecLen = 0; + } else { + qdf_mem_copy(session_entry->tspecIes, + &assoc_rsp->TSPECInfo[0], + session_entry->tspecLen); + } + } else { + lim_log(mac_ctx, LOGE, FL("TSPEC has Zero length")); + } + } else { + session_entry->tspecLen = 0; + session_entry->tspecIes = NULL; + lim_log(mac_ctx, LOG1, + FL("Tspec EID *NOT* present in assoc rsp")); + } + return; +} + +/** + * lim_update_ese_tsm() - update session with TSM info. + * @mac_ctx: Pointer to Global MAC structure + * @session_entry: PE session handle + * @assoc_rsp: pointer to assoc response + * + * This function is called by lim_process_assoc_rsp_frame() to + * update PE session context with TSM IE data and send + * eWNI_TSM_IE_IND to SME. + * + * Return: None + */ +static void lim_update_ese_tsm(tpAniSirGlobal mac_ctx, + tpPESession session_entry, tpSirAssocRsp assoc_rsp) +{ + uint8_t cnt = 0; + tpEseTSMContext tsm_ctx; + + lim_log(mac_ctx, LOG1, + FL("TSM IE Present in Reassoc Rsp")); + /* + * Start the TSM timer only if the TSPEC + * Ie is present in the reassoc rsp + */ + if (!assoc_rsp->tspecPresent) { + lim_log(mac_ctx, LOGE, + FL("TSM present but TSPEC IE not present")); + return; + } + tsm_ctx = &session_entry->eseContext.tsm; + /* Find the TSPEC IE with VO user priority */ + for (cnt = 0; cnt < assoc_rsp->num_tspecs; cnt++) { + if (upToAc(assoc_rsp->TSPECInfo[cnt].user_priority) == + EDCA_AC_VO) { + tsm_ctx->tid = + assoc_rsp->TSPECInfo[cnt].user_priority; + qdf_mem_copy(&tsm_ctx->tsmInfo, + &assoc_rsp->tsmIE, sizeof(tSirMacESETSMIE)); + lim_send_sme_tsm_ie_ind(mac_ctx, + session_entry, assoc_rsp->tsmIE.tsid, + assoc_rsp->tsmIE.state, + assoc_rsp->tsmIE.msmt_interval); + if (tsm_ctx->tsmInfo.state) + tsm_ctx->tsmMetrics.RoamingCount++; + break; + } + } +} +#endif + +/** + * lim_update_stads_ext_cap() - update sta ds with ext cap + * @mac_ctx: Pointer to Global MAC structure + * @session_entry: PE session handle + * @assoc_rsp: pointer to assoc response + * + * This function is called by lim_process_assoc_rsp_frame() to + * update STA DS with ext capablities. + * + * Return: None + */ +static void lim_update_stads_ext_cap(tpAniSirGlobal mac_ctx, + tpPESession session_entry, tpSirAssocRsp assoc_rsp, + tpDphHashNode sta_ds) +{ + struct s_ext_cap *ext_cap; + if (!assoc_rsp->ExtCap.present) { + sta_ds->timingMeasCap = 0; +#ifdef FEATURE_WLAN_TDLS + session_entry->tdls_prohibited = false; + session_entry->tdls_chan_swit_prohibited = false; +#endif + lim_log(mac_ctx, LOG1, FL("ExtCap not present")); + return; + } + + ext_cap = (struct s_ext_cap *)assoc_rsp->ExtCap.bytes; + lim_set_stads_rtt_cap(sta_ds, ext_cap, mac_ctx); +#ifdef FEATURE_WLAN_TDLS + session_entry->tdls_prohibited = ext_cap->tdls_prohibited; + session_entry->tdls_chan_swit_prohibited = + ext_cap->tdls_chan_swit_prohibited; + lim_log(mac_ctx, LOG1, + FL("ExtCap: tdls_prohibited:%d, tdls_chan_swit_prohibited: %d"), + ext_cap->tdls_prohibited, + ext_cap->tdls_chan_swit_prohibited); +#endif +} + +/** + * lim_stop_reassoc_retry_timer() - Cleanup after reassoc response is received + * @mac_ctx: Global MAC context + * + * Stop the reassoc retry timer and release the stored reassoc request. + * + * Return: None + */ +static void lim_stop_reassoc_retry_timer(tpAniSirGlobal mac_ctx) +{ + mac_ctx->lim.reAssocRetryAttempt = 0; + if ((NULL != mac_ctx->lim.pSessionEntry) + && (NULL != + mac_ctx->lim.pSessionEntry->pLimMlmReassocRetryReq)) { + qdf_mem_free( + mac_ctx->lim.pSessionEntry->pLimMlmReassocRetryReq); + mac_ctx->lim.pSessionEntry->pLimMlmReassocRetryReq = NULL; + } + lim_deactivate_and_change_timer(mac_ctx, eLIM_REASSOC_FAIL_TIMER); +} + +/** + * lim_process_assoc_rsp_frame() - Processes assoc response + * @mac_ctx: Pointer to Global MAC structure + * @rx_packet_info - A pointer to Rx packet info structure + * @sub_type - Indicates whether it is Association Response (=0) or + * Reassociation Response (=1) frame + * + * This function is called by limProcessMessageQueue() upon + * Re/Association Response frame reception. + * + * Return: None + */ + +void +lim_process_assoc_rsp_frame(tpAniSirGlobal mac_ctx, + uint8_t *rx_pkt_info, uint8_t subtype, tpPESession session_entry) +{ + uint8_t *body; + uint16_t caps, ie_len; + uint32_t frame_len; + tSirMacAddr current_bssid; + tpSirMacMgmtHdr hdr = NULL; + tSirMacCapabilityInfo mac_capab; + tpDphHashNode sta_ds; + tpSirAssocRsp assoc_rsp; + tLimMlmAssocCnf assoc_cnf; + tSchBeaconStruct *beacon; +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + uint8_t sme_sessionid = 0; + tCsrRoamSession *roam_session; +#endif + + /* Initialize status code to success. */ + if (lim_is_roam_synch_in_progress(session_entry)) + hdr = (tpSirMacMgmtHdr) mac_ctx->roam.pReassocResp; + else + hdr = WMA_GET_RX_MAC_HEADER(rx_pkt_info); +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + sme_sessionid = session_entry->smeSessionId; +#endif + assoc_cnf.resultCode = eSIR_SME_SUCCESS; + /* Update PE session Id */ + assoc_cnf.sessionId = session_entry->peSessionId; + if (hdr == NULL) { + lim_log(mac_ctx, LOGE, + FL("LFR3: Reassoc response packet header is NULL")); + return; + } + + lim_log(mac_ctx, LOG1, + FL("received Re/Assoc(%d) resp on sessionid: %d systemrole: %d" + "and mlmstate: %d RSSI %d from " MAC_ADDRESS_STR), subtype, + session_entry->peSessionId, GET_LIM_SYSTEM_ROLE(session_entry), + session_entry->limMlmState, + (uint) abs((int8_t) WMA_GET_RX_RSSI_NORMALIZED(rx_pkt_info)), + MAC_ADDR_ARRAY(hdr->sa)); + + beacon = qdf_mem_malloc(sizeof(tSchBeaconStruct)); + if (NULL == beacon) { + lim_log(mac_ctx, LOGE, FL("Unable to allocate memory")); + return; + } + + if (LIM_IS_AP_ROLE(session_entry)) { + /* + * Should not have received Re/Association + * Response frame on AP. Log error + */ + lim_log(mac_ctx, LOGE, + FL("Should not recieved Re/Assoc Response in role %d "), + GET_LIM_SYSTEM_ROLE(session_entry)); + qdf_mem_free(beacon); + return; + } + if (lim_is_roam_synch_in_progress(session_entry)) { + hdr = (tpSirMacMgmtHdr) mac_ctx->roam.pReassocResp; + frame_len = mac_ctx->roam.reassocRespLen - SIR_MAC_HDR_LEN_3A; + } else { + hdr = WMA_GET_RX_MAC_HEADER(rx_pkt_info); + frame_len = WMA_GET_RX_PAYLOAD_LEN(rx_pkt_info); + } + if (((subtype == LIM_ASSOC) && + (session_entry->limMlmState != eLIM_MLM_WT_ASSOC_RSP_STATE)) || + ((subtype == LIM_REASSOC) && + !lim_is_roam_synch_in_progress(session_entry) && + ((session_entry->limMlmState != eLIM_MLM_WT_REASSOC_RSP_STATE) + && (session_entry->limMlmState != + eLIM_MLM_WT_FT_REASSOC_RSP_STATE) + ))) { + /* Received unexpected Re/Association Response frame */ + + lim_log(mac_ctx, LOG1, + FL("Recieved Re/Assoc rsp in unexpected " + "state %d on session=%d"), + session_entry->limMlmState, session_entry->peSessionId); + if (!hdr->fc.retry) { + if (!(mac_ctx->lim.retry_packet_cnt & 0xf)) { + lim_log(mac_ctx, LOGE, + FL("recvd Re/Assoc rsp:not a retry frame")); + lim_print_mlm_state(mac_ctx, LOGE, + session_entry->limMlmState); + } else { + mac_ctx->lim.retry_packet_cnt++; + } + } + qdf_mem_free(beacon); + return; + } + sir_copy_mac_addr(current_bssid, session_entry->bssId); + if (subtype == LIM_ASSOC) { + if (qdf_mem_cmp + (hdr->sa, current_bssid, sizeof(tSirMacAddr))) { + /* + * Received Association Response frame from an entity + * other than one to which request was initiated. + * Ignore this and wait until Assoc Failure Timeout + */ + lim_log(mac_ctx, LOGW, + FL("received AssocRsp from unexpected peer " + MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(hdr->sa)); + qdf_mem_free(beacon); + return; + } + } else { + if (qdf_mem_cmp + (hdr->sa, session_entry->limReAssocbssId, + sizeof(tSirMacAddr))) { + /* + * Received Reassociation Response frame from an entity + * other than one to which request was initiated. + * Ignore this and wait until Reassoc Failure Timeout. + */ + lim_log(mac_ctx, LOGW, + FL("received ReassocRsp from unexpected peer " + MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(hdr->sa)); + qdf_mem_free(beacon); + return; + } + } + + assoc_rsp = qdf_mem_malloc(sizeof(*assoc_rsp)); + if (NULL == assoc_rsp) { + lim_log(mac_ctx, LOGP, + FL("Allocate Memory failed in AssocRsp")); + qdf_mem_free(beacon); + return; + } + /* Get pointer to Re/Association Response frame body */ + if (lim_is_roam_synch_in_progress(session_entry)) + body = mac_ctx->roam.pReassocResp + SIR_MAC_HDR_LEN_3A; + else + body = WMA_GET_RX_MPDU_DATA(rx_pkt_info); + /* parse Re/Association Response frame. */ + if (sir_convert_assoc_resp_frame2_struct(mac_ctx, body, + frame_len, assoc_rsp) == eSIR_FAILURE) { + qdf_mem_free(assoc_rsp); + lim_log(mac_ctx, LOGE, + FL("Parse error Assoc resp subtype %d," "length=%d"), + frame_len, subtype); + qdf_mem_free(beacon); + return; + } + + if (!assoc_rsp->suppRatesPresent) { + lim_log(mac_ctx, LOGE, + FL("assoc response does not have supported rate set")); + qdf_mem_copy(&assoc_rsp->supportedRates, + &session_entry->rateSet, + sizeof(tSirMacRateSet)); + } + + assoc_cnf.protStatusCode = assoc_rsp->statusCode; + if (session_entry->assocRsp != NULL) { + lim_log(mac_ctx, LOGW, + FL("session_entry->assocRsp is not NULL freeing it " + "and setting NULL")); + qdf_mem_free(session_entry->assocRsp); + session_entry->assocRsp = NULL; + session_entry->assocRspLen = 0; + } + + session_entry->assocRsp = qdf_mem_malloc(frame_len); + if (NULL == session_entry->assocRsp) { + lim_log(mac_ctx, LOGE, + FL("Unable to allocate memory for assoc res,len=%d"), + frame_len); + } else { + /* + * Store the Assoc response. This is sent + * to csr/hdd in join cnf response. + */ + qdf_mem_copy(session_entry->assocRsp, body, frame_len); + session_entry->assocRspLen = frame_len; + } + + lim_update_ric_data(mac_ctx, session_entry, assoc_rsp); + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + roam_session = + &mac_ctx->roam.roamSession[sme_sessionid]; + if (assoc_rsp->FTInfo.R0KH_ID.present) { + roam_session->ftSmeContext.r0kh_id_len = + assoc_rsp->FTInfo.R0KH_ID.num_PMK_R0_ID; + qdf_mem_copy(roam_session->ftSmeContext.r0kh_id, + assoc_rsp->FTInfo.R0KH_ID.PMK_R0_ID, + roam_session->ftSmeContext.r0kh_id_len); + } else { + roam_session->ftSmeContext.r0kh_id_len = 0; + qdf_mem_zero(roam_session->ftSmeContext.r0kh_id, + SIR_ROAM_R0KH_ID_MAX_LEN); + } +#endif + +#ifdef FEATURE_WLAN_ESE + lim_update_ese_tspec(mac_ctx, session_entry, assoc_rsp); +#endif + + if (assoc_rsp->capabilityInfo.ibss) { + /* + * Received Re/Association Response from peer + * with IBSS capability set. + * Ignore the frame and wait until Re/assoc + * failure timeout. + */ + lim_log(mac_ctx, LOGE, + FL("received Re/AssocRsp frame with IBSS capability")); + qdf_mem_free(assoc_rsp); + qdf_mem_free(beacon); + return; + } + + if (cfg_get_capability_info(mac_ctx, &caps, session_entry) + != eSIR_SUCCESS) { + qdf_mem_free(assoc_rsp); + qdf_mem_free(beacon); + lim_log(mac_ctx, LOGP, FL("could not retrieve Capabilities ")); + return; + } + lim_copy_u16((uint8_t *) &mac_capab, caps); + + /* Stop Association failure timer */ + if (subtype == LIM_ASSOC) + lim_deactivate_and_change_timer(mac_ctx, eLIM_ASSOC_FAIL_TIMER); + else + lim_stop_reassoc_retry_timer(mac_ctx); + + if (assoc_rsp->statusCode != eSIR_MAC_SUCCESS_STATUS +#ifdef WLAN_FEATURE_11W + && (!session_entry->limRmfEnabled || + assoc_rsp->statusCode != eSIR_MAC_TRY_AGAIN_LATER) +#endif + ) { + /* + *Re/Association response was received + * either with failure code. + */ + lim_log(mac_ctx, LOGE, + FL("received Re/AssocRsp frame failure code %d"), + assoc_rsp->statusCode); + /* + * Need to update 'association failure' error counter + * along with STATUS CODE + * Return Assoc confirm to SME with received failure code + */ + assoc_cnf.resultCode = eSIR_SME_ASSOC_REFUSED; + /* Delete Pre-auth context for the associated BSS */ + if (lim_search_pre_auth_list(mac_ctx, hdr->sa)) + lim_delete_pre_auth_node(mac_ctx, hdr->sa); + goto assocReject; + } else if ((assoc_rsp->aid & 0x3FFF) > 2007) { + /* + * Re/Association response was received + * with invalid AID value + */ + lim_log(mac_ctx, LOGE, FL("received Re/AssocRsp frame with" + "invalid aid %X"), assoc_rsp->aid); + assoc_cnf.resultCode = eSIR_SME_INVALID_ASSOC_RSP_RXED; + assoc_cnf.protStatusCode = eSIR_MAC_UNSPEC_FAILURE_STATUS; + /* Send advisory Disassociation frame to AP */ + lim_send_disassoc_mgmt_frame(mac_ctx, + eSIR_MAC_UNSPEC_FAILURE_REASON, + hdr->sa, session_entry, false); + goto assocReject; + } + /* + * Association Response received with success code + * Set the link state to POSTASSOC now that we have received + * assoc/reassoc response + * NOTE: for BTAMP case, it is being handled in + * lim_process_mlm_assoc_req + */ +#ifdef WLAN_FEATURE_11W + if (session_entry->limRmfEnabled && + assoc_rsp->statusCode == eSIR_MAC_TRY_AGAIN_LATER) { + if (assoc_rsp->TimeoutInterval.present && + (assoc_rsp->TimeoutInterval.timeoutType == + SIR_MAC_TI_TYPE_ASSOC_COMEBACK)) { + uint16_t timeout_value = + assoc_rsp->TimeoutInterval.timeoutValue; + if (timeout_value < 10) { + /* + * if this value is less than 10 then our timer + * will fail to start and due to this we will + * never re-attempt. Better modify the timer + * value here. + */ + timeout_value = 10; + } + lim_log(mac_ctx, LOG1, + FL("ASSOC res with eSIR_MAC_TRY_AGAIN_LATER " + " recvd.Starting timer to wait timeout=%d."), + timeout_value); + if (QDF_STATUS_SUCCESS != + qdf_mc_timer_start( + &session_entry->pmfComebackTimer, + timeout_value)) { + lim_log(mac_ctx, LOGE, + FL("Failed to start comeback timer.")); + + assoc_cnf.resultCode = eSIR_SME_ASSOC_REFUSED; + assoc_cnf.protStatusCode = + eSIR_MAC_UNSPEC_FAILURE_STATUS; + + /* + * Delete Pre-auth context for the + * associated BSS + */ + if (lim_search_pre_auth_list(mac_ctx, hdr->sa)) + lim_delete_pre_auth_node(mac_ctx, + hdr->sa); + + goto assocReject; + } + } else { + lim_log(mac_ctx, LOGW, + FL("ASSOC resp with try again event recvd, but try again time interval IE is wrong")); + + assoc_cnf.resultCode = eSIR_SME_ASSOC_REFUSED; + assoc_cnf.protStatusCode = + eSIR_MAC_UNSPEC_FAILURE_STATUS; + + /* Delete Pre-auth context for the associated BSS */ + if (lim_search_pre_auth_list(mac_ctx, hdr->sa)) + lim_delete_pre_auth_node(mac_ctx, hdr->sa); + + goto assocReject; + } + qdf_mem_free(beacon); + qdf_mem_free(assoc_rsp); + return; + } +#endif + if (!lim_is_roam_synch_in_progress(session_entry)) { + if (lim_set_link_state + (mac_ctx, eSIR_LINK_POSTASSOC_STATE, + session_entry->bssId, + session_entry->selfMacAddr, NULL, + NULL) != eSIR_SUCCESS) { + lim_log(mac_ctx, LOGE, + FL("Set link state to POSTASSOC failed")); + qdf_mem_free(beacon); + qdf_mem_free(assoc_rsp); + return; + } + } + + lim_diag_event_report(mac_ctx, WLAN_PE_DIAG_ROAM_ASSOC_COMP_EVENT, + session_entry, assoc_rsp->statusCode ? eSIR_FAILURE : + eSIR_SUCCESS, assoc_rsp->statusCode); + + if (assoc_rsp->QosMapSet.present) + qdf_mem_copy(&session_entry->QosMapSet, + &assoc_rsp->QosMapSet, sizeof(tSirQosMapSet)); + else + qdf_mem_zero(&session_entry->QosMapSet, sizeof(tSirQosMapSet)); + + if (assoc_rsp->obss_scanparams.present) + lim_update_obss_scanparams(session_entry, + &assoc_rsp->obss_scanparams); + + if (subtype == LIM_REASSOC) { + lim_log + (mac_ctx, LOG1, FL("Successfully Reassociated with BSS")); +#ifdef FEATURE_WLAN_ESE + if (assoc_rsp->tsmPresent) + lim_update_ese_tsm(mac_ctx, session_entry, assoc_rsp); +#endif + if (session_entry->pLimMlmJoinReq) { + qdf_mem_free(session_entry->pLimMlmJoinReq); + session_entry->pLimMlmJoinReq = NULL; + } + + session_entry->limAssocResponseData = (void *)assoc_rsp; + /* + * Store the ReAssocRsp Frame in DphTable + * to be used during processing DelSta and + * DelBss to send AddBss again + */ + sta_ds = + dph_get_hash_entry(mac_ctx, DPH_STA_HASH_INDEX_PEER, + &session_entry->dph.dphHashTable); + + if (!sta_ds) { + lim_log(mac_ctx, LOGE, + FL("could not get hash entry at DPH for")); + lim_print_mac_addr(mac_ctx, hdr->sa, LOGE); + assoc_cnf.resultCode = + eSIR_SME_INVALID_ASSOC_RSP_RXED; + assoc_cnf.protStatusCode = + eSIR_MAC_UNSPEC_FAILURE_STATUS; + + /* Send advisory Disassociation frame to AP */ + lim_send_disassoc_mgmt_frame(mac_ctx, + eSIR_MAC_UNSPEC_FAILURE_REASON, hdr->sa, + session_entry, false); + goto assocReject; + } + if ((session_entry->limMlmState == + eLIM_MLM_WT_FT_REASSOC_RSP_STATE) || + lim_is_roam_synch_in_progress(session_entry)) { + lim_log(mac_ctx, LOG1, FL("Sending self sta")); + lim_update_assoc_sta_datas(mac_ctx, sta_ds, assoc_rsp, + session_entry); + lim_update_stads_ext_cap(mac_ctx, session_entry, + assoc_rsp, sta_ds); + /* Store assigned AID for TIM processing */ + session_entry->limAID = assoc_rsp->aid & 0x3FFF; + /* Downgrade the EDCA parameters if needed */ + lim_set_active_edca_params(mac_ctx, + session_entry->gLimEdcaParams, + session_entry); + /* Send the active EDCA parameters to HAL */ + if (!lim_is_roam_synch_in_progress(session_entry)) { + lim_send_edca_params(mac_ctx, + session_entry->gLimEdcaParamsActive, + sta_ds->bssId); + lim_add_ft_sta_self(mac_ctx, + (assoc_rsp->aid & 0x3FFF), + session_entry); + } + qdf_mem_free(beacon); + return; + } + + /* + * If we're re-associating to the same BSS, + * we don't want to invoke delete STA, delete + * BSS, as that would remove the already + * established TSPEC. Just go ahead and re-add + * the BSS, STA with new capability information. + * However, if we're re-associating to a different + * BSS, then follow thru with del STA, del BSS, + * add BSS, add STA. + */ + if (sir_compare_mac_addr(session_entry->bssId, + session_entry->limReAssocbssId)) + lim_handle_add_bss_in_re_assoc_context(mac_ctx, sta_ds, + session_entry); + else { + /* + * reset the uapsd mask settings since + * we're re-associating to new AP + */ + session_entry->gUapsdPerAcDeliveryEnableMask = 0; + session_entry->gUapsdPerAcTriggerEnableMask = 0; + + if (lim_cleanup_rx_path(mac_ctx, sta_ds, session_entry) + != eSIR_SUCCESS) { + lim_log(mac_ctx, LOGE, + FL("Could not cleanup the rx path")); + goto assocReject; + } + } + qdf_mem_free(beacon); + return; + } + lim_log(mac_ctx, LOG1, + FL("Successfully Associated with BSS " MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(hdr->sa)); +#ifdef FEATURE_WLAN_ESE + if (session_entry->eseContext.tsm.tsmInfo.state) + session_entry->eseContext.tsm.tsmMetrics.RoamingCount = 0; +#endif + /* Store assigned AID for TIM processing */ + session_entry->limAID = assoc_rsp->aid & 0x3FFF; + + /* STA entry was created during pre-assoc state. */ + sta_ds = dph_get_hash_entry(mac_ctx, DPH_STA_HASH_INDEX_PEER, + &session_entry->dph.dphHashTable); + if (sta_ds == NULL) { + /* Could not add hash table entry */ + lim_log(mac_ctx, LOGE, FL("could not get hash entry at DPH ")); + lim_print_mac_addr(mac_ctx, hdr->sa, LOGE); + assoc_cnf.resultCode = eSIR_SME_RESOURCES_UNAVAILABLE; + assoc_cnf.protStatusCode = eSIR_SME_SUCCESS; + lim_post_sme_message(mac_ctx, LIM_MLM_ASSOC_CNF, + (uint32_t *) &assoc_cnf); + qdf_mem_free(assoc_rsp); + qdf_mem_free(beacon); + return; + } + /* Delete Pre-auth context for the associated BSS */ + if (lim_search_pre_auth_list(mac_ctx, hdr->sa)) + lim_delete_pre_auth_node(mac_ctx, hdr->sa); + + lim_update_assoc_sta_datas(mac_ctx, sta_ds, assoc_rsp, session_entry); + /* + * Extract the AP capabilities from the beacon that + * was received earlier + */ + ie_len = lim_get_ielen_from_bss_description( + &session_entry->pLimJoinReq->bssDescription); + lim_extract_ap_capabilities(mac_ctx, + (uint8_t *) session_entry->pLimJoinReq->bssDescription.ieFields, + ie_len, + beacon); + + if (beacon->VHTCaps.present) + sta_ds->parsed_ies.vht_caps = beacon->VHTCaps; + if (beacon->HTCaps.present) + sta_ds->parsed_ies.ht_caps = beacon->HTCaps; + if (beacon->hs20vendor_ie.present) + sta_ds->parsed_ies.hs20vendor_ie = beacon->hs20vendor_ie; + if (beacon->HTInfo.present) + sta_ds->parsed_ies.ht_operation = beacon->HTInfo; + if (beacon->VHTOperation.present) + sta_ds->parsed_ies.vht_operation = beacon->VHTOperation; + + if (mac_ctx->lim.gLimProtectionControl != + WNI_CFG_FORCE_POLICY_PROTECTION_DISABLE) + lim_decide_sta_protection_on_assoc(mac_ctx, beacon, + session_entry); + + if (beacon->erpPresent) { + if (beacon->erpIEInfo.barkerPreambleMode) + session_entry->beaconParams.fShortPreamble = false; + else + session_entry->beaconParams.fShortPreamble = true; + } + +#ifdef FEATURE_WLAN_DIAG_SUPPORT + lim_diag_event_report(mac_ctx, WLAN_PE_DIAG_CONNECTED, session_entry, + eSIR_SUCCESS, eSIR_SUCCESS); +#endif + lim_update_stads_ext_cap(mac_ctx, session_entry, assoc_rsp, sta_ds); + /* Update the BSS Entry, this entry was added during preassoc. */ + if (eSIR_SUCCESS == lim_sta_send_add_bss(mac_ctx, assoc_rsp, + beacon, + &session_entry->pLimJoinReq->bssDescription, true, + session_entry)) { + qdf_mem_free(assoc_rsp); + qdf_mem_free(beacon); + return; + } else { + lim_log(mac_ctx, LOGE, FL("could not update the bss entry")); + assoc_cnf.resultCode = eSIR_SME_RESOURCES_UNAVAILABLE; + assoc_cnf.protStatusCode = eSIR_MAC_UNSPEC_FAILURE_STATUS; + } + +assocReject: + if ((subtype == LIM_ASSOC) + || ((subtype == LIM_REASSOC) + && (session_entry->limMlmState == + eLIM_MLM_WT_FT_REASSOC_RSP_STATE))) { + lim_log(mac_ctx, LOGE, FL("Assoc Rejected by the peer. " + "mlmestate: %d sessionid %d Reason: %d MACADDR:" + MAC_ADDRESS_STR), + session_entry->limMlmState, + session_entry->peSessionId, + assoc_cnf.resultCode, MAC_ADDR_ARRAY(hdr->sa)); + session_entry->limMlmState = eLIM_MLM_IDLE_STATE; + MTRACE(mac_trace(mac_ctx, TRACE_CODE_MLM_STATE, + session_entry->peSessionId, + session_entry->limMlmState)); + if (session_entry->pLimMlmJoinReq) { + qdf_mem_free(session_entry->pLimMlmJoinReq); + session_entry->pLimMlmJoinReq = NULL; + } + if (subtype == LIM_ASSOC) { + lim_post_sme_message(mac_ctx, LIM_MLM_ASSOC_CNF, + (uint32_t *) &assoc_cnf); + } else { + assoc_cnf.resultCode = eSIR_SME_FT_REASSOC_FAILURE; + lim_post_sme_message(mac_ctx, LIM_MLM_REASSOC_CNF, + (uint32_t *)&assoc_cnf); + } + } else { + lim_restore_pre_reassoc_state(mac_ctx, + eSIR_SME_REASSOC_REFUSED, + assoc_cnf.protStatusCode, + session_entry); + } + + qdf_mem_free(beacon); + qdf_mem_free(assoc_rsp); + return; +} diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_process_auth_frame.c b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_process_auth_frame.c new file mode 100644 index 0000000000000000000000000000000000000000..43968afe38f1e87a25b82b2cd7798331122a2e35 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_process_auth_frame.c @@ -0,0 +1,1601 @@ +/* + * Copyright (c) 2011-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * + * This file lim_process_auth_frame.cc contains the code + * for processing received Authentication Frame. + * Author: Chandra Modumudi + * Date: 03/11/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + * 05/12/2010 js To support Shared key authentication at AP side + * + */ + +#include "wni_api.h" +#include "wni_cfg.h" +#include "ani_global.h" +#include "cfg_api.h" + +#include "utils_api.h" +#include "lim_utils.h" +#include "lim_assoc_utils.h" +#include "lim_security_utils.h" +#include "lim_ser_des_utils.h" +#include "lim_ft.h" +#include "cds_utils.h" + +/** + * is_auth_valid + * + ***FUNCTION: + * This function is called by lim_process_auth_frame() upon Authentication + * frame reception. + * + ***LOGIC: + * This function is used to test validity of auth frame: + * - AUTH1 and AUTH3 must be received in AP mode + * - AUTH2 and AUTH4 must be received in STA mode + * - AUTH3 and AUTH4 must have challenge text IE, that is,'type' field has been set to + * SIR_MAC_CHALLENGE_TEXT_EID by parser + * - + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param *auth - Pointer to extracted auth frame body + * + * @return 0 or 1 (Valid) + */ + +static inline unsigned int is_auth_valid(tpAniSirGlobal pMac, + tpSirMacAuthFrameBody auth, + tpPESession sessionEntry) +{ + unsigned int valid = 1; + + if (((auth->authTransactionSeqNumber == SIR_MAC_AUTH_FRAME_1) || + (auth->authTransactionSeqNumber == SIR_MAC_AUTH_FRAME_3)) && + (LIM_IS_STA_ROLE(sessionEntry))) + valid = 0; + + if (((auth->authTransactionSeqNumber == SIR_MAC_AUTH_FRAME_2) || + (auth->authTransactionSeqNumber == SIR_MAC_AUTH_FRAME_4)) && + (LIM_IS_AP_ROLE(sessionEntry))) + valid = 0; + + if (((auth->authTransactionSeqNumber == SIR_MAC_AUTH_FRAME_3) || + (auth->authTransactionSeqNumber == SIR_MAC_AUTH_FRAME_4)) && + (auth->type != SIR_MAC_CHALLENGE_TEXT_EID) && + (auth->authAlgoNumber != eSIR_SHARED_KEY)) + valid = 0; + + return valid; +} + +static void lim_process_auth_shared_system_algo(tpAniSirGlobal mac_ctx, + tpSirMacMgmtHdr mac_hdr, + tSirMacAuthFrameBody *rx_auth_frm_body, + tSirMacAuthFrameBody *auth_frame, + uint8_t *challenge_txt_arr, + tpPESession pe_session) +{ + uint32_t val; + uint8_t cfg_privacy_opt_imp, *challenge; + struct tLimPreAuthNode *auth_node; + + lim_log(mac_ctx, LOGW, FL("=======> eSIR_SHARED_KEY ...")); + if (LIM_IS_AP_ROLE(pe_session)) + val = pe_session->privacy; + else if (wlan_cfg_get_int(mac_ctx, + WNI_CFG_PRIVACY_ENABLED, &val) != eSIR_SUCCESS) + lim_log(mac_ctx, LOGP, FL("couldnt retrieve Privacy option")); + cfg_privacy_opt_imp = (uint8_t) val; + if (!cfg_privacy_opt_imp) { + lim_log(mac_ctx, LOGE, + FL("rx Auth frame for unsupported auth algorithm %d " + MAC_ADDRESS_STR), + rx_auth_frm_body->authAlgoNumber, + MAC_ADDR_ARRAY(mac_hdr->sa)); + + /* + * Authenticator does not have WEP + * implemented. + * Reject by sending Authentication frame + * with Auth algorithm not supported status + * code. + */ + auth_frame->authAlgoNumber = rx_auth_frm_body->authAlgoNumber; + auth_frame->authTransactionSeqNumber = + rx_auth_frm_body->authTransactionSeqNumber + 1; + auth_frame->authStatusCode = + eSIR_MAC_AUTH_ALGO_NOT_SUPPORTED_STATUS; + + lim_send_auth_mgmt_frame(mac_ctx, auth_frame, + mac_hdr->sa, LIM_NO_WEP_IN_FC, + pe_session); + return; + } else { + /* Create entry for this STA in pre-auth list */ + auth_node = lim_acquire_free_pre_auth_node(mac_ctx, + &mac_ctx->lim.gLimPreAuthTimerTable); + if (auth_node == NULL) { + lim_log(mac_ctx, LOGW, FL("Max preauth-nodes reached")); + lim_print_mac_addr(mac_ctx, mac_hdr->sa, LOGW); + return; + } + + qdf_mem_copy((uint8_t *) auth_node->peerMacAddr, mac_hdr->sa, + sizeof(tSirMacAddr)); + auth_node->mlmState = eLIM_MLM_WT_AUTH_FRAME3_STATE; + auth_node->authType = + (tAniAuthType) rx_auth_frm_body->authAlgoNumber; + auth_node->fSeen = 0; + auth_node->fTimerStarted = 0; + auth_node->seq_num = ((mac_hdr->seqControl.seqNumHi << 4) | + (mac_hdr->seqControl.seqNumLo)); + auth_node->timestamp = qdf_mc_timer_get_system_ticks(); + lim_add_pre_auth_node(mac_ctx, auth_node); + + lim_log(mac_ctx, LOG1, FL("Alloc new data: %p id %d peer "), + auth_node, auth_node->authNodeIdx); + lim_print_mac_addr(mac_ctx, mac_hdr->sa, LOG1); + /* / Create and activate Auth Response timer */ + if (tx_timer_change_context(&auth_node->timer, + auth_node->authNodeIdx) != TX_SUCCESS) { + /* Could not start Auth response timer. Log error */ + lim_log(mac_ctx, LOGP, + FL("Unable to chg context auth response timer for peer ")); + lim_print_mac_addr(mac_ctx, mac_hdr->sa, LOGP); + + /* + * Send Auth frame with unspecified failure status code. + */ + + auth_frame->authAlgoNumber = + rx_auth_frm_body->authAlgoNumber; + auth_frame->authTransactionSeqNumber = + rx_auth_frm_body->authTransactionSeqNumber + 1; + auth_frame->authStatusCode = + eSIR_MAC_UNSPEC_FAILURE_STATUS; + + lim_send_auth_mgmt_frame(mac_ctx, auth_frame, + mac_hdr->sa, LIM_NO_WEP_IN_FC, + pe_session); + lim_delete_pre_auth_node(mac_ctx, mac_hdr->sa); + return; + } + lim_activate_auth_rsp_timer(mac_ctx, auth_node); + auth_node->fTimerStarted = 1; + /* + * get random bytes and use as challenge text. + * If it fails we already have random stack bytes. + */ + if (!QDF_IS_STATUS_SUCCESS(cds_rand_get_bytes(0, + (uint8_t *) challenge_txt_arr, + SIR_MAC_AUTH_CHALLENGE_LENGTH))) + lim_log(mac_ctx, LOGE, + FL("Challenge text preparation failed")); + challenge = auth_node->challengeText; + qdf_mem_copy(challenge, (uint8_t *)challenge_txt_arr, + sizeof(challenge_txt_arr)); + /* + * Sending Authenticaton frame with challenge. + */ + auth_frame->authAlgoNumber = rx_auth_frm_body->authAlgoNumber; + auth_frame->authTransactionSeqNumber = + rx_auth_frm_body->authTransactionSeqNumber + 1; + auth_frame->authStatusCode = eSIR_MAC_SUCCESS_STATUS; + auth_frame->type = SIR_MAC_CHALLENGE_TEXT_EID; + auth_frame->length = SIR_MAC_AUTH_CHALLENGE_LENGTH; + qdf_mem_copy(auth_frame->challengeText, + auth_node->challengeText, + SIR_MAC_AUTH_CHALLENGE_LENGTH); + lim_send_auth_mgmt_frame(mac_ctx, auth_frame, + mac_hdr->sa, LIM_NO_WEP_IN_FC, + pe_session); + } +} + +static void lim_process_auth_open_system_algo(tpAniSirGlobal mac_ctx, + tpSirMacMgmtHdr mac_hdr, + tSirMacAuthFrameBody *rx_auth_frm_body, + tSirMacAuthFrameBody *auth_frame, + tpPESession pe_session) +{ + struct tLimPreAuthNode *auth_node; + + lim_log(mac_ctx, LOGW, FL("=======> eSIR_OPEN_SYSTEM ...")); + /* Create entry for this STA in pre-auth list */ + auth_node = lim_acquire_free_pre_auth_node(mac_ctx, + &mac_ctx->lim.gLimPreAuthTimerTable); + if (auth_node == NULL) { + lim_log(mac_ctx, LOGW, + FL("Max pre-auth nodes reached ")); + lim_print_mac_addr(mac_ctx, mac_hdr->sa, LOGW); + return; + } + lim_log(mac_ctx, LOG1, FL("Alloc new data: %p peer "), auth_node); + lim_print_mac_addr(mac_ctx, mac_hdr->sa, LOG1); + qdf_mem_copy((uint8_t *) auth_node->peerMacAddr, + mac_hdr->sa, sizeof(tSirMacAddr)); + auth_node->mlmState = eLIM_MLM_AUTHENTICATED_STATE; + auth_node->authType = (tAniAuthType) rx_auth_frm_body->authAlgoNumber; + auth_node->fSeen = 0; + auth_node->fTimerStarted = 0; + auth_node->seq_num = ((mac_hdr->seqControl.seqNumHi << 4) | + (mac_hdr->seqControl.seqNumLo)); + auth_node->timestamp = qdf_mc_timer_get_system_ticks(); + lim_add_pre_auth_node(mac_ctx, auth_node); + /* + * Send Authenticaton frame with Success + * status code. + */ + auth_frame->authAlgoNumber = rx_auth_frm_body->authAlgoNumber; + auth_frame->authTransactionSeqNumber = + rx_auth_frm_body->authTransactionSeqNumber + 1; + auth_frame->authStatusCode = eSIR_MAC_SUCCESS_STATUS; + lim_send_auth_mgmt_frame(mac_ctx, auth_frame, mac_hdr->sa, + LIM_NO_WEP_IN_FC, + pe_session); +} + +static void lim_process_auth_frame_type1(tpAniSirGlobal mac_ctx, + tpSirMacMgmtHdr mac_hdr, + tSirMacAuthFrameBody *rx_auth_frm_body, + uint8_t *rx_pkt_info, uint16_t curr_seq_num, + tSirMacAuthFrameBody *auth_frame, tpPESession pe_session) +{ + tpDphHashNode sta_ds_ptr = NULL; + struct tLimPreAuthNode *auth_node; + uint8_t challenge_txt_arr[SIR_MAC_AUTH_CHALLENGE_LENGTH]; + uint32_t maxnum_preauth; + uint16_t associd = 0; + + /* AuthFrame 1 */ + sta_ds_ptr = dph_lookup_hash_entry(mac_ctx, mac_hdr->sa, + &associd, &pe_session->dph.dphHashTable); + if (sta_ds_ptr) { + tLimMlmDisassocReq *pMlmDisassocReq = NULL; + tLimMlmDeauthReq *pMlmDeauthReq = NULL; + tAniBool isConnected = eSIR_TRUE; + + pMlmDisassocReq = + mac_ctx->lim.limDisassocDeauthCnfReq.pMlmDisassocReq; + if (pMlmDisassocReq && + (!qdf_mem_cmp((uint8_t *) mac_hdr->sa, (uint8_t *) + &pMlmDisassocReq->peer_macaddr.bytes, + QDF_MAC_ADDR_SIZE))) { + lim_log(mac_ctx, LOGE, + FL("TODO:Ack for disassoc frame is pending Issue delsta for " + MAC_ADDRESS_STR), + MAC_ADDR_ARRAY( + pMlmDisassocReq->peer_macaddr.bytes)); + lim_process_disassoc_ack_timeout(mac_ctx); + isConnected = eSIR_FALSE; + } + pMlmDeauthReq = + mac_ctx->lim.limDisassocDeauthCnfReq.pMlmDeauthReq; + if (pMlmDeauthReq && + (!qdf_mem_cmp((uint8_t *) mac_hdr->sa, (uint8_t *) + &pMlmDeauthReq->peer_macaddr.bytes, + QDF_MAC_ADDR_SIZE))) { + lim_log(mac_ctx, LOGE, + FL("TODO:Ack for deauth frame is pending Issue delsta for " + MAC_ADDRESS_STR), + MAC_ADDR_ARRAY( + pMlmDeauthReq->peer_macaddr.bytes)); + lim_process_deauth_ack_timeout(mac_ctx); + isConnected = eSIR_FALSE; + } + + /* + * pStaDS != NULL and isConnected = 1 means the STA is already + * connected, But SAP received the Auth from that station. + * For non PMF connection send Deauth frame as STA will retry + * to connect back. + * + * For PMF connection the AP should not tear down or otherwise + * modify the state of the existing association until the + * SA-Query procedure determines that the original SA is + * invalid. + */ + if (isConnected +#ifdef WLAN_FEATURE_11W + && !sta_ds_ptr->rmfEnabled +#endif + ) { + lim_log(mac_ctx, LOGE, + FL("STA is already connected but received auth frame" + "Send the Deauth and lim Delete Station Context" + "(staId: %d, associd: %d) "), + sta_ds_ptr->staIndex, associd); + lim_send_deauth_mgmt_frame(mac_ctx, + eSIR_MAC_UNSPEC_FAILURE_REASON, + (uint8_t *) mac_hdr->sa, + pe_session, false); + lim_trigger_sta_deletion(mac_ctx, sta_ds_ptr, + pe_session); + return; + } + } + /* Check if there exists pre-auth context for this STA */ + auth_node = lim_search_pre_auth_list(mac_ctx, mac_hdr->sa); + if (auth_node) { + /* Pre-auth context exists for the STA */ + if (!(mac_hdr->fc.retry == 0 || + auth_node->seq_num != curr_seq_num)) { + /* + * This can happen when first authentication frame is + * received but ACK lost at STA side, in this case 2nd + * auth frame is already in transmission queue + */ + lim_log(mac_ctx, LOGW, + FL("STA is initiating Auth after ACK lost")); + return; + } + /* + * STA is initiating brand-new Authentication + * sequence after local Auth Response timeout Or STA + * retrying to transmit First Auth frame due to packet + * drop OTA Delete Pre-auth node and fall through. + */ + if (auth_node->fTimerStarted) + lim_deactivate_and_change_per_sta_id_timer( + mac_ctx, eLIM_AUTH_RSP_TIMER, + auth_node->authNodeIdx); + lim_log(mac_ctx, LOGE, FL("STA is initiating brand-new Auth")); + lim_delete_pre_auth_node(mac_ctx, mac_hdr->sa); + /* + * SAP Mode:Disassociate the station and + * delete its entry if we have its entry + * already and received "auth" from the + * same station. + * SAP dphHashTable.size = 8 + */ + for (associd = 0; associd < pe_session->dph.dphHashTable.size; + associd++) { + sta_ds_ptr = dph_get_hash_entry(mac_ctx, associd, + &pe_session->dph.dphHashTable); + if (NULL == sta_ds_ptr) + continue; + if (sta_ds_ptr->valid && (!qdf_mem_cmp( + (uint8_t *)&sta_ds_ptr->staAddr, + (uint8_t *) &(mac_hdr->sa), + (uint8_t) sizeof(tSirMacAddr)))) + break; + sta_ds_ptr = NULL; + } + + if (NULL != sta_ds_ptr +#ifdef WLAN_FEATURE_11W + && !sta_ds_ptr->rmfEnabled +#endif + ) { + lim_log(mac_ctx, LOGE, + FL("lim Delete Station Context (staId: %d, associd: %d) "), + sta_ds_ptr->staIndex, associd); + lim_send_deauth_mgmt_frame(mac_ctx, + eSIR_MAC_UNSPEC_FAILURE_REASON, + (uint8_t *)auth_node->peerMacAddr, + pe_session, false); + lim_trigger_sta_deletion(mac_ctx, sta_ds_ptr, + pe_session); + return; + } + } + if (wlan_cfg_get_int(mac_ctx, WNI_CFG_MAX_NUM_PRE_AUTH, + (uint32_t *) &maxnum_preauth) != eSIR_SUCCESS) + lim_log(mac_ctx, LOGP, FL("could not retrieve MaxNumPreAuth")); + + if (mac_ctx->lim.gLimNumPreAuthContexts == maxnum_preauth && + !lim_delete_open_auth_pre_auth_node(mac_ctx)) { + lim_log(mac_ctx, LOGE, FL("Max no of preauth context reached")); + /* + * Maximum number of pre-auth contexts reached. + * Send Authentication frame with unspecified failure + */ + auth_frame->authAlgoNumber = rx_auth_frm_body->authAlgoNumber; + auth_frame->authTransactionSeqNumber = + rx_auth_frm_body->authTransactionSeqNumber + 1; + auth_frame->authStatusCode = + eSIR_MAC_UNSPEC_FAILURE_STATUS; + + lim_send_auth_mgmt_frame(mac_ctx, auth_frame, + mac_hdr->sa, LIM_NO_WEP_IN_FC, + pe_session); + return; + } + /* No Pre-auth context exists for the STA. */ + if (lim_is_auth_algo_supported(mac_ctx, + (tAniAuthType) rx_auth_frm_body->authAlgoNumber, + pe_session)) { + + if (lim_get_session_by_macaddr(mac_ctx, mac_hdr->sa)) { + + auth_frame->authAlgoNumber = + rx_auth_frm_body->authAlgoNumber; + auth_frame->authTransactionSeqNumber = + rx_auth_frm_body->authTransactionSeqNumber + 1; + auth_frame->authStatusCode = + eSIR_MAC_WME_INVALID_PARAMS_STATUS; + + lim_send_auth_mgmt_frame(mac_ctx, auth_frame, + mac_hdr->sa, LIM_NO_WEP_IN_FC, + pe_session); + return; + } + + switch (rx_auth_frm_body->authAlgoNumber) { + case eSIR_OPEN_SYSTEM: + lim_process_auth_open_system_algo(mac_ctx, mac_hdr, + rx_auth_frm_body, auth_frame, pe_session); + break; + + case eSIR_SHARED_KEY: + lim_process_auth_shared_system_algo(mac_ctx, mac_hdr, + rx_auth_frm_body, auth_frame, + challenge_txt_arr, pe_session); + break; + default: + lim_log(mac_ctx, LOGE, + FL("rx Auth frm for unsupported auth algo %d " + MAC_ADDRESS_STR), + rx_auth_frm_body->authAlgoNumber, + MAC_ADDR_ARRAY(mac_hdr->sa)); + + /* + * Responding party does not support the + * authentication algorithm requested by + * sending party. + * Reject by sending Authentication frame + * with auth algorithm not supported status code + */ + auth_frame->authAlgoNumber = + rx_auth_frm_body->authAlgoNumber; + auth_frame->authTransactionSeqNumber = + rx_auth_frm_body->authTransactionSeqNumber + 1; + auth_frame->authStatusCode = + eSIR_MAC_AUTH_ALGO_NOT_SUPPORTED_STATUS; + lim_send_auth_mgmt_frame(mac_ctx, auth_frame, + mac_hdr->sa, LIM_NO_WEP_IN_FC, + pe_session); + return; + } + } else { + lim_log(mac_ctx, LOGE, + FL("received Authentication frame for unsupported auth algorithm %d " + MAC_ADDRESS_STR), + rx_auth_frm_body->authAlgoNumber, + MAC_ADDR_ARRAY(mac_hdr->sa)); + + /* + * Responding party does not support the + * authentication algorithm requested by sending party. + * Reject Authentication with StatusCode=13. + */ + auth_frame->authAlgoNumber = rx_auth_frm_body->authAlgoNumber; + auth_frame->authTransactionSeqNumber = + rx_auth_frm_body->authTransactionSeqNumber + 1; + auth_frame->authStatusCode = + eSIR_MAC_AUTH_ALGO_NOT_SUPPORTED_STATUS; + + lim_send_auth_mgmt_frame(mac_ctx, auth_frame, + mac_hdr->sa, + LIM_NO_WEP_IN_FC, + pe_session); + return; + } +} + +static void lim_process_auth_frame_type2(tpAniSirGlobal mac_ctx, + tpSirMacMgmtHdr mac_hdr, + tSirMacAuthFrameBody *rx_auth_frm_body, + tSirMacAuthFrameBody *auth_frame, + uint8_t *plainbody, + uint8_t *body_ptr, uint16_t frame_len, + tpPESession pe_session) +{ + uint8_t key_id, cfg_privacy_opt_imp; + uint32_t val, key_length = 8; + uint8_t defaultkey[SIR_MAC_KEY_LENGTH]; + struct tLimPreAuthNode *auth_node; + uint8_t encr_auth_frame[LIM_ENCR_AUTH_BODY_LEN]; + + /* AuthFrame 2 */ + if (pe_session->limMlmState != eLIM_MLM_WT_AUTH_FRAME2_STATE) { + /** + * Check if a Reassociation is in progress and this is a + * Pre-Auth frame + */ + if (LIM_IS_STA_ROLE(pe_session) && + (pe_session->limSmeState == eLIM_SME_WT_REASSOC_STATE) && + (rx_auth_frm_body->authStatusCode == + eSIR_MAC_SUCCESS_STATUS) && + (pe_session->ftPEContext.pFTPreAuthReq != NULL) && + (!qdf_mem_cmp( + pe_session->ftPEContext.pFTPreAuthReq->preAuthbssId, + mac_hdr->sa, sizeof(tSirMacAddr)))) { + + /* Update the FTIEs in the saved auth response */ + lim_log(mac_ctx, LOGW, + FL("rx PreAuth frm2 in smestate %d from %pM"), + pe_session->limSmeState, mac_hdr->sa); + pe_session->ftPEContext.saved_auth_rsp_length = 0; + + if ((body_ptr != NULL) && (frame_len < MAX_FTIE_SIZE)) { + qdf_mem_copy( + pe_session->ftPEContext.saved_auth_rsp, + body_ptr, frame_len); + pe_session->ftPEContext.saved_auth_rsp_length = + frame_len; + } + } else { + /* + * Received Auth frame2 in an unexpected state. + * Log error and ignore the frame. + */ + lim_log(mac_ctx, LOG1, + FL("rx Auth frm2 from peer in state %d, addr "), + pe_session->limMlmState); + lim_print_mac_addr(mac_ctx, mac_hdr->sa, LOG1); + } + return; + } + + if (qdf_mem_cmp((uint8_t *) mac_hdr->sa, + (uint8_t *) &mac_ctx->lim.gpLimMlmAuthReq->peerMacAddr, + sizeof(tSirMacAddr))) { + /* + * Received Authentication frame from an entity + * other than one request was initiated. + * Wait until Authentication Failure Timeout. + */ + + lim_log(mac_ctx, LOGW, + FL("received Auth frame2 from unexpected peer " + MAC_ADDRESS_STR), MAC_ADDR_ARRAY(mac_hdr->sa)); + return; + } + + if (rx_auth_frm_body->authStatusCode == + eSIR_MAC_AUTH_ALGO_NOT_SUPPORTED_STATUS) { + /* + * Interoperability workaround: Linksys WAP4400N is returning + * wrong authType in OpenAuth response in case of + * SharedKey AP configuration. Pretend we don't see that, + * so upper layer can fallback to SharedKey authType, + * and successfully connect to the AP. + */ + if (rx_auth_frm_body->authAlgoNumber != + mac_ctx->lim.gpLimMlmAuthReq->authType) { + rx_auth_frm_body->authAlgoNumber = + mac_ctx->lim.gpLimMlmAuthReq->authType; + } + } + + if (rx_auth_frm_body->authAlgoNumber != + mac_ctx->lim.gpLimMlmAuthReq->authType) { + /* + * Received Authentication frame with an auth + * algorithm other than one requested. + * Wait until Authentication Failure Timeout. + */ + + lim_log(mac_ctx, LOGW, + FL("rx Auth frame2 for unexpected auth algo number %d " + MAC_ADDRESS_STR), + rx_auth_frm_body->authAlgoNumber, + MAC_ADDR_ARRAY(mac_hdr->sa)); + return; + } + + if (rx_auth_frm_body->authStatusCode != eSIR_MAC_SUCCESS_STATUS) { + /* + * Authentication failure. + * Return Auth confirm with received failure code to SME + */ + lim_log(mac_ctx, LOGE, + FL("rx Auth frame from peer with failure code %d " + MAC_ADDRESS_STR), + rx_auth_frm_body->authStatusCode, + MAC_ADDR_ARRAY(mac_hdr->sa)); + lim_restore_from_auth_state(mac_ctx, eSIR_SME_AUTH_REFUSED, + rx_auth_frm_body->authStatusCode, + pe_session); + return; + } + + if (rx_auth_frm_body->authAlgoNumber == eSIR_OPEN_SYSTEM) { + pe_session->limCurrentAuthType = eSIR_OPEN_SYSTEM; + auth_node = lim_acquire_free_pre_auth_node(mac_ctx, + &mac_ctx->lim.gLimPreAuthTimerTable); + if (auth_node == NULL) { + lim_log(mac_ctx, LOGW, + FL("Max pre-auth nodes reached ")); + lim_print_mac_addr(mac_ctx, mac_hdr->sa, LOGW); + return; + } + + lim_log(mac_ctx, LOG1, + FL("Alloc new data: %p peer"), auth_node); + lim_print_mac_addr(mac_ctx, mac_hdr->sa, LOG1); + qdf_mem_copy((uint8_t *) auth_node->peerMacAddr, + mac_ctx->lim.gpLimMlmAuthReq->peerMacAddr, + sizeof(tSirMacAddr)); + auth_node->fTimerStarted = 0; + auth_node->authType = + mac_ctx->lim.gpLimMlmAuthReq->authType; + auth_node->seq_num = + ((mac_hdr->seqControl.seqNumHi << 4) | + (mac_hdr->seqControl.seqNumLo)); + auth_node->timestamp = qdf_mc_timer_get_system_ticks(); + lim_add_pre_auth_node(mac_ctx, auth_node); + lim_restore_from_auth_state(mac_ctx, eSIR_SME_SUCCESS, + rx_auth_frm_body->authStatusCode, pe_session); + } else { + /* Shared key authentication */ + if (LIM_IS_AP_ROLE(pe_session)) + val = pe_session->privacy; + else if (wlan_cfg_get_int(mac_ctx, + WNI_CFG_PRIVACY_ENABLED, + &val) != eSIR_SUCCESS) + lim_log(mac_ctx, LOGP, + FL("couldnt retrieve Privacy option")); + cfg_privacy_opt_imp = (uint8_t) val; + if (!cfg_privacy_opt_imp) { + /* + * Requesting STA does not have WEP implemented. + * Reject with unsupported authentication algo + * Status code & wait until auth failure timeout + */ + + lim_log(mac_ctx, LOGE, + FL("rx Auth frm from peer for unsupported auth algo %d " + MAC_ADDRESS_STR), + rx_auth_frm_body->authAlgoNumber, + MAC_ADDR_ARRAY(mac_hdr->sa)); + + auth_frame->authAlgoNumber = + rx_auth_frm_body->authAlgoNumber; + auth_frame->authTransactionSeqNumber = + rx_auth_frm_body->authTransactionSeqNumber + 1; + auth_frame->authStatusCode = + eSIR_MAC_AUTH_ALGO_NOT_SUPPORTED_STATUS; + lim_send_auth_mgmt_frame(mac_ctx, auth_frame, + mac_hdr->sa, LIM_NO_WEP_IN_FC, + pe_session); + return; + } + if (rx_auth_frm_body->type != SIR_MAC_CHALLENGE_TEXT_EID) { + lim_log(mac_ctx, LOGE, + FL("rx auth frm with invalid challenge txtie")); + return; + } + if (wlan_cfg_get_int(mac_ctx, WNI_CFG_WEP_DEFAULT_KEYID, + &val) != eSIR_SUCCESS) + lim_log(mac_ctx, LOGP, + FL("could not retrieve Default key_id")); + key_id = (uint8_t) val; + val = SIR_MAC_KEY_LENGTH; + if (LIM_IS_AP_ROLE(pe_session)) { + tpSirKeys key_ptr = + &pe_session->WEPKeyMaterial[key_id].key[0]; + qdf_mem_copy(defaultkey, key_ptr->key, + key_ptr->keyLength); + } else if (wlan_cfg_get_str(mac_ctx, + (uint16_t)(WNI_CFG_WEP_DEFAULT_KEY_1 + key_id), + defaultkey, &val) != eSIR_SUCCESS) { + /* Couldnt get Default key from CFG. */ + lim_log(mac_ctx, LOGP, + FL("cant retrieve Defaultkey")); + auth_frame->authAlgoNumber = + rx_auth_frm_body->authAlgoNumber; + auth_frame->authTransactionSeqNumber = + rx_auth_frm_body->authTransactionSeqNumber + 1; + auth_frame->authStatusCode = + eSIR_MAC_CHALLENGE_FAILURE_STATUS; + lim_send_auth_mgmt_frame(mac_ctx, + auth_frame, mac_hdr->sa, + LIM_NO_WEP_IN_FC, + pe_session); + lim_restore_from_auth_state(mac_ctx, + eSIR_SME_INVALID_WEP_DEFAULT_KEY, + eSIR_MAC_UNSPEC_FAILURE_REASON, + pe_session); + return; + } + key_length = val; + ((tpSirMacAuthFrameBody)plainbody)->authAlgoNumber = + sir_swap_u16if_needed(rx_auth_frm_body->authAlgoNumber); + ((tpSirMacAuthFrameBody)plainbody)->authTransactionSeqNumber = + sir_swap_u16if_needed((uint16_t)( + rx_auth_frm_body->authTransactionSeqNumber + + 1)); + ((tpSirMacAuthFrameBody)plainbody)->authStatusCode = + eSIR_MAC_SUCCESS_STATUS; + ((tpSirMacAuthFrameBody)plainbody)->type = + SIR_MAC_CHALLENGE_TEXT_EID; + ((tpSirMacAuthFrameBody)plainbody)->length = + SIR_MAC_AUTH_CHALLENGE_LENGTH; + qdf_mem_copy((uint8_t *) ( + (tpSirMacAuthFrameBody)plainbody)->challengeText, + rx_auth_frm_body->challengeText, + SIR_MAC_AUTH_CHALLENGE_LENGTH); + lim_encrypt_auth_frame(mac_ctx, key_id, + defaultkey, plainbody, + encr_auth_frame, key_length); + pe_session->limMlmState = eLIM_MLM_WT_AUTH_FRAME4_STATE; + MTRACE(mac_trace(mac_ctx, TRACE_CODE_MLM_STATE, + pe_session->peSessionId, + pe_session->limMlmState)); + lim_send_auth_mgmt_frame(mac_ctx, + (tpSirMacAuthFrameBody)encr_auth_frame, + mac_hdr->sa, LIM_WEP_IN_FC, + pe_session); + + return; + } +} + +static void lim_process_auth_frame_type3(tpAniSirGlobal mac_ctx, + tpSirMacMgmtHdr mac_hdr, + tSirMacAuthFrameBody *rx_auth_frm_body, + tSirMacAuthFrameBody *auth_frame, + tpPESession pe_session) +{ + struct tLimPreAuthNode *auth_node; + + /* AuthFrame 3 */ + if (rx_auth_frm_body->authAlgoNumber != eSIR_SHARED_KEY) { + lim_log(mac_ctx, LOGE, + FL("rx Auth frame3 from peer with auth algo number %d " + MAC_ADDRESS_STR), + rx_auth_frm_body->authAlgoNumber, + MAC_ADDR_ARRAY(mac_hdr->sa)); + /* + * Received Authentication frame3 with algorithm other than + * Shared Key authentication type. Reject with Auth frame4 + * with 'out of sequence' status code. + */ + auth_frame->authAlgoNumber = eSIR_SHARED_KEY; + auth_frame->authTransactionSeqNumber = SIR_MAC_AUTH_FRAME_4; + auth_frame->authStatusCode = + eSIR_MAC_AUTH_FRAME_OUT_OF_SEQ_STATUS; + lim_send_auth_mgmt_frame(mac_ctx, auth_frame, + mac_hdr->sa, LIM_NO_WEP_IN_FC, + pe_session); + return; + } + + if (LIM_IS_AP_ROLE(pe_session) || + LIM_IS_IBSS_ROLE(pe_session)) { + /* + * Check if wep bit was set in FC. If not set, + * reject with Authentication frame4 with + * 'challenge failure' status code. + */ + if (!mac_hdr->fc.wep) { + lim_log(mac_ctx, LOGE, + FL("received Auth frame3 from peer with no WEP bit set " + MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(mac_hdr->sa)); + /* WEP bit is not set in FC of Auth Frame3 */ + auth_frame->authAlgoNumber = eSIR_SHARED_KEY; + auth_frame->authTransactionSeqNumber = + SIR_MAC_AUTH_FRAME_4; + auth_frame->authStatusCode = + eSIR_MAC_CHALLENGE_FAILURE_STATUS; + lim_send_auth_mgmt_frame(mac_ctx, auth_frame, + mac_hdr->sa, + LIM_NO_WEP_IN_FC, + pe_session); + return; + } + + auth_node = lim_search_pre_auth_list(mac_ctx, mac_hdr->sa); + if (auth_node == NULL) { + lim_log(mac_ctx, LOGW, + FL("received AuthFrame3 from peer that has no preauth context " + MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(mac_hdr->sa)); + /* + * No 'pre-auth' context exists for this STA that sent + * an Authentication frame3. Send Auth frame4 with + * 'out of sequence' status code. + */ + auth_frame->authAlgoNumber = eSIR_SHARED_KEY; + auth_frame->authTransactionSeqNumber = + SIR_MAC_AUTH_FRAME_4; + auth_frame->authStatusCode = + eSIR_MAC_AUTH_FRAME_OUT_OF_SEQ_STATUS; + lim_send_auth_mgmt_frame(mac_ctx, auth_frame, + mac_hdr->sa, LIM_NO_WEP_IN_FC, + pe_session); + return; + } + + if (auth_node->mlmState == eLIM_MLM_AUTH_RSP_TIMEOUT_STATE) { + lim_log(mac_ctx, LOGW, + FL("auth response timer timedout for peer " + MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(mac_hdr->sa)); + /* + * Received Auth Frame3 after Auth Response timeout. + * Reject by sending Auth Frame4 with + * Auth respone timeout Status Code. + */ + auth_frame->authAlgoNumber = eSIR_SHARED_KEY; + auth_frame->authTransactionSeqNumber = + SIR_MAC_AUTH_FRAME_4; + auth_frame->authStatusCode = + eSIR_MAC_AUTH_RSP_TIMEOUT_STATUS; + + lim_send_auth_mgmt_frame(mac_ctx, auth_frame, + mac_hdr->sa, LIM_NO_WEP_IN_FC, + pe_session); + /* Delete pre-auth context of STA */ + lim_delete_pre_auth_node(mac_ctx, mac_hdr->sa); + return; + } + if (rx_auth_frm_body->authStatusCode != + eSIR_MAC_SUCCESS_STATUS) { + /* + * Received Authenetication Frame 3 with status code + * other than success. Wait until Auth response timeout + * to delete STA context. + */ + lim_log(mac_ctx, LOGE, + FL("rx Auth frm3 from peer with status code %d " + MAC_ADDRESS_STR), + rx_auth_frm_body->authStatusCode, + MAC_ADDR_ARRAY(mac_hdr->sa)); + return; + } + /* + * Check if received challenge text is same as one sent in + * Authentication frame3 + */ + if (!qdf_mem_cmp(rx_auth_frm_body->challengeText, + auth_node->challengeText, + SIR_MAC_AUTH_CHALLENGE_LENGTH)) { + /* + * Challenge match. STA is autheticated + * Delete Authentication response timer if running + */ + lim_deactivate_and_change_per_sta_id_timer(mac_ctx, + eLIM_AUTH_RSP_TIMER, auth_node->authNodeIdx); + + auth_node->fTimerStarted = 0; + auth_node->mlmState = eLIM_MLM_AUTHENTICATED_STATE; + + /* + * Send Auth Frame4 with 'success' Status Code. + */ + auth_frame->authAlgoNumber = eSIR_SHARED_KEY; + auth_frame->authTransactionSeqNumber = + SIR_MAC_AUTH_FRAME_4; + auth_frame->authStatusCode = + eSIR_MAC_SUCCESS_STATUS; + lim_send_auth_mgmt_frame(mac_ctx, auth_frame, + mac_hdr->sa, LIM_NO_WEP_IN_FC, + pe_session); + return; + } else { + lim_log(mac_ctx, LOGW, + FL("Challenge failure for peer " + MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(mac_hdr->sa)); + /* + * Challenge Failure. + * Send Authentication frame4 with 'challenge failure' + * status code and wait until Auth response timeout to + * delete STA context. + */ + auth_frame->authAlgoNumber = + rx_auth_frm_body->authAlgoNumber; + auth_frame->authTransactionSeqNumber = + SIR_MAC_AUTH_FRAME_4; + auth_frame->authStatusCode = + eSIR_MAC_CHALLENGE_FAILURE_STATUS; + lim_send_auth_mgmt_frame(mac_ctx, auth_frame, + mac_hdr->sa, LIM_NO_WEP_IN_FC, + pe_session); + return; + } + } +} + +static void lim_process_auth_frame_type4(tpAniSirGlobal mac_ctx, + tpSirMacMgmtHdr mac_hdr, + tSirMacAuthFrameBody *rx_auth_frm_body, + tpPESession pe_session) +{ + struct tLimPreAuthNode *auth_node; + + if (pe_session->limMlmState != eLIM_MLM_WT_AUTH_FRAME4_STATE) { + /* + * Received Authentication frame4 in an unexpected state. + * Log error and ignore the frame. + */ + + lim_log(mac_ctx, LOG1, + FL("received unexpected Auth frame4 from peer in state %d, addr " + MAC_ADDRESS_STR), + pe_session->limMlmState, + MAC_ADDR_ARRAY(mac_hdr->sa)); + return; + } + + if (rx_auth_frm_body->authAlgoNumber != eSIR_SHARED_KEY) { + /* + * Received Authentication frame4 with algorithm other than + * Shared Key authentication type. + * Wait until Auth failure timeout to report authentication + * failure to SME. + */ + lim_log(mac_ctx, LOGE, + FL("received Auth frame4 from peer with invalid auth algo %d " + MAC_ADDRESS_STR), + rx_auth_frm_body->authAlgoNumber, + MAC_ADDR_ARRAY(mac_hdr->sa)); + return; + } + + if (qdf_mem_cmp((uint8_t *) mac_hdr->sa, + (uint8_t *) &mac_ctx->lim.gpLimMlmAuthReq->peerMacAddr, + sizeof(tSirMacAddr))) { + /* + * Received Authentication frame from an entity + * other than one to which request was initiated. + * Wait until Authentication Failure Timeout. + */ + + lim_log(mac_ctx, LOGW, + FL("received Auth frame4 from unexpected peer " + MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(mac_hdr->sa)); + return; + } + + if (rx_auth_frm_body->authAlgoNumber != + mac_ctx->lim.gpLimMlmAuthReq->authType) { + /* + * Received Authentication frame with an auth algorithm + * other than one requested. + * Wait until Authentication Failure Timeout. + */ + + lim_log(mac_ctx, LOGE, + FL("received Authentication frame from peer with invalid auth seq number %d " + MAC_ADDRESS_STR), + rx_auth_frm_body->authTransactionSeqNumber, + MAC_ADDR_ARRAY(mac_hdr->sa)); + return; + } + + if (rx_auth_frm_body->authStatusCode == eSIR_MAC_SUCCESS_STATUS) { + /* + * Authentication Success, Inform SME of same. + */ + pe_session->limCurrentAuthType = eSIR_SHARED_KEY; + auth_node = lim_acquire_free_pre_auth_node(mac_ctx, + &mac_ctx->lim.gLimPreAuthTimerTable); + if (auth_node == NULL) { + lim_log(mac_ctx, LOGW, + FL("Max pre-auth nodes reached ")); + lim_print_mac_addr(mac_ctx, mac_hdr->sa, LOGW); + return; + } + lim_log(mac_ctx, LOG1, FL("Alloc new data: %p peer "), + auth_node); + lim_print_mac_addr(mac_ctx, mac_hdr->sa, LOG1); + qdf_mem_copy((uint8_t *) auth_node->peerMacAddr, + mac_ctx->lim.gpLimMlmAuthReq->peerMacAddr, + sizeof(tSirMacAddr)); + auth_node->fTimerStarted = 0; + auth_node->authType = mac_ctx->lim.gpLimMlmAuthReq->authType; + auth_node->seq_num = ((mac_hdr->seqControl.seqNumHi << 4) | + (mac_hdr->seqControl.seqNumLo)); + auth_node->timestamp = qdf_mc_timer_get_system_ticks(); + lim_add_pre_auth_node(mac_ctx, auth_node); + lim_restore_from_auth_state(mac_ctx, eSIR_SME_SUCCESS, + rx_auth_frm_body->authStatusCode, pe_session); + } else { + /* + * Authentication failure. + * Return Auth confirm with received failure code to SME + */ + + lim_log(mac_ctx, LOGE, + FL("Authentication failure from peer " + MAC_ADDRESS_STR), MAC_ADDR_ARRAY(mac_hdr->sa)); + lim_restore_from_auth_state(mac_ctx, eSIR_SME_AUTH_REFUSED, + rx_auth_frm_body->authStatusCode, + pe_session); + } +} + +/** + * lim_process_auth_frame() - to process auth frame + * @mac_ctx - Pointer to Global MAC structure + * @rx_pkt_info - A pointer to Rx packet info structure + * @session - A pointer to session + * + * This function is called by limProcessMessageQueue() upon Authentication + * frame reception. + * + * LOGIC: + * This function processes received Authentication frame and responds + * with either next Authentication frame in sequence to peer MAC entity + * or LIM_MLM_AUTH_IND on AP or LIM_MLM_AUTH_CNF on STA. + * + * NOTE: + * 1. Authentication failures are reported to SME with same status code + * received from the peer MAC entity. + * 2. Authentication frame2/4 received with alogirthm number other than + * one requested in frame1/3 are logged with an error and auth confirm + * will be sent to SME only after auth failure timeout. + * 3. Inconsistency in the spec: + * On receiving Auth frame2, specs says that if WEP key mapping key + * or default key is NULL, Auth frame3 with a status code 15 (challenge + * failure to be returned to peer entity. However, section 7.2.3.10, + * table 14 says that status code field is 'reserved' for frame3 ! + * In the current implementation, Auth frame3 is returned with status + * code 15 overriding section 7.2.3.10. + * 4. If number pre-authentications reach configrable max limit, + * Authentication frame with 'unspecified failure' status code is + * returned to requesting entity. + * + * Return: None + */ +void +lim_process_auth_frame(tpAniSirGlobal mac_ctx, uint8_t *rx_pkt_info, + tpPESession pe_session) +{ + uint8_t *body_ptr, key_id, cfg_privacy_opt_imp; + uint8_t defaultkey[SIR_MAC_KEY_LENGTH]; + uint8_t *plainbody = NULL; + uint8_t decrypt_result; + uint16_t frame_len, curr_seq_num = 0; + uint32_t val, key_length = 8; + tSirMacAuthFrameBody *rx_auth_frm_body, *rx_auth_frame, *auth_frame; + tpSirMacMgmtHdr mac_hdr; + struct tLimPreAuthNode *auth_node; + + /* Get pointer to Authentication frame header and body */ + mac_hdr = WMA_GET_RX_MAC_HEADER(rx_pkt_info); + frame_len = WMA_GET_RX_PAYLOAD_LEN(rx_pkt_info); + + if (!frame_len) { + /* Log error */ + lim_log(mac_ctx, LOGE, + FL("received Auth frame with no body from %pM"), + mac_hdr->sa); + return; + } + + if (lim_is_group_addr(mac_hdr->sa)) { + /* + * Received Auth frame from a BC/MC address + * Log error and ignore it + */ + lim_log(mac_ctx, LOGE, + FL("received Auth frame from a BC/MC addr %pM"), + mac_hdr->sa); + return; + } + curr_seq_num = (mac_hdr->seqControl.seqNumHi << 4) | + (mac_hdr->seqControl.seqNumLo); + + lim_log(mac_ctx, LOG1, + FL("Sessionid: %d System role : %d limMlmState: %d :Auth " + "Frame Received: BSSID: " MAC_ADDRESS_STR " (RSSI %d)"), + pe_session->peSessionId, GET_LIM_SYSTEM_ROLE(pe_session), + pe_session->limMlmState, MAC_ADDR_ARRAY(mac_hdr->bssId), + (uint) abs((int8_t) WMA_GET_RX_RSSI_NORMALIZED(rx_pkt_info))); + + body_ptr = WMA_GET_RX_MPDU_DATA(rx_pkt_info); + + /* Restore default failure timeout */ + if (QDF_P2P_CLIENT_MODE == pe_session->pePersona && + pe_session->defaultAuthFailureTimeout) { + lim_log(mac_ctx, LOG1, FL("Restore default failure timeout")); + cfg_set_int(mac_ctx, WNI_CFG_AUTHENTICATE_FAILURE_TIMEOUT, + pe_session->defaultAuthFailureTimeout); + } + + rx_auth_frame = qdf_mem_malloc(sizeof(tSirMacAuthFrameBody)); + if (!rx_auth_frame) { + pe_err("failed to allocate memory"); + return; + } + auth_frame = qdf_mem_malloc(sizeof(tSirMacAuthFrameBody)); + if (!auth_frame) { + pe_err("failed to allocate memory"); + goto free; + } + plainbody = qdf_mem_malloc(LIM_ENCR_AUTH_BODY_LEN); + if (!plainbody) { + pe_err("failed to allocate memory for plainbody"); + goto free; + } + qdf_mem_zero(plainbody, LIM_ENCR_AUTH_BODY_LEN); + /* + * Determine if WEP bit is set in the FC or received MAC header + * Note: WEP bit is set in FC of MAC header. + */ + if (mac_hdr->fc.wep) { + /* + * If TKIP counter measures enabled then issue Deauth + * frame to station + */ + if (pe_session->bTkipCntrMeasActive && + LIM_IS_AP_ROLE(pe_session)) { + lim_log(mac_ctx, LOGE, + FL("Tkip counter enabled, send deauth to %pM"), + mac_hdr->sa); + lim_send_deauth_mgmt_frame(mac_ctx, + eSIR_MAC_MIC_FAILURE_REASON, + mac_hdr->sa, pe_session, false); + goto free; + } + /* Extract key ID from IV (most 2 bits of 4th byte of IV) */ + key_id = (*(body_ptr + 3)) >> 6; + + /* + * On STA in infrastructure BSS, Authentication frames received + * with WEP bit set in the FC must be rejected with challenge + * failure status code (wierd thing in the spec - this should've + * been rejected with unspecified failure/unexpected assertion + * of wep bit (this status code does not exist though) or + * Out-of-sequence-Authentication-Frame status code. + */ + if (LIM_IS_STA_ROLE(pe_session)) { + auth_frame->authAlgoNumber = eSIR_SHARED_KEY; + auth_frame->authTransactionSeqNumber = + SIR_MAC_AUTH_FRAME_4; + auth_frame->authStatusCode = + eSIR_MAC_CHALLENGE_FAILURE_STATUS; + /* Log error */ + lim_log(mac_ctx, LOGE, + FL("rx Auth frm with wep bit set role=%d %pM"), + GET_LIM_SYSTEM_ROLE(pe_session), mac_hdr->sa); + lim_send_auth_mgmt_frame(mac_ctx, auth_frame, + mac_hdr->sa, LIM_NO_WEP_IN_FC, + pe_session); + goto free; + } + + if (frame_len < LIM_ENCR_AUTH_BODY_LEN) { + /* Log error */ + lim_log(mac_ctx, LOGE, + FL("Not enough size [%d] to decry rx Auth frm"), + frame_len); + lim_print_mac_addr(mac_ctx, mac_hdr->sa, LOGE); + goto free; + } + if (LIM_IS_AP_ROLE(pe_session)) { + val = pe_session->privacy; + } else if (wlan_cfg_get_int(mac_ctx, WNI_CFG_PRIVACY_ENABLED, + &val) != eSIR_SUCCESS) { + /* + * Accept Authentication frame only if Privacy is + * implemented, if Could not get Privacy option + * from CFG then Log fatal error + */ + lim_log(mac_ctx, LOGP, + FL("could not retrieve Privacy option")); + } + cfg_privacy_opt_imp = (uint8_t) val; + + if (!cfg_privacy_opt_imp) { + lim_log(mac_ctx, LOGE, + FL("received Authentication frame3 from peer that while privacy option is turned OFF " + MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(mac_hdr->sa)); + /* + * Privacy option is not implemented. + * So reject Authentication frame received with + * WEP bit set by sending Authentication frame + * with 'challenge failure' status code. This is + * another strange thing in the spec. Status code + * should have been 'unsupported algorithm' status code. + */ + auth_frame->authAlgoNumber = eSIR_SHARED_KEY; + auth_frame->authTransactionSeqNumber = + SIR_MAC_AUTH_FRAME_4; + auth_frame->authStatusCode = + eSIR_MAC_CHALLENGE_FAILURE_STATUS; + lim_send_auth_mgmt_frame(mac_ctx, auth_frame, + mac_hdr->sa, LIM_NO_WEP_IN_FC, + pe_session); + goto free; + } + + /* + * Privacy option is implemented. Check if the received frame is + * Authentication frame3 and there is a context for requesting + * STA. If not, reject with unspecified failure status code + */ + auth_node = lim_search_pre_auth_list(mac_ctx, mac_hdr->sa); + if (auth_node == NULL) { + lim_log(mac_ctx, LOGE, + FL("rx Auth frame with no preauth ctx with WEP bit set " + MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(mac_hdr->sa)); + /* + * No 'pre-auth' context exists for this STA + * that sent an Authentication frame with FC + * bit set. Send Auth frame4 with + * 'out of sequence' status code. + */ + auth_frame->authAlgoNumber = eSIR_SHARED_KEY; + auth_frame->authTransactionSeqNumber = + SIR_MAC_AUTH_FRAME_4; + auth_frame->authStatusCode = + eSIR_MAC_AUTH_FRAME_OUT_OF_SEQ_STATUS; + lim_send_auth_mgmt_frame(mac_ctx, auth_frame, + mac_hdr->sa, LIM_NO_WEP_IN_FC, + pe_session); + goto free; + } + /* Change the auth-response timeout */ + lim_deactivate_and_change_per_sta_id_timer(mac_ctx, + eLIM_AUTH_RSP_TIMER, auth_node->authNodeIdx); + + /* 'Pre-auth' status exists for STA */ + if ((auth_node->mlmState != eLIM_MLM_WT_AUTH_FRAME3_STATE) && + (auth_node->mlmState != + eLIM_MLM_AUTH_RSP_TIMEOUT_STATE)) { + lim_log(mac_ctx, LOGE, + FL("received Authentication frame from peer that is in state %d " + MAC_ADDRESS_STR), + auth_node->mlmState, + MAC_ADDR_ARRAY(mac_hdr->sa)); + /* + * Should not have received Authentication frame + * with WEP bit set in FC in other states. + * Reject by sending Authenticaton frame with + * out of sequence Auth frame status code. + */ + auth_frame->authAlgoNumber = eSIR_SHARED_KEY; + auth_frame->authTransactionSeqNumber = + SIR_MAC_AUTH_FRAME_4; + auth_frame->authStatusCode = + eSIR_MAC_AUTH_FRAME_OUT_OF_SEQ_STATUS; + + lim_send_auth_mgmt_frame(mac_ctx, auth_frame, + mac_hdr->sa, LIM_NO_WEP_IN_FC, + pe_session); + goto free; + } + + val = SIR_MAC_KEY_LENGTH; + + if (LIM_IS_AP_ROLE(pe_session)) { + tpSirKeys key_ptr; + key_ptr = &pe_session->WEPKeyMaterial[key_id].key[0]; + qdf_mem_copy(defaultkey, key_ptr->key, + key_ptr->keyLength); + val = key_ptr->keyLength; + } else if (wlan_cfg_get_str(mac_ctx, + (uint16_t) (WNI_CFG_WEP_DEFAULT_KEY_1 + key_id), + defaultkey, &val) != eSIR_SUCCESS) { + lim_log(mac_ctx, LOGP, + FL("could not retrieve Default key")); + + /* + * Send Authentication frame + * with challenge failure status code + */ + auth_frame->authAlgoNumber = eSIR_SHARED_KEY; + auth_frame->authTransactionSeqNumber = + SIR_MAC_AUTH_FRAME_4; + auth_frame->authStatusCode = + eSIR_MAC_CHALLENGE_FAILURE_STATUS; + lim_send_auth_mgmt_frame(mac_ctx, auth_frame, + mac_hdr->sa, LIM_NO_WEP_IN_FC, + pe_session); + goto free; + } + + key_length = val; + decrypt_result = lim_decrypt_auth_frame(mac_ctx, defaultkey, + body_ptr, plainbody, key_length, + (uint16_t) (frame_len - + SIR_MAC_WEP_IV_LENGTH)); + if (decrypt_result == LIM_DECRYPT_ICV_FAIL) { + lim_log(mac_ctx, LOGE, + FL("received Authentication frame from peer that failed decryption: " + MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(mac_hdr->sa)); + /* ICV failure */ + lim_delete_pre_auth_node(mac_ctx, mac_hdr->sa); + auth_frame->authAlgoNumber = eSIR_SHARED_KEY; + auth_frame->authTransactionSeqNumber = + SIR_MAC_AUTH_FRAME_4; + auth_frame->authStatusCode = + eSIR_MAC_CHALLENGE_FAILURE_STATUS; + + lim_send_auth_mgmt_frame(mac_ctx, auth_frame, + mac_hdr->sa, LIM_NO_WEP_IN_FC, + pe_session); + goto free; + } + if ((sir_convert_auth_frame2_struct(mac_ctx, plainbody, + frame_len - 8, rx_auth_frame) != eSIR_SUCCESS) + || (!is_auth_valid(mac_ctx, rx_auth_frame, + pe_session))) { + lim_log(mac_ctx, LOGE, + FL("failed to convert Auth Frame to structure or Auth is not valid ")); + goto free; + } + } else if ((sir_convert_auth_frame2_struct(mac_ctx, body_ptr, + frame_len, rx_auth_frame) != eSIR_SUCCESS) + || (!is_auth_valid(mac_ctx, rx_auth_frame, + pe_session))) { + lim_log(mac_ctx, LOGE, + FL("failed to convert Auth Frame to structure or Auth is not valid ")); + goto free; + } + + rx_auth_frm_body = rx_auth_frame; + + lim_log(mac_ctx, LOGW, + FL("Received Auth frame with type=%d seqnum=%d, status=%d (%d)"), + (uint32_t) rx_auth_frm_body->authAlgoNumber, + (uint32_t) rx_auth_frm_body->authTransactionSeqNumber, + (uint32_t) rx_auth_frm_body->authStatusCode, + (uint32_t) mac_ctx->lim.gLimNumPreAuthContexts); + + /* + * IOT Workaround: with invalid WEP key, some APs reply + * AuthFrame 4 with invalid seqNumber. This AuthFrame + * will be dropped by driver, thus driver sends the + * generic status code instead of protocol status code. + * As a workaround, override AuthFrame 4's seqNumber. + */ + if ((pe_session->limMlmState == + eLIM_MLM_WT_AUTH_FRAME4_STATE) && + (rx_auth_frm_body->authTransactionSeqNumber != + SIR_MAC_AUTH_FRAME_1) && + (rx_auth_frm_body->authTransactionSeqNumber != + SIR_MAC_AUTH_FRAME_2) && + (rx_auth_frm_body->authTransactionSeqNumber != + SIR_MAC_AUTH_FRAME_3)) { + lim_log(mac_ctx, LOGW, + FL("Override AuthFrame 4's seqNumber to 4.")); + rx_auth_frm_body->authTransactionSeqNumber = + SIR_MAC_AUTH_FRAME_4; + } + + + switch (rx_auth_frm_body->authTransactionSeqNumber) { + case SIR_MAC_AUTH_FRAME_1: + lim_process_auth_frame_type1(mac_ctx, + mac_hdr, rx_auth_frm_body, rx_pkt_info, + curr_seq_num, auth_frame, pe_session); + break; + case SIR_MAC_AUTH_FRAME_2: + lim_process_auth_frame_type2(mac_ctx, + mac_hdr, rx_auth_frm_body, auth_frame, plainbody, + body_ptr, frame_len, pe_session); + break; + case SIR_MAC_AUTH_FRAME_3: + lim_process_auth_frame_type3(mac_ctx, + mac_hdr, rx_auth_frm_body, auth_frame, pe_session); + break; + case SIR_MAC_AUTH_FRAME_4: + lim_process_auth_frame_type4(mac_ctx, + mac_hdr, rx_auth_frm_body, pe_session); + break; + default: + /* Invalid Authentication Frame received. Ignore it. */ + lim_log(mac_ctx, LOGE, + FL("rx auth frm with invalid authseq no %d from: %pM"), + rx_auth_frm_body->authTransactionSeqNumber, + mac_hdr->sa); + break; + } +free: + if (auth_frame) + qdf_mem_free(auth_frame); + if (rx_auth_frame) + qdf_mem_free(rx_auth_frame); + if (plainbody) + qdf_mem_free(plainbody); +} + +/*---------------------------------------------------------------------- + * + * Pass the received Auth frame. This is possibly the pre-auth from the + * neighbor AP, in the same mobility domain. + * This will be used in case of 11r FT. + * + * !!!! This is going to be renoved for the next checkin. We will be creating + * the session before sending out the Auth. Thus when auth response + * is received we will have a session in progress. !!!!! + ***---------------------------------------------------------------------- + */ +tSirRetStatus lim_process_auth_frame_no_session(tpAniSirGlobal pMac, uint8_t *pBd, + void *body) +{ + tpSirMacMgmtHdr pHdr; + tpPESession psessionEntry = NULL; + uint8_t *pBody; + uint16_t frameLen; + tSirMacAuthFrameBody rxAuthFrame; + tSirMacAuthFrameBody *pRxAuthFrameBody = NULL; + tSirRetStatus ret_status = eSIR_FAILURE; + int i; + + pHdr = WMA_GET_RX_MAC_HEADER(pBd); + pBody = WMA_GET_RX_MPDU_DATA(pBd); + frameLen = WMA_GET_RX_PAYLOAD_LEN(pBd); + + lim_log(pMac, LOG1, + FL("Auth Frame Received: BSSID " MAC_ADDRESS_STR " (RSSI %d)"), + MAC_ADDR_ARRAY(pHdr->bssId), + (uint) abs((int8_t) WMA_GET_RX_RSSI_NORMALIZED(pBd))); + + /* Auth frame has come on a new BSS, however, we need to find the session + * from where the auth-req was sent to the new AP + */ + for (i = 0; i < pMac->lim.maxBssId; i++) { + /* Find first free room in session table */ + if (pMac->lim.gpSession[i].valid == true && + pMac->lim.gpSession[i].ftPEContext.ftPreAuthSession == + true) { + /* Found the session */ + psessionEntry = &pMac->lim.gpSession[i]; + pMac->lim.gpSession[i].ftPEContext.ftPreAuthSession = + false; + } + } + + if (psessionEntry == NULL) { + lim_log(pMac, LOGE, + FL + ("Error: Unable to find session id while in pre-auth phase for FT")); + return eSIR_FAILURE; + } + + if (psessionEntry->ftPEContext.pFTPreAuthReq == NULL) { + lim_log(pMac, LOGE, FL("Error: No FT")); + /* No FT in progress. */ + return eSIR_FAILURE; + } + + if (frameLen == 0) { + lim_log(pMac, LOGE, FL("Error: Frame len = 0")); + return eSIR_FAILURE; + } + lim_print_mac_addr(pMac, pHdr->bssId, LOG2); + lim_print_mac_addr(pMac, + psessionEntry->ftPEContext.pFTPreAuthReq->preAuthbssId, + LOG2); + lim_log(pMac, LOG2, FL("seqControl 0x%X"), + ((pHdr->seqControl.seqNumHi << 8) | + (pHdr->seqControl.seqNumLo << 4) | + (pHdr->seqControl.fragNum))); + + /* Check that its the same bssId we have for preAuth */ + if (qdf_mem_cmp + (psessionEntry->ftPEContext.pFTPreAuthReq->preAuthbssId, + pHdr->bssId, sizeof(tSirMacAddr))) { + lim_log(pMac, LOGE, FL("Error: Same bssid as preauth BSSID")); + /* In this case SME if indeed has triggered a */ + /* pre auth it will time out. */ + return eSIR_FAILURE; + } + + if (true == + psessionEntry->ftPEContext.pFTPreAuthReq->bPreAuthRspProcessed) { + /* + * This is likely a duplicate for the same pre-auth request. + * PE/LIM already posted a response to SME. Hence, drop it. + * TBD: + * 1) How did we even receive multiple auth responses? + * 2) Do we need to delete pre-auth session? Suppose we + * previously received an auth resp with failure which + * would not have created the session and forwarded to SME. + * And, we subsequently received an auth resp with success + * which would have created the session. This will now be + * dropped without being forwarded to SME! However, it is + * very unlikely to receive auth responses from the same + * AP with different reason codes. + * NOTE: return eSIR_SUCCESS so that the packet is dropped + * as this was indeed a response from the BSSID we tried to + * pre-auth. + */ + PELOGE(lim_log(pMac, LOG1, "Auth rsp already posted to SME" + " (session %p, FT session %p)", psessionEntry, + psessionEntry); + ); + return eSIR_SUCCESS; + } else { + PELOGE(lim_log(pMac, LOGW, "Auth rsp not yet posted to SME" + " (session %p, FT session %p)", psessionEntry, + psessionEntry); + ); + psessionEntry->ftPEContext.pFTPreAuthReq->bPreAuthRspProcessed = + true; + } + + lim_log(pMac, LOG1, FL("Pre-Auth response received from neighbor")); + lim_log(pMac, LOG1, FL("Pre-Auth done state")); + /* Stopping timer now, that we have our unicast from the AP */ + /* of our choice. */ + lim_deactivate_and_change_timer(pMac, eLIM_FT_PREAUTH_RSP_TIMER); + + /* Save off the auth resp. */ + if ((sir_convert_auth_frame2_struct(pMac, pBody, frameLen, &rxAuthFrame) != + eSIR_SUCCESS)) { + lim_log(pMac, LOGE, + FL("failed to convert Auth frame to struct")); + lim_handle_ft_pre_auth_rsp(pMac, eSIR_FAILURE, NULL, 0, + psessionEntry); + return eSIR_FAILURE; + } + pRxAuthFrameBody = &rxAuthFrame; + + PELOGE(lim_log(pMac, LOG1, + FL + ("Received Auth frame with type=%d seqnum=%d, status=%d (%d)"), + (uint32_t) pRxAuthFrameBody->authAlgoNumber, + (uint32_t) pRxAuthFrameBody->authTransactionSeqNumber, + (uint32_t) pRxAuthFrameBody->authStatusCode, + (uint32_t) pMac->lim.gLimNumPreAuthContexts); + ) + switch (pRxAuthFrameBody->authTransactionSeqNumber) { + case SIR_MAC_AUTH_FRAME_2: + if (pRxAuthFrameBody->authStatusCode != eSIR_MAC_SUCCESS_STATUS) { + lim_log(pMac, LOGE, "Auth status code received is %d", + (uint32_t) pRxAuthFrameBody->authStatusCode); + if (eSIR_MAC_MAX_ASSOC_STA_REACHED_STATUS == + pRxAuthFrameBody->authStatusCode) + ret_status = eSIR_LIM_MAX_STA_REACHED_ERROR; + } else { + ret_status = eSIR_SUCCESS; + } + break; + + default: + lim_log(pMac, LOGE, "Seq. no incorrect expected 2 received %d", + (uint32_t) pRxAuthFrameBody->authTransactionSeqNumber); + break; + } + + /* Send the Auth response to SME */ + lim_handle_ft_pre_auth_rsp(pMac, ret_status, pBody, frameLen, psessionEntry); + + return ret_status; +} diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_process_beacon_frame.c b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_process_beacon_frame.c new file mode 100644 index 0000000000000000000000000000000000000000..7ff7e61fa9c7984cc6602f38404927cb1b8bd6e0 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_process_beacon_frame.c @@ -0,0 +1,258 @@ +/* + * Copyright (c) 2011-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * + * This file lim_process_beacon_frame.cc contains the code + * for processing Received Beacon Frame. + * Author: Chandra Modumudi + * Date: 03/01/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + * + */ + +#include "wni_cfg.h" +#include "ani_global.h" +#include "cfg_api.h" +#include "sch_api.h" +#include "utils_api.h" +#include "lim_types.h" +#include "lim_utils.h" +#include "lim_assoc_utils.h" +#include "lim_prop_exts_utils.h" +#include "lim_ser_des_utils.h" + +/** + * lim_process_beacon_frame() - to process beacon frames + * @mac_ctx: Pointer to Global MAC structure + * @rx_pkt_info: A pointer to RX packet info structure + * @session: A pointer to session + * + * This function is called by limProcessMessageQueue() upon Beacon + * frame reception. + * Note: + * 1. Beacons received in 'normal' state in IBSS are handled by + * Beacon Processing module. + * + * Return: none + */ + +void +lim_process_beacon_frame(tpAniSirGlobal mac_ctx, uint8_t *rx_pkt_info, + tpPESession session) +{ + tpSirMacMgmtHdr mac_hdr; + tSchBeaconStruct *bcn_ptr; + + mac_ctx->lim.gLimNumBeaconsRcvd++; + + /* + * here is it required to increment session specific heartBeat + * beacon counter + */ + mac_hdr = WMA_GET_RX_MAC_HEADER(rx_pkt_info); + lim_log(mac_ctx, LOG2, + FL("Received Beacon frame with length=%d from "), + WMA_GET_RX_MPDU_LEN(rx_pkt_info)); + lim_print_mac_addr(mac_ctx, mac_hdr->sa, LOG2); + + /* Expect Beacon in any state as Scan is independent of LIM state */ + bcn_ptr = qdf_mem_malloc(sizeof(*bcn_ptr)); + if (NULL == bcn_ptr) { + lim_log(mac_ctx, LOGE, + FL("Unable to allocate memory")); + return; + } + /* Parse received Beacon */ + if (sir_convert_beacon_frame2_struct(mac_ctx, + rx_pkt_info, bcn_ptr) != + eSIR_SUCCESS) { + /* + * Received wrongly formatted/invalid Beacon. + * Ignore it and move on. + */ + lim_log(mac_ctx, LOGW, + FL("Received invalid Beacon in state %X"), + session->limMlmState); + lim_print_mlm_state(mac_ctx, LOGW, + session->limMlmState); + qdf_mem_free(bcn_ptr); + return; + } + + /* + * during scanning, when any session is active, and + * beacon/Pr belongs to one of the session, fill up the + * following, TBD - HB couter + */ + if (sir_compare_mac_addr(session->bssId, + bcn_ptr->bssid)) { + qdf_mem_copy((uint8_t *)&session->lastBeaconTimeStamp, + (uint8_t *) bcn_ptr->timeStamp, + sizeof(uint64_t)); + session->lastBeaconDtimCount = + bcn_ptr->tim.dtimCount; + session->currentBssBeaconCnt++; + } + MTRACE(mac_trace(mac_ctx, + TRACE_CODE_RX_MGMT_TSF, 0, bcn_ptr->timeStamp[0]);) + MTRACE(mac_trace(mac_ctx, TRACE_CODE_RX_MGMT_TSF, 0, + bcn_ptr->timeStamp[1]);) + lim_check_and_add_bss_description(mac_ctx, bcn_ptr, + rx_pkt_info, false, true); + + if ((mac_ctx->lim.gLimMlmState == + eLIM_MLM_WT_PROBE_RESP_STATE) || + (mac_ctx->lim.gLimMlmState == + eLIM_MLM_PASSIVE_SCAN_STATE)) { + /* If we are scanning for P2P, only accept probe rsp */ + if ((mac_ctx->lim.gLimHalScanState != + eLIM_HAL_SCANNING_STATE) || + (NULL == mac_ctx->lim.gpLimMlmScanReq) || + !mac_ctx->lim.gpLimMlmScanReq->p2pSearch) + lim_check_and_add_bss_description(mac_ctx, bcn_ptr, + rx_pkt_info, + ((mac_ctx->lim.gLimHalScanState == + eLIM_HAL_SCANNING_STATE) ? true : false), + false); + /* + * Calling dfsChannelList which will convert DFS channel + * to active channel for x secs if this channel is DFS + */ + lim_set_dfs_channel_list(mac_ctx, + bcn_ptr->channelNumber, + &mac_ctx->lim.dfschannelList); + } else if (session->limMlmState == + eLIM_MLM_WT_JOIN_BEACON_STATE) { + if (session->beacon != NULL) { + qdf_mem_free(session->beacon); + session->beacon = NULL; + session->bcnLen = 0; + } + session->bcnLen = WMA_GET_RX_PAYLOAD_LEN(rx_pkt_info); + session->beacon = qdf_mem_malloc(session->bcnLen); + if (NULL == session->beacon) { + lim_log(mac_ctx, LOGE, + FL("fail to alloc mem to store bcn")); + } else { + /* + * Store the Beacon/ProbeRsp. This is sent to + * csr/hdd in join cnf response. + */ + qdf_mem_copy(session->beacon, + WMA_GET_RX_MPDU_DATA(rx_pkt_info), + session->bcnLen); + } + lim_check_and_announce_join_success(mac_ctx, bcn_ptr, + mac_hdr, session); + } + qdf_mem_free(bcn_ptr); + return; +} + +/**--------------------------------------------------------------- + \fn lim_process_beacon_frame_no_session + \brief This function is called by limProcessMessageQueue() + \ upon Beacon reception. + \ + \param pMac + \param *pRxPacketInfo - A pointer to Rx packet info structure + \return None + ------------------------------------------------------------------*/ +void +lim_process_beacon_frame_no_session(tpAniSirGlobal pMac, uint8_t *pRxPacketInfo) +{ + tpSirMacMgmtHdr pHdr; + tSchBeaconStruct *pBeacon; + + pMac->lim.gLimNumBeaconsRcvd++; + pHdr = WMA_GET_RX_MAC_HEADER(pRxPacketInfo); + + lim_log(pMac, LOG2, FL("Received Beacon frame with length=%d from "), + WMA_GET_RX_MPDU_LEN(pRxPacketInfo)); + lim_print_mac_addr(pMac, pHdr->sa, LOG2); + + + /** + * No session has been established. Expect Beacon only when + * 1. STA is in Scan mode waiting for Beacon/Probe response or + * 2. STA/AP is in Learn mode + */ + if ((pMac->lim.gLimMlmState == eLIM_MLM_WT_PROBE_RESP_STATE) || + (pMac->lim.gLimMlmState == eLIM_MLM_PASSIVE_SCAN_STATE) || + (pMac->lim.gLimMlmState == eLIM_MLM_LEARN_STATE)) { + pBeacon = qdf_mem_malloc(sizeof(tSchBeaconStruct)); + if (NULL == pBeacon) { + lim_log(pMac, LOGE, + FL + ("Unable to allocate memory in lim_process_beacon_frame_no_session")); + return; + } + + if (sir_convert_beacon_frame2_struct + (pMac, (uint8_t *) pRxPacketInfo, + pBeacon) != eSIR_SUCCESS) { + /* Received wrongly formatted/invalid Beacon. Ignore and move on. */ + lim_log(pMac, LOGW, + FL + ("Received invalid Beacon in global MLM state %X"), + pMac->lim.gLimMlmState); + lim_print_mlm_state(pMac, LOGW, pMac->lim.gLimMlmState); + qdf_mem_free(pBeacon); + return; + } + + if ((pMac->lim.gLimMlmState == eLIM_MLM_WT_PROBE_RESP_STATE) || + (pMac->lim.gLimMlmState == eLIM_MLM_PASSIVE_SCAN_STATE)) { + /*If we are scanning for P2P, only accept probe rsp */ + if ((pMac->lim.gLimHalScanState != + eLIM_HAL_SCANNING_STATE) || + (NULL == pMac->lim.gpLimMlmScanReq) || + !pMac->lim.gpLimMlmScanReq->p2pSearch) + lim_check_and_add_bss_description(pMac, pBeacon, + pRxPacketInfo, true, false); + /* Calling dfsChannelList which will convert DFS channel + * to Active channel for x secs if this channel is DFS channel */ + lim_set_dfs_channel_list(pMac, pBeacon->channelNumber, + &pMac->lim.dfschannelList); + } else if (pMac->lim.gLimMlmState == eLIM_MLM_LEARN_STATE) { + } /* end of eLIM_MLM_LEARN_STATE) */ + qdf_mem_free(pBeacon); + } /* end of (eLIM_MLM_WT_PROBE_RESP_STATE) || (eLIM_MLM_PASSIVE_SCAN_STATE) */ + else { + lim_log(pMac, LOG1, FL("Rcvd Beacon in unexpected MLM state %s (%d)"), + lim_mlm_state_str(pMac->lim.gLimMlmState), + pMac->lim.gLimMlmState); +#ifdef WLAN_DEBUG + pMac->lim.gLimUnexpBcnCnt++; +#endif + } + + return; +} /*** end lim_process_beacon_frame_no_session() ***/ diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_process_cfg_updates.c b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_process_cfg_updates.c new file mode 100644 index 0000000000000000000000000000000000000000..7f4c16e2ac6fd3745e16ae42eda4fa6691ad5818 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_process_cfg_updates.c @@ -0,0 +1,498 @@ +/* + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * This file lim_process_cfg_updates.cc contains the utility functions + * to handle various CFG parameter update events + * Author: Chandra Modumudi + * Date: 01/20/03 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + */ + +#include "ani_global.h" + +#include "wni_cfg.h" +#include "sir_mac_prot_def.h" +#include "cfg_api.h" +#include "lim_types.h" +#include "lim_utils.h" +#include "lim_prop_exts_utils.h" +#include "sch_api.h" +#include "rrm_api.h" + +static void lim_update_config(tpAniSirGlobal pMac, tpPESession psessionEntry); + +static void lim_set_default_key_id_and_keys(tpAniSirGlobal pMac) +{ +#ifdef FIXME_GEN6 + uint32_t val; + uint32_t dkCfgId; + PELOG1(lim_log(pMac, LOG1, FL("Setting default keys at SP"));) + if (wlan_cfg_get_int(pMac, WNI_CFG_WEP_DEFAULT_KEYID, + &val) != eSIR_SUCCESS) { + lim_log(pMac, LOGP, + FL("Unable to retrieve defaultKeyId from CFG")); + } + dkCfgId = limGetCfgIdOfDefaultKeyid(val); +#endif + +} /*** end lim_set_default_key_id_and_keys() ***/ +/** ------------------------------------------------------------- + \fn lim_set_cfg_protection + \brief sets lim global cfg cache from the config. + \param tpAniSirGlobal pMac + \return None + -------------------------------------------------------------*/ +void lim_set_cfg_protection(tpAniSirGlobal pMac, tpPESession pesessionEntry) +{ + uint32_t val = 0; + + if (pesessionEntry != NULL && LIM_IS_AP_ROLE(pesessionEntry)) { + if (pesessionEntry->gLimProtectionControl == + WNI_CFG_FORCE_POLICY_PROTECTION_DISABLE) + qdf_mem_set((void *)&pesessionEntry->cfgProtection, + sizeof(tCfgProtection), 0); + else { + lim_log(pMac, LOG1, + FL(" frm11a = %d, from11b = %d, frm11g = %d, " + "ht20 = %d, nongf = %d, lsigTxop = %d, " + "rifs = %d, obss = %d"), + pesessionEntry->cfgProtection.fromlla, + pesessionEntry->cfgProtection.fromllb, + pesessionEntry->cfgProtection.fromllg, + pesessionEntry->cfgProtection.ht20, + pesessionEntry->cfgProtection.nonGf, + pesessionEntry->cfgProtection.lsigTxop, + pesessionEntry->cfgProtection.rifs, + pesessionEntry->cfgProtection.obss); + } + } else { + if (wlan_cfg_get_int(pMac, WNI_CFG_FORCE_POLICY_PROTECTION, &val) + != eSIR_SUCCESS) { + lim_log(pMac, LOGP, + FL + ("reading WNI_CFG_FORCE_POLICY_PROTECTION cfg failed")); + return; + } else + pMac->lim.gLimProtectionControl = (uint8_t) val; + + if (wlan_cfg_get_int(pMac, WNI_CFG_PROTECTION_ENABLED, &val) != + eSIR_SUCCESS) { + lim_log(pMac, LOGP, FL("reading protection cfg failed")); + return; + } + + if (pMac->lim.gLimProtectionControl == + WNI_CFG_FORCE_POLICY_PROTECTION_DISABLE) + qdf_mem_set((void *)&pMac->lim.cfgProtection, + sizeof(tCfgProtection), 0); + else { + pMac->lim.cfgProtection.fromlla = + (val >> WNI_CFG_PROTECTION_ENABLED_FROM_llA) & 1; + pMac->lim.cfgProtection.fromllb = + (val >> WNI_CFG_PROTECTION_ENABLED_FROM_llB) & 1; + pMac->lim.cfgProtection.fromllg = + (val >> WNI_CFG_PROTECTION_ENABLED_FROM_llG) & 1; + pMac->lim.cfgProtection.ht20 = + (val >> WNI_CFG_PROTECTION_ENABLED_HT_20) & 1; + pMac->lim.cfgProtection.nonGf = + (val >> WNI_CFG_PROTECTION_ENABLED_NON_GF) & 1; + pMac->lim.cfgProtection.lsigTxop = + (val >> WNI_CFG_PROTECTION_ENABLED_LSIG_TXOP) & 1; + pMac->lim.cfgProtection.rifs = + (val >> WNI_CFG_PROTECTION_ENABLED_RIFS) & 1; + pMac->lim.cfgProtection.obss = + (val >> WNI_CFG_PROTECTION_ENABLED_OBSS) & 1; + + } + } +} + +/** + * lim_handle_param_update() + * + ***FUNCTION: + * This function is use to post a message whenever need indicate + * there is update of config parameter. + * + ***PARAMS: + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * + * @param pMac - Pointer to Global MAC structure + * @param cfgId - ID of CFG parameter that got updated + * @return None + */ +void lim_handle_param_update(tpAniSirGlobal pMac, eUpdateIEsType cfgId) +{ + tSirMsgQ msg = { 0 }; + uint32_t status; + + PELOG3(lim_log + (pMac, LOG3, FL("Handling CFG parameter id %X update"), cfgId); + ) + switch (cfgId) { + case eUPDATE_IE_PROBE_BCN: + { + msg.type = SIR_LIM_UPDATE_BEACON; + status = lim_post_msg_api(pMac, &msg); + + if (status != TX_SUCCESS) + PELOGE(lim_log + (pMac, LOGE, + FL("Failed lim_post_msg_api %u"), status); + ) + break; + } + default: + break; + } +} + +/** + * lim_handle_cf_gparam_update() + * + ***FUNCTION: + * This function is called by lim_process_messages() to + * whenever SIR_CFG_PARAM_UPDATE_IND message is posted + * to LIM (due to a set operation on a CFG parameter). + * + ***PARAMS: + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * + * @param pMac - Pointer to Global MAC structure + * @param cfgId - ID of CFG parameter that got updated + * @return None + */ + +void lim_handle_cf_gparam_update(tpAniSirGlobal pMac, uint32_t cfgId) +{ + uint32_t val1, val2; + uint16_t val16; + tSirMacHTParametersInfo *pAmpduParamInfo; + + PELOG3(lim_log + (pMac, LOG3, FL("Handling CFG parameter id %X update"), cfgId); + ) + switch (cfgId) { + case WNI_CFG_WEP_DEFAULT_KEYID: + + /* !!LAC - when the default KeyID is changed, force all of the */ + /* keys and the keyID to be reprogrammed. this allows the */ + /* keys to change after the initial setting of the keys when the CFG was */ + /* applied at association time through CFG changes of the keys. */ + lim_set_default_key_id_and_keys(pMac); + + break; + + case WNI_CFG_EXCLUDE_UNENCRYPTED: + if (wlan_cfg_get_int(pMac, WNI_CFG_EXCLUDE_UNENCRYPTED, + &val1) != eSIR_SUCCESS) { + lim_log(pMac, LOGP, + FL("Unable to retrieve excludeUnencr from CFG")); + } + lim_log(pMac, LOGE, + FL("Unsupported CFG: WNI_CFG_EXCLUDE_UNENCRYPTED")); + + break; + + case WNI_CFG_ASSOCIATION_FAILURE_TIMEOUT: + if (pMac->lim.gLimMlmState != eLIM_MLM_WT_ASSOC_RSP_STATE) { + /* 'Change' timer for future activations */ + lim_deactivate_and_change_timer(pMac, + eLIM_ASSOC_FAIL_TIMER); + } + + break; + + case WNI_CFG_PROTECTION_ENABLED: + lim_set_cfg_protection(pMac, NULL); + break; + case WNI_CFG_PROBE_RSP_BCN_ADDNIE_FLAG: + { + tSirMsgQ msg = { 0 }; + uint32_t status; + + msg.type = SIR_LIM_UPDATE_BEACON; + + status = lim_post_msg_api(pMac, &msg); + + if (status != TX_SUCCESS) + PELOGE(lim_log + (pMac, LOGE, + FL("Failed lim_post_msg_api %u"), status); + ) + break; + } + + case WNI_CFG_MPDU_DENSITY: + if (wlan_cfg_get_int(pMac, WNI_CFG_HT_AMPDU_PARAMS, &val1) != + eSIR_SUCCESS) { + PELOGE(lim_log + (pMac, LOGE, + FL("could not retrieve HT AMPDU Param CFG")); + ) + break; + } + if (wlan_cfg_get_int(pMac, WNI_CFG_MPDU_DENSITY, &val2) != + eSIR_SUCCESS) { + PELOGE(lim_log + (pMac, LOGE, + FL("could not retrieve MPDU Density CFG")); + ) + break; + } + val16 = (uint16_t) val1; + pAmpduParamInfo = (tSirMacHTParametersInfo *) &val16; + pAmpduParamInfo->mpduDensity = (uint8_t) val2; + if (cfg_set_int + (pMac, WNI_CFG_HT_AMPDU_PARAMS, + *(uint8_t *) pAmpduParamInfo) != eSIR_SUCCESS) + PELOGE(lim_log + (pMac, LOGE, + FL("could not update HT AMPDU Param CFG")); + ) + + break; + case WNI_CFG_MAX_RX_AMPDU_FACTOR: + if (wlan_cfg_get_int(pMac, WNI_CFG_HT_AMPDU_PARAMS, &val1) != + eSIR_SUCCESS) { + PELOGE(lim_log + (pMac, LOGE, + FL("could not retrieve HT AMPDU Param CFG")); + ) + break; + } + if (wlan_cfg_get_int(pMac, WNI_CFG_MAX_RX_AMPDU_FACTOR, &val2) != + eSIR_SUCCESS) { + PELOGE(lim_log + (pMac, LOGE, + FL("could not retrieve AMPDU Factor CFG")); + ) + break; + } + val16 = (uint16_t) val1; + pAmpduParamInfo = (tSirMacHTParametersInfo *) &val16; + pAmpduParamInfo->maxRxAMPDUFactor = (uint8_t) val2; + if (cfg_set_int + (pMac, WNI_CFG_HT_AMPDU_PARAMS, + *(uint8_t *) pAmpduParamInfo) != eSIR_SUCCESS) + PELOGE(lim_log + (pMac, LOGE, + FL("could not update HT AMPDU Param CFG")); + ) + break; + + case WNI_CFG_DOT11_MODE: + if (wlan_cfg_get_int(pMac, WNI_CFG_DOT11_MODE, &val1) != + eSIR_SUCCESS) { + PELOGE(lim_log + (pMac, LOGE, + FL("could not retrieve Dot11 Mode CFG")); + ) + break; + } + break; + + case WNI_CFG_SCAN_IN_POWERSAVE: + if (wlan_cfg_get_int(pMac, WNI_CFG_SCAN_IN_POWERSAVE, &val1) != + eSIR_SUCCESS) { + lim_log(pMac, LOGE, + FL("Unable to get WNI_CFG_SCAN_IN_POWERSAVE ")); + break; + } + pMac->lim.gScanInPowersave = (uint8_t) val1; + break; + + case WNI_CFG_ASSOC_STA_LIMIT: + if (wlan_cfg_get_int(pMac, WNI_CFG_ASSOC_STA_LIMIT, &val1) != + eSIR_SUCCESS) { + lim_log(pMac, LOGE, + FL("Unable to get WNI_CFG_ASSOC_STA_LIMIT")); + break; + } + pMac->lim.gLimAssocStaLimit = (uint16_t) val1; + break; + default: + break; + } +} /*** end lim_handle_cf_gparam_update() ***/ + +/** + * lim_apply_configuration() + * + ***FUNCTION: + * This function is called to apply the configured parameters + * before joining or reassociating with a BSS or starting a BSS. + * + ***PARAMS: + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * + * @param pMac - Pointer to Global MAC structure + * @return None + */ + +void lim_apply_configuration(tpAniSirGlobal pMac, tpPESession psessionEntry) +{ + uint32_t val = 0, phyMode; + + PELOG2(lim_log(pMac, LOG2, FL("Applying config"));) + + psessionEntry->limSentCapsChangeNtf = false; + + lim_get_phy_mode(pMac, &phyMode, psessionEntry); + + /* Set default keyId and keys */ + lim_set_default_key_id_and_keys(pMac); + + lim_update_config(pMac, psessionEntry); + + lim_get_short_slot_from_phy_mode(pMac, psessionEntry, phyMode, + &psessionEntry->shortSlotTimeSupported); + + lim_set_cfg_protection(pMac, psessionEntry); + + /* Added for BT - AMP Support */ + if (LIM_IS_AP_ROLE(psessionEntry) || + LIM_IS_IBSS_ROLE(psessionEntry)) { + /* This check is required to ensure the beacon generation is not done + as a part of join request for a BT-AMP station */ + + if (psessionEntry->statypeForBss == STA_ENTRY_SELF) { + PELOG1(lim_log + (pMac, LOG1, + FL("Initializing BT-AMP beacon generation")); + ) + sch_set_beacon_interval(pMac, psessionEntry); + sch_set_fixed_beacon_fields(pMac, psessionEntry); + } + } + + if (wlan_cfg_get_int(pMac, WNI_CFG_SCAN_IN_POWERSAVE, &val) != + eSIR_SUCCESS) { + lim_log(pMac, LOGP, + FL("could not retrieve WNI_CFG_SCAN_IN_POWERSAVE")); + return; + } + + PELOG1(lim_log(pMac, LOG1, FL("pMac->lim.gScanInPowersave = %hu"), + pMac->lim.gScanInPowersave); + ) + pMac->lim.gScanInPowersave = (uint8_t) val; + +} /*** end lim_apply_configuration() ***/ + +/** + * lim_update_config + * + * FUNCTION: + * Update the local state from CFG database + * (This used to be dphUpdateConfig) + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param None + * @return None + */ + +static void lim_update_config(tpAniSirGlobal pMac, tpPESession psessionEntry) +{ + uint32_t val; + + sir_copy_mac_addr(pMac->lim.gLimMyMacAddr, psessionEntry->selfMacAddr); + + if (wlan_cfg_get_int(pMac, WNI_CFG_SHORT_PREAMBLE, &val) != eSIR_SUCCESS) + lim_log(pMac, LOGP, FL("cfg get short preamble failed")); + psessionEntry->beaconParams.fShortPreamble = (val) ? 1 : 0; + + /* In STA case this parameter is filled during the join request */ + if (LIM_IS_AP_ROLE(psessionEntry) || + LIM_IS_IBSS_ROLE(psessionEntry)) { + if (wlan_cfg_get_int(pMac, WNI_CFG_WME_ENABLED, &val) != + eSIR_SUCCESS) + lim_log(pMac, LOGP, FL("cfg get wme enabled failed")); + psessionEntry->limWmeEnabled = (val) ? 1 : 0; + } + + if (wlan_cfg_get_int(pMac, WNI_CFG_WSM_ENABLED, &val) != eSIR_SUCCESS) + lim_log(pMac, LOGP, FL("cfg get wsm enabled failed")); + psessionEntry->limWsmEnabled = (val) ? 1 : 0; + + if ((!psessionEntry->limWmeEnabled) && (psessionEntry->limWsmEnabled)) { + PELOGE(lim_log(pMac, LOGE, FL("Can't enable WSM without WME"));) + psessionEntry->limWsmEnabled = 0; + } + /* In STA , this parameter is filled during the join request */ + if (LIM_IS_AP_ROLE(psessionEntry) || LIM_IS_IBSS_ROLE(psessionEntry)) { + if (wlan_cfg_get_int(pMac, WNI_CFG_QOS_ENABLED, &val) != + eSIR_SUCCESS) + lim_log(pMac, LOGP, FL("cfg get qos enabled failed")); + psessionEntry->limQosEnabled = (val) ? 1 : 0; + } + if (wlan_cfg_get_int(pMac, WNI_CFG_HCF_ENABLED, &val) != eSIR_SUCCESS) + lim_log(pMac, LOGP, FL("cfg get hcf enabled failed")); + psessionEntry->limHcfEnabled = (val) ? 1 : 0; + + /* AP: WSM should enable HCF as well, for STA enable WSM only after */ + /* association response is received */ + if (psessionEntry->limWsmEnabled && LIM_IS_AP_ROLE(psessionEntry)) + psessionEntry->limHcfEnabled = 1; + + if (wlan_cfg_get_int(pMac, WNI_CFG_11D_ENABLED, &val) != eSIR_SUCCESS) + lim_log(pMac, LOGP, FL("cfg get 11d enabled failed")); + psessionEntry->lim11dEnabled = (val) ? 1 : 0; + + if (wlan_cfg_get_int(pMac, WNI_CFG_ASSOC_STA_LIMIT, &val) != eSIR_SUCCESS) { + lim_log(pMac, LOGP, FL("cfg get assoc sta limit failed")); + } + pMac->lim.gLimAssocStaLimit = (uint16_t) val; + + PELOG1(lim_log(pMac, LOG1, FL("Updated Lim shadow state based on CFG"));) +} diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_process_deauth_frame.c b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_process_deauth_frame.c new file mode 100644 index 0000000000000000000000000000000000000000..38cf09d79793fe3e59c40d0f48f19c241dbff356 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_process_deauth_frame.c @@ -0,0 +1,611 @@ +/* + * Copyright (c) 2011-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * + * This file lim_process_deauth_frame.cc contains the code + * for processing Deauthentication Frame. + * Author: Chandra Modumudi + * Date: 03/24/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + * + */ +#include "cds_api.h" +#include "ani_global.h" + +#include "utils_api.h" +#include "lim_types.h" +#include "lim_utils.h" +#include "lim_assoc_utils.h" +#include "lim_security_utils.h" +#include "lim_ser_des_utils.h" +#include "sch_api.h" +#include "lim_send_messages.h" + +/** + * lim_process_deauth_frame + * + ***FUNCTION: + * This function is called by limProcessMessageQueue() upon + * Deauthentication frame reception. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param pMac - Pointer to Global MAC structure + * @param *pRxPacketInfo - A pointer to Buffer descriptor + associated PDUs + * @return None + */ + +void +lim_process_deauth_frame(tpAniSirGlobal pMac, uint8_t *pRxPacketInfo, + tpPESession psessionEntry) +{ + uint8_t *pBody; + uint16_t aid, reasonCode; + tpSirMacMgmtHdr pHdr; + tLimMlmAssocCnf mlmAssocCnf; + tLimMlmDeauthInd mlmDeauthInd; + tpDphHashNode pStaDs; + tpPESession pRoamSessionEntry = NULL; + uint8_t roamSessionId; +#ifdef WLAN_FEATURE_11W + uint32_t frameLen; +#endif + int32_t frame_rssi; + + pHdr = WMA_GET_RX_MAC_HEADER(pRxPacketInfo); + + pBody = WMA_GET_RX_MPDU_DATA(pRxPacketInfo); + frame_rssi = (int32_t)WMA_GET_RX_RSSI_NORMALIZED(pRxPacketInfo); + + if (LIM_IS_STA_ROLE(psessionEntry) && + ((eLIM_SME_WT_DISASSOC_STATE == psessionEntry->limSmeState) || + (eLIM_SME_WT_DEAUTH_STATE == psessionEntry->limSmeState))) { + /*Every 15th deauth frame will be logged in kmsg */ + if (!(psessionEntry->deauthmsgcnt & 0xF)) { + PELOGE(lim_log(pMac, LOGE, + FL + ("received Deauth frame in DEAUTH_WT_STATE" + "(already processing previously received DEAUTH frame).." + "Dropping this.. Deauth Failed %d"), + ++psessionEntry->deauthmsgcnt); + ) + } else { + psessionEntry->deauthmsgcnt++; + } + return; + } + + if (lim_is_group_addr(pHdr->sa)) { + /* Received Deauth frame from a BC/MC address */ + /* Log error and ignore it */ + PELOGE(lim_log(pMac, LOGE, + FL("received Deauth frame from a BC/MC address")); + ) + + return; + } + + if (lim_is_group_addr(pHdr->da) && !lim_is_addr_bc(pHdr->da)) { + /* Received Deauth frame for a MC address */ + /* Log error and ignore it */ + PELOGE(lim_log(pMac, LOGE, + FL("received Deauth frame for a MC address")); + ) + + return; + } + if (!lim_validate_received_frame_a1_addr(pMac, + pHdr->da, psessionEntry)) { + lim_log(pMac, LOGE, + FL("rx frame doesn't have valid a1 address, drop it")); + return; + } +#ifdef WLAN_FEATURE_11W + /* PMF: If this session is a PMF session, then ensure that this frame was protected */ + if (psessionEntry->limRmfEnabled + && (WMA_GET_RX_DPU_FEEDBACK(pRxPacketInfo) & + DPU_FEEDBACK_UNPROTECTED_ERROR)) { + PELOGE(lim_log + (pMac, LOGE, + FL("received an unprotected deauth from AP")); + ) + + /* + * When 11w offload is enabled then + * firmware should not fwd this frame + */ + if (LIM_IS_STA_ROLE(psessionEntry) && pMac->pmf_offload) { + lim_log(pMac, LOGE, + FL("11w offload is enable,unprotected deauth is not expected") + ); + return; + } + + /* If the frame received is unprotected, forward it to the supplicant to initiate */ + /* an SA query */ + frameLen = WMA_GET_RX_PAYLOAD_LEN(pRxPacketInfo); + + /* send the unprotected frame indication to SME */ + lim_send_sme_unprotected_mgmt_frame_ind(pMac, pHdr->fc.subType, + (uint8_t *) pHdr, + (frameLen + + sizeof(tSirMacMgmtHdr)), + psessionEntry->smeSessionId, + psessionEntry); + return; + } +#endif + + /* Get reasonCode from Deauthentication frame body */ + reasonCode = sir_read_u16(pBody); + + PELOGE(lim_log(pMac, LOGE, + FL("Received Deauth frame for Addr: " MAC_ADDRESS_STR + "(mlm state = %s, sme state = %d systemrole = %d " + "RSSI = %d) with reason code %d [%s] from " + MAC_ADDRESS_STR), MAC_ADDR_ARRAY(pHdr->da), + lim_mlm_state_str(psessionEntry->limMlmState), + psessionEntry->limSmeState, + GET_LIM_SYSTEM_ROLE(psessionEntry), frame_rssi, + reasonCode, lim_dot11_reason_str(reasonCode), + MAC_ADDR_ARRAY(pHdr->sa)); + ) + lim_diag_event_report(pMac, WLAN_PE_DIAG_DEAUTH_FRAME_EVENT, + psessionEntry, 0, reasonCode); + + if (lim_check_disassoc_deauth_ack_pending(pMac, (uint8_t *) pHdr->sa)) { + PELOGE(lim_log(pMac, LOGE, + FL + ("Ignore the Deauth received, while waiting for ack of " + "disassoc/deauth")); + ) + lim_clean_up_disassoc_deauth_req(pMac, (uint8_t *) pHdr->sa, 1); + return; + } + + if (LIM_IS_AP_ROLE(psessionEntry)) { + switch (reasonCode) { + case eSIR_MAC_UNSPEC_FAILURE_REASON: + case eSIR_MAC_DEAUTH_LEAVING_BSS_REASON: + /* Valid reasonCode in received Deauthentication frame */ + break; + + default: + /* Invalid reasonCode in received Deauthentication frame */ + /* Log error and ignore the frame */ + PELOGE(lim_log(pMac, LOGE, + FL + ("received Deauth frame with invalid reasonCode %d from " + MAC_ADDRESS_STR), reasonCode, + MAC_ADDR_ARRAY(pHdr->sa)); + ) + + break; + } + } else if (LIM_IS_STA_ROLE(psessionEntry)) { + switch (reasonCode) { + case eSIR_MAC_UNSPEC_FAILURE_REASON: + case eSIR_MAC_PREV_AUTH_NOT_VALID_REASON: + case eSIR_MAC_DEAUTH_LEAVING_BSS_REASON: + case eSIR_MAC_CLASS2_FRAME_FROM_NON_AUTH_STA_REASON: + case eSIR_MAC_CLASS3_FRAME_FROM_NON_ASSOC_STA_REASON: + case eSIR_MAC_STA_NOT_PRE_AUTHENTICATED_REASON: + /* Valid reasonCode in received Deauth frame */ + break; + + default: + /* Invalid reasonCode in received Deauth frame */ + /* Log error and ignore the frame */ + PELOGE(lim_log(pMac, LOGE, + FL + ("received Deauth frame with invalid reasonCode %d from " + MAC_ADDRESS_STR), reasonCode, + MAC_ADDR_ARRAY(pHdr->sa)); + ) + + break; + } + } else { + /* Received Deauth frame in either IBSS */ + /* or un-known role. Log and ignore it */ + lim_log(pMac, LOGE, + FL + ("received Deauth frame with reasonCode %d in role %d from " + MAC_ADDRESS_STR), reasonCode, + GET_LIM_SYSTEM_ROLE(psessionEntry), + MAC_ADDR_ARRAY(pHdr->sa)); + + return; + } + + /** If we are in the middle of ReAssoc, a few things could happen: + * - STA is reassociating to current AP, and receives deauth from: + * a) current AP + * b) other AP + * - STA is reassociating to a new AP, and receives deauth from: + * c) current AP + * d) reassoc AP + * e) other AP + * + * The logic is: + * 1) If rcv deauth from an AP other than the one we're trying to + * reassociate with, then drop the deauth frame (case b, c, e) + * 2) If rcv deauth from the "new" reassoc AP (case d), then restore + * context with previous AP and send SME_REASSOC_RSP failure. + * 3) If rcv deauth from the reassoc AP, which is also the same + * AP we're currently associated with (case a), then proceed + * with normal deauth processing. + */ + pRoamSessionEntry = + pe_find_session_by_bssid(pMac, psessionEntry->limReAssocbssId, + &roamSessionId); + + if (lim_is_reassoc_in_progress(pMac, psessionEntry) + || lim_is_reassoc_in_progress(pMac, pRoamSessionEntry)) { + if (!IS_REASSOC_BSSID(pMac, pHdr->sa, psessionEntry)) { + PELOGE(lim_log + (pMac, LOGE, + FL("Rcv Deauth from unknown/different " + "AP while ReAssoc. Ignore " MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(pHdr->sa)); + ) + PELOGE(lim_log + (pMac, LOGE, + FL(" limReAssocbssId : " MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(psessionEntry-> + limReAssocbssId)); + ) + return; + } + + /** Received deauth from the new AP to which we tried to ReAssociate. + * Drop ReAssoc and Restore the Previous context( current connected AP). + */ + if (!IS_CURRENT_BSSID(pMac, pHdr->sa, psessionEntry)) { + PELOGE(lim_log + (pMac, LOGE, + FL("received DeAuth from the New AP to " + "which ReAssoc is sent " MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(pHdr->sa)); + ) + PELOGE(lim_log + (pMac, LOGE, + FL(" psessionEntry->bssId: " + MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(psessionEntry->bssId)); + ) + lim_restore_pre_reassoc_state(pMac, + eSIR_SME_REASSOC_REFUSED, + reasonCode, + psessionEntry); + return; + } + } + + /* If received DeAuth from AP other than the one we're trying to join with + * nor associated with, then ignore deauth and delete Pre-auth entry. + */ + if (!LIM_IS_AP_ROLE(psessionEntry)) { + if (!IS_CURRENT_BSSID(pMac, pHdr->bssId, psessionEntry)) { + PELOGE(lim_log + (pMac, LOGE, + FL("received DeAuth from an AP other " + "than we're trying to join. Ignore. " + MAC_ADDRESS_STR), MAC_ADDR_ARRAY(pHdr->sa)); + ) + if (lim_search_pre_auth_list(pMac, pHdr->sa)) { + PELOG1(lim_log + (pMac, LOG1, + FL("Preauth entry exist. " + "Deleting... ")); + ) + lim_delete_pre_auth_node(pMac, pHdr->sa); + } + return; + } + } + + pStaDs = + dph_lookup_hash_entry(pMac, pHdr->sa, &aid, + &psessionEntry->dph.dphHashTable); + + /* Check for pre-assoc states */ + switch (GET_LIM_SYSTEM_ROLE(psessionEntry)) { + case eLIM_STA_ROLE: + switch (psessionEntry->limMlmState) { + case eLIM_MLM_WT_AUTH_FRAME2_STATE: + /** + * AP sent Deauth frame while waiting + * for Auth frame2. Report Auth failure + * to SME. + */ + + /* Log error */ + PELOG1(lim_log(pMac, LOG1, + FL + ("received Deauth frame state %X with failure " + "code %d from " MAC_ADDRESS_STR), + psessionEntry->limMlmState, reasonCode, + MAC_ADDR_ARRAY(pHdr->sa)); + ) + + lim_restore_from_auth_state(pMac, + eSIR_SME_DEAUTH_WHILE_JOIN, + reasonCode, psessionEntry); + + return; + + case eLIM_MLM_AUTHENTICATED_STATE: + lim_log(pMac, LOG1, + FL("received Deauth frame state %X with " + "reasonCode=%d from " MAC_ADDRESS_STR), + psessionEntry->limMlmState, reasonCode, + MAC_ADDR_ARRAY(pHdr->sa)); + /* / Issue Deauth Indication to SME. */ + qdf_mem_copy((uint8_t *) &mlmDeauthInd.peerMacAddr, + pHdr->sa, sizeof(tSirMacAddr)); + mlmDeauthInd.reasonCode = reasonCode; + + psessionEntry->limMlmState = eLIM_MLM_IDLE_STATE; + MTRACE(mac_trace + (pMac, TRACE_CODE_MLM_STATE, + psessionEntry->peSessionId, + psessionEntry->limMlmState)); + + lim_post_sme_message(pMac, + LIM_MLM_DEAUTH_IND, + (uint32_t *) &mlmDeauthInd); + return; + + case eLIM_MLM_WT_ASSOC_RSP_STATE: + /** + * AP may have 'aged-out' our Pre-auth + * context. Delete local pre-auth context + * if any and issue ASSOC_CNF to SME. + */ + lim_log(pMac, LOG1, + FL("received Deauth frame state %X with " + "reasonCode=%d from " MAC_ADDRESS_STR), + psessionEntry->limMlmState, reasonCode, + MAC_ADDR_ARRAY(pHdr->sa)); + if (lim_search_pre_auth_list(pMac, pHdr->sa)) + lim_delete_pre_auth_node(pMac, pHdr->sa); + + if (psessionEntry->pLimMlmJoinReq) { + qdf_mem_free(psessionEntry->pLimMlmJoinReq); + psessionEntry->pLimMlmJoinReq = NULL; + } + + mlmAssocCnf.resultCode = eSIR_SME_DEAUTH_WHILE_JOIN; + mlmAssocCnf.protStatusCode = reasonCode; + + /* PE session Id */ + mlmAssocCnf.sessionId = psessionEntry->peSessionId; + + psessionEntry->limMlmState = + psessionEntry->limPrevMlmState; + MTRACE(mac_trace + (pMac, TRACE_CODE_MLM_STATE, + psessionEntry->peSessionId, + psessionEntry->limMlmState)); + + /* Deactive Association response timeout */ + lim_deactivate_and_change_timer(pMac, + eLIM_ASSOC_FAIL_TIMER); + + lim_post_sme_message(pMac, + LIM_MLM_ASSOC_CNF, + (uint32_t *) &mlmAssocCnf); + + return; + + case eLIM_MLM_WT_ADD_STA_RSP_STATE: + psessionEntry->fDeauthReceived = true; + PELOGW(lim_log(pMac, LOGW, + FL + ("Received Deauth frame in state %X with Reason " + "Code %d from Peer" MAC_ADDRESS_STR), + psessionEntry->limMlmState, reasonCode, + MAC_ADDR_ARRAY(pHdr->sa)); + ) + return; + + case eLIM_MLM_IDLE_STATE: + case eLIM_MLM_LINK_ESTABLISHED_STATE: +#ifdef FEATURE_WLAN_TDLS + if ((NULL != pStaDs) + && (STA_ENTRY_TDLS_PEER == pStaDs->staType)) { + PELOGE(lim_log + (pMac, LOGE, + FL + ("received Deauth frame in state %X with " + "reason code %d from Tdls peer" + MAC_ADDRESS_STR), + psessionEntry->limMlmState, reasonCode, + MAC_ADDR_ARRAY(pHdr->sa)); + ) + lim_send_sme_tdls_del_sta_ind(pMac, pStaDs, + psessionEntry, + reasonCode); + return; + } else { + + /* + * Delete all the TDLS peers only if Deauth + * is received from the AP + */ + if (IS_CURRENT_BSSID(pMac, pHdr->sa, psessionEntry)) + lim_delete_tdls_peers(pMac, psessionEntry); +#endif + /** + * This could be Deauthentication frame from + * a BSS with which pre-authentication was + * performed. Delete Pre-auth entry if found. + */ + if (lim_search_pre_auth_list(pMac, pHdr->sa)) + lim_delete_pre_auth_node(pMac, pHdr->sa); +#ifdef FEATURE_WLAN_TDLS + } +#endif + break; + + case eLIM_MLM_WT_REASSOC_RSP_STATE: + lim_log(pMac, LOGE, + FL("received Deauth frame state %X with " + "reasonCode=%d from " MAC_ADDRESS_STR), + psessionEntry->limMlmState, reasonCode, + MAC_ADDR_ARRAY(pHdr->sa)); + break; + + case eLIM_MLM_WT_FT_REASSOC_RSP_STATE: + PELOGE(lim_log(pMac, LOGE, + FL + ("received Deauth frame in FT state %X with " + "reasonCode=%d from " MAC_ADDRESS_STR), + psessionEntry->limMlmState, reasonCode, + MAC_ADDR_ARRAY(pHdr->sa)); + ) + break; + + default: + PELOGE(lim_log(pMac, LOGE, + FL + ("received Deauth frame in state %X with " + "reasonCode=%d from " MAC_ADDRESS_STR), + psessionEntry->limMlmState, reasonCode, + MAC_ADDR_ARRAY(pHdr->sa)); + ) + return; + } + break; + + case eLIM_STA_IN_IBSS_ROLE: + break; + + case eLIM_AP_ROLE: + break; + + default: + + return; + } /* end switch (pMac->lim.gLimSystemRole) */ + + /** + * Extract 'associated' context for STA, if any. + * This is maintained by DPH and created by LIM. + */ + if (NULL == pStaDs) { + lim_log(pMac, LOGE, FL("pStaDs is NULL")); + return; + } + + if ((pStaDs->mlmStaContext.mlmState == eLIM_MLM_WT_DEL_STA_RSP_STATE) || + (pStaDs->mlmStaContext.mlmState == eLIM_MLM_WT_DEL_BSS_RSP_STATE)) { + /** + * Already in the process of deleting context for the peer + * and received Deauthentication frame. Log and Ignore. + */ + PELOGE(lim_log(pMac, LOGE, + FL + ("received Deauth frame from peer that is in state %X, addr " + MAC_ADDRESS_STR), pStaDs->mlmStaContext.mlmState, + MAC_ADDR_ARRAY(pHdr->sa)); + ) + return; + } + pStaDs->mlmStaContext.disassocReason = (tSirMacReasonCodes) reasonCode; + pStaDs->mlmStaContext.cleanupTrigger = eLIM_PEER_ENTITY_DEAUTH; + + /* / Issue Deauth Indication to SME. */ + qdf_mem_copy((uint8_t *) &mlmDeauthInd.peerMacAddr, + pStaDs->staAddr, sizeof(tSirMacAddr)); + mlmDeauthInd.reasonCode = + (uint8_t) pStaDs->mlmStaContext.disassocReason; + mlmDeauthInd.deauthTrigger = eLIM_PEER_ENTITY_DEAUTH; + + /* + * If we're in the middle of ReAssoc and received deauth from + * the ReAssoc AP, then notify SME by sending REASSOC_RSP with + * failure result code. SME will post the disconnect to the + * supplicant and the latter would start a fresh assoc. + */ + if (lim_is_reassoc_in_progress(pMac, psessionEntry)) { + /** + * AP may have 'aged-out' our Pre-auth + * context. Delete local pre-auth context + * if any and issue REASSOC_CNF to SME. + */ + if (lim_search_pre_auth_list(pMac, pHdr->sa)) + lim_delete_pre_auth_node(pMac, pHdr->sa); + + if (psessionEntry->limAssocResponseData) { + qdf_mem_free(psessionEntry->limAssocResponseData); + psessionEntry->limAssocResponseData = NULL; + } + + PELOGE(lim_log(pMac, LOGE, FL("Rcv Deauth from ReAssoc AP. " + "Issue REASSOC_CNF. ")); + ) + /* + * TODO: Instead of overloading eSIR_SME_FT_REASSOC_TIMEOUT_FAILURE + * it would have been good to define/use a different failure type. + * Using eSIR_SME_FT_REASSOC_FAILURE does not seem to clean-up + * properly and we end up seeing "transmit queue timeout". + */ + lim_post_reassoc_failure(pMac, + eSIR_SME_FT_REASSOC_TIMEOUT_FAILURE, + eSIR_MAC_UNSPEC_FAILURE_STATUS, + psessionEntry); + return; + } + /* reset the deauthMsgCnt here since we are able to Process + * the deauth frame and sending up the indication as well */ + if (psessionEntry->deauthmsgcnt != 0) + psessionEntry->deauthmsgcnt = 0; + + if (LIM_IS_STA_ROLE(psessionEntry)) + wma_tx_abort(psessionEntry->smeSessionId); + + lim_update_lost_link_info(pMac, psessionEntry, frame_rssi); + + /* / Deauthentication from peer MAC entity */ + if (LIM_IS_STA_ROLE(psessionEntry)) + lim_post_sme_message(pMac, LIM_MLM_DEAUTH_IND, + (uint32_t *) &mlmDeauthInd); + + /* send eWNI_SME_DEAUTH_IND to SME */ + lim_send_sme_deauth_ind(pMac, pStaDs, psessionEntry); + return; + +} /*** end lim_process_deauth_frame() ***/ diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_process_disassoc_frame.c b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_process_disassoc_frame.c new file mode 100644 index 0000000000000000000000000000000000000000..af9dbd134ef935aa5b494a6f66a2efef83c9f6fc --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_process_disassoc_frame.c @@ -0,0 +1,400 @@ +/* + * Copyright (c) 2011-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * + * This file lim_process_disassoc_frame.cc contains the code + * for processing Disassocation Frame. + * Author: Chandra Modumudi + * Date: 03/24/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + * + */ +#include "cds_api.h" +#include "wni_api.h" +#include "sir_api.h" +#include "ani_global.h" +#include "wni_cfg.h" + +#include "utils_api.h" +#include "lim_types.h" +#include "lim_utils.h" +#include "lim_assoc_utils.h" +#include "lim_security_utils.h" +#include "lim_ser_des_utils.h" +#include "lim_send_messages.h" +#include "sch_api.h" + +/** + * lim_process_disassoc_frame + * + ***FUNCTION: + * This function is called by limProcessMessageQueue() upon + * Disassociation frame reception. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * DPH drops packets for STA with 'valid' bit in pStaDs set to '0'. + * + ***NOTE: + * + * @param pMac - Pointer to Global MAC structure + * @param *pRxPacketInfo - A pointer to Rx packet info structure + * @return None + */ +void +lim_process_disassoc_frame(tpAniSirGlobal pMac, uint8_t *pRxPacketInfo, + tpPESession psessionEntry) +{ + uint8_t *pBody; + uint16_t aid, reasonCode; + tpSirMacMgmtHdr pHdr; + tpDphHashNode pStaDs; + tLimMlmDisassocInd mlmDisassocInd; +#ifdef WLAN_FEATURE_11W + uint32_t frameLen; +#endif + int32_t frame_rssi; + + pHdr = WMA_GET_RX_MAC_HEADER(pRxPacketInfo); + pBody = WMA_GET_RX_MPDU_DATA(pRxPacketInfo); + + frame_rssi = (int32_t)WMA_GET_RX_RSSI_NORMALIZED(pRxPacketInfo); + + if (lim_is_group_addr(pHdr->sa)) { + /* Received Disassoc frame from a BC/MC address */ + /* Log error and ignore it */ + PELOGE(lim_log(pMac, LOGE, + FL + ("received Disassoc frame from a BC/MC address")); + ) + + return; + } + + if (lim_is_group_addr(pHdr->da) && !lim_is_addr_bc(pHdr->da)) { + /* Received Disassoc frame for a MC address */ + /* Log error and ignore it */ + PELOGE(lim_log(pMac, LOGE, + FL("received Disassoc frame for a MC address")); + ) + + return; + } + if (!lim_validate_received_frame_a1_addr(pMac, + pHdr->da, psessionEntry)) { + lim_log(pMac, LOGE, + FL("rx frame doesn't have valid a1 address, drop it")); + return; + } + + if (LIM_IS_STA_ROLE(psessionEntry) && + ((eLIM_SME_WT_DISASSOC_STATE == psessionEntry->limSmeState) || + (eLIM_SME_WT_DEAUTH_STATE == psessionEntry->limSmeState))) { + if (!(psessionEntry->disassocmsgcnt & 0xF)) { + pe_info("received Disassoc frame in %s" + "(already processing previously received Disassoc frame)" + "Dropping this.. Disassoc Failed %d", + lim_sme_state_str(psessionEntry->limSmeState), + ++psessionEntry->disassocmsgcnt); + } else { + psessionEntry->disassocmsgcnt++; + } + return; + } +#ifdef WLAN_FEATURE_11W + /* PMF: If this session is a PMF session, then ensure that this frame was protected */ + if (psessionEntry->limRmfEnabled + && (WMA_GET_RX_DPU_FEEDBACK(pRxPacketInfo) & + DPU_FEEDBACK_UNPROTECTED_ERROR)) { + PELOGE(lim_log + (pMac, LOGE, + FL("received an unprotected disassoc from AP")); + ) + + /* + * When 11w offload is enabled then + * firmware should not fwd this frame + */ + if (LIM_IS_STA_ROLE(psessionEntry) && pMac->pmf_offload) { + lim_log(pMac, LOGE, + FL("11w offload is enable,unprotected disassoc is not expected") + ); + return; + } + + /* If the frame received is unprotected, forward it to the supplicant to initiate */ + /* an SA query */ + frameLen = WMA_GET_RX_PAYLOAD_LEN(pRxPacketInfo); + /* send the unprotected frame indication to SME */ + lim_send_sme_unprotected_mgmt_frame_ind(pMac, pHdr->fc.subType, + (uint8_t *) pHdr, + (frameLen + + sizeof(tSirMacMgmtHdr)), + psessionEntry->smeSessionId, + psessionEntry); + return; + } +#endif + + /* Get reasonCode from Disassociation frame body */ + reasonCode = sir_read_u16(pBody); + + PELOG2(lim_log(pMac, LOGE, + FL("Received Disassoc frame for Addr: " MAC_ADDRESS_STR + "(mlm state=%s, sme state=%d RSSI=%d)," + "with reason code %d [%s] from " MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(pHdr->da), + lim_mlm_state_str(psessionEntry->limMlmState), + psessionEntry->limSmeState, frame_rssi, reasonCode, + lim_dot11_reason_str(reasonCode), MAC_ADDR_ARRAY(pHdr->sa)); + ) + lim_diag_event_report(pMac, WLAN_PE_DIAG_DISASSOC_FRAME_EVENT, + psessionEntry, 0, reasonCode); + /** + * Extract 'associated' context for STA, if any. + * This is maintained by DPH and created by LIM. + */ + pStaDs = + dph_lookup_hash_entry(pMac, pHdr->sa, &aid, + &psessionEntry->dph.dphHashTable); + + if (pStaDs == NULL) { + /** + * Disassociating STA is not associated. + * Log error. + */ + PELOGE(lim_log(pMac, LOGE, + FL + ("received Disassoc frame from STA that does not have context " + "reasonCode=%d, addr " MAC_ADDRESS_STR), + reasonCode, MAC_ADDR_ARRAY(pHdr->sa)); + ) + + return; + } + + if (lim_check_disassoc_deauth_ack_pending(pMac, (uint8_t *) pHdr->sa)) { + PELOGE(lim_log(pMac, LOGE, + FL("Ignore the DisAssoc received, while waiting " + "for ack of disassoc/deauth")); + ) + lim_clean_up_disassoc_deauth_req(pMac, (uint8_t *) pHdr->sa, 1); + return; + } + + if (psessionEntry->disassocmsgcnt != 0) + psessionEntry->disassocmsgcnt = 0; + + /** If we are in the Wait for ReAssoc Rsp state */ + if (lim_is_reassoc_in_progress(pMac, psessionEntry)) { + /** If we had received the DisAssoc from, + * a. the Current AP during ReAssociate to different AP in same ESS + * b. Unknown AP + * drop/ignore the DisAssoc received + */ + if (!IS_REASSOC_BSSID(pMac, pHdr->sa, psessionEntry)) { + PELOGE(lim_log + (pMac, LOGE, + FL("Ignore the DisAssoc received, while " + "Processing ReAssoc with different/unknown AP")); + ) + return; + } + /** If the Disassoc is received from the new AP to which we tried to ReAssociate + * Drop ReAssoc and Restore the Previous context( current connected AP). + */ + if (!IS_CURRENT_BSSID(pMac, pHdr->sa, psessionEntry)) { + PELOGW(lim_log + (pMac, LOGW, + FL + ("received Disassoc from the New AP to which ReAssoc is sent ")); + ) + lim_restore_pre_reassoc_state(pMac, + eSIR_SME_REASSOC_REFUSED, + reasonCode, + psessionEntry); + return; + } + } + + if (LIM_IS_AP_ROLE(psessionEntry)) { + switch (reasonCode) { + case eSIR_MAC_UNSPEC_FAILURE_REASON: + case eSIR_MAC_DISASSOC_DUE_TO_INACTIVITY_REASON: + case eSIR_MAC_DISASSOC_LEAVING_BSS_REASON: + case eSIR_MAC_MIC_FAILURE_REASON: + case eSIR_MAC_4WAY_HANDSHAKE_TIMEOUT_REASON: + case eSIR_MAC_GR_KEY_UPDATE_TIMEOUT_REASON: + case eSIR_MAC_RSN_IE_MISMATCH_REASON: + case eSIR_MAC_1X_AUTH_FAILURE_REASON: + /* Valid reasonCode in received Disassociation frame */ + break; + + default: + /* Invalid reasonCode in received Disassociation frame */ + PELOGE(lim_log(pMac, LOGE, + FL + ("received Disassoc frame with invalid reasonCode " + "%d from " MAC_ADDRESS_STR), reasonCode, + MAC_ADDR_ARRAY(pHdr->sa)); + ) + break; + } + } else if (LIM_IS_STA_ROLE(psessionEntry) && + ((psessionEntry->limSmeState != eLIM_SME_WT_JOIN_STATE) && + (psessionEntry->limSmeState != eLIM_SME_WT_AUTH_STATE) && + (psessionEntry->limSmeState != eLIM_SME_WT_ASSOC_STATE) && + (psessionEntry->limSmeState != eLIM_SME_WT_REASSOC_STATE))) { + switch (reasonCode) { + case eSIR_MAC_DEAUTH_LEAVING_BSS_REASON: + case eSIR_MAC_DISASSOC_LEAVING_BSS_REASON: + /* Valid reasonCode in received Disassociation frame */ + /* as long as we're not about to channel switch */ + if (psessionEntry->gLimChannelSwitch.state != + eLIM_CHANNEL_SWITCH_IDLE) { + lim_log(pMac, LOGE, + FL + ("Ignoring disassoc frame due to upcoming " + "channel switch, from " + MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(pHdr->sa)); + return; + } + break; + + default: + break; + } + } else { + /* Received Disassociation frame in either IBSS */ + /* or un-known role. Log and ignore it */ + lim_log(pMac, LOGE, + FL + ("received Disassoc frame with invalid reasonCode %d in role " + "%d in sme state %d from " MAC_ADDRESS_STR), reasonCode, + GET_LIM_SYSTEM_ROLE(psessionEntry), psessionEntry->limSmeState, + MAC_ADDR_ARRAY(pHdr->sa)); + + return; + } + + if ((pStaDs->mlmStaContext.mlmState == eLIM_MLM_WT_DEL_STA_RSP_STATE) || + (pStaDs->mlmStaContext.mlmState == eLIM_MLM_WT_DEL_BSS_RSP_STATE)) { + /** + * Already in the process of deleting context for the peer + * and received Disassociation frame. Log and Ignore. + */ + PELOGE(lim_log(pMac, LOGE, + FL("received Disassoc frame in state %d from " + MAC_ADDRESS_STR), + pStaDs->mlmStaContext.mlmState, + MAC_ADDR_ARRAY(pHdr->sa)); + ) + + return; + } +#ifdef FEATURE_WLAN_TDLS + /** + * Delete all the TDLS peers only if Disassoc is received + * from the AP + */ + if ((LIM_IS_STA_ROLE(psessionEntry)) && + ((pStaDs->mlmStaContext.mlmState == + eLIM_MLM_LINK_ESTABLISHED_STATE) || + (pStaDs->mlmStaContext.mlmState == + eLIM_MLM_IDLE_STATE)) && + (IS_CURRENT_BSSID(pMac, pHdr->sa, psessionEntry))) + lim_delete_tdls_peers(pMac, psessionEntry); +#endif + + if (pStaDs->mlmStaContext.mlmState != eLIM_MLM_LINK_ESTABLISHED_STATE) { + /** + * Requesting STA is in some 'transient' state? + * Log error. + */ + if (pStaDs->mlmStaContext.mlmState == + eLIM_MLM_WT_ASSOC_CNF_STATE) + pStaDs->mlmStaContext.updateContext = 1; + + PELOGE(lim_log(pMac, LOGE, + FL + ("received Disassoc frame from peer that is in state %X, addr " + MAC_ADDRESS_STR), pStaDs->mlmStaContext.mlmState, + MAC_ADDR_ARRAY(pHdr->sa)); + ) + + } /* if (pStaDs->mlmStaContext.mlmState != eLIM_MLM_LINK_ESTABLISHED_STATE) */ + + pStaDs->mlmStaContext.cleanupTrigger = eLIM_PEER_ENTITY_DISASSOC; + pStaDs->mlmStaContext.disassocReason = (tSirMacReasonCodes) reasonCode; + + /* Issue Disassoc Indication to SME. */ + qdf_mem_copy((uint8_t *) &mlmDisassocInd.peerMacAddr, + (uint8_t *) pStaDs->staAddr, sizeof(tSirMacAddr)); + mlmDisassocInd.reasonCode = + (uint8_t) pStaDs->mlmStaContext.disassocReason; + mlmDisassocInd.disassocTrigger = eLIM_PEER_ENTITY_DISASSOC; + + /* Update PE session Id */ + mlmDisassocInd.sessionId = psessionEntry->peSessionId; + + if (lim_is_reassoc_in_progress(pMac, psessionEntry)) { + + /* If we're in the middle of ReAssoc and received disassoc from + * the ReAssoc AP, then notify SME by sending REASSOC_RSP with + * failure result code. By design, SME will then issue "Disassoc" + * and cleanup will happen at that time. + */ + PELOGE(lim_log + (pMac, LOGE, + FL("received Disassoc from AP while waiting " + "for Reassoc Rsp")); + ) + + if (psessionEntry->limAssocResponseData) { + qdf_mem_free(psessionEntry->limAssocResponseData); + psessionEntry->limAssocResponseData = NULL; + } + + lim_restore_pre_reassoc_state(pMac, eSIR_SME_REASSOC_REFUSED, + reasonCode, psessionEntry); + return; + } + + lim_update_lost_link_info(pMac, psessionEntry, frame_rssi); + lim_post_sme_message(pMac, LIM_MLM_DISASSOC_IND, + (uint32_t *) &mlmDisassocInd); + + /* send eWNI_SME_DISASSOC_IND to SME */ + lim_send_sme_disassoc_ind(pMac, pStaDs, psessionEntry); + + return; +} /*** end lim_process_disassoc_frame() ***/ diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_process_message_queue.c b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_process_message_queue.c new file mode 100644 index 0000000000000000000000000000000000000000..f2796eecd5f68b5d4bc4bdc036b668996c8c9afe --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_process_message_queue.c @@ -0,0 +1,2277 @@ +/* + * Copyright (c) 2011-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * This file lim ProcessMessageQueue.cc contains the code + * for processing LIM message Queue. + * Author: Chandra Modumudi + * Date: 02/11/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + * + */ +#include "cds_api.h" +#include "wni_api.h" +#include "wma_types.h" + +#include "wni_cfg.h" +#include "cfg_api.h" +#include "sir_common.h" +#include "utils_api.h" +#include "lim_types.h" +#include "lim_utils.h" +#include "lim_assoc_utils.h" +#include "lim_prop_exts_utils.h" + +#include "lim_admit_control.h" +#include "lim_ibss_peer_mgmt.h" +#include "sch_api.h" +#include "lim_ft_defs.h" +#include "lim_session.h" +#include "lim_send_messages.h" + +#include "rrm_api.h" + +#include "lim_ft.h" + +#include "qdf_types.h" +#include "cds_packet.h" +#include "qdf_mem.h" +#include "cds_concurrency.h" +#include "nan_datapath.h" + +void lim_log_session_states(tpAniSirGlobal pMac); +static void lim_process_normal_hdd_msg(tpAniSirGlobal mac_ctx, + struct sSirMsgQ *msg, uint8_t rsp_reqd); + +/** + * lim_process_dual_mac_cfg_resp() - Process set dual mac config response + * @mac: Global MAC pointer + * @body: Set dual mac config response in sir_dual_mac_config_resp format + * + * Process the set dual mac config response and post the message + * to SME to process this further and release the active + * command list + * + * Return: None + */ +static void lim_process_dual_mac_cfg_resp(tpAniSirGlobal mac, void *body) +{ + struct sir_dual_mac_config_resp *resp, *param; + uint32_t len, fail_resp = 0; + tSirMsgQ msg; + + resp = (struct sir_dual_mac_config_resp *)body; + if (!resp) { + lim_log(mac, LOGE, FL("Set dual mac cfg param is NULL")); + fail_resp = 1; + /* Not returning here. If possible, let us proceed + * and send fail response to SME + */ + } + + len = sizeof(*param); + + param = qdf_mem_malloc(len); + if (!param) { + lim_log(mac, LOGE, FL("Fail to allocate memory")); + /* Memory allocation for param failed. + * Cannot send fail status back to SME + */ + return; + } + + if (fail_resp) { + lim_log(mac, LOGE, FL("Send fail status to SME")); + param->status = SET_HW_MODE_STATUS_ECANCELED; + } else { + param->status = resp->status; + /* + * TODO: Update this HW mode info in any UMAC params, if needed + */ + } + + msg.type = eWNI_SME_SET_DUAL_MAC_CFG_RESP; + msg.bodyptr = param; + msg.bodyval = 0; + lim_log(mac, LOG1, FL("Send eWNI_SME_SET_DUAL_MAC_CFG_RESP to SME")); + lim_sys_process_mmh_msg_api(mac, &msg, ePROT); + return; +} + +/** + * lim_process_set_hw_mode_resp() - Process set HW mode response + * @mac: Global MAC pointer + * @body: Set HW mode response in sir_set_hw_mode_resp format + * + * Process the set HW mode response and post the message + * to SME to process this further and release the active + * command list + * + * Return: None + */ +static void lim_process_set_hw_mode_resp(tpAniSirGlobal mac, void *body) +{ + struct sir_set_hw_mode_resp *resp, *param; + uint32_t len, i, fail_resp = 0; + tSirMsgQ msg; + + resp = (struct sir_set_hw_mode_resp *)body; + if (!resp) { + lim_log(mac, LOGE, FL("Set HW mode param is NULL")); + fail_resp = 1; + /* Not returning here. If possible, let us proceed + * and send fail response to SME */ + } + + len = sizeof(*param); + + param = qdf_mem_malloc(len); + if (!param) { + lim_log(mac, LOGE, FL("Fail to allocate memory")); + /* Memory allocation for param failed. + * Cannot send fail status back to SME + */ + return; + } + + if (fail_resp) { + lim_log(mac, LOGE, FL("Send fail status to SME")); + param->status = SET_HW_MODE_STATUS_ECANCELED; + param->cfgd_hw_mode_index = 0; + param->num_vdev_mac_entries = 0; + } else { + param->status = resp->status; + param->cfgd_hw_mode_index = resp->cfgd_hw_mode_index; + param->num_vdev_mac_entries = resp->num_vdev_mac_entries; + + for (i = 0; i < resp->num_vdev_mac_entries; i++) { + param->vdev_mac_map[i].vdev_id = + resp->vdev_mac_map[i].vdev_id; + param->vdev_mac_map[i].mac_id = + resp->vdev_mac_map[i].mac_id; + } + /* + * TODO: Update this HW mode info in any UMAC params, if needed + */ + } + + msg.type = eWNI_SME_SET_HW_MODE_RESP; + msg.bodyptr = param; + msg.bodyval = 0; + lim_log(mac, LOGE, FL("Send eWNI_SME_SET_HW_MODE_RESP to SME")); + lim_sys_process_mmh_msg_api(mac, &msg, ePROT); + return; +} + +/** + * lim_process_antenna_mode_resp() - Process set antenna mode + * response + * @mac: Global MAC pointer + * @body: Set antenna mode response in sir_antenna_mode_resp + * format + * + * Process the set antenna mode response and post the message + * to SME to process this further and release the active + * command list + * + * Return: None + */ +static void lim_process_set_antenna_resp(tpAniSirGlobal mac, void *body) +{ + struct sir_antenna_mode_resp *resp, *param; + bool fail_resp = false; + tSirMsgQ msg; + + resp = (struct sir_antenna_mode_resp *)body; + if (!resp) { + lim_log(mac, LOGE, FL("Set antenna mode resp is NULL")); + fail_resp = true; + /* Not returning here. If possible, let us proceed + * and send fail response to SME + */ + } + + param = qdf_mem_malloc(sizeof(*param)); + if (!param) { + lim_log(mac, LOGE, FL("Fail to allocate memory")); + /* Memory allocation for param failed. + * Cannot send fail status back to SME + */ + return; + } + + if (fail_resp) { + lim_log(mac, LOGE, FL("Send fail status to SME")); + param->status = SET_ANTENNA_MODE_STATUS_ECANCELED; + } else { + param->status = resp->status; + } + + msg.type = eWNI_SME_SET_ANTENNA_MODE_RESP; + msg.bodyptr = param; + msg.bodyval = 0; + lim_log(mac, LOG1, FL("Send eWNI_SME_SET_ANTENNA_MODE_RESP to SME")); + lim_sys_process_mmh_msg_api(mac, &msg, ePROT); + return; +} + +/** + * lim_process_set_default_scan_ie_request() - Process the Set default + * Scan IE request from HDD. + * @mac_ctx: Pointer to Global MAC structure + * @msg_buf: Pointer to incoming data + * + * This function receives the default scan IEs and updates the ext cap IE + * (if present) with FTM capabilities and pass the Scan IEs to WMA. + * + * Return: None + */ +static void lim_process_set_default_scan_ie_request(tpAniSirGlobal mac_ctx, + uint32_t *msg_buf) +{ + struct hdd_default_scan_ie *set_ie_params; + struct vdev_ie_info *wma_ie_params; + uint8_t *local_ie_buf; + uint16_t local_ie_len; + tSirMsgQ msg_q; + tSirRetStatus ret_code; + QDF_STATUS qdf_status; + + if (!msg_buf) { + lim_log(mac_ctx, LOGE, FL("msg_buf is NULL")); + return; + } + + set_ie_params = (struct hdd_default_scan_ie *) msg_buf; + local_ie_len = set_ie_params->ie_len; + + local_ie_buf = qdf_mem_malloc(MAX_DEFAULT_SCAN_IE_LEN); + if (!local_ie_buf) { + lim_log(mac_ctx, LOGE, + FL("Scan IE Update fails due to malloc failure")); + return; + } + + if (lim_update_ext_cap_ie(mac_ctx, + (uint8_t *)set_ie_params->ie_data, + local_ie_buf, &local_ie_len)) { + lim_log(mac_ctx, LOGE, FL("Update ext cap IEs fails")); + goto scan_ie_send_fail; + } + + if (mac_ctx->roam.configParam.qcn_ie_support) { + qdf_status = lim_add_qcn_ie(mac_ctx, local_ie_buf, + &local_ie_len); + if (QDF_IS_STATUS_ERROR(qdf_status)) + goto scan_ie_send_fail; + } + + wma_ie_params = qdf_mem_malloc(sizeof(*wma_ie_params) + local_ie_len); + if (!wma_ie_params) { + lim_log(mac_ctx, LOGE, FL("fail to alloc wma_ie_params")); + goto scan_ie_send_fail; + } + wma_ie_params->vdev_id = set_ie_params->session_id; + wma_ie_params->ie_id = DEFAULT_SCAN_IE_ID; + wma_ie_params->length = local_ie_len; + wma_ie_params->data = (uint8_t *)(wma_ie_params) + + sizeof(*wma_ie_params); + qdf_mem_copy(wma_ie_params->data, local_ie_buf, local_ie_len); + + msg_q.type = WMA_SET_IE_INFO; + msg_q.bodyptr = wma_ie_params; + msg_q.bodyval = 0; + ret_code = wma_post_ctrl_msg(mac_ctx, &msg_q); + if (eSIR_SUCCESS != ret_code) { + lim_log(mac_ctx, LOGE, FL("fail to send WMA_SET_IE_INFO")); + qdf_mem_free(wma_ie_params); + } +scan_ie_send_fail: + qdf_mem_free(local_ie_buf); +} + +/** + * lim_process_hw_mode_trans_ind() - Process set HW mode transition indication + * @mac: Global MAC pointer + * @body: Set HW mode response in sir_hw_mode_trans_ind format + * + * Process the set HW mode transition indication and post the message + * to SME to invoke the HDD callback + * command list + * + * Return: None + */ +static void lim_process_hw_mode_trans_ind(tpAniSirGlobal mac, void *body) +{ + struct sir_hw_mode_trans_ind *ind, *param; + uint32_t len, i; + tSirMsgQ msg; + + ind = (struct sir_hw_mode_trans_ind *)body; + if (!ind) { + lim_log(mac, LOGE, FL("Set HW mode trans ind param is NULL")); + return; + } + + len = sizeof(*param); + + param = qdf_mem_malloc(len); + if (!param) { + lim_log(mac, LOGE, FL("Fail to allocate memory")); + return; + } + + param->old_hw_mode_index = ind->old_hw_mode_index; + param->new_hw_mode_index = ind->new_hw_mode_index; + param->num_vdev_mac_entries = ind->num_vdev_mac_entries; + + for (i = 0; i < ind->num_vdev_mac_entries; i++) { + param->vdev_mac_map[i].vdev_id = + ind->vdev_mac_map[i].vdev_id; + param->vdev_mac_map[i].mac_id = + ind->vdev_mac_map[i].mac_id; + } + + /* TODO: Update this HW mode info in any UMAC params, if needed */ + + msg.type = eWNI_SME_HW_MODE_TRANS_IND; + msg.bodyptr = param; + msg.bodyval = 0; + lim_log(mac, LOGE, FL("Send eWNI_SME_HW_MODE_TRANS_IND to SME")); + lim_sys_process_mmh_msg_api(mac, &msg, ePROT); + return; +} + +/** ------------------------------------------------------------- + \fn def_msg_decision + \brief The function decides whether to defer a message or not in limProcessMessage function + \param tpAniSirGlobal pMac + \param tSirMsgQ limMsg + \param tSirMacTspecIE *ppInfo + \return none + -------------------------------------------------------------*/ + +uint8_t static def_msg_decision(tpAniSirGlobal pMac, tpSirMsgQ limMsg) +{ + uint8_t type, subtype; + QDF_STATUS status; + bool mgmt_pkt_defer = true; + +/* this function should not changed */ + if (pMac->lim.gLimSmeState == eLIM_SME_OFFLINE_STATE) { + /* Defer processsing this message */ + if (lim_defer_msg(pMac, limMsg) != TX_SUCCESS) { + QDF_TRACE(QDF_MODULE_ID_PE, LOGE, + FL("Unable to Defer Msg")); + lim_log_session_states(pMac); + lim_handle_defer_msg_error(pMac, limMsg); + } + return true; + } + /* When defer is requested then defer all the messages except HAL responses. */ + if ((!lim_is_system_in_scan_state(pMac)) + && (true != GET_LIM_PROCESS_DEFD_MESGS(pMac)) + && !pMac->lim.gLimSystemInScanLearnMode) { + + if (limMsg->type == SIR_BB_XPORT_MGMT_MSG) { + /* + * Dont defer beacon and probe response + * because it will fill the defer queue quickly + */ + status = lim_util_get_type_subtype(limMsg->bodyptr, + &type, &subtype); + if (QDF_IS_STATUS_SUCCESS(status) && + (type == SIR_MAC_MGMT_FRAME) && + ((subtype == SIR_MAC_MGMT_BEACON) || + (subtype == SIR_MAC_MGMT_PROBE_RSP))) + mgmt_pkt_defer = false; + } + + if ((limMsg->type != WMA_ADD_BSS_RSP) + && (limMsg->type != WMA_DELETE_BSS_RSP) + && (limMsg->type != WMA_DELETE_BSS_HO_FAIL_RSP) + && (limMsg->type != WMA_ADD_STA_RSP) + && (limMsg->type != WMA_DELETE_STA_RSP) + && (limMsg->type != WMA_SET_BSSKEY_RSP) + && (limMsg->type != WMA_SET_STAKEY_RSP) + && (limMsg->type != WMA_SET_STA_BCASTKEY_RSP) + && (limMsg->type != WMA_AGGR_QOS_RSP) + && (limMsg->type != WMA_SET_MIMOPS_RSP) + && (limMsg->type != WMA_SWITCH_CHANNEL_RSP) + && (limMsg->type != WMA_P2P_NOA_ATTR_IND) + && (limMsg->type != WMA_P2P_NOA_START_IND) && + (limMsg->type != WMA_ADD_TS_RSP) && + /* + * LIM won't process any defer queue commands if gLimAddtsSent is + * set to TRUE. gLimAddtsSent will be set TRUE to while sending + * ADDTS REQ. Say, when deferring is enabled, if + * SIR_LIM_ADDTS_RSP_TIMEOUT is posted (because of not receiving ADDTS + * RSP) then this command will be added to defer queue and as + * gLimAddtsSent is set TRUE LIM will never process any commands from + * defer queue, including SIR_LIM_ADDTS_RSP_TIMEOUT. Hence allowing + * SIR_LIM_ADDTS_RSP_TIMEOUT command to be processed with deferring + * enabled, so that this will be processed immediately and sets + * gLimAddtsSent to FALSE. + */ + (limMsg->type != SIR_LIM_ADDTS_RSP_TIMEOUT) && + /* Allow processing of RX frames while awaiting reception + * of ADD TS response over the air. This logic particularly + * handles the case when host sends ADD BA request to FW + * after ADD TS request is sent over the air and + * ADD TS response received over the air */ + !(limMsg->type == SIR_BB_XPORT_MGMT_MSG && + pMac->lim.gLimAddtsSent) && + (mgmt_pkt_defer)) { + pe_debug("Defer the current message %s , gLimProcessDefdMsgs is false and system is not in scan/learn mode", + lim_msg_str(limMsg->type)); + /* Defer processsing this message */ + if (lim_defer_msg(pMac, limMsg) != TX_SUCCESS) { + QDF_TRACE(QDF_MODULE_ID_PE, LOGE, + FL("Unable to Defer Msg")); + lim_log_session_states(pMac); + lim_handle_defer_msg_error(pMac, limMsg); + + } + return true; + } + } + return false; +} + +#ifdef FEATURE_WLAN_EXTSCAN +static void +__lim_pno_match_fwd_bcn_probepsp(tpAniSirGlobal pmac, uint8_t *rx_pkt_info, + tSirProbeRespBeacon *frame, uint32_t ie_len, + uint32_t msg_type) +{ + struct pno_match_found *result; + uint8_t *body; + tSirMsgQ mmh_msg; + tpSirMacMgmtHdr hdr; + uint32_t num_results = 1, len, i; + + /* Upon receiving every matched beacon, bss info is forwarded to the + * the upper layer, hence num_results is set to 1 */ + len = sizeof(*result) + (num_results * sizeof(tSirWifiScanResult)) + + ie_len; + + result = qdf_mem_malloc(len); + if (NULL == result) { + lim_log(pmac, LOGE, FL("Memory allocation failed")); + return; + } + hdr = WMA_GET_RX_MAC_HEADER(rx_pkt_info); + body = WMA_GET_RX_MPDU_DATA(rx_pkt_info); + + /* Received frame does not have request id, hence set 0 */ + result->request_id = 0; + result->more_data = 0; + result->num_results = num_results; + + for (i = 0; i < result->num_results; i++) { + result->ap[i].ts = qdf_mc_timer_get_system_time(); + result->ap[i].beaconPeriod = frame->beaconInterval; + result->ap[i].capability = + lim_get_u16((uint8_t *) &frame->capabilityInfo); + result->ap[i].channel = WMA_GET_RX_CH(rx_pkt_info); + result->ap[i].rssi = WMA_GET_RX_RSSI_NORMALIZED(rx_pkt_info); + result->ap[i].rtt = 0; + result->ap[i].rtt_sd = 0; + result->ap[i].ieLength = ie_len; + qdf_mem_copy((uint8_t *) &result->ap[i].ssid[0], + (uint8_t *) frame->ssId.ssId, frame->ssId.length); + result->ap[i].ssid[frame->ssId.length] = '\0'; + qdf_mem_copy((uint8_t *) &result->ap[i].bssid, + (uint8_t *) hdr->bssId, + sizeof(tSirMacAddr)); + /* Copy IE fields */ + qdf_mem_copy((uint8_t *) &result->ap[i].ieData, + body + SIR_MAC_B_PR_SSID_OFFSET, ie_len); + } + + mmh_msg.type = msg_type; + mmh_msg.bodyptr = result; + mmh_msg.bodyval = 0; + lim_sys_process_mmh_msg_api(pmac, &mmh_msg, ePROT); +} + + +static void +__lim_ext_scan_forward_bcn_probe_rsp(tpAniSirGlobal pmac, uint8_t *rx_pkt_info, + tSirProbeRespBeacon *frame, + uint32_t ie_len, + uint32_t msg_type) +{ + tpSirWifiFullScanResultEvent result; + uint8_t *body; + tSirMsgQ mmh_msg; + tpSirMacMgmtHdr hdr; + uint32_t frame_len; + tSirBssDescription *bssdescr; + + result = qdf_mem_malloc(sizeof(*result) + ie_len); + if (NULL == result) { + lim_log(pmac, LOGE, FL("Memory allocation failed")); + return; + } + hdr = WMA_GET_RX_MAC_HEADER(rx_pkt_info); + body = WMA_GET_RX_MPDU_DATA(rx_pkt_info); + + /* Received frame does not have request id, hence set 0 */ + result->requestId = 0; + + result->moreData = 0; + result->ap.ts = qdf_mc_timer_get_system_time(); + result->ap.beaconPeriod = frame->beaconInterval; + result->ap.capability = + lim_get_u16((uint8_t *) &frame->capabilityInfo); + result->ap.channel = WMA_GET_RX_CH(rx_pkt_info); + result->ap.rssi = WMA_GET_RX_RSSI_NORMALIZED(rx_pkt_info); + result->ap.rtt = 0; + result->ap.rtt_sd = 0; + result->ap.ieLength = ie_len; + + qdf_mem_copy((uint8_t *) &result->ap.ssid[0], + (uint8_t *) frame->ssId.ssId, frame->ssId.length); + result->ap.ssid[frame->ssId.length] = '\0'; + qdf_mem_copy((uint8_t *) &result->ap.bssid.bytes, + (uint8_t *) hdr->bssId, + QDF_MAC_ADDR_SIZE); + /* Copy IE fields */ + qdf_mem_copy((uint8_t *) &result->ap.ieData, + body + SIR_MAC_B_PR_SSID_OFFSET, ie_len); + + + frame_len = sizeof(*bssdescr) + ie_len - sizeof(bssdescr->ieFields[1]); + bssdescr = (tSirBssDescription *) qdf_mem_malloc(frame_len); + + if (NULL == bssdescr) { + lim_log(pmac, LOGE, + FL("qdf_mem_malloc(length=%d) failed"), frame_len); + return; + } + + qdf_mem_zero(bssdescr, frame_len); + + lim_collect_bss_description(pmac, bssdescr, frame, rx_pkt_info, false); + /* + * Send the beacon to CSR with registered callback routine. + * scan_id and flags parameters are currently unused and set to 0. + * EXT scan results will also be added to scan cache in SME + */ + if (pmac->lim.add_bssdescr_callback) { + (pmac->lim.add_bssdescr_callback) (pmac, bssdescr, 0, 0); + } else { + lim_log(pmac, LOGE, + FL("No CSR callback routine to send beacon/probe response")); + } + qdf_mem_free(bssdescr); + + mmh_msg.type = msg_type; + mmh_msg.bodyptr = result; + mmh_msg.bodyval = 0; + lim_sys_process_mmh_msg_api(pmac, &mmh_msg, ePROT); +} + +static void +__lim_process_ext_scan_beacon_probe_rsp(tpAniSirGlobal pmac, + uint8_t *rx_pkt_info, + uint8_t sub_type) +{ + tSirProbeRespBeacon *frame; + uint8_t *body; + uint32_t frm_len; + tSirRetStatus status; + + frm_len = WMA_GET_RX_PAYLOAD_LEN(rx_pkt_info); + if (frm_len <= SIR_MAC_B_PR_SSID_OFFSET) { + lim_log(pmac, LOGP, + FL("RX packet has invalid length %d"), frm_len); + return; + } + + frame = qdf_mem_malloc(sizeof(*frame)); + if (NULL == frame) { + lim_log(pmac, LOGE, FL("Memory allocation failed")); + return; + } + + if (sub_type == SIR_MAC_MGMT_BEACON) { + lim_log(pmac, LOG2, FL("Beacon due to ExtScan/epno")); + status = sir_convert_beacon_frame2_struct(pmac, + (uint8_t *)rx_pkt_info, + frame); + } else if (sub_type == SIR_MAC_MGMT_PROBE_RSP) { + lim_log(pmac, LOG2, FL("Probe Rsp due to ExtScan/epno")); + body = WMA_GET_RX_MPDU_DATA(rx_pkt_info); + status = sir_convert_probe_frame2_struct(pmac, body, + frm_len, frame); + } else { + qdf_mem_free(frame); + return; + } + + if (status != eSIR_SUCCESS) { + lim_log(pmac, LOGE, FL("Frame parsing failed")); + qdf_mem_free(frame); + return; + } + + if (WMA_IS_EXTSCAN_SCAN_SRC(rx_pkt_info)) + __lim_ext_scan_forward_bcn_probe_rsp(pmac, rx_pkt_info, frame, + (frm_len - SIR_MAC_B_PR_SSID_OFFSET), + eWNI_SME_EXTSCAN_FULL_SCAN_RESULT_IND); + + if (WMA_IS_EPNO_SCAN_SRC(rx_pkt_info)) + __lim_pno_match_fwd_bcn_probepsp(pmac, rx_pkt_info, frame, + (frm_len - SIR_MAC_B_PR_SSID_OFFSET), + eWNI_SME_EPNO_NETWORK_FOUND_IND); + + qdf_mem_free(frame); +} +#endif + +/* + * Beacon Handling Cases: + * during scanning, when no session is active: + * handled by lim_handle_frames_in_scan_state before __lim_handle_beacon call is invoked. + * during scanning, when any session is active, but beacon/Pr does not belong to that session, psessionEntry will be null. + * handled by lim_handle_frames_in_scan_state before __lim_handle_beacon call is invoked. + * during scanning, when any session is active, and beacon/Pr belongs to one of the session, psessionEntry will not be null. + * handled by lim_handle_frames_in_scan_state before __lim_handle_beacon call is invoked. + * Not scanning, no session: + * there should not be any beacon coming, if coming, should be dropped. + * Not Scanning, + */ +static void +__lim_handle_beacon(tpAniSirGlobal pMac, tpSirMsgQ pMsg, + tpPESession psessionEntry) +{ + /* checking for global SME state... */ + uint8_t *pRxPacketInfo; + lim_get_b_dfrom_rx_packet(pMac, pMsg->bodyptr, + (uint32_t **) &pRxPacketInfo); + + /* This function should not be called if beacon is received in scan state. */ + /* So not doing any checks for the global state. */ + + if (psessionEntry == NULL) { + sch_beacon_process(pMac, pRxPacketInfo, NULL); + } else if ((psessionEntry->limSmeState == eLIM_SME_LINK_EST_STATE) || + (psessionEntry->limSmeState == eLIM_SME_NORMAL_STATE)) { + sch_beacon_process(pMac, pRxPacketInfo, psessionEntry); + } else + lim_process_beacon_frame(pMac, pRxPacketInfo, psessionEntry); + + return; +} + +/** + * lim_defer_msg() + * + ***FUNCTION: + * This function is called to defer the messages received + * during Learn mode + * + ***LOGIC: + * NA + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param pMac - Pointer to Global MAC structure + * @param pMsg of type tSirMsgQ - Pointer to the message structure + * @return None + */ + +uint32_t lim_defer_msg(tpAniSirGlobal pMac, tSirMsgQ *pMsg) +{ + uint32_t retCode = TX_SUCCESS; + + retCode = lim_write_deferred_msg_q(pMac, pMsg); + + if (retCode == TX_SUCCESS) { + MTRACE(mac_trace_msg_rx + (pMac, NO_SESSION, + LIM_TRACE_MAKE_RXMSG(pMsg->type, LIM_MSG_DEFERRED)); + ) + } else { + pe_err("Dropped lim message (0x%X) Message %s", pMsg->type, lim_msg_str(pMsg->type)); + MTRACE(mac_trace_msg_rx + (pMac, NO_SESSION, + LIM_TRACE_MAKE_RXMSG(pMsg->type, LIM_MSG_DROPPED)); + ) + } + + return retCode; +} /*** end lim_defer_msg() ***/ + +/** + * lim_handle_unknown_a2_index_frames() - This function handles Unknown Unicast + * (A2 Index) packets + * @mac_ctx: Pointer to the Global Mac Context. + * @rx_pkt_buffer: Pointer to the packet Buffer descriptor. + * @session_entry: Pointer to the PE Session Entry. + * + * This routine will handle public action frames. + * + * Return: None. + */ +static void lim_handle_unknown_a2_index_frames(tpAniSirGlobal mac_ctx, + void *rx_pkt_buffer, tpPESession session_entry) +{ +#ifdef FEATURE_WLAN_TDLS + tpSirMacDataHdr3a mac_hdr; +#endif + if (LIM_IS_P2P_DEVICE_ROLE(session_entry)) + lim_process_action_frame_no_session(mac_ctx, + (uint8_t *) rx_pkt_buffer); +#ifdef FEATURE_WLAN_TDLS + mac_hdr = WMA_GET_RX_MPDUHEADER3A(rx_pkt_buffer); + + if (lim_is_group_addr(mac_hdr->addr2)) { + QDF_TRACE(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_INFO_HIGH, + FL("Ignoring A2 Invalid Packet received for MC/BC:")); + lim_print_mac_addr(mac_ctx, mac_hdr->addr2, LOG2); + return; + } + QDF_TRACE(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_INFO, + FL("type=0x%x, subtype=0x%x"), + mac_hdr->fc.type, mac_hdr->fc.subType); + /* Currently only following type and subtype are handled. + * If there are more combinations, then add switch-case + * statements. + */ + if (LIM_IS_STA_ROLE(session_entry) && + (mac_hdr->fc.type == SIR_MAC_MGMT_FRAME) && + (mac_hdr->fc.subType == SIR_MAC_MGMT_ACTION)) + lim_process_action_frame(mac_ctx, rx_pkt_buffer, session_entry); +#endif + return; +} + +/** + * lim_check_mgmt_registered_frames() - This function handles registered + * management frames. + * + * @mac_ctx: Pointer to the Global Mac Context. + * @buff_desc: Pointer to the packet Buffer descriptor. + * @session_entry: Pointer to the PE Session Entry. + * + * This function is called to process to check if received frame match with + * any of the registered frame from HDD. If yes pass this frame to SME. + * + * Return: True or False for Match or Mismatch respectively. + */ +static bool +lim_check_mgmt_registered_frames(tpAniSirGlobal mac_ctx, uint8_t *buff_desc, + tpPESession session_entry) +{ + tSirMacFrameCtl fc; + tpSirMacMgmtHdr hdr; + uint8_t *body; + struct mgmt_frm_reg_info *mgmt_frame = NULL; + struct mgmt_frm_reg_info *next_frm = NULL; + uint16_t frm_type; + uint16_t frm_len; + uint8_t type, sub_type; + bool match = false; + QDF_STATUS qdf_status; + + hdr = WMA_GET_RX_MAC_HEADER(buff_desc); + fc = hdr->fc; + frm_type = (fc.type << 2) | (fc.subType << 4); + body = WMA_GET_RX_MPDU_DATA(buff_desc); + frm_len = WMA_GET_RX_PAYLOAD_LEN(buff_desc); + + qdf_mutex_acquire(&mac_ctx->lim.lim_frame_register_lock); + qdf_list_peek_front(&mac_ctx->lim.gLimMgmtFrameRegistratinQueue, + (qdf_list_node_t **) &mgmt_frame); + qdf_mutex_release(&mac_ctx->lim.lim_frame_register_lock); + + while (mgmt_frame != NULL) { + type = (mgmt_frame->frameType >> 2) & 0x03; + sub_type = (mgmt_frame->frameType >> 4) & 0x0f; + if ((type == SIR_MAC_MGMT_FRAME) + && (fc.type == SIR_MAC_MGMT_FRAME) + && (sub_type == SIR_MAC_MGMT_RESERVED15)) { + QDF_TRACE(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_INFO_HIGH, + FL + ("rcvd frm match for SIR_MAC_MGMT_RESERVED15")); + match = true; + break; + } + if (mgmt_frame->frameType == frm_type) { + if (mgmt_frame->matchLen <= 0) { + match = true; + break; + } + if (mgmt_frame->matchLen <= frm_len && + (!qdf_mem_cmp(mgmt_frame->matchData, body, + mgmt_frame->matchLen))) { + /* found match! */ + match = true; + break; + } + } + + qdf_mutex_acquire(&mac_ctx->lim.lim_frame_register_lock); + qdf_status = + qdf_list_peek_next( + &mac_ctx->lim.gLimMgmtFrameRegistratinQueue, + (qdf_list_node_t *) mgmt_frame, + (qdf_list_node_t **) &next_frm); + qdf_mutex_release(&mac_ctx->lim.lim_frame_register_lock); + mgmt_frame = next_frm; + next_frm = NULL; + } + + if (match) { + QDF_TRACE(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_INFO, + FL("rcvd frame match with registered frame params")); + /* Indicate this to SME */ + lim_send_sme_mgmt_frame_ind(mac_ctx, hdr->fc.subType, + (uint8_t *) hdr, + WMA_GET_RX_PAYLOAD_LEN(buff_desc) + + sizeof(tSirMacMgmtHdr), mgmt_frame->sessionId, + WMA_GET_RX_CH(buff_desc), session_entry, 0); + + if ((type == SIR_MAC_MGMT_FRAME) + && (fc.type == SIR_MAC_MGMT_FRAME) + && (sub_type == SIR_MAC_MGMT_RESERVED15)) + /* These packets needs to be processed by PE/SME + * as well as HDD.If it returns true here, + * the packet is forwarded to HDD only. + */ + match = false; + } + + return match; +} + +/** + * lim_handle80211_frames() + * + ***FUNCTION: + * This function is called to process 802.11 frames + * received by LIM. + * + ***LOGIC: + * NA + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param pMac - Pointer to Global MAC structure + * @param pMsg of type tSirMsgQ - Pointer to the message structure + * @return None + */ + +static void +lim_handle80211_frames(tpAniSirGlobal pMac, tpSirMsgQ limMsg, uint8_t *pDeferMsg) +{ + uint8_t *pRxPacketInfo = NULL; + tSirMacFrameCtl fc; + tpSirMacMgmtHdr pHdr = NULL; + tpPESession psessionEntry = NULL; + uint8_t sessionId; + tAniBool isFrmFt = false; + + *pDeferMsg = false; + lim_get_b_dfrom_rx_packet(pMac, limMsg->bodyptr, + (uint32_t **) &pRxPacketInfo); + + pHdr = WMA_GET_RX_MAC_HEADER(pRxPacketInfo); + isFrmFt = WMA_GET_RX_FT_DONE(pRxPacketInfo); + fc = pHdr->fc; + + if (pMac->sap.SapDfsInfo.is_dfs_cac_timer_running) { + psessionEntry = pe_find_session_by_bssid(pMac, + pHdr->bssId, &sessionId); + if (psessionEntry && + (QDF_SAP_MODE == psessionEntry->pePersona)) { + lim_log(pMac, LOG1, + FL("CAC timer running - drop the frame")); + goto end; + } + } + +#ifdef WLAN_DUMP_MGMTFRAMES + lim_log(pMac, LOGE, + FL("ProtVersion %d, Type %d, Subtype %d rateIndex=%d"), + fc.protVer, fc.type, fc.subType, + WMA_GET_RX_MAC_RATE_IDX(pRxPacketInfo)); + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_ERROR, pHdr, + WMA_GET_RX_MPDU_HEADER_LEN(pRxPacketInfo)); +#endif + if (pMac->fEnableDebugLog & 0x1) { + if ((fc.type == SIR_MAC_MGMT_FRAME) && + (fc.subType != SIR_MAC_MGMT_PROBE_REQ) && + (fc.subType != SIR_MAC_MGMT_PROBE_RSP) && + (fc.subType != SIR_MAC_MGMT_BEACON)) { + lim_log(pMac, LOGE, + FL("RX MGMT - Type %hu, SubType %hu, seq num[%d]"), + fc.type, + fc.subType, + ((pHdr->seqControl.seqNumHi << + HIGH_SEQ_NUM_OFFSET) | + pHdr->seqControl.seqNumLo)); + } + } +#ifdef FEATURE_WLAN_EXTSCAN + if (WMA_IS_EXTSCAN_SCAN_SRC(pRxPacketInfo) || + WMA_IS_EPNO_SCAN_SRC(pRxPacketInfo)) { + if (fc.subType == SIR_MAC_MGMT_BEACON || + fc.subType == SIR_MAC_MGMT_PROBE_RSP) { + __lim_process_ext_scan_beacon_probe_rsp(pMac, + pRxPacketInfo, + fc.subType); + } else { + lim_log(pMac, LOGE, + FL("Wrong frameType %d, Subtype %d for %d"), + fc.type, fc.subType, + WMA_GET_SCAN_SRC(pRxPacketInfo)); + } + goto end; + } +#endif + if (WMA_GET_OFFLOADSCANLEARN(pRxPacketInfo)) { + if (fc.subType == SIR_MAC_MGMT_BEACON) { + lim_log(pMac, LOG2, FL("Learning scan beacon")); + __lim_handle_beacon(pMac, limMsg, NULL); + } else if (fc.subType == SIR_MAC_MGMT_PROBE_RSP) { + lim_log(pMac, LOG2, FL("Learning scan probe rsp")); + lim_process_probe_rsp_frame_no_session(pMac, pRxPacketInfo); + } else { + lim_log(pMac, LOGE, + FL("Wrong frame Type %d, Subtype %d for LFR"), + fc.type, fc.subType); + } + goto end; + } + /* Added For BT-AMP Support */ + psessionEntry = pe_find_session_by_bssid(pMac, pHdr->bssId, + &sessionId); + if (psessionEntry == NULL) { + if (fc.subType == SIR_MAC_MGMT_AUTH) { + lim_log(pMac, LOG1, + FL("ProtVersion %d, Type %d, Subtype %d rateIndex=%d"), + fc.protVer, fc.type, fc.subType, + WMA_GET_RX_MAC_RATE_IDX(pRxPacketInfo)); + lim_print_mac_addr(pMac, pHdr->bssId, LOG1); + if (lim_process_auth_frame_no_session + (pMac, pRxPacketInfo, + limMsg->bodyptr) == eSIR_SUCCESS) { + goto end; + } + } + /* Public action frame can be received from non-assoc stations*/ + if ((fc.subType != SIR_MAC_MGMT_PROBE_RSP) && + (fc.subType != SIR_MAC_MGMT_BEACON) && + (fc.subType != SIR_MAC_MGMT_PROBE_REQ) + && (fc.subType != SIR_MAC_MGMT_ACTION)) { + + psessionEntry = pe_find_session_by_peer_sta(pMac, + pHdr->sa, &sessionId); + if (psessionEntry == NULL) { + lim_log(pMac, LOG3, + FL("session does not exist for bssId")); + lim_print_mac_addr(pMac, pHdr->sa, LOG3); + goto end; + } else { + lim_log(pMac, LOG3, + "SessionId:%d exists for given Bssid", + psessionEntry->peSessionId); + } + } + /* For p2p resp frames search for valid session with DA as */ + /* BSSID will be SA and session will be present with DA only */ + if (fc.subType == SIR_MAC_MGMT_ACTION) { + psessionEntry = + pe_find_session_by_bssid(pMac, pHdr->da, &sessionId); + } + } + + /* Check if frame is registered by HDD */ + if (lim_check_mgmt_registered_frames(pMac, pRxPacketInfo, psessionEntry)) { + lim_log(pMac, LOG1, FL("Received frame is passed to SME")); + goto end; + } + + if (fc.protVer != SIR_MAC_PROTOCOL_VERSION) { /* Received Frame with non-zero Protocol Version */ + lim_log(pMac, LOGE, + FL("Unexpected frame with protVersion %d received"), + fc.protVer); + lim_pkt_free(pMac, TXRX_FRM_802_11_MGMT, pRxPacketInfo, + (void *)limMsg->bodyptr); +#ifdef WLAN_DEBUG + pMac->lim.numProtErr++; +#endif + goto end; + } + +/* Chance of crashing : to be done BT-AMP ........happens when broadcast probe req is received */ + +#ifdef WLAN_DEBUG + pMac->lim.numMAC[fc.type][fc.subType]++; +#endif + + switch (fc.type) { + case SIR_MAC_MGMT_FRAME: + { + /* Received Management frame */ + switch (fc.subType) { + case SIR_MAC_MGMT_ASSOC_REQ: + /* Make sure the role supports Association */ + if (LIM_IS_AP_ROLE(psessionEntry)) + lim_process_assoc_req_frame(pMac, + pRxPacketInfo, + LIM_ASSOC, + psessionEntry); + else { + /* Unwanted messages - Log error */ + lim_log(pMac, LOGE, + FL + ("unexpected message received %X"), + limMsg->type); + lim_print_msg_name(pMac, LOGE, + limMsg->type); + } + break; + + case SIR_MAC_MGMT_ASSOC_RSP: + lim_process_assoc_rsp_frame(pMac, pRxPacketInfo, + LIM_ASSOC, + psessionEntry); + break; + + case SIR_MAC_MGMT_REASSOC_REQ: + /* Make sure the role supports Reassociation */ + if (LIM_IS_AP_ROLE(psessionEntry)) { + lim_process_assoc_req_frame(pMac, + pRxPacketInfo, + LIM_REASSOC, + psessionEntry); + } else { + /* Unwanted messages - Log error */ + lim_log(pMac, LOGE, + FL + ("unexpected message received %X"), + limMsg->type); + lim_print_msg_name(pMac, LOGE, + limMsg->type); + } + break; + + case SIR_MAC_MGMT_REASSOC_RSP: + lim_process_assoc_rsp_frame(pMac, pRxPacketInfo, + LIM_REASSOC, + psessionEntry); + break; + + case SIR_MAC_MGMT_PROBE_REQ: + lim_process_probe_req_frame_multiple_bss(pMac, + pRxPacketInfo, + psessionEntry); + break; + + case SIR_MAC_MGMT_PROBE_RSP: + if (psessionEntry == NULL) + lim_process_probe_rsp_frame_no_session(pMac, + pRxPacketInfo); + else + lim_process_probe_rsp_frame(pMac, + pRxPacketInfo, + psessionEntry); + break; + + case SIR_MAC_MGMT_BEACON: + __lim_handle_beacon(pMac, limMsg, psessionEntry); + break; + + case SIR_MAC_MGMT_DISASSOC: + lim_process_disassoc_frame(pMac, pRxPacketInfo, + psessionEntry); + break; + + case SIR_MAC_MGMT_AUTH: + lim_process_auth_frame(pMac, pRxPacketInfo, + psessionEntry); + break; + + case SIR_MAC_MGMT_DEAUTH: + lim_process_deauth_frame(pMac, pRxPacketInfo, + psessionEntry); + break; + + case SIR_MAC_MGMT_ACTION: + if (psessionEntry == NULL) + lim_process_action_frame_no_session(pMac, + pRxPacketInfo); + else { + if (WMA_GET_RX_UNKNOWN_UCAST + (pRxPacketInfo)) + lim_handle_unknown_a2_index_frames + (pMac, pRxPacketInfo, + psessionEntry); + else + lim_process_action_frame(pMac, + pRxPacketInfo, + psessionEntry); + } + break; + default: + /* Received Management frame of 'reserved' subtype */ + break; + } /* switch (fc.subType) */ + + } + break; + case SIR_MAC_DATA_FRAME: + { + } + break; + default: + /* Received frame of type 'reserved' */ + break; + + } /* switch (fc.type) */ + +end: + lim_pkt_free(pMac, TXRX_FRM_802_11_MGMT, pRxPacketInfo, + (void *)limMsg->bodyptr); + return; +} /*** end lim_handle80211_frames() ***/ + +/** + * lim_send_stop_scan_offload_req() + * + ***FUNCTION: + * This function will be called to abort the ongoing offloaded scan + * request. + * + * + ***NOTE: + * + * @param pMac Pointer to Global MAC structure + * @return QDF_STATUS_SUCCESS or QDF_STATUS_E_FAILURE + */ +static QDF_STATUS lim_send_stop_scan_offload_req(tpAniSirGlobal pMac, + uint8_t SessionId, uint32_t scan_id, uint32_t scan_requestor_id) +{ + tSirMsgQ msg; + tSirRetStatus rc = eSIR_SUCCESS; + tAbortScanParams *pAbortScanParams; + + pAbortScanParams = qdf_mem_malloc(sizeof(tAbortScanParams)); + if (NULL == pAbortScanParams) { + lim_log(pMac, LOGP, + FL("Memory allocation failed for AbortScanParams")); + return QDF_STATUS_E_NOMEM; + } + + pAbortScanParams->SessionId = SessionId; + pAbortScanParams->scan_id = scan_id; + pAbortScanParams->scan_requestor_id = scan_requestor_id; + msg.type = WMA_STOP_SCAN_OFFLOAD_REQ; + msg.bodyptr = pAbortScanParams; + msg.bodyval = 0; + + rc = wma_post_ctrl_msg(pMac, &msg); + if (rc != eSIR_SUCCESS) { + lim_log(pMac, LOGE, FL("wma_post_ctrl_msg() return failure")); + qdf_mem_free(pAbortScanParams); + return QDF_STATUS_E_FAILURE; + } + + lim_log(pMac, LOG1, FL("Abort ongoing offload scan.")); + return QDF_STATUS_SUCCESS; + +} + +/** + * lim_process_abort_scan_ind() - abort the scan which is presently being run + * + * @mac_ctx: Pointer to Global MAC structure + * @session_id: PE session + * @scan_id: Scan ID from the scan request + * @scan_requesor_id: Entity requesting the scan + * + * @return: None + */ +void lim_process_abort_scan_ind(tpAniSirGlobal mac_ctx, + uint8_t session_id, uint32_t scan_id, uint32_t scan_requestor_id) +{ +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM + lim_diag_event_report(mac_ctx, WLAN_PE_DIAG_SCAN_ABORT_IND_EVENT, + NULL, 0, 0); +#endif + + lim_log(mac_ctx, LOG2, FL("scan_id %d, scan_requestor_id 0x%x"), + scan_id, scan_requestor_id); + + /* send stop scan cmd to firmware */ + lim_send_stop_scan_offload_req(mac_ctx, session_id, scan_id, + scan_requestor_id); + return; +} + +static void lim_process_sme_obss_scan_ind(tpAniSirGlobal mac_ctx, + struct sSirMsgQ *msg) +{ + struct sPESession *session; + uint8_t session_id; + struct sme_obss_ht40_scanind_msg *ht40_scanind; + + ht40_scanind = (struct sme_obss_ht40_scanind_msg *)msg->bodyptr; + session = pe_find_session_by_bssid(mac_ctx, + ht40_scanind->mac_addr.bytes, &session_id); + if (session == NULL) { + QDF_TRACE(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_INFO, + "OBSS Scan not started: session id is NULL"); + return; + } + if (session->htSupportedChannelWidthSet == + WNI_CFG_CHANNEL_BONDING_MODE_ENABLE) { + QDF_TRACE(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_INFO, + "OBSS Scan Start Req: session id %d" + "htSupportedChannelWidthSet %d", + session->peSessionId, + session->htSupportedChannelWidthSet); + lim_send_ht40_obss_scanind(mac_ctx, session); + } else { + QDF_TRACE(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_INFO, + "OBSS Scan not started: channel width - %d session %d", + session->htSupportedChannelWidthSet, + session->peSessionId); + } + return; +} + +/** + * lim_process_messages() - Process messages from upper layers. + * + * @mac_ctx: Pointer to the Global Mac Context. + * @msg: Received message. + * + * Return: None. + */ +static void lim_process_messages(tpAniSirGlobal mac_ctx, tpSirMsgQ msg) +{ +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE + uint8_t vdev_id = 0; + tUpdateBeaconParams beacon_params; +#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ + uint8_t i; + uint8_t p2p_go_exists = 0; + tpPESession session_entry = NULL; + uint8_t defer_msg = false; + tLinkStateParams *link_state_param; + uint16_t pkt_len = 0; + cds_pkt_t *body_ptr = NULL; + QDF_STATUS qdf_status; + tSirMsgQ new_msg; + tSirSmeScanAbortReq *req_msg = NULL; + uint8_t session_id; + uint32_t scan_id; + +#ifdef FEATURE_WLAN_TDLS + tSirTdlsInd *tdls_ind = NULL; + tpDphHashNode sta_ds = NULL; + tTdlsLinkEstablishParams *tdls_link_params = NULL; +#endif + tSirMbMsgP2p *p2p_msg = NULL; + tSirSetActiveModeSetBncFilterReq *bcn_filter_req = NULL; + + if (ANI_DRIVER_TYPE(mac_ctx) == eDRIVER_TYPE_MFG) { + qdf_mem_free(msg->bodyptr); + msg->bodyptr = NULL; + return; + } + if (msg == NULL) { + lim_log(mac_ctx, LOGE, FL("Message pointer is Null")); + QDF_ASSERT(0); + return; + } +#ifdef WLAN_DEBUG + mac_ctx->lim.numTot++; +#endif + /* + * MTRACE logs not captured for events received from SME + * SME enums (eWNI_SME_START_REQ) starts with 0x16xx. + * Compare received SME events with SIR_SME_MODULE_ID + */ + if ((SIR_SME_MODULE_ID == + (uint8_t)MAC_TRACE_GET_MODULE_ID(msg->type)) && + (msg->type != eWNI_SME_REGISTER_MGMT_FRAME_REQ)) { + MTRACE(mac_trace(mac_ctx, TRACE_CODE_RX_SME_MSG, + NO_SESSION, msg->type)); + } else { + /* + * Omitting below message types as these are too frequent + * and when crash happens we loose critical trace logs + * if these are also logged + */ + if (msg->type != SIR_CFG_PARAM_UPDATE_IND && + msg->type != SIR_BB_XPORT_MGMT_MSG && + msg->type != WMA_RX_SCAN_EVENT) + MTRACE(mac_trace_msg_rx(mac_ctx, NO_SESSION, + LIM_TRACE_MAKE_RXMSG(msg->type, + LIM_MSG_PROCESSED));) + } + + switch (msg->type) { + + case SIR_LIM_UPDATE_BEACON: + lim_update_beacon(mac_ctx); + break; + case SIR_CFG_PARAM_UPDATE_IND: + if (!lim_is_system_in_scan_state(mac_ctx)) { + lim_handle_cf_gparam_update(mac_ctx, msg->bodyval); + break; + } + /* System is in DFS (Learn) mode. + * Defer processsing this message + */ + if (lim_defer_msg(mac_ctx, msg) != TX_SUCCESS) { + if (!(mac_ctx->lim.deferredMsgCnt & 0xF)) + QDF_TRACE(QDF_MODULE_ID_PE, LOGE, + FL("Unable to Defer Msg")); + lim_log_session_states(mac_ctx); + lim_print_msg_name(mac_ctx, LOGE, msg->type); + } + break; + case WMA_SWITCH_CHANNEL_RSP: + lim_process_switch_channel_rsp(mac_ctx, msg->bodyptr); + msg->bodyptr = NULL; + break; +#ifdef ANI_SIR_IBSS_PEER_CACHING + case WMA_IBSS_STA_ADD: + lim_ibss_sta_add(mac_ctx, msg->bodyptr); + break; +#endif + case SIR_BB_XPORT_MGMT_MSG: + /* These messages are from Peer MAC entity. */ +#ifdef WLAN_DEBUG + mac_ctx->lim.numBbt++; +#endif + /* The original msg which we were deferring have the + * bodyPointer point to 'BD' instead of 'cds pkt'. If we + * don't make a copy of msg, then overwrite the + * msg->bodyPointer and next time when we try to + * process the msg, we will try to use 'BD' as + * 'cds Pkt' which will cause a crash + */ + if (msg->bodyptr == NULL) { + lim_log(mac_ctx, LOGE, FL("Message bodyptr is Null")); + QDF_ASSERT(0); + break; + } + qdf_mem_copy((uint8_t *) &new_msg, + (uint8_t *) msg, sizeof(tSirMsgQ)); + body_ptr = (cds_pkt_t *) new_msg.bodyptr; + cds_pkt_get_packet_length(body_ptr, &pkt_len); + + qdf_status = wma_ds_peek_rx_packet_info(body_ptr, + (void **) &new_msg.bodyptr, false); + + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + lim_decrement_pending_mgmt_count(mac_ctx); + cds_pkt_return_packet(body_ptr); + break; + } + + if (WMA_GET_ROAMCANDIDATEIND(new_msg.bodyptr)) + lim_log(mac_ctx, LOG1, FL("roamCandidateInd %d"), + WMA_GET_ROAMCANDIDATEIND(new_msg.bodyptr)); + + if (WMA_GET_OFFLOADSCANLEARN(new_msg.bodyptr)) + lim_log(mac_ctx, LOG1, FL("offloadScanLearn %d"), + WMA_GET_OFFLOADSCANLEARN(new_msg.bodyptr)); + + lim_handle80211_frames(mac_ctx, &new_msg, &defer_msg); + + if (defer_msg == true) { + QDF_TRACE(QDF_MODULE_ID_PE, LOG1, + FL("Defer Msg type=%x"), msg->type); + if (lim_defer_msg(mac_ctx, msg) != TX_SUCCESS) { + QDF_TRACE(QDF_MODULE_ID_PE, LOGE, + FL("Unable to Defer Msg")); + lim_log_session_states(mac_ctx); + lim_decrement_pending_mgmt_count(mac_ctx); + cds_pkt_return_packet(body_ptr); + } + } else { + /* PE is not deferring this 802.11 frame so we need to + * call cds_pkt_return. Asumption here is when Rx mgmt + * frame processing is done, cds packet could be + * freed here. + */ + lim_decrement_pending_mgmt_count(mac_ctx); + cds_pkt_return_packet(body_ptr); + } + break; + case eWNI_SME_SCAN_REQ: + case eWNI_SME_REMAIN_ON_CHANNEL_REQ: + case eWNI_SME_DISASSOC_REQ: + case eWNI_SME_DEAUTH_REQ: +#ifdef FEATURE_WLAN_TDLS + case eWNI_SME_TDLS_SEND_MGMT_REQ: + case eWNI_SME_TDLS_ADD_STA_REQ: + case eWNI_SME_TDLS_DEL_STA_REQ: + case eWNI_SME_TDLS_LINK_ESTABLISH_REQ: +#endif + case eWNI_SME_RESET_AP_CAPS_CHANGED: + case eWNI_SME_SET_HW_MODE_REQ: + case eWNI_SME_SET_DUAL_MAC_CFG_REQ: + case eWNI_SME_SET_ANTENNA_MODE_REQ: + case eWNI_SME_UPDATE_ACCESS_POLICY_VENDOR_IE: + case eWNI_SME_UPDATE_CONFIG: + /* These messages are from HDD. Need to respond to HDD */ + lim_process_normal_hdd_msg(mac_ctx, msg, true); + break; + case eWNI_SME_SEND_DISASSOC_FRAME: + /* Need to response to hdd */ + lim_process_normal_hdd_msg(mac_ctx, msg, true); + break; + case eWNI_SME_SCAN_ABORT_IND: + req_msg = msg->bodyptr; + if (req_msg) { + session_id = req_msg->sessionId; + scan_id = req_msg->scan_id; + lim_process_abort_scan_ind(mac_ctx, session_id, + scan_id, USER_SCAN_REQUESTOR_ID); + qdf_mem_free((void *)msg->bodyptr); + msg->bodyptr = NULL; + } + break; + case eWNI_SME_PDEV_SET_HT_VHT_IE: + case eWNI_SME_SET_VDEV_IES_PER_BAND: + case eWNI_SME_SYS_READY_IND: + case eWNI_SME_JOIN_REQ: + case eWNI_SME_REASSOC_REQ: + case eWNI_SME_START_BSS_REQ: + case eWNI_SME_STOP_BSS_REQ: + case eWNI_SME_SWITCH_CHL_IND: + case eWNI_SME_SETCONTEXT_REQ: + case eWNI_SME_DISASSOC_CNF: + case eWNI_SME_DEAUTH_CNF: + case eWNI_SME_ASSOC_CNF: + case eWNI_SME_ADDTS_REQ: + case eWNI_SME_DELTS_REQ: + case eWNI_SME_GET_ASSOC_STAS_REQ: + case eWNI_SME_TKIP_CNTR_MEAS_REQ: + case eWNI_SME_UPDATE_APWPSIE_REQ: + case eWNI_SME_SESSION_UPDATE_PARAM: + case eWNI_SME_GET_WPSPBC_SESSION_REQ: + case eWNI_SME_SET_APWPARSNIEs_REQ: + case eWNI_SME_CHNG_MCC_BEACON_INTERVAL: + case eWNI_SME_NEIGHBOR_REPORT_REQ_IND: + case eWNI_SME_BEACON_REPORT_RESP_XMIT_IND: +#if defined FEATURE_WLAN_ESE + case eWNI_SME_ESE_ADJACENT_AP_REPORT: +#endif + case eWNI_SME_FT_UPDATE_KEY: + case eWNI_SME_FT_PRE_AUTH_REQ: + case eWNI_SME_FT_AGGR_QOS_REQ: + case eWNI_SME_REGISTER_MGMT_FRAME_REQ: + case eWNI_SME_UPDATE_NOA: + case eWNI_SME_CLEAR_DFS_CHANNEL_LIST: + case eWNI_SME_GET_STATISTICS_REQ: +#ifdef FEATURE_WLAN_ESE + case eWNI_SME_GET_TSM_STATS_REQ: +#endif /* FEATURE_WLAN_ESE */ + case eWNI_SME_REGISTER_MGMT_FRAME_CB: + case eWNI_SME_EXT_CHANGE_CHANNEL: + case eWNI_SME_ROAM_SCAN_OFFLOAD_REQ: + case eWNI_SME_NDP_INITIATOR_REQ: + case eWNI_SME_NDP_RESPONDER_REQ: + case eWNI_SME_NDP_END_REQ: + case eWNI_SME_REGISTER_P2P_ACK_CB: + /* These messages are from HDD.No need to respond to HDD */ + lim_process_normal_hdd_msg(mac_ctx, msg, false); + break; + case eWNI_SME_SEND_ACTION_FRAME_IND: + lim_send_p2p_action_frame(mac_ctx, msg); + qdf_mem_free(msg->bodyptr); + msg->bodyptr = NULL; + break; + case eWNI_SME_ABORT_REMAIN_ON_CHAN_IND: + p2p_msg = (tSirMbMsgP2p *) msg->bodyptr; + lim_process_abort_scan_ind(mac_ctx, p2p_msg->sessionId, + p2p_msg->scan_id, ROC_SCAN_REQUESTOR_ID); + qdf_mem_free(msg->bodyptr); + msg->bodyptr = NULL; + break; + case eWNI_SME_MON_INIT_SESSION: + lim_mon_init_session(mac_ctx, msg->bodyptr); + qdf_mem_free(msg->bodyptr); + msg->bodyptr = NULL; + break; + case SIR_HAL_P2P_NOA_START_IND: + session_entry = &mac_ctx->lim.gpSession[0]; + lim_log(mac_ctx, LOG1, "LIM received NOA start %x", msg->type); + + /* Since insert NOA is done and NOA start msg received, + * we should deactivate the Insert NOA timer + */ + lim_deactivate_and_change_timer(mac_ctx, + eLIM_INSERT_SINGLESHOT_NOA_TIMER); + + for (i = 0; i < mac_ctx->lim.maxBssId; i++) { + session_entry = &mac_ctx->lim.gpSession[i]; + if ((session_entry != NULL) && (session_entry->valid) && + (session_entry->pePersona == QDF_P2P_GO_MODE)) { + /* Save P2P NOA start attribute for Go persona*/ + p2p_go_exists = 1; + qdf_mem_copy(&session_entry->p2pGoPsNoaStartInd, + msg->bodyptr, sizeof(tSirP2PNoaStart)); + qdf_status = + session_entry->p2pGoPsNoaStartInd.status; + if (qdf_status != QDF_STATUS_SUCCESS) + QDF_TRACE(QDF_MODULE_ID_PE, LOGW, + FL( + "GO NOA start status %d by FW"), + qdf_status); + break; + } + } + + if (p2p_go_exists == 0) + QDF_TRACE(QDF_MODULE_ID_PE, LOGW, + FL( + "GO is removed by the time NOA start recvd")); + + /* We received the NOA start indication. Now we can send down + * the SME request which requires off-channel operation */ + lim_process_regd_defd_sme_req_after_noa_start(mac_ctx); + qdf_mem_free(msg->bodyptr); + msg->bodyptr = NULL; + break; +#ifdef FEATURE_WLAN_TDLS + case SIR_HAL_TDLS_IND: + tdls_ind = (tpSirTdlsInd) msg->bodyptr; + session_entry = pe_find_session_by_sta_id(mac_ctx, + tdls_ind->staIdx, &session_id); + if (session_entry == NULL) { + lim_log(mac_ctx, LOG1, + FL("No session exist for given bssId")); + qdf_mem_free(msg->bodyptr); + msg->bodyptr = NULL; + return; + } + sta_ds = dph_get_hash_entry(mac_ctx, tdls_ind->assocId, + &session_entry->dph.dphHashTable); + if (sta_ds == NULL) { + lim_log(mac_ctx, LOG1, + FL("No sta_ds exist for given staId")); + qdf_mem_free(msg->bodyptr); + msg->bodyptr = NULL; + return; + } + + if (STA_ENTRY_TDLS_PEER == sta_ds->staType) { + lim_log(mac_ctx, LOGE, + FL("rcvd TDLS IND from FW with RC %d "), + tdls_ind->reasonCode); + lim_send_sme_tdls_del_sta_ind(mac_ctx, sta_ds, + session_entry, tdls_ind->reasonCode); + } + qdf_mem_free(msg->bodyptr); + msg->bodyptr = NULL; + break; +#endif + case SIR_HAL_P2P_NOA_ATTR_IND: + session_entry = &mac_ctx->lim.gpSession[0]; + lim_log(mac_ctx, LOG1, FL("Received message Noa_ATTR %x"), + msg->type); + for (i = 0; i < mac_ctx->lim.maxBssId; i++) { + session_entry = &mac_ctx->lim.gpSession[i]; + if ((session_entry != NULL) && (session_entry->valid) + && (session_entry->pePersona == + QDF_P2P_GO_MODE)) { /* Save P2P attr for Go */ + qdf_mem_copy( + &session_entry->p2pGoPsUpdate, + msg->bodyptr, + sizeof(tSirP2PNoaAttr)); + lim_log(mac_ctx, LOG2, + FL("bssId" + MAC_ADDRESS_STR + " ctWin=%d oppPsFlag=%d"), + MAC_ADDR_ARRAY( + session_entry->bssId), + session_entry->p2pGoPsUpdate.ctWin, + session_entry->p2pGoPsUpdate.oppPsFlag); + lim_log(mac_ctx, LOG2, + FL + (" uNoa1IntervalCnt=%d uNoa1Duration=%d uNoa1Interval=%d uNoa1StartTime=%d"), + session_entry->p2pGoPsUpdate.uNoa1IntervalCnt, + session_entry->p2pGoPsUpdate.uNoa1Duration, + session_entry->p2pGoPsUpdate.uNoa1Interval, + session_entry->p2pGoPsUpdate.uNoa1StartTime); + break; + } + } + qdf_mem_free(msg->bodyptr); + msg->bodyptr = NULL; + break; + case WMA_MISSED_BEACON_IND: + lim_ps_offload_handle_missed_beacon_ind(mac_ctx, msg); + qdf_mem_free(msg->bodyptr); + msg->bodyptr = NULL; + break; + case SIR_LIM_ADDTS_RSP_TIMEOUT: + lim_process_sme_req_messages(mac_ctx, msg); + break; +#ifdef FEATURE_WLAN_ESE + case WMA_TSM_STATS_RSP: + lim_send_sme_pe_ese_tsm_rsp(mac_ctx, + (tAniGetTsmStatsRsp *) msg->bodyptr); + break; +#endif + case WMA_ADD_TS_RSP: + lim_process_hal_add_ts_rsp(mac_ctx, msg); + break; + case SIR_LIM_DEL_TS_IND: + lim_process_del_ts_ind(mac_ctx, msg); + break; + case SIR_LIM_BEACON_GEN_IND: + if (mac_ctx->lim.gLimSystemRole != eLIM_AP_ROLE) + sch_process_pre_beacon_ind(mac_ctx, msg); + break; + case SIR_LIM_DELETE_STA_CONTEXT_IND: + lim_delete_sta_context(mac_ctx, msg); + break; + case SIR_LIM_PERIODIC_PROBE_REQ_TIMEOUT: + case SIR_LIM_JOIN_FAIL_TIMEOUT: + case SIR_LIM_PERIODIC_JOIN_PROBE_REQ_TIMEOUT: + case SIR_LIM_AUTH_FAIL_TIMEOUT: + case SIR_LIM_AUTH_RSP_TIMEOUT: + case SIR_LIM_ASSOC_FAIL_TIMEOUT: + case SIR_LIM_REASSOC_FAIL_TIMEOUT: + case SIR_LIM_FT_PREAUTH_RSP_TIMEOUT: + case SIR_LIM_REMAIN_CHN_TIMEOUT: + case SIR_LIM_INSERT_SINGLESHOT_NOA_TIMEOUT: + case SIR_LIM_DISASSOC_ACK_TIMEOUT: + case SIR_LIM_DEAUTH_ACK_TIMEOUT: + case SIR_LIM_CONVERT_ACTIVE_CHANNEL_TO_PASSIVE: + case SIR_LIM_AUTH_RETRY_TIMEOUT: + /* These timeout messages are handled by MLM sub module */ + lim_process_mlm_req_messages(mac_ctx, msg); + break; + case SIR_LIM_HEART_BEAT_TIMEOUT: + /** check if heart beat failed, even if one Beacon + * is rcvd within the Heart Beat interval continue + * normal processing + */ + if (NULL == msg->bodyptr) + lim_log(mac_ctx, LOGE, + FL("Can't Process HB TO - bodyptr is Null")); + else { + session_entry = (tpPESession) msg->bodyptr; + lim_log(mac_ctx, LOGE, + FL + ("SIR_LIM_HEART_BEAT_TIMEOUT, Session %d"), + ((tpPESession) msg->bodyptr)->peSessionId); + limResetHBPktCount(session_entry); + lim_handle_heart_beat_timeout_for_session(mac_ctx, + session_entry); + } + break; + case SIR_LIM_PROBE_HB_FAILURE_TIMEOUT: + lim_handle_heart_beat_failure_timeout(mac_ctx); + break; + break; + case SIR_LIM_CNF_WAIT_TIMEOUT: + /* Does not receive CNF or dummy packet */ + lim_handle_cnf_wait_timeout(mac_ctx, (uint16_t) msg->bodyval); + break; + case SIR_LIM_RETRY_INTERRUPT_MSG: + /* Message from ISR upon TFP's max retry limit interrupt */ + break; + case SIR_LIM_INV_KEY_INTERRUPT_MSG: + /* Message from ISR upon SP's Invalid session key interrupt */ + break; + case SIR_LIM_KEY_ID_INTERRUPT_MSG: + /* Message from ISR upon SP's Invalid key ID interrupt */ + break; + case SIR_LIM_REPLAY_THRES_INTERRUPT_MSG: + /* Message from ISR upon SP's Replay threshold interrupt */ + break; + case SIR_LIM_CHANNEL_SWITCH_TIMEOUT: + lim_process_channel_switch_timeout(mac_ctx); + break; + case SIR_LIM_QUIET_TIMEOUT: + lim_process_quiet_timeout(mac_ctx); + break; + case SIR_LIM_QUIET_BSS_TIMEOUT: + lim_process_quiet_bss_timeout(mac_ctx); + break; + case SIR_LIM_UPDATE_OLBC_CACHEL_TIMEOUT: + lim_handle_update_olbc_cache(mac_ctx); + break; +#ifdef FEATURE_WLAN_TDLS + case SIR_HAL_TDLS_SHOULD_DISCOVER: + case SIR_HAL_TDLS_SHOULD_TEARDOWN: + case SIR_HAL_TDLS_PEER_DISCONNECTED: + QDF_TRACE(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_INFO, + ("%s received tdls event: 0x%x"), __func__, msg->type); + lim_send_sme_tdls_event_notify(mac_ctx, msg->type, + (void *)msg->bodyptr); + break; +#endif + case WMA_ADD_BSS_RSP: + lim_process_mlm_add_bss_rsp(mac_ctx, msg); + break; + case WMA_ADD_STA_RSP: + lim_process_add_sta_rsp(mac_ctx, msg); + break; + case WMA_DELETE_STA_RSP: + lim_process_mlm_del_sta_rsp(mac_ctx, msg); + break; + case WMA_DELETE_BSS_RSP: + case WMA_DELETE_BSS_HO_FAIL_RSP: + lim_handle_delete_bss_rsp(mac_ctx, msg); + break; + case WMA_CSA_OFFLOAD_EVENT: + lim_handle_csa_offload_msg(mac_ctx, msg); + break; + case WMA_SET_BSSKEY_RSP: + case WMA_SET_STA_BCASTKEY_RSP: + lim_process_mlm_set_bss_key_rsp(mac_ctx, msg); + break; + case WMA_SET_STAKEY_RSP: + lim_process_mlm_set_sta_key_rsp(mac_ctx, msg); + break; + case WMA_GET_STATISTICS_RSP: + lim_send_sme_pe_statistics_rsp(mac_ctx, msg->type, + (void *)msg->bodyptr); + break; + case WMA_SET_MIMOPS_RSP: + case WMA_SET_TX_POWER_RSP: + qdf_mem_free((void *)msg->bodyptr); + msg->bodyptr = NULL; + break; + case WMA_SET_MAX_TX_POWER_RSP: + rrm_set_max_tx_power_rsp(mac_ctx, msg); + if (msg->bodyptr != NULL) { + qdf_mem_free((void *)msg->bodyptr); + msg->bodyptr = NULL; + } + break; + case SIR_LIM_ADDR2_MISS_IND: + lim_log(mac_ctx, LOGE, + FL("Addr2 mismatch interrupt received %X"), msg->type); + /* message from HAL indicating addr2 mismatch interrupt occurred + * msg->bodyptr contains only pointer to 48-bit addr2 field + */ + qdf_mem_free((void *)(msg->bodyptr)); + msg->bodyptr = NULL; + break; + case WMA_AGGR_QOS_RSP: + lim_process_ft_aggr_qo_s_rsp(mac_ctx, msg); + break; + case WMA_SET_LINK_STATE_RSP: + link_state_param = (tLinkStateParams *) msg->bodyptr; + session_entry = link_state_param->session; + if (link_state_param->ft +#if defined WLAN_FEATURE_ROAM_OFFLOAD + && !session_entry->bRoamSynchInProgress +#endif + ) + lim_send_reassoc_req_with_ft_ies_mgmt_frame(mac_ctx, + session_entry->pLimMlmReassocReq, + session_entry); + if (link_state_param->callback) + link_state_param->callback(mac_ctx, + link_state_param->callbackArg, + link_state_param->status); + qdf_mem_free((void *)(msg->bodyptr)); + msg->bodyptr = NULL; + break; + case eWNI_SME_SET_BCN_FILTER_REQ: + bcn_filter_req = + (tSirSetActiveModeSetBncFilterReq *) msg->bodyptr; + session_entry = pe_find_session_by_bssid(mac_ctx, + bcn_filter_req->bssid.bytes, &session_id); + if ((session_entry != NULL) && + (lim_send_beacon_filter_info(mac_ctx, session_entry) != + eSIR_SUCCESS)) + lim_log(mac_ctx, LOGE, + FL("Failied to send Beacon Filter Info ")); + qdf_mem_free((void *)(msg->bodyptr)); + msg->bodyptr = NULL; + break; +#ifdef FEATURE_WLAN_TDLS + case WMA_SET_TDLS_LINK_ESTABLISH_REQ_RSP: + tdls_link_params = (tTdlsLinkEstablishParams *) msg->bodyptr; + session_entry = pe_find_session_by_sta_id(mac_ctx, + tdls_link_params->staIdx, &session_id); + if (session_entry == NULL) { + lim_log(mac_ctx, LOGE, + FL("session %u does not exist"), session_id); + /* Still send the eWNI_SME_TDLS_LINK_ESTABLISH_RSP + * message to SME with session id as zero and status + * as FAILURE so, that message queued in SME queue + * can be freed to prevent the SME cmd buffer leak + */ + lim_send_sme_tdls_link_establish_req_rsp(mac_ctx, 0, + NULL, NULL, eSIR_FAILURE); + } else { + lim_send_sme_tdls_link_establish_req_rsp(mac_ctx, + session_entry->smeSessionId, NULL, NULL, + tdls_link_params->status); + } + qdf_mem_free((void *)(msg->bodyptr)); + msg->bodyptr = NULL; + break; +#endif + case WMA_RX_SCAN_EVENT: + lim_process_rx_scan_event(mac_ctx, msg->bodyptr); + break; + case WMA_IBSS_PEER_INACTIVITY_IND: + lim_process_ibss_peer_inactivity(mac_ctx, msg->bodyptr); + qdf_mem_free((void *)(msg->bodyptr)); + msg->bodyptr = NULL; + break; + case WMA_DFS_RADAR_IND: + lim_send_sme_dfs_event_notify(mac_ctx, msg->type, + (void *)msg->bodyptr); + /* msg->bodyptr will be freed up by SME/CSR */ + break; + case WMA_DFS_BEACON_TX_SUCCESS_IND: + lim_process_beacon_tx_success_ind(mac_ctx, msg->type, + (void *)msg->bodyptr); + qdf_mem_free((void *)msg->bodyptr); + msg->bodyptr = NULL; + break; + case WMA_DISASSOC_TX_COMP: + lim_disassoc_tx_complete_cnf(mac_ctx, msg->bodyval); + break; + case WMA_DEAUTH_TX_COMP: + lim_deauth_tx_complete_cnf(mac_ctx, msg->bodyval); + break; +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE + case WMA_UPDATE_Q2Q_IE_IND: + qdf_mem_zero(&beacon_params, sizeof(tUpdateBeaconParams)); + beacon_params.paramChangeBitmap = 0; + for (i = 0; i < mac_ctx->lim.maxBssId; i++) { + vdev_id = ((uint8_t *)msg->bodyptr)[i]; + session_entry = pe_find_session_by_sme_session_id( + mac_ctx, vdev_id); + if (session_entry == NULL) + continue; + session_entry->sap_advertise_avoid_ch_ie = + (uint8_t)msg->bodyval; + /* + * if message comes for DFS channel, no need to update: + * 1) We wont have MCC with DFS channels. so no need to + * add Q2Q IE + * 2) We cannot end up in DFS channel SCC by channel + * switch from non DFS MCC scenario, so no need to + * remove Q2Q IE + * 3) There is however a case where device start MCC and + * then user modifies hostapd.conf and does SAP + * restart, in such a case, beacon params will be + * reset and thus will not contain Q2Q IE, by default + */ + if (cds_get_channel_state( + session_entry->currentOperChannel) + != CHANNEL_STATE_DFS) { + beacon_params.bssIdx = session_entry->bssIdx; + beacon_params.beaconInterval = + session_entry->beaconParams.beaconInterval; + beacon_params.paramChangeBitmap |= + PARAM_BCN_INTERVAL_CHANGED; + sch_set_fixed_beacon_fields(mac_ctx, + session_entry); + lim_send_beacon_params(mac_ctx, &beacon_params, + session_entry); + } + } + qdf_mem_free(msg->bodyptr); + msg->bodyptr = NULL; + break; +#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ + case eWNI_SME_NSS_UPDATE_REQ: + case eWNI_SME_DFS_BEACON_CHAN_SW_IE_REQ: + lim_process_sme_req_messages(mac_ctx, msg); + qdf_mem_free((void *)msg->bodyptr); + msg->bodyptr = NULL; + break; + case eWNI_SME_CHANNEL_CHANGE_REQ: + lim_process_sme_req_messages(mac_ctx, msg); + qdf_mem_free((void *)msg->bodyptr); + msg->bodyptr = NULL; + break; + case eWNI_SME_START_BEACON_REQ: + lim_process_sme_req_messages(mac_ctx, msg); + qdf_mem_free((void *)msg->bodyptr); + msg->bodyptr = NULL; + break; + case eWNI_SME_UPDATE_ADDITIONAL_IES: + lim_process_sme_req_messages(mac_ctx, msg); + qdf_mem_free((void *)msg->bodyptr); + msg->bodyptr = NULL; + break; + case eWNI_SME_MODIFY_ADDITIONAL_IES: + lim_process_sme_req_messages(mac_ctx, msg); + qdf_mem_free((void *)msg->bodyptr); + msg->bodyptr = NULL; + break; +#ifdef QCA_HT_2040_COEX + case eWNI_SME_SET_HT_2040_MODE: + lim_process_sme_req_messages(mac_ctx, msg); + qdf_mem_free((void *)msg->bodyptr); + msg->bodyptr = NULL; + break; +#endif + case SIR_HAL_PDEV_SET_HW_MODE_RESP: + lim_process_set_hw_mode_resp(mac_ctx, msg->bodyptr); + qdf_mem_free((void *)msg->bodyptr); + msg->bodyptr = NULL; + break; + case SIR_HAL_PDEV_HW_MODE_TRANS_IND: + lim_process_hw_mode_trans_ind(mac_ctx, msg->bodyptr); + qdf_mem_free((void *)msg->bodyptr); + msg->bodyptr = NULL; + break; + case SIR_HAL_PDEV_MAC_CFG_RESP: + lim_process_dual_mac_cfg_resp(mac_ctx, msg->bodyptr); + qdf_mem_free((void *)msg->bodyptr); + msg->bodyptr = NULL; + break; + case eWNI_SME_SET_IE_REQ: + lim_process_sme_req_messages(mac_ctx, msg); + qdf_mem_free((void *)msg->bodyptr); + msg->bodyptr = NULL; + break; + case eWNI_SME_HT40_OBSS_SCAN_IND: + lim_process_sme_obss_scan_ind(mac_ctx, msg); + qdf_mem_free(msg->bodyptr); + break; + case SIR_HAL_SOC_ANTENNA_MODE_RESP: + lim_process_set_antenna_resp(mac_ctx, msg->bodyptr); + qdf_mem_free((void *)msg->bodyptr); + msg->bodyptr = NULL; + break; + case eWNI_SME_DEFAULT_SCAN_IE: + lim_process_set_default_scan_ie_request(mac_ctx, msg->bodyptr); + qdf_mem_free((void *)msg->bodyptr); + msg->bodyptr = NULL; + break; + case eWNI_SME_DEL_ALL_TDLS_PEERS: + lim_process_sme_del_all_tdls_peers(mac_ctx, msg->bodyptr); + qdf_mem_free((void *)msg->bodyptr); + msg->bodyptr = NULL; + break; + default: + qdf_mem_free((void *)msg->bodyptr); + msg->bodyptr = NULL; + /* Unwanted messages */ + lim_log(mac_ctx, LOGE, + FL("Discarding unexpected message received %X"), + msg->type); + lim_print_msg_name(mac_ctx, LOGE, msg->type); + break; + + } /* switch (msg->type) */ +} /*** end lim_process_messages() ***/ + +/** + * lim_process_deferred_message_queue() + * + * This function is called by LIM while exiting from Learn + * mode. This function fetches messages posted to the LIM + * deferred message queue limDeferredMsgQ. + * + * @pMac: Pointer to Global MAC structure + * @return None + */ + +static void lim_process_deferred_message_queue(tpAniSirGlobal pMac) +{ + tSirMsgQ limMsg = { 0, 0, 0 }; + + tSirMsgQ *readMsg; + uint16_t size; + + /* + ** check any deferred messages need to be processed + **/ + size = pMac->lim.gLimDeferredMsgQ.size; + if (size > 0) { + while ((readMsg = lim_read_deferred_msg_q(pMac)) != NULL) { + qdf_mem_copy((uint8_t *) &limMsg, + (uint8_t *) readMsg, sizeof(tSirMsgQ)); + size--; + lim_process_messages(pMac, &limMsg); + + if ((lim_is_system_in_scan_state(pMac)) + || (true != GET_LIM_PROCESS_DEFD_MESGS(pMac)) + || (pMac->lim.gLimSystemInScanLearnMode) + || pMac->lim.gLimAddtsSent) + break; + } + } +} /*** end lim_process_deferred_message_queue() ***/ + +/** + * lim_message_processor() - Process messages from LIM. + * @mac_ctx: Pointer to the Global Mac Context. + * @msg: Received LIM message. + * + * Wrapper function for lim_process_messages when handling messages received by + * LIM. Could either defer messages or process them. + * + * Return: None. + */ +void lim_message_processor(tpAniSirGlobal mac_ctx, tpSirMsgQ msg) +{ + if (eLIM_MLM_OFFLINE_STATE == mac_ctx->lim.gLimMlmState) { + pe_free_msg(mac_ctx, msg); + return; + } + + if (!def_msg_decision(mac_ctx, msg)) { + lim_process_messages(mac_ctx, msg); + /* process deferred message queue if allowed */ + if ((!(mac_ctx->lim.gLimAddtsSent)) && + (!(lim_is_system_in_scan_state(mac_ctx))) && + (true == GET_LIM_PROCESS_DEFD_MESGS(mac_ctx))) + lim_process_deferred_message_queue(mac_ctx); + } +} + +/** + * lim_process_normal_hdd_msg() - Process the message and defer if needed + * @mac_ctx : Pointer to Global MAC structure + * @msg : The message need to be processed + * @rsp_reqd: whether return result to hdd + * + * This function checks the current lim state and decide whether the message + * passed will be deferred or not. + * + * Return: None + */ +static void lim_process_normal_hdd_msg(tpAniSirGlobal mac_ctx, tSirMsgQ *msg, + uint8_t rsp_reqd) +{ + bool defer_msg = true; + + /* Added For BT-AMP Support */ + if ((mac_ctx->lim.gLimSystemRole == eLIM_AP_ROLE) + || (mac_ctx->lim.gLimSystemRole == eLIM_UNKNOWN_ROLE)) { + /* + * This check is required only for the AP and in 2 cases. + * 1. If we are in learn mode and we receive any of these + * messages, you have to come out of scan and process the + * message, hence dont defer the message here. In handler, + * these message could be defered till we actually come out of + * scan mode. + * 2. If radar is detected, you might have to defer all of + * these messages except Stop BSS request/ Switch channel + * request. This decision is also made inside its handler. + * + * Please be careful while using the flag defer_msg. Possibly + * you might end up in an infinite loop. + */ + if ((msg->type == eWNI_SME_START_BSS_REQ) || + (msg->type == eWNI_SME_STOP_BSS_REQ) || + (msg->type == eWNI_SME_SWITCH_CHL_IND)) + defer_msg = false; + } + + if (((mac_ctx->lim.gLimAddtsSent) || + (lim_is_system_in_scan_state(mac_ctx))) && defer_msg) { + /* + * System is in DFS (Learn) mode or awaiting addts response or + * if radar is detected, Defer processsing this message + */ + if (lim_defer_msg(mac_ctx, msg) != TX_SUCCESS) { +#ifdef WLAN_DEBUG + mac_ctx->lim.numSme++; +#endif + lim_log_session_states(mac_ctx); + /* Release body */ + qdf_mem_free(msg->bodyptr); + msg->bodyptr = NULL; + } + } else { + /* + * These messages are from HDD.Since these requests may also be + * generated internally within LIM module, need to distinquish + * and send response to host + */ + if (rsp_reqd) + mac_ctx->lim.gLimRspReqd = true; +#ifdef WLAN_DEBUG + mac_ctx->lim.numSme++; +#endif + if (lim_process_sme_req_messages(mac_ctx, msg)) { + /* + * Release body. limProcessSmeReqMessage consumed the + * buffer. We can free it. + */ + qdf_mem_free(msg->bodyptr); + msg->bodyptr = NULL; + } + } +} + +void +handle_ht_capabilityand_ht_info(struct sAniSirGlobal *pMac, + tpPESession psessionEntry) +{ + tSirMacHTCapabilityInfo macHTCapabilityInfo; + tSirMacHTParametersInfo macHTParametersInfo; + tSirMacHTInfoField1 macHTInfoField1; + tSirMacHTInfoField2 macHTInfoField2; + tSirMacHTInfoField3 macHTInfoField3; + uint32_t cfgValue; + uint8_t *ptr; + + if (wlan_cfg_get_int(pMac, WNI_CFG_HT_CAP_INFO, &cfgValue) != + eSIR_SUCCESS) { + lim_log(pMac, LOGP, + FL("Fail to retrieve WNI_CFG_HT_CAP_INFO value")); + return; + } + ptr = (uint8_t *) &macHTCapabilityInfo; + *((uint16_t *) ptr) = (uint16_t) (cfgValue & 0xffff); + pMac->lim.gHTLsigTXOPProtection = + (uint8_t) macHTCapabilityInfo.lsigTXOPProtection; + pMac->lim.gHTMIMOPSState = + (tSirMacHTMIMOPowerSaveState) macHTCapabilityInfo.mimoPowerSave; + pMac->lim.gHTGreenfield = (uint8_t) macHTCapabilityInfo.greenField; + pMac->lim.gHTMaxAmsduLength = + (uint8_t) macHTCapabilityInfo.maximalAMSDUsize; + pMac->lim.gHTShortGI20Mhz = (uint8_t) macHTCapabilityInfo.shortGI20MHz; + pMac->lim.gHTShortGI40Mhz = (uint8_t) macHTCapabilityInfo.shortGI40MHz; + pMac->lim.gHTPSMPSupport = (uint8_t) macHTCapabilityInfo.psmp; + pMac->lim.gHTDsssCckRate40MHzSupport = + (uint8_t) macHTCapabilityInfo.dsssCckMode40MHz; + + if (wlan_cfg_get_int(pMac, WNI_CFG_HT_AMPDU_PARAMS, &cfgValue) != + eSIR_SUCCESS) { + lim_log(pMac, LOGP, + FL("Fail to retrieve WNI_CFG_HT_PARAM_INFO value")); + return; + } + ptr = (uint8_t *) &macHTParametersInfo; + *ptr = (uint8_t) (cfgValue & 0xff); + pMac->lim.gHTAMpduDensity = (uint8_t) macHTParametersInfo.mpduDensity; + pMac->lim.gHTMaxRxAMpduFactor = + (uint8_t) macHTParametersInfo.maxRxAMPDUFactor; + + /* Get HT IE Info */ + if (wlan_cfg_get_int(pMac, WNI_CFG_HT_INFO_FIELD1, &cfgValue) != + eSIR_SUCCESS) { + lim_log(pMac, LOGP, + FL("Fail to retrieve WNI_CFG_HT_INFO_FIELD1 value")); + return; + } + ptr = (uint8_t *) &macHTInfoField1; + *((uint8_t *) ptr) = (uint8_t) (cfgValue & 0xff); + pMac->lim.gHTServiceIntervalGranularity = + (uint8_t) macHTInfoField1.serviceIntervalGranularity; + pMac->lim.gHTControlledAccessOnly = + (uint8_t) macHTInfoField1.controlledAccessOnly; + pMac->lim.gHTRifsMode = (uint8_t) macHTInfoField1.rifsMode; + + if (wlan_cfg_get_int(pMac, WNI_CFG_HT_INFO_FIELD2, &cfgValue) != + eSIR_SUCCESS) { + lim_log(pMac, LOGP, + FL("Fail to retrieve WNI_CFG_HT_INFO_FIELD2 value")); + return; + } + ptr = (uint8_t *) &macHTInfoField2; + *((uint16_t *) ptr) = (uint16_t) (cfgValue & 0xffff); + pMac->lim.gHTOperMode = (tSirMacHTOperatingMode) macHTInfoField2.opMode; + + if (wlan_cfg_get_int(pMac, WNI_CFG_HT_INFO_FIELD3, &cfgValue) != + eSIR_SUCCESS) { + lim_log(pMac, LOGP, + FL("Fail to retrieve WNI_CFG_HT_INFO_FIELD3 value")); + return; + } + ptr = (uint8_t *) &macHTInfoField3; + *((uint16_t *) ptr) = (uint16_t) (cfgValue & 0xffff); + pMac->lim.gHTPCOActive = (uint8_t) macHTInfoField3.pcoActive; + pMac->lim.gHTPCOPhase = (uint8_t) macHTInfoField3.pcoPhase; + pMac->lim.gHTSecondaryBeacon = + (uint8_t) macHTInfoField3.secondaryBeacon; + pMac->lim.gHTDualCTSProtection = + (uint8_t) macHTInfoField3.dualCTSProtection; + pMac->lim.gHTSTBCBasicMCS = (uint8_t) macHTInfoField3.basicSTBCMCS; + + /* The lim globals for channelwidth and secondary chnl have been removed and should not be used during no session; + * instead direct cfg is read and used when no session for transmission of mgmt frames (same as old); + * For now, we might come here during init and join with sessionEntry = NULL; in that case just fill the globals which exist + * Sessionized entries values will be filled in join or add bss req. The ones which are missed in join are filled below + */ + if (psessionEntry != NULL) { + psessionEntry->htCapability = + IS_DOT11_MODE_HT(psessionEntry->dot11mode); + psessionEntry->beaconParams.fLsigTXOPProtectionFullSupport = + (uint8_t) macHTInfoField3.lsigTXOPProtectionFullSupport; + lim_init_obss_params(pMac, psessionEntry); + } +} + +void lim_log_session_states(tpAniSirGlobal mac_ctx) +{ +#ifdef WLAN_DEBUG + int i; + + for (i = 0; i < mac_ctx->lim.maxBssId; i++) { + if (mac_ctx->lim.gpSession[i].valid) { + QDF_TRACE(QDF_MODULE_ID_PE, LOG1, + FL("sysRole(%d) Session (%d)"), + mac_ctx->lim.gLimSystemRole, i); + QDF_TRACE(QDF_MODULE_ID_PE, LOG1, + FL("SME: Curr %s,Prev %s,MLM: Curr %s,Prev %s"), + lim_sme_state_str( + mac_ctx->lim.gpSession[i].limSmeState), + lim_sme_state_str( + mac_ctx->lim.gpSession[i].limPrevSmeState), + lim_mlm_state_str( + mac_ctx->lim.gpSession[i].limMlmState), + lim_mlm_state_str( + mac_ctx->lim.gpSession[i].limPrevMlmState)); + } + } +#endif +} diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_process_mlm_host_roam.c b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_process_mlm_host_roam.c new file mode 100644 index 0000000000000000000000000000000000000000..56b13a37f17faf998f662287dbef90371e5303a1 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_process_mlm_host_roam.c @@ -0,0 +1,746 @@ +/* + * Copyright (c) 2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * 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. + */ + +/** + * DOC: lim_process_mlm_host_roam.c + * + * Host based roaming MLM implementation + */ +#include "cds_api.h" +#include "wni_cfg.h" +#include "ani_global.h" +#include "sir_api.h" +#include "sir_params.h" +#include "cfg_api.h" + +#include "sch_api.h" +#include "utils_api.h" +#include "lim_utils.h" +#include "lim_assoc_utils.h" +#include "lim_prop_exts_utils.h" +#include "lim_security_utils.h" +#include "lim_send_messages.h" +#include "lim_send_messages.h" +#include "lim_session_utils.h" +#include +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM +#include "host_diag_core_log.h" +#endif +#include "wma_if.h" +#include "rrm_api.h" +static void lim_handle_sme_reaasoc_result(tpAniSirGlobal, tSirResultCodes, + uint16_t, tpPESession); +/** + * lim_process_mlm_reassoc_req() - process mlm reassoc request. + * + * @mac_ctx: pointer to Global MAC structure + * @msg: pointer to the MLM message buffer + * + * This function is called to process MLM_REASSOC_REQ message + * from SME + * + * Return: None + */ +void lim_process_mlm_reassoc_req(tpAniSirGlobal mac_ctx, uint32_t *msg) +{ + uint8_t channel, sec_ch_offset; + struct tLimPreAuthNode *auth_node; + tLimMlmReassocReq *reassoc_req; + tLimMlmReassocCnf reassoc_cnf; + tpPESession session; + + if (msg == NULL) { + lim_log(mac_ctx, LOGE, FL("Buffer is Pointing to NULL")); + return; + } + + reassoc_req = (tLimMlmReassocReq *) msg; + session = pe_find_session_by_session_id(mac_ctx, + reassoc_req->sessionId); + if (NULL == session) { + lim_log(mac_ctx, LOGE, + FL("Session Does not exist for given sessionId %d"), + reassoc_req->sessionId); + qdf_mem_free(reassoc_req); + return; + } + + lim_log(mac_ctx, LOG1, + FL("ReAssoc Req on session %d role %d mlm %d " MAC_ADDRESS_STR), + reassoc_req->sessionId, GET_LIM_SYSTEM_ROLE(session), + session->limMlmState, MAC_ADDR_ARRAY(reassoc_req->peerMacAddr)); + + if (LIM_IS_AP_ROLE(session) || + (session->limMlmState != + eLIM_MLM_LINK_ESTABLISHED_STATE)) { + /* + * Received Reassoc request in invalid state or + * in AP role.Return Reassoc confirm with Invalid + * parameters code. + */ + + lim_log(mac_ctx, LOGW, + FL("unexpect msg,state %Xrole %d,MAC" MAC_ADDRESS_STR), + session->limMlmState, GET_LIM_SYSTEM_ROLE(session), + MAC_ADDR_ARRAY(reassoc_req->peerMacAddr)); + lim_print_mlm_state(mac_ctx, LOGW, session->limMlmState); + reassoc_cnf.resultCode = eSIR_SME_INVALID_PARAMETERS; + reassoc_cnf.protStatusCode = eSIR_MAC_UNSPEC_FAILURE_STATUS; + goto end; + } + + if (session->pLimMlmReassocReq) + qdf_mem_free(session->pLimMlmReassocReq); + + /* + * Hold Re-Assoc request as part of Session, knock-out mac_ctx + * Hold onto Reassoc request parameters + */ + session->pLimMlmReassocReq = reassoc_req; + + /* See if we have pre-auth context with new AP */ + auth_node = lim_search_pre_auth_list(mac_ctx, session->limReAssocbssId); + + if (!auth_node && (qdf_mem_cmp(reassoc_req->peerMacAddr, + session->bssId, + sizeof(tSirMacAddr)))) { + /* + * Either pre-auth context does not exist AND + * we are not reassociating with currently + * associated AP. + * Return Reassoc confirm with not authenticated + */ + reassoc_cnf.resultCode = eSIR_SME_STA_NOT_AUTHENTICATED; + reassoc_cnf.protStatusCode = eSIR_MAC_UNSPEC_FAILURE_STATUS; + + goto end; + } + /* assign the sessionId to the timer object */ + mac_ctx->lim.limTimers.gLimReassocFailureTimer.sessionId = + reassoc_req->sessionId; + session->limPrevMlmState = session->limMlmState; + session->limMlmState = eLIM_MLM_WT_REASSOC_RSP_STATE; + MTRACE(mac_trace(mac_ctx, TRACE_CODE_MLM_STATE, session->peSessionId, + session->limMlmState)); + + /* Derive channel from BSS description and store it at CFG. */ + channel = session->limReassocChannelId; + sec_ch_offset = session->reAssocHtSecondaryChannelOffset; + + /* Apply previously set configuration at HW */ + lim_apply_configuration(mac_ctx, session); + + /* store the channel switch sessionEntry in the lim global var */ + session->channelChangeReasonCode = + LIM_SWITCH_CHANNEL_REASSOC; + + /* Switch channel to the new Operating channel for Reassoc */ + lim_set_channel(mac_ctx, channel, + session->ch_center_freq_seg0, + session->ch_center_freq_seg1, + session->ch_width, + session->maxTxPower, + session->peSessionId); + + return; +end: + reassoc_cnf.protStatusCode = eSIR_MAC_UNSPEC_FAILURE_STATUS; + /* Update PE sessio Id */ + reassoc_cnf.sessionId = reassoc_req->sessionId; + /* Free up buffer allocated for reassocReq */ + qdf_mem_free(reassoc_req); + session->pLimReAssocReq = NULL; + lim_post_sme_message(mac_ctx, LIM_MLM_REASSOC_CNF, + (uint32_t *) &reassoc_cnf); +} + +/** + * lim_handle_sme_reaasoc_result() - Handle the reassoc result + * @pMac: Global MAC Context + * @resultCode: Result code + * @protStatusCode: Protocol Status Code + * @psessionEntry: PE Session + * + * This function is called to process reassoc failures + * upon receiving REASSOC_CNF with a failure code or + * MLM_REASSOC_CNF with a success code in case of STA role + * + * Return: None + */ +static void lim_handle_sme_reaasoc_result(tpAniSirGlobal pMac, + tSirResultCodes resultCode, uint16_t protStatusCode, + tpPESession psessionEntry) +{ + tpDphHashNode pStaDs = NULL; + uint8_t smesessionId; + uint16_t smetransactionId; + + if (psessionEntry == NULL) { + PELOGE(lim_log(pMac, LOGE, FL("psessionEntry is NULL "));) + return; + } + smesessionId = psessionEntry->smeSessionId; + smetransactionId = psessionEntry->transactionId; + if (resultCode != eSIR_SME_SUCCESS) { + pStaDs = + dph_get_hash_entry(pMac, DPH_STA_HASH_INDEX_PEER, + &psessionEntry->dph.dphHashTable); + if (pStaDs != NULL) { + pStaDs->mlmStaContext.disassocReason = + eSIR_MAC_UNSPEC_FAILURE_REASON; + pStaDs->mlmStaContext.cleanupTrigger = + eLIM_JOIN_FAILURE; + pStaDs->mlmStaContext.resultCode = resultCode; + pStaDs->mlmStaContext.protStatusCode = protStatusCode; + lim_cleanup_rx_path(pMac, pStaDs, psessionEntry); + /* Cleanup if add bss failed */ + if (psessionEntry->add_bss_failed) { + dph_delete_hash_entry(pMac, + pStaDs->staAddr, pStaDs->assocId, + &psessionEntry->dph.dphHashTable); + goto error; + } + return; + } + } +error: + /* Delete teh session if REASSOC failure occurred. */ + if (resultCode != eSIR_SME_SUCCESS) { + if (NULL != psessionEntry) { + pe_delete_session(pMac, psessionEntry); + psessionEntry = NULL; + } + } + lim_send_sme_join_reassoc_rsp(pMac, eWNI_SME_REASSOC_RSP, resultCode, + protStatusCode, psessionEntry, smesessionId, smetransactionId); +} + +/** + * lim_process_mlm_reassoc_cnf() - process mlm reassoc cnf msg + * + * @mac_ctx: Pointer to Global MAC structure + * @msg_buf: A pointer to the MLM message buffer + * + * This function is called to process MLM_REASSOC_CNF message from MLM State + * machine. + * + * @Return: void + */ +void lim_process_mlm_reassoc_cnf(tpAniSirGlobal mac_ctx, uint32_t *msg_buf) +{ + tpPESession session; + tLimMlmReassocCnf *lim_mlm_reassoc_cnf; + + if (msg_buf == NULL) { + lim_log(mac_ctx, LOGE, FL("Buffer is Pointing to NULL")); + return; + } + lim_mlm_reassoc_cnf = (tLimMlmReassocCnf *) msg_buf; + session = pe_find_session_by_session_id(mac_ctx, + lim_mlm_reassoc_cnf->sessionId); + if (session == NULL) { + lim_log(mac_ctx, LOGE, + FL("session Does not exist for given session Id")); + return; + } + if ((session->limSmeState != eLIM_SME_WT_REASSOC_STATE) || + LIM_IS_AP_ROLE(session)) { + /* + * Should not have received Reassocication confirm + * from MLM in other states OR on AP. + */ + lim_log(mac_ctx, LOGE, + FL("Rcv unexpected MLM_REASSOC_CNF role %d, sme 0x%X"), + GET_LIM_SYSTEM_ROLE(session), session->limSmeState); + return; + } + if (session->pLimReAssocReq) { + qdf_mem_free(session->pLimReAssocReq); + session->pLimReAssocReq = NULL; + } + + /* + * Upon Reassoc success or failure, freeup the cached preauth request, + * to ensure that channel switch is now allowed following any change in + * HT params. + */ + if (session->ftPEContext.pFTPreAuthReq) { + lim_log(mac_ctx, LOG1, FL("Freeing pFTPreAuthReq= %p"), + session->ftPEContext.pFTPreAuthReq); + if (session->ftPEContext.pFTPreAuthReq->pbssDescription) { + qdf_mem_free( + session->ftPEContext.pFTPreAuthReq->pbssDescription); + session->ftPEContext.pFTPreAuthReq->pbssDescription = + NULL; + } + qdf_mem_free(session->ftPEContext.pFTPreAuthReq); + session->ftPEContext.pFTPreAuthReq = NULL; + session->ftPEContext.ftPreAuthSession = false; + } + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + if (session->bRoamSynchInProgress) { + QDF_TRACE(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_DEBUG, + FL("LFR3:Re-set the LIM Ctxt Roam Synch In Progress")); + session->bRoamSynchInProgress = false; + } +#endif + + lim_log(mac_ctx, LOG1, FL("Rcv MLM_REASSOC_CNF with result code %d"), + lim_mlm_reassoc_cnf->resultCode); + if (lim_mlm_reassoc_cnf->resultCode == eSIR_SME_SUCCESS) { + /* Successful Reassociation */ + QDF_TRACE(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_DEBUG, + FL("*** Reassociated with new BSS ***")); + + session->limSmeState = eLIM_SME_LINK_EST_STATE; + MTRACE(mac_trace(mac_ctx, TRACE_CODE_SME_STATE, + session->peSessionId, session->limSmeState)); + + /* Need to send Reassoc rsp with Reassoc success to Host. */ + lim_send_sme_join_reassoc_rsp(mac_ctx, eWNI_SME_REASSOC_RSP, + lim_mlm_reassoc_cnf->resultCode, + lim_mlm_reassoc_cnf->protStatusCode, + session, session->smeSessionId, + session->transactionId); + } else if (lim_mlm_reassoc_cnf->resultCode + == eSIR_SME_REASSOC_REFUSED) { + /* + * Reassociation failure With the New AP but we still have the + * link with the Older AP + */ + session->limSmeState = eLIM_SME_LINK_EST_STATE; + MTRACE(mac_trace(mac_ctx, TRACE_CODE_SME_STATE, + session->peSessionId, session->limSmeState)); + + /* Need to send Reassoc rsp with Assoc failure to Host. */ + lim_send_sme_join_reassoc_rsp(mac_ctx, eWNI_SME_REASSOC_RSP, + lim_mlm_reassoc_cnf->resultCode, + lim_mlm_reassoc_cnf->protStatusCode, + session, session->smeSessionId, + session->transactionId); + } else { + /* Reassociation failure */ + session->limSmeState = eLIM_SME_JOIN_FAILURE_STATE; + MTRACE(mac_trace(mac_ctx, TRACE_CODE_SME_STATE, + session->peSessionId, session->limSmeState)); + /* Need to send Reassoc rsp with Assoc failure to Host. */ + lim_handle_sme_reaasoc_result(mac_ctx, + lim_mlm_reassoc_cnf->resultCode, + lim_mlm_reassoc_cnf->protStatusCode, + session); + } +} + +/** + * lim_process_sta_mlm_add_bss_rsp_ft() - Handle the ADD BSS response + * @pMac: Global MAC context + * @limMsgQ: ADD BSS Parameters + * @psessionEntry: PE Session + * + * Function to handle WMA_ADD_BSS_RSP, in FT reassoc state. + * Send ReAssociation Request. + * + *Return: None + */ +void lim_process_sta_mlm_add_bss_rsp_ft(tpAniSirGlobal pMac, + tpSirMsgQ limMsgQ, tpPESession psessionEntry) +{ + tLimMlmReassocCnf mlmReassocCnf; /* keep sme */ + tpDphHashNode pStaDs = NULL; + tpAddStaParams pAddStaParams = NULL; + uint32_t listenInterval = WNI_CFG_LISTEN_INTERVAL_STADEF; + tpAddBssParams pAddBssParams = (tpAddBssParams) limMsgQ->bodyptr; + uint32_t selfStaDot11Mode = 0; + + /* Sanity Checks */ + + if (pAddBssParams == NULL) { + PELOGE(lim_log(pMac, LOGE, FL("Invalid parameters"));) + goto end; + } + if (eLIM_MLM_WT_ADD_BSS_RSP_FT_REASSOC_STATE != + psessionEntry->limMlmState) { + goto end; + } + + pStaDs = dph_add_hash_entry(pMac, pAddBssParams->bssId, + DPH_STA_HASH_INDEX_PEER, + &psessionEntry->dph.dphHashTable); + if (pStaDs == NULL) { + /* Could not add hash table entry */ + lim_log(pMac, LOGE, FL("could not add hash entry at DPH for")); + lim_print_mac_addr(pMac, pAddBssParams->staContext.staMac, + LOGE); + goto end; + } + /* Prepare and send Reassociation request frame */ + /* start reassoc timer. */ +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + if (psessionEntry->bRoamSynchInProgress != true) { +#endif + pMac->lim.limTimers.gLimReassocFailureTimer.sessionId = + psessionEntry->peSessionId; + /* / Start reassociation failure timer */ + MTRACE(mac_trace + (pMac, TRACE_CODE_TIMER_ACTIVATE, + psessionEntry->peSessionId, eLIM_REASSOC_FAIL_TIMER)); + if (tx_timer_activate + (&pMac->lim.limTimers.gLimReassocFailureTimer) + != TX_SUCCESS) { + /* / Could not start reassoc failure timer. */ + /* Log error */ + lim_log(pMac, LOGP, + FL("could not start Reassoc failure timer")); + /* Return Reassoc confirm with */ + /* Resources Unavailable */ + mlmReassocCnf.resultCode = + eSIR_SME_RESOURCES_UNAVAILABLE; + mlmReassocCnf.protStatusCode = + eSIR_MAC_UNSPEC_FAILURE_STATUS; + goto end; + } + pMac->lim.pSessionEntry = psessionEntry; + if (NULL == pMac->lim.pSessionEntry->pLimMlmReassocRetryReq) { + /* Take a copy of reassoc request for retrying */ + pMac->lim.pSessionEntry->pLimMlmReassocRetryReq = + qdf_mem_malloc(sizeof(tLimMlmReassocReq)); + if (NULL == + pMac->lim.pSessionEntry->pLimMlmReassocRetryReq) + goto end; + qdf_mem_copy(pMac->lim.pSessionEntry-> + pLimMlmReassocRetryReq, + psessionEntry->pLimMlmReassocReq, + sizeof(tLimMlmReassocReq)); + } + pMac->lim.reAssocRetryAttempt = 0; + lim_send_reassoc_req_with_ft_ies_mgmt_frame(pMac, + psessionEntry-> + pLimMlmReassocReq, + psessionEntry); +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + } else { + QDF_TRACE(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_DEBUG, + "LFR3:Do not activate timer and dont send the reassoc"); + } +#endif + psessionEntry->limPrevMlmState = psessionEntry->limMlmState; + psessionEntry->limMlmState = eLIM_MLM_WT_FT_REASSOC_RSP_STATE; + MTRACE(mac_trace + (pMac, TRACE_CODE_MLM_STATE, psessionEntry->peSessionId, + eLIM_MLM_WT_FT_REASSOC_RSP_STATE)); + PELOGE(lim_log + (pMac, LOG1, FL("Set the mlm state to %d session=%d"), + psessionEntry->limMlmState, psessionEntry->peSessionId); + ) + + psessionEntry->bssIdx = (uint8_t) pAddBssParams->bssIdx; + + /* Success, handle below */ + pStaDs->bssId = pAddBssParams->bssIdx; + /* STA Index(genr by HAL) for the BSS entry is stored here */ + pStaDs->staIndex = pAddBssParams->staContext.staIdx; + pStaDs->ucUcastSig = pAddBssParams->staContext.ucUcastSig; + pStaDs->ucBcastSig = pAddBssParams->staContext.ucBcastSig; + + rrm_cache_mgmt_tx_power(pMac, pAddBssParams->txMgmtPower, + psessionEntry); + + pAddStaParams = qdf_mem_malloc(sizeof(tAddStaParams)); + if (NULL == pAddStaParams) { + lim_log(pMac, LOGP, + FL("Unable to allocate memory during ADD_STA")); + goto end; + } + + /* / Add STA context at MAC HW (BMU, RHP & TFP) */ + qdf_mem_copy((uint8_t *) pAddStaParams->staMac, + (uint8_t *) psessionEntry->selfMacAddr, + sizeof(tSirMacAddr)); + + qdf_mem_copy((uint8_t *) pAddStaParams->bssId, + psessionEntry->bssId, sizeof(tSirMacAddr)); + + pAddStaParams->staType = STA_ENTRY_SELF; + pAddStaParams->status = QDF_STATUS_SUCCESS; + pAddStaParams->respReqd = 1; + + /* Update PE session ID */ + pAddStaParams->sessionId = psessionEntry->peSessionId; + pAddStaParams->smesessionId = psessionEntry->smeSessionId; + + /* This will indicate HAL to "allocate" a new STA index */ +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + if (psessionEntry->bRoamSynchInProgress != true) +#endif + pAddStaParams->staIdx = STA_INVALID_IDX; + pAddStaParams->updateSta = false; + + pAddStaParams->shortPreambleSupported = + (uint8_t) psessionEntry->beaconParams.fShortPreamble; + lim_populate_peer_rate_set(pMac, &pAddStaParams->supportedRates, NULL, + false, psessionEntry, NULL); + + if (psessionEntry->htCapability) { + pAddStaParams->htCapable = psessionEntry->htCapability; + pAddStaParams->vhtCapable = psessionEntry->vhtCapability; + pAddStaParams->ch_width = psessionEntry->ch_width; + pAddStaParams->greenFieldCapable = + lim_get_ht_capability(pMac, eHT_GREENFIELD, + psessionEntry); + pAddStaParams->mimoPS = + lim_get_ht_capability(pMac, eHT_MIMO_POWER_SAVE, + psessionEntry); + pAddStaParams->rifsMode = + lim_get_ht_capability(pMac, eHT_RIFS_MODE, + psessionEntry); + pAddStaParams->lsigTxopProtection = + lim_get_ht_capability(pMac, eHT_LSIG_TXOP_PROTECTION, + psessionEntry); + pAddStaParams->maxAmpduDensity = + lim_get_ht_capability(pMac, eHT_MPDU_DENSITY, + psessionEntry); + pAddStaParams->maxAmpduSize = + lim_get_ht_capability(pMac, eHT_MAX_RX_AMPDU_FACTOR, + psessionEntry); + pAddStaParams->maxAmsduSize = + lim_get_ht_capability(pMac, eHT_MAX_AMSDU_LENGTH, + psessionEntry); + pAddStaParams->max_amsdu_num = + lim_get_ht_capability(pMac, eHT_MAX_AMSDU_NUM, + psessionEntry); + pAddStaParams->fDsssCckMode40Mhz = + lim_get_ht_capability(pMac, eHT_DSSS_CCK_MODE_40MHZ, + psessionEntry); + pAddStaParams->fShortGI20Mhz = + lim_get_ht_capability(pMac, eHT_SHORT_GI_20MHZ, + psessionEntry); + pAddStaParams->fShortGI40Mhz = + lim_get_ht_capability(pMac, eHT_SHORT_GI_40MHZ, + psessionEntry); + } + + if (wlan_cfg_get_int(pMac, WNI_CFG_LISTEN_INTERVAL, &listenInterval) != + eSIR_SUCCESS) + lim_log(pMac, LOGP, FL("Couldn't get LISTEN_INTERVAL")); + pAddStaParams->listenInterval = (uint16_t) listenInterval; + + wlan_cfg_get_int(pMac, WNI_CFG_DOT11_MODE, &selfStaDot11Mode); + pAddStaParams->encryptType = psessionEntry->encryptType; + pAddStaParams->maxTxPower = psessionEntry->maxTxPower; + + /* Lets save this for when we receive the Reassoc Rsp */ + psessionEntry->ftPEContext.pAddStaReq = pAddStaParams; + + if (pAddBssParams != NULL) { + qdf_mem_free(pAddBssParams); + pAddBssParams = NULL; + limMsgQ->bodyptr = NULL; + } +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + if (psessionEntry->bRoamSynchInProgress) { + QDF_TRACE(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_DEBUG, + "LFR3:Prep and save AddStaReq for post-assoc-rsp"); + lim_process_assoc_rsp_frame(pMac, pMac->roam.pReassocResp, + LIM_REASSOC, psessionEntry); + } +#endif + return; + +end: + /* Free up buffer allocated for reassocReq */ + if (psessionEntry != NULL) + if (psessionEntry->pLimMlmReassocReq != NULL) { + qdf_mem_free(psessionEntry->pLimMlmReassocReq); + psessionEntry->pLimMlmReassocReq = NULL; + } + + if (pAddBssParams != NULL) { + qdf_mem_free(pAddBssParams); + pAddBssParams = NULL; + limMsgQ->bodyptr = NULL; + } + + mlmReassocCnf.resultCode = eSIR_SME_FT_REASSOC_FAILURE; + mlmReassocCnf.protStatusCode = eSIR_MAC_UNSPEC_FAILURE_STATUS; + /* Update PE session Id */ + if (psessionEntry != NULL) + mlmReassocCnf.sessionId = psessionEntry->peSessionId; + else + mlmReassocCnf.sessionId = 0; + + lim_post_sme_message(pMac, LIM_MLM_REASSOC_CNF, + (uint32_t *) &mlmReassocCnf); +} + +/** + * lim_process_mlm_ft_reassoc_req() - Handle the Reassoc request + * @pMac: Global MAC context + * @pMsgBuf: Buffer which holds the data + * @psessionEntry: PE Session + * + * This function handles the Reassoc Req from SME + * + * Return: None + */ +void lim_process_mlm_ft_reassoc_req(tpAniSirGlobal pMac, uint32_t *pMsgBuf, + tpPESession psessionEntry) +{ + uint8_t smeSessionId = 0; + uint16_t transactionId = 0; + uint8_t chanNum = 0; + tLimMlmReassocReq *pMlmReassocReq; + uint16_t caps; + uint32_t val; + tSirMsgQ msgQ; + tSirRetStatus retCode; + uint32_t teleBcnEn = 0; + + chanNum = psessionEntry->currentOperChannel; + lim_get_session_info(pMac, (uint8_t *) pMsgBuf, &smeSessionId, + &transactionId); + psessionEntry->smeSessionId = smeSessionId; + psessionEntry->transactionId = transactionId; + +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM /* FEATURE_WLAN_DIAG_SUPPORT */ + lim_diag_event_report(pMac, WLAN_PE_DIAG_REASSOCIATING, + psessionEntry, 0, 0); +#endif + + /* Nothing to be done if the session is not in STA mode */ + if (!LIM_IS_STA_ROLE(psessionEntry)) { + lim_log(pMac, LOGE, FL("psessionEntry is not in STA mode")); + return; + } + + if (NULL == psessionEntry->ftPEContext.pAddBssReq) { + lim_log(pMac, LOGE, FL("pAddBssReq is NULL")); + return; + } + pMlmReassocReq = qdf_mem_malloc(sizeof(tLimMlmReassocReq)); + if (NULL == pMlmReassocReq) { + lim_log(pMac, LOGE, + FL("call to AllocateMemory failed for mlmReassocReq")); + return; + } + + qdf_mem_copy(pMlmReassocReq->peerMacAddr, + psessionEntry->bssId, sizeof(tSirMacAddr)); + + if (wlan_cfg_get_int(pMac, WNI_CFG_REASSOCIATION_FAILURE_TIMEOUT, + (uint32_t *) &pMlmReassocReq->reassocFailureTimeout) + != eSIR_SUCCESS) { + /** + * Could not get ReassocFailureTimeout value + * from CFG. Log error. + */ + lim_log(pMac, LOGE, + FL("could not retrieve ReassocFailureTimeout value")); + qdf_mem_free(pMlmReassocReq); + return; + } + + if (cfg_get_capability_info(pMac, &caps, psessionEntry) != + eSIR_SUCCESS) { + /** + * Could not get Capabilities value + * from CFG. Log error. + */ + lim_log(pMac, LOGE, FL("could not get Capabilities value")); + qdf_mem_free(pMlmReassocReq); + return; + } + + lim_update_caps_info_for_bss(pMac, &caps, + psessionEntry->pLimReAssocReq->bssDescription.capabilityInfo); + lim_log(pMac, LOG1, FL("Capabilities info FT Reassoc: 0x%X"), caps); + + pMlmReassocReq->capabilityInfo = caps; + + /* Update PE sessionId */ + pMlmReassocReq->sessionId = psessionEntry->peSessionId; + + /* If telescopic beaconing is enabled, set listen interval + to WNI_CFG_TELE_BCN_MAX_LI + */ + if (wlan_cfg_get_int(pMac, WNI_CFG_TELE_BCN_WAKEUP_EN, &teleBcnEn) != + eSIR_SUCCESS) { + lim_log(pMac, LOGP, + FL("Couldn't get WNI_CFG_TELE_BCN_WAKEUP_EN")); + qdf_mem_free(pMlmReassocReq); + return; + } + + if (teleBcnEn) { + if (wlan_cfg_get_int(pMac, WNI_CFG_TELE_BCN_MAX_LI, &val) != + eSIR_SUCCESS) { + /** + * Could not get ListenInterval value + * from CFG. Log error. + */ + lim_log(pMac, LOGE, + FL("could not retrieve ListenInterval")); + qdf_mem_free(pMlmReassocReq); + return; + } + } else { + if (wlan_cfg_get_int(pMac, WNI_CFG_LISTEN_INTERVAL, &val) != + eSIR_SUCCESS) { + /** + * Could not get ListenInterval value + * from CFG. Log error. + */ + lim_log(pMac, LOGE, + FL("could not retrieve ListenInterval")); + qdf_mem_free(pMlmReassocReq); + return; + } + } + if (lim_set_link_state + (pMac, eSIR_LINK_PREASSOC_STATE, psessionEntry->bssId, + psessionEntry->selfMacAddr, NULL, NULL) != eSIR_SUCCESS) { + qdf_mem_free(pMlmReassocReq); + return; + } + + pMlmReassocReq->listenInterval = (uint16_t) val; + psessionEntry->pLimMlmReassocReq = pMlmReassocReq; + + /* we need to defer the message until we get response back from HAL */ + SET_LIM_PROCESS_DEFD_MESGS(pMac, false); + + msgQ.type = SIR_HAL_ADD_BSS_REQ; + msgQ.reserved = 0; + msgQ.bodyptr = psessionEntry->ftPEContext.pAddBssReq; + msgQ.bodyval = 0; + + lim_log(pMac, LOG1, FL("Sending SIR_HAL_ADD_BSS_REQ...")); + MTRACE(mac_trace_msg_tx(pMac, psessionEntry->peSessionId, msgQ.type)); + retCode = wma_post_ctrl_msg(pMac, &msgQ); + if (eSIR_SUCCESS != retCode) { + qdf_mem_free(psessionEntry->ftPEContext.pAddBssReq); + lim_log(pMac, LOGE, + FL("Posting ADD_BSS_REQ to HAL failed, reason=%X"), + retCode); + } + + psessionEntry->ftPEContext.pAddBssReq = NULL; + return; +} diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_process_mlm_req_messages.c b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_process_mlm_req_messages.c new file mode 100644 index 0000000000000000000000000000000000000000..b4aee9d5638af2807079a21d4844e27715f5d2fa --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_process_mlm_req_messages.c @@ -0,0 +1,2704 @@ +/* + * Copyright (c) 2011-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#include "cds_api.h" +#include "wni_cfg.h" +#include "ani_global.h" +#include "sir_api.h" +#include "sir_params.h" +#include "cfg_api.h" + +#include "sch_api.h" +#include "utils_api.h" +#include "lim_utils.h" +#include "lim_assoc_utils.h" +#include "lim_prop_exts_utils.h" +#include "lim_security_utils.h" +#include "lim_send_messages.h" +#include "lim_send_messages.h" +#include "lim_session_utils.h" +#include +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM +#include "host_diag_core_log.h" +#endif +#include "wma_if.h" + +static void lim_process_mlm_start_req(tpAniSirGlobal, uint32_t *); +static void lim_process_mlm_join_req(tpAniSirGlobal, uint32_t *); +static void lim_process_mlm_auth_req(tpAniSirGlobal, uint32_t *); +static void lim_process_mlm_assoc_req(tpAniSirGlobal, uint32_t *); +static void lim_process_mlm_disassoc_req(tpAniSirGlobal, uint32_t *); +static void lim_process_mlm_deauth_req(tpAniSirGlobal, uint32_t *); +static void lim_process_mlm_set_keys_req(tpAniSirGlobal, uint32_t *); + +/* MLM Timeout event handler templates */ +static void lim_process_periodic_probe_req_timer(tpAniSirGlobal mac_ctx); +static void lim_process_join_failure_timeout(tpAniSirGlobal); +static void lim_process_auth_failure_timeout(tpAniSirGlobal); +static void lim_process_auth_rsp_timeout(tpAniSirGlobal, uint32_t); +static void lim_process_assoc_failure_timeout(tpAniSirGlobal, uint32_t); +static void lim_process_periodic_join_probe_req_timer(tpAniSirGlobal); +static void lim_process_auth_retry_timer(tpAniSirGlobal); + +/** + * lim_process_mlm_req_messages() - process mlm request messages + * @mac_ctx: global MAC context + * @msg: mlm request message + * + * This function is called by lim_post_mlm_message(). This + * function handles MLM primitives invoked by SME. + * Depending on the message type, corresponding function will be + * called. + * ASSUMPTIONS: + * 1. Upon receiving Beacon in WT_JOIN_STATE, MLM module invokes + * APIs exposed by Beacon Processing module for setting parameters + * at MAC hardware. + * 2. If attempt to Reassociate with an AP fails, link with current + * AP is restored back. + * + * Return: None + */ +void lim_process_mlm_req_messages(tpAniSirGlobal mac_ctx, tpSirMsgQ msg) +{ + switch (msg->type) { + case LIM_MLM_START_REQ: + lim_process_mlm_start_req(mac_ctx, msg->bodyptr); + break; + case LIM_MLM_JOIN_REQ: + lim_process_mlm_join_req(mac_ctx, msg->bodyptr); + break; + case LIM_MLM_AUTH_REQ: + lim_process_mlm_auth_req(mac_ctx, msg->bodyptr); + break; + case LIM_MLM_ASSOC_REQ: + lim_process_mlm_assoc_req(mac_ctx, msg->bodyptr); + break; + case LIM_MLM_REASSOC_REQ: + lim_process_mlm_reassoc_req(mac_ctx, msg->bodyptr); + break; + case LIM_MLM_DISASSOC_REQ: + lim_process_mlm_disassoc_req(mac_ctx, msg->bodyptr); + break; + case LIM_MLM_DEAUTH_REQ: + lim_process_mlm_deauth_req(mac_ctx, msg->bodyptr); + break; + case LIM_MLM_SETKEYS_REQ: + lim_process_mlm_set_keys_req(mac_ctx, msg->bodyptr); + break; + case SIR_LIM_PERIODIC_PROBE_REQ_TIMEOUT: + lim_process_periodic_probe_req_timer(mac_ctx); + break; + case SIR_LIM_JOIN_FAIL_TIMEOUT: + lim_process_join_failure_timeout(mac_ctx); + break; + case SIR_LIM_PERIODIC_JOIN_PROBE_REQ_TIMEOUT: + lim_process_periodic_join_probe_req_timer(mac_ctx); + break; + case SIR_LIM_AUTH_FAIL_TIMEOUT: + lim_process_auth_failure_timeout(mac_ctx); + break; + case SIR_LIM_AUTH_RSP_TIMEOUT: + lim_process_auth_rsp_timeout(mac_ctx, msg->bodyval); + break; + case SIR_LIM_ASSOC_FAIL_TIMEOUT: + lim_process_assoc_failure_timeout(mac_ctx, msg->bodyval); + break; + case SIR_LIM_FT_PREAUTH_RSP_TIMEOUT: + lim_process_ft_preauth_rsp_timeout(mac_ctx); + break; + case SIR_LIM_REMAIN_CHN_TIMEOUT: + lim_process_remain_on_chn_timeout(mac_ctx); + break; + case SIR_LIM_INSERT_SINGLESHOT_NOA_TIMEOUT: + lim_process_insert_single_shot_noa_timeout(mac_ctx); + break; + case SIR_LIM_CONVERT_ACTIVE_CHANNEL_TO_PASSIVE: + lim_convert_active_channel_to_passive_channel(mac_ctx); + break; + case SIR_LIM_DISASSOC_ACK_TIMEOUT: + lim_process_disassoc_ack_timeout(mac_ctx); + break; + case SIR_LIM_DEAUTH_ACK_TIMEOUT: + lim_process_deauth_ack_timeout(mac_ctx); + break; + case SIR_LIM_AUTH_RETRY_TIMEOUT: + lim_process_auth_retry_timer(mac_ctx); + break; + case LIM_MLM_TSPEC_REQ: + default: + break; + } /* switch (msg->type) */ +} + +/* WLAN_SUSPEND_LINK Related */ + +/** + * lim_is_link_suspended()- check if link is suspended + * @mac_ctx: global MAC context + * + * This function returns is link is suspended or not. + * Since Suspend link uses init scan, it just returns + * gLimSystemInScanLearnMode flag. + * + * Return: uint8_t(gLimSystemInScanLearnMode flag) + */ +uint8_t lim_is_link_suspended(tpAniSirGlobal mac_ctx) +{ + return mac_ctx->lim.gLimSystemInScanLearnMode; +} + +/** + * lim_change_channel_with_callback() - change channel and register callback + * @mac_ctx: global MAC context + * @new_chan: new channel to switch + * @callback: Callback function + * @cbdata: callback data + * @session_entry: PE session pointer + * + * This function is called to change channel and perform off channel operation + * if required. The caller registers a callback to be called at the end of the + * channel change. + * + * Return: None + */ +void +lim_change_channel_with_callback(tpAniSirGlobal mac_ctx, uint8_t new_chan, + CHANGE_CHANNEL_CALLBACK callback, + uint32_t *cbdata, tpPESession session_entry) +{ + /* Sanity checks for the current and new channel */ + lim_log(mac_ctx, LOG1, FL("Switching channel to %d"), new_chan); + session_entry->channelChangeReasonCode = + LIM_SWITCH_CHANNEL_OPERATION; + + mac_ctx->lim.gpchangeChannelCallback = callback; + mac_ctx->lim.gpchangeChannelData = cbdata; + + lim_send_switch_chnl_params(mac_ctx, new_chan, 0, 0, + CH_WIDTH_20MHZ, session_entry->maxTxPower, + session_entry->peSessionId, false); + + return; +} + +/** + * lim_covert_channel_scan_type() - switch between ACTIVE and PASSIVE scan type + * @mac_ctx: global MAC context + * @chan_num: channel number to change the scan type + * @passive_to_active: flag to indicate if switch allowed + * + * This function is called to get the list, + * change the channel type and set again. + * NOTE: If a channel is ACTIVE, this function will make it as PASSIVE + * If a channel is PASSIVE, this fucntion will make it as ACTIVE + * + * Return: None + */ + +void lim_covert_channel_scan_type(tpAniSirGlobal mac_ctx, uint8_t chan_num, + bool passive_to_active) +{ + + uint32_t i; + uint8_t chan_pair[WNI_CFG_SCAN_CONTROL_LIST_LEN]; + uint32_t len = WNI_CFG_SCAN_CONTROL_LIST_LEN; + tSirRetStatus status; + + status = wlan_cfg_get_str(mac_ctx, WNI_CFG_SCAN_CONTROL_LIST, + chan_pair, &len); + if (eSIR_SUCCESS != status) { + lim_log(mac_ctx, LOGE, FL("Unable to get scan control list")); + return; + } + if (len > WNI_CFG_SCAN_CONTROL_LIST_LEN) { + lim_log(mac_ctx, LOGE, + FL("Invalid scan control list length:%d"), len); + return; + } + for (i = 0; (i + 1) < len; i += 2) { + if (chan_pair[i] != chan_num) /* skip this channel */ + continue; + if ((eSIR_PASSIVE_SCAN == chan_pair[i + 1]) && + true == passive_to_active) { + lim_log(mac_ctx, LOG1, FL + ("Channel %d changed from Passive to Active"), + chan_num); + chan_pair[i + 1] = eSIR_ACTIVE_SCAN; + break; + } + if ((eSIR_ACTIVE_SCAN == chan_pair[i + 1]) && + false == passive_to_active) { + lim_log(mac_ctx, LOG1, FL + ("Channel %d changed from Active to Passive"), + chan_num); + chan_pair[i + 1] = eSIR_PASSIVE_SCAN; + break; + } + } + + cfg_set_str_notify(mac_ctx, WNI_CFG_SCAN_CONTROL_LIST, + (uint8_t *) chan_pair, len, false); + return; +} + +/** + * lim_set_dfs_channel_list() - convert dfs channel list to active channel list + * @mac_ctx: global MAC context. + * @chan_num: channel number + * @dfs_ch_list: list of DFS channels + * + * This function is called to convert DFS channel list to active channel list + * when any beacon is present on that channel. This function store time for + * passive channels which help to know that for how much time channel has been + * passive. + * + * NOTE: If a channel is ACTIVE, it won't store any time + * If a channel is PAssive, it will store time as timestamp + * + * Return: None + */ +void lim_set_dfs_channel_list(tpAniSirGlobal mac_ctx, uint8_t chan_num, + tSirDFSChannelList *dfs_ch_list) +{ + bool pass_to_active = true; + + if (!((1 <= chan_num) && (165 >= chan_num))) { + lim_log(mac_ctx, LOGE, FL("Invalid Channel: %d"), chan_num); + return; + } + + if (true == lim_isconnected_on_dfs_channel(chan_num)) { + if (dfs_ch_list->timeStamp[chan_num] == 0) { + /* + * Received first beacon; + * Convert DFS channel to Active channel. + */ + lim_log(mac_ctx, LOG1, + FL("Received first beacon on DFS channel: %d"), + chan_num); + lim_covert_channel_scan_type(mac_ctx, chan_num, + pass_to_active); + } + dfs_ch_list->timeStamp[chan_num] = + qdf_mc_timer_get_system_time(); + } else { + return; + } + + if (!tx_timer_running + (&mac_ctx->lim.limTimers.gLimActiveToPassiveChannelTimer)) { + tx_timer_activate( + &mac_ctx->lim.limTimers.gLimActiveToPassiveChannelTimer); + } + + return; +} + +/** + * lim_restore_pre_scan_state() - restore HW state prior to scan + * + * @mac_ctx: global MAC context + * + * This function is called by lim_continue_channel_scan() + * to restore HW state prior to entering 'scan state' + * + * Return: None + */ +void lim_restore_pre_scan_state(tpAniSirGlobal mac_ctx) +{ + /* Deactivate MIN/MAX channel timers if running */ + lim_deactivate_and_change_timer(mac_ctx, eLIM_MIN_CHANNEL_TIMER); + lim_deactivate_and_change_timer(mac_ctx, eLIM_MAX_CHANNEL_TIMER); + + mac_ctx->lim.gLimSystemInScanLearnMode = 0; + lim_log(mac_ctx, LOG1, FL("Scan ended, took %llu tu"), + (tx_time_get() - mac_ctx->lim.scanStartTime)); +} + +/** + * mlm_add_sta() - MLM add sta + * @mac_ctx: global MAC context + * @sta_param: Add sta params + * @bssid: BSSID + * @ht_capable: HT capability + * @session_entry: PE session entry + * + * This function is called to update station parameters + * + * Return: None + */ +static void mlm_add_sta(tpAniSirGlobal mac_ctx, tpAddStaParams sta_param, + uint8_t *bssid, uint8_t ht_capable, tpPESession session_entry) +{ + uint32_t val; + uint32_t self_dot11mode = 0; + + wlan_cfg_get_int(mac_ctx, WNI_CFG_DOT11_MODE, &self_dot11mode); + sta_param->staType = STA_ENTRY_SELF; /* Identifying self */ + + qdf_mem_copy(sta_param->bssId, bssid, sizeof(tSirMacAddr)); + qdf_mem_copy(sta_param->staMac, session_entry->selfMacAddr, + sizeof(tSirMacAddr)); + + /* Configuration related parameters to be changed to support BT-AMP */ + + if (eSIR_SUCCESS != wlan_cfg_get_int(mac_ctx, WNI_CFG_LISTEN_INTERVAL, + &val)) + lim_log(mac_ctx, LOGP, FL("Couldn't get LISTEN_INTERVAL")); + sta_param->listenInterval = (uint16_t) val; + + if (eSIR_SUCCESS != wlan_cfg_get_int(mac_ctx, WNI_CFG_SHORT_PREAMBLE, + &val)) + lim_log(mac_ctx, LOGP, FL("Couldn't get SHORT_PREAMBLE")); + sta_param->shortPreambleSupported = (uint8_t) val; + + sta_param->assocId = 0; /* Is SMAC OK with this? */ + sta_param->wmmEnabled = 0; + sta_param->uAPSD = 0; + sta_param->maxSPLen = 0; + sta_param->us32MaxAmpduDuration = 0; + sta_param->maxAmpduSize = 0; /* 0: 8k, 1: 16k,2: 32k,3: 64k, 4:128k */ + + /* For Self STA get the LDPC capability from config.ini */ + sta_param->htLdpcCapable = + (session_entry->txLdpcIniFeatureEnabled & 0x01); + sta_param->vhtLdpcCapable = + ((session_entry->txLdpcIniFeatureEnabled >> 1) & 0x01); + + if (IS_DOT11_MODE_HT(session_entry->dot11mode)) { + sta_param->htCapable = ht_capable; + sta_param->greenFieldCapable = + lim_get_ht_capability(mac_ctx, eHT_GREENFIELD, + session_entry); + sta_param->ch_width = + lim_get_ht_capability(mac_ctx, + eHT_SUPPORTED_CHANNEL_WIDTH_SET, session_entry); + sta_param->mimoPS = + (tSirMacHTMIMOPowerSaveState)lim_get_ht_capability( + mac_ctx, eHT_MIMO_POWER_SAVE, session_entry); + sta_param->rifsMode = + lim_get_ht_capability(mac_ctx, eHT_RIFS_MODE, + session_entry); + sta_param->lsigTxopProtection = + lim_get_ht_capability(mac_ctx, eHT_LSIG_TXOP_PROTECTION, + session_entry); + sta_param->maxAmpduDensity = + lim_get_ht_capability(mac_ctx, eHT_MPDU_DENSITY, + session_entry); + sta_param->maxAmsduSize = + lim_get_ht_capability(mac_ctx, eHT_MAX_AMSDU_LENGTH, + session_entry); + sta_param->max_amsdu_num = + lim_get_ht_capability(mac_ctx, eHT_MAX_AMSDU_NUM, + session_entry); + sta_param->fDsssCckMode40Mhz = + lim_get_ht_capability(mac_ctx, eHT_DSSS_CCK_MODE_40MHZ, + session_entry); + sta_param->fShortGI20Mhz = + lim_get_ht_capability(mac_ctx, eHT_SHORT_GI_20MHZ, + session_entry); + sta_param->fShortGI40Mhz = + lim_get_ht_capability(mac_ctx, eHT_SHORT_GI_40MHZ, + session_entry); + } + if (session_entry->vhtCapability) { + sta_param->vhtCapable = true; + sta_param->vhtTxBFCapable = + session_entry->vht_config.su_beam_formee; + sta_param->vhtTxMUBformeeCapable = + session_entry->vht_config.mu_beam_formee; + sta_param->enable_su_tx_bformer = + session_entry->vht_config.su_beam_former; + } + /* + * Since this is Self-STA, need to populate Self MAX_AMPDU_SIZE + * capabilities + */ + if (IS_DOT11_MODE_VHT(self_dot11mode)) { + val = 0; /* Default 8K AMPDU size */ + if (eSIR_SUCCESS != wlan_cfg_get_int(mac_ctx, + WNI_CFG_VHT_AMPDU_LEN_EXPONENT, &val)) + lim_log(mac_ctx, LOGE, FL + ("Couldn't get WNI_CFG_VHT_AMPDU_LEN_EXPONENT")); + sta_param->maxAmpduSize = (uint8_t) val; + } + sta_param->enableVhtpAid = session_entry->enableVhtpAid; + sta_param->enableAmpduPs = session_entry->enableAmpduPs; + sta_param->enableHtSmps = session_entry->enableHtSmps; + sta_param->htSmpsconfig = session_entry->htSmpsvalue; + sta_param->send_smps_action = session_entry->send_smps_action; + + lim_populate_own_rate_set(mac_ctx, &sta_param->supportedRates, NULL, + false, session_entry, NULL); + + lim_log(mac_ctx, LOGE, FL( + "GF: %d, ChnlWidth: %d, MimoPS: %d, lsigTXOP: %d, dsssCCK: %d," + " SGI20: %d, SGI40%d"), sta_param->greenFieldCapable, + sta_param->ch_width, sta_param->mimoPS, + sta_param->lsigTxopProtection, sta_param->fDsssCckMode40Mhz, + sta_param->fShortGI20Mhz, sta_param->fShortGI40Mhz); + + if (QDF_P2P_GO_MODE == session_entry->pePersona) + sta_param->p2pCapableSta = 1; +} + +/** + * lim_mlm_add_bss() - HAL interface for WMA_ADD_BSS_REQ + * @mac_ctx: global MAC context + * @mlm_start_req: MLM start request + * @session: PE session entry + * + * Package WMA_ADD_BSS_REQ to HAL, in order to start a BSS + * + * Return: eSIR_SME_SUCCESS on success, other error codes otherwise + */ +tSirResultCodes +lim_mlm_add_bss(tpAniSirGlobal mac_ctx, + tLimMlmStartReq *mlm_start_req, tpPESession session) +{ + tSirMsgQ msg_buf; + tpAddBssParams addbss_param = NULL; + uint32_t retcode; + bool is_ch_dfs = false; + + /* Package WMA_ADD_BSS_REQ message parameters */ + addbss_param = qdf_mem_malloc(sizeof(tAddBssParams)); + if (NULL == addbss_param) { + lim_log(mac_ctx, LOGE, + FL("Unable to allocate memory during ADD_BSS")); + /* Respond to SME with LIM_MLM_START_CNF */ + return eSIR_MEM_ALLOC_FAILED; + } + + /* Fill in tAddBssParams members */ + qdf_mem_copy(addbss_param->bssId, mlm_start_req->bssId, + sizeof(tSirMacAddr)); + + /* Fill in tAddBssParams selfMacAddr */ + qdf_mem_copy(addbss_param->selfMacAddr, + session->selfMacAddr, sizeof(tSirMacAddr)); + + addbss_param->bssType = mlm_start_req->bssType; + if (mlm_start_req->bssType == eSIR_IBSS_MODE) + addbss_param->operMode = BSS_OPERATIONAL_MODE_STA; + else if (mlm_start_req->bssType == eSIR_INFRA_AP_MODE) + addbss_param->operMode = BSS_OPERATIONAL_MODE_AP; + else if (mlm_start_req->bssType == eSIR_NDI_MODE) + addbss_param->operMode = BSS_OPERATIONAL_MODE_NDI; + + addbss_param->shortSlotTimeSupported = session->shortSlotTimeSupported; + addbss_param->beaconInterval = mlm_start_req->beaconPeriod; + addbss_param->dtimPeriod = mlm_start_req->dtimPeriod; + addbss_param->wps_state = mlm_start_req->wps_state; + addbss_param->cfParamSet.cfpCount = mlm_start_req->cfParamSet.cfpCount; + addbss_param->cfParamSet.cfpPeriod = + mlm_start_req->cfParamSet.cfpPeriod; + addbss_param->cfParamSet.cfpMaxDuration = + mlm_start_req->cfParamSet.cfpMaxDuration; + addbss_param->cfParamSet.cfpDurRemaining = + mlm_start_req->cfParamSet.cfpDurRemaining; + + addbss_param->rateSet.numRates = mlm_start_req->rateSet.numRates; + qdf_mem_copy(addbss_param->rateSet.rate, mlm_start_req->rateSet.rate, + mlm_start_req->rateSet.numRates); + + addbss_param->nwType = mlm_start_req->nwType; + addbss_param->htCapable = mlm_start_req->htCapable; + addbss_param->vhtCapable = session->vhtCapability; + addbss_param->ch_width = session->ch_width; + addbss_param->ch_center_freq_seg0 = + session->ch_center_freq_seg0; + addbss_param->ch_center_freq_seg1 = + session->ch_center_freq_seg1; + addbss_param->htOperMode = mlm_start_req->htOperMode; + addbss_param->dualCTSProtection = mlm_start_req->dualCTSProtection; + addbss_param->txChannelWidthSet = mlm_start_req->txChannelWidthSet; + + addbss_param->currentOperChannel = mlm_start_req->channelNumber; +#ifdef WLAN_FEATURE_11W + addbss_param->rmfEnabled = session->limRmfEnabled; +#endif + + /* Update PE sessionId */ + addbss_param->sessionId = mlm_start_req->sessionId; + + /* Send the SSID to HAL to enable SSID matching for IBSS */ + qdf_mem_copy(&(addbss_param->ssId.ssId), + mlm_start_req->ssId.ssId, mlm_start_req->ssId.length); + addbss_param->ssId.length = mlm_start_req->ssId.length; + addbss_param->bHiddenSSIDEn = mlm_start_req->ssidHidden; + lim_log(mac_ctx, LOGE, FL("TRYING TO HIDE SSID %d"), + addbss_param->bHiddenSSIDEn); + /* CR309183. Disable Proxy Probe Rsp. Host handles Probe Requests. Until FW fixed. */ + addbss_param->bProxyProbeRespEn = 0; + addbss_param->obssProtEnabled = mlm_start_req->obssProtEnabled; + + addbss_param->maxTxPower = session->maxTxPower; + mlm_add_sta(mac_ctx, &addbss_param->staContext, + addbss_param->bssId, addbss_param->htCapable, + session); + + addbss_param->status = QDF_STATUS_SUCCESS; + addbss_param->respReqd = 1; + + /* Set a new state for MLME */ + session->limMlmState = eLIM_MLM_WT_ADD_BSS_RSP_STATE; + MTRACE(mac_trace(mac_ctx, TRACE_CODE_MLM_STATE, session->peSessionId, + session->limMlmState)); + + /* pass on the session persona to hal */ + addbss_param->halPersona = session->pePersona; + + if (session->ch_width == CH_WIDTH_160MHZ) { + is_ch_dfs = true; + } else if (session->ch_width == CH_WIDTH_80P80MHZ) { + if (cds_get_channel_state(mlm_start_req->channelNumber) == + CHANNEL_STATE_DFS || + cds_get_channel_state(session->ch_center_freq_seg1 - + SIR_80MHZ_START_CENTER_CH_DIFF) == + CHANNEL_STATE_DFS) + is_ch_dfs = true; + } else { + if (cds_get_channel_state(mlm_start_req->channelNumber) == + CHANNEL_STATE_DFS) + is_ch_dfs = true; + } + + addbss_param->bSpectrumMgtEnabled = + session->spectrumMgtEnabled || is_ch_dfs; + addbss_param->extSetStaKeyParamValid = 0; + + addbss_param->dot11_mode = session->dot11mode; + addbss_param->nss = session->nss; + if (QDF_IBSS_MODE == addbss_param->halPersona) { + addbss_param->nss_2g = mac_ctx->vdev_type_nss_2g.ibss; + addbss_param->nss_5g = mac_ctx->vdev_type_nss_5g.ibss; + addbss_param->tx_aggregation_size = + mac_ctx->roam.configParam.tx_aggregation_size; + addbss_param->rx_aggregation_size = + mac_ctx->roam.configParam.rx_aggregation_size; + } + lim_log(mac_ctx, LOG2, FL("dot11_mode:%d nss value:%d"), + addbss_param->dot11_mode, addbss_param->nss); + + if (cds_is_5_mhz_enabled()) { + addbss_param->ch_width = CH_WIDTH_5MHZ; + addbss_param->staContext.ch_width = CH_WIDTH_5MHZ; + } else if (cds_is_10_mhz_enabled()) { + addbss_param->ch_width = CH_WIDTH_10MHZ; + addbss_param->staContext.ch_width = CH_WIDTH_10MHZ; + } + + msg_buf.type = WMA_ADD_BSS_REQ; + msg_buf.reserved = 0; + msg_buf.bodyptr = addbss_param; + msg_buf.bodyval = 0; + MTRACE(mac_trace_msg_tx(mac_ctx, session->peSessionId, msg_buf.type)); + + lim_log(mac_ctx, LOGW, FL("Sending WMA_ADD_BSS_REQ...")); + retcode = wma_post_ctrl_msg(mac_ctx, &msg_buf); + if (eSIR_SUCCESS != retcode) { + lim_log(mac_ctx, LOGE, + FL("Posting ADD_BSS_REQ to HAL failed, reason=%X"), + retcode); + qdf_mem_free(addbss_param); + return eSIR_SME_HAL_SEND_MESSAGE_FAIL; + } + + return eSIR_SME_SUCCESS; +} + +/** + * lim_process_mlm_start_req() - process MLM_START_REQ message + * + * @mac_ctx: global MAC context + * @msg_buf: Pointer to MLM message buffer + * + * This function is called to process MLM_START_REQ message + * from SME + * 1) MLME receives LIM_MLM_START_REQ from LIM + * 2) MLME sends WMA_ADD_BSS_REQ to HAL + * 3) MLME changes state to eLIM_MLM_WT_ADD_BSS_RSP_STATE + * MLME now waits for HAL to send WMA_ADD_BSS_RSP + * + * Return: None + */ +static void lim_process_mlm_start_req(tpAniSirGlobal mac_ctx, uint32_t *msg_buf) +{ + tLimMlmStartReq *mlm_start_req; + tLimMlmStartCnf mlm_start_cnf; + tpPESession session = NULL; + + if (msg_buf == NULL) { + lim_log(mac_ctx, LOGE, FL("Buffer is Pointing to NULL")); + return; + } + + mlm_start_req = (tLimMlmStartReq *) msg_buf; + session = pe_find_session_by_session_id(mac_ctx, + mlm_start_req->sessionId); + if (NULL == session) { + lim_log(mac_ctx, LOGP, + FL("Session Does not exist for given sessionID")); + mlm_start_cnf.resultCode = eSIR_SME_REFUSED; + goto end; + } + + if (session->limMlmState != eLIM_MLM_IDLE_STATE) { + /* + * Should not have received Start req in states other than idle. + * Return Start confirm with failure code. + */ + lim_log(mac_ctx, LOGE, + FL("received unexpected MLM_START_REQ in state %X"), + session->limMlmState); + lim_print_mlm_state(mac_ctx, LOGE, session->limMlmState); + mlm_start_cnf.resultCode = + eSIR_SME_BSS_ALREADY_STARTED_OR_JOINED; + goto end; + } + + mlm_start_cnf.resultCode = + lim_mlm_add_bss(mac_ctx, mlm_start_req, session); + +end: + /* Update PE session Id */ + mlm_start_cnf.sessionId = mlm_start_req->sessionId; + + /* Free up buffer allocated for LimMlmScanReq */ + qdf_mem_free(msg_buf); + + /* + * Respond immediately to LIM, only if MLME has not been + * successfully able to send WMA_ADD_BSS_REQ to HAL. + * Else, LIM_MLM_START_CNF will be sent after receiving + * WMA_ADD_BSS_RSP from HAL + */ + if (eSIR_SME_SUCCESS != mlm_start_cnf.resultCode) + lim_post_sme_message(mac_ctx, LIM_MLM_START_CNF, + (uint32_t *) &mlm_start_cnf); +} + +/** + * lim_post_join_set_link_state_callback()- registered callback to perform post + * peer creation operations + * + * @mac: pointer to global mac structure + * @callback_arg: registered callback argument + * @status: peer creation status + * + * this is registered callback function during association to perform + * post peer creation operation based on the peer creation status + * + * Return: none + */ +static void lim_post_join_set_link_state_callback(tpAniSirGlobal mac, + void *callback_arg, bool status) +{ + uint8_t chan_num, sec_chan_offset; + tpPESession session_entry = (tpPESession) callback_arg; + tLimMlmJoinCnf mlm_join_cnf; + + lim_log(mac, LOG1, FL("Sessionid %d set link state(%d) cb status:%d"), + session_entry->peSessionId, session_entry->limMlmState, + status); + + if (!status) { + lim_log(mac, LOGE, + FL("failed to find pe session for session id:%d"), + session_entry->peSessionId); + goto failure; + } + + chan_num = session_entry->currentOperChannel; + sec_chan_offset = session_entry->htSecondaryChannelOffset; + /* + * store the channel switch session_entry in the lim + * global variable + */ + session_entry->channelChangeReasonCode = + LIM_SWITCH_CHANNEL_JOIN; + session_entry->pLimMlmReassocRetryReq = NULL; + lim_log(mac, LOG1, + FL("[lim_process_mlm_join_req]: suspend link success(%d) " + "on sessionid: %d setting channel to: %d with ch_width :%d " + "and maxtxPower: %d"), status, session_entry->peSessionId, + session_entry->currentOperChannel, + session_entry->ch_width, + session_entry->maxTxPower); + lim_set_channel(mac, session_entry->currentOperChannel, + session_entry->ch_center_freq_seg0, + session_entry->ch_center_freq_seg1, + session_entry->ch_width, + session_entry->maxTxPower, + session_entry->peSessionId); + return; + +failure: + MTRACE(mac_trace(mac, TRACE_CODE_MLM_STATE, session_entry->peSessionId, + session_entry->limMlmState)); + session_entry->limMlmState = eLIM_MLM_IDLE_STATE; + mlm_join_cnf.resultCode = eSIR_SME_RESOURCES_UNAVAILABLE; + mlm_join_cnf.sessionId = session_entry->peSessionId; + mlm_join_cnf.protStatusCode = eSIR_MAC_UNSPEC_FAILURE_STATUS; + lim_post_sme_message(mac, LIM_MLM_JOIN_CNF, (uint32_t *) &mlm_join_cnf); +} + +/** + * lim_process_mlm_post_join_suspend_link() - This function is called after the + * suspend link while joining off channel. + * + * @mac_ctx: Pointer to Global MAC structure + * @status: status of suspend link. + * @ctx: passed while calling suspend link(session) + * + * This function does following: + * Check for suspend state. + * If success, proceed with setting link state to recieve the + * probe response/beacon from intended AP. + * Switch to the APs channel. + * On an error case, send the MLM_JOIN_CNF with error status. + * + * @Return None + */ +static void +lim_process_mlm_post_join_suspend_link(tpAniSirGlobal mac_ctx, + QDF_STATUS status, + uint32_t *ctx) +{ + tLimMlmJoinCnf mlm_join_cnf; + tpPESession session = (tpPESession) ctx; + tSirLinkState lnk_state; + + if (QDF_STATUS_SUCCESS != status) { + lim_log(mac_ctx, LOGE, + FL("Sessionid %d Suspend link(NOTIFY_BSS) failed. Still proceeding with join"), + session->peSessionId); + } + lim_deactivate_and_change_timer(mac_ctx, eLIM_JOIN_FAIL_TIMER); + + /* assign appropriate sessionId to the timer object */ + mac_ctx->lim.limTimers.gLimJoinFailureTimer.sessionId = + session->peSessionId; + + lnk_state = eSIR_LINK_PREASSOC_STATE; + lim_log(mac_ctx, LOG1, FL("[lim_process_mlm_join_req]: lnk_state:%d"), + lnk_state); + + if (lim_set_link_state(mac_ctx, lnk_state, + session->pLimMlmJoinReq->bssDescription.bssId, + session->selfMacAddr, + lim_post_join_set_link_state_callback, + session) != eSIR_SUCCESS) { + lim_log(mac_ctx, LOGE, + FL("SessionId:%d lim_set_link_state to eSIR_LINK_PREASSOC_STATE Failed!!"), + session->peSessionId); + lim_print_mac_addr(mac_ctx, + session->pLimMlmJoinReq->bssDescription.bssId, LOGE); + mlm_join_cnf.resultCode = eSIR_SME_RESOURCES_UNAVAILABLE; + session->limMlmState = eLIM_MLM_IDLE_STATE; + MTRACE(mac_trace(mac_ctx, TRACE_CODE_MLM_STATE, + session->peSessionId, session->limMlmState)); + goto error; + } + + return; +error: + mlm_join_cnf.resultCode = eSIR_SME_RESOURCES_UNAVAILABLE; + mlm_join_cnf.sessionId = session->peSessionId; + mlm_join_cnf.protStatusCode = eSIR_MAC_UNSPEC_FAILURE_STATUS; + lim_post_sme_message(mac_ctx, LIM_MLM_JOIN_CNF, + (uint32_t *) &mlm_join_cnf); +} + +/** + * lim_process_mlm_join_req() - process mlm join request. + * + * @mac_ctx: Pointer to Global MAC structure + * @msg: Pointer to the MLM message buffer + * + * This function is called to process MLM_JOIN_REQ message + * from SME. It does following: + * 1) Initialize LIM, HAL, DPH + * 2) Configure the BSS for which the JOIN REQ was received + * a) Send WMA_ADD_BSS_REQ to HAL - + * This will identify the BSS that we are interested in + * --AND-- + * Add a STA entry for the AP (in a STA context) + * b) Wait for WMA_ADD_BSS_RSP + * c) Send WMA_ADD_STA_REQ to HAL + * This will add the "local STA" entry to the STA table + * 3) Continue as before, i.e, + * a) Send a PROBE REQ + * b) Wait for PROBE RSP/BEACON containing the SSID that + * we are interested in + * c) Then start an AUTH seq + * d) Followed by the ASSOC seq + * + * @Return: None + */ +static void lim_process_mlm_join_req(tpAniSirGlobal mac_ctx, uint32_t *msg) +{ + tLimMlmJoinCnf mlmjoin_cnf; + uint8_t sessionid; + tpPESession session; + + sessionid = ((tpLimMlmJoinReq) msg)->sessionId; + + session = pe_find_session_by_session_id(mac_ctx, sessionid); + if (NULL == session) { + lim_log(mac_ctx, LOGE, FL("SessionId:%d does not exist"), + sessionid); + goto error; + } + + if (!LIM_IS_AP_ROLE(session) && + ((session->limMlmState == eLIM_MLM_IDLE_STATE) || + (session->limMlmState == eLIM_MLM_JOINED_STATE)) && + (SIR_MAC_GET_ESS + (((tpLimMlmJoinReq) msg)->bssDescription.capabilityInfo) != + SIR_MAC_GET_IBSS(((tpLimMlmJoinReq) msg)->bssDescription. + capabilityInfo))) { + /* Hold onto Join request parameters */ + + session->pLimMlmJoinReq = (tpLimMlmJoinReq) msg; + if (is_lim_session_off_channel(mac_ctx, sessionid)) { + lim_log(mac_ctx, LOG1, + "SessionId:%d LimSession is on OffChannel", + sessionid); + /* suspend link */ + lim_log(mac_ctx, LOG1, + FL("Suspend link, sessionid %d is off channel"), + sessionid); + if (lim_is_link_suspended(mac_ctx)) { + lim_log(mac_ctx, LOGE, FL( + "link is already suspended, session %d" + ), sessionid); + goto error; + } + lim_process_mlm_post_join_suspend_link(mac_ctx, + QDF_STATUS_SUCCESS, (uint32_t *)session); + } else { + lim_log(mac_ctx, LOG1, FL("No need to Suspend link")); + /* + * No need to Suspend link as LimSession is not + * off channel, calling + * lim_process_mlm_post_join_suspend_link with + * status as SUCCESS. + */ + lim_log(mac_ctx, LOG1, + FL("SessionId:%d Join req on current chan"), + sessionid); + lim_process_mlm_post_join_suspend_link(mac_ctx, + QDF_STATUS_SUCCESS, (uint32_t *)session); + } + return; + } else { + /** + * Should not have received JOIN req in states other than + * Idle state or on AP. + * Return join confirm with invalid parameters code. + */ + lim_log(mac_ctx, LOGE, + FL("Session:%d Unexpected Join req, role %d state %X"), + session->peSessionId, GET_LIM_SYSTEM_ROLE(session), + session->limMlmState); + lim_print_mlm_state(mac_ctx, LOGE, session->limMlmState); + } + +error: + qdf_mem_free(msg); + if (session != NULL) + session->pLimMlmJoinReq = NULL; + mlmjoin_cnf.resultCode = eSIR_SME_RESOURCES_UNAVAILABLE; + mlmjoin_cnf.sessionId = sessionid; + mlmjoin_cnf.protStatusCode = eSIR_MAC_UNSPEC_FAILURE_STATUS; + lim_post_sme_message(mac_ctx, LIM_MLM_JOIN_CNF, + (uint32_t *)&mlmjoin_cnf); + +} + +/** + * lim_is_auth_req_expected() - check if auth request is expected + * + * @mac_ctx: global MAC context + * @session: PE session entry + * + * This function is called by lim_process_mlm_auth_req to check + * if auth request is expected. + * + * Return: true if expected and false otherwise + */ +static bool lim_is_auth_req_expected(tpAniSirGlobal mac_ctx, + tpPESession session) +{ + bool flag = false; + + /* + * Expect Auth request only when: + * 1. STA joined/associated with a BSS or + * 2. STA is in IBSS mode + * and STA is going to authenticate with a unicast + * address and requested authentication algorithm is + * supported. + */ + + flag = (((LIM_IS_STA_ROLE(session) && + ((session->limMlmState == eLIM_MLM_JOINED_STATE) || + (session->limMlmState == + eLIM_MLM_LINK_ESTABLISHED_STATE))) || + (LIM_IS_IBSS_ROLE(session) && + (session->limMlmState == + eLIM_MLM_BSS_STARTED_STATE))) && + (!lim_is_group_addr(mac_ctx->lim.gpLimMlmAuthReq->peerMacAddr)) + && lim_is_auth_algo_supported(mac_ctx, + mac_ctx->lim.gpLimMlmAuthReq->authType, session)); + + return flag; +} + +/** + * lim_is_preauth_ctx_exisits() - check if preauth context exists + * + * @mac_ctx: global MAC context + * @session: PE session entry + * @preauth_node_ptr: pointer to preauth node pointer + * + * This function is called by lim_process_mlm_auth_req to check + * if preauth context already exists + * + * Return: true if exists and false otherwise + */ +static bool lim_is_preauth_ctx_exists(tpAniSirGlobal mac_ctx, + tpPESession session, + struct tLimPreAuthNode **preauth_node_ptr) +{ + bool fl = false; + struct tLimPreAuthNode *preauth_node; + tpDphHashNode stads; + tSirMacAddr curr_bssid; + + preauth_node = *preauth_node_ptr; + sir_copy_mac_addr(curr_bssid, session->bssId); + stads = dph_get_hash_entry(mac_ctx, DPH_STA_HASH_INDEX_PEER, + &session->dph.dphHashTable); + preauth_node = lim_search_pre_auth_list(mac_ctx, + mac_ctx->lim.gpLimMlmAuthReq->peerMacAddr); + + fl = (((LIM_IS_STA_ROLE(session)) && + (session->limMlmState == eLIM_MLM_LINK_ESTABLISHED_STATE) && + ((stads != NULL) && + (mac_ctx->lim.gpLimMlmAuthReq->authType == + stads->mlmStaContext.authType)) && + (!qdf_mem_cmp(mac_ctx->lim.gpLimMlmAuthReq->peerMacAddr, + curr_bssid, sizeof(tSirMacAddr)))) || + ((preauth_node != NULL) && + (preauth_node->authType == + mac_ctx->lim.gpLimMlmAuthReq->authType))); + + return fl; +} + +/** + * lim_process_mlm_auth_req() - process lim auth request + * + * @mac_ctx: global MAC context + * @msg: MLM auth request message + * + * This function is called to process MLM_AUTH_REQ message from SME + * + * @Return: None + */ +static void lim_process_mlm_auth_req(tpAniSirGlobal mac_ctx, uint32_t *msg) +{ + uint32_t num_preauth_ctx; + tSirMacAddr curr_bssid; + tSirMacAuthFrameBody auth_frame_body; + tLimMlmAuthCnf mlm_auth_cnf; + struct tLimPreAuthNode *preauth_node = NULL; + uint8_t session_id; + tpPESession session; + + if (msg == NULL) { + lim_log(mac_ctx, LOGE, FL("Buffer is Pointing to NULL")); + return; + } + + mac_ctx->lim.gpLimMlmAuthReq = (tLimMlmAuthReq *) msg; + session_id = mac_ctx->lim.gpLimMlmAuthReq->sessionId; + session = pe_find_session_by_session_id(mac_ctx, session_id); + if (NULL == session) { + lim_log(mac_ctx, LOGP, FL("SessionId:%d does not exist"), + session_id); + return; + } + + lim_log(mac_ctx, LOG1, FL("Process Auth Req sessionID %d Systemrole %d" + "mlmstate %d from: " MAC_ADDRESS_STR + " with authtype %d"), session_id, + GET_LIM_SYSTEM_ROLE(session), session->limMlmState, + MAC_ADDR_ARRAY(mac_ctx->lim.gpLimMlmAuthReq->peerMacAddr), + mac_ctx->lim.gpLimMlmAuthReq->authType); + + sir_copy_mac_addr(curr_bssid, session->bssId); + + if (!lim_is_auth_req_expected(mac_ctx, session)) { + /* + * Unexpected auth request. + * Return Auth confirm with Invalid parameters code. + */ + mlm_auth_cnf.resultCode = eSIR_SME_INVALID_PARAMETERS; + goto end; + } + + /* + * This is a request for pre-authentication. Check if there exists + * context already for the requested peer OR + * if this request is for the AP we're currently associated with. + * If yes, return auth confirm immediately when + * requested auth type is same as the one used before. + */ + if (lim_is_preauth_ctx_exists(mac_ctx, session, &preauth_node)) { + lim_log(mac_ctx, LOG2, + FL("Already have pre-auth context with peer: " + MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(mac_ctx->lim.gpLimMlmAuthReq->peerMacAddr)); + mlm_auth_cnf.resultCode = (tSirResultCodes) + eSIR_MAC_SUCCESS_STATUS; + goto end; + } else { + if (wlan_cfg_get_int(mac_ctx, WNI_CFG_MAX_NUM_PRE_AUTH, + (uint32_t *) &num_preauth_ctx) != eSIR_SUCCESS) + lim_log(mac_ctx, LOGP, + FL("Could not retrieve NumPreAuthLimit from CFG")); + + if (mac_ctx->lim.gLimNumPreAuthContexts == num_preauth_ctx) { + lim_log(mac_ctx, LOGW, + FL("Number of pre-auth reached max limit")); + /* Return Auth confirm with reject code */ + mlm_auth_cnf.resultCode = + eSIR_SME_MAX_NUM_OF_PRE_AUTH_REACHED; + goto end; + } + } + + /* Delete pre-auth node if exists */ + if (preauth_node) + lim_delete_pre_auth_node(mac_ctx, + mac_ctx->lim.gpLimMlmAuthReq->peerMacAddr); + + session->limPrevMlmState = session->limMlmState; + session->limMlmState = eLIM_MLM_WT_AUTH_FRAME2_STATE; + MTRACE(mac_trace(mac_ctx, TRACE_CODE_MLM_STATE, session->peSessionId, + session->limMlmState)); + + /* Prepare & send Authentication frame */ + auth_frame_body.authAlgoNumber = + (uint8_t) mac_ctx->lim.gpLimMlmAuthReq->authType; + auth_frame_body.authTransactionSeqNumber = SIR_MAC_AUTH_FRAME_1; + auth_frame_body.authStatusCode = 0; +#ifdef FEATURE_WLAN_DIAG_SUPPORT + lim_diag_event_report(mac_ctx, WLAN_PE_DIAG_AUTH_START_EVENT, session, + eSIR_SUCCESS, auth_frame_body.authStatusCode); +#endif + mac_ctx->auth_ack_status = LIM_AUTH_ACK_NOT_RCD; + lim_send_auth_mgmt_frame(mac_ctx, + &auth_frame_body, mac_ctx->lim.gpLimMlmAuthReq->peerMacAddr, + LIM_NO_WEP_IN_FC, session); + + /* assign appropriate session_id to the timer object */ + mac_ctx->lim.limTimers.gLimAuthFailureTimer.sessionId = session_id; + + /* assign appropriate sessionId to the timer object */ + mac_ctx->lim.limTimers.g_lim_periodic_auth_retry_timer.sessionId = + session_id; + lim_deactivate_and_change_timer(mac_ctx, eLIM_AUTH_RETRY_TIMER); + /* Activate Auth failure timer */ + MTRACE(mac_trace(mac_ctx, TRACE_CODE_TIMER_ACTIVATE, + session->peSessionId, eLIM_AUTH_FAIL_TIMER)); + if (tx_timer_activate(&mac_ctx->lim.limTimers.gLimAuthFailureTimer) + != TX_SUCCESS) { + /* Could not start Auth failure timer. */ + lim_log(mac_ctx, LOGE, + FL("could not start Auth failure timer")); + /* Cleanup as if auth timer expired */ + lim_process_auth_failure_timeout(mac_ctx); + } else { + MTRACE(mac_trace(mac_ctx, TRACE_CODE_TIMER_ACTIVATE, + session->peSessionId, eLIM_AUTH_RETRY_TIMER)); + /* Activate Auth Retry timer */ + if (tx_timer_activate + (&mac_ctx->lim.limTimers.g_lim_periodic_auth_retry_timer) + != TX_SUCCESS) + lim_log(mac_ctx, LOGE, + FL("could not activate Auth Retry timer")); + } + + return; +end: + qdf_mem_copy((uint8_t *) &mlm_auth_cnf.peerMacAddr, + (uint8_t *) &mac_ctx->lim.gpLimMlmAuthReq->peerMacAddr, + sizeof(tSirMacAddr)); + + mlm_auth_cnf.authType = mac_ctx->lim.gpLimMlmAuthReq->authType; + mlm_auth_cnf.sessionId = session_id; + + qdf_mem_free(mac_ctx->lim.gpLimMlmAuthReq); + mac_ctx->lim.gpLimMlmAuthReq = NULL; + lim_log(mac_ctx, LOG1, "SessionId:%d LimPostSme LIM_MLM_AUTH_CNF ", + session_id); + lim_post_sme_message(mac_ctx, LIM_MLM_AUTH_CNF, + (uint32_t *) &mlm_auth_cnf); +} + +/** + * lim_process_mlm_assoc_req() - This function is called to process + * MLM_ASSOC_REQ message from SME + * + * @mac_ctx: Pointer to Global MAC structure + * @msg_buf: A pointer to the MLM message buffer + * + * This function is called to process MLM_ASSOC_REQ message from SME + * + * @Return None + */ + +static void lim_process_mlm_assoc_req(tpAniSirGlobal mac_ctx, uint32_t *msg_buf) +{ + tSirMacAddr curr_bssId; + tLimMlmAssocReq *mlm_assoc_req; + tLimMlmAssocCnf mlm_assoc_cnf; + tpPESession session_entry; + + if (msg_buf == NULL) { + lim_log(mac_ctx, LOGE, FL("Buffer is Pointing to NULL")); + return; + } + + mlm_assoc_req = (tLimMlmAssocReq *) msg_buf; + session_entry = pe_find_session_by_session_id(mac_ctx, + mlm_assoc_req->sessionId); + if (session_entry == NULL) { + lim_log(mac_ctx, LOGP, + FL("SessionId:%d Session Does not exist"), + mlm_assoc_req->sessionId); + qdf_mem_free(mlm_assoc_req); + return; + } + + sir_copy_mac_addr(curr_bssId, session_entry->bssId); + + if (!(!LIM_IS_AP_ROLE(session_entry) && + (session_entry->limMlmState == eLIM_MLM_AUTHENTICATED_STATE || + session_entry->limMlmState == eLIM_MLM_JOINED_STATE) && + (!qdf_mem_cmp(mlm_assoc_req->peerMacAddr, + curr_bssId, sizeof(tSirMacAddr))))) { + /* + * Received Association request either in invalid state + * or to a peer MAC entity whose address is different + * from one that STA is currently joined with or on AP. + * Return Assoc confirm with Invalid parameters code. + */ + lim_log(mac_ctx, LOGW, + FL("received unexpected MLM_ASSOC_CNF in state %X for role=%d, MAC addr= " + MAC_ADDRESS_STR), session_entry->limMlmState, + GET_LIM_SYSTEM_ROLE(session_entry), + MAC_ADDR_ARRAY(mlm_assoc_req->peerMacAddr)); + lim_print_mlm_state(mac_ctx, LOGW, session_entry->limMlmState); + mlm_assoc_cnf.resultCode = eSIR_SME_INVALID_PARAMETERS; + mlm_assoc_cnf.protStatusCode = eSIR_MAC_UNSPEC_FAILURE_STATUS; + goto end; + } + + /* map the session entry pointer to the AssocFailureTimer */ + mac_ctx->lim.limTimers.gLimAssocFailureTimer.sessionId = + mlm_assoc_req->sessionId; +#ifdef WLAN_FEATURE_11W + /* + * Store current MLM state in case ASSOC response returns with + * TRY_AGAIN_LATER return code. + */ + if (session_entry->limRmfEnabled) { + session_entry->pmfComebackTimerInfo.limPrevMlmState = + session_entry->limPrevMlmState; + session_entry->pmfComebackTimerInfo.limMlmState = + session_entry->limMlmState; + } +#endif /* WLAN_FEATURE_11W */ + + session_entry->limPrevMlmState = session_entry->limMlmState; + session_entry->limMlmState = eLIM_MLM_WT_ASSOC_RSP_STATE; + MTRACE(mac_trace(mac_ctx, TRACE_CODE_MLM_STATE, + session_entry->peSessionId, + session_entry->limMlmState)); + lim_log(mac_ctx, LOG1, FL("SessionId:%d Sending Assoc_Req Frame"), + session_entry->peSessionId); + + /* Prepare and send Association request frame */ + lim_send_assoc_req_mgmt_frame(mac_ctx, mlm_assoc_req, session_entry); + + /* Start association failure timer */ + MTRACE(mac_trace(mac_ctx, TRACE_CODE_TIMER_ACTIVATE, + session_entry->peSessionId, eLIM_ASSOC_FAIL_TIMER)); + if (tx_timer_activate(&mac_ctx->lim.limTimers.gLimAssocFailureTimer) + != TX_SUCCESS) { + lim_log(mac_ctx, LOGP, + FL("SessionId:%d couldn't start Assoc failure timer"), + session_entry->peSessionId); + /* Cleanup as if assoc timer expired */ + lim_process_assoc_failure_timeout(mac_ctx, LIM_ASSOC); + } + + return; +end: + /* Update PE session Id */ + mlm_assoc_cnf.sessionId = mlm_assoc_req->sessionId; + /* Free up buffer allocated for assocReq */ + qdf_mem_free(mlm_assoc_req); + lim_post_sme_message(mac_ctx, LIM_MLM_ASSOC_CNF, + (uint32_t *) &mlm_assoc_cnf); +} + +/** + * lim_process_mlm_disassoc_req_ntf() - process disassoc request notification + * + * @mac_ctx: global MAC context + * @suspend_status: suspend status + * @msg: mlm message buffer + * + * This function is used to process MLM disassoc notification + * + * Return: None + */ +static void +lim_process_mlm_disassoc_req_ntf(tpAniSirGlobal mac_ctx, + QDF_STATUS suspend_status, uint32_t *msg) +{ + uint16_t aid; + struct qdf_mac_addr curr_bssid; + tpDphHashNode stads; + tLimMlmDisassocReq *mlm_disassocreq; + tLimMlmDisassocCnf mlm_disassoccnf; + tpPESession session; + extern bool send_disassoc_frame; + tLimMlmStates mlm_state; + tSirSmeDisassocRsp *sme_disassoc_rsp; + + if (QDF_STATUS_SUCCESS != suspend_status) + lim_log(mac_ctx, LOGE, FL("Suspend Status is not success %X"), + suspend_status); + + mlm_disassocreq = (tLimMlmDisassocReq *) msg; + + session = pe_find_session_by_session_id(mac_ctx, + mlm_disassocreq->sessionId); + if (NULL == session) { + lim_log(mac_ctx, LOGE, + FL("session does not exist for given sessionId %d"), + mlm_disassocreq->sessionId); + mlm_disassoccnf.resultCode = eSIR_SME_INVALID_PARAMETERS; + goto end; + } + + lim_log(mac_ctx, LOG1, + FL("Process DisAssoc Req on sessionID %d Systemrole %d" + "mlmstate %d from: " MAC_ADDRESS_STR), + mlm_disassocreq->sessionId, GET_LIM_SYSTEM_ROLE(session), + session->limMlmState, + MAC_ADDR_ARRAY(mlm_disassocreq->peer_macaddr.bytes)); + + qdf_mem_copy(curr_bssid.bytes, session->bssId, QDF_MAC_ADDR_SIZE); + + switch (GET_LIM_SYSTEM_ROLE(session)) { + case eLIM_STA_ROLE: + if (!qdf_is_macaddr_equal(&mlm_disassocreq->peer_macaddr, + &curr_bssid)) { + lim_log(mac_ctx, LOGW, + FL("received MLM_DISASSOC_REQ with invalid BSS id")); + lim_print_mac_addr(mac_ctx, + mlm_disassocreq->peer_macaddr.bytes, LOGW); + + /* + * Disassociation response due to host triggered + * disassociation + */ + sme_disassoc_rsp = + qdf_mem_malloc(sizeof(tSirSmeDisassocRsp)); + if (NULL == sme_disassoc_rsp) { + lim_log(mac_ctx, LOGP, + FL("memory allocation failed for disassoc rsp")); + return; + } + + lim_log(mac_ctx, LOG1, + FL("send disassoc rsp with ret code %d for" MAC_ADDRESS_STR), + eSIR_SME_DEAUTH_STATUS, + MAC_ADDR_ARRAY( + mlm_disassocreq->peer_macaddr.bytes)); + + sme_disassoc_rsp->messageType = eWNI_SME_DISASSOC_RSP; + sme_disassoc_rsp->length = sizeof(tSirSmeDisassocRsp); + sme_disassoc_rsp->sessionId = + mlm_disassocreq->sessionId; + sme_disassoc_rsp->transactionId = 0; + sme_disassoc_rsp->statusCode = eSIR_SME_DEAUTH_STATUS; + + qdf_copy_macaddr(&sme_disassoc_rsp->peer_macaddr, + &mlm_disassocreq->peer_macaddr); + msg = (uint32_t *)sme_disassoc_rsp; + + lim_send_sme_disassoc_deauth_ntf(mac_ctx, + QDF_STATUS_SUCCESS, msg); + return; + + } + break; + case eLIM_STA_IN_IBSS_ROLE: + break; + case eLIM_AP_ROLE: + case eLIM_P2P_DEVICE_GO: + if (true == + mac_ctx->sap.SapDfsInfo.is_dfs_cac_timer_running) { + lim_log(mac_ctx, LOGE, + FL("CAC timer is running, drop disassoc from going out")); + mlm_disassoccnf.resultCode = eSIR_SME_SUCCESS; + goto end; + } + break; + default: + break; + } /* end switch (GET_LIM_SYSTEM_ROLE(session)) */ + + /* + * Check if there exists a context for the peer entity + * to be disassociated with. + */ + stads = dph_lookup_hash_entry(mac_ctx, + mlm_disassocreq->peer_macaddr.bytes, + &aid, &session->dph.dphHashTable); + if (stads) + mlm_state = stads->mlmStaContext.mlmState; + + if ((stads == NULL) || + (stads && + ((mlm_state != eLIM_MLM_LINK_ESTABLISHED_STATE) && + (mlm_state != eLIM_MLM_WT_ASSOC_CNF_STATE) && + (mlm_state != eLIM_MLM_ASSOCIATED_STATE)))) { + /* + * Received LIM_MLM_DISASSOC_REQ for STA that does not + * have context or in some transit state. + */ + lim_log(mac_ctx, LOGW, + FL("Invalid MLM_DISASSOC_REQ, Addr= " MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(mlm_disassocreq->peer_macaddr.bytes)); + if (stads != NULL) + lim_log(mac_ctx, LOGE, FL("Sta MlmState : %d"), + stads->mlmStaContext.mlmState); + + /* Prepare and Send LIM_MLM_DISASSOC_CNF */ + mlm_disassoccnf.resultCode = eSIR_SME_INVALID_PARAMETERS; + goto end; + } + + stads->mlmStaContext.disassocReason = (tSirMacReasonCodes) + mlm_disassocreq->reasonCode; + stads->mlmStaContext.cleanupTrigger = mlm_disassocreq->disassocTrigger; + + /* + * Set state to mlm State to eLIM_MLM_WT_DEL_STA_RSP_STATE + * This is to address the issue of race condition between + * disconnect request from the HDD and deauth from AP + */ + + stads->mlmStaContext.mlmState = eLIM_MLM_WT_DEL_STA_RSP_STATE; + + /* Send Disassociate frame to peer entity */ + if (send_disassoc_frame && (mlm_disassocreq->reasonCode != + eSIR_MAC_DISASSOC_DUE_TO_FTHANDOFF_REASON)) { + mac_ctx->lim.limDisassocDeauthCnfReq.pMlmDisassocReq = + mlm_disassocreq; + /* + * Set state to mlm State to eLIM_MLM_WT_DEL_STA_RSP_STATE + * This is to address the issue of race condition between + * disconnect request from the HDD and deauth from AP + */ + stads->mlmStaContext.mlmState = eLIM_MLM_WT_DEL_STA_RSP_STATE; + + lim_send_disassoc_mgmt_frame(mac_ctx, + mlm_disassocreq->reasonCode, + mlm_disassocreq->peer_macaddr.bytes, session, true); + /* + * Abort Tx so that data frames won't be sent to the AP + * after sending Disassoc. + */ + if (LIM_IS_STA_ROLE(session)) + wma_tx_abort(session->smeSessionId); + } else { + /* Disassoc frame is not sent OTA */ + send_disassoc_frame = 1; + /* Receive path cleanup with dummy packet */ + if (eSIR_SUCCESS != + lim_cleanup_rx_path(mac_ctx, stads, session)) { + mlm_disassoccnf.resultCode = + eSIR_SME_RESOURCES_UNAVAILABLE; + goto end; + } + /* Free up buffer allocated for mlmDisassocReq */ + qdf_mem_free(mlm_disassocreq); + } + + return; + +end: + qdf_mem_copy((uint8_t *) &mlm_disassoccnf.peerMacAddr, + (uint8_t *) mlm_disassocreq->peer_macaddr.bytes, + QDF_MAC_ADDR_SIZE); + mlm_disassoccnf.aid = mlm_disassocreq->aid; + mlm_disassoccnf.disassocTrigger = mlm_disassocreq->disassocTrigger; + + /* Update PE session ID */ + mlm_disassoccnf.sessionId = mlm_disassocreq->sessionId; + + /* Free up buffer allocated for mlmDisassocReq */ + qdf_mem_free(mlm_disassocreq); + + lim_post_sme_message(mac_ctx, LIM_MLM_DISASSOC_CNF, + (uint32_t *) &mlm_disassoccnf); +} + +/** + * lim_check_disassoc_deauth_ack_pending() - check if deauth is pending + * + * @mac_ctx - global MAC context + * @sta_mac - station MAC + * + * This function checks if diassociation or deauthentication is pending for + * given station MAC address. + * + * Return: true if pending and false otherwise. + */ +bool lim_check_disassoc_deauth_ack_pending(tpAniSirGlobal mac_ctx, + uint8_t *sta_mac) +{ + tLimMlmDisassocReq *disassoc_req; + tLimMlmDeauthReq *deauth_req; + + disassoc_req = mac_ctx->lim.limDisassocDeauthCnfReq.pMlmDisassocReq; + deauth_req = mac_ctx->lim.limDisassocDeauthCnfReq.pMlmDeauthReq; + if ((disassoc_req && (!qdf_mem_cmp((uint8_t *) sta_mac, + (uint8_t *) &disassoc_req->peer_macaddr.bytes, + QDF_MAC_ADDR_SIZE))) || + (deauth_req && (!qdf_mem_cmp((uint8_t *) sta_mac, + (uint8_t *) &deauth_req->peer_macaddr.bytes, + QDF_MAC_ADDR_SIZE)))) { + lim_log(mac_ctx, LOG1, FL("Disassoc/Deauth ack pending")); + return true; + } else { + lim_log(mac_ctx, LOG1, + FL("Disassoc/Deauth Ack not pending")); + return false; + } +} + +/* + * lim_clean_up_disassoc_deauth_req() - cleans up pending disassoc or deauth req + * + * @mac_ctx: mac_ctx + * @sta_mac: sta mac address + * @clean_rx_path: flag to indicate whether to cleanup rx path or not + * + * This function cleans up pending disassoc or deauth req + * + * Return: void + */ +void lim_clean_up_disassoc_deauth_req(tpAniSirGlobal mac_ctx, + uint8_t *sta_mac, bool clean_rx_path) +{ + tLimMlmDisassocReq *mlm_disassoc_req; + tLimMlmDeauthReq *mlm_deauth_req; + mlm_disassoc_req = mac_ctx->lim.limDisassocDeauthCnfReq.pMlmDisassocReq; + if (mlm_disassoc_req && + (!qdf_mem_cmp((uint8_t *) sta_mac, + (uint8_t *) &mlm_disassoc_req->peer_macaddr.bytes, + QDF_MAC_ADDR_SIZE))) { + if (clean_rx_path) { + lim_process_disassoc_ack_timeout(mac_ctx); + } else { + if (tx_timer_running( + &mac_ctx->lim.limTimers.gLimDisassocAckTimer)) { + lim_deactivate_and_change_timer(mac_ctx, + eLIM_DISASSOC_ACK_TIMER); + } + qdf_mem_free(mlm_disassoc_req); + mac_ctx->lim.limDisassocDeauthCnfReq.pMlmDisassocReq = + NULL; + } + } + + mlm_deauth_req = mac_ctx->lim.limDisassocDeauthCnfReq.pMlmDeauthReq; + if (mlm_deauth_req && + (!qdf_mem_cmp((uint8_t *) sta_mac, + (uint8_t *) &mlm_deauth_req->peer_macaddr.bytes, + QDF_MAC_ADDR_SIZE))) { + if (clean_rx_path) { + lim_process_deauth_ack_timeout(mac_ctx); + } else { + if (tx_timer_running( + &mac_ctx->lim.limTimers.gLimDeauthAckTimer)) { + lim_deactivate_and_change_timer(mac_ctx, + eLIM_DEAUTH_ACK_TIMER); + } + qdf_mem_free(mlm_deauth_req); + mac_ctx->lim.limDisassocDeauthCnfReq.pMlmDeauthReq = + NULL; + } + } +} + +/* + * lim_process_disassoc_ack_timeout() - wrapper function around + * lim_send_disassoc_cnf + * + * @mac_ctx: mac_ctx + * + * wrapper function around lim_send_disassoc_cnf + * + * Return: void + */ +void lim_process_disassoc_ack_timeout(tpAniSirGlobal mac_ctx) +{ + lim_log(mac_ctx, LOG1, FL("")); + lim_send_disassoc_cnf(mac_ctx); +} + +/** + * lim_process_mlm_disassoc_req() - This function is called to process + * MLM_DISASSOC_REQ message from SME + * + * @mac_ctx: Pointer to Global MAC structure + * @msg_buf: A pointer to the MLM message buffer + * + * This function is called to process MLM_DISASSOC_REQ message from SME + * + * @Return: None + */ +static void +lim_process_mlm_disassoc_req(tpAniSirGlobal mac_ctx, uint32_t *msg_buf) +{ + tLimMlmDisassocReq *mlm_disassoc_req; + + if (msg_buf == NULL) { + lim_log(mac_ctx, LOGE, + FL("Buffer is Pointing to NULL")); + return; + } + + mlm_disassoc_req = (tLimMlmDisassocReq *) msg_buf; + lim_log(mac_ctx, LOG1, + FL("Process disassoc req, sessionID %d from: "MAC_ADDRESS_STR), + mlm_disassoc_req->sessionId, + MAC_ADDR_ARRAY(mlm_disassoc_req->peer_macaddr.bytes)); + + lim_process_mlm_disassoc_req_ntf(mac_ctx, QDF_STATUS_SUCCESS, + (uint32_t *) msg_buf); +} + +/** + * lim_process_mlm_deauth_req_ntf() - This function is process mlm deauth req + * notification + * + * @mac_ctx: Pointer to Global MAC structure + * @suspend_status: suspend status + * @msg_buf: A pointer to the MLM message buffer + * + * This function is process mlm deauth req notification + * + * @Return: None + */ +static void +lim_process_mlm_deauth_req_ntf(tpAniSirGlobal mac_ctx, + QDF_STATUS suspend_status, uint32_t *msg_buf) +{ + uint16_t aid; + tSirMacAddr curr_bssId; + tpDphHashNode sta_ds; + struct tLimPreAuthNode *auth_node; + tLimMlmDeauthReq *mlm_deauth_req; + tLimMlmDeauthCnf mlm_deauth_cnf; + tpPESession session; + tSirSmeDeauthRsp *sme_deauth_rsp; + + if (QDF_STATUS_SUCCESS != suspend_status) + lim_log(mac_ctx, LOGE, FL("Suspend Status is not success %X"), + suspend_status); + + mlm_deauth_req = (tLimMlmDeauthReq *) msg_buf; + session = pe_find_session_by_session_id(mac_ctx, + mlm_deauth_req->sessionId); + if (NULL == session) { + lim_log(mac_ctx, LOGE, + FL("session does not exist for given sessionId %d"), + mlm_deauth_req->sessionId); + qdf_mem_free(mlm_deauth_req); + return; + } + lim_log(mac_ctx, LOG1, FL("Process Deauth Req on sessionID %d Systemrole %d" + "mlmstate %d from: " MAC_ADDRESS_STR), + mlm_deauth_req->sessionId, + GET_LIM_SYSTEM_ROLE(session), + session->limMlmState, + MAC_ADDR_ARRAY(mlm_deauth_req->peer_macaddr.bytes)); + sir_copy_mac_addr(curr_bssId, session->bssId); + + switch (GET_LIM_SYSTEM_ROLE(session)) { + case eLIM_STA_ROLE: + switch (session->limMlmState) { + case eLIM_MLM_IDLE_STATE: + /* + * Attempting to Deauthenticate with a pre-authenticated + * peer. Deauthetiate with peer if there exists a + * pre-auth context below. + */ + break; + case eLIM_MLM_AUTHENTICATED_STATE: + case eLIM_MLM_WT_ASSOC_RSP_STATE: + case eLIM_MLM_LINK_ESTABLISHED_STATE: + if (qdf_mem_cmp(mlm_deauth_req->peer_macaddr.bytes, + curr_bssId, QDF_MAC_ADDR_SIZE)) { + lim_log(mac_ctx, LOGE, + FL("received MLM_DEAUTH_REQ with invalid BSS id " + "Peer MAC: "MAC_ADDRESS_STR + " CFG BSSID Addr : "MAC_ADDRESS_STR), + MAC_ADDR_ARRAY( + mlm_deauth_req->peer_macaddr.bytes), + MAC_ADDR_ARRAY(curr_bssId)); + /* + * Deauthentication response to host triggered + * deauthentication + */ + sme_deauth_rsp = + qdf_mem_malloc(sizeof(tSirSmeDeauthRsp)); + if (NULL == sme_deauth_rsp) { + lim_log(mac_ctx, LOGP, + FL("memory allocation failed for deauth rsp")); + return; + } + + lim_log(mac_ctx, LOG1, + FL("send deauth rsp with ret code %d for" MAC_ADDRESS_STR), + eSIR_SME_DEAUTH_STATUS, + MAC_ADDR_ARRAY( + mlm_deauth_req->peer_macaddr.bytes)); + + sme_deauth_rsp->messageType = + eWNI_SME_DEAUTH_RSP; + sme_deauth_rsp->length = + sizeof(tSirSmeDeauthRsp); + sme_deauth_rsp->statusCode = + eSIR_SME_DEAUTH_STATUS; + sme_deauth_rsp->sessionId = + mlm_deauth_req->sessionId; + sme_deauth_rsp->transactionId = 0; + + qdf_mem_copy(sme_deauth_rsp->peer_macaddr.bytes, + mlm_deauth_req->peer_macaddr.bytes, + QDF_MAC_ADDR_SIZE); + + msg_buf = (uint32_t *)sme_deauth_rsp; + + lim_send_sme_disassoc_deauth_ntf(mac_ctx, + QDF_STATUS_SUCCESS, msg_buf); + return; + } + + if ((session->limMlmState == + eLIM_MLM_AUTHENTICATED_STATE) || + (session->limMlmState == + eLIM_MLM_WT_ASSOC_RSP_STATE)) { + /* Send deauth frame to peer entity */ + lim_send_deauth_mgmt_frame(mac_ctx, + mlm_deauth_req->reasonCode, + mlm_deauth_req->peer_macaddr.bytes, + session, false); + /* Prepare and Send LIM_MLM_DEAUTH_CNF */ + mlm_deauth_cnf.resultCode = eSIR_SME_SUCCESS; + session->limMlmState = eLIM_MLM_IDLE_STATE; + MTRACE(mac_trace(mac_ctx, TRACE_CODE_MLM_STATE, + session->peSessionId, + session->limMlmState)); + goto end; + } + break; + default: + lim_log(mac_ctx, LOGW, + FL("received MLM_DEAUTH_REQ with in state %d for peer " + MAC_ADDRESS_STR), + session->limMlmState, + MAC_ADDR_ARRAY( + mlm_deauth_req->peer_macaddr.bytes)); + lim_print_mlm_state(mac_ctx, LOGW, + session->limMlmState); + /* Prepare and Send LIM_MLM_DEAUTH_CNF */ + mlm_deauth_cnf.resultCode = + eSIR_SME_STA_NOT_AUTHENTICATED; + + goto end; + } + break; + case eLIM_STA_IN_IBSS_ROLE: + lim_log(mac_ctx, LOGE, FL("received MLM_DEAUTH_REQ IBSS Mode")); + mlm_deauth_cnf.resultCode = eSIR_SME_INVALID_PARAMETERS; + goto end; + case eLIM_AP_ROLE: + case eLIM_P2P_DEVICE_GO: + if (true == + mac_ctx->sap.SapDfsInfo.is_dfs_cac_timer_running) { + lim_log(mac_ctx, LOGE, + FL("CAC timer is running, drop disassoc from going out")); + mlm_deauth_cnf.resultCode = eSIR_SME_SUCCESS; + goto end; + } + break; + + default: + break; + } /* end switch (GET_LIM_SYSTEM_ROLE(session)) */ + + /* + * Check if there exists a context for the peer entity + * to be deauthenticated with. + */ + sta_ds = dph_lookup_hash_entry(mac_ctx, + mlm_deauth_req->peer_macaddr.bytes, + &aid, &session->dph.dphHashTable); + + if (sta_ds == NULL) { + /* Check if there exists pre-auth context for this STA */ + auth_node = lim_search_pre_auth_list(mac_ctx, + mlm_deauth_req->peer_macaddr.bytes); + if (auth_node == NULL) { + /* + * Received DEAUTH REQ for a STA that is neither + * Associated nor Pre-authenticated. Log error, + * Prepare and Send LIM_MLM_DEAUTH_CNF + */ + lim_log(mac_ctx, LOGW, + FL("received MLM_DEAUTH_REQ in mlme state %d for STA that " + "does not have context, Addr=" + MAC_ADDRESS_STR), + session->limMlmState, + MAC_ADDR_ARRAY( + mlm_deauth_req->peer_macaddr.bytes)); + mlm_deauth_cnf.resultCode = + eSIR_SME_STA_NOT_AUTHENTICATED; + } else { + mlm_deauth_cnf.resultCode = eSIR_SME_SUCCESS; + /* Delete STA from pre-auth STA list */ + lim_delete_pre_auth_node(mac_ctx, + mlm_deauth_req->peer_macaddr.bytes); + /* Send Deauthentication frame to peer entity */ + lim_send_deauth_mgmt_frame(mac_ctx, + mlm_deauth_req->reasonCode, + mlm_deauth_req->peer_macaddr.bytes, + session, false); + } + goto end; + } else if ((sta_ds->mlmStaContext.mlmState != + eLIM_MLM_LINK_ESTABLISHED_STATE) && + (sta_ds->mlmStaContext.mlmState != + eLIM_MLM_WT_ASSOC_CNF_STATE)) { + /* + * received MLM_DEAUTH_REQ for STA that either has no context or + * in some transit state + */ + lim_log(mac_ctx, LOGW, + FL("Invalid MLM_DEAUTH_REQ, Addr="MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(mlm_deauth_req->peer_macaddr.bytes)); + /* Prepare and Send LIM_MLM_DEAUTH_CNF */ + mlm_deauth_cnf.resultCode = eSIR_SME_INVALID_PARAMETERS; + goto end; + } + /* sta_ds->mlmStaContext.rxPurgeReq = 1; */ + sta_ds->mlmStaContext.disassocReason = (tSirMacReasonCodes) + mlm_deauth_req->reasonCode; + sta_ds->mlmStaContext.cleanupTrigger = mlm_deauth_req->deauthTrigger; + mac_ctx->lim.limDisassocDeauthCnfReq.pMlmDeauthReq = mlm_deauth_req; + /* + * Set state to mlm State to eLIM_MLM_WT_DEL_STA_RSP_STATE + * This is to address the issue of race condition between + * disconnect request from the HDD and disassoc from + * inactivity timer. This will make sure that we will not + * process disassoc if deauth is in progress for the station + * and thus mlmStaContext.cleanupTrigger will not be overwritten. + */ + sta_ds->mlmStaContext.mlmState = eLIM_MLM_WT_DEL_STA_RSP_STATE; + /* Send Deauthentication frame to peer entity */ + lim_send_deauth_mgmt_frame(mac_ctx, mlm_deauth_req->reasonCode, + mlm_deauth_req->peer_macaddr.bytes, + session, true); + return; +end: + qdf_copy_macaddr(&mlm_deauth_cnf.peer_macaddr, + &mlm_deauth_req->peer_macaddr); + mlm_deauth_cnf.deauthTrigger = mlm_deauth_req->deauthTrigger; + mlm_deauth_cnf.aid = mlm_deauth_req->aid; + mlm_deauth_cnf.sessionId = mlm_deauth_req->sessionId; + + /* Free up buffer allocated for mlmDeauthReq */ + qdf_mem_free(mlm_deauth_req); + lim_post_sme_message(mac_ctx, + LIM_MLM_DEAUTH_CNF, (uint32_t *) &mlm_deauth_cnf); +} + +/* + * lim_process_deauth_ack_timeout() - wrapper function around + * lim_send_deauth_cnf + * + * @mac_ctx: mac_ctx + * + * wrapper function around lim_send_deauth_cnf + * + * Return: void + */ +void lim_process_deauth_ack_timeout(tpAniSirGlobal mac_ctx) +{ + lim_log(mac_ctx, LOG1, FL("")); + lim_send_deauth_cnf(mac_ctx); +} + +/* + * lim_process_mlm_deauth_req() - This function is called to process + * MLM_DEAUTH_REQ message from SME + * + * @mac_ctx: Pointer to Global MAC structure + * @msg_buf: A pointer to the MLM message buffer + * + * This function is called to process MLM_DEAUTH_REQ message from SME + * + * @Return: None + */ +static void +lim_process_mlm_deauth_req(tpAniSirGlobal mac_ctx, uint32_t *msg_buf) +{ + tLimMlmDeauthReq *mlm_deauth_req; + tpPESession session; + + if (msg_buf == NULL) { + PELOGE(lim_log(mac_ctx, LOGE, FL("Buffer is Pointing to NULL"));) + return; + } + + mlm_deauth_req = (tLimMlmDeauthReq *) msg_buf; + lim_log(mac_ctx, LOG1, + FL("Process Deauth Req on sessionID %d from: " + MAC_ADDRESS_STR), + mlm_deauth_req->sessionId, + MAC_ADDR_ARRAY(mlm_deauth_req->peer_macaddr.bytes)); + + session = pe_find_session_by_session_id(mac_ctx, + mlm_deauth_req->sessionId); + if (NULL == session) { + lim_log(mac_ctx, LOGE, + FL("session does not exist for given sessionId %d"), + mlm_deauth_req->sessionId); + return; + } + lim_process_mlm_deauth_req_ntf(mac_ctx, QDF_STATUS_SUCCESS, + (uint32_t *) msg_buf); +} + +/** + * lim_process_mlm_set_keys_req() - This function is called to process + * MLM_SETKEYS_REQ message from SME + * + * @mac_ctx: Pointer to Global MAC structure + * @msg_buf: A pointer to the MLM message buffer + * + * This function is called to process MLM_SETKEYS_REQ message from SME + * + * @Return: None + */ +static void +lim_process_mlm_set_keys_req(tpAniSirGlobal mac_ctx, uint32_t *msg_buf) +{ + uint16_t aid; + uint16_t sta_idx = 0; + uint32_t default_key_id = 0; + struct qdf_mac_addr curr_bssid; + tpDphHashNode sta_ds; + tLimMlmSetKeysReq *mlm_set_keys_req; + tLimMlmSetKeysCnf mlm_set_keys_cnf; + tpPESession session; + + if (msg_buf == NULL) { + lim_log(mac_ctx, LOGE, FL("Buffer is Pointing to NULL")); + return; + } + + mlm_set_keys_req = (tLimMlmSetKeysReq *) msg_buf; + /* Hold onto the SetKeys request parameters */ + mac_ctx->lim.gpLimMlmSetKeysReq = (void *)mlm_set_keys_req; + session = pe_find_session_by_session_id(mac_ctx, + mlm_set_keys_req->sessionId); + if (NULL == session) { + lim_log(mac_ctx, LOGE, + FL("session does not exist for given sessionId")); + return; + } + + lim_log(mac_ctx, LOGW, + FL("Received MLM_SETKEYS_REQ with parameters:" + "AID [%d], ED Type [%d], # Keys [%d] & Peer MAC Addr - "), + mlm_set_keys_req->aid, mlm_set_keys_req->edType, + mlm_set_keys_req->numKeys); + lim_print_mac_addr(mac_ctx, mlm_set_keys_req->peer_macaddr.bytes, LOGW); + qdf_mem_copy(curr_bssid.bytes, session->bssId, QDF_MAC_ADDR_SIZE); + + switch (GET_LIM_SYSTEM_ROLE(session)) { + case eLIM_STA_ROLE: + /* + * In case of TDLS, peerMac address need not be BssId. Skip this + * check if TDLS is enabled. + */ +#ifndef FEATURE_WLAN_TDLS + if ((!qdf_is_macaddr_broadcast( + &mlm_set_keys_req->peer_macaddr)) && + (!qdf_is_macaddr_equal(&mlm_set_keys_req->peer_macaddr, + &curr_bssid))) { + lim_log(mac_ctx, LOGW, + FL("Received MLM_SETKEYS_REQ with invalid BSSID" + MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(mlm_set_keys_req-> + peer_macaddr.bytes)); + /* + * Prepare and Send LIM_MLM_SETKEYS_CNF with error code + */ + mlm_set_keys_cnf.resultCode = + eSIR_SME_INVALID_PARAMETERS; + goto end; + } +#endif + break; + case eLIM_STA_IN_IBSS_ROLE: + /* + * update the IBSS PE session encrption type based on the + * key type + */ + session->encryptType = mlm_set_keys_req->edType; + break; + default: + break; + } + + /* + * Use the "unicast" parameter to determine if the "Group Keys" + * are being set. + * mlm_set_keys_req->key.unicast = 0 -> Multicast/broadcast + * mlm_set_keys_req->key.unicast - 1 -> Unicast keys are being set + */ + if (qdf_is_macaddr_broadcast(&mlm_set_keys_req->peer_macaddr)) { + lim_log(mac_ctx, LOG1, FL("Trying to set Group Keys...%d "), + mlm_set_keys_req->sessionId); + /* + * When trying to set Group Keys for any security mode other + * than WEP, use the STA Index corresponding to the AP... + */ + switch (mlm_set_keys_req->edType) { + case eSIR_ED_CCMP: +#ifdef WLAN_FEATURE_11W + case eSIR_ED_AES_128_CMAC: +#endif + sta_idx = session->staId; + break; + default: + break; + } + } else { + lim_log(mac_ctx, LOG1, FL("Trying to set Unicast Keys...")); + /* + * Check if there exists a context for the + * peer entity for which keys need to be set. + */ + sta_ds = dph_lookup_hash_entry(mac_ctx, + mlm_set_keys_req->peer_macaddr.bytes, &aid, + &session->dph.dphHashTable); + if ((sta_ds == NULL) || + ((sta_ds->mlmStaContext.mlmState != + eLIM_MLM_LINK_ESTABLISHED_STATE) && + !LIM_IS_AP_ROLE(session))) { + /* + * Received LIM_MLM_SETKEYS_REQ for STA that does not + * have context or in some transit state. + */ + lim_log(mac_ctx, LOG1, + FL("Invalid MLM_SETKEYS_REQ, Addr = " + MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(mlm_set_keys_req-> + peer_macaddr.bytes)); + /* Prepare and Send LIM_MLM_SETKEYS_CNF */ + mlm_set_keys_cnf.resultCode = + eSIR_SME_INVALID_PARAMETERS; + goto end; + } else { + sta_idx = sta_ds->staIndex; + } + } + + if ((mlm_set_keys_req->numKeys == 0) + && (mlm_set_keys_req->edType != eSIR_ED_NONE)) { + /* + * Broadcast/Multicast Keys (for WEP!!) are NOT sent + * via this interface!! This indicates to HAL that the WEP Keys + * need to be extracted from the CFG and applied to hardware + */ + default_key_id = 0xff; + } else if (mlm_set_keys_req->key[0].keyId && + ((mlm_set_keys_req->edType == eSIR_ED_WEP40) || + (mlm_set_keys_req->edType == eSIR_ED_WEP104))) { + /* + * If the Key Id is non zero and encryption mode is WEP, + * the key index is coming from the upper layers so that key + * only need to be used as the default tx key, This is being + * used only in case of WEP mode in HAL + */ + default_key_id = mlm_set_keys_req->key[0].keyId; + } else { + default_key_id = 0; + } + lim_log(mac_ctx, LOG1, + FL("Trying to set keys for STA Index [%d], using default_key_id [%d]"), + sta_idx, default_key_id); + + if (qdf_is_macaddr_broadcast(&mlm_set_keys_req->peer_macaddr)) { + session->limPrevMlmState = session->limMlmState; + session->limMlmState = eLIM_MLM_WT_SET_BSS_KEY_STATE; + MTRACE(mac_trace(mac_ctx, TRACE_CODE_MLM_STATE, + session->peSessionId, session->limMlmState)); + lim_log(mac_ctx, LOG1, FL("Trying to set Group Keys...%d "), + session->peSessionId); + /* Package WMA_SET_BSSKEY_REQ message parameters */ + lim_send_set_bss_key_req(mac_ctx, mlm_set_keys_req, session); + return; + } else { + /* + * Package WMA_SET_STAKEY_REQ / WMA_SET_STA_BCASTKEY_REQ message + * parameters + */ + lim_send_set_sta_key_req(mac_ctx, mlm_set_keys_req, sta_idx, + (uint8_t) default_key_id, session, + true); + return; + } +end: + mlm_set_keys_cnf.sessionId = mlm_set_keys_req->sessionId; + lim_post_sme_set_keys_cnf(mac_ctx, mlm_set_keys_req, &mlm_set_keys_cnf); +} + +/** + * lim_process_periodic_probe_req_timer() - This function is called to process + * periodic probe request to send during scan. + * + * @mac_ctx: Pointer to Global MAC structure + * + * This function is called to process periodic probe request to send during scan + * + * @Return None + */ +static void lim_process_periodic_probe_req_timer(tpAniSirGlobal mac_ctx) +{ + uint8_t channel_num; + uint8_t i = 0; + tLimMlmScanReq *mlm_scan_req; + tSirRetStatus status = eSIR_SUCCESS; + TX_TIMER *probe_req_timer = + &mac_ctx->lim.limTimers.gLimPeriodicProbeReqTimer; + + if (qdf_mc_timer_get_current_state(&probe_req_timer->qdf_timer) + != QDF_TIMER_STATE_STOPPED) { + lim_log(mac_ctx, LOG1, FL("Invalid state of timer")); + return; + } + + if (!((mac_ctx->lim.gLimMlmState == eLIM_MLM_WT_PROBE_RESP_STATE) + && (probe_req_timer->sessionId != 0xff) + && (mac_ctx->lim.probeCounter < mac_ctx->lim.maxProbe))) { + lim_log(mac_ctx, LOG1, + FL("received unexpected Periodic scan timeout in state %X"), + mac_ctx->lim.gLimMlmState); + return; + } + + mlm_scan_req = mac_ctx->lim.gpLimMlmScanReq; + mac_ctx->lim.probeCounter++; + /* Periodic channel timer timed out to send probe request. */ + channel_num = lim_get_current_scan_channel(mac_ctx); + do { + /* + * Prepare and send Probe Request frame for all the SSIDs + * present in the saved MLM + */ + status = lim_send_probe_req_mgmt_frame(mac_ctx, + &mlm_scan_req->ssId[i], mlm_scan_req->bssId, + channel_num, mac_ctx->lim.gSelfMacAddr, + mlm_scan_req->dot11mode, + mlm_scan_req->uIEFieldLen, + (uint8_t *) (mlm_scan_req) + + mlm_scan_req->uIEFieldOffset); + if (status != eSIR_SUCCESS) { + lim_log(mac_ctx, LOGE, + FL("send ProbeReq failed for SSID %s on channel: %d"), + mlm_scan_req->ssId[i].ssId, channel_num); + return; + } + i++; + } while (i < mlm_scan_req->numSsid); + /* Activate timer again */ + if (tx_timer_activate(probe_req_timer) != TX_SUCCESS) { + lim_log(mac_ctx, LOGP, + FL("could not start periodic probe req timer")); + return; + } +} + +/** + * lim_process_join_failure_timeout() - This function is called to process + * JoinFailureTimeout + * + * @mac_ctx: Pointer to Global MAC structure + * + * This function is called to process JoinFailureTimeout + * + * @Return None + */ +static void lim_process_join_failure_timeout(tpAniSirGlobal mac_ctx) +{ + tLimMlmJoinCnf mlm_join_cnf; + uint32_t len; +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM + host_log_rssi_pkt_type *rssi_log = NULL; +#endif + tpPESession session; + + session = pe_find_session_by_session_id(mac_ctx, + mac_ctx->lim.limTimers.gLimJoinFailureTimer.sessionId); + if (NULL == session) { + lim_log(mac_ctx, LOGE, + FL("Session Does not exist for given sessionID")); + return; + } +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM + WLAN_HOST_DIAG_LOG_ALLOC(rssi_log, + host_log_rssi_pkt_type, LOG_WLAN_RSSI_UPDATE_C); + if (rssi_log) + rssi_log->rssi = session->rssi; + WLAN_HOST_DIAG_LOG_REPORT(rssi_log); +#endif + + if (session->limMlmState == eLIM_MLM_WT_JOIN_BEACON_STATE) { + len = sizeof(tSirMacAddr); + /* Change timer for future activations */ + lim_deactivate_and_change_timer(mac_ctx, eLIM_JOIN_FAIL_TIMER); + /* Change Periodic probe req timer for future activation */ + lim_deactivate_and_change_timer(mac_ctx, + eLIM_PERIODIC_JOIN_PROBE_REQ_TIMER); + /* Issue MLM join confirm with timeout reason code */ + lim_log(mac_ctx, LOGE, + FL("Join Failure Timeout, In eLIM_MLM_WT_JOIN_BEACON_STATE session:%d " + MAC_ADDRESS_STR), + session->peSessionId, MAC_ADDR_ARRAY(session->bssId)); + + mlm_join_cnf.resultCode = eSIR_SME_JOIN_TIMEOUT_RESULT_CODE; + mlm_join_cnf.protStatusCode = eSIR_MAC_UNSPEC_FAILURE_STATUS; + session->limMlmState = eLIM_MLM_IDLE_STATE; + MTRACE(mac_trace(mac_ctx, TRACE_CODE_MLM_STATE, + session->peSessionId, session->limMlmState)); + /* Update PE session Id */ + mlm_join_cnf.sessionId = session->peSessionId; + /* Freeup buffer allocated to join request */ + if (session->pLimMlmJoinReq) { + qdf_mem_free(session->pLimMlmJoinReq); + session->pLimMlmJoinReq = NULL; + } + lim_post_sme_message(mac_ctx, LIM_MLM_JOIN_CNF, + (uint32_t *) &mlm_join_cnf); + return; + } else { + lim_log(mac_ctx, LOGW, + FL("received unexpected JOIN failure timeout in state %X"), + session->limMlmState); + lim_print_mlm_state(mac_ctx, LOGW, session->limMlmState); + } +} + +/** + * lim_process_periodic_join_probe_req_timer() - This function is called to + * process periodic probe request send during joining process. + * + * @mac_ctx: Pointer to Global MAC structure + * + * This function is called to process periodic probe request send during + * joining process. + * + * @Return None + */ +static void lim_process_periodic_join_probe_req_timer(tpAniSirGlobal mac_ctx) +{ + tpPESession session; + tSirMacSSid ssid; + + session = pe_find_session_by_session_id(mac_ctx, + mac_ctx->lim.limTimers.gLimPeriodicJoinProbeReqTimer.sessionId); + if (NULL == session) { + lim_log(mac_ctx, LOGE, + FL("session does not exist for given SessionId : %d"), + mac_ctx->lim.limTimers.gLimPeriodicJoinProbeReqTimer. + sessionId); + return; + } + + if ((true == + tx_timer_running(&mac_ctx->lim.limTimers.gLimJoinFailureTimer)) + && (session->limMlmState == eLIM_MLM_WT_JOIN_BEACON_STATE)) { + qdf_mem_copy(ssid.ssId, session->ssId.ssId, + session->ssId.length); + ssid.length = session->ssId.length; + lim_send_probe_req_mgmt_frame(mac_ctx, &ssid, + session->pLimMlmJoinReq->bssDescription.bssId, + session->currentOperChannel /*chanNum */, + session->selfMacAddr, session->dot11mode, + session->pLimJoinReq->addIEScan.length, + session->pLimJoinReq->addIEScan.addIEdata); + lim_deactivate_and_change_timer(mac_ctx, + eLIM_PERIODIC_JOIN_PROBE_REQ_TIMER); + /* Activate Join Periodic Probe Req timer */ + if (tx_timer_activate( + &mac_ctx->lim.limTimers.gLimPeriodicJoinProbeReqTimer) != + TX_SUCCESS) { + lim_log(mac_ctx, LOGP, + FL("could not activate Periodic Join req failure timer")); + return; + } + } +} + +/** + * lim_process_auth_retry_timer()- function to Retry Auth + * @mac_ctx:pointer to global mac + * + * Return: void + */ + +static void lim_process_auth_retry_timer(tpAniSirGlobal mac_ctx) +{ + tpPESession session_entry; + + lim_log(mac_ctx, LOG1, FL("ENTER")); + + session_entry = + pe_find_session_by_session_id(mac_ctx, + mac_ctx->lim.limTimers.g_lim_periodic_auth_retry_timer.sessionId); + if (NULL == session_entry) { + lim_log(mac_ctx, LOGE, + FL("session does not exist for given SessionId : %d"), + mac_ctx->lim.limTimers. + g_lim_periodic_auth_retry_timer.sessionId); + return; + } + + if (tx_timer_running(&mac_ctx->lim.limTimers.gLimAuthFailureTimer) && + (session_entry->limMlmState == eLIM_MLM_WT_AUTH_FRAME2_STATE) && + (LIM_AUTH_ACK_RCD_SUCCESS != mac_ctx->auth_ack_status)) { + tSirMacAuthFrameBody auth_frame; + + /* + * Send the auth retry only in case we have received ack failure + * else just restart the retry timer. + */ + if (LIM_AUTH_ACK_RCD_FAILURE == mac_ctx->auth_ack_status) { + /* Prepare & send Authentication frame */ + auth_frame.authAlgoNumber = + (uint8_t) mac_ctx->lim.gpLimMlmAuthReq->authType; + auth_frame.authTransactionSeqNumber = + SIR_MAC_AUTH_FRAME_1; + auth_frame.authStatusCode = 0; + lim_log(mac_ctx, LOGW, FL("Retry Auth ")); + mac_ctx->auth_ack_status = LIM_AUTH_ACK_NOT_RCD; + lim_send_auth_mgmt_frame(mac_ctx, + &auth_frame, + mac_ctx->lim.gpLimMlmAuthReq->peerMacAddr, + LIM_NO_WEP_IN_FC, session_entry); + } + + lim_deactivate_and_change_timer(mac_ctx, eLIM_AUTH_RETRY_TIMER); + + /* Activate Auth Retry timer */ + if (tx_timer_activate + (&mac_ctx->lim.limTimers.g_lim_periodic_auth_retry_timer) + != TX_SUCCESS) { + lim_log(mac_ctx, LOGE, + FL("could not activate Auth Retry failure timer")); + return; + } + } + return; +} /*** lim_process_auth_retry_timer() ***/ + +/** + * lim_process_auth_failure_timeout() - This function is called to process Min + * Channel Timeout during channel scan. + * + * @mac_ctx: Pointer to Global MAC structure + * + * This function is called to process Min Channel Timeout during channel scan. + * + * @Return: None + */ +static void lim_process_auth_failure_timeout(tpAniSirGlobal mac_ctx) +{ + /* fetch the sessionEntry based on the sessionId */ + tpPESession session; +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM + host_log_rssi_pkt_type *rssi_log = NULL; +#endif + + session = pe_find_session_by_session_id(mac_ctx, + mac_ctx->lim.limTimers.gLimAuthFailureTimer.sessionId); + if (NULL == session) { + lim_log(mac_ctx, LOGP, + FL("Session Does not exist for given sessionID")); + return; + } + + lim_log(mac_ctx, LOGE, + FL("received AUTH failure timeout in sessionid %d " + "limMlmstate %X limSmeState %X"), + session->peSessionId, session->limMlmState, + session->limSmeState); +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM + lim_diag_event_report(mac_ctx, WLAN_PE_DIAG_AUTH_TIMEOUT, session, + 0, AUTH_FAILURE_TIMEOUT); + + WLAN_HOST_DIAG_LOG_ALLOC(rssi_log, host_log_rssi_pkt_type, + LOG_WLAN_RSSI_UPDATE_C); + if (rssi_log) + rssi_log->rssi = session->rssi; + WLAN_HOST_DIAG_LOG_REPORT(rssi_log); +#endif + + switch (session->limMlmState) { + case eLIM_MLM_WT_AUTH_FRAME2_STATE: + case eLIM_MLM_WT_AUTH_FRAME4_STATE: + /* + * Requesting STA did not receive next auth frame before Auth + * Failure timeout. Issue MLM auth confirm with timeout reason + * code. Restore default failure timeout + */ + if (QDF_P2P_CLIENT_MODE == session->pePersona + && session->defaultAuthFailureTimeout) + cfg_set_int(mac_ctx, + WNI_CFG_AUTHENTICATE_FAILURE_TIMEOUT, + session->defaultAuthFailureTimeout); + lim_restore_from_auth_state(mac_ctx, + eSIR_SME_AUTH_TIMEOUT_RESULT_CODE, + eSIR_MAC_UNSPEC_FAILURE_REASON, session); + break; + default: + /* + * Auth failure timer should not have timed out + * in states other than wt_auth_frame2/4 + */ + lim_log(mac_ctx, LOGE, + FL("received unexpected AUTH failure timeout in state %X"), + session->limMlmState); + lim_print_mlm_state(mac_ctx, LOGE, session->limMlmState); + break; + } +} + +/** + * lim_process_auth_rsp_timeout() - This function is called to process Min + * Channel Timeout during channel scan. + * + * @mac_ctx: Pointer to Global MAC structure + * + * This function is called to process Min Channel Timeout during channel scan. + * + * @Return: None + */ +static void +lim_process_auth_rsp_timeout(tpAniSirGlobal mac_ctx, uint32_t auth_idx) +{ + struct tLimPreAuthNode *auth_node; + tpPESession session; + uint8_t session_id; + + auth_node = lim_get_pre_auth_node_from_index(mac_ctx, + &mac_ctx->lim.gLimPreAuthTimerTable, auth_idx); + if (NULL == auth_node) { + lim_log(mac_ctx, LOGW, FL("Invalid auth node")); + return; + } + + session = pe_find_session_by_bssid(mac_ctx, auth_node->peerMacAddr, + &session_id); + if (NULL == session) { + lim_log(mac_ctx, LOGW, + FL("session does not exist for given BSSID ")); + return; + } + +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM + lim_diag_event_report(mac_ctx, WLAN_PE_DIAG_AUTH_TIMEOUT, + session, 0, AUTH_RESPONSE_TIMEOUT); +#endif + + if (LIM_IS_AP_ROLE(session) || LIM_IS_IBSS_ROLE(session)) { + if (auth_node->mlmState != eLIM_MLM_WT_AUTH_FRAME3_STATE) { + lim_log(mac_ctx, LOGE, + FL("received AUTH rsp timeout in unexpected " + "state for MAC address: " MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(auth_node->peerMacAddr)); + } else { + auth_node->mlmState = eLIM_MLM_AUTH_RSP_TIMEOUT_STATE; + auth_node->fTimerStarted = 0; + lim_log(mac_ctx, LOG1, + FL("AUTH rsp timedout for MAC address " + MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(auth_node->peerMacAddr)); + /* Change timer to reactivate it in future */ + lim_deactivate_and_change_per_sta_id_timer(mac_ctx, + eLIM_AUTH_RSP_TIMER, auth_node->authNodeIdx); + lim_delete_pre_auth_node(mac_ctx, + auth_node->peerMacAddr); + } + } +} + +/** + * lim_process_assoc_failure_timeout() - This function is called to process Min + * Channel Timeout during channel scan. + * + * @mac_ctx Pointer to Global MAC structure + * + * This function is called to process Min Channel Timeout during channel scan. + * + * @Return: None + */ +static void +lim_process_assoc_failure_timeout(tpAniSirGlobal mac_ctx, uint32_t msg_type) +{ + + tLimMlmAssocCnf mlm_assoc_cnf; + tpPESession session; +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM + host_log_rssi_pkt_type *rssi_log = NULL; +#endif + /* + * to fetch the lim/mlm state based on the session_id, use the + * below sessionEntry + */ + uint8_t session_id; + + if (msg_type == LIM_ASSOC) + session_id = + mac_ctx->lim.limTimers.gLimAssocFailureTimer.sessionId; + else + session_id = + mac_ctx->lim.limTimers.gLimReassocFailureTimer.sessionId; + + session = pe_find_session_by_session_id(mac_ctx, session_id); + if (NULL == session) { + lim_log(mac_ctx, LOGP, + FL("Session Does not exist for given sessionID")); + return; + } +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM + lim_diag_event_report(mac_ctx, WLAN_PE_DIAG_ASSOC_TIMEOUT, + session, 0, 0); + + WLAN_HOST_DIAG_LOG_ALLOC(rssi_log, + host_log_rssi_pkt_type, + LOG_WLAN_RSSI_UPDATE_C); + if (rssi_log) + rssi_log->rssi = session->rssi; + WLAN_HOST_DIAG_LOG_REPORT(rssi_log); +#endif + + lim_log(mac_ctx, LOG1, + FL("Re/Association Response not received before timeout ")); + + /* + * Send Deauth to handle the scenareo where association timeout happened + * when device has missed the assoc resp sent by peer. + * By sending deauth try to clear the session created on peer device. + */ + lim_log(mac_ctx, LOGE, + FL("Sessionid: %d try sending deauth on channel %d to BSSID: " + MAC_ADDRESS_STR), session->peSessionId, + session->currentOperChannel, + MAC_ADDR_ARRAY(session->bssId)); + lim_send_deauth_mgmt_frame(mac_ctx, eSIR_MAC_UNSPEC_FAILURE_REASON, + session->bssId, session, false); + + if ((LIM_IS_AP_ROLE(session)) || + ((session->limMlmState != eLIM_MLM_WT_ASSOC_RSP_STATE) && + (session->limMlmState != eLIM_MLM_WT_REASSOC_RSP_STATE) && + (session->limMlmState != eLIM_MLM_WT_FT_REASSOC_RSP_STATE))) { + /* + * Re/Assoc failure timer should not have timedout on AP + * or in a state other than wt_re/assoc_response. + */ + lim_log(mac_ctx, LOGW, + FL("received unexpected REASSOC failure timeout in state %X for role %d"), + session->limMlmState, + GET_LIM_SYSTEM_ROLE(session)); + lim_print_mlm_state(mac_ctx, LOGW, session->limMlmState); + return; + } + + if ((msg_type == LIM_ASSOC) || ((msg_type == LIM_REASSOC) + && (session->limMlmState == eLIM_MLM_WT_FT_REASSOC_RSP_STATE))) { + lim_log(mac_ctx, LOGE, + FL("(Re)Assoc Failure Timeout occurred.")); + session->limMlmState = eLIM_MLM_IDLE_STATE; + MTRACE(mac_trace(mac_ctx, TRACE_CODE_MLM_STATE, + session->peSessionId, session->limMlmState)); + /* Change timer for future activations */ + lim_deactivate_and_change_timer(mac_ctx, eLIM_ASSOC_FAIL_TIMER); + /* + * Free up buffer allocated for JoinReq held by + * MLM state machine + */ + if (session->pLimMlmJoinReq) { + qdf_mem_free(session->pLimMlmJoinReq); + session->pLimMlmJoinReq = NULL; + } + /* To remove the preauth node in case of fail to associate */ + if (lim_search_pre_auth_list(mac_ctx, session->bssId)) { + lim_log(mac_ctx, LOG1, + FL(" delete pre auth node for "MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(session->bssId)); + lim_delete_pre_auth_node(mac_ctx, + session->bssId); + } + + mlm_assoc_cnf.resultCode = eSIR_SME_ASSOC_TIMEOUT_RESULT_CODE; + mlm_assoc_cnf.protStatusCode = eSIR_MAC_UNSPEC_FAILURE_STATUS; + /* Update PE session Id */ + mlm_assoc_cnf.sessionId = session->peSessionId; + if (msg_type == LIM_ASSOC) { + lim_post_sme_message(mac_ctx, LIM_MLM_ASSOC_CNF, + (uint32_t *) &mlm_assoc_cnf); + } else { + /* + * Will come here only in case of 11r, Ese FT + * when reassoc rsp is not received and we + * receive a reassoc - timesout + */ + mlm_assoc_cnf.resultCode = + eSIR_SME_FT_REASSOC_TIMEOUT_FAILURE; + lim_post_sme_message(mac_ctx, LIM_MLM_REASSOC_CNF, + (uint32_t *) &mlm_assoc_cnf); + } + } else { + /* + * Restore pre-reassoc req state. + * Set BSSID to currently associated AP address. + */ + session->limMlmState = session->limPrevMlmState; + MTRACE(mac_trace(mac_ctx, TRACE_CODE_MLM_STATE, + session->peSessionId, session->limMlmState)); + lim_restore_pre_reassoc_state(mac_ctx, + eSIR_SME_REASSOC_TIMEOUT_RESULT_CODE, + eSIR_MAC_UNSPEC_FAILURE_STATUS, session); + } +} + +/** + * lim_complete_mlm_scan() - This function is called to send MLM_SCAN_CNF + * message to SME state machine. + * + * @mac_ctx: Pointer to Global MAC structure + * @ret_code: Result code to be sent + * + * This function is called to send MLM_SCAN_CNF message to SME state machine. + * + * @Return: None + */ + +void lim_complete_mlm_scan(tpAniSirGlobal mac_ctx, tSirResultCodes ret_code) +{ + tLimMlmScanCnf mlm_scan_cnf; + + /* Restore previous MLM state */ + mac_ctx->lim.gLimMlmState = mac_ctx->lim.gLimPrevMlmState; + MTRACE(mac_trace(mac_ctx, TRACE_CODE_MLM_STATE, NO_SESSION, + mac_ctx->lim.gLimMlmState)); + lim_restore_pre_scan_state(mac_ctx); + /* Free up mac_ctx->lim.gLimMlmScanReq */ + if (NULL != mac_ctx->lim.gpLimMlmScanReq) { + qdf_mem_free(mac_ctx->lim.gpLimMlmScanReq); + mac_ctx->lim.gpLimMlmScanReq = NULL; + } + + mlm_scan_cnf.resultCode = ret_code; + lim_post_sme_message(mac_ctx, LIM_MLM_SCAN_CNF, + (uint32_t *) &mlm_scan_cnf); +} + +/** + * lim_set_channel() - set channel api for lim + * + * @mac_ctx: Pointer to Global MAC structure + * @channel: power save state + * @ch_center_freq_seg0: center freq seq 0 + * @ch_center_freq_seg1: center freq seq 1 + * @ch_width: channel width + * @max_tx_power: max tx power + * @pe_session_id: pe session id + * + * set channel api for lim + * + * @Return: None + */ +void lim_set_channel(tpAniSirGlobal mac_ctx, uint8_t channel, + uint8_t ch_center_freq_seg0, uint8_t ch_center_freq_seg1, + enum phy_ch_width ch_width, int8_t max_tx_power, + uint8_t pe_session_id) +{ + tpPESession pe_session; + pe_session = pe_find_session_by_session_id(mac_ctx, pe_session_id); + + if (NULL == pe_session) { + lim_log(mac_ctx, LOGP, FL("Invalid PE session = %d"), + pe_session_id); + return; + } + lim_send_switch_chnl_params(mac_ctx, channel, ch_center_freq_seg0, + ch_center_freq_seg1, ch_width, + max_tx_power, pe_session_id, false); +} diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_process_mlm_rsp_messages.c b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_process_mlm_rsp_messages.c new file mode 100644 index 0000000000000000000000000000000000000000..b1c892c7711b08b6060204042df7e43804384233 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_process_mlm_rsp_messages.c @@ -0,0 +1,3413 @@ +/* + * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#include "wni_api.h" +#include "wni_cfg.h" +#include "cfg_api.h" +#include "sir_api.h" +#include "sch_api.h" +#include "utils_api.h" +#include "lim_utils.h" +#include "lim_assoc_utils.h" +#include "lim_security_utils.h" +#include "lim_ser_des_utils.h" +#include "lim_timer_utils.h" +#include "lim_send_messages.h" +#include "lim_admit_control.h" +#include "lim_send_messages.h" +#include "lim_ibss_peer_mgmt.h" +#include "lim_ft.h" +#include "lim_ft_defs.h" +#include "lim_session.h" +#include "lim_session_utils.h" +#include "rrm_api.h" +#include "wma_types.h" +#include "cds_utils.h" +#include "lim_types.h" +#include "cds_concurrency.h" +#include "nan_datapath.h" + +#define MAX_SUPPORTED_PEERS_WEP 16 + +void lim_process_mlm_join_cnf(tpAniSirGlobal, uint32_t *); +void lim_process_mlm_auth_cnf(tpAniSirGlobal, uint32_t *); +void lim_process_mlm_start_cnf(tpAniSirGlobal, uint32_t *); +void lim_process_mlm_assoc_ind(tpAniSirGlobal, uint32_t *); +void lim_process_mlm_assoc_cnf(tpAniSirGlobal, uint32_t *); +void lim_process_mlm_reassoc_ind(tpAniSirGlobal, uint32_t *); +void lim_process_mlm_set_keys_cnf(tpAniSirGlobal, uint32_t *); +void lim_process_mlm_disassoc_ind(tpAniSirGlobal, uint32_t *); +void lim_process_mlm_disassoc_cnf(tpAniSirGlobal, uint32_t *); +void lim_process_mlm_deauth_ind(tpAniSirGlobal, uint32_t *); +void lim_process_mlm_deauth_cnf(tpAniSirGlobal, uint32_t *); +void lim_process_mlm_purge_sta_ind(tpAniSirGlobal, uint32_t *); +void lim_get_session_info(tpAniSirGlobal pMac, uint8_t *, uint8_t *, + uint16_t *); +/** + * lim_process_mlm_rsp_messages() + * + ***FUNCTION: + * This function is called to processes various MLM response (CNF/IND + * messages from MLM State machine. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param pMac Pointer to Global MAC structure + * @param msgType Indicates the MLM message type + * @param *pMsgBuf A pointer to the MLM message buffer + * + * @return None + */ +void +lim_process_mlm_rsp_messages(tpAniSirGlobal pMac, uint32_t msgType, + uint32_t *pMsgBuf) +{ + + if (pMsgBuf == NULL) { + PELOGE(lim_log(pMac, LOGE, FL("Buffer is Pointing to NULL"));) + return; + } + MTRACE(mac_trace(pMac, TRACE_CODE_TX_LIM_MSG, 0, msgType)); + switch (msgType) { + case LIM_MLM_AUTH_CNF: + lim_process_mlm_auth_cnf(pMac, pMsgBuf); + break; + case LIM_MLM_ASSOC_CNF: + lim_process_mlm_assoc_cnf(pMac, pMsgBuf); + break; + case LIM_MLM_START_CNF: + lim_process_mlm_start_cnf(pMac, pMsgBuf); + break; + case LIM_MLM_JOIN_CNF: + lim_process_mlm_join_cnf(pMac, pMsgBuf); + break; + case LIM_MLM_ASSOC_IND: + lim_process_mlm_assoc_ind(pMac, pMsgBuf); + break; + case LIM_MLM_REASSOC_CNF: + lim_process_mlm_reassoc_cnf(pMac, pMsgBuf); + break; + case LIM_MLM_DISASSOC_CNF: + lim_process_mlm_disassoc_cnf(pMac, pMsgBuf); + break; + case LIM_MLM_DISASSOC_IND: + lim_process_mlm_disassoc_ind(pMac, pMsgBuf); + break; + case LIM_MLM_PURGE_STA_IND: + lim_process_mlm_purge_sta_ind(pMac, pMsgBuf); + break; + case LIM_MLM_DEAUTH_CNF: + lim_process_mlm_deauth_cnf(pMac, pMsgBuf); + break; + case LIM_MLM_DEAUTH_IND: + lim_process_mlm_deauth_ind(pMac, pMsgBuf); + break; + case LIM_MLM_SETKEYS_CNF: + lim_process_mlm_set_keys_cnf(pMac, pMsgBuf); + break; + case LIM_MLM_TSPEC_CNF: + break; + default: + break; + } /* switch (msgType) */ + return; +} /*** end lim_process_mlm_rsp_messages() ***/ + +/** + * lim_process_mlm_start_cnf() + * + ***FUNCTION: + * This function is called to processes MLM_START_CNF + * message from MLM State machine. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param pMac Pointer to Global MAC structure + * @param pMsgBuf A pointer to the MLM message buffer + * + * @return None + */ +void lim_process_mlm_start_cnf(tpAniSirGlobal pMac, uint32_t *pMsgBuf) +{ + tpPESession psessionEntry = NULL; + tLimMlmStartCnf *pLimMlmStartCnf; + uint8_t smesessionId; + uint16_t smetransactionId; + uint8_t channelId; + uint8_t send_bcon_ind = false; + + if (pMsgBuf == NULL) { + PELOGE(lim_log(pMac, LOGE, FL("Buffer is Pointing to NULL"));) + return; + } + pLimMlmStartCnf = (tLimMlmStartCnf *) pMsgBuf; + psessionEntry = pe_find_session_by_session_id(pMac, + pLimMlmStartCnf->sessionId); + if (psessionEntry == NULL) { + PELOGE(lim_log(pMac, LOGE, FL( + "Session does Not exist with given sessionId "));) + return; + } + smesessionId = psessionEntry->smeSessionId; + smetransactionId = psessionEntry->transactionId; + + if (psessionEntry->limSmeState != eLIM_SME_WT_START_BSS_STATE) { + /* + * Should not have received Start confirm from MLM + * in other states. Log error. + */ + PELOGE(lim_log(pMac, LOGE, FL + ("received unexpected MLM_START_CNF in state %X"), + psessionEntry->limSmeState);) + return; + } + if (((tLimMlmStartCnf *) pMsgBuf)->resultCode == eSIR_SME_SUCCESS) { + + /* + * Update global SME state so that Beacon Generation + * module starts writing Beacon frames into TFP's + * Beacon file register. + */ + psessionEntry->limSmeState = eLIM_SME_NORMAL_STATE; + MTRACE(mac_trace + (pMac, TRACE_CODE_SME_STATE, psessionEntry->peSessionId, + psessionEntry->limSmeState)); + if (psessionEntry->bssType == eSIR_INFRA_AP_MODE) + lim_log(pMac, LOG1, + FL("*** Started BSS in INFRA AP SIDE***")); + else if (psessionEntry->bssType == eSIR_NDI_MODE) + lim_log(pMac, LOG1, + FL("*** Started BSS in NDI mode ***")); + else + lim_log(pMac, LOG1, FL("*** Started BSS ***")); + } else { + /* Start BSS is a failure */ + pe_delete_session(pMac, psessionEntry); + psessionEntry = NULL; + PELOGE(lim_log(pMac, LOGE, FL("Start BSS Failed "));) + } + /* Send response to Host */ + lim_send_sme_start_bss_rsp(pMac, eWNI_SME_START_BSS_RSP, + ((tLimMlmStartCnf *)pMsgBuf)->resultCode, + psessionEntry, smesessionId, smetransactionId); + if ((psessionEntry != NULL) && + (((tLimMlmStartCnf *) pMsgBuf)->resultCode == + eSIR_SME_SUCCESS)) { + channelId = psessionEntry->pLimStartBssReq->channelId; + + /* We should start beacon transmission only if the channel + * on which we are operating is non-DFS until the channel + * availability check is done. The PE will receive an explicit + * request from upper layers to start the beacon transmission + */ + + if (!(LIM_IS_IBSS_ROLE(psessionEntry) || + (LIM_IS_AP_ROLE(psessionEntry)))) + return; + if (psessionEntry->ch_width == CH_WIDTH_160MHZ) { + send_bcon_ind = false; + } else if (psessionEntry->ch_width == CH_WIDTH_80P80MHZ) { + if ((cds_get_channel_state(channelId) != + CHANNEL_STATE_DFS) && + (cds_get_channel_state(psessionEntry-> + ch_center_freq_seg1 - + SIR_80MHZ_START_CENTER_CH_DIFF) != + CHANNEL_STATE_DFS)) + send_bcon_ind = true; + } else { + if (cds_get_channel_state(channelId) != + CHANNEL_STATE_DFS) + send_bcon_ind = true; + } + if (send_bcon_ind) { + /* Configure beacon and send beacons to HAL */ + QDF_TRACE(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_INFO, + FL("Start Beacon with ssid %s Ch %d"), + psessionEntry->ssId.ssId, + psessionEntry->currentOperChannel); + lim_send_beacon_ind(pMac, psessionEntry); + } + } +} + +/*** end lim_process_mlm_start_cnf() ***/ + +/** + * lim_process_mlm_join_cnf() - Processes join confirmation + * @mac_ctx: Pointer to Global MAC structure + * @msg: A pointer to the MLM message buffer + * + * This Function handles the join confirmation message + * LIM_MLM_JOIN_CNF. + * + * Return: None + */ +void lim_process_mlm_join_cnf(tpAniSirGlobal mac_ctx, + uint32_t *msg) +{ + tSirResultCodes result_code; + tLimMlmJoinCnf *join_cnf; + tpPESession session_entry; + + join_cnf = (tLimMlmJoinCnf *) msg; + session_entry = pe_find_session_by_session_id(mac_ctx, + join_cnf->sessionId); + if (session_entry == NULL) { + lim_log(mac_ctx, LOGE, FL("SessionId:%d does not exist"), + join_cnf->sessionId); + return; + } + + if (session_entry->limSmeState != eLIM_SME_WT_JOIN_STATE) { + lim_log(mac_ctx, LOGE, + FL("received unexpected MLM_JOIN_CNF in state %X"), + session_entry->limSmeState); + return; + } + + result_code = ((tLimMlmJoinCnf *) msg)->resultCode; + /* Process Join confirm from MLM */ + if (result_code == eSIR_SME_SUCCESS) { + lim_log(mac_ctx, LOG1, FL("***SessionId:%d Joined ESS ***"), + join_cnf->sessionId); + /* Setup hardware upfront */ + if (lim_sta_send_add_bss_pre_assoc(mac_ctx, false, + session_entry) == eSIR_SUCCESS) + return; + else + result_code = eSIR_SME_REFUSED; + } + + /* Join failure */ + session_entry->limSmeState = eLIM_SME_JOIN_FAILURE_STATE; + MTRACE(mac_trace(mac_ctx, TRACE_CODE_SME_STATE, + session_entry->peSessionId, + session_entry->limSmeState)); + /* Send Join response to Host */ + lim_handle_sme_join_result(mac_ctx, result_code, + ((tLimMlmJoinCnf *) msg)->protStatusCode, session_entry); + return; +} + +/** + * lim_send_mlm_assoc_req() - Association request will be processed + * mac_ctx: Pointer to Global MAC structure + * session_entry: Pointer to session etnry + * + * This function is sends ASSOC request MLM message to MLM State machine. + * ASSOC request packet would be by picking parameters from psessionEntry + * automatically based on the current state of MLM state machine. + * ASSUMPTIONS: + * this function is called in middle of connection state machine and is + * expected to be called after auth cnf has been received or after ASSOC rsp + * with TRY_AGAIN_LATER was received and required time has elapsed after that. + * + * Return: None + */ + +static void lim_send_mlm_assoc_req(tpAniSirGlobal mac_ctx, + tpPESession session_entry) +{ + tLimMlmAssocReq *assoc_req; + uint32_t val; + uint16_t caps; + uint32_t tele_bcn = 0; + tpSirMacCapabilityInfo cap_info; + + /* Successful MAC based authentication. Trigger Association with BSS */ + lim_log(mac_ctx, LOG1, FL("SessionId:%d Authenticated with BSS"), + session_entry->peSessionId); + + if (NULL == session_entry->pLimJoinReq) { + lim_log(mac_ctx, LOGE, FL("Join Request is NULL.")); + /* No need to Assert. JOIN timeout will handle this error */ + return; + } + + assoc_req = qdf_mem_malloc(sizeof(tLimMlmAssocReq)); + if (NULL == assoc_req) { + lim_log(mac_ctx, LOGP, + FL("call to AllocateMemory failed for mlmAssocReq")); + return; + } + val = sizeof(tSirMacAddr); + sir_copy_mac_addr(assoc_req->peerMacAddr, session_entry->bssId); + if (wlan_cfg_get_int(mac_ctx, WNI_CFG_ASSOCIATION_FAILURE_TIMEOUT, + (uint32_t *) &assoc_req->assocFailureTimeout) + != eSIR_SUCCESS) { + /* Could not get AssocFailureTimeout value from CFG.*/ + lim_log(mac_ctx, LOGP, + FL("could not retrieve AssocFailureTimeout value")); + } + + if (cfg_get_capability_info(mac_ctx, &caps, session_entry) + != eSIR_SUCCESS) + /* Could not get Capabilities value from CFG.*/ + lim_log(mac_ctx, LOGP, + FL("could not retrieve Capabilities value")); + + /* Clear spectrum management bit if AP doesn't support it */ + if (!(session_entry->pLimJoinReq->bssDescription.capabilityInfo & + LIM_SPECTRUM_MANAGEMENT_BIT_MASK)) + /* + * AP doesn't support spectrum management + * clear spectrum management bit + */ + caps &= (~LIM_SPECTRUM_MANAGEMENT_BIT_MASK); + + /* Clear rrm bit if AP doesn't support it */ + if (!(session_entry->pLimJoinReq->bssDescription.capabilityInfo & + LIM_RRM_BIT_MASK)) + caps &= (~LIM_RRM_BIT_MASK); + + /* Clear short preamble bit if AP does not support it */ + if (!(session_entry->pLimJoinReq->bssDescription.capabilityInfo & + (LIM_SHORT_PREAMBLE_BIT_MASK))) { + caps &= (~LIM_SHORT_PREAMBLE_BIT_MASK); + lim_log(mac_ctx, LOG1, + FL("Clearing short preamble:no AP support")); + } + + /* Clear immediate block ack bit if AP does not support it */ + if (!(session_entry->pLimJoinReq->bssDescription.capabilityInfo & + (LIM_IMMEDIATE_BLOCK_ACK_MASK))) { + caps &= (~LIM_IMMEDIATE_BLOCK_ACK_MASK); + lim_log(mac_ctx, LOG1, + FL("Clearing Immed Blk Ack:no AP support")); + } + + assoc_req->capabilityInfo = caps; + cap_info = ((tpSirMacCapabilityInfo) &assoc_req->capabilityInfo); + lim_log(mac_ctx, LOG3, FL("Capabilities to be used in AssocReq=0x%X," + "privacy bit=%x shortSlotTime %x"), caps, + cap_info->privacy, + cap_info->shortSlotTime); + + /* + * If telescopic beaconing is enabled, set listen interval to + * WNI_CFG_TELE_BCN_MAX_LI + */ + if (wlan_cfg_get_int(mac_ctx, WNI_CFG_TELE_BCN_WAKEUP_EN, &tele_bcn) + != eSIR_SUCCESS) + lim_log(mac_ctx, LOGP, + FL("Couldn't get WNI_CFG_TELE_BCN_WAKEUP_EN")); + + val = WNI_CFG_LISTEN_INTERVAL_STADEF; + if (tele_bcn) { + if (wlan_cfg_get_int(mac_ctx, WNI_CFG_TELE_BCN_MAX_LI, &val) != + eSIR_SUCCESS) + /* + * Could not get ListenInterval value + * from CFG. Log error. + */ + lim_log(mac_ctx, LOGP, + FL("could not retrieve ListenInterval")); + } else { + if (wlan_cfg_get_int(mac_ctx, WNI_CFG_LISTEN_INTERVAL, + &val) != eSIR_SUCCESS) + /* + * Could not get ListenInterval value + * from CFG. Log error. + */ + lim_log(mac_ctx, LOGP, + FL("could not retrieve ListenInterval")); + } +#ifdef FEATURE_WLAN_DIAG_SUPPORT + lim_diag_event_report(mac_ctx, WLAN_PE_DIAG_ASSOC_REQ_EVENT, + session_entry, eSIR_SUCCESS, eSIR_SUCCESS); +#endif + assoc_req->listenInterval = (uint16_t) val; + /* Update PE session ID */ + assoc_req->sessionId = session_entry->peSessionId; + session_entry->limPrevSmeState = session_entry->limSmeState; + session_entry->limSmeState = eLIM_SME_WT_ASSOC_STATE; + MTRACE(mac_trace(mac_ctx, TRACE_CODE_SME_STATE, + session_entry->peSessionId, session_entry->limSmeState)); + lim_post_mlm_message(mac_ctx, LIM_MLM_ASSOC_REQ, + (uint32_t *) assoc_req); +} + +#ifdef WLAN_FEATURE_11W +/** + * lim_pmf_comeback_timer_callback() -PMF callback handler + * @context: Timer context + * + * This function is called to processes the PMF comeback + * callback + * + * Return: None + */ +void lim_pmf_comeback_timer_callback(void *context) +{ + tComebackTimerInfo *info = (tComebackTimerInfo *) context; + tpAniSirGlobal mac_ctx = info->pMac; + tpPESession psessionEntry = &mac_ctx->lim.gpSession[info->sessionID]; + + lim_log(mac_ctx, LOGE, + FL("comeback later timer expired. sending MLM ASSOC req")); + /* set MLM state such that ASSOC REQ packet will be sent out */ + psessionEntry->limPrevMlmState = info->limPrevMlmState; + psessionEntry->limMlmState = info->limMlmState; + lim_send_mlm_assoc_req(mac_ctx, psessionEntry); +} +#endif /* WLAN_FEATURE_11W */ + +/** + * lim_process_mlm_auth_cnf()-Process Auth confirmation + * @mac_ctx: Pointer to Global MAC structure + * @msg: A pointer to the MLM message buffer + * + * This function is called to processes MLM_AUTH_CNF + * message from MLM State machine. + * + * Return: None + */ +void lim_process_mlm_auth_cnf(tpAniSirGlobal mac_ctx, uint32_t *msg) +{ + tAniAuthType auth_type, auth_mode; + tLimMlmAuthReq *auth_req; + tLimMlmAuthCnf *auth_cnf; + tpPESession session_entry; + + if (msg == NULL) { + lim_log(mac_ctx, LOGE, FL("Buffer is Pointing to NULL")); + return; + } + auth_cnf = (tLimMlmAuthCnf *) msg; + session_entry = pe_find_session_by_session_id(mac_ctx, + auth_cnf->sessionId); + if (session_entry == NULL) { + lim_log(mac_ctx, LOGE, FL("SessionId:%d session doesn't exist"), + auth_cnf->sessionId); + return; + } + + if ((session_entry->limSmeState != eLIM_SME_WT_AUTH_STATE && + session_entry->limSmeState != eLIM_SME_WT_PRE_AUTH_STATE) || + LIM_IS_AP_ROLE(session_entry)) { + /** + * Should not have received AUTH confirm + * from MLM in other states or on AP. + * Log error + */ + lim_log(mac_ctx, LOGE, + FL("SessionId:%d received MLM_AUTH_CNF in state %X"), + session_entry->peSessionId, session_entry->limSmeState); + return; + } + + if (auth_cnf->resultCode == eSIR_SME_SUCCESS) { + if (session_entry->limSmeState == eLIM_SME_WT_AUTH_STATE) { + lim_send_mlm_assoc_req(mac_ctx, session_entry); + } else { + /* + * Successful Pre-authentication. Send + * Pre-auth response to host + */ + session_entry->limSmeState = + session_entry->limPrevSmeState; + MTRACE(mac_trace + (mac_ctx, TRACE_CODE_SME_STATE, + session_entry->peSessionId, + session_entry->limSmeState)); + } + /* Return for success case */ + return; + } + /* + * Failure case handle: + * Process AUTH confirm from MLM + */ + if (session_entry->limSmeState == eLIM_SME_WT_AUTH_STATE) { + if (wlan_cfg_get_int(mac_ctx, WNI_CFG_AUTHENTICATION_TYPE, + (uint32_t *) &auth_type) != eSIR_SUCCESS) { + /* + * Could not get AuthType value from CFG. + * Log error. + */ + lim_log(mac_ctx, LOGP, + FL("Fail to retrieve AuthType value")); + } + } else { + auth_type = mac_ctx->lim.gLimPreAuthType; + } + + if ((auth_type == eSIR_AUTO_SWITCH) && + (auth_cnf->authType == eSIR_SHARED_KEY) && + ((eSIR_MAC_AUTH_ALGO_NOT_SUPPORTED_STATUS == + auth_cnf->protStatusCode) || + (auth_cnf->resultCode == eSIR_SME_AUTH_TIMEOUT_RESULT_CODE))) { + /* + * When shared authentication fails with reason + * code "13" and authType set to 'auto switch', + * Try with open Authentication + */ + auth_mode = eSIR_OPEN_SYSTEM; + /* Trigger MAC based Authentication */ + auth_req = qdf_mem_malloc(sizeof(tLimMlmAuthReq)); + if (NULL == auth_req) { + /* Log error */ + lim_log(mac_ctx, LOGP, + FL("mlmAuthReq :Memory alloc failed ")); + return; + } + if (session_entry->limSmeState == + eLIM_SME_WT_AUTH_STATE) { + sir_copy_mac_addr(auth_req->peerMacAddr, + session_entry->bssId); + } else { + qdf_mem_copy((uint8_t *)&auth_req->peerMacAddr, + (uint8_t *)&mac_ctx->lim.gLimPreAuthPeerAddr, + sizeof(tSirMacAddr)); + } + auth_req->authType = auth_mode; + /* Update PE session Id */ + auth_req->sessionId = auth_cnf->sessionId; + if (wlan_cfg_get_int(mac_ctx, + WNI_CFG_AUTHENTICATE_FAILURE_TIMEOUT, + (uint32_t *) &auth_req->authFailureTimeout) + != eSIR_SUCCESS) { + /* + * Could not get AuthFailureTimeout value from CFG. + * Log error. + */ + lim_log(mac_ctx, LOGP, + FL("Fail:retrieve AuthFailureTimeout ")); + } + lim_post_mlm_message(mac_ctx, LIM_MLM_AUTH_REQ, + (uint32_t *) auth_req); + return; + } else { + /* MAC based authentication failure */ + if (session_entry->limSmeState == + eLIM_SME_WT_AUTH_STATE) { + lim_log(mac_ctx, LOGE, + FL("Auth Failure occurred.")); + session_entry->limSmeState = + eLIM_SME_JOIN_FAILURE_STATE; + MTRACE(mac_trace(mac_ctx, TRACE_CODE_SME_STATE, + session_entry->peSessionId, + session_entry->limSmeState)); + session_entry->limMlmState = + eLIM_MLM_IDLE_STATE; + MTRACE(mac_trace(mac_ctx, TRACE_CODE_MLM_STATE, + session_entry->peSessionId, + session_entry->limMlmState)); + /* + * Need to send Join response with + * auth failure to Host. + */ + lim_handle_sme_join_result(mac_ctx, + auth_cnf->resultCode, + auth_cnf->protStatusCode, + session_entry); + } else { + /* + * Pre-authentication failure. + * Send Pre-auth failure response to host + */ + session_entry->limSmeState = + session_entry->limPrevSmeState; + MTRACE(mac_trace(mac_ctx, TRACE_CODE_SME_STATE, + session_entry->peSessionId, + session_entry->limSmeState)); + } + } +} + +/** + * lim_process_mlm_assoc_cnf() - Process association confirmation + * @mac_ctx: Pointer to Global MAC structure + * @msg: A pointer to the MLM message buffer + * + * This function is called to processes MLM_ASSOC_CNF + * message from MLM State machine. + * + * Return: None + */ +void lim_process_mlm_assoc_cnf(tpAniSirGlobal mac_ctx, + uint32_t *msg) +{ + tpPESession session_entry; + tLimMlmAssocCnf *assoc_cnf; + + if (msg == NULL) { + lim_log(mac_ctx, LOGE, FL("Buffer is Pointing to NULL")); + return; + } + assoc_cnf = (tLimMlmAssocCnf *) msg; + session_entry = pe_find_session_by_session_id(mac_ctx, + assoc_cnf->sessionId); + if (session_entry == NULL) { + lim_log(mac_ctx, LOGE, + FL("SessionId:%d Session does not exist"), + assoc_cnf->sessionId); + return; + } + if (session_entry->limSmeState != eLIM_SME_WT_ASSOC_STATE || + LIM_IS_AP_ROLE(session_entry)) { + /* + * Should not have received Assocication confirm + * from MLM in other states OR on AP. + * Log error + */ + lim_log(mac_ctx, LOGE, + FL("SessionId:%d Received MLM_ASSOC_CNF in state %X"), + session_entry->peSessionId, session_entry->limSmeState); + return; + } + if (((tLimMlmAssocCnf *) msg)->resultCode != eSIR_SME_SUCCESS) { + /* Association failure */ + lim_log(mac_ctx, LOG1, FL("SessionId:%d Association failure resultCode: %d limSmeState:%d"), + session_entry->peSessionId, + ((tLimMlmAssocCnf *) msg)->resultCode, + session_entry->limSmeState); + + /* If driver gets deauth when its waiting for ADD_STA_RSP then + * we need to do DEL_STA followed by DEL_BSS. So based on below + * reason-code here we decide whether to do only DEL_BSS or + * DEL_STA + DEL_BSS. + */ + if (((tLimMlmAssocCnf *) msg)->resultCode != + eSIR_SME_JOIN_DEAUTH_FROM_AP_DURING_ADD_STA) + session_entry->limSmeState = + eLIM_SME_JOIN_FAILURE_STATE; + + MTRACE(mac_trace(mac_ctx, TRACE_CODE_SME_STATE, + session_entry->peSessionId, mac_ctx->lim.gLimSmeState)); + /* + * Need to send Join response with + * Association failure to Host. + */ + lim_handle_sme_join_result(mac_ctx, + ((tLimMlmAssocCnf *) msg)->resultCode, + ((tLimMlmAssocCnf *) msg)->protStatusCode, + session_entry); + } else { + /* Successful Association */ + lim_log(mac_ctx, LOG1, FL("SessionId:%d Associated with BSS"), + session_entry->peSessionId); + session_entry->limSmeState = eLIM_SME_LINK_EST_STATE; + MTRACE(mac_trace(mac_ctx, TRACE_CODE_SME_STATE, + session_entry->peSessionId, + session_entry->limSmeState)); + /** + * Need to send Join response with + * Association success to Host. + */ + lim_handle_sme_join_result(mac_ctx, + ((tLimMlmAssocCnf *) msg)->resultCode, + ((tLimMlmAssocCnf *) msg)->protStatusCode, + session_entry); + } +} + +/** + * lim_fill_assoc_ind_params() - Initialize association indication + * mac_ctx: Pointer to Global MAC structure + * assoc_ind: PE association indication structure + * sme_assoc_ind: SME association indication + * session_entry: PE session entry + * + * This function is called to initialzie the association + * indication strucutre to process association indication. + * + * Return: None + */ + +static void +lim_fill_assoc_ind_params(tpAniSirGlobal mac_ctx, + tpLimMlmAssocInd assoc_ind, tSirSmeAssocInd *sme_assoc_ind, + tpPESession session_entry) +{ + sme_assoc_ind->length = sizeof(tSirSmeAssocInd); + sme_assoc_ind->sessionId = session_entry->smeSessionId; + + /* Required for indicating the frames to upper layer */ + sme_assoc_ind->assocReqLength = assoc_ind->assocReqLength; + sme_assoc_ind->assocReqPtr = assoc_ind->assocReqPtr; + + sme_assoc_ind->beaconPtr = session_entry->beacon; + sme_assoc_ind->beaconLength = session_entry->bcnLen; + + /* Fill in peerMacAddr */ + qdf_mem_copy(sme_assoc_ind->peerMacAddr, assoc_ind->peerMacAddr, + sizeof(tSirMacAddr)); + + /* Fill in aid */ + sme_assoc_ind->aid = assoc_ind->aid; + /* Fill in bssId */ + qdf_mem_copy(sme_assoc_ind->bssId, session_entry->bssId, + sizeof(tSirMacAddr)); + /* Fill in authType */ + sme_assoc_ind->authType = assoc_ind->authType; + /* Fill in ssId */ + qdf_mem_copy((uint8_t *) &sme_assoc_ind->ssId, + (uint8_t *) &(assoc_ind->ssId), assoc_ind->ssId.length + 1); + sme_assoc_ind->rsnIE.length = assoc_ind->rsnIE.length; + qdf_mem_copy((uint8_t *) &sme_assoc_ind->rsnIE.rsnIEdata, + (uint8_t *) &(assoc_ind->rsnIE.rsnIEdata), + assoc_ind->rsnIE.length); + +#ifdef FEATURE_WLAN_WAPI + sme_assoc_ind->wapiIE.length = assoc_ind->wapiIE.length; + qdf_mem_copy((uint8_t *) &sme_assoc_ind->wapiIE.wapiIEdata, + (uint8_t *) &(assoc_ind->wapiIE.wapiIEdata), + assoc_ind->wapiIE.length); +#endif + sme_assoc_ind->addIE.length = assoc_ind->addIE.length; + qdf_mem_copy((uint8_t *) &sme_assoc_ind->addIE.addIEdata, + (uint8_t *) &(assoc_ind->addIE.addIEdata), + assoc_ind->addIE.length); + + /* Copy the new TITAN capabilities */ + sme_assoc_ind->spectrumMgtIndicator = assoc_ind->spectrumMgtIndicator; + if (assoc_ind->spectrumMgtIndicator == eSIR_TRUE) { + sme_assoc_ind->powerCap.minTxPower = + assoc_ind->powerCap.minTxPower; + sme_assoc_ind->powerCap.maxTxPower = + assoc_ind->powerCap.maxTxPower; + sme_assoc_ind->supportedChannels.numChnl = + assoc_ind->supportedChannels.numChnl; + qdf_mem_copy((uint8_t *) &sme_assoc_ind->supportedChannels. + channelList, + (uint8_t *) &(assoc_ind->supportedChannels.channelList), + assoc_ind->supportedChannels.numChnl); + } + qdf_mem_copy(&sme_assoc_ind->chan_info, &assoc_ind->chan_info, + sizeof(tSirSmeChanInfo)); + /* Fill in WmmInfo */ + sme_assoc_ind->wmmEnabledSta = assoc_ind->WmmStaInfoPresent; +} + +/** + * lim_process_mlm_assoc_ind() + * + ***FUNCTION: + * This function is called to processes MLM_ASSOC_IND + * message from MLM State machine. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param pMac Pointer to Global MAC structure + * @param pMsgBuf A pointer to the MLM message buffer + * + * @return None + */ +void lim_process_mlm_assoc_ind(tpAniSirGlobal pMac, uint32_t *pMsgBuf) +{ + uint32_t len; + cds_msg_t msg; + tSirSmeAssocInd *pSirSmeAssocInd; + tpDphHashNode pStaDs = 0; + tpPESession psessionEntry; + if (pMsgBuf == NULL) { + PELOGE(lim_log(pMac, LOGE, FL("Buffer is Pointing to NULL"));) + return; + } + psessionEntry = pe_find_session_by_session_id(pMac, + ((tpLimMlmAssocInd) pMsgBuf)-> + sessionId); + if (psessionEntry == NULL) { + lim_log(pMac, LOGE, + FL("Session Does not exist for given sessionId")); + return; + } + /* / Inform Host of STA association */ + len = sizeof(tSirSmeAssocInd); + pSirSmeAssocInd = qdf_mem_malloc(len); + if (NULL == pSirSmeAssocInd) { + /* Log error */ + lim_log(pMac, LOGP, + FL + ("call to AllocateMemory failed for eWNI_SME_ASSOC_IND")); + return; + } + + pSirSmeAssocInd->messageType = eWNI_SME_ASSOC_IND; + lim_fill_assoc_ind_params(pMac, (tpLimMlmAssocInd) pMsgBuf, pSirSmeAssocInd, + psessionEntry); + msg.type = eWNI_SME_ASSOC_IND; + msg.bodyptr = pSirSmeAssocInd; + msg.bodyval = 0; + pStaDs = dph_get_hash_entry(pMac, + ((tpLimMlmAssocInd) pMsgBuf)->aid, + &psessionEntry->dph.dphHashTable); + if (!pStaDs) { /* good time to panic... */ + lim_log(pMac, LOGE, + FL + ("MLM AssocInd: Station context no longer valid (aid %d)"), + ((tpLimMlmAssocInd) pMsgBuf)->aid); + qdf_mem_free(pSirSmeAssocInd); + + return; + } + pSirSmeAssocInd->staId = pStaDs->staIndex; + pSirSmeAssocInd->reassocReq = pStaDs->mlmStaContext.subType; + pSirSmeAssocInd->timingMeasCap = pStaDs->timingMeasCap; + MTRACE(mac_trace(pMac, TRACE_CODE_TX_SME_MSG, + psessionEntry->peSessionId, msg.type)); +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM /* FEATURE_WLAN_DIAG_SUPPORT */ + lim_diag_event_report(pMac, WLAN_PE_DIAG_ASSOC_IND_EVENT, psessionEntry, 0, + 0); +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + pe_debug("Create CNF_WAIT_TIMER after received LIM_MLM_ASSOC_IND"); + /* + ** turn on a timer to detect the loss of ASSOC CNF + **/ + lim_activate_cnf_timer(pMac, + (uint16_t) ((tpLimMlmAssocInd) pMsgBuf)->aid, + psessionEntry); + + pMac->lim.sme_msg_callback(pMac, &msg); +} /*** end lim_process_mlm_assoc_ind() ***/ + +/** + * lim_process_mlm_disassoc_ind() + * + ***FUNCTION: + * This function is called to processes MLM_DISASSOC_IND + * message from MLM State machine. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param pMac Pointer to Global MAC structure + * @param pMsgBuf A pointer to the MLM message buffer + * + * @return None + */ +void lim_process_mlm_disassoc_ind(tpAniSirGlobal pMac, uint32_t *pMsgBuf) +{ + tLimMlmDisassocInd *pMlmDisassocInd; + tpPESession psessionEntry; + pMlmDisassocInd = (tLimMlmDisassocInd *) pMsgBuf; + psessionEntry = pe_find_session_by_session_id(pMac, + pMlmDisassocInd->sessionId); + if (psessionEntry == NULL) { + lim_log(pMac, LOGP, + FL("Session Does not exist for given sessionID")); + return; + } + switch (GET_LIM_SYSTEM_ROLE(psessionEntry)) { + case eLIM_STA_IN_IBSS_ROLE: + break; + case eLIM_STA_ROLE: + psessionEntry->limSmeState = eLIM_SME_WT_DISASSOC_STATE; + MTRACE(mac_trace + (pMac, TRACE_CODE_SME_STATE, psessionEntry->peSessionId, + psessionEntry->limSmeState)); + break; + default: /* eLIM_AP_ROLE */ + PELOG1(lim_log(pMac, LOG1, + FL("*** Peer staId=%d Disassociated ***"), + pMlmDisassocInd->aid); + ) + /* Send SME_DISASOC_IND after Polaris cleanup */ + /* (after receiving LIM_MLM_PURGE_STA_IND) */ + break; + } /* end switch (GET_LIM_SYSTEM_ROLE(psessionEntry)) */ +} /*** end lim_process_mlm_disassoc_ind() ***/ + +/** + * lim_process_mlm_disassoc_cnf() - Processes disassociation + * @mac_ctx: Pointer to Global MAC structure + * @msg: A pointer to the MLM message buffer + * + * This function is called to processes MLM_DISASSOC_CNF + * message from MLM State machine. + * + * Return: None + */ +void lim_process_mlm_disassoc_cnf(tpAniSirGlobal mac_ctx, + uint32_t *msg) +{ + tSirResultCodes result_code; + tLimMlmDisassocCnf *disassoc_cnf; + tpPESession session_entry; + disassoc_cnf = (tLimMlmDisassocCnf *) msg; + + session_entry = + pe_find_session_by_session_id(mac_ctx, disassoc_cnf->sessionId); + if (session_entry == NULL) { + lim_log(mac_ctx, LOGE, + FL("session Does not exist for given session Id")); + return; + } + result_code = (tSirResultCodes)(disassoc_cnf->disassocTrigger == + eLIM_LINK_MONITORING_DISASSOC) ? + eSIR_SME_LOST_LINK_WITH_PEER_RESULT_CODE : + disassoc_cnf->resultCode; + if (LIM_IS_STA_ROLE(session_entry)) { + /* Disassociate Confirm from MLM */ + if ((session_entry->limSmeState != eLIM_SME_WT_DISASSOC_STATE) + && (session_entry->limSmeState != + eLIM_SME_WT_DEAUTH_STATE)) { + /* + * Should not have received + * Disassocate confirm + * from MLM in other states.Log error + */ + lim_log(mac_ctx, LOGE, + FL("received MLM_DISASSOC_CNF in state %X"), + session_entry->limSmeState); + return; + } + if (mac_ctx->lim.gLimRspReqd) + mac_ctx->lim.gLimRspReqd = false; + if (disassoc_cnf->disassocTrigger == + eLIM_PROMISCUOUS_MODE_DISASSOC) { + if (disassoc_cnf->resultCode != eSIR_SME_SUCCESS) + session_entry->limSmeState = + session_entry->limPrevSmeState; + else + session_entry->limSmeState = + eLIM_SME_OFFLINE_STATE; + MTRACE(mac_trace + (mac_ctx, TRACE_CODE_SME_STATE, + session_entry->peSessionId, + session_entry->limSmeState)); + } else { + if (disassoc_cnf->resultCode != eSIR_SME_SUCCESS) + session_entry->limSmeState = + session_entry->limPrevSmeState; + else + session_entry->limSmeState = + eLIM_SME_IDLE_STATE; + MTRACE(mac_trace(mac_ctx, TRACE_CODE_SME_STATE, + session_entry->peSessionId, + session_entry->limSmeState)); + lim_send_sme_disassoc_ntf(mac_ctx, + disassoc_cnf->peerMacAddr, result_code, + disassoc_cnf->disassocTrigger, + disassoc_cnf->aid, session_entry->smeSessionId, + session_entry->transactionId, session_entry); + } + } else if (LIM_IS_AP_ROLE(session_entry)) { + lim_send_sme_disassoc_ntf(mac_ctx, disassoc_cnf->peerMacAddr, + result_code, disassoc_cnf->disassocTrigger, + disassoc_cnf->aid, session_entry->smeSessionId, + session_entry->transactionId, session_entry); + } +} + +/** + * lim_process_mlm_deauth_ind() + * + ***FUNCTION: + * This function is called to processes MLM_DEAUTH_IND + * message from MLM State machine. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param pMac Pointer to Global MAC structure + * @param pMsgBuf A pointer to the MLM message buffer + * + * @return None + */ +void lim_process_mlm_deauth_ind(tpAniSirGlobal pMac, uint32_t *pMsgBuf) +{ + tLimMlmDeauthInd *pMlmDeauthInd; + tpPESession psessionEntry; + uint8_t sessionId; + pMlmDeauthInd = (tLimMlmDeauthInd *) pMsgBuf; + psessionEntry = pe_find_session_by_bssid(pMac, + pMlmDeauthInd->peerMacAddr, &sessionId); + if (psessionEntry == NULL) { + lim_log(pMac, LOGE, + FL("session does not exist for Addr:" MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(pMlmDeauthInd->peerMacAddr)); + return; + } + switch (GET_LIM_SYSTEM_ROLE(psessionEntry)) { + case eLIM_STA_IN_IBSS_ROLE: + break; + case eLIM_STA_ROLE: + psessionEntry->limSmeState = eLIM_SME_WT_DEAUTH_STATE; + MTRACE(mac_trace + (pMac, TRACE_CODE_SME_STATE, psessionEntry->peSessionId, + psessionEntry->limSmeState)); + + default: /* eLIM_AP_ROLE */ + { + PELOG1(lim_log(pMac, LOG1, + FL + ("*** Received Deauthentication from staId=%d ***"), + pMlmDeauthInd->aid); + ) + } + /* Send SME_DEAUTH_IND after Polaris cleanup */ + /* (after receiving LIM_MLM_PURGE_STA_IND) */ + break; + } /* end switch (GET_LIM_SYSTEM_ROLE(psessionEntry)) */ +} /*** end lim_process_mlm_deauth_ind() ***/ + +/** + * lim_process_mlm_deauth_cnf() + * + ***FUNCTION: + * This function is called to processes MLM_DEAUTH_CNF + * message from MLM State machine. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param pMac Pointer to Global MAC structure + * @param pMsgBuf A pointer to the MLM message buffer + * + * @return None + */ +void lim_process_mlm_deauth_cnf(tpAniSirGlobal pMac, uint32_t *pMsgBuf) +{ + uint16_t aid; + tSirResultCodes resultCode; + tLimMlmDeauthCnf *pMlmDeauthCnf; + tpPESession psessionEntry; + + if (pMsgBuf == NULL) { + PELOGE(lim_log(pMac, LOGE, FL("Buffer is Pointing to NULL"));) + return; + } + pMlmDeauthCnf = (tLimMlmDeauthCnf *) pMsgBuf; + psessionEntry = pe_find_session_by_session_id(pMac, + pMlmDeauthCnf->sessionId); + if (psessionEntry == NULL) { + PELOGE(lim_log + (pMac, LOGE, + FL("session does not exist for given session Id ")); + ) + return; + } + + resultCode = (tSirResultCodes) + (pMlmDeauthCnf->deauthTrigger == + eLIM_LINK_MONITORING_DEAUTH) ? + eSIR_SME_LOST_LINK_WITH_PEER_RESULT_CODE : + pMlmDeauthCnf->resultCode; + aid = LIM_IS_AP_ROLE(psessionEntry) ? pMlmDeauthCnf->aid : 1; + if (LIM_IS_STA_ROLE(psessionEntry)) { + /* Deauth Confirm from MLM */ + if ((psessionEntry->limSmeState != eLIM_SME_WT_DISASSOC_STATE) + && psessionEntry->limSmeState != + eLIM_SME_WT_DEAUTH_STATE) { + /** + * Should not have received Deauth confirm + * from MLM in other states. + * Log error + */ + PELOGE(lim_log(pMac, LOGE, + FL + ("received unexpected MLM_DEAUTH_CNF in state %X"), + psessionEntry->limSmeState);) + return; + } + if (pMlmDeauthCnf->resultCode == eSIR_SME_SUCCESS) { + psessionEntry->limSmeState = eLIM_SME_IDLE_STATE; + PELOG1(lim_log(pMac, LOG1, + FL("*** Deauthenticated with BSS ***"));) + } else + psessionEntry->limSmeState = + psessionEntry->limPrevSmeState; + MTRACE(mac_trace + (pMac, TRACE_CODE_SME_STATE, psessionEntry->peSessionId, + psessionEntry->limSmeState)); + + if (pMac->lim.gLimRspReqd) + pMac->lim.gLimRspReqd = false; + } + /* On STA or on BASIC AP, send SME_DEAUTH_RSP to host */ + lim_send_sme_deauth_ntf(pMac, pMlmDeauthCnf->peer_macaddr.bytes, + resultCode, + pMlmDeauthCnf->deauthTrigger, + aid, psessionEntry->smeSessionId, + psessionEntry->transactionId); +} /*** end lim_process_mlm_deauth_cnf() ***/ + +/** + * lim_process_mlm_purge_sta_ind() + * + ***FUNCTION: + * This function is called to processes MLM_PURGE_STA_IND + * message from MLM State machine. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param pMac Pointer to Global MAC structure + * @param pMsgBuf A pointer to the MLM message buffer + * + * @return None + */ +void lim_process_mlm_purge_sta_ind(tpAniSirGlobal pMac, uint32_t *pMsgBuf) +{ + tSirResultCodes resultCode; + tpLimMlmPurgeStaInd pMlmPurgeStaInd; + tpPESession psessionEntry; + if (pMsgBuf == NULL) { + PELOGE(lim_log(pMac, LOGE, FL("Buffer is Pointing to NULL"));) + return; + } + pMlmPurgeStaInd = (tpLimMlmPurgeStaInd) pMsgBuf; + psessionEntry = pe_find_session_by_session_id(pMac, + pMlmPurgeStaInd->sessionId); + if (psessionEntry == NULL) { + PELOGE(lim_log + (pMac, LOGE, + FL("session does not exist for given bssId")); + ) + return; + } + /* Purge STA indication from MLM */ + resultCode = (tSirResultCodes) pMlmPurgeStaInd->reasonCode; + switch (GET_LIM_SYSTEM_ROLE(psessionEntry)) { + case eLIM_STA_IN_IBSS_ROLE: + break; + case eLIM_STA_ROLE: + default: /* eLIM_AP_ROLE */ + if (LIM_IS_STA_ROLE(psessionEntry) && + (psessionEntry->limSmeState != + eLIM_SME_WT_DISASSOC_STATE) && + (psessionEntry->limSmeState != eLIM_SME_WT_DEAUTH_STATE)) { + /** + * Should not have received + * Purge STA indication + * from MLM in other states. + * Log error + */ + PELOGE(lim_log(pMac, LOGE, + FL + ("received unexpected MLM_PURGE_STA_IND in state %X"), + psessionEntry->limSmeState); + ) + break; + } + PELOG1(lim_log(pMac, LOG1, + FL("*** Cleanup completed for staId=%d ***"), + pMlmPurgeStaInd->aid); + ) + if (LIM_IS_STA_ROLE(psessionEntry)) { + psessionEntry->limSmeState = eLIM_SME_IDLE_STATE; + MTRACE(mac_trace + (pMac, TRACE_CODE_SME_STATE, + psessionEntry->peSessionId, + psessionEntry->limSmeState)); + + } + if (pMlmPurgeStaInd->purgeTrigger == eLIM_PEER_ENTITY_DEAUTH) { + lim_send_sme_deauth_ntf(pMac, + pMlmPurgeStaInd->peerMacAddr, + resultCode, + pMlmPurgeStaInd->purgeTrigger, + pMlmPurgeStaInd->aid, + psessionEntry->smeSessionId, + psessionEntry->transactionId); + } else + lim_send_sme_disassoc_ntf(pMac, + pMlmPurgeStaInd->peerMacAddr, + resultCode, + pMlmPurgeStaInd->purgeTrigger, + pMlmPurgeStaInd->aid, + psessionEntry->smeSessionId, + psessionEntry->transactionId, + psessionEntry); + } /* end switch (GET_LIM_SYSTEM_ROLE(psessionEntry)) */ +} /*** end lim_process_mlm_purge_sta_ind() ***/ + +/** + * lim_process_mlm_set_keys_cnf() + * + ***FUNCTION: + * This function is called to processes MLM_SETKEYS_CNF + * message from MLM State machine. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param pMac Pointer to Global MAC structure + * @param pMsgBuf A pointer to the MLM message buffer + * + * @return None + */ +void lim_process_mlm_set_keys_cnf(tpAniSirGlobal pMac, uint32_t *pMsgBuf) +{ + /* Prepare and send SME_SETCONTEXT_RSP message */ + tLimMlmSetKeysCnf *pMlmSetKeysCnf; + tpPESession psessionEntry; + uint16_t aid; + tpDphHashNode sta_ds; + + if (pMsgBuf == NULL) { + PELOGE(lim_log(pMac, LOGE, FL("Buffer is Pointing to NULL"));) + return; + } + pMlmSetKeysCnf = (tLimMlmSetKeysCnf *) pMsgBuf; + psessionEntry = pe_find_session_by_session_id(pMac, + pMlmSetKeysCnf->sessionId); + if (psessionEntry == NULL) { + PELOGE(lim_log + (pMac, LOGE, + FL("session does not exist for given sessionId ")); + ) + return; + } + psessionEntry->is_key_installed = 0; + lim_log(pMac, LOG1, + FL("Received MLM_SETKEYS_CNF with resultCode = %d"), + pMlmSetKeysCnf->resultCode); + /* if the status is success keys are installed in the + * Firmware so we can set the protection bit + */ + if (eSIR_SME_SUCCESS == pMlmSetKeysCnf->resultCode) { + if (pMlmSetKeysCnf->key_len_nonzero) + psessionEntry->is_key_installed = 1; + if (LIM_IS_AP_ROLE(psessionEntry)) { + sta_ds = dph_lookup_hash_entry(pMac, + pMlmSetKeysCnf->peer_macaddr.bytes, + &aid, &psessionEntry->dph.dphHashTable); + if (sta_ds != NULL && pMlmSetKeysCnf->key_len_nonzero) + sta_ds->is_key_installed = 1; + } + } + lim_log(pMac, LOG1, + FL("is_key_installed = %d"), + psessionEntry->is_key_installed); + + lim_send_sme_set_context_rsp(pMac, + pMlmSetKeysCnf->peer_macaddr, + 1, + (tSirResultCodes) pMlmSetKeysCnf->resultCode, + psessionEntry, psessionEntry->smeSessionId, + psessionEntry->transactionId); +} /*** end lim_process_mlm_set_keys_cnf() ***/ + +/** + * lim_join_result_callback() - Callback to handle join rsp + * @mac: Pointer to Global MAC structure + * @param: callback argument + * @status: status + * + * This callback function is used to delete PE session + * entry and send join response to sme. + * + * Return: None + */ +static void lim_join_result_callback(tpAniSirGlobal mac, void *param, + bool status) +{ + join_params *link_state_params = (join_params *) param; + tpPESession session; + uint8_t sme_session_id; + uint16_t sme_trans_id; + + if (!link_state_params) { + lim_log(mac, LOGE, + FL("Link state params is NULL")); + return; + } + session = pe_find_session_by_session_id(mac, link_state_params-> + pe_session_id); + if (!session) { + qdf_mem_free(link_state_params); + return; + } + sme_session_id = session->smeSessionId; + sme_trans_id = session->transactionId; + lim_send_sme_join_reassoc_rsp(mac, eWNI_SME_JOIN_RSP, + link_state_params->result_code, + link_state_params->prot_status_code, + NULL, sme_session_id, sme_trans_id); + pe_delete_session(mac, session); + qdf_mem_free(link_state_params); +} + +/** + * lim_handle_sme_join_result() - Handles sme join result + * @mac_ctx: Pointer to Global MAC structure + * @result_code: Failure code to be sent + * @prot_status_code : Protocol status code + * @session_entry: PE session handle + * + * This function is called to process join/auth/assoc failures + * upon receiving MLM_JOIN/AUTH/ASSOC_CNF with a failure code or + * MLM_ASSOC_CNF with a success code in case of STA role and + * MLM_JOIN_CNF with success in case of STA in IBSS role. + * + * Return: None + */ +void lim_handle_sme_join_result(tpAniSirGlobal mac_ctx, + tSirResultCodes result_code, uint16_t prot_status_code, + tpPESession session_entry) +{ + tpDphHashNode sta_ds = NULL; + uint8_t sme_session_id; + uint16_t sme_trans_id; + join_params *param = NULL; + + if (session_entry == NULL) { + lim_log(mac_ctx, LOGE, FL("psessionEntry is NULL ")); + return; + } + sme_session_id = session_entry->smeSessionId; + sme_trans_id = session_entry->transactionId; + /* + * When associations is failed , delete the session created + * and pass NULL to limsendsmeJoinReassocRsp() + */ + if (result_code != eSIR_SME_SUCCESS) { + sta_ds = + dph_get_hash_entry(mac_ctx, DPH_STA_HASH_INDEX_PEER, + &session_entry->dph.dphHashTable); + if (sta_ds != NULL) { + sta_ds->mlmStaContext.disassocReason = + eSIR_MAC_UNSPEC_FAILURE_REASON; + sta_ds->mlmStaContext.cleanupTrigger = + eLIM_JOIN_FAILURE; + sta_ds->mlmStaContext.resultCode = result_code; + sta_ds->mlmStaContext.protStatusCode = prot_status_code; + /* + * FIX_ME: at the end of lim_cleanup_rx_path, + * make sure PE is sending eWNI_SME_JOIN_RSP + * to SME + */ + lim_cleanup_rx_path(mac_ctx, sta_ds, session_entry); + qdf_mem_free(session_entry->pLimJoinReq); + session_entry->pLimJoinReq = NULL; + /* Cleanup if add bss failed */ + if (session_entry->add_bss_failed) { + dph_delete_hash_entry(mac_ctx, + sta_ds->staAddr, sta_ds->assocId, + &session_entry->dph.dphHashTable); + goto error; + } + return; + } + qdf_mem_free(session_entry->pLimJoinReq); + session_entry->pLimJoinReq = NULL; + } +error: + /* Delete the session if JOIN failure occurred. */ + if (result_code != eSIR_SME_SUCCESS) { + param = qdf_mem_malloc(sizeof(join_params)); + if (param != NULL) { + param->result_code = result_code; + param->prot_status_code = prot_status_code; + param->pe_session_id = session_entry->peSessionId; + } + if (lim_set_link_state + (mac_ctx, eSIR_LINK_DOWN_STATE, session_entry->bssId, + session_entry->selfMacAddr, lim_join_result_callback, + param) != eSIR_SUCCESS) { + qdf_mem_free(param); + param = NULL; + lim_log(mac_ctx, LOGE, + FL("Failed to set the LinkState.")); + } + return; + } + + lim_send_sme_join_reassoc_rsp(mac_ctx, eWNI_SME_JOIN_RSP, result_code, + prot_status_code, session_entry, sme_session_id, sme_trans_id); +} + +/** + * lim_process_mlm_add_sta_rsp() + * + ***FUNCTION: + * This function is called to process a WMA_ADD_STA_RSP from HAL. + * Upon receipt of this message from HAL, MLME - + * > Determines the "state" in which this message was received + * > Forwards it to the appropriate callback + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param pMac Pointer to Global MAC structure + * @param tSirMsgQ The MsgQ header, which contains the response buffer + * + * @return None + */ +void lim_process_mlm_add_sta_rsp(tpAniSirGlobal pMac, tpSirMsgQ limMsgQ, + tpPESession psessionEntry) +{ + /* we need to process the deferred message since the initiating req. there might be nested request. */ + /* in the case of nested request the new request initiated from the response will take care of resetting */ + /* the deffered flag. */ + SET_LIM_PROCESS_DEFD_MESGS(pMac, true); + if (LIM_IS_AP_ROLE(psessionEntry)) { + lim_process_ap_mlm_add_sta_rsp(pMac, limMsgQ, psessionEntry); + return; + } + lim_process_sta_mlm_add_sta_rsp(pMac, limMsgQ, psessionEntry); +} + +/** + * lim_process_sta_mlm_add_sta_rsp () - Process add sta response + * @mac_ctx: Pointer to mac context + * @msg: tpSirMsgQan Message structure + * @session_entry: PE session entry + * + * Process ADD STA response sent from WMA and posts results + * to SME. + * + * Return: Null + */ + +void lim_process_sta_mlm_add_sta_rsp(tpAniSirGlobal mac_ctx, + tpSirMsgQ msg, tpPESession session_entry) +{ + tLimMlmAssocCnf mlm_assoc_cnf; + tpDphHashNode sta_ds; + uint32_t msg_type = LIM_MLM_ASSOC_CNF; + tpAddStaParams add_sta_params = (tpAddStaParams) msg->bodyptr; + tpPESession ft_session = NULL; + uint8_t ft_session_id; + + if (NULL == add_sta_params) { + lim_log(mac_ctx, LOGE, FL("Encountered NULL Pointer")); + return; + } + + if (session_entry->limSmeState == eLIM_SME_WT_REASSOC_STATE) + msg_type = LIM_MLM_REASSOC_CNF; + + if (true == session_entry->fDeauthReceived) { + lim_log(mac_ctx, LOGE, + FL("Received Deauth frame in ADD_STA_RESP state")); + if (QDF_STATUS_SUCCESS == add_sta_params->status) { + lim_log(mac_ctx, LOGE, + FL("ADD_STA success, send update result code with eSIR_SME_JOIN_DEAUTH_FROM_AP_DURING_ADD_STA staIdx: %d limMlmState: %d"), + add_sta_params->staIdx, + session_entry->limMlmState); + + if (session_entry->limSmeState == + eLIM_SME_WT_REASSOC_STATE) + msg_type = LIM_MLM_REASSOC_CNF; + /* + * We are sending result code + * eSIR_SME_JOIN_DEAUTH_FROM_AP_DURING_ADD_STA which + * will trigger proper cleanup (DEL_STA/DEL_BSS both + * required) in either assoc cnf or reassoc cnf handler. + */ + mlm_assoc_cnf.resultCode = + eSIR_SME_JOIN_DEAUTH_FROM_AP_DURING_ADD_STA; + mlm_assoc_cnf.protStatusCode = + eSIR_MAC_UNSPEC_FAILURE_STATUS; + session_entry->staId = add_sta_params->staIdx; + goto end; + } + } + + if (QDF_STATUS_SUCCESS == add_sta_params->status) { + if (eLIM_MLM_WT_ADD_STA_RSP_STATE != + session_entry->limMlmState) { + lim_log(mac_ctx, LOGE, + FL("Received WMA_ADD_STA_RSP in state %X"), + session_entry->limMlmState); + mlm_assoc_cnf.resultCode = + (tSirResultCodes) eSIR_SME_REFUSED; + goto end; + } + if (session_entry->limSmeState == eLIM_SME_WT_REASSOC_STATE) { + /* check if we have keys(PTK)to install in case of 11r */ + tpftPEContext ft_ctx = &session_entry->ftPEContext; + ft_session = pe_find_session_by_bssid(mac_ctx, + session_entry->limReAssocbssId, &ft_session_id); + if (ft_session != NULL && + ft_ctx->PreAuthKeyInfo.extSetStaKeyParamValid + == true) { + tpLimMlmSetKeysReq pMlmStaKeys = + &ft_ctx->PreAuthKeyInfo.extSetStaKeyParam; + lim_send_set_sta_key_req(mac_ctx, pMlmStaKeys, + 0, 0, ft_session, false); + ft_ctx->PreAuthKeyInfo.extSetStaKeyParamValid = + false; + } + } + /* + * Update the DPH Hash Entry for this STA + * with proper state info + */ + sta_ds = + dph_get_hash_entry(mac_ctx, DPH_STA_HASH_INDEX_PEER, + &session_entry->dph.dphHashTable); + if (NULL != sta_ds) { + sta_ds->mlmStaContext.mlmState = + eLIM_MLM_LINK_ESTABLISHED_STATE; + sta_ds->nss = add_sta_params->nss; + } else + lim_log(mac_ctx, LOGW, + FL("Fail to get DPH Hash Entry for AID - %d"), + DPH_STA_HASH_INDEX_PEER); + session_entry->limMlmState = eLIM_MLM_LINK_ESTABLISHED_STATE; + MTRACE(mac_trace(mac_ctx, TRACE_CODE_MLM_STATE, + session_entry->peSessionId, + session_entry->limMlmState)); + /* + * Storing the self StaIndex(Generated by HAL) in + * session context, instead of storing it in DPH Hash + * entry for Self STA. + * DPH entry for the self STA stores the sta index for + * the BSS entry to which the STA is associated + */ + session_entry->staId = add_sta_params->staIdx; + +#ifdef WLAN_DEBUG + mac_ctx->lim.gLimNumLinkEsts++; +#endif +#ifdef FEATURE_WLAN_TDLS + /* initialize TDLS peer related data */ + lim_init_tdls_data(mac_ctx, session_entry); +#endif + /* + * Return Assoc confirm to SME with success + * FIXME - Need the correct ASSOC RSP code to + * be passed in here + */ + mlm_assoc_cnf.resultCode = (tSirResultCodes) eSIR_SME_SUCCESS; + } else { + lim_log(mac_ctx, LOGE, FL("ADD_STA failed!")); + if (session_entry->limSmeState == eLIM_SME_WT_REASSOC_STATE) + mlm_assoc_cnf.resultCode = + (tSirResultCodes) eSIR_SME_FT_REASSOC_FAILURE; + else + mlm_assoc_cnf.resultCode = + (tSirResultCodes) eSIR_SME_REFUSED; + mlm_assoc_cnf.protStatusCode = eSIR_MAC_UNSPEC_FAILURE_STATUS; + } +end: + if (NULL != msg->bodyptr) { + qdf_mem_free(add_sta_params); + msg->bodyptr = NULL; + } + /* Updating PE session Id */ + mlm_assoc_cnf.sessionId = session_entry->peSessionId; + lim_post_sme_message(mac_ctx, msg_type, (uint32_t *) &mlm_assoc_cnf); + if (true == session_entry->fDeauthReceived) + session_entry->fDeauthReceived = false; + return; +} + +void lim_process_mlm_del_bss_rsp(tpAniSirGlobal pMac, tpSirMsgQ limMsgQ, + tpPESession psessionEntry) +{ + /* we need to process the deferred message since the initiating req. there might be nested request. */ + /* in the case of nested request the new request initiated from the response will take care of resetting */ + /* the deffered flag. */ + SET_LIM_PROCESS_DEFD_MESGS(pMac, true); + pMac->sys.gSysFrameCount[SIR_MAC_MGMT_FRAME][SIR_MAC_MGMT_DEAUTH] = 0; + + if (LIM_IS_AP_ROLE(psessionEntry) && + (psessionEntry->statypeForBss == STA_ENTRY_SELF)) { + lim_process_ap_mlm_del_bss_rsp(pMac, limMsgQ, psessionEntry); + return; + } + lim_process_sta_mlm_del_bss_rsp(pMac, limMsgQ, psessionEntry); + +#ifdef WLAN_FEATURE_11W + if (psessionEntry->limRmfEnabled) { + if (eSIR_SUCCESS != + lim_send_exclude_unencrypt_ind(pMac, true, psessionEntry)) { + lim_log(pMac, LOGE, + FL + ("Could not send down Exclude Unencrypted Indication!")); + } + } +#endif +} + +void lim_process_sta_mlm_del_bss_rsp(tpAniSirGlobal pMac, tpSirMsgQ limMsgQ, + tpPESession psessionEntry) +{ + tpDeleteBssParams pDelBssParams = (tpDeleteBssParams) limMsgQ->bodyptr; + tpDphHashNode pStaDs = + dph_get_hash_entry(pMac, DPH_STA_HASH_INDEX_PEER, + &psessionEntry->dph.dphHashTable); + tSirResultCodes statusCode = eSIR_SME_SUCCESS; + + if (NULL == pDelBssParams) { + lim_log(pMac, LOGE, FL("Invalid body pointer in message")); + goto end; + } + if (QDF_STATUS_SUCCESS == pDelBssParams->status) { + PELOGW(lim_log(pMac, LOGW, + FL("STA received the DEL_BSS_RSP for BSSID: %X."), + pDelBssParams->bssIdx); + ) + if (lim_set_link_state + (pMac, eSIR_LINK_IDLE_STATE, psessionEntry->bssId, + psessionEntry->selfMacAddr, NULL, + NULL) != eSIR_SUCCESS) { + PELOGE(lim_log + (pMac, LOGE, + FL("Failure in setting link state to IDLE")); + ) + statusCode = eSIR_SME_REFUSED; + goto end; + } + if (pStaDs == NULL) { + lim_log(pMac, LOGE, FL("DPH Entry for STA 1 missing.")); + statusCode = eSIR_SME_REFUSED; + goto end; + } + if (eLIM_MLM_WT_DEL_BSS_RSP_STATE != + pStaDs->mlmStaContext.mlmState) { + PELOGE(lim_log + (pMac, LOGE, + FL + ("Received unexpected WMA_DEL_BSS_RSP in state %X"), + pStaDs->mlmStaContext.mlmState); + ) + statusCode = eSIR_SME_REFUSED; + goto end; + } + PELOG1(lim_log + (pMac, LOG1, FL("STA AssocID %d MAC "), pStaDs->assocId); + lim_print_mac_addr(pMac, pStaDs->staAddr, LOG1); + ) + } else { + lim_log(pMac, LOGE, FL("DEL BSS failed!")); + statusCode = eSIR_SME_STOP_BSS_FAILURE; + } +end: + if (0 != limMsgQ->bodyptr) { + qdf_mem_free(pDelBssParams); + limMsgQ->bodyptr = NULL; + } + if (pStaDs == NULL) + return; + if ((LIM_IS_STA_ROLE(psessionEntry)) && + (psessionEntry->limSmeState != + eLIM_SME_WT_DISASSOC_STATE && + psessionEntry->limSmeState != + eLIM_SME_WT_DEAUTH_STATE) && + pStaDs->mlmStaContext.cleanupTrigger != + eLIM_JOIN_FAILURE) { + /** The Case where the DelBss is invoked from + * context of other than normal DisAssoc / Deauth OR + * as part of Join Failure. + */ + lim_handle_del_bss_in_re_assoc_context(pMac, pStaDs, psessionEntry); + return; + } + lim_prepare_and_send_del_sta_cnf(pMac, pStaDs, statusCode, psessionEntry); + return; +} + +void lim_process_ap_mlm_del_bss_rsp(tpAniSirGlobal pMac, tpSirMsgQ limMsgQ, + tpPESession psessionEntry) +{ + tSirResultCodes rc = eSIR_SME_SUCCESS; + tSirRetStatus status; + tpDeleteBssParams pDelBss = (tpDeleteBssParams) limMsgQ->bodyptr; + tSirMacAddr nullBssid = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + + if (psessionEntry == NULL) { + lim_log(pMac, LOGE, FL("Session entry passed is NULL")); + if (pDelBss != NULL) { + qdf_mem_free(pDelBss); + limMsgQ->bodyptr = NULL; + } + return; + } + + if (pDelBss == NULL) { + PELOGE(lim_log(pMac, LOGE, FL("BSS: DEL_BSS_RSP with no body!"));) + rc = eSIR_SME_REFUSED; + goto end; + } + pMac->lim.gLimMlmState = eLIM_MLM_IDLE_STATE; + MTRACE(mac_trace + (pMac, TRACE_CODE_MLM_STATE, NO_SESSION, + pMac->lim.gLimMlmState)); + + if (eLIM_MLM_WT_DEL_BSS_RSP_STATE != psessionEntry->limMlmState) { + lim_log(pMac, LOGE, + FL("Received unexpected WMA_DEL_BSS_RSP in state %X"), + psessionEntry->limMlmState); + rc = eSIR_SME_REFUSED; + goto end; + } + if (pDelBss->status != QDF_STATUS_SUCCESS) { + lim_log(pMac, LOGE, FL("BSS: DEL_BSS_RSP error (%x) Bss %d "), + pDelBss->status, pDelBss->bssIdx); + rc = eSIR_SME_STOP_BSS_FAILURE; + goto end; + } + status = lim_set_link_state(pMac, eSIR_LINK_IDLE_STATE, nullBssid, + psessionEntry->selfMacAddr, NULL, NULL); + if (status != eSIR_SUCCESS) { + rc = eSIR_SME_REFUSED; + goto end; + } + /** Softmac may send all the buffered packets right after resuming the transmission hence + * to occupy the medium during non channel occupancy period. So resume the transmission after + * HAL gives back the response. + */ + dph_hash_table_class_init(pMac, &psessionEntry->dph.dphHashTable); + lim_delete_pre_auth_list(pMac); + /* Initialize number of associated stations during cleanup */ + psessionEntry->gLimNumOfCurrentSTAs = 0; +end: + lim_send_sme_rsp(pMac, eWNI_SME_STOP_BSS_RSP, rc, + psessionEntry->smeSessionId, + psessionEntry->transactionId); + pe_delete_session(pMac, psessionEntry); + + if (pDelBss != NULL) { + qdf_mem_free(pDelBss); + limMsgQ->bodyptr = NULL; + } +} + +/** + * lim_process_mlm_del_sta_rsp() - Process DEL STA response + * @mac_ctx: Pointer to Global MAC structure + * @msg: The MsgQ header, which contains the response buffer + * + * This function is called to process a WMA_DEL_STA_RSP from + * WMA Upon receipt of this message from FW. + * + * Return: None + */ +void lim_process_mlm_del_sta_rsp(tpAniSirGlobal mac_ctx, + tpSirMsgQ msg) +{ + /* + * we need to process the deferred message since the + * initiating req. there might be nested request + * in the case of nested request the new request + * initiated from the response will take care of resetting + * the deffered flag. + */ + tpPESession session_entry; + tpDeleteStaParams del_sta_params; + del_sta_params = (tpDeleteStaParams) msg->bodyptr; + if (NULL == del_sta_params) { + lim_log(mac_ctx, LOGE, + FL("null pointer del_sta_params msg")); + return; + } + SET_LIM_PROCESS_DEFD_MESGS(mac_ctx, true); + + session_entry = pe_find_session_by_session_id(mac_ctx, + del_sta_params->sessionId); + if (NULL == session_entry) { + lim_log(mac_ctx, LOGP, FL("Session Doesn't exist: %d"), + del_sta_params->sessionId); + qdf_mem_free(del_sta_params); + msg->bodyptr = NULL; + return; + } + + if (LIM_IS_AP_ROLE(session_entry)) { + lim_process_ap_mlm_del_sta_rsp(mac_ctx, msg, + session_entry); + return; + } + if (LIM_IS_NDI_ROLE(session_entry)) { + lim_process_ndi_del_sta_rsp(mac_ctx, msg, session_entry); + return; + } + lim_process_sta_mlm_del_sta_rsp(mac_ctx, msg, session_entry); +} + +/** + * lim_process_ap_mlm_del_sta_rsp() - Process WMA_DEL_STA_RSP + * @mac_ctx: Global pointer to MAC context + * @msg: Received message + * @session_entry: Session entry + * + * Process WMA_DEL_STA_RSP for AP role + * + * Retunrn: None + */ +void lim_process_ap_mlm_del_sta_rsp(tpAniSirGlobal mac_ctx, + tpSirMsgQ msg, + tpPESession session_entry) +{ + tpDeleteStaParams del_sta_params = (tpDeleteStaParams) msg->bodyptr; + tpDphHashNode sta_ds; + tSirResultCodes status_code = eSIR_SME_SUCCESS; + + if (msg->bodyptr == NULL) { + lim_log(mac_ctx, LOGE, FL("msg->bodyptr NULL")); + return; + } + + sta_ds = dph_get_hash_entry(mac_ctx, del_sta_params->assocId, + &session_entry->dph.dphHashTable); + if (sta_ds == NULL) { + lim_log(mac_ctx, LOGE, FL("DPH Entry for STA %X missing."), + del_sta_params->assocId); + status_code = eSIR_SME_REFUSED; + qdf_mem_free(del_sta_params); + msg->bodyptr = NULL; + return; + } + lim_log(mac_ctx, LOG1, FL("Received del Sta Rsp in StaD MlmState : %d"), + sta_ds->mlmStaContext.mlmState); + if (QDF_STATUS_SUCCESS != del_sta_params->status) { + lim_log(mac_ctx, LOGW, FL("DEL STA failed!")); + status_code = eSIR_SME_REFUSED; + goto end; + } + + lim_log(mac_ctx, LOGW, + FL("AP received the DEL_STA_RSP for assocID: %X."), + del_sta_params->assocId); + if ((eLIM_MLM_WT_DEL_STA_RSP_STATE != sta_ds->mlmStaContext.mlmState) && + (eLIM_MLM_WT_ASSOC_DEL_STA_RSP_STATE != + sta_ds->mlmStaContext.mlmState)) { + lim_log(mac_ctx, LOGE, + FL("Received unexpected WMA_DEL_STA_RSP in state %s for staId %d assocId %d "), + lim_mlm_state_str(sta_ds->mlmStaContext.mlmState), + sta_ds->staIndex, sta_ds->assocId); + status_code = eSIR_SME_REFUSED; + goto end; + } + + lim_log(mac_ctx, LOG1, FL("Deleted STA AssocID %d staId %d MAC "), + sta_ds->assocId, sta_ds->staIndex); + lim_print_mac_addr(mac_ctx, sta_ds->staAddr, LOG1); + if (eLIM_MLM_WT_ASSOC_DEL_STA_RSP_STATE == + sta_ds->mlmStaContext.mlmState) { + qdf_mem_free(del_sta_params); + msg->bodyptr = NULL; + if (lim_add_sta(mac_ctx, sta_ds, false, session_entry) != + eSIR_SUCCESS) { + lim_log(mac_ctx, LOGE, FL("could not Add STA with assocId=%d"), + sta_ds->assocId); + /* + * delete the TS if it has already been added. + * send the response with error status. + */ + if (sta_ds->qos.addtsPresent) { + tpLimTspecInfo pTspecInfo; + if (eSIR_SUCCESS == + lim_tspec_find_by_assoc_id(mac_ctx, + sta_ds->assocId, + &sta_ds->qos.addts.tspec, + &mac_ctx->lim.tspecInfo[0], + &pTspecInfo)) { + lim_admit_control_delete_ts(mac_ctx, + sta_ds->assocId, + &sta_ds->qos.addts.tspec.tsinfo, + NULL, + &pTspecInfo->idx); + } + } + lim_reject_association(mac_ctx, sta_ds->staAddr, + sta_ds->mlmStaContext.subType, true, + sta_ds->mlmStaContext.authType, sta_ds->assocId, + true, + (tSirResultCodes)eSIR_MAC_UNSPEC_FAILURE_STATUS, + session_entry); + } + return; + } +end: + qdf_mem_free(del_sta_params); + msg->bodyptr = NULL; + if (eLIM_MLM_WT_ASSOC_DEL_STA_RSP_STATE != + sta_ds->mlmStaContext.mlmState) { + lim_prepare_and_send_del_sta_cnf(mac_ctx, sta_ds, status_code, + session_entry); + } + return; +} + +void lim_process_sta_mlm_del_sta_rsp(tpAniSirGlobal pMac, tpSirMsgQ limMsgQ, + tpPESession psessionEntry) +{ + tSirResultCodes statusCode = eSIR_SME_SUCCESS; + tpDeleteStaParams pDelStaParams = (tpDeleteStaParams) limMsgQ->bodyptr; + tpDphHashNode pStaDs = NULL; + if (NULL == pDelStaParams) { + lim_log(pMac, LOGE, FL("Encountered NULL Pointer")); + goto end; + } + lim_log(pMac, LOG1, FL("Del STA RSP received. Status:%d AssocID:%d"), + pDelStaParams->status, pDelStaParams->assocId); + +#ifdef FEATURE_WLAN_TDLS + if (pDelStaParams->staType == STA_ENTRY_TDLS_PEER) { + lim_log(pMac, LOG1, FL("TDLS Del STA RSP received.")); + lim_process_tdls_del_sta_rsp(pMac, limMsgQ, psessionEntry); + return; + } +#endif + if (QDF_STATUS_SUCCESS != pDelStaParams->status) + lim_log(pMac, LOGE, FL( + "Del STA failed! Status:%d, proceeding with Del BSS"), + pDelStaParams->status); + + pStaDs = dph_get_hash_entry(pMac, DPH_STA_HASH_INDEX_PEER, + &psessionEntry->dph.dphHashTable); + if (pStaDs == NULL) { + lim_log(pMac, LOGE, FL("DPH Entry for STA %X missing."), + pDelStaParams->assocId); + statusCode = eSIR_SME_REFUSED; + goto end; + } + if (eLIM_MLM_WT_DEL_STA_RSP_STATE != psessionEntry->limMlmState) { + lim_log(pMac, LOGE, FL( + "Received unexpected WDA_DELETE_STA_RSP in state %s"), + lim_mlm_state_str(psessionEntry->limMlmState)); + statusCode = eSIR_SME_REFUSED; + goto end; + } + lim_log(pMac, LOG1, FL("STA AssocID %d MAC "), pStaDs->assocId); + lim_print_mac_addr(pMac, pStaDs->staAddr, LOG1); + /* + * we must complete all cleanup related to delSta before + * calling limDelBSS. + */ + if (0 != limMsgQ->bodyptr) { + qdf_mem_free(pDelStaParams); + limMsgQ->bodyptr = NULL; + } + /* Proceed to do DelBSS even if DelSta resulted in failure */ + statusCode = (tSirResultCodes)lim_del_bss(pMac, pStaDs, 0, + psessionEntry); + return; +end: + if (0 != limMsgQ->bodyptr) { + qdf_mem_free(pDelStaParams); + limMsgQ->bodyptr = NULL; + } + return; +} + +void lim_process_ap_mlm_add_sta_rsp(tpAniSirGlobal pMac, tpSirMsgQ limMsgQ, + tpPESession psessionEntry) +{ + tpAddStaParams pAddStaParams = (tpAddStaParams) limMsgQ->bodyptr; + tpDphHashNode pStaDs = NULL; + + if (NULL == pAddStaParams) { + lim_log(pMac, LOGE, FL("Invalid body pointer in message")); + goto end; + } + + pStaDs = + dph_get_hash_entry(pMac, pAddStaParams->assocId, + &psessionEntry->dph.dphHashTable); + if (pStaDs == NULL) { + /* TODO: any response to be sent out here ? */ + lim_log(pMac, LOGE, FL("DPH Entry for STA %X missing."), + pAddStaParams->assocId); + goto end; + } + /* */ + /* TODO & FIXME_GEN4 */ + /* Need to inspect tSirMsgQ.reserved for a valid Dialog token! */ + /* */ + /* TODO: any check for pMac->lim.gLimMlmState ? */ + if (eLIM_MLM_WT_ADD_STA_RSP_STATE != pStaDs->mlmStaContext.mlmState) { + /* TODO: any response to be sent out here ? */ + lim_log(pMac, LOGE, + FL("Received unexpected WMA_ADD_STA_RSP in state %X"), + pStaDs->mlmStaContext.mlmState); + goto end; + } + if (QDF_STATUS_SUCCESS != pAddStaParams->status) { + PELOGE(lim_log + (pMac, LOGE, + FL("Error! rcvd delSta rsp from HAL with status %d"), + pAddStaParams->status); + ) + lim_reject_association(pMac, pStaDs->staAddr, + pStaDs->mlmStaContext.subType, + true, pStaDs->mlmStaContext.authType, + pStaDs->assocId, true, + (tSirResultCodes) + eSIR_MAC_UNSPEC_FAILURE_STATUS, + psessionEntry); + goto end; + } + pStaDs->bssId = pAddStaParams->bssIdx; + pStaDs->staIndex = pAddStaParams->staIdx; + pStaDs->nss = pAddStaParams->nss; + /* if the AssocRsp frame is not acknowledged, then keep alive timer will take care of the state */ + pStaDs->valid = 1; + pStaDs->mlmStaContext.mlmState = eLIM_MLM_WT_ASSOC_CNF_STATE; + lim_log(pMac, LOG1, + FL("AddStaRsp Success.STA AssocID %d staId %d MAC "), + pStaDs->assocId, pStaDs->staIndex); + lim_print_mac_addr(pMac, pStaDs->staAddr, LOG1); + + /* For BTAMP-AP, the flow sequence shall be: + * 1) PE sends eWNI_SME_ASSOC_IND to SME + * 2) PE receives eWNI_SME_ASSOC_CNF from SME + * 3) BTAMP-AP sends Re/Association Response to BTAMP-STA + */ + lim_send_mlm_assoc_ind(pMac, pStaDs, psessionEntry); + /* fall though to reclaim the original Add STA Response message */ +end: + if (0 != limMsgQ->bodyptr) { + qdf_mem_free(pAddStaParams); + limMsgQ->bodyptr = NULL; + } + return; +} + +/** + * lim_process_ap_mlm_add_bss_rsp() + * + ***FUNCTION: + * This function is called to process a WMA_ADD_BSS_RSP from HAL. + * Upon receipt of this message from HAL, MLME - + * > Validates the result of WMA_ADD_BSS_REQ + * > Init other remaining LIM variables + * > Init the AID pool, for that BSSID + * > Init the Pre-AUTH list, for that BSSID + * > Create LIM timers, specific to that BSSID + * > Init DPH related parameters that are specific to that BSSID + * > TODO - When do we do the actual change channel? + * + ***LOGIC: + * SME sends eWNI_SME_START_BSS_REQ to LIM + * LIM sends LIM_MLM_START_REQ to MLME + * MLME sends WMA_ADD_BSS_REQ to HAL + * HAL responds with WMA_ADD_BSS_RSP to MLME + * MLME responds with LIM_MLM_START_CNF to LIM + * LIM responds with eWNI_SME_START_BSS_RSP to SME + * + ***ASSUMPTIONS: + * tSirMsgQ.body is allocated by MLME during lim_process_mlm_start_req + * tSirMsgQ.body will now be freed by this routine + * + ***NOTE: + * + * @param pMac Pointer to Global MAC structure + * @param tSirMsgQ The MsgQ header, which contains the response buffer + * + * @return None + */ +static void lim_process_ap_mlm_add_bss_rsp(tpAniSirGlobal pMac, tpSirMsgQ limMsgQ) +{ + tLimMlmStartCnf mlmStartCnf; + tpPESession psessionEntry; + uint8_t isWepEnabled = false; + tpAddBssParams pAddBssParams = (tpAddBssParams) limMsgQ->bodyptr; + if (NULL == pAddBssParams) { + lim_log(pMac, LOGE, FL("Encountered NULL Pointer")); + goto end; + } + /* TBD: free the memory before returning, do it for all places where lookup fails. */ + psessionEntry = pe_find_session_by_session_id(pMac, + pAddBssParams->sessionId); + if (psessionEntry == NULL) { + PELOGE(lim_log + (pMac, LOGE, + FL("session does not exist for given sessionId")); + ) + if (NULL != pAddBssParams) { + qdf_mem_free(pAddBssParams); + limMsgQ->bodyptr = NULL; + } + return; + } + /* Update PE session Id */ + mlmStartCnf.sessionId = pAddBssParams->sessionId; + if (QDF_STATUS_SUCCESS == pAddBssParams->status) { + PELOG2(lim_log + (pMac, LOG2, + FL("WMA_ADD_BSS_RSP returned with QDF_STATUS_SUCCESS")); + ) + if (lim_set_link_state + (pMac, eSIR_LINK_AP_STATE, psessionEntry->bssId, + psessionEntry->selfMacAddr, NULL, + NULL) != eSIR_SUCCESS) + goto end; + /* Set MLME state */ + psessionEntry->limMlmState = eLIM_MLM_BSS_STARTED_STATE; + psessionEntry->chainMask = pAddBssParams->chainMask; + psessionEntry->smpsMode = pAddBssParams->smpsMode; + MTRACE(mac_trace + (pMac, TRACE_CODE_MLM_STATE, psessionEntry->peSessionId, + psessionEntry->limMlmState)); + if (eSIR_IBSS_MODE == pAddBssParams->bssType) { + /** IBSS is 'active' when we receive + * Beacon frames from other STAs that are part of same IBSS. + * Mark internal state as inactive until then. + */ + psessionEntry->limIbssActive = false; + psessionEntry->statypeForBss = STA_ENTRY_PEER; /* to know session created for self/peer */ + limResetHBPktCount(psessionEntry); + } + psessionEntry->bssIdx = (uint8_t) pAddBssParams->bssIdx; + + psessionEntry->limSystemRole = eLIM_STA_IN_IBSS_ROLE; + + if (eSIR_INFRA_AP_MODE == pAddBssParams->bssType) + psessionEntry->limSystemRole = eLIM_AP_ROLE; + else + psessionEntry->limSystemRole = eLIM_STA_IN_IBSS_ROLE; + sch_edca_profile_update(pMac, psessionEntry); + lim_init_pre_auth_list(pMac); + /* Check the SAP security configuration.If configured to + * WEP then max clients supported is 16 + */ + if (psessionEntry->privacy) { + if ((psessionEntry->gStartBssRSNIe.present) + || (psessionEntry->gStartBssWPAIe.present)) + lim_log(pMac, LOG1, + FL("WPA/WPA2 SAP configuration")); + else { + if (pMac->lim.gLimAssocStaLimit > + MAX_SUPPORTED_PEERS_WEP) { + lim_log(pMac, LOG1, + FL("WEP SAP Configuration")); + pMac->lim.gLimAssocStaLimit = + MAX_SUPPORTED_PEERS_WEP; + isWepEnabled = true; + } + } + } + lim_init_peer_idxpool(pMac, psessionEntry); + + /* Start OLBC timer */ + if (tx_timer_activate + (&pMac->lim.limTimers.gLimUpdateOlbcCacheTimer) != + TX_SUCCESS) { + lim_log(pMac, LOGE, FL("tx_timer_activate failed")); + } + + /* Apply previously set configuration at HW */ + lim_apply_configuration(pMac, psessionEntry); + + /* In lim_apply_configuration gLimAssocStaLimit is assigned from cfg. + * So update the value to 16 in case SoftAP is configured in WEP. + */ + if ((pMac->lim.gLimAssocStaLimit > MAX_SUPPORTED_PEERS_WEP) + && (isWepEnabled)) + pMac->lim.gLimAssocStaLimit = MAX_SUPPORTED_PEERS_WEP; + psessionEntry->staId = pAddBssParams->staContext.staIdx; + mlmStartCnf.resultCode = eSIR_SME_SUCCESS; + } else { + lim_log(pMac, LOGE, FL("WMA_ADD_BSS_REQ failed with status %d"), + pAddBssParams->status); + mlmStartCnf.resultCode = eSIR_SME_HAL_SEND_MESSAGE_FAIL; + } + lim_post_sme_message(pMac, LIM_MLM_START_CNF, (uint32_t *) &mlmStartCnf); +end: + if (0 != limMsgQ->bodyptr) { + qdf_mem_free(pAddBssParams); + limMsgQ->bodyptr = NULL; + } +} + +/** + * lim_process_ibss_mlm_add_bss_rsp() + * + ***FUNCTION: + * This function is called to process a WMA_ADD_BSS_RSP from HAL. + * Upon receipt of this message from HAL, MLME - + * > Validates the result of WMA_ADD_BSS_REQ + * > Init other remaining LIM variables + * > Init the AID pool, for that BSSID + * > Init the Pre-AUTH list, for that BSSID + * > Create LIM timers, specific to that BSSID + * > Init DPH related parameters that are specific to that BSSID + * > TODO - When do we do the actual change channel? + * + ***LOGIC: + * SME sends eWNI_SME_START_BSS_REQ to LIM + * LIM sends LIM_MLM_START_REQ to MLME + * MLME sends WMA_ADD_BSS_REQ to HAL + * HAL responds with WMA_ADD_BSS_RSP to MLME + * MLME responds with LIM_MLM_START_CNF to LIM + * LIM responds with eWNI_SME_START_BSS_RSP to SME + * + ***ASSUMPTIONS: + * tSirMsgQ.body is allocated by MLME during lim_process_mlm_start_req + * tSirMsgQ.body will now be freed by this routine + * + ***NOTE: + * + * @param pMac Pointer to Global MAC structure + * @param tSirMsgQ The MsgQ header, which contains the response buffer + * + * @return None + */ +static void +lim_process_ibss_mlm_add_bss_rsp(tpAniSirGlobal pMac, tpSirMsgQ limMsgQ, + tpPESession psessionEntry) +{ + tLimMlmStartCnf mlmStartCnf; + tpAddBssParams pAddBssParams = (tpAddBssParams) limMsgQ->bodyptr; + + if (NULL == pAddBssParams) { + lim_log(pMac, LOGE, FL("Invalid body pointer in message")); + goto end; + } + if (QDF_STATUS_SUCCESS == pAddBssParams->status) { + PELOG1(lim_log + (pMac, LOG1, + FL("WMA_ADD_BSS_RSP returned with QDF_STATUS_SUCCESS")); + ) + if (lim_set_link_state + (pMac, eSIR_LINK_IBSS_STATE, psessionEntry->bssId, + psessionEntry->selfMacAddr, NULL, + NULL) != eSIR_SUCCESS) + goto end; + /* Set MLME state */ + psessionEntry->limMlmState = eLIM_MLM_BSS_STARTED_STATE; + MTRACE(mac_trace + (pMac, TRACE_CODE_MLM_STATE, psessionEntry->peSessionId, + psessionEntry->limMlmState)); + /** IBSS is 'active' when we receive + * Beacon frames from other STAs that are part of same IBSS. + * Mark internal state as inactive until then. + */ + psessionEntry->limIbssActive = false; + limResetHBPktCount(psessionEntry); + psessionEntry->bssIdx = (uint8_t) pAddBssParams->bssIdx; + psessionEntry->limSystemRole = eLIM_STA_IN_IBSS_ROLE; + psessionEntry->statypeForBss = STA_ENTRY_SELF; + sch_edca_profile_update(pMac, psessionEntry); + if (0 == psessionEntry->freePeerIdxHead) + lim_init_peer_idxpool(pMac, psessionEntry); + + /* Apply previously set configuration at HW */ + lim_apply_configuration(pMac, psessionEntry); + psessionEntry->staId = pAddBssParams->staContext.staIdx; + mlmStartCnf.resultCode = eSIR_SME_SUCCESS; + /* If ADD BSS was issued as part of IBSS coalescing, don't send the message to SME, as that is internal to LIM */ + if (true == pMac->lim.gLimIbssCoalescingHappened) { + lim_ibss_add_bss_rsp_when_coalescing(pMac, limMsgQ->bodyptr, + psessionEntry); + goto end; + } + } else { + lim_log(pMac, LOGE, FL("WMA_ADD_BSS_REQ failed with status %d"), + pAddBssParams->status); + mlmStartCnf.resultCode = eSIR_SME_HAL_SEND_MESSAGE_FAIL; + } + /* Send this message to SME, when ADD_BSS is initiated by SME */ + /* If ADD_BSS is done as part of coalescing, this won't happen. */ + /* Update PE session Id */ + mlmStartCnf.sessionId = psessionEntry->peSessionId; + lim_post_sme_message(pMac, LIM_MLM_START_CNF, (uint32_t *) &mlmStartCnf); +end: + if (0 != limMsgQ->bodyptr) { + qdf_mem_free(pAddBssParams); + limMsgQ->bodyptr = NULL; + } +} + +/** + * csr_neighbor_roam_handoff_req_hdlr - Processes handoff request + * @mac_ctx: Pointer to mac context + * @msg: message sent to HDD + * @session_entry: PE session handle + * + * This function is called to process a WMA_ADD_BSS_RSP from HAL. + * Upon receipt of this message from HAL if the state is pre assoc. + * + * Return: Null + */ +static void +lim_process_sta_add_bss_rsp_pre_assoc(tpAniSirGlobal mac_ctx, + tpSirMsgQ msg, tpPESession session_entry) +{ + tpAddBssParams pAddBssParams = (tpAddBssParams) msg->bodyptr; + tAniAuthType cfgAuthType, authMode; + tLimMlmAuthReq *pMlmAuthReq; + tpDphHashNode pStaDs = NULL; + + if (NULL == pAddBssParams) { + lim_log(mac_ctx, LOGE, FL("Invalid body pointer in message")); + goto joinFailure; + } + if (QDF_STATUS_SUCCESS == pAddBssParams->status) { + pStaDs = dph_add_hash_entry(mac_ctx, + pAddBssParams->staContext.staMac, + DPH_STA_HASH_INDEX_PEER, + &session_entry->dph.dphHashTable); + if (pStaDs == NULL) { + /* Could not add hash table entry */ + lim_log(mac_ctx, LOGE, + FL("could not add hash entry at DPH for ")); + lim_print_mac_addr(mac_ctx, + pAddBssParams->staContext.staMac, LOGE); + goto joinFailure; + } + session_entry->bssIdx = (uint8_t) pAddBssParams->bssIdx; + /* Success, handle below */ + pStaDs->bssId = pAddBssParams->bssIdx; + /* STA Index(genr by HAL) for the BSS entry is stored here */ + pStaDs->staIndex = pAddBssParams->staContext.staIdx; + /* Trigger Authentication with AP */ + if (wlan_cfg_get_int(mac_ctx, WNI_CFG_AUTHENTICATION_TYPE, + (uint32_t *) &cfgAuthType) != eSIR_SUCCESS) { + /* + * Could not get AuthType from CFG. + * Log error. + */ + lim_log(mac_ctx, LOGP, + FL("could not retrieve AuthType")); + } + /* Try shared Authentication first */ + if (cfgAuthType == eSIR_AUTO_SWITCH) + authMode = eSIR_SHARED_KEY; + else + authMode = cfgAuthType; + + /* Trigger MAC based Authentication */ + pMlmAuthReq = qdf_mem_malloc(sizeof(tLimMlmAuthReq)); + if (NULL == pMlmAuthReq) { + lim_log(mac_ctx, LOGP, + FL("Allocate Memory failed for mlmAuthReq")); + return; + } + sir_copy_mac_addr(pMlmAuthReq->peerMacAddr, + session_entry->bssId); + + pMlmAuthReq->authType = authMode; + if (wlan_cfg_get_int(mac_ctx, + WNI_CFG_AUTHENTICATE_FAILURE_TIMEOUT, + (uint32_t *) &pMlmAuthReq->authFailureTimeout) + != eSIR_SUCCESS) { + /* + * Could not get AuthFailureTimeout + * value from CFG. Log error. + */ + lim_log(mac_ctx, LOGP, + FL("Fail: retrieve AuthFailureTimeout value")); + } + session_entry->limMlmState = eLIM_MLM_JOINED_STATE; + MTRACE(mac_trace(mac_ctx, TRACE_CODE_MLM_STATE, + session_entry->peSessionId, eLIM_MLM_JOINED_STATE)); + pMlmAuthReq->sessionId = session_entry->peSessionId; + session_entry->limPrevSmeState = session_entry->limSmeState; + session_entry->limSmeState = eLIM_SME_WT_AUTH_STATE; + /* remember staId in case of assoc timeout/failure handling */ + session_entry->staId = pAddBssParams->staContext.staIdx; + + MTRACE(mac_trace(mac_ctx, TRACE_CODE_SME_STATE, + session_entry->peSessionId, + session_entry->limSmeState)); + lim_log(mac_ctx, LOG1, + FL("SessionId:%d lim_post_mlm_message " + "LIM_MLM_AUTH_REQ with limSmeState:%d"), + session_entry->peSessionId, session_entry->limSmeState); + lim_post_mlm_message(mac_ctx, LIM_MLM_AUTH_REQ, + (uint32_t *) pMlmAuthReq); + return; + } + +joinFailure: + { + session_entry->limSmeState = eLIM_SME_JOIN_FAILURE_STATE; + MTRACE(mac_trace(mac_ctx, TRACE_CODE_SME_STATE, + session_entry->peSessionId, + session_entry->limSmeState)); + + /* Send Join response to Host */ + lim_handle_sme_join_result(mac_ctx, eSIR_SME_REFUSED, + eSIR_MAC_UNSPEC_FAILURE_STATUS, session_entry); + } + +} + +/** + * lim_process_sta_mlm_add_bss_rsp() - Process ADD BSS response + * @mac_ctx: Pointer to Global MAC structure + * @msg: The MsgQ header, which contains the response buffer + * + * This function is called to process a WMA_ADD_BSS_RSP from HAL. + * Upon receipt of this message from HAL, MLME - + * > Validates the result of WMA_ADD_BSS_REQ + * > Now, send an ADD_STA to HAL and ADD the "local" STA itself + * + * MLME had sent WMA_ADD_BSS_REQ to HAL + * HAL responded with WMA_ADD_BSS_RSP to MLME + * MLME now sends WMA_ADD_STA_REQ to HAL + * ASSUMPTIONS: + * tSirMsgQ.body is allocated by MLME during lim_process_mlm_join_req + * tSirMsgQ.body will now be freed by this routine + * + * Return: None + */ +static void +lim_process_sta_mlm_add_bss_rsp(tpAniSirGlobal mac_ctx, + tpSirMsgQ msg, tpPESession session_entry) +{ + tpAddBssParams add_bss_params = (tpAddBssParams) msg->bodyptr; + tLimMlmAssocCnf mlm_assoc_cnf; + uint32_t msg_type = LIM_MLM_ASSOC_CNF; + uint32_t sub_type = LIM_ASSOC; + tpDphHashNode sta_ds = NULL; + uint16_t sta_idx = STA_INVALID_IDX; + uint8_t update_sta = false; + mlm_assoc_cnf.resultCode = eSIR_SME_SUCCESS; + + if (eLIM_MLM_WT_ADD_BSS_RSP_PREASSOC_STATE == + session_entry->limMlmState) { + lim_log(mac_ctx, LOG1, + "SessionId:%d lim_process_sta_add_bss_rsp_pre_assoc", + session_entry->peSessionId); + lim_process_sta_add_bss_rsp_pre_assoc(mac_ctx, msg, + session_entry); + goto end; + } + if (eLIM_MLM_WT_ADD_BSS_RSP_REASSOC_STATE == session_entry->limMlmState + || (eLIM_MLM_WT_ADD_BSS_RSP_FT_REASSOC_STATE == + session_entry->limMlmState)) { + msg_type = LIM_MLM_REASSOC_CNF; + sub_type = LIM_REASSOC; + /* + * If Reassoc is happening for the same BSS, then + * use the existing StaId and indicate to HAL to update + * the existing STA entry. + * If Reassoc is happening for the new BSS, then + * old BSS and STA entry would have been already deleted + * before PE tries to add BSS for the new BSS, so set the + * updateSta to false and pass INVALID STA Index. + */ + if (sir_compare_mac_addr(session_entry->bssId, + session_entry->limReAssocbssId)) { + sta_idx = session_entry->staId; + update_sta = true; + } + } + + if (add_bss_params == 0) + goto end; +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + if (session_entry->bRoamSynchInProgress) + QDF_TRACE(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_DEBUG, + "LFR3:lim_process_sta_mlm_add_bss_rsp"); +#endif + + if (QDF_STATUS_SUCCESS == add_bss_params->status) { + if (eLIM_MLM_WT_ADD_BSS_RSP_FT_REASSOC_STATE == + session_entry->limMlmState) { + lim_log(mac_ctx, LOG1, FL("Mlm=%d %d"), + session_entry->limMlmState, + eLIM_MLM_WT_ADD_BSS_RSP_REASSOC_STATE); + lim_process_sta_mlm_add_bss_rsp_ft(mac_ctx, msg, + session_entry); + goto end; + } + + /* Set MLME state */ + session_entry->limMlmState = eLIM_MLM_WT_ADD_STA_RSP_STATE; + MTRACE(mac_trace(mac_ctx, TRACE_CODE_MLM_STATE, + session_entry->peSessionId, + session_entry->limMlmState)); + /* to know the session started for self or for peer */ + session_entry->statypeForBss = STA_ENTRY_PEER; + /* Now, send WMA_ADD_STA_REQ */ + lim_log(mac_ctx, LOGW, + FL("SessionId:%d On STA: ADD_BSS was successful"), + session_entry->peSessionId); + sta_ds = + dph_get_hash_entry(mac_ctx, DPH_STA_HASH_INDEX_PEER, + &session_entry->dph.dphHashTable); + if (sta_ds == NULL) { + lim_log(mac_ctx, LOGE, + FL("Session:%d Fail to add Self Entry for STA"), + session_entry->peSessionId); + mlm_assoc_cnf.resultCode = + (tSirResultCodes) eSIR_SME_REFUSED; + } else { + session_entry->bssIdx = + (uint8_t) add_bss_params->bssIdx; + /* Success, handle below */ + sta_ds->bssId = add_bss_params->bssIdx; + /* + * STA Index(genr by HAL) for the BSS + * entry is stored here + */ + sta_ds->staIndex = add_bss_params->staContext.staIdx; + sta_ds->ucUcastSig = + add_bss_params->staContext.ucUcastSig; + sta_ds->ucBcastSig = + add_bss_params->staContext.ucBcastSig; + /* Downgrade the EDCA parameters if needed */ + lim_set_active_edca_params(mac_ctx, + session_entry->gLimEdcaParams, session_entry); + lim_send_edca_params(mac_ctx, + session_entry->gLimEdcaParamsActive, + sta_ds->bssId); + rrm_cache_mgmt_tx_power(mac_ctx, + add_bss_params->txMgmtPower, session_entry); + if (lim_add_sta_self(mac_ctx, sta_idx, update_sta, + session_entry) != eSIR_SUCCESS) { + /* Add STA context at HW */ + lim_log(mac_ctx, LOGE, + FL("Session:%d could not Add Self" + "Entry for the station"), + session_entry->peSessionId); + mlm_assoc_cnf.resultCode = + (tSirResultCodes) eSIR_SME_REFUSED; + } + } + } else { + lim_log(mac_ctx, LOGP, FL("SessionId:%d ADD_BSS failed!"), + session_entry->peSessionId); + mlm_assoc_cnf.protStatusCode = eSIR_MAC_UNSPEC_FAILURE_STATUS; + /* Return Assoc confirm to SME with failure */ + if (eLIM_MLM_WT_ADD_BSS_RSP_FT_REASSOC_STATE == + session_entry->limMlmState) + mlm_assoc_cnf.resultCode = + (tSirResultCodes) eSIR_SME_FT_REASSOC_FAILURE; + else + mlm_assoc_cnf.resultCode = + (tSirResultCodes) eSIR_SME_REFUSED; + session_entry->add_bss_failed = true; + } + + if (mlm_assoc_cnf.resultCode != eSIR_SME_SUCCESS) { + session_entry->limMlmState = eLIM_MLM_IDLE_STATE; + if (lim_set_link_state(mac_ctx, eSIR_LINK_IDLE_STATE, + session_entry->bssId, + session_entry->selfMacAddr, + NULL, NULL) != eSIR_SUCCESS) + lim_log(mac_ctx, LOGE, FL("Failed to set the LinkState")); + /* Update PE session Id */ + mlm_assoc_cnf.sessionId = session_entry->peSessionId; + lim_post_sme_message(mac_ctx, msg_type, + (uint32_t *) &mlm_assoc_cnf); + } +end: + if (0 != msg->bodyptr) { + qdf_mem_free(add_bss_params); + msg->bodyptr = NULL; + } +} + +/** + * lim_process_mlm_add_bss_rsp() - Processes ADD BSS Response + * + * @mac_ctx - Pointer to Global MAC structure + * @msg - The MsgQ header, which contains the response buffer + * + * This function is called to process a WMA_ADD_BSS_RSP from HAL. + * Upon receipt of this message from HAL, MLME - + * Determines the "state" in which this message was received + * Forwards it to the appropriate callback + * + *LOGIC: + * WMA_ADD_BSS_RSP can be received by MLME while the LIM is + * in the following two states: + * 1) As AP, LIM state = eLIM_SME_WT_START_BSS_STATE + * 2) As STA, LIM state = eLIM_SME_WT_JOIN_STATE + * Based on these two states, this API will determine where to + * route the message to + * + * Return None + */ +void lim_process_mlm_add_bss_rsp(tpAniSirGlobal mac_ctx, + tpSirMsgQ msg) +{ + tLimMlmStartCnf mlm_start_cnf; + tpPESession session_entry; + tpAddBssParams add_bss_param = (tpAddBssParams) (msg->bodyptr); + tSirBssType bss_type; + + if (NULL == add_bss_param) { + lim_log(mac_ctx, LOGE, FL("Encountered NULL Pointer")); + return; + } + + /* + * we need to process the deferred message since the + * initiating req.there might be nested request. + * in the case of nested request the new request initiated + * from the response will take care of resetting the deffered + * flag. + */ + SET_LIM_PROCESS_DEFD_MESGS(mac_ctx, true); + /* Validate SME/LIM/MLME state */ + session_entry = pe_find_session_by_session_id(mac_ctx, + add_bss_param->sessionId); + if (session_entry == NULL) { + lim_log(mac_ctx, LOGE, FL("SessionId:%d Session Doesn't exist"), + add_bss_param->sessionId); + if (NULL != add_bss_param) { + qdf_mem_free(add_bss_param); + msg->bodyptr = NULL; + } + return; + } + + bss_type = session_entry->bssType; + /* update PE session Id */ + mlm_start_cnf.sessionId = session_entry->peSessionId; + if (eSIR_IBSS_MODE == bss_type) { + lim_process_ibss_mlm_add_bss_rsp(mac_ctx, msg, session_entry); + } else if (eSIR_NDI_MODE == session_entry->bssType) { + lim_process_ndi_mlm_add_bss_rsp(mac_ctx, msg, session_entry); + } else { + if (eLIM_SME_WT_START_BSS_STATE == session_entry->limSmeState) { + if (eLIM_MLM_WT_ADD_BSS_RSP_STATE != + session_entry->limMlmState) { + /* Mesg received from HAL in Invalid state! */ + lim_log(mac_ctx, LOGE, + FL("SessionId:%d Received " + " WMA_ADD_BSS_RSP in state %X"), + session_entry->peSessionId, + session_entry->limMlmState); + mlm_start_cnf.resultCode = + eSIR_SME_BSS_ALREADY_STARTED_OR_JOINED; + if (0 != msg->bodyptr) { + qdf_mem_free(add_bss_param); + msg->bodyptr = NULL; + } + lim_post_sme_message(mac_ctx, LIM_MLM_START_CNF, + (uint32_t *) &mlm_start_cnf); + } else + lim_process_ap_mlm_add_bss_rsp(mac_ctx, msg); + } else { + /* Called while processing assoc response */ + lim_process_sta_mlm_add_bss_rsp(mac_ctx, msg, + session_entry); + } + } + +#ifdef WLAN_FEATURE_11W + if (session_entry->limRmfEnabled) { + if (eSIR_SUCCESS != + lim_send_exclude_unencrypt_ind(mac_ctx, false, + session_entry)) { + lim_log(mac_ctx, LOGE, + FL("Failed to send Exclude Unencrypted Ind.")); + } + } +#endif +} + +/** + * lim_process_mlm_set_sta_key_rsp() - Process STA key response + * + * @mac_ctx: Pointer to Global MAC structure + * @msg: The MsgQ header, which contains the response buffer + * + * This function is called to process the following two + * messages from HAL: + * 1) WMA_SET_BSSKEY_RSP + * 2) WMA_SET_STAKEY_RSP + * 3) WMA_SET_STA_BCASTKEY_RSP + * Upon receipt of this message from HAL, + * MLME - + * > Determines the "state" in which this message was received + * > Forwards it to the appropriate callback + * LOGIC: + * WMA_SET_BSSKEY_RSP/WMA_SET_STAKEY_RSP can be + * received by MLME while in the following state: + * MLME state = eLIM_MLM_WT_SET_BSS_KEY_STATE --OR-- + * MLME state = eLIM_MLM_WT_SET_STA_KEY_STATE --OR-- + * MLME state = eLIM_MLM_WT_SET_STA_BCASTKEY_STATE + * Based on this state, this API will determine where to + * route the message to + * Assumption: + * ONLY the MLME state is being taken into account for now. + * This is because, it appears that the handling of the + * SETKEYS REQ is handled symmetrically on both the AP & STA + * + * Return: None + */ +void lim_process_mlm_set_sta_key_rsp(tpAniSirGlobal mac_ctx, + tpSirMsgQ msg) +{ + uint8_t resp_reqd = 1; + tLimMlmSetKeysCnf mlm_set_key_cnf; + uint8_t session_id = 0; + tpPESession session_entry; + uint16_t key_len; + uint16_t result_status; + + SET_LIM_PROCESS_DEFD_MESGS(mac_ctx, true); + qdf_mem_set((void *)&mlm_set_key_cnf, sizeof(tLimMlmSetKeysCnf), 0); + if (NULL == msg->bodyptr) { + PELOGE(lim_log(mac_ctx, LOGE, FL("msg bodyptr is NULL"));) + return; + } + session_id = ((tpSetStaKeyParams) msg->bodyptr)->sessionId; + session_entry = pe_find_session_by_session_id(mac_ctx, session_id); + if (session_entry == NULL) { + PELOGE(lim_log(mac_ctx, LOGE, + FL("session does not exist for given session_id"));) + qdf_mem_free(msg->bodyptr); + msg->bodyptr = NULL; + return; + } + if (eLIM_MLM_WT_SET_STA_KEY_STATE != session_entry->limMlmState) { + /* Mesg received from HAL in Invalid state! */ + lim_log(mac_ctx, LOGE, + FL("Received unexpected [Mesg Id - %d] in state %X"), + msg->type, session_entry->limMlmState); + /* There's not much that MLME can do at this stage... */ + resp_reqd = 0; + } else { + mlm_set_key_cnf.resultCode = + (uint16_t)(((tpSetStaKeyParams) msg->bodyptr)->status); + } + + result_status = (uint16_t)(((tpSetStaKeyParams) msg->bodyptr)->status); + key_len = ((tpSetStaKeyParams)msg->bodyptr)->key[0].keyLength; + + if (result_status == eSIR_SME_SUCCESS && key_len) + mlm_set_key_cnf.key_len_nonzero = true; + else + mlm_set_key_cnf.key_len_nonzero = false; + + + qdf_mem_free(msg->bodyptr); + msg->bodyptr = NULL; + /* Restore MLME state */ + session_entry->limMlmState = session_entry->limPrevMlmState; + MTRACE(mac_trace(mac_ctx, TRACE_CODE_MLM_STATE, + session_entry->peSessionId, session_entry->limMlmState)); + if (resp_reqd) { + tpLimMlmSetKeysReq lpLimMlmSetKeysReq = + (tpLimMlmSetKeysReq) mac_ctx->lim.gpLimMlmSetKeysReq; + /* Prepare and Send LIM_MLM_SETKEYS_CNF */ + if (NULL != lpLimMlmSetKeysReq) { + qdf_copy_macaddr(&mlm_set_key_cnf.peer_macaddr, + &lpLimMlmSetKeysReq->peer_macaddr); + /* + * Free the buffer cached for the global + * mac_ctx->lim.gpLimMlmSetKeysReq + */ + qdf_mem_free(mac_ctx->lim.gpLimMlmSetKeysReq); + mac_ctx->lim.gpLimMlmSetKeysReq = NULL; + } + mlm_set_key_cnf.sessionId = session_id; + lim_post_sme_message(mac_ctx, LIM_MLM_SETKEYS_CNF, + (uint32_t *) &mlm_set_key_cnf); + } +} + +/** + * lim_process_mlm_set_bss_key_rsp() - handles BSS key + * + * @mac_ctx: A pointer to Global MAC structure + * @msg: Message from SME + * + * This function processes BSS key response and updates + * PE status accordingly. + * + * Return: NULL + */ +void lim_process_mlm_set_bss_key_rsp(tpAniSirGlobal mac_ctx, + tpSirMsgQ msg) +{ + tLimMlmSetKeysCnf set_key_cnf; + uint16_t result_status; + uint8_t session_id = 0; + tpPESession session_entry; + tpLimMlmSetKeysReq set_key_req; + uint16_t key_len; + + SET_LIM_PROCESS_DEFD_MESGS(mac_ctx, true); + qdf_mem_set((void *)&set_key_cnf, sizeof(tLimMlmSetKeysCnf), 0); + if (NULL == msg->bodyptr) { + PELOGE(lim_log(mac_ctx, LOGE, FL("msg bodyptr is null"));) + return; + } + session_id = ((tpSetBssKeyParams) msg->bodyptr)->sessionId; + session_entry = pe_find_session_by_session_id(mac_ctx, session_id); + if (session_entry == NULL) { + PELOGE(lim_log(mac_ctx, LOGE, + FL("session does not exist for given sessionId [%d]"), + session_id);) + qdf_mem_free(msg->bodyptr); + msg->bodyptr = NULL; + return; + } + if (eLIM_MLM_WT_SET_BSS_KEY_STATE == session_entry->limMlmState) { + result_status = + (uint16_t)(((tpSetBssKeyParams)msg->bodyptr)->status); + key_len = ((tpSetBssKeyParams)msg->bodyptr)->key[0].keyLength; + } else { + /* + * BCAST key also uses tpSetStaKeyParams. + * Done this way for readabilty. + */ + result_status = + (uint16_t)(((tpSetStaKeyParams)msg->bodyptr)->status); + key_len = ((tpSetStaKeyParams)msg->bodyptr)->key[0].keyLength; + } + + if (result_status == eSIR_SME_SUCCESS && key_len) + set_key_cnf.key_len_nonzero = true; + else + set_key_cnf.key_len_nonzero = false; + + /* Validate MLME state */ + if (eLIM_MLM_WT_SET_BSS_KEY_STATE != session_entry->limMlmState && + eLIM_MLM_WT_SET_STA_BCASTKEY_STATE != + session_entry->limMlmState) { + /* Msg received from HAL in Invalid state! */ + lim_log(mac_ctx, LOGE, + FL("Received unexpected [Mesg Id - %d] in state %X"), + msg->type, session_entry->limMlmState); + } else { + set_key_cnf.resultCode = result_status; + } + + qdf_mem_free(msg->bodyptr); + msg->bodyptr = NULL; + /* Restore MLME state */ + session_entry->limMlmState = session_entry->limPrevMlmState; + + MTRACE(mac_trace + (mac_ctx, TRACE_CODE_MLM_STATE, session_entry->peSessionId, + session_entry->limMlmState)); + set_key_req = + (tpLimMlmSetKeysReq) mac_ctx->lim.gpLimMlmSetKeysReq; + set_key_cnf.sessionId = session_id; + + /* Prepare and Send LIM_MLM_SETKEYS_CNF */ + if (NULL != set_key_req) { + qdf_copy_macaddr(&set_key_cnf.peer_macaddr, + &set_key_req->peer_macaddr); + /* + * Free the buffer cached for the + * global mac_ctx->lim.gpLimMlmSetKeysReq + */ + qdf_mem_free(mac_ctx->lim.gpLimMlmSetKeysReq); + mac_ctx->lim.gpLimMlmSetKeysReq = NULL; + } + lim_post_sme_message(mac_ctx, LIM_MLM_SETKEYS_CNF, + (uint32_t *) &set_key_cnf); +} + +/** + * lim_process_switch_channel_re_assoc_req() + * + ***FUNCTION: + * This function is called to send the reassoc req mgmt frame after the + * switchChannelRsp message is received from HAL. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param pMac - Pointer to Global MAC structure. + * @param psessionEntry - session related information. + * @param status - channel switch success/failure. + * + * @return None + */ +static void lim_process_switch_channel_re_assoc_req(tpAniSirGlobal pMac, + tpPESession psessionEntry, + QDF_STATUS status) +{ + tLimMlmReassocCnf mlmReassocCnf; + tLimMlmReassocReq *pMlmReassocReq; + pMlmReassocReq = + (tLimMlmReassocReq *) (psessionEntry->pLimMlmReassocReq); + if (pMlmReassocReq == NULL) { + lim_log(pMac, LOGP, + FL + ("pLimMlmReassocReq does not exist for given switchChanSession")); + mlmReassocCnf.resultCode = eSIR_SME_RESOURCES_UNAVAILABLE; + goto end; + } + + if (status != QDF_STATUS_SUCCESS) { + PELOGE(lim_log(pMac, LOGE, FL("Change channel failed!!"));) + mlmReassocCnf.resultCode = eSIR_SME_CHANNEL_SWITCH_FAIL; + goto end; + } + /* / Start reassociation failure timer */ + MTRACE(mac_trace + (pMac, TRACE_CODE_TIMER_ACTIVATE, psessionEntry->peSessionId, + eLIM_REASSOC_FAIL_TIMER)); + if (tx_timer_activate(&pMac->lim.limTimers.gLimReassocFailureTimer) + != TX_SUCCESS) { + /* / Could not start reassoc failure timer. */ + /* Log error */ + lim_log(pMac, LOGP, + FL("could not start Reassociation failure timer")); + /* Return Reassoc confirm with */ + /* Resources Unavailable */ + mlmReassocCnf.resultCode = eSIR_SME_RESOURCES_UNAVAILABLE; + goto end; + } + /* / Prepare and send Reassociation request frame */ + lim_send_reassoc_req_mgmt_frame(pMac, pMlmReassocReq, psessionEntry); + return; +end: + /* Free up buffer allocated for reassocReq */ + if (pMlmReassocReq != NULL) { + /* Update PE session Id */ + mlmReassocCnf.sessionId = pMlmReassocReq->sessionId; + qdf_mem_free(pMlmReassocReq); + psessionEntry->pLimMlmReassocReq = NULL; + } else { + mlmReassocCnf.sessionId = 0; + } + + mlmReassocCnf.protStatusCode = eSIR_MAC_UNSPEC_FAILURE_STATUS; + /* Update PE sessio Id */ + mlmReassocCnf.sessionId = psessionEntry->peSessionId; + + lim_post_sme_message(pMac, LIM_MLM_REASSOC_CNF, + (uint32_t *) &mlmReassocCnf); +} + + +/** + * lim_process_switch_channel_join_req() -Initiates probe request + * + * @mac_ctx - A pointer to Global MAC structure + * @sessionEntry - session related information. + * @status - channel switch success/failure + * + * This function is called to send the probe req mgmt frame + * after the switchChannelRsp message is received from HAL. + * + * Return None + */ +static void lim_process_switch_channel_join_req( + tpAniSirGlobal mac_ctx, tpPESession session_entry, + QDF_STATUS status) +{ + tSirMacSSid ssId; + tLimMlmJoinCnf join_cnf; + if (status != QDF_STATUS_SUCCESS) { + PELOGE(lim_log(mac_ctx, LOGE, FL("Change channel failed!!"));) + goto error; + } + + if ((NULL == session_entry) || (NULL == session_entry->pLimMlmJoinReq) + || (NULL == session_entry->pLimJoinReq)) { + PELOGE(lim_log(mac_ctx, LOGE, FL("invalid pointer!!"));) + goto error; + } + + session_entry->limPrevMlmState = session_entry->limMlmState; + session_entry->limMlmState = eLIM_MLM_WT_JOIN_BEACON_STATE; + lim_log(mac_ctx, LOG1, + FL("Sessionid %d prev lim state %d new lim state %d " + "systemrole = %d"), session_entry->peSessionId, + session_entry->limPrevMlmState, + session_entry->limMlmState, GET_LIM_SYSTEM_ROLE(session_entry)); + + /* Apply previously set configuration at HW */ + lim_apply_configuration(mac_ctx, session_entry); + + /* + * If sendDeauthBeforeCon is enabled, Send Deauth first to AP if last + * disconnection was caused by HB failure. + */ + if (mac_ctx->roam.configParam.sendDeauthBeforeCon) { + int apCount; + + for (apCount = 0; apCount < 2; apCount++) { + + if (!qdf_mem_cmp(session_entry->pLimMlmJoinReq->bssDescription.bssId, + mac_ctx->lim.gLimHeartBeatApMac[apCount], sizeof(tSirMacAddr))) { + + lim_log(mac_ctx, LOGE, FL("Index %d Sessionid: %d Send deauth on " + "channel %d to BSSID: "MAC_ADDRESS_STR), apCount, + session_entry->peSessionId, session_entry->currentOperChannel, + MAC_ADDR_ARRAY(session_entry->pLimMlmJoinReq->bssDescription. + bssId)); + + lim_send_deauth_mgmt_frame(mac_ctx, eSIR_MAC_UNSPEC_FAILURE_REASON, + session_entry->pLimMlmJoinReq->bssDescription.bssId, + session_entry, false); + + qdf_mem_zero(mac_ctx->lim.gLimHeartBeatApMac[apCount], + sizeof(tSirMacAddr)); + break; + } + } + } + + /* Wait for Beacon to announce join success */ + qdf_mem_copy(ssId.ssId, + session_entry->ssId.ssId, session_entry->ssId.length); + ssId.length = session_entry->ssId.length; + + lim_deactivate_and_change_timer(mac_ctx, + eLIM_PERIODIC_JOIN_PROBE_REQ_TIMER); + + /* assign appropriate sessionId to the timer object */ + mac_ctx->lim.limTimers.gLimPeriodicJoinProbeReqTimer.sessionId = + session_entry->peSessionId; + lim_log(mac_ctx, LOG1, + FL("Sessionid: %d Send Probe req on channel %d ssid:%.*s " + "BSSID: " MAC_ADDRESS_STR), session_entry->peSessionId, + session_entry->currentOperChannel, ssId.length, ssId.ssId, + MAC_ADDR_ARRAY( + session_entry->pLimMlmJoinReq->bssDescription.bssId)); + + /* + * We need to wait for probe response, so start join + * timeout timer.This timer will be deactivated once + * we receive probe response. + */ + MTRACE(mac_trace(mac_ctx, TRACE_CODE_TIMER_ACTIVATE, + session_entry->peSessionId, eLIM_JOIN_FAIL_TIMER)); + if (tx_timer_activate(&mac_ctx->lim.limTimers.gLimJoinFailureTimer) != + TX_SUCCESS) { + lim_log(mac_ctx, LOGP, + FL("couldn't activate Join failure timer")); + session_entry->limMlmState = session_entry->limPrevMlmState; + MTRACE(mac_trace(mac_ctx, TRACE_CODE_MLM_STATE, + session_entry->peSessionId, + mac_ctx->lim.gLimMlmState)); + goto error; + } + /* include additional IE if there is */ + lim_send_probe_req_mgmt_frame(mac_ctx, &ssId, + session_entry->pLimMlmJoinReq->bssDescription.bssId, + session_entry->currentOperChannel, session_entry->selfMacAddr, + session_entry->dot11mode, + session_entry->pLimJoinReq->addIEScan.length, + session_entry->pLimJoinReq->addIEScan.addIEdata); + + if (session_entry->pePersona == QDF_P2P_CLIENT_MODE) { + /* Activate Join Periodic Probe Req timer */ + if (tx_timer_activate + (&mac_ctx->lim.limTimers.gLimPeriodicJoinProbeReqTimer) + != TX_SUCCESS) { + lim_log(mac_ctx, LOGP, + FL("Periodic JoinReq timer activate failed")); + goto error; + } + } + return; +error: + if (NULL != session_entry) { + if (session_entry->pLimMlmJoinReq) { + qdf_mem_free(session_entry->pLimMlmJoinReq); + session_entry->pLimMlmJoinReq = NULL; + } + if (session_entry->pLimJoinReq) { + qdf_mem_free(session_entry->pLimJoinReq); + session_entry->pLimJoinReq = NULL; + } + join_cnf.sessionId = session_entry->peSessionId; + } else { + join_cnf.sessionId = 0; + } + join_cnf.resultCode = eSIR_SME_RESOURCES_UNAVAILABLE; + join_cnf.protStatusCode = eSIR_MAC_UNSPEC_FAILURE_STATUS; + lim_post_sme_message(mac_ctx, LIM_MLM_JOIN_CNF, (uint32_t *)&join_cnf); +} + +/** + * lim_process_switch_channel_rsp() + * + ***FUNCTION: + * This function is called to process switchChannelRsp message from HAL. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param pMac - Pointer to Global MAC structure + * @param body - message body. + * + * @return None + */ +void lim_process_switch_channel_rsp(tpAniSirGlobal pMac, void *body) +{ + tpSwitchChannelParams pChnlParams = NULL; + QDF_STATUS status; + uint16_t channelChangeReasonCode; + uint8_t peSessionId; + tpPESession psessionEntry; + /* we need to process the deferred message since the initiating req. there might be nested request. */ + /* in the case of nested request the new request initiated from the response will take care of resetting */ + /* the deffered flag. */ + SET_LIM_PROCESS_DEFD_MESGS(pMac, true); + pChnlParams = (tpSwitchChannelParams) body; + status = pChnlParams->status; + peSessionId = pChnlParams->peSessionId; + + psessionEntry = pe_find_session_by_session_id(pMac, peSessionId); + if (psessionEntry == NULL) { + lim_log(pMac, LOGP, + FL("session does not exist for given sessionId")); + return; + } + psessionEntry->ch_switch_in_progress = false; + /* HAL fills in the tx power used for mgmt frames in this field. */ + /* Store this value to use in TPC report IE. */ + rrm_cache_mgmt_tx_power(pMac, pChnlParams->txMgmtPower, psessionEntry); + channelChangeReasonCode = psessionEntry->channelChangeReasonCode; + /* initialize it back to invalid id */ + psessionEntry->chainMask = pChnlParams->chainMask; + psessionEntry->smpsMode = pChnlParams->smpsMode; + psessionEntry->channelChangeReasonCode = 0xBAD; + lim_log(pMac, LOG1, FL("channelChangeReasonCode %d"), + channelChangeReasonCode); + switch (channelChangeReasonCode) { + case LIM_SWITCH_CHANNEL_REASSOC: + lim_process_switch_channel_re_assoc_req(pMac, psessionEntry, status); + break; + case LIM_SWITCH_CHANNEL_JOIN: + lim_process_switch_channel_join_req(pMac, psessionEntry, status); + break; + + case LIM_SWITCH_CHANNEL_OPERATION: + /* + * The above code should also use the callback. + * mechanism below, there is scope for cleanup here. + * THat way all this response handler does is call the call back + * We can get rid of the reason code here. + */ + if (pMac->lim.gpchangeChannelCallback) { + PELOG1(lim_log + (pMac, LOG1, + "Channel changed hence invoke registered call back"); + ) + pMac->lim.gpchangeChannelCallback(pMac, status, + pMac->lim. + gpchangeChannelData, + psessionEntry); + } + /* If MCC upgrade/DBS downgrade happended during channel switch, + * the policy manager connection table needs to be updated. + */ + cds_update_connection_info(psessionEntry->smeSessionId); + if (psessionEntry->pePersona == QDF_P2P_CLIENT_MODE) { + lim_log(pMac, LOG1, + FL("Send p2p operating channel change conf action frame once first beacon is received on new channel")); + psessionEntry->send_p2p_conf_frame = true; + } + break; + case LIM_SWITCH_CHANNEL_SAP_DFS: + { + /* Note: This event code specific to SAP mode + * When SAP session issues channel change as performing + * DFS, we will come here. Other sessions, for e.g. P2P + * will have to define their own event code and channel + * switch handler. This is required since the SME may + * require completely different information for P2P unlike + * SAP. + */ + lim_send_sme_ap_channel_switch_resp(pMac, psessionEntry, + pChnlParams); + /* If MCC upgrade/DBS downgrade happended during channel switch, + * the policy manager connection table needs to be updated. + */ + cds_update_connection_info(psessionEntry->smeSessionId); + cds_set_do_hw_mode_change_flag(true); + } + break; + default: + break; + } + qdf_mem_free(body); +} + +void lim_send_beacon_ind(tpAniSirGlobal pMac, tpPESession psessionEntry) +{ + tBeaconGenParams *pBeaconGenParams = NULL; + tSirMsgQ limMsg; + /** Allocate the Memory for Beacon Pre Message and for Stations in PoweSave*/ + if (psessionEntry == NULL) { + PELOGE(lim_log(pMac, LOGE, + FL("Error:Unable to get the PESessionEntry")); + ) + return; + } + pBeaconGenParams = qdf_mem_malloc(sizeof(*pBeaconGenParams)); + if (NULL == pBeaconGenParams) { + PELOGE(lim_log(pMac, LOGP, + FL + ("Unable to allocate memory during sending beaconPreMessage")); + ) + return; + } + qdf_mem_copy((void *)pBeaconGenParams->bssId, + (void *)psessionEntry->bssId, QDF_MAC_ADDR_SIZE); + limMsg.bodyptr = pBeaconGenParams; + sch_process_pre_beacon_ind(pMac, &limMsg); + return; +} + +#ifdef FEATURE_WLAN_SCAN_PNO +/** + * lim_send_sme_scan_cache_updated_ind() + * + ***FUNCTION: + * This function is used to post WMA_SME_SCAN_CACHE_UPDATED message to WMA. + * This message is the indication to WMA that all scan cache results + * are updated from LIM to SME. Mainly used only in PNO offload case. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * This function should be called after posting scan cache results to SME. + * + ***NOTE: + * NA + * + * @return None + */ +static void lim_send_sme_scan_cache_updated_ind(uint8_t sessionId) +{ + cds_msg_t msg; + + msg.type = WMA_SME_SCAN_CACHE_UPDATED; + msg.reserved = 0; + msg.bodyptr = NULL; + msg.bodyval = sessionId; + + if (!QDF_IS_STATUS_SUCCESS + (cds_mq_post_message(QDF_MODULE_ID_WMA, &msg))) + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Not able to post WMA_SME_SCAN_CACHE_UPDATED message to WMA", + __func__); +} +#endif + +static void lim_send_scan_offload_complete(tpAniSirGlobal pMac, + tSirScanOffloadEvent *pScanEvent) +{ + + pMac->lim.gLimRspReqd = false; + lim_send_sme_scan_rsp(pMac, pScanEvent->reasonCode, + pScanEvent->sessionId, 0, pScanEvent->scanId); +#ifdef FEATURE_WLAN_SCAN_PNO + lim_send_sme_scan_cache_updated_ind(pScanEvent->sessionId); +#endif +} + +void lim_process_rx_scan_event(tpAniSirGlobal pMac, void *buf) +{ + tSirScanOffloadEvent *pScanEvent = (tSirScanOffloadEvent *) buf; + + switch (pScanEvent->event) { + case SIR_SCAN_EVENT_STARTED: + break; + case SIR_SCAN_EVENT_COMPLETED: + lim_log(pMac, LOG1, FL("No.of beacons and probe response received per scan %d"), + pMac->lim.beacon_probe_rsp_cnt_per_scan); +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM /* FEATURE_WLAN_DIAG_SUPPORT */ + lim_diag_event_report(pMac, WLAN_PE_DIAG_SCAN_COMPLETE_EVENT, NULL, + eSIR_SUCCESS, eSIR_SUCCESS); + if (pMac->lim.beacon_probe_rsp_cnt_per_scan) + lim_diag_event_report(pMac, + WLAN_PE_DIAG_SCAN_RESULT_FOUND_EVENT, + NULL, eSIR_SUCCESS, eSIR_SUCCESS); +#endif + /* Fall through */ + case SIR_SCAN_EVENT_START_FAILED: + if (ROC_SCAN_REQUESTOR_ID == pScanEvent->requestor) { + lim_send_sme_roc_rsp(pMac, eWNI_SME_REMAIN_ON_CHN_RSP, + QDF_STATUS_SUCCESS, + pScanEvent->sessionId, + pScanEvent->scanId); + qdf_mem_free(pMac->lim.gpLimRemainOnChanReq); + pMac->lim.gpLimRemainOnChanReq = NULL; + /* + * If remain on channel timer expired and action frame + * is pending then indicate confirmation with status + * failure. + */ + if (pMac->lim.mgmtFrameSessionId != 0xff) { + lim_p2p_action_cnf(pMac, false); + pMac->lim.mgmtFrameSessionId = 0xff; + } + } else if (PREAUTH_REQUESTOR_ID == pScanEvent->requestor) { + lim_preauth_scan_event_handler(pMac, pScanEvent->event, + pScanEvent->sessionId, + pScanEvent->scanId); + } else { + lim_send_scan_offload_complete(pMac, pScanEvent); + } + break; + case SIR_SCAN_EVENT_FOREIGN_CHANNEL: + if (ROC_SCAN_REQUESTOR_ID == pScanEvent->requestor) { + /*Send Ready on channel indication to SME */ + if (pMac->lim.gpLimRemainOnChanReq) { + lim_send_sme_roc_rsp(pMac, + eWNI_SME_REMAIN_ON_CHN_RDY_IND, + QDF_STATUS_SUCCESS, + pScanEvent->sessionId, + pScanEvent->scanId); + } else { + lim_log(pMac, LOGE, + FL("gpLimRemainOnChanReq is NULL")); + } + } else if (PREAUTH_REQUESTOR_ID == pScanEvent->requestor) { + lim_preauth_scan_event_handler(pMac, pScanEvent->event, + pScanEvent->sessionId, + pScanEvent->scanId); + } + break; + case SIR_SCAN_EVENT_BSS_CHANNEL: + case SIR_SCAN_EVENT_DEQUEUED: + case SIR_SCAN_EVENT_PREEMPTED: + default: + QDF_TRACE(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_DEBUG, + "Received unhandled scan event %u", + pScanEvent->event); + } + qdf_mem_free(buf); +} diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_process_probe_req_frame.c b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_process_probe_req_frame.c new file mode 100644 index 0000000000000000000000000000000000000000..1cea1deda676831607a76986f46a7331c71d829c --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_process_probe_req_frame.c @@ -0,0 +1,697 @@ +/* + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * This file lim_process_probe_req_frame.cc contains the code + * for processing Probe Request Frame. + * Author: Chandra Modumudi + * Date: 02/28/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + * + */ + +#include "wni_cfg.h" +#include "ani_global.h" +#include "cfg_api.h" + +#include "utils_api.h" +#include "lim_types.h" +#include "lim_utils.h" +#include "lim_assoc_utils.h" +#include "lim_ser_des_utils.h" +#include "parser_api.h" +#include "lim_ft_defs.h" +#include "lim_session.h" + +void + +lim_send_sme_probe_req_ind(tpAniSirGlobal pMac, + tSirMacAddr peerMacAddr, + uint8_t *pProbeReqIE, + uint32_t ProbeReqIELen, tpPESession psessionEntry); + +/** + * lim_get_wpspbc_sessions() - to get wps pbs sessions + * @mac_ctx: Pointer to Global MAC structure + * @addr: probe request source MAC addresss + * @uuid_e: A pointer to UUIDE element of WPS IE in WPS PBC probe request + * @session: A pointer to station PE session + * + * This function is called to query the WPS PBC overlap. This function + * check WPS PBC probe request link list for PBC overlap + * + * @return None + */ + +void lim_get_wpspbc_sessions(tpAniSirGlobal mac_ctx, struct qdf_mac_addr addr, + uint8_t *uuid_e, eWPSPBCOverlap *overlap, + tpPESession session) +{ + int count = 0; + tSirWPSPBCSession *pbc; + uint32_t cur_time; + + cur_time = (uint32_t) (qdf_mc_timer_get_system_ticks() / + QDF_TICKS_PER_SECOND); + qdf_zero_macaddr(&addr); + qdf_mem_set((uint8_t *) uuid_e, SIR_WPS_UUID_LEN, 0); + for (pbc = session->pAPWPSPBCSession; pbc; pbc = pbc->next) { + if (cur_time > pbc->timestamp + SIR_WPS_PBC_WALK_TIME) + break; + count++; + if (count > 1) + break; + qdf_copy_macaddr(&addr, &pbc->addr); + qdf_mem_copy((uint8_t *) uuid_e, (uint8_t *) pbc->uuid_e, + SIR_WPS_UUID_LEN); + } + if (count > 1) + /* Overlap */ + *overlap = eSAP_WPSPBC_OVERLAP_IN120S; + else if (count == 0) + /* no WPS probe request in 120 second */ + *overlap = eSAP_WPSPBC_NO_WPSPBC_PROBE_REQ_IN120S; + else + /* One WPS probe request in 120 second */ + *overlap = eSAP_WPSPBC_ONE_WPSPBC_PROBE_REQ_IN120S; + + lim_log(mac_ctx, LOGE, FL("overlap = %d"), *overlap); + sir_dump_buf(mac_ctx, SIR_LIM_MODULE_ID, LOGE, addr.bytes, + QDF_MAC_ADDR_SIZE); + sir_dump_buf(mac_ctx, SIR_LIM_MODULE_ID, LOGE, uuid_e, + SIR_WPS_UUID_LEN); + return; +} + +/** + * lim_remove_timeout_pbc_sessions() - remove pbc probe req entries. + * @pMac - Pointer to Global MAC structure + * @pbc - The beginning entry in WPS PBC probe request link list + * + * This function is called to remove the WPS PBC probe request entries from + * specific entry to end. + * + * Return - None + */ +static void lim_remove_timeout_pbc_sessions(tpAniSirGlobal pMac, + tSirWPSPBCSession *pbc) +{ + tSirWPSPBCSession *prev; + + while (pbc) { + prev = pbc; + pbc = pbc->next; + + PELOG4(lim_log(pMac, LOG4, FL("WPS PBC sessions remove"));) + PELOG4(sir_dump_buf + (pMac, SIR_LIM_MODULE_ID, LOG4, prev->addr, + sizeof(tSirMacAddr)); + ) + PELOG4(sir_dump_buf + (pMac, SIR_LIM_MODULE_ID, LOG4, prev->uuid_e, + SIR_WPS_UUID_LEN); + ) + + qdf_mem_free(prev); + } +} + +/** + * lim_remove_pbc_sessions() - Remove PBC sessions + * @mac: Pointer to Global MAC structure + * @remove_mac: MAC Address of STA in WPS Session to be removed + * @session_entry: session entry + * + * Return: none + */ +void lim_remove_pbc_sessions(tpAniSirGlobal mac, struct qdf_mac_addr remove_mac, + tpPESession session_entry) +{ + tSirWPSPBCSession *pbc, *prev = NULL; + prev = pbc = session_entry->pAPWPSPBCSession; + + while (pbc) { + if (qdf_is_macaddr_equal(&pbc->addr, &remove_mac)) { + prev->next = pbc->next; + if (pbc == session_entry->pAPWPSPBCSession) + session_entry->pAPWPSPBCSession = pbc->next; + qdf_mem_free(pbc); + return; + } + prev = pbc; + pbc = pbc->next; + } +} + +/** + * lim_update_pbc_session_entry + * + ***FUNCTION: + * This function is called when probe request with WPS PBC IE is received + * + ***LOGIC: + * This function add the WPS PBC probe request in the WPS PBC probe request link list + * The link list is in decreased time order of probe request that is received. + * The entry that is more than 120 second is removed. + * + ***ASSUMPTIONS: + * + * + ***NOTE: + * + * @param pMac Pointer to Global MAC structure + * @param addr A pointer to probe request source MAC addresss + * @param uuid_e A pointer to UUIDE element of WPS IE + * @param psessionEntry A pointer to station PE session + * + * @return None + */ + +static void lim_update_pbc_session_entry(tpAniSirGlobal pMac, + uint8_t *addr, uint8_t *uuid_e, + tpPESession psessionEntry) +{ + tSirWPSPBCSession *pbc, *prev = NULL; + + uint32_t curTime; + + curTime = + (uint32_t) (qdf_mc_timer_get_system_ticks() / + QDF_TICKS_PER_SECOND); + + PELOG4(lim_log + (pMac, LOG4, FL("Receive WPS probe reques curTime=%d"), curTime); + ) + PELOG4(sir_dump_buf + (pMac, SIR_LIM_MODULE_ID, LOG4, addr, sizeof(tSirMacAddr)); + ) + PELOG4(sir_dump_buf + (pMac, SIR_LIM_MODULE_ID, LOG4, uuid_e, SIR_WPS_UUID_LEN); + ) + + pbc = psessionEntry->pAPWPSPBCSession; + + while (pbc) { + if ((!qdf_mem_cmp + ((uint8_t *) pbc->addr.bytes, (uint8_t *) addr, + QDF_MAC_ADDR_SIZE)) + && (!qdf_mem_cmp((uint8_t *) pbc->uuid_e, + (uint8_t *) uuid_e, SIR_WPS_UUID_LEN))) { + if (prev) + prev->next = pbc->next; + else + psessionEntry->pAPWPSPBCSession = pbc->next; + break; + } + prev = pbc; + pbc = pbc->next; + } + + if (!pbc) { + pbc = qdf_mem_malloc(sizeof(tSirWPSPBCSession)); + if (NULL == pbc) { + PELOGE(lim_log + (pMac, LOGE, FL("memory allocate failed!")); + ) + return; + } + qdf_mem_copy((uint8_t *) pbc->addr.bytes, (uint8_t *) addr, + QDF_MAC_ADDR_SIZE); + + if (uuid_e) + qdf_mem_copy((uint8_t *) pbc->uuid_e, + (uint8_t *) uuid_e, SIR_WPS_UUID_LEN); + } + + pbc->next = psessionEntry->pAPWPSPBCSession; + psessionEntry->pAPWPSPBCSession = pbc; + pbc->timestamp = curTime; + + /* remove entries that have timed out */ + prev = pbc; + pbc = pbc->next; + + while (pbc) { + if (curTime > pbc->timestamp + SIR_WPS_PBC_WALK_TIME) { + prev->next = NULL; + lim_remove_timeout_pbc_sessions(pMac, pbc); + break; + } + prev = pbc; + pbc = pbc->next; + } +} + +/** + * lim_wpspbc_close + * + ***FUNCTION: + * This function is called when BSS is closed + * + ***LOGIC: + * This function remove all the WPS PBC entries + * + ***ASSUMPTIONS: + * + * + ***NOTE: + * + * @param pMac Pointer to Global MAC structure + * @param psessionEntry A pointer to station PE session + * + * @return None + */ + +void lim_wpspbc_close(tpAniSirGlobal pMac, tpPESession psessionEntry) +{ + + lim_remove_timeout_pbc_sessions(pMac, psessionEntry->pAPWPSPBCSession); + +} + +/** + * lim_check11b_rates + * + ***FUNCTION: + * This function is called by lim_process_probe_req_frame() upon + * Probe Request frame reception. + * + ***LOGIC: + * This function check 11b rates in supportedRates and extendedRates rates + * + ***NOTE: + * + * @param rate + * + * @return BOOLEAN + */ + +static bool lim_check11b_rates(uint8_t rate) +{ + if ((0x02 == (rate)) + || (0x04 == (rate)) + || (0x0b == (rate)) + || (0x16 == (rate)) + ) { + return true; + } + return false; +} + +/** + * lim_process_probe_req_frame: to process probe req frame + * @mac_ctx: Pointer to Global MAC structure + * @rx_pkt_info: A pointer to Buffer descriptor + associated PDUs + * @session: a ponter to session entry + * + * This function is called by limProcessMessageQueue() upon + * Probe Request frame reception. This function processes received + * Probe Request frame and responds with Probe Response. + * Only AP or STA in IBSS mode that sent last Beacon will respond to + * Probe Request. + * ASSUMPTIONS: + * 1. AP or STA in IBSS mode that sent last Beacon will always respond + * to Probe Request received with broadcast SSID. + * NOTE: + * 1. Dunno what to do with Rates received in Probe Request frame + * 2. Frames with out-of-order fields/IEs are dropped. + * + * + * Return: none + */ + +void +lim_process_probe_req_frame(tpAniSirGlobal mac_ctx, uint8_t *rx_pkt_info, + tpPESession session) +{ + uint8_t *body_ptr; + tpSirMacMgmtHdr mac_hdr; + uint32_t frame_len; + tSirProbeReq probe_req; + tAniSSID ssid; + + /* Don't send probe responses if disabled */ + if (mac_ctx->lim.gLimProbeRespDisableFlag) + return; + + /* + * Don't send probe response if P2P go is scanning till scan + * come to idle state. + */ + if ((session->pePersona == QDF_P2P_GO_MODE) && + ((mac_ctx->lim.gpLimRemainOnChanReq) || + (mac_ctx->lim.gLimHalScanState != eLIM_HAL_IDLE_SCAN_STATE))) { + lim_log(mac_ctx, LOG3, + FL("GO is scanning, don't send probersp on diff chnl")); + return; + } + mac_hdr = WMA_GET_RX_MAC_HEADER(rx_pkt_info); + if (LIM_IS_AP_ROLE(session) || + (LIM_IS_IBSS_ROLE(session) && + (WMA_GET_RX_BEACON_SENT(rx_pkt_info)))) { + frame_len = WMA_GET_RX_PAYLOAD_LEN(rx_pkt_info); + + lim_log(mac_ctx, LOG3, + FL("Received Probe Request %d bytes from "), + frame_len); + lim_print_mac_addr(mac_ctx, mac_hdr->sa, LOG3); + /* Get pointer to Probe Request frame body */ + body_ptr = WMA_GET_RX_MPDU_DATA(rx_pkt_info); + + /* check for vendor IE presence */ + if ((session->access_policy_vendor_ie) && + (session->access_policy == + LIM_ACCESS_POLICY_RESPOND_IF_IE_IS_PRESENT)) { + if (!cfg_get_vendor_ie_ptr_from_oui(mac_ctx, + &session->access_policy_vendor_ie[2], + 3, body_ptr, frame_len)) { + lim_log(mac_ctx, LOG1, FL( + "Vendor IE is not present and access policy is %x, dropping probe request"), + session->access_policy); + return; + } + } + + /* Parse Probe Request frame */ + if (sir_convert_probe_req_frame2_struct(mac_ctx, body_ptr, + frame_len, &probe_req) == eSIR_FAILURE) { + lim_log(mac_ctx, LOGE, + FL("Parse error ProbeReq, length=%d, SA is: " + MAC_ADDRESS_STR), frame_len, + MAC_ADDR_ARRAY(mac_hdr->sa)); + mac_ctx->sys.probeError++; + return; + } + if (session->pePersona == QDF_P2P_GO_MODE) { + uint8_t i = 0, rate_11b = 0, other_rates = 0; + /* Check 11b rates in supported rates */ + for (i = 0; i < probe_req.supportedRates.numRates; + i++) { + if (lim_check11b_rates( + probe_req.supportedRates.rate[i] & + 0x7f)) + rate_11b++; + else + other_rates++; + } + + /* Check 11b rates in extended rates */ + for (i = 0; i < probe_req.extendedRates.numRates; i++) { + if (lim_check11b_rates( + probe_req.extendedRates.rate[i] & 0x7f)) + rate_11b++; + else + other_rates++; + } + + if ((rate_11b > 0) && (other_rates == 0)) { + lim_log(mac_ctx, LOG3, + FL("Received a probe req frame with only 11b rates, SA is: ")); + lim_print_mac_addr(mac_ctx, + mac_hdr->sa, LOG3); + return; + } + } + if (LIM_IS_AP_ROLE(session) && + ((session->APWPSIEs.SirWPSProbeRspIE.FieldPresent + & SIR_WPS_PROBRSP_VER_PRESENT) + && (probe_req.wscIePresent == 1) + && (probe_req.probeReqWscIeInfo.DevicePasswordID.id == + WSC_PASSWD_ID_PUSH_BUTTON) + && (probe_req.probeReqWscIeInfo.UUID_E.present == 1))) { + if (session->fwdWPSPBCProbeReq) { + sir_dump_buf(mac_ctx, SIR_LIM_MODULE_ID, + LOG4, mac_hdr->sa, sizeof(tSirMacAddr)); + sir_dump_buf(mac_ctx, SIR_LIM_MODULE_ID, + LOG4, body_ptr, frame_len); + lim_send_sme_probe_req_ind(mac_ctx, mac_hdr->sa, + body_ptr, frame_len, session); + } else { + lim_update_pbc_session_entry(mac_ctx, + mac_hdr->sa, + probe_req.probeReqWscIeInfo.UUID_E.uuid, + session); + } + } + ssid.length = session->ssId.length; + /* Copy the SSID from sessio entry to local variable */ + qdf_mem_copy(ssid.ssId, session->ssId.ssId, + session->ssId.length); + + /* + * Compare received SSID with current SSID. If they match, + * reply with Probe Response + */ + if (probe_req.ssId.length) { + if (!ssid.length) + goto multipleSSIDcheck; + + if (!qdf_mem_cmp((uint8_t *) &ssid, + (uint8_t *) &(probe_req.ssId), + (uint8_t) (ssid.length + 1))) { + lim_send_probe_rsp_mgmt_frame(mac_ctx, + mac_hdr->sa, &ssid, + DPH_USE_MGMT_STAID, + DPH_NON_KEEPALIVE_FRAME, + session, + probe_req.p2pIePresent); + return; + } else if (session->pePersona == + QDF_P2P_GO_MODE) { + uint8_t direct_ssid[7] = "DIRECT-"; + uint8_t direct_ssid_len = 7; + if (!qdf_mem_cmp((uint8_t *) &direct_ssid, + (uint8_t *) &(probe_req.ssId.ssId), + (uint8_t) (direct_ssid_len))) { + lim_send_probe_rsp_mgmt_frame(mac_ctx, + mac_hdr->sa, + &ssid, + DPH_USE_MGMT_STAID, + DPH_NON_KEEPALIVE_FRAME, + session, + probe_req.p2pIePresent); + return; + } + } else { + lim_log(mac_ctx, LOG3, + FL("Ignore ProbeReq frm with unmatch SSID received from ")); + lim_print_mac_addr(mac_ctx, mac_hdr->sa, + LOG3); + mac_ctx->sys.probeBadSsid++; + } + } else { + /* + * Broadcast SSID in the Probe Request. + * Reply with SSID we're configured with. + * Turn off the SSID length to 0 if hidden SSID feature + * is present + */ + if (session->ssidHidden) + /* + * We are returning from here as probe request + * contains the broadcast SSID. So no need to + * send the probe resp + */ + return; + lim_send_probe_rsp_mgmt_frame(mac_ctx, mac_hdr->sa, + &ssid, + DPH_USE_MGMT_STAID, + DPH_NON_KEEPALIVE_FRAME, + session, + probe_req.p2pIePresent); + return; + } +multipleSSIDcheck: + lim_log(mac_ctx, LOG3, + FL("Ignore ProbeReq frm with unmatch SSID rcved from")); + lim_print_mac_addr(mac_ctx, mac_hdr->sa, LOG3); + mac_ctx->sys.probeBadSsid++; + } else { + /* Ignore received Probe Request frame */ + lim_log(mac_ctx, LOG3, + FL("Ignoring Probe Request frame received from ")); + lim_print_mac_addr(mac_ctx, mac_hdr->sa, LOG3); + mac_ctx->sys.probeIgnore++; + } + return; +} + +/** + * lim_indicate_probe_req_to_hdd + * + ***FUNCTION: + * This function is called by lim_process_probe_req_frame_multiple_bss() upon + * Probe Request frame reception. + * + ***LOGIC: + * This function processes received Probe Request frame and Pass + * Probe Request Frame to HDD. + * + * @param pMac Pointer to Global MAC structure + * @param *pBd A pointer to Buffer descriptor + associated PDUs + * @param psessionEntry A pointer to PE session + * + * @return None + */ + +static void +lim_indicate_probe_req_to_hdd(tpAniSirGlobal pMac, uint8_t *pBd, + tpPESession psessionEntry) +{ + tpSirMacMgmtHdr pHdr; + uint32_t frameLen; + + lim_log(pMac, LOG1, "Received a probe request frame"); + + pHdr = WMA_GET_RX_MAC_HEADER(pBd); + frameLen = WMA_GET_RX_PAYLOAD_LEN(pBd); + + /* send the probe req to SME. */ + lim_send_sme_mgmt_frame_ind(pMac, pHdr->fc.subType, + (uint8_t *) pHdr, + (frameLen + sizeof(tSirMacMgmtHdr)), + psessionEntry->smeSessionId, WMA_GET_RX_CH(pBd), + psessionEntry, 0); +} /*** end lim_indicate_probe_req_to_hdd() ***/ + +/** + * lim_process_probe_req_frame_multiple_bss() - to process probe req + * @mac_ctx: Pointer to Global MAC structure + * @buf_descr: A pointer to Buffer descriptor + associated PDUs + * @session: A pointer to PE session + * + * This function is called by limProcessMessageQueue() upon + * Probe Request frame reception. This function call + * lim_indicate_probe_req_to_hdd function to indicate + * Probe Request frame to HDD. It also call lim_process_probe_req_frame + * function which process received Probe Request frame and responds + * with Probe Response. + * + * @return None + */ +void +lim_process_probe_req_frame_multiple_bss(tpAniSirGlobal mac_ctx, + uint8_t *buf_descr, tpPESession session) +{ + uint8_t i; + + if (session != NULL) { + if (LIM_IS_AP_ROLE(session)) { + lim_indicate_probe_req_to_hdd(mac_ctx, + buf_descr, session); + } + lim_process_probe_req_frame(mac_ctx, buf_descr, session); + return; + } + + for (i = 0; i < mac_ctx->lim.maxBssId; i++) { + session = pe_find_session_by_session_id(mac_ctx, i); + if (session == NULL) + continue; + if (LIM_IS_AP_ROLE(session)) + lim_indicate_probe_req_to_hdd(mac_ctx, + buf_descr, session); + if (LIM_IS_AP_ROLE(session) || + LIM_IS_IBSS_ROLE(session)) + lim_process_probe_req_frame(mac_ctx, + buf_descr, session); + } +} + +/** + * lim_send_sme_probe_req_ind() + * + ***FUNCTION: + * This function is to send + * eWNI_SME_WPS_PBC_PROBE_REQ_IND message to host + * + ***PARAMS: + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * This function is used for sending eWNI_SME_WPS_PBC_PROBE_REQ_IND + * to host. + * + * @param peerMacAddr Indicates the peer MAC addr that the probe request + * is generated. + * @param pProbeReqIE pointer to RAW probe request IE + * @param ProbeReqIELen The length of probe request IE. + * @param psessionEntry A pointer to PE session + * + * @return None + */ +void +lim_send_sme_probe_req_ind(tpAniSirGlobal pMac, + tSirMacAddr peerMacAddr, + uint8_t *pProbeReqIE, + uint32_t ProbeReqIELen, tpPESession psessionEntry) +{ + tSirSmeProbeReqInd *pSirSmeProbeReqInd; + tSirMsgQ msgQ; + + pSirSmeProbeReqInd = qdf_mem_malloc(sizeof(tSirSmeProbeReqInd)); + if (NULL == pSirSmeProbeReqInd) { + /* Log error */ + lim_log(pMac, LOGP, + FL + ("call to AllocateMemory failed for eWNI_SME_PROBE_REQ_IND")); + return; + } + + msgQ.type = eWNI_SME_WPS_PBC_PROBE_REQ_IND; + msgQ.bodyval = 0; + msgQ.bodyptr = pSirSmeProbeReqInd; + + pSirSmeProbeReqInd->messageType = eWNI_SME_WPS_PBC_PROBE_REQ_IND; + pSirSmeProbeReqInd->length = sizeof(tSirSmeProbeReq); + pSirSmeProbeReqInd->sessionId = psessionEntry->smeSessionId; + + qdf_mem_copy(pSirSmeProbeReqInd->bssid.bytes, psessionEntry->bssId, + QDF_MAC_ADDR_SIZE); + qdf_mem_copy(pSirSmeProbeReqInd->WPSPBCProbeReq.peer_macaddr.bytes, + peerMacAddr, QDF_MAC_ADDR_SIZE); + + MTRACE(mac_trace(pMac, TRACE_CODE_TX_SME_MSG, + psessionEntry->peSessionId, msgQ.type)); + pSirSmeProbeReqInd->WPSPBCProbeReq.probeReqIELen = + (uint16_t) ProbeReqIELen; + qdf_mem_copy(pSirSmeProbeReqInd->WPSPBCProbeReq.probeReqIE, pProbeReqIE, + ProbeReqIELen); + + if (lim_sys_process_mmh_msg_api(pMac, &msgQ, ePROT) != eSIR_SUCCESS) { + PELOGE(lim_log + (pMac, LOGE, FL("couldnt send the probe req to hdd")); + ) + } + +} /*** end lim_send_sme_probe_req_ind() ***/ diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_process_probe_rsp_frame.c b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_process_probe_rsp_frame.c new file mode 100644 index 0000000000000000000000000000000000000000..daf93ffffadd2c7c802466be46abf1044e95a4db --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_process_probe_rsp_frame.c @@ -0,0 +1,403 @@ +/* + * Copyright (c) 2011-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * + * This file lim_process_probe_rsp_frame.cc contains the code + * for processing Probe Response Frame. + * Author: Chandra Modumudi + * Date: 03/01/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + * + */ + +#include "wni_api.h" +#include "wni_cfg.h" +#include "ani_global.h" +#include "sch_api.h" +#include "utils_api.h" +#include "lim_api.h" +#include "lim_types.h" +#include "lim_utils.h" +#include "lim_assoc_utils.h" +#include "lim_prop_exts_utils.h" +#include "lim_ser_des_utils.h" +#include "lim_send_messages.h" + +#include "parser_api.h" + +/** + * lim_validate_ie_information_in_probe_rsp_frame () - validates ie + * information in probe response. + * @mac_ctx: mac context + * @pRxPacketInfo: Rx packet info + * + * Return: 0 on success, one on failure + */ +static tSirRetStatus +lim_validate_ie_information_in_probe_rsp_frame(tpAniSirGlobal mac_ctx, + uint8_t *pRxPacketInfo) +{ + tSirRetStatus status = eSIR_SUCCESS; + uint8_t *pframe; + uint32_t nframe; + uint32_t missing_rsn_bytes; + + /* + * Validate a Probe response frame for malformed frame. + * If the frame is malformed then do not consider as it + * may cause problem fetching wrong IE values + */ + + if (WMA_GET_RX_PAYLOAD_LEN(pRxPacketInfo) < + (SIR_MAC_B_PR_SSID_OFFSET + SIR_MAC_MIN_IE_LEN)) + return eSIR_FAILURE; + + pframe = WMA_GET_RX_MPDU_DATA(pRxPacketInfo); + nframe = WMA_GET_RX_PAYLOAD_LEN(pRxPacketInfo); + missing_rsn_bytes = 0; + + status = sir_validate_and_rectify_ies(mac_ctx, + pframe, nframe, &missing_rsn_bytes); + + if (status == eSIR_SUCCESS) + WMA_GET_RX_MPDU_LEN(pRxPacketInfo) += missing_rsn_bytes; + + return status; +} + +/** + * lim_process_probe_rsp_frame() - processes received Probe Response frame + * @mac_ctx: Pointer to Global MAC structure + * @rx_Packet_info: A pointer to Buffer descriptor + associated PDUs + * @session_entry: Handle to the session. + * + * This function processes received Probe Response frame. + * Frames with out-of-order IEs are dropped. + * In case of IBSS, join 'success' makes MLM state machine + * transition into 'BSS started' state. This may have to change + * depending on supporting what kinda Authentication in IBSS. + * + * Return: None + */ +void +lim_process_probe_rsp_frame(tpAniSirGlobal mac_ctx, uint8_t *rx_Packet_info, + tpPESession session_entry) +{ + uint8_t *body; + uint32_t frame_len = 0; + tSirMacAddr current_bssid; + tpSirMacMgmtHdr header; + tSirProbeRespBeacon *probe_rsp; + uint8_t qos_enabled = false; + uint8_t wme_enabled = false; + + if (!session_entry) { + lim_log(mac_ctx, LOGE, FL("session_entry is NULL")); + return; + } + lim_log(mac_ctx, LOG1, "SessionId:%d ProbeRsp Frame is received", + session_entry->peSessionId); + + probe_rsp = qdf_mem_malloc(sizeof(tSirProbeRespBeacon)); + if (NULL == probe_rsp) { + lim_log(mac_ctx, LOGE, + FL + ("Unable to allocate memory ")); + return; + } + + probe_rsp->ssId.length = 0; + probe_rsp->wpa.length = 0; + + header = WMA_GET_RX_MAC_HEADER(rx_Packet_info); + + lim_log(mac_ctx, LOG2, + FL("Rx Probe Response with length = %d from "MAC_ADDRESS_STR), + WMA_GET_RX_MPDU_LEN(rx_Packet_info), + MAC_ADDR_ARRAY(header->sa)); + + /* Validate IE information before processing Probe Response Frame */ + if (lim_validate_ie_information_in_probe_rsp_frame(mac_ctx, + rx_Packet_info) != + eSIR_SUCCESS) { + lim_log(mac_ctx, LOG1, + FL("Parse error ProbeResponse, length=%d"), frame_len); + qdf_mem_free(probe_rsp); + return; + } + + frame_len = WMA_GET_RX_PAYLOAD_LEN(rx_Packet_info); + QDF_TRACE(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_INFO, + FL("Probe Resp Frame Received: BSSID " + MAC_ADDRESS_STR " (RSSI %d)"), + MAC_ADDR_ARRAY(header->bssId), + (uint) abs((int8_t)WMA_GET_RX_RSSI_NORMALIZED(rx_Packet_info))); + /* Get pointer to Probe Response frame body */ + body = WMA_GET_RX_MPDU_DATA(rx_Packet_info); + /* Enforce Mandatory IEs */ + if ((sir_convert_probe_frame2_struct(mac_ctx, + body, frame_len, probe_rsp) == eSIR_FAILURE) || + !probe_rsp->ssidPresent) { + lim_log(mac_ctx, LOG1, + FL("Parse error ProbeResponse, length=%d"), frame_len); + qdf_mem_free(probe_rsp); + return; + } + + lim_check_and_add_bss_description(mac_ctx, probe_rsp, + rx_Packet_info, false, true); + /* To Support BT-AMP */ + if ((mac_ctx->lim.gLimMlmState == + eLIM_MLM_WT_PROBE_RESP_STATE) || + (mac_ctx->lim.gLimMlmState == + eLIM_MLM_PASSIVE_SCAN_STATE)) { + lim_check_and_add_bss_description(mac_ctx, probe_rsp, + rx_Packet_info, ((mac_ctx->lim. + gLimHalScanState == eLIM_HAL_SCANNING_STATE) + ? true : false), true); + } else if (session_entry->limMlmState == + eLIM_MLM_WT_JOIN_BEACON_STATE) { + /* + * Either Beacon/probe response is required. + * Hence store it in same buffer. + */ + if (session_entry->beacon != NULL) { + qdf_mem_free(session_entry->beacon); + session_entry->beacon = NULL; + session_entry->bcnLen = 0; + } + session_entry->bcnLen = + WMA_GET_RX_PAYLOAD_LEN(rx_Packet_info); + session_entry->beacon = + qdf_mem_malloc(session_entry->bcnLen); + if (NULL == session_entry->beacon) { + lim_log(mac_ctx, LOGE, + FL("No Memory to store beacon")); + } else { + /* + * Store the Beacon/ProbeRsp. + * This is sent to csr/hdd in join cnf response. + */ + qdf_mem_copy(session_entry->beacon, + WMA_GET_RX_MPDU_DATA + (rx_Packet_info), + session_entry->bcnLen); + } + /* STA in WT_JOIN_BEACON_STATE */ + lim_check_and_announce_join_success(mac_ctx, probe_rsp, + header, + session_entry); + } else if (session_entry->limMlmState == + eLIM_MLM_LINK_ESTABLISHED_STATE) { + tpDphHashNode sta_ds = NULL; + /* + * Check if this Probe Response is for + * our Probe Request sent upon reaching + * heart beat threshold + */ + sir_copy_mac_addr(current_bssid, session_entry->bssId); + if (qdf_mem_cmp(current_bssid, header->bssId, + sizeof(tSirMacAddr))) { + qdf_mem_free(probe_rsp); + return; + } + if (!LIM_IS_CONNECTION_ACTIVE(session_entry)) { + lim_log(mac_ctx, LOGW, + FL("Recved Probe Resp from AP,AP-alive")); + if (probe_rsp->HTInfo.present) + lim_received_hb_handler(mac_ctx, + probe_rsp->HTInfo.primaryChannel, + session_entry); + else + lim_received_hb_handler(mac_ctx, + (uint8_t)probe_rsp->channelNumber, + session_entry); + } + if (LIM_IS_STA_ROLE(session_entry)) { + if (probe_rsp->channelSwitchPresent) { + /* + * on receiving channel switch announcement + * from AP, delete all TDLS peers before + * leaving BSS and proceed for channel switch + */ + lim_delete_tdls_peers(mac_ctx, session_entry); + + lim_update_channel_switch(mac_ctx, + probe_rsp, + session_entry); + } else if (session_entry->gLimSpecMgmt.dot11hChanSwState + == eLIM_11H_CHANSW_RUNNING) { + lim_cancel_dot11h_channel_switch( + mac_ctx, session_entry); + } + } + /* + * Now Process EDCA Parameters, if EDCAParamSet + * count is different. + * -- While processing beacons in link established + * state if it is determined that + * QoS Info IE has a different count for EDCA Params, + * and EDCA IE is not present in beacon, + * then probe req is sent out to get the EDCA params. + */ + sta_ds = dph_get_hash_entry(mac_ctx, + DPH_STA_HASH_INDEX_PEER, + &session_entry->dph.dphHashTable); + limGetQosMode(session_entry, &qos_enabled); + limGetWmeMode(session_entry, &wme_enabled); + lim_log(mac_ctx, LOG2, + FL("wmeEdcaPresent: %d wme_enabled: %d"), + probe_rsp->wmeEdcaPresent, wme_enabled); + lim_log(mac_ctx, LOG2, + FL("edcaPresent: %d, qos_enabled: %d"), + probe_rsp->edcaPresent, qos_enabled); + lim_log(mac_ctx, LOG2, + FL("edcaParams.qosInfo.count: %d"), + probe_rsp->edcaParams.qosInfo.count); + lim_log(mac_ctx, LOG2, + FL("schObject.gLimEdcaParamSetCount: %d"), + session_entry->gLimEdcaParamSetCount); + if (((probe_rsp->wmeEdcaPresent && wme_enabled) || + (probe_rsp->edcaPresent && qos_enabled)) && + (probe_rsp->edcaParams.qosInfo.count != + session_entry->gLimEdcaParamSetCount)) { + if (sch_beacon_edca_process(mac_ctx, + &probe_rsp->edcaParams, + session_entry) != eSIR_SUCCESS) { + lim_log(mac_ctx, LOGE, + FL("EDCA param process error")); + } else if (sta_ds != NULL) { + /* + * If needed, downgrade the + * EDCA parameters + */ + lim_set_active_edca_params(mac_ctx, + session_entry-> + gLimEdcaParams, + session_entry); + lim_send_edca_params(mac_ctx, + session_entry-> + gLimEdcaParamsActive, + sta_ds->bssId); + } else { + lim_log(mac_ctx, LOGE, + FL("SelfEntry missing in Hash")); + } + } + if (session_entry->fWaitForProbeRsp == true) { + lim_log(mac_ctx, LOGW, + FL("Check probe resp for caps change")); + lim_detect_change_in_ap_capabilities( + mac_ctx, probe_rsp, session_entry); + } + } else { + if (LIM_IS_IBSS_ROLE(session_entry) && + (session_entry->limMlmState == + eLIM_MLM_BSS_STARTED_STATE)) + lim_handle_ibss_coalescing(mac_ctx, probe_rsp, + rx_Packet_info, session_entry); + } + qdf_mem_free(probe_rsp); + + /* Ignore Probe Response frame in all other states */ + return; +} + +/** + * lim_process_probe_rsp_frame_no_session() - process Probe Response frame + * @mac_ctx: Pointer to Global MAC structure + * @rx_packet_info: A pointer to Buffer descriptor + associated PDUs + * + * This function processes received Probe Response frame with no session. + * + * Return: None + */ +void +lim_process_probe_rsp_frame_no_session(tpAniSirGlobal mac_ctx, + uint8_t *rx_packet_info) +{ + uint8_t *body; + uint32_t frame_len = 0; + tpSirMacMgmtHdr header; + tSirProbeRespBeacon *probe_rsp; + + probe_rsp = qdf_mem_malloc(sizeof(tSirProbeRespBeacon)); + if (NULL == probe_rsp) { + lim_log(mac_ctx, LOGE, + FL("Unable to allocate memory")); + return; + } + + probe_rsp->ssId.length = 0; + probe_rsp->wpa.length = 0; + + header = WMA_GET_RX_MAC_HEADER(rx_packet_info); + + lim_log(mac_ctx, LOG2, + FL("Received Probe Response frame with length=%d from "), + WMA_GET_RX_MPDU_LEN(rx_packet_info)); + lim_print_mac_addr(mac_ctx, header->sa, LOG2); + + /* Validate IE information before processing Probe Response Frame */ + if (lim_validate_ie_information_in_probe_rsp_frame(mac_ctx, + rx_packet_info) != + eSIR_SUCCESS) { + lim_log(mac_ctx, LOG1, + FL("Parse error ProbeResponse, length=%d"), frame_len); + qdf_mem_free(probe_rsp); + return; + } + + frame_len = WMA_GET_RX_PAYLOAD_LEN(rx_packet_info); + lim_log(mac_ctx, LOG2, + FL("Probe Resp Frame Received: BSSID " + MAC_ADDRESS_STR " (RSSI %d)"), + MAC_ADDR_ARRAY(header->bssId), + (uint) abs((int8_t)WMA_GET_RX_RSSI_NORMALIZED( + rx_packet_info))); + /* + * Get pointer to Probe Response frame body + */ + body = WMA_GET_RX_MPDU_DATA(rx_packet_info); + if (sir_convert_probe_frame2_struct(mac_ctx, body, frame_len, + probe_rsp) == eSIR_FAILURE) { + lim_log(mac_ctx, LOG1, + FL("Parse error ProbeResponse, length=%d\n"), + frame_len); + qdf_mem_free(probe_rsp); + return; + } + + lim_log(mac_ctx, LOG2, FL("Save this probe rsp in LFR cache")); + lim_check_and_add_bss_description(mac_ctx, probe_rsp, + rx_packet_info, false, true); + qdf_mem_free(probe_rsp); + return; +} diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_process_sme_req_messages.c b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_process_sme_req_messages.c new file mode 100644 index 0000000000000000000000000000000000000000..4fb11c50fe56e0f864df1ce529206088a384993e --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_process_sme_req_messages.c @@ -0,0 +1,6345 @@ +/* + * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * This file lim_process_sme_req_messages.cc contains the code + * for processing SME request messages. + * Author: Chandra Modumudi + * Date: 02/11/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + * + */ + +#include "cds_api.h" +#include "wni_api.h" +#include "wni_cfg.h" +#include "cfg_api.h" +#include "sir_api.h" +#include "sch_api.h" +#include "utils_api.h" +#include "lim_types.h" +#include "lim_utils.h" +#include "lim_assoc_utils.h" +#include "lim_security_utils.h" +#include "lim_ser_des_utils.h" +#include "lim_sme_req_utils.h" +#include "lim_ibss_peer_mgmt.h" +#include "lim_admit_control.h" +#include "dph_hash_table.h" +#include "lim_send_messages.h" +#include "lim_api.h" +#include "wmm_apsd.h" +#include "sir_mac_prot_def.h" +#include "rrm_api.h" +#include "nan_datapath.h" + +#include "sap_api.h" + + +#include +#include "cds_regdomain.h" + +/* + * This overhead is time for sending NOA start to host in case of GO/sending + * NULL data & receiving ACK in case of P2P Client and starting actual scanning + * with init scan req/rsp plus in case of concurrency, taking care of sending + * null data and receiving ACK to/from AP/Also SetChannel with calibration + * is taking around 7ms . + */ +#define SCAN_MESSAGING_OVERHEAD 20 /* in msecs */ +#define JOIN_NOA_DURATION 2000 /* in msecs */ +#define OEM_DATA_NOA_DURATION 60 /* in msecs */ +#define DEFAULT_PASSIVE_MAX_CHANNEL_TIME 110 /* in msecs */ + +#define CONV_MS_TO_US 1024 /* conversion factor from ms to us */ + +#define BEACON_INTERVAL_THRESHOLD 50 /* in msecs */ +#define STA_BURST_SCAN_DURATION 120 /* in msecs */ + +/* SME REQ processing function templates */ +static bool __lim_process_sme_sys_ready_ind(tpAniSirGlobal, uint32_t *); +static bool __lim_process_sme_start_bss_req(tpAniSirGlobal, tpSirMsgQ pMsg); +static void __lim_process_sme_scan_req(tpAniSirGlobal, uint32_t *); +static void __lim_process_sme_join_req(tpAniSirGlobal, uint32_t *); +static void __lim_process_sme_reassoc_req(tpAniSirGlobal, uint32_t *); +static void __lim_process_sme_disassoc_req(tpAniSirGlobal, uint32_t *); +static void __lim_process_sme_disassoc_cnf(tpAniSirGlobal, uint32_t *); +static void __lim_process_sme_deauth_req(tpAniSirGlobal, uint32_t *); +static void __lim_process_sme_set_context_req(tpAniSirGlobal, uint32_t *); +static bool __lim_process_sme_stop_bss_req(tpAniSirGlobal, tpSirMsgQ pMsg); +static void __lim_process_send_disassoc_frame(tpAniSirGlobal mac_ctx, + uint32_t *msg_buf); +static void lim_process_sme_channel_change_request(tpAniSirGlobal pMac, + uint32_t *pMsg); +static void lim_process_sme_start_beacon_req(tpAniSirGlobal pMac, uint32_t *pMsg); +static void lim_process_sme_dfs_csa_ie_request(tpAniSirGlobal pMac, uint32_t *pMsg); +static void lim_process_nss_update_request(tpAniSirGlobal pMac, uint32_t *pMsg); +static void lim_process_set_ie_req(tpAniSirGlobal pMac, uint32_t *pMsg); + +static void lim_start_bss_update_add_ie_buffer(tpAniSirGlobal pMac, + uint8_t **pDstData_buff, + uint16_t *pDstDataLen, + uint8_t *pSrcData_buff, + uint16_t srcDataLen); + +static void lim_update_add_ie_buffer(tpAniSirGlobal pMac, + uint8_t **pDstData_buff, + uint16_t *pDstDataLen, + uint8_t *pSrcData_buff, uint16_t srcDataLen); +static bool lim_update_ibss_prop_add_ies(tpAniSirGlobal pMac, + uint8_t **pDstData_buff, + uint16_t *pDstDataLen, + tSirModifyIE *pModifyIE); +static void lim_process_modify_add_ies(tpAniSirGlobal pMac, uint32_t *pMsg); + +static void lim_process_update_add_ies(tpAniSirGlobal pMac, uint32_t *pMsg); + +static void lim_process_ext_change_channel(tpAniSirGlobal mac_ctx, + uint32_t *msg); + +/** + * lim_process_set_hw_mode() - Send set HW mode command to WMA + * @mac: Globacl MAC pointer + * @msg: Message containing the hw mode index + * + * Send the set HW mode command to WMA + * + * Return: QDF_STATUS_SUCCESS if message posting is successful + */ +static QDF_STATUS lim_process_set_hw_mode(tpAniSirGlobal mac, uint32_t *msg) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + cds_msg_t cds_message; + struct sir_hw_mode *req_msg; + uint32_t len; + struct s_sir_set_hw_mode *buf; + tSirMsgQ resp_msg; + struct sir_set_hw_mode_resp *param; + + buf = (struct s_sir_set_hw_mode *) msg; + if (!buf) { + lim_log(mac, LOGE, FL("Set HW mode param is NULL")); + /* To free the active command list */ + goto fail; + } + + len = sizeof(*req_msg); + + req_msg = qdf_mem_malloc(len); + if (!req_msg) { + lim_log(mac, LOGE, FL("qdf_mem_malloc failed")); + /* Free the active command list + * Probably the malloc is going to fail there as well?! + */ + return QDF_STATUS_E_NOMEM; + } + + req_msg->hw_mode_index = buf->set_hw.hw_mode_index; + req_msg->reason = buf->set_hw.reason; + /* Other parameters are not needed for WMA */ + + cds_message.bodyptr = req_msg; + cds_message.type = SIR_HAL_PDEV_SET_HW_MODE; + + lim_log(mac, LOG1, FL("Posting SIR_HAL_SOC_SET_HW_MOD to WMA")); + status = cds_mq_post_message(CDS_MQ_ID_WMA, &cds_message); + if (!QDF_IS_STATUS_SUCCESS(status)) { + lim_log(mac, LOGE, + FL("cds_mq_post_message failed!(err=%d)"), + status); + qdf_mem_free(req_msg); + goto fail; + } + return status; +fail: + param = qdf_mem_malloc(sizeof(*param)); + if (!param) { + lim_log(mac, LOGE, FL("HW mode resp failed")); + return QDF_STATUS_E_FAILURE; + } + param->status = SET_HW_MODE_STATUS_ECANCELED; + param->cfgd_hw_mode_index = 0; + param->num_vdev_mac_entries = 0; + resp_msg.type = eWNI_SME_SET_HW_MODE_RESP; + resp_msg.bodyptr = param; + resp_msg.bodyval = 0; + lim_sys_process_mmh_msg_api(mac, &resp_msg, ePROT); + return QDF_STATUS_SUCCESS; +} + +/** + * lim_process_set_dual_mac_cfg_req() - Set dual mac config command to WMA + * @mac: Global MAC pointer + * @msg: Message containing the dual mac config parameter + * + * Send the set dual mac config command to WMA + * + * Return: QDF_STATUS_SUCCESS if message posting is successful + */ +static QDF_STATUS lim_process_set_dual_mac_cfg_req(tpAniSirGlobal mac, + uint32_t *msg) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + cds_msg_t cds_message; + struct sir_dual_mac_config *req_msg; + uint32_t len; + struct sir_set_dual_mac_cfg *buf; + tSirMsgQ resp_msg; + struct sir_dual_mac_config_resp *param; + + buf = (struct sir_set_dual_mac_cfg *) msg; + if (!buf) { + lim_log(mac, LOGE, FL("Set Dual mac config is NULL")); + /* To free the active command list */ + goto fail; + } + + len = sizeof(*req_msg); + + req_msg = qdf_mem_malloc(len); + if (!req_msg) { + lim_log(mac, LOGE, FL("qdf_mem_malloc failed")); + /* Free the active command list + * Probably the malloc is going to fail there as well?! + */ + return QDF_STATUS_E_NOMEM; + } + + req_msg->scan_config = buf->set_dual_mac.scan_config; + req_msg->fw_mode_config = buf->set_dual_mac.fw_mode_config; + /* Other parameters are not needed for WMA */ + + cds_message.bodyptr = req_msg; + cds_message.type = SIR_HAL_PDEV_DUAL_MAC_CFG_REQ; + + lim_log(mac, LOG1, + FL("Post SIR_HAL_PDEV_DUAL_MAC_CFG_REQ to WMA: %x %x"), + req_msg->scan_config, req_msg->fw_mode_config); + status = cds_mq_post_message(CDS_MQ_ID_WMA, &cds_message); + if (!QDF_IS_STATUS_SUCCESS(status)) { + lim_log(mac, LOGE, + FL("cds_mq_post_message failed!(err=%d)"), + status); + qdf_mem_free(req_msg); + goto fail; + } + return status; +fail: + param = qdf_mem_malloc(sizeof(*param)); + if (!param) { + lim_log(mac, LOGE, FL("Dual mac config resp failed")); + return QDF_STATUS_E_FAILURE; + } + param->status = SET_HW_MODE_STATUS_ECANCELED; + resp_msg.type = eWNI_SME_SET_DUAL_MAC_CFG_RESP; + resp_msg.bodyptr = param; + resp_msg.bodyval = 0; + lim_sys_process_mmh_msg_api(mac, &resp_msg, ePROT); + return QDF_STATUS_SUCCESS; +} + +/** + * lim_process_set_antenna_mode_req() - Set antenna mode command + * to WMA + * @mac: Global MAC pointer + * @msg: Message containing the antenna mode parameter + * + * Send the set antenna mode command to WMA + * + * Return: QDF_STATUS_SUCCESS if message posting is successful + */ +static QDF_STATUS lim_process_set_antenna_mode_req(tpAniSirGlobal mac, + uint32_t *msg) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + cds_msg_t cds_message; + struct sir_antenna_mode_param *req_msg; + struct sir_set_antenna_mode *buf; + tSirMsgQ resp_msg; + struct sir_antenna_mode_resp *param; + + buf = (struct sir_set_antenna_mode *) msg; + if (!buf) { + lim_log(mac, LOGE, FL("Set antenna mode is NULL")); + /* To free the active command list */ + goto fail; + } + + req_msg = qdf_mem_malloc(sizeof(*req_msg)); + if (!req_msg) { + lim_log(mac, LOGE, FL("qdf_mem_malloc failed")); + return QDF_STATUS_E_NOMEM; + } + + req_msg->num_rx_chains = buf->set_antenna_mode.num_rx_chains; + req_msg->num_tx_chains = buf->set_antenna_mode.num_tx_chains; + + cds_message.bodyptr = req_msg; + cds_message.type = SIR_HAL_SOC_ANTENNA_MODE_REQ; + + lim_log(mac, LOG1, + FL("Post SIR_HAL_SOC_ANTENNA_MODE_REQ to WMA: %d %d"), + req_msg->num_rx_chains, + req_msg->num_tx_chains); + status = cds_mq_post_message(CDS_MQ_ID_WMA, &cds_message); + if (!QDF_IS_STATUS_SUCCESS(status)) { + lim_log(mac, LOGE, + FL("cds_mq_post_message failed!(err=%d)"), + status); + qdf_mem_free(req_msg); + goto fail; + } + return status; +fail: + param = qdf_mem_malloc(sizeof(*param)); + if (!param) { + lim_log(mac, LOGE, FL("antenna mode resp failed")); + return QDF_STATUS_E_NOMEM; + } + param->status = SET_ANTENNA_MODE_STATUS_ECANCELED; + resp_msg.type = eWNI_SME_SET_ANTENNA_MODE_RESP; + resp_msg.bodyptr = param; + resp_msg.bodyval = 0; + lim_sys_process_mmh_msg_api(mac, &resp_msg, ePROT); + return QDF_STATUS_SUCCESS; +} + +/** + * __lim_fresh_scan_reqd() - determine if a fresh scan request must be issued. + * @mac_ctx: Pointer to Global MAC structure + * @return_fresh_results: Trigger fresh scan. + * + * PE will do fresh scan, if all of the active sessions are in + * good state (Link Est or BSS Started). If one of the sessions + * is not in one of the above states, then PE does not do fresh + * scan. If no session exists (scanning very first time), + * then PE will always do fresh scan if SME asks it to do that. + * + * Return: true for fresh scan results, false if in invalid state. + */ +static uint8_t +__lim_fresh_scan_reqd(tpAniSirGlobal mac_ctx, uint8_t return_fresh_results) +{ + uint8_t valid_state = true; + int i; + + lim_log(mac_ctx, LOG1, FL("gLimSmeState: %d, returnFreshResults 0x%x"), + mac_ctx->lim.gLimSmeState, return_fresh_results); + + if (mac_ctx->lim.gLimSmeState != eLIM_SME_IDLE_STATE) { + lim_log(mac_ctx, LOG1, FL("return FALSE")); + return false; + } + + for (i = 0; i < mac_ctx->lim.maxBssId; i++) { + + if (mac_ctx->lim.gpSession[i].valid == false) + continue; + + lim_log(mac_ctx, LOG1, + FL("session %d, bsstype %d, limSystemRole %d, limSmeState %d"), + i, mac_ctx->lim.gpSession[i].bssType, + mac_ctx->lim.gpSession[i].limSystemRole, + mac_ctx->lim.gpSession[i].limSmeState); + + if (mac_ctx->lim.gpSession[i].bssType == eSIR_NDI_MODE) + continue; + + if (mac_ctx->lim.gpSession[i].bssType == + eSIR_INFRASTRUCTURE_MODE && + mac_ctx->lim.gpSession[i].limSmeState == + eLIM_SME_LINK_EST_STATE) + continue; + + if (mac_ctx->lim.gpSession[i].bssType == eSIR_IBSS_MODE && + mac_ctx->lim.gpSession[i].limSmeState == + eLIM_SME_NORMAL_STATE) + continue; + + if (mac_ctx->lim.gpSession[i].bssType == eSIR_INFRA_AP_MODE && + mac_ctx->lim.gpSession[i].pePersona == + QDF_P2P_GO_MODE && + mac_ctx->lim.gpSession[i].limSmeState == + eLIM_SME_NORMAL_STATE) + continue; + + if (mac_ctx->lim.gpSession[i].limSystemRole == eLIM_AP_ROLE && + mac_ctx->lim.gpSession[i].limSmeState == + eLIM_SME_NORMAL_STATE) + continue; + + valid_state = false; + break; + } + + lim_log(mac_ctx, LOG1, FL("valid_state: %d"), valid_state); + + if ((valid_state) && + (return_fresh_results & SIR_BG_SCAN_RETURN_FRESH_RESULTS)) + return true; + else + return false; +} + +/** + * __lim_is_sme_assoc_cnf_valid() + * + ***FUNCTION: + * This function is called by __lim_process_sme_assoc_cnf_new() upon + * receiving SME_ASSOC_CNF. + * + ***LOGIC: + * Message validity checks are performed in this function + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param pMeasReq Pointer to Received ASSOC_CNF message + * @return true When received SME_ASSOC_CNF is formatted + * correctly + * false otherwise + */ + +static inline uint8_t __lim_is_sme_assoc_cnf_valid(tpSirSmeAssocCnf pAssocCnf) +{ + if (qdf_is_macaddr_group(&pAssocCnf->peer_macaddr)) + return false; + else + return true; +} /*** end __lim_is_sme_assoc_cnf_valid() ***/ + +/** + * __lim_get_sme_join_req_size_for_alloc() + * + ***FUNCTION: + * This function is called in various places to get IE length + * from tSirBssDescription structure + * number being scanned. + * + ***PARAMS: + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param pBssDescr + * @return Total IE length + */ + +static uint16_t __lim_get_sme_join_req_size_for_alloc(uint8_t *pBuf) +{ + uint16_t len = 0; + + if (!pBuf) + return len; + + pBuf += sizeof(uint16_t); + len = lim_get_u16(pBuf); + return len; +} + +/** + * __lim_is_defered_msg_for_learn() - message handling in SME learn state + * @pMac: Global MAC context + * @pMsg: Pointer to message posted from SME to LIM. + * + * Has role only if 11h is enabled. Not used on STA side. + * Defers the message if SME is in learn state and brings + * the LIM back to normal mode. + * + * Return: true - If defered false - Otherwise + */ + +static bool __lim_is_defered_msg_for_learn(tpAniSirGlobal pMac, tpSirMsgQ pMsg) +{ + if (lim_is_system_in_scan_state(pMac)) { + if (lim_defer_msg(pMac, pMsg) != TX_SUCCESS) { + lim_log(pMac, LOGE, FL("Could not defer Msg = %d"), + pMsg->type); + return false; + } + lim_log(pMac, LOG1, + FL("Defer the message, in learn mode type = %d"), + pMsg->type); + return true; + } + return false; +} + +/** + * __lim_is_defered_msg_for_radar() - Defers the message if radar is detected + * @mac_ctx: Pointer to Global MAC structure + * @message: Pointer to message posted from SME to LIM. + * + * Has role only if 11h is enabled. Not used on STA side. + * Defers the message if radar is detected. + * + * Return: true, if defered otherwise return false. + */ +static bool +__lim_is_defered_msg_for_radar(tpAniSirGlobal mac_ctx, tpSirMsgQ message) +{ + /* + * fRadarDetCurOperChan will be set only if we + * detect radar in current operating channel and + * System Role == AP ROLE + * + * TODO: Need to take care radar detection. + * + * if (LIM_IS_RADAR_DETECTED(mac_ctx)) + */ + if (0) { + if (lim_defer_msg(mac_ctx, message) != TX_SUCCESS) { + lim_log(mac_ctx, LOGE, FL("Could not defer Msg = %d"), + message->type); + return false; + } + lim_log(mac_ctx, LOG1, + FL("Defer the message, in learn mode type = %d"), + message->type); + return true; + } + return false; +} + +/** + * __lim_process_sme_sys_ready_ind () - Process ready indication from WMA + * @pMac: Global MAC context + * @pMsgBuf: Message from WMA + * + * handles the notification from HDD. PE just forwards this message to HAL. + * + * Return: true-Posting to HAL failed, so PE will consume the buffer. + * false-Posting to HAL successful, so HAL will consume the buffer. + */ + +static bool __lim_process_sme_sys_ready_ind(tpAniSirGlobal pMac, uint32_t *pMsgBuf) +{ + tSirMsgQ msg; + tSirSmeReadyReq *ready_req = (tSirSmeReadyReq *) pMsgBuf; + + msg.type = WMA_SYS_READY_IND; + msg.reserved = 0; + msg.bodyptr = pMsgBuf; + msg.bodyval = 0; + + if (ANI_DRIVER_TYPE(pMac) != eDRIVER_TYPE_MFG) { + ready_req->pe_roam_synch_cb = pe_roam_synch_callback; + pe_register_callbacks_with_wma(pMac, ready_req); + pMac->lim.add_bssdescr_callback = ready_req->add_bssdescr_cb; + pMac->lim.sme_msg_callback = ready_req->sme_msg_cb; + } + PELOGW(lim_log(pMac, LOGW, FL("sending WMA_SYS_READY_IND msg to HAL"));) + MTRACE(mac_trace_msg_tx(pMac, NO_SESSION, msg.type)); + + if (eSIR_SUCCESS != wma_post_ctrl_msg(pMac, &msg)) { + lim_log(pMac, LOGP, FL("wma_post_ctrl_msg failed")); + return true; + } + return false; +} + +/** + *lim_configure_ap_start_bss_session() - Configure the AP Start BSS in session. + *@mac_ctx: Pointer to Global MAC structure + *@session: A pointer to session entry + *@sme_start_bss_req: Start BSS Request from upper layers. + * + * This function is used to configure the start bss parameters + * in to the session. + * + * Return: None. + */ +static void +lim_configure_ap_start_bss_session(tpAniSirGlobal mac_ctx, tpPESession session, + tpSirSmeStartBssReq sme_start_bss_req) +{ + session->limSystemRole = eLIM_AP_ROLE; + session->privacy = sme_start_bss_req->privacy; + session->fwdWPSPBCProbeReq = sme_start_bss_req->fwdWPSPBCProbeReq; + session->authType = sme_start_bss_req->authType; + /* Store the DTIM period */ + session->dtimPeriod = (uint8_t) sme_start_bss_req->dtimPeriod; + /* Enable/disable UAPSD */ + session->apUapsdEnable = sme_start_bss_req->apUapsdEnable; + if (session->pePersona == QDF_P2P_GO_MODE) { + session->proxyProbeRspEn = 0; + } else { + /* + * To detect PBC overlap in SAP WPS mode, + * Host handles Probe Requests. + */ + if (SAP_WPS_DISABLED == sme_start_bss_req->wps_state) + session->proxyProbeRspEn = 1; + else + session->proxyProbeRspEn = 0; + } + session->ssidHidden = sme_start_bss_req->ssidHidden; + session->wps_state = sme_start_bss_req->wps_state; + session->sap_dot11mc = sme_start_bss_req->sap_dot11mc; + session->vendor_vht_sap = + sme_start_bss_req->vendor_vht_sap; + lim_get_short_slot_from_phy_mode(mac_ctx, session, session->gLimPhyMode, + &session->shortSlotTimeSupported); + session->isCoalesingInIBSSAllowed = + sme_start_bss_req->isCoalesingInIBSSAllowed; + +} + +/** + * __lim_handle_sme_start_bss_request() - process SME_START_BSS_REQ message + *@mac_ctx: Pointer to Global MAC structure + *@msg_buf: A pointer to the SME message buffer + * + * This function is called to process SME_START_BSS_REQ message + * from HDD or upper layer application. + * + * Return: None + */ +static void +__lim_handle_sme_start_bss_request(tpAniSirGlobal mac_ctx, uint32_t *msg_buf) +{ + uint16_t size; + uint32_t val = 0; + tSirRetStatus ret_status; + tSirMacChanNum channel_number; + tLimMlmStartReq *mlm_start_req = NULL; + tpSirSmeStartBssReq sme_start_bss_req = NULL; + tSirResultCodes ret_code = eSIR_SME_SUCCESS; + /* Flag Used in case of IBSS to Auto generate BSSID. */ + uint32_t auto_gen_bssid = false; + uint8_t session_id; + tpPESession session = NULL; + uint8_t sme_session_id = 0xFF; + uint16_t sme_transaction_id = 0xFF; + uint32_t chanwidth; + struct vdev_type_nss *vdev_type_nss; + tSirRetStatus cfg_get_wmi_dfs_master_param = eSIR_SUCCESS; + +/* FEATURE_WLAN_DIAG_SUPPORT */ +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM + /* + * Since the session is not created yet, sending NULL. + * The response should have the correct state. + */ + lim_diag_event_report(mac_ctx, WLAN_PE_DIAG_START_BSS_REQ_EVENT, + NULL, 0, 0); +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + + lim_log(mac_ctx, LOG1, FL("Received START_BSS_REQ")); + size = sizeof(tSirSmeStartBssReq); + sme_start_bss_req = qdf_mem_malloc(size); + if (NULL == sme_start_bss_req) { + lim_log(mac_ctx, LOGE, + FL("Allocate Memory fail for LimStartBssReq")); + /* Send failure response to host */ + ret_code = eSIR_SME_RESOURCES_UNAVAILABLE; + goto free; + } + qdf_mem_copy(sme_start_bss_req, msg_buf, sizeof(tSirSmeStartBssReq)); + sme_session_id = sme_start_bss_req->sessionId; + sme_transaction_id = sme_start_bss_req->transactionId; + + if ((mac_ctx->lim.gLimSmeState == eLIM_SME_OFFLINE_STATE) || + (mac_ctx->lim.gLimSmeState == eLIM_SME_IDLE_STATE)) { + if (!lim_is_sme_start_bss_req_valid(mac_ctx, + sme_start_bss_req)) { + lim_log(mac_ctx, LOGW, + FL("Received invalid eWNI_SME_START_BSS_REQ")); + ret_code = eSIR_SME_INVALID_PARAMETERS; + goto free; + } + + /* + * This is the place where PE is going to create a session. + * If session is not existed, then create a new session + */ + session = pe_find_session_by_bssid(mac_ctx, + sme_start_bss_req->bssid.bytes, &session_id); + if (session != NULL) { + lim_log(mac_ctx, LOGW, + FL("Session Already exists for given BSSID")); + ret_code = eSIR_SME_BSS_ALREADY_STARTED_OR_JOINED; + session = NULL; + goto free; + } else { + session = pe_create_session(mac_ctx, + sme_start_bss_req->bssid.bytes, + &session_id, mac_ctx->lim.maxStation, + sme_start_bss_req->bssType); + if (session == NULL) { + lim_log(mac_ctx, LOGW, + FL("Session Can not be created ")); + ret_code = eSIR_SME_RESOURCES_UNAVAILABLE; + goto free; + } + } + + if (QDF_NDI_MODE != sme_start_bss_req->bssPersona) { + /* Probe resp add ie */ + lim_start_bss_update_add_ie_buffer(mac_ctx, + &session->addIeParams.probeRespData_buff, + &session->addIeParams.probeRespDataLen, + sme_start_bss_req->addIeParams. + probeRespData_buff, + sme_start_bss_req->addIeParams. + probeRespDataLen); + + /* Probe Beacon add ie */ + lim_start_bss_update_add_ie_buffer(mac_ctx, + &session->addIeParams.probeRespBCNData_buff, + &session->addIeParams.probeRespBCNDataLen, + sme_start_bss_req->addIeParams. + probeRespBCNData_buff, + sme_start_bss_req->addIeParams. + probeRespBCNDataLen); + + /* Assoc resp IE */ + lim_start_bss_update_add_ie_buffer(mac_ctx, + &session->addIeParams.assocRespData_buff, + &session->addIeParams.assocRespDataLen, + sme_start_bss_req->addIeParams. + assocRespData_buff, + sme_start_bss_req->addIeParams. + assocRespDataLen); + } + /* Store the session related params in newly created session */ + session->pLimStartBssReq = sme_start_bss_req; + + /* Store PE session_id in session Table */ + session->peSessionId = session_id; + + /* Store SME session Id in sessionTable */ + session->smeSessionId = sme_start_bss_req->sessionId; + + session->transactionId = sme_start_bss_req->transactionId; + + qdf_mem_copy(&(session->htConfig), + &(sme_start_bss_req->htConfig), + sizeof(session->htConfig)); + + qdf_mem_copy(&(session->vht_config), + &(sme_start_bss_req->vht_config), + sizeof(session->vht_config)); + + sir_copy_mac_addr(session->selfMacAddr, + sme_start_bss_req->self_macaddr.bytes); + + /* Copy SSID to session table */ + qdf_mem_copy((uint8_t *) &session->ssId, + (uint8_t *) &sme_start_bss_req->ssId, + (sme_start_bss_req->ssId.length + 1)); + + session->bssType = sme_start_bss_req->bssType; + + session->nwType = sme_start_bss_req->nwType; + + session->beaconParams.beaconInterval = + sme_start_bss_req->beaconInterval; + + /* Store the channel number in session Table */ + session->currentOperChannel = + sme_start_bss_req->channelId; + + /* Store Persona */ + session->pePersona = sme_start_bss_req->bssPersona; + QDF_TRACE(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_INFO, + FL("PE PERSONA=%d"), session->pePersona); + + /* Update the phymode */ + session->gLimPhyMode = sme_start_bss_req->nwType; + + session->maxTxPower = + cfg_get_regulatory_max_transmit_power(mac_ctx, + session->currentOperChannel); + /* Store the dot 11 mode in to the session Table */ + session->dot11mode = sme_start_bss_req->dot11mode; +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH + session->cc_switch_mode = + sme_start_bss_req->cc_switch_mode; +#endif + session->htCapability = + IS_DOT11_MODE_HT(session->dot11mode); + session->vhtCapability = + IS_DOT11_MODE_VHT(session->dot11mode); + QDF_TRACE(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_INFO, + FL("*****session->vhtCapability = %d"), + session->vhtCapability); + session->txLdpcIniFeatureEnabled = + sme_start_bss_req->txLdpcIniFeatureEnabled; +#ifdef WLAN_FEATURE_11W + session->limRmfEnabled = + sme_start_bss_req->pmfCapable ? 1 : 0; + lim_log(mac_ctx, LOG1, FL("Session RMF enabled: %d"), + session->limRmfEnabled); +#endif + + qdf_mem_copy((void *)&session->rateSet, + (void *)&sme_start_bss_req->operationalRateSet, + sizeof(tSirMacRateSet)); + qdf_mem_copy((void *)&session->extRateSet, + (void *)&sme_start_bss_req->extendedRateSet, + sizeof(tSirMacRateSet)); + + if (IS_5G_CH(session->currentOperChannel)) + vdev_type_nss = &mac_ctx->vdev_type_nss_5g; + else + vdev_type_nss = &mac_ctx->vdev_type_nss_2g; + + switch (sme_start_bss_req->bssType) { + case eSIR_INFRA_AP_MODE: + lim_configure_ap_start_bss_session(mac_ctx, session, + sme_start_bss_req); + if (session->pePersona == QDF_SAP_MODE) + session->vdev_nss = vdev_type_nss->sap; + else + session->vdev_nss = vdev_type_nss->p2p_go; + break; + case eSIR_IBSS_MODE: + session->limSystemRole = eLIM_STA_IN_IBSS_ROLE; + lim_get_short_slot_from_phy_mode(mac_ctx, session, + session->gLimPhyMode, + &session->shortSlotTimeSupported); + + /* + * initialize to "OPEN". + * will be updated upon key installation + */ + session->encryptType = eSIR_ED_NONE; + session->vdev_nss = vdev_type_nss->ibss; + + break; + case eSIR_NDI_MODE: + session->limSystemRole = eLIM_NDI_ROLE; + break; + + + /* + * There is one more mode called auto mode. + * which is used no where + */ + + /* FORBUILD -TEMPFIX.. HOW TO use AUTO MODE????? */ + + default: + /* not used anywhere...used in scan function */ + break; + } + + lim_log(mac_ctx, LOG1, FL("persona - %d, nss - %d"), + session->pePersona, session->vdev_nss); + session->nss = session->vdev_nss; + /* + * Allocate memory for the array of + * parsed (Re)Assoc request structure + */ + if (sme_start_bss_req->bssType == eSIR_INFRA_AP_MODE) { + session->parsedAssocReq = + qdf_mem_malloc(session->dph.dphHashTable. + size * sizeof(tpSirAssocReq)); + if (NULL == session->parsedAssocReq) { + lim_log(mac_ctx, LOGW, + FL("AllocateMemory() failed")); + ret_code = eSIR_SME_RESOURCES_UNAVAILABLE; + goto free; + } + } + + if (!sme_start_bss_req->channelId && + sme_start_bss_req->bssType != eSIR_NDI_MODE) { + lim_log(mac_ctx, LOGE, + FL("Received invalid eWNI_SME_START_BSS_REQ")); + ret_code = eSIR_SME_INVALID_PARAMETERS; + goto free; + } + channel_number = sme_start_bss_req->channelId; +#ifdef QCA_HT_2040_COEX + if (sme_start_bss_req->obssEnabled) + session->htSupportedChannelWidthSet = + session->htCapability; + else +#endif + session->htSupportedChannelWidthSet = + (sme_start_bss_req->sec_ch_offset) ? 1 : 0; + session->htSecondaryChannelOffset = + sme_start_bss_req->sec_ch_offset; + session->htRecommendedTxWidthSet = + (session->htSecondaryChannelOffset) ? 1 : 0; + QDF_TRACE(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_INFO, + FL("cbMode %u"), sme_start_bss_req->cbMode); + if (session->vhtCapability || session->htCapability) { + chanwidth = sme_start_bss_req->vht_channel_width; + lim_log(mac_ctx, LOG1, + FL("vht_channel_width %u htSupportedChannelWidthSet %d"), + sme_start_bss_req->vht_channel_width, + session->htSupportedChannelWidthSet); + session->ch_width = chanwidth; + if (session->htSupportedChannelWidthSet) { + session->ch_center_freq_seg0 = + sme_start_bss_req->center_freq_seg0; + session->ch_center_freq_seg1 = + sme_start_bss_req->center_freq_seg1; + } else { + session->ch_center_freq_seg0 = 0; + session->ch_center_freq_seg1 = 0; + } + } + + if (session->vhtCapability && + (session->ch_width > CH_WIDTH_80MHZ)) { + session->nss = 1; + lim_log(mac_ctx, LOG1, FL("nss set to [%d]"), + session->nss); + } + lim_log(mac_ctx, LOG1, FL("vht su tx bformer %d"), + session->vht_config.su_beam_former); + + /* Delete pre-auth list if any */ + lim_delete_pre_auth_list(mac_ctx); + + if (session->nss == 1) { + session->vht_config.su_beam_former = 0; + session->vht_config.tx_stbc = 0; + session->vht_config.num_soundingdim = 0; + session->htConfig.ht_tx_stbc = 0; + } + /* + * keep the RSN/WPA IE information in PE Session Entry + * later will be using this to check when received (Re)Assoc req + */ + lim_set_rs_nie_wp_aiefrom_sme_start_bss_req_message(mac_ctx, + &sme_start_bss_req->rsnIE, session); + + if (LIM_IS_AP_ROLE(session) || + LIM_IS_IBSS_ROLE(session) || + LIM_IS_NDI_ROLE(session)) { + session->gLimProtectionControl = + sme_start_bss_req->protEnabled; + /* + * each byte will have the following info + * bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0 + * reserved reserved RIFS Lsig n-GF ht20 11g 11b + */ + qdf_mem_copy((void *)&session->cfgProtection, + (void *)&sme_start_bss_req->ht_capab, + sizeof(uint16_t)); + /* Initialize WPS PBC session link list */ + session->pAPWPSPBCSession = NULL; + } + /* Prepare and Issue LIM_MLM_START_REQ to MLM */ + mlm_start_req = qdf_mem_malloc(sizeof(tLimMlmStartReq)); + if (NULL == mlm_start_req) { + lim_log(mac_ctx, LOGP, + FL("Allocate Memory failed for mlmStartReq")); + ret_code = eSIR_SME_RESOURCES_UNAVAILABLE; + goto free; + } + + /* Copy SSID to the MLM start structure */ + qdf_mem_copy((uint8_t *) &mlm_start_req->ssId, + (uint8_t *) &sme_start_bss_req->ssId, + sme_start_bss_req->ssId.length + 1); + mlm_start_req->ssidHidden = sme_start_bss_req->ssidHidden; + mlm_start_req->obssProtEnabled = + sme_start_bss_req->obssProtEnabled; + + mlm_start_req->bssType = session->bssType; + + /* Fill PE session Id from the session Table */ + mlm_start_req->sessionId = session->peSessionId; + + if (mlm_start_req->bssType == eSIR_INFRA_AP_MODE || + mlm_start_req->bssType == eSIR_NDI_MODE) { + /* + * Copy the BSSId from sessionTable to + * mlmStartReq struct + */ + sir_copy_mac_addr(mlm_start_req->bssId, session->bssId); + } else { + /* ibss mode */ + mac_ctx->lim.gLimIbssCoalescingHappened = false; + + ret_status = wlan_cfg_get_int(mac_ctx, + WNI_CFG_IBSS_AUTO_BSSID, + &auto_gen_bssid); + if (ret_status != eSIR_SUCCESS) { + lim_log(mac_ctx, LOGP, + FL("Get Auto Gen BSSID fail,Status=%d"), + ret_status); + ret_code = eSIR_LOGP_EXCEPTION; + goto free; + } + + if (!auto_gen_bssid) { + /* + * We're not auto generating BSSID. + * Instead, get it from session entry + */ + sir_copy_mac_addr(mlm_start_req->bssId, + session->bssId); + /* + * Start IBSS group BSSID + * Auto Generating BSSID. + */ + auto_gen_bssid = ((mlm_start_req->bssId[0] & + 0x01) ? true : false); + } + + if (auto_gen_bssid) { + /* + * if BSSID is not any uc id. + * then use locally generated BSSID. + * Autogenerate the BSSID + */ + lim_get_random_bssid(mac_ctx, + mlm_start_req->bssId); + mlm_start_req->bssId[0] = 0x02; + + /* + * Copy randomly generated BSSID + * to the session Table + */ + sir_copy_mac_addr(session->bssId, + mlm_start_req->bssId); + } + } + /* store the channel num in mlmstart req structure */ + mlm_start_req->channelNumber = session->currentOperChannel; + mlm_start_req->cbMode = sme_start_bss_req->cbMode; + mlm_start_req->beaconPeriod = + session->beaconParams.beaconInterval; + + if (LIM_IS_AP_ROLE(session)) { + mlm_start_req->dtimPeriod = session->dtimPeriod; + mlm_start_req->wps_state = session->wps_state; + + } else { + if (wlan_cfg_get_int(mac_ctx, + WNI_CFG_DTIM_PERIOD, &val) != eSIR_SUCCESS) + lim_log(mac_ctx, LOGP, + FL("could not retrieve DTIM Period")); + mlm_start_req->dtimPeriod = (uint8_t) val; + } + + if (wlan_cfg_get_int(mac_ctx, WNI_CFG_CFP_PERIOD, &val) != + eSIR_SUCCESS) + lim_log(mac_ctx, LOGP, + FL("could not retrieve Beacon interval")); + mlm_start_req->cfParamSet.cfpPeriod = (uint8_t) val; + + if (wlan_cfg_get_int(mac_ctx, WNI_CFG_CFP_MAX_DURATION, &val) != + eSIR_SUCCESS) + lim_log(mac_ctx, LOGP, + FL("could not retrieve CFPMaxDuration")); + mlm_start_req->cfParamSet.cfpMaxDuration = (uint16_t) val; + + /* + * this may not be needed anymore now, + * as rateSet is now included in the + * session entry and MLM has session context. + */ + qdf_mem_copy((void *)&mlm_start_req->rateSet, + (void *)&session->rateSet, + sizeof(tSirMacRateSet)); + + /* Now populate the 11n related parameters */ + mlm_start_req->nwType = session->nwType; + mlm_start_req->htCapable = session->htCapability; + + mlm_start_req->htOperMode = mac_ctx->lim.gHTOperMode; + /* Unused */ + mlm_start_req->dualCTSProtection = + mac_ctx->lim.gHTDualCTSProtection; + mlm_start_req->txChannelWidthSet = + session->htRecommendedTxWidthSet; + + session->limRFBand = lim_get_rf_band(channel_number); + + /* Initialize 11h Enable Flag */ + session->lim11hEnable = 0; + if ((mlm_start_req->bssType != eSIR_IBSS_MODE) && + (SIR_BAND_5_GHZ == session->limRFBand)) { + if (wlan_cfg_get_int(mac_ctx, + WNI_CFG_11H_ENABLED, &val) != eSIR_SUCCESS) + lim_log(mac_ctx, LOGP, + FL("Fail to get WNI_CFG_11H_ENABLED ")); + else + session->lim11hEnable = val; + + if (session->lim11hEnable && + (eSIR_INFRA_AP_MODE == + mlm_start_req->bssType)) { + cfg_get_wmi_dfs_master_param = + wlan_cfg_get_int(mac_ctx, + WNI_CFG_DFS_MASTER_ENABLED, + &val); + session->lim11hEnable = val; + } + if (cfg_get_wmi_dfs_master_param != eSIR_SUCCESS) + /* Failed get CFG WNI_CFG_DFS_MASTER_ENABLED */ + lim_log(mac_ctx, LOGE, + FL("Get Fail, CFG DFS ENABLE")); + } + + if (!session->lim11hEnable) { + if (cfg_set_int(mac_ctx, + WNI_CFG_LOCAL_POWER_CONSTRAINT, 0) != + eSIR_SUCCESS) + /* + * Failed to set the CFG param + * WNI_CFG_LOCAL_POWER_CONSTRAINT + */ + lim_log(mac_ctx, LOGE, + FL("Set LOCAL_POWER_CONSTRAINT failed")); + } + + session->limPrevSmeState = session->limSmeState; + session->limSmeState = eLIM_SME_WT_START_BSS_STATE; + MTRACE(mac_trace + (mac_ctx, TRACE_CODE_SME_STATE, + session->peSessionId, + session->limSmeState)); + + lim_post_mlm_message(mac_ctx, LIM_MLM_START_REQ, + (uint32_t *) mlm_start_req); + return; + } else { + + lim_log(mac_ctx, LOGE, + FL("Received unexpected START_BSS_REQ, in state %X"), + mac_ctx->lim.gLimSmeState); + ret_code = eSIR_SME_BSS_ALREADY_STARTED_OR_JOINED; + goto free; + } /* if (mac_ctx->lim.gLimSmeState == eLIM_SME_OFFLINE_STATE) */ + +free: + if ((session != NULL) && + (session->pLimStartBssReq == sme_start_bss_req)) { + session->pLimStartBssReq = NULL; + } + if (NULL != sme_start_bss_req) + qdf_mem_free(sme_start_bss_req); + if (NULL != mlm_start_req) + qdf_mem_free(mlm_start_req); + if (NULL != session) { + pe_delete_session(mac_ctx, session); + session = NULL; + } + lim_send_sme_start_bss_rsp(mac_ctx, eWNI_SME_START_BSS_RSP, ret_code, + session, sme_session_id, sme_transaction_id); +} + +/** + * __lim_process_sme_start_bss_req() - Call handler to start BSS + * + * @pMac: Global MAC context + * @pMsg: Message pointer + * + * Wrapper for the function __lim_handle_sme_start_bss_request + * This message will be defered until softmac come out of + * scan mode or if we have detected radar on the current + * operating channel. + * + * return true - If we consumed the buffer + * false - If have defered the message. + */ +static bool __lim_process_sme_start_bss_req(tpAniSirGlobal pMac, tpSirMsgQ pMsg) +{ + if (__lim_is_defered_msg_for_learn(pMac, pMsg) || + __lim_is_defered_msg_for_radar(pMac, pMsg)) { + /** + * If message defered, buffer is not consumed yet. + * So return false + */ + return false; + } + + __lim_handle_sme_start_bss_request(pMac, (uint32_t *) pMsg->bodyptr); + return true; +} + +/** + * lim_get_random_bssid() + * + * FUNCTION:This function is called to process generate the random number for bssid + * This function is called to process SME_SCAN_REQ message + * from HDD or upper layer application. + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * 1. geneartes the unique random number for bssid in ibss + * + * @param pMac Pointer to Global MAC structure + * @param *data Pointer to bssid buffer + * @return None + */ +void lim_get_random_bssid(tpAniSirGlobal pMac, uint8_t *data) +{ + uint32_t random[2]; + random[0] = tx_time_get(); + random[0] |= (random[0] << 15); + random[1] = random[0] >> 1; + qdf_mem_copy(data, (uint8_t *) random, sizeof(tSirMacAddr)); +} + +static QDF_STATUS lim_send_hal_start_scan_offload_req(tpAniSirGlobal pMac, + tpSirSmeScanReq pScanReq) +{ + tSirScanOffloadReq *pScanOffloadReq; + uint8_t *p; + tSirMsgQ msg; + uint16_t i, len; + uint16_t addn_ie_len = 0; + tSirRetStatus status, rc = eSIR_SUCCESS; + tDot11fIEExtCap extracted_extcap = {0}; + bool extcap_present = true; + + if (pScanReq->uIEFieldLen) { + status = lim_strip_extcap_update_struct(pMac, + (uint8_t *) pScanReq + pScanReq->uIEFieldOffset, + &pScanReq->uIEFieldLen, &extracted_extcap); + + if (eSIR_SUCCESS != status) { + extcap_present = false; + lim_log(pMac, LOG1, + FL("Unable to Strip ExtCap IE from Scan Req")); + } + + if (extcap_present) { + lim_log(pMac, LOG1, + FL("Extcap was part of SCAN IE - Updating FW")); + lim_send_ext_cap_ie(pMac, pScanReq->sessionId, + &extracted_extcap, true); + } + } else { + lim_log(pMac, LOG1, + FL("No IEs in the scan request from supplicant")); + } + + /** + * The tSirScanOffloadReq will reserve the space for first channel, + * so allocate the memory for (numChannels - 1) and uIEFieldLen + */ + len = sizeof(tSirScanOffloadReq) + + (pScanReq->channelList.numChannels - 1) + + pScanReq->uIEFieldLen; + + pScanOffloadReq = qdf_mem_malloc(len); + if (NULL == pScanOffloadReq) { + lim_log(pMac, LOGE, + FL("AllocateMemory failed for pScanOffloadReq")); + return QDF_STATUS_E_NOMEM; + } + + msg.type = WMA_START_SCAN_OFFLOAD_REQ; + msg.bodyptr = pScanOffloadReq; + msg.bodyval = 0; + + qdf_copy_macaddr(&pScanOffloadReq->bssId, &pScanReq->bssId); + + if (pScanReq->numSsid > SIR_SCAN_MAX_NUM_SSID) { + lim_log(pMac, LOGE, + FL("Invalid value (%d) for numSsid"), + SIR_SCAN_MAX_NUM_SSID); + qdf_mem_free(pScanOffloadReq); + return QDF_STATUS_E_FAILURE; + } + + pScanOffloadReq->numSsid = pScanReq->numSsid; + for (i = 0; i < pScanOffloadReq->numSsid; i++) { + pScanOffloadReq->ssId[i].length = pScanReq->ssId[i].length; + qdf_mem_copy((uint8_t *) pScanOffloadReq->ssId[i].ssId, + (uint8_t *) pScanReq->ssId[i].ssId, + pScanOffloadReq->ssId[i].length); + } + + pScanOffloadReq->hiddenSsid = pScanReq->hiddenSsid; + qdf_copy_macaddr(&pScanOffloadReq->selfMacAddr, &pScanReq->selfMacAddr); + pScanOffloadReq->bssType = pScanReq->bssType; + pScanOffloadReq->dot11mode = pScanReq->dot11mode; + pScanOffloadReq->scanType = pScanReq->scanType; + pScanOffloadReq->minChannelTime = pScanReq->minChannelTime; + pScanOffloadReq->maxChannelTime = pScanReq->maxChannelTime; + pScanOffloadReq->scan_num_probes = pScanReq->scan_num_probes; + pScanOffloadReq->scan_probe_repeat_time = + pScanReq->scan_probe_repeat_time; + pScanOffloadReq->restTime = pScanReq->restTime; + pScanOffloadReq->min_rest_time = pScanReq->min_rest_time; + pScanOffloadReq->idle_time = pScanReq->idle_time; + pScanOffloadReq->scan_adaptive_dwell_mode = + pScanReq->scan_adaptive_dwell_mode; + + for (i = 0; i < pMac->lim.maxBssId; i++) { + tpPESession session_entry = + pe_find_session_by_sme_session_id(pMac, i); + if (session_entry && + (eLIM_MLM_LINK_ESTABLISHED_STATE == + session_entry->limMlmState) && + (session_entry->beaconParams.beaconInterval + < BEACON_INTERVAL_THRESHOLD)) { + pScanOffloadReq->burst_scan_duration = + STA_BURST_SCAN_DURATION; + break; + } + } + + /* for normal scan, the value for p2pScanType should be 0 + always */ + if (pScanReq->p2pSearch) + pScanOffloadReq->p2pScanType = P2P_SCAN_TYPE_SEARCH; + + pScanOffloadReq->sessionId = pScanReq->sessionId; + pScanOffloadReq->scan_id = pScanReq->scan_id; + pScanOffloadReq->scan_requestor_id = USER_SCAN_REQUESTOR_ID; + pScanOffloadReq->scan_adaptive_dwell_mode = + pScanReq->scan_adaptive_dwell_mode; + + if (pScanOffloadReq->sessionId >= pMac->lim.maxBssId) + lim_log(pMac, LOGE, FL("Invalid pe sessionID : %d"), + pScanOffloadReq->sessionId); + + pScanOffloadReq->channelList.numChannels = + pScanReq->channelList.numChannels; + p = &(pScanOffloadReq->channelList.channelNumber[0]); + for (i = 0; i < pScanOffloadReq->channelList.numChannels; i++) + p[i] = pScanReq->channelList.channelNumber[i]; + + pScanOffloadReq->uIEFieldLen = pScanReq->uIEFieldLen; + pScanOffloadReq->uIEFieldOffset = len - addn_ie_len - + pScanOffloadReq->uIEFieldLen; + qdf_mem_copy((uint8_t *) pScanOffloadReq + + pScanOffloadReq->uIEFieldOffset, + (uint8_t *) pScanReq + pScanReq->uIEFieldOffset, + pScanReq->uIEFieldLen); + + pScanOffloadReq->enable_scan_randomization = + pScanReq->enable_scan_randomization; + if (pScanOffloadReq->enable_scan_randomization) { + qdf_mem_copy(pScanOffloadReq->mac_addr, pScanReq->mac_addr, + QDF_MAC_ADDR_SIZE); + qdf_mem_copy(pScanOffloadReq->mac_addr_mask, + pScanReq->mac_addr_mask, QDF_MAC_ADDR_SIZE); + } + + rc = wma_post_ctrl_msg(pMac, &msg); + if (rc != eSIR_SUCCESS) { + lim_log(pMac, LOGE, FL("wma_post_ctrl_msg() return failure")); + qdf_mem_free(pScanOffloadReq); + return QDF_STATUS_E_FAILURE; + } + + lim_log(pMac, LOG1, FL("Processed Offload Scan Request Successfully")); + + return QDF_STATUS_SUCCESS; +} + +/** + * __lim_process_sme_scan_req() - Process the SME Scan Request + * @mac_ctx: Global MAC Context + * @msg_buf: Buffer which contains the request and pertinent parameters + * + * This function is called to process SME_SCAN_REQ message + * from HDD or upper layer application. + * + * Return: None + */ + +static void __lim_process_sme_scan_req(tpAniSirGlobal mac_ctx, + uint32_t *msg_buf) +{ + tpSirSmeScanReq scan_req; + uint8_t valid_req = 0; + +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM /* FEATURE_WLAN_DIAG_SUPPORT */ + lim_diag_event_report(mac_ctx, WLAN_PE_DIAG_SCAN_REQ_EVENT, NULL, + eSIR_SUCCESS, eSIR_SUCCESS); +#endif + mac_ctx->lim.beacon_probe_rsp_cnt_per_scan = 0; + + scan_req = (tpSirSmeScanReq) msg_buf; + lim_log(mac_ctx, LOG1, + FL("SME SCAN REQ id %d numChan %d min %d max %d IELen %d first %d fresh %d unique %d type %s (%d) rsp %d"), + scan_req->scan_id, scan_req->channelList.numChannels, + scan_req->minChannelTime, scan_req->maxChannelTime, + scan_req->uIEFieldLen, scan_req->returnAfterFirstMatch, + scan_req->returnFreshResults, scan_req->returnUniqueResults, + lim_scan_type_to_string(scan_req->scanType), + scan_req->scanType, mac_ctx->lim.gLimRspReqd ? 1 : 0); + /* + * Since scan req always requires a response, we will overwrite response + * required here. This is added esp to take care of the condition where + * in p2p go case, we hold the scan req and insert single NOA. We send + * the held scan request to FW later on getting start NOA ind from FW so + * we lose state of the gLimRspReqd flag for the scan req if any other + * request comes by then. e.g. While unit testing, we found when insert + * single NOA is done, we see a get stats request which turns the flag + * gLimRspReqd to false; now when we actually start the saved scan req + * for init scan after getting NOA started, the gLimRspReqd being a + * global flag is showing false instead of true value for this saved + * scan req. Since all scan reqs coming to lim require a response, + * there is no harm in setting the global flag gLimRspReqd to true here. + */ + mac_ctx->lim.gLimRspReqd = true; + + /* + * copy the Self MAC address from SmeReq to the globalplace, + * used for sending probe req + */ + sir_copy_mac_addr(mac_ctx->lim.gSelfMacAddr, + scan_req->selfMacAddr.bytes); + valid_req = lim_is_sme_scan_req_valid(mac_ctx, scan_req); + + if (!valid_req || mac_ctx->lim.scan_disabled) { + lim_log(mac_ctx, LOGE, + FL("Scan disabled %d, Valid Scan Req %d"), + mac_ctx->lim.scan_disabled, valid_req); + + if (mac_ctx->lim.gLimRspReqd) { + mac_ctx->lim.gLimRspReqd = false; + + lim_send_sme_scan_rsp(mac_ctx, + eSIR_SME_INVALID_PARAMETERS, + scan_req->sessionId, + scan_req->transactionId, + scan_req->scan_id); + } + return; + } + + /* + * If scan request is received in idle, joinFailed + * states or in link established state (in STA role) + * or in normal state (in STA-in-IBSS/AP role) with + * 'return fresh scan results' request from HDD or + * it is periodic background scanning request, + * trigger fresh scan request to MLM + */ + if (__lim_fresh_scan_reqd(mac_ctx, scan_req->returnFreshResults)) { + + mac_ctx->lim.gLim24Band11dScanDone = 0; + mac_ctx->lim.gLim50Band11dScanDone = 0; + mac_ctx->lim.gLimReturnAfterFirstMatch = + scan_req->returnAfterFirstMatch; + mac_ctx->lim.gLimReturnUniqueResults = + ((scan_req->returnUniqueResults) > 0 ? true : false); + + if (QDF_STATUS_SUCCESS != + lim_send_hal_start_scan_offload_req(mac_ctx, + scan_req)) { + lim_log(mac_ctx, LOGE, FL( + "Couldn't send Offload scan request")); + lim_send_sme_scan_rsp(mac_ctx, + eSIR_SME_INVALID_PARAMETERS, + scan_req->sessionId, + scan_req->transactionId, + scan_req->scan_id); + return; + } + } else { + /* In all other cases return 'cached' scan results */ + if (mac_ctx->lim.gLimRspReqd) { + mac_ctx->lim.gLimRspReqd = false; + lim_send_sme_scan_rsp(mac_ctx, eSIR_SME_SUCCESS, + scan_req->sessionId, + scan_req->transactionId, scan_req->scan_id); + } + } +} + +/** + * __lim_process_clear_dfs_channel_list() + * + ***FUNCTION: + ***Clear DFS channel list when country is changed/aquired. + .*This message is sent from SME. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param pMac Pointer to Global MAC structure + * @param *pMsgBuf A pointer to the SME message buffer + * @return None + */ +static void __lim_process_clear_dfs_channel_list(tpAniSirGlobal pMac, tpSirMsgQ pMsg) +{ + qdf_mem_set(&pMac->lim.dfschannelList, sizeof(tSirDFSChannelList), 0); +} + +/** + * __lim_process_sme_join_req() - process SME_JOIN_REQ message + * @mac_ctx: Pointer to Global MAC structure + * @msg_buf: A pointer to the SME message buffer + * + * This function is called to process SME_JOIN_REQ message + * from HDD or upper layer application. + * + * Return: None + */ +static void +__lim_process_sme_join_req(tpAniSirGlobal mac_ctx, uint32_t *msg_buf) +{ + tpSirSmeJoinReq sme_join_req = NULL; + tLimMlmJoinReq *mlm_join_req; + tSirResultCodes ret_code = eSIR_SME_SUCCESS; + uint32_t val = 0; + uint16_t n_size; + uint8_t session_id; + tpPESession session = NULL; + uint8_t sme_session_id = 0; + uint16_t sme_transaction_id = 0; + int8_t local_power_constraint = 0, reg_max = 0; + uint16_t ie_len; + uint8_t *vendor_ie; + tSirBssDescription *bss_desc; + struct vdev_type_nss *vdev_type_nss; + + if (!mac_ctx || !msg_buf) { + QDF_TRACE(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_ERROR, + FL("JOIN REQ with invalid data")); + return; + } + +/* FEATURE_WLAN_DIAG_SUPPORT */ +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM + /* + * Not sending any session, since it is not created yet. + * The response whould have correct state. + */ + lim_diag_event_report(mac_ctx, WLAN_PE_DIAG_JOIN_REQ_EVENT, NULL, 0, 0); +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + + /* + * Expect Join request in idle state. + * Reassociate request is expected in link established state. + */ + + /* Global SME and LIM states are not defined yet for BT-AMP Support */ + if (mac_ctx->lim.gLimSmeState == eLIM_SME_IDLE_STATE) { + n_size = __lim_get_sme_join_req_size_for_alloc((uint8_t *) + msg_buf); + + sme_join_req = qdf_mem_malloc(n_size); + if (NULL == sme_join_req) { + lim_log(mac_ctx, LOGP, + FL("AllocateMemory failed for sme_join_req")); + ret_code = eSIR_SME_RESOURCES_UNAVAILABLE; + goto end; + } + (void)qdf_mem_copy((void *)sme_join_req, (void *)msg_buf, + n_size); + + if (!lim_is_sme_join_req_valid(mac_ctx, sme_join_req)) { + /* Received invalid eWNI_SME_JOIN_REQ */ + /* Log the event */ + lim_log(mac_ctx, LOGW, + FL("SessionId:%d JOIN REQ with invalid data"), + sme_join_req->sessionId); + ret_code = eSIR_SME_INVALID_PARAMETERS; + goto end; + } + + /* + * Update the capability here itself as this is used in + * lim_extract_ap_capability() below. If not updated issues + * like not honoring power constraint on 1st association after + * driver loading might occur. + */ + lim_update_rrm_capability(mac_ctx, sme_join_req); + + bss_desc = &sme_join_req->bssDescription; + /* check for the existence of start BSS session */ + session = pe_find_session_by_bssid(mac_ctx, bss_desc->bssId, + &session_id); + + if (session != NULL) { + lim_log(mac_ctx, LOGE, + FL("Session(%d) Already exists for BSSID: " + MAC_ADDRESS_STR " in limSmeState = %X"), + session_id, + MAC_ADDR_ARRAY(bss_desc->bssId), + session->limSmeState); + + if (session->limSmeState == eLIM_SME_LINK_EST_STATE && + session->smeSessionId == sme_join_req->sessionId) { + /* + * Received eWNI_SME_JOIN_REQ for same + * BSS as currently associated. + * Log the event and send success + */ + lim_log(mac_ctx, LOGW, + FL("SessionId: %d"), session_id); + lim_log(mac_ctx, LOGW, + FL("JOIN_REQ for current joined BSS")); + /* Send Join success response to host */ + ret_code = eSIR_SME_ALREADY_JOINED_A_BSS; + session = NULL; + goto end; + } else { + lim_log(mac_ctx, LOGE, + FL("JOIN_REQ not for current joined BSS")); + ret_code = eSIR_SME_REFUSED; + session = NULL; + goto end; + } + } else { + /* + * Session Entry does not exist for given BSSId + * Try to Create a new session + */ + session = pe_create_session(mac_ctx, bss_desc->bssId, + &session_id, mac_ctx->lim.maxStation, + eSIR_INFRASTRUCTURE_MODE); + if (session == NULL) { + lim_log(mac_ctx, LOGE, + FL("Session Can not be created ")); + ret_code = eSIR_SME_RESOURCES_UNAVAILABLE; + goto end; + } else + lim_log(mac_ctx, LOG2, + FL("SessionId:%d New session created"), + session_id); + } + session->max_amsdu_num = sme_join_req->max_amsdu_num; + + /* + * Store Session related parameters + * Store PE session Id in session Table + */ + session->peSessionId = session_id; + + /* store the smejoin req handle in session table */ + session->pLimJoinReq = sme_join_req; + + /* Store SME session Id in sessionTable */ + session->smeSessionId = sme_join_req->sessionId; + + /* Store SME transaction Id in session Table */ + session->transactionId = sme_join_req->transactionId; + + /* Store beaconInterval */ + session->beaconParams.beaconInterval = + bss_desc->beaconInterval; + + qdf_mem_copy(&(session->htConfig), &(sme_join_req->htConfig), + sizeof(session->htConfig)); + + qdf_mem_copy(&(session->vht_config), + &(sme_join_req->vht_config), + sizeof(session->vht_config)); + + /* Copying of bssId is already done, while creating session */ + sir_copy_mac_addr(session->selfMacAddr, + sme_join_req->selfMacAddr); + session->bssType = sme_join_req->bsstype; + + session->statypeForBss = STA_ENTRY_PEER; + session->limWmeEnabled = sme_join_req->isWMEenabled; + session->limQosEnabled = sme_join_req->isQosEnabled; + session->wps_registration = sme_join_req->wps_registration; + + session->enable_bcast_probe_rsp = + sme_join_req->enable_bcast_probe_rsp; + + /* Update supplicant configured ignore assoc disallowed */ + session->ignore_assoc_disallowed = + sme_join_req->ignore_assoc_disallowed; + /* Store vendor specfic IE for CISCO AP */ + ie_len = (bss_desc->length + sizeof(bss_desc->length) - + GET_FIELD_OFFSET(tSirBssDescription, ieFields)); + + vendor_ie = cfg_get_vendor_ie_ptr_from_oui(mac_ctx, + SIR_MAC_CISCO_OUI, SIR_MAC_CISCO_OUI_SIZE, + ((uint8_t *)&bss_desc->ieFields), ie_len); + + if (NULL != vendor_ie) { + lim_log(mac_ctx, LOG1, FL("Cisco vendor OUI present")); + session->isCiscoVendorAP = true; + } else { + session->isCiscoVendorAP = false; + } + + /* Copy the dot 11 mode in to the session table */ + + session->dot11mode = sme_join_req->dot11mode; +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH + session->cc_switch_mode = sme_join_req->cc_switch_mode; +#endif + session->nwType = bss_desc->nwType; + session->enableAmpduPs = sme_join_req->enableAmpduPs; + session->enableHtSmps = sme_join_req->enableHtSmps; + session->htSmpsvalue = sme_join_req->htSmps; + session->send_smps_action = + sme_join_req->send_smps_action; + /* + * By default supported NSS 1x1 is set to true + * and later on updated while determining session + * supported rates which is the intersection of + * self and peer rates + */ + session->supported_nss_1x1 = true; + /*Store Persona */ + session->pePersona = sme_join_req->staPersona; + lim_log(mac_ctx, LOG1, + FL("enable Smps: %d mode: %d send action: %d supported nss 1x1: %d pePersona %d cbMode %d"), + session->enableHtSmps, + session->htSmpsvalue, + session->send_smps_action, + session->supported_nss_1x1, + session->pePersona, + sme_join_req->cbMode); + + /*Store Persona */ + session->pePersona = sme_join_req->staPersona; + QDF_TRACE(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_INFO, + FL("PE PERSONA=%d cbMode %u"), + session->pePersona, sme_join_req->cbMode); + /* Copy The channel Id to the session Table */ + session->currentOperChannel = bss_desc->channelId; + if (IS_5G_CH(session->currentOperChannel)) + vdev_type_nss = &mac_ctx->vdev_type_nss_5g; + else + vdev_type_nss = &mac_ctx->vdev_type_nss_2g; + if (session->pePersona == QDF_P2P_CLIENT_MODE) + session->vdev_nss = vdev_type_nss->p2p_cli; + else + session->vdev_nss = vdev_type_nss->sta; + session->nss = session->vdev_nss; + session->vhtCapability = + IS_DOT11_MODE_VHT(session->dot11mode); + if (session->vhtCapability) { + if (session->pePersona == QDF_STA_MODE) { + session->vht_config.su_beam_formee = + sme_join_req->vht_config.su_beam_formee; + } else { + session->vht_config.su_beam_formee = 0; + } + session->enableVhtpAid = + sme_join_req->enableVhtpAid; + session->enableVhtGid = + sme_join_req->enableVhtGid; + lim_log(mac_ctx, LOG1, FL("vht su bformer [%d]"), + session->vht_config.su_beam_former); + } + + lim_log(mac_ctx, LOG1, + FL("vhtCapability: %d su_beam_formee: %d txbf_csn_value: %d su_tx_bformer %d"), + session->vhtCapability, + session->vht_config.su_beam_formee, + session->vht_config.csnof_beamformer_antSup, + session->vht_config.su_beam_former); + /*Phy mode */ + session->gLimPhyMode = bss_desc->nwType; + handle_ht_capabilityand_ht_info(mac_ctx, session); + /* cbMode is already merged value of peer and self - + * done by csr in csr_get_cb_mode_from_ies */ + session->htSupportedChannelWidthSet = + (sme_join_req->cbMode) ? 1 : 0; + session->htRecommendedTxWidthSet = + session->htSupportedChannelWidthSet; + session->htSecondaryChannelOffset = sme_join_req->cbMode; + + if (PHY_DOUBLE_CHANNEL_HIGH_PRIMARY == sme_join_req->cbMode) { + session->ch_center_freq_seg0 = + session->currentOperChannel - 2; + session->ch_width = CH_WIDTH_40MHZ; + } else if (PHY_DOUBLE_CHANNEL_LOW_PRIMARY == + sme_join_req->cbMode) { + session->ch_center_freq_seg0 = + session->currentOperChannel + 2; + session->ch_width = CH_WIDTH_40MHZ; + } else { + session->ch_center_freq_seg0 = 0; + session->ch_width = CH_WIDTH_20MHZ; + } + + /* Record if management frames need to be protected */ +#ifdef WLAN_FEATURE_11W + if (eSIR_ED_AES_128_CMAC == sme_join_req->MgmtEncryptionType) + session->limRmfEnabled = 1; + else + session->limRmfEnabled = 0; +#endif + +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM + session->rssi = bss_desc->rssi; +#endif + + /* Copy the SSID from smejoinreq to session entry */ + session->ssId.length = sme_join_req->ssId.length; + qdf_mem_copy(session->ssId.ssId, sme_join_req->ssId.ssId, + session->ssId.length); + + /* + * Determin 11r or ESE connection based on input from SME + * which inturn is dependent on the profile the user wants + * to connect to, So input is coming from supplicant + */ + session->is11Rconnection = sme_join_req->is11Rconnection; +#ifdef FEATURE_WLAN_ESE + session->isESEconnection = sme_join_req->isESEconnection; +#endif + session->isFastTransitionEnabled = + sme_join_req->isFastTransitionEnabled; + + session->isFastRoamIniFeatureEnabled = + sme_join_req->isFastRoamIniFeatureEnabled; + session->txLdpcIniFeatureEnabled = + sme_join_req->txLdpcIniFeatureEnabled; + + if (session->bssType == eSIR_INFRASTRUCTURE_MODE) { + session->limSystemRole = eLIM_STA_ROLE; + } else { + /* + * Throw an error and return and make + * sure to delete the session. + */ + lim_log(mac_ctx, LOGE, + FL("recvd JOIN_REQ with invalid bss type %d"), + session->bssType); + ret_code = eSIR_SME_INVALID_PARAMETERS; + goto end; + } + + if (sme_join_req->addIEScan.length) + qdf_mem_copy(&session->pLimJoinReq->addIEScan, + &sme_join_req->addIEScan, sizeof(tSirAddie)); + + if (sme_join_req->addIEAssoc.length) + qdf_mem_copy(&session->pLimJoinReq->addIEAssoc, + &sme_join_req->addIEAssoc, sizeof(tSirAddie)); + + val = sizeof(tLimMlmJoinReq) + + session->pLimJoinReq->bssDescription.length + 2; + mlm_join_req = qdf_mem_malloc(val); + if (NULL == mlm_join_req) { + lim_log(mac_ctx, LOGP, + FL("AllocateMemory failed for mlmJoinReq")); + ret_code = eSIR_SME_RESOURCES_UNAVAILABLE; + goto end; + } + + /* PE SessionId is stored as a part of JoinReq */ + mlm_join_req->sessionId = session->peSessionId; + + if (wlan_cfg_get_int(mac_ctx, WNI_CFG_JOIN_FAILURE_TIMEOUT, + (uint32_t *) &mlm_join_req->joinFailureTimeout) != + eSIR_SUCCESS) { + lim_log(mac_ctx, LOGP, + FL("couldn't retrieve JoinFailureTimer value" + " setting to default value")); + mlm_join_req->joinFailureTimeout = + WNI_CFG_JOIN_FAILURE_TIMEOUT_STADEF; + } + + /* copy operational rate from session */ + qdf_mem_copy((void *)&session->rateSet, + (void *)&sme_join_req->operationalRateSet, + sizeof(tSirMacRateSet)); + qdf_mem_copy((void *)&session->extRateSet, + (void *)&sme_join_req->extendedRateSet, + sizeof(tSirMacRateSet)); + /* + * this may not be needed anymore now, as rateSet is now + * included in the session entry and MLM has session context. + */ + qdf_mem_copy((void *)&mlm_join_req->operationalRateSet, + (void *)&session->rateSet, + sizeof(tSirMacRateSet)); + + session->encryptType = sme_join_req->UCEncryptionType; + + mlm_join_req->bssDescription.length = + session->pLimJoinReq->bssDescription.length; + + qdf_mem_copy((uint8_t *) &mlm_join_req->bssDescription.bssId, + (uint8_t *) + &session->pLimJoinReq->bssDescription.bssId, + session->pLimJoinReq->bssDescription.length + 2); + + session->limCurrentBssCaps = + session->pLimJoinReq->bssDescription.capabilityInfo; + + reg_max = cfg_get_regulatory_max_transmit_power(mac_ctx, + session->currentOperChannel); + local_power_constraint = reg_max; + + lim_extract_ap_capability(mac_ctx, + (uint8_t *) + session->pLimJoinReq->bssDescription.ieFields, + lim_get_ielen_from_bss_description( + &session->pLimJoinReq->bssDescription), + &session->limCurrentBssQosCaps, + &session->limCurrentBssPropCap, + &session->gLimCurrentBssUapsd, + &local_power_constraint, session); + + /* + * Once the AP capabilities are available then set the + * beam forming capabilities accordingly. + */ + if (session->nss == 1) { + session->vht_config.su_beam_former = 0; + session->vht_config.tx_stbc = 0; + session->vht_config.num_soundingdim = 0; + session->htConfig.ht_tx_stbc = 0; + } + + session->maxTxPower = lim_get_max_tx_power(reg_max, + local_power_constraint, + mac_ctx->roam.configParam.nTxPowerCap); + + lim_log(mac_ctx, LOG1, + FL("Reg max %d local power con %d max tx pwr %d"), + reg_max, local_power_constraint, session->maxTxPower); + + if (session->gLimCurrentBssUapsd) { + session->gUapsdPerAcBitmask = + session->pLimJoinReq->uapsdPerAcBitmask; + lim_log(mac_ctx, LOG1, + FL("UAPSD flag for all AC - 0x%2x"), + session->gUapsdPerAcBitmask); + + /* resetting the dynamic uapsd mask */ + session->gUapsdPerAcDeliveryEnableMask = 0; + session->gUapsdPerAcTriggerEnableMask = 0; + } + + session->limRFBand = + lim_get_rf_band(session->currentOperChannel); + + /* Initialize 11h Enable Flag */ + if (SIR_BAND_5_GHZ == session->limRFBand) { + if (wlan_cfg_get_int(mac_ctx, WNI_CFG_11H_ENABLED, + &val) != eSIR_SUCCESS) { + lim_log(mac_ctx, LOGP, + FL("Fail to get WNI_CFG_11H_ENABLED ")); + session->lim11hEnable = + WNI_CFG_11H_ENABLED_STADEF; + } else { + session->lim11hEnable = val; + } + } else { + session->lim11hEnable = 0; + } + + /* + * To care of the scenario when STA transitions from + * IBSS to Infrastructure mode. + */ + mac_ctx->lim.gLimIbssCoalescingHappened = false; + + session->limPrevSmeState = session->limSmeState; + session->limSmeState = eLIM_SME_WT_JOIN_STATE; + MTRACE(mac_trace(mac_ctx, TRACE_CODE_SME_STATE, + session->peSessionId, + session->limSmeState)); + + /* Indicate whether spectrum management is enabled */ + session->spectrumMgtEnabled = + sme_join_req->spectrumMgtIndicator; + + /* Enable the spectrum management if this is a DFS channel */ + if (session->country_info_present && + lim_isconnected_on_dfs_channel( + session->currentOperChannel)) + session->spectrumMgtEnabled = true; + + session->isOSENConnection = sme_join_req->isOSENConnection; + + /* Issue LIM_MLM_JOIN_REQ to MLM */ + lim_post_mlm_message(mac_ctx, LIM_MLM_JOIN_REQ, + (uint32_t *) mlm_join_req); + return; + + } else { + /* Received eWNI_SME_JOIN_REQ un expected state */ + lim_log(mac_ctx, LOGE, + FL("received unexpected SME_JOIN_REQ in state %X"), + mac_ctx->lim.gLimSmeState); + lim_print_sme_state(mac_ctx, LOGE, mac_ctx->lim.gLimSmeState); + ret_code = eSIR_SME_UNEXPECTED_REQ_RESULT_CODE; + session = NULL; + goto end; + } + +end: + lim_get_session_info(mac_ctx, (uint8_t *) msg_buf, + &sme_session_id, &sme_transaction_id); + + if (sme_join_req) { + qdf_mem_free(sme_join_req); + sme_join_req = NULL; + if (NULL != session) + session->pLimJoinReq = NULL; + } + if (ret_code != eSIR_SME_SUCCESS) { + if (NULL != session) { + pe_delete_session(mac_ctx, session); + session = NULL; + } + } + lim_log(mac_ctx, LOG1, + FL("Send failure status on sessionid: %d with ret_code = %d"), + sme_session_id, ret_code); + lim_send_sme_join_reassoc_rsp(mac_ctx, eWNI_SME_JOIN_RSP, ret_code, + eSIR_MAC_UNSPEC_FAILURE_STATUS, session, sme_session_id, + sme_transaction_id); +} + +uint8_t lim_get_max_tx_power(int8_t regMax, int8_t apTxPower, + uint8_t iniTxPower) +{ + uint8_t maxTxPower = 0; + uint8_t txPower = QDF_MIN(regMax, (apTxPower)); + txPower = QDF_MIN(txPower, iniTxPower); + if ((txPower >= MIN_TX_PWR_CAP) && (txPower <= MAX_TX_PWR_CAP)) + maxTxPower = txPower; + else if (txPower < MIN_TX_PWR_CAP) + maxTxPower = MIN_TX_PWR_CAP; + else + maxTxPower = MAX_TX_PWR_CAP; + + return maxTxPower; +} + +/** + * __lim_process_sme_reassoc_req() - process reassoc req + * + * @mac_ctx: Pointer to Global MAC structure + * @msg_buf: pointer to the SME message buffer + * + * This function is called to process SME_REASSOC_REQ message + * from HDD or upper layer application. + * + * Return: None + */ + +static void __lim_process_sme_reassoc_req(tpAniSirGlobal mac_ctx, + uint32_t *msg_buf) +{ + uint16_t caps; + uint32_t val; + tpSirSmeJoinReq reassoc_req = NULL; + tLimMlmReassocReq *mlm_reassoc_req; + tSirResultCodes ret_code = eSIR_SME_SUCCESS; + tpPESession session_entry = NULL; + uint8_t session_id; + uint8_t sme_session_id; + uint16_t transaction_id; + int8_t local_pwr_constraint = 0, reg_max = 0; + uint32_t tele_bcn_en = 0; + uint16_t size; + + lim_log(mac_ctx, LOG3, FL("Received REASSOC_REQ")); + + size = __lim_get_sme_join_req_size_for_alloc((uint8_t *)msg_buf); + reassoc_req = qdf_mem_malloc(size); + if (NULL == reassoc_req) { + lim_log(mac_ctx, LOGP, + FL("call to AllocateMemory failed for reassoc_req")); + + ret_code = eSIR_SME_RESOURCES_UNAVAILABLE; + goto end; + } + (void)qdf_mem_copy((void *)reassoc_req, (void *)msg_buf, size); + + if (!lim_is_sme_join_req_valid(mac_ctx, + (tpSirSmeJoinReq)reassoc_req)) { + /* + * Received invalid eWNI_SME_REASSOC_REQ + */ + lim_log(mac_ctx, LOGW, + FL("received SME_REASSOC_REQ with invalid data")); + + ret_code = eSIR_SME_INVALID_PARAMETERS; + goto end; + } + + session_entry = pe_find_session_by_bssid(mac_ctx, + reassoc_req->bssDescription.bssId, + &session_id); + if (session_entry == NULL) { + lim_log(mac_ctx, LOGE, + FL("Session does not exist for given bssId")); + lim_print_mac_addr(mac_ctx, reassoc_req->bssDescription.bssId, + LOGE); + ret_code = eSIR_SME_INVALID_PARAMETERS; + lim_get_session_info(mac_ctx, (uint8_t *)msg_buf, + &sme_session_id, &transaction_id); + session_entry = + pe_find_session_by_sme_session_id(mac_ctx, + sme_session_id); + if (session_entry != NULL) + lim_handle_sme_join_result(mac_ctx, + eSIR_SME_INVALID_PARAMETERS, + eSIR_MAC_UNSPEC_FAILURE_STATUS, + session_entry); + goto end; + } +#ifdef FEATURE_WLAN_DIAG_SUPPORT /* FEATURE_WLAN_DIAG_SUPPORT */ + lim_diag_event_report(mac_ctx, WLAN_PE_DIAG_REASSOC_REQ_EVENT, + session_entry, eSIR_SUCCESS, eSIR_SUCCESS); +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + /* mac_ctx->lim.gpLimReassocReq = reassoc_req;//TO SUPPORT BT-AMP */ + + /* Store the reassoc handle in the session Table */ + session_entry->pLimReAssocReq = reassoc_req; + + session_entry->dot11mode = reassoc_req->dot11mode; + session_entry->vhtCapability = + IS_DOT11_MODE_VHT(reassoc_req->dot11mode); + + if (session_entry->vhtCapability) { + if (session_entry->pePersona == QDF_STA_MODE) { + session_entry->vht_config.su_beam_formee = + reassoc_req->vht_config.su_beam_formee; + } else { + reassoc_req->vht_config.su_beam_formee = 0; + } + session_entry->enableVhtpAid = + reassoc_req->enableVhtpAid; + session_entry->enableVhtGid = + reassoc_req->enableVhtGid; + lim_log(mac_ctx, LOG1, FL("vht su bformer [%d]"), + session_entry->vht_config.su_beam_former); + } + + lim_log(mac_ctx, LOG1, + FL("vhtCapability: %d su_beam_formee: %d su_tx_bformer %d"), + session_entry->vhtCapability, + session_entry->vht_config.su_beam_formee, + session_entry->vht_config.su_beam_former); + + session_entry->enableHtSmps = reassoc_req->enableHtSmps; + session_entry->htSmpsvalue = reassoc_req->htSmps; + session_entry->send_smps_action = + reassoc_req->send_smps_action; + lim_log(mac_ctx, LOG1, + FL("enableHtSmps: %d htSmps: %d send action: %d supported nss 1x1: %d"), + session_entry->enableHtSmps, + session_entry->htSmpsvalue, + session_entry->send_smps_action, + session_entry->supported_nss_1x1); + /* + * Reassociate request is expected + * in link established state only. + */ + + if (session_entry->limSmeState != eLIM_SME_LINK_EST_STATE) { + if (session_entry->limSmeState == eLIM_SME_WT_REASSOC_STATE) { + /* + * May be from 11r FT pre-auth. So lets check it + * before we bail out + */ + lim_log(mac_ctx, LOG1, FL( + "Session in reassoc state is %d"), + session_entry->peSessionId); + + /* Make sure its our preauth bssid */ + if (qdf_mem_cmp(reassoc_req->bssDescription.bssId, + session_entry->limReAssocbssId, + 6)) { + lim_print_mac_addr(mac_ctx, + reassoc_req->bssDescription. + bssId, LOGE); + lim_log(mac_ctx, LOGP, + FL("Unknown bssId in reassoc state")); + ret_code = eSIR_SME_INVALID_PARAMETERS; + goto end; + } + + lim_process_mlm_ft_reassoc_req(mac_ctx, msg_buf, + session_entry); + return; + } + /* + * Should not have received eWNI_SME_REASSOC_REQ + */ + lim_log(mac_ctx, LOGE, + FL("received unexpected SME_REASSOC_REQ in state %X"), + session_entry->limSmeState); + lim_print_sme_state(mac_ctx, LOGE, session_entry->limSmeState); + + ret_code = eSIR_SME_UNEXPECTED_REQ_RESULT_CODE; + goto end; + } + + qdf_mem_copy(session_entry->limReAssocbssId, + session_entry->pLimReAssocReq->bssDescription.bssId, + sizeof(tSirMacAddr)); + + session_entry->limReassocChannelId = + session_entry->pLimReAssocReq->bssDescription.channelId; + + session_entry->reAssocHtSupportedChannelWidthSet = + (session_entry->pLimReAssocReq->cbMode) ? 1 : 0; + session_entry->reAssocHtRecommendedTxWidthSet = + session_entry->reAssocHtSupportedChannelWidthSet; + session_entry->reAssocHtSecondaryChannelOffset = + session_entry->pLimReAssocReq->cbMode; + + session_entry->limReassocBssCaps = + session_entry->pLimReAssocReq->bssDescription.capabilityInfo; + reg_max = cfg_get_regulatory_max_transmit_power(mac_ctx, + session_entry->currentOperChannel); + local_pwr_constraint = reg_max; + + lim_extract_ap_capability(mac_ctx, + (uint8_t *)session_entry->pLimReAssocReq->bssDescription.ieFields, + lim_get_ielen_from_bss_description( + &session_entry->pLimReAssocReq->bssDescription), + &session_entry->limReassocBssQosCaps, + &session_entry->limReassocBssPropCap, + &session_entry->gLimCurrentBssUapsd, + &local_pwr_constraint, session_entry); + session_entry->maxTxPower = QDF_MIN(reg_max, (local_pwr_constraint)); + lim_log(mac_ctx, LOGE, + FL("Reg max = %d, local pwr constraint = %d, max tx = %d"), + reg_max, local_pwr_constraint, session_entry->maxTxPower); + /* Copy the SSID from session entry to local variable */ + session_entry->limReassocSSID.length = reassoc_req->ssId.length; + qdf_mem_copy(session_entry->limReassocSSID.ssId, + reassoc_req->ssId.ssId, + session_entry->limReassocSSID.length); + if (session_entry->gLimCurrentBssUapsd) { + session_entry->gUapsdPerAcBitmask = + session_entry->pLimReAssocReq->uapsdPerAcBitmask; + lim_log(mac_ctx, LOG1, + FL("UAPSD flag for all AC - 0x%2x"), + session_entry->gUapsdPerAcBitmask); + } + + mlm_reassoc_req = qdf_mem_malloc(sizeof(tLimMlmReassocReq)); + if (NULL == mlm_reassoc_req) { + lim_log(mac_ctx, LOGP, + FL("call to AllocateMemory failed for mlmReassocReq")); + + ret_code = eSIR_SME_RESOURCES_UNAVAILABLE; + goto end; + } + + qdf_mem_copy(mlm_reassoc_req->peerMacAddr, + session_entry->limReAssocbssId, sizeof(tSirMacAddr)); + + if (wlan_cfg_get_int(mac_ctx, WNI_CFG_REASSOCIATION_FAILURE_TIMEOUT, + (uint32_t *)&mlm_reassoc_req->reassocFailureTimeout) != + eSIR_SUCCESS) { + /* + * Could not get ReassocFailureTimeout value + * from CFG. Log error. + */ + lim_log(mac_ctx, LOGP, + FL("could not retrieve ReassocFailureTimeout value")); + } + + if (cfg_get_capability_info(mac_ctx, &caps, session_entry) != + eSIR_SUCCESS) { + /* + * Could not get Capabilities value + * from CFG. Log error. + */ + lim_log(mac_ctx, LOGP, FL( + "could not retrieve Capabilities value")); + } + + lim_update_caps_info_for_bss(mac_ctx, &caps, + reassoc_req->bssDescription.capabilityInfo); + lim_log(mac_ctx, LOG1, FL("Capabilities info Reassoc: 0x%X"), caps); + + mlm_reassoc_req->capabilityInfo = caps; + + /* Update PE session_id */ + mlm_reassoc_req->sessionId = session_id; + + /* + * If telescopic beaconing is enabled, set listen interval to + * WNI_CFG_TELE_BCN_MAX_LI + */ + if (wlan_cfg_get_int(mac_ctx, WNI_CFG_TELE_BCN_WAKEUP_EN, + &tele_bcn_en) != eSIR_SUCCESS) + lim_log(mac_ctx, LOGP, + FL("Couldn't get WNI_CFG_TELE_BCN_WAKEUP_EN")); + + val = WNI_CFG_LISTEN_INTERVAL_STADEF; + + if (tele_bcn_en) { + if (wlan_cfg_get_int(mac_ctx, WNI_CFG_TELE_BCN_MAX_LI, &val) != + eSIR_SUCCESS) + /* + * Could not get ListenInterval value + * from CFG. Log error. + */ + lim_log(mac_ctx, LOGP, + FL("could not retrieve ListenInterval")); + } else { + if (wlan_cfg_get_int(mac_ctx, WNI_CFG_LISTEN_INTERVAL, &val) != + eSIR_SUCCESS) + /* + * Could not get ListenInterval value + * from CFG. Log error. + */ + lim_log(mac_ctx, LOGP, + FL("could not retrieve ListenInterval")); + } + + mlm_reassoc_req->listenInterval = (uint16_t) val; + + /* Indicate whether spectrum management is enabled */ + session_entry->spectrumMgtEnabled = reassoc_req->spectrumMgtIndicator; + + /* Enable the spectrum management if this is a DFS channel */ + if (session_entry->country_info_present && + lim_isconnected_on_dfs_channel( + session_entry->currentOperChannel)) + session_entry->spectrumMgtEnabled = true; + + session_entry->limPrevSmeState = session_entry->limSmeState; + session_entry->limSmeState = eLIM_SME_WT_REASSOC_STATE; + + MTRACE(mac_trace(mac_ctx, TRACE_CODE_SME_STATE, + session_entry->peSessionId, + session_entry->limSmeState)); + + lim_post_mlm_message(mac_ctx, + LIM_MLM_REASSOC_REQ, (uint32_t *)mlm_reassoc_req); + return; +end: + if (reassoc_req) { + qdf_mem_free(reassoc_req); + if (session_entry) + session_entry->pLimReAssocReq = NULL; + } + + if (session_entry) { + /* + * error occurred after we determined the session so extract + * session and transaction info from there + */ + sme_session_id = session_entry->smeSessionId; + transaction_id = session_entry->transactionId; + } else + /* + * error occurred before or during the time we determined + * the session so extract the session and transaction info + * from the message + */ + lim_get_session_info(mac_ctx, (uint8_t *) msg_buf, + &sme_session_id, &transaction_id); + + /* + * Send Reassoc failure response to host + * (note session_entry may be NULL, but that's OK) + */ + lim_send_sme_join_reassoc_rsp(mac_ctx, eWNI_SME_REASSOC_RSP, + ret_code, eSIR_MAC_UNSPEC_FAILURE_STATUS, + session_entry, sme_session_id, + transaction_id); +} + +bool send_disassoc_frame = 1; +/** + * __lim_process_sme_disassoc_req() + * + ***FUNCTION: + * This function is called to process SME_DISASSOC_REQ message + * from HDD or upper layer application. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param pMac Pointer to Global MAC structure + * @param *pMsgBuf A pointer to the SME message buffer + * @return None + */ + +static void __lim_process_sme_disassoc_req(tpAniSirGlobal pMac, uint32_t *pMsgBuf) +{ + uint16_t disassocTrigger, reasonCode; + tLimMlmDisassocReq *pMlmDisassocReq; + tSirResultCodes retCode = eSIR_SME_SUCCESS; + tSirSmeDisassocReq smeDisassocReq; + tpPESession psessionEntry = NULL; + uint8_t sessionId; + uint8_t smesessionId; + uint16_t smetransactionId; + + if (pMsgBuf == NULL) { + lim_log(pMac, LOGE, FL("Buffer is Pointing to NULL")); + return; + } + + qdf_mem_copy(&smeDisassocReq, pMsgBuf, sizeof(tSirSmeDisassocReq)); + smesessionId = smeDisassocReq.sessionId; + smetransactionId = smeDisassocReq.transactionId; + if (!lim_is_sme_disassoc_req_valid(pMac, + &smeDisassocReq, + psessionEntry)) { + PELOGE(lim_log(pMac, LOGE, + FL("received invalid SME_DISASSOC_REQ message"));) + if (pMac->lim.gLimRspReqd) { + pMac->lim.gLimRspReqd = false; + + retCode = eSIR_SME_INVALID_PARAMETERS; + disassocTrigger = eLIM_HOST_DISASSOC; + goto sendDisassoc; + } + + return; + } + + psessionEntry = pe_find_session_by_bssid(pMac, + smeDisassocReq.bssid.bytes, + &sessionId); + if (psessionEntry == NULL) { + lim_log(pMac, LOGE, + FL("session does not exist for given bssId " + MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(smeDisassocReq.bssid.bytes)); + retCode = eSIR_SME_INVALID_PARAMETERS; + disassocTrigger = eLIM_HOST_DISASSOC; + goto sendDisassoc; + } + lim_log(pMac, LOG1, + FL("received DISASSOC_REQ message on sessionid %d Systemrole %d Reason: %u SmeState: %d from: " + MAC_ADDRESS_STR), smesessionId, + GET_LIM_SYSTEM_ROLE(psessionEntry), smeDisassocReq.reasonCode, + pMac->lim.gLimSmeState, + MAC_ADDR_ARRAY(smeDisassocReq.peer_macaddr.bytes)); + +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM /* FEATURE_WLAN_DIAG_SUPPORT */ + lim_diag_event_report(pMac, WLAN_PE_DIAG_DISASSOC_REQ_EVENT, psessionEntry, + 0, smeDisassocReq.reasonCode); +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + + /* Update SME session Id and SME transaction ID */ + + psessionEntry->smeSessionId = smesessionId; + psessionEntry->transactionId = smetransactionId; + lim_log(pMac, LOGW, FL("ho_fail: %d "), smeDisassocReq.process_ho_fail); + psessionEntry->process_ho_fail = smeDisassocReq.process_ho_fail; + + switch (GET_LIM_SYSTEM_ROLE(psessionEntry)) { + case eLIM_STA_ROLE: + switch (psessionEntry->limSmeState) { + case eLIM_SME_ASSOCIATED_STATE: + case eLIM_SME_LINK_EST_STATE: + lim_log(pMac, LOG1, + FL("Rcvd SME_DISASSOC_REQ in limSmeState: %d "), + psessionEntry->limSmeState); + psessionEntry->limPrevSmeState = + psessionEntry->limSmeState; + psessionEntry->limSmeState = eLIM_SME_WT_DISASSOC_STATE; + /* Delete all TDLS peers connected before leaving BSS */ + lim_delete_tdls_peers(pMac, psessionEntry); + MTRACE(mac_trace(pMac, TRACE_CODE_SME_STATE, + psessionEntry->peSessionId, + psessionEntry->limSmeState)); + break; + + case eLIM_SME_WT_DEAUTH_STATE: + /* PE shall still process the DISASSOC_REQ and proceed with + * link tear down even if it had already sent a DEAUTH_IND to + * to SME. pMac->lim.gLimPrevSmeState shall remain the same as + * its been set when PE entered WT_DEAUTH_STATE. + */ + psessionEntry->limSmeState = eLIM_SME_WT_DISASSOC_STATE; + MTRACE(mac_trace + (pMac, TRACE_CODE_SME_STATE, + psessionEntry->peSessionId, + psessionEntry->limSmeState)); + lim_log(pMac, LOG1, + FL("Rcvd SME_DISASSOC_REQ while in SME_WT_DEAUTH_STATE. ")); + break; + + case eLIM_SME_WT_DISASSOC_STATE: + /* PE Recieved a Disassoc frame. Normally it gets DISASSOC_CNF but it + * received DISASSOC_REQ. Which means host is also trying to disconnect. + * PE can continue processing DISASSOC_REQ and send the response instead + * of failing the request. SME will anyway ignore DEAUTH_IND that was sent + * for disassoc frame. + * + * It will send a disassoc, which is ok. However, we can use the global flag + * sendDisassoc to not send disassoc frame. + */ + lim_log(pMac, LOG1, + FL("Rcvd SME_DISASSOC_REQ while in SME_WT_DISASSOC_STATE. ")); + break; + + case eLIM_SME_JOIN_FAILURE_STATE: { + /* Already in Disconnected State, return success */ + lim_log(pMac, LOG1, + FL("Rcvd SME_DISASSOC_REQ while in eLIM_SME_JOIN_FAILURE_STATE. ")); + if (pMac->lim.gLimRspReqd) { + retCode = eSIR_SME_SUCCESS; + disassocTrigger = eLIM_HOST_DISASSOC; + goto sendDisassoc; + } + } + break; + default: + /** + * STA is not currently associated. + * Log error and send response to host + */ + lim_log(pMac, LOGE, + FL("received unexpected SME_DISASSOC_REQ in state %X"), + psessionEntry->limSmeState); + lim_print_sme_state(pMac, LOGE, + psessionEntry->limSmeState); + + if (pMac->lim.gLimRspReqd) { + if (psessionEntry->limSmeState != + eLIM_SME_WT_ASSOC_STATE) + pMac->lim.gLimRspReqd = false; + + retCode = eSIR_SME_UNEXPECTED_REQ_RESULT_CODE; + disassocTrigger = eLIM_HOST_DISASSOC; + goto sendDisassoc; + } + + return; + } + + break; + + case eLIM_AP_ROLE: + /* Fall through */ + break; + + case eLIM_STA_IN_IBSS_ROLE: + default: + /* eLIM_UNKNOWN_ROLE */ + lim_log(pMac, LOGE, + FL("received unexpected SME_DISASSOC_REQ for role %d"), + GET_LIM_SYSTEM_ROLE(psessionEntry)); + + retCode = eSIR_SME_UNEXPECTED_REQ_RESULT_CODE; + disassocTrigger = eLIM_HOST_DISASSOC; + goto sendDisassoc; + } /* end switch (pMac->lim.gLimSystemRole) */ + + disassocTrigger = eLIM_HOST_DISASSOC; + reasonCode = smeDisassocReq.reasonCode; + + if (smeDisassocReq.doNotSendOverTheAir) { + lim_log(pMac, LOG1, FL("do not send dissoc over the air")); + send_disassoc_frame = 0; + } + /* Trigger Disassociation frame to peer MAC entity */ + lim_log(pMac, LOG1, FL("Sending Disasscoc with disassoc Trigger" + " : %d, reasonCode : %d"), + disassocTrigger, reasonCode); + + pMlmDisassocReq = qdf_mem_malloc(sizeof(tLimMlmDisassocReq)); + if (NULL == pMlmDisassocReq) { + /* Log error */ + lim_log(pMac, LOGP, + FL("call to AllocateMemory failed for mlmDisassocReq")); + + return; + } + + qdf_copy_macaddr(&pMlmDisassocReq->peer_macaddr, + &smeDisassocReq.peer_macaddr); + + pMlmDisassocReq->reasonCode = reasonCode; + pMlmDisassocReq->disassocTrigger = disassocTrigger; + + /* Update PE session ID */ + pMlmDisassocReq->sessionId = sessionId; + + lim_post_mlm_message(pMac, + LIM_MLM_DISASSOC_REQ, (uint32_t *) pMlmDisassocReq); + return; + +sendDisassoc: + if (psessionEntry) + lim_send_sme_disassoc_ntf(pMac, + smeDisassocReq.peer_macaddr.bytes, + retCode, + disassocTrigger, + 1, smesessionId, smetransactionId, + psessionEntry); + else + lim_send_sme_disassoc_ntf(pMac, + smeDisassocReq.peer_macaddr.bytes, + retCode, disassocTrigger, 1, + smesessionId, smetransactionId, NULL); + +} /*** end __lim_process_sme_disassoc_req() ***/ + +/** ----------------------------------------------------------------- + \brief __lim_process_sme_disassoc_cnf() - Process SME_DISASSOC_CNF + + This function is called to process SME_DISASSOC_CNF message + from HDD or upper layer application. + + \param pMac - global mac structure + \param pStaDs - station dph hash node + \return none + \sa + ----------------------------------------------------------------- */ +static void __lim_process_sme_disassoc_cnf(tpAniSirGlobal pMac, uint32_t *pMsgBuf) +{ + tSirSmeDisassocCnf smeDisassocCnf; + uint16_t aid; + tpDphHashNode pStaDs; + tpPESession psessionEntry; + uint8_t sessionId; + + PELOG1(lim_log(pMac, LOG1, FL("received DISASSOC_CNF message"));) + + qdf_mem_copy(&smeDisassocCnf, pMsgBuf, + sizeof(struct sSirSmeDisassocCnf)); + + psessionEntry = pe_find_session_by_bssid(pMac, + smeDisassocCnf.bssid.bytes, + &sessionId); + if (psessionEntry == NULL) { + lim_log(pMac, LOGE, + FL("session does not exist for given bssId")); + return; + } + + if (!lim_is_sme_disassoc_cnf_valid(pMac, &smeDisassocCnf, psessionEntry)) { + lim_log(pMac, LOGE, + FL("received invalid SME_DISASSOC_CNF message")); + return; + } +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM /* FEATURE_WLAN_DIAG_SUPPORT */ + if (smeDisassocCnf.messageType == eWNI_SME_DISASSOC_CNF) + lim_diag_event_report(pMac, WLAN_PE_DIAG_DISASSOC_CNF_EVENT, + psessionEntry, + (uint16_t) smeDisassocCnf.statusCode, 0); + else if (smeDisassocCnf.messageType == eWNI_SME_DEAUTH_CNF) + lim_diag_event_report(pMac, WLAN_PE_DIAG_DEAUTH_CNF_EVENT, + psessionEntry, + (uint16_t) smeDisassocCnf.statusCode, 0); +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + + switch (GET_LIM_SYSTEM_ROLE(psessionEntry)) { + case eLIM_STA_ROLE: + if ((psessionEntry->limSmeState != eLIM_SME_IDLE_STATE) && + (psessionEntry->limSmeState != eLIM_SME_WT_DISASSOC_STATE) + && (psessionEntry->limSmeState != + eLIM_SME_WT_DEAUTH_STATE)) { + lim_log(pMac, LOGE, + FL + ("received unexp SME_DISASSOC_CNF in state %X"), + psessionEntry->limSmeState); + lim_print_sme_state(pMac, LOGE, + psessionEntry->limSmeState); + return; + } + break; + + case eLIM_AP_ROLE: + /* Fall through */ + break; + + case eLIM_STA_IN_IBSS_ROLE: + default: /* eLIM_UNKNOWN_ROLE */ + lim_log(pMac, LOGE, + FL("received unexpected SME_DISASSOC_CNF role %d"), + GET_LIM_SYSTEM_ROLE(psessionEntry)); + + return; + } + + if ((psessionEntry->limSmeState == eLIM_SME_WT_DISASSOC_STATE) || + (psessionEntry->limSmeState == eLIM_SME_WT_DEAUTH_STATE) || + LIM_IS_AP_ROLE(psessionEntry)) { + pStaDs = dph_lookup_hash_entry(pMac, + smeDisassocCnf.peer_macaddr.bytes, &aid, + &psessionEntry->dph.dphHashTable); + if (pStaDs == NULL) { + lim_log(pMac, LOGE, + FL("DISASSOC_CNF for a STA with no context, addr= " + MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(smeDisassocCnf.peer_macaddr.bytes)); + return; + } + + if ((pStaDs->mlmStaContext.mlmState == + eLIM_MLM_WT_DEL_STA_RSP_STATE) || + (pStaDs->mlmStaContext.mlmState == + eLIM_MLM_WT_DEL_STA_RSP_STATE)) { + lim_log(pMac, LOGE, + FL("No need of cleanup for addr:" MAC_ADDRESS_STR "as MLM state is %d"), + MAC_ADDR_ARRAY(smeDisassocCnf.peer_macaddr.bytes), + pStaDs->mlmStaContext.mlmState); + return; + } + + /* Delete FT session if there exists one */ + lim_ft_cleanup_pre_auth_info(pMac, psessionEntry); + lim_cleanup_rx_path(pMac, pStaDs, psessionEntry); + + lim_clean_up_disassoc_deauth_req(pMac, + (char *)&smeDisassocCnf.peer_macaddr, 0); + } + + return; +} + +/** + * __lim_process_sme_deauth_req() - process sme deauth req + * @mac_ctx: Pointer to Global MAC structure + * @msg_buf: pointer to the SME message buffer + * + * This function is called to process SME_DEAUTH_REQ message + * from HDD or upper layer application. + * + * Return: None + */ + +static void __lim_process_sme_deauth_req(tpAniSirGlobal mac_ctx, + uint32_t *msg_buf) +{ + uint16_t deauth_trigger, reason_code; + tLimMlmDeauthReq *mlm_deauth_req; + tSirSmeDeauthReq sme_deauth_req; + tSirResultCodes ret_code = eSIR_SME_SUCCESS; + tpPESession session_entry; + uint8_t session_id; /* PE sessionId */ + uint8_t sme_session_id; + uint16_t sme_transaction_id; + + lim_log(mac_ctx, LOG1, FL("received DEAUTH_REQ message")); + + qdf_mem_copy(&sme_deauth_req, msg_buf, sizeof(tSirSmeDeauthReq)); + sme_session_id = sme_deauth_req.sessionId; + sme_transaction_id = sme_deauth_req.transactionId; + + /* + * We need to get a session first but we don't even know + * if the message is correct. + */ + session_entry = pe_find_session_by_bssid(mac_ctx, + sme_deauth_req.bssid.bytes, + &session_id); + if (session_entry == NULL) { + lim_log(mac_ctx, LOGE, + FL("session does not exist for given bssId")); + ret_code = eSIR_SME_INVALID_PARAMETERS; + deauth_trigger = eLIM_HOST_DEAUTH; + goto send_deauth; + } + + if (!lim_is_sme_deauth_req_valid(mac_ctx, &sme_deauth_req, + session_entry)) { + lim_log(mac_ctx, LOGE, + FL("received invalid SME_DEAUTH_REQ message")); + mac_ctx->lim.gLimRspReqd = false; + + ret_code = eSIR_SME_INVALID_PARAMETERS; + deauth_trigger = eLIM_HOST_DEAUTH; + goto send_deauth; + } + lim_log(mac_ctx, LOG1, + FL("received DEAUTH_REQ sessionid %d Systemrole %d reasoncode %u limSmestate %d from " + MAC_ADDRESS_STR), sme_session_id, + GET_LIM_SYSTEM_ROLE(session_entry), sme_deauth_req.reasonCode, + session_entry->limSmeState, + MAC_ADDR_ARRAY(sme_deauth_req.peer_macaddr.bytes)); +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM /* FEATURE_WLAN_DIAG_SUPPORT */ + lim_diag_event_report(mac_ctx, WLAN_PE_DIAG_DEAUTH_REQ_EVENT, + session_entry, 0, sme_deauth_req.reasonCode); +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + + /* Update SME session ID and Transaction ID */ + session_entry->smeSessionId = sme_session_id; + session_entry->transactionId = sme_transaction_id; + + switch (GET_LIM_SYSTEM_ROLE(session_entry)) { + case eLIM_STA_ROLE: + switch (session_entry->limSmeState) { + case eLIM_SME_ASSOCIATED_STATE: + case eLIM_SME_LINK_EST_STATE: + /* Delete all TDLS peers connected before leaving BSS */ + lim_delete_tdls_peers(mac_ctx, session_entry); + case eLIM_SME_WT_ASSOC_STATE: + case eLIM_SME_JOIN_FAILURE_STATE: + case eLIM_SME_IDLE_STATE: + session_entry->limPrevSmeState = + session_entry->limSmeState; + session_entry->limSmeState = eLIM_SME_WT_DEAUTH_STATE; + MTRACE(mac_trace(mac_ctx, TRACE_CODE_SME_STATE, + session_entry->peSessionId, + session_entry->limSmeState)); + /* Send Deauthentication request to MLM below */ + break; + case eLIM_SME_WT_DEAUTH_STATE: + case eLIM_SME_WT_DISASSOC_STATE: + /* + * PE Recieved a Deauth/Disassoc frame. Normally it get + * DEAUTH_CNF/DISASSOC_CNF but it received DEAUTH_REQ. + * Which means host is also trying to disconnect. + * PE can continue processing DEAUTH_REQ and send + * the response instead of failing the request. + * SME will anyway ignore DEAUTH_IND/DISASSOC_IND that + * was sent for deauth/disassoc frame. + */ + session_entry->limSmeState = eLIM_SME_WT_DEAUTH_STATE; + lim_log(mac_ctx, LOG1, FL( + "Rcvd SME_DEAUTH_REQ while in SME_WT_DEAUTH_STATE")); + break; + default: + /* + * STA is not in a state to deauthenticate with + * peer. Log error and send response to host. + */ + lim_log(mac_ctx, LOGE, FL( + "received unexp SME_DEAUTH_REQ in state %X"), + session_entry->limSmeState); + lim_print_sme_state(mac_ctx, LOGE, + session_entry->limSmeState); + + if (mac_ctx->lim.gLimRspReqd) { + mac_ctx->lim.gLimRspReqd = false; + + ret_code = eSIR_SME_STA_NOT_AUTHENTICATED; + deauth_trigger = eLIM_HOST_DEAUTH; + + /* + * here we received deauth request from AP so sme state + * is eLIM_SME_WT_DEAUTH_STATE.if we have ISSUED + * delSta then mlm state should be + * eLIM_MLM_WT_DEL_STA_RSP_STATE and ifwe got delBSS + * rsp then mlm state should be eLIM_MLM_IDLE_STATE + * so the below condition captures the state where + * delSta not done and firmware still in + * connected state. + */ + if (session_entry->limSmeState == + eLIM_SME_WT_DEAUTH_STATE && + session_entry->limMlmState != + eLIM_MLM_IDLE_STATE && + session_entry->limMlmState != + eLIM_MLM_WT_DEL_STA_RSP_STATE) + ret_code = eSIR_SME_DEAUTH_STATUS; + goto send_deauth; + } + return; + } + break; + + case eLIM_STA_IN_IBSS_ROLE: + lim_log(mac_ctx, LOGE, FL("Deauth not allowed in IBSS")); + if (mac_ctx->lim.gLimRspReqd) { + mac_ctx->lim.gLimRspReqd = false; + ret_code = eSIR_SME_INVALID_PARAMETERS; + deauth_trigger = eLIM_HOST_DEAUTH; + goto send_deauth; + } + return; + case eLIM_AP_ROLE: + break; + default: + lim_log(mac_ctx, LOGE, + FL("received unexpected SME_DEAUTH_REQ for role %X"), + GET_LIM_SYSTEM_ROLE(session_entry)); + if (mac_ctx->lim.gLimRspReqd) { + mac_ctx->lim.gLimRspReqd = false; + ret_code = eSIR_SME_INVALID_PARAMETERS; + deauth_trigger = eLIM_HOST_DEAUTH; + goto send_deauth; + } + return; + } /* end switch (mac_ctx->lim.gLimSystemRole) */ + + if (sme_deauth_req.reasonCode == eLIM_LINK_MONITORING_DEAUTH) { + /* Deauthentication is triggered by Link Monitoring */ + lim_log(mac_ctx, LOG1, FL("** Lost link with AP **")); + deauth_trigger = eLIM_LINK_MONITORING_DEAUTH; + reason_code = eSIR_MAC_UNSPEC_FAILURE_REASON; + } else { + deauth_trigger = eLIM_HOST_DEAUTH; + reason_code = sme_deauth_req.reasonCode; + } + + /* Trigger Deauthentication frame to peer MAC entity */ + mlm_deauth_req = qdf_mem_malloc(sizeof(tLimMlmDeauthReq)); + if (NULL == mlm_deauth_req) { + lim_log(mac_ctx, LOGP, + FL("call to AllocateMemory failed for mlmDeauthReq")); + if (mac_ctx->lim.gLimRspReqd) { + mac_ctx->lim.gLimRspReqd = false; + ret_code = eSIR_SME_RESOURCES_UNAVAILABLE; + deauth_trigger = eLIM_HOST_DEAUTH; + goto send_deauth; + } + return; + } + + qdf_copy_macaddr(&mlm_deauth_req->peer_macaddr, + &sme_deauth_req.peer_macaddr); + + mlm_deauth_req->reasonCode = reason_code; + mlm_deauth_req->deauthTrigger = deauth_trigger; + + /* Update PE session Id */ + mlm_deauth_req->sessionId = session_id; + + lim_post_mlm_message(mac_ctx, LIM_MLM_DEAUTH_REQ, + (uint32_t *)mlm_deauth_req); + return; + +send_deauth: + lim_send_sme_deauth_ntf(mac_ctx, sme_deauth_req.peer_macaddr.bytes, + ret_code, deauth_trigger, 1, + sme_session_id, sme_transaction_id); +} + +/** + * __lim_process_sme_set_context_req() + * + * @mac_ctx: Pointer to Global MAC structure + * @msg_buf: pointer to the SME message buffer + * + * This function is called to process SME_SETCONTEXT_REQ message + * from HDD or upper layer application. + * + * Return: None + */ + +static void +__lim_process_sme_set_context_req(tpAniSirGlobal mac_ctx, uint32_t *msg_buf) +{ + tpSirSmeSetContextReq set_context_req; + tLimMlmSetKeysReq *mlm_set_key_req; + tpPESession session_entry; + uint8_t session_id; /* PE sessionID */ + uint8_t sme_session_id; + uint16_t sme_transaction_id; + + lim_log(mac_ctx, LOG1, FL("received SETCONTEXT_REQ message")); + + if (msg_buf == NULL) { + lim_log(mac_ctx, LOGE, FL("Buffer is Pointing to NULL")); + return; + } + + set_context_req = qdf_mem_malloc(sizeof(struct sSirSmeSetContextReq)); + if (NULL == set_context_req) { + lim_log(mac_ctx, LOGP, FL( + "call to AllocateMemory failed for set_context_req")); + return; + } + qdf_mem_copy(set_context_req, msg_buf, + sizeof(struct sSirSmeSetContextReq)); + sme_session_id = set_context_req->sessionId; + sme_transaction_id = set_context_req->transactionId; + + if ((!lim_is_sme_set_context_req_valid(mac_ctx, set_context_req))) { + lim_log(mac_ctx, LOGW, + FL("received invalid SME_SETCONTEXT_REQ message")); + goto end; + } + + if (set_context_req->keyMaterial.numKeys > + SIR_MAC_MAX_NUM_OF_DEFAULT_KEYS) { + lim_log(mac_ctx, LOGE, FL( + "numKeys:%d is more than SIR_MAC_MAX_NUM_OF_DEFAULT_KEYS"), + set_context_req->keyMaterial.numKeys); + lim_send_sme_set_context_rsp(mac_ctx, + set_context_req->peer_macaddr, 1, + eSIR_SME_INVALID_PARAMETERS, NULL, + sme_session_id, sme_transaction_id); + goto end; + } + + session_entry = pe_find_session_by_bssid(mac_ctx, + set_context_req->bssid.bytes, &session_id); + if (session_entry == NULL) { + lim_log(mac_ctx, LOGW, + FL("Session does not exist for given BSSID")); + lim_send_sme_set_context_rsp(mac_ctx, + set_context_req->peer_macaddr, 1, + eSIR_SME_INVALID_PARAMETERS, NULL, + sme_session_id, sme_transaction_id); + goto end; + } +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM /* FEATURE_WLAN_DIAG_SUPPORT */ + lim_diag_event_report(mac_ctx, WLAN_PE_DIAG_SETCONTEXT_REQ_EVENT, + session_entry, 0, 0); +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + + if ((LIM_IS_STA_ROLE(session_entry) && + (session_entry->limSmeState == eLIM_SME_LINK_EST_STATE)) || + ((LIM_IS_IBSS_ROLE(session_entry) || + LIM_IS_AP_ROLE(session_entry)) && + (session_entry->limSmeState == eLIM_SME_NORMAL_STATE))) { + /* Trigger MLM_SETKEYS_REQ */ + mlm_set_key_req = qdf_mem_malloc(sizeof(tLimMlmSetKeysReq)); + if (NULL == mlm_set_key_req) { + lim_log(mac_ctx, LOGP, FL( + "mem alloc failed for mlmSetKeysReq")); + goto end; + } + mlm_set_key_req->edType = set_context_req->keyMaterial.edType; + mlm_set_key_req->numKeys = + set_context_req->keyMaterial.numKeys; + if (mlm_set_key_req->numKeys > + SIR_MAC_MAX_NUM_OF_DEFAULT_KEYS) { + lim_log(mac_ctx, LOGP, FL( + "no.of keys exceeded max num of default keys limit")); + goto end; + } + qdf_copy_macaddr(&mlm_set_key_req->peer_macaddr, + &set_context_req->peer_macaddr); + + qdf_mem_copy((uint8_t *) &mlm_set_key_req->key, + (uint8_t *) &set_context_req->keyMaterial.key, + sizeof(tSirKeys) * + (mlm_set_key_req->numKeys ? mlm_set_key_req-> + numKeys : 1)); + + mlm_set_key_req->sessionId = session_id; + mlm_set_key_req->smesessionId = sme_session_id; + lim_log(mac_ctx, LOG1, FL( + "received SETCONTEXT_REQ message sessionId=%d"), + mlm_set_key_req->sessionId); + + if (((set_context_req->keyMaterial.edType == eSIR_ED_WEP40) || + (set_context_req->keyMaterial.edType == eSIR_ED_WEP104)) && + LIM_IS_AP_ROLE(session_entry)) { + if (set_context_req->keyMaterial.key[0].keyLength) { + uint8_t key_id; + key_id = + set_context_req->keyMaterial.key[0].keyId; + qdf_mem_copy((uint8_t *) + &session_entry->WEPKeyMaterial[key_id], + (uint8_t *) &set_context_req->keyMaterial, + sizeof(tSirKeyMaterial)); + } else { + uint32_t i; + for (i = 0; i < SIR_MAC_MAX_NUM_OF_DEFAULT_KEYS; + i++) { + qdf_mem_copy((uint8_t *) + &mlm_set_key_req->key[i], + (uint8_t *)session_entry->WEPKeyMaterial[i].key, + sizeof(tSirKeys)); + } + } + } + lim_post_mlm_message(mac_ctx, LIM_MLM_SETKEYS_REQ, + (uint32_t *) mlm_set_key_req); + } else { + lim_log(mac_ctx, LOGE, FL( + "rcvd unexpected SME_SETCONTEXT_REQ for role %d, state=%X"), + GET_LIM_SYSTEM_ROLE(session_entry), + session_entry->limSmeState); + lim_print_sme_state(mac_ctx, LOGE, session_entry->limSmeState); + + lim_send_sme_set_context_rsp(mac_ctx, + set_context_req->peer_macaddr, 1, + eSIR_SME_UNEXPECTED_REQ_RESULT_CODE, + session_entry, sme_session_id, + sme_transaction_id); + } +end: + qdf_mem_free(set_context_req); + return; +} + +/** + * lim_process_sme_get_assoc_sta_info() - process sme assoc sta req + * + * @mac_ctx: Pointer to Global MAC structure + * @msg_buf: pointer to the SME message buffer + * + * This function is called to process SME_GET_ASSOC_STAS_REQ message + * from HDD or upper layer application. + * + * Return: None + */ + +static void lim_process_sme_get_assoc_sta_info(tpAniSirGlobal mac_ctx, + uint32_t *msg_buf) +{ + tSirSmeGetAssocSTAsReq get_assoc_stas_req; + tpDphHashNode sta_ds = NULL; + tpPESession session_entry = NULL; + tSap_Event sap_event; + tpWLAN_SAPEventCB sap_event_cb = NULL; + tpSap_AssocMacAddr assoc_sta_tmp = NULL; + uint8_t session_id = CSR_SESSION_ID_INVALID; + uint8_t assoc_id = 0; + uint8_t sta_cnt = 0; + + if (msg_buf == NULL) { + lim_log(mac_ctx, LOGE, FL("Buffer is Pointing to NULL")); + return; + } + + qdf_mem_copy(&get_assoc_stas_req, msg_buf, + sizeof(struct sSirSmeGetAssocSTAsReq)); + /* + * Get Associated stations from PE. + * Find PE session Entry + */ + session_entry = pe_find_session_by_bssid(mac_ctx, + get_assoc_stas_req.bssid.bytes, + &session_id); + if (session_entry == NULL) { + lim_log(mac_ctx, LOGE, + FL("session does not exist for given bssId")); + goto lim_assoc_sta_end; + } + + if (!LIM_IS_AP_ROLE(session_entry)) { + lim_log(mac_ctx, LOGE, FL( + "Received unexpected message in state %X, in role %X"), + session_entry->limSmeState, + GET_LIM_SYSTEM_ROLE(session_entry)); + goto lim_assoc_sta_end; + } + /* Retrieve values obtained in the request message */ + sap_event_cb = (tpWLAN_SAPEventCB)get_assoc_stas_req.pSapEventCallback; + assoc_sta_tmp = (tpSap_AssocMacAddr)get_assoc_stas_req.pAssocStasArray; + + if (NULL == assoc_sta_tmp) + goto lim_assoc_sta_end; + for (assoc_id = 0; assoc_id < session_entry->dph.dphHashTable.size; + assoc_id++) { + sta_ds = dph_get_hash_entry(mac_ctx, assoc_id, + &session_entry->dph.dphHashTable); + if (NULL == sta_ds) + continue; + if (sta_ds->valid) { + qdf_mem_copy((uint8_t *) &assoc_sta_tmp->staMac, + (uint8_t *) &sta_ds->staAddr, + QDF_MAC_ADDR_SIZE); + assoc_sta_tmp->assocId = (uint8_t) sta_ds->assocId; + assoc_sta_tmp->staId = (uint8_t) sta_ds->staIndex; + + qdf_mem_copy((uint8_t *)&assoc_sta_tmp->supportedRates, + (uint8_t *)&sta_ds->supportedRates, + sizeof(tSirSupportedRates)); + assoc_sta_tmp->ShortGI40Mhz = sta_ds->htShortGI40Mhz; + assoc_sta_tmp->ShortGI20Mhz = sta_ds->htShortGI20Mhz; + assoc_sta_tmp->Support40Mhz = + sta_ds->htDsssCckRate40MHzSupport; + + lim_log(mac_ctx, LOG1, FL("dph Station Number = %d"), + sta_cnt + 1); + lim_log(mac_ctx, LOG1, FL("MAC = " MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(sta_ds->staAddr)); + lim_log(mac_ctx, LOG1, FL("Association Id = %d"), + sta_ds->assocId); + lim_log(mac_ctx, LOG1, FL("Station Index = %d"), + sta_ds->staIndex); + assoc_sta_tmp++; + sta_cnt++; + } + } +lim_assoc_sta_end: + /* + * Call hdd callback with sap event to send the list of + * associated stations from PE + */ + if (sap_event_cb != NULL) { + sap_event.sapHddEventCode = eSAP_ASSOC_STA_CALLBACK_EVENT; + sap_event.sapevt.sapAssocStaListEvent.module = + QDF_MODULE_ID_PE; + sap_event.sapevt.sapAssocStaListEvent.noOfAssocSta = sta_cnt; + sap_event.sapevt.sapAssocStaListEvent.pAssocStas = + (tpSap_AssocMacAddr)get_assoc_stas_req.pAssocStasArray; + sap_event_cb(&sap_event, get_assoc_stas_req.pUsrContext); + } +} + +/** + * lim_process_sme_get_wpspbc_sessions - process sme get wpspbc req + * + * @mac_ctx: Pointer to Global MAC structure + * @msg_buf: pointer to WPS PBC overlap query message + * + * This function parses get WPS PBC overlap information + * message and call callback to pass WPS PBC overlap + * information back to hdd. + * + * Return: None + */ +static void lim_process_sme_get_wpspbc_sessions(tpAniSirGlobal mac_ctx, + uint32_t *msg_buf) +{ + tSirSmeGetWPSPBCSessionsReq get_wps_pbc_sessions_req; + tpPESession session_entry = NULL; + tSap_Event sap_event; + tpWLAN_SAPEventCB sap_event_cb = NULL; + uint8_t session_id = CSR_SESSION_ID_INVALID; + tSap_GetWPSPBCSessionEvent *sap_get_wpspbc_event; + + if (msg_buf == NULL) { + lim_log(mac_ctx, LOGE, FL("Buffer is Pointing to NULL")); + return; + } + + sap_get_wpspbc_event = &sap_event.sapevt.sapGetWPSPBCSessionEvent; + sap_get_wpspbc_event->status = QDF_STATUS_E_FAULT; + + qdf_mem_copy(&get_wps_pbc_sessions_req, msg_buf, + sizeof(struct sSirSmeGetWPSPBCSessionsReq)); + /* + * Get Associated stations from PE + * Find PE session Entry + */ + session_entry = pe_find_session_by_bssid(mac_ctx, + get_wps_pbc_sessions_req.bssid.bytes, &session_id); + if (session_entry == NULL) { + lim_log(mac_ctx, LOGE, + FL("session does not exist for given bssId")); + goto lim_get_wpspbc_sessions_end; + } + + if (!LIM_IS_AP_ROLE(session_entry)) { + lim_log(mac_ctx, LOGE, + FL("Received unexpected message in role %X"), + GET_LIM_SYSTEM_ROLE(session_entry)); + goto lim_get_wpspbc_sessions_end; + } + /* + * Call hdd callback with sap event to send the + * WPS PBC overlap information + */ + sap_event.sapHddEventCode = eSAP_GET_WPSPBC_SESSION_EVENT; + sap_get_wpspbc_event->module = QDF_MODULE_ID_PE; + + if (qdf_is_macaddr_zero(&get_wps_pbc_sessions_req.remove_mac)) { + lim_get_wpspbc_sessions(mac_ctx, + sap_get_wpspbc_event->addr, + sap_get_wpspbc_event->UUID_E, + &sap_get_wpspbc_event->wpsPBCOverlap, + session_entry); + } else { + lim_remove_pbc_sessions(mac_ctx, + get_wps_pbc_sessions_req.remove_mac, + session_entry); + /* don't have to inform the HDD/Host */ + return; + } + + lim_log(mac_ctx, LOGE, FL("wpsPBCOverlap %d"), + sap_get_wpspbc_event->wpsPBCOverlap); + lim_print_mac_addr(mac_ctx, + sap_get_wpspbc_event->addr.bytes, LOG4); + + sap_get_wpspbc_event->status = QDF_STATUS_SUCCESS; + +lim_get_wpspbc_sessions_end: + sap_event_cb = + (tpWLAN_SAPEventCB)get_wps_pbc_sessions_req.pSapEventCallback; + if (NULL != sap_event_cb) + sap_event_cb(&sap_event, get_wps_pbc_sessions_req.pUsrContext); +} + +/** + * __lim_counter_measures() + * + * FUNCTION: + * This function is called to "implement" MIC counter measure + * and is *temporary* only + * + * LOGIC: on AP, disassoc all STA associated thru TKIP, + * we don't do the proper STA disassoc sequence since the + * BSS will be stoped anyway + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param pMac Pointer to Global MAC structure + * @return None + */ + +static void __lim_counter_measures(tpAniSirGlobal pMac, tpPESession psessionEntry) +{ + tSirMacAddr mac = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; + if (LIM_IS_AP_ROLE(psessionEntry)) + lim_send_disassoc_mgmt_frame(pMac, eSIR_MAC_MIC_FAILURE_REASON, + mac, psessionEntry, false); +}; + +static void lim_process_tkip_counter_measures(tpAniSirGlobal pMac, + uint32_t *pMsgBuf) +{ + tSirSmeTkipCntrMeasReq tkipCntrMeasReq; + tpPESession psessionEntry; + uint8_t sessionId; /* PE sessionId */ + + qdf_mem_copy(&tkipCntrMeasReq, pMsgBuf, + sizeof(struct sSirSmeTkipCntrMeasReq)); + + psessionEntry = pe_find_session_by_bssid(pMac, + tkipCntrMeasReq.bssId.bytes, &sessionId); + if (NULL == psessionEntry) { + lim_log(pMac, LOGE, + FL("session does not exist for given BSSID ")); + return; + } + + if (tkipCntrMeasReq.bEnable) + __lim_counter_measures(pMac, psessionEntry); + + psessionEntry->bTkipCntrMeasActive = tkipCntrMeasReq.bEnable; +} + +static void +__lim_handle_sme_stop_bss_request(tpAniSirGlobal pMac, uint32_t *pMsgBuf) +{ + tSirSmeStopBssReq stopBssReq; + tSirRetStatus status; + tLimSmeStates prevState; + tpPESession psessionEntry; + uint8_t smesessionId; + uint8_t sessionId; + uint16_t smetransactionId; + uint8_t i = 0; + tpDphHashNode pStaDs = NULL; + + qdf_mem_copy(&stopBssReq, pMsgBuf, sizeof(tSirSmeStopBssReq)); + smesessionId = stopBssReq.sessionId; + smetransactionId = stopBssReq.transactionId; + + if (!lim_is_sme_stop_bss_req_valid(pMsgBuf)) { + PELOGW(lim_log(pMac, LOGW, + FL("received invalid SME_STOP_BSS_REQ message"));) + /* Send Stop BSS response to host */ + lim_send_sme_rsp(pMac, eWNI_SME_STOP_BSS_RSP, + eSIR_SME_INVALID_PARAMETERS, smesessionId, + smetransactionId); + return; + } + + psessionEntry = pe_find_session_by_bssid(pMac, + stopBssReq.bssid.bytes, + &sessionId); + if (psessionEntry == NULL) { + lim_log(pMac, LOGW, + FL("session does not exist for given BSSID ")); + lim_send_sme_rsp(pMac, eWNI_SME_STOP_BSS_RSP, + eSIR_SME_INVALID_PARAMETERS, smesessionId, + smetransactionId); + return; + } +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM /* FEATURE_WLAN_DIAG_SUPPORT */ + lim_diag_event_report(pMac, WLAN_PE_DIAG_STOP_BSS_REQ_EVENT, psessionEntry, + 0, 0); +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + + if (psessionEntry->limSmeState != eLIM_SME_NORMAL_STATE || /* Added For BT -AMP Support */ + LIM_IS_STA_ROLE(psessionEntry)) { + /** + * Should not have received STOP_BSS_REQ in states + * other than 'normal' state or on STA in Infrastructure + * mode. Log error and return response to host. + */ + lim_log(pMac, LOGE, + FL + ("received unexpected SME_STOP_BSS_REQ in state %X, for role %d"), + psessionEntry->limSmeState, + GET_LIM_SYSTEM_ROLE(psessionEntry)); + lim_print_sme_state(pMac, LOGE, psessionEntry->limSmeState); + /* / Send Stop BSS response to host */ + lim_send_sme_rsp(pMac, eWNI_SME_STOP_BSS_RSP, + eSIR_SME_UNEXPECTED_REQ_RESULT_CODE, smesessionId, + smetransactionId); + return; + } + + if (LIM_IS_AP_ROLE(psessionEntry)) + lim_wpspbc_close(pMac, psessionEntry); + + lim_log(pMac, LOGW, + FL("RECEIVED STOP_BSS_REQ with reason code=%d"), + stopBssReq.reasonCode); + + prevState = psessionEntry->limSmeState; + + psessionEntry->limSmeState = eLIM_SME_IDLE_STATE; + MTRACE(mac_trace + (pMac, TRACE_CODE_SME_STATE, psessionEntry->peSessionId, + psessionEntry->limSmeState)); + + /* Update SME session Id and Transaction Id */ + psessionEntry->smeSessionId = smesessionId; + psessionEntry->transactionId = smetransactionId; + + /* STA_IN_IBSS and NDI should NOT send Disassoc frame */ + if (!LIM_IS_IBSS_ROLE(psessionEntry) && + !LIM_IS_NDI_ROLE(psessionEntry)) { + tSirMacAddr bcAddr = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; + if (stopBssReq.reasonCode == eSIR_SME_MIC_COUNTER_MEASURES) + /* Send disassoc all stations associated thru TKIP */ + __lim_counter_measures(pMac, psessionEntry); + else + lim_send_disassoc_mgmt_frame(pMac, + eSIR_MAC_DEAUTH_LEAVING_BSS_REASON, + bcAddr, psessionEntry, false); + } + + if (!LIM_IS_NDI_ROLE(psessionEntry)) { + /* Free the buffer allocated in START_BSS_REQ */ + qdf_mem_free(psessionEntry->addIeParams.probeRespData_buff); + psessionEntry->addIeParams.probeRespDataLen = 0; + psessionEntry->addIeParams.probeRespData_buff = NULL; + + qdf_mem_free(psessionEntry->addIeParams.assocRespData_buff); + psessionEntry->addIeParams.assocRespDataLen = 0; + psessionEntry->addIeParams.assocRespData_buff = NULL; + + qdf_mem_free(psessionEntry->addIeParams.probeRespBCNData_buff); + psessionEntry->addIeParams.probeRespBCNDataLen = 0; + psessionEntry->addIeParams.probeRespBCNData_buff = NULL; + + /* + * lim_del_bss is also called as part of coalescing, + * when we send DEL BSS followed by Add Bss msg. + */ + pMac->lim.gLimIbssCoalescingHappened = false; + } + for (i = 1; i < pMac->lim.gLimAssocStaLimit; i++) { + pStaDs = + dph_get_hash_entry(pMac, i, &psessionEntry->dph.dphHashTable); + if (NULL == pStaDs) + continue; + status = lim_del_sta(pMac, pStaDs, false, psessionEntry); + if (eSIR_SUCCESS == status) { + lim_delete_dph_hash_entry(pMac, pStaDs->staAddr, + pStaDs->assocId, psessionEntry); + lim_release_peer_idx(pMac, pStaDs->assocId, psessionEntry); + } else { + lim_log(pMac, LOGE, + FL("lim_del_sta failed with Status : %d"), status); + QDF_ASSERT(0); + } + } + /* send a delBss to HAL and wait for a response */ + status = lim_del_bss(pMac, NULL, psessionEntry->bssIdx, psessionEntry); + + if (status != eSIR_SUCCESS) { + PELOGE(lim_log + (pMac, LOGE, FL("delBss failed for bss %d"), + psessionEntry->bssIdx); + ) + psessionEntry->limSmeState = prevState; + + MTRACE(mac_trace + (pMac, TRACE_CODE_SME_STATE, psessionEntry->peSessionId, + psessionEntry->limSmeState)); + + lim_send_sme_rsp(pMac, eWNI_SME_STOP_BSS_RSP, + eSIR_SME_STOP_BSS_FAILURE, smesessionId, + smetransactionId); + } +} + +/** + * __lim_process_sme_stop_bss_req() - Process STOP_BSS from SME + * @pMac: Global MAC context + * @pMsg: Message from SME + * + * Wrapper for the function __lim_handle_sme_stop_bss_request + * This message will be defered until softmac come out of + * scan mode. Message should be handled even if we have + * detected radar in the current operating channel. + * + * Return: true - If we consumed the buffer + * false - If have defered the message. + */ + +static bool __lim_process_sme_stop_bss_req(tpAniSirGlobal pMac, tpSirMsgQ pMsg) +{ + if (__lim_is_defered_msg_for_learn(pMac, pMsg)) { + /** + * If message defered, buffer is not consumed yet. + * So return false + */ + return false; + } + __lim_handle_sme_stop_bss_request(pMac, (uint32_t *) pMsg->bodyptr); + return true; +} /*** end __lim_process_sme_stop_bss_req() ***/ + +void lim_process_sme_del_bss_rsp(tpAniSirGlobal pMac, + uint32_t body, tpPESession psessionEntry) +{ + + (void)body; + SET_LIM_PROCESS_DEFD_MESGS(pMac, true); + lim_ibss_delete(pMac, psessionEntry); + dph_hash_table_class_init(pMac, &psessionEntry->dph.dphHashTable); + lim_delete_pre_auth_list(pMac); + lim_send_sme_rsp(pMac, eWNI_SME_STOP_BSS_RSP, eSIR_SME_SUCCESS, + psessionEntry->smeSessionId, + psessionEntry->transactionId); + return; +} + +/** + * __lim_process_sme_assoc_cnf_new() - process sme assoc/reassoc cnf + * + * @mac_ctx: pointer to mac context + * @msg_type: message type + * @msg_buf: pointer to the SME message buffer + * + * This function handles SME_ASSOC_CNF/SME_REASSOC_CNF + * in BTAMP AP. + * + * Return: None + */ + +void __lim_process_sme_assoc_cnf_new(tpAniSirGlobal mac_ctx, uint32_t msg_type, + uint32_t *msg_buf) +{ + tSirSmeAssocCnf assoc_cnf; + tpDphHashNode sta_ds = NULL; + tpPESession session_entry = NULL; + uint8_t session_id; + tpSirAssocReq assoc_req; + + if (msg_buf == NULL) { + lim_log(mac_ctx, LOGE, FL("msg_buf is NULL ")); + goto end; + } + + qdf_mem_copy(&assoc_cnf, msg_buf, sizeof(struct sSirSmeAssocCnf)); + if (!__lim_is_sme_assoc_cnf_valid(&assoc_cnf)) { + lim_log(mac_ctx, LOGE, + FL("Received invalid SME_RE(ASSOC)_CNF message ")); + goto end; + } + + session_entry = pe_find_session_by_bssid(mac_ctx, assoc_cnf.bssid.bytes, + &session_id); + if (session_entry == NULL) { + lim_log(mac_ctx, LOGE, + FL("session does not exist for given bssId")); + goto end; + } + + if ((!LIM_IS_AP_ROLE(session_entry)) || + ((session_entry->limSmeState != eLIM_SME_NORMAL_STATE) && + (session_entry->limSmeState != + eLIM_SME_NORMAL_CHANNEL_SCAN_STATE))) { + lim_log(mac_ctx, LOGE, FL( + "Rcvd unexpected msg %X in state %X, in role %X"), + msg_type, session_entry->limSmeState, + GET_LIM_SYSTEM_ROLE(session_entry)); + goto end; + } + sta_ds = dph_get_hash_entry(mac_ctx, assoc_cnf.aid, + &session_entry->dph.dphHashTable); + if (sta_ds == NULL) { + lim_log(mac_ctx, LOGE, FL( + "Rcvd invalid msg %X due to no STA ctx, aid %d, peer "), + msg_type, assoc_cnf.aid); + lim_print_mac_addr(mac_ctx, assoc_cnf.peer_macaddr.bytes, LOG1); + + /* + * send a DISASSOC_IND message to WSM to make sure + * the state in WSM and LIM is the same + */ + lim_send_sme_disassoc_ntf(mac_ctx, assoc_cnf.peer_macaddr.bytes, + eSIR_SME_STA_NOT_ASSOCIATED, + eLIM_PEER_ENTITY_DISASSOC, assoc_cnf.aid, + session_entry->smeSessionId, + session_entry->transactionId, + session_entry); + goto end; + } + if (qdf_mem_cmp((uint8_t *)sta_ds->staAddr, + (uint8_t *) assoc_cnf.peer_macaddr.bytes, + QDF_MAC_ADDR_SIZE)) { + lim_log(mac_ctx, LOG1, FL( + "peerMacAddr mismatched for aid %d, peer "), + assoc_cnf.aid); + lim_print_mac_addr(mac_ctx, assoc_cnf.peer_macaddr.bytes, LOG1); + goto end; + } + + if ((sta_ds->mlmStaContext.mlmState != eLIM_MLM_WT_ASSOC_CNF_STATE) || + ((sta_ds->mlmStaContext.subType == LIM_ASSOC) && + (msg_type != eWNI_SME_ASSOC_CNF)) || + ((sta_ds->mlmStaContext.subType == LIM_REASSOC) && + (msg_type != eWNI_SME_ASSOC_CNF))) { + lim_log(mac_ctx, LOG1, FL( + "not in MLM_WT_ASSOC_CNF_STATE, for aid %d, peer" + "StaD mlmState : %d"), + assoc_cnf.aid, sta_ds->mlmStaContext.mlmState); + lim_print_mac_addr(mac_ctx, assoc_cnf.peer_macaddr.bytes, LOG1); + goto end; + } + /* + * Deactivate/delet CNF_WAIT timer since ASSOC_CNF + * has been received + */ + lim_log(mac_ctx, LOG1, FL("Received SME_ASSOC_CNF. Delete Timer")); + lim_deactivate_and_change_per_sta_id_timer(mac_ctx, + eLIM_CNF_WAIT_TIMER, sta_ds->assocId); + + if (assoc_cnf.statusCode == eSIR_SME_SUCCESS) { + /* + * In BTAMP-AP, PE already finished the WMA_ADD_STA sequence + * when it had received Assoc Request frame. Now, PE just needs + * to send association rsp frame to the requesting BTAMP-STA. + */ + sta_ds->mlmStaContext.mlmState = + eLIM_MLM_LINK_ESTABLISHED_STATE; + lim_log(mac_ctx, LOG1, + FL("sending Assoc Rsp frame to STA (assoc id=%d) "), + sta_ds->assocId); + lim_send_assoc_rsp_mgmt_frame(mac_ctx, eSIR_SUCCESS, + sta_ds->assocId, sta_ds->staAddr, + sta_ds->mlmStaContext.subType, sta_ds, + session_entry); + goto end; + } else { + /* + * SME_ASSOC_CNF status is non-success, so STA is not allowed + * to be associated since the HAL sta entry is created for + * denied STA we need to remove this HAL entry. + * So to do that set updateContext to 1 + */ + if (!sta_ds->mlmStaContext.updateContext) + sta_ds->mlmStaContext.updateContext = 1; + lim_log(mac_ctx, LOG1, + FL("Recv Assoc Cnf, status Code : %d(assoc id=%d) "), + assoc_cnf.statusCode, sta_ds->assocId); + lim_reject_association(mac_ctx, sta_ds->staAddr, + sta_ds->mlmStaContext.subType, + true, sta_ds->mlmStaContext.authType, + sta_ds->assocId, true, + eSIR_MAC_UNSPEC_FAILURE_STATUS, + session_entry); + } +end: + if (((session_entry != NULL) && (sta_ds != NULL)) && + (session_entry->parsedAssocReq[sta_ds->assocId] != NULL)) { + assoc_req = (tpSirAssocReq) + session_entry->parsedAssocReq[sta_ds->assocId]; + if (assoc_req->assocReqFrame) { + qdf_mem_free(assoc_req->assocReqFrame); + assoc_req->assocReqFrame = NULL; + } + qdf_mem_free(session_entry->parsedAssocReq[sta_ds->assocId]); + session_entry->parsedAssocReq[sta_ds->assocId] = NULL; + } +} + +static void __lim_process_sme_addts_req(tpAniSirGlobal pMac, uint32_t *pMsgBuf) +{ + tpDphHashNode pStaDs; + tSirMacAddr peerMac; + tpSirAddtsReq pSirAddts; + uint32_t timeout; + tpPESession psessionEntry; + uint8_t sessionId; /* PE sessionId */ + uint8_t smesessionId; + uint16_t smetransactionId; + + if (pMsgBuf == NULL) { + lim_log(pMac, LOGE, FL("Buffer is Pointing to NULL")); + return; + } + + lim_get_session_info(pMac, (uint8_t *) pMsgBuf, &smesessionId, + &smetransactionId); + + pSirAddts = (tpSirAddtsReq) pMsgBuf; + + psessionEntry = pe_find_session_by_bssid(pMac, pSirAddts->bssid.bytes, + &sessionId); + if (psessionEntry == NULL) { + lim_log(pMac, LOGE, "Session Does not exist for given bssId"); + lim_send_sme_addts_rsp(pMac, pSirAddts->rspReqd, eSIR_FAILURE, + NULL, pSirAddts->req.tspec, + smesessionId, smetransactionId); + return; + } +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM /* FEATURE_WLAN_DIAG_SUPPORT */ + lim_diag_event_report(pMac, WLAN_PE_DIAG_ADDTS_REQ_EVENT, psessionEntry, 0, + 0); +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + + /* if sta + * - verify assoc state + * - send addts request to ap + * - wait for addts response from ap + * if ap, just ignore with error log + */ + PELOG1(lim_log(pMac, LOG1, + FL("Received SME_ADDTS_REQ (TSid %d, UP %d)"), + pSirAddts->req.tspec.tsinfo.traffic.tsid, + pSirAddts->req.tspec.tsinfo.traffic.userPrio); + ) + + if (!LIM_IS_STA_ROLE(psessionEntry)) { + PELOGE(lim_log(pMac, LOGE, "AddTs received on AP - ignoring");) + lim_send_sme_addts_rsp(pMac, pSirAddts->rspReqd, eSIR_FAILURE, + psessionEntry, pSirAddts->req.tspec, + smesessionId, smetransactionId); + return; + } + + pStaDs = + dph_get_hash_entry(pMac, DPH_STA_HASH_INDEX_PEER, + &psessionEntry->dph.dphHashTable); + + if (pStaDs == NULL) { + PELOGE(lim_log + (pMac, LOGE, "Cannot find AP context for addts req"); + ) + lim_send_sme_addts_rsp(pMac, pSirAddts->rspReqd, eSIR_FAILURE, + psessionEntry, pSirAddts->req.tspec, + smesessionId, smetransactionId); + return; + } + + if ((!pStaDs->valid) || (pStaDs->mlmStaContext.mlmState != + eLIM_MLM_LINK_ESTABLISHED_STATE)) { + lim_log(pMac, LOGE, "AddTs received in invalid MLM state"); + lim_send_sme_addts_rsp(pMac, pSirAddts->rspReqd, eSIR_FAILURE, + psessionEntry, pSirAddts->req.tspec, + smesessionId, smetransactionId); + return; + } + + pSirAddts->req.wsmTspecPresent = 0; + pSirAddts->req.wmeTspecPresent = 0; + pSirAddts->req.lleTspecPresent = 0; + + if ((pStaDs->wsmEnabled) && + (pSirAddts->req.tspec.tsinfo.traffic.accessPolicy != + SIR_MAC_ACCESSPOLICY_EDCA)) + pSirAddts->req.wsmTspecPresent = 1; + else if (pStaDs->wmeEnabled) + pSirAddts->req.wmeTspecPresent = 1; + else if (pStaDs->lleEnabled) + pSirAddts->req.lleTspecPresent = 1; + else { + PELOGW(lim_log + (pMac, LOGW, FL("ADDTS_REQ ignore - qos is disabled")); + ) + lim_send_sme_addts_rsp(pMac, pSirAddts->rspReqd, eSIR_FAILURE, + psessionEntry, pSirAddts->req.tspec, + smesessionId, smetransactionId); + return; + } + + if ((psessionEntry->limSmeState != eLIM_SME_ASSOCIATED_STATE) && + (psessionEntry->limSmeState != eLIM_SME_LINK_EST_STATE)) { + lim_log(pMac, LOGE, + "AddTs received in invalid LIMsme state (%d)", + psessionEntry->limSmeState); + lim_send_sme_addts_rsp(pMac, pSirAddts->rspReqd, eSIR_FAILURE, + psessionEntry, pSirAddts->req.tspec, + smesessionId, smetransactionId); + return; + } + + if (pMac->lim.gLimAddtsSent) { + lim_log(pMac, LOGE, + "Addts (token %d, tsid %d, up %d) is still pending", + pMac->lim.gLimAddtsReq.req.dialogToken, + pMac->lim.gLimAddtsReq.req.tspec.tsinfo.traffic.tsid, + pMac->lim.gLimAddtsReq.req.tspec.tsinfo.traffic. + userPrio); + lim_send_sme_addts_rsp(pMac, pSirAddts->rspReqd, eSIR_FAILURE, + psessionEntry, pSirAddts->req.tspec, + smesessionId, smetransactionId); + return; + } + + sir_copy_mac_addr(peerMac, psessionEntry->bssId); + + /* save the addts request */ + pMac->lim.gLimAddtsSent = true; + qdf_mem_copy((uint8_t *) &pMac->lim.gLimAddtsReq, + (uint8_t *) pSirAddts, sizeof(tSirAddtsReq)); + + /* ship out the message now */ + lim_send_addts_req_action_frame(pMac, peerMac, &pSirAddts->req, + psessionEntry); + PELOG1(lim_log(pMac, LOG1, "Sent ADDTS request");) + /* start a timer to wait for the response */ + if (pSirAddts->timeout) + timeout = pSirAddts->timeout; + else if (wlan_cfg_get_int(pMac, WNI_CFG_ADDTS_RSP_TIMEOUT, &timeout) != + eSIR_SUCCESS) { + lim_log(pMac, LOGP, + FL("Unable to get Cfg param %d (Addts Rsp Timeout)"), + WNI_CFG_ADDTS_RSP_TIMEOUT); + return; + } + + timeout = SYS_MS_TO_TICKS(timeout); + if (tx_timer_change(&pMac->lim.limTimers.gLimAddtsRspTimer, timeout, 0) + != TX_SUCCESS) { + lim_log(pMac, LOGP, FL("AddtsRsp timer change failed!")); + return; + } + pMac->lim.gLimAddtsRspTimerCount++; + if (tx_timer_change_context(&pMac->lim.limTimers.gLimAddtsRspTimer, + pMac->lim.gLimAddtsRspTimerCount) != + TX_SUCCESS) { + lim_log(pMac, LOGP, FL("AddtsRsp timer change failed!")); + return; + } + MTRACE(mac_trace + (pMac, TRACE_CODE_TIMER_ACTIVATE, psessionEntry->peSessionId, + eLIM_ADDTS_RSP_TIMER)); + + /* add the sessionId to the timer object */ + pMac->lim.limTimers.gLimAddtsRspTimer.sessionId = sessionId; + if (tx_timer_activate(&pMac->lim.limTimers.gLimAddtsRspTimer) != + TX_SUCCESS) { + lim_log(pMac, LOGP, FL("AddtsRsp timer activation failed!")); + return; + } + return; +} + +static void __lim_process_sme_delts_req(tpAniSirGlobal pMac, uint32_t *pMsgBuf) +{ + tSirMacAddr peerMacAddr; + uint8_t ac; + tSirMacTSInfo *pTsinfo; + tpSirDeltsReq pDeltsReq = (tpSirDeltsReq) pMsgBuf; + tpDphHashNode pStaDs = NULL; + tpPESession psessionEntry; + uint8_t sessionId; + uint32_t status = eSIR_SUCCESS; + uint8_t smesessionId; + uint16_t smetransactionId; + + lim_get_session_info(pMac, (uint8_t *) pMsgBuf, &smesessionId, + &smetransactionId); + + psessionEntry = pe_find_session_by_bssid(pMac, + pDeltsReq->bssid.bytes, + &sessionId); + if (psessionEntry == NULL) { + lim_log(pMac, LOGE, "Session Does not exist for given bssId"); + status = eSIR_FAILURE; + goto end; + } +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM /* FEATURE_WLAN_DIAG_SUPPORT */ + lim_diag_event_report(pMac, WLAN_PE_DIAG_DELTS_REQ_EVENT, psessionEntry, 0, + 0); +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + + if (eSIR_SUCCESS != + lim_validate_delts_req(pMac, pDeltsReq, peerMacAddr, psessionEntry)) { + PELOGE(lim_log(pMac, LOGE, FL("lim_validate_delts_req failed"));) + status = eSIR_FAILURE; + lim_send_sme_delts_rsp(pMac, pDeltsReq, eSIR_FAILURE, psessionEntry, + smesessionId, smetransactionId); + return; + } + + lim_log(pMac, LOG1, + FL("Sent DELTS request to station with assocId = %d MacAddr = " + MAC_ADDRESS_STR), + pDeltsReq->aid, MAC_ADDR_ARRAY(peerMacAddr)); + + lim_send_delts_req_action_frame(pMac, peerMacAddr, + pDeltsReq->req.wmeTspecPresent, + &pDeltsReq->req.tsinfo, + &pDeltsReq->req.tspec, psessionEntry); + + pTsinfo = + pDeltsReq->req.wmeTspecPresent ? &pDeltsReq->req.tspec. + tsinfo : &pDeltsReq->req.tsinfo; + + /* We've successfully send DELTS frame to AP. Update the + * dynamic UAPSD mask. The AC for this TSPEC to be deleted + * is no longer trigger enabled or delivery enabled + */ + lim_set_tspec_uapsd_mask_per_session(pMac, psessionEntry, + pTsinfo, CLEAR_UAPSD_MASK); + + /* We're deleting the TSPEC, so this particular AC is no longer + * admitted. PE needs to downgrade the EDCA + * parameters(for the AC for which TS is being deleted) to the + * next best AC for which ACM is not enabled, and send the + * updated values to HAL. + */ + ac = upToAc(pTsinfo->traffic.userPrio); + + if (pTsinfo->traffic.direction == SIR_MAC_DIRECTION_UPLINK) { + psessionEntry->gAcAdmitMask[SIR_MAC_DIRECTION_UPLINK] &= + ~(1 << ac); + } else if (pTsinfo->traffic.direction == + SIR_MAC_DIRECTION_DNLINK) { + psessionEntry->gAcAdmitMask[SIR_MAC_DIRECTION_DNLINK] &= + ~(1 << ac); + } else if (pTsinfo->traffic.direction == + SIR_MAC_DIRECTION_BIDIR) { + psessionEntry->gAcAdmitMask[SIR_MAC_DIRECTION_UPLINK] &= + ~(1 << ac); + psessionEntry->gAcAdmitMask[SIR_MAC_DIRECTION_DNLINK] &= + ~(1 << ac); + } + + lim_set_active_edca_params(pMac, psessionEntry->gLimEdcaParams, + psessionEntry); + + pStaDs = + dph_get_hash_entry(pMac, DPH_STA_HASH_INDEX_PEER, + &psessionEntry->dph.dphHashTable); + if (pStaDs != NULL) { + lim_send_edca_params(pMac, psessionEntry->gLimEdcaParamsActive, + pStaDs->bssId); + status = eSIR_SUCCESS; + } else { + lim_log(pMac, LOGE, FL("Self entry missing in Hash Table ")); + status = eSIR_FAILURE; + } +#ifdef FEATURE_WLAN_ESE + lim_send_sme_tsm_ie_ind(pMac, psessionEntry, 0, 0, 0); +#endif + + /* send an sme response back */ +end: + lim_send_sme_delts_rsp(pMac, pDeltsReq, eSIR_SUCCESS, psessionEntry, + smesessionId, smetransactionId); +} + +void lim_process_sme_addts_rsp_timeout(tpAniSirGlobal pMac, uint32_t param) +{ + /* fetch the sessionEntry based on the sessionId */ + tpPESession psessionEntry; + psessionEntry = pe_find_session_by_session_id(pMac, + pMac->lim.limTimers.gLimAddtsRspTimer. + sessionId); + if (psessionEntry == NULL) { + lim_log(pMac, LOGP, + FL("Session Does not exist for given sessionID")); + return; + } + + if (!LIM_IS_STA_ROLE(psessionEntry)) { + lim_log(pMac, LOGW, "AddtsRspTimeout in non-Sta role (%d)", + GET_LIM_SYSTEM_ROLE(psessionEntry)); + pMac->lim.gLimAddtsSent = false; + return; + } + + if (!pMac->lim.gLimAddtsSent) { + lim_log(pMac, LOGW, "AddtsRspTimeout but no AddtsSent"); + return; + } + + if (param != pMac->lim.gLimAddtsRspTimerCount) { + lim_log(pMac, LOGE, + FL("Invalid AddtsRsp Timer count %d (exp %d)"), param, + pMac->lim.gLimAddtsRspTimerCount); + return; + } + /* this a real response timeout */ + pMac->lim.gLimAddtsSent = false; + pMac->lim.gLimAddtsRspTimerCount++; + + lim_send_sme_addts_rsp(pMac, true, eSIR_SME_ADDTS_RSP_TIMEOUT, + psessionEntry, pMac->lim.gLimAddtsReq.req.tspec, + psessionEntry->smeSessionId, + psessionEntry->transactionId); +} + +/** + * __lim_process_sme_get_statistics_request() + * + ***FUNCTION: + * + * + ***NOTE: + * + * @param pMac Pointer to Global MAC structure + * @param *pMsgBuf A pointer to the SME message buffer + * @return None + */ +static void +__lim_process_sme_get_statistics_request(tpAniSirGlobal pMac, uint32_t *pMsgBuf) +{ + tpAniGetPEStatsReq pPEStatsReq; + tSirMsgQ msgQ; + + pPEStatsReq = (tpAniGetPEStatsReq) pMsgBuf; + + msgQ.type = WMA_GET_STATISTICS_REQ; + + msgQ.reserved = 0; + msgQ.bodyptr = pMsgBuf; + msgQ.bodyval = 0; + MTRACE(mac_trace_msg_tx(pMac, NO_SESSION, msgQ.type)); + + if (eSIR_SUCCESS != (wma_post_ctrl_msg(pMac, &msgQ))) { + qdf_mem_free(pMsgBuf); + pMsgBuf = NULL; + lim_log(pMac, LOGP, "Unable to forward request"); + return; + } + + return; +} + +#ifdef FEATURE_WLAN_ESE +/** + * __lim_process_sme_get_tsm_stats_request() - get tsm stats request + * + * @pMac: Pointer to Global MAC structure + * @pMsgBuf: A pointer to the SME message buffer + * + * Return: None + */ +static void +__lim_process_sme_get_tsm_stats_request(tpAniSirGlobal pMac, uint32_t *pMsgBuf) +{ + tSirMsgQ msgQ; + + msgQ.type = WMA_TSM_STATS_REQ; + msgQ.reserved = 0; + msgQ.bodyptr = pMsgBuf; + msgQ.bodyval = 0; + MTRACE(mac_trace_msg_tx(pMac, NO_SESSION, msgQ.type)); + + if (eSIR_SUCCESS != (wma_post_ctrl_msg(pMac, &msgQ))) { + qdf_mem_free(pMsgBuf); + pMsgBuf = NULL; + lim_log(pMac, LOGP, "Unable to forward request"); + return; + } +} +#endif /* FEATURE_WLAN_ESE */ + +static void +__lim_process_sme_update_apwpsi_es(tpAniSirGlobal pMac, uint32_t *pMsgBuf) +{ + tpSirUpdateAPWPSIEsReq pUpdateAPWPSIEsReq; + tpPESession psessionEntry; + uint8_t sessionId; /* PE sessionID */ + + PELOG1(lim_log(pMac, LOG1, FL("received UPDATE_APWPSIEs_REQ message"));); + + if (pMsgBuf == NULL) { + lim_log(pMac, LOGE, FL("Buffer is Pointing to NULL")); + return; + } + + pUpdateAPWPSIEsReq = qdf_mem_malloc(sizeof(tSirUpdateAPWPSIEsReq)); + if (NULL == pUpdateAPWPSIEsReq) { + lim_log(pMac, LOGP, + FL + ("call to AllocateMemory failed for pUpdateAPWPSIEsReq")); + return; + } + qdf_mem_copy(pUpdateAPWPSIEsReq, pMsgBuf, + sizeof(struct sSirUpdateAPWPSIEsReq)); + + psessionEntry = pe_find_session_by_bssid(pMac, + pUpdateAPWPSIEsReq->bssid.bytes, + &sessionId); + if (psessionEntry == NULL) { + lim_log(pMac, LOGW, + FL("Session does not exist for given BSSID")); + goto end; + } + + qdf_mem_copy(&psessionEntry->APWPSIEs, &pUpdateAPWPSIEsReq->APWPSIEs, + sizeof(tSirAPWPSIEs)); + + sch_set_fixed_beacon_fields(pMac, psessionEntry); + lim_send_beacon_ind(pMac, psessionEntry); + +end: + qdf_mem_free(pUpdateAPWPSIEsReq); + return; +} + +static void lim_process_sme_update_config(tpAniSirGlobal mac_ctx, + struct update_config *msg) +{ + tpPESession pe_session; + + pe_debug("received eWNI_SME_UPDATE_HT_CONFIG message"); + if (msg == NULL) { + pe_err("Buffer is Pointing to NULL"); + return; + } + + pe_session = pe_find_session_by_sme_session_id(mac_ctx, + msg->sme_session_id); + if (pe_session == NULL) { + pe_warn("Session does not exist for given BSSID"); + return; + } + + switch (msg->capab) { + case WNI_CFG_HT_CAP_INFO_ADVANCE_CODING: + pe_session->htConfig.ht_rx_ldpc = msg->value; + break; + case WNI_CFG_HT_CAP_INFO_TX_STBC: + pe_session->htConfig.ht_tx_stbc = msg->value; + break; + case WNI_CFG_HT_CAP_INFO_RX_STBC: + pe_session->htConfig.ht_rx_stbc = msg->value; + break; + case WNI_CFG_HT_CAP_INFO_SHORT_GI_20MHZ: + pe_session->htConfig.ht_sgi20 = msg->value; + break; + case WNI_CFG_HT_CAP_INFO_SHORT_GI_40MHZ: + pe_session->htConfig.ht_sgi40 = msg->value; + break; + } + + if (LIM_IS_AP_ROLE(pe_session)) { + sch_set_fixed_beacon_fields(mac_ctx, pe_session); + lim_send_beacon_ind(mac_ctx, pe_session); + } +} + +void +lim_send_vdev_restart(tpAniSirGlobal pMac, + tpPESession psessionEntry, uint8_t sessionId) +{ + tpHalHiddenSsidVdevRestart pHalHiddenSsidVdevRestart = NULL; + tSirMsgQ msgQ; + tSirRetStatus retCode = eSIR_SUCCESS; + + if (psessionEntry == NULL) { + PELOGE(lim_log + (pMac, LOGE, "%s:%d: Invalid parameters", __func__, + __LINE__); + ) + return; + } + + pHalHiddenSsidVdevRestart = + qdf_mem_malloc(sizeof(tHalHiddenSsidVdevRestart)); + if (NULL == pHalHiddenSsidVdevRestart) { + PELOGE(lim_log + (pMac, LOGE, "%s:%d: Unable to allocate memory", + __func__, __LINE__); + ) + return; + } + + pHalHiddenSsidVdevRestart->ssidHidden = psessionEntry->ssidHidden; + pHalHiddenSsidVdevRestart->sessionId = sessionId; + + msgQ.type = WMA_HIDDEN_SSID_VDEV_RESTART; + msgQ.bodyptr = pHalHiddenSsidVdevRestart; + msgQ.bodyval = 0; + + retCode = wma_post_ctrl_msg(pMac, &msgQ); + if (eSIR_SUCCESS != retCode) { + PELOGE(lim_log + (pMac, LOGE, "%s:%d: wma_post_ctrl_msg() failed", __func__, + __LINE__); + ) + qdf_mem_free(pHalHiddenSsidVdevRestart); + } +} + +/** + * __lim_process_roam_scan_offload_req() - Process Roam scan offload from csr + * @mac_ctx: Pointer to Global MAC structure + * @msg_buf: Pointer to SME message buffer + * + * Return: None + */ +static void __lim_process_roam_scan_offload_req(tpAniSirGlobal mac_ctx, + uint32_t *msg_buf) +{ + tpPESession pe_session; + tSirMsgQ wma_msg; + tSirRetStatus status; + tSirRoamOffloadScanReq *req_buffer; + uint16_t local_ie_len; + uint8_t *local_ie_buf; + + req_buffer = (tSirRoamOffloadScanReq *)msg_buf; + pe_session = pe_find_session_by_sme_session_id(mac_ctx, + req_buffer->sessionId); + + local_ie_buf = qdf_mem_malloc(MAX_DEFAULT_SCAN_IE_LEN); + if (!local_ie_buf) { + lim_log(mac_ctx, LOGE, + FL("Mem Alloc failed for local_ie_buf")); + qdf_mem_free(req_buffer); + return; + } + + local_ie_len = req_buffer->assoc_ie.length; + /* Update ext cap IE if present */ + if (local_ie_len && + !lim_update_ext_cap_ie(mac_ctx, req_buffer->assoc_ie.addIEdata, + local_ie_buf, &local_ie_len)) { + if (local_ie_len < + QDF_ARRAY_SIZE(req_buffer->assoc_ie.addIEdata)) { + req_buffer->assoc_ie.length = local_ie_len; + qdf_mem_copy(req_buffer->assoc_ie.addIEdata, + local_ie_buf, local_ie_len); + } + } + qdf_mem_free(local_ie_buf); + + wma_msg.type = WMA_ROAM_SCAN_OFFLOAD_REQ; + wma_msg.bodyptr = req_buffer; + + status = wma_post_ctrl_msg(mac_ctx, &wma_msg); + if (eSIR_SUCCESS != status) { + lim_log(mac_ctx, LOGE, + FL("Posting WMA_ROAM_SCAN_OFFLOAD_REQ failed")); + qdf_mem_free(req_buffer); + } +} + +/* + * lim_handle_update_ssid_hidden() - Processes SSID hidden update + * @mac_ctx: Pointer to global mac context + * @session: Pointer to PE session + * @ssid_hidden: SSID hidden value to set; 0 - Broadcast SSID, + * 1 - Disable broadcast SSID + * + * Return: None + */ +static void lim_handle_update_ssid_hidden(tpAniSirGlobal mac_ctx, + tpPESession session, uint8_t ssid_hidden) +{ + lim_log(mac_ctx, LOG1, FL("received HIDE_SSID message")); + if (ssid_hidden != session->ssidHidden) + session->ssidHidden = ssid_hidden; + else { + lim_log(mac_ctx, LOG1, FL("Same config already present!")); + return; + } + + /* Send vdev restart */ + lim_send_vdev_restart(mac_ctx, session, session->smeSessionId); + + /* Update beacon */ + sch_set_fixed_beacon_fields(mac_ctx, session); + lim_send_beacon_ind(mac_ctx, session); + + return; +} + +/** + * __lim_process_sme_session_update - process SME session update msg + * + * @mac_ctx: Pointer to global mac context + * @msg_buf: Pointer to the received message buffer + * + * Return: None + */ +static void __lim_process_sme_session_update(tpAniSirGlobal mac_ctx, + uint32_t *msg_buf) +{ + struct sir_update_session_param *msg; + tpPESession session; + + if (!msg_buf) { + lim_log(mac_ctx, LOGE, FL("Buffer is Pointing to NULL")); + return; + } + + msg = (struct sir_update_session_param *) msg_buf; + + session = pe_find_session_by_sme_session_id(mac_ctx, msg->session_id); + if (!session) { + lim_log(mac_ctx, LOGW, + "Session does not exist for given sessionId %d", + msg->session_id); + return; + } + + lim_log(mac_ctx, LOG1, FL("received SME Session update for %d val %d"), + msg->param_type, msg->param_val); + switch (msg->param_type) { + case SIR_PARAM_SSID_HIDDEN: + lim_handle_update_ssid_hidden(mac_ctx, session, msg->param_val); + break; + case SIR_PARAM_IGNORE_ASSOC_DISALLOWED: + session->ignore_assoc_disallowed = msg->param_val; + break; + default: + lim_log(mac_ctx, LOGE, FL("Unknown session param")); + break; + } +} + +static void __lim_process_sme_set_wparsni_es(tpAniSirGlobal pMac, uint32_t *pMsgBuf) +{ + tpSirUpdateAPWPARSNIEsReq pUpdateAPWPARSNIEsReq; + tpPESession psessionEntry; + uint8_t sessionId; /* PE sessionID */ + + if (pMsgBuf == NULL) { + lim_log(pMac, LOGE, FL("Buffer is Pointing to NULL")); + return; + } + + pUpdateAPWPARSNIEsReq = qdf_mem_malloc(sizeof(tSirUpdateAPWPSIEsReq)); + if (NULL == pUpdateAPWPARSNIEsReq) { + lim_log(pMac, LOGP, + FL + ("call to AllocateMemory failed for pUpdateAPWPARSNIEsReq")); + return; + } + qdf_mem_copy(pUpdateAPWPARSNIEsReq, pMsgBuf, + sizeof(struct sSirUpdateAPWPARSNIEsReq)); + + psessionEntry = pe_find_session_by_bssid(pMac, + pUpdateAPWPARSNIEsReq->bssid.bytes, + &sessionId); + if (psessionEntry == NULL) { + lim_log(pMac, LOGW, + FL("Session does not exist for given BSSID")); + goto end; + } + + qdf_mem_copy(&psessionEntry->pLimStartBssReq->rsnIE, + &pUpdateAPWPARSNIEsReq->APWPARSNIEs, sizeof(tSirRSNie)); + + lim_set_rs_nie_wp_aiefrom_sme_start_bss_req_message(pMac, + &psessionEntry-> + pLimStartBssReq->rsnIE, + psessionEntry); + + psessionEntry->pLimStartBssReq->privacy = 1; + psessionEntry->privacy = 1; + + sch_set_fixed_beacon_fields(pMac, psessionEntry); + lim_send_beacon_ind(pMac, psessionEntry); + +end: + qdf_mem_free(pUpdateAPWPARSNIEsReq); + return; +} /*** end __lim_process_sme_set_wparsni_es(tpAniSirGlobal pMac, uint32_t *pMsgBuf) ***/ + +/* + Update the beacon Interval dynamically if beaconInterval is different in MCC + */ +static void __lim_process_sme_change_bi(tpAniSirGlobal pMac, uint32_t *pMsgBuf) +{ + tpSirChangeBIParams pChangeBIParams; + tpPESession psessionEntry; + uint8_t sessionId = 0; + tUpdateBeaconParams beaconParams; + + PELOG1(lim_log(pMac, LOG1, + FL("received Update Beacon Interval message")); + ); + + if (pMsgBuf == NULL) { + lim_log(pMac, LOGE, FL("Buffer is Pointing to NULL")); + return; + } + + qdf_mem_zero(&beaconParams, sizeof(tUpdateBeaconParams)); + pChangeBIParams = (tpSirChangeBIParams) pMsgBuf; + + psessionEntry = pe_find_session_by_bssid(pMac, + pChangeBIParams->bssid.bytes, + &sessionId); + if (psessionEntry == NULL) { + lim_log(pMac, LOGE, + FL("Session does not exist for given BSSID")); + return; + } + + /*Update sessionEntry Beacon Interval */ + if (psessionEntry->beaconParams.beaconInterval != + pChangeBIParams->beaconInterval) { + psessionEntry->beaconParams.beaconInterval = + pChangeBIParams->beaconInterval; + } + + /*Update sch beaconInterval */ + if (pMac->sch.schObject.gSchBeaconInterval != + pChangeBIParams->beaconInterval) { + pMac->sch.schObject.gSchBeaconInterval = + pChangeBIParams->beaconInterval; + + PELOG1(lim_log(pMac, LOG1, + FL + ("LIM send update BeaconInterval Indication : %d"), + pChangeBIParams->beaconInterval); + ); + + if (false == pMac->sap.SapDfsInfo.is_dfs_cac_timer_running) { + /* Update beacon */ + sch_set_fixed_beacon_fields(pMac, psessionEntry); + + beaconParams.bssIdx = psessionEntry->bssIdx; + /* Set change in beacon Interval */ + beaconParams.beaconInterval = + pChangeBIParams->beaconInterval; + beaconParams.paramChangeBitmap = + PARAM_BCN_INTERVAL_CHANGED; + lim_send_beacon_params(pMac, &beaconParams, psessionEntry); + } + } + + return; +} /*** end __lim_process_sme_change_bi(tpAniSirGlobal pMac, uint32_t *pMsgBuf) ***/ + +#ifdef QCA_HT_2040_COEX +static void __lim_process_sme_set_ht2040_mode(tpAniSirGlobal pMac, + uint32_t *pMsgBuf) +{ + tpSirSetHT2040Mode pSetHT2040Mode; + tpPESession psessionEntry; + uint8_t sessionId = 0; + cds_msg_t msg; + tUpdateVHTOpMode *pHtOpMode = NULL; + uint16_t staId = 0; + tpDphHashNode pStaDs = NULL; + + PELOG1(lim_log(pMac, LOG1, FL("received Set HT 20/40 mode message"));); + if (pMsgBuf == NULL) { + lim_log(pMac, LOGE, FL("Buffer is Pointing to NULL")); + return; + } + + pSetHT2040Mode = (tpSirSetHT2040Mode) pMsgBuf; + + psessionEntry = pe_find_session_by_bssid(pMac, + pSetHT2040Mode->bssid.bytes, + &sessionId); + if (psessionEntry == NULL) { + lim_log(pMac, LOG1, + FL("Session does not exist for given BSSID ")); + lim_print_mac_addr(pMac, pSetHT2040Mode->bssid.bytes, LOG1); + return; + } + + lim_log(pMac, LOG1, FL("Update session entry for cbMod=%d"), + pSetHT2040Mode->cbMode); + /*Update sessionEntry HT related fields */ + switch (pSetHT2040Mode->cbMode) { + case PHY_SINGLE_CHANNEL_CENTERED: + psessionEntry->htSecondaryChannelOffset = + PHY_SINGLE_CHANNEL_CENTERED; + psessionEntry->htRecommendedTxWidthSet = 0; + if (pSetHT2040Mode->obssEnabled) + psessionEntry->htSupportedChannelWidthSet + = eHT_CHANNEL_WIDTH_40MHZ; + else + psessionEntry->htSupportedChannelWidthSet + = eHT_CHANNEL_WIDTH_20MHZ; + break; + case PHY_DOUBLE_CHANNEL_LOW_PRIMARY: + psessionEntry->htSecondaryChannelOffset = + PHY_DOUBLE_CHANNEL_LOW_PRIMARY; + psessionEntry->htRecommendedTxWidthSet = 1; + break; + case PHY_DOUBLE_CHANNEL_HIGH_PRIMARY: + psessionEntry->htSecondaryChannelOffset = + PHY_DOUBLE_CHANNEL_HIGH_PRIMARY; + psessionEntry->htRecommendedTxWidthSet = 1; + break; + default: + lim_log(pMac, LOGE, FL("Invalid cbMode")); + return; + } + + /* Update beacon */ + sch_set_fixed_beacon_fields(pMac, psessionEntry); + lim_send_beacon_ind(pMac, psessionEntry); + + /* update OP Mode for each associated peer */ + for (staId = 0; staId < psessionEntry->dph.dphHashTable.size; staId++) { + pStaDs = dph_get_hash_entry(pMac, staId, + &psessionEntry->dph.dphHashTable); + if (NULL == pStaDs) + continue; + + if (pStaDs->valid && pStaDs->htSupportedChannelWidthSet) { + pHtOpMode = qdf_mem_malloc(sizeof(tUpdateVHTOpMode)); + if (NULL == pHtOpMode) { + lim_log(pMac, LOGE, + FL + ("%s: Not able to allocate memory for setting OP mode"), + __func__); + return; + } + pHtOpMode->opMode = + (psessionEntry->htSecondaryChannelOffset == + PHY_SINGLE_CHANNEL_CENTERED) ? + eHT_CHANNEL_WIDTH_20MHZ : eHT_CHANNEL_WIDTH_40MHZ; + pHtOpMode->staId = staId; + qdf_mem_copy(pHtOpMode->peer_mac, &pStaDs->staAddr, + sizeof(tSirMacAddr)); + pHtOpMode->smesessionId = sessionId; + pHtOpMode->dot11_mode = psessionEntry->dot11mode; + + msg.type = WMA_UPDATE_OP_MODE; + msg.reserved = 0; + msg.bodyptr = pHtOpMode; + if (!QDF_IS_STATUS_SUCCESS + (cds_mq_post_message(QDF_MODULE_ID_WMA, &msg))) { + lim_log(pMac, LOGE, + FL + ("%s: Not able to post WMA_UPDATE_OP_MODE message to WMA"), + __func__); + qdf_mem_free(pHtOpMode); + return; + } + lim_log(pMac, LOG1, + FL + ("%s: Notifed FW about OP mode: %d for staId=%d"), + __func__, pHtOpMode->opMode, staId); + + } else + lim_log(pMac, LOG1, + FL("%s: station %d does not support HT40\n"), + __func__, staId); + } + + return; +} +#endif + +/* -------------------------------------------------------------------- */ +/** + * __lim_process_report_message + * + * FUNCTION: Processes the next received Radio Resource Management message + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param None + * @return None + */ + +static void __lim_process_report_message(tpAniSirGlobal pMac, tpSirMsgQ pMsg) +{ + switch (pMsg->type) { + case eWNI_SME_NEIGHBOR_REPORT_REQ_IND: + rrm_process_neighbor_report_req(pMac, pMsg->bodyptr); + break; + case eWNI_SME_BEACON_REPORT_RESP_XMIT_IND: + rrm_process_beacon_report_xmit(pMac, pMsg->bodyptr); + break; + default: + lim_log(pMac, LOGE, FL("Invalid msg type:%d"), pMsg->type); + } +} + +/* -------------------------------------------------------------------- */ +/** + * lim_send_set_max_tx_power_req + * + * FUNCTION: Send SIR_HAL_SET_MAX_TX_POWER_REQ message to change the max tx power. + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param txPower txPower to be set. + * @param pSessionEntry session entry. + * @return None + */ +tSirRetStatus +lim_send_set_max_tx_power_req(tpAniSirGlobal pMac, int8_t txPower, + tpPESession pSessionEntry) +{ + tpMaxTxPowerParams pMaxTxParams = NULL; + tSirRetStatus retCode = eSIR_SUCCESS; + tSirMsgQ msgQ; + + if (pSessionEntry == NULL) { + lim_log(pMac, LOGE, FL("Inavalid parameters")); + return eSIR_FAILURE; + } + + pMaxTxParams = qdf_mem_malloc(sizeof(tMaxTxPowerParams)); + if (NULL == pMaxTxParams) { + lim_log(pMac, LOGP, + FL("Unable to allocate memory for pMaxTxParams ")); + return eSIR_MEM_ALLOC_FAILED; + + } + pMaxTxParams->power = txPower; + qdf_mem_copy(pMaxTxParams->bssId.bytes, pSessionEntry->bssId, + QDF_MAC_ADDR_SIZE); + qdf_mem_copy(pMaxTxParams->selfStaMacAddr.bytes, + pSessionEntry->selfMacAddr, + QDF_MAC_ADDR_SIZE); + + msgQ.type = WMA_SET_MAX_TX_POWER_REQ; + msgQ.bodyptr = pMaxTxParams; + msgQ.bodyval = 0; + lim_log(pMac, LOG1, FL("Post WMA_SET_MAX_TX_POWER_REQ to WMA")); + MTRACE(mac_trace_msg_tx(pMac, pSessionEntry->peSessionId, msgQ.type)); + retCode = wma_post_ctrl_msg(pMac, &msgQ); + if (eSIR_SUCCESS != retCode) { + lim_log(pMac, LOGE, FL("wma_post_ctrl_msg() failed")); + qdf_mem_free(pMaxTxParams); + } + return retCode; +} + +/** + * __lim_process_sme_register_mgmt_frame_req() - process sme reg mgmt frame req + * + * @mac_ctx: Pointer to Global MAC structure + * @msg_buf: pointer to the SME message buffer + * + * This function is called to process eWNI_SME_REGISTER_MGMT_FRAME_REQ message + * from SME. It Register this information within PE. + * + * Return: None + */ +static void __lim_process_sme_register_mgmt_frame_req(tpAniSirGlobal mac_ctx, + uint32_t *msg_buf) +{ + QDF_STATUS qdf_status; + tpSirRegisterMgmtFrame sme_req = (tpSirRegisterMgmtFrame)msg_buf; + struct mgmt_frm_reg_info *lim_mgmt_regn = NULL; + struct mgmt_frm_reg_info *next = NULL; + bool match = false; + + lim_log(mac_ctx, LOG1, FL( + "registerFrame %d, frameType %d, matchLen %d"), + sme_req->registerFrame, sme_req->frameType, + sme_req->matchLen); + /* First check whether entry exists already */ + qdf_mutex_acquire(&mac_ctx->lim.lim_frame_register_lock); + qdf_list_peek_front(&mac_ctx->lim.gLimMgmtFrameRegistratinQueue, + (qdf_list_node_t **) &lim_mgmt_regn); + qdf_mutex_release(&mac_ctx->lim.lim_frame_register_lock); + + while (lim_mgmt_regn != NULL) { + if (lim_mgmt_regn->frameType != sme_req->frameType) + goto skip_match; + if (sme_req->matchLen) { + if ((lim_mgmt_regn->matchLen == sme_req->matchLen) && + (!qdf_mem_cmp(lim_mgmt_regn->matchData, + sme_req->matchData, + lim_mgmt_regn->matchLen))) { + /* found match! */ + match = true; + break; + } + } else { + /* found match! */ + match = true; + break; + } +skip_match: + qdf_mutex_acquire(&mac_ctx->lim.lim_frame_register_lock); + qdf_status = qdf_list_peek_next( + &mac_ctx->lim.gLimMgmtFrameRegistratinQueue, + (qdf_list_node_t *)lim_mgmt_regn, + (qdf_list_node_t **)&next); + qdf_mutex_release(&mac_ctx->lim.lim_frame_register_lock); + lim_mgmt_regn = next; + next = NULL; + } + if (match) { + qdf_mutex_acquire(&mac_ctx->lim.lim_frame_register_lock); + if (QDF_STATUS_SUCCESS == + qdf_list_remove_node( + &mac_ctx->lim.gLimMgmtFrameRegistratinQueue, + (qdf_list_node_t *)lim_mgmt_regn)) + qdf_mem_free(lim_mgmt_regn); + qdf_mutex_release(&mac_ctx->lim.lim_frame_register_lock); + } + + if (sme_req->registerFrame) { + lim_mgmt_regn = + qdf_mem_malloc(sizeof(struct mgmt_frm_reg_info) + + sme_req->matchLen); + if (lim_mgmt_regn != NULL) { + lim_mgmt_regn->frameType = sme_req->frameType; + lim_mgmt_regn->matchLen = sme_req->matchLen; + lim_mgmt_regn->sessionId = sme_req->sessionId; + if (sme_req->matchLen) { + qdf_mem_copy(lim_mgmt_regn->matchData, + sme_req->matchData, + sme_req->matchLen); + } + qdf_mutex_acquire( + &mac_ctx->lim.lim_frame_register_lock); + qdf_list_insert_front(&mac_ctx->lim. + gLimMgmtFrameRegistratinQueue, + &lim_mgmt_regn->node); + qdf_mutex_release( + &mac_ctx->lim.lim_frame_register_lock); + } + } + return; +} + +static void __lim_deregister_deferred_sme_req_after_noa_start(tpAniSirGlobal pMac) +{ + lim_log(pMac, LOG1, FL("Dereg msgType %d"), + pMac->lim.gDeferMsgTypeForNOA); + pMac->lim.gDeferMsgTypeForNOA = 0; + if (pMac->lim.gpDefdSmeMsgForNOA != NULL) { + /* __lim_process_sme_scan_req consumed the buffer. We can free it. */ + qdf_mem_free(pMac->lim.gpDefdSmeMsgForNOA); + pMac->lim.gpDefdSmeMsgForNOA = NULL; + } +} + +/** + * lim_process_regd_defd_sme_req_after_noa_start() + * + * mac_ctx: Pointer to Global MAC structure + * + * This function is called to process deferred sme req message + * after noa start. + * + * Return: None + */ +void lim_process_regd_defd_sme_req_after_noa_start(tpAniSirGlobal mac_ctx) +{ + bool buf_consumed = true; + + lim_log(mac_ctx, LOG1, FL("Process defd sme req %d"), + mac_ctx->lim.gDeferMsgTypeForNOA); + + if ((mac_ctx->lim.gDeferMsgTypeForNOA == 0) || + (mac_ctx->lim.gpDefdSmeMsgForNOA == NULL)) { + lim_log(mac_ctx, LOGW, + FL("start rcvd from FW when no sme deferred msg pending. Do nothing. ")); + lim_log(mac_ctx, LOGW, + FL("It may happen when NOA start ind and timeout happen at the same time")); + return; + } + switch (mac_ctx->lim.gDeferMsgTypeForNOA) { + case eWNI_SME_SCAN_REQ: + __lim_process_sme_scan_req(mac_ctx, + mac_ctx->lim.gpDefdSmeMsgForNOA); + break; + case eWNI_SME_REMAIN_ON_CHANNEL_REQ: + buf_consumed = lim_process_remain_on_chnl_req(mac_ctx, + mac_ctx->lim.gpDefdSmeMsgForNOA); + /* + * lim_process_remain_on_chnl_req doesnt want us to free + * the buffer since it is freed in lim_remain_on_chn_rsp. + * this change is to avoid "double free" + */ + if (false == buf_consumed) + mac_ctx->lim.gpDefdSmeMsgForNOA = NULL; + break; + case eWNI_SME_JOIN_REQ: + __lim_process_sme_join_req(mac_ctx, + mac_ctx->lim.gpDefdSmeMsgForNOA); + break; + default: + lim_log(mac_ctx, LOGE, FL("Unknown deferred msg type %d"), + mac_ctx->lim.gDeferMsgTypeForNOA); + break; + } + __lim_deregister_deferred_sme_req_after_noa_start(mac_ctx); +} + +static void +__lim_process_sme_reset_ap_caps_change(tpAniSirGlobal pMac, uint32_t *pMsgBuf) +{ + tpSirResetAPCapsChange pResetCapsChange; + tpPESession psessionEntry; + uint8_t sessionId = 0; + if (pMsgBuf == NULL) { + lim_log(pMac, LOGE, FL("Buffer is Pointing to NULL")); + return; + } + + pResetCapsChange = (tpSirResetAPCapsChange) pMsgBuf; + psessionEntry = + pe_find_session_by_bssid(pMac, pResetCapsChange->bssId.bytes, + &sessionId); + if (psessionEntry == NULL) { + lim_log(pMac, LOGE, + FL("Session does not exist for given BSSID")); + return; + } + + psessionEntry->limSentCapsChangeNtf = false; + return; +} + +/** + * lim_register_p2p_ack_ind_cb() - Save the p2p ack indication callback. + * @mac_ctx: Mac pointer + * @msg_buf: Msg pointer containing the callback + * + * This function is used to save the p2p ack indication callback in PE. + * + * Return: None + */ +static void lim_register_p2p_ack_ind_cb(tpAniSirGlobal mac_ctx, + uint32_t *msg_buf) +{ + struct sir_sme_p2p_ack_ind_cb_req *sme_req = + (struct sir_sme_p2p_ack_ind_cb_req *)msg_buf; + + if (NULL == msg_buf) { + lim_log(mac_ctx, LOGE, FL("msg_buf is null")); + return; + } + if (sme_req->callback) + mac_ctx->p2p_ack_ind_cb = + sme_req->callback; + else + lim_log(mac_ctx, LOGE, FL("sme_req->callback is null")); +} + +/** + * lim_register_mgmt_frame_ind_cb() - Save the Management frame + * indication callback in PE. + * @mac_ptr: Mac pointer + * @msg_buf: Msg pointer containing the callback + * + * This function is used save the Management frame + * indication callback in PE. + * + * Return: None + */ +static void lim_register_mgmt_frame_ind_cb(tpAniSirGlobal mac_ctx, + uint32_t *msg_buf) +{ + struct sir_sme_mgmt_frame_cb_req *sme_req = + (struct sir_sme_mgmt_frame_cb_req *)msg_buf; + + if (NULL == msg_buf) { + lim_log(mac_ctx, LOGE, FL("msg_buf is null")); + return; + } + if (sme_req->callback) + mac_ctx->mgmt_frame_ind_cb = + (sir_mgmt_frame_ind_callback)sme_req->callback; + else + lim_log(mac_ctx, LOGE, FL("sme_req->callback is null")); +} + +/** + *__lim_process_send_disassoc_frame: function processes disassoc frame + * @mac_ctx: pointer to mac context + * @msg_buf: message buffer + * + * function processes disassoc request received from SME + * + * return: none + */ +static void __lim_process_send_disassoc_frame(tpAniSirGlobal mac_ctx, + uint32_t *msg_buf) +{ + struct sme_send_disassoc_frm_req sme_send_disassoc_frame_req; + tSirRetStatus status; + tpPESession session_entry = NULL; + uint8_t sme_session_id; + uint16_t sme_trans_id; + + if (msg_buf == NULL) { + lim_log(mac_ctx, LOGE, FL("Buffer is Pointing to NULL")); + return; + } + + lim_get_session_info(mac_ctx, (uint8_t *)msg_buf, &sme_session_id, + &sme_trans_id); + + status = lim_send_disassoc_frm_req_ser_des(mac_ctx, + &sme_send_disassoc_frame_req, + (uint8_t *)msg_buf); + + if ((eSIR_FAILURE == status) || + (lim_is_group_addr(sme_send_disassoc_frame_req.peer_mac) && + !lim_is_addr_bc(sme_send_disassoc_frame_req.peer_mac))) { + PELOGE(lim_log(mac_ctx, LOGE, + FL("received invalid SME_DISASSOC_REQ message"));) + return; + } + + session_entry = pe_find_session_by_sme_session_id( + mac_ctx, sme_session_id); + if (session_entry == NULL) { + lim_log(mac_ctx, LOGE, + FL("session does not exist for given bssId "MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(sme_send_disassoc_frame_req.peer_mac)); + return; + } + + lim_log(mac_ctx, LOG1, + FL("msg_type->%d len->%d sess_id->%d trans_id->%d mac->"MAC_ADDRESS_STR" reason->%d wait_for_ack->%d"), + sme_send_disassoc_frame_req.msg_type, + sme_send_disassoc_frame_req.length, + sme_send_disassoc_frame_req.session_id, + sme_send_disassoc_frame_req.trans_id, + MAC_ADDR_ARRAY(sme_send_disassoc_frame_req.peer_mac), + sme_send_disassoc_frame_req.reason, + sme_send_disassoc_frame_req.wait_for_ack); + + lim_send_disassoc_mgmt_frame(mac_ctx, + sme_send_disassoc_frame_req.reason, + sme_send_disassoc_frame_req.peer_mac, + session_entry, sme_send_disassoc_frame_req.wait_for_ack); +} + +/** + * lim_set_pdev_ht_ie() - sends the set HT IE req to FW + * @mac_ctx: Pointer to Global MAC structure + * @pdev_id: pdev id to set the IE. + * @nss: Nss values to prepare the HT IE. + * + * Prepares the HT IE with self capabilities for different + * Nss values and sends the set HT IE req to FW. + * + * Return: None + */ +static void lim_set_pdev_ht_ie(tpAniSirGlobal mac_ctx, uint8_t pdev_id, + uint8_t nss) +{ + struct set_ie_param *ie_params; + tSirMsgQ msg; + tSirRetStatus rc = eSIR_SUCCESS; + uint8_t *p_ie = NULL; + tHtCaps *p_ht_cap; + int i; + + for (i = 1; i <= nss; i++) { + ie_params = qdf_mem_malloc(sizeof(*ie_params)); + if (NULL == ie_params) { + lim_log(mac_ctx, LOGE, FL("mem alloc failed")); + return; + } + ie_params->nss = i; + ie_params->pdev_id = pdev_id; + ie_params->ie_type = DOT11_HT_IE; + /* 2 for IE len and EID */ + ie_params->ie_len = 2 + sizeof(tHtCaps); + ie_params->ie_ptr = qdf_mem_malloc(ie_params->ie_len); + if (NULL == ie_params->ie_ptr) { + qdf_mem_free(ie_params); + lim_log(mac_ctx, LOGE, FL("mem alloc failed")); + return; + } + *ie_params->ie_ptr = SIR_MAC_HT_CAPABILITIES_EID; + *(ie_params->ie_ptr + 1) = ie_params->ie_len - 2; + lim_set_ht_caps(mac_ctx, NULL, ie_params->ie_ptr, + ie_params->ie_len); + + if (NSS_1x1_MODE == i) { + p_ie = lim_get_ie_ptr_new(mac_ctx, ie_params->ie_ptr, + ie_params->ie_len, + DOT11F_EID_HTCAPS, ONE_BYTE); + if (NULL == p_ie) { + qdf_mem_free(ie_params->ie_ptr); + qdf_mem_free(ie_params); + lim_log(mac_ctx, LOGE, + FL("failed to get IE ptr")); + return; + } + p_ht_cap = (tHtCaps *)&p_ie[2]; + p_ht_cap->supportedMCSSet[1] = 0; + p_ht_cap->txSTBC = 0; + } + + msg.type = WMA_SET_PDEV_IE_REQ; + msg.bodyptr = ie_params; + msg.bodyval = 0; + + rc = wma_post_ctrl_msg(mac_ctx, &msg); + if (rc != eSIR_SUCCESS) { + lim_log(mac_ctx, LOGE, + FL("wma_post_ctrl_msg() return failure")); + qdf_mem_free(ie_params->ie_ptr); + qdf_mem_free(ie_params); + return; + } + } +} + +/** + * lim_set_pdev_vht_ie() - sends the set VHT IE to req FW + * @mac_ctx: Pointer to Global MAC structure + * @pdev_id: pdev id to set the IE. + * @nss: Nss values to prepare the VHT IE. + * + * Prepares the VHT IE with self capabilities for different + * Nss values and sends the set VHT IE req to FW. + * + * Return: None + */ +static void lim_set_pdev_vht_ie(tpAniSirGlobal mac_ctx, uint8_t pdev_id, + uint8_t nss) +{ + struct set_ie_param *ie_params; + tSirMsgQ msg; + tSirRetStatus rc = eSIR_SUCCESS; + uint8_t *p_ie = NULL; + tSirMacVHTCapabilityInfo *vht_cap; + int i; + tSirVhtMcsInfo *vht_mcs; + + for (i = 1; i <= nss; i++) { + ie_params = qdf_mem_malloc(sizeof(*ie_params)); + if (NULL == ie_params) { + lim_log(mac_ctx, LOGE, FL("mem alloc failed")); + return; + } + ie_params->nss = i; + ie_params->pdev_id = pdev_id; + ie_params->ie_type = DOT11_VHT_IE; + /* 2 for IE len and EID */ + ie_params->ie_len = 2 + sizeof(tSirMacVHTCapabilityInfo) + + sizeof(tSirVhtMcsInfo); + ie_params->ie_ptr = qdf_mem_malloc(ie_params->ie_len); + if (NULL == ie_params->ie_ptr) { + qdf_mem_free(ie_params); + lim_log(mac_ctx, LOGE, FL("mem alloc failed")); + return; + } + *ie_params->ie_ptr = SIR_MAC_VHT_CAPABILITIES_EID; + *(ie_params->ie_ptr + 1) = ie_params->ie_len - 2; + lim_set_vht_caps(mac_ctx, NULL, ie_params->ie_ptr, + ie_params->ie_len); + + if (NSS_1x1_MODE == i) { + p_ie = lim_get_ie_ptr_new(mac_ctx, ie_params->ie_ptr, + ie_params->ie_len, + DOT11F_EID_VHTCAPS, ONE_BYTE); + if (NULL == p_ie) { + qdf_mem_free(ie_params->ie_ptr); + qdf_mem_free(ie_params); + lim_log(mac_ctx, LOGE, + FL("failed to get IE ptr")); + return; + } + vht_cap = (tSirMacVHTCapabilityInfo *)&p_ie[2]; + vht_cap->txSTBC = 0; + vht_mcs = + (tSirVhtMcsInfo *)&p_ie[2 + + sizeof(tSirMacVHTCapabilityInfo)]; + vht_mcs->rxMcsMap |= DISABLE_NSS2_MCS; + vht_mcs->rxHighest = + VHT_RX_HIGHEST_SUPPORTED_DATA_RATE_1_1; + vht_mcs->txMcsMap |= DISABLE_NSS2_MCS; + vht_mcs->txHighest = + VHT_TX_HIGHEST_SUPPORTED_DATA_RATE_1_1; + } + msg.type = WMA_SET_PDEV_IE_REQ; + msg.bodyptr = ie_params; + msg.bodyval = 0; + + rc = wma_post_ctrl_msg(mac_ctx, &msg); + if (rc != eSIR_SUCCESS) { + lim_log(mac_ctx, LOGE, + FL("wma_post_ctrl_msg failure")); + qdf_mem_free(ie_params->ie_ptr); + qdf_mem_free(ie_params); + return; + } + } +} + +/** + * lim_process_set_vdev_ies_per_band() - process the set vdev IE req + * @mac_ctx: Pointer to Global MAC structure + * @msg_buf: Pointer to the SME message buffer + * + * This function is called by limProcessMessageQueue(). This function sets the + * VDEV IEs to the FW. + * + * Return: None + */ +static void lim_process_set_vdev_ies_per_band(tpAniSirGlobal mac_ctx, + uint32_t *msg_buf) +{ + struct sir_set_vdev_ies_per_band *p_msg = + (struct sir_set_vdev_ies_per_band *)msg_buf; + + if (NULL == p_msg) { + lim_log(mac_ctx, LOGE, FL("NULL p_msg")); + return; + } + + lim_log(mac_ctx, LOG1, FL("rcvd set vdev ie per band req vdev_id = %d"), + p_msg->vdev_id); + /* intentionally using NULL here so that self capabilty are sent */ + if (lim_send_ies_per_band(mac_ctx, NULL, p_msg->vdev_id) != + QDF_STATUS_SUCCESS) + lim_log(mac_ctx, LOGE, FL("Unable to send HT/VHT Cap to FW")); +} + +/** + * lim_process_set_pdev_IEs() - process the set pdev IE req + * @mac_ctx: Pointer to Global MAC structure + * @msg_buf: Pointer to the SME message buffer + * + * This function is called by limProcessMessageQueue(). This + * function sets the PDEV IEs to the FW. + * + * Return: None + */ +static void lim_process_set_pdev_IEs(tpAniSirGlobal mac_ctx, uint32_t *msg_buf) +{ + struct sir_set_ht_vht_cfg *ht_vht_cfg; + + ht_vht_cfg = (struct sir_set_ht_vht_cfg *)msg_buf; + + if (NULL == ht_vht_cfg) { + lim_log(mac_ctx, LOGE, FL("NULL ht_vht_cfg")); + return; + } + + lim_log(mac_ctx, LOG1, FL("rcvd set pdev ht vht ie req with nss = %d"), + ht_vht_cfg->nss); + lim_set_pdev_ht_ie(mac_ctx, ht_vht_cfg->pdev_id, ht_vht_cfg->nss); + + if (IS_DOT11_MODE_VHT(ht_vht_cfg->dot11mode)) + lim_set_pdev_vht_ie(mac_ctx, ht_vht_cfg->pdev_id, + ht_vht_cfg->nss); +} + +/** + * lim_process_sme_update_access_policy_vendor_ie: function updates vendor IE + * + * access policy + * @mac_ctx: pointer to mac context + * @msg: message buffer + * + * function processes vendor IE and access policy from SME and updates PE + * + * session entry + * + * return: none +*/ +static void lim_process_sme_update_access_policy_vendor_ie( + tpAniSirGlobal mac_ctx, + uint32_t *msg) +{ + struct sme_update_access_policy_vendor_ie *update_vendor_ie; + struct sPESession *pe_session_entry; + uint8_t num_bytes; + + if (!msg) { + lim_log(mac_ctx, LOGE, FL("Buffer is Pointing to NULL")); + return; + } + update_vendor_ie = (struct sme_update_access_policy_vendor_ie *) msg; + pe_session_entry = pe_find_session_by_sme_session_id(mac_ctx, + update_vendor_ie->sme_session_id); + + if (!pe_session_entry) { + lim_log(mac_ctx, LOGE, + FL("Session does not exist for given sme session id(%hu)"), + update_vendor_ie->sme_session_id); + return; + } + if (pe_session_entry->access_policy_vendor_ie) + qdf_mem_free(pe_session_entry->access_policy_vendor_ie); + + num_bytes = update_vendor_ie->ie[1] + 2; + pe_session_entry->access_policy_vendor_ie = qdf_mem_malloc(num_bytes); + + if (!pe_session_entry->access_policy_vendor_ie) { + lim_log(mac_ctx, LOGE, + FL("Failed to allocate memory for vendor ie")); + return; + } + qdf_mem_copy(pe_session_entry->access_policy_vendor_ie, + &update_vendor_ie->ie[0], num_bytes); + + pe_session_entry->access_policy = update_vendor_ie->access_policy; +} + +/** + * lim_process_sme_req_messages() + * + ***FUNCTION: + * This function is called by limProcessMessageQueue(). This + * function processes SME request messages from HDD or upper layer + * application. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param pMac Pointer to Global MAC structure + * @param msgType Indicates the SME message type + * @param *pMsgBuf A pointer to the SME message buffer + * @return Boolean - true - if pMsgBuf is consumed and can be freed. + * false - if pMsgBuf is not to be freed. + */ + +bool lim_process_sme_req_messages(tpAniSirGlobal pMac, tpSirMsgQ pMsg) +{ + bool bufConsumed = true; /* Set this flag to false within case block of any following message, that doesnt want pMsgBuf to be freed. */ + uint32_t *pMsgBuf = pMsg->bodyptr; + tpSirSmeScanReq pScanReq; + PELOG1(lim_log + (pMac, LOG1, + FL + ("LIM Received SME Message %s(%d) Global LimSmeState:%s(%d) Global LimMlmState: %s(%d)"), + lim_msg_str(pMsg->type), pMsg->type, + lim_sme_state_str(pMac->lim.gLimSmeState), pMac->lim.gLimSmeState, + lim_mlm_state_str(pMac->lim.gLimMlmState), pMac->lim.gLimMlmState); + ) + + pScanReq = (tpSirSmeScanReq) pMsgBuf; + /* If no insert NOA required then execute the code below */ + + switch (pMsg->type) { + case eWNI_SME_SYS_READY_IND: + bufConsumed = __lim_process_sme_sys_ready_ind(pMac, pMsgBuf); + break; + + case eWNI_SME_START_BSS_REQ: + bufConsumed = __lim_process_sme_start_bss_req(pMac, pMsg); + break; + + case eWNI_SME_SCAN_REQ: + __lim_process_sme_scan_req(pMac, pMsgBuf); + break; + + case eWNI_SME_REMAIN_ON_CHANNEL_REQ: + bufConsumed = lim_process_remain_on_chnl_req(pMac, pMsgBuf); + break; + + case eWNI_SME_UPDATE_NOA: + __lim_process_sme_no_a_update(pMac, pMsgBuf); + break; + case eWNI_SME_CLEAR_DFS_CHANNEL_LIST: + __lim_process_clear_dfs_channel_list(pMac, pMsg); + break; + case eWNI_SME_JOIN_REQ: + __lim_process_sme_join_req(pMac, pMsgBuf); + break; + + case eWNI_SME_REASSOC_REQ: + __lim_process_sme_reassoc_req(pMac, pMsgBuf); + break; + + case eWNI_SME_DISASSOC_REQ: + __lim_process_sme_disassoc_req(pMac, pMsgBuf); + break; + + case eWNI_SME_DISASSOC_CNF: + case eWNI_SME_DEAUTH_CNF: + __lim_process_sme_disassoc_cnf(pMac, pMsgBuf); + break; + + case eWNI_SME_DEAUTH_REQ: + __lim_process_sme_deauth_req(pMac, pMsgBuf); + break; + + case eWNI_SME_SEND_DISASSOC_FRAME: + __lim_process_send_disassoc_frame(pMac, pMsgBuf); + break; + + case eWNI_SME_SETCONTEXT_REQ: + __lim_process_sme_set_context_req(pMac, pMsgBuf); + break; + + case eWNI_SME_STOP_BSS_REQ: + bufConsumed = __lim_process_sme_stop_bss_req(pMac, pMsg); + break; + + case eWNI_SME_ASSOC_CNF: + if (pMsg->type == eWNI_SME_ASSOC_CNF) + PELOG1(lim_log(pMac, + LOG1, FL("Received ASSOC_CNF message"));) + __lim_process_sme_assoc_cnf_new(pMac, pMsg->type, + pMsgBuf); + break; + + case eWNI_SME_ADDTS_REQ: + PELOG1(lim_log(pMac, LOG1, FL("Received ADDTS_REQ message"));) + __lim_process_sme_addts_req(pMac, pMsgBuf); + break; + + case eWNI_SME_DELTS_REQ: + PELOG1(lim_log(pMac, LOG1, FL("Received DELTS_REQ message"));) + __lim_process_sme_delts_req(pMac, pMsgBuf); + break; + + case SIR_LIM_ADDTS_RSP_TIMEOUT: + PELOG1(lim_log + (pMac, LOG1, + FL("Received SIR_LIM_ADDTS_RSP_TIMEOUT message ")); + ) + lim_process_sme_addts_rsp_timeout(pMac, pMsg->bodyval); + break; + + case eWNI_SME_GET_STATISTICS_REQ: + __lim_process_sme_get_statistics_request(pMac, pMsgBuf); + /* HAL consumes pMsgBuf. It will be freed there. Set bufConsumed to false. */ + bufConsumed = false; + break; +#ifdef FEATURE_WLAN_ESE + case eWNI_SME_GET_TSM_STATS_REQ: + __lim_process_sme_get_tsm_stats_request(pMac, pMsgBuf); + bufConsumed = false; + break; +#endif /* FEATURE_WLAN_ESE */ + case eWNI_SME_GET_ASSOC_STAS_REQ: + lim_process_sme_get_assoc_sta_info(pMac, pMsgBuf); + break; + case eWNI_SME_TKIP_CNTR_MEAS_REQ: + lim_process_tkip_counter_measures(pMac, pMsgBuf); + break; + + case eWNI_SME_SESSION_UPDATE_PARAM: + __lim_process_sme_session_update(pMac, pMsgBuf); + break; + case eWNI_SME_ROAM_SCAN_OFFLOAD_REQ: + __lim_process_roam_scan_offload_req(pMac, pMsgBuf); + bufConsumed = false; + break; + case eWNI_SME_UPDATE_APWPSIE_REQ: + __lim_process_sme_update_apwpsi_es(pMac, pMsgBuf); + break; + case eWNI_SME_GET_WPSPBC_SESSION_REQ: + lim_process_sme_get_wpspbc_sessions(pMac, pMsgBuf); + break; + + case eWNI_SME_SET_APWPARSNIEs_REQ: + __lim_process_sme_set_wparsni_es(pMac, pMsgBuf); + break; + + case eWNI_SME_CHNG_MCC_BEACON_INTERVAL: + /* Update the beaconInterval */ + __lim_process_sme_change_bi(pMac, pMsgBuf); + break; + +#ifdef QCA_HT_2040_COEX + case eWNI_SME_SET_HT_2040_MODE: + __lim_process_sme_set_ht2040_mode(pMac, pMsgBuf); + break; +#endif + + case eWNI_SME_NEIGHBOR_REPORT_REQ_IND: + case eWNI_SME_BEACON_REPORT_RESP_XMIT_IND: + __lim_process_report_message(pMac, pMsg); + break; + + case eWNI_SME_FT_PRE_AUTH_REQ: + bufConsumed = (bool) lim_process_ft_pre_auth_req(pMac, pMsg); + break; + case eWNI_SME_FT_UPDATE_KEY: + lim_process_ft_update_key(pMac, pMsgBuf); + break; + + case eWNI_SME_FT_AGGR_QOS_REQ: + lim_process_ft_aggr_qos_req(pMac, pMsgBuf); + break; + + case eWNI_SME_REGISTER_MGMT_FRAME_REQ: + __lim_process_sme_register_mgmt_frame_req(pMac, pMsgBuf); + break; +#ifdef FEATURE_WLAN_TDLS + case eWNI_SME_TDLS_SEND_MGMT_REQ: + lim_process_sme_tdls_mgmt_send_req(pMac, pMsgBuf); + break; + case eWNI_SME_TDLS_ADD_STA_REQ: + lim_process_sme_tdls_add_sta_req(pMac, pMsgBuf); + break; + case eWNI_SME_TDLS_DEL_STA_REQ: + lim_process_sme_tdls_del_sta_req(pMac, pMsgBuf); + break; + case eWNI_SME_TDLS_LINK_ESTABLISH_REQ: + lim_process_sme_tdls_link_establish_req(pMac, pMsgBuf); + break; +#endif + case eWNI_SME_RESET_AP_CAPS_CHANGED: + __lim_process_sme_reset_ap_caps_change(pMac, pMsgBuf); + break; + + case eWNI_SME_CHANNEL_CHANGE_REQ: + lim_process_sme_channel_change_request(pMac, pMsgBuf); + break; + + case eWNI_SME_START_BEACON_REQ: + lim_process_sme_start_beacon_req(pMac, pMsgBuf); + break; + + case eWNI_SME_DFS_BEACON_CHAN_SW_IE_REQ: + lim_process_sme_dfs_csa_ie_request(pMac, pMsgBuf); + break; + + case eWNI_SME_UPDATE_ADDITIONAL_IES: + lim_process_update_add_ies(pMac, pMsgBuf); + break; + + case eWNI_SME_MODIFY_ADDITIONAL_IES: + lim_process_modify_add_ies(pMac, pMsgBuf); + break; + case eWNI_SME_SET_HW_MODE_REQ: + lim_process_set_hw_mode(pMac, pMsgBuf); + break; + case eWNI_SME_NSS_UPDATE_REQ: + lim_process_nss_update_request(pMac, pMsgBuf); + break; + case eWNI_SME_SET_DUAL_MAC_CFG_REQ: + lim_process_set_dual_mac_cfg_req(pMac, pMsgBuf); + break; + case eWNI_SME_SET_IE_REQ: + lim_process_set_ie_req(pMac, pMsgBuf); + break; + case eWNI_SME_REGISTER_MGMT_FRAME_CB: + lim_register_mgmt_frame_ind_cb(pMac, pMsgBuf); + break; + case eWNI_SME_EXT_CHANGE_CHANNEL: + lim_process_ext_change_channel(pMac, pMsgBuf); + break; + case eWNI_SME_SET_ANTENNA_MODE_REQ: + lim_process_set_antenna_mode_req(pMac, pMsgBuf); + break; + case eWNI_SME_PDEV_SET_HT_VHT_IE: + lim_process_set_pdev_IEs(pMac, pMsgBuf); + break; + case eWNI_SME_SET_VDEV_IES_PER_BAND: + lim_process_set_vdev_ies_per_band(pMac, pMsgBuf); + break; + case eWNI_SME_NDP_END_REQ: + case eWNI_SME_NDP_INITIATOR_REQ: + case eWNI_SME_NDP_RESPONDER_REQ: + lim_handle_ndp_request_message(pMac, pMsg); + break; + case eWNI_SME_REGISTER_P2P_ACK_CB: + lim_register_p2p_ack_ind_cb(pMac, pMsgBuf); + break; + case eWNI_SME_UPDATE_ACCESS_POLICY_VENDOR_IE: + lim_process_sme_update_access_policy_vendor_ie(pMac, pMsgBuf); + break; + case eWNI_SME_UPDATE_CONFIG: + lim_process_sme_update_config(pMac, + (struct update_config *)pMsgBuf); + break; + default: + qdf_mem_free((void *)pMsg->bodyptr); + pMsg->bodyptr = NULL; + break; + } /* switch (msgType) */ + + return bufConsumed; +} /*** end lim_process_sme_req_messages() ***/ + +/** + * lim_process_sme_start_beacon_req() + * + ***FUNCTION: + * This function is called by limProcessMessageQueue(). This + * function processes SME request messages from HDD or upper layer + * application. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param pMac Pointer to Global MAC structure + * @param msgType Indicates the SME message type + * @param *pMsgBuf A pointer to the SME message buffer + * @return Boolean - true - if pMsgBuf is consumed and can be freed. + * false - if pMsgBuf is not to be freed. + */ +static void lim_process_sme_start_beacon_req(tpAniSirGlobal pMac, uint32_t *pMsg) +{ + tpSirStartBeaconIndication pBeaconStartInd; + tpPESession psessionEntry; + uint8_t sessionId; /* PE sessionID */ + + if (pMsg == NULL) { + lim_log(pMac, LOGE, FL("Buffer is Pointing to NULL")); + return; + } + + pBeaconStartInd = (tpSirStartBeaconIndication) pMsg; + psessionEntry = pe_find_session_by_bssid(pMac, + pBeaconStartInd->bssid, + &sessionId); + if (psessionEntry == NULL) { + lim_print_mac_addr(pMac, pBeaconStartInd->bssid, LOGE); + lim_log(pMac, LOGE, + FL("Session does not exist for given bssId")); + return; + } + + if (pBeaconStartInd->beaconStartStatus == true) { + /* + * Currently this Indication comes from SAP + * to start Beacon Tx on a DFS channel + * since beaconing has to be done on DFS + * channel only after CAC WAIT is completed. + * On a DFS Channel LIM does not start beacon + * Tx right after the WMA_ADD_BSS_RSP. + */ + lim_apply_configuration(pMac, psessionEntry); + QDF_TRACE(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_INFO, + FL("Start Beacon with ssid %s Ch %d"), + psessionEntry->ssId.ssId, + psessionEntry->currentOperChannel); + lim_send_beacon_ind(pMac, psessionEntry); + } else { + lim_log(pMac, LOGE, FL("Invalid Beacon Start Indication")); + return; + } +} + +/** + * lim_process_sme_channel_change_request() - process sme ch change req + * + * @mac_ctx: Pointer to Global MAC structure + * @msg_buf: pointer to the SME message buffer + * + * This function is called to process SME_CHANNEL_CHANGE_REQ message + * + * Return: None + */ +static void lim_process_sme_channel_change_request(tpAniSirGlobal mac_ctx, + uint32_t *msg_buf) +{ + tpSirChanChangeRequest ch_change_req; + tpPESession session_entry; + uint8_t session_id; /* PE session_id */ + int8_t max_tx_pwr; + uint32_t val = 0; + + if (msg_buf == NULL) { + lim_log(mac_ctx, LOGE, FL("msg_buf is NULL")); + return; + } + ch_change_req = (tpSirChanChangeRequest)msg_buf; + + max_tx_pwr = cfg_get_regulatory_max_transmit_power(mac_ctx, + ch_change_req->targetChannel); + + if ((ch_change_req->messageType != eWNI_SME_CHANNEL_CHANGE_REQ) || + (max_tx_pwr == WMA_MAX_TXPOWER_INVALID)) { + lim_log(mac_ctx, LOGE, FL("Invalid Request/max_tx_pwr")); + return; + } + + session_entry = pe_find_session_by_bssid(mac_ctx, + ch_change_req->bssid, &session_id); + if (session_entry == NULL) { + lim_print_mac_addr(mac_ctx, ch_change_req->bssid, LOGE); + lim_log(mac_ctx, LOGE, FL( + "Session does not exist for given bssId")); + return; + } + + if (session_entry->currentOperChannel == + ch_change_req->targetChannel) { + lim_log(mac_ctx, LOGE, FL("target CH is same as current CH")); + return; + } + + if (LIM_IS_AP_ROLE(session_entry)) + session_entry->channelChangeReasonCode = + LIM_SWITCH_CHANNEL_SAP_DFS; + else + session_entry->channelChangeReasonCode = + LIM_SWITCH_CHANNEL_OPERATION; + + lim_log(mac_ctx, LOGW, FL( + "switch old chnl %d to new chnl %d, ch_bw %d"), + session_entry->currentOperChannel, + ch_change_req->targetChannel, + ch_change_req->ch_width); + + /* Store the New Channel Params in session_entry */ + session_entry->ch_width = ch_change_req->ch_width; + session_entry->ch_center_freq_seg0 = + ch_change_req->center_freq_seg_0; + session_entry->ch_center_freq_seg1 = + ch_change_req->center_freq_seg_1; + session_entry->htSecondaryChannelOffset = ch_change_req->sec_ch_offset; + session_entry->htSupportedChannelWidthSet = + (ch_change_req->ch_width ? 1 : 0); + session_entry->htRecommendedTxWidthSet = + session_entry->htSupportedChannelWidthSet; + session_entry->currentOperChannel = + ch_change_req->targetChannel; + session_entry->limRFBand = + lim_get_rf_band(session_entry->currentOperChannel); + /* Initialize 11h Enable Flag */ + if (SIR_BAND_5_GHZ == session_entry->limRFBand) { + if (wlan_cfg_get_int(mac_ctx, WNI_CFG_11H_ENABLED, &val) != + eSIR_SUCCESS) + lim_log(mac_ctx, LOGP, + FL("Fail to get WNI_CFG_11H_ENABLED")); + } + + session_entry->lim11hEnable = val; + session_entry->dot11mode = ch_change_req->dot11mode; + qdf_mem_copy(&session_entry->rateSet, + &ch_change_req->operational_rateset, + sizeof(session_entry->rateSet)); + qdf_mem_copy(&session_entry->extRateSet, + &ch_change_req->extended_rateset, + sizeof(session_entry->extRateSet)); + lim_set_channel(mac_ctx, ch_change_req->targetChannel, + session_entry->ch_center_freq_seg0, + session_entry->ch_center_freq_seg1, + session_entry->ch_width, + max_tx_pwr, session_entry->peSessionId); +} + +/****************************************************************************** +* lim_start_bss_update_add_ie_buffer() +* +***FUNCTION: +* This function checks the src buffer and its length and then malloc for +* dst buffer update the same +* +***LOGIC: +* +***ASSUMPTIONS: +* +***NOTE: +* +* @param pMac Pointer to Global MAC structure +* @param **pDstData_buff A pointer to pointer of uint8_t dst buffer +* @param *pDstDataLen A pointer to pointer of uint16_t dst buffer length +* @param *pSrcData_buff A pointer of uint8_t src buffer +* @param srcDataLen src buffer length +******************************************************************************/ + +static void +lim_start_bss_update_add_ie_buffer(tpAniSirGlobal pMac, + uint8_t **pDstData_buff, + uint16_t *pDstDataLen, + uint8_t *pSrcData_buff, uint16_t srcDataLen) +{ + + if (srcDataLen > 0 && pSrcData_buff != NULL) { + *pDstDataLen = srcDataLen; + + *pDstData_buff = qdf_mem_malloc(*pDstDataLen); + + if (NULL == *pDstData_buff) { + lim_log(pMac, LOGE, + FL("AllocateMemory failed for pDstData_buff")); + return; + } + qdf_mem_copy(*pDstData_buff, pSrcData_buff, *pDstDataLen); + } else { + *pDstData_buff = NULL; + *pDstDataLen = 0; + } +} + +/****************************************************************************** +* lim_update_add_ie_buffer() +* +***FUNCTION: +* This function checks the src buffer and length if src buffer length more +* than dst buffer length then free the dst buffer and malloc for the new src +* length, and update the dst buffer and length. But if dst buffer is bigger +* than src buffer length then it just update the dst buffer and length +* +***LOGIC: +* +***ASSUMPTIONS: +* +***NOTE: +* +* @param pMac Pointer to Global MAC structure +* @param **pDstData_buff A pointer to pointer of uint8_t dst buffer +* @param *pDstDataLen A pointer to pointer of uint16_t dst buffer length +* @param *pSrcData_buff A pointer of uint8_t src buffer +* @param srcDataLen src buffer length +******************************************************************************/ + +static void +lim_update_add_ie_buffer(tpAniSirGlobal pMac, + uint8_t **pDstData_buff, + uint16_t *pDstDataLen, + uint8_t *pSrcData_buff, uint16_t srcDataLen) +{ + + if (NULL == pSrcData_buff) { + lim_log(pMac, LOGE, FL("src buffer is null.")); + return; + } + + if (srcDataLen > *pDstDataLen) { + *pDstDataLen = srcDataLen; + /* free old buffer */ + qdf_mem_free(*pDstData_buff); + /* allocate a new */ + *pDstData_buff = qdf_mem_malloc(*pDstDataLen); + + if (NULL == *pDstData_buff) { + lim_log(pMac, LOGE, FL("Memory allocation failed.")); + *pDstDataLen = 0; + return; + } + } + + /* copy the content of buffer into dst buffer + */ + *pDstDataLen = srcDataLen; + qdf_mem_copy(*pDstData_buff, pSrcData_buff, *pDstDataLen); + +} + +/** + * lim_update_ibss_prop_add_ies() - update IBSS prop IE + * @pMac : Pointer to Global MAC structure + * @pDstData_buff : A pointer to pointer of dst buffer + * @pDstDataLen : A pointer to pointer of dst buffer length + * @pModifyIE : A pointer to tSirModifyIE + * + * This function replaces previous ibss prop_ie with new ibss prop_ie. + * + * Return: + * True or false depending upon whether IE is updated or not + */ +static bool +lim_update_ibss_prop_add_ies(tpAniSirGlobal pMac, uint8_t **pDstData_buff, + uint16_t *pDstDataLen, tSirModifyIE *pModifyIE) +{ + int32_t oui_length; + uint8_t *ibss_ie = NULL; + uint8_t *vendor_ie; +#define MAC_VENDOR_OUI "\x00\x16\x32" +#define MAC_VENDOR_SIZE 3 + + ibss_ie = pModifyIE->pIEBuffer; + oui_length = pModifyIE->oui_length; + + if ((0 == oui_length) || (NULL == ibss_ie)) { + PELOGE(lim_log(pMac, LOGE, + FL("Invalid set IBSS vendor IE command length %d "), + oui_length);) + return false; + } + + /* + * Why replace only beacon OUI data here: + * 1. other ie (such as wpa) shall not be overwritten here. + * 2. per spec, beacon oui ie might be set twice and original one + * shall be updated. + */ + vendor_ie = cfg_get_vendor_ie_ptr_from_oui(pMac, MAC_VENDOR_OUI, + MAC_VENDOR_SIZE, *pDstData_buff, *pDstDataLen); + if (vendor_ie) { + QDF_ASSERT((vendor_ie[1] + 2) == pModifyIE->ieBufferlength); + qdf_mem_copy(vendor_ie, pModifyIE->pIEBuffer, + pModifyIE->ieBufferlength); + } else { + uint16_t new_length = pModifyIE->ieBufferlength + *pDstDataLen; + uint8_t *new_ptr = qdf_mem_malloc(new_length); + + if (NULL == new_ptr) { + lim_log(pMac, LOGE, FL("Memory allocation failed.")); + return false; + } + qdf_mem_copy(new_ptr, *pDstData_buff, *pDstDataLen); + qdf_mem_copy(&new_ptr[*pDstDataLen], pModifyIE->pIEBuffer, + pModifyIE->ieBufferlength); + qdf_mem_free(*pDstData_buff); + *pDstDataLen = new_length; + *pDstData_buff = new_ptr; + } + return true; +} + +/* +* lim_process_modify_add_ies() - process modify additional IE req. +* +* @mac_ctx: Pointer to Global MAC structure +* @msg_buf: pointer to the SME message buffer +* +* This function update the PE buffers for additional IEs. +* +* Return: None +*/ +static void lim_process_modify_add_ies(tpAniSirGlobal mac_ctx, + uint32_t *msg_buf) +{ + tpSirModifyIEsInd modify_add_ies; + tpPESession session_entry; + uint8_t session_id; + bool ret = false; + tSirAddIeParams *add_ie_params; + + if (msg_buf == NULL) { + lim_log(mac_ctx, LOGE, FL("msg_buf is NULL")); + return; + } + + modify_add_ies = (tpSirModifyIEsInd)msg_buf; + /* Incoming message has smeSession, use BSSID to find PE session */ + session_entry = pe_find_session_by_bssid(mac_ctx, + modify_add_ies->modifyIE.bssid.bytes, &session_id); + + if (NULL == session_entry) { + lim_log(mac_ctx, LOGE, FL("Session not found for given bssid. " + MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(modify_add_ies->modifyIE.bssid.bytes)); + goto end; + } + if ((0 == modify_add_ies->modifyIE.ieBufferlength) || + (0 == modify_add_ies->modifyIE.ieIDLen) || + (NULL == modify_add_ies->modifyIE.pIEBuffer)) { + lim_log(mac_ctx, LOGE, + FL("Invalid request pIEBuffer %p ieBufferlength %d ieIDLen %d ieID %d. update Type %d"), + modify_add_ies->modifyIE.pIEBuffer, + modify_add_ies->modifyIE.ieBufferlength, + modify_add_ies->modifyIE.ieID, + modify_add_ies->modifyIE.ieIDLen, + modify_add_ies->updateType); + goto end; + } + add_ie_params = &session_entry->addIeParams; + switch (modify_add_ies->updateType) { + case eUPDATE_IE_PROBE_RESP: + /* Probe resp */ + if (LIM_IS_IBSS_ROLE(session_entry)) { + lim_update_ibss_prop_add_ies(mac_ctx, + &add_ie_params->probeRespData_buff, + &add_ie_params->probeRespDataLen, + &modify_add_ies->modifyIE); + } + break; + case eUPDATE_IE_ASSOC_RESP: + /* assoc resp IE */ + if (add_ie_params->assocRespDataLen == 0) { + QDF_TRACE(QDF_MODULE_ID_PE, + QDF_TRACE_LEVEL_ERROR, FL( + "assoc resp add ie not present %d"), + add_ie_params->assocRespDataLen); + } + /* search through the buffer and modify the IE */ + break; + case eUPDATE_IE_PROBE_BCN: + /*probe beacon IE */ + if (LIM_IS_IBSS_ROLE(session_entry)) { + ret = lim_update_ibss_prop_add_ies(mac_ctx, + &add_ie_params->probeRespBCNData_buff, + &add_ie_params->probeRespBCNDataLen, + &modify_add_ies->modifyIE); + } + if (ret == true && modify_add_ies->modifyIE.notify) { + lim_handle_param_update(mac_ctx, + modify_add_ies->updateType); + } + break; + default: + lim_log(mac_ctx, LOGE, FL("unhandled buffer type %d"), + modify_add_ies->updateType); + break; + } +end: + qdf_mem_free(modify_add_ies->modifyIE.pIEBuffer); + modify_add_ies->modifyIE.pIEBuffer = NULL; +} + +/* +* lim_process_update_add_ies() - process additional IE update req +* +* @mac_ctx: Pointer to Global MAC structure +* @msg_buf: pointer to the SME message buffer +* +* This function update the PE buffers for additional IEs. +* +* Return: None +*/ +static void lim_process_update_add_ies(tpAniSirGlobal mac_ctx, + uint32_t *msg_buf) +{ + tpSirUpdateIEsInd update_add_ies = (tpSirUpdateIEsInd)msg_buf; + uint8_t session_id; + tpPESession session_entry; + tSirAddIeParams *addn_ie; + uint16_t new_length = 0; + uint8_t *new_ptr = NULL; + tSirUpdateIE *update_ie; + + if (msg_buf == NULL) { + lim_log(mac_ctx, LOGE, FL("msg_buf is NULL")); + return; + } + update_ie = &update_add_ies->updateIE; + /* incoming message has smeSession, use BSSID to find PE session */ + session_entry = pe_find_session_by_bssid(mac_ctx, + update_ie->bssid.bytes, &session_id); + + if (NULL == session_entry) { + lim_log(mac_ctx, LOGE, FL("Session not found for given bssid. " + MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(update_ie->bssid.bytes)); + goto end; + } + addn_ie = &session_entry->addIeParams; + /* if len is 0, upper layer requested freeing of buffer */ + if (0 == update_ie->ieBufferlength) { + switch (update_add_ies->updateType) { + case eUPDATE_IE_PROBE_RESP: + qdf_mem_free(addn_ie->probeRespData_buff); + addn_ie->probeRespData_buff = NULL; + addn_ie->probeRespDataLen = 0; + break; + case eUPDATE_IE_ASSOC_RESP: + qdf_mem_free(addn_ie->assocRespData_buff); + addn_ie->assocRespData_buff = NULL; + addn_ie->assocRespDataLen = 0; + break; + case eUPDATE_IE_PROBE_BCN: + qdf_mem_free(addn_ie->probeRespBCNData_buff); + addn_ie->probeRespBCNData_buff = NULL; + addn_ie->probeRespBCNDataLen = 0; + + if (update_ie->notify) + lim_handle_param_update(mac_ctx, + update_add_ies->updateType); + break; + default: + break; + } + return; + } + switch (update_add_ies->updateType) { + case eUPDATE_IE_PROBE_RESP: + if (update_ie->append) { + /* + * In case of append, allocate new memory + * with combined length + */ + new_length = update_ie->ieBufferlength + + addn_ie->probeRespDataLen; + new_ptr = qdf_mem_malloc(new_length); + if (NULL == new_ptr) { + lim_log(mac_ctx, LOGE, FL( + "Memory allocation failed.")); + goto end; + } + /* append buffer to end of local buffers */ + qdf_mem_copy(new_ptr, addn_ie->probeRespData_buff, + addn_ie->probeRespDataLen); + qdf_mem_copy(&new_ptr[addn_ie->probeRespDataLen], + update_ie->pAdditionIEBuffer, + update_ie->ieBufferlength); + /* free old memory */ + qdf_mem_free(addn_ie->probeRespData_buff); + /* adjust length accordingly */ + addn_ie->probeRespDataLen = new_length; + /* save refernece of local buffer in PE session */ + addn_ie->probeRespData_buff = new_ptr; + goto end; + } + lim_update_add_ie_buffer(mac_ctx, &addn_ie->probeRespData_buff, + &addn_ie->probeRespDataLen, + update_ie->pAdditionIEBuffer, + update_ie->ieBufferlength); + break; + case eUPDATE_IE_ASSOC_RESP: + /* assoc resp IE */ + lim_update_add_ie_buffer(mac_ctx, &addn_ie->assocRespData_buff, + &addn_ie->assocRespDataLen, + update_ie->pAdditionIEBuffer, + update_ie->ieBufferlength); + break; + case eUPDATE_IE_PROBE_BCN: + /* probe resp Bcn IE */ + lim_update_add_ie_buffer(mac_ctx, + &addn_ie->probeRespBCNData_buff, + &addn_ie->probeRespBCNDataLen, + update_ie->pAdditionIEBuffer, + update_ie->ieBufferlength); + if (update_ie->notify) + lim_handle_param_update(mac_ctx, + update_add_ies->updateType); + break; + default: + lim_log(mac_ctx, LOGE, FL("unhandled buffer type %d."), + update_add_ies->updateType); + break; + } +end: + qdf_mem_free(update_ie->pAdditionIEBuffer); + update_ie->pAdditionIEBuffer = NULL; +} + +/** + * send_extended_chan_switch_action_frame()- function to send ECSA + * action frame for each sta connected to SAP/GO and AP in case of + * STA . + * @mac_ctx: pointer to global mac structure + * @new_channel: new channel to switch to. + * @ch_bandwidth: BW of channel to calculate op_class + * @session_entry: pe session + * + * This function is called to send ECSA frame for STA/CLI and SAP/GO. + * + * Return: void + */ + +static void send_extended_chan_switch_action_frame(tpAniSirGlobal mac_ctx, + uint16_t new_channel, uint8_t ch_bandwidth, + tpPESession session_entry) +{ + uint16_t op_class; + uint8_t switch_mode = 0, i; + tpDphHashNode psta; + + + op_class = cds_reg_dmn_get_opclass_from_channel( + mac_ctx->scan.countryCodeCurrent, + new_channel, + ch_bandwidth); + + if (LIM_IS_AP_ROLE(session_entry) && + (mac_ctx->sap.SapDfsInfo.disable_dfs_ch_switch == false)) + switch_mode = 1; + + if (LIM_IS_AP_ROLE(session_entry)) { + for (i = 0; i < mac_ctx->lim.maxStation; i++) { + psta = + session_entry->dph.dphHashTable.pDphNodeArray + i; + if (psta && psta->added) + lim_send_extended_chan_switch_action_frame( + mac_ctx, + psta->staAddr, + switch_mode, op_class, new_channel, + LIM_MAX_CSA_IE_UPDATES, session_entry); + } + } else if (LIM_IS_STA_ROLE(session_entry)) { + lim_send_extended_chan_switch_action_frame(mac_ctx, + session_entry->bssId, + switch_mode, op_class, new_channel, + LIM_MAX_CSA_IE_UPDATES, session_entry); + } + +} + +/** + * lim_process_sme_dfs_csa_ie_request() - process sme dfs csa ie req + * + * @mac_ctx: Pointer to Global MAC structure + * @msg_buf: pointer to the SME message buffer + * + * This function processes SME request messages from HDD or upper layer + * application. + * + * Return: None + */ +static void lim_process_sme_dfs_csa_ie_request(tpAniSirGlobal mac_ctx, + uint32_t *msg_buf) +{ + tpSirDfsCsaIeRequest dfs_csa_ie_req; + tpPESession session_entry = NULL; + uint8_t session_id; + tLimWiderBWChannelSwitchInfo *wider_bw_ch_switch; + enum offset_t ch_offset; + + if (msg_buf == NULL) { + lim_log(mac_ctx, LOGE, FL("Buffer is Pointing to NULL")); + return; + } + + dfs_csa_ie_req = (tSirDfsCsaIeRequest *)msg_buf; + session_entry = pe_find_session_by_bssid(mac_ctx, + dfs_csa_ie_req->bssid, &session_id); + if (session_entry == NULL) { + lim_log(mac_ctx, LOGE, FL( + "Session not found for given BSSID" MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(dfs_csa_ie_req->bssid)); + return; + } + + if (session_entry->valid && !LIM_IS_AP_ROLE(session_entry)) { + lim_log(mac_ctx, LOGE, FL("Invalid SystemRole %d"), + GET_LIM_SYSTEM_ROLE(session_entry)); + return; + } + + /* target channel */ + session_entry->gLimChannelSwitch.primaryChannel = + dfs_csa_ie_req->targetChannel; + + /* Channel switch announcement needs to be included in beacon */ + session_entry->dfsIncludeChanSwIe = true; + session_entry->gLimChannelSwitch.switchCount = LIM_MAX_CSA_IE_UPDATES; + session_entry->gLimChannelSwitch.ch_width = + dfs_csa_ie_req->ch_params.ch_width; + session_entry->gLimChannelSwitch.sec_ch_offset = + dfs_csa_ie_req->ch_params.sec_ch_offset; + if (mac_ctx->sap.SapDfsInfo.disable_dfs_ch_switch == false) + session_entry->gLimChannelSwitch.switchMode = 1; + + /* + * Validate if SAP is operating HT or VHT mode and set the Channel + * Switch Wrapper element with the Wide Band Switch subelement. + */ + if (true != session_entry->vhtCapability) + goto skip_vht; + + /* Now encode the Wider Ch BW element depending on the ch width */ + wider_bw_ch_switch = &session_entry->gLimWiderBWChannelSwitch; + switch (dfs_csa_ie_req->ch_params.ch_width) { + case CH_WIDTH_20MHZ: + /* + * Wide channel BW sublement in channel wrapper element is not + * required in case of 20 Mhz operation. Currently It is set + * only set in case of 40/80 Mhz Operation. + */ + session_entry->dfsIncludeChanWrapperIe = false; + wider_bw_ch_switch->newChanWidth = + WNI_CFG_VHT_CHANNEL_WIDTH_20_40MHZ; + break; + case CH_WIDTH_40MHZ: + session_entry->dfsIncludeChanWrapperIe = false; + wider_bw_ch_switch->newChanWidth = + WNI_CFG_VHT_CHANNEL_WIDTH_20_40MHZ; + break; + case CH_WIDTH_80MHZ: + session_entry->dfsIncludeChanWrapperIe = true; + wider_bw_ch_switch->newChanWidth = + WNI_CFG_VHT_CHANNEL_WIDTH_80MHZ; + break; + case CH_WIDTH_160MHZ: + session_entry->dfsIncludeChanWrapperIe = true; + wider_bw_ch_switch->newChanWidth = + WNI_CFG_VHT_CHANNEL_WIDTH_160MHZ; + break; + case CH_WIDTH_80P80MHZ: + session_entry->dfsIncludeChanWrapperIe = true; + wider_bw_ch_switch->newChanWidth = + WNI_CFG_VHT_CHANNEL_WIDTH_80_PLUS_80MHZ; + /* + * This is not applicable for 20/40/80 Mhz. + * Only used when we support 80+80 Mhz operation. + * In case of 80+80 Mhz, this parameter indicates + * center channel frequency index of 80 Mhz channel of + * frequency segment 1. + */ + wider_bw_ch_switch->newCenterChanFreq1 = + dfs_csa_ie_req->ch_params.center_freq_seg1; + break; + default: + session_entry->dfsIncludeChanWrapperIe = false; + /* + * Need to handle 80+80 Mhz Scenario. When 80+80 is supported + * set the gLimWiderBWChannelSwitch.newChanWidth to 3 + */ + lim_log(mac_ctx, LOGE, FL("Invalid Channel Width")); + break; + } + /* Fetch the center channel based on the channel width */ + wider_bw_ch_switch->newCenterChanFreq0 = + dfs_csa_ie_req->ch_params.center_freq_seg0; +skip_vht: + /* Send CSA IE request from here */ + if (sch_set_fixed_beacon_fields(mac_ctx, session_entry) != + eSIR_SUCCESS) { + lim_log(mac_ctx, LOGE, FL("Unable to set CSA IE in beacon")); + return; + } + + /* + * First beacon update request is sent here, the remaining updates are + * done when the FW responds back after sending the first beacon after + * the template update + */ + lim_send_beacon_ind(mac_ctx, session_entry); + + if (dfs_csa_ie_req->ch_params.ch_width == CH_WIDTH_80MHZ) + ch_offset = BW80; + else + ch_offset = dfs_csa_ie_req->ch_params.sec_ch_offset; + + lim_log(mac_ctx, LOG1, FL("IE count:%d chan:%d width:%d wrapper:%d ch_offset:%d"), + session_entry->gLimChannelSwitch.switchCount, + session_entry->gLimChannelSwitch.primaryChannel, + session_entry->gLimChannelSwitch.ch_width, + session_entry->dfsIncludeChanWrapperIe, + ch_offset); + + /* Send ECSA Action frame after updating the beacon */ + send_extended_chan_switch_action_frame(mac_ctx, + session_entry->gLimChannelSwitch.primaryChannel, + ch_offset, session_entry); + session_entry->gLimChannelSwitch.switchCount--; +} + +/** + * lim_process_ext_change_channel()- function to send ECSA + * action frame for STA/CLI . + * @mac_ctx: pointer to global mac structure + * @msg: params from sme for new channel. + * + * This function is called to send ECSA frame for STA/CLI. + * + * Return: void + */ + +static void lim_process_ext_change_channel(tpAniSirGlobal mac_ctx, + uint32_t *msg) +{ + struct sir_sme_ext_cng_chan_req *ext_chng_channel = + (struct sir_sme_ext_cng_chan_req *) msg; + tpPESession session_entry = NULL; + + if (NULL == msg) { + lim_log(mac_ctx, LOGE, FL("Buffer is Pointing to NULL")); + return; + } + session_entry = + pe_find_session_by_sme_session_id(mac_ctx, + ext_chng_channel->session_id); + if (NULL == session_entry) { + lim_log(mac_ctx, LOGE, + FL("Session not found for given session %d"), + ext_chng_channel->session_id); + return; + } + if (LIM_IS_AP_ROLE(session_entry)) { + lim_log(mac_ctx, LOGE, + FL("not an STA/CLI session")); + return; + } + send_extended_chan_switch_action_frame(mac_ctx, + ext_chng_channel->new_channel, + 0, session_entry); +} + +/** + * lim_process_nss_update_request() - process sme nss update req + * + * @mac_ctx: Pointer to Global MAC structure + * @msg_buf: pointer to the SME message buffer + * + * This function processes SME request messages from HDD or upper layer + * application. + * + * Return: None + */ +static void lim_process_nss_update_request(tpAniSirGlobal mac_ctx, + uint32_t *msg_buf) +{ + struct sir_nss_update_request *nss_update_req_ptr; + tpPESession session_entry = NULL; + + if (msg_buf == NULL) { + lim_log(mac_ctx, LOGE, FL("Buffer is Pointing to NULL")); + return; + } + + nss_update_req_ptr = (struct sir_nss_update_request *)msg_buf; + session_entry = pe_find_session_by_sme_session_id(mac_ctx, + nss_update_req_ptr->vdev_id); + if (session_entry == NULL) { + lim_log(mac_ctx, LOGE, FL( + "Session not found for given session_id %d"), + nss_update_req_ptr->vdev_id); + return; + } + + if (session_entry->valid && !LIM_IS_AP_ROLE(session_entry)) { + lim_log(mac_ctx, LOGE, FL("Invalid SystemRole %d"), + GET_LIM_SYSTEM_ROLE(session_entry)); + return; + } + + /* populate nss field in the beacon */ + session_entry->gLimOperatingMode.present = 1; + session_entry->gLimOperatingMode.rxNSS = nss_update_req_ptr->new_nss; + session_entry->gLimOperatingMode.chanWidth = session_entry->ch_width; + + if ((nss_update_req_ptr->new_nss == NSS_1x1_MODE) && + (session_entry->ch_width > CH_WIDTH_80MHZ)) + session_entry->gLimOperatingMode.chanWidth = CH_WIDTH_80MHZ; + + pe_debug("ch width %hu", session_entry->gLimOperatingMode.chanWidth); + + /* Send nss update request from here */ + if (sch_set_fixed_beacon_fields(mac_ctx, session_entry) != + eSIR_SUCCESS) { + lim_log(mac_ctx, LOGE, + FL("Unable to set op mode IE in beacon")); + return; + } + + lim_send_beacon_ind(mac_ctx, session_entry); +} + +/** + * lim_process_set_ie_req() - process sme set IE request + * + * @mac_ctx: Pointer to Global MAC structure + * @msg_buf: pointer to the SME message buffer + * + * This function processes SME request messages from HDD or upper layer + * application. + * + * Return: None + */ +static void lim_process_set_ie_req(tpAniSirGlobal mac_ctx, uint32_t *msg_buf) +{ + struct send_extcap_ie *msg; + QDF_STATUS status; + + if (msg_buf == NULL) { + lim_log(mac_ctx, LOGE, FL("Buffer is Pointing to NULL")); + return; + } + + msg = (struct send_extcap_ie *)msg_buf; + status = lim_send_ext_cap_ie(mac_ctx, msg->session_id, NULL, false); + if (QDF_STATUS_SUCCESS != status) + lim_log(mac_ctx, LOGE, FL("Unable to send ExtCap to FW")); + +} diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_process_tdls.c b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_process_tdls.c new file mode 100644 index 0000000000000000000000000000000000000000..59a14677ed169ea434bdee2c73dff86f45c904ef --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_process_tdls.c @@ -0,0 +1,3545 @@ +/* + * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/*=========================================================================== + * lim_process_tdls.c + * OVERVIEW: + * + * DEPENDENCIES: + * + * Are listed for each API below. + * ===========================================================================*/ + +/*=========================================================================== + + * EDIT HISTORY FOR FILE + + * This section contains comments describing changes made to the module. + * Notice that changes are listed in reverse chronological order. + + * $Header$$DateTime$$Author$ + + * when who what, where, why + * ---------- --- ------------------------------------------------------ + * 05/05/2010 Ashwani Initial Creation, added TDLS action frame + * functionality,TDLS message exchange with SME..etc.. + + ===========================================================================*/ + +/** + * \file lim_process_tdls.c + * + * \brief Code for preparing,processing and sending 802.11z action frames + * + */ + +#ifdef FEATURE_WLAN_TDLS + +#include "sir_api.h" +#include "ani_global.h" +#include "sir_mac_prot_def.h" +#include "cfg_api.h" +#include "utils_api.h" +#include "lim_types.h" +#include "lim_utils.h" +#include "lim_security_utils.h" +#include "dot11f.h" +#include "lim_sta_hash_api.h" +#include "sch_api.h" +#include "lim_send_messages.h" +#include "utils_parser.h" +#include "lim_assoc_utils.h" +#include "lim_prop_exts_utils.h" +#include "dph_hash_table.h" +#include "wma_types.h" +#include "cds_regdomain.h" +#include "cds_utils.h" + +/* define NO_PAD_TDLS_MIN_8023_SIZE to NOT padding: See CR#447630 + There was IOT issue with cisco 1252 open mode, where it pads + discovery req/teardown frame with some junk value up to min size. + To avoid this issue, we pad QCOM_VENDOR_IE. + If there is other IOT issue because of this bandage, define NO_PAD... + */ +#ifndef NO_PAD_TDLS_MIN_8023_SIZE +#define MIN_IEEE_8023_SIZE 46 +#define MIN_VENDOR_SPECIFIC_IE_SIZE 5 +#endif + +static tSirRetStatus lim_tdls_setup_add_sta(tpAniSirGlobal pMac, + tSirTdlsAddStaReq * pAddStaReq, tpPESession psessionEntry); + +/* + * TDLS data frames will go out/come in as non-qos data. + * so, eth_890d_header will be aligned access.. + */ +static const uint8_t eth_890d_header[] = { + 0xaa, 0xaa, 0x03, 0x00, + 0x00, 0x00, 0x89, 0x0d, +}; + +/* + * type of links used in TDLS + */ +enum tdlsLinks { + TDLS_LINK_AP, + TDLS_LINK_DIRECT +} e_tdls_link; + +/* + * node status in node searching + */ +enum tdlsLinkNodeStatus { + TDLS_NODE_NOT_FOUND, + TDLS_NODE_FOUND +} e_tdls_link_node_status; + +enum tdlsReqType { + TDLS_INITIATOR, + TDLS_RESPONDER +} e_tdls_req_type; + +typedef enum tdlsLinkSetupStatus { + TDLS_SETUP_STATUS_SUCCESS = 0, + TDLS_SETUP_STATUS_FAILURE = 37 +} etdlsLinkSetupStatus; + +/* These maps to Kernel TDLS peer capability + * flags and should get changed as and when necessary + */ +enum tdls_peer_capability { + TDLS_PEER_HT_CAP = 0, + TDLS_PEER_VHT_CAP = 1, + TDLS_PEER_WMM_CAP = 2 +} e_tdls_peer_capability; + +/* some local defines */ +#define LINK_IDEN_ADDR_OFFSET(x) (&x.LinkIdentifier) +#define PTI_LINK_IDEN_OFFSET (5) +#define PTI_BUF_STATUS_OFFSET (25) + +/* TODO, Move this parameters to configuration */ +#define PEER_PSM_SUPPORT (0) +#define TDLS_SUPPORT (1) +#define TDLS_PROHIBITED (0) +#define TDLS_CH_SWITCH_PROHIBITED (1) +/** @brief Set bit manipulation macro */ +#define SET_BIT(value, mask) ((value) |= (1 << (mask))) +/** @brief Clear bit manipulation macro */ +#define CLEAR_BIT(value, mask) ((value) &= ~(1 << (mask))) +/** @brief Check bit manipulation macro */ +#define CHECK_BIT(value, mask) ((value) & (1 << (mask))) + +#define SET_PEER_AID_BITMAP(peer_bitmap, aid) \ + do { \ + if ((aid) < (sizeof(uint32_t) << 3)) \ + SET_BIT(peer_bitmap[0], (aid)); \ + else if ((aid) < (sizeof(uint32_t) << 4)) \ + SET_BIT(peer_bitmap[1], ((aid) - (sizeof(uint32_t) << 3)));\ + } while (0); + +#define CLEAR_PEER_AID_BITMAP(peer_bitmap, aid) \ + do { \ + if ((aid) < (sizeof(uint32_t) << 3)) \ + CLEAR_BIT(peer_bitmap[0], (aid)); \ + else if ((aid) < (sizeof(uint32_t) << 4)) \ + CLEAR_BIT(peer_bitmap[1], ((aid) - (sizeof(uint32_t) << 3)));\ + } while (0); + +#ifdef LIM_DEBUG_TDLS + +#ifdef FEATURE_WLAN_TDLS +#define WNI_CFG_TDLS_LINK_SETUP_RSP_TIMEOUT (800) +#define WNI_CFG_TDLS_LINK_SETUP_CNF_TIMEOUT (200) +#endif + +#define IS_QOS_ENABLED(psessionEntry) ((((psessionEntry)->limQosEnabled) && \ + SIR_MAC_GET_QOS((psessionEntry)->limCurrentBssCaps)) || \ + (((psessionEntry)->limWmeEnabled) && \ + LIM_BSS_CAPS_GET(WME, (psessionEntry)->limCurrentBssQosCaps))) + +#define TID_AC_VI 4 +#define TID_AC_BK 1 + +static const uint8_t *lim_trace_tdls_action_string(uint8_t tdlsActionCode) +{ + switch (tdlsActionCode) { + CASE_RETURN_STRING(SIR_MAC_TDLS_SETUP_REQ); + CASE_RETURN_STRING(SIR_MAC_TDLS_SETUP_RSP); + CASE_RETURN_STRING(SIR_MAC_TDLS_SETUP_CNF); + CASE_RETURN_STRING(SIR_MAC_TDLS_TEARDOWN); + CASE_RETURN_STRING(SIR_MAC_TDLS_PEER_TRAFFIC_IND); + CASE_RETURN_STRING(SIR_MAC_TDLS_CH_SWITCH_REQ); + CASE_RETURN_STRING(SIR_MAC_TDLS_CH_SWITCH_RSP); + CASE_RETURN_STRING(SIR_MAC_TDLS_PEER_TRAFFIC_RSP); + CASE_RETURN_STRING(SIR_MAC_TDLS_DIS_REQ); + CASE_RETURN_STRING(SIR_MAC_TDLS_DIS_RSP); + } + return (const uint8_t *)"UNKNOWN"; +} +#endif +/* + * initialize TDLS setup list and related data structures. + */ +void lim_init_tdls_data(tpAniSirGlobal pMac, tpPESession pSessionEntry) +{ + lim_init_peer_idxpool(pMac, pSessionEntry); + + return; +} + +static void populate_dot11f_tdls_offchannel_params( + tpAniSirGlobal pMac, + tpPESession psessionEntry, + tDot11fIESuppChannels *suppChannels, + tDot11fIESuppOperatingClasses *suppOperClasses) +{ + uint32_t numChans = WNI_CFG_VALID_CHANNEL_LIST_LEN; + uint8_t validChan[WNI_CFG_VALID_CHANNEL_LIST_LEN]; + uint8_t i; + uint8_t valid_count = 0; + uint8_t chanOffset; + uint8_t op_class; + uint8_t numClasses; + uint8_t classes[CDS_MAX_SUPP_OPER_CLASSES]; + uint32_t band; + uint8_t nss_2g; + uint8_t nss_5g; + + if (wlan_cfg_get_str(pMac, WNI_CFG_VALID_CHANNEL_LIST, + validChan, &numChans) != eSIR_SUCCESS) { + /** + * Could not get Valid channel list from CFG. + * Log error. + */ + lim_log(pMac, LOGE, + FL("could not retrieve Valid channel list")); + return; + } + + if (IS_5G_CH(psessionEntry->currentOperChannel)) + band = eCSR_BAND_5G; + else + band = eCSR_BAND_24; + + nss_5g = QDF_MIN(pMac->vdev_type_nss_5g.tdls, + pMac->user_configured_nss); + nss_2g = QDF_MIN(pMac->vdev_type_nss_2g.tdls, + pMac->user_configured_nss); + + /* validating the channel list for DFS and 2G channels */ + for (i = 0U; i < numChans; i++) { + if ((band == eCSR_BAND_5G) && + (NSS_2x2_MODE == nss_5g) && + (NSS_1x1_MODE == nss_2g) && + (true == CDS_IS_DFS_CH(validChan[i]))) { + lim_log(pMac, LOG1, + FL("skipping channel %d, nss_5g: %d, nss_2g: %d"), + validChan[i], nss_5g, nss_2g); + continue; + } else { + if (true == cds_is_dsrc_channel( + cds_chan_to_freq(validChan[i]))) { + lim_log(pMac, LOG1, + FL("skipping channel %d from the valid channel list"), + validChan[i]); + continue; + } + } + + if (valid_count >= ARRAY_SIZE(suppChannels->bands)) + break; + suppChannels->bands[valid_count][0] = validChan[i]; + suppChannels->bands[valid_count][1] = 1; + valid_count++; + } + + suppChannels->num_bands = valid_count; + suppChannels->present = 1; + + /* find channel offset and get op class for current operating channel */ + switch (psessionEntry->htSecondaryChannelOffset) { + case PHY_SINGLE_CHANNEL_CENTERED: + chanOffset = BW20; + break; + + case PHY_DOUBLE_CHANNEL_LOW_PRIMARY: + chanOffset = BW40_LOW_PRIMARY; + break; + + case PHY_DOUBLE_CHANNEL_HIGH_PRIMARY: + chanOffset = BW40_HIGH_PRIMARY; + break; + + default: + chanOffset = BWALL; + break; + + } + + op_class = cds_reg_dmn_get_opclass_from_channel( + pMac->scan.countryCodeCurrent, + psessionEntry->currentOperChannel, + chanOffset); + + if (op_class == 0) { + lim_log(pMac, LOGE, + FL( + "Present Operating class is wrong, countryCodeCurrent: %s, currentOperChannel: %d, htSecondaryChannelOffset: %d, chanOffset: %d" + ), + pMac->scan.countryCodeCurrent, + psessionEntry->currentOperChannel, + psessionEntry->htSecondaryChannelOffset, + chanOffset); + } else { + lim_log(pMac, LOG1, + FL( + "Present Operating channel: %d chanOffset: %d, op class=%d" + ), + psessionEntry->currentOperChannel, chanOffset, + op_class); + } + suppOperClasses->present = 1; + suppOperClasses->classes[0] = op_class; + + cds_reg_dmn_get_curr_opclasses(&numClasses, &classes[0]); + + for (i = 0; i < numClasses; i++) { + suppOperClasses->classes[i + 1] = classes[i]; + } + /* add one for present operating class, added in the beginning */ + suppOperClasses->num_classes = numClasses + 1; + + return; +} + +/* + * FUNCTION: Populate Link Identifier element IE + * + */ + +static void populate_dot11f_link_iden(tpAniSirGlobal pMac, + tpPESession psessionEntry, + tDot11fIELinkIdentifier *linkIden, + struct qdf_mac_addr peer_mac, + uint8_t reqType) +{ + uint8_t *initStaAddr = NULL; + uint8_t *respStaAddr = NULL; + + (reqType == TDLS_INITIATOR) ? ((initStaAddr = linkIden->InitStaAddr), + (respStaAddr = linkIden->RespStaAddr)) + : ((respStaAddr = linkIden->InitStaAddr), + (initStaAddr = linkIden->RespStaAddr)); + qdf_mem_copy((uint8_t *) linkIden->bssid, + (uint8_t *) psessionEntry->bssId, QDF_MAC_ADDR_SIZE); + + qdf_mem_copy((uint8_t *) initStaAddr, + psessionEntry->selfMacAddr, QDF_MAC_ADDR_SIZE); + + qdf_mem_copy((uint8_t *) respStaAddr, (uint8_t *) peer_mac.bytes, + QDF_MAC_ADDR_SIZE); + + linkIden->present = 1; + return; + +} + +static void populate_dot11f_tdls_ext_capability(tpAniSirGlobal pMac, + tpPESession psessionEntry, + tDot11fIEExtCap *extCapability) +{ + struct s_ext_cap *p_ext_cap = (struct s_ext_cap *)extCapability->bytes; + + p_ext_cap->tdls_peer_psm_supp = PEER_PSM_SUPPORT; + p_ext_cap->tdls_peer_uapsd_buffer_sta = pMac->lim.gLimTDLSBufStaEnabled; + + /* + * Set TDLS channel switching bits only if offchannel is enabled + * and TDLS Channel Switching is not prohibited by AP in ExtCap + * IE in assoc/re-assoc response. + */ + if ((1 == pMac->lim.gLimTDLSOffChannelEnabled) && + (!psessionEntry->tdls_chan_swit_prohibited)) { + p_ext_cap->tdls_channel_switching = 1; + p_ext_cap->tdls_chan_swit_prohibited = 0; + } else { + p_ext_cap->tdls_channel_switching = 0; + p_ext_cap->tdls_chan_swit_prohibited = TDLS_CH_SWITCH_PROHIBITED; + } + p_ext_cap->tdls_support = TDLS_SUPPORT; + p_ext_cap->tdls_prohibited = TDLS_PROHIBITED; + + extCapability->present = 1; + extCapability->num_bytes = lim_compute_ext_cap_ie_length(extCapability); + + return; +} + +/* + * prepare TDLS frame header, it includes + * | | | | + * |802.11 header|RFC1042 header|TDLS_PYLOAD_TYPE|PAYLOAD + * | | | | + */ +static uint32_t lim_prepare_tdls_frame_header(tpAniSirGlobal pMac, uint8_t *pFrame, + tDot11fIELinkIdentifier *link_iden, + uint8_t tdlsLinkType, uint8_t reqType, + uint8_t tid, + tpPESession psessionEntry) +{ + tpSirMacDataHdr3a pMacHdr; + uint32_t header_offset = 0; + uint8_t *addr1 = NULL; + uint8_t *addr3 = NULL; + uint8_t toDs = (tdlsLinkType == TDLS_LINK_AP) + ? ANI_TXDIR_TODS : ANI_TXDIR_IBSS; + uint8_t *peerMac = (reqType == TDLS_INITIATOR) + ? link_iden->RespStaAddr : link_iden->InitStaAddr; + uint8_t *staMac = (reqType == TDLS_INITIATOR) + ? link_iden->InitStaAddr : link_iden->RespStaAddr; + tpDphHashNode sta_ds; + uint16_t aid = 0; + uint8_t qos_mode = 0; + + pMacHdr = (tpSirMacDataHdr3a) (pFrame); + + /* + * if TDLS frame goes through the AP link, it follows normal address + * pattern, if TDLS frame goes thorugh the direct link, then + * A1--> Peer STA addr, A2-->Self STA address, A3--> BSSID + */ + (tdlsLinkType == TDLS_LINK_AP) ? ((addr1 = (link_iden->bssid)), + (addr3 = (peerMac))) + : ((addr1 = (peerMac)), (addr3 = (link_iden->bssid))); + /* + * prepare 802.11 header + */ + pMacHdr->fc.protVer = SIR_MAC_PROTOCOL_VERSION; + pMacHdr->fc.type = SIR_MAC_DATA_FRAME; + + sta_ds = dph_lookup_hash_entry(pMac, peerMac, &aid, + &psessionEntry->dph.dphHashTable); + if (sta_ds) + qos_mode = sta_ds->qosMode; + + pMacHdr->fc.subType = + ((IS_QOS_ENABLED(psessionEntry) && + (tdlsLinkType == TDLS_LINK_AP)) || + ((tdlsLinkType == TDLS_LINK_DIRECT) && qos_mode)) + ? SIR_MAC_DATA_QOS_DATA : SIR_MAC_DATA_DATA; + + /* + * TL is not setting up below fields, so we are doing it here + */ + pMacHdr->fc.toDS = toDs; + pMacHdr->fc.powerMgmt = 0; + pMacHdr->fc.wep = (psessionEntry->encryptType == eSIR_ED_NONE) ? 0 : 1; + + qdf_mem_copy((uint8_t *) pMacHdr->addr1, + (uint8_t *) addr1, sizeof(tSirMacAddr)); + qdf_mem_copy((uint8_t *) pMacHdr->addr2, + (uint8_t *) staMac, sizeof(tSirMacAddr)); + + qdf_mem_copy((uint8_t *) pMacHdr->addr3, + (uint8_t *) (addr3), sizeof(tSirMacAddr)); + + lim_log(pMac, LOG1, + FL( + "Preparing TDLS frame header to %s A1:" + MAC_ADDRESS_STR", A2:"MAC_ADDRESS_STR", A3:" + MAC_ADDRESS_STR + ), + (tdlsLinkType == TDLS_LINK_AP) ? "AP" : "DIRECT", + MAC_ADDR_ARRAY(pMacHdr->addr1), + MAC_ADDR_ARRAY(pMacHdr->addr2), + MAC_ADDR_ARRAY(pMacHdr->addr3)); + + if (pMacHdr->fc.subType == SIR_MAC_DATA_QOS_DATA) { + pMacHdr->qosControl.tid = tid; + header_offset += sizeof(tSirMacDataHdr3a); + } else + header_offset += sizeof(tSirMacMgmtHdr); + + /* + * Now form RFC1042 header + */ + qdf_mem_copy((uint8_t *) (pFrame + header_offset), + (uint8_t *) eth_890d_header, sizeof(eth_890d_header)); + + header_offset += sizeof(eth_890d_header); + + /* add payload type as TDLS */ + *(pFrame + header_offset) = PAYLOAD_TYPE_TDLS; + header_offset += PAYLOAD_TYPE_TDLS_SIZE; + return header_offset; +} + +/** + * lim_mgmt_tdls_tx_complete - callback to indicate Tx completion + * @mac_ctx: pointer to mac structure + * @tx_complete: indicates tx sucess/failure + * + * function will be invoked on receiving tx completion indication + * + * return: success: eHAL_STATUS_SUCCESS failure: eHAL_STATUS_FAILURE + */ +static QDF_STATUS lim_mgmt_tdls_tx_complete(tpAniSirGlobal mac_ctx, + uint32_t tx_complete) +{ + lim_log(mac_ctx, LOG1, FL("tdls_frm_session_id %x tx_complete %x"), + mac_ctx->lim.tdls_frm_session_id, tx_complete); + + if (NO_SESSION != mac_ctx->lim.tdls_frm_session_id) { + lim_send_sme_mgmt_tx_completion(mac_ctx, + mac_ctx->lim.tdls_frm_session_id, + tx_complete); + mac_ctx->lim.tdls_frm_session_id = NO_SESSION; + } + return QDF_STATUS_SUCCESS; +} + +/* + * This function can be used for bacst or unicast discovery request + * We are not differentiating it here, it will all depnds on peer MAC address, + */ +static tSirRetStatus lim_send_tdls_dis_req_frame(tpAniSirGlobal pMac, + struct qdf_mac_addr peer_mac, + uint8_t dialog, + tpPESession psessionEntry, + enum sir_wifi_traffic_ac ac) +{ + tDot11fTDLSDisReq tdlsDisReq; + uint32_t status = 0; + uint32_t nPayload = 0; + uint32_t size = 0; + uint32_t nBytes = 0; + uint32_t header_offset = 0; + uint8_t *pFrame; + void *pPacket; + QDF_STATUS qdf_status; +#ifndef NO_PAD_TDLS_MIN_8023_SIZE + uint32_t padLen = 0; +#endif + uint8_t smeSessionId = 0; + + if (NULL == psessionEntry) { + lim_log(pMac, LOGE, FL("psessionEntry is NULL")); + return eSIR_FAILURE; + } + smeSessionId = psessionEntry->smeSessionId; + /* + * The scheme here is to fill out a 'tDot11fProbeRequest' structure + * and then hand it off to 'dot11f_pack_probe_request' (for + * serialization). We start by zero-initializing the structure: + */ + qdf_mem_set((uint8_t *) &tdlsDisReq, sizeof(tDot11fTDLSDisReq), 0); + + /* + * setup Fixed fields, + */ + tdlsDisReq.Category.category = SIR_MAC_ACTION_TDLS; + tdlsDisReq.Action.action = SIR_MAC_TDLS_DIS_REQ; + tdlsDisReq.DialogToken.token = dialog; + + size = sizeof(tSirMacAddr); + + populate_dot11f_link_iden(pMac, psessionEntry, &tdlsDisReq.LinkIdentifier, + peer_mac, TDLS_INITIATOR); + + /* + * now we pack it. First, how much space are we going to need? + */ + status = dot11f_get_packed_tdls_dis_req_size(pMac, &tdlsDisReq, &nPayload); + if (DOT11F_FAILED(status)) { + lim_log(pMac, LOGP, + FL( + "Failed to calculate the packed size for a discovery Request (0x%08x)." + ), + status); + /* We'll fall back on the worst case scenario: */ + nPayload = sizeof(tDot11fTDLSDisReq); + } else if (DOT11F_WARNED(status)) { + lim_log(pMac, LOGW, + FL( + "There were warnings while calculating the packed size for a discovery Request (0x%08x)." + ), + status); + } + + /* + * This frame is going out from PE as data frames with special ethertype + * 89-0d. + * 8 bytes of RFC 1042 header + */ + + nBytes = nPayload + ((IS_QOS_ENABLED(psessionEntry)) + ? sizeof(tSirMacDataHdr3a) : + sizeof(tSirMacMgmtHdr)) + + sizeof(eth_890d_header) + + PAYLOAD_TYPE_TDLS_SIZE; + +#ifndef NO_PAD_TDLS_MIN_8023_SIZE + /* IOT issue with some AP : some AP doesn't like the data packet size < minimum 802.3 frame length (64) + Hence AP itself padding some bytes, which caused teardown packet is dropped at + receiver side. To avoid such IOT issue, we added some extra bytes to meet data frame size >= 64 + */ + if (nPayload + PAYLOAD_TYPE_TDLS_SIZE < MIN_IEEE_8023_SIZE) { + padLen = + MIN_IEEE_8023_SIZE - (nPayload + PAYLOAD_TYPE_TDLS_SIZE); + + /* if padLen is less than minimum vendorSpecific (5), pad up to 5 */ + if (padLen < MIN_VENDOR_SPECIFIC_IE_SIZE) + padLen = MIN_VENDOR_SPECIFIC_IE_SIZE; + + nBytes += padLen; + } +#endif + + /* Ok-- try to allocate memory from MGMT PKT pool */ + + qdf_status = cds_packet_alloc((uint16_t) nBytes, (void **)&pFrame, + (void **)&pPacket); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + lim_log(pMac, LOGP, + FL( + "Failed to allocate %d bytes for a TDLS Discovery Request." + ), + nBytes); + return eSIR_MEM_ALLOC_FAILED; + } + + /* zero out the memory */ + qdf_mem_set(pFrame, nBytes, 0); + + /* + * IE formation, memory allocation is completed, Now form TDLS discovery + * request frame + */ + + /* fill out the buffer descriptor */ + + header_offset = lim_prepare_tdls_frame_header(pMac, pFrame, + LINK_IDEN_ADDR_OFFSET(tdlsDisReq), TDLS_LINK_AP, + TDLS_INITIATOR, + (ac == WIFI_AC_VI) ? TID_AC_VI : TID_AC_BK, + psessionEntry); + + status = dot11f_pack_tdls_dis_req(pMac, &tdlsDisReq, pFrame + + header_offset, nPayload, &nPayload); + + if (DOT11F_FAILED(status)) { + lim_log(pMac, LOGE, + FL("Failed to pack a TDLS discovery req (0x%08x)."), + status); + cds_packet_free((void *)pPacket); + return eSIR_FAILURE; + } else if (DOT11F_WARNED(status)) { + lim_log(pMac, LOGW, + FL( + "There were warnings while packing TDLS Discovery Request (0x%08x)." + ), + status); + } +#ifndef NO_PAD_TDLS_MIN_8023_SIZE + if (padLen != 0) { + /* QCOM VENDOR OUI = { 0x00, 0xA0, 0xC6, type = 0x0000 }; */ + uint8_t *padVendorSpecific = pFrame + header_offset + nPayload; + /* make QCOM_VENDOR_OUI, and type = 0x0000, and all the payload to be zero */ + padVendorSpecific[0] = 221; + padVendorSpecific[1] = padLen - 2; + padVendorSpecific[2] = 0x00; + padVendorSpecific[3] = 0xA0; + padVendorSpecific[4] = 0xC6; + + lim_log(pMac, LOGW, + FL("Padding Vendor Specific Ie Len = %d"), padLen); + + /* padding zero if more than 5 bytes are required */ + if (padLen > MIN_VENDOR_SPECIFIC_IE_SIZE) + qdf_mem_set(pFrame + header_offset + nPayload + + MIN_VENDOR_SPECIFIC_IE_SIZE, + padLen - MIN_VENDOR_SPECIFIC_IE_SIZE, 0); + } +#endif + + lim_log(pMac, LOG1, + FL("[TDLS] action %d (%s) -AP-> OTA peer="MAC_ADDRESS_STR), + SIR_MAC_TDLS_DIS_REQ, + lim_trace_tdls_action_string(SIR_MAC_TDLS_DIS_REQ), + MAC_ADDR_ARRAY(peer_mac.bytes)); + + pMac->lim.tdls_frm_session_id = psessionEntry->smeSessionId; + qdf_status = wma_tx_frameWithTxComplete(pMac, pPacket, + (uint16_t) nBytes, + TXRX_FRM_802_11_DATA, + ANI_TXDIR_TODS, + TID_AC_VI, + lim_tx_complete, pFrame, + lim_mgmt_tdls_tx_complete, + HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME | + HAL_USE_PEER_STA_REQUESTED_MASK, + smeSessionId, false, 0); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + pMac->lim.tdls_frm_session_id = NO_SESSION; + lim_log(pMac, LOGE, + FL("could not send TDLS Discovery Request frame")); + return eSIR_FAILURE; + } + + return eSIR_SUCCESS; + +} + +/* + * This static function is consistent with any kind of TDLS management + * frames we are sending. Currently it is being used by lim_send_tdls_dis_rsp_frame, + * lim_send_tdls_link_setup_req_frame and lim_send_tdls_setup_rsp_frame + */ +static void populate_dot11f_tdls_ht_vht_cap(tpAniSirGlobal pMac, + uint32_t selfDot11Mode, + tDot11fIEHTCaps *htCap, + tDot11fIEVHTCaps *vhtCap, + tpPESession psessionEntry) +{ + uint8_t nss; + uint32_t val; + + if (IS_5G_CH(psessionEntry->currentOperChannel)) + nss = pMac->vdev_type_nss_5g.tdls; + else + nss = pMac->vdev_type_nss_2g.tdls; + + nss = QDF_MIN(nss, pMac->user_configured_nss); + if (IS_DOT11_MODE_HT(selfDot11Mode)) { + /* Include HT Capability IE */ + populate_dot11f_ht_caps(pMac, NULL, htCap); + val = SIZE_OF_SUPPORTED_MCS_SET; + wlan_cfg_get_str(pMac, WNI_CFG_SUPPORTED_MCS_SET, + &htCap->supportedMCSSet[0], &val); + if (NSS_1x1_MODE == nss) + htCap->supportedMCSSet[1] = 0; + /* + * Advertise ht capability and max supported channel bandwidth + * when populating HT IE in TDLS Setup Request/Setup Response/ + * Setup Confirmation frames. + * 11.21.6.2 Setting up a 40 MHz direct link: A 40 MHz + * off-channel direct link may be started if both TDLS peer STAs + * indicated 40 MHz support in the Supported Channel Width Set + * field of the HT Capabilities element (which is included in + * the TDLS Setup Request frame and the TDLS Setup Response + * frame). Switching to a 40 MHz off-channel direct link is + * achieved by including the following information in the TDLS + * Channel Switch Request + * 11.21.1 General: The channel width of the TDLS direct link on + * the base channel shall not exceed the channel width of the + * BSS to which the TDLS peer STAs are associated. + */ + htCap->supportedChannelWidthSet = 1; + } else { + htCap->present = 0; + } + lim_log(pMac, LOG1, FL("HT present = %hu, Chan Width = %hu"), + htCap->present, htCap->supportedChannelWidthSet); + if (((psessionEntry->currentOperChannel <= SIR_11B_CHANNEL_END) && + pMac->roam.configParam.enableVhtFor24GHz) || + (psessionEntry->currentOperChannel >= SIR_11B_CHANNEL_END)) { + if (IS_DOT11_MODE_VHT(selfDot11Mode) && + IS_FEATURE_SUPPORTED_BY_FW(DOT11AC)) { + /* Include VHT Capability IE */ + populate_dot11f_vht_caps(pMac, psessionEntry, vhtCap); + + /* + * Set to 0 if the TDLS STA does not support either 160 + * or 80+80 MHz. + * Set to 1 if the TDLS STA supports 160 MHz. + * Set to 2 if the TDLS STA supports 160 MHz and + * 80+80 MHz. + * The value 3 is reserved + */ + vhtCap->supportedChannelWidthSet = 0; + + vhtCap->suBeamformeeCap = 0; + vhtCap->suBeamFormerCap = 0; + vhtCap->muBeamformeeCap = 0; + vhtCap->muBeamformerCap = 0; + + wlan_cfg_get_int(pMac, WNI_CFG_VHT_RX_MCS_MAP, &val); + vhtCap->rxMCSMap = val; + wlan_cfg_get_int(pMac, + WNI_CFG_VHT_RX_HIGHEST_SUPPORTED_DATA_RATE, + &val); + vhtCap->rxHighSupDataRate = val; + wlan_cfg_get_int(pMac, WNI_CFG_VHT_TX_MCS_MAP, &val); + vhtCap->txMCSMap = val; + wlan_cfg_get_int(pMac, + WNI_CFG_VHT_TX_HIGHEST_SUPPORTED_DATA_RATE, + &val); + vhtCap->txSupDataRate = val; + if (nss == NSS_1x1_MODE) { + vhtCap->txMCSMap |= DISABLE_NSS2_MCS; + vhtCap->rxMCSMap |= DISABLE_NSS2_MCS; + vhtCap->txSupDataRate = + VHT_TX_HIGHEST_SUPPORTED_DATA_RATE_1_1; + vhtCap->rxHighSupDataRate = + VHT_RX_HIGHEST_SUPPORTED_DATA_RATE_1_1; + } + } else { + vhtCap->present = 0; + } + } else { + /* Vht Disable from ini in 2.4 GHz */ + vhtCap->present = 0; + } + lim_log(pMac, LOG1, FL("VHT present = %hu, Chan Width = %hu"), + vhtCap->present, vhtCap->supportedChannelWidthSet); +} + +/* + * Send TDLS discovery response frame on direct link. + */ + +static tSirRetStatus lim_send_tdls_dis_rsp_frame(tpAniSirGlobal pMac, + struct qdf_mac_addr peer_mac, + uint8_t dialog, + tpPESession psessionEntry, + uint8_t *addIe, + uint16_t addIeLen) +{ + tDot11fTDLSDisRsp tdlsDisRsp; + uint16_t caps = 0; + uint32_t status = 0; + uint32_t nPayload = 0; + uint32_t nBytes = 0; + uint8_t *pFrame; + void *pPacket; + QDF_STATUS qdf_status; + uint32_t selfDot11Mode; +/* Placeholder to support different channel bonding mode of TDLS than AP. */ +/* Today, WNI_CFG_CHANNEL_BONDING_MODE will be overwritten when connecting to AP */ +/* To support this feature, we need to introduce WNI_CFG_TDLS_CHANNEL_BONDING_MODE */ +/* As of now, we hardcoded to max channel bonding of dot11Mode (i.e HT80 for 11ac/HT40 for 11n) */ +/* uint32_t tdlsChannelBondingMode; */ + uint8_t smeSessionId = 0; + + if (NULL == psessionEntry) { + lim_log(pMac, LOGE, FL("psessionEntry is NULL")); + return eSIR_FAILURE; + } + smeSessionId = psessionEntry->smeSessionId; + + /* + * The scheme here is to fill out a 'tDot11fProbeRequest' structure + * and then hand it off to 'dot11f_pack_probe_request' (for + * serialization). We start by zero-initializing the structure: + */ + qdf_mem_set((uint8_t *) &tdlsDisRsp, sizeof(tDot11fTDLSDisRsp), 0); + + /* + * setup Fixed fields, + */ + tdlsDisRsp.Category.category = SIR_MAC_ACTION_PUBLIC_USAGE; + tdlsDisRsp.Action.action = SIR_MAC_TDLS_DIS_RSP; + tdlsDisRsp.DialogToken.token = dialog; + + populate_dot11f_link_iden(pMac, psessionEntry, + &tdlsDisRsp.LinkIdentifier, + peer_mac, TDLS_RESPONDER); + + if (cfg_get_capability_info(pMac, &caps, psessionEntry) + != eSIR_SUCCESS) { + /* + * Could not get Capabilities value + * from CFG. Log error. + */ + lim_log(pMac, LOGE, + FL("could not retrieve Capabilities value")); + } + swap_bit_field16(caps, (uint16_t *) &tdlsDisRsp.Capabilities); + + /* populate supported rate and ext supported rate IE */ + if (eSIR_FAILURE == populate_dot11f_rates_tdls(pMac, + &tdlsDisRsp.SuppRates, + &tdlsDisRsp.ExtSuppRates, + psessionEntry->currentOperChannel)) + lim_log(pMac, LOGE, + FL("could not populate supported data rates")); + + /* populate extended capability IE */ + populate_dot11f_tdls_ext_capability(pMac, + psessionEntry, + &tdlsDisRsp.ExtCap); + + wlan_cfg_get_int(pMac, WNI_CFG_DOT11_MODE, &selfDot11Mode); + + /* Populate HT/VHT Capabilities */ + populate_dot11f_tdls_ht_vht_cap(pMac, selfDot11Mode, &tdlsDisRsp.HTCaps, + &tdlsDisRsp.VHTCaps, psessionEntry); + + /* Populate TDLS offchannel param only if offchannel is enabled + * and TDLS Channel Switching is not prohibited by AP in ExtCap + * IE in assoc/re-assoc response. + */ + if ((1 == pMac->lim.gLimTDLSOffChannelEnabled) && + (!psessionEntry->tdls_chan_swit_prohibited)) { + populate_dot11f_tdls_offchannel_params(pMac, psessionEntry, + &tdlsDisRsp.SuppChannels, + &tdlsDisRsp. + SuppOperatingClasses); + if (pMac->roam.configParam.bandCapability != eCSR_BAND_24) { + tdlsDisRsp.ht2040_bss_coexistence.present = 1; + tdlsDisRsp.ht2040_bss_coexistence.info_request = 1; + } + } else { + lim_log(pMac, LOG1, + FL("TDLS offchan not enabled, or channel switch prohibited by AP, gLimTDLSOffChannelEnabled (%d), tdls_chan_swit_prohibited (%d)"), + pMac->lim.gLimTDLSOffChannelEnabled, + psessionEntry->tdls_chan_swit_prohibited); + } + /* + * now we pack it. First, how much space are we going to need? + */ + status = dot11f_get_packed_tdls_dis_rsp_size(pMac, &tdlsDisRsp, &nPayload); + if (DOT11F_FAILED(status)) { + lim_log(pMac, LOGE, + FL( + "Failed to calculate the packed size for a Discovery Response (0x%08x)." + ), + status); + /* We'll fall back on the worst case scenario: */ + nPayload = sizeof(tDot11fProbeRequest); + } else if (DOT11F_WARNED(status)) { + lim_log(pMac, LOGW, + FL( + "There were warnings while calculating the packed size for a Discovery Response (0x%08x)." + ), + status); + } + + /* + * This frame is going out from PE as data frames with special ethertype + * 89-0d. + * 8 bytes of RFC 1042 header + */ + + nBytes = nPayload + sizeof(tSirMacMgmtHdr) + addIeLen; + + /* Ok-- try to allocate memory from MGMT PKT pool */ + qdf_status = cds_packet_alloc((uint16_t) nBytes, (void **)&pFrame, + (void **)&pPacket); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + lim_log(pMac, LOGE, + FL( + "Failed to allocate %d bytes for a TDLS Discovery Request." + ), + nBytes); + return eSIR_MEM_ALLOC_FAILED; + } + + /* zero out the memory */ + qdf_mem_set(pFrame, nBytes, 0); + + /* + * IE formation, memory allocation is completed, Now form TDLS discovery + * response frame + */ + + /* Make public Action Frame */ + + lim_populate_mac_header(pMac, pFrame, SIR_MAC_MGMT_FRAME, + SIR_MAC_MGMT_ACTION, peer_mac.bytes, + psessionEntry->selfMacAddr); + + { + tpSirMacMgmtHdr pMacHdr; + pMacHdr = (tpSirMacMgmtHdr) pFrame; + pMacHdr->fc.toDS = ANI_TXDIR_IBSS; + pMacHdr->fc.powerMgmt = 0; + sir_copy_mac_addr(pMacHdr->bssId, psessionEntry->bssId); + } + + status = dot11f_pack_tdls_dis_rsp(pMac, &tdlsDisRsp, pFrame + + sizeof(tSirMacMgmtHdr), + nPayload, &nPayload); + + if (DOT11F_FAILED(status)) { + lim_log(pMac, LOGE, + FL( + "Failed to pack a TDLS discovery response (0x%08x)." + ), + status); + cds_packet_free((void *)pPacket); + return eSIR_FAILURE; + } else if (DOT11F_WARNED(status)) { + lim_log(pMac, LOGW, + FL( + "There were warnings while packing TDLS Discovery Response (0x%08x)." + ), + status); + } + if (0 != addIeLen) { + lim_log(pMac, LOG1, + FL("Copy Additional Ie Len = %d"), addIeLen); + qdf_mem_copy(pFrame + sizeof(tSirMacMgmtHdr) + nPayload, addIe, + addIeLen); + } + lim_log(pMac, LOG1, + FL("[TDLS] action %d (%s) -DIRECT-> OTA peer="MAC_ADDRESS_STR), + SIR_MAC_TDLS_DIS_RSP, + lim_trace_tdls_action_string(SIR_MAC_TDLS_DIS_RSP), + MAC_ADDR_ARRAY(peer_mac.bytes)); + + pMac->lim.tdls_frm_session_id = psessionEntry->smeSessionId; + /* + * Transmit Discovery response and watch if this is delivered to + * peer STA. + */ + /* In CLD 2.0, pass Discovery Response as mgmt frame so that + * wma does not do header conversion to 802.3 before calling tx/rx + * routine and subsequenly target also sends frame as is OTA + */ + qdf_status = wma_tx_frameWithTxComplete(pMac, pPacket, (uint16_t) nBytes, + TXRX_FRM_802_11_MGMT, + ANI_TXDIR_IBSS, + 0, + lim_tx_complete, pFrame, + lim_mgmt_tdls_tx_complete, + HAL_USE_SELF_STA_REQUESTED_MASK, + smeSessionId, false, 0); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + pMac->lim.tdls_frm_session_id = NO_SESSION; + lim_log(pMac, LOGE, + FL("could not send TDLS Discovery Response frame!")); + return eSIR_FAILURE; + } + + return eSIR_SUCCESS; + +} + +/* + * This static function is currently used by lim_send_tdls_link_setup_req_frame and + * lim_send_tdls_setup_rsp_frame to populate the AID if device is 11ac capable. + */ +static void populate_dotf_tdls_vht_aid(tpAniSirGlobal pMac, uint32_t selfDot11Mode, + struct qdf_mac_addr peerMac, + tDot11fIEAID *Aid, + tpPESession psessionEntry) +{ + if (((psessionEntry->currentOperChannel <= SIR_11B_CHANNEL_END) && + pMac->roam.configParam.enableVhtFor24GHz) || + (psessionEntry->currentOperChannel >= SIR_11B_CHANNEL_END)) { + if (IS_DOT11_MODE_VHT(selfDot11Mode) && + IS_FEATURE_SUPPORTED_BY_FW(DOT11AC)) { + + uint16_t aid; + tpDphHashNode pStaDs; + + pStaDs = + dph_lookup_hash_entry(pMac, peerMac.bytes, &aid, + &psessionEntry->dph. + dphHashTable); + if (NULL != pStaDs) { + Aid->present = 1; + Aid->assocId = aid | LIM_AID_MASK; /* set bit 14 and 15 1's */ + } else { + Aid->present = 0; + lim_log(pMac, LOGE, + FL("pStaDs is NULL for " + MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(peerMac.bytes)); + } + } + } else { + Aid->present = 0; + lim_log(pMac, LOGW, FL("Vht not enable from ini for 2.4GHz.")); + } +} + +#ifdef CONFIG_HL_SUPPORT + +/** + * wma_tx_frame_with_tx_complete_send() - Send tx frames on Direct link or AP link + * depend on reason code + * @pMac: pointer to MAC Sirius parameter structure + * @pPacket: pointer to mgmt packet + * @nBytes: number of bytes to send + * @tid:tid value for AC + * @pFrame: pointer to tdls frame + * @smeSessionId:session id + * @flag: tdls flag + * + * Send TDLS Teardown frame on Direct link or AP link, depends on reason code. + * + * Return: None + */ +static inline QDF_STATUS +wma_tx_frame_with_tx_complete_send(tpAniSirGlobal pMac, void *pPacket, + uint16_t nBytes, + uint8_t tid, + uint8_t *pFrame, + uint8_t smeSessionId, bool flag) +{ + return wma_tx_frameWithTxComplete(pMac, pPacket, + (uint16_t) nBytes, + TXRX_FRM_802_11_DATA, + ANI_TXDIR_TODS, + tid, + lim_tx_complete, pFrame, + lim_mgmt_tdls_tx_complete, + HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME + | HAL_USE_PEER_STA_REQUESTED_MASK, + smeSessionId, flag, 0); +} +#else + +static inline QDF_STATUS +wma_tx_frame_with_tx_complete_send(tpAniSirGlobal pMac, void *pPacket, + uint16_t nBytes, + uint8_t tid, + uint8_t *pFrame, + uint8_t smeSessionId, bool flag) +{ + return wma_tx_frameWithTxComplete(pMac, pPacket, + (uint16_t) nBytes, + TXRX_FRM_802_11_DATA, + ANI_TXDIR_TODS, + tid, + lim_tx_complete, pFrame, + lim_mgmt_tdls_tx_complete, + HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME + | HAL_USE_PEER_STA_REQUESTED_MASK, + smeSessionId, false, 0); +} +#endif + +void lim_set_tdls_flags(roam_offload_synch_ind *roam_sync_ind_ptr, + tpPESession ft_session_ptr) +{ + roam_sync_ind_ptr->join_rsp->tdls_prohibited = + ft_session_ptr->tdls_prohibited; + roam_sync_ind_ptr->join_rsp->tdls_chan_swit_prohibited = + ft_session_ptr->tdls_chan_swit_prohibited; +} + +/* + * TDLS setup Request frame on AP link + */ +static +tSirRetStatus lim_send_tdls_link_setup_req_frame(tpAniSirGlobal pMac, + struct qdf_mac_addr peer_mac, + uint8_t dialog, + tpPESession psessionEntry, + uint8_t *addIe, + uint16_t addIeLen, + enum sir_wifi_traffic_ac ac) +{ + tDot11fTDLSSetupReq tdlsSetupReq; + uint16_t caps = 0; + uint32_t status = 0; + uint32_t nPayload = 0; + uint32_t nBytes = 0; + uint32_t header_offset = 0; + uint8_t *pFrame; + void *pPacket; + QDF_STATUS qdf_status; + uint32_t selfDot11Mode; + uint8_t smeSessionId = 0; +/* Placeholder to support different channel bonding mode of TDLS than AP. */ +/* Today, WNI_CFG_CHANNEL_BONDING_MODE will be overwritten when connecting to AP */ +/* To support this feature, we need to introduce WNI_CFG_TDLS_CHANNEL_BONDING_MODE */ +/* As of now, we hardcoded to max channel bonding of dot11Mode (i.e HT80 for 11ac/HT40 for 11n) */ +/* uint32_t tdlsChannelBondingMode; */ + + /* + * The scheme here is to fill out a 'tDot11fProbeRequest' structure + * and then hand it off to 'dot11f_pack_probe_request' (for + * serialization). We start by zero-initializing the structure: + */ + smeSessionId = psessionEntry->smeSessionId; + + qdf_mem_set((uint8_t *) &tdlsSetupReq, sizeof(tDot11fTDLSSetupReq), 0); + tdlsSetupReq.Category.category = SIR_MAC_ACTION_TDLS; + tdlsSetupReq.Action.action = SIR_MAC_TDLS_SETUP_REQ; + tdlsSetupReq.DialogToken.token = dialog; + + populate_dot11f_link_iden(pMac, psessionEntry, + &tdlsSetupReq.LinkIdentifier, peer_mac, + TDLS_INITIATOR); + + if (cfg_get_capability_info(pMac, &caps, psessionEntry) != eSIR_SUCCESS) { + /* + * Could not get Capabilities value + * from CFG. Log error. + */ + lim_log(pMac, LOGE, + FL("could not retrieve Capabilities value")); + } + swap_bit_field16(caps, (uint16_t *) &tdlsSetupReq.Capabilities); + + /* populate supported rate and ext supported rate IE */ + if (eSIR_FAILURE == populate_dot11f_rates_tdls(pMac, + &tdlsSetupReq.SuppRates, + &tdlsSetupReq.ExtSuppRates, + psessionEntry->currentOperChannel)) + lim_log(pMac, LOGE, + FL("could not populate supported data rates")); + + /* Populate extended capability IE */ + populate_dot11f_tdls_ext_capability(pMac, + psessionEntry, + &tdlsSetupReq.ExtCap); + + if (1 == pMac->lim.gLimTDLSWmmMode) { + uint32_t val = 0; + + lim_log(pMac, LOG1, + FL("populate WMM IE in Setup Request Frame")); + /* include WMM IE */ + tdlsSetupReq.WMMInfoStation.version = SIR_MAC_OUI_VERSION_1; + tdlsSetupReq.WMMInfoStation.acvo_uapsd = + (pMac->lim.gLimTDLSUapsdMask & 0x01); + tdlsSetupReq.WMMInfoStation.acvi_uapsd = + ((pMac->lim.gLimTDLSUapsdMask & 0x02) >> 1); + tdlsSetupReq.WMMInfoStation.acbk_uapsd = + ((pMac->lim.gLimTDLSUapsdMask & 0x04) >> 2); + tdlsSetupReq.WMMInfoStation.acbe_uapsd = + ((pMac->lim.gLimTDLSUapsdMask & 0x08) >> 3); + + if (wlan_cfg_get_int(pMac, WNI_CFG_MAX_SP_LENGTH, &val) != + eSIR_SUCCESS) + lim_log(pMac, LOGE, + FL("could not retrieve Max SP Length")); + + tdlsSetupReq.WMMInfoStation.max_sp_length = (uint8_t) val; + tdlsSetupReq.WMMInfoStation.present = 1; + } else { + /* + * TODO: we need to see if we have to support conditions where + * we have EDCA parameter info element is needed a) if we need + * different QOS parameters for off channel operations or QOS + * is not supported on AP link and we wanted to QOS on direct + * link. + */ + + /* Populate QOS info, needed for Peer U-APSD session */ + + /* + * TODO: Now hardcoded, since populate_dot11f_qos_caps_station() + * depends on AP's capability, and TDLS doesn't want to depend + * on AP's capability + */ + + lim_log(pMac, LOG1, + FL("populate QOS IE in Setup Request Frame")); + tdlsSetupReq.QOSCapsStation.present = 1; + tdlsSetupReq.QOSCapsStation.max_sp_length = 0; + tdlsSetupReq.QOSCapsStation.qack = 0; + tdlsSetupReq.QOSCapsStation.acbe_uapsd = + ((pMac->lim.gLimTDLSUapsdMask & 0x08) >> 3); + tdlsSetupReq.QOSCapsStation.acbk_uapsd = + ((pMac->lim.gLimTDLSUapsdMask & 0x04) >> 2); + tdlsSetupReq.QOSCapsStation.acvi_uapsd = + ((pMac->lim.gLimTDLSUapsdMask & 0x02) >> 1); + tdlsSetupReq.QOSCapsStation.acvo_uapsd = + (pMac->lim.gLimTDLSUapsdMask & 0x01); + } + + /* + * we will always try to init TDLS link with 11n capabilities + * let TDLS setup response to come, and we will set our caps based + * of peer caps + */ + + wlan_cfg_get_int(pMac, WNI_CFG_DOT11_MODE, &selfDot11Mode); + + /* Populate HT/VHT Capabilities */ + populate_dot11f_tdls_ht_vht_cap(pMac, selfDot11Mode, &tdlsSetupReq.HTCaps, + &tdlsSetupReq.VHTCaps, psessionEntry); + + /* Populate AID */ + populate_dotf_tdls_vht_aid(pMac, selfDot11Mode, peer_mac, + &tdlsSetupReq.AID, psessionEntry); + + /* Populate TDLS offchannel param only if offchannel is enabled + * and TDLS Channel Switching is not prohibited by AP in ExtCap + * IE in assoc/re-assoc response. + */ + if ((1 == pMac->lim.gLimTDLSOffChannelEnabled) && + (!psessionEntry->tdls_chan_swit_prohibited)) { + populate_dot11f_tdls_offchannel_params(pMac, psessionEntry, + &tdlsSetupReq.SuppChannels, + &tdlsSetupReq. + SuppOperatingClasses); + if (pMac->roam.configParam.bandCapability != eCSR_BAND_24) { + tdlsSetupReq.ht2040_bss_coexistence.present = 1; + tdlsSetupReq.ht2040_bss_coexistence.info_request = 1; + } + } else { + lim_log(pMac, LOG1, + FL("TDLS offchan not enabled, or channel switch prohibited by AP, gLimTDLSOffChannelEnabled (%d), tdls_chan_swit_prohibited (%d)"), + pMac->lim.gLimTDLSOffChannelEnabled, + psessionEntry->tdls_chan_swit_prohibited); + } + /* + * now we pack it. First, how much space are we going to need? + */ + status = dot11f_get_packed_tdls_setup_req_size(pMac, &tdlsSetupReq, + &nPayload); + if (DOT11F_FAILED(status)) { + lim_log(pMac, LOGE, + FL( + "Failed to calculate the packed size for a Setup Request (0x%08x)." + ), + status); + /* We'll fall back on the worst case scenario: */ + nPayload = sizeof(tDot11fProbeRequest); + } else if (DOT11F_WARNED(status)) { + lim_log(pMac, LOGW, + FL( + "There were warnings while calculating the packed size for a Setup Request (0x%08x)." + ), + status); + } + + /* + * This frame is going out from PE as data frames with special ethertype + * 89-0d. + * 8 bytes of RFC 1042 header + */ + + nBytes = nPayload + ((IS_QOS_ENABLED(psessionEntry)) + ? sizeof(tSirMacDataHdr3a) : + sizeof(tSirMacMgmtHdr)) + + sizeof(eth_890d_header) + + PAYLOAD_TYPE_TDLS_SIZE + addIeLen; + + /* Ok-- try to allocate memory from MGMT PKT pool */ + qdf_status = cds_packet_alloc((uint16_t) nBytes, (void **)&pFrame, + (void **)&pPacket); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + lim_log(pMac, LOGE, + FL( + "Failed to allocate %d bytes for a TDLS Setup Request." + ), + nBytes); + return eSIR_MEM_ALLOC_FAILED; + } + + /* zero out the memory */ + qdf_mem_set(pFrame, nBytes, 0); + + /* + * IE formation, memory allocation is completed, Now form TDLS discovery + * request frame + */ + + /* fill out the buffer descriptor */ + + header_offset = lim_prepare_tdls_frame_header(pMac, pFrame, + LINK_IDEN_ADDR_OFFSET(tdlsSetupReq), + TDLS_LINK_AP, TDLS_INITIATOR, + (ac == WIFI_AC_VI) ? TID_AC_VI : TID_AC_BK, + psessionEntry); + + lim_log(pMac, LOGW, + FL( + "SupportedChnlWidth %x rxMCSMap %x rxMCSMap %x txSupDataRate %x" + ), + tdlsSetupReq.VHTCaps.supportedChannelWidthSet, + tdlsSetupReq.VHTCaps.rxMCSMap, + tdlsSetupReq.VHTCaps.txMCSMap, + tdlsSetupReq.VHTCaps.txSupDataRate); + + status = dot11f_pack_tdls_setup_req(pMac, &tdlsSetupReq, pFrame + + header_offset, nPayload, &nPayload); + + if (DOT11F_FAILED(status)) { + lim_log(pMac, LOGE, + FL("Failed to pack a TDLS Setup request (0x%08x)."), + status); + cds_packet_free((void *)pPacket); + return eSIR_FAILURE; + } else if (DOT11F_WARNED(status)) { + lim_log(pMac, LOGW, + FL( + "There were warnings while packing TDLS Setup Request (0x%08x)." + ), + status); + } + /* Copy the additional IE. */ + /* TODO : addIe is added at the end of the frame. This means it doesnt */ + /* follow the order. This should be ok, but we should consider changing this */ + /* if there is any IOT issue. */ + if (addIeLen != 0) { + lim_log(pMac, LOG1, FL("Copy Additional Ie Len = %d"), + addIeLen); + qdf_mem_copy(pFrame + header_offset + nPayload, addIe, + addIeLen); + } + + lim_log(pMac, LOG1, + FL("[TDLS] action %d (%s) -AP-> OTA peer="MAC_ADDRESS_STR), + SIR_MAC_TDLS_SETUP_REQ, + lim_trace_tdls_action_string(SIR_MAC_TDLS_SETUP_REQ), + MAC_ADDR_ARRAY(peer_mac.bytes)); + + pMac->lim.tdls_frm_session_id = psessionEntry->smeSessionId; + + qdf_status = wma_tx_frame_with_tx_complete_send(pMac, pPacket, + (uint16_t) nBytes, + TID_AC_VI, + pFrame, + smeSessionId, true); + + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + pMac->lim.tdls_frm_session_id = NO_SESSION; + lim_log(pMac, LOGE, + FL("could not send TDLS Setup Request frame!")); + return eSIR_FAILURE; + } + + return eSIR_SUCCESS; + +} + +/* + * Send TDLS Teardown frame on Direct link or AP link, depends on reason code. + */ +static +tSirRetStatus lim_send_tdls_teardown_frame(tpAniSirGlobal pMac, + struct qdf_mac_addr peer_mac, + uint16_t reason, + uint8_t responder, + tpPESession psessionEntry, + uint8_t *addIe, uint16_t addIeLen, + enum sir_wifi_traffic_ac ac) +{ + tDot11fTDLSTeardown teardown; + uint32_t status = 0; + uint32_t nPayload = 0; + uint32_t nBytes = 0; + uint32_t header_offset = 0; + uint8_t *pFrame; + void *pPacket; + QDF_STATUS qdf_status; +#ifndef NO_PAD_TDLS_MIN_8023_SIZE + uint32_t padLen = 0; +#endif + uint8_t smeSessionId = 0; + tpDphHashNode sta_ds; + uint16_t aid = 0; + uint8_t qos_mode = 0; + uint8_t tdls_link_type; + + if (NULL == psessionEntry) { + lim_log(pMac, LOGE, FL("psessionEntry is NULL")); + return eSIR_FAILURE; + } + smeSessionId = psessionEntry->smeSessionId; + /* + * The scheme here is to fill out a 'tDot11fProbeRequest' structure + * and then hand it off to 'dot11f_pack_probe_request' (for + * serialization). We start by zero-initializing the structure: + */ + qdf_mem_set((uint8_t *) &teardown, sizeof(tDot11fTDLSTeardown), 0); + teardown.Category.category = SIR_MAC_ACTION_TDLS; + teardown.Action.action = SIR_MAC_TDLS_TEARDOWN; + teardown.Reason.code = reason; + + populate_dot11f_link_iden(pMac, psessionEntry, &teardown.LinkIdentifier, + peer_mac, + (responder == + true) ? TDLS_RESPONDER : TDLS_INITIATOR); + + /* + * now we pack it. First, how much space are we going to need? + */ + status = dot11f_get_packed_tdls_teardown_size(pMac, &teardown, &nPayload); + if (DOT11F_FAILED(status)) { + lim_log(pMac, LOGE, + FL( + "Failed to calculate the packed size for a discovery Request (0x%08x)." + ), + status); + /* We'll fall back on the worst case scenario: */ + nPayload = sizeof(tDot11fProbeRequest); + } else if (DOT11F_WARNED(status)) { + lim_log(pMac, LOGW, + FL( + "There were warnings while calculating the packed size for a discovery Request (0x%08x)." + ), + status); + } + + /* + * This frame is going out from PE as data frames with special ethertype + * 89-0d. + * 8 bytes of RFC 1042 header + */ + sta_ds = dph_lookup_hash_entry(pMac, psessionEntry->bssId, &aid, + &psessionEntry->dph.dphHashTable); + if (sta_ds) + qos_mode = sta_ds->qosMode; + tdls_link_type = (reason == eSIR_MAC_TDLS_TEARDOWN_PEER_UNREACHABLE) + ? TDLS_LINK_AP : TDLS_LINK_DIRECT; + nBytes = nPayload + (((IS_QOS_ENABLED(psessionEntry) && + (tdls_link_type == TDLS_LINK_AP)) || + ((tdls_link_type == TDLS_LINK_DIRECT) && qos_mode)) + ? sizeof(tSirMacDataHdr3a) : + sizeof(tSirMacMgmtHdr)) + + sizeof(eth_890d_header) + + PAYLOAD_TYPE_TDLS_SIZE + addIeLen; + +#ifndef NO_PAD_TDLS_MIN_8023_SIZE + /* IOT issue with some AP : some AP doesn't like the data packet size < minimum 802.3 frame length (64) + Hence AP itself padding some bytes, which caused teardown packet is dropped at + receiver side. To avoid such IOT issue, we added some extra bytes to meet data frame size >= 64 + */ + if (nPayload + PAYLOAD_TYPE_TDLS_SIZE < MIN_IEEE_8023_SIZE) { + padLen = + MIN_IEEE_8023_SIZE - (nPayload + PAYLOAD_TYPE_TDLS_SIZE); + + /* if padLen is less than minimum vendorSpecific (5), pad up to 5 */ + if (padLen < MIN_VENDOR_SPECIFIC_IE_SIZE) + padLen = MIN_VENDOR_SPECIFIC_IE_SIZE; + + nBytes += padLen; + } +#endif + + /* Ok-- try to allocate memory from MGMT PKT pool */ + qdf_status = cds_packet_alloc((uint16_t) nBytes, (void **)&pFrame, + (void **)&pPacket); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + lim_log(pMac, LOGE, + FL( + "Failed to allocate %d bytes for a TDLS Teardown Frame." + ), + nBytes); + return eSIR_MEM_ALLOC_FAILED; + } + + /* zero out the memory */ + qdf_mem_set(pFrame, nBytes, 0); + + /* + * IE formation, memory allocation is completed, Now form TDLS discovery + * request frame + */ + + /* fill out the buffer descriptor */ + lim_log(pMac, LOGE, FL("Reason of TDLS Teardown: %d"), reason); + header_offset = lim_prepare_tdls_frame_header(pMac, pFrame, + LINK_IDEN_ADDR_OFFSET(teardown), + (reason == eSIR_MAC_TDLS_TEARDOWN_PEER_UNREACHABLE) ? + TDLS_LINK_AP : TDLS_LINK_DIRECT, + (responder == true) ? TDLS_RESPONDER : TDLS_INITIATOR, + (ac == WIFI_AC_VI) ? TID_AC_VI : TID_AC_BK, + psessionEntry); + + status = dot11f_pack_tdls_teardown(pMac, &teardown, pFrame + + header_offset, nPayload, &nPayload); + + if (DOT11F_FAILED(status)) { + lim_log(pMac, LOGE, + FL("Failed to pack a TDLS Teardown frame (0x%08x)."), + status); + cds_packet_free((void *)pPacket); + return eSIR_FAILURE; + } else if (DOT11F_WARNED(status)) { + lim_log(pMac, LOGW, + FL( + "There were warnings while packing TDLS Teardown frame (0x%08x)." + ), + status); + } + + if (addIeLen != 0) { + lim_log(pMac, LOGW, + FL("Copy Additional Ie Len = %d"), addIeLen); + qdf_mem_copy(pFrame + header_offset + nPayload, addIe, + addIeLen); + } +#ifndef NO_PAD_TDLS_MIN_8023_SIZE + if (padLen != 0) { + /* QCOM VENDOR OUI = { 0x00, 0xA0, 0xC6, type = 0x0000 }; */ + uint8_t *padVendorSpecific = + pFrame + header_offset + nPayload + addIeLen; + /* make QCOM_VENDOR_OUI, and type = 0x0000, and all the payload to be zero */ + padVendorSpecific[0] = 221; + padVendorSpecific[1] = padLen - 2; + padVendorSpecific[2] = 0x00; + padVendorSpecific[3] = 0xA0; + padVendorSpecific[4] = 0xC6; + + lim_log(pMac, LOG1, FL("Padding Vendor Specific Ie Len = %d"), + padLen); + + /* padding zero if more than 5 bytes are required */ + if (padLen > MIN_VENDOR_SPECIFIC_IE_SIZE) + qdf_mem_set(pFrame + header_offset + nPayload + + addIeLen + MIN_VENDOR_SPECIFIC_IE_SIZE, + padLen - MIN_VENDOR_SPECIFIC_IE_SIZE, 0); + } +#endif + lim_log(pMac, LOG1, + FL("[TDLS] action %d (%s) -%s-> OTA peer="MAC_ADDRESS_STR), + SIR_MAC_TDLS_TEARDOWN, + lim_trace_tdls_action_string(SIR_MAC_TDLS_TEARDOWN), + ((reason == eSIR_MAC_TDLS_TEARDOWN_PEER_UNREACHABLE) ? "AP" : + "DIRECT"), + MAC_ADDR_ARRAY(peer_mac.bytes)); + + pMac->lim.tdls_frm_session_id = psessionEntry->smeSessionId; + + qdf_status = wma_tx_frame_with_tx_complete_send(pMac, pPacket, + (uint16_t) nBytes, + TID_AC_VI, + pFrame, + smeSessionId, + (reason == eSIR_MAC_TDLS_TEARDOWN_PEER_UNREACHABLE) + ? true : false); + + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + pMac->lim.tdls_frm_session_id = NO_SESSION; + lim_log(pMac, LOGE, + FL("could not send TDLS Teardown frame")); + return eSIR_FAILURE; + + } + return eSIR_SUCCESS; +} + +/* + * Send Setup RSP frame on AP link. + */ +static tSirRetStatus lim_send_tdls_setup_rsp_frame(tpAniSirGlobal pMac, + struct qdf_mac_addr peer_mac, + uint8_t dialog, + tpPESession psessionEntry, + etdlsLinkSetupStatus setupStatus, + uint8_t *addIe, + uint16_t addIeLen, + enum sir_wifi_traffic_ac ac) +{ + tDot11fTDLSSetupRsp tdlsSetupRsp; + uint32_t status = 0; + uint16_t caps = 0; + uint32_t nPayload = 0; + uint32_t header_offset = 0; + uint32_t nBytes = 0; + uint8_t *pFrame; + void *pPacket; + QDF_STATUS qdf_status; + uint32_t selfDot11Mode; +/* Placeholder to support different channel bonding mode of TDLS than AP. */ +/* Today, WNI_CFG_CHANNEL_BONDING_MODE will be overwritten when connecting to AP */ +/* To support this feature, we need to introduce WNI_CFG_TDLS_CHANNEL_BONDING_MODE */ +/* As of now, we hardcoded to max channel bonding of dot11Mode (i.e HT80 for 11ac/HT40 for 11n) */ +/* uint32_t tdlsChannelBondingMode; */ + uint8_t smeSessionId = 0; + + if (NULL == psessionEntry) { + lim_log(pMac, LOGE, FL("psessionEntry is NULL")); + return eSIR_FAILURE; + } + smeSessionId = psessionEntry->smeSessionId; + + /* + * The scheme here is to fill out a 'tDot11fProbeRequest' structure + * and then hand it off to 'dot11f_pack_probe_request' (for + * serialization). We start by zero-initializing the structure: + */ + qdf_mem_set((uint8_t *) &tdlsSetupRsp, sizeof(tDot11fTDLSSetupRsp), 0); + + /* + * setup Fixed fields, + */ + tdlsSetupRsp.Category.category = SIR_MAC_ACTION_TDLS; + tdlsSetupRsp.Action.action = SIR_MAC_TDLS_SETUP_RSP; + tdlsSetupRsp.DialogToken.token = dialog; + + populate_dot11f_link_iden(pMac, psessionEntry, + &tdlsSetupRsp.LinkIdentifier, peer_mac, + TDLS_RESPONDER); + + if (cfg_get_capability_info(pMac, &caps, psessionEntry) != eSIR_SUCCESS) { + /* + * Could not get Capabilities value + * from CFG. Log error. + */ + lim_log(pMac, LOGE, + FL("could not retrieve Capabilities value")); + } + swap_bit_field16(caps, (uint16_t *) &tdlsSetupRsp.Capabilities); + + /* populate supported rate and ext supported rate IE */ + if (eSIR_FAILURE == populate_dot11f_rates_tdls(pMac, + &tdlsSetupRsp.SuppRates, + &tdlsSetupRsp.ExtSuppRates, + psessionEntry->currentOperChannel)) + lim_log(pMac, LOGE, + FL("could not populate supported data rates")); + + /* Populate extended capability IE */ + populate_dot11f_tdls_ext_capability(pMac, + psessionEntry, + &tdlsSetupRsp.ExtCap); + + if (1 == pMac->lim.gLimTDLSWmmMode) { + uint32_t val = 0; + + lim_log(pMac, LOG1, + FL("populate WMM IE in Setup Response frame")); + /* include WMM IE */ + tdlsSetupRsp.WMMInfoStation.version = SIR_MAC_OUI_VERSION_1; + tdlsSetupRsp.WMMInfoStation.acvo_uapsd = + (pMac->lim.gLimTDLSUapsdMask & 0x01); + tdlsSetupRsp.WMMInfoStation.acvi_uapsd = + ((pMac->lim.gLimTDLSUapsdMask & 0x02) >> 1); + tdlsSetupRsp.WMMInfoStation.acbk_uapsd = + ((pMac->lim.gLimTDLSUapsdMask & 0x04) >> 2); + tdlsSetupRsp.WMMInfoStation.acbe_uapsd = + ((pMac->lim.gLimTDLSUapsdMask & 0x08) >> 3); + if (wlan_cfg_get_int(pMac, WNI_CFG_MAX_SP_LENGTH, &val) != + eSIR_SUCCESS) + lim_log(pMac, LOGE, + FL("could not retrieve Max SP Length")); + tdlsSetupRsp.WMMInfoStation.max_sp_length = (uint8_t) val; + tdlsSetupRsp.WMMInfoStation.present = 1; + } else { + /* + * TODO: we need to see if we have to support conditions where + * we have EDCA parameter info element is needed a) if we need + * different QOS parameters for off channel operations or QOS + * is not supported on AP link and we wanted to QOS on direct + * link. + */ + /* Populate QOS info, needed for Peer U-APSD session */ + /* + * TODO: Now hardcoded, because + * populate_dot11f_qos_caps_station() depends on AP's + * capability, and TDLS doesn't want to depend on AP's + * capability + */ + lim_log(pMac, LOG1, + FL("populate QOS IE in Setup Response frame")); + tdlsSetupRsp.QOSCapsStation.present = 1; + tdlsSetupRsp.QOSCapsStation.max_sp_length = 0; + tdlsSetupRsp.QOSCapsStation.qack = 0; + tdlsSetupRsp.QOSCapsStation.acbe_uapsd = + ((pMac->lim.gLimTDLSUapsdMask & 0x08) >> 3); + tdlsSetupRsp.QOSCapsStation.acbk_uapsd = + ((pMac->lim.gLimTDLSUapsdMask & 0x04) >> 2); + tdlsSetupRsp.QOSCapsStation.acvi_uapsd = + ((pMac->lim.gLimTDLSUapsdMask & 0x02) >> 1); + tdlsSetupRsp.QOSCapsStation.acvo_uapsd = + (pMac->lim.gLimTDLSUapsdMask & 0x01); + } + + wlan_cfg_get_int(pMac, WNI_CFG_DOT11_MODE, &selfDot11Mode); + + /* Populate HT/VHT Capabilities */ + populate_dot11f_tdls_ht_vht_cap(pMac, selfDot11Mode, &tdlsSetupRsp.HTCaps, + &tdlsSetupRsp.VHTCaps, psessionEntry); + + /* Populate AID */ + populate_dotf_tdls_vht_aid(pMac, selfDot11Mode, peer_mac, + &tdlsSetupRsp.AID, psessionEntry); + + /* Populate TDLS offchannel param only if offchannel is enabled + * and TDLS Channel Switching is not prohibited by AP in ExtCap + * IE in assoc/re-assoc response. + */ + if ((1 == pMac->lim.gLimTDLSOffChannelEnabled) && + (!psessionEntry->tdls_chan_swit_prohibited)) { + populate_dot11f_tdls_offchannel_params(pMac, psessionEntry, + &tdlsSetupRsp.SuppChannels, + &tdlsSetupRsp. + SuppOperatingClasses); + if (pMac->roam.configParam.bandCapability != eCSR_BAND_24) { + tdlsSetupRsp.ht2040_bss_coexistence.present = 1; + tdlsSetupRsp.ht2040_bss_coexistence.info_request = 1; + } + } else { + lim_log(pMac, LOG1, + FL("TDLS offchan not enabled, or channel switch prohibited by AP, gLimTDLSOffChannelEnabled (%d), tdls_chan_swit_prohibited (%d)"), + pMac->lim.gLimTDLSOffChannelEnabled, + psessionEntry->tdls_chan_swit_prohibited); + } + tdlsSetupRsp.Status.status = setupStatus; + /* + * now we pack it. First, how much space are we going to need? + */ + status = dot11f_get_packed_tdls_setup_rsp_size(pMac, &tdlsSetupRsp, + &nPayload); + if (DOT11F_FAILED(status)) { + lim_log(pMac, LOGE, + FL( + "Failed to calculate the packed size for a Setup Response (0x%08x)." + ), + status); + /* We'll fall back on the worst case scenario: */ + nPayload = sizeof(tDot11fProbeRequest); + } else if (DOT11F_WARNED(status)) { + lim_log(pMac, LOGW, + FL( + "There were warnings while calculating the packed size for Setup Response (0x%08x)." + ), + status); + } + + /* + * This frame is going out from PE as data frames with special ethertype + * 89-0d. + * 8 bytes of RFC 1042 header + */ + + nBytes = nPayload + ((IS_QOS_ENABLED(psessionEntry)) + ? sizeof(tSirMacDataHdr3a) : + sizeof(tSirMacMgmtHdr)) + + sizeof(eth_890d_header) + + PAYLOAD_TYPE_TDLS_SIZE + addIeLen; + + /* Ok-- try to allocate memory from MGMT PKT pool */ + qdf_status = cds_packet_alloc((uint16_t) nBytes, (void **)&pFrame, + (void **)&pPacket); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + lim_log(pMac, LOGE, + FL( + "Failed to allocate %d bytes for a TDLS Setup Response." + ), + nBytes); + return eSIR_MEM_ALLOC_FAILED; + } + + /* zero out the memory */ + qdf_mem_set(pFrame, nBytes, 0); + + /* + * IE formation, memory allocation is completed, Now form TDLS discovery + * request frame + */ + + /* fill out the buffer descriptor */ + + header_offset = lim_prepare_tdls_frame_header(pMac, pFrame, + LINK_IDEN_ADDR_OFFSET(tdlsSetupRsp), TDLS_LINK_AP, + TDLS_RESPONDER, + (ac == WIFI_AC_VI) ? TID_AC_VI : TID_AC_BK, + psessionEntry); + + lim_log(pMac, LOG1, + FL( + "SupportedChnlWidth %x rxMCSMap %x rxMCSMap %x txSupDataRate %x" + ), + tdlsSetupRsp.VHTCaps.supportedChannelWidthSet, + tdlsSetupRsp.VHTCaps.rxMCSMap, + tdlsSetupRsp.VHTCaps.txMCSMap, + tdlsSetupRsp.VHTCaps.txSupDataRate); + status = dot11f_pack_tdls_setup_rsp(pMac, &tdlsSetupRsp, + pFrame + header_offset, + nPayload, &nPayload); + + if (DOT11F_FAILED(status)) { + lim_log(pMac, LOGE, + FL("Failed to pack a TDLS Setup Response (0x%08x)."), + status); + cds_packet_free((void *)pPacket); + return eSIR_FAILURE; + } else if (DOT11F_WARNED(status)) { + lim_log(pMac, LOGW, + FL( + "There were warnings while packing TDLS Setup Response (0x%08x)." + ), + status); + } + /* Copy the additional IE. */ + /* TODO : addIe is added at the end of the frame. This means it doesnt */ + /* follow the order. This should be ok, but we should consider changing this */ + /* if there is any IOT issue. */ + if (addIeLen != 0) { + qdf_mem_copy(pFrame + header_offset + nPayload, addIe, + addIeLen); + } + + lim_log(pMac, LOG1, + FL("[TDLS] action %d (%s) -AP-> OTA peer="MAC_ADDRESS_STR), + SIR_MAC_TDLS_SETUP_RSP, + lim_trace_tdls_action_string(SIR_MAC_TDLS_SETUP_RSP), + MAC_ADDR_ARRAY(peer_mac.bytes)); + + pMac->lim.tdls_frm_session_id = psessionEntry->smeSessionId; + + qdf_status = wma_tx_frame_with_tx_complete_send(pMac, pPacket, + (uint16_t) nBytes, + TID_AC_VI, + pFrame, + smeSessionId, true); + + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + pMac->lim.tdls_frm_session_id = NO_SESSION; + lim_log(pMac, LOGE, + FL("could not send TDLS Dis Request frame!")); + return eSIR_FAILURE; + } + + return eSIR_SUCCESS; +} + +/* + * Send TDLS setup CNF frame on AP link + */ +static +tSirRetStatus lim_send_tdls_link_setup_cnf_frame(tpAniSirGlobal pMac, + struct qdf_mac_addr peer_mac, + uint8_t dialog, + uint32_t peerCapability, + tpPESession psessionEntry, + uint8_t *addIe, + uint16_t addIeLen, + enum sir_wifi_traffic_ac ac) +{ + tDot11fTDLSSetupCnf tdlsSetupCnf; + uint32_t status = 0; + uint32_t nPayload = 0; + uint32_t nBytes = 0; + uint32_t header_offset = 0; + uint8_t *pFrame; + void *pPacket; + QDF_STATUS qdf_status; +#ifndef NO_PAD_TDLS_MIN_8023_SIZE + uint32_t padLen = 0; +#endif + uint8_t smeSessionId = 0; + + /* + * The scheme here is to fill out a 'tDot11fProbeRequest' structure + * and then hand it off to 'dot11f_pack_probe_request' (for + * serialization). We start by zero-initializing the structure: + */ + smeSessionId = psessionEntry->smeSessionId; + + qdf_mem_set((uint8_t *) &tdlsSetupCnf, sizeof(tDot11fTDLSSetupCnf), 0); + + /* + * setup Fixed fields, + */ + tdlsSetupCnf.Category.category = SIR_MAC_ACTION_TDLS; + tdlsSetupCnf.Action.action = SIR_MAC_TDLS_SETUP_CNF; + tdlsSetupCnf.DialogToken.token = dialog; + + populate_dot11f_link_iden(pMac, psessionEntry, + &tdlsSetupCnf.LinkIdentifier, peer_mac, + TDLS_INITIATOR); + /* + * TODO: we need to see if we have to support conditions where we have + * EDCA parameter info element is needed a) if we need different QOS + * parameters for off channel operations or QOS is not supported on + * AP link and we wanted to QOS on direct link. + */ + + /* Check self and peer WMM capable */ + if ((1 == pMac->lim.gLimTDLSWmmMode) && + (CHECK_BIT(peerCapability, TDLS_PEER_WMM_CAP))) { + lim_log(pMac, LOG1, FL("populate WMM praram in Setup Confirm")); + populate_dot11f_wmm_params(pMac, &tdlsSetupCnf.WMMParams, + psessionEntry); + } + + /* Check peer is VHT capable */ + if (CHECK_BIT(peerCapability, TDLS_PEER_VHT_CAP)) { + populate_dot11f_vht_operation(pMac, + psessionEntry, + &tdlsSetupCnf.VHTOperation); + populate_dot11f_ht_info(pMac, &tdlsSetupCnf.HTInfo, psessionEntry); + } else if (CHECK_BIT(peerCapability, TDLS_PEER_HT_CAP)) { /* Check peer is HT capable */ + populate_dot11f_ht_info(pMac, &tdlsSetupCnf.HTInfo, psessionEntry); + } + + /* + * now we pack it. First, how much space are we going to need? + */ + status = dot11f_get_packed_tdls_setup_cnf_size(pMac, &tdlsSetupCnf, + &nPayload); + if (DOT11F_FAILED(status)) { + lim_log(pMac, LOGE, + FL( + "Failed to calculate the packed size for a Setup Confirm (0x%08x)." + ), + status); + /* We'll fall back on the worst case scenario: */ + nPayload = sizeof(tDot11fProbeRequest); + } else if (DOT11F_WARNED(status)) { + lim_log(pMac, LOGW, + FL( + "There were warnings while calculating the packed size for Setup Confirm (0x%08x)." + ), + status); + } + + /* + * This frame is going out from PE as data frames with special ethertype + * 89-0d. + * 8 bytes of RFC 1042 header + */ + + nBytes = nPayload + ((IS_QOS_ENABLED(psessionEntry)) + ? sizeof(tSirMacDataHdr3a) : + sizeof(tSirMacMgmtHdr)) + + sizeof(eth_890d_header) + + PAYLOAD_TYPE_TDLS_SIZE + addIeLen; + +#ifndef NO_PAD_TDLS_MIN_8023_SIZE + /* IOT issue with some AP : some AP doesn't like the data packet size < minimum 802.3 frame length (64) + Hence AP itself padding some bytes, which caused teardown packet is dropped at + receiver side. To avoid such IOT issue, we added some extra bytes to meet data frame size >= 64 + */ + if (nPayload + PAYLOAD_TYPE_TDLS_SIZE < MIN_IEEE_8023_SIZE) { + padLen = + MIN_IEEE_8023_SIZE - (nPayload + PAYLOAD_TYPE_TDLS_SIZE); + + /* if padLen is less than minimum vendorSpecific (5), pad up to 5 */ + if (padLen < MIN_VENDOR_SPECIFIC_IE_SIZE) + padLen = MIN_VENDOR_SPECIFIC_IE_SIZE; + + nBytes += padLen; + } +#endif + + /* Ok-- try to allocate memory from MGMT PKT pool */ + qdf_status = cds_packet_alloc((uint16_t) nBytes, (void **)&pFrame, + (void **)&pPacket); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + lim_log(pMac, LOGE, + FL( + "Failed to allocate %d bytes for a TDLS Setup Confirm." + ), + nBytes); + return eSIR_MEM_ALLOC_FAILED; + } + + /* zero out the memory */ + qdf_mem_set(pFrame, nBytes, 0); + + /* + * IE formation, memory allocation is completed, Now form TDLS discovery + * request frame + */ + + /* fill out the buffer descriptor */ + + header_offset = lim_prepare_tdls_frame_header(pMac, pFrame, + LINK_IDEN_ADDR_OFFSET(tdlsSetupCnf), + TDLS_LINK_AP, + TDLS_INITIATOR, + (ac == WIFI_AC_VI) ? TID_AC_VI : TID_AC_BK, + psessionEntry); + + status = dot11f_pack_tdls_setup_cnf(pMac, &tdlsSetupCnf, pFrame + + header_offset, nPayload, &nPayload); + + if (DOT11F_FAILED(status)) { + lim_log(pMac, LOGE, + FL("Failed to pack a TDLS discovery req (0x%08x)."), + status); + cds_packet_free((void *)pPacket); + return eSIR_FAILURE; + } else if (DOT11F_WARNED(status)) { + lim_log(pMac, LOGW, + FL( + "There were warnings while packing TDLS Discovery Request (0x%08x)." + ), + status); + } + /* Copy the additional IE. */ + /* TODO : addIe is added at the end of the frame. This means it doesnt */ + /* follow the order. This should be ok, but we should consider changing this */ + /* if there is any IOT issue. */ + if (addIeLen != 0) { + qdf_mem_copy(pFrame + header_offset + nPayload, addIe, + addIeLen); + } +#ifndef NO_PAD_TDLS_MIN_8023_SIZE + if (padLen != 0) { + /* QCOM VENDOR OUI = { 0x00, 0xA0, 0xC6, type = 0x0000 }; */ + uint8_t *padVendorSpecific = + pFrame + header_offset + nPayload + addIeLen; + /* make QCOM_VENDOR_OUI, and type = 0x0000, and all the payload to be zero */ + padVendorSpecific[0] = 221; + padVendorSpecific[1] = padLen - 2; + padVendorSpecific[2] = 0x00; + padVendorSpecific[3] = 0xA0; + padVendorSpecific[4] = 0xC6; + + lim_log(pMac, LOG1, FL("Padding Vendor Specific Ie Len = %d"), + padLen); + + /* padding zero if more than 5 bytes are required */ + if (padLen > MIN_VENDOR_SPECIFIC_IE_SIZE) + qdf_mem_set(pFrame + header_offset + nPayload + + addIeLen + MIN_VENDOR_SPECIFIC_IE_SIZE, + padLen - MIN_VENDOR_SPECIFIC_IE_SIZE, 0); + } +#endif + + lim_log(pMac, LOG1, + FL("[TDLS] action %d (%s) -AP-> OTA peer="MAC_ADDRESS_STR), + SIR_MAC_TDLS_SETUP_CNF, + lim_trace_tdls_action_string(SIR_MAC_TDLS_SETUP_CNF), + MAC_ADDR_ARRAY(peer_mac.bytes)); + + pMac->lim.tdls_frm_session_id = psessionEntry->smeSessionId; + + qdf_status = wma_tx_frame_with_tx_complete_send(pMac, pPacket, + (uint16_t) nBytes, + TID_AC_VI, + pFrame, + smeSessionId, true); + + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + pMac->lim.tdls_frm_session_id = NO_SESSION; + lim_log(pMac, LOGE, + FL("could not send TDLS Setup Confirm frame")); + return eSIR_FAILURE; + + } + + return eSIR_SUCCESS; +} + +/* This Function is similar to populate_dot11f_ht_caps, except that the HT Capabilities + * are considered from the AddStaReq rather from the cfg.dat as in populate_dot11f_ht_caps + */ +static tSirRetStatus lim_tdls_populate_dot11f_ht_caps(tpAniSirGlobal pMac, + tpPESession psessionEntry, + tSirTdlsAddStaReq * + pTdlsAddStaReq, + tDot11fIEHTCaps *pDot11f) +{ + uint32_t nCfgValue; + uint8_t nCfgValue8; + tSirMacHTParametersInfo *pHTParametersInfo; + union { + uint16_t nCfgValue16; + tSirMacHTCapabilityInfo htCapInfo; + tSirMacExtendedHTCapabilityInfo extHtCapInfo; + } uHTCapabilityInfo; + + tSirMacTxBFCapabilityInfo *pTxBFCapabilityInfo; + tSirMacASCapabilityInfo *pASCapabilityInfo; + + nCfgValue = pTdlsAddStaReq->htCap.capInfo; + + uHTCapabilityInfo.nCfgValue16 = nCfgValue & 0xFFFF; + + pDot11f->advCodingCap = uHTCapabilityInfo.htCapInfo.advCodingCap; + pDot11f->mimoPowerSave = uHTCapabilityInfo.htCapInfo.mimoPowerSave; + pDot11f->greenField = uHTCapabilityInfo.htCapInfo.greenField; + pDot11f->shortGI20MHz = uHTCapabilityInfo.htCapInfo.shortGI20MHz; + pDot11f->shortGI40MHz = uHTCapabilityInfo.htCapInfo.shortGI40MHz; + pDot11f->txSTBC = uHTCapabilityInfo.htCapInfo.txSTBC; + pDot11f->rxSTBC = uHTCapabilityInfo.htCapInfo.rxSTBC; + pDot11f->delayedBA = uHTCapabilityInfo.htCapInfo.delayedBA; + pDot11f->maximalAMSDUsize = + uHTCapabilityInfo.htCapInfo.maximalAMSDUsize; + pDot11f->dsssCckMode40MHz = + uHTCapabilityInfo.htCapInfo.dsssCckMode40MHz; + pDot11f->psmp = uHTCapabilityInfo.htCapInfo.psmp; + pDot11f->stbcControlFrame = + uHTCapabilityInfo.htCapInfo.stbcControlFrame; + pDot11f->lsigTXOPProtection = + uHTCapabilityInfo.htCapInfo.lsigTXOPProtection; + + /* + * All sessionized entries will need the check below + * Only in case of NO session + */ + if (psessionEntry == NULL) { + pDot11f->supportedChannelWidthSet = + uHTCapabilityInfo.htCapInfo.supportedChannelWidthSet; + } else { + pDot11f->supportedChannelWidthSet = + psessionEntry->htSupportedChannelWidthSet; + } + + /* Ensure that shortGI40MHz is Disabled if supportedChannelWidthSet is + eHT_CHANNEL_WIDTH_20MHZ */ + if (pDot11f->supportedChannelWidthSet == eHT_CHANNEL_WIDTH_20MHZ) { + pDot11f->shortGI40MHz = 0; + } + + lim_log(pMac, LOG1, + FL( + "SupportedChnlWidth: %d, mimoPS: %d, GF: %d, shortGI20:%d, shortGI40: %d, dsssCck: %d" + ), + pDot11f->supportedChannelWidthSet, + pDot11f->mimoPowerSave, + pDot11f->greenField, + pDot11f->shortGI20MHz, + pDot11f->shortGI40MHz, + pDot11f->dsssCckMode40MHz); + + nCfgValue = pTdlsAddStaReq->htCap.ampduParamsInfo; + + nCfgValue8 = (uint8_t) nCfgValue; + pHTParametersInfo = (tSirMacHTParametersInfo *) &nCfgValue8; + + pDot11f->maxRxAMPDUFactor = pHTParametersInfo->maxRxAMPDUFactor; + pDot11f->mpduDensity = pHTParametersInfo->mpduDensity; + pDot11f->reserved1 = pHTParametersInfo->reserved; + + lim_log(pMac, LOG1, FL("AMPDU Param: %x"), nCfgValue); + + qdf_mem_copy(pDot11f->supportedMCSSet, pTdlsAddStaReq->htCap.suppMcsSet, + SIZE_OF_SUPPORTED_MCS_SET); + + nCfgValue = pTdlsAddStaReq->htCap.extendedHtCapInfo; + + uHTCapabilityInfo.nCfgValue16 = nCfgValue & 0xFFFF; + + pDot11f->pco = uHTCapabilityInfo.extHtCapInfo.pco; + pDot11f->transitionTime = uHTCapabilityInfo.extHtCapInfo.transitionTime; + pDot11f->mcsFeedback = uHTCapabilityInfo.extHtCapInfo.mcsFeedback; + + nCfgValue = pTdlsAddStaReq->htCap.txBFCapInfo; + + pTxBFCapabilityInfo = (tSirMacTxBFCapabilityInfo *) &nCfgValue; + pDot11f->txBF = pTxBFCapabilityInfo->txBF; + pDot11f->rxStaggeredSounding = pTxBFCapabilityInfo->rxStaggeredSounding; + pDot11f->txStaggeredSounding = pTxBFCapabilityInfo->txStaggeredSounding; + pDot11f->rxZLF = pTxBFCapabilityInfo->rxZLF; + pDot11f->txZLF = pTxBFCapabilityInfo->txZLF; + pDot11f->implicitTxBF = pTxBFCapabilityInfo->implicitTxBF; + pDot11f->calibration = pTxBFCapabilityInfo->calibration; + pDot11f->explicitCSITxBF = pTxBFCapabilityInfo->explicitCSITxBF; + pDot11f->explicitUncompressedSteeringMatrix = + pTxBFCapabilityInfo->explicitUncompressedSteeringMatrix; + pDot11f->explicitBFCSIFeedback = + pTxBFCapabilityInfo->explicitBFCSIFeedback; + pDot11f->explicitUncompressedSteeringMatrixFeedback = + pTxBFCapabilityInfo->explicitUncompressedSteeringMatrixFeedback; + pDot11f->explicitCompressedSteeringMatrixFeedback = + pTxBFCapabilityInfo->explicitCompressedSteeringMatrixFeedback; + pDot11f->csiNumBFAntennae = pTxBFCapabilityInfo->csiNumBFAntennae; + pDot11f->uncompressedSteeringMatrixBFAntennae = + pTxBFCapabilityInfo->uncompressedSteeringMatrixBFAntennae; + pDot11f->compressedSteeringMatrixBFAntennae = + pTxBFCapabilityInfo->compressedSteeringMatrixBFAntennae; + + nCfgValue = pTdlsAddStaReq->htCap.antennaSelectionInfo; + + nCfgValue8 = (uint8_t) nCfgValue; + + pASCapabilityInfo = (tSirMacASCapabilityInfo *) &nCfgValue8; + pDot11f->antennaSelection = pASCapabilityInfo->antennaSelection; + pDot11f->explicitCSIFeedbackTx = + pASCapabilityInfo->explicitCSIFeedbackTx; + pDot11f->antennaIndicesFeedbackTx = + pASCapabilityInfo->antennaIndicesFeedbackTx; + pDot11f->explicitCSIFeedback = pASCapabilityInfo->explicitCSIFeedback; + pDot11f->antennaIndicesFeedback = + pASCapabilityInfo->antennaIndicesFeedback; + pDot11f->rxAS = pASCapabilityInfo->rxAS; + pDot11f->txSoundingPPDUs = pASCapabilityInfo->txSoundingPPDUs; + + pDot11f->present = pTdlsAddStaReq->htcap_present; + + return eSIR_SUCCESS; + +} + +static tSirRetStatus +lim_tdls_populate_dot11f_vht_caps(tpAniSirGlobal pMac, + tSirTdlsAddStaReq *pTdlsAddStaReq, + tDot11fIEVHTCaps *pDot11f) +{ + uint32_t nCfgValue = 0; + union { + uint32_t nCfgValue32; + tSirMacVHTCapabilityInfo vhtCapInfo; + } uVHTCapabilityInfo; + union { + uint16_t nCfgValue16; + tSirMacVHTTxSupDataRateInfo vhtTxSupDataRateInfo; + tSirMacVHTRxSupDataRateInfo vhtRxsupDataRateInfo; + } uVHTSupDataRateInfo; + + pDot11f->present = pTdlsAddStaReq->vhtcap_present; + + nCfgValue = pTdlsAddStaReq->vhtCap.vhtCapInfo; + uVHTCapabilityInfo.nCfgValue32 = nCfgValue; + + pDot11f->maxMPDULen = uVHTCapabilityInfo.vhtCapInfo.maxMPDULen; + pDot11f->supportedChannelWidthSet = + uVHTCapabilityInfo.vhtCapInfo.supportedChannelWidthSet; + pDot11f->ldpcCodingCap = uVHTCapabilityInfo.vhtCapInfo.ldpcCodingCap; + pDot11f->shortGI80MHz = uVHTCapabilityInfo.vhtCapInfo.shortGI80MHz; + pDot11f->shortGI160and80plus80MHz = + uVHTCapabilityInfo.vhtCapInfo.shortGI160and80plus80MHz; + pDot11f->txSTBC = uVHTCapabilityInfo.vhtCapInfo.txSTBC; + pDot11f->rxSTBC = uVHTCapabilityInfo.vhtCapInfo.rxSTBC; + pDot11f->suBeamFormerCap = 0; + pDot11f->suBeamformeeCap = 0; + pDot11f->csnofBeamformerAntSup = + uVHTCapabilityInfo.vhtCapInfo.csnofBeamformerAntSup; + pDot11f->numSoundingDim = uVHTCapabilityInfo.vhtCapInfo.numSoundingDim; + pDot11f->muBeamformerCap = 0; + pDot11f->muBeamformeeCap = 0; + pDot11f->vhtTXOPPS = uVHTCapabilityInfo.vhtCapInfo.vhtTXOPPS; + pDot11f->htcVHTCap = uVHTCapabilityInfo.vhtCapInfo.htcVHTCap; + pDot11f->maxAMPDULenExp = uVHTCapabilityInfo.vhtCapInfo.maxAMPDULenExp; + pDot11f->vhtLinkAdaptCap = + uVHTCapabilityInfo.vhtCapInfo.vhtLinkAdaptCap; + pDot11f->rxAntPattern = uVHTCapabilityInfo.vhtCapInfo.rxAntPattern; + pDot11f->txAntPattern = uVHTCapabilityInfo.vhtCapInfo.txAntPattern; + pDot11f->reserved1 = uVHTCapabilityInfo.vhtCapInfo.reserved1; + + pDot11f->rxMCSMap = pTdlsAddStaReq->vhtCap.suppMcs.rxMcsMap; + + nCfgValue = pTdlsAddStaReq->vhtCap.suppMcs.rxHighest; + uVHTSupDataRateInfo.nCfgValue16 = nCfgValue & 0xffff; + pDot11f->rxHighSupDataRate = + uVHTSupDataRateInfo.vhtRxsupDataRateInfo.rxSupDataRate; + + pDot11f->txMCSMap = pTdlsAddStaReq->vhtCap.suppMcs.txMcsMap; + + nCfgValue = pTdlsAddStaReq->vhtCap.suppMcs.txHighest; + uVHTSupDataRateInfo.nCfgValue16 = nCfgValue & 0xffff; + pDot11f->txSupDataRate = + uVHTSupDataRateInfo.vhtTxSupDataRateInfo.txSupDataRate; + + pDot11f->reserved3 = uVHTSupDataRateInfo.vhtTxSupDataRateInfo.reserved; + + lim_log_vht_cap(pMac, pDot11f); + + return eSIR_SUCCESS; + +} + +/** + * lim_tdls_populate_matching_rate_set() - populate matching rate set + * + * @mac_ctx - global MAC context + * @stads - station hash entry + * @supp_rate_set - pointer to supported rate set + * @supp_rates_len - length of the supported rates + * @supp_mcs_set - pointer to supported MSC set + * @session_entry - pointer to PE session entry + * @vht_caps - pointer to VHT capability + * + * + * This function gets set of available rates from the config and compare them + * against the set of received supported rates. After the comparison station + * entry's rates is populated with 11A rates and 11B rates. + * + * Return: eSIR_SUCCESS on success, eSIR_FAILURE on failure. + */ +static tSirRetStatus +lim_tdls_populate_matching_rate_set(tpAniSirGlobal mac_ctx, tpDphHashNode stads, + uint8_t *supp_rate_set, + uint8_t supp_rates_len, + uint8_t *supp_mcs_set, + tpPESession session_entry, + tDot11fIEVHTCaps *vht_caps) +{ + tSirMacRateSet temp_rate_set; + uint32_t i, j, val, min, is_a_rate; + tSirMacRateSet temp_rate_set2; + uint32_t phymode; + uint8_t mcsSet[SIZE_OF_SUPPORTED_MCS_SET]; + tpSirSupportedRates rates; + uint8_t a_rateindex = 0; + uint8_t b_rateindex = 0; + uint8_t nss; + is_a_rate = 0; + temp_rate_set2.numRates = 0; + + lim_get_phy_mode(mac_ctx, &phymode, NULL); + + /* get own rate set */ + val = WNI_CFG_OPERATIONAL_RATE_SET_LEN; + if (wlan_cfg_get_str(mac_ctx, WNI_CFG_OPERATIONAL_RATE_SET, + (uint8_t *) &temp_rate_set.rate, + &val) != eSIR_SUCCESS) { + /* Could not get rateset from CFG. Log error. */ + lim_log(mac_ctx, LOGE, FL("could not retrieve rateset")); + val = 0; + } + temp_rate_set.numRates = val; + + if (phymode == WNI_CFG_PHY_MODE_11G) { + /* get own extended rate set */ + val = WNI_CFG_EXTENDED_OPERATIONAL_RATE_SET_LEN; + if (wlan_cfg_get_str(mac_ctx, + WNI_CFG_EXTENDED_OPERATIONAL_RATE_SET, + (uint8_t *) &temp_rate_set2.rate, + &val) != eSIR_SUCCESS) + temp_rate_set2.numRates = val; + } + + if ((temp_rate_set.numRates + temp_rate_set2.numRates) > 12) { + lim_log(mac_ctx, LOGE, FL("more than 12 rates in CFG")); + return eSIR_FAILURE; + } + + /** + * Handling of the rate set IEs is the following: + * - keep only rates that we support and that the station supports + * - sort and the rates into the pSta->rate array + */ + + /* Copy all rates in temp_rate_set, there are 12 rates max */ + for (i = 0; i < temp_rate_set2.numRates; i++) + temp_rate_set.rate[i + temp_rate_set.numRates] = + temp_rate_set2.rate[i]; + + temp_rate_set.numRates += temp_rate_set2.numRates; + + /** + * Sort rates in temp_rate_set (they are likely to be already sorted) + * put the result in temp_rate_set2 + */ + temp_rate_set2.numRates = 0; + + for (i = 0; i < temp_rate_set.numRates; i++) { + min = 0; + val = 0xff; + + for (j = 0; j < temp_rate_set.numRates; j++) + if ((uint32_t) (temp_rate_set.rate[j] & 0x7f) < val) { + val = temp_rate_set.rate[j] & 0x7f; + min = j; + } + + temp_rate_set2.rate[temp_rate_set2.numRates++] = + temp_rate_set.rate[min]; + temp_rate_set.rate[min] = 0xff; + } + + /** + * Copy received rates in temp_rate_set, the parser has ensured + * unicity of the rates so there cannot be more than 12 . + */ + if (supp_rates_len > SIR_MAC_RATESET_EID_MAX) { + lim_log(mac_ctx, LOGW, + FL( + "Supported rates length %d more than the Max limit, reset to Max" + ), + supp_rates_len); + supp_rates_len = SIR_MAC_RATESET_EID_MAX; + } + + for (i = 0; i < supp_rates_len; i++) + temp_rate_set.rate[i] = supp_rate_set[i]; + + temp_rate_set.numRates = supp_rates_len; + + rates = &stads->supportedRates; + qdf_mem_set((uint8_t *) rates, sizeof(tSirSupportedRates), 0); + + for (i = 0; i < temp_rate_set2.numRates; i++) { + for (j = 0; j < temp_rate_set.numRates; j++) { + if ((temp_rate_set2.rate[i] & 0x7F) != + (temp_rate_set.rate[j] & 0x7F)) + continue; + + if ((b_rateindex > SIR_NUM_11B_RATES) || + (a_rateindex > SIR_NUM_11A_RATES)) { + lim_log(mac_ctx, LOGE, + FL("Invalid number of rates (11b->%d, 11a->%d)"), + b_rateindex, a_rateindex); + return eSIR_FAILURE; + } + if (sirIsArate(temp_rate_set2.rate[i] & 0x7f)) { + is_a_rate = 1; + if (a_rateindex < SIR_NUM_11A_RATES) + rates->llaRates[a_rateindex++] = temp_rate_set2.rate[i]; + } else { + if (b_rateindex < SIR_NUM_11B_RATES) + rates->llbRates[b_rateindex++] = temp_rate_set2.rate[i]; + } + break; + } + } + + if (IS_5G_CH(session_entry->currentOperChannel)) + nss = mac_ctx->vdev_type_nss_5g.tdls; + else + nss = mac_ctx->vdev_type_nss_2g.tdls; + + nss = QDF_MIN(nss, mac_ctx->user_configured_nss); + + /* compute the matching MCS rate set, if peer is 11n capable and self mode is 11n */ +#ifdef FEATURE_WLAN_TDLS + if (stads->mlmStaContext.htCapability) +#else + if (IS_DOT11_MODE_HT(session_entry->dot11mode) && + (stads->mlmStaContext.htCapability)) +#endif + { + val = SIZE_OF_SUPPORTED_MCS_SET; + if (wlan_cfg_get_str(mac_ctx, WNI_CFG_SUPPORTED_MCS_SET, + mcsSet, &val) != eSIR_SUCCESS) { + /* Could not get rateset from CFG. Log error. */ + lim_log(mac_ctx, LOGP, + FL("could not retrieve supportedMCSSet")); + return eSIR_FAILURE; + } + + if (NSS_1x1_MODE == nss) + mcsSet[1] = 0; + for (i = 0; i < val; i++) + stads->supportedRates.supportedMCSSet[i] = + mcsSet[i] & supp_mcs_set[i]; + + lim_log(mac_ctx, LOG1, + FL("MCS Rate Set Bitmap from CFG and DPH")); + for (i = 0; i < SIR_MAC_MAX_SUPPORTED_MCS_SET; i++) { + lim_log(mac_ctx, LOG1, FL("%x %x"), mcsSet[i], + stads->supportedRates.supportedMCSSet[i]); + } + } + lim_populate_vht_mcs_set(mac_ctx, &stads->supportedRates, vht_caps, + session_entry, nss); + /** + * Set the erpEnabled bit if the phy is in G mode and at least + * one A rate is supported + */ + if ((phymode == WNI_CFG_PHY_MODE_11G) && is_a_rate) + stads->erpEnabled = eHAL_SET; + + return eSIR_SUCCESS; +} + +/* + * update HASH node entry info + */ +static void lim_tdls_update_hash_node_info(tpAniSirGlobal pMac, + tDphHashNode *pStaDs, + tSirTdlsAddStaReq *pTdlsAddStaReq, + tpPESession psessionEntry) +{ + tDot11fIEHTCaps htCap = {0,}; + tDot11fIEHTCaps *htCaps; + tDot11fIEVHTCaps *pVhtCaps = NULL; + tDot11fIEVHTCaps *pVhtCaps_txbf = NULL; + tDot11fIEVHTCaps vhtCap; + uint8_t cbMode; + tpDphHashNode pSessStaDs = NULL; + uint16_t aid; + + if (pTdlsAddStaReq->tdlsAddOper == TDLS_OPER_ADD) { + populate_dot11f_ht_caps(pMac, psessionEntry, &htCap); + } else if (pTdlsAddStaReq->tdlsAddOper == TDLS_OPER_UPDATE) { + lim_tdls_populate_dot11f_ht_caps(pMac, NULL, pTdlsAddStaReq, &htCap); + } + htCaps = &htCap; + if (htCaps->present) { + pStaDs->mlmStaContext.htCapability = 1; + pStaDs->htGreenfield = htCaps->greenField; + /* + * pStaDs->htSupportedChannelWidthSet should have the base + * channel capability. The htSupportedChannelWidthSet of the + * TDLS link on base channel should be less than or equal to + * channel width of STA-AP link. So take this setting from the + * psessionEntry. + */ + lim_log(pMac, LOG1, + FL("supportedChannelWidthSet 0x%x htSupportedChannelWidthSet 0x%x"), + htCaps->supportedChannelWidthSet, + psessionEntry->htSupportedChannelWidthSet); + pStaDs->htSupportedChannelWidthSet = + (htCaps->supportedChannelWidthSet < + psessionEntry->htSupportedChannelWidthSet) ? + htCaps->supportedChannelWidthSet : + psessionEntry->htSupportedChannelWidthSet; + lim_log(pMac, LOG1, FL("pStaDs->htSupportedChannelWidthSet 0x%x"), + pStaDs->htSupportedChannelWidthSet); + + pStaDs->htMIMOPSState = htCaps->mimoPowerSave; + pStaDs->htMaxAmsduLength = htCaps->maximalAMSDUsize; + pStaDs->htAMpduDensity = htCaps->mpduDensity; + pStaDs->htDsssCckRate40MHzSupport = htCaps->dsssCckMode40MHz; + pStaDs->htShortGI20Mhz = htCaps->shortGI20MHz; + pStaDs->htShortGI40Mhz = htCaps->shortGI40MHz; + pStaDs->htMaxRxAMpduFactor = htCaps->maxRxAMPDUFactor; + lim_fill_rx_highest_supported_rate(pMac, + &pStaDs->supportedRates. + rxHighestDataRate, + htCaps->supportedMCSSet); + pStaDs->baPolicyFlag = 0xFF; + pMac->lim.gLimTdlsLinkMode = TDLS_LINK_MODE_N; + pStaDs->ht_caps = pTdlsAddStaReq->htCap.capInfo; + } else { + pStaDs->mlmStaContext.htCapability = 0; + pMac->lim.gLimTdlsLinkMode = TDLS_LINK_MODE_BG; + } + lim_tdls_populate_dot11f_vht_caps(pMac, pTdlsAddStaReq, &vhtCap); + pVhtCaps = &vhtCap; + if (pVhtCaps->present) { + pStaDs->mlmStaContext.vhtCapability = 1; + + /* + * 11.21.1 General: The channel width of the TDLS direct + * link on the base channel shall not exceed the channel + * width of the BSS to which the TDLS peer STAs are + * associated. + */ + if (psessionEntry->ch_width) + pStaDs->vhtSupportedChannelWidthSet = + psessionEntry->ch_width - 1; + else + pStaDs->vhtSupportedChannelWidthSet = + psessionEntry->ch_width; + + lim_log(pMac, LOG1, FL("vhtSupportedChannelWidthSet = %hu, htSupportedChannelWidthSet %hu"), + pStaDs->vhtSupportedChannelWidthSet, + pStaDs->htSupportedChannelWidthSet); + + pStaDs->vhtLdpcCapable = pVhtCaps->ldpcCodingCap; + pStaDs->vhtBeamFormerCapable = 0; + pMac->lim.gLimTdlsLinkMode = TDLS_LINK_MODE_AC; + pVhtCaps_txbf = (tDot11fIEVHTCaps *) (&pTdlsAddStaReq->vhtCap); + pVhtCaps_txbf->suBeamformeeCap = 0; + pVhtCaps_txbf->suBeamFormerCap = 0; + pVhtCaps_txbf->muBeamformerCap = 0; + pVhtCaps_txbf->muBeamformeeCap = 0; + pStaDs->vht_caps = pTdlsAddStaReq->vhtCap.vhtCapInfo; + } else { + pStaDs->mlmStaContext.vhtCapability = 0; + pStaDs->vhtSupportedChannelWidthSet = + WNI_CFG_VHT_CHANNEL_WIDTH_20_40MHZ; + } + + /* + * Calculate the Secondary Coannel Offset if our + * own channel bonding state is enabled + */ + if (psessionEntry->htSupportedChannelWidthSet) { + cbMode = lim_select_cb_mode(pStaDs, psessionEntry, + psessionEntry->currentOperChannel, + pStaDs->vhtSupportedChannelWidthSet); + + if (pStaDs->mlmStaContext.vhtCapability) + pStaDs->htSecondaryChannelOffset = + lim_get_htcb_state(cbMode); + else + pStaDs->htSecondaryChannelOffset = cbMode; + } + pSessStaDs = dph_lookup_hash_entry(pMac, psessionEntry->bssId, &aid, + &psessionEntry->dph.dphHashTable); + /* Lets enable QOS parameter */ + pStaDs->qosMode = (pTdlsAddStaReq->capability & CAPABILITIES_QOS_OFFSET) + || pTdlsAddStaReq->htcap_present; + pStaDs->wmeEnabled = 1; + pStaDs->lleEnabled = 0; + /* TDLS Dummy AddSTA does not have qosInfo , is it OK ?? + */ + pStaDs->qos.capability.qosInfo = + (*(tSirMacQosInfoStation *) &pTdlsAddStaReq->uapsd_queues); + + /* populate matching rate set */ + + /* TDLS Dummy AddSTA does not have HTCap,VHTCap,Rates info , is it OK ?? + */ + lim_tdls_populate_matching_rate_set(pMac, pStaDs, + pTdlsAddStaReq->supported_rates, + pTdlsAddStaReq->supported_rates_length, + (uint8_t *) pTdlsAddStaReq->htCap. + suppMcsSet, psessionEntry, pVhtCaps); + + /* TDLS Dummy AddSTA does not have right capability , is it OK ?? + */ + pStaDs->mlmStaContext.capabilityInfo = + (*(tSirMacCapabilityInfo *) &pTdlsAddStaReq->capability); + + return; +} + +/* + * Add STA for TDLS setup procedure + */ +static tSirRetStatus lim_tdls_setup_add_sta(tpAniSirGlobal pMac, + tSirTdlsAddStaReq *pAddStaReq, + tpPESession psessionEntry) +{ + tpDphHashNode pStaDs = NULL; + tSirRetStatus status = eSIR_SUCCESS; + uint16_t aid = 0; + + pStaDs = dph_lookup_hash_entry(pMac, pAddStaReq->peermac.bytes, &aid, + &psessionEntry->dph.dphHashTable); + if (NULL == pStaDs) { + aid = lim_assign_peer_idx(pMac, psessionEntry); + + if (!aid) { + lim_log(pMac, LOGE, + FL("No more free AID for peer " + MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(pAddStaReq->peermac.bytes)); + return eSIR_FAILURE; + } + + /* Set the aid in peerAIDBitmap as it has been assigned to TDLS peer */ + SET_PEER_AID_BITMAP(psessionEntry->peerAIDBitmap, aid); + + lim_log(pMac, LOG1, FL("Aid = %d, for peer =" MAC_ADDRESS_STR), + aid, MAC_ADDR_ARRAY(pAddStaReq->peermac.bytes)); + pStaDs = + dph_get_hash_entry(pMac, aid, + &psessionEntry->dph.dphHashTable); + + if (pStaDs) { + (void)lim_del_sta(pMac, pStaDs, false /*asynchronous */, + psessionEntry); + lim_delete_dph_hash_entry(pMac, pStaDs->staAddr, aid, + psessionEntry); + } + + pStaDs = dph_add_hash_entry(pMac, pAddStaReq->peermac.bytes, + aid, &psessionEntry->dph.dphHashTable); + + if (NULL == pStaDs) { + lim_log(pMac, LOGE, FL("add hash entry failed")); + QDF_ASSERT(0); + return eSIR_FAILURE; + } + } + + lim_tdls_update_hash_node_info(pMac, pStaDs, pAddStaReq, psessionEntry); + + pStaDs->staType = STA_ENTRY_TDLS_PEER; + + status = + lim_add_sta(pMac, pStaDs, + (pAddStaReq->tdlsAddOper == + TDLS_OPER_UPDATE) ? true : false, psessionEntry); + + if (eSIR_SUCCESS != status) { + /* should not fail */ + QDF_ASSERT(0); + } + return status; +} + +/* + * Del STA, after Link is teardown or discovery response sent on direct link + */ +static tpDphHashNode lim_tdls_del_sta(tpAniSirGlobal pMac, + struct qdf_mac_addr peerMac, + tpPESession psessionEntry, + bool resp_reqd) +{ + tSirRetStatus status = eSIR_SUCCESS; + uint16_t peerIdx = 0; + tpDphHashNode pStaDs = NULL; + + pStaDs = dph_lookup_hash_entry(pMac, peerMac.bytes, &peerIdx, + &psessionEntry->dph.dphHashTable); + + if (pStaDs) { + + lim_log(pMac, LOG1, FL("DEL STA peer MAC: "MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(pStaDs->staAddr)); + + lim_log(pMac, LOG1, + FL("STA type = %x, sta idx = %x resp_reqd %d"), + pStaDs->staType, + pStaDs->staIndex, + resp_reqd); + + status = lim_del_sta(pMac, pStaDs, resp_reqd, psessionEntry); + } + + return pStaDs; +} + +/* + * Once Link is setup with PEER, send Add STA ind to SME + */ +static QDF_STATUS lim_send_sme_tdls_add_sta_rsp(tpAniSirGlobal pMac, + uint8_t sessionId, + tSirMacAddr peerMac, + uint8_t updateSta, + tDphHashNode *pStaDs, uint8_t status) +{ + tSirMsgQ mmhMsg = { 0 }; + tSirTdlsAddStaRsp *addStaRsp = NULL; + mmhMsg.type = eWNI_SME_TDLS_ADD_STA_RSP; + + addStaRsp = qdf_mem_malloc(sizeof(tSirTdlsAddStaRsp)); + if (NULL == addStaRsp) { + lim_log(pMac, LOGE, FL("Failed to allocate memory")); + return QDF_STATUS_E_NOMEM; + } + + addStaRsp->sessionId = sessionId; + addStaRsp->statusCode = status; + if (pStaDs) { + addStaRsp->staId = pStaDs->staIndex; + addStaRsp->ucastSig = pStaDs->ucUcastSig; + addStaRsp->bcastSig = pStaDs->ucBcastSig; + } + if (peerMac) { + qdf_mem_copy(addStaRsp->peermac.bytes, + (uint8_t *) peerMac, QDF_MAC_ADDR_SIZE); + } + if (updateSta) + addStaRsp->tdlsAddOper = TDLS_OPER_UPDATE; + else + addStaRsp->tdlsAddOper = TDLS_OPER_ADD; + + addStaRsp->length = sizeof(tSirTdlsAddStaRsp); + addStaRsp->messageType = eWNI_SME_TDLS_ADD_STA_RSP; + + mmhMsg.bodyptr = addStaRsp; + mmhMsg.bodyval = 0; + lim_sys_process_mmh_msg_api(pMac, &mmhMsg, ePROT); + + return QDF_STATUS_SUCCESS; +} + +/* + * STA RSP received from HAL + */ +QDF_STATUS lim_process_tdls_add_sta_rsp(tpAniSirGlobal pMac, void *msg, + tpPESession psessionEntry) +{ + tAddStaParams *pAddStaParams = (tAddStaParams *) msg; + uint8_t status = eSIR_SUCCESS; + tDphHashNode *pStaDs = NULL; + uint16_t aid = 0; + + SET_LIM_PROCESS_DEFD_MESGS(pMac, true); + lim_log(pMac, LOG1, FL("staIdx=%d, staMac="MAC_ADDRESS_STR), + pAddStaParams->staIdx, + MAC_ADDR_ARRAY(pAddStaParams->staMac)); + + if (pAddStaParams->status != QDF_STATUS_SUCCESS) { + QDF_ASSERT(0); + lim_log(pMac, LOGE, FL("Add sta failed ")); + status = eSIR_FAILURE; + goto add_sta_error; + } + + pStaDs = dph_lookup_hash_entry(pMac, pAddStaParams->staMac, &aid, + &psessionEntry->dph.dphHashTable); + if (NULL == pStaDs) { + lim_log(pMac, LOGE, FL("pStaDs is NULL ")); + status = eSIR_FAILURE; + goto add_sta_error; + } + + pStaDs->bssId = pAddStaParams->bssIdx; + pStaDs->staIndex = pAddStaParams->staIdx; + pStaDs->ucUcastSig = pAddStaParams->ucUcastSig; + pStaDs->ucBcastSig = pAddStaParams->ucBcastSig; + pStaDs->mlmStaContext.mlmState = eLIM_MLM_LINK_ESTABLISHED_STATE; + pStaDs->valid = 1; +add_sta_error: + status = lim_send_sme_tdls_add_sta_rsp(pMac, psessionEntry->smeSessionId, + pAddStaParams->staMac, + pAddStaParams->updateSta, pStaDs, + status); + qdf_mem_free(pAddStaParams); + return status; +} + +/** + * lim_process_sme_tdls_mgmt_send_req() - send out tdls management frames + * + * @mac_ctx - global mac context + * @msg - message buffer received from SME. + * + * Process Send Mgmt Request from SME and transmit to AP. + * + * Return: eSIR_SUCCESS on success, error code otherwise + */ +tSirRetStatus lim_process_sme_tdls_mgmt_send_req(tpAniSirGlobal mac_ctx, + uint32_t *msg) +{ + /* get all discovery request parameters */ + tSirTdlsSendMgmtReq *send_req = (tSirTdlsSendMgmtReq *) msg; + tpPESession session_entry; + uint8_t session_id; + tSirResultCodes result_code = eSIR_SME_INVALID_PARAMETERS; + + lim_log(mac_ctx, LOG1, FL("Send Mgmt Recieved")); + session_entry = pe_find_session_by_bssid(mac_ctx, + send_req->bssid.bytes, &session_id); + if (NULL == session_entry) { + lim_log(mac_ctx, LOGE, + FL("PE Session does not exist for given sme session_id %d"), + send_req->sessionId); + goto lim_tdls_send_mgmt_error; + } + + /* check if we are in proper state to work as TDLS client */ + if (!LIM_IS_STA_ROLE(session_entry)) { + QDF_TRACE(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_ERROR, + FL("send mgmt received in wrong system Role %d"), + GET_LIM_SYSTEM_ROLE(session_entry)); + goto lim_tdls_send_mgmt_error; + } + + /* + * if we are still good, go ahead and check if we are in proper state to + * do TDLS discovery req/rsp/....frames. + */ + if ((session_entry->limSmeState != eLIM_SME_ASSOCIATED_STATE) && + (session_entry->limSmeState != eLIM_SME_LINK_EST_STATE)) { + lim_log(mac_ctx, LOGE, + FL("send mgmt received in invalid LIMsme state (%d)"), + session_entry->limSmeState); + goto lim_tdls_send_mgmt_error; + } + + cds_tdls_tx_rx_mgmt_event(SIR_MAC_ACTION_TDLS, + SIR_MAC_ACTION_TX, SIR_MAC_MGMT_ACTION, + send_req->reqType, send_req->peer_mac.bytes); + + switch (send_req->reqType) { + case SIR_MAC_TDLS_DIS_REQ: + lim_log(mac_ctx, LOG1, FL("Transmit Discovery Request Frame")); + /* format TDLS discovery request frame and transmit it */ + lim_send_tdls_dis_req_frame(mac_ctx, send_req->peer_mac, + send_req->dialog, session_entry, + send_req->ac); + result_code = eSIR_SME_SUCCESS; + break; + case SIR_MAC_TDLS_DIS_RSP: + lim_log(mac_ctx, LOG1, FL("Transmit Discovery Response Frame")); + /* Send a response mgmt action frame */ + lim_send_tdls_dis_rsp_frame(mac_ctx, send_req->peer_mac, + send_req->dialog, session_entry, &send_req->addIe[0], + (send_req->length - sizeof(tSirTdlsSendMgmtReq))); + result_code = eSIR_SME_SUCCESS; + break; + case SIR_MAC_TDLS_SETUP_REQ: + lim_log(mac_ctx, LOG1, FL("Transmit Setup Request Frame")); + lim_send_tdls_link_setup_req_frame(mac_ctx, + send_req->peer_mac, send_req->dialog, session_entry, + &send_req->addIe[0], + (send_req->length - sizeof(tSirTdlsSendMgmtReq)), + send_req->ac); + result_code = eSIR_SME_SUCCESS; + break; + case SIR_MAC_TDLS_SETUP_RSP: + lim_log(mac_ctx, LOG1, FL("Transmit Setup Response Frame")); + lim_send_tdls_setup_rsp_frame(mac_ctx, + send_req->peer_mac, send_req->dialog, session_entry, + send_req->statusCode, &send_req->addIe[0], + (send_req->length - sizeof(tSirTdlsSendMgmtReq)), + send_req->ac); + result_code = eSIR_SME_SUCCESS; + break; + case SIR_MAC_TDLS_SETUP_CNF: + lim_log(mac_ctx, LOG1, FL("Transmit Setup Confirm Frame")); + lim_send_tdls_link_setup_cnf_frame(mac_ctx, + send_req->peer_mac, send_req->dialog, + send_req->peerCapability, session_entry, + &send_req->addIe[0], + (send_req->length - sizeof(tSirTdlsSendMgmtReq)), + send_req->ac); + result_code = eSIR_SME_SUCCESS; + break; + case SIR_MAC_TDLS_TEARDOWN: + lim_log(mac_ctx, LOG1, FL("Transmit Teardown Frame")); + lim_send_tdls_teardown_frame(mac_ctx, + send_req->peer_mac, send_req->statusCode, + send_req->responder, session_entry, + &send_req->addIe[0], + (send_req->length - sizeof(tSirTdlsSendMgmtReq)), + send_req->ac); + result_code = eSIR_SME_SUCCESS; + break; + case SIR_MAC_TDLS_PEER_TRAFFIC_IND: + break; + case SIR_MAC_TDLS_CH_SWITCH_REQ: + break; + case SIR_MAC_TDLS_CH_SWITCH_RSP: + break; + case SIR_MAC_TDLS_PEER_TRAFFIC_RSP: + break; + default: + break; + } + +lim_tdls_send_mgmt_error: + lim_send_sme_rsp(mac_ctx, eWNI_SME_TDLS_SEND_MGMT_RSP, + result_code, send_req->sessionId, + send_req->transactionId); + + return eSIR_SUCCESS; +} + +/* + * Send Response to Link Establish Request to SME + */ +void lim_send_sme_tdls_link_establish_req_rsp(tpAniSirGlobal pMac, + uint8_t sessionId, + struct qdf_mac_addr *peermac, + tDphHashNode *pStaDs, uint8_t status) +{ + tSirMsgQ mmhMsg = { 0 }; + + tSirTdlsLinkEstablishReqRsp *pTdlsLinkEstablishReqRsp = NULL; + + pTdlsLinkEstablishReqRsp = + qdf_mem_malloc(sizeof(tSirTdlsLinkEstablishReqRsp)); + if (NULL == pTdlsLinkEstablishReqRsp) { + lim_log(pMac, LOGE, FL("Failed to allocate memory")); + return; + } + lim_log(pMac, LOG1, FL("Send Resp to TDL Link Establish Req to SME")); + pTdlsLinkEstablishReqRsp->statusCode = status; + if (peermac) + qdf_copy_macaddr(&pTdlsLinkEstablishReqRsp->peermac, peermac); + + pTdlsLinkEstablishReqRsp->sessionId = sessionId; + mmhMsg.type = eWNI_SME_TDLS_LINK_ESTABLISH_RSP; + mmhMsg.bodyptr = pTdlsLinkEstablishReqRsp; + mmhMsg.bodyval = 0; + lim_sys_process_mmh_msg_api(pMac, &mmhMsg, ePROT); + return; + +} + +/* + * Once link is teardown, send Del Peer Ind to SME + */ +static QDF_STATUS lim_send_sme_tdls_del_sta_rsp(tpAniSirGlobal pMac, + uint8_t sessionId, + struct qdf_mac_addr peerMac, + tDphHashNode *pStaDs, uint8_t status) +{ + tSirMsgQ mmhMsg = { 0 }; + tSirTdlsDelStaRsp *pDelSta = NULL; + mmhMsg.type = eWNI_SME_TDLS_DEL_STA_RSP; + + pDelSta = qdf_mem_malloc(sizeof(tSirTdlsDelStaRsp)); + if (NULL == pDelSta) { + lim_log(pMac, LOGE, FL("Failed to allocate memory")); + return QDF_STATUS_E_NOMEM; + } + + pDelSta->sessionId = sessionId; + pDelSta->statusCode = status; + if (pStaDs) { + pDelSta->staId = pStaDs->staIndex; + } else + pDelSta->staId = STA_INVALID_IDX; + + qdf_copy_macaddr(&pDelSta->peermac, &peerMac); + + pDelSta->length = sizeof(tSirTdlsDelStaRsp); + pDelSta->messageType = eWNI_SME_TDLS_DEL_STA_RSP; + + mmhMsg.bodyptr = pDelSta; + + mmhMsg.bodyval = 0; + lim_sys_process_mmh_msg_api(pMac, &mmhMsg, ePROT); + return QDF_STATUS_SUCCESS; + +} + +/* + * Process Send Mgmt Request from SME and transmit to AP. + */ +tSirRetStatus lim_process_sme_tdls_add_sta_req(tpAniSirGlobal pMac, + uint32_t *pMsgBuf) +{ + /* get all discovery request parameters */ + tSirTdlsAddStaReq *pAddStaReq = (tSirTdlsAddStaReq *) pMsgBuf; + tpPESession psessionEntry; + uint8_t sessionId; + + lim_log(pMac, LOG1, FL("TDLS Add STA Request Recieved")); + psessionEntry = + pe_find_session_by_bssid(pMac, pAddStaReq->bssid.bytes, + &sessionId); + if (psessionEntry == NULL) { + lim_log(pMac, LOGE, + FL( + "PE Session does not exist for given sme sessionId %d" + ), + pAddStaReq->sessionId); + goto lim_tdls_add_sta_error; + } + + /* check if we are in proper state to work as TDLS client */ + if (!LIM_IS_STA_ROLE(psessionEntry)) { + QDF_TRACE(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_ERROR, + "send mgmt received in wrong system Role %d", + GET_LIM_SYSTEM_ROLE(psessionEntry)); + goto lim_tdls_add_sta_error; + } + + /* + * if we are still good, go ahead and check if we are in proper state to + * do TDLS discovery req/rsp/....frames. + */ + if ((psessionEntry->limSmeState != eLIM_SME_ASSOCIATED_STATE) && + (psessionEntry->limSmeState != eLIM_SME_LINK_EST_STATE)) { + + lim_log(pMac, LOGE, + FL("send mgmt received in invalid LIMsme state (%d)"), + psessionEntry->limSmeState); + goto lim_tdls_add_sta_error; + } + + pMac->lim.gLimAddStaTdls = true; + + /* To start with, send add STA request to HAL */ + if (eSIR_FAILURE == lim_tdls_setup_add_sta(pMac, pAddStaReq, psessionEntry)) { + lim_log(pMac, LOGE, + FL("Add TDLS Station request failed")); + goto lim_tdls_add_sta_error; + } + return eSIR_SUCCESS; +lim_tdls_add_sta_error: + lim_send_sme_tdls_add_sta_rsp(pMac, + pAddStaReq->sessionId, + pAddStaReq->peermac.bytes, + (pAddStaReq->tdlsAddOper == TDLS_OPER_UPDATE), + NULL, eSIR_FAILURE); + + return eSIR_SUCCESS; +} + +/* + * Process Del Sta Request from SME . + */ +tSirRetStatus lim_process_sme_tdls_del_sta_req(tpAniSirGlobal pMac, + uint32_t *pMsgBuf) +{ + /* get all discovery request parameters */ + tSirTdlsDelStaReq *pDelStaReq = (tSirTdlsDelStaReq *) pMsgBuf; + tpPESession psessionEntry; + uint8_t sessionId; + + lim_log(pMac, LOG1, FL("TDLS Delete STA Request Recieved")); + psessionEntry = + pe_find_session_by_bssid(pMac, pDelStaReq->bssid.bytes, + &sessionId); + if (psessionEntry == NULL) { + lim_log(pMac, LOGE, + FL( + "PE Session does not exist for given sme sessionId %d" + ), + pDelStaReq->sessionId); + lim_send_sme_tdls_del_sta_rsp(pMac, pDelStaReq->sessionId, + pDelStaReq->peermac, NULL, + eSIR_FAILURE); + return eSIR_FAILURE; + } + + /* check if we are in proper state to work as TDLS client */ + if (!LIM_IS_STA_ROLE(psessionEntry)) { + QDF_TRACE(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_ERROR, + "Del sta received in wrong system Role %d", + GET_LIM_SYSTEM_ROLE(psessionEntry)); + goto lim_tdls_del_sta_error; + } + + /* + * if we are still good, go ahead and check if we are in proper state to + * do TDLS discovery req/rsp/....frames. + */ + if ((psessionEntry->limSmeState != eLIM_SME_ASSOCIATED_STATE) && + (psessionEntry->limSmeState != eLIM_SME_LINK_EST_STATE)) { + + lim_log(pMac, LOGE, + FL("Del Sta received in invalid LIMsme state (%d)"), + psessionEntry->limSmeState); + goto lim_tdls_del_sta_error; + } + + lim_tdls_del_sta(pMac, pDelStaReq->peermac, psessionEntry, true); + return eSIR_SUCCESS; + +lim_tdls_del_sta_error: + lim_send_sme_tdls_del_sta_rsp(pMac, psessionEntry->smeSessionId, + pDelStaReq->peermac, NULL, eSIR_FAILURE); + + return eSIR_SUCCESS; +} + +/* Intersects the two input arrays and outputs an array */ +/* For now the array length of uint8_t suffices */ +static void lim_tdls_get_intersection(uint8_t *input_array1, + uint8_t input1_length, + uint8_t *input_array2, + uint8_t input2_length, + uint8_t *output_array, + uint8_t *output_length) +{ + uint8_t i, j, k = 0, flag = 0; + for (i = 0; i < input1_length; i++) { + flag = 0; + for (j = 0; j < input2_length; j++) { + if (input_array1[i] == input_array2[j]) { + flag = 1; + break; + } + } + if (flag == 1) { + output_array[k] = input_array1[i]; + k++; + } + } + *output_length = k; +} + +/** + * lim_process_sme_tdls_link_establish_req() - process tdls link establishment + * request + * + * @mac_ctx - global MAC context + * @msg_buf - message buffer from SME + * + * Process Link Establishment Request from SME + * + * Return: eSIR_SUCCESS on success, failure code otherwise. + */ +tSirRetStatus lim_process_sme_tdls_link_establish_req(tpAniSirGlobal mac_ctx, + uint32_t *msg_buf) +{ + /* get all discovery request parameters */ + tSirTdlsLinkEstablishReq *tdls_req = + (tSirTdlsLinkEstablishReq *) msg_buf; + tpPESession session_entry; + uint8_t session_id; + tpTdlsLinkEstablishParams tdls_req_params; + tSirMsgQ msg; + uint16_t peer_idx = 0; + tpDphHashNode stads = NULL; + uint32_t self_num_chan = WNI_CFG_VALID_CHANNEL_LIST_LEN; + uint8_t self_supp_chan[WNI_CFG_VALID_CHANNEL_LIST_LEN]; + + QDF_TRACE(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_INFO, + FL("Process TDLS Link Establishment Request from SME")); + + session_entry = pe_find_session_by_bssid(mac_ctx, tdls_req->bssid.bytes, + &session_id); + if (NULL == session_entry) { + QDF_TRACE(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_ERROR, + FL("PE Session does not exist for sme session_id %d"), + tdls_req->sessionId); + lim_send_sme_tdls_link_establish_req_rsp(mac_ctx, + tdls_req->sessionId, &tdls_req->peermac, NULL, + eSIR_FAILURE); + return eSIR_FAILURE; + } + + /* check if we are in proper state to work as TDLS client */ + if (!LIM_IS_STA_ROLE(session_entry)) { + QDF_TRACE(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_ERROR, + FL("TDLS Link Establish Request received in wrong system Role %d"), + GET_LIM_SYSTEM_ROLE(session_entry)); + goto lim_tdls_link_establish_error; + } + + /* + * if we are still good, go ahead and check if we are in proper state to + * do TDLS discovery req/rsp/....frames. + */ + if ((session_entry->limSmeState != eLIM_SME_ASSOCIATED_STATE) && + (session_entry->limSmeState != eLIM_SME_LINK_EST_STATE)) { + lim_log(mac_ctx, LOGE, + FL("TDLS Link Establish Request received in invalid LIMsme state (%d)"), + session_entry->limSmeState); + goto lim_tdls_link_establish_error; + } + + stads = dph_lookup_hash_entry(mac_ctx, tdls_req->peermac.bytes, + &peer_idx, + &session_entry->dph.dphHashTable); + if (NULL == stads) { + lim_log(mac_ctx, LOGE, FL("stads is NULL")); + goto lim_tdls_link_establish_error; + } + tdls_req_params = qdf_mem_malloc(sizeof(tTdlsLinkEstablishParams)); + if (NULL == tdls_req_params) { + lim_log(mac_ctx, LOGE, + FL("Unable to allocate memory TDLS Link Establish Request")); + return eSIR_MEM_ALLOC_FAILED; + } + + tdls_req_params->staIdx = stads->staIndex; + tdls_req_params->isResponder = tdls_req->isResponder; + tdls_req_params->uapsdQueues = tdls_req->uapsdQueues; + tdls_req_params->maxSp = tdls_req->maxSp; + tdls_req_params->isBufsta = tdls_req->isBufSta; + tdls_req_params->isOffChannelSupported = + tdls_req->isOffChannelSupported; + + if (0 == tdls_req->supportedChannelsLen) + goto send_tdls_establish_request; + + if (wlan_cfg_get_str(mac_ctx, WNI_CFG_VALID_CHANNEL_LIST, + self_supp_chan, + &self_num_chan) != eSIR_SUCCESS) { + /** + * Could not get Valid channel list from CFG. + * Log error. + */ + lim_log(mac_ctx, LOGE, + FL("could not retrieve Valid channel list")); + } + + if (self_num_chan > WNI_CFG_VALID_CHANNEL_LIST_LEN) { + lim_log(mac_ctx, LOGE, + FL("Channel List more than Valid Channel list")); + self_num_chan = WNI_CFG_VALID_CHANNEL_LIST_LEN; + } + + if (tdls_req->supportedChannelsLen > SIR_MAC_MAX_SUPP_CHANNELS) { + lim_log(mac_ctx, LOGE, + FL("Channel List is more than the supported Channel list")); + tdls_req->supportedChannelsLen = SIR_MAC_MAX_SUPP_CHANNELS; + } + + lim_tdls_get_intersection(self_supp_chan, self_num_chan, + tdls_req->supportedChannels, tdls_req->supportedChannelsLen, + tdls_req_params->validChannels, + &tdls_req_params->validChannelsLen); + +send_tdls_establish_request: + qdf_mem_copy(tdls_req_params->validOperClasses, + tdls_req->supportedOperClasses, + tdls_req->supportedOperClassesLen); + tdls_req_params->validOperClassesLen = + tdls_req->supportedOperClassesLen; + + msg.type = WMA_SET_TDLS_LINK_ESTABLISH_REQ; + msg.reserved = 0; + msg.bodyptr = tdls_req_params; + msg.bodyval = 0; + if (eSIR_SUCCESS != wma_post_ctrl_msg(mac_ctx, &msg)) { + lim_log(mac_ctx, LOGE, FL("halPostMsgApi failed")); + goto lim_tdls_link_establish_error; + } + return eSIR_SUCCESS; + +lim_tdls_link_establish_error: + lim_send_sme_tdls_link_establish_req_rsp(mac_ctx, + session_entry->smeSessionId, &tdls_req->peermac, NULL, + eSIR_FAILURE); + + return eSIR_SUCCESS; +} + +/** + * lim_check_aid_and_delete_peer() - Funtion to check aid and delete peer + * @p_mac: pointer to mac context + * @session_entry: pointer to PE session + * + * This function verifies aid and delete's peer with that aid from hash table + * + * Return: None + */ +static void lim_check_aid_and_delete_peer(tpAniSirGlobal p_mac, + tpPESession session_entry) +{ + tpDphHashNode stads = NULL; + int i, aid; + size_t aid_bitmap_size = sizeof(session_entry->peerAIDBitmap); + struct qdf_mac_addr mac_addr; + + /* + * Check all the set bit in peerAIDBitmap and delete the peer + * (with that aid) entry from the hash table and add the aid + * in free pool + */ + lim_log(p_mac, LOG1, FL("Delete all the TDLS peer connected")); + for (i = 0; i < aid_bitmap_size / sizeof(uint32_t); i++) { + for (aid = 0; aid < (sizeof(uint32_t) << 3); aid++) { + if (!CHECK_BIT(session_entry->peerAIDBitmap[i], aid)) + continue; + stads = dph_get_hash_entry(p_mac, + (aid + i * (sizeof(uint32_t) << 3)), + &session_entry->dph.dphHashTable); + + if (NULL == stads) + goto skip; + + lim_log(p_mac, LOG1, + FL("Deleting "MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(stads->staAddr)); + + lim_send_deauth_mgmt_frame(p_mac, + eSIR_MAC_DEAUTH_LEAVING_BSS_REASON, + stads->staAddr, session_entry, false); + + /* Delete TDLS peer */ + qdf_mem_copy(mac_addr.bytes, stads->staAddr, + QDF_MAC_ADDR_SIZE); + + lim_tdls_del_sta(p_mac, mac_addr, + session_entry, false); + + dph_delete_hash_entry(p_mac, + stads->staAddr, stads->assocId, + &session_entry->dph.dphHashTable); +skip: + lim_release_peer_idx(p_mac, + (aid + i * (sizeof(uint32_t) << 3)), + session_entry); + CLEAR_BIT(session_entry->peerAIDBitmap[i], aid); + } + } +} + +/** + * lim_delete_tdls_peers() - delete tdls peers + * + * @mac_ctx - global MAC context + * @session_entry - PE session entry + * + * Delete all the TDLS peer connected before leaving the BSS + * + * Return: eSIR_SUCCESS on success, error code otherwise + */ +tSirRetStatus lim_delete_tdls_peers(tpAniSirGlobal mac_ctx, + tpPESession session_entry) +{ + if (NULL == session_entry) { + lim_log(mac_ctx, LOGE, FL("NULL session_entry")); + return eSIR_FAILURE; + } + + lim_check_aid_and_delete_peer(mac_ctx, session_entry); + + if (lim_is_roam_synch_in_progress(session_entry)) + return eSIR_SUCCESS; + + lim_send_sme_tdls_delete_all_peer_ind(mac_ctx, session_entry); + + return eSIR_SUCCESS; +} + +/** + * lim_process_sme_del_all_tdls_peers(): process delete tdls peers + * @p_mac: pointer to mac context + * @msg_buf: message buffer + * + * This function processes request to delete tdls peers + * + * Return: Success: eSIR_SUCCESS Failure: Error value + */ +tSirRetStatus lim_process_sme_del_all_tdls_peers(tpAniSirGlobal p_mac, + uint32_t *msg_buf) +{ + struct sir_del_all_tdls_peers *msg; + tpPESession session_entry; + uint8_t session_id; + + msg = (struct sir_del_all_tdls_peers *)msg_buf; + if (msg == NULL) { + lim_log(p_mac, LOGE, FL("NULL msg")); + return eSIR_FAILURE; + } + + session_entry = pe_find_session_by_bssid(p_mac, + msg->bssid.bytes, &session_id); + if (NULL == session_entry) { + lim_log(p_mac, LOGE, FL("NULL psessionEntry")); + return eSIR_FAILURE; + } + + lim_check_aid_and_delete_peer(p_mac, session_entry); + + return eSIR_SUCCESS; +} + +/** + * lim_process_tdls_del_sta_rsp() - Handle WDA_DELETE_STA_RSP for TDLS + * @mac_ctx: Global MAC context + * @lim_msg: LIM message + * @pe_session: PE session + * + * Return: None + */ +void lim_process_tdls_del_sta_rsp(tpAniSirGlobal mac_ctx, tpSirMsgQ lim_msg, + tpPESession session_entry) +{ + tpDeleteStaParams del_sta_params = (tpDeleteStaParams) lim_msg->bodyptr; + tpDphHashNode sta_ds; + uint16_t peer_idx = 0; + struct qdf_mac_addr peer_mac; + + if (!del_sta_params) { + lim_log(mac_ctx, LOGE, + FL("del_sta_params is NULL")); + return; + } + + sta_ds = dph_lookup_hash_entry(mac_ctx, del_sta_params->staMac, + &peer_idx, &session_entry->dph.dphHashTable); + if (!sta_ds) { + lim_log(mac_ctx, LOGE, + FL("DPH Entry for STA %X is missing."), + DPH_STA_HASH_INDEX_PEER); + goto skip_event; + } + + qdf_mem_copy(peer_mac.bytes, + del_sta_params->staMac, QDF_MAC_ADDR_SIZE); + + if (QDF_STATUS_SUCCESS != del_sta_params->status) { + lim_log(mac_ctx, LOGE, FL("DEL STA failed!")); + lim_send_sme_tdls_del_sta_rsp(mac_ctx, + session_entry->smeSessionId, + peer_mac, NULL, eSIR_FAILURE); + goto skip_event; + } + + lim_log(mac_ctx, LOG1, FL("DEL STA success")); + + /* now send indication to SME-->HDD->TL to remove STA from TL */ + + lim_send_sme_tdls_del_sta_rsp(mac_ctx, session_entry->smeSessionId, + peer_mac, sta_ds, + eSIR_SUCCESS); + lim_release_peer_idx(mac_ctx, sta_ds->assocId, session_entry); + + /* Clear the aid in peerAIDBitmap as this aid is now in freepool */ + CLEAR_PEER_AID_BITMAP(session_entry->peerAIDBitmap, + sta_ds->assocId); + lim_delete_dph_hash_entry(mac_ctx, sta_ds->staAddr, sta_ds->assocId, + session_entry); + +skip_event: + qdf_mem_free(del_sta_params); + lim_msg->bodyptr = NULL; +} + + +#endif diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_prop_exts_utils.c b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_prop_exts_utils.c new file mode 100644 index 0000000000000000000000000000000000000000..53c10ff777593d81d839fadd99590a2092bc65ea --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_prop_exts_utils.c @@ -0,0 +1,455 @@ +/* + * Copyright (c) 2011-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * + * This file lim_prop_exts_utils.cc contains the utility functions + * to populate, parse proprietary extensions required to + * support ANI feature set. + * + * Author: Chandra Modumudi + * Date: 11/27/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + * + */ +#include "ani_global.h" +#include "wni_cfg.h" +#include "sir_common.h" +#include "sir_debug.h" +#include "utils_api.h" +#include "cfg_api.h" +#include "lim_api.h" +#include "lim_types.h" +#include "lim_utils.h" +#include "lim_assoc_utils.h" +#include "lim_prop_exts_utils.h" +#include "lim_ser_des_utils.h" +#include "lim_trace.h" +#include "lim_ft_defs.h" +#include "lim_session.h" +#include "wma.h" + +#define LIM_GET_NOISE_MAX_TRY 5 + +#ifdef FEATURE_WLAN_ESE +/** + * get_local_power_constraint_probe_response() - extracts local constraint + * from probe response + * @beacon_struct: beacon structure + * @local_constraint: local constraint pointer + * @session: A pointer to session entry. + * + * Return: None + */ +static void get_local_power_constraint_probe_response( + tpSirProbeRespBeacon beacon_struct, + int8_t *local_constraint, + tpPESession session) +{ + if (beacon_struct->eseTxPwr.present) + *local_constraint = + beacon_struct->eseTxPwr.power_limit; +} + +/** + * get_ese_version_ie_probe_response() - extracts ESE version IE + * from probe response + * @beacon_struct: beacon structure + * @session: A pointer to session entry. + * + * Return: None + */ +static void get_ese_version_ie_probe_response(tpAniSirGlobal mac_ctx, + tpSirProbeRespBeacon beacon_struct, + tpPESession session) +{ + if (mac_ctx->roam.configParam.isEseIniFeatureEnabled) + session->is_ese_version_ie_present = + beacon_struct->is_ese_ver_ie_present; +} +#else +static void get_local_power_constraint_probe_response( + tpSirProbeRespBeacon beacon_struct, + int8_t *local_constraint, + tpPESession session) +{ + +} + +static inline void get_ese_version_ie_probe_response(tpAniSirGlobal mac_ctx, + tpSirProbeRespBeacon beacon_struct, + tpPESession session) +{ +} +#endif + +/** + * lim_get_nss_supported_by_beacon() - finds out nss from beacom + * @bcn: beacon structure pointer + * @session: pointer to pe session + * + * Return: number of nss advertised by beacon + */ +static uint8_t lim_get_nss_supported_by_beacon(tpSchBeaconStruct bcn, + tpPESession session) +{ + if (session->vhtCapability && bcn->VHTCaps.present) { + if ((bcn->VHTCaps.rxMCSMap & 0xC0) != 0xC0) + return 4; + + if ((bcn->VHTCaps.rxMCSMap & 0x30) != 0x30) + return 3; + + if ((bcn->VHTCaps.rxMCSMap & 0x0C) != 0x0C) + return 2; + } else if (session->htCapability && bcn->HTCaps.present) { + if (bcn->HTCaps.supportedMCSSet[3]) + return 4; + + if (bcn->HTCaps.supportedMCSSet[2]) + return 3; + + if (bcn->HTCaps.supportedMCSSet[1]) + return 2; + } + + return 1; +} + +/** + * lim_extract_ap_capability() - extract AP's HCF/WME/WSM capability + * @mac_ctx: Pointer to Global MAC structure + * @p_ie: Pointer to starting IE in Beacon/Probe Response + * @ie_len: Length of all IEs combined + * @qos_cap: Bits are set according to capabilities + * @prop_cap: Pointer to prop info IE. + * @uapsd: pointer to uapsd + * @local_constraint: Pointer to local power constraint. + * @session: A pointer to session entry. + * + * This function is called to extract AP's HCF/WME/WSM capability + * from the IEs received from it in Beacon/Probe Response frames + * + * Return: None + */ +void +lim_extract_ap_capability(tpAniSirGlobal mac_ctx, uint8_t *p_ie, + uint16_t ie_len, uint8_t *qos_cap, uint16_t *prop_cap, uint8_t *uapsd, + int8_t *local_constraint, tpPESession session) +{ + tSirProbeRespBeacon *beacon_struct; + uint32_t enable_txbf_20mhz; + tSirRetStatus cfg_get_status = eSIR_FAILURE; + uint8_t ap_bcon_ch_width; + bool new_ch_width_dfn = false; + tDot11fIEVHTOperation *vht_op; + uint8_t fw_vht_ch_wd; + uint8_t vht_ch_wd; + uint8_t center_freq_diff; + struct s_ext_cap *ext_cap; + + beacon_struct = qdf_mem_malloc(sizeof(tSirProbeRespBeacon)); + if (NULL == beacon_struct) { + lim_log(mac_ctx, LOGE, FL("Unable to allocate memory")); + return; + } + + *qos_cap = 0; + *prop_cap = 0; + *uapsd = 0; + lim_log(mac_ctx, LOG3, + FL("In lim_extract_ap_capability: The IE's being received:")); + sir_dump_buf(mac_ctx, SIR_LIM_MODULE_ID, LOG3, p_ie, ie_len); + if (sir_parse_beacon_ie(mac_ctx, beacon_struct, p_ie, + (uint32_t) ie_len) != eSIR_SUCCESS) { + lim_log(mac_ctx, LOGE, FL( + "sir_parse_beacon_ie failed to parse beacon")); + qdf_mem_free(beacon_struct); + return; + } + + if (mac_ctx->roam.configParam.is_force_1x1 && + cfg_get_vendor_ie_ptr_from_oui(mac_ctx, SIR_MAC_VENDOR_AP_1_OUI, + SIR_MAC_VENDOR_AP_1_OUI_LEN, p_ie, ie_len) && + lim_get_nss_supported_by_beacon(beacon_struct, session) == 2 && + mac_ctx->lteCoexAntShare && + IS_24G_CH(session->currentOperChannel)) { + session->supported_nss_1x1 = true; + session->vdev_nss = 1; + session->nss = 1; + lim_log(mac_ctx, LOGE, FL("For special ap, NSS: %d"), + session->nss); + } + + if (session->nss > lim_get_nss_supported_by_beacon(beacon_struct, + session)) { + session->nss = lim_get_nss_supported_by_beacon(beacon_struct, + session); + session->vdev_nss = session->nss; + } + + if (session->nss == 1) + session->supported_nss_1x1 = true; + + if (beacon_struct->wmeInfoPresent || + beacon_struct->wmeEdcaPresent || + beacon_struct->HTCaps.present) + LIM_BSS_CAPS_SET(WME, *qos_cap); + if (LIM_BSS_CAPS_GET(WME, *qos_cap) + && beacon_struct->wsmCapablePresent) + LIM_BSS_CAPS_SET(WSM, *qos_cap); + if (beacon_struct->propIEinfo.capabilityPresent) + *prop_cap = beacon_struct->propIEinfo.capability; + if (beacon_struct->HTCaps.present) + mac_ctx->lim.htCapabilityPresentInBeacon = 1; + else + mac_ctx->lim.htCapabilityPresentInBeacon = 0; + + lim_log(mac_ctx, LOG1, FL( + "Bcon: VHTCap.present %d SU Beamformer %d BSS_VHT_CAPABLE %d"), + beacon_struct->VHTCaps.present, + beacon_struct->VHTCaps.suBeamFormerCap, + IS_BSS_VHT_CAPABLE(beacon_struct->VHTCaps)); + + vht_op = &beacon_struct->VHTOperation; + if (IS_BSS_VHT_CAPABLE(beacon_struct->VHTCaps) && + vht_op->present && + session->vhtCapability) { + session->vhtCapabilityPresentInBeacon = 1; + if (((beacon_struct->Vendor1IEPresent && + beacon_struct->vendor_vht_ie.present && + beacon_struct->Vendor3IEPresent)) && + (((beacon_struct->VHTCaps.txMCSMap & VHT_MCS_3x3_MASK) == + VHT_MCS_3x3_MASK) && + ((beacon_struct->VHTCaps.txMCSMap & VHT_MCS_2x2_MASK) != + VHT_MCS_2x2_MASK))) + session->vht_config.su_beam_formee = 0; + } else { + session->vhtCapabilityPresentInBeacon = 0; + } + + if (session->vhtCapabilityPresentInBeacon == 1 && + !session->htSupportedChannelWidthSet) { + cfg_get_status = wlan_cfg_get_int(mac_ctx, + WNI_CFG_VHT_ENABLE_TXBF_20MHZ, + &enable_txbf_20mhz); + if ((IS_SIR_STATUS_SUCCESS(cfg_get_status)) && + (false == enable_txbf_20mhz)) + session->vht_config.su_beam_formee = 0; + } else if (session->vhtCapabilityPresentInBeacon && + vht_op->chanWidth) { + /* If VHT is supported min 80 MHz support is must */ + ap_bcon_ch_width = vht_op->chanWidth; + if ((ap_bcon_ch_width == WNI_CFG_VHT_CHANNEL_WIDTH_80MHZ) && + vht_op->chanCenterFreqSeg2) { + new_ch_width_dfn = true; + if (vht_op->chanCenterFreqSeg2 > + vht_op->chanCenterFreqSeg1) + center_freq_diff = vht_op->chanCenterFreqSeg2 - + vht_op->chanCenterFreqSeg1; + else + center_freq_diff = vht_op->chanCenterFreqSeg1 - + vht_op->chanCenterFreqSeg2; + if (center_freq_diff == 8) + ap_bcon_ch_width = + WNI_CFG_VHT_CHANNEL_WIDTH_160MHZ; + else if (center_freq_diff > 16) + ap_bcon_ch_width = + WNI_CFG_VHT_CHANNEL_WIDTH_80_PLUS_80MHZ; + } + + fw_vht_ch_wd = wma_get_vht_ch_width(); + vht_ch_wd = QDF_MIN(fw_vht_ch_wd, ap_bcon_ch_width); + /* + * If the supported channel width is greater than 80MHz and + * AP supports Nss > 1 in 160MHz mode then connect the STA + * in 2x2 80MHz mode instead of connecting in 160MHz mode. + */ + if ((vht_ch_wd > WNI_CFG_VHT_CHANNEL_WIDTH_80MHZ) && + mac_ctx->sta_prefer_80MHz_over_160MHz) { + if (!(IS_VHT_NSS_1x1(beacon_struct->VHTCaps.txMCSMap)) + && + (!IS_VHT_NSS_1x1(beacon_struct->VHTCaps.rxMCSMap))) + vht_ch_wd = WNI_CFG_VHT_CHANNEL_WIDTH_80MHZ; + } + /* + * VHT OP IE old definition: + * vht_op->chanCenterFreqSeg1: center freq of 80MHz/160MHz/ + * primary 80 in 80+80MHz. + * + * vht_op->chanCenterFreqSeg2: center freq of secondary 80 + * in 80+80MHz. + * + * VHT OP IE NEW definition: + * vht_op->chanCenterFreqSeg1: center freq of 80MHz/primary + * 80 in 80+80MHz/center freq of the 80 MHz channel segment + * that contains the primary channel in 160MHz mode. + * + * vht_op->chanCenterFreqSeg2: center freq of secondary 80 + * in 80+80MHz/center freq of 160MHz. + */ + session->ch_center_freq_seg0 = vht_op->chanCenterFreqSeg1; + session->ch_center_freq_seg1 = vht_op->chanCenterFreqSeg2; + if (vht_ch_wd == WNI_CFG_VHT_CHANNEL_WIDTH_160MHZ) { + /* DUT or AP supports only 160MHz */ + if (ap_bcon_ch_width == + WNI_CFG_VHT_CHANNEL_WIDTH_160MHZ) { + /* AP is in 160MHz mode */ + if (!new_ch_width_dfn) { + session->ch_center_freq_seg1 = + vht_op->chanCenterFreqSeg1; + session->ch_center_freq_seg0 = + lim_get_80Mhz_center_channel( + beacon_struct->channelNumber); + } + } else { + /* DUT supports only 160MHz and AP is + * in 80+80 mode + */ + vht_ch_wd = WNI_CFG_VHT_CHANNEL_WIDTH_80MHZ; + session->ch_center_freq_seg1 = 0; + } + } else if (vht_ch_wd == WNI_CFG_VHT_CHANNEL_WIDTH_80MHZ) { + /* DUT or AP supports only 80MHz */ + if (ap_bcon_ch_width == + WNI_CFG_VHT_CHANNEL_WIDTH_160MHZ && + !new_ch_width_dfn) + /* AP is in 160MHz mode */ + session->ch_center_freq_seg0 = + lim_get_80Mhz_center_channel( + beacon_struct->channelNumber); + else + session->ch_center_freq_seg1 = 0; + } + session->ch_width = vht_ch_wd + 1; + lim_log(mac_ctx, LOG1, FL( + "cntr_freq0 %d, cntr_freq1 %d, width %d"), + session->ch_center_freq_seg0, + session->ch_center_freq_seg1, + session->ch_width); + if (CH_WIDTH_80MHZ < session->ch_width) { + session->vht_config.su_beam_former = 0; + session->nss = 1; + } + } + + if (session->vhtCapability && + session->vhtCapabilityPresentInBeacon && + beacon_struct->ext_cap.present) { + ext_cap = (struct s_ext_cap *)beacon_struct->ext_cap.bytes; + session->gLimOperatingMode.present = + ext_cap->oper_mode_notification; + if (ext_cap->oper_mode_notification) { + if (CH_WIDTH_160MHZ > session->ch_width) + session->gLimOperatingMode.chanWidth = + session->ch_width; + else + session->gLimOperatingMode.chanWidth = + CH_WIDTH_160MHZ; + } else { + lim_log(mac_ctx, LOGE, FL( + "AP does not support op_mode rx")); + } + } + /* Extract the UAPSD flag from WMM Parameter element */ + if (beacon_struct->wmeEdcaPresent) + *uapsd = beacon_struct->edcaParams.qosInfo.uapsd; + + if (mac_ctx->roam.configParam.allow_tpc_from_ap) { + if (beacon_struct->powerConstraintPresent) { + *local_constraint -= + beacon_struct->localPowerConstraint. + localPowerConstraints; + } else { + get_local_power_constraint_probe_response( + beacon_struct, local_constraint, session); + } + } + + get_ese_version_ie_probe_response(mac_ctx, beacon_struct, session); + + session->country_info_present = false; + /* Initializing before first use */ + if (beacon_struct->countryInfoPresent) + session->country_info_present = true; + /* Check if Extended caps are present in probe resp or not */ + if (beacon_struct->ext_cap.present) + session->is_ext_caps_present = true; + /* Update HS 2.0 Information Element */ + if (beacon_struct->hs20vendor_ie.present) { + lim_log(mac_ctx, LOG1, + FL("HS20 Indication Element Present, rel#:%u, id:%u\n"), + beacon_struct->hs20vendor_ie.release_num, + beacon_struct->hs20vendor_ie.hs_id_present); + qdf_mem_copy(&session->hs20vendor_ie, + &beacon_struct->hs20vendor_ie, + sizeof(tDot11fIEhs20vendor_ie) - + sizeof(beacon_struct->hs20vendor_ie.hs_id)); + if (beacon_struct->hs20vendor_ie.hs_id_present) + qdf_mem_copy(&session->hs20vendor_ie.hs_id, + &beacon_struct->hs20vendor_ie.hs_id, + sizeof(beacon_struct->hs20vendor_ie.hs_id)); + } + qdf_mem_free(beacon_struct); + return; +} /****** end lim_extract_ap_capability() ******/ + +/** + * lim_get_htcb_state + * + ***FUNCTION: + * This routing provides the translation of Airgo Enum to HT enum for determining + * secondary channel offset. + * Airgo Enum is required for backward compatibility purposes. + * + * + ***NOTE: + * + * @param pMac - Pointer to Global MAC structure + * @return The corresponding HT enumeration + */ +ePhyChanBondState lim_get_htcb_state(ePhyChanBondState aniCBMode) +{ + switch (aniCBMode) { + case PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_LOW: + case PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_CENTERED: + case PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_HIGH: + case PHY_DOUBLE_CHANNEL_HIGH_PRIMARY: + return PHY_DOUBLE_CHANNEL_HIGH_PRIMARY; + case PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_LOW: + case PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_CENTERED: + case PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_HIGH: + case PHY_DOUBLE_CHANNEL_LOW_PRIMARY: + return PHY_DOUBLE_CHANNEL_LOW_PRIMARY; + case PHY_QUADRUPLE_CHANNEL_20MHZ_CENTERED_40MHZ_CENTERED: + return PHY_SINGLE_CHANNEL_CENTERED; + default: + return PHY_SINGLE_CHANNEL_CENTERED; + } +} diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_prop_exts_utils.h b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_prop_exts_utils.h new file mode 100644 index 0000000000000000000000000000000000000000..9aaaab9dde73d0bdf719f997aabba270383936cd --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_prop_exts_utils.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2011-2014, 2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * + * This file lim_prop_exts_utils.h contains the definitions + * used by all LIM modules to support proprietary features. + * Author: Chandra Modumudi + * Date: 12/11/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + * + */ + +#ifndef __LIM_PROP_EXTS_UTILS_H +#define __LIM_PROP_EXTS_UTILS_H + +/* Function templates */ +void limQuietBss(tpAniSirGlobal, uint32_t); +void lim_cleanupMeasData(tpAniSirGlobal); +void limDeleteMeasTimers(tpAniSirGlobal); +void limStopMeasTimers(tpAniSirGlobal pMac); +void lim_cleanupMeasResources(tpAniSirGlobal); +void limRestorePreLearnState(tpAniSirGlobal); +void limCollectMeasurementData(tpAniSirGlobal, uint32_t *, tpSchBeaconStruct); +void limCollectRSSI(tpAniSirGlobal); +void limDeleteCurrentBssWdsNode(tpAniSirGlobal); +uint32_t limComputeAvg(tpAniSirGlobal, uint32_t, uint32_t); + +/* / Function to extract AP's HCF capability from IE fields */ +void lim_extract_ap_capability(tpAniSirGlobal, uint8_t *, uint16_t, uint8_t *, + uint16_t *, uint8_t *, int8_t *, tpPESession); + +ePhyChanBondState lim_get_htcb_state(ePhyChanBondState aniCBMode); + +#endif /* __LIM_PROP_EXTS_UTILS_H */ diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_reassoc_utils.c b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_reassoc_utils.c new file mode 100644 index 0000000000000000000000000000000000000000..0257e705102e79bf7bba171799ab2a242e8f934a --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_reassoc_utils.c @@ -0,0 +1,558 @@ +/* + * Copyright (c) 2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * 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. + */ + +/** + * DOC: lim_reassoc_utils.c + * + * Host based roaming re-association utilities + */ + +#include "cds_api.h" +#include "ani_global.h" +#include "wni_api.h" +#include "sir_common.h" + +#include "wni_cfg.h" +#include "cfg_api.h" + +#include "sch_api.h" +#include "utils_api.h" +#include "lim_utils.h" +#include "lim_assoc_utils.h" +#include "lim_security_utils.h" +#include "lim_ser_des_utils.h" +#include "lim_sta_hash_api.h" +#include "lim_admit_control.h" +#include "lim_send_messages.h" +#include "lim_ibss_peer_mgmt.h" +#include "lim_ft_defs.h" +#include "lim_session.h" + +#include "qdf_types.h" +#include "wma_types.h" +#include "lim_types.h" + +/** + * lim_update_re_assoc_globals() - Update reassoc global data + * @pMac: Global MAC context + * @pAssocRsp: Reassociation response data + * @psessionEntry: PE Session + * + * This function is called to Update the Globals (LIM) during ReAssoc. + * + * Return: None + */ + +void lim_update_re_assoc_globals(tpAniSirGlobal pMac, tpSirAssocRsp pAssocRsp, + tpPESession psessionEntry) +{ + /* Update the current Bss Information */ + qdf_mem_copy(psessionEntry->bssId, + psessionEntry->limReAssocbssId, sizeof(tSirMacAddr)); + psessionEntry->currentOperChannel = psessionEntry->limReassocChannelId; + psessionEntry->htSecondaryChannelOffset = + psessionEntry->reAssocHtSupportedChannelWidthSet; + psessionEntry->htRecommendedTxWidthSet = + psessionEntry->reAssocHtRecommendedTxWidthSet; + psessionEntry->htSecondaryChannelOffset = + psessionEntry->reAssocHtSecondaryChannelOffset; + psessionEntry->limCurrentBssCaps = psessionEntry->limReassocBssCaps; + psessionEntry->limCurrentBssQosCaps = + psessionEntry->limReassocBssQosCaps; + psessionEntry->limCurrentBssPropCap = + psessionEntry->limReassocBssPropCap; + + qdf_mem_copy((uint8_t *) &psessionEntry->ssId, + (uint8_t *) &psessionEntry->limReassocSSID, + psessionEntry->limReassocSSID.length + 1); + + /* Store assigned AID for TIM processing */ + psessionEntry->limAID = pAssocRsp->aid & 0x3FFF; + /** Set the State Back to ReAssoc Rsp*/ + psessionEntry->limMlmState = eLIM_MLM_WT_REASSOC_RSP_STATE; + MTRACE(mac_trace + (pMac, TRACE_CODE_MLM_STATE, psessionEntry->peSessionId, + psessionEntry->limMlmState)); + +} + +/** + * @lim_handle_del_bss_in_re_assoc_context() - DEL BSS during reassociation + * @pMac: Global MAC Context + * @pStaDs: Station Hash entry + * @psessionEntry: PE Session + * + * While Processing the ReAssociation Response Frame in STA, + * a.immediately after receiving the Reassoc Response the RxCleanUp is + * being issued and the end of DelBSS the new BSS is being added. + * + * b. If an AP rejects the ReAssociation (Disassoc/Deauth) with some context + * change, We need to update CSR with ReAssocCNF Response with the + * ReAssoc Fail and the reason Code, that is also being handled in the + * DELBSS context only + * + * Return: None + */ +void lim_handle_del_bss_in_re_assoc_context(tpAniSirGlobal pMac, + tpDphHashNode pStaDs, tpPESession psessionEntry) +{ + tLimMlmReassocCnf mlmReassocCnf; + tpSirBssDescription bss_desc; + /* + * Skipped the DeleteDPH Hash Entry as we need it for the new BSS + * Set the MlmState to IDLE + */ + psessionEntry->limMlmState = eLIM_MLM_IDLE_STATE; + /* Update PE session Id */ + mlmReassocCnf.sessionId = psessionEntry->peSessionId; + switch (psessionEntry->limSmeState) { + case eLIM_SME_WT_REASSOC_STATE: + { + tpSirAssocRsp assocRsp; + tpDphHashNode pStaDs; + tSirRetStatus retStatus = eSIR_SUCCESS; + tpSchBeaconStruct beacon_struct; + beacon_struct = qdf_mem_malloc(sizeof(tSchBeaconStruct)); + if (NULL == beacon_struct) { + lim_log(pMac, LOGE, FL("beaconStruct alloc failed")); + mlmReassocCnf.resultCode = + eSIR_SME_RESOURCES_UNAVAILABLE; + mlmReassocCnf.protStatusCode = + eSIR_MAC_UNSPEC_FAILURE_STATUS; + lim_delete_dph_hash_entry(pMac, psessionEntry->bssId, + DPH_STA_HASH_INDEX_PEER, psessionEntry); + goto error; + } + /* Delete the older STA Table entry */ + lim_delete_dph_hash_entry(pMac, psessionEntry->bssId, + DPH_STA_HASH_INDEX_PEER, psessionEntry); + /* + * Add an entry for AP to hash table + * maintained by DPH module + */ + pStaDs = dph_add_hash_entry(pMac, + psessionEntry->limReAssocbssId, + DPH_STA_HASH_INDEX_PEER, + &psessionEntry->dph.dphHashTable); + if (pStaDs == NULL) { + /* Could not add hash table entry */ + lim_log(pMac, LOGE, + FL("could not add hash entry at DPH for ")); + lim_print_mac_addr(pMac, + psessionEntry->limReAssocbssId, LOGE); + mlmReassocCnf.resultCode = + eSIR_SME_RESOURCES_UNAVAILABLE; + mlmReassocCnf.protStatusCode = eSIR_SME_SUCCESS; + qdf_mem_free(beacon_struct); + goto error; + } + /* + * While Processing the ReAssoc Response Frame the Rsp Frame + * is being stored to be used here for sending ADDBSS + */ + assocRsp = + (tpSirAssocRsp) psessionEntry->limAssocResponseData; + lim_update_assoc_sta_datas(pMac, pStaDs, assocRsp, + psessionEntry); + lim_update_re_assoc_globals(pMac, assocRsp, psessionEntry); + bss_desc = &psessionEntry->pLimReAssocReq->bssDescription; + lim_extract_ap_capabilities(pMac, + (uint8_t *) bss_desc->ieFields, + lim_get_ielen_from_bss_description(bss_desc), + beacon_struct); + if (pMac->lim.gLimProtectionControl != + WNI_CFG_FORCE_POLICY_PROTECTION_DISABLE) + lim_decide_sta_protection_on_assoc(pMac, + beacon_struct, + psessionEntry); + if (beacon_struct->erpPresent) { + if (beacon_struct->erpIEInfo.barkerPreambleMode) + psessionEntry->beaconParams.fShortPreamble = 0; + else + psessionEntry->beaconParams.fShortPreamble = 1; + } + /* + * updateBss flag is false, as in this case, PE is first + * deleting the existing BSS and then adding a new one + */ + if (eSIR_SUCCESS != + lim_sta_send_add_bss(pMac, assocRsp, beacon_struct, + bss_desc, + false, psessionEntry)) { + lim_log(pMac, LOGE, + FL("Posting ADDBSS in the ReAssocCtx Failed ")); + retStatus = eSIR_FAILURE; + } + if (retStatus != eSIR_SUCCESS) { + mlmReassocCnf.resultCode = + eSIR_SME_RESOURCES_UNAVAILABLE; + mlmReassocCnf.protStatusCode = + eSIR_MAC_UNSPEC_FAILURE_STATUS; + qdf_mem_free(assocRsp); + pMac->lim.gLimAssocResponseData = NULL; + qdf_mem_free(beacon_struct); + goto error; + } + qdf_mem_free(assocRsp); + qdf_mem_free(beacon_struct); + psessionEntry->limAssocResponseData = NULL; + } + break; + case eLIM_SME_WT_REASSOC_LINK_FAIL_STATE: + { + mlmReassocCnf.resultCode = + pStaDs->mlmStaContext.disassocReason; + mlmReassocCnf.protStatusCode = + pStaDs->mlmStaContext.cleanupTrigger; + /** Set the SME State back to WT_Reassoc State*/ + psessionEntry->limSmeState = eLIM_SME_WT_REASSOC_STATE; + lim_delete_dph_hash_entry(pMac, pStaDs->staAddr, + pStaDs->assocId, psessionEntry); + if (LIM_IS_STA_ROLE(psessionEntry)) { + psessionEntry->limMlmState = + eLIM_MLM_IDLE_STATE; + } + lim_post_sme_message(pMac, LIM_MLM_REASSOC_CNF, + (uint32_t *) &mlmReassocCnf); + } + break; + default: + lim_log(pMac, LOGE, + FL("DelBss in wrong system Role and SME State")); + + mlmReassocCnf.resultCode = eSIR_SME_REFUSED; + mlmReassocCnf.protStatusCode = + eSIR_SME_UNEXPECTED_REQ_RESULT_CODE; + goto error; + } + return; +error: + lim_post_sme_message(pMac, LIM_MLM_REASSOC_CNF, + (uint32_t *) &mlmReassocCnf); +} + +/** + * @lim_handle_add_bss_in_re_assoc_context() - ADD BSS during reassociation + * @pMac: Global MAC Context + * @pStaDs: Station Hash entry + * @psessionEntry: PE Session + * + * While Processing the ReAssociation Response Frame in STA, + * a. immediately after receiving the Reassoc Response the RxCleanUp is + * being issued and the end of DelBSS the new BSS is being added. + * + * b. If an AP rejects the ReAssociation (Disassoc/Deauth) with some context + * change, We need to update CSR with ReAssocCNF Response with the + * ReAssoc Fail and the reason Code, that is also being handled in the + * DELBSS context only + * + * Return: None + */ +void lim_handle_add_bss_in_re_assoc_context(tpAniSirGlobal pMac, + tpDphHashNode pStaDs, tpPESession psessionEntry) +{ + tLimMlmReassocCnf mlmReassocCnf; + /** Skipped the DeleteDPH Hash Entry as we need it for the new BSS*/ + /** Set the MlmState to IDLE*/ + psessionEntry->limMlmState = eLIM_MLM_IDLE_STATE; + MTRACE(mac_trace + (pMac, TRACE_CODE_MLM_STATE, psessionEntry->peSessionId, + psessionEntry->limMlmState)); + switch (psessionEntry->limSmeState) { + case eLIM_SME_WT_REASSOC_STATE: { + tpSirAssocRsp assocRsp; + tpDphHashNode pStaDs; + tSirRetStatus retStatus = eSIR_SUCCESS; + tSchBeaconStruct *pBeaconStruct; + pBeaconStruct = + qdf_mem_malloc(sizeof(tSchBeaconStruct)); + if (NULL == pBeaconStruct) { + lim_log(pMac, LOGE, FL("Unable to allocate memory")); + mlmReassocCnf.resultCode = + eSIR_SME_RESOURCES_UNAVAILABLE; + mlmReassocCnf.protStatusCode = + eSIR_SME_RESOURCES_UNAVAILABLE; + goto Error; + } + /* Get the AP entry from DPH hash table */ + pStaDs = + dph_get_hash_entry(pMac, DPH_STA_HASH_INDEX_PEER, + &psessionEntry->dph.dphHashTable); + if (pStaDs == NULL) { + lim_log(pMac, LOGE, + FL("Fail to get STA PEER entry from hash")); + mlmReassocCnf.resultCode = + eSIR_SME_RESOURCES_UNAVAILABLE; + mlmReassocCnf.protStatusCode = eSIR_SME_SUCCESS; + qdf_mem_free(pBeaconStruct); + goto Error; + } + /* + * While Processing the ReAssoc Response Frame the Rsp Frame + * is being stored to be used here for sending ADDBSS + */ + assocRsp = + (tpSirAssocRsp) psessionEntry->limAssocResponseData; + lim_update_assoc_sta_datas(pMac, pStaDs, assocRsp, + psessionEntry); + lim_update_re_assoc_globals(pMac, assocRsp, psessionEntry); + lim_extract_ap_capabilities(pMac, + (uint8_t *) psessionEntry-> + pLimReAssocReq->bssDescription. + ieFields, + lim_get_ielen_from_bss_description + (&psessionEntry-> + pLimReAssocReq-> + bssDescription), + pBeaconStruct); + if (pMac->lim.gLimProtectionControl != + WNI_CFG_FORCE_POLICY_PROTECTION_DISABLE) + lim_decide_sta_protection_on_assoc(pMac, + pBeaconStruct, + psessionEntry); + + if (pBeaconStruct->erpPresent) { + if (pBeaconStruct->erpIEInfo.barkerPreambleMode) + psessionEntry->beaconParams. + fShortPreamble = 0; + else + psessionEntry->beaconParams. + fShortPreamble = 1; + } + + psessionEntry->isNonRoamReassoc = 1; + if (eSIR_SUCCESS != + lim_sta_send_add_bss(pMac, assocRsp, pBeaconStruct, + &psessionEntry->pLimReAssocReq-> + bssDescription, true, + psessionEntry)) { + lim_log(pMac, LOGE, + FL("Post ADDBSS in the ReAssocCtxt Failed ")); + retStatus = eSIR_FAILURE; + } + if (retStatus != eSIR_SUCCESS) { + mlmReassocCnf.resultCode = + eSIR_SME_RESOURCES_UNAVAILABLE; + mlmReassocCnf.protStatusCode = + eSIR_MAC_UNSPEC_FAILURE_STATUS; + qdf_mem_free(assocRsp); + pMac->lim.gLimAssocResponseData = NULL; + qdf_mem_free(pBeaconStruct); + goto Error; + } + qdf_mem_free(assocRsp); + psessionEntry->limAssocResponseData = NULL; + qdf_mem_free(pBeaconStruct); + } + break; + case eLIM_SME_WT_REASSOC_LINK_FAIL_STATE: { + /* Case wherein the DisAssoc / Deauth + * being sent as response to ReAssoc Req + * Send the Reason code as the same received + * in Disassoc / Deauth Frame + */ + mlmReassocCnf.resultCode = + pStaDs->mlmStaContext.disassocReason; + mlmReassocCnf.protStatusCode = + pStaDs->mlmStaContext.cleanupTrigger; + /** Set the SME State back to WT_Reassoc State*/ + psessionEntry->limSmeState = eLIM_SME_WT_REASSOC_STATE; + lim_delete_dph_hash_entry(pMac, pStaDs->staAddr, + pStaDs->assocId, psessionEntry); + if (LIM_IS_STA_ROLE(psessionEntry)) { + psessionEntry->limMlmState = + eLIM_MLM_IDLE_STATE; + MTRACE(mac_trace + (pMac, TRACE_CODE_MLM_STATE, + psessionEntry->peSessionId, + psessionEntry->limMlmState)); + } + + lim_post_sme_message(pMac, LIM_MLM_REASSOC_CNF, + (uint32_t *) &mlmReassocCnf); + } + break; + default: + lim_log(pMac, LOGE, + FL("DelBss in the wrong system Role and SME State")); + mlmReassocCnf.resultCode = eSIR_SME_REFUSED; + mlmReassocCnf.protStatusCode = + eSIR_SME_UNEXPECTED_REQ_RESULT_CODE; + goto Error; + } + return; +Error: + lim_post_sme_message(pMac, LIM_MLM_REASSOC_CNF, + (uint32_t *) &mlmReassocCnf); +} + +/** + * lim_is_reassoc_in_progress() - Check if reassoiciation is in progress + * @pMac: Global MAC Context + * @psessionEntry: PE Session + * + * Return: true When STA is waiting for Reassoc response from AP + * else false + */ +bool lim_is_reassoc_in_progress(tpAniSirGlobal pMac, tpPESession psessionEntry) +{ + if (psessionEntry == NULL) + return false; + if ((LIM_IS_STA_ROLE(psessionEntry)) && + ((psessionEntry->limSmeState == eLIM_SME_WT_REASSOC_STATE) || + (psessionEntry->limSmeState == + eLIM_SME_WT_REASSOC_LINK_FAIL_STATE))) + return true; + + return false; +} + +/** + * lim_add_ft_sta_self()- function to add STA once we have connected with a + * new AP + * @mac_ctx: pointer to global mac structure + * @assoc_id: association id for the station connection + * @session_entry: pe session entr + * + * This function is called to add a STA once we have connected with a new + * AP, that we have performed an FT to. + * + * The Add STA Response is created and now after the ADD Bss Is Successful + * we add the self sta. We update with the association id from the reassoc + * response from the AP. + * + * Return: eSIR_SUCCESS on success else eSirRetStatus failure codes + */ +tSirRetStatus lim_add_ft_sta_self(tpAniSirGlobal mac_ctx, uint16_t assoc_id, + tpPESession session_entry) +{ + tpAddStaParams add_sta_params = NULL; + tSirRetStatus ret_code = eSIR_SUCCESS; + tSirMsgQ msg_q; + + add_sta_params = session_entry->ftPEContext.pAddStaReq; + add_sta_params->assocId = assoc_id; + add_sta_params->smesessionId = session_entry->smeSessionId; + + msg_q.type = WMA_ADD_STA_REQ; + msg_q.reserved = 0; + msg_q.bodyptr = add_sta_params; + msg_q.bodyval = 0; + + QDF_TRACE(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_DEBUG, + "Sending WMA_ADD_STA_REQ (aid %d)", + add_sta_params->assocId); + MTRACE(mac_trace_msg_tx(mac_ctx, session_entry->peSessionId, + msg_q.type)); + + session_entry->limPrevMlmState = session_entry->limMlmState; + MTRACE(mac_trace(mac_ctx, TRACE_CODE_MLM_STATE, + session_entry->peSessionId, eLIM_MLM_WT_ADD_STA_RSP_STATE)); + session_entry->limMlmState = eLIM_MLM_WT_ADD_STA_RSP_STATE; + ret_code = wma_post_ctrl_msg(mac_ctx, &msg_q); + if (eSIR_SUCCESS != ret_code) { + lim_log(mac_ctx, LOGE, + FL("Posting WMA_ADD_STA_REQ to HAL failed, reason=%X"), + ret_code); + qdf_mem_free(add_sta_params); + } + + session_entry->ftPEContext.pAddStaReq = NULL; + return ret_code; +} + +/** + * lim_restore_pre_reassoc_state() - Restore the pre-association context + * @pMac: Global MAC Context + * @resultCode: Assoc response result + * @protStatusCode: Internal protocol status code + * @psessionEntry: PE Session + * + * This function is called on STA role whenever Reasociation + * Response with a reject code is received from AP. + * Reassociation failure timer is stopped, Old (or current) AP's + * context is restored both at Polaris & software + * + * Return: None + */ + +void +lim_restore_pre_reassoc_state(tpAniSirGlobal pMac, + tSirResultCodes resultCode, uint16_t protStatusCode, + tpPESession psessionEntry) +{ + tLimMlmReassocCnf mlmReassocCnf; + + lim_log(pMac, LOG1, + FL("sessionid: %d protStatusCode: %d resultCode: %d"), + psessionEntry->smeSessionId, protStatusCode, resultCode); + + psessionEntry->limMlmState = eLIM_MLM_LINK_ESTABLISHED_STATE; + MTRACE(mac_trace + (pMac, TRACE_CODE_MLM_STATE, psessionEntry->peSessionId, + eLIM_MLM_LINK_ESTABLISHED_STATE)); + + /* 'Change' timer for future activations */ + lim_deactivate_and_change_timer(pMac, eLIM_REASSOC_FAIL_TIMER); + + lim_set_channel(pMac, psessionEntry->currentOperChannel, + psessionEntry->ch_center_freq_seg0, + psessionEntry->ch_center_freq_seg1, + psessionEntry->ch_width, + psessionEntry->maxTxPower, + psessionEntry->peSessionId); + + /* @ToDo:Need to Integrate the STOP the Dataxfer to AP from 11H code */ + + mlmReassocCnf.resultCode = resultCode; + mlmReassocCnf.protStatusCode = protStatusCode; + mlmReassocCnf.sessionId = psessionEntry->peSessionId; + lim_post_sme_message(pMac, + LIM_MLM_REASSOC_CNF, (uint32_t *) &mlmReassocCnf); +} + +/** + * lim_post_reassoc_failure() - Post failure message to SME + * @pMac: Global MAC Context + * @resultCode: Result Code + * @protStatusCode: Protocol Status Code + * @psessionEntry: PE Session + * + * Return: None + */ +void lim_post_reassoc_failure(tpAniSirGlobal pMac, + tSirResultCodes resultCode, uint16_t protStatusCode, + tpPESession psessionEntry) +{ + tLimMlmReassocCnf mlmReassocCnf; + + psessionEntry->limMlmState = eLIM_MLM_LINK_ESTABLISHED_STATE; + MTRACE(mac_trace + (pMac, TRACE_CODE_MLM_STATE, psessionEntry->peSessionId, + eLIM_MLM_LINK_ESTABLISHED_STATE)); + + lim_deactivate_and_change_timer(pMac, eLIM_REASSOC_FAIL_TIMER); + + mlmReassocCnf.resultCode = resultCode; + mlmReassocCnf.protStatusCode = protStatusCode; + mlmReassocCnf.sessionId = psessionEntry->peSessionId; + lim_post_sme_message(pMac, + LIM_MLM_REASSOC_CNF, (uint32_t *) &mlmReassocCnf); +} diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_roam_timer_utils.c b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_roam_timer_utils.c new file mode 100644 index 0000000000000000000000000000000000000000..aebc31cd3d51ec9c3739fa30b526691692d846d2 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_roam_timer_utils.c @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * 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. + */ + +/** + * DOC: lim_roam_timer_utils.c + * + * Host based roaming timers implementation + */ + +#include "lim_types.h" +#include "lim_utils.h" +#include "lim_assoc_utils.h" +#include "lim_security_utils.h" + +/** + * lim_create_timers_host_roam() - Create timers used in host based roaming + * @mac_ctx: Global MAC context + * + * Create reassoc and preauth timers + * + * Return: TX_SUCCESS or TX_TIMER_ERROR + */ +uint32_t lim_create_timers_host_roam(tpAniSirGlobal mac_ctx) +{ + uint32_t cfg_value; + if (wlan_cfg_get_int(mac_ctx, WNI_CFG_REASSOCIATION_FAILURE_TIMEOUT, + &cfg_value) != eSIR_SUCCESS) + lim_log(mac_ctx, LOGP, + FL("could not retrieve ReassocFailureTimeout value")); + + cfg_value = SYS_MS_TO_TICKS(cfg_value); + /* Create Association failure timer and activate it later */ + if (tx_timer_create(mac_ctx, + &mac_ctx->lim.limTimers.gLimReassocFailureTimer, + "REASSOC FAILURE TIMEOUT", lim_assoc_failure_timer_handler, + LIM_REASSOC, cfg_value, 0, TX_NO_ACTIVATE) != TX_SUCCESS) { + lim_log(mac_ctx, LOGP, FL("failed to create Reassoc timer")); + return TX_TIMER_ERROR; + } + cfg_value = 1000; + cfg_value = SYS_MS_TO_TICKS(cfg_value); + if (tx_timer_create(mac_ctx, + &mac_ctx->lim.limTimers.gLimFTPreAuthRspTimer, + "FT PREAUTH RSP TIMEOUT", + lim_timer_handler, SIR_LIM_FT_PREAUTH_RSP_TIMEOUT, + cfg_value, 0, TX_NO_ACTIVATE) != TX_SUCCESS) { + lim_log(mac_ctx, LOGP, FL("failed to create Join fail timer")); + goto err_roam_timer; + } + return TX_SUCCESS; + +err_roam_timer: + tx_timer_delete(&mac_ctx->lim.limTimers.gLimReassocFailureTimer); + return TX_TIMER_ERROR; +} + +/** + * lim_delete_timers_host_roam() - Delete timers used in host based roaming + * @mac_ctx: Global MAC context + * + * Delete reassoc and preauth timers + * + * Return: none + */ +void lim_delete_timers_host_roam(tpAniSirGlobal mac_ctx) +{ + tLimTimers *lim_timer = &mac_ctx->lim.limTimers; + + /* Deactivate and delete Reassociation failure timer. */ + tx_timer_deactivate(&lim_timer->gLimReassocFailureTimer); + tx_timer_delete(&lim_timer->gLimReassocFailureTimer); + + /* Deactivate and delete FT Preauth response timer */ + tx_timer_deactivate(&lim_timer->gLimFTPreAuthRspTimer); + tx_timer_delete(&lim_timer->gLimFTPreAuthRspTimer); +} + +/** + * lim_deactivate_and_change_timer_host_roam() - Change timers in host roaming + * @mac_ctx: Pointer to Global MAC structure + * @timer_id: enum of timer to be deactivated and changed + * + * This function is called to deactivate and change a timer for future + * re-activation for host roaming timers. + * + * Return: None + */ +void lim_deactivate_and_change_timer_host_roam(tpAniSirGlobal mac_ctx, + uint32_t timer_id) +{ + uint32_t val = 0; + + switch (timer_id) { + case eLIM_REASSOC_FAIL_TIMER: + if (tx_timer_deactivate + (&mac_ctx->lim.limTimers.gLimReassocFailureTimer) != + TX_SUCCESS) { + lim_log(mac_ctx, LOGP, + FL("unable to deactivate Reassoc fail timer")); + } + if (wlan_cfg_get_int(mac_ctx, + WNI_CFG_REASSOCIATION_FAILURE_TIMEOUT, + &val) != eSIR_SUCCESS) { + lim_log(mac_ctx, LOGP, + FL("could not get ReassocFailureTimeout val")); + } + val = SYS_MS_TO_TICKS(val); + if (tx_timer_change + (&mac_ctx->lim.limTimers.gLimReassocFailureTimer, val, + 0) != TX_SUCCESS) { + lim_log(mac_ctx, LOGP, + FL("unable to change Reassoc fail timer")); + } + break; + + case eLIM_FT_PREAUTH_RSP_TIMER: + if (tx_timer_deactivate + (&mac_ctx->lim.limTimers.gLimFTPreAuthRspTimer) != + TX_SUCCESS) { + lim_log(mac_ctx, LOGP, + FL("Unable to deactivate Preauth Fail timer")); + return; + } + val = 1000; + val = SYS_MS_TO_TICKS(val); + if (tx_timer_change( + &mac_ctx->lim.limTimers.gLimFTPreAuthRspTimer, + val, 0) != TX_SUCCESS) { + lim_log(mac_ctx, LOGP, + FL("Unable to change Join Failure timer")); + return; + } + break; + } +} diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_scan_result_utils.c b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_scan_result_utils.c new file mode 100644 index 0000000000000000000000000000000000000000..cdae3603620972d953d95737da8a5c85a6bfed56 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_scan_result_utils.c @@ -0,0 +1,392 @@ +/* + * Copyright (c) 2011-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * This file lim_scan_result_utils.cc contains the utility functions + * LIM uses for maintaining and accessing scan results on STA. + * Author: Chandra Modumudi + * Date: 02/13/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + */ + +#include "lim_types.h" +#include "lim_utils.h" +#include "lim_ser_des_utils.h" +#include "lim_api.h" +#include "lim_ft_defs.h" +#include "lim_session.h" +#include "rrm_api.h" +#include "cds_utils.h" + + +/** + * lim_collect_bss_description() + * + ***FUNCTION: + * This function is called during scan upon receiving + * Beacon/Probe Response frame to check if the received + * frame matches scan criteria, collect BSS description + * and add it to cached scan results. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param pMac - Pointer to Global MAC structure + * @param pBPR - Pointer to parsed Beacon/Probe Response structure + * @param pRxPacketInfo - Pointer to Received frame's BD + * @param fScanning - flag to indicate if it is during scan. + * --------------------------------------------- + * + * @return None + */ +void +lim_collect_bss_description(tpAniSirGlobal pMac, + tSirBssDescription *pBssDescr, + tpSirProbeRespBeacon pBPR, + uint8_t *pRxPacketInfo, uint8_t fScanning) +{ + uint8_t *pBody; + uint32_t ieLen = 0; + tpSirMacMgmtHdr pHdr; + uint8_t channelNum; + uint8_t rxChannel; + uint8_t rfBand = 0; + + pHdr = WMA_GET_RX_MAC_HEADER(pRxPacketInfo); + + if (SIR_MAC_B_PR_SSID_OFFSET > WMA_GET_RX_PAYLOAD_LEN(pRxPacketInfo)) { + QDF_ASSERT(WMA_GET_RX_PAYLOAD_LEN(pRxPacketInfo) >= + SIR_MAC_B_PR_SSID_OFFSET); + return; + } + ieLen = + WMA_GET_RX_PAYLOAD_LEN(pRxPacketInfo) - SIR_MAC_B_PR_SSID_OFFSET; + rxChannel = WMA_GET_RX_CH(pRxPacketInfo); + pBody = WMA_GET_RX_MPDU_DATA(pRxPacketInfo); + rfBand = WMA_GET_RX_RFBAND(pRxPacketInfo); + + /** + * Length of BSS desription is without length of + * length itself and length of pointer that holds ieFields. + * + * tSirBssDescription + * +--------+---------------------------------+---------------+ + * | length | other fields | pointer to IEs| + * +--------+---------------------------------+---------------+ + * ^ + * ieFields + */ + pBssDescr->length = (uint16_t)(offsetof(tSirBssDescription, ieFields[0]) + - sizeof(pBssDescr->length) + ieLen); + + /* Copy BSS Id */ + qdf_mem_copy((uint8_t *) &pBssDescr->bssId, + (uint8_t *) pHdr->bssId, sizeof(tSirMacAddr)); + + /* Copy Timestamp, Beacon Interval and Capability Info */ + pBssDescr->scansystimensec = qdf_get_bootbased_boottime_ns(); + + pBssDescr->timeStamp[0] = pBPR->timeStamp[0]; + pBssDescr->timeStamp[1] = pBPR->timeStamp[1]; + pBssDescr->beaconInterval = pBPR->beaconInterval; + pBssDescr->capabilityInfo = + lim_get_u16((uint8_t *) &pBPR->capabilityInfo); + + /* HT capability */ + if (pBPR->HTCaps.present) { + pBssDescr->ht_caps_present = 1; + if (pBPR->HTCaps.supportedChannelWidthSet) + pBssDescr->chan_width = eHT_CHANNEL_WIDTH_40MHZ; + } + /* VHT Parameters */ + if (pBPR->VHTCaps.present) { + pBssDescr->vht_caps_present = 1; + if (pBPR->VHTCaps.muBeamformerCap) + pBssDescr->beacomforming_capable = 1; + } + if (pBPR->VHTOperation.present) + if (pBPR->VHTOperation.chanWidth == 1) + pBssDescr->chan_width = eHT_CHANNEL_WIDTH_80MHZ; + + if (!pBssDescr->beaconInterval) { + lim_log(pMac, LOGW, + FL("Beacon Interval is ZERO, making it to default 100 " + MAC_ADDRESS_STR), MAC_ADDR_ARRAY(pHdr->bssId)); + pBssDescr->beaconInterval = 100; + } + /* + * There is a narrow window after Channel Switch msg is sent to HAL and before the AGC is shut + * down and beacons/Probe Rsps can trickle in and we may report the incorrect channel in 5Ghz + * band, so not relying on the 'last Scanned Channel' stored in LIM. + * Instead use the value returned by RXP in BD. This the the same value which HAL programs into + * RXP before every channel switch. + * Right now there is a problem in 5Ghz, where we are receiving beacons from a channel different from + * the currently scanned channel. so incorrect channel is reported to CSR and association does not happen. + * So for now we keep on looking for the channel info in the beacon (DSParamSet IE OR HT Info IE), and only if it + * is not present in the beacon, we go for the channel info present in RXP. + * This fix will work for 5Ghz 11n devices, but for 11a devices, we have to rely on RXP routing flag to get the correct channel. + * So The problem of incorrect channel reporting in 5Ghz will still remain for 11a devices. + */ + pBssDescr->channelId = lim_get_channel_from_beacon(pMac, pBPR); + + if (pBssDescr->channelId == 0) { + /* If the channel Id is not retrieved from Beacon, extract the channel from BD */ + if (!rxChannel) { + rxChannel = pMac->lim.gLimCurrentScanChannelId; + } + pBssDescr->channelId = rxChannel; + } + + pBssDescr->channelIdSelf = pBssDescr->channelId; + pBssDescr->rx_channel = rxChannel; + + /* set the network type in bss description */ + channelNum = pBssDescr->channelId; + pBssDescr->nwType = + lim_get_nw_type(pMac, channelNum, SIR_MAC_MGMT_FRAME, pBPR); + + /* Copy RSSI & SINR from BD */ + + lim_log(pMac, LOG4, "*********BSS Description for BSSID:********* "); + sir_dump_buf(pMac, SIR_LIM_MODULE_ID, LOG4, pBssDescr->bssId, 6); + sir_dump_buf(pMac, SIR_LIM_MODULE_ID, LOG4, + (uint8_t *) pRxPacketInfo, 36); + + pBssDescr->rssi = (int8_t) WMA_GET_RX_RSSI_NORMALIZED(pRxPacketInfo); + pBssDescr->rssi_raw = (int8_t) WMA_GET_RX_RSSI_RAW(pRxPacketInfo); + + /* SINR no longer reported by HW */ + pBssDescr->sinr = 0; + lim_log(pMac, LOG3, + FL(MAC_ADDRESS_STR " rssi: normalized = %d, absolute = %d"), + MAC_ADDR_ARRAY(pHdr->bssId), pBssDescr->rssi, + pBssDescr->rssi_raw); + + pBssDescr->received_time = (uint64_t)qdf_mc_timer_get_system_time(); + pBssDescr->tsf_delta = WMA_GET_RX_TSF_DELTA(pRxPacketInfo); + pBssDescr->seq_ctrl = pHdr->seqControl; + + lim_log(pMac, LOG1, + FL("BSSID: "MAC_ADDRESS_STR " tsf_delta = %u ReceivedTime = %llu ssid = %s"), + MAC_ADDR_ARRAY(pHdr->bssId), pBssDescr->tsf_delta, + pBssDescr->received_time, + ((pBPR->ssidPresent) ? (char *)pBPR->ssId.ssId : "")); + + lim_log(pMac, LOG1, FL("Seq Ctrl: Frag Num: %d, Seq Num: LO:%02x HI:%02x"), + pBssDescr->seq_ctrl.fragNum, pBssDescr->seq_ctrl.seqNumLo, + pBssDescr->seq_ctrl.seqNumHi); + + if (fScanning) { + rrm_get_start_tsf(pMac, pBssDescr->startTSF); + pBssDescr->parentTSF = WMA_GET_RX_TIMESTAMP(pRxPacketInfo); + } + + /* MobilityDomain */ + pBssDescr->mdie[0] = 0; + pBssDescr->mdie[1] = 0; + pBssDescr->mdie[2] = 0; + pBssDescr->mdiePresent = false; + /* If mdie is present in the probe resp we */ + /* fill it in the bss description */ + if (pBPR->mdiePresent) { + pBssDescr->mdiePresent = true; + pBssDescr->mdie[0] = pBPR->mdie[0]; + pBssDescr->mdie[1] = pBPR->mdie[1]; + pBssDescr->mdie[2] = pBPR->mdie[2]; + } + + if (pBPR->QBSSLoad.present) { + pBssDescr->QBSSLoad_present = true; + pBssDescr->QBSSLoad_avail = pBPR->QBSSLoad.avail; + pBssDescr->qbss_chan_load = pBPR->QBSSLoad.chautil; + } + /* Copy IE fields */ + qdf_mem_copy((uint8_t *) &pBssDescr->ieFields, + pBody + SIR_MAC_B_PR_SSID_OFFSET, ieLen); + + /*set channel number in beacon in case it is not present */ + pBPR->channelNumber = pBssDescr->channelId; + + lim_log(pMac, LOG3, + FL("Collected BSS Description for Channel(%1d), length(%u), IE Fields(%u)"), + pBssDescr->channelId, pBssDescr->length, ieLen); + pMac->lim.beacon_probe_rsp_cnt_per_scan++; + + return; +} /*** end lim_collect_bss_description() ***/ + +/** + * lim_check_and_add_bss_description() + * @mac_ctx: Pointer to Global MAC structure + * @bpr: Pointer to parsed Beacon/Probe Response structure + * @rx_packet_info: Pointer to Received frame's BD + * @scanning: bool to indicate whether the BSS is from current scan + * or just happens to receive a beacon + * + * FUNCTION: + * This function is called during scan upon receiving + * Beacon/Probe Response frame to check if the received + * frame matches scan criteria, collect BSS description + * and add it to cached scan results. + * + * Return: None + */ + +void +lim_check_and_add_bss_description(tpAniSirGlobal mac_ctx, + tpSirProbeRespBeacon bpr, uint8_t *rx_packet_info, + bool scanning, uint8_t fProbeRsp) +{ + tSirBssDescription *bssdescr = NULL; + uint32_t frame_len, ie_len = 0; + uint8_t rx_chan_in_beacon = 0; + QDF_STATUS status; + uint8_t rf_band = 0; + uint8_t rx_chan_bd = 0; + uint32_t flags = 0; + bool drop_bcn_prb_rsp = true; + uint8_t freq_diff = 0; + + tSirMacAddr bssid_zero = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0}; + tpSirMacDataHdr3a hdr; + + hdr = WMA_GET_RX_MPDUHEADER3A((uint8_t *) rx_packet_info); + + /* Check For Null BSSID and Skip in case of P2P */ + if (!qdf_mem_cmp(bssid_zero, &hdr->addr3, 6)) + return; + + /* + * SSID/BSSID policy: + * Accept beacons/probe responses with any SSID or BSSID because + * multiple scan requests may be running at the same time and + * firmware may forward results to CLD from scans requested through a + * different path. + * + * CSA Policy: + * There is no point in caching & reporting the scan results for APs + * which are in the process of switching the channel. So, we are not + * caching the scan results for APs which are adverzing the + * channel-switch element in their beacons and probe responses. + */ + if (bpr->channelSwitchPresent) + return; + + /* + * If beacon/probe resp DS param channel does not match with + * RX BD channel then don't save the results. It might be a beacon + * from another channel heard as noise on the current scanning channel + */ + + if ((bpr->dsParamsPresent) || (bpr->HTInfo.present)) { + /* This means that we are in 2.4GHz mode or 5GHz 11n mode */ + rx_chan_in_beacon = lim_get_channel_from_beacon(mac_ctx, bpr); + rf_band = WMA_GET_RX_RFBAND(rx_packet_info); + rx_chan_bd = WMA_GET_RX_CH(rx_packet_info); + + if (rx_chan_bd != rx_chan_in_beacon) { + /* Drop beacon, if CH do not match */ + if (mac_ctx->allow_adj_ch_bcn) { + freq_diff = abs(cds_chan_to_freq(rx_chan_bd) - + cds_chan_to_freq( + rx_chan_in_beacon)); + if (freq_diff <= 10) + drop_bcn_prb_rsp = false; + } + /* Drop beacon, if CH do not match, Drop */ + if (!fProbeRsp && drop_bcn_prb_rsp) { + lim_log(mac_ctx, LOG3, + FL("Beacon/Probe Rsp dropped. Channel in BD %d. Channel in beacon %d"), + rx_chan_bd, rx_chan_in_beacon); + return; + } + /* Probe RSP, do not drop */ + else { + if (!mac_ctx->allow_adj_ch_bcn) + flags |= WLAN_SKIP_RSSI_UPDATE; + lim_log(mac_ctx, LOG3, + FL("SSID %s, CH in ProbeRsp %d, CH in BD %d, mismatch, Do Not Drop"), + bpr->ssId.ssId, rx_chan_in_beacon, + WMA_GET_RX_CH(rx_packet_info)); + WMA_GET_RX_CH(rx_packet_info) = + rx_chan_in_beacon; + } + } + } + + /* + * Allocate buffer to hold BSS description from + * received Beacon frame. + * Include size of fixed fields and IEs length + */ + + ie_len = WMA_GET_RX_PAYLOAD_LEN(rx_packet_info); + if (ie_len <= SIR_MAC_B_PR_SSID_OFFSET) { + lim_log(mac_ctx, LOGP, + FL("RX packet has invalid length %d"), ie_len); + return; + } + + ie_len -= SIR_MAC_B_PR_SSID_OFFSET; + + /* IEs will be overlap ieFields field. Adjust the length accordingly */ + frame_len = sizeof(*bssdescr) + ie_len - sizeof(bssdescr->ieFields[1]); + bssdescr = (tSirBssDescription *) qdf_mem_malloc(frame_len); + + if (NULL == bssdescr) { + /* Log error */ + lim_log(mac_ctx, LOGE, + FL("qdf_mem_malloc(length=%d) failed"), frame_len); + return; + } + + /* In scan state, store scan result. */ + lim_collect_bss_description(mac_ctx, bssdescr, bpr, rx_packet_info, + scanning); + bssdescr->fProbeRsp = fProbeRsp; + + /* + * Send the beacon to CSR with registered callback routine. + * scan_id and flags parameters are currently unused and set to 0. + */ + if (mac_ctx->lim.add_bssdescr_callback) { + (mac_ctx->lim.add_bssdescr_callback) (mac_ctx, + bssdescr, 0, flags); + } else { + lim_log(mac_ctx, LOGE, + FL("No CSR callback routine to send beacons")); + status = QDF_STATUS_E_INVAL; + } + qdf_mem_free(bssdescr); +} diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_scan_result_utils.h b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_scan_result_utils.h new file mode 100644 index 0000000000000000000000000000000000000000..0b55f1741d972fcc25b1783f410b429ea2e3dea7 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_scan_result_utils.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2012, 2014-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * This file lim_scan_result_utils.h contains the utility definitions + * LIM uses for maintaining and accessing scan results on STA. + * Author: Chandra Modumudi + * Date: 02/13/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + */ +#ifndef __LIM_SCAN_UTILS_H +#define __LIM_SCAN_UTILS_H + +#include "parser_api.h" +#include "lim_types.h" + +/* Scan result hash related functions */ +uint8_t lim_scan_hash_function(tSirMacAddr); +void lim_restore_pre_scan_state(tpAniSirGlobal); +void lim_copy_scan_result(tpAniSirGlobal, uint8_t *); +void lim_check_and_add_bss_description(tpAniSirGlobal, tpSirProbeRespBeacon, + uint8_t *, bool, uint8_t); +void lim_collect_bss_description(tpAniSirGlobal pMac, + tSirBssDescription *pBssDescr, + tpSirProbeRespBeacon pBPR, + uint8_t *pRxPacketInfo, uint8_t fScanning); +#endif /* __LIM_SCAN_UTILS_H */ diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_security_utils.c b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_security_utils.c new file mode 100644 index 0000000000000000000000000000000000000000..37d9c0361cb2886016cbc65915164140cfd31db1 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_security_utils.c @@ -0,0 +1,1074 @@ +/* + * Copyright (c) 2013-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * + * This file lim_utils.cc contains the utility functions + * LIM uses. + * Author: Chandra Modumudi + * Date: 02/13/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + */ + +#include "ani_global.h" +#include "wni_api.h" + +#include "sir_common.h" +#include "wni_cfg.h" +#include "cfg_api.h" + +#include "utils_api.h" +#include "lim_utils.h" +#include "lim_security_utils.h" +#include "lim_ft_defs.h" +#include "lim_session.h" + +#define LIM_SEED_LENGTH 16 +/* + * preauth node timeout value in interval of 10msec + */ +#define LIM_OPENAUTH_TIMEOUT 500 + +/** + * lim_is_auth_algo_supported() + * + ***FUNCTION: + * This function is called in various places within LIM code + * to determine whether passed authentication algorithm is enabled + * or not + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param authType Indicates MAC based authentication type + * (eSIR_OPEN_SYSTEM or eSIR_SHARED_KEY) + * If Shared Key authentication to be used, + * 'Privacy Option Implemented' flag is also + * checked. + * + * @return true if passed authType is enabled else false + */ +uint8_t +lim_is_auth_algo_supported(tpAniSirGlobal pMac, tAniAuthType authType, + tpPESession psessionEntry) +{ + uint32_t algoEnable, privacyOptImp; + + if (authType == eSIR_OPEN_SYSTEM) { + + if (LIM_IS_AP_ROLE(psessionEntry)) { + if ((psessionEntry->authType == eSIR_OPEN_SYSTEM) + || (psessionEntry->authType == eSIR_AUTO_SWITCH)) + return true; + else + return false; + } + + if (wlan_cfg_get_int(pMac, WNI_CFG_OPEN_SYSTEM_AUTH_ENABLE, + &algoEnable) != eSIR_SUCCESS) { + /** + * Could not get AuthAlgo1 Enable value + * from CFG. Log error. + */ + lim_log(pMac, LOGE, + FL("could not retrieve AuthAlgo1 Enable value")); + + return false; + } else + return algoEnable > 0 ? true : false; + } else { + + if (LIM_IS_AP_ROLE(psessionEntry)) { + if ((psessionEntry->authType == eSIR_SHARED_KEY) + || (psessionEntry->authType == eSIR_AUTO_SWITCH)) + algoEnable = true; + else + algoEnable = false; + + } else + + if (wlan_cfg_get_int + (pMac, WNI_CFG_SHARED_KEY_AUTH_ENABLE, + &algoEnable) != eSIR_SUCCESS) { + /** + * Could not get AuthAlgo2 Enable value + * from CFG. Log error. + */ + lim_log(pMac, LOGE, + FL("could not retrieve AuthAlgo2 Enable value")); + + return false; + } + + if (LIM_IS_AP_ROLE(psessionEntry)) { + privacyOptImp = psessionEntry->privacy; + } else + + if (wlan_cfg_get_int(pMac, WNI_CFG_PRIVACY_ENABLED, + &privacyOptImp) != eSIR_SUCCESS) { + /** + * Could not get PrivacyOptionImplemented value + * from CFG. Log error. + */ + lim_log(pMac, LOGE, + FL + ("could not retrieve PrivacyOptImplemented value")); + + return false; + } + return algoEnable && privacyOptImp; + } +} /****** end lim_is_auth_algo_supported() ******/ + +/** + * lim_init_pre_auth_list + * + ***FUNCTION: + * This function is called while starting a BSS at AP + * to initialize MAC authenticated STA list. This may also be called + * while joining/starting an IBSS if MAC authentication is allowed + * in IBSS mode. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param pMac - Pointer to Global MAC structure + * @return None + */ + +void lim_init_pre_auth_list(tpAniSirGlobal pMac) +{ + pMac->lim.pLimPreAuthList = NULL; + +} /*** end lim_init_pre_auth_list() ***/ + +/** + * lim_delete_pre_auth_list + * + ***FUNCTION: + * This function is called cleanup Pre-auth list either on + * AP or on STA when moving from one persona to other. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param pMac - Pointer to Global MAC structure + * @return None + */ + +void lim_delete_pre_auth_list(tpAniSirGlobal pMac) +{ + struct tLimPreAuthNode *pCurrNode, *pTempNode; + + pCurrNode = pTempNode = pMac->lim.pLimPreAuthList; + while (pCurrNode != NULL) { + pTempNode = pCurrNode->next; + + PELOG1(lim_log(pMac, LOG1, FL("=====> lim_delete_pre_auth_list "));) + lim_release_pre_auth_node(pMac, pCurrNode); + + pCurrNode = pTempNode; + } + pMac->lim.pLimPreAuthList = NULL; +} /*** end lim_delete_pre_auth_list() ***/ + +/** + * lim_search_pre_auth_list + * + ***FUNCTION: + * This function is called when Authentication frame is received + * by AP (or at a STA in IBSS supporting MAC based authentication) + * to search if a STA is in the middle of MAC Authentication + * transaction sequence. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param macAddr - MAC address of the STA that sent + * Authentication frame. + * + * @return Pointer to pre-auth node if found, else NULL + */ + +struct tLimPreAuthNode *lim_search_pre_auth_list(tpAniSirGlobal pMac, + tSirMacAddr macAddr) +{ + struct tLimPreAuthNode *pTempNode = pMac->lim.pLimPreAuthList; + + while (pTempNode != NULL) { + if (!qdf_mem_cmp((uint8_t *) macAddr, + (uint8_t *) &pTempNode->peerMacAddr, + sizeof(tSirMacAddr))) + break; + + pTempNode = pTempNode->next; + } + + return pTempNode; +} /*** end lim_search_pre_auth_list() ***/ + +/** + * lim_delete_open_auth_pre_auth_node() - delete any stale preauth nodes + * @mac_ctx: Pointer to Global MAC structure + * + * This function is called to delete any stale preauth nodes on + * receiving authentication frame and existing preauth nodes + * reached the maximum allowed limit. + * + * Return: return true if any preauthnode deleted else false + */ +uint8_t +lim_delete_open_auth_pre_auth_node(tpAniSirGlobal mac_ctx) +{ + struct tLimPreAuthNode *prev_node, *temp_node, *found_node; + uint8_t auth_node_freed = false; + + temp_node = prev_node = mac_ctx->lim.pLimPreAuthList; + + if (temp_node == NULL) + return auth_node_freed; + + while (temp_node != NULL) { + if (temp_node->mlmState == eLIM_MLM_AUTHENTICATED_STATE && + temp_node->authType == eSIR_OPEN_SYSTEM && + (qdf_mc_timer_get_system_ticks() > + (LIM_OPENAUTH_TIMEOUT + temp_node->timestamp) || + qdf_mc_timer_get_system_ticks() < temp_node->timestamp)) { + /* Found node to be deleted */ + auth_node_freed = true; + found_node = temp_node; + if (mac_ctx->lim.pLimPreAuthList == temp_node) { + prev_node = mac_ctx->lim.pLimPreAuthList = + temp_node = found_node->next; + } else { + prev_node->next = temp_node->next; + temp_node = prev_node->next; + } + + lim_release_pre_auth_node(mac_ctx, found_node); + } else { + prev_node = temp_node; + temp_node = prev_node->next; + } + } + + return auth_node_freed; +} + +/** + * lim_add_pre_auth_node + * + ***FUNCTION: + * This function is called at AP while sending Authentication + * frame2. + * This may also be called on a STA in IBSS if MAC authentication is + * allowed in IBSS mode. + * + ***LOGIC: + * Node is always added to the front of the list + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param pMac - Pointer to Global MAC structure + * @param pAuthNode - Pointer to pre-auth node to be added to the list. + * + * @return None + */ + +void lim_add_pre_auth_node(tpAniSirGlobal pMac, struct tLimPreAuthNode *pAuthNode) +{ + pMac->lim.gLimNumPreAuthContexts++; + + pAuthNode->next = pMac->lim.pLimPreAuthList; + + pMac->lim.pLimPreAuthList = pAuthNode; +} /*** end lim_add_pre_auth_node() ***/ + +/** + * lim_release_pre_auth_node + * + ***FUNCTION: + * This function is called to realease the accquired + * pre auth node from list. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param pMac - Pointer to Global MAC structure + * @param pAuthNode - Pointer to Pre Auth node to be released + * @return None + */ + +void lim_release_pre_auth_node(tpAniSirGlobal pMac, tpLimPreAuthNode pAuthNode) +{ + pAuthNode->fFree = 1; + MTRACE(mac_trace + (pMac, TRACE_CODE_TIMER_DEACTIVATE, NO_SESSION, + eLIM_PRE_AUTH_CLEANUP_TIMER)); + tx_timer_deactivate(&pAuthNode->timer); + pMac->lim.gLimNumPreAuthContexts--; +} /*** end lim_release_pre_auth_node() ***/ + +/** + * lim_delete_pre_auth_node + * + ***FUNCTION: + * This function is called at AP when a pre-authenticated STA is + * Associated/Reassociated or when AuthFrame4 is received after + * Auth Response timeout. + * This may also be called on a STA in IBSS if MAC authentication and + * Association/Reassociation is allowed in IBSS mode. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param pMac - Pointer to Global MAC structure + * @param peerMacAddr - MAC address of the STA that need to be deleted + * from pre-auth node list. + * + * @return None + */ + +void lim_delete_pre_auth_node(tpAniSirGlobal pMac, tSirMacAddr macAddr) +{ + struct tLimPreAuthNode *pPrevNode, *pTempNode; + + pTempNode = pPrevNode = pMac->lim.pLimPreAuthList; + + if (pTempNode == NULL) + return; + + if (!qdf_mem_cmp((uint8_t *) macAddr, + (uint8_t *) &pTempNode->peerMacAddr, + sizeof(tSirMacAddr))) { + /* First node to be deleted */ + + pMac->lim.pLimPreAuthList = pTempNode->next; + + PELOG1(lim_log + (pMac, LOG1, + FL + ("=====> lim_delete_pre_auth_node : first node to delete")); + ) + PELOG1(lim_log + (pMac, LOG1, + FL("Release data entry: %x id %d peer "), pTempNode, + pTempNode->authNodeIdx); + lim_print_mac_addr(pMac, macAddr, LOG1); + ) + lim_release_pre_auth_node(pMac, pTempNode); + + return; + } + + pTempNode = pTempNode->next; + + while (pTempNode != NULL) { + if (!qdf_mem_cmp((uint8_t *) macAddr, + (uint8_t *) &pTempNode->peerMacAddr, + sizeof(tSirMacAddr))) { + /* Found node to be deleted */ + + pPrevNode->next = pTempNode->next; + + PELOG1(lim_log + (pMac, LOG1, + FL + ("=====> lim_delete_pre_auth_node : subsequent node to delete")); + lim_log(pMac, LOG1, + FL("Release data entry: %x id %d peer "), + pTempNode, pTempNode->authNodeIdx); + lim_print_mac_addr(pMac, macAddr, LOG1); + ) + lim_release_pre_auth_node(pMac, pTempNode); + + return; + } + + pPrevNode = pTempNode; + pTempNode = pTempNode->next; + } + + /* Should not be here */ + /* Log error */ + lim_log(pMac, LOGP, FL("peer not found in pre-auth list, addr= ")); + lim_print_mac_addr(pMac, macAddr, LOGP); + +} /*** end lim_delete_pre_auth_node() ***/ + +/** + * limRestoreFromPreAuthState + * + ***FUNCTION: + * This function is called on STA whenever an Authentication + * sequence is complete and state prior to auth need to be + * restored. + * + ***LOGIC: + * MLM_AUTH_CNF is prepared and sent to SME state machine. + * In case of restoring from pre-auth: + * - Channel Id is programmed at LO/RF synthesizer + * - BSSID is programmed at RHP + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param pMac - Pointer to Global MAC structure + * @param resultCode - result of authentication attempt + * @return None + */ + +void +lim_restore_from_auth_state(tpAniSirGlobal pMac, tSirResultCodes resultCode, + uint16_t protStatusCode, tpPESession sessionEntry) +{ + tSirMacAddr currentBssId; + tLimMlmAuthCnf mlmAuthCnf; + +#ifdef FEATURE_WLAN_DIAG_SUPPORT + lim_diag_event_report(pMac, WLAN_PE_DIAG_AUTH_COMP_EVENT, sessionEntry, + resultCode, protStatusCode); +#endif + + qdf_mem_copy((uint8_t *) &mlmAuthCnf.peerMacAddr, + (uint8_t *) &pMac->lim.gpLimMlmAuthReq->peerMacAddr, + sizeof(tSirMacAddr)); + mlmAuthCnf.authType = pMac->lim.gpLimMlmAuthReq->authType; + mlmAuthCnf.resultCode = resultCode; + mlmAuthCnf.protStatusCode = protStatusCode; + + /* Update PE session ID */ + mlmAuthCnf.sessionId = sessionEntry->peSessionId; + + /* / Free up buffer allocated */ + /* / for pMac->lim.gLimMlmAuthReq */ + qdf_mem_free(pMac->lim.gpLimMlmAuthReq); + pMac->lim.gpLimMlmAuthReq = NULL; + + sessionEntry->limMlmState = sessionEntry->limPrevMlmState; + + MTRACE(mac_trace + (pMac, TRACE_CODE_MLM_STATE, sessionEntry->peSessionId, + sessionEntry->limMlmState)); + + /* + * Set the auth_ack_status status flag as success as + * host have received the auth rsp and no longer auth + * retry is needed also cancel the auth rety timer + */ + pMac->auth_ack_status = LIM_AUTH_ACK_RCD_SUCCESS; + /* 'Change' timer for future activations */ + lim_deactivate_and_change_timer(pMac, eLIM_AUTH_RETRY_TIMER); + + /* 'Change' timer for future activations */ + lim_deactivate_and_change_timer(pMac, eLIM_AUTH_FAIL_TIMER); + + sir_copy_mac_addr(currentBssId, sessionEntry->bssId); + + if (sessionEntry->limSmeState == eLIM_SME_WT_PRE_AUTH_STATE) { + pMac->lim.gLimPreAuthChannelNumber = 0; + } + + lim_post_sme_message(pMac, LIM_MLM_AUTH_CNF, (uint32_t *) &mlmAuthCnf); +} /*** end lim_restore_from_auth_state() ***/ + +/** + * lim_encrypt_auth_frame() + * + ***FUNCTION: + * This function is called in lim_process_auth_frame() function + * to encrypt Authentication frame3 body. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param pMac Pointer to Global MAC structure + * @param keyId key id to used + * @param pKey Pointer to the key to be used for encryption + * @param pPlainText Pointer to the body to be encrypted + * @param pEncrBody Pointer to the encrypted auth frame body + * @param keyLength 8 (WEP40) or 16 (WEP104) + * @return None + */ + +void +lim_encrypt_auth_frame(tpAniSirGlobal pMac, uint8_t keyId, uint8_t *pKey, + uint8_t *pPlainText, uint8_t *pEncrBody, + uint32_t keyLength) +{ + uint8_t seed[LIM_SEED_LENGTH], icv[SIR_MAC_WEP_ICV_LENGTH]; + + keyLength += 3; + + /* Bytes 3-7 of seed is key */ + qdf_mem_copy((uint8_t *) &seed[3], pKey, keyLength - 3); + + /* Compute CRC-32 and place them in last 4 bytes of plain text */ + lim_compute_crc32(icv, pPlainText, sizeof(tSirMacAuthFrameBody)); + + qdf_mem_copy(pPlainText + sizeof(tSirMacAuthFrameBody), + icv, SIR_MAC_WEP_ICV_LENGTH); + + /* Run RC4 on plain text with the seed */ + lim_rc4(pEncrBody + SIR_MAC_WEP_IV_LENGTH, + (uint8_t *) pPlainText, seed, keyLength, + LIM_ENCR_AUTH_BODY_LEN - SIR_MAC_WEP_IV_LENGTH); + + /* Prepare IV */ + pEncrBody[0] = seed[0]; + pEncrBody[1] = seed[1]; + pEncrBody[2] = seed[2]; + pEncrBody[3] = keyId << 6; +} /****** end lim_encrypt_auth_frame() ******/ + +/** + * lim_compute_crc32() + * + ***FUNCTION: + * This function is called to compute CRC-32 on a given source. + * Used while encrypting/decrypting Authentication frame 3. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param pDest Destination location for computed CRC + * @param pSrc Source location to be CRC computed + * @param len Length over which CRC to be computed + * @return None + */ + +void lim_compute_crc32(uint8_t *pDest, uint8_t *pSrc, uint16_t len) +{ + uint32_t crc; + int i; + + crc = 0; + crc = ~crc; + + while (len-- > 0) + crc = lim_crc_update(crc, *pSrc++); + + crc = ~crc; + + for (i = 0; i < SIR_MAC_WEP_IV_LENGTH; i++) { + pDest[i] = (uint8_t) crc; + crc >>= 8; + } +} /****** end lim_compute_crc32() ******/ + +/** + * lim_rc4() + * + ***FUNCTION: + * This function is called to run RC4 algorithm. Called while + * encrypting/decrypting Authentication frame 3. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param pDest Destination location for encrypted text + * @param pSrc Source location to be encrypted + * @param seed Contains seed (IV + key) for PRNG + * @param keyLength 8 (WEP40) or 16 (WEP104) + * @param frameLen Length of the frame + * + * @return None + */ + +void +lim_rc4(uint8_t *pDest, uint8_t *pSrc, uint8_t *seed, uint32_t keyLength, + uint16_t frameLen) +{ + typedef struct { + uint8_t i, j; + uint8_t sbox[256]; + } tRC4Context; + + tRC4Context ctx; + + { + uint16_t i, j, k; + + /* */ + /* Initialize sbox using seed */ + /* */ + + ctx.i = ctx.j = 0; + for (i = 0; i < 256; i++) + ctx.sbox[i] = (uint8_t) i; + + j = 0; + k = 0; + for (i = 0; i < 256; i++) { + uint8_t temp; + if (k < LIM_SEED_LENGTH) + j = (uint8_t) (j + ctx.sbox[i] + seed[k]); + temp = ctx.sbox[i]; + ctx.sbox[i] = ctx.sbox[j]; + ctx.sbox[j] = temp; + + if (++k >= keyLength) + k = 0; + } + } + + { + uint8_t i = ctx.i; + uint8_t j = ctx.j; + uint16_t len = frameLen; + + while (len-- > 0) { + uint8_t temp1, temp2; + + i = (uint8_t) (i + 1); + temp1 = ctx.sbox[i]; + j = (uint8_t) (j + temp1); + + ctx.sbox[i] = temp2 = ctx.sbox[j]; + ctx.sbox[j] = temp1; + + temp1 = (uint8_t) (temp1 + temp2); + temp1 = ctx.sbox[temp1]; + temp2 = (uint8_t) (pSrc ? *pSrc++ : 0); + + *pDest++ = (uint8_t) (temp1 ^ temp2); + } + + ctx.i = i; + ctx.j = j; + } +} /****** end lim_rc4() ******/ + +/** + * lim_decrypt_auth_frame() + * + ***FUNCTION: + * This function is called in lim_process_auth_frame() function + * to decrypt received Authentication frame3 body. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param pMac Pointer to Global MAC structure + * @param pKey Pointer to the key to be used for decryption + * @param pEncrBody Pointer to the body to be decrypted + * @param pPlainBody Pointer to the decrypted body + * @param keyLength 8 (WEP40) or 16 (WEP104) + * + * @return Decrypt result - eSIR_SUCCESS for success and + * LIM_DECRYPT_ICV_FAIL for ICV mismatch. + * If decryption is a success, pBody will + * have decrypted auth frame body. + */ + +uint8_t +lim_decrypt_auth_frame(tpAniSirGlobal pMac, uint8_t *pKey, uint8_t *pEncrBody, + uint8_t *pPlainBody, uint32_t keyLength, uint16_t frameLen) +{ + uint8_t seed[LIM_SEED_LENGTH], icv[SIR_MAC_WEP_ICV_LENGTH]; + int i; + keyLength += 3; + + /* Bytes 0-2 of seed is received IV */ + qdf_mem_copy((uint8_t *) seed, pEncrBody, SIR_MAC_WEP_IV_LENGTH - 1); + + /* Bytes 3-7 of seed is key */ + qdf_mem_copy((uint8_t *) &seed[3], pKey, keyLength - 3); + + /* Run RC4 on encrypted text with the seed */ + lim_rc4(pPlainBody, + pEncrBody + SIR_MAC_WEP_IV_LENGTH, seed, keyLength, frameLen); + + PELOG4(lim_log(pMac, LOG4, FL("plainbody is ")); + sir_dump_buf(pMac, SIR_LIM_MODULE_ID, LOG4, pPlainBody, frameLen); + ) + /* Compute CRC-32 and place them in last 4 bytes of encrypted body */ + lim_compute_crc32(icv, + (uint8_t *) pPlainBody, + (frameLen - SIR_MAC_WEP_ICV_LENGTH)); + + /* Compare RX_ICV with computed ICV */ + for (i = 0; i < SIR_MAC_WEP_ICV_LENGTH; i++) { + PELOG4(lim_log + (pMac, LOG4, FL(" computed ICV%d[%x], rxed ICV%d[%x]"), + i, icv[i], i, + pPlainBody[frameLen - SIR_MAC_WEP_ICV_LENGTH + i]); + ) + if (icv[i] != + pPlainBody[frameLen - SIR_MAC_WEP_ICV_LENGTH + i]) + return LIM_DECRYPT_ICV_FAIL; + } + + return eSIR_SUCCESS; +} /****** end lim_decrypt_auth_frame() ******/ + +/** + * lim_post_sme_set_keys_cnf + * + * A utility API to send MLM_SETKEYS_CNF to SME + */ +void lim_post_sme_set_keys_cnf(tpAniSirGlobal pMac, + tLimMlmSetKeysReq *pMlmSetKeysReq, + tLimMlmSetKeysCnf *mlmSetKeysCnf) +{ + /* Prepare and Send LIM_MLM_SETKEYS_CNF */ + qdf_copy_macaddr(&mlmSetKeysCnf->peer_macaddr, + &pMlmSetKeysReq->peer_macaddr); + + /* Free up buffer allocated for mlmSetKeysReq */ + qdf_mem_free(pMlmSetKeysReq); + pMac->lim.gpLimMlmSetKeysReq = NULL; + + lim_post_sme_message(pMac, + LIM_MLM_SETKEYS_CNF, (uint32_t *) mlmSetKeysCnf); +} + +/** + * lim_send_set_bss_key_req() + * + ***FUNCTION: + * This function is called from lim_process_mlm_set_keys_req(), + * when PE is trying to setup the Group Keys related + * to a specified encryption type + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param pMac Pointer to Global MAC structure + * @param pMlmSetKeysReq Pointer to MLM_SETKEYS_REQ buffer + * @return none + */ +void lim_send_set_bss_key_req(tpAniSirGlobal pMac, + tLimMlmSetKeysReq *pMlmSetKeysReq, + tpPESession psessionEntry) +{ + tSirMsgQ msgQ; + tpSetBssKeyParams pSetBssKeyParams = NULL; + tLimMlmSetKeysCnf mlmSetKeysCnf; + tSirRetStatus retCode; + uint32_t val = 0; + + if (pMlmSetKeysReq->numKeys > SIR_MAC_MAX_NUM_OF_DEFAULT_KEYS) { + lim_log(pMac, LOG1, + FL + ("numKeys = %d is more than SIR_MAC_MAX_NUM_OF_DEFAULT_KEYS"), + pMlmSetKeysReq->numKeys); + + /* Respond to SME with error code */ + mlmSetKeysCnf.resultCode = eSIR_SME_INVALID_PARAMETERS; + goto end; + } + /* Package WMA_SET_BSSKEY_REQ message parameters */ + + pSetBssKeyParams = qdf_mem_malloc(sizeof(tSetBssKeyParams)); + if (NULL == pSetBssKeyParams) { + lim_log(pMac, LOGE, + FL("Unable to allocate memory during SET_BSSKEY")); + + /* Respond to SME with error code */ + mlmSetKeysCnf.resultCode = eSIR_SME_RESOURCES_UNAVAILABLE; + goto end; + } + + /* Update the WMA_SET_BSSKEY_REQ parameters */ + pSetBssKeyParams->bssIdx = psessionEntry->bssIdx; + pSetBssKeyParams->encType = pMlmSetKeysReq->edType; + + if (eSIR_SUCCESS != wlan_cfg_get_int(pMac, WNI_CFG_SINGLE_TID_RC, &val)) { + lim_log(pMac, LOGP, FL("Unable to read WNI_CFG_SINGLE_TID_RC")); + } + + pSetBssKeyParams->singleTidRc = (uint8_t) val; + + /* Update PE session Id */ + pSetBssKeyParams->sessionId = psessionEntry->peSessionId; + + pSetBssKeyParams->smesessionId = pMlmSetKeysReq->smesessionId; + + if (pMlmSetKeysReq->key[0].keyId && + ((pMlmSetKeysReq->edType == eSIR_ED_WEP40) || + (pMlmSetKeysReq->edType == eSIR_ED_WEP104)) + ) { + /* IF the key id is non-zero and encryption type is WEP, Send all the 4 + * keys to HAL with filling the key at right index in pSetBssKeyParams->key. */ + pSetBssKeyParams->numKeys = SIR_MAC_MAX_NUM_OF_DEFAULT_KEYS; + qdf_mem_copy((uint8_t *) &pSetBssKeyParams-> + key[pMlmSetKeysReq->key[0].keyId], + (uint8_t *) &pMlmSetKeysReq->key[0], + sizeof(pMlmSetKeysReq->key[0])); + + } else { + pSetBssKeyParams->numKeys = pMlmSetKeysReq->numKeys; + qdf_mem_copy((uint8_t *) &pSetBssKeyParams->key, + (uint8_t *) &pMlmSetKeysReq->key, + sizeof(tSirKeys) * pMlmSetKeysReq->numKeys); + } + + SET_LIM_PROCESS_DEFD_MESGS(pMac, false); + msgQ.type = WMA_SET_BSSKEY_REQ; + msgQ.reserved = 0; + msgQ.bodyptr = pSetBssKeyParams; + msgQ.bodyval = 0; + + lim_log(pMac, LOGW, FL("Sending WMA_SET_BSSKEY_REQ...")); + MTRACE(mac_trace_msg_tx(pMac, psessionEntry->peSessionId, msgQ.type)); + retCode = wma_post_ctrl_msg(pMac, &msgQ); + if (eSIR_SUCCESS != retCode) { + lim_log(pMac, LOGE, + FL("Posting SET_BSSKEY to HAL failed, reason=%X"), + retCode); + + /* Respond to SME with LIM_MLM_SETKEYS_CNF */ + mlmSetKeysCnf.resultCode = eSIR_SME_HAL_SEND_MESSAGE_FAIL; + } else + return; /* Continue after WMA_SET_BSSKEY_RSP... */ + +end: + lim_post_sme_set_keys_cnf(pMac, pMlmSetKeysReq, &mlmSetKeysCnf); + +} + +/** + * @function : lim_send_set_sta_key_req() + * + * @brief : This function is called from lim_process_mlm_set_keys_req(), + * when PE is trying to setup the Unicast Keys related + * to a specified STA with specified encryption type + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param pMac Pointer to Global MAC structure + * @param pMlmSetKeysReq Pointer to MLM_SETKEYS_REQ buffer + * @param staIdx STA index for which the keys are being set + * @param defWEPIdx The default WEP key index [0..3] + * @return none + */ +void lim_send_set_sta_key_req(tpAniSirGlobal pMac, + tLimMlmSetKeysReq *pMlmSetKeysReq, + uint16_t staIdx, + uint8_t defWEPIdx, + tpPESession sessionEntry, bool sendRsp) +{ + tSirMsgQ msgQ; + tpSetStaKeyParams pSetStaKeyParams = NULL; + tLimMlmSetKeysCnf mlmSetKeysCnf; + tSirRetStatus retCode; + uint32_t val = 0; + + /* Package WMA_SET_STAKEY_REQ message parameters */ + pSetStaKeyParams = qdf_mem_malloc(sizeof(tSetStaKeyParams)); + if (NULL == pSetStaKeyParams) { + lim_log(pMac, LOGP, + FL("Unable to allocate memory during SET_BSSKEY")); + return; + } + + /* Update the WMA_SET_STAKEY_REQ parameters */ + pSetStaKeyParams->staIdx = staIdx; + pSetStaKeyParams->encType = pMlmSetKeysReq->edType; + + if (eSIR_SUCCESS != wlan_cfg_get_int(pMac, WNI_CFG_SINGLE_TID_RC, &val)) { + lim_log(pMac, LOGP, FL("Unable to read WNI_CFG_SINGLE_TID_RC")); + } + + pSetStaKeyParams->singleTidRc = (uint8_t) val; + + /* Update PE session ID */ + pSetStaKeyParams->sessionId = sessionEntry->peSessionId; + + /** + * For WEP - defWEPIdx indicates the default WEP + * Key to be used for TX + * For all others, there's just one key that can + * be used and hence it is assumed that + * defWEPIdx = 0 (from the caller) + */ + + pSetStaKeyParams->defWEPIdx = defWEPIdx; + + pSetStaKeyParams->smesessionId = pMlmSetKeysReq->smesessionId; + qdf_copy_macaddr(&pSetStaKeyParams->peer_macaddr, + &pMlmSetKeysReq->peer_macaddr); + + if (sendRsp == true) { + /** Store the Previous MlmState*/ + sessionEntry->limPrevMlmState = sessionEntry->limMlmState; + SET_LIM_PROCESS_DEFD_MESGS(pMac, false); + } + + if (LIM_IS_IBSS_ROLE(sessionEntry) + && !pMlmSetKeysReq->key[0].unicast) { + if (sendRsp == true) + sessionEntry->limMlmState = + eLIM_MLM_WT_SET_STA_BCASTKEY_STATE; + msgQ.type = WMA_SET_STA_BCASTKEY_REQ; + } else { + if (sendRsp == true) + sessionEntry->limMlmState = + eLIM_MLM_WT_SET_STA_KEY_STATE; + msgQ.type = WMA_SET_STAKEY_REQ; + } + MTRACE(mac_trace + (pMac, TRACE_CODE_MLM_STATE, sessionEntry->peSessionId, + sessionEntry->limMlmState)); + + /** + * In the Case of WEP_DYNAMIC, ED_TKIP and ED_CCMP + * the Key[0] contains the KEY, so just copy that alone, + * for the case of WEP_STATIC the hal gets the key from cfg + */ + switch (pMlmSetKeysReq->edType) { + case eSIR_ED_WEP40: + case eSIR_ED_WEP104: + /* FIXME! Is this OK? */ + if (0 == pMlmSetKeysReq->numKeys) { + uint32_t i; + + for (i = 0; i < SIR_MAC_MAX_NUM_OF_DEFAULT_KEYS; i++) { + qdf_mem_copy((uint8_t *) &pSetStaKeyParams-> + key[i], + (uint8_t *) &pMlmSetKeysReq-> + key[i], sizeof(tSirKeys)); + } + pSetStaKeyParams->wepType = eSIR_WEP_STATIC; + sessionEntry->limMlmState = + eLIM_MLM_WT_SET_STA_KEY_STATE; + MTRACE(mac_trace + (pMac, TRACE_CODE_MLM_STATE, + sessionEntry->peSessionId, + sessionEntry->limMlmState)); + } else { + /*This case the keys are coming from upper layer so need to fill the + * key at the default wep key index and send to the HAL */ + if (defWEPIdx < SIR_MAC_MAX_NUM_OF_DEFAULT_KEYS) { + qdf_mem_copy((uint8_t *) &pSetStaKeyParams-> + key[defWEPIdx], + (uint8_t *) &pMlmSetKeysReq-> + key[0], + sizeof(pMlmSetKeysReq->key[0])); + pMlmSetKeysReq->numKeys = + SIR_MAC_MAX_NUM_OF_DEFAULT_KEYS; + } else { + lim_log(pMac, LOGE, FL("Wrong Key Index %d"), + defWEPIdx); + qdf_mem_free(pSetStaKeyParams); + return; + } + } + break; + case eSIR_ED_TKIP: + case eSIR_ED_CCMP: +#ifdef FEATURE_WLAN_WAPI + case eSIR_ED_WPI: +#endif + { + qdf_mem_copy((uint8_t *) &pSetStaKeyParams->key, + (uint8_t *) &pMlmSetKeysReq->key[0], + sizeof(tSirKeys)); + } + break; + default: + break; + } + + pSetStaKeyParams->sendRsp = sendRsp; + + msgQ.reserved = 0; + msgQ.bodyptr = pSetStaKeyParams; + msgQ.bodyval = 0; + + lim_log(pMac, LOG1, FL("Sending WMA_SET_STAKEY_REQ...")); + MTRACE(mac_trace_msg_tx(pMac, sessionEntry->peSessionId, msgQ.type)); + retCode = wma_post_ctrl_msg(pMac, &msgQ); + if (eSIR_SUCCESS != retCode) { + lim_log(pMac, LOGE, + FL("Posting SET_STAKEY to HAL failed, reason=%X"), + retCode); + /* Respond to SME with LIM_MLM_SETKEYS_CNF */ + mlmSetKeysCnf.resultCode = eSIR_SME_HAL_SEND_MESSAGE_FAIL; + } else + return; /* Continue after WMA_SET_STAKEY_RSP... */ + + if (sendRsp == true) + lim_post_sme_set_keys_cnf(pMac, pMlmSetKeysReq, &mlmSetKeysCnf); +} diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_security_utils.h b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_security_utils.h new file mode 100644 index 0000000000000000000000000000000000000000..c3410ea5533569b5be7c213c7e9fd0d88b173801 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_security_utils.h @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2011-2015, 2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * + * This file lim_security_utils.h contains the utility definitions + * related to WEP encryption/decryption etc. + * Author: Chandra Modumudi + * Date: 02/13/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + */ +#ifndef __LIM_SECURITY_UTILS_H +#define __LIM_SECURITY_UTILS_H +#include "sir_mac_prot_def.h" /* for tSirMacAuthFrameBody */ + +#define LIM_ENCR_AUTH_BODY_LEN (sizeof(tSirMacAuthFrameBody) + \ + SIR_MAC_WEP_IV_LENGTH + \ + SIR_MAC_WEP_ICV_LENGTH) +struct tLimPreAuthNode; + +uint8_t lim_is_auth_algo_supported(tpAniSirGlobal, tAniAuthType, tpPESession); + +/* MAC based authentication related functions */ +void lim_init_pre_auth_list(tpAniSirGlobal); +void lim_delete_pre_auth_list(tpAniSirGlobal); +struct tLimPreAuthNode *lim_search_pre_auth_list(tpAniSirGlobal, tSirMacAddr); +void lim_add_pre_auth_node(tpAniSirGlobal, struct tLimPreAuthNode *); +void lim_delete_pre_auth_node(tpAniSirGlobal, tSirMacAddr); +void lim_release_pre_auth_node(tpAniSirGlobal pMac, tpLimPreAuthNode pAuthNode); +void lim_restore_from_auth_state(tpAniSirGlobal, + tSirResultCodes, uint16_t, tpPESession); +uint8_t lim_delete_open_auth_pre_auth_node(tpAniSirGlobal mac_ctx); + +/* Encryption/Decryption related functions */ +void lim_compute_crc32(uint8_t *, uint8_t *, uint16_t); +void lim_rc4(uint8_t *, uint8_t *, uint8_t *, uint32_t, uint16_t); +void lim_encrypt_auth_frame(tpAniSirGlobal, uint8_t, uint8_t *, uint8_t *, + uint8_t *, uint32_t); +uint8_t lim_decrypt_auth_frame(tpAniSirGlobal, uint8_t *, uint8_t *, uint8_t *, + uint32_t, uint16_t); + +void lim_send_set_bss_key_req(tpAniSirGlobal, tLimMlmSetKeysReq *, tpPESession); +void lim_send_set_sta_key_req(tpAniSirGlobal, tLimMlmSetKeysReq *, uint16_t, uint8_t, + tpPESession, bool sendRsp); +void lim_post_sme_set_keys_cnf(tpAniSirGlobal, tLimMlmSetKeysReq *, + tLimMlmSetKeysCnf *); + +#define PTAPS 0xedb88320 + +static inline uint32_t lim_crc_update(uint32_t crc, uint8_t x) +{ + + /* Update CRC computation for 8 bits contained in x */ + /* */ + uint32_t z; + uint32_t fb; + int i; + + z = crc ^ x; + for (i = 0; i < 8; i++) { + fb = z & 1; + z >>= 1; + if (fb) + z ^= PTAPS; + } + return z; +} + +#endif /* __LIM_SECURITY_UTILS_H */ diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_send_frames_host_roam.c b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_send_frames_host_roam.c new file mode 100644 index 0000000000000000000000000000000000000000..d2093f5db7cd873f2e4bd2c3a327f83f488ca3ff --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_send_frames_host_roam.c @@ -0,0 +1,805 @@ +/* + * Copyright (c) 2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * 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. + */ + +/** + * DOC: lim_send_frames_host_roam.c + * + * Send management frames for host based roaming + */ +#include "sir_api.h" +#include "ani_global.h" +#include "sir_mac_prot_def.h" +#include "cfg_api.h" +#include "utils_api.h" +#include "lim_types.h" +#include "lim_utils.h" +#include "lim_security_utils.h" +#include "lim_prop_exts_utils.h" +#include "dot11f.h" +#include "lim_sta_hash_api.h" +#include "sch_api.h" +#include "lim_send_messages.h" +#include "lim_assoc_utils.h" +#include "lim_ft.h" +#ifdef WLAN_FEATURE_11W +#include "wni_cfg.h" +#endif + +#include "lim_ft_defs.h" +#include "lim_session.h" +#include "qdf_types.h" +#include "qdf_trace.h" +#include "cds_utils.h" +#include "sme_trace.h" +#include "rrm_api.h" + +#include "wma_types.h" + +/** + * lim_send_reassoc_req_with_ft_ies_mgmt_frame() - Send Reassoc Req with FTIEs. + * + * @mac_ctx: Handle to mac context + * @mlm_reassoc_req: Original reassoc request + * @pe_session: PE session information + * + * It builds a reassoc request with FT IEs and sends it to AP through WMA. + * Then it creates assoc request and stores it for sending after join + * confirmation. + * + * Return: None + */ +void lim_send_reassoc_req_with_ft_ies_mgmt_frame(tpAniSirGlobal mac_ctx, + tLimMlmReassocReq *mlm_reassoc_req, + tpPESession pe_session) +{ + static tDot11fReAssocRequest frm; + uint16_t caps; + uint8_t *frame; + uint32_t bytes, payload, status; + uint8_t qos_enabled, wme_enabled, wsm_enabled; + void *packet; + QDF_STATUS qdf_status; + uint8_t power_caps_populated = false; + uint16_t ft_ies_length = 0; + uint8_t *body; + uint16_t add_ie_len; + uint8_t *add_ie; + uint8_t *wps_ie = NULL; + uint8_t tx_flag = 0; + uint8_t sme_sessionid = 0; + bool vht_enabled = false; + tpSirMacMgmtHdr mac_hdr; + tftSMEContext *ft_sme_context; + + if (NULL == pe_session) + return; + + sme_sessionid = pe_session->smeSessionId; + + /* check this early to avoid unncessary operation */ + if (NULL == pe_session->pLimReAssocReq) + return; + + add_ie_len = pe_session->pLimReAssocReq->addIEAssoc.length; + add_ie = pe_session->pLimReAssocReq->addIEAssoc.addIEdata; + lim_log(mac_ctx, LOG1, + FL("called in state (%d)."), pe_session->limMlmState); + + qdf_mem_set((uint8_t *) &frm, sizeof(frm), 0); + + caps = mlm_reassoc_req->capabilityInfo; +#if defined(FEATURE_WLAN_WAPI) + /* + * According to WAPI standard: + * 7.3.1.4 Capability Information field + * In WAPI, non-AP STAs within an ESS set the Privacy subfield + * to 0 in transmitted Association or Reassociation management + * frames. APs ignore the Privacy subfield within received + * Association and Reassociation management frames. + */ + if (pe_session->encryptType == eSIR_ED_WPI) + ((tSirMacCapabilityInfo *) &caps)->privacy = 0; +#endif + swap_bit_field16(caps, (uint16_t *) &frm.Capabilities); + + frm.ListenInterval.interval = mlm_reassoc_req->listenInterval; + + /* + * Get the old bssid of the older AP. + * The previous ap bssid is stored in the FT Session + * while creating the PE FT Session for reassociation. + */ + qdf_mem_copy((uint8_t *)frm.CurrentAPAddress.mac, + pe_session->prev_ap_bssid, sizeof(tSirMacAddr)); + + populate_dot11f_ssid2(mac_ctx, &frm.SSID); + populate_dot11f_supp_rates(mac_ctx, POPULATE_DOT11F_RATES_OPERATIONAL, + &frm.SuppRates, pe_session); + + qos_enabled = (pe_session->limQosEnabled) && + SIR_MAC_GET_QOS(pe_session->limReassocBssCaps); + + wme_enabled = (pe_session->limWmeEnabled) && + LIM_BSS_CAPS_GET(WME, pe_session->limReassocBssQosCaps); + + wsm_enabled = (pe_session->limWsmEnabled) && wme_enabled && + LIM_BSS_CAPS_GET(WSM, pe_session->limReassocBssQosCaps); + + if (pe_session->lim11hEnable && + pe_session->pLimReAssocReq->spectrumMgtIndicator == eSIR_TRUE) { + power_caps_populated = true; + + populate_dot11f_power_caps(mac_ctx, &frm.PowerCaps, + LIM_REASSOC, pe_session); + populate_dot11f_supp_channels(mac_ctx, &frm.SuppChannels, + LIM_REASSOC, pe_session); + } + if (mac_ctx->rrm.rrmPEContext.rrmEnable && + SIR_MAC_GET_RRM(pe_session->limCurrentBssCaps)) { + if (power_caps_populated == false) { + power_caps_populated = true; + populate_dot11f_power_caps(mac_ctx, &frm.PowerCaps, + LIM_REASSOC, pe_session); + } + } + + if (qos_enabled) + populate_dot11f_qos_caps_station(mac_ctx, pe_session, + &frm.QOSCapsStation); + + populate_dot11f_ext_supp_rates(mac_ctx, + POPULATE_DOT11F_RATES_OPERATIONAL, &frm.ExtSuppRates, + pe_session); + + if (mac_ctx->rrm.rrmPEContext.rrmEnable && + SIR_MAC_GET_RRM(pe_session->limCurrentBssCaps)) + populate_dot11f_rrm_ie(mac_ctx, &frm.RRMEnabledCap, pe_session); + + /* + * Ideally this should be enabled for 11r also. But 11r does + * not follow the usual norm of using the Opaque object + * for rsnie and fties. Instead we just add the rsnie and fties + * at the end of the pack routine for 11r. + * This should ideally! be fixed. + */ + /* + * The join request *should* contain zero or one of the WPA and RSN + * IEs. The payload send along with the request is a + * 'tSirSmeJoinReq'; the IE portion is held inside a 'tSirRSNie': + * + * typedef struct sSirRSNie + * { + * uint16_t length; + * uint8_t rsnIEdata[SIR_MAC_MAX_IE_LENGTH+2]; + * } tSirRSNie, *tpSirRSNie; + * + * So, we should be able to make the following two calls harmlessly, + * since they do nothing if they don't find the given IE in the + * bytestream with which they're provided. + * + * The net effect of this will be to faithfully transmit whatever + * security IE is in the join request. + + * However, if we're associating for the purpose of WPS + * enrollment, and we've been configured to indicate that by + * eliding the WPA or RSN IE, we just skip this: + */ + if (!pe_session->is11Rconnection) { + if (add_ie_len && add_ie) + wps_ie = limGetWscIEPtr(mac_ctx, add_ie, add_ie_len); + if (NULL == wps_ie) { + populate_dot11f_rsn_opaque(mac_ctx, + &(pe_session->pLimReAssocReq->rsnIE), + &frm.RSNOpaque); + populate_dot11f_wpa_opaque(mac_ctx, + &(pe_session->pLimReAssocReq->rsnIE), + &frm.WPAOpaque); + } +#ifdef FEATURE_WLAN_ESE + if (pe_session->pLimReAssocReq->cckmIE.length) { + populate_dot11f_ese_cckm_opaque(mac_ctx, + &(pe_session->pLimReAssocReq->cckmIE), + &frm.ESECckmOpaque); + } +#endif + } +#ifdef FEATURE_WLAN_ESE + /* + * ESE Version IE will be included in re-association request + * when ESE is enabled on DUT through ini and it is also + * advertised by the peer AP to which we are trying to + * associate to. + */ + if (pe_session->is_ese_version_ie_present && + mac_ctx->roam.configParam.isEseIniFeatureEnabled) + populate_dot11f_ese_version(&frm.ESEVersion); + /* For ESE Associations fill the ESE IEs */ + if (pe_session->isESEconnection && + pe_session->pLimReAssocReq->isESEFeatureIniEnabled) { +#ifndef FEATURE_DISABLE_RM + populate_dot11f_ese_rad_mgmt_cap(&frm.ESERadMgmtCap); +#endif + } +#endif /* FEATURE_WLAN_ESE */ + + /* include WME EDCA IE as well */ + if (wme_enabled) { + populate_dot11f_wmm_info_station_per_session(mac_ctx, + pe_session, &frm.WMMInfoStation); + if (wsm_enabled) + populate_dot11f_wmm_caps(&frm.WMMCaps); +#ifdef FEATURE_WLAN_ESE + if (pe_session->isESEconnection) { + uint32_t phymode; + uint8_t rate; + + populate_dot11f_re_assoc_tspec(mac_ctx, &frm, + pe_session); + + /* + * Populate the TSRS IE if TSPEC is included in + * the reassoc request + */ + lim_get_phy_mode(mac_ctx, &phymode, pe_session); + if (phymode == WNI_CFG_PHY_MODE_11G || + phymode == WNI_CFG_PHY_MODE_11A) + rate = TSRS_11AG_RATE_6MBPS; + else + rate = TSRS_11B_RATE_5_5MBPS; + + if (pe_session->pLimReAssocReq->eseTspecInfo. + numTspecs) { + tSirMacESETSRSIE tsrs_ie; + + tsrs_ie.tsid = 0; + tsrs_ie.rates[0] = rate; + populate_dot11_tsrsie(mac_ctx, &tsrs_ie, + &frm.ESETrafStrmRateSet, + sizeof(uint8_t)); + } + } +#endif + } + + ft_sme_context = &mac_ctx->roam.roamSession[sme_sessionid].ftSmeContext; + if (pe_session->htCapability && + mac_ctx->lim.htCapabilityPresentInBeacon) { + populate_dot11f_ht_caps(mac_ctx, pe_session, &frm.HTCaps); + } + if (pe_session->pLimReAssocReq->bssDescription.mdiePresent && + (ft_sme_context->addMDIE == true) +#if defined FEATURE_WLAN_ESE + && !pe_session->isESEconnection +#endif + ) { + populate_mdie(mac_ctx, &frm.MobilityDomain, + pe_session->pLimReAssocReq->bssDescription.mdie); + } + if (pe_session->vhtCapability && + pe_session->vhtCapabilityPresentInBeacon) { + lim_log(mac_ctx, LOG1, + FL("Populate VHT IEs in Re-Assoc Request")); + populate_dot11f_vht_caps(mac_ctx, pe_session, &frm.VHTCaps); + vht_enabled = true; + populate_dot11f_ext_cap(mac_ctx, vht_enabled, &frm.ExtCap, + pe_session); + } + if (!vht_enabled && + pe_session->is_vendor_specific_vhtcaps) { + lim_log(mac_ctx, LOG1, + FL("Populate Vendor VHT IEs in Re-Assoc Request")); + frm.vendor_vht_ie.present = 1; + frm.vendor_vht_ie.type = + pe_session->vendor_specific_vht_ie_type; + frm.vendor_vht_ie.sub_type = + pe_session->vendor_specific_vht_ie_sub_type; + frm.vendor_vht_ie.VHTCaps.present = 1; + populate_dot11f_vht_caps(mac_ctx, pe_session, + &frm.vendor_vht_ie.VHTCaps); + vht_enabled = true; + } + status = dot11f_get_packed_re_assoc_request_size(mac_ctx, &frm, + &payload); + if (DOT11F_FAILED(status)) { + lim_log(mac_ctx, LOGP, + FL("Failure in size calculation (0x%08x)."), status); + /* We'll fall back on the worst case scenario: */ + payload = sizeof(tDot11fReAssocRequest); + } else if (DOT11F_WARNED(status)) { + lim_log(mac_ctx, LOGW, + FL("Warnings in size calculation(0x%08x)."), status); + } + + bytes = payload + sizeof(tSirMacMgmtHdr) + add_ie_len; + + lim_log(mac_ctx, LOG1, FL("FT IE Reassoc Req (%d)."), + ft_sme_context->reassoc_ft_ies_length); + + if (pe_session->is11Rconnection) + ft_ies_length = ft_sme_context->reassoc_ft_ies_length; + + qdf_status = cds_packet_alloc((uint16_t) bytes + ft_ies_length, + (void **)&frame, (void **)&packet); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + pe_session->limMlmState = pe_session->limPrevMlmState; + MTRACE(qdf_trace(QDF_MODULE_ID_PE, TRACE_CODE_MLM_STATE, + pe_session->peSessionId, + pe_session->limMlmState)); + lim_log(mac_ctx, LOGP, FL("Failed to alloc memory %d"), bytes); + goto end; + } + /* Paranoia: */ + qdf_mem_set(frame, bytes + ft_ies_length, 0); + + lim_print_mac_addr(mac_ctx, pe_session->limReAssocbssId, LOG1); + /* Next, we fill out the buffer descriptor: */ + lim_populate_mac_header(mac_ctx, frame, SIR_MAC_MGMT_FRAME, + SIR_MAC_MGMT_REASSOC_REQ, pe_session->limReAssocbssId, + pe_session->selfMacAddr); + mac_hdr = (tpSirMacMgmtHdr) frame; + /* That done, pack the ReAssoc Request: */ + status = dot11f_pack_re_assoc_request(mac_ctx, &frm, frame + + sizeof(tSirMacMgmtHdr), + payload, &payload); + if (DOT11F_FAILED(status)) { + lim_log(mac_ctx, LOGE, FL("Failure in pack (0x%08x)."), status); + cds_packet_free((void *)packet); + goto end; + } else if (DOT11F_WARNED(status)) { + lim_log(mac_ctx, LOGW, FL("Warnings in pack (0x%08x)."), + status); + } + + lim_log(mac_ctx, LOG3, + FL("*** Sending Re-Assoc Request length %d %d to "), + bytes, payload); + + if (pe_session->assocReq != NULL) { + qdf_mem_free(pe_session->assocReq); + pe_session->assocReq = NULL; + pe_session->assocReqLen = 0; + } + + if (add_ie_len) { + qdf_mem_copy(frame + sizeof(tSirMacMgmtHdr) + payload, + add_ie, add_ie_len); + payload += add_ie_len; + } + + pe_session->assocReq = qdf_mem_malloc(payload); + if (NULL == pe_session->assocReq) { + lim_log(mac_ctx, LOGE, FL("Failed to alloc memory")); + } else { + /* + * Store the Assoc request. This is sent to csr/hdd in + * join cnf response. + */ + qdf_mem_copy(pe_session->assocReq, + frame + sizeof(tSirMacMgmtHdr), payload); + pe_session->assocReqLen = payload; + } + + if (pe_session->is11Rconnection && ft_sme_context->reassoc_ft_ies) { + int i = 0; + + body = frame + bytes; + for (i = 0; i < ft_ies_length; i++) { + *body = ft_sme_context->reassoc_ft_ies[i]; + body++; + } + } + lim_log(mac_ctx, LOG1, FL("Re-assoc Req Frame is: ")); + sir_dump_buf(mac_ctx, SIR_LIM_MODULE_ID, LOG1, + (uint8_t *) frame, (bytes + ft_ies_length)); + + if ((NULL != pe_session->ftPEContext.pFTPreAuthReq) && + (SIR_BAND_5_GHZ == lim_get_rf_band( + pe_session->ftPEContext.pFTPreAuthReq->preAuthchannelNum))) + tx_flag |= HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME; + else if ((SIR_BAND_5_GHZ == + lim_get_rf_band(pe_session->currentOperChannel)) + || (pe_session->pePersona == QDF_P2P_CLIENT_MODE) + || (pe_session->pePersona == QDF_P2P_GO_MODE)) + tx_flag |= HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME; + + if (NULL != pe_session->assocReq) { + qdf_mem_free(pe_session->assocReq); + pe_session->assocReq = NULL; + pe_session->assocReqLen = 0; + } + if (ft_ies_length) { + pe_session->assocReq = qdf_mem_malloc(ft_ies_length); + if (NULL == pe_session->assocReq) { + lim_log(mac_ctx, + LOGE, FL("Failed to alloc memory for FT IEs")); + pe_session->assocReqLen = 0; + } else { + /* + * Store the FT IEs. This is sent to csr/hdd in + * join cnf response. + */ + qdf_mem_copy(pe_session->assocReq, + ft_sme_context->reassoc_ft_ies, ft_ies_length); + pe_session->assocReqLen = ft_ies_length; + } + } else { + lim_log(mac_ctx, LOG1, FL("FT IEs not present")); + pe_session->assocReqLen = 0; + } + +#ifdef FEATURE_WLAN_DIAG_SUPPORT + lim_diag_event_report(mac_ctx, WLAN_PE_DIAG_REASSOC_START_EVENT, + pe_session, eSIR_SUCCESS, eSIR_SUCCESS); +#endif + MTRACE(qdf_trace(QDF_MODULE_ID_PE, TRACE_CODE_TX_MGMT, + pe_session->peSessionId, mac_hdr->fc.subType)); + qdf_status = wma_tx_frame(mac_ctx, packet, + (uint16_t) (bytes + ft_ies_length), + TXRX_FRM_802_11_MGMT, ANI_TXDIR_TODS, 7, + lim_tx_complete, frame, tx_flag, sme_sessionid, + 0); + MTRACE(qdf_trace(QDF_MODULE_ID_PE, TRACE_CODE_TX_COMPLETE, + pe_session->peSessionId, qdf_status)); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + lim_log(mac_ctx, LOGE, + FL("Failed to send Re-Assoc Request (%X)!"), + qdf_status); + } + +end: + /* Free up buffer allocated for mlmAssocReq */ + qdf_mem_free(mlm_reassoc_req); + pe_session->pLimMlmReassocReq = NULL; + +} + +/** + * lim_send_retry_reassoc_req_frame() - Retry for reassociation + * @pMac: Global MAC Context + * @pMlmReassocReq: Request buffer to be sent + * @psessionEntry: PE Session + * + * Return: None + */ +void lim_send_retry_reassoc_req_frame(tpAniSirGlobal pMac, + tLimMlmReassocReq *pMlmReassocReq, + tpPESession psessionEntry) +{ + tLimMlmReassocCnf mlmReassocCnf; /* keep sme */ + tLimMlmReassocReq *pTmpMlmReassocReq = NULL; + if (NULL == pTmpMlmReassocReq) { + pTmpMlmReassocReq = qdf_mem_malloc(sizeof(tLimMlmReassocReq)); + if (NULL == pTmpMlmReassocReq) + goto end; + qdf_mem_copy(pTmpMlmReassocReq, pMlmReassocReq, + sizeof(tLimMlmReassocReq)); + } + /* Prepare and send Reassociation request frame */ + /* start reassoc timer. */ + pMac->lim.limTimers.gLimReassocFailureTimer.sessionId = + psessionEntry->peSessionId; + /* Start reassociation failure timer */ + MTRACE(qdf_trace(QDF_MODULE_ID_PE, TRACE_CODE_TIMER_ACTIVATE, + psessionEntry->peSessionId, eLIM_REASSOC_FAIL_TIMER)); + if (tx_timer_activate(&pMac->lim.limTimers.gLimReassocFailureTimer) + != TX_SUCCESS) { + /* Could not start reassoc failure timer. */ + /* Log error */ + lim_log(pMac, LOGP, + FL("could not start Reassociation failure timer")); + /* Return Reassoc confirm with */ + /* Resources Unavailable */ + mlmReassocCnf.resultCode = eSIR_SME_RESOURCES_UNAVAILABLE; + mlmReassocCnf.protStatusCode = eSIR_MAC_UNSPEC_FAILURE_STATUS; + goto end; + } + + lim_send_reassoc_req_with_ft_ies_mgmt_frame(pMac, pTmpMlmReassocReq, + psessionEntry); + return; + +end: + /* Free up buffer allocated for reassocReq */ + if (pMlmReassocReq != NULL) { + qdf_mem_free(pMlmReassocReq); + pMlmReassocReq = NULL; + } + if (pTmpMlmReassocReq != NULL) { + qdf_mem_free(pTmpMlmReassocReq); + pTmpMlmReassocReq = NULL; + } + mlmReassocCnf.resultCode = eSIR_SME_FT_REASSOC_FAILURE; + mlmReassocCnf.protStatusCode = eSIR_MAC_UNSPEC_FAILURE_STATUS; + /* Update PE sessio Id */ + mlmReassocCnf.sessionId = psessionEntry->peSessionId; + + lim_post_sme_message(pMac, LIM_MLM_REASSOC_CNF, + (uint32_t *) &mlmReassocCnf); +} + +/** + * lim_send_reassoc_req_mgmt_frame() - Send the reassociation frame + * @pMac: Global MAC Context + * @pMlmReassocReq: Reassociation request buffer to be sent + * @psessionEntry: PE Session + * + * Return: None + */ +void lim_send_reassoc_req_mgmt_frame(tpAniSirGlobal pMac, + tLimMlmReassocReq *pMlmReassocReq, + tpPESession psessionEntry) +{ + static tDot11fReAssocRequest frm; + uint16_t caps; + uint8_t *pFrame; + uint32_t nBytes, nPayload, nStatus; + uint8_t fQosEnabled, fWmeEnabled, fWsmEnabled; + void *pPacket; + QDF_STATUS qdf_status; + uint16_t nAddIELen; + uint8_t *pAddIE; + uint8_t *wpsIe = NULL; + uint8_t txFlag = 0; + uint8_t PowerCapsPopulated = false; + uint8_t smeSessionId = 0; + bool isVHTEnabled = false; + tpSirMacMgmtHdr pMacHdr; + + if (NULL == psessionEntry) + return; + + smeSessionId = psessionEntry->smeSessionId; + if (NULL == psessionEntry->pLimReAssocReq) + return; + nAddIELen = psessionEntry->pLimReAssocReq->addIEAssoc.length; + pAddIE = psessionEntry->pLimReAssocReq->addIEAssoc.addIEdata; + + qdf_mem_set((uint8_t *) &frm, sizeof(frm), 0); + + caps = pMlmReassocReq->capabilityInfo; +#if defined(FEATURE_WLAN_WAPI) + /* + * CR: 262463 : + * According to WAPI standard: + * 7.3.1.4 Capability Information field + * In WAPI, non-AP STAs within an ESS set the Privacy subfield to 0 in + * transmitted. Association or Reassociation management frames. APs + * ignore the Privacy subfield within received Association and + * Reassociation management frames. + */ + if (psessionEntry->encryptType == eSIR_ED_WPI) + ((tSirMacCapabilityInfo *) &caps)->privacy = 0; +#endif + swap_bit_field16(caps, (uint16_t *) &frm.Capabilities); + + frm.ListenInterval.interval = pMlmReassocReq->listenInterval; + + qdf_mem_copy((uint8_t *) frm.CurrentAPAddress.mac, + (uint8_t *) psessionEntry->bssId, 6); + + populate_dot11f_ssid2(pMac, &frm.SSID); + populate_dot11f_supp_rates(pMac, POPULATE_DOT11F_RATES_OPERATIONAL, + &frm.SuppRates, psessionEntry); + + fQosEnabled = (psessionEntry->limQosEnabled) && + SIR_MAC_GET_QOS(psessionEntry->limReassocBssCaps); + + fWmeEnabled = (psessionEntry->limWmeEnabled) && + LIM_BSS_CAPS_GET(WME, psessionEntry->limReassocBssQosCaps); + + fWsmEnabled = (psessionEntry->limWsmEnabled) && fWmeEnabled && + LIM_BSS_CAPS_GET(WSM, psessionEntry->limReassocBssQosCaps); + + if (psessionEntry->lim11hEnable && + psessionEntry->pLimReAssocReq->spectrumMgtIndicator == eSIR_TRUE) { + PowerCapsPopulated = true; + populate_dot11f_power_caps(pMac, &frm.PowerCaps, LIM_REASSOC, + psessionEntry); + populate_dot11f_supp_channels(pMac, &frm.SuppChannels, + LIM_REASSOC, psessionEntry); + } + if (pMac->rrm.rrmPEContext.rrmEnable && + SIR_MAC_GET_RRM(psessionEntry->limCurrentBssCaps)) { + if (PowerCapsPopulated == false) { + PowerCapsPopulated = true; + populate_dot11f_power_caps(pMac, &frm.PowerCaps, + LIM_REASSOC, psessionEntry); + } + } + + if (fQosEnabled) + populate_dot11f_qos_caps_station(pMac, psessionEntry, + &frm.QOSCapsStation); + + populate_dot11f_ext_supp_rates(pMac, POPULATE_DOT11F_RATES_OPERATIONAL, + &frm.ExtSuppRates, psessionEntry); + + if (pMac->rrm.rrmPEContext.rrmEnable && + SIR_MAC_GET_RRM(psessionEntry->limCurrentBssCaps)) + populate_dot11f_rrm_ie(pMac, &frm.RRMEnabledCap, psessionEntry); + /* The join request *should* contain zero or one of the WPA and RSN */ + /* IEs. The payload send along with the request is a */ + /* 'tSirSmeJoinReq'; the IE portion is held inside a 'tSirRSNie': */ + + /* typedef struct sSirRSNie */ + /* { */ + /* uint16_t length; */ + /* uint8_t rsnIEdata[SIR_MAC_MAX_IE_LENGTH+2]; */ + /* } tSirRSNie, *tpSirRSNie; */ + + /* So, we should be able to make the following two calls harmlessly, */ + /* since they do nothing if they don't find the given IE in the */ + /* bytestream with which they're provided. */ + + /* The net effect of this will be to faithfully transmit whatever */ + /* security IE is in the join request. */ + + /**However*, if we're associating for the purpose of WPS */ + /* enrollment, and we've been configured to indicate that by */ + /* eliding the WPA or RSN IE, we just skip this: */ + if (nAddIELen && pAddIE) + wpsIe = limGetWscIEPtr(pMac, pAddIE, nAddIELen); + if (NULL == wpsIe) { + populate_dot11f_rsn_opaque(pMac, + &(psessionEntry->pLimReAssocReq->rsnIE), + &frm.RSNOpaque); + populate_dot11f_wpa_opaque(pMac, + &(psessionEntry->pLimReAssocReq->rsnIE), + &frm.WPAOpaque); +#if defined(FEATURE_WLAN_WAPI) + populate_dot11f_wapi_opaque(pMac, + &(psessionEntry->pLimReAssocReq-> + rsnIE), &frm.WAPIOpaque); +#endif /* defined(FEATURE_WLAN_WAPI) */ + } + /* include WME EDCA IE as well */ + if (fWmeEnabled) { + populate_dot11f_wmm_info_station_per_session(pMac, + psessionEntry, &frm.WMMInfoStation); + + if (fWsmEnabled) + populate_dot11f_wmm_caps(&frm.WMMCaps); + } + + if (psessionEntry->htCapability && + pMac->lim.htCapabilityPresentInBeacon) { + populate_dot11f_ht_caps(pMac, psessionEntry, &frm.HTCaps); + } + if (psessionEntry->vhtCapability && + psessionEntry->vhtCapabilityPresentInBeacon) { + lim_log(pMac, LOGW, FL("Populate VHT IEs in Re-Assoc Request")); + populate_dot11f_vht_caps(pMac, psessionEntry, &frm.VHTCaps); + isVHTEnabled = true; + } + populate_dot11f_ext_cap(pMac, isVHTEnabled, &frm.ExtCap, psessionEntry); + nStatus = + dot11f_get_packed_re_assoc_request_size(pMac, &frm, &nPayload); + if (DOT11F_FAILED(nStatus)) { + lim_log(pMac, LOGP, FL("Fail to get size:ReassocReq(0x%08x)"), + nStatus); + /* We'll fall back on the worst case scenario: */ + nPayload = sizeof(tDot11fReAssocRequest); + } else if (DOT11F_WARNED(nStatus)) { + lim_log(pMac, LOGW, FL("warning for size:ReAssoc Req(0x%08x)."), + nStatus); + } + + nBytes = nPayload + sizeof(tSirMacMgmtHdr) + nAddIELen; + + qdf_status = cds_packet_alloc((uint16_t) nBytes, (void **)&pFrame, + (void **)&pPacket); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + psessionEntry->limMlmState = psessionEntry->limPrevMlmState; + MTRACE(qdf_trace(QDF_MODULE_ID_PE, TRACE_CODE_MLM_STATE, + psessionEntry->peSessionId, + psessionEntry->limMlmState)); + lim_log(pMac, LOGP, + FL("Failed to alloc %d bytes for a ReAssociation Req."), + nBytes); + goto end; + } + /* Paranoia: */ + qdf_mem_set(pFrame, nBytes, 0); + + /* Next, we fill out the buffer descriptor: */ + lim_populate_mac_header(pMac, pFrame, SIR_MAC_MGMT_FRAME, + SIR_MAC_MGMT_REASSOC_REQ, psessionEntry->limReAssocbssId, + psessionEntry->selfMacAddr); + pMacHdr = (tpSirMacMgmtHdr) pFrame; + + /* That done, pack the Probe Request: */ + nStatus = dot11f_pack_re_assoc_request(pMac, &frm, pFrame + + sizeof(tSirMacMgmtHdr), + nPayload, &nPayload); + if (DOT11F_FAILED(nStatus)) { + lim_log(pMac, LOGE, FL("Fail to pack a Re-Assoc Req(0x%08x)."), + nStatus); + cds_packet_free((void *)pPacket); + goto end; + } else if (DOT11F_WARNED(nStatus)) { + lim_log(pMac, LOGW, FL("warning packing a Re-AssocReq(0x%08x)"), + nStatus); + } + + PELOG1(lim_log + (pMac, LOG1, + FL("*** Sending Re-Association Request length %d" "to "), + nBytes); + ) + + if (psessionEntry->assocReq != NULL) { + qdf_mem_free(psessionEntry->assocReq); + psessionEntry->assocReq = NULL; + psessionEntry->assocReqLen = 0; + } + + if (nAddIELen) { + qdf_mem_copy(pFrame + sizeof(tSirMacMgmtHdr) + nPayload, + pAddIE, nAddIELen); + nPayload += nAddIELen; + } + + psessionEntry->assocReq = qdf_mem_malloc(nPayload); + if (NULL == psessionEntry->assocReq) { + lim_log(pMac, LOGE, FL("Unable to allocate mem for assoc req")); + } else { + /* Store the Assocrequest. It is sent to csr in joincnfrsp */ + qdf_mem_copy(psessionEntry->assocReq, + pFrame + sizeof(tSirMacMgmtHdr), nPayload); + psessionEntry->assocReqLen = nPayload; + } + + if ((SIR_BAND_5_GHZ == + lim_get_rf_band(psessionEntry->currentOperChannel)) + || (psessionEntry->pePersona == QDF_P2P_CLIENT_MODE) || + (psessionEntry->pePersona == QDF_P2P_GO_MODE)) + txFlag |= HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME; + + if (psessionEntry->pePersona == QDF_P2P_CLIENT_MODE || + psessionEntry->pePersona == QDF_STA_MODE) + txFlag |= HAL_USE_PEER_STA_REQUESTED_MASK; + +#ifdef FEATURE_WLAN_DIAG_SUPPORT + lim_diag_event_report(pMac, WLAN_PE_DIAG_REASSOC_START_EVENT, + psessionEntry, eSIR_SUCCESS, eSIR_SUCCESS); +#endif + MTRACE(qdf_trace(QDF_MODULE_ID_PE, TRACE_CODE_TX_MGMT, + psessionEntry->peSessionId, pMacHdr->fc.subType)); + qdf_status = + wma_tx_frame(pMac, pPacket, + (uint16_t) (sizeof(tSirMacMgmtHdr) + nPayload), + TXRX_FRM_802_11_MGMT, ANI_TXDIR_TODS, 7, + lim_tx_complete, pFrame, txFlag, smeSessionId, 0); + MTRACE(qdf_trace + (QDF_MODULE_ID_PE, TRACE_CODE_TX_COMPLETE, + psessionEntry->peSessionId, qdf_status)); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + lim_log(pMac, LOGE, + FL("Failed to send Re-Association Request (%X)!"), + qdf_status); + /* Pkt will be freed up by the callback */ + } + +end: + /* Free up buffer allocated for mlmAssocReq */ + qdf_mem_free(pMlmReassocReq); + psessionEntry->pLimMlmReassocReq = NULL; + +} diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_send_management_frames.c b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_send_management_frames.c new file mode 100644 index 0000000000000000000000000000000000000000..f63c04aeeb64445c2bf474d4c86f387f6e571cc7 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_send_management_frames.c @@ -0,0 +1,4711 @@ +/* + * Copyright (c) 2011-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * \file lim_send_management_frames.c + * + * \brief Code for preparing and sending 802.11 Management frames + * + * + */ + +#include "sir_api.h" +#include "ani_global.h" +#include "sir_mac_prot_def.h" +#include "cfg_api.h" +#include "utils_api.h" +#include "lim_types.h" +#include "lim_utils.h" +#include "lim_security_utils.h" +#include "lim_prop_exts_utils.h" +#include "dot11f.h" +#include "lim_sta_hash_api.h" +#include "sch_api.h" +#include "lim_send_messages.h" +#include "lim_assoc_utils.h" +#include "lim_ft.h" +#ifdef WLAN_FEATURE_11W +#include "wni_cfg.h" +#endif + +#include "lim_ft_defs.h" +#include "lim_session.h" +#include "qdf_types.h" +#include "qdf_trace.h" +#include "cds_utils.h" +#include "sme_trace.h" +#include "rrm_api.h" + +#include "wma_types.h" + +/** + * + * \brief This function is called to add the sequence number to the + * management frames + * + * \param pMac Pointer to Global MAC structure + * + * \param pMacHdr Pointer to MAC management header + * + * The pMacHdr argument points to the MAC management header. The + * sequence number stored in the pMac structure will be incremented + * and updated to the MAC management header. The start sequence + * number is WLAN_HOST_SEQ_NUM_MIN and the end value is + * WLAN_HOST_SEQ_NUM_MAX. After reaching the MAX value, the sequence + * number will roll over. + * + */ +static void lim_add_mgmt_seq_num(tpAniSirGlobal pMac, tpSirMacMgmtHdr pMacHdr) +{ + if (pMac->mgmtSeqNum >= WLAN_HOST_SEQ_NUM_MAX) { + pMac->mgmtSeqNum = WLAN_HOST_SEQ_NUM_MIN - 1; + } + + pMac->mgmtSeqNum++; + + pMacHdr->seqControl.seqNumLo = (pMac->mgmtSeqNum & LOW_SEQ_NUM_MASK); + pMacHdr->seqControl.seqNumHi = + ((pMac->mgmtSeqNum & HIGH_SEQ_NUM_MASK) >> HIGH_SEQ_NUM_OFFSET); +} + +/** + * + * \brief This function is called before sending a p2p action frame + * inorder to add sequence numbers to action packets + * + * \param pMac Pointer to Global MAC structure + * + * \param pBD Pointer to the frame buffer that needs to be populate + * + * The pMacHdr argument points to the MAC management header. The + * sequence number stored in the pMac structure will be incremented + * and updated to the MAC management header. The start sequence + * number is WLAN_HOST_SEQ_NUM_MIN and the end value is + * WLAN_HOST_SEQ_NUM_MAX. After reaching the MAX value, the sequence + * number will roll over. + * + */ +void lim_populate_p2p_mac_header(tpAniSirGlobal pMac, uint8_t *pBD) +{ + tpSirMacMgmtHdr pMacHdr; + + /* / Prepare MAC management header */ + pMacHdr = (tpSirMacMgmtHdr) (pBD); + + /* Prepare sequence number */ + lim_add_mgmt_seq_num(pMac, pMacHdr); + lim_log(pMac, LOG1, "seqNumLo=%d, seqNumHi=%d, mgmtSeqNum=%d", + pMacHdr->seqControl.seqNumLo, + pMacHdr->seqControl.seqNumHi, pMac->mgmtSeqNum); +} + +/** + * lim_populate_mac_header() - Fill in 802.11 header of frame + * + * @mac_ctx: Pointer to Global MAC structure + * @buf: Pointer to the frame buffer that needs to be populate + * @type: 802.11 Type of the frame + * @sub_type: 802.11 Subtype of the frame + * @peer_addr: dst address + * @self_mac_addr: local mac address + * + * This function is called by various LIM modules to prepare the + * 802.11 frame MAC header + * + * The buf argument points to the beginning of the frame buffer to + * which - a) The 802.11 MAC header is set b) Following this MAC header + * will be the MGMT frame payload The payload itself is populated by the + * caller API + * + * Return: None + */ + +void lim_populate_mac_header(tpAniSirGlobal mac_ctx, uint8_t *buf, + uint8_t type, uint8_t sub_type, tSirMacAddr peer_addr, + tSirMacAddr self_mac_addr) +{ + tpSirMacMgmtHdr mac_hdr; + + /* Prepare MAC management header */ + mac_hdr = (tpSirMacMgmtHdr) (buf); + + /* Prepare FC */ + mac_hdr->fc.protVer = SIR_MAC_PROTOCOL_VERSION; + mac_hdr->fc.type = type; + mac_hdr->fc.subType = sub_type; + + /* Prepare Address 1 */ + qdf_mem_copy((uint8_t *) mac_hdr->da, + (uint8_t *) peer_addr, sizeof(tSirMacAddr)); + + /* Prepare Address 2 */ + sir_copy_mac_addr(mac_hdr->sa, self_mac_addr); + + /* Prepare Address 3 */ + qdf_mem_copy((uint8_t *) mac_hdr->bssId, + (uint8_t *) peer_addr, sizeof(tSirMacAddr)); + + /* Prepare sequence number */ + lim_add_mgmt_seq_num(mac_ctx, mac_hdr); + lim_log(mac_ctx, LOG1, "seqNumLo=%d, seqNumHi=%d, mgmtSeqNum=%d", + mac_hdr->seqControl.seqNumLo, + mac_hdr->seqControl.seqNumHi, mac_ctx->mgmtSeqNum); +} + +/** + * lim_send_probe_req_mgmt_frame() - send probe request management frame + * @mac_ctx: Pointer to Global MAC structure + * @ssid: SSID to be sent in Probe Request frame + * @bssid: BSSID to be sent in Probe Request frame + * @channel: Channel # on which the Probe Request is going out + * @self_macaddr: self MAC address + * @dot11mode: self dotllmode + * @additional_ielen: if non-zero, include additional_ie in the Probe Request + * frame + * @additional_ie: if additional_ielen is non zero, include this field in the + * Probe Request frame + * + * This function is called by various LIM modules to send Probe Request frame + * during active scan/learn phase. + * Probe request is sent out in the following scenarios: + * --heartbeat failure: session needed + * --join req: session needed + * --foreground scan: no session + * --background scan: no session + * --sch_beacon_processing: to get EDCA parameters: session needed + * + * Return: tSirRetStatus (eSIR_SUCCESS on success and error codes otherwise) + */ +tSirRetStatus +lim_send_probe_req_mgmt_frame(tpAniSirGlobal mac_ctx, + tSirMacSSid *ssid, + tSirMacAddr bssid, + uint8_t channel, + tSirMacAddr self_macaddr, + uint32_t dot11mode, + uint32_t additional_ielen, uint8_t *additional_ie) +{ + tDot11fProbeRequest pr; + uint32_t status, bytes, payload; + uint8_t *frame; + void *packet; + QDF_STATUS qdf_status; + tpPESession pesession; + uint8_t sessionid; + uint8_t *p2pie = NULL; + uint8_t txflag = 0; + uint8_t sme_sessionid = 0; + bool is_vht_enabled = false; + uint8_t txPower; + uint16_t addn_ielen = additional_ielen; + bool extracted_ext_cap_flag = false; + tDot11fIEExtCap extracted_ext_cap; + tSirRetStatus sir_status; + + /* The probe req should not send 11ac capabilieties if band is 2.4GHz, + * unless enableVhtFor24GHz is enabled in INI. So if enableVhtFor24GHz + * is false and dot11mode is 11ac set it to 11n. + */ + if (channel <= SIR_11B_CHANNEL_END && + (false == mac_ctx->roam.configParam.enableVhtFor24GHz) && + (WNI_CFG_DOT11_MODE_11AC == dot11mode || + WNI_CFG_DOT11_MODE_11AC_ONLY == dot11mode)) + dot11mode = WNI_CFG_DOT11_MODE_11N; + /* + * session context may or may not be present, when probe request needs + * to be sent out. Following cases exist: + * --heartbeat failure: session needed + * --join req: session needed + * --foreground scan: no session + * --background scan: no session + * --sch_beacon_processing: to get EDCA parameters: session needed + * If session context does not exist, some IEs will be populated from + * CFGs, e.g. Supported and Extended rate set IEs + */ + pesession = pe_find_session_by_bssid(mac_ctx, bssid, &sessionid); + + if (pesession != NULL) + sme_sessionid = pesession->smeSessionId; + + /* The scheme here is to fill out a 'tDot11fProbeRequest' structure */ + /* and then hand it off to 'dot11f_pack_probe_request' (for */ + /* serialization). We start by zero-initializing the structure: */ + qdf_mem_set((uint8_t *) &pr, sizeof(pr), 0); + + /* & delegating to assorted helpers: */ + populate_dot11f_ssid(mac_ctx, ssid, &pr.SSID); + + if (addn_ielen && additional_ie) + p2pie = limGetP2pIEPtr(mac_ctx, additional_ie, addn_ielen); + + /* + * Don't include 11b rate if it is a P2P serach or probe request is + * sent by P2P Client + */ + if ((WNI_CFG_DOT11_MODE_11B != dot11mode) && (p2pie != NULL) && + (((mac_ctx->lim.gpLimMlmScanReq != NULL) && + mac_ctx->lim.gpLimMlmScanReq->p2pSearch) || + ((pesession != NULL) && + (QDF_P2P_CLIENT_MODE == pesession->pePersona)) + ) + ) { + /* + * In the below API pass channel number > 14, do that it fills + * only 11a rates in supported rates + */ + populate_dot11f_supp_rates(mac_ctx, 15, &pr.SuppRates, + pesession); + } else { + populate_dot11f_supp_rates(mac_ctx, channel, + &pr.SuppRates, pesession); + + if (WNI_CFG_DOT11_MODE_11B != dot11mode) { + populate_dot11f_ext_supp_rates1(mac_ctx, channel, + &pr.ExtSuppRates); + } + } + + /* + * Table 7-14 in IEEE Std. 802.11k-2008 says + * DS params "can" be present in RRM is disabled and "is" present if + * RRM is enabled. It should be ok even if we add it into probe req when + * RRM is not enabled. + */ + populate_dot11f_ds_params(mac_ctx, &pr.DSParams, channel); + /* Call RRM module to get the tx power for management used. */ + txPower = (uint8_t) rrm_get_mgmt_tx_power(mac_ctx, pesession); + populate_dot11f_wfatpc(mac_ctx, &pr.WFATPC, txPower, 0); + + + if (pesession != NULL) { + pesession->htCapability = IS_DOT11_MODE_HT(dot11mode); + /* Include HT Capability IE */ + if (pesession->htCapability) + populate_dot11f_ht_caps(mac_ctx, pesession, &pr.HTCaps); + } else { /* pesession == NULL */ + if (IS_DOT11_MODE_HT(dot11mode)) + populate_dot11f_ht_caps(mac_ctx, NULL, &pr.HTCaps); + } + + /* + * Set channelbonding information as "disabled" when tunned to a + * 2.4 GHz channel + */ + if (channel <= SIR_11B_CHANNEL_END) { + if (mac_ctx->roam.configParam.channelBondingMode24GHz + == PHY_SINGLE_CHANNEL_CENTERED) { + pr.HTCaps.supportedChannelWidthSet = + eHT_CHANNEL_WIDTH_20MHZ; + pr.HTCaps.shortGI40MHz = 0; + } else { + pr.HTCaps.supportedChannelWidthSet = + eHT_CHANNEL_WIDTH_40MHZ; + } + } + if (pesession != NULL) { + pesession->vhtCapability = IS_DOT11_MODE_VHT(dot11mode); + /* Include VHT Capability IE */ + if (pesession->vhtCapability) { + populate_dot11f_vht_caps(mac_ctx, pesession, + &pr.VHTCaps); + is_vht_enabled = true; + } + } else { + if (IS_DOT11_MODE_VHT(dot11mode)) { + populate_dot11f_vht_caps(mac_ctx, pesession, + &pr.VHTCaps); + is_vht_enabled = true; + } + } + if (pesession != NULL) + populate_dot11f_ext_cap(mac_ctx, is_vht_enabled, &pr.ExtCap, + pesession); + + if (mac_ctx->roam.configParam.qcn_ie_support) + populate_dot11f_qcn_ie(&pr.QCN_IE); + + if (addn_ielen) { + qdf_mem_zero((uint8_t *)&extracted_ext_cap, + sizeof(tDot11fIEExtCap)); + sir_status = lim_strip_extcap_update_struct(mac_ctx, + additional_ie, + &addn_ielen, + &extracted_ext_cap); + if (eSIR_SUCCESS != sir_status) { + lim_log(mac_ctx, LOG1, + FL("Unable to Stripoff ExtCap IE from Probe Req")); + } else { + struct s_ext_cap *p_ext_cap = + (struct s_ext_cap *) + extracted_ext_cap.bytes; + if (p_ext_cap->interworking_service) + p_ext_cap->qos_map = 1; + extracted_ext_cap.num_bytes = + lim_compute_ext_cap_ie_length + (&extracted_ext_cap); + extracted_ext_cap_flag = + (extracted_ext_cap.num_bytes > 0); + } + } + + /* + * Extcap IE now support variable length, merge Extcap IE from addn_ie + * may change the frame size. Therefore, MUST merge ExtCap IE before + * dot11f get packed payload size. + */ + if (extracted_ext_cap_flag) + lim_merge_extcap_struct(&pr.ExtCap, &extracted_ext_cap, true); + + /* That's it-- now we pack it. First, how much space are we going to */ + status = dot11f_get_packed_probe_request_size(mac_ctx, &pr, &payload); + if (DOT11F_FAILED(status)) { + lim_log(mac_ctx, LOGE, + FL("Failed to calculate the packed size for a Probe Request (0x%08x)."), + status); + /* We'll fall back on the worst case scenario: */ + payload = sizeof(tDot11fProbeRequest); + } else if (DOT11F_WARNED(status)) { + lim_log(mac_ctx, LOGW, + FL("There were warnings while calculating the packed size for a Probe Request (0x%08x)."), + status); + } + + bytes = payload + sizeof(tSirMacMgmtHdr) + addn_ielen; + + /* Ok-- try to allocate some memory: */ + qdf_status = cds_packet_alloc((uint16_t) bytes, (void **)&frame, + (void **)&packet); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + lim_log(mac_ctx, LOGP, FL("Failed to allocate %d bytes for a Probe Request."), bytes); + return eSIR_MEM_ALLOC_FAILED; + } + /* Paranoia: */ + qdf_mem_set(frame, bytes, 0); + + /* Next, we fill out the buffer descriptor: */ + lim_populate_mac_header(mac_ctx, frame, SIR_MAC_MGMT_FRAME, + SIR_MAC_MGMT_PROBE_REQ, bssid, self_macaddr); + + /* That done, pack the Probe Request: */ + status = dot11f_pack_probe_request(mac_ctx, &pr, frame + + sizeof(tSirMacMgmtHdr), + payload, &payload); + if (DOT11F_FAILED(status)) { + lim_log(mac_ctx, LOGE, + FL("Failed to pack a Probe Request (0x%08x)."), status); + cds_packet_free((void *)packet); + return eSIR_FAILURE; /* allocated! */ + } else if (DOT11F_WARNED(status)) { + lim_log(mac_ctx, LOGW, FL("There were warnings while packing a Probe Request (0x%08x)."), status); + } + /* Append any AddIE if present. */ + if (addn_ielen) { + qdf_mem_copy(frame + sizeof(tSirMacMgmtHdr) + payload, + additional_ie, addn_ielen); + payload += addn_ielen; + } + + /* If this probe request is sent during P2P Search State, then we need + * to send it at OFDM rate. + */ + if ((SIR_BAND_5_GHZ == lim_get_rf_band(channel)) + || ((mac_ctx->lim.gpLimMlmScanReq != NULL) && + mac_ctx->lim.gpLimMlmScanReq->p2pSearch) + /* + * For unicast probe req mgmt from Join function we don't set + * above variables. So we need to add one more check whether it + * is pePersona is P2P_CLIENT or not + */ + || ((pesession != NULL) && + (QDF_P2P_CLIENT_MODE == pesession->pePersona)) + ) { + txflag |= HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME; + } + + qdf_status = + wma_tx_frame(mac_ctx, packet, + (uint16_t) sizeof(tSirMacMgmtHdr) + payload, + TXRX_FRM_802_11_MGMT, ANI_TXDIR_TODS, 7, + lim_tx_complete, frame, txflag, sme_sessionid, + 0); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + lim_log(mac_ctx, LOGE, + FL("could not send Probe Request frame!")); + /* Pkt will be freed up by the callback */ + return eSIR_FAILURE; + } + + return eSIR_SUCCESS; +} /* End lim_send_probe_req_mgmt_frame. */ + +static tSirRetStatus lim_get_addn_ie_for_probe_resp(tpAniSirGlobal pMac, + uint8_t *addIE, uint16_t *addnIELen, + uint8_t probeReqP2pIe) +{ + /* If Probe request doesn't have P2P IE, then take out P2P IE + from additional IE */ + if (!probeReqP2pIe) { + uint8_t *tempbuf = NULL; + uint16_t tempLen = 0; + int left = *addnIELen; + uint8_t *ptr = addIE; + uint8_t elem_id, elem_len; + + if (NULL == addIE) { + PELOGE(lim_log(pMac, LOGE, FL(" NULL addIE pointer"));) + return eSIR_FAILURE; + } + + tempbuf = qdf_mem_malloc(left); + if (NULL == tempbuf) { + PELOGE(lim_log(pMac, LOGE, + FL + ("Unable to allocate memory to store addn IE")); + ) + return eSIR_MEM_ALLOC_FAILED; + } + + while (left >= 2) { + elem_id = ptr[0]; + elem_len = ptr[1]; + left -= 2; + if (elem_len > left) { + lim_log(pMac, LOGE, + FL + ("****Invalid IEs eid = %d elem_len=%d left=%d*****"), + elem_id, elem_len, left); + qdf_mem_free(tempbuf); + return eSIR_FAILURE; + } + if (!((SIR_MAC_EID_VENDOR == elem_id) && + (memcmp + (&ptr[2], SIR_MAC_P2P_OUI, + SIR_MAC_P2P_OUI_SIZE) == 0))) { + qdf_mem_copy(tempbuf + tempLen, &ptr[0], + elem_len + 2); + tempLen += (elem_len + 2); + } + left -= elem_len; + ptr += (elem_len + 2); + } + qdf_mem_copy(addIE, tempbuf, tempLen); + *addnIELen = tempLen; + qdf_mem_free(tempbuf); + } + return eSIR_SUCCESS; +} + +/** + * lim_send_probe_rsp_mgmt_frame() - Send probe response + * + * @mac_ctx: Handle for mac context + * @peer_macaddr: Mac address of requesting peer + * @ssid: SSID for response + * @n_staid: Station ID, currently unused. + * @pe_session: PE session id + * @keepalive: Keep alive flag. Currently unused. + * @preq_p2pie: P2P IE in incoming probe request + * + * Builds and sends probe response frame to the requesting peer + * + * Return: void + */ + +void +lim_send_probe_rsp_mgmt_frame(tpAniSirGlobal mac_ctx, + tSirMacAddr peer_macaddr, + tpAniSSID ssid, + short n_staid, + uint8_t keepalive, + tpPESession pe_session, uint8_t preq_p2pie) +{ + tDot11fProbeResponse *frm; + tSirRetStatus sir_status; + uint32_t cfg, payload, bytes = 0, status; + tpSirMacMgmtHdr mac_hdr; + uint8_t *frame; + void *packet = NULL; + QDF_STATUS qdf_status; + uint32_t addn_ie_present = false; + + uint16_t addn_ie_len = 0; + uint32_t wps_ap = 0, tmp; + uint8_t tx_flag = 0; + uint8_t *add_ie = NULL; + uint8_t *p2p_ie = NULL; + uint8_t noalen = 0; + uint8_t total_noalen = 0; + uint8_t noa_stream[SIR_MAX_NOA_ATTR_LEN + SIR_P2P_IE_HEADER_LEN]; + uint8_t noa_ie[SIR_MAX_NOA_ATTR_LEN + SIR_P2P_IE_HEADER_LEN]; + uint8_t sme_sessionid = 0; + bool is_vht_enabled = false; + tDot11fIEExtCap extracted_ext_cap = {0}; + bool extracted_ext_cap_flag = false; + + /* We don't answer requests in this case*/ + if (ANI_DRIVER_TYPE(mac_ctx) == eDRIVER_TYPE_MFG) + return; + + if (NULL == pe_session) + return; + + /* + * In case when cac timer is running for this SAP session then + * avoid sending probe rsp out. It is violation of dfs specification. + */ + if (((pe_session->pePersona == QDF_SAP_MODE) || + (pe_session->pePersona == QDF_P2P_GO_MODE)) && + (true == mac_ctx->sap.SapDfsInfo.is_dfs_cac_timer_running)) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO, + FL("CAC timer is running, probe response dropped")); + return; + } + sme_sessionid = pe_session->smeSessionId; + frm = qdf_mem_malloc(sizeof(tDot11fProbeResponse)); + if (NULL == frm) { + lim_log(mac_ctx, LOGE, + FL("Unable to allocate memory")); + return; + } + + /* + * Fill out 'frm', after which we'll just hand the struct off to + * 'dot11f_pack_probe_response'. + */ + qdf_mem_set((uint8_t *) frm, sizeof(tDot11fProbeResponse), 0); + + /* + * Timestamp to be updated by TFP, below. + * + * Beacon Interval: + */ + if (LIM_IS_AP_ROLE(pe_session)) { + frm->BeaconInterval.interval = + mac_ctx->sch.schObject.gSchBeaconInterval; + } else { + sir_status = wlan_cfg_get_int(mac_ctx, + WNI_CFG_BEACON_INTERVAL, &cfg); + if (eSIR_SUCCESS != sir_status) { + lim_log(mac_ctx, LOGP, + FL("Failed to get WNI_CFG_BEACON_INTERVAL (%d)."), + sir_status); + goto err_ret; + } + frm->BeaconInterval.interval = (uint16_t) cfg; + } + + populate_dot11f_capabilities(mac_ctx, &frm->Capabilities, pe_session); + populate_dot11f_ssid(mac_ctx, (tSirMacSSid *) ssid, &frm->SSID); + populate_dot11f_supp_rates(mac_ctx, POPULATE_DOT11F_RATES_OPERATIONAL, + &frm->SuppRates, pe_session); + + populate_dot11f_ds_params(mac_ctx, &frm->DSParams, + pe_session->currentOperChannel); + populate_dot11f_ibss_params(mac_ctx, &frm->IBSSParams, pe_session); + + if (LIM_IS_AP_ROLE(pe_session)) { + if (pe_session->wps_state != SAP_WPS_DISABLED) + populate_dot11f_probe_res_wpsi_es(mac_ctx, + &frm->WscProbeRes, + pe_session); + } else { + if (wlan_cfg_get_int(mac_ctx, (uint16_t) WNI_CFG_WPS_ENABLE, + &tmp) != eSIR_SUCCESS) + lim_log(mac_ctx, LOGP, "Failed to cfg get id %d", + WNI_CFG_WPS_ENABLE); + + wps_ap = tmp & WNI_CFG_WPS_ENABLE_AP; + + if (wps_ap) + populate_dot11f_wsc_in_probe_res(mac_ctx, + &frm->WscProbeRes); + + if (mac_ctx->lim.wscIeInfo.probeRespWscEnrollmentState == + eLIM_WSC_ENROLL_BEGIN) { + populate_dot11f_wsc_registrar_info_in_probe_res(mac_ctx, + &frm->WscProbeRes); + mac_ctx->lim.wscIeInfo.probeRespWscEnrollmentState = + eLIM_WSC_ENROLL_IN_PROGRESS; + } + + if (mac_ctx->lim.wscIeInfo.wscEnrollmentState == + eLIM_WSC_ENROLL_END) { + de_populate_dot11f_wsc_registrar_info_in_probe_res( + mac_ctx, &frm->WscProbeRes); + mac_ctx->lim.wscIeInfo.probeRespWscEnrollmentState = + eLIM_WSC_ENROLL_NOOP; + } + } + + populate_dot11f_country(mac_ctx, &frm->Country, pe_session); + populate_dot11f_edca_param_set(mac_ctx, &frm->EDCAParamSet, pe_session); + + if (pe_session->dot11mode != WNI_CFG_DOT11_MODE_11B) + populate_dot11f_erp_info(mac_ctx, &frm->ERPInfo, pe_session); + + populate_dot11f_ext_supp_rates(mac_ctx, + POPULATE_DOT11F_RATES_OPERATIONAL, + &frm->ExtSuppRates, pe_session); + + /* Populate HT IEs, when operating in 11n */ + if (pe_session->htCapability) { + populate_dot11f_ht_caps(mac_ctx, pe_session, &frm->HTCaps); + populate_dot11f_ht_info(mac_ctx, &frm->HTInfo, pe_session); + } + if (pe_session->vhtCapability) { + lim_log(mac_ctx, LOG1, FL("Populate VHT IE in Probe Response")); + populate_dot11f_vht_caps(mac_ctx, pe_session, &frm->VHTCaps); + populate_dot11f_vht_operation(mac_ctx, pe_session, + &frm->VHTOperation); + /* + * we do not support multi users yet. + * populate_dot11f_vht_ext_bss_load( mac_ctx, + * &frm.VHTExtBssLoad ); + */ + is_vht_enabled = true; + } + + populate_dot11f_ext_cap(mac_ctx, is_vht_enabled, &frm->ExtCap, + pe_session); + + if (pe_session->pLimStartBssReq) { + populate_dot11f_wpa(mac_ctx, + &(pe_session->pLimStartBssReq->rsnIE), + &frm->WPA); + populate_dot11f_rsn_opaque(mac_ctx, + &(pe_session->pLimStartBssReq->rsnIE), + &frm->RSNOpaque); + } + + populate_dot11f_wmm(mac_ctx, &frm->WMMInfoAp, &frm->WMMParams, + &frm->WMMCaps, pe_session); + +#if defined(FEATURE_WLAN_WAPI) + if (pe_session->pLimStartBssReq) + populate_dot11f_wapi(mac_ctx, + &(pe_session->pLimStartBssReq->rsnIE), + &frm->WAPI); +#endif /* defined(FEATURE_WLAN_WAPI) */ + + if (mac_ctx->lim.gpLimRemainOnChanReq) + bytes += (mac_ctx->lim.gpLimRemainOnChanReq->length - + sizeof(tSirRemainOnChnReq)); + else + /* + * Only use CFG for non-listen mode. This CFG is not working for + * concurrency. In listening mode, probe rsp IEs is passed in + * the message from SME to PE. + */ + addn_ie_present = + (pe_session->addIeParams.probeRespDataLen != 0); + + if (addn_ie_present) { + + add_ie = qdf_mem_malloc( + pe_session->addIeParams.probeRespDataLen); + if (NULL == add_ie) { + lim_log(mac_ctx, LOGE, + FL("add_ie allocation failed")); + goto err_ret; + } + + qdf_mem_copy(add_ie, + pe_session->addIeParams.probeRespData_buff, + pe_session->addIeParams.probeRespDataLen); + addn_ie_len = pe_session->addIeParams.probeRespDataLen; + + if (eSIR_SUCCESS != lim_get_addn_ie_for_probe_resp(mac_ctx, + add_ie, &addn_ie_len, preq_p2pie)) { + lim_log(mac_ctx, LOGP, + FL("Unable to get addn_ie")); + goto err_ret; + } + + sir_status = lim_strip_extcap_update_struct(mac_ctx, + add_ie, &addn_ie_len, + &extracted_ext_cap); + if (eSIR_SUCCESS != sir_status) { + lim_log(mac_ctx, LOG1, + FL("Unable to strip off ExtCap IE")); + } else { + extracted_ext_cap_flag = true; + } + + bytes = bytes + addn_ie_len; + + if (preq_p2pie) + p2p_ie = limGetP2pIEPtr(mac_ctx, &add_ie[0], + addn_ie_len); + + if (p2p_ie != NULL) { + /* get NoA attribute stream P2P IE */ + noalen = lim_get_noa_attr_stream(mac_ctx, + noa_stream, pe_session); + if (noalen != 0) { + total_noalen = + lim_build_p2p_ie(mac_ctx, &noa_ie[0], + &noa_stream[0], noalen); + bytes = bytes + total_noalen; + } + } + } + + /* + * Extcap IE now support variable length, merge Extcap IE from addn_ie + * may change the frame size. Therefore, MUST merge ExtCap IE before + * dot11f get packed payload size. + */ + if (extracted_ext_cap_flag) + lim_merge_extcap_struct(&frm->ExtCap, &extracted_ext_cap, + true); + + status = dot11f_get_packed_probe_response_size(mac_ctx, frm, &payload); + if (DOT11F_FAILED(status)) { + lim_log(mac_ctx, LOGE, + FL("Probe Response size error (0x%08x)."), + status); + /* We'll fall back on the worst case scenario: */ + payload = sizeof(tDot11fProbeResponse); + } else if (DOT11F_WARNED(status)) { + lim_log(mac_ctx, LOGW, + FL("Probe Response size warning (0x%08x)."), + status); + } + + bytes += payload + sizeof(tSirMacMgmtHdr); + + qdf_status = cds_packet_alloc((uint16_t) bytes, (void **)&frame, + (void **)&packet); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + lim_log(mac_ctx, LOGP, FL("Probe Response allocation failed")); + goto err_ret; + } + /* Paranoia: */ + qdf_mem_set(frame, bytes, 0); + + /* Next, we fill out the buffer descriptor: */ + lim_populate_mac_header(mac_ctx, frame, SIR_MAC_MGMT_FRAME, + SIR_MAC_MGMT_PROBE_RSP, peer_macaddr, + pe_session->selfMacAddr); + + mac_hdr = (tpSirMacMgmtHdr) frame; + + sir_copy_mac_addr(mac_hdr->bssId, pe_session->bssId); + + /* That done, pack the Probe Response: */ + status = + dot11f_pack_probe_response(mac_ctx, frm, + frame + sizeof(tSirMacMgmtHdr), + payload, &payload); + if (DOT11F_FAILED(status)) { + lim_log(mac_ctx, LOGE, + FL("Probe Response pack failure (0x%08x)."), + status); + goto err_ret; + } else if (DOT11F_WARNED(status)) { + lim_log(mac_ctx, LOGW, + FL("Probe Response pack warning (0x%08x)."), + status); + } + + lim_log(mac_ctx, LOG3, FL("Sending Probe Response frame to ")); + lim_print_mac_addr(mac_ctx, peer_macaddr, LOG3); + + mac_ctx->sys.probeRespond++; + + if (mac_ctx->lim.gpLimRemainOnChanReq) + qdf_mem_copy(frame + sizeof(tSirMacMgmtHdr) + payload, + mac_ctx->lim.gpLimRemainOnChanReq->probeRspIe, + (mac_ctx->lim.gpLimRemainOnChanReq->length - + sizeof(tSirRemainOnChnReq))); + + if (addn_ie_present) + qdf_mem_copy(frame + sizeof(tSirMacMgmtHdr) + payload, + &add_ie[0], addn_ie_len); + + if (noalen != 0) { + if (total_noalen > + (SIR_MAX_NOA_ATTR_LEN + SIR_P2P_IE_HEADER_LEN)) { + lim_log(mac_ctx, LOGE, + FL("Not able to insert NoA, total len=%d"), + total_noalen); + goto err_ret; + } else { + qdf_mem_copy(&frame[bytes - (total_noalen)], + &noa_ie[0], total_noalen); + } + } + + if ((SIR_BAND_5_GHZ == lim_get_rf_band(pe_session->currentOperChannel)) + || (pe_session->pePersona == QDF_P2P_CLIENT_MODE) || + (pe_session->pePersona == QDF_P2P_GO_MODE) + ) + tx_flag |= HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME; + + /* Queue Probe Response frame in high priority WQ */ + qdf_status = wma_tx_frame((tHalHandle) mac_ctx, packet, + (uint16_t) bytes, + TXRX_FRM_802_11_MGMT, + ANI_TXDIR_TODS, + 7, lim_tx_complete, frame, tx_flag, + sme_sessionid, 0); + + /* Pkt will be freed up by the callback */ + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) + lim_log(mac_ctx, LOGE, FL("Could not send Probe Response.")); + + if (add_ie != NULL) + qdf_mem_free(add_ie); + + qdf_mem_free(frm); + return; + +err_ret: + if (add_ie != NULL) + qdf_mem_free(add_ie); + if (frm != NULL) + qdf_mem_free(frm); + if (packet != NULL) + cds_packet_free((void *)packet); + return; + +} /* End lim_send_probe_rsp_mgmt_frame. */ + +void +lim_send_addts_req_action_frame(tpAniSirGlobal pMac, + tSirMacAddr peerMacAddr, + tSirAddtsReqInfo *pAddTS, tpPESession psessionEntry) +{ + uint16_t i; + uint8_t *pFrame; + tDot11fAddTSRequest AddTSReq; + tDot11fWMMAddTSRequest WMMAddTSReq; + uint32_t nPayload, nBytes, nStatus; + tpSirMacMgmtHdr pMacHdr; + void *pPacket; +#ifdef FEATURE_WLAN_ESE + uint32_t phyMode; +#endif + QDF_STATUS qdf_status; + uint8_t txFlag = 0; + uint8_t smeSessionId = 0; + + if (NULL == psessionEntry) { + return; + } + + smeSessionId = psessionEntry->smeSessionId; + + if (!pAddTS->wmeTspecPresent) { + qdf_mem_set((uint8_t *) &AddTSReq, sizeof(AddTSReq), 0); + + AddTSReq.Action.action = SIR_MAC_QOS_ADD_TS_REQ; + AddTSReq.DialogToken.token = pAddTS->dialogToken; + AddTSReq.Category.category = SIR_MAC_ACTION_QOS_MGMT; + if (pAddTS->lleTspecPresent) { + populate_dot11f_tspec(&pAddTS->tspec, &AddTSReq.TSPEC); + } else { + populate_dot11f_wmmtspec(&pAddTS->tspec, + &AddTSReq.WMMTSPEC); + } + + if (pAddTS->lleTspecPresent) { + AddTSReq.num_WMMTCLAS = 0; + AddTSReq.num_TCLAS = pAddTS->numTclas; + for (i = 0; i < pAddTS->numTclas; ++i) { + populate_dot11f_tclas(pMac, &pAddTS->tclasInfo[i], + &AddTSReq.TCLAS[i]); + } + } else { + AddTSReq.num_TCLAS = 0; + AddTSReq.num_WMMTCLAS = pAddTS->numTclas; + for (i = 0; i < pAddTS->numTclas; ++i) { + populate_dot11f_wmmtclas(pMac, + &pAddTS->tclasInfo[i], + &AddTSReq.WMMTCLAS[i]); + } + } + + if (pAddTS->tclasProcPresent) { + if (pAddTS->lleTspecPresent) { + AddTSReq.TCLASSPROC.processing = + pAddTS->tclasProc; + AddTSReq.TCLASSPROC.present = 1; + } else { + AddTSReq.WMMTCLASPROC.version = 1; + AddTSReq.WMMTCLASPROC.processing = + pAddTS->tclasProc; + AddTSReq.WMMTCLASPROC.present = 1; + } + } + + nStatus = + dot11f_get_packed_add_ts_request_size(pMac, &AddTSReq, &nPayload); + if (DOT11F_FAILED(nStatus)) { + lim_log(pMac, LOGP, + FL("Failed to calculate the packed size f" + "or an Add TS Request (0x%08x)."), nStatus); + /* We'll fall back on the worst case scenario: */ + nPayload = sizeof(tDot11fAddTSRequest); + } else if (DOT11F_WARNED(nStatus)) { + lim_log(pMac, LOGW, + FL("There were warnings while calculating" + "the packed size for an Add TS Request" + " (0x%08x)."), nStatus); + } + } else { + qdf_mem_set((uint8_t *) &WMMAddTSReq, sizeof(WMMAddTSReq), 0); + + WMMAddTSReq.Action.action = SIR_MAC_QOS_ADD_TS_REQ; + WMMAddTSReq.DialogToken.token = pAddTS->dialogToken; + WMMAddTSReq.Category.category = SIR_MAC_ACTION_WME; + + /* WMM spec 2.2.10 - status code is only filled in for ADDTS response */ + WMMAddTSReq.StatusCode.statusCode = 0; + + populate_dot11f_wmmtspec(&pAddTS->tspec, &WMMAddTSReq.WMMTSPEC); +#ifdef FEATURE_WLAN_ESE + lim_get_phy_mode(pMac, &phyMode, psessionEntry); + + if (phyMode == WNI_CFG_PHY_MODE_11G + || phyMode == WNI_CFG_PHY_MODE_11A) { + pAddTS->tsrsIE.rates[0] = TSRS_11AG_RATE_6MBPS; + } else { + pAddTS->tsrsIE.rates[0] = TSRS_11B_RATE_5_5MBPS; + } + populate_dot11_tsrsie(pMac, &pAddTS->tsrsIE, + &WMMAddTSReq.ESETrafStrmRateSet, + sizeof(uint8_t)); +#endif + /* fillWmeTspecIE */ + + nStatus = + dot11f_get_packed_wmm_add_ts_request_size(pMac, &WMMAddTSReq, + &nPayload); + if (DOT11F_FAILED(nStatus)) { + lim_log(pMac, LOGP, + FL("Failed to calculate the packed size f" + "or a WMM Add TS Request (0x%08x)."), + nStatus); + /* We'll fall back on the worst case scenario: */ + nPayload = sizeof(tDot11fAddTSRequest); + } else if (DOT11F_WARNED(nStatus)) { + lim_log(pMac, LOGW, + FL("There were warnings while calculating" + "the packed size for a WMM Add TS Requ" + "est (0x%08x)."), nStatus); + } + } + + nBytes = nPayload + sizeof(tSirMacMgmtHdr); + + qdf_status = cds_packet_alloc((uint16_t) nBytes, (void **)&pFrame, + (void **)&pPacket); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + lim_log(pMac, LOGP, FL("Failed to allocate %d bytes for an Ad" + "d TS Request."), nBytes); + return; + } + /* Paranoia: */ + qdf_mem_set(pFrame, nBytes, 0); + + /* Next, we fill out the buffer descriptor: */ + lim_populate_mac_header(pMac, pFrame, SIR_MAC_MGMT_FRAME, + SIR_MAC_MGMT_ACTION, peerMacAddr, psessionEntry->selfMacAddr); + pMacHdr = (tpSirMacMgmtHdr) pFrame; + + sir_copy_mac_addr(pMacHdr->bssId, psessionEntry->bssId); + +#ifdef WLAN_FEATURE_11W + lim_set_protected_bit(pMac, psessionEntry, peerMacAddr, pMacHdr); +#endif + + /* That done, pack the struct: */ + if (!pAddTS->wmeTspecPresent) { + nStatus = dot11f_pack_add_ts_request(pMac, &AddTSReq, + pFrame + + sizeof(tSirMacMgmtHdr), + nPayload, &nPayload); + if (DOT11F_FAILED(nStatus)) { + lim_log(pMac, LOGE, + FL("Failed to pack an Add TS Request " + "(0x%08x)."), nStatus); + cds_packet_free((void *)pPacket); + return; /* allocated! */ + } else if (DOT11F_WARNED(nStatus)) { + lim_log(pMac, LOGW, + FL("There were warnings while packing " + "an Add TS Request (0x%08x)."), nStatus); + } + } else { + nStatus = dot11f_pack_wmm_add_ts_request(pMac, &WMMAddTSReq, + pFrame + + sizeof(tSirMacMgmtHdr), + nPayload, &nPayload); + if (DOT11F_FAILED(nStatus)) { + lim_log(pMac, LOGE, + FL("Failed to pack a WMM Add TS Reque" + "st (0x%08x)."), nStatus); + cds_packet_free((void *)pPacket); + return; /* allocated! */ + } else if (DOT11F_WARNED(nStatus)) { + lim_log(pMac, LOGW, + FL("There were warnings while packing " + "a WMM Add TS Request (0x%08x)."), nStatus); + } + } + + PELOG3(lim_log(pMac, LOG3, FL("Sending an Add TS Request frame to ")); + lim_print_mac_addr(pMac, peerMacAddr, LOG3); + ) + + if ((SIR_BAND_5_GHZ == + lim_get_rf_band(psessionEntry->currentOperChannel)) + || (psessionEntry->pePersona == QDF_P2P_CLIENT_MODE) + || (psessionEntry->pePersona == QDF_P2P_GO_MODE) + ) { + txFlag |= HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME; + } + + MTRACE(qdf_trace(QDF_MODULE_ID_PE, TRACE_CODE_TX_MGMT, + psessionEntry->peSessionId, pMacHdr->fc.subType)); + + /* Queue Addts Response frame in high priority WQ */ + qdf_status = wma_tx_frame(pMac, pPacket, (uint16_t) nBytes, + TXRX_FRM_802_11_MGMT, + ANI_TXDIR_TODS, + 7, lim_tx_complete, pFrame, txFlag, + smeSessionId, 0); + MTRACE(qdf_trace(QDF_MODULE_ID_PE, TRACE_CODE_TX_COMPLETE, + psessionEntry->peSessionId, qdf_status)); + + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + lim_log(pMac, LOGE, FL("*** Could not send an Add TS Request" + " (%X) ***"), qdf_status); + /* Pkt will be freed up by the callback */ + } + +} /* End lim_send_addts_req_action_frame. */ + +/** + * lim_send_assoc_rsp_mgmt_frame() - Send assoc response + * @mac_ctx: Handle for mac context + * @status_code: Status code for assoc response frame + * @aid: Association ID + * @peer_addr: Mac address of requesting peer + * @subtype: Assoc/Reassoc + * @sta: Pointer to station node + * @pe_session: PE session id. + * + * Builds and sends association response frame to the requesting peer. + * + * Return: void + */ + +void +lim_send_assoc_rsp_mgmt_frame(tpAniSirGlobal mac_ctx, + uint16_t status_code, uint16_t aid, tSirMacAddr peer_addr, + uint8_t subtype, tpDphHashNode sta, tpPESession pe_session) +{ + static tDot11fAssocResponse frm; + uint8_t *frame; + tpSirMacMgmtHdr mac_hdr; + tSirRetStatus sir_status; + uint8_t lle_mode = 0, addts; + tHalBitVal qos_mode, wme_mode; + uint32_t payload, bytes = 0, status; + void *packet; + QDF_STATUS qdf_status; + tUpdateBeaconParams beacon_params; + uint8_t tx_flag = 0; + uint32_t addn_ie_len = 0; + uint8_t add_ie[WNI_CFG_ASSOC_RSP_ADDNIE_DATA_LEN]; + tpSirAssocReq assoc_req = NULL; + uint8_t sme_session = 0; + bool is_vht = false; + uint16_t stripoff_len = 0; + tDot11fIEExtCap extracted_ext_cap; + bool extracted_flag = false; +#ifdef WLAN_FEATURE_11W + uint32_t retry_int; + uint32_t max_retries; +#endif + + if (NULL == pe_session) { + lim_log(mac_ctx, LOGE, FL("pe_session is NULL")); + return; + } + + sme_session = pe_session->smeSessionId; + + qdf_mem_set((uint8_t *) &frm, sizeof(frm), 0); + + limGetQosMode(pe_session, &qos_mode); + limGetWmeMode(pe_session, &wme_mode); + + /* + * An Add TS IE is added only if the AP supports it and + * the requesting STA sent a traffic spec. + */ + addts = (qos_mode && sta && sta->qos.addtsPresent) ? 1 : 0; + + frm.Status.status = status_code; + + frm.AID.associd = aid | LIM_AID_MASK; + + if (NULL == sta) { + populate_dot11f_supp_rates(mac_ctx, + POPULATE_DOT11F_RATES_OPERATIONAL, + &frm.SuppRates, pe_session); + populate_dot11f_ext_supp_rates(mac_ctx, + POPULATE_DOT11F_RATES_OPERATIONAL, + &frm.ExtSuppRates, pe_session); + } else { + populate_dot11f_assoc_rsp_rates(mac_ctx, &frm.SuppRates, + &frm.ExtSuppRates, + sta->supportedRates.llbRates, + sta->supportedRates.llaRates); + } + + if (LIM_IS_AP_ROLE(pe_session) && sta != NULL && + eSIR_SUCCESS == status_code) { + assoc_req = (tpSirAssocReq) + pe_session->parsedAssocReq[sta->assocId]; + /* + * populate P2P IE in AssocRsp when assocReq from the peer + * includes P2P IE + */ + if (assoc_req != NULL && assoc_req->addIEPresent) + populate_dot11_assoc_res_p2p_ie(mac_ctx, + &frm.P2PAssocRes, + assoc_req); + } + + if (NULL != sta) { + if (eHAL_SET == qos_mode) { + if (sta->lleEnabled) { + lle_mode = 1; + populate_dot11f_edca_param_set(mac_ctx, + &frm.EDCAParamSet, pe_session); + } + } + + if ((!lle_mode) && (eHAL_SET == wme_mode) && sta->wmeEnabled) { + populate_dot11f_wmm_params(mac_ctx, &frm.WMMParams, + pe_session); + + if (sta->wsmEnabled) + populate_dot11f_wmm_caps(&frm.WMMCaps); + } + + if (sta->mlmStaContext.htCapability && + pe_session->htCapability) { + lim_log(mac_ctx, LOG1, + FL("Populate HT IEs in Assoc Response")); + populate_dot11f_ht_caps(mac_ctx, pe_session, + &frm.HTCaps); + /* + * Check the STA capability and + * update the HTCaps accordingly + */ + frm.HTCaps.supportedChannelWidthSet = ( + sta->htSupportedChannelWidthSet < + pe_session->htSupportedChannelWidthSet) ? + sta->htSupportedChannelWidthSet : + pe_session->htSupportedChannelWidthSet; + if (!frm.HTCaps.supportedChannelWidthSet) + frm.HTCaps.shortGI40MHz = 0; + + populate_dot11f_ht_info(mac_ctx, &frm.HTInfo, + pe_session); + } + lim_log(mac_ctx, LOG1, + FL("SupportedChnlWidth: %d, mimoPS: %d, GF: %d, short GI20:%d, shortGI40: %d, dsssCck: %d, AMPDU Param: %x"), + frm.HTCaps.supportedChannelWidthSet, + frm.HTCaps.mimoPowerSave, + frm.HTCaps.greenField, frm.HTCaps.shortGI20MHz, + frm.HTCaps.shortGI40MHz, + frm.HTCaps.dsssCckMode40MHz, + frm.HTCaps.maxRxAMPDUFactor); + + if (sta->mlmStaContext.vhtCapability && + pe_session->vhtCapability) { + lim_log(mac_ctx, LOG1, + FL("Populate VHT IEs in Assoc Response")); + populate_dot11f_vht_caps(mac_ctx, pe_session, + &frm.VHTCaps); + populate_dot11f_vht_operation(mac_ctx, pe_session, + &frm.VHTOperation); + is_vht = true; + } else { + /* + * 2G-AS platform: SAP associates with HT (11n)clients + * as 2x1 in 2G and 2X2 in 5G + * Non-2G-AS platform: SAP associates with HT (11n) + * clients as 2X2 in 2G and 5G + * 5G-AS: Don’t care + */ + if (frm.HTCaps.present && mac_ctx->hw_dbs_capable && + mac_ctx->lteCoexAntShare && + IS_24G_CH(pe_session->currentOperChannel)) + frm.HTCaps.supportedMCSSet[1] = 0; + } + if (pe_session->vhtCapability && + pe_session->vendor_vht_sap && + (assoc_req != NULL) && + assoc_req->vendor_vht_ie.VHTCaps.present) { + lim_log(mac_ctx, LOG1, + FL("Populate Vendor VHT IEs in Assoc Rsponse")); + frm.vendor_vht_ie.present = 1; + frm.vendor_vht_ie.type = + pe_session->vendor_specific_vht_ie_type; + frm.vendor_vht_ie.sub_type = + pe_session->vendor_specific_vht_ie_sub_type; + + frm.vendor_vht_ie.VHTCaps.present = 1; + populate_dot11f_vht_caps(mac_ctx, pe_session, + &frm.vendor_vht_ie.VHTCaps); + is_vht = true; + } + populate_dot11f_ext_cap(mac_ctx, is_vht, &frm.ExtCap, + pe_session); + +#ifdef WLAN_FEATURE_11W + if (eSIR_MAC_TRY_AGAIN_LATER == status_code) { + if (wlan_cfg_get_int + (mac_ctx, WNI_CFG_PMF_SA_QUERY_MAX_RETRIES, + &max_retries) != eSIR_SUCCESS) + lim_log(mac_ctx, LOGE, + FL("get WNI_CFG_PMF_SA_QUERY_MAX_RETRIES failure")); + else if (wlan_cfg_get_int + (mac_ctx, + WNI_CFG_PMF_SA_QUERY_RETRY_INTERVAL, + &retry_int) != eSIR_SUCCESS) + lim_log(mac_ctx, LOGE, + FL("get WNI_CFG_PMF_SA_QUERY_RETRY_INTERVAL failure")); + else + populate_dot11f_timeout_interval(mac_ctx, + &frm.TimeoutInterval, + SIR_MAC_TI_TYPE_ASSOC_COMEBACK, + (max_retries - + sta->pmfSaQueryRetryCount) + * retry_int); + } +#endif + } + + qdf_mem_set((uint8_t *) &beacon_params, sizeof(beacon_params), 0); + + if (LIM_IS_AP_ROLE(pe_session) && + (pe_session->gLimProtectionControl != + WNI_CFG_FORCE_POLICY_PROTECTION_DISABLE)) + lim_decide_ap_protection(mac_ctx, peer_addr, + &beacon_params, pe_session); + + lim_update_short_preamble(mac_ctx, peer_addr, &beacon_params, + pe_session); + lim_update_short_slot_time(mac_ctx, peer_addr, &beacon_params, + pe_session); + + /* + * Populate Do11capabilities after updating session with + * Assos req details + */ + populate_dot11f_capabilities(mac_ctx, &frm.Capabilities, pe_session); + + beacon_params.bssIdx = pe_session->bssIdx; + + /* Send message to HAL about beacon parameter change. */ + if ((false == mac_ctx->sap.SapDfsInfo.is_dfs_cac_timer_running) + && beacon_params.paramChangeBitmap) { + sch_set_fixed_beacon_fields(mac_ctx, pe_session); + lim_send_beacon_params(mac_ctx, &beacon_params, pe_session); + } + + if (assoc_req != NULL) { + addn_ie_len = pe_session->addIeParams.assocRespDataLen; + + /* Nonzero length indicates Assoc rsp IE available */ + if (addn_ie_len > 0 && + addn_ie_len <= WNI_CFG_ASSOC_RSP_ADDNIE_DATA_LEN && + (bytes + addn_ie_len) <= SIR_MAX_PACKET_SIZE) { + qdf_mem_copy(add_ie, + pe_session->addIeParams.assocRespData_buff, + pe_session->addIeParams.assocRespDataLen); + + qdf_mem_set((uint8_t *) &extracted_ext_cap, + sizeof(extracted_ext_cap), 0); + + stripoff_len = addn_ie_len; + sir_status = + lim_strip_extcap_update_struct + (mac_ctx, &add_ie[0], &stripoff_len, + &extracted_ext_cap); + if (eSIR_SUCCESS != sir_status) { + lim_log(mac_ctx, LOG1, + FL("strip off extcap IE failed")); + } else { + addn_ie_len = stripoff_len; + extracted_flag = true; + } + bytes = bytes + addn_ie_len; + } + lim_log(mac_ctx, LOG1, + FL("addn_ie_len = %d for Assoc Resp : %d"), + addn_ie_len, assoc_req->addIEPresent); + } + + /* + * Extcap IE now support variable length, merge Extcap IE from addn_ie + * may change the frame size. Therefore, MUST merge ExtCap IE before + * dot11f get packed payload size. + */ + if (extracted_flag) + lim_merge_extcap_struct(&(frm.ExtCap), &extracted_ext_cap, + true); + + /* Allocate a buffer for this frame: */ + status = dot11f_get_packed_assoc_response_size(mac_ctx, &frm, &payload); + if (DOT11F_FAILED(status)) { + lim_log(mac_ctx, LOGE, + FL("get Association Response size failure (0x%08x)."), + status); + return; + } else if (DOT11F_WARNED(status)) { + lim_log(mac_ctx, LOGW, + FL("get Association Response size warning (0x%08x)."), + status); + } + + bytes += sizeof(tSirMacMgmtHdr) + payload; + + qdf_status = cds_packet_alloc((uint16_t) bytes, (void **)&frame, + (void **)&packet); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + lim_log(mac_ctx, LOGP, FL("cds_packet_alloc failed.")); + return; + } + /* Paranoia: */ + qdf_mem_set(frame, bytes, 0); + + /* Next, we fill out the buffer descriptor: */ + lim_populate_mac_header(mac_ctx, frame, SIR_MAC_MGMT_FRAME, + (LIM_ASSOC == subtype) ? + SIR_MAC_MGMT_ASSOC_RSP : SIR_MAC_MGMT_REASSOC_RSP, + peer_addr, + pe_session->selfMacAddr); + mac_hdr = (tpSirMacMgmtHdr) frame; + + sir_copy_mac_addr(mac_hdr->bssId, pe_session->bssId); + + status = dot11f_pack_assoc_response(mac_ctx, &frm, + frame + sizeof(tSirMacMgmtHdr), + payload, &payload); + if (DOT11F_FAILED(status)) { + lim_log(mac_ctx, LOGE, + FL("Association Response pack failure(0x%08x)."), + status); + cds_packet_free((void *)packet); + return; + } else if (DOT11F_WARNED(status)) { + lim_log(mac_ctx, LOGW, + FL("Association Response pack warning (0x%08x)."), + status); + } + + if (subtype == LIM_ASSOC) + lim_log(mac_ctx, LOG1, + FL("*** Sending Assoc Resp status %d aid %d to "), + status_code, aid); + else + lim_log(mac_ctx, LOG1, + FL("*** Sending ReAssoc Resp status %d aid %d to "), + status_code, aid); + + lim_print_mac_addr(mac_ctx, mac_hdr->da, LOG1); + + if (addn_ie_len && addn_ie_len <= WNI_CFG_ASSOC_RSP_ADDNIE_DATA_LEN) + qdf_mem_copy(frame + sizeof(tSirMacMgmtHdr) + payload, + &add_ie[0], addn_ie_len); + + if ((SIR_BAND_5_GHZ == + lim_get_rf_band(pe_session->currentOperChannel)) || + (pe_session->pePersona == QDF_P2P_CLIENT_MODE) || + (pe_session->pePersona == QDF_P2P_GO_MODE)) + tx_flag |= HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME; + + MTRACE(qdf_trace(QDF_MODULE_ID_PE, TRACE_CODE_TX_MGMT, + pe_session->peSessionId, mac_hdr->fc.subType)); + /* Queue Association Response frame in high priority WQ */ + qdf_status = wma_tx_frame(mac_ctx, packet, (uint16_t) bytes, + TXRX_FRM_802_11_MGMT, + ANI_TXDIR_TODS, + 7, lim_tx_complete, frame, tx_flag, + sme_session, 0); + MTRACE(qdf_trace(QDF_MODULE_ID_PE, TRACE_CODE_TX_COMPLETE, + pe_session->peSessionId, qdf_status)); + + /* Pkt will be freed up by the callback */ + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) + lim_log(mac_ctx, LOGE, + FL("*** Could not Send Re/AssocRsp, retCode=%X ***"), + qdf_status); + + /* + * update the ANI peer station count. + * FIXME_PROTECTION : take care of different type of station + * counter inside this function. + */ + lim_util_count_sta_add(mac_ctx, sta, pe_session); + +} + +void +lim_send_delts_req_action_frame(tpAniSirGlobal pMac, + tSirMacAddr peer, + uint8_t wmmTspecPresent, + tSirMacTSInfo *pTsinfo, + tSirMacTspecIE *pTspecIe, tpPESession psessionEntry) +{ + uint8_t *pFrame; + tpSirMacMgmtHdr pMacHdr; + tDot11fDelTS DelTS; + tDot11fWMMDelTS WMMDelTS; + uint32_t nBytes, nPayload, nStatus; + void *pPacket; + QDF_STATUS qdf_status; + uint8_t txFlag = 0; + uint8_t smeSessionId = 0; + + if (NULL == psessionEntry) { + return; + } + + smeSessionId = psessionEntry->smeSessionId; + + if (!wmmTspecPresent) { + qdf_mem_set((uint8_t *) &DelTS, sizeof(DelTS), 0); + + DelTS.Category.category = SIR_MAC_ACTION_QOS_MGMT; + DelTS.Action.action = SIR_MAC_QOS_DEL_TS_REQ; + populate_dot11f_ts_info(pTsinfo, &DelTS.TSInfo); + + nStatus = dot11f_get_packed_del_ts_size(pMac, &DelTS, &nPayload); + if (DOT11F_FAILED(nStatus)) { + lim_log(pMac, LOGP, + FL("Failed to calculate the packed si" + "ze for a Del TS (0x%08x)."), nStatus); + /* We'll fall back on the worst case scenario: */ + nPayload = sizeof(tDot11fDelTS); + } else if (DOT11F_WARNED(nStatus)) { + lim_log(pMac, LOGW, + FL("There were warnings while calcula" + "ting the packed size for a Del TS" + " (0x%08x)."), nStatus); + } + } else { + qdf_mem_set((uint8_t *) &WMMDelTS, sizeof(WMMDelTS), 0); + + WMMDelTS.Category.category = SIR_MAC_ACTION_WME; + WMMDelTS.Action.action = SIR_MAC_QOS_DEL_TS_REQ; + WMMDelTS.DialogToken.token = 0; + WMMDelTS.StatusCode.statusCode = 0; + populate_dot11f_wmmtspec(pTspecIe, &WMMDelTS.WMMTSPEC); + nStatus = + dot11f_get_packed_wmm_del_ts_size(pMac, &WMMDelTS, &nPayload); + if (DOT11F_FAILED(nStatus)) { + lim_log(pMac, LOGP, + FL("Failed to calculate the packed si" + "ze for a WMM Del TS (0x%08x)."), nStatus); + /* We'll fall back on the worst case scenario: */ + nPayload = sizeof(tDot11fDelTS); + } else if (DOT11F_WARNED(nStatus)) { + lim_log(pMac, LOGW, + FL("There were warnings while calcula" + "ting the packed size for a WMM De" + "l TS (0x%08x)."), nStatus); + } + } + + nBytes = nPayload + sizeof(tSirMacMgmtHdr); + + qdf_status = + cds_packet_alloc((uint16_t) nBytes, (void **)&pFrame, + (void **)&pPacket); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + lim_log(pMac, LOGP, FL("Failed to allocate %d bytes for an Ad" + "d TS Response."), nBytes); + return; + } + /* Paranoia: */ + qdf_mem_set(pFrame, nBytes, 0); + + /* Next, we fill out the buffer descriptor: */ + lim_populate_mac_header(pMac, pFrame, SIR_MAC_MGMT_FRAME, + SIR_MAC_MGMT_ACTION, peer, psessionEntry->selfMacAddr); + pMacHdr = (tpSirMacMgmtHdr) pFrame; + + sir_copy_mac_addr(pMacHdr->bssId, psessionEntry->bssId); + +#ifdef WLAN_FEATURE_11W + lim_set_protected_bit(pMac, psessionEntry, peer, pMacHdr); +#endif + + /* That done, pack the struct: */ + if (!wmmTspecPresent) { + nStatus = dot11f_pack_del_ts(pMac, &DelTS, + pFrame + sizeof(tSirMacMgmtHdr), + nPayload, &nPayload); + if (DOT11F_FAILED(nStatus)) { + lim_log(pMac, LOGE, + FL("Failed to pack a Del TS frame (0x%08x)."), + nStatus); + cds_packet_free((void *)pPacket); + return; /* allocated! */ + } else if (DOT11F_WARNED(nStatus)) { + lim_log(pMac, LOGW, + FL("There were warnings while packing " + "a Del TS frame (0x%08x)."), nStatus); + } + } else { + nStatus = dot11f_pack_wmm_del_ts(pMac, &WMMDelTS, + pFrame + sizeof(tSirMacMgmtHdr), + nPayload, &nPayload); + if (DOT11F_FAILED(nStatus)) { + lim_log(pMac, LOGE, + FL + ("Failed to pack a WMM Del TS frame (0x%08x)."), + nStatus); + cds_packet_free((void *)pPacket); + return; /* allocated! */ + } else if (DOT11F_WARNED(nStatus)) { + lim_log(pMac, LOGW, + FL("There were warnings while packing " + "a WMM Del TS frame (0x%08x)."), nStatus); + } + } + + PELOG1(lim_log + (pMac, LOG1, FL("Sending DELTS REQ (size %d) to "), nBytes); + lim_print_mac_addr(pMac, pMacHdr->da, LOG1); + ) + + if ((SIR_BAND_5_GHZ == + lim_get_rf_band(psessionEntry->currentOperChannel)) + || (psessionEntry->pePersona == QDF_P2P_CLIENT_MODE) + || (psessionEntry->pePersona == QDF_P2P_GO_MODE) + ) { + txFlag |= HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME; + } + + MTRACE(qdf_trace(QDF_MODULE_ID_PE, TRACE_CODE_TX_MGMT, + psessionEntry->peSessionId, pMacHdr->fc.subType)); + qdf_status = wma_tx_frame(pMac, pPacket, (uint16_t) nBytes, + TXRX_FRM_802_11_MGMT, + ANI_TXDIR_TODS, + 7, lim_tx_complete, pFrame, txFlag, + smeSessionId, 0); + MTRACE(qdf_trace(QDF_MODULE_ID_PE, TRACE_CODE_TX_COMPLETE, + psessionEntry->peSessionId, qdf_status)); + /* Pkt will be freed up by the callback */ + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) + lim_log(pMac, LOGE, FL("Failed to send Del TS (%X)!"), + qdf_status); + +} /* End lim_send_delts_req_action_frame. */ + +/** + * lim_assoc_tx_complete_cnf()- Confirmation for assoc sent over the air + * + * @mac_ctx: pointer to global mac + * @tx_complete : Sent status + * + * Return: This returns QDF_STATUS + */ + +static QDF_STATUS lim_assoc_tx_complete_cnf(tpAniSirGlobal mac_ctx, + uint32_t tx_complete) +{ + uint16_t assoc_ack_status; + uint16_t reason_code; + + lim_log(mac_ctx, LOG1, + FL("tx_complete= %d"), tx_complete); + if (tx_complete) { + assoc_ack_status = ACKED; + reason_code = eSIR_SUCCESS; + } else { + assoc_ack_status = NOT_ACKED; + reason_code = eSIR_FAILURE; + } + + lim_diag_event_report(mac_ctx, WLAN_PE_DIAG_ASSOC_ACK_EVENT, + NULL, assoc_ack_status, reason_code); + return QDF_STATUS_SUCCESS; +} + +/** + * lim_send_assoc_req_mgmt_frame() - Send association request + * @mac_ctx: Handle to MAC context + * @mlm_assoc_req: Association request information + * @pe_session: PE session information + * + * Builds and transmits association request frame to AP. + * + * Return: Void + */ + +void +lim_send_assoc_req_mgmt_frame(tpAniSirGlobal mac_ctx, + tLimMlmAssocReq *mlm_assoc_req, + tpPESession pe_session) +{ + tDot11fAssocRequest *frm; + uint16_t caps; + uint8_t *frame; + tSirRetStatus sir_status; + tLimMlmAssocCnf assoc_cnf; + uint32_t bytes = 0, payload, status; + uint8_t qos_enabled, wme_enabled, wsm_enabled; + void *packet; + QDF_STATUS qdf_status; + uint16_t add_ie_len, assoc_ack_status; + uint8_t *add_ie; + uint8_t *wps_ie = NULL; + uint8_t power_caps = false; + uint8_t tx_flag = 0; + uint8_t sme_sessionid = 0; + bool vht_enabled = false; + tDot11fIEExtCap extr_ext_cap; + bool extr_ext_flag = true; + tpSirMacMgmtHdr mac_hdr; + uint32_t ie_offset = 0; + uint8_t *p_ext_cap = NULL; + tDot11fIEExtCap bcn_ext_cap; + uint8_t *bcn_ie = NULL; + uint32_t bcn_ie_len = 0; + + if (NULL == pe_session) { + lim_log(mac_ctx, LOGE, FL("pe_session is NULL")); + return; + } + + sme_sessionid = pe_session->smeSessionId; + + /* check this early to avoid unncessary operation */ + if (NULL == pe_session->pLimJoinReq) { + lim_log(mac_ctx, LOGE, FL("pe_session->pLimJoinReq is NULL")); + return; + } + add_ie_len = pe_session->pLimJoinReq->addIEAssoc.length; + add_ie = pe_session->pLimJoinReq->addIEAssoc.addIEdata; + + frm = qdf_mem_malloc(sizeof(tDot11fAssocRequest)); + if (NULL == frm) { + lim_log(mac_ctx, LOGE, FL("Unable to allocate memory")); + return; + } + qdf_mem_set((uint8_t *) frm, sizeof(tDot11fAssocRequest), 0); + + if (add_ie_len && pe_session->is_ext_caps_present) { + qdf_mem_set((uint8_t *) &extr_ext_cap, sizeof(tDot11fIEExtCap), + 0); + sir_status = lim_strip_extcap_update_struct(mac_ctx, + add_ie, &add_ie_len, &extr_ext_cap); + if (eSIR_SUCCESS != sir_status) { + extr_ext_flag = false; + lim_log(mac_ctx, LOG1, + FL("Unable to Stripoff ExtCap IE from Assoc Req")); + } else { + struct s_ext_cap *p_ext_cap = (struct s_ext_cap *) + extr_ext_cap.bytes; + + if (p_ext_cap->interworking_service) + p_ext_cap->qos_map = 1; + extr_ext_cap.num_bytes = + lim_compute_ext_cap_ie_length(&extr_ext_cap); + extr_ext_flag = (extr_ext_cap.num_bytes > 0); + } + } else { + lim_log(mac_ctx, LOG1, + FL("No addn IE or peer dosen't support addnIE for Assoc Req")); + extr_ext_flag = false; + } + + caps = mlm_assoc_req->capabilityInfo; +#if defined(FEATURE_WLAN_WAPI) + /* + * According to WAPI standard: + * 7.3.1.4 Capability Information field + * In WAPI, non-AP STAs within an ESS set the Privacy subfield to 0 + * in transmitted Association or Reassociation management frames. + * APs ignore the Privacy subfield within received Association and + * Reassociation management frames. + */ + if (pe_session->encryptType == eSIR_ED_WPI) + ((tSirMacCapabilityInfo *) &caps)->privacy = 0; +#endif + swap_bit_field16(caps, (uint16_t *) &frm->Capabilities); + + frm->ListenInterval.interval = mlm_assoc_req->listenInterval; + populate_dot11f_ssid2(mac_ctx, &frm->SSID); + populate_dot11f_supp_rates(mac_ctx, POPULATE_DOT11F_RATES_OPERATIONAL, + &frm->SuppRates, pe_session); + + qos_enabled = (pe_session->limQosEnabled) && + SIR_MAC_GET_QOS(pe_session->limCurrentBssCaps); + + wme_enabled = (pe_session->limWmeEnabled) && + LIM_BSS_CAPS_GET(WME, pe_session->limCurrentBssQosCaps); + + /* We prefer .11e asociations: */ + if (qos_enabled) + wme_enabled = false; + + wsm_enabled = (pe_session->limWsmEnabled) && wme_enabled && + LIM_BSS_CAPS_GET(WSM, pe_session->limCurrentBssQosCaps); + + if (pe_session->lim11hEnable && + pe_session->pLimJoinReq->spectrumMgtIndicator == eSIR_TRUE) { + power_caps = true; + + populate_dot11f_power_caps(mac_ctx, &frm->PowerCaps, + LIM_ASSOC, pe_session); + populate_dot11f_supp_channels(mac_ctx, &frm->SuppChannels, + LIM_ASSOC, pe_session); + + } + if (mac_ctx->rrm.rrmPEContext.rrmEnable && + SIR_MAC_GET_RRM(pe_session->limCurrentBssCaps)) { + if (power_caps == false) { + power_caps = true; + populate_dot11f_power_caps(mac_ctx, &frm->PowerCaps, + LIM_ASSOC, pe_session); + } + } + if (qos_enabled) + populate_dot11f_qos_caps_station(mac_ctx, pe_session, + &frm->QOSCapsStation); + + populate_dot11f_ext_supp_rates(mac_ctx, + POPULATE_DOT11F_RATES_OPERATIONAL, &frm->ExtSuppRates, + pe_session); + + if (mac_ctx->rrm.rrmPEContext.rrmEnable && + SIR_MAC_GET_RRM(pe_session->limCurrentBssCaps)) + populate_dot11f_rrm_ie(mac_ctx, &frm->RRMEnabledCap, + pe_session); + + /* + * The join request *should* contain zero or one of the WPA and RSN + * IEs. The payload send along with the request is a + * 'tSirSmeJoinReq'; the IE portion is held inside a 'tSirRSNie': + * typedef struct sSirRSNie + * { + * uint16_t length; + * uint8_t rsnIEdata[SIR_MAC_MAX_IE_LENGTH+2]; + * } tSirRSNie, *tpSirRSNie; + * So, we should be able to make the following two calls harmlessly, + * since they do nothing if they don't find the given IE in the + * bytestream with which they're provided. + * The net effect of this will be to faithfully transmit whatever + * security IE is in the join request. + * However, if we're associating for the purpose of WPS + * enrollment, and we've been configured to indicate that by + * eliding the WPA or RSN IE, we just skip this: + */ + if (add_ie_len && add_ie) + wps_ie = limGetWscIEPtr(mac_ctx, add_ie, add_ie_len); + + if (NULL == wps_ie) { + populate_dot11f_rsn_opaque(mac_ctx, + &(pe_session->pLimJoinReq->rsnIE), + &frm->RSNOpaque); + populate_dot11f_wpa_opaque(mac_ctx, + &(pe_session->pLimJoinReq->rsnIE), + &frm->WPAOpaque); +#if defined(FEATURE_WLAN_WAPI) + populate_dot11f_wapi_opaque(mac_ctx, + &(pe_session->pLimJoinReq->rsnIE), + &frm->WAPIOpaque); +#endif /* defined(FEATURE_WLAN_WAPI) */ + } + /* include WME EDCA IE as well */ + if (wme_enabled) { + populate_dot11f_wmm_info_station_per_session(mac_ctx, + pe_session, &frm->WMMInfoStation); + + if (wsm_enabled) + populate_dot11f_wmm_caps(&frm->WMMCaps); + } + + /* + * Populate HT IEs, when operating in 11n and + * when AP is also operating in 11n mode + */ + if (pe_session->htCapability && + mac_ctx->lim.htCapabilityPresentInBeacon) { + lim_log(mac_ctx, LOG1, FL("Populate HT Caps in Assoc Request")); + populate_dot11f_ht_caps(mac_ctx, pe_session, &frm->HTCaps); + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_DEBUG, + &frm->HTCaps, sizeof(frm->HTCaps)); + } + lim_log(mac_ctx, LOG1, + FL("SupportedChnlWidth: %d, mimoPS: %d, GF: %d, short GI20:%d, shortGI40: %d, dsssCck: %d, AMPDU Param: %x"), + frm->HTCaps.supportedChannelWidthSet, + frm->HTCaps.mimoPowerSave, + frm->HTCaps.greenField, frm->HTCaps.shortGI20MHz, + frm->HTCaps.shortGI40MHz, + frm->HTCaps.dsssCckMode40MHz, + frm->HTCaps.maxRxAMPDUFactor); + + if (pe_session->vhtCapability && + pe_session->vhtCapabilityPresentInBeacon) { + lim_log(mac_ctx, LOG1, FL("Populate VHT IEs in Assoc Request")); + populate_dot11f_vht_caps(mac_ctx, pe_session, &frm->VHTCaps); + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_DEBUG, + &frm->VHTCaps, sizeof(frm->VHTCaps)); + vht_enabled = true; + if (pe_session->enableHtSmps && + !pe_session->supported_nss_1x1) { + lim_log(mac_ctx, LOGE, FL( + "VHT OP mode IE in Assoc Req")); + populate_dot11f_operating_mode(mac_ctx, + &frm->OperatingMode, pe_session); + } + } + if (!vht_enabled && + pe_session->is_vendor_specific_vhtcaps) { + lim_log(mac_ctx, LOG1, + FL("Populate Vendor VHT IEs in Assoc Request")); + frm->vendor_vht_ie.present = 1; + frm->vendor_vht_ie.type = + pe_session->vendor_specific_vht_ie_type; + frm->vendor_vht_ie.sub_type = + pe_session->vendor_specific_vht_ie_sub_type; + + frm->vendor_vht_ie.VHTCaps.present = 1; + pe_session->vht_config.su_beam_formee = 0; + populate_dot11f_vht_caps(mac_ctx, pe_session, + &frm->vendor_vht_ie.VHTCaps); + vht_enabled = true; + } + if (pe_session->is_ext_caps_present) + populate_dot11f_ext_cap(mac_ctx, vht_enabled, + &frm->ExtCap, pe_session); + + if (mac_ctx->roam.configParam.qcn_ie_support) + populate_dot11f_qcn_ie(&frm->QCN_IE); + + if (pe_session->pLimJoinReq->is11Rconnection) { + tSirBssDescription *bssdescr; + + bssdescr = &pe_session->pLimJoinReq->bssDescription; + lim_log(mac_ctx, LOG1, FL("mdie = %02x %02x %02x"), + (unsigned int) bssdescr->mdie[0], + (unsigned int) bssdescr->mdie[1], + (unsigned int) bssdescr->mdie[2]); + populate_mdie(mac_ctx, &frm->MobilityDomain, + pe_session->pLimJoinReq->bssDescription.mdie); + } else { + /* No 11r IEs dont send any MDIE */ + lim_log(mac_ctx, LOG1, FL("MDIE not present")); + } + +#ifdef FEATURE_WLAN_ESE + /* + * ESE Version IE will be included in association request + * when ESE is enabled on DUT through ini and it is also + * advertised by the peer AP to which we are trying to + * associate to. + */ + if (pe_session->is_ese_version_ie_present && + mac_ctx->roam.configParam.isEseIniFeatureEnabled) + populate_dot11f_ese_version(&frm->ESEVersion); + /* For ESE Associations fill the ESE IEs */ + if (pe_session->isESEconnection && + pe_session->pLimJoinReq->isESEFeatureIniEnabled) { +#ifndef FEATURE_DISABLE_RM + populate_dot11f_ese_rad_mgmt_cap(&frm->ESERadMgmtCap); +#endif + } +#endif + + /* + * Extcap IE now support variable length, merge Extcap IE from addn_ie + * may change the frame size. Therefore, MUST merge ExtCap IE before + * dot11f get packed payload size. + */ + if (extr_ext_flag) + lim_merge_extcap_struct(&frm->ExtCap, &extr_ext_cap, true); + + /* Clear the bits in EXTCAP IE if AP not advertise it in beacon */ + if (frm->ExtCap.present && pe_session->is_ext_caps_present) { + ie_offset = DOT11F_FF_TIMESTAMP_LEN + + DOT11F_FF_BEACONINTERVAL_LEN + + DOT11F_FF_CAPABILITIES_LEN; + + qdf_mem_zero((uint8_t *)&bcn_ext_cap, sizeof(tDot11fIEExtCap)); + if (pe_session->beacon && pe_session->bcnLen > ie_offset) { + bcn_ie = pe_session->beacon + ie_offset; + bcn_ie_len = pe_session->bcnLen - ie_offset; + p_ext_cap = lim_get_ie_ptr_new(mac_ctx, + bcn_ie, + bcn_ie_len, + DOT11F_EID_EXTCAP, + ONE_BYTE); + lim_update_extcap_struct(mac_ctx, p_ext_cap, + &bcn_ext_cap); + lim_merge_extcap_struct(&frm->ExtCap, &bcn_ext_cap, + false); + } + } + + if (eSIR_SUCCESS != lim_strip_supp_op_class_update_struct(mac_ctx, + add_ie, &add_ie_len, &frm->SuppOperatingClasses)) + lim_log(mac_ctx, LOG1, + FL("Unable to Stripoff supp op classes IE from Assoc Req")); + + status = dot11f_get_packed_assoc_request_size(mac_ctx, frm, &payload); + if (DOT11F_FAILED(status)) { + lim_log(mac_ctx, LOGP, + FL("Association Request packet size failure(0x%08x)."), + status); + /* We'll fall back on the worst case scenario: */ + payload = sizeof(tDot11fAssocRequest); + } else if (DOT11F_WARNED(status)) { + lim_log(mac_ctx, LOGW, + FL("Association request packet size warning (0x%08x)."), + status); + } + + bytes = payload + sizeof(tSirMacMgmtHdr) + add_ie_len; + + qdf_status = cds_packet_alloc((uint16_t) bytes, (void **)&frame, + (void **)&packet); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + lim_log(mac_ctx, LOGP, FL("Failed to allocate %d bytes."), + bytes); + + pe_session->limMlmState = pe_session->limPrevMlmState; + MTRACE(qdf_trace(QDF_MODULE_ID_PE, TRACE_CODE_MLM_STATE, + pe_session->peSessionId, + pe_session->limMlmState)); + + /* Update PE session id */ + assoc_cnf.sessionId = pe_session->peSessionId; + + assoc_cnf.resultCode = eSIR_SME_RESOURCES_UNAVAILABLE; + + cds_packet_free((void *)packet); + + lim_post_sme_message(mac_ctx, LIM_MLM_ASSOC_CNF, + (uint32_t *) &assoc_cnf); + + qdf_mem_free(frm); + return; + } + /* Paranoia: */ + qdf_mem_set(frame, bytes, 0); + + /* Next, we fill out the buffer descriptor: */ + lim_populate_mac_header(mac_ctx, frame, SIR_MAC_MGMT_FRAME, + SIR_MAC_MGMT_ASSOC_REQ, pe_session->bssId, + pe_session->selfMacAddr); + /* That done, pack the Assoc Request: */ + status = dot11f_pack_assoc_request(mac_ctx, frm, + frame + sizeof(tSirMacMgmtHdr), payload, &payload); + if (DOT11F_FAILED(status)) { + lim_log(mac_ctx, LOGE, + FL("Assoc request pack failure (0x%08x)"), status); + cds_packet_free((void *)packet); + qdf_mem_free(frm); + return; + } else if (DOT11F_WARNED(status)) { + lim_log(mac_ctx, LOGW, + FL("Assoc request pack warning (0x%08x)"), status); + } + + lim_log(mac_ctx, LOG1, + FL("*** Sending Association Request length %d to "), bytes); + if (pe_session->assocReq != NULL) { + qdf_mem_free(pe_session->assocReq); + pe_session->assocReq = NULL; + pe_session->assocReqLen = 0; + } + + if (add_ie_len) { + qdf_mem_copy(frame + sizeof(tSirMacMgmtHdr) + payload, + add_ie, add_ie_len); + payload += add_ie_len; + } + + pe_session->assocReq = qdf_mem_malloc(payload); + if (NULL == pe_session->assocReq) { + lim_log(mac_ctx, LOGE, FL("Unable to allocate memory")); + } else { + /* + * Store the Assoc request. This is sent to csr/hdd in + * join cnf response. + */ + qdf_mem_copy(pe_session->assocReq, + frame + sizeof(tSirMacMgmtHdr), payload); + pe_session->assocReqLen = payload; + } + + if ((SIR_BAND_5_GHZ == lim_get_rf_band(pe_session->currentOperChannel)) + || (pe_session->pePersona == QDF_P2P_CLIENT_MODE) + || (pe_session->pePersona == QDF_P2P_GO_MODE) + ) + tx_flag |= HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME; + + if (pe_session->pePersona == QDF_P2P_CLIENT_MODE || + pe_session->pePersona == QDF_STA_MODE) + tx_flag |= HAL_USE_PEER_STA_REQUESTED_MASK; + +#ifdef FEATURE_WLAN_DIAG_SUPPORT + lim_diag_event_report(mac_ctx, WLAN_PE_DIAG_ASSOC_START_EVENT, + pe_session, eSIR_SUCCESS, eSIR_SUCCESS); +#endif + mac_hdr = (tpSirMacMgmtHdr) frame; + MTRACE(qdf_trace(QDF_MODULE_ID_PE, TRACE_CODE_TX_MGMT, + pe_session->peSessionId, mac_hdr->fc.subType)); + + qdf_status = wma_tx_frameWithTxComplete(mac_ctx, packet, + (uint16_t) (sizeof(tSirMacMgmtHdr) + payload), + TXRX_FRM_802_11_MGMT, ANI_TXDIR_TODS, 7, + lim_tx_complete, frame, + lim_assoc_tx_complete_cnf, + tx_flag, sme_sessionid, false, 0); + MTRACE(qdf_trace(QDF_MODULE_ID_PE, TRACE_CODE_TX_COMPLETE, + pe_session->peSessionId, qdf_status)); + + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + lim_log(mac_ctx, LOGE, + FL("Failed to send Association Request (%X)!"), + qdf_status); + assoc_ack_status = SENT_FAIL; + lim_diag_event_report(mac_ctx, WLAN_PE_DIAG_ASSOC_ACK_EVENT, + pe_session, assoc_ack_status, eSIR_FAILURE); + /* Pkt will be freed up by the callback */ + qdf_mem_free(frm); + return; + } + + /* Free up buffer allocated for mlm_assoc_req */ + qdf_mem_free(mlm_assoc_req); + mlm_assoc_req = NULL; + qdf_mem_free(frm); + return; +} + +/** + * lim_auth_tx_complete_cnf()- Confirmation for auth sent over the air + * + * @mac_ctx: pointer to global mac + * @tx_complete : Sent status + * + * Return: This returns QDF_STATUS + */ + +static QDF_STATUS lim_auth_tx_complete_cnf(tpAniSirGlobal mac_ctx, + uint32_t tx_complete) +{ + uint16_t auth_ack_status; + uint16_t reason_code; + + lim_log(mac_ctx, LOG1, + FL("tx_complete= %d"), tx_complete); + if (tx_complete) { + mac_ctx->auth_ack_status = LIM_AUTH_ACK_RCD_SUCCESS; + auth_ack_status = ACKED; + reason_code = eSIR_SUCCESS; + /* 'Change' timer for future activations */ + lim_deactivate_and_change_timer(mac_ctx, eLIM_AUTH_RETRY_TIMER); + } else { + mac_ctx->auth_ack_status = LIM_AUTH_ACK_RCD_FAILURE; + auth_ack_status = NOT_ACKED; + reason_code = eSIR_FAILURE; + } + + lim_diag_event_report(mac_ctx, WLAN_PE_DIAG_AUTH_ACK_EVENT, + NULL, auth_ack_status, reason_code); + return QDF_STATUS_SUCCESS; +} + +/** + * lim_send_auth_mgmt_frame() - Send an Authentication frame + * + * @mac_ctx: Pointer to Global MAC structure + * @auth_frame: Pointer to Authentication frame structure + * @peer_addr: MAC address of destination peer + * @wep_bit: wep bit in frame control for Authentication frame3 + * @session: PE session information + * + * This function is called by lim_process_mlm_messages(). Authentication frame + * is formatted and sent when this function is called. + * + * Return: void + */ + +void +lim_send_auth_mgmt_frame(tpAniSirGlobal mac_ctx, + tpSirMacAuthFrameBody auth_frame, + tSirMacAddr peer_addr, + uint8_t wep_bit, + tpPESession session) +{ + uint8_t *frame, *body; + uint32_t frame_len = 0, body_len = 0; + tpSirMacMgmtHdr mac_hdr; + void *packet; + QDF_STATUS qdf_status; + uint8_t tx_flag = 0; + uint8_t sme_sessionid = 0; + uint16_t ft_ies_length = 0, auth_ack_status; + + if (NULL == session) { + lim_log(mac_ctx, LOGE, FL("Error: psession Entry is NULL")); + return; + } + + sme_sessionid = session->smeSessionId; + + if (wep_bit == LIM_WEP_IN_FC) { + /* + * Auth frame3 to be sent with encrypted framebody + * + * Allocate buffer for Authenticaton frame of size + * equal to management frame header length plus 2 bytes + * each for auth algorithm number, transaction number, + * status code, 128 bytes for challenge text and + * 4 bytes each for IV & ICV. + */ + lim_log(mac_ctx, LOG1, + FL("Sending encrypted auth frame to " MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(peer_addr)); + + frame_len = sizeof(tSirMacMgmtHdr) + LIM_ENCR_AUTH_BODY_LEN; + body_len = LIM_ENCR_AUTH_BODY_LEN; + + goto alloc_packet; + } + + lim_log(mac_ctx, LOG1, + FL("Sending Auth seq# %d status %d (%d) to " + MAC_ADDRESS_STR), + auth_frame->authTransactionSeqNumber, + auth_frame->authStatusCode, + (auth_frame->authStatusCode == eSIR_MAC_SUCCESS_STATUS), + MAC_ADDR_ARRAY(peer_addr)); + + switch (auth_frame->authTransactionSeqNumber) { + case SIR_MAC_AUTH_FRAME_1: + /* + * Allocate buffer for Authenticaton frame of size + * equal to management frame header length plus 2 bytes + * each for auth algorithm number, transaction number + * and status code. + */ + + frame_len = sizeof(tSirMacMgmtHdr) + + SIR_MAC_AUTH_CHALLENGE_OFFSET; + body_len = SIR_MAC_AUTH_CHALLENGE_OFFSET; + + if (auth_frame->authAlgoNumber == eSIR_FT_AUTH) { + if (NULL != session->ftPEContext.pFTPreAuthReq && + 0 != session->ftPEContext.pFTPreAuthReq-> + ft_ies_length) { + ft_ies_length = session->ftPEContext. + pFTPreAuthReq->ft_ies_length; + frame_len += ft_ies_length; + lim_log(mac_ctx, LOG3, + FL("Auth frame, FTIES length added=%d"), + ft_ies_length); + } else { + lim_log(mac_ctx, LOG3, + FL("Auth frame, Does not contain FTIES!!!")); + frame_len += (2 + SIR_MDIE_SIZE); + } + } + break; + + case SIR_MAC_AUTH_FRAME_2: + if ((auth_frame->authAlgoNumber == eSIR_OPEN_SYSTEM) || + ((auth_frame->authAlgoNumber == eSIR_SHARED_KEY) && + (auth_frame->authStatusCode != + eSIR_MAC_SUCCESS_STATUS))) { + /* + * Allocate buffer for Authenticaton frame of size + * equal to management frame header length plus + * 2 bytes each for auth algorithm number, + * transaction number and status code. + */ + + frame_len = sizeof(tSirMacMgmtHdr) + + SIR_MAC_AUTH_CHALLENGE_OFFSET; + body_len = SIR_MAC_AUTH_CHALLENGE_OFFSET; + } else { + /* + * Shared Key algorithm with challenge text + * to be sent. + * + * Allocate buffer for Authenticaton frame of size + * equal to management frame header length plus + * 2 bytes each for auth algorithm number, + * transaction number, status code and 128 bytes + * for challenge text. + */ + + frame_len = sizeof(tSirMacMgmtHdr) + + sizeof(tSirMacAuthFrame); + body_len = sizeof(tSirMacAuthFrameBody); + } + break; + + case SIR_MAC_AUTH_FRAME_3: + /* + * Auth frame3 to be sent without encrypted framebody + * + * Allocate buffer for Authenticaton frame of size equal + * to management frame header length plus 2 bytes each + * for auth algorithm number, transaction number and + * status code. + */ + + frame_len = sizeof(tSirMacMgmtHdr) + + SIR_MAC_AUTH_CHALLENGE_OFFSET; + body_len = SIR_MAC_AUTH_CHALLENGE_OFFSET; + break; + + case SIR_MAC_AUTH_FRAME_4: + /* + * Allocate buffer for Authenticaton frame of size equal + * to management frame header length plus 2 bytes each + * for auth algorithm number, transaction number and + * status code. + */ + + frame_len = sizeof(tSirMacMgmtHdr) + + SIR_MAC_AUTH_CHALLENGE_OFFSET; + body_len = SIR_MAC_AUTH_CHALLENGE_OFFSET; + + break; + default: + lim_log(mac_ctx, LOGE, FL("Invalid auth transaction seq num.")); + return; + } /* switch (auth_frame->authTransactionSeqNumber) */ + +alloc_packet: + qdf_status = cds_packet_alloc((uint16_t) frame_len, (void **)&frame, + (void **)&packet); + + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + lim_log(mac_ctx, LOGP, + FL("call to bufAlloc failed for AUTH frame")); + return; + } + + qdf_mem_zero(frame, frame_len); + + /* Prepare BD */ + lim_populate_mac_header(mac_ctx, frame, SIR_MAC_MGMT_FRAME, + SIR_MAC_MGMT_AUTH, peer_addr, session->selfMacAddr); + mac_hdr = (tpSirMacMgmtHdr) frame; + mac_hdr->fc.wep = wep_bit; + + /* Prepare BSSId */ + if (LIM_IS_AP_ROLE(session)) + qdf_mem_copy((uint8_t *) mac_hdr->bssId, + (uint8_t *) session->bssId, + sizeof(tSirMacAddr)); + + /* Prepare Authentication frame body */ + body = frame + sizeof(tSirMacMgmtHdr); + + if (wep_bit == LIM_WEP_IN_FC) { + qdf_mem_copy(body, (uint8_t *) auth_frame, body_len); + + lim_log(mac_ctx, LOG1, + FL("Sending Auth seq# 3 to " MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(mac_hdr->da)); + + } else { + *((uint16_t *) (body)) = + sir_swap_u16if_needed(auth_frame->authAlgoNumber); + body += sizeof(uint16_t); + body_len -= sizeof(uint16_t); + + *((uint16_t *) (body)) = + sir_swap_u16if_needed( + auth_frame->authTransactionSeqNumber); + body += sizeof(uint16_t); + body_len -= sizeof(uint16_t); + + *((uint16_t *) (body)) = + sir_swap_u16if_needed(auth_frame->authStatusCode); + body += sizeof(uint16_t); + body_len -= sizeof(uint16_t); + if (body_len <= (sizeof(auth_frame->type) + + sizeof(auth_frame->length) + + sizeof(auth_frame->challengeText))) + qdf_mem_copy(body, (uint8_t *) &auth_frame->type, + body_len); + + if ((auth_frame->authAlgoNumber == eSIR_FT_AUTH) && + (auth_frame->authTransactionSeqNumber == + SIR_MAC_AUTH_FRAME_1) && + (session->ftPEContext.pFTPreAuthReq != NULL)) { + + if (ft_ies_length > 0) { + qdf_mem_copy(body, + session->ftPEContext. + pFTPreAuthReq->ft_ies, + ft_ies_length); + lim_log(mac_ctx, LOG2, + FL("Auth1 Frame FTIE is: ")); + sir_dump_buf(mac_ctx, SIR_LIM_MODULE_ID, LOG2, + (uint8_t *) body, + ft_ies_length); + } else if (NULL != session->ftPEContext. + pFTPreAuthReq->pbssDescription) { + /* MDID attr is 54 */ + *body = SIR_MDIE_ELEMENT_ID; + body++; + *body = SIR_MDIE_SIZE; + body++; + qdf_mem_copy(body, + &session->ftPEContext.pFTPreAuthReq-> + pbssDescription->mdie[0], + SIR_MDIE_SIZE); + } + } + + lim_log(mac_ctx, LOG1, + FL("*** Sending Auth seq# %d status %d (%d) to " + MAC_ADDRESS_STR), + auth_frame->authTransactionSeqNumber, + auth_frame->authStatusCode, + (auth_frame->authStatusCode == + eSIR_MAC_SUCCESS_STATUS), + MAC_ADDR_ARRAY(mac_hdr->da)); + } + sir_dump_buf(mac_ctx, SIR_LIM_MODULE_ID, LOG2, frame, frame_len); + + if ((NULL != session->ftPEContext.pFTPreAuthReq) && + (SIR_BAND_5_GHZ == lim_get_rf_band( + session->ftPEContext.pFTPreAuthReq->preAuthchannelNum))) + tx_flag |= HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME; + else if ((SIR_BAND_5_GHZ == + lim_get_rf_band(session->currentOperChannel)) + || (session->pePersona == QDF_P2P_CLIENT_MODE) + || (session->pePersona == QDF_P2P_GO_MODE)) + tx_flag |= HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME; + + if (session->pePersona == QDF_P2P_CLIENT_MODE || + session->pePersona == QDF_STA_MODE) + tx_flag |= HAL_USE_PEER_STA_REQUESTED_MASK; + + MTRACE(qdf_trace(QDF_MODULE_ID_PE, TRACE_CODE_TX_MGMT, + session->peSessionId, mac_hdr->fc.subType)); + + mac_ctx->auth_ack_status = LIM_AUTH_ACK_NOT_RCD; + qdf_status = wma_tx_frameWithTxComplete(mac_ctx, packet, + (uint16_t)frame_len, + TXRX_FRM_802_11_MGMT, ANI_TXDIR_TODS, + 7, lim_tx_complete, frame, + lim_auth_tx_complete_cnf, + tx_flag, sme_sessionid, false, 0); + MTRACE(qdf_trace(QDF_MODULE_ID_PE, TRACE_CODE_TX_COMPLETE, + session->peSessionId, qdf_status)); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + lim_log(mac_ctx, LOGE, + FL("*** Could not send Auth frame, retCode=%X ***"), + qdf_status); + mac_ctx->auth_ack_status = LIM_AUTH_ACK_RCD_FAILURE; + auth_ack_status = SENT_FAIL; + lim_diag_event_report(mac_ctx, WLAN_PE_DIAG_AUTH_ACK_EVENT, + session, auth_ack_status, eSIR_FAILURE); + } + return; +} + +QDF_STATUS lim_send_deauth_cnf(tpAniSirGlobal pMac) +{ + uint16_t aid; + tpDphHashNode pStaDs; + tLimMlmDeauthReq *pMlmDeauthReq; + tLimMlmDeauthCnf mlmDeauthCnf; + tpPESession psessionEntry; + + pMlmDeauthReq = pMac->lim.limDisassocDeauthCnfReq.pMlmDeauthReq; + if (pMlmDeauthReq) { + if (tx_timer_running(&pMac->lim.limTimers.gLimDeauthAckTimer)) { + lim_deactivate_and_change_timer(pMac, + eLIM_DEAUTH_ACK_TIMER); + } + + psessionEntry = pe_find_session_by_session_id(pMac, + pMlmDeauthReq->sessionId); + if (psessionEntry == NULL) { + PELOGE(lim_log(pMac, LOGE, + FL + ("session does not exist for given sessionId")); + ) + mlmDeauthCnf.resultCode = + eSIR_SME_INVALID_PARAMETERS; + goto end; + } + + pStaDs = + dph_lookup_hash_entry(pMac, + pMlmDeauthReq->peer_macaddr.bytes, + &aid, + &psessionEntry->dph.dphHashTable); + if (pStaDs == NULL) { + mlmDeauthCnf.resultCode = eSIR_SME_INVALID_PARAMETERS; + goto end; + } + + /* / Receive path cleanup with dummy packet */ + lim_ft_cleanup_pre_auth_info(pMac, psessionEntry); + lim_cleanup_rx_path(pMac, pStaDs, psessionEntry); + if ((psessionEntry->limSystemRole == eLIM_STA_ROLE) && + ( +#ifdef FEATURE_WLAN_ESE + (psessionEntry->isESEconnection) || +#endif + (psessionEntry->isFastRoamIniFeatureEnabled) || + (psessionEntry->is11Rconnection))) { + lim_log(pMac, LOGE, + FL("FT Preauth (%p,%d) Deauth rc %d src = %d"), + psessionEntry, + psessionEntry->peSessionId, + pMlmDeauthReq->reasonCode, + pMlmDeauthReq->deauthTrigger); + lim_ft_cleanup(pMac, psessionEntry); + } else { + lim_log(pMac, LOGE, + FL("No FT Preauth Session Cleanup in role %d" +#ifdef FEATURE_WLAN_ESE + " isESE %d" +#endif + " isLFR %d" + " is11r %d, Deauth reason %d Trigger = %d"), + psessionEntry->limSystemRole, +#ifdef FEATURE_WLAN_ESE + psessionEntry->isESEconnection, +#endif + psessionEntry->isFastRoamIniFeatureEnabled, + psessionEntry->is11Rconnection, + pMlmDeauthReq->reasonCode, + pMlmDeauthReq->deauthTrigger); + } + /* Free up buffer allocated for mlmDeauthReq */ + qdf_mem_free(pMlmDeauthReq); + pMac->lim.limDisassocDeauthCnfReq.pMlmDeauthReq = NULL; + } + return QDF_STATUS_SUCCESS; +end: + qdf_copy_macaddr(&mlmDeauthCnf.peer_macaddr, + &pMlmDeauthReq->peer_macaddr); + mlmDeauthCnf.deauthTrigger = pMlmDeauthReq->deauthTrigger; + mlmDeauthCnf.aid = pMlmDeauthReq->aid; + mlmDeauthCnf.sessionId = pMlmDeauthReq->sessionId; + + /* Free up buffer allocated */ + /* for mlmDeauthReq */ + qdf_mem_free(pMlmDeauthReq); + + lim_post_sme_message(pMac, + LIM_MLM_DEAUTH_CNF, (uint32_t *) &mlmDeauthCnf); + return QDF_STATUS_SUCCESS; +} + +/** + * lim_send_disassoc_cnf() - Send disassoc confirmation to SME + * + * @mac_ctx: Handle to MAC context + * + * Sends disassoc confirmation to SME. Removes disassoc request stored + * in lim. + * + * Return: QDF_STATUS_SUCCESS + */ + +QDF_STATUS lim_send_disassoc_cnf(tpAniSirGlobal mac_ctx) +{ + uint16_t aid; + tpDphHashNode sta_ds; + tLimMlmDisassocCnf disassoc_cnf; + tpPESession pe_session; + tLimMlmDisassocReq *disassoc_req; + + disassoc_req = mac_ctx->lim.limDisassocDeauthCnfReq.pMlmDisassocReq; + if (disassoc_req) { + if (tx_timer_running( + &mac_ctx->lim.limTimers.gLimDisassocAckTimer)) + lim_deactivate_and_change_timer(mac_ctx, + eLIM_DISASSOC_ACK_TIMER); + + pe_session = pe_find_session_by_session_id( + mac_ctx, disassoc_req->sessionId); + if (pe_session == NULL) { + lim_log(mac_ctx, LOGE, + FL("No session for given sessionId")); + disassoc_cnf.resultCode = + eSIR_SME_INVALID_PARAMETERS; + goto end; + } + + sta_ds = dph_lookup_hash_entry(mac_ctx, + disassoc_req->peer_macaddr.bytes, &aid, + &pe_session->dph.dphHashTable); + if (sta_ds == NULL) { + lim_log(mac_ctx, LOGE, FL("StaDs Null")); + disassoc_cnf.resultCode = eSIR_SME_INVALID_PARAMETERS; + goto end; + } + /* Receive path cleanup with dummy packet */ + if (eSIR_SUCCESS != + lim_cleanup_rx_path(mac_ctx, sta_ds, pe_session)) { + disassoc_cnf.resultCode = + eSIR_SME_RESOURCES_UNAVAILABLE; + lim_log(mac_ctx, LOGE, FL("cleanup_rx_path error")); + goto end; + } + if (LIM_IS_STA_ROLE(pe_session) && + (disassoc_req->reasonCode != + eSIR_MAC_DISASSOC_DUE_TO_FTHANDOFF_REASON)) { + lim_log(mac_ctx, LOG1, + FL("FT Preauth Session (%p,%d) Clean up" +#ifdef FEATURE_WLAN_ESE + " isESE %d" +#endif + " isLFR %d" + " is11r %d reason %d"), + pe_session, pe_session->peSessionId, +#ifdef FEATURE_WLAN_ESE + pe_session->isESEconnection, +#endif + pe_session->isFastRoamIniFeatureEnabled, + pe_session->is11Rconnection, + disassoc_req->reasonCode); + + /* Delete FT session if there exists one */ + lim_ft_cleanup_pre_auth_info(mac_ctx, pe_session); + } + /* Free up buffer allocated for mlmDisassocReq */ + qdf_mem_free(disassoc_req); + mac_ctx->lim.limDisassocDeauthCnfReq.pMlmDisassocReq = NULL; + return QDF_STATUS_SUCCESS; + } else { + return QDF_STATUS_SUCCESS; + } +end: + qdf_mem_copy((uint8_t *) &disassoc_cnf.peerMacAddr, + (uint8_t *) disassoc_req->peer_macaddr.bytes, + QDF_MAC_ADDR_SIZE); + disassoc_cnf.aid = disassoc_req->aid; + disassoc_cnf.disassocTrigger = disassoc_req->disassocTrigger; + + /* Update PE session ID */ + disassoc_cnf.sessionId = disassoc_req->sessionId; + + if (disassoc_req != NULL) { + /* / Free up buffer allocated for mlmDisassocReq */ + qdf_mem_free(disassoc_req); + mac_ctx->lim.limDisassocDeauthCnfReq.pMlmDisassocReq = NULL; + } + + lim_post_sme_message(mac_ctx, LIM_MLM_DISASSOC_CNF, + (uint32_t *) &disassoc_cnf); + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS lim_disassoc_tx_complete_cnf(tpAniSirGlobal pMac, + uint32_t txCompleteSuccess) +{ + lim_log(pMac, LOG1, + FL("txCompleteSuccess: %d"), txCompleteSuccess); + return lim_send_disassoc_cnf(pMac); +} + +QDF_STATUS lim_deauth_tx_complete_cnf(tpAniSirGlobal pMac, + uint32_t txCompleteSuccess) +{ + lim_log(pMac, LOG1, + FL("txCompleteSuccess: %d"), txCompleteSuccess); + return lim_send_deauth_cnf(pMac); +} + +/** + * \brief This function is called to send Disassociate frame. + * + * + * \param pMac Pointer to Global MAC structure + * + * \param nReason Indicates the reason that need to be sent in + * Disassociation frame + * + * \param peerMacAddr MAC address of the STA to which Disassociation frame is + * sent + * + * + */ + +void +lim_send_disassoc_mgmt_frame(tpAniSirGlobal pMac, + uint16_t nReason, + tSirMacAddr peer, + tpPESession psessionEntry, bool waitForAck) +{ + tDot11fDisassociation frm; + uint8_t *pFrame; + tpSirMacMgmtHdr pMacHdr; + uint32_t nBytes, nPayload, nStatus; + void *pPacket; + QDF_STATUS qdf_status; + uint8_t txFlag = 0; + uint32_t val = 0; + uint8_t smeSessionId = 0; + if (NULL == psessionEntry) { + return; + } + + /* + * In case when cac timer is running for this SAP session then + * avoid sending disassoc out. It is violation of dfs specification. + */ + if (((psessionEntry->pePersona == QDF_SAP_MODE) || + (psessionEntry->pePersona == QDF_P2P_GO_MODE)) && + (true == pMac->sap.SapDfsInfo.is_dfs_cac_timer_running)) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO, + FL + ("CAC timer is running, drop disassoc from going out")); + return; + } + smeSessionId = psessionEntry->smeSessionId; + + qdf_mem_set((uint8_t *) &frm, sizeof(frm), 0); + + frm.Reason.code = nReason; + + nStatus = dot11f_get_packed_disassociation_size(pMac, &frm, &nPayload); + if (DOT11F_FAILED(nStatus)) { + lim_log(pMac, LOGP, FL("Failed to calculate the packed size f" + "or a Disassociation (0x%08x)."), + nStatus); + /* We'll fall back on the worst case scenario: */ + nPayload = sizeof(tDot11fDisassociation); + } else if (DOT11F_WARNED(nStatus)) { + lim_log(pMac, LOGW, FL("There were warnings while calculating " + "the packed size for a Disassociation " + "(0x%08x)."), nStatus); + } + + nBytes = nPayload + sizeof(tSirMacMgmtHdr); + + qdf_status = cds_packet_alloc((uint16_t) nBytes, (void **)&pFrame, + (void **)&pPacket); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + lim_log(pMac, LOGP, FL("Failed to allocate %d bytes for a Dis" + "association."), nBytes); + return; + } + /* Paranoia: */ + qdf_mem_set(pFrame, nBytes, 0); + + /* Next, we fill out the buffer descriptor: */ + lim_populate_mac_header(pMac, pFrame, SIR_MAC_MGMT_FRAME, + SIR_MAC_MGMT_DISASSOC, peer, psessionEntry->selfMacAddr); + pMacHdr = (tpSirMacMgmtHdr) pFrame; + + /* Prepare the BSSID */ + sir_copy_mac_addr(pMacHdr->bssId, psessionEntry->bssId); + +#ifdef WLAN_FEATURE_11W + lim_set_protected_bit(pMac, psessionEntry, peer, pMacHdr); +#endif + + nStatus = dot11f_pack_disassociation(pMac, &frm, pFrame + + sizeof(tSirMacMgmtHdr), + nPayload, &nPayload); + if (DOT11F_FAILED(nStatus)) { + lim_log(pMac, LOGE, + FL("Failed to pack a Disassociation (0x%08x)."), + nStatus); + cds_packet_free((void *)pPacket); + return; /* allocated! */ + } else if (DOT11F_WARNED(nStatus)) { + lim_log(pMac, LOGW, FL("There were warnings while packing a D" + "isassociation (0x%08x)."), nStatus); + } + + lim_log(pMac, LOG1, + FL("***Sessionid %d Sending Disassociation frame with " + "reason %u and waitForAck %d to " MAC_ADDRESS_STR " ,From " + MAC_ADDRESS_STR), psessionEntry->peSessionId, nReason, + waitForAck, MAC_ADDR_ARRAY(pMacHdr->da), + MAC_ADDR_ARRAY(psessionEntry->selfMacAddr)); + + if ((SIR_BAND_5_GHZ == lim_get_rf_band(psessionEntry->currentOperChannel)) + || (psessionEntry->pePersona == QDF_P2P_CLIENT_MODE) || + (psessionEntry->pePersona == QDF_P2P_GO_MODE) + ) { + txFlag |= HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME; + } + + txFlag |= HAL_USE_PEER_STA_REQUESTED_MASK; + + if (waitForAck) { + MTRACE(qdf_trace(QDF_MODULE_ID_PE, TRACE_CODE_TX_MGMT, + psessionEntry->peSessionId, + pMacHdr->fc.subType)); + /* Queue Disassociation frame in high priority WQ */ + /* get the duration from the request */ + qdf_status = + wma_tx_frameWithTxComplete(pMac, pPacket, (uint16_t) nBytes, + TXRX_FRM_802_11_MGMT, + ANI_TXDIR_TODS, 7, lim_tx_complete, + pFrame, lim_disassoc_tx_complete_cnf, + txFlag, smeSessionId, false, 0); + MTRACE(qdf_trace + (QDF_MODULE_ID_PE, TRACE_CODE_TX_COMPLETE, + psessionEntry->peSessionId, qdf_status)); + + val = SYS_MS_TO_TICKS(LIM_DISASSOC_DEAUTH_ACK_TIMEOUT); + + if (tx_timer_change + (&pMac->lim.limTimers.gLimDisassocAckTimer, val, 0) + != TX_SUCCESS) { + lim_log(pMac, LOGP, + FL("Unable to change Disassoc ack Timer val")); + return; + } else if (TX_SUCCESS != + tx_timer_activate(&pMac->lim.limTimers. + gLimDisassocAckTimer)) { + lim_log(pMac, LOGP, + FL("Unable to activate Disassoc ack Timer")); + lim_deactivate_and_change_timer(pMac, + eLIM_DISASSOC_ACK_TIMER); + return; + } + } else { + MTRACE(qdf_trace(QDF_MODULE_ID_PE, TRACE_CODE_TX_MGMT, + psessionEntry->peSessionId, + pMacHdr->fc.subType)); + /* Queue Disassociation frame in high priority WQ */ + qdf_status = wma_tx_frame(pMac, pPacket, (uint16_t) nBytes, + TXRX_FRM_802_11_MGMT, + ANI_TXDIR_TODS, + 7, + lim_tx_complete, pFrame, txFlag, + smeSessionId, 0); + MTRACE(qdf_trace + (QDF_MODULE_ID_PE, TRACE_CODE_TX_COMPLETE, + psessionEntry->peSessionId, qdf_status)); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + lim_log(pMac, LOGE, + FL("Failed to send Disassociation (%X)!"), + qdf_status); + /* Pkt will be freed up by the callback */ + } + } +} /* End lim_send_disassoc_mgmt_frame. */ + +/** + * \brief This function is called to send a Deauthenticate frame + * + * + * \param pMac Pointer to global MAC structure + * + * \param nReason Indicates the reason that need to be sent in the + * Deauthenticate frame + * + * \param peeer address of the STA to which the frame is to be sent + * + * + */ + +void +lim_send_deauth_mgmt_frame(tpAniSirGlobal pMac, + uint16_t nReason, + tSirMacAddr peer, + tpPESession psessionEntry, bool waitForAck) +{ + tDot11fDeAuth frm; + uint8_t *pFrame; + tpSirMacMgmtHdr pMacHdr; + uint32_t nBytes, nPayload, nStatus; + void *pPacket; + QDF_STATUS qdf_status; + uint8_t txFlag = 0; + uint32_t val = 0; +#ifdef FEATURE_WLAN_TDLS + uint16_t aid; + tpDphHashNode pStaDs; +#endif + uint8_t smeSessionId = 0; + + if (NULL == psessionEntry) { + return; + } + + /* + * In case when cac timer is running for this SAP session then + * avoid deauth frame out. It is violation of dfs specification. + */ + if (((psessionEntry->pePersona == QDF_SAP_MODE) || + (psessionEntry->pePersona == QDF_P2P_GO_MODE)) && + (true == pMac->sap.SapDfsInfo.is_dfs_cac_timer_running)) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO, + FL + ("CAC timer is running, drop the deauth from going out")); + return; + } + smeSessionId = psessionEntry->smeSessionId; + + qdf_mem_set((uint8_t *) &frm, sizeof(frm), 0); + + frm.Reason.code = nReason; + + nStatus = dot11f_get_packed_de_auth_size(pMac, &frm, &nPayload); + if (DOT11F_FAILED(nStatus)) { + lim_log(pMac, LOGP, FL("Failed to calculate the packed size f" + "or a De-Authentication (0x%08x)."), + nStatus); + /* We'll fall back on the worst case scenario: */ + nPayload = sizeof(tDot11fDeAuth); + } else if (DOT11F_WARNED(nStatus)) { + lim_log(pMac, LOGW, FL("There were warnings while calculating " + "the packed size for a De-Authentication " + "(0x%08x)."), nStatus); + } + + nBytes = nPayload + sizeof(tSirMacMgmtHdr); + + qdf_status = cds_packet_alloc((uint16_t) nBytes, (void **)&pFrame, + (void **)&pPacket); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + lim_log(pMac, LOGP, FL("Failed to allocate %d bytes for a De-" + "Authentication."), nBytes); + return; + } + /* Paranoia: */ + qdf_mem_set(pFrame, nBytes, 0); + + /* Next, we fill out the buffer descriptor: */ + lim_populate_mac_header(pMac, pFrame, SIR_MAC_MGMT_FRAME, + SIR_MAC_MGMT_DEAUTH, peer, psessionEntry->selfMacAddr); + pMacHdr = (tpSirMacMgmtHdr) pFrame; + + /* Prepare the BSSID */ + sir_copy_mac_addr(pMacHdr->bssId, psessionEntry->bssId); + +#ifdef WLAN_FEATURE_11W + lim_set_protected_bit(pMac, psessionEntry, peer, pMacHdr); +#endif + + nStatus = dot11f_pack_de_auth(pMac, &frm, pFrame + + sizeof(tSirMacMgmtHdr), nPayload, &nPayload); + if (DOT11F_FAILED(nStatus)) { + lim_log(pMac, LOGE, + FL("Failed to pack a DeAuthentication (0x%08x)."), + nStatus); + cds_packet_free((void *)pPacket); + return; + } else if (DOT11F_WARNED(nStatus)) { + lim_log(pMac, LOGW, FL("There were warnings while packing a D" + "e-Authentication (0x%08x)."), nStatus); + } + lim_log(pMac, LOG1, FL("***Sessionid %d Sending Deauth frame with " + "reason %u and waitForAck %d to " MAC_ADDRESS_STR + " ,From " MAC_ADDRESS_STR), + psessionEntry->peSessionId, nReason, waitForAck, + MAC_ADDR_ARRAY(pMacHdr->da), + MAC_ADDR_ARRAY(psessionEntry->selfMacAddr)); + + if ((SIR_BAND_5_GHZ == lim_get_rf_band(psessionEntry->currentOperChannel)) + || (psessionEntry->pePersona == QDF_P2P_CLIENT_MODE) || + (psessionEntry->pePersona == QDF_P2P_GO_MODE) + ) { + txFlag |= HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME; + } + + txFlag |= HAL_USE_PEER_STA_REQUESTED_MASK; +#ifdef FEATURE_WLAN_TDLS + pStaDs = + dph_lookup_hash_entry(pMac, peer, &aid, + &psessionEntry->dph.dphHashTable); +#endif + + if (waitForAck) { + MTRACE(qdf_trace(QDF_MODULE_ID_PE, TRACE_CODE_TX_MGMT, + psessionEntry->peSessionId, + pMacHdr->fc.subType)); + /* Queue Disassociation frame in high priority WQ */ + qdf_status = + wma_tx_frameWithTxComplete(pMac, pPacket, (uint16_t) nBytes, + TXRX_FRM_802_11_MGMT, + ANI_TXDIR_TODS, 7, lim_tx_complete, + pFrame, lim_deauth_tx_complete_cnf, + txFlag, smeSessionId, false, 0); + MTRACE(qdf_trace + (QDF_MODULE_ID_PE, TRACE_CODE_TX_COMPLETE, + psessionEntry->peSessionId, qdf_status)); + /* Pkt will be freed up by the callback lim_tx_complete */ + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + lim_log(pMac, LOGE, + FL("Failed to send De-Authentication (%X)!"), + qdf_status); + + /* Call lim_process_deauth_ack_timeout which will send + * DeauthCnf for this frame + */ + lim_process_deauth_ack_timeout(pMac); + return; + } + + val = SYS_MS_TO_TICKS(LIM_DISASSOC_DEAUTH_ACK_TIMEOUT); + + if (tx_timer_change + (&pMac->lim.limTimers.gLimDeauthAckTimer, val, 0) + != TX_SUCCESS) { + lim_log(pMac, LOGP, + FL("Unable to change Deauth ack Timer val")); + return; + } else if (TX_SUCCESS != + tx_timer_activate(&pMac->lim.limTimers. + gLimDeauthAckTimer)) { + lim_log(pMac, LOGP, + FL("Unable to activate Deauth ack Timer")); + lim_deactivate_and_change_timer(pMac, + eLIM_DEAUTH_ACK_TIMER); + return; + } + } else { + MTRACE(qdf_trace(QDF_MODULE_ID_PE, TRACE_CODE_TX_MGMT, + psessionEntry->peSessionId, + pMacHdr->fc.subType)); +#ifdef FEATURE_WLAN_TDLS + if ((NULL != pStaDs) + && (STA_ENTRY_TDLS_PEER == pStaDs->staType)) { + /* Queue Disassociation frame in high priority WQ */ + qdf_status = + wma_tx_frame(pMac, pPacket, (uint16_t) nBytes, + TXRX_FRM_802_11_MGMT, ANI_TXDIR_IBSS, + 7, lim_tx_complete, pFrame, txFlag, + smeSessionId, 0); + } else { +#endif + /* Queue Disassociation frame in high priority WQ */ + qdf_status = + wma_tx_frame(pMac, pPacket, (uint16_t) nBytes, + TXRX_FRM_802_11_MGMT, ANI_TXDIR_TODS, + 7, lim_tx_complete, pFrame, txFlag, + smeSessionId, 0); +#ifdef FEATURE_WLAN_TDLS + } +#endif + MTRACE(qdf_trace(QDF_MODULE_ID_PE, TRACE_CODE_TX_COMPLETE, + psessionEntry->peSessionId, qdf_status)); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + lim_log(pMac, LOGE, + FL("Failed to send De-Authentication (%X)!"), + qdf_status); + /* Pkt will be freed up by the callback */ + } + } + +} /* End lim_send_deauth_mgmt_frame. */ + +#ifdef ANI_SUPPORT_11H +/** + * \brief Send a Measurement Report Action frame + * + * + * \param pMac Pointer to the global MAC structure + * + * \param pMeasReqFrame Address of a tSirMacMeasReqActionFrame + * + * \return eSIR_SUCCESS on success, eSIR_FAILURE else + * + * + */ + +tSirRetStatus +lim_send_meas_report_frame(tpAniSirGlobal pMac, + tpSirMacMeasReqActionFrame pMeasReqFrame, + tSirMacAddr peer, tpPESession psessionEntry) +{ + tDot11fMeasurementReport frm; + uint8_t *pFrame; + tSirRetStatus nSirStatus; + tpSirMacMgmtHdr pMacHdr; + uint32_t nBytes, nPayload, nStatus; + void *pPacket; + QDF_STATUS qdf_status; + + qdf_mem_set((uint8_t *) &frm, sizeof(frm), 0); + + frm.Category.category = SIR_MAC_ACTION_SPECTRUM_MGMT; + frm.Action.action = SIR_MAC_ACTION_MEASURE_REPORT_ID; + frm.DialogToken.token = pMeasReqFrame->actionHeader.dialogToken; + + switch (pMeasReqFrame->measReqIE.measType) { + case SIR_MAC_BASIC_MEASUREMENT_TYPE: + nSirStatus = + populate_dot11f_measurement_report0(pMac, pMeasReqFrame, + &frm.MeasurementReport); + break; + case SIR_MAC_CCA_MEASUREMENT_TYPE: + nSirStatus = + populate_dot11f_measurement_report1(pMac, pMeasReqFrame, + &frm.MeasurementReport); + break; + case SIR_MAC_RPI_MEASUREMENT_TYPE: + nSirStatus = + populate_dot11f_measurement_report2(pMac, pMeasReqFrame, + &frm.MeasurementReport); + break; + default: + lim_log(pMac, LOGE, FL("Unknown measurement type %d in limSen" + "dMeasReportFrame."), + pMeasReqFrame->measReqIE.measType); + return eSIR_FAILURE; + } + + if (eSIR_SUCCESS != nSirStatus) + return eSIR_FAILURE; + + nStatus = dot11f_get_packed_measurement_report_size(pMac, &frm, &nPayload); + if (DOT11F_FAILED(nStatus)) { + lim_log(pMac, LOGP, FL("Failed to calculate the packed size f" + "or a Measurement Report (0x%08x)."), + nStatus); + /* We'll fall back on the worst case scenario: */ + nPayload = sizeof(tDot11fMeasurementReport); + } else if (DOT11F_WARNED(nStatus)) { + lim_log(pMac, LOGW, FL("There were warnings while calculating " + "the packed size for a Measurement Rep" + "ort (0x%08x)."), nStatus); + } + + nBytes = nPayload + sizeof(tSirMacMgmtHdr); + + qdf_status = + cds_packet_alloc(pMac->hHdd, TXRX_FRM_802_11_MGMT, + (uint16_t) nBytes, (void **)&pFrame, + (void **)&pPacket); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + lim_log(pMac, LOGP, FL("Failed to allocate %d bytes for a De-" + "Authentication."), nBytes); + return eSIR_FAILURE; + } + /* Paranoia: */ + qdf_mem_set(pFrame, nBytes, 0); + + /* Next, we fill out the buffer descriptor: */ + lim_populate_mac_header(pMac, pFrame, SIR_MAC_MGMT_FRAME, + SIR_MAC_MGMT_ACTION, peer); + pMacHdr = (tpSirMacMgmtHdr) pFrame; + + qdf_mem_copy(pMacHdr->bssId, psessionEntry->bssId, sizeof(tSirMacAddr)); + +#ifdef WLAN_FEATURE_11W + lim_set_protected_bit(pMac, psessionEntry, peer, pMacHdr); +#endif + + nStatus = dot11f_pack_measurement_report(pMac, &frm, pFrame + + sizeof(tSirMacMgmtHdr), + nPayload, &nPayload); + if (DOT11F_FAILED(nStatus)) { + lim_log(pMac, LOGE, + FL("Failed to pack a Measurement Report (0x%08x)."), + nStatus); + cds_packet_free(pMac->hHdd, TXRX_FRM_802_11_MGMT, + (void *)pFrame, (void *)pPacket); + return eSIR_FAILURE; /* allocated! */ + } else if (DOT11F_WARNED(nStatus)) { + lim_log(pMac, LOGW, FL("There were warnings while packing a M" + "easurement Report (0x%08x)."), nStatus); + } + + MTRACE(qdf_trace(QDF_MODULE_ID_PE, TRACE_CODE_TX_MGMT, + ((psessionEntry) ? psessionEntry-> + peSessionId : NO_SESSION), pMacHdr->fc.subType)); + qdf_status = + wma_tx_frame(pMac, pPacket, (uint16_t) nBytes, + TXRX_FRM_802_11_MGMT, ANI_TXDIR_TODS, 7, + lim_tx_complete, pFrame, 0, 0); + MTRACE(qdf_trace + (QDF_MODULE_ID_PE, TRACE_CODE_TX_COMPLETE, + ((psessionEntry) ? psessionEntry->peSessionId : NO_SESSION), + qdf_status)); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + lim_log(pMac, LOGE, + FL("Failed to send a Measurement Report (%X)!"), + qdf_status); + /* Pkt will be freed up by the callback */ + return eSIR_FAILURE; /* just allocated... */ + } + + return eSIR_SUCCESS; + +} /* End lim_send_meas_report_frame. */ + +/** + * \brief Send a TPC Request Action frame + * + * + * \param pMac Pointer to the global MAC datastructure + * + * \param peer MAC address to which the frame should be sent + * + * + */ + +void +lim_send_tpc_request_frame(tpAniSirGlobal pMac, + tSirMacAddr peer, tpPESession psessionEntry) +{ + tDot11fTPCRequest frm; + uint8_t *pFrame; + tpSirMacMgmtHdr pMacHdr; + uint32_t nBytes, nPayload, nStatus; + void *pPacket; + QDF_STATUS qdf_status; + + qdf_mem_set((uint8_t *) &frm, sizeof(frm), 0); + + frm.Category.category = SIR_MAC_ACTION_SPECTRUM_MGMT; + frm.Action.action = SIR_MAC_ACTION_TPC_REQUEST_ID; + frm.DialogToken.token = 1; + frm.TPCRequest.present = 1; + + nStatus = dot11f_get_packed_tpc_request_size(pMac, &frm, &nPayload); + if (DOT11F_FAILED(nStatus)) { + lim_log(pMac, LOGP, FL("Failed to calculate the packed size f" + "or a TPC Request (0x%08x)."), nStatus); + /* We'll fall back on the worst case scenario: */ + nPayload = sizeof(tDot11fTPCRequest); + } else if (DOT11F_WARNED(nStatus)) { + lim_log(pMac, LOGW, FL("There were warnings while calculating " + "the packed size for a TPC Request (0x" + "%08x)."), nStatus); + } + + nBytes = nPayload + sizeof(tSirMacMgmtHdr); + + qdf_status = + cds_packet_alloc(pMac->hHdd, TXRX_FRM_802_11_MGMT, + (uint16_t) nBytes, (void **)&pFrame, + (void **)&pPacket); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + lim_log(pMac, LOGP, FL("Failed to allocate %d bytes for a TPC" + " Request."), nBytes); + return; + } + /* Paranoia: */ + qdf_mem_set(pFrame, nBytes, 0); + + /* Next, we fill out the buffer descriptor: */ + lim_populate_mac_header(pMac, pFrame, SIR_MAC_MGMT_FRAME, + SIR_MAC_MGMT_ACTION, peer); + pMacHdr = (tpSirMacMgmtHdr) pFrame; + + qdf_mem_copy(pMacHdr->bssId, psessionEntry->bssId, sizeof(tSirMacAddr)); + +#ifdef WLAN_FEATURE_11W + lim_set_protected_bit(pMac, psessionEntry, peer, pMacHdr); +#endif + + nStatus = dot11f_pack_tpc_request(pMac, &frm, pFrame + + sizeof(tSirMacMgmtHdr), + nPayload, &nPayload); + if (DOT11F_FAILED(nStatus)) { + lim_log(pMac, LOGE, FL("Failed to pack a TPC Request (0x%08x)."), + nStatus); + cds_packet_free(pMac->hHdd, TXRX_FRM_802_11_MGMT, + (void *)pFrame, (void *)pPacket); + return; /* allocated! */ + } else if (DOT11F_WARNED(nStatus)) { + lim_log(pMac, LOGW, FL("There were warnings while packing a T" + "PC Request (0x%08x)."), nStatus); + } + + MTRACE(qdf_trace(QDF_MODULE_ID_PE, TRACE_CODE_TX_MGMT, + ((psessionEntry) ? psessionEntry-> + peSessionId : NO_SESSION), pMacHdr->fc.subType)); + qdf_status = + wma_tx_frame(pMac, pPacket, (uint16_t) nBytes, + TXRX_FRM_802_11_MGMT, ANI_TXDIR_TODS, 7, + lim_tx_complete, pFrame, 0, 0); + MTRACE(qdf_trace + (QDF_MODULE_ID_PE, TRACE_CODE_TX_COMPLETE, + ((psessionEntry) ? psessionEntry->peSessionId : NO_SESSION), + qdf_status)); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + lim_log(pMac, LOGE, + FL("Failed to send a TPC Request (%X)!"), + qdf_status); + /* Pkt will be freed up by the callback */ + } + +} /* End lim_send_tpc_request_frame. */ + +/** + * \brief Send a TPC Report Action frame + * + * + * \param pMac Pointer to the global MAC datastructure + * + * \param pTpcReqFrame Pointer to the received TPC Request + * + * \return eSIR_SUCCESS on success, eSIR_FAILURE else + * + * + */ + +tSirRetStatus +lim_send_tpc_report_frame(tpAniSirGlobal pMac, + tpSirMacTpcReqActionFrame pTpcReqFrame, + tSirMacAddr peer, tpPESession psessionEntry) +{ + tDot11fTPCReport frm; + uint8_t *pFrame; + tpSirMacMgmtHdr pMacHdr; + uint32_t nBytes, nPayload, nStatus; + void *pPacket; + QDF_STATUS qdf_status; + + qdf_mem_set((uint8_t *) &frm, sizeof(frm), 0); + + frm.Category.category = SIR_MAC_ACTION_SPECTRUM_MGMT; + frm.Action.action = SIR_MAC_ACTION_TPC_REPORT_ID; + frm.DialogToken.token = pTpcReqFrame->actionHeader.dialogToken; + + frm.TPCReport.tx_power = 0; + frm.TPCReport.link_margin = 0; + frm.TPCReport.present = 1; + + nStatus = dot11f_get_packed_tpc_report_size(pMac, &frm, &nPayload); + if (DOT11F_FAILED(nStatus)) { + lim_log(pMac, LOGP, FL("Failed to calculate the packed size f" + "or a TPC Report (0x%08x)."), nStatus); + /* We'll fall back on the worst case scenario: */ + nPayload = sizeof(tDot11fTPCReport); + } else if (DOT11F_WARNED(nStatus)) { + lim_log(pMac, LOGW, FL("There were warnings while calculating " + "the packed size for a TPC Report (0x" + "%08x)."), nStatus); + } + + nBytes = nPayload + sizeof(tSirMacMgmtHdr); + + qdf_status = + cds_packet_alloc(pMac->hHdd, TXRX_FRM_802_11_MGMT, + (uint16_t) nBytes, (void **)&pFrame, + (void **)&pPacket); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + lim_log(pMac, LOGP, FL("Failed to allocate %d bytes for a TPC" + " Report."), nBytes); + return eSIR_FAILURE; + } + /* Paranoia: */ + qdf_mem_set(pFrame, nBytes, 0); + + /* Next, we fill out the buffer descriptor: */ + lim_populate_mac_header(pMac, pFrame, SIR_MAC_MGMT_FRAME, + SIR_MAC_MGMT_ACTION, peer); + + pMacHdr = (tpSirMacMgmtHdr) pFrame; + + qdf_mem_copy(pMacHdr->bssId, psessionEntry->bssId, sizeof(tSirMacAddr)); + +#ifdef WLAN_FEATURE_11W + lim_set_protected_bit(pMac, psessionEntry, peer, pMacHdr); +#endif + + nStatus = dot11f_pack_tpc_report(pMac, &frm, pFrame + + sizeof(tSirMacMgmtHdr), + nPayload, &nPayload); + if (DOT11F_FAILED(nStatus)) { + lim_log(pMac, LOGE, FL("Failed to pack a TPC Report (0x%08x)."), + nStatus); + cds_packet_free(pMac->hHdd, TXRX_FRM_802_11_MGMT, + (void *)pFrame, (void *)pPacket); + return eSIR_FAILURE; /* allocated! */ + } else if (DOT11F_WARNED(nStatus)) { + lim_log(pMac, LOGW, FL("There were warnings while packing a T" + "PC Report (0x%08x)."), nStatus); + } + + MTRACE(qdf_trace(QDF_MODULE_ID_PE, TRACE_CODE_TX_MGMT, + ((psessionEntry) ? psessionEntry-> + peSessionId : NO_SESSION), pMacHdr->fc.subType)); + qdf_status = + wma_tx_frame(pMac, pPacket, (uint16_t) nBytes, + TXRX_FRM_802_11_MGMT, ANI_TXDIR_TODS, 7, + lim_tx_complete, pFrame, 0, 0); + MTRACE(qdf_trace + (QDF_MODULE_ID_PE, TRACE_CODE_TX_COMPLETE, + ((psessionEntry) ? psessionEntry->peSessionId : NO_SESSION), + qdf_status)); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + lim_log(pMac, LOGE, + FL("Failed to send a TPC Report (%X)!"), + qdf_status); + /* Pkt will be freed up by the callback */ + return eSIR_FAILURE; /* just allocated... */ + } + + return eSIR_SUCCESS; + +} /* End lim_send_tpc_report_frame. */ +#endif /* ANI_SUPPORT_11H */ + +/** + * \brief Send a Channel Switch Announcement + * + * + * \param pMac Pointer to the global MAC datastructure + * + * \param peer MAC address to which this frame will be sent + * + * \param nMode + * + * \param nNewChannel + * + * \param nCount + * + * \return eSIR_SUCCESS on success, eSIR_FAILURE else + * + * + */ + +tSirRetStatus +lim_send_channel_switch_mgmt_frame(tpAniSirGlobal pMac, + tSirMacAddr peer, + uint8_t nMode, + uint8_t nNewChannel, + uint8_t nCount, tpPESession psessionEntry) +{ + tDot11fChannelSwitch frm; + uint8_t *pFrame; + tpSirMacMgmtHdr pMacHdr; + uint32_t nBytes, nPayload, nStatus; /* , nCfg; */ + void *pPacket; + QDF_STATUS qdf_status; + uint8_t txFlag = 0; + + uint8_t smeSessionId = 0; + + if (psessionEntry == NULL) { + PELOGE(lim_log(pMac, LOGE, FL("Session entry is NULL!!!"));) + return eSIR_FAILURE; + } + smeSessionId = psessionEntry->smeSessionId; + + qdf_mem_set((uint8_t *) &frm, sizeof(frm), 0); + + frm.Category.category = SIR_MAC_ACTION_SPECTRUM_MGMT; + frm.Action.action = SIR_MAC_ACTION_CHANNEL_SWITCH_ID; + frm.ChanSwitchAnn.switchMode = nMode; + frm.ChanSwitchAnn.newChannel = nNewChannel; + frm.ChanSwitchAnn.switchCount = nCount; + frm.ChanSwitchAnn.present = 1; + + nStatus = dot11f_get_packed_channel_switch_size(pMac, &frm, &nPayload); + if (DOT11F_FAILED(nStatus)) { + lim_log(pMac, LOGP, FL("Failed to calculate the packed size f" + "or a Channel Switch (0x%08x)."), + nStatus); + /* We'll fall back on the worst case scenario: */ + nPayload = sizeof(tDot11fChannelSwitch); + } else if (DOT11F_WARNED(nStatus)) { + lim_log(pMac, LOGW, FL("There were warnings while calculating " + "the packed size for a Channel Switch (0x" + "%08x)."), nStatus); + } + + nBytes = nPayload + sizeof(tSirMacMgmtHdr); + + qdf_status = + cds_packet_alloc((uint16_t) nBytes, (void **)&pFrame, + (void **)&pPacket); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + lim_log(pMac, LOGP, FL("Failed to allocate %d bytes for a TPC" + " Report."), nBytes); + return eSIR_FAILURE; + } + /* Paranoia: */ + qdf_mem_set(pFrame, nBytes, 0); + + /* Next, we fill out the buffer descriptor: */ + lim_populate_mac_header(pMac, pFrame, SIR_MAC_MGMT_FRAME, + SIR_MAC_MGMT_ACTION, peer, + psessionEntry->selfMacAddr); + pMacHdr = (tpSirMacMgmtHdr) pFrame; + qdf_mem_copy((uint8_t *) pMacHdr->bssId, + (uint8_t *) psessionEntry->bssId, sizeof(tSirMacAddr)); + +#ifdef WLAN_FEATURE_11W + lim_set_protected_bit(pMac, psessionEntry, peer, pMacHdr); +#endif + + nStatus = dot11f_pack_channel_switch(pMac, &frm, pFrame + + sizeof(tSirMacMgmtHdr), + nPayload, &nPayload); + if (DOT11F_FAILED(nStatus)) { + lim_log(pMac, LOGE, + FL("Failed to pack a Channel Switch (0x%08x)."), + nStatus); + cds_packet_free((void *)pPacket); + return eSIR_FAILURE; /* allocated! */ + } else if (DOT11F_WARNED(nStatus)) { + lim_log(pMac, LOGW, FL("There were warnings while packing a C" + "hannel Switch (0x%08x)."), nStatus); + } + + if ((SIR_BAND_5_GHZ == lim_get_rf_band(psessionEntry->currentOperChannel)) + || (psessionEntry->pePersona == QDF_P2P_CLIENT_MODE) || + (psessionEntry->pePersona == QDF_P2P_GO_MODE) + ) { + txFlag |= HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME; + } + + MTRACE(qdf_trace(QDF_MODULE_ID_PE, TRACE_CODE_TX_MGMT, + psessionEntry->peSessionId, pMacHdr->fc.subType)); + qdf_status = wma_tx_frame(pMac, pPacket, (uint16_t) nBytes, + TXRX_FRM_802_11_MGMT, + ANI_TXDIR_TODS, + 7, lim_tx_complete, pFrame, txFlag, + smeSessionId, 0); + MTRACE(qdf_trace(QDF_MODULE_ID_PE, TRACE_CODE_TX_COMPLETE, + psessionEntry->peSessionId, qdf_status)); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + lim_log(pMac, LOGE, + FL("Failed to send a Channel Switch (%X)!"), + qdf_status); + /* Pkt will be freed up by the callback */ + return eSIR_FAILURE; + } + + return eSIR_SUCCESS; + +} /* End lim_send_channel_switch_mgmt_frame. */ + +/** + * lim_send_extended_chan_switch_action_frame()- function to send ECSA + * action frame over the air . + * @mac_ctx: pointer to global mac structure + * @peer: Destination mac. + * @mode: channel switch mode + * @new_op_class: new op class + * @new_channel: new channel to switch + * @count: channel switch count + * + * This function is called to send ECSA frame. + * + * Return: success if frame is sent else return failure + */ + +tSirRetStatus +lim_send_extended_chan_switch_action_frame(tpAniSirGlobal mac_ctx, + tSirMacAddr peer, uint8_t mode, uint8_t new_op_class, + uint8_t new_channel, uint8_t count, tpPESession session_entry) +{ + tDot11fext_channel_switch_action_frame frm; + uint8_t *frame; + tpSirMacMgmtHdr mac_hdr; + uint32_t num_bytes, n_payload, status; + void *packet; + QDF_STATUS qdf_status; + uint8_t txFlag = 0; + uint8_t sme_session_id = 0; + + if (session_entry == NULL) { + lim_log(mac_ctx, LOGE, FL("Session entry is NULL!!!")); + return eSIR_FAILURE; + } + + sme_session_id = session_entry->smeSessionId; + + qdf_mem_set(&frm, sizeof(frm), 0); + + frm.Category.category = SIR_MAC_ACTION_PUBLIC_USAGE; + frm.Action.action = SIR_MAC_ACTION_EXT_CHANNEL_SWITCH_ID; + + frm.ext_chan_switch_ann_action.switch_mode = mode; + frm.ext_chan_switch_ann_action.op_class = new_op_class; + frm.ext_chan_switch_ann_action.new_channel = new_channel; + frm.ext_chan_switch_ann_action.switch_count = count; + + + status = dot11f_get_packed_ext_channel_switch_action_frame_size(mac_ctx, + &frm, &n_payload); + if (DOT11F_FAILED(status)) { + lim_log(mac_ctx, LOGP, + FL("Failed to get packed size for Channel Switch 0x%08x."), + status); + /* We'll fall back on the worst case scenario*/ + n_payload = sizeof(tDot11fext_channel_switch_action_frame); + } else if (DOT11F_WARNED(status)) { + lim_log(mac_ctx, LOGW, + FL("There were warnings while calculating the packed size for a Ext Channel Switch (0x%08x)."), + status); + } + + num_bytes = n_payload + sizeof(tSirMacMgmtHdr); + + qdf_status = cds_packet_alloc((uint16_t)num_bytes, + (void **) &frame, (void **) &packet); + + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + lim_log(mac_ctx, LOGP, + FL("Failed to allocate %d bytes for a Ext Channel Switch."), + num_bytes); + return eSIR_FAILURE; + } + + /* Paranoia*/ + qdf_mem_set(frame, num_bytes, 0); + + /* Next, we fill out the buffer descriptor */ + lim_populate_mac_header(mac_ctx, frame, SIR_MAC_MGMT_FRAME, + SIR_MAC_MGMT_ACTION, peer, session_entry->selfMacAddr); + mac_hdr = (tpSirMacMgmtHdr) frame; + qdf_mem_copy((uint8_t *) mac_hdr->bssId, + (uint8_t *) session_entry->bssId, + sizeof(tSirMacAddr)); + + status = dot11f_pack_ext_channel_switch_action_frame(mac_ctx, &frm, + frame + sizeof(tSirMacMgmtHdr), n_payload, &n_payload); + if (DOT11F_FAILED(status)) { + lim_log(mac_ctx, LOGE, + FL("Failed to pack a Channel Switch 0x%08x."), + status); + cds_packet_free((void *)packet); + return eSIR_FAILURE; + } else if (DOT11F_WARNED(status)) { + lim_log(mac_ctx, LOGW, + FL("There were warnings while packing a Channel Switch 0x%08x."), + status); + } + + if ((SIR_BAND_5_GHZ == + lim_get_rf_band(session_entry->currentOperChannel)) || + (session_entry->pePersona == QDF_P2P_CLIENT_MODE) || + (session_entry->pePersona == QDF_P2P_GO_MODE)) { + txFlag |= HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME; + } + + lim_log(mac_ctx, LOG1, + FL("Send Ext channel Switch to :"MAC_ADDRESS_STR" with swcount %d, swmode %d , newchannel %d newops %d"), + MAC_ADDR_ARRAY(mac_hdr->da), + frm.ext_chan_switch_ann_action.switch_count, + frm.ext_chan_switch_ann_action.switch_mode, + frm.ext_chan_switch_ann_action.new_channel, + frm.ext_chan_switch_ann_action.op_class); + + MTRACE(qdf_trace(QDF_MODULE_ID_PE, TRACE_CODE_TX_MGMT, + session_entry->peSessionId, mac_hdr->fc.subType)); + qdf_status = wma_tx_frame(mac_ctx, packet, (uint16_t) num_bytes, + TXRX_FRM_802_11_MGMT, + ANI_TXDIR_TODS, + 7, + lim_tx_complete, frame, + txFlag, sme_session_id, 0); + MTRACE(qdf_trace(QDF_MODULE_ID_PE, TRACE_CODE_TX_COMPLETE, + session_entry->peSessionId, qdf_status)); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + lim_log(mac_ctx, LOGE, + FL("Failed to send a Ext Channel Switch %X!"), + qdf_status); + /* Pkt will be freed up by the callback */ + return eSIR_FAILURE; + } + return eSIR_SUCCESS; +} /* End lim_send_extended_chan_switch_action_frame */ + + +/** + * lim_oper_chan_change_confirm_tx_complete_cnf()- Confirmation for oper_chan_change_confirm + * sent over the air + * + * @mac_ctx: pointer to global mac + * @tx_complete : Sent status + * + * Return: This returns QDF_STATUS + */ + +static QDF_STATUS lim_oper_chan_change_confirm_tx_complete_cnf( + tpAniSirGlobal mac_ctx, + uint32_t tx_complete) +{ + lim_log(mac_ctx, LOG1, + FL(" tx_complete= %d"), tx_complete); + return QDF_STATUS_SUCCESS; +} + +/** + * lim_p2p_oper_chan_change_confirm_action_frame()- function to send + * p2p oper chan change confirm action frame + * @mac_ctx: pointer to global mac structure + * @peer: Destination mac. + * @session_entry: session entry + * + * This function is called to send p2p oper chan change confirm action frame. + * + * Return: success if frame is sent else return failure + */ + +tSirRetStatus +lim_p2p_oper_chan_change_confirm_action_frame(tpAniSirGlobal mac_ctx, + tSirMacAddr peer, tpPESession session_entry) +{ + tDot11fp2p_oper_chan_change_confirm frm; + uint8_t *frame; + tpSirMacMgmtHdr mac_hdr; + uint32_t num_bytes, n_payload, status; + void *packet; + QDF_STATUS qdf_status; + uint8_t tx_flag = 0; + uint8_t sme_session_id = 0; + + if (session_entry == NULL) { + lim_log(mac_ctx, LOGE, FL("Session entry is NULL!!!")); + return eSIR_FAILURE; + } + + sme_session_id = session_entry->smeSessionId; + + qdf_mem_set(&frm, sizeof(frm), 0); + + frm.Category.category = SIR_MAC_ACTION_VENDOR_SPECIFIC_CATEGORY; + + qdf_mem_copy(frm.p2p_action_oui.oui_data, + SIR_MAC_P2P_OUI, SIR_MAC_P2P_OUI_SIZE); + frm.p2p_action_subtype.subtype = 0x04; + frm.DialogToken.token = 0x0; + + if (session_entry->htCapability) { + lim_log(mac_ctx, LOG1, FL("Populate HT Caps in Assoc Request")); + populate_dot11f_ht_caps(mac_ctx, session_entry, &frm.HTCaps); + } + + if (session_entry->vhtCapability) { + lim_log(mac_ctx, LOG1, FL("Populate VHT Caps in Assoc Request")); + populate_dot11f_vht_caps(mac_ctx, session_entry, &frm.VHTCaps); + populate_dot11f_operating_mode(mac_ctx, + &frm.OperatingMode, session_entry); + } + + status = dot11f_get_packed_p2p_oper_chan_change_confirmSize(mac_ctx, + &frm, &n_payload); + if (DOT11F_FAILED(status)) { + lim_log(mac_ctx, LOGP, + FL("Failed to get packed size 0x%08x."), + status); + /* We'll fall back on the worst case scenario*/ + n_payload = sizeof(tDot11fp2p_oper_chan_change_confirm); + } else if (DOT11F_WARNED(status)) { + lim_log(mac_ctx, LOGW, + FL("There were warnings while calculating the packed size (0x%08x)."), + status); + } + + num_bytes = n_payload + sizeof(tSirMacMgmtHdr); + + qdf_status = cds_packet_alloc((uint16_t)num_bytes, + (void **) &frame, (void **) &packet); + + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + lim_log(mac_ctx, LOGP, + FL("Failed to allocate %d bytes."), + num_bytes); + return eSIR_FAILURE; + } + + qdf_mem_set(frame, num_bytes, 0); + + /* Next, fill out the buffer descriptor */ + lim_populate_mac_header(mac_ctx, frame, SIR_MAC_MGMT_FRAME, + SIR_MAC_MGMT_ACTION, peer, session_entry->selfMacAddr); + mac_hdr = (tpSirMacMgmtHdr) frame; + qdf_mem_copy((uint8_t *) mac_hdr->bssId, + (uint8_t *) session_entry->bssId, + sizeof(tSirMacAddr)); + + status = dot11f_pack_p2p_oper_chan_change_confirm(mac_ctx, &frm, + frame + sizeof(tSirMacMgmtHdr), n_payload, &n_payload); + if (DOT11F_FAILED(status)) { + lim_log(mac_ctx, LOGE, + FL("Failed to pack 0x%08x."), + status); + cds_packet_free((void *)packet); + return eSIR_FAILURE; + } else if (DOT11F_WARNED(status)) { + lim_log(mac_ctx, LOGW, + FL("There were warnings while packing 0x%08x."), + status); + } + + if ((SIR_BAND_5_GHZ == + lim_get_rf_band(session_entry->currentOperChannel)) || + (session_entry->pePersona == QDF_P2P_CLIENT_MODE) || + (session_entry->pePersona == QDF_P2P_GO_MODE)) { + tx_flag |= HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME; + } + lim_log(mac_ctx, LOG1, FL("Send frame on channel %d to mac " + MAC_ADDRESS_STR), session_entry->currentOperChannel, + MAC_ADDR_ARRAY(peer)); + + MTRACE(qdf_trace(QDF_MODULE_ID_PE, TRACE_CODE_TX_MGMT, + session_entry->peSessionId, mac_hdr->fc.subType)); + + qdf_status = wma_tx_frameWithTxComplete(mac_ctx, packet, + (uint16_t)num_bytes, + TXRX_FRM_802_11_MGMT, ANI_TXDIR_TODS, + 7, lim_tx_complete, frame, + lim_oper_chan_change_confirm_tx_complete_cnf, + tx_flag, sme_session_id, false, 0); + + MTRACE(qdf_trace(QDF_MODULE_ID_PE, TRACE_CODE_TX_COMPLETE, + session_entry->peSessionId, qdf_status)); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + lim_log(mac_ctx, LOGE, + FL("Failed to send status %X!"), + qdf_status); + /* Pkt will be freed up by the callback */ + return eSIR_FAILURE; + } + return eSIR_SUCCESS; +} + + +tSirRetStatus +lim_send_vht_opmode_notification_frame(tpAniSirGlobal pMac, + tSirMacAddr peer, + uint8_t nMode, tpPESession psessionEntry) +{ + tDot11fOperatingMode frm; + uint8_t *pFrame; + tpSirMacMgmtHdr pMacHdr; + uint32_t nBytes, nPayload = 0, nStatus; /* , nCfg; */ + void *pPacket; + QDF_STATUS qdf_status; + uint8_t txFlag = 0; + + uint8_t smeSessionId = 0; + + if (psessionEntry == NULL) { + PELOGE(lim_log(pMac, LOGE, FL("Session entry is NULL!!!"));) + return eSIR_FAILURE; + } + smeSessionId = psessionEntry->smeSessionId; + + qdf_mem_set((uint8_t *) &frm, sizeof(frm), 0); + + frm.Category.category = SIR_MAC_ACTION_VHT; + frm.Action.action = SIR_MAC_VHT_OPMODE_NOTIFICATION; + frm.OperatingMode.chanWidth = nMode; + frm.OperatingMode.rxNSS = 0; + frm.OperatingMode.rxNSSType = 0; + + nStatus = dot11f_get_packed_operating_mode_size(pMac, &frm, &nPayload); + if (DOT11F_FAILED(nStatus)) { + lim_log(pMac, LOGP, FL("Failed to calculate the packed size f" + "or a Operating Mode (0x%08x)."), + nStatus); + /* We'll fall back on the worst case scenario: */ + nPayload = sizeof(tDot11fOperatingMode); + } else if (DOT11F_WARNED(nStatus)) { + lim_log(pMac, LOGW, FL("There were warnings while calculating " + "the packed size for a Operating Mode (0x" + "%08x)."), nStatus); + } + + nBytes = nPayload + sizeof(tSirMacMgmtHdr); + + qdf_status = + cds_packet_alloc((uint16_t) nBytes, (void **)&pFrame, + (void **)&pPacket); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + lim_log(pMac, LOGP, + FL("Failed to allocate %d bytes for a Operating Mode" + " Report."), nBytes); + return eSIR_FAILURE; + } + /* Paranoia: */ + qdf_mem_set(pFrame, nBytes, 0); + + /* Next, we fill out the buffer descriptor: */ + if (psessionEntry->pePersona == QDF_SAP_MODE) + lim_populate_mac_header(pMac, pFrame, SIR_MAC_MGMT_FRAME, + SIR_MAC_MGMT_ACTION, peer, + psessionEntry->selfMacAddr); + else + lim_populate_mac_header(pMac, pFrame, SIR_MAC_MGMT_FRAME, + SIR_MAC_MGMT_ACTION, psessionEntry->bssId, + psessionEntry->selfMacAddr); + pMacHdr = (tpSirMacMgmtHdr) pFrame; + qdf_mem_copy((uint8_t *) pMacHdr->bssId, + (uint8_t *) psessionEntry->bssId, sizeof(tSirMacAddr)); + nStatus = dot11f_pack_operating_mode(pMac, &frm, pFrame + + sizeof(tSirMacMgmtHdr), + nPayload, &nPayload); + if (DOT11F_FAILED(nStatus)) { + lim_log(pMac, LOGE, + FL("Failed to pack a Operating Mode (0x%08x)."), + nStatus); + cds_packet_free((void *)pPacket); + return eSIR_FAILURE; /* allocated! */ + } else if (DOT11F_WARNED(nStatus)) { + lim_log(pMac, LOGW, + FL("There were warnings while packing a Operating Mode" + " (0x%08x)."), nStatus); + } + if ((SIR_BAND_5_GHZ == lim_get_rf_band(psessionEntry->currentOperChannel)) + || (psessionEntry->pePersona == QDF_P2P_CLIENT_MODE) || + (psessionEntry->pePersona == QDF_P2P_GO_MODE) + ) { + txFlag |= HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME; + } + + MTRACE(qdf_trace(QDF_MODULE_ID_PE, TRACE_CODE_TX_MGMT, + psessionEntry->peSessionId, pMacHdr->fc.subType)); + qdf_status = wma_tx_frame(pMac, pPacket, (uint16_t) nBytes, + TXRX_FRM_802_11_MGMT, + ANI_TXDIR_TODS, + 7, lim_tx_complete, pFrame, txFlag, + smeSessionId, 0); + MTRACE(qdf_trace(QDF_MODULE_ID_PE, TRACE_CODE_TX_COMPLETE, + psessionEntry->peSessionId, qdf_status)); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + lim_log(pMac, LOGE, + FL("Failed to send a Channel Switch (%X)!"), + qdf_status); + /* Pkt will be freed up by the callback */ + return eSIR_FAILURE; + } + + return eSIR_SUCCESS; +} + +/** + * \brief Send a Neighbor Report Request Action frame + * + * + * \param pMac Pointer to the global MAC structure + * + * \param pNeighborReq Address of a tSirMacNeighborReportReq + * + * \param peer mac address of peer station. + * + * \param psessionEntry address of session entry. + * + * \return eSIR_SUCCESS on success, eSIR_FAILURE else + * + * + */ + +tSirRetStatus +lim_send_neighbor_report_request_frame(tpAniSirGlobal pMac, + tpSirMacNeighborReportReq pNeighborReq, + tSirMacAddr peer, tpPESession psessionEntry) +{ + tSirRetStatus statusCode = eSIR_SUCCESS; + tDot11fNeighborReportRequest frm; + uint8_t *pFrame; + tpSirMacMgmtHdr pMacHdr; + uint32_t nBytes, nPayload, nStatus; + void *pPacket; + QDF_STATUS qdf_status; + uint8_t txFlag = 0; + uint8_t smeSessionId = 0; + + if (psessionEntry == NULL) { + lim_log(pMac, LOGE, + FL + ("(psession == NULL) in Request to send Neighbor Report request action frame")); + return eSIR_FAILURE; + } + smeSessionId = psessionEntry->smeSessionId; + qdf_mem_set((uint8_t *) &frm, sizeof(frm), 0); + + frm.Category.category = SIR_MAC_ACTION_RRM; + frm.Action.action = SIR_MAC_RRM_NEIGHBOR_REQ; + frm.DialogToken.token = pNeighborReq->dialogToken; + + if (pNeighborReq->ssid_present) { + populate_dot11f_ssid(pMac, &pNeighborReq->ssid, &frm.SSID); + } + + nStatus = + dot11f_get_packed_neighbor_report_request_size(pMac, &frm, &nPayload); + if (DOT11F_FAILED(nStatus)) { + lim_log(pMac, LOGP, FL("Failed to calculate the packed size f" + "or a Neighbor Report Request(0x%08x)."), + nStatus); + /* We'll fall back on the worst case scenario: */ + nPayload = sizeof(tDot11fNeighborReportRequest); + } else if (DOT11F_WARNED(nStatus)) { + lim_log(pMac, LOGW, FL("There were warnings while calculating " + "the packed size for a Neighbor Rep" + "ort Request(0x%08x)."), nStatus); + } + + nBytes = nPayload + sizeof(tSirMacMgmtHdr); + + qdf_status = + cds_packet_alloc((uint16_t) nBytes, (void **)&pFrame, + (void **)&pPacket); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + lim_log(pMac, LOGP, + FL("Failed to allocate %d bytes for a Neighbor " + "Report Request."), nBytes); + return eSIR_FAILURE; + } + /* Paranoia: */ + qdf_mem_set(pFrame, nBytes, 0); + + /* Copy necessary info to BD */ + lim_populate_mac_header(pMac, pFrame, SIR_MAC_MGMT_FRAME, + SIR_MAC_MGMT_ACTION, peer, psessionEntry->selfMacAddr); + + /* Update A3 with the BSSID */ + pMacHdr = (tpSirMacMgmtHdr) pFrame; + + sir_copy_mac_addr(pMacHdr->bssId, psessionEntry->bssId); + +#ifdef WLAN_FEATURE_11W + lim_set_protected_bit(pMac, psessionEntry, peer, pMacHdr); +#endif + + /* Now, we're ready to "pack" the frames */ + nStatus = dot11f_pack_neighbor_report_request(pMac, + &frm, + pFrame + + sizeof(tSirMacMgmtHdr), + nPayload, &nPayload); + + if (DOT11F_FAILED(nStatus)) { + lim_log(pMac, LOGE, + FL + ("Failed to pack an Neighbor Report Request (0x%08x)."), + nStatus); + + /* FIXME - Need to convert to tSirRetStatus */ + statusCode = eSIR_FAILURE; + goto returnAfterError; + } else if (DOT11F_WARNED(nStatus)) { + lim_log(pMac, LOGW, + FL("There were warnings while packing Neighbor Report " + "Request (0x%08x)."), nStatus); + } + + lim_log(pMac, LOGW, FL("Sending a Neighbor Report Request to ")); + lim_print_mac_addr(pMac, peer, LOGW); + + if ((SIR_BAND_5_GHZ == lim_get_rf_band(psessionEntry->currentOperChannel)) + || (psessionEntry->pePersona == QDF_P2P_CLIENT_MODE) || + (psessionEntry->pePersona == QDF_P2P_GO_MODE) + ) { + txFlag |= HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME; + } + + MTRACE(qdf_trace(QDF_MODULE_ID_PE, TRACE_CODE_TX_MGMT, + psessionEntry->peSessionId, pMacHdr->fc.subType)); + qdf_status = wma_tx_frame(pMac, + pPacket, + (uint16_t) nBytes, + TXRX_FRM_802_11_MGMT, + ANI_TXDIR_TODS, + 7, lim_tx_complete, pFrame, txFlag, + smeSessionId, 0); + MTRACE(qdf_trace(QDF_MODULE_ID_PE, TRACE_CODE_TX_COMPLETE, + psessionEntry->peSessionId, qdf_status)); + if (QDF_STATUS_SUCCESS != qdf_status) { + PELOGE(lim_log + (pMac, LOGE, FL("wma_tx_frame FAILED! Status [%d]"), + qdf_status); + ) + statusCode = eSIR_FAILURE; + /* Pkt will be freed up by the callback */ + return statusCode; + } else + return eSIR_SUCCESS; + +returnAfterError: + cds_packet_free((void *)pPacket); + + return statusCode; +} /* End lim_send_neighbor_report_request_frame. */ + +/** + * \brief Send a Link Report Action frame + * + * + * \param pMac Pointer to the global MAC structure + * + * \param pLinkReport Address of a tSirMacLinkReport + * + * \param peer mac address of peer station. + * + * \param psessionEntry address of session entry. + * + * \return eSIR_SUCCESS on success, eSIR_FAILURE else + * + * + */ + +tSirRetStatus +lim_send_link_report_action_frame(tpAniSirGlobal pMac, + tpSirMacLinkReport pLinkReport, + tSirMacAddr peer, tpPESession psessionEntry) +{ + tSirRetStatus statusCode = eSIR_SUCCESS; + tDot11fLinkMeasurementReport frm; + uint8_t *pFrame; + tpSirMacMgmtHdr pMacHdr; + uint32_t nBytes, nPayload, nStatus; + void *pPacket; + QDF_STATUS qdf_status; + uint8_t txFlag = 0; + uint8_t smeSessionId = 0; + + if (psessionEntry == NULL) { + lim_log(pMac, LOGE, + FL + ("(psession == NULL) in Request to send Link Report action frame")); + return eSIR_FAILURE; + } + + qdf_mem_set((uint8_t *) &frm, sizeof(frm), 0); + + frm.Category.category = SIR_MAC_ACTION_RRM; + frm.Action.action = SIR_MAC_RRM_LINK_MEASUREMENT_RPT; + frm.DialogToken.token = pLinkReport->dialogToken; + + /* IEEE Std. 802.11 7.3.2.18. for the report element. */ + /* Even though TPC report an IE, it is represented using fixed fields since it is positioned */ + /* in the middle of other fixed fields in the link report frame(IEEE Std. 802.11k section7.4.6.4 */ + /* and frame parser always expects IEs to come after all fixed fields. It is easier to handle */ + /* such case this way than changing the frame parser. */ + frm.TPCEleID.TPCId = SIR_MAC_TPC_RPT_EID; + frm.TPCEleLen.TPCLen = 2; + frm.TxPower.txPower = pLinkReport->txPower; + frm.LinkMargin.linkMargin = 0; + + frm.RxAntennaId.antennaId = pLinkReport->rxAntenna; + frm.TxAntennaId.antennaId = pLinkReport->txAntenna; + frm.RCPI.rcpi = pLinkReport->rcpi; + frm.RSNI.rsni = pLinkReport->rsni; + + nStatus = + dot11f_get_packed_link_measurement_report_size(pMac, &frm, &nPayload); + if (DOT11F_FAILED(nStatus)) { + lim_log(pMac, LOGP, FL("Failed to calculate the packed size f" + "or a Link Report (0x%08x)."), nStatus); + /* We'll fall back on the worst case scenario: */ + nPayload = sizeof(tDot11fLinkMeasurementReport); + } else if (DOT11F_WARNED(nStatus)) { + lim_log(pMac, LOGW, FL("There were warnings while calculating " + "the packed size for a Link Rep" + "ort (0x%08x)."), nStatus); + } + + nBytes = nPayload + sizeof(tSirMacMgmtHdr); + + qdf_status = + cds_packet_alloc((uint16_t) nBytes, (void **)&pFrame, + (void **)&pPacket); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + lim_log(pMac, LOGP, FL("Failed to allocate %d bytes for a Link " + "Report."), nBytes); + return eSIR_FAILURE; + } + /* Paranoia: */ + qdf_mem_set(pFrame, nBytes, 0); + + /* Copy necessary info to BD */ + lim_populate_mac_header(pMac, pFrame, SIR_MAC_MGMT_FRAME, + SIR_MAC_MGMT_ACTION, peer, psessionEntry->selfMacAddr); + + /* Update A3 with the BSSID */ + pMacHdr = (tpSirMacMgmtHdr) pFrame; + + sir_copy_mac_addr(pMacHdr->bssId, psessionEntry->bssId); + +#ifdef WLAN_FEATURE_11W + lim_set_protected_bit(pMac, psessionEntry, peer, pMacHdr); +#endif + + /* Now, we're ready to "pack" the frames */ + nStatus = dot11f_pack_link_measurement_report(pMac, + &frm, + pFrame + + sizeof(tSirMacMgmtHdr), + nPayload, &nPayload); + + if (DOT11F_FAILED(nStatus)) { + lim_log(pMac, LOGE, + FL("Failed to pack an Link Report (0x%08x)."), nStatus); + + /* FIXME - Need to convert to tSirRetStatus */ + statusCode = eSIR_FAILURE; + goto returnAfterError; + } else if (DOT11F_WARNED(nStatus)) { + lim_log(pMac, LOGW, + FL + ("There were warnings while packing Link Report (0x%08x)."), + nStatus); + } + + lim_log(pMac, LOGW, FL("Sending a Link Report to ")); + lim_print_mac_addr(pMac, peer, LOGW); + + if ((SIR_BAND_5_GHZ == lim_get_rf_band(psessionEntry->currentOperChannel)) + || (psessionEntry->pePersona == QDF_P2P_CLIENT_MODE) || + (psessionEntry->pePersona == QDF_P2P_GO_MODE)) { + txFlag |= HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME; + } + + MTRACE(qdf_trace(QDF_MODULE_ID_PE, TRACE_CODE_TX_MGMT, + psessionEntry->peSessionId, pMacHdr->fc.subType)); + qdf_status = wma_tx_frame(pMac, + pPacket, + (uint16_t) nBytes, + TXRX_FRM_802_11_MGMT, + ANI_TXDIR_TODS, + 7, lim_tx_complete, pFrame, txFlag, + smeSessionId, 0); + MTRACE(qdf_trace(QDF_MODULE_ID_PE, TRACE_CODE_TX_COMPLETE, + psessionEntry->peSessionId, qdf_status)); + if (QDF_STATUS_SUCCESS != qdf_status) { + PELOGE(lim_log + (pMac, LOGE, FL("wma_tx_frame FAILED! Status [%d]"), + qdf_status); + ) + statusCode = eSIR_FAILURE; + /* Pkt will be freed up by the callback */ + return statusCode; + } else + return eSIR_SUCCESS; + +returnAfterError: + cds_packet_free((void *)pPacket); + + return statusCode; +} /* End lim_send_link_report_action_frame. */ + +/** + * \brief Send a Beacon Report Action frame + * + * + * \param pMac Pointer to the global MAC structure + * + * \param dialog_token dialog token to be used in the action frame. + * + * \param num_report number of reports in pRRMReport. + * + * \param pRRMReport Address of a tSirMacRadioMeasureReport. + * + * \param peer mac address of peer station. + * + * \param psessionEntry address of session entry. + * + * \return eSIR_SUCCESS on success, eSIR_FAILURE else + * + * + */ + +tSirRetStatus +lim_send_radio_measure_report_action_frame(tpAniSirGlobal pMac, + uint8_t dialog_token, + uint8_t num_report, + tpSirMacRadioMeasureReport pRRMReport, + tSirMacAddr peer, + tpPESession psessionEntry) +{ + tSirRetStatus statusCode = eSIR_SUCCESS; + uint8_t *pFrame; + tpSirMacMgmtHdr pMacHdr; + uint32_t nBytes, nPayload, nStatus; + void *pPacket; + QDF_STATUS qdf_status; + uint8_t i; + uint8_t txFlag = 0; + uint8_t smeSessionId = 0; + + tDot11fRadioMeasurementReport *frm = + qdf_mem_malloc(sizeof(tDot11fRadioMeasurementReport)); + if (!frm) { + lim_log(pMac, LOGE, + FL + ("Not enough memory to allocate tDot11fRadioMeasurementReport")); + return eSIR_MEM_ALLOC_FAILED; + } + + if (psessionEntry == NULL) { + lim_log(pMac, LOGE, + FL + ("(psession == NULL) in Request to send Beacon Report action frame")); + qdf_mem_free(frm); + return eSIR_FAILURE; + } + + lim_log(pMac, LOG1, FL("dialog_token %d num_report %d"), + dialog_token, num_report); + + frm->Category.category = SIR_MAC_ACTION_RRM; + frm->Action.action = SIR_MAC_RRM_RADIO_MEASURE_RPT; + frm->DialogToken.token = dialog_token; + + frm->num_MeasurementReport = + (num_report > + RADIO_REPORTS_MAX_IN_A_FRAME) ? RADIO_REPORTS_MAX_IN_A_FRAME : + num_report; + + for (i = 0; i < frm->num_MeasurementReport; i++) { + frm->MeasurementReport[i].type = pRRMReport[i].type; + frm->MeasurementReport[i].token = pRRMReport[i].token; + frm->MeasurementReport[i].late = 0; /* IEEE 802.11k section 7.3.22. (always zero in rrm) */ + switch (pRRMReport[i].type) { + case SIR_MAC_RRM_BEACON_TYPE: + populate_dot11f_beacon_report(pMac, + &frm->MeasurementReport[i], + &pRRMReport[i].report. + beaconReport); + frm->MeasurementReport[i].incapable = + pRRMReport[i].incapable; + frm->MeasurementReport[i].refused = + pRRMReport[i].refused; + frm->MeasurementReport[i].present = 1; + break; + default: + frm->MeasurementReport[i].incapable = + pRRMReport[i].incapable; + frm->MeasurementReport[i].refused = + pRRMReport[i].refused; + frm->MeasurementReport[i].present = 1; + break; + } + } + + nStatus = + dot11f_get_packed_radio_measurement_report_size(pMac, frm, &nPayload); + if (DOT11F_FAILED(nStatus)) { + lim_log(pMac, LOGP, FL("Failed to calculate the packed size f" + "or a Radio Measure Report (0x%08x)."), + nStatus); + /* We'll fall back on the worst case scenario: */ + nPayload = sizeof(tDot11fLinkMeasurementReport); + qdf_mem_free(frm); + return eSIR_FAILURE; + } else if (DOT11F_WARNED(nStatus)) { + lim_log(pMac, LOGW, FL("There were warnings while calculating " + "the packed size for a Radio Measure Rep" + "ort (0x%08x)."), nStatus); + } + + nBytes = nPayload + sizeof(tSirMacMgmtHdr); + + qdf_status = + cds_packet_alloc((uint16_t) nBytes, (void **)&pFrame, + (void **)&pPacket); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + lim_log(pMac, LOGP, + FL("Failed to allocate %d bytes for a Radio Measure " + "Report."), nBytes); + qdf_mem_free(frm); + return eSIR_FAILURE; + } + /* Paranoia: */ + qdf_mem_set(pFrame, nBytes, 0); + + /* Copy necessary info to BD */ + lim_populate_mac_header(pMac, pFrame, SIR_MAC_MGMT_FRAME, + SIR_MAC_MGMT_ACTION, peer, psessionEntry->selfMacAddr); + + /* Update A3 with the BSSID */ + pMacHdr = (tpSirMacMgmtHdr) pFrame; + + sir_copy_mac_addr(pMacHdr->bssId, psessionEntry->bssId); + +#ifdef WLAN_FEATURE_11W + lim_set_protected_bit(pMac, psessionEntry, peer, pMacHdr); +#endif + + /* Now, we're ready to "pack" the frames */ + nStatus = dot11f_pack_radio_measurement_report(pMac, + frm, + pFrame + + sizeof(tSirMacMgmtHdr), + nPayload, &nPayload); + + if (DOT11F_FAILED(nStatus)) { + lim_log(pMac, LOGE, + FL("Failed to pack an Radio Measure Report (0x%08x)."), + nStatus); + + /* FIXME - Need to convert to tSirRetStatus */ + statusCode = eSIR_FAILURE; + goto returnAfterError; + } else if (DOT11F_WARNED(nStatus)) { + lim_log(pMac, LOGW, + FL("There were warnings while packing Radio " + "Measure Report (0x%08x)."), nStatus); + } + + lim_log(pMac, LOGW, FL("Sending a Radio Measure Report to ")); + lim_print_mac_addr(pMac, peer, LOGW); + + if ((SIR_BAND_5_GHZ == lim_get_rf_band(psessionEntry->currentOperChannel)) + || (psessionEntry->pePersona == QDF_P2P_CLIENT_MODE) || + (psessionEntry->pePersona == QDF_P2P_GO_MODE) + ) { + txFlag |= HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME; + } + + MTRACE(qdf_trace(QDF_MODULE_ID_PE, TRACE_CODE_TX_MGMT, + psessionEntry->peSessionId, pMacHdr->fc.subType)); + qdf_status = wma_tx_frame(pMac, + pPacket, + (uint16_t) nBytes, + TXRX_FRM_802_11_MGMT, + ANI_TXDIR_TODS, + 7, lim_tx_complete, pFrame, txFlag, + smeSessionId, 0); + MTRACE(qdf_trace(QDF_MODULE_ID_PE, TRACE_CODE_TX_COMPLETE, + psessionEntry->peSessionId, qdf_status)); + if (QDF_STATUS_SUCCESS != qdf_status) { + PELOGE(lim_log + (pMac, LOGE, FL("wma_tx_frame FAILED! Status [%d]"), + qdf_status); + ) + statusCode = eSIR_FAILURE; + /* Pkt will be freed up by the callback */ + qdf_mem_free(frm); + return statusCode; + } else { + qdf_mem_free(frm); + return eSIR_SUCCESS; + } + +returnAfterError: + qdf_mem_free(frm); + cds_packet_free((void *)pPacket); + return statusCode; +} + +#ifdef WLAN_FEATURE_11W +/** + * \brief Send SA query request action frame to peer + * + * \sa lim_send_sa_query_request_frame + * + * + * \param pMac The global tpAniSirGlobal object + * + * \param transId Transaction identifier + * + * \param peer The Mac address of the station to which this action frame is addressed + * + * \param psessionEntry The PE session entry + * + * \return eSIR_SUCCESS if setup completes successfully + * eSIR_FAILURE is some problem is encountered + */ + +tSirRetStatus lim_send_sa_query_request_frame(tpAniSirGlobal pMac, uint8_t *transId, + tSirMacAddr peer, + tpPESession psessionEntry) +{ + + tDot11fSaQueryReq frm; /* SA query request action frame */ + uint8_t *pFrame; + tSirRetStatus nSirStatus; + tpSirMacMgmtHdr pMacHdr; + uint32_t nBytes, nPayload, nStatus; + void *pPacket; + QDF_STATUS qdf_status; + uint8_t txFlag = 0; + uint8_t smeSessionId = 0; + + qdf_mem_set((uint8_t *) &frm, sizeof(frm), 0); + frm.Category.category = SIR_MAC_ACTION_SA_QUERY; + /* 11w action field is : + action: 0 --> SA Query Request action frame + action: 1 --> SA Query Response action frame */ + frm.Action.action = SIR_MAC_SA_QUERY_REQ; + /* 11w SA Query Request transId */ + qdf_mem_copy(&frm.TransactionId.transId[0], &transId[0], 2); + + nStatus = dot11f_get_packed_sa_query_req_size(pMac, &frm, &nPayload); + if (DOT11F_FAILED(nStatus)) { + lim_log(pMac, LOGP, FL("Failed to calculate the packed size " + "for an SA Query Request (0x%08x)."), + nStatus); + /* We'll fall back on the worst case scenario: */ + nPayload = sizeof(tDot11fSaQueryReq); + } else if (DOT11F_WARNED(nStatus)) { + lim_log(pMac, LOGW, FL("There were warnings while calculating " + "the packed size for an SA Query Request" + " (0x%08x)."), nStatus); + } + + nBytes = nPayload + sizeof(tSirMacMgmtHdr); + qdf_status = + cds_packet_alloc(nBytes, (void **)&pFrame, (void **)&pPacket); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + lim_log(pMac, LOGP, + FL("Failed to allocate %d bytes for a SA Query Request " + "action frame"), nBytes); + return eSIR_FAILURE; + } + /* Paranoia: */ + qdf_mem_set(pFrame, nBytes, 0); + + /* Copy necessary info to BD */ + lim_populate_mac_header(pMac, pFrame, SIR_MAC_MGMT_FRAME, + SIR_MAC_MGMT_ACTION, peer, psessionEntry->selfMacAddr); + + /* Update A3 with the BSSID */ + pMacHdr = (tpSirMacMgmtHdr) pFrame; + + sir_copy_mac_addr(pMacHdr->bssId, psessionEntry->bssId); + + /* Since this is a SA Query Request, set the "protect" (aka WEP) bit */ + /* in the FC */ + lim_set_protected_bit(pMac, psessionEntry, peer, pMacHdr); + + /* Pack 11w SA Query Request frame */ + nStatus = dot11f_pack_sa_query_req(pMac, + &frm, + pFrame + sizeof(tSirMacMgmtHdr), + nPayload, &nPayload); + + if (DOT11F_FAILED(nStatus)) { + lim_log(pMac, LOGE, + FL("Failed to pack an SA Query Request (0x%08x)."), + nStatus); + /* FIXME - Need to convert to tSirRetStatus */ + nSirStatus = eSIR_FAILURE; + goto returnAfterError; + } else if (DOT11F_WARNED(nStatus)) { + lim_log(pMac, LOGW, + FL + ("There were warnings while packing SA Query Request (0x%08x)."), + nStatus); + } + + lim_log(pMac, LOG1, FL("Sending an SA Query Request to ")); + lim_print_mac_addr(pMac, peer, LOG1); + lim_log(pMac, LOG1, FL("Sending an SA Query Request from ")); + lim_print_mac_addr(pMac, psessionEntry->selfMacAddr, LOG1); + + if ((SIR_BAND_5_GHZ == lim_get_rf_band(psessionEntry->currentOperChannel)) +#ifdef WLAN_FEATURE_P2P + || (psessionEntry->pePersona == QDF_P2P_CLIENT_MODE) || + (psessionEntry->pePersona == QDF_P2P_GO_MODE) +#endif + ) { + txFlag |= HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME; + } + smeSessionId = psessionEntry->smeSessionId; + + qdf_status = wma_tx_frame(pMac, + pPacket, + (uint16_t) nBytes, + TXRX_FRM_802_11_MGMT, + ANI_TXDIR_TODS, + 7, lim_tx_complete, pFrame, txFlag, + smeSessionId, 0); + if (QDF_STATUS_SUCCESS != qdf_status) { + PELOGE(lim_log + (pMac, LOGE, FL("wma_tx_frame FAILED! Status [%d]"), + qdf_status); + ) + nSirStatus = eSIR_FAILURE; + /* Pkt will be freed up by the callback */ + return nSirStatus; + } else { + return eSIR_SUCCESS; + } + +returnAfterError: + cds_packet_free((void *)pPacket); + return nSirStatus; +} /* End lim_send_sa_query_request_frame */ + +/** + * \brief Send SA query response action frame to peer + * + * \sa lim_send_sa_query_response_frame + * + * + * \param pMac The global tpAniSirGlobal object + * + * \param transId Transaction identifier received in SA query request action frame + * + * \param peer The Mac address of the AP to which this action frame is addressed + * + * \param psessionEntry The PE session entry + * + * \return eSIR_SUCCESS if setup completes successfully + * eSIR_FAILURE is some problem is encountered + */ + +tSirRetStatus lim_send_sa_query_response_frame(tpAniSirGlobal pMac, + uint8_t *transId, tSirMacAddr peer, + tpPESession psessionEntry) +{ + + tDot11fSaQueryRsp frm; /* SA query reponse action frame */ + uint8_t *pFrame; + tSirRetStatus nSirStatus; + tpSirMacMgmtHdr pMacHdr; + uint32_t nBytes, nPayload, nStatus; + void *pPacket; + QDF_STATUS qdf_status; + uint8_t txFlag = 0; + uint8_t smeSessionId = 0; + + smeSessionId = psessionEntry->smeSessionId; + + qdf_mem_set((uint8_t *) &frm, sizeof(frm), 0); + frm.Category.category = SIR_MAC_ACTION_SA_QUERY; + /*11w action field is : + action: 0 --> SA query request action frame + action: 1 --> SA query response action frame */ + frm.Action.action = SIR_MAC_SA_QUERY_RSP; + /*11w SA query response transId is same as + SA query request transId */ + qdf_mem_copy(&frm.TransactionId.transId[0], &transId[0], 2); + + nStatus = dot11f_get_packed_sa_query_rsp_size(pMac, &frm, &nPayload); + if (DOT11F_FAILED(nStatus)) { + lim_log(pMac, LOGP, FL("Failed to calculate the packed size f" + "or a SA Query Response (0x%08x)."), + nStatus); + /* We'll fall back on the worst case scenario: */ + nPayload = sizeof(tDot11fSaQueryRsp); + } else if (DOT11F_WARNED(nStatus)) { + lim_log(pMac, LOGW, FL("There were warnings while calculating " + "the packed size for an SA Query Response" + " (0x%08x)."), nStatus); + } + + nBytes = nPayload + sizeof(tSirMacMgmtHdr); + qdf_status = + cds_packet_alloc(nBytes, (void **)&pFrame, (void **)&pPacket); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + lim_log(pMac, LOGP, + FL("Failed to allocate %d bytes for a SA query response" + " action frame"), nBytes); + return eSIR_FAILURE; + } + /* Paranoia: */ + qdf_mem_set(pFrame, nBytes, 0); + + /* Copy necessary info to BD */ + lim_populate_mac_header(pMac, pFrame, SIR_MAC_MGMT_FRAME, + SIR_MAC_MGMT_ACTION, peer, psessionEntry->selfMacAddr); + + /* Update A3 with the BSSID */ + pMacHdr = (tpSirMacMgmtHdr) pFrame; + + sir_copy_mac_addr(pMacHdr->bssId, psessionEntry->bssId); + + /* Since this is a SA Query Response, set the "protect" (aka WEP) bit */ + /* in the FC */ + lim_set_protected_bit(pMac, psessionEntry, peer, pMacHdr); + + /* Pack 11w SA query response frame */ + nStatus = dot11f_pack_sa_query_rsp(pMac, + &frm, + pFrame + sizeof(tSirMacMgmtHdr), + nPayload, &nPayload); + + if (DOT11F_FAILED(nStatus)) { + lim_log(pMac, LOGE, + FL("Failed to pack an SA Query Response (0x%08x)."), + nStatus); + /* FIXME - Need to convert to tSirRetStatus */ + nSirStatus = eSIR_FAILURE; + goto returnAfterError; + } else if (DOT11F_WARNED(nStatus)) { + lim_log(pMac, LOGW, + FL + ("There were warnings while packing SA Query Response (0x%08x)."), + nStatus); + } + + lim_log(pMac, LOG1, FL("Sending a SA Query Response to ")); + lim_print_mac_addr(pMac, peer, LOGW); + + if ((SIR_BAND_5_GHZ == lim_get_rf_band(psessionEntry->currentOperChannel)) +#ifdef WLAN_FEATURE_P2P + || (psessionEntry->pePersona == QDF_P2P_CLIENT_MODE) || + (psessionEntry->pePersona == QDF_P2P_GO_MODE) +#endif + ) { + txFlag |= HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME; + } + + MTRACE(qdf_trace(QDF_MODULE_ID_PE, TRACE_CODE_TX_MGMT, + psessionEntry->peSessionId, pMacHdr->fc.subType)); + qdf_status = wma_tx_frame(pMac, + pPacket, + (uint16_t) nBytes, + TXRX_FRM_802_11_MGMT, + ANI_TXDIR_TODS, + 7, lim_tx_complete, pFrame, txFlag, + smeSessionId, 0); + MTRACE(qdf_trace(QDF_MODULE_ID_PE, TRACE_CODE_TX_COMPLETE, + psessionEntry->peSessionId, qdf_status)); + if (QDF_STATUS_SUCCESS != qdf_status) { + PELOGE(lim_log + (pMac, LOGE, FL("wma_tx_frame FAILED! Status [%d]"), + qdf_status); + ) + nSirStatus = eSIR_FAILURE; + /* Pkt will be freed up by the callback */ + return nSirStatus; + } else { + return eSIR_SUCCESS; + } + +returnAfterError: + cds_packet_free((void *)pPacket); + return nSirStatus; +} /* End lim_send_sa_query_response_frame */ +#endif diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_send_messages.c b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_send_messages.c new file mode 100644 index 0000000000000000000000000000000000000000..3adc595dd331b694856e633af99d6858180729c2 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_send_messages.c @@ -0,0 +1,930 @@ +/* + * Copyright (c) 2011-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * + * lim_send_messages.c: Provides functions to send messages or Indications to HAL. + * Author: Sunit Bhatia + * Date: 09/21/2006 + * History:- + * Date Modified by Modification Information + * + * -------------------------------------------------------------------------- + * + */ +#include "lim_send_messages.h" +#include "cfg_api.h" +#include "lim_trace.h" +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM /* FEATURE_WLAN_DIAG_SUPPORT */ +#include "host_diag_core_log.h" +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + +/* When beacon filtering is enabled, firmware will + * analyze the selected beacons received during BMPS, + * and monitor any changes in the IEs as listed below. + * The format of the table is: + * - EID + * - Check for IE presence + * - Byte offset + * - Byte value + * - Bit Mask + * - Byte refrence + */ +static tBeaconFilterIe beacon_filter_table[] = { + {SIR_MAC_DS_PARAM_SET_EID, 0, {0, 0, DS_PARAM_CHANNEL_MASK, 0} }, + {SIR_MAC_ERP_INFO_EID, 0, {0, 0, ERP_FILTER_MASK, 0} }, + {SIR_MAC_EDCA_PARAM_SET_EID, 0, {0, 0, EDCA_FILTER_MASK, 0} }, + {SIR_MAC_QOS_CAPABILITY_EID, 0, {0, 0, QOS_FILTER_MASK, 0} }, + {SIR_MAC_CHNL_SWITCH_ANN_EID, 1, {0, 0, 0, 0} }, + {SIR_MAC_HT_INFO_EID, 0, {0, 0, HT_BYTE0_FILTER_MASK, 0} }, + {SIR_MAC_HT_INFO_EID, 0, {2, 0, HT_BYTE2_FILTER_MASK, 0} }, + {SIR_MAC_HT_INFO_EID, 0, {5, 0, HT_BYTE5_FILTER_MASK, 0} }, + {SIR_MAC_PWR_CONSTRAINT_EID, 0, {0, 0, 0, 0} }, + {SIR_MAC_VHT_OPMODE_EID, 0, {0, 0, 0, 0} }, + {SIR_MAC_VHT_OPERATION_EID, 0, {0, 0, VHTOP_CHWIDTH_MASK, 0} } +}; + +/** + * lim_send_cf_params() + * + ***FUNCTION: + * This function is called to send CFP Parameters to WMA, when they are changed. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param pMac pointer to Global Mac structure. + * @param bssIdx Bss Index of the BSS to which STA is associated. + * @param cfpCount CFP Count, if that is changed. + * @param cfpPeriod CFP Period if that is changed. + * + * @return success if message send is ok, else false. + */ +tSirRetStatus lim_send_cf_params(tpAniSirGlobal pMac, uint8_t bssIdx, + uint8_t cfpCount, uint8_t cfpPeriod) +{ + tpUpdateCFParams pCFParams = NULL; + tSirRetStatus retCode = eSIR_SUCCESS; + tSirMsgQ msgQ; + + pCFParams = qdf_mem_malloc(sizeof(tUpdateCFParams)); + if (NULL == pCFParams) { + lim_log(pMac, LOGP, + FL("Unable to allocate memory during Update CF Params")); + retCode = eSIR_MEM_ALLOC_FAILED; + goto returnFailure; + } + pCFParams->cfpCount = cfpCount; + pCFParams->cfpPeriod = cfpPeriod; + pCFParams->bssIdx = bssIdx; + + msgQ.type = WMA_UPDATE_CF_IND; + msgQ.reserved = 0; + msgQ.bodyptr = pCFParams; + msgQ.bodyval = 0; + lim_log(pMac, LOG3, FL("Sending WMA_UPDATE_CF_IND...")); + MTRACE(mac_trace_msg_tx(pMac, NO_SESSION, msgQ.type)); + retCode = wma_post_ctrl_msg(pMac, &msgQ); + if (eSIR_SUCCESS != retCode) { + qdf_mem_free(pCFParams); + lim_log(pMac, LOGP, + FL("Posting WMA_UPDATE_CF_IND failed, reason=%X"), + retCode); + } +returnFailure: + return retCode; +} + +/** + * lim_send_beacon_params() - updates bcn params to WMA + * + * @pMac : pointer to Global Mac structure. + * @tpUpdateBeaconParams : pointer to the structure, which contains the beacon + * parameters which are changed. + * + * This function is called to send beacon interval, short preamble or other + * parameters to WMA, which are changed and indication is received in beacon. + * + * @return success if message send is ok, else false. + */ +tSirRetStatus lim_send_beacon_params(tpAniSirGlobal pMac, + tpUpdateBeaconParams pUpdatedBcnParams, + tpPESession psessionEntry) +{ + tpUpdateBeaconParams pBcnParams = NULL; + tSirRetStatus retCode = eSIR_SUCCESS; + tSirMsgQ msgQ; + + pBcnParams = qdf_mem_malloc(sizeof(*pBcnParams)); + if (NULL == pBcnParams) { + lim_log(pMac, LOGP, + FL("Unable to allocate memory during Update Beacon Params")); + return eSIR_MEM_ALLOC_FAILED; + } + qdf_mem_copy((uint8_t *) pBcnParams, pUpdatedBcnParams, + sizeof(*pBcnParams)); + msgQ.type = WMA_UPDATE_BEACON_IND; + msgQ.reserved = 0; + msgQ.bodyptr = pBcnParams; + msgQ.bodyval = 0; + PELOG3(lim_log(pMac, LOG3, + FL("Sending WMA_UPDATE_BEACON_IND, paramChangeBitmap in hex = %x"), + pUpdatedBcnParams->paramChangeBitmap);) + if (NULL == psessionEntry) { + qdf_mem_free(pBcnParams); + MTRACE(mac_trace_msg_tx(pMac, NO_SESSION, msgQ.type)); + return eSIR_FAILURE; + } else { + MTRACE(mac_trace_msg_tx(pMac, + psessionEntry->peSessionId, + msgQ.type)); + } + pBcnParams->smeSessionId = psessionEntry->smeSessionId; + retCode = wma_post_ctrl_msg(pMac, &msgQ); + if (eSIR_SUCCESS != retCode) { + qdf_mem_free(pBcnParams); + lim_log(pMac, LOGP, + FL("Posting WMA_UPDATE_BEACON_IND, reason=%X"), + retCode); + } + lim_send_beacon_ind(pMac, psessionEntry); + return retCode; +} + +/** + * lim_send_switch_chnl_params() + * + ***FUNCTION: + * This function is called to send Channel Switch Indication to WMA + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param pMac pointer to Global Mac structure. + * @param chnlNumber New Channel Number to be switched to. + * @param ch_width an enum for channel width. + * @param localPowerConstraint 11h local power constraint value + * + * @return success if message send is ok, else false. + */ +tSirRetStatus lim_send_switch_chnl_params(tpAniSirGlobal pMac, + uint8_t chnlNumber, + uint8_t ch_center_freq_seg0, + uint8_t ch_center_freq_seg1, + enum phy_ch_width ch_width, + int8_t maxTxPower, + uint8_t peSessionId, + uint8_t is_restart) +{ + tpSwitchChannelParams pChnlParams = NULL; + tSirMsgQ msgQ; + tpPESession pSessionEntry; + pSessionEntry = pe_find_session_by_session_id(pMac, peSessionId); + if (pSessionEntry == NULL) { + lim_log(pMac, LOGP, FL( + "Unable to get Session for session Id %d"), + peSessionId); + return eSIR_FAILURE; + } + pChnlParams = qdf_mem_malloc(sizeof(tSwitchChannelParams)); + if (NULL == pChnlParams) { + lim_log(pMac, LOGP, FL( + "Unable to allocate memory for Switch Ch Params")); + return eSIR_MEM_ALLOC_FAILED; + } + pChnlParams->channelNumber = chnlNumber; + pChnlParams->ch_center_freq_seg0 = ch_center_freq_seg0; + pChnlParams->ch_center_freq_seg1 = ch_center_freq_seg1; + pChnlParams->ch_width = ch_width; + qdf_mem_copy(pChnlParams->selfStaMacAddr, pSessionEntry->selfMacAddr, + sizeof(tSirMacAddr)); + pChnlParams->maxTxPower = maxTxPower; + qdf_mem_copy(pChnlParams->bssId, pSessionEntry->bssId, + sizeof(tSirMacAddr)); + pChnlParams->peSessionId = peSessionId; + pChnlParams->vhtCapable = pSessionEntry->vhtCapability; + pChnlParams->dot11_mode = pSessionEntry->dot11mode; + pChnlParams->nss = pSessionEntry->nss; + lim_log(pMac, LOG2, FL("nss value: %d"), pChnlParams->nss); + + /*Set DFS flag for DFS channel */ + if (ch_width == CH_WIDTH_160MHZ) { + pChnlParams->isDfsChannel = true; + } else if (ch_width == CH_WIDTH_80P80MHZ) { + pChnlParams->isDfsChannel = false; + if (cds_get_channel_state(chnlNumber) == CHANNEL_STATE_DFS || + cds_get_channel_state(pChnlParams->ch_center_freq_seg1 - + SIR_80MHZ_START_CENTER_CH_DIFF) == + CHANNEL_STATE_DFS) + pChnlParams->isDfsChannel = true; + } else { + if (cds_get_channel_state(chnlNumber) == CHANNEL_STATE_DFS) + pChnlParams->isDfsChannel = true; + else + pChnlParams->isDfsChannel = false; + } + + pChnlParams->restart_on_chan_switch = is_restart; + + if (cds_is_5_mhz_enabled()) + pChnlParams->ch_width = CH_WIDTH_5MHZ; + else if (cds_is_10_mhz_enabled()) + pChnlParams->ch_width = CH_WIDTH_10MHZ; + + /* we need to defer the message until we + * get the response back from WMA + */ + SET_LIM_PROCESS_DEFD_MESGS(pMac, false); + msgQ.type = WMA_CHNL_SWITCH_REQ; + msgQ.reserved = 0; + msgQ.bodyptr = pChnlParams; + msgQ.bodyval = 0; + PELOG3(lim_log(pMac, LOG3, FL( + "Sending CH_SWITCH_REQ, ch_width %d, ch_num %d, maxTxPower %d"), + pChnlParams->ch_width, + pChnlParams->channelNumber, pChnlParams->maxTxPower);) + MTRACE(mac_trace_msg_tx(pMac, peSessionId, msgQ.type)); + if (eSIR_SUCCESS != wma_post_ctrl_msg(pMac, &msgQ)) { + qdf_mem_free(pChnlParams); + lim_log(pMac, LOGP, FL( + "Posting CH_SWITCH_REQ to WMA failed")); + return eSIR_FAILURE; + } + pSessionEntry->ch_switch_in_progress = true; + return eSIR_SUCCESS; +} + +/** + * lim_send_edca_params() + * + ***FUNCTION: + * This function is called to send dynamically changing EDCA Parameters to WMA. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param pMac pointer to Global Mac structure. + * @param tpUpdatedEdcaParams pointer to the structure which contains + * dynamically changing EDCA parameters. + * @param highPerformance If the peer is Airgo (taurus) then switch to highPerformance is true. + * + * @return success if message send is ok, else false. + */ +tSirRetStatus lim_send_edca_params(tpAniSirGlobal pMac, + tSirMacEdcaParamRecord *pUpdatedEdcaParams, + uint16_t bssIdx) +{ + tEdcaParams *pEdcaParams = NULL; + tSirRetStatus retCode = eSIR_SUCCESS; + tSirMsgQ msgQ; + uint8_t i; + + pEdcaParams = qdf_mem_malloc(sizeof(tEdcaParams)); + if (NULL == pEdcaParams) { + lim_log(pMac, LOGP, + FL("Unable to allocate memory during Update EDCA Params")); + retCode = eSIR_MEM_ALLOC_FAILED; + return retCode; + } + pEdcaParams->bssIdx = bssIdx; + pEdcaParams->acbe = pUpdatedEdcaParams[EDCA_AC_BE]; + pEdcaParams->acbk = pUpdatedEdcaParams[EDCA_AC_BK]; + pEdcaParams->acvi = pUpdatedEdcaParams[EDCA_AC_VI]; + pEdcaParams->acvo = pUpdatedEdcaParams[EDCA_AC_VO]; + msgQ.type = WMA_UPDATE_EDCA_PROFILE_IND; + msgQ.reserved = 0; + msgQ.bodyptr = pEdcaParams; + msgQ.bodyval = 0; + PELOG1(lim_log(pMac, LOG1, + FL("Sending WMA_UPDATE_EDCA_PROFILE_IND, EDCA Parameters:"));) + for (i = 0; i < MAX_NUM_AC; i++) { + PELOG1(lim_log(pMac, LOG1, + FL("AC[%d]: AIFSN %d, ACM %d, CWmin %d, CWmax %d, TxOp %d "), + i, pUpdatedEdcaParams[i].aci.aifsn, + pUpdatedEdcaParams[i].aci.acm, + pUpdatedEdcaParams[i].cw.min, + pUpdatedEdcaParams[i].cw.max, + pUpdatedEdcaParams[i].txoplimit);) + } + MTRACE(mac_trace_msg_tx(pMac, NO_SESSION, msgQ.type)); + retCode = wma_post_ctrl_msg(pMac, &msgQ); + if (eSIR_SUCCESS != retCode) { + qdf_mem_free(pEdcaParams); + lim_log(pMac, LOGP, + FL("Posting WMA_UPDATE_EDCA_PROFILE_IND failed, reason=%X"), + retCode); + } + return retCode; +} + +/** + * lim_set_active_edca_params() - Choose best EDCA parameters + * + * @mac_ctx: pointer to Global Mac structure. + * @edca_params: pointer to the local EDCA parameters + * @pe_session: point to the session entry + * + * This function is called to set the most up-to-date EDCA parameters + * given the default local EDCA parameters. The rules are as following: + * - If ACM bit is set for all ACs, then downgrade everything to Best Effort. + * - If ACM is not set for any AC, then PE will use the default EDCA + * parameters as advertised by AP. + * - If ACM is set in any of the ACs, PE will use the EDCA parameters + * from the next best AC for which ACM is not enabled. + * + * Return: none + */ + +void lim_set_active_edca_params(tpAniSirGlobal mac_ctx, + tSirMacEdcaParamRecord *edca_params, + tpPESession pe_session) +{ + uint8_t ac, new_ac, i; + uint8_t ac_admitted; +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM /* FEATURE_WLAN_DIAG_SUPPORT */ + host_log_qos_edca_pkt_type *log_ptr = NULL; +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + /* Initialize gLimEdcaParamsActive[] to be same as localEdcaParams */ + pe_session->gLimEdcaParamsActive[EDCA_AC_BE] = edca_params[EDCA_AC_BE]; + pe_session->gLimEdcaParamsActive[EDCA_AC_BK] = edca_params[EDCA_AC_BK]; + pe_session->gLimEdcaParamsActive[EDCA_AC_VI] = edca_params[EDCA_AC_VI]; + pe_session->gLimEdcaParamsActive[EDCA_AC_VO] = edca_params[EDCA_AC_VO]; + /* An AC requires downgrade if the ACM bit is set, and the AC has not + * yet been admitted in uplink or bi-directions. + * If an AC requires downgrade, it will downgrade to the next beset AC + * for which ACM is not enabled. + * + * - There's no need to downgrade AC_BE since it IS the lowest AC. Hence + * start the for loop with AC_BK. + * - If ACM bit is set for an AC, initially downgrade it to AC_BE. Then + * traverse thru the AC list. If we do find the next best AC which is + * better than AC_BE, then use that one. For example, if ACM bits are set + * such that: BE_ACM=1, BK_ACM=1, VI_ACM=1, VO_ACM=0 + * then all AC will be downgraded to AC_BE. + */ + lim_log(mac_ctx, LOG1, FL("adAdmitMask[UPLINK] = 0x%x "), + pe_session->gAcAdmitMask[SIR_MAC_DIRECTION_UPLINK]); + lim_log(mac_ctx, LOG1, FL("adAdmitMask[DOWNLINK] = 0x%x "), + pe_session->gAcAdmitMask[SIR_MAC_DIRECTION_DNLINK]); + for (ac = EDCA_AC_BK; ac <= EDCA_AC_VO; ac++) { + ac_admitted = + ((pe_session->gAcAdmitMask[SIR_MAC_DIRECTION_UPLINK] & + (1 << ac)) >> ac); + + lim_log(mac_ctx, LOG1, + FL("For AC[%d]: acm=%d, ac_admitted=%d "), + ac, edca_params[ac].aci.acm, ac_admitted); + if ((edca_params[ac].aci.acm == 1) && (ac_admitted == 0)) { + lim_log(mac_ctx, LOG1, + FL("We need to downgrade AC %d!! "), ac); + /* Loop backwards through AC values until it finds + * acm == 0 or reaches EDCA_AC_BE. + * Note that for block has no executable statements. + */ + for (i = ac - 1; + (i > EDCA_AC_BE && + (edca_params[i].aci.acm != 0)); + i--) + ; + new_ac = i; + lim_log(mac_ctx, LOGW, + FL("Downgrading AC %d ---> AC %d "), + ac, new_ac); + pe_session->gLimEdcaParamsActive[ac] = + edca_params[new_ac]; + } + } +/* log: LOG_WLAN_QOS_EDCA_C */ +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM /* FEATURE_WLAN_DIAG_SUPPORT */ + WLAN_HOST_DIAG_LOG_ALLOC(log_ptr, host_log_qos_edca_pkt_type, + LOG_WLAN_QOS_EDCA_C); + if (log_ptr) { + tSirMacEdcaParamRecord *rec; + + rec = &pe_session->gLimEdcaParamsActive[EDCA_AC_BE]; + log_ptr->aci_be = rec->aci.aci; + log_ptr->cw_be = rec->cw.max << 4 | rec->cw.min; + log_ptr->txoplimit_be = rec->txoplimit; + + rec = &pe_session->gLimEdcaParamsActive[EDCA_AC_BK]; + log_ptr->aci_bk = rec->aci.aci; + log_ptr->cw_bk = rec->cw.max << 4 | rec->cw.min; + log_ptr->txoplimit_bk = rec->txoplimit; + + rec = &pe_session->gLimEdcaParamsActive[EDCA_AC_VI]; + log_ptr->aci_vi = rec->aci.aci; + log_ptr->cw_vi = rec->cw.max << 4 | rec->cw.min; + log_ptr->txoplimit_vi = rec->txoplimit; + + rec = &pe_session->gLimEdcaParamsActive[EDCA_AC_VO]; + log_ptr->aci_vo = rec->aci.aci; + log_ptr->cw_vo = rec->cw.max << 4 | rec->cw.min; + log_ptr->txoplimit_vo = rec->txoplimit; + } + WLAN_HOST_DIAG_LOG_REPORT(log_ptr); +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + + return; +} + +/** --------------------------------------------------------- + \fn lim_set_link_state + \brief LIM sends a message to WMA to set the link state + \param tpAniSirGlobal pMac + \param tSirLinkState state + \return None + -----------------------------------------------------------*/ +tSirRetStatus lim_set_link_state(tpAniSirGlobal pMac, tSirLinkState state, + tSirMacAddr bssId, tSirMacAddr selfMacAddr, + tpSetLinkStateCallback callback, + void *callbackArg) +{ + tSirMsgQ msgQ; + tSirRetStatus retCode; + tpLinkStateParams pLinkStateParams = NULL; + /* Allocate memory. */ + pLinkStateParams = qdf_mem_malloc(sizeof(tLinkStateParams)); + if (NULL == pLinkStateParams) { + lim_log(pMac, LOGP, + FL + ("Unable to allocate memory while sending Set Link State")); + retCode = eSIR_MEM_ALLOC_FAILED; + return retCode; + } + pLinkStateParams->state = state; + pLinkStateParams->callback = callback; + pLinkStateParams->callbackArg = callbackArg; + + /* Copy Mac address */ + sir_copy_mac_addr(pLinkStateParams->bssid, bssId); + sir_copy_mac_addr(pLinkStateParams->selfMacAddr, selfMacAddr); + + msgQ.type = WMA_SET_LINK_STATE; + msgQ.reserved = 0; + msgQ.bodyptr = pLinkStateParams; + msgQ.bodyval = 0; + + MTRACE(mac_trace_msg_tx(pMac, NO_SESSION, msgQ.type)); + + retCode = (uint32_t) wma_post_ctrl_msg(pMac, &msgQ); + if (retCode != eSIR_SUCCESS) { + qdf_mem_free(pLinkStateParams); + lim_log(pMac, LOGP, + FL("Posting link state %d failed, reason = %x "), state, + retCode); + } + return retCode; +} + +extern tSirRetStatus lim_set_link_state_ft(tpAniSirGlobal pMac, tSirLinkState + state, tSirMacAddr bssId, + tSirMacAddr selfMacAddr, int ft, + tpPESession psessionEntry) +{ + tSirMsgQ msgQ; + tSirRetStatus retCode; + tpLinkStateParams pLinkStateParams = NULL; + /* Allocate memory. */ + pLinkStateParams = qdf_mem_malloc(sizeof(tLinkStateParams)); + if (NULL == pLinkStateParams) { + lim_log(pMac, LOGP, + FL + ("Unable to allocate memory while sending Set Link State")); + retCode = eSIR_MEM_ALLOC_FAILED; + return retCode; + } + pLinkStateParams->state = state; + /* Copy Mac address */ + sir_copy_mac_addr(pLinkStateParams->bssid, bssId); + sir_copy_mac_addr(pLinkStateParams->selfMacAddr, selfMacAddr); + pLinkStateParams->ft = 1; + pLinkStateParams->session = psessionEntry; + + msgQ.type = WMA_SET_LINK_STATE; + msgQ.reserved = 0; + msgQ.bodyptr = pLinkStateParams; + msgQ.bodyval = 0; + if (NULL == psessionEntry) { + MTRACE(mac_trace_msg_tx(pMac, NO_SESSION, msgQ.type)); + } else { + MTRACE(mac_trace_msg_tx + (pMac, psessionEntry->peSessionId, msgQ.type)); + } + + retCode = (uint32_t) wma_post_ctrl_msg(pMac, &msgQ); + if (retCode != eSIR_SUCCESS) { + qdf_mem_free(pLinkStateParams); + lim_log(pMac, LOGP, + FL("Posting link state %d failed, reason = %x "), state, + retCode); + } + return retCode; +} + +/** --------------------------------------------------------- + \fn lim_send_beacon_filter_info + \brief LIM sends beacon filtering info to WMA + \param tpAniSirGlobal pMac + \return None + -----------------------------------------------------------*/ +tSirRetStatus lim_send_beacon_filter_info(tpAniSirGlobal pMac, + tpPESession psessionEntry) +{ + tpBeaconFilterMsg pBeaconFilterMsg = NULL; + tSirRetStatus retCode = eSIR_SUCCESS; + tSirMsgQ msgQ; + uint8_t *ptr; + uint32_t i; + uint32_t msgSize; + tpBeaconFilterIe pIe; + + if (psessionEntry == NULL) { + lim_log(pMac, LOGE, FL("Fail to find the right session ")); + retCode = eSIR_FAILURE; + return retCode; + } + msgSize = sizeof(tBeaconFilterMsg) + sizeof(beacon_filter_table); + pBeaconFilterMsg = qdf_mem_malloc(msgSize); + if (NULL == pBeaconFilterMsg) { + lim_log(pMac, LOGP, + FL("Fail to allocate memory for beaconFiilterMsg ")); + retCode = eSIR_MEM_ALLOC_FAILED; + return retCode; + } + /* Fill in capability Info and mask */ + /* Don't send this message if no active Infra session is found. */ + pBeaconFilterMsg->capabilityInfo = psessionEntry->limCurrentBssCaps; + pBeaconFilterMsg->capabilityMask = CAPABILITY_FILTER_MASK; + pBeaconFilterMsg->beaconInterval = + (uint16_t) psessionEntry->beaconParams.beaconInterval; + /* Fill in number of IEs in beacon_filter_table */ + pBeaconFilterMsg->ieNum = + (uint16_t) (sizeof(beacon_filter_table) / sizeof(tBeaconFilterIe)); + /* Fill the BSSIDX */ + pBeaconFilterMsg->bssIdx = psessionEntry->bssIdx; + + /* Fill message with info contained in the beacon_filter_table */ + ptr = (uint8_t *) pBeaconFilterMsg + sizeof(tBeaconFilterMsg); + for (i = 0; i < (pBeaconFilterMsg->ieNum); i++) { + pIe = (tpBeaconFilterIe) ptr; + pIe->elementId = beacon_filter_table[i].elementId; + pIe->checkIePresence = beacon_filter_table[i].checkIePresence; + pIe->byte.offset = beacon_filter_table[i].byte.offset; + pIe->byte.value = beacon_filter_table[i].byte.value; + pIe->byte.bitMask = beacon_filter_table[i].byte.bitMask; + pIe->byte.ref = beacon_filter_table[i].byte.ref; + ptr += sizeof(tBeaconFilterIe); + } + msgQ.type = WMA_BEACON_FILTER_IND; + msgQ.reserved = 0; + msgQ.bodyptr = pBeaconFilterMsg; + msgQ.bodyval = 0; + lim_log(pMac, LOG3, FL("Sending WMA_BEACON_FILTER_IND...")); + MTRACE(mac_trace_msg_tx(pMac, psessionEntry->peSessionId, msgQ.type)); + retCode = wma_post_ctrl_msg(pMac, &msgQ); + if (eSIR_SUCCESS != retCode) { + qdf_mem_free(pBeaconFilterMsg); + lim_log(pMac, LOGP, + FL("Posting WMA_BEACON_FILTER_IND failed, reason=%X"), + retCode); + return retCode; + } + return retCode; +} + +tSirRetStatus lim_send_mode_update(tpAniSirGlobal pMac, + tUpdateVHTOpMode *pTempParam, + tpPESession psessionEntry) +{ + tUpdateVHTOpMode *pVhtOpMode = NULL; + tSirRetStatus retCode = eSIR_SUCCESS; + tSirMsgQ msgQ; + + pVhtOpMode = qdf_mem_malloc(sizeof(tUpdateVHTOpMode)); + if (NULL == pVhtOpMode) { + lim_log(pMac, LOGP, + FL("Unable to allocate memory during Update Op Mode")); + return eSIR_MEM_ALLOC_FAILED; + } + qdf_mem_copy((uint8_t *) pVhtOpMode, pTempParam, + sizeof(tUpdateVHTOpMode)); + msgQ.type = WMA_UPDATE_OP_MODE; + msgQ.reserved = 0; + msgQ.bodyptr = pVhtOpMode; + msgQ.bodyval = 0; + lim_log(pMac, LOG3, FL( + "Sending WMA_UPDATE_OP_MODE, op_mode %d, sta_id %d"), + pVhtOpMode->opMode, pVhtOpMode->staId); + if (NULL == psessionEntry) + MTRACE(mac_trace_msg_tx(pMac, NO_SESSION, msgQ.type)); + else + MTRACE(mac_trace_msg_tx(pMac, + psessionEntry->peSessionId, + msgQ.type)); + retCode = wma_post_ctrl_msg(pMac, &msgQ); + if (eSIR_SUCCESS != retCode) { + qdf_mem_free(pVhtOpMode); + lim_log(pMac, LOGP, + FL("Posting WMA_UPDATE_OP_MODE failed, reason=%X"), + retCode); + } + + return retCode; +} + +tSirRetStatus lim_send_rx_nss_update(tpAniSirGlobal pMac, + tUpdateRxNss *pTempParam, + tpPESession psessionEntry) +{ + tUpdateRxNss *pRxNss = NULL; + tSirRetStatus retCode = eSIR_SUCCESS; + tSirMsgQ msgQ; + + pRxNss = qdf_mem_malloc(sizeof(tUpdateRxNss)); + if (NULL == pRxNss) { + lim_log(pMac, LOGP, + FL("Unable to allocate memory during Update Rx Nss")); + return eSIR_MEM_ALLOC_FAILED; + } + qdf_mem_copy((uint8_t *) pRxNss, pTempParam, sizeof(tUpdateRxNss)); + msgQ.type = WMA_UPDATE_RX_NSS; + msgQ.reserved = 0; + msgQ.bodyptr = pRxNss; + msgQ.bodyval = 0; + PELOG3(lim_log(pMac, LOG3, FL("Sending WMA_UPDATE_RX_NSS"));) + if (NULL == psessionEntry) + MTRACE(mac_trace_msg_tx(pMac, NO_SESSION, msgQ.type)); + else + MTRACE(mac_trace_msg_tx(pMac, + psessionEntry->peSessionId, + msgQ.type)); + retCode = wma_post_ctrl_msg(pMac, &msgQ); + if (eSIR_SUCCESS != retCode) { + qdf_mem_free(pRxNss); + lim_log(pMac, LOGP, + FL("Posting WMA_UPDATE_RX_NSS failed, reason=%X"), + retCode); + } + + return retCode; +} + +tSirRetStatus lim_set_membership(tpAniSirGlobal pMac, + tUpdateMembership *pTempParam, + tpPESession psessionEntry) +{ + tUpdateMembership *pMembership = NULL; + tSirRetStatus retCode = eSIR_SUCCESS; + tSirMsgQ msgQ; + + pMembership = qdf_mem_malloc(sizeof(tUpdateMembership)); + if (NULL == pMembership) { + lim_log(pMac, LOGP, + FL("Unable to allocate memory during Update Membership Mode")); + return eSIR_MEM_ALLOC_FAILED; + } + qdf_mem_copy((uint8_t *) pMembership, pTempParam, + sizeof(tUpdateMembership)); + + msgQ.type = WMA_UPDATE_MEMBERSHIP; + msgQ.reserved = 0; + msgQ.bodyptr = pMembership; + msgQ.bodyval = 0; + PELOG3(lim_log(pMac, LOG3, FL("Sending WMA_UPDATE_MEMBERSHIP"));) + if (NULL == psessionEntry) + MTRACE(mac_trace_msg_tx(pMac, NO_SESSION, msgQ.type)); + else + MTRACE(mac_trace_msg_tx(pMac, + psessionEntry->peSessionId, + msgQ.type)); + retCode = wma_post_ctrl_msg(pMac, &msgQ); + if (eSIR_SUCCESS != retCode) { + qdf_mem_free(pMembership); + lim_log(pMac, LOGP, + FL("Posting WMA_UPDATE_MEMBERSHIP failed, reason=%X"), + retCode); + } + + return retCode; +} + +tSirRetStatus lim_set_user_pos(tpAniSirGlobal pMac, + tUpdateUserPos *pTempParam, + tpPESession psessionEntry) +{ + tUpdateUserPos *pUserPos = NULL; + tSirRetStatus retCode = eSIR_SUCCESS; + tSirMsgQ msgQ; + + pUserPos = qdf_mem_malloc(sizeof(tUpdateUserPos)); + if (NULL == pUserPos) { + lim_log(pMac, LOGP, + FL("Unable to allocate memory during Update User Position")); + return eSIR_MEM_ALLOC_FAILED; + } + qdf_mem_copy((uint8_t *) pUserPos, pTempParam, sizeof(tUpdateUserPos)); + + msgQ.type = WMA_UPDATE_USERPOS; + msgQ.reserved = 0; + msgQ.bodyptr = pUserPos; + msgQ.bodyval = 0; + PELOG3(lim_log(pMac, LOG3, FL("Sending WMA_UPDATE_USERPOS"));) + if (NULL == psessionEntry) + MTRACE(mac_trace_msg_tx(pMac, NO_SESSION, msgQ.type)); + else + MTRACE(mac_trace_msg_tx(pMac, + psessionEntry->peSessionId, + msgQ.type)); + retCode = wma_post_ctrl_msg(pMac, &msgQ); + if (eSIR_SUCCESS != retCode) { + qdf_mem_free(pUserPos); + lim_log(pMac, LOGP, + FL("Posting WMA_UPDATE_USERPOS failed, reason=%X"), + retCode); + } + + return retCode; +} + +#ifdef WLAN_FEATURE_11W +/** + * lim_send_exclude_unencrypt_ind() - sends WMA_EXCLUDE_UNENCRYPTED_IND to HAL + * @pMac: mac global context + * @excludeUnenc: true: ignore, false: indicate + * @psessionEntry: session context + * + * LIM sends a message to HAL to indicate whether to ignore or indicate the + * unprotected packet error. + * + * Return: status of operation + */ +tSirRetStatus lim_send_exclude_unencrypt_ind(tpAniSirGlobal pMac, + bool excludeUnenc, + tpPESession psessionEntry) +{ + tSirRetStatus retCode = eSIR_SUCCESS; + tSirMsgQ msgQ; + tSirWlanExcludeUnencryptParam *pExcludeUnencryptParam; + + pExcludeUnencryptParam = + qdf_mem_malloc(sizeof(tSirWlanExcludeUnencryptParam)); + if (NULL == pExcludeUnencryptParam) { + lim_log(pMac, LOGP, + FL("Unable to allocate memory during lim_send_exclude_unencrypt_ind")); + return eSIR_MEM_ALLOC_FAILED; + } + + pExcludeUnencryptParam->excludeUnencrypt = excludeUnenc; + qdf_mem_copy(pExcludeUnencryptParam->bssid.bytes, psessionEntry->bssId, + QDF_MAC_ADDR_SIZE); + + msgQ.type = WMA_EXCLUDE_UNENCRYPTED_IND; + msgQ.reserved = 0; + msgQ.bodyptr = pExcludeUnencryptParam; + msgQ.bodyval = 0; + PELOG3(lim_log(pMac, LOG3, FL("Sending WMA_EXCLUDE_UNENCRYPTED_IND"));) + MTRACE(mac_trace_msg_tx(pMac, psessionEntry->peSessionId, msgQ.type)); + retCode = wma_post_ctrl_msg(pMac, &msgQ); + if (eSIR_SUCCESS != retCode) { + qdf_mem_free(pExcludeUnencryptParam); + lim_log(pMac, LOGP, + FL("Posting WMA_EXCLUDE_UNENCRYPTED_IND failed, reason=%X"), + retCode); + } + + return retCode; +} +#endif + +/** + * lim_send_ht40_obss_scanind() - send ht40 obss start scan request + * mac: mac context + * session PE session handle + * + * LIM sends a HT40 start scan message to WMA + * + * Return: status of operation + */ +tSirRetStatus lim_send_ht40_obss_scanind(tpAniSirGlobal mac_ctx, + struct sPESession *session) +{ + enum eSirRetStatus ret = eSIR_SUCCESS; + struct obss_ht40_scanind *ht40_obss_scanind; + uint32_t channelnum; + struct sSirMsgQ msg; + uint8_t chan_list[WNI_CFG_VALID_CHANNEL_LIST_LEN]; + uint8_t channel24gnum, count; + + ht40_obss_scanind = qdf_mem_malloc(sizeof(struct obss_ht40_scanind)); + if (NULL == ht40_obss_scanind) { + QDF_TRACE(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_ERROR, + "Memory allocation failed"); + return eSIR_FAILURE; + } + QDF_TRACE(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_ERROR, + "OBSS Scan Indication bssIdx- %d staId %d", + session->bssIdx, session->staId); + + ht40_obss_scanind->cmd = HT40_OBSS_SCAN_PARAM_START; + ht40_obss_scanind->scan_type = eSIR_ACTIVE_SCAN; + ht40_obss_scanind->obss_passive_dwelltime = + session->obss_ht40_scanparam.obss_passive_dwelltime; + ht40_obss_scanind->obss_active_dwelltime = + session->obss_ht40_scanparam.obss_active_dwelltime; + ht40_obss_scanind->obss_width_trigger_interval = + session->obss_ht40_scanparam.obss_width_trigger_interval; + ht40_obss_scanind->obss_passive_total_per_channel = + session->obss_ht40_scanparam.obss_passive_total_per_channel; + ht40_obss_scanind->obss_active_total_per_channel = + session->obss_ht40_scanparam.obss_active_total_per_channel; + ht40_obss_scanind->bsswidth_ch_trans_delay = + session->obss_ht40_scanparam.bsswidth_ch_trans_delay; + ht40_obss_scanind->obss_activity_threshold = + session->obss_ht40_scanparam.obss_activity_threshold; + ht40_obss_scanind->current_operatingclass = + cds_reg_dmn_get_opclass_from_channel( + mac_ctx->scan.countryCodeCurrent, + session->currentOperChannel, + session->ch_width); + channelnum = WNI_CFG_VALID_CHANNEL_LIST_LEN; + if (wlan_cfg_get_str(mac_ctx, WNI_CFG_VALID_CHANNEL_LIST, + chan_list, &channelnum) != eSIR_SUCCESS) { + lim_log(mac_ctx, LOGE, + FL("could not retrieve Valid channel list")); + qdf_mem_free(ht40_obss_scanind); + return eSIR_FAILURE; + } + /* Extract 24G channel list */ + channel24gnum = 0; + for (count = 0; count < channelnum && + (channel24gnum < SIR_ROAM_MAX_CHANNELS); count++) { + if ((chan_list[count] > CHAN_ENUM_1) && + (chan_list[count] < CHAN_ENUM_14)) { + ht40_obss_scanind->channels[channel24gnum] = + chan_list[count]; + channel24gnum++; + } + } + ht40_obss_scanind->channel_count = channel24gnum; + /* FW API requests BSS IDX */ + ht40_obss_scanind->self_sta_idx = session->staId; + ht40_obss_scanind->bss_id = session->bssIdx; + ht40_obss_scanind->fortymhz_intolerent = 0; + ht40_obss_scanind->iefield_len = 0; + msg.type = WMA_HT40_OBSS_SCAN_IND; + msg.reserved = 0; + msg.bodyptr = (void *)ht40_obss_scanind; + msg.bodyval = 0; + lim_log(mac_ctx, LOG1, + FL("Sending WDA_HT40_OBSS_SCAN_IND to WDA" + "Obss Scan trigger width = %d, delay factor = %d"), + ht40_obss_scanind->obss_width_trigger_interval, + ht40_obss_scanind->bsswidth_ch_trans_delay); + ret = wma_post_ctrl_msg(mac_ctx, &msg); + if (eSIR_SUCCESS != ret) { + lim_log(mac_ctx, LOGP, + FL("WDA_HT40_OBSS_SCAN_IND msg failed, reason=%X"), + ret); + qdf_mem_free(ht40_obss_scanind); + } + return ret; +} diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_send_messages.h b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_send_messages.h new file mode 100644 index 0000000000000000000000000000000000000000..c5c00d0e642f6f981f102bc8adbe6e7826ba9b96 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_send_messages.h @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2011-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * + * lim_send_messages.h: Provides functions to send messages or Indications to HAL. + * Author: Sunit Bhatia + * Date: 09/21/2006 + * History:- + * Date Modified by Modification Information + * + * -------------------------------------------------------------------------- + * + */ +#ifndef __LIM_SEND_MESSAGES_H +#define __LIM_SEND_MESSAGES_H + +#include "ani_global.h" +#include "lim_types.h" +#include "wma_if.h" +#include "sir_params.h" +tSirRetStatus lim_send_cf_params(tpAniSirGlobal pMac, uint8_t bssIdx, + uint8_t cfpCount, uint8_t cfpPeriod); +tSirRetStatus lim_send_beacon_params(tpAniSirGlobal pMac, + tpUpdateBeaconParams pUpdatedBcnParams, + tpPESession psessionEntry); +/* tSirRetStatus lim_send_beacon_params(tpAniSirGlobal pMac, tpUpdateBeaconParams pUpdatedBcnParams); */ +tSirRetStatus lim_send_mode_update(tpAniSirGlobal pMac, + tUpdateVHTOpMode *tempParam, + tpPESession psessionEntry); +tSirRetStatus lim_send_rx_nss_update(tpAniSirGlobal pMac, + tUpdateRxNss *tempParam, + tpPESession psessionEntry); + +tSirRetStatus lim_set_membership(tpAniSirGlobal pMac, + tUpdateMembership *pTempParam, + tpPESession psessionEntry); + +tSirRetStatus lim_set_user_pos(tpAniSirGlobal pMac, + tUpdateUserPos *pTempParam, + tpPESession psessionEntry); +tSirRetStatus lim_send_switch_chnl_params(tpAniSirGlobal pMac, + uint8_t chnlNumber, + uint8_t ch_center_freq_seg0, + uint8_t ch_center_freq_seg1, + enum phy_ch_width ch_width, + int8_t maxTxPower, + uint8_t peSessionId, + uint8_t is_restart); + +tSirRetStatus lim_send_edca_params(tpAniSirGlobal pMac, + tSirMacEdcaParamRecord *pUpdatedEdcaParams, + uint16_t bssIdx); +tSirRetStatus lim_set_link_state(tpAniSirGlobal pMac, tSirLinkState state, + tSirMacAddr bssId, tSirMacAddr selfMac, + tpSetLinkStateCallback callback, + void *callbackArg); +extern tSirRetStatus lim_set_link_state_ft(tpAniSirGlobal pMac, tSirLinkState + state, tSirMacAddr bssId, + tSirMacAddr selfMacAddr, int ft, + tpPESession psessionEntry); +void lim_set_active_edca_params(tpAniSirGlobal pMac, + tSirMacEdcaParamRecord *plocalEdcaParams, + tpPESession psessionEntry); +#define CAPABILITY_FILTER_MASK 0x73CF +#define ERP_FILTER_MASK 0xF8 +#define EDCA_FILTER_MASK 0xF0 +#define QOS_FILTER_MASK 0xF0 +#define HT_BYTE0_FILTER_MASK 0x0 +#define HT_BYTE2_FILTER_MASK 0xEB +#define HT_BYTE5_FILTER_MASK 0xFD +#define DS_PARAM_CHANNEL_MASK 0x0 +#define VHTOP_CHWIDTH_MASK 0xFC + +tSirRetStatus lim_send_beacon_filter_info(tpAniSirGlobal pMac, + tpPESession psessionEntry); + +#ifdef WLAN_FEATURE_11W +tSirRetStatus lim_send_exclude_unencrypt_ind(tpAniSirGlobal pMac, + bool excludeUnenc, + tpPESession psessionEntry); +#endif +tSirRetStatus lim_send_ht40_obss_scanind(tpAniSirGlobal mac_ctx, + tpPESession session); +void lim_handle_sme_join_result(tpAniSirGlobal, + tSirResultCodes, uint16_t, tpPESession); +#endif diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_send_sme_rsp_messages.c b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_send_sme_rsp_messages.c new file mode 100644 index 0000000000000000000000000000000000000000..fec27a31afbbe5698691111a860b2d805246a900 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_send_sme_rsp_messages.c @@ -0,0 +1,2709 @@ +/* + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * This file lim_send_sme_rspMessages.cc contains the functions + * for sending SME response/notification messages to applications + * above MAC software. + * Author: Chandra Modumudi + * Date: 02/13/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + */ + +#include "qdf_types.h" +#include "wni_api.h" +#include "sir_common.h" +#include "ani_global.h" + +#include "wni_cfg.h" +#include "sys_def.h" +#include "cfg_api.h" + +#include "sch_api.h" +#include "utils_api.h" +#include "lim_utils.h" +#include "lim_security_utils.h" +#include "lim_ser_des_utils.h" +#include "lim_send_sme_rsp_messages.h" +#include "lim_ibss_peer_mgmt.h" +#include "lim_session_utils.h" +#include "lim_types.h" +#include "sir_api.h" +#include "cds_regdomain.h" +#include "lim_send_messages.h" +#include "nan_datapath.h" +#include "lim_assoc_utils.h" + +static void lim_handle_join_rsp_status(tpAniSirGlobal mac_ctx, + tpPESession session_entry, tSirResultCodes result_code, + tpSirSmeJoinRsp sme_join_rsp); + +/** + * lim_send_sme_rsp() - Send Response to upper layers + * @mac_ctx: Pointer to Global MAC structure + * @msg_type: Indicates message type + * @result_code: Indicates the result of previously issued + * eWNI_SME_msg_type_REQ message + * + * This function is called by lim_process_sme_req_messages() to send + * eWNI_SME_START_RSP, eWNI_SME_STOP_BSS_RSP + * or eWNI_SME_SWITCH_CHL_RSP messages to applications above MAC + * Software. + * + * Return: None + */ + +void +lim_send_sme_rsp(tpAniSirGlobal mac_ctx, uint16_t msg_type, + tSirResultCodes result_code, uint8_t sme_session_id, + uint16_t sme_transaction_id) +{ + tSirMsgQ msg; + tSirSmeRsp *sme_rsp; + + lim_log(mac_ctx, LOG1, FL("Sending message %s with reasonCode %s"), + lim_msg_str(msg_type), lim_result_code_str(result_code)); + + sme_rsp = qdf_mem_malloc(sizeof(tSirSmeRsp)); + if (NULL == sme_rsp) { + /* Buffer not available. Log error */ + QDF_TRACE(QDF_MODULE_ID_PE, LOGP, + FL("call to AllocateMemory failed for eWNI_SME_*_RSP")); + return; + } + + sme_rsp->messageType = msg_type; + sme_rsp->length = sizeof(tSirSmeRsp); + sme_rsp->statusCode = result_code; + + sme_rsp->sessionId = sme_session_id; + sme_rsp->transactionId = sme_transaction_id; + + msg.type = msg_type; + msg.bodyptr = sme_rsp; + msg.bodyval = 0; + MTRACE(mac_trace(mac_ctx, TRACE_CODE_TX_SME_MSG, + sme_session_id, msg.type)); + +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM /* FEATURE_WLAN_DIAG_SUPPORT */ + switch (msg_type) { + case eWNI_SME_STOP_BSS_RSP: + lim_diag_event_report(mac_ctx, WLAN_PE_DIAG_STOP_BSS_RSP_EVENT, + NULL, (uint16_t) result_code, 0); + break; + } +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + lim_sys_process_mmh_msg_api(mac_ctx, &msg, ePROT); +} + + + +/** + * lim_send_sme_roc_rsp() - Send Response to SME + * @mac_ctx: Pointer to Global MAC structure + * @status: Resume link status + * @result_code: Result of the ROC request + * @sme_session_id: SME sesson Id + * @scan_id: Scan Identifier + * + * This function is called to send ROC rsp + * message to SME. + * + * Return: None + */ +void +lim_send_sme_roc_rsp(tpAniSirGlobal mac_ctx, uint16_t msg_type, + tSirResultCodes result_code, uint8_t sme_session_id, + uint32_t scan_id) +{ + tSirMsgQ msg; + struct sir_roc_rsp *sme_rsp; + + lim_log(mac_ctx, LOG1, + FL("Sending message %s with reasonCode %s scanId %d"), + lim_msg_str(msg_type), lim_result_code_str(result_code), + scan_id); + + sme_rsp = qdf_mem_malloc(sizeof(struct sir_roc_rsp)); + if (NULL == sme_rsp) { + QDF_TRACE(QDF_MODULE_ID_PE, LOGP, + FL("call to AllocateMemory failed for eWNI_SME_*_RSP")); + return; + } + + sme_rsp->message_type = msg_type; + sme_rsp->length = sizeof(struct sir_roc_rsp); + sme_rsp->status = result_code; + + sme_rsp->session_id = sme_session_id; + sme_rsp->scan_id = scan_id; + + msg.type = msg_type; + msg.bodyptr = sme_rsp; + msg.bodyval = 0; + MTRACE(mac_trace_msg_tx(mac_ctx, sme_session_id, msg.type)); + lim_sys_process_mmh_msg_api(mac_ctx, &msg, ePROT); +} + + +/** + * lim_get_max_rate_flags() - Get rate flags + * @mac_ctx: Pointer to global MAC structure + * @sta_ds: Pointer to station ds structure + * + * This function is called to get the rate flags for a connection + * from the station ds structure depending on the ht and the vht + * channel width supported. + * + * Return: Returns the populated rate_flags + */ +uint32_t lim_get_max_rate_flags(tpAniSirGlobal mac_ctx, tpDphHashNode sta_ds) +{ + uint32_t rate_flags = 0; + + if (sta_ds == NULL) { + lim_log(mac_ctx, LOGE, FL("sta_ds is NULL")); + return rate_flags; + } + + if (!sta_ds->mlmStaContext.htCapability && + !sta_ds->mlmStaContext.vhtCapability) { + rate_flags |= eHAL_TX_RATE_LEGACY; + } else { + if (sta_ds->mlmStaContext.vhtCapability) { + if (WNI_CFG_VHT_CHANNEL_WIDTH_80MHZ == + sta_ds->vhtSupportedChannelWidthSet) { + rate_flags |= eHAL_TX_RATE_VHT80; + } else if (WNI_CFG_VHT_CHANNEL_WIDTH_20_40MHZ == + sta_ds->vhtSupportedChannelWidthSet) { + if (sta_ds->htSupportedChannelWidthSet) + rate_flags |= eHAL_TX_RATE_VHT40; + else + rate_flags |= eHAL_TX_RATE_VHT20; + } + } else if (sta_ds->mlmStaContext.htCapability) { + if (sta_ds->htSupportedChannelWidthSet) + rate_flags |= eHAL_TX_RATE_HT40; + else + rate_flags |= eHAL_TX_RATE_HT20; + } + } + + if (sta_ds->htShortGI20Mhz || sta_ds->htShortGI40Mhz) + rate_flags |= eHAL_TX_RATE_SGI; + + return rate_flags; +} + +/** + * lim_send_sme_join_reassoc_rsp_after_resume() - Send Response to SME + * @mac_ctx Pointer to Global MAC structure + * @status Resume link status + * @ctx context passed while calling resmune link. + * (join response to be sent) + * + * This function is called to send Join/Reassoc rsp + * message to SME after the resume link. + * + * Return: None + */ +static void lim_send_sme_join_reassoc_rsp_after_resume(tpAniSirGlobal mac_ctx, + QDF_STATUS status, uint32_t *ctx) +{ + tSirMsgQ msg; + tpSirSmeJoinRsp sme_join_rsp = (tpSirSmeJoinRsp) ctx; + + msg.type = sme_join_rsp->messageType; + msg.bodyptr = sme_join_rsp; + msg.bodyval = 0; + MTRACE(mac_trace(mac_ctx, TRACE_CODE_TX_SME_MSG, NO_SESSION, msg.type)); + lim_sys_process_mmh_msg_api(mac_ctx, &msg, ePROT); +} + +/** + * lim_handle_join_rsp_status() - Handle the response. + * @mac_ctx: Pointer to Global MAC structure + * @session_entry: PE Session Info + * @result_code: Indicates the result of previously issued + * eWNI_SME_msgType_REQ message + * @sme_join_rsp The received response. + * + * This function will handle both the success and failure status + * of the received response. + * + * Return: None + */ +static void lim_handle_join_rsp_status(tpAniSirGlobal mac_ctx, + tpPESession session_entry, tSirResultCodes result_code, + tpSirSmeJoinRsp sme_join_rsp) +{ + uint16_t bss_ie_len; + void *bss_ies; + bool is_vendor_ap_1_present; + +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH + tSirSmeHTProfile *ht_profile; +#endif + if (result_code == eSIR_SME_SUCCESS) { + if (session_entry->beacon != NULL) { + sme_join_rsp->beaconLength = session_entry->bcnLen; + qdf_mem_copy(sme_join_rsp->frames, + session_entry->beacon, + sme_join_rsp->beaconLength); + qdf_mem_free(session_entry->beacon); + session_entry->beacon = NULL; + session_entry->bcnLen = 0; + lim_log(mac_ctx, LOG1, FL("Beacon=%d"), + sme_join_rsp->beaconLength); + } + if (session_entry->assocReq != NULL) { + sme_join_rsp->assocReqLength = + session_entry->assocReqLen; + qdf_mem_copy(sme_join_rsp->frames + + sme_join_rsp->beaconLength, + session_entry->assocReq, + sme_join_rsp->assocReqLength); + qdf_mem_free(session_entry->assocReq); + session_entry->assocReq = NULL; + session_entry->assocReqLen = 0; + lim_log(mac_ctx, + LOG1, FL("AssocReq=%d"), + sme_join_rsp->assocReqLength); + } + if (session_entry->assocRsp != NULL) { + sme_join_rsp->assocRspLength = + session_entry->assocRspLen; + qdf_mem_copy(sme_join_rsp->frames + + sme_join_rsp->beaconLength + + sme_join_rsp->assocReqLength, + session_entry->assocRsp, + sme_join_rsp->assocRspLength); + qdf_mem_free(session_entry->assocRsp); + session_entry->assocRsp = NULL; + session_entry->assocRspLen = 0; + } + if (session_entry->ricData != NULL) { + sme_join_rsp->parsedRicRspLen = + session_entry->RICDataLen; + qdf_mem_copy(sme_join_rsp->frames + + sme_join_rsp->beaconLength + + sme_join_rsp->assocReqLength + + sme_join_rsp->assocRspLength, + session_entry->ricData, + sme_join_rsp->parsedRicRspLen); + qdf_mem_free(session_entry->ricData); + session_entry->ricData = NULL; + session_entry->RICDataLen = 0; + lim_log(mac_ctx, LOG1, FL("RicLength=%d"), + sme_join_rsp->parsedRicRspLen); + } +#ifdef FEATURE_WLAN_ESE + if (session_entry->tspecIes != NULL) { + sme_join_rsp->tspecIeLen = + session_entry->tspecLen; + qdf_mem_copy(sme_join_rsp->frames + + sme_join_rsp->beaconLength + + sme_join_rsp->assocReqLength + + sme_join_rsp->assocRspLength + + sme_join_rsp->parsedRicRspLen, + session_entry->tspecIes, + sme_join_rsp->tspecIeLen); + qdf_mem_free(session_entry->tspecIes); + session_entry->tspecIes = NULL; + session_entry->tspecLen = 0; + lim_log(mac_ctx, LOG1, FL("ESE-TspecLen=%d"), + sme_join_rsp->tspecIeLen); + } +#endif + sme_join_rsp->aid = session_entry->limAID; + lim_log(mac_ctx, LOG1, FL("AssocRsp=%d"), + sme_join_rsp->assocRspLength); + sme_join_rsp->vht_channel_width = + session_entry->ch_width; +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH + if (session_entry->cc_switch_mode != + QDF_MCC_TO_SCC_SWITCH_DISABLE) { + ht_profile = &sme_join_rsp->HTProfile; + ht_profile->htSupportedChannelWidthSet = + session_entry->htSupportedChannelWidthSet; + ht_profile->htRecommendedTxWidthSet = + session_entry->htRecommendedTxWidthSet; + ht_profile->htSecondaryChannelOffset = + session_entry->htSecondaryChannelOffset; + ht_profile->dot11mode = session_entry->dot11mode; + ht_profile->htCapability = session_entry->htCapability; + ht_profile->vhtCapability = + session_entry->vhtCapability; + ht_profile->apCenterChan = session_entry->ch_center_freq_seg0; + ht_profile->apChanWidth = session_entry->ch_width; + } +#endif + bss_ie_len = lim_get_ielen_from_bss_description( + &session_entry->pLimJoinReq->bssDescription); + bss_ies = &session_entry->pLimJoinReq->bssDescription.ieFields; + is_vendor_ap_1_present = (cfg_get_vendor_ie_ptr_from_oui(mac_ctx, + SIR_MAC_VENDOR_AP_1_OUI, SIR_MAC_VENDOR_AP_1_OUI_LEN, + bss_ies, bss_ie_len) != NULL); + + if (mac_ctx->roam.configParam.is_force_1x1 && + is_vendor_ap_1_present && (session_entry->nss == 2) && + (mac_ctx->lteCoexAntShare == 0 || + IS_5G_CH(session_entry->currentOperChannel))) { + /* SET vdev param */ + pe_debug("sending SMPS intolrent vdev_param"); + wma_cli_set_command(session_entry->smeSessionId, + (int)WMI_VDEV_PARAM_SMPS_INTOLERANT, + 1, VDEV_CMD); + + } + } else { + if (session_entry->beacon != NULL) { + qdf_mem_free(session_entry->beacon); + session_entry->beacon = NULL; + session_entry->bcnLen = 0; + } + if (session_entry->assocReq != NULL) { + qdf_mem_free(session_entry->assocReq); + session_entry->assocReq = NULL; + session_entry->assocReqLen = 0; + } + if (session_entry->assocRsp != NULL) { + qdf_mem_free(session_entry->assocRsp); + session_entry->assocRsp = NULL; + session_entry->assocRspLen = 0; + } + if (session_entry->ricData != NULL) { + qdf_mem_free(session_entry->ricData); + session_entry->ricData = NULL; + session_entry->RICDataLen = 0; + } +#ifdef FEATURE_WLAN_ESE + if (session_entry->tspecIes != NULL) { + qdf_mem_free(session_entry->tspecIes); + session_entry->tspecIes = NULL; + session_entry->tspecLen = 0; + } +#endif + } +} + +/** + * lim_add_bss_info() - copy data from session entry to join rsp + * @sta_ds: Station dph entry + * @sme_join_rsp: Join response buffer to be filled up + * + * Return: None + */ +static void lim_add_bss_info(tpDphHashNode sta_ds, tpSirSmeJoinRsp sme_join_rsp) +{ + struct parsed_ies *parsed_ies = &sta_ds->parsed_ies; + + if (parsed_ies->hs20vendor_ie.present) + sme_join_rsp->hs20vendor_ie = parsed_ies->hs20vendor_ie; + if (parsed_ies->vht_caps.present) + sme_join_rsp->vht_caps = parsed_ies->vht_caps; + if (parsed_ies->ht_caps.present) + sme_join_rsp->ht_caps = parsed_ies->ht_caps; + if (parsed_ies->ht_operation.present) + sme_join_rsp->ht_operation = parsed_ies->ht_operation; + if (parsed_ies->vht_operation.present) + sme_join_rsp->vht_operation = parsed_ies->vht_operation; +} + +/** + * lim_send_sme_join_reassoc_rsp() - Send Response to Upper Layers + * @mac_ctx: Pointer to Global MAC structure + * @msg_type: Indicates message type + * @result_code: Indicates the result of previously issued + * eWNI_SME_msgType_REQ message + * @prot_status_code: Protocol Status Code + * @session_entry: PE Session Info + * @sme_session_id: SME Session ID + * @sme_transaction_id: SME Transaction ID + * + * This function is called by lim_process_sme_req_messages() to send + * eWNI_SME_JOIN_RSP or eWNI_SME_REASSOC_RSP messages to applications + * above MAC Software. + * + * Return: None + */ + +void +lim_send_sme_join_reassoc_rsp(tpAniSirGlobal mac_ctx, uint16_t msg_type, + tSirResultCodes result_code, uint16_t prot_status_code, + tpPESession session_entry, uint8_t sme_session_id, + uint16_t sme_transaction_id) +{ + tpSirSmeJoinRsp sme_join_rsp; + uint32_t rsp_len; + tpDphHashNode sta_ds = NULL; +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM /* FEATURE_WLAN_DIAG_SUPPORT */ + if (msg_type == eWNI_SME_REASSOC_RSP) + lim_diag_event_report(mac_ctx, WLAN_PE_DIAG_REASSOC_RSP_EVENT, + session_entry, (uint16_t) result_code, 0); + else + lim_diag_event_report(mac_ctx, WLAN_PE_DIAG_JOIN_RSP_EVENT, + session_entry, (uint16_t) result_code, 0); +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + + lim_log(mac_ctx, LOG1, FL("Sending message %s with reasonCode %s"), + lim_msg_str(msg_type), lim_result_code_str(result_code)); + + if (session_entry == NULL) { + rsp_len = sizeof(tSirSmeJoinRsp); + sme_join_rsp = qdf_mem_malloc(rsp_len); + if (NULL == sme_join_rsp) { + lim_log(mac_ctx, LOGP, + FL("Mem Alloc fail - JOIN/REASSOC_RSP")); + return; + } + + sme_join_rsp->beaconLength = 0; + sme_join_rsp->assocReqLength = 0; + sme_join_rsp->assocRspLength = 0; + } else { + rsp_len = session_entry->assocReqLen + + session_entry->assocRspLen + session_entry->bcnLen + + session_entry->RICDataLen + +#ifdef FEATURE_WLAN_ESE + session_entry->tspecLen + +#endif + sizeof(tSirSmeJoinRsp) - sizeof(uint8_t); + sme_join_rsp = qdf_mem_malloc(rsp_len); + if (NULL == sme_join_rsp) { + lim_log(mac_ctx, LOGP, + FL("MemAlloc fail - JOIN/REASSOC_RSP")); + return; + } + if (result_code == eSIR_SME_SUCCESS) { + sta_ds = dph_get_hash_entry(mac_ctx, + DPH_STA_HASH_INDEX_PEER, + &session_entry->dph.dphHashTable); + if (sta_ds == NULL) { + lim_log(mac_ctx, LOGE, + FL("Get Self Sta Entry fail")); + } else { + /* Pass the peer's staId */ + sme_join_rsp->staId = sta_ds->staIndex; + sme_join_rsp->ucastSig = + sta_ds->ucUcastSig; + sme_join_rsp->bcastSig = + sta_ds->ucBcastSig; + sme_join_rsp->timingMeasCap = + sta_ds->timingMeasCap; +#ifdef FEATURE_WLAN_TDLS + sme_join_rsp->tdls_prohibited = + session_entry->tdls_prohibited; + sme_join_rsp->tdls_chan_swit_prohibited = + session_entry->tdls_chan_swit_prohibited; +#endif + sme_join_rsp->nss = sta_ds->nss; + sme_join_rsp->max_rate_flags = + lim_get_max_rate_flags(mac_ctx, sta_ds); + lim_add_bss_info(sta_ds, sme_join_rsp); + } + } + sme_join_rsp->beaconLength = 0; + sme_join_rsp->assocReqLength = 0; + sme_join_rsp->assocRspLength = 0; + sme_join_rsp->parsedRicRspLen = 0; +#ifdef FEATURE_WLAN_ESE + sme_join_rsp->tspecIeLen = 0; +#endif + lim_handle_join_rsp_status(mac_ctx, session_entry, result_code, + sme_join_rsp); + + /* Send supported NSS 1x1 to SME */ + sme_join_rsp->supported_nss_1x1 = + session_entry->supported_nss_1x1; + lim_log(mac_ctx, LOG1, + FL("SME Join Rsp is supported NSS 1X1: %d"), + sme_join_rsp->supported_nss_1x1); + } + + sme_join_rsp->messageType = msg_type; + sme_join_rsp->length = (uint16_t) rsp_len; + sme_join_rsp->statusCode = result_code; + sme_join_rsp->protStatusCode = prot_status_code; + + sme_join_rsp->sessionId = sme_session_id; + sme_join_rsp->transactionId = sme_transaction_id; + + lim_send_sme_join_reassoc_rsp_after_resume(mac_ctx, QDF_STATUS_SUCCESS, + (uint32_t *)sme_join_rsp); +} + +/** + * lim_send_sme_start_bss_rsp() + * + ***FUNCTION: + * This function is called to send eWNI_SME_START_BSS_RSP + * message to applications above MAC Software. + * + ***PARAMS: + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param pMac Pointer to Global MAC structure + * @param msgType Indicates message type + * @param resultCode Indicates the result of previously issued + * eWNI_SME_msgType_REQ message + * + * @return None + */ + +void +lim_send_sme_start_bss_rsp(tpAniSirGlobal pMac, + uint16_t msgType, tSirResultCodes resultCode, + tpPESession psessionEntry, uint8_t smesessionId, + uint16_t smetransactionId) +{ + + uint16_t size = 0; + tSirMsgQ mmhMsg; + tSirSmeStartBssRsp *pSirSmeRsp; + uint16_t ieLen; + uint16_t ieOffset, curLen; + + PELOG1(lim_log(pMac, LOG1, FL("Sending message %s with reasonCode %s"), + lim_msg_str(msgType), lim_result_code_str(resultCode)); + ) + + size = sizeof(tSirSmeStartBssRsp); + + if (psessionEntry == NULL) { + pSirSmeRsp = qdf_mem_malloc(size); + if (NULL == pSirSmeRsp) { + /* / Buffer not available. Log error */ + lim_log(pMac, LOGP, + FL + ("call to AllocateMemory failed for eWNI_SME_START_BSS_RSP")); + return; + } + } else { + /* subtract size of beaconLength + Mac Hdr + Fixed Fields before SSID */ + ieOffset = sizeof(tAniBeaconStruct) + SIR_MAC_B_PR_SSID_OFFSET; + ieLen = psessionEntry->schBeaconOffsetBegin + + psessionEntry->schBeaconOffsetEnd - ieOffset; + /* calculate the memory size to allocate */ + size += ieLen; + + pSirSmeRsp = qdf_mem_malloc(size); + if (NULL == pSirSmeRsp) { + /* / Buffer not available. Log error */ + lim_log(pMac, LOGP, + FL + ("call to AllocateMemory failed for eWNI_SME_START_BSS_RSP")); + + return; + } + size = sizeof(tSirSmeStartBssRsp); + if (resultCode == eSIR_SME_SUCCESS) { + + sir_copy_mac_addr(pSirSmeRsp->bssDescription.bssId, + psessionEntry->bssId); + + /* Read beacon interval from session */ + pSirSmeRsp->bssDescription.beaconInterval = + (uint16_t) psessionEntry->beaconParams. + beaconInterval; + pSirSmeRsp->bssType = psessionEntry->bssType; + + if (cfg_get_capability_info + (pMac, &pSirSmeRsp->bssDescription.capabilityInfo, + psessionEntry) + != eSIR_SUCCESS) + lim_log(pMac, LOGP, + FL + ("could not retrieve Capabilities value")); + + lim_get_phy_mode(pMac, + (uint32_t *) &pSirSmeRsp->bssDescription. + nwType, psessionEntry); + + pSirSmeRsp->bssDescription.channelId = + psessionEntry->currentOperChannel; + + if (!LIM_IS_NDI_ROLE(psessionEntry)) { + curLen = psessionEntry->schBeaconOffsetBegin - ieOffset; + qdf_mem_copy((uint8_t *) &pSirSmeRsp->bssDescription. + ieFields, + psessionEntry->pSchBeaconFrameBegin + + ieOffset, (uint32_t) curLen); + + qdf_mem_copy(((uint8_t *) &pSirSmeRsp->bssDescription. + ieFields) + curLen, + psessionEntry->pSchBeaconFrameEnd, + (uint32_t) psessionEntry-> + schBeaconOffsetEnd); + + pSirSmeRsp->bssDescription.length = (uint16_t) + (offsetof(tSirBssDescription, ieFields[0]) + - sizeof(pSirSmeRsp->bssDescription.length) + + ieLen); + /* This is the size of the message, subtracting the size of the pointer to ieFields */ + size += ieLen - sizeof(uint32_t); + } +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH + if (psessionEntry->cc_switch_mode + != QDF_MCC_TO_SCC_SWITCH_DISABLE) { + pSirSmeRsp->HTProfile. + htSupportedChannelWidthSet = + psessionEntry->htSupportedChannelWidthSet; + pSirSmeRsp->HTProfile.htRecommendedTxWidthSet = + psessionEntry->htRecommendedTxWidthSet; + pSirSmeRsp->HTProfile.htSecondaryChannelOffset = + psessionEntry->htSecondaryChannelOffset; + pSirSmeRsp->HTProfile.dot11mode = + psessionEntry->dot11mode; + pSirSmeRsp->HTProfile.htCapability = + psessionEntry->htCapability; + pSirSmeRsp->HTProfile.vhtCapability = + psessionEntry->vhtCapability; + pSirSmeRsp->HTProfile.apCenterChan = + psessionEntry->ch_center_freq_seg0; + pSirSmeRsp->HTProfile.apChanWidth = + psessionEntry->ch_width; + } +#endif + } + } + pSirSmeRsp->messageType = msgType; + pSirSmeRsp->length = size; + + /* Update SME session Id and transaction Id */ + pSirSmeRsp->sessionId = smesessionId; + pSirSmeRsp->transactionId = smetransactionId; + pSirSmeRsp->statusCode = resultCode; + if (psessionEntry != NULL) + pSirSmeRsp->staId = psessionEntry->staId; /* else it will be always zero smeRsp StaID = 0 */ + + mmhMsg.type = msgType; + mmhMsg.bodyptr = pSirSmeRsp; + mmhMsg.bodyval = 0; + if (psessionEntry == NULL) { + MTRACE(mac_trace(pMac, TRACE_CODE_TX_SME_MSG, + NO_SESSION, mmhMsg.type)); + } else { + MTRACE(mac_trace(pMac, TRACE_CODE_TX_SME_MSG, + psessionEntry->peSessionId, mmhMsg.type)); + } +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM /* FEATURE_WLAN_DIAG_SUPPORT */ + lim_diag_event_report(pMac, WLAN_PE_DIAG_START_BSS_RSP_EVENT, + psessionEntry, (uint16_t) resultCode, 0); +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + + lim_sys_process_mmh_msg_api(pMac, &mmhMsg, ePROT); +} /*** end lim_send_sme_start_bss_rsp() ***/ + +/** + * lim_send_sme_scan_rsp() - Send scan response to SME + * @pMac: Pointer to Global MAC structure + * @length: Indicates length of message + * @resultCode: Indicates the result of previously issued + * eWNI_SME_SCAN_REQ message + * @scan_id: scan identifier + * + * This function is called by lim_process_sme_req_messages() to send + * eWNI_SME_SCAN_RSP message to applications above MAC + * + * return: None + */ + +void +lim_send_sme_scan_rsp(tpAniSirGlobal pMac, tSirResultCodes resultCode, + uint8_t smesessionId, uint16_t smetranscationId, + uint32_t scan_id) +{ + lim_post_sme_scan_rsp_message(pMac, resultCode, smesessionId, + smetranscationId, scan_id); +} + +/** + * lim_post_sme_scan_rsp_message() + * + ***FUNCTION: + * This function is called by lim_send_sme_scan_rsp() to send + * eWNI_SME_SCAN_RSP message with failed result code + * + ***NOTE: + * NA + * + * @param pMac Pointer to Global MAC structure + * @param length Indicates length of message + * @param resultCode failed result code + * + * @return None + */ + +void +lim_post_sme_scan_rsp_message(tpAniSirGlobal pMac, + tSirResultCodes resultCode, uint8_t smesessionId, + uint16_t smetransactionId, + uint32_t scan_id) +{ + tpSirSmeScanRsp pSirSmeScanRsp; + tSirMsgQ mmhMsg; + + lim_log(pMac, LOG1, FL("send SME_SCAN_RSP (reasonCode %s)."), + lim_result_code_str(resultCode)); + + pSirSmeScanRsp = qdf_mem_malloc(sizeof(tSirSmeScanRsp)); + if (NULL == pSirSmeScanRsp) { + lim_log(pMac, LOGP, + FL("AllocateMemory failed for eWNI_SME_SCAN_RSP")); + return; + } + + pSirSmeScanRsp->messageType = eWNI_SME_SCAN_RSP; + pSirSmeScanRsp->statusCode = resultCode; + + /*Update SME session Id and transaction Id */ + pSirSmeScanRsp->sessionId = smesessionId; + pSirSmeScanRsp->transcationId = smetransactionId; + pSirSmeScanRsp->scan_id = scan_id; + + mmhMsg.type = eWNI_SME_SCAN_RSP; + mmhMsg.bodyptr = pSirSmeScanRsp; + mmhMsg.bodyval = 0; + + MTRACE(mac_trace(pMac, TRACE_CODE_TX_SME_MSG, NO_SESSION, mmhMsg.type)); +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM /* FEATURE_WLAN_DIAG_SUPPORT */ + lim_diag_event_report(pMac, WLAN_PE_DIAG_SCAN_RSP_EVENT, NULL, + (uint16_t) resultCode, 0); +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + + lim_sys_process_mmh_msg_api(pMac, &mmhMsg, ePROT); + return; + +} /*** lim_post_sme_scan_rsp_message ***/ + +void lim_send_sme_disassoc_deauth_ntf(tpAniSirGlobal pMac, + QDF_STATUS status, uint32_t *pCtx) +{ + tSirMsgQ mmhMsg; + tSirMsgQ *pMsg = (tSirMsgQ *) pCtx; + + mmhMsg.type = pMsg->type; + mmhMsg.bodyptr = pMsg; + mmhMsg.bodyval = 0; + + MTRACE(mac_trace(pMac, TRACE_CODE_TX_SME_MSG, NO_SESSION, mmhMsg.type)); + + lim_sys_process_mmh_msg_api(pMac, &mmhMsg, ePROT); +} + +/** + * lim_send_sme_disassoc_ntf() + * + ***FUNCTION: + * This function is called by limProcessSmeMessages() to send + * eWNI_SME_DISASSOC_RSP/IND message to host + * + ***PARAMS: + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * This function is used for sending eWNI_SME_DISASSOC_CNF, + * or eWNI_SME_DISASSOC_IND to host depending on + * disassociation trigger. + * + * @param peerMacAddr Indicates the peer MAC addr to which + * disassociate was initiated + * @param reasonCode Indicates the reason for Disassociation + * @param disassocTrigger Indicates the trigger for Disassociation + * @param aid Indicates the STAID. This parameter is + * present only on AP. + * + * @return None + */ +void +lim_send_sme_disassoc_ntf(tpAniSirGlobal pMac, + tSirMacAddr peerMacAddr, + tSirResultCodes reasonCode, + uint16_t disassocTrigger, + uint16_t aid, + uint8_t smesessionId, + uint16_t smetransactionId, tpPESession psessionEntry) +{ + + uint8_t *pBuf; + tSirSmeDisassocRsp *pSirSmeDisassocRsp; + tSirSmeDisassocInd *pSirSmeDisassocInd; + uint32_t *pMsg = NULL; + bool failure = false; + tpPESession session = NULL; + uint16_t i, assoc_id; + tpDphHashNode sta_ds = NULL; + struct sir_sme_discon_done_ind *sir_sme_dis_ind; + + lim_log(pMac, LOG1, FL("Disassoc Ntf with trigger : %d reasonCode: %d"), + disassocTrigger, reasonCode); + + switch (disassocTrigger) { + case eLIM_DUPLICATE_ENTRY: + /* + * Duplicate entry is removed at LIM. + * Initiate new entry for other session + */ + lim_log(pMac, LOG1, + FL("Rcvd eLIM_DUPLICATE_ENTRY for " MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(peerMacAddr)); + + for (i = 0; i < pMac->lim.maxBssId; i++) { + if ((&pMac->lim.gpSession[i] != NULL) && + (pMac->lim.gpSession[i].valid) && + (pMac->lim.gpSession[i].pePersona == + QDF_SAP_MODE)) { + /* Find the sta ds entry in another session */ + session = &pMac->lim.gpSession[i]; + sta_ds = dph_lookup_hash_entry(pMac, + peerMacAddr, &assoc_id, + &session->dph.dphHashTable); + } + } + if (sta_ds +#ifdef WLAN_FEATURE_11W + && (!sta_ds->rmfEnabled) +#endif + ) { + if (lim_add_sta(pMac, sta_ds, false, session) != + eSIR_SUCCESS) + lim_log(pMac, LOGE, + FL("could not Add STA with assocId=%d"), + sta_ds->assocId); + } + failure = true; + break; + + case eLIM_HOST_DISASSOC: + /** + * Disassociation response due to + * host triggered disassociation + */ + + pSirSmeDisassocRsp = qdf_mem_malloc(sizeof(tSirSmeDisassocRsp)); + if (NULL == pSirSmeDisassocRsp) { + /* Log error */ + lim_log(pMac, LOGP, FL("Memory allocation failed")); + failure = true; + goto error; + } + lim_log(pMac, LOG1, FL("send eWNI_SME_DISASSOC_RSP with " + "retCode: %d for " MAC_ADDRESS_STR), + reasonCode, MAC_ADDR_ARRAY(peerMacAddr)); + pSirSmeDisassocRsp->messageType = eWNI_SME_DISASSOC_RSP; + pSirSmeDisassocRsp->length = sizeof(tSirSmeDisassocRsp); + /* sessionId */ + pBuf = (uint8_t *) &pSirSmeDisassocRsp->sessionId; + *pBuf = smesessionId; + pBuf++; + + /* transactionId */ + lim_copy_u16(pBuf, smetransactionId); + pBuf += sizeof(uint16_t); + + /* statusCode */ + lim_copy_u32(pBuf, reasonCode); + pBuf += sizeof(tSirResultCodes); + + /* peerMacAddr */ + qdf_mem_copy(pBuf, peerMacAddr, sizeof(tSirMacAddr)); + pBuf += sizeof(tSirMacAddr); + + /* Clear Station Stats */ + /* for sta, it is always 1, IBSS is handled at halInitSta */ + +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM /* FEATURE_WLAN_DIAG_SUPPORT */ + + lim_diag_event_report(pMac, WLAN_PE_DIAG_DISASSOC_RSP_EVENT, + psessionEntry, (uint16_t) reasonCode, 0); +#endif + pMsg = (uint32_t *) pSirSmeDisassocRsp; + break; + + case eLIM_PEER_ENTITY_DISASSOC: + case eLIM_LINK_MONITORING_DISASSOC: + sir_sme_dis_ind = + qdf_mem_malloc(sizeof(*sir_sme_dis_ind)); + if (!sir_sme_dis_ind) { + lim_log(pMac, LOGE, + FL("call to AllocateMemory failed for disconnect indication")); + return; + } + + lim_log(pMac, LOG1, + FL("send eWNI_SME_DISCONNECT_DONE_IND with retCode: %d"), + reasonCode); + + sir_sme_dis_ind->message_type = + eWNI_SME_DISCONNECT_DONE_IND; + sir_sme_dis_ind->length = + sizeof(*sir_sme_dis_ind); + qdf_mem_copy(sir_sme_dis_ind->peer_mac, peerMacAddr, + sizeof(tSirMacAddr)); + sir_sme_dis_ind->session_id = smesessionId; + sir_sme_dis_ind->reason_code = reasonCode; + /* + * Instead of sending deauth reason code as 505 which is + * internal value(eSIR_SME_LOST_LINK_WITH_PEER_RESULT_CODE) + * Send reason code as zero to Supplicant + */ + if (reasonCode == eSIR_SME_LOST_LINK_WITH_PEER_RESULT_CODE) + sir_sme_dis_ind->reason_code = 0; + else + sir_sme_dis_ind->reason_code = reasonCode; + + pMsg = (uint32_t *)sir_sme_dis_ind; + + break; + + default: + /** + * Disassociation indication due to Disassociation + * frame reception from peer entity or due to + * loss of link with peer entity. + */ + pSirSmeDisassocInd = qdf_mem_malloc(sizeof(tSirSmeDisassocInd)); + if (NULL == pSirSmeDisassocInd) { + /* Log error */ + lim_log(pMac, LOGP, FL("Memory allocation failed")); + failure = true; + goto error; + } + lim_log(pMac, LOG1, FL("send eWNI_SME_DISASSOC_IND with " + "retCode: %d for " MAC_ADDRESS_STR), + reasonCode, MAC_ADDR_ARRAY(peerMacAddr)); + pSirSmeDisassocInd->messageType = eWNI_SME_DISASSOC_IND; + pSirSmeDisassocInd->length = sizeof(tSirSmeDisassocInd); + + /* Update SME session Id and Transaction Id */ + pSirSmeDisassocInd->sessionId = smesessionId; + pSirSmeDisassocInd->transactionId = smetransactionId; + pSirSmeDisassocInd->reasonCode = reasonCode; + pBuf = (uint8_t *) &pSirSmeDisassocInd->statusCode; + + lim_copy_u32(pBuf, reasonCode); + pBuf += sizeof(tSirResultCodes); + + qdf_mem_copy(pBuf, psessionEntry->bssId, sizeof(tSirMacAddr)); + pBuf += sizeof(tSirMacAddr); + + qdf_mem_copy(pBuf, peerMacAddr, sizeof(tSirMacAddr)); + +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM /* FEATURE_WLAN_DIAG_SUPPORT */ + lim_diag_event_report(pMac, WLAN_PE_DIAG_DISASSOC_IND_EVENT, + psessionEntry, (uint16_t) reasonCode, 0); +#endif + pMsg = (uint32_t *) pSirSmeDisassocInd; + + break; + } + +error: + /* Delete the PE session Created */ + if ((psessionEntry != NULL) && LIM_IS_STA_ROLE(psessionEntry)) + pe_delete_session(pMac, psessionEntry); + + if (false == failure) + lim_send_sme_disassoc_deauth_ntf(pMac, QDF_STATUS_SUCCESS, + (uint32_t *) pMsg); +} /*** end lim_send_sme_disassoc_ntf() ***/ + +/** ----------------------------------------------------------------- + \brief lim_send_sme_disassoc_ind() - sends SME_DISASSOC_IND + + After receiving disassociation frame from peer entity, this + function sends a eWNI_SME_DISASSOC_IND to SME with a specific + reason code. + + \param pMac - global mac structure + \param pStaDs - station dph hash node + \return none + \sa + ----------------------------------------------------------------- */ +void +lim_send_sme_disassoc_ind(tpAniSirGlobal pMac, tpDphHashNode pStaDs, + tpPESession psessionEntry) +{ + tSirMsgQ mmhMsg; + tSirSmeDisassocInd *pSirSmeDisassocInd; + + pSirSmeDisassocInd = qdf_mem_malloc(sizeof(tSirSmeDisassocInd)); + if (NULL == pSirSmeDisassocInd) { + lim_log(pMac, LOGP, + FL("AllocateMemory failed for eWNI_SME_DISASSOC_IND")); + return; + } + + pSirSmeDisassocInd->messageType = eWNI_SME_DISASSOC_IND; + pSirSmeDisassocInd->length = sizeof(tSirSmeDisassocInd); + + pSirSmeDisassocInd->sessionId = psessionEntry->smeSessionId; + pSirSmeDisassocInd->transactionId = psessionEntry->transactionId; + pSirSmeDisassocInd->statusCode = eSIR_SME_DEAUTH_STATUS; + pSirSmeDisassocInd->reasonCode = pStaDs->mlmStaContext.disassocReason; + + qdf_mem_copy(pSirSmeDisassocInd->bssid.bytes, psessionEntry->bssId, + QDF_MAC_ADDR_SIZE); + + qdf_mem_copy(pSirSmeDisassocInd->peer_macaddr.bytes, pStaDs->staAddr, + QDF_MAC_ADDR_SIZE); + + pSirSmeDisassocInd->staId = pStaDs->staIndex; + + mmhMsg.type = eWNI_SME_DISASSOC_IND; + mmhMsg.bodyptr = pSirSmeDisassocInd; + mmhMsg.bodyval = 0; + + MTRACE(mac_trace(pMac, TRACE_CODE_TX_SME_MSG, + psessionEntry->peSessionId, mmhMsg.type)); +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM /* FEATURE_WLAN_DIAG_SUPPORT */ + lim_diag_event_report(pMac, WLAN_PE_DIAG_DISASSOC_IND_EVENT, psessionEntry, + 0, (uint16_t) pStaDs->mlmStaContext.disassocReason); +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + + lim_sys_process_mmh_msg_api(pMac, &mmhMsg, ePROT); + +} /*** end lim_send_sme_disassoc_ind() ***/ + +/** ----------------------------------------------------------------- + \brief lim_send_sme_deauth_ind() - sends SME_DEAUTH_IND + + After receiving deauthentication frame from peer entity, this + function sends a eWNI_SME_DEAUTH_IND to SME with a specific + reason code. + + \param pMac - global mac structure + \param pStaDs - station dph hash node + \return none + \sa + ----------------------------------------------------------------- */ +void +lim_send_sme_deauth_ind(tpAniSirGlobal pMac, tpDphHashNode pStaDs, + tpPESession psessionEntry) +{ + tSirMsgQ mmhMsg; + tSirSmeDeauthInd *pSirSmeDeauthInd; + + pSirSmeDeauthInd = qdf_mem_malloc(sizeof(tSirSmeDeauthInd)); + if (NULL == pSirSmeDeauthInd) { + lim_log(pMac, LOGP, + FL("AllocateMemory failed for eWNI_SME_DEAUTH_IND ")); + return; + } + + pSirSmeDeauthInd->messageType = eWNI_SME_DEAUTH_IND; + pSirSmeDeauthInd->length = sizeof(tSirSmeDeauthInd); + + pSirSmeDeauthInd->sessionId = psessionEntry->smeSessionId; + pSirSmeDeauthInd->transactionId = psessionEntry->transactionId; + if (eSIR_INFRA_AP_MODE == psessionEntry->bssType) { + pSirSmeDeauthInd->statusCode = + (tSirResultCodes) pStaDs->mlmStaContext.cleanupTrigger; + } else { + /* Need to indicatet he reascon code over the air */ + pSirSmeDeauthInd->statusCode = + (tSirResultCodes) pStaDs->mlmStaContext.disassocReason; + } + /* BSSID */ + qdf_mem_copy(pSirSmeDeauthInd->bssid.bytes, psessionEntry->bssId, + QDF_MAC_ADDR_SIZE); + /* peerMacAddr */ + qdf_mem_copy(pSirSmeDeauthInd->peer_macaddr.bytes, pStaDs->staAddr, + QDF_MAC_ADDR_SIZE); + pSirSmeDeauthInd->reasonCode = pStaDs->mlmStaContext.disassocReason; + + pSirSmeDeauthInd->staId = pStaDs->staIndex; + if (eSIR_MAC_PEER_STA_REQ_LEAVING_BSS_REASON == + pStaDs->mlmStaContext.disassocReason) + pSirSmeDeauthInd->rssi = pStaDs->del_sta_ctx_rssi; + + mmhMsg.type = eWNI_SME_DEAUTH_IND; + mmhMsg.bodyptr = pSirSmeDeauthInd; + mmhMsg.bodyval = 0; + + MTRACE(mac_trace_msg_tx(pMac, psessionEntry->peSessionId, mmhMsg.type)); +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM /* FEATURE_WLAN_DIAG_SUPPORT */ + lim_diag_event_report(pMac, WLAN_PE_DIAG_DEAUTH_IND_EVENT, psessionEntry, + 0, pStaDs->mlmStaContext.cleanupTrigger); +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + + lim_sys_process_mmh_msg_api(pMac, &mmhMsg, ePROT); + return; +} /*** end lim_send_sme_deauth_ind() ***/ + +#ifdef FEATURE_WLAN_TDLS +/** + * lim_send_sme_tdls_del_sta_ind() + * + ***FUNCTION: + * This function is called to send the TDLS STA context deletion to SME. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * + ***NOTE: + * NA + * + * @param pMac - Pointer to global MAC structure + * @param pStaDs - Pointer to internal STA Datastructure + * @param psessionEntry - Pointer to the session entry + * @param reasonCode - Reason for TDLS sta deletion + * @return None + */ +void +lim_send_sme_tdls_del_sta_ind(tpAniSirGlobal pMac, tpDphHashNode pStaDs, + tpPESession psessionEntry, uint16_t reasonCode) +{ + tSirMsgQ mmhMsg; + tSirTdlsDelStaInd *pSirTdlsDelStaInd; + + pSirTdlsDelStaInd = qdf_mem_malloc(sizeof(tSirTdlsDelStaInd)); + if (NULL == pSirTdlsDelStaInd) { + lim_log(pMac, LOGP, + FL + ("AllocateMemory failed for eWNI_SME_TDLS_DEL_STA_IND ")); + return; + } + lim_log(pMac, LOG1, FL("Delete TDLS Peer "MAC_ADDRESS_STR + "with reason code %d"), + MAC_ADDR_ARRAY(pStaDs->staAddr), reasonCode); + /* messageType */ + pSirTdlsDelStaInd->messageType = eWNI_SME_TDLS_DEL_STA_IND; + pSirTdlsDelStaInd->length = sizeof(tSirTdlsDelStaInd); + + /* sessionId */ + pSirTdlsDelStaInd->sessionId = psessionEntry->smeSessionId; + + /* peerMacAddr */ + qdf_mem_copy(pSirTdlsDelStaInd->peermac.bytes, pStaDs->staAddr, + QDF_MAC_ADDR_SIZE); + + /* staId */ + lim_copy_u16((uint8_t *) (&pSirTdlsDelStaInd->staId), + (uint16_t) pStaDs->staIndex); + + /* reasonCode */ + lim_copy_u16((uint8_t *) (&pSirTdlsDelStaInd->reasonCode), reasonCode); + + mmhMsg.type = eWNI_SME_TDLS_DEL_STA_IND; + mmhMsg.bodyptr = pSirTdlsDelStaInd; + mmhMsg.bodyval = 0; + + lim_sys_process_mmh_msg_api(pMac, &mmhMsg, ePROT); + return; +} /*** end lim_send_sme_tdls_del_sta_ind() ***/ + +/** + * lim_send_sme_tdls_delete_all_peer_ind() + * + ***FUNCTION: + * This function is called to send the eWNI_SME_TDLS_DEL_ALL_PEER_IND + * message to SME. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * + ***NOTE: + * NA + * + * @param pMac - Pointer to global MAC structure + * @param psessionEntry - Pointer to the session entry + * @return None + */ +void +lim_send_sme_tdls_delete_all_peer_ind(tpAniSirGlobal pMac, tpPESession psessionEntry) +{ + tSirMsgQ mmhMsg; + tSirTdlsDelAllPeerInd *pSirTdlsDelAllPeerInd; + + pSirTdlsDelAllPeerInd = qdf_mem_malloc(sizeof(tSirTdlsDelAllPeerInd)); + if (NULL == pSirTdlsDelAllPeerInd) { + lim_log(pMac, LOGP, + FL + ("AllocateMemory failed for eWNI_SME_TDLS_DEL_ALL_PEER_IND")); + return; + } + /* messageType */ + pSirTdlsDelAllPeerInd->messageType = eWNI_SME_TDLS_DEL_ALL_PEER_IND; + pSirTdlsDelAllPeerInd->length = sizeof(tSirTdlsDelAllPeerInd); + + /* sessionId */ + pSirTdlsDelAllPeerInd->sessionId = psessionEntry->smeSessionId; + + mmhMsg.type = eWNI_SME_TDLS_DEL_ALL_PEER_IND; + mmhMsg.bodyptr = pSirTdlsDelAllPeerInd; + mmhMsg.bodyval = 0; + + lim_sys_process_mmh_msg_api(pMac, &mmhMsg, ePROT); + return; +} /*** end lim_send_sme_tdls_delete_all_peer_ind() ***/ + +/** + * lim_send_sme_mgmt_tx_completion() + * + ***FUNCTION: + * This function is called to send the eWNI_SME_MGMT_FRM_TX_COMPLETION_IND + * message to SME. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * + ***NOTE: + * NA + * + * @param pMac - Pointer to global MAC structure + * @param psessionEntry - Pointer to the session entry + * @param txCompleteStatus - TX Complete Status of Mgmt Frames + * @return None + */ +void +lim_send_sme_mgmt_tx_completion(tpAniSirGlobal pMac, + uint32_t sme_session_id, + uint32_t txCompleteStatus) +{ + tSirMsgQ mmhMsg; + tSirMgmtTxCompletionInd *pSirMgmtTxCompletionInd; + + pSirMgmtTxCompletionInd = + qdf_mem_malloc(sizeof(tSirMgmtTxCompletionInd)); + if (NULL == pSirMgmtTxCompletionInd) { + lim_log(pMac, LOGP, + FL + ("AllocateMemory failed for eWNI_SME_MGMT_FRM_TX_COMPLETION_IND")); + return; + } + /* messageType */ + pSirMgmtTxCompletionInd->messageType = + eWNI_SME_MGMT_FRM_TX_COMPLETION_IND; + pSirMgmtTxCompletionInd->length = sizeof(tSirMgmtTxCompletionInd); + + /* sessionId */ + pSirMgmtTxCompletionInd->sessionId = sme_session_id; + + pSirMgmtTxCompletionInd->txCompleteStatus = txCompleteStatus; + + mmhMsg.type = eWNI_SME_MGMT_FRM_TX_COMPLETION_IND; + mmhMsg.bodyptr = pSirMgmtTxCompletionInd; + mmhMsg.bodyval = 0; + + lim_sys_process_mmh_msg_api(pMac, &mmhMsg, ePROT); + return; +} /*** end lim_send_sme_tdls_delete_all_peer_ind() ***/ + +void lim_send_sme_tdls_event_notify(tpAniSirGlobal pMac, uint16_t msgType, + void *events) +{ + tSirMsgQ mmhMsg; + + switch (msgType) { + case SIR_HAL_TDLS_SHOULD_DISCOVER: + mmhMsg.type = eWNI_SME_TDLS_SHOULD_DISCOVER; + break; + case SIR_HAL_TDLS_SHOULD_TEARDOWN: + mmhMsg.type = eWNI_SME_TDLS_SHOULD_TEARDOWN; + break; + case SIR_HAL_TDLS_PEER_DISCONNECTED: + mmhMsg.type = eWNI_SME_TDLS_PEER_DISCONNECTED; + break; + case SIR_HAL_TDLS_CONNECTION_TRACKER_NOTIFICATION: + mmhMsg.type = eWNI_SME_TDLS_CONNECTION_TRACKER_NOTIFICATION; + break; + } + + mmhMsg.bodyptr = events; + mmhMsg.bodyval = 0; + lim_sys_process_mmh_msg_api(pMac, &mmhMsg, ePROT); + return; +} +#endif /* FEATURE_WLAN_TDLS */ + +/** + * lim_send_sme_deauth_ntf() + * + ***FUNCTION: + * This function is called by limProcessSmeMessages() to send + * eWNI_SME_DISASSOC_RSP/IND message to host + * + ***PARAMS: + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * This function is used for sending eWNI_SME_DEAUTH_CNF or + * eWNI_SME_DEAUTH_IND to host depending on deauthentication trigger. + * + * @param peerMacAddr Indicates the peer MAC addr to which + * deauthentication was initiated + * @param reasonCode Indicates the reason for Deauthetication + * @param deauthTrigger Indicates the trigger for Deauthetication + * @param aid Indicates the STAID. This parameter is present + * only on AP. + * + * @return None + */ +void +lim_send_sme_deauth_ntf(tpAniSirGlobal pMac, tSirMacAddr peerMacAddr, + tSirResultCodes reasonCode, uint16_t deauthTrigger, + uint16_t aid, uint8_t smesessionId, + uint16_t smetransactionId) +{ + uint8_t *pBuf; + tSirSmeDeauthRsp *pSirSmeDeauthRsp; + tSirSmeDeauthInd *pSirSmeDeauthInd; + tpPESession psessionEntry; + uint8_t sessionId; + uint32_t *pMsg; + struct sir_sme_discon_done_ind *sir_sme_dis_ind; + + psessionEntry = pe_find_session_by_bssid(pMac, peerMacAddr, &sessionId); + switch (deauthTrigger) { + case eLIM_HOST_DEAUTH: + /** + * Deauthentication response to host triggered + * deauthentication. + */ + pSirSmeDeauthRsp = qdf_mem_malloc(sizeof(tSirSmeDeauthRsp)); + if (NULL == pSirSmeDeauthRsp) { + /* Log error */ + lim_log(pMac, LOGP, + FL + ("call to AllocateMemory failed for eWNI_SME_DEAUTH_RSP")); + + return; + } + lim_log(pMac, LOG1, FL("send eWNI_SME_DEAUTH_RSP with " + "retCode: %d for" MAC_ADDRESS_STR), + reasonCode, MAC_ADDR_ARRAY(peerMacAddr)); + pSirSmeDeauthRsp->messageType = eWNI_SME_DEAUTH_RSP; + pSirSmeDeauthRsp->length = sizeof(tSirSmeDeauthRsp); + pSirSmeDeauthRsp->statusCode = reasonCode; + pSirSmeDeauthRsp->sessionId = smesessionId; + pSirSmeDeauthRsp->transactionId = smetransactionId; + + pBuf = (uint8_t *) pSirSmeDeauthRsp->peer_macaddr.bytes; + qdf_mem_copy(pBuf, peerMacAddr, sizeof(tSirMacAddr)); + +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM /* FEATURE_WLAN_DIAG_SUPPORT */ + lim_diag_event_report(pMac, WLAN_PE_DIAG_DEAUTH_RSP_EVENT, + psessionEntry, 0, (uint16_t) reasonCode); +#endif + pMsg = (uint32_t *) pSirSmeDeauthRsp; + + break; + + case eLIM_PEER_ENTITY_DEAUTH: + case eLIM_LINK_MONITORING_DEAUTH: + sir_sme_dis_ind = + qdf_mem_malloc(sizeof(*sir_sme_dis_ind)); + if (!sir_sme_dis_ind) { + lim_log(pMac, LOGE, + FL("call to AllocateMemory failed for disconnect indication")); + return; + } + + lim_log(pMac, LOG1, + FL("send eWNI_SME_DISCONNECT_DONE_IND withretCode: %d"), + reasonCode); + + sir_sme_dis_ind->message_type = + eWNI_SME_DISCONNECT_DONE_IND; + sir_sme_dis_ind->length = + sizeof(*sir_sme_dis_ind); + sir_sme_dis_ind->session_id = smesessionId; + sir_sme_dis_ind->reason_code = reasonCode; + qdf_mem_copy(sir_sme_dis_ind->peer_mac, peerMacAddr, + ETH_ALEN); + /* + * Instead of sending deauth reason code as 505 which is + * internal value(eSIR_SME_LOST_LINK_WITH_PEER_RESULT_CODE) + * Send reason code as zero to Supplicant + */ + if (reasonCode == eSIR_SME_LOST_LINK_WITH_PEER_RESULT_CODE) + sir_sme_dis_ind->reason_code = 0; + else + sir_sme_dis_ind->reason_code = reasonCode; + + pMsg = (uint32_t *)sir_sme_dis_ind; + + break; + + default: + /** + * Deauthentication indication due to Deauthentication + * frame reception from peer entity or due to + * loss of link with peer entity. + */ + pSirSmeDeauthInd = qdf_mem_malloc(sizeof(tSirSmeDeauthInd)); + if (NULL == pSirSmeDeauthInd) { + /* Log error */ + lim_log(pMac, LOGP, + FL + ("call to AllocateMemory failed for eWNI_SME_DEAUTH_Ind")); + + return; + } + lim_log(pMac, LOG1, FL("send eWNI_SME_DEAUTH_IND with " + "retCode: %d for " MAC_ADDRESS_STR), + reasonCode, MAC_ADDR_ARRAY(peerMacAddr)); + pSirSmeDeauthInd->messageType = eWNI_SME_DEAUTH_IND; + pSirSmeDeauthInd->length = sizeof(tSirSmeDeauthInd); + pSirSmeDeauthInd->reasonCode = eSIR_MAC_UNSPEC_FAILURE_REASON; + + /* sessionId */ + pBuf = (uint8_t *) &pSirSmeDeauthInd->sessionId; + *pBuf++ = smesessionId; + + /* transaction ID */ + lim_copy_u16(pBuf, smetransactionId); + pBuf += sizeof(uint16_t); + + /* status code */ + lim_copy_u32(pBuf, reasonCode); + pBuf += sizeof(tSirResultCodes); + + /* bssId */ + qdf_mem_copy(pBuf, psessionEntry->bssId, sizeof(tSirMacAddr)); + pBuf += sizeof(tSirMacAddr); + + /* peerMacAddr */ + qdf_mem_copy(pSirSmeDeauthInd->peer_macaddr.bytes, peerMacAddr, + QDF_MAC_ADDR_SIZE); + +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM /* FEATURE_WLAN_DIAG_SUPPORT */ + lim_diag_event_report(pMac, WLAN_PE_DIAG_DEAUTH_IND_EVENT, + psessionEntry, 0, (uint16_t) reasonCode); +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + pMsg = (uint32_t *) pSirSmeDeauthInd; + + break; + } + + /*Delete the PE session created */ + if (psessionEntry != NULL) { + pe_delete_session(pMac, psessionEntry); + } + + lim_send_sme_disassoc_deauth_ntf(pMac, QDF_STATUS_SUCCESS, + (uint32_t *) pMsg); + +} /*** end lim_send_sme_deauth_ntf() ***/ + +/** + * lim_send_sme_wm_status_change_ntf() - Send Notification + * @mac_ctx: Global MAC Context + * @status_change_code: Indicates the change in the wireless medium. + * @status_change_info: Indicates the information associated with + * change in the wireless medium. + * @info_len: Indicates the length of status change information + * being sent. + * @session_id SessionID + * + * This function is called by limProcessSmeMessages() to send + * eWNI_SME_WM_STATUS_CHANGE_NTF message to host. + * + * Return: None + */ +void +lim_send_sme_wm_status_change_ntf(tpAniSirGlobal mac_ctx, + tSirSmeStatusChangeCode status_change_code, + uint32_t *status_change_info, uint16_t info_len, uint8_t session_id) +{ + tSirMsgQ msg; + tSirSmeWmStatusChangeNtf *wm_status_change_ntf; + uint32_t max_info_len; + + wm_status_change_ntf = qdf_mem_malloc(sizeof(tSirSmeWmStatusChangeNtf)); + if (NULL == wm_status_change_ntf) { + lim_log(mac_ctx, LOGE, + FL("Mem Alloc failed - eWNI_SME_WM_STATUS_CHANGE_NTF")); + return; + } + + msg.type = eWNI_SME_WM_STATUS_CHANGE_NTF; + msg.bodyval = 0; + msg.bodyptr = wm_status_change_ntf; + + switch (status_change_code) { + case eSIR_SME_AP_CAPS_CHANGED: + max_info_len = sizeof(tSirSmeApNewCaps); + break; + case eSIR_SME_JOINED_NEW_BSS: + max_info_len = sizeof(tSirSmeNewBssInfo); + break; + default: + max_info_len = sizeof(wm_status_change_ntf->statusChangeInfo); + break; + } + + switch (status_change_code) { + case eSIR_SME_RADAR_DETECTED: + break; + default: + wm_status_change_ntf->messageType = + eWNI_SME_WM_STATUS_CHANGE_NTF; + wm_status_change_ntf->statusChangeCode = status_change_code; + wm_status_change_ntf->length = sizeof(tSirSmeWmStatusChangeNtf); + wm_status_change_ntf->sessionId = session_id; + if (info_len <= max_info_len && status_change_info) { + qdf_mem_copy( + (uint8_t *) &wm_status_change_ntf->statusChangeInfo, + (uint8_t *) status_change_info, info_len); + } + lim_log(mac_ctx, LOGE, + FL("**---** StatusChg: code 0x%x, length %d **---**"), + status_change_code, info_len); + break; + } + + MTRACE(mac_trace(mac_ctx, TRACE_CODE_TX_SME_MSG, session_id, msg.type)); + if (eSIR_SUCCESS != lim_sys_process_mmh_msg_api(mac_ctx, &msg, ePROT)) { + qdf_mem_free(wm_status_change_ntf); + lim_log(mac_ctx, LOGP, + FL("lim_sys_process_mmh_msg_api failed")); + } + +} /*** end lim_send_sme_wm_status_change_ntf() ***/ + +/** + * lim_send_sme_set_context_rsp() + * + ***FUNCTION: + * This function is called by limProcessSmeMessages() to send + * eWNI_SME_SETCONTEXT_RSP message to host + * + ***PARAMS: + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * + * @param pMac Pointer to Global MAC structure + * @param peerMacAddr Indicates the peer MAC addr to which + * setContext was performed + * @param aid Indicates the aid corresponding to the peer MAC + * address + * @param resultCode Indicates the result of previously issued + * eWNI_SME_SETCONTEXT_RSP message + * + * @return None + */ +void +lim_send_sme_set_context_rsp(tpAniSirGlobal pMac, + struct qdf_mac_addr peer_macaddr, uint16_t aid, + tSirResultCodes resultCode, + tpPESession psessionEntry, uint8_t smesessionId, + uint16_t smetransactionId) +{ + tSirMsgQ mmhMsg; + tSirSmeSetContextRsp *pSirSmeSetContextRsp; + + pSirSmeSetContextRsp = qdf_mem_malloc(sizeof(tSirSmeSetContextRsp)); + if (NULL == pSirSmeSetContextRsp) { + /* Log error */ + lim_log(pMac, LOGP, + FL + ("call to AllocateMemory failed for SmeSetContextRsp")); + + return; + } + + pSirSmeSetContextRsp->messageType = eWNI_SME_SETCONTEXT_RSP; + pSirSmeSetContextRsp->length = sizeof(tSirSmeSetContextRsp); + pSirSmeSetContextRsp->statusCode = resultCode; + + qdf_copy_macaddr(&pSirSmeSetContextRsp->peer_macaddr, &peer_macaddr); + + /* Update SME session and transaction Id */ + pSirSmeSetContextRsp->sessionId = smesessionId; + pSirSmeSetContextRsp->transactionId = smetransactionId; + + mmhMsg.type = eWNI_SME_SETCONTEXT_RSP; + mmhMsg.bodyptr = pSirSmeSetContextRsp; + mmhMsg.bodyval = 0; + if (NULL == psessionEntry) { + MTRACE(mac_trace(pMac, TRACE_CODE_TX_SME_MSG, + NO_SESSION, mmhMsg.type)); + } else { + MTRACE(mac_trace(pMac, TRACE_CODE_TX_SME_MSG, + psessionEntry->peSessionId, mmhMsg.type)); + } + +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM /* FEATURE_WLAN_DIAG_SUPPORT */ + lim_diag_event_report(pMac, WLAN_PE_DIAG_SETCONTEXT_RSP_EVENT, + psessionEntry, (uint16_t) resultCode, 0); +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + + lim_sys_process_mmh_msg_api(pMac, &mmhMsg, ePROT); +} /*** end lim_send_sme_set_context_rsp() ***/ + +/** + * lim_send_sme_neighbor_bss_ind() + * + ***FUNCTION: + * This function is called by lim_lookup_nadd_hash_entry() to send + * eWNI_SME_NEIGHBOR_BSS_IND message to host + * + ***PARAMS: + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * This function is used for sending eWNI_SME_NEIGHBOR_BSS_IND to + * host upon detecting new BSS during background scanning if CFG + * option is enabled for sending such indication + * + * @param pMac - Pointer to Global MAC structure + * @return None + */ + +void +lim_send_sme_neighbor_bss_ind(tpAniSirGlobal pMac, tLimScanResultNode *pBssDescr) +{ + tSirMsgQ msgQ; + uint32_t val; + tSirSmeNeighborBssInd *pNewBssInd; + + if ((pMac->lim.gLimSmeState != eLIM_SME_LINK_EST_WT_SCAN_STATE) || + ((pMac->lim.gLimSmeState == eLIM_SME_LINK_EST_WT_SCAN_STATE) && + pMac->lim.gLimRspReqd)) { + /* LIM is not in background scan state OR */ + /* current scan is initiated by HDD. */ + /* No need to send new BSS indication to HDD */ + return; + } + + if (wlan_cfg_get_int(pMac, WNI_CFG_NEW_BSS_FOUND_IND, &val) != + eSIR_SUCCESS) { + lim_log(pMac, LOGP, + FL("could not get NEIGHBOR_BSS_IND from CFG")); + + return; + } + + if (val == 0) + return; + + /** + * Need to indicate new BSSs found during + * background scanning to host. + * Allocate buffer for sending indication. + * Length of buffer is length of BSS description + * and length of header itself + */ + val = pBssDescr->bssDescription.length + sizeof(uint16_t) + + sizeof(uint32_t) + sizeof(uint8_t); + pNewBssInd = qdf_mem_malloc(val); + if (NULL == pNewBssInd) { + /* Log error */ + lim_log(pMac, LOGP, + FL + ("call to AllocateMemory failed for eWNI_SME_NEIGHBOR_BSS_IND")); + + return; + } + + pNewBssInd->messageType = eWNI_SME_NEIGHBOR_BSS_IND; + pNewBssInd->length = (uint16_t) val; + pNewBssInd->sessionId = 0; + + qdf_mem_copy((uint8_t *) pNewBssInd->bssDescription, + (uint8_t *) &pBssDescr->bssDescription, + pBssDescr->bssDescription.length + sizeof(uint16_t)); + + msgQ.type = eWNI_SME_NEIGHBOR_BSS_IND; + msgQ.bodyptr = pNewBssInd; + msgQ.bodyval = 0; + MTRACE(mac_trace(pMac, TRACE_CODE_TX_SME_MSG, NO_SESSION, msgQ.type)); + lim_sys_process_mmh_msg_api(pMac, &msgQ, ePROT); +} /*** end lim_send_sme_neighbor_bss_ind() ***/ + +/** ----------------------------------------------------------------- + \brief lim_send_sme_addts_rsp() - sends SME ADDTS RSP + \ This function sends a eWNI_SME_ADDTS_RSP to SME. + \ SME only looks at rc and tspec field. + \param pMac - global mac structure + \param rspReqd - is SmeAddTsRsp required + \param status - status code of SME_ADD_TS_RSP + \return tspec + \sa + ----------------------------------------------------------------- */ +void +lim_send_sme_addts_rsp(tpAniSirGlobal pMac, uint8_t rspReqd, uint32_t status, + tpPESession psessionEntry, tSirMacTspecIE tspec, + uint8_t smesessionId, uint16_t smetransactionId) +{ + tpSirAddtsRsp rsp; + tSirMsgQ mmhMsg; + + if (!rspReqd) + return; + + rsp = qdf_mem_malloc(sizeof(tSirAddtsRsp)); + if (NULL == rsp) { + lim_log(pMac, LOGP, FL("AllocateMemory failed for ADDTS_RSP")); + return; + } + + rsp->messageType = eWNI_SME_ADDTS_RSP; + rsp->rc = status; + rsp->rsp.status = (enum eSirMacStatusCodes)status; + rsp->rsp.tspec = tspec; + /* Update SME session Id and transcation Id */ + rsp->sessionId = smesessionId; + rsp->transactionId = smetransactionId; + + mmhMsg.type = eWNI_SME_ADDTS_RSP; + mmhMsg.bodyptr = rsp; + mmhMsg.bodyval = 0; + if (NULL == psessionEntry) { + MTRACE(mac_trace(pMac, TRACE_CODE_TX_SME_MSG, + NO_SESSION, mmhMsg.type)); + } else { + MTRACE(mac_trace(pMac, TRACE_CODE_TX_SME_MSG, + psessionEntry->peSessionId, mmhMsg.type)); + } +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM /* FEATURE_WLAN_DIAG_SUPPORT */ + lim_diag_event_report(pMac, WLAN_PE_DIAG_ADDTS_RSP_EVENT, psessionEntry, 0, + 0); +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + + lim_sys_process_mmh_msg_api(pMac, &mmhMsg, ePROT); + return; +} + +void +lim_send_sme_delts_rsp(tpAniSirGlobal pMac, tpSirDeltsReq delts, uint32_t status, + tpPESession psessionEntry, uint8_t smesessionId, + uint16_t smetransactionId) +{ + tpSirDeltsRsp rsp; + tSirMsgQ mmhMsg; + + lim_log(pMac, LOGW, "SendSmeDeltsRsp (aid %d, tsid %d, up %d) status %d", + delts->aid, + delts->req.tsinfo.traffic.tsid, + delts->req.tsinfo.traffic.userPrio, status); + if (!delts->rspReqd) + return; + + rsp = qdf_mem_malloc(sizeof(tSirDeltsRsp)); + if (NULL == rsp) { + /* Log error */ + lim_log(pMac, LOGP, FL("AllocateMemory failed for DELTS_RSP")); + return; + } + + if (psessionEntry != NULL) { + + rsp->aid = delts->aid; + qdf_copy_macaddr(&rsp->macaddr, &delts->macaddr); + qdf_mem_copy((uint8_t *) &rsp->rsp, (uint8_t *) &delts->req, + sizeof(tSirDeltsReqInfo)); + } + + rsp->messageType = eWNI_SME_DELTS_RSP; + rsp->rc = status; + + /* Update SME session Id and transcation Id */ + rsp->sessionId = smesessionId; + rsp->transactionId = smetransactionId; + + mmhMsg.type = eWNI_SME_DELTS_RSP; + mmhMsg.bodyptr = rsp; + mmhMsg.bodyval = 0; + if (NULL == psessionEntry) { + MTRACE(mac_trace(pMac, TRACE_CODE_TX_SME_MSG, + NO_SESSION, mmhMsg.type)); + } else { + MTRACE(mac_trace(pMac, TRACE_CODE_TX_SME_MSG, + psessionEntry->peSessionId, mmhMsg.type)); + } +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM /* FEATURE_WLAN_DIAG_SUPPORT */ + lim_diag_event_report(pMac, WLAN_PE_DIAG_DELTS_RSP_EVENT, psessionEntry, + (uint16_t) status, 0); +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + + lim_sys_process_mmh_msg_api(pMac, &mmhMsg, ePROT); +} + +void +lim_send_sme_delts_ind(tpAniSirGlobal pMac, tpSirDeltsReqInfo delts, uint16_t aid, + tpPESession psessionEntry) +{ + tpSirDeltsRsp rsp; + tSirMsgQ mmhMsg; + + lim_log(pMac, LOGW, "SendSmeDeltsInd (aid %d, tsid %d, up %d)", + aid, delts->tsinfo.traffic.tsid, delts->tsinfo.traffic.userPrio); + + rsp = qdf_mem_malloc(sizeof(tSirDeltsRsp)); + if (NULL == rsp) { + /* Log error */ + lim_log(pMac, LOGP, FL("AllocateMemory failed for DELTS_IND")); + return; + } + + rsp->messageType = eWNI_SME_DELTS_IND; + rsp->rc = eSIR_SUCCESS; + rsp->aid = aid; + qdf_mem_copy((uint8_t *) &rsp->rsp, (uint8_t *) delts, sizeof(*delts)); + + /* Update SME session Id and SME transaction Id */ + + rsp->sessionId = psessionEntry->smeSessionId; + rsp->transactionId = psessionEntry->transactionId; + + mmhMsg.type = eWNI_SME_DELTS_IND; + mmhMsg.bodyptr = rsp; + mmhMsg.bodyval = 0; + MTRACE(mac_trace_msg_tx(pMac, psessionEntry->peSessionId, mmhMsg.type)); +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM /* FEATURE_WLAN_DIAG_SUPPORT */ + lim_diag_event_report(pMac, WLAN_PE_DIAG_DELTS_IND_EVENT, psessionEntry, 0, + 0); +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + + lim_sys_process_mmh_msg_api(pMac, &mmhMsg, ePROT); +} + +/** + * lim_send_sme_pe_statistics_rsp() + * + ***FUNCTION: + * This function is called to send 802.11 statistics response to HDD. + * This function posts the result back to HDD. This is a response to + * HDD's request for statistics. + * + ***PARAMS: + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param pMac Pointer to Global MAC structure + * @param p80211Stats Statistics sent in response + * @param resultCode TODO: + * + * + * @return none + */ + +void +lim_send_sme_pe_statistics_rsp(tpAniSirGlobal pMac, uint16_t msgType, void *stats) +{ + tSirMsgQ mmhMsg; + uint8_t sessionId; + tAniGetPEStatsRsp *pPeStats = (tAniGetPEStatsRsp *) stats; + tpPESession pPeSessionEntry; + + /* Get the Session Id based on Sta Id */ + pPeSessionEntry = + pe_find_session_by_sta_id(pMac, pPeStats->staId, &sessionId); + + /* Fill the Session Id */ + if (NULL != pPeSessionEntry) { + /* Fill the Session Id */ + pPeStats->sessionId = pPeSessionEntry->smeSessionId; + } + + pPeStats->msgType = eWNI_SME_GET_STATISTICS_RSP; + + /* msgType should be WMA_GET_STATISTICS_RSP */ + mmhMsg.type = eWNI_SME_GET_STATISTICS_RSP; + + mmhMsg.bodyptr = stats; + mmhMsg.bodyval = 0; + MTRACE(mac_trace(pMac, TRACE_CODE_TX_SME_MSG, NO_SESSION, mmhMsg.type)); + lim_sys_process_mmh_msg_api(pMac, &mmhMsg, ePROT); + + return; + +} /*** end lim_send_sme_pe_statistics_rsp() ***/ + +#ifdef FEATURE_WLAN_ESE +/** + * lim_send_sme_pe_ese_tsm_rsp() - send tsm response + * @pMac: Pointer to global pMac structure + * @pStats: Pointer to TSM Stats + * + * This function is called to send tsm stats response to HDD. + * This function posts the result back to HDD. This is a response to + * HDD's request to get tsm stats. + * + * Return: None + */ +void lim_send_sme_pe_ese_tsm_rsp(tpAniSirGlobal pMac, + tAniGetTsmStatsRsp *pStats) +{ + tSirMsgQ mmhMsg; + uint8_t sessionId; + tAniGetTsmStatsRsp *pPeStats = (tAniGetTsmStatsRsp *) pStats; + tpPESession pPeSessionEntry = NULL; + + /* Get the Session Id based on Sta Id */ + pPeSessionEntry = + pe_find_session_by_sta_id(pMac, pPeStats->staId, &sessionId); + + /* Fill the Session Id */ + if (NULL != pPeSessionEntry) { + /* Fill the Session Id */ + pPeStats->sessionId = pPeSessionEntry->smeSessionId; + } else { + PELOGE(lim_log + (pMac, LOGE, FL("Session not found for the Sta id(%d)"), + pPeStats->staId);) + qdf_mem_free(pPeStats->tsmStatsReq); + qdf_mem_free(pPeStats); + return; + } + + pPeStats->msgType = eWNI_SME_GET_TSM_STATS_RSP; + pPeStats->tsmMetrics.RoamingCount + = pPeSessionEntry->eseContext.tsm.tsmMetrics.RoamingCount; + pPeStats->tsmMetrics.RoamingDly + = pPeSessionEntry->eseContext.tsm.tsmMetrics.RoamingDly; + + mmhMsg.type = eWNI_SME_GET_TSM_STATS_RSP; + mmhMsg.bodyptr = pStats; + mmhMsg.bodyval = 0; + MTRACE(mac_trace(pMac, TRACE_CODE_TX_SME_MSG, sessionId, mmhMsg.type)); + lim_sys_process_mmh_msg_api(pMac, &mmhMsg, ePROT); + + return; +} /*** end lim_send_sme_pe_ese_tsm_rsp() ***/ + +#endif /* FEATURE_WLAN_ESE */ + +void +lim_send_sme_ibss_peer_ind(tpAniSirGlobal pMac, + tSirMacAddr peerMacAddr, + uint16_t staIndex, + uint8_t ucastIdx, + uint8_t bcastIdx, + uint8_t *beacon, + uint16_t beaconLen, uint16_t msgType, uint8_t sessionId) +{ + tSirMsgQ mmhMsg; + tSmeIbssPeerInd *pNewPeerInd; + + pNewPeerInd = qdf_mem_malloc(sizeof(tSmeIbssPeerInd) + beaconLen); + if (NULL == pNewPeerInd) { + PELOGE(lim_log(pMac, LOGE, FL("Failed to allocate memory"));) + return; + } + + qdf_mem_copy((uint8_t *) pNewPeerInd->peer_addr.bytes, + peerMacAddr, QDF_MAC_ADDR_SIZE); + pNewPeerInd->staId = staIndex; + pNewPeerInd->ucastSig = ucastIdx; + pNewPeerInd->bcastSig = bcastIdx; + pNewPeerInd->mesgLen = sizeof(tSmeIbssPeerInd) + beaconLen; + pNewPeerInd->mesgType = msgType; + pNewPeerInd->sessionId = sessionId; + + if (beacon != NULL) { + qdf_mem_copy((void *)((uint8_t *) pNewPeerInd + + sizeof(tSmeIbssPeerInd)), (void *)beacon, + beaconLen); + } + + mmhMsg.type = msgType; + mmhMsg.bodyptr = pNewPeerInd; + MTRACE(mac_trace(pMac, TRACE_CODE_TX_SME_MSG, sessionId, mmhMsg.type)); + lim_sys_process_mmh_msg_api(pMac, &mmhMsg, ePROT); + +} + +/** + * lim_process_csa_wbw_ie() - Process CSA Wide BW IE + * @mac_ctx: pointer to global adapter context + * @csa_params: pointer to CSA parameters + * @chnl_switch_info:pointer to channel switch parameters + * @session_entry: session pointer + * + * Return: None + */ +static void lim_process_csa_wbw_ie(tpAniSirGlobal mac_ctx, + struct csa_offload_params *csa_params, + tLimWiderBWChannelSwitchInfo *chnl_switch_info, + tpPESession session_entry) +{ + struct ch_params_s ch_params = {0}; + uint8_t ap_new_ch_width; + bool new_ch_width_dfn = false; + uint8_t center_freq_diff; + + ap_new_ch_width = csa_params->new_ch_width + 1; + if ((ap_new_ch_width == CH_WIDTH_80MHZ) && + csa_params->new_ch_freq_seg2) { + new_ch_width_dfn = true; + if (csa_params->new_ch_freq_seg2 > + csa_params->new_ch_freq_seg1) + center_freq_diff = csa_params->new_ch_freq_seg2 - + csa_params->new_ch_freq_seg1; + else + center_freq_diff = csa_params->new_ch_freq_seg1 - + csa_params->new_ch_freq_seg2; + if (center_freq_diff == CENTER_FREQ_DIFF_160MHz) + ap_new_ch_width = CH_WIDTH_160MHZ; + else if (center_freq_diff > CENTER_FREQ_DIFF_80P80MHz) + ap_new_ch_width = CH_WIDTH_80P80MHZ; + else + ap_new_ch_width = CH_WIDTH_80MHZ; + } + session_entry->gLimChannelSwitch.state = + eLIM_CHANNEL_SWITCH_PRIMARY_AND_SECONDARY; + if ((ap_new_ch_width == CH_WIDTH_160MHZ) && + !new_ch_width_dfn) { + ch_params.ch_width = CH_WIDTH_160MHZ; + cds_set_channel_params(csa_params->channel, 0, + &ch_params); + ap_new_ch_width = ch_params.ch_width; + csa_params->new_ch_freq_seg1 = ch_params.center_freq_seg0; + csa_params->new_ch_freq_seg2 = ch_params.center_freq_seg1; + } + chnl_switch_info->newChanWidth = ap_new_ch_width; + chnl_switch_info->newCenterChanFreq0 = csa_params->new_ch_freq_seg1; + chnl_switch_info->newCenterChanFreq1 = csa_params->new_ch_freq_seg2; + + if (session_entry->ch_width == ap_new_ch_width) + goto prnt_log; + + if (session_entry->ch_width == CH_WIDTH_80MHZ) { + chnl_switch_info->newChanWidth = CH_WIDTH_80MHZ; + chnl_switch_info->newCenterChanFreq1 = 0; + } else { + session_entry->ch_width = ap_new_ch_width; + chnl_switch_info->newChanWidth = ap_new_ch_width; + } +prnt_log: + lim_log(mac_ctx, LOG1, + FL("new channel: %d new_ch_width:%d seg0:%d seg1:%d"), + csa_params->channel, + chnl_switch_info->newChanWidth, + chnl_switch_info->newCenterChanFreq0, + chnl_switch_info->newCenterChanFreq1); +} +/** + * lim_handle_csa_offload_msg() - Handle CSA offload message + * @mac_ctx: pointer to global adapter context + * @msg: Message pointer. + * + * Return: None + */ +void lim_handle_csa_offload_msg(tpAniSirGlobal mac_ctx, tpSirMsgQ msg) +{ + tpPESession session_entry; + tSirMsgQ mmh_msg; + struct csa_offload_params *csa_params = + (struct csa_offload_params *) (msg->bodyptr); + tpSmeCsaOffloadInd csa_offload_ind; + tpDphHashNode sta_ds = NULL; + uint8_t session_id; + uint16_t aid = 0; + uint16_t chan_space = 0; + struct ch_params_s ch_params; + + tLimWiderBWChannelSwitchInfo *chnl_switch_info = NULL; + tLimChannelSwitchInfo *lim_ch_switch = NULL; + + lim_log(mac_ctx, LOG1, FL("handle csa offload msg")); + + if (!csa_params) { + lim_log(mac_ctx, LOGE, FL("limMsgQ body ptr is NULL")); + return; + } + + session_entry = + pe_find_session_by_bssid(mac_ctx, + csa_params->bssId, &session_id); + if (!session_entry) { + lim_log(mac_ctx, LOGE, + FL("Session does not exists for %pM"), + csa_params->bssId); + goto err; + } + + sta_ds = dph_lookup_hash_entry(mac_ctx, session_entry->bssId, &aid, + &session_entry->dph.dphHashTable); + + if (!sta_ds) { + lim_log(mac_ctx, LOGE, + FL("sta_ds does not exist")); + goto err; + } + + if (!LIM_IS_STA_ROLE(session_entry)) { + lim_log(mac_ctx, LOG1, FL("Invalid role to handle CSA")); + goto err; + } + + /* + * on receiving channel switch announcement from AP, delete all + * TDLS peers before leaving BSS and proceed for channel switch + */ + lim_delete_tdls_peers(mac_ctx, session_entry); + + lim_ch_switch = &session_entry->gLimChannelSwitch; + session_entry->gLimChannelSwitch.switchMode = + csa_params->switch_mode; + /* timer already started by firmware, switch immediately */ + session_entry->gLimChannelSwitch.switchCount = 0; + session_entry->gLimChannelSwitch.primaryChannel = + csa_params->channel; + session_entry->gLimChannelSwitch.state = + eLIM_CHANNEL_SWITCH_PRIMARY_ONLY; + session_entry->gLimChannelSwitch.ch_width = CH_WIDTH_20MHZ; + lim_ch_switch->sec_ch_offset = + session_entry->htSecondaryChannelOffset; + session_entry->gLimChannelSwitch.ch_center_freq_seg0 = 0; + session_entry->gLimChannelSwitch.ch_center_freq_seg1 = 0; + chnl_switch_info = + &session_entry->gLimWiderBWChannelSwitch; + + lim_log(mac_ctx, LOG1, + FL("vht:%d ht:%d flag:%x chan:%d"), + session_entry->vhtCapability, + session_entry->htSupportedChannelWidthSet, + csa_params->ies_present_flag, + csa_params->channel); + lim_log(mac_ctx, LOG1, + FL("seg1:%d seg2:%d width:%d country:%s class:%d"), + csa_params->new_ch_freq_seg1, + csa_params->new_ch_freq_seg2, + csa_params->new_ch_width, + mac_ctx->scan.countryCodeCurrent, + csa_params->new_op_class); + + if (session_entry->vhtCapability && + session_entry->htSupportedChannelWidthSet) { + if (csa_params->ies_present_flag & lim_wbw_ie_present) { + lim_process_csa_wbw_ie(mac_ctx, csa_params, + chnl_switch_info, session_entry); + lim_ch_switch->sec_ch_offset = + csa_params->sec_chan_offset; + } else if (csa_params->ies_present_flag + & lim_xcsa_ie_present) { + chan_space = + cds_reg_dmn_get_chanwidth_from_opclass( + mac_ctx->scan.countryCodeCurrent, + csa_params->channel, + csa_params->new_op_class); + session_entry->gLimChannelSwitch.state = + eLIM_CHANNEL_SWITCH_PRIMARY_AND_SECONDARY; + + if (chan_space == 80) { + chnl_switch_info->newChanWidth = + CH_WIDTH_80MHZ; + } else if (chan_space == 40) { + chnl_switch_info->newChanWidth = + CH_WIDTH_40MHZ; + } else { + chnl_switch_info->newChanWidth = + CH_WIDTH_20MHZ; + lim_ch_switch->state = + eLIM_CHANNEL_SWITCH_PRIMARY_ONLY; + } + + ch_params.ch_width = + chnl_switch_info->newChanWidth; + cds_set_channel_params(csa_params->channel, + 0, &ch_params); + chnl_switch_info->newCenterChanFreq0 = + ch_params.center_freq_seg0; + /* + * This is not applicable for 20/40/80 MHz. + * Only used when we support 80+80 MHz operation. + * In case of 80+80 MHz, this parameter indicates + * center channel frequency index of 80 MHz + * channel offrequency segment 1. + */ + chnl_switch_info->newCenterChanFreq1 = + ch_params.center_freq_seg1; + lim_ch_switch->sec_ch_offset = + ch_params.sec_ch_offset; + + } + session_entry->gLimChannelSwitch.ch_center_freq_seg0 = + chnl_switch_info->newCenterChanFreq0; + session_entry->gLimChannelSwitch.ch_center_freq_seg1 = + chnl_switch_info->newCenterChanFreq1; + session_entry->gLimChannelSwitch.ch_width = + chnl_switch_info->newChanWidth; + + } else if (session_entry->htSupportedChannelWidthSet) { + if (csa_params->ies_present_flag + & lim_xcsa_ie_present) { + chan_space = + cds_reg_dmn_get_chanwidth_from_opclass( + mac_ctx->scan.countryCodeCurrent, + csa_params->channel, + csa_params->new_op_class); + lim_ch_switch->state = + eLIM_CHANNEL_SWITCH_PRIMARY_AND_SECONDARY; + if (chan_space == 40) { + lim_ch_switch->ch_width = + CH_WIDTH_40MHZ; + chnl_switch_info->newChanWidth = + CH_WIDTH_40MHZ; + ch_params.ch_width = + chnl_switch_info->newChanWidth; + cds_set_channel_params( + csa_params->channel, + 0, &ch_params); + lim_ch_switch->ch_center_freq_seg0 = + ch_params.center_freq_seg0; + lim_ch_switch->sec_ch_offset = + ch_params.sec_ch_offset; + } else { + lim_ch_switch->ch_width = + CH_WIDTH_20MHZ; + chnl_switch_info->newChanWidth = + CH_WIDTH_40MHZ; + lim_ch_switch->state = + eLIM_CHANNEL_SWITCH_PRIMARY_ONLY; + lim_ch_switch->sec_ch_offset = + PHY_SINGLE_CHANNEL_CENTERED; + } + } else { + lim_ch_switch->ch_width = + CH_WIDTH_40MHZ; + lim_ch_switch->state = + eLIM_CHANNEL_SWITCH_PRIMARY_AND_SECONDARY; + ch_params.ch_width = CH_WIDTH_40MHZ; + cds_set_channel_params(csa_params->channel, + 0, &ch_params); + lim_ch_switch->ch_center_freq_seg0 = + ch_params.center_freq_seg0; + lim_ch_switch->sec_ch_offset = + ch_params.sec_ch_offset; + } + + } + lim_log(mac_ctx, LOG1, FL("new ch width = %d space:%d"), + session_entry->gLimChannelSwitch.ch_width, chan_space); + if ((session_entry->currentOperChannel == csa_params->channel) && + (session_entry->ch_width == + session_entry->gLimChannelSwitch.ch_width)) { + lim_log(mac_ctx, LOGE, FL( + "Ignore CSA, no change in ch and bw")); + goto err; + } + + lim_prepare_for11h_channel_switch(mac_ctx, session_entry); + csa_offload_ind = qdf_mem_malloc(sizeof(tSmeCsaOffloadInd)); + if (NULL == csa_offload_ind) { + lim_log(mac_ctx, LOGE, + FL("memalloc fail eWNI_SME_CSA_OFFLOAD_EVENT")); + goto err; + } + + csa_offload_ind->mesgType = eWNI_SME_CSA_OFFLOAD_EVENT; + csa_offload_ind->mesgLen = sizeof(tSmeCsaOffloadInd); + qdf_mem_copy(csa_offload_ind->bssid.bytes, session_entry->bssId, + QDF_MAC_ADDR_SIZE); + mmh_msg.type = eWNI_SME_CSA_OFFLOAD_EVENT; + mmh_msg.bodyptr = csa_offload_ind; + mmh_msg.bodyval = 0; + lim_log(mac_ctx, LOG1, + FL("Sending eWNI_SME_CSA_OFFLOAD_EVENT to SME.")); + MTRACE(mac_trace_msg_tx + (mac_ctx, session_entry->peSessionId, mmh_msg.type)); +#ifdef FEATURE_WLAN_DIAG_SUPPORT + lim_diag_event_report(mac_ctx, + WLAN_PE_DIAG_SWITCH_CHL_IND_EVENT, session_entry, + eSIR_SUCCESS, eSIR_SUCCESS); +#endif + lim_sys_process_mmh_msg_api(mac_ctx, &mmh_msg, ePROT); + +err: + qdf_mem_free(csa_params); +} + +/*-------------------------------------------------------------------------- + \brief pe_delete_session() - Handle the Delete BSS Response from HAL. + + \param pMac - pointer to global adapter context + \param sessionId - Message pointer. + + \sa + --------------------------------------------------------------------------*/ + +void lim_handle_delete_bss_rsp(tpAniSirGlobal pMac, tpSirMsgQ MsgQ) +{ + tpPESession psessionEntry; + tpDeleteBssParams pDelBss = (tpDeleteBssParams) (MsgQ->bodyptr); + + psessionEntry = + pe_find_session_by_session_id(pMac, pDelBss->sessionId); + if (psessionEntry == NULL) { + lim_log(pMac, LOGE, + FL("Session Does not exist for given sessionID %d"), + pDelBss->sessionId); + qdf_mem_free(MsgQ->bodyptr); + return; + } + /* + * During DEL BSS handling, the PE Session will be deleted, but it is + * better to clear this flag if the session is hanging around due + * to some error conditions so that the next DEL_BSS request does + * not take the HO_FAIL path + */ + psessionEntry->process_ho_fail = false; + if (LIM_IS_IBSS_ROLE(psessionEntry)) + lim_ibss_del_bss_rsp(pMac, MsgQ->bodyptr, psessionEntry); + else if (LIM_IS_UNKNOWN_ROLE(psessionEntry)) + lim_process_sme_del_bss_rsp(pMac, MsgQ->bodyval, psessionEntry); + else if (LIM_IS_NDI_ROLE(psessionEntry)) + lim_ndi_del_bss_rsp(pMac, MsgQ->bodyptr, psessionEntry); + else + lim_process_mlm_del_bss_rsp(pMac, MsgQ, psessionEntry); + +} + +/** ----------------------------------------------------------------- + \brief lim_send_sme_aggr_qos_rsp() - sends SME FT AGGR QOS RSP + \ This function sends a eWNI_SME_FT_AGGR_QOS_RSP to SME. + \ SME only looks at rc and tspec field. + \param pMac - global mac structure + \param rspReqd - is SmeAddTsRsp required + \param status - status code of eWNI_SME_FT_AGGR_QOS_RSP + \return tspec + \sa + ----------------------------------------------------------------- */ +void +lim_send_sme_aggr_qos_rsp(tpAniSirGlobal pMac, tpSirAggrQosRsp aggrQosRsp, + uint8_t smesessionId) +{ + tSirMsgQ mmhMsg; + + mmhMsg.type = eWNI_SME_FT_AGGR_QOS_RSP; + mmhMsg.bodyptr = aggrQosRsp; + mmhMsg.bodyval = 0; + MTRACE(mac_trace(pMac, TRACE_CODE_TX_SME_MSG, + smesessionId, mmhMsg.type)); + lim_sys_process_mmh_msg_api(pMac, &mmhMsg, ePROT); + + return; +} + +void lim_send_sme_max_assoc_exceeded_ntf(tpAniSirGlobal pMac, tSirMacAddr peerMacAddr, + uint8_t smesessionId) +{ + tSirMsgQ mmhMsg; + tSmeMaxAssocInd *pSmeMaxAssocInd; + + pSmeMaxAssocInd = qdf_mem_malloc(sizeof(tSmeMaxAssocInd)); + if (NULL == pSmeMaxAssocInd) { + PELOGE(lim_log(pMac, LOGE, FL("Failed to allocate memory"));) + return; + } + qdf_mem_copy((uint8_t *) pSmeMaxAssocInd->peer_mac.bytes, + (uint8_t *) peerMacAddr, QDF_MAC_ADDR_SIZE); + pSmeMaxAssocInd->mesgType = eWNI_SME_MAX_ASSOC_EXCEEDED; + pSmeMaxAssocInd->mesgLen = sizeof(tSmeMaxAssocInd); + pSmeMaxAssocInd->sessionId = smesessionId; + mmhMsg.type = pSmeMaxAssocInd->mesgType; + mmhMsg.bodyptr = pSmeMaxAssocInd; + PELOG1(lim_log(pMac, LOG1, FL("msgType %s peerMacAddr " MAC_ADDRESS_STR + " sme session id %d"), + "eWNI_SME_MAX_ASSOC_EXCEEDED", + MAC_ADDR_ARRAY(peerMacAddr)); + ) + MTRACE(mac_trace(pMac, TRACE_CODE_TX_SME_MSG, + smesessionId, mmhMsg.type)); + lim_sys_process_mmh_msg_api(pMac, &mmhMsg, ePROT); + + return; +} + +/** ----------------------------------------------------------------- + \brief lim_send_sme_dfs_event_notify() - sends + eWNI_SME_DFS_RADAR_FOUND + After receiving WMI_PHYERR_EVENTID indication frame from FW, this + function sends a eWNI_SME_DFS_RADAR_FOUND to SME to notify + that a RADAR is found on current operating channel and SAP- + has to move to a new channel. + \param pMac - global mac structure + \param msgType - message type received from lower layer + \param event - event data received from lower layer + \return none + \sa + ----------------------------------------------------------------- */ +void +lim_send_sme_dfs_event_notify(tpAniSirGlobal pMac, uint16_t msgType, void *event) +{ + tSirMsgQ mmhMsg; + mmhMsg.type = eWNI_SME_DFS_RADAR_FOUND; + mmhMsg.bodyptr = event; + mmhMsg.bodyval = 0; + lim_sys_process_mmh_msg_api(pMac, &mmhMsg, ePROT); + return; +} + +/*-------------------------------------------------------------------------- + \brief lim_send_dfs_chan_sw_ie_update() + This timer handler updates the channel switch IE in beacon template + + \param pMac - pointer to global adapter context + \return - channel to scan from valid session else zero. + \sa + --------------------------------------------------------------------------*/ +static void +lim_send_dfs_chan_sw_ie_update(tpAniSirGlobal pMac, tpPESession psessionEntry) +{ + + /* Update the beacon template and send to FW */ + if (sch_set_fixed_beacon_fields(pMac, psessionEntry) != eSIR_SUCCESS) { + PELOGE(lim_log(pMac, LOGE, FL("Unable to set CSA IE in beacon"));) + return; + } + + /* Send update beacon template message */ + lim_send_beacon_ind(pMac, psessionEntry); + PELOG1(lim_log(pMac, LOG1, + FL(" Updated CSA IE, IE COUNT = %d"), + psessionEntry->gLimChannelSwitch.switchCount); + ) + + return; +} + +/** ----------------------------------------------------------------- + \brief lim_send_sme_ap_channel_switch_resp() - sends + eWNI_SME_CHANNEL_CHANGE_RSP + After receiving WMA_SWITCH_CHANNEL_RSP indication this + function sends a eWNI_SME_CHANNEL_CHANGE_RSP to SME to notify + that the Channel change has been done to the specified target + channel in the Channel change request + \param pMac - global mac structure + \param psessionEntry - session info + \param pChnlParams - Channel switch params + --------------------------------------------------------------------*/ +void +lim_send_sme_ap_channel_switch_resp(tpAniSirGlobal pMac, + tpPESession psessionEntry, + tpSwitchChannelParams pChnlParams) +{ + tSirMsgQ mmhMsg; + tpSwitchChannelParams pSmeSwithChnlParams; + uint8_t channelId; + bool is_ch_dfs = false; + enum phy_ch_width ch_width; + uint8_t ch_center_freq_seg1; + + pSmeSwithChnlParams = (tSwitchChannelParams *) + qdf_mem_malloc(sizeof(tSwitchChannelParams)); + if (NULL == pSmeSwithChnlParams) { + lim_log(pMac, LOGP, + FL("AllocateMemory failed for pSmeSwithChnlParams\n")); + return; + } + + qdf_mem_copy(pSmeSwithChnlParams, pChnlParams, + sizeof(tSwitchChannelParams)); + + channelId = pSmeSwithChnlParams->channelNumber; + ch_width = pSmeSwithChnlParams->ch_width; + ch_center_freq_seg1 = pSmeSwithChnlParams->ch_center_freq_seg1; + + /* + * Pass the sme sessionID to SME instead + * PE session ID. + */ + pSmeSwithChnlParams->peSessionId = psessionEntry->smeSessionId; + + mmhMsg.type = eWNI_SME_CHANNEL_CHANGE_RSP; + mmhMsg.bodyptr = (void *)pSmeSwithChnlParams; + mmhMsg.bodyval = 0; + lim_sys_process_mmh_msg_api(pMac, &mmhMsg, ePROT); + + /* + * We should start beacon transmission only if the new + * channel after channel change is Non-DFS. For a DFS + * channel, PE will receive an explicit request from + * upper layers to start the beacon transmission . + */ + + if (ch_width == CH_WIDTH_160MHZ) { + is_ch_dfs = true; + } else if (ch_width == CH_WIDTH_80P80MHZ) { + if (cds_get_channel_state(channelId) == CHANNEL_STATE_DFS || + cds_get_channel_state(ch_center_freq_seg1 - + SIR_80MHZ_START_CENTER_CH_DIFF) == + CHANNEL_STATE_DFS) + is_ch_dfs = true; + } else { + if (cds_get_channel_state(channelId) == CHANNEL_STATE_DFS) + is_ch_dfs = true; + } + + if (!is_ch_dfs) { + if (channelId == psessionEntry->currentOperChannel) { + lim_apply_configuration(pMac, psessionEntry); + lim_send_beacon_ind(pMac, psessionEntry); + } else { + PELOG1(lim_log(pMac, LOG1, + FL + ("Failed to Transmit Beacons on channel = %d" + "after AP channel change response"), + psessionEntry->bcnLen); + ) + } + } + return; +} + +/** ----------------------------------------------------------------- + \brief lim_process_beacon_tx_success_ind() - This function is used + explicitely to handle successful beacon transmission indication + from the FW. This is a generic event generated by the FW afer the + first beacon is sent out after the beacon template update by the + host + \param pMac - global mac structure + \param psessionEntry - session info + \return none + \sa + ----------------------------------------------------------------- */ +void +lim_process_beacon_tx_success_ind(tpAniSirGlobal pMac, uint16_t msgType, void *event) +{ + /* Currently, this event is used only for DFS channel switch announcement + * IE update in the template. If required to be used for other IE updates + * add appropriate code by introducing a state variable + */ + tpPESession psessionEntry; + tSirMsgQ mmhMsg; + tSirSmeCSAIeTxCompleteRsp *pChanSwTxResponse; + struct sir_beacon_tx_complete_rsp *beacon_tx_comp_rsp_ptr; + uint8_t length = sizeof(tSirSmeCSAIeTxCompleteRsp); + tpSirFirstBeaconTxCompleteInd pBcnTxInd = + (tSirFirstBeaconTxCompleteInd *) event; + + psessionEntry = pe_find_session_by_bss_idx(pMac, pBcnTxInd->bssIdx); + if (psessionEntry == NULL) { + lim_log(pMac, LOGE, + FL("Session Does not exist for given sessionID")); + return; + } + + lim_log(pMac, LOG1, FL("role:%d swIe:%d opIe:%d"), + GET_LIM_SYSTEM_ROLE(psessionEntry), + psessionEntry->dfsIncludeChanSwIe, + psessionEntry->gLimOperatingMode.present); + + if (LIM_IS_AP_ROLE(psessionEntry) && + true == psessionEntry->dfsIncludeChanSwIe) { + /* Send only 5 beacons with CSA IE Set in when a radar is detected */ + if (psessionEntry->gLimChannelSwitch.switchCount > 0) { + /* + * Send the next beacon with updated CSA IE count + */ + lim_send_dfs_chan_sw_ie_update(pMac, psessionEntry); + /* Decrement the IE count */ + psessionEntry->gLimChannelSwitch.switchCount--; + } else { + /* Done with CSA IE update, send response back to SME */ + psessionEntry->gLimChannelSwitch.switchCount = 0; + if (pMac->sap.SapDfsInfo.disable_dfs_ch_switch == false) + psessionEntry->gLimChannelSwitch.switchMode = 0; + psessionEntry->dfsIncludeChanSwIe = false; + psessionEntry->dfsIncludeChanWrapperIe = false; + + pChanSwTxResponse = (tSirSmeCSAIeTxCompleteRsp *) + qdf_mem_malloc(length); + + if (NULL == pChanSwTxResponse) { + lim_log(pMac, LOGP, + FL + ("AllocateMemory failed for tSirSmeCSAIeTxCompleteRsp")); + return; + } + + pChanSwTxResponse->sessionId = + psessionEntry->smeSessionId; + pChanSwTxResponse->chanSwIeTxStatus = + QDF_STATUS_SUCCESS; + + mmhMsg.type = eWNI_SME_DFS_CSAIE_TX_COMPLETE_IND; + mmhMsg.bodyptr = pChanSwTxResponse; + mmhMsg.bodyval = 0; + lim_sys_process_mmh_msg_api(pMac, &mmhMsg, ePROT); + } + } + + if (LIM_IS_AP_ROLE(psessionEntry) && + psessionEntry->gLimOperatingMode.present) { + /* Done with nss update, send response back to SME */ + psessionEntry->gLimOperatingMode.present = 0; + beacon_tx_comp_rsp_ptr = (struct sir_beacon_tx_complete_rsp *) + qdf_mem_malloc(sizeof(*beacon_tx_comp_rsp_ptr)); + if (NULL == beacon_tx_comp_rsp_ptr) { + lim_log(pMac, LOGP, + FL + ("AllocateMemory failed for beacon_tx_comp_rsp_ptr")); + return; + } + beacon_tx_comp_rsp_ptr->session_id = + psessionEntry->smeSessionId; + beacon_tx_comp_rsp_ptr->tx_status = QDF_STATUS_SUCCESS; + mmhMsg.type = eWNI_SME_NSS_UPDATE_RSP; + mmhMsg.bodyptr = beacon_tx_comp_rsp_ptr; + mmhMsg.bodyval = 0; + lim_sys_process_mmh_msg_api(pMac, &mmhMsg, ePROT); + } + return; +} diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_send_sme_rsp_messages.h b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_send_sme_rsp_messages.h new file mode 100644 index 0000000000000000000000000000000000000000..55a58ff0ee039c4c4b3c7e2c24beea067de3d973 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_send_sme_rsp_messages.h @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * This file lim_send_sme_rsp_messages.h contains the definitions for + * sending SME response/notification messages to applications above + * MAC software. + * Author: Chandra Modumudi + * Date: 02/11/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + * + */ +#ifndef __LIM_SEND_SME_RSP_H +#define __LIM_SEND_SME_RSP_H + +#include "sir_common.h" +#include "sir_api.h" +#include "sir_mac_prot_def.h" + +/* Functions for sending responses to Host */ +void lim_send_sme_rsp(tpAniSirGlobal, uint16_t, tSirResultCodes, uint8_t, + uint16_t); +void lim_send_sme_roc_rsp(tpAniSirGlobal mac_ctx, uint16_t msg_type, + tSirResultCodes result_code, uint8_t sme_session_id, + uint32_t scan_id); +void lim_send_sme_start_bss_rsp(tpAniSirGlobal, uint16_t, tSirResultCodes, + tpPESession, uint8_t, uint16_t); +void lim_send_sme_scan_rsp(tpAniSirGlobal, tSirResultCodes, uint8_t, + uint16_t, uint32_t scan_id); +void lim_post_sme_scan_rsp_message(tpAniSirGlobal, tSirResultCodes, + uint8_t, uint16_t, uint32_t scan_id); + +void lim_send_sme_join_reassoc_rsp(tpAniSirGlobal, uint16_t, tSirResultCodes, + uint16_t, tpPESession, uint8_t, uint16_t); +void lim_send_sme_disassoc_ntf(tpAniSirGlobal, tSirMacAddr, tSirResultCodes, + uint16_t, uint16_t, uint8_t, uint16_t, tpPESession); +void lim_send_sme_deauth_ntf(tpAniSirGlobal, tSirMacAddr, tSirResultCodes, uint16_t, + uint16_t, uint8_t, uint16_t); +void lim_send_sme_disassoc_ind(tpAniSirGlobal, tpDphHashNode, tpPESession); +void lim_send_sme_deauth_ind(tpAniSirGlobal, tpDphHashNode, + tpPESession psessionEntry); +void lim_send_sme_wm_status_change_ntf(tpAniSirGlobal, tSirSmeStatusChangeCode, + uint32_t *, uint16_t, uint8_t); +void lim_send_sme_set_context_rsp(tpAniSirGlobal, struct qdf_mac_addr, uint16_t, + tSirResultCodes, tpPESession, uint8_t, uint16_t); +void lim_send_sme_neighbor_bss_ind(tpAniSirGlobal, tLimScanResultNode *); +void lim_handle_delete_bss_rsp(tpAniSirGlobal pMac, tpSirMsgQ MsgQ); +void lim_handle_csa_offload_msg(tpAniSirGlobal mac_ctx, tpSirMsgQ msg); + +void +lim_send_sme_aggr_qos_rsp(tpAniSirGlobal pMac, tpSirAggrQosRsp aggrQosRsp, + uint8_t smesessionId); + +void lim_send_sme_addts_rsp(tpAniSirGlobal pMac, uint8_t rspReqd, uint32_t status, + tpPESession psessionEntry, tSirMacTspecIE tspec, + uint8_t smesessionId, uint16_t smetransactionId); +void lim_send_sme_delts_rsp(tpAniSirGlobal pMac, tpSirDeltsReq delts, + uint32_t status, tpPESession psessionEntry, + uint8_t smessionId, uint16_t smetransactionId); +void lim_send_sme_delts_ind(tpAniSirGlobal pMac, tpSirDeltsReqInfo delts, + uint16_t aid, tpPESession); +void lim_send_sme_stats_rsp(tpAniSirGlobal pMac, uint16_t msgtype, void *stats); + +void lim_send_sme_pe_statistics_rsp(tpAniSirGlobal pMac, uint16_t msgtype, + void *stats); +#ifdef FEATURE_WLAN_ESE +void lim_send_sme_pe_ese_tsm_rsp(tpAniSirGlobal pMac, tAniGetTsmStatsRsp *pStats); +#endif + +void lim_send_sme_ibss_peer_ind(tpAniSirGlobal pMac, tSirMacAddr peerMacAddr, + uint16_t staIndex, uint8_t ucastIdx, + uint8_t bcastIdx, uint8_t *beacon, + uint16_t beaconLen, uint16_t msgType, + uint8_t sessionId); +void lim_send_sme_max_assoc_exceeded_ntf(tpAniSirGlobal pMac, tSirMacAddr peerMacAddr, + uint8_t smesessionId); +#ifdef FEATURE_WLAN_TDLS +void lim_send_sme_tdls_link_establish_req_rsp(tpAniSirGlobal pMac, uint8_t sessionId, + struct qdf_mac_addr *peermac, + tDphHashNode *pStaDs, uint8_t status); +void lim_send_sme_tdls_event_notify(tpAniSirGlobal pMac, uint16_t msgType, + void *events); +#endif + +void lim_send_sme_dfs_event_notify(tpAniSirGlobal pMac, uint16_t msgType, + void *event); +void lim_send_sme_ap_channel_switch_resp(tpAniSirGlobal pMac, + tpPESession psessionEntry, + tpSwitchChannelParams pChnlParams); +void +lim_process_beacon_tx_success_ind(tpAniSirGlobal pMac, uint16_t msgType, + void *event); + +typedef enum { + lim_csa_ie_present = 0x00000001, + lim_xcsa_ie_present = 0x00000002, + lim_wbw_ie_present = 0x00000004, + lim_cswarp_ie_present = 0x00000008, +} lim_csa_event_ies_present_flag; + +#endif /* __LIM_SEND_SME_RSP_H */ diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_ser_des_utils.c b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_ser_des_utils.c new file mode 100644 index 0000000000000000000000000000000000000000..55da544f7a6415b37b3771aea50f2f86a46babb5 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_ser_des_utils.c @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2011-2015,2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * + * This file lim_ser_des_utils.cc contains the serializer/deserializer + * utility functions LIM uses while communicating with upper layer + * software entities + * Author: Chandra Modumudi + * Date: 10/20/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + */ + +#include "ani_system_defs.h" +#include "utils_api.h" +#include "lim_types.h" +#include "lim_utils.h" +#include "lim_ser_des_utils.h" + + +/**--------------------------------------------------------------- + \fn lim_get_session_info + \brief This function returns the sessionId and transactionId + \ of a message. This assumes that the message structure + \ is of format: + \ uint16_t messageType + \ uint16_t messageLength + \ uint8_t sessionId + \ uint16_t transactionId + \param pMac - pMac global structure + \param *pBuf - pointer to the message buffer + \param sessionId - returned session id value + \param transactionId - returned transaction ID value + \return None + ------------------------------------------------------------------*/ +void +lim_get_session_info(tpAniSirGlobal pMac, uint8_t *pBuf, uint8_t *sessionId, + uint16_t *transactionId) +{ + if (!pBuf) { + lim_log(pMac, LOGE, FL("NULL ptr received. ")); + return; + } + + pBuf += sizeof(uint16_t); /* skip message type */ + pBuf += sizeof(uint16_t); /* skip message length */ + + *sessionId = *pBuf; /* get sessionId */ + pBuf++; + *transactionId = lim_get_u16(pBuf); /* get transactionId */ + + return; +} + +/** + * lim_send_disassoc_frm_req_ser_des - called on receiving SME_DISASSOC_REQ + * @mac_ctx: pointer to mac context + * @disassoc_frm_req: pointer to structure sme_send_disassoc_frm_req + * + * function send's disassoc frame request on receiving SME_DISASSOC_REQ + * + * return: eSIR_SUCCESS:Success Error value: Failure + */ +tSirRetStatus lim_send_disassoc_frm_req_ser_des(tpAniSirGlobal mac_ctx, + struct sme_send_disassoc_frm_req *disassoc_frm_req, + uint8_t *buf) +{ + A_INT16 len = 0; + + if (!disassoc_frm_req || !buf) + return eSIR_FAILURE; + + disassoc_frm_req->msg_type = lim_get_u16(buf); + buf += sizeof(A_UINT16); + + len = disassoc_frm_req->length = lim_get_u16(buf); + buf += sizeof(A_UINT16); + + PELOG1(lim_log(mac_ctx, LOG1, + FL("SME_DISASSOC_REQ length %d bytes is:"), len);) + PELOG1(sirDumpBuf(mac_ctx, SIR_LIM_MODULE_ID, LOG1, buf, len);) + + if (len < (A_INT16) sizeof(A_UINT32)) + return eSIR_FAILURE; + + /* skip message header */ + len -= sizeof(A_UINT32); + if (len < 0) + return eSIR_FAILURE; + + /* Extract sessionID */ + disassoc_frm_req->session_id = *buf; + buf += sizeof(A_UINT8); + len -= sizeof(A_UINT8); + if (len < 0) + return eSIR_FAILURE; + + /* Extract transactionid */ + disassoc_frm_req->trans_id = lim_get_u16(buf); + buf += sizeof(A_UINT16); + len -= sizeof(A_UINT16); + + if (len < 0) + return eSIR_FAILURE; + + /* Extract peerMacAddr */ + qdf_mem_copy(disassoc_frm_req->peer_mac, buf, sizeof(tSirMacAddr)); + buf += sizeof(tSirMacAddr); + len -= sizeof(tSirMacAddr); + + if (len < 0) + return eSIR_FAILURE; + + /* Extract reasonCode */ + disassoc_frm_req->reason = lim_get_u16(buf); + buf += sizeof(A_UINT16); + len -= sizeof(A_UINT16); + + if (len < 0) + return eSIR_FAILURE; + + disassoc_frm_req->wait_for_ack = *buf; + buf += sizeof(A_UINT8); + len -= sizeof(A_UINT8); + + return eSIR_SUCCESS; +} diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_ser_des_utils.h b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_ser_des_utils.h new file mode 100644 index 0000000000000000000000000000000000000000..82b9c48cf7f525d11f68545210b87761af573cc6 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_ser_des_utils.h @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2011-2015,2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * + * This file lim_ser_des_utils.h contains the utility definitions + * LIM uses while processing messages from upper layer software + * modules + * Author: Chandra Modumudi + * Date: 10/20/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + */ +#ifndef __LIM_SERDES_UTILS_H +#define __LIM_SERDES_UTILS_H + +#include "sir_api.h" +#include "ani_system_defs.h" +#include "sir_mac_prot_def.h" +#include "utils_api.h" +#include "lim_types.h" +#include "lim_prop_exts_utils.h" + +void lim_get_session_info(tpAniSirGlobal pMac, uint8_t *, + uint8_t *, uint16_t *); + +/* Byte String <--> uint16_t/uint32_t copy functions */ +static inline void lim_copy_u16(uint8_t *ptr, uint16_t u16Val) +{ +#if ((defined(ANI_OS_TYPE_QNX) && defined(ANI_LITTLE_BYTE_ENDIAN)) || \ + (defined(ANI_OS_TYPE_ANDROID) && defined(ANI_LITTLE_BYTE_ENDIAN))) + *ptr++ = (uint8_t) (u16Val & 0xff); + *ptr = (uint8_t) ((u16Val >> 8) & 0xff); +#else +#error "Unknown combination of OS Type and endianess" +#endif +} + +static inline uint16_t lim_get_u16(uint8_t *ptr) +{ +#if ((defined(ANI_OS_TYPE_QNX) && defined(ANI_LITTLE_BYTE_ENDIAN)) || \ + (defined(ANI_OS_TYPE_ANDROID) && defined(ANI_LITTLE_BYTE_ENDIAN))) + return ((uint16_t) (*(ptr + 1) << 8)) | ((uint16_t) (*ptr)); +#else +#error "Unknown combination of OS Type and endianess" +#endif +} + +static inline void lim_copy_u32(uint8_t *ptr, uint32_t u32Val) +{ +#if ((defined(ANI_OS_TYPE_QNX) && defined(ANI_LITTLE_BYTE_ENDIAN)) || \ + (defined(ANI_OS_TYPE_ANDROID) && defined(ANI_LITTLE_BYTE_ENDIAN))) + *ptr++ = (uint8_t) (u32Val & 0xff); + *ptr++ = (uint8_t) ((u32Val >> 8) & 0xff); + *ptr++ = (uint8_t) ((u32Val >> 16) & 0xff); + *ptr = (uint8_t) ((u32Val >> 24) & 0xff); +#else +#error "Unknown combination of OS Type and endianess" +#endif +} + +static inline uint32_t lim_get_u32(uint8_t *ptr) +{ +#if ((defined(ANI_OS_TYPE_QNX) && defined(ANI_LITTLE_BYTE_ENDIAN)) || \ + (defined(ANI_OS_TYPE_ANDROID) && defined(ANI_LITTLE_BYTE_ENDIAN))) + return ((*(ptr + 3) << 24) | + (*(ptr + 2) << 16) | (*(ptr + 1) << 8) | (*(ptr))); +#else +#error "Unknown combination of OS Type and endianess" +#endif +} + +tSirRetStatus lim_send_disassoc_frm_req_ser_des(tpAniSirGlobal mac_ctx, + struct sme_send_disassoc_frm_req *disassoc_frm_req, + uint8_t *buf); + +#endif /* __LIM_SERDES_UTILS_H */ diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_session.c b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_session.c new file mode 100644 index 0000000000000000000000000000000000000000..116bd84e183ca9051038f3322eb151f8842498ba --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_session.c @@ -0,0 +1,844 @@ +/* + * Copyright (c) 2011-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/**========================================================================= + + \file lim_session.c + + \brief implementation for lim Session related APIs + + \author Sunit Bhatia + + ========================================================================*/ + +/*-------------------------------------------------------------------------- + Include Files + ------------------------------------------------------------------------*/ +#include "ani_global.h" +#include "lim_debug.h" +#include "lim_ft_defs.h" +#include "lim_ft.h" +#include "lim_session.h" +#include "lim_utils.h" + +#include "sch_api.h" +#include "lim_send_messages.h" + +/*-------------------------------------------------------------------------- + + \brief pe_init_beacon_params() - Initialize the beaconParams structure + + \param tpPESession - pointer to the session context or NULL if session can not be created. + \return void + \sa + + --------------------------------------------------------------------------*/ + +static void pe_init_beacon_params(tpAniSirGlobal pMac, + tpPESession psessionEntry) +{ + psessionEntry->beaconParams.beaconInterval = 0; + psessionEntry->beaconParams.fShortPreamble = 0; + psessionEntry->beaconParams.llaCoexist = 0; + psessionEntry->beaconParams.llbCoexist = 0; + psessionEntry->beaconParams.llgCoexist = 0; + psessionEntry->beaconParams.ht20Coexist = 0; + psessionEntry->beaconParams.llnNonGFCoexist = 0; + psessionEntry->beaconParams.fRIFSMode = 0; + psessionEntry->beaconParams.fLsigTXOPProtectionFullSupport = 0; + psessionEntry->beaconParams.gHTObssMode = 0; + + /* Number of legacy STAs associated */ + qdf_mem_set((void *)&psessionEntry->gLim11bParams, + sizeof(tLimProtStaParams), 0); + qdf_mem_set((void *)&psessionEntry->gLim11aParams, + sizeof(tLimProtStaParams), 0); + qdf_mem_set((void *)&psessionEntry->gLim11gParams, + sizeof(tLimProtStaParams), 0); + qdf_mem_set((void *)&psessionEntry->gLimNonGfParams, + sizeof(tLimProtStaParams), 0); + qdf_mem_set((void *)&psessionEntry->gLimHt20Params, + sizeof(tLimProtStaParams), 0); + qdf_mem_set((void *)&psessionEntry->gLimLsigTxopParams, + sizeof(tLimProtStaParams), 0); + qdf_mem_set((void *)&psessionEntry->gLimOlbcParams, + sizeof(tLimProtStaParams), 0); +} + +/* + * pe_reset_protection_callback() - resets protection structs so that when an AP + * causing use of protection goes away, corresponding protection bit can be + * reset + * @ptr: pointer to pSessionEntry + * + * This function resets protection structs so that when an AP causing use of + * protection goes away, corresponding protection bit can be reset. This allowes + * protection bits to be reset once legacy overlapping APs are gone. + * + * Return: void + */ +static void pe_reset_protection_callback(void *ptr) +{ + tpPESession pe_session_entry = (tpPESession)ptr; + tpAniSirGlobal mac_ctx = (tpAniSirGlobal)pe_session_entry->mac_ctx; + int8_t i = 0; + tUpdateBeaconParams beacon_params; + uint16_t current_protection_state = 0; + tpDphHashNode station_hash_node = NULL; + tSirMacHTOperatingMode old_op_mode; + bool bcn_prms_changed = false; + + if (pe_session_entry->valid == false) { + QDF_TRACE(QDF_MODULE_ID_PE, + QDF_TRACE_LEVEL_ERROR, + FL("session already deleted. exiting timer callback")); + return; + } + + /* + * During CAC period, if the callback is triggered, the beacon + * template may get updated. Subsequently if the vdev is not up, the + * vdev would be made up -- which should not happen during the CAC + * period. To avoid this, ignore the protection callback if the session + * is not yet up. + */ + if (!wma_is_vdev_up(pe_session_entry->smeSessionId)) { + QDF_TRACE(QDF_MODULE_ID_PE, + QDF_TRACE_LEVEL_ERROR, + FL("session is not up yet. exiting timer callback")); + return; + } + + current_protection_state |= + pe_session_entry->gLimOverlap11gParams.protectionEnabled | + pe_session_entry->gLimOverlap11aParams.protectionEnabled << 1 | + pe_session_entry->gLimOverlapHt20Params.protectionEnabled << 2 | + pe_session_entry->gLimOverlapNonGfParams.protectionEnabled << 3 | + pe_session_entry->gLimOlbcParams.protectionEnabled << 4; + + QDF_TRACE(QDF_MODULE_ID_PE, + QDF_TRACE_LEVEL_INFO, + FL("old protection state: 0x%04X, new protection state: 0x%04X"), + pe_session_entry->old_protection_state, + current_protection_state); + + qdf_mem_zero(&pe_session_entry->gLimOverlap11gParams, + sizeof(pe_session_entry->gLimOverlap11gParams)); + qdf_mem_zero(&pe_session_entry->gLimOverlap11aParams, + sizeof(pe_session_entry->gLimOverlap11aParams)); + qdf_mem_zero(&pe_session_entry->gLimOverlapHt20Params, + sizeof(pe_session_entry->gLimOverlapHt20Params)); + qdf_mem_zero(&pe_session_entry->gLimOverlapNonGfParams, + sizeof(pe_session_entry->gLimOverlapNonGfParams)); + + qdf_mem_zero(&pe_session_entry->gLimOlbcParams, + sizeof(pe_session_entry->gLimOlbcParams)); + + /* + * Do not reset fShortPreamble and beaconInterval, as they + * are not updated. + */ + pe_session_entry->beaconParams.llaCoexist = 0; + pe_session_entry->beaconParams.llbCoexist = 0; + pe_session_entry->beaconParams.llgCoexist = 0; + pe_session_entry->beaconParams.ht20Coexist = 0; + pe_session_entry->beaconParams.llnNonGFCoexist = 0; + pe_session_entry->beaconParams.fRIFSMode = 0; + pe_session_entry->beaconParams.fLsigTXOPProtectionFullSupport = 0; + pe_session_entry->beaconParams.gHTObssMode = 0; + + qdf_mem_zero(&mac_ctx->lim.gLimOverlap11gParams, + sizeof(mac_ctx->lim.gLimOverlap11gParams)); + qdf_mem_zero(&mac_ctx->lim.gLimOverlap11aParams, + sizeof(mac_ctx->lim.gLimOverlap11aParams)); + qdf_mem_zero(&mac_ctx->lim.gLimOverlapHt20Params, + sizeof(mac_ctx->lim.gLimOverlapHt20Params)); + qdf_mem_zero(&mac_ctx->lim.gLimOverlapNonGfParams, + sizeof(mac_ctx->lim.gLimOverlapNonGfParams)); + + old_op_mode = pe_session_entry->htOperMode; + pe_session_entry->htOperMode = eSIR_HT_OP_MODE_PURE; + mac_ctx->lim.gHTOperMode = eSIR_HT_OP_MODE_PURE; + + qdf_mem_zero(&beacon_params, sizeof(tUpdateBeaconParams)); + /* index 0, is self node, peers start from 1 */ + for (i = 1 ; i <= mac_ctx->lim.gLimAssocStaLimit ; i++) { + station_hash_node = dph_get_hash_entry(mac_ctx, i, + &pe_session_entry->dph.dphHashTable); + if (NULL == station_hash_node) + continue; + lim_decide_ap_protection(mac_ctx, station_hash_node->staAddr, + &beacon_params, pe_session_entry); + } + + if (pe_session_entry->htOperMode != old_op_mode) + bcn_prms_changed = true; + + if ((current_protection_state != + pe_session_entry->old_protection_state) && + (false == mac_ctx->sap.SapDfsInfo.is_dfs_cac_timer_running)) { + QDF_TRACE(QDF_MODULE_ID_PE, + QDF_TRACE_LEVEL_ERROR, + FL("protection changed, update beacon template")); + /* update beacon fix params and send update to FW */ + qdf_mem_zero(&beacon_params, sizeof(tUpdateBeaconParams)); + beacon_params.bssIdx = pe_session_entry->bssIdx; + beacon_params.fShortPreamble = + pe_session_entry->beaconParams.fShortPreamble; + beacon_params.beaconInterval = + pe_session_entry->beaconParams.beaconInterval; + beacon_params.llaCoexist = + pe_session_entry->beaconParams.llaCoexist; + beacon_params.llbCoexist = + pe_session_entry->beaconParams.llbCoexist; + beacon_params.llgCoexist = + pe_session_entry->beaconParams.llgCoexist; + beacon_params.ht20MhzCoexist = + pe_session_entry->beaconParams.ht20Coexist; + beacon_params.llnNonGFCoexist = + pe_session_entry->beaconParams.llnNonGFCoexist; + beacon_params.fLsigTXOPProtectionFullSupport = + pe_session_entry->beaconParams. + fLsigTXOPProtectionFullSupport; + beacon_params.fRIFSMode = + pe_session_entry->beaconParams.fRIFSMode; + beacon_params.smeSessionId = + pe_session_entry->smeSessionId; + beacon_params.paramChangeBitmap |= PARAM_llBCOEXIST_CHANGED; + bcn_prms_changed = true; + } + + if (bcn_prms_changed) { + sch_set_fixed_beacon_fields(mac_ctx, pe_session_entry); + lim_send_beacon_params(mac_ctx, &beacon_params, pe_session_entry); + } + + pe_session_entry->old_protection_state = current_protection_state; + if (qdf_mc_timer_start(&pe_session_entry-> + protection_fields_reset_timer, + SCH_PROTECTION_RESET_TIME) + != QDF_STATUS_SUCCESS) { + QDF_TRACE(QDF_MODULE_ID_PE, + QDF_TRACE_LEVEL_ERROR, + FL("cannot create or start protectionFieldsResetTimer")); + } +} + +/** + * lim_get_peer_idxpool_size: get number of peer idx pool size + * @num_sta: Max number of STA + * @bss_type: BSS type + * + * The peer index start from 1 and thus index 0 is not used, so + * add 1 to the max sta. For STA if TDLS is enabled add 2 as + * index 1 is reserved for peer BSS. + * + * Return: number of peer idx pool size + */ +#ifdef FEATURE_WLAN_TDLS +static inline uint8_t +lim_get_peer_idxpool_size(uint16_t num_sta, tSirBssType bss_type) +{ + /* + * In station role, index 1 is reserved for peer + * corresponding to AP. For TDLS the index should + * start from 2 + */ + if (bss_type == eSIR_INFRASTRUCTURE_MODE) + return num_sta + 2; + else + return num_sta + 1; + +} +#else +static inline uint8_t +lim_get_peer_idxpool_size(uint16_t num_sta, tSirBssType bss_type) +{ + return num_sta + 1; +} +#endif + +/** + * pe_create_session() creates a new PE session given the BSSID + * @param pMac: pointer to global adapter context + * @param bssid: BSSID of the new session + * @param sessionId: session ID is returned here, if session is created. + * @param bssType: station or a + * + * This function returns the session context and the session ID if the session + * corresponding to the passed BSSID is found in the PE session table. + * + * Return: tpPESession: pointer to the session context or NULL if session + * can not be created. + */ + +tpPESession +pe_create_session(tpAniSirGlobal pMac, uint8_t *bssid, uint8_t *sessionId, + uint16_t numSta, tSirBssType bssType) +{ + QDF_STATUS status; + uint8_t i; + tpPESession session_ptr; + for (i = 0; i < pMac->lim.maxBssId; i++) { + /* Find first free room in session table */ + if (pMac->lim.gpSession[i].valid == true) + continue; + break; + } + + if (i == pMac->lim.maxBssId) { + lim_log(pMac, LOGE, + FL("Session can't be created. Reached max sessions")); + return NULL; + } + + session_ptr = &pMac->lim.gpSession[i]; + qdf_mem_set((void *)session_ptr, sizeof(tPESession), 0); + /* Allocate space for Station Table for this session. */ + session_ptr->dph.dphHashTable.pHashTable = + qdf_mem_malloc(sizeof(tpDphHashNode) * (numSta + 1)); + if (NULL == session_ptr->dph.dphHashTable.pHashTable) { + lim_log(pMac, LOGE, FL("memory allocate failed!")); + return NULL; + } + + session_ptr->dph.dphHashTable.pDphNodeArray = + qdf_mem_malloc(sizeof(tDphHashNode) * (numSta + 1)); + if (NULL == session_ptr->dph.dphHashTable.pDphNodeArray) { + lim_log(pMac, LOGE, FL("memory allocate failed!")); + qdf_mem_free(session_ptr->dph.dphHashTable.pHashTable); + session_ptr->dph.dphHashTable. + pHashTable = NULL; + return NULL; + } + + + session_ptr->dph.dphHashTable.size = numSta + 1; + dph_hash_table_class_init(pMac, &session_ptr->dph.dphHashTable); + session_ptr->gpLimPeerIdxpool = qdf_mem_malloc( + sizeof(*(session_ptr->gpLimPeerIdxpool)) * + lim_get_peer_idxpool_size(numSta, bssType)); + if (NULL == session_ptr->gpLimPeerIdxpool) { + lim_log(pMac, LOGE, FL("memory allocate failed!")); + qdf_mem_free(session_ptr->dph.dphHashTable.pHashTable); + qdf_mem_free(session_ptr->dph.dphHashTable.pDphNodeArray); + session_ptr->dph.dphHashTable.pHashTable = NULL; + session_ptr->dph.dphHashTable.pDphNodeArray = NULL; + return NULL; + } + session_ptr->freePeerIdxHead = 0; + session_ptr->freePeerIdxTail = 0; + session_ptr->gLimNumOfCurrentSTAs = 0; + /* Copy the BSSID to the session table */ + sir_copy_mac_addr(session_ptr->bssId, bssid); + if (bssType == eSIR_MONITOR_MODE) + sir_copy_mac_addr(pMac->lim.gpSession[i].selfMacAddr, bssid); + session_ptr->valid = true; + /* Intialize the SME and MLM states to IDLE */ + session_ptr->limMlmState = eLIM_MLM_IDLE_STATE; + session_ptr->limSmeState = eLIM_SME_IDLE_STATE; + session_ptr->limCurrentAuthType = eSIR_OPEN_SYSTEM; + pe_init_beacon_params(pMac, &pMac->lim.gpSession[i]); + session_ptr->is11Rconnection = false; +#ifdef FEATURE_WLAN_ESE + session_ptr->isESEconnection = false; +#endif + session_ptr->isFastTransitionEnabled = false; + session_ptr->isFastRoamIniFeatureEnabled = false; + *sessionId = i; + session_ptr->gLimPhyMode = WNI_CFG_PHY_MODE_11G; + /* Initialize CB mode variables when session is created */ + session_ptr->htSupportedChannelWidthSet = 0; + session_ptr->htRecommendedTxWidthSet = 0; + session_ptr->htSecondaryChannelOffset = 0; +#ifdef FEATURE_WLAN_TDLS + qdf_mem_set(session_ptr->peerAIDBitmap, + sizeof(session_ptr->peerAIDBitmap), 0); + session_ptr->tdls_prohibited = false; + session_ptr->tdls_chan_swit_prohibited = false; +#endif + session_ptr->fWaitForProbeRsp = 0; + session_ptr->fIgnoreCapsChange = 0; + + QDF_TRACE(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_DEBUG, + FL("Create a new PE session(%d), BSSID: "MAC_ADDRESS_STR" Max No. of STA %d"), + *sessionId, MAC_ADDR_ARRAY(bssid), numSta); + + if (eSIR_INFRA_AP_MODE == bssType || eSIR_IBSS_MODE == bssType) { + session_ptr->pSchProbeRspTemplate = + qdf_mem_malloc(SCH_MAX_PROBE_RESP_SIZE); + session_ptr->pSchBeaconFrameBegin = + qdf_mem_malloc(SCH_MAX_BEACON_SIZE); + session_ptr->pSchBeaconFrameEnd = + qdf_mem_malloc(SCH_MAX_BEACON_SIZE); + if ((NULL == session_ptr->pSchProbeRspTemplate) + || (NULL == session_ptr->pSchBeaconFrameBegin) + || (NULL == session_ptr->pSchBeaconFrameEnd)) { + lim_log(pMac, LOGE, FL("memory allocate failed!")); + qdf_mem_free(session_ptr->dph.dphHashTable.pHashTable); + qdf_mem_free(session_ptr->dph.dphHashTable.pDphNodeArray); + qdf_mem_free(session_ptr->gpLimPeerIdxpool); + qdf_mem_free(session_ptr->pSchProbeRspTemplate); + qdf_mem_free(session_ptr->pSchBeaconFrameBegin); + qdf_mem_free(session_ptr->pSchBeaconFrameEnd); + + session_ptr->dph.dphHashTable.pHashTable = NULL; + session_ptr->dph.dphHashTable.pDphNodeArray = NULL; + session_ptr->gpLimPeerIdxpool = NULL; + session_ptr->pSchProbeRspTemplate = NULL; + session_ptr->pSchBeaconFrameBegin = NULL; + session_ptr->pSchBeaconFrameEnd = NULL; + return NULL; + } + } + if (eSIR_INFRASTRUCTURE_MODE == bssType) + lim_ft_open(pMac, &pMac->lim.gpSession[i]); + + if (eSIR_MONITOR_MODE == bssType) + lim_ft_open(pMac, &pMac->lim.gpSession[i]); + + if (eSIR_INFRA_AP_MODE == bssType) { + session_ptr->old_protection_state = 0; + session_ptr->mac_ctx = (void *)pMac; + status = qdf_mc_timer_init( + &session_ptr->protection_fields_reset_timer, + QDF_TIMER_TYPE_SW, pe_reset_protection_callback, + (void *)&pMac->lim.gpSession[i]); + if (status == QDF_STATUS_SUCCESS) { + status = qdf_mc_timer_start( + &session_ptr->protection_fields_reset_timer, + SCH_PROTECTION_RESET_TIME); + } + if (status != QDF_STATUS_SUCCESS) + QDF_TRACE(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_ERROR, + FL("cannot create or start protectionFieldsResetTimer")); + } + + session_ptr->pmfComebackTimerInfo.pMac = pMac; + session_ptr->pmfComebackTimerInfo.sessionID = *sessionId; + status = qdf_mc_timer_init(&session_ptr->pmfComebackTimer, + QDF_TIMER_TYPE_SW, lim_pmf_comeback_timer_callback, + (void *)&session_ptr->pmfComebackTimerInfo); + if (!QDF_IS_STATUS_SUCCESS(status)) + lim_log(pMac, LOGE, FL("cannot init pmf comeback timer.")); + session_ptr->deauthmsgcnt = 0; + session_ptr->disassocmsgcnt = 0; + session_ptr->ht_client_cnt = 0; + + return &pMac->lim.gpSession[i]; +} + +/*-------------------------------------------------------------------------- + \brief pe_find_session_by_bssid() - looks up the PE session given the BSSID. + + This function returns the session context and the session ID if the session + corresponding to the given BSSID is found in the PE session table. + + \param pMac - pointer to global adapter context + \param bssid - BSSID of the session + \param sessionId -session ID is returned here, if session is found. + + \return tpPESession - pointer to the session context or NULL if session is not found. + + \sa + --------------------------------------------------------------------------*/ +tpPESession pe_find_session_by_bssid(tpAniSirGlobal pMac, uint8_t *bssid, + uint8_t *sessionId) +{ + uint8_t i; + + for (i = 0; i < pMac->lim.maxBssId; i++) { + /* If BSSID matches return corresponding tables address */ + if ((pMac->lim.gpSession[i].valid) + && (sir_compare_mac_addr(pMac->lim.gpSession[i].bssId, + bssid))) { + *sessionId = i; + return &pMac->lim.gpSession[i]; + } + } + + lim_log(pMac, LOG4, FL("Session lookup fails for BSSID:")); + lim_print_mac_addr(pMac, bssid, LOG4); + return NULL; + +} + +/*-------------------------------------------------------------------------- + \brief pe_find_session_by_bss_idx() - looks up the PE session given the bssIdx. + + This function returns the session context if the session + corresponding to the given bssIdx is found in the PE session table. + \param pMac - pointer to global adapter context + \param bssIdx - bss index of the session + \return tpPESession - pointer to the session context or NULL if session is not found. + \sa + --------------------------------------------------------------------------*/ +tpPESession pe_find_session_by_bss_idx(tpAniSirGlobal pMac, uint8_t bssIdx) +{ + uint8_t i; + for (i = 0; i < pMac->lim.maxBssId; i++) { + /* If BSSID matches return corresponding tables address */ + if ((pMac->lim.gpSession[i].valid) + && (pMac->lim.gpSession[i].bssIdx == bssIdx)) { + return &pMac->lim.gpSession[i]; + } + } + lim_log(pMac, LOG4, FL("Session lookup fails for bssIdx: %d"), bssIdx); + return NULL; +} + +/*-------------------------------------------------------------------------- + \brief pe_find_session_by_session_id() - looks up the PE session given the session ID. + + This function returns the session context if the session + corresponding to the given session ID is found in the PE session table. + + \param pMac - pointer to global adapter context + \param sessionId -session ID for which session context needs to be looked up. + + \return tpPESession - pointer to the session context or NULL if session is not found. + + \sa + --------------------------------------------------------------------------*/ +tpPESession pe_find_session_by_session_id(tpAniSirGlobal pMac, uint8_t sessionId) +{ + if (sessionId >= pMac->lim.maxBssId) { + lim_log(pMac, LOGE, FL("Invalid sessionId: %d \n "), sessionId); + return NULL; + } + if ((pMac->lim.gpSession[sessionId].valid == true)) { + return &pMac->lim.gpSession[sessionId]; + } + return NULL; + +} + +/** + * pe_find_session_by_sta_id() - looks up the PE session given staid. + * @mac_ctx: pointer to global adapter context + * @staid: StaId of the session + * @session_id: session ID is returned here, if session is found. + * + * This function returns the session context and the session ID if the session + * corresponding to the given StaId is found in the PE session table. + * + * Return: session pointer + */ +tpPESession +pe_find_session_by_sta_id(tpAniSirGlobal mac_ctx, + uint8_t staid, + uint8_t *session_id) +{ + uint8_t i, j; + tpPESession session_ptr; + dphHashTableClass *dph_ptr; + + for (i = 0; i < mac_ctx->lim.maxBssId; i++) { + if (!mac_ctx->lim.gpSession[i].valid) + continue; + session_ptr = &mac_ctx->lim.gpSession[i]; + dph_ptr = &session_ptr->dph.dphHashTable; + for (j = 0; j < dph_ptr->size; j++) { + if (dph_ptr->pDphNodeArray[j].valid + && dph_ptr->pDphNodeArray[j].added + && staid == dph_ptr->pDphNodeArray[j].staIndex) { + *session_id = i; + return session_ptr; + } + } + } + + lim_log(mac_ctx, LOG4, + FL("Session lookup fails for StaId: %d"), staid); + return NULL; +} + +/** + * pe_delete_session() - deletes the PE session given the session ID. + * @mac_ctx: pointer to global adapter context + * @session: session to be deleted. + * + * Deletes the given PE session + * + * Return: void + */ +void pe_delete_session(tpAniSirGlobal mac_ctx, tpPESession session) +{ + uint16_t i = 0; + uint16_t n; + TX_TIMER *timer_ptr; + + if (!session || (session && !session->valid)) { + QDF_TRACE(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_DEBUG, + FL("session is not valid")); + return; + } + + QDF_TRACE(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_DEBUG, + FL("Trying to delete PE session %d Opmode %d BssIdx %d BSSID: "MAC_ADDRESS_STR), + session->peSessionId, session->operMode, + session->bssIdx, + MAC_ADDR_ARRAY(session->bssId)); + for (n = 0; n < (mac_ctx->lim.maxStation + 1); n++) { + timer_ptr = &mac_ctx->lim.limTimers.gpLimCnfWaitTimer[n]; + if (session->peSessionId == timer_ptr->sessionId) + if (true == tx_timer_running(timer_ptr)) + tx_timer_deactivate(timer_ptr); + } + + if (LIM_IS_AP_ROLE(session)) { + qdf_mc_timer_stop(&session->protection_fields_reset_timer); + qdf_mc_timer_destroy(&session->protection_fields_reset_timer); + } + + /* Delete FT related information */ + lim_ft_cleanup(mac_ctx, session); + if (session->pLimStartBssReq != NULL) { + qdf_mem_free(session->pLimStartBssReq); + session->pLimStartBssReq = NULL; + } + + if (session->pLimJoinReq != NULL) { + qdf_mem_free(session->pLimJoinReq); + session->pLimJoinReq = NULL; + } + + if (session->pLimReAssocReq != NULL) { + qdf_mem_free(session->pLimReAssocReq); + session->pLimReAssocReq = NULL; + } + + if (session->pLimMlmJoinReq != NULL) { + qdf_mem_free(session->pLimMlmJoinReq); + session->pLimMlmJoinReq = NULL; + } + + if (session->dph.dphHashTable.pHashTable != NULL) { + qdf_mem_free(session->dph.dphHashTable.pHashTable); + session->dph.dphHashTable.pHashTable = NULL; + } + + if (session->dph.dphHashTable.pDphNodeArray != NULL) { + qdf_mem_free(session->dph.dphHashTable.pDphNodeArray); + session->dph.dphHashTable.pDphNodeArray = NULL; + } + + if (session->gpLimPeerIdxpool != NULL) { + qdf_mem_free(session->gpLimPeerIdxpool); + session->gpLimPeerIdxpool = NULL; + } + + if (session->beacon != NULL) { + qdf_mem_free(session->beacon); + session->beacon = NULL; + session->bcnLen = 0; + } + + if (session->assocReq != NULL) { + qdf_mem_free(session->assocReq); + session->assocReq = NULL; + session->assocReqLen = 0; + } + + if (session->assocRsp != NULL) { + qdf_mem_free(session->assocRsp); + session->assocRsp = NULL; + session->assocRspLen = 0; + } + + if (session->parsedAssocReq != NULL) { + tpSirAssocReq tmp_ptr = NULL; + /* Cleanup the individual allocation first */ + for (i = 0; i < session->dph.dphHashTable.size; i++) { + if (session->parsedAssocReq[i] == NULL) + continue; + tmp_ptr = ((tpSirAssocReq) + (session->parsedAssocReq[i])); + if (tmp_ptr->assocReqFrame) { + qdf_mem_free(tmp_ptr->assocReqFrame); + tmp_ptr->assocReqFrame = NULL; + tmp_ptr->assocReqFrameLength = 0; + } + qdf_mem_free(session->parsedAssocReq[i]); + session->parsedAssocReq[i] = NULL; + } + /* Cleanup the whole block */ + qdf_mem_free(session->parsedAssocReq); + session->parsedAssocReq = NULL; + } + if (NULL != session->limAssocResponseData) { + qdf_mem_free(session->limAssocResponseData); + session->limAssocResponseData = NULL; + } + if (NULL != session->pLimMlmReassocRetryReq) { + qdf_mem_free(session->pLimMlmReassocRetryReq); + session->pLimMlmReassocRetryReq = NULL; + } + if (NULL != session->pLimMlmReassocReq) { + qdf_mem_free(session->pLimMlmReassocReq); + session->pLimMlmReassocReq = NULL; + } + + if (NULL != session->pSchProbeRspTemplate) { + qdf_mem_free(session->pSchProbeRspTemplate); + session->pSchProbeRspTemplate = NULL; + } + + if (NULL != session->pSchBeaconFrameBegin) { + qdf_mem_free(session->pSchBeaconFrameBegin); + session->pSchBeaconFrameBegin = NULL; + } + + if (NULL != session->pSchBeaconFrameEnd) { + qdf_mem_free(session->pSchBeaconFrameEnd); + session->pSchBeaconFrameEnd = NULL; + } + + /* Must free the buffer before peSession invalid */ + if (NULL != session->addIeParams.probeRespData_buff) { + qdf_mem_free(session->addIeParams.probeRespData_buff); + session->addIeParams.probeRespData_buff = NULL; + session->addIeParams.probeRespDataLen = 0; + } + if (NULL != session->addIeParams.assocRespData_buff) { + qdf_mem_free(session->addIeParams.assocRespData_buff); + session->addIeParams.assocRespData_buff = NULL; + session->addIeParams.assocRespDataLen = 0; + } + if (NULL != session->addIeParams.probeRespBCNData_buff) { + qdf_mem_free(session->addIeParams.probeRespBCNData_buff); + session->addIeParams.probeRespBCNData_buff = NULL; + session->addIeParams.probeRespBCNDataLen = 0; + } +#ifdef WLAN_FEATURE_11W + if (QDF_TIMER_STATE_RUNNING == + qdf_mc_timer_get_current_state(&session->pmfComebackTimer)) + qdf_mc_timer_stop(&session->pmfComebackTimer); + qdf_mc_timer_destroy(&session->pmfComebackTimer); +#endif + session->valid = false; + + if (session->access_policy_vendor_ie) + qdf_mem_free(session->access_policy_vendor_ie); + + session->access_policy_vendor_ie = NULL; + + if (LIM_IS_AP_ROLE(session)) + lim_check_and_reset_protection_params(mac_ctx); + session->deauthmsgcnt = 0; + session->disassocmsgcnt = 0; + + return; +} + +/*-------------------------------------------------------------------------- + \brief pe_find_session_by_peer_sta() - looks up the PE session given the Station Address. + + This function returns the session context and the session ID if the session + corresponding to the given station address is found in the PE session table. + + \param pMac - pointer to global adapter context + \param sa - Peer STA Address of the session + \param sessionId -session ID is returned here, if session is found. + + \return tpPESession - pointer to the session context or NULL if session is not found. + + \sa + --------------------------------------------------------------------------*/ + +tpPESession pe_find_session_by_peer_sta(tpAniSirGlobal pMac, uint8_t *sa, + uint8_t *sessionId) +{ + uint8_t i; + tpDphHashNode pSta; + uint16_t aid; + + for (i = 0; i < pMac->lim.maxBssId; i++) { + if ((pMac->lim.gpSession[i].valid)) { + pSta = + dph_lookup_hash_entry(pMac, sa, &aid, + &pMac->lim.gpSession[i].dph. + dphHashTable); + if (pSta != NULL) { + *sessionId = i; + return &pMac->lim.gpSession[i]; + } + } + } + + lim_log(pMac, LOG1, FL("Session lookup fails for Peer StaId:")); + lim_print_mac_addr(pMac, sa, LOG1); + return NULL; +} + +/** + * pe_find_session_by_sme_session_id() - looks up the PE session for given sme + * session id + * @mac_ctx: pointer to global adapter context + * @sme_session_id: sme session id + * + * looks up the PE session for given sme session id + * + * Return: pe session entry for given sme session if found else NULL + */ +tpPESession pe_find_session_by_sme_session_id(tpAniSirGlobal mac_ctx, + uint8_t sme_session_id) +{ + uint8_t i; + for (i = 0; i < mac_ctx->lim.maxBssId; i++) { + if ((mac_ctx->lim.gpSession[i].valid) && + (mac_ctx->lim.gpSession[i].smeSessionId == + sme_session_id)) { + return &mac_ctx->lim.gpSession[i]; + } + } + lim_log(mac_ctx, LOG4, + FL("Session lookup fails for smeSessionID: %d"), + sme_session_id); + return NULL; +} + +/** + * pe_get_active_session_count() - function to return active pe session count + * + * @mac_ctx: pointer to global mac structure + * + * returns number of active pe session count + * + * Return: 0 if there are no active sessions else return number of active + * sessions + */ +uint8_t pe_get_active_session_count(tpAniSirGlobal mac_ctx) +{ + uint8_t i, active_session_count = 0; + + for (i = 0; i < mac_ctx->lim.maxBssId; i++) + if (mac_ctx->lim.gpSession[i].valid) + active_session_count++; + + return active_session_count; +} diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_session_utils.c b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_session_utils.c new file mode 100644 index 0000000000000000000000000000000000000000..fb9aab1443e237c775e6ab4de2b6c2d7b3462a40 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_session_utils.c @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2011-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/**========================================================================= + + \file lim_session_utils.c + \brief implementation for lim Session Utility APIs + \author Sunit Bhatia + ========================================================================*/ + +/*-------------------------------------------------------------------------- + Include Files + ------------------------------------------------------------------------*/ +#include "ani_global.h" +#include "lim_debug.h" +#include "lim_ft_defs.h" +#include "lim_session.h" +#include "lim_session_utils.h" +#include "lim_utils.h" + +/** + * is_lim_session_off_channel() - checks if any other off channel session exists + * @mac_ctx: Global MAC context. + * @sessionId: PE session ID. + * + * Return: This function returns true if the session Id passed needs to be on + * a different channel than atleast one session already active. + **/ +uint8_t is_lim_session_off_channel(tpAniSirGlobal mac_ctx, uint8_t session_id) +{ + uint8_t i; + + if (session_id >= mac_ctx->lim.maxBssId) { + lim_log(mac_ctx, LOGE, FL("Invalid session_id:%d"), session_id); + return false; + } + + for (i = 0; i < mac_ctx->lim.maxBssId; i++) { + /* Skip the session_id that is to be joined. */ + if (i == session_id) + continue; + /* + * if another session is valid and it is on different channel + * then it is an off channel operation. + */ + if ((mac_ctx->lim.gpSession[i].valid) && + (mac_ctx->lim.gpSession[i].currentOperChannel != + mac_ctx->lim.gpSession[session_id].currentOperChannel)) + return true; + } + return false; + +} + +/** + * lim_is_chan_switch_running() - check if channel switch is happening + * @mac_ctx: Global MAC context. + * + * Return: 1 - if channel switch is happening on any session. + * 0 - if channel switch is not happening. + **/ +uint8_t lim_is_chan_switch_running(tpAniSirGlobal mac_ctx) +{ + uint8_t i; + + for (i = 0; i < mac_ctx->lim.maxBssId; i++) + if (mac_ctx->lim.gpSession[i].valid && + mac_ctx->lim.gpSession[i].gLimSpecMgmt.dot11hChanSwState + == eLIM_11H_CHANSW_RUNNING) + return 1; + return 0; +} + +/** + * lim_is_in_mcc() - check if device is in MCC + * @mac_ctx: Global MAC context. + * + * Return: true - if in MCC. + * false - Not in MCC + **/ +uint8_t lim_is_in_mcc(tpAniSirGlobal mac_ctx) +{ + uint8_t i; + uint8_t chan = 0; + uint8_t curr_oper_channel = 0; + + for (i = 0; i < mac_ctx->lim.maxBssId; i++) { + /* + * if another session is valid and it is on different channel + * it is an off channel operation. + */ + if ((mac_ctx->lim.gpSession[i].valid)) { + curr_oper_channel = + mac_ctx->lim.gpSession[i].currentOperChannel; + if (chan == 0) + chan = curr_oper_channel; + else if (chan != curr_oper_channel) + return true; + } + } + return false; +} + +/** + * pe_get_current_stas_count() - Total stations associated on all sessions. + * @mac_ctx: Global MAC context. + * + * Return: true - Number of stations active on all sessions. + **/ +uint8_t pe_get_current_stas_count(tpAniSirGlobal mac_ctx) +{ + uint8_t i; + uint8_t stacount = 0; + for (i = 0; i < mac_ctx->lim.maxBssId; i++) + if (mac_ctx->lim.gpSession[i].valid == true) + stacount += + mac_ctx->lim.gpSession[i].gLimNumOfCurrentSTAs; + return stacount; +} diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_session_utils.h b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_session_utils.h new file mode 100644 index 0000000000000000000000000000000000000000..d1dd7d1c0370e2a074841a5e85492ab22680404b --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_session_utils.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#if !defined(__LIM_SESSION_UTILS_H) +#define __LIM_SESSION_UTILS_H + +uint8_t is_lim_session_off_channel(tpAniSirGlobal pMac, uint8_t sessionId); +uint8_t lim_is_chan_switch_running(tpAniSirGlobal pMac); +uint8_t lim_is_in_mcc(tpAniSirGlobal pMac); +uint8_t pe_get_current_stas_count(tpAniSirGlobal pMac); + +#endif /* #if !defined( __LIM_SESSION_UTILS_H ) */ diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_sme_req_utils.c b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_sme_req_utils.c new file mode 100644 index 0000000000000000000000000000000000000000..cd2112ba05318a2f39bd895745d5289d9ef36bb6 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_sme_req_utils.c @@ -0,0 +1,926 @@ +/* + * Copyright (c) 2011-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * + * This file lim_sme_req_utils.cc contains the utility functions + * for processing SME request messages. + * Author: Chandra Modumudi + * Date: 02/11/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + * 05/26/10 js WPA handling in (Re)Assoc frames + * + */ + +#include "wni_api.h" +#include "wni_cfg.h" +#include "cfg_api.h" +#include "sir_api.h" +#include "sch_api.h" +#include "utils_api.h" +#include "lim_types.h" +#include "lim_utils.h" +#include "lim_assoc_utils.h" +#include "lim_security_utils.h" +#include "lim_ser_des_utils.h" +#include "lim_sme_req_utils.h" + +/** + * lim_is_rs_nie_valid_in_sme_req_message() + * + * @mac_ctx Pointer to Global MAC structure + * @rsn_ie Pointer to received RSN IE + * + * This function is called to verify if the RSN IE received in various SME_REQ + * messages is valid or not + * + * Return: true when RSN IE is valid, false otherwise + * + */ + +static uint8_t +lim_is_rsn_ie_valid_in_sme_req_message(tpAniSirGlobal mac_ctx, tpSirRSNie rsn_ie) +{ + uint8_t start = 0; + uint32_t privacy, val; + int len; + + if (wlan_cfg_get_int(mac_ctx, WNI_CFG_PRIVACY_ENABLED, + &privacy) != eSIR_SUCCESS) { + lim_log(mac_ctx, LOGP, FL("Unable to retrieve POI from CFG")); + } + + if (wlan_cfg_get_int(mac_ctx, WNI_CFG_RSN_ENABLED, &val) + != eSIR_SUCCESS) { + lim_log(mac_ctx, LOGP, + FL("Unable to retrieve RSN_ENABLED from CFG")); + } + + if (rsn_ie->length && (!privacy || !val)) { + /* Privacy & RSN not enabled in CFG. + * In order to allow mixed mode for Guest access + * allow BSS creation/join with no Privacy capability + * yet advertising WPA IE + */ + PELOG1(lim_log(mac_ctx, LOG1, + FL("RSN ie len %d PRIVACY %d RSN %d"), + rsn_ie->length, privacy, val);) + } + + if (!rsn_ie->length) + return true; + + if ((rsn_ie->rsnIEdata[0] != DOT11F_EID_RSN) +#ifdef FEATURE_WLAN_WAPI + && (rsn_ie->rsnIEdata[0] != DOT11F_EID_WAPI) +#endif + && (rsn_ie->rsnIEdata[0] != DOT11F_EID_WPA)) { + lim_log(mac_ctx, LOGE, FL("RSN/WPA/WAPI EID %d not [%d || %d]"), + rsn_ie->rsnIEdata[0], DOT11F_EID_RSN, + DOT11F_EID_WPA); + return false; + } + + len = rsn_ie->length; + start = 0; + while (len > 0) { + switch (rsn_ie->rsnIEdata[start]) { + case DOT11F_EID_RSN: + /* Check validity of RSN IE */ + if ((rsn_ie->rsnIEdata[start + 1] > + DOT11F_IE_RSN_MAX_LEN) + || (rsn_ie->rsnIEdata[start + 1] < + DOT11F_IE_RSN_MIN_LEN)) { + lim_log(mac_ctx, LOGE, + FL("RSN IE len %d not [%d,%d]"), + rsn_ie->rsnIEdata[start + 1], + DOT11F_IE_RSN_MIN_LEN, + DOT11F_IE_RSN_MAX_LEN); + return false; + } + break; + case DOT11F_EID_WPA: + /* Check validity of WPA IE */ + if (SIR_MAC_MAX_IE_LENGTH <= start) + break; + + if (start <= (SIR_MAC_MAX_IE_LENGTH - sizeof(uint32_t))) + val = sir_read_u32((uint8_t *) & + rsn_ie->rsnIEdata[start + 2]); + + if ((rsn_ie->rsnIEdata[start + 1] < + DOT11F_IE_WPA_MIN_LEN) + || (rsn_ie->rsnIEdata[start + 1] > + DOT11F_IE_WPA_MAX_LEN) + || (SIR_MAC_WPA_OUI != val)) { + lim_log(mac_ctx, LOGE, + FL("WPA IE len %d not [%d,%d] OR data 0x%x not 0x%x"), + rsn_ie->rsnIEdata[start + 1], + DOT11F_IE_WPA_MIN_LEN, + DOT11F_IE_WPA_MAX_LEN, + val, SIR_MAC_WPA_OUI); + return false; + } + break; +#ifdef FEATURE_WLAN_WAPI + case DOT11F_EID_WAPI: + if ((rsn_ie->rsnIEdata[start + 1] > + DOT11F_IE_WAPI_MAX_LEN) + || (rsn_ie->rsnIEdata[start + 1] < + DOT11F_IE_WAPI_MIN_LEN)) { + lim_log(mac_ctx, LOGE, + FL("WAPI IE len %d not [%d,%d]"), + rsn_ie->rsnIEdata[start + 1], + DOT11F_IE_WAPI_MIN_LEN, + DOT11F_IE_WAPI_MAX_LEN); + return false; + } + break; +#endif + default: + /* we will never be here, simply for completeness */ + return false; + } /* end of switch */ + /* EID + length field + length */ + start += 2 + rsn_ie->rsnIEdata[start + 1]; + len -= start; + } /* end while loop */ + return true; +} /*** end lim_is_rs_nie_valid_in_sme_req_message() ***/ + +/** + * lim_is_addie_valid_in_sme_req_message() + * + ***FUNCTION: + * This function is called to verify if the Add IE + * received in various SME_REQ messages is valid or not + * + ***LOGIC: + * Add IE validity checks are performed on only length + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param pMac Pointer to Global MAC structure + * @param pWSCie Pointer to received WSC IE + * @return true when WSC IE is valid, false otherwise + */ + +static uint8_t +lim_is_addie_valid_in_sme_req_message(tpAniSirGlobal pMac, tpSirAddie pAddie) +{ + int left = pAddie->length; + uint8_t *ptr = pAddie->addIEdata; + uint8_t elem_id, elem_len; + + if (left == 0) + return true; + + while (left >= 2) { + elem_id = ptr[0]; + elem_len = ptr[1]; + left -= 2; + if (elem_len > left) { + lim_log(pMac, LOGE, + FL + ("****Invalid Add IEs eid = %d elem_len=%d left=%d*****"), + elem_id, elem_len, left); + return false; + } + + left -= elem_len; + ptr += (elem_len + 2); + } + /* there shouldn't be any left byte */ + + return true; +} /*** end lim_is_addie_valid_in_sme_req_message() ***/ + +/** + * lim_set_rs_nie_wp_aiefrom_sme_start_bss_req_message() - to set rsnie/wpaie + * + * @mac_ctx : Pointer to Global MAC structure + * @rsn_ie : Pointer to received RSN IE + * @session : Pointer to pe session + * + * This function is called to verify if the RSN IE received in various + * SME_REQ messages is valid or not. RSN IE validity checks are performed in + * this function + * + * Return: true when RSN IE is valid, false otherwise + */ +uint8_t +lim_set_rs_nie_wp_aiefrom_sme_start_bss_req_message(tpAniSirGlobal mac_ctx, + tpSirRSNie rsn_ie, + tpPESession session) +{ + uint8_t wpa_idx = 0; + uint32_t privacy, val; + + if (wlan_cfg_get_int(mac_ctx, WNI_CFG_PRIVACY_ENABLED, + &privacy) != eSIR_SUCCESS) + lim_log(mac_ctx, LOGP, FL("Unable to retrieve POI from CFG")); + + if (wlan_cfg_get_int(mac_ctx, WNI_CFG_RSN_ENABLED, + &val) != eSIR_SUCCESS) + lim_log(mac_ctx, LOGP, + FL("Unable to retrieve RSN_ENABLED from CFG")); + + if (rsn_ie->length && (!privacy || !val)) { + /* + * Privacy & RSN not enabled in CFG. + * In order to allow mixed mode for Guest access + * allow BSS creation/join with no Privacy capability + * yet advertising WPA IE + */ + lim_log(mac_ctx, LOG1, + FL("RSN ie len %d but PRIVACY %d RSN %d"), + rsn_ie->length, privacy, val); + } + + if (!rsn_ie->length) + return true; + + if ((rsn_ie->rsnIEdata[0] != SIR_MAC_RSN_EID) && + (rsn_ie->rsnIEdata[0] != SIR_MAC_WPA_EID)) { + lim_log(mac_ctx, LOGE, FL("RSN/WPA EID %d not [%d || %d]"), + rsn_ie->rsnIEdata[0], SIR_MAC_RSN_EID, + SIR_MAC_WPA_EID); + return false; + } + /* Check validity of RSN IE */ + if ((rsn_ie->rsnIEdata[0] == SIR_MAC_RSN_EID) && + (rsn_ie->rsnIEdata[1] < SIR_MAC_RSN_IE_MIN_LENGTH)) { + lim_log(mac_ctx, LOGE, FL("RSN IE len %d not [%d,%d]"), + rsn_ie->rsnIEdata[1], SIR_MAC_RSN_IE_MIN_LENGTH, + SIR_MAC_RSN_IE_MAX_LENGTH); + return false; + } + + if (rsn_ie->length > rsn_ie->rsnIEdata[1] + 2) { + if (rsn_ie->rsnIEdata[0] != SIR_MAC_RSN_EID) { + lim_log(mac_ctx, LOGE, + FL("First byte[%d] in rsnIEdata isn't RSN_EID"), + rsn_ie->rsnIEdata[1]); + return false; + } + lim_log(mac_ctx, LOG1, + FL("WPA IE is present along with WPA2 IE")); + wpa_idx = 2 + rsn_ie->rsnIEdata[1]; + } else if ((rsn_ie->length == rsn_ie->rsnIEdata[1] + 2) && + (rsn_ie->rsnIEdata[0] == SIR_MAC_RSN_EID)) { + lim_log(mac_ctx, LOG1, FL("Only RSN IE is present")); + dot11f_unpack_ie_rsn(mac_ctx, &rsn_ie->rsnIEdata[2], + (uint8_t) rsn_ie->length, + &session->gStartBssRSNIe); + } else if ((rsn_ie->length == rsn_ie->rsnIEdata[1] + 2) + && (rsn_ie->rsnIEdata[0] == SIR_MAC_WPA_EID)) { + lim_log(mac_ctx, LOG1, FL("Only WPA IE is present")); + dot11f_unpack_ie_wpa(mac_ctx, &rsn_ie->rsnIEdata[6], + (uint8_t) rsn_ie->length - 4, + &session->gStartBssWPAIe); + } + /* Check validity of WPA IE */ + if (wpa_idx + 6 >= SIR_MAC_MAX_IE_LENGTH) + return false; + + val = sir_read_u32((uint8_t *)&rsn_ie->rsnIEdata[wpa_idx + 2]); + if ((rsn_ie->rsnIEdata[wpa_idx] == SIR_MAC_WPA_EID) + && ((rsn_ie->rsnIEdata[wpa_idx + 1] < SIR_MAC_WPA_IE_MIN_LENGTH) + || (SIR_MAC_WPA_OUI != val))) { + lim_log(mac_ctx, LOGE, + FL("WPA IE len %d not [%d,%d] OR data 0x%x not 0x%x"), + rsn_ie->rsnIEdata[1], + SIR_MAC_RSN_IE_MIN_LENGTH, + SIR_MAC_RSN_IE_MAX_LENGTH, val, + SIR_MAC_WPA_OUI); + return false; + } else { + /* Both RSN and WPA IEs are present */ + dot11f_unpack_ie_rsn(mac_ctx, &rsn_ie->rsnIEdata[2], + (uint8_t) rsn_ie->length, + &session->gStartBssRSNIe); + dot11f_unpack_ie_wpa(mac_ctx, &rsn_ie->rsnIEdata[wpa_idx + 6], + rsn_ie->rsnIEdata[wpa_idx + 1] - 4, + &session->gStartBssWPAIe); + } + return true; +} + +/** + * lim_is_bss_descr_valid_in_sme_req_message() + * + ***FUNCTION: + * This function is called to verify if the BSS Descr + * received in various SME_REQ messages is valid or not + * + ***LOGIC: + * BSS Descritipion validity checks are performed in this function + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param pMac Pointer to Global MAC structure + * @param pBssDescr Pointer to received Bss Descritipion + * @return true when BSS description is valid, false otherwise + */ + +static uint8_t +lim_is_bss_descr_valid_in_sme_req_message(tpAniSirGlobal pMac, + tpSirBssDescription pBssDescr) +{ + uint8_t valid = true; + + if (lim_is_addr_bc(pBssDescr->bssId) || !pBssDescr->channelId) { + valid = false; + goto end; + } + +end: + return valid; +} /*** end lim_is_bss_descr_valid_in_sme_req_message() ***/ + +/** + * lim_is_sme_start_bss_req_valid() - To validate sme start bss request + * + * @mac_ctx: Pointer to Global MAC structure + * @start_bss_req: Pointer to received SME_START_BSS_REQ message + * + * This function is called by lim_process_sme_req_messages() upon + * receiving SME_START_BSS_REQ message from application. + * + * Return: true when received SME_START_BSS_REQ is formatted correctly false + * otherwise + */ + +uint8_t +lim_is_sme_start_bss_req_valid(tpAniSirGlobal mac_ctx, + tpSirSmeStartBssReq start_bss_req) +{ + uint8_t i = 0; + tSirMacRateSet *opr_rates = &start_bss_req->operationalRateSet; + + PELOG1(lim_log(mac_ctx, LOG1, + FL("Parsed START_BSS_REQ fields are bssType=%s (%d), channelId=%d, SSID len=%d, rsnIE len=%d, nwType=%d, rateset len=%d"), + lim_bss_type_to_string(start_bss_req->bssType), + start_bss_req->bssType, start_bss_req->channelId, + start_bss_req->ssId.length, start_bss_req->rsnIE.length, + start_bss_req->nwType, opr_rates->numRates);) + + switch (start_bss_req->bssType) { + case eSIR_INFRASTRUCTURE_MODE: + /** + * Should not have received start BSS req with bssType + * Infrastructure on STA. + */ + lim_log(mac_ctx, LOGE, + FL("Invalid bssType %d in eWNI_SME_START_BSS_REQ"), + start_bss_req->bssType); + return false; + break; + case eSIR_IBSS_MODE: + break; + case eSIR_INFRA_AP_MODE: + break; + case eSIR_NDI_MODE: + break; + default: + /** + * Should not have received start BSS req with bssType + * other than Infrastructure/IBSS. + */ + lim_log(mac_ctx, LOGW, + FL("Invalid bssType %d in eWNI_SME_START_BSS_REQ"), + start_bss_req->bssType); + return false; + } + + if (start_bss_req->bssType == eSIR_IBSS_MODE + && (!start_bss_req->ssId.length + || start_bss_req->ssId.length > SIR_MAC_MAX_SSID_LENGTH)) { + lim_log(mac_ctx, LOGW, + FL("Invalid SSID length in eWNI_SME_START_BSS_REQ")); + return false; + } + + if (!lim_is_rsn_ie_valid_in_sme_req_message(mac_ctx, + &start_bss_req->rsnIE)) + return false; + + if (start_bss_req->nwType != eSIR_11A_NW_TYPE + && start_bss_req->nwType != eSIR_11B_NW_TYPE + && start_bss_req->nwType != eSIR_11G_NW_TYPE) + return false; + + if (start_bss_req->nwType == eSIR_11A_NW_TYPE) { + for (i = 0; i < opr_rates->numRates; i++) { + if (sirIsArate(opr_rates->rate[i] & 0x7F)) + continue; + + lim_log(mac_ctx, LOGW, + FL("Invalid operational 11A rates")); + sir_dump_buf(mac_ctx, SIR_LIM_MODULE_ID, LOG2, + opr_rates->rate, opr_rates->numRates); + return false; + } + return true; + } + /* check if all the rates in the opr rate set are legal 11G rates */ + if (start_bss_req->nwType == eSIR_11G_NW_TYPE) { + for (i = 0; i < opr_rates->numRates; i++) { + if (sirIsGrate(opr_rates->rate[i] & 0x7F)) + continue; + + lim_log(mac_ctx, LOGW, + FL("Invalid operational 11G rates")); + sir_dump_buf(mac_ctx, SIR_LIM_MODULE_ID, LOG2, + opr_rates->rate, opr_rates->numRates); + return false; + } + return true; + } + + for (i = 0; i < opr_rates->numRates; i++) { + if (sirIsBrate(opr_rates->rate[i] & 0x7F)) + continue; + + lim_log(mac_ctx, LOGW, + FL("Invalid operational 11B rates")); + sir_dump_buf(mac_ctx, SIR_LIM_MODULE_ID, LOG2, + opr_rates->rate, opr_rates->numRates); + return false; + } + return true; +} + +/** + * lim_is_sme_join_req_valid() + * + ***FUNCTION: + * This function is called by lim_process_sme_req_messages() upon + * receiving SME_JOIN_REQ message from application. + * + ***LOGIC: + * Message validity checks are performed in this function + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param pMac Pointer to Global MAC structure + * @param pJoinReq Pointer to received SME_JOIN_REQ message + * @return true when received SME_JOIN_REQ is formatted correctly + * false otherwise + */ + +uint8_t lim_is_sme_join_req_valid(tpAniSirGlobal pMac, tpSirSmeJoinReq pJoinReq) +{ + uint8_t valid = true; + + if (!lim_is_rsn_ie_valid_in_sme_req_message(pMac, &pJoinReq->rsnIE)) { + lim_log(pMac, LOGE, + FL("received SME_JOIN_REQ with invalid RSNIE")); + valid = false; + goto end; + } + + if (!lim_is_addie_valid_in_sme_req_message(pMac, &pJoinReq->addIEScan)) { + lim_log(pMac, LOGE, + FL + ("received SME_JOIN_REQ with invalid additional IE for scan")); + valid = false; + goto end; + } + + if (!lim_is_addie_valid_in_sme_req_message(pMac, &pJoinReq->addIEAssoc)) { + lim_log(pMac, LOGE, + FL + ("received SME_JOIN_REQ with invalid additional IE for assoc")); + valid = false; + goto end; + } + + if (!lim_is_bss_descr_valid_in_sme_req_message(pMac, &pJoinReq->bssDescription)) { + /* / Received eWNI_SME_JOIN_REQ with invalid BSS Info */ + /* Log the event */ + lim_log(pMac, LOGE, + FL("received SME_JOIN_REQ with invalid bssInfo")); + + valid = false; + goto end; + } + + /* + Reject Join Req if the Self Mac Address and + the Ap's Mac Address is same + */ + if (!qdf_mem_cmp((uint8_t *) pJoinReq->selfMacAddr, + (uint8_t *) pJoinReq->bssDescription.bssId, + (uint8_t) (sizeof(tSirMacAddr)))) { + /* Log the event */ + lim_log(pMac, LOGE, + FL + ("received SME_JOIN_REQ with Self Mac and BSSID Same")); + + valid = false; + goto end; + } + +end: + return valid; +} /*** end lim_is_sme_join_req_valid() ***/ + +/** + * lim_is_sme_disassoc_req_valid() + * + ***FUNCTION: + * This function is called by lim_process_sme_req_messages() upon + * receiving SME_DISASSOC_REQ message from application. + * + ***LOGIC: + * Message validity checks are performed in this function + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param pMac Pointer to Global MAC structure + * @param pDisassocReq Pointer to received SME_DISASSOC_REQ message + * @return true When received SME_DISASSOC_REQ is formatted + * correctly + * false otherwise + */ + +uint8_t +lim_is_sme_disassoc_req_valid(tpAniSirGlobal pMac, + tpSirSmeDisassocReq pDisassocReq, + tpPESession psessionEntry) +{ + if (qdf_is_macaddr_group(&pDisassocReq->peer_macaddr) && + !qdf_is_macaddr_broadcast(&pDisassocReq->peer_macaddr)) + return false; + + return true; +} /*** end lim_is_sme_disassoc_req_valid() ***/ + +/** + * lim_is_sme_disassoc_cnf_valid() + * + ***FUNCTION: + * This function is called by lim_process_sme_req_messages() upon + * receiving SME_DISASSOC_CNF message from application. + * + ***LOGIC: + * Message validity checks are performed in this function + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param pMac Pointer to Global MAC structure + * @param pDisassocCnf Pointer to received SME_DISASSOC_REQ message + * @return true When received SME_DISASSOC_CNF is formatted + * correctly + * false otherwise + */ + +uint8_t +lim_is_sme_disassoc_cnf_valid(tpAniSirGlobal pMac, + tpSirSmeDisassocCnf pDisassocCnf, + tpPESession psessionEntry) +{ + if (qdf_is_macaddr_group(&pDisassocCnf->peer_macaddr)) + return false; + + return true; +} /*** end lim_is_sme_disassoc_cnf_valid() ***/ + +/** + * lim_is_sme_deauth_req_valid() + * + ***FUNCTION: + * This function is called by lim_process_sme_req_messages() upon + * receiving SME_DEAUTH_REQ message from application. + * + ***LOGIC: + * Message validity checks are performed in this function + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param pMac Pointer to Global MAC structure + * @param pDeauthReq Pointer to received SME_DEAUTH_REQ message + * @return true When received SME_DEAUTH_REQ is formatted correctly + * false otherwise + */ + +uint8_t +lim_is_sme_deauth_req_valid(tpAniSirGlobal pMac, tpSirSmeDeauthReq pDeauthReq, + tpPESession psessionEntry) +{ + if (qdf_is_macaddr_group(&pDeauthReq->peer_macaddr) && + !qdf_is_macaddr_broadcast(&pDeauthReq->peer_macaddr)) + return false; + + return true; +} /*** end lim_is_sme_deauth_req_valid() ***/ + +/** + * lim_is_sme_scan_req_valid() + * + ***FUNCTION: + * This function is called by lim_process_sme_req_messages() upon + * receiving SME_SCAN_REQ message from application. + * + ***LOGIC: + * Message validity checks are performed in this function + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param pScanReq Pointer to received SME_SCAN_REQ message + * @return true when received SME_SCAN_REQ is formatted correctly + * false otherwise + */ + +uint8_t lim_is_sme_scan_req_valid(tpAniSirGlobal pMac, tpSirSmeScanReq pScanReq) +{ + uint8_t valid = true; + uint8_t i = 0; + + if (pScanReq->numSsid > SIR_SCAN_MAX_NUM_SSID) { + valid = false; + lim_log(pMac, LOGE, + FL("Number of SSIDs > SIR_SCAN_MAX_NUM_SSID")); + goto end; + } + + for (i = 0; i < pScanReq->numSsid; i++) { + if (pScanReq->ssId[i].length > SIR_MAC_MAX_SSID_LENGTH) { + lim_log(pMac, LOGE, + FL + ("Requested SSID length > SIR_MAC_MAX_SSID_LENGTH")); + valid = false; + goto end; + } + } + if ((pScanReq->bssType < 0) || (pScanReq->bssType > eSIR_AUTO_MODE)) { + lim_log(pMac, LOGE, FL("Invalid BSS Type")); + valid = false; + } + if (qdf_is_macaddr_group(&pScanReq->bssId) && + !qdf_is_macaddr_broadcast(&pScanReq->bssId)) { + valid = false; + lim_log(pMac, LOGE, + FL("BSSID is group addr and is not Broadcast Addr")); + } + if (! + (pScanReq->scanType == eSIR_PASSIVE_SCAN + || pScanReq->scanType == eSIR_ACTIVE_SCAN)) { + valid = false; + lim_log(pMac, LOGE, FL("Invalid Scan Type")); + } + if (pScanReq->channelList.numChannels > SIR_MAX_NUM_CHANNELS) { + valid = false; + lim_log(pMac, LOGE, + FL("Number of Channels > SIR_MAX_NUM_CHANNELS")); + } + + /* + ** check min/max channelTime range + **/ + if (valid) { + if ((pScanReq->scanType == eSIR_ACTIVE_SCAN) && + (pScanReq->maxChannelTime < pScanReq->minChannelTime)) { + lim_log(pMac, LOGE, + FL("Max Channel Time < Min Channel Time")); + valid = false; + goto end; + } + } + +end: + return valid; +} /*** end lim_is_sme_scan_req_valid() ***/ + +/** + * lim_is_sme_set_context_req_valid() + * + ***FUNCTION: + * This function is called by lim_process_sme_req_messages() upon + * receiving SME_SET_CONTEXT_REQ message from application. + * + ***LOGIC: + * Message validity checks are performed in this function + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param pMsg - Pointer to received SME_SET_CONTEXT_REQ message + * @return true when received SME_SET_CONTEXT_REQ is formatted correctly + * false otherwise + */ + +uint8_t +lim_is_sme_set_context_req_valid(tpAniSirGlobal pMac, + tpSirSmeSetContextReq pSetContextReq) +{ + uint8_t i = 0; + uint8_t valid = true; + tpSirKeys pKey = pSetContextReq->keyMaterial.key; + + if ((pSetContextReq->keyMaterial.edType != eSIR_ED_WEP40) && + (pSetContextReq->keyMaterial.edType != eSIR_ED_WEP104) && + (pSetContextReq->keyMaterial.edType != eSIR_ED_NONE) && +#ifdef FEATURE_WLAN_WAPI + (pSetContextReq->keyMaterial.edType != eSIR_ED_WPI) && +#endif + !pSetContextReq->keyMaterial.numKeys) { + /** + * No keys present in case of TKIP or CCMP + * Log error. + */ + lim_log(pMac, LOGW, + FL + ("No keys present in SME_SETCONTEXT_REQ for edType=%d"), + pSetContextReq->keyMaterial.edType); + + valid = false; + goto end; + } + + if (pSetContextReq->keyMaterial.numKeys && + (pSetContextReq->keyMaterial.edType == eSIR_ED_NONE)) { + /** + * Keys present in case of no ED policy + * Log error. + */ + lim_log(pMac, LOGW, + FL("Keys present in SME_SETCONTEXT_REQ for edType=%d"), + pSetContextReq->keyMaterial.edType); + + valid = false; + goto end; + } + + if (pSetContextReq->keyMaterial.edType >= eSIR_ED_NOT_IMPLEMENTED) { + /** + * Invalid edType in the message + * Log error. + */ + lim_log(pMac, LOGW, + FL("Invalid edType=%d in SME_SETCONTEXT_REQ"), + pSetContextReq->keyMaterial.edType); + + valid = false; + goto end; + } else if (pSetContextReq->keyMaterial.edType > eSIR_ED_NONE) { + uint32_t poi; + + if (wlan_cfg_get_int(pMac, WNI_CFG_PRIVACY_ENABLED, + &poi) != eSIR_SUCCESS) { + lim_log(pMac, LOGP, + FL("Unable to retrieve POI from CFG")); + } + + if (!poi) { + /** + * Privacy is not enabled + * In order to allow mixed mode for Guest access + * allow BSS creation/join with no Privacy capability + * yet advertising WPA IE + */ + PELOG1(lim_log(pMac, LOG1, + FL + ("Privacy is not enabled, yet non-None EDtype=%d in SME_SETCONTEXT_REQ"), + pSetContextReq->keyMaterial.edType); + ) + } + } + + for (i = 0; i < pSetContextReq->keyMaterial.numKeys; i++) { + if (((pSetContextReq->keyMaterial.edType == eSIR_ED_WEP40) && + (pKey->keyLength != 5)) || + ((pSetContextReq->keyMaterial.edType == eSIR_ED_WEP104) && + (pKey->keyLength != 13)) || + ((pSetContextReq->keyMaterial.edType == eSIR_ED_TKIP) && + (pKey->keyLength != 32)) || +#ifdef FEATURE_WLAN_WAPI + ((pSetContextReq->keyMaterial.edType == eSIR_ED_WPI) && + (pKey->keyLength != 32)) || +#endif + ((pSetContextReq->keyMaterial.edType == eSIR_ED_CCMP) && + (pKey->keyLength != 16))) { + /** + * Invalid key length for a given ED type + * Log error. + */ + lim_log(pMac, LOGW, + FL + ("Invalid keyLength =%d for edType=%d in SME_SETCONTEXT_REQ"), + pKey->keyLength, + pSetContextReq->keyMaterial.edType); + + valid = false; + goto end; + } + pKey++; + } + +end: + return valid; +} /*** end lim_is_sme_set_context_req_valid() ***/ + +/** + * lim_is_sme_stop_bss_req_valid() + * + ***FUNCTION: + * This function is called by lim_process_sme_req_messages() upon + * receiving SME_STOP_BSS_REQ message from application. + * + ***LOGIC: + * Message validity checks are performed in this function + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param pMsg - Pointer to received SME_STOP_BSS_REQ message + * @return true when received SME_STOP_BSS_REQ is formatted correctly + * false otherwise + */ + +uint8_t lim_is_sme_stop_bss_req_valid(uint32_t *pMsg) +{ + uint8_t valid = true; + + return valid; +} /*** end lim_is_sme_stop_bss_req_valid() ***/ + +/** + * lim_get_bss_id_from_sme_join_req_msg() + * + ***FUNCTION: + * This function is called in various places to get BSSID + * from BSS description/Neighbor BSS Info in the SME_JOIN_REQ/ + * SME_REASSOC_REQ message. + * + ***PARAMS: + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param pBuf - Pointer to received SME_JOIN/SME_REASSOC_REQ + * message + * @return pBssId - Pointer to BSSID + */ + +uint8_t *lim_get_bss_id_from_sme_join_req_msg(uint8_t *pBuf) +{ + if (!pBuf) + return NULL; + + pBuf += sizeof(uint32_t); /* skip message header */ + + pBuf += lim_get_u16(pBuf) + sizeof(uint16_t); /* skip RSN IE */ + + pBuf += sizeof(uint16_t); /* skip length of BSS description */ + + return pBuf; +} /*** end lim_get_bss_id_from_sme_join_req_msg() ***/ diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_sme_req_utils.h b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_sme_req_utils.h new file mode 100644 index 0000000000000000000000000000000000000000..7e89373ad2e1c6fb026f0fbcc98f877a08ab0dfa --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_sme_req_utils.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2011-2012,2014-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * + * This file lim_sme_req_utils.h contains the utility definitions + * LIM uses while processing SME request messsages. + * Author: Chandra Modumudi + * Date: 02/13/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + */ +#ifndef __LIM_SME_REQ_UTILS_H +#define __LIM_SME_REQ_UTILS_H + +#include "sir_api.h" +#include "lim_types.h" + +/* LIM SME request messages related utility functions */ +uint8_t lim_is_sme_start_bss_req_valid(tpAniSirGlobal, tpSirSmeStartBssReq); +uint8_t lim_set_rs_nie_wp_aiefrom_sme_start_bss_req_message(tpAniSirGlobal, + tpSirRSNie, tpPESession); +uint8_t lim_is_sme_scan_req_valid(tpAniSirGlobal, tpSirSmeScanReq); +uint8_t lim_is_sme_join_req_valid(tpAniSirGlobal, tpSirSmeJoinReq); +uint8_t lim_is_sme_disassoc_req_valid(tpAniSirGlobal, tpSirSmeDisassocReq, + tpPESession); +uint8_t lim_is_sme_deauth_req_valid(tpAniSirGlobal, tpSirSmeDeauthReq, tpPESession); +uint8_t lim_is_sme_set_context_req_valid(tpAniSirGlobal, tpSirSmeSetContextReq); +uint8_t lim_is_sme_stop_bss_req_valid(uint32_t *); +uint8_t *lim_get_bss_id_from_sme_join_req_msg(uint8_t *); +uint8_t lim_is_sme_disassoc_cnf_valid(tpAniSirGlobal, tpSirSmeDisassocCnf, + tpPESession); + +#endif /* __LIM_SME_REQ_UTILS_H */ diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_sta_hash_api.c b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_sta_hash_api.c new file mode 100644 index 0000000000000000000000000000000000000000..794ebaad073e5e4df26a0e97316f03af704a1413 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_sta_hash_api.c @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2011-2012, 2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * + * lim_sta_hash_api.c: Provides access functions to get/set values of station hash entry fields. + * Author: Sunit Bhatia + * Date: 09/19/2006 + * History:- + * Date Modified by Modification Information + * + * -------------------------------------------------------------------------- + * + */ + +#include "lim_sta_hash_api.h" + +/** + * lim_get_sta_hash_bssidx() + * + ***FUNCTION: + * This function is called to Get the Bss Index of the currently associated Station. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param pMac pointer to Global Mac structure. + * @param assocId AssocID of the Station. + * @param bssidx pointer to the bss index, which will be returned by the function. + * + * @return success if GET operation is ok, else Failure. + */ + +tSirRetStatus lim_get_sta_hash_bssidx(tpAniSirGlobal pMac, uint16_t assocId, + uint8_t *bssidx, tpPESession psessionEntry) +{ + tpDphHashNode pSta = + dph_get_hash_entry(pMac, assocId, &psessionEntry->dph.dphHashTable); + + if (pSta == NULL) { + PELOGE(lim_log(pMac, LOGE, FL("invalid STA %d"), assocId);) + return eSIR_LIM_INVALID_STA; + } + + *bssidx = (uint8_t) pSta->bssId; + return eSIR_SUCCESS; +} diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_sta_hash_api.h b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_sta_hash_api.h new file mode 100644 index 0000000000000000000000000000000000000000..9a34091ad39d19cb207f14ddb745b7a8e2b8f37b --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_sta_hash_api.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2011-2012, 2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * + * This file lim_sta_hash_api.h contains the + * function prototypes for accessing station hash entry fields. + * + * Author: Sunit Bhatia + * Date: 09/19/2006 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + * + */ + +#ifndef __LIM_STA_HASH_API_H__ +#define __LIM_STA_HASH_API_H__ + +#include "ani_global.h" +#include "lim_types.h" + +tSirRetStatus lim_get_sta_hash_bssidx(tpAniSirGlobal pMac, uint16_t assocId, + uint8_t *bssidx, tpPESession psessionEntry); + +#endif diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_timer_utils.c b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_timer_utils.c new file mode 100644 index 0000000000000000000000000000000000000000..8d40225cd1a892624ac106c0a043501a000c489a --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_timer_utils.c @@ -0,0 +1,1281 @@ +/* + * Copyright (c) 2011-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * This file lim_timer_utils.cc contains the utility functions + * LIM uses for handling various timers. + * Author: Chandra Modumudi + * Date: 02/13/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + */ + +#include "lim_types.h" +#include "lim_utils.h" +#include "lim_assoc_utils.h" +#include "lim_security_utils.h" +#include + +/* channel Switch Timer in ticks */ +#define LIM_CHANNEL_SWITCH_TIMER_TICKS 1 +/* Lim Quite timer in ticks */ +#define LIM_QUIET_TIMER_TICKS 100 +/* Lim Quite BSS timer interval in ticks */ +#define LIM_QUIET_BSS_TIMER_TICK 100 +/* Lim KeepAlive timer default (3000)ms */ +#define LIM_KEEPALIVE_TIMER_MS 3000 +/* Lim JoinProbeRequest Retry timer default (200)ms */ +#define LIM_JOIN_PROBE_REQ_TIMER_MS 200 +/* Lim Periodic Auth Retry timer default 60 ms */ +#define LIM_AUTH_RETRY_TIMER_MS 60 + + +/* This timer is a periodic timer which expires at every 1 sec to + convert ACTIVE DFS channel to DFS channels */ +#define ACTIVE_TO_PASSIVE_CONVERISON_TIMEOUT 1000 + +static bool lim_create_non_ap_timers(tpAniSirGlobal pMac) +{ + uint32_t cfgValue; + /* Create Channel Switch Timer */ + if (tx_timer_create(pMac, &pMac->lim.limTimers.gLimChannelSwitchTimer, + "CHANNEL SWITCH TIMER", + lim_channel_switch_timer_handler, 0, + LIM_CHANNEL_SWITCH_TIMER_TICKS, + 0, TX_NO_ACTIVATE) != TX_SUCCESS) { + lim_log(pMac, LOGP, FL("failed to create Ch Switch timer")); + return false; + } + /* Create Quiet Timer + * This is used on the STA to go and shut-off Tx/Rx "after" the + * specified quiteInterval + */ + if (tx_timer_create(pMac, &pMac->lim.limTimers.gLimQuietTimer, + "QUIET TIMER", lim_quiet_timer_handler, + SIR_LIM_QUIET_TIMEOUT, LIM_QUIET_TIMER_TICKS, + 0, TX_NO_ACTIVATE) != TX_SUCCESS) { + lim_log(pMac, LOGP, FL("failed to create Quiet Begin Timer")); + return false; + } + /* Create Quiet BSS Timer + * After the specified quiteInterval, determined by gLimQuietTimer, this + * timer, gLimQuietBssTimer, trigger and put the STA to sleep for the + * specified gLimQuietDuration + */ + if (tx_timer_create(pMac, &pMac->lim.limTimers.gLimQuietBssTimer, + "QUIET BSS TIMER", lim_quiet_bss_timer_handler, + SIR_LIM_QUIET_BSS_TIMEOUT, LIM_QUIET_BSS_TIMER_TICK, + 0, TX_NO_ACTIVATE) != TX_SUCCESS) { + lim_log(pMac, LOGP, FL("failed to create Quiet Bss Timer")); + return false; + } + + if (wlan_cfg_get_int(pMac, WNI_CFG_JOIN_FAILURE_TIMEOUT, + &cfgValue) != eSIR_SUCCESS) + lim_log(pMac, LOGP, + FL("could not retrieve JoinFailureTimeout value")); + cfgValue = SYS_MS_TO_TICKS(cfgValue); + /* Create Join failure timer and activate it later */ + if (tx_timer_create(pMac, &pMac->lim.limTimers.gLimJoinFailureTimer, + "JOIN FAILURE TIMEOUT", + lim_timer_handler, SIR_LIM_JOIN_FAIL_TIMEOUT, + cfgValue, 0, + TX_NO_ACTIVATE) != TX_SUCCESS) { + /* / Could not create Join failure timer. */ + /* Log error */ + lim_log(pMac, LOGP, + FL("could not create Join failure timer")); + return false; + } + /* Send unicast probe req frame every 200 ms */ + if (tx_timer_create(pMac, + &pMac->lim.limTimers.gLimPeriodicJoinProbeReqTimer, + "Periodic Join Probe Request Timer", + lim_timer_handler, + SIR_LIM_PERIODIC_JOIN_PROBE_REQ_TIMEOUT, + SYS_MS_TO_TICKS(LIM_JOIN_PROBE_REQ_TIMER_MS), 0, + TX_NO_ACTIVATE) != TX_SUCCESS) { + lim_log(pMac, LOGP, + FL("could not create Periodic Join Probe Request tmr")); + return false; + } + + /* Send Auth frame every 60 ms */ + if ((tx_timer_create(pMac, + &pMac->lim.limTimers.g_lim_periodic_auth_retry_timer, + "Periodic AUTH Timer", + lim_timer_handler, SIR_LIM_AUTH_RETRY_TIMEOUT, + SYS_MS_TO_TICKS(LIM_AUTH_RETRY_TIMER_MS), 0, + TX_NO_ACTIVATE)) != TX_SUCCESS) { + lim_log(pMac, LOGP, + FL("could not create Periodic AUTH Timer")); + return false; + } + + if (wlan_cfg_get_int(pMac, WNI_CFG_ASSOCIATION_FAILURE_TIMEOUT, + &cfgValue) != eSIR_SUCCESS) + lim_log(pMac, LOGP, + FL("could not retrieve AssocFailureTimeout value")); + + cfgValue = SYS_MS_TO_TICKS(cfgValue); + /* Create Association failure timer and activate it later */ + if (tx_timer_create(pMac, &pMac->lim.limTimers.gLimAssocFailureTimer, + "ASSOC FAILURE TIMEOUT", + lim_assoc_failure_timer_handler, LIM_ASSOC, + cfgValue, 0, TX_NO_ACTIVATE) != TX_SUCCESS) { + lim_log(pMac, LOGP, + FL("could not create Association failure timer")); + return false; + } + + if (wlan_cfg_get_int(pMac, WNI_CFG_ADDTS_RSP_TIMEOUT, &cfgValue) + != eSIR_SUCCESS) + lim_log(pMac, LOGP, + FL("Fail to get WNI_CFG_ADDTS_RSP_TIMEOUT ")); + + cfgValue = SYS_MS_TO_TICKS(cfgValue); + + /* Create Addts response timer and activate it later */ + if (tx_timer_create(pMac, &pMac->lim.limTimers.gLimAddtsRspTimer, + "ADDTS RSP TIMEOUT", + lim_addts_response_timer_handler, + SIR_LIM_ADDTS_RSP_TIMEOUT, + cfgValue, 0, TX_NO_ACTIVATE) != TX_SUCCESS) { + lim_log(pMac, LOGP, + FL("could not create Addts response timer")); + return false; + } + + if (wlan_cfg_get_int(pMac, WNI_CFG_AUTHENTICATE_FAILURE_TIMEOUT, + &cfgValue) != eSIR_SUCCESS) + lim_log(pMac, LOGP, + FL("could not retrieve AuthFailureTimeout value")); + + cfgValue = SYS_MS_TO_TICKS(cfgValue); + /* Create Auth failure timer and activate it later */ + if (tx_timer_create(pMac, &pMac->lim.limTimers.gLimAuthFailureTimer, + "AUTH FAILURE TIMEOUT", + lim_timer_handler, + SIR_LIM_AUTH_FAIL_TIMEOUT, + cfgValue, 0, TX_NO_ACTIVATE) != TX_SUCCESS) { + lim_log(pMac, LOGP, FL("could not create Auth failure timer")); + return false; + } + + if (wlan_cfg_get_int(pMac, WNI_CFG_PROBE_AFTER_HB_FAIL_TIMEOUT, + &cfgValue) != eSIR_SUCCESS) + lim_log(pMac, LOGP, + FL("could not retrieve PROBE_AFTER_HB_FAIL_TIMEOUT value")); + + /* Change timer to reactivate it in future */ + cfgValue = SYS_MS_TO_TICKS(cfgValue); + if (tx_timer_create(pMac, &pMac->lim.limTimers.gLimProbeAfterHBTimer, + "Probe after Heartbeat TIMEOUT", + lim_timer_handler, + SIR_LIM_PROBE_HB_FAILURE_TIMEOUT, + cfgValue, 0, TX_NO_ACTIVATE) != TX_SUCCESS) { + lim_log(pMac, LOGP, FL("unable to create ProbeAfterHBTimer")); + return false; + } + + return true; +} +/** + * lim_create_timers() + * + * @pMac : Pointer to Global MAC structure + * + * This function is called upon receiving + * 1. SME_START_REQ for STA in ESS role + * 2. SME_START_BSS_REQ for AP role & STA in IBSS role + * + * @return : status of operation + */ + +uint32_t lim_create_timers(tpAniSirGlobal pMac) +{ + uint32_t cfgValue, i = 0; + uint32_t cfgValue1; + + lim_log(pMac, LOG1, + FL("Creating Timers used by LIM module in Role %d"), + pMac->lim.gLimSystemRole); + /* Create timers required for host roaming feature */ + if (TX_SUCCESS != lim_create_timers_host_roam(pMac)) + return TX_TIMER_ERROR; + + if (wlan_cfg_get_int(pMac, WNI_CFG_ACTIVE_MINIMUM_CHANNEL_TIME, + &cfgValue) != eSIR_SUCCESS) { + lim_log(pMac, LOGP, + FL("could not retrieve MinChannelTimeout value")); + } + cfgValue = SYS_MS_TO_TICKS(cfgValue); + /* Periodic probe request timer value is half of the Min channel + * timer. Probe request sends periodically till min/max channel + * timer expires + */ + cfgValue1 = cfgValue / 2; + /* Create periodic probe request timer and activate them later */ + if (cfgValue1 >= 1 + && (tx_timer_create(pMac, + &pMac->lim.limTimers.gLimPeriodicProbeReqTimer, + "Periodic Probe Request Timer", lim_timer_handler, + SIR_LIM_PERIODIC_PROBE_REQ_TIMEOUT, cfgValue1, 0, + TX_NO_ACTIVATE) != TX_SUCCESS)) { + lim_log(pMac, LOGP, + FL("could not create periodic probe timer")); + goto err_timer; + } + + if (wlan_cfg_get_int(pMac, WNI_CFG_ACTIVE_MAXIMUM_CHANNEL_TIME, + &cfgValue) != eSIR_SUCCESS) + lim_log(pMac, LOGP, + FL("could not retrieve MAXChannelTimeout value")); + + cfgValue = SYS_MS_TO_TICKS(cfgValue); + /* Limiting max numm of probe req for each channel scan */ + pMac->lim.maxProbe = (cfgValue / cfgValue1); + + if (pMac->lim.gLimSystemRole != eLIM_AP_ROLE) + if (false == lim_create_non_ap_timers(pMac)) + goto err_timer; + + /* Create all CNF_WAIT Timers upfront */ + if (wlan_cfg_get_int(pMac, WNI_CFG_WT_CNF_TIMEOUT, &cfgValue) + != eSIR_SUCCESS) { + lim_log(pMac, LOGP, FL("could not retrieve CNF timeout value")); + } + + cfgValue = SYS_MS_TO_TICKS(cfgValue); + for (i = 0; i < (pMac->lim.maxStation + 1); i++) { + if (tx_timer_create(pMac, + &pMac->lim.limTimers.gpLimCnfWaitTimer[i], + "CNF_MISS_TIMEOUT", + lim_cnf_wait_tmer_handler, + (uint32_t) i, cfgValue, + 0, TX_NO_ACTIVATE) != TX_SUCCESS) { + lim_log(pMac, LOGP, FL("Cannot create CNF wait timer")); + goto err_timer; + } + } + + /* Alloc and init table for the preAuth timer list */ + if (wlan_cfg_get_int(pMac, WNI_CFG_MAX_NUM_PRE_AUTH, + &cfgValue) != eSIR_SUCCESS) + lim_log(pMac, LOGP, FL("could not retrieve mac preauth value")); + pMac->lim.gLimPreAuthTimerTable.numEntry = cfgValue; + pMac->lim.gLimPreAuthTimerTable.pTable = + qdf_mem_malloc(cfgValue * sizeof(tLimPreAuthNode *)); + + if (pMac->lim.gLimPreAuthTimerTable.pTable == NULL) { + lim_log(pMac, LOGP, FL("AllocateMemory failed!")); + goto err_timer; + } + + for (i = 0; i < cfgValue; i++) { + pMac->lim.gLimPreAuthTimerTable.pTable[i] = + qdf_mem_malloc(sizeof(tLimPreAuthNode)); + if (pMac->lim.gLimPreAuthTimerTable.pTable[i] == NULL) { + pMac->lim.gLimPreAuthTimerTable.numEntry = 0; + lim_log(pMac, LOGP, FL("AllocateMemory failed!")); + goto err_timer; + } + } + + lim_init_pre_auth_timer_table(pMac, &pMac->lim.gLimPreAuthTimerTable); + PELOG1(lim_log(pMac, LOG1, + FL("alloc and init table for preAuth timers"));) + + if (wlan_cfg_get_int(pMac, WNI_CFG_OLBC_DETECT_TIMEOUT, + &cfgValue) != eSIR_SUCCESS) + lim_log(pMac, LOGP, + FL("could not retrieve OLBD detect timeout value")); + + cfgValue = SYS_MS_TO_TICKS(cfgValue); + if (tx_timer_create(pMac, &pMac->lim.limTimers.gLimUpdateOlbcCacheTimer, + "OLBC UPDATE CACHE TIMEOUT", + lim_update_olbc_cache_timer_handler, + SIR_LIM_UPDATE_OLBC_CACHEL_TIMEOUT, cfgValue, + cfgValue, TX_NO_ACTIVATE) != TX_SUCCESS) { + lim_log(pMac, LOGP, FL("Cannot create update OLBC cache tmr")); + goto err_timer; + } + cfgValue = 1000; + cfgValue = SYS_MS_TO_TICKS(cfgValue); + if (tx_timer_create(pMac, &pMac->lim.limTimers.gLimRemainOnChannelTimer, + "FT PREAUTH RSP TIMEOUT", + lim_timer_handler, SIR_LIM_REMAIN_CHN_TIMEOUT, + cfgValue, 0, TX_NO_ACTIVATE) != TX_SUCCESS) { + lim_log(pMac, LOGP, FL("could not create Join failure timer")); + goto err_timer; + } + + cfgValue = 1000; + cfgValue = SYS_MS_TO_TICKS(cfgValue); + if (tx_timer_create(pMac, &pMac->lim.limTimers.gLimDisassocAckTimer, + "DISASSOC ACK TIMEOUT", + lim_timer_handler, SIR_LIM_DISASSOC_ACK_TIMEOUT, + cfgValue, 0, TX_NO_ACTIVATE) != TX_SUCCESS) { + lim_log(pMac, LOGP, FL("could not DISASSOC ACK TIMEOUT timer")); + goto err_timer; + } + + cfgValue = 1000; + cfgValue = SYS_MS_TO_TICKS(cfgValue); + if (tx_timer_create(pMac, &pMac->lim.limTimers.gLimDeauthAckTimer, + "DISASSOC ACK TIMEOUT", + lim_timer_handler, SIR_LIM_DEAUTH_ACK_TIMEOUT, + cfgValue, 0, TX_NO_ACTIVATE) != TX_SUCCESS) { + lim_log(pMac, LOGP, + FL("could not create DEAUTH ACK TIMEOUT timer")); + goto err_timer; + } + + /* (> no of BI* no of TUs per BI * 1TU in msec + + * p2p start time offset*1 TU in msec = 2*100*1.024 + 5*1.024 + * = 204.8 + 5.12 = 209.20) + */ + cfgValue = LIM_INSERT_SINGLESHOTNOA_TIMEOUT_VALUE; + cfgValue = SYS_MS_TO_TICKS(cfgValue); + if (tx_timer_create(pMac, + &pMac->lim.limTimers.gLimP2pSingleShotNoaInsertTimer, + "Single Shot NOA Insert timeout", lim_timer_handler, + SIR_LIM_INSERT_SINGLESHOT_NOA_TIMEOUT, cfgValue, 0, + TX_NO_ACTIVATE) != TX_SUCCESS) { + lim_log(pMac, LOGP, + FL("Can't create Single Shot NOA Insert Timeout tmr")); + goto err_timer; + } + + cfgValue = ACTIVE_TO_PASSIVE_CONVERISON_TIMEOUT; + cfgValue = SYS_MS_TO_TICKS(cfgValue); + if (tx_timer_create(pMac, + &pMac->lim.limTimers.gLimActiveToPassiveChannelTimer, + "ACTIVE TO PASSIVE CHANNEL", lim_timer_handler, + SIR_LIM_CONVERT_ACTIVE_CHANNEL_TO_PASSIVE, cfgValue, 0, + TX_NO_ACTIVATE) != TX_SUCCESS) { + lim_log(pMac, LOGW, + FL("could not create timer for passive channel to active channel")); + goto err_timer; + } + + return TX_SUCCESS; + +err_timer: + tx_timer_delete(&pMac->lim.limTimers.gLimDeauthAckTimer); + tx_timer_delete(&pMac->lim.limTimers.gLimDisassocAckTimer); + tx_timer_delete(&pMac->lim.limTimers.gLimRemainOnChannelTimer); + tx_timer_delete(&pMac->lim.limTimers.gLimFTPreAuthRspTimer); + tx_timer_delete(&pMac->lim.limTimers.gLimUpdateOlbcCacheTimer); + while (((int32_t)-- i) >= 0) { + tx_timer_delete(&pMac->lim.limTimers.gpLimCnfWaitTimer[i]); + } + tx_timer_delete(&pMac->lim.limTimers.gLimProbeAfterHBTimer); + tx_timer_delete(&pMac->lim.limTimers.gLimAuthFailureTimer); + tx_timer_delete(&pMac->lim.limTimers.gLimAddtsRspTimer); + tx_timer_delete(&pMac->lim.limTimers.gLimReassocFailureTimer); + tx_timer_delete(&pMac->lim.limTimers.gLimAssocFailureTimer); + tx_timer_delete(&pMac->lim.limTimers.gLimJoinFailureTimer); + tx_timer_delete(&pMac->lim.limTimers.gLimPeriodicJoinProbeReqTimer); + tx_timer_delete(&pMac->lim.limTimers.g_lim_periodic_auth_retry_timer); + tx_timer_delete(&pMac->lim.limTimers.gLimQuietBssTimer); + tx_timer_delete(&pMac->lim.limTimers.gLimQuietTimer); + tx_timer_delete(&pMac->lim.limTimers.gLimChannelSwitchTimer); + tx_timer_delete(&pMac->lim.limTimers.gLimPeriodicProbeReqTimer); + tx_timer_delete(&pMac->lim.limTimers.gLimP2pSingleShotNoaInsertTimer); + tx_timer_delete(&pMac->lim.limTimers.gLimActiveToPassiveChannelTimer); + + if (NULL != pMac->lim.gLimPreAuthTimerTable.pTable) { + for (i = 0; i < pMac->lim.gLimPreAuthTimerTable.numEntry; i++) + qdf_mem_free(pMac->lim.gLimPreAuthTimerTable.pTable[i]); + qdf_mem_free(pMac->lim.gLimPreAuthTimerTable.pTable); + pMac->lim.gLimPreAuthTimerTable.pTable = NULL; + } + return TX_TIMER_ERROR; +} /****** end lim_create_timers() ******/ + +/** + * lim_timer_handler() + * + ***FUNCTION: + * This function is called upon + * 1. MIN_CHANNEL, MAX_CHANNEL timer expiration during scanning + * 2. JOIN_FAILURE timer expiration while joining a BSS + * 3. AUTH_FAILURE timer expiration while authenticating with a peer + * 4. Heartbeat timer expiration on STA + * 5. Background scan timer expiration on STA + * 6. AID release, Pre-auth cleanup and Link monitoring timer + * expiration on AP + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param param - Message corresponding to the timer that expired + * + * @return None + */ + +void lim_timer_handler(void *pMacGlobal, uint32_t param) +{ + uint32_t statusCode; + tSirMsgQ msg; + tpAniSirGlobal pMac = (tpAniSirGlobal) pMacGlobal; + + /* Prepare and post message to LIM Message Queue */ + + msg.type = (uint16_t) param; + msg.bodyptr = NULL; + msg.bodyval = 0; + + statusCode = lim_post_msg_high_priority(pMac, &msg); + if (statusCode != eSIR_SUCCESS) + lim_log(pMac, LOGE, + FL("posting message %X to LIM failed, reason=%d"), + msg.type, statusCode); +} /****** end lim_timer_handler() ******/ + +/** + * lim_addts_response_timer_handler() + * + ***FUNCTION: + * This function is called upon Addts response timer expiration on sta + * + ***LOGIC: + * Message SIR_LIM_ADDTS_RSP_TIMEOUT is posted to gSirLimMsgQ + * when this function is executed. + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param param - pointer to pre-auth node + * + * @return None + */ + +void lim_addts_response_timer_handler(void *pMacGlobal, uint32_t param) +{ + tSirMsgQ msg; + tpAniSirGlobal pMac = (tpAniSirGlobal) pMacGlobal; + + /* Prepare and post message to LIM Message Queue */ + + msg.type = SIR_LIM_ADDTS_RSP_TIMEOUT; + msg.bodyval = param; + msg.bodyptr = NULL; + + lim_post_msg_api(pMac, &msg); +} /****** end lim_auth_response_timer_handler() ******/ + +/** + * lim_auth_response_timer_handler() + * + ***FUNCTION: + * This function is called upon Auth response timer expiration on AP + * + ***LOGIC: + * Message SIR_LIM_AUTH_RSP_TIMEOUT is posted to gSirLimMsgQ + * when this function is executed. + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param param - pointer to pre-auth node + * + * @return None + */ + +void lim_auth_response_timer_handler(void *pMacGlobal, uint32_t param) +{ + tSirMsgQ msg; + tpAniSirGlobal pMac = (tpAniSirGlobal) pMacGlobal; + + /* Prepare and post message to LIM Message Queue */ + + msg.type = SIR_LIM_AUTH_RSP_TIMEOUT; + msg.bodyptr = NULL; + msg.bodyval = (uint32_t) param; + + lim_post_msg_api(pMac, &msg); +} /****** end lim_auth_response_timer_handler() ******/ + +/** + * lim_assoc_failure_timer_handler() + * + * @mac_global : Pointer to Global MAC structure + * @param : Indicates whether this is assoc or reassoc failure timeout + * + * This function is called upon Re/Assoc failure timer expiration on STA. + * Message SIR_LIM_ASSOC_FAIL_TIMEOUT is posted to gSirLimMsgQ when this + * function is executed. + * + * Return void + */ +void lim_assoc_failure_timer_handler(void *mac_global, uint32_t param) +{ + tSirMsgQ msg; + tpAniSirGlobal mac_ctx = (tpAniSirGlobal) mac_global; + tpPESession session = NULL; + + session = mac_ctx->lim.pSessionEntry; + if (LIM_REASSOC == param && NULL != session + && session->limMlmState == eLIM_MLM_WT_FT_REASSOC_RSP_STATE) { + lim_log(mac_ctx, LOGE, FL("Reassoc timeout happened")); + if (mac_ctx->lim.reAssocRetryAttempt < + LIM_MAX_REASSOC_RETRY_LIMIT) { + lim_send_retry_reassoc_req_frame(mac_ctx, + session->pLimMlmReassocRetryReq, session); + mac_ctx->lim.reAssocRetryAttempt++; + lim_log(mac_ctx, LOGW, + FL("Reassoc request retry is sent %d times"), + mac_ctx->lim.reAssocRetryAttempt); + return; + } else { + lim_log(mac_ctx, LOGW, + FL("Reassoc request retry MAX(%d) reached"), + LIM_MAX_REASSOC_RETRY_LIMIT); + if (NULL != session->pLimMlmReassocRetryReq) { + qdf_mem_free(session->pLimMlmReassocRetryReq); + session->pLimMlmReassocRetryReq = NULL; + } + } + } + /* Prepare and post message to LIM Message Queue */ + msg.type = SIR_LIM_ASSOC_FAIL_TIMEOUT; + msg.bodyval = (uint32_t) param; + msg.bodyptr = NULL; + lim_post_msg_api(mac_ctx, &msg); +} /****** end lim_assoc_failure_timer_handler() ******/ + +/** + * lim_update_olbc_cache_timer_handler() + * + ***FUNCTION: + * This function is called upon update olbc cache timer expiration + * on STA + * + ***LOGIC: + * Message SIR_LIM_UPDATE_OLBC_CACHEL_TIMEOUT is posted to gSirLimMsgQ + * when this function is executed. + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param + * + * @return None + */ +void lim_update_olbc_cache_timer_handler(void *pMacGlobal, uint32_t param) +{ + tSirMsgQ msg; + tpAniSirGlobal pMac = (tpAniSirGlobal) pMacGlobal; + + /* Prepare and post message to LIM Message Queue */ + + msg.type = SIR_LIM_UPDATE_OLBC_CACHEL_TIMEOUT; + msg.bodyval = 0; + msg.bodyptr = NULL; + + lim_post_msg_api(pMac, &msg); +} /****** end lim_update_olbc_cache_timer_handler() ******/ + +/** + * lim_deactivate_and_change_timer() + * + ***FUNCTION: + * This function is called to deactivate and change a timer + * for future re-activation + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param pMac - Pointer to Global MAC structure + * @param timerId - enum of timer to be deactivated and changed + * This enum is defined in lim_utils.h file + * + * @return None + */ + +void lim_deactivate_and_change_timer(tpAniSirGlobal pMac, uint32_t timerId) +{ + uint32_t val = 0; + tpPESession session_entry; + + switch (timerId) { + case eLIM_REASSOC_FAIL_TIMER: + case eLIM_FT_PREAUTH_RSP_TIMER: + lim_deactivate_and_change_timer_host_roam(pMac, timerId); + break; + + case eLIM_ADDTS_RSP_TIMER: + pMac->lim.gLimAddtsRspTimerCount++; + if (tx_timer_deactivate(&pMac->lim.limTimers.gLimAddtsRspTimer) + != TX_SUCCESS) { + /* Could not deactivate AddtsRsp Timer */ + /* Log error */ + lim_log(pMac, LOGP, + FL("Unable to deactivate AddtsRsp timer")); + } + break; + + case eLIM_PERIODIC_PROBE_REQ_TIMER: + if (tx_timer_deactivate + (&pMac->lim.limTimers.gLimPeriodicProbeReqTimer) + != TX_SUCCESS) { + /* Could not deactivate min channel timer. */ + /* Log error */ + lim_log(pMac, LOGP, + FL("Unable to deactivate periodic timer")); + } + + val = + SYS_MS_TO_TICKS(pMac->lim.gpLimMlmScanReq->minChannelTime) / + 2; + if (val) { + if (tx_timer_change( + &pMac->lim.limTimers.gLimPeriodicProbeReqTimer, + val, 0) != TX_SUCCESS) { + /* Could not change min channel timer. */ + /* Log error */ + lim_log(pMac, LOGP, + FL("Unable to change periodic timer")); + } + } else + lim_log(pMac, LOGE, + FL("Do not change gLimPeriodicProbeReqTimer values," + "value = %d minchannel time = %d" + "maxchannel time = %d"), val, + pMac->lim.gpLimMlmScanReq->minChannelTime, + pMac->lim.gpLimMlmScanReq->maxChannelTime); + + break; + + case eLIM_JOIN_FAIL_TIMER: + if (tx_timer_deactivate + (&pMac->lim.limTimers.gLimJoinFailureTimer) + != TX_SUCCESS) { + /** + * Could not deactivate Join Failure + * timer. Log error. + */ + lim_log(pMac, LOGP, + FL("Unable to deactivate Join Failure timer")); + } + + if (wlan_cfg_get_int(pMac, WNI_CFG_JOIN_FAILURE_TIMEOUT, + &val) != eSIR_SUCCESS) { + /** + * Could not get JoinFailureTimeout value + * from CFG. Log error. + */ + lim_log(pMac, LOGP, + FL + ("could not retrieve JoinFailureTimeout value")); + } + val = SYS_MS_TO_TICKS(val); + + if (tx_timer_change(&pMac->lim.limTimers.gLimJoinFailureTimer, + val, 0) != TX_SUCCESS) { + /** + * Could not change Join Failure + * timer. Log error. + */ + lim_log(pMac, LOGP, + FL("Unable to change Join Failure timer")); + } + + break; + + case eLIM_PERIODIC_JOIN_PROBE_REQ_TIMER: + if (tx_timer_deactivate + (&pMac->lim.limTimers.gLimPeriodicJoinProbeReqTimer) + != TX_SUCCESS) { + /* Could not deactivate periodic join req Times. */ + lim_log(pMac, LOGP, + FL + ("Unable to deactivate periodic join request timer")); + } + + val = SYS_MS_TO_TICKS(LIM_JOIN_PROBE_REQ_TIMER_MS); + if (tx_timer_change + (&pMac->lim.limTimers.gLimPeriodicJoinProbeReqTimer, val, + 0) != TX_SUCCESS) { + /* Could not change periodic join req times. */ + /* Log error */ + lim_log(pMac, LOGP, + FL + ("Unable to change periodic join request timer")); + } + + break; + + case eLIM_AUTH_FAIL_TIMER: + if (tx_timer_deactivate + (&pMac->lim.limTimers.gLimAuthFailureTimer) + != TX_SUCCESS) { + /* Could not deactivate Auth failure timer. */ + /* Log error */ + lim_log(pMac, LOGP, + FL("Unable to deactivate auth failure timer")); + } + /* Change timer to reactivate it in future */ + if (wlan_cfg_get_int(pMac, WNI_CFG_AUTHENTICATE_FAILURE_TIMEOUT, + &val) != eSIR_SUCCESS) { + /** + * Could not get AuthFailureTimeout value + * from CFG. Log error. + */ + lim_log(pMac, LOGP, + FL + ("could not retrieve AuthFailureTimeout value")); + } + val = SYS_MS_TO_TICKS(val); + + if (tx_timer_change(&pMac->lim.limTimers.gLimAuthFailureTimer, + val, 0) != TX_SUCCESS) { + /* Could not change Authentication failure timer. */ + /* Log error */ + lim_log(pMac, LOGP, + FL("unable to change Auth failure timer")); + } + + break; + + case eLIM_AUTH_RETRY_TIMER: + + if (tx_timer_deactivate + (&pMac->lim.limTimers.g_lim_periodic_auth_retry_timer) + != TX_SUCCESS) { + /* Could not deactivate Auth Retry Timer. */ + lim_log(pMac, LOGE, + FL("Unable to deactivate Auth Retry timer")); + } + session_entry = pe_find_session_by_session_id(pMac, + pMac->lim.limTimers. + g_lim_periodic_auth_retry_timer.sessionId); + if (NULL == session_entry) { + lim_log(pMac, LOGE, + FL("session does not exist for given SessionId : %d"), + pMac->lim.limTimers. + g_lim_periodic_auth_retry_timer.sessionId); + break; + } + /* 3/5 of the beacon interval */ + val = (session_entry->beaconParams.beaconInterval * 3) / 5; + val = SYS_MS_TO_TICKS(val); + if (tx_timer_change + (&pMac->lim.limTimers.g_lim_periodic_auth_retry_timer, + val, 0) != TX_SUCCESS) { + /* Could not change Auth Retry timer. */ + lim_log(pMac, LOGE, + FL("Unable to change Auth Retry timer")); + } + break; + + case eLIM_ASSOC_FAIL_TIMER: + if (tx_timer_deactivate + (&pMac->lim.limTimers.gLimAssocFailureTimer) != + TX_SUCCESS) { + /* Could not deactivate Association failure timer. */ + /* Log error */ + lim_log(pMac, LOGP, + FL + ("unable to deactivate Association failure timer")); + } + /* Change timer to reactivate it in future */ + if (wlan_cfg_get_int(pMac, WNI_CFG_ASSOCIATION_FAILURE_TIMEOUT, + &val) != eSIR_SUCCESS) { + /** + * Could not get AssocFailureTimeout value + * from CFG. Log error. + */ + lim_log(pMac, LOGP, + FL + ("could not retrieve AssocFailureTimeout value")); + } + val = SYS_MS_TO_TICKS(val); + + if (tx_timer_change(&pMac->lim.limTimers.gLimAssocFailureTimer, + val, 0) != TX_SUCCESS) { + /* Could not change Association failure timer. */ + /* Log error */ + lim_log(pMac, LOGP, + FL("unable to change Assoc failure timer")); + } + + break; + + case eLIM_PROBE_AFTER_HB_TIMER: + if (tx_timer_deactivate + (&pMac->lim.limTimers.gLimProbeAfterHBTimer) != + TX_SUCCESS) { + /* Could not deactivate Heartbeat timer. */ + /* Log error */ + lim_log(pMac, LOGP, + FL("unable to deactivate probeAfterHBTimer")); + } else { + lim_log(pMac, LOG1, + FL("Deactivated probe after hb timer")); + } + + if (wlan_cfg_get_int(pMac, WNI_CFG_PROBE_AFTER_HB_FAIL_TIMEOUT, + &val) != eSIR_SUCCESS) { + /** + * Could not get PROBE_AFTER_HB_FAILURE + * value from CFG. Log error. + */ + lim_log(pMac, LOGP, + FL + ("could not retrieve PROBE_AFTER_HB_FAIL_TIMEOUT value")); + } + /* Change timer to reactivate it in future */ + val = SYS_MS_TO_TICKS(val); + + if (tx_timer_change(&pMac->lim.limTimers.gLimProbeAfterHBTimer, + val, 0) != TX_SUCCESS) { + /* Could not change HeartBeat timer. */ + /* Log error */ + lim_log(pMac, LOGP, + FL("unable to change ProbeAfterHBTimer")); + } else { + lim_log(pMac, LOGW, + FL("Probe after HB timer value is changed = %u"), + val); + } + + break; + + case eLIM_LEARN_DURATION_TIMER: + break; + + case eLIM_REMAIN_CHN_TIMER: + if (tx_timer_deactivate + (&pMac->lim.limTimers.gLimRemainOnChannelTimer) != + TX_SUCCESS) { + /** + ** Could not deactivate Join Failure + ** timer. Log error. + **/ + lim_log(pMac, LOGP, + FL("Unable to deactivate Remain on Chn timer")); + return; + } + val = 1000; + val = SYS_MS_TO_TICKS(val); + if (tx_timer_change + (&pMac->lim.limTimers.gLimRemainOnChannelTimer, val, + 0) != TX_SUCCESS) { + /** + * Could not change Join Failure + * timer. Log error. + */ + lim_log(pMac, LOGP, FL("Unable to change timer")); + return; + } + break; + + case eLIM_CONVERT_ACTIVE_CHANNEL_TO_PASSIVE: + if (tx_timer_deactivate + (&pMac->lim.limTimers.gLimActiveToPassiveChannelTimer) != + TX_SUCCESS) { + /** + ** Could not deactivate Active to passive channel timer. + ** Log error. + **/ + lim_log(pMac, LOGP, FL("Unable to Deactivate " + "Active to passive channel timer")); + return; + } + val = ACTIVE_TO_PASSIVE_CONVERISON_TIMEOUT; + val = SYS_MS_TO_TICKS(val); + if (tx_timer_change + (&pMac->lim.limTimers.gLimActiveToPassiveChannelTimer, val, + 0) != TX_SUCCESS) { + /** + * Could not change timer to check scan type for passive channel. + * timer. Log error. + */ + lim_log(pMac, LOGP, FL("Unable to change timer")); + return; + } + break; + + case eLIM_DISASSOC_ACK_TIMER: + if (tx_timer_deactivate + (&pMac->lim.limTimers.gLimDisassocAckTimer) != TX_SUCCESS) { + /** + ** Could not deactivate Join Failure + ** timer. Log error. + **/ + lim_log(pMac, LOGP, + FL("Unable to deactivate Disassoc ack timer")); + return; + } + val = 1000; + val = SYS_MS_TO_TICKS(val); + if (tx_timer_change(&pMac->lim.limTimers.gLimDisassocAckTimer, + val, 0) != TX_SUCCESS) { + /** + * Could not change Join Failure + * timer. Log error. + */ + lim_log(pMac, LOGP, FL("Unable to change timer")); + return; + } + break; + + case eLIM_DEAUTH_ACK_TIMER: + if (tx_timer_deactivate(&pMac->lim.limTimers.gLimDeauthAckTimer) + != TX_SUCCESS) { + /** + ** Could not deactivate Join Failure + ** timer. Log error. + **/ + lim_log(pMac, LOGP, + FL("Unable to deactivate Deauth ack timer")); + return; + } + val = 1000; + val = SYS_MS_TO_TICKS(val); + if (tx_timer_change(&pMac->lim.limTimers.gLimDeauthAckTimer, + val, 0) != TX_SUCCESS) { + /** + * Could not change Join Failure + * timer. Log error. + */ + lim_log(pMac, LOGP, FL("Unable to change timer")); + return; + } + break; + + case eLIM_INSERT_SINGLESHOT_NOA_TIMER: + if (tx_timer_deactivate + (&pMac->lim.limTimers.gLimP2pSingleShotNoaInsertTimer) != + TX_SUCCESS) { + /** + ** Could not deactivate SingleShot NOA Insert + ** timer. Log error. + **/ + lim_log(pMac, LOGP, + FL + ("Unable to deactivate SingleShot NOA Insert timer")); + return; + } + val = LIM_INSERT_SINGLESHOTNOA_TIMEOUT_VALUE; + val = SYS_MS_TO_TICKS(val); + if (tx_timer_change + (&pMac->lim.limTimers.gLimP2pSingleShotNoaInsertTimer, val, + 0) != TX_SUCCESS) { + /** + * Could not change Single Shot NOA Insert + * timer. Log error. + */ + lim_log(pMac, LOGP, FL("Unable to change timer")); + return; + } + break; + + default: + /* Invalid timerId. Log error */ + break; + } +} /****** end lim_deactivate_and_change_timer() ******/ + +/** + * lim_deactivate_and_change_per_sta_id_timer() + * + * + * @brief: This function is called to deactivate and change a per STA timer + * for future re-activation + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + * @note staId for eLIM_AUTH_RSP_TIMER is auth Node Index. + * + * @param pMac - Pointer to Global MAC structure + * @param timerId - enum of timer to be deactivated and changed + * This enum is defined in lim_utils.h file + * @param staId - staId + * + * @return None + */ + +void +lim_deactivate_and_change_per_sta_id_timer(tpAniSirGlobal pMac, uint32_t timerId, + uint16_t staId) +{ + uint32_t val; + + switch (timerId) { + case eLIM_CNF_WAIT_TIMER: + + if (tx_timer_deactivate + (&pMac->lim.limTimers.gpLimCnfWaitTimer[staId]) + != TX_SUCCESS) { + lim_log(pMac, LOGP, + FL("unable to deactivate CNF wait timer")); + + } + /* Change timer to reactivate it in future */ + + if (wlan_cfg_get_int(pMac, WNI_CFG_WT_CNF_TIMEOUT, + &val) != eSIR_SUCCESS) { + /** + * Could not get cnf timeout value + * from CFG. Log error. + */ + lim_log(pMac, LOGP, + FL("could not retrieve cnf timeout value")); + } + val = SYS_MS_TO_TICKS(val); + + if (tx_timer_change + (&pMac->lim.limTimers.gpLimCnfWaitTimer[staId], val, + val) != TX_SUCCESS) { + /* Could not change cnf timer. */ + /* Log error */ + lim_log(pMac, LOGP, + FL("unable to change cnf wait timer")); + } + + break; + + case eLIM_AUTH_RSP_TIMER: + { + tLimPreAuthNode *pAuthNode; + + pAuthNode = + lim_get_pre_auth_node_from_index(pMac, + &pMac->lim. + gLimPreAuthTimerTable, + staId); + + if (pAuthNode == NULL) { + lim_log(pMac, LOGP, + FL("Invalid Pre Auth Index passed :%d"), + staId); + break; + } + + if (tx_timer_deactivate(&pAuthNode->timer) != + TX_SUCCESS) { + /* Could not deactivate auth response timer. */ + /* Log error */ + lim_log(pMac, LOGP, + FL + ("unable to deactivate auth response timer")); + } + /* Change timer to reactivate it in future */ + + if (wlan_cfg_get_int + (pMac, WNI_CFG_AUTHENTICATE_RSP_TIMEOUT, + &val) != eSIR_SUCCESS) { + /** + * Could not get auth rsp timeout value + * from CFG. Log error. + */ + lim_log(pMac, LOGP, + FL + ("could not retrieve auth response timeout value")); + } + + val = SYS_MS_TO_TICKS(val); + + if (tx_timer_change(&pAuthNode->timer, val, 0) != + TX_SUCCESS) { + /* Could not change auth rsp timer. */ + /* Log error */ + lim_log(pMac, LOGP, + FL("unable to change auth rsp timer")); + } + } + break; + + default: + /* Invalid timerId. Log error */ + break; + + } +} + +/** + * lim_activate_cnf_timer() + * + ***FUNCTION: + * This function is called to activate a per STA timer + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param pMac - Pointer to Global MAC structure + * @param StaId - staId + * + * @return None + */ + +void lim_activate_cnf_timer(tpAniSirGlobal pMac, uint16_t staId, + tpPESession psessionEntry) +{ + pMac->lim.limTimers.gpLimCnfWaitTimer[staId].sessionId = + psessionEntry->peSessionId; + if (tx_timer_activate(&pMac->lim.limTimers.gpLimCnfWaitTimer[staId]) + != TX_SUCCESS) { + lim_log(pMac, LOGP, FL("could not activate cnf wait timer")); + } +} + +/** + * lim_activate_auth_rsp_timer() + * + ***FUNCTION: + * This function is called to activate a per STA timer + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param pMac - Pointer to Global MAC structure + * @param id - id + * + * @return None + */ + +void lim_activate_auth_rsp_timer(tpAniSirGlobal pMac, tLimPreAuthNode *pAuthNode) +{ + if (tx_timer_activate(&pAuthNode->timer) != TX_SUCCESS) { + /* / Could not activate auth rsp timer. */ + /* Log error */ + lim_log(pMac, LOGP, FL("could not activate auth rsp timer")); + } +} + +/** + * limAssocCnfWaitTmerHandler() + * + ***FUNCTION: + * This function post a message to send a disassociate frame out. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * + ***NOTE: + * NA + * + * @param + * + * @return None + */ + +void lim_cnf_wait_tmer_handler(void *pMacGlobal, uint32_t param) +{ + tSirMsgQ msg; + uint32_t statusCode; + tpAniSirGlobal pMac = (tpAniSirGlobal) pMacGlobal; + + msg.type = SIR_LIM_CNF_WAIT_TIMEOUT; + msg.bodyval = (uint32_t) param; + msg.bodyptr = NULL; + + statusCode = lim_post_msg_api(pMac, &msg); + if (statusCode != eSIR_SUCCESS) + lim_log(pMac, LOGE, + FL("posting to LIM failed, reason=%d"), statusCode); + +} + +void lim_channel_switch_timer_handler(void *pMacGlobal, uint32_t param) +{ + tSirMsgQ msg; + tpAniSirGlobal pMac = (tpAniSirGlobal) pMacGlobal; + + PELOG1(lim_log(pMac, LOG1, + FL("ChannelSwitch Timer expired. Posting msg to LIM ")); + ) + + msg.type = SIR_LIM_CHANNEL_SWITCH_TIMEOUT; + msg.bodyval = (uint32_t) param; + msg.bodyptr = NULL; + + lim_post_msg_api(pMac, &msg); +} + +void lim_quiet_timer_handler(void *pMacGlobal, uint32_t param) +{ + tSirMsgQ msg; + tpAniSirGlobal pMac = (tpAniSirGlobal) pMacGlobal; + + msg.type = SIR_LIM_QUIET_TIMEOUT; + msg.bodyval = (uint32_t) param; + msg.bodyptr = NULL; + + PELOG1(lim_log(pMac, LOG1, FL("Post SIR_LIM_QUIET_TIMEOUT msg. "));) + lim_post_msg_api(pMac, &msg); +} + +void lim_quiet_bss_timer_handler(void *pMacGlobal, uint32_t param) +{ + tSirMsgQ msg; + tpAniSirGlobal pMac = (tpAniSirGlobal) pMacGlobal; + + msg.type = SIR_LIM_QUIET_BSS_TIMEOUT; + msg.bodyval = (uint32_t) param; + msg.bodyptr = NULL; + PELOG1(lim_log(pMac, LOG1, FL("Post SIR_LIM_QUIET_BSS_TIMEOUT msg. "));) + lim_post_msg_api(pMac, &msg); +} diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_timer_utils.h b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_timer_utils.h new file mode 100644 index 0000000000000000000000000000000000000000..c4fa1971144504ba69a454516815b50080949622 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_timer_utils.h @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2011-2014, 2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * + * This file lim_timer_utils.h contains the utility definitions + * LIM uses for timer handling. + * Author: Chandra Modumudi + * Date: 02/13/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + */ +#ifndef __LIM_TIMER_UTILS_H +#define __LIM_TIMER_UTILS_H + +#include "lim_types.h" + +/* Timer related functions */ +enum { + eLIM_MIN_CHANNEL_TIMER, + eLIM_MAX_CHANNEL_TIMER, + eLIM_JOIN_FAIL_TIMER, + eLIM_AUTH_FAIL_TIMER, + eLIM_AUTH_RESP_TIMER, + eLIM_ASSOC_FAIL_TIMER, + eLIM_REASSOC_FAIL_TIMER, + eLIM_PRE_AUTH_CLEANUP_TIMER, + eLIM_CNF_WAIT_TIMER, + eLIM_AUTH_RSP_TIMER, + eLIM_UPDATE_OLBC_CACHE_TIMER, + eLIM_PROBE_AFTER_HB_TIMER, + eLIM_ADDTS_RSP_TIMER, + eLIM_CHANNEL_SWITCH_TIMER, + eLIM_LEARN_DURATION_TIMER, + eLIM_QUIET_TIMER, + eLIM_QUIET_BSS_TIMER, + eLIM_WPS_OVERLAP_TIMER, + eLIM_FT_PREAUTH_RSP_TIMER, + eLIM_REMAIN_CHN_TIMER, + eLIM_PERIODIC_PROBE_REQ_TIMER, + eLIM_DISASSOC_ACK_TIMER, + eLIM_DEAUTH_ACK_TIMER, + eLIM_PERIODIC_JOIN_PROBE_REQ_TIMER, + eLIM_INSERT_SINGLESHOT_NOA_TIMER, + eLIM_CONVERT_ACTIVE_CHANNEL_TO_PASSIVE, + eLIM_AUTH_RETRY_TIMER +}; + +#define LIM_DISASSOC_DEAUTH_ACK_TIMEOUT 500 +#define LIM_INSERT_SINGLESHOTNOA_TIMEOUT_VALUE 500 + +/* Timer Handler functions */ +uint32_t lim_create_timers(tpAniSirGlobal); +void lim_timer_handler(void *, uint32_t); +void lim_auth_response_timer_handler(void *, uint32_t); +void lim_assoc_failure_timer_handler(void *, uint32_t); +void limReassocFailureTimerHandler(void *, uint32_t); + +void lim_deactivate_and_change_timer(tpAniSirGlobal, uint32_t); +void limDummyPktExpTimerHandler(void *, uint32_t); +void lim_cnf_wait_tmer_handler(void *, uint32_t); +void lim_deactivate_and_change_per_sta_id_timer(tpAniSirGlobal, uint32_t, uint16_t); +void lim_activate_cnf_timer(tpAniSirGlobal, uint16_t, tpPESession); +void lim_activate_auth_rsp_timer(tpAniSirGlobal, tLimPreAuthNode *); +void lim_update_olbc_cache_timer_handler(void *, uint32_t); +void lim_addts_response_timer_handler(void *, uint32_t); +void lim_channel_switch_timer_handler(void *, uint32_t); +void lim_quiet_timer_handler(void *, uint32_t); +void lim_quiet_bss_timer_handler(void *, uint32_t); +void limCBScanIntervalTimerHandler(void *, uint32_t); +void limCBScanDurationTimerHandler(void *, uint32_t); +#endif /* __LIM_TIMER_UTILS_H */ diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_trace.c b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_trace.c new file mode 100644 index 0000000000000000000000000000000000000000..3107a3ae4273892f19cfcd37e4e3cff37bde7fb0 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_trace.c @@ -0,0 +1,492 @@ +/* + * Copyright (c) 2013-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/**========================================================================= + + \file lim_trace.c + + \brief implementation for trace related APIs + + \author Sunit Bhatia + + ========================================================================*/ + +/*-------------------------------------------------------------------------- + Include Files + ------------------------------------------------------------------------*/ + +#include "ani_global.h" /* for tpAniSirGlobal */ + +#include "lim_trace.h" +#include "lim_timer_utils.h" +#include "qdf_trace.h" + +#ifdef LIM_TRACE_RECORD +uint32_t g_mgmt_frame_stats[14]; + +#define LIM_TRACE_MAX_SUBTYPES 14 + +static uint8_t *__lim_trace_get_timer_string(uint16_t timerId) +{ + switch (timerId) { + CASE_RETURN_STRING(eLIM_MIN_CHANNEL_TIMER); + CASE_RETURN_STRING(eLIM_MAX_CHANNEL_TIMER); + CASE_RETURN_STRING(eLIM_JOIN_FAIL_TIMER); + CASE_RETURN_STRING(eLIM_AUTH_FAIL_TIMER); + CASE_RETURN_STRING(eLIM_AUTH_RESP_TIMER); + CASE_RETURN_STRING(eLIM_ASSOC_FAIL_TIMER); + CASE_RETURN_STRING(eLIM_REASSOC_FAIL_TIMER); + CASE_RETURN_STRING(eLIM_PRE_AUTH_CLEANUP_TIMER); + CASE_RETURN_STRING(eLIM_CNF_WAIT_TIMER); + CASE_RETURN_STRING(eLIM_AUTH_RSP_TIMER); + CASE_RETURN_STRING(eLIM_UPDATE_OLBC_CACHE_TIMER); + CASE_RETURN_STRING(eLIM_PROBE_AFTER_HB_TIMER); + CASE_RETURN_STRING(eLIM_ADDTS_RSP_TIMER); + CASE_RETURN_STRING(eLIM_CHANNEL_SWITCH_TIMER); + CASE_RETURN_STRING(eLIM_LEARN_DURATION_TIMER); + CASE_RETURN_STRING(eLIM_QUIET_TIMER); + CASE_RETURN_STRING(eLIM_QUIET_BSS_TIMER); + CASE_RETURN_STRING(eLIM_WPS_OVERLAP_TIMER); + CASE_RETURN_STRING(eLIM_FT_PREAUTH_RSP_TIMER); + CASE_RETURN_STRING(eLIM_REMAIN_CHN_TIMER); + CASE_RETURN_STRING(eLIM_PERIODIC_PROBE_REQ_TIMER); + CASE_RETURN_STRING(eLIM_DISASSOC_ACK_TIMER); + CASE_RETURN_STRING(eLIM_DEAUTH_ACK_TIMER); + CASE_RETURN_STRING(eLIM_PERIODIC_JOIN_PROBE_REQ_TIMER); + CASE_RETURN_STRING(eLIM_INSERT_SINGLESHOT_NOA_TIMER); + CASE_RETURN_STRING(eLIM_CONVERT_ACTIVE_CHANNEL_TO_PASSIVE); + CASE_RETURN_STRING(eLIM_AUTH_RETRY_TIMER); + default: + return "UNKNOWN"; + break; + } +} + +static uint8_t *__lim_trace_get_mgmt_drop_reason_string(uint16_t dropReason) +{ + + switch (dropReason) { + CASE_RETURN_STRING(eMGMT_DROP_INFRA_BCN_IN_IBSS); + CASE_RETURN_STRING(eMGMT_DROP_INVALID_SIZE); + CASE_RETURN_STRING(eMGMT_DROP_NON_SCAN_MODE_FRAME); + CASE_RETURN_STRING(eMGMT_DROP_NOT_LAST_IBSS_BCN); + CASE_RETURN_STRING(eMGMT_DROP_NO_DROP); + CASE_RETURN_STRING(eMGMT_DROP_SCAN_MODE_FRAME); + CASE_RETURN_STRING(eMGMT_DROP_SPURIOUS_FRAME); + + default: + return "UNKNOWN"; + break; + } +} + +void lim_trace_init(tpAniSirGlobal pMac) +{ + qdf_trace_register(QDF_MODULE_ID_PE, (tp_qdf_trace_cb) &lim_trace_dump); +} + +void lim_trace_dump(tpAniSirGlobal pMac, tp_qdf_trace_record pRecord, + uint16_t recIndex) +{ + + static char *frameSubtypeStr[LIM_TRACE_MAX_SUBTYPES] = { + "Association request", + "Association response", + "Reassociation request", + "Reassociation response", + "Probe request", + "Probe response", + NULL, + NULL, + "Beacon", + "ATIM", + "Disassociation", + "Authentication", + "Deauthentication", + "Action" + }; + + switch (pRecord->code) { + case TRACE_CODE_MLM_STATE: + lim_log(pMac, LOG1, + "%04d %012llu %s S%d %-14s %-30s(0x%x)", recIndex, + pRecord->qtime, pRecord->time, pRecord->session, + "MLM State:", + lim_trace_get_mlm_state_string( + (uint16_t) pRecord->data), + pRecord->data); + break; + case TRACE_CODE_SME_STATE: + lim_log(pMac, LOG1, + "%04d %012llu %s S%d %-14s %-30s(0x%x)", recIndex, + pRecord->qtime, pRecord->time, pRecord->session, + "SME State:", + lim_trace_get_sme_state_string( + (uint16_t) pRecord->data), + pRecord->data); + break; + case TRACE_CODE_TX_MGMT: + lim_log(pMac, LOG1, + "%04d %012llu %s S%d %-14s %-30s(0x%x)", recIndex, + pRecord->qtime, pRecord->time, pRecord->session, + "TX Mgmt:", frameSubtypeStr[pRecord->data], + pRecord->data); + break; + + case TRACE_CODE_RX_MGMT: + if (LIM_TRACE_MAX_SUBTYPES <= + LIM_TRACE_GET_SUBTYPE(pRecord->data)) { + lim_log(pMac, LOG1, "Wrong Subtype - %d", + LIM_TRACE_GET_SUBTYPE(pRecord->data)); + } else { + lim_log(pMac, LOG1, + "%04d %012llu %s S%d %-14s %-30s(%d) SN: %d", + recIndex, pRecord->qtime, pRecord->time, + pRecord->session, "RX Mgmt:", + frameSubtypeStr[LIM_TRACE_GET_SUBTYPE + (pRecord->data)], + LIM_TRACE_GET_SUBTYPE(pRecord->data), + LIM_TRACE_GET_SSN(pRecord->data)); + } + break; + case TRACE_CODE_RX_MGMT_DROP: + lim_log(pMac, LOG1, "%04d %012llu %s S%d %-14s %-30s(%d)", + recIndex, pRecord->qtime, pRecord->time, + pRecord->session, "Drop RX Mgmt:", + __lim_trace_get_mgmt_drop_reason_string( + (uint16_t) pRecord->data), + pRecord->data); + break; + + case TRACE_CODE_RX_MGMT_TSF: + lim_log(pMac, LOG1, + "%04d %012llu %s S%d %-14s %-30s0x%x(%d)", + recIndex, pRecord->qtime, pRecord->time, + pRecord->session, "RX Mgmt TSF:", " ", + pRecord->data, pRecord->data); + break; + + case TRACE_CODE_TX_COMPLETE: + lim_log(pMac, LOG1, "%04d %012llu %s S%d %-14s %d", recIndex, + pRecord->qtime, pRecord->time, pRecord->session, + "TX Complete", pRecord->data); + break; + + case TRACE_CODE_TX_SME_MSG: + lim_log(pMac, LOG1, + "%04d %012llu %s S%d %-14s %-30s(0x%x)", recIndex, + pRecord->qtime, pRecord->time, pRecord->session, + "TX SME Msg:", + mac_trace_get_sme_msg_string((uint16_t) pRecord->data), + pRecord->data); + break; + case TRACE_CODE_RX_SME_MSG: + lim_log(pMac, LOG1, + "%04d %012llu %s S%d %-14s %-30s(0x%x)", recIndex, + pRecord->qtime, pRecord->time, pRecord->session, + LIM_TRACE_GET_DEFRD_OR_DROPPED( + pRecord->data) ? "Def/Drp LIM Msg:" : "RX Sme Msg:", + mac_trace_get_sme_msg_string((uint16_t) pRecord->data), + pRecord->data); + break; + + case TRACE_CODE_TX_WMA_MSG: + lim_log(pMac, LOG1, + "%04d %012llu %s S%d %-14s %-30s(0x%x)", recIndex, + pRecord->qtime, pRecord->time, pRecord->session, + "TX WMA Msg:", + mac_trace_get_wma_msg_string((uint16_t) pRecord->data), + pRecord->data); + break; + + case TRACE_CODE_RX_WMA_MSG: + lim_log(pMac, LOG1, + "%04d %012llu %s S%d %-14s %-30s(0x%x)", recIndex, + pRecord->qtime, pRecord->time, pRecord->session, + LIM_TRACE_GET_DEFRD_OR_DROPPED( + pRecord->data) ? "Def/Drp LIM Msg:" : "RX WMA Msg:", + mac_trace_get_wma_msg_string((uint16_t) pRecord->data), + pRecord->data); + break; + + case TRACE_CODE_TX_LIM_MSG: + lim_log(pMac, LOG1, + "%04d %012llu %s S%d %-14s %-30s(0x%x)", recIndex, + pRecord->qtime, pRecord->time, pRecord->session, + "TX LIM Msg:", + mac_trace_get_lim_msg_string((uint16_t) pRecord->data), + pRecord->data); + break; + case TRACE_CODE_RX_LIM_MSG: + lim_log(pMac, LOG1, + "%04d %012llu %s S%d %-14s %-30s(0x%x)", recIndex, + pRecord->qtime, pRecord->time, pRecord->session, + LIM_TRACE_GET_DEFRD_OR_DROPPED( + pRecord->data) ? "Def/Drp LIM Msg:" : "RX LIM Msg", + mac_trace_get_lim_msg_string((uint16_t) pRecord->data), + pRecord->data); + break; + case TRACE_CODE_TX_CFG_MSG: + lim_log(pMac, LOG1, + "%04d %012llu %s S%d %-14s %-30s(0x%x) ", recIndex, + pRecord->qtime, pRecord->time, pRecord->session, + "TX CFG Msg:", + mac_trace_get_cfg_msg_string((uint16_t) pRecord->data), + pRecord->data); + break; + case TRACE_CODE_RX_CFG_MSG: + lim_log(pMac, LOG1, + "%04d %012llu %s S%d %-14s %-30s(0x%x) ", recIndex, + pRecord->qtime, pRecord->time, pRecord->session, + LIM_TRACE_GET_DEFRD_OR_DROPPED( + pRecord->data) ? "Def/Drp LIM Msg:" : "RX CFG Msg:", + mac_trace_get_cfg_msg_string( + (uint16_t)MAC_TRACE_GET_MSG_ID(pRecord->data)), + pRecord->data); + break; + + case TRACE_CODE_TIMER_ACTIVATE: + lim_log(pMac, LOG1, + "%04d %012llu %s S%d %-14s %-30s(0x%x)", recIndex, + pRecord->qtime, pRecord->time, pRecord->session, + "Timer Actvtd", + __lim_trace_get_timer_string((uint16_t) pRecord->data), + pRecord->data); + break; + case TRACE_CODE_TIMER_DEACTIVATE: + lim_log(pMac, LOG1, + "%04d %012llu %s S%d %-14s %-30s(0x%x)", recIndex, + pRecord->qtime, pRecord->time, pRecord->session, + "Timer DeActvtd", + __lim_trace_get_timer_string((uint16_t) pRecord->data), + pRecord->data); + break; + + case TRACE_CODE_INFO_LOG: + lim_log(pMac, LOG1, + "%04d %012llu %s S%d %-14s %-30s(0x%x)", + recIndex, pRecord->qtime, pRecord->time, + pRecord->session, "INFORMATION_LOG", + mac_trace_get_info_log_string((uint16_t) pRecord->data), + pRecord->data); + break; + default: + lim_log(pMac, LOG1, "%04d %012llu %s S%d %-14s(%d) (0x%x)", + recIndex, pRecord->qtime, pRecord->time, + pRecord->session, "Unknown Code", + pRecord->code, pRecord->data); + break; + } +} + +void mac_trace_msg_tx(tpAniSirGlobal pMac, uint8_t session, uint32_t data) +{ + + uint16_t msgId = (uint16_t) MAC_TRACE_GET_MSG_ID(data); + uint8_t moduleId = (uint8_t) MAC_TRACE_GET_MODULE_ID(data); + + switch (moduleId) { + case SIR_LIM_MODULE_ID: + if (msgId >= SIR_LIM_ITC_MSG_TYPES_BEGIN) + mac_trace(pMac, TRACE_CODE_TX_LIM_MSG, session, data); + else + mac_trace(pMac, TRACE_CODE_TX_SME_MSG, session, data); + break; + case SIR_WMA_MODULE_ID: + mac_trace(pMac, TRACE_CODE_TX_WMA_MSG, session, data); + break; + case SIR_CFG_MODULE_ID: + mac_trace(pMac, TRACE_CODE_TX_CFG_MSG, session, data); + break; + default: + mac_trace(pMac, moduleId, session, data); + break; + } +} + +void mac_trace_msg_tx_new(tpAniSirGlobal pMac, uint8_t module, uint8_t session, + uint32_t data) +{ + uint16_t msgId = (uint16_t) MAC_TRACE_GET_MSG_ID(data); + uint8_t moduleId = (uint8_t) MAC_TRACE_GET_MODULE_ID(data); + + switch (moduleId) { + case SIR_LIM_MODULE_ID: + if (msgId >= SIR_LIM_ITC_MSG_TYPES_BEGIN) + mac_trace_new(pMac, module, TRACE_CODE_TX_LIM_MSG, + session, data); + else + mac_trace_new(pMac, module, TRACE_CODE_TX_SME_MSG, + session, data); + break; + case SIR_WMA_MODULE_ID: + mac_trace_new(pMac, module, TRACE_CODE_TX_WMA_MSG, session, data); + break; + case SIR_CFG_MODULE_ID: + mac_trace_new(pMac, module, TRACE_CODE_TX_CFG_MSG, session, data); + break; + default: + mac_trace(pMac, moduleId, session, data); + break; + } +} + +/* + * bit31: Rx message defferred or not + * bit 0-15: message ID: + */ +void mac_trace_msg_rx(tpAniSirGlobal pMac, uint8_t session, uint32_t data) +{ + uint16_t msgId = (uint16_t) MAC_TRACE_GET_MSG_ID(data); + uint8_t moduleId = (uint8_t) MAC_TRACE_GET_MODULE_ID(data); + + switch (moduleId) { + case SIR_LIM_MODULE_ID: + if (msgId >= SIR_LIM_ITC_MSG_TYPES_BEGIN) + mac_trace(pMac, TRACE_CODE_RX_LIM_MSG, session, data); + else + mac_trace(pMac, TRACE_CODE_RX_SME_MSG, session, data); + break; + case SIR_WMA_MODULE_ID: + mac_trace(pMac, TRACE_CODE_RX_WMA_MSG, session, data); + break; + case SIR_CFG_MODULE_ID: + mac_trace(pMac, TRACE_CODE_RX_CFG_MSG, session, data); + break; + default: + mac_trace(pMac, moduleId, session, data); + break; + } +} + +/* + * bit31: Rx message defferred or not + * bit 0-15: message ID: + */ +void mac_trace_msg_rx_new(tpAniSirGlobal pMac, uint8_t module, uint8_t session, + uint32_t data) +{ + uint16_t msgId = (uint16_t) MAC_TRACE_GET_MSG_ID(data); + uint8_t moduleId = (uint8_t) MAC_TRACE_GET_MODULE_ID(data); + + switch (moduleId) { + case SIR_LIM_MODULE_ID: + if (msgId >= SIR_LIM_ITC_MSG_TYPES_BEGIN) + mac_trace_new(pMac, module, TRACE_CODE_RX_LIM_MSG, + session, data); + else + mac_trace_new(pMac, module, TRACE_CODE_RX_SME_MSG, + session, data); + break; + case SIR_WMA_MODULE_ID: + mac_trace_new(pMac, module, TRACE_CODE_RX_WMA_MSG, session, data); + break; + case SIR_CFG_MODULE_ID: + mac_trace_new(pMac, module, TRACE_CODE_RX_CFG_MSG, session, data); + break; + default: + mac_trace(pMac, moduleId, session, data); + break; + } +} + +uint8_t *lim_trace_get_mlm_state_string(uint32_t mlmState) +{ + switch (mlmState) { + CASE_RETURN_STRING(eLIM_MLM_OFFLINE_STATE); + CASE_RETURN_STRING(eLIM_MLM_IDLE_STATE); + CASE_RETURN_STRING(eLIM_MLM_WT_PROBE_RESP_STATE); + CASE_RETURN_STRING(eLIM_MLM_PASSIVE_SCAN_STATE); + CASE_RETURN_STRING(eLIM_MLM_WT_JOIN_BEACON_STATE); + CASE_RETURN_STRING(eLIM_MLM_JOINED_STATE); + CASE_RETURN_STRING(eLIM_MLM_BSS_STARTED_STATE); + CASE_RETURN_STRING(eLIM_MLM_WT_AUTH_FRAME2_STATE); + CASE_RETURN_STRING(eLIM_MLM_WT_AUTH_FRAME3_STATE); + CASE_RETURN_STRING(eLIM_MLM_WT_AUTH_FRAME4_STATE); + CASE_RETURN_STRING(eLIM_MLM_AUTH_RSP_TIMEOUT_STATE); + CASE_RETURN_STRING(eLIM_MLM_AUTHENTICATED_STATE); + CASE_RETURN_STRING(eLIM_MLM_WT_ASSOC_RSP_STATE); + CASE_RETURN_STRING(eLIM_MLM_WT_REASSOC_RSP_STATE); + CASE_RETURN_STRING(eLIM_MLM_ASSOCIATED_STATE); + CASE_RETURN_STRING(eLIM_MLM_REASSOCIATED_STATE); + CASE_RETURN_STRING(eLIM_MLM_LINK_ESTABLISHED_STATE); + CASE_RETURN_STRING(eLIM_MLM_WT_ASSOC_CNF_STATE); + CASE_RETURN_STRING(eLIM_MLM_LEARN_STATE); + CASE_RETURN_STRING(eLIM_MLM_WT_ADD_BSS_RSP_STATE); + CASE_RETURN_STRING(eLIM_MLM_WT_DEL_BSS_RSP_STATE); + CASE_RETURN_STRING(eLIM_MLM_WT_ADD_BSS_RSP_ASSOC_STATE); + CASE_RETURN_STRING(eLIM_MLM_WT_ADD_BSS_RSP_PREASSOC_STATE); + CASE_RETURN_STRING(eLIM_MLM_WT_ADD_BSS_RSP_REASSOC_STATE); + CASE_RETURN_STRING(eLIM_MLM_WT_ADD_STA_RSP_STATE); + CASE_RETURN_STRING(eLIM_MLM_WT_DEL_STA_RSP_STATE); + CASE_RETURN_STRING(eLIM_MLM_WT_ASSOC_DEL_STA_RSP_STATE); + CASE_RETURN_STRING(eLIM_MLM_WT_SET_BSS_KEY_STATE); + CASE_RETURN_STRING(eLIM_MLM_WT_SET_STA_KEY_STATE); + CASE_RETURN_STRING(eLIM_MLM_WT_SET_STA_BCASTKEY_STATE); + CASE_RETURN_STRING(eLIM_MLM_WT_SET_MIMOPS_STATE); + CASE_RETURN_STRING(eLIM_MLM_WT_ADD_BSS_RSP_FT_REASSOC_STATE); + CASE_RETURN_STRING(eLIM_MLM_WT_FT_REASSOC_RSP_STATE); + CASE_RETURN_STRING(eLIM_MLM_P2P_LISTEN_STATE); + default: + return "UNKNOWN"; + break; + } +} + +uint8_t *lim_trace_get_sme_state_string(uint32_t smeState) +{ + switch (smeState) { + + CASE_RETURN_STRING(eLIM_SME_OFFLINE_STATE); + CASE_RETURN_STRING(eLIM_SME_IDLE_STATE); + CASE_RETURN_STRING(eLIM_SME_SUSPEND_STATE); + CASE_RETURN_STRING(eLIM_SME_WT_SCAN_STATE); + CASE_RETURN_STRING(eLIM_SME_WT_JOIN_STATE); + CASE_RETURN_STRING(eLIM_SME_WT_AUTH_STATE); + CASE_RETURN_STRING(eLIM_SME_WT_ASSOC_STATE); + CASE_RETURN_STRING(eLIM_SME_WT_REASSOC_STATE); + CASE_RETURN_STRING(eLIM_SME_WT_REASSOC_LINK_FAIL_STATE); + CASE_RETURN_STRING(eLIM_SME_JOIN_FAILURE_STATE); + CASE_RETURN_STRING(eLIM_SME_ASSOCIATED_STATE); + CASE_RETURN_STRING(eLIM_SME_REASSOCIATED_STATE); + CASE_RETURN_STRING(eLIM_SME_LINK_EST_STATE); + CASE_RETURN_STRING(eLIM_SME_LINK_EST_WT_SCAN_STATE); + CASE_RETURN_STRING(eLIM_SME_WT_PRE_AUTH_STATE); + CASE_RETURN_STRING(eLIM_SME_WT_DISASSOC_STATE); + CASE_RETURN_STRING(eLIM_SME_WT_DEAUTH_STATE); + CASE_RETURN_STRING(eLIM_SME_WT_START_BSS_STATE); + CASE_RETURN_STRING(eLIM_SME_WT_STOP_BSS_STATE); + CASE_RETURN_STRING(eLIM_SME_NORMAL_STATE); + CASE_RETURN_STRING(eLIM_SME_CHANNEL_SCAN_STATE); + CASE_RETURN_STRING(eLIM_SME_NORMAL_CHANNEL_SCAN_STATE); + default: + return "UNKNOWN"; + break; + } +} + +#endif diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_types.h b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_types.h new file mode 100644 index 0000000000000000000000000000000000000000..6487a7e5be22030540b71a118c2753f0afe5c43c --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_types.h @@ -0,0 +1,891 @@ +/* + * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * This file lim_types.h contains the definitions used by all + * all LIM modules. + * Author: Chandra Modumudi + * Date: 02/11/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + * + */ +#ifndef __LIM_TYPES_H +#define __LIM_TYPES_H + +#include "wni_api.h" +#include "sir_api.h" +#include "sir_common.h" +#include "sir_mac_prot_def.h" +#include "utils_api.h" + +#include "lim_api.h" +#include "lim_debug.h" +#include "lim_trace.h" +#include "lim_send_sme_rsp_messages.h" +#include "sys_global.h" +#include "dph_global.h" +#include "parser_api.h" +#include "wma_if.h" + +#define LINK_TEST_DEFER 1 + +#define TRACE_EVENT_CNF_TIMER_DEACT 0x6600 +#define TRACE_EVENT_CNF_TIMER_ACT 0x6601 +#define TRACE_EVENT_AUTH_RSP_TIMER_DEACT 0x6602 +#define TRACE_EVENT_AUTH_RSP_TIMER_ACT 0x6603 + +/* MLM message types */ +#define LIM_MLM_MSG_START 1000 +#define LIM_MLM_SCAN_REQ LIM_MLM_MSG_START +#define LIM_MLM_SCAN_CNF (LIM_MLM_MSG_START + 1) +#define LIM_MLM_START_REQ (LIM_MLM_MSG_START + 2) +#define LIM_MLM_START_CNF (LIM_MLM_MSG_START + 3) +#define LIM_MLM_JOIN_REQ (LIM_MLM_MSG_START + 4) +#define LIM_MLM_JOIN_CNF (LIM_MLM_MSG_START + 5) +#define LIM_MLM_AUTH_REQ (LIM_MLM_MSG_START + 6) +#define LIM_MLM_AUTH_CNF (LIM_MLM_MSG_START + 7) +#define LIM_MLM_AUTH_IND (LIM_MLM_MSG_START + 8) +#define LIM_MLM_ASSOC_REQ (LIM_MLM_MSG_START + 9) +#define LIM_MLM_ASSOC_CNF (LIM_MLM_MSG_START + 10) +#define LIM_MLM_ASSOC_IND (LIM_MLM_MSG_START + 11) +#define LIM_MLM_DISASSOC_REQ (LIM_MLM_MSG_START + 12) +#define LIM_MLM_DISASSOC_CNF (LIM_MLM_MSG_START + 13) +#define LIM_MLM_DISASSOC_IND (LIM_MLM_MSG_START + 14) +#define LIM_MLM_REASSOC_REQ (LIM_MLM_MSG_START + 15) +#define LIM_MLM_REASSOC_CNF (LIM_MLM_MSG_START + 16) +#define LIM_MLM_REASSOC_IND (LIM_MLM_MSG_START + 17) +#define LIM_MLM_DEAUTH_REQ (LIM_MLM_MSG_START + 18) +#define LIM_MLM_DEAUTH_CNF (LIM_MLM_MSG_START + 19) +#define LIM_MLM_DEAUTH_IND (LIM_MLM_MSG_START + 20) +#define LIM_MLM_TSPEC_REQ (LIM_MLM_MSG_START + 21) +#define LIM_MLM_TSPEC_CNF (LIM_MLM_MSG_START + 22) +#define LIM_MLM_TSPEC_IND (LIM_MLM_MSG_START + 23) +#define LIM_MLM_SETKEYS_REQ (LIM_MLM_MSG_START + 24) +#define LIM_MLM_SETKEYS_CNF (LIM_MLM_MSG_START + 25) +#define LIM_MLM_LINK_TEST_STOP_REQ (LIM_MLM_MSG_START + 30) +#define LIM_MLM_PURGE_STA_IND (LIM_MLM_MSG_START + 31) +/* + * Values (LIM_MLM_MSG_START + 32) through + * (LIM_MLM_MSG_START + 40) are unused. + */ + +#define LIM_HASH_ADD 0 +#define LIM_HASH_UPDATE 1 + +#define LIM_WEP_IN_FC 1 +#define LIM_NO_WEP_IN_FC 0 + +#define LIM_DECRYPT_ICV_FAIL 1 + +/* / Definitions to distinquish between Association/Reassociaton */ +#define LIM_ASSOC 0 +#define LIM_REASSOC 1 + +/* / Minimum Memory blocks require for different scenario */ +#define LIM_MIN_MEM_ASSOC 4 + +/* / Verifies whether given mac addr matches the CURRENT Bssid */ +#define IS_CURRENT_BSSID(pMac, addr, psessionEntry) (!qdf_mem_cmp(addr, \ + psessionEntry->bssId, \ + sizeof(psessionEntry->bssId))) +/* / Verifies whether given addr matches the REASSOC Bssid */ +#define IS_REASSOC_BSSID(pMac, addr, psessionEntry) (!qdf_mem_cmp(addr, \ + psessionEntry->limReAssocbssId, \ + sizeof(psessionEntry->limReAssocbssId))) + +#define REQ_TYPE_REGISTRAR (0x2) +#define REQ_TYPE_WLAN_MANAGER_REGISTRAR (0x3) + +#define RESP_TYPE_REGISTRAR (0x2) +#define RESP_TYPE_ENROLLEE_INFO_ONLY (0x0) +#define RESP_TYPE_ENROLLEE_OPEN_8021X (0x1) +#define RESP_TYPE_AP (0x3) +#define LIM_TX_FRAMES_THRESHOLD_ON_CHIP 300 + + +#define HAL_TXCOMP_REQUESTED_MASK 0x1 /* bit 0 for TxComp intr requested. */ +#define HAL_USE_SELF_STA_REQUESTED_MASK 0x2 /* bit 1 for STA overwrite with selfSta Requested. */ +#define HAL_TX_NO_ENCRYPTION_MASK 0x4 /* bit 2. If set, the frame is not to be encrypted */ +#if defined(LIBRA_WAPI_SUPPORT) +#define HAL_WAPI_STA_MASK 0x8 /* bit 3. If set, this frame is for WAPI station */ +#endif + +#define HAL_TRIGGER_ENABLED_AC_MASK 0x10 /* bit 4 for data frames belonging to trigger enabled AC */ +#define HAL_USE_NO_ACK_REQUESTED_MASK 0x20 + +#define HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME 0x40 /* Bit 6 will be used to control BD rate for Management frames */ +#define HAL_USE_PEER_STA_REQUESTED_MASK 0x80 /* bit 7 will be used to control frames for p2p interface */ + +#ifdef FEATURE_WLAN_TDLS +#define HAL_TDLS_PEER_STA_MASK 0x80 /* bit 7 set for TDLS peer station */ +#endif + + +/* enums used by LIM are as follows */ + +enum eLimDisassocTrigger { + eLIM_HOST_DISASSOC, + eLIM_PEER_ENTITY_DISASSOC, + eLIM_LINK_MONITORING_DISASSOC, + eLIM_PROMISCUOUS_MODE_DISASSOC, + eLIM_HOST_DEAUTH, + eLIM_PEER_ENTITY_DEAUTH, + eLIM_LINK_MONITORING_DEAUTH, + eLIM_JOIN_FAILURE, + eLIM_REASSOC_REJECT, + eLIM_DUPLICATE_ENTRY +}; + +/* Reason code to determine the channel change context while sending + * WMA_CHNL_SWITCH_REQ message to HAL + */ +enum eChannelChangeReasonCodes { + LIM_SWITCH_CHANNEL_REASSOC, + LIM_SWITCH_CHANNEL_JOIN, + LIM_SWITCH_CHANNEL_OPERATION, /* Generic change channel */ + LIM_SWITCH_CHANNEL_SAP_DFS, /* DFS channel change */ +}; + +typedef struct sLimAuthRspTimeout { + tSirMacAddr peerMacAddr; +} tLimAuthRspTimeout; + +typedef struct sLimMlmStartReq { + tSirMacSSid ssId; + tSirBssType bssType; + tSirMacAddr bssId; + tSirMacBeaconInterval beaconPeriod; + uint8_t dtimPeriod; + tSirMacCfParamSet cfParamSet; + tSirMacChanNum channelNumber; + ePhyChanBondState cbMode; + uint16_t atimWindow; + tSirMacRateSet rateSet; + uint8_t sessionId; /* Added For BT-AMP Support */ + + /* Parameters reqd for new HAL (message) interface */ + tSirNwType nwType; + uint8_t htCapable; + tSirMacHTOperatingMode htOperMode; + uint8_t dualCTSProtection; + uint8_t txChannelWidthSet; + uint8_t ssidHidden; + uint8_t wps_state; + uint8_t obssProtEnabled; + uint8_t beacon_tx_rate; +} tLimMlmStartReq, *tpLimMlmStartReq; + +typedef struct sLimMlmStartCnf { + tSirResultCodes resultCode; + uint8_t sessionId; +} tLimMlmStartCnf, *tpLimMlmStartCnf; + +typedef struct sLimMlmScanCnf { + tSirResultCodes resultCode; + uint16_t scanResultLength; + uint8_t sessionId; + tSirBssDescription bssDescription[1]; + /* + * WARNING: Pls make bssDescription as last variable in struct + * tLimMlmScanCnf as it has ieFields followed after this bss + * description. Adding a variable after this corrupts the ieFields + */ +} tLimMlmScanCnf, *tpLimMlmScanCnf; + +typedef struct sLimScanResult { + uint16_t numBssDescriptions; + tSirBssDescription bssDescription[1]; +} tLimScanResult; + +typedef struct sLimMlmJoinCnf { + tSirResultCodes resultCode; + uint16_t protStatusCode; + uint8_t sessionId; +} tLimMlmJoinCnf, *tpLimMlmJoinCnf; + +typedef struct sLimMlmAssocReq { + tSirMacAddr peerMacAddr; + uint32_t assocFailureTimeout; + uint16_t capabilityInfo; + tSirMacListenInterval listenInterval; + uint8_t sessionId; +} tLimMlmAssocReq, *tpLimMlmAssocReq; + +typedef struct sLimMlmAssocCnf { + tSirResultCodes resultCode; /* Internal status code. */ + uint16_t protStatusCode; /* Protocol Status code. */ + uint8_t sessionId; +} tLimMlmAssocCnf, *tpLimMlmAssocCnf; + +typedef struct sLimMlmAssocInd { + tSirMacAddr peerMacAddr; + uint16_t aid; + tAniAuthType authType; + tAniSSID ssId; + tSirRSNie rsnIE; + tSirWAPIie wapiIE; + tSirAddie addIE; /* additional IE received from the peer, which possibly includes WSC IE and/or P2P IE. */ + tSirMacCapabilityInfo capabilityInfo; + tAniBool spectrumMgtIndicator; + tSirMacPowerCapInfo powerCap; + tSirSupChnl supportedChannels; + uint8_t sessionId; + + tAniBool WmmStaInfoPresent; + + /* Required for indicating the frames to upper layer */ + uint32_t beaconLength; + uint8_t *beaconPtr; + uint32_t assocReqLength; + uint8_t *assocReqPtr; + tSirSmeChanInfo chan_info; +} tLimMlmAssocInd, *tpLimMlmAssocInd; + +typedef struct sLimMlmReassocReq { + tSirMacAddr peerMacAddr; + uint32_t reassocFailureTimeout; + uint16_t capabilityInfo; + tSirMacListenInterval listenInterval; + uint8_t sessionId; +} tLimMlmReassocReq, *tpLimMlmReassocReq; + +typedef struct sLimMlmReassocCnf { + tSirResultCodes resultCode; + uint16_t protStatusCode; /* Protocol Status code. */ + uint8_t sessionId; +} tLimMlmReassocCnf, *tpLimMlmReassocCnf; + +typedef struct sLimMlmReassocInd { + tSirMacAddr peerMacAddr; + tSirMacAddr currentApAddr; + uint16_t aid; + tAniAuthType authType; + tAniSSID ssId; + tSirRSNie rsnIE; + tSirWAPIie wapiIE; + tSirAddie addIE; /* additional IE received from the peer, which can be WSC IE and/or P2P IE. */ + tSirMacCapabilityInfo capabilityInfo; + tAniBool spectrumMgtIndicator; + tSirMacPowerCapInfo powerCap; + tSirSupChnl supportedChannels; + + tAniBool WmmStaInfoPresent; + + /* Required for indicating the frames to upper layer */ + uint32_t beaconLength; + uint8_t *beaconPtr; + uint32_t assocReqLength; + uint8_t *assocReqPtr; +} tLimMlmReassocInd, *tpLimMlmReassocInd; + +typedef struct sLimMlmAuthCnf { + tSirMacAddr peerMacAddr; + tAniAuthType authType; + tSirResultCodes resultCode; + uint16_t protStatusCode; + uint8_t sessionId; +} tLimMlmAuthCnf, *tpLimMlmAuthCnf; + +typedef struct sLimMlmDeauthReq { + struct qdf_mac_addr peer_macaddr; + uint16_t reasonCode; + uint16_t deauthTrigger; + uint16_t aid; + uint8_t sessionId; /* Added for BT-AMP SUPPORT */ + +} tLimMlmDeauthReq, *tpLimMlmDeauthReq; + +typedef struct sLimMlmDeauthCnf { + struct qdf_mac_addr peer_macaddr; + tSirResultCodes resultCode; + uint16_t deauthTrigger; + uint16_t aid; + uint8_t sessionId; +} tLimMlmDeauthCnf, *tpLimMLmDeauthCnf; + +typedef struct sLimMlmDeauthInd { + tSirMacAddr peerMacAddr; + uint16_t reasonCode; + uint16_t deauthTrigger; + uint16_t aid; +} tLimMlmDeauthInd, *tpLimMlmDeauthInd; + +typedef struct sLimMlmDisassocReq { + struct qdf_mac_addr peer_macaddr; + uint16_t reasonCode; + uint16_t disassocTrigger; + uint16_t aid; + uint8_t sessionId; +} tLimMlmDisassocReq, *tpLimMlmDisassocReq; + +typedef struct sLimMlmDisassocCnf { + tSirMacAddr peerMacAddr; + tSirResultCodes resultCode; + uint16_t disassocTrigger; + uint16_t aid; + uint8_t sessionId; +} tLimMlmDisassocCnf, *tpLimMlmDisassocCnf; + +typedef struct sLimMlmDisassocInd { + tSirMacAddr peerMacAddr; + uint16_t reasonCode; + uint16_t disassocTrigger; + uint16_t aid; + uint8_t sessionId; +} tLimMlmDisassocInd, *tpLimMlmDisassocInd; + +typedef struct sLimMlmPurgeStaReq { + tSirMacAddr peerMacAddr; + uint16_t aid; + uint8_t sessionId; /* Added For BT-AMP Support */ +} tLimMlmPurgeStaReq, *tpLimMlmPurgeStaReq; + +typedef struct sLimMlmPurgeStaInd { + tSirMacAddr peerMacAddr; + uint16_t reasonCode; + uint16_t purgeTrigger; + uint16_t aid; + uint8_t sessionId; +} tLimMlmPurgeStaInd, *tpLimMlmPurgeStaInd; + +/** + * struct sLimMlmSetKeysCnf - set key confirmation parameters + * @peer_macaddr: peer mac address + * @resultCode: Result of set key operation + * @aid: association id + * @sessionId: PE session id + * @key_len_nonzero: Keys are non-zero length + */ +typedef struct sLimMlmSetKeysCnf { + struct qdf_mac_addr peer_macaddr; + uint16_t resultCode; + uint16_t aid; + uint8_t sessionId; + bool key_len_nonzero; +} tLimMlmSetKeysCnf, *tpLimMlmSetKeysCnf; + +typedef struct sLimMlmResetReq { + tSirMacAddr macAddr; + uint8_t performCleanup; + uint8_t sessionId; +} tLimMlmResetReq, *tpLimMlmResetReq; + +typedef struct sLimMlmResetCnf { + tSirMacAddr macAddr; + tSirResultCodes resultCode; + uint8_t sessionId; +} tLimMlmResetCnf, *tpLimMlmResetCnf; + +typedef struct sLimMlmLinkTestStopReq { + tSirMacAddr peerMacAddr; + uint8_t sessionId; +} tLimMlmLinkTestStopReq, *tpLimMlmLinkTestStopReq; + +/* Function templates */ + +bool lim_process_sme_req_messages(tpAniSirGlobal, tpSirMsgQ); +void lim_process_mlm_req_messages(tpAniSirGlobal, tpSirMsgQ); +void lim_process_mlm_rsp_messages(tpAniSirGlobal, uint32_t, uint32_t *); +void lim_process_sme_del_bss_rsp(tpAniSirGlobal, uint32_t, tpPESession); + +void lim_get_random_bssid(tpAniSirGlobal pMac, uint8_t *data); + +/* Function to handle HT and HT IE CFG parameter intializations */ +void handle_ht_capabilityand_ht_info(struct sAniSirGlobal *pMac, + tpPESession psessionEntry); + +/* Function to handle CFG parameter updates */ +void lim_handle_cf_gparam_update(tpAniSirGlobal, uint32_t); + +void lim_handle_param_update(tpAniSirGlobal pMac, eUpdateIEsType cfgId); + +/* Function to apply CFG parameters before join/reassoc/start BSS */ +void lim_apply_configuration(tpAniSirGlobal, tpPESession); + +void lim_set_cfg_protection(tpAniSirGlobal pMac, tpPESession pesessionEntry); + +/* Function to Initialize MLM state machine on STA */ +tSirRetStatus lim_init_mlm(tpAniSirGlobal); + +/* Function to cleanup MLM state machine */ +void lim_cleanup_mlm(tpAniSirGlobal); + +/* Management frame handling functions */ +void lim_process_beacon_frame(tpAniSirGlobal, uint8_t *, tpPESession); +void lim_process_beacon_frame_no_session(tpAniSirGlobal, uint8_t *); +void lim_process_probe_req_frame(tpAniSirGlobal, uint8_t *, tpPESession); +void lim_process_probe_rsp_frame(tpAniSirGlobal, uint8_t *, tpPESession); +void lim_process_probe_rsp_frame_no_session(tpAniSirGlobal, uint8_t *); +void lim_process_probe_req_frame_multiple_bss(tpAniSirGlobal, uint8_t *, + tpPESession); + +/* Process Auth frame when we have a session in progress. */ +void lim_process_auth_frame(tpAniSirGlobal, uint8_t *, tpPESession); +tSirRetStatus lim_process_auth_frame_no_session(tpAniSirGlobal pMac, uint8_t *, + void *body); + +void lim_process_assoc_req_frame(tpAniSirGlobal, uint8_t *, uint8_t, tpPESession); +void lim_send_mlm_assoc_ind(tpAniSirGlobal pMac, tpDphHashNode pStaDs, + tpPESession psessionEntry); + +void lim_process_assoc_rsp_frame(tpAniSirGlobal, uint8_t *, uint8_t, tpPESession); +void lim_process_disassoc_frame(tpAniSirGlobal, uint8_t *, tpPESession); +void lim_process_deauth_frame(tpAniSirGlobal, uint8_t *, tpPESession); +void lim_process_action_frame(tpAniSirGlobal, uint8_t *, tpPESession); +void lim_process_action_frame_no_session(tpAniSirGlobal pMac, uint8_t *pRxMetaInfo); + +void lim_populate_p2p_mac_header(tpAniSirGlobal, uint8_t *); +void lim_populate_mac_header(tpAniSirGlobal, uint8_t *, uint8_t, uint8_t, + tSirMacAddr, tSirMacAddr); +tSirRetStatus lim_send_probe_req_mgmt_frame(tpAniSirGlobal, tSirMacSSid *, + tSirMacAddr, uint8_t, tSirMacAddr, + uint32_t, uint32_t, uint8_t *); +void lim_send_probe_rsp_mgmt_frame(tpAniSirGlobal, tSirMacAddr, tpAniSSID, short, + uint8_t, tpPESession, uint8_t); +void lim_send_auth_mgmt_frame(tpAniSirGlobal, tSirMacAuthFrameBody *, tSirMacAddr, + uint8_t, tpPESession); +void lim_send_assoc_req_mgmt_frame(tpAniSirGlobal, tLimMlmAssocReq *, tpPESession); +#ifdef WLAN_FEATURE_HOST_ROAM +void lim_send_reassoc_req_with_ft_ies_mgmt_frame(tpAniSirGlobal pMac, + tLimMlmReassocReq *pMlmReassocReq, tpPESession psessionEntry); +void lim_send_reassoc_req_mgmt_frame(tpAniSirGlobal, tLimMlmReassocReq *, + tpPESession); +#else +static inline void lim_send_reassoc_req_with_ft_ies_mgmt_frame( + tpAniSirGlobal pMac, tLimMlmReassocReq *pMlmReassocReq, + tpPESession psessionEntry) +{} +static inline void lim_send_reassoc_req_mgmt_frame(tpAniSirGlobal mac_ctx, + tLimMlmReassocReq *reassoc_req, tpPESession pe_session) +{} +#endif +void lim_send_delts_req_action_frame(tpAniSirGlobal pMac, tSirMacAddr peer, + uint8_t wmmTspecPresent, + tSirMacTSInfo * pTsinfo, + tSirMacTspecIE * pTspecIe, + tpPESession psessionEntry); +void lim_send_addts_req_action_frame(tpAniSirGlobal pMac, tSirMacAddr peerMacAddr, + tSirAddtsReqInfo *addts, tpPESession); +void lim_send_addts_rsp_action_frame(tpAniSirGlobal pMac, tSirMacAddr peerMacAddr, + uint16_t statusCode, tSirAddtsReqInfo *addts, + tSirMacScheduleIE *pSchedule, tpPESession); + +void lim_send_assoc_rsp_mgmt_frame(tpAniSirGlobal, uint16_t, uint16_t, tSirMacAddr, + uint8_t, tpDphHashNode pSta, tpPESession); + +void lim_send_disassoc_mgmt_frame(tpAniSirGlobal, uint16_t, tSirMacAddr, + tpPESession, bool waitForAck); +void lim_send_deauth_mgmt_frame(tpAniSirGlobal, uint16_t, tSirMacAddr, tpPESession, + bool waitForAck); + +tSirResultCodes lim_mlm_add_bss(tpAniSirGlobal, tLimMlmStartReq *, + tpPESession psessionEntry); + +tSirRetStatus lim_send_channel_switch_mgmt_frame(tpAniSirGlobal, tSirMacAddr, + uint8_t, uint8_t, uint8_t, + tpPESession); + +tSirRetStatus lim_send_extended_chan_switch_action_frame(tpAniSirGlobal mac_ctx, + tSirMacAddr peer, uint8_t mode, uint8_t new_op_class, + uint8_t new_channel, uint8_t count, tpPESession session_entry); +tSirRetStatus lim_p2p_oper_chan_change_confirm_action_frame( + tpAniSirGlobal mac_ctx, tSirMacAddr peer, + tpPESession session_entry); + +tSirRetStatus lim_send_vht_opmode_notification_frame(tpAniSirGlobal pMac, + tSirMacAddr peer, uint8_t nMode, + tpPESession psessionEntry); + +tSirRetStatus lim_send_neighbor_report_request_frame(tpAniSirGlobal, + tpSirMacNeighborReportReq, + tSirMacAddr, tpPESession); +tSirRetStatus lim_send_link_report_action_frame(tpAniSirGlobal, tpSirMacLinkReport, + tSirMacAddr, tpPESession); +tSirRetStatus lim_send_radio_measure_report_action_frame(tpAniSirGlobal, uint8_t, + uint8_t, + tpSirMacRadioMeasureReport, + tSirMacAddr, tpPESession); + + +#ifdef FEATURE_WLAN_TDLS +void lim_init_tdls_data(tpAniSirGlobal, tpPESession); +tSirRetStatus lim_process_sme_tdls_mgmt_send_req(tpAniSirGlobal pMac, + uint32_t *pMsgBuf); +tSirRetStatus lim_process_sme_tdls_add_sta_req(tpAniSirGlobal pMac, + uint32_t *pMsgBuf); +tSirRetStatus lim_process_sme_tdls_link_establish_req(tpAniSirGlobal pMac, + uint32_t *pMsgBuf); +tSirRetStatus lim_process_sme_tdls_del_sta_req(tpAniSirGlobal pMac, + uint32_t *pMsgBuf); +void lim_send_sme_tdls_delete_all_peer_ind(tpAniSirGlobal pMac, + tpPESession psessionEntry); +void lim_send_sme_mgmt_tx_completion( + tpAniSirGlobal pMac, + uint32_t sme_session_id, + uint32_t txCompleteStatus); +tSirRetStatus lim_delete_tdls_peers(tpAniSirGlobal mac_ctx, + tpPESession session_entry); +QDF_STATUS lim_process_tdls_add_sta_rsp(tpAniSirGlobal pMac, void *msg, tpPESession); +void lim_process_tdls_del_sta_rsp(tpAniSirGlobal mac_ctx, tpSirMsgQ lim_msg, + tpPESession session_entry); +#else +static inline tSirRetStatus lim_delete_tdls_peers(tpAniSirGlobal mac_ctx, + tpPESession session_entry) +{ + return eSIR_SUCCESS; +} +static inline void lim_init_tdls_data(tpAniSirGlobal pMac, + tpPESession pSessionEntry) +{ + +} +#endif + +/* Algorithms & Link Monitoring related functions */ +/* / Function that handles heartbeat failure */ +void lim_handle_heart_beat_failure(tpAniSirGlobal, tpPESession); + +/* / Function that triggers link tear down with AP upon HB failure */ +void lim_tear_down_link_with_ap(tpAniSirGlobal, uint8_t, tSirMacReasonCodes); + +/* / Function that processes Max retries interrupt from TFP */ +void limHandleMaxRetriesInterrupt(uint32_t); + +/* / Function that defers the messages received */ +uint32_t lim_defer_msg(tpAniSirGlobal, tSirMsgQ *); + +/* / Function that Switches the Channel and sets the CB Mode */ +void lim_set_channel(tpAniSirGlobal pMac, uint8_t channel, + uint8_t ch_center_freq_seg0, uint8_t ch_center_freq_seg1, + enum phy_ch_width ch_width, int8_t maxTxPower, + uint8_t peSessionId); + + +/* / Function that completes channel scan */ +void lim_complete_mlm_scan(tpAniSirGlobal, tSirResultCodes); + +#ifdef ANI_SUPPORT_11H +/* / Function that sends Measurement Report action frame */ +tSirRetStatus lim_send_meas_report_frame(tpAniSirGlobal, tpSirMacMeasReqActionFrame, + tSirMacAddr, tpPESession psessionEntry); + +/* / Function that sends TPC Report action frame */ +tSirRetStatus lim_send_tpc_report_frame(tpAniSirGlobal, tpSirMacTpcReqActionFrame, + tSirMacAddr, tpPESession psessionEntry); +#endif + +/* / Function that sends TPC Request action frame */ +void lim_send_tpc_request_frame(tpAniSirGlobal, tSirMacAddr, + tpPESession psessionEntry); + +/* Function(s) to handle responses received from HAL */ +void lim_process_mlm_add_bss_rsp(tpAniSirGlobal pMac, tpSirMsgQ limMsgQ); +void lim_process_mlm_add_sta_rsp(tpAniSirGlobal pMac, tpSirMsgQ limMsgQt, + tpPESession psessionEntry); +void lim_process_mlm_del_sta_rsp(tpAniSirGlobal pMac, tpSirMsgQ limMsgQ); +void lim_process_mlm_del_bss_rsp(tpAniSirGlobal pMac, tpSirMsgQ limMsgQ, + tpPESession); +void lim_process_sta_mlm_add_sta_rsp(tpAniSirGlobal pMac, tpSirMsgQ limMsgQ, + tpPESession psessionEntry); +void lim_process_sta_mlm_del_sta_rsp(tpAniSirGlobal pMac, tpSirMsgQ limMsgQ, + tpPESession psessionEntry); +void lim_process_sta_mlm_del_bss_rsp(tpAniSirGlobal pMac, tpSirMsgQ limMsgQ, + tpPESession psessionEntry); +void lim_process_mlm_set_sta_key_rsp(tpAniSirGlobal pMac, tpSirMsgQ limMsgQ); +void lim_process_mlm_set_bss_key_rsp(tpAniSirGlobal pMac, tpSirMsgQ limMsgQ); + +/* Function to process WMA_SWITCH_CHANNEL_RSP message */ +void lim_process_switch_channel_rsp(tpAniSirGlobal pMac, void *); + +void lim_covert_channel_scan_type(tpAniSirGlobal pMac, uint8_t channelNum, + bool passiveToActive); +void lim_set_dfs_channel_list(tpAniSirGlobal pMac, uint8_t channelNum, + tSirDFSChannelList *dfsChannelList); +void limContinueChannelLearn(tpAniSirGlobal); +/* WLAN_SUSPEND_LINK Related */ +uint8_t lim_is_link_suspended(tpAniSirGlobal pMac); +/* end WLAN_SUSPEND_LINK Related */ + +#ifdef WLAN_FEATURE_11W +/* 11w send SA query request action frame */ +tSirRetStatus lim_send_sa_query_request_frame(tpAniSirGlobal pMac, uint8_t *transId, + tSirMacAddr peer, + tpPESession psessionEntry); +/* 11w SA query request action frame handler */ +tSirRetStatus lim_send_sa_query_response_frame(tpAniSirGlobal pMac, + uint8_t *transId, tSirMacAddr peer, + tpPESession psessionEntry); +#endif + +/* Inline functions */ + +/** + * lim_post_sme_message() + * + ***FUNCTION: + * This function is called by limProcessMlmMessages(). In this + * function MLM sub-module invokes MLM ind/cnf primitives. + * + ***LOGIC: + * Initially MLM makes an SME function call to invoke MLM ind/cnf + * primitive. In future this can be enhanced to 'post' messages to SME. + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param pMac Pointer to Global MAC structure + * @param msgType Indicates the MLM primitive message type + * @param *pMsgBuf A pointer to the MLM message buffer + * + * @return None + */ +static inline void +lim_post_sme_message(tpAniSirGlobal pMac, uint32_t msgType, uint32_t *pMsgBuf) +{ + tSirMsgQ msg; + + if (pMsgBuf == NULL) { + lim_log(pMac, LOGE, FL("Buffer is Pointing to NULL")); + return; + } + + msg.type = (uint16_t) msgType; + msg.bodyptr = pMsgBuf; + msg.bodyval = 0; + if (msgType > eWNI_SME_MSG_TYPES_BEGIN) { + MTRACE(mac_trace(pMac, TRACE_CODE_TX_SME_MSG, NO_SESSION, + msg.type)); + lim_process_sme_req_messages(pMac, &msg); + } else { + lim_process_mlm_rsp_messages(pMac, msgType, pMsgBuf); + } +} /*** end lim_post_sme_message() ***/ + +/** + * lim_post_mlm_message() + * + ***FUNCTION: + * This function is called by limProcessSmeMessages(). In this + * function SME invokes MLME primitives. + * + ***PARAMS: + * + ***LOGIC: + * Initially SME makes an MLM function call to invoke MLM primitive. + * In future this can be enhanced to 'post' messages to MLM. + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param pMac Pointer to Global MAC structure + * @param msgType Indicates the MLM primitive message type + * @param *pMsgBuf A pointer to the MLM message buffer + * + * @return None + */ +static inline void +lim_post_mlm_message(tpAniSirGlobal pMac, uint32_t msgType, uint32_t *pMsgBuf) +{ + + tSirMsgQ msg; + if (pMsgBuf == NULL) { + lim_log(pMac, LOGE, FL("Buffer is Pointing to NULL")); + return; + } + msg.type = (uint16_t) msgType; + msg.bodyptr = pMsgBuf; + msg.bodyval = 0; + MTRACE(mac_trace_msg_rx(pMac, NO_SESSION, msg.type)); + lim_process_mlm_req_messages(pMac, &msg); +} /*** end lim_post_mlm_message() ***/ + +/** + * lim_get_current_scan_channel() + * + ***FUNCTION: + * This function is called in various places to get current channel + * number being scanned. + * + ***PARAMS: + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param pMac Pointer to Global MAC structure + * @return Channel number + */ +static inline uint8_t lim_get_current_scan_channel(tpAniSirGlobal pMac) +{ + uint8_t *pChanNum = + pMac->lim.gpLimMlmScanReq->channelList.channelNumber; + + return *(pChanNum + pMac->lim.gLimCurrentScanChannelId); +} /*** end lim_get_current_scan_channel() ***/ + +/** + * lim_get_ielen_from_bss_description() + * + ***FUNCTION: + * This function is called in various places to get IE length + * from tSirBssDescription structure + * number being scanned. + * + ***PARAMS: + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param pBssDescr + * @return Total IE length + */ + +static inline uint16_t +lim_get_ielen_from_bss_description(tpSirBssDescription pBssDescr) +{ + uint16_t ielen; + + if (!pBssDescr) + return 0; + + /* + * Length of BSS desription is without length of + * length itself and length of pointer + * that holds ieFields + * + * <------------sizeof(tSirBssDescription)--------------------> + * +--------+---------------------------------+---------------+ + * | length | other fields | pointer to IEs| + * +--------+---------------------------------+---------------+ + * ^ + * ieFields + */ + + ielen = (uint16_t)(pBssDescr->length + sizeof(pBssDescr->length) - + GET_FIELD_OFFSET(tSirBssDescription, ieFields)); + + return ielen; +} /*** end lim_get_ielen_from_bss_description() ***/ + +/** + * lim_send_beacon_ind() + * + ***FUNCTION: + * This function is called to send the beacon indication + * number being scanned. + * + ***PARAMS: + * + ***LOGIC: + * + ***ASSUMPTIONS: + */ + +void lim_send_beacon_ind(tpAniSirGlobal pMac, tpPESession psessionEntry); + +void +lim_send_vdev_restart(tpAniSirGlobal pMac, tpPESession psessionEntry, + uint8_t sessionId); + +void lim_get_wpspbc_sessions(tpAniSirGlobal pMac, struct qdf_mac_addr addr, + uint8_t *uuid_e, eWPSPBCOverlap *overlap, + tpPESession psessionEntry); +void limWPSPBCTimeout(tpAniSirGlobal pMac, tpPESession psessionEntry); +void lim_wpspbc_close(tpAniSirGlobal pMac, tpPESession psessionEntry); +void lim_remove_pbc_sessions(tpAniSirGlobal pMac, + struct qdf_mac_addr pRemoveMac, + tpPESession psessionEntry); + +#define LIM_WPS_OVERLAP_TIMER_MS 10000 +void +lim_change_channel_with_callback(tpAniSirGlobal pMac, uint8_t newChannel, + CHANGE_CHANNEL_CALLBACK callback, + uint32_t *cbdata, tpPESession psessionEntry); + +void lim_send_sme_mgmt_frame_ind(tpAniSirGlobal pMac, uint8_t frameType, + uint8_t *frame, uint32_t frameLen, + uint16_t sessionId, uint32_t rxChan, + tpPESession psessionEntry, int8_t rxRssi); +void lim_process_remain_on_chn_timeout(tpAniSirGlobal pMac); +void lim_process_insert_single_shot_noa_timeout(tpAniSirGlobal pMac); +void lim_convert_active_channel_to_passive_channel(tpAniSirGlobal pMac); +void lim_send_p2p_action_frame(tpAniSirGlobal pMac, tpSirMsgQ pMsg); +tSirRetStatus __lim_process_sme_no_a_update(tpAniSirGlobal pMac, uint32_t *pMsgBuf); +void lim_process_regd_defd_sme_req_after_noa_start(tpAniSirGlobal pMac); + +void lim_process_disassoc_ack_timeout(tpAniSirGlobal pMac); +void lim_process_deauth_ack_timeout(tpAniSirGlobal pMac); +QDF_STATUS lim_send_disassoc_cnf(tpAniSirGlobal pMac); +QDF_STATUS lim_send_deauth_cnf(tpAniSirGlobal pMac); +QDF_STATUS lim_disassoc_tx_complete_cnf(tpAniSirGlobal pMac, + uint32_t txCompleteSuccess); +QDF_STATUS lim_deauth_tx_complete_cnf(tpAniSirGlobal pMac, + uint32_t txCompleteSuccess); + +typedef struct sSetLinkCbackParams { + void *cbackDataPtr; +} tSetLinkCbackParams; + +void lim_process_rx_scan_event(tpAniSirGlobal mac, void *buf); + +int lim_process_remain_on_chnl_req(tpAniSirGlobal pMac, uint32_t *pMsg); +void lim_remain_on_chn_rsp(tpAniSirGlobal pMac, QDF_STATUS status, uint32_t *data); +void lim_send_sme_disassoc_deauth_ntf(tpAniSirGlobal mac_ctx, + QDF_STATUS status, uint32_t *ctx); +tSirRetStatus lim_process_sme_del_all_tdls_peers(tpAniSirGlobal p_mac, + uint32_t *msg_buf); +/* / Bit value data structure */ +typedef enum sHalBitVal /* For Bit operations */ +{ + eHAL_CLEAR, + eHAL_SET +} tHalBitVal; + +enum { + eHI_PRI, + ePROT, + eDBG +}; + +#endif /* __LIM_TYPES_H */ diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_utils.c b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_utils.c new file mode 100644 index 0000000000000000000000000000000000000000..86e56042ff8a526542b91670aaac3b6ef601c56c --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_utils.c @@ -0,0 +1,7538 @@ +/* + * Copyright (c) 2011-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * This file lim_utils.cc contains the utility functions + * LIM uses. + * Author: Chandra Modumudi + * Date: 02/13/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + */ + +#include "sch_api.h" +#include "lim_utils.h" +#include "lim_types.h" +#include "lim_security_utils.h" +#include "lim_prop_exts_utils.h" +#include "lim_send_messages.h" +#include "lim_ser_des_utils.h" +#include "lim_admit_control.h" +#include "lim_sta_hash_api.h" +#include "dot11f.h" +#include "dot11fdefs.h" +#include "wmm_apsd.h" +#include "lim_trace.h" +#ifdef FEATURE_WLAN_DIAG_SUPPORT +#include "host_diag_core_event.h" +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ +#include "lim_ibss_peer_mgmt.h" +#include "lim_session_utils.h" +#include "lim_ft_defs.h" +#include "lim_session.h" +#include "cds_reg_service.h" +#include "nan_datapath.h" +#include "wma.h" + +#ifdef WLAN_FEATURE_11W +#include "wni_cfg.h" +#endif +#define ASCII_SPACE_CHARACTER 0x20 + +/** ------------------------------------------------------------- + \fn lim_delete_dialogue_token_list + \brief deletes the complete lim dialogue token linked list. + \param tpAniSirGlobal pMac + \return None + -------------------------------------------------------------*/ +void lim_delete_dialogue_token_list(tpAniSirGlobal pMac) +{ + tpDialogueToken pCurrNode = pMac->lim.pDialogueTokenHead; + + while (NULL != pMac->lim.pDialogueTokenHead) { + pCurrNode = pMac->lim.pDialogueTokenHead; + pMac->lim.pDialogueTokenHead = + pMac->lim.pDialogueTokenHead->next; + qdf_mem_free(pCurrNode); + pCurrNode = NULL; + } + pMac->lim.pDialogueTokenTail = NULL; +} + +char *lim_dot11_reason_str(uint16_t reasonCode) +{ + switch (reasonCode) { + case 0: + return " "; + CASE_RETURN_STRING(eSIR_MAC_UNSPEC_FAILURE_REASON); + CASE_RETURN_STRING(eSIR_MAC_PREV_AUTH_NOT_VALID_REASON); + CASE_RETURN_STRING(eSIR_MAC_DEAUTH_LEAVING_BSS_REASON); + CASE_RETURN_STRING(eSIR_MAC_DISASSOC_DUE_TO_INACTIVITY_REASON); + CASE_RETURN_STRING(eSIR_MAC_DISASSOC_DUE_TO_DISABILITY_REASON); + CASE_RETURN_STRING + (eSIR_MAC_CLASS2_FRAME_FROM_NON_AUTH_STA_REASON); + CASE_RETURN_STRING + (eSIR_MAC_CLASS3_FRAME_FROM_NON_ASSOC_STA_REASON); + CASE_RETURN_STRING(eSIR_MAC_DISASSOC_LEAVING_BSS_REASON); + CASE_RETURN_STRING(eSIR_MAC_STA_NOT_PRE_AUTHENTICATED_REASON); + CASE_RETURN_STRING(eSIR_MAC_PWR_CAPABILITY_BAD_REASON); + CASE_RETURN_STRING(eSIR_MAC_SPRTD_CHANNELS_BAD_REASON); + + CASE_RETURN_STRING(eSIR_MAC_INVALID_IE_REASON); + CASE_RETURN_STRING(eSIR_MAC_MIC_FAILURE_REASON); + CASE_RETURN_STRING(eSIR_MAC_4WAY_HANDSHAKE_TIMEOUT_REASON); + CASE_RETURN_STRING(eSIR_MAC_GR_KEY_UPDATE_TIMEOUT_REASON); + CASE_RETURN_STRING(eSIR_MAC_RSN_IE_MISMATCH_REASON); + + CASE_RETURN_STRING(eSIR_MAC_INVALID_MC_CIPHER_REASON); + CASE_RETURN_STRING(eSIR_MAC_INVALID_UC_CIPHER_REASON); + CASE_RETURN_STRING(eSIR_MAC_INVALID_AKMP_REASON); + CASE_RETURN_STRING(eSIR_MAC_UNSUPPORTED_RSN_IE_VER_REASON); + CASE_RETURN_STRING(eSIR_MAC_INVALID_RSN_CAPABILITIES_REASON); + CASE_RETURN_STRING(eSIR_MAC_1X_AUTH_FAILURE_REASON); + CASE_RETURN_STRING(eSIR_MAC_CIPHER_SUITE_REJECTED_REASON); +#ifdef FEATURE_WLAN_TDLS + CASE_RETURN_STRING(eSIR_MAC_TDLS_TEARDOWN_PEER_UNREACHABLE); + CASE_RETURN_STRING(eSIR_MAC_TDLS_TEARDOWN_UNSPEC_REASON); +#endif + /* Reserved 27 - 30 */ +#ifdef WLAN_FEATURE_11W + CASE_RETURN_STRING + (eSIR_MAC_ROBUST_MGMT_FRAMES_POLICY_VIOLATION); +#endif + CASE_RETURN_STRING(eSIR_MAC_QOS_UNSPECIFIED_REASON); + CASE_RETURN_STRING(eSIR_MAC_QAP_NO_BANDWIDTH_REASON); + CASE_RETURN_STRING(eSIR_MAC_XS_UNACKED_FRAMES_REASON); + CASE_RETURN_STRING(eSIR_MAC_BAD_TXOP_USE_REASON); + CASE_RETURN_STRING(eSIR_MAC_PEER_STA_REQ_LEAVING_BSS_REASON); + CASE_RETURN_STRING(eSIR_MAC_PEER_REJECT_MECHANISIM_REASON); + CASE_RETURN_STRING(eSIR_MAC_MECHANISM_NOT_SETUP_REASON); + + CASE_RETURN_STRING(eSIR_MAC_PEER_TIMEDOUT_REASON); + CASE_RETURN_STRING(eSIR_MAC_CIPHER_NOT_SUPPORTED_REASON); + CASE_RETURN_STRING(eSIR_MAC_DISASSOC_DUE_TO_FTHANDOFF_REASON); + /* Reserved 47 - 65535 */ + default: + return "Unknown"; + } +} + +char *lim_mlm_state_str(tLimMlmStates state) +{ + switch (state) { + case eLIM_MLM_OFFLINE_STATE: + return "eLIM_MLM_OFFLINE_STATE"; + case eLIM_MLM_IDLE_STATE: + return "eLIM_MLM_IDLE_STATE"; + case eLIM_MLM_WT_PROBE_RESP_STATE: + return "eLIM_MLM_WT_PROBE_RESP_STATE"; + case eLIM_MLM_PASSIVE_SCAN_STATE: + return "eLIM_MLM_PASSIVE_SCAN_STATE"; + case eLIM_MLM_WT_JOIN_BEACON_STATE: + return "eLIM_MLM_WT_JOIN_BEACON_STATE"; + case eLIM_MLM_JOINED_STATE: + return "eLIM_MLM_JOINED_STATE"; + case eLIM_MLM_BSS_STARTED_STATE: + return "eLIM_MLM_BSS_STARTED_STATE"; + case eLIM_MLM_WT_AUTH_FRAME2_STATE: + return "eLIM_MLM_WT_AUTH_FRAME2_STATE"; + case eLIM_MLM_WT_AUTH_FRAME3_STATE: + return "eLIM_MLM_WT_AUTH_FRAME3_STATE"; + case eLIM_MLM_WT_AUTH_FRAME4_STATE: + return "eLIM_MLM_WT_AUTH_FRAME4_STATE"; + case eLIM_MLM_AUTH_RSP_TIMEOUT_STATE: + return "eLIM_MLM_AUTH_RSP_TIMEOUT_STATE"; + case eLIM_MLM_AUTHENTICATED_STATE: + return "eLIM_MLM_AUTHENTICATED_STATE"; + case eLIM_MLM_WT_ASSOC_RSP_STATE: + return "eLIM_MLM_WT_ASSOC_RSP_STATE"; + case eLIM_MLM_WT_REASSOC_RSP_STATE: + return "eLIM_MLM_WT_REASSOC_RSP_STATE"; + case eLIM_MLM_WT_FT_REASSOC_RSP_STATE: + return "eLIM_MLM_WT_FT_REASSOC_RSP_STATE"; + case eLIM_MLM_WT_DEL_STA_RSP_STATE: + return "eLIM_MLM_WT_DEL_STA_RSP_STATE"; + case eLIM_MLM_WT_DEL_BSS_RSP_STATE: + return "eLIM_MLM_WT_DEL_BSS_RSP_STATE"; + case eLIM_MLM_WT_ADD_STA_RSP_STATE: + return "eLIM_MLM_WT_ADD_STA_RSP_STATE"; + case eLIM_MLM_WT_ADD_BSS_RSP_STATE: + return "eLIM_MLM_WT_ADD_BSS_RSP_STATE"; + case eLIM_MLM_REASSOCIATED_STATE: + return "eLIM_MLM_REASSOCIATED_STATE"; + case eLIM_MLM_LINK_ESTABLISHED_STATE: + return "eLIM_MLM_LINK_ESTABLISHED_STATE"; + case eLIM_MLM_WT_ASSOC_CNF_STATE: + return "eLIM_MLM_WT_ASSOC_CNF_STATE"; + case eLIM_MLM_WT_ADD_BSS_RSP_ASSOC_STATE: + return "eLIM_MLM_WT_ADD_BSS_RSP_ASSOC_STATE"; + case eLIM_MLM_WT_ADD_BSS_RSP_REASSOC_STATE: + return "eLIM_MLM_WT_ADD_BSS_RSP_REASSOC_STATE"; + case eLIM_MLM_WT_ADD_BSS_RSP_FT_REASSOC_STATE: + return "eLIM_MLM_WT_ADD_BSS_RSP_FT_REASSOC_STATE"; + case eLIM_MLM_WT_ASSOC_DEL_STA_RSP_STATE: + return "eLIM_MLM_WT_ASSOC_DEL_STA_RSP_STATE"; + case eLIM_MLM_WT_SET_BSS_KEY_STATE: + return "eLIM_MLM_WT_SET_BSS_KEY_STATE"; + case eLIM_MLM_WT_SET_STA_KEY_STATE: + return "eLIM_MLM_WT_SET_STA_KEY_STATE"; + default: + return "INVALID MLM state"; + } +} + +void +lim_print_mlm_state(tpAniSirGlobal pMac, uint16_t logLevel, tLimMlmStates state) +{ + lim_log(pMac, logLevel, lim_mlm_state_str(state)); +} + +char *lim_sme_state_str(tLimSmeStates state) +{ + switch (state) { + case eLIM_SME_OFFLINE_STATE: + return "eLIM_SME_OFFLINE_STATE"; + case eLIM_SME_IDLE_STATE: + return "eLIM_SME_OFFLINE_STATE"; + case eLIM_SME_SUSPEND_STATE: + return "eLIM_SME_SUSPEND_STATE"; + case eLIM_SME_WT_SCAN_STATE: + return "eLIM_SME_WT_SCAN_STATE"; + case eLIM_SME_WT_JOIN_STATE: + return "eLIM_SME_WT_JOIN_STATE"; + case eLIM_SME_WT_AUTH_STATE: + return "eLIM_SME_WT_AUTH_STATE"; + case eLIM_SME_WT_ASSOC_STATE: + return "eLIM_SME_WT_ASSOC_STATE"; + case eLIM_SME_WT_REASSOC_STATE: + return "eLIM_SME_WT_REASSOC_STATE"; + case eLIM_SME_WT_REASSOC_LINK_FAIL_STATE: + return "eLIM_SME_WT_REASSOC_LINK_FAIL_STATE"; + case eLIM_SME_JOIN_FAILURE_STATE: + return "eLIM_SME_JOIN_FAILURE_STATE"; + case eLIM_SME_ASSOCIATED_STATE: + return "eLIM_SME_ASSOCIATED_STATE"; + case eLIM_SME_REASSOCIATED_STATE: + return "eLIM_SME_REASSOCIATED_STATE"; + case eLIM_SME_LINK_EST_STATE: + return "eLIM_SME_LINK_EST_STATE"; + case eLIM_SME_LINK_EST_WT_SCAN_STATE: + return "eLIM_SME_LINK_EST_WT_SCAN_STATE"; + case eLIM_SME_WT_PRE_AUTH_STATE: + return "eLIM_SME_WT_PRE_AUTH_STATE"; + case eLIM_SME_WT_DISASSOC_STATE: + return "eLIM_SME_WT_DISASSOC_STATE"; + case eLIM_SME_WT_DEAUTH_STATE: + return "eLIM_SME_WT_DEAUTH_STATE"; + case eLIM_SME_WT_START_BSS_STATE: + return "eLIM_SME_WT_START_BSS_STATE"; + case eLIM_SME_WT_STOP_BSS_STATE: + return "eLIM_SME_WT_STOP_BSS_STATE"; + case eLIM_SME_NORMAL_STATE: + return "eLIM_SME_NORMAL_STATE"; + case eLIM_SME_CHANNEL_SCAN_STATE: + return "eLIM_SME_CHANNEL_SCAN_STATE"; + case eLIM_SME_NORMAL_CHANNEL_SCAN_STATE: + return "eLIM_SME_NORMAL_CHANNEL_SCAN_STATE"; + default: + return "INVALID SME STATE"; + } +} + +void +lim_print_sme_state(tpAniSirGlobal pMac, uint16_t logLevel, tLimSmeStates state) +{ + lim_log(pMac, logLevel, lim_sme_state_str(state)); +} + +char *lim_msg_str(uint32_t msgType) +{ +#ifdef FIXME_GEN6 + switch (msgType) { + case eWNI_SME_SYS_READY_IND: + return "eWNI_SME_SYS_READY_IND"; + case eWNI_SME_SCAN_REQ: + return "eWNI_SME_SCAN_REQ"; + case eWNI_SME_SCAN_RSP: + return "eWNI_SME_SCAN_RSP"; + case eWNI_SME_JOIN_REQ: + return "eWNI_SME_JOIN_REQ"; + case eWNI_SME_JOIN_RSP: + return "eWNI_SME_JOIN_RSP"; + case eWNI_SME_SETCONTEXT_REQ: + return "eWNI_SME_SETCONTEXT_REQ"; + case eWNI_SME_SETCONTEXT_RSP: + return "eWNI_SME_SETCONTEXT_RSP"; + case eWNI_SME_REASSOC_REQ: + return "eWNI_SME_REASSOC_REQ"; + case eWNI_SME_REASSOC_RSP: + return "eWNI_SME_REASSOC_RSP"; + case eWNI_SME_DISASSOC_REQ: + return "eWNI_SME_DISASSOC_REQ"; + case eWNI_SME_DISASSOC_RSP: + return "eWNI_SME_DISASSOC_RSP"; + case eWNI_SME_DISASSOC_IND: + return "eWNI_SME_DISASSOC_IND"; + case eWNI_SME_DISASSOC_CNF: + return "eWNI_SME_DISASSOC_CNF"; + case eWNI_SME_DEAUTH_REQ: + return "eWNI_SME_DEAUTH_REQ"; + case eWNI_SME_DEAUTH_RSP: + return "eWNI_SME_DEAUTH_RSP"; + case eWNI_SME_DEAUTH_IND: + return "eWNI_SME_DEAUTH_IND"; + case eWNI_SME_WM_STATUS_CHANGE_NTF: + return "eWNI_SME_WM_STATUS_CHANGE_NTF"; + case eWNI_SME_START_BSS_REQ: + return "eWNI_SME_START_BSS_REQ"; + case eWNI_SME_START_BSS_RSP: + return "eWNI_SME_START_BSS_RSP"; + case eWNI_SME_ASSOC_IND: + return "eWNI_SME_ASSOC_IND"; + case eWNI_SME_ASSOC_CNF: + return "eWNI_SME_ASSOC_CNF"; + case eWNI_SME_SWITCH_CHL_IND: + return "eWNI_SME_SWITCH_CHL_IND"; + case eWNI_SME_STOP_BSS_REQ: + return "eWNI_SME_STOP_BSS_REQ"; + case eWNI_SME_STOP_BSS_RSP: + return "eWNI_SME_STOP_BSS_RSP"; + case eWNI_SME_NEIGHBOR_BSS_IND: + return "eWNI_SME_NEIGHBOR_BSS_IND"; + case eWNI_SME_DEAUTH_CNF: + return "eWNI_SME_DEAUTH_CNF"; + case eWNI_SME_ADDTS_REQ: + return "eWNI_SME_ADDTS_REQ"; + case eWNI_SME_ADDTS_RSP: + return "eWNI_SME_ADDTS_RSP"; + case eWNI_SME_DELTS_REQ: + return "eWNI_SME_DELTS_REQ"; + case eWNI_SME_DELTS_RSP: + return "eWNI_SME_DELTS_RSP"; + case eWNI_SME_DELTS_IND: + return "eWNI_SME_DELTS_IND"; + case WMA_SUSPEND_ACTIVITY_RSP: + return "WMA_SUSPEND_ACTIVITY_RSP"; + case SIR_LIM_RETRY_INTERRUPT_MSG: + return "SIR_LIM_RETRY_INTERRUPT_MSG"; + case SIR_BB_XPORT_MGMT_MSG: + return "SIR_BB_XPORT_MGMT_MSG"; + case SIR_LIM_INV_KEY_INTERRUPT_MSG: + return "SIR_LIM_INV_KEY_INTERRUPT_MSG"; + case SIR_LIM_KEY_ID_INTERRUPT_MSG: + return "SIR_LIM_KEY_ID_INTERRUPT_MSG"; + case SIR_LIM_REPLAY_THRES_INTERRUPT_MSG: + return "SIR_LIM_REPLAY_THRES_INTERRUPT_MSG"; + case SIR_LIM_JOIN_FAIL_TIMEOUT: + return "SIR_LIM_JOIN_FAIL_TIMEOUT"; + case SIR_LIM_AUTH_FAIL_TIMEOUT: + return "SIR_LIM_AUTH_FAIL_TIMEOUT"; + case SIR_LIM_AUTH_RSP_TIMEOUT: + return "SIR_LIM_AUTH_RSP_TIMEOUT"; + case SIR_LIM_ASSOC_FAIL_TIMEOUT: + return "SIR_LIM_ASSOC_FAIL_TIMEOUT"; + case SIR_LIM_REASSOC_FAIL_TIMEOUT: + return "SIR_LIM_REASSOC_FAIL_TIMEOUT"; + case SIR_LIM_HEART_BEAT_TIMEOUT: + return "SIR_LIM_HEART_BEAT_TIMEOUT"; + case SIR_LIM_ADDTS_RSP_TIMEOUT: + return "SIR_LIM_ADDTS_RSP_TIMEOUT"; + case SIR_LIM_LINK_TEST_DURATION_TIMEOUT: + return "SIR_LIM_LINK_TEST_DURATION_TIMEOUT"; + case SIR_LIM_HASH_MISS_THRES_TIMEOUT: + return "SIR_LIM_HASH_MISS_THRES_TIMEOUT"; + case SIR_LIM_UPDATE_OLBC_CACHEL_TIMEOUT: + return "SIR_LIM_UPDATE_OLBC_CACHEL_TIMEOUT"; + case SIR_LIM_CNF_WAIT_TIMEOUT: + return "SIR_LIM_CNF_WAIT_TIMEOUT"; + case SIR_LIM_RADAR_DETECT_IND: + return "SIR_LIM_RADAR_DETECT_IND"; + case SIR_LIM_FT_PREAUTH_RSP_TIMEOUT: + return "SIR_LIM_FT_PREAUTH_RSP_TIMEOUT"; + case WNI_CFG_PARAM_UPDATE_IND: + return "WNI_CFG_PARAM_UPDATE_IND"; + case WNI_CFG_DNLD_REQ: + return "WNI_CFG_DNLD_REQ"; + case WNI_CFG_DNLD_CNF: + return "WNI_CFG_DNLD_CNF"; + case WNI_CFG_GET_RSP: + return "WNI_CFG_GET_RSP"; + case WNI_CFG_SET_CNF: + return "WNI_CFG_SET_CNF"; + case WNI_CFG_GET_ATTRIB_RSP: + return "WNI_CFG_GET_ATTRIB_RSP"; + case WNI_CFG_ADD_GRP_ADDR_CNF: + return "WNI_CFG_ADD_GRP_ADDR_CNF"; + case WNI_CFG_DEL_GRP_ADDR_CNF: + return "WNI_CFG_DEL_GRP_ADDR_CNF"; + case ANI_CFG_GET_RADIO_STAT_RSP: + return "ANI_CFG_GET_RADIO_STAT_RSP"; + case ANI_CFG_GET_PER_STA_STAT_RSP: + return "ANI_CFG_GET_PER_STA_STAT_RSP"; + case ANI_CFG_GET_AGG_STA_STAT_RSP: + return "ANI_CFG_GET_AGG_STA_STAT_RSP"; + case ANI_CFG_CLEAR_STAT_RSP: + return "ANI_CFG_CLEAR_STAT_RSP"; + case WNI_CFG_DNLD_RSP: + return "WNI_CFG_DNLD_RSP"; + case WNI_CFG_GET_REQ: + return "WNI_CFG_GET_REQ"; + case WNI_CFG_SET_REQ: + return "WNI_CFG_SET_REQ"; + case WNI_CFG_SET_REQ_NO_RSP: + return "WNI_CFG_SET_REQ_NO_RSP"; + case eWNI_PMC_ENTER_IMPS_RSP: + return "eWNI_PMC_ENTER_IMPS_RSP"; + case eWNI_PMC_EXIT_IMPS_RSP: + return "eWNI_PMC_EXIT_IMPS_RSP"; + case eWNI_PMC_ENTER_BMPS_RSP: + return "eWNI_PMC_ENTER_BMPS_RSP"; + case eWNI_PMC_EXIT_BMPS_RSP: + return "eWNI_PMC_EXIT_BMPS_RSP"; + case eWNI_PMC_EXIT_BMPS_IND: + return "eWNI_PMC_EXIT_BMPS_IND"; + case eWNI_SME_SET_BCN_FILTER_REQ: + return "eWNI_SME_SET_BCN_FILTER_REQ"; +#ifdef FEATURE_WLAN_ESE + case eWNI_SME_GET_TSM_STATS_REQ: + return "eWNI_SME_GET_TSM_STATS_REQ"; + case eWNI_SME_GET_TSM_STATS_RSP: + return "eWNI_SME_GET_TSM_STATS_RSP"; +#endif /* FEATURE_WLAN_ESE */ + case eWNI_SME_CSA_OFFLOAD_EVENT: + return "eWNI_SME_CSA_OFFLOAD_EVENT"; + case eWNI_SME_SET_HW_MODE_REQ: + return "eWNI_SME_SET_HW_MODE_REQ"; + case eWNI_SME_SET_HW_MODE_RESP: + return "eWNI_SME_SET_HW_MODE_RESP"; + case eWNI_SME_HW_MODE_TRANS_IND: + return "eWNI_SME_HW_MODE_TRANS_IND"; + default: + return "INVALID SME message"; + } +#endif + return ""; +} + +char *lim_result_code_str(tSirResultCodes resultCode) +{ + switch (resultCode) { + case eSIR_SME_SUCCESS: + return "eSIR_SME_SUCCESS"; + case eSIR_LOGP_EXCEPTION: + return "eSIR_LOGP_EXCEPTION"; + case eSIR_SME_INVALID_PARAMETERS: + return "eSIR_SME_INVALID_PARAMETERS"; + case eSIR_SME_UNEXPECTED_REQ_RESULT_CODE: + return "eSIR_SME_UNEXPECTED_REQ_RESULT_CODE"; + case eSIR_SME_RESOURCES_UNAVAILABLE: + return "eSIR_SME_RESOURCES_UNAVAILABLE"; + case eSIR_SME_SCAN_FAILED: + return "eSIR_SME_SCAN_FAILED"; + case eSIR_SME_BSS_ALREADY_STARTED_OR_JOINED: + return "eSIR_SME_BSS_ALREADY_STARTED_OR_JOINED"; + case eSIR_SME_LOST_LINK_WITH_PEER_RESULT_CODE: + return "eSIR_SME_LOST_LINK_WITH_PEER_RESULT_CODE"; + case eSIR_SME_REFUSED: + return "eSIR_SME_REFUSED"; + case eSIR_SME_JOIN_TIMEOUT_RESULT_CODE: + return "eSIR_SME_JOIN_TIMEOUT_RESULT_CODE"; + case eSIR_SME_AUTH_TIMEOUT_RESULT_CODE: + return "eSIR_SME_AUTH_TIMEOUT_RESULT_CODE"; + case eSIR_SME_ASSOC_TIMEOUT_RESULT_CODE: + return "eSIR_SME_ASSOC_TIMEOUT_RESULT_CODE"; + case eSIR_SME_REASSOC_TIMEOUT_RESULT_CODE: + return "eSIR_SME_REASSOC_TIMEOUT_RESULT_CODE"; + case eSIR_SME_MAX_NUM_OF_PRE_AUTH_REACHED: + return "eSIR_SME_MAX_NUM_OF_PRE_AUTH_REACHED"; + case eSIR_SME_AUTH_REFUSED: + return "eSIR_SME_AUTH_REFUSED"; + case eSIR_SME_INVALID_WEP_DEFAULT_KEY: + return "eSIR_SME_INVALID_WEP_DEFAULT_KEY"; + case eSIR_SME_ASSOC_REFUSED: + return "eSIR_SME_ASSOC_REFUSED"; + case eSIR_SME_REASSOC_REFUSED: + return "eSIR_SME_REASSOC_REFUSED"; + case eSIR_SME_STA_NOT_AUTHENTICATED: + return "eSIR_SME_STA_NOT_AUTHENTICATED"; + case eSIR_SME_STA_NOT_ASSOCIATED: + return "eSIR_SME_STA_NOT_ASSOCIATED"; + case eSIR_SME_ALREADY_JOINED_A_BSS: + return "eSIR_SME_ALREADY_JOINED_A_BSS"; + case eSIR_SME_MORE_SCAN_RESULTS_FOLLOW: + return "eSIR_SME_MORE_SCAN_RESULTS_FOLLOW"; + case eSIR_SME_INVALID_ASSOC_RSP_RXED: + return "eSIR_SME_INVALID_ASSOC_RSP_RXED"; + case eSIR_SME_MIC_COUNTER_MEASURES: + return "eSIR_SME_MIC_COUNTER_MEASURES"; + case eSIR_SME_ADDTS_RSP_TIMEOUT: + return "eSIR_SME_ADDTS_RSP_TIMEOUT"; + case eSIR_SME_CHANNEL_SWITCH_FAIL: + return "eSIR_SME_CHANNEL_SWITCH_FAIL"; + case eSIR_SME_HAL_SCAN_INIT_FAILED: + return "eSIR_SME_HAL_SCAN_INIT_FAILED"; + case eSIR_SME_HAL_SCAN_END_FAILED: + return "eSIR_SME_HAL_SCAN_END_FAILED"; + case eSIR_SME_HAL_SCAN_FINISH_FAILED: + return "eSIR_SME_HAL_SCAN_FINISH_FAILED"; + case eSIR_SME_HAL_SEND_MESSAGE_FAIL: + return "eSIR_SME_HAL_SEND_MESSAGE_FAIL"; + + default: + return "INVALID resultCode"; + } +} + +void lim_print_msg_name(tpAniSirGlobal pMac, uint16_t logLevel, uint32_t msgType) +{ + lim_log(pMac, logLevel, lim_msg_str(msgType)); +} + +/** + * lim_init_mlm() - This function is called by limProcessSmeMessages() to + * initialize MLM state machine on STA + * @pMac: Pointer to Global MAC structure + * + * @Return: Status of operation + */ +tSirRetStatus lim_init_mlm(tpAniSirGlobal pMac) +{ + uint32_t retVal; + + pMac->lim.gLimTimersCreated = 0; + + MTRACE(mac_trace(pMac, TRACE_CODE_MLM_STATE, NO_SESSION, + pMac->lim.gLimMlmState)); + + /* Initialize number of pre-auth contexts */ + pMac->lim.gLimNumPreAuthContexts = 0; + + /* Initialize MAC based Authentication STA list */ + lim_init_pre_auth_list(pMac); + + /* Create timers used by LIM */ + retVal = lim_create_timers(pMac); + if (retVal != TX_SUCCESS) { + lim_log(pMac, LOGP, FL("lim_create_timers Failed")); + return eSIR_SUCCESS; + } + + pMac->lim.gLimTimersCreated = 1; + return eSIR_SUCCESS; +} /*** end lim_init_mlm() ***/ + +/** + * lim_deactivate_del_sta() - This function deactivate/delete associates STA + * @mac_ctx: pointer to Global Mac Structure + * @bss_entry: index for bss_entry + * @psession_entry: pointer to session entry + * @sta_ds: pointer to tpDphHashNode + * + * Function deactivate/delete associates STA + * + * Return: none + */ +static void lim_deactivate_del_sta(tpAniSirGlobal mac_ctx, uint32_t bss_entry, + tpPESession psession_entry, tpDphHashNode sta_ds) +{ + uint32_t sta_entry; + + for (sta_entry = 1; sta_entry < mac_ctx->lim.gLimAssocStaLimit; + sta_entry++) { + psession_entry = &mac_ctx->lim.gpSession[bss_entry]; + sta_ds = dph_get_hash_entry(mac_ctx, sta_entry, + &psession_entry->dph.dphHashTable); + if (NULL == sta_ds) + continue; + + QDF_TRACE(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_ERROR, + FL("Deleting pmfSaQueryTimer for staid[%d]"), + sta_ds->staIndex); + tx_timer_deactivate(&sta_ds->pmfSaQueryTimer); + tx_timer_delete(&sta_ds->pmfSaQueryTimer); + } +} + +/** + * lim_cleanup_mlm() - This function is called to cleanup + * @mac_ctx: Pointer to Global MAC structure + * + * Function is called to cleanup any resources allocated by the MLM + * state machine. + * + * Return: none + */ +void lim_cleanup_mlm(tpAniSirGlobal mac_ctx) +{ + uint32_t n; + tLimPreAuthNode **pAuthNode; +#ifdef WLAN_FEATURE_11W + uint32_t bss_entry; + tpDphHashNode sta_ds = NULL; + tpPESession psession_entry = NULL; +#endif + tLimTimers *lim_timer = NULL; + + if (mac_ctx->lim.gLimTimersCreated == 1) { + lim_timer = &mac_ctx->lim.limTimers; + + lim_delete_timers_host_roam(mac_ctx); + /* Deactivate and delete Periodic Probe channel timers. */ + tx_timer_deactivate(&lim_timer->gLimPeriodicProbeReqTimer); + tx_timer_delete(&lim_timer->gLimPeriodicProbeReqTimer); + + /* Deactivate and delete channel switch timer. */ + tx_timer_deactivate(&lim_timer->gLimChannelSwitchTimer); + tx_timer_delete(&lim_timer->gLimChannelSwitchTimer); + + /* Deactivate and delete addts response timer. */ + tx_timer_deactivate(&lim_timer->gLimAddtsRspTimer); + tx_timer_delete(&lim_timer->gLimAddtsRspTimer); + + /* Deactivate and delete Join failure timer. */ + tx_timer_deactivate(&lim_timer->gLimJoinFailureTimer); + tx_timer_delete(&lim_timer->gLimJoinFailureTimer); + + /* Deactivate and delete Periodic Join Probe Request timer. */ + tx_timer_deactivate(&lim_timer->gLimPeriodicJoinProbeReqTimer); + tx_timer_delete(&lim_timer->gLimPeriodicJoinProbeReqTimer); + + /* Deactivate and delete Auth Retry timer. */ + tx_timer_deactivate + (&lim_timer->g_lim_periodic_auth_retry_timer); + tx_timer_delete(&lim_timer->g_lim_periodic_auth_retry_timer); + + /* Deactivate and delete Association failure timer. */ + tx_timer_deactivate(&lim_timer->gLimAssocFailureTimer); + tx_timer_delete(&lim_timer->gLimAssocFailureTimer); + + /* Deactivate and delete Authentication failure timer. */ + tx_timer_deactivate(&lim_timer->gLimAuthFailureTimer); + tx_timer_delete(&lim_timer->gLimAuthFailureTimer); + + /* Deactivate and delete wait-for-probe-after-Heartbeat timer. */ + tx_timer_deactivate(&lim_timer->gLimProbeAfterHBTimer); + tx_timer_delete(&lim_timer->gLimProbeAfterHBTimer); + + /* Deactivate and delete Quiet timer. */ + tx_timer_deactivate(&lim_timer->gLimQuietTimer); + tx_timer_delete(&lim_timer->gLimQuietTimer); + + /* Deactivate and delete Quiet BSS timer. */ + tx_timer_deactivate(&lim_timer->gLimQuietBssTimer); + tx_timer_delete(&lim_timer->gLimQuietBssTimer); + + /* Deactivate and delete cnf wait timer */ + for (n = 0; n < (mac_ctx->lim.maxStation + 1); n++) { + tx_timer_deactivate(&lim_timer->gpLimCnfWaitTimer[n]); + tx_timer_delete(&lim_timer->gpLimCnfWaitTimer[n]); + } + + pAuthNode = mac_ctx->lim.gLimPreAuthTimerTable.pTable; + + /* Deactivate any Authentication response timers */ + lim_delete_pre_auth_list(mac_ctx); + + /* Delete any Auth rsp timers, which might have been started */ + for (n = 0; n < mac_ctx->lim.gLimPreAuthTimerTable.numEntry; + n++) + tx_timer_delete(&pAuthNode[n]->timer); + + tx_timer_deactivate(&lim_timer->gLimUpdateOlbcCacheTimer); + tx_timer_delete(&lim_timer->gLimUpdateOlbcCacheTimer); + tx_timer_deactivate(&lim_timer->gLimPreAuthClnupTimer); + tx_timer_delete(&lim_timer->gLimPreAuthClnupTimer); + + /* Deactivate and delete remain on channel timer */ + tx_timer_deactivate(&lim_timer->gLimRemainOnChannelTimer); + tx_timer_delete(&lim_timer->gLimRemainOnChannelTimer); + + + tx_timer_deactivate(&lim_timer->gLimDisassocAckTimer); + tx_timer_delete(&lim_timer->gLimDisassocAckTimer); + + tx_timer_deactivate(&lim_timer->gLimDeauthAckTimer); + tx_timer_delete(&lim_timer->gLimDeauthAckTimer); + + tx_timer_deactivate(&lim_timer-> + gLimP2pSingleShotNoaInsertTimer); + tx_timer_delete(&lim_timer-> + gLimP2pSingleShotNoaInsertTimer); + + tx_timer_deactivate(&lim_timer-> + gLimActiveToPassiveChannelTimer); + tx_timer_delete(&lim_timer-> + gLimActiveToPassiveChannelTimer); + + mac_ctx->lim.gLimTimersCreated = 0; + } +#ifdef WLAN_FEATURE_11W + /* + * When SSR is triggered, we need to loop through + * each STA associated per BSSId and deactivate/delete + * the pmfSaQueryTimer for it + */ + for (bss_entry = 0; bss_entry < mac_ctx->lim.maxBssId; + bss_entry++) { + if (!mac_ctx->lim.gpSession[bss_entry].valid) + continue; + lim_deactivate_del_sta(mac_ctx, bss_entry, + psession_entry, sta_ds); + } +#endif + +} /*** end lim_cleanup_mlm() ***/ + +/** + * lim_is_addr_bc() + * + ***FUNCTION: + * This function is called in various places within LIM code + * to determine whether passed MAC address is a broadcast or not + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param macAddr Indicates MAC address that need to be determined + * whether it is Broadcast address or not + * + * @return true if passed address is Broadcast address else false + */ + +uint8_t lim_is_addr_bc(tSirMacAddr macAddr) +{ + int i; + for (i = 0; i < 6; i++) { + if ((macAddr[i] & 0xFF) != 0xFF) + return false; + } + + return true; +} /****** end lim_is_addr_bc() ******/ + +/** + * lim_is_group_addr() + * + ***FUNCTION: + * This function is called in various places within LIM code + * to determine whether passed MAC address is a group address or not + * + ***LOGIC: + * If least significant bit of first octet of the MAC address is + * set to 1, it is a Group address. + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param macAddr Indicates MAC address that need to be determined + * whether it is Group address or not + * + * @return true if passed address is Group address else false + */ + +uint8_t lim_is_group_addr(tSirMacAddr macAddr) +{ + if ((macAddr[0] & 0x01) == 0x01) + return true; + else + return false; +} /****** end lim_is_group_addr() ******/ + +/** + * lim_print_mac_addr() + * + ***FUNCTION: + * This function is called to print passed MAC address + * in : format. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * @param macAddr - MacAddr to be printed + * @param logLevel - Loglevel to be used + * + * @return None. + */ + +void lim_print_mac_addr(tpAniSirGlobal pMac, tSirMacAddr macAddr, uint8_t logLevel) +{ + lim_log(pMac, logLevel, FL(MAC_ADDRESS_STR), MAC_ADDR_ARRAY(macAddr)); +} /****** end lim_print_mac_addr() ******/ + +/* + * lim_reset_deferred_msg_q() + * + ***FUNCTION: + * This function resets the deferred message queue parameters. + * + ***PARAMS: + * @param pMac - Pointer to Global MAC structure + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + ***RETURNS: + * None + */ + +void lim_reset_deferred_msg_q(tpAniSirGlobal pMac) +{ + tSirMsgQ *read_msg; + + if (pMac->lim.gLimDeferredMsgQ.size > 0) { + while ((read_msg = lim_read_deferred_msg_q(pMac)) != NULL) { + pe_free_msg(pMac, read_msg); + } + } + + pMac->lim.gLimDeferredMsgQ.size = + pMac->lim.gLimDeferredMsgQ.write = + pMac->lim.gLimDeferredMsgQ.read = 0; + +} + +#define LIM_DEFERRED_Q_CHECK_THRESHOLD (MAX_DEFERRED_QUEUE_LEN/2) +#define LIM_MAX_NUM_MGMT_FRAME_DEFERRED (MAX_DEFERRED_QUEUE_LEN/2) + +/** + * lim_write_deferred_msg_q() - This function queues up a deferred message + * + * @mac_ctx: Pointer to Global MAC structure + * @lim_msg: a LIM message + * + * Function queues up a deferred message for later processing on the + * STA side. + * + * Return: none + */ + +uint8_t lim_write_deferred_msg_q(tpAniSirGlobal mac_ctx, tpSirMsgQ lim_msg) +{ + uint8_t type, subtype; + + pe_debug("Queue a deferred message size: %d write: %d - type: 0x%x", + mac_ctx->lim.gLimDeferredMsgQ.size, + mac_ctx->lim.gLimDeferredMsgQ.write, + lim_msg->type); + + /* check if the deferred message queue is full */ + if (mac_ctx->lim.gLimDeferredMsgQ.size >= MAX_DEFERRED_QUEUE_LEN) { + if (!(mac_ctx->lim.deferredMsgCnt & 0xF)) { + lim_log(mac_ctx, LOGE, + FL("queue->MsgQ full Msg:%d Msgs Failed:%d"), + lim_msg->type, + ++mac_ctx->lim.deferredMsgCnt); + cds_flush_logs(WLAN_LOG_TYPE_NON_FATAL, + WLAN_LOG_INDICATOR_HOST_DRIVER, + WLAN_LOG_REASON_QUEUE_FULL, + true, false); + } else { + mac_ctx->lim.deferredMsgCnt++; + } + return TX_QUEUE_FULL; + } + + /* + * In the application, there should not be more than 1 message get + * queued up. If happens, flags a warning. In the future, this can + * happen. + */ + if (mac_ctx->lim.gLimDeferredMsgQ.size > 0) + lim_log(mac_ctx, LOGW, + FL("%d Deferred Msg (type 0x%x, scan %d, global sme %d, global mlme %d, addts %d)"), + mac_ctx->lim.gLimDeferredMsgQ.size, + lim_msg->type, + lim_is_system_in_scan_state(mac_ctx), + mac_ctx->lim.gLimSmeState, + mac_ctx->lim.gLimMlmState, + mac_ctx->lim.gLimAddtsSent); + + if (SIR_BB_XPORT_MGMT_MSG == lim_msg->type) { + lim_util_get_type_subtype(lim_msg->bodyptr, + &type, &subtype); + pe_debug(" Deferred managment type %d subtype %d ", + type, subtype); + } + + /* + * To prevent the deferred Q is full of management frames, only give + * them certain space + */ + if ((SIR_BB_XPORT_MGMT_MSG == lim_msg->type) && + (LIM_DEFERRED_Q_CHECK_THRESHOLD < + mac_ctx->lim.gLimDeferredMsgQ.size)) { + uint16_t idx, count = 0; + for (idx = 0; idx < mac_ctx->lim.gLimDeferredMsgQ.size; + idx++) { + if (SIR_BB_XPORT_MGMT_MSG == + mac_ctx->lim.gLimDeferredMsgQ. + deferredQueue[idx].type) { + count++; + } + } + if (LIM_MAX_NUM_MGMT_FRAME_DEFERRED < count) { + /* + * We reach the quota for management frames, + * drop this one + */ + lim_log(mac_ctx, LOGW, + FL("Too many queue->MsgQ Msg: %d (count=%d)"), + lim_msg->type, count); + /* Return error, caller knows what to do */ + return TX_QUEUE_FULL; + } + } + + ++mac_ctx->lim.gLimDeferredMsgQ.size; + + /* reset the count here since we are able to defer the message */ + if (mac_ctx->lim.deferredMsgCnt != 0) + mac_ctx->lim.deferredMsgCnt = 0; + + /* if the write pointer hits the end of the queue, rewind it */ + if (mac_ctx->lim.gLimDeferredMsgQ.write >= MAX_DEFERRED_QUEUE_LEN) + mac_ctx->lim.gLimDeferredMsgQ.write = 0; + + /* save the message to the queue and advanced the write pointer */ + qdf_mem_copy((uint8_t *) &mac_ctx->lim.gLimDeferredMsgQ. + deferredQueue[mac_ctx->lim.gLimDeferredMsgQ.write++], + (uint8_t *) lim_msg, sizeof(tSirMsgQ)); + return TX_SUCCESS; + +} + +/* + * lim_read_deferred_msg_q() + * + ***FUNCTION: + * This function dequeues a deferred message for processing on the + * STA side. + * + ***PARAMS: + * @param pMac - Pointer to Global MAC structure + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * + * + ***RETURNS: + * Returns the message at the head of the deferred message queue + */ + +tSirMsgQ *lim_read_deferred_msg_q(tpAniSirGlobal pMac) +{ + tSirMsgQ *msg; + + /* + ** check any messages left. If no, return + **/ + if (pMac->lim.gLimDeferredMsgQ.size <= 0) + return NULL; + + /* + ** decrement the queue size + **/ + pMac->lim.gLimDeferredMsgQ.size--; + + /* + ** retrieve the message from the head of the queue + **/ + msg = + &pMac->lim.gLimDeferredMsgQ.deferredQueue[pMac->lim. + gLimDeferredMsgQ.read]; + + /* + ** advance the read pointer + **/ + pMac->lim.gLimDeferredMsgQ.read++; + + /* + ** if the read pointer hits the end of the queue, rewind it + **/ + if (pMac->lim.gLimDeferredMsgQ.read >= MAX_DEFERRED_QUEUE_LEN) + pMac->lim.gLimDeferredMsgQ.read = 0; + + PELOG1(lim_log(pMac, LOG1, + FL + ("** DeQueue a deferred message (size %d read %d) - type 0x%x **"), + pMac->lim.gLimDeferredMsgQ.size, + pMac->lim.gLimDeferredMsgQ.read, msg->type); + ) + + PELOG1(lim_log + (pMac, LOG1, + FL + ("DQ msg -- scan %d, global sme %d, global mlme %d, addts %d"), + lim_is_system_in_scan_state(pMac), pMac->lim.gLimSmeState, + pMac->lim.gLimMlmState, pMac->lim.gLimAddtsSent); + ) + + return msg; +} + +tSirRetStatus +lim_sys_process_mmh_msg_api(tpAniSirGlobal pMac, tSirMsgQ *pMsg, uint8_t qType) +{ + /* FIXME */ + sys_process_mmh_msg(pMac, pMsg); + return eSIR_SUCCESS; +} + +/* + * lim_handle_update_olbc_cache() - This function update olbc cache + * + * @mac_ctx: Pointer to Global MAC structure + * + * Function updates olbc cache + * + * Return: none + */ +void lim_handle_update_olbc_cache(tpAniSirGlobal mac_ctx) +{ + int i; + static int enable; + tUpdateBeaconParams beaconParams; + + tpPESession psessionEntry = lim_is_ap_session_active(mac_ctx); + + if (psessionEntry == NULL) { + lim_log(mac_ctx, LOGE, FL(" Session not found")); + return; + } + + qdf_mem_set((uint8_t *) &beaconParams, sizeof(tUpdateBeaconParams), 0); + beaconParams.bssIdx = psessionEntry->bssIdx; + + beaconParams.paramChangeBitmap = 0; + /* + * This is doing a 2 pass check. The first pass is to invalidate + * all the cache entries. The second pass is to decide whether to + * disable protection. + */ + if (!enable) { + lim_log(mac_ctx, LOG2, FL("Resetting OLBC cache")); + psessionEntry->gLimOlbcParams.numSta = 0; + psessionEntry->gLimOverlap11gParams.numSta = 0; + psessionEntry->gLimOverlapHt20Params.numSta = 0; + psessionEntry->gLimNonGfParams.numSta = 0; + psessionEntry->gLimLsigTxopParams.numSta = 0; + + for (i = 0; i < LIM_PROT_STA_OVERLAP_CACHE_SIZE; i++) + mac_ctx->lim.protStaOverlapCache[i].active = false; + + enable = 1; + } else { + if ((!psessionEntry->gLimOlbcParams.numSta) && + (psessionEntry->gLimOlbcParams.protectionEnabled) && + (!psessionEntry->gLim11bParams.protectionEnabled)) { + lim_log(mac_ctx, LOG1, + FL("Overlap cache clear and no 11B STA set")); + lim_enable11g_protection(mac_ctx, false, true, + &beaconParams, + psessionEntry); + } + + if ((!psessionEntry->gLimOverlap11gParams.numSta) && + (psessionEntry->gLimOverlap11gParams.protectionEnabled) + && (!psessionEntry->gLim11gParams.protectionEnabled)) { + lim_log(mac_ctx, LOG1, + FL("Overlap cache clear and no 11G STA set")); + lim_enable_ht_protection_from11g(mac_ctx, false, true, + &beaconParams, + psessionEntry); + } + + if ((!psessionEntry->gLimOverlapHt20Params.numSta) && + (psessionEntry->gLimOverlapHt20Params.protectionEnabled) + && (!psessionEntry->gLimHt20Params.protectionEnabled)) { + lim_log(mac_ctx, LOG1, + FL("Overlap cache clear and no HT20 STA set")); + lim_enable11g_protection(mac_ctx, false, true, + &beaconParams, + psessionEntry); + } + + enable = 0; + } + + if ((false == mac_ctx->sap.SapDfsInfo.is_dfs_cac_timer_running) + && beaconParams.paramChangeBitmap) { + sch_set_fixed_beacon_fields(mac_ctx, psessionEntry); + lim_send_beacon_params(mac_ctx, &beaconParams, psessionEntry); + } + /* Start OLBC timer */ + if (tx_timer_activate(&mac_ctx->lim.limTimers.gLimUpdateOlbcCacheTimer) + != TX_SUCCESS) + lim_log(mac_ctx, LOGE, FL("tx_timer_activate failed")); +} + +/** + * lim_is_null_ssid() - This function checks if ssid supplied is Null SSID + * @ssid: pointer to tSirMacSSid + * + * Function checks if ssid supplied is Null SSID + * + * Return: none + */ + +uint8_t lim_is_null_ssid(tSirMacSSid *ssid) +{ + uint8_t fnull_ssid = false; + uint32_t ssid_len; + uint8_t *ssid_str; + + if (0 == ssid->length) { + fnull_ssid = true; + return fnull_ssid; + } + /* If the first charactes is space, then check if all + * characters in SSID are spaces to consider it as NULL SSID + */ + if ((ASCII_SPACE_CHARACTER == ssid->ssId[0]) && + (ssid->length == 1)) { + fnull_ssid = true; + return fnull_ssid; + } else { + /* check if all the charactes in SSID are NULL */ + ssid_len = ssid->length; + ssid_str = ssid->ssId; + + while (ssid_len) { + if (*ssid_str) + return fnull_ssid; + + ssid_str++; + ssid_len--; + } + + if (0 == ssid_len) { + fnull_ssid = true; + return fnull_ssid; + } + } + + return fnull_ssid; +} + +/** ------------------------------------------------------------- + \fn lim_update_prot_sta_params + \brief updates protection related counters. + \param tpAniSirGlobal pMac + \param tSirMacAddr peerMacAddr + \param tLimProtStaCacheType protStaCacheType + \param tHalBitVal gfSupported + \param tHalBitVal lsigTxopSupported + \return None + -------------------------------------------------------------*/ +static void +lim_update_prot_sta_params(tpAniSirGlobal pMac, + tSirMacAddr peerMacAddr, + tLimProtStaCacheType protStaCacheType, + tHalBitVal gfSupported, tHalBitVal lsigTxopSupported, + tpPESession psessionEntry) +{ + uint32_t i; + + PELOG1(lim_log(pMac, LOG1, FL("A STA is associated:")); + lim_log(pMac, LOG1, FL("Addr : ")); + lim_print_mac_addr(pMac, peerMacAddr, LOG1); + ) + + for (i = 0; i < LIM_PROT_STA_CACHE_SIZE; i++) { + if (psessionEntry->protStaCache[i].active) { + PELOG1(lim_log(pMac, LOG1, FL("Addr: "));) + PELOG1(lim_print_mac_addr + (pMac, psessionEntry->protStaCache[i].addr, + LOG1); + ) + + if (!qdf_mem_cmp + (psessionEntry->protStaCache[i].addr, + peerMacAddr, sizeof(tSirMacAddr))) { + PELOG1(lim_log + (pMac, LOG1, + FL + ("matching cache entry at %d already active."), + i); + ) + return; + } + } + } + + for (i = 0; i < LIM_PROT_STA_CACHE_SIZE; i++) { + if (!psessionEntry->protStaCache[i].active) + break; + } + + if (i >= LIM_PROT_STA_CACHE_SIZE) { + PELOGE(lim_log(pMac, LOGE, FL("No space in ProtStaCache"));) + return; + } + + qdf_mem_copy(psessionEntry->protStaCache[i].addr, + peerMacAddr, sizeof(tSirMacAddr)); + + psessionEntry->protStaCache[i].protStaCacheType = protStaCacheType; + psessionEntry->protStaCache[i].active = true; + if (eLIM_PROT_STA_CACHE_TYPE_llB == protStaCacheType) { + psessionEntry->gLim11bParams.numSta++; + lim_log(pMac, LOG1, FL("11B, ")); + } else if (eLIM_PROT_STA_CACHE_TYPE_llG == protStaCacheType) { + psessionEntry->gLim11gParams.numSta++; + lim_log(pMac, LOG1, FL("11G, ")); + } else if (eLIM_PROT_STA_CACHE_TYPE_HT20 == protStaCacheType) { + psessionEntry->gLimHt20Params.numSta++; + lim_log(pMac, LOG1, FL("HT20, ")); + } + + if (!gfSupported) { + psessionEntry->gLimNonGfParams.numSta++; + lim_log(pMac, LOG1, FL("NonGf, ")); + } + if (!lsigTxopSupported) { + psessionEntry->gLimLsigTxopParams.numSta++; + lim_log(pMac, LOG1, FL("!lsigTxopSupported")); + } +} /* --------------------------------------------------------------------- */ + +/** ------------------------------------------------------------- + \fn lim_decide_ap_protection + \brief Decides all the protection related staiton coexistence and also sets + \ short preamble and short slot appropriately. This function will be called + \ when AP is ready to send assocRsp tp the station joining right now. + \param tpAniSirGlobal pMac + \param tSirMacAddr peerMacAddr + \return None + -------------------------------------------------------------*/ +void +lim_decide_ap_protection(tpAniSirGlobal pMac, tSirMacAddr peerMacAddr, + tpUpdateBeaconParams pBeaconParams, + tpPESession psessionEntry) +{ + uint16_t tmpAid; + tpDphHashNode pStaDs; + tSirRFBand rfBand = SIR_BAND_UNKNOWN; + uint32_t phyMode; + tLimProtStaCacheType protStaCacheType = + eLIM_PROT_STA_CACHE_TYPE_INVALID; + tHalBitVal gfSupported = eHAL_SET, lsigTxopSupported = eHAL_SET; + + pBeaconParams->paramChangeBitmap = 0; + /* check whether to enable protection or not */ + pStaDs = + dph_lookup_hash_entry(pMac, peerMacAddr, &tmpAid, + &psessionEntry->dph.dphHashTable); + if (NULL == pStaDs) { + PELOG1(lim_log(pMac, LOG1, FL("pStaDs is NULL"));) + return; + } + lim_get_rf_band_new(pMac, &rfBand, psessionEntry); + /* if we are in 5 GHZ band */ + if (SIR_BAND_5_GHZ == rfBand) { + /* We are 11N. we need to protect from 11A and Ht20. we don't need any other protection in 5 GHZ. */ + /* HT20 case is common between both the bands and handled down as common code. */ + if (true == psessionEntry->htCapability) { + /* we are 11N and 11A station is joining. */ + /* protection from 11A required. */ + if (false == pStaDs->mlmStaContext.htCapability) { + lim_update_11a_protection(pMac, true, false, + pBeaconParams, + psessionEntry); + return; + } + } + } else if (SIR_BAND_2_4_GHZ == rfBand) { + lim_get_phy_mode(pMac, &phyMode, psessionEntry); + + /* We are 11G. Check if we need protection from 11b Stations. */ + if ((phyMode == WNI_CFG_PHY_MODE_11G) && + (false == psessionEntry->htCapability)) { + + if (pStaDs->erpEnabled == eHAL_CLEAR) { + protStaCacheType = eLIM_PROT_STA_CACHE_TYPE_llB; + /* enable protection */ + PELOG3(lim_log + (pMac, LOG3, + FL("Enabling protection from 11B")); + ) + lim_enable11g_protection(pMac, true, false, + pBeaconParams, + psessionEntry); + } + } + /* HT station. */ + if (true == psessionEntry->htCapability) { + /* check if we need protection from 11b station */ + if ((pStaDs->erpEnabled == eHAL_CLEAR) && + (!pStaDs->mlmStaContext.htCapability)) { + protStaCacheType = eLIM_PROT_STA_CACHE_TYPE_llB; + /* enable protection */ + PELOG3(lim_log + (pMac, LOG3, + FL("Enabling protection from 11B")); + ) + lim_enable11g_protection(pMac, true, false, + pBeaconParams, + psessionEntry); + } + /* station being joined is non-11b and non-ht ==> 11g device */ + else if (!pStaDs->mlmStaContext.htCapability) { + protStaCacheType = eLIM_PROT_STA_CACHE_TYPE_llG; + /* enable protection */ + lim_enable_ht_protection_from11g(pMac, true, false, + pBeaconParams, + psessionEntry); + } + /* ERP mode is enabled for the latest station joined */ + /* latest station joined is HT capable */ + /* This case is being handled in common code (commn between both the bands) below. */ + } + } + /* we are HT and HT station is joining. This code is common for both the bands. */ + if ((true == psessionEntry->htCapability) && + (true == pStaDs->mlmStaContext.htCapability)) { + if (!pStaDs->htGreenfield) { + lim_enable_ht_non_gf_protection(pMac, true, false, + pBeaconParams, + psessionEntry); + gfSupported = eHAL_CLEAR; + } + /* Station joining is HT 20Mhz */ + if ((eHT_CHANNEL_WIDTH_20MHZ == + pStaDs->htSupportedChannelWidthSet) && + (eHT_CHANNEL_WIDTH_20MHZ != + psessionEntry->htSupportedChannelWidthSet)){ + protStaCacheType = eLIM_PROT_STA_CACHE_TYPE_HT20; + lim_enable_ht20_protection(pMac, true, false, + pBeaconParams, psessionEntry); + } + /* Station joining does not support LSIG TXOP Protection */ + if (!pStaDs->htLsigTXOPProtection) { + lim_enable_ht_lsig_txop_protection(pMac, false, false, + pBeaconParams, + psessionEntry); + lsigTxopSupported = eHAL_CLEAR; + } + } + + lim_update_prot_sta_params(pMac, peerMacAddr, protStaCacheType, + gfSupported, lsigTxopSupported, psessionEntry); + + return; +} + +/** ------------------------------------------------------------- + \fn lim_enable_overlap11g_protection + \brief wrapper function for setting overlap 11g protection. + \param tpAniSirGlobal pMac + \param tpUpdateBeaconParams pBeaconParams + \param tpSirMacMgmtHdr pMh + \return None + -------------------------------------------------------------*/ +void +lim_enable_overlap11g_protection(tpAniSirGlobal pMac, + tpUpdateBeaconParams pBeaconParams, + tpSirMacMgmtHdr pMh, tpPESession psessionEntry) +{ + lim_update_overlap_sta_param(pMac, pMh->bssId, + &(psessionEntry->gLimOlbcParams)); + + if (psessionEntry->gLimOlbcParams.numSta && + !psessionEntry->gLimOlbcParams.protectionEnabled) { + /* enable protection */ + PELOG1(lim_log(pMac, LOG1, FL("OLBC happens!!!"));) + lim_enable11g_protection(pMac, true, true, pBeaconParams, + psessionEntry); + } +} + +/** + * lim_update_short_preamble() - This function Updates short preamble + * @mac_ctx: pointer to Global MAC structure + * @peer_mac_addr: pointer to tSirMacAddr + * @pbeaconparams: pointer to tpUpdateBeaconParams + * @psession_entry: pointer to tpPESession + * + * Function Updates short preamble if needed when a new station joins + * + * Return: none + */ +void +lim_update_short_preamble(tpAniSirGlobal mac_ctx, tSirMacAddr peer_mac_addr, + tpUpdateBeaconParams beaconparams, + tpPESession psession_entry) +{ + uint16_t aid; + tpDphHashNode sta_ds; + uint32_t phy_mode; + uint16_t i; + + /* check whether to enable protection or not */ + sta_ds = + dph_lookup_hash_entry(mac_ctx, peer_mac_addr, &aid, + &psession_entry->dph.dphHashTable); + + lim_get_phy_mode(mac_ctx, &phy_mode, psession_entry); + + if (sta_ds == NULL || phy_mode != WNI_CFG_PHY_MODE_11G) + return; + + if (sta_ds->shortPreambleEnabled != eHAL_CLEAR) + return; + + lim_log(mac_ctx, LOG1, + FL("Short Preamble is not enabled in Assoc Req from ")); + + lim_print_mac_addr(mac_ctx, peer_mac_addr, LOG1); + + for (i = 0; i < LIM_PROT_STA_CACHE_SIZE; i++) { + if (LIM_IS_AP_ROLE(psession_entry) && + (psession_entry->gLimNoShortParams. + staNoShortCache[i].active) && + (!qdf_mem_cmp + (psession_entry->gLimNoShortParams. + staNoShortCache[i].addr, + peer_mac_addr, sizeof(tSirMacAddr)))) + return; + else if (!LIM_IS_AP_ROLE(psession_entry) && + (mac_ctx->lim.gLimNoShortParams. + staNoShortCache[i].active) && + (!qdf_mem_cmp(mac_ctx->lim.gLimNoShortParams. + staNoShortCache[i].addr, + peer_mac_addr, + sizeof(tSirMacAddr)))) + return; + } + + for (i = 0; i < LIM_PROT_STA_CACHE_SIZE; i++) { + if (LIM_IS_AP_ROLE(psession_entry) && + !psession_entry->gLimNoShortParams. + staNoShortCache[i].active) + break; + else if (!mac_ctx->lim.gLimNoShortParams. + staNoShortCache[i].active) + break; + } + + if (i >= LIM_PROT_STA_CACHE_SIZE) { + tLimNoShortParams *lim_params = + &psession_entry->gLimNoShortParams; + if (LIM_IS_AP_ROLE(psession_entry)) { + lim_log(mac_ctx, LOGE, + FL("No space in Short cache (#active %d, #sta %d) for sta "), + i, + lim_params->numNonShortPreambleSta); + lim_print_mac_addr(mac_ctx, peer_mac_addr, LOGE); + return; + } else { + lim_log(mac_ctx, LOGE, + FL("No space in Short cache (#active %d, #sta %d) for sta "), + i, + lim_params->numNonShortPreambleSta); + lim_print_mac_addr(mac_ctx, peer_mac_addr, LOGE); + return; + } + + } + + if (LIM_IS_AP_ROLE(psession_entry)) { + qdf_mem_copy(psession_entry->gLimNoShortParams. + staNoShortCache[i].addr, + peer_mac_addr, sizeof(tSirMacAddr)); + psession_entry->gLimNoShortParams.staNoShortCache[i]. + active = true; + psession_entry->gLimNoShortParams.numNonShortPreambleSta++; + } else { + qdf_mem_copy(mac_ctx->lim.gLimNoShortParams. + staNoShortCache[i].addr, + peer_mac_addr, sizeof(tSirMacAddr)); + mac_ctx->lim.gLimNoShortParams.staNoShortCache[i].active = true; + mac_ctx->lim.gLimNoShortParams.numNonShortPreambleSta++; + } + + /* enable long preamble */ + lim_log(mac_ctx, LOG1, FL("Disabling short preamble")); + + if (lim_enable_short_preamble(mac_ctx, false, beaconparams, + psession_entry) != eSIR_SUCCESS) + lim_log(mac_ctx, LOGE, FL("Cannot enable long preamble")); +} + +/** + * lim_update_short_slot_time() - This function Updates short slot time + * @mac_ctx: pointer to Global MAC structure + * @peer_mac_addr: pointer to tSirMacAddr + * @beacon_params: pointer to tpUpdateBeaconParams + * @psession_entry: pointer to tpPESession + * + * Function Updates short slot time if needed when a new station joins + * + * Return: None + */ +void +lim_update_short_slot_time(tpAniSirGlobal mac_ctx, tSirMacAddr peer_mac_addr, + tpUpdateBeaconParams beacon_params, + tpPESession session_entry) +{ + uint16_t aid; + tpDphHashNode sta_ds; + uint32_t phy_mode; + uint32_t val; + uint16_t i; + + /* check whether to enable protection or not */ + sta_ds = dph_lookup_hash_entry(mac_ctx, peer_mac_addr, &aid, + &session_entry->dph.dphHashTable); + lim_get_phy_mode(mac_ctx, &phy_mode, session_entry); + + if (sta_ds == NULL || phy_mode != WNI_CFG_PHY_MODE_11G) + return; + + /* + * Only in case of softap in 11g mode, slot time might change + * depending on the STA being added. In 11a case, it should + * be always 1 and in 11b case, it should be always 0. + * Only when the new STA has short slot time disabled, we need to + * change softap's overall slot time settings else the default for + * softap is always short slot enabled. When the last long slot STA + * leaves softAP, we take care of it in lim_decide_short_slot + */ + if (sta_ds->shortSlotTimeEnabled != eHAL_CLEAR) + return; + + lim_log(mac_ctx, LOG1, FL("Short Slot Time is not enabled in Assoc Req from ")); + lim_print_mac_addr(mac_ctx, peer_mac_addr, LOG1); + for (i = 0; i < LIM_PROT_STA_CACHE_SIZE; i++) { + if (LIM_IS_AP_ROLE(session_entry) && + session_entry->gLimNoShortSlotParams. + staNoShortSlotCache[i].active) { + if (!qdf_mem_cmp(session_entry-> + gLimNoShortSlotParams.staNoShortSlotCache[i].addr, + peer_mac_addr, sizeof(tSirMacAddr))) + return; + } else if (!LIM_IS_AP_ROLE(session_entry)) { + if (mac_ctx->lim.gLimNoShortSlotParams. + staNoShortSlotCache[i].active) { + if (!qdf_mem_cmp(mac_ctx-> + lim.gLimNoShortSlotParams. + staNoShortSlotCache[i].addr, + peer_mac_addr, sizeof(tSirMacAddr))) + return; + } + } + } + for (i = 0; i < LIM_PROT_STA_CACHE_SIZE; i++) { + if (LIM_IS_AP_ROLE(session_entry) && + !session_entry->gLimNoShortSlotParams. + staNoShortSlotCache[i].active) + break; + else + if (!mac_ctx->lim.gLimNoShortSlotParams. + staNoShortSlotCache[i].active) + break; + } + + if (i >= LIM_PROT_STA_CACHE_SIZE) { + if (LIM_IS_AP_ROLE(session_entry)) { + lim_log(mac_ctx, LOGE, + FL("No space in ShortSlot cache (#active %d, #sta %d) for sta "), + i, session_entry->gLimNoShortSlotParams. + numNonShortSlotSta); + lim_print_mac_addr(mac_ctx, peer_mac_addr, LOGE); + return; + } else { + lim_log(mac_ctx, LOGE, + FL("No space in ShortSlot cache (#active %d, #sta %d) for sta "), + i, + mac_ctx->lim.gLimNoShortSlotParams. + numNonShortSlotSta); + lim_print_mac_addr(mac_ctx, peer_mac_addr, LOGE); + return; + } + } + + if (LIM_IS_AP_ROLE(session_entry)) { + qdf_mem_copy(session_entry->gLimNoShortSlotParams. + staNoShortSlotCache[i].addr, + peer_mac_addr, sizeof(tSirMacAddr)); + session_entry->gLimNoShortSlotParams. + staNoShortSlotCache[i].active = true; + session_entry->gLimNoShortSlotParams.numNonShortSlotSta++; + } else { + qdf_mem_copy(mac_ctx->lim.gLimNoShortSlotParams. + staNoShortSlotCache[i].addr, + peer_mac_addr, sizeof(tSirMacAddr)); + mac_ctx->lim.gLimNoShortSlotParams. + staNoShortSlotCache[i].active = true; + mac_ctx->lim.gLimNoShortSlotParams. + numNonShortSlotSta++; + } + wlan_cfg_get_int(mac_ctx, WNI_CFG_11G_SHORT_SLOT_TIME_ENABLED, &val); + /* + * Here we check if we are AP role and short slot enabled + * (both admin and oper modes) but we have atleast one STA + * connected with only long slot enabled, we need to change + * our beacon/pb rsp to broadcast short slot disabled + */ + if ((LIM_IS_AP_ROLE(session_entry)) && (val && + session_entry->gLimNoShortSlotParams.numNonShortSlotSta + && session_entry->shortSlotTimeSupported)) { + /* enable long slot time */ + beacon_params->fShortSlotTime = false; + beacon_params->paramChangeBitmap |= + PARAM_SHORT_SLOT_TIME_CHANGED; + lim_log(mac_ctx, LOG1, + FL("Disable short slot time. Enable long slot time.")); + session_entry->shortSlotTimeSupported = false; + } else if (!LIM_IS_AP_ROLE(session_entry) && + (val && mac_ctx->lim.gLimNoShortSlotParams. + numNonShortSlotSta && + session_entry->shortSlotTimeSupported)) { + /* enable long slot time */ + beacon_params->fShortSlotTime = false; + beacon_params->paramChangeBitmap |= + PARAM_SHORT_SLOT_TIME_CHANGED; + lim_log(mac_ctx, LOG1, + FL("Disable short slot time. Enable long slot time.")); + session_entry->shortSlotTimeSupported = false; + } +} + +/** ------------------------------------------------------------- + \fn lim_decide_sta_protection_on_assoc + \brief Decide protection related settings on Sta while association. + \param tpAniSirGlobal pMac + \param tpSchBeaconStruct pBeaconStruct + \return None + -------------------------------------------------------------*/ +void +lim_decide_sta_protection_on_assoc(tpAniSirGlobal pMac, + tpSchBeaconStruct pBeaconStruct, + tpPESession psessionEntry) +{ + tSirRFBand rfBand = SIR_BAND_UNKNOWN; + uint32_t phyMode = WNI_CFG_PHY_MODE_NONE; + + lim_get_rf_band_new(pMac, &rfBand, psessionEntry); + lim_get_phy_mode(pMac, &phyMode, psessionEntry); + + if (SIR_BAND_5_GHZ == rfBand) { + if ((eSIR_HT_OP_MODE_MIXED == pBeaconStruct->HTInfo.opMode) || + (eSIR_HT_OP_MODE_OVERLAP_LEGACY == + pBeaconStruct->HTInfo.opMode)) { + if (pMac->lim.cfgProtection.fromlla) + psessionEntry->beaconParams.llaCoexist = true; + } else if (eSIR_HT_OP_MODE_NO_LEGACY_20MHZ_HT == + pBeaconStruct->HTInfo.opMode) { + if (pMac->lim.cfgProtection.ht20) + psessionEntry->beaconParams.ht20Coexist = true; + } + + } else if (SIR_BAND_2_4_GHZ == rfBand) { + /* spec 7.3.2.13 */ + /* UseProtection will be set when nonERP STA is associated. */ + /* NonERPPresent bit will be set when: */ + /* --nonERP Sta is associated OR */ + /* --nonERP Sta exists in overlapping BSS */ + /* when useProtection is not set then protection from nonERP stations is optional. */ + + /* CFG protection from 11b is enabled and */ + /* 11B device in the BSS */ + /* TODO, This is not sessionized */ + if (phyMode != WNI_CFG_PHY_MODE_11B) { + if (pMac->lim.cfgProtection.fromllb && + pBeaconStruct->erpPresent && + (pBeaconStruct->erpIEInfo.useProtection || + pBeaconStruct->erpIEInfo.nonErpPresent)) { + psessionEntry->beaconParams.llbCoexist = true; + } + /* AP has no 11b station associated. */ + else { + psessionEntry->beaconParams.llbCoexist = false; + } + } + /* following code block is only for HT station. */ + if ((psessionEntry->htCapability) && + (pBeaconStruct->HTInfo.present)) { + tDot11fIEHTInfo htInfo = pBeaconStruct->HTInfo; + + /* Obss Non HT STA present mode */ + psessionEntry->beaconParams.gHTObssMode = + (uint8_t) htInfo.obssNonHTStaPresent; + + /* CFG protection from 11G is enabled and */ + /* our AP has at least one 11G station associated. */ + if (pMac->lim.cfgProtection.fromllg && + ((eSIR_HT_OP_MODE_MIXED == htInfo.opMode) || + (eSIR_HT_OP_MODE_OVERLAP_LEGACY == htInfo.opMode)) + && (!psessionEntry->beaconParams.llbCoexist)) { + if (pMac->lim.cfgProtection.fromllg) + psessionEntry->beaconParams.llgCoexist = + true; + } + /* AP has only HT stations associated and at least one station is HT 20 */ + /* disable protection from any non-HT devices. */ + /* decision for disabling protection from 11b has already been taken above. */ + if (eSIR_HT_OP_MODE_NO_LEGACY_20MHZ_HT == htInfo.opMode) { + /* Disable protection from 11G station. */ + psessionEntry->beaconParams.llgCoexist = false; + /* CFG protection from HT 20 is enabled. */ + if (pMac->lim.cfgProtection.ht20) + psessionEntry->beaconParams. + ht20Coexist = true; + } + /* Disable protection from non-HT and HT20 devices. */ + /* decision for disabling protection from 11b has already been taken above. */ + if (eSIR_HT_OP_MODE_PURE == htInfo.opMode) { + psessionEntry->beaconParams.llgCoexist = false; + psessionEntry->beaconParams.ht20Coexist = false; + } + + } + } + /* protection related factors other than HT operating mode. Applies to 2.4 GHZ as well as 5 GHZ. */ + if ((psessionEntry->htCapability) && (pBeaconStruct->HTInfo.present)) { + tDot11fIEHTInfo htInfo = pBeaconStruct->HTInfo; + psessionEntry->beaconParams.fRIFSMode = + (uint8_t) htInfo.rifsMode; + psessionEntry->beaconParams.llnNonGFCoexist = + (uint8_t) htInfo.nonGFDevicesPresent; + psessionEntry->beaconParams.fLsigTXOPProtectionFullSupport = + (uint8_t) htInfo.lsigTXOPProtectionFullSupport; + } +} + + +/** + * lim_decide_sta_11bg_protection() - decides protection related settings on sta + * @mac_ctx: pointer to global mac structure + * @beacon_struct: pointer to tpschbeaconstruct + * @beaconparams: pointer to tpupdatebeaconparams + * @psession_entry: pointer to tppesession + * @phy_mode: phy mode index + * + * decides 11bg protection related settings on sta while processing beacon + * + * Return: none + */ +static void +lim_decide_sta_11bg_protection(tpAniSirGlobal mac_ctx, + tpSchBeaconStruct beacon_struct, + tpUpdateBeaconParams beaconparams, + tpPESession psession_entry, + uint32_t phy_mode) +{ + + tDot11fIEHTInfo htInfo; + + /* + * spec 7.3.2.13 + * UseProtection will be set when nonERP STA is associated. + * NonERPPresent bit will be set when: + * --nonERP Sta is associated OR + * --nonERP Sta exists in overlapping BSS + * when useProtection is not set then protection from + * nonERP stations is optional. + */ + if (phy_mode != WNI_CFG_PHY_MODE_11B) { + if (beacon_struct->erpPresent && + (beacon_struct->erpIEInfo.useProtection || + beacon_struct->erpIEInfo.nonErpPresent)) { + lim_enable11g_protection(mac_ctx, true, false, + beaconparams, + psession_entry); + } + /* AP has no 11b station associated. */ + else { + /* disable protection from 11b station */ + lim_enable11g_protection(mac_ctx, false, false, + beaconparams, + psession_entry); + } + } + + if (!(psession_entry->htCapability) || + !(beacon_struct->HTInfo.present)) + return; + + /* following code is only for HT station. */ + + htInfo = beacon_struct->HTInfo; + /* AP has at least one 11G station associated. */ + if (((eSIR_HT_OP_MODE_MIXED == htInfo.opMode) || + (eSIR_HT_OP_MODE_OVERLAP_LEGACY == htInfo.opMode)) && + (!psession_entry->beaconParams.llbCoexist)) { + lim_enable_ht_protection_from11g(mac_ctx, true, false, + beaconparams, psession_entry); + + } + /* + * no HT operating mode change ==> no change in + * protection settings except for MIXED_MODE/Legacy + * Mode. + */ + /* + * in Mixed mode/legacy Mode even if there is no + * change in HT operating mode, there might be + * change in 11bCoexist or 11gCoexist. Hence this + * check is being done after mixed/legacy mode + * check. + */ + if (mac_ctx->lim.gHTOperMode != + (tSirMacHTOperatingMode)htInfo.opMode) { + mac_ctx->lim.gHTOperMode = + (tSirMacHTOperatingMode) htInfo.opMode; + /* + * AP has only HT stations associated and + * at least one station is HT 20 + */ + + /* disable protection from any non-HT devices. */ + + /* + * decision for disabling protection from + * 11b has already been taken above. + */ + if (eSIR_HT_OP_MODE_NO_LEGACY_20MHZ_HT == + htInfo.opMode) { + /* Disable protection from 11G station. */ + lim_enable_ht_protection_from11g(mac_ctx, false, + false, beaconparams, + psession_entry); + + lim_enable_ht20_protection(mac_ctx, true, false, + beaconparams, + psession_entry); + } + /* + * Disable protection from non-HT and + * HT20 devices. + */ + /* + * decision for disabling protection from + * 11b has already been taken above. + */ + else if (eSIR_HT_OP_MODE_PURE == htInfo.opMode) { + lim_enable_ht_protection_from11g(mac_ctx, false, + false, beaconparams, + psession_entry); + + lim_enable_ht20_protection(mac_ctx, false, + false, beaconparams, + psession_entry); + + } + } + +} + +/** + * lim_decide_sta_protection() - decides protection related settings on sta + * @mac_ctx: pointer to global mac structure + * @beacon_struct: pointer to tpschbeaconstruct + * @beaconparams: pointer to tpupdatebeaconparams + * @psession_entry: pointer to tppesession + * + * decides protection related settings on sta while processing beacon + * + * Return: none + */ +void +lim_decide_sta_protection(tpAniSirGlobal mac_ctx, + tpSchBeaconStruct beacon_struct, + tpUpdateBeaconParams beaconparams, + tpPESession psession_entry) +{ + + tSirRFBand rfband = SIR_BAND_UNKNOWN; + uint32_t phy_mode = WNI_CFG_PHY_MODE_NONE; + + lim_get_rf_band_new(mac_ctx, &rfband, psession_entry); + lim_get_phy_mode(mac_ctx, &phy_mode, psession_entry); + + if ((SIR_BAND_5_GHZ == rfband) && + /* we are HT capable. */ + (true == psession_entry->htCapability) && + (beacon_struct->HTInfo.present)) { + /* + * we are HT capable, AP's HT OPMode is + * mixed / overlap legacy ==> need protection + * from 11A. + */ + if ((eSIR_HT_OP_MODE_MIXED == + beacon_struct->HTInfo.opMode) || + (eSIR_HT_OP_MODE_OVERLAP_LEGACY == + beacon_struct->HTInfo.opMode)) { + lim_update_11a_protection(mac_ctx, true, false, + beaconparams, psession_entry); + } + /* + * we are HT capable, AP's HT OPMode is + * HT20 ==> disable protection from 11A if + * enabled. + */ + /* protection from HT20 if needed. */ + else if (eSIR_HT_OP_MODE_NO_LEGACY_20MHZ_HT == + beacon_struct->HTInfo.opMode) { + lim_update_11a_protection(mac_ctx, false, false, + beaconparams, psession_entry); + lim_enable_ht20_protection(mac_ctx, true, false, + beaconparams, psession_entry); + } else if (eSIR_HT_OP_MODE_PURE == + beacon_struct->HTInfo.opMode) { + lim_update_11a_protection(mac_ctx, false, false, + beaconparams, psession_entry); + lim_enable_ht20_protection(mac_ctx, false, + false, beaconparams, + psession_entry); + } + } else if (SIR_BAND_2_4_GHZ == rfband) { + lim_decide_sta_11bg_protection(mac_ctx, beacon_struct, + beaconparams, psession_entry, phy_mode); + } + /* + * following code block is only for HT station. + * (2.4 GHZ as well as 5 GHZ) + */ + if ((psession_entry->htCapability) && (beacon_struct->HTInfo.present)) { + tDot11fIEHTInfo htInfo = beacon_struct->HTInfo; + /* + * Check for changes in protection related factors other + * than HT operating mode. + */ + /* + * Check for changes in RIFS mode, nonGFDevicesPresent, + * lsigTXOPProtectionFullSupport. + */ + if (psession_entry->beaconParams.fRIFSMode != + (uint8_t) htInfo.rifsMode) { + beaconparams->fRIFSMode = + psession_entry->beaconParams.fRIFSMode = + (uint8_t) htInfo.rifsMode; + beaconparams->paramChangeBitmap |= + PARAM_RIFS_MODE_CHANGED; + } + + if (psession_entry->beaconParams.llnNonGFCoexist != + htInfo.nonGFDevicesPresent) { + beaconparams->llnNonGFCoexist = + psession_entry->beaconParams.llnNonGFCoexist = + (uint8_t) htInfo.nonGFDevicesPresent; + beaconparams->paramChangeBitmap |= + PARAM_NON_GF_DEVICES_PRESENT_CHANGED; + } + + if (psession_entry->beaconParams. + fLsigTXOPProtectionFullSupport != + (uint8_t) htInfo.lsigTXOPProtectionFullSupport) { + beaconparams->fLsigTXOPProtectionFullSupport = + psession_entry->beaconParams. + fLsigTXOPProtectionFullSupport = + (uint8_t) htInfo. + lsigTXOPProtectionFullSupport; + beaconparams->paramChangeBitmap |= + PARAM_LSIG_TXOP_FULL_SUPPORT_CHANGED; + } + /* + * For Station just update the global lim variable, + * no need to send message to HAL since Station already + * taking care of HT OPR Mode=01, + * meaning AP is seeing legacy + */ + /* stations in overlapping BSS. */ + if (psession_entry->beaconParams.gHTObssMode != + (uint8_t) htInfo.obssNonHTStaPresent) + psession_entry->beaconParams.gHTObssMode = + (uint8_t) htInfo.obssNonHTStaPresent; + + } +} + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +static void lim_trigger_channel_switch_through_roaming(uint32_t sme_sessionid, + tSirMacAddr bssid, uint8_t channel) +{ + struct wma_roam_invoke_cmd *fastreassoc; + cds_msg_t msg = {0}; + + fastreassoc = qdf_mem_malloc(sizeof(struct wma_roam_invoke_cmd)); + if (NULL == fastreassoc) { + hdd_err("qdf_mem_malloc failed for fastreassoc"); + return; + } + fastreassoc->vdev_id = sme_sessionid; + fastreassoc->channel = channel; + fastreassoc->bssid[0] = bssid[0]; + fastreassoc->bssid[1] = bssid[1]; + fastreassoc->bssid[2] = bssid[2]; + fastreassoc->bssid[3] = bssid[3]; + fastreassoc->bssid[4] = bssid[4]; + fastreassoc->bssid[5] = bssid[5]; + + msg.type = SIR_HAL_ROAM_INVOKE; + msg.reserved = 0; + msg.bodyptr = fastreassoc; + if (QDF_STATUS_SUCCESS != cds_mq_post_message(QDF_MODULE_ID_WMA, + &msg)) { + qdf_mem_free(fastreassoc); + hdd_err("Not able to post ROAM_INVOKE_CMD message to WMA"); + } +} + +static void lim_csa_ecsa_handler(tpAniSirGlobal mac_ctx, tpPESession session) +{ + uint8_t old_channel, new_channel; + + old_channel = session->currentOperChannel; + new_channel = session->gLimChannelSwitch.primaryChannel; + switch (session->gLimChannelSwitch.state) { + case eLIM_CHANNEL_SWITCH_PRIMARY_ONLY: + lim_log(mac_ctx, LOG1, FL("CHANNEL_SWITCH_PRIMARY_ONLY ")); + if (!CDS_IS_SAME_BAND_CHANNELS(old_channel, new_channel)) { + lim_trigger_channel_switch_through_roaming( + session->smeSessionId, session->bssId, + session->gLimChannelSwitch.primaryChannel); + } else { + lim_switch_primary_channel(mac_ctx, + session->gLimChannelSwitch.primaryChannel, + session); + } + session->gLimChannelSwitch.state = eLIM_CHANNEL_SWITCH_IDLE; + break; + case eLIM_CHANNEL_SWITCH_PRIMARY_AND_SECONDARY: + lim_log(mac_ctx, LOG1, + FL("CHANNEL_SWITCH_PRIMARY_AND_SECONDARY")); + if (!CDS_IS_SAME_BAND_CHANNELS(old_channel, new_channel)) { + lim_trigger_channel_switch_through_roaming( + session->smeSessionId, session->bssId, + session->gLimChannelSwitch.primaryChannel); + } else { + lim_switch_primary_secondary_channel(mac_ctx, session, + session->gLimChannelSwitch.primaryChannel, + session->gLimChannelSwitch.ch_center_freq_seg0, + session->gLimChannelSwitch.ch_center_freq_seg1, + session->gLimChannelSwitch.ch_width); + } + session->gLimChannelSwitch.state = eLIM_CHANNEL_SWITCH_IDLE; + break; + case eLIM_CHANNEL_SWITCH_IDLE: + default: + lim_log(mac_ctx, LOGE, FL("incorrect state ")); + if (lim_restore_pre_channel_switch_state(mac_ctx, session) != + eSIR_SUCCESS) + lim_log(mac_ctx, LOGP, + FL("Can't restore state, reset the system")); + return; + } +} +#else +static void lim_csa_ecsa_handler(tpAniSirGlobal mac_ctx, tpPESession session) +{ + uint8_t old_channel, new_channel; + + old_channel = session->currentOperChannel; + new_channel = session->gLimChannelSwitch.primaryChannel; + switch (session->gLimChannelSwitch.state) { + case eLIM_CHANNEL_SWITCH_PRIMARY_ONLY: + lim_log(mac_ctx, LOG1, FL("CHANNEL_SWITCH_PRIMARY_ONLY ")); + lim_switch_primary_channel(mac_ctx, + session->gLimChannelSwitch.primaryChannel, + session); + session->gLimChannelSwitch.state = eLIM_CHANNEL_SWITCH_IDLE; + break; + case eLIM_CHANNEL_SWITCH_PRIMARY_AND_SECONDARY: + lim_log(mac_ctx, LOG1, + FL("CHANNEL_SWITCH_PRIMARY_AND_SECONDARY")); + lim_switch_primary_secondary_channel(mac_ctx, session, + session->gLimChannelSwitch.primaryChannel, + session->gLimChannelSwitch.ch_center_freq_seg0, + session->gLimChannelSwitch.ch_center_freq_seg1, + session->gLimChannelSwitch.ch_width); + session->gLimChannelSwitch.state = eLIM_CHANNEL_SWITCH_IDLE; + break; + case eLIM_CHANNEL_SWITCH_IDLE: + default: + lim_log(mac_ctx, LOGE, FL("incorrect state ")); + if (lim_restore_pre_channel_switch_state(mac_ctx, session) != + eSIR_SUCCESS) + lim_log(mac_ctx, LOGP, + FL("Can't restore state, reset the system")); + return; + } +} +#endif + +/** + * lim_process_channel_switch_timeout() + * + ***FUNCTION: + * This function is invoked when Channel Switch Timer expires at + * the STA. Now, STA must stop traffic, and then change/disable + * primary or secondary channel. + * + * + ***NOTE: + * @param pMac - Pointer to Global MAC structure + * @return None + */ +void lim_process_channel_switch_timeout(tpAniSirGlobal pMac) +{ + tpPESession psessionEntry = NULL; + uint8_t channel; /* This is received and stored from channelSwitch Action frame */ + + psessionEntry = pe_find_session_by_session_id(pMac, + pMac->lim.limTimers.gLimChannelSwitchTimer.sessionId); + if (psessionEntry == NULL) { + lim_log(pMac, LOGE, + FL("Session Does not exist for given sessionID")); + return; + } + + if (!LIM_IS_STA_ROLE(psessionEntry)) { + lim_log(pMac, LOGW, + "Channel switch can be done only in STA role, Current Role = %d", + GET_LIM_SYSTEM_ROLE(psessionEntry)); + return; + } + + if (psessionEntry->gLimSpecMgmt.dot11hChanSwState != + eLIM_11H_CHANSW_RUNNING) { + lim_log(pMac, LOGW, + FL("Channel switch timer should not have been running in state %d"), + psessionEntry->gLimSpecMgmt.dot11hChanSwState); + return; + } + + channel = psessionEntry->gLimChannelSwitch.primaryChannel; + /* Restore Channel Switch parameters to default */ + psessionEntry->gLimChannelSwitch.switchTimeoutValue = 0; + + /* Channel-switch timeout has occurred. reset the state */ + psessionEntry->gLimSpecMgmt.dot11hChanSwState = eLIM_11H_CHANSW_END; + + /* Check if the AP is switching to a channel that we support. + * Else, just don't bother to switch. Indicate HDD to look for a + * better AP to associate + */ + if (!lim_is_channel_valid_for_channel_switch(pMac, channel)) { + /* We need to restore pre-channelSwitch state on the STA */ + if (lim_restore_pre_channel_switch_state(pMac, psessionEntry) != + eSIR_SUCCESS) { + lim_log(pMac, LOGP, + FL + ("Could not restore pre-channelSwitch (11h) state, resetting the system")); + return; + } + + /* + * If the channel-list that AP is asking us to switch is invalid + * then we cannot switch the channel. Just disassociate from AP. + * We will find a better AP !!! + */ + if ((psessionEntry->limMlmState == + eLIM_MLM_LINK_ESTABLISHED_STATE) && + (psessionEntry->limSmeState != eLIM_SME_WT_DISASSOC_STATE) && + (psessionEntry->limSmeState != eLIM_SME_WT_DEAUTH_STATE)) { + lim_log(pMac, LOGE, FL("Invalid channel! Disconnect")); + lim_tear_down_link_with_ap(pMac, + pMac->lim.limTimers. + gLimChannelSwitchTimer.sessionId, + eSIR_MAC_UNSPEC_FAILURE_REASON); + return; + } + } + lim_covert_channel_scan_type(pMac, psessionEntry->currentOperChannel, + false); + pMac->lim.dfschannelList.timeStamp[psessionEntry->currentOperChannel] = + 0; + lim_csa_ecsa_handler(pMac, psessionEntry); +} + +/** + * lim_update_channel_switch() - This Function updates channel switch + * @mac_ctx: pointer to Global MAC structure + * @beacon: pointer to tpSirProbeRespBeacon + * @psessionentry: pointer to tpPESession + * + * This function is invoked whenever Station receives + * either 802.11h channel switch IE or airgo proprietary + * channel switch IE. + * + * Return: none + */ +void +lim_update_channel_switch(struct sAniSirGlobal *mac_ctx, + tpSirProbeRespBeacon beacon, + tpPESession psession_entry) +{ + uint16_t beacon_period; + tDot11fIEChanSwitchAnn *chnl_switch; + tLimChannelSwitchInfo *ch_switch_params; + tDot11fIEWiderBWChanSwitchAnn *widerchnl_switch; + + beacon_period = psession_entry->beaconParams.beaconInterval; + + /* 802.11h standard channel switch IE */ + chnl_switch = &(beacon->channelSwitchIE); + ch_switch_params = &psession_entry->gLimChannelSwitch; + ch_switch_params->primaryChannel = + chnl_switch->newChannel; + ch_switch_params->switchCount = chnl_switch->switchCount; + ch_switch_params->switchTimeoutValue = + SYS_MS_TO_TICKS(beacon_period) * (chnl_switch->switchCount); + ch_switch_params->switchMode = chnl_switch->switchMode; + widerchnl_switch = &(beacon->WiderBWChanSwitchAnn); + if (beacon->WiderBWChanSwitchAnnPresent) { + psession_entry->gLimWiderBWChannelSwitch.newChanWidth = + widerchnl_switch->newChanWidth; + psession_entry->gLimWiderBWChannelSwitch.newCenterChanFreq0 = + widerchnl_switch->newCenterChanFreq0; + psession_entry->gLimWiderBWChannelSwitch.newCenterChanFreq1 = + widerchnl_switch->newCenterChanFreq1; + } + /* Only primary channel switch element is present */ + ch_switch_params->state = + eLIM_CHANNEL_SWITCH_PRIMARY_ONLY; + ch_switch_params->ch_width = CH_WIDTH_20MHZ; + + /* + * Do not bother to look and operate on extended channel switch element + * if our own channel-bonding state is not enabled + */ + if (psession_entry->htSupportedChannelWidthSet && + beacon->sec_chan_offset_present) { + if (beacon->sec_chan_offset.secondaryChannelOffset == + PHY_DOUBLE_CHANNEL_LOW_PRIMARY) { + ch_switch_params->state = + eLIM_CHANNEL_SWITCH_PRIMARY_AND_SECONDARY; + ch_switch_params->ch_width = CH_WIDTH_40MHZ; + ch_switch_params->ch_center_freq_seg0 = + ch_switch_params->primaryChannel + 2; + } else if (beacon->sec_chan_offset.secondaryChannelOffset == + PHY_DOUBLE_CHANNEL_HIGH_PRIMARY) { + ch_switch_params->state = + eLIM_CHANNEL_SWITCH_PRIMARY_AND_SECONDARY; + ch_switch_params->ch_width = CH_WIDTH_40MHZ; + ch_switch_params->ch_center_freq_seg0 = + ch_switch_params->primaryChannel - 2; + } + if (psession_entry->vhtCapability && + beacon->WiderBWChanSwitchAnnPresent) { + ch_switch_params->ch_width = + widerchnl_switch->newChanWidth + 1; + ch_switch_params->ch_center_freq_seg0 = + psession_entry->gLimWiderBWChannelSwitch. + newCenterChanFreq0; + ch_switch_params->ch_center_freq_seg1 = + psession_entry->gLimWiderBWChannelSwitch. + newCenterChanFreq1; + } + } + if (eSIR_SUCCESS != lim_start_channel_switch(mac_ctx, psession_entry)) + lim_log(mac_ctx, LOGW, FL("Could not start Channel Switch")); + + lim_log(mac_ctx, LOGW, + FL("session %d primary chl %d, ch_width %d, count %d (%d ticks)"), + psession_entry->peSessionId, + psession_entry->gLimChannelSwitch.primaryChannel, + psession_entry->gLimChannelSwitch.ch_width, + psession_entry->gLimChannelSwitch.switchCount, + psession_entry->gLimChannelSwitch.switchTimeoutValue); + return; +} + +/** + * lim_cancel_dot11h_channel_switch + * + ***FUNCTION: + * This function is called when STA does not send updated channel-swith IE + * after indicating channel-switch start. This will cancel the channel-swith + * timer which is already running. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param pMac - Pointer to Global MAC structure + * + * @return None + */ +void lim_cancel_dot11h_channel_switch(tpAniSirGlobal pMac, + tpPESession psessionEntry) +{ + if (!LIM_IS_STA_ROLE(psessionEntry)) + return; + + PELOGW(lim_log + (pMac, LOGW, FL("Received a beacon without channel switch IE")); + ) + MTRACE(mac_trace + (pMac, TRACE_CODE_TIMER_DEACTIVATE, + psessionEntry->peSessionId, eLIM_CHANNEL_SWITCH_TIMER)); + + if (tx_timer_deactivate(&pMac->lim.limTimers.gLimChannelSwitchTimer) != + eSIR_SUCCESS) { + PELOGE(lim_log(pMac, LOGE, FL("tx_timer_deactivate failed!"));) + } + + /* We need to restore pre-channelSwitch state on the STA */ + if (lim_restore_pre_channel_switch_state(pMac, psessionEntry) != + eSIR_SUCCESS) { + PELOGE(lim_log + (pMac, LOGE, + FL + ("LIM: Could not restore pre-channelSwitch (11h) state, resetting the system")); + ) + + } +} + +/** + * lim_cancel_dot11h_quiet() + * + * @mac_ctx: pointer to global mac structure + * @psession_entry: pointer to tppesession + * + * Cancel the quieting on Station if latest beacon + * doesn't contain quiet IE in it. + * + * Return: none + */ +void lim_cancel_dot11h_quiet(tpAniSirGlobal pMac, tpPESession psessionEntry) +{ + if (!LIM_IS_STA_ROLE(psessionEntry)) + return; + + if (psessionEntry->gLimSpecMgmt.quietState == eLIM_QUIET_BEGIN) { + MTRACE(mac_trace + (pMac, TRACE_CODE_TIMER_DEACTIVATE, + psessionEntry->peSessionId, eLIM_QUIET_TIMER)); + if (tx_timer_deactivate(&pMac->lim.limTimers.gLimQuietTimer) != + TX_SUCCESS) { + PELOGE(lim_log + (pMac, LOGE, FL("tx_timer_deactivate failed")); + ) + } + } else if (psessionEntry->gLimSpecMgmt.quietState == eLIM_QUIET_RUNNING) { + MTRACE(mac_trace + (pMac, TRACE_CODE_TIMER_DEACTIVATE, + psessionEntry->peSessionId, eLIM_QUIET_BSS_TIMER)); + if (tx_timer_deactivate(&pMac->lim.limTimers.gLimQuietBssTimer) + != TX_SUCCESS) { + PELOGE(lim_log + (pMac, LOGE, FL("tx_timer_deactivate failed")); + ) + } + /** + * If the channel switch is already running in silent mode, dont resume the + * transmission. Channel switch timer when timeout, transmission will be resumed. + */ + if (! + ((psessionEntry->gLimSpecMgmt.dot11hChanSwState == + eLIM_11H_CHANSW_RUNNING) + && (psessionEntry->gLimChannelSwitch.switchMode == + eSIR_CHANSW_MODE_SILENT))) { + lim_frame_transmission_control(pMac, eLIM_TX_ALL, + eLIM_RESUME_TX); + lim_restore_pre_quiet_state(pMac, psessionEntry); + } + } + psessionEntry->gLimSpecMgmt.quietState = eLIM_QUIET_INIT; +} + +/** + * lim_process_quiet_timeout + * + * FUNCTION: + * This function is active only on the STA. + * Handles SIR_LIM_QUIET_TIMEOUT + * + * LOGIC: + * This timeout can occur under only one circumstance: + * + * 1) When gLimQuietState = eLIM_QUIET_BEGIN + * This indicates that the timeout "interval" has + * expired. This is a trigger for the STA to now + * shut-off Tx/Rx for the specified gLimQuietDuration + * -> The TIMER object gLimQuietBssTimer is + * activated + * -> With timeout = gLimQuietDuration + * -> gLimQuietState is set to eLIM_QUIET_RUNNING + * + * ASSUMPTIONS: + * Using two TIMER objects - + * gLimQuietTimer & gLimQuietBssTimer + * + * NOTE: + * + * @param pMac - Pointer to Global MAC structure + * + * @return None + */ +void lim_process_quiet_timeout(tpAniSirGlobal pMac) +{ + tpPESession psessionEntry; + + psessionEntry = pe_find_session_by_session_id(pMac, + pMac->lim.limTimers.gLimQuietTimer.sessionId); + if (psessionEntry == NULL) { + lim_log(pMac, LOGE, + FL("Session Does not exist for given sessionID")); + return; + } + + PELOG1(lim_log + (pMac, LOG1, FL("quietState = %d"), + psessionEntry->gLimSpecMgmt.quietState); + ) + switch (psessionEntry->gLimSpecMgmt.quietState) { + case eLIM_QUIET_BEGIN: + /* Time to Stop data traffic for quietDuration */ + /* lim_deactivate_and_change_timer(pMac, eLIM_QUIET_BSS_TIMER); */ + if (TX_SUCCESS != tx_timer_deactivate( + &pMac->lim.limTimers.gLimQuietBssTimer)) { + lim_log(pMac, LOGE, + FL + ("Unable to de-activate gLimQuietBssTimer! Will attempt to activate anyway...")); + } + /* gLimQuietDuration appears to be in units of ticks */ + /* Use it as is */ + if (TX_SUCCESS != + tx_timer_change(&pMac->lim.limTimers.gLimQuietBssTimer, + psessionEntry->gLimSpecMgmt.quietDuration, + 0)) { + lim_log(pMac, LOGE, + FL + ("Unable to change gLimQuietBssTimer! Will still attempt to activate anyway...")); + } + MTRACE(mac_trace + (pMac, TRACE_CODE_TIMER_ACTIVATE, + pMac->lim.limTimers.gLimQuietTimer.sessionId, + eLIM_QUIET_BSS_TIMER)); + if (TX_SUCCESS != + tx_timer_activate(&pMac->lim.limTimers.gLimQuietBssTimer)) { + lim_log(pMac, LOGW, + FL + ("Unable to activate gLimQuietBssTimer! The STA will be unable to honor Quiet BSS...")); + } else { + /* Transition to eLIM_QUIET_RUNNING */ + psessionEntry->gLimSpecMgmt.quietState = + eLIM_QUIET_RUNNING; + /* Shut-off Tx/Rx for gLimSpecMgmt.quietDuration */ + /* freeze the transmission */ + lim_frame_transmission_control(pMac, eLIM_TX_ALL, + eLIM_STOP_TX); + + lim_log(pMac, LOG2, + FL("Quiet BSS: STA shutting down for %d ticks"), + psessionEntry->gLimSpecMgmt.quietDuration); + } + break; + + case eLIM_QUIET_RUNNING: + case eLIM_QUIET_INIT: + case eLIM_QUIET_END: + default: + /* */ + /* As of now, nothing to be done */ + /* */ + break; + } +} + +/** + * lim_process_quiet_bss_timeout() - Handles SIR_LIM_QUIET_BSS_TIMEOUT + * @mac_ctx: pointer to Globale Mac Structure + * + * This function is active on the AP and STA. + * Handles SIR_LIM_QUIET_BSS_TIMEOUT + * + * On the AP - + * When the SIR_LIM_QUIET_BSS_TIMEOUT is triggered, it is + * an indication for the AP to START sending out the + * Quiet BSS IE. + * If 802.11H is enabled, the Quiet BSS IE is sent as per + * the 11H spec + * If 802.11H is not enabled, the Quiet BSS IE is sent as + * a Proprietary IE. This will be understood by all the + * TITAN STA's + * Transitioning gLimQuietState to eLIM_QUIET_BEGIN will + * initiate the SCH to include the Quiet BSS IE in all + * its subsequent Beacons/PR's. + * The Quiet BSS IE will be included in all the Beacons + * & PR's until the next DTIM period + * + * On the STA - + * When gLimQuietState = eLIM_QUIET_RUNNING + * This indicates that the STA was successfully shut-off + * for the specified gLimQuietDuration. This is a trigger + * for the STA to now resume data traffic. + * -> gLimQuietState is set to eLIM_QUIET_INIT + * + * + * Return: none + */ +void lim_process_quiet_bss_timeout(tpAniSirGlobal mac_ctx) +{ + tpPESession psession_entry = NULL; + tLimTimers *lim_timer = &mac_ctx->lim.limTimers; + + psession_entry = pe_find_session_by_session_id(mac_ctx, + lim_timer->gLimQuietBssTimer.sessionId); + + if (psession_entry == NULL) { + lim_log(mac_ctx, LOGP, + FL("Session Does not exist for given sessionID")); + return; + } + + lim_log(mac_ctx, LOG1, FL("quietState = %d"), + psession_entry->gLimSpecMgmt.quietState); + + if (LIM_IS_AP_ROLE(psession_entry)) + return; + + /* eLIM_STA_ROLE */ + switch (psession_entry->gLimSpecMgmt.quietState) { + case eLIM_QUIET_RUNNING: + /* Transition to eLIM_QUIET_INIT */ + psession_entry->gLimSpecMgmt.quietState = eLIM_QUIET_INIT; + + /* + * Resume data traffic only if channel switch is + * not running in silent mode. + */ + if (!((psession_entry->gLimSpecMgmt.dot11hChanSwState == + eLIM_11H_CHANSW_RUNNING) && + (psession_entry->gLimChannelSwitch.switchMode == + eSIR_CHANSW_MODE_SILENT))) { + lim_frame_transmission_control(mac_ctx, eLIM_TX_ALL, + eLIM_RESUME_TX); + lim_restore_pre_quiet_state(mac_ctx, psession_entry); + } + lim_log(mac_ctx, LOG2, FL("Quiet BSS: Resuming traffic...")); + break; + + case eLIM_QUIET_INIT: + case eLIM_QUIET_BEGIN: + case eLIM_QUIET_END: + lim_log(mac_ctx, LOG2, FL("Quiet state not in RUNNING")); + /* + * If the quiet period has ended, then resume the + * frame transmission + */ + lim_frame_transmission_control(mac_ctx, eLIM_TX_ALL, + eLIM_RESUME_TX); + lim_restore_pre_quiet_state(mac_ctx, psession_entry); + psession_entry->gLimSpecMgmt.quietState = eLIM_QUIET_INIT; + break; + + default: + /* As of now, nothing to be done */ + break; + } +} + +/**---------------------------------------------- + \fn lim_start_quiet_timer + \brief Starts the quiet timer. + + \param pMac + \return NONE + -----------------------------------------------*/ +void lim_start_quiet_timer(tpAniSirGlobal pMac, uint8_t sessionId) +{ + tpPESession psessionEntry; + psessionEntry = pe_find_session_by_session_id(pMac, sessionId); + + if (psessionEntry == NULL) { + lim_log(pMac, LOGP, + FL("Session Does not exist for given sessionID")); + return; + } + + if (!LIM_IS_STA_ROLE(psessionEntry)) + return; + /* First, de-activate Timer, if its already active */ + lim_cancel_dot11h_quiet(pMac, psessionEntry); + + MTRACE(mac_trace + (pMac, TRACE_CODE_TIMER_ACTIVATE, sessionId, eLIM_QUIET_TIMER)); + if (TX_SUCCESS != + tx_timer_deactivate(&pMac->lim.limTimers.gLimQuietTimer)) { + lim_log(pMac, LOGE, + FL + ("Unable to deactivate gLimQuietTimer! Will still attempt to re-activate anyway...")); + } + /* Set the NEW timeout value, in ticks */ + if (TX_SUCCESS != tx_timer_change(&pMac->lim.limTimers.gLimQuietTimer, + SYS_MS_TO_TICKS(psessionEntry-> + gLimSpecMgmt. + quietTimeoutValue), + 0)) { + lim_log(pMac, LOGE, + FL + ("Unable to change gLimQuietTimer! Will still attempt to re-activate anyway...")); + } + + pMac->lim.limTimers.gLimQuietTimer.sessionId = sessionId; + if (TX_SUCCESS != + tx_timer_activate(&pMac->lim.limTimers.gLimQuietTimer)) { + lim_log(pMac, LOGE, + FL + ("Unable to activate gLimQuietTimer! STA cannot honor Quiet BSS!")); + lim_restore_pre_quiet_state(pMac, psessionEntry); + + psessionEntry->gLimSpecMgmt.quietState = eLIM_QUIET_INIT; + return; + } +} + +/** ------------------------------------------------------------------------ **/ +/** + * keep track of the number of ANI peers associated in the BSS + * For the first and last ANI peer, we have to update EDCA params as needed + * + * When the first ANI peer joins the BSS, we notify SCH + * When the last ANI peer leaves the BSS, we notfiy SCH + */ +void +lim_util_count_sta_add(tpAniSirGlobal pMac, + tpDphHashNode pSta, tpPESession psessionEntry) +{ + + if ((!pSta) || (!pSta->valid) || (pSta->fAniCount)) + return; + + pSta->fAniCount = 1; + + if (pMac->lim.gLimNumOfAniSTAs++ != 0) + return; + + /* get here only if this is the first ANI peer in the BSS */ + sch_edca_profile_update(pMac, psessionEntry); +} + +void +lim_util_count_sta_del(tpAniSirGlobal pMac, + tpDphHashNode pSta, tpPESession psessionEntry) +{ + + if ((pSta == NULL) || (!pSta->fAniCount)) + return; + + /* Only if sta is invalid and the validInDummyState bit is set to 1, + * then go ahead and update the count and profiles. This ensures + * that the "number of ani station" count is properly incremented/decremented. + */ + if (pSta->valid == 1) + return; + + pSta->fAniCount = 0; + + if (pMac->lim.gLimNumOfAniSTAs <= 0) { + lim_log(pMac, LOGE, + FL + ("CountStaDel: ignoring Delete Req when AniPeer count is %d"), + pMac->lim.gLimNumOfAniSTAs); + return; + } + + pMac->lim.gLimNumOfAniSTAs--; + + if (pMac->lim.gLimNumOfAniSTAs != 0) + return; + + /* get here only if this is the last ANI peer in the BSS */ + sch_edca_profile_update(pMac, psessionEntry); +} + +/** + * lim_switch_channel_cback() + * + ***FUNCTION: + * This is the callback function registered while requesting to switch channel + * after AP indicates a channel switch for spectrum management (11h). + * + ***NOTE: + * @param pMac Pointer to Global MAC structure + * @param status Status of channel switch request + * @param data User data + * @param psessionEntry Session information + * @return NONE + */ +void lim_switch_channel_cback(tpAniSirGlobal pMac, QDF_STATUS status, + uint32_t *data, tpPESession psessionEntry) +{ + tSirMsgQ mmhMsg = { 0 }; + tSirSmeSwitchChannelInd *pSirSmeSwitchChInd; + + psessionEntry->currentOperChannel = psessionEntry->currentReqChannel; + + /* We need to restore pre-channelSwitch state on the STA */ + if (lim_restore_pre_channel_switch_state(pMac, psessionEntry) != + eSIR_SUCCESS) { + lim_log(pMac, LOGP, + FL + ("Could not restore pre-channelSwitch (11h) state, resetting the system")); + return; + } + + mmhMsg.type = eWNI_SME_SWITCH_CHL_IND; + pSirSmeSwitchChInd = qdf_mem_malloc(sizeof(tSirSmeSwitchChannelInd)); + if (NULL == pSirSmeSwitchChInd) { + lim_log(pMac, LOGP, + FL("Failed to allocate buffer for buffer descriptor")); + return; + } + + pSirSmeSwitchChInd->messageType = eWNI_SME_SWITCH_CHL_IND; + pSirSmeSwitchChInd->length = sizeof(tSirSmeSwitchChannelInd); + pSirSmeSwitchChInd->newChannelId = + psessionEntry->gLimChannelSwitch.primaryChannel; + pSirSmeSwitchChInd->sessionId = psessionEntry->smeSessionId; + pSirSmeSwitchChInd->chan_params.ch_width = + psessionEntry->gLimChannelSwitch.ch_width; + pSirSmeSwitchChInd->chan_params.sec_ch_offset = + psessionEntry->gLimChannelSwitch.sec_ch_offset; + pSirSmeSwitchChInd->chan_params.center_freq_seg0 = + psessionEntry->gLimChannelSwitch.ch_center_freq_seg0; + pSirSmeSwitchChInd->chan_params.center_freq_seg1 = + psessionEntry->gLimChannelSwitch.ch_center_freq_seg1; + + lim_log(pMac, LOG1, + FL("session:%d chan:%d width:%d sec offset:%d seg0:%d seg1:%d"), + pSirSmeSwitchChInd->sessionId, + pSirSmeSwitchChInd->newChannelId, + pSirSmeSwitchChInd->chan_params.ch_width, + pSirSmeSwitchChInd->chan_params.sec_ch_offset, + pSirSmeSwitchChInd->chan_params.center_freq_seg0, + pSirSmeSwitchChInd->chan_params.center_freq_seg1); + + qdf_mem_copy(pSirSmeSwitchChInd->bssid.bytes, psessionEntry->bssId, + QDF_MAC_ADDR_SIZE); + mmhMsg.bodyptr = pSirSmeSwitchChInd; + mmhMsg.bodyval = 0; + + MTRACE(mac_trace(pMac, TRACE_CODE_TX_SME_MSG, + psessionEntry->peSessionId, mmhMsg.type)); + + sys_process_mmh_msg(pMac, &mmhMsg); +} + +/** + * lim_switch_primary_channel() + * + ***FUNCTION: + * This function changes the current operating channel + * and sets the new new channel ID in WNI_CFG_CURRENT_CHANNEL. + * + ***NOTE: + * @param pMac Pointer to Global MAC structure + * @param newChannel new chnannel ID + * @return NONE + */ +void lim_switch_primary_channel(tpAniSirGlobal pMac, uint8_t newChannel, + tpPESession psessionEntry) +{ + + PELOG3(lim_log + (pMac, LOG3, + FL("lim_switch_primary_channel: old chnl %d --> new chnl %d "), + psessionEntry->currentOperChannel, newChannel); + ) + psessionEntry->currentReqChannel = newChannel; + psessionEntry->limRFBand = lim_get_rf_band(newChannel); + + psessionEntry->channelChangeReasonCode = LIM_SWITCH_CHANNEL_OPERATION; + + pMac->lim.gpchangeChannelCallback = lim_switch_channel_cback; + pMac->lim.gpchangeChannelData = NULL; + + lim_send_switch_chnl_params(pMac, newChannel, 0, 0, CH_WIDTH_20MHZ, + psessionEntry->maxTxPower, + psessionEntry->peSessionId, false); + return; +} + +/** + * lim_switch_primary_secondary_channel() + * + ***FUNCTION: + * This function changes the primary and secondary channel. + * If 11h is enabled and user provides a "new channel ID" + * that is different from the current operating channel, + * then we must set this new channel in WNI_CFG_CURRENT_CHANNEL, + * assign notify LIM of such change. + * + ***NOTE: + * @param pMac Pointer to Global MAC structure + * @param newChannel New chnannel ID (or current channel ID) + * @param subband CB secondary info: + * - eANI_CB_SECONDARY_NONE + * - eANI_CB_SECONDARY_UP + * - eANI_CB_SECONDARY_DOWN + * @return NONE + */ +void lim_switch_primary_secondary_channel(tpAniSirGlobal pMac, + tpPESession psessionEntry, + uint8_t newChannel, + uint8_t ch_center_freq_seg0, + uint8_t ch_center_freq_seg1, + enum phy_ch_width ch_width) +{ + uint8_t subband = 0; + + /* Assign the callback to resume TX once channel is changed. */ + psessionEntry->currentReqChannel = newChannel; + psessionEntry->limRFBand = lim_get_rf_band(newChannel); + psessionEntry->channelChangeReasonCode = LIM_SWITCH_CHANNEL_OPERATION; + pMac->lim.gpchangeChannelCallback = lim_switch_channel_cback; + pMac->lim.gpchangeChannelData = NULL; + + lim_send_switch_chnl_params(pMac, newChannel, ch_center_freq_seg0, + ch_center_freq_seg1, ch_width, + psessionEntry->maxTxPower, + psessionEntry->peSessionId, + false); + + /* Store the new primary and secondary channel in session entries if different */ + if (psessionEntry->currentOperChannel != newChannel) { + lim_log(pMac, LOGW, + FL("switch old chnl %d --> new chnl %d "), + psessionEntry->currentOperChannel, newChannel); + psessionEntry->currentOperChannel = newChannel; + } + if (psessionEntry->htSecondaryChannelOffset != + psessionEntry->gLimChannelSwitch.sec_ch_offset) { + lim_log(pMac, LOGW, + FL("switch old sec chnl %d --> new sec chnl %d "), + psessionEntry->htSecondaryChannelOffset, subband); + psessionEntry->htSecondaryChannelOffset = + psessionEntry->gLimChannelSwitch.sec_ch_offset; + if (psessionEntry->htSecondaryChannelOffset == + PHY_SINGLE_CHANNEL_CENTERED) { + psessionEntry->htSupportedChannelWidthSet = + WNI_CFG_CHANNEL_BONDING_MODE_DISABLE; + } else { + psessionEntry->htSupportedChannelWidthSet = + WNI_CFG_CHANNEL_BONDING_MODE_ENABLE; + } + psessionEntry->htRecommendedTxWidthSet = + psessionEntry->htSupportedChannelWidthSet; + } + + return; +} + +/** + * lim_active_scan_allowed() + * + ***FUNCTION: + * Checks if active scans are permitted on the given channel + * + ***LOGIC: + * The config variable SCAN_CONTROL_LIST contains pairs of (channelNum, activeScanAllowed) + * Need to check if the channelNum matches, then depending on the corresponding + * scan flag, return true (for activeScanAllowed==1) or false (otherwise). + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param pMac Pointer to Global MAC structure + * @param channelNum channel number + * @return None + */ + +uint8_t lim_active_scan_allowed(tpAniSirGlobal pMac, uint8_t channelNum) +{ + uint32_t i; + uint8_t channelPair[WNI_CFG_SCAN_CONTROL_LIST_LEN]; + uint32_t len = WNI_CFG_SCAN_CONTROL_LIST_LEN; + if (wlan_cfg_get_str(pMac, WNI_CFG_SCAN_CONTROL_LIST, channelPair, &len) + != eSIR_SUCCESS) { + PELOGE(lim_log + (pMac, LOGE, FL("Unable to get scan control list")); + ) + return false; + } + + if (len > WNI_CFG_SCAN_CONTROL_LIST_LEN) { + lim_log(pMac, LOGE, FL("Invalid scan control list length:%d"), + len); + return false; + } + + for (i = 0; (i + 1) < len; i += 2) { + if (channelPair[i] == channelNum) + return ((channelPair[i + 1] == + eSIR_ACTIVE_SCAN) ? true : false); + } + return false; +} + +/** + * lim_get_ht_capability() + * + ***FUNCTION: + * A utility function that returns the "current HT capability state" for the HT + * capability of interest (as requested in the API) + * + ***LOGIC: + * This routine will return with the "current" setting of a requested HT + * capability. This state info could be retrieved from - + * a) CFG (for static entries) + * b) Run time info + * - Dynamic state maintained by LIM + * - Configured at radio init time by SME + * + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * + * @param pMac Pointer to Global MAC structure + * @param htCap The HT capability being queried + * @return uint8_t The current state of the requested HT capability is returned in a + * uint8_t variable + */ + +uint8_t lim_get_ht_capability(tpAniSirGlobal pMac, + uint32_t htCap, tpPESession psessionEntry) +{ + uint8_t retVal = 0; + uint8_t *ptr; + uint32_t cfgValue; + tSirMacHTCapabilityInfo macHTCapabilityInfo = { 0 }; + tSirMacExtendedHTCapabilityInfo macExtHTCapabilityInfo = { 0 }; + tSirMacTxBFCapabilityInfo macTxBFCapabilityInfo = { 0 }; + tSirMacASCapabilityInfo macASCapabilityInfo = { 0 }; + + /* */ + /* Determine which CFG to read from. Not ALL of the HT */ + /* related CFG's need to be read each time this API is */ + /* accessed */ + /* */ + if (htCap >= eHT_ANTENNA_SELECTION && htCap < eHT_SI_GRANULARITY) { + /* Get Antenna Seletion HT Capabilities */ + if (eSIR_SUCCESS != + wlan_cfg_get_int(pMac, WNI_CFG_AS_CAP, &cfgValue)) + cfgValue = 0; + ptr = (uint8_t *) &macASCapabilityInfo; + *((uint8_t *) ptr) = (uint8_t) (cfgValue & 0xff); + } else { + if (htCap >= eHT_TX_BEAMFORMING && + htCap < eHT_ANTENNA_SELECTION) { + /* Get Transmit Beam Forming HT Capabilities */ + if (eSIR_SUCCESS != + wlan_cfg_get_int(pMac, WNI_CFG_TX_BF_CAP, &cfgValue)) + cfgValue = 0; + ptr = (uint8_t *) &macTxBFCapabilityInfo; + *((uint32_t *) ptr) = (uint32_t) (cfgValue); + } else { + if (htCap >= eHT_PCO && htCap < eHT_TX_BEAMFORMING) { + /* Get Extended HT Capabilities */ + if (eSIR_SUCCESS != + wlan_cfg_get_int(pMac, + WNI_CFG_EXT_HT_CAP_INFO, + &cfgValue)) + cfgValue = 0; + ptr = (uint8_t *) &macExtHTCapabilityInfo; + *((uint16_t *) ptr) = + (uint16_t) (cfgValue & 0xffff); + } else { + if (htCap < eHT_MAX_RX_AMPDU_FACTOR) { + /* Get HT Capabilities */ + if (eSIR_SUCCESS != + wlan_cfg_get_int(pMac, + WNI_CFG_HT_CAP_INFO, + &cfgValue)) + cfgValue = 0; + ptr = (uint8_t *) &macHTCapabilityInfo; + /* CR 265282 MDM SoftAP 2.4PL: SoftAP boot up crash in 2.4 PL builds while same WLAN SU is working on 2.1 PL */ + *ptr++ = cfgValue & 0xff; + *ptr = (cfgValue >> 8) & 0xff; + } + } + } + } + + switch (htCap) { + case eHT_LSIG_TXOP_PROTECTION: + retVal = pMac->lim.gHTLsigTXOPProtection; + break; + + case eHT_STBC_CONTROL_FRAME: + retVal = (uint8_t) macHTCapabilityInfo.stbcControlFrame; + break; + + case eHT_PSMP: + retVal = pMac->lim.gHTPSMPSupport; + break; + + case eHT_DSSS_CCK_MODE_40MHZ: + retVal = pMac->lim.gHTDsssCckRate40MHzSupport; + break; + + case eHT_MAX_AMSDU_LENGTH: + retVal = (uint8_t) macHTCapabilityInfo.maximalAMSDUsize; + break; + + case eHT_MAX_AMSDU_NUM: + retVal = (uint8_t) psessionEntry->max_amsdu_num; + break; + + case eHT_RX_STBC: + retVal = (uint8_t) psessionEntry->htConfig.ht_rx_stbc; + break; + + case eHT_TX_STBC: + retVal = (uint8_t) psessionEntry->htConfig.ht_tx_stbc; + break; + + case eHT_SHORT_GI_40MHZ: + retVal = (uint8_t) (psessionEntry->htConfig.ht_sgi40) ? + macHTCapabilityInfo.shortGI40MHz : 0; + break; + + case eHT_SHORT_GI_20MHZ: + retVal = (uint8_t) (psessionEntry->htConfig.ht_sgi20) ? + macHTCapabilityInfo.shortGI20MHz : 0; + break; + + case eHT_GREENFIELD: + retVal = (uint8_t) macHTCapabilityInfo.greenField; + break; + + case eHT_MIMO_POWER_SAVE: + retVal = (uint8_t) pMac->lim.gHTMIMOPSState; + break; + + case eHT_SUPPORTED_CHANNEL_WIDTH_SET: + retVal = (uint8_t) psessionEntry->htSupportedChannelWidthSet; + break; + + case eHT_ADVANCED_CODING: + retVal = (uint8_t) psessionEntry->htConfig.ht_rx_ldpc; + break; + + case eHT_MAX_RX_AMPDU_FACTOR: + retVal = pMac->lim.gHTMaxRxAMpduFactor; + break; + + case eHT_MPDU_DENSITY: + retVal = pMac->lim.gHTAMpduDensity; + break; + + case eHT_PCO: + retVal = (uint8_t) macExtHTCapabilityInfo.pco; + break; + + case eHT_TRANSITION_TIME: + retVal = (uint8_t) macExtHTCapabilityInfo.transitionTime; + break; + + case eHT_MCS_FEEDBACK: + retVal = (uint8_t) macExtHTCapabilityInfo.mcsFeedback; + break; + + case eHT_TX_BEAMFORMING: + retVal = (uint8_t) macTxBFCapabilityInfo.txBF; + break; + + case eHT_ANTENNA_SELECTION: + retVal = (uint8_t) macASCapabilityInfo.antennaSelection; + break; + + case eHT_SI_GRANULARITY: + retVal = pMac->lim.gHTServiceIntervalGranularity; + break; + + case eHT_CONTROLLED_ACCESS: + retVal = pMac->lim.gHTControlledAccessOnly; + break; + + case eHT_RIFS_MODE: + retVal = psessionEntry->beaconParams.fRIFSMode; + break; + + case eHT_RECOMMENDED_TX_WIDTH_SET: + retVal = psessionEntry->htRecommendedTxWidthSet; + break; + + case eHT_EXTENSION_CHANNEL_OFFSET: + retVal = psessionEntry->htSecondaryChannelOffset; + break; + + case eHT_OP_MODE: + if (LIM_IS_AP_ROLE(psessionEntry)) + retVal = psessionEntry->htOperMode; + else + retVal = pMac->lim.gHTOperMode; + break; + + case eHT_BASIC_STBC_MCS: + retVal = pMac->lim.gHTSTBCBasicMCS; + break; + + case eHT_DUAL_CTS_PROTECTION: + retVal = pMac->lim.gHTDualCTSProtection; + break; + + case eHT_LSIG_TXOP_PROTECTION_FULL_SUPPORT: + retVal = + psessionEntry->beaconParams.fLsigTXOPProtectionFullSupport; + break; + + case eHT_PCO_ACTIVE: + retVal = pMac->lim.gHTPCOActive; + break; + + case eHT_PCO_PHASE: + retVal = pMac->lim.gHTPCOPhase; + break; + + default: + break; + } + + return retVal; +} + +/** + * lim_enable_11a_protection() - updates protection params for enable 11a + * protection request + * @mac_ctx: pointer to Global MAC structure + * @overlap: 1=> called from overlap context, 0 => called from assoc context. + * @bcn_prms: beacon parameters + * @pe_session: pe session entry + * + * This fucntion updates protection params for enable 11a protection request + * + * @Return: void + */ +static void +lim_enable_11a_protection(tpAniSirGlobal mac_ctx, + uint8_t overlap, + tpUpdateBeaconParams bcn_prms, + tpPESession pe_session) +{ + /* + * If we are AP and HT capable, we need to set the HT OP mode + * appropriately. + */ + if (LIM_IS_AP_ROLE(pe_session) && (true == pe_session->htCapability)) { + if (overlap) { + mac_ctx->lim.gLimOverlap11aParams.protectionEnabled = + true; + if ((eSIR_HT_OP_MODE_OVERLAP_LEGACY != + mac_ctx->lim.gHTOperMode) + && (eSIR_HT_OP_MODE_MIXED != + mac_ctx->lim.gHTOperMode)) { + mac_ctx->lim.gHTOperMode = + eSIR_HT_OP_MODE_OVERLAP_LEGACY; + pe_session->htOperMode = + eSIR_HT_OP_MODE_OVERLAP_LEGACY; + lim_enable_ht_rifs_protection(mac_ctx, true, + overlap, bcn_prms, pe_session); + lim_enable_ht_obss_protection(mac_ctx, true, + overlap, bcn_prms, pe_session); + } + } else { + pe_session->gLim11aParams.protectionEnabled = true; + if (eSIR_HT_OP_MODE_MIXED != pe_session->htOperMode) { + mac_ctx->lim.gHTOperMode = + eSIR_HT_OP_MODE_MIXED; + pe_session->htOperMode = eSIR_HT_OP_MODE_MIXED; + lim_enable_ht_rifs_protection(mac_ctx, true, + overlap, bcn_prms, pe_session); + lim_enable_ht_obss_protection(mac_ctx, true, + overlap, bcn_prms, pe_session); + } + } + } + /* This part is common for station as well. */ + if (false == pe_session->beaconParams.llaCoexist) { + lim_log(mac_ctx, LOGW, + FL(" => protection from 11A Enabled")); + bcn_prms->llaCoexist = true; + pe_session->beaconParams.llaCoexist = true; + bcn_prms->paramChangeBitmap |= PARAM_llACOEXIST_CHANGED; + } +} + +/** + * lim_disable_11a_protection() - updates protection params for disable 11a + * protection request + * @mac_ctx: pointer to Global MAC structure + * @overlap: 1=> called from overlap context, 0 => called from assoc context. + * @bcn_prms: beacon parameters + * @pe_session: pe session entry + * + * This fucntion updates protection params for disable 11a protection request + * + * @Return: void + */ +static void +lim_disable_11a_protection(tpAniSirGlobal mac_ctx, + uint8_t overlap, + tpUpdateBeaconParams bcn_prms, + tpPESession pe_session) +{ + if (false == pe_session->beaconParams.llaCoexist) + return; + + /* for station role */ + if (!LIM_IS_AP_ROLE(pe_session)) { + lim_log(mac_ctx, LOGW, + FL("===> Protection from 11A Disabled")); + bcn_prms->llaCoexist = false; + pe_session->beaconParams.llaCoexist = false; + bcn_prms->paramChangeBitmap |= PARAM_llACOEXIST_CHANGED; + return; + } + /* + * for AP role. + * we need to take care of HT OP mode change if needed. + * We need to take care of Overlap cases. + */ + if (overlap) { + /* Overlap Legacy protection disabled. */ + mac_ctx->lim.gLimOverlap11aParams.protectionEnabled = false; + + /* + * We need to take care of HT OP mode iff we are HT AP. + * OR no HT op-mode change is needed if any of the overlap + * protection enabled. + */ + if (!pe_session->htCapability || + (mac_ctx->lim.gLimOverlap11aParams.protectionEnabled + || mac_ctx->lim.gLimOverlapHt20Params.protectionEnabled + || mac_ctx->lim.gLimOverlapNonGfParams.protectionEnabled)) + goto disable_11a_end; + + /* Check if there is a need to change HT OP mode. */ + if (eSIR_HT_OP_MODE_OVERLAP_LEGACY == + mac_ctx->lim.gHTOperMode) { + lim_enable_ht_rifs_protection(mac_ctx, false, overlap, + bcn_prms, pe_session); + lim_enable_ht_obss_protection(mac_ctx, false, overlap, + bcn_prms, pe_session); + + if (pe_session->gLimHt20Params.protectionEnabled) + mac_ctx->lim.gHTOperMode = + eSIR_HT_OP_MODE_NO_LEGACY_20MHZ_HT; + else + mac_ctx->lim.gHTOperMode = eSIR_HT_OP_MODE_PURE; + } + } else { + /* Disable protection from 11A stations. */ + pe_session->gLim11aParams.protectionEnabled = false; + lim_enable_ht_obss_protection(mac_ctx, false, overlap, + bcn_prms, pe_session); + + /* + * Check if any other non-HT protection enabled. Right now we + * are in HT OP Mixed mode. Change HT op mode appropriately. + */ + + /* Change HT OP mode to 01 if any overlap protection enabled */ + if (mac_ctx->lim.gLimOverlap11aParams.protectionEnabled + || mac_ctx->lim.gLimOverlapHt20Params.protectionEnabled + || mac_ctx->lim.gLimOverlapNonGfParams.protectionEnabled) { + mac_ctx->lim.gHTOperMode = + eSIR_HT_OP_MODE_OVERLAP_LEGACY; + pe_session->htOperMode = eSIR_HT_OP_MODE_OVERLAP_LEGACY; + lim_enable_ht_rifs_protection(mac_ctx, true, overlap, + bcn_prms, pe_session); + } else if (pe_session->gLimHt20Params.protectionEnabled) { + mac_ctx->lim.gHTOperMode = + eSIR_HT_OP_MODE_NO_LEGACY_20MHZ_HT; + pe_session->htOperMode = + eSIR_HT_OP_MODE_NO_LEGACY_20MHZ_HT; + lim_enable_ht_rifs_protection(mac_ctx, false, overlap, + bcn_prms, pe_session); + } else { + mac_ctx->lim.gHTOperMode = eSIR_HT_OP_MODE_PURE; + pe_session->htOperMode = eSIR_HT_OP_MODE_PURE; + lim_enable_ht_rifs_protection(mac_ctx, false, overlap, + bcn_prms, pe_session); + } + } + +disable_11a_end: + if (!mac_ctx->lim.gLimOverlap11aParams.protectionEnabled && + !pe_session->gLim11aParams.protectionEnabled) { + lim_log(mac_ctx, LOGW, + FL("===> Protection from 11A Disabled")); + bcn_prms->llaCoexist = false; + pe_session->beaconParams.llaCoexist = false; + bcn_prms->paramChangeBitmap |= PARAM_llACOEXIST_CHANGED; + } +} + +/** + * lim_update_11a_protection() - based on config setting enables\disables 11a + * protection. + * @mac_ctx: pointer to Global MAC structure + * @enable: 1=> enable protection, 0=> disable protection. + * @overlap: 1=> called from overlap context, 0 => called from assoc context. + * @bcn_prms: beacon parameters + * @session: pe session entry + * + * This based on config setting enables\disables 11a protection. + * + * @Return: success of failure of operation + */ +tSirRetStatus +lim_update_11a_protection(tpAniSirGlobal mac_ctx, uint8_t enable, + uint8_t overlap, tpUpdateBeaconParams bcn_prms, + tpPESession session) +{ + if (NULL == session) { + lim_log(mac_ctx, LOGW, FL("session is NULL")); + return eSIR_FAILURE; + } + /* overlapping protection configuration check. */ + if (!overlap) { + /* normal protection config check */ + if ((LIM_IS_AP_ROLE(session)) && + (!session->cfgProtection.fromlla)) { + /* protection disabled. */ + lim_log(mac_ctx, LOGW, + FL("protection from 11a is disabled")); + return eSIR_SUCCESS; + } + } + + if (enable) + lim_enable_11a_protection(mac_ctx, overlap, bcn_prms, session); + else + lim_disable_11a_protection(mac_ctx, overlap, bcn_prms, session); + + return eSIR_SUCCESS; +} + +/** + * lim_handle_enable11g_protection_enabled() - handle 11g protection enabled + * @mac_ctx: pointer to Globale Mac structure + * @beaconparams: pointer to tpUpdateBeaconParams + * @overlap: 1=> called from overlap context, 0 => called from assoc context. + * @session_entry: pointer to tpPESession + * + * Function handles 11g protection enaled case + * + * Return: none + */ +static void +lim_handle_enable11g_protection_enabled(tpAniSirGlobal mac_ctx, + tpUpdateBeaconParams beaconparams, + uint8_t overlap, tpPESession session_entry) +{ + /* + * If we are AP and HT capable, we need to set the HT OP mode + * appropriately. + */ + if (LIM_IS_AP_ROLE(session_entry) && overlap) { + session_entry->gLimOlbcParams.protectionEnabled = true; + + lim_log(mac_ctx, LOG1, FL("protection from olbc is enabled")); + + if (true == session_entry->htCapability) { + if ((eSIR_HT_OP_MODE_OVERLAP_LEGACY != + session_entry->htOperMode) && + (eSIR_HT_OP_MODE_MIXED != + session_entry->htOperMode)) { + session_entry->htOperMode = + eSIR_HT_OP_MODE_OVERLAP_LEGACY; + } + /* + * CR-263021: OBSS bit is not switching back to 0 after + * disabling the overlapping legacy BSS + */ + /* + * This fixes issue of OBSS bit not set after 11b, 11g + * station leaves + */ + lim_enable_ht_rifs_protection(mac_ctx, true, + overlap, beaconparams, session_entry); + /* + * Not processing OBSS bit from other APs, as we are + * already taking care of Protection from overlapping + * BSS based on erp IE or useProtection bit + */ + lim_enable_ht_obss_protection(mac_ctx, true, + overlap, beaconparams, session_entry); + } + } else if (LIM_IS_AP_ROLE(session_entry) && !overlap) { + session_entry->gLim11bParams.protectionEnabled = true; + lim_log(mac_ctx, LOG1, FL("protection from 11b is enabled")); + if (true == session_entry->htCapability) { + if (eSIR_HT_OP_MODE_MIXED != + session_entry->htOperMode) { + session_entry->htOperMode = + eSIR_HT_OP_MODE_MIXED; + lim_enable_ht_rifs_protection(mac_ctx, + true, overlap, beaconparams, + session_entry); + lim_enable_ht_obss_protection(mac_ctx, + true, overlap, beaconparams, + session_entry); + } + } + } + + /* This part is common for staiton as well. */ + if (false == session_entry->beaconParams.llbCoexist) { + lim_log(mac_ctx, LOG1, FL("=> 11G Protection Enabled")); + beaconparams->llbCoexist = + session_entry->beaconParams.llbCoexist = true; + beaconparams->paramChangeBitmap |= + PARAM_llBCOEXIST_CHANGED; + } +} + +/** + * lim_handle_11g_protection_for_11bcoexist() - 11g protection for 11b co-ex + * @mac_ctx: pointer to Globale Mac structure + * @beaconparams: pointer to tpUpdateBeaconParams + * @overlap: 1=> called from overlap context, 0 => called from assoc context. + * @session_entry: pointer to tpPESession + * + * Function handles 11g protection for 11b co-exist + * + * Return: none + */ +static void +lim_handle_11g_protection_for_11bcoexist(tpAniSirGlobal mac_ctx, + tpUpdateBeaconParams beaconparams, + uint8_t overlap, tpPESession session_entry) +{ + /* + * For AP role: + * we need to take care of HT OP mode change if needed. + * We need to take care of Overlap cases. + */ + if (LIM_IS_AP_ROLE(session_entry) && overlap) { + /* Overlap Legacy protection disabled. */ + session_entry->gLimOlbcParams.protectionEnabled = false; + + /* We need to take care of HT OP mode if we are HT AP. */ + if (session_entry->htCapability) { + /* + * no HT op mode change if any of the overlap + * protection enabled. + */ + if (!(session_entry->gLimOverlap11gParams. + protectionEnabled || + session_entry->gLimOverlapHt20Params. + protectionEnabled || + session_entry->gLimOverlapNonGfParams. + protectionEnabled) && + /* + * Check if there is a need to change HT + * OP mode. + */ + (eSIR_HT_OP_MODE_OVERLAP_LEGACY == + session_entry->htOperMode)) { + lim_enable_ht_rifs_protection(mac_ctx, false, + overlap, beaconparams, session_entry); + lim_enable_ht_obss_protection(mac_ctx, false, + overlap, beaconparams, session_entry); + if (session_entry->gLimHt20Params. + protectionEnabled) { + if (eHT_CHANNEL_WIDTH_20MHZ == + session_entry->htSupportedChannelWidthSet) + session_entry->htOperMode = + eSIR_HT_OP_MODE_PURE; + else + session_entry->htOperMode = + eSIR_HT_OP_MODE_NO_LEGACY_20MHZ_HT; + } else + session_entry->htOperMode = + eSIR_HT_OP_MODE_PURE; + } + } + } else if (LIM_IS_AP_ROLE(session_entry) && !overlap) { + /* Disable protection from 11B stations. */ + session_entry->gLim11bParams.protectionEnabled = false; + lim_log(mac_ctx, LOG1, FL("===> 11B Protection Disabled")); + /* Check if any other non-HT protection enabled. */ + if (!session_entry->gLim11gParams.protectionEnabled) { + /* Right now we are in HT OP Mixed mode. */ + /* Change HT op mode appropriately. */ + lim_enable_ht_obss_protection(mac_ctx, false, overlap, + beaconparams, session_entry); + /* + * Change HT OP mode to 01 if any overlap protection + * enabled + */ + if (session_entry->gLimOlbcParams.protectionEnabled || + session_entry->gLimOverlap11gParams. + protectionEnabled || + session_entry->gLimOverlapHt20Params. + protectionEnabled || + session_entry->gLimOverlapNonGfParams. + protectionEnabled) { + session_entry->htOperMode = + eSIR_HT_OP_MODE_OVERLAP_LEGACY; + lim_log(mac_ctx, LOG1, + FL("===> 11G Protection Disabled")); + lim_enable_ht_rifs_protection(mac_ctx, true, + overlap, beaconparams, + session_entry); + } else if (session_entry->gLimHt20Params. + protectionEnabled) { + /* Commenting because of CR 258588 WFA cert */ + /* session_entry->htOperMode = + eSIR_HT_OP_MODE_NO_LEGACY_20MHZ_HT; */ + session_entry->htOperMode = + eSIR_HT_OP_MODE_PURE; + lim_log(mac_ctx, LOG1, + FL("===> 11G Protection Disabled")); + lim_enable_ht_rifs_protection(mac_ctx, false, + overlap, beaconparams, + session_entry); + } else { + session_entry->htOperMode = + eSIR_HT_OP_MODE_PURE; + lim_enable_ht_rifs_protection(mac_ctx, false, + overlap, beaconparams, + session_entry); + } + } + } + if (LIM_IS_AP_ROLE(session_entry)) { + if (!session_entry->gLimOlbcParams.protectionEnabled && + !session_entry->gLim11bParams.protectionEnabled) { + lim_log(mac_ctx, LOG1, + FL("===> 11G Protection Disabled")); + beaconparams->llbCoexist = + session_entry->beaconParams.llbCoexist = + false; + beaconparams->paramChangeBitmap |= + PARAM_llBCOEXIST_CHANGED; + } + } + /* For station role */ + if (!LIM_IS_AP_ROLE(session_entry)) { + lim_log(mac_ctx, LOG1, FL("===> 11G Protection Disabled")); + beaconparams->llbCoexist = + session_entry->beaconParams.llbCoexist = false; + beaconparams->paramChangeBitmap |= + PARAM_llBCOEXIST_CHANGED; + } +} + +/** + * lim_enable11g_protection() - Function to enable 11g protection + * @mac_ctx: pointer to Global Mac structure + * @enable: 1=> enable protection, 0=> disable protection. + * @overlap: 1=> called from overlap context, 0 => called from assoc context. + * @beaconparams: pointer to tpUpdateBeaconParams + * @session_entry: pointer to tpPESession + * + * based on config setting enables\disables 11g protection. + * + * Return: Success - eSIR_SUCCESS - Success, Error number - Failure + */ +tSirRetStatus +lim_enable11g_protection(tpAniSirGlobal mac_ctx, uint8_t enable, + uint8_t overlap, tpUpdateBeaconParams beaconparams, + tpPESession session_entry) +{ + + /* overlapping protection configuration check. */ + if (!overlap) { + /* normal protection config check */ + if ((LIM_IS_AP_ROLE(session_entry)) && + !session_entry->cfgProtection.fromllb) { + /* protection disabled. */ + lim_log(mac_ctx, LOG1, + FL("protection from 11b is disabled")); + return eSIR_SUCCESS; + } else if (!LIM_IS_AP_ROLE(session_entry)) { + if (!mac_ctx->lim.cfgProtection.fromllb) { + /* protection disabled. */ + lim_log(mac_ctx, LOG1, + FL("protection from 11b is disabled")); + return eSIR_SUCCESS; + } + } + } + + if (enable) { + lim_handle_enable11g_protection_enabled(mac_ctx, beaconparams, + overlap, session_entry); + } else if (true == session_entry->beaconParams.llbCoexist) { + lim_handle_11g_protection_for_11bcoexist(mac_ctx, beaconparams, + overlap, session_entry); + } + return eSIR_SUCCESS; +} + +/** ------------------------------------------------------------- + \fn lim_enable_ht_protection_from11g + \brief based on cofig enables\disables protection from 11g. + \param uint8_t enable : 1=> enable protection, 0=> disable protection. + \param uint8_t overlap: 1=> called from overlap context, 0 => called from assoc context. + \param tpUpdateBeaconParams pBeaconParams + \return None + -------------------------------------------------------------*/ +tSirRetStatus +lim_enable_ht_protection_from11g(tpAniSirGlobal pMac, uint8_t enable, + uint8_t overlap, + tpUpdateBeaconParams pBeaconParams, + tpPESession psessionEntry) +{ + if (!psessionEntry->htCapability) + return eSIR_SUCCESS; /* protection from 11g is only for HT stations. */ + + /* overlapping protection configuration check. */ + if (overlap) { + if ((LIM_IS_AP_ROLE(psessionEntry)) + && (!psessionEntry->cfgProtection.overlapFromllg)) { + /* protection disabled. */ + PELOG3(lim_log + (pMac, LOG3, + FL("overlap protection from 11g is disabled")); + ); + return eSIR_SUCCESS; + } + } else { + /* normal protection config check */ + if (LIM_IS_AP_ROLE(psessionEntry) && + !psessionEntry->cfgProtection.fromllg) { + /* protection disabled. */ + PELOG3(lim_log + (pMac, LOG3, + FL("protection from 11g is disabled")); + ) + return eSIR_SUCCESS; + } else if (!LIM_IS_AP_ROLE(psessionEntry)) { + if (!pMac->lim.cfgProtection.fromllg) { + /* protection disabled. */ + PELOG3(lim_log + (pMac, LOG3, + FL("protection from 11g is disabled")); + ) + return eSIR_SUCCESS; + } + } + } + if (enable) { + /* If we are AP and HT capable, we need to set the HT OP mode */ + /* appropriately. */ + + if (LIM_IS_AP_ROLE(psessionEntry)) { + if (overlap) { + psessionEntry->gLimOverlap11gParams. + protectionEnabled = true; + /* 11g exists in overlap BSS. */ + /* need not to change the operating mode to overlap_legacy */ + /* if higher or same protection operating mode is enabled right now. */ + if ((eSIR_HT_OP_MODE_OVERLAP_LEGACY != + psessionEntry->htOperMode) + && (eSIR_HT_OP_MODE_MIXED != + psessionEntry->htOperMode)) { + psessionEntry->htOperMode = + eSIR_HT_OP_MODE_OVERLAP_LEGACY; + } + lim_enable_ht_rifs_protection(pMac, true, overlap, + pBeaconParams, + psessionEntry); + lim_enable_ht_obss_protection(pMac, true, overlap, + pBeaconParams, + psessionEntry); + } else { + /* 11g is associated to an AP operating in 11n mode. */ + /* Change the HT operating mode to 'mixed mode'. */ + psessionEntry->gLim11gParams.protectionEnabled = + true; + if (eSIR_HT_OP_MODE_MIXED != + psessionEntry->htOperMode) { + psessionEntry->htOperMode = + eSIR_HT_OP_MODE_MIXED; + lim_enable_ht_rifs_protection(pMac, true, + overlap, + pBeaconParams, + psessionEntry); + lim_enable_ht_obss_protection(pMac, true, + overlap, + pBeaconParams, + psessionEntry); + } + } + } + /* This part is common for staiton as well. */ + if (false == psessionEntry->beaconParams.llgCoexist) { + pBeaconParams->llgCoexist = + psessionEntry->beaconParams.llgCoexist = true; + pBeaconParams->paramChangeBitmap |= + PARAM_llGCOEXIST_CHANGED; + } else if (true == + psessionEntry->gLimOverlap11gParams. + protectionEnabled) { + /* As operating mode changed after G station assoc some way to update beacon */ + /* This addresses the issue of mode not changing to - 11 in beacon when OBSS overlap is enabled */ + /* pMac->sch.schObject.fBeaconChanged = 1; */ + pBeaconParams->paramChangeBitmap |= + PARAM_llGCOEXIST_CHANGED; + } + } else if (true == psessionEntry->beaconParams.llgCoexist) { + /* for AP role. */ + /* we need to take care of HT OP mode change if needed. */ + /* We need to take care of Overlap cases. */ + + if (LIM_IS_AP_ROLE(psessionEntry)) { + if (overlap) { + /* Overlap Legacy protection disabled. */ + if (psessionEntry->gLim11gParams.numSta == 0) + psessionEntry->gLimOverlap11gParams. + protectionEnabled = false; + + /* no HT op mode change if any of the overlap protection enabled. */ + if (! + (psessionEntry->gLimOlbcParams. + protectionEnabled + || psessionEntry->gLimOverlapHt20Params. + protectionEnabled + || psessionEntry->gLimOverlapNonGfParams. + protectionEnabled)) { + /* Check if there is a need to change HT OP mode. */ + if (eSIR_HT_OP_MODE_OVERLAP_LEGACY == + psessionEntry->htOperMode) { + lim_enable_ht_rifs_protection(pMac, + false, + overlap, + pBeaconParams, + psessionEntry); + lim_enable_ht_obss_protection(pMac, + false, + overlap, + pBeaconParams, + psessionEntry); + + if (psessionEntry->gLimHt20Params.protectionEnabled) { + if (eHT_CHANNEL_WIDTH_20MHZ == + psessionEntry->htSupportedChannelWidthSet) + psessionEntry->htOperMode = + eSIR_HT_OP_MODE_PURE; + else + psessionEntry->htOperMode = + eSIR_HT_OP_MODE_NO_LEGACY_20MHZ_HT; + } else + psessionEntry->htOperMode = + eSIR_HT_OP_MODE_PURE; + } + } + } else { + /* Disable protection from 11G stations. */ + psessionEntry->gLim11gParams.protectionEnabled = + false; + /* Check if any other non-HT protection enabled. */ + if (!psessionEntry->gLim11bParams. + protectionEnabled) { + + /* Right now we are in HT OP Mixed mode. */ + /* Change HT op mode appropriately. */ + lim_enable_ht_obss_protection(pMac, false, + overlap, + pBeaconParams, + psessionEntry); + + /* Change HT OP mode to 01 if any overlap protection enabled */ + if (psessionEntry->gLimOlbcParams. + protectionEnabled + || psessionEntry-> + gLimOverlap11gParams. + protectionEnabled + || psessionEntry-> + gLimOverlapHt20Params. + protectionEnabled + || psessionEntry-> + gLimOverlapNonGfParams. + protectionEnabled) { + psessionEntry->htOperMode = + eSIR_HT_OP_MODE_OVERLAP_LEGACY; + lim_enable_ht_rifs_protection(pMac, + true, + overlap, + pBeaconParams, + psessionEntry); + } else if (psessionEntry-> + gLimHt20Params. + protectionEnabled) { + /* Commenting because of CR 258588 WFA cert */ + /* psessionEntry->htOperMode = eSIR_HT_OP_MODE_NO_LEGACY_20MHZ_HT; */ + psessionEntry->htOperMode = + eSIR_HT_OP_MODE_PURE; + lim_enable_ht_rifs_protection(pMac, + false, + overlap, + pBeaconParams, + psessionEntry); + } else { + psessionEntry->htOperMode = + eSIR_HT_OP_MODE_PURE; + lim_enable_ht_rifs_protection(pMac, + false, + overlap, + pBeaconParams, + psessionEntry); + } + } + } + if (!psessionEntry->gLimOverlap11gParams. + protectionEnabled + && !psessionEntry->gLim11gParams. + protectionEnabled) { + PELOG1(lim_log + (pMac, LOG1, + FL + ("===> Protection from 11G Disabled")); + ) + pBeaconParams->llgCoexist = + psessionEntry->beaconParams.llgCoexist = + false; + pBeaconParams->paramChangeBitmap |= + PARAM_llGCOEXIST_CHANGED; + } + } + /* for station role */ + else { + PELOG1(lim_log + (pMac, LOG1, + FL("===> Protection from 11G Disabled")); + ) + pBeaconParams->llgCoexist = + psessionEntry->beaconParams.llgCoexist = false; + pBeaconParams->paramChangeBitmap |= + PARAM_llGCOEXIST_CHANGED; + } + } + return eSIR_SUCCESS; +} + +/* FIXME_PROTECTION : need to check for no APSD whenever we want to enable this protection. */ +/* This check will be done at the caller. */ + +/** ------------------------------------------------------------- + \fn limEnableHtObssProtection + \brief based on cofig enables\disables obss protection. + \param uint8_t enable : 1=> enable protection, 0=> disable protection. + \param uint8_t overlap: 1=> called from overlap context, 0 => called from assoc context. + \param tpUpdateBeaconParams pBeaconParams + \return None + -------------------------------------------------------------*/ +tSirRetStatus +lim_enable_ht_obss_protection(tpAniSirGlobal pMac, uint8_t enable, + uint8_t overlap, tpUpdateBeaconParams pBeaconParams, + tpPESession psessionEntry) +{ + + if (!psessionEntry->htCapability) + return eSIR_SUCCESS; /* this protection is only for HT stations. */ + + /* overlapping protection configuration check. */ + if (overlap) { + /* overlapping protection configuration check. */ + } else { + /* normal protection config check */ + if ((LIM_IS_AP_ROLE(psessionEntry)) && + !psessionEntry->cfgProtection.obss) { /* ToDo Update this field */ + /* protection disabled. */ + PELOG1(lim_log + (pMac, LOG1, + FL("protection from Obss is disabled")); + ) + return eSIR_SUCCESS; + } else if (!LIM_IS_AP_ROLE(psessionEntry)) { + if (!pMac->lim.cfgProtection.obss) { /* ToDo Update this field */ + /* protection disabled. */ + PELOG1(lim_log + (pMac, LOG1, + FL("protection from Obss is disabled")); + ) + return eSIR_SUCCESS; + } + } + } + + if (LIM_IS_AP_ROLE(psessionEntry)) { + if ((enable) + && (false == psessionEntry->beaconParams.gHTObssMode)) { + PELOG1(lim_log + (pMac, LOG1, FL("=>obss protection enabled")); + ) + psessionEntry->beaconParams.gHTObssMode = true; + pBeaconParams->paramChangeBitmap |= PARAM_OBSS_MODE_CHANGED; /* UPDATE AN ENUM FOR OBSS MODE */ + + } else if (!enable + && (true == + psessionEntry->beaconParams.gHTObssMode)) { + PELOG1(lim_log + (pMac, LOG1, + FL("===> obss Protection disabled")); + ) + psessionEntry->beaconParams.gHTObssMode = false; + pBeaconParams->paramChangeBitmap |= + PARAM_OBSS_MODE_CHANGED; + + } +/* CR-263021: OBSS bit is not switching back to 0 after disabling the overlapping legacy BSS */ + if (!enable && !overlap) { + psessionEntry->gLimOverlap11gParams.protectionEnabled = + false; + } + } else { + if ((enable) + && (false == psessionEntry->beaconParams.gHTObssMode)) { + PELOG1(lim_log + (pMac, LOG1, FL("=>obss protection enabled")); + ) + psessionEntry->beaconParams.gHTObssMode = true; + pBeaconParams->paramChangeBitmap |= PARAM_OBSS_MODE_CHANGED; /* UPDATE AN ENUM FOR OBSS MODE */ + + } else if (!enable + && (true == + psessionEntry->beaconParams.gHTObssMode)) { + + PELOG1(lim_log + (pMac, LOG1, + FL("===> obss Protection disabled")); + ) + psessionEntry->beaconParams.gHTObssMode = false; + pBeaconParams->paramChangeBitmap |= + PARAM_OBSS_MODE_CHANGED; + + } + } + return eSIR_SUCCESS; +} + +/** + * lim_handle_ht20protection_enabled() - Handle ht20 protection enabled + * @mac_ctx: pointer to Gloal Mac Structure + * @overlap: variable for overlap detection + * @beaconparams: pointer to tpUpdateBeaconParams + * @session_entry: pointer to tpPESession + * + * Function handles ht20 protection enabled + * + * Return: none + */ +static void lim_handle_ht20protection_enabled(tpAniSirGlobal mac_ctx, + uint8_t overlap, tpUpdateBeaconParams beaconparams, + tpPESession session_entry) +{ + /* + * If we are AP and HT capable, we need to set the HT OP mode + * appropriately. + */ + if (LIM_IS_AP_ROLE(session_entry) && overlap) { + session_entry->gLimOverlapHt20Params.protectionEnabled = true; + if ((eSIR_HT_OP_MODE_OVERLAP_LEGACY != + session_entry->htOperMode) && + (eSIR_HT_OP_MODE_MIXED != + session_entry->htOperMode)) { + session_entry->htOperMode = + eSIR_HT_OP_MODE_OVERLAP_LEGACY; + lim_enable_ht_rifs_protection(mac_ctx, true, + overlap, beaconparams, session_entry); + } + } else if (LIM_IS_AP_ROLE(session_entry) && !overlap) { + session_entry->gLimHt20Params.protectionEnabled = true; + if (eSIR_HT_OP_MODE_PURE == session_entry->htOperMode) { + if (session_entry->htSupportedChannelWidthSet != + eHT_CHANNEL_WIDTH_20MHZ) + session_entry->htOperMode = + eSIR_HT_OP_MODE_NO_LEGACY_20MHZ_HT; + lim_enable_ht_rifs_protection(mac_ctx, false, + overlap, beaconparams, session_entry); + lim_enable_ht_obss_protection(mac_ctx, false, + overlap, beaconparams, session_entry); + } + } + /* This part is common for staiton as well. */ + if (false == session_entry->beaconParams.ht20Coexist) { + lim_log(mac_ctx, LOG1, + FL("=> Protection from HT20 Enabled")); + beaconparams->ht20MhzCoexist = + session_entry->beaconParams.ht20Coexist = true; + beaconparams->paramChangeBitmap |= + PARAM_HT20MHZCOEXIST_CHANGED; + } +} + +/** + * lim_handle_ht20coexist_ht20protection() - ht20 protection for ht20 coexist + * @mac_ctx: pointer to Gloal Mac Structure + * @beaconparams: pointer to tpUpdateBeaconParams + * @session_entry: pointer to tpPESession + * @overlap: variable for overlap detection + * + * Function handles ht20 protection for ht20 coexist + * + * Return: none + */ +static void lim_handle_ht20coexist_ht20protection(tpAniSirGlobal mac_ctx, + tpUpdateBeaconParams beaconparams, + tpPESession session_entry, uint8_t overlap) +{ + /* + * For AP role: + * we need to take care of HT OP mode change if needed. + * We need to take care of Overlap cases. + */ + if (LIM_IS_AP_ROLE(session_entry) && overlap) { + /* Overlap Legacy protection disabled. */ + session_entry->gLimOverlapHt20Params.protectionEnabled = + false; + /* + * no HT op mode change if any of the overlap + * protection enabled. + */ + if (!(session_entry->gLimOlbcParams.protectionEnabled || + session_entry->gLimOverlap11gParams.protectionEnabled || + session_entry->gLimOverlapHt20Params.protectionEnabled + || session_entry->gLimOverlapNonGfParams. + protectionEnabled) && + /* + * Check if there is a need to change HT + * OP mode. + */ + (eSIR_HT_OP_MODE_OVERLAP_LEGACY == + session_entry->htOperMode)) { + if (session_entry->gLimHt20Params. + protectionEnabled) { + if (eHT_CHANNEL_WIDTH_20MHZ == + session_entry->htSupportedChannelWidthSet) + session_entry->htOperMode = + eSIR_HT_OP_MODE_PURE; + else + session_entry->htOperMode = + eSIR_HT_OP_MODE_NO_LEGACY_20MHZ_HT; + + lim_enable_ht_rifs_protection(mac_ctx, + false, overlap, beaconparams, + session_entry); + lim_enable_ht_obss_protection(mac_ctx, + false, overlap, beaconparams, + session_entry); + } else { + session_entry->htOperMode = + eSIR_HT_OP_MODE_PURE; + } + } + } else if (LIM_IS_AP_ROLE(session_entry) && !overlap) { + /* Disable protection from 11G stations. */ + session_entry->gLimHt20Params.protectionEnabled = false; + /* Change HT op mode appropriately. */ + if (eSIR_HT_OP_MODE_NO_LEGACY_20MHZ_HT == + session_entry->htOperMode) { + session_entry->htOperMode = + eSIR_HT_OP_MODE_PURE; + lim_enable_ht_rifs_protection(mac_ctx, false, + overlap, beaconparams, session_entry); + lim_enable_ht_obss_protection(mac_ctx, false, + overlap, beaconparams, session_entry); + } + } + if (LIM_IS_AP_ROLE(session_entry)) { + lim_log(mac_ctx, LOG1, + FL("===> Protection from HT 20 Disabled")); + beaconparams->ht20MhzCoexist = + session_entry->beaconParams.ht20Coexist = false; + beaconparams->paramChangeBitmap |= + PARAM_HT20MHZCOEXIST_CHANGED; + } + if (!LIM_IS_AP_ROLE(session_entry)) { + /* For station role */ + lim_log(mac_ctx, LOG1, + FL("===> Protection from HT20 Disabled")); + beaconparams->ht20MhzCoexist = + session_entry->beaconParams.ht20Coexist = false; + beaconparams->paramChangeBitmap |= + PARAM_HT20MHZCOEXIST_CHANGED; + } +} + +/** + * lim_enable_ht20_protection() - Function to enable ht20 protection + * @mac_ctx: pointer to Global Mac structure + * @enable: 1=> enable protection, 0=> disable protection. + * @overlap: 1=> called from overlap context, 0 => called from assoc context. + * @beaconparams: pointer to tpUpdateBeaconParams + * @session_entry: pointer to tpPESession + * + * based on cofig enables\disables protection from Ht20 + * + * Return: 0 - success + */ +tSirRetStatus lim_enable_ht20_protection(tpAniSirGlobal mac_ctx, uint8_t enable, + uint8_t overlap, tpUpdateBeaconParams beaconparams, + tpPESession session_entry) +{ + /* This protection is only for HT stations. */ + if (!session_entry->htCapability) + return eSIR_SUCCESS; + + /* overlapping protection configuration check. */ + if (!overlap) { + /* normal protection config check */ + if ((LIM_IS_AP_ROLE(session_entry)) && + !session_entry->cfgProtection.ht20) { + /* protection disabled. */ + lim_log(mac_ctx, LOG3, + FL("protection from HT20 is disabled")); + return eSIR_SUCCESS; + } else if (!LIM_IS_AP_ROLE(session_entry)) { + if (!mac_ctx->lim.cfgProtection.ht20) { + /* protection disabled. */ + lim_log(mac_ctx, LOG3, + FL("protection from HT20 is disabled")); + return eSIR_SUCCESS; + } + } + } + + if (enable) + lim_handle_ht20protection_enabled(mac_ctx, overlap, + beaconparams, session_entry); + else if (true == session_entry->beaconParams.ht20Coexist) + lim_handle_ht20coexist_ht20protection(mac_ctx, beaconparams, + session_entry, overlap); + + return eSIR_SUCCESS; +} + +/** ------------------------------------------------------------- + \fn lim_enable_ht_non_gf_protection + \brief based on cofig enables\disables protection from NonGf. + \param uint8_t enable : 1=> enable protection, 0=> disable protection. + \param uint8_t overlap: 1=> called from overlap context, 0 => called from assoc context. + \param tpUpdateBeaconParams pBeaconParams + \return None + -------------------------------------------------------------*/ +tSirRetStatus +lim_enable_ht_non_gf_protection(tpAniSirGlobal pMac, uint8_t enable, + uint8_t overlap, tpUpdateBeaconParams pBeaconParams, + tpPESession psessionEntry) +{ + if (!psessionEntry->htCapability) + return eSIR_SUCCESS; /* this protection is only for HT stations. */ + + /* overlapping protection configuration check. */ + if (overlap) { + } else { + /* normal protection config check */ + if (LIM_IS_AP_ROLE(psessionEntry) && + !psessionEntry->cfgProtection.nonGf) { + /* protection disabled. */ + PELOG3(lim_log + (pMac, LOG3, + FL("protection from NonGf is disabled")); + ) + return eSIR_SUCCESS; + } else if (!LIM_IS_AP_ROLE(psessionEntry)) { + /* normal protection config check */ + if (!pMac->lim.cfgProtection.nonGf) { + /* protection disabled. */ + PELOG3(lim_log + (pMac, LOG3, + FL + ("protection from NonGf is disabled")); + ) + return eSIR_SUCCESS; + } + } + } + if (LIM_IS_AP_ROLE(psessionEntry)) { + if ((enable) + && (false == psessionEntry->beaconParams.llnNonGFCoexist)) { + PELOG1(lim_log + (pMac, LOG1, + FL(" => Protection from non GF Enabled")); + ) + pBeaconParams->llnNonGFCoexist = + psessionEntry->beaconParams.llnNonGFCoexist = true; + pBeaconParams->paramChangeBitmap |= + PARAM_NON_GF_DEVICES_PRESENT_CHANGED; + } else if (!enable + && (true == + psessionEntry->beaconParams.llnNonGFCoexist)) { + PELOG1(lim_log + (pMac, LOG1, + FL("===> Protection from Non GF Disabled")); + ) + pBeaconParams->llnNonGFCoexist = + psessionEntry->beaconParams.llnNonGFCoexist = false; + pBeaconParams->paramChangeBitmap |= + PARAM_NON_GF_DEVICES_PRESENT_CHANGED; + } + } else { + if ((enable) + && (false == psessionEntry->beaconParams.llnNonGFCoexist)) { + PELOG1(lim_log + (pMac, LOG1, + FL(" => Protection from non GF Enabled")); + ) + pBeaconParams->llnNonGFCoexist = + psessionEntry->beaconParams.llnNonGFCoexist = true; + pBeaconParams->paramChangeBitmap |= + PARAM_NON_GF_DEVICES_PRESENT_CHANGED; + } else if (!enable + && (true == + psessionEntry->beaconParams.llnNonGFCoexist)) { + PELOG1(lim_log + (pMac, LOG1, + FL("===> Protection from Non GF Disabled")); + ) + pBeaconParams->llnNonGFCoexist = + psessionEntry->beaconParams.llnNonGFCoexist = false; + pBeaconParams->paramChangeBitmap |= + PARAM_NON_GF_DEVICES_PRESENT_CHANGED; + } + } + + return eSIR_SUCCESS; +} + +/** ------------------------------------------------------------- + \fn lim_enable_ht_lsig_txop_protection + \brief based on cofig enables\disables LsigTxop protection. + \param uint8_t enable : 1=> enable protection, 0=> disable protection. + \param uint8_t overlap: 1=> called from overlap context, 0 => called from assoc context. + \param tpUpdateBeaconParams pBeaconParams + \return None + -------------------------------------------------------------*/ +tSirRetStatus +lim_enable_ht_lsig_txop_protection(tpAniSirGlobal pMac, uint8_t enable, + uint8_t overlap, + tpUpdateBeaconParams pBeaconParams, + tpPESession psessionEntry) +{ + if (!psessionEntry->htCapability) + return eSIR_SUCCESS; /* this protection is only for HT stations. */ + + /* overlapping protection configuration check. */ + if (overlap) { + } else { + /* normal protection config check */ + if (LIM_IS_AP_ROLE(psessionEntry) && + !psessionEntry->cfgProtection.lsigTxop) { + /* protection disabled. */ + PELOG3(lim_log + (pMac, LOG3, + FL + (" protection from LsigTxop not supported is disabled")); + ) + return eSIR_SUCCESS; + } else if (!LIM_IS_AP_ROLE(psessionEntry)) { + /* normal protection config check */ + if (!pMac->lim.cfgProtection.lsigTxop) { + /* protection disabled. */ + PELOG3(lim_log + (pMac, LOG3, + FL + (" protection from LsigTxop not supported is disabled")); + ) + return eSIR_SUCCESS; + } + } + } + + if (LIM_IS_AP_ROLE(psessionEntry)) { + if ((enable) + && (false == + psessionEntry->beaconParams. + fLsigTXOPProtectionFullSupport)) { + PELOG1(lim_log + (pMac, LOG1, + FL(" => Protection from LsigTxop Enabled")); + ) + pBeaconParams->fLsigTXOPProtectionFullSupport = + psessionEntry->beaconParams. + fLsigTXOPProtectionFullSupport = true; + pBeaconParams->paramChangeBitmap |= + PARAM_LSIG_TXOP_FULL_SUPPORT_CHANGED; + } else if (!enable + && (true == + psessionEntry->beaconParams. + fLsigTXOPProtectionFullSupport)) { + PELOG1(lim_log + (pMac, LOG1, + FL("===> Protection from LsigTxop Disabled")); + ) + pBeaconParams->fLsigTXOPProtectionFullSupport = + psessionEntry->beaconParams. + fLsigTXOPProtectionFullSupport = false; + pBeaconParams->paramChangeBitmap |= + PARAM_LSIG_TXOP_FULL_SUPPORT_CHANGED; + } + } else { + if ((enable) + && (false == + psessionEntry->beaconParams. + fLsigTXOPProtectionFullSupport)) { + PELOG1(lim_log + (pMac, LOG1, + FL(" => Protection from LsigTxop Enabled")); + ) + pBeaconParams->fLsigTXOPProtectionFullSupport = + psessionEntry->beaconParams. + fLsigTXOPProtectionFullSupport = true; + pBeaconParams->paramChangeBitmap |= + PARAM_LSIG_TXOP_FULL_SUPPORT_CHANGED; + } else if (!enable + && (true == + psessionEntry->beaconParams. + fLsigTXOPProtectionFullSupport)) { + PELOG1(lim_log + (pMac, LOG1, + FL("===> Protection from LsigTxop Disabled")); + ) + pBeaconParams->fLsigTXOPProtectionFullSupport = + psessionEntry->beaconParams. + fLsigTXOPProtectionFullSupport = false; + pBeaconParams->paramChangeBitmap |= + PARAM_LSIG_TXOP_FULL_SUPPORT_CHANGED; + } + } + return eSIR_SUCCESS; +} + +/* FIXME_PROTECTION : need to check for no APSD whenever we want to enable this protection. */ +/* This check will be done at the caller. */ +/** ------------------------------------------------------------- + \fn lim_enable_ht_rifs_protection + \brief based on cofig enables\disables Rifs protection. + \param uint8_t enable : 1=> enable protection, 0=> disable protection. + \param uint8_t overlap: 1=> called from overlap context, 0 => called from assoc context. + \param tpUpdateBeaconParams pBeaconParams + \return None + -------------------------------------------------------------*/ +tSirRetStatus +lim_enable_ht_rifs_protection(tpAniSirGlobal pMac, uint8_t enable, + uint8_t overlap, tpUpdateBeaconParams pBeaconParams, + tpPESession psessionEntry) +{ + if (!psessionEntry->htCapability) + return eSIR_SUCCESS; /* this protection is only for HT stations. */ + + /* overlapping protection configuration check. */ + if (overlap) { + } else { + /* normal protection config check */ + if (LIM_IS_AP_ROLE(psessionEntry) && + !psessionEntry->cfgProtection.rifs) { + /* protection disabled. */ + PELOG3(lim_log + (pMac, LOG3, + FL(" protection from Rifs is disabled")); + ) + return eSIR_SUCCESS; + } else if (!LIM_IS_AP_ROLE(psessionEntry)) { + /* normal protection config check */ + if (!pMac->lim.cfgProtection.rifs) { + /* protection disabled. */ + PELOG3(lim_log + (pMac, LOG3, + FL + (" protection from Rifs is disabled")); + ) + return eSIR_SUCCESS; + } + } + } + + if (LIM_IS_AP_ROLE(psessionEntry)) { + /* Disabling the RIFS Protection means Enable the RIFS mode of operation in the BSS */ + if ((!enable) + && (false == psessionEntry->beaconParams.fRIFSMode)) { + PELOG1(lim_log + (pMac, LOG1, FL(" => Rifs protection Disabled")); + ) + pBeaconParams->fRIFSMode = + psessionEntry->beaconParams.fRIFSMode = true; + pBeaconParams->paramChangeBitmap |= + PARAM_RIFS_MODE_CHANGED; + } + /* Enabling the RIFS Protection means Disable the RIFS mode of operation in the BSS */ + else if (enable + && (true == psessionEntry->beaconParams.fRIFSMode)) { + PELOG1(lim_log + (pMac, LOG1, FL("===> Rifs Protection Enabled")); + ) + pBeaconParams->fRIFSMode = + psessionEntry->beaconParams.fRIFSMode = false; + pBeaconParams->paramChangeBitmap |= + PARAM_RIFS_MODE_CHANGED; + } + } else { + /* Disabling the RIFS Protection means Enable the RIFS mode of operation in the BSS */ + if ((!enable) + && (false == psessionEntry->beaconParams.fRIFSMode)) { + PELOG1(lim_log + (pMac, LOG1, FL(" => Rifs protection Disabled")); + ) + pBeaconParams->fRIFSMode = + psessionEntry->beaconParams.fRIFSMode = true; + pBeaconParams->paramChangeBitmap |= + PARAM_RIFS_MODE_CHANGED; + } + /* Enabling the RIFS Protection means Disable the RIFS mode of operation in the BSS */ + else if (enable + && (true == psessionEntry->beaconParams.fRIFSMode)) { + PELOG1(lim_log + (pMac, LOG1, FL("===> Rifs Protection Enabled")); + ) + pBeaconParams->fRIFSMode = + psessionEntry->beaconParams.fRIFSMode = false; + pBeaconParams->paramChangeBitmap |= + PARAM_RIFS_MODE_CHANGED; + } + } + return eSIR_SUCCESS; +} + +/* --------------------------------------------------------------------- */ +/** + * lim_enable_short_preamble + * + * FUNCTION: + * Enable/Disable short preamble + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param enable Flag to enable/disable short preamble + * @return None + */ + +tSirRetStatus +lim_enable_short_preamble(tpAniSirGlobal pMac, uint8_t enable, + tpUpdateBeaconParams pBeaconParams, + tpPESession psessionEntry) +{ + uint32_t val; + + if (wlan_cfg_get_int(pMac, WNI_CFG_SHORT_PREAMBLE, &val) != eSIR_SUCCESS) { + /* Could not get short preamble enabled flag from CFG. Log error. */ + lim_log(pMac, LOGP, + FL("could not retrieve short preamble flag")); + return eSIR_FAILURE; + } + + if (!val) + return eSIR_SUCCESS; + + if (wlan_cfg_get_int(pMac, WNI_CFG_11G_SHORT_PREAMBLE_ENABLED, &val) != + eSIR_SUCCESS) { + lim_log(pMac, LOGP, + FL + ("could not retrieve 11G short preamble switching enabled flag")); + return eSIR_FAILURE; + } + + if (!val) /* 11G short preamble switching is disabled. */ + return eSIR_SUCCESS; + + if (LIM_IS_AP_ROLE(psessionEntry)) { + if (enable && (psessionEntry->beaconParams.fShortPreamble == 0)) { + PELOG1(lim_log + (pMac, LOG1, FL("===> Short Preamble Enabled")); + ) + psessionEntry->beaconParams.fShortPreamble = true; + pBeaconParams->fShortPreamble = + (uint8_t) psessionEntry->beaconParams. + fShortPreamble; + pBeaconParams->paramChangeBitmap |= + PARAM_SHORT_PREAMBLE_CHANGED; + } else if (!enable + && (psessionEntry->beaconParams.fShortPreamble == + 1)) { + PELOG1(lim_log + (pMac, LOG1, FL("===> Short Preamble Disabled")); + ) + psessionEntry->beaconParams.fShortPreamble = false; + pBeaconParams->fShortPreamble = + (uint8_t) psessionEntry->beaconParams. + fShortPreamble; + pBeaconParams->paramChangeBitmap |= + PARAM_SHORT_PREAMBLE_CHANGED; + } + } + + return eSIR_SUCCESS; +} + +/** + * lim_tx_complete + * + * Function: + * This is LIM's very own "TX MGMT frame complete" completion routine. + * + * Logic: + * LIM wants to send a MGMT frame (broadcast or unicast) + * LIM allocates memory using cds_packet_alloc( ..., **pData, **pPacket ) + * LIM transmits the MGMT frame using the API: + * wma_tx_frame( ... pPacket, ..., (void *) lim_tx_complete, pData ) + * HDD, via wma_tx_frame/DXE, "transfers" the packet over to BMU + * HDD, if it determines that a TX completion routine (in this case + * lim_tx_complete) has been provided, will invoke this callback + * LIM will try to free the TX MGMT packet that was earlier allocated, in order + * to send this MGMT frame, using the PAL API cds_packet_free( ... pData, pPacket ) + * + * Assumptions: + * Presently, this is ONLY being used for MGMT frames/packets + * TODO: + * Would it do good for LIM to have some sort of "signature" validation to + * ensure that the pData argument passed in was a buffer that was actually + * allocated by LIM and/or is not corrupted? + * + * Note: FIXME and TODO + * Looks like cds_packet_free() is interested in pPacket. But, when this completion + * routine is called, only pData is made available to LIM!! + * + * @param void A pointer to pData. Shouldn't it be pPacket?! + * + * @return none + */ +void lim_tx_complete(tHalHandle hHal, void *data, bool free) +{ + if (free) + cds_packet_free((void *)data); +} + +/** + * \brief This function updates lim global structure, if CB parameters in the BSS + * have changed, and sends an indication to HAL also with the + * updated HT Parameters. + * This function does not detect the change in the primary channel, that is done as part + * of channel Swtich IE processing. + * If STA is configured with '20Mhz only' mode, then this function does not do anything + * This function changes the CB mode, only if the self capability is set to '20 as well as 40Mhz' + * + * + * \param pMac Pointer to global MAC structure + * + * \param pRcvdHTInfo Pointer to HT Info IE obtained from a Beacon or + * Probe Response + * + * \param bssIdx BSS Index of the Bss to which Station is associated. + * + * + */ + +void lim_update_sta_run_time_ht_switch_chnl_params(tpAniSirGlobal pMac, + tDot11fIEHTInfo *pHTInfo, + uint8_t bssIdx, + tpPESession psessionEntry) +{ + uint8_t center_freq = 0; + + /* If self capability is set to '20Mhz only', then do not change the CB mode. */ + if (!lim_get_ht_capability + (pMac, eHT_SUPPORTED_CHANNEL_WIDTH_SET, psessionEntry)) + return; + + if (psessionEntry->ftPEContext.ftPreAuthSession) { + lim_log(pMac, LOGE, + FL("FT PREAUTH channel change is in progress")); + return; + } + + /* + * Do not try to switch channel if RoC is in progress. RoC code path + * uses pMac->lim.gpLimRemainOnChanReq to notify the upper layers that + * the device has started listening on the channel requested as part of + * RoC, if we set pMac->lim.gpLimRemainOnChanReq to NULL as we do below + * then the upper layers will think that the channel change is not + * successful and the RoC from the upper layer perspective will never + * end... + */ + if (pMac->lim.gpLimRemainOnChanReq) { + lim_log(pMac, LOG1, FL("RoC is in progress")); + return; + } + + if (psessionEntry->ch_switch_in_progress == true) { + pe_debug("ch switch is in progress, ignore HT IE BW update"); + return; + } + + if (!pHTInfo->primaryChannel) { + pe_debug("Ignore as primary channel is 0 in HT info"); + return; + } + + if (psessionEntry->htSecondaryChannelOffset != + (uint8_t) pHTInfo->secondaryChannelOffset + || psessionEntry->htRecommendedTxWidthSet != + (uint8_t) pHTInfo->recommendedTxWidthSet) { + psessionEntry->htSecondaryChannelOffset = + (ePhyChanBondState) pHTInfo->secondaryChannelOffset; + psessionEntry->htRecommendedTxWidthSet = + (uint8_t) pHTInfo->recommendedTxWidthSet; + if (eHT_CHANNEL_WIDTH_40MHZ == + psessionEntry->htRecommendedTxWidthSet) { + if (PHY_DOUBLE_CHANNEL_LOW_PRIMARY == + pHTInfo->secondaryChannelOffset) + center_freq = pHTInfo->primaryChannel + 2; + else if (PHY_DOUBLE_CHANNEL_HIGH_PRIMARY == + pHTInfo->secondaryChannelOffset) + center_freq = pHTInfo->primaryChannel - 2; + } + + /* notify HAL */ + lim_log(pMac, LOGW, FL("Channel Information in HT IE change" + "d; sending notification to HAL.")); + lim_log(pMac, LOGW, FL("Primary Channel: %d, Secondary Chan" + "nel Offset: %d, Channel Width: %d"), + pHTInfo->primaryChannel, center_freq, + psessionEntry->htRecommendedTxWidthSet); + psessionEntry->channelChangeReasonCode = + LIM_SWITCH_CHANNEL_OPERATION; + pMac->lim.gpchangeChannelCallback = NULL; + pMac->lim.gpchangeChannelData = NULL; + + lim_send_switch_chnl_params(pMac, (uint8_t) pHTInfo->primaryChannel, + center_freq, 0, + psessionEntry->htRecommendedTxWidthSet, + psessionEntry->maxTxPower, + psessionEntry->peSessionId, + true); + + /* In case of IBSS, if STA should update HT Info IE in its beacons. */ + if (LIM_IS_IBSS_ROLE(psessionEntry)) { + sch_set_fixed_beacon_fields(pMac, psessionEntry); + } + + } +} /* End limUpdateStaRunTimeHTParams. */ + +/** + * \brief This function updates the lim global structure, if any of the + * HT Capabilities have changed. + * + * + * \param pMac Pointer to Global MAC structure + * + * \param pHTCapability Pointer to HT Capability Information Element + * obtained from a Beacon or Probe Response + * + * + * + */ + +void lim_update_sta_run_time_ht_capability(tpAniSirGlobal pMac, + tDot11fIEHTCaps *pHTCaps) +{ + + if (pMac->lim.gHTLsigTXOPProtection != + (uint8_t) pHTCaps->lsigTXOPProtection) { + pMac->lim.gHTLsigTXOPProtection = + (uint8_t) pHTCaps->lsigTXOPProtection; + /* Send change notification to HAL */ + } + + if (pMac->lim.gHTAMpduDensity != (uint8_t) pHTCaps->mpduDensity) { + pMac->lim.gHTAMpduDensity = (uint8_t) pHTCaps->mpduDensity; + /* Send change notification to HAL */ + } + + if (pMac->lim.gHTMaxRxAMpduFactor != + (uint8_t) pHTCaps->maxRxAMPDUFactor) { + pMac->lim.gHTMaxRxAMpduFactor = + (uint8_t) pHTCaps->maxRxAMPDUFactor; + /* Send change notification to HAL */ + } + +} /* End lim_update_sta_run_time_ht_capability. */ + +/** + * \brief This function updates lim global structure, if any of the HT + * Info Parameters have changed. + * + * + * \param pMac Pointer to the global MAC structure + * + * \param pHTInfo Pointer to the HT Info IE obtained from a Beacon or + * Probe Response + * + * + */ + +void lim_update_sta_run_time_ht_info(tpAniSirGlobal pMac, + tDot11fIEHTInfo *pHTInfo, + tpPESession psessionEntry) +{ + if (psessionEntry->htRecommendedTxWidthSet != + (uint8_t) pHTInfo->recommendedTxWidthSet) { + psessionEntry->htRecommendedTxWidthSet = + (uint8_t) pHTInfo->recommendedTxWidthSet; + /* Send change notification to HAL */ + } + + if (psessionEntry->beaconParams.fRIFSMode != + (uint8_t) pHTInfo->rifsMode) { + psessionEntry->beaconParams.fRIFSMode = + (uint8_t) pHTInfo->rifsMode; + /* Send change notification to HAL */ + } + + if (pMac->lim.gHTServiceIntervalGranularity != + (uint8_t) pHTInfo->serviceIntervalGranularity) { + pMac->lim.gHTServiceIntervalGranularity = + (uint8_t) pHTInfo->serviceIntervalGranularity; + /* Send change notification to HAL */ + } + + if (pMac->lim.gHTOperMode != (tSirMacHTOperatingMode) pHTInfo->opMode) { + pMac->lim.gHTOperMode = + (tSirMacHTOperatingMode) pHTInfo->opMode; + /* Send change notification to HAL */ + } + + if (psessionEntry->beaconParams.llnNonGFCoexist != + pHTInfo->nonGFDevicesPresent) { + psessionEntry->beaconParams.llnNonGFCoexist = + (uint8_t) pHTInfo->nonGFDevicesPresent; + } + + if (pMac->lim.gHTSTBCBasicMCS != (uint8_t) pHTInfo->basicSTBCMCS) { + pMac->lim.gHTSTBCBasicMCS = (uint8_t) pHTInfo->basicSTBCMCS; + /* Send change notification to HAL */ + } + + if (pMac->lim.gHTDualCTSProtection != + (uint8_t) pHTInfo->dualCTSProtection) { + pMac->lim.gHTDualCTSProtection = + (uint8_t) pHTInfo->dualCTSProtection; + /* Send change notification to HAL */ + } + + if (pMac->lim.gHTSecondaryBeacon != (uint8_t) pHTInfo->secondaryBeacon) { + pMac->lim.gHTSecondaryBeacon = + (uint8_t) pHTInfo->secondaryBeacon; + /* Send change notification to HAL */ + } + + if (psessionEntry->beaconParams.fLsigTXOPProtectionFullSupport != + (uint8_t) pHTInfo->lsigTXOPProtectionFullSupport) { + psessionEntry->beaconParams.fLsigTXOPProtectionFullSupport = + (uint8_t) pHTInfo->lsigTXOPProtectionFullSupport; + /* Send change notification to HAL */ + } + + if (pMac->lim.gHTPCOActive != (uint8_t) pHTInfo->pcoActive) { + pMac->lim.gHTPCOActive = (uint8_t) pHTInfo->pcoActive; + /* Send change notification to HAL */ + } + + if (pMac->lim.gHTPCOPhase != (uint8_t) pHTInfo->pcoPhase) { + pMac->lim.gHTPCOPhase = (uint8_t) pHTInfo->pcoPhase; + /* Send change notification to HAL */ + } + +} /* End lim_update_sta_run_time_ht_info. */ + +/** ------------------------------------------------------------- + \fn lim_process_hal_ind_messages + \brief callback function for HAL indication + \param tpAniSirGlobal pMac + \param uint32_t mesgId + \param void *mesgParam + \return tSirRetStatu - status + -------------------------------------------------------------*/ + +tSirRetStatus lim_process_hal_ind_messages(tpAniSirGlobal pMac, uint32_t msgId, + void *msgParam) +{ + /* its PE's responsibility to free msgparam when its done extracting the message parameters. */ + tSirMsgQ msg; + + switch (msgId) { + case SIR_LIM_DEL_TS_IND: + case SIR_LIM_DELETE_STA_CONTEXT_IND: + case SIR_LIM_BEACON_GEN_IND: + msg.type = (uint16_t) msgId; + msg.bodyptr = msgParam; + msg.bodyval = 0; + break; + + default: + qdf_mem_free(msgParam); + lim_log(pMac, LOGP, FL("invalid message id = %d received"), + msgId); + return eSIR_FAILURE; + } + + if (lim_post_msg_api(pMac, &msg) != eSIR_SUCCESS) { + qdf_mem_free(msgParam); + lim_log(pMac, LOGP, FL("lim_post_msg_api failed for msgid = %d"), + msg.type); + return eSIR_FAILURE; + } + return eSIR_SUCCESS; +} + +/** + * lim_validate_delts_req() - This function validates DelTs req + * @mac_ctx: pointer to Global Mac structure + * @delts_req: pointer to delete traffic stream structure + * @peer_mac_addr: variable for peer mac address + * + * Function validates DelTs req originated by SME or by HAL and also + * sends halMsg_DelTs to HAL + * + * Return: eSIR_SUCCESS - Success, eSIR_FAILURE - Failure + */ + +tSirRetStatus +lim_validate_delts_req(tpAniSirGlobal mac_ctx, tpSirDeltsReq delts_req, + tSirMacAddr peer_mac_addr, tpPESession psession_entry) +{ + tpDphHashNode sta; + uint8_t ts_status; + tSirMacTSInfo *tsinfo; + uint32_t i; + uint8_t tspec_idx; + + /* + * if sta + * - verify assoc state + * - del tspec locally + * if ap + * - verify sta is in assoc state + * - del sta tspec locally + */ + if (delts_req == NULL) { + lim_log(mac_ctx, LOGE, + FL("Delete TS request pointer is NULL")); + return eSIR_FAILURE; + } + + if (LIM_IS_STA_ROLE(psession_entry)) { + uint32_t val; + + /* station always talks to the AP */ + sta = dph_get_hash_entry(mac_ctx, DPH_STA_HASH_INDEX_PEER, + &psession_entry->dph.dphHashTable); + + val = sizeof(tSirMacAddr); + sir_copy_mac_addr(peer_mac_addr, psession_entry->bssId); + + } else { + uint16_t associd; + uint8_t *macaddr = (uint8_t *) peer_mac_addr; + + associd = delts_req->aid; + if (associd != 0) + sta = dph_get_hash_entry(mac_ctx, associd, + &psession_entry->dph.dphHashTable); + else + sta = dph_lookup_hash_entry(mac_ctx, + delts_req->macaddr.bytes, + &associd, + &psession_entry->dph. + dphHashTable); + + if (sta != NULL) + /* TBD: check sta assoc state as well */ + for (i = 0; i < sizeof(tSirMacAddr); i++) + macaddr[i] = sta->staAddr[i]; + } + + if (sta == NULL) { + lim_log(mac_ctx, LOGE, + FL("Cannot find station context for delts req")); + return eSIR_FAILURE; + } + + if ((!sta->valid) || + (sta->mlmStaContext.mlmState != + eLIM_MLM_LINK_ESTABLISHED_STATE)) { + lim_log(mac_ctx, LOGE, + FL("Invalid Sta (or state) for DelTsReq")); + return eSIR_FAILURE; + } + + delts_req->req.wsmTspecPresent = 0; + delts_req->req.wmeTspecPresent = 0; + delts_req->req.lleTspecPresent = 0; + + if ((sta->wsmEnabled) && + (delts_req->req.tspec.tsinfo.traffic.accessPolicy != + SIR_MAC_ACCESSPOLICY_EDCA)) + delts_req->req.wsmTspecPresent = 1; + else if (sta->wmeEnabled) + delts_req->req.wmeTspecPresent = 1; + else if (sta->lleEnabled) + delts_req->req.lleTspecPresent = 1; + else { + lim_log(mac_ctx, LOGW, + FL("DELTS_REQ ignore - qos is disabled")); + return eSIR_FAILURE; + } + + tsinfo = delts_req->req.wmeTspecPresent ? &delts_req->req.tspec.tsinfo + : &delts_req->req.tsinfo; + lim_log(mac_ctx, LOG1, + FL("received DELTS_REQ message (wmeTspecPresent = %d, lleTspecPresent = %d, wsmTspecPresent = %d, tsid %d, up %d, direction = %d)"), + delts_req->req.wmeTspecPresent, + delts_req->req.lleTspecPresent, + delts_req->req.wsmTspecPresent, tsinfo->traffic.tsid, + tsinfo->traffic.userPrio, tsinfo->traffic.direction); + + /* if no Access Control, ignore the request */ + if (lim_admit_control_delete_ts(mac_ctx, sta->assocId, tsinfo, + &ts_status, &tspec_idx) != eSIR_SUCCESS) { + lim_log(mac_ctx, LOGE, + FL("ERROR DELTS request for sta assocId %d (tsid %d, up %d)"), + sta->assocId, tsinfo->traffic.tsid, + tsinfo->traffic.userPrio); + return eSIR_FAILURE; + } else if ((tsinfo->traffic.accessPolicy == SIR_MAC_ACCESSPOLICY_HCCA) + || (tsinfo->traffic.accessPolicy == + SIR_MAC_ACCESSPOLICY_BOTH)) { + /* edca only now. */ + } else if (tsinfo->traffic.accessPolicy == SIR_MAC_ACCESSPOLICY_EDCA) { + /* send message to HAL to delete TS */ + if (eSIR_SUCCESS != + lim_send_hal_msg_del_ts(mac_ctx, sta->staIndex, + tspec_idx, delts_req->req, + psession_entry->peSessionId, + psession_entry->bssId)) { + lim_log(mac_ctx, LOGW, + FL("DelTs with UP %d failed in lim_send_hal_msg_del_ts - ignoring request"), + tsinfo->traffic.userPrio); + return eSIR_FAILURE; + } + } + return eSIR_SUCCESS; +} + +/** ------------------------------------------------------------- + \fn lim_register_hal_ind_call_back + \brief registers callback function to HAL for any indication. + \param tpAniSirGlobal pMac + \return none. + -------------------------------------------------------------*/ +void lim_register_hal_ind_call_back(tpAniSirGlobal pMac) +{ + tSirMsgQ msg; + tpHalIndCB pHalCB; + + pHalCB = qdf_mem_malloc(sizeof(tHalIndCB)); + if (NULL == pHalCB) { + lim_log(pMac, LOGP, FL("AllocateMemory() failed")); + return; + } + + pHalCB->pHalIndCB = lim_process_hal_ind_messages; + + msg.type = WMA_REGISTER_PE_CALLBACK; + msg.bodyptr = pHalCB; + msg.bodyval = 0; + + MTRACE(mac_trace_msg_tx(pMac, NO_SESSION, msg.type)); + if (eSIR_SUCCESS != wma_post_ctrl_msg(pMac, &msg)) { + qdf_mem_free(pHalCB); + lim_log(pMac, LOGP, FL("wma_post_ctrl_msg() failed")); + } + + return; +} + +/** + * lim_process_del_ts_ind() - handle del_ts_ind from HAL + * + * @mac_ctx: pointer to Global Mac Structure + * @lim_msg: pointer to msg buff + * + * handles the DeleteTS indication coming from HAL or generated by PE itself + * in some error cases. Validates the request, sends the DelTs action frame + * to the Peer and sends DelTs indicatoin to HDD. + * + * Return: none + */ +void lim_process_del_ts_ind(tpAniSirGlobal pMac, tpSirMsgQ limMsg) +{ + tpDphHashNode pSta; + tpDelTsParams pDelTsParam = (tpDelTsParams) (limMsg->bodyptr); + tpSirDeltsReq pDelTsReq = NULL; + tSirMacAddr peerMacAddr; + tpSirDeltsReqInfo pDelTsReqInfo; + tpLimTspecInfo pTspecInfo; + tpPESession psessionEntry; + uint8_t sessionId; + + psessionEntry = pe_find_session_by_bssid(pMac, pDelTsParam->bssId, + &sessionId); + if (psessionEntry == NULL) { + lim_log(pMac, LOGE, + FL("session does not exist for given BssId")); + qdf_mem_free(limMsg->bodyptr); + limMsg->bodyptr = NULL; + return; + } + + pTspecInfo = &(pMac->lim.tspecInfo[pDelTsParam->tspecIdx]); + if (pTspecInfo->inuse == false) { + PELOGE(lim_log + (pMac, LOGE, + FL("tspec entry with index %d is not in use"), + pDelTsParam->tspecIdx); + ) + goto error1; + } + + pSta = + dph_get_hash_entry(pMac, pTspecInfo->assocId, + &psessionEntry->dph.dphHashTable); + if (pSta == NULL) { + lim_log(pMac, LOGE, + FL("Could not find entry in DPH table for assocId = %d"), + pTspecInfo->assocId); + goto error1; + } + + pDelTsReq = qdf_mem_malloc(sizeof(tSirDeltsReq)); + if (NULL == pDelTsReq) { + PELOGE(lim_log(pMac, LOGE, FL("AllocateMemory() failed"));) + goto error1; + } + + if (pSta->wmeEnabled) + qdf_mem_copy(&(pDelTsReq->req.tspec), &(pTspecInfo->tspec), + sizeof(tSirMacTspecIE)); + else + qdf_mem_copy(&(pDelTsReq->req.tsinfo), + &(pTspecInfo->tspec.tsinfo), + sizeof(tSirMacTSInfo)); + + /* validate the req */ + if (eSIR_SUCCESS != + lim_validate_delts_req(pMac, pDelTsReq, peerMacAddr, psessionEntry)) { + PELOGE(lim_log(pMac, LOGE, FL("lim_validate_delts_req failed"));) + goto error2; + } + PELOG1(lim_log(pMac, LOG1, "Sent DELTS request to station with " + "assocId = %d MacAddr = " MAC_ADDRESS_STR, + pDelTsReq->aid, MAC_ADDR_ARRAY(peerMacAddr)); + ) + + lim_send_delts_req_action_frame(pMac, peerMacAddr, + pDelTsReq->req.wmeTspecPresent, + &pDelTsReq->req.tsinfo, + &pDelTsReq->req.tspec, psessionEntry); + + /* prepare and send an sme indication to HDD */ + pDelTsReqInfo = qdf_mem_malloc(sizeof(tSirDeltsReqInfo)); + if (NULL == pDelTsReqInfo) { + PELOGE(lim_log(pMac, LOGE, FL("AllocateMemory() failed"));) + goto error3; + } + + if (pSta->wmeEnabled) + qdf_mem_copy(&(pDelTsReqInfo->tspec), &(pTspecInfo->tspec), + sizeof(tSirMacTspecIE)); + else + qdf_mem_copy(&(pDelTsReqInfo->tsinfo), + &(pTspecInfo->tspec.tsinfo), + sizeof(tSirMacTSInfo)); + + lim_send_sme_delts_ind(pMac, pDelTsReqInfo, pDelTsReq->aid, psessionEntry); + +error3: + qdf_mem_free(pDelTsReqInfo); +error2: + qdf_mem_free(pDelTsReq); +error1: + qdf_mem_free(limMsg->bodyptr); + limMsg->bodyptr = NULL; + return; +} + +/** + * @function : lim_post_sm_state_update() + * + * @brief : This function Updates the HAL and Softmac about the change in the STA's SMPS state. + * + * LOGIC: + * + * ASSUMPTIONS: + * NA + * + * NOTE: + * NA + * + * @param pMac - Pointer to Global MAC structure + * @param limMsg - Lim Message structure object with the MimoPSparam in body + * @return None + */ +tSirRetStatus +lim_post_sm_state_update(tpAniSirGlobal pMac, + uint16_t staIdx, tSirMacHTMIMOPowerSaveState state, + uint8_t *pPeerStaMac, uint8_t sessionId) +{ + tSirRetStatus retCode = eSIR_SUCCESS; + tSirMsgQ msgQ; + tpSetMIMOPS pMIMO_PSParams; + + msgQ.reserved = 0; + msgQ.type = WMA_SET_MIMOPS_REQ; + + /* Allocate for WMA_SET_MIMOPS_REQ */ + pMIMO_PSParams = qdf_mem_malloc(sizeof(tSetMIMOPS)); + if (NULL == pMIMO_PSParams) { + lim_log(pMac, LOGP, FL(" AllocateMemory failed")); + return eSIR_MEM_ALLOC_FAILED; + } + + pMIMO_PSParams->htMIMOPSState = state; + pMIMO_PSParams->staIdx = staIdx; + pMIMO_PSParams->fsendRsp = true; + pMIMO_PSParams->sessionId = sessionId; + qdf_mem_copy(pMIMO_PSParams->peerMac, pPeerStaMac, sizeof(tSirMacAddr)); + + msgQ.bodyptr = pMIMO_PSParams; + msgQ.bodyval = 0; + + lim_log(pMac, LOG2, FL("Sending WMA_SET_MIMOPS_REQ...")); + + MTRACE(mac_trace_msg_tx(pMac, NO_SESSION, msgQ.type)); + retCode = wma_post_ctrl_msg(pMac, &msgQ); + if (eSIR_SUCCESS != retCode) { + lim_log(pMac, LOGP, + FL + ("Posting WMA_SET_MIMOPS_REQ to HAL failed! Reason = %d"), + retCode); + qdf_mem_free(pMIMO_PSParams); + return retCode; + } + + return retCode; +} + +void lim_pkt_free(tpAniSirGlobal pMac, + eFrameType frmType, uint8_t *pRxPacketInfo, void *pBody) +{ + (void)pMac; + (void)frmType; + (void)pRxPacketInfo; + (void)pBody; +} + +/** + * lim_get_b_dfrom_rx_packet() + * + ***FUNCTION: + * This function is called to get pointer to Polaris + * Buffer Descriptor containing MAC header & other control + * info from the body of the message posted to LIM. + * + ***LOGIC: + * NA + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param body - Received message body + * @param pRxPacketInfo - Pointer to received BD + * @return None + */ + +void +lim_get_b_dfrom_rx_packet(tpAniSirGlobal pMac, void *body, uint32_t **pRxPacketInfo) +{ + *pRxPacketInfo = (uint32_t *) body; +} /*** end lim_get_b_dfrom_rx_packet() ***/ + +void lim_resset_scan_channel_info(tpAniSirGlobal pMac) +{ + qdf_mem_set(&pMac->lim.scanChnInfo, sizeof(tLimScanChnInfo), 0); +} + +/** + * @function : lim_is_channel_valid_for_channel_switch() + * + * @brief : This function checks if the channel to which AP + * is expecting us to switch, is a valid channel for us. + * LOGIC: + * + * ASSUMPTIONS: + * NA + * + * NOTE: + * NA + * + * @param pMac - Pointer to Global MAC structure + * @param channel - New channel to which we are expected to move + * @return None + */ +tAniBool lim_is_channel_valid_for_channel_switch(tpAniSirGlobal pMac, uint8_t channel) +{ + uint8_t index; + uint32_t validChannelListLen = WNI_CFG_VALID_CHANNEL_LIST_LEN; + tSirMacChanNum validChannelList[WNI_CFG_VALID_CHANNEL_LIST_LEN]; + + if (wlan_cfg_get_str(pMac, WNI_CFG_VALID_CHANNEL_LIST, + (uint8_t *) validChannelList, + (uint32_t *) &validChannelListLen) != + eSIR_SUCCESS) { + PELOGE(lim_log + (pMac, LOGE, + FL("could not retrieve valid channel list")); + ) + return eSIR_FALSE; + } + + for (index = 0; index < validChannelListLen; index++) { + if (validChannelList[index] == channel) + return eSIR_TRUE; + } + + /* channel does not belong to list of valid channels */ + return eSIR_FALSE; +} + +/**------------------------------------------------------ + \fn __lim_fill_tx_control_params + \brief Fill the message for stopping/resuming tx. + + \param pMac + \param pTxCtrlMsg - Pointer to tx control message. + \param type - Which way we want to stop/ resume tx. + \param mode - To stop/resume. + -------------------------------------------------------*/ +static QDF_STATUS +__lim_fill_tx_control_params(tpAniSirGlobal pMac, tpTxControlParams pTxCtrlMsg, + tLimQuietTxMode type, tLimControlTx mode) +{ + + tpPESession psessionEntry = &pMac->lim.gpSession[0]; + + if (mode == eLIM_STOP_TX) + pTxCtrlMsg->stopTx = true; + else + pTxCtrlMsg->stopTx = false; + + switch (type) { + case eLIM_TX_ALL: + /** Stops/resumes transmission completely */ + pTxCtrlMsg->fCtrlGlobal = 1; + break; + + case eLIM_TX_BSS_BUT_BEACON: + /** Stops/resumes transmission on a particular BSS. Stopping BSS, doesnt + * stop beacon transmission. + */ + pTxCtrlMsg->ctrlBss = 1; + pTxCtrlMsg->bssBitmap |= (1 << psessionEntry->bssIdx); + break; + + case eLIM_TX_STA: + /** Memory for station bitmap is allocated dynamically in caller of this + * so decode properly here and fill the bitmap. Now not implemented, + * fall through. + */ + case eLIM_TX_BSS: + /* Fall thru... */ + default: + PELOGW(lim_log(pMac, LOGW, FL("Invalid case: Not Handled"));) + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * @function : lim_frame_transmission_control() + * + * @brief : This API is called by the user to halt/resume any frame + * transmission from the device. If stopped, all frames will be + * queued starting from hardware. Then back-pressure + * is built till the driver. + * LOGIC: + * + * ASSUMPTIONS: + * NA + * + * NOTE: + * NA + * + * @param pMac - Pointer to Global MAC structure + * @return None + */ +void lim_frame_transmission_control(tpAniSirGlobal pMac, tLimQuietTxMode type, + tLimControlTx mode) +{ + + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpTxControlParams pTxCtrlMsg; + tSirMsgQ msgQ; + uint8_t nBytes = 0; /* No of bytes required for station bitmap. */ + + /** Allocate only required number of bytes for station bitmap + * Make it to align to 4 byte boundary */ + nBytes = (uint8_t) HALMSG_NUMBYTES_STATION_BITMAP(pMac->lim.maxStation); + + pTxCtrlMsg = qdf_mem_malloc(sizeof(*pTxCtrlMsg) + nBytes); + if (NULL == pTxCtrlMsg) { + lim_log(pMac, LOGP, FL("AllocateMemory() failed")); + return; + } + + status = __lim_fill_tx_control_params(pMac, pTxCtrlMsg, type, mode); + if (status != QDF_STATUS_SUCCESS) { + qdf_mem_free(pTxCtrlMsg); + lim_log(pMac, LOGP, + FL("__lim_fill_tx_control_params failed, status = %d"), + status); + return; + } + + msgQ.bodyptr = (void *)pTxCtrlMsg; + msgQ.bodyval = 0; + msgQ.reserved = 0; + msgQ.type = WMA_TRANSMISSION_CONTROL_IND; + + MTRACE(mac_trace_msg_tx(pMac, NO_SESSION, msgQ.type)); + if (wma_post_ctrl_msg(pMac, &msgQ) != eSIR_SUCCESS) { + qdf_mem_free(pTxCtrlMsg); + lim_log(pMac, LOGP, FL("Posting Message to HAL failed")); + return; + } + + if (mode == eLIM_STOP_TX) { + PELOG1(lim_log + (pMac, LOG1, + FL + ("Stopping the transmission of all packets, indicated softmac")); + ) + } else { + PELOG1(lim_log + (pMac, LOG1, + FL + ("Resuming the transmission of all packets, indicated softmac")); + ) + } + return; +} + +/** + * @function : lim_restore_pre_channel_switch_state() + * + * @brief : This API is called by the user to undo any + * specific changes done on the device during + * channel switch. + * LOGIC: + * + * ASSUMPTIONS: + * NA + * + * NOTE: + * NA + * + * @param pMac - Pointer to Global MAC structure + * @return None + */ + +tSirRetStatus +lim_restore_pre_channel_switch_state(tpAniSirGlobal pMac, tpPESession psessionEntry) +{ + + tSirRetStatus retCode = eSIR_SUCCESS; + + if (!LIM_IS_STA_ROLE(psessionEntry)) + return retCode; + + /* Channel switch should be ready for the next time */ + psessionEntry->gLimSpecMgmt.dot11hChanSwState = eLIM_11H_CHANSW_INIT; + + /* Restore the frame transmission, all the time. */ + lim_frame_transmission_control(pMac, eLIM_TX_ALL, eLIM_RESUME_TX); + + return retCode; +} + +/**-------------------------------------------- + \fn lim_restore_pre_quiet_state + \brief Restore the pre quiet state + + \param pMac + \return NONE + ---------------------------------------------*/ +tSirRetStatus lim_restore_pre_quiet_state(tpAniSirGlobal pMac, + tpPESession psessionEntry) +{ + + tSirRetStatus retCode = eSIR_SUCCESS; + + if (pMac->lim.gLimSystemRole != eLIM_STA_ROLE) + return retCode; + + /* Quiet should be ready for the next time */ + psessionEntry->gLimSpecMgmt.quietState = eLIM_QUIET_INIT; + + /* Restore the frame transmission, all the time. */ + if (psessionEntry->gLimSpecMgmt.quietState == eLIM_QUIET_RUNNING) + lim_frame_transmission_control(pMac, eLIM_TX_ALL, eLIM_RESUME_TX); + + return retCode; +} + +/** + * @function: lim_prepare_for11h_channel_switch() + * + * @brief : This API is called by the user to prepare for + * 11h channel switch. As of now, the API does + * very minimal work. User can add more into the + * same API if needed. + * LOGIC: + * + * ASSUMPTIONS: + * NA + * + * NOTE: + * NA + * + * @param pMac - Pointer to Global MAC structure + * @param psessionEntry + * @return None + */ +void +lim_prepare_for11h_channel_switch(tpAniSirGlobal pMac, tpPESession psessionEntry) +{ + if (!LIM_IS_STA_ROLE(psessionEntry)) + return; + + /* Flag to indicate 11h channel switch in progress */ + psessionEntry->gLimSpecMgmt.dot11hChanSwState = eLIM_11H_CHANSW_RUNNING; + + if (pMac->lim.gLimSmeState == eLIM_SME_LINK_EST_WT_SCAN_STATE || + pMac->lim.gLimSmeState == eLIM_SME_CHANNEL_SCAN_STATE) { + PELOGE(lim_log + (pMac, LOG1, + FL("Posting finish scan as we are in scan state")); + ) + /* Stop ongoing scanning if any */ + if (GET_LIM_PROCESS_DEFD_MESGS(pMac)) { + /* Set the resume channel to Any valid channel (invalid). */ + /* This will instruct HAL to set it to any previous valid channel. */ + pe_set_resume_channel(pMac, 0, 0); + } else { + lim_restore_pre_channel_switch_state(pMac, psessionEntry); + } + return; + } else { + PELOGE(lim_log + (pMac, LOG1, + FL("Not in scan state, start channel switch timer")); + ) + /** We are safe to switch channel at this point */ + lim_stop_tx_and_switch_channel(pMac, psessionEntry->peSessionId); + } +} + +/**---------------------------------------------------- + \fn lim_get_nw_type + + \brief Get type of the network from data packet or beacon + \param pMac + \param channelNum - Channel number + \param type - Type of packet. + \param pBeacon - Pointer to beacon or probe response + + \return Network type a/b/g. + -----------------------------------------------------*/ +tSirNwType lim_get_nw_type(tpAniSirGlobal pMac, uint8_t channelNum, uint32_t type, + tpSchBeaconStruct pBeacon) +{ + tSirNwType nwType = eSIR_11B_NW_TYPE; + + if (type == SIR_MAC_DATA_FRAME) { + if ((channelNum > 0) && (channelNum < 15)) { + nwType = eSIR_11G_NW_TYPE; + } else { + nwType = eSIR_11A_NW_TYPE; + } + } else { + if ((channelNum > 0) && (channelNum < 15)) { + int i; + /* 11b or 11g packet */ + /* 11g iff extended Rate IE is present or */ + /* if there is an A rate in suppRate IE */ + for (i = 0; i < pBeacon->supportedRates.numRates; i++) { + if (sirIsArate + (pBeacon->supportedRates.rate[i] & 0x7f)) { + nwType = eSIR_11G_NW_TYPE; + break; + } + } + if (pBeacon->extendedRatesPresent) { + PELOG3(lim_log + (pMac, LOG3, FL("Beacon, nwtype=G")); + ) + nwType = eSIR_11G_NW_TYPE; + } else if (pBeacon->HTInfo.present || + IS_BSS_VHT_CAPABLE(pBeacon->VHTCaps)) { + nwType = eSIR_11G_NW_TYPE; + } + } else { + /* 11a packet */ + PELOG3(lim_log(pMac, LOG3, FL("Beacon, nwtype=A"));) + nwType = eSIR_11A_NW_TYPE; + } + } + return nwType; +} + +/**--------------------------------------------------------- + \fn lim_get_channel_from_beacon + \brief To extract channel number from beacon + + \param pMac + \param pBeacon - Pointer to beacon or probe rsp + \return channel number + -----------------------------------------------------------*/ +uint8_t lim_get_channel_from_beacon(tpAniSirGlobal pMac, tpSchBeaconStruct pBeacon) +{ + uint8_t channelNum = 0; + + if (pBeacon->dsParamsPresent) + channelNum = pBeacon->channelNumber; + else if (pBeacon->HTInfo.present) + channelNum = pBeacon->HTInfo.primaryChannel; + else + channelNum = pBeacon->channelNumber; + + return channelNum; +} + +void lim_set_tspec_uapsd_mask_per_session(tpAniSirGlobal pMac, + tpPESession psessionEntry, + tSirMacTSInfo *pTsInfo, uint32_t action) +{ + uint8_t userPrio = (uint8_t) pTsInfo->traffic.userPrio; + uint16_t direction = pTsInfo->traffic.direction; + uint8_t ac = upToAc(userPrio); + + PELOG1(lim_log + (pMac, LOG1, FL("Set UAPSD mask for AC %d, dir %d, action=%d") + , ac, direction, action); + ) + + /* Converting AC to appropriate Uapsd Bit Mask + * AC_BE(0) --> UAPSD_BITOFFSET_ACVO(3) + * AC_BK(1) --> UAPSD_BITOFFSET_ACVO(2) + * AC_VI(2) --> UAPSD_BITOFFSET_ACVO(1) + * AC_VO(3) --> UAPSD_BITOFFSET_ACVO(0) + */ + ac = ((~ac) & 0x3); + + if (action == CLEAR_UAPSD_MASK) { + if (direction == SIR_MAC_DIRECTION_UPLINK) + psessionEntry->gUapsdPerAcTriggerEnableMask &= + ~(1 << ac); + else if (direction == SIR_MAC_DIRECTION_DNLINK) + psessionEntry->gUapsdPerAcDeliveryEnableMask &= + ~(1 << ac); + else if (direction == SIR_MAC_DIRECTION_BIDIR) { + psessionEntry->gUapsdPerAcTriggerEnableMask &= + ~(1 << ac); + psessionEntry->gUapsdPerAcDeliveryEnableMask &= + ~(1 << ac); + } + } else if (action == SET_UAPSD_MASK) { + if (direction == SIR_MAC_DIRECTION_UPLINK) + psessionEntry->gUapsdPerAcTriggerEnableMask |= + (1 << ac); + else if (direction == SIR_MAC_DIRECTION_DNLINK) + psessionEntry->gUapsdPerAcDeliveryEnableMask |= + (1 << ac); + else if (direction == SIR_MAC_DIRECTION_BIDIR) { + psessionEntry->gUapsdPerAcTriggerEnableMask |= + (1 << ac); + psessionEntry->gUapsdPerAcDeliveryEnableMask |= + (1 << ac); + } + } + + lim_log(pMac, LOG1, + FL("New psessionEntry->gUapsdPerAcTriggerEnableMask = 0x%x "), + psessionEntry->gUapsdPerAcTriggerEnableMask); + lim_log(pMac, LOG1, + FL("New psessionEntry->gUapsdPerAcDeliveryEnableMask = 0x%x "), + psessionEntry->gUapsdPerAcDeliveryEnableMask); + + return; +} + +/** + * lim_handle_heart_beat_timeout_for_session() - Handle heart beat time out + * @mac_ctx: pointer to Global Mac Structure + * @psession_entry: pointer to tpPESession + * + * Function handles heart beat time out for session + * + * Return: none + */ +void lim_handle_heart_beat_timeout_for_session(tpAniSirGlobal mac_ctx, + tpPESession psession_entry) +{ + if (psession_entry->valid == true) { + if (psession_entry->bssType == eSIR_IBSS_MODE) + lim_ibss_heart_beat_handle(mac_ctx, psession_entry); + + if ((psession_entry->bssType == eSIR_INFRASTRUCTURE_MODE) && + (LIM_IS_STA_ROLE(psession_entry))) + lim_handle_heart_beat_failure(mac_ctx, psession_entry); + } + /* + * In the function lim_handle_heart_beat_failure things can change + * so check for the session entry valid and the other things + * again + */ + if ((psession_entry->valid == true) && + (psession_entry->bssType == eSIR_INFRASTRUCTURE_MODE) && + (LIM_IS_STA_ROLE(psession_entry)) && + (psession_entry->LimHBFailureStatus == true)) { + tLimTimers *lim_timer = &mac_ctx->lim.limTimers; + /* + * Activate Probe After HeartBeat Timer incase HB + * Failure detected + */ + PELOGW(lim_log(mac_ctx, LOGW, + FL("Sending Probe for Session: %d"), + psession_entry->bssIdx);) + lim_deactivate_and_change_timer(mac_ctx, + eLIM_PROBE_AFTER_HB_TIMER); + MTRACE(mac_trace(mac_ctx, TRACE_CODE_TIMER_ACTIVATE, 0, + eLIM_PROBE_AFTER_HB_TIMER)); + if (tx_timer_activate(&lim_timer->gLimProbeAfterHBTimer) + != TX_SUCCESS) + lim_log(mac_ctx, LOGP, + FL("Fail to re-activate Probe-after-hb timer")); + } +} + +uint8_t lim_get_current_operating_channel(tpAniSirGlobal pMac) +{ + uint8_t i; + for (i = 0; i < pMac->lim.maxBssId; i++) { + if (pMac->lim.gpSession[i].valid == true) { + if ((pMac->lim.gpSession[i].bssType == + eSIR_INFRASTRUCTURE_MODE) + && (pMac->lim.gpSession[i].limSystemRole == + eLIM_STA_ROLE)) { + return pMac->lim.gpSession[i]. + currentOperChannel; + } + } + } + return 0; +} + +/** + * lim_process_add_sta_rsp() - process WDA_ADD_STA_RSP from WMA + * @mac_ctx: Pointer to Global MAC structure + * @msg: msg from WMA + * + * @Return: void + */ +void lim_process_add_sta_rsp(tpAniSirGlobal mac_ctx, tpSirMsgQ msg) +{ + tpPESession session; + tpAddStaParams add_sta_params; + + add_sta_params = (tpAddStaParams) msg->bodyptr; + + session = pe_find_session_by_session_id(mac_ctx, + add_sta_params->sessionId); + if (session == NULL) { + lim_log(mac_ctx, LOGP, + FL("Session Does not exist for given sessionID")); + qdf_mem_free(add_sta_params); + return; + } + session->csaOffloadEnable = add_sta_params->csaOffloadEnable; + if (LIM_IS_IBSS_ROLE(session)) + (void)lim_ibss_add_sta_rsp(mac_ctx, msg->bodyptr, session); + else if (LIM_IS_NDI_ROLE(session)) + lim_ndp_add_sta_rsp(mac_ctx, session, msg->bodyptr); +#ifdef FEATURE_WLAN_TDLS + else if (mac_ctx->lim.gLimAddStaTdls) { + lim_process_tdls_add_sta_rsp(mac_ctx, msg->bodyptr, session); + mac_ctx->lim.gLimAddStaTdls = false; + } +#endif + else + lim_process_mlm_add_sta_rsp(mac_ctx, msg, session); + +} + +/** + * lim_update_beacon() - This function updates beacon + * @mac_ctx: pointer to Global Mac Structure + * + * This Function is invoked to update the beacon + * + * Return: none + */ +void lim_update_beacon(tpAniSirGlobal mac_ctx) +{ + uint8_t i; + + for (i = 0; i < mac_ctx->lim.maxBssId; i++) { + if (mac_ctx->lim.gpSession[i].valid != true) + continue; + if (((mac_ctx->lim.gpSession[i].limSystemRole == eLIM_AP_ROLE) + || (mac_ctx->lim.gpSession[i].limSystemRole == + eLIM_STA_IN_IBSS_ROLE)) + && (eLIM_SME_NORMAL_STATE == + mac_ctx->lim.gpSession[i].limSmeState)) { + + sch_set_fixed_beacon_fields(mac_ctx, + &mac_ctx->lim.gpSession[i]); + + if (false == mac_ctx->sap.SapDfsInfo. + is_dfs_cac_timer_running) + lim_send_beacon_ind(mac_ctx, + &mac_ctx->lim.gpSession[i]); + } + } +} + +/** + * lim_handle_heart_beat_failure_timeout - handle heart beat failure + * @mac_ctx: pointer to Global Mac Structure + * + * Function handle heart beat failure timeout + * + * Return: none + */ +void lim_handle_heart_beat_failure_timeout(tpAniSirGlobal mac_ctx) +{ + uint8_t i; + tpPESession psession_entry; + /* + * Probe response is not received after HB failure. + * This is handled by LMM sub module. + */ + for (i = 0; i < mac_ctx->lim.maxBssId; i++) { + if (mac_ctx->lim.gpSession[i].valid != true) + continue; + psession_entry = &mac_ctx->lim.gpSession[i]; + if (psession_entry->LimHBFailureStatus != true) + continue; + lim_log(mac_ctx, LOGE, FL("SME %d, MLME %d, HB-Count %d"), + psession_entry->limSmeState, + psession_entry->limMlmState, + psession_entry->LimRxedBeaconCntDuringHB); + +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM + lim_diag_event_report(mac_ctx, WLAN_PE_DIAG_HB_FAILURE_TIMEOUT, + psession_entry, 0, 0); +#endif + if ((psession_entry->limMlmState == + eLIM_MLM_LINK_ESTABLISHED_STATE) && + (psession_entry->limSmeState != + eLIM_SME_WT_DISASSOC_STATE) && + (psession_entry->limSmeState != + eLIM_SME_WT_DEAUTH_STATE) && + ((!LIM_IS_CONNECTION_ACTIVE(psession_entry)) || + /* + * Disconnect even if we have not received a single + * beacon after connection. + */ + (psession_entry->currentBssBeaconCnt == 0))) { + lim_log(mac_ctx, LOGE, FL("for session:%d "), + psession_entry->peSessionId); + + lim_send_deauth_mgmt_frame(mac_ctx, + eSIR_MAC_DISASSOC_DUE_TO_INACTIVITY_REASON, + psession_entry->bssId, psession_entry, false); + + /* + * AP did not respond to Probe Request. + * Tear down link with it. + */ + lim_tear_down_link_with_ap(mac_ctx, + psession_entry->peSessionId, + eSIR_BEACON_MISSED); + mac_ctx->lim.gLimProbeFailureAfterHBfailedCnt++; + } else { + lim_log(mac_ctx, LOGE, + FL("Unexpected wt-probe-timeout in state ")); + lim_print_mlm_state(mac_ctx, LOGE, + psession_entry->limMlmState); + } + } + /* + * Deactivate Timer ProbeAfterHB Timer -> As its a oneshot timer, + * need not deactivate the timer + * tx_timer_deactivate(&pMac->lim.limTimers.gLimProbeAfterHBTimer); + */ +} + +/* + * This function assumes there will not be more than one IBSS session active at any time. + */ +tpPESession lim_is_ibss_session_active(tpAniSirGlobal pMac) +{ + uint8_t i; + + for (i = 0; i < pMac->lim.maxBssId; i++) { + if ((pMac->lim.gpSession[i].valid) && + (pMac->lim.gpSession[i].limSystemRole == + eLIM_STA_IN_IBSS_ROLE)) + return &pMac->lim.gpSession[i]; + } + + return NULL; +} + +tpPESession lim_is_ap_session_active(tpAniSirGlobal pMac) +{ + uint8_t i; + + for (i = 0; i < pMac->lim.maxBssId; i++) { + if (pMac->lim.gpSession[i].valid && + (pMac->lim.gpSession[i].limSystemRole == eLIM_AP_ROLE)) + return &pMac->lim.gpSession[i]; + } + + return NULL; +} + +/**--------------------------------------------------------- + \fn lim_handle_defer_msg_error + \brief handles error scenario, when the msg can not be deferred. + \param pMac + \param pLimMsg LIM msg, which could not be deferred. + \return void + -----------------------------------------------------------*/ + +void lim_handle_defer_msg_error(tpAniSirGlobal pMac, tpSirMsgQ pLimMsg) +{ + if (SIR_BB_XPORT_MGMT_MSG == pLimMsg->type) { + lim_decrement_pending_mgmt_count(pMac); + cds_pkt_return_packet((cds_pkt_t *) pLimMsg->bodyptr); + pLimMsg->bodyptr = NULL; + } else if (pLimMsg->bodyptr != NULL) { + qdf_mem_free(pLimMsg->bodyptr); + pLimMsg->bodyptr = NULL; + } + +} + +#ifdef FEATURE_WLAN_DIAG_SUPPORT +/**--------------------------------------------------------- + \fn lim_diag_event_report + \brief This function reports Diag event + \param pMac + \param eventType + \param bssid + \param status + \param reasonCode + \return void + -----------------------------------------------------------*/ +void lim_diag_event_report(tpAniSirGlobal pMac, uint16_t eventType, + tpPESession pSessionEntry, uint16_t status, + uint16_t reasonCode) +{ + tSirMacAddr nullBssid = { 0, 0, 0, 0, 0, 0 }; + WLAN_HOST_DIAG_EVENT_DEF(peEvent, host_event_wlan_pe_payload_type); + + qdf_mem_set(&peEvent, sizeof(host_event_wlan_pe_payload_type), 0); + + if (NULL == pSessionEntry) { + qdf_mem_copy(peEvent.bssid, nullBssid, sizeof(tSirMacAddr)); + peEvent.sme_state = (uint16_t) pMac->lim.gLimSmeState; + peEvent.mlm_state = (uint16_t) pMac->lim.gLimMlmState; + + } else { + qdf_mem_copy(peEvent.bssid, pSessionEntry->bssId, + sizeof(tSirMacAddr)); + peEvent.sme_state = (uint16_t) pSessionEntry->limSmeState; + peEvent.mlm_state = (uint16_t) pSessionEntry->limMlmState; + } + peEvent.event_type = eventType; + peEvent.status = status; + peEvent.reason_code = reasonCode; + + WLAN_HOST_DIAG_EVENT_REPORT(&peEvent, EVENT_WLAN_PE); + return; +} + +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + +uint8_t *lim_get_ie_ptr_new(tpAniSirGlobal pMac, uint8_t *pIes, int length, + uint8_t eid, eSizeOfLenField size_of_len_field) +{ + int left = length; + uint8_t *ptr = pIes; + uint8_t elem_id; + uint16_t elem_len; + + while (left >= (size_of_len_field + 1)) { + elem_id = ptr[0]; + if (size_of_len_field == TWO_BYTE) { + elem_len = ((uint16_t) ptr[1]) | (ptr[2] << 8); + } else { + elem_len = ptr[1]; + } + + left -= (size_of_len_field + 1); + if (elem_len > left) { + lim_log(pMac, LOGE, + FL + ("****Invalid IEs eid = %d elem_len=%d left=%d*****"), + eid, elem_len, left); + return NULL; + } + if (elem_id == eid) { + return ptr; + } + + left -= elem_len; + ptr += (elem_len + (size_of_len_field + 1)); + } + return NULL; +} + +/* Returns length of P2P stream and Pointer ie passed to this function is filled with noa stream */ + +uint8_t lim_build_p2p_ie(tpAniSirGlobal pMac, uint8_t *ie, uint8_t *data, + uint8_t ie_len) +{ + int length = 0; + uint8_t *ptr = ie; + + ptr[length++] = SIR_MAC_EID_VENDOR; + ptr[length++] = ie_len + SIR_MAC_P2P_OUI_SIZE; + qdf_mem_copy(&ptr[length], SIR_MAC_P2P_OUI, SIR_MAC_P2P_OUI_SIZE); + qdf_mem_copy(&ptr[length + SIR_MAC_P2P_OUI_SIZE], data, ie_len); + return ie_len + SIR_P2P_IE_HEADER_LEN; +} + +/* Returns length of NoA stream and Pointer pNoaStream passed to this function is filled with noa stream */ + +uint8_t lim_get_noa_attr_stream_in_mult_p2p_ies(tpAniSirGlobal pMac, + uint8_t *noaStream, uint8_t noaLen, + uint8_t overFlowLen) +{ + uint8_t overFlowP2pStream[SIR_MAX_NOA_ATTR_LEN]; + + if ((noaLen <= (SIR_MAX_NOA_ATTR_LEN + SIR_P2P_IE_HEADER_LEN)) && + (noaLen >= overFlowLen) && (overFlowLen <= SIR_MAX_NOA_ATTR_LEN)) { + qdf_mem_copy(overFlowP2pStream, + noaStream + noaLen - overFlowLen, overFlowLen); + noaStream[noaLen - overFlowLen] = SIR_MAC_EID_VENDOR; + noaStream[noaLen - overFlowLen + 1] = + overFlowLen + SIR_MAC_P2P_OUI_SIZE; + qdf_mem_copy(noaStream + noaLen - overFlowLen + 2, + SIR_MAC_P2P_OUI, SIR_MAC_P2P_OUI_SIZE); + qdf_mem_copy(noaStream + noaLen + 2 + SIR_MAC_P2P_OUI_SIZE - + overFlowLen, overFlowP2pStream, overFlowLen); + } + + return noaLen + SIR_P2P_IE_HEADER_LEN; + +} + +/* Returns length of NoA stream and Pointer pNoaStream passed to this function is filled with noa stream */ +uint8_t lim_get_noa_attr_stream(tpAniSirGlobal pMac, uint8_t *pNoaStream, + tpPESession psessionEntry) +{ + uint8_t len = 0; + + uint8_t *pBody = pNoaStream; + + if ((psessionEntry != NULL) && (psessionEntry->valid) && + (psessionEntry->pePersona == QDF_P2P_GO_MODE)) { + if ((!(psessionEntry->p2pGoPsUpdate.uNoa1Duration)) + && (!(psessionEntry->p2pGoPsUpdate.uNoa2Duration)) + && (!psessionEntry->p2pGoPsUpdate.oppPsFlag) + ) + return 0; /* No NoA Descriptor then return 0 */ + + pBody[0] = SIR_P2P_NOA_ATTR; + + pBody[3] = psessionEntry->p2pGoPsUpdate.index; + pBody[4] = + psessionEntry->p2pGoPsUpdate.ctWin | (psessionEntry-> + p2pGoPsUpdate. + oppPsFlag << 7); + len = 5; + pBody += len; + + if (psessionEntry->p2pGoPsUpdate.uNoa1Duration) { + *pBody = psessionEntry->p2pGoPsUpdate.uNoa1IntervalCnt; + pBody += 1; + len += 1; + + *((uint32_t *) (pBody)) = + sir_swap_u32if_needed(psessionEntry->p2pGoPsUpdate. + uNoa1Duration); + pBody += sizeof(uint32_t); + len += 4; + + *((uint32_t *) (pBody)) = + sir_swap_u32if_needed(psessionEntry->p2pGoPsUpdate. + uNoa1Interval); + pBody += sizeof(uint32_t); + len += 4; + + *((uint32_t *) (pBody)) = + sir_swap_u32if_needed(psessionEntry->p2pGoPsUpdate. + uNoa1StartTime); + pBody += sizeof(uint32_t); + len += 4; + + } + + if (psessionEntry->p2pGoPsUpdate.uNoa2Duration) { + *pBody = psessionEntry->p2pGoPsUpdate.uNoa2IntervalCnt; + pBody += 1; + len += 1; + + *((uint32_t *) (pBody)) = + sir_swap_u32if_needed(psessionEntry->p2pGoPsUpdate. + uNoa2Duration); + pBody += sizeof(uint32_t); + len += 4; + + *((uint32_t *) (pBody)) = + sir_swap_u32if_needed(psessionEntry->p2pGoPsUpdate. + uNoa2Interval); + pBody += sizeof(uint32_t); + len += 4; + + *((uint32_t *) (pBody)) = + sir_swap_u32if_needed(psessionEntry->p2pGoPsUpdate. + uNoa2StartTime); + pBody += sizeof(uint32_t); + len += 4; + + } + + pBody = pNoaStream + 1; + *((uint16_t *) (pBody)) = sir_swap_u16if_needed(len - 3); /*one byte for Attr and 2 bytes for length */ + + return len; + + } + return 0; + +} + +void pe_set_resume_channel(tpAniSirGlobal pMac, uint16_t channel, + ePhyChanBondState phyCbState) +{ + + pMac->lim.gResumeChannel = channel; + pMac->lim.gResumePhyCbState = phyCbState; +} + +bool lim_is_noa_insert_reqd(tpAniSirGlobal pMac) +{ + uint8_t i; + for (i = 0; i < pMac->lim.maxBssId; i++) { + if (pMac->lim.gpSession[i].valid == true) { + if ((eLIM_AP_ROLE == + pMac->lim.gpSession[i].limSystemRole) + && (QDF_P2P_GO_MODE == + pMac->lim.gpSession[i].pePersona) + ) { + return true; + } + } + } + return false; +} + +bool lim_isconnected_on_dfs_channel(uint8_t currentChannel) +{ + if (CHANNEL_STATE_DFS == + cds_get_channel_state(currentChannel)) { + return true; + } else { + return false; + } +} + +#ifdef WLAN_FEATURE_11W +void lim_pmf_sa_query_timer_handler(void *pMacGlobal, uint32_t param) +{ + tpAniSirGlobal pMac = (tpAniSirGlobal) pMacGlobal; + tPmfSaQueryTimerId timerId; + tpPESession psessionEntry; + tpDphHashNode pSta; + uint32_t maxRetries; + + lim_log(pMac, LOG1, FL("SA Query timer fires")); + timerId.value = param; + + /* Check that SA Query is in progress */ + psessionEntry = pe_find_session_by_session_id(pMac, + timerId.fields.sessionId); + if (psessionEntry == NULL) { + lim_log(pMac, LOGE, + FL("Session does not exist for given session ID %d"), + timerId.fields.sessionId); + return; + } + pSta = dph_get_hash_entry(pMac, timerId.fields.peerIdx, + &psessionEntry->dph.dphHashTable); + if (pSta == NULL) { + lim_log(pMac, LOGE, + FL("Entry does not exist for given peer index %d"), + timerId.fields.peerIdx); + return; + } + if (DPH_SA_QUERY_IN_PROGRESS != pSta->pmfSaQueryState) + return; + + /* Increment the retry count, check if reached maximum */ + if (wlan_cfg_get_int(pMac, WNI_CFG_PMF_SA_QUERY_MAX_RETRIES, + &maxRetries) != eSIR_SUCCESS) { + lim_log(pMac, LOGE, + FL + ("Could not retrieve PMF SA Query maximum retries value")); + pSta->pmfSaQueryState = DPH_SA_QUERY_NOT_IN_PROGRESS; + return; + } + pSta->pmfSaQueryRetryCount++; + if (pSta->pmfSaQueryRetryCount >= maxRetries) { + lim_log(pMac, LOGE, FL("SA Query timed out,Deleting STA")); + lim_print_mac_addr(pMac, pSta->staAddr, LOGE); + lim_send_disassoc_mgmt_frame(pMac, + eSIR_MAC_DISASSOC_DUE_TO_INACTIVITY_REASON, + pSta->staAddr, psessionEntry, false); + lim_trigger_sta_deletion(pMac, pSta, psessionEntry); + pSta->pmfSaQueryState = DPH_SA_QUERY_TIMED_OUT; + return; + } + /* Retry SA Query */ + lim_send_sa_query_request_frame(pMac, + (uint8_t *) &(pSta-> + pmfSaQueryCurrentTransId), + pSta->staAddr, psessionEntry); + pSta->pmfSaQueryCurrentTransId++; + lim_log(pMac, LOGE, FL("Starting SA Query retry %d"), + pSta->pmfSaQueryRetryCount); + if (tx_timer_activate(&pSta->pmfSaQueryTimer) != TX_SUCCESS) { + lim_log(pMac, LOGE, FL("PMF SA Query timer activation failed!")); + pSta->pmfSaQueryState = DPH_SA_QUERY_NOT_IN_PROGRESS; + } +} +#endif + +bool lim_check_vht_op_mode_change(tpAniSirGlobal pMac, tpPESession psessionEntry, + uint8_t chanWidth, uint8_t dot11_mode, + uint8_t staId, uint8_t *peerMac) +{ + tUpdateVHTOpMode tempParam; + + tempParam.opMode = chanWidth; + tempParam.dot11_mode = dot11_mode; + tempParam.staId = staId; + tempParam.smesessionId = psessionEntry->smeSessionId; + qdf_mem_copy(tempParam.peer_mac, peerMac, sizeof(tSirMacAddr)); + + lim_send_mode_update(pMac, &tempParam, psessionEntry); + + return true; +} + +bool lim_set_nss_change(tpAniSirGlobal pMac, tpPESession psessionEntry, + uint8_t rxNss, uint8_t staId, uint8_t *peerMac) +{ + tUpdateRxNss tempParam; + + tempParam.rxNss = rxNss; + tempParam.staId = staId; + tempParam.smesessionId = psessionEntry->smeSessionId; + qdf_mem_copy(tempParam.peer_mac, peerMac, sizeof(tSirMacAddr)); + + lim_send_rx_nss_update(pMac, &tempParam, psessionEntry); + + return true; +} + +bool lim_check_membership_user_position(tpAniSirGlobal pMac, + tpPESession psessionEntry, + uint32_t membership, uint32_t userPosition, + uint8_t staId) +{ + tUpdateMembership tempParamMembership; + tUpdateUserPos tempParamUserPosition; + + tempParamMembership.membership = membership; + tempParamMembership.staId = staId; + tempParamMembership.smesessionId = psessionEntry->smeSessionId; + qdf_mem_copy(tempParamMembership.peer_mac, psessionEntry->bssId, + sizeof(tSirMacAddr)); + + lim_set_membership(pMac, &tempParamMembership, psessionEntry); + + tempParamUserPosition.userPos = userPosition; + tempParamUserPosition.staId = staId; + tempParamUserPosition.smesessionId = psessionEntry->smeSessionId; + qdf_mem_copy(tempParamUserPosition.peer_mac, psessionEntry->bssId, + sizeof(tSirMacAddr)); + + lim_set_user_pos(pMac, &tempParamUserPosition, psessionEntry); + + return true; +} + +void lim_get_short_slot_from_phy_mode(tpAniSirGlobal pMac, tpPESession psessionEntry, + uint32_t phyMode, uint8_t *pShortSlotEnabled) +{ + uint8_t val = 0; + + /* only 2.4G band should have short slot enable, rest it should be default */ + if (phyMode == WNI_CFG_PHY_MODE_11G) { + /* short slot is default in all other modes */ + if ((psessionEntry->pePersona == QDF_SAP_MODE) || + (psessionEntry->pePersona == QDF_IBSS_MODE) || + (psessionEntry->pePersona == QDF_P2P_GO_MODE)) { + val = true; + } + /* Program Polaris based on AP capability */ + if (psessionEntry->limMlmState == eLIM_MLM_WT_JOIN_BEACON_STATE) { + /* Joining BSS. */ + val = + SIR_MAC_GET_SHORT_SLOT_TIME(psessionEntry-> + limCurrentBssCaps); + } else if (psessionEntry->limMlmState == + eLIM_MLM_WT_REASSOC_RSP_STATE) { + /* Reassociating with AP. */ + val = + SIR_MAC_GET_SHORT_SLOT_TIME(psessionEntry-> + limReassocBssCaps); + } + } else { + /* + * 11B does not short slot and short slot is default + * for 11A mode. Hence, not need to set this bit + */ + val = false; + } + + lim_log(pMac, LOG1, FL("phyMode = %u shortslotsupported = %u"), phyMode, + val); + *pShortSlotEnabled = val; +} + +#ifdef WLAN_FEATURE_11W +/** + * + * \brief This function is called by various LIM modules to correctly set + * the Protected bit in the Frame Control Field of the 802.11 frame MAC header + * + * + * \param pMac Pointer to Global MAC structure + * + * \param psessionEntry Pointer to session corresponding to the connection + * + * \param peer Peer address of the STA to which the frame is to be sent + * + * \param pMacHdr Pointer to the frame MAC header + * + * \return nothing + * + * + */ +void +lim_set_protected_bit(tpAniSirGlobal pMac, + tpPESession psessionEntry, + tSirMacAddr peer, tpSirMacMgmtHdr pMacHdr) +{ + uint16_t aid; + tpDphHashNode pStaDs; + + if (LIM_IS_AP_ROLE(psessionEntry)) { + + pStaDs = dph_lookup_hash_entry(pMac, peer, &aid, + &psessionEntry->dph.dphHashTable); + if (pStaDs != NULL) { + /* rmfenabled will be set at the time of addbss. + * but sometimes EAP auth fails and keys are not + * installed then if we send any management frame + * like deauth/disassoc with this bit set then + * firmware crashes. so check for keys are + * installed or not also before setting the bit + */ + if (pStaDs->rmfEnabled && pStaDs->is_key_installed) + pMacHdr->fc.wep = 1; + } + } else if (psessionEntry->limRmfEnabled && + psessionEntry->is_key_installed) { + pMacHdr->fc.wep = 1; + } +} /*** end lim_set_protected_bit() ***/ +#endif + +void lim_set_ht_caps(tpAniSirGlobal p_mac, tpPESession p_session_entry, + uint8_t *p_ie_start, uint32_t num_bytes) +{ + uint8_t *p_ie = NULL; + tDot11fIEHTCaps dot11_ht_cap = {0,}; + + populate_dot11f_ht_caps(p_mac, p_session_entry, &dot11_ht_cap); + p_ie = lim_get_ie_ptr_new(p_mac, p_ie_start, num_bytes, + DOT11F_EID_HTCAPS, ONE_BYTE); + lim_log(p_mac, LOG2, FL("p_ie %p dot11_ht_cap.supportedMCSSet[0]=0x%x"), + p_ie, dot11_ht_cap.supportedMCSSet[0]); + if (p_ie) { + /* convert from unpacked to packed structure */ + tHtCaps *p_ht_cap = (tHtCaps *) &p_ie[2]; + + p_ht_cap->advCodingCap = dot11_ht_cap.advCodingCap; + p_ht_cap->supportedChannelWidthSet = + dot11_ht_cap.supportedChannelWidthSet; + p_ht_cap->mimoPowerSave = dot11_ht_cap.mimoPowerSave; + p_ht_cap->greenField = dot11_ht_cap.greenField; + p_ht_cap->shortGI20MHz = dot11_ht_cap.shortGI20MHz; + p_ht_cap->shortGI40MHz = dot11_ht_cap.shortGI40MHz; + p_ht_cap->txSTBC = dot11_ht_cap.txSTBC; + p_ht_cap->rxSTBC = dot11_ht_cap.rxSTBC; + p_ht_cap->delayedBA = dot11_ht_cap.delayedBA; + p_ht_cap->maximalAMSDUsize = dot11_ht_cap.maximalAMSDUsize; + p_ht_cap->dsssCckMode40MHz = dot11_ht_cap.dsssCckMode40MHz; + p_ht_cap->psmp = dot11_ht_cap.psmp; + p_ht_cap->stbcControlFrame = dot11_ht_cap.stbcControlFrame; + p_ht_cap->lsigTXOPProtection = dot11_ht_cap.lsigTXOPProtection; + p_ht_cap->maxRxAMPDUFactor = dot11_ht_cap.maxRxAMPDUFactor; + p_ht_cap->mpduDensity = dot11_ht_cap.mpduDensity; + qdf_mem_copy((void *)p_ht_cap->supportedMCSSet, + (void *)(dot11_ht_cap.supportedMCSSet), + sizeof(p_ht_cap->supportedMCSSet)); + p_ht_cap->pco = dot11_ht_cap.pco; + p_ht_cap->transitionTime = dot11_ht_cap.transitionTime; + p_ht_cap->mcsFeedback = dot11_ht_cap.mcsFeedback; + p_ht_cap->txBF = dot11_ht_cap.txBF; + p_ht_cap->rxStaggeredSounding = + dot11_ht_cap.rxStaggeredSounding; + p_ht_cap->txStaggeredSounding = + dot11_ht_cap.txStaggeredSounding; + p_ht_cap->rxZLF = dot11_ht_cap.rxZLF; + p_ht_cap->txZLF = dot11_ht_cap.txZLF; + p_ht_cap->implicitTxBF = dot11_ht_cap.implicitTxBF; + p_ht_cap->calibration = dot11_ht_cap.calibration; + p_ht_cap->explicitCSITxBF = dot11_ht_cap.explicitCSITxBF; + p_ht_cap->explicitUncompressedSteeringMatrix = + dot11_ht_cap.explicitUncompressedSteeringMatrix; + p_ht_cap->explicitBFCSIFeedback = + dot11_ht_cap.explicitBFCSIFeedback; + p_ht_cap->explicitUncompressedSteeringMatrixFeedback = + dot11_ht_cap.explicitUncompressedSteeringMatrixFeedback; + p_ht_cap->explicitCompressedSteeringMatrixFeedback = + dot11_ht_cap.explicitCompressedSteeringMatrixFeedback; + p_ht_cap->csiNumBFAntennae = dot11_ht_cap.csiNumBFAntennae; + p_ht_cap->uncompressedSteeringMatrixBFAntennae = + dot11_ht_cap.uncompressedSteeringMatrixBFAntennae; + p_ht_cap->compressedSteeringMatrixBFAntennae = + dot11_ht_cap.compressedSteeringMatrixBFAntennae; + p_ht_cap->antennaSelection = dot11_ht_cap.antennaSelection; + p_ht_cap->explicitCSIFeedbackTx = + dot11_ht_cap.explicitCSIFeedbackTx; + p_ht_cap->antennaIndicesFeedbackTx = + dot11_ht_cap.antennaIndicesFeedbackTx; + p_ht_cap->explicitCSIFeedback = + dot11_ht_cap.explicitCSIFeedback; + p_ht_cap->antennaIndicesFeedback = + dot11_ht_cap.antennaIndicesFeedback; + p_ht_cap->rxAS = dot11_ht_cap.rxAS; + p_ht_cap->txSoundingPPDUs = dot11_ht_cap.txSoundingPPDUs; + } +} + +void lim_set_vht_caps(tpAniSirGlobal p_mac, tpPESession p_session_entry, + uint8_t *p_ie_start, uint32_t num_bytes) +{ + uint8_t *p_ie = NULL; + tDot11fIEVHTCaps dot11_vht_cap; + + populate_dot11f_vht_caps(p_mac, p_session_entry, &dot11_vht_cap); + p_ie = lim_get_ie_ptr_new(p_mac, p_ie_start, num_bytes, + DOT11F_EID_VHTCAPS, ONE_BYTE); + + if (p_ie) { + tSirMacVHTCapabilityInfo *vht_cap = + (tSirMacVHTCapabilityInfo *) &p_ie[2]; + tSirVhtMcsInfo *vht_mcs = (tSirVhtMcsInfo *) &p_ie[2 + + sizeof(tSirMacVHTCapabilityInfo)]; + + union { + uint16_t u_value; + tSirMacVHTRxSupDataRateInfo vht_rx_supp_rate; + tSirMacVHTTxSupDataRateInfo vht_tx_supp_rate; + } u_vht_data_rate_info; + + vht_cap->maxMPDULen = dot11_vht_cap.maxMPDULen; + vht_cap->supportedChannelWidthSet = + dot11_vht_cap.supportedChannelWidthSet; + vht_cap->ldpcCodingCap = dot11_vht_cap.ldpcCodingCap; + vht_cap->shortGI80MHz = dot11_vht_cap.shortGI80MHz; + vht_cap->shortGI160and80plus80MHz = + dot11_vht_cap.shortGI160and80plus80MHz; + vht_cap->txSTBC = dot11_vht_cap.txSTBC; + vht_cap->rxSTBC = dot11_vht_cap.rxSTBC; + vht_cap->suBeamFormerCap = dot11_vht_cap.suBeamFormerCap; + vht_cap->suBeamformeeCap = dot11_vht_cap.suBeamformeeCap; + vht_cap->csnofBeamformerAntSup = + dot11_vht_cap.csnofBeamformerAntSup; + vht_cap->numSoundingDim = dot11_vht_cap.numSoundingDim; + vht_cap->muBeamformerCap = dot11_vht_cap.muBeamformerCap; + vht_cap->muBeamformeeCap = dot11_vht_cap.muBeamformeeCap; + vht_cap->vhtTXOPPS = dot11_vht_cap.vhtTXOPPS; + vht_cap->htcVHTCap = dot11_vht_cap.htcVHTCap; + vht_cap->maxAMPDULenExp = dot11_vht_cap.maxAMPDULenExp; + vht_cap->vhtLinkAdaptCap = dot11_vht_cap.vhtLinkAdaptCap; + vht_cap->rxAntPattern = dot11_vht_cap.rxAntPattern; + vht_cap->txAntPattern = dot11_vht_cap.txAntPattern; + vht_cap->reserved1 = dot11_vht_cap.reserved1; + + /* Populate VHT MCS Information */ + vht_mcs->rxMcsMap = dot11_vht_cap.rxMCSMap; + u_vht_data_rate_info.vht_rx_supp_rate.rxSupDataRate = + dot11_vht_cap.rxHighSupDataRate; + u_vht_data_rate_info.vht_rx_supp_rate.reserved = + dot11_vht_cap.reserved2; + vht_mcs->rxHighest = u_vht_data_rate_info.u_value; + + vht_mcs->txMcsMap = dot11_vht_cap.txMCSMap; + u_vht_data_rate_info.vht_tx_supp_rate.txSupDataRate = + dot11_vht_cap.txSupDataRate; + u_vht_data_rate_info.vht_tx_supp_rate.reserved = + dot11_vht_cap.reserved3; + vht_mcs->txHighest = u_vht_data_rate_info.u_value; + } +} + +/** + * lim_validate_received_frame_a1_addr() - To validate received frame's A1 addr + * @mac_ctx: pointer to mac context + * @a1: received frame's a1 address which is nothing but our self address + * @session: PE session pointer + * + * This routine will validate, A1 addres of the received frame + * + * Return: true or false + */ +bool lim_validate_received_frame_a1_addr(tpAniSirGlobal mac_ctx, + tSirMacAddr a1, tpPESession session) +{ + if (mac_ctx == NULL || session == NULL) { + QDF_TRACE(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_INFO, + "mac or session context is null"); + /* let main routine handle it */ + return true; + } + if (lim_is_group_addr(a1) || lim_is_addr_bc(a1)) { + /* just for fail safe, don't handle MC/BC a1 in this routine */ + return true; + } + if (qdf_mem_cmp(a1, session->selfMacAddr, 6)) { + lim_log(mac_ctx, LOGE, + FL("Invalid A1 address in received frame")); + return false; + } + return true; +} + +/** + * lim_check_and_reset_protection_params() - reset protection related parameters + * + * @mac_ctx: pointer to global mac structure + * + * resets protection related global parameters if the pe active session count + * is zero. + * + * Return: None + */ +void lim_check_and_reset_protection_params(tpAniSirGlobal mac_ctx) +{ + if (!pe_get_active_session_count(mac_ctx)) { + qdf_mem_zero(&mac_ctx->lim.gLimOverlap11gParams, + sizeof(mac_ctx->lim.gLimOverlap11gParams)); + qdf_mem_zero(&mac_ctx->lim.gLimOverlap11aParams, + sizeof(mac_ctx->lim.gLimOverlap11aParams)); + qdf_mem_zero(&mac_ctx->lim.gLimOverlapHt20Params, + sizeof(mac_ctx->lim.gLimOverlapHt20Params)); + qdf_mem_zero(&mac_ctx->lim.gLimOverlapNonGfParams, + sizeof(mac_ctx->lim.gLimOverlapNonGfParams)); + + mac_ctx->lim.gHTOperMode = eSIR_HT_OP_MODE_PURE; + } +} + +/** + * lim_set_stads_rtt_cap() - update station node RTT capability + * @sta_ds: Station hash node + * @ext_cap: Pointer to extended capability + * @mac_ctx: global MAC context + * + * This funciton update hash node's RTT capability based on received + * Extended capability IE. + * + * Return: None + */ +void lim_set_stads_rtt_cap(tpDphHashNode sta_ds, struct s_ext_cap *ext_cap, + tpAniSirGlobal mac_ctx) +{ + sta_ds->timingMeasCap = 0; + sta_ds->timingMeasCap |= (ext_cap->timing_meas) ? + RTT_TIMING_MEAS_CAPABILITY : + RTT_INVALID; + sta_ds->timingMeasCap |= (ext_cap->fine_time_meas_initiator) ? + RTT_FINE_TIME_MEAS_INITIATOR_CAPABILITY : + RTT_INVALID; + sta_ds->timingMeasCap |= (ext_cap->fine_time_meas_responder) ? + RTT_FINE_TIME_MEAS_RESPONDER_CAPABILITY : + RTT_INVALID; + + lim_log(mac_ctx, LOG1, + FL("ExtCap present, timingMeas: %d Initiator: %d Responder: %d"), + ext_cap->timing_meas, ext_cap->fine_time_meas_initiator, + ext_cap->fine_time_meas_responder); +} + +/** + * lim_send_ie() - sends IE to wma + * @mac_ctx: global MAC context + * @sme_session_id: sme session id + * @eid: IE id + * @band: band for which IE is intended + * @buf: buffer containing IE + * @len: length of buffer + * + * This funciton sends the IE data to WMA. + * + * Return: status of operation + */ +static QDF_STATUS lim_send_ie(tpAniSirGlobal mac_ctx, uint32_t sme_session_id, + uint8_t eid, enum cds_band_type band, + uint8_t *buf, uint32_t len) +{ + struct vdev_ie_info *ie_msg; + cds_msg_t msg = {0}; + QDF_STATUS status; + + /* Allocate memory for the WMI request */ + ie_msg = qdf_mem_malloc(sizeof(*ie_msg) + len); + if (!ie_msg) { + lim_log(mac_ctx, LOGE, FL("Failed to allocate memory")); + return QDF_STATUS_E_NOMEM; + } + + ie_msg->vdev_id = sme_session_id; + ie_msg->ie_id = eid; + ie_msg->length = len; + ie_msg->band = band; + /* IE data buffer starts at end of the struct */ + ie_msg->data = (uint8_t *)&ie_msg[1]; + + qdf_mem_copy(ie_msg->data, buf, len); + msg.type = WMA_SET_IE_INFO; + msg.bodyptr = ie_msg; + msg.reserved = 0; + + status = cds_mq_post_message(QDF_MODULE_ID_WMA, &msg); + if (QDF_STATUS_SUCCESS != status) { + lim_log(mac_ctx, LOGE, + FL("Not able to post WMA_SET_IE_INFO to WMA")); + qdf_mem_free(ie_msg); + return status; + } + + return status; +} + +/** + * lim_get_rx_ldpc() - gets ldpc setting for given channel(band) + * @mac_ctx: global mac context + * @ch: channel for which ldpc setting is required + * + * Return: true if enabled and false otherwise + */ +static inline bool lim_get_rx_ldpc(tpAniSirGlobal mac_ctx, uint8_t ch) +{ + if (mac_ctx->roam.configParam.rxLdpcEnable && + wma_is_rx_ldpc_supported_for_channel(CDS_CHANNEL_NUM(ch))) + return true; + else + return false; +} + +/** + * lim_send_ies_per_band() - gets ht and vht capability and send to firmware via + * wma + * @mac_ctx: global mac context + * @session: pe session. This can be NULL. In that case self cap will be sent + * @vdev_id: vdev for which IE is targeted + * + * This funciton gets ht and vht capability and send to firmware via wma + * + * Return: status of operation + */ +QDF_STATUS lim_send_ies_per_band(tpAniSirGlobal mac_ctx, + tpPESession session, + uint8_t vdev_id) +{ + uint8_t ht_caps[DOT11F_IE_HTCAPS_MIN_LEN + 2] = {0}; + uint8_t vht_caps[DOT11F_IE_VHTCAPS_MAX_LEN + 2] = {0}; + tHtCaps *p_ht_cap = (tHtCaps *)(&ht_caps[2]); + tSirMacVHTCapabilityInfo *p_vht_cap = + (tSirMacVHTCapabilityInfo *)(&vht_caps[2]); + + /* + * Note: Do not use Dot11f VHT structure, since 1 byte present flag in + * it is causing weird padding errors. Instead use Sir Mac VHT struct + * to send IE to wma. + */ + ht_caps[0] = DOT11F_EID_HTCAPS; + ht_caps[1] = DOT11F_IE_HTCAPS_MIN_LEN; + lim_set_ht_caps(mac_ctx, session, ht_caps, + DOT11F_IE_HTCAPS_MIN_LEN + 2); + /* Get LDPC and over write for 2G */ + p_ht_cap->advCodingCap = lim_get_rx_ldpc(mac_ctx, CHAN_ENUM_6); + /* Get self cap for HT40 support in 2G */ + if (mac_ctx->roam.configParam.channelBondingMode24GHz) { + p_ht_cap->supportedChannelWidthSet = 1; + p_ht_cap->shortGI40MHz = 1; + } else { + p_ht_cap->supportedChannelWidthSet = 0; + p_ht_cap->shortGI40MHz = 0; + } + lim_send_ie(mac_ctx, vdev_id, DOT11F_EID_HTCAPS, + CDS_BAND_2GHZ, &ht_caps[2], DOT11F_IE_HTCAPS_MIN_LEN); + /* + * Get LDPC and over write for 5G - using channel 64 because it + * is available in all reg domains. + */ + p_ht_cap->advCodingCap = lim_get_rx_ldpc(mac_ctx, CHAN_ENUM_64); + /* Get self cap for HT40 support in 5G */ + if (mac_ctx->roam.configParam.channelBondingMode5GHz) { + p_ht_cap->supportedChannelWidthSet = 1; + p_ht_cap->shortGI40MHz = 1; + } else { + p_ht_cap->supportedChannelWidthSet = 0; + p_ht_cap->shortGI40MHz = 0; + } + lim_send_ie(mac_ctx, vdev_id, DOT11F_EID_HTCAPS, + CDS_BAND_5GHZ, &ht_caps[2], DOT11F_IE_HTCAPS_MIN_LEN); + + vht_caps[0] = DOT11F_EID_VHTCAPS; + vht_caps[1] = DOT11F_IE_VHTCAPS_MAX_LEN; + lim_set_vht_caps(mac_ctx, session, vht_caps, + DOT11F_IE_VHTCAPS_MIN_LEN + 2); + /* + * Get LDPC and over write for 5G - using channel 64 because it + * is available in all reg domains. + */ + p_vht_cap->ldpcCodingCap = lim_get_rx_ldpc(mac_ctx, CHAN_ENUM_64); + /* Self VHT channel width for 5G is already negotiated with FW */ + lim_send_ie(mac_ctx, vdev_id, DOT11F_EID_VHTCAPS, + CDS_BAND_5GHZ, &vht_caps[2], DOT11F_IE_VHTCAPS_MIN_LEN); + + /* Get LDPC and over write for 2G */ + p_vht_cap->ldpcCodingCap = lim_get_rx_ldpc(mac_ctx, CHAN_ENUM_6); + /* Self VHT 80/160/80+80 channel width for 2G is 0 */ + p_vht_cap->supportedChannelWidthSet = 0; + p_vht_cap->shortGI80MHz = 0; + p_vht_cap->shortGI160and80plus80MHz = 0; + lim_send_ie(mac_ctx, vdev_id, DOT11F_EID_VHTCAPS, + CDS_BAND_2GHZ, &vht_caps[2], DOT11F_IE_VHTCAPS_MIN_LEN); + + return QDF_STATUS_SUCCESS; +} + +/** + * lim_send_ext_cap_ie() - send ext cap IE to FW + * @mac_ctx: global MAC context + * @session_entry: PE session + * @extra_extcap: extracted ext cap + * @merge: merge extra ext cap + * + * This function is invoked after VDEV is created to update firmware + * about the extended capabilities that the corresponding VDEV is capable + * of. Since STA/SAP can have different Extended capabilities set, this function + * is called per vdev creation. + * + * Return: QDF_STATUS + */ +QDF_STATUS lim_send_ext_cap_ie(tpAniSirGlobal mac_ctx, + uint32_t session_id, + tDot11fIEExtCap *extra_extcap, bool merge) +{ + tDot11fIEExtCap ext_cap_data = {0}; + uint32_t dot11mode, num_bytes; + bool vht_enabled = false; + struct vdev_ie_info *vdev_ie; + cds_msg_t msg = {0}; + tSirRetStatus status; + uint8_t *temp, i; + + wlan_cfg_get_int(mac_ctx, WNI_CFG_DOT11_MODE, &dot11mode); + if (IS_DOT11_MODE_VHT(dot11mode)) + vht_enabled = true; + + status = populate_dot11f_ext_cap(mac_ctx, vht_enabled, &ext_cap_data, + NULL); + if (eSIR_SUCCESS != status) { + lim_log(mac_ctx, LOGE, FL("Failed to populate ext cap IE")); + return QDF_STATUS_E_FAILURE; + } + + num_bytes = ext_cap_data.num_bytes; + + if (merge && NULL != extra_extcap && extra_extcap->num_bytes > 0) { + if (extra_extcap->num_bytes > ext_cap_data.num_bytes) + num_bytes = extra_extcap->num_bytes; + lim_merge_extcap_struct(&ext_cap_data, extra_extcap, true); + } + + /* Allocate memory for the WMI request, and copy the parameter */ + vdev_ie = qdf_mem_malloc(sizeof(*vdev_ie) + num_bytes); + if (!vdev_ie) { + lim_log(mac_ctx, LOGE, FL("Failed to allocate memory")); + return QDF_STATUS_E_NOMEM; + } + + vdev_ie->vdev_id = session_id; + vdev_ie->ie_id = DOT11F_EID_EXTCAP; + vdev_ie->length = num_bytes; + vdev_ie->band = 0; + + lim_log(mac_ctx, LOG1, FL("vdev %d ieid %d len %d"), session_id, + DOT11F_EID_EXTCAP, num_bytes); + temp = ext_cap_data.bytes; + for (i = 0; i < num_bytes; i++, temp++) + lim_log(mac_ctx, LOG1, FL("%d byte is %02x"), i+1, *temp); + + vdev_ie->data = (uint8_t *)vdev_ie + sizeof(*vdev_ie); + qdf_mem_copy(vdev_ie->data, ext_cap_data.bytes, num_bytes); + + msg.type = WMA_SET_IE_INFO; + msg.bodyptr = vdev_ie; + msg.reserved = 0; + + if (QDF_STATUS_SUCCESS != + cds_mq_post_message(QDF_MODULE_ID_WMA, &msg)) { + lim_log(mac_ctx, LOGE, + FL("Not able to post WMA_SET_IE_INFO to WDA")); + qdf_mem_free(vdev_ie); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * lim_strip_ie() - strip requested IE from IE buffer + * @mac_ctx: global MAC context + * @addn_ie: Additional IE buffer + * @addn_ielen: Length of additional IE + * @eid: EID of IE to strip + * @size_of_len_field: lenght of IE length field + * @oui: if present matches OUI also + * @oui_length: if previous present, this is length of oui + * @extracted_ie: if not NULL, copy the stripped IE to this buffer + * + * This utility function is used to strip of the requested IE if present + * in IE buffer. + * + * Return: tSirRetStatus + */ +tSirRetStatus lim_strip_ie(tpAniSirGlobal mac_ctx, + uint8_t *addn_ie, uint16_t *addn_ielen, + uint8_t eid, eSizeOfLenField size_of_len_field, + uint8_t *oui, uint8_t oui_length, uint8_t *extracted_ie, + uint32_t eid_max_len) +{ + uint8_t *tempbuf = NULL; + uint16_t templen = 0; + int left = *addn_ielen; + uint8_t *ptr = addn_ie; + uint8_t elem_id; + uint16_t elem_len; + + if (NULL == addn_ie) { + lim_log(mac_ctx, LOG1, FL("NULL addn_ie pointer")); + return eSIR_IGNORE_IE; + } + + tempbuf = qdf_mem_malloc(left); + if (NULL == tempbuf) { + lim_log(mac_ctx, LOGE, FL("Unable to allocate memory")); + return eSIR_MEM_ALLOC_FAILED; + } + + while (left >= 2) { + elem_id = ptr[0]; + left -= 1; + if (size_of_len_field == TWO_BYTE) { + elem_len = *((uint16_t *)&ptr[1]); + left -= 2; + } else { + elem_len = ptr[1]; + left -= 1; + } + if (elem_len > left) { + lim_log(mac_ctx, LOGE, + FL("Invalid IEs eid = %d elem_len=%d left=%d"), + elem_id, elem_len, left); + qdf_mem_free(tempbuf); + return eSIR_FAILURE; + } + + if (eid != elem_id || + (oui && qdf_mem_cmp(oui, + &ptr[size_of_len_field + 1], + oui_length))) { + qdf_mem_copy(tempbuf + templen, &ptr[0], + elem_len + size_of_len_field + 1); + templen += (elem_len + size_of_len_field + 1); + } else { + /* + * eid matched and if provided OUI also matched + * take oui IE and store in provided buffer. + */ + if (NULL != extracted_ie) { + qdf_mem_set(extracted_ie, + eid_max_len + size_of_len_field + 1, + 0); + if (elem_len <= eid_max_len) + qdf_mem_copy(extracted_ie, &ptr[0], + elem_len + size_of_len_field + 1); + } + } + left -= elem_len; + ptr += (elem_len + size_of_len_field + 1); + } + qdf_mem_copy(addn_ie, tempbuf, templen); + + *addn_ielen = templen; + qdf_mem_free(tempbuf); + + return eSIR_SUCCESS; +} + +tSirRetStatus lim_strip_supp_op_class_update_struct(tpAniSirGlobal mac_ctx, + uint8_t *addn_ie, uint16_t *addn_ielen, + tDot11fIESuppOperatingClasses *dst) +{ + uint8_t extracted_buff[DOT11F_IE_SUPPOPERATINGCLASSES_MAX_LEN + 2]; + tSirRetStatus status; + + qdf_mem_set((uint8_t *)&extracted_buff[0], + DOT11F_IE_SUPPOPERATINGCLASSES_MAX_LEN + 2, + 0); + status = lim_strip_ie(mac_ctx, addn_ie, addn_ielen, + DOT11F_EID_SUPPOPERATINGCLASSES, ONE_BYTE, + NULL, 0, extracted_buff, + DOT11F_IE_SUPPOPERATINGCLASSES_MAX_LEN); + if (eSIR_SUCCESS != status) { + lim_log(mac_ctx, LOG1, + FL("Failed to strip supp_op_mode IE status = (%d)."), + status); + return status; + } + + if (DOT11F_EID_SUPPOPERATINGCLASSES != extracted_buff[0] || + extracted_buff[1] > DOT11F_IE_SUPPOPERATINGCLASSES_MAX_LEN) { + lim_log(mac_ctx, LOG1, FL("Invalid IEs eid = %d elem_len=%d "), + extracted_buff[0], extracted_buff[1]); + return eSIR_FAILURE; + } + + /* update the extracted supp op class to struct*/ + if (DOT11F_PARSE_SUCCESS != dot11f_unpack_ie_supp_operating_classes( + mac_ctx, &extracted_buff[2], extracted_buff[1], dst)) { + lim_log(mac_ctx, LOGE, FL("dot11f_unpack Parse Error ")); + return eSIR_FAILURE; + } + + return eSIR_SUCCESS; +} + +/** + * lim_update_extcap_struct() - poputlate the dot11f structure + * @mac_ctx: global MAC context + * @buf: extracted IE buffer + * @dst: extended capability IE structure to be updated + * + * This function is used to update the extended capability structure + * with @buf. + * + * Return: None + */ +void lim_update_extcap_struct(tpAniSirGlobal mac_ctx, + uint8_t *buf, tDot11fIEExtCap *dst) +{ + uint8_t out[DOT11F_IE_EXTCAP_MAX_LEN]; + uint32_t status; + + if (NULL == buf) { + lim_log(mac_ctx, LOGE, FL("Invalid Buffer Address")); + return; + } + + if (NULL == dst) { + lim_log(mac_ctx, LOGE, FL("NULL dst pointer")); + return; + } + + if (DOT11F_EID_EXTCAP != buf[0] || buf[1] > DOT11F_IE_EXTCAP_MAX_LEN) { + lim_log(mac_ctx, LOG1, FL("Invalid IEs eid = %d elem_len=%d "), + buf[0], buf[1]); + return; + } + + qdf_mem_set((uint8_t *)&out[0], DOT11F_IE_EXTCAP_MAX_LEN, 0); + qdf_mem_copy(&out[0], &buf[2], buf[1]); + + status = dot11f_unpack_ie_ext_cap(mac_ctx, &out[0], + buf[1], dst); + if (DOT11F_PARSE_SUCCESS != status) + pe_err("dot11f_unpack Parse Error %d", status); +} + +/** + * lim_strip_extcap_update_struct - strip extended capability IE and populate + * the dot11f structure + * @mac_ctx: global MAC context + * @addn_ie: Additional IE buffer + * @addn_ielen: Length of additional IE + * @dst: extended capability IE structure to be updated + * + * This function is used to strip extended capability IE from IE buffer and + * update the passed structure. + * + * Return: tSirRetStatus + */ +tSirRetStatus lim_strip_extcap_update_struct(tpAniSirGlobal mac_ctx, + uint8_t *addn_ie, uint16_t *addn_ielen, tDot11fIEExtCap *dst) +{ + uint8_t extracted_buff[DOT11F_IE_EXTCAP_MAX_LEN + 2]; + tSirRetStatus status; + + qdf_mem_set((uint8_t *)&extracted_buff[0], DOT11F_IE_EXTCAP_MAX_LEN + 2, + 0); + status = lim_strip_ie(mac_ctx, addn_ie, addn_ielen, + DOT11F_EID_EXTCAP, ONE_BYTE, + NULL, 0, extracted_buff, + DOT11F_IE_EXTCAP_MAX_LEN); + if (eSIR_SUCCESS != status) { + lim_log(mac_ctx, LOG1, + FL("Failed to strip extcap IE status = (%d)."), status); + return status; + } + + /* update the extracted ExtCap to struct*/ + lim_update_extcap_struct(mac_ctx, extracted_buff, dst); + return status; +} + +/** + * lim_merge_extcap_struct() - merge extended capabilities info + * @dst: destination extended capabilities + * @src: source extended capabilities + * @add: true if add the capabilites, false if strip the capabilites. + * + * This function is used to take @src info and add/strip it to/from + * @dst extended capabilities info. + * + * Return: None + */ +void lim_merge_extcap_struct(tDot11fIEExtCap *dst, + tDot11fIEExtCap *src, + bool add) +{ + uint8_t *tempdst = (uint8_t *)dst->bytes; + uint8_t *tempsrc = (uint8_t *)src->bytes; + uint8_t structlen = member_size(tDot11fIEExtCap, bytes); + + /* Return if @src not present */ + if (!src->present) + return; + + /* Return if strip the capabilites from @dst which not present */ + if (!dst->present && !add) + return; + + /* Merge the capabilites info in other cases */ + while (tempdst && tempsrc && structlen--) { + if (add) + *tempdst |= *tempsrc; + else + *tempdst &= *tempsrc; + tempdst++; + tempsrc++; + } + dst->num_bytes = lim_compute_ext_cap_ie_length(dst); + if (dst->num_bytes == 0) + dst->present = 0; + else + dst->present = 1; +} + +/** + * lim_get_80Mhz_center_channel - finds 80 Mhz center channel + * + * @primary_channel: Primary channel for given 80 MHz band + * + * There are fixed 80MHz band and for each fixed band there is only one center + * valid channel. Also location of primary channel decides what 80 MHz band will + * it use, hence it decides what center channel will be used. This function + * does thus calculation and returns the center channel. + * + * Return: center channel + */ +uint8_t +lim_get_80Mhz_center_channel(uint8_t primary_channel) +{ + if (primary_channel >= 36 && primary_channel <= 48) + return (36+48)/2; + if (primary_channel >= 52 && primary_channel <= 64) + return (52+64)/2; + if (primary_channel >= 100 && primary_channel <= 112) + return (100+112)/2; + if (primary_channel >= 116 && primary_channel <= 128) + return (116+128)/2; + if (primary_channel >= 132 && primary_channel <= 144) + return (132+144)/2; + if (primary_channel >= 149 && primary_channel <= 161) + return (149+161)/2; + + return INVALID_CHANNEL_ID; +} + +/** + * lim_scan_type_to_string(): converts scan type enum to string. + * @scan_type: enum value of scan_type. + * + * Return: Printable string for scan_type + */ +const char *lim_scan_type_to_string(const uint8_t scan_type) +{ + switch (scan_type) { + CASE_RETURN_STRING(eSIR_PASSIVE_SCAN); + CASE_RETURN_STRING(eSIR_ACTIVE_SCAN); + CASE_RETURN_STRING(eSIR_BEACON_TABLE); + default: + return "Unknown scan_type"; + } +} + +/** + * lim_bss_type_to_string(): converts bss type enum to string. + * @bss_type: enum value of bss_type. + * + * Return: Printable string for bss_type + */ +const char *lim_bss_type_to_string(const uint16_t bss_type) +{ + switch (bss_type) { + CASE_RETURN_STRING(eSIR_INFRASTRUCTURE_MODE); + CASE_RETURN_STRING(eSIR_INFRA_AP_MODE); + CASE_RETURN_STRING(eSIR_IBSS_MODE); + CASE_RETURN_STRING(eSIR_AUTO_MODE); + CASE_RETURN_STRING(eSIR_NDI_MODE); + default: + return "Unknown bss_type"; + } +} + +/** + * lim_init_obss_params(): Initializes the OBSS Scan Parameters + * @sesssion: LIM session + * @mac_ctx: Mac context + * + * Return: None + */ +void lim_init_obss_params(tpAniSirGlobal mac_ctx, tpPESession session) +{ + uint32_t cfg_value; + + if (wlan_cfg_get_int(mac_ctx, WNI_CFG_OBSS_HT40_SCAN_ACTIVE_DWELL_TIME, + &cfg_value) != eSIR_SUCCESS) { + lim_log(mac_ctx, LOGE, + FL("Fail to retrieve %x value"), + WNI_CFG_OBSS_HT40_SCAN_ACTIVE_DWELL_TIME); + return; + } + session->obss_ht40_scanparam.obss_active_dwelltime = cfg_value; + + if (wlan_cfg_get_int(mac_ctx, WNI_CFG_OBSS_HT40_SCAN_PASSIVE_DWELL_TIME, + &cfg_value) != eSIR_SUCCESS) { + lim_log(mac_ctx, LOGE, + FL("Fail to retrieve %x value"), + WNI_CFG_OBSS_HT40_SCAN_PASSIVE_DWELL_TIME); + return; + } + session->obss_ht40_scanparam.obss_passive_dwelltime = cfg_value; + + if (wlan_cfg_get_int(mac_ctx, + WNI_CFG_OBSS_HT40_SCAN_WIDTH_TRIGGER_INTERVAL, + &cfg_value) != eSIR_SUCCESS) { + lim_log(mac_ctx, LOGE, + FL("Fail to retrieve %x value"), + WNI_CFG_OBSS_HT40_SCAN_WIDTH_TRIGGER_INTERVAL); + return; + } + session->obss_ht40_scanparam.obss_width_trigger_interval = cfg_value; + if (wlan_cfg_get_int(mac_ctx, + WNI_CFG_OBSS_HT40_SCAN_ACTIVE_TOTAL_PER_CHANNEL, + &cfg_value) != eSIR_SUCCESS) { + lim_log(mac_ctx, LOGE, + FL("Fail to retrieve %x value"), + WNI_CFG_OBSS_HT40_SCAN_ACTIVE_TOTAL_PER_CHANNEL); + return; + } + session->obss_ht40_scanparam.obss_active_total_per_channel = cfg_value; + if (wlan_cfg_get_int(mac_ctx, + WNI_CFG_OBSS_HT40_SCAN_PASSIVE_TOTAL_PER_CHANNEL, &cfg_value) + != eSIR_SUCCESS) { + lim_log(mac_ctx, LOGE, + FL("Fail to retrieve %x value"), + WNI_CFG_OBSS_HT40_SCAN_PASSIVE_TOTAL_PER_CHANNEL); + return; + } + session->obss_ht40_scanparam.obss_passive_total_per_channel = cfg_value; + + if (wlan_cfg_get_int(mac_ctx, + WNI_CFG_OBSS_HT40_WIDTH_CH_TRANSITION_DELAY, &cfg_value) + != eSIR_SUCCESS) { + lim_log(mac_ctx, LOGE, + FL("Fail to retrieve %x value"), + WNI_CFG_OBSS_HT40_WIDTH_CH_TRANSITION_DELAY); + return; + } + session->obss_ht40_scanparam.bsswidth_ch_trans_delay = + cfg_value; + + if (wlan_cfg_get_int(mac_ctx, WNI_CFG_OBSS_HT40_SCAN_ACTIVITY_THRESHOLD, + &cfg_value) != eSIR_SUCCESS) { + lim_log(mac_ctx, LOGE, + FL("Fail to retrieve %x value"), + WNI_CFG_OBSS_HT40_SCAN_ACTIVITY_THRESHOLD); + return; + } + session->obss_ht40_scanparam.obss_activity_threshold = cfg_value; +} + +/** + * lim_update_obss_scanparams(): Updates OBSS SCAN IE parameters to session + * @sesssion: LIM session + * @scan_params: Scan parameters + * + * Return: None + */ +void lim_update_obss_scanparams(tpPESession session, + tDot11fIEOBSSScanParameters *scan_params) +{ + /* + * If the recieved value is not in the range specified + * by the Specification then it will be the default value + * configured through cfg + */ + if ((scan_params->obssScanActiveDwell > + WNI_CFG_OBSS_HT40_SCAN_ACTIVE_DWELL_TIME_STAMIN) && + (scan_params->obssScanActiveDwell < + WNI_CFG_OBSS_HT40_SCAN_ACTIVE_DWELL_TIME_STAMAX)) + session->obss_ht40_scanparam.obss_active_dwelltime = + scan_params->obssScanActiveDwell; + + if ((scan_params->obssScanPassiveDwell > + WNI_CFG_OBSS_HT40_SCAN_PASSIVE_DWELL_TIME_STAMIN) && + (scan_params->obssScanPassiveDwell < + WNI_CFG_OBSS_HT40_SCAN_PASSIVE_DWELL_TIME_STAMAX)) + session->obss_ht40_scanparam.obss_active_dwelltime = + scan_params->obssScanPassiveDwell; + + if ((scan_params->bssWidthChannelTransitionDelayFactor > + WNI_CFG_OBSS_HT40_WIDTH_CH_TRANSITION_DELAY_STAMIN) && + (scan_params->bssWidthChannelTransitionDelayFactor < + WNI_CFG_OBSS_HT40_WIDTH_CH_TRANSITION_DELAY_STAMAX)) + session->obss_ht40_scanparam.bsswidth_ch_trans_delay = + scan_params->bssWidthChannelTransitionDelayFactor; + + if ((scan_params->obssScanActiveTotalPerChannel > + WNI_CFG_OBSS_HT40_SCAN_ACTIVE_TOTAL_PER_CHANNEL_STAMIN) && + (scan_params->obssScanActiveTotalPerChannel < + WNI_CFG_OBSS_HT40_SCAN_ACTIVE_TOTAL_PER_CHANNEL_STAMAX)) + session->obss_ht40_scanparam.obss_active_total_per_channel = + scan_params->obssScanActiveTotalPerChannel; + + if ((scan_params->obssScanPassiveTotalPerChannel > + WNI_CFG_OBSS_HT40_SCAN_PASSIVE_TOTAL_PER_CHANNEL_STAMIN) && + (scan_params->obssScanPassiveTotalPerChannel < + WNI_CFG_OBSS_HT40_SCAN_PASSIVE_TOTAL_PER_CHANNEL_STAMAX)) + session->obss_ht40_scanparam.obss_passive_total_per_channel = + scan_params->obssScanPassiveTotalPerChannel; + + if ((scan_params->bssChannelWidthTriggerScanInterval > + WNI_CFG_OBSS_HT40_SCAN_WIDTH_TRIGGER_INTERVAL_STAMIN) && + (scan_params->bssChannelWidthTriggerScanInterval < + WNI_CFG_OBSS_HT40_SCAN_WIDTH_TRIGGER_INTERVAL_STAMAX)) + session->obss_ht40_scanparam.obss_width_trigger_interval = + scan_params->bssChannelWidthTriggerScanInterval; + + if ((scan_params->obssScanActivityThreshold > + WNI_CFG_OBSS_HT40_SCAN_ACTIVITY_THRESHOLD_STAMIN) && + (scan_params->obssScanActivityThreshold < + WNI_CFG_OBSS_HT40_SCAN_ACTIVITY_THRESHOLD_STAMAX)) + session->obss_ht40_scanparam.obss_activity_threshold = + scan_params->obssScanActivityThreshold; + return; +} + +/** + * lim_is_robust_mgmt_action_frame() - Check if action category is + * robust action frame + * @action_category: Action frame category. + * + * This function is used to check if given action category is robust + * action frame. + * + * Return: bool + */ +bool lim_is_robust_mgmt_action_frame(uint8_t action_category) +{ + switch (action_category) { + /* + * NOTE: This function doesn't take care of the DMG + * (Directional Multi-Gigatbit) BSS case as 8011ad + * support is not yet added. In future, if the support + * is required then this function need few more arguments + * and little change in logic. + */ + case SIR_MAC_ACTION_SPECTRUM_MGMT: + case SIR_MAC_ACTION_QOS_MGMT: + case SIR_MAC_ACTION_DLP: + case SIR_MAC_ACTION_BLKACK: + case SIR_MAC_ACTION_RRM: + case SIR_MAC_ACTION_FAST_BSS_TRNST: + case SIR_MAC_ACTION_SA_QUERY: + case SIR_MAC_ACTION_PROT_DUAL_PUB: + case SIR_MAC_ACTION_WNM: + case SIR_MAC_ACITON_MESH: + case SIR_MAC_ACTION_MHF: + case SIR_MAC_ACTION_FST: + return true; + default: + QDF_TRACE(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_INFO, + FL("non-PMF action category[%d] "), + action_category); + break; + } + return false; +} + +/** + * lim_compute_ext_cap_ie_length - compute the length of ext cap ie + * based on the bits set + * @ext_cap: extended IEs structure + * + * Return: length of the ext cap ie, 0 means should not present + */ +uint8_t lim_compute_ext_cap_ie_length(tDot11fIEExtCap *ext_cap) +{ + uint8_t i = DOT11F_IE_EXTCAP_MAX_LEN; + + while (i) { + if (ext_cap->bytes[i-1]) + break; + i--; + } + + return i; +} + +/** + * lim_update_caps_info_for_bss - Update capability info for this BSS + * + * @mac_ctx: mac context + * @caps: Pointer to capability info to be updated + * @bss_caps: Capability info of the BSS + * + * Update the capability info in Assoc/Reassoc request frames and reset + * the spectrum management, short preamble, immediate block ack bits + * if the BSS doesnot support it + * + * Return: None + */ +void lim_update_caps_info_for_bss(tpAniSirGlobal mac_ctx, + uint16_t *caps, uint16_t bss_caps) +{ + if (!(bss_caps & LIM_SPECTRUM_MANAGEMENT_BIT_MASK)) { + *caps &= (~LIM_SPECTRUM_MANAGEMENT_BIT_MASK); + lim_log(mac_ctx, LOG1, FL("Clearing spectrum management:no AP support")); + } + + if (!(bss_caps & LIM_SHORT_PREAMBLE_BIT_MASK)) { + *caps &= (~LIM_SHORT_PREAMBLE_BIT_MASK); + lim_log(mac_ctx, LOG1, FL("Clearing short preamble:no AP support")); + } + + if (!(bss_caps & LIM_IMMEDIATE_BLOCK_ACK_MASK)) { + *caps &= (~LIM_IMMEDIATE_BLOCK_ACK_MASK); + lim_log(mac_ctx, LOG1, FL("Clearing Immed Blk Ack:no AP support")); + } +} +/** + * lim_send_set_dtim_period(): Send SIR_HAL_SET_DTIM_PERIOD message + * to set dtim period. + * + * @sesssion: LIM session + * @dtim_period: dtim value + * @mac_ctx: Mac context + * @return None + */ +void lim_send_set_dtim_period(tpAniSirGlobal mac_ctx, uint8_t dtim_period, + tpPESession session) +{ + struct set_dtim_params *dtim_params = NULL; + tSirRetStatus ret = eSIR_SUCCESS; + tSirMsgQ msg; + + if (session == NULL) { + lim_log(mac_ctx, LOGE, FL("Inavalid parameters")); + return; + } + dtim_params = qdf_mem_malloc(sizeof(*dtim_params)); + if (NULL == dtim_params) { + lim_log(mac_ctx, LOGP, + FL("Unable to allocate memory")); + return; + } + dtim_params->dtim_period = dtim_period; + dtim_params->session_id = session->smeSessionId; + msg.type = WMA_SET_DTIM_PERIOD; + msg.bodyptr = dtim_params; + msg.bodyval = 0; + lim_log(mac_ctx, LOG1, FL("Post WMA_SET_DTIM_PERIOD to WMA")); + ret = wma_post_ctrl_msg(mac_ctx, &msg); + if (eSIR_SUCCESS != ret) { + lim_log(mac_ctx, LOGE, FL("wma_post_ctrl_msg() failed")); + qdf_mem_free(dtim_params); + } +} + +/** + * lim_is_valid_frame(): validate RX frame using last processed frame details + * to find if it is duplicate frame. + * + * @last_processed_frm: last processed frame pointer. + * @pRxPacketInfo: RX packet. + * + * Frame treat as duplicate: + * if retry bit is set and + * if source address and seq number matches with the last processed frame + * + * Return: false if duplicate frame, else true. + */ +bool lim_is_valid_frame(last_processed_msg *last_processed_frm, + uint8_t *pRxPacketInfo) +{ + uint16_t seq_num; + tpSirMacMgmtHdr pHdr; + + if (!pRxPacketInfo) { + QDF_TRACE(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_ERROR, + FL("Invalid RX frame")); + return false; + } + + pHdr = WMA_GET_RX_MAC_HEADER(pRxPacketInfo); + + if (pHdr->fc.retry == 0) + return true; + + seq_num = (((pHdr->seqControl.seqNumHi << + HIGH_SEQ_NUM_OFFSET) | + pHdr->seqControl.seqNumLo)); + + if (last_processed_frm->seq_num == seq_num && + qdf_mem_cmp(last_processed_frm->sa, pHdr->sa, ETH_ALEN) == 0) { + QDF_TRACE(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_ERROR, + FL("Duplicate frame from "MAC_ADDRESS_STR " Seq Number %d"), + MAC_ADDR_ARRAY(pHdr->sa), seq_num); + return false; + } + return true; +} + +/** + * lim_update_last_processed_frame(): update new processed frame info to cache. + * + * @last_processed_frm: last processed frame pointer. + * @pRxPacketInfo: Successfully processed RX packet. + * + * Return: None. + */ +void lim_update_last_processed_frame(last_processed_msg *last_processed_frm, + uint8_t *pRxPacketInfo) +{ + uint16_t seq_num; + tpSirMacMgmtHdr pHdr; + + if (!pRxPacketInfo) { + QDF_TRACE(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_ERROR, + FL("Invalid RX frame")); + return; + } + + pHdr = WMA_GET_RX_MAC_HEADER(pRxPacketInfo); + seq_num = (((pHdr->seqControl.seqNumHi << + HIGH_SEQ_NUM_OFFSET) | + pHdr->seqControl.seqNumLo)); + + qdf_mem_copy(last_processed_frm->sa, pHdr->sa, ETH_ALEN); + last_processed_frm->seq_num = seq_num; +} + +tCsrRoamSession *lim_get_session_by_macaddr(tpAniSirGlobal mac_ctx, + tSirMacAddr self_mac) +{ + int i = 0; + tCsrRoamSession *session; + + if (!mac_ctx || !self_mac) { + QDF_TRACE(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_ERROR, + FL("Invalid arguments")); + return NULL; + } + + for (i = 0; i < mac_ctx->sme.max_intf_count; i++) { + session = CSR_GET_SESSION(mac_ctx, i); + if (!session) + continue; + else if (!qdf_mem_cmp(&session->selfMacAddr, + self_mac, sizeof(tSirMacAddr))) { + + QDF_TRACE(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_INFO, + FL("session %d exists with mac address " + MAC_ADDRESS_STR), session->sessionId, + MAC_ADDR_ARRAY(self_mac)); + + return session; + } + } + + return NULL; +} + +void lim_decrement_pending_mgmt_count(tpAniSirGlobal mac_ctx) +{ + qdf_spin_lock(&mac_ctx->sys.bbt_mgmt_lock); + if (!mac_ctx->sys.sys_bbt_pending_mgmt_count) { + qdf_spin_unlock(&mac_ctx->sys.bbt_mgmt_lock); + lim_log(mac_ctx, LOGW, + FL("sys_bbt_pending_mgmt_count value is 0")); + return; + } + mac_ctx->sys.sys_bbt_pending_mgmt_count--; + qdf_spin_unlock(&mac_ctx->sys.bbt_mgmt_lock); +} + +QDF_STATUS lim_util_get_type_subtype(void *pkt, uint8_t *type, + uint8_t *subtype) +{ + cds_pkt_t *cds_pkt; + QDF_STATUS status; + tpSirMacMgmtHdr hdr; + uint8_t *rxpktinfor; + + cds_pkt = (cds_pkt_t *) pkt; + if (!cds_pkt) { + pe_err("NULL packet received"); + return QDF_STATUS_E_FAILURE; + } + status = + wma_ds_peek_rx_packet_info(cds_pkt, (void *)&rxpktinfor, false); + if (!QDF_IS_STATUS_SUCCESS(status)) { + pe_err("Failed extract cds packet. status %d", status); + return QDF_STATUS_E_FAILURE; + } + + hdr = WMA_GET_RX_MAC_HEADER(rxpktinfor); + if (hdr->fc.type == SIR_MAC_MGMT_FRAME) { + pe_debug("RxBd: %p mHdr: %p Type: %d Subtype: %d SizesFC: %zu", + rxpktinfor, hdr, hdr->fc.type, hdr->fc.subType, + sizeof(tSirMacFrameCtl)); + *type = hdr->fc.type; + *subtype = hdr->fc.subType; + } else { + pe_err("Not a managment packet type %d", hdr->fc.type); + return QDF_STATUS_E_INVAL; + } + return QDF_STATUS_SUCCESS; +} diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_utils.h b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_utils.h new file mode 100644 index 0000000000000000000000000000000000000000..906c5a3a90b2bc45245129893413aefc1ac61a68 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_utils.h @@ -0,0 +1,711 @@ +/* + * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * This file lim_utils.h contains the utility definitions + * LIM uses. + * Author: Chandra Modumudi + * Date: 02/13/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + */ +#ifndef __LIM_UTILS_H +#define __LIM_UTILS_H + +#include "sir_api.h" +#include "sir_debug.h" +#include "cfg_api.h" + +#include "lim_types.h" +#include "lim_scan_result_utils.h" +#include "lim_timer_utils.h" +#include "lim_trace.h" +typedef enum { + ONE_BYTE = 1, + TWO_BYTE = 2 +} eSizeOfLenField; + +#define LIM_STA_ID_MASK 0x00FF +#define LIM_AID_MASK 0xC000 +#define LIM_SPECTRUM_MANAGEMENT_BIT_MASK 0x0100 +#define LIM_RRM_BIT_MASK 0x1000 +#define LIM_SHORT_PREAMBLE_BIT_MASK 0x0020 +#define LIM_IMMEDIATE_BLOCK_ACK_MASK 0x8000 +#define LIM_MAX_REASSOC_RETRY_LIMIT 2 + +/* classifier ID is coded as 0-3: tsid, 4-5:direction */ +#define LIM_MAKE_CLSID(tsid, dir) (((tsid) & 0x0F) | (((dir) & 0x03) << 4)) + +#define VHT_MCS_3x3_MASK 0x30 +#define VHT_MCS_2x2_MASK 0x0C + +#define CENTER_FREQ_DIFF_160MHz 8 +#define CENTER_FREQ_DIFF_80P80MHz 16 + +#define IS_VHT_NSS_1x1(__mcs_map) ((__mcs_map & 0xFFFC) == 0xFFFC) + +#define MGMT_RX_PACKETS_THRESHOLD 200 + +#ifdef WLAN_FEATURE_11W +typedef union uPmfSaQueryTimerId { + struct { + uint8_t sessionId; + uint16_t peerIdx; + } fields; + uint32_t value; +} tPmfSaQueryTimerId, *tpPmfSaQueryTimerId; +#endif + +typedef struct last_processed_frame { + tSirMacAddr sa; + uint16_t seq_num; +} last_processed_msg; + +/* LIM utility functions */ +bool lim_is_valid_frame(last_processed_msg *last_processed_frm, + uint8_t *pRxPacketInfo); +void lim_update_last_processed_frame(last_processed_msg *last_processed_frm, + uint8_t *pRxPacketInfo); +void limGetBssidFromPkt(tpAniSirGlobal, uint8_t *, uint8_t *, uint32_t *); +char *lim_dot11_reason_str(uint16_t reasonCode); +char *lim_mlm_state_str(tLimMlmStates state); +char *lim_sme_state_str(tLimSmeStates state); +char *lim_msg_str(uint32_t msgType); +char *lim_result_code_str(tSirResultCodes resultCode); +char *lim_dot11_mode_str(tpAniSirGlobal pMac, uint8_t dot11Mode); +void lim_print_mlm_state(tpAniSirGlobal pMac, uint16_t logLevel, + tLimMlmStates state); +void lim_print_sme_state(tpAniSirGlobal pMac, uint16_t logLevel, + tLimSmeStates state); +void lim_print_msg_name(tpAniSirGlobal pMac, uint16_t logLevel, uint32_t msgType); + +extern tSirRetStatus lim_send_set_max_tx_power_req(tpAniSirGlobal pMac, + int8_t txPower, + tpPESession pSessionEntry); +extern uint8_t lim_get_max_tx_power(int8_t regMax, int8_t apTxPower, + uint8_t iniTxPower); +uint8_t lim_is_addr_bc(tSirMacAddr); +uint8_t lim_is_group_addr(tSirMacAddr); + +/* check for type of scan allowed */ +uint8_t lim_active_scan_allowed(tpAniSirGlobal, uint8_t); + +/* AID pool management functions */ +void lim_init_peer_idxpool(tpAniSirGlobal, tpPESession); +uint16_t lim_assign_peer_idx(tpAniSirGlobal, tpPESession); + +void lim_enable_overlap11g_protection(tpAniSirGlobal pMac, + tpUpdateBeaconParams pBeaconParams, + tpSirMacMgmtHdr pMh, + tpPESession psessionEntry); +void lim_update_overlap_sta_param(tpAniSirGlobal pMac, tSirMacAddr bssId, + tpLimProtStaParams pStaParams); +void lim_update_short_preamble(tpAniSirGlobal pMac, tSirMacAddr peerMacAddr, + tpUpdateBeaconParams pBeaconParams, + tpPESession psessionEntry); +void lim_update_short_slot_time(tpAniSirGlobal pMac, tSirMacAddr peerMacAddr, + tpUpdateBeaconParams pBeaconParams, + tpPESession psessionEntry); + +/* + * The below 'product' check tobe removed if 'Association' is + * allowed in IBSS. + */ +void lim_release_peer_idx(tpAniSirGlobal, uint16_t, tpPESession); + +void lim_decide_ap_protection(tpAniSirGlobal pMac, tSirMacAddr peerMacAddr, + tpUpdateBeaconParams pBeaconParams, tpPESession); +void lim_decide_ap_protection_on_delete(tpAniSirGlobal pMac, + tpDphHashNode pStaDs, + tpUpdateBeaconParams pBeaconParams, + tpPESession psessionEntry); + +extern tSirRetStatus lim_update_11a_protection(tpAniSirGlobal pMac, + uint8_t enable, + uint8_t overlap, + tpUpdateBeaconParams pBeaconParams, + tpPESession); +extern tSirRetStatus lim_enable11g_protection(tpAniSirGlobal pMac, + uint8_t enable, + uint8_t overlap, + tpUpdateBeaconParams pBeaconParams, + tpPESession psessionEntry); +extern tSirRetStatus lim_enable_ht_protection_from11g(tpAniSirGlobal pMac, + uint8_t enable, + uint8_t overlap, + tpUpdateBeaconParams + pBeaconParams, + tpPESession psessionEntry); +extern tSirRetStatus lim_enable_ht20_protection(tpAniSirGlobal pMac, + uint8_t enable, uint8_t overlap, + tpUpdateBeaconParams pBeaconParams, + tpPESession sessionEntry); +extern tSirRetStatus lim_enable_ht_non_gf_protection(tpAniSirGlobal pMac, + uint8_t enable, uint8_t overlap, + tpUpdateBeaconParams + pBeaconParams, tpPESession); +extern tSirRetStatus lim_enable_ht_rifs_protection(tpAniSirGlobal pMac, + uint8_t enable, uint8_t overlap, + tpUpdateBeaconParams + pBeaconParams, + tpPESession psessionEntry); +extern tSirRetStatus lim_enable_ht_lsig_txop_protection(tpAniSirGlobal pMac, + uint8_t enable, + uint8_t overlap, + tpUpdateBeaconParams + pBeaconParams, tpPESession); +extern tSirRetStatus lim_enable_short_preamble(tpAniSirGlobal pMac, + uint8_t enable, + tpUpdateBeaconParams pBeaconParams, + tpPESession psessionEntry); +extern tSirRetStatus lim_enable_ht_obss_protection(tpAniSirGlobal pMac, + uint8_t enable, uint8_t overlap, + tpUpdateBeaconParams + pBeaconParams, tpPESession); +void lim_decide_sta_protection(tpAniSirGlobal pMac, + tpSchBeaconStruct pBeaconStruct, + tpUpdateBeaconParams pBeaconParams, + tpPESession psessionEntry); +void lim_decide_sta_protection_on_assoc(tpAniSirGlobal pMac, + tpSchBeaconStruct pBeaconStruct, + tpPESession psessionEntry); +void lim_update_sta_run_time_ht_switch_chnl_params(tpAniSirGlobal pMac, + tDot11fIEHTInfo *pHTInfo, + uint8_t bssIdx, + tpPESession psessionEntry); +/* Print MAC address utility function */ +void lim_print_mac_addr(tpAniSirGlobal, tSirMacAddr, uint8_t); + +/* Deferred Message Queue read/write */ +uint8_t lim_write_deferred_msg_q(tpAniSirGlobal pMac, tpSirMsgQ limMsg); +tSirMsgQ *lim_read_deferred_msg_q(tpAniSirGlobal pMac); +void lim_handle_defer_msg_error(tpAniSirGlobal pMac, tpSirMsgQ pLimMsg); + +/* Deferred Message Queue Reset */ +void lim_reset_deferred_msg_q(tpAniSirGlobal pMac); + +tSirRetStatus lim_sys_process_mmh_msg_api(tpAniSirGlobal, tSirMsgQ *, uint8_t); + +void lim_handle_update_olbc_cache(tpAniSirGlobal pMac); + +uint8_t lim_is_null_ssid(tSirMacSSid *pSsid); + +/* 11h Support */ +void lim_stop_tx_and_switch_channel(tpAniSirGlobal pMac, uint8_t sessionId); +void lim_process_channel_switch_timeout(tpAniSirGlobal); +tSirRetStatus lim_start_channel_switch(tpAniSirGlobal pMac, + tpPESession psessionEntry); +void lim_update_channel_switch(tpAniSirGlobal, tpSirProbeRespBeacon, + tpPESession psessionEntry); +void lim_process_quiet_timeout(tpAniSirGlobal); +void lim_process_quiet_bss_timeout(tpAniSirGlobal); + +void lim_start_quiet_timer(tpAniSirGlobal pMac, uint8_t sessionId); +void lim_switch_primary_channel(tpAniSirGlobal, uint8_t, tpPESession); +void lim_switch_primary_secondary_channel(tpAniSirGlobal pMac, + tpPESession psessionEntry, + uint8_t newChannel, + uint8_t ch_center_freq_seg0, + uint8_t ch_center_freq_seg1, + enum phy_ch_width ch_width); +void limUpdateStaRunTimeHTSwtichChnlParams(tpAniSirGlobal pMac, + tDot11fIEHTInfo *pRcvdHTInfo, + uint8_t bssIdx); +void lim_update_sta_run_time_ht_capability(tpAniSirGlobal pMac, + tDot11fIEHTCaps *pHTCaps); +void lim_update_sta_run_time_ht_info(struct sAniSirGlobal *pMac, + tDot11fIEHTInfo *pRcvdHTInfo, + tpPESession psessionEntry); +void lim_cancel_dot11h_channel_switch(tpAniSirGlobal pMac, + tpPESession psessionEntry); +void lim_cancel_dot11h_quiet(tpAniSirGlobal pMac, tpPESession psessionEntry); +tAniBool lim_is_channel_valid_for_channel_switch(tpAniSirGlobal pMac, + uint8_t channel); +void lim_frame_transmission_control(tpAniSirGlobal pMac, tLimQuietTxMode type, + tLimControlTx mode); +tSirRetStatus lim_restore_pre_channel_switch_state(tpAniSirGlobal pMac, + tpPESession psessionEntry); +tSirRetStatus lim_restore_pre_quiet_state(tpAniSirGlobal pMac, + tpPESession psessionEntry); + +void lim_prepare_for11h_channel_switch(tpAniSirGlobal pMac, + tpPESession psessionEntry); +void lim_switch_channel_cback(tpAniSirGlobal pMac, QDF_STATUS status, + uint32_t *data, tpPESession psessionEntry); + +/** + * lim_get_session_by_macaddr() - api to find session based on MAC + * @mac_ctx: Pointer to global mac structure. + * @self_mac: MAC address. + * + * This function is used to get session for given MAC address. + * + * Return: session pointer if exists, NULL otherwise. + */ +tCsrRoamSession *lim_get_session_by_macaddr(tpAniSirGlobal mac_ctx, + tSirMacAddr self_mac); + +static inline tSirRFBand lim_get_rf_band(uint8_t channel) +{ + if ((channel >= SIR_11A_CHANNEL_BEGIN) && + (channel <= SIR_11A_CHANNEL_END)) + return SIR_BAND_5_GHZ; + + if ((channel >= SIR_11B_CHANNEL_BEGIN) && + (channel <= SIR_11B_CHANNEL_END)) + return SIR_BAND_2_4_GHZ; + + return SIR_BAND_UNKNOWN; +} + +static inline tSirRetStatus +lim_get_mgmt_staid(tpAniSirGlobal pMac, uint16_t *staid, + tpPESession psessionEntry) +{ + if (LIM_IS_AP_ROLE(psessionEntry)) + *staid = 1; + else if (LIM_IS_STA_ROLE(psessionEntry)) + *staid = 0; + else + return eSIR_FAILURE; + + return eSIR_SUCCESS; +} + +static inline uint8_t lim_is_system_in_set_mimops_state(tpAniSirGlobal pMac) +{ + if (pMac->lim.gLimMlmState == eLIM_MLM_WT_SET_MIMOPS_STATE) + return true; + return false; +} + +static inline uint8_t +is_entering_mimo_ps(tSirMacHTMIMOPowerSaveState curState, + tSirMacHTMIMOPowerSaveState newState) +{ + if (curState == eSIR_HT_MIMO_PS_NO_LIMIT && + (newState == eSIR_HT_MIMO_PS_DYNAMIC + || newState == eSIR_HT_MIMO_PS_STATIC)) + return true; + return false; +} + +static inline int lim_select_cb_mode(tDphHashNode *pStaDs, + tpPESession psessionEntry, uint8_t channel, + uint8_t chan_bw) +{ + if (pStaDs->mlmStaContext.vhtCapability && chan_bw) { + if (channel == 36 || channel == 52 || channel == 100 || + channel == 116 || channel == 149) { + return PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_LOW - 1; + } else if (channel == 40 || channel == 56 || channel == 104 || + channel == 120 || channel == 153) { + return PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_LOW - 1; + } else if (channel == 44 || channel == 60 || channel == 108 || + channel == 124 || channel == 157) { + return PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_HIGH - 1; + } else if (channel == 48 || channel == 64 || channel == 112 || + channel == 128 || channel == 161) { + return PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_HIGH - 1; + } else if (channel == 165) { + return PHY_SINGLE_CHANNEL_CENTERED; + } + } else if (pStaDs->mlmStaContext.htCapability) { + if (channel == 40 || channel == 48 || channel == 56 || + channel == 64 || channel == 104 || channel == 112 || + channel == 120 || channel == 128 || channel == 136 || + channel == 144 || channel == 153 || channel == 161) { + return PHY_DOUBLE_CHANNEL_LOW_PRIMARY; + } else if (channel == 36 || channel == 44 || channel == 52 || + channel == 60 || channel == 100 || + channel == 108 || channel == 116 || + channel == 124 || channel == 132 || + channel == 140 || channel == 149 || + channel == 157) { + return PHY_DOUBLE_CHANNEL_HIGH_PRIMARY; + } else if (channel == 165) { + return PHY_SINGLE_CHANNEL_CENTERED; + } + } + return PHY_SINGLE_CHANNEL_CENTERED; +} + +/* ANI peer station count management and associated actions */ +void lim_util_count_sta_add(tpAniSirGlobal pMac, tpDphHashNode pSta, + tpPESession psessionEntry); +void lim_util_count_sta_del(tpAniSirGlobal pMac, tpDphHashNode pSta, + tpPESession psessionEntry); + +uint8_t lim_get_ht_capability(tpAniSirGlobal, uint32_t, tpPESession); +void lim_tx_complete(tHalHandle hHal, void *pData, bool free); + +/** + * This function will be registered with HAL for callback when TSPEC inactivity + * timer fires. + */ + +void lim_process_del_ts_ind(tpAniSirGlobal pMac, tpSirMsgQ limMsg); +tSirRetStatus lim_process_hal_ind_messages(tpAniSirGlobal pMac, uint32_t mesgId, + void *mesgParam); +tSirRetStatus lim_validate_delts_req(tpAniSirGlobal pMac, + tpSirDeltsReq pDeltsReq, + tSirMacAddr peerMacAddr, + tpPESession psessionEntry); + +/* callback function registration to HAL for any indication. */ +void lim_register_hal_ind_call_back(tpAniSirGlobal pMac); +void lim_pkt_free(tpAniSirGlobal pMac, + eFrameType frmType, uint8_t *pBD, void *body); + +void lim_get_b_dfrom_rx_packet(tpAniSirGlobal pMac, void *body, uint32_t **pBD); + +/** + * utils_power_xy() - calc result of base raised to power + * @base: Base value + * @power: Base raised to this Power value + * + * Given a base(X) and power(Y), this API will return + * the result of base raised to power - (X ^ Y) + * + * Return: Result of X^Y + * + */ +static inline uint32_t utils_power_xy(uint16_t base, uint16_t power) +{ + uint32_t result = 1, i; + + for (i = 0; i < power; i++) + result *= base; + + return result; +} + +tSirRetStatus lim_post_sm_state_update(tpAniSirGlobal pMac, + uint16_t StaIdx, + tSirMacHTMIMOPowerSaveState MIMOPSState, + uint8_t *pPeerStaMac, uint8_t sessionId); + +void lim_delete_sta_context(tpAniSirGlobal pMac, tpSirMsgQ limMsg); +void lim_delete_dialogue_token_list(tpAniSirGlobal pMac); +void lim_resset_scan_channel_info(tpAniSirGlobal pMac); +uint8_t lim_get_channel_from_beacon(tpAniSirGlobal pMac, + tpSchBeaconStruct pBeacon); +tSirNwType lim_get_nw_type(tpAniSirGlobal pMac, uint8_t channelNum, + uint32_t type, tpSchBeaconStruct pBeacon); + +void lim_set_tspec_uapsd_mask_per_session(tpAniSirGlobal pMac, + tpPESession psessionEntry, + tSirMacTSInfo *pTsInfo, uint32_t action); + +void lim_handle_heart_beat_timeout_for_session(tpAniSirGlobal pMac, + tpPESession psessionEntry); + +void lim_process_add_sta_rsp(tpAniSirGlobal pMac, tpSirMsgQ pMsgQ); + +void lim_update_beacon(tpAniSirGlobal pMac); + +void lim_process_ap_mlm_add_sta_rsp(tpAniSirGlobal pMac, tpSirMsgQ limMsgQ, + tpPESession psessionEntry); +void lim_process_ap_mlm_del_bss_rsp(tpAniSirGlobal pMac, + tpSirMsgQ limMsgQ, + tpPESession psessionEntry); + +void lim_process_ap_mlm_del_sta_rsp(tpAniSirGlobal pMac, + tpSirMsgQ limMsgQ, + tpPESession psessionEntry); + +tpPESession lim_is_ibss_session_active(tpAniSirGlobal pMac); +tpPESession lim_is_ap_session_active(tpAniSirGlobal pMac); +void lim_handle_heart_beat_failure_timeout(tpAniSirGlobal pMac); + +uint8_t *lim_get_ie_ptr_new(tpAniSirGlobal pMac, uint8_t *pIes, int length, + uint8_t eid, eSizeOfLenField size_of_len_field); + +#define limGetWscIEPtr(pMac, ie, ie_len) \ + cfg_get_vendor_ie_ptr_from_oui(pMac, SIR_MAC_WSC_OUI, \ + SIR_MAC_WSC_OUI_SIZE, ie, ie_len) + +#define limGetP2pIEPtr(pMac, ie, ie_len) \ + cfg_get_vendor_ie_ptr_from_oui(pMac, SIR_MAC_P2P_OUI, \ + SIR_MAC_P2P_OUI_SIZE, ie, ie_len) + +uint8_t lim_get_noa_attr_stream_in_mult_p2p_ies(tpAniSirGlobal pMac, + uint8_t *noaStream, uint8_t noaLen, + uint8_t overFlowLen); +uint8_t lim_get_noa_attr_stream(tpAniSirGlobal pMac, uint8_t *pNoaStream, + tpPESession psessionEntry); + +uint8_t lim_build_p2p_ie(tpAniSirGlobal pMac, uint8_t *ie, uint8_t *data, + uint8_t ie_len); +bool lim_is_noa_insert_reqd(tpAniSirGlobal pMac); +bool lim_isconnected_on_dfs_channel(uint8_t currentChannel); +uint8_t lim_get_current_operating_channel(tpAniSirGlobal pMac); +uint32_t lim_get_max_rate_flags(tpAniSirGlobal mac_ctx, tpDphHashNode sta_ds); + +bool lim_check_vht_op_mode_change(tpAniSirGlobal pMac, + tpPESession psessionEntry, + uint8_t chanWidth, uint8_t dot11_mode, + uint8_t staId, uint8_t *peerMac); +bool lim_set_nss_change(tpAniSirGlobal pMac, tpPESession psessionEntry, + uint8_t rxNss, uint8_t staId, uint8_t *peerMac); +bool lim_check_membership_user_position(tpAniSirGlobal pMac, + tpPESession psessionEntry, + uint32_t membership, uint32_t userPosition, + uint8_t staId); + +/** + * enum ack_status - Indicate TX status of ASSOC/AUTH + * @ACKED : Ack is received. + * @NOT_ACKED : No Ack received. + * @SENT_FAIL : Failure while sending. + * + * Indicate if driver is waiting for ACK status of assoc/auth or ACK received + * for ASSOC/AUTH OR NO ACK is received for the assoc/auth sent or assoc/auth + * sent failed. + */ +enum assoc_ack_status { + ACKED, + NOT_ACKED, + SENT_FAIL, +}; + +typedef enum { + WLAN_PE_DIAG_SCAN_REQ_EVENT = 0, + WLAN_PE_DIAG_SCAN_ABORT_IND_EVENT, + WLAN_PE_DIAG_SCAN_RSP_EVENT, + WLAN_PE_DIAG_JOIN_REQ_EVENT, + WLAN_PE_DIAG_JOIN_RSP_EVENT, + WLAN_PE_DIAG_SETCONTEXT_REQ_EVENT, + WLAN_PE_DIAG_SETCONTEXT_RSP_EVENT, + WLAN_PE_DIAG_REASSOC_REQ_EVENT, + WLAN_PE_DIAG_REASSOC_RSP_EVENT, + WLAN_PE_DIAG_AUTH_REQ_EVENT, + WLAN_PE_DIAG_AUTH_RSP_EVENT = 10, + WLAN_PE_DIAG_DISASSOC_REQ_EVENT, + WLAN_PE_DIAG_DISASSOC_RSP_EVENT, + WLAN_PE_DIAG_DISASSOC_IND_EVENT, + WLAN_PE_DIAG_DISASSOC_CNF_EVENT, + WLAN_PE_DIAG_DEAUTH_REQ_EVENT, + WLAN_PE_DIAG_DEAUTH_RSP_EVENT, + WLAN_PE_DIAG_DEAUTH_IND_EVENT, + WLAN_PE_DIAG_START_BSS_REQ_EVENT, + WLAN_PE_DIAG_START_BSS_RSP_EVENT, + WLAN_PE_DIAG_AUTH_IND_EVENT = 20, + WLAN_PE_DIAG_ASSOC_IND_EVENT, + WLAN_PE_DIAG_ASSOC_CNF_EVENT, + WLAN_PE_DIAG_REASSOC_IND_EVENT, + WLAN_PE_DIAG_SWITCH_CHL_IND_EVENT, + WLAN_PE_DIAG_SWITCH_CHL_RSP_EVENT, + WLAN_PE_DIAG_STOP_BSS_REQ_EVENT, + WLAN_PE_DIAG_STOP_BSS_RSP_EVENT, + WLAN_PE_DIAG_DEAUTH_CNF_EVENT, + WLAN_PE_DIAG_ADDTS_REQ_EVENT, + WLAN_PE_DIAG_ADDTS_RSP_EVENT = 30, + WLAN_PE_DIAG_DELTS_REQ_EVENT , + WLAN_PE_DIAG_DELTS_RSP_EVENT, + WLAN_PE_DIAG_DELTS_IND_EVENT, + WLAN_PE_DIAG_ENTER_BMPS_REQ_EVENT, + WLAN_PE_DIAG_ENTER_BMPS_RSP_EVENT, + WLAN_PE_DIAG_EXIT_BMPS_REQ_EVENT, + WLAN_PE_DIAG_EXIT_BMPS_RSP_EVENT, + WLAN_PE_DIAG_EXIT_BMPS_IND_EVENT, + WLAN_PE_DIAG_ENTER_IMPS_REQ_EVENT, + WLAN_PE_DIAG_ENTER_IMPS_RSP_EVENT = 40, + WLAN_PE_DIAG_EXIT_IMPS_REQ_EVENT, + WLAN_PE_DIAG_EXIT_IMPS_RSP_EVENT, + WLAN_PE_DIAG_ENTER_UAPSD_REQ_EVENT, + WLAN_PE_DIAG_ENTER_UAPSD_RSP_EVENT, + WLAN_PE_DIAG_EXIT_UAPSD_REQ_EVENT , + WLAN_PE_DIAG_EXIT_UAPSD_RSP_EVENT, + WLAN_PE_DIAG_WOWL_ADD_BCAST_PTRN_EVENT, + WLAN_PE_DIAG_WOWL_DEL_BCAST_PTRN_EVENT, + WLAN_PE_DIAG_ENTER_WOWL_REQ_EVENT, + WLAN_PE_DIAG_ENTER_WOWL_RSP_EVENT = 50, + WLAN_PE_DIAG_EXIT_WOWL_REQ_EVENT, + WLAN_PE_DIAG_EXIT_WOWL_RSP_EVENT, + WLAN_PE_DIAG_HAL_ADDBA_REQ_EVENT, + WLAN_PE_DIAG_HAL_ADDBA_RSP_EVENT, + WLAN_PE_DIAG_HAL_DELBA_IND_EVENT, + WLAN_PE_DIAG_HB_FAILURE_TIMEOUT, + WLAN_PE_DIAG_PRE_AUTH_REQ_EVENT, + WLAN_PE_DIAG_PRE_AUTH_RSP_EVENT, + WLAN_PE_DIAG_PREAUTH_DONE, + WLAN_PE_DIAG_REASSOCIATING = 60, + WLAN_PE_DIAG_CONNECTED, + WLAN_PE_DIAG_ASSOC_REQ_EVENT, + WLAN_PE_DIAG_AUTH_COMP_EVENT, + WLAN_PE_DIAG_ASSOC_COMP_EVENT, + WLAN_PE_DIAG_AUTH_START_EVENT, + WLAN_PE_DIAG_ASSOC_START_EVENT, + WLAN_PE_DIAG_REASSOC_START_EVENT, + WLAN_PE_DIAG_ROAM_AUTH_START_EVENT, + WLAN_PE_DIAG_ROAM_AUTH_COMP_EVENT, + WLAN_PE_DIAG_ROAM_ASSOC_START_EVENT = 70, + WLAN_PE_DIAG_ROAM_ASSOC_COMP_EVENT, + WLAN_PE_DIAG_SCAN_COMPLETE_EVENT, + WLAN_PE_DIAG_SCAN_RESULT_FOUND_EVENT, + WLAN_PE_DIAG_ASSOC_TIMEOUT, + WLAN_PE_DIAG_AUTH_TIMEOUT, + WLAN_PE_DIAG_DEAUTH_FRAME_EVENT, + WLAN_PE_DIAG_DISASSOC_FRAME_EVENT, + WLAN_PE_DIAG_AUTH_ACK_EVENT, + WLAN_PE_DIAG_ASSOC_ACK_EVENT, +} WLAN_PE_DIAG_EVENT_TYPE; + +#ifdef FEATURE_WLAN_DIAG_SUPPORT +void lim_diag_event_report(tpAniSirGlobal pMac, uint16_t eventType, + tpPESession pSessionEntry, uint16_t status, + uint16_t reasonCode); +#else +static inline void lim_diag_event_report(tpAniSirGlobal pMac, uint16_t + eventType, tpPESession pSessionEntry, uint16_t status, + uint16_t reasonCode) {} +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + +void pe_set_resume_channel(tpAniSirGlobal pMac, uint16_t channel, + ePhyChanBondState cbState); + +void lim_get_short_slot_from_phy_mode(tpAniSirGlobal pMac, + tpPESession psessionEntry, + uint32_t phyMode, uint8_t *pShortSlotEnable); + +void lim_clean_up_disassoc_deauth_req(tpAniSirGlobal pMac, uint8_t *staMac, + bool cleanRxPath); + +bool lim_check_disassoc_deauth_ack_pending(tpAniSirGlobal pMac, + uint8_t *staMac); + +#ifdef WLAN_FEATURE_11W +void lim_pmf_sa_query_timer_handler(void *pMacGlobal, uint32_t param); +#endif + +void lim_set_protected_bit(tpAniSirGlobal pMac, + tpPESession psessionEntry, + tSirMacAddr peer, tpSirMacMgmtHdr pMacHdr); + +#ifdef WLAN_FEATURE_11W +void lim_pmf_comeback_timer_callback(void *context); +#endif /* WLAN_FEATURE_11W */ + +void lim_set_ht_caps(tpAniSirGlobal p_mac, + tpPESession p_session_ntry, + uint8_t *p_ie_start, + uint32_t num_bytes); + +void lim_set_vht_caps(tpAniSirGlobal p_mac, + tpPESession p_session_entry, + uint8_t *p_ie_start, + uint32_t num_bytes); +bool lim_validate_received_frame_a1_addr(tpAniSirGlobal mac_ctx, + tSirMacAddr a1, tpPESession session); +void lim_set_stads_rtt_cap(tpDphHashNode sta_ds, struct s_ext_cap *ext_cap, + tpAniSirGlobal mac_ctx); + +void lim_check_and_reset_protection_params(tpAniSirGlobal mac_ctx); + +QDF_STATUS lim_send_ext_cap_ie(tpAniSirGlobal mac_ctx, uint32_t session_id, + tDot11fIEExtCap *extracted_extcap, bool merge); + +QDF_STATUS lim_send_ies_per_band(tpAniSirGlobal mac_ctx, + tpPESession session, uint8_t vdev_id); + +tSirRetStatus lim_strip_extcap_ie(tpAniSirGlobal mac_ctx, uint8_t *addn_ie, + uint16_t *addn_ielen, uint8_t *extracted_extcap); +void lim_update_extcap_struct(tpAniSirGlobal mac_ctx, uint8_t *buf, + tDot11fIEExtCap *ext_cap); +tSirRetStatus lim_strip_extcap_update_struct(tpAniSirGlobal mac_ctx, + uint8_t *addn_ie, uint16_t *addn_ielen, tDot11fIEExtCap *dst); +void lim_merge_extcap_struct(tDot11fIEExtCap *dst, tDot11fIEExtCap *src, + bool add); + +/** + * lim_strip_op_class_update_struct - strip sup op class IE and populate + * the dot11f structure + * @mac_ctx: global MAC context + * @addn_ie: Additional IE buffer + * @addn_ielen: Length of additional IE + * @dst: Supp operating class IE structure to be updated + * + * This function is used to strip supp op class IE from IE buffer and + * update the passed structure. + * + * Return: tSirRetStatus + */ +tSirRetStatus lim_strip_supp_op_class_update_struct(tpAniSirGlobal mac_ctx, + uint8_t *addn_ie, uint16_t *addn_ielen, + tDot11fIESuppOperatingClasses *dst); + +uint8_t lim_get_80Mhz_center_channel(uint8_t primary_channel); +void lim_update_obss_scanparams(tpPESession session, + tDot11fIEOBSSScanParameters *scan_params); +void lim_init_obss_params(tpAniSirGlobal mac_ctx, tpPESession session); +#ifdef WLAN_FEATURE_HOST_ROAM +uint32_t lim_create_timers_host_roam(tpAniSirGlobal mac_ctx); +void lim_delete_timers_host_roam(tpAniSirGlobal mac_ctx); +void lim_deactivate_and_change_timer_host_roam(tpAniSirGlobal mac_ctx, + uint32_t timer_id); +#else +static inline uint32_t lim_create_timers_host_roam(tpAniSirGlobal mac_ctx) +{ + return 0; +} +static inline void lim_delete_timers_host_roam(tpAniSirGlobal mac_ctx) +{} +static inline void lim_deactivate_and_change_timer_host_roam( + tpAniSirGlobal mac_ctx, uint32_t timer_id) +{} +#endif + +bool lim_is_robust_mgmt_action_frame(uint8_t action_category); +uint8_t lim_compute_ext_cap_ie_length(tDot11fIEExtCap *ext_cap); +QDF_STATUS lim_p2p_action_cnf(tpAniSirGlobal mac_ctx, + uint32_t tx_complete_success); +void lim_update_caps_info_for_bss(tpAniSirGlobal mac_ctx, + uint16_t *caps, uint16_t bss_caps); +void lim_send_set_dtim_period(tpAniSirGlobal mac_ctx, uint8_t dtim_period, + tpPESession session); + +tSirRetStatus lim_strip_ie(tpAniSirGlobal mac_ctx, + uint8_t *addn_ie, uint16_t *addn_ielen, + uint8_t eid, eSizeOfLenField size_of_len_field, + uint8_t *oui, uint8_t out_len, uint8_t *extracted_ie, + uint32_t eid_max_len); +/** + * lim_decrement_pending_mgmt_count: Decrement mgmt frame count + * @mac_ctx: Pointer to global MAC structure + * + * This function is used to decrement pe mgmt count once frame + * removed from queue + * + * Return: None + */ +void lim_decrement_pending_mgmt_count(tpAniSirGlobal mac_ctx); +QDF_STATUS lim_util_get_type_subtype(void *pkt, uint8_t *type, + uint8_t *subtype); + +#endif /* __LIM_UTILS_H */ diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/nan/nan_datapath.c b/drivers/staging/qcacld-3.0/core/mac/src/pe/nan/nan_datapath.c new file mode 100644 index 0000000000000000000000000000000000000000..0b1950105b5e0033c023e7aef751a56dcbfb30f6 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/nan/nan_datapath.c @@ -0,0 +1,910 @@ +/* + * Copyright (c) 2016-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * 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. + */ + +/** + * DOC: nan_datapath.c + * + * MAC NAN Data path API implementation + */ + +#include "lim_utils.h" +#include "lim_api.h" +#include "lim_assoc_utils.h" +#include "nan_datapath.h" +#include "lim_types.h" +#include "lim_send_messages.h" +#include "wma_nan_datapath.h" + +/** + * lim_send_ndp_event_to_sme() - generic function to prepare and send NDP + * message to SME. + * @mac_ctx: handle to mac context structure + * @msg_type: sme message type to send + * @body_ptr: buffer + * @len: buffer length + * @body_val: value + * + * Return: None + */ +static void lim_send_ndp_event_to_sme(tpAniSirGlobal mac_ctx, uint32_t msg_type, + void *body_ptr, uint32_t len, uint32_t body_val) +{ + tSirMsgQ mmh_msg = {0}; + + mmh_msg.type = msg_type; + if (len && body_ptr) { + mmh_msg.bodyptr = qdf_mem_malloc(len); + if (NULL == mmh_msg.bodyptr) { + lim_log(mac_ctx, LOGE, FL("Malloc failed")); + return; + } + qdf_mem_copy(mmh_msg.bodyptr, body_ptr, len); + } else { + mmh_msg.bodyval = body_val; + } + lim_sys_process_mmh_msg_api(mac_ctx, &mmh_msg, ePROT); +} + +/** + * lim_add_ndi_peer() - Function to add ndi peer + * @mac_ctx: handle to mac structure + * @vdev_id: vdev id on which peer is added + * @peer_mac_addr: peer to be added + * + * Return: QDF_STATUS_SUCCESS on success; error number otherwise + */ +static QDF_STATUS lim_add_ndi_peer(tpAniSirGlobal mac_ctx, + uint32_t vdev_id, struct qdf_mac_addr peer_mac_addr) +{ + tpPESession session; + tpDphHashNode sta_ds; + uint16_t assoc_id, peer_idx; + tSirRetStatus status; + + session = pe_find_session_by_sme_session_id(mac_ctx, + vdev_id); + if (session == NULL) { + /* couldn't find session */ + return QDF_STATUS_E_FAILURE; + } + sta_ds = dph_lookup_hash_entry(mac_ctx, + peer_mac_addr.bytes, + &assoc_id, &session->dph.dphHashTable); + /* peer exists, don't do anything */ + if (sta_ds != NULL) { + lim_log(mac_ctx, LOGE, FL("NDI Peer already exists!!")); + return QDF_STATUS_SUCCESS; + } + lim_log(mac_ctx, LOG1, + FL("Need to create NDI Peer :" MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(peer_mac_addr.bytes)); + peer_idx = lim_assign_peer_idx(mac_ctx, session); + sta_ds = dph_add_hash_entry(mac_ctx, peer_mac_addr.bytes, peer_idx, + &session->dph.dphHashTable); + if (sta_ds == NULL) { + lim_log(mac_ctx, LOGE, + FL("Couldn't add dph entry")); + /* couldn't add dph entry */ + return QDF_STATUS_E_FAILURE; + } + /* wma decides NDI mode from wma->inferface struct */ + sta_ds->staType = STA_ENTRY_NDI_PEER; + status = lim_add_sta(mac_ctx, sta_ds, false, session); + if (eSIR_SUCCESS != status) { + /* couldn't add peer */ + lim_log(mac_ctx, LOGE, + FL("limAddSta failed status: %d"), + status); + return QDF_STATUS_E_FAILURE; + } + return QDF_STATUS_SUCCESS; +} + +/** + * lim_handle_ndp_indication_event() - Function to handle SIR_HAL_NDP_INDICATION + * event from WMA + * @mac_ctx: handle to mac structure + * @ndp_ind: ndp indication event params + * + * Return: QDF_STATUS_SUCCESS on success; error number otherwise + */ +static QDF_STATUS lim_handle_ndp_indication_event(tpAniSirGlobal mac_ctx, + struct ndp_indication_event *ndp_ind) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + + lim_log(mac_ctx, LOG1, + FL("role: %d, vdev: %d, csid: %d, peer_mac_addr " + MAC_ADDRESS_STR), + ndp_ind->role, ndp_ind->vdev_id, ndp_ind->ncs_sk_type, + MAC_ADDR_ARRAY(ndp_ind->peer_mac_addr.bytes)); + + if ((ndp_ind->role == NDP_ROLE_INITIATOR) || + ((NDP_ROLE_RESPONDER == ndp_ind->role) && + (NDP_ACCEPT_POLICY_ALL == ndp_ind->policy))) { + status = lim_add_ndi_peer(mac_ctx, ndp_ind->vdev_id, + ndp_ind->peer_mac_addr); + if (QDF_STATUS_SUCCESS != status) { + lim_log(mac_ctx, LOGE, + FL("Couldn't add ndi peer, ndp_role: %d"), + ndp_ind->role); + goto ndp_indication_failed; + } + } + if (NDP_ROLE_RESPONDER == ndp_ind->role) + lim_send_ndp_event_to_sme(mac_ctx, eWNI_SME_NDP_INDICATION, + ndp_ind, sizeof(*ndp_ind), 0); + /* + * With NDP indication if peer does not exists already add_sta is + * executed resulting in new peer else no action is taken. Note that + * new_peer event is not necessary event and should not be sent if case + * anything fails in this function. Rather eWNI_SME_NDP_CONFIRM_IND is + * used to indicate success of final operation and abscence of it can be + * used by service layer to identify failure. + */ +ndp_indication_failed: + /* + * Free config if failure or for NDP_ROLE_INITIATOR role + * As for success responder case this info is sent till HDD + * and will be freed in sme. + */ + if (status != QDF_STATUS_SUCCESS || + NDP_ROLE_INITIATOR == ndp_ind->role) { + qdf_mem_free(ndp_ind->ndp_config.ndp_cfg); + qdf_mem_free(ndp_ind->ndp_info.ndp_app_info); + ndp_ind->ndp_config.ndp_cfg = NULL; + ndp_ind->ndp_info.ndp_app_info = NULL; + } + return status; +} + +/** + * lim_ndp_responder_rsp_handler() - Handler for NDP responder rsp + * @mac_ctx: handle to mac structure + * @ndp_rsp: pointer to rsp message + * @bodyval: value + * + * Return: QDF_STATUS_SUCCESS on success; error number otherwise + */ +static QDF_STATUS lim_ndp_responder_rsp_handler(tpAniSirGlobal mac_ctx, + struct ndp_responder_rsp_event *rsp_ind, uint32_t bodyval) +{ + QDF_STATUS ret_val = QDF_STATUS_SUCCESS; + + if ((NULL == rsp_ind) || bodyval) { + lim_log(mac_ctx, LOGE, + FL("rsp_ind is NULL or bodyval %d"), bodyval); + /* msg to unblock SME, but not send rsp to HDD */ + bodyval = true; + ret_val = QDF_STATUS_E_INVAL; + goto responder_rsp; + } + + if (QDF_STATUS_SUCCESS == rsp_ind->status && + rsp_ind->create_peer == true) { + ret_val = lim_add_ndi_peer(mac_ctx, rsp_ind->vdev_id, + rsp_ind->peer_mac_addr); + if (QDF_STATUS_SUCCESS != ret_val) { + lim_log(mac_ctx, LOGE, + FL("Couldn't add ndi peer")); + rsp_ind->status = QDF_STATUS_E_FAILURE; + } + } + +responder_rsp: + /* send eWNI_SME_NDP_RESPONDER_RSP */ + lim_send_ndp_event_to_sme(mac_ctx, eWNI_SME_NDP_RESPONDER_RSP, + bodyval ? NULL : rsp_ind, + bodyval ? 0 : sizeof(*rsp_ind), bodyval); + return ret_val; +} + +/** + * lim_ndp_delete_peer_by_addr() - Delete NAN data peer, given addr and vdev_id + * @mac_ctx: handle to mac context + * @vdev_id: vdev_id on which peer was added + * @peer_ndi_mac_addr: mac addr of peer + * This function deletes a peer if there was NDP_Confirm with REJECT + * + * Return: None + */ +static +void lim_ndp_delete_peer_by_addr(tpAniSirGlobal mac_ctx, uint8_t vdev_id, + struct qdf_mac_addr peer_ndi_mac_addr) +{ + tpPESession session; + tpDphHashNode sta_ds; + uint16_t peer_idx; + + lim_log(mac_ctx, LOG1, + FL("deleting peer: "MAC_ADDRESS_STR" confirm rejected"), + MAC_ADDR_ARRAY(peer_ndi_mac_addr.bytes)); + + session = pe_find_session_by_sme_session_id(mac_ctx, vdev_id); + if (!session || (session->bssType != eSIR_NDI_MODE)) { + lim_log(mac_ctx, LOGE, + FL("PE session is NULL or non-NDI for sme session %d"), + vdev_id); + return; + } + + sta_ds = dph_lookup_hash_entry(mac_ctx, peer_ndi_mac_addr.bytes, + &peer_idx, &session->dph.dphHashTable); + if (!sta_ds) { + lim_log(mac_ctx, LOGE, FL("Unknown NDI Peer")); + return; + } + if (sta_ds->staType != STA_ENTRY_NDI_PEER) { + lim_log(mac_ctx, LOGE, FL("Non-NDI Peer ignored")); + return; + } + /* + * Call lim_del_sta() with response required set true. Hence + * DphHashEntry will be deleted after receiving that response. + */ + + lim_del_sta(mac_ctx, sta_ds, true, session); +} + +/** + * lim_ndp_delete_peers() - Delete NAN data peers + * @mac_ctx: handle to mac context + * @ndp_map: NDP instance/peer map + * @num_peers: number of peers entries in peer_map + * This function deletes a peer if there are no active NDPs left with that peer + * + * Return: None + */ +static void lim_ndp_delete_peers(tpAniSirGlobal mac_ctx, + struct peer_ndp_map *ndp_map, uint8_t num_peers) +{ + tpDphHashNode sta_ds = NULL; + uint16_t deleted_num = 0; + int i, j; + tpPESession session; + struct qdf_mac_addr *deleted_peers; + uint16_t peer_idx; + bool found; + + deleted_peers = qdf_mem_malloc(num_peers * sizeof(*deleted_peers)); + if (!deleted_peers) { + lim_log(mac_ctx, LOGE, FL("Memory allocation failed")); + return; + } + + for (i = 0; i < num_peers; i++) { + lim_log(mac_ctx, LOG1, + FL("ndp_map[%d]: MAC: " MAC_ADDRESS_STR " num_active %d"), + i, + MAC_ADDR_ARRAY(ndp_map[i].peer_ndi_mac_addr.bytes), + ndp_map[i].num_active_ndp_sessions); + + /* Do not delete a peer with active NDPs */ + if (ndp_map[i].num_active_ndp_sessions > 0) + continue; + + session = pe_find_session_by_sme_session_id(mac_ctx, + ndp_map[i].vdev_id); + if (!session || (session->bssType != eSIR_NDI_MODE)) { + lim_log(mac_ctx, LOGE, + FL("PE session is NULL or non-NDI for sme session %d"), + ndp_map[i].vdev_id); + continue; + } + + /* Check if this peer is already in the deleted list */ + found = false; + for (j = 0; j < deleted_num && !found; j++) { + if (!qdf_mem_cmp( + &deleted_peers[j].bytes, + &ndp_map[i].peer_ndi_mac_addr.bytes, + QDF_MAC_ADDR_SIZE)) { + found = true; + break; + } + } + if (found) + continue; + + sta_ds = dph_lookup_hash_entry(mac_ctx, + ndp_map[i].peer_ndi_mac_addr.bytes, + &peer_idx, &session->dph.dphHashTable); + if (!sta_ds) { + lim_log(mac_ctx, LOGE, FL("Unknown NDI Peer")); + continue; + } + if (sta_ds->staType != STA_ENTRY_NDI_PEER) { + lim_log(mac_ctx, LOGE, + FL("Non-NDI Peer ignored")); + continue; + } + /* + * Call lim_del_sta() with response required set true. + * Hence DphHashEntry will be deleted after receiving + * that response. + */ + lim_del_sta(mac_ctx, sta_ds, true, session); + qdf_copy_macaddr(&deleted_peers[deleted_num++], + &ndp_map[i].peer_ndi_mac_addr); + } + qdf_mem_free(deleted_peers); +} + +/** + * lim_ndp_end_indication_handler() - Handler for NDP end indication + * @mac_ctx: handle to mac context + * @ind_buf: pointer to indication buffer + * + * It deletes peers from ndp_map. Response of that operation goes + * to LIM and HDD. But peer information does not go to service layer. + * ndp_id_list is sent to service layer; it is not interpreted by the + * driver. + * + * Return: QDF_STATUS_SUCCESS on success; error number otherwise + */ +static QDF_STATUS lim_ndp_end_indication_handler(tpAniSirGlobal mac_ctx, + uint32_t *ind_buf) +{ + + struct ndp_end_indication_event *ndp_event_buf = + (struct ndp_end_indication_event *)ind_buf; + int buf_size; + + if (!ind_buf) { + lim_log(mac_ctx, LOGE, FL("NDP end indication buffer is NULL")); + return QDF_STATUS_E_INVAL; + } + lim_ndp_delete_peers(mac_ctx, ndp_event_buf->ndp_map, + ndp_event_buf->num_ndp_ids); + + buf_size = sizeof(*ndp_event_buf) + ndp_event_buf->num_ndp_ids * + sizeof(ndp_event_buf->ndp_map[0]); + lim_send_ndp_event_to_sme(mac_ctx, eWNI_SME_NDP_END_IND, + ndp_event_buf, buf_size, false); + + return QDF_STATUS_SUCCESS; +} + +/** + * lim_process_ndi_del_sta_rsp() - Handle WDA_DELETE_STA_RSP in eLIM_NDI_ROLE + * @mac_ctx: Global MAC context + * @lim_msg: LIM message + * @pe_session: PE session + * + * Return: None + */ +void lim_process_ndi_del_sta_rsp(tpAniSirGlobal mac_ctx, tpSirMsgQ lim_msg, + tpPESession pe_session) +{ + tpDeleteStaParams del_sta_params = (tpDeleteStaParams) lim_msg->bodyptr; + tpDphHashNode sta_ds; + tSirResultCodes status = eSIR_SME_SUCCESS; + struct sme_ndp_peer_ind peer_ind; + + if (!del_sta_params) { + lim_log(mac_ctx, LOGE, + FL("del_sta_params is NULL")); + return; + } + if (!LIM_IS_NDI_ROLE(pe_session)) { + lim_log(mac_ctx, LOGE, + FL("Session %d is not NDI role"), del_sta_params->assocId); + status = eSIR_SME_REFUSED; + goto skip_event; + } + + sta_ds = dph_get_hash_entry(mac_ctx, del_sta_params->assocId, + &pe_session->dph.dphHashTable); + if (!sta_ds) { + lim_log(mac_ctx, LOGE, + FL("DPH Entry for STA %X is missing."), + del_sta_params->assocId); + status = eSIR_SME_REFUSED; + goto skip_event; + } + + if (QDF_STATUS_SUCCESS != del_sta_params->status) { + lim_log(mac_ctx, LOGE, FL("DEL STA failed!")); + status = eSIR_SME_REFUSED; + goto skip_event; + } + lim_log(mac_ctx, LOG1, + FL("Deleted STA AssocID %d staId %d MAC " MAC_ADDRESS_STR), + sta_ds->assocId, sta_ds->staIndex, + MAC_ADDR_ARRAY(sta_ds->staAddr)); + + /* + * Copy peer info in del peer indication before + * lim_delete_dph_hash_entry is called as this will be lost. + */ + peer_ind.msg_len = sizeof(peer_ind); + peer_ind.msg_type = eWNI_SME_NDP_PEER_DEPARTED_IND; + peer_ind.session_id = pe_session->smeSessionId; + peer_ind.sta_id = sta_ds->staIndex; + qdf_mem_copy(&peer_ind.peer_mac_addr.bytes, + sta_ds->staAddr, sizeof(tSirMacAddr)); + + lim_release_peer_idx(mac_ctx, sta_ds->assocId, pe_session); + lim_delete_dph_hash_entry(mac_ctx, sta_ds->staAddr, sta_ds->assocId, + pe_session); + pe_session->limMlmState = eLIM_MLM_IDLE_STATE; + + lim_send_ndp_event_to_sme(mac_ctx, eWNI_SME_NDP_PEER_DEPARTED_IND, + &peer_ind, sizeof(peer_ind), false); + +skip_event: + qdf_mem_free(del_sta_params); + lim_msg->bodyptr = NULL; +} + +/** + * lim_handle_ndp_event_message() - Handler for NDP events/RSP from WMA + * @mac_ctx: handle to mac structure + * @msg: pointer to message + * + * Return: QDF_STATUS_SUCCESS on success; error number otherwise + */ +QDF_STATUS lim_handle_ndp_event_message(tpAniSirGlobal mac_ctx, cds_msg_t *msg) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + + switch (msg->type) { + case SIR_HAL_NDP_CONFIRM: { + struct ndp_confirm_event *ndp_confirm = msg->bodyptr; + if (ndp_confirm->rsp_code != NDP_RESPONSE_ACCEPT && + ndp_confirm->num_active_ndps_on_peer == 0) { + /* + * This peer was created at ndp_indication but + * ndp_confirm failed, so it needs to be deleted + */ + lim_log(mac_ctx, LOGE, + FL("NDP confirm with reject and no active ndp sessions. deleting peer: "MAC_ADDRESS_STR" on vdev_id: %d"), + MAC_ADDR_ARRAY( + ndp_confirm->peer_ndi_mac_addr.bytes), + ndp_confirm->vdev_id); + lim_ndp_delete_peer_by_addr(mac_ctx, + ndp_confirm->vdev_id, + ndp_confirm->peer_ndi_mac_addr); + } + lim_send_ndp_event_to_sme(mac_ctx, eWNI_SME_NDP_CONFIRM_IND, + msg->bodyptr, sizeof(*ndp_confirm), + msg->bodyval); + break; + } + case SIR_HAL_NDP_INITIATOR_RSP: + lim_send_ndp_event_to_sme(mac_ctx, eWNI_SME_NDP_INITIATOR_RSP, + msg->bodyptr, sizeof(struct ndp_initiator_rsp), + msg->bodyval); + break; + case SIR_HAL_NDP_INDICATION: { + struct ndp_indication_event *ndp_ind = msg->bodyptr; + status = lim_handle_ndp_indication_event(mac_ctx, ndp_ind); + break; + } + case SIR_HAL_NDP_RESPONDER_RSP: + status = lim_ndp_responder_rsp_handler(mac_ctx, msg->bodyptr, + msg->bodyval); + break; + case SIR_HAL_NDP_END_RSP: { + lim_send_ndp_event_to_sme(mac_ctx, eWNI_SME_NDP_END_RSP, + msg->bodyptr, + sizeof(struct ndp_end_rsp_event), + msg->bodyval); + break; + } + case SIR_HAL_NDP_END_IND: + status = lim_ndp_end_indication_handler(mac_ctx, msg->bodyptr); + break; + default: + lim_log(mac_ctx, LOGE, + FL("Unhandled NDP event: %d"), msg->type); + status = QDF_STATUS_E_NOSUPPORT; + break; + } + /* + * No need to free body pointer, since the function is serving purpose + * of callback and bodyptr if allocated is freed by caller itself + */ + return status; +} + +/** + * lim_process_sme_ndp_initiator_req() - Handler for eWNI_SME_NDP_INITIATOR_REQ + * from SME. + * @mac_ctx: handle to mac structure + * @ndp_msg: ndp initiator request msg + * + * Return: Status of operation + */ +static QDF_STATUS lim_process_sme_ndp_initiator_req(tpAniSirGlobal mac_ctx, + void *ndp_msg) +{ + tSirMsgQ msg; + QDF_STATUS status; + + struct sir_sme_ndp_initiator_req *sme_req = + (struct sir_sme_ndp_initiator_req *)ndp_msg; + struct ndp_initiator_req *wma_req; + + if (NULL == ndp_msg) { + lim_log(mac_ctx, LOGE, FL("invalid ndp_req")); + status = QDF_STATUS_E_INVAL; + goto send_initiator_rsp; + } + wma_req = qdf_mem_malloc(sizeof(*wma_req)); + if (wma_req == NULL) { + lim_log(mac_ctx, LOGE, FL("malloc failed")); + status = QDF_STATUS_E_NOMEM; + goto send_initiator_rsp; + } + + qdf_mem_copy(wma_req, &sme_req->req, sizeof(*wma_req)); + msg.type = SIR_HAL_NDP_INITIATOR_REQ; + msg.reserved = 0; + msg.bodyptr = wma_req; + msg.bodyval = 0; + + lim_log(mac_ctx, LOG1, FL("sending WDA_NDP_INITIATOR_REQ to WMA")); + MTRACE(mac_trace_msg_tx(mac_ctx, NO_SESSION, msg.type)); + + if (eSIR_SUCCESS != wma_post_ctrl_msg(mac_ctx, &msg)) + lim_log(mac_ctx, LOGP, FL("wma_post_ctrl_msg failed")); + + return QDF_STATUS_SUCCESS; +send_initiator_rsp: + /* msg to unblock SME, but not send rsp to HDD */ + lim_send_ndp_event_to_sme(mac_ctx, eWNI_SME_NDP_INITIATOR_RSP, + NULL, 0, true); + return status; +} + +/** + * lim_process_sme_ndp_responder_req() - Handler for NDP responder req + * @mac_ctx: handle to mac structure + * @ndp_msg: pointer to message + * + * Return: QDF_STATUS_SUCCESS on success or failure code in case of failure + */ +static QDF_STATUS lim_process_sme_ndp_responder_req(tpAniSirGlobal mac_ctx, + struct sir_sme_ndp_responder_req *lim_msg) +{ + tSirMsgQ msg; + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct ndp_responder_req *responder_req; + + if (NULL == lim_msg) { + lim_log(mac_ctx, LOGE, FL("ndp_msg is NULL")); + status = QDF_STATUS_E_INVAL; + goto send_failure_rsp; + } + responder_req = qdf_mem_malloc(sizeof(*responder_req)); + if (NULL == responder_req) { + lim_log(mac_ctx, LOGE, + FL("Unable to allocate memory for responder_req")); + status = QDF_STATUS_E_NOMEM; + goto send_failure_rsp; + } + qdf_mem_copy(responder_req, &lim_msg->req, sizeof(*responder_req)); + msg.type = SIR_HAL_NDP_RESPONDER_REQ; + msg.reserved = 0; + msg.bodyptr = responder_req; + msg.bodyval = 0; + + lim_log(mac_ctx, LOG1, FL("sending SIR_HAL_NDP_RESPONDER_REQ to WMA")); + MTRACE(mac_trace_msg_tx(mac_ctx, NO_SESSION, msg.type)); + + if (eSIR_SUCCESS != wma_post_ctrl_msg(mac_ctx, &msg)) { + lim_log(mac_ctx, LOGP, FL("wma_post_ctrl_msg failed")); + status = QDF_STATUS_E_FAILURE; + qdf_mem_free(responder_req); + goto send_failure_rsp; + } + return status; +send_failure_rsp: + /* msg to unblock SME, but not send rsp to HDD */ + lim_send_ndp_event_to_sme(mac_ctx, eWNI_SME_NDP_RESPONDER_RSP, + NULL, 0, true); + return status; +} + +/** + * lim_process_sme_ndp_data_end_req() - Handler for eWNI_SME_NDP_END_REQ + * from SME. + * @mac_ctx: handle to mac context + * @sme_msg: ndp data end request msg + * + * Return: Status of operation + */ +static +QDF_STATUS lim_process_sme_ndp_data_end_req(tpAniSirGlobal mac_ctx, + struct sir_sme_ndp_end_req *sme_msg) +{ + tSirMsgQ msg; + uint32_t len; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + if (NULL == sme_msg) { + lim_log(mac_ctx, LOGE, FL("invalid ndp_req")); + /* msg to unblock SME, but not send rsp to HDD */ + lim_send_ndp_event_to_sme(mac_ctx, eWNI_SME_NDP_END_RSP, NULL, + 0, true); + return QDF_STATUS_E_INVAL; + } + + msg.type = SIR_HAL_NDP_END_REQ; + msg.reserved = 0; + len = sizeof(*sme_msg->req) + (sme_msg->req->num_ndp_instances * + sizeof(uint32_t)); + msg.bodyptr = qdf_mem_malloc(len); + if (NULL == msg.bodyptr) { + /* msg to unblock SME, but not send rsp to HDD */ + lim_send_ndp_event_to_sme(mac_ctx, eWNI_SME_NDP_END_RSP, NULL, + 0, true); + return QDF_STATUS_E_NOMEM; + } + qdf_mem_copy(msg.bodyptr, sme_msg->req, len); + msg.bodyval = 0; + + lim_log(mac_ctx, LOG1, FL("sending SIR_HAL_NDP_END_REQ to WMA")); + MTRACE(mac_trace_msg_tx(mac_ctx, NO_SESSION, msg.type)); + + if (eSIR_SUCCESS != wma_post_ctrl_msg(mac_ctx, &msg)) { + lim_log(mac_ctx, LOGP, FL("wma_post_ctrl_msg failed")); + status = QDF_STATUS_E_FAILURE; + } + + return status; +} + +/** + * lim_handle_ndp_request_message() - Handler for NDP req from SME + * @mac_ctx: handle to mac structure + * @msg: pointer to message + * + * Return: QDF_STATUS_SUCCESS on success; error number otherwise + */ +QDF_STATUS lim_handle_ndp_request_message(tpAniSirGlobal mac_ctx, + tpSirMsgQ msg) +{ + QDF_STATUS status; + + switch (msg->type) { + case eWNI_SME_NDP_END_REQ: + status = lim_process_sme_ndp_data_end_req(mac_ctx, + msg->bodyptr); + break; + case eWNI_SME_NDP_INITIATOR_REQ: + status = lim_process_sme_ndp_initiator_req(mac_ctx, + msg->bodyptr); + break; + case eWNI_SME_NDP_RESPONDER_REQ: + status = lim_process_sme_ndp_responder_req(mac_ctx, + msg->bodyptr); + break; + default: + lim_log(mac_ctx, LOGE, FL("Unhandled NDP request: %d"), + msg->type); + status = QDF_STATUS_E_NOSUPPORT; + break; + } + return status; +} + +/** + * lim_process_ndi_mlm_add_bss_rsp() - Process ADD_BSS response for NDI + * @mac_ctx: Pointer to Global MAC structure + * @lim_msgq: The MsgQ header, which contains the response buffer + * @session_entry: PE session + * + * Return: None + */ +void lim_process_ndi_mlm_add_bss_rsp(tpAniSirGlobal mac_ctx, tpSirMsgQ lim_msgq, + tpPESession session_entry) +{ + tLimMlmStartCnf mlm_start_cnf; + tpAddBssParams add_bss_params = (tpAddBssParams) lim_msgq->bodyptr; + + if (NULL == add_bss_params) { + lim_log(mac_ctx, LOGE, FL("Invalid body pointer in message")); + goto end; + } + lim_log(mac_ctx, LOG1, FL("Status %d"), add_bss_params->status); + if (QDF_STATUS_SUCCESS == add_bss_params->status) { + lim_log(mac_ctx, LOG1, + FL("WDA_ADD_BSS_RSP returned QDF_STATUS_SUCCESS")); + session_entry->limMlmState = eLIM_MLM_BSS_STARTED_STATE; + MTRACE(mac_trace(mac_ctx, TRACE_CODE_MLM_STATE, + session_entry->peSessionId, + session_entry->limMlmState)); + session_entry->bssIdx = (uint8_t) add_bss_params->bssIdx; + session_entry->limSystemRole = eLIM_NDI_ROLE; + session_entry->statypeForBss = STA_ENTRY_SELF; + session_entry->staId = add_bss_params->staContext.staIdx; + /* Apply previously set configuration at HW */ + lim_apply_configuration(mac_ctx, session_entry); + mlm_start_cnf.resultCode = eSIR_SME_SUCCESS; + } else { + lim_log(mac_ctx, LOGE, + FL("WDA_ADD_BSS_REQ failed with status %d"), + add_bss_params->status); + mlm_start_cnf.resultCode = eSIR_SME_HAL_SEND_MESSAGE_FAIL; + } + mlm_start_cnf.sessionId = session_entry->peSessionId; + lim_post_sme_message(mac_ctx, LIM_MLM_START_CNF, + (uint32_t *) &mlm_start_cnf); +end: + qdf_mem_free(lim_msgq->bodyptr); + lim_msgq->bodyptr = NULL; +} + +/** + * lim_ndi_del_bss_rsp() - Handler for DEL BSS resp for NDI interface + * @mac_ctx: handle to mac structure + * @msg: pointer to message + * @session_entry: session entry + * + * Return: None + */ +void lim_ndi_del_bss_rsp(tpAniSirGlobal mac_ctx, + void *msg, tpPESession session_entry) +{ + tSirResultCodes rc = eSIR_SME_SUCCESS; + tpDeleteBssParams del_bss = (tpDeleteBssParams) msg; + + SET_LIM_PROCESS_DEFD_MESGS(mac_ctx, true); + if (del_bss == NULL) { + lim_log(mac_ctx, LOGE, + FL("NDI: DEL_BSS_RSP with no body!")); + rc = eSIR_SME_STOP_BSS_FAILURE; + goto end; + } + session_entry = + pe_find_session_by_session_id(mac_ctx, del_bss->sessionId); + if (!session_entry) { + lim_log(mac_ctx, LOGE, + FL("Session Does not exist for given sessionID")); + goto end; + } + + if (del_bss->status != QDF_STATUS_SUCCESS) { + lim_log(mac_ctx, LOGE, + FL("NDI: DEL_BSS_RSP error (%x) Bss %d "), + del_bss->status, del_bss->bssIdx); + rc = eSIR_SME_STOP_BSS_FAILURE; + goto end; + } + + if (lim_set_link_state(mac_ctx, eSIR_LINK_IDLE_STATE, + session_entry->selfMacAddr, + session_entry->selfMacAddr, NULL, NULL) + != eSIR_SUCCESS) { + lim_log(mac_ctx, LOGE, + FL("NDI: DEL_BSS_RSP setLinkState failed")); + goto end; + } + + session_entry->limMlmState = eLIM_MLM_IDLE_STATE; + +end: + if (del_bss) + qdf_mem_free(del_bss); + /* Delete PE session once BSS is deleted */ + if (NULL != session_entry) { + lim_send_sme_rsp(mac_ctx, eWNI_SME_STOP_BSS_RSP, + rc, session_entry->smeSessionId, + session_entry->transactionId); + pe_delete_session(mac_ctx, session_entry); + session_entry = NULL; + } +} + +/** + * lim_send_sme_ndp_add_sta_rsp() - prepares and send new peer ind to SME + * @mac_ctx: handle to mac structure + * @session: session pointer + * @add_sta_rsp: add sta response struct + * + * Return: status of operation + */ +static QDF_STATUS lim_send_sme_ndp_add_sta_rsp(tpAniSirGlobal mac_ctx, + tpPESession session, + tAddStaParams *add_sta_rsp) +{ + tSirMsgQ mmh_msg = {0}; + struct sme_ndp_peer_ind *new_peer_ind; + + mmh_msg.type = eWNI_SME_NDP_NEW_PEER_IND; + + if (NULL == add_sta_rsp) { + lim_log(mac_ctx, LOGE, FL("Invalid add_sta_rsp")); + return QDF_STATUS_E_INVAL; + } + + new_peer_ind = qdf_mem_malloc(sizeof(*new_peer_ind)); + if (NULL == new_peer_ind) { + lim_log(mac_ctx, LOGE, FL("Failed to allocate memory")); + return QDF_STATUS_E_NOMEM; + } + + /* this message is going to HDD, fill in sme session id */ + new_peer_ind->session_id = add_sta_rsp->smesessionId; + new_peer_ind->msg_len = sizeof(struct sme_ndp_peer_ind); + new_peer_ind->msg_type = eWNI_SME_NDP_NEW_PEER_IND; + qdf_mem_copy(new_peer_ind->peer_mac_addr.bytes, add_sta_rsp->staMac, + sizeof(tSirMacAddr)); + new_peer_ind->sta_id = add_sta_rsp->staIdx; + + mmh_msg.bodyptr = new_peer_ind; + mmh_msg.bodyval = 0; + lim_sys_process_mmh_msg_api(mac_ctx, &mmh_msg, ePROT); + return QDF_STATUS_SUCCESS; +} + +/** + * lim_ndp_add_sta_rsp() - handles add sta rsp for NDP from WMA + * @mac_ctx: handle to mac structure + * @session: session pointer + * @add_sta_rsp: add sta response struct + * + * Return: None + */ +void lim_ndp_add_sta_rsp(tpAniSirGlobal mac_ctx, tpPESession session, + tAddStaParams *add_sta_rsp) +{ + tpDphHashNode sta_ds; + uint16_t peer_idx; + + if (NULL == add_sta_rsp) { + lim_log(mac_ctx, LOGE, FL("Invalid add_sta_rsp")); + qdf_mem_free(add_sta_rsp); + return; + } + + SET_LIM_PROCESS_DEFD_MESGS(mac_ctx, true); + sta_ds = dph_lookup_hash_entry(mac_ctx, add_sta_rsp->staMac, &peer_idx, + &session->dph.dphHashTable); + if (sta_ds == NULL) { + lim_log(mac_ctx, LOGE, + FL("NAN: ADD_STA_RSP for unknown MAC addr " + MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(add_sta_rsp->staMac)); + qdf_mem_free(add_sta_rsp); + return; + } + + if (add_sta_rsp->status != QDF_STATUS_SUCCESS) { + lim_log(mac_ctx, LOGE, + FL("NAN: ADD_STA_RSP error %x for MAC addr: %pM"), + add_sta_rsp->status, add_sta_rsp->staMac); + /* delete the sta_ds allocated during ADD STA */ + lim_delete_dph_hash_entry(mac_ctx, add_sta_rsp->staMac, + peer_idx, session); + qdf_mem_free(add_sta_rsp); + return; + } + sta_ds->bssId = add_sta_rsp->bssIdx; + sta_ds->staIndex = add_sta_rsp->staIdx; + sta_ds->ucUcastSig = add_sta_rsp->ucUcastSig; + sta_ds->ucBcastSig = add_sta_rsp->ucBcastSig; + sta_ds->valid = 1; + sta_ds->mlmStaContext.mlmState = eLIM_MLM_LINK_ESTABLISHED_STATE; + lim_send_sme_ndp_add_sta_rsp(mac_ctx, session, add_sta_rsp); + qdf_mem_free(add_sta_rsp); +} diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/nan/nan_datapath.h b/drivers/staging/qcacld-3.0/core/mac/src/pe/nan/nan_datapath.h new file mode 100644 index 0000000000000000000000000000000000000000..0fbfa2fd2857d90a2c7714edcac6ed2c7123fa34 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/nan/nan_datapath.h @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * 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. + */ + +/** + * DOC: nan_datapath.h + * + * MAC NAN Data path API specification + */ + +#ifndef __MAC_NAN_DATAPATH_H +#define __MAC_NAN_DATAPATH_H + +#ifdef WLAN_FEATURE_NAN_DATAPATH + +#include "sir_common.h" +#include "ani_global.h" +#include "sir_params.h" + +/** + * struct ndp_peer_node - structure for holding per-peer context + * @next: pointer to the next peer + * @peer_mac_addr: peer mac address + * @ext_rates_present: extended rates supported + * @edca_present: edca supported + * @wme_edca_present: WME EDCA supported + * @wme_info_present: WME info supported + * @ht_capable: HT capable + * @vht_capable: VHT capabale + * @ht_sec_chan_offset: HT secondary channel offset + * @capability_info: Generic capability info + * @supported_rates: Supported rates + * @extended_rates: Supported extended rates + * @supported_mcs_rate: Supported MCS rates + * @edca_params: EDCA parameters + * @erp_ie_present: ERP IE supported + * @ht_green_field: HT green field supported + * @ht_shortGI_40Mhz; 40 MHZ short GI support + * @ht_shortGI_20Mhz; 20 MHZ short GI support + * @ht_mimo_ps_state: MIMO power state + * @ht_ampdu_density: AMPDU density + * @ht_max_rxampdu_factor: receieve AMPDU factor + * @ht_max_amsdu_len: Max AMSDU lengh supported + * @ht_supp_chan_widthset: Supported channel widthset + * @ht_ldpc_capable: LDPC capable + * @heartbeat_failure: heart beat failure indication flag + * @vht_caps: VHT capability + * @vht_supp_chanwidth_set: VHT supported channel width + * @vht_beamformer_capable: Beam former capable + */ +struct ndp_peer_node { + struct ndp_peer_node *next; + struct qdf_mac_addr peer_mac_addr; + uint8_t ext_rates_present; + uint8_t edca_present; + uint8_t wme_edca_present; + uint8_t wme_info_present; + uint8_t ht_capable; + uint8_t vht_capable; + uint8_t ht_sec_chan_offset; + tSirMacCapabilityInfo capability_info; + tSirMacRateSet supported_rates; + tSirMacRateSet extended_rates; + uint8_t supported_mcs_rate[SIZE_OF_SUPPORTED_MCS_SET]; + tSirMacEdcaParamSetIE edca_params; + uint8_t erp_ie_present; + uint8_t ht_green_field; + uint8_t ht_shortGI_40Mhz; + uint8_t ht_shortGI_20Mhz; + /* MIMO Power Save */ + tSirMacHTMIMOPowerSaveState ht_mimo_ps_state; + uint8_t ht_ampdu_density; + /* Maximum Rx A-MPDU factor */ + uint8_t ht_max_rxampdu_factor; + uint8_t ht_max_amsdu_len; + uint8_t ht_supp_chan_widthset; + uint8_t ht_ldpc_capable; + uint8_t heartbeat_failure; + +#ifdef WLAN_FEATURE_11AC + tDot11fIEVHTCaps vht_caps; + uint8_t vht_supp_chanwidth_set; + uint8_t vht_beamformer_capable; +#endif +}; + +/* Function to process NDP requests */ +QDF_STATUS lim_handle_ndp_request_message(tpAniSirGlobal mac_ctx, + tpSirMsgQ msg); +/* Function to process NDP events */ +QDF_STATUS lim_handle_ndp_event_message(tpAniSirGlobal mac_ctx, cds_msg_t *msg); +void lim_process_ndi_mlm_add_bss_rsp(tpAniSirGlobal mac_ctx, + tpSirMsgQ lim_msg_q, + tpPESession session_entry); +/* Handler for DEL BSS resp for NDI interface */ +void lim_ndi_del_bss_rsp(tpAniSirGlobal mac_ctx, + void *msg, tpPESession session_entry); + +void lim_ndp_add_sta_rsp(tpAniSirGlobal mac_ctx, tpPESession session_entry, + tAddStaParams *add_sta_rsp); + +void lim_process_ndi_del_sta_rsp(tpAniSirGlobal mac_ctx, tpSirMsgQ lim_msg, + tpPESession pe_session); + +#else + +/* Function to process NDP requests */ +static inline QDF_STATUS lim_handle_ndp_request_message(tpAniSirGlobal mac_ctx, + tpSirMsgQ msg) +{ + return QDF_STATUS_SUCCESS; +} + +/* Function to process NDP events */ +static inline QDF_STATUS lim_handle_ndp_event_message(tpAniSirGlobal mac_ctx, + cds_msg_t *msg) +{ + return QDF_STATUS_SUCCESS; +} + +/* Function to process NDP events */ +static inline void lim_process_ndi_mlm_add_bss_rsp(tpAniSirGlobal mac_ctx, + tpSirMsgQ lim_msg_q, + tpPESession session_entry) +{ +} +static inline void lim_ndi_del_bss_rsp(tpAniSirGlobal mac_ctx, + void *msg, tpPESession session_entry) +{ +} +static inline void lim_process_ndi_del_sta_rsp(tpAniSirGlobal mac_ctx, + tpSirMsgQ lim_msg, tpPESession pe_session) +{ +} + +static inline void lim_ndp_add_sta_rsp(tpAniSirGlobal mac_ctx, + tpPESession session_entry, + tAddStaParams *add_sta_rsp) +{ +} + +#endif /* WLAN_FEATURE_NAN_DATAPATH */ + +#endif /* __MAC_NAN_DATAPATH_H */ diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/rrm/rrm_api.c b/drivers/staging/qcacld-3.0/core/mac/src/pe/rrm/rrm_api.c new file mode 100644 index 0000000000000000000000000000000000000000..0f1f51fe2de7781b1f0e875c045c64274f45e4c6 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/rrm/rrm_api.c @@ -0,0 +1,1361 @@ +/* + * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/**========================================================================= + + \file rrm_api.c + + \brief implementation for PE RRM APIs + + ========================================================================*/ + +/* $Header$ */ + + +/*-------------------------------------------------------------------------- + Include Files + ------------------------------------------------------------------------*/ +#include "cds_api.h" +#include "wni_api.h" +#include "sir_api.h" +#include "ani_global.h" +#include "wni_cfg.h" +#include "lim_types.h" +#include "lim_utils.h" +#include "lim_send_sme_rsp_messages.h" +#include "parser_api.h" +#include "lim_send_messages.h" +#include "rrm_global.h" +#include "rrm_api.h" + +#define MAX_RRM_TX_PWR_CAP 22 + +uint8_t +rrm_get_min_of_max_tx_power(tpAniSirGlobal pMac, + int8_t regMax, int8_t apTxPower) +{ + uint8_t maxTxPower = 0; + uint8_t txPower = QDF_MIN(regMax, (apTxPower)); + if ((txPower >= RRM_MIN_TX_PWR_CAP) && (txPower <= RRM_MAX_TX_PWR_CAP)) + maxTxPower = txPower; + else if (txPower < RRM_MIN_TX_PWR_CAP) + maxTxPower = RRM_MIN_TX_PWR_CAP; + else + maxTxPower = RRM_MAX_TX_PWR_CAP; + + lim_log(pMac, LOG3, + "%s: regulatoryMax = %d, apTxPwr = %d, maxTxpwr = %d", + __func__, regMax, apTxPower, maxTxPower); + return maxTxPower; +} + +/* -------------------------------------------------------------------- */ +/** + * rrm_cache_mgmt_tx_power + ** + * FUNCTION: Store Tx power for management frames. + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param pSessionEntry session entry. + * @return None + */ +void +rrm_cache_mgmt_tx_power(tpAniSirGlobal pMac, int8_t txPower, + tpPESession pSessionEntry) +{ + lim_log(pMac, LOG1, "Cache Mgmt Tx Power = %d", txPower); + + if (pSessionEntry == NULL) { + lim_log(pMac, LOG3, "%s: pSessionEntry is NULL", __func__); + pMac->rrm.rrmPEContext.txMgmtPower = txPower; + } else + pSessionEntry->txMgmtPower = txPower; +} + +/* -------------------------------------------------------------------- */ +/** + * rrm_get_mgmt_tx_power + * + * FUNCTION: Get the Tx power for management frames. + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param pSessionEntry session entry. + * @return txPower + */ +int8_t rrm_get_mgmt_tx_power(tpAniSirGlobal pMac, tpPESession pSessionEntry) +{ + if (pSessionEntry == NULL) { + lim_log(pMac, LOG3, "%s: txpower from rrmPEContext: %d", + __func__, pMac->rrm.rrmPEContext.txMgmtPower); + return pMac->rrm.rrmPEContext.txMgmtPower; + } + + lim_log(pMac, LOG1, FL("tx mgmt pwr %d"), pSessionEntry->txMgmtPower); + + return pSessionEntry->txMgmtPower; +} + +/* -------------------------------------------------------------------- */ +/** + * rrm_send_set_max_tx_power_req + * + * FUNCTION: Send WMA_SET_MAX_TX_POWER_REQ message to change the max tx power. + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param txPower txPower to be set. + * @param pSessionEntry session entry. + * @return None + */ +tSirRetStatus +rrm_send_set_max_tx_power_req(tpAniSirGlobal pMac, int8_t txPower, + tpPESession pSessionEntry) +{ + tpMaxTxPowerParams pMaxTxParams; + tSirRetStatus retCode = eSIR_SUCCESS; + tSirMsgQ msgQ; + + if (pSessionEntry == NULL) { + PELOGE(lim_log(pMac, LOGE, FL("Invalid parameters"));) + return eSIR_FAILURE; + } + pMaxTxParams = qdf_mem_malloc(sizeof(tMaxTxPowerParams)); + if (NULL == pMaxTxParams) { + lim_log(pMac, LOGP, + FL("Unable to allocate memory for pMaxTxParams ")); + return eSIR_MEM_ALLOC_FAILED; + + } + /* Allocated memory for pMaxTxParams...will be freed in other module */ + pMaxTxParams->power = txPower; + qdf_mem_copy(pMaxTxParams->bssId.bytes, pSessionEntry->bssId, + QDF_MAC_ADDR_SIZE); + qdf_mem_copy(pMaxTxParams->selfStaMacAddr.bytes, + pSessionEntry->selfMacAddr, + QDF_MAC_ADDR_SIZE); + + msgQ.type = WMA_SET_MAX_TX_POWER_REQ; + msgQ.reserved = 0; + msgQ.bodyptr = pMaxTxParams; + msgQ.bodyval = 0; + + lim_log(pMac, LOG3, + FL("Sending WMA_SET_MAX_TX_POWER_REQ with power(%d) to HAL"), + txPower); + + MTRACE(mac_trace_msg_tx(pMac, pSessionEntry->peSessionId, msgQ.type)); + retCode = wma_post_ctrl_msg(pMac, &msgQ); + if (eSIR_SUCCESS != retCode) { + lim_log(pMac, LOGP, + FL + ("Posting WMA_SET_MAX_TX_POWER_REQ to HAL failed, reason=%X"), + retCode); + qdf_mem_free(pMaxTxParams); + return retCode; + } + return retCode; +} + +/* -------------------------------------------------------------------- */ +/** + * rrm_set_max_tx_power_rsp + * + * FUNCTION: Process WMA_SET_MAX_TX_POWER_RSP message. + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param txPower txPower to be set. + * @param pSessionEntry session entry. + * @return None + */ +tSirRetStatus rrm_set_max_tx_power_rsp(tpAniSirGlobal pMac, tpSirMsgQ limMsgQ) +{ + tSirRetStatus retCode = eSIR_SUCCESS; + tpMaxTxPowerParams pMaxTxParams = (tpMaxTxPowerParams) limMsgQ->bodyptr; + tpPESession pSessionEntry; + uint8_t sessionId, i; + + if (qdf_is_macaddr_broadcast(&pMaxTxParams->bssId)) { + for (i = 0; i < pMac->lim.maxBssId; i++) { + if ((pMac->lim.gpSession[i].valid == true)) { + pSessionEntry = &pMac->lim.gpSession[i]; + rrm_cache_mgmt_tx_power(pMac, pMaxTxParams->power, + pSessionEntry); + } + } + } else { + pSessionEntry = pe_find_session_by_bssid(pMac, + pMaxTxParams->bssId.bytes, + &sessionId); + if (pSessionEntry == NULL) { + PELOGE(lim_log + (pMac, LOGE, FL("Unable to find session:")); + ) + retCode = eSIR_FAILURE; + } else { + rrm_cache_mgmt_tx_power(pMac, pMaxTxParams->power, + pSessionEntry); + } + } + + qdf_mem_free(limMsgQ->bodyptr); + limMsgQ->bodyptr = NULL; + return retCode; +} + +/* -------------------------------------------------------------------- */ +/** + * rrm_process_link_measurement_request + * + * FUNCTION: Processes the Link measurement request and send the report. + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param pBd pointer to BD to extract RSSI and SNR + * @param pLinkReq pointer to the Link request frame structure. + * @param pSessionEntry session entry. + * @return None + */ +tSirRetStatus +rrm_process_link_measurement_request(tpAniSirGlobal pMac, + uint8_t *pRxPacketInfo, + tDot11fLinkMeasurementRequest *pLinkReq, + tpPESession pSessionEntry) +{ + tSirMacLinkReport LinkReport; + tpSirMacMgmtHdr pHdr; + int8_t currentRSSI = 0; + + lim_log(pMac, LOG3, "Received Link measurement request"); + + if (pRxPacketInfo == NULL || pLinkReq == NULL || pSessionEntry == NULL) { + PELOGE(lim_log(pMac, LOGE, + "%s Invalid parameters - Ignoring the request", + __func__); + ) + return eSIR_FAILURE; + } + pHdr = WMA_GET_RX_MAC_HEADER(pRxPacketInfo); + + LinkReport.txPower = lim_get_max_tx_power(pLinkReq->MaxTxPower.maxTxPower, + MAX_RRM_TX_PWR_CAP, + pMac->roam.configParam. + nTxPowerCap); + + if ((LinkReport.txPower != (uint8_t) (pSessionEntry->maxTxPower)) && + (eSIR_SUCCESS == rrm_send_set_max_tx_power_req(pMac, + LinkReport.txPower, + pSessionEntry))) { + PELOGW(lim_log + (pMac, LOGW, + FL(" maxTx power in link report is not same as local..." + " Local = %d Link Request TxPower = %d" + " Link Report TxPower = %d"), + pSessionEntry->maxTxPower, LinkReport.txPower, + pLinkReq->MaxTxPower.maxTxPower); + ) + pSessionEntry->maxTxPower = + LinkReport.txPower; + } + + LinkReport.dialogToken = pLinkReq->DialogToken.token; + LinkReport.rxAntenna = 0; + LinkReport.txAntenna = 0; + currentRSSI = WMA_GET_RX_RSSI_RAW(pRxPacketInfo); + + lim_log(pMac, LOG1, "Received Link report frame with %d", currentRSSI); + + /* 2008 11k spec reference: 18.4.8.5 RCPI Measurement */ + if ((currentRSSI) <= RCPI_LOW_RSSI_VALUE) + LinkReport.rcpi = 0; + else if ((currentRSSI > RCPI_LOW_RSSI_VALUE) && (currentRSSI <= 0)) + LinkReport.rcpi = CALCULATE_RCPI(currentRSSI); + else + LinkReport.rcpi = RCPI_MAX_VALUE; + + LinkReport.rsni = WMA_GET_RX_SNR(pRxPacketInfo); + + lim_log(pMac, LOG3, "Sending Link report frame"); + + return lim_send_link_report_action_frame(pMac, &LinkReport, pHdr->sa, + pSessionEntry); +} + +/* -------------------------------------------------------------------- */ +/** + * rrm_process_neighbor_report_response + * + * FUNCTION: Processes the Neighbor Report response from the peer AP. + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param pNeighborRep pointer to the Neighbor report frame structure. + * @param pSessionEntry session entry. + * @return None + */ +tSirRetStatus +rrm_process_neighbor_report_response(tpAniSirGlobal pMac, + tDot11fNeighborReportResponse *pNeighborRep, + tpPESession pSessionEntry) +{ + tSirRetStatus status = eSIR_FAILURE; + tpSirNeighborReportInd pSmeNeighborRpt = NULL; + uint16_t length; + uint8_t i; + tSirMsgQ mmhMsg; + + if (pNeighborRep == NULL || pSessionEntry == NULL) { + PELOGE(lim_log(pMac, LOGE, FL(" Invalid parameters"));) + return status; + } + + lim_log(pMac, LOG3, FL("Neighbor report response received ")); + + /* Dialog token */ + if (pMac->rrm.rrmPEContext.DialogToken != + pNeighborRep->DialogToken.token) { + PELOGE(lim_log + (pMac, LOGE, + "Dialog token mismatch in the received Neighbor report"); + ) + return eSIR_FAILURE; + } + if (pNeighborRep->num_NeighborReport == 0) { + PELOGE(lim_log + (pMac, LOGE, + "No neighbor report in the frame...Dropping it"); + ) + return eSIR_FAILURE; + } + length = (sizeof(tSirNeighborReportInd)) + + (sizeof(tSirNeighborBssDescription) * + (pNeighborRep->num_NeighborReport - 1)); + + /* Prepare the request to send to SME. */ + pSmeNeighborRpt = qdf_mem_malloc(length); + if (NULL == pSmeNeighborRpt) { + PELOGE(lim_log(pMac, LOGP, FL("Unable to allocate memory"));) + return eSIR_MEM_ALLOC_FAILED; + + } + + /* Allocated memory for pSmeNeighborRpt...will be freed by other module */ + + for (i = 0; i < pNeighborRep->num_NeighborReport; i++) { + pSmeNeighborRpt->sNeighborBssDescription[i].length = sizeof(tSirNeighborBssDescription); /*+ any optional ies */ + qdf_mem_copy(pSmeNeighborRpt->sNeighborBssDescription[i].bssId, + pNeighborRep->NeighborReport[i].bssid, + sizeof(tSirMacAddr)); + pSmeNeighborRpt->sNeighborBssDescription[i].bssidInfo.rrmInfo. + fApPreauthReachable = + pNeighborRep->NeighborReport[i].APReachability; + pSmeNeighborRpt->sNeighborBssDescription[i].bssidInfo.rrmInfo. + fSameSecurityMode = + pNeighborRep->NeighborReport[i].Security; + pSmeNeighborRpt->sNeighborBssDescription[i].bssidInfo.rrmInfo. + fSameAuthenticator = + pNeighborRep->NeighborReport[i].KeyScope; + pSmeNeighborRpt->sNeighborBssDescription[i].bssidInfo.rrmInfo. + fCapSpectrumMeasurement = + pNeighborRep->NeighborReport[i].SpecMgmtCap; + pSmeNeighborRpt->sNeighborBssDescription[i].bssidInfo.rrmInfo. + fCapQos = pNeighborRep->NeighborReport[i].QosCap; + pSmeNeighborRpt->sNeighborBssDescription[i].bssidInfo.rrmInfo. + fCapApsd = pNeighborRep->NeighborReport[i].apsd; + pSmeNeighborRpt->sNeighborBssDescription[i].bssidInfo.rrmInfo. + fCapRadioMeasurement = pNeighborRep->NeighborReport[i].rrm; + pSmeNeighborRpt->sNeighborBssDescription[i].bssidInfo.rrmInfo. + fCapDelayedBlockAck = + pNeighborRep->NeighborReport[i].DelayedBA; + pSmeNeighborRpt->sNeighborBssDescription[i].bssidInfo.rrmInfo. + fCapImmediateBlockAck = + pNeighborRep->NeighborReport[i].ImmBA; + pSmeNeighborRpt->sNeighborBssDescription[i].bssidInfo.rrmInfo. + fMobilityDomain = + pNeighborRep->NeighborReport[i].MobilityDomain; + + pSmeNeighborRpt->sNeighborBssDescription[i].regClass = + pNeighborRep->NeighborReport[i].regulatoryClass; + pSmeNeighborRpt->sNeighborBssDescription[i].channel = + pNeighborRep->NeighborReport[i].channel; + pSmeNeighborRpt->sNeighborBssDescription[i].phyType = + pNeighborRep->NeighborReport[i].PhyType; + } + + pSmeNeighborRpt->messageType = eWNI_SME_NEIGHBOR_REPORT_IND; + pSmeNeighborRpt->length = length; + pSmeNeighborRpt->sessionId = pSessionEntry->smeSessionId; + pSmeNeighborRpt->numNeighborReports = pNeighborRep->num_NeighborReport; + qdf_mem_copy(pSmeNeighborRpt->bssId, pSessionEntry->bssId, + sizeof(tSirMacAddr)); + + /* Send request to SME. */ + mmhMsg.type = pSmeNeighborRpt->messageType; + mmhMsg.bodyptr = pSmeNeighborRpt; + MTRACE(mac_trace(pMac, TRACE_CODE_TX_SME_MSG, + pSessionEntry->peSessionId, mmhMsg.type)); + status = lim_sys_process_mmh_msg_api(pMac, &mmhMsg, ePROT); + + return status; + +} + +/* -------------------------------------------------------------------- */ +/** + * rrm_process_neighbor_report_req + * + * FUNCTION: + * + * LOGIC: Create a Neighbor report request and send it to peer. + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param pNeighborReq Neighbor report request params . + * @return None + */ +tSirRetStatus +rrm_process_neighbor_report_req(tpAniSirGlobal pMac, + tpSirNeighborReportReqInd pNeighborReq) +{ + tSirRetStatus status = eSIR_SUCCESS; + tSirMacNeighborReportReq NeighborReportReq; + tpPESession pSessionEntry; + uint8_t sessionId; + + if (pNeighborReq == NULL) { + PELOGE(lim_log(pMac, LOGE, "NeighborReq is NULL");) + return eSIR_FAILURE; + } + pSessionEntry = pe_find_session_by_bssid(pMac, pNeighborReq->bssId, + &sessionId); + if (pSessionEntry == NULL) { + PELOGE(lim_log + (pMac, LOGE, + FL("session does not exist for given bssId")); + ) + return eSIR_FAILURE; + } + + lim_log(pMac, LOG1, FL("SSID present = %d "), pNeighborReq->noSSID); + + qdf_mem_set(&NeighborReportReq, sizeof(tSirMacNeighborReportReq), 0); + + NeighborReportReq.dialogToken = ++pMac->rrm.rrmPEContext.DialogToken; + NeighborReportReq.ssid_present = !pNeighborReq->noSSID; + if (NeighborReportReq.ssid_present) { + qdf_mem_copy(&NeighborReportReq.ssid, &pNeighborReq->ucSSID, + sizeof(tSirMacSSid)); + PELOGE(sir_dump_buf + (pMac, SIR_LIM_MODULE_ID, LOGE, + (uint8_t *) NeighborReportReq.ssid.ssId, + NeighborReportReq.ssid.length); + ) + } + + status = + lim_send_neighbor_report_request_frame(pMac, &NeighborReportReq, + pNeighborReq->bssId, + pSessionEntry); + + return status; +} + +#define ABS(x) ((x < 0) ? -x : x) +/* -------------------------------------------------------------------- */ +/** + * rrm_process_beacon_report_req + * + * FUNCTION: Processes the Beacon report request from the peer AP. + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param pCurrentReq pointer to the current Req comtext. + * @param pBeaconReq pointer to the beacon report request IE from the peer. + * @param pSessionEntry session entry. + * @return None + */ +static tRrmRetStatus +rrm_process_beacon_report_req(tpAniSirGlobal pMac, + tpRRMReq pCurrentReq, + tDot11fIEMeasurementRequest *pBeaconReq, + tpPESession pSessionEntry) +{ + tSirMsgQ mmhMsg; + tpSirBeaconReportReqInd pSmeBcnReportReq; + uint8_t num_channels = 0, num_APChanReport; + uint16_t measDuration, maxMeasduration; + int8_t maxDuration; + uint8_t sign; + + if (pBeaconReq->measurement_request.Beacon.BeaconReporting.present && + (pBeaconReq->measurement_request.Beacon.BeaconReporting. + reportingCondition != 0)) { + /* Repeated measurement is not supported. This means number of repetitions should be zero.(Already checked) */ + /* All test case in VoWifi(as of version 0.36) use zero for number of repetitions. */ + /* Beacon reporting should not be included in request if number of repetitons is zero. */ + /* IEEE Std 802.11k-2008 Table 7-29g and section 11.10.8.1 */ + + PELOGE(lim_log + (pMac, LOGE, + "Dropping the request: Reporting condition included in beacon report request and it is not zero"); + ) + return eRRM_INCAPABLE; + } + + /* The logic here is to check the measurement duration passed in the beacon request. Following are the cases handled. + Case 1: If measurement duration received in the beacon request is greater than the max measurement duration advertised + in the RRM capabilities(Assoc Req), and Duration Mandatory bit is set to 1, REFUSE the beacon request + Case 2: If measurement duration received in the beacon request is greater than the max measurement duration advertised + in the RRM capabilities(Assoc Req), and Duration Mandatory bit is set to 0, perform measurement for + the duration advertised in the RRM capabilities + + maxMeasurementDuration = 2^(nonOperatingChanMax - 4) * BeaconInterval + */ + maxDuration = + pMac->rrm.rrmPEContext.rrmEnabledCaps.nonOperatingChanMax - 4; + sign = (maxDuration < 0) ? 1 : 0; + maxDuration = (1L << ABS(maxDuration)); + if (!sign) + maxMeasduration = + maxDuration * pSessionEntry->beaconParams.beaconInterval; + else + maxMeasduration = + pSessionEntry->beaconParams.beaconInterval / maxDuration; + + measDuration = pBeaconReq->measurement_request.Beacon.meas_duration; + + lim_log(pMac, LOG1, + "maxDuration = %d sign = %d maxMeasduration = %d measDuration = %d", + maxDuration, sign, maxMeasduration, measDuration); + + if (maxMeasduration < measDuration) { + if (pBeaconReq->durationMandatory) { + PELOGE(lim_log + (pMac, LOGE, + "Dropping the request: duration mandatory and maxduration > measduration"); + ) + return eRRM_REFUSED; + } else + measDuration = maxMeasduration; + } + /* Cache the data required for sending report. */ + pCurrentReq->request.Beacon.reportingDetail = + pBeaconReq->measurement_request.Beacon.BcnReportingDetail. + present ? pBeaconReq->measurement_request.Beacon.BcnReportingDetail. + reportingDetail : BEACON_REPORTING_DETAIL_ALL_FF_IE; + + if (pBeaconReq->measurement_request.Beacon.RequestedInfo.present) { + pCurrentReq->request.Beacon.reqIes.pElementIds = + qdf_mem_malloc(sizeof(uint8_t) * + pBeaconReq->measurement_request.Beacon. + RequestedInfo.num_requested_eids); + if (NULL == pCurrentReq->request.Beacon.reqIes.pElementIds) { + lim_log(pMac, LOGP, + FL + ("Unable to allocate memory for request IEs buffer")); + return eRRM_FAILURE; + } + lim_log(pMac, LOG3, FL(" Allocated memory for pElementIds")); + + pCurrentReq->request.Beacon.reqIes.num = + pBeaconReq->measurement_request.Beacon.RequestedInfo. + num_requested_eids; + qdf_mem_copy(pCurrentReq->request.Beacon.reqIes.pElementIds, + pBeaconReq->measurement_request.Beacon. + RequestedInfo.requested_eids, + pCurrentReq->request.Beacon.reqIes.num); + } + + if (pBeaconReq->measurement_request.Beacon.num_APChannelReport) { + for (num_APChanReport = 0; + num_APChanReport < + pBeaconReq->measurement_request.Beacon.num_APChannelReport; + num_APChanReport++) + num_channels += + pBeaconReq->measurement_request.Beacon. + APChannelReport[num_APChanReport].num_channelList; + } + /* Prepare the request to send to SME. */ + pSmeBcnReportReq = qdf_mem_malloc(sizeof(tSirBeaconReportReqInd)); + if (NULL == pSmeBcnReportReq) { + lim_log(pMac, LOGP, + FL + ("Unable to allocate memory during Beacon Report Req Ind to SME")); + + return eRRM_FAILURE; + + } + + /* Allocated memory for pSmeBcnReportReq....will be freed by other modulea */ + qdf_mem_copy(pSmeBcnReportReq->bssId, pSessionEntry->bssId, + sizeof(tSirMacAddr)); + pSmeBcnReportReq->messageType = eWNI_SME_BEACON_REPORT_REQ_IND; + pSmeBcnReportReq->length = sizeof(tSirBeaconReportReqInd); + pSmeBcnReportReq->uDialogToken = pBeaconReq->measurement_token; + pSmeBcnReportReq->msgSource = eRRM_MSG_SOURCE_11K; + pSmeBcnReportReq->randomizationInterval = + SYS_TU_TO_MS(pBeaconReq->measurement_request.Beacon.randomization); + pSmeBcnReportReq->channelInfo.regulatoryClass = + pBeaconReq->measurement_request.Beacon.regClass; + pSmeBcnReportReq->channelInfo.channelNum = + pBeaconReq->measurement_request.Beacon.channel; + pSmeBcnReportReq->measurementDuration[0] = SYS_TU_TO_MS(measDuration); + pSmeBcnReportReq->fMeasurementtype[0] = + pBeaconReq->measurement_request.Beacon.meas_mode; + qdf_mem_copy(pSmeBcnReportReq->macaddrBssid, + pBeaconReq->measurement_request.Beacon.BSSID, + sizeof(tSirMacAddr)); + + if (pBeaconReq->measurement_request.Beacon.SSID.present) { + pSmeBcnReportReq->ssId.length = + pBeaconReq->measurement_request.Beacon.SSID.num_ssid; + qdf_mem_copy(pSmeBcnReportReq->ssId.ssId, + pBeaconReq->measurement_request.Beacon.SSID.ssid, + pSmeBcnReportReq->ssId.length); + } + + pCurrentReq->token = pBeaconReq->measurement_token; + + pSmeBcnReportReq->channelList.numChannels = num_channels; + if (pBeaconReq->measurement_request.Beacon.num_APChannelReport) { + uint8_t *ch_lst = pSmeBcnReportReq->channelList.channelNumber; + uint8_t len; + uint16_t ch_ctr = 0; + for (num_APChanReport = 0; + num_APChanReport < + pBeaconReq->measurement_request.Beacon.num_APChannelReport; + num_APChanReport++) { + len = pBeaconReq->measurement_request.Beacon. + APChannelReport[num_APChanReport].num_channelList; + if (ch_ctr + len > + sizeof(pSmeBcnReportReq->channelList.channelNumber)) + break; + + qdf_mem_copy(&ch_lst[ch_ctr], + pBeaconReq->measurement_request.Beacon. + APChannelReport[num_APChanReport]. + channelList, len); + + ch_ctr += len; + } + } + /* Send request to SME. */ + mmhMsg.type = eWNI_SME_BEACON_REPORT_REQ_IND; + mmhMsg.bodyptr = pSmeBcnReportReq; + MTRACE(mac_trace(pMac, TRACE_CODE_TX_SME_MSG, + pSessionEntry->peSessionId, mmhMsg.type)); + if (eSIR_SUCCESS != lim_sys_process_mmh_msg_api(pMac, &mmhMsg, ePROT)) + return eRRM_FAILURE; + return eRRM_SUCCESS; +} + +/* -------------------------------------------------------------------- */ +/** + * rrm_fill_beacon_ies + * + * FUNCTION: + * + * LOGIC: Fills Fixed fields and Ies in bss description to an array of uint8_t. + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param pIes - pointer to the buffer that should be populated with ies. + * @param pNumIes - returns the num of ies filled in this param. + * @param pIesMaxSize - Max size of the buffer pIes. + * @param eids - pointer to array of eids. If NULL, all ies will be populated. + * @param numEids - number of elements in array eids. + * @param pBssDesc - pointer to Bss Description. + * @return None + */ +static void +rrm_fill_beacon_ies(tpAniSirGlobal pMac, + uint8_t *pIes, uint8_t *pNumIes, uint8_t pIesMaxSize, + uint8_t *eids, uint8_t numEids, tpSirBssDescription pBssDesc) +{ + uint8_t len, *pBcnIes, count = 0, i; + uint8_t BcnNumIes; + + if ((pIes == NULL) || (pNumIes == NULL) || (pBssDesc == NULL)) { + PELOGE(lim_log(pMac, LOGE, FL(" Invalid parameters"));) + return; + } + /* Make sure that if eid is null, numEids is set to zero. */ + numEids = (eids == NULL) ? 0 : numEids; + + pBcnIes = (uint8_t *) &pBssDesc->ieFields[0]; + BcnNumIes = (uint8_t) GET_IE_LEN_IN_BSS(pBssDesc->length); + + *pNumIes = 0; + + *((uint32_t *) pIes) = pBssDesc->timeStamp[0]; + *pNumIes += sizeof(uint32_t); + pIes += sizeof(uint32_t); + *((uint32_t *) pIes) = pBssDesc->timeStamp[1]; + *pNumIes += sizeof(uint32_t); + pIes += sizeof(uint32_t); + *((uint16_t *) pIes) = pBssDesc->beaconInterval; + *pNumIes += sizeof(uint16_t); + pIes += sizeof(uint16_t); + *((uint16_t *) pIes) = pBssDesc->capabilityInfo; + *pNumIes += sizeof(uint16_t); + pIes += sizeof(uint16_t); + + while (BcnNumIes > 0) { + len = *(pBcnIes + 1) + 2; /* element id + length. */ + lim_log(pMac, LOG3, "EID = %d, len = %d total = %d", + *pBcnIes, *(pBcnIes + 1), len); + + i = 0; + do { + if (((eids == NULL) || (*pBcnIes == eids[i])) && + ((*pNumIes) + len) < pIesMaxSize) { + lim_log(pMac, LOG3, "Adding Eid %d, len=%d", + *pBcnIes, len); + + qdf_mem_copy(pIes, pBcnIes, len); + pIes += len; + *pNumIes += len; + count++; + break; + } + i++; + } while (i < numEids); + + pBcnIes += len; + BcnNumIes -= len; + } + lim_log(pMac, LOG1, "Total length of Ies added = %d", *pNumIes); +} + +/** + * rrm_process_beacon_report_xmit() - create a rrm action frame + * @mac_ctx: Global pointer to MAC context + * @beacon_xmit_ind: Data for beacon report IE from SME. + * + * Create a Radio measurement report action frame and send it to peer. + * + * Return: tSirRetStatus + */ +tSirRetStatus +rrm_process_beacon_report_xmit(tpAniSirGlobal mac_ctx, + tpSirBeaconReportXmitInd beacon_xmit_ind) +{ + tSirRetStatus status = eSIR_SUCCESS; + tSirMacRadioMeasureReport *report = NULL; + tSirMacBeaconReport *beacon_report; + tpSirBssDescription bss_desc; + tpRRMReq curr_req = mac_ctx->rrm.rrmPEContext.pCurrentReq; + tpPESession session_entry; + uint8_t session_id; + uint8_t bss_desc_count = 0; + + lim_log(mac_ctx, LOG1, FL("Received beacon report xmit indication")); + + if (NULL == beacon_xmit_ind) { + lim_log(mac_ctx, LOGE, + FL("Received beacon_xmit_ind is NULL in PE")); + return eSIR_FAILURE; + } + + if (NULL == curr_req) { + lim_log(mac_ctx, LOGE, + FL("Received report xmit while there is no request pending in PE")); + return eSIR_FAILURE; + } + + if ((beacon_xmit_ind->numBssDesc) || curr_req->sendEmptyBcnRpt) { + beacon_xmit_ind->numBssDesc = (beacon_xmit_ind->numBssDesc == + RRM_BCN_RPT_NO_BSS_INFO) ? RRM_BCN_RPT_MIN_RPT : + beacon_xmit_ind->numBssDesc; + + session_entry = pe_find_session_by_bssid(mac_ctx, + beacon_xmit_ind->bssId, &session_id); + if (NULL == session_entry) { + lim_log(mac_ctx, LOGE, FL("session does not exist for given bssId")); + return eSIR_FAILURE; + } + + report = qdf_mem_malloc(beacon_xmit_ind->numBssDesc * + sizeof(*report)); + + if (NULL == report) { + lim_log(mac_ctx, LOGE, FL("RRM Report is NULL, allocation failed")); + return eSIR_MEM_ALLOC_FAILED; + } + + for (bss_desc_count = 0; bss_desc_count < + beacon_xmit_ind->numBssDesc; bss_desc_count++) { + beacon_report = + &report[bss_desc_count].report.beaconReport; + /* + * If the scan result is NULL then send report request + * with option subelement as NULL. + */ + bss_desc = beacon_xmit_ind-> + pBssDescription[bss_desc_count]; + /* Prepare the beacon report and send it to the peer.*/ + report[bss_desc_count].token = + beacon_xmit_ind->uDialogToken; + report[bss_desc_count].refused = 0; + report[bss_desc_count].incapable = 0; + report[bss_desc_count].type = SIR_MAC_RRM_BEACON_TYPE; + + /* + * Valid response is included if the size of + * becon xmit is == size of beacon xmit ind + ies + */ + if (beacon_xmit_ind->length < sizeof(*beacon_xmit_ind)) + continue; + beacon_report->regClass = beacon_xmit_ind->regClass; + if (bss_desc) { + beacon_report->channel = bss_desc->channelId; + qdf_mem_copy(beacon_report->measStartTime, + bss_desc->startTSF, + sizeof(bss_desc->startTSF)); + beacon_report->measDuration = + SYS_MS_TO_TU(beacon_xmit_ind->duration); + beacon_report->phyType = bss_desc->nwType; + beacon_report->bcnProbeRsp = 1; + beacon_report->rsni = bss_desc->sinr; + beacon_report->rcpi = bss_desc->rssi; + beacon_report->antennaId = 0; + beacon_report->parentTSF = bss_desc->parentTSF; + qdf_mem_copy(beacon_report->bssid, + bss_desc->bssId, sizeof(tSirMacAddr)); + } + + switch (curr_req->request.Beacon.reportingDetail) { + case BEACON_REPORTING_DETAIL_NO_FF_IE: + /* 0: No need to include any elements. */ + lim_log(mac_ctx, LOG3, + FL("No reporting detail requested")); + break; + case BEACON_REPORTING_DETAIL_ALL_FF_REQ_IE: + /* 1: Include all FFs and Requested Ies. */ + lim_log(mac_ctx, LOG3, + FL("Only requested IEs in reporting detail requested")); + + if (bss_desc) { + rrm_fill_beacon_ies(mac_ctx, + (uint8_t *) &beacon_report->Ies[0], + (uint8_t *) &beacon_report->numIes, + BEACON_REPORT_MAX_IES, + curr_req->request.Beacon.reqIes. + pElementIds, + curr_req->request.Beacon.reqIes.num, + bss_desc); + } + break; + case BEACON_REPORTING_DETAIL_ALL_FF_IE: + /* 2: default - Include all FFs and all Ies. */ + default: + lim_log(mac_ctx, LOG3, FL("Default all IEs and FFs")); + if (bss_desc) { + rrm_fill_beacon_ies(mac_ctx, + (uint8_t *) &beacon_report->Ies[0], + (uint8_t *) &beacon_report->numIes, + BEACON_REPORT_MAX_IES, + NULL, + 0, + bss_desc); + } + break; + } + } + + lim_log(mac_ctx, LOG1, FL("Sending Action frame with %d bss info"), + bss_desc_count); + lim_send_radio_measure_report_action_frame(mac_ctx, + curr_req->dialog_token, bss_desc_count, report, + beacon_xmit_ind->bssId, session_entry); + + curr_req->sendEmptyBcnRpt = false; + } + + if (beacon_xmit_ind->fMeasureDone) { + lim_log(mac_ctx, LOG3, FL("Measurement done....cleanup the context")); + rrm_cleanup(mac_ctx); + } + + if (NULL != report) + qdf_mem_free(report); + + return status; +} + +static void rrm_process_beacon_request_failure(tpAniSirGlobal pMac, + tpPESession pSessionEntry, + tSirMacAddr peer, + tRrmRetStatus status) +{ + tpSirMacRadioMeasureReport pReport = NULL; + tpRRMReq pCurrentReq = pMac->rrm.rrmPEContext.pCurrentReq; + + pReport = qdf_mem_malloc(sizeof(tSirMacRadioMeasureReport)); + if (NULL == pReport) { + lim_log(pMac, LOGP, + FL + ("Unable to allocate memory during RRM Req processing")); + return; + } + pReport->token = pCurrentReq->token; + pReport->type = SIR_MAC_RRM_BEACON_TYPE; + + lim_log(pMac, LOG1, + FL("status %d token %d"), status, pReport->token); + + switch (status) { + case eRRM_REFUSED: + pReport->refused = 1; + break; + case eRRM_INCAPABLE: + pReport->incapable = 1; + break; + default: + PELOGE(lim_log(pMac, LOGE, + FL + (" Beacon request processing failed no report sent with status %d "), + status); + ); + qdf_mem_free(pReport); + return; + } + + lim_send_radio_measure_report_action_frame(pMac, pCurrentReq->dialog_token, 1, + pReport, peer, pSessionEntry); + + qdf_mem_free(pReport); + lim_log(pMac, LOG3, FL(" Free memory for pReport")); + return; +} + +/** + * rrm_process_beacon_req() - Update curr_req and report + * @mac_ctx: Global pointer to MAC context + * @peer: Macaddress of the peer requesting the radio measurement + * @session_entry: session entry + * @curr_req: Pointer to RRM request + * @report: Pointer to radio measurement report + * @rrm_req: Array of Measurement request IEs + * @num_report: No.of reports + * @index: Index for Measurement request + * + * Update structure sRRMReq and sSirMacRadioMeasureReport and pass it to + * rrm_process_beacon_report_req(). + * + * Return: tSirRetStatus + */ +static +tSirRetStatus rrm_process_beacon_req(tpAniSirGlobal mac_ctx, tSirMacAddr peer, + tpPESession session_entry, tpRRMReq curr_req, + tpSirMacRadioMeasureReport report, + tDot11fRadioMeasurementRequest *rrm_req, + uint8_t *num_report, int index) +{ + tRrmRetStatus rrm_status = eRRM_SUCCESS; + + if (curr_req) { + if (report == NULL) { + /* + * Allocate memory to send reports for + * any subsequent requests. + */ + report = qdf_mem_malloc(sizeof(*report) * + (rrm_req->num_MeasurementRequest - index)); + if (NULL == report) { + lim_log(mac_ctx, LOGP, + FL("Unable to allocate memory during RRM Req processing")); + return eSIR_MEM_ALLOC_FAILED; + } + lim_log(mac_ctx, LOG3, + FL("rrm beacon type refused of %d report in beacon table"), + *num_report); + } + report[*num_report].refused = 1; + report[*num_report].type = SIR_MAC_RRM_BEACON_TYPE; + report[*num_report].token = + rrm_req->MeasurementRequest[index].measurement_token; + (*num_report)++; + return eSIR_SUCCESS; + } else { + curr_req = qdf_mem_malloc(sizeof(*curr_req)); + if (NULL == curr_req) { + lim_log(mac_ctx, LOGP, + FL("Unable to allocate memory during RRM Req processing")); + qdf_mem_free(report); + return eSIR_MEM_ALLOC_FAILED; + } + lim_log(mac_ctx, LOG3, FL(" Processing Beacon Report request")); + curr_req->dialog_token = rrm_req->DialogToken.token; + curr_req->token = rrm_req-> + MeasurementRequest[index].measurement_token; + curr_req->sendEmptyBcnRpt = true; + mac_ctx->rrm.rrmPEContext.pCurrentReq = curr_req; + rrm_status = rrm_process_beacon_report_req(mac_ctx, curr_req, + &rrm_req->MeasurementRequest[index], session_entry); + if (eRRM_SUCCESS != rrm_status) { + rrm_process_beacon_request_failure(mac_ctx, + session_entry, peer, rrm_status); + rrm_cleanup(mac_ctx); + } + } + return eSIR_SUCCESS; +} + +/** + * update_rrm_report() - Set incapable bit + * @mac_ctx: Global pointer to MAC context + * @report: Pointer to radio measurement report + * @rrm_req: Array of Measurement request IEs + * @num_report: No.of reports + * @index: Index for Measurement request + * + * Send a report with incapabale bit set + * + * Return: tSirRetStatus + */ +static +tSirRetStatus update_rrm_report(tpAniSirGlobal mac_ctx, + tpSirMacRadioMeasureReport report, + tDot11fRadioMeasurementRequest *rrm_req, + uint8_t *num_report, int index) +{ + if (report == NULL) { + /* + * Allocate memory to send reports for + * any subsequent requests. + */ + report = qdf_mem_malloc(sizeof(*report) * + (rrm_req->num_MeasurementRequest - index)); + if (NULL == report) { + lim_log(mac_ctx, LOGP, FL("Unable to allocate memory during RRM Req processing")); + return eSIR_MEM_ALLOC_FAILED; + } + lim_log(mac_ctx, LOG3, FL("rrm beacon type incapable of %d report "), + *num_report); + } + report[*num_report].incapable = 1; + report[*num_report].type = + rrm_req->MeasurementRequest[index].measurement_type; + report[*num_report].token = + rrm_req->MeasurementRequest[index].measurement_token; + (*num_report)++; + return eSIR_SUCCESS; +} + +/* -------------------------------------------------------------------- */ +/** + * rrm_process_radio_measurement_request - Process rrm request + * @mac_ctx: Global pointer to MAC context + * @peer: Macaddress of the peer requesting the radio measurement. + * @rrm_req: Array of Measurement request IEs + * @session_entry: session entry. + * + * Processes the Radio Resource Measurement request. + * + * Return: tSirRetStatus + */ +tSirRetStatus +rrm_process_radio_measurement_request(tpAniSirGlobal mac_ctx, + tSirMacAddr peer, + tDot11fRadioMeasurementRequest *rrm_req, + tpPESession session_entry) +{ + uint8_t i; + tSirRetStatus status = eSIR_SUCCESS; + tpSirMacRadioMeasureReport report = NULL; + uint8_t num_report = 0; + tpRRMReq curr_req = mac_ctx->rrm.rrmPEContext.pCurrentReq; + + if (!rrm_req->num_MeasurementRequest) { + report = qdf_mem_malloc(sizeof(tSirMacRadioMeasureReport)); + if (NULL == report) { + lim_log(mac_ctx, LOGP, FL("Unable to allocate memory during RRM Req processing")); + return eSIR_MEM_ALLOC_FAILED; + } + lim_log(mac_ctx, LOGE, FL("No requestIes in the measurement request, sending incapable report")); + report->incapable = 1; + num_report = 1; + lim_send_radio_measure_report_action_frame(mac_ctx, + rrm_req->DialogToken.token, num_report, report, peer, + session_entry); + qdf_mem_free(report); + return eSIR_FAILURE; + } + /* PF Fix */ + if (rrm_req->NumOfRepetitions.repetitions > 0) { + lim_log(mac_ctx, LOG1, FL(" number of repetitions %d"), + rrm_req->NumOfRepetitions.repetitions); + /* + * Send a report with incapable bit set. + * Not supporting repetitions. + */ + report = qdf_mem_malloc(sizeof(tSirMacRadioMeasureReport)); + if (NULL == report) { + lim_log(mac_ctx, LOGP, FL("Unable to allocate memory during RRM Req processing")); + return eSIR_MEM_ALLOC_FAILED; + } + lim_log(mac_ctx, LOGE, FL("Allocated memory for report")); + report->incapable = 1; + report->type = rrm_req->MeasurementRequest[0].measurement_type; + num_report = 1; + goto end; + } + + for (i = 0; i < rrm_req->num_MeasurementRequest; i++) { + switch (rrm_req->MeasurementRequest[i].measurement_type) { + case SIR_MAC_RRM_BEACON_TYPE: + /* Process beacon request. */ + status = rrm_process_beacon_req(mac_ctx, peer, + session_entry, curr_req, report, rrm_req, + &num_report, i); + if (eSIR_SUCCESS != status) + return status; + break; + case SIR_MAC_RRM_LCI_TYPE: + case SIR_MAC_RRM_LOCATION_CIVIC_TYPE: + case SIR_MAC_RRM_FINE_TIME_MEAS_TYPE: + lim_log(mac_ctx, LOG1, + FL("RRM with type: %d sent to userspace"), + rrm_req->MeasurementRequest[i].measurement_type); + break; + default: + /* Send a report with incapabale bit set. */ + status = update_rrm_report(mac_ctx, report, rrm_req, + &num_report, i); + if (eSIR_SUCCESS != status) + return status; + break; + } + } + +end: + if (report) { + lim_send_radio_measure_report_action_frame(mac_ctx, + rrm_req->DialogToken.token, num_report, report, + peer, session_entry); + qdf_mem_free(report); + lim_log(mac_ctx, LOG3, FL(" Free memory for report")); + } + return status; +} + +/* -------------------------------------------------------------------- */ +/** + * rrm_update_start_tsf + ** + * FUNCTION: Store start TSF of measurement. + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param startTSF - TSF value at the start of measurement. + * @return None + */ +void rrm_update_start_tsf(tpAniSirGlobal pMac, uint32_t startTSF[2]) +{ + pMac->rrm.rrmPEContext.startTSF[0] = startTSF[0]; + pMac->rrm.rrmPEContext.startTSF[1] = startTSF[1]; +} + +/* -------------------------------------------------------------------- */ +/** + * rrm_get_start_tsf + * + * FUNCTION: Get the Start TSF. + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param startTSF - store star TSF in this buffer. + * @return txPower + */ +void rrm_get_start_tsf(tpAniSirGlobal pMac, uint32_t *pStartTSF) +{ + pStartTSF[0] = pMac->rrm.rrmPEContext.startTSF[0]; + pStartTSF[1] = pMac->rrm.rrmPEContext.startTSF[1]; + +} + +/* -------------------------------------------------------------------- */ +/** + * rrm_get_capabilities + * + * FUNCTION: + * Returns a pointer to tpRRMCaps with all the caps enabled in RRM + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param pSessionEntry + * @return pointer to tRRMCaps + */ +tpRRMCaps rrm_get_capabilities(tpAniSirGlobal pMac, tpPESession pSessionEntry) +{ + return &pMac->rrm.rrmPEContext.rrmEnabledCaps; +} + +/* -------------------------------------------------------------------- */ +/** + * rrm_initialize + * + * FUNCTION: + * Initialize RRM module + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @return None + */ + +tSirRetStatus rrm_initialize(tpAniSirGlobal pMac) +{ + tpRRMCaps pRRMCaps = &pMac->rrm.rrmPEContext.rrmEnabledCaps; + + pMac->rrm.rrmPEContext.pCurrentReq = NULL; + pMac->rrm.rrmPEContext.txMgmtPower = 0; + pMac->rrm.rrmPEContext.DialogToken = 0; + + pMac->rrm.rrmPEContext.rrmEnable = 0; + + qdf_mem_set(pRRMCaps, sizeof(tRRMCaps), 0); + pRRMCaps->LinkMeasurement = 1; + pRRMCaps->NeighborRpt = 1; + pRRMCaps->BeaconPassive = 1; + pRRMCaps->BeaconActive = 1; + pRRMCaps->BeaconTable = 1; + pRRMCaps->APChanReport = 1; + pRRMCaps->fine_time_meas_rpt = 1; + pRRMCaps->lci_capability = 1; + + pRRMCaps->operatingChanMax = 3; + pRRMCaps->nonOperatingChanMax = 3; + + return eSIR_SUCCESS; +} + +/* -------------------------------------------------------------------- */ +/** + * rrm_cleanup + * + * FUNCTION: + * cleanup RRM module + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param mode + * @param rate + * @return None + */ + +tSirRetStatus rrm_cleanup(tpAniSirGlobal pMac) +{ + if (pMac->rrm.rrmPEContext.pCurrentReq) { + if (pMac->rrm.rrmPEContext.pCurrentReq->request.Beacon.reqIes. + pElementIds) { + qdf_mem_free(pMac->rrm.rrmPEContext.pCurrentReq-> + request.Beacon.reqIes.pElementIds); + lim_log(pMac, LOG4, FL(" Free memory for pElementIds")); + } + + qdf_mem_free(pMac->rrm.rrmPEContext.pCurrentReq); + lim_log(pMac, LOG4, FL(" Free memory for pCurrentReq")); + } + + pMac->rrm.rrmPEContext.pCurrentReq = NULL; + return eSIR_SUCCESS; +} + +/** + * lim_update_rrm_capability() - Update PE context's rrm capability + * @mac_ctx: Global pointer to MAC context + * @join_req: Pointer to SME join request. + * + * Update PE context's rrm capability based on SME join request. + * + * Return: None + */ +void lim_update_rrm_capability(tpAniSirGlobal mac_ctx, + tpSirSmeJoinReq join_req) +{ + mac_ctx->rrm.rrmPEContext.rrmEnable = join_req->rrm_config.rrm_enabled; + qdf_mem_copy(&mac_ctx->rrm.rrmPEContext.rrmEnabledCaps, + &join_req->rrm_config.rm_capability, + RMENABLEDCAP_MAX_LEN); + + return; +} diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/sch/sch_api.c b/drivers/staging/qcacld-3.0/core/mac/src/pe/sch/sch_api.c new file mode 100644 index 0000000000000000000000000000000000000000..5ecf8a24d557698f411a80971011f2ee28b30372 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/sch/sch_api.c @@ -0,0 +1,603 @@ +/* + * Copyright (c) 2011-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * + * This file sch_api.cc contains functions related to the API exposed + * by scheduler module + * + * Author: Sandesh Goel + * Date: 02/25/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + * + */ +#include "cds_api.h" +#include "ani_global.h" +#include "wni_cfg.h" + +#include "sir_mac_prot_def.h" +#include "sir_mac_prop_exts.h" +#include "sir_common.h" + +#include "cfg_api.h" + +#include "lim_api.h" + +#include "sch_api.h" +#include "sch_debug.h" + +#include "sch_sys_params.h" +#include "lim_trace.h" +#include "lim_types.h" +#include "lim_utils.h" + +#include "wma_types.h" + +/* -------------------------------------------------------------------- */ +/* */ +/* Static Variables */ +/* */ +/* ------------------------------------------------------------------- */ + +/* -------------------------------------------------------------------- */ +/** + * sch_init_globals + * + * FUNCTION: + * Initialize globals + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param None + * @return None + */ + +void sch_init_globals(tpAniSirGlobal pMac) +{ + pMac->sch.gSchHcfEnabled = false; + + pMac->sch.gSchScanRequested = false; + pMac->sch.gSchScanReqRcvd = false; + + pMac->sch.gSchGenBeacon = 1; + pMac->sch.gSchBeaconsSent = 0; + pMac->sch.gSchBeaconsWritten = 0; + pMac->sch.gSchBcnParseErrorCnt = 0; + pMac->sch.gSchBcnIgnored = 0; + pMac->sch.gSchBBXportRcvCnt = 0; + pMac->sch.gSchUnknownRcvCnt = 0; + pMac->sch.gSchBcnRcvCnt = 0; + pMac->sch.gSchRRRcvCnt = 0; + pMac->sch.qosNullCnt = 0; + pMac->sch.numData = 0; + pMac->sch.numPoll = 0; + pMac->sch.numCorrupt = 0; + pMac->sch.numBogusInt = 0; + pMac->sch.numTxAct0 = 0; + pMac->sch.rrTimeout = SCH_RR_TIMEOUT; + pMac->sch.pollPeriod = SCH_POLL_PERIOD; + pMac->sch.multipleSched = 1; + pMac->sch.maxPollTimeouts = 20; + pMac->sch.checkCfbFlagStuck = 0; +} + +/* -------------------------------------------------------------------- */ +/** + * sch_post_message + * + * FUNCTION: + * Post the beacon message to the scheduler message queue + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param pMsg pointer to message + * @return None + */ + +tSirRetStatus sch_post_message(tpAniSirGlobal pMac, tpSirMsgQ pMsg) +{ + sch_process_message(pMac, pMsg); + + return eSIR_SUCCESS; +} + +/* --------------------------------------------------------------------------- */ +/** + * sch_send_start_scan_rsp + * + * FUNCTION: + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param None + * @return None + */ + +void sch_send_start_scan_rsp(tpAniSirGlobal pMac) +{ + tSirMsgQ msgQ; + uint32_t retCode; + + PELOG1(sch_log(pMac, LOG1, FL("Sending LIM message to go into scan"));) + msgQ.type = SIR_SCH_START_SCAN_RSP; + retCode = lim_post_msg_api(pMac, &msgQ); + if (retCode != eSIR_SUCCESS) + sch_log(pMac, LOGE, + FL("Posting START_SCAN_RSP to LIM failed, reason=%X"), + retCode); +} + +/** + * sch_send_beacon_req + * + * FUNCTION: + * + * LOGIC: + * 1) SCH received SIR_SCH_BEACON_GEN_IND + * 2) SCH updates TIM IE and other beacon related IE's + * 3) SCH sends WMA_SEND_BEACON_REQ to HAL. HAL then copies the beacon + * template to memory + * + * ASSUMPTIONS: + * Memory allocation is reqd to send this message and SCH allocates memory. + * The assumption is that HAL will "free" this memory. + * + * NOTE: + * + * @param pMac global + * + * @param beaconPayload + * + * @param size - Length of the beacon + * + * @return QDF_STATUS + */ +tSirRetStatus sch_send_beacon_req(tpAniSirGlobal pMac, uint8_t *beaconPayload, + uint16_t size, tpPESession psessionEntry) +{ + tSirMsgQ msgQ; + tpSendbeaconParams beaconParams = NULL; + tSirRetStatus retCode; + + sch_log(pMac, LOG2, + FL + ("Indicating HAL to copy the beacon template [%d bytes] to memory"), + size); + + beaconParams = qdf_mem_malloc(sizeof(tSendbeaconParams)); + if (NULL == beaconParams) + return eSIR_MEM_ALLOC_FAILED; + + msgQ.type = WMA_SEND_BEACON_REQ; + + /* No Dialog Token reqd, as a response is not solicited */ + msgQ.reserved = 0; + + /* Fill in tSendbeaconParams members */ + qdf_mem_copy(beaconParams->bssId, psessionEntry->bssId, + sizeof(psessionEntry->bssId)); + + if (LIM_IS_IBSS_ROLE(psessionEntry)) { + beaconParams->timIeOffset = 0; + } else { + beaconParams->timIeOffset = psessionEntry->schBeaconOffsetBegin; + } + + /* p2pIeOffset should be atleast greater than timIeOffset */ + if ((pMac->sch.schObject.p2pIeOffset != 0) && + (pMac->sch.schObject.p2pIeOffset < + psessionEntry->schBeaconOffsetBegin)) { + sch_log(pMac, LOGE, FL("Invalid p2pIeOffset:[%d]"), + pMac->sch.schObject.p2pIeOffset); + QDF_ASSERT(0); + qdf_mem_free(beaconParams); + return eSIR_FAILURE; + } + beaconParams->p2pIeOffset = pMac->sch.schObject.p2pIeOffset; +#ifdef WLAN_SOFTAP_FW_BEACON_TX_PRNT_LOG + sch_log(pMac, LOGE, FL("TimIeOffset:[%d]"), beaconParams->TimIeOffset); +#endif + + beaconParams->beacon = beaconPayload; + beaconParams->beaconLength = (uint32_t) size; + msgQ.bodyptr = beaconParams; + msgQ.bodyval = 0; + + /* Keep a copy of recent beacon frame sent */ + + /* free previous copy of the beacon */ + if (psessionEntry->beacon) { + qdf_mem_free(psessionEntry->beacon); + } + + psessionEntry->bcnLen = 0; + psessionEntry->beacon = NULL; + + psessionEntry->beacon = qdf_mem_malloc(size); + if (psessionEntry->beacon != NULL) { + qdf_mem_copy(psessionEntry->beacon, beaconPayload, size); + psessionEntry->bcnLen = size; + } + + MTRACE(mac_trace_msg_tx(pMac, psessionEntry->peSessionId, msgQ.type)); + retCode = wma_post_ctrl_msg(pMac, &msgQ); + if (eSIR_SUCCESS != retCode) { + sch_log(pMac, LOGE, + FL("Posting SEND_BEACON_REQ to HAL failed, reason=%X"), + retCode); + } else { + sch_log(pMac, LOG2, + FL("Successfully posted WMA_SEND_BEACON_REQ to HAL")); + + if (LIM_IS_AP_ROLE(psessionEntry) && + (pMac->sch.schObject.fBeaconChanged)) { + retCode = lim_send_probe_rsp_template_to_hal(pMac, + psessionEntry, + &psessionEntry-> + DefProbeRspIeBitmap + [0]); + if (eSIR_SUCCESS != retCode) { + /* check whether we have to free any memory */ + sch_log(pMac, LOGE, + FL + ("FAILED to send probe response template with retCode %d"), + retCode); + } + } + } + + return retCode; +} + +static uint32_t lim_remove_p2p_ie_from_add_ie(tpAniSirGlobal pMac, + tpPESession psessionEntry, + uint8_t *addIeWoP2pIe, + uint32_t *addnIELenWoP2pIe) +{ + uint32_t left = psessionEntry->addIeParams.probeRespDataLen; + uint8_t *ptr = psessionEntry->addIeParams.probeRespData_buff; + uint8_t elem_id, elem_len; + uint32_t offset = 0; + uint8_t eid = 0xDD; + + qdf_mem_copy(addIeWoP2pIe, ptr, left); + *addnIELenWoP2pIe = left; + + if (addIeWoP2pIe != NULL) { + while (left >= 2) { + elem_id = ptr[0]; + elem_len = ptr[1]; + left -= 2; + if (elem_len > left) { + sch_log(pMac, LOGE, FL("Invalid IEs")); + return eSIR_FAILURE; + } + if ((elem_id == eid) && + (!qdf_mem_cmp(&ptr[2], + "\x50\x6f\x9a\x09", 4))) { + left -= elem_len; + ptr += (elem_len + 2); + qdf_mem_copy(&addIeWoP2pIe[offset], ptr, left); + *addnIELenWoP2pIe -= (2 + elem_len); + } else { + left -= elem_len; + ptr += (elem_len + 2); + offset += 2 + elem_len; + } + } + } + return eSIR_SUCCESS; +} + +uint32_t lim_send_probe_rsp_template_to_hal(tpAniSirGlobal pMac, + tpPESession psessionEntry, + uint32_t *IeBitmap) +{ + tSirMsgQ msgQ; + uint8_t *pFrame2Hal = psessionEntry->pSchProbeRspTemplate; + tpSendProbeRespParams pprobeRespParams = NULL; + uint32_t retCode = eSIR_FAILURE; + uint32_t nPayload, nBytes = 0, nStatus; + tpSirMacMgmtHdr pMacHdr; + uint32_t addnIEPresent = false; + uint8_t *addIE = NULL; + uint8_t *addIeWoP2pIe = NULL; + uint32_t addnIELenWoP2pIe = 0; + uint32_t retStatus; + tDot11fIEExtCap extracted_extcap; + bool extcap_present = false; + tDot11fProbeResponse *prb_rsp_frm; + tSirRetStatus status; + uint16_t addn_ielen = 0; + + /* Check if probe response IE is present or not */ + addnIEPresent = (psessionEntry->addIeParams.probeRespDataLen != 0); + if (addnIEPresent) { + /* + * probe response template should not have P2P IE. + * In case probe request has P2P IE or WPS IE, the + * probe request will be forwarded to the Host and + * Host will send the probe response. In other cases + * FW will send the probe response. So, if the template + * has P2P IE, the probe response sent to non P2P devices + * by the FW, may also have P2P IE which will fail + * P2P cert case 6.1.3 + */ + addIeWoP2pIe = qdf_mem_malloc(psessionEntry->addIeParams. + probeRespDataLen); + if (NULL == addIeWoP2pIe) { + sch_log(pMac, LOGE, + FL("FAILED to alloc memory when removing P2P IE")); + return eSIR_MEM_ALLOC_FAILED; + } + + retStatus = lim_remove_p2p_ie_from_add_ie(pMac, psessionEntry, + addIeWoP2pIe, &addnIELenWoP2pIe); + if (retStatus != eSIR_SUCCESS) { + qdf_mem_free(addIeWoP2pIe); + return eSIR_FAILURE; + } + + /* Probe rsp IE available */ + /*need to check the data length */ + addIE = qdf_mem_malloc(addnIELenWoP2pIe); + if (NULL == addIE) { + sch_log(pMac, LOGE, + FL("Unable to get WNI_CFG_PROBE_RSP_ADDNIE_DATA1 length")); + qdf_mem_free(addIeWoP2pIe); + return eSIR_MEM_ALLOC_FAILED; + } + addn_ielen = addnIELenWoP2pIe; + + if (addn_ielen <= WNI_CFG_PROBE_RSP_ADDNIE_DATA1_LEN && + addn_ielen && (nBytes + addn_ielen) <= SIR_MAX_PACKET_SIZE) + qdf_mem_copy(addIE, addIeWoP2pIe, addnIELenWoP2pIe); + + qdf_mem_free(addIeWoP2pIe); + + qdf_mem_zero((uint8_t *)&extracted_extcap, + sizeof(tDot11fIEExtCap)); + status = lim_strip_extcap_update_struct(pMac, addIE, + &addn_ielen, &extracted_extcap); + if (eSIR_SUCCESS != status) { + sch_log(pMac, LOG1, FL("extcap not extracted")); + } else { + extcap_present = true; + } + } + + if (addnIEPresent) { + if ((nBytes + addn_ielen) <= SIR_MAX_PACKET_SIZE) + nBytes += addn_ielen; + else + addnIEPresent = false; /* Dont include the IE. */ + } + + /* + * Extcap IE now support variable length, merge Extcap IE from addn_ie + * may change the frame size. Therefore, MUST merge ExtCap IE before + * dot11f get packed payload size. + */ + prb_rsp_frm = &psessionEntry->probeRespFrame; + if (extcap_present) + lim_merge_extcap_struct(&prb_rsp_frm->ExtCap, + &extracted_extcap, + true); + + nStatus = dot11f_get_packed_probe_response_size(pMac, + &psessionEntry->probeRespFrame, &nPayload); + if (DOT11F_FAILED(nStatus)) { + sch_log(pMac, LOGE, + FL("Failed to calculate the packed size for a Probe Response (0x%08x)."), + nStatus); + /* We'll fall back on the worst case scenario: */ + nPayload = sizeof(tDot11fProbeResponse); + } else if (DOT11F_WARNED(nStatus)) { + sch_log(pMac, LOGE, + FL("There were warnings while calculating the packed size for a Probe Response (0x%08x)."), + nStatus); + } + + nBytes += nPayload + sizeof(tSirMacMgmtHdr); + + /* Paranoia: */ + qdf_mem_set(pFrame2Hal, nBytes, 0); + + /* Next, we fill out the buffer descriptor: */ + lim_populate_mac_header(pMac, pFrame2Hal, SIR_MAC_MGMT_FRAME, + SIR_MAC_MGMT_PROBE_RSP, + psessionEntry->selfMacAddr, + psessionEntry->selfMacAddr); + + pMacHdr = (tpSirMacMgmtHdr) pFrame2Hal; + + sir_copy_mac_addr(pMacHdr->bssId, psessionEntry->bssId); + + /* That done, pack the Probe Response: */ + nStatus = + dot11f_pack_probe_response(pMac, &psessionEntry->probeRespFrame, + pFrame2Hal + sizeof(tSirMacMgmtHdr), + nPayload, &nPayload); + + if (DOT11F_FAILED(nStatus)) { + sch_log(pMac, LOGE, + FL("Failed to pack a Probe Response (0x%08x)."), + nStatus); + + qdf_mem_free(addIE); + return retCode; /* allocated! */ + } else if (DOT11F_WARNED(nStatus)) { + sch_log(pMac, LOGE, FL("There were warnings while packing a P" + "robe Response (0x%08x)."), nStatus); + } + + if (addnIEPresent) { + qdf_mem_copy(&pFrame2Hal[nBytes - addn_ielen], + &addIE[0], addn_ielen); + } + + /* free the allocated Memory */ + qdf_mem_free(addIE); + + pprobeRespParams = qdf_mem_malloc(sizeof(tSendProbeRespParams)); + if (NULL == pprobeRespParams) { + sch_log(pMac, LOGE, + FL + ("lim_send_probe_rsp_template_to_hal: HAL probe response params malloc failed for bytes %d"), + nBytes); + } else { + sir_copy_mac_addr(pprobeRespParams->bssId, psessionEntry->bssId); + pprobeRespParams->pProbeRespTemplate = pFrame2Hal; + pprobeRespParams->probeRespTemplateLen = nBytes; + qdf_mem_copy(pprobeRespParams->ucProxyProbeReqValidIEBmap, + IeBitmap, (sizeof(uint32_t) * 8)); + msgQ.type = WMA_SEND_PROBE_RSP_TMPL; + msgQ.reserved = 0; + msgQ.bodyptr = pprobeRespParams; + msgQ.bodyval = 0; + + retCode = wma_post_ctrl_msg(pMac, &msgQ); + if (eSIR_SUCCESS != retCode) { + /* free the allocated Memory */ + sch_log(pMac, LOGE, + FL + ("lim_send_probe_rsp_template_to_hal: FAIL bytes %d retcode[%X]"), + nBytes, retCode); + qdf_mem_free(pprobeRespParams); + } else { + sch_log(pMac, LOG1, + FL + ("lim_send_probe_rsp_template_to_hal: Probe response template msg posted to HAL of bytes %d"), + nBytes); + } + } + + return retCode; +} + +/** + * sch_gen_timing_advert_frame() - Generate the TA frame and populate the buffer + * @pMac: the global MAC context + * @self_addr: the self MAC address + * @buf: the buffer that will contain the frame + * @timestamp_offset: return for the offset of the timestamp field + * @time_value_offset: return for the time_value field in the TA IE + * + * Return: the length of the buffer. + */ +int sch_gen_timing_advert_frame(tpAniSirGlobal mac_ctx, tSirMacAddr self_addr, + uint8_t **buf, uint32_t *timestamp_offset, uint32_t *time_value_offset) +{ + tDot11fTimingAdvertisementFrame frame; + uint32_t payload_size, buf_size; + int status; + struct qdf_mac_addr wildcard_bssid = { + {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, + }; + + qdf_mem_zero((uint8_t *)&frame, sizeof(tDot11fTimingAdvertisementFrame)); + + /* Populate the TA fields */ + status = populate_dot11f_timing_advert_frame(mac_ctx, &frame); + if (status) { + sch_log(mac_ctx, LOGE, FL("Error populating TA frame %x"), + status); + return status; + } + + status = dot11f_get_packed_timing_advertisement_frame_size(mac_ctx, + &frame, &payload_size); + if (DOT11F_FAILED(status)) { + sch_log(mac_ctx, LOGE, FL("Error getting packed frame size %x"), + status); + return status; + } else if (DOT11F_WARNED(status)) { + sch_log(mac_ctx, LOGW, FL("Warning getting packed frame size")); + } + + buf_size = sizeof(tSirMacMgmtHdr) + payload_size; + *buf = qdf_mem_malloc(buf_size); + if (*buf == NULL) { + sch_log(mac_ctx, LOGE, FL("Cannot allocate memory")); + return eSIR_FAILURE; + } + + payload_size = 0; + status = dot11f_pack_timing_advertisement_frame(mac_ctx, &frame, + *buf + sizeof(tSirMacMgmtHdr), buf_size - + sizeof(tSirMacMgmtHdr), &payload_size); + sch_log(mac_ctx, LOGE, FL("TA payload size2 = %d"), payload_size); + if (DOT11F_FAILED(status)) { + sch_log(mac_ctx, LOGE, FL("Error packing frame %x"), status); + goto fail; + } else if (DOT11F_WARNED(status)) { + sch_log(mac_ctx, LOGE, FL("Warning packing frame")); + } + + lim_populate_mac_header(mac_ctx, *buf, SIR_MAC_MGMT_FRAME, + SIR_MAC_MGMT_TIME_ADVERT, wildcard_bssid.bytes, self_addr); + + /* The timestamp field is right after the header */ + *timestamp_offset = sizeof(tSirMacMgmtHdr); + + *time_value_offset = sizeof(tSirMacMgmtHdr) + + sizeof(tDot11fFfTimeStamp) + sizeof(tDot11fFfCapabilities); + + /* Add the Country IE length */ + dot11f_get_packed_ie_country(mac_ctx, &frame.Country, + time_value_offset); + /* Add 2 for Country IE EID and Length fields */ + *time_value_offset += 2; + + /* Add the PowerConstraint IE size */ + if (frame.Country.present == 1) + *time_value_offset += 3; + + /* Add the offset inside TA IE */ + *time_value_offset += 3; + + return payload_size + sizeof(tSirMacMgmtHdr); + +fail: + if (*buf) + qdf_mem_free(*buf); + return status; +} diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/sch/sch_beacon_gen.c b/drivers/staging/qcacld-3.0/core/mac/src/pe/sch/sch_beacon_gen.c new file mode 100644 index 0000000000000000000000000000000000000000..2f06cbd2dea2624a6685201bbf5167a7b46a86cd --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/sch/sch_beacon_gen.c @@ -0,0 +1,996 @@ +/* + * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * This file sch_beacon_gen.cc contains beacon generation related + * functions + * + * Author: Sandesh Goel + * Date: 02/25/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + * + */ + +#include "cds_api.h" +#include "wni_cfg.h" +#include "ani_global.h" +#include "sir_mac_prot_def.h" + +#include "lim_utils.h" +#include "lim_api.h" + +#include "wma_if.h" +#include "cfg_api.h" +#include "sch_api.h" + +#include "parser_api.h" + +#include "sch_debug.h" + +const uint8_t p2p_oui[] = { 0x50, 0x6F, 0x9A, 0x9 }; + +static tSirRetStatus sch_get_p2p_ie_offset(uint8_t *pExtraIe, + uint32_t extraIeLen, + uint16_t *pP2pIeOffset) +{ + tSirRetStatus status = eSIR_FAILURE; + *pP2pIeOffset = 0; + + /* Extra IE is not present */ + if (0 == extraIeLen) { + return status; + } + /* Calculate the P2P IE Offset */ + do { + if (*pExtraIe == 0xDD) { + if (!qdf_mem_cmp + ((void *)(pExtraIe + 2), &p2p_oui, sizeof(p2p_oui))) { + status = eSIR_SUCCESS; + break; + } + } + + (*pP2pIeOffset)++; + pExtraIe++; + } while (--extraIeLen > 0); + + return status; +} + +/** + * sch_append_addn_ie() - adds additional IEs to frame + * @mac_ctx: mac global context + * @session: pe session pointer + * @frm: frame where additional IE is to be added + * @max_bcn_size: max beacon size + * @num_bytes: final size + * @addn_ie: pointer to additional IE + * @addn_ielen: lenght of additional IE + * + * Return: status of operation + */ +static tSirRetStatus +sch_append_addn_ie(tpAniSirGlobal mac_ctx, tpPESession session, + uint8_t *frm, uint32_t max_bcn_size, uint32_t *num_bytes, + uint8_t *addn_ie, uint16_t addn_ielen) +{ + tSirRetStatus status = eSIR_FAILURE; + uint8_t add_ie[WNI_CFG_PROBE_RSP_BCN_ADDNIE_DATA_LEN]; + uint8_t *p2p_ie = NULL; + uint8_t noa_len = 0; + uint8_t noa_strm[SIR_MAX_NOA_ATTR_LEN + SIR_P2P_IE_HEADER_LEN]; + bool valid_ie; + + valid_ie = (addn_ielen <= WNI_CFG_PROBE_RSP_BCN_ADDNIE_DATA_LEN && + addn_ielen && ((addn_ielen + *num_bytes) <= max_bcn_size)); + + if (!valid_ie) + return status; + + qdf_mem_copy(&add_ie[0], addn_ie, addn_ielen); + + p2p_ie = limGetP2pIEPtr(mac_ctx, &add_ie[0], addn_ielen); + if ((p2p_ie != NULL) && !mac_ctx->beacon_offload) { + /* get NoA attribute stream P2P IE */ + noa_len = lim_get_noa_attr_stream(mac_ctx, noa_strm, session); + if (noa_len) { + if ((noa_len + addn_ielen) <= + WNI_CFG_PROBE_RSP_BCN_ADDNIE_DATA_LEN) { + qdf_mem_copy(&add_ie[addn_ielen], noa_strm, + noa_len); + addn_ielen += noa_len; + p2p_ie[1] += noa_len; + } else { + sch_log(mac_ctx, LOGE, + FL("Not able to insert NoA because of length constraint")); + } + } + } + if (addn_ielen <= WNI_CFG_PROBE_RSP_BCN_ADDNIE_DATA_LEN) { + qdf_mem_copy(frm, &add_ie[0], addn_ielen); + *num_bytes = *num_bytes + addn_ielen; + } else { + sch_log(mac_ctx, LOGW, + FL("Not able to insert because of len constraint %d"), + addn_ielen); + } + return status; +} + +/** + * sch_set_fixed_beacon_fields() - sets the fixed params in beacon frame + * @mac_ctx: mac global context + * @session: pe session entry + * @band: out param, band caclculated + * @opr_ch: operating channels + * + * Return: status of operation + */ + +tSirRetStatus +sch_set_fixed_beacon_fields(tpAniSirGlobal mac_ctx, tpPESession session) +{ + tpAniBeaconStruct bcn_struct = (tpAniBeaconStruct) + session->pSchBeaconFrameBegin; + tpSirMacMgmtHdr mac; + uint16_t offset; + uint8_t *ptr; + tDot11fBeacon1 *bcn_1; + tDot11fBeacon2 *bcn_2; + uint32_t i, n_status, n_bytes; + uint32_t wps_ap_enable = 0, tmp; + tDot11fIEWscProbeRes *wsc_prb_res; + uint8_t *extra_ie = NULL; + uint32_t extra_ie_len = 0; + uint16_t extra_ie_offset = 0; + uint16_t p2p_ie_offset = 0; + tSirRetStatus status = eSIR_SUCCESS; + bool is_vht_enabled = false; + uint16_t addn_ielen = 0; + uint8_t *addn_ie = NULL; + tDot11fIEExtCap extracted_extcap; + bool extcap_present = true, addnie_present = false; + + bcn_1 = qdf_mem_malloc(sizeof(tDot11fBeacon1)); + if (NULL == bcn_1) { + sch_log(mac_ctx, LOGE, FL("Failed to allocate memory")); + return eSIR_MEM_ALLOC_FAILED; + } + + bcn_2 = qdf_mem_malloc(sizeof(tDot11fBeacon2)); + if (NULL == bcn_2) { + sch_log(mac_ctx, LOGE, FL("Failed to allocate memory")); + qdf_mem_free(bcn_1); + return eSIR_MEM_ALLOC_FAILED; + } + + wsc_prb_res = qdf_mem_malloc(sizeof(tDot11fIEWscProbeRes)); + if (NULL == wsc_prb_res) { + sch_log(mac_ctx, LOGE, FL("Failed to allocate memory")); + qdf_mem_free(bcn_1); + qdf_mem_free(bcn_2); + return eSIR_MEM_ALLOC_FAILED; + } + + sch_log(mac_ctx, LOG1, FL("Setting fixed beacon fields")); + + /* + * First set the fixed fields: + * set the TFP headers, set the mac header + */ + qdf_mem_set((uint8_t *) &bcn_struct->macHdr, sizeof(tSirMacMgmtHdr), 0); + mac = (tpSirMacMgmtHdr) &bcn_struct->macHdr; + mac->fc.type = SIR_MAC_MGMT_FRAME; + mac->fc.subType = SIR_MAC_MGMT_BEACON; + + for (i = 0; i < 6; i++) + mac->da[i] = 0xff; + + qdf_mem_copy(mac->sa, session->selfMacAddr, + sizeof(session->selfMacAddr)); + qdf_mem_copy(mac->bssId, session->bssId, sizeof(session->bssId)); + + mac->fc.fromDS = 0; + mac->fc.toDS = 0; + + /* Skip over the timestamp (it'll be updated later). */ + bcn_1->BeaconInterval.interval = + session->beaconParams.beaconInterval; + populate_dot11f_capabilities(mac_ctx, &bcn_1->Capabilities, session); + if (session->ssidHidden) { + bcn_1->SSID.present = 1; + /* rest of the fileds are 0 for hidden ssid */ + if ((session->ssId.length) && + (session->ssidHidden == eHIDDEN_SSID_ZERO_CONTENTS)) + bcn_1->SSID.num_ssid = session->ssId.length; + } else { + populate_dot11f_ssid(mac_ctx, &session->ssId, &bcn_1->SSID); + } + + populate_dot11f_supp_rates(mac_ctx, POPULATE_DOT11F_RATES_OPERATIONAL, + &bcn_1->SuppRates, session); + populate_dot11f_ds_params(mac_ctx, &bcn_1->DSParams, + session->currentOperChannel); + populate_dot11f_ibss_params(mac_ctx, &bcn_1->IBSSParams, session); + + offset = sizeof(tAniBeaconStruct); + ptr = session->pSchBeaconFrameBegin + offset; + + if (LIM_IS_AP_ROLE(session)) { + /* Initialize the default IE bitmap to zero */ + qdf_mem_set((uint8_t *) &(session->DefProbeRspIeBitmap), + (sizeof(uint32_t) * 8), 0); + + /* Initialize the default IE bitmap to zero */ + qdf_mem_set((uint8_t *) &(session->probeRespFrame), + sizeof(session->probeRespFrame), 0); + + /* + * Can be efficiently updated whenever new IE added in Probe + * response in future + */ + if (lim_update_probe_rsp_template_ie_bitmap_beacon1(mac_ctx, + bcn_1, session) != eSIR_SUCCESS) + sch_log(mac_ctx, LOGE, + FL("Failed to build ProbeRsp template")); + } + + n_status = dot11f_pack_beacon1(mac_ctx, bcn_1, ptr, + SCH_MAX_BEACON_SIZE - offset, &n_bytes); + if (DOT11F_FAILED(n_status)) { + sch_log(mac_ctx, LOGE, + FL("Failed to packed a tDot11fBeacon1 (0x%08x.)."), + n_status); + qdf_mem_free(bcn_1); + qdf_mem_free(bcn_2); + qdf_mem_free(wsc_prb_res); + return eSIR_FAILURE; + } else if (DOT11F_WARNED(n_status)) { + sch_log(mac_ctx, LOGE, + FL("Warnings while packing a tDot11fBeacon1(0x%08x.)."), + n_status); + } + session->schBeaconOffsetBegin = offset + (uint16_t) n_bytes; + sch_log(mac_ctx, LOG1, FL("Initialized beacon begin, offset %d"), + offset); + + /* Initialize the 'new' fields at the end of the beacon */ + + if ((session->limSystemRole == eLIM_AP_ROLE) && + session->dfsIncludeChanSwIe == true) { + populate_dot_11_f_ext_chann_switch_ann(mac_ctx, + &bcn_2->ext_chan_switch_ann, + session); + sch_log(mac_ctx, LOG1, + FL("ecsa: mode:%d reg:%d chan:%d count:%d"), + bcn_2->ext_chan_switch_ann.switch_mode, + bcn_2->ext_chan_switch_ann.new_reg_class, + bcn_2->ext_chan_switch_ann.new_channel, + bcn_2->ext_chan_switch_ann.switch_count); + } + + populate_dot11_supp_operating_classes(mac_ctx, + &bcn_2->SuppOperatingClasses, session); + populate_dot11f_country(mac_ctx, &bcn_2->Country, session); + if (bcn_1->Capabilities.qos) + populate_dot11f_edca_param_set(mac_ctx, &bcn_2->EDCAParamSet, + session); + + if (session->lim11hEnable) { + populate_dot11f_power_constraints(mac_ctx, + &bcn_2->PowerConstraints); + populate_dot11f_tpc_report(mac_ctx, &bcn_2->TPCReport, session); + /* Need to insert channel switch announcement here */ + if ((LIM_IS_AP_ROLE(session) + || LIM_IS_P2P_DEVICE_GO(session)) + && session->dfsIncludeChanSwIe == true) { + /* + * Channel switch announcement only if radar is detected + * and SAP has instructed to announce channel switch IEs + * in beacon and probe responses + */ + populate_dot11f_chan_switch_ann(mac_ctx, + &bcn_2->ChanSwitchAnn, session); + sch_log(mac_ctx, LOG1, + FL("csa: mode:%d chan:%d count:%d"), + bcn_2->ChanSwitchAnn.switchMode, + bcn_2->ChanSwitchAnn.newChannel, + bcn_2->ChanSwitchAnn.switchCount); + + /* + * TODO: depending the CB mode, extended channel switch + * announcement need to be called + */ + /* + populate_dot11f_ext_chan_switch_ann(mac_ctx, + &bcn_2->ExtChanSwitchAnn, session); + */ + /* + * TODO: If in 11AC mode, wider bw channel switch + * announcement needs to be called + */ + /* + populate_dot11f_wider_bw_chan_switch_ann(mac_ctx, + &bcn_2->WiderBWChanSwitchAnn, session); + */ + /* + * Populate the Channel Switch Wrapper Element if + * SAP operates in 40/80 Mhz Channel Width. + */ + if (true == session->dfsIncludeChanWrapperIe) { + populate_dot11f_chan_switch_wrapper(mac_ctx, + &bcn_2->ChannelSwitchWrapper, session); + sch_log(mac_ctx, LOG1, + FL("wrapper: width:%d f0:%d f1:%d"), + bcn_2->ChannelSwitchWrapper. + WiderBWChanSwitchAnn.newChanWidth, + bcn_2->ChannelSwitchWrapper. + WiderBWChanSwitchAnn.newCenterChanFreq0, + bcn_2->ChannelSwitchWrapper. + WiderBWChanSwitchAnn.newCenterChanFreq1 + ); + } + } + } + +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE + /* populate proprietary IE for MDM device operating in AP-MCC */ + populate_dot11f_avoid_channel_ie(mac_ctx, &bcn_2->QComVendorIE, + session); +#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ + + if (session->dot11mode != WNI_CFG_DOT11_MODE_11B) + populate_dot11f_erp_info(mac_ctx, &bcn_2->ERPInfo, session); + + if (session->htCapability) { + populate_dot11f_ht_caps(mac_ctx, session, &bcn_2->HTCaps); + populate_dot11f_ht_info(mac_ctx, &bcn_2->HTInfo, session); + } + if (session->vhtCapability) { + sch_log(mac_ctx, LOGW, FL("Populate VHT IEs in Beacon")); + populate_dot11f_vht_caps(mac_ctx, session, &bcn_2->VHTCaps); + populate_dot11f_vht_operation(mac_ctx, session, + &bcn_2->VHTOperation); + is_vht_enabled = true; + /* following is for MU MIMO: we do not support it yet */ + /* + populate_dot11f_vht_ext_bss_load( mac_ctx, &bcn2.VHTExtBssLoad); + */ + if (session->gLimOperatingMode.present) + populate_dot11f_operating_mode(mac_ctx, + &bcn_2->OperatingMode, session); + } + if (session->limSystemRole != eLIM_STA_IN_IBSS_ROLE) + populate_dot11f_ext_cap(mac_ctx, is_vht_enabled, &bcn_2->ExtCap, + session); + populate_dot11f_ext_supp_rates(mac_ctx, + POPULATE_DOT11F_RATES_OPERATIONAL, + &bcn_2->ExtSuppRates, session); + + if (session->pLimStartBssReq != NULL) { + populate_dot11f_wpa(mac_ctx, &session->pLimStartBssReq->rsnIE, + &bcn_2->WPA); + populate_dot11f_rsn_opaque(mac_ctx, + &session->pLimStartBssReq->rsnIE, + &bcn_2->RSNOpaque); + } + + if (session->limWmeEnabled) + populate_dot11f_wmm(mac_ctx, &bcn_2->WMMInfoAp, + &bcn_2->WMMParams, &bcn_2->WMMCaps, session); + if (LIM_IS_AP_ROLE(session)) { + if (session->wps_state != SAP_WPS_DISABLED) { + populate_dot11f_beacon_wpsi_es(mac_ctx, + &bcn_2->WscBeacon, session); + } + } else { + if (wlan_cfg_get_int(mac_ctx, + (uint16_t) WNI_CFG_WPS_ENABLE, &tmp) != eSIR_SUCCESS) + sch_log(mac_ctx, LOGP, FL("Failed to cfg get id %d"), + WNI_CFG_WPS_ENABLE); + + wps_ap_enable = tmp & WNI_CFG_WPS_ENABLE_AP; + + if (wps_ap_enable) + populate_dot11f_wsc(mac_ctx, &bcn_2->WscBeacon); + + if (mac_ctx->lim.wscIeInfo.wscEnrollmentState == + eLIM_WSC_ENROLL_BEGIN) { + populate_dot11f_wsc_registrar_info(mac_ctx, + &bcn_2->WscBeacon); + mac_ctx->lim.wscIeInfo.wscEnrollmentState = + eLIM_WSC_ENROLL_IN_PROGRESS; + } + + if (mac_ctx->lim.wscIeInfo.wscEnrollmentState == + eLIM_WSC_ENROLL_END) { + de_populate_dot11f_wsc_registrar_info(mac_ctx, + &bcn_2->WscBeacon); + mac_ctx->lim.wscIeInfo.wscEnrollmentState = + eLIM_WSC_ENROLL_NOOP; + } + } + + if ((LIM_IS_AP_ROLE(session))) { + /* + * Can be efficiently updated whenever new IE added in Probe + * response in future + */ + lim_update_probe_rsp_template_ie_bitmap_beacon2(mac_ctx, bcn_2, + &session->DefProbeRspIeBitmap[0], + &session->probeRespFrame); + + /* update probe response WPS IE instead of beacon WPS IE */ + if (session->wps_state != SAP_WPS_DISABLED) { + if (session->APWPSIEs.SirWPSProbeRspIE.FieldPresent) + populate_dot11f_probe_res_wpsi_es(mac_ctx, + wsc_prb_res, session); + else + wsc_prb_res->present = 0; + if (wsc_prb_res->present) { + set_probe_rsp_ie_bitmap( + &session->DefProbeRspIeBitmap[0], + SIR_MAC_WPA_EID); + qdf_mem_copy((void *) + &session->probeRespFrame.WscProbeRes, + (void *)wsc_prb_res, + sizeof(tDot11fIEWscProbeRes)); + } + } + + } + + addnie_present = (session->addIeParams.probeRespBCNDataLen != 0); + if (addnie_present) { + addn_ielen = session->addIeParams.probeRespBCNDataLen; + addn_ie = qdf_mem_malloc(addn_ielen); + if (!addn_ie) { + sch_log(mac_ctx, LOGE, FL("addn_ie malloc failed")); + qdf_mem_free(bcn_1); + qdf_mem_free(bcn_2); + qdf_mem_free(wsc_prb_res); + return eSIR_MEM_ALLOC_FAILED; + } + qdf_mem_copy(addn_ie, + session->addIeParams.probeRespBCNData_buff, + addn_ielen); + + qdf_mem_zero((uint8_t *)&extracted_extcap, + sizeof(tDot11fIEExtCap)); + status = lim_strip_extcap_update_struct(mac_ctx, addn_ie, + &addn_ielen, &extracted_extcap); + if (eSIR_SUCCESS != status) { + extcap_present = false; + sch_log(mac_ctx, LOG1, FL("extcap not extracted")); + } + /* merge extcap IE */ + if (extcap_present && + session->limSystemRole != eLIM_STA_IN_IBSS_ROLE) + lim_merge_extcap_struct(&bcn_2->ExtCap, + &extracted_extcap, + true); + + } + + n_status = dot11f_pack_beacon2(mac_ctx, bcn_2, + session->pSchBeaconFrameEnd, + SCH_MAX_BEACON_SIZE, &n_bytes); + if (DOT11F_FAILED(n_status)) { + sch_log(mac_ctx, LOGE, + FL("Failed to packed a tDot11fBeacon2 (0x%08x.)."), + n_status); + qdf_mem_free(bcn_1); + qdf_mem_free(bcn_2); + qdf_mem_free(wsc_prb_res); + qdf_mem_free(addn_ie); + return eSIR_FAILURE; + } else if (DOT11F_WARNED(n_status)) { + sch_log(mac_ctx, LOGE, + FL("Warnings while packing a tDot11fBeacon2(0x%08x.)."), + n_status); + } + + extra_ie = session->pSchBeaconFrameEnd + n_bytes; + extra_ie_offset = n_bytes; + + /* TODO: Append additional IE here. */ + if (addn_ielen > 0) + sch_append_addn_ie(mac_ctx, session, + session->pSchBeaconFrameEnd + n_bytes, + SCH_MAX_BEACON_SIZE, &n_bytes, addn_ie, addn_ielen); + + session->schBeaconOffsetEnd = (uint16_t) n_bytes; + extra_ie_len = n_bytes - extra_ie_offset; + /* Get the p2p Ie Offset */ + status = sch_get_p2p_ie_offset(extra_ie, extra_ie_len, &p2p_ie_offset); + if (eSIR_SUCCESS == status) + /* Update the P2P Ie Offset */ + mac_ctx->sch.schObject.p2pIeOffset = + session->schBeaconOffsetBegin + TIM_IE_SIZE + + extra_ie_offset + p2p_ie_offset; + else + mac_ctx->sch.schObject.p2pIeOffset = 0; + + sch_log(mac_ctx, LOG1, FL("Initialized beacon end, offset %d"), + session->schBeaconOffsetEnd); + mac_ctx->sch.schObject.fBeaconChanged = 1; + qdf_mem_free(bcn_1); + qdf_mem_free(bcn_2); + qdf_mem_free(wsc_prb_res); + qdf_mem_free(addn_ie); + return eSIR_SUCCESS; +} + +tSirRetStatus lim_update_probe_rsp_template_ie_bitmap_beacon1(tpAniSirGlobal pMac, + tDot11fBeacon1 *beacon1, + tpPESession + psessionEntry) +{ + uint32_t *DefProbeRspIeBitmap; + tDot11fProbeResponse *prb_rsp; + if (!psessionEntry) { + sch_log(pMac, LOGE, FL("PESession is null!")); + return eSIR_FAILURE; + } + DefProbeRspIeBitmap = &psessionEntry->DefProbeRspIeBitmap[0]; + prb_rsp = &psessionEntry->probeRespFrame; + prb_rsp->BeaconInterval = beacon1->BeaconInterval; + qdf_mem_copy((void *)&prb_rsp->Capabilities, + (void *)&beacon1->Capabilities, + sizeof(beacon1->Capabilities)); + + /* SSID */ + if (beacon1->SSID.present) { + set_probe_rsp_ie_bitmap(DefProbeRspIeBitmap, SIR_MAC_SSID_EID); + /* populating it, because probe response has to go with SSID even in hidden case */ + populate_dot11f_ssid(pMac, &psessionEntry->ssId, &prb_rsp->SSID); + } + /* supported rates */ + if (beacon1->SuppRates.present) { + set_probe_rsp_ie_bitmap(DefProbeRspIeBitmap, SIR_MAC_RATESET_EID); + qdf_mem_copy((void *)&prb_rsp->SuppRates, + (void *)&beacon1->SuppRates, + sizeof(beacon1->SuppRates)); + + } + /* DS Parameter set */ + if (beacon1->DSParams.present) { + set_probe_rsp_ie_bitmap(DefProbeRspIeBitmap, + SIR_MAC_DS_PARAM_SET_EID); + qdf_mem_copy((void *)&prb_rsp->DSParams, + (void *)&beacon1->DSParams, + sizeof(beacon1->DSParams)); + + } + + /* IBSS params will not be present in the Beacons transmitted by AP */ + return eSIR_SUCCESS; +} + +void lim_update_probe_rsp_template_ie_bitmap_beacon2(tpAniSirGlobal pMac, + tDot11fBeacon2 *beacon2, + uint32_t *DefProbeRspIeBitmap, + tDot11fProbeResponse *prb_rsp) +{ + /* IBSS parameter set - will not be present in probe response tx by AP */ + /* country */ + if (beacon2->Country.present) { + set_probe_rsp_ie_bitmap(DefProbeRspIeBitmap, SIR_MAC_COUNTRY_EID); + qdf_mem_copy((void *)&prb_rsp->Country, + (void *)&beacon2->Country, + sizeof(beacon2->Country)); + + } + /* Power constraint */ + if (beacon2->PowerConstraints.present) { + set_probe_rsp_ie_bitmap(DefProbeRspIeBitmap, + SIR_MAC_PWR_CONSTRAINT_EID); + qdf_mem_copy((void *)&prb_rsp->PowerConstraints, + (void *)&beacon2->PowerConstraints, + sizeof(beacon2->PowerConstraints)); + + } + /* Channel Switch Annoouncement SIR_MAC_CHNL_SWITCH_ANN_EID */ + if (beacon2->ChanSwitchAnn.present) { + set_probe_rsp_ie_bitmap(DefProbeRspIeBitmap, + SIR_MAC_CHNL_SWITCH_ANN_EID); + qdf_mem_copy((void *)&prb_rsp->ChanSwitchAnn, + (void *)&beacon2->ChanSwitchAnn, + sizeof(beacon2->ChanSwitchAnn)); + + } + + /* EXT Channel Switch Announcement CHNL_EXTENDED_SWITCH_ANN_EID*/ + if (beacon2->ext_chan_switch_ann.present) { + set_probe_rsp_ie_bitmap(DefProbeRspIeBitmap, + SIR_MAC_CHNL_EXTENDED_SWITCH_ANN_EID); + qdf_mem_copy((void *)&prb_rsp->ext_chan_switch_ann, + (void *)&beacon2->ext_chan_switch_ann, + sizeof(beacon2->ext_chan_switch_ann)); + } + + /* Supported operating class */ + if (beacon2->SuppOperatingClasses.present) { + set_probe_rsp_ie_bitmap(DefProbeRspIeBitmap, + SIR_MAC_OPERATING_CLASS_EID); + qdf_mem_copy((void *)&prb_rsp->SuppOperatingClasses, + (void *)&beacon2->SuppOperatingClasses, + sizeof(beacon2->SuppOperatingClasses)); + } + +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE + if (beacon2->QComVendorIE.present) { + set_probe_rsp_ie_bitmap(DefProbeRspIeBitmap, + SIR_MAC_QCOM_VENDOR_EID); + qdf_mem_copy((void *)&prb_rsp->QComVendorIE, + (void *)&beacon2->QComVendorIE, + sizeof(beacon2->QComVendorIE)); + } +#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ + + /* ERP information */ + if (beacon2->ERPInfo.present) { + set_probe_rsp_ie_bitmap(DefProbeRspIeBitmap, SIR_MAC_ERP_INFO_EID); + qdf_mem_copy((void *)&prb_rsp->ERPInfo, + (void *)&beacon2->ERPInfo, + sizeof(beacon2->ERPInfo)); + + } + /* Extended supported rates */ + if (beacon2->ExtSuppRates.present) { + set_probe_rsp_ie_bitmap(DefProbeRspIeBitmap, + SIR_MAC_EXTENDED_RATE_EID); + qdf_mem_copy((void *)&prb_rsp->ExtSuppRates, + (void *)&beacon2->ExtSuppRates, + sizeof(beacon2->ExtSuppRates)); + + } + + /* WPA */ + if (beacon2->WPA.present) { + set_probe_rsp_ie_bitmap(DefProbeRspIeBitmap, SIR_MAC_WPA_EID); + qdf_mem_copy((void *)&prb_rsp->WPA, (void *)&beacon2->WPA, + sizeof(beacon2->WPA)); + + } + + /* RSN */ + if (beacon2->RSNOpaque.present) { + set_probe_rsp_ie_bitmap(DefProbeRspIeBitmap, SIR_MAC_RSN_EID); + qdf_mem_copy((void *)&prb_rsp->RSNOpaque, + (void *)&beacon2->RSNOpaque, + sizeof(beacon2->RSNOpaque)); + } + + /* EDCA Parameter set */ + if (beacon2->EDCAParamSet.present) { + set_probe_rsp_ie_bitmap(DefProbeRspIeBitmap, + SIR_MAC_EDCA_PARAM_SET_EID); + qdf_mem_copy((void *)&prb_rsp->EDCAParamSet, + (void *)&beacon2->EDCAParamSet, + sizeof(beacon2->EDCAParamSet)); + + } + /* Vendor specific - currently no vendor specific IEs added */ + /* Requested IEs - currently we are not processing this will be added later */ + /* HT capability IE */ + if (beacon2->HTCaps.present) { + set_probe_rsp_ie_bitmap(DefProbeRspIeBitmap, + SIR_MAC_HT_CAPABILITIES_EID); + qdf_mem_copy((void *)&prb_rsp->HTCaps, (void *)&beacon2->HTCaps, + sizeof(beacon2->HTCaps)); + } + /* HT Info IE */ + if (beacon2->HTInfo.present) { + set_probe_rsp_ie_bitmap(DefProbeRspIeBitmap, SIR_MAC_HT_INFO_EID); + qdf_mem_copy((void *)&prb_rsp->HTInfo, (void *)&beacon2->HTInfo, + sizeof(beacon2->HTInfo)); + } + if (beacon2->VHTCaps.present) { + set_probe_rsp_ie_bitmap(DefProbeRspIeBitmap, + SIR_MAC_VHT_CAPABILITIES_EID); + qdf_mem_copy((void *)&prb_rsp->VHTCaps, + (void *)&beacon2->VHTCaps, + sizeof(beacon2->VHTCaps)); + } + if (beacon2->VHTOperation.present) { + set_probe_rsp_ie_bitmap(DefProbeRspIeBitmap, + SIR_MAC_VHT_OPERATION_EID); + qdf_mem_copy((void *)&prb_rsp->VHTOperation, + (void *)&beacon2->VHTOperation, + sizeof(beacon2->VHTOperation)); + } + if (beacon2->VHTExtBssLoad.present) { + set_probe_rsp_ie_bitmap(DefProbeRspIeBitmap, + SIR_MAC_VHT_EXT_BSS_LOAD_EID); + qdf_mem_copy((void *)&prb_rsp->VHTExtBssLoad, + (void *)&beacon2->VHTExtBssLoad, + sizeof(beacon2->VHTExtBssLoad)); + } + /* WMM IE */ + if (beacon2->WMMParams.present) { + set_probe_rsp_ie_bitmap(DefProbeRspIeBitmap, SIR_MAC_WPA_EID); + qdf_mem_copy((void *)&prb_rsp->WMMParams, + (void *)&beacon2->WMMParams, + sizeof(beacon2->WMMParams)); + } + /* WMM capability - most of the case won't be present */ + if (beacon2->WMMCaps.present) { + set_probe_rsp_ie_bitmap(DefProbeRspIeBitmap, SIR_MAC_WPA_EID); + qdf_mem_copy((void *)&prb_rsp->WMMCaps, + (void *)&beacon2->WMMCaps, + sizeof(beacon2->WMMCaps)); + } + + /* Extended Capability */ + if (beacon2->ExtCap.present) { + set_probe_rsp_ie_bitmap(DefProbeRspIeBitmap, DOT11F_EID_EXTCAP); + qdf_mem_copy((void *)&prb_rsp->ExtCap, + (void *)&beacon2->ExtCap, + sizeof(beacon2->ExtCap)); + } + +} + +void set_probe_rsp_ie_bitmap(uint32_t *IeBitmap, uint32_t pos) +{ + uint32_t index, temp; + + index = pos >> 5; + if (index >= 8) { + return; + } + temp = IeBitmap[index]; + + temp |= 1 << (pos & 0x1F); + + IeBitmap[index] = temp; +} + +/* -------------------------------------------------------------------- */ +/** + * write_beacon_to_memory + * + * FUNCTION: + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param None + * @param size Size of the beacon to write to memory + * @param length Length field of the beacon to write to memory + * @return None + */ + +static void write_beacon_to_memory(tpAniSirGlobal pMac, uint16_t size, + uint16_t length, tpPESession psessionEntry) +{ + uint16_t i; + tpAniBeaconStruct pBeacon; + + /* copy end of beacon only if length > 0 */ + if (length > 0) { + for (i = 0; i < psessionEntry->schBeaconOffsetEnd; i++) + psessionEntry->pSchBeaconFrameBegin[size++] = + psessionEntry->pSchBeaconFrameEnd[i]; + } + /* Update the beacon length */ + pBeacon = (tpAniBeaconStruct) psessionEntry->pSchBeaconFrameBegin; + /* Do not include the beaconLength indicator itself */ + if (length == 0) { + pBeacon->beaconLength = 0; + /* Dont copy entire beacon, Copy length field alone */ + size = 4; + } else + pBeacon->beaconLength = (uint32_t) size - sizeof(uint32_t); + + /* write size bytes from pSchBeaconFrameBegin */ + PELOG2(sch_log(pMac, LOG2, FL("Beacon size - %d bytes"), size);) + PELOG2(sir_dump_buf + (pMac, SIR_SCH_MODULE_ID, LOG2, + psessionEntry->pSchBeaconFrameBegin, size); + ) + + if (!pMac->sch.schObject.fBeaconChanged) + return; + + pMac->sch.gSchGenBeacon = 1; + if (pMac->sch.gSchGenBeacon) { + pMac->sch.gSchBeaconsSent++; + + /* */ + /* Copy beacon data to SoftMAC shared memory... */ + /* Do this by sending a message to HAL */ + /* */ + + size = (size + 3) & (~3); + if (eSIR_SUCCESS != + sch_send_beacon_req(pMac, psessionEntry->pSchBeaconFrameBegin, + size, psessionEntry)) + PELOGE(sch_log + (pMac, LOGE, + FL + ("sch_send_beacon_req() returned an error (zsize %d)"), + size); + ) + else { + pMac->sch.gSchBeaconsWritten++; + } + } + pMac->sch.schObject.fBeaconChanged = 0; +} + +/** + * sch_generate_tim + * + * FUNCTION: + * Generate TIM + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param pMac pointer to global mac structure + * @param **pPtr pointer to the buffer, where the TIM bit is to be written. + * @param *timLength pointer to limLength, which needs to be returned. + * @return None + */ +void sch_generate_tim(tpAniSirGlobal pMac, uint8_t **pPtr, uint16_t *timLength, + uint8_t dtimPeriod) +{ + uint8_t *ptr = *pPtr; + uint32_t val = 0; + uint32_t minAid = 1; /* Always start with AID 1 as minimum */ + uint32_t maxAid = HAL_NUM_STA; + + /* Generate partial virtual bitmap */ + uint8_t N1 = minAid / 8; + uint8_t N2 = maxAid / 8; + if (N1 & 1) + N1--; + + *timLength = N2 - N1 + 4; + val = dtimPeriod; + + /* + * Write 0xFF to firmware's field to detect firmware's mal-function + * early. DTIM count and bitmap control usually cannot be 0xFF, so it + * is easy to know that firmware never updated DTIM count/bitmap control + * field after host driver downloaded beacon template if end-user complaints + * that DTIM count and bitmapControl is 0xFF. + */ + *ptr++ = SIR_MAC_TIM_EID; + *ptr++ = (uint8_t) (*timLength); + /* location for dtimCount. will be filled in by FW. */ + *ptr++ = 0xFF; + *ptr++ = (uint8_t) val; + /* location for bitmap control. will be filled in by FW. */ + *ptr++ = 0xFF; + ptr += (N2 - N1 + 1); + + PELOG2(sir_dump_buf + (pMac, SIR_SCH_MODULE_ID, LOG2, *pPtr, (*timLength) + 2); + ) + * pPtr = ptr; +} +/* -------------------------------------------------------------------- */ +/** + * @function: SchProcessPreBeaconInd + * + * @brief : Process the PreBeacon Indication from the Lim + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param : pMac - tpAniSirGlobal + * + * @return None + */ + +void sch_process_pre_beacon_ind(tpAniSirGlobal pMac, tpSirMsgQ limMsg) +{ + tpBeaconGenParams pMsg = (tpBeaconGenParams) limMsg->bodyptr; + uint32_t beaconSize; + tpPESession psessionEntry; + uint8_t sessionId; + + psessionEntry = pe_find_session_by_bssid(pMac, pMsg->bssId, &sessionId); + if (psessionEntry == NULL) { + PELOGE(sch_log(pMac, LOGE, FL("session lookup fails"));) + goto end; + } + + beaconSize = psessionEntry->schBeaconOffsetBegin; + + /* If SME is not in normal mode, no need to generate beacon */ + if (psessionEntry->limSmeState != eLIM_SME_NORMAL_STATE) { + PELOGE(sch_log + (pMac, LOG1, + FL("PreBeaconInd received in invalid state: %d"), + psessionEntry->limSmeState); + ) + goto end; + } + + switch (GET_LIM_SYSTEM_ROLE(psessionEntry)) { + + case eLIM_STA_IN_IBSS_ROLE: + /* generate IBSS parameter set */ + if (psessionEntry->statypeForBss == STA_ENTRY_SELF) + write_beacon_to_memory(pMac, (uint16_t) beaconSize, + (uint16_t) beaconSize, + psessionEntry); + else + PELOGE(sch_log + (pMac, LOGE, + FL + ("can not send beacon for PEER session entry")); + ) + break; + + case eLIM_AP_ROLE: { + uint8_t *ptr = + &psessionEntry->pSchBeaconFrameBegin[psessionEntry-> + schBeaconOffsetBegin]; + uint16_t timLength = 0; + if (psessionEntry->statypeForBss == STA_ENTRY_SELF) { + sch_generate_tim(pMac, &ptr, &timLength, + psessionEntry->dtimPeriod); + beaconSize += 2 + timLength; + write_beacon_to_memory(pMac, (uint16_t) beaconSize, + (uint16_t) beaconSize, + psessionEntry); + } else + PELOGE(sch_log + (pMac, LOGE, + FL + ("can not send beacon for PEER session entry")); + ) + } + break; + + default: + PELOGE(sch_log + (pMac, LOGE, + FL + ("Error-PE has Receive PreBeconGenIndication when System is in %d role"), + GET_LIM_SYSTEM_ROLE(psessionEntry)); + ) + } + +end: + qdf_mem_free(pMsg); + + } diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/sch/sch_beacon_process.c b/drivers/staging/qcacld-3.0/core/mac/src/pe/sch/sch_beacon_process.c new file mode 100644 index 0000000000000000000000000000000000000000..23bd6d50897de229696287a2bb90efe949913f73 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/sch/sch_beacon_process.c @@ -0,0 +1,1054 @@ +/* + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * This file sch_beacon_process.cc contains beacon processing related + * functions + * + * Author: Sandesh Goel + * Date: 02/25/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + * + */ + +#include "cds_api.h" +#include "wni_cfg.h" + +#include "cfg_api.h" +#include "lim_api.h" +#include "utils_api.h" +#include "sch_debug.h" +#include "sch_api.h" + +#include "lim_utils.h" +#include "lim_send_messages.h" +#include "lim_sta_hash_api.h" + +#include "rrm_api.h" + +#ifdef FEATURE_WLAN_DIAG_SUPPORT +#include "host_diag_core_log.h" +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + +#include "wma.h" +/** + * Number of bytes of variation in beacon length from the last beacon + * to trigger reprogramming of rx delay register + */ +#define SCH_BEACON_LEN_DELTA 3 + +/* calculate 2^cw - 1 */ +#define CW_GET(cw) (((cw) == 0) ? 1 : ((1 << (cw)) - 1)) + +static void +ap_beacon_process_5_ghz(tpAniSirGlobal mac_ctx, uint8_t *rx_pkt_info, + tpSchBeaconStruct bcn_struct, + tpUpdateBeaconParams bcn_prm, tpPESession session, + uint32_t phy_mode) +{ + tpSirMacMgmtHdr mac_hdr = WMA_GET_RX_MAC_HEADER(rx_pkt_info); + if (!session->htCapability) + return; + + if (bcn_struct->channelNumber != session->currentOperChannel) + return; + + /* 11a (non HT) AP overlaps or */ + /* HT AP with HT op mode as mixed overlaps. */ + /* HT AP with HT op mode as overlap legacy overlaps. */ + if (!bcn_struct->HTInfo.present + || (eSIR_HT_OP_MODE_MIXED == bcn_struct->HTInfo.opMode) + || (eSIR_HT_OP_MODE_OVERLAP_LEGACY == bcn_struct->HTInfo.opMode)) { + lim_update_overlap_sta_param(mac_ctx, mac_hdr->bssId, + &(mac_ctx->lim.gLimOverlap11aParams)); + + if (mac_ctx->lim.gLimOverlap11aParams.numSta + && !mac_ctx->lim.gLimOverlap11aParams.protectionEnabled) { + lim_update_11a_protection(mac_ctx, true, true, + bcn_prm, session); + } + return; + } + /* HT AP with HT20 op mode overlaps. */ + if (eSIR_HT_OP_MODE_NO_LEGACY_20MHZ_HT != bcn_struct->HTInfo.opMode) + return; + + lim_update_overlap_sta_param(mac_ctx, mac_hdr->bssId, + &(mac_ctx->lim.gLimOverlapHt20Params)); + + if (mac_ctx->lim.gLimOverlapHt20Params.numSta + && !mac_ctx->lim.gLimOverlapHt20Params.protectionEnabled) + lim_enable_ht20_protection(mac_ctx, true, true, + bcn_prm, session); +} + +static void +ap_beacon_process_24_ghz(tpAniSirGlobal mac_ctx, uint8_t *rx_pkt_info, + tpSchBeaconStruct bcn_struct, + tpUpdateBeaconParams bcn_prm, tpPESession session, + uint32_t phy_mode) +{ + tpSirMacMgmtHdr mac_hdr = WMA_GET_RX_MAC_HEADER(rx_pkt_info); + bool tmp_exp = false; + /* We are 11G AP. */ + if ((phy_mode == WNI_CFG_PHY_MODE_11G) && + (false == session->htCapability)) { + if (bcn_struct->channelNumber != session->currentOperChannel) + return; + + tmp_exp = (!bcn_struct->erpPresent + && !bcn_struct->HTInfo.present) + /* if erp not present then 11B AP overlapping */ + || (!mac_ctx->roam.configParam.ignore_peer_erp_info && + bcn_struct->erpPresent && + (bcn_struct->erpIEInfo.useProtection + || bcn_struct->erpIEInfo.nonErpPresent)); + if (!tmp_exp) + return; +#ifdef FEATURE_WLAN_ESE + if (session->isESEconnection) + QDF_TRACE(QDF_MODULE_ID_PE, + QDF_TRACE_LEVEL_INFO, + FL("[INFOLOG]ESE 11g erpPresent=%d useProtection=%d nonErpPresent=%d"), + bcn_struct->erpPresent, + bcn_struct->erpIEInfo.useProtection, + bcn_struct->erpIEInfo.nonErpPresent); +#endif + lim_enable_overlap11g_protection(mac_ctx, bcn_prm, + mac_hdr, session); + return; + } + /* handling the case when HT AP has overlapping legacy BSS. */ + if (!session->htCapability) + return; + + if (bcn_struct->channelNumber != session->currentOperChannel) + return; + + tmp_exp = (!bcn_struct->erpPresent && !bcn_struct->HTInfo.present) + /* if erp not present then 11B AP overlapping */ + || (!mac_ctx->roam.configParam.ignore_peer_erp_info && + bcn_struct->erpPresent && + (bcn_struct->erpIEInfo.useProtection + || bcn_struct->erpIEInfo.nonErpPresent)); + if (tmp_exp) { +#ifdef FEATURE_WLAN_ESE + if (session->isESEconnection) { + QDF_TRACE(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_INFO, + FL("[INFOLOG]ESE 11g erpPresent=%d useProtection=%d nonErpPresent=%d"), + bcn_struct->erpPresent, + bcn_struct->erpIEInfo.useProtection, + bcn_struct->erpIEInfo.nonErpPresent); + } +#endif + lim_enable_overlap11g_protection(mac_ctx, bcn_prm, + mac_hdr, session); + } + /* 11g device overlaps */ + tmp_exp = bcn_struct->erpPresent + && !(bcn_struct->erpIEInfo.useProtection + || bcn_struct->erpIEInfo.nonErpPresent) + && !(bcn_struct->HTInfo.present); + if (tmp_exp) { + lim_update_overlap_sta_param(mac_ctx, mac_hdr->bssId, + &(session->gLimOverlap11gParams)); + + if (session->gLimOverlap11gParams.numSta + && !session->gLimOverlap11gParams.protectionEnabled) + lim_enable_ht_protection_from11g(mac_ctx, true, true, + bcn_prm, session); + } + /* ht device overlaps. + * here we will check for HT related devices only which might need + * protection. check for 11b and 11g is already done in the previous + * blocks. so we will not check for HT operating mode as MIXED. + */ + if (!bcn_struct->HTInfo.present) + return; + + /* + * if we are not already in mixed mode or legacy mode as HT operating + * mode and received beacon has HT operating mode as legacy then we need + * to enable protection from 11g station. we don't need protection from + * 11b because if that's needed then our operating mode would have + * already been set to legacy in the previous blocks. + */ + if ((eSIR_HT_OP_MODE_OVERLAP_LEGACY == bcn_struct->HTInfo.opMode) && + !mac_ctx->roam.configParam.ignore_peer_ht_opmode) { + if (eSIR_HT_OP_MODE_OVERLAP_LEGACY == mac_ctx->lim.gHTOperMode + || eSIR_HT_OP_MODE_MIXED == mac_ctx->lim.gHTOperMode) + return; + lim_update_overlap_sta_param(mac_ctx, mac_hdr->bssId, + &(session->gLimOverlap11gParams)); + if (session->gLimOverlap11gParams.numSta + && !session->gLimOverlap11gParams.protectionEnabled) + lim_enable_ht_protection_from11g(mac_ctx, true, true, + bcn_prm, session); + return; + } + + if (eSIR_HT_OP_MODE_NO_LEGACY_20MHZ_HT == bcn_struct->HTInfo.opMode) { + lim_update_overlap_sta_param(mac_ctx, mac_hdr->bssId, + &(session->gLimOverlapHt20Params)); + if (session->gLimOverlapHt20Params.numSta + && !session->gLimOverlapHt20Params.protectionEnabled) + lim_enable_ht20_protection(mac_ctx, true, true, + bcn_prm, session); + } +} + +/** + * ap_beacon_process() - processes incoming beacons + * + * @mac_ctx: mac global context + * @rx_pkt_info: incoming beacon packet + * @bcn_struct: beacon struct + * @bcn_prm: beacon params + * @session: pe session entry + * + * Return: void + */ +static void +ap_beacon_process(tpAniSirGlobal mac_ctx, uint8_t *rx_pkt_info, + tpSchBeaconStruct bcn_struct, + tpUpdateBeaconParams bcn_prm, tpPESession session) +{ + uint32_t phy_mode; + tSirRFBand rf_band = SIR_BAND_UNKNOWN; + /* Get RF band from session */ + rf_band = session->limRFBand; + + lim_get_phy_mode(mac_ctx, &phy_mode, session); + + if (SIR_BAND_5_GHZ == rf_band) + ap_beacon_process_5_ghz(mac_ctx, rx_pkt_info, bcn_struct, + bcn_prm, session, phy_mode); + else if (SIR_BAND_2_4_GHZ == rf_band) + ap_beacon_process_24_ghz(mac_ctx, rx_pkt_info, bcn_struct, + bcn_prm, session, phy_mode); + mac_ctx->sch.gSchBcnIgnored++; +} + +/* -------------------------------------------------------------------- */ + +/** + * __sch_beacon_process_no_session + * + * FUNCTION: + * Process the received beacon frame when + * -- Station is not scanning + * -- No corresponding session is found + * + * LOGIC: + * Following scenarios exist when Session Does not exist: + * * IBSS Beacons, when IBSS session already exists with same SSID, + * but from STA which has not yet joined and has a different BSSID. + * - invoke lim_handle_ibs_scoalescing with the session context of existing IBSS session. + * + * * IBSS Beacons when IBSS session does not exist, only Infra or BT-AMP session exists, + * then save the beacon in the scan results and throw it away. + * + * * Infra Beacons + * - beacons received when no session active + * should not come here, it should be handled as part of scanning, + * else they should not be getting received, should update scan results and drop it if that happens. + * - beacons received when IBSS session active: + * update scan results and drop it. + * - beacons received when Infra session(STA) is active: + * update scan results and drop it + * - beacons received when BT-STA session is active: + * update scan results and drop it. + * - beacons received when Infra/BT-STA or Infra/IBSS is active. + * update scan results and drop it. + * + + */ +static void __sch_beacon_process_no_session(tpAniSirGlobal pMac, + tpSchBeaconStruct pBeacon, + uint8_t *pRxPacketInfo) +{ + tpPESession psessionEntry = NULL; + + psessionEntry = lim_is_ibss_session_active(pMac); + if (psessionEntry != NULL) { + lim_handle_ibss_coalescing(pMac, pBeacon, pRxPacketInfo, + psessionEntry); + } + /* If station(STA/BT-STA/BT-AP/IBSS) mode, Always save the + * beacon in the scan results, if atleast one session is + * active. sch_beacon_process_no_session will be called only + * when there is atleast one session active, so not checking + * it again here. + */ + lim_check_and_add_bss_description(pMac, pBeacon, pRxPacketInfo, false, + false); + return; +} + +/** + * get_operating_channel_width() - Get operating channel width + * @stads - station entry. + * + * This function returns the operating channel width based on + * the supported channel width entry. + * + * Return: tSirMacHTChannelWidth on success + */ +static tSirMacHTChannelWidth get_operating_channel_width(tpDphHashNode stads) +{ + tSirMacHTChannelWidth ch_width = eHT_CHANNEL_WIDTH_20MHZ; + + if (stads->vhtSupportedChannelWidthSet == + WNI_CFG_VHT_CHANNEL_WIDTH_160MHZ) + ch_width = eHT_CHANNEL_WIDTH_160MHZ; + else if (stads->vhtSupportedChannelWidthSet == + WNI_CFG_VHT_CHANNEL_WIDTH_80_PLUS_80MHZ) + ch_width = eHT_CHANNEL_WIDTH_160MHZ; + else if (stads->vhtSupportedChannelWidthSet == + WNI_CFG_VHT_CHANNEL_WIDTH_80MHZ) + ch_width = eHT_CHANNEL_WIDTH_80MHZ; + else if (stads->htSupportedChannelWidthSet) + ch_width = eHT_CHANNEL_WIDTH_40MHZ; + else + ch_width = eHT_CHANNEL_WIDTH_20MHZ; + + return ch_width; +} + +/* + * sch_bcn_process_sta() - Process the received beacon frame for sta, + * bt_amp_sta + * + * @mac_ctx: mac_ctx + * @bcn: beacon struct + * @rx_pkt_info: received packet info + * @session: pe session pointer + * @bssIdx: bss index + * @beaconParams: update beacon params + * @sendProbeReq: out flag to indicate if probe rsp is to be sent + * @pMh: mac header + * + * Process the received beacon frame for sta + * + * Return: success of failure of operation + */ +static bool +sch_bcn_process_sta(tpAniSirGlobal mac_ctx, + tpSchBeaconStruct bcn, + uint8_t *rx_pkt_info, + tpPESession session, uint8_t *bssIdx, + tUpdateBeaconParams *beaconParams, + uint8_t *sendProbeReq, tpSirMacMgmtHdr pMh) +{ + uint32_t bi; + tpDphHashNode pStaDs = NULL; + /* + * This handles two cases: + * -- Infra STA receving beacons from AP + */ + /* Always save the beacon into LIM's cached scan results */ + lim_check_and_add_bss_description(mac_ctx, bcn, rx_pkt_info, + false, false); + + /** + * This is the Beacon received from the AP we're currently associated + * with. Check if there are any changes in AP's capabilities + */ + if ((uint8_t) bcn->channelNumber != session->currentOperChannel) { + PELOGE(sch_log(mac_ctx, LOGE, + FL("Channel Change from %d --> %d - Ignoring beacon!"), + session->currentOperChannel, + bcn->channelNumber);) + return false; + } + lim_detect_change_in_ap_capabilities(mac_ctx, bcn, session); + if (lim_get_sta_hash_bssidx(mac_ctx, DPH_STA_HASH_INDEX_PEER, bssIdx, + session) != eSIR_SUCCESS) + return false; + + beaconParams->bssIdx = *bssIdx; + qdf_mem_copy((uint8_t *) &session->lastBeaconTimeStamp, + (uint8_t *) bcn->timeStamp, sizeof(uint64_t)); + session->lastBeaconDtimCount = bcn->tim.dtimCount; + session->currentBssBeaconCnt++; + if (session->lastBeaconDtimPeriod != bcn->tim.dtimPeriod) { + session->lastBeaconDtimPeriod = bcn->tim.dtimPeriod; + lim_send_set_dtim_period(mac_ctx, bcn->tim.dtimPeriod, + session); + } + MTRACE(mac_trace(mac_ctx, TRACE_CODE_RX_MGMT_TSF, + session->peSessionId, bcn->timeStamp[0]);) + MTRACE(mac_trace(mac_ctx, TRACE_CODE_RX_MGMT_TSF, + session->peSessionId, bcn->timeStamp[1]);) + + /* Read beacon interval session Entry */ + bi = session->beaconParams.beaconInterval; + if (bi != bcn->beaconInterval) { + PELOG1(sch_log(mac_ctx, LOG1, + FL("Beacon interval changed from %d to %d"), + bcn->beaconInterval, bi);) + + bi = bcn->beaconInterval; + session->beaconParams.beaconInterval = (uint16_t) bi; + beaconParams->paramChangeBitmap |= PARAM_BCN_INTERVAL_CHANGED; + beaconParams->beaconInterval = (uint16_t) bi; + } + + if (bcn->cfPresent) { + cfg_set_int(mac_ctx, WNI_CFG_CFP_PERIOD, + bcn->cfParamSet.cfpPeriod); + lim_send_cf_params(mac_ctx, *bssIdx, + bcn->cfParamSet.cfpCount, + bcn->cfParamSet.cfpPeriod); + } + + /* No need to send DTIM Period and Count to HAL/SMAC */ + /* SMAC already parses TIM bit. */ + if (bcn->timPresent) + cfg_set_int(mac_ctx, WNI_CFG_DTIM_PERIOD, bcn->tim.dtimPeriod); + + if (mac_ctx->lim.gLimProtectionControl != + WNI_CFG_FORCE_POLICY_PROTECTION_DISABLE) + lim_decide_sta_protection(mac_ctx, bcn, beaconParams, session); + + if (bcn->erpPresent) { + if (bcn->erpIEInfo.barkerPreambleMode) + lim_enable_short_preamble(mac_ctx, false, + beaconParams, session); + else + lim_enable_short_preamble(mac_ctx, true, + beaconParams, session); + } + lim_update_short_slot(mac_ctx, bcn, beaconParams, session); + + pStaDs = dph_get_hash_entry(mac_ctx, DPH_STA_HASH_INDEX_PEER, + &session->dph.dphHashTable); + if ((bcn->wmeEdcaPresent && (session->limWmeEnabled)) + || (bcn->edcaPresent && (session->limQosEnabled))) { + if (bcn->edcaParams.qosInfo.count != + session->gLimEdcaParamSetCount) { + if (sch_beacon_edca_process(mac_ctx, &bcn->edcaParams, + session) != eSIR_SUCCESS) { + PELOGE(sch_log(mac_ctx, LOGE, + FL("EDCA parameter processing error"));) + } else if (pStaDs != NULL) { + /* If needed, downgrade the EDCA parameters */ + lim_set_active_edca_params(mac_ctx, + session->gLimEdcaParams, session); + lim_send_edca_params(mac_ctx, + session->gLimEdcaParamsActive, + pStaDs->bssId); + } else { + PELOGE(sch_log(mac_ctx, LOGE, + FL("Self Entry missing in Hash Table"));) + } + } + return true; + } + + if ((bcn->qosCapabilityPresent && session->limQosEnabled) + && (bcn->qosCapability.qosInfo.count != + session->gLimEdcaParamSetCount)) + *sendProbeReq = true; + + return true; +} + +/** + * update_nss() - Function to update NSS + * @mac_ctx: pointer to Global Mac structure + * @sta_ds: pointer to tpDphHashNode + * @beacon: pointer to tpSchBeaconStruct + * @session_entry: pointer to tpPESession + * @mgmt_hdr: pointer to tpSirMacMgmtHdr + * + * function to update NSS + * + * Return: none + */ +static void update_nss(tpAniSirGlobal mac_ctx, tpDphHashNode sta_ds, + tpSchBeaconStruct beacon, tpPESession session_entry, + tpSirMacMgmtHdr mgmt_hdr) +{ + if (sta_ds->vhtSupportedRxNss != (beacon->OperatingMode.rxNSS + 1)) { + sta_ds->vhtSupportedRxNss = + beacon->OperatingMode.rxNSS + 1; + lim_set_nss_change(mac_ctx, session_entry, + sta_ds->vhtSupportedRxNss, sta_ds->staIndex, + mgmt_hdr->sa); + } +} + +/* + * sch_bcn_process_sta_ibss() - Process the received beacon frame + * for sta, bt_amp_sta and ibss + * + * @mac_ctx: mac_ctx + * @bcn: beacon struct + * @rx_pkt_info: received packet info + * @session: pe session pointer + * @bssIdx: bss index + * @beaconParams: update beacon params + * @sendProbeReq: out flag to indicate if probe rsp is to be sent + * @pMh: mac header + * + * Process the received beacon frame for sta and ibss + * + * Return: void + */ +static void +sch_bcn_process_sta_ibss(tpAniSirGlobal mac_ctx, + tpSchBeaconStruct bcn, + uint8_t *rx_pkt_info, + tpPESession session, uint8_t *bssIdx, + tUpdateBeaconParams *beaconParams, + uint8_t *sendProbeReq, tpSirMacMgmtHdr pMh) +{ + tpDphHashNode pStaDs = NULL; + uint16_t aid; + uint8_t operMode; + uint8_t chWidth = 0; + uint8_t cb_mode; + uint32_t fw_vht_ch_wd = wma_get_vht_ch_width(); + bool skip_opmode_update = false; + + if (CHAN_ENUM_14 >= session->currentOperChannel) + cb_mode = mac_ctx->roam.configParam.channelBondingMode24GHz; + else + cb_mode = mac_ctx->roam.configParam.channelBondingMode5GHz; + /* check for VHT capability */ + pStaDs = dph_lookup_hash_entry(mac_ctx, pMh->sa, &aid, + &session->dph.dphHashTable); + if ((NULL == pStaDs) || + (WNI_CFG_CHANNEL_BONDING_MODE_DISABLE == cb_mode) || + ((NULL != pStaDs) && + (STA_INVALID_IDX == pStaDs->staIndex))) + return; + + if (session->vhtCapability && bcn->OperatingMode.present) { + operMode = get_operating_channel_width(pStaDs); + if ((operMode == eHT_CHANNEL_WIDTH_80MHZ) && + (bcn->OperatingMode.chanWidth > eHT_CHANNEL_WIDTH_80MHZ)) + skip_opmode_update = true; + + if (!skip_opmode_update && + ((operMode != bcn->OperatingMode.chanWidth) || + (pStaDs->vhtSupportedRxNss != + (bcn->OperatingMode.rxNSS + 1)))) { + PELOGE(sch_log(mac_ctx, LOGE, + FL("received OpMode Chanwidth %d, staIdx = %d"), + bcn->OperatingMode.chanWidth, pStaDs->staIndex);) + PELOGE(sch_log(mac_ctx, LOGE, + FL("MAC - %0x:%0x:%0x:%0x:%0x:%0x"), + pMh->sa[0], pMh->sa[1], + pMh->sa[2], pMh->sa[3], + pMh->sa[4], pMh->sa[5]);) + + if ((bcn->OperatingMode.chanWidth >= + eHT_CHANNEL_WIDTH_160MHZ) && + (fw_vht_ch_wd > eHT_CHANNEL_WIDTH_80MHZ)) { + PELOGE(sch_log(mac_ctx, LOGE, + FL("Updating the CH Width to 160MHz"));) + pStaDs->vhtSupportedChannelWidthSet = + WNI_CFG_VHT_CHANNEL_WIDTH_160MHZ; + pStaDs->htSupportedChannelWidthSet = + eHT_CHANNEL_WIDTH_40MHZ; + chWidth = eHT_CHANNEL_WIDTH_160MHZ; + } else if (bcn->OperatingMode.chanWidth >= + eHT_CHANNEL_WIDTH_80MHZ) { + PELOGE(sch_log(mac_ctx, LOGE, + FL("Updating the CH Width to 80MHz"));) + pStaDs->vhtSupportedChannelWidthSet = + WNI_CFG_VHT_CHANNEL_WIDTH_80MHZ; + pStaDs->htSupportedChannelWidthSet = + eHT_CHANNEL_WIDTH_40MHZ; + chWidth = eHT_CHANNEL_WIDTH_80MHZ; + } else if (bcn->OperatingMode.chanWidth == + eHT_CHANNEL_WIDTH_40MHZ) { + PELOGE(sch_log(mac_ctx, LOGE, + FL("Updating the CH Width to 40MHz"));) + pStaDs->vhtSupportedChannelWidthSet = + WNI_CFG_VHT_CHANNEL_WIDTH_20_40MHZ; + pStaDs->htSupportedChannelWidthSet = + eHT_CHANNEL_WIDTH_40MHZ; + chWidth = eHT_CHANNEL_WIDTH_40MHZ; + } else if (bcn->OperatingMode.chanWidth == + eHT_CHANNEL_WIDTH_20MHZ) { + PELOGE(sch_log(mac_ctx, LOGE, + FL("Updating the CH Width to 20MHz"));) + pStaDs->vhtSupportedChannelWidthSet = + WNI_CFG_VHT_CHANNEL_WIDTH_20_40MHZ; + pStaDs->htSupportedChannelWidthSet = + eHT_CHANNEL_WIDTH_20MHZ; + chWidth = eHT_CHANNEL_WIDTH_20MHZ; + } + lim_check_vht_op_mode_change(mac_ctx, session, + chWidth, session->dot11mode, + pStaDs->staIndex, pMh->sa); + update_nss(mac_ctx, pStaDs, bcn, session, pMh); + } + return; + } + + if (!(session->vhtCapability && bcn->VHTOperation.present)) + return; + + operMode = pStaDs->vhtSupportedChannelWidthSet; + if ((operMode == WNI_CFG_VHT_CHANNEL_WIDTH_80MHZ) && + (operMode < bcn->VHTOperation.chanWidth)) + skip_opmode_update = true; + + if (!skip_opmode_update && + (operMode != bcn->VHTOperation.chanWidth)) { + PELOGE(sch_log(mac_ctx, LOGE, + FL("received VHTOP CHWidth %d staIdx = %d"), + bcn->VHTOperation.chanWidth, pStaDs->staIndex);) + PELOGE(sch_log(mac_ctx, LOGE, + FL(" MAC - %0x:%0x:%0x:%0x:%0x:%0x"), + pMh->sa[0], pMh->sa[1], + pMh->sa[2], pMh->sa[3], + pMh->sa[4], pMh->sa[5]);) + + if ((bcn->VHTOperation.chanWidth >= + WNI_CFG_VHT_CHANNEL_WIDTH_160MHZ) && + (fw_vht_ch_wd > eHT_CHANNEL_WIDTH_80MHZ)) { + PELOGE(sch_log(mac_ctx, LOGE, + FL("Updating the CH Width to 160MHz"));) + pStaDs->vhtSupportedChannelWidthSet = + bcn->VHTOperation.chanWidth; + pStaDs->htSupportedChannelWidthSet = + eHT_CHANNEL_WIDTH_40MHZ; + chWidth = eHT_CHANNEL_WIDTH_160MHZ; + } else if (bcn->VHTOperation.chanWidth >= + WNI_CFG_VHT_CHANNEL_WIDTH_80MHZ) { + PELOGE(sch_log(mac_ctx, LOGE, + FL("Updating the CH Width to 80MHz"));) + pStaDs->vhtSupportedChannelWidthSet = + WNI_CFG_VHT_CHANNEL_WIDTH_80MHZ; + pStaDs->htSupportedChannelWidthSet = + eHT_CHANNEL_WIDTH_40MHZ; + chWidth = eHT_CHANNEL_WIDTH_80MHZ; + } else if (bcn->VHTOperation.chanWidth == + WNI_CFG_VHT_CHANNEL_WIDTH_20_40MHZ) { + pStaDs->vhtSupportedChannelWidthSet = + WNI_CFG_VHT_CHANNEL_WIDTH_20_40MHZ; + if (bcn->HTCaps.supportedChannelWidthSet) { + PELOGE(sch_log(mac_ctx, LOGE, + FL("Updating the CH Width to 40MHz"));) + pStaDs->htSupportedChannelWidthSet = + eHT_CHANNEL_WIDTH_40MHZ; + chWidth = eHT_CHANNEL_WIDTH_40MHZ; + } else { + PELOGE(sch_log(mac_ctx, LOGE, + FL("Updating the CH Width to 20MHz"));) + pStaDs->htSupportedChannelWidthSet = + eHT_CHANNEL_WIDTH_20MHZ; + chWidth = eHT_CHANNEL_WIDTH_20MHZ; + } + } + lim_check_vht_op_mode_change(mac_ctx, session, + chWidth, session->dot11mode, + pStaDs->staIndex, pMh->sa); + } + return; +} + +/** + * get_local_power_constraint_beacon() - extracts local constraint + * from beacon + * @bcn: beacon structure + * @local_constraint: local constraint pointer + * + * Return: None + */ +#ifdef FEATURE_WLAN_ESE +static void get_local_power_constraint_beacon( + tpSchBeaconStruct bcn, + int8_t *local_constraint) +{ + if (bcn->eseTxPwr.present) + *local_constraint = bcn->eseTxPwr.power_limit; +} +#else +static void get_local_power_constraint_beacon( + tpSchBeaconStruct bcn, + int8_t *local_constraint) +{ + +} +#endif + +/* + * __sch_beacon_process_for_session() - Process the received beacon frame when + * station is not scanning and corresponding session is found + * + * + * @mac_ctx: mac_ctx + * @bcn: beacon struct + * @rx_pkt_info: received packet info + * @session: pe session pointer + * + * Following scenarios exist when Session exists + * IBSS STA receving beacons from IBSS Peers, who are part of IBSS. + * - call lim_handle_ibs_scoalescing with that session context. + * Infra STA receving beacons from AP to which it is connected + * - call sch_beacon_processFromAP with that session's context. + * - call sch_beacon_processFromAP with that session's context. + * (here need to make sure BTAP creates session entry for BT STA) + * - just update the beacon count for heart beat purposes for now, + * for now, don't process the beacon. + * Infra/IBSS both active and receives IBSS beacon: + * - call lim_handle_ibs_scoalescing with that session context. + * Infra/IBSS both active and receives Infra beacon: + * - call sch_beacon_processFromAP with that session's context. + * any updates to EDCA parameters will be effective for IBSS as well, + * even though no WMM for IBSS ?? Need to figure out how to handle + * this scenario. + * Infra/BTSTA both active and receive Infra beacon. + * - change in EDCA parameters on Infra affect the BTSTA link. + * Update the same parameters on BT link + * Infra/BTSTA both active and receive BT-AP beacon. + * - update beacon cnt for heartbeat + * Infra/BTAP both active and receive Infra beacon. + * - BT-AP starts advertising BE parameters from Infra AP, if they get + * changed. + * Infra/BTAP both active and receive BTSTA beacon. + * - update beacon cnt for heartbeat + * + * Return: void + */ +static void __sch_beacon_process_for_session(tpAniSirGlobal mac_ctx, + tpSchBeaconStruct bcn, + uint8_t *rx_pkt_info, + tpPESession session) +{ + uint8_t bssIdx = 0; + tUpdateBeaconParams beaconParams; + uint8_t sendProbeReq = false; + tpSirMacMgmtHdr pMh = WMA_GET_RX_MAC_HEADER(rx_pkt_info); + int8_t regMax = 0, maxTxPower = 0, local_constraint; + qdf_mem_zero(&beaconParams, sizeof(tUpdateBeaconParams)); + beaconParams.paramChangeBitmap = 0; + + if (LIM_IS_IBSS_ROLE(session)) { + lim_handle_ibss_coalescing(mac_ctx, bcn, rx_pkt_info, session); + } else if (LIM_IS_STA_ROLE(session)) { + if (false == sch_bcn_process_sta(mac_ctx, bcn, + rx_pkt_info, session, &bssIdx, + &beaconParams, &sendProbeReq, pMh)) + return; + } + + if (session->htCapability && bcn->HTInfo.present && + !LIM_IS_IBSS_ROLE(session)) + lim_update_sta_run_time_ht_switch_chnl_params(mac_ctx, + &bcn->HTInfo, bssIdx, session); + + if (LIM_IS_STA_ROLE(session) + || LIM_IS_IBSS_ROLE(session)) { + /* Channel Switch information element updated */ + if (bcn->channelSwitchPresent) { + /* + * on receiving channel switch announcement from AP, + * delete all TDLS peers before leaving BSS and proceed + * for channel switch + */ + if (LIM_IS_STA_ROLE(session)) + lim_delete_tdls_peers(mac_ctx, session); + + lim_update_channel_switch(mac_ctx, bcn, session); + } else if (session->gLimSpecMgmt.dot11hChanSwState == + eLIM_11H_CHANSW_RUNNING) { + lim_cancel_dot11h_channel_switch(mac_ctx, session); + } + } + if (LIM_IS_STA_ROLE(session) + || LIM_IS_IBSS_ROLE(session)) + sch_bcn_process_sta_ibss(mac_ctx, bcn, + rx_pkt_info, session, &bssIdx, + &beaconParams, &sendProbeReq, pMh); + /* Obtain the Max Tx power for the current regulatory */ + regMax = cfg_get_regulatory_max_transmit_power(mac_ctx, + session->currentOperChannel); + + local_constraint = regMax; + + if (mac_ctx->roam.configParam.allow_tpc_from_ap) { + get_local_power_constraint_beacon(bcn, &local_constraint); + sch_log(mac_ctx, LOG1, "ESE localPowerConstraint = %d,", + local_constraint); + + if (mac_ctx->rrm.rrmPEContext.rrmEnable && + bcn->powerConstraintPresent) { + local_constraint = regMax; + local_constraint -= + bcn->localPowerConstraint.localPowerConstraints; + sch_log(mac_ctx, LOG1, "localPowerConstraint = %d,", + local_constraint); + } + } + + maxTxPower = lim_get_max_tx_power(regMax, local_constraint, + mac_ctx->roam.configParam.nTxPowerCap); + + sch_log(mac_ctx, LOG1, "RegMax = %d, MaxTx pwr = %d", + regMax, maxTxPower); + + + /* If maxTxPower is increased or decreased */ + if (maxTxPower != session->maxTxPower) { + sch_log(mac_ctx, LOG1, + FL("Local power constraint change, Updating new maxTx power %d from old pwr %d"), + maxTxPower, session->maxTxPower); + if (lim_send_set_max_tx_power_req(mac_ctx, maxTxPower, session) + == eSIR_SUCCESS) + session->maxTxPower = maxTxPower; + } + + /* Indicate to LIM that Beacon is received */ + if (bcn->HTInfo.present) + lim_received_hb_handler(mac_ctx, + (uint8_t) bcn->HTInfo.primaryChannel, session); + else + lim_received_hb_handler(mac_ctx, (uint8_t) bcn->channelNumber, + session); + + /* + * I don't know if any additional IE is required here. Currently, not + * include addIE. + */ + if (sendProbeReq) + lim_send_probe_req_mgmt_frame(mac_ctx, &session->ssId, + session->bssId, session->currentOperChannel, + session->selfMacAddr, session->dot11mode, 0, NULL); + + if ((false == mac_ctx->sap.SapDfsInfo.is_dfs_cac_timer_running) + && beaconParams.paramChangeBitmap) { + PELOGW(sch_log(mac_ctx, LOGW, + FL("Beacon for session[%d] got changed."), + session->peSessionId);) + PELOGW(sch_log(mac_ctx, LOGW, + FL("sending beacon param change bitmap: 0x%x "), + beaconParams.paramChangeBitmap);) + lim_send_beacon_params(mac_ctx, &beaconParams, session); + } + + if ((session->pePersona == QDF_P2P_CLIENT_MODE) && + session->send_p2p_conf_frame) { + lim_p2p_oper_chan_change_confirm_action_frame(mac_ctx, + session->bssId, session); + session->send_p2p_conf_frame = false; + } +} + +/** + * sch_beacon_process() - process the beacon frame + * @mac_ctx: mac global context + * @rx_pkt_info: pointer to buffer descriptor + * + * Return: None + */ +void +sch_beacon_process(tpAniSirGlobal mac_ctx, uint8_t *rx_pkt_info, + tpPESession session) +{ + static tSchBeaconStruct bcn; + tUpdateBeaconParams bcn_prm; + tpPESession ap_session = NULL; + uint8_t i; + + qdf_mem_zero(&bcn_prm, sizeof(tUpdateBeaconParams)); + bcn_prm.paramChangeBitmap = 0; + mac_ctx->sch.gSchBcnRcvCnt++; + /* Convert the beacon frame into a structure */ + if (sir_convert_beacon_frame2_struct(mac_ctx, (uint8_t *) rx_pkt_info, + &bcn) != eSIR_SUCCESS) { + PELOGE(sch_log(mac_ctx, LOGE, FL("beacon parsing failed"));) + mac_ctx->sch.gSchBcnParseErrorCnt++; + return; + } + + if (bcn.ssidPresent) + bcn.ssId.ssId[bcn.ssId.length] = 0; + /* + * First process the beacon in the context of any existing AP or BTAP + * session. This takes cares of following two scenarios: + * - session = NULL: + * e.g. beacon received from a neighboring BSS, you want to apply the + * protection settings to BTAP/InfraAP beacons + * - session is non NULL: + * e.g. beacon received is from the INFRA AP to which you are connected + * on another concurrent link. In this case also, we want to apply the + * protection settings(as advertised by Infra AP) to BTAP beacons + */ + for (i = 0; i < mac_ctx->lim.maxBssId; i++) { + ap_session = pe_find_session_by_session_id(mac_ctx, i); + if (!((ap_session != NULL) && + (!(WMA_GET_OFFLOADSCANLEARN(rx_pkt_info))))) + continue; + + if (!LIM_IS_AP_ROLE(ap_session)) + continue; + + bcn_prm.bssIdx = ap_session->bssIdx; + if (ap_session->gLimProtectionControl != + WNI_CFG_FORCE_POLICY_PROTECTION_DISABLE) + ap_beacon_process(mac_ctx, rx_pkt_info, + &bcn, &bcn_prm, ap_session); + + if ((false == mac_ctx->sap.SapDfsInfo.is_dfs_cac_timer_running) + && bcn_prm.paramChangeBitmap) { + /* Update the bcn and apply the new settings to HAL */ + sch_set_fixed_beacon_fields(mac_ctx, ap_session); + PELOG1(sch_log(mac_ctx, LOG1, + FL("Beacon for PE session[%d] got changed."), + ap_session->peSessionId);) + PELOG1(sch_log(mac_ctx, LOG1, + FL("sending beacon param change bitmap: 0x%x"), + bcn_prm.paramChangeBitmap);) + lim_send_beacon_params(mac_ctx, &bcn_prm, ap_session); + } + } + + /* + * Now process the beacon in the context of the BSS which is + * transmitting the beacons, if one is found + */ + if (session == NULL) + __sch_beacon_process_no_session(mac_ctx, &bcn, rx_pkt_info); + else + __sch_beacon_process_for_session(mac_ctx, &bcn, rx_pkt_info, + session); +} + +/** + * sch_beacon_edca_process(): Process the EDCA parameter set in the received + * beacon frame + * + * @mac_ctx: mac global context + * @edca: reference to edca parameters in beacon struct + * @session : pesession entry + * + * @return status of operation + */ +tSirRetStatus +sch_beacon_edca_process(tpAniSirGlobal pMac, tSirMacEdcaParamSetIE *edca, + tpPESession session) +{ + uint8_t i; +#ifdef FEATURE_WLAN_DIAG_SUPPORT + host_log_qos_edca_pkt_type *log_ptr = NULL; +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + + sch_log(pMac, LOG2, + FL("Updating parameter set count: Old %d ---> new %d"), + session->gLimEdcaParamSetCount, edca->qosInfo.count); + + session->gLimEdcaParamSetCount = edca->qosInfo.count; + session->gLimEdcaParams[EDCA_AC_BE] = edca->acbe; + session->gLimEdcaParams[EDCA_AC_BK] = edca->acbk; + session->gLimEdcaParams[EDCA_AC_VI] = edca->acvi; + session->gLimEdcaParams[EDCA_AC_VO] = edca->acvo; + + if (pMac->roam.configParam.enable_edca_params) { + session->gLimEdcaParams[EDCA_AC_VO].aci.aifsn = + pMac->roam.configParam.edca_vo_aifs; + session->gLimEdcaParams[EDCA_AC_VI].aci.aifsn = + pMac->roam.configParam.edca_vi_aifs; + session->gLimEdcaParams[EDCA_AC_BK].aci.aifsn = + pMac->roam.configParam.edca_bk_aifs; + session->gLimEdcaParams[EDCA_AC_BE].aci.aifsn = + pMac->roam.configParam.edca_be_aifs; + + session->gLimEdcaParams[EDCA_AC_VO].cw.min = + pMac->roam.configParam.edca_vo_cwmin; + session->gLimEdcaParams[EDCA_AC_VI].cw.min = + pMac->roam.configParam.edca_vi_cwmin; + session->gLimEdcaParams[EDCA_AC_BK].cw.min = + pMac->roam.configParam.edca_bk_cwmin; + session->gLimEdcaParams[EDCA_AC_BE].cw.min = + pMac->roam.configParam.edca_be_cwmin; + + session->gLimEdcaParams[EDCA_AC_VO].cw.max = + pMac->roam.configParam.edca_vo_cwmax; + session->gLimEdcaParams[EDCA_AC_VI].cw.max = + pMac->roam.configParam.edca_vi_cwmax; + session->gLimEdcaParams[EDCA_AC_BK].cw.max = + pMac->roam.configParam.edca_bk_cwmax; + session->gLimEdcaParams[EDCA_AC_BE].cw.max = + pMac->roam.configParam.edca_be_cwmax; + } +#ifdef FEATURE_WLAN_DIAG_SUPPORT + WLAN_HOST_DIAG_LOG_ALLOC(log_ptr, host_log_qos_edca_pkt_type, + LOG_WLAN_QOS_EDCA_C); + if (log_ptr) { + log_ptr->aci_be = session->gLimEdcaParams[EDCA_AC_BE].aci.aci; + log_ptr->cw_be = + session->gLimEdcaParams[EDCA_AC_BE].cw.max << 4 + | session->gLimEdcaParams[EDCA_AC_BE].cw.min; + log_ptr->txoplimit_be = + session->gLimEdcaParams[EDCA_AC_BE].txoplimit; + log_ptr->aci_bk = + session->gLimEdcaParams[EDCA_AC_BK].aci.aci; + log_ptr->cw_bk = + session->gLimEdcaParams[EDCA_AC_BK].cw.max << 4 + | session->gLimEdcaParams[EDCA_AC_BK].cw.min; + log_ptr->txoplimit_bk = + session->gLimEdcaParams[EDCA_AC_BK].txoplimit; + log_ptr->aci_vi = + session->gLimEdcaParams[EDCA_AC_VI].aci.aci; + log_ptr->cw_vi = + session->gLimEdcaParams[EDCA_AC_VI].cw.max << 4 + | session->gLimEdcaParams[EDCA_AC_VI].cw.min; + log_ptr->txoplimit_vi = + session->gLimEdcaParams[EDCA_AC_VI].txoplimit; + log_ptr->aci_vo = + session->gLimEdcaParams[EDCA_AC_VO].aci.aci; + log_ptr->cw_vo = + session->gLimEdcaParams[EDCA_AC_VO].cw.max << 4 + | session->gLimEdcaParams[EDCA_AC_VO].cw.min; + log_ptr->txoplimit_vo = + session->gLimEdcaParams[EDCA_AC_VO].txoplimit; + } + WLAN_HOST_DIAG_LOG_REPORT(log_ptr); +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + sch_log(pMac, LOG1, + FL("Edsa param enabled in ini %d. Updating Local EDCA Params(gLimEdcaParams) to: "), + pMac->roam.configParam.enable_edca_params); + for (i = 0; i < MAX_NUM_AC; i++) { + sch_log(pMac, LOG1, + FL("AC[%d]: AIFSN: %d, ACM %d, CWmin %d, CWmax %d, TxOp %d"), + i, session->gLimEdcaParams[i].aci.aifsn, + session->gLimEdcaParams[i].aci.acm, + session->gLimEdcaParams[i].cw.min, + session->gLimEdcaParams[i].cw.max, + session->gLimEdcaParams[i].txoplimit); + } + return eSIR_SUCCESS; +} diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/sch/sch_debug.c b/drivers/staging/qcacld-3.0/core/mac/src/pe/sch/sch_debug.c new file mode 100644 index 0000000000000000000000000000000000000000..28b65f45085dbdde973550253c8be67f4f9fad58 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/sch/sch_debug.c @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2011-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * + * This file sch_debug.cc contains some debug functions. + * + * Author: Sandesh Goel + * Date: 02/25/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + * + */ + +#include "qdf_trace.h" +#include "sch_debug.h" +#define LOG_SIZE 256 + +void sch_log(tpAniSirGlobal pMac, uint32_t loglevel, const char *pString, ...) +{ + + QDF_TRACE_LEVEL qdf_debug_level; + char logBuffer[LOG_SIZE]; + va_list marker; + + /* getting proper Debug level */ + qdf_debug_level = get_vos_debug_level(loglevel); + + /* extracting arguments from pstring */ + va_start(marker, pString); + vsnprintf(logBuffer, LOG_SIZE, pString, marker); + QDF_TRACE(QDF_MODULE_ID_PE, qdf_debug_level, "%s", logBuffer); + va_end(marker); +} + +/* -------------------------------------------------------------------- */ diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/sch/sch_debug.h b/drivers/staging/qcacld-3.0/core/mac/src/pe/sch/sch_debug.h new file mode 100644 index 0000000000000000000000000000000000000000..d27f72733dfed66991dbe350e4b02d02ff4d8578 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/sch/sch_debug.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2011-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * + * This file sch_debug.h contains some debug macros. + * + * Author: Sandesh Goel + * Date: 02/25/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + * + */ + +#ifndef __SCH_DEBUG_H__ +#define __SCH_DEBUG_H__ + +#include "utils_api.h" +#include "sir_debug.h" + +#if !defined(__printf) +#define __printf(a, b) +#endif + +void __printf(3, 4) sch_log(tpAniSirGlobal pMac, uint32_t loglevel, + const char *pString, ...); + +#endif diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/sch/sch_message.c b/drivers/staging/qcacld-3.0/core/mac/src/pe/sch/sch_message.c new file mode 100644 index 0000000000000000000000000000000000000000..020821169399b4e98fa43947249ca8595a5b6abe --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/sch/sch_message.c @@ -0,0 +1,604 @@ +/* + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#include "cds_api.h" +#include "sir_common.h" + +#include "wni_cfg.h" +#include "ani_global.h" +#include "cfg_api.h" +#include "lim_api.h" +#include "lim_send_messages.h" + +#include "sch_api.h" +#include "sch_debug.h" + +/* / Minimum beacon interval allowed (in Kus) */ +#define SCH_BEACON_INTERVAL_MIN 10 + +/* / Maximum beacon interval allowed (in Kus) */ +#define SCH_BEACON_INTERVAL_MAX 10000 + +/* / convert the CW values into a uint16_t */ +#define GET_CW(pCw) ((uint16_t) ((*(pCw) << 8) + *((pCw) + 1))) + +/* local functions */ +static tSirRetStatus get_wmm_local_params(tpAniSirGlobal pMac, + uint32_t + params[] + [WNI_CFG_EDCA_ANI_ACBK_LOCAL_LEN]); +static void set_sch_edca_params(tpAniSirGlobal pMac, + uint32_t params[][WNI_CFG_EDCA_ANI_ACBK_LOCAL_LEN], + tpPESession psessionEntry); + +/* -------------------------------------------------------------------- */ +/** + * sch_set_beacon_interval + * + * FUNCTION: + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param None + * @return None + */ + +void sch_set_beacon_interval(tpAniSirGlobal pMac, tpPESession psessionEntry) +{ + uint32_t bi; + + bi = psessionEntry->beaconParams.beaconInterval; + + if (bi < SCH_BEACON_INTERVAL_MIN || bi > SCH_BEACON_INTERVAL_MAX) { + sch_log(pMac, LOGE, + FL("Invalid beacon interval %d (should be [%d,%d]"), bi, + SCH_BEACON_INTERVAL_MIN, SCH_BEACON_INTERVAL_MAX); + return; + } + + pMac->sch.schObject.gSchBeaconInterval = (uint16_t) bi; +} + +/* -------------------------------------------------------------------- */ +/** + * sch_process_message + * + * FUNCTION: + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param None + * @return None + */ + +void sch_process_message(tpAniSirGlobal pMac, tpSirMsgQ pSchMsg) +{ + uint32_t val; + + tpPESession psessionEntry = &pMac->lim.gpSession[0]; + PELOG3(sch_log(pMac, LOG3, FL("Received message (%x) "), pSchMsg->type);) + + switch (pSchMsg->type) { + + case SIR_SCH_CHANNEL_SWITCH_REQUEST: + sch_log(pMac, LOGE, FL("Channel switch request not handled")); + break; + + case SIR_SCH_START_SCAN_REQ: + pMac->sch.gSchScanReqRcvd = true; + if (pMac->sch.gSchHcfEnabled) { + /* In HCF mode, wait for TFP to stop before sending a response */ + if (pMac->sch.schObject.gSchCFBInitiated || + pMac->sch.schObject.gSchCFPInitiated) { + PELOG1(sch_log(pMac, LOG1, + FL + ("Waiting for TFP to halt before sending " + "start scan response")); + ) + } else + sch_send_start_scan_rsp(pMac); + } else { + /* In eDCF mode, send the response right away */ + sch_send_start_scan_rsp(pMac); + } + break; + + case SIR_SCH_END_SCAN_NTF: + PELOG3(sch_log(pMac, LOG3, + FL("Received STOP_SCAN_NTF from LIM")); + ) + pMac->sch.gSchScanReqRcvd = false; + break; + + case SIR_CFG_PARAM_UPDATE_IND: + + if (wlan_cfg_get_int(pMac, (uint16_t) pSchMsg->bodyval, &val) != + eSIR_SUCCESS) + sch_log(pMac, LOGP, FL("failed to cfg get id %d"), + pSchMsg->bodyval); + + switch (pSchMsg->bodyval) { + case WNI_CFG_BEACON_INTERVAL: + /* What to do for IBSS ?? - TBD */ + if (LIM_IS_AP_ROLE(psessionEntry)) + sch_set_beacon_interval(pMac, psessionEntry); + break; + + case WNI_CFG_DTIM_PERIOD: + pMac->sch.schObject.gSchDTIMCount = 0; + break; + + case WNI_CFG_CFP_PERIOD: + pMac->sch.schObject.gSchCFPCount = 0; + break; + + case WNI_CFG_EDCA_PROFILE: + sch_edca_profile_update(pMac, psessionEntry); + break; + + case WNI_CFG_EDCA_ANI_ACBK_LOCAL: + case WNI_CFG_EDCA_ANI_ACBE_LOCAL: + case WNI_CFG_EDCA_ANI_ACVI_LOCAL: + case WNI_CFG_EDCA_ANI_ACVO_LOCAL: + case WNI_CFG_EDCA_WME_ACBK_LOCAL: + case WNI_CFG_EDCA_WME_ACBE_LOCAL: + case WNI_CFG_EDCA_WME_ACVI_LOCAL: + case WNI_CFG_EDCA_WME_ACVO_LOCAL: + if (LIM_IS_AP_ROLE(psessionEntry)) + sch_qos_update_local(pMac, psessionEntry); + break; + + case WNI_CFG_EDCA_ANI_ACBK: + case WNI_CFG_EDCA_ANI_ACBE: + case WNI_CFG_EDCA_ANI_ACVI: + case WNI_CFG_EDCA_ANI_ACVO: + case WNI_CFG_EDCA_WME_ACBK: + case WNI_CFG_EDCA_WME_ACBE: + case WNI_CFG_EDCA_WME_ACVI: + case WNI_CFG_EDCA_WME_ACVO: + if (LIM_IS_AP_ROLE(psessionEntry)) { + sch_qos_update_broadcast(pMac, psessionEntry); + } + break; + + default: + sch_log(pMac, LOGE, + FL("Cfg param %d indication not handled"), + pSchMsg->bodyval); + } + break; + + default: + sch_log(pMac, LOGE, FL("Unknown message in schMsgQ type %d"), + pSchMsg->type); + } + +} + +/* get the local or broadcast parameters based on the profile sepcified in the config */ +/* params are delivered in this order: BK, BE, VI, VO */ +static tSirRetStatus +sch_get_params(tpAniSirGlobal pMac, + uint32_t params[][WNI_CFG_EDCA_ANI_ACBK_LOCAL_LEN], + uint8_t local) +{ + uint32_t val; + uint32_t i, idx; + uint32_t *prf; + + uint32_t ani_l[] = { + WNI_CFG_EDCA_ANI_ACBE_LOCAL, WNI_CFG_EDCA_ANI_ACBK_LOCAL, + WNI_CFG_EDCA_ANI_ACVI_LOCAL, WNI_CFG_EDCA_ANI_ACVO_LOCAL}; + uint32_t wme_l[] = { + WNI_CFG_EDCA_WME_ACBE_LOCAL, WNI_CFG_EDCA_WME_ACBK_LOCAL, + WNI_CFG_EDCA_WME_ACVI_LOCAL, WNI_CFG_EDCA_WME_ACVO_LOCAL}; + uint32_t ani_b[] = { WNI_CFG_EDCA_ANI_ACBE, WNI_CFG_EDCA_ANI_ACBK, + WNI_CFG_EDCA_ANI_ACVI, WNI_CFG_EDCA_ANI_ACVO}; + uint32_t wme_b[] = { WNI_CFG_EDCA_WME_ACBE, WNI_CFG_EDCA_WME_ACBK, + WNI_CFG_EDCA_WME_ACVI, WNI_CFG_EDCA_WME_ACVO}; + + if (wlan_cfg_get_int(pMac, WNI_CFG_EDCA_PROFILE, &val) != eSIR_SUCCESS) { + sch_log(pMac, LOGP, FL("failed to cfg get EDCA_PROFILE id %d"), + WNI_CFG_EDCA_PROFILE); + return eSIR_FAILURE; + } + + if (val >= WNI_CFG_EDCA_PROFILE_MAX) { + sch_log(pMac, LOGE, + FL("Invalid EDCA_PROFILE %d, using %d instead"), val, + WNI_CFG_EDCA_PROFILE_ANI); + val = WNI_CFG_EDCA_PROFILE_ANI; + } + + sch_log(pMac, LOGW, FL("EdcaProfile: Using %d (%s)"), val, + ((val == WNI_CFG_EDCA_PROFILE_WMM) ? "WMM" : "HiPerf")); + + if (local) { + switch (val) { + case WNI_CFG_EDCA_PROFILE_WMM: + prf = &wme_l[0]; + break; + case WNI_CFG_EDCA_PROFILE_ANI: + default: + prf = &ani_l[0]; + break; + } + } else { + switch (val) { + case WNI_CFG_EDCA_PROFILE_WMM: + prf = &wme_b[0]; + break; + case WNI_CFG_EDCA_PROFILE_ANI: + default: + prf = &ani_b[0]; + break; + } + } + + for (i = 0; i < 4; i++) { + uint8_t data[WNI_CFG_EDCA_ANI_ACBK_LEN]; + uint32_t len = WNI_CFG_EDCA_ANI_ACBK_LOCAL_LEN; + if (wlan_cfg_get_str + (pMac, (uint16_t) prf[i], (uint8_t *) &data[0], + &len) != eSIR_SUCCESS) { + sch_log(pMac, LOGP, FL("cfgGet failed for %d"), prf[i]); + return eSIR_FAILURE; + } + if (len > WNI_CFG_EDCA_ANI_ACBK_LOCAL_LEN) { + sch_log(pMac, LOGE, + FL("cfgGet for %d: length is %d instead of %d"), + prf[i], len, WNI_CFG_EDCA_ANI_ACBK_LOCAL_LEN); + return eSIR_FAILURE; + } + for (idx = 0; idx < len; idx++) + params[i][idx] = (uint32_t) data[idx]; + } + PELOG1(sch_log + (pMac, LOG1, FL("GetParams: local=%d, profile = %d Done"), local, + val); + ) + return eSIR_SUCCESS; +} + +/** + * broadcast_wmm_of_concurrent_sta_session() - broadcasts wmm info + * @mac_ctx: mac global context + * @session: pesession entry + * + * Return: true if wmm param updated, false if wmm param not updated + */ +static bool +broadcast_wmm_of_concurrent_sta_session(tpAniSirGlobal mac_ctx, + tpPESession session) +{ + uint8_t i, j; + tpPESession concurrent_session = NULL; + + for (i = 0; i < mac_ctx->lim.maxBssId; i++) { + /* + * Find another INFRA STA AP session on same operating channel. + * The session entry passed to this API is for GO/SoftAP session + * that is getting added currently + */ + if (!((mac_ctx->lim.gpSession[i].valid == true) && + (mac_ctx->lim.gpSession[i].peSessionId != + session->peSessionId) + && (mac_ctx->lim.gpSession[i].currentOperChannel == + session->currentOperChannel) + && (mac_ctx->lim.gpSession[i].limSystemRole + == eLIM_STA_ROLE))) + continue; + + concurrent_session = &(mac_ctx->lim.gpSession[i]); + break; + } + + if (concurrent_session == NULL) + return false; + + if (!qdf_mem_cmp(session->gLimEdcaParamsBC, + concurrent_session->gLimEdcaParams, + sizeof(concurrent_session->gLimEdcaParams))) + return false; + + /* + * Once atleast one concurrent session on same channel is found and WMM + * broadcast params for current SoftAP/GO session updated, return + */ + for (j = 0; j < MAX_NUM_AC; j++) { + session->gLimEdcaParamsBC[j].aci.acm = + concurrent_session->gLimEdcaParams[j].aci.acm; + session->gLimEdcaParamsBC[j].aci.aifsn = + concurrent_session->gLimEdcaParams[j].aci.aifsn; + session->gLimEdcaParamsBC[j].cw.min = + concurrent_session->gLimEdcaParams[j].cw.min; + session->gLimEdcaParamsBC[j].cw.max = + concurrent_session->gLimEdcaParams[j].cw.max; + session->gLimEdcaParamsBC[j].txoplimit = + concurrent_session->gLimEdcaParams[j].txoplimit; + PELOG1(sch_log(mac_ctx, LOG1, + FL("QoSUpdateBCast changed again due to concurrent INFRA STA session: AC :%d: AIFSN: %d, ACM %d, CWmin %d, CWmax %d, TxOp %d"), + j, session->gLimEdcaParamsBC[j].aci.aifsn, + session->gLimEdcaParamsBC[j].aci.acm, + session->gLimEdcaParamsBC[j].cw.min, + session->gLimEdcaParamsBC[j].cw.max, + session->gLimEdcaParamsBC[j].txoplimit);) + } + return true; +} + +void sch_qos_update_broadcast(tpAniSirGlobal pMac, tpPESession psessionEntry) +{ + uint32_t params[4][WNI_CFG_EDCA_ANI_ACBK_LOCAL_LEN]; + uint32_t cwminidx, cwmaxidx, txopidx; + uint32_t phyMode; + uint8_t i; + bool updated = false; + + if (sch_get_params(pMac, params, false) != eSIR_SUCCESS) { + PELOGE(sch_log(pMac, LOGE, FL("QosUpdateBroadcast: failed"));) + return; + } + lim_get_phy_mode(pMac, &phyMode, psessionEntry); + + PELOG1(sch_log(pMac, LOG1, "QosUpdBcast: mode %d", phyMode);) + + if (phyMode == WNI_CFG_PHY_MODE_11G) { + cwminidx = WNI_CFG_EDCA_PROFILE_CWMING_IDX; + cwmaxidx = WNI_CFG_EDCA_PROFILE_CWMAXG_IDX; + txopidx = WNI_CFG_EDCA_PROFILE_TXOPG_IDX; + } else if (phyMode == WNI_CFG_PHY_MODE_11B) { + cwminidx = WNI_CFG_EDCA_PROFILE_CWMINB_IDX; + cwmaxidx = WNI_CFG_EDCA_PROFILE_CWMAXB_IDX; + txopidx = WNI_CFG_EDCA_PROFILE_TXOPB_IDX; + } else { + /* This can happen if mode is not set yet, assume 11a mode */ + cwminidx = WNI_CFG_EDCA_PROFILE_CWMINA_IDX; + cwmaxidx = WNI_CFG_EDCA_PROFILE_CWMAXA_IDX; + txopidx = WNI_CFG_EDCA_PROFILE_TXOPA_IDX; + } + + for (i = 0; i < MAX_NUM_AC; i++) { + if (psessionEntry->gLimEdcaParamsBC[i].aci.acm != + (uint8_t) params[i][WNI_CFG_EDCA_PROFILE_ACM_IDX]) { + psessionEntry->gLimEdcaParamsBC[i].aci.acm = + (uint8_t) params[i][WNI_CFG_EDCA_PROFILE_ACM_IDX]; + updated = true; + } + if (psessionEntry->gLimEdcaParamsBC[i].aci.aifsn != + (uint8_t) params[i][WNI_CFG_EDCA_PROFILE_AIFSN_IDX]) { + psessionEntry->gLimEdcaParamsBC[i].aci.aifsn = + (uint8_t) params[i][WNI_CFG_EDCA_PROFILE_AIFSN_IDX]; + updated = true; + } + if (psessionEntry->gLimEdcaParamsBC[i].cw.min != + convert_cw(GET_CW(¶ms[i][cwminidx]))) { + psessionEntry->gLimEdcaParamsBC[i].cw.min = + convert_cw(GET_CW(¶ms[i][cwminidx])); + updated = true; + } + if (psessionEntry->gLimEdcaParamsBC[i].cw.max != + convert_cw(GET_CW(¶ms[i][cwmaxidx]))) { + psessionEntry->gLimEdcaParamsBC[i].cw.max = + convert_cw(GET_CW(¶ms[i][cwmaxidx])); + updated = true; + } + if (psessionEntry->gLimEdcaParamsBC[i].txoplimit != + (uint16_t) params[i][txopidx]) { + psessionEntry->gLimEdcaParamsBC[i].txoplimit = + (uint16_t) params[i][txopidx]; + updated = true; + } + + PELOG1(sch_log + (pMac, LOG1, + "QoSUpdateBCast: AC :%d: AIFSN: %d, ACM %d, CWmin %d, CWmax %d, TxOp %d", + i, psessionEntry->gLimEdcaParamsBC[i].aci.aifsn, + psessionEntry->gLimEdcaParamsBC[i].aci.acm, + psessionEntry->gLimEdcaParamsBC[i].cw.min, + psessionEntry->gLimEdcaParamsBC[i].cw.max, + psessionEntry->gLimEdcaParamsBC[i].txoplimit); + ) + + } + + /* If there exists a concurrent STA-AP session, use its WMM params to broadcast in beacons. WFA Wifi Direct test plan 6.1.14 requirement */ + if (broadcast_wmm_of_concurrent_sta_session(pMac, psessionEntry)) + updated = true; + if (updated) + psessionEntry->gLimEdcaParamSetCount++; + + if (sch_set_fixed_beacon_fields(pMac, psessionEntry) != eSIR_SUCCESS) + PELOGE(sch_log(pMac, LOGE, "Unable to set beacon fields!");) +} + +void sch_qos_update_local(tpAniSirGlobal pMac, tpPESession psessionEntry) +{ + + uint32_t params[4][WNI_CFG_EDCA_ANI_ACBK_LOCAL_LEN]; + + if (sch_get_params(pMac, params, true /*local */) != eSIR_SUCCESS) { + PELOGE(sch_log(pMac, LOGE, FL("sch_get_params(local) failed"));) + return; + } + + set_sch_edca_params(pMac, params, psessionEntry); + + /* For AP, the bssID is stored in LIM Global context. */ + lim_send_edca_params(pMac, psessionEntry->gLimEdcaParams, + psessionEntry->bssIdx); +} + +/** ---------------------------------------------------------- + \fn sch_set_default_edca_params + \brief This function sets the gLimEdcaParams to the default + \ local wmm profile. + \param tpAniSirGlobal pMac + \return none + \ ------------------------------------------------------------ */ +void sch_set_default_edca_params(tpAniSirGlobal pMac, tpPESession psessionEntry) +{ + uint32_t params[4][WNI_CFG_EDCA_ANI_ACBK_LOCAL_LEN]; + + if (get_wmm_local_params(pMac, params) != eSIR_SUCCESS) { + PELOGE(sch_log(pMac, LOGE, FL("get_wmm_local_params() failed"));) + return; + } + + set_sch_edca_params(pMac, params, psessionEntry); + return; +} + +/** ---------------------------------------------------------- + \fn set_sch_edca_params + \brief This function fills in the gLimEdcaParams structure + \ with the given edca params. + \param tpAniSirGlobal pMac + \return none + \ ------------------------------------------------------------ */ +static void +set_sch_edca_params(tpAniSirGlobal pMac, + uint32_t params[][WNI_CFG_EDCA_ANI_ACBK_LOCAL_LEN], + tpPESession psessionEntry) +{ + uint32_t i; + uint32_t cwminidx, cwmaxidx, txopidx; + uint32_t phyMode; + + lim_get_phy_mode(pMac, &phyMode, psessionEntry); + + PELOG1(sch_log(pMac, LOG1, FL("lim_get_phy_mode() = %d"), phyMode);) + /* if (pMac->lim.gLimPhyMode == WNI_CFG_PHY_MODE_11G) */ + if (phyMode == WNI_CFG_PHY_MODE_11G) { + cwminidx = WNI_CFG_EDCA_PROFILE_CWMING_IDX; + cwmaxidx = WNI_CFG_EDCA_PROFILE_CWMAXG_IDX; + txopidx = WNI_CFG_EDCA_PROFILE_TXOPG_IDX; + } + /* else if (pMac->lim.gLimPhyMode == WNI_CFG_PHY_MODE_11B) */ + else if (phyMode == WNI_CFG_PHY_MODE_11B) { + cwminidx = WNI_CFG_EDCA_PROFILE_CWMINB_IDX; + cwmaxidx = WNI_CFG_EDCA_PROFILE_CWMAXB_IDX; + txopidx = WNI_CFG_EDCA_PROFILE_TXOPB_IDX; + } else { + /* This can happen if mode is not set yet, assume 11a mode */ + cwminidx = WNI_CFG_EDCA_PROFILE_CWMINA_IDX; + cwmaxidx = WNI_CFG_EDCA_PROFILE_CWMAXA_IDX; + txopidx = WNI_CFG_EDCA_PROFILE_TXOPA_IDX; + } + + for (i = 0; i < MAX_NUM_AC; i++) { + psessionEntry->gLimEdcaParams[i].aci.acm = + (uint8_t) params[i][WNI_CFG_EDCA_PROFILE_ACM_IDX]; + psessionEntry->gLimEdcaParams[i].aci.aifsn = + (uint8_t) params[i][WNI_CFG_EDCA_PROFILE_AIFSN_IDX]; + psessionEntry->gLimEdcaParams[i].cw.min = + convert_cw(GET_CW(¶ms[i][cwminidx])); + psessionEntry->gLimEdcaParams[i].cw.max = + convert_cw(GET_CW(¶ms[i][cwmaxidx])); + psessionEntry->gLimEdcaParams[i].txoplimit = + (uint16_t) params[i][txopidx]; + + PELOG1(sch_log + (pMac, LOG1, + FL + ("AC :%d: AIFSN: %d, ACM %d, CWmin %d, CWmax %d, TxOp %d"), + i, psessionEntry->gLimEdcaParams[i].aci.aifsn, + psessionEntry->gLimEdcaParams[i].aci.acm, + psessionEntry->gLimEdcaParams[i].cw.min, + psessionEntry->gLimEdcaParams[i].cw.max, + psessionEntry->gLimEdcaParams[i].txoplimit); + ) + + } + return; +} + +/** ---------------------------------------------------------- + \fn get_wmm_local_params + \brief This function gets the WMM local edca parameters. + \param tpAniSirGlobal pMac + \param uint32_t params[][WNI_CFG_EDCA_ANI_ACBK_LOCAL_LEN] + \return none + \ ------------------------------------------------------------ */ +static tSirRetStatus +get_wmm_local_params(tpAniSirGlobal pMac, + uint32_t params[][WNI_CFG_EDCA_ANI_ACBK_LOCAL_LEN]) +{ + uint32_t i, idx; + uint32_t *prf; + uint32_t wme_l[] = { + WNI_CFG_EDCA_WME_ACBE_LOCAL, WNI_CFG_EDCA_WME_ACBK_LOCAL, + WNI_CFG_EDCA_WME_ACVI_LOCAL, WNI_CFG_EDCA_WME_ACVO_LOCAL}; + + prf = &wme_l[0]; + for (i = 0; i < 4; i++) { + uint8_t data[WNI_CFG_EDCA_ANI_ACBK_LEN]; + uint32_t len = WNI_CFG_EDCA_ANI_ACBK_LOCAL_LEN; + if (wlan_cfg_get_str + (pMac, (uint16_t) prf[i], (uint8_t *) &data[0], + &len) != eSIR_SUCCESS) { + sch_log(pMac, LOGP, FL("cfgGet failed for %d"), prf[i]); + return eSIR_FAILURE; + } + if (len > WNI_CFG_EDCA_ANI_ACBK_LOCAL_LEN) { + sch_log(pMac, LOGE, + FL("cfgGet for %d: length is %d instead of %d"), + prf[i], len, WNI_CFG_EDCA_ANI_ACBK_LOCAL_LEN); + return eSIR_FAILURE; + } + for (idx = 0; idx < len; idx++) + params[i][idx] = (uint32_t) data[idx]; + } + return eSIR_SUCCESS; +} + +/** ---------------------------------------------------------- + \fn sch_edca_profile_update + \brief This function updates the local and broadcast + \ EDCA params in the gLimEdcaParams structure. It also + \ updates the edcaParamSetCount. + \param tpAniSirGlobal pMac + \return none + \ ------------------------------------------------------------ */ +void sch_edca_profile_update(tpAniSirGlobal pMac, tpPESession psessionEntry) +{ + if (LIM_IS_AP_ROLE(psessionEntry) || + LIM_IS_IBSS_ROLE(psessionEntry)) { + sch_qos_update_local(pMac, psessionEntry); + sch_qos_update_broadcast(pMac, psessionEntry); + } +} + +/* -------------------------------------------------------------------- */ diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/sch/sch_sys_params.h b/drivers/staging/qcacld-3.0/core/mac/src/pe/sch/sch_sys_params.h new file mode 100644 index 0000000000000000000000000000000000000000..adf5c198277fccd1e4e5e8fd702afda803dba8aa --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/sch/sch_sys_params.h @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2011-2012, 2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * + * This file sch_sys_params.h contains scheduler parameter definitions + * + * Author: Sandesh Goel + * Date: 02/25/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + * + */ + +#ifndef __SCH_SYS_PARAMS_H__ +#define __SCH_SYS_PARAMS_H__ + +/* / Unsolicited poll period (ms) (0 to disable) */ +#define SCH_POLL_PERIOD 1000 + +/* / RR timeout value (ms) (0 to disable) */ +#define SCH_RR_TIMEOUT_MS 40 + +/* / Default CP:CFP ratio */ +#define SCH_DEFAULT_CP_TO_CFP_RATIO 0 + +/* / Default maximum CFP duration (us) */ +#define SCH_DEFAULT_MAX_CFP_TIME 60000 + +/* / Default minimum CP duration (us) */ +#define SCH_DEFAULT_MIN_CP_TIME 100 + +/* / Amount of delay prior to starting CFP (us) */ +#define SCH_CFP_START_DELAY 100 + +/* / Unit of Txop in micro seconds */ +#define TXOP_UNIT_IN_USEC 32 + +/* / Minimum amount of time granted per instruction on average (units of txop) */ +#define MIN_TXOP_PER_INSTRUCTION 50 + +/* / Maximum amount of time granted per instruction (units of txop) */ +#define MAX_TXOP_PER_INSTRUCTION 300 /* HACK - 100 */ + +/* / Maximum amount of time granted to one entire schedule (units of txop) */ +#define MAX_TXOP_PER_SCHEDULE 400 + +/* / Scheduling quantum (units of TXOP) */ +#define SCH_QUANTUM_QUEUE 4 + +/* / Maximum unused quantum allowed to be accumulated by a queue */ +#define MAX_ACCUMULATED_QUANTUM 500 + +/* / Minimum allocated quantum for an uplink flow before a poll instruction is written */ +#define SCH_MIN_UL_ALLOC 12 + +/* ---- Scheduling Policy ---- */ + +/* / Number of QOS classes */ +#define SCH_NUM_QOS_CLASSES 2 + +#define SCH_POLICY_STRICT_PRI 0 +#define SCH_POLICY_DRR 1 + +/* / Scheduling quantum for each class if using DRR */ +#define SCH_QUANTUM_CLASS 100 + +/* / The default scheduling policy between classes */ +#define SCH_POLICY_DEFAULT SCH_POLICY_STRICT_PRI + +/* Scheduling weights for each priority */ + +#define SCH_QUANTUM_0 40 +#define SCH_QUANTUM_1 36 +#define SCH_QUANTUM_2 32 +#define SCH_QUANTUM_3 28 +#define SCH_QUANTUM_4 24 +#define SCH_QUANTUM_5 20 +#define SCH_QUANTUM_6 16 +#define SCH_QUANTUM_7 12 + +#endif diff --git a/drivers/staging/qcacld-3.0/core/mac/src/sys/common/inc/wlan_qct_sys.h b/drivers/staging/qcacld-3.0/core/mac/src/sys/common/inc/wlan_qct_sys.h new file mode 100644 index 0000000000000000000000000000000000000000..65f6ff5396be7cabbdfe1714b7d5d505b3a72451 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/sys/common/inc/wlan_qct_sys.h @@ -0,0 +1,195 @@ +/* + * Copyright (c) 2013-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#if !defined(WLAN_QCT_SYS_H__) +#define WLAN_QCT_SYS_H__ + +/**=========================================================================== + + \file wlan_qct_sys.h + + \brief System module API + + ==========================================================================*/ + +/* $HEADER$ */ + +/*--------------------------------------------------------------------------- + Include files + -------------------------------------------------------------------------*/ +#include +#include +#include + +/*--------------------------------------------------------------------------- + Preprocessor definitions and constants + -------------------------------------------------------------------------*/ + +/*--------------------------------------------------------------------------- + Type declarations + -------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------- + + \brief sysResponseCback() - SYS async resonse callback + + This is a protype for the callback function that SYS makes to various + modules in the system. + + \param pUserData - user data that is passed to the Callback function + when it is invoked. + + \return Nothing + + \sa sysMcStart(), sysMcThreadProbe(), sysTxThreadProbe() + + --------------------------------------------------------------------------*/ +typedef void (*sysResponseCback)(void *pUserData); + +typedef enum { + SYS_MSG_ID_MC_START, + SYS_MSG_ID_MC_THR_PROBE, + SYS_MSG_ID_MC_TIMER, + SYS_MSG_ID_MC_STOP, + SYS_MSG_ID_FTM_RSP, + SYS_MSG_ID_QVIT, + +} SYS_MSG_ID; + +/*--------------------------------------------------------------------------- + Preprocessor definitions and constants + -------------------------------------------------------------------------*/ + +/*--------------------------------------------------------------------------- + Function declarations and documenation + -------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------- + + \brief sys_build_message_header() - Build / initialize a SYS message header + + This function will initialize the SYS message header with the message type + and any internal fields needed for a new SYS message. This function sets + all but the message body, which is up to the caller to setup based on the + specific message being built. + + \note There are internal / reserved items in a SYS message that must be + set correctly for the message to be recognized as a SYS message by + the SYS message handlers. It is important for every SYS message to + be setup / built / initialized through this function. + + \param sysMsgId - a valid message ID for a SYS message. See the + SYS_MSG_ID enum for all the valid SYS message IDs. + + \param pMsg - pointer to the message structure to be setup. + + \return + + \sa + + --------------------------------------------------------------------------*/ +QDF_STATUS sys_build_message_header(SYS_MSG_ID sysMsgId, cds_msg_t *pMsg); + +/*---------------------------------------------------------------------------- + + \brief sysMcStart() - start the system Main Controller thread. + + This function starts the SYS (Main Controller) module. Starting this + module triggers the CFG download to the 'legacy' MAC software. + + \param p_cds_context - pointer to the CDS Context + + \param userCallback - this is a callback that is called when the SYS + has completed the 'start' funciton. + + \param pUserData - pointer to some user data entity that is passed to + the callback function as a parameter when invoked. + + \return QDF_STATUS_SUCCESS - + + \todo: We have not 'status' on the callback. How do we notify the + callback that there is a failure ? + + \sa + + --------------------------------------------------------------------------*/ +QDF_STATUS sysMcStart(v_CONTEXT_t p_cds_context, sysResponseCback userCallback, + void *pUserData); + +/*---------------------------------------------------------------------------- + + \brief sys_stop() - Stop the SYS module. + + This function stops the SYS module. + + \todo: What else do we need to do on sys_stop()? + + \param p_cds_context - pointer to the CDS Context + + \return QDF_STATUS_SUCCESS - the SYS module is stopped. + + QDF_STATUS_E_FAILURE - the SYS module open failed to stop. + + \sa + + --------------------------------------------------------------------------*/ +QDF_STATUS sys_stop(v_CONTEXT_t p_cds_context); + +/*---------------------------------------------------------------------------- + + \brief sys_mc_process_msg() - process SYS messages on the Main Controller thread + + This function processes SYS Messages on the Main Controller thread. + SYS messages consist of all 'legacy' messages (messages bound for legacy + modules like LIM, HAL, PE, etc.) as well as newly defined SYS message + types. + + SYS messages are identified by their type (in the SYS_MESSAGES enum) as + well as a 'cookie' that is in the reserved field of the message structure. + This 'cookie' is introduced to prevent any message type/ID conflicts with + the 'legacy' message types. + + Any module attempting to post a message to the SYS module must set the + message type to one of the types in the SYS_MESSAGE enum *and* must also + set the Reserved field in the message body to SYS_MSG_COOKIE. + + \param p_cds_context - pointer to the CDS Context + + \param pMsg - pointer to the message to be processed. + + \return - QDF_STATUS_SUCCESS - the message was processed successfully. + + QDF_STATUS_E_BADMSG - a bad (unknown type) message was received + and subsequently not processed. + \sa + + --------------------------------------------------------------------------*/ +QDF_STATUS sys_mc_process_msg(v_CONTEXT_t p_cds_context, cds_msg_t *pMsg); + +void wlan_sys_probe(void); + +#endif /* WLAN_QCT_SYS_H__ */ diff --git a/drivers/staging/qcacld-3.0/core/mac/src/sys/common/src/wlan_qct_sys.c b/drivers/staging/qcacld-3.0/core/mac/src/sys/common/src/wlan_qct_sys.c new file mode 100644 index 0000000000000000000000000000000000000000..01bb4db41f17bc8ceac500126bc188e19cdec089 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/sys/common/src/wlan_qct_sys.c @@ -0,0 +1,376 @@ +/* + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#include +#include +#include /* needed for tSirRetStatus */ +#include /* needed for tSirMbMsg */ +#include /* needed for SIR_... message types */ +#include /* needed for WNI_... message types */ +#include "ani_global.h" +#include "wma_types.h" +#include "sme_api.h" +#include "mac_init_api.h" +#include "qdf_trace.h" + +/* + * Cookie for SYS messages. Note that anyone posting a SYS Message + * has to write the COOKIE in the reserved field of the message. The + * SYS Module relies on this COOKIE + */ +#define SYS_MSG_COOKIE 0xFACE + +/* SYS stop timeout 30 seconds */ +#define SYS_STOP_TIMEOUT (30000) +static qdf_event_t g_stop_evt; + +/** + * sys_build_message_header() - to build the sys message header + * @sysMsgId: message id + * @pMsg: pointer to message context + * + * This API is used to build the sys message header. + * + * Return: QDF_STATUS + */ +QDF_STATUS sys_build_message_header(SYS_MSG_ID sysMsgId, cds_msg_t *pMsg) +{ + pMsg->type = sysMsgId; + pMsg->reserved = SYS_MSG_COOKIE; + + return QDF_STATUS_SUCCESS; +} + +/** + * sys_stop_complete_cb() - a callback when system stop completes + * @pUserData: pointer to user provided data context + * + * this callback is used once system stop is completed. + * + * Return: none + */ +#ifdef QDF_ENABLE_TRACING +static void sys_stop_complete_cb(void *pUserData) +{ + qdf_event_t *pStopEvt = (qdf_event_t *) pUserData; + QDF_STATUS qdf_status = qdf_event_set(pStopEvt); + + QDF_ASSERT(QDF_IS_STATUS_SUCCESS(qdf_status)); + +} +#else +static void sys_stop_complete_cb(void *pUserData) +{ + return; +} +#endif + +/** + * sys_stop() - To post stop message to system module + * @p_cds_context: pointer to cds context + * + * This API is used post a stop message to system module + * + * Return: QDF_STATUS + */ +QDF_STATUS sys_stop(v_CONTEXT_t p_cds_context) +{ + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + cds_msg_t sysMsg; + + /* Initialize the stop event */ + qdf_status = qdf_event_create(&g_stop_evt); + + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) + return qdf_status; + + /* post a message to SYS module in MC to stop SME and MAC */ + sys_build_message_header(SYS_MSG_ID_MC_STOP, &sysMsg); + + /* Save the user callback and user data */ + sysMsg.callback = sys_stop_complete_cb; + sysMsg.bodyptr = (void *)&g_stop_evt; + + /* post the message.. */ + qdf_status = cds_mq_post_message(CDS_MQ_ID_SYS, &sysMsg); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) + qdf_status = QDF_STATUS_E_BADMSG; + + qdf_status = qdf_wait_single_event(&g_stop_evt, SYS_STOP_TIMEOUT); + QDF_ASSERT(QDF_IS_STATUS_SUCCESS(qdf_status)); + + qdf_status = qdf_event_destroy(&g_stop_evt); + QDF_ASSERT(QDF_IS_STATUS_SUCCESS(qdf_status)); + + return qdf_status; +} + +/** + * sys_mc_process_msg() - to process system mc thread messages + * @p_cds_context: pointer to cds context + * @pMsg: message pointer + * + * This API is used to process the message + * + * Return: QDF_STATUS + */ +QDF_STATUS sys_mc_process_msg(v_CONTEXT_t p_cds_context, cds_msg_t *pMsg) +{ + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + qdf_mc_timer_callback_t timerCB; + tpAniSirGlobal mac_ctx; + void *hHal; + + if (NULL == pMsg) { + QDF_TRACE(QDF_MODULE_ID_SYS, QDF_TRACE_LEVEL_ERROR, + "%s: NULL pointer to cds_msg_t", __func__); + QDF_ASSERT(0); + return QDF_STATUS_E_INVAL; + } + + /* + * All 'new' SYS messages are identified by a cookie in the reserved + * field of the message as well as the message type. This prevents + * the possibility of overlap in the message types defined for new + * SYS messages with the 'legacy' message types. The legacy messages + * will not have this cookie in the reserved field + */ + if (SYS_MSG_COOKIE == pMsg->reserved) { + /* Process all the new SYS messages.. */ + switch (pMsg->type) { + case SYS_MSG_ID_MC_START: + /* + * Handling for this message is not needed now so adding + * debug print and QDF_ASSERT + */ + QDF_TRACE(QDF_MODULE_ID_SYS, QDF_TRACE_LEVEL_ERROR, + "Rx SYS_MSG_ID_MC_START msgType= %d [0x%08x]", + pMsg->type, pMsg->type); + QDF_ASSERT(0); + break; + + case SYS_MSG_ID_MC_STOP: + QDF_TRACE(QDF_MODULE_ID_SYS, QDF_TRACE_LEVEL_INFO, + "Processing SYS MC STOP"); + + /* get the HAL context... */ + hHal = cds_get_context(QDF_MODULE_ID_PE); + if (NULL == hHal) { + QDF_TRACE(QDF_MODULE_ID_SYS, + QDF_TRACE_LEVEL_ERROR, + "%s: Invalid hHal", __func__); + } else { + qdf_status = sme_stop(hHal, + HAL_STOP_TYPE_SYS_DEEP_SLEEP); + QDF_ASSERT(QDF_IS_STATUS_SUCCESS(qdf_status)); + qdf_status = mac_stop(hHal, + HAL_STOP_TYPE_SYS_DEEP_SLEEP); + QDF_ASSERT(QDF_IS_STATUS_SUCCESS(qdf_status)); + + ((sysResponseCback) pMsg->callback)( + (void *)pMsg->bodyptr); + + qdf_status = QDF_STATUS_SUCCESS; + } + break; + + case SYS_MSG_ID_MC_THR_PROBE: + /* + * Process MC thread probe. Just callback to the + * function that is in the message. + */ + QDF_TRACE(QDF_MODULE_ID_SYS, QDF_TRACE_LEVEL_ERROR, + "Rx SYS_MSG_ID_MC_THR_PROBE msgType=%d[0x%08x]", + pMsg->type, pMsg->type); + break; + + case SYS_MSG_ID_MC_TIMER: + timerCB = pMsg->callback; + if (NULL != timerCB) + timerCB(pMsg->bodyptr); + break; + + case SYS_MSG_ID_FTM_RSP: + hHal = cds_get_context(QDF_MODULE_ID_PE); + if (NULL == hHal) { + QDF_TRACE(QDF_MODULE_ID_SYS, + QDF_TRACE_LEVEL_ERROR, + FL("Invalid hal")); + qdf_mem_free(pMsg->bodyptr); + break; + } + mac_ctx = PMAC_STRUCT(hHal); + if (NULL == mac_ctx) { + QDF_TRACE(QDF_MODULE_ID_SYS, + QDF_TRACE_LEVEL_ERROR, + FL("Invalid mac context")); + qdf_mem_free(pMsg->bodyptr); + break; + } + if (NULL == mac_ctx->ftm_msg_processor_callback) { + QDF_TRACE(QDF_MODULE_ID_SYS, + QDF_TRACE_LEVEL_ERROR, + FL("callback pointer is NULL")); + qdf_mem_free(pMsg->bodyptr); + break; + } + mac_ctx->ftm_msg_processor_callback( + (void *)pMsg->bodyptr); + qdf_mem_free(pMsg->bodyptr); + break; + + default: + QDF_TRACE(QDF_MODULE_ID_SYS, QDF_TRACE_LEVEL_ERROR, + "Unknown message type msgType= %d [0x%08x]", + pMsg->type, pMsg->type); + break; + + } + } else { + QDF_TRACE(QDF_MODULE_ID_SYS, + QDF_TRACE_LEVEL_ERROR, + "Rx SYS unknown MC msgtype= %d [0x%08X]", + pMsg->type, pMsg->type); + QDF_ASSERT(0); + qdf_status = QDF_STATUS_E_BADMSG; + + if (pMsg->bodyptr) + qdf_mem_free(pMsg->bodyptr); + } + return qdf_status; +} + +/** + * sys_process_mmh_msg() - this api to process mmh message + * @pMac: pointer to mac context + * @pMsg: pointer to message + * + * This API is used to process mmh message + * + * Return: none + */ +void sys_process_mmh_msg(tpAniSirGlobal pMac, tSirMsgQ *pMsg) +{ + CDS_MQ_ID targetMQ = CDS_MQ_ID_SYS; + + /* + * The body of this pMsg is a tSirMbMsg + * Contrary to previous generation, we cannot free it here! + * It is up to the callee to free it + */ + if (NULL == pMsg) { + QDF_TRACE(QDF_MODULE_ID_SYS, QDF_TRACE_LEVEL_ERROR, + "NULL Message Pointer"); + QDF_ASSERT(0); + return; + } + + switch (pMsg->type) { + /* + * Following messages are routed to SYS + */ + case WNI_CFG_DNLD_REQ: + case WNI_CFG_DNLD_CNF: + /* Forward this message to the SYS module */ + targetMQ = CDS_MQ_ID_SYS; + QDF_TRACE(QDF_MODULE_ID_SYS, QDF_TRACE_LEVEL_ERROR, + "Handling for the Message ID %d is removed in SYS", + pMsg->type); + QDF_ASSERT(0); + break; + + /* + * Following messages are routed to HAL + */ + case WNI_CFG_DNLD_RSP: + /* Forward this message to the HAL module */ + targetMQ = CDS_MQ_ID_WMA; + QDF_TRACE(QDF_MODULE_ID_SYS, QDF_TRACE_LEVEL_ERROR, + "Handling for the Message ID %d is removed as no HAL", + pMsg->type); + + QDF_ASSERT(0); + break; + + case WNI_CFG_GET_REQ: + case WNI_CFG_SET_REQ: + case WNI_CFG_SET_REQ_NO_RSP: + case eWNI_SME_SYS_READY_IND: + /* Forward this message to the PE module */ + targetMQ = CDS_MQ_ID_PE; + break; + + case WNI_CFG_GET_RSP: + case WNI_CFG_SET_CNF: + /* Forward this message to the SME module */ + targetMQ = CDS_MQ_ID_SME; + break; + + default: + if ((pMsg->type >= eWNI_SME_MSG_TYPES_BEGIN) + && (pMsg->type <= eWNI_SME_MSG_TYPES_END)) { + targetMQ = CDS_MQ_ID_SME; + break; + } + + QDF_TRACE(QDF_MODULE_ID_SYS, QDF_TRACE_LEVEL_ERROR, + "Message of ID %d is not yet handled by SYS", + pMsg->type); + QDF_ASSERT(0); + } + + /* + * Post now the message to the appropriate module for handling + */ + if (QDF_STATUS_SUCCESS != cds_mq_post_message(targetMQ, + (cds_msg_t *) pMsg)) { + /* + * Caller doesn't allocate memory for the pMsg. + * It allocate memory for bodyptr free the mem and return + */ + if (pMsg->bodyptr) + qdf_mem_free(pMsg->bodyptr); + } + +} + +/** + * wlan_sys_probe() - API to post MC thread probe + * + * This API will be used send probe message + * + * Return: none + */ +void wlan_sys_probe(void) +{ + cds_msg_t cds_message; + + cds_message.reserved = SYS_MSG_COOKIE; + cds_message.type = SYS_MSG_ID_MC_THR_PROBE; + cds_message.bodyptr = NULL; + cds_mq_post_message(CDS_MQ_ID_SYS, &cds_message); +} diff --git a/drivers/staging/qcacld-3.0/core/mac/src/sys/legacy/src/platform/inc/sys_wrapper.h b/drivers/staging/qcacld-3.0/core/mac/src/sys/legacy/src/platform/inc/sys_wrapper.h new file mode 100644 index 0000000000000000000000000000000000000000..68c4a001794045250c38bc7a4e618de8de18cd04 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/sys/legacy/src/platform/inc/sys_wrapper.h @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2011-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * @file VossWrapper.h + * + * @brief This header file contains the various structure definitions and + * function prototypes for the RTOS abstraction layer, implemented for VOSS + */ + +#ifndef __VOSS_WRAPPER_H +#define __VOSS_WRAPPER_H + +#ifdef __cplusplus +extern "C" { +#endif + + +/*--------------------------------------------------------------------------- + * Include Files + * ------------------------------------------------------------------------*/ + +#include "sir_types.h" +#include "sir_params.h" +#include "sys_def.h" +#include "qdf_mc_timer.h" +#include "qdf_types.h" +#include "qdf_trace.h" +#include "qdf_mem.h" + +/* Interlocked Compare Exchange related definitions */ + +/* Define basic constants for the ThreadX kernel. */ + +#define TX_NO_WAIT 0 +#define TX_WAIT_FOREVER 0xFFFFFFFFUL +#define TX_AUTO_ACTIVATE 1 +#define TX_NO_ACTIVATE 0 + +/* API return values. */ +#define TX_SUCCESS 0x00 +#define TX_QUEUE_FULL 0x01 +/* ... */ +#define TX_NO_INSTANCE 0x0D +/* ... */ +#define TX_TIMER_ERROR 0x15 +#define TX_TICK_ERROR 0x16 +/* ... */ + +#ifndef true +#define true 1 +#endif + +#ifndef false +#define false 0 +#endif + +/* Following macro specifies the number of milliseconds which constitute 1 ThreadX timer tick. Used + for mimicking the ThreadX timer behaviour on VOSS. */ +/* Use the same MACRO used by firmware modules to calculate TICKs from mSec */ +/* Mismatch would cause worng timer value to be programmed */ +#define TX_MSECS_IN_1_TICK SYS_TICK_DUR_MS + +/* Signature with which the TX_TIMER struct is initialized, when the timer is created */ +#define TX_AIRGO_TMR_SIGNATURE 0xDEADBEEF + +#ifdef TIMER_MANAGER +#define tx_timer_create(a, b, c, d, e, f, g, h) tx_timer_create_intern_debug((void *)a, b, c, d, e, f, g, h, __FILE__, __LINE__) +#else +#define tx_timer_create(a, b, c, d, e, f, g, h) tx_timer_create_intern((void *)a, b, c, d, e, f, g, h) +#endif + +/*--------------------------------------------------------------------*/ +/* Timer structure */ +/* This structure is used to implement ThreadX timer facility. Just */ +/* like ThreadX, timer expiration handler executes at the highest */ +/* possible priority level, i.e. DISPATCH_LEVEL. */ +/*--------------------------------------------------------------------*/ +typedef struct TX_TIMER_STRUCT { +#ifdef WLAN_DEBUG +#define TIMER_MAX_NAME_LEN 50 + char timerName[TIMER_MAX_NAME_LEN]; +#endif + uint64_t tmrSignature; + void (*pExpireFunc)(void *, uint32_t); + uint32_t expireInput; + uint64_t initScheduleTimeInMsecs; + uint64_t rescheduleTimeInMsecs; + qdf_mc_timer_t qdf_timer; + + /* Pointer to the MAC global structure, which stores the context for the NIC, */ + /* for which this timer is supposed to operate. */ + void *pMac; + uint8_t sessionId; + +} TX_TIMER; + +#define TX_TIMER_VALID(timer) (timer.pMac != 0) + +extern uint64_t tx_time_get(void); +extern uint32_t tx_timer_activate(TX_TIMER *); +extern uint32_t tx_timer_change(TX_TIMER *, uint64_t, uint64_t); +extern uint32_t tx_timer_change_context(TX_TIMER *, uint32_t); +#ifdef TIMER_MANAGER +extern uint32_t tx_timer_create_intern_debug(void *, TX_TIMER *, + char *, void (*)(void *, + uint32_t), + uint32_t, uint64_t, + uint64_t, uint64_t, + char *fileName, + uint32_t lineNum); +#else +extern uint32_t tx_timer_create_intern(void *, TX_TIMER *, char *, + void (*)(void *, uint32_t), + uint32_t, uint64_t, uint64_t, + uint64_t); +#endif +extern uint32_t tx_timer_deactivate(TX_TIMER *); +extern uint32_t tx_timer_delete(TX_TIMER *); +extern bool tx_timer_running(TX_TIMER *); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/drivers/staging/qcacld-3.0/core/mac/src/sys/legacy/src/platform/src/sys_wrapper.c b/drivers/staging/qcacld-3.0/core/mac/src/sys/legacy/src/platform/src/sys_wrapper.c new file mode 100644 index 0000000000000000000000000000000000000000..1a20cd5a37e058a2832dcfb7e9867bf9a63387ea --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/sys/legacy/src/platform/src/sys_wrapper.c @@ -0,0 +1,485 @@ +/* + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/*=========================================================================== + @file VossWrapper.c + + @brief This source file contains the various function definitions for the + RTOS abstraction layer, implemented for VOSS + ===========================================================================*/ + +/*=========================================================================== + + EDIT HISTORY FOR FILE + + This section contains comments describing changes made to the module. + Notice that changes are listed in reverse chronological order. + + $Header:$ $DateTime: $ $Author: $ + + when who what, where, why + -------- --- -------------------------------------------------------- + 03/31/09 sho Remove the use of qdf_timerIsActive flag as it is not + thread-safe + 02/17/08 sho Fix the timer callback function to work when it is called + after the timer has stopped due to a race condition. + 02/10/08 sho Refactor the TX timer to use VOS timer directly instead + of using VOS utility timer + 12/15/08 sho Resolved errors and warnings from the AMSS compiler when + this is ported from WM + 11/20/08 sho Renamed this to VosWrapper.c; remove all dependencies on + WM platform and allow this to work on all VOSS enabled + platform + 06/24/08 tbh Modified the file to remove the dependecy on HDD files as + part of Gen6 bring up process. + 10/29/02 Neelay Das Created file. + + ===========================================================================*/ + +/*--------------------------------------------------------------------------- + * Include Files + * ------------------------------------------------------------------------*/ +#include "sys_wrapper.h" + +#ifdef WLAN_DEBUG +#define TIMER_NAME (timer_ptr->timerName) +#else +#define TIMER_NAME "N/A" +#endif + +/**--------------------------------------------------------------------- + * tx_time_get() + * + * FUNCTION: + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param + * + * @return current system time in units of miliseconds + * + */ +uint64_t tx_time_get(void) +{ + return qdf_mc_timer_get_system_ticks(); + +} /* * tx_time_get() */ + +/**--------------------------------------------------------------------- + * tx_timer_activate() + * + * FUNCTION: + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param + * + * @return TX_SUCCESS. + * + */ +uint32_t tx_timer_activate(TX_TIMER *timer_ptr) +{ + QDF_STATUS status; + + /* Uncomment the asserts, if the intention is to debug the occurence of the */ + /* following anomalous cnditions. */ + + /* Assert that the timer structure pointer passed, is not NULL */ + /* dbgAssert(NULL != timer_ptr); */ + + /* If the NIC is halting just spoof a successful timer activation, so that all */ + /* the timers can be cleaned up. */ + + if (NULL == timer_ptr) + return TX_TIMER_ERROR; + + /* Put a check for the free builds */ + if (TX_AIRGO_TMR_SIGNATURE != timer_ptr->tmrSignature) { + QDF_ASSERT(timer_ptr->tmrSignature == 0); + + return TX_TIMER_ERROR; + + } + /* Check for an uninitialized timer */ + QDF_ASSERT(0 != strlen(TIMER_NAME)); + + status = qdf_mc_timer_start(&timer_ptr->qdf_timer, + timer_ptr->initScheduleTimeInMsecs); + + if (QDF_STATUS_SUCCESS == status) { + return TX_SUCCESS; + } else if (QDF_STATUS_E_ALREADY == status) { + /* starting timer fails because timer is already started; this is okay */ + QDF_TRACE(QDF_MODULE_ID_SYS, QDF_TRACE_LEVEL_INFO, + "Timer %s is already running\n", TIMER_NAME); + return TX_SUCCESS; + } else { + QDF_TRACE(QDF_MODULE_ID_SYS, QDF_TRACE_LEVEL_ERROR, + "Timer %s fails to activate\n", TIMER_NAME); + return TX_TIMER_ERROR; + } +} /*** tx_timer_activate() ***/ + +/**--------------------------------------------------------------------- + * tx_timer_change() + * + * FUNCTION: + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param + * + * @return TX_SUCCESS. + * + */ +uint32_t tx_timer_change(TX_TIMER *timer_ptr, + uint64_t initScheduleTimeInTicks, + uint64_t rescheduleTimeInTicks) +{ + /* Put a check for the free builds */ + if (TX_AIRGO_TMR_SIGNATURE != timer_ptr->tmrSignature) { + QDF_ASSERT(timer_ptr->tmrSignature == 0); + return TX_TIMER_ERROR; + } + /* changes cannot be applied until timer stops running */ + if (QDF_TIMER_STATE_STOPPED == + qdf_mc_timer_get_current_state(&timer_ptr->qdf_timer)) { + timer_ptr->initScheduleTimeInMsecs = + TX_MSECS_IN_1_TICK * initScheduleTimeInTicks; + timer_ptr->rescheduleTimeInMsecs = + TX_MSECS_IN_1_TICK * rescheduleTimeInTicks; + return TX_SUCCESS; + } else { + return TX_TIMER_ERROR; + } +} /*** tx_timer_change() ***/ + +/**--------------------------------------------------------------------- + * tx_timer_change_context() + * + * FUNCTION: + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param + * + * @return TX_SUCCESS. + * + */ +uint32_t tx_timer_change_context(TX_TIMER *timer_ptr, + uint32_t expiration_input) +{ + + /* Put a check for the free builds */ + if (TX_AIRGO_TMR_SIGNATURE != timer_ptr->tmrSignature) { + QDF_ASSERT(timer_ptr->tmrSignature == 0); + + return TX_TIMER_ERROR; + } + /* changes cannot be applied until timer stops running */ + if (QDF_TIMER_STATE_STOPPED == + qdf_mc_timer_get_current_state(&timer_ptr->qdf_timer)) { + timer_ptr->expireInput = expiration_input; + return TX_SUCCESS; + } else { + return TX_TIMER_ERROR; + } +} /*** tx_timer_change() ***/ + +/**--------------------------------------------------------------------- + * tx_main_timer_func() + * + * FUNCTION: + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param + * + * @return None. + * + */ +static void tx_main_timer_func(void *functionContext) +{ + TX_TIMER *timer_ptr = (TX_TIMER *) functionContext; + + if (NULL == timer_ptr) { + QDF_ASSERT(0); + return; + } + + if (NULL == timer_ptr->pExpireFunc) { + QDF_ASSERT(0); + return; + } + + /* Now call the actual timer function, taking the function pointer, */ + /* from the timer structure. */ + (*timer_ptr->pExpireFunc)(timer_ptr->pMac, timer_ptr->expireInput); + + /* check if this needs to be rescheduled */ + if (0 != timer_ptr->rescheduleTimeInMsecs) { + QDF_STATUS status; + status = qdf_mc_timer_start(&timer_ptr->qdf_timer, + timer_ptr->rescheduleTimeInMsecs); + timer_ptr->rescheduleTimeInMsecs = 0; + + if (QDF_STATUS_SUCCESS != status) { + QDF_TRACE(QDF_MODULE_ID_SYS, QDF_TRACE_LEVEL_WARN, + "Unable to reschedule timer %s; status=%d", + TIMER_NAME, status); + } + } +} /*** tx_timer_change() ***/ + +#ifdef TIMER_MANAGER +uint32_t tx_timer_create_intern_debug(void *pMacGlobal, + TX_TIMER *timer_ptr, char *name_ptr, + void (*expiration_function)(void *, + uint32_t), + uint32_t expiration_input, + uint64_t initScheduleTimeInTicks, + uint64_t rescheduleTimeInTicks, + uint64_t auto_activate, char *fileName, + uint32_t lineNum) +{ + QDF_STATUS status; + + if (NULL == expiration_function) { + QDF_TRACE(QDF_MODULE_ID_SYS, QDF_TRACE_LEVEL_ERROR, + "NULL timer expiration"); + QDF_ASSERT(0); + return TX_TIMER_ERROR; + } + + if (NULL == name_ptr) { + + QDF_TRACE(QDF_MODULE_ID_SYS, QDF_TRACE_LEVEL_ERROR, + "NULL name pointer for timer"); + QDF_ASSERT(0); + return TX_TIMER_ERROR; + } + if (!initScheduleTimeInTicks) + return TX_TICK_ERROR; + + if (!timer_ptr) + return TX_TIMER_ERROR; + + /* Initialize timer structure */ + timer_ptr->pExpireFunc = expiration_function; + timer_ptr->expireInput = expiration_input; + timer_ptr->initScheduleTimeInMsecs = + TX_MSECS_IN_1_TICK * initScheduleTimeInTicks; + timer_ptr->rescheduleTimeInMsecs = + TX_MSECS_IN_1_TICK * rescheduleTimeInTicks; + timer_ptr->pMac = pMacGlobal; + + /* Set the flag indicating that the timer was created */ + timer_ptr->tmrSignature = TX_AIRGO_TMR_SIGNATURE; + +#ifdef WLAN_DEBUG + /* Store the timer name */ + strlcpy(timer_ptr->timerName, name_ptr, sizeof(timer_ptr->timerName)); +#endif /* Store the timer name, for Debug build only */ + + status = + qdf_mc_timer_init_debug(&timer_ptr->qdf_timer, QDF_TIMER_TYPE_SW, + tx_main_timer_func, (void *) timer_ptr, + fileName, lineNum); + if (QDF_STATUS_SUCCESS != status) { + QDF_TRACE(QDF_MODULE_ID_SYS, QDF_TRACE_LEVEL_ERROR, + "Cannot create timer for %s\n", TIMER_NAME); + return TX_TIMER_ERROR; + } + + if (0 != rescheduleTimeInTicks) { + QDF_TRACE(QDF_MODULE_ID_SYS, QDF_TRACE_LEVEL_INFO, + "Creating periodic timer for %s\n", TIMER_NAME); + } + /* Activate this timer if required */ + if (auto_activate) { + tx_timer_activate(timer_ptr); + } + + return TX_SUCCESS; + +} /* ** tx_timer_create() *** / */ +#else +uint32_t tx_timer_create_intern(void *pMacGlobal, TX_TIMER *timer_ptr, + char *name_ptr, + void (*expiration_function)(void *, + uint32_t), + uint32_t expiration_input, + uint64_t initScheduleTimeInTicks, + uint64_t rescheduleTimeInTicks, + uint64_t auto_activate) +{ + QDF_STATUS status; + + if ((NULL == name_ptr) || (NULL == expiration_function)) + return TX_TIMER_ERROR; + + if (!initScheduleTimeInTicks) + return TX_TICK_ERROR; + + if (!timer_ptr) + return TX_TIMER_ERROR; + + /* Initialize timer structure */ + timer_ptr->pExpireFunc = expiration_function; + timer_ptr->expireInput = expiration_input; + timer_ptr->initScheduleTimeInMsecs = + TX_MSECS_IN_1_TICK * initScheduleTimeInTicks; + timer_ptr->rescheduleTimeInMsecs = + TX_MSECS_IN_1_TICK * rescheduleTimeInTicks; + timer_ptr->pMac = pMacGlobal; + + /* Set the flag indicating that the timer was created */ + timer_ptr->tmrSignature = TX_AIRGO_TMR_SIGNATURE; + +#ifdef WLAN_DEBUG + /* Store the timer name */ + strlcpy(timer_ptr->timerName, name_ptr, sizeof(timer_ptr->timerName)); +#endif /* Store the timer name, for Debug build only */ + + status = qdf_mc_timer_init(&timer_ptr->qdf_timer, QDF_TIMER_TYPE_SW, + tx_main_timer_func, (void *) timer_ptr); + if (QDF_STATUS_SUCCESS != status) { + QDF_TRACE(QDF_MODULE_ID_SYS, QDF_TRACE_LEVEL_ERROR, + "Cannot create timer for %s\n", TIMER_NAME); + return TX_TIMER_ERROR; + } + + if (0 != rescheduleTimeInTicks) { + QDF_TRACE(QDF_MODULE_ID_SYS, QDF_TRACE_LEVEL_INFO, + "Creating periodic timer for %s\n", TIMER_NAME); + } + /* Activate this timer if required */ + if (auto_activate) { + tx_timer_activate(timer_ptr); + } + + return TX_SUCCESS; + +} /* ** tx_timer_create() *** / */ +#endif + +/**--------------------------------------------------------------------- + * tx_timer_deactivate() + * + * FUNCTION: + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param + * + * @return TX_SUCCESS. + * + */ +uint32_t tx_timer_deactivate(TX_TIMER *timer_ptr) +{ + QDF_STATUS vStatus; + + /* Put a check for the free builds */ + if (TX_AIRGO_TMR_SIGNATURE != timer_ptr->tmrSignature) { + return TX_TIMER_ERROR; + } + /* if the timer is not running then we do not need to do anything here */ + vStatus = qdf_mc_timer_stop(&timer_ptr->qdf_timer); + if (QDF_STATUS_SUCCESS != vStatus) { + QDF_TRACE(QDF_MODULE_ID_SYS, QDF_TRACE_LEVEL_INFO_HIGH, + "Unable to stop timer %s; status =%d\n", + TIMER_NAME, vStatus); + } + + return TX_SUCCESS; + +} /*** tx_timer_deactivate() ***/ + +uint32_t tx_timer_delete(TX_TIMER *timer_ptr) +{ + /* Put a check for the free builds */ + if (TX_AIRGO_TMR_SIGNATURE != timer_ptr->tmrSignature) { + return TX_TIMER_ERROR; + } + + qdf_mc_timer_destroy(&timer_ptr->qdf_timer); + return TX_SUCCESS; +} /*** tx_timer_delete() ***/ + +/**--------------------------------------------------------------------- + * tx_timer_running() + * + * FUNCTION: + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param + * + * @return TX_SUCCESS. + * + */ +bool tx_timer_running(TX_TIMER *timer_ptr) +{ + /* Put a check for the free builds */ + if (TX_AIRGO_TMR_SIGNATURE != timer_ptr->tmrSignature) + return false; + + if (QDF_TIMER_STATE_RUNNING == + qdf_mc_timer_get_current_state(&timer_ptr->qdf_timer)) { + return true; + } + return false; + +} /*** tx_timer_running() ***/ diff --git a/drivers/staging/qcacld-3.0/core/mac/src/sys/legacy/src/system/inc/sys_debug.h b/drivers/staging/qcacld-3.0/core/mac/src/sys/legacy/src/system/inc/sys_debug.h new file mode 100644 index 0000000000000000000000000000000000000000..4a2578885d214686df04d540cbeead869608eebb --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/sys/legacy/src/system/inc/sys_debug.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2011-2012, 2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * + * This file sys_global.h contains the logDump utility for system module. + * Author: V. K. Kandarpa + * Date: 01/24/2002 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + */ +#ifndef __SYS_DEBUG_H__ +#define __SYS_DEBUG_H__ + +#include +#include "utils_api.h" +#include "sir_debug.h" +#include "sir_params.h" + +void sys_log(tpAniSirGlobal pMac, uint32_t loglevel, const char *pString, ...); + +#endif /* __SYS_DEBUG_H__ */ diff --git a/drivers/staging/qcacld-3.0/core/mac/src/sys/legacy/src/system/inc/sys_def.h b/drivers/staging/qcacld-3.0/core/mac/src/sys/legacy/src/system/inc/sys_def.h new file mode 100644 index 0000000000000000000000000000000000000000..abdae33dc19c1a5a21291aa4fecd10c8ea3e0fa9 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/sys/legacy/src/system/inc/sys_def.h @@ -0,0 +1,168 @@ +/* + * Copyright (c) 2011-2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * + * This file sys_def.h contains the common definitions used to bring up + * Sirius system. + * Author: V. K. Kandarpa + * Date: 04/13/2002 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + */ + +#ifndef __SYSDEF_H +#define __SYSDEF_H + +/* / Sirius system level definitions */ +/* NOTE: Do not program system timer tick duration to less than 1msec */ + +/* / System timer tick duration in nanoseconds */ +#define SYS_TICK_DUR_NS 10000000 /* 10ms */ +#define SYS_TICK_TO_MICRO_SECOND 10000 + +/* / System timer tick duration in milliseconds */ +#define SYS_TICK_DUR_MS (SYS_TICK_DUR_NS/1000000) + +/* / Clocks in a millisecond */ +#define SYS_CLOCKS_PER_MS 120000 /* 120 MHz */ + +/* / System timer tick duration in clocks */ +#define SYS_TICK_DUR_CLK (SYS_TICK_DUR_MS * SYS_CLOCKS_PER_MS) + +/* / Number of timer ticks in a second */ +#define SYS_TICKS_PER_SECOND (1000/SYS_TICK_DUR_MS) + +/* / Macro to convert MS to Ticks */ +#define SYS_MS_TO_TICKS(x) ((x) / SYS_TICK_DUR_MS) + +/* / Macro to convert Seconds to Ticks */ +#define SYS_SEC_TO_TICKS(x) ((x) * SYS_TICKS_PER_SECOND) + +/* / Macro to convert Minutes to Ticks */ +#define SYS_MIN_TO_TICKS(x) (((x) * 60) * SYS_TICKS_PER_SECOND) + +/* / MNT task processing interval in seconds */ +#define SYS_MNT_INTERVAL 60 + +/* / MS to Time Units */ +#define SYS_MS_TO_TU(x) ((x * 1000) >> 10) + +/* / TU to MS */ +#define SYS_TU_TO_MS(x) ((x << 10) / 1000) + +/* --------- End of Windows & RTAI ----------- */ + +/* / Message queue definitions */ + +/* / gHalMsgQ */ +#define SYS_HAL_Q_SIZE 200 /* Holds up to 25 messages */ + +/* / gMMHhiPriorityMsgQ */ +#define SYS_MMH_HI_PRI_Q_SIZE 200 /* Holds up to 25 messages */ + +/* / gMMHprotocolMsgQ */ +#define SYS_MMH_PROT_Q_SIZE 400 /* Holds up to 50 messages */ + +/* / gMMHdebugMsgQ */ +#define SYS_MMH_DEBUG_Q_SIZE 800 /* Holds up to 100 messages */ + +/* / gMAINTmsgQ */ +#define SYS_MNT_Q_SIZE 200 /* Holds up to 25 messages */ + +/* / LIM Message Queue */ +#define SYS_LIM_Q_SIZE 400 /* Holds up to 50 messages */ + +/* / Scheduler Message Queue */ +#define SYS_SCH_Q_SIZE 800 /* Holds up to 25 messages */ + +/* / PMM Message Queue */ +#define SYS_PMM_Q_SIZE 800 /* Holds up to 100 messages */ + +/* / TX Message Queue */ +#define SYS_TX_Q_SIZE 2048 /* Holds up to 400 messages */ + +/* / RX Message Queue */ +#define SYS_RX_Q_SIZE 2048 /* Holds up to 400 messages */ + +/* / PTT Message Queue */ +#define SYS_NIM_PTT_Q_SIZE 200 /* Holds up to 25 messages */ + +/* / Thread definitions */ +/* tHAL */ + +#define SYS_HAL_THREAD_ENTRY_FUNCTION halEntry +#define SYS_HAL_STACK_SIZE 8192 +#define SYS_HAL_THREAD_PRIORITY 2 + +/* tDPH */ + +#define SYS_DPH_THREAD_ENTRY_FUNCTION dphEntry +#define SYS_DPH_STACK_SIZE 8192 +#define SYS_DPH_THREAD_PRIORITY 15 + +/* tBBT */ + +#define SYS_BBT_THREAD_ENTRY_FUNCTION bbtEntry +#define SYS_BBT_STACK_SIZE 8192 +#define SYS_BBT_THREAD_PRIORITY 16 + +/* tSCH */ + +#define SYS_SCH_STACK_SIZE 8192 +#define SYS_SCH_THREAD_PRIORITY 17 + +/* tPMM */ + +#define SYS_PMM_STACK_SIZE 8192 +#define SYS_PMM_THREAD_PRIORITY 17 + +/* tLIM */ + +#define SYS_LIM_THREAD_ENTRY_FUNCTION limEntry +#define SYS_LIM_STACK_SIZE 8192 +#define SYS_LIM_THREAD_PRIORITY 18 + +/* tMAINT */ + +#define SYS_MNT_THREAD_ENTRY_FUNCTION mntEntry +#define SYS_MNT_STACK_SIZE 8192 +#define SYS_MNT_THREAD_PRIORITY 25 + +/* tMMH */ + +#define SYS_MMH_THREAD_ENTRY_FUNCTION mmhEntry +#define SYS_MMH_STACK_SIZE 8192 +#define SYS_MMH_THREAD_PRIORITY 10 + +/* tNIM_MNT_PKT_GEN */ + +#define SYS_NIM_PTT_THREAD_STACK_SIZE 8192 +#define SYS_NIM_PTT_THREAD_PRIORITY 28 + +#endif /* __SYSDEF_H */ diff --git a/drivers/staging/qcacld-3.0/core/mac/src/sys/legacy/src/system/inc/sys_entry_func.h b/drivers/staging/qcacld-3.0/core/mac/src/sys/legacy/src/system/inc/sys_entry_func.h new file mode 100644 index 0000000000000000000000000000000000000000..41afc8bdfd3fbb2424ef245faadb7e6e434b8250 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/sys/legacy/src/system/inc/sys_entry_func.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2011-2012, 2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * + * This file sys_entry_func.h contains module entry functions definitions + * Author: V. K. Kandarpa + * Date: 04/13/2002 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + */ +#ifndef __SYS_ENTRY_FUNC_H +#define __SYS_ENTRY_FUNC_H + +#include "ani_global.h" + +extern tSirRetStatus sys_init_globals(tpAniSirGlobal); +extern void sysBbtEntry(uint32_t dummy); +extern void sysSchEntry(uint32_t dummy); +extern void sysPmmEntry(uint32_t dummy); +extern void sysDphEntry(uint32_t dummy); +extern void sysLimEntry(uint32_t dummy); +extern void sysMmhEntry(uint32_t dummy); +extern void sysMntEntry(uint32_t dummy); +extern void sysHalEntry(uint32_t dummy); +extern void sysNimPttEntry(uint32_t dummy); + +#endif /* __SYS_ENTRY_FUNC_H */ diff --git a/drivers/staging/qcacld-3.0/core/mac/src/sys/legacy/src/system/inc/sys_startup.h b/drivers/staging/qcacld-3.0/core/mac/src/sys/legacy/src/system/inc/sys_startup.h new file mode 100644 index 0000000000000000000000000000000000000000..e56bd6193dba26cd3037f7848e77c0e76a3906ba --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/sys/legacy/src/system/inc/sys_startup.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2011-2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * + * sys_startup.h: System startup header file. + * Author: V. K. Kandarpa + * Date: 01/29/2002 + * + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------------- + * + */ + +#ifndef __SYSSTARTUP_H +#define __SYSSTARTUP_H + +#include "sir_params.h" + +/* Defines */ + +/* Function */ + +extern void sysMACCleanup(void *); +extern tSirRetStatus sys_bbt_process_message_core(struct sAniSirGlobal *, tpSirMsgQ, + uint32_t, uint32_t); + +#endif /* __SYSSTARTUP_H */ diff --git a/drivers/staging/qcacld-3.0/core/mac/src/sys/legacy/src/system/src/mac_init_api.c b/drivers/staging/qcacld-3.0/core/mac/src/sys/legacy/src/system/src/mac_init_api.c new file mode 100644 index 0000000000000000000000000000000000000000..fb1591b6bb437d13cd4dd663efe00cb95283f5cd --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/sys/legacy/src/system/src/mac_init_api.c @@ -0,0 +1,185 @@ +/* + * Copyright (c) 2011-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * + * mac_init_api.c - This file has all the mac level init functions + * for all the defined threads at system level. + * Author: Dinesh Upadhyay + * Date: 04/23/2007 + * History:- + * Date: 04/08/2008 Modified by: Santosh Mandiganal + * Modification Information: Code to allocate and free the memory for DumpTable entry. + * -------------------------------------------------------------------------- + * + */ +/* Standard include files */ +#include "cfg_api.h" /* cfg_cleanup */ +#include "lim_api.h" /* lim_cleanup */ +#include "sir_types.h" +#include "sys_debug.h" +#include "sys_entry_func.h" +#include "mac_init_api.h" + +#ifdef TRACE_RECORD +#include "mac_trace.h" +#endif + +static tAniSirGlobal global_mac_context; + +extern tSirRetStatus halDoCfgInit(tpAniSirGlobal pMac); +extern tSirRetStatus halProcessStartEvent(tpAniSirGlobal pMac); + +tSirRetStatus mac_start(tHalHandle hHal, void *pHalMacStartParams) +{ + tSirRetStatus status = eSIR_SUCCESS; + tpAniSirGlobal pMac = (tpAniSirGlobal) hHal; + + if (NULL == pMac) { + QDF_ASSERT(0); + status = eSIR_FAILURE; + return status; + } + + pMac->gDriverType = + ((tHalMacStartParameters *) pHalMacStartParams)->driverType; + + sys_log(pMac, LOG2, FL("called")); + + if (ANI_DRIVER_TYPE(pMac) != eDRIVER_TYPE_MFG) { + status = pe_start(pMac); + } + + return status; +} + +/** ------------------------------------------------------------- + \fn mac_stop + \brief this function will be called from HDD to stop MAC. This function will stop all the mac modules. + \ memory with global context will only be initialized not freed here. + \param tHalHandle hHal + \param tHalStopType + \return tSirRetStatus + -------------------------------------------------------------*/ + +tSirRetStatus mac_stop(tHalHandle hHal, tHalStopType stopType) +{ + tpAniSirGlobal pMac = (tpAniSirGlobal) hHal; + pe_stop(pMac); + cfg_cleanup(pMac); + + return eSIR_SUCCESS; +} + +/** ------------------------------------------------------------- + \fn mac_open + \brief this function will be called during init. This function is suppose to allocate all the + \ memory with the global context will be allocated here. + \param tHalHandle pHalHandle + \param tHddHandle hHdd + \param tHalOpenParameters* pHalOpenParams + \return tSirRetStatus + -------------------------------------------------------------*/ + +tSirRetStatus mac_open(tHalHandle *pHalHandle, tHddHandle hHdd, + struct cds_config_info *cds_cfg) +{ + tpAniSirGlobal p_mac = &global_mac_context; + tSirRetStatus status = eSIR_SUCCESS; + + if (pHalHandle == NULL) + return eSIR_FAILURE; + + /* + * Set various global fields of p_mac here + * (Could be platform dependant as some variables in p_mac are platform + * dependant) + */ + p_mac->hHdd = hHdd; + *pHalHandle = (tHalHandle) p_mac; + + { + /* + * For Non-FTM cases this value will be reset during mac_start + */ + if (cds_cfg->driver_type) + p_mac->gDriverType = eDRIVER_TYPE_MFG; + + /* Call various PE (and other layer init here) */ + if (eSIR_SUCCESS != log_init(p_mac)) + return eSIR_FAILURE; + + /* Call routine to initialize CFG data structures */ + if (eSIR_SUCCESS != cfg_init(p_mac)) { + log_deinit(p_mac); + return eSIR_FAILURE; + } + + sys_init_globals(p_mac); + } + + /* FW: 0 to 2047 and Host: 2048 to 4095 */ + p_mac->mgmtSeqNum = WLAN_HOST_SEQ_NUM_MIN - 1; + p_mac->first_scan_done = false; + + status = pe_open(p_mac, cds_cfg); + if (eSIR_SUCCESS != status) { + sys_log(p_mac, LOGE, FL("pe_open failure")); + cfg_de_init(p_mac); + log_deinit(p_mac); + } + + return status; +} + +/** ------------------------------------------------------------- + \fn mac_close + \brief this function will be called in shutdown sequence from HDD. All the + \ allocated memory with global context will be freed here. + \param tpAniSirGlobal pMac + \return none + -------------------------------------------------------------*/ + +tSirRetStatus mac_close(tHalHandle hHal) +{ + + tpAniSirGlobal pMac = (tpAniSirGlobal) hHal; + + if (!pMac) + return eSIR_FAILURE; + + pe_close(pMac); + + /* Call routine to free-up all CFG data structures */ + cfg_de_init(pMac); + + log_deinit(pMac); + + qdf_mem_zero(pMac, sizeof(*pMac)); + + return eSIR_SUCCESS; +} diff --git a/drivers/staging/qcacld-3.0/core/mac/src/sys/legacy/src/system/src/sys_entry_func.c b/drivers/staging/qcacld-3.0/core/mac/src/sys/legacy/src/system/src/sys_entry_func.c new file mode 100644 index 0000000000000000000000000000000000000000..2df4bc7ef8889cc041edbf4a3ba616a472bf7d67 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/sys/legacy/src/system/src/sys_entry_func.c @@ -0,0 +1,242 @@ +/* + * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * sys_entry_func.cc - This file has all the system level entry functions + * for all the defined threads at system level. + * Author: V. K. Kandarpa + * Date: 01/16/2002 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------------- + * + */ +/* Standard include files */ + +/* Application Specific include files */ +#include "sir_common.h" +#include "ani_global.h" + +#include "lim_api.h" +#include "sch_api.h" +#include "utils_api.h" + +#include "sys_debug.h" +#include "sys_def.h" +#include "sys_entry_func.h" +#include "sys_startup.h" +#include "lim_trace.h" +#include "wma_types.h" + +tSirRetStatus postPTTMsgApi(tpAniSirGlobal pMac, tSirMsgQ *pMsg); + +#include "qdf_types.h" +#include "cds_packet.h" + +#define MAX_DEAUTH_ALLOWED 5 +/* --------------------------------------------------------------------------- */ +/** + * sys_init_globals + * + * FUNCTION: + * Initializes system level global parameters + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param tpAniSirGlobal Sirius software parameter struct pointer + * @return None + */ + +tSirRetStatus sys_init_globals(tpAniSirGlobal pMac) +{ + + qdf_mem_set((uint8_t *) &pMac->sys, sizeof(pMac->sys), 0); + + pMac->sys.gSysEnableScanMode = 1; + pMac->sys.gSysEnableLinkMonitorMode = 0; + sch_init_globals(pMac); + + return eSIR_SUCCESS; +} + +/** + * sys_bbt_process_message_core() - to process BBT messages + * @mac_ctx: pointer to mac context + * @msg: message pointer + * @type: type of persona + * @subtype: subtype of persona + * + * This routine is to process some bbt messages + * + * Return: None + */ +tSirRetStatus +sys_bbt_process_message_core(tpAniSirGlobal mac_ctx, tpSirMsgQ msg, + uint32_t type, uint32_t subtype) +{ + uint32_t framecount; + tSirRetStatus ret; + void *bd_ptr; + tMgmtFrmDropReason dropreason; + cds_pkt_t *vos_pkt = (cds_pkt_t *) msg->bodyptr; + QDF_STATUS qdf_status = + wma_ds_peek_rx_packet_info(vos_pkt, &bd_ptr, false); + + mac_ctx->sys.gSysBbtReceived++; + + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) + goto fail; + + sys_log(mac_ctx, LOG3, FL("Rx Mgmt Frame Subtype: %d\n"), subtype); + sir_dump_buf(mac_ctx, SIR_SYS_MODULE_ID, LOG3, + (uint8_t *) WMA_GET_RX_MAC_HEADER(bd_ptr), + WMA_GET_RX_MPDU_LEN(bd_ptr)); + sir_dump_buf(mac_ctx, SIR_SYS_MODULE_ID, LOG3, + WMA_GET_RX_MPDU_DATA(bd_ptr), + WMA_GET_RX_PAYLOAD_LEN(bd_ptr)); + + mac_ctx->sys.gSysFrameCount[type][subtype]++; + framecount = mac_ctx->sys.gSysFrameCount[type][subtype]; + + if (type == SIR_MAC_MGMT_FRAME) { + tpSirMacMgmtHdr mac_hdr; + + /* + * Drop beacon frames in deferred state to avoid VOSS run out of + * message wrappers. + */ + if ((subtype == SIR_MAC_MGMT_BEACON) && + (!lim_is_system_in_scan_state(mac_ctx)) && + (GET_LIM_PROCESS_DEFD_MESGS(mac_ctx) != true) && + !mac_ctx->lim.gLimSystemInScanLearnMode) { + sys_log(mac_ctx, LOG1, + FL("dropping received beacon in deffered state")); + goto fail; + } + + dropreason = lim_is_pkt_candidate_for_drop(mac_ctx, bd_ptr, + subtype); + if (eMGMT_DROP_NO_DROP != dropreason) { + sys_log(mac_ctx, LOG1, + FL("Mgmt Frame %d being dropped, reason: %d\n"), + subtype, dropreason); + MTRACE(mac_trace(mac_ctx, + TRACE_CODE_RX_MGMT_DROP, NO_SESSION, + dropreason);) + goto fail; + } + + mac_hdr = WMA_GET_RX_MAC_HEADER(bd_ptr); + if (subtype == SIR_MAC_MGMT_ASSOC_REQ) { + sys_log(mac_ctx, LOG1, + FL("ASSOC REQ frame allowed: da: " MAC_ADDRESS_STR ", sa: " MAC_ADDRESS_STR ", bssid: " MAC_ADDRESS_STR ", Assoc Req count so far: %d\n"), + MAC_ADDR_ARRAY(mac_hdr->da), + MAC_ADDR_ARRAY(mac_hdr->sa), + MAC_ADDR_ARRAY(mac_hdr->bssId), + mac_ctx->sys.gSysFrameCount[type][subtype]); + } + if (subtype == SIR_MAC_MGMT_DEAUTH) { + sys_log(mac_ctx, LOG1, + FL("DEAUTH frame allowed: da: " MAC_ADDRESS_STR ", sa: " MAC_ADDRESS_STR ", bssid: " MAC_ADDRESS_STR ", DEAUTH count so far: %d\n"), + MAC_ADDR_ARRAY(mac_hdr->da), + MAC_ADDR_ARRAY(mac_hdr->sa), + MAC_ADDR_ARRAY(mac_hdr->bssId), + mac_ctx->sys.gSysFrameCount[type][subtype]); + } + if (subtype == SIR_MAC_MGMT_DISASSOC) { + sys_log(mac_ctx, LOG1, + FL("DISASSOC frame allowed: da: " MAC_ADDRESS_STR ", sa: " MAC_ADDRESS_STR ", bssid: " MAC_ADDRESS_STR ", DISASSOC count so far: %d\n"), + MAC_ADDR_ARRAY(mac_hdr->da), + MAC_ADDR_ARRAY(mac_hdr->sa), + MAC_ADDR_ARRAY(mac_hdr->bssId), + mac_ctx->sys.gSysFrameCount[type][subtype]); + } + + /* + * Post the message to PE Queue. Prioritize the + * Auth and assoc frames. + */ + if ((subtype == SIR_MAC_MGMT_AUTH) || + (subtype == SIR_MAC_MGMT_ASSOC_RSP) || + (subtype == SIR_MAC_MGMT_REASSOC_RSP) || + (subtype == SIR_MAC_MGMT_ASSOC_REQ) || + (subtype == SIR_MAC_MGMT_REASSOC_REQ)) + ret = (tSirRetStatus) + lim_post_msg_high_priority(mac_ctx, msg); + else + ret = (tSirRetStatus) lim_post_msg_api(mac_ctx, msg); + if (ret != eSIR_SUCCESS) { + sys_log(mac_ctx, LOGE, + FL("posting to LIM2 failed, ret %d\n"), ret); + goto fail; + } + mac_ctx->sys.gSysBbtPostedToLim++; + } else if (type == SIR_MAC_DATA_FRAME) { +#ifdef FEATURE_WLAN_ESE + PELOGW(sys_log(mac_ctx, LOGW, FL("IAPP Frame...\n"));); + /* Post the message to PE Queue */ + ret = (tSirRetStatus) lim_post_msg_api(mac_ctx, msg); + if (ret != eSIR_SUCCESS) { + sys_log(mac_ctx, LOGE, + FL("posting to LIM2 failed, ret %d\n"), ret); + goto fail; + } + mac_ctx->sys.gSysBbtPostedToLim++; +#endif + } else { + sys_log(mac_ctx, LOG3, + "BBT received Invalid type %d subtype %d " + "LIM state %X. BD dump is:\n", type, subtype, + lim_get_sme_state(mac_ctx)); + goto fail; + } + return eSIR_SUCCESS; +fail: + mac_ctx->sys.gSysBbtDropped++; + return eSIR_FAILURE; +} + +void sys_log(tpAniSirGlobal pMac, uint32_t loglevel, const char *pString, ...) +{ + /* Verify against current log level */ + if (loglevel > + pMac->utils.gLogDbgLevel[LOG_INDEX_FOR_MODULE(SIR_SYS_MODULE_ID)]) + return; + else { + va_list marker; + + va_start(marker, pString); /* Initialize variable arguments. */ + + log_debug(pMac, SIR_SYS_MODULE_ID, loglevel, pString, marker); + + va_end(marker); /* Reset variable arguments. */ + } +} diff --git a/drivers/staging/qcacld-3.0/core/mac/src/sys/legacy/src/utils/inc/dot11fdefs.h b/drivers/staging/qcacld-3.0/core/mac/src/sys/legacy/src/utils/inc/dot11fdefs.h new file mode 100644 index 0000000000000000000000000000000000000000..7a155bf8cdee58ae2cb1f6aea261df550d32def1 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/sys/legacy/src/utils/inc/dot11fdefs.h @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2011-2012, 2014-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef DOT11FDEFS_H_82A7B72E_C36C_465D_82A7_139EA5322582 +#define DOT11FDEFS_H_82A7B72E_C36C_465D_82A7_139EA5322582 +/** + * \file dot11fdefs.h + * + * \brief C defines customizing our framesc-generated code + * + * + * + * + * 'framesc' generates code written in terms of a number of macros + * intended for customization. + * + * + */ + +#include "parser_api.h" + +/* This controls how the "dot11f" code copies memory */ +#define DOT11F_MEMCPY(ctx, dst, src, len) \ + qdf_mem_copy((uint8_t *)(dst), (uint8_t *)(src), (len)) + +/* This controls how the "dot11f" code compares memory */ +#define DOT11F_MEMCMP(ctx, lhs, rhs, len) \ + (qdf_mem_cmp((uint8_t *)(lhs), (uint8_t *)(rhs), (len))) + +#if defined(DBG) && (DBG != 0) + +# /* define DOT11F_ENABLE_LOGGING */ +# /* define DOT11F_DUMP_FRAMES */ +#define DOT11F_LOG_GATE (4) +#define FRAMES_SEV_FOR_FRAME(ctx, sig) \ + (DOT11F_ASSOCREQUEST == (sig) ? 3 : 5) + +#if defined(DOT11F_ENABLE_LOGGING) + +#define DOT11F_HAVE_LOG_MACROS + +#define FRAMES_LOG0(ctx, sev, fmt) \ + dot11f_log((ctx), (sev), (fmt)); + +#define FRAMES_LOG1(ctx, sev, fmt, p1) \ + dot11f_log((ctx), (sev), (fmt), (p1)); + +#define FRAMES_LOG2(ctx, sev, fmt, p1, p2) \ + dot11f_log((ctx), (sev), (fmt), (p1), (p2)); + +#define FRAMES_LOG3(ctx, sev, fmt, p1, p2, p3) \ + dot11f_log((ctx), (sev), (fmt), (p1), (p2), (p3)); + +#define FRAMES_DUMP(ctx, sev, p, n) \ + sir_dump_buf((pCtx), SIR_DBG_MODULE_ID, (sev), (p), (n)); + +#endif /* #if defined( DOT11F_ENABLE_LOGGING ) */ + +#else + +#undef DOT11F_ENABLE_LOGGING +#undef DOT11F_DUMP_FRAMES +#define DOT11F_LOG_GATE (1) + +#endif + +/* #define DOT11F_ENABLE_DBG_BREAK ( 1 ) */ + +/* Local Variables: */ +/* fill-column: 72 */ +/* indent-tabs-mode: nil */ +/* show-trailing-whitespace: t */ +/* End: */ + +#endif /* DOT11FDEFS_H_82A7B72E_C36C_465D_82A7_139EA5322582 */ diff --git a/drivers/staging/qcacld-3.0/core/mac/src/sys/legacy/src/utils/inc/utils_parser.h b/drivers/staging/qcacld-3.0/core/mac/src/sys/legacy/src/utils/inc/utils_parser.h new file mode 100644 index 0000000000000000000000000000000000000000..3b63a0df737ef2ae93822ecdf469bd5070781ef2 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/sys/legacy/src/utils/inc/utils_parser.h @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2011-2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * + * This file utils_parser.h contains the utility function protos + * used internally by the parser + * Author: Chandra Modumudi + * Date: 02/11/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + * + */ +#ifndef __UTILS_PARSE_H__ +#define __UTILS_PARSE_H__ + +#include +#include "sir_api.h" +#include "dot11f.h" +#include "utils_api.h" + +void convert_ssid(tpAniSirGlobal, tSirMacSSid *, tDot11fIESSID *); +void convert_supp_rates(tpAniSirGlobal, tSirMacRateSet *, tDot11fIESuppRates *); +void convert_fh_params(tpAniSirGlobal, tSirMacFHParamSet *, + tDot11fIEFHParamSet *); +void convert_ext_supp_rates(tpAniSirGlobal, tSirMacRateSet *, + tDot11fIEExtSuppRates *); +void convert_qos_caps(tpAniSirGlobal, tSirMacQosCapabilityIE *, + tDot11fIEQOSCapsAp *); +void convert_qos_caps_station(tpAniSirGlobal, tSirMacQosCapabilityStaIE *, + tDot11fIEQOSCapsStation *); +tSirRetStatus convert_wpa(tpAniSirGlobal, tSirMacWpaInfo *, tDot11fIEWPA *); +tSirRetStatus convert_wpa_opaque(tpAniSirGlobal, tSirMacWpaInfo *, + tDot11fIEWPAOpaque *); +tSirRetStatus convert_wapi_opaque(tpAniSirGlobal, tSirMacWapiInfo *, + tDot11fIEWAPIOpaque *); +tSirRetStatus convert_rsn(tpAniSirGlobal, tSirMacRsnInfo *, tDot11fIERSN *); +tSirRetStatus convert_rsn_opaque(tpAniSirGlobal, tSirMacRsnInfo *, + tDot11fIERSNOpaque *); +void convert_power_caps(tpAniSirGlobal, tSirMacPowerCapabilityIE *, + tDot11fIEPowerCaps *); +void convert_supp_channels(tpAniSirGlobal, tSirMacSupportedChannelIE *, + tDot11fIESuppChannels *); +void convert_cf_params(tpAniSirGlobal, tSirMacCfParamSet *, tDot11fIECFParams *); +void convert_tim(tpAniSirGlobal, tSirMacTim *, tDot11fIETIM *); +void convert_country(tpAniSirGlobal, tSirCountryInformation *, + tDot11fIECountry *); +void convert_wmm_params(tpAniSirGlobal, tSirMacEdcaParamSetIE *, + tDot11fIEWMMParams *); +void convert_erp_info(tpAniSirGlobal, tSirMacErpInfo *, tDot11fIEERPInfo *); +void convert_edca_param(tpAniSirGlobal, tSirMacEdcaParamSetIE *, + tDot11fIEEDCAParamSet *); +void convert_tspec(tpAniSirGlobal, tSirMacTspecIE *, tDot11fIETSPEC *); +tSirRetStatus convert_tclas(tpAniSirGlobal, tSirTclasInfo *, tDot11fIETCLAS *); +void convert_wmmtspec(tpAniSirGlobal, tSirMacTspecIE *, tDot11fIEWMMTSPEC *); +tSirRetStatus convert_wmmtclas(tpAniSirGlobal, tSirTclasInfo *, + tDot11fIEWMMTCLAS *); +void convert_ts_delay(tpAniSirGlobal, tSirMacTsDelayIE *, tDot11fIETSDelay *); +void convert_schedule(tpAniSirGlobal, tSirMacScheduleIE *, tDot11fIESchedule *); +void convert_wmm_schedule(tpAniSirGlobal, tSirMacScheduleIE *, + tDot11fIEWMMSchedule *); +tSirRetStatus convert_wsc_opaque(tpAniSirGlobal, tSirAddie *, + tDot11fIEWscIEOpaque *); +tSirRetStatus convert_p2p_opaque(tpAniSirGlobal, tSirAddie *, + tDot11fIEP2PIEOpaque *); +#ifdef WLAN_FEATURE_WFD +tSirRetStatus convert_wfd_opaque(tpAniSirGlobal, tSirAddie *, + tDot11fIEWFDIEOpaque *); +#endif +void convert_qos_mapset_frame(tpAniSirGlobal, tSirQosMapSet *, + tDot11fIEQosMapSet *); + +#endif diff --git a/drivers/staging/qcacld-3.0/core/mac/src/sys/legacy/src/utils/src/dot11f.c b/drivers/staging/qcacld-3.0/core/mac/src/sys/legacy/src/utils/src/dot11f.c new file mode 100644 index 0000000000000000000000000000000000000000..a6089b382ff44c843788978f9e23b053f02e3b4f --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/sys/legacy/src/utils/src/dot11f.c @@ -0,0 +1,22975 @@ +/* + * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * \file dot11f.c + * + * \brief Structures, functions & definitions for + * working with 802.11 Frames + * + * + * This file was automatically generated by 'framesc' + * Fri Jun 9 14:23:47 2017 from the following file(s): + * + * dot11f.frms + * + * PLEASE DON'T EDIT THIS FILE BY HAND! + * + */ + +#if !defined ANI_OS_TYPE_OSX && !defined ANI_OS_TYPE_LINUX && !defined ANI_OS_TYPE_ANDROID +#include /* For memcpy */ +#include /* For _vsnprintf */ +#include /* For offsetof */ +#endif + +#include +#include +#include "dot11fdefs.h" +#include "dot11f.h" + +#if defined(_MSC_VER) +#pragma warning (disable:4244) +#pragma warning (disable:4505) +#pragma warning (disable:4702) +#pragma warning (disable:4996)/* ... was declared deprecated */ +#endif /* Microsoft C/C++ */ + +typedef unsigned char tFRAMES_BOOL; +typedef void (*pfnGeneric_t)(void); + +typedef struct sFFDefn { + const char *name; + uint32_t offset; + uint16_t sig; + uint8_t size; +} tFFDefn; + +typedef struct sIEDefn { + uint32_t offset; + uint32_t presenceOffset; + uint32_t countOffset; + const char *name; + uint16_t arraybound; + uint16_t minSize; + uint16_t maxSize; + uint16_t sig; + unsigned char oui[5]; + unsigned char noui; + uint8_t eid; + tFRAMES_BOOL fMandatory; +} tIEDefn; + +#if !defined(countof) +#define countof(x) (sizeof((x)) / sizeof((x)[0])) +#endif + +#if !defined(DOT11F_MEMCPY) +#define DOT11F_MEMCPY(ctx, dst, src, len) \ + memcpy((dst), (src), (len)) +#endif + +#if !defined(DOT11F_MEMCMP) +#define DOT11F_MEMCMP(ctx, lhs, rhs, len) \ + memcmp((lhs), (rhs), (len)) +#endif + +#ifndef DOT11F_HAVE_LOG_SEVERITIES +#define FRLOG_OFF (0) +#define FRLOGP (1) +#define FRLOGE (2) +#define FRLOGW (3) +#define FRLOG1 (4) +#define FRLOG2 (5) +#define FRLOG3 (6) +#define FRLOG4 (7) +#endif + +#define FRFL(x) x + +#define FRAMES_LOG0(ctx, sev, fmt) +#define FRAMES_LOG1(ctx, sev, fmt, p1) +#define FRAMES_LOG2(ctx, sev, fmt, p1, p2) +#define FRAMES_LOG3(ctx, sev, fmt, p1, p2, p3) +#define FRAMES_DUMP(ctx, sev, p, n) +#ifndef FRAMES_SEV_FOR_FRAME +#define FRAMES_SEV_FOR_FRAME(ctx, sig) FRLOG3 +#endif + +#if defined(DOT11F_ENABLE_DBG_BREAK) && defined (WIN32) +#define FRAMES_DBG_BREAK() { _asm int 3 } +#else +#define FRAMES_DBG_BREAK() +#endif + +#if !defined(DOT11F_PARAMETER_CHECK) +#if defined (DOT11F_HAVE_WIN32_API) + +#define DOT11F_PARAMETER_CHECK(pBuf, nBuf, pFrm, nFrm) \ + if (!pBuf || IsBadReadPtr(pBuf, nBuf))\ + return DOT11F_BAD_INPUT_BUFFER; \ + if (!pFrm || IsBadWritePtr(pFrm, nFrm))\ + return DOT11F_BAD_OUTPUT_BUFFER \ + +#define DOT11F_PARAMETER_CHECK2(pSrc, pBuf, nBuf, pnConsumed) \ + if (!pSrc || IsBadReadPtr(pSrc, 4))\ + eturn DOT11F_BAD_INPUT_BUFFER; \ + if (!pBuf || IsBadWritePtr(pBuf, nBuf))\ + return DOT11F_BAD_OUTPUT_BUFFER; \ + if (!nBuf)\ + return DOT11F_BAD_OUTPUT_BUFFER; \ + if (IsBadWritePtr(pnConsumed, 4))\ + return DOT11F_BAD_OUTPUT_BUFFER \ + +#else + +#define DOT11F_PARAMETER_CHECK(pBuf, nBuf, pFrm, nFrm) \ + if (!pBuf)\ + return DOT11F_BAD_INPUT_BUFFER; \ + if (!pFrm)\ + return DOT11F_BAD_OUTPUT_BUFFER \ + +#define DOT11F_PARAMETER_CHECK2(pSrc, pBuf, nBuf, pnConsumed) \ + if (!pSrc)\ + return DOT11F_BAD_INPUT_BUFFER; \ + if (!pBuf)\ + return DOT11F_BAD_OUTPUT_BUFFER; \ + if (!nBuf)\ + return DOT11F_BAD_OUTPUT_BUFFER; \ + if (!pnConsumed)\ + return DOT11F_BAD_OUTPUT_BUFFER \ + +#endif +#endif + +static void framesntohs(tpAniSirGlobal pCtx, + uint16_t *pOut, + uint8_t *pIn, + tFRAMES_BOOL fMsb) +{ + (void)pCtx; +#if defined (DOT11F_LITTLE_ENDIAN_HOST) + if (!fMsb) + DOT11F_MEMCPY(pCtx, (uint16_t *)pOut, pIn, 2); + else + *pOut = (uint16_t)(*pIn << 8) | *(pIn + 1); +#else + if (!fMsb) + *pOut = (uint16_t)(*pIn | (*(pIn + 1) << 8)); + else + DOT11F_MEMCPY(pCtx, (uint16_t *)pOut, pIn, 2); +#endif +} + +static void framesntohl(tpAniSirGlobal pCtx, + uint32_t *pOut, + uint8_t *pIn, + tFRAMES_BOOL fMsb) +{ + (void)pCtx; +#if defined (DOT11F_LITTLE_ENDIAN_HOST) + if (!fMsb) + DOT11F_MEMCPY(pCtx, (uint32_t *)pOut, pIn, 4); + else + *pOut = (uint32_t)(*pIn << 24) | + (*(pIn + 1) << 16) | + (*(pIn + 2) << 8) | + (*(pIn + 3)); +#else + if (!fMsb) + *pOut = (uint32_t)(*(pIn + 3) << 24) | + (*(pIn + 2) << 16) | + (*(pIn + 1) << 8) | + (*(pIn)); +else + *pOut = *(uint32_t *)pIn; +#endif +} + +static void framesntohq(tpAniSirGlobal pCtx, + tDOT11F_U64 *pOut, + uint8_t *pIn, + tFRAMES_BOOL fMsb) +{ +#if defined (DOT11F_LITTLE_ENDIAN_HOST) + framesntohl(pCtx, &((*pOut)[0]), pIn, fMsb); + framesntohl(pCtx, &((*pOut)[1]), pIn + 4, fMsb); +#else + framesntohl(pCtx, &((*pOut)[1]), pIn, fMsb); + framesntohl(pCtx, &((*pOut)[0]), pIn + 4, fMsb); +#endif +} + +static void frameshtons(tpAniSirGlobal pCtx, + uint8_t *pOut, + uint16_t pIn, + tFRAMES_BOOL fMsb) +{ + (void)pCtx; +#if defined (DOT11F_LITTLE_ENDIAN_HOST) + if (!fMsb) { + DOT11F_MEMCPY(pCtx, pOut, &pIn, 2); + } else { + *pOut = (pIn & 0xff00) >> 8; + *(pOut + 1) = pIn & 0xff; + } +#else + if (!fMsb) { + *pOut = pIn & 0xff; + *(pOut + 1) = (pIn & 0xff00) >> 8; + } else { + DOT11F_MEMCPY(pCtx, pOut, &pIn, 2); + } +#endif +} + +static void frameshtonl(tpAniSirGlobal pCtx, + uint8_t *pOut, + uint32_t pIn, + tFRAMES_BOOL fMsb) +{ + (void)pCtx; +#if defined (DOT11F_LITTLE_ENDIAN_HOST) + if (!fMsb) { + DOT11F_MEMCPY(pCtx, pOut, &pIn, 4); + } else { + *pOut = (pIn & 0xff000000) >> 24; + *(pOut + 1) = (pIn & 0x00ff0000) >> 16; + *(pOut + 2) = (pIn & 0x0000ff00) >> 8; + *(pOut + 3) = (pIn & 0x000000ff); + } +#else + if (!fMsb) { + *pOut = (pIn & 0x000000ff); + *(pOut + 1) = (pIn & 0x0000ff00) >> 8; + *(pOut + 2) = (pIn & 0x00ff0000) >> 16; + *(pOut + 3) = (pIn & 0xff000000) >> 24; + } else { + DOT11F_MEMCPY(pCtx, pOut, &pIn, 4); + } +#endif +} + +static void frameshtonq(tpAniSirGlobal pCtx, + uint8_t *pOut, + tDOT11F_U64 pIn, + tFRAMES_BOOL fMsb) +{ +#if defined (DOT11F_LITTLE_ENDIAN_HOST) + frameshtonl(pCtx, pOut, pIn[0], fMsb); + frameshtonl(pCtx, pOut + 4, pIn[1], fMsb); +#else + frameshtonl(pCtx, pOut + 4, pIn[1], fMsb); + frameshtonl(pCtx, pOut, pIn[0], fMsb); +#endif +} + +static const tIEDefn *find_ie_defn(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint32_t nBuf, + const tIEDefn IEs[]) +{ + const tIEDefn *pIe; + (void)pCtx; + + pIe = &(IEs[0]); + while (0xff != pIe->eid) { + if (*pBuf == pIe->eid) { + if (0 == pIe->noui) + return pIe; + + if ((nBuf > (uint32_t)(pIe->noui + 2)) && + (!DOT11F_MEMCMP(pCtx, pBuf + 2, pIe->oui, + pIe->noui))) + return pIe; + } + + ++pIe; + } + + return NULL; +} + +static uint32_t get_container_ies_len(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint32_t nBuf, + uint8_t *pnConsumed, + const tIEDefn IEs[]) +{ + const tIEDefn *pIe, *pIeFirst; + uint8_t *pBufRemaining = pBuf; + uint8_t len = 0; + (void)pCtx; + + pIeFirst = &(IEs[0]); + + if (*pBufRemaining != pIeFirst->eid) + return DOT11F_INTERNAL_ERROR; + len += *(pBufRemaining+1); + pBufRemaining += len + 2; + len += 2; + while (len < nBuf) { + pIe = find_ie_defn(pCtx, pBufRemaining, nBuf + len, IEs); + if (NULL == pIe) + break; + if (pIe->eid == pIeFirst->eid) + break; + len += *(pBufRemaining + 1) + 2; + pBufRemaining += *(pBufRemaining + 1) + 2; + } + + *pnConsumed = len; + return DOT11F_PARSE_SUCCESS; + +} + + +static uint32_t unpack_core(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint32_t nBuf, + const tFFDefn FFs[], + const tIEDefn IEs[], + uint8_t *pFrm, + size_t nFrm); +static uint32_t pack_core(tpAniSirGlobal pCtx, + uint8_t *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed, + const tFFDefn FFs[], + const tIEDefn IEs[]); +static uint32_t get_packed_size_core(tpAniSirGlobal pCtx, + uint8_t *pFrm, + uint32_t *pnNeeded, + const tIEDefn IEs[]); + +static uint32_t dot11f_unpack_tlv_common_func(tpAniSirGlobal pCtx, uint8_t *pBuf, + uint16_t tlvlen, uint8_t *pDstPresent, + uint8_t *pDstField) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)tlvlen; /* Shutup the compiler */ + + *pDstPresent = 1; + *pDstField = *pBuf; + (void)pCtx; + return status; +} /* End dot11f_unpack_tlv_common_func. */ + +static uint32_t dot11f_unpack_tlv_common_func2(tpAniSirGlobal pCtx, uint8_t *pBuf, + uint16_t tlvlen, uint8_t *pDstPresent, + uint16_t *pDstState) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)tlvlen; /* Shutup the compiler */ + + *pDstPresent = 1; + framesntohs(pCtx, pDstState, pBuf, 1); + (void)pCtx; + return status; + +} /* End dot11f_unpack_tlv_common_func2. */ + +static void dot11f_unpack_ff_common_func(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint16_t *pDstField) +{ + framesntohs(pCtx, pDstField, pBuf, 0); + (void)pCtx; +} /* End dot11f_unpack_ff_common_func. */ + +static uint32_t dot11f_unpack_ie_common_func(tpAniSirGlobal pCtx, uint8_t *pBuf, + uint8_t ielen, uint8_t *pDstPresent , + uint8_t *pDstField) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)ielen; + (void)pBuf; + if ((*pDstPresent)) + status = DOT11F_DUPLICATE_IE; + *pDstPresent = 1; + *pDstField = *pBuf; + (void)pCtx; + + return status; +} /* End dot11f_unpack_ie_common_func */ + +typedef struct sTLVDefn { + uint32_t offset; + uint32_t presenceOffset; + const char *name; + uint16_t sig; + uint32_t id; + uint32_t pec; + uint32_t minSize; + uint32_t maxSize; + uint8_t fMandatory; + uint8_t sType; + uint8_t sLen; + uint8_t fMsb; +} tTLVDefn; + +static const tTLVDefn *find_tlv_defn(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint32_t nBuf, + const tTLVDefn TLVs[]) +{ + const tTLVDefn *pTlv; + uint32_t pec; + uint16_t id; + + pTlv = &(TLVs[0]); + (void)pCtx; + if (pTlv->sType == 2) + framesntohs(pCtx, &id, pBuf, 1); + else + id = *pBuf; + + while (0xffff != pTlv->id) { + if (id == pTlv->id) { + if (0 == pTlv->pec) + return pTlv; + + if (nBuf > 5) { + pec = ((*(pBuf + 4)) << 16) | + ((*(pBuf + 5)) << 8) | + *(pBuf + 6); + if (pec == pTlv->pec) + return pTlv; + } + } + + ++pTlv; + } + + return NULL; +} + +static uint32_t unpack_tlv_core(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint32_t nBuf, + const tTLVDefn TLVs[], + uint8_t *pFrm, + size_t nFrm); +static uint32_t pack_tlv_core(tpAniSirGlobal pCtx, + uint8_t *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed, + const tTLVDefn TLVs[], + uint32_t *pidx); +static uint32_t get_packed_size_tlv_core(tpAniSirGlobal pCtx, + uint8_t *pFrm, + uint32_t *pnNeeded, + const tTLVDefn TLVs[]); + +#define SigFfAID (0x0001) + +void dot11f_unpack_ff_action(tpAniSirGlobal pCtx, + uint8_t *pBuf, + tDot11fFfAction *pDst) +{ + pDst->action = *pBuf; + (void)pCtx; +} /* End dot11f_unpack_ff_action. */ + +#define SigFfAction (0x0002) + +#define SigFfAuthAlgo (0x0003) + +#define SigFfAuthSeqNo (0x0004) + +#define SigFfBeaconInterval (0x0005) + +void dot11f_unpack_ff_capabilities(tpAniSirGlobal pCtx, + uint8_t *pBuf, + tDot11fFfCapabilities *pDst) +{ + uint16_t tmp0__; + framesntohs(pCtx, &tmp0__, pBuf, 0); + pDst->ess = tmp0__ >> 0 & 0x1; + pDst->ibss = tmp0__ >> 1 & 0x1; + pDst->cfPollable = tmp0__ >> 2 & 0x1; + pDst->cfPollReq = tmp0__ >> 3 & 0x1; + pDst->privacy = tmp0__ >> 4 & 0x1; + pDst->shortPreamble = tmp0__ >> 5 & 0x1; + pDst->pbcc = tmp0__ >> 6 & 0x1; + pDst->channelAgility = tmp0__ >> 7 & 0x1; + pDst->spectrumMgt = tmp0__ >> 8 & 0x1; + pDst->qos = tmp0__ >> 9 & 0x1; + pDst->shortSlotTime = tmp0__ >> 10 & 0x1; + pDst->apsd = tmp0__ >> 11 & 0x1; + pDst->rrm = tmp0__ >> 12 & 0x1; + pDst->dsssOfdm = tmp0__ >> 13 & 0x1; + pDst->delayedBA = tmp0__ >> 14 & 0x1; + pDst->immediateBA = tmp0__ >> 15 & 0x1; + (void)pCtx; +} /* End dot11f_unpack_ff_capabilities. */ + +#define SigFfCapabilities (0x0006) + +void dot11f_unpack_ff_category(tpAniSirGlobal pCtx, + uint8_t *pBuf, + tDot11fFfCategory *pDst) +{ + pDst->category = *pBuf; + (void)pCtx; +} /* End dot11f_unpack_ff_category. */ + +#define SigFfCategory (0x0007) + +void dot11f_unpack_ff_current_ap_address(tpAniSirGlobal pCtx, + uint8_t *pBuf, + tDot11fFfCurrentAPAddress *pDst) +{ + DOT11F_MEMCPY(pCtx, pDst->mac, pBuf, 6); + (void)pCtx; +} /* End dot11f_unpack_ff_current_ap_address. */ + +#define SigFfCurrentAPAddress (0x0008) + +void dot11f_unpack_ff_dialog_token(tpAniSirGlobal pCtx, + uint8_t *pBuf, + tDot11fFfDialogToken *pDst) +{ + pDst->token = *pBuf; + (void)pCtx; +} /* End dot11f_unpack_ff_dialog_token. */ + +#define SigFfDialogToken (0x0009) + +void dot11f_unpack_ff_link_margin(tpAniSirGlobal pCtx, + uint8_t *pBuf, + tDot11fFfLinkMargin *pDst) +{ + pDst->linkMargin = *pBuf; + (void)pCtx; +} /* End dot11f_unpack_ff_link_margin. */ + +#define SigFfLinkMargin (0x000a) + +#define SigFfListenInterval (0x000b) + +void dot11f_unpack_ff_max_tx_power(tpAniSirGlobal pCtx, + uint8_t *pBuf, + tDot11fFfMaxTxPower *pDst) +{ + pDst->maxTxPower = *pBuf; + (void)pCtx; +} /* End dot11f_unpack_ff_max_tx_power. */ + +#define SigFfMaxTxPower (0x000c) + +void dot11f_unpack_ff_num_of_repetitions(tpAniSirGlobal pCtx, + uint8_t *pBuf, + tDot11fFfNumOfRepetitions *pDst) +{ + framesntohs(pCtx, &pDst->repetitions, pBuf, 0); + (void)pCtx; +} /* End dot11f_unpack_ff_num_of_repetitions. */ + +#define SigFfNumOfRepetitions (0x000d) + +void dot11f_unpack_ff_operating_mode(tpAniSirGlobal pCtx, + uint8_t *pBuf, + tDot11fFfOperatingMode *pDst) +{ + uint8_t tmp1__; + tmp1__ = *pBuf; + pDst->chanWidth = tmp1__ >> 0 & 0x3; + pDst->reserved = tmp1__ >> 2 & 0x3; + pDst->rxNSS = tmp1__ >> 4 & 0x7; + pDst->rxNSSType = tmp1__ >> 7 & 0x1; + (void)pCtx; +} /* End dot11f_unpack_ff_operating_mode. */ + +#define SigFfOperatingMode (0x000e) + +void dot11f_unpack_ff_rcpi(tpAniSirGlobal pCtx, + uint8_t *pBuf, + tDot11fFfRCPI *pDst) +{ + pDst->rcpi = *pBuf; + (void)pCtx; +} /* End dot11f_unpack_ff_rcpi. */ + +#define SigFfRCPI (0x000f) + +void dot11f_unpack_ff_rsni(tpAniSirGlobal pCtx, + uint8_t *pBuf, + tDot11fFfRSNI *pDst) +{ + pDst->rsni = *pBuf; + (void)pCtx; +} /* End dot11f_unpack_ff_rsni. */ + +#define SigFfRSNI (0x0010) + +#define SigFfReason (0x0011) + +void dot11f_unpack_ff_rx_antenna_id(tpAniSirGlobal pCtx, + uint8_t *pBuf, + tDot11fFfRxAntennaId *pDst) +{ + pDst->antennaId = *pBuf; + (void)pCtx; +} /* End dot11f_unpack_ff_rx_antenna_id. */ + +#define SigFfRxAntennaId (0x0012) + +void dot11f_unpack_ff_sm_power_mode_set(tpAniSirGlobal pCtx, + uint8_t *pBuf, + tDot11fFfSMPowerModeSet *pDst) +{ + uint8_t tmp2__; + tmp2__ = *pBuf; + pDst->PowerSave_En = tmp2__ >> 0 & 0x1; + pDst->Mode = tmp2__ >> 1 & 0x1; + pDst->reserved = tmp2__ >> 2 & 0x3f; + (void)pCtx; +} /* End dot11f_unpack_ff_sm_power_mode_set. */ + +#define SigFfSMPowerModeSet (0x0013) + +#define SigFfStatus (0x0014) + +void dot11f_unpack_ff_status_code(tpAniSirGlobal pCtx, + uint8_t *pBuf, + tDot11fFfStatusCode *pDst) +{ + pDst->statusCode = *pBuf; + (void)pCtx; +} /* End dot11f_unpack_ff_status_code. */ + +#define SigFfStatusCode (0x0015) + +void dot11f_unpack_ff_tpc_ele_id(tpAniSirGlobal pCtx, + uint8_t *pBuf, + tDot11fFfTPCEleID *pDst) +{ + pDst->TPCId = *pBuf; + (void)pCtx; +} /* End dot11f_unpack_ff_tpc_ele_id. */ + +#define SigFfTPCEleID (0x0016) + +void dot11f_unpack_ff_tpc_ele_len(tpAniSirGlobal pCtx, + uint8_t *pBuf, + tDot11fFfTPCEleLen *pDst) +{ + pDst->TPCLen = *pBuf; + (void)pCtx; +} /* End dot11f_unpack_ff_tpc_ele_len. */ + +#define SigFfTPCEleLen (0x0017) + +void dot11f_unpack_ff_ts_info(tpAniSirGlobal pCtx, + uint8_t *pBuf, + tDot11fFfTSInfo *pDst) +{ + uint32_t tmp3__; + framesntohl(pCtx, &tmp3__, pBuf, 0); + pDst->traffic_type = tmp3__ >> 0 & 0x1; + pDst->tsid = tmp3__ >> 1 & 0xf; + pDst->direction = tmp3__ >> 5 & 0x3; + pDst->access_policy = tmp3__ >> 7 & 0x3; + pDst->aggregation = tmp3__ >> 9 & 0x1; + pDst->psb = tmp3__ >> 10 & 0x1; + pDst->user_priority = tmp3__ >> 11 & 0x7; + pDst->tsinfo_ack_pol = tmp3__ >> 14 & 0x3; + pDst->schedule = tmp3__ >> 16 & 0x1; + pDst->unused = tmp3__ >> 17 & 0x7fff; + (void)pCtx; +} /* End dot11f_unpack_ff_ts_info. */ + +#define SigFfTSInfo (0x0018) + +void dot11f_unpack_ff_time_stamp(tpAniSirGlobal pCtx, + uint8_t *pBuf, + tDot11fFfTimeStamp *pDst) +{ + framesntohq(pCtx, &pDst->timestamp, pBuf, 0); + (void)pCtx; +} /* End dot11f_unpack_ff_time_stamp. */ + +#define SigFfTimeStamp (0x0019) + +void dot11f_unpack_ff_transaction_id(tpAniSirGlobal pCtx, + uint8_t *pBuf, + tDot11fFfTransactionId *pDst) +{ + DOT11F_MEMCPY(pCtx, pDst->transId, pBuf, 2); + (void)pCtx; +} /* End dot11f_unpack_ff_transaction_id. */ + +#define SigFfTransactionId (0x001a) + +void dot11f_unpack_ff_tx_antenna_id(tpAniSirGlobal pCtx, + uint8_t *pBuf, + tDot11fFfTxAntennaId *pDst) +{ + pDst->antennaId = *pBuf; + (void)pCtx; +} /* End dot11f_unpack_ff_tx_antenna_id. */ + +#define SigFfTxAntennaId (0x001b) + +void dot11f_unpack_ff_tx_power(tpAniSirGlobal pCtx, + uint8_t *pBuf, + tDot11fFfTxPower *pDst) +{ + pDst->txPower = *pBuf; + (void)pCtx; +} /* End dot11f_unpack_ff_tx_power. */ + +#define SigFfTxPower (0x001c) + +void dot11f_unpack_ff_vht_membership_status_array(tpAniSirGlobal pCtx, + uint8_t *pBuf, + tDot11fFfVhtMembershipStatusArray *pDst) +{ + DOT11F_MEMCPY(pCtx, pDst->membershipStatusArray, pBuf, 8); + (void)pCtx; +} /* End dot11f_unpack_ff_vht_membership_status_array. */ + +#define SigFfVhtMembershipStatusArray (0x001d) + +void dot11f_unpack_ff_vht_user_position_array(tpAniSirGlobal pCtx, + uint8_t *pBuf, + tDot11fFfVhtUserPositionArray *pDst) +{ + DOT11F_MEMCPY(pCtx, pDst->userPositionArray, pBuf, 16); + (void)pCtx; +} /* End dot11f_unpack_ff_vht_user_position_array. */ + +#define SigFfVhtUserPositionArray (0x001e) + +void dot11f_unpack_ff_ext_chan_switch_ann_action(tpAniSirGlobal pCtx, + uint8_t *pBuf, + tDot11fFfext_chan_switch_ann_action *pDst) +{ + uint32_t tmp4__; + framesntohl(pCtx, &tmp4__, pBuf, 0); + pDst->switch_mode = tmp4__ >> 0 & 0xff; + pDst->op_class = tmp4__ >> 8 & 0xff; + pDst->new_channel = tmp4__ >> 16 & 0xff; + pDst->switch_count = tmp4__ >> 24 & 0xff; + (void)pCtx; +} /* End dot11f_unpack_ff_ext_chan_switch_ann_action. */ + +#define SigFfext_chan_switch_ann_action (0x001f) + +void dot11f_unpack_ff_p2p_action_oui(tpAniSirGlobal pCtx, + uint8_t *pBuf, + tDot11fFfp2p_action_oui *pDst) +{ + DOT11F_MEMCPY(pCtx, pDst->oui_data, pBuf, 4); + (void)pCtx; +} /* End dot11f_unpack_ff_p2p_action_oui. */ + +#define SigFfp2p_action_oui (0x0020) + +void dot11f_unpack_ff_p2p_action_subtype(tpAniSirGlobal pCtx, + uint8_t *pBuf, + tDot11fFfp2p_action_subtype *pDst) +{ + pDst->subtype = *pBuf; + (void)pCtx; +} /* End dot11f_unpack_ff_p2p_action_subtype. */ + +#define SigFfp2p_action_subtype (0x0021) + +uint32_t dot11f_unpack_tlv_authorized_ma_cs(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint16_t tlvlen, + tDot11fTLVAuthorizedMACs *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + pDst->present = 1; + DOT11F_MEMCPY(pCtx, pDst->mac, pBuf, 6); + pBuf += 6; + tlvlen -= (uint8_t)6; + (void)pCtx; + return status; +} /* End dot11f_unpack_tlv_authorized_ma_cs. */ + +#define SigTlvAuthorizedMACs (0x0001) + + +#define SigTlvRequestToEnroll (0x0002) + + +uint32_t dot11f_unpack_tlv_version2(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint16_t tlvlen, + tDot11fTLVVersion2 *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + uint8_t tmp5__; + pDst->present = 1; + tmp5__ = *pBuf; + pBuf += 1; + tlvlen -= 1; + pDst->minor = tmp5__ >> 0 & 0xf; + pDst->major = tmp5__ >> 4 & 0xf; + (void)pCtx; + return status; +} /* End dot11f_unpack_tlv_version2. */ + +#define SigTlvVersion2 (0x0003) + + +#define SigTlvAPSetupLocked (0x0004) + + +#define SigTlvAssociationState (0x0005) + + +#define SigTlvConfigMethods (0x0006) + + +#define SigTlvConfigurationError (0x0007) + + +uint32_t dot11f_unpack_tlv_device_name(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint16_t tlvlen, + tDot11fTLVDeviceName *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + pDst->present = 1; + pDst->num_text = (uint8_t)(tlvlen); + if (tlvlen > 32) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->text, pBuf, (tlvlen)); + pBuf += (tlvlen); + tlvlen -= (tlvlen); + (void)pCtx; + return status; +} /* End dot11f_unpack_tlv_device_name. */ + +#define SigTlvDeviceName (0x0008) + + +#define SigTlvDevicePasswordID (0x0009) + + +uint32_t dot11f_unpack_tlv_extended_listen_timing(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint16_t tlvlen, + tDot11fTLVExtendedListenTiming *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + pDst->present = 1; + framesntohs(pCtx, &pDst->availibilityPeriod, pBuf, 0); + pBuf += 2; + tlvlen -= (uint8_t)2; + framesntohs(pCtx, &pDst->availibilityInterval, pBuf, 0); + pBuf += 2; + tlvlen -= (uint8_t)2; + (void)pCtx; + return status; +} /* End dot11f_unpack_tlv_extended_listen_timing. */ + +#define SigTlvExtendedListenTiming (0x000a) + + +uint32_t dot11f_unpack_tlv_listen_channel(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint16_t tlvlen, + tDot11fTLVListenChannel *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + pDst->present = 1; + DOT11F_MEMCPY(pCtx, pDst->countryString, pBuf, 3); + pBuf += 3; + tlvlen -= (uint8_t)3; + pDst->regulatoryClass = *pBuf; + pBuf += 1; + tlvlen -= (uint8_t)1; + pDst->channel = *pBuf; + pBuf += 1; + tlvlen -= (uint8_t)1; + (void)pCtx; + return status; +} /* End dot11f_unpack_tlv_listen_channel. */ + +#define SigTlvListenChannel (0x000b) + + +uint32_t dot11f_unpack_tlv_manufacturer(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint16_t tlvlen, + tDot11fTLVManufacturer *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + pDst->present = 1; + pDst->num_name = (uint8_t)(tlvlen); + if (tlvlen > 64) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->name, pBuf, (tlvlen)); + pBuf += (tlvlen); + tlvlen -= (tlvlen); + (void)pCtx; + return status; +} /* End dot11f_unpack_tlv_manufacturer. */ + +#define SigTlvManufacturer (0x000c) + + +#define SigTlvMinorReasonCode (0x000d) + + +uint32_t dot11f_unpack_tlv_model_name(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint16_t tlvlen, + tDot11fTLVModelName *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + pDst->present = 1; + pDst->num_text = (uint8_t)(tlvlen); + if (tlvlen > 32) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->text, pBuf, (tlvlen)); + pBuf += (tlvlen); + tlvlen -= (tlvlen); + (void)pCtx; + return status; +} /* End dot11f_unpack_tlv_model_name. */ + +#define SigTlvModelName (0x000e) + + +uint32_t dot11f_unpack_tlv_model_number(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint16_t tlvlen, + tDot11fTLVModelNumber *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + pDst->present = 1; + pDst->num_text = (uint8_t)(tlvlen); + if (tlvlen > 32) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->text, pBuf, (tlvlen)); + pBuf += (tlvlen); + tlvlen -= (tlvlen); + (void)pCtx; + return status; +} /* End dot11f_unpack_tlv_model_number. */ + +#define SigTlvModelNumber (0x000f) + + +uint32_t dot11f_unpack_tlv_notice_of_absence(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint16_t tlvlen, + tDot11fTLVNoticeOfAbsence *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + pDst->present = 1; + pDst->index = *pBuf; + pBuf += 1; + tlvlen -= (uint8_t)1; + pDst->CTSWindowOppPS = *pBuf; + pBuf += 1; + tlvlen -= (uint8_t)1; + pDst->num_NoADesc = (uint8_t)(tlvlen); + if (tlvlen > 36) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->NoADesc, pBuf, (tlvlen)); + pBuf += (tlvlen); + tlvlen -= (tlvlen); + (void)pCtx; + return status; +} /* End dot11f_unpack_tlv_notice_of_absence. */ + +#define SigTlvNoticeOfAbsence (0x0010) + + +uint32_t dot11f_unpack_tlv_operating_channel(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint16_t tlvlen, + tDot11fTLVOperatingChannel *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + pDst->present = 1; + DOT11F_MEMCPY(pCtx, pDst->countryString, pBuf, 3); + pBuf += 3; + tlvlen -= (uint8_t)3; + pDst->regulatoryClass = *pBuf; + pBuf += 1; + tlvlen -= (uint8_t)1; + pDst->channel = *pBuf; + pBuf += 1; + tlvlen -= (uint8_t)1; + (void)pCtx; + return status; +} /* End dot11f_unpack_tlv_operating_channel. */ + +#define SigTlvOperatingChannel (0x0011) + + +uint32_t dot11f_unpack_tlv_p2_p_capability(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint16_t tlvlen, + tDot11fTLVP2PCapability *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + pDst->present = 1; + pDst->deviceCapability = *pBuf; + pBuf += 1; + tlvlen -= (uint8_t)1; + pDst->groupCapability = *pBuf; + pBuf += 1; + tlvlen -= (uint8_t)1; + (void)pCtx; + return status; +} /* End dot11f_unpack_tlv_p2_p_capability. */ + +#define SigTlvP2PCapability (0x0012) + + +uint32_t dot11f_unpack_tlv_p2_p_device_id(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint16_t tlvlen, + tDot11fTLVP2PDeviceId *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + pDst->present = 1; + DOT11F_MEMCPY(pCtx, pDst->P2PDeviceAddress, pBuf, 6); + pBuf += 6; + tlvlen -= (uint8_t)6; + (void)pCtx; + return status; +} /* End dot11f_unpack_tlv_p2_p_device_id. */ + +#define SigTlvP2PDeviceId (0x0013) + + +static const tTLVDefn TLVS_P2PDeviceInfo[] = { + { offsetof(tDot11fTLVP2PDeviceInfo, DeviceName), + offsetof(tDot11fTLVDeviceName, present), "DeviceName", SigTlvDeviceName, + DOT11F_TLV_DEVICENAME, 0, 4, 36, 1, 2, 2, 1, }, + {0, 0, NULL, 0, 0xffff, 0, 0, 0, 0, 0, 0}, +}; + +uint32_t dot11f_unpack_tlv_p2_p_device_info(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint16_t tlvlen, + tDot11fTLVP2PDeviceInfo *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + pDst->present = 1; + DOT11F_MEMCPY(pCtx, pDst->P2PDeviceAddress, pBuf, 6); + pBuf += 6; + tlvlen -= (uint8_t)6; + framesntohs(pCtx, &pDst->configMethod, pBuf, 0); + pBuf += 2; + tlvlen -= (uint8_t)2; + DOT11F_MEMCPY(pCtx, pDst->primaryDeviceType, pBuf, 8); + pBuf += 8; + tlvlen -= (uint8_t)8; + (void)pCtx; + status |= unpack_tlv_core(pCtx, + pBuf, + tlvlen, + TLVS_P2PDeviceInfo, + (uint8_t *)pDst, + sizeof(*pDst)); + return status; +} /* End dot11f_unpack_tlv_p2_p_device_info. */ + +#define SigTlvP2PDeviceInfo (0x0014) + + +uint32_t dot11f_unpack_tlv_p2_p_group_info(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint16_t tlvlen, + tDot11fTLVP2PGroupInfo *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + pDst->present = 1; + pDst->num_P2PClientInfoDesc = (uint8_t)(tlvlen); + DOT11F_MEMCPY(pCtx, pDst->P2PClientInfoDesc, pBuf, (tlvlen)); + pBuf += (tlvlen); + tlvlen -= (tlvlen); + (void)pCtx; + return status; +} /* End dot11f_unpack_tlv_p2_p_group_info. */ + +#define SigTlvP2PGroupInfo (0x0015) + + +#define SigTlvP2PStatus (0x0016) + + +uint32_t dot11f_unpack_tlv_primary_device_type(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint16_t tlvlen, + tDot11fTLVPrimaryDeviceType *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pBuf; (void)tlvlen; /* Shutup the compiler */ + pDst->present = 1; + framesntohs(pCtx, &pDst->primary_category, pBuf, 1); + pBuf += 2; + tlvlen -= (uint8_t)2; + DOT11F_MEMCPY(pCtx, pDst->oui, pBuf, 4); + pBuf += 4; + tlvlen -= (uint8_t)4; + framesntohs(pCtx, &pDst->sub_category, pBuf, 1); + pBuf += 2; + tlvlen -= (uint8_t)2; + (void)pCtx; + return status; +} /* End dot11f_unpack_tlv_primary_device_type. */ + +#define SigTlvPrimaryDeviceType (0x0017) + + +#define SigTlvRFBands (0x0018) + + +uint32_t dot11f_unpack_tlv_request_device_type(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint16_t tlvlen, + tDot11fTLVRequestDeviceType *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + pDst->present = 1; + framesntohs(pCtx, &pDst->primary_category, pBuf, 1); + pBuf += 2; + tlvlen -= (uint8_t)2; + DOT11F_MEMCPY(pCtx, pDst->oui, pBuf, 4); + pBuf += 4; + tlvlen -= (uint8_t)4; + framesntohs(pCtx, &pDst->sub_category, pBuf, 1); + pBuf += 2; + tlvlen -= (uint8_t)2; + (void)pCtx; + return status; +} /* End dot11f_unpack_tlv_request_device_type. */ + +#define SigTlvRequestDeviceType (0x0019) + + +#define SigTlvRequestType (0x001a) + + +#define SigTlvResponseType (0x001b) + + +#define SigTlvSelectedRegistrar (0x001c) + + +#define SigTlvSelectedRegistrarConfigMethods (0x001d) + + +uint32_t dot11f_unpack_tlv_serial_number(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint16_t tlvlen, + tDot11fTLVSerialNumber *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + pDst->present = 1; + pDst->num_text = (uint8_t)(tlvlen); + if (tlvlen > 32) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->text, pBuf, (tlvlen)); + pBuf += (tlvlen); + tlvlen -= (tlvlen); + (void)pCtx; + return status; +} /* End dot11f_unpack_tlv_serial_number. */ + +#define SigTlvSerialNumber (0x001e) + + +uint32_t dot11f_unpack_tlv_uuid_e(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint16_t tlvlen, + tDot11fTLVUUID_E *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + pDst->present = 1; + DOT11F_MEMCPY(pCtx, pDst->uuid, pBuf, 16); + pBuf += 16; + tlvlen -= (uint8_t)16; + (void)pCtx; + return status; +} /* End dot11f_unpack_tlv_uuid_e. */ + +#define SigTlvUUID_E (0x001f) + + +uint32_t dot11f_unpack_tlv_uuid_r(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint16_t tlvlen, + tDot11fTLVUUID_R *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + pDst->present = 1; + DOT11F_MEMCPY(pCtx, pDst->uuid, pBuf, 16); + pBuf += 16; + tlvlen -= (uint8_t)16; + (void)pCtx; + return status; +} /* End dot11f_unpack_tlv_uuid_r. */ + +#define SigTlvUUID_R (0x0020) + + +static const tTLVDefn TLVS_VendorExtension[] = { + { offsetof(tDot11fTLVVendorExtension, Version2), + offsetof(tDot11fTLVVersion2, present), "Version2", SigTlvVersion2, + DOT11F_TLV_VERSION2, 0, 3, 3, 0, 1, 1, 1, }, + { offsetof(tDot11fTLVVendorExtension, AuthorizedMACs), + offsetof(tDot11fTLVAuthorizedMACs, present), "AuthorizedMACs", + SigTlvAuthorizedMACs, DOT11F_TLV_AUTHORIZEDMACS, 0, 8, 8, 0, 1, 1, 1, }, + { offsetof(tDot11fTLVVendorExtension, RequestToEnroll), + offsetof(tDot11fTLVRequestToEnroll, present), "RequestToEnroll", + SigTlvRequestToEnroll, DOT11F_TLV_REQUESTTOENROLL, + 0, 3, 3, 0, 1, 1, 1, }, + {0, 0, NULL, 0, 0xffff, 0, 0, 0, 0, 0, 0}, +}; + +uint32_t dot11f_unpack_tlv_vendor_extension(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint16_t tlvlen, + tDot11fTLVVendorExtension *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + pDst->present = 1; + DOT11F_MEMCPY(pCtx, pDst->vendorId, pBuf, 3); + pBuf += 3; + tlvlen -= (uint8_t)3; + (void)pCtx; + status |= unpack_tlv_core(pCtx, + pBuf, + tlvlen, + TLVS_VendorExtension, + (uint8_t *)pDst, + sizeof(*pDst)); + return status; +} /* End dot11f_unpack_tlv_vendor_extension. */ + +#define SigTlvVendorExtension (0x0021) + + +uint32_t dot11f_unpack_tlv_version(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint16_t tlvlen, + tDot11fTLVVersion *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + uint8_t tmp6__; + pDst->present = 1; + tmp6__ = *pBuf; + pBuf += 1; + tlvlen -= 1; + pDst->minor = tmp6__ >> 0 & 0xf; + pDst->major = tmp6__ >> 4 & 0xf; + (void)pCtx; + return status; +} /* End dot11f_unpack_tlv_version. */ + +#define SigTlvVersion (0x0022) + + +#define SigTlvWPSState (0x0023) + + +uint32_t dot11f_unpack_tlv_p2_p_interface(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint16_t tlvlen, + tDot11fTLVP2PInterface *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + pDst->present = 1; + DOT11F_MEMCPY(pCtx, pDst->P2PDeviceAddress, pBuf, 6); + pBuf += 6; + tlvlen -= (uint8_t)6; + (void)pCtx; + return status; +} /* End dot11f_unpack_tlv_p2_p_interface. */ + +#define SigTlvP2PInterface (0x0024) + + +#define SigTlvP2PManageability (0x0025) + + +uint32_t dot11f_unpack_ie_gtk(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEGTK *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + uint16_t tmp7__; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + framesntohs(pCtx, &tmp7__, pBuf, 0); + pBuf += 2; + ielen -= 2; + pDst->keyId = tmp7__ >> 0 & 0x3; + pDst->reserved = tmp7__ >> 2 & 0x3feb; + pDst->keyLength = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + DOT11F_MEMCPY(pCtx, pDst->RSC, pBuf, 8); + pBuf += 8; + ielen -= (uint8_t)8; + pDst->num_key = (uint8_t)(ielen); + if (ielen > 32) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->key, pBuf, (ielen)); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_gtk. */ + +#define SigIeGTK (0x0001) + + +uint32_t dot11f_unpack_ie_igtk(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEIGTK *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + DOT11F_MEMCPY(pCtx, pDst->keyID, pBuf, 2); + pBuf += 2; + ielen -= (uint8_t)2; + DOT11F_MEMCPY(pCtx, pDst->IPN, pBuf, 6); + pBuf += 6; + ielen -= (uint8_t)6; + pDst->keyLength = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + DOT11F_MEMCPY(pCtx, pDst->key, pBuf, 24); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_igtk. */ + +#define SigIeIGTK (0x0002) + + +uint32_t dot11f_unpack_ie_r0_kh_id(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIER0KH_ID *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->num_PMK_R0_ID = (uint8_t)(ielen); + if (ielen > 48) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->PMK_R0_ID, pBuf, (ielen)); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_r0_kh_id. */ + +#define SigIeR0KH_ID (0x0003) + + +uint32_t dot11f_unpack_ie_r1_kh_id(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIER1KH_ID *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + DOT11F_MEMCPY(pCtx, pDst->PMK_R1_ID, pBuf, 6); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_r1_kh_id. */ + +#define SigIeR1KH_ID (0x0004) + + +uint32_t dot11f_unpack_ie_ap_channel_report(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEAPChannelReport *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->regulatoryClass = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->num_channelList = (uint8_t)(ielen); + if (ielen > 50) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->channelList, pBuf, (ielen)); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_ap_channel_report. */ + +#define SigIeAPChannelReport (0x0005) + + +uint32_t dot11f_unpack_ie_bcn_reporting_detail(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEBcnReportingDetail *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->reportingDetail = *pBuf; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_bcn_reporting_detail. */ + +#define SigIeBcnReportingDetail (0x0006) + + +uint32_t dot11f_unpack_ie_beacon_report_frm_body(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEBeaconReportFrmBody *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->num_reportedFields = (uint8_t)(ielen); + if (ielen > 224) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->reportedFields, pBuf, (ielen)); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_beacon_report_frm_body. */ + +#define SigIeBeaconReportFrmBody (0x0007) + + +uint32_t dot11f_unpack_ie_beacon_reporting(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEBeaconReporting *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->reportingCondition = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->threshold = *pBuf; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_beacon_reporting. */ + +#define SigIeBeaconReporting (0x0008) + + +uint32_t dot11f_unpack_ie_condensed_country_str(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIECondensedCountryStr *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + DOT11F_MEMCPY(pCtx, pDst->countryStr, pBuf, 2); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_condensed_country_str. */ + +#define SigIeCondensedCountryStr (0x0009) + + +uint32_t dot11f_unpack_ie_measurement_pilot(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEMeasurementPilot *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->measurementPilot = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->num_vendorSpecific = (uint8_t)(ielen); + DOT11F_MEMCPY(pCtx, pDst->vendorSpecific, pBuf, (ielen)); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_measurement_pilot. */ + +#define SigIeMeasurementPilot (0x000a) + + +uint32_t dot11f_unpack_ie_multi_bssid(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEMultiBssid *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->maxBSSIDIndicator = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->num_vendorSpecific = (uint8_t)(ielen); + DOT11F_MEMCPY(pCtx, pDst->vendorSpecific, pBuf, (ielen)); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_multi_bssid. */ + +#define SigIeMultiBssid (0x000b) + + +uint32_t dot11f_unpack_ie_ric_data(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIERICData *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->Identifier = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->resourceDescCount = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + framesntohs(pCtx, &pDst->statusCode, pBuf, 0); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_ric_data. */ + +#define SigIeRICData (0x000c) + + +uint32_t dot11f_unpack_ie_ric_descriptor(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIERICDescriptor *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->resourceType = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->num_variableData = (uint8_t)(ielen); + DOT11F_MEMCPY(pCtx, pDst->variableData, pBuf, (ielen)); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_ric_descriptor. */ + +#define SigIeRICDescriptor (0x000d) + + +uint32_t dot11f_unpack_ie_rrm_enabled_cap(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIERRMEnabledCap *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + uint8_t tmp8__; + uint8_t tmp9__; + uint8_t tmp10__; + uint8_t tmp11__; + uint8_t tmp12__; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + tmp8__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->LinkMeasurement = tmp8__ >> 0 & 0x1; + pDst->NeighborRpt = tmp8__ >> 1 & 0x1; + pDst->parallel = tmp8__ >> 2 & 0x1; + pDst->repeated = tmp8__ >> 3 & 0x1; + pDst->BeaconPassive = tmp8__ >> 4 & 0x1; + pDst->BeaconActive = tmp8__ >> 5 & 0x1; + pDst->BeaconTable = tmp8__ >> 6 & 0x1; + pDst->BeaconRepCond = tmp8__ >> 7 & 0x1; + tmp9__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->FrameMeasurement = tmp9__ >> 0 & 0x1; + pDst->ChannelLoad = tmp9__ >> 1 & 0x1; + pDst->NoiseHistogram = tmp9__ >> 2 & 0x1; + pDst->statistics = tmp9__ >> 3 & 0x1; + pDst->LCIMeasurement = tmp9__ >> 4 & 0x1; + pDst->LCIAzimuth = tmp9__ >> 5 & 0x1; + pDst->TCMCapability = tmp9__ >> 6 & 0x1; + pDst->triggeredTCM = tmp9__ >> 7 & 0x1; + tmp10__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->APChanReport = tmp10__ >> 0 & 0x1; + pDst->RRMMIBEnabled = tmp10__ >> 1 & 0x1; + pDst->operatingChanMax = tmp10__ >> 2 & 0x7; + pDst->nonOperatinChanMax = tmp10__ >> 5 & 0x7; + tmp11__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->MeasurementPilot = tmp11__ >> 0 & 0x7; + pDst->MeasurementPilotEnabled = tmp11__ >> 3 & 0x1; + pDst->NeighborTSFOffset = tmp11__ >> 4 & 0x1; + pDst->RCPIMeasurement = tmp11__ >> 5 & 0x1; + pDst->RSNIMeasurement = tmp11__ >> 6 & 0x1; + pDst->BssAvgAccessDelay = tmp11__ >> 7 & 0x1; + tmp12__ = *pBuf; + pDst->BSSAvailAdmission = tmp12__ >> 0 & 0x1; + pDst->AntennaInformation = tmp12__ >> 1 & 0x1; + pDst->fine_time_meas_rpt = tmp12__ >> 2 & 0x1; + pDst->lci_capability = tmp12__ >> 3 & 0x1; + pDst->reserved = tmp12__ >> 4 & 0xf; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_rrm_enabled_cap. */ + +#define SigIeRRMEnabledCap (0x000e) + + +uint32_t dot11f_unpack_ie_requested_info(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIERequestedInfo *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->num_requested_eids = (uint8_t)(ielen); + DOT11F_MEMCPY(pCtx, pDst->requested_eids, pBuf, (ielen)); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_requested_info. */ + +#define SigIeRequestedInfo (0x000f) + + +uint32_t dot11f_unpack_ie_ssid(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIESSID *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) { + status = DOT11F_DUPLICATE_IE; + return status; + } + pDst->present = 1; + pDst->num_ssid = (uint8_t)(ielen); + if (ielen > 32) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->ssid, pBuf, (ielen)); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_ssid. */ + +#define SigIeSSID (0x0010) + + +uint32_t dot11f_unpack_ie_schedule(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIESchedule *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + uint16_t tmp13__; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + framesntohs(pCtx, &tmp13__, pBuf, 0); + pBuf += 2; + ielen -= 2; + pDst->aggregation = tmp13__ >> 0 & 0x1; + pDst->tsid = tmp13__ >> 1 & 0xf; + pDst->direction = tmp13__ >> 5 & 0x3; + pDst->reserved = tmp13__ >> 7 & 0x1ff; + framesntohl(pCtx, &pDst->service_start_time, pBuf, 0); + pBuf += 4; + ielen -= (uint8_t)4; + framesntohl(pCtx, &pDst->service_interval, pBuf, 0); + pBuf += 4; + ielen -= (uint8_t)4; + framesntohs(pCtx, &pDst->max_service_dur, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + framesntohs(pCtx, &pDst->spec_interval, pBuf, 0); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_schedule. */ + +#define SigIeSchedule (0x0011) + + +uint32_t dot11f_unpack_ie_tclas(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIETCLAS *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->user_priority = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->classifier_type = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->classifier_mask = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + switch (pDst->classifier_type) { + case 0: + DOT11F_MEMCPY(pCtx, pDst->info.EthParams.source, pBuf, 6); + pBuf += 6; + ielen -= (uint8_t)6; + DOT11F_MEMCPY(pCtx, pDst->info.EthParams.dest, pBuf, 6); + pBuf += 6; + ielen -= (uint8_t)6; + framesntohs(pCtx, &pDst->info.EthParams.type, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + break; + case 1: + pDst->info.IpParams.version = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + switch (pDst->info.IpParams.version) { + case 4: + DOT11F_MEMCPY(pCtx, pDst->info.IpParams.params.IpV4Params.source, pBuf, 4); + pBuf += 4; + ielen -= (uint8_t)4; + DOT11F_MEMCPY(pCtx, pDst->info.IpParams.params.IpV4Params.dest, pBuf, 4); + pBuf += 4; + ielen -= (uint8_t)4; + framesntohs(pCtx, &pDst->info.IpParams.params.IpV4Params.src_port, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + framesntohs(pCtx, &pDst->info.IpParams.params.IpV4Params.dest_port, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + pDst->info.IpParams.params.IpV4Params.DSCP = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->info.IpParams.params.IpV4Params.proto = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->info.IpParams.params.IpV4Params.reserved = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + break; + case 6: + DOT11F_MEMCPY(pCtx, pDst->info.IpParams.params.IpV6Params.source, pBuf, 16); + pBuf += 16; + ielen -= (uint8_t)16; + DOT11F_MEMCPY(pCtx, pDst->info.IpParams.params.IpV6Params.dest, pBuf, 16); + pBuf += 16; + ielen -= (uint8_t)16; + framesntohs(pCtx, &pDst->info.IpParams.params.IpV6Params.src_port, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + framesntohs(pCtx, &pDst->info.IpParams.params.IpV6Params.dest_port, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + DOT11F_MEMCPY(pCtx, pDst->info.IpParams.params.IpV6Params.flow_label, pBuf, 3); + pBuf += 3; + ielen -= (uint8_t)3; + break; + } + break; + case 2: + framesntohs(pCtx, &pDst->info.Params8021dq.tag_type, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + break; + } + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_tclas. */ + +#define SigIeTCLAS (0x0012) + + +#define SigIeTCLASSPROC (0x0013) + + +uint32_t dot11f_unpack_ie_ts_delay(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIETSDelay *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + framesntohl(pCtx, &pDst->delay, pBuf, 0); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_ts_delay. */ + +#define SigIeTSDelay (0x0014) + + +uint32_t dot11f_unpack_ie_tsf_info(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIETSFInfo *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + framesntohs(pCtx, &pDst->TsfOffset, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + framesntohs(pCtx, &pDst->BeaconIntvl, pBuf, 0); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_tsf_info. */ + +#define SigIeTSFInfo (0x0015) + + +uint32_t dot11f_unpack_ie_tspec(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIETSPEC *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + uint16_t tmp14__; + uint8_t tmp15__; + uint16_t tmp16__; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + framesntohs(pCtx, &tmp14__, pBuf, 0); + pBuf += 2; + ielen -= 2; + pDst->traffic_type = tmp14__ >> 0 & 0x1; + pDst->tsid = tmp14__ >> 1 & 0xf; + pDst->direction = tmp14__ >> 5 & 0x3; + pDst->access_policy = tmp14__ >> 7 & 0x3; + pDst->aggregation = tmp14__ >> 9 & 0x1; + pDst->psb = tmp14__ >> 10 & 0x1; + pDst->user_priority = tmp14__ >> 11 & 0x7; + pDst->tsinfo_ack_pol = tmp14__ >> 14 & 0x3; + tmp15__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->schedule = tmp15__ >> 0 & 0x1; + pDst->unused = tmp15__ >> 1 & 0x7f; + framesntohs(pCtx, &tmp16__, pBuf, 0); + pBuf += 2; + ielen -= 2; + pDst->size = tmp16__ >> 0 & 0x7fff; + pDst->fixed = tmp16__ >> 15 & 0x1; + framesntohs(pCtx, &pDst->max_msdu_size, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + framesntohl(pCtx, &pDst->min_service_int, pBuf, 0); + pBuf += 4; + ielen -= (uint8_t)4; + framesntohl(pCtx, &pDst->max_service_int, pBuf, 0); + pBuf += 4; + ielen -= (uint8_t)4; + framesntohl(pCtx, &pDst->inactivity_int, pBuf, 0); + pBuf += 4; + ielen -= (uint8_t)4; + framesntohl(pCtx, &pDst->suspension_int, pBuf, 0); + pBuf += 4; + ielen -= (uint8_t)4; + framesntohl(pCtx, &pDst->service_start_time, pBuf, 0); + pBuf += 4; + ielen -= (uint8_t)4; + framesntohl(pCtx, &pDst->min_data_rate, pBuf, 0); + pBuf += 4; + ielen -= (uint8_t)4; + framesntohl(pCtx, &pDst->mean_data_rate, pBuf, 0); + pBuf += 4; + ielen -= (uint8_t)4; + framesntohl(pCtx, &pDst->peak_data_rate, pBuf, 0); + pBuf += 4; + ielen -= (uint8_t)4; + framesntohl(pCtx, &pDst->burst_size, pBuf, 0); + pBuf += 4; + ielen -= (uint8_t)4; + framesntohl(pCtx, &pDst->delay_bound, pBuf, 0); + pBuf += 4; + ielen -= (uint8_t)4; + framesntohl(pCtx, &pDst->min_phy_rate, pBuf, 0); + pBuf += 4; + ielen -= (uint8_t)4; + framesntohs(pCtx, &pDst->surplus_bw_allowance, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + framesntohs(pCtx, &pDst->medium_time, pBuf, 0); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_tspec. */ + +#define SigIeTSPEC (0x0016) + + +uint32_t dot11f_unpack_ie_vht_caps(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEVHTCaps *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + uint32_t tmp17__; + uint16_t tmp18__; + uint16_t tmp19__; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + framesntohl(pCtx, &tmp17__, pBuf, 0); + pBuf += 4; + ielen -= 4; + pDst->maxMPDULen = tmp17__ >> 0 & 0x3; + pDst->supportedChannelWidthSet = tmp17__ >> 2 & 0x3; + pDst->ldpcCodingCap = tmp17__ >> 4 & 0x1; + pDst->shortGI80MHz = tmp17__ >> 5 & 0x1; + pDst->shortGI160and80plus80MHz = tmp17__ >> 6 & 0x1; + pDst->txSTBC = tmp17__ >> 7 & 0x1; + pDst->rxSTBC = tmp17__ >> 8 & 0x7; + pDst->suBeamFormerCap = tmp17__ >> 11 & 0x1; + pDst->suBeamformeeCap = tmp17__ >> 12 & 0x1; + pDst->csnofBeamformerAntSup = tmp17__ >> 13 & 0x7; + pDst->numSoundingDim = tmp17__ >> 16 & 0x7; + pDst->muBeamformerCap = tmp17__ >> 19 & 0x1; + pDst->muBeamformeeCap = tmp17__ >> 20 & 0x1; + pDst->vhtTXOPPS = tmp17__ >> 21 & 0x1; + pDst->htcVHTCap = tmp17__ >> 22 & 0x1; + pDst->maxAMPDULenExp = tmp17__ >> 23 & 0x7; + pDst->vhtLinkAdaptCap = tmp17__ >> 26 & 0x3; + pDst->rxAntPattern = tmp17__ >> 28 & 0x1; + pDst->txAntPattern = tmp17__ >> 29 & 0x1; + pDst->reserved1 = tmp17__ >> 30 & 0x3; + framesntohs(pCtx, &pDst->rxMCSMap, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + framesntohs(pCtx, &tmp18__, pBuf, 0); + pBuf += 2; + ielen -= 2; + pDst->rxHighSupDataRate = tmp18__ >> 0 & 0x1fff; + pDst->reserved2 = tmp18__ >> 13 & 0x7; + framesntohs(pCtx, &pDst->txMCSMap, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + framesntohs(pCtx, &tmp19__, pBuf, 0); + pDst->txSupDataRate = tmp19__ >> 0 & 0x1fff; + pDst->reserved3 = tmp19__ >> 13 & 0x7; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_vht_caps. */ + +#define SigIeVHTCaps (0x0017) + + +uint32_t dot11f_unpack_ie_vht_operation(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEVHTOperation *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->chanWidth = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->chanCenterFreqSeg1 = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->chanCenterFreqSeg2 = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + framesntohs(pCtx, &pDst->basicMCSSet, pBuf, 0); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_vht_operation. */ + +#define SigIeVHTOperation (0x0018) + + +uint32_t dot11f_unpack_ie_wmm_schedule(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEWMMSchedule *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + uint16_t tmp20__; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->version = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (pDst->version != 0x1) { + pDst->present = 0; + return status | DOT11F_BAD_FIXED_VALUE; + } + framesntohs(pCtx, &tmp20__, pBuf, 0); + pBuf += 2; + ielen -= 2; + pDst->aggregation = tmp20__ >> 0 & 0x1; + pDst->tsid = tmp20__ >> 1 & 0xf; + pDst->direction = tmp20__ >> 5 & 0x3; + pDst->reserved = tmp20__ >> 7 & 0x1ff; + framesntohl(pCtx, &pDst->service_start_time, pBuf, 0); + pBuf += 4; + ielen -= (uint8_t)4; + framesntohl(pCtx, &pDst->service_interval, pBuf, 0); + pBuf += 4; + ielen -= (uint8_t)4; + framesntohs(pCtx, &pDst->max_service_dur, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + framesntohs(pCtx, &pDst->spec_interval, pBuf, 0); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_wmm_schedule. */ + +#define SigIeWMMSchedule (0x0019) + + +uint32_t dot11f_unpack_ie_wmmtclas(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEWMMTCLAS *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->version = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (pDst->version != 0x1) { + pDst->present = 0; + return status | DOT11F_BAD_FIXED_VALUE; + } + pDst->user_priority = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->classifier_type = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->classifier_mask = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + switch (pDst->classifier_type) { + case 0: + DOT11F_MEMCPY(pCtx, pDst->info.EthParams.source, pBuf, 6); + pBuf += 6; + ielen -= (uint8_t)6; + DOT11F_MEMCPY(pCtx, pDst->info.EthParams.dest, pBuf, 6); + pBuf += 6; + ielen -= (uint8_t)6; + framesntohs(pCtx, &pDst->info.EthParams.type, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + break; + case 1: + pDst->info.IpParams.version = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + switch (pDst->info.IpParams.version) { + case 4: + DOT11F_MEMCPY(pCtx, pDst->info.IpParams.params.IpV4Params.source, pBuf, 4); + pBuf += 4; + ielen -= (uint8_t)4; + DOT11F_MEMCPY(pCtx, pDst->info.IpParams.params.IpV4Params.dest, pBuf, 4); + pBuf += 4; + ielen -= (uint8_t)4; + framesntohs(pCtx, &pDst->info.IpParams.params.IpV4Params.src_port, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + framesntohs(pCtx, &pDst->info.IpParams.params.IpV4Params.dest_port, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + pDst->info.IpParams.params.IpV4Params.DSCP = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->info.IpParams.params.IpV4Params.proto = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->info.IpParams.params.IpV4Params.reserved = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + break; + case 6: + DOT11F_MEMCPY(pCtx, pDst->info.IpParams.params.IpV6Params.source, pBuf, 16); + pBuf += 16; + ielen -= (uint8_t)16; + DOT11F_MEMCPY(pCtx, pDst->info.IpParams.params.IpV6Params.dest, pBuf, 16); + pBuf += 16; + ielen -= (uint8_t)16; + framesntohs(pCtx, &pDst->info.IpParams.params.IpV6Params.src_port, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + framesntohs(pCtx, &pDst->info.IpParams.params.IpV6Params.dest_port, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + DOT11F_MEMCPY(pCtx, pDst->info.IpParams.params.IpV6Params.flow_label, pBuf, 3); + pBuf += 3; + ielen -= (uint8_t)3; + break; + } + break; + case 2: + framesntohs(pCtx, &pDst->info.Params8021dq.tag_type, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + break; + } + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_wmmtclas. */ + +#define SigIeWMMTCLAS (0x001a) + + +uint32_t dot11f_unpack_ie_wmmtclasproc(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEWMMTCLASPROC *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->version = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (pDst->version != 0x1) { + pDst->present = 0; + return status | DOT11F_BAD_FIXED_VALUE; + } + pDst->processing = *pBuf; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_wmmtclasproc. */ + +#define SigIeWMMTCLASPROC (0x001b) + + +uint32_t dot11f_unpack_ie_wmmts_delay(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEWMMTSDelay *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->version = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (pDst->version != 0x1) { + pDst->present = 0; + return status | DOT11F_BAD_FIXED_VALUE; + } + framesntohl(pCtx, &pDst->delay, pBuf, 0); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_wmmts_delay. */ + +#define SigIeWMMTSDelay (0x001c) + + +uint32_t dot11f_unpack_ie_wmmtspec(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEWMMTSPEC *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + uint16_t tmp21__; + uint8_t tmp22__; + uint16_t tmp23__; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->version = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (pDst->version != 0x1) { + pDst->present = 0; + return status | DOT11F_BAD_FIXED_VALUE; + } + framesntohs(pCtx, &tmp21__, pBuf, 0); + pBuf += 2; + ielen -= 2; + pDst->traffic_type = tmp21__ >> 0 & 0x1; + pDst->tsid = tmp21__ >> 1 & 0xf; + pDst->direction = tmp21__ >> 5 & 0x3; + pDst->access_policy = tmp21__ >> 7 & 0x3; + pDst->aggregation = tmp21__ >> 9 & 0x1; + pDst->psb = tmp21__ >> 10 & 0x1; + pDst->user_priority = tmp21__ >> 11 & 0x7; + pDst->tsinfo_ack_pol = tmp21__ >> 14 & 0x3; + tmp22__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->tsinfo_rsvd = tmp22__ >> 0 & 0x7f; + pDst->burst_size_defn = tmp22__ >> 7 & 0x1; + framesntohs(pCtx, &tmp23__, pBuf, 0); + pBuf += 2; + ielen -= 2; + pDst->size = tmp23__ >> 0 & 0x7fff; + pDst->fixed = tmp23__ >> 15 & 0x1; + framesntohs(pCtx, &pDst->max_msdu_size, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + framesntohl(pCtx, &pDst->min_service_int, pBuf, 0); + pBuf += 4; + ielen -= (uint8_t)4; + framesntohl(pCtx, &pDst->max_service_int, pBuf, 0); + pBuf += 4; + ielen -= (uint8_t)4; + framesntohl(pCtx, &pDst->inactivity_int, pBuf, 0); + pBuf += 4; + ielen -= (uint8_t)4; + framesntohl(pCtx, &pDst->suspension_int, pBuf, 0); + pBuf += 4; + ielen -= (uint8_t)4; + framesntohl(pCtx, &pDst->service_start_time, pBuf, 0); + pBuf += 4; + ielen -= (uint8_t)4; + framesntohl(pCtx, &pDst->min_data_rate, pBuf, 0); + pBuf += 4; + ielen -= (uint8_t)4; + framesntohl(pCtx, &pDst->mean_data_rate, pBuf, 0); + pBuf += 4; + ielen -= (uint8_t)4; + framesntohl(pCtx, &pDst->peak_data_rate, pBuf, 0); + pBuf += 4; + ielen -= (uint8_t)4; + framesntohl(pCtx, &pDst->burst_size, pBuf, 0); + pBuf += 4; + ielen -= (uint8_t)4; + framesntohl(pCtx, &pDst->delay_bound, pBuf, 0); + pBuf += 4; + ielen -= (uint8_t)4; + framesntohl(pCtx, &pDst->min_phy_rate, pBuf, 0); + pBuf += 4; + ielen -= (uint8_t)4; + framesntohs(pCtx, &pDst->surplus_bw_allowance, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + framesntohs(pCtx, &pDst->medium_time, pBuf, 0); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_wmmtspec. */ + +#define SigIeWMMTSPEC (0x001d) + + +uint32_t dot11f_unpack_ie_wider_bw_chan_switch_ann(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEWiderBWChanSwitchAnn *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->newChanWidth = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->newCenterChanFreq0 = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->newCenterChanFreq1 = *pBuf; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_wider_bw_chan_switch_ann. */ + +#define SigIeWiderBWChanSwitchAnn (0x001e) + + +uint32_t dot11f_unpack_ie_azimuth_req(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEazimuth_req *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->request = *pBuf; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_azimuth_req. */ + +#define SigIeazimuth_req (0x001f) + + +uint32_t dot11f_unpack_ie_max_age(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEmax_age *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + framesntohs(pCtx, &pDst->max_age, pBuf, 0); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_max_age. */ + +#define SigIemax_age (0x0020) + + +static const tFFDefn FFS_neighbor_rpt[] = { + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_neighbor_rpt[] = { + { offsetof(tDot11fIEneighbor_rpt, TSFInfo), offsetof(tDot11fIETSFInfo, + present), 0, "TSFInfo", 0, 6, 6, SigIeTSFInfo, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_TSFINFO, 0, }, + { offsetof(tDot11fIEneighbor_rpt, CondensedCountryStr), + offsetof(tDot11fIECondensedCountryStr, present), 0, "CondensedCountryStr", + 0, 4, 4, SigIeCondensedCountryStr, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_CONDENSEDCOUNTRYSTR, 0, }, + { offsetof(tDot11fIEneighbor_rpt, MeasurementPilot), + offsetof(tDot11fIEMeasurementPilot, present), 0, "MeasurementPilot", + 0, 3, 258, SigIeMeasurementPilot, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_MEASUREMENTPILOT, 0, }, + { offsetof(tDot11fIEneighbor_rpt, RRMEnabledCap), + offsetof(tDot11fIERRMEnabledCap, present), 0, "RRMEnabledCap", + 0, 7, 7, SigIeRRMEnabledCap, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_RRMENABLEDCAP, 0, }, + { offsetof(tDot11fIEneighbor_rpt, MultiBssid), + offsetof(tDot11fIEMultiBssid, present), 0, "MultiBssid", + 0, 3, 258, SigIeMultiBssid, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_MULTIBSSID, 0, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, }, +}; + +uint32_t dot11f_unpack_ie_neighbor_rpt(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEneighbor_rpt *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + uint8_t tmp24__; + uint8_t tmp25__; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + DOT11F_MEMCPY(pCtx, pDst->bssid, pBuf, 6); + pBuf += 6; + ielen -= (uint8_t)6; + tmp24__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->APReachability = tmp24__ >> 0 & 0x3; + pDst->Security = tmp24__ >> 2 & 0x1; + pDst->KeyScope = tmp24__ >> 3 & 0x1; + pDst->SpecMgmtCap = tmp24__ >> 4 & 0x1; + pDst->QosCap = tmp24__ >> 5 & 0x1; + pDst->apsd = tmp24__ >> 6 & 0x1; + pDst->rrm = tmp24__ >> 7 & 0x1; + tmp25__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->DelayedBA = tmp25__ >> 0 & 0x1; + pDst->ImmBA = tmp25__ >> 1 & 0x1; + pDst->MobilityDomain = tmp25__ >> 2 & 0x1; + pDst->reserved = tmp25__ >> 3 & 0x1f; + framesntohs(pCtx, &pDst->reserved1, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + pDst->regulatoryClass = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->channel = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->PhyType = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + (void)pCtx; + status |= unpack_core(pCtx, + pBuf, + ielen, + FFS_neighbor_rpt, + IES_neighbor_rpt, + (uint8_t *)pDst, + sizeof(*pDst)); + return status; +} /* End dot11f_unpack_ie_neighbor_rpt. */ + +#define SigIeneighbor_rpt (0x0021) + + +uint32_t dot11f_unpack_ie_req_mac_addr(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEreq_mac_addr *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + DOT11F_MEMCPY(pCtx, pDst->addr, pBuf, 6); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_req_mac_addr. */ + +#define SigIereq_mac_addr (0x0022) + + +uint32_t dot11f_unpack_ie_tgt_mac_addr(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEtgt_mac_addr *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + DOT11F_MEMCPY(pCtx, pDst->addr, pBuf, 6); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_tgt_mac_addr. */ + +#define SigIetgt_mac_addr (0x0023) + + +uint32_t dot11f_unpack_ie_vht_transmit_power_env(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEvht_transmit_power_env *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->num_bytes = (uint8_t)(ielen); + if (ielen > 5) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->bytes, pBuf, (ielen)); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_vht_transmit_power_env. */ + +#define SigIevht_transmit_power_env (0x0024) + + +uint32_t dot11f_unpack_ie_aid(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEAID *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + framesntohs(pCtx, &pDst->assocId, pBuf, 0); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_aid. */ + +#define SigIeAID (0x0025) + + +uint32_t dot11f_unpack_ie_cf_params(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIECFParams *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->cfp_count = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->cfp_period = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + framesntohs(pCtx, &pDst->cfp_maxduration, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + framesntohs(pCtx, &pDst->cfp_durremaining, pBuf, 0); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_cf_params. */ + +#define SigIeCFParams (0x0026) + + +uint32_t dot11f_unpack_ie_challenge_text(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEChallengeText *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->num_text = (uint8_t)(ielen); + if (ielen > 253) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->text, pBuf, (ielen)); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_challenge_text. */ + +#define SigIeChallengeText (0x0027) + + +uint32_t dot11f_unpack_ie_chan_switch_ann(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEChanSwitchAnn *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->switchMode = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->newChannel = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->switchCount = *pBuf; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_chan_switch_ann. */ + +#define SigIeChanSwitchAnn (0x0028) + + +static const tFFDefn FFS_ChannelSwitchWrapper[] = { + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_ChannelSwitchWrapper[] = { + { offsetof(tDot11fIEChannelSwitchWrapper, WiderBWChanSwitchAnn), + offsetof(tDot11fIEWiderBWChanSwitchAnn, present), 0, + "WiderBWChanSwitchAnn", 0, 5, 5, SigIeWiderBWChanSwitchAnn, + {0, 0, 0, 0, 0}, 0, DOT11F_EID_WIDERBWCHANSWITCHANN, 0, }, + { offsetof(tDot11fIEChannelSwitchWrapper, vht_transmit_power_env), + offsetof(tDot11fIEvht_transmit_power_env, present), 0, + "vht_transmit_power_env", 0, 4, 7, SigIevht_transmit_power_env, + {0, 0, 0, 0, 0}, 0, DOT11F_EID_VHT_TRANSMIT_POWER_ENV, 0, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, }, +}; + +uint32_t dot11f_unpack_ie_channel_switch_wrapper(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEChannelSwitchWrapper *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + (void)pCtx; + status |= unpack_core(pCtx, + pBuf, + ielen, + FFS_ChannelSwitchWrapper, + IES_ChannelSwitchWrapper, + (uint8_t *)pDst, + sizeof(*pDst)); + return status; +} /* End dot11f_unpack_ie_channel_switch_wrapper. */ + +#define SigIeChannelSwitchWrapper (0x0029) + + +uint32_t dot11f_unpack_ie_country(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIECountry *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + DOT11F_MEMCPY(pCtx, pDst->country, pBuf, 3); + pBuf += 3; + ielen -= (uint8_t)3; + if (!ielen) { + pDst->num_triplets = 0U; + return 0U; + } else { + pDst->num_triplets = (uint8_t)(ielen / 3); + if (ielen > 84 * 3) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->triplets, pBuf, (ielen)); + } + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_country. */ + +#define SigIeCountry (0x002a) + + +#define SigIeDSParams (0x002b) + + +uint32_t dot11f_unpack_ie_edca_param_set(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEEDCAParamSet *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + uint8_t tmp26__; + uint8_t tmp27__; + uint8_t tmp28__; + uint8_t tmp29__; + uint8_t tmp30__; + uint8_t tmp31__; + uint8_t tmp32__; + uint8_t tmp33__; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->qos = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->reserved = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + tmp26__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->acbe_aifsn = tmp26__ >> 0 & 0xf; + pDst->acbe_acm = tmp26__ >> 4 & 0x1; + pDst->acbe_aci = tmp26__ >> 5 & 0x3; + pDst->unused1 = tmp26__ >> 7 & 0x1; + tmp27__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->acbe_acwmin = tmp27__ >> 0 & 0xf; + pDst->acbe_acwmax = tmp27__ >> 4 & 0xf; + framesntohs(pCtx, &pDst->acbe_txoplimit, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + tmp28__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->acbk_aifsn = tmp28__ >> 0 & 0xf; + pDst->acbk_acm = tmp28__ >> 4 & 0x1; + pDst->acbk_aci = tmp28__ >> 5 & 0x3; + pDst->unused2 = tmp28__ >> 7 & 0x1; + tmp29__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->acbk_acwmin = tmp29__ >> 0 & 0xf; + pDst->acbk_acwmax = tmp29__ >> 4 & 0xf; + framesntohs(pCtx, &pDst->acbk_txoplimit, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + tmp30__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->acvi_aifsn = tmp30__ >> 0 & 0xf; + pDst->acvi_acm = tmp30__ >> 4 & 0x1; + pDst->acvi_aci = tmp30__ >> 5 & 0x3; + pDst->unused3 = tmp30__ >> 7 & 0x1; + tmp31__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->acvi_acwmin = tmp31__ >> 0 & 0xf; + pDst->acvi_acwmax = tmp31__ >> 4 & 0xf; + framesntohs(pCtx, &pDst->acvi_txoplimit, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + tmp32__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->acvo_aifsn = tmp32__ >> 0 & 0xf; + pDst->acvo_acm = tmp32__ >> 4 & 0x1; + pDst->acvo_aci = tmp32__ >> 5 & 0x3; + pDst->unused4 = tmp32__ >> 7 & 0x1; + tmp33__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->acvo_acwmin = tmp33__ >> 0 & 0xf; + pDst->acvo_acwmax = tmp33__ >> 4 & 0xf; + framesntohs(pCtx, &pDst->acvo_txoplimit, pBuf, 0); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_edca_param_set. */ + +#define SigIeEDCAParamSet (0x002c) + + +uint32_t dot11f_unpack_ie_erp_info(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEERPInfo *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + uint8_t tmp34__; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + tmp34__ = *pBuf; + pDst->non_erp_present = tmp34__ >> 0 & 0x1; + pDst->use_prot = tmp34__ >> 1 & 0x1; + pDst->barker_preamble = tmp34__ >> 2 & 0x1; + pDst->unused = tmp34__ >> 3 & 0x1f; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_erp_info. */ + +#define SigIeERPInfo (0x002d) + + +uint32_t dot11f_unpack_ie_ese_cckm_opaque(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEESECckmOpaque *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->num_data = (uint8_t)(ielen); + if (ielen > 20) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->data, pBuf, (ielen)); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_ese_cckm_opaque. */ + +#define SigIeESECckmOpaque (0x002e) + + +uint32_t dot11f_unpack_ie_ese_rad_mgmt_cap(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEESERadMgmtCap *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + uint8_t tmp35__; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->mgmt_state = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + tmp35__ = *pBuf; + pDst->mbssid_mask = tmp35__ >> 0 & 0x7; + pDst->reserved = tmp35__ >> 3 & 0x1f; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_ese_rad_mgmt_cap. */ + +#define SigIeESERadMgmtCap (0x002f) + + +uint32_t dot11f_unpack_ie_ese_traf_strm_met(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEESETrafStrmMet *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->tsid = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->state = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + framesntohs(pCtx, &pDst->msmt_interval, pBuf, 0); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_ese_traf_strm_met. */ + +#define SigIeESETrafStrmMet (0x0030) + + +uint32_t dot11f_unpack_ie_ese_traf_strm_rate_set(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEESETrafStrmRateSet *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->tsid = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->num_tsrates = (uint8_t)(ielen); + if (ielen > 8) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->tsrates, pBuf, (ielen)); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_ese_traf_strm_rate_set. */ + +#define SigIeESETrafStrmRateSet (0x0031) + + +uint32_t dot11f_unpack_ie_ese_txmit_power(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEESETxmitPower *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->power_limit = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->reserved = *pBuf; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_ese_txmit_power. */ + +#define SigIeESETxmitPower (0x0032) + + +uint32_t dot11f_unpack_ie_ese_version(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEESEVersion *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->version = *pBuf; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_ese_version. */ + +#define SigIeESEVersion (0x0033) + + +uint32_t dot11f_unpack_ie_ext_cap(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEExtCap *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + + if (!ielen) /* Check to ensure copying of ielen bytes */ + goto endUnpackIeExtCap; + pDst->num_bytes = (uint8_t)(ielen); + if (ielen > 15) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->bytes, pBuf, (ielen)); + +endUnpackIeExtCap: + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_ext_cap. */ + +#define SigIeExtCap (0x0034) + + +uint32_t dot11f_unpack_ie_ext_supp_rates(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEExtSuppRates *pDst) +{ + uint8_t i; + uint8_t rate_indx = 0; + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + for (i = 0; i < ielen; i++) { + if ((DOT11F_IS_BG_RATE(pBuf[i] & 0x7F)) && + (rate_indx < 12)) { + pDst->rates[rate_indx++] = pBuf[i]; + } + } + + if (rate_indx == 0) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + pDst->num_rates = rate_indx; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_ext_supp_rates. */ + +#define SigIeExtSuppRates (0x0035) + + +uint32_t dot11f_unpack_ie_fh_param_set(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEFHParamSet *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + framesntohs(pCtx, &pDst->dwell_time, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + pDst->hop_set = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->hop_pattern = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->hop_index = *pBuf; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_fh_param_set. */ + +#define SigIeFHParamSet (0x0036) + + +uint32_t dot11f_unpack_ie_fh_params(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEFHParams *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->radix = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->nchannels = *pBuf; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_fh_params. */ + +#define SigIeFHParams (0x0037) + + +uint32_t dot11f_unpack_ie_fh_patt_table(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEFHPattTable *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->flag = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->nsets = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->modulus = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->offset = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->num_randtable = (uint8_t)(ielen); + if (ielen > 251) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->randtable, pBuf, (ielen)); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_fh_patt_table. */ + +#define SigIeFHPattTable (0x0038) + + +static const tFFDefn FFS_FTInfo[] = { + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_FTInfo[] = { + { offsetof(tDot11fIEFTInfo, R1KH_ID), offsetof(tDot11fIER1KH_ID, present), + 0, "R1KH_ID", 0, 8, 8, SigIeR1KH_ID, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_R1KH_ID, 0, }, + { offsetof(tDot11fIEFTInfo, GTK), offsetof(tDot11fIEGTK, present), 0, "GTK", + 0, 18, 45, SigIeGTK, {0, 0, 0, 0, 0}, 0, DOT11F_EID_GTK, 0, }, + { offsetof(tDot11fIEFTInfo, R0KH_ID), offsetof(tDot11fIER0KH_ID, present), + 0, "R0KH_ID", 0, 3, 50, SigIeR0KH_ID, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_R0KH_ID, 0, }, + { offsetof(tDot11fIEFTInfo, IGTK), offsetof(tDot11fIEIGTK, present), 0, + "IGTK", 0, 35, 35, SigIeIGTK, {0, 0, 0, 0, 0}, 0, DOT11F_EID_IGTK, 0, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, }, +}; + +uint32_t dot11f_unpack_ie_ft_info(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEFTInfo *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + uint16_t tmp36__; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + framesntohs(pCtx, &tmp36__, pBuf, 0); + pBuf += 2; + ielen -= 2; + pDst->reserved = tmp36__ >> 0 & 0xff; + pDst->IECount = tmp36__ >> 8 & 0xff; + DOT11F_MEMCPY(pCtx, pDst->MIC, pBuf, 16); + pBuf += 16; + ielen -= (uint8_t)16; + DOT11F_MEMCPY(pCtx, pDst->Anonce, pBuf, 32); + pBuf += 32; + ielen -= (uint8_t)32; + DOT11F_MEMCPY(pCtx, pDst->Snonce, pBuf, 32); + pBuf += 32; + ielen -= (uint8_t)32; + (void)pCtx; + status |= unpack_core(pCtx, + pBuf, + ielen, + FFS_FTInfo, + IES_FTInfo, + (uint8_t *)pDst, + sizeof(*pDst)); + return status; +} /* End dot11f_unpack_ie_ft_info. */ + +#define SigIeFTInfo (0x0039) + + +uint32_t dot11f_unpack_ie_ht_caps(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEHTCaps *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + uint16_t tmp37__; + uint8_t tmp38__; + uint16_t tmp39__; + uint32_t tmp40__; + uint8_t tmp41__; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + framesntohs(pCtx, &tmp37__, pBuf, 0); + pBuf += 2; + ielen -= 2; + pDst->advCodingCap = tmp37__ >> 0 & 0x1; + pDst->supportedChannelWidthSet = tmp37__ >> 1 & 0x1; + pDst->mimoPowerSave = tmp37__ >> 2 & 0x3; + pDst->greenField = tmp37__ >> 4 & 0x1; + pDst->shortGI20MHz = tmp37__ >> 5 & 0x1; + pDst->shortGI40MHz = tmp37__ >> 6 & 0x1; + pDst->txSTBC = tmp37__ >> 7 & 0x1; + pDst->rxSTBC = tmp37__ >> 8 & 0x3; + pDst->delayedBA = tmp37__ >> 10 & 0x1; + pDst->maximalAMSDUsize = tmp37__ >> 11 & 0x1; + pDst->dsssCckMode40MHz = tmp37__ >> 12 & 0x1; + pDst->psmp = tmp37__ >> 13 & 0x1; + pDst->stbcControlFrame = tmp37__ >> 14 & 0x1; + pDst->lsigTXOPProtection = tmp37__ >> 15 & 0x1; + tmp38__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->maxRxAMPDUFactor = tmp38__ >> 0 & 0x3; + pDst->mpduDensity = tmp38__ >> 2 & 0x7; + pDst->reserved1 = tmp38__ >> 5 & 0x7; + DOT11F_MEMCPY(pCtx, pDst->supportedMCSSet, pBuf, 16); + pBuf += 16; + ielen -= (uint8_t)16; + framesntohs(pCtx, &tmp39__, pBuf, 0); + pBuf += 2; + ielen -= 2; + pDst->pco = tmp39__ >> 0 & 0x1; + pDst->transitionTime = tmp39__ >> 1 & 0x3; + pDst->reserved2 = tmp39__ >> 3 & 0x1f; + pDst->mcsFeedback = tmp39__ >> 8 & 0x3; + pDst->reserved3 = tmp39__ >> 10 & 0x3f; + framesntohl(pCtx, &tmp40__, pBuf, 0); + pBuf += 4; + ielen -= 4; + pDst->txBF = tmp40__ >> 0 & 0x1; + pDst->rxStaggeredSounding = tmp40__ >> 1 & 0x1; + pDst->txStaggeredSounding = tmp40__ >> 2 & 0x1; + pDst->rxZLF = tmp40__ >> 3 & 0x1; + pDst->txZLF = tmp40__ >> 4 & 0x1; + pDst->implicitTxBF = tmp40__ >> 5 & 0x1; + pDst->calibration = tmp40__ >> 6 & 0x3; + pDst->explicitCSITxBF = tmp40__ >> 8 & 0x1; + pDst->explicitUncompressedSteeringMatrix = tmp40__ >> 9 & 0x1; + pDst->explicitBFCSIFeedback = tmp40__ >> 10 & 0x7; + pDst->explicitUncompressedSteeringMatrixFeedback = tmp40__ >> 13 & 0x7; + pDst->explicitCompressedSteeringMatrixFeedback = tmp40__ >> 16 & 0x7; + pDst->csiNumBFAntennae = tmp40__ >> 19 & 0x3; + pDst->uncompressedSteeringMatrixBFAntennae = tmp40__ >> 21 & 0x3; + pDst->compressedSteeringMatrixBFAntennae = tmp40__ >> 23 & 0x3; + pDst->reserved4 = tmp40__ >> 25 & 0x7f; + tmp41__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->antennaSelection = tmp41__ >> 0 & 0x1; + pDst->explicitCSIFeedbackTx = tmp41__ >> 1 & 0x1; + pDst->antennaIndicesFeedbackTx = tmp41__ >> 2 & 0x1; + pDst->explicitCSIFeedback = tmp41__ >> 3 & 0x1; + pDst->antennaIndicesFeedback = tmp41__ >> 4 & 0x1; + pDst->rxAS = tmp41__ >> 5 & 0x1; + pDst->txSoundingPPDUs = tmp41__ >> 6 & 0x1; + pDst->reserved5 = tmp41__ >> 7 & 0x1; + pDst->num_rsvd = (uint8_t)(ielen); + if (ielen > 32) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->rsvd, pBuf, (ielen)); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_ht_caps. */ + +#define SigIeHTCaps (0x003a) + + +uint32_t dot11f_unpack_ie_ht_info(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEHTInfo *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + uint8_t tmp42__; + uint16_t tmp43__; + uint16_t tmp44__; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->primaryChannel = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + tmp42__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->secondaryChannelOffset = tmp42__ >> 0 & 0x3; + pDst->recommendedTxWidthSet = tmp42__ >> 2 & 0x1; + pDst->rifsMode = tmp42__ >> 3 & 0x1; + pDst->controlledAccessOnly = tmp42__ >> 4 & 0x1; + pDst->serviceIntervalGranularity = tmp42__ >> 5 & 0x7; + framesntohs(pCtx, &tmp43__, pBuf, 0); + pBuf += 2; + ielen -= 2; + pDst->opMode = tmp43__ >> 0 & 0x3; + pDst->nonGFDevicesPresent = tmp43__ >> 2 & 0x1; + pDst->transmitBurstLimit = tmp43__ >> 3 & 0x1; + pDst->obssNonHTStaPresent = tmp43__ >> 4 & 0x1; + pDst->reserved = tmp43__ >> 5 & 0x7ff; + framesntohs(pCtx, &tmp44__, pBuf, 0); + pBuf += 2; + ielen -= 2; + pDst->basicSTBCMCS = tmp44__ >> 0 & 0x7f; + pDst->dualCTSProtection = tmp44__ >> 7 & 0x1; + pDst->secondaryBeacon = tmp44__ >> 8 & 0x1; + pDst->lsigTXOPProtectionFullSupport = tmp44__ >> 9 & 0x1; + pDst->pcoActive = tmp44__ >> 10 & 0x1; + pDst->pcoPhase = tmp44__ >> 11 & 0x1; + pDst->reserved2 = tmp44__ >> 12 & 0xf; + DOT11F_MEMCPY(pCtx, pDst->basicMCSSet, pBuf, 16); + pBuf += 16; + ielen -= (uint8_t)16; + pDst->num_rsvd = (uint8_t)(ielen); + if (ielen > 32) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->rsvd, pBuf, (ielen)); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_ht_info. */ + +#define SigIeHTInfo (0x003b) + + +uint32_t dot11f_unpack_ie_ibss_params(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEIBSSParams *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + framesntohs(pCtx, &pDst->atim, pBuf, 0); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_ibss_params. */ + +#define SigIeIBSSParams (0x003c) + + +uint32_t dot11f_unpack_ie_link_identifier(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIELinkIdentifier *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + DOT11F_MEMCPY(pCtx, pDst->bssid, pBuf, 6); + pBuf += 6; + ielen -= (uint8_t)6; + DOT11F_MEMCPY(pCtx, pDst->InitStaAddr, pBuf, 6); + pBuf += 6; + ielen -= (uint8_t)6; + DOT11F_MEMCPY(pCtx, pDst->RespStaAddr, pBuf, 6); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_link_identifier. */ + +#define SigIeLinkIdentifier (0x003d) + + +uint32_t dot11f_unpack_ie_MBO_IE(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEMBO_IE *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + DOT11F_MEMCPY(pCtx, pDst->mbo_cap, pBuf, 3); + pBuf += 3; + ielen -= (uint8_t)3; + pDst->num_assoc_disallowed = (uint8_t)(ielen); + if (ielen > 3) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->assoc_disallowed, pBuf, (ielen)); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_MBO_IE. */ + +#define SigIeMBO_IE (0x003e) + + +static const tFFDefn FFS_reportBeacon[] = { + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_reportBeacon[] = { + { offsetof(tDot11fIEMeasurementReport, + report.Beacon.BeaconReportFrmBody), + offsetof(tDot11fIEBeaconReportFrmBody, present), 0, "BeaconReportFrmBody", + 0, 2, 226, SigIeBeaconReportFrmBody, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_BEACONREPORTFRMBODY, 0, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, }, +}; + +uint32_t dot11f_unpack_ie_measurement_report(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEMeasurementReport *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + uint8_t tmp45__; + uint8_t tmp46__; + uint8_t tmp47__; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->token = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + tmp45__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->late = tmp45__ >> 0 & 0x1; + pDst->incapable = tmp45__ >> 1 & 0x1; + pDst->refused = tmp45__ >> 2 & 0x1; + pDst->unused = tmp45__ >> 3 & 0x1f; + pDst->type = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (!ielen) { + return 0U; + } else { + switch (pDst->type) { + case 0: + pDst->report.Basic.channel = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + framesntohq(pCtx, &pDst->report.Basic.meas_start_time, pBuf, 0); + pBuf += 8; + ielen -= (uint8_t)8; + framesntohs(pCtx, &pDst->report.Basic.meas_duration, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + tmp46__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->report.Basic.bss = tmp46__ >> 0 & 0x1; + pDst->report.Basic.ofdm_preamble = tmp46__ >> 1 & 0x1; + pDst->report.Basic.unid_signal = tmp46__ >> 2 & 0x1; + pDst->report.Basic.rader = tmp46__ >> 3 & 0x1; + pDst->report.Basic.unmeasured = tmp46__ >> 4 & 0x1; + pDst->report.Basic.unused = tmp46__ >> 5 & 0x7; + break; + case 1: + pDst->report.CCA.channel = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + framesntohq(pCtx, &pDst->report.CCA.meas_start_time, pBuf, 0); + pBuf += 8; + ielen -= (uint8_t)8; + framesntohs(pCtx, &pDst->report.CCA.meas_duration, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + pDst->report.CCA.cca_busy_fraction = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + break; + case 2: + pDst->report.RPIHistogram.channel = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + framesntohq(pCtx, &pDst->report.RPIHistogram.meas_start_time, pBuf, 0); + pBuf += 8; + ielen -= (uint8_t)8; + framesntohs(pCtx, &pDst->report.RPIHistogram.meas_duration, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + pDst->report.RPIHistogram.rpi0_density = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->report.RPIHistogram.rpi1_density = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->report.RPIHistogram.rpi2_density = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->report.RPIHistogram.rpi3_density = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->report.RPIHistogram.rpi4_density = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->report.RPIHistogram.rpi5_density = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->report.RPIHistogram.rpi6_density = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->report.RPIHistogram.rpi7_density = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + break; + case 5: + pDst->report.Beacon.regClass = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->report.Beacon.channel = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + framesntohq(pCtx, &pDst->report.Beacon.meas_start_time, pBuf, 0); + pBuf += 8; + ielen -= (uint8_t)8; + framesntohs(pCtx, &pDst->report.Beacon.meas_duration, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + tmp47__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->report.Beacon.condensed_PHY = tmp47__ >> 0 & 0x7f; + pDst->report.Beacon.reported_frame_type = tmp47__ >> 7 & 0x1; + pDst->report.Beacon.RCPI = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->report.Beacon.RSNI = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + DOT11F_MEMCPY(pCtx, pDst->report.Beacon.BSSID, pBuf, 6); + pBuf += 6; + ielen -= (uint8_t)6; + pDst->report.Beacon.antenna_id = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + framesntohl(pCtx, &pDst->report.Beacon.parent_TSF, pBuf, 0); + pBuf += 4; + ielen -= (uint8_t)4; + status |= unpack_core(pCtx, + pBuf, + ielen, + FFS_reportBeacon, + IES_reportBeacon, + (uint8_t *)pDst, + sizeof(*pDst)); + break; + } + } + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_measurement_report. */ + +#define SigIeMeasurementReport (0x003f) + + +static const tFFDefn FFS_measurement_requestBeacon[] = { + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_measurement_requestBeacon[] = { + { offsetof(tDot11fIEMeasurementRequest, + measurement_request.Beacon.SSID), offsetof(tDot11fIESSID, present), 0, + "SSID", 0, 2, 34, SigIeSSID, {0, 0, 0, 0, 0}, 0, DOT11F_EID_SSID, 0, }, + { offsetof(tDot11fIEMeasurementRequest, + measurement_request.Beacon.BeaconReporting), + offsetof(tDot11fIEBeaconReporting, present), 0, "BeaconReporting", + 0, 4, 4, SigIeBeaconReporting, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_BEACONREPORTING, 0, }, + { offsetof(tDot11fIEMeasurementRequest, + measurement_request.Beacon.BcnReportingDetail), + offsetof(tDot11fIEBcnReportingDetail, present), 0, "BcnReportingDetail", + 0, 3, 3, SigIeBcnReportingDetail, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_BCNREPORTINGDETAIL, 0, }, + { offsetof(tDot11fIEMeasurementRequest, + measurement_request.Beacon.RequestedInfo), + offsetof(tDot11fIERequestedInfo, present), 0, "RequestedInfo", + 0, 2, 257, SigIeRequestedInfo, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_REQUESTEDINFO, 0, }, + { offsetof(tDot11fIEMeasurementRequest, + measurement_request.Beacon.APChannelReport), + offsetof(tDot11fIEAPChannelReport, present), + offsetof(tDot11fIEMeasurementRequest, measurement_request.Beacon.num_APChannelReport), "APChannelReport", 2, 3, 53, SigIeAPChannelReport, {0, 0, 0, 0, 0}, 0, DOT11F_EID_APCHANNELREPORT, 0, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, }, +}; + +static const tFFDefn FFS_measurement_requestlci[] = { + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_measurement_requestlci[] = { + { offsetof(tDot11fIEMeasurementRequest, + measurement_request.lci.azimuth_req), offsetof(tDot11fIEazimuth_req, + present), 0, "azimuth_req", 0, 3, 3, SigIeazimuth_req, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_AZIMUTH_REQ, 0, }, + { offsetof(tDot11fIEMeasurementRequest, + measurement_request.lci.req_mac_addr), offsetof(tDot11fIEreq_mac_addr, + present), 0, "req_mac_addr", 0, 8, 8, SigIereq_mac_addr, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_REQ_MAC_ADDR, 0, }, + { offsetof(tDot11fIEMeasurementRequest, + measurement_request.lci.tgt_mac_addr), offsetof(tDot11fIEtgt_mac_addr, + present), 0, "tgt_mac_addr", 0, 8, 8, SigIetgt_mac_addr, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_TGT_MAC_ADDR, 0, }, + { offsetof(tDot11fIEMeasurementRequest, + measurement_request.lci.max_age), offsetof(tDot11fIEmax_age, present), 0, + "max_age", 0, 4, 4, SigIemax_age, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_MAX_AGE, 0, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, }, +}; + +static const tFFDefn FFS_measurement_requestftmrr[] = { + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_measurement_requestftmrr[] = { + { offsetof(tDot11fIEMeasurementRequest, + measurement_request.ftmrr.neighbor_rpt), offsetof(tDot11fIEneighbor_rpt, + present), 0, "neighbor_rpt", 0, 15, 548, SigIeneighbor_rpt, + {0, 0, 0, 0, 0}, 0, DOT11F_EID_NEIGHBOR_RPT, 0, }, + { offsetof(tDot11fIEMeasurementRequest, + measurement_request.ftmrr.max_age), offsetof(tDot11fIEmax_age, present), + 0, "max_age", 0, 4, 4, SigIemax_age, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_MAX_AGE, 0, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, }, +}; + +uint32_t dot11f_unpack_ie_measurement_request(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEMeasurementRequest *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + uint8_t tmp48__; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->measurement_token = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + tmp48__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->parallel = tmp48__ >> 0 & 0x1; + pDst->enable = tmp48__ >> 1 & 0x1; + pDst->request = tmp48__ >> 2 & 0x1; + pDst->report = tmp48__ >> 3 & 0x1; + pDst->durationMandatory = tmp48__ >> 4 & 0x1; + pDst->unused = tmp48__ >> 5 & 0x7; + pDst->measurement_type = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + switch (pDst->measurement_type) { + case 0: + pDst->measurement_request.Basic.channel_no = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + DOT11F_MEMCPY(pCtx, pDst->measurement_request.Basic.meas_start_time, pBuf, 8); + pBuf += 8; + ielen -= (uint8_t)8; + framesntohs(pCtx, &pDst->measurement_request.Basic.meas_duration, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + break; + case 1: + pDst->measurement_request.CCA.channel_no = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + DOT11F_MEMCPY(pCtx, pDst->measurement_request.CCA.meas_start_time, pBuf, 8); + pBuf += 8; + ielen -= (uint8_t)8; + framesntohs(pCtx, &pDst->measurement_request.CCA.meas_duration, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + break; + case 2: + pDst->measurement_request.RPIHistogram.channel_no = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + DOT11F_MEMCPY(pCtx, pDst->measurement_request.RPIHistogram.meas_start_time, pBuf, 8); + pBuf += 8; + ielen -= (uint8_t)8; + framesntohs(pCtx, &pDst->measurement_request.RPIHistogram.meas_duration, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + break; + case 5: + pDst->measurement_request.Beacon.regClass = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->measurement_request.Beacon.channel = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + framesntohs(pCtx, &pDst->measurement_request.Beacon.randomization, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + framesntohs(pCtx, &pDst->measurement_request.Beacon.meas_duration, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + pDst->measurement_request.Beacon.meas_mode = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + DOT11F_MEMCPY(pCtx, pDst->measurement_request.Beacon.BSSID, pBuf, 6); + pBuf += 6; + ielen -= (uint8_t)6; + status |= unpack_core(pCtx, + pBuf, + ielen, + FFS_measurement_requestBeacon, + IES_measurement_requestBeacon, + (uint8_t *)pDst, + sizeof(*pDst)); + break; + case 8: + pDst->measurement_request.lci.loc_subject = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + status |= unpack_core(pCtx, + pBuf, + ielen, + FFS_measurement_requestlci, + IES_measurement_requestlci, + (uint8_t *)pDst, + sizeof(*pDst)); + break; + case 16: + framesntohs(pCtx, &pDst->measurement_request.ftmrr.random_interval, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + pDst->measurement_request.ftmrr.min_ap_count = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + status |= unpack_core(pCtx, + pBuf, + ielen, + FFS_measurement_requestftmrr, + IES_measurement_requestftmrr, + (uint8_t *)pDst, + sizeof(*pDst)); + break; + } + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_measurement_request. */ + +#define SigIeMeasurementRequest (0x0040) + + +uint32_t dot11f_unpack_ie_mobility_domain(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEMobilityDomain *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + uint8_t tmp49__; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + framesntohs(pCtx, &pDst->MDID, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + tmp49__ = *pBuf; + pDst->overDSCap = tmp49__ >> 0 & 0x1; + pDst->resourceReqCap = tmp49__ >> 1 & 0x1; + pDst->reserved = tmp49__ >> 2 & 0x3f; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_mobility_domain. */ + +#define SigIeMobilityDomain (0x0041) + + +static const tFFDefn FFS_NeighborReport[] = { + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_NeighborReport[] = { + { offsetof(tDot11fIENeighborReport, TSFInfo), offsetof(tDot11fIETSFInfo, + present), 0, "TSFInfo", 0, 6, 6, SigIeTSFInfo, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_TSFINFO, 0, }, + { offsetof(tDot11fIENeighborReport, CondensedCountryStr), + offsetof(tDot11fIECondensedCountryStr, present), 0, "CondensedCountryStr", + 0, 4, 4, SigIeCondensedCountryStr, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_CONDENSEDCOUNTRYSTR, 0, }, + { offsetof(tDot11fIENeighborReport, MeasurementPilot), + offsetof(tDot11fIEMeasurementPilot, present), 0, "MeasurementPilot", + 0, 3, 258, SigIeMeasurementPilot, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_MEASUREMENTPILOT, 0, }, + { offsetof(tDot11fIENeighborReport, RRMEnabledCap), + offsetof(tDot11fIERRMEnabledCap, present), 0, "RRMEnabledCap", + 0, 7, 7, SigIeRRMEnabledCap, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_RRMENABLEDCAP, 0, }, + { offsetof(tDot11fIENeighborReport, MultiBssid), + offsetof(tDot11fIEMultiBssid, present), 0, "MultiBssid", + 0, 3, 258, SigIeMultiBssid, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_MULTIBSSID, 0, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, }, +}; + +uint32_t dot11f_unpack_ie_neighbor_report(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIENeighborReport *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + uint8_t tmp50__; + uint8_t tmp51__; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + DOT11F_MEMCPY(pCtx, pDst->bssid, pBuf, 6); + pBuf += 6; + ielen -= (uint8_t)6; + tmp50__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->APReachability = tmp50__ >> 0 & 0x3; + pDst->Security = tmp50__ >> 2 & 0x1; + pDst->KeyScope = tmp50__ >> 3 & 0x1; + pDst->SpecMgmtCap = tmp50__ >> 4 & 0x1; + pDst->QosCap = tmp50__ >> 5 & 0x1; + pDst->apsd = tmp50__ >> 6 & 0x1; + pDst->rrm = tmp50__ >> 7 & 0x1; + tmp51__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->DelayedBA = tmp51__ >> 0 & 0x1; + pDst->ImmBA = tmp51__ >> 1 & 0x1; + pDst->MobilityDomain = tmp51__ >> 2 & 0x1; + pDst->reserved = tmp51__ >> 3 & 0x1f; + framesntohs(pCtx, &pDst->reserved1, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + pDst->regulatoryClass = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->channel = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->PhyType = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + (void)pCtx; + status |= unpack_core(pCtx, + pBuf, + ielen, + FFS_NeighborReport, + IES_NeighborReport, + (uint8_t *)pDst, + sizeof(*pDst)); + return status; +} /* End dot11f_unpack_ie_neighbor_report. */ + +#define SigIeNeighborReport (0x0042) + + +uint32_t dot11f_unpack_ie_obss_scan_parameters(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEOBSSScanParameters *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + framesntohs(pCtx, &pDst->obssScanPassiveDwell, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + framesntohs(pCtx, &pDst->obssScanActiveDwell, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + framesntohs(pCtx, &pDst->bssChannelWidthTriggerScanInterval, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + framesntohs(pCtx, &pDst->obssScanPassiveTotalPerChannel, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + framesntohs(pCtx, &pDst->obssScanActiveTotalPerChannel, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + framesntohs(pCtx, &pDst->bssWidthChannelTransitionDelayFactor, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + framesntohs(pCtx, &pDst->obssScanActivityThreshold, pBuf, 0); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_obss_scan_parameters. */ + +#define SigIeOBSSScanParameters (0x0043) + + +uint32_t dot11f_unpack_ie_operating_mode(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEOperatingMode *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + uint8_t tmp52__; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + tmp52__ = *pBuf; + pDst->chanWidth = tmp52__ >> 0 & 0x3; + pDst->reserved = tmp52__ >> 2 & 0x3; + pDst->rxNSS = tmp52__ >> 4 & 0x7; + pDst->rxNSSType = tmp52__ >> 7 & 0x1; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_operating_mode. */ + +#define SigIeOperatingMode (0x0044) + + +static const tTLVDefn TLVS_P2PAssocReq[] = { + { offsetof(tDot11fIEP2PAssocReq, P2PCapability), + offsetof(tDot11fTLVP2PCapability, present), "P2PCapability", + SigTlvP2PCapability, DOT11F_TLV_P2PCAPABILITY, 0, 5, 5, 1, 1, 2, 0, }, + { offsetof(tDot11fIEP2PAssocReq, ExtendedListenTiming), + offsetof(tDot11fTLVExtendedListenTiming, present), + "ExtendedListenTiming", SigTlvExtendedListenTiming, + DOT11F_TLV_EXTENDEDLISTENTIMING, 0, 7, 7, 0, 1, 2, 0, }, + { offsetof(tDot11fIEP2PAssocReq, P2PDeviceInfo), + offsetof(tDot11fTLVP2PDeviceInfo, present), "P2PDeviceInfo", + SigTlvP2PDeviceInfo, DOT11F_TLV_P2PDEVICEINFO, 0, 19, 55, 1, 1, 2, 0, }, + {0, 0, NULL, 0, 0xffff, 0, 0, 0, 0, 0, 0}, +}; + +uint32_t dot11f_unpack_ie_p2_p_assoc_req(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEP2PAssocReq *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pBuf; (void)ielen; /* Shutup the compiler */ + pDst->present = 1; + status = unpack_tlv_core(pCtx, pBuf, ielen, + TLVS_P2PAssocReq, + (uint8_t *)pDst, sizeof(*pDst)); + return status; +} /* End dot11f_unpack_ie_p2_p_assoc_req. */ + +#define SigIeP2PAssocReq (0x0045) + + +static const tTLVDefn TLVS_P2PAssocRes[] = { + { offsetof(tDot11fIEP2PAssocRes, P2PStatus), + offsetof(tDot11fTLVP2PStatus, present), "P2PStatus", SigTlvP2PStatus, + DOT11F_TLV_P2PSTATUS, 0, 4, 4, 1, 1, 2, 0, }, + { offsetof(tDot11fIEP2PAssocRes, ExtendedListenTiming), + offsetof(tDot11fTLVExtendedListenTiming, present), + "ExtendedListenTiming", SigTlvExtendedListenTiming, + DOT11F_TLV_EXTENDEDLISTENTIMING, 0, 7, 7, 0, 1, 2, 0, }, + {0, 0, NULL, 0, 0xffff, 0, 0, 0, 0, 0, 0}, +}; + +uint32_t dot11f_unpack_ie_p2_p_assoc_res(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEP2PAssocRes *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pBuf; (void)ielen; /* Shutup the compiler */ + pDst->present = 1; + status = unpack_tlv_core(pCtx, pBuf, ielen, + TLVS_P2PAssocRes, + (uint8_t *)pDst, sizeof(*pDst)); + return status; +} /* End dot11f_unpack_ie_p2_p_assoc_res. */ + +#define SigIeP2PAssocRes (0x0046) + + +static const tTLVDefn TLVS_P2PBeacon[] = { + { offsetof(tDot11fIEP2PBeacon, P2PCapability), + offsetof(tDot11fTLVP2PCapability, present), "P2PCapability", + SigTlvP2PCapability, DOT11F_TLV_P2PCAPABILITY, 0, 5, 5, 1, 1, 2, 0, }, + { offsetof(tDot11fIEP2PBeacon, P2PDeviceId), + offsetof(tDot11fTLVP2PDeviceId, present), "P2PDeviceId", + SigTlvP2PDeviceId, DOT11F_TLV_P2PDEVICEID, 0, 9, 9, 1, 1, 2, 0, }, + { offsetof(tDot11fIEP2PBeacon, NoticeOfAbsence), + offsetof(tDot11fTLVNoticeOfAbsence, present), "NoticeOfAbsence", + SigTlvNoticeOfAbsence, DOT11F_TLV_NOTICEOFABSENCE, + 0, 5, 41, 0, 1, 2, 0, }, + {0, 0, NULL, 0, 0xffff, 0, 0, 0, 0, 0, 0}, +}; + +uint32_t dot11f_unpack_ie_p2_p_beacon(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEP2PBeacon *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pBuf; (void)ielen; /* Shutup the compiler */ + pDst->present = 1; + status = unpack_tlv_core(pCtx, pBuf, ielen, + TLVS_P2PBeacon, + (uint8_t *)pDst, sizeof(*pDst)); + return status; +} /* End dot11f_unpack_ie_p2_p_beacon. */ + +#define SigIeP2PBeacon (0x0047) + + +static const tTLVDefn TLVS_P2PBeaconProbeRes[] = { + { offsetof(tDot11fIEP2PBeaconProbeRes, P2PCapability), + offsetof(tDot11fTLVP2PCapability, present), "P2PCapability", + SigTlvP2PCapability, DOT11F_TLV_P2PCAPABILITY, 0, 5, 5, 0, 1, 2, 0, }, + { offsetof(tDot11fIEP2PBeaconProbeRes, P2PDeviceId), + offsetof(tDot11fTLVP2PDeviceId, present), "P2PDeviceId", + SigTlvP2PDeviceId, DOT11F_TLV_P2PDEVICEID, 0, 9, 9, 0, 1, 2, 0, }, + { offsetof(tDot11fIEP2PBeaconProbeRes, ExtendedListenTiming), + offsetof(tDot11fTLVExtendedListenTiming, present), + "ExtendedListenTiming", SigTlvExtendedListenTiming, + DOT11F_TLV_EXTENDEDLISTENTIMING, 0, 7, 7, 0, 1, 2, 0, }, + { offsetof(tDot11fIEP2PBeaconProbeRes, NoticeOfAbsence), + offsetof(tDot11fTLVNoticeOfAbsence, present), "NoticeOfAbsence", + SigTlvNoticeOfAbsence, DOT11F_TLV_NOTICEOFABSENCE, + 0, 5, 41, 0, 1, 2, 0, }, + { offsetof(tDot11fIEP2PBeaconProbeRes, P2PDeviceInfo), + offsetof(tDot11fTLVP2PDeviceInfo, present), "P2PDeviceInfo", + SigTlvP2PDeviceInfo, DOT11F_TLV_P2PDEVICEINFO, 0, 19, 55, 0, 1, 2, 0, }, + { offsetof(tDot11fIEP2PBeaconProbeRes, P2PGroupInfo), + offsetof(tDot11fTLVP2PGroupInfo, present), "P2PGroupInfo", + SigTlvP2PGroupInfo, DOT11F_TLV_P2PGROUPINFO, 0, 3, 1027, 0, 1, 2, 0, }, + {0, 0, NULL, 0, 0xffff, 0, 0, 0, 0, 0, 0}, +}; + +uint32_t dot11f_unpack_ie_p2_p_beacon_probe_res(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEP2PBeaconProbeRes *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pBuf; (void)ielen; /* Shutup the compiler */ + pDst->present = 1; + status = unpack_tlv_core(pCtx, pBuf, ielen, + TLVS_P2PBeaconProbeRes, + (uint8_t *)pDst, sizeof(*pDst)); + return status; +} /* End dot11f_unpack_ie_p2_p_beacon_probe_res. */ + +#define SigIeP2PBeaconProbeRes (0x0048) + + +static const tTLVDefn TLVS_P2PDeAuth[] = { + { offsetof(tDot11fIEP2PDeAuth, MinorReasonCode), + offsetof(tDot11fTLVMinorReasonCode, present), "MinorReasonCode", + SigTlvMinorReasonCode, DOT11F_TLV_MINORREASONCODE, + 0, 4, 4, 1, 1, 2, 0, }, + {0, 0, NULL, 0, 0xffff, 0, 0, 0, 0, 0, 0}, +}; + +uint32_t dot11f_unpack_ie_p2_p_de_auth(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEP2PDeAuth *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pBuf; (void)ielen; /* Shutup the compiler */ + pDst->present = 1; + status = unpack_tlv_core(pCtx, pBuf, ielen, + TLVS_P2PDeAuth, + (uint8_t *)pDst, sizeof(*pDst)); + return status; +} /* End dot11f_unpack_ie_p2_p_de_auth. */ + +#define SigIeP2PDeAuth (0x0049) + + +static const tTLVDefn TLVS_P2PDisAssoc[] = { + { offsetof(tDot11fIEP2PDisAssoc, MinorReasonCode), + offsetof(tDot11fTLVMinorReasonCode, present), "MinorReasonCode", + SigTlvMinorReasonCode, DOT11F_TLV_MINORREASONCODE, + 0, 4, 4, 1, 1, 2, 0, }, + {0, 0, NULL, 0, 0xffff, 0, 0, 0, 0, 0, 0}, +}; + +uint32_t dot11f_unpack_ie_p2_p_dis_assoc(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEP2PDisAssoc *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pBuf; (void)ielen; /* Shutup the compiler */ + pDst->present = 1; + status = unpack_tlv_core(pCtx, pBuf, ielen, + TLVS_P2PDisAssoc, + (uint8_t *)pDst, sizeof(*pDst)); + return status; +} /* End dot11f_unpack_ie_p2_p_dis_assoc. */ + +#define SigIeP2PDisAssoc (0x004a) + + +uint32_t dot11f_unpack_ie_p2_pie_opaque(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEP2PIEOpaque *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->num_data = (uint8_t)(ielen); + if (ielen > 249) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->data, pBuf, (ielen)); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_p2_pie_opaque. */ + +#define SigIeP2PIEOpaque (0x004b) + + +static const tTLVDefn TLVS_P2PProbeReq[] = { + { offsetof(tDot11fIEP2PProbeReq, P2PCapability), + offsetof(tDot11fTLVP2PCapability, present), "P2PCapability", + SigTlvP2PCapability, DOT11F_TLV_P2PCAPABILITY, 0, 5, 5, 1, 1, 2, 0, }, + { offsetof(tDot11fIEP2PProbeReq, P2PDeviceId), + offsetof(tDot11fTLVP2PDeviceId, present), "P2PDeviceId", + SigTlvP2PDeviceId, DOT11F_TLV_P2PDEVICEID, 0, 9, 9, 0, 1, 2, 0, }, + { offsetof(tDot11fIEP2PProbeReq, ListenChannel), + offsetof(tDot11fTLVListenChannel, present), "ListenChannel", + SigTlvListenChannel, DOT11F_TLV_LISTENCHANNEL, 0, 8, 8, 1, 1, 2, 0, }, + { offsetof(tDot11fIEP2PProbeReq, ExtendedListenTiming), + offsetof(tDot11fTLVExtendedListenTiming, present), + "ExtendedListenTiming", SigTlvExtendedListenTiming, + DOT11F_TLV_EXTENDEDLISTENTIMING, 0, 7, 7, 0, 1, 2, 0, }, + { offsetof(tDot11fIEP2PProbeReq, OperatingChannel), + offsetof(tDot11fTLVOperatingChannel, present), "OperatingChannel", + SigTlvOperatingChannel, DOT11F_TLV_OPERATINGCHANNEL, + 0, 8, 8, 0, 1, 2, 0, }, + {0, 0, NULL, 0, 0xffff, 0, 0, 0, 0, 0, 0}, +}; + +uint32_t dot11f_unpack_ie_p2_p_probe_req(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEP2PProbeReq *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pBuf; (void)ielen; /* Shutup the compiler */ + pDst->present = 1; + status = unpack_tlv_core(pCtx, pBuf, ielen, + TLVS_P2PProbeReq, + (uint8_t *)pDst, sizeof(*pDst)); + return status; +} /* End dot11f_unpack_ie_p2_p_probe_req. */ + +#define SigIeP2PProbeReq (0x004c) + + +static const tTLVDefn TLVS_P2PProbeRes[] = { + { offsetof(tDot11fIEP2PProbeRes, P2PCapability), + offsetof(tDot11fTLVP2PCapability, present), "P2PCapability", + SigTlvP2PCapability, DOT11F_TLV_P2PCAPABILITY, 0, 5, 5, 1, 1, 2, 0, }, + { offsetof(tDot11fIEP2PProbeRes, ExtendedListenTiming), + offsetof(tDot11fTLVExtendedListenTiming, present), + "ExtendedListenTiming", SigTlvExtendedListenTiming, + DOT11F_TLV_EXTENDEDLISTENTIMING, 0, 7, 7, 0, 1, 2, 0, }, + { offsetof(tDot11fIEP2PProbeRes, NoticeOfAbsence), + offsetof(tDot11fTLVNoticeOfAbsence, present), "NoticeOfAbsence", + SigTlvNoticeOfAbsence, DOT11F_TLV_NOTICEOFABSENCE, + 0, 5, 41, 0, 1, 2, 0, }, + { offsetof(tDot11fIEP2PProbeRes, P2PDeviceInfo), + offsetof(tDot11fTLVP2PDeviceInfo, present), "P2PDeviceInfo", + SigTlvP2PDeviceInfo, DOT11F_TLV_P2PDEVICEINFO, 0, 19, 55, 1, 1, 2, 0, }, + { offsetof(tDot11fIEP2PProbeRes, P2PGroupInfo), + offsetof(tDot11fTLVP2PGroupInfo, present), "P2PGroupInfo", + SigTlvP2PGroupInfo, DOT11F_TLV_P2PGROUPINFO, 0, 3, 1027, 0, 1, 2, 0, }, + {0, 0, NULL, 0, 0xffff, 0, 0, 0, 0, 0, 0}, +}; + +uint32_t dot11f_unpack_ie_p2_p_probe_res(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEP2PProbeRes *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pBuf; (void)ielen; /* Shutup the compiler */ + pDst->present = 1; + status = unpack_tlv_core(pCtx, pBuf, ielen, + TLVS_P2PProbeRes, + (uint8_t *)pDst, sizeof(*pDst)); + return status; +} /* End dot11f_unpack_ie_p2_p_probe_res. */ + +#define SigIeP2PProbeRes (0x004d) + + +uint32_t dot11f_unpack_ie_pti_control(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEPTIControl *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->tid = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + framesntohs(pCtx, &pDst->sequence_control, pBuf, 0); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_pti_control. */ + +#define SigIePTIControl (0x004e) + + +uint32_t dot11f_unpack_ie_pu_buffer_status(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEPUBufferStatus *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + uint8_t tmp53__; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + tmp53__ = *pBuf; + pDst->ac_bk_traffic_aval = tmp53__ >> 0 & 0x1; + pDst->ac_be_traffic_aval = tmp53__ >> 1 & 0x1; + pDst->ac_vi_traffic_aval = tmp53__ >> 2 & 0x1; + pDst->ac_vo_traffic_aval = tmp53__ >> 3 & 0x1; + pDst->reserved = tmp53__ >> 4 & 0xf; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_pu_buffer_status. */ + +#define SigIePUBufferStatus (0x004f) + + +uint32_t dot11f_unpack_ie_power_caps(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEPowerCaps *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->minTxPower = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->maxTxPower = *pBuf; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_power_caps. */ + +#define SigIePowerCaps (0x0050) + + +uint32_t dot11f_unpack_ie_power_constraints(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEPowerConstraints *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->localPowerConstraints = *pBuf; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_power_constraints. */ + +#define SigIePowerConstraints (0x0051) + + +uint32_t dot11f_unpack_ie_qbss_load(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEQBSSLoad *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + framesntohs(pCtx, &pDst->stacount, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + pDst->chautil = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + framesntohs(pCtx, &pDst->avail, pBuf, 0); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_qbss_load. */ + +#define SigIeQBSSLoad (0x0052) + + +uint32_t dot11f_unpack_ie_QCN_IE(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEQCN_IE *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + DOT11F_MEMCPY(pCtx, pDst->version, pBuf, 4); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_QCN_IE. */ + +#define SigIeQCN_IE (0x0053) + + +uint32_t dot11f_unpack_ie_QComVendorIE(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEQComVendorIE *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->type = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->channel = *pBuf; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_QComVendorIE. */ + +#define SigIeQComVendorIE (0x0054) + + +uint32_t dot11f_unpack_ie_qos_caps_ap(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEQOSCapsAp *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + uint8_t tmp54__; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + tmp54__ = *pBuf; + pDst->count = tmp54__ >> 0 & 0xf; + pDst->qack = tmp54__ >> 4 & 0x1; + pDst->qreq = tmp54__ >> 5 & 0x1; + pDst->txopreq = tmp54__ >> 6 & 0x1; + pDst->reserved = tmp54__ >> 7 & 0x1; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_qos_caps_ap. */ + +#define SigIeQOSCapsAp (0x0055) + + +uint32_t dot11f_unpack_ie_qos_caps_station(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEQOSCapsStation *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + uint8_t tmp55__; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + tmp55__ = *pBuf; + pDst->acvo_uapsd = tmp55__ >> 0 & 0x1; + pDst->acvi_uapsd = tmp55__ >> 1 & 0x1; + pDst->acbk_uapsd = tmp55__ >> 2 & 0x1; + pDst->acbe_uapsd = tmp55__ >> 3 & 0x1; + pDst->qack = tmp55__ >> 4 & 0x1; + pDst->max_sp_length = tmp55__ >> 5 & 0x3; + pDst->more_data_ack = tmp55__ >> 7 & 0x1; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_qos_caps_station. */ + +#define SigIeQOSCapsStation (0x0056) + + +uint32_t dot11f_unpack_ie_qos_map_set(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEQosMapSet *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->num_dscp_exceptions = (uint8_t)(ielen); + if (ielen > 60) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->dscp_exceptions, pBuf, (ielen)); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_qos_map_set. */ + +#define SigIeQosMapSet (0x0057) + + +uint32_t dot11f_unpack_ie_quiet(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEQuiet *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->count = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->period = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + framesntohs(pCtx, &pDst->duration, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + framesntohs(pCtx, &pDst->offset, pBuf, 0); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_quiet. */ + +#define SigIeQuiet (0x0058) + + +uint32_t dot11f_unpack_ie_rcpiie(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIERCPIIE *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->rcpi = *pBuf; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_rcpiie. */ + +#define SigIeRCPIIE (0x0059) + + +static const tFFDefn FFS_RICDataDesc[] = { + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_RICDataDesc[] = { + { offsetof(tDot11fIERICDataDesc, RICData), offsetof(tDot11fIERICData, + present), 0, "RICData", 0, 6, 6, SigIeRICData, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_RICDATA, 1, }, + { offsetof(tDot11fIERICDataDesc, RICDescriptor), + offsetof(tDot11fIERICDescriptor, present), 0, "RICDescriptor", + 0, 3, 258, SigIeRICDescriptor, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_RICDESCRIPTOR, 0, }, + { offsetof(tDot11fIERICDataDesc, TSPEC), offsetof(tDot11fIETSPEC, + present), 0, "TSPEC", 0, 57, 57, SigIeTSPEC, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_TSPEC, 0, }, + { offsetof(tDot11fIERICDataDesc, TCLAS), offsetof(tDot11fIETCLAS, + present), offsetof(tDot11fIERICDataDesc, num_TCLAS), "TCLAS", + 2, 7, 45, SigIeTCLAS, {0, 0, 0, 0, 0}, 0, DOT11F_EID_TCLAS, 0, }, + { offsetof(tDot11fIERICDataDesc, TCLASSPROC), + offsetof(tDot11fIETCLASSPROC, present), 0, "TCLASSPROC", + 0, 3, 3, SigIeTCLASSPROC, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_TCLASSPROC, 0, }, + { offsetof(tDot11fIERICDataDesc, TSDelay), offsetof(tDot11fIETSDelay, + present), 0, "TSDelay", 0, 6, 6, SigIeTSDelay, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_TSDELAY, 0, }, + { offsetof(tDot11fIERICDataDesc, Schedule), offsetof(tDot11fIESchedule, + present), 0, "Schedule", 0, 16, 16, SigIeSchedule, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_SCHEDULE, 0, }, + { offsetof(tDot11fIERICDataDesc, WMMTSPEC), offsetof(tDot11fIEWMMTSPEC, + present), 0, "WMMTSPEC", 0, 63, 63, SigIeWMMTSPEC, {0, 80, 242, 2, 2}, + 5, DOT11F_EID_WMMTSPEC, 0, }, + { offsetof(tDot11fIERICDataDesc, WMMTCLAS), offsetof(tDot11fIEWMMTCLAS, + present), offsetof(tDot11fIERICDataDesc, num_WMMTCLAS), "WMMTCLAS", + 2, 13, 51, SigIeWMMTCLAS, {0, 80, 242, 2, 6}, + 5, DOT11F_EID_WMMTCLAS, 0, }, + { offsetof(tDot11fIERICDataDesc, WMMTCLASPROC), + offsetof(tDot11fIEWMMTCLASPROC, present), 0, "WMMTCLASPROC", + 0, 9, 9, SigIeWMMTCLASPROC, {0, 80, 242, 2, 7}, + 5, DOT11F_EID_WMMTCLASPROC, 0, }, + { offsetof(tDot11fIERICDataDesc, WMMTSDelay), + offsetof(tDot11fIEWMMTSDelay, present), 0, "WMMTSDelay", + 0, 12, 12, SigIeWMMTSDelay, {0, 80, 242, 2, 8}, + 5, DOT11F_EID_WMMTSDELAY, 0, }, + { offsetof(tDot11fIERICDataDesc, WMMSchedule), + offsetof(tDot11fIEWMMSchedule, present), 0, "WMMSchedule", + 0, 22, 22, SigIeWMMSchedule, {0, 80, 242, 2, 9}, + 5, DOT11F_EID_WMMSCHEDULE, 0, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, }, +}; + +uint32_t dot11f_unpack_ie_ric_data_desc(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIERICDataDesc *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + (void)pCtx; + status |= unpack_core(pCtx, + pBuf, + ielen, + FFS_RICDataDesc, + IES_RICDataDesc, + (uint8_t *)pDst, + sizeof(*pDst)); + return status; +} /* End dot11f_unpack_ie_ric_data_desc. */ + +#define SigIeRICDataDesc (0x005a) + + +uint32_t dot11f_unpack_ie_rsn(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIERSN *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + framesntohs(pCtx, &pDst->version, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + if (pDst->version != 0x1) { + pDst->present = 0; + return status | DOT11F_BAD_FIXED_VALUE; + } + DOT11F_MEMCPY(pCtx, pDst->gp_cipher_suite, pBuf, 4); + pBuf += 4; + ielen -= (uint8_t)4; + if (!ielen) { + pDst->pwise_cipher_suite_count = 0U; + pDst->akm_suite_count = 0U; + pDst->pmkid_count = 0U; + return 0U; + } else { + framesntohs(pCtx, &pDst->pwise_cipher_suite_count, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + } + if (pDst->pwise_cipher_suite_count > 4) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->pwise_cipher_suites, pBuf, (pDst->pwise_cipher_suite_count * 4)); + pBuf += (pDst->pwise_cipher_suite_count * 4); + ielen -= (pDst->pwise_cipher_suite_count * 4); + if (!ielen) { + pDst->akm_suite_count = 0U; + pDst->pmkid_count = 0U; + return 0U; + } else { + framesntohs(pCtx, &pDst->akm_suite_count, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + } + if (pDst->akm_suite_count > 4) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->akm_suites, pBuf, (pDst->akm_suite_count * 4)); + pBuf += (pDst->akm_suite_count * 4); + ielen -= (pDst->akm_suite_count * 4); + if (!ielen) { + pDst->pmkid_count = 0U; + return 0U; + } else { + DOT11F_MEMCPY(pCtx, pDst->RSN_Cap, pBuf, 2); + pBuf += 2; + ielen -= (uint8_t)2; + } + if (!ielen) { + pDst->pmkid_count = 0U; + return 0U; + } else { + framesntohs(pCtx, &pDst->pmkid_count, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + } + if (pDst->pmkid_count > 4) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->pmkid, pBuf, (pDst->pmkid_count * 16)); + pBuf += (pDst->pmkid_count * 16); + ielen -= (pDst->pmkid_count * 16); + if (!ielen) { + return 0U; + } else { + DOT11F_MEMCPY(pCtx, pDst->gp_mgmt_cipher_suite, pBuf, 4); + } + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_rsn. */ + +#define SigIeRSN (0x005b) + + +uint32_t dot11f_unpack_ie_rsniie(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIERSNIIE *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->rsni = *pBuf; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_rsniie. */ + +#define SigIeRSNIIE (0x005c) + + +uint32_t dot11f_unpack_ie_rsn_opaque(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIERSNOpaque *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->num_data = (uint8_t)(ielen); + if (ielen > 253) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->data, pBuf, (ielen)); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_rsn_opaque. */ + +#define SigIeRSNOpaque (0x005d) + + +uint32_t dot11f_unpack_ie_supp_channels(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIESuppChannels *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->num_bands = (uint8_t)(ielen / 2); + if (ielen > 48 * 2) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->bands, pBuf, (ielen)); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_supp_channels. */ + +#define SigIeSuppChannels (0x005e) + + +uint32_t dot11f_unpack_ie_supp_operating_classes(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIESuppOperatingClasses *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->num_classes = (uint8_t)(ielen); + if (ielen > 32) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->classes, pBuf, (ielen)); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_supp_operating_classes. */ + +#define SigIeSuppOperatingClasses (0x005f) + + +uint32_t dot11f_unpack_ie_supp_rates(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIESuppRates *pDst) +{ + uint8_t i; + uint8_t rate_indx = 0; + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + for (i = 0; i < ielen; i++) { + if ((DOT11F_IS_BG_RATE(pBuf[i] & 0x7F)) && + (rate_indx < 12)) { + pDst->rates[rate_indx++] = pBuf[i]; + } + } + + if (rate_indx == 0) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + pDst->num_rates = rate_indx; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_supp_rates. */ + +#define SigIeSuppRates (0x0060) + + +uint32_t dot11f_unpack_ie_tim(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIETIM *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->dtim_count = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->dtim_period = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->bmpctl = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->num_vbmp = (uint8_t)(ielen); + if (ielen > 251) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->vbmp, pBuf, (ielen)); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_tim. */ + +#define SigIeTIM (0x0061) + + +uint32_t dot11f_unpack_ie_tpc_report(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIETPCReport *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->tx_power = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->link_margin = *pBuf; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_tpc_report. */ + +#define SigIeTPCReport (0x0062) + + +uint32_t dot11f_unpack_ie_tpc_request(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIETPCRequest *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_tpc_request. */ + +#define SigIeTPCRequest (0x0063) + + +uint32_t dot11f_unpack_ie_time_advertisement(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIETimeAdvertisement *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->timing_capabilities = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + DOT11F_MEMCPY(pCtx, pDst->time_value, pBuf, 10); + pBuf += 10; + ielen -= (uint8_t)10; + DOT11F_MEMCPY(pCtx, pDst->time_error, pBuf, 5); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_time_advertisement. */ + +#define SigIeTimeAdvertisement (0x0064) + + +uint32_t dot11f_unpack_ie_timeout_interval(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIETimeoutInterval *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->timeoutType = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + framesntohl(pCtx, &pDst->timeoutValue, pBuf, 0); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_timeout_interval. */ + +#define SigIeTimeoutInterval (0x0065) + + +uint32_t dot11f_unpack_ie_vht_ext_bss_load(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEVHTExtBssLoad *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->muMIMOCapStaCount = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->ssUnderUtil = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->FortyMHzUtil = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->EightyMHzUtil = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->OneSixtyMHzUtil = *pBuf; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_vht_ext_bss_load. */ + +#define SigIeVHTExtBssLoad (0x0066) + + +uint32_t dot11f_unpack_ie_vendor1_ie(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEVendor1IE *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_vendor1_ie. */ + +#define SigIeVendor1IE (0x0067) + + +uint32_t dot11f_unpack_ie_vendor3_ie(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEVendor3IE *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_vendor3_ie. */ + +#define SigIeVendor3IE (0x0068) + + +uint32_t dot11f_unpack_ie_wapi(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEWAPI *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + uint16_t tmp56__; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + framesntohs(pCtx, &pDst->version, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + if (pDst->version != 0x1) { + pDst->present = 0; + return status | DOT11F_BAD_FIXED_VALUE; + } + framesntohs(pCtx, &pDst->akm_suite_count, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + if (pDst->akm_suite_count > 4) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->akm_suites, pBuf, (pDst->akm_suite_count * 4)); + pBuf += (pDst->akm_suite_count * 4); + ielen -= (pDst->akm_suite_count * 4); + framesntohs(pCtx, &pDst->unicast_cipher_suite_count, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + if (pDst->unicast_cipher_suite_count > 4) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->unicast_cipher_suites, pBuf, (pDst->unicast_cipher_suite_count * 4)); + pBuf += (pDst->unicast_cipher_suite_count * 4); + ielen -= (pDst->unicast_cipher_suite_count * 4); + DOT11F_MEMCPY(pCtx, pDst->multicast_cipher_suite, pBuf, 4); + pBuf += 4; + ielen -= (uint8_t)4; + framesntohs(pCtx, &tmp56__, pBuf, 0); + pBuf += 2; + ielen -= 2; + pDst->preauth = tmp56__ >> 0 & 0x1; + pDst->reserved = tmp56__ >> 1 & 0x7fff; + if (!ielen) { + pDst->bkid_count = 0U; + return 0U; + } else { + framesntohs(pCtx, &pDst->bkid_count, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + } + if (pDst->bkid_count > 4) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->bkid, pBuf, (pDst->bkid_count * 16)); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_wapi. */ + +#define SigIeWAPI (0x0069) + + +uint32_t dot11f_unpack_ie_wapi_opaque(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEWAPIOpaque *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->num_data = (uint8_t)(ielen); + if (ielen > 253) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->data, pBuf, (ielen)); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_wapi_opaque. */ + +#define SigIeWAPIOpaque (0x006a) + + +uint32_t dot11f_unpack_ie_wfatpc(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEWFATPC *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->txPower = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->linkMargin = *pBuf; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_wfatpc. */ + +#define SigIeWFATPC (0x006b) + + +uint32_t dot11f_unpack_ie_wfdie_opaque(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEWFDIEOpaque *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->num_data = (uint8_t)(ielen); + if (ielen > 249) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->data, pBuf, (ielen)); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_wfdie_opaque. */ + +#define SigIeWFDIEOpaque (0x006c) + + +uint32_t dot11f_unpack_ie_wmm_caps(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEWMMCaps *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + uint8_t tmp57__; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->version = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (pDst->version != 0x1) { + pDst->present = 0; + return status | DOT11F_BAD_FIXED_VALUE; + } + tmp57__ = *pBuf; + pDst->reserved = tmp57__ >> 0 & 0xf; + pDst->qack = tmp57__ >> 4 & 0x1; + pDst->queue_request = tmp57__ >> 5 & 0x1; + pDst->txop_request = tmp57__ >> 6 & 0x1; + pDst->more_ack = tmp57__ >> 7 & 0x1; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_wmm_caps. */ + +#define SigIeWMMCaps (0x006d) + + +uint32_t dot11f_unpack_ie_wmm_info_ap(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEWMMInfoAp *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + uint8_t tmp58__; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->version = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + tmp58__ = *pBuf; + pDst->param_set_count = tmp58__ >> 0 & 0xf; + pDst->reserved = tmp58__ >> 4 & 0x7; + pDst->uapsd = tmp58__ >> 7 & 0x1; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_wmm_info_ap. */ + +#define SigIeWMMInfoAp (0x006e) + + +uint32_t dot11f_unpack_ie_wmm_info_station(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEWMMInfoStation *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + uint8_t tmp59__; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->version = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + tmp59__ = *pBuf; + pDst->acvo_uapsd = tmp59__ >> 0 & 0x1; + pDst->acvi_uapsd = tmp59__ >> 1 & 0x1; + pDst->acbk_uapsd = tmp59__ >> 2 & 0x1; + pDst->acbe_uapsd = tmp59__ >> 3 & 0x1; + pDst->reserved1 = tmp59__ >> 4 & 0x1; + pDst->max_sp_length = tmp59__ >> 5 & 0x3; + pDst->reserved2 = tmp59__ >> 7 & 0x1; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_wmm_info_station. */ + +#define SigIeWMMInfoStation (0x006f) + + +uint32_t dot11f_unpack_ie_wmm_params(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEWMMParams *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + uint8_t tmp60__; + uint8_t tmp61__; + uint8_t tmp62__; + uint8_t tmp63__; + uint8_t tmp64__; + uint8_t tmp65__; + uint8_t tmp66__; + uint8_t tmp67__; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->version = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (pDst->version != 0x1) { + pDst->present = 0; + return status | DOT11F_BAD_FIXED_VALUE; + } + pDst->qosInfo = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->reserved2 = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + tmp60__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->acbe_aifsn = tmp60__ >> 0 & 0xf; + pDst->acbe_acm = tmp60__ >> 4 & 0x1; + pDst->acbe_aci = tmp60__ >> 5 & 0x3; + pDst->unused1 = tmp60__ >> 7 & 0x1; + tmp61__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->acbe_acwmin = tmp61__ >> 0 & 0xf; + pDst->acbe_acwmax = tmp61__ >> 4 & 0xf; + framesntohs(pCtx, &pDst->acbe_txoplimit, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + tmp62__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->acbk_aifsn = tmp62__ >> 0 & 0xf; + pDst->acbk_acm = tmp62__ >> 4 & 0x1; + pDst->acbk_aci = tmp62__ >> 5 & 0x3; + pDst->unused2 = tmp62__ >> 7 & 0x1; + tmp63__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->acbk_acwmin = tmp63__ >> 0 & 0xf; + pDst->acbk_acwmax = tmp63__ >> 4 & 0xf; + framesntohs(pCtx, &pDst->acbk_txoplimit, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + tmp64__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->acvi_aifsn = tmp64__ >> 0 & 0xf; + pDst->acvi_acm = tmp64__ >> 4 & 0x1; + pDst->acvi_aci = tmp64__ >> 5 & 0x3; + pDst->unused3 = tmp64__ >> 7 & 0x1; + tmp65__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->acvi_acwmin = tmp65__ >> 0 & 0xf; + pDst->acvi_acwmax = tmp65__ >> 4 & 0xf; + framesntohs(pCtx, &pDst->acvi_txoplimit, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + tmp66__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->acvo_aifsn = tmp66__ >> 0 & 0xf; + pDst->acvo_acm = tmp66__ >> 4 & 0x1; + pDst->acvo_aci = tmp66__ >> 5 & 0x3; + pDst->unused4 = tmp66__ >> 7 & 0x1; + tmp67__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->acvo_acwmin = tmp67__ >> 0 & 0xf; + pDst->acvo_acwmax = tmp67__ >> 4 & 0xf; + framesntohs(pCtx, &pDst->acvo_txoplimit, pBuf, 0); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_wmm_params. */ + +#define SigIeWMMParams (0x0070) + + +uint32_t dot11f_unpack_ie_wpa(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEWPA *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + framesntohs(pCtx, &pDst->version, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + if (pDst->version != 0x1) { + pDst->present = 0; + return status | DOT11F_BAD_FIXED_VALUE; + } + if (!ielen) { + pDst->multicast_cipher_present = 0U; + pDst->unicast_cipher_count = 0U; + pDst->auth_suite_count = 0U; + return 0U; + } else { + pDst->multicast_cipher_present = 1U; + DOT11F_MEMCPY(pCtx, pDst->multicast_cipher, pBuf, 4); + pBuf += 4; + ielen -= (uint8_t)4; + } + if (!ielen) { + pDst->unicast_cipher_count = 0U; + pDst->auth_suite_count = 0U; + return 0U; + } else { + framesntohs(pCtx, &pDst->unicast_cipher_count, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + } + if (pDst->unicast_cipher_count > 4) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->unicast_ciphers, pBuf, (pDst->unicast_cipher_count * 4)); + pBuf += (pDst->unicast_cipher_count * 4); + ielen -= (pDst->unicast_cipher_count * 4); + if (!ielen) { + pDst->auth_suite_count = 0U; + return 0U; + } else { + framesntohs(pCtx, &pDst->auth_suite_count, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + } + if (pDst->auth_suite_count > 4) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->auth_suites, pBuf, (pDst->auth_suite_count * 4)); + pBuf += (pDst->auth_suite_count * 4); + ielen -= (pDst->auth_suite_count * 4); + if (!ielen) { + return 0U; + } else { + framesntohs(pCtx, &pDst->caps, pBuf, 0); + } + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_wpa. */ + +#define SigIeWPA (0x0071) + + +uint32_t dot11f_unpack_ie_wpa_opaque(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEWPAOpaque *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->num_data = (uint8_t)(ielen); + if (ielen > 249) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->data, pBuf, (ielen)); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_wpa_opaque. */ + +#define SigIeWPAOpaque (0x0072) + + +static const tTLVDefn TLVS_WSC[] = { + { offsetof(tDot11fIEWSC, Version), offsetof(tDot11fTLVVersion, present), + "Version", SigTlvVersion, DOT11F_TLV_VERSION, 0, 5, 5, 1, 2, 2, 1, }, + { offsetof(tDot11fIEWSC, WPSState), offsetof(tDot11fTLVWPSState, present), + "WPSState", SigTlvWPSState, DOT11F_TLV_WPSSTATE, 0, 5, 5, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWSC, APSetupLocked), + offsetof(tDot11fTLVAPSetupLocked, present), "APSetupLocked", + SigTlvAPSetupLocked, DOT11F_TLV_APSETUPLOCKED, 0, 5, 5, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWSC, SelectedRegistrarConfigMethods), + offsetof(tDot11fTLVSelectedRegistrarConfigMethods, present), + "SelectedRegistrarConfigMethods", SigTlvSelectedRegistrarConfigMethods, + DOT11F_TLV_SELECTEDREGISTRARCONFIGMETHODS, 0, 6, 6, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWSC, UUID_E), offsetof(tDot11fTLVUUID_E, present), + "UUID_E", SigTlvUUID_E, DOT11F_TLV_UUID_E, 0, 20, 20, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWSC, UUID_R), offsetof(tDot11fTLVUUID_R, present), + "UUID_R", SigTlvUUID_R, DOT11F_TLV_UUID_R, 0, 20, 20, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWSC, RFBands), offsetof(tDot11fTLVRFBands, present), + "RFBands", SigTlvRFBands, DOT11F_TLV_RFBANDS, 0, 5, 5, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWSC, SelectedRegistrar), + offsetof(tDot11fTLVSelectedRegistrar, present), "SelectedRegistrar", + SigTlvSelectedRegistrar, DOT11F_TLV_SELECTEDREGISTRAR, + 0, 5, 5, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWSC, ConfigMethods), + offsetof(tDot11fTLVConfigMethods, present), "ConfigMethods", + SigTlvConfigMethods, DOT11F_TLV_CONFIGMETHODS, 0, 6, 6, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWSC, AssociationState), + offsetof(tDot11fTLVAssociationState, present), "AssociationState", + SigTlvAssociationState, DOT11F_TLV_ASSOCIATIONSTATE, + 0, 6, 6, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWSC, ConfigurationError), + offsetof(tDot11fTLVConfigurationError, present), "ConfigurationError", + SigTlvConfigurationError, DOT11F_TLV_CONFIGURATIONERROR, + 0, 6, 6, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWSC, Manufacturer), offsetof(tDot11fTLVManufacturer, + present), "Manufacturer", SigTlvManufacturer, DOT11F_TLV_MANUFACTURER, + 0, 4, 68, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWSC, ModelName), offsetof(tDot11fTLVModelName, + present), "ModelName", SigTlvModelName, DOT11F_TLV_MODELNAME, + 0, 4, 36, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWSC, ModelNumber), offsetof(tDot11fTLVModelNumber, + present), "ModelNumber", SigTlvModelNumber, DOT11F_TLV_MODELNUMBER, + 0, 4, 36, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWSC, SerialNumber), offsetof(tDot11fTLVSerialNumber, + present), "SerialNumber", SigTlvSerialNumber, DOT11F_TLV_SERIALNUMBER, + 0, 4, 36, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWSC, DeviceName), offsetof(tDot11fTLVDeviceName, + present), "DeviceName", SigTlvDeviceName, DOT11F_TLV_DEVICENAME, + 0, 4, 36, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWSC, DevicePasswordID), + offsetof(tDot11fTLVDevicePasswordID, present), "DevicePasswordID", + SigTlvDevicePasswordID, DOT11F_TLV_DEVICEPASSWORDID, + 0, 6, 6, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWSC, PrimaryDeviceType), + offsetof(tDot11fTLVPrimaryDeviceType, present), "PrimaryDeviceType", + SigTlvPrimaryDeviceType, DOT11F_TLV_PRIMARYDEVICETYPE, + 0, 12, 12, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWSC, RequestType), offsetof(tDot11fTLVRequestType, + present), "RequestType", SigTlvRequestType, DOT11F_TLV_REQUESTTYPE, + 0, 5, 5, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWSC, ResponseType), offsetof(tDot11fTLVResponseType, + present), "ResponseType", SigTlvResponseType, DOT11F_TLV_RESPONSETYPE, + 0, 5, 5, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWSC, VendorExtension), + offsetof(tDot11fTLVVendorExtension, present), "VendorExtension", + SigTlvVendorExtension, DOT11F_TLV_VENDOREXTENSION, + 0, 7, 21, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWSC, RequestDeviceType), + offsetof(tDot11fTLVRequestDeviceType, present), "RequestDeviceType", + SigTlvRequestDeviceType, DOT11F_TLV_REQUESTDEVICETYPE, + 0, 12, 12, 0, 2, 2, 1, }, + {0, 0, NULL, 0, 0xffff, 0, 0, 0, 0, 0, 0}, +}; + +uint32_t dot11f_unpack_ie_wsc(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEWSC *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pBuf; (void)ielen; /* Shutup the compiler */ + pDst->present = 1; + status = unpack_tlv_core(pCtx, pBuf, ielen, + TLVS_WSC, + (uint8_t *)pDst, sizeof(*pDst)); + return status; +} /* End dot11f_unpack_ie_wsc. */ + +#define SigIeWSC (0x0073) + + +static const tTLVDefn TLVS_WscAssocReq[] = { + { offsetof(tDot11fIEWscAssocReq, Version), offsetof(tDot11fTLVVersion, + present), "Version", SigTlvVersion, DOT11F_TLV_VERSION, + 0, 5, 5, 1, 2, 2, 1, }, + { offsetof(tDot11fIEWscAssocReq, RequestType), + offsetof(tDot11fTLVRequestType, present), "RequestType", + SigTlvRequestType, DOT11F_TLV_REQUESTTYPE, 0, 5, 5, 1, 2, 2, 1, }, + { offsetof(tDot11fIEWscAssocReq, VendorExtension), + offsetof(tDot11fTLVVendorExtension, present), "VendorExtension", + SigTlvVendorExtension, DOT11F_TLV_VENDOREXTENSION, + 0, 7, 21, 0, 2, 2, 1, }, + {0, 0, NULL, 0, 0xffff, 0, 0, 0, 0, 0, 0}, +}; + +uint32_t dot11f_unpack_ie_wsc_assoc_req(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEWscAssocReq *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pBuf; (void)ielen; /* Shutup the compiler */ + pDst->present = 1; + status = unpack_tlv_core(pCtx, pBuf, ielen, + TLVS_WscAssocReq, + (uint8_t *)pDst, sizeof(*pDst)); + return status; +} /* End dot11f_unpack_ie_wsc_assoc_req. */ + +#define SigIeWscAssocReq (0x0074) + + +static const tTLVDefn TLVS_WscAssocRes[] = { + { offsetof(tDot11fIEWscAssocRes, Version), offsetof(tDot11fTLVVersion, + present), "Version", SigTlvVersion, DOT11F_TLV_VERSION, + 0, 5, 5, 1, 2, 2, 1, }, + { offsetof(tDot11fIEWscAssocRes, ResponseType), + offsetof(tDot11fTLVResponseType, present), "ResponseType", + SigTlvResponseType, DOT11F_TLV_RESPONSETYPE, 0, 5, 5, 1, 2, 2, 1, }, + { offsetof(tDot11fIEWscAssocRes, VendorExtension), + offsetof(tDot11fTLVVendorExtension, present), "VendorExtension", + SigTlvVendorExtension, DOT11F_TLV_VENDOREXTENSION, + 0, 7, 21, 0, 2, 2, 1, }, + {0, 0, NULL, 0, 0xffff, 0, 0, 0, 0, 0, 0}, +}; + +uint32_t dot11f_unpack_ie_wsc_assoc_res(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEWscAssocRes *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pBuf; (void)ielen; /* Shutup the compiler */ + pDst->present = 1; + status = unpack_tlv_core(pCtx, pBuf, ielen, + TLVS_WscAssocRes, + (uint8_t *)pDst, sizeof(*pDst)); + return status; +} /* End dot11f_unpack_ie_wsc_assoc_res. */ + +#define SigIeWscAssocRes (0x0075) + + +static const tTLVDefn TLVS_WscBeacon[] = { + { offsetof(tDot11fIEWscBeacon, Version), offsetof(tDot11fTLVVersion, + present), "Version", SigTlvVersion, DOT11F_TLV_VERSION, + 0, 5, 5, 1, 2, 2, 1, }, + { offsetof(tDot11fIEWscBeacon, WPSState), offsetof(tDot11fTLVWPSState, + present), "WPSState", SigTlvWPSState, DOT11F_TLV_WPSSTATE, + 0, 5, 5, 1, 2, 2, 1, }, + { offsetof(tDot11fIEWscBeacon, APSetupLocked), + offsetof(tDot11fTLVAPSetupLocked, present), "APSetupLocked", + SigTlvAPSetupLocked, DOT11F_TLV_APSETUPLOCKED, 0, 5, 5, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWscBeacon, SelectedRegistrar), + offsetof(tDot11fTLVSelectedRegistrar, present), "SelectedRegistrar", + SigTlvSelectedRegistrar, DOT11F_TLV_SELECTEDREGISTRAR, + 0, 5, 5, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWscBeacon, DevicePasswordID), + offsetof(tDot11fTLVDevicePasswordID, present), "DevicePasswordID", + SigTlvDevicePasswordID, DOT11F_TLV_DEVICEPASSWORDID, + 0, 6, 6, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWscBeacon, SelectedRegistrarConfigMethods), + offsetof(tDot11fTLVSelectedRegistrarConfigMethods, present), + "SelectedRegistrarConfigMethods", SigTlvSelectedRegistrarConfigMethods, + DOT11F_TLV_SELECTEDREGISTRARCONFIGMETHODS, 0, 6, 6, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWscBeacon, UUID_E), offsetof(tDot11fTLVUUID_E, + present), "UUID_E", SigTlvUUID_E, DOT11F_TLV_UUID_E, + 0, 20, 20, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWscBeacon, RFBands), offsetof(tDot11fTLVRFBands, + present), "RFBands", SigTlvRFBands, DOT11F_TLV_RFBANDS, + 0, 5, 5, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWscBeacon, VendorExtension), + offsetof(tDot11fTLVVendorExtension, present), "VendorExtension", + SigTlvVendorExtension, DOT11F_TLV_VENDOREXTENSION, + 0, 7, 21, 0, 2, 2, 1, }, + {0, 0, NULL, 0, 0xffff, 0, 0, 0, 0, 0, 0}, +}; + +uint32_t dot11f_unpack_ie_wsc_beacon(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEWscBeacon *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pBuf; (void)ielen; /* Shutup the compiler */ + pDst->present = 1; + status = unpack_tlv_core(pCtx, pBuf, ielen, + TLVS_WscBeacon, + (uint8_t *)pDst, sizeof(*pDst)); + return status; +} /* End dot11f_unpack_ie_wsc_beacon. */ + +#define SigIeWscBeacon (0x0076) + + +static const tTLVDefn TLVS_WscBeaconProbeRes[] = { + { offsetof(tDot11fIEWscBeaconProbeRes, Version), + offsetof(tDot11fTLVVersion, present), "Version", SigTlvVersion, + DOT11F_TLV_VERSION, 0, 5, 5, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWscBeaconProbeRes, WPSState), + offsetof(tDot11fTLVWPSState, present), "WPSState", SigTlvWPSState, + DOT11F_TLV_WPSSTATE, 0, 5, 5, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWscBeaconProbeRes, APSetupLocked), + offsetof(tDot11fTLVAPSetupLocked, present), "APSetupLocked", + SigTlvAPSetupLocked, DOT11F_TLV_APSETUPLOCKED, 0, 5, 5, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWscBeaconProbeRes, SelectedRegistrar), + offsetof(tDot11fTLVSelectedRegistrar, present), "SelectedRegistrar", + SigTlvSelectedRegistrar, DOT11F_TLV_SELECTEDREGISTRAR, + 0, 5, 5, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWscBeaconProbeRes, DevicePasswordID), + offsetof(tDot11fTLVDevicePasswordID, present), "DevicePasswordID", + SigTlvDevicePasswordID, DOT11F_TLV_DEVICEPASSWORDID, + 0, 6, 6, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWscBeaconProbeRes, SelectedRegistrarConfigMethods), + offsetof(tDot11fTLVSelectedRegistrarConfigMethods, present), + "SelectedRegistrarConfigMethods", SigTlvSelectedRegistrarConfigMethods, + DOT11F_TLV_SELECTEDREGISTRARCONFIGMETHODS, 0, 6, 6, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWscBeaconProbeRes, ResponseType), + offsetof(tDot11fTLVResponseType, present), "ResponseType", + SigTlvResponseType, DOT11F_TLV_RESPONSETYPE, 0, 5, 5, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWscBeaconProbeRes, UUID_E), + offsetof(tDot11fTLVUUID_E, present), "UUID_E", SigTlvUUID_E, + DOT11F_TLV_UUID_E, 0, 20, 20, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWscBeaconProbeRes, Manufacturer), + offsetof(tDot11fTLVManufacturer, present), "Manufacturer", + SigTlvManufacturer, DOT11F_TLV_MANUFACTURER, 0, 4, 68, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWscBeaconProbeRes, ModelName), + offsetof(tDot11fTLVModelName, present), "ModelName", SigTlvModelName, + DOT11F_TLV_MODELNAME, 0, 4, 36, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWscBeaconProbeRes, ModelNumber), + offsetof(tDot11fTLVModelNumber, present), "ModelNumber", + SigTlvModelNumber, DOT11F_TLV_MODELNUMBER, 0, 4, 36, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWscBeaconProbeRes, SerialNumber), + offsetof(tDot11fTLVSerialNumber, present), "SerialNumber", + SigTlvSerialNumber, DOT11F_TLV_SERIALNUMBER, 0, 4, 36, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWscBeaconProbeRes, PrimaryDeviceType), + offsetof(tDot11fTLVPrimaryDeviceType, present), "PrimaryDeviceType", + SigTlvPrimaryDeviceType, DOT11F_TLV_PRIMARYDEVICETYPE, + 0, 12, 12, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWscBeaconProbeRes, DeviceName), + offsetof(tDot11fTLVDeviceName, present), "DeviceName", SigTlvDeviceName, + DOT11F_TLV_DEVICENAME, 0, 4, 36, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWscBeaconProbeRes, ConfigMethods), + offsetof(tDot11fTLVConfigMethods, present), "ConfigMethods", + SigTlvConfigMethods, DOT11F_TLV_CONFIGMETHODS, 0, 6, 6, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWscBeaconProbeRes, RFBands), + offsetof(tDot11fTLVRFBands, present), "RFBands", SigTlvRFBands, + DOT11F_TLV_RFBANDS, 0, 5, 5, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWscBeaconProbeRes, VendorExtension), + offsetof(tDot11fTLVVendorExtension, present), "VendorExtension", + SigTlvVendorExtension, DOT11F_TLV_VENDOREXTENSION, + 0, 7, 21, 0, 2, 2, 1, }, + {0, 0, NULL, 0, 0xffff, 0, 0, 0, 0, 0, 0}, +}; + +uint32_t dot11f_unpack_ie_wsc_beacon_probe_res(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEWscBeaconProbeRes *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pBuf; (void)ielen; /* Shutup the compiler */ + pDst->present = 1; + status = unpack_tlv_core(pCtx, pBuf, ielen, + TLVS_WscBeaconProbeRes, + (uint8_t *)pDst, sizeof(*pDst)); + return status; +} /* End dot11f_unpack_ie_wsc_beacon_probe_res. */ + +#define SigIeWscBeaconProbeRes (0x0077) + + +uint32_t dot11f_unpack_ie_wsc_ie_opaque(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEWscIEOpaque *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->num_data = (uint8_t)(ielen); + if (ielen > 249) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->data, pBuf, (ielen)); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_wsc_ie_opaque. */ + +#define SigIeWscIEOpaque (0x0078) + + +static const tTLVDefn TLVS_WscProbeReq[] = { + { offsetof(tDot11fIEWscProbeReq, Version), offsetof(tDot11fTLVVersion, + present), "Version", SigTlvVersion, DOT11F_TLV_VERSION, + 0, 5, 5, 1, 2, 2, 1, }, + { offsetof(tDot11fIEWscProbeReq, RequestType), + offsetof(tDot11fTLVRequestType, present), "RequestType", + SigTlvRequestType, DOT11F_TLV_REQUESTTYPE, 0, 5, 5, 1, 2, 2, 1, }, + { offsetof(tDot11fIEWscProbeReq, ConfigMethods), + offsetof(tDot11fTLVConfigMethods, present), "ConfigMethods", + SigTlvConfigMethods, DOT11F_TLV_CONFIGMETHODS, 0, 6, 6, 1, 2, 2, 1, }, + { offsetof(tDot11fIEWscProbeReq, UUID_E), offsetof(tDot11fTLVUUID_E, + present), "UUID_E", SigTlvUUID_E, DOT11F_TLV_UUID_E, + 0, 20, 20, 1, 2, 2, 1, }, + { offsetof(tDot11fIEWscProbeReq, PrimaryDeviceType), + offsetof(tDot11fTLVPrimaryDeviceType, present), "PrimaryDeviceType", + SigTlvPrimaryDeviceType, DOT11F_TLV_PRIMARYDEVICETYPE, + 0, 12, 12, 1, 2, 2, 1, }, + { offsetof(tDot11fIEWscProbeReq, RFBands), offsetof(tDot11fTLVRFBands, + present), "RFBands", SigTlvRFBands, DOT11F_TLV_RFBANDS, + 0, 5, 5, 1, 2, 2, 1, }, + { offsetof(tDot11fIEWscProbeReq, AssociationState), + offsetof(tDot11fTLVAssociationState, present), "AssociationState", + SigTlvAssociationState, DOT11F_TLV_ASSOCIATIONSTATE, + 0, 6, 6, 1, 2, 2, 1, }, + { offsetof(tDot11fIEWscProbeReq, ConfigurationError), + offsetof(tDot11fTLVConfigurationError, present), "ConfigurationError", + SigTlvConfigurationError, DOT11F_TLV_CONFIGURATIONERROR, + 0, 6, 6, 1, 2, 2, 1, }, + { offsetof(tDot11fIEWscProbeReq, DevicePasswordID), + offsetof(tDot11fTLVDevicePasswordID, present), "DevicePasswordID", + SigTlvDevicePasswordID, DOT11F_TLV_DEVICEPASSWORDID, + 0, 6, 6, 1, 2, 2, 1, }, + { offsetof(tDot11fIEWscProbeReq, Manufacturer), + offsetof(tDot11fTLVManufacturer, present), "Manufacturer", + SigTlvManufacturer, DOT11F_TLV_MANUFACTURER, 0, 4, 68, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWscProbeReq, ModelName), + offsetof(tDot11fTLVModelName, present), "ModelName", SigTlvModelName, + DOT11F_TLV_MODELNAME, 0, 4, 36, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWscProbeReq, ModelNumber), + offsetof(tDot11fTLVModelNumber, present), "ModelNumber", + SigTlvModelNumber, DOT11F_TLV_MODELNUMBER, 0, 4, 36, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWscProbeReq, DeviceName), + offsetof(tDot11fTLVDeviceName, present), "DeviceName", SigTlvDeviceName, + DOT11F_TLV_DEVICENAME, 0, 4, 36, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWscProbeReq, VendorExtension), + offsetof(tDot11fTLVVendorExtension, present), "VendorExtension", + SigTlvVendorExtension, DOT11F_TLV_VENDOREXTENSION, + 0, 7, 21, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWscProbeReq, RequestDeviceType), + offsetof(tDot11fTLVRequestDeviceType, present), "RequestDeviceType", + SigTlvRequestDeviceType, DOT11F_TLV_REQUESTDEVICETYPE, + 0, 12, 12, 0, 2, 2, 1, }, + {0, 0, NULL, 0, 0xffff, 0, 0, 0, 0, 0, 0}, +}; + +uint32_t dot11f_unpack_ie_wsc_probe_req(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEWscProbeReq *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pBuf; (void)ielen; /* Shutup the compiler */ + pDst->present = 1; + status = unpack_tlv_core(pCtx, pBuf, ielen, + TLVS_WscProbeReq, + (uint8_t *)pDst, sizeof(*pDst)); + return status; +} /* End dot11f_unpack_ie_wsc_probe_req. */ + +#define SigIeWscProbeReq (0x0079) + + +static const tTLVDefn TLVS_WscProbeRes[] = { + { offsetof(tDot11fIEWscProbeRes, Version), offsetof(tDot11fTLVVersion, + present), "Version", SigTlvVersion, DOT11F_TLV_VERSION, + 0, 5, 5, 1, 2, 2, 1, }, + { offsetof(tDot11fIEWscProbeRes, WPSState), offsetof(tDot11fTLVWPSState, + present), "WPSState", SigTlvWPSState, DOT11F_TLV_WPSSTATE, + 0, 5, 5, 1, 2, 2, 1, }, + { offsetof(tDot11fIEWscProbeRes, APSetupLocked), + offsetof(tDot11fTLVAPSetupLocked, present), "APSetupLocked", + SigTlvAPSetupLocked, DOT11F_TLV_APSETUPLOCKED, 0, 5, 5, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWscProbeRes, SelectedRegistrar), + offsetof(tDot11fTLVSelectedRegistrar, present), "SelectedRegistrar", + SigTlvSelectedRegistrar, DOT11F_TLV_SELECTEDREGISTRAR, + 0, 5, 5, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWscProbeRes, DevicePasswordID), + offsetof(tDot11fTLVDevicePasswordID, present), "DevicePasswordID", + SigTlvDevicePasswordID, DOT11F_TLV_DEVICEPASSWORDID, + 0, 6, 6, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWscProbeRes, SelectedRegistrarConfigMethods), + offsetof(tDot11fTLVSelectedRegistrarConfigMethods, present), + "SelectedRegistrarConfigMethods", SigTlvSelectedRegistrarConfigMethods, + DOT11F_TLV_SELECTEDREGISTRARCONFIGMETHODS, 0, 6, 6, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWscProbeRes, ResponseType), + offsetof(tDot11fTLVResponseType, present), "ResponseType", + SigTlvResponseType, DOT11F_TLV_RESPONSETYPE, 0, 5, 5, 1, 2, 2, 1, }, + { offsetof(tDot11fIEWscProbeRes, UUID_E), offsetof(tDot11fTLVUUID_E, + present), "UUID_E", SigTlvUUID_E, DOT11F_TLV_UUID_E, + 0, 20, 20, 1, 2, 2, 1, }, + { offsetof(tDot11fIEWscProbeRes, Manufacturer), + offsetof(tDot11fTLVManufacturer, present), "Manufacturer", + SigTlvManufacturer, DOT11F_TLV_MANUFACTURER, 0, 4, 68, 1, 2, 2, 1, }, + { offsetof(tDot11fIEWscProbeRes, ModelName), + offsetof(tDot11fTLVModelName, present), "ModelName", SigTlvModelName, + DOT11F_TLV_MODELNAME, 0, 4, 36, 1, 2, 2, 1, }, + { offsetof(tDot11fIEWscProbeRes, ModelNumber), + offsetof(tDot11fTLVModelNumber, present), "ModelNumber", + SigTlvModelNumber, DOT11F_TLV_MODELNUMBER, 0, 4, 36, 1, 2, 2, 1, }, + { offsetof(tDot11fIEWscProbeRes, SerialNumber), + offsetof(tDot11fTLVSerialNumber, present), "SerialNumber", + SigTlvSerialNumber, DOT11F_TLV_SERIALNUMBER, 0, 4, 36, 1, 2, 2, 1, }, + { offsetof(tDot11fIEWscProbeRes, PrimaryDeviceType), + offsetof(tDot11fTLVPrimaryDeviceType, present), "PrimaryDeviceType", + SigTlvPrimaryDeviceType, DOT11F_TLV_PRIMARYDEVICETYPE, + 0, 12, 12, 1, 2, 2, 1, }, + { offsetof(tDot11fIEWscProbeRes, DeviceName), + offsetof(tDot11fTLVDeviceName, present), "DeviceName", SigTlvDeviceName, + DOT11F_TLV_DEVICENAME, 0, 4, 36, 1, 2, 2, 1, }, + { offsetof(tDot11fIEWscProbeRes, ConfigMethods), + offsetof(tDot11fTLVConfigMethods, present), "ConfigMethods", + SigTlvConfigMethods, DOT11F_TLV_CONFIGMETHODS, 0, 6, 6, 1, 2, 2, 1, }, + { offsetof(tDot11fIEWscProbeRes, RFBands), offsetof(tDot11fTLVRFBands, + present), "RFBands", SigTlvRFBands, DOT11F_TLV_RFBANDS, + 0, 5, 5, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWscProbeRes, VendorExtension), + offsetof(tDot11fTLVVendorExtension, present), "VendorExtension", + SigTlvVendorExtension, DOT11F_TLV_VENDOREXTENSION, + 0, 7, 21, 0, 2, 2, 1, }, + {0, 0, NULL, 0, 0xffff, 0, 0, 0, 0, 0, 0}, +}; + +uint32_t dot11f_unpack_ie_wsc_probe_res(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEWscProbeRes *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pBuf; (void)ielen; /* Shutup the compiler */ + pDst->present = 1; + status = unpack_tlv_core(pCtx, pBuf, ielen, + TLVS_WscProbeRes, + (uint8_t *)pDst, sizeof(*pDst)); + return status; +} /* End dot11f_unpack_ie_wsc_probe_res. */ + +#define SigIeWscProbeRes (0x007a) + + +static const tTLVDefn TLVS_WscReassocRes[] = { + { offsetof(tDot11fIEWscReassocRes, Version), offsetof(tDot11fTLVVersion, + present), "Version", SigTlvVersion, DOT11F_TLV_VERSION, + 0, 5, 5, 1, 2, 2, 1, }, + { offsetof(tDot11fIEWscReassocRes, ResponseType), + offsetof(tDot11fTLVResponseType, present), "ResponseType", + SigTlvResponseType, DOT11F_TLV_RESPONSETYPE, 0, 5, 5, 1, 2, 2, 1, }, + { offsetof(tDot11fIEWscReassocRes, VendorExtension), + offsetof(tDot11fTLVVendorExtension, present), "VendorExtension", + SigTlvVendorExtension, DOT11F_TLV_VENDOREXTENSION, + 0, 7, 21, 0, 2, 2, 1, }, + {0, 0, NULL, 0, 0xffff, 0, 0, 0, 0, 0, 0}, +}; + +uint32_t dot11f_unpack_ie_wsc_reassoc_res(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEWscReassocRes *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pBuf; (void)ielen; /* Shutup the compiler */ + pDst->present = 1; + status = unpack_tlv_core(pCtx, pBuf, ielen, + TLVS_WscReassocRes, + (uint8_t *)pDst, sizeof(*pDst)); + return status; +} /* End dot11f_unpack_ie_wsc_reassoc_res. */ + +#define SigIeWscReassocRes (0x007b) + + +uint32_t dot11f_unpack_ie_ext_chan_switch_ann(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEext_chan_switch_ann *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->switch_mode = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->new_reg_class = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->new_channel = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->switch_count = *pBuf; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_ext_chan_switch_ann. */ + +#define SigIeext_chan_switch_ann (0x007c) + + +uint32_t dot11f_unpack_ie_hs20vendor_ie(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEhs20vendor_ie *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + uint8_t tmp68__; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + tmp68__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->dgaf_dis = tmp68__ >> 0 & 0x1; + pDst->hs_id_present = tmp68__ >> 1 & 0x3; + pDst->reserved = tmp68__ >> 3 & 0x1; + pDst->release_num = tmp68__ >> 4 & 0xf; + if (!ielen) { + return 0U; + } else { + switch (pDst->hs_id_present) { + case 1: + framesntohs(pCtx, &pDst->hs_id.pps_mo.pps_mo_id, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + break; + case 2: + framesntohs(pCtx, &pDst->hs_id.anqp_domain.anqp_domain_id, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + break; + } + } + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_hs20vendor_ie. */ + +#define SigIehs20vendor_ie (0x007d) + + +uint32_t dot11f_unpack_ie_ht2040_bss_coexistence(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEht2040_bss_coexistence *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + uint8_t tmp69__; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + tmp69__ = *pBuf; + pDst->info_request = tmp69__ >> 0 & 0x1; + pDst->forty_mhz_intolerant = tmp69__ >> 1 & 0x1; + pDst->twenty_mhz_bsswidth_req = tmp69__ >> 2 & 0x1; + pDst->obss_scan_exemption_req = tmp69__ >> 3 & 0x1; + pDst->obss_scan_exemption_grant = tmp69__ >> 4 & 0x1; + pDst->unused = tmp69__ >> 5 & 0x7; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_ht2040_bss_coexistence. */ + +#define SigIeht2040_bss_coexistence (0x007e) + + +uint32_t dot11f_unpack_ie_ht2040_bss_intolerant_report(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEht2040_bss_intolerant_report *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->operating_class = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->num_channel_list = (uint8_t)(ielen); + if (ielen > 50) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->channel_list, pBuf, (ielen)); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_ht2040_bss_intolerant_report. */ + +#define SigIeht2040_bss_intolerant_report (0x007f) + + +uint32_t dot11f_unpack_ie_sec_chan_offset_ele(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEsec_chan_offset_ele *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->secondaryChannelOffset = *pBuf; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_sec_chan_offset_ele. */ + +#define SigIesec_chan_offset_ele (0x0080) + + +static const tFFDefn FFS_vendor_vht_ie[] = { + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_vendor_vht_ie[] = { + { offsetof(tDot11fIEvendor_vht_ie, VHTCaps), offsetof(tDot11fIEVHTCaps, + present), 0, "VHTCaps", 0, 14, 14, SigIeVHTCaps, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_VHTCAPS, 0, }, + { offsetof(tDot11fIEvendor_vht_ie, VHTOperation), + offsetof(tDot11fIEVHTOperation, present), 0, "VHTOperation", + 0, 7, 7, SigIeVHTOperation, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_VHTOPERATION, 0, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, }, +}; + +uint32_t dot11f_unpack_ie_vendor_vht_ie(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEvendor_vht_ie *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + status = DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->type = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->sub_type = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + (void)pCtx; + status |= unpack_core(pCtx, + pBuf, + ielen, + FFS_vendor_vht_ie, + IES_vendor_vht_ie, + (uint8_t *)pDst, + sizeof(*pDst)); + return status; +} /* End dot11f_unpack_ie_vendor_vht_ie. */ + +#define SigIevendor_vht_ie (0x0081) + + +static const tFFDefn FFS_AddTSRequest[] = { + { "Category", offsetof(tDot11fAddTSRequest, Category), SigFfCategory, + DOT11F_FF_CATEGORY_LEN, }, + { "Action", offsetof(tDot11fAddTSRequest, Action), SigFfAction, + DOT11F_FF_ACTION_LEN, }, + { "DialogToken", offsetof(tDot11fAddTSRequest, DialogToken), + SigFfDialogToken, DOT11F_FF_DIALOGTOKEN_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_AddTSRequest[] = { + { offsetof(tDot11fAddTSRequest, TSPEC), offsetof(tDot11fIETSPEC, present), + 0, "TSPEC", 0, 57, 57, SigIeTSPEC, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_TSPEC, 1, }, + { offsetof(tDot11fAddTSRequest, TCLAS), offsetof(tDot11fIETCLAS, present), + offsetof(tDot11fAddTSRequest, num_TCLAS), "TCLAS", 2, 7, 45, SigIeTCLAS, + {0, 0, 0, 0, 0}, 0, DOT11F_EID_TCLAS, 0, }, + { offsetof(tDot11fAddTSRequest, TCLASSPROC), + offsetof(tDot11fIETCLASSPROC, present), 0, "TCLASSPROC", + 0, 3, 3, SigIeTCLASSPROC, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_TCLASSPROC, 0, }, + { offsetof(tDot11fAddTSRequest, WMMTSPEC), offsetof(tDot11fIEWMMTSPEC, + present), 0, "WMMTSPEC", 0, 63, 63, SigIeWMMTSPEC, {0, 80, 242, 2, 2}, + 5, DOT11F_EID_WMMTSPEC, 0, }, + { offsetof(tDot11fAddTSRequest, WMMTCLAS), offsetof(tDot11fIEWMMTCLAS, + present), offsetof(tDot11fAddTSRequest, num_WMMTCLAS), "WMMTCLAS", + 2, 13, 51, SigIeWMMTCLAS, {0, 80, 242, 2, 6}, + 5, DOT11F_EID_WMMTCLAS, 0, }, + { offsetof(tDot11fAddTSRequest, WMMTCLASPROC), + offsetof(tDot11fIEWMMTCLASPROC, present), 0, "WMMTCLASPROC", + 0, 9, 9, SigIeWMMTCLASPROC, {0, 80, 242, 2, 7}, + 5, DOT11F_EID_WMMTCLASPROC, 0, }, + { offsetof(tDot11fAddTSRequest, ESETrafStrmRateSet), + offsetof(tDot11fIEESETrafStrmRateSet, present), 0, "ESETrafStrmRateSet", + 0, 7, 15, SigIeESETrafStrmRateSet, {0, 64, 150, 8, 0}, + 4, DOT11F_EID_ESETRAFSTRMRATESET, 0, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_add_ts_request(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fAddTSRequest *pFrm) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_AddTSRequest, IES_AddTSRequest, + (uint8_t *)pFrm, sizeof(*pFrm)); + + (void)i; + return status; + +} /* End dot11f_unpack_add_ts_request. */ + +static const tFFDefn FFS_AddTSResponse[] = { + { "Category", offsetof(tDot11fAddTSResponse, Category), SigFfCategory, + DOT11F_FF_CATEGORY_LEN, }, + { "Action", offsetof(tDot11fAddTSResponse, Action), SigFfAction, + DOT11F_FF_ACTION_LEN, }, + { "DialogToken", offsetof(tDot11fAddTSResponse, DialogToken), + SigFfDialogToken, DOT11F_FF_DIALOGTOKEN_LEN, }, + { "Status", offsetof(tDot11fAddTSResponse, Status), SigFfStatus, + DOT11F_FF_STATUS_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_AddTSResponse[] = { + { offsetof(tDot11fAddTSResponse, TSDelay), offsetof(tDot11fIETSDelay, + present), 0, "TSDelay", 0, 6, 6, SigIeTSDelay, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_TSDELAY, 1, }, + { offsetof(tDot11fAddTSResponse, TSPEC), offsetof(tDot11fIETSPEC, + present), 0, "TSPEC", 0, 57, 57, SigIeTSPEC, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_TSPEC, 1, }, + { offsetof(tDot11fAddTSResponse, TCLAS), offsetof(tDot11fIETCLAS, + present), offsetof(tDot11fAddTSResponse, num_TCLAS), "TCLAS", + 2, 7, 45, SigIeTCLAS, {0, 0, 0, 0, 0}, 0, DOT11F_EID_TCLAS, 0, }, + { offsetof(tDot11fAddTSResponse, TCLASSPROC), + offsetof(tDot11fIETCLASSPROC, present), 0, "TCLASSPROC", + 0, 3, 3, SigIeTCLASSPROC, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_TCLASSPROC, 0, }, + { offsetof(tDot11fAddTSResponse, Schedule), offsetof(tDot11fIESchedule, + present), 0, "Schedule", 0, 16, 16, SigIeSchedule, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_SCHEDULE, 0, }, + { offsetof(tDot11fAddTSResponse, WMMTSDelay), + offsetof(tDot11fIEWMMTSDelay, present), 0, "WMMTSDelay", + 0, 12, 12, SigIeWMMTSDelay, {0, 80, 242, 2, 8}, + 5, DOT11F_EID_WMMTSDELAY, 0, }, + { offsetof(tDot11fAddTSResponse, WMMSchedule), + offsetof(tDot11fIEWMMSchedule, present), 0, "WMMSchedule", + 0, 22, 22, SigIeWMMSchedule, {0, 80, 242, 2, 9}, + 5, DOT11F_EID_WMMSCHEDULE, 0, }, + { offsetof(tDot11fAddTSResponse, WMMTSPEC), offsetof(tDot11fIEWMMTSPEC, + present), 0, "WMMTSPEC", 0, 63, 63, SigIeWMMTSPEC, {0, 80, 242, 2, 2}, + 5, DOT11F_EID_WMMTSPEC, 0, }, + { offsetof(tDot11fAddTSResponse, WMMTCLAS), offsetof(tDot11fIEWMMTCLAS, + present), offsetof(tDot11fAddTSResponse, num_WMMTCLAS), "WMMTCLAS", + 2, 13, 51, SigIeWMMTCLAS, {0, 80, 242, 2, 6}, + 5, DOT11F_EID_WMMTCLAS, 0, }, + { offsetof(tDot11fAddTSResponse, WMMTCLASPROC), + offsetof(tDot11fIEWMMTCLASPROC, present), 0, "WMMTCLASPROC", + 0, 9, 9, SigIeWMMTCLASPROC, {0, 80, 242, 2, 7}, + 5, DOT11F_EID_WMMTCLASPROC, 0, }, + { offsetof(tDot11fAddTSResponse, ESETrafStrmMet), + offsetof(tDot11fIEESETrafStrmMet, present), 0, "ESETrafStrmMet", + 0, 10, 10, SigIeESETrafStrmMet, {0, 64, 150, 7, 0}, + 4, DOT11F_EID_ESETRAFSTRMMET, 0, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_add_ts_response(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fAddTSResponse *pFrm) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_AddTSResponse, IES_AddTSResponse, + (uint8_t *)pFrm, sizeof(*pFrm)); + + (void)i; + return status; + +} /* End dot11f_unpack_add_ts_response. */ + +static const tFFDefn FFS_AssocRequest[] = { + { "Capabilities", offsetof(tDot11fAssocRequest, Capabilities), + SigFfCapabilities, DOT11F_FF_CAPABILITIES_LEN, }, + { "ListenInterval", offsetof(tDot11fAssocRequest, ListenInterval), + SigFfListenInterval, DOT11F_FF_LISTENINTERVAL_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_AssocRequest[] = { + { offsetof(tDot11fAssocRequest, SSID), offsetof(tDot11fIESSID, present), 0, + "SSID", 0, 2, 34, SigIeSSID, {0, 0, 0, 0, 0}, 0, DOT11F_EID_SSID, 1, }, + { offsetof(tDot11fAssocRequest, SuppRates), offsetof(tDot11fIESuppRates, + present), 0, "SuppRates", 0, 2, 14, SigIeSuppRates, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_SUPPRATES, 1, }, + { offsetof(tDot11fAssocRequest, OperatingMode), + offsetof(tDot11fIEOperatingMode, present), 0, "OperatingMode", + 0, 3, 3, SigIeOperatingMode, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_OPERATINGMODE, 0, }, + { offsetof(tDot11fAssocRequest, PowerCaps), offsetof(tDot11fIEPowerCaps, + present), 0, "PowerCaps", 0, 4, 4, SigIePowerCaps, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_POWERCAPS, 0, }, + { offsetof(tDot11fAssocRequest, SuppChannels), + offsetof(tDot11fIESuppChannels, present), 0, "SuppChannels", + 0, 4, 98, SigIeSuppChannels, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_SUPPCHANNELS, 0, }, + { offsetof(tDot11fAssocRequest, HTCaps), offsetof(tDot11fIEHTCaps, + present), 0, "HTCaps", 0, 28, 60, SigIeHTCaps, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_HTCAPS, 0, }, + { offsetof(tDot11fAssocRequest, QOSCapsStation), + offsetof(tDot11fIEQOSCapsStation, present), 0, "QOSCapsStation", + 0, 3, 3, SigIeQOSCapsStation, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_QOSCAPSSTATION, 0, }, + { offsetof(tDot11fAssocRequest, RSNOpaque), offsetof(tDot11fIERSNOpaque, + present), 0, "RSNOpaque", 0, 8, 255, SigIeRSNOpaque, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_RSNOPAQUE, 0, }, + { offsetof(tDot11fAssocRequest, ExtSuppRates), + offsetof(tDot11fIEExtSuppRates, present), 0, "ExtSuppRates", + 0, 3, 14, SigIeExtSuppRates, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_EXTSUPPRATES, 0, }, + { offsetof(tDot11fAssocRequest, MobilityDomain), + offsetof(tDot11fIEMobilityDomain, present), 0, "MobilityDomain", + 0, 5, 5, SigIeMobilityDomain, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_MOBILITYDOMAIN, 0, }, + { offsetof(tDot11fAssocRequest, SuppOperatingClasses), + offsetof(tDot11fIESuppOperatingClasses, present), 0, + "SuppOperatingClasses", 0, 3, 34, SigIeSuppOperatingClasses, + {0, 0, 0, 0, 0}, 0, DOT11F_EID_SUPPOPERATINGCLASSES, 0, }, + { offsetof(tDot11fAssocRequest, WAPIOpaque), + offsetof(tDot11fIEWAPIOpaque, present), 0, "WAPIOpaque", + 0, 8, 255, SigIeWAPIOpaque, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_WAPIOPAQUE, 0, }, + { offsetof(tDot11fAssocRequest, WAPI), offsetof(tDot11fIEWAPI, present), 0, + "WAPI", 0, 14, 112, SigIeWAPI, {0, 0, 0, 0, 0}, 0, DOT11F_EID_WAPI, 0, }, + { offsetof(tDot11fAssocRequest, RRMEnabledCap), + offsetof(tDot11fIERRMEnabledCap, present), 0, "RRMEnabledCap", + 0, 7, 7, SigIeRRMEnabledCap, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_RRMENABLEDCAP, 0, }, + { offsetof(tDot11fAssocRequest, QosMapSet), offsetof(tDot11fIEQosMapSet, + present), 0, "QosMapSet", 0, 2, 62, SigIeQosMapSet, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_QOSMAPSET, 0, }, + { offsetof(tDot11fAssocRequest, ExtCap), offsetof(tDot11fIEExtCap, + present), 0, "ExtCap", 0, 3, 17, SigIeExtCap, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_EXTCAP, 0, }, + { offsetof(tDot11fAssocRequest, VHTCaps), offsetof(tDot11fIEVHTCaps, + present), 0, "VHTCaps", 0, 14, 14, SigIeVHTCaps, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_VHTCAPS, 0, }, + { offsetof(tDot11fAssocRequest, WPAOpaque), offsetof(tDot11fIEWPAOpaque, + present), 0, "WPAOpaque", 0, 8, 255, SigIeWPAOpaque, {0, 80, 242, 1, 0}, + 4, DOT11F_EID_WPAOPAQUE, 0, }, + { offsetof(tDot11fAssocRequest, WMMCaps), offsetof(tDot11fIEWMMCaps, + present), 0, "WMMCaps", 0, 9, 9, SigIeWMMCaps, {0, 80, 242, 2, 5}, + 5, DOT11F_EID_WMMCAPS, 0, }, + { offsetof(tDot11fAssocRequest, WMMInfoStation), + offsetof(tDot11fIEWMMInfoStation, present), 0, "WMMInfoStation", + 0, 9, 9, SigIeWMMInfoStation, {0, 80, 242, 2, 0}, + 5, DOT11F_EID_WMMINFOSTATION, 0, }, + { offsetof(tDot11fAssocRequest, WscIEOpaque), + offsetof(tDot11fIEWscIEOpaque, present), 0, "WscIEOpaque", + 0, 8, 255, SigIeWscIEOpaque, {0, 80, 242, 4, 0}, + 4, DOT11F_EID_WSCIEOPAQUE, 0, }, + { offsetof(tDot11fAssocRequest, ESERadMgmtCap), + offsetof(tDot11fIEESERadMgmtCap, present), 0, "ESERadMgmtCap", + 0, 8, 8, SigIeESERadMgmtCap, {0, 64, 150, 1, 0}, + 4, DOT11F_EID_ESERADMGMTCAP, 0, }, + { offsetof(tDot11fAssocRequest, ESEVersion), + offsetof(tDot11fIEESEVersion, present), 0, "ESEVersion", + 0, 7, 7, SigIeESEVersion, {0, 64, 150, 3, 0}, + 4, DOT11F_EID_ESEVERSION, 0, }, + { offsetof(tDot11fAssocRequest, P2PIEOpaque), + offsetof(tDot11fIEP2PIEOpaque, present), 0, "P2PIEOpaque", + 0, 8, 255, SigIeP2PIEOpaque, {80, 111, 154, 9, 0}, + 4, DOT11F_EID_P2PIEOPAQUE, 0, }, + { offsetof(tDot11fAssocRequest, WFDIEOpaque), + offsetof(tDot11fIEWFDIEOpaque, present), 0, "WFDIEOpaque", + 0, 8, 255, SigIeWFDIEOpaque, {80, 111, 154, 10, 0}, + 4, DOT11F_EID_WFDIEOPAQUE, 0, }, + { offsetof(tDot11fAssocRequest, vendor_vht_ie), + offsetof(tDot11fIEvendor_vht_ie, present), 0, "vendor_vht_ie", + 0, 7, 28, SigIevendor_vht_ie, {0, 144, 76, 0, 0}, + 3, DOT11F_EID_VENDOR_VHT_IE, 0, }, + { offsetof(tDot11fAssocRequest, hs20vendor_ie), + offsetof(tDot11fIEhs20vendor_ie, present), 0, "hs20vendor_ie", + 0, 7, 9, SigIehs20vendor_ie, {80, 111, 154, 16, 0}, + 4, DOT11F_EID_HS20VENDOR_IE, 0, }, + { offsetof(tDot11fAssocRequest, QCN_IE), offsetof(tDot11fIEQCN_IE, + present), 0, "QCN_IE", 0, 10, 10, SigIeQCN_IE, {140, 253, 240, 1, 0}, + 4, DOT11F_EID_QCN_IE, 0, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_assoc_request(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fAssocRequest *pFrm) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_AssocRequest, IES_AssocRequest, + (uint8_t *)pFrm, sizeof(*pFrm)); + + (void)i; + return status; + +} /* End dot11f_unpack_assoc_request. */ + +static const tFFDefn FFS_AssocResponse[] = { + { "Capabilities", offsetof(tDot11fAssocResponse, Capabilities), + SigFfCapabilities, DOT11F_FF_CAPABILITIES_LEN, }, + { "Status", offsetof(tDot11fAssocResponse, Status), SigFfStatus, + DOT11F_FF_STATUS_LEN, }, + { "AID", offsetof(tDot11fAssocResponse, AID), SigFfAID, + DOT11F_FF_AID_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_AssocResponse[] = { + { offsetof(tDot11fAssocResponse, SuppRates), offsetof(tDot11fIESuppRates, + present), 0, "SuppRates", 0, 2, 14, SigIeSuppRates, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_SUPPRATES, 1, }, + { offsetof(tDot11fAssocResponse, ExtSuppRates), + offsetof(tDot11fIEExtSuppRates, present), 0, "ExtSuppRates", + 0, 3, 14, SigIeExtSuppRates, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_EXTSUPPRATES, 0, }, + { offsetof(tDot11fAssocResponse, EDCAParamSet), + offsetof(tDot11fIEEDCAParamSet, present), 0, "EDCAParamSet", + 0, 20, 20, SigIeEDCAParamSet, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_EDCAPARAMSET, 0, }, + { offsetof(tDot11fAssocResponse, RCPIIE), offsetof(tDot11fIERCPIIE, + present), 0, "RCPIIE", 0, 3, 3, SigIeRCPIIE, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_RCPIIE, 0, }, + { offsetof(tDot11fAssocResponse, RSNIIE), offsetof(tDot11fIERSNIIE, + present), 0, "RSNIIE", 0, 3, 3, SigIeRSNIIE, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_RSNIIE, 0, }, + { offsetof(tDot11fAssocResponse, RRMEnabledCap), + offsetof(tDot11fIERRMEnabledCap, present), 0, "RRMEnabledCap", + 0, 7, 7, SigIeRRMEnabledCap, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_RRMENABLEDCAP, 0, }, + { offsetof(tDot11fAssocResponse, MobilityDomain), + offsetof(tDot11fIEMobilityDomain, present), 0, "MobilityDomain", + 0, 5, 5, SigIeMobilityDomain, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_MOBILITYDOMAIN, 0, }, + { offsetof(tDot11fAssocResponse, FTInfo), offsetof(tDot11fIEFTInfo, + present), 0, "FTInfo", 0, 84, 222, SigIeFTInfo, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_FTINFO, 0, }, + { offsetof(tDot11fAssocResponse, RICDataDesc), + offsetof(tDot11fIERICDataDesc, present), + offsetof(tDot11fAssocResponse, num_RICDataDesc), "RICDataDesc", + 2, 2, 550, SigIeRICDataDesc, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_RICDATADESC, 0, }, + { offsetof(tDot11fAssocResponse, WPA), offsetof(tDot11fIEWPA, present), 0, + "WPA", 0, 8, 50, SigIeWPA, {0, 80, 242, 1, 0}, 4, DOT11F_EID_WPA, 0, }, + { offsetof(tDot11fAssocResponse, TimeoutInterval), + offsetof(tDot11fIETimeoutInterval, present), 0, "TimeoutInterval", + 0, 7, 7, SigIeTimeoutInterval, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_TIMEOUTINTERVAL, 0, }, + { offsetof(tDot11fAssocResponse, HTCaps), offsetof(tDot11fIEHTCaps, + present), 0, "HTCaps", 0, 28, 60, SigIeHTCaps, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_HTCAPS, 0, }, + { offsetof(tDot11fAssocResponse, HTInfo), offsetof(tDot11fIEHTInfo, + present), 0, "HTInfo", 0, 24, 56, SigIeHTInfo, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_HTINFO, 0, }, + { offsetof(tDot11fAssocResponse, WMMParams), offsetof(tDot11fIEWMMParams, + present), 0, "WMMParams", 0, 26, 26, SigIeWMMParams, {0, 80, 242, 2, 1}, + 5, DOT11F_EID_WMMPARAMS, 0, }, + { offsetof(tDot11fAssocResponse, WMMCaps), offsetof(tDot11fIEWMMCaps, + present), 0, "WMMCaps", 0, 9, 9, SigIeWMMCaps, {0, 80, 242, 2, 5}, + 5, DOT11F_EID_WMMCAPS, 0, }, + { offsetof(tDot11fAssocResponse, ESERadMgmtCap), + offsetof(tDot11fIEESERadMgmtCap, present), 0, "ESERadMgmtCap", + 0, 8, 8, SigIeESERadMgmtCap, {0, 64, 150, 1, 0}, + 4, DOT11F_EID_ESERADMGMTCAP, 0, }, + { offsetof(tDot11fAssocResponse, ESETrafStrmMet), + offsetof(tDot11fIEESETrafStrmMet, present), 0, "ESETrafStrmMet", + 0, 10, 10, SigIeESETrafStrmMet, {0, 64, 150, 7, 0}, + 4, DOT11F_EID_ESETRAFSTRMMET, 0, }, + { offsetof(tDot11fAssocResponse, ESETxmitPower), + offsetof(tDot11fIEESETxmitPower, present), 0, "ESETxmitPower", + 0, 8, 8, SigIeESETxmitPower, {0, 64, 150, 0, 0}, + 4, DOT11F_EID_ESETXMITPOWER, 0, }, + { offsetof(tDot11fAssocResponse, WMMTSPEC), offsetof(tDot11fIEWMMTSPEC, + present), offsetof(tDot11fAssocResponse, num_WMMTSPEC), "WMMTSPEC", + 4, 63, 63, SigIeWMMTSPEC, {0, 80, 242, 2, 2}, + 5, DOT11F_EID_WMMTSPEC, 0, }, + { offsetof(tDot11fAssocResponse, WscAssocRes), + offsetof(tDot11fIEWscAssocRes, present), 0, "WscAssocRes", + 0, 6, 37, SigIeWscAssocRes, {0, 80, 242, 4, 0}, + 4, DOT11F_EID_WSCASSOCRES, 0, }, + { offsetof(tDot11fAssocResponse, P2PAssocRes), + offsetof(tDot11fIEP2PAssocRes, present), 0, "P2PAssocRes", + 0, 6, 17, SigIeP2PAssocRes, {80, 111, 154, 9, 0}, + 4, DOT11F_EID_P2PASSOCRES, 0, }, + { offsetof(tDot11fAssocResponse, VHTCaps), offsetof(tDot11fIEVHTCaps, + present), 0, "VHTCaps", 0, 14, 14, SigIeVHTCaps, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_VHTCAPS, 0, }, + { offsetof(tDot11fAssocResponse, VHTOperation), + offsetof(tDot11fIEVHTOperation, present), 0, "VHTOperation", + 0, 7, 7, SigIeVHTOperation, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_VHTOPERATION, 0, }, + { offsetof(tDot11fAssocResponse, ExtCap), offsetof(tDot11fIEExtCap, + present), 0, "ExtCap", 0, 3, 17, SigIeExtCap, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_EXTCAP, 0, }, + { offsetof(tDot11fAssocResponse, OBSSScanParameters), + offsetof(tDot11fIEOBSSScanParameters, present), 0, "OBSSScanParameters", + 0, 16, 16, SigIeOBSSScanParameters, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_OBSSSCANPARAMETERS, 0, }, + { offsetof(tDot11fAssocResponse, QosMapSet), offsetof(tDot11fIEQosMapSet, + present), 0, "QosMapSet", 0, 2, 62, SigIeQosMapSet, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_QOSMAPSET, 0, }, + { offsetof(tDot11fAssocResponse, vendor_vht_ie), + offsetof(tDot11fIEvendor_vht_ie, present), 0, "vendor_vht_ie", + 0, 7, 28, SigIevendor_vht_ie, {0, 144, 76, 0, 0}, + 3, DOT11F_EID_VENDOR_VHT_IE, 0, }, + { offsetof(tDot11fAssocResponse, QCN_IE), offsetof(tDot11fIEQCN_IE, + present), 0, "QCN_IE", 0, 10, 10, SigIeQCN_IE, {140, 253, 240, 1, 0}, + 4, DOT11F_EID_QCN_IE, 0, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_assoc_response(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fAssocResponse *pFrm) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_AssocResponse, IES_AssocResponse, + (uint8_t *)pFrm, sizeof(*pFrm)); + + (void)i; + return status; + +} /* End dot11f_unpack_assoc_response. */ + +static const tFFDefn FFS_Authentication[] = { + { "AuthAlgo", offsetof(tDot11fAuthentication, AuthAlgo), SigFfAuthAlgo, + DOT11F_FF_AUTHALGO_LEN, }, + { "AuthSeqNo", offsetof(tDot11fAuthentication, AuthSeqNo), SigFfAuthSeqNo, + DOT11F_FF_AUTHSEQNO_LEN, }, + { "Status", offsetof(tDot11fAuthentication, Status), SigFfStatus, + DOT11F_FF_STATUS_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_Authentication[] = { + { offsetof(tDot11fAuthentication, ChallengeText), + offsetof(tDot11fIEChallengeText, present), 0, "ChallengeText", + 0, 3, 255, SigIeChallengeText, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_CHALLENGETEXT, 0, }, + { offsetof(tDot11fAuthentication, RSNOpaque), + offsetof(tDot11fIERSNOpaque, present), 0, "RSNOpaque", + 0, 8, 255, SigIeRSNOpaque, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_RSNOPAQUE, 0, }, + { offsetof(tDot11fAuthentication, MobilityDomain), + offsetof(tDot11fIEMobilityDomain, present), 0, "MobilityDomain", + 0, 5, 5, SigIeMobilityDomain, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_MOBILITYDOMAIN, 0, }, + { offsetof(tDot11fAuthentication, FTInfo), offsetof(tDot11fIEFTInfo, + present), 0, "FTInfo", 0, 84, 222, SigIeFTInfo, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_FTINFO, 0, }, + { offsetof(tDot11fAuthentication, TimeoutInterval), + offsetof(tDot11fIETimeoutInterval, present), 0, "TimeoutInterval", + 0, 7, 7, SigIeTimeoutInterval, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_TIMEOUTINTERVAL, 0, }, + { offsetof(tDot11fAuthentication, RICDataDesc), + offsetof(tDot11fIERICDataDesc, present), + offsetof(tDot11fAuthentication, num_RICDataDesc), "RICDataDesc", + 2, 2, 550, SigIeRICDataDesc, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_RICDATADESC, 0, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_authentication(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fAuthentication *pFrm) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_Authentication, IES_Authentication, + (uint8_t *)pFrm, sizeof(*pFrm)); + + (void)i; + return status; + +} /* End dot11f_unpack_authentication. */ + +static const tFFDefn FFS_Beacon[] = { + { "TimeStamp", offsetof(tDot11fBeacon, TimeStamp), SigFfTimeStamp, + DOT11F_FF_TIMESTAMP_LEN, }, + { "BeaconInterval", offsetof(tDot11fBeacon, BeaconInterval), + SigFfBeaconInterval, DOT11F_FF_BEACONINTERVAL_LEN, }, + { "Capabilities", offsetof(tDot11fBeacon, Capabilities), + SigFfCapabilities, DOT11F_FF_CAPABILITIES_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_Beacon[] = { + { offsetof(tDot11fBeacon, SSID), offsetof(tDot11fIESSID, present), 0, + "SSID", 0, 2, 34, SigIeSSID, {0, 0, 0, 0, 0}, 0, DOT11F_EID_SSID, 1, }, + { offsetof(tDot11fBeacon, SuppRates), offsetof(tDot11fIESuppRates, + present), 0, "SuppRates", 0, 2, 14, SigIeSuppRates, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_SUPPRATES, 1, }, + { offsetof(tDot11fBeacon, FHParamSet), offsetof(tDot11fIEFHParamSet, + present), 0, "FHParamSet", 0, 7, 7, SigIeFHParamSet, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_FHPARAMSET, 0, }, + { offsetof(tDot11fBeacon, DSParams), offsetof(tDot11fIEDSParams, present), + 0, "DSParams", 0, 3, 3, SigIeDSParams, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_DSPARAMS, 0, }, + { offsetof(tDot11fBeacon, CFParams), offsetof(tDot11fIECFParams, present), + 0, "CFParams", 0, 8, 8, SigIeCFParams, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_CFPARAMS, 0, }, + { offsetof(tDot11fBeacon, IBSSParams), offsetof(tDot11fIEIBSSParams, + present), 0, "IBSSParams", 0, 4, 4, SigIeIBSSParams, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_IBSSPARAMS, 0, }, + { offsetof(tDot11fBeacon, TIM), offsetof(tDot11fIETIM, present), 0, "TIM", + 0, 6, 256, SigIeTIM, {0, 0, 0, 0, 0}, 0, DOT11F_EID_TIM, 0, }, + { offsetof(tDot11fBeacon, Country), offsetof(tDot11fIECountry, present), 0, + "Country", 0, 5, 257, SigIeCountry, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_COUNTRY, 0, }, + { offsetof(tDot11fBeacon, FHParams), offsetof(tDot11fIEFHParams, present), + 0, "FHParams", 0, 4, 4, SigIeFHParams, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_FHPARAMS, 0, }, + { offsetof(tDot11fBeacon, FHPattTable), offsetof(tDot11fIEFHPattTable, + present), 0, "FHPattTable", 0, 6, 257, SigIeFHPattTable, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_FHPATTTABLE, 0, }, + { offsetof(tDot11fBeacon, PowerConstraints), + offsetof(tDot11fIEPowerConstraints, present), 0, "PowerConstraints", + 0, 3, 3, SigIePowerConstraints, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_POWERCONSTRAINTS, 0, }, + { offsetof(tDot11fBeacon, ChanSwitchAnn), + offsetof(tDot11fIEChanSwitchAnn, present), 0, "ChanSwitchAnn", + 0, 5, 5, SigIeChanSwitchAnn, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_CHANSWITCHANN, 0, }, + { offsetof(tDot11fBeacon, ext_chan_switch_ann), + offsetof(tDot11fIEext_chan_switch_ann, present), 0, "ext_chan_switch_ann", + 0, 6, 6, SigIeext_chan_switch_ann, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_EXT_CHAN_SWITCH_ANN, 0, }, + { offsetof(tDot11fBeacon, SuppOperatingClasses), + offsetof(tDot11fIESuppOperatingClasses, present), 0, + "SuppOperatingClasses", 0, 3, 34, SigIeSuppOperatingClasses, + {0, 0, 0, 0, 0}, 0, DOT11F_EID_SUPPOPERATINGCLASSES, 0, }, + { offsetof(tDot11fBeacon, Quiet), offsetof(tDot11fIEQuiet, present), 0, + "Quiet", 0, 8, 8, SigIeQuiet, {0, 0, 0, 0, 0}, 0, DOT11F_EID_QUIET, 0, }, + { offsetof(tDot11fBeacon, TPCReport), offsetof(tDot11fIETPCReport, + present), 0, "TPCReport", 0, 4, 4, SigIeTPCReport, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_TPCREPORT, 0, }, + { offsetof(tDot11fBeacon, ERPInfo), offsetof(tDot11fIEERPInfo, present), 0, + "ERPInfo", 0, 3, 3, SigIeERPInfo, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_ERPINFO, 0, }, + { offsetof(tDot11fBeacon, ExtSuppRates), offsetof(tDot11fIEExtSuppRates, + present), 0, "ExtSuppRates", 0, 3, 14, SigIeExtSuppRates, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_EXTSUPPRATES, 0, }, + { offsetof(tDot11fBeacon, RSN), offsetof(tDot11fIERSN, present), 0, "RSN", + 0, 8, 116, SigIeRSN, {0, 0, 0, 0, 0}, 0, DOT11F_EID_RSN, 0, }, + { offsetof(tDot11fBeacon, QBSSLoad), offsetof(tDot11fIEQBSSLoad, present), + 0, "QBSSLoad", 0, 7, 7, SigIeQBSSLoad, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_QBSSLOAD, 0, }, + { offsetof(tDot11fBeacon, EDCAParamSet), offsetof(tDot11fIEEDCAParamSet, + present), 0, "EDCAParamSet", 0, 20, 20, SigIeEDCAParamSet, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_EDCAPARAMSET, 0, }, + { offsetof(tDot11fBeacon, QOSCapsAp), offsetof(tDot11fIEQOSCapsAp, + present), 0, "QOSCapsAp", 0, 3, 3, SigIeQOSCapsAp, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_QOSCAPSAP, 0, }, + { offsetof(tDot11fBeacon, APChannelReport), + offsetof(tDot11fIEAPChannelReport, present), 0, "APChannelReport", + 0, 3, 53, SigIeAPChannelReport, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_APCHANNELREPORT, 0, }, + { offsetof(tDot11fBeacon, RRMEnabledCap), + offsetof(tDot11fIERRMEnabledCap, present), 0, "RRMEnabledCap", + 0, 7, 7, SigIeRRMEnabledCap, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_RRMENABLEDCAP, 0, }, + { offsetof(tDot11fBeacon, MobilityDomain), + offsetof(tDot11fIEMobilityDomain, present), 0, "MobilityDomain", + 0, 5, 5, SigIeMobilityDomain, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_MOBILITYDOMAIN, 0, }, + { offsetof(tDot11fBeacon, WPA), offsetof(tDot11fIEWPA, present), 0, "WPA", + 0, 8, 50, SigIeWPA, {0, 80, 242, 1, 0}, 4, DOT11F_EID_WPA, 0, }, + { offsetof(tDot11fBeacon, HTCaps), offsetof(tDot11fIEHTCaps, present), 0, + "HTCaps", 0, 28, 60, SigIeHTCaps, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_HTCAPS, 0, }, + { offsetof(tDot11fBeacon, HTInfo), offsetof(tDot11fIEHTInfo, present), 0, + "HTInfo", 0, 24, 56, SigIeHTInfo, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_HTINFO, 0, }, + { offsetof(tDot11fBeacon, sec_chan_offset_ele), + offsetof(tDot11fIEsec_chan_offset_ele, present), 0, "sec_chan_offset_ele", + 0, 3, 3, SigIesec_chan_offset_ele, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_SEC_CHAN_OFFSET_ELE, 0, }, + { offsetof(tDot11fBeacon, WMMInfoAp), offsetof(tDot11fIEWMMInfoAp, + present), 0, "WMMInfoAp", 0, 9, 9, SigIeWMMInfoAp, {0, 80, 242, 2, 0}, + 5, DOT11F_EID_WMMINFOAP, 0, }, + { offsetof(tDot11fBeacon, WMMParams), offsetof(tDot11fIEWMMParams, + present), 0, "WMMParams", 0, 26, 26, SigIeWMMParams, {0, 80, 242, 2, 1}, + 5, DOT11F_EID_WMMPARAMS, 0, }, + { offsetof(tDot11fBeacon, WMMCaps), offsetof(tDot11fIEWMMCaps, present), 0, + "WMMCaps", 0, 9, 9, SigIeWMMCaps, {0, 80, 242, 2, 5}, + 5, DOT11F_EID_WMMCAPS, 0, }, + { offsetof(tDot11fBeacon, WAPI), offsetof(tDot11fIEWAPI, present), 0, + "WAPI", 0, 14, 112, SigIeWAPI, {0, 0, 0, 0, 0}, 0, DOT11F_EID_WAPI, 0, }, + { offsetof(tDot11fBeacon, ESERadMgmtCap), + offsetof(tDot11fIEESERadMgmtCap, present), 0, "ESERadMgmtCap", + 0, 8, 8, SigIeESERadMgmtCap, {0, 64, 150, 1, 0}, + 4, DOT11F_EID_ESERADMGMTCAP, 0, }, + { offsetof(tDot11fBeacon, ESETrafStrmMet), + offsetof(tDot11fIEESETrafStrmMet, present), 0, "ESETrafStrmMet", + 0, 10, 10, SigIeESETrafStrmMet, {0, 64, 150, 7, 0}, + 4, DOT11F_EID_ESETRAFSTRMMET, 0, }, + { offsetof(tDot11fBeacon, ESETxmitPower), + offsetof(tDot11fIEESETxmitPower, present), 0, "ESETxmitPower", + 0, 8, 8, SigIeESETxmitPower, {0, 64, 150, 0, 0}, + 4, DOT11F_EID_ESETXMITPOWER, 0, }, + { offsetof(tDot11fBeacon, WscBeacon), offsetof(tDot11fIEWscBeacon, + present), 0, "WscBeacon", 0, 6, 84, SigIeWscBeacon, {0, 80, 242, 4, 0}, + 4, DOT11F_EID_WSCBEACON, 0, }, + { offsetof(tDot11fBeacon, P2PBeacon), offsetof(tDot11fIEP2PBeacon, + present), 0, "P2PBeacon", 0, 6, 61, SigIeP2PBeacon, {80, 111, 154, 9, 0}, + 4, DOT11F_EID_P2PBEACON, 0, }, + { offsetof(tDot11fBeacon, VHTCaps), offsetof(tDot11fIEVHTCaps, present), 0, + "VHTCaps", 0, 14, 14, SigIeVHTCaps, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_VHTCAPS, 0, }, + { offsetof(tDot11fBeacon, VHTOperation), offsetof(tDot11fIEVHTOperation, + present), 0, "VHTOperation", 0, 7, 7, SigIeVHTOperation, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_VHTOPERATION, 0, }, + { offsetof(tDot11fBeacon, VHTExtBssLoad), + offsetof(tDot11fIEVHTExtBssLoad, present), 0, "VHTExtBssLoad", + 0, 7, 7, SigIeVHTExtBssLoad, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_VHTEXTBSSLOAD, 0, }, + { offsetof(tDot11fBeacon, ExtCap), offsetof(tDot11fIEExtCap, present), 0, + "ExtCap", 0, 3, 17, SigIeExtCap, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_EXTCAP, 0, }, + { offsetof(tDot11fBeacon, OperatingMode), + offsetof(tDot11fIEOperatingMode, present), 0, "OperatingMode", + 0, 3, 3, SigIeOperatingMode, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_OPERATINGMODE, 0, }, + { offsetof(tDot11fBeacon, WiderBWChanSwitchAnn), + offsetof(tDot11fIEWiderBWChanSwitchAnn, present), 0, + "WiderBWChanSwitchAnn", 0, 5, 5, SigIeWiderBWChanSwitchAnn, + {0, 0, 0, 0, 0}, 0, DOT11F_EID_WIDERBWCHANSWITCHANN, 0, }, + { offsetof(tDot11fBeacon, OBSSScanParameters), + offsetof(tDot11fIEOBSSScanParameters, present), 0, "OBSSScanParameters", + 0, 16, 16, SigIeOBSSScanParameters, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_OBSSSCANPARAMETERS, 0, }, + { offsetof(tDot11fBeacon, Vendor1IE), offsetof(tDot11fIEVendor1IE, + present), 0, "Vendor1IE", 0, 5, 5, SigIeVendor1IE, {0, 16, 24, 0, 0}, + 3, DOT11F_EID_VENDOR1IE, 0, }, + { offsetof(tDot11fBeacon, vendor_vht_ie), + offsetof(tDot11fIEvendor_vht_ie, present), 0, "vendor_vht_ie", + 0, 7, 28, SigIevendor_vht_ie, {0, 144, 76, 0, 0}, + 3, DOT11F_EID_VENDOR_VHT_IE, 0, }, + { offsetof(tDot11fBeacon, Vendor3IE), offsetof(tDot11fIEVendor3IE, + present), 0, "Vendor3IE", 0, 5, 5, SigIeVendor3IE, {0, 22, 50, 0, 0}, + 3, DOT11F_EID_VENDOR3IE, 0, }, + { offsetof(tDot11fBeacon, hs20vendor_ie), + offsetof(tDot11fIEhs20vendor_ie, present), 0, "hs20vendor_ie", + 0, 7, 9, SigIehs20vendor_ie, {80, 111, 154, 16, 0}, + 4, DOT11F_EID_HS20VENDOR_IE, 0, }, + { offsetof(tDot11fBeacon, ChannelSwitchWrapper), + offsetof(tDot11fIEChannelSwitchWrapper, present), 0, + "ChannelSwitchWrapper", 0, 2, 14, SigIeChannelSwitchWrapper, + {0, 0, 0, 0, 0}, 0, DOT11F_EID_CHANNELSWITCHWRAPPER, 0, }, + { offsetof(tDot11fBeacon, QComVendorIE), offsetof(tDot11fIEQComVendorIE, + present), 0, "QComVendorIE", 0, 7, 7, SigIeQComVendorIE, + {0, 160, 198, 0, 0}, 3, DOT11F_EID_QCOMVENDORIE, 0, }, + { offsetof(tDot11fBeacon, ESEVersion), offsetof(tDot11fIEESEVersion, + present), 0, "ESEVersion", 0, 7, 7, SigIeESEVersion, {0, 64, 150, 3, 0}, + 4, DOT11F_EID_ESEVERSION, 0, }, + { offsetof(tDot11fBeacon, MBO_IE), offsetof(tDot11fIEMBO_IE, present), 0, + "MBO_IE", 0, 9, 12, SigIeMBO_IE, {80, 111, 154, 22, 0}, + 4, DOT11F_EID_MBO_IE, 0, }, + { offsetof(tDot11fBeacon, QCN_IE), offsetof(tDot11fIEQCN_IE, present), 0, + "QCN_IE", 0, 10, 10, SigIeQCN_IE, {140, 253, 240, 1, 0}, + 4, DOT11F_EID_QCN_IE, 0, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_beacon(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fBeacon *pFrm) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_Beacon, IES_Beacon, + (uint8_t *)pFrm, sizeof(*pFrm)); + + (void)i; + return status; + +} /* End dot11f_unpack_beacon. */ + +static const tFFDefn FFS_Beacon1[] = { + { "TimeStamp", offsetof(tDot11fBeacon1, TimeStamp), SigFfTimeStamp, + DOT11F_FF_TIMESTAMP_LEN, }, + { "BeaconInterval", offsetof(tDot11fBeacon1, BeaconInterval), + SigFfBeaconInterval, DOT11F_FF_BEACONINTERVAL_LEN, }, + { "Capabilities", offsetof(tDot11fBeacon1, Capabilities), + SigFfCapabilities, DOT11F_FF_CAPABILITIES_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_Beacon1[] = { + { offsetof(tDot11fBeacon1, SSID), offsetof(tDot11fIESSID, present), 0, + "SSID", 0, 2, 34, SigIeSSID, {0, 0, 0, 0, 0}, 0, DOT11F_EID_SSID, 1, }, + { offsetof(tDot11fBeacon1, SuppRates), offsetof(tDot11fIESuppRates, + present), 0, "SuppRates", 0, 2, 14, SigIeSuppRates, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_SUPPRATES, 1, }, + { offsetof(tDot11fBeacon1, DSParams), offsetof(tDot11fIEDSParams, + present), 0, "DSParams", 0, 3, 3, SigIeDSParams, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_DSPARAMS, 0, }, + { offsetof(tDot11fBeacon1, IBSSParams), offsetof(tDot11fIEIBSSParams, + present), 0, "IBSSParams", 0, 4, 4, SigIeIBSSParams, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_IBSSPARAMS, 0, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_beacon1(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fBeacon1 *pFrm) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_Beacon1, IES_Beacon1, + (uint8_t *)pFrm, sizeof(*pFrm)); + + (void)i; + return status; + +} /* End dot11f_unpack_beacon1. */ + +static const tFFDefn FFS_Beacon2[] = { + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_Beacon2[] = { + { offsetof(tDot11fBeacon2, Country), offsetof(tDot11fIECountry, present), + 0, "Country", 0, 5, 257, SigIeCountry, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_COUNTRY, 0, }, + { offsetof(tDot11fBeacon2, PowerConstraints), + offsetof(tDot11fIEPowerConstraints, present), 0, "PowerConstraints", + 0, 3, 3, SigIePowerConstraints, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_POWERCONSTRAINTS, 0, }, + { offsetof(tDot11fBeacon2, ChanSwitchAnn), + offsetof(tDot11fIEChanSwitchAnn, present), 0, "ChanSwitchAnn", + 0, 5, 5, SigIeChanSwitchAnn, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_CHANSWITCHANN, 0, }, + { offsetof(tDot11fBeacon2, ext_chan_switch_ann), + offsetof(tDot11fIEext_chan_switch_ann, present), 0, "ext_chan_switch_ann", + 0, 6, 6, SigIeext_chan_switch_ann, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_EXT_CHAN_SWITCH_ANN, 0, }, + { offsetof(tDot11fBeacon2, SuppOperatingClasses), + offsetof(tDot11fIESuppOperatingClasses, present), 0, + "SuppOperatingClasses", 0, 3, 34, SigIeSuppOperatingClasses, + {0, 0, 0, 0, 0}, 0, DOT11F_EID_SUPPOPERATINGCLASSES, 0, }, + { offsetof(tDot11fBeacon2, Quiet), offsetof(tDot11fIEQuiet, present), 0, + "Quiet", 0, 8, 8, SigIeQuiet, {0, 0, 0, 0, 0}, 0, DOT11F_EID_QUIET, 0, }, + { offsetof(tDot11fBeacon2, TPCReport), offsetof(tDot11fIETPCReport, + present), 0, "TPCReport", 0, 4, 4, SigIeTPCReport, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_TPCREPORT, 0, }, + { offsetof(tDot11fBeacon2, ERPInfo), offsetof(tDot11fIEERPInfo, present), + 0, "ERPInfo", 0, 3, 3, SigIeERPInfo, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_ERPINFO, 0, }, + { offsetof(tDot11fBeacon2, ExtSuppRates), offsetof(tDot11fIEExtSuppRates, + present), 0, "ExtSuppRates", 0, 3, 14, SigIeExtSuppRates, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_EXTSUPPRATES, 0, }, + { offsetof(tDot11fBeacon2, RSNOpaque), offsetof(tDot11fIERSNOpaque, + present), 0, "RSNOpaque", 0, 8, 255, SigIeRSNOpaque, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_RSNOPAQUE, 0, }, + { offsetof(tDot11fBeacon2, EDCAParamSet), offsetof(tDot11fIEEDCAParamSet, + present), 0, "EDCAParamSet", 0, 20, 20, SigIeEDCAParamSet, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_EDCAPARAMSET, 0, }, + { offsetof(tDot11fBeacon2, APChannelReport), + offsetof(tDot11fIEAPChannelReport, present), 0, "APChannelReport", + 0, 3, 53, SigIeAPChannelReport, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_APCHANNELREPORT, 0, }, + { offsetof(tDot11fBeacon2, RRMEnabledCap), + offsetof(tDot11fIERRMEnabledCap, present), 0, "RRMEnabledCap", + 0, 7, 7, SigIeRRMEnabledCap, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_RRMENABLEDCAP, 0, }, + { offsetof(tDot11fBeacon2, MobilityDomain), + offsetof(tDot11fIEMobilityDomain, present), 0, "MobilityDomain", + 0, 5, 5, SigIeMobilityDomain, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_MOBILITYDOMAIN, 0, }, + { offsetof(tDot11fBeacon2, WPA), offsetof(tDot11fIEWPA, present), 0, "WPA", + 0, 8, 50, SigIeWPA, {0, 80, 242, 1, 0}, 4, DOT11F_EID_WPA, 0, }, + { offsetof(tDot11fBeacon2, HTCaps), offsetof(tDot11fIEHTCaps, present), 0, + "HTCaps", 0, 28, 60, SigIeHTCaps, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_HTCAPS, 0, }, + { offsetof(tDot11fBeacon2, HTInfo), offsetof(tDot11fIEHTInfo, present), 0, + "HTInfo", 0, 24, 56, SigIeHTInfo, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_HTINFO, 0, }, + { offsetof(tDot11fBeacon2, sec_chan_offset_ele), + offsetof(tDot11fIEsec_chan_offset_ele, present), 0, "sec_chan_offset_ele", + 0, 3, 3, SigIesec_chan_offset_ele, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_SEC_CHAN_OFFSET_ELE, 0, }, + { offsetof(tDot11fBeacon2, WMMInfoAp), offsetof(tDot11fIEWMMInfoAp, + present), 0, "WMMInfoAp", 0, 9, 9, SigIeWMMInfoAp, {0, 80, 242, 2, 0}, + 5, DOT11F_EID_WMMINFOAP, 0, }, + { offsetof(tDot11fBeacon2, WMMParams), offsetof(tDot11fIEWMMParams, + present), 0, "WMMParams", 0, 26, 26, SigIeWMMParams, {0, 80, 242, 2, 1}, + 5, DOT11F_EID_WMMPARAMS, 0, }, + { offsetof(tDot11fBeacon2, WMMCaps), offsetof(tDot11fIEWMMCaps, present), + 0, "WMMCaps", 0, 9, 9, SigIeWMMCaps, {0, 80, 242, 2, 5}, + 5, DOT11F_EID_WMMCAPS, 0, }, + { offsetof(tDot11fBeacon2, WscBeacon), offsetof(tDot11fIEWscBeacon, + present), 0, "WscBeacon", 0, 6, 84, SigIeWscBeacon, {0, 80, 242, 4, 0}, + 4, DOT11F_EID_WSCBEACON, 0, }, + { offsetof(tDot11fBeacon2, WAPI), offsetof(tDot11fIEWAPI, present), 0, + "WAPI", 0, 14, 112, SigIeWAPI, {0, 0, 0, 0, 0}, 0, DOT11F_EID_WAPI, 0, }, + { offsetof(tDot11fBeacon2, ESERadMgmtCap), + offsetof(tDot11fIEESERadMgmtCap, present), 0, "ESERadMgmtCap", + 0, 8, 8, SigIeESERadMgmtCap, {0, 64, 150, 1, 0}, + 4, DOT11F_EID_ESERADMGMTCAP, 0, }, + { offsetof(tDot11fBeacon2, ESETrafStrmMet), + offsetof(tDot11fIEESETrafStrmMet, present), 0, "ESETrafStrmMet", + 0, 10, 10, SigIeESETrafStrmMet, {0, 64, 150, 7, 0}, + 4, DOT11F_EID_ESETRAFSTRMMET, 0, }, + { offsetof(tDot11fBeacon2, ESETxmitPower), + offsetof(tDot11fIEESETxmitPower, present), 0, "ESETxmitPower", + 0, 8, 8, SigIeESETxmitPower, {0, 64, 150, 0, 0}, + 4, DOT11F_EID_ESETXMITPOWER, 0, }, + { offsetof(tDot11fBeacon2, P2PBeacon), offsetof(tDot11fIEP2PBeacon, + present), 0, "P2PBeacon", 0, 6, 61, SigIeP2PBeacon, {80, 111, 154, 9, 0}, + 4, DOT11F_EID_P2PBEACON, 0, }, + { offsetof(tDot11fBeacon2, VHTCaps), offsetof(tDot11fIEVHTCaps, present), + 0, "VHTCaps", 0, 14, 14, SigIeVHTCaps, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_VHTCAPS, 0, }, + { offsetof(tDot11fBeacon2, VHTOperation), offsetof(tDot11fIEVHTOperation, + present), 0, "VHTOperation", 0, 7, 7, SigIeVHTOperation, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_VHTOPERATION, 0, }, + { offsetof(tDot11fBeacon2, VHTExtBssLoad), + offsetof(tDot11fIEVHTExtBssLoad, present), 0, "VHTExtBssLoad", + 0, 7, 7, SigIeVHTExtBssLoad, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_VHTEXTBSSLOAD, 0, }, + { offsetof(tDot11fBeacon2, ExtCap), offsetof(tDot11fIEExtCap, present), 0, + "ExtCap", 0, 3, 17, SigIeExtCap, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_EXTCAP, 0, }, + { offsetof(tDot11fBeacon2, OperatingMode), + offsetof(tDot11fIEOperatingMode, present), 0, "OperatingMode", + 0, 3, 3, SigIeOperatingMode, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_OPERATINGMODE, 0, }, + { offsetof(tDot11fBeacon2, WiderBWChanSwitchAnn), + offsetof(tDot11fIEWiderBWChanSwitchAnn, present), 0, + "WiderBWChanSwitchAnn", 0, 5, 5, SigIeWiderBWChanSwitchAnn, + {0, 0, 0, 0, 0}, 0, DOT11F_EID_WIDERBWCHANSWITCHANN, 0, }, + { offsetof(tDot11fBeacon2, OBSSScanParameters), + offsetof(tDot11fIEOBSSScanParameters, present), 0, "OBSSScanParameters", + 0, 16, 16, SigIeOBSSScanParameters, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_OBSSSCANPARAMETERS, 0, }, + { offsetof(tDot11fBeacon2, Vendor1IE), offsetof(tDot11fIEVendor1IE, + present), 0, "Vendor1IE", 0, 5, 5, SigIeVendor1IE, {0, 16, 24, 0, 0}, + 3, DOT11F_EID_VENDOR1IE, 0, }, + { offsetof(tDot11fBeacon2, vendor_vht_ie), + offsetof(tDot11fIEvendor_vht_ie, present), 0, "vendor_vht_ie", + 0, 7, 28, SigIevendor_vht_ie, {0, 144, 76, 0, 0}, + 3, DOT11F_EID_VENDOR_VHT_IE, 0, }, + { offsetof(tDot11fBeacon2, Vendor3IE), offsetof(tDot11fIEVendor3IE, + present), 0, "Vendor3IE", 0, 5, 5, SigIeVendor3IE, {0, 22, 50, 0, 0}, + 3, DOT11F_EID_VENDOR3IE, 0, }, + { offsetof(tDot11fBeacon2, hs20vendor_ie), + offsetof(tDot11fIEhs20vendor_ie, present), 0, "hs20vendor_ie", + 0, 7, 9, SigIehs20vendor_ie, {80, 111, 154, 16, 0}, + 4, DOT11F_EID_HS20VENDOR_IE, 0, }, + { offsetof(tDot11fBeacon2, ChannelSwitchWrapper), + offsetof(tDot11fIEChannelSwitchWrapper, present), 0, + "ChannelSwitchWrapper", 0, 2, 14, SigIeChannelSwitchWrapper, + {0, 0, 0, 0, 0}, 0, DOT11F_EID_CHANNELSWITCHWRAPPER, 0, }, + { offsetof(tDot11fBeacon2, QComVendorIE), offsetof(tDot11fIEQComVendorIE, + present), 0, "QComVendorIE", 0, 7, 7, SigIeQComVendorIE, + {0, 160, 198, 0, 0}, 3, DOT11F_EID_QCOMVENDORIE, 0, }, + { offsetof(tDot11fBeacon2, ESEVersion), offsetof(tDot11fIEESEVersion, + present), 0, "ESEVersion", 0, 7, 7, SigIeESEVersion, {0, 64, 150, 3, 0}, + 4, DOT11F_EID_ESEVERSION, 0, }, + { offsetof(tDot11fBeacon2, QCN_IE), offsetof(tDot11fIEQCN_IE, present), 0, + "QCN_IE", 0, 10, 10, SigIeQCN_IE, {140, 253, 240, 1, 0}, + 4, DOT11F_EID_QCN_IE, 0, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_beacon2(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fBeacon2 *pFrm) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_Beacon2, IES_Beacon2, + (uint8_t *)pFrm, sizeof(*pFrm)); + + (void)i; + return status; + +} /* End dot11f_unpack_beacon2. */ + +static const tFFDefn FFS_BeaconIEs[] = { + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_BeaconIEs[] = { + { offsetof(tDot11fBeaconIEs, SSID), offsetof(tDot11fIESSID, present), 0, + "SSID", 0, 2, 34, SigIeSSID, {0, 0, 0, 0, 0}, 0, DOT11F_EID_SSID, 1, }, + { offsetof(tDot11fBeaconIEs, SuppRates), offsetof(tDot11fIESuppRates, + present), 0, "SuppRates", 0, 2, 14, SigIeSuppRates, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_SUPPRATES, 1, }, + { offsetof(tDot11fBeaconIEs, FHParamSet), offsetof(tDot11fIEFHParamSet, + present), 0, "FHParamSet", 0, 7, 7, SigIeFHParamSet, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_FHPARAMSET, 0, }, + { offsetof(tDot11fBeaconIEs, DSParams), offsetof(tDot11fIEDSParams, + present), 0, "DSParams", 0, 3, 3, SigIeDSParams, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_DSPARAMS, 0, }, + { offsetof(tDot11fBeaconIEs, CFParams), offsetof(tDot11fIECFParams, + present), 0, "CFParams", 0, 8, 8, SigIeCFParams, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_CFPARAMS, 0, }, + { offsetof(tDot11fBeaconIEs, IBSSParams), offsetof(tDot11fIEIBSSParams, + present), 0, "IBSSParams", 0, 4, 4, SigIeIBSSParams, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_IBSSPARAMS, 0, }, + { offsetof(tDot11fBeaconIEs, TIM), offsetof(tDot11fIETIM, present), 0, + "TIM", 0, 6, 256, SigIeTIM, {0, 0, 0, 0, 0}, 0, DOT11F_EID_TIM, 0, }, + { offsetof(tDot11fBeaconIEs, Country), offsetof(tDot11fIECountry, + present), 0, "Country", 0, 5, 257, SigIeCountry, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_COUNTRY, 0, }, + { offsetof(tDot11fBeaconIEs, FHParams), offsetof(tDot11fIEFHParams, + present), 0, "FHParams", 0, 4, 4, SigIeFHParams, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_FHPARAMS, 0, }, + { offsetof(tDot11fBeaconIEs, FHPattTable), offsetof(tDot11fIEFHPattTable, + present), 0, "FHPattTable", 0, 6, 257, SigIeFHPattTable, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_FHPATTTABLE, 0, }, + { offsetof(tDot11fBeaconIEs, PowerConstraints), + offsetof(tDot11fIEPowerConstraints, present), 0, "PowerConstraints", + 0, 3, 3, SigIePowerConstraints, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_POWERCONSTRAINTS, 0, }, + { offsetof(tDot11fBeaconIEs, ChanSwitchAnn), + offsetof(tDot11fIEChanSwitchAnn, present), 0, "ChanSwitchAnn", + 0, 5, 5, SigIeChanSwitchAnn, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_CHANSWITCHANN, 0, }, + { offsetof(tDot11fBeaconIEs, ext_chan_switch_ann), + offsetof(tDot11fIEext_chan_switch_ann, present), 0, "ext_chan_switch_ann", + 0, 6, 6, SigIeext_chan_switch_ann, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_EXT_CHAN_SWITCH_ANN, 0, }, + { offsetof(tDot11fBeaconIEs, SuppOperatingClasses), + offsetof(tDot11fIESuppOperatingClasses, present), 0, + "SuppOperatingClasses", 0, 3, 34, SigIeSuppOperatingClasses, + {0, 0, 0, 0, 0}, 0, DOT11F_EID_SUPPOPERATINGCLASSES, 0, }, + { offsetof(tDot11fBeaconIEs, Quiet), offsetof(tDot11fIEQuiet, present), 0, + "Quiet", 0, 8, 8, SigIeQuiet, {0, 0, 0, 0, 0}, 0, DOT11F_EID_QUIET, 0, }, + { offsetof(tDot11fBeaconIEs, TPCReport), offsetof(tDot11fIETPCReport, + present), 0, "TPCReport", 0, 4, 4, SigIeTPCReport, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_TPCREPORT, 0, }, + { offsetof(tDot11fBeaconIEs, ERPInfo), offsetof(tDot11fIEERPInfo, + present), 0, "ERPInfo", 0, 3, 3, SigIeERPInfo, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_ERPINFO, 0, }, + { offsetof(tDot11fBeaconIEs, ExtSuppRates), + offsetof(tDot11fIEExtSuppRates, present), 0, "ExtSuppRates", + 0, 3, 14, SigIeExtSuppRates, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_EXTSUPPRATES, 0, }, + { offsetof(tDot11fBeaconIEs, RSN), offsetof(tDot11fIERSN, present), 0, + "RSN", 0, 8, 116, SigIeRSN, {0, 0, 0, 0, 0}, 0, DOT11F_EID_RSN, 0, }, + { offsetof(tDot11fBeaconIEs, QBSSLoad), offsetof(tDot11fIEQBSSLoad, + present), 0, "QBSSLoad", 0, 7, 7, SigIeQBSSLoad, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_QBSSLOAD, 0, }, + { offsetof(tDot11fBeaconIEs, EDCAParamSet), + offsetof(tDot11fIEEDCAParamSet, present), 0, "EDCAParamSet", + 0, 20, 20, SigIeEDCAParamSet, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_EDCAPARAMSET, 0, }, + { offsetof(tDot11fBeaconIEs, QOSCapsAp), offsetof(tDot11fIEQOSCapsAp, + present), 0, "QOSCapsAp", 0, 3, 3, SigIeQOSCapsAp, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_QOSCAPSAP, 0, }, + { offsetof(tDot11fBeaconIEs, APChannelReport), + offsetof(tDot11fIEAPChannelReport, present), 0, "APChannelReport", + 0, 3, 53, SigIeAPChannelReport, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_APCHANNELREPORT, 0, }, + { offsetof(tDot11fBeaconIEs, RRMEnabledCap), + offsetof(tDot11fIERRMEnabledCap, present), 0, "RRMEnabledCap", + 0, 7, 7, SigIeRRMEnabledCap, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_RRMENABLEDCAP, 0, }, + { offsetof(tDot11fBeaconIEs, MobilityDomain), + offsetof(tDot11fIEMobilityDomain, present), 0, "MobilityDomain", + 0, 5, 5, SigIeMobilityDomain, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_MOBILITYDOMAIN, 0, }, + { offsetof(tDot11fBeaconIEs, WPA), offsetof(tDot11fIEWPA, present), 0, + "WPA", 0, 8, 50, SigIeWPA, {0, 80, 242, 1, 0}, 4, DOT11F_EID_WPA, 0, }, + { offsetof(tDot11fBeaconIEs, HTCaps), offsetof(tDot11fIEHTCaps, present), + 0, "HTCaps", 0, 28, 60, SigIeHTCaps, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_HTCAPS, 0, }, + { offsetof(tDot11fBeaconIEs, HTInfo), offsetof(tDot11fIEHTInfo, present), + 0, "HTInfo", 0, 24, 56, SigIeHTInfo, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_HTINFO, 0, }, + { offsetof(tDot11fBeaconIEs, sec_chan_offset_ele), + offsetof(tDot11fIEsec_chan_offset_ele, present), 0, "sec_chan_offset_ele", + 0, 3, 3, SigIesec_chan_offset_ele, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_SEC_CHAN_OFFSET_ELE, 0, }, + { offsetof(tDot11fBeaconIEs, WMMInfoAp), offsetof(tDot11fIEWMMInfoAp, + present), 0, "WMMInfoAp", 0, 9, 9, SigIeWMMInfoAp, {0, 80, 242, 2, 0}, + 5, DOT11F_EID_WMMINFOAP, 0, }, + { offsetof(tDot11fBeaconIEs, WMMParams), offsetof(tDot11fIEWMMParams, + present), 0, "WMMParams", 0, 26, 26, SigIeWMMParams, {0, 80, 242, 2, 1}, + 5, DOT11F_EID_WMMPARAMS, 0, }, + { offsetof(tDot11fBeaconIEs, WMMCaps), offsetof(tDot11fIEWMMCaps, + present), 0, "WMMCaps", 0, 9, 9, SigIeWMMCaps, {0, 80, 242, 2, 5}, + 5, DOT11F_EID_WMMCAPS, 0, }, + { offsetof(tDot11fBeaconIEs, WAPI), offsetof(tDot11fIEWAPI, present), 0, + "WAPI", 0, 14, 112, SigIeWAPI, {0, 0, 0, 0, 0}, 0, DOT11F_EID_WAPI, 0, }, + { offsetof(tDot11fBeaconIEs, ESEVersion), offsetof(tDot11fIEESEVersion, + present), 0, "ESEVersion", 0, 7, 7, SigIeESEVersion, {0, 64, 150, 3, 0}, + 4, DOT11F_EID_ESEVERSION, 0, }, + { offsetof(tDot11fBeaconIEs, ESERadMgmtCap), + offsetof(tDot11fIEESERadMgmtCap, present), 0, "ESERadMgmtCap", + 0, 8, 8, SigIeESERadMgmtCap, {0, 64, 150, 1, 0}, + 4, DOT11F_EID_ESERADMGMTCAP, 0, }, + { offsetof(tDot11fBeaconIEs, ESETrafStrmMet), + offsetof(tDot11fIEESETrafStrmMet, present), 0, "ESETrafStrmMet", + 0, 10, 10, SigIeESETrafStrmMet, {0, 64, 150, 7, 0}, + 4, DOT11F_EID_ESETRAFSTRMMET, 0, }, + { offsetof(tDot11fBeaconIEs, ESETxmitPower), + offsetof(tDot11fIEESETxmitPower, present), 0, "ESETxmitPower", + 0, 8, 8, SigIeESETxmitPower, {0, 64, 150, 0, 0}, + 4, DOT11F_EID_ESETXMITPOWER, 0, }, + { offsetof(tDot11fBeaconIEs, WscBeaconProbeRes), + offsetof(tDot11fIEWscBeaconProbeRes, present), 0, "WscBeaconProbeRes", + 0, 6, 319, SigIeWscBeaconProbeRes, {0, 80, 242, 4, 0}, + 4, DOT11F_EID_WSCBEACONPROBERES, 0, }, + { offsetof(tDot11fBeaconIEs, P2PBeaconProbeRes), + offsetof(tDot11fIEP2PBeaconProbeRes, present), 0, "P2PBeaconProbeRes", + 0, 6, 1150, SigIeP2PBeaconProbeRes, {80, 111, 154, 9, 0}, + 4, DOT11F_EID_P2PBEACONPROBERES, 0, }, + { offsetof(tDot11fBeaconIEs, VHTCaps), offsetof(tDot11fIEVHTCaps, + present), 0, "VHTCaps", 0, 14, 14, SigIeVHTCaps, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_VHTCAPS, 0, }, + { offsetof(tDot11fBeaconIEs, VHTOperation), + offsetof(tDot11fIEVHTOperation, present), 0, "VHTOperation", + 0, 7, 7, SigIeVHTOperation, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_VHTOPERATION, 0, }, + { offsetof(tDot11fBeaconIEs, VHTExtBssLoad), + offsetof(tDot11fIEVHTExtBssLoad, present), 0, "VHTExtBssLoad", + 0, 7, 7, SigIeVHTExtBssLoad, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_VHTEXTBSSLOAD, 0, }, + { offsetof(tDot11fBeaconIEs, ExtCap), offsetof(tDot11fIEExtCap, present), + 0, "ExtCap", 0, 3, 17, SigIeExtCap, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_EXTCAP, 0, }, + { offsetof(tDot11fBeaconIEs, OperatingMode), + offsetof(tDot11fIEOperatingMode, present), 0, "OperatingMode", + 0, 3, 3, SigIeOperatingMode, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_OPERATINGMODE, 0, }, + { offsetof(tDot11fBeaconIEs, WiderBWChanSwitchAnn), + offsetof(tDot11fIEWiderBWChanSwitchAnn, present), 0, + "WiderBWChanSwitchAnn", 0, 5, 5, SigIeWiderBWChanSwitchAnn, + {0, 0, 0, 0, 0}, 0, DOT11F_EID_WIDERBWCHANSWITCHANN, 0, }, + { offsetof(tDot11fBeaconIEs, OBSSScanParameters), + offsetof(tDot11fIEOBSSScanParameters, present), 0, "OBSSScanParameters", + 0, 16, 16, SigIeOBSSScanParameters, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_OBSSSCANPARAMETERS, 0, }, + { offsetof(tDot11fBeaconIEs, Vendor1IE), offsetof(tDot11fIEVendor1IE, + present), 0, "Vendor1IE", 0, 5, 5, SigIeVendor1IE, {0, 16, 24, 0, 0}, + 3, DOT11F_EID_VENDOR1IE, 0, }, + { offsetof(tDot11fBeaconIEs, vendor_vht_ie), + offsetof(tDot11fIEvendor_vht_ie, present), 0, "vendor_vht_ie", + 0, 7, 28, SigIevendor_vht_ie, {0, 144, 76, 0, 0}, + 3, DOT11F_EID_VENDOR_VHT_IE, 0, }, + { offsetof(tDot11fBeaconIEs, Vendor3IE), offsetof(tDot11fIEVendor3IE, + present), 0, "Vendor3IE", 0, 5, 5, SigIeVendor3IE, {0, 22, 50, 0, 0}, + 3, DOT11F_EID_VENDOR3IE, 0, }, + { offsetof(tDot11fBeaconIEs, hs20vendor_ie), + offsetof(tDot11fIEhs20vendor_ie, present), 0, "hs20vendor_ie", + 0, 7, 9, SigIehs20vendor_ie, {80, 111, 154, 16, 0}, + 4, DOT11F_EID_HS20VENDOR_IE, 0, }, + { offsetof(tDot11fBeaconIEs, ChannelSwitchWrapper), + offsetof(tDot11fIEChannelSwitchWrapper, present), 0, + "ChannelSwitchWrapper", 0, 2, 14, SigIeChannelSwitchWrapper, + {0, 0, 0, 0, 0}, 0, DOT11F_EID_CHANNELSWITCHWRAPPER, 0, }, + { offsetof(tDot11fBeaconIEs, QComVendorIE), + offsetof(tDot11fIEQComVendorIE, present), 0, "QComVendorIE", + 0, 7, 7, SigIeQComVendorIE, {0, 160, 198, 0, 0}, + 3, DOT11F_EID_QCOMVENDORIE, 0, }, + { offsetof(tDot11fBeaconIEs, MBO_IE), offsetof(tDot11fIEMBO_IE, present), + 0, "MBO_IE", 0, 9, 12, SigIeMBO_IE, {80, 111, 154, 22, 0}, + 4, DOT11F_EID_MBO_IE, 0, }, + { offsetof(tDot11fBeaconIEs, QCN_IE), offsetof(tDot11fIEQCN_IE, present), + 0, "QCN_IE", 0, 10, 10, SigIeQCN_IE, {140, 253, 240, 1, 0}, + 4, DOT11F_EID_QCN_IE, 0, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_beacon_i_es(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fBeaconIEs *pFrm) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_BeaconIEs, IES_BeaconIEs, + (uint8_t *)pFrm, sizeof(*pFrm)); + + (void)i; + return status; + +} /* End dot11f_unpack_beacon_i_es. */ + +static const tFFDefn FFS_ChannelSwitch[] = { + { "Category", offsetof(tDot11fChannelSwitch, Category), SigFfCategory, + DOT11F_FF_CATEGORY_LEN, }, + { "Action", offsetof(tDot11fChannelSwitch, Action), SigFfAction, + DOT11F_FF_ACTION_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_ChannelSwitch[] = { + { offsetof(tDot11fChannelSwitch, ChanSwitchAnn), + offsetof(tDot11fIEChanSwitchAnn, present), 0, "ChanSwitchAnn", + 0, 5, 5, SigIeChanSwitchAnn, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_CHANSWITCHANN, 1, }, + { offsetof(tDot11fChannelSwitch, sec_chan_offset_ele), + offsetof(tDot11fIEsec_chan_offset_ele, present), 0, "sec_chan_offset_ele", + 0, 3, 3, SigIesec_chan_offset_ele, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_SEC_CHAN_OFFSET_ELE, 0, }, + { offsetof(tDot11fChannelSwitch, WiderBWChanSwitchAnn), + offsetof(tDot11fIEWiderBWChanSwitchAnn, present), 0, + "WiderBWChanSwitchAnn", 0, 5, 5, SigIeWiderBWChanSwitchAnn, + {0, 0, 0, 0, 0}, 0, DOT11F_EID_WIDERBWCHANSWITCHANN, 0, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_channel_switch(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fChannelSwitch *pFrm) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_ChannelSwitch, IES_ChannelSwitch, + (uint8_t *)pFrm, sizeof(*pFrm)); + + (void)i; + return status; + +} /* End dot11f_unpack_channel_switch. */ + +static const tFFDefn FFS_DeAuth[] = { + { "Reason", offsetof(tDot11fDeAuth, Reason), SigFfReason, + DOT11F_FF_REASON_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_DeAuth[] = { + { offsetof(tDot11fDeAuth, P2PDeAuth), offsetof(tDot11fIEP2PDeAuth, + present), 0, "P2PDeAuth", 0, 6, 10, SigIeP2PDeAuth, {80, 111, 154, 9, 0}, + 4, DOT11F_EID_P2PDEAUTH, 0, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_de_auth(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fDeAuth *pFrm) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_DeAuth, IES_DeAuth, + (uint8_t *)pFrm, sizeof(*pFrm)); + + (void)i; + return status; + +} /* End dot11f_unpack_de_auth. */ + +static const tFFDefn FFS_DelTS[] = { + { "Category", offsetof(tDot11fDelTS, Category), SigFfCategory, + DOT11F_FF_CATEGORY_LEN, }, + { "Action", offsetof(tDot11fDelTS, Action), SigFfAction, + DOT11F_FF_ACTION_LEN, }, + { "TSInfo", offsetof(tDot11fDelTS, TSInfo), SigFfTSInfo, + DOT11F_FF_TSINFO_LEN, }, + { "Reason", offsetof(tDot11fDelTS, Reason), SigFfReason, + DOT11F_FF_REASON_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_DelTS[] = { + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_del_ts(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fDelTS *pFrm) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_DelTS, IES_DelTS, + (uint8_t *)pFrm, sizeof(*pFrm)); + + (void)i; + return status; + +} /* End dot11f_unpack_del_ts. */ + +static const tFFDefn FFS_Disassociation[] = { + { "Reason", offsetof(tDot11fDisassociation, Reason), SigFfReason, + DOT11F_FF_REASON_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_Disassociation[] = { + { offsetof(tDot11fDisassociation, P2PDisAssoc), + offsetof(tDot11fIEP2PDisAssoc, present), 0, "P2PDisAssoc", + 0, 6, 10, SigIeP2PDisAssoc, {80, 111, 154, 9, 0}, + 4, DOT11F_EID_P2PDISASSOC, 0, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_disassociation(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fDisassociation *pFrm) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_Disassociation, IES_Disassociation, + (uint8_t *)pFrm, sizeof(*pFrm)); + + (void)i; + return status; + +} /* End dot11f_unpack_disassociation. */ + +static const tFFDefn FFS_LinkMeasurementReport[] = { + { "Category", offsetof(tDot11fLinkMeasurementReport, Category), + SigFfCategory, DOT11F_FF_CATEGORY_LEN, }, + { "Action", offsetof(tDot11fLinkMeasurementReport, Action), SigFfAction, + DOT11F_FF_ACTION_LEN, }, + { "DialogToken", offsetof(tDot11fLinkMeasurementReport, DialogToken), + SigFfDialogToken, DOT11F_FF_DIALOGTOKEN_LEN, }, + { "TPCEleID", offsetof(tDot11fLinkMeasurementReport, TPCEleID), + SigFfTPCEleID, DOT11F_FF_TPCELEID_LEN, }, + { "TPCEleLen", offsetof(tDot11fLinkMeasurementReport, TPCEleLen), + SigFfTPCEleLen, DOT11F_FF_TPCELELEN_LEN, }, + { "TxPower", offsetof(tDot11fLinkMeasurementReport, TxPower), + SigFfTxPower, DOT11F_FF_TXPOWER_LEN, }, + { "LinkMargin", offsetof(tDot11fLinkMeasurementReport, LinkMargin), + SigFfLinkMargin, DOT11F_FF_LINKMARGIN_LEN, }, + { "RxAntennaId", offsetof(tDot11fLinkMeasurementReport, RxAntennaId), + SigFfRxAntennaId, DOT11F_FF_RXANTENNAID_LEN, }, + { "TxAntennaId", offsetof(tDot11fLinkMeasurementReport, TxAntennaId), + SigFfTxAntennaId, DOT11F_FF_TXANTENNAID_LEN, }, + { "RCPI", offsetof(tDot11fLinkMeasurementReport, RCPI), SigFfRCPI, + DOT11F_FF_RCPI_LEN, }, + { "RSNI", offsetof(tDot11fLinkMeasurementReport, RSNI), SigFfRSNI, + DOT11F_FF_RSNI_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_LinkMeasurementReport[] = { + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_link_measurement_report(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fLinkMeasurementReport *pFrm) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_LinkMeasurementReport, IES_LinkMeasurementReport, + (uint8_t *)pFrm, sizeof(*pFrm)); + + (void)i; + return status; + +} /* End dot11f_unpack_link_measurement_report. */ + +static const tFFDefn FFS_LinkMeasurementRequest[] = { + { "Category", offsetof(tDot11fLinkMeasurementRequest, Category), + SigFfCategory, DOT11F_FF_CATEGORY_LEN, }, + { "Action", offsetof(tDot11fLinkMeasurementRequest, Action), SigFfAction, + DOT11F_FF_ACTION_LEN, }, + { "DialogToken", offsetof(tDot11fLinkMeasurementRequest, DialogToken), + SigFfDialogToken, DOT11F_FF_DIALOGTOKEN_LEN, }, + { "TxPower", offsetof(tDot11fLinkMeasurementRequest, TxPower), + SigFfTxPower, DOT11F_FF_TXPOWER_LEN, }, + { "MaxTxPower", offsetof(tDot11fLinkMeasurementRequest, MaxTxPower), + SigFfMaxTxPower, DOT11F_FF_MAXTXPOWER_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_LinkMeasurementRequest[] = { + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_link_measurement_request(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fLinkMeasurementRequest *pFrm) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_LinkMeasurementRequest, IES_LinkMeasurementRequest, + (uint8_t *)pFrm, sizeof(*pFrm)); + + (void)i; + return status; + +} /* End dot11f_unpack_link_measurement_request. */ + +static const tFFDefn FFS_MeasurementReport[] = { + { "Category", offsetof(tDot11fMeasurementReport, Category), SigFfCategory, + DOT11F_FF_CATEGORY_LEN, }, + { "Action", offsetof(tDot11fMeasurementReport, Action), SigFfAction, + DOT11F_FF_ACTION_LEN, }, + { "DialogToken", offsetof(tDot11fMeasurementReport, DialogToken), + SigFfDialogToken, DOT11F_FF_DIALOGTOKEN_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_MeasurementReport[] = { + { offsetof(tDot11fMeasurementReport, MeasurementReport), + offsetof(tDot11fIEMeasurementReport, present), 0, "MeasurementReport", + 0, 5, 31, SigIeMeasurementReport, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_MEASUREMENTREPORT, 1, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_measurement_report(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fMeasurementReport *pFrm) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_MeasurementReport, IES_MeasurementReport, + (uint8_t *)pFrm, sizeof(*pFrm)); + + (void)i; + return status; + +} /* End dot11f_unpack_measurement_report. */ + +static const tFFDefn FFS_MeasurementRequest[] = { + { "Category", offsetof(tDot11fMeasurementRequest, Category), + SigFfCategory, DOT11F_FF_CATEGORY_LEN, }, + { "Action", offsetof(tDot11fMeasurementRequest, Action), SigFfAction, + DOT11F_FF_ACTION_LEN, }, + { "DialogToken", offsetof(tDot11fMeasurementRequest, DialogToken), + SigFfDialogToken, DOT11F_FF_DIALOGTOKEN_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_MeasurementRequest[] = { + { offsetof(tDot11fMeasurementRequest, MeasurementRequest), + offsetof(tDot11fIEMeasurementRequest, present), + offsetof(tDot11fMeasurementRequest, num_MeasurementRequest), + "MeasurementRequest", 4, 6, 18, SigIeMeasurementRequest, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_MEASUREMENTREQUEST, 1, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_measurement_request(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fMeasurementRequest *pFrm) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_MeasurementRequest, IES_MeasurementRequest, + (uint8_t *)pFrm, sizeof(*pFrm)); + + (void)i; + return status; + +} /* End dot11f_unpack_measurement_request. */ + +static const tFFDefn FFS_NeighborReportRequest[] = { + { "Category", offsetof(tDot11fNeighborReportRequest, Category), + SigFfCategory, DOT11F_FF_CATEGORY_LEN, }, + { "Action", offsetof(tDot11fNeighborReportRequest, Action), SigFfAction, + DOT11F_FF_ACTION_LEN, }, + { "DialogToken", offsetof(tDot11fNeighborReportRequest, DialogToken), + SigFfDialogToken, DOT11F_FF_DIALOGTOKEN_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_NeighborReportRequest[] = { + { offsetof(tDot11fNeighborReportRequest, SSID), offsetof(tDot11fIESSID, + present), 0, "SSID", 0, 2, 34, SigIeSSID, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_SSID, 0, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_neighbor_report_request(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fNeighborReportRequest *pFrm) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_NeighborReportRequest, IES_NeighborReportRequest, + (uint8_t *)pFrm, sizeof(*pFrm)); + + (void)i; + return status; + +} /* End dot11f_unpack_neighbor_report_request. */ + +static const tFFDefn FFS_NeighborReportResponse[] = { + { "Category", offsetof(tDot11fNeighborReportResponse, Category), + SigFfCategory, DOT11F_FF_CATEGORY_LEN, }, + { "Action", offsetof(tDot11fNeighborReportResponse, Action), SigFfAction, + DOT11F_FF_ACTION_LEN, }, + { "DialogToken", offsetof(tDot11fNeighborReportResponse, DialogToken), + SigFfDialogToken, DOT11F_FF_DIALOGTOKEN_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_NeighborReportResponse[] = { + { offsetof(tDot11fNeighborReportResponse, NeighborReport), + offsetof(tDot11fIENeighborReport, present), + offsetof(tDot11fNeighborReportResponse, num_NeighborReport), + "NeighborReport", 15, 15, 548, SigIeNeighborReport, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_NEIGHBORREPORT, 0, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_neighbor_report_response(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fNeighborReportResponse *pFrm) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_NeighborReportResponse, IES_NeighborReportResponse, + (uint8_t *)pFrm, sizeof(*pFrm)); + + (void)i; + return status; + +} /* End dot11f_unpack_neighbor_report_response. */ + +static const tFFDefn FFS_OperatingMode[] = { + { "Category", offsetof(tDot11fOperatingMode, Category), SigFfCategory, + DOT11F_FF_CATEGORY_LEN, }, + { "Action", offsetof(tDot11fOperatingMode, Action), SigFfAction, + DOT11F_FF_ACTION_LEN, }, + { "OperatingMode", offsetof(tDot11fOperatingMode, OperatingMode), + SigFfOperatingMode, DOT11F_FF_OPERATINGMODE_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_OperatingMode[] = { + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_operating_mode(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fOperatingMode *pFrm) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_OperatingMode, IES_OperatingMode, + (uint8_t *)pFrm, sizeof(*pFrm)); + + (void)i; + return status; + +} /* End dot11f_unpack_operating_mode. */ + +static const tFFDefn FFS_ProbeRequest[] = { + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_ProbeRequest[] = { + { offsetof(tDot11fProbeRequest, SSID), offsetof(tDot11fIESSID, present), 0, + "SSID", 0, 2, 34, SigIeSSID, {0, 0, 0, 0, 0}, 0, DOT11F_EID_SSID, 1, }, + { offsetof(tDot11fProbeRequest, SuppRates), offsetof(tDot11fIESuppRates, + present), 0, "SuppRates", 0, 2, 14, SigIeSuppRates, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_SUPPRATES, 1, }, + { offsetof(tDot11fProbeRequest, RequestedInfo), + offsetof(tDot11fIERequestedInfo, present), 0, "RequestedInfo", + 0, 2, 257, SigIeRequestedInfo, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_REQUESTEDINFO, 0, }, + { offsetof(tDot11fProbeRequest, ExtSuppRates), + offsetof(tDot11fIEExtSuppRates, present), 0, "ExtSuppRates", + 0, 3, 14, SigIeExtSuppRates, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_EXTSUPPRATES, 0, }, + { offsetof(tDot11fProbeRequest, DSParams), offsetof(tDot11fIEDSParams, + present), 0, "DSParams", 0, 3, 3, SigIeDSParams, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_DSPARAMS, 0, }, + { offsetof(tDot11fProbeRequest, HTCaps), offsetof(tDot11fIEHTCaps, + present), 0, "HTCaps", 0, 28, 60, SigIeHTCaps, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_HTCAPS, 0, }, + { offsetof(tDot11fProbeRequest, WscProbeReq), + offsetof(tDot11fIEWscProbeReq, present), 0, "WscProbeReq", + 0, 6, 286, SigIeWscProbeReq, {0, 80, 242, 4, 0}, + 4, DOT11F_EID_WSCPROBEREQ, 0, }, + { offsetof(tDot11fProbeRequest, WFATPC), offsetof(tDot11fIEWFATPC, + present), 0, "WFATPC", 0, 9, 9, SigIeWFATPC, {0, 80, 242, 8, 0}, + 5, DOT11F_EID_WFATPC, 0, }, + { offsetof(tDot11fProbeRequest, P2PProbeReq), + offsetof(tDot11fIEP2PProbeReq, present), 0, "P2PProbeReq", + 0, 6, 43, SigIeP2PProbeReq, {80, 111, 154, 9, 0}, + 4, DOT11F_EID_P2PPROBEREQ, 0, }, + { offsetof(tDot11fProbeRequest, VHTCaps), offsetof(tDot11fIEVHTCaps, + present), 0, "VHTCaps", 0, 14, 14, SigIeVHTCaps, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_VHTCAPS, 0, }, + { offsetof(tDot11fProbeRequest, ExtCap), offsetof(tDot11fIEExtCap, + present), 0, "ExtCap", 0, 3, 17, SigIeExtCap, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_EXTCAP, 0, }, + { offsetof(tDot11fProbeRequest, QCN_IE), offsetof(tDot11fIEQCN_IE, + present), 0, "QCN_IE", 0, 10, 10, SigIeQCN_IE, {140, 253, 240, 1, 0}, + 4, DOT11F_EID_QCN_IE, 0, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_probe_request(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fProbeRequest *pFrm) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_ProbeRequest, IES_ProbeRequest, + (uint8_t *)pFrm, sizeof(*pFrm)); + + (void)i; + return status; + +} /* End dot11f_unpack_probe_request. */ + +static const tFFDefn FFS_ProbeResponse[] = { + { "TimeStamp", offsetof(tDot11fProbeResponse, TimeStamp), SigFfTimeStamp, + DOT11F_FF_TIMESTAMP_LEN, }, + { "BeaconInterval", offsetof(tDot11fProbeResponse, BeaconInterval), + SigFfBeaconInterval, DOT11F_FF_BEACONINTERVAL_LEN, }, + { "Capabilities", offsetof(tDot11fProbeResponse, Capabilities), + SigFfCapabilities, DOT11F_FF_CAPABILITIES_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_ProbeResponse[] = { + { offsetof(tDot11fProbeResponse, SSID), offsetof(tDot11fIESSID, present), + 0, "SSID", 0, 2, 34, SigIeSSID, {0, 0, 0, 0, 0}, 0, DOT11F_EID_SSID, 1, }, + { offsetof(tDot11fProbeResponse, SuppRates), offsetof(tDot11fIESuppRates, + present), 0, "SuppRates", 0, 2, 14, SigIeSuppRates, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_SUPPRATES, 1, }, + { offsetof(tDot11fProbeResponse, FHParamSet), + offsetof(tDot11fIEFHParamSet, present), 0, "FHParamSet", + 0, 7, 7, SigIeFHParamSet, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_FHPARAMSET, 0, }, + { offsetof(tDot11fProbeResponse, DSParams), offsetof(tDot11fIEDSParams, + present), 0, "DSParams", 0, 3, 3, SigIeDSParams, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_DSPARAMS, 0, }, + { offsetof(tDot11fProbeResponse, CFParams), offsetof(tDot11fIECFParams, + present), 0, "CFParams", 0, 8, 8, SigIeCFParams, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_CFPARAMS, 0, }, + { offsetof(tDot11fProbeResponse, IBSSParams), + offsetof(tDot11fIEIBSSParams, present), 0, "IBSSParams", + 0, 4, 4, SigIeIBSSParams, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_IBSSPARAMS, 0, }, + { offsetof(tDot11fProbeResponse, Country), offsetof(tDot11fIECountry, + present), 0, "Country", 0, 5, 257, SigIeCountry, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_COUNTRY, 0, }, + { offsetof(tDot11fProbeResponse, FHParams), offsetof(tDot11fIEFHParams, + present), 0, "FHParams", 0, 4, 4, SigIeFHParams, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_FHPARAMS, 0, }, + { offsetof(tDot11fProbeResponse, FHPattTable), + offsetof(tDot11fIEFHPattTable, present), 0, "FHPattTable", + 0, 6, 257, SigIeFHPattTable, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_FHPATTTABLE, 0, }, + { offsetof(tDot11fProbeResponse, PowerConstraints), + offsetof(tDot11fIEPowerConstraints, present), 0, "PowerConstraints", + 0, 3, 3, SigIePowerConstraints, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_POWERCONSTRAINTS, 0, }, + { offsetof(tDot11fProbeResponse, ChanSwitchAnn), + offsetof(tDot11fIEChanSwitchAnn, present), 0, "ChanSwitchAnn", + 0, 5, 5, SigIeChanSwitchAnn, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_CHANSWITCHANN, 0, }, + { offsetof(tDot11fProbeResponse, ext_chan_switch_ann), + offsetof(tDot11fIEext_chan_switch_ann, present), 0, "ext_chan_switch_ann", + 0, 6, 6, SigIeext_chan_switch_ann, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_EXT_CHAN_SWITCH_ANN, 0, }, + { offsetof(tDot11fProbeResponse, SuppOperatingClasses), + offsetof(tDot11fIESuppOperatingClasses, present), 0, + "SuppOperatingClasses", 0, 3, 34, SigIeSuppOperatingClasses, + {0, 0, 0, 0, 0}, 0, DOT11F_EID_SUPPOPERATINGCLASSES, 0, }, + { offsetof(tDot11fProbeResponse, Quiet), offsetof(tDot11fIEQuiet, + present), 0, "Quiet", 0, 8, 8, SigIeQuiet, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_QUIET, 0, }, + { offsetof(tDot11fProbeResponse, TPCReport), offsetof(tDot11fIETPCReport, + present), 0, "TPCReport", 0, 4, 4, SigIeTPCReport, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_TPCREPORT, 0, }, + { offsetof(tDot11fProbeResponse, ERPInfo), offsetof(tDot11fIEERPInfo, + present), 0, "ERPInfo", 0, 3, 3, SigIeERPInfo, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_ERPINFO, 0, }, + { offsetof(tDot11fProbeResponse, ExtSuppRates), + offsetof(tDot11fIEExtSuppRates, present), 0, "ExtSuppRates", + 0, 3, 14, SigIeExtSuppRates, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_EXTSUPPRATES, 0, }, + { offsetof(tDot11fProbeResponse, RSNOpaque), offsetof(tDot11fIERSNOpaque, + present), 0, "RSNOpaque", 0, 8, 255, SigIeRSNOpaque, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_RSNOPAQUE, 0, }, + { offsetof(tDot11fProbeResponse, QBSSLoad), offsetof(tDot11fIEQBSSLoad, + present), 0, "QBSSLoad", 0, 7, 7, SigIeQBSSLoad, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_QBSSLOAD, 0, }, + { offsetof(tDot11fProbeResponse, EDCAParamSet), + offsetof(tDot11fIEEDCAParamSet, present), 0, "EDCAParamSet", + 0, 20, 20, SigIeEDCAParamSet, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_EDCAPARAMSET, 0, }, + { offsetof(tDot11fProbeResponse, RRMEnabledCap), + offsetof(tDot11fIERRMEnabledCap, present), 0, "RRMEnabledCap", + 0, 7, 7, SigIeRRMEnabledCap, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_RRMENABLEDCAP, 0, }, + { offsetof(tDot11fProbeResponse, APChannelReport), + offsetof(tDot11fIEAPChannelReport, present), 0, "APChannelReport", + 0, 3, 53, SigIeAPChannelReport, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_APCHANNELREPORT, 0, }, + { offsetof(tDot11fProbeResponse, MobilityDomain), + offsetof(tDot11fIEMobilityDomain, present), 0, "MobilityDomain", + 0, 5, 5, SigIeMobilityDomain, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_MOBILITYDOMAIN, 0, }, + { offsetof(tDot11fProbeResponse, WPA), offsetof(tDot11fIEWPA, present), 0, + "WPA", 0, 8, 50, SigIeWPA, {0, 80, 242, 1, 0}, 4, DOT11F_EID_WPA, 0, }, + { offsetof(tDot11fProbeResponse, HTCaps), offsetof(tDot11fIEHTCaps, + present), 0, "HTCaps", 0, 28, 60, SigIeHTCaps, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_HTCAPS, 0, }, + { offsetof(tDot11fProbeResponse, HTInfo), offsetof(tDot11fIEHTInfo, + present), 0, "HTInfo", 0, 24, 56, SigIeHTInfo, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_HTINFO, 0, }, + { offsetof(tDot11fProbeResponse, sec_chan_offset_ele), + offsetof(tDot11fIEsec_chan_offset_ele, present), 0, "sec_chan_offset_ele", + 0, 3, 3, SigIesec_chan_offset_ele, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_SEC_CHAN_OFFSET_ELE, 0, }, + { offsetof(tDot11fProbeResponse, WMMInfoAp), offsetof(tDot11fIEWMMInfoAp, + present), 0, "WMMInfoAp", 0, 9, 9, SigIeWMMInfoAp, {0, 80, 242, 2, 0}, + 5, DOT11F_EID_WMMINFOAP, 0, }, + { offsetof(tDot11fProbeResponse, WMMParams), offsetof(tDot11fIEWMMParams, + present), 0, "WMMParams", 0, 26, 26, SigIeWMMParams, {0, 80, 242, 2, 1}, + 5, DOT11F_EID_WMMPARAMS, 0, }, + { offsetof(tDot11fProbeResponse, WMMCaps), offsetof(tDot11fIEWMMCaps, + present), 0, "WMMCaps", 0, 9, 9, SigIeWMMCaps, {0, 80, 242, 2, 5}, + 5, DOT11F_EID_WMMCAPS, 0, }, + { offsetof(tDot11fProbeResponse, WAPI), offsetof(tDot11fIEWAPI, present), + 0, "WAPI", 0, 14, 112, SigIeWAPI, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_WAPI, 0, }, + { offsetof(tDot11fProbeResponse, ESERadMgmtCap), + offsetof(tDot11fIEESERadMgmtCap, present), 0, "ESERadMgmtCap", + 0, 8, 8, SigIeESERadMgmtCap, {0, 64, 150, 1, 0}, + 4, DOT11F_EID_ESERADMGMTCAP, 0, }, + { offsetof(tDot11fProbeResponse, ESETrafStrmMet), + offsetof(tDot11fIEESETrafStrmMet, present), 0, "ESETrafStrmMet", + 0, 10, 10, SigIeESETrafStrmMet, {0, 64, 150, 7, 0}, + 4, DOT11F_EID_ESETRAFSTRMMET, 0, }, + { offsetof(tDot11fProbeResponse, ESETxmitPower), + offsetof(tDot11fIEESETxmitPower, present), 0, "ESETxmitPower", + 0, 8, 8, SigIeESETxmitPower, {0, 64, 150, 0, 0}, + 4, DOT11F_EID_ESETXMITPOWER, 0, }, + { offsetof(tDot11fProbeResponse, WscProbeRes), + offsetof(tDot11fIEWscProbeRes, present), 0, "WscProbeRes", + 0, 6, 319, SigIeWscProbeRes, {0, 80, 242, 4, 0}, + 4, DOT11F_EID_WSCPROBERES, 0, }, + { offsetof(tDot11fProbeResponse, P2PProbeRes), + offsetof(tDot11fIEP2PProbeRes, present), 0, "P2PProbeRes", + 0, 6, 1141, SigIeP2PProbeRes, {80, 111, 154, 9, 0}, + 4, DOT11F_EID_P2PPROBERES, 0, }, + { offsetof(tDot11fProbeResponse, VHTCaps), offsetof(tDot11fIEVHTCaps, + present), 0, "VHTCaps", 0, 14, 14, SigIeVHTCaps, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_VHTCAPS, 0, }, + { offsetof(tDot11fProbeResponse, VHTOperation), + offsetof(tDot11fIEVHTOperation, present), 0, "VHTOperation", + 0, 7, 7, SigIeVHTOperation, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_VHTOPERATION, 0, }, + { offsetof(tDot11fProbeResponse, VHTExtBssLoad), + offsetof(tDot11fIEVHTExtBssLoad, present), 0, "VHTExtBssLoad", + 0, 7, 7, SigIeVHTExtBssLoad, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_VHTEXTBSSLOAD, 0, }, + { offsetof(tDot11fProbeResponse, ExtCap), offsetof(tDot11fIEExtCap, + present), 0, "ExtCap", 0, 3, 17, SigIeExtCap, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_EXTCAP, 0, }, + { offsetof(tDot11fProbeResponse, OBSSScanParameters), + offsetof(tDot11fIEOBSSScanParameters, present), 0, "OBSSScanParameters", + 0, 16, 16, SigIeOBSSScanParameters, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_OBSSSCANPARAMETERS, 0, }, + { offsetof(tDot11fProbeResponse, Vendor1IE), offsetof(tDot11fIEVendor1IE, + present), 0, "Vendor1IE", 0, 5, 5, SigIeVendor1IE, {0, 16, 24, 0, 0}, + 3, DOT11F_EID_VENDOR1IE, 0, }, + { offsetof(tDot11fProbeResponse, vendor_vht_ie), + offsetof(tDot11fIEvendor_vht_ie, present), 0, "vendor_vht_ie", + 0, 7, 28, SigIevendor_vht_ie, {0, 144, 76, 0, 0}, + 3, DOT11F_EID_VENDOR_VHT_IE, 0, }, + { offsetof(tDot11fProbeResponse, Vendor3IE), offsetof(tDot11fIEVendor3IE, + present), 0, "Vendor3IE", 0, 5, 5, SigIeVendor3IE, {0, 22, 50, 0, 0}, + 3, DOT11F_EID_VENDOR3IE, 0, }, + { offsetof(tDot11fProbeResponse, hs20vendor_ie), + offsetof(tDot11fIEhs20vendor_ie, present), 0, "hs20vendor_ie", + 0, 7, 9, SigIehs20vendor_ie, {80, 111, 154, 16, 0}, + 4, DOT11F_EID_HS20VENDOR_IE, 0, }, + { offsetof(tDot11fProbeResponse, ChannelSwitchWrapper), + offsetof(tDot11fIEChannelSwitchWrapper, present), 0, + "ChannelSwitchWrapper", 0, 2, 14, SigIeChannelSwitchWrapper, + {0, 0, 0, 0, 0}, 0, DOT11F_EID_CHANNELSWITCHWRAPPER, 0, }, + { offsetof(tDot11fProbeResponse, QComVendorIE), + offsetof(tDot11fIEQComVendorIE, present), 0, "QComVendorIE", + 0, 7, 7, SigIeQComVendorIE, {0, 160, 198, 0, 0}, + 3, DOT11F_EID_QCOMVENDORIE, 0, }, + { offsetof(tDot11fProbeResponse, ESEVersion), + offsetof(tDot11fIEESEVersion, present), 0, "ESEVersion", + 0, 7, 7, SigIeESEVersion, {0, 64, 150, 3, 0}, + 4, DOT11F_EID_ESEVERSION, 0, }, + { offsetof(tDot11fProbeResponse, MBO_IE), offsetof(tDot11fIEMBO_IE, + present), 0, "MBO_IE", 0, 9, 12, SigIeMBO_IE, {80, 111, 154, 22, 0}, + 4, DOT11F_EID_MBO_IE, 0, }, + { offsetof(tDot11fProbeResponse, QCN_IE), offsetof(tDot11fIEQCN_IE, + present), 0, "QCN_IE", 0, 10, 10, SigIeQCN_IE, {140, 253, 240, 1, 0}, + 4, DOT11F_EID_QCN_IE, 0, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_probe_response(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fProbeResponse *pFrm) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_ProbeResponse, IES_ProbeResponse, + (uint8_t *)pFrm, sizeof(*pFrm)); + + (void)i; + return status; + +} /* End dot11f_unpack_probe_response. */ + +static const tFFDefn FFS_QosMapConfigure[] = { + { "Category", offsetof(tDot11fQosMapConfigure, Category), SigFfCategory, + DOT11F_FF_CATEGORY_LEN, }, + { "Action", offsetof(tDot11fQosMapConfigure, Action), SigFfAction, + DOT11F_FF_ACTION_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_QosMapConfigure[] = { + { offsetof(tDot11fQosMapConfigure, QosMapSet), + offsetof(tDot11fIEQosMapSet, present), 0, "QosMapSet", + 0, 2, 62, SigIeQosMapSet, {0, 0, 0, 0, 0}, 0, DOT11F_EID_QOSMAPSET, 1, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_qos_map_configure(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fQosMapConfigure *pFrm) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_QosMapConfigure, IES_QosMapConfigure, + (uint8_t *)pFrm, sizeof(*pFrm)); + + (void)i; + return status; + +} /* End dot11f_unpack_qos_map_configure. */ + +static const tFFDefn FFS_RadioMeasurementReport[] = { + { "Category", offsetof(tDot11fRadioMeasurementReport, Category), + SigFfCategory, DOT11F_FF_CATEGORY_LEN, }, + { "Action", offsetof(tDot11fRadioMeasurementReport, Action), SigFfAction, + DOT11F_FF_ACTION_LEN, }, + { "DialogToken", offsetof(tDot11fRadioMeasurementReport, DialogToken), + SigFfDialogToken, DOT11F_FF_DIALOGTOKEN_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_RadioMeasurementReport[] = { + { offsetof(tDot11fRadioMeasurementReport, MeasurementReport), + offsetof(tDot11fIEMeasurementReport, present), + offsetof(tDot11fRadioMeasurementReport, num_MeasurementReport), + "MeasurementReport", 4, 5, 31, SigIeMeasurementReport, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_MEASUREMENTREPORT, 1, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_radio_measurement_report(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fRadioMeasurementReport *pFrm) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_RadioMeasurementReport, IES_RadioMeasurementReport, + (uint8_t *)pFrm, sizeof(*pFrm)); + + (void)i; + return status; + +} /* End dot11f_unpack_radio_measurement_report. */ + +static const tFFDefn FFS_RadioMeasurementRequest[] = { + { "Category", offsetof(tDot11fRadioMeasurementRequest, Category), + SigFfCategory, DOT11F_FF_CATEGORY_LEN, }, + { "Action", offsetof(tDot11fRadioMeasurementRequest, Action), SigFfAction, + DOT11F_FF_ACTION_LEN, }, + { "DialogToken", offsetof(tDot11fRadioMeasurementRequest, DialogToken), + SigFfDialogToken, DOT11F_FF_DIALOGTOKEN_LEN, }, + { "NumOfRepetitions", offsetof(tDot11fRadioMeasurementRequest, + NumOfRepetitions), SigFfNumOfRepetitions, + DOT11F_FF_NUMOFREPETITIONS_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_RadioMeasurementRequest[] = { + { offsetof(tDot11fRadioMeasurementRequest, MeasurementRequest), + offsetof(tDot11fIEMeasurementRequest, present), + offsetof(tDot11fRadioMeasurementRequest, num_MeasurementRequest), + "MeasurementRequest", 2, 6, 18, SigIeMeasurementRequest, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_MEASUREMENTREQUEST, 1, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_radio_measurement_request(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fRadioMeasurementRequest *pFrm) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_RadioMeasurementRequest, IES_RadioMeasurementRequest, + (uint8_t *)pFrm, sizeof(*pFrm)); + + (void)i; + return status; + +} /* End dot11f_unpack_radio_measurement_request. */ + +static const tFFDefn FFS_ReAssocRequest[] = { + { "Capabilities", offsetof(tDot11fReAssocRequest, Capabilities), + SigFfCapabilities, DOT11F_FF_CAPABILITIES_LEN, }, + { "ListenInterval", offsetof(tDot11fReAssocRequest, ListenInterval), + SigFfListenInterval, DOT11F_FF_LISTENINTERVAL_LEN, }, + { "CurrentAPAddress", offsetof(tDot11fReAssocRequest, CurrentAPAddress), + SigFfCurrentAPAddress, DOT11F_FF_CURRENTAPADDRESS_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_ReAssocRequest[] = { + { offsetof(tDot11fReAssocRequest, SSID), offsetof(tDot11fIESSID, present), + 0, "SSID", 0, 2, 34, SigIeSSID, {0, 0, 0, 0, 0}, 0, DOT11F_EID_SSID, 1, }, + { offsetof(tDot11fReAssocRequest, SuppRates), + offsetof(tDot11fIESuppRates, present), 0, "SuppRates", + 0, 2, 14, SigIeSuppRates, {0, 0, 0, 0, 0}, 0, DOT11F_EID_SUPPRATES, 1, }, + { offsetof(tDot11fReAssocRequest, ExtSuppRates), + offsetof(tDot11fIEExtSuppRates, present), 0, "ExtSuppRates", + 0, 3, 14, SigIeExtSuppRates, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_EXTSUPPRATES, 0, }, + { offsetof(tDot11fReAssocRequest, PowerCaps), + offsetof(tDot11fIEPowerCaps, present), 0, "PowerCaps", + 0, 4, 4, SigIePowerCaps, {0, 0, 0, 0, 0}, 0, DOT11F_EID_POWERCAPS, 0, }, + { offsetof(tDot11fReAssocRequest, SuppChannels), + offsetof(tDot11fIESuppChannels, present), 0, "SuppChannels", + 0, 4, 98, SigIeSuppChannels, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_SUPPCHANNELS, 0, }, + { offsetof(tDot11fReAssocRequest, RSNOpaque), + offsetof(tDot11fIERSNOpaque, present), 0, "RSNOpaque", + 0, 8, 255, SigIeRSNOpaque, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_RSNOPAQUE, 0, }, + { offsetof(tDot11fReAssocRequest, QOSCapsStation), + offsetof(tDot11fIEQOSCapsStation, present), 0, "QOSCapsStation", + 0, 3, 3, SigIeQOSCapsStation, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_QOSCAPSSTATION, 0, }, + { offsetof(tDot11fReAssocRequest, RRMEnabledCap), + offsetof(tDot11fIERRMEnabledCap, present), 0, "RRMEnabledCap", + 0, 7, 7, SigIeRRMEnabledCap, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_RRMENABLEDCAP, 0, }, + { offsetof(tDot11fReAssocRequest, MobilityDomain), + offsetof(tDot11fIEMobilityDomain, present), 0, "MobilityDomain", + 0, 5, 5, SigIeMobilityDomain, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_MOBILITYDOMAIN, 0, }, + { offsetof(tDot11fReAssocRequest, FTInfo), offsetof(tDot11fIEFTInfo, + present), 0, "FTInfo", 0, 84, 222, SigIeFTInfo, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_FTINFO, 0, }, + { offsetof(tDot11fReAssocRequest, RICDataDesc), + offsetof(tDot11fIERICDataDesc, present), + offsetof(tDot11fReAssocRequest, num_RICDataDesc), "RICDataDesc", + 2, 2, 550, SigIeRICDataDesc, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_RICDATADESC, 0, }, + { offsetof(tDot11fReAssocRequest, WPAOpaque), + offsetof(tDot11fIEWPAOpaque, present), 0, "WPAOpaque", + 0, 8, 255, SigIeWPAOpaque, {0, 80, 242, 1, 0}, + 4, DOT11F_EID_WPAOPAQUE, 0, }, + { offsetof(tDot11fReAssocRequest, HTCaps), offsetof(tDot11fIEHTCaps, + present), 0, "HTCaps", 0, 28, 60, SigIeHTCaps, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_HTCAPS, 0, }, + { offsetof(tDot11fReAssocRequest, WMMCaps), offsetof(tDot11fIEWMMCaps, + present), 0, "WMMCaps", 0, 9, 9, SigIeWMMCaps, {0, 80, 242, 2, 5}, + 5, DOT11F_EID_WMMCAPS, 0, }, + { offsetof(tDot11fReAssocRequest, WMMInfoStation), + offsetof(tDot11fIEWMMInfoStation, present), 0, "WMMInfoStation", + 0, 9, 9, SigIeWMMInfoStation, {0, 80, 242, 2, 0}, + 5, DOT11F_EID_WMMINFOSTATION, 0, }, + { offsetof(tDot11fReAssocRequest, WscIEOpaque), + offsetof(tDot11fIEWscIEOpaque, present), 0, "WscIEOpaque", + 0, 8, 255, SigIeWscIEOpaque, {0, 80, 242, 4, 0}, + 4, DOT11F_EID_WSCIEOPAQUE, 0, }, + { offsetof(tDot11fReAssocRequest, WAPIOpaque), + offsetof(tDot11fIEWAPIOpaque, present), 0, "WAPIOpaque", + 0, 8, 255, SigIeWAPIOpaque, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_WAPIOPAQUE, 0, }, + { offsetof(tDot11fReAssocRequest, WAPI), offsetof(tDot11fIEWAPI, present), + 0, "WAPI", 0, 14, 112, SigIeWAPI, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_WAPI, 0, }, + { offsetof(tDot11fReAssocRequest, ESERadMgmtCap), + offsetof(tDot11fIEESERadMgmtCap, present), 0, "ESERadMgmtCap", + 0, 8, 8, SigIeESERadMgmtCap, {0, 64, 150, 1, 0}, + 4, DOT11F_EID_ESERADMGMTCAP, 0, }, + { offsetof(tDot11fReAssocRequest, ESEVersion), + offsetof(tDot11fIEESEVersion, present), 0, "ESEVersion", + 0, 7, 7, SigIeESEVersion, {0, 64, 150, 3, 0}, + 4, DOT11F_EID_ESEVERSION, 0, }, + { offsetof(tDot11fReAssocRequest, ESECckmOpaque), + offsetof(tDot11fIEESECckmOpaque, present), 0, "ESECckmOpaque", + 0, 12, 26, SigIeESECckmOpaque, {0, 64, 150, 0, 0}, + 4, DOT11F_EID_ESECCKMOPAQUE, 0, }, + { offsetof(tDot11fReAssocRequest, WMMTSPEC), offsetof(tDot11fIEWMMTSPEC, + present), offsetof(tDot11fReAssocRequest, num_WMMTSPEC), "WMMTSPEC", + 4, 63, 63, SigIeWMMTSPEC, {0, 80, 242, 2, 2}, + 5, DOT11F_EID_WMMTSPEC, 0, }, + { offsetof(tDot11fReAssocRequest, ESETrafStrmRateSet), + offsetof(tDot11fIEESETrafStrmRateSet, present), 0, "ESETrafStrmRateSet", + 0, 7, 15, SigIeESETrafStrmRateSet, {0, 64, 150, 8, 0}, + 4, DOT11F_EID_ESETRAFSTRMRATESET, 0, }, + { offsetof(tDot11fReAssocRequest, P2PIEOpaque), + offsetof(tDot11fIEP2PIEOpaque, present), 0, "P2PIEOpaque", + 0, 8, 255, SigIeP2PIEOpaque, {80, 111, 154, 9, 0}, + 4, DOT11F_EID_P2PIEOPAQUE, 0, }, + { offsetof(tDot11fReAssocRequest, WFDIEOpaque), + offsetof(tDot11fIEWFDIEOpaque, present), 0, "WFDIEOpaque", + 0, 8, 255, SigIeWFDIEOpaque, {80, 111, 154, 10, 0}, + 4, DOT11F_EID_WFDIEOPAQUE, 0, }, + { offsetof(tDot11fReAssocRequest, VHTCaps), offsetof(tDot11fIEVHTCaps, + present), 0, "VHTCaps", 0, 14, 14, SigIeVHTCaps, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_VHTCAPS, 0, }, + { offsetof(tDot11fReAssocRequest, ExtCap), offsetof(tDot11fIEExtCap, + present), 0, "ExtCap", 0, 3, 17, SigIeExtCap, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_EXTCAP, 0, }, + { offsetof(tDot11fReAssocRequest, OperatingMode), + offsetof(tDot11fIEOperatingMode, present), 0, "OperatingMode", + 0, 3, 3, SigIeOperatingMode, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_OPERATINGMODE, 0, }, + { offsetof(tDot11fReAssocRequest, QosMapSet), + offsetof(tDot11fIEQosMapSet, present), 0, "QosMapSet", + 0, 2, 62, SigIeQosMapSet, {0, 0, 0, 0, 0}, 0, DOT11F_EID_QOSMAPSET, 0, }, + { offsetof(tDot11fReAssocRequest, vendor_vht_ie), + offsetof(tDot11fIEvendor_vht_ie, present), 0, "vendor_vht_ie", + 0, 7, 28, SigIevendor_vht_ie, {0, 144, 76, 0, 0}, + 3, DOT11F_EID_VENDOR_VHT_IE, 0, }, + { offsetof(tDot11fReAssocRequest, hs20vendor_ie), + offsetof(tDot11fIEhs20vendor_ie, present), 0, "hs20vendor_ie", + 0, 7, 9, SigIehs20vendor_ie, {80, 111, 154, 16, 0}, + 4, DOT11F_EID_HS20VENDOR_IE, 0, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_re_assoc_request(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fReAssocRequest *pFrm) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_ReAssocRequest, IES_ReAssocRequest, + (uint8_t *)pFrm, sizeof(*pFrm)); + + (void)i; + return status; + +} /* End dot11f_unpack_re_assoc_request. */ + +static const tFFDefn FFS_ReAssocResponse[] = { + { "Capabilities", offsetof(tDot11fReAssocResponse, Capabilities), + SigFfCapabilities, DOT11F_FF_CAPABILITIES_LEN, }, + { "Status", offsetof(tDot11fReAssocResponse, Status), SigFfStatus, + DOT11F_FF_STATUS_LEN, }, + { "AID", offsetof(tDot11fReAssocResponse, AID), SigFfAID, + DOT11F_FF_AID_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_ReAssocResponse[] = { + { offsetof(tDot11fReAssocResponse, SuppRates), + offsetof(tDot11fIESuppRates, present), 0, "SuppRates", + 0, 2, 14, SigIeSuppRates, {0, 0, 0, 0, 0}, 0, DOT11F_EID_SUPPRATES, 1, }, + { offsetof(tDot11fReAssocResponse, ExtSuppRates), + offsetof(tDot11fIEExtSuppRates, present), 0, "ExtSuppRates", + 0, 3, 14, SigIeExtSuppRates, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_EXTSUPPRATES, 0, }, + { offsetof(tDot11fReAssocResponse, EDCAParamSet), + offsetof(tDot11fIEEDCAParamSet, present), 0, "EDCAParamSet", + 0, 20, 20, SigIeEDCAParamSet, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_EDCAPARAMSET, 0, }, + { offsetof(tDot11fReAssocResponse, RCPIIE), offsetof(tDot11fIERCPIIE, + present), 0, "RCPIIE", 0, 3, 3, SigIeRCPIIE, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_RCPIIE, 0, }, + { offsetof(tDot11fReAssocResponse, RSNIIE), offsetof(tDot11fIERSNIIE, + present), 0, "RSNIIE", 0, 3, 3, SigIeRSNIIE, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_RSNIIE, 0, }, + { offsetof(tDot11fReAssocResponse, RRMEnabledCap), + offsetof(tDot11fIERRMEnabledCap, present), 0, "RRMEnabledCap", + 0, 7, 7, SigIeRRMEnabledCap, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_RRMENABLEDCAP, 0, }, + { offsetof(tDot11fReAssocResponse, RSNOpaque), + offsetof(tDot11fIERSNOpaque, present), 0, "RSNOpaque", + 0, 8, 255, SigIeRSNOpaque, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_RSNOPAQUE, 0, }, + { offsetof(tDot11fReAssocResponse, MobilityDomain), + offsetof(tDot11fIEMobilityDomain, present), 0, "MobilityDomain", + 0, 5, 5, SigIeMobilityDomain, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_MOBILITYDOMAIN, 0, }, + { offsetof(tDot11fReAssocResponse, FTInfo), offsetof(tDot11fIEFTInfo, + present), 0, "FTInfo", 0, 84, 222, SigIeFTInfo, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_FTINFO, 0, }, + { offsetof(tDot11fReAssocResponse, RICDataDesc), + offsetof(tDot11fIERICDataDesc, present), + offsetof(tDot11fReAssocResponse, num_RICDataDesc), "RICDataDesc", + 2, 2, 550, SigIeRICDataDesc, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_RICDATADESC, 0, }, + { offsetof(tDot11fReAssocResponse, WPA), offsetof(tDot11fIEWPA, present), + 0, "WPA", 0, 8, 50, SigIeWPA, {0, 80, 242, 1, 0}, 4, DOT11F_EID_WPA, 0, }, + { offsetof(tDot11fReAssocResponse, TimeoutInterval), + offsetof(tDot11fIETimeoutInterval, present), 0, "TimeoutInterval", + 0, 7, 7, SigIeTimeoutInterval, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_TIMEOUTINTERVAL, 0, }, + { offsetof(tDot11fReAssocResponse, HTCaps), offsetof(tDot11fIEHTCaps, + present), 0, "HTCaps", 0, 28, 60, SigIeHTCaps, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_HTCAPS, 0, }, + { offsetof(tDot11fReAssocResponse, HTInfo), offsetof(tDot11fIEHTInfo, + present), 0, "HTInfo", 0, 24, 56, SigIeHTInfo, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_HTINFO, 0, }, + { offsetof(tDot11fReAssocResponse, WMMParams), + offsetof(tDot11fIEWMMParams, present), 0, "WMMParams", + 0, 26, 26, SigIeWMMParams, {0, 80, 242, 2, 1}, + 5, DOT11F_EID_WMMPARAMS, 0, }, + { offsetof(tDot11fReAssocResponse, ESERadMgmtCap), + offsetof(tDot11fIEESERadMgmtCap, present), 0, "ESERadMgmtCap", + 0, 8, 8, SigIeESERadMgmtCap, {0, 64, 150, 1, 0}, + 4, DOT11F_EID_ESERADMGMTCAP, 0, }, + { offsetof(tDot11fReAssocResponse, ESETrafStrmMet), + offsetof(tDot11fIEESETrafStrmMet, present), 0, "ESETrafStrmMet", + 0, 10, 10, SigIeESETrafStrmMet, {0, 64, 150, 7, 0}, + 4, DOT11F_EID_ESETRAFSTRMMET, 0, }, + { offsetof(tDot11fReAssocResponse, ESETxmitPower), + offsetof(tDot11fIEESETxmitPower, present), 0, "ESETxmitPower", + 0, 8, 8, SigIeESETxmitPower, {0, 64, 150, 0, 0}, + 4, DOT11F_EID_ESETXMITPOWER, 0, }, + { offsetof(tDot11fReAssocResponse, WMMTSPEC), offsetof(tDot11fIEWMMTSPEC, + present), offsetof(tDot11fReAssocResponse, num_WMMTSPEC), "WMMTSPEC", + 4, 63, 63, SigIeWMMTSPEC, {0, 80, 242, 2, 2}, + 5, DOT11F_EID_WMMTSPEC, 0, }, + { offsetof(tDot11fReAssocResponse, ESETrafStrmRateSet), + offsetof(tDot11fIEESETrafStrmRateSet, present), 0, "ESETrafStrmRateSet", + 0, 7, 15, SigIeESETrafStrmRateSet, {0, 64, 150, 8, 0}, + 4, DOT11F_EID_ESETRAFSTRMRATESET, 0, }, + { offsetof(tDot11fReAssocResponse, WscReassocRes), + offsetof(tDot11fIEWscReassocRes, present), 0, "WscReassocRes", + 0, 6, 37, SigIeWscReassocRes, {0, 80, 242, 4, 0}, + 4, DOT11F_EID_WSCREASSOCRES, 0, }, + { offsetof(tDot11fReAssocResponse, P2PAssocRes), + offsetof(tDot11fIEP2PAssocRes, present), 0, "P2PAssocRes", + 0, 6, 17, SigIeP2PAssocRes, {80, 111, 154, 9, 0}, + 4, DOT11F_EID_P2PASSOCRES, 0, }, + { offsetof(tDot11fReAssocResponse, VHTCaps), offsetof(tDot11fIEVHTCaps, + present), 0, "VHTCaps", 0, 14, 14, SigIeVHTCaps, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_VHTCAPS, 0, }, + { offsetof(tDot11fReAssocResponse, VHTOperation), + offsetof(tDot11fIEVHTOperation, present), 0, "VHTOperation", + 0, 7, 7, SigIeVHTOperation, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_VHTOPERATION, 0, }, + { offsetof(tDot11fReAssocResponse, ExtCap), offsetof(tDot11fIEExtCap, + present), 0, "ExtCap", 0, 3, 17, SigIeExtCap, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_EXTCAP, 0, }, + { offsetof(tDot11fReAssocResponse, OBSSScanParameters), + offsetof(tDot11fIEOBSSScanParameters, present), 0, "OBSSScanParameters", + 0, 16, 16, SigIeOBSSScanParameters, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_OBSSSCANPARAMETERS, 0, }, + { offsetof(tDot11fReAssocResponse, QosMapSet), + offsetof(tDot11fIEQosMapSet, present), 0, "QosMapSet", + 0, 2, 62, SigIeQosMapSet, {0, 0, 0, 0, 0}, 0, DOT11F_EID_QOSMAPSET, 0, }, + { offsetof(tDot11fReAssocResponse, vendor_vht_ie), + offsetof(tDot11fIEvendor_vht_ie, present), 0, "vendor_vht_ie", + 0, 7, 28, SigIevendor_vht_ie, {0, 144, 76, 0, 0}, + 3, DOT11F_EID_VENDOR_VHT_IE, 0, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_re_assoc_response(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fReAssocResponse *pFrm) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_ReAssocResponse, IES_ReAssocResponse, + (uint8_t *)pFrm, sizeof(*pFrm)); + + (void)i; + return status; + +} /* End dot11f_unpack_re_assoc_response. */ + +static const tFFDefn FFS_SMPowerSave[] = { + { "Category", offsetof(tDot11fSMPowerSave, Category), SigFfCategory, + DOT11F_FF_CATEGORY_LEN, }, + { "Action", offsetof(tDot11fSMPowerSave, Action), SigFfAction, + DOT11F_FF_ACTION_LEN, }, + { "SMPowerModeSet", offsetof(tDot11fSMPowerSave, SMPowerModeSet), + SigFfSMPowerModeSet, DOT11F_FF_SMPOWERMODESET_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_SMPowerSave[] = { + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_sm_power_save(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fSMPowerSave *pFrm) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_SMPowerSave, IES_SMPowerSave, + (uint8_t *)pFrm, sizeof(*pFrm)); + + (void)i; + return status; + +} /* End dot11f_unpack_sm_power_save. */ + +static const tFFDefn FFS_SaQueryReq[] = { + { "Category", offsetof(tDot11fSaQueryReq, Category), SigFfCategory, + DOT11F_FF_CATEGORY_LEN, }, + { "Action", offsetof(tDot11fSaQueryReq, Action), SigFfAction, + DOT11F_FF_ACTION_LEN, }, + { "TransactionId", offsetof(tDot11fSaQueryReq, TransactionId), + SigFfTransactionId, DOT11F_FF_TRANSACTIONID_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_SaQueryReq[] = { + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_sa_query_req(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fSaQueryReq *pFrm) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_SaQueryReq, IES_SaQueryReq, + (uint8_t *)pFrm, sizeof(*pFrm)); + + (void)i; + return status; + +} /* End dot11f_unpack_sa_query_req. */ + +static const tFFDefn FFS_SaQueryRsp[] = { + { "Category", offsetof(tDot11fSaQueryRsp, Category), SigFfCategory, + DOT11F_FF_CATEGORY_LEN, }, + { "Action", offsetof(tDot11fSaQueryRsp, Action), SigFfAction, + DOT11F_FF_ACTION_LEN, }, + { "TransactionId", offsetof(tDot11fSaQueryRsp, TransactionId), + SigFfTransactionId, DOT11F_FF_TRANSACTIONID_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_SaQueryRsp[] = { + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_sa_query_rsp(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fSaQueryRsp *pFrm) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_SaQueryRsp, IES_SaQueryRsp, + (uint8_t *)pFrm, sizeof(*pFrm)); + + (void)i; + return status; + +} /* End dot11f_unpack_sa_query_rsp. */ + +static const tFFDefn FFS_TDLSDisReq[] = { + { "Category", offsetof(tDot11fTDLSDisReq, Category), SigFfCategory, + DOT11F_FF_CATEGORY_LEN, }, + { "Action", offsetof(tDot11fTDLSDisReq, Action), SigFfAction, + DOT11F_FF_ACTION_LEN, }, + { "DialogToken", offsetof(tDot11fTDLSDisReq, DialogToken), + SigFfDialogToken, DOT11F_FF_DIALOGTOKEN_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_TDLSDisReq[] = { + { offsetof(tDot11fTDLSDisReq, LinkIdentifier), + offsetof(tDot11fIELinkIdentifier, present), 0, "LinkIdentifier", + 0, 20, 20, SigIeLinkIdentifier, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_LINKIDENTIFIER, 1, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_tdls_dis_req(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fTDLSDisReq *pFrm) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_TDLSDisReq, IES_TDLSDisReq, + (uint8_t *)pFrm, sizeof(*pFrm)); + + (void)i; + return status; + +} /* End dot11f_unpack_tdls_dis_req. */ + +static const tFFDefn FFS_TDLSDisRsp[] = { + { "Category", offsetof(tDot11fTDLSDisRsp, Category), SigFfCategory, + DOT11F_FF_CATEGORY_LEN, }, + { "Action", offsetof(tDot11fTDLSDisRsp, Action), SigFfAction, + DOT11F_FF_ACTION_LEN, }, + { "DialogToken", offsetof(tDot11fTDLSDisRsp, DialogToken), + SigFfDialogToken, DOT11F_FF_DIALOGTOKEN_LEN, }, + { "Capabilities", offsetof(tDot11fTDLSDisRsp, Capabilities), + SigFfCapabilities, DOT11F_FF_CAPABILITIES_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_TDLSDisRsp[] = { + { offsetof(tDot11fTDLSDisRsp, SuppRates), offsetof(tDot11fIESuppRates, + present), 0, "SuppRates", 0, 2, 14, SigIeSuppRates, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_SUPPRATES, 1, }, + { offsetof(tDot11fTDLSDisRsp, ExtSuppRates), + offsetof(tDot11fIEExtSuppRates, present), 0, "ExtSuppRates", + 0, 3, 14, SigIeExtSuppRates, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_EXTSUPPRATES, 0, }, + { offsetof(tDot11fTDLSDisRsp, SuppChannels), + offsetof(tDot11fIESuppChannels, present), 0, "SuppChannels", + 0, 4, 98, SigIeSuppChannels, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_SUPPCHANNELS, 0, }, + { offsetof(tDot11fTDLSDisRsp, SuppOperatingClasses), + offsetof(tDot11fIESuppOperatingClasses, present), 0, + "SuppOperatingClasses", 0, 3, 34, SigIeSuppOperatingClasses, + {0, 0, 0, 0, 0}, 0, DOT11F_EID_SUPPOPERATINGCLASSES, 0, }, + { offsetof(tDot11fTDLSDisRsp, RSN), offsetof(tDot11fIERSN, present), 0, + "RSN", 0, 8, 116, SigIeRSN, {0, 0, 0, 0, 0}, 0, DOT11F_EID_RSN, 0, }, + { offsetof(tDot11fTDLSDisRsp, ExtCap), offsetof(tDot11fIEExtCap, present), + 0, "ExtCap", 0, 3, 17, SigIeExtCap, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_EXTCAP, 0, }, + { offsetof(tDot11fTDLSDisRsp, FTInfo), offsetof(tDot11fIEFTInfo, present), + 0, "FTInfo", 0, 84, 222, SigIeFTInfo, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_FTINFO, 0, }, + { offsetof(tDot11fTDLSDisRsp, TimeoutInterval), + offsetof(tDot11fIETimeoutInterval, present), 0, "TimeoutInterval", + 0, 7, 7, SigIeTimeoutInterval, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_TIMEOUTINTERVAL, 0, }, + { offsetof(tDot11fTDLSDisRsp, RICData), offsetof(tDot11fIERICData, + present), 0, "RICData", 0, 6, 6, SigIeRICData, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_RICDATA, 0, }, + { offsetof(tDot11fTDLSDisRsp, HTCaps), offsetof(tDot11fIEHTCaps, present), + 0, "HTCaps", 0, 28, 60, SigIeHTCaps, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_HTCAPS, 0, }, + { offsetof(tDot11fTDLSDisRsp, ht2040_bss_coexistence), + offsetof(tDot11fIEht2040_bss_coexistence, present), 0, + "ht2040_bss_coexistence", 0, 3, 3, SigIeht2040_bss_coexistence, + {0, 0, 0, 0, 0}, 0, DOT11F_EID_HT2040_BSS_COEXISTENCE, 0, }, + { offsetof(tDot11fTDLSDisRsp, LinkIdentifier), + offsetof(tDot11fIELinkIdentifier, present), 0, "LinkIdentifier", + 0, 20, 20, SigIeLinkIdentifier, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_LINKIDENTIFIER, 1, }, + { offsetof(tDot11fTDLSDisRsp, VHTCaps), offsetof(tDot11fIEVHTCaps, + present), 0, "VHTCaps", 0, 14, 14, SigIeVHTCaps, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_VHTCAPS, 0, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_tdls_dis_rsp(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fTDLSDisRsp *pFrm) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_TDLSDisRsp, IES_TDLSDisRsp, + (uint8_t *)pFrm, sizeof(*pFrm)); + + (void)i; + return status; + +} /* End dot11f_unpack_tdls_dis_rsp. */ + +static const tFFDefn FFS_TDLSPeerTrafficInd[] = { + { "Category", offsetof(tDot11fTDLSPeerTrafficInd, Category), + SigFfCategory, DOT11F_FF_CATEGORY_LEN, }, + { "Action", offsetof(tDot11fTDLSPeerTrafficInd, Action), SigFfAction, + DOT11F_FF_ACTION_LEN, }, + { "DialogToken", offsetof(tDot11fTDLSPeerTrafficInd, DialogToken), + SigFfDialogToken, DOT11F_FF_DIALOGTOKEN_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_TDLSPeerTrafficInd[] = { + { offsetof(tDot11fTDLSPeerTrafficInd, LinkIdentifier), + offsetof(tDot11fIELinkIdentifier, present), 0, "LinkIdentifier", + 0, 20, 20, SigIeLinkIdentifier, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_LINKIDENTIFIER, 1, }, + { offsetof(tDot11fTDLSPeerTrafficInd, PTIControl), + offsetof(tDot11fIEPTIControl, present), 0, "PTIControl", + 0, 5, 5, SigIePTIControl, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_PTICONTROL, 0, }, + { offsetof(tDot11fTDLSPeerTrafficInd, PUBufferStatus), + offsetof(tDot11fIEPUBufferStatus, present), 0, "PUBufferStatus", + 0, 3, 3, SigIePUBufferStatus, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_PUBUFFERSTATUS, 1, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_tdls_peer_traffic_ind(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fTDLSPeerTrafficInd *pFrm) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_TDLSPeerTrafficInd, IES_TDLSPeerTrafficInd, + (uint8_t *)pFrm, sizeof(*pFrm)); + + (void)i; + return status; + +} /* End dot11f_unpack_tdls_peer_traffic_ind. */ + +static const tFFDefn FFS_TDLSPeerTrafficRsp[] = { + { "Category", offsetof(tDot11fTDLSPeerTrafficRsp, Category), + SigFfCategory, DOT11F_FF_CATEGORY_LEN, }, + { "Action", offsetof(tDot11fTDLSPeerTrafficRsp, Action), SigFfAction, + DOT11F_FF_ACTION_LEN, }, + { "DialogToken", offsetof(tDot11fTDLSPeerTrafficRsp, DialogToken), + SigFfDialogToken, DOT11F_FF_DIALOGTOKEN_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_TDLSPeerTrafficRsp[] = { + { offsetof(tDot11fTDLSPeerTrafficRsp, LinkIdentifier), + offsetof(tDot11fIELinkIdentifier, present), 0, "LinkIdentifier", + 0, 20, 20, SigIeLinkIdentifier, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_LINKIDENTIFIER, 1, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_tdls_peer_traffic_rsp(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fTDLSPeerTrafficRsp *pFrm) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_TDLSPeerTrafficRsp, IES_TDLSPeerTrafficRsp, + (uint8_t *)pFrm, sizeof(*pFrm)); + + (void)i; + return status; + +} /* End dot11f_unpack_tdls_peer_traffic_rsp. */ + +static const tFFDefn FFS_TDLSSetupCnf[] = { + { "Category", offsetof(tDot11fTDLSSetupCnf, Category), SigFfCategory, + DOT11F_FF_CATEGORY_LEN, }, + { "Action", offsetof(tDot11fTDLSSetupCnf, Action), SigFfAction, + DOT11F_FF_ACTION_LEN, }, + { "Status", offsetof(tDot11fTDLSSetupCnf, Status), SigFfStatus, + DOT11F_FF_STATUS_LEN, }, + { "DialogToken", offsetof(tDot11fTDLSSetupCnf, DialogToken), + SigFfDialogToken, DOT11F_FF_DIALOGTOKEN_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_TDLSSetupCnf[] = { + { offsetof(tDot11fTDLSSetupCnf, RSN), offsetof(tDot11fIERSN, present), 0, + "RSN", 0, 8, 116, SigIeRSN, {0, 0, 0, 0, 0}, 0, DOT11F_EID_RSN, 0, }, + { offsetof(tDot11fTDLSSetupCnf, EDCAParamSet), + offsetof(tDot11fIEEDCAParamSet, present), 0, "EDCAParamSet", + 0, 20, 20, SigIeEDCAParamSet, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_EDCAPARAMSET, 0, }, + { offsetof(tDot11fTDLSSetupCnf, FTInfo), offsetof(tDot11fIEFTInfo, + present), 0, "FTInfo", 0, 84, 222, SigIeFTInfo, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_FTINFO, 0, }, + { offsetof(tDot11fTDLSSetupCnf, TimeoutInterval), + offsetof(tDot11fIETimeoutInterval, present), 0, "TimeoutInterval", + 0, 7, 7, SigIeTimeoutInterval, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_TIMEOUTINTERVAL, 0, }, + { offsetof(tDot11fTDLSSetupCnf, HTInfo), offsetof(tDot11fIEHTInfo, + present), 0, "HTInfo", 0, 24, 56, SigIeHTInfo, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_HTINFO, 0, }, + { offsetof(tDot11fTDLSSetupCnf, LinkIdentifier), + offsetof(tDot11fIELinkIdentifier, present), 0, "LinkIdentifier", + 0, 20, 20, SigIeLinkIdentifier, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_LINKIDENTIFIER, 0, }, + { offsetof(tDot11fTDLSSetupCnf, WMMParams), offsetof(tDot11fIEWMMParams, + present), 0, "WMMParams", 0, 26, 26, SigIeWMMParams, {0, 80, 242, 2, 1}, + 5, DOT11F_EID_WMMPARAMS, 0, }, + { offsetof(tDot11fTDLSSetupCnf, VHTOperation), + offsetof(tDot11fIEVHTOperation, present), 0, "VHTOperation", + 0, 7, 7, SigIeVHTOperation, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_VHTOPERATION, 0, }, + { offsetof(tDot11fTDLSSetupCnf, OperatingMode), + offsetof(tDot11fIEOperatingMode, present), 0, "OperatingMode", + 0, 3, 3, SigIeOperatingMode, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_OPERATINGMODE, 0, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_tdls_setup_cnf(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fTDLSSetupCnf *pFrm) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_TDLSSetupCnf, IES_TDLSSetupCnf, + (uint8_t *)pFrm, sizeof(*pFrm)); + + (void)i; + return status; + +} /* End dot11f_unpack_tdls_setup_cnf. */ + +static const tFFDefn FFS_TDLSSetupReq[] = { + { "Category", offsetof(tDot11fTDLSSetupReq, Category), SigFfCategory, + DOT11F_FF_CATEGORY_LEN, }, + { "Action", offsetof(tDot11fTDLSSetupReq, Action), SigFfAction, + DOT11F_FF_ACTION_LEN, }, + { "DialogToken", offsetof(tDot11fTDLSSetupReq, DialogToken), + SigFfDialogToken, DOT11F_FF_DIALOGTOKEN_LEN, }, + { "Capabilities", offsetof(tDot11fTDLSSetupReq, Capabilities), + SigFfCapabilities, DOT11F_FF_CAPABILITIES_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_TDLSSetupReq[] = { + { offsetof(tDot11fTDLSSetupReq, SuppRates), offsetof(tDot11fIESuppRates, + present), 0, "SuppRates", 0, 2, 14, SigIeSuppRates, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_SUPPRATES, 1, }, + { offsetof(tDot11fTDLSSetupReq, Country), offsetof(tDot11fIECountry, + present), 0, "Country", 0, 5, 257, SigIeCountry, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_COUNTRY, 0, }, + { offsetof(tDot11fTDLSSetupReq, ExtSuppRates), + offsetof(tDot11fIEExtSuppRates, present), 0, "ExtSuppRates", + 0, 3, 14, SigIeExtSuppRates, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_EXTSUPPRATES, 0, }, + { offsetof(tDot11fTDLSSetupReq, SuppChannels), + offsetof(tDot11fIESuppChannels, present), 0, "SuppChannels", + 0, 4, 98, SigIeSuppChannels, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_SUPPCHANNELS, 0, }, + { offsetof(tDot11fTDLSSetupReq, RSN), offsetof(tDot11fIERSN, present), 0, + "RSN", 0, 8, 116, SigIeRSN, {0, 0, 0, 0, 0}, 0, DOT11F_EID_RSN, 0, }, + { offsetof(tDot11fTDLSSetupReq, ExtCap), offsetof(tDot11fIEExtCap, + present), 0, "ExtCap", 0, 3, 17, SigIeExtCap, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_EXTCAP, 0, }, + { offsetof(tDot11fTDLSSetupReq, SuppOperatingClasses), + offsetof(tDot11fIESuppOperatingClasses, present), 0, + "SuppOperatingClasses", 0, 3, 34, SigIeSuppOperatingClasses, + {0, 0, 0, 0, 0}, 0, DOT11F_EID_SUPPOPERATINGCLASSES, 0, }, + { offsetof(tDot11fTDLSSetupReq, QOSCapsStation), + offsetof(tDot11fIEQOSCapsStation, present), 0, "QOSCapsStation", + 0, 3, 3, SigIeQOSCapsStation, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_QOSCAPSSTATION, 0, }, + { offsetof(tDot11fTDLSSetupReq, FTInfo), offsetof(tDot11fIEFTInfo, + present), 0, "FTInfo", 0, 84, 222, SigIeFTInfo, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_FTINFO, 0, }, + { offsetof(tDot11fTDLSSetupReq, TimeoutInterval), + offsetof(tDot11fIETimeoutInterval, present), 0, "TimeoutInterval", + 0, 7, 7, SigIeTimeoutInterval, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_TIMEOUTINTERVAL, 0, }, + { offsetof(tDot11fTDLSSetupReq, RICData), offsetof(tDot11fIERICData, + present), 0, "RICData", 0, 6, 6, SigIeRICData, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_RICDATA, 0, }, + { offsetof(tDot11fTDLSSetupReq, HTCaps), offsetof(tDot11fIEHTCaps, + present), 0, "HTCaps", 0, 28, 60, SigIeHTCaps, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_HTCAPS, 0, }, + { offsetof(tDot11fTDLSSetupReq, ht2040_bss_coexistence), + offsetof(tDot11fIEht2040_bss_coexistence, present), 0, + "ht2040_bss_coexistence", 0, 3, 3, SigIeht2040_bss_coexistence, + {0, 0, 0, 0, 0}, 0, DOT11F_EID_HT2040_BSS_COEXISTENCE, 0, }, + { offsetof(tDot11fTDLSSetupReq, LinkIdentifier), + offsetof(tDot11fIELinkIdentifier, present), 0, "LinkIdentifier", + 0, 20, 20, SigIeLinkIdentifier, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_LINKIDENTIFIER, 1, }, + { offsetof(tDot11fTDLSSetupReq, WMMInfoStation), + offsetof(tDot11fIEWMMInfoStation, present), 0, "WMMInfoStation", + 0, 9, 9, SigIeWMMInfoStation, {0, 80, 242, 2, 0}, + 5, DOT11F_EID_WMMINFOSTATION, 0, }, + { offsetof(tDot11fTDLSSetupReq, AID), offsetof(tDot11fIEAID, present), 0, + "AID", 0, 4, 4, SigIeAID, {0, 0, 0, 0, 0}, 0, DOT11F_EID_AID, 0, }, + { offsetof(tDot11fTDLSSetupReq, VHTCaps), offsetof(tDot11fIEVHTCaps, + present), 0, "VHTCaps", 0, 14, 14, SigIeVHTCaps, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_VHTCAPS, 0, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_tdls_setup_req(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fTDLSSetupReq *pFrm) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_TDLSSetupReq, IES_TDLSSetupReq, + (uint8_t *)pFrm, sizeof(*pFrm)); + + (void)i; + return status; + +} /* End dot11f_unpack_tdls_setup_req. */ + +static const tFFDefn FFS_TDLSSetupRsp[] = { + { "Category", offsetof(tDot11fTDLSSetupRsp, Category), SigFfCategory, + DOT11F_FF_CATEGORY_LEN, }, + { "Action", offsetof(tDot11fTDLSSetupRsp, Action), SigFfAction, + DOT11F_FF_ACTION_LEN, }, + { "Status", offsetof(tDot11fTDLSSetupRsp, Status), SigFfStatus, + DOT11F_FF_STATUS_LEN, }, + { "DialogToken", offsetof(tDot11fTDLSSetupRsp, DialogToken), + SigFfDialogToken, DOT11F_FF_DIALOGTOKEN_LEN, }, + { "Capabilities", offsetof(tDot11fTDLSSetupRsp, Capabilities), + SigFfCapabilities, DOT11F_FF_CAPABILITIES_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_TDLSSetupRsp[] = { + { offsetof(tDot11fTDLSSetupRsp, SuppRates), offsetof(tDot11fIESuppRates, + present), 0, "SuppRates", 0, 2, 14, SigIeSuppRates, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_SUPPRATES, 0, }, + { offsetof(tDot11fTDLSSetupRsp, Country), offsetof(tDot11fIECountry, + present), 0, "Country", 0, 5, 257, SigIeCountry, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_COUNTRY, 0, }, + { offsetof(tDot11fTDLSSetupRsp, ExtSuppRates), + offsetof(tDot11fIEExtSuppRates, present), 0, "ExtSuppRates", + 0, 3, 14, SigIeExtSuppRates, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_EXTSUPPRATES, 0, }, + { offsetof(tDot11fTDLSSetupRsp, SuppChannels), + offsetof(tDot11fIESuppChannels, present), 0, "SuppChannels", + 0, 4, 98, SigIeSuppChannels, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_SUPPCHANNELS, 0, }, + { offsetof(tDot11fTDLSSetupRsp, RSN), offsetof(tDot11fIERSN, present), 0, + "RSN", 0, 8, 116, SigIeRSN, {0, 0, 0, 0, 0}, 0, DOT11F_EID_RSN, 0, }, + { offsetof(tDot11fTDLSSetupRsp, ExtCap), offsetof(tDot11fIEExtCap, + present), 0, "ExtCap", 0, 3, 17, SigIeExtCap, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_EXTCAP, 0, }, + { offsetof(tDot11fTDLSSetupRsp, SuppOperatingClasses), + offsetof(tDot11fIESuppOperatingClasses, present), 0, + "SuppOperatingClasses", 0, 3, 34, SigIeSuppOperatingClasses, + {0, 0, 0, 0, 0}, 0, DOT11F_EID_SUPPOPERATINGCLASSES, 0, }, + { offsetof(tDot11fTDLSSetupRsp, QOSCapsStation), + offsetof(tDot11fIEQOSCapsStation, present), 0, "QOSCapsStation", + 0, 3, 3, SigIeQOSCapsStation, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_QOSCAPSSTATION, 0, }, + { offsetof(tDot11fTDLSSetupRsp, FTInfo), offsetof(tDot11fIEFTInfo, + present), 0, "FTInfo", 0, 84, 222, SigIeFTInfo, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_FTINFO, 0, }, + { offsetof(tDot11fTDLSSetupRsp, TimeoutInterval), + offsetof(tDot11fIETimeoutInterval, present), 0, "TimeoutInterval", + 0, 7, 7, SigIeTimeoutInterval, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_TIMEOUTINTERVAL, 0, }, + { offsetof(tDot11fTDLSSetupRsp, RICData), offsetof(tDot11fIERICData, + present), 0, "RICData", 0, 6, 6, SigIeRICData, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_RICDATA, 0, }, + { offsetof(tDot11fTDLSSetupRsp, HTCaps), offsetof(tDot11fIEHTCaps, + present), 0, "HTCaps", 0, 28, 60, SigIeHTCaps, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_HTCAPS, 0, }, + { offsetof(tDot11fTDLSSetupRsp, ht2040_bss_coexistence), + offsetof(tDot11fIEht2040_bss_coexistence, present), 0, + "ht2040_bss_coexistence", 0, 3, 3, SigIeht2040_bss_coexistence, + {0, 0, 0, 0, 0}, 0, DOT11F_EID_HT2040_BSS_COEXISTENCE, 0, }, + { offsetof(tDot11fTDLSSetupRsp, LinkIdentifier), + offsetof(tDot11fIELinkIdentifier, present), 0, "LinkIdentifier", + 0, 20, 20, SigIeLinkIdentifier, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_LINKIDENTIFIER, 0, }, + { offsetof(tDot11fTDLSSetupRsp, WMMInfoStation), + offsetof(tDot11fIEWMMInfoStation, present), 0, "WMMInfoStation", + 0, 9, 9, SigIeWMMInfoStation, {0, 80, 242, 2, 0}, + 5, DOT11F_EID_WMMINFOSTATION, 0, }, + { offsetof(tDot11fTDLSSetupRsp, AID), offsetof(tDot11fIEAID, present), 0, + "AID", 0, 4, 4, SigIeAID, {0, 0, 0, 0, 0}, 0, DOT11F_EID_AID, 0, }, + { offsetof(tDot11fTDLSSetupRsp, VHTCaps), offsetof(tDot11fIEVHTCaps, + present), 0, "VHTCaps", 0, 14, 14, SigIeVHTCaps, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_VHTCAPS, 0, }, + { offsetof(tDot11fTDLSSetupRsp, OperatingMode), + offsetof(tDot11fIEOperatingMode, present), 0, "OperatingMode", + 0, 3, 3, SigIeOperatingMode, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_OPERATINGMODE, 0, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_tdls_setup_rsp(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fTDLSSetupRsp *pFrm) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_TDLSSetupRsp, IES_TDLSSetupRsp, + (uint8_t *)pFrm, sizeof(*pFrm)); + + (void)i; + return status; + +} /* End dot11f_unpack_tdls_setup_rsp. */ + +static const tFFDefn FFS_TDLSTeardown[] = { + { "Category", offsetof(tDot11fTDLSTeardown, Category), SigFfCategory, + DOT11F_FF_CATEGORY_LEN, }, + { "Action", offsetof(tDot11fTDLSTeardown, Action), SigFfAction, + DOT11F_FF_ACTION_LEN, }, + { "Reason", offsetof(tDot11fTDLSTeardown, Reason), SigFfReason, + DOT11F_FF_REASON_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_TDLSTeardown[] = { + { offsetof(tDot11fTDLSTeardown, FTInfo), offsetof(tDot11fIEFTInfo, + present), 0, "FTInfo", 0, 84, 222, SigIeFTInfo, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_FTINFO, 0, }, + { offsetof(tDot11fTDLSTeardown, LinkIdentifier), + offsetof(tDot11fIELinkIdentifier, present), 0, "LinkIdentifier", + 0, 20, 20, SigIeLinkIdentifier, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_LINKIDENTIFIER, 1, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_tdls_teardown(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fTDLSTeardown *pFrm) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_TDLSTeardown, IES_TDLSTeardown, + (uint8_t *)pFrm, sizeof(*pFrm)); + + (void)i; + return status; + +} /* End dot11f_unpack_tdls_teardown. */ + +static const tFFDefn FFS_TPCReport[] = { + { "Category", offsetof(tDot11fTPCReport, Category), SigFfCategory, + DOT11F_FF_CATEGORY_LEN, }, + { "Action", offsetof(tDot11fTPCReport, Action), SigFfAction, + DOT11F_FF_ACTION_LEN, }, + { "DialogToken", offsetof(tDot11fTPCReport, DialogToken), + SigFfDialogToken, DOT11F_FF_DIALOGTOKEN_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_TPCReport[] = { + { offsetof(tDot11fTPCReport, TPCReport), offsetof(tDot11fIETPCReport, + present), 0, "TPCReport", 0, 4, 4, SigIeTPCReport, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_TPCREPORT, 1, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_tpc_report(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fTPCReport *pFrm) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_TPCReport, IES_TPCReport, + (uint8_t *)pFrm, sizeof(*pFrm)); + + (void)i; + return status; + +} /* End dot11f_unpack_tpc_report. */ + +static const tFFDefn FFS_TPCRequest[] = { + { "Category", offsetof(tDot11fTPCRequest, Category), SigFfCategory, + DOT11F_FF_CATEGORY_LEN, }, + { "Action", offsetof(tDot11fTPCRequest, Action), SigFfAction, + DOT11F_FF_ACTION_LEN, }, + { "DialogToken", offsetof(tDot11fTPCRequest, DialogToken), + SigFfDialogToken, DOT11F_FF_DIALOGTOKEN_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_TPCRequest[] = { + { offsetof(tDot11fTPCRequest, TPCRequest), offsetof(tDot11fIETPCRequest, + present), 0, "TPCRequest", 0, 2, 2, SigIeTPCRequest, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_TPCREQUEST, 1, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_tpc_request(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fTPCRequest *pFrm) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_TPCRequest, IES_TPCRequest, + (uint8_t *)pFrm, sizeof(*pFrm)); + + (void)i; + return status; + +} /* End dot11f_unpack_tpc_request. */ + +static const tFFDefn FFS_TimingAdvertisementFrame[] = { + { "TimeStamp", offsetof(tDot11fTimingAdvertisementFrame, TimeStamp), + SigFfTimeStamp, DOT11F_FF_TIMESTAMP_LEN, }, + { "Capabilities", offsetof(tDot11fTimingAdvertisementFrame, + Capabilities), SigFfCapabilities, DOT11F_FF_CAPABILITIES_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_TimingAdvertisementFrame[] = { + { offsetof(tDot11fTimingAdvertisementFrame, Country), + offsetof(tDot11fIECountry, present), 0, "Country", 0, 5, 257, SigIeCountry, + {0, 0, 0, 0, 0}, 0, DOT11F_EID_COUNTRY, 0, }, + { offsetof(tDot11fTimingAdvertisementFrame, PowerConstraints), + offsetof(tDot11fIEPowerConstraints, present), 0, "PowerConstraints", + 0, 3, 3, SigIePowerConstraints, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_POWERCONSTRAINTS, 0, }, + { offsetof(tDot11fTimingAdvertisementFrame, TimeAdvertisement), + offsetof(tDot11fIETimeAdvertisement, present), 0, "TimeAdvertisement", + 0, 18, 18, SigIeTimeAdvertisement, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_TIMEADVERTISEMENT, 0, }, + { offsetof(tDot11fTimingAdvertisementFrame, ExtCap), + offsetof(tDot11fIEExtCap, present), 0, "ExtCap", 0, 3, 17, SigIeExtCap, + {0, 0, 0, 0, 0}, 0, DOT11F_EID_EXTCAP, 0, }, + { offsetof(tDot11fTimingAdvertisementFrame, Vendor1IE), + offsetof(tDot11fIEVendor1IE, present), 0, "Vendor1IE", + 0, 5, 5, SigIeVendor1IE, {0, 16, 24, 0, 0}, + 3, DOT11F_EID_VENDOR1IE, 0, }, + { offsetof(tDot11fTimingAdvertisementFrame, Vendor3IE), + offsetof(tDot11fIEVendor3IE, present), 0, "Vendor3IE", + 0, 5, 5, SigIeVendor3IE, {0, 22, 50, 0, 0}, + 3, DOT11F_EID_VENDOR3IE, 0, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_timing_advertisement_frame(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fTimingAdvertisementFrame *pFrm) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_TimingAdvertisementFrame, IES_TimingAdvertisementFrame, + (uint8_t *)pFrm, sizeof(*pFrm)); + + (void)i; + return status; + +} /* End dot11f_unpack_timing_advertisement_frame. */ + +static const tFFDefn FFS_VHTGidManagementActionFrame[] = { + { "Category", offsetof(tDot11fVHTGidManagementActionFrame, Category), + SigFfCategory, DOT11F_FF_CATEGORY_LEN, }, + { "Action", offsetof(tDot11fVHTGidManagementActionFrame, Action), + SigFfAction, DOT11F_FF_ACTION_LEN, }, + { "VhtMembershipStatusArray", + offsetof(tDot11fVHTGidManagementActionFrame, VhtMembershipStatusArray), + SigFfVhtMembershipStatusArray, + DOT11F_FF_VHTMEMBERSHIPSTATUSARRAY_LEN, }, + { "VhtUserPositionArray", offsetof(tDot11fVHTGidManagementActionFrame, + VhtUserPositionArray), SigFfVhtUserPositionArray, + DOT11F_FF_VHTUSERPOSITIONARRAY_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_VHTGidManagementActionFrame[] = { + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_vht_gid_management_action_frame(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fVHTGidManagementActionFrame *pFrm) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_VHTGidManagementActionFrame, IES_VHTGidManagementActionFrame, + (uint8_t *)pFrm, sizeof(*pFrm)); + + (void)i; + return status; + +} /* End dot11f_unpack_vht_gid_management_action_frame. */ + +static const tFFDefn FFS_WMMAddTSRequest[] = { + { "Category", offsetof(tDot11fWMMAddTSRequest, Category), SigFfCategory, + DOT11F_FF_CATEGORY_LEN, }, + { "Action", offsetof(tDot11fWMMAddTSRequest, Action), SigFfAction, + DOT11F_FF_ACTION_LEN, }, + { "DialogToken", offsetof(tDot11fWMMAddTSRequest, DialogToken), + SigFfDialogToken, DOT11F_FF_DIALOGTOKEN_LEN, }, + { "StatusCode", offsetof(tDot11fWMMAddTSRequest, StatusCode), + SigFfStatusCode, DOT11F_FF_STATUSCODE_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_WMMAddTSRequest[] = { + { offsetof(tDot11fWMMAddTSRequest, WMMTSPEC), offsetof(tDot11fIEWMMTSPEC, + present), 0, "WMMTSPEC", 0, 63, 63, SigIeWMMTSPEC, {0, 80, 242, 2, 2}, + 5, DOT11F_EID_WMMTSPEC, 1, }, + { offsetof(tDot11fWMMAddTSRequest, ESETrafStrmRateSet), + offsetof(tDot11fIEESETrafStrmRateSet, present), 0, "ESETrafStrmRateSet", + 0, 7, 15, SigIeESETrafStrmRateSet, {0, 64, 150, 8, 0}, + 4, DOT11F_EID_ESETRAFSTRMRATESET, 0, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_wmm_add_ts_request(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fWMMAddTSRequest *pFrm) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_WMMAddTSRequest, IES_WMMAddTSRequest, + (uint8_t *)pFrm, sizeof(*pFrm)); + + (void)i; + return status; + +} /* End dot11f_unpack_wmm_add_ts_request. */ + +static const tFFDefn FFS_WMMAddTSResponse[] = { + { "Category", offsetof(tDot11fWMMAddTSResponse, Category), SigFfCategory, + DOT11F_FF_CATEGORY_LEN, }, + { "Action", offsetof(tDot11fWMMAddTSResponse, Action), SigFfAction, + DOT11F_FF_ACTION_LEN, }, + { "DialogToken", offsetof(tDot11fWMMAddTSResponse, DialogToken), + SigFfDialogToken, DOT11F_FF_DIALOGTOKEN_LEN, }, + { "StatusCode", offsetof(tDot11fWMMAddTSResponse, StatusCode), + SigFfStatusCode, DOT11F_FF_STATUSCODE_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_WMMAddTSResponse[] = { + { offsetof(tDot11fWMMAddTSResponse, WMMTSPEC), + offsetof(tDot11fIEWMMTSPEC, present), 0, "WMMTSPEC", + 0, 63, 63, SigIeWMMTSPEC, {0, 80, 242, 2, 2}, + 5, DOT11F_EID_WMMTSPEC, 0, }, + { offsetof(tDot11fWMMAddTSResponse, ESETrafStrmMet), + offsetof(tDot11fIEESETrafStrmMet, present), 0, "ESETrafStrmMet", + 0, 10, 10, SigIeESETrafStrmMet, {0, 64, 150, 7, 0}, + 4, DOT11F_EID_ESETRAFSTRMMET, 0, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_wmm_add_ts_response(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fWMMAddTSResponse *pFrm) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_WMMAddTSResponse, IES_WMMAddTSResponse, + (uint8_t *)pFrm, sizeof(*pFrm)); + + (void)i; + return status; + +} /* End dot11f_unpack_wmm_add_ts_response. */ + +static const tFFDefn FFS_WMMDelTS[] = { + { "Category", offsetof(tDot11fWMMDelTS, Category), SigFfCategory, + DOT11F_FF_CATEGORY_LEN, }, + { "Action", offsetof(tDot11fWMMDelTS, Action), SigFfAction, + DOT11F_FF_ACTION_LEN, }, + { "DialogToken", offsetof(tDot11fWMMDelTS, DialogToken), SigFfDialogToken, + DOT11F_FF_DIALOGTOKEN_LEN, }, + { "StatusCode", offsetof(tDot11fWMMDelTS, StatusCode), SigFfStatusCode, + DOT11F_FF_STATUSCODE_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_WMMDelTS[] = { + { offsetof(tDot11fWMMDelTS, WMMTSPEC), offsetof(tDot11fIEWMMTSPEC, + present), 0, "WMMTSPEC", 0, 63, 63, SigIeWMMTSPEC, {0, 80, 242, 2, 2}, + 5, DOT11F_EID_WMMTSPEC, 1, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_wmm_del_ts(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fWMMDelTS *pFrm) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_WMMDelTS, IES_WMMDelTS, + (uint8_t *)pFrm, sizeof(*pFrm)); + + (void)i; + return status; + +} /* End dot11f_unpack_wmm_del_ts. */ + +static const tFFDefn FFS_ext_channel_switch_action_frame[] = { + { "Category", offsetof(tDot11fext_channel_switch_action_frame, Category), + SigFfCategory, DOT11F_FF_CATEGORY_LEN, }, + { "Action", offsetof(tDot11fext_channel_switch_action_frame, Action), + SigFfAction, DOT11F_FF_ACTION_LEN, }, + { "ext_chan_switch_ann_action", + offsetof(tDot11fext_channel_switch_action_frame, + ext_chan_switch_ann_action), SigFfext_chan_switch_ann_action, + DOT11F_FF_EXT_CHAN_SWITCH_ANN_ACTION_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_ext_channel_switch_action_frame[] = { + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_ext_channel_switch_action_frame(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fext_channel_switch_action_frame *pFrm) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_ext_channel_switch_action_frame, IES_ext_channel_switch_action_frame, + (uint8_t *)pFrm, sizeof(*pFrm)); + + (void)i; + return status; + +} /* End dot11f_unpack_ext_channel_switch_action_frame. */ + +static const tFFDefn FFS_ht2040_bss_coexistence_mgmt_action_frame[] = { + { "Category", offsetof(tDot11fht2040_bss_coexistence_mgmt_action_frame, + Category), SigFfCategory, DOT11F_FF_CATEGORY_LEN, }, + { "Action", offsetof(tDot11fht2040_bss_coexistence_mgmt_action_frame, + Action), SigFfAction, DOT11F_FF_ACTION_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_ht2040_bss_coexistence_mgmt_action_frame[] = { + { offsetof(tDot11fht2040_bss_coexistence_mgmt_action_frame, + ht2040_bss_coexistence), offsetof(tDot11fIEht2040_bss_coexistence, + present), 0, "ht2040_bss_coexistence", + 0, 3, 3, SigIeht2040_bss_coexistence, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_HT2040_BSS_COEXISTENCE, 1, }, + { offsetof(tDot11fht2040_bss_coexistence_mgmt_action_frame, + ht2040_bss_intolerant_report), + offsetof(tDot11fIEht2040_bss_intolerant_report, present), 0, + "ht2040_bss_intolerant_report", + 0, 3, 53, SigIeht2040_bss_intolerant_report, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_HT2040_BSS_INTOLERANT_REPORT, 1, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_ht2040_bss_coexistence_mgmt_action_frame(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fht2040_bss_coexistence_mgmt_action_frame *pFrm) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_ht2040_bss_coexistence_mgmt_action_frame, IES_ht2040_bss_coexistence_mgmt_action_frame, + (uint8_t *)pFrm, sizeof(*pFrm)); + + (void)i; + return status; + +} /* End dot11f_unpack_ht2040_bss_coexistence_mgmt_action_frame. */ + +static const tFFDefn FFS_p2p_oper_chan_change_confirm[] = { + { "Category", offsetof(tDot11fp2p_oper_chan_change_confirm, Category), + SigFfCategory, DOT11F_FF_CATEGORY_LEN, }, + { "p2p_action_oui", offsetof(tDot11fp2p_oper_chan_change_confirm, + p2p_action_oui), SigFfp2p_action_oui, DOT11F_FF_P2P_ACTION_OUI_LEN, }, + { "p2p_action_subtype", offsetof(tDot11fp2p_oper_chan_change_confirm, + p2p_action_subtype), SigFfp2p_action_subtype, + DOT11F_FF_P2P_ACTION_SUBTYPE_LEN, }, + { "DialogToken", offsetof(tDot11fp2p_oper_chan_change_confirm, + DialogToken), SigFfDialogToken, DOT11F_FF_DIALOGTOKEN_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_p2p_oper_chan_change_confirm[] = { + { offsetof(tDot11fp2p_oper_chan_change_confirm, HTCaps), + offsetof(tDot11fIEHTCaps, present), 0, "HTCaps", 0, 28, 60, SigIeHTCaps, + {0, 0, 0, 0, 0}, 0, DOT11F_EID_HTCAPS, 0, }, + { offsetof(tDot11fp2p_oper_chan_change_confirm, VHTCaps), + offsetof(tDot11fIEVHTCaps, present), 0, "VHTCaps", 0, 14, 14, SigIeVHTCaps, + {0, 0, 0, 0, 0}, 0, DOT11F_EID_VHTCAPS, 0, }, + { offsetof(tDot11fp2p_oper_chan_change_confirm, OperatingMode), + offsetof(tDot11fIEOperatingMode, present), 0, "OperatingMode", + 0, 3, 3, SigIeOperatingMode, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_OPERATINGMODE, 0, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_p2p_oper_chan_change_confirm(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fp2p_oper_chan_change_confirm *pFrm) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_p2p_oper_chan_change_confirm, IES_p2p_oper_chan_change_confirm, + (uint8_t *)pFrm, sizeof(*pFrm)); + + (void)i; + return status; + +} /* End dot11f_unpack_p2p_oper_chan_change_confirm. */ + +static uint32_t unpack_core(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint32_t nBuf, + const tFFDefn FFs[], + const tIEDefn IEs[], + uint8_t *pFrm, + size_t nFrm) +{ + const tFFDefn *pFf; + const tIEDefn *pIe; + uint8_t *pBufRemaining; + uint32_t nBufRemaining, status; + uint8_t eid, len; + tFRAMES_BOOL *pfFound; + uint32_t countOffset = 0; + + DOT11F_PARAMETER_CHECK(pBuf, nBuf, pFrm, nFrm); + (void)nFrm; + + (void)pCtx; + status = DOT11F_PARSE_SUCCESS; + pBufRemaining = pBuf; + nBufRemaining = nBuf; + + pIe = &IEs[0]; + while (0xff != pIe->eid) { + pfFound = (tFRAMES_BOOL *)(pFrm + pIe->offset + + pIe->presenceOffset); + *pfFound = 0U; + if (pIe->countOffset) + *(uint16_t *)(pFrm + pIe->countOffset) = 0U; + ++pIe; + } + + pFf = &FFs[0]; + while (pFf->size) { + if (pFf->size > nBufRemaining) { + FRAMES_LOG3(pCtx, FRLOGE, FRFL("Fixed field %s is %d" + "bytes in size, but there are only %d bytes left i" + "n this frame.\n"), pFf->name, pFf->size, + nBufRemaining); + FRAMES_DBG_BREAK(); + return DOT11F_MISSING_FIXED_FIELD; + } + + switch (pFf->sig) { + + case SigFfAID: + dot11f_unpack_ff_common_func(pCtx, + pBufRemaining, (uint16_t *)&(((tDot11fFfAID *) + (pFrm + pFf->offset))->associd)); + break; + case SigFfAction: + dot11f_unpack_ff_action(pCtx, + pBufRemaining, (tDot11fFfAction *) + (pFrm + pFf->offset)); + break; + case SigFfAuthAlgo: + dot11f_unpack_ff_common_func(pCtx, + pBufRemaining, (uint16_t *)&(((tDot11fFfAuthAlgo *) + (pFrm + pFf->offset))->algo)); + break; + case SigFfAuthSeqNo: + dot11f_unpack_ff_common_func(pCtx, + pBufRemaining, (uint16_t *)&(((tDot11fFfAuthSeqNo *) + (pFrm + pFf->offset))->no)); + break; + case SigFfBeaconInterval: + dot11f_unpack_ff_common_func(pCtx, + pBufRemaining, (uint16_t *)&(((tDot11fFfBeaconInterval *) + (pFrm + pFf->offset))->interval)); + break; + case SigFfCapabilities: + dot11f_unpack_ff_capabilities(pCtx, + pBufRemaining, (tDot11fFfCapabilities *) + (pFrm + pFf->offset)); + break; + case SigFfCategory: + dot11f_unpack_ff_category(pCtx, + pBufRemaining, (tDot11fFfCategory *) + (pFrm + pFf->offset)); + break; + case SigFfCurrentAPAddress: + dot11f_unpack_ff_current_ap_address(pCtx, + pBufRemaining, (tDot11fFfCurrentAPAddress *) + (pFrm + pFf->offset)); + break; + case SigFfDialogToken: + dot11f_unpack_ff_dialog_token(pCtx, + pBufRemaining, (tDot11fFfDialogToken *) + (pFrm + pFf->offset)); + break; + case SigFfLinkMargin: + dot11f_unpack_ff_link_margin(pCtx, + pBufRemaining, (tDot11fFfLinkMargin *) + (pFrm + pFf->offset)); + break; + case SigFfListenInterval: + dot11f_unpack_ff_common_func(pCtx, + pBufRemaining, (uint16_t *)&(((tDot11fFfListenInterval *) + (pFrm + pFf->offset))->interval)); + break; + case SigFfMaxTxPower: + dot11f_unpack_ff_max_tx_power(pCtx, + pBufRemaining, (tDot11fFfMaxTxPower *) + (pFrm + pFf->offset)); + break; + case SigFfNumOfRepetitions: + dot11f_unpack_ff_num_of_repetitions(pCtx, + pBufRemaining, (tDot11fFfNumOfRepetitions *) + (pFrm + pFf->offset)); + break; + case SigFfOperatingMode: + dot11f_unpack_ff_operating_mode(pCtx, + pBufRemaining, (tDot11fFfOperatingMode *) + (pFrm + pFf->offset)); + break; + case SigFfRCPI: + dot11f_unpack_ff_rcpi(pCtx, + pBufRemaining, (tDot11fFfRCPI *) + (pFrm + pFf->offset)); + break; + case SigFfRSNI: + dot11f_unpack_ff_rsni(pCtx, + pBufRemaining, (tDot11fFfRSNI *) + (pFrm + pFf->offset)); + break; + case SigFfReason: + dot11f_unpack_ff_common_func(pCtx, + pBufRemaining, (uint16_t *)&(((tDot11fFfReason *) + (pFrm + pFf->offset))->code)); + break; + case SigFfRxAntennaId: + dot11f_unpack_ff_rx_antenna_id(pCtx, + pBufRemaining, (tDot11fFfRxAntennaId *) + (pFrm + pFf->offset)); + break; + case SigFfSMPowerModeSet: + dot11f_unpack_ff_sm_power_mode_set(pCtx, + pBufRemaining, (tDot11fFfSMPowerModeSet *) + (pFrm + pFf->offset)); + break; + case SigFfStatus: + dot11f_unpack_ff_common_func(pCtx, + pBufRemaining, (uint16_t *)&(((tDot11fFfStatus *) + (pFrm + pFf->offset))->status)); + break; + case SigFfStatusCode: + dot11f_unpack_ff_status_code(pCtx, + pBufRemaining, (tDot11fFfStatusCode *) + (pFrm + pFf->offset)); + break; + case SigFfTPCEleID: + dot11f_unpack_ff_tpc_ele_id(pCtx, + pBufRemaining, (tDot11fFfTPCEleID *) + (pFrm + pFf->offset)); + break; + case SigFfTPCEleLen: + dot11f_unpack_ff_tpc_ele_len(pCtx, + pBufRemaining, (tDot11fFfTPCEleLen *) + (pFrm + pFf->offset)); + break; + case SigFfTSInfo: + dot11f_unpack_ff_ts_info(pCtx, + pBufRemaining, (tDot11fFfTSInfo *) + (pFrm + pFf->offset)); + break; + case SigFfTimeStamp: + dot11f_unpack_ff_time_stamp(pCtx, + pBufRemaining, (tDot11fFfTimeStamp *) + (pFrm + pFf->offset)); + break; + case SigFfTransactionId: + dot11f_unpack_ff_transaction_id(pCtx, + pBufRemaining, (tDot11fFfTransactionId *) + (pFrm + pFf->offset)); + break; + case SigFfTxAntennaId: + dot11f_unpack_ff_tx_antenna_id(pCtx, + pBufRemaining, (tDot11fFfTxAntennaId *) + (pFrm + pFf->offset)); + break; + case SigFfTxPower: + dot11f_unpack_ff_tx_power(pCtx, + pBufRemaining, (tDot11fFfTxPower *) + (pFrm + pFf->offset)); + break; + case SigFfVhtMembershipStatusArray: + dot11f_unpack_ff_vht_membership_status_array(pCtx, + pBufRemaining, (tDot11fFfVhtMembershipStatusArray *) + (pFrm + pFf->offset)); + break; + case SigFfVhtUserPositionArray: + dot11f_unpack_ff_vht_user_position_array(pCtx, + pBufRemaining, (tDot11fFfVhtUserPositionArray *) + (pFrm + pFf->offset)); + break; + case SigFfext_chan_switch_ann_action: + dot11f_unpack_ff_ext_chan_switch_ann_action(pCtx, + pBufRemaining, (tDot11fFfext_chan_switch_ann_action *) + (pFrm + pFf->offset)); + break; + case SigFfp2p_action_oui: + dot11f_unpack_ff_p2p_action_oui(pCtx, + pBufRemaining, (tDot11fFfp2p_action_oui *) + (pFrm + pFf->offset)); + break; + case SigFfp2p_action_subtype: + dot11f_unpack_ff_p2p_action_subtype(pCtx, + pBufRemaining, (tDot11fFfp2p_action_subtype *) + (pFrm + pFf->offset)); + break; + default: + FRAMES_LOG1(pCtx, FRLOGE, FRFL("INTERNAL ERROR: I don'" + "t know about the FF signature %d-- this is most " + "likely a 'framesc' bug.\n"), pFf->sig); + return DOT11F_INTERNAL_ERROR; + } + + pBufRemaining += pFf->size; + nBufRemaining -= pFf->size; + ++pFf; + } + + while (nBufRemaining) { + if (1 == nBufRemaining) { + FRAMES_LOG0(pCtx, FRLOGE, FRFL("This frame reports " + "only one byte remaining after it's fixed fields.\n")); + status |= DOT11F_INCOMPLETE_IE; + FRAMES_DBG_BREAK(); + goto MandatoryCheck; + } + + pIe = find_ie_defn(pCtx, pBufRemaining, nBufRemaining, IEs); + + eid = *pBufRemaining++; --nBufRemaining; + len = *pBufRemaining++; --nBufRemaining; + + if (pIe && pIe->noui) { + if (pIe->noui > nBufRemaining) { + FRAMES_LOG3(pCtx, FRLOGW, FRFL("IE %d reports " + "length %d, but it has an OUI of %d bytes.\n"), + eid, len, pIe->noui); + FRAMES_DUMP(pCtx, FRLOG1, pBuf, nBuf); + FRAMES_LOG2(pCtx, FRLOG1, FRFL("We've parsed %d by" + "tes of this buffer, and show %d left.\n"), + pBufRemaining - pBuf, nBufRemaining); + status |= DOT11F_INCOMPLETE_IE; + FRAMES_DBG_BREAK(); + goto MandatoryCheck; + } + pBufRemaining += pIe->noui; + nBufRemaining -= pIe->noui; + len -= pIe->noui; + } + + if (len > nBufRemaining) { + FRAMES_LOG3(pCtx, FRLOGW, FRFL("IE %d reports length %" + "d, but there are only %d bytes remaining in this" + " frame.\n"), eid, len, nBufRemaining); + FRAMES_DUMP(pCtx, FRLOG1, pBuf, nBuf); + FRAMES_LOG2(pCtx, FRLOG1, FRFL("We've parsed %d by" + "tes of this buffer, and show %d left.\n"), + pBufRemaining - pBuf, nBufRemaining); + status |= DOT11F_INCOMPLETE_IE; + FRAMES_DBG_BREAK(); + goto MandatoryCheck; + } + + if (pIe) { + if (nBufRemaining < pIe->minSize - pIe->noui - 2U) { + FRAMES_LOG3(pCtx, FRLOGW, FRFL("The IE %s must be " + "at least %d bytes in size, but there are onl" + "y %d bytes remaining in this frame.\n"), + pIe->name, pIe->minSize, nBufRemaining); + FRAMES_DUMP(pCtx, FRLOG1, pBuf, nBuf); + status |= DOT11F_INCOMPLETE_IE; + FRAMES_DBG_BREAK(); + goto MandatoryCheck; + } else { + if (len > pIe->maxSize - pIe->noui - 2U) { + FRAMES_LOG1(pCtx, FRLOGW, FRFL("The IE %s reports " + "an unexpectedly large size; it is presumably " + "more up-to-date than this parser, but this wa" + "rning may also indicate a corrupt frame.\n"), + pIe->name); + FRAMES_DUMP(pCtx, FRLOG1, pBuf, nBuf); + } + + countOffset = ((0 != pIe->arraybound) * + (*(uint16_t *)(pFrm + pIe->countOffset))); + if (0 != pIe->arraybound && countOffset >= pIe->arraybound) { + status |= DOT11F_DUPLICATE_IE; + goto skip_dup_ie; + } + switch (pIe->sig) { + case SigIeGTK: + status |= + dot11f_unpack_ie_gtk( + pCtx, pBufRemaining, len, + (tDot11fIEGTK *) + (pFrm + pIe->offset + + sizeof(tDot11fIEGTK) * + countOffset)); + break; + case SigIeIGTK: + status |= + dot11f_unpack_ie_igtk( + pCtx, pBufRemaining, len, + (tDot11fIEIGTK *) + (pFrm + pIe->offset + + sizeof(tDot11fIEIGTK) * + countOffset)); + break; + case SigIeR0KH_ID: + status |= + dot11f_unpack_ie_r0_kh_id( + pCtx, pBufRemaining, len, + (tDot11fIER0KH_ID *) + (pFrm + pIe->offset + + sizeof(tDot11fIER0KH_ID) * + countOffset)); + break; + case SigIeR1KH_ID: + status |= + dot11f_unpack_ie_r1_kh_id( + pCtx, pBufRemaining, len, + (tDot11fIER1KH_ID *) + (pFrm + pIe->offset + + sizeof(tDot11fIER1KH_ID) * + countOffset)); + break; + case SigIeAPChannelReport: + status |= + dot11f_unpack_ie_ap_channel_report( + pCtx, pBufRemaining, len, + (tDot11fIEAPChannelReport *) + (pFrm + pIe->offset + + sizeof(tDot11fIEAPChannelReport) * + countOffset)); + break; + case SigIeBcnReportingDetail: + status |= + dot11f_unpack_ie_bcn_reporting_detail( + pCtx, pBufRemaining, len, + (tDot11fIEBcnReportingDetail *) + (pFrm + pIe->offset + + sizeof(tDot11fIEBcnReportingDetail) * + countOffset)); + break; + case SigIeBeaconReportFrmBody: + status |= + dot11f_unpack_ie_beacon_report_frm_body( + pCtx, pBufRemaining, len, + (tDot11fIEBeaconReportFrmBody *) + (pFrm + pIe->offset + + sizeof(tDot11fIEBeaconReportFrmBody) * + countOffset)); + break; + case SigIeBeaconReporting: + status |= + dot11f_unpack_ie_beacon_reporting( + pCtx, pBufRemaining, len, + (tDot11fIEBeaconReporting *) + (pFrm + pIe->offset + + sizeof(tDot11fIEBeaconReporting) * + countOffset)); + break; + case SigIeCondensedCountryStr: + status |= + dot11f_unpack_ie_condensed_country_str( + pCtx, pBufRemaining, len, + (tDot11fIECondensedCountryStr *) + (pFrm + pIe->offset + + sizeof(tDot11fIECondensedCountryStr) * + countOffset)); + break; + case SigIeMeasurementPilot: + status |= + dot11f_unpack_ie_measurement_pilot( + pCtx, pBufRemaining, len, + (tDot11fIEMeasurementPilot *) + (pFrm + pIe->offset + + sizeof(tDot11fIEMeasurementPilot) * + countOffset)); + break; + case SigIeMultiBssid: + status |= + dot11f_unpack_ie_multi_bssid( + pCtx, pBufRemaining, len, + (tDot11fIEMultiBssid *) + (pFrm + pIe->offset + + sizeof(tDot11fIEMultiBssid) * + countOffset)); + break; + case SigIeRICData: + status |= + dot11f_unpack_ie_ric_data( + pCtx, pBufRemaining, len, + (tDot11fIERICData *) + (pFrm + pIe->offset + + sizeof(tDot11fIERICData) * + countOffset)); + break; + case SigIeRICDescriptor: + status |= + dot11f_unpack_ie_ric_descriptor( + pCtx, pBufRemaining, len, + (tDot11fIERICDescriptor *) + (pFrm + pIe->offset + + sizeof(tDot11fIERICDescriptor) * + countOffset)); + break; + case SigIeRRMEnabledCap: + status |= + dot11f_unpack_ie_rrm_enabled_cap( + pCtx, pBufRemaining, len, + (tDot11fIERRMEnabledCap *) + (pFrm + pIe->offset + + sizeof(tDot11fIERRMEnabledCap) * + countOffset)); + break; + case SigIeRequestedInfo: + status |= + dot11f_unpack_ie_requested_info( + pCtx, pBufRemaining, len, + (tDot11fIERequestedInfo *) + (pFrm + pIe->offset + + sizeof(tDot11fIERequestedInfo) * + countOffset)); + break; + case SigIeSSID: + status |= + dot11f_unpack_ie_ssid( + pCtx, pBufRemaining, len, + (tDot11fIESSID *) + (pFrm + pIe->offset + + sizeof(tDot11fIESSID) * + countOffset)); + break; + case SigIeSchedule: + status |= + dot11f_unpack_ie_schedule( + pCtx, pBufRemaining, len, + (tDot11fIESchedule *) + (pFrm + pIe->offset + + sizeof(tDot11fIESchedule) * + countOffset)); + break; + case SigIeTCLAS: + status |= + dot11f_unpack_ie_tclas( + pCtx, pBufRemaining, len, + (tDot11fIETCLAS *) + (pFrm + pIe->offset + + sizeof(tDot11fIETCLAS) * + countOffset)); + break; + case SigIeTCLASSPROC: + status |= dot11f_unpack_ie_common_func(pCtx, pBufRemaining, len, + (uint8_t *) &(((tDot11fIETCLASSPROC *)(pFrm + pIe->offset + sizeof(tDot11fIETCLASSPROC)*countOffset))->present), + (uint8_t *) &(((tDot11fIETCLASSPROC *)(pFrm + pIe->offset + sizeof(tDot11fIETCLASSPROC)*countOffset))->processing)); + break; + case SigIeTSDelay: + status |= + dot11f_unpack_ie_ts_delay( + pCtx, pBufRemaining, len, + (tDot11fIETSDelay *) + (pFrm + pIe->offset + + sizeof(tDot11fIETSDelay) * + countOffset)); + break; + case SigIeTSFInfo: + status |= + dot11f_unpack_ie_tsf_info( + pCtx, pBufRemaining, len, + (tDot11fIETSFInfo *) + (pFrm + pIe->offset + + sizeof(tDot11fIETSFInfo) * + countOffset)); + break; + case SigIeTSPEC: + status |= + dot11f_unpack_ie_tspec( + pCtx, pBufRemaining, len, + (tDot11fIETSPEC *) + (pFrm + pIe->offset + + sizeof(tDot11fIETSPEC) * + countOffset)); + break; + case SigIeVHTCaps: + status |= + dot11f_unpack_ie_vht_caps( + pCtx, pBufRemaining, len, + (tDot11fIEVHTCaps *) + (pFrm + pIe->offset + + sizeof(tDot11fIEVHTCaps) * + countOffset)); + break; + case SigIeVHTOperation: + status |= + dot11f_unpack_ie_vht_operation( + pCtx, pBufRemaining, len, + (tDot11fIEVHTOperation *) + (pFrm + pIe->offset + + sizeof(tDot11fIEVHTOperation) * + countOffset)); + break; + case SigIeWMMSchedule: + status |= + dot11f_unpack_ie_wmm_schedule( + pCtx, pBufRemaining, len, + (tDot11fIEWMMSchedule *) + (pFrm + pIe->offset + + sizeof(tDot11fIEWMMSchedule) * + countOffset)); + break; + case SigIeWMMTCLAS: + status |= + dot11f_unpack_ie_wmmtclas( + pCtx, pBufRemaining, len, + (tDot11fIEWMMTCLAS *) + (pFrm + pIe->offset + + sizeof(tDot11fIEWMMTCLAS) * + countOffset)); + break; + case SigIeWMMTCLASPROC: + status |= + dot11f_unpack_ie_wmmtclasproc( + pCtx, pBufRemaining, len, + (tDot11fIEWMMTCLASPROC *) + (pFrm + pIe->offset + + sizeof(tDot11fIEWMMTCLASPROC) * + countOffset)); + break; + case SigIeWMMTSDelay: + status |= + dot11f_unpack_ie_wmmts_delay( + pCtx, pBufRemaining, len, + (tDot11fIEWMMTSDelay *) + (pFrm + pIe->offset + + sizeof(tDot11fIEWMMTSDelay) * + countOffset)); + break; + case SigIeWMMTSPEC: + status |= + dot11f_unpack_ie_wmmtspec( + pCtx, pBufRemaining, len, + (tDot11fIEWMMTSPEC *) + (pFrm + pIe->offset + + sizeof(tDot11fIEWMMTSPEC) * + countOffset)); + break; + case SigIeWiderBWChanSwitchAnn: + status |= + dot11f_unpack_ie_wider_bw_chan_switch_ann( + pCtx, pBufRemaining, len, + (tDot11fIEWiderBWChanSwitchAnn *) + (pFrm + pIe->offset + + sizeof(tDot11fIEWiderBWChanSwitchAnn) * + countOffset)); + break; + case SigIeazimuth_req: + status |= + dot11f_unpack_ie_azimuth_req( + pCtx, pBufRemaining, len, + (tDot11fIEazimuth_req *) + (pFrm + pIe->offset + + sizeof(tDot11fIEazimuth_req) * + countOffset)); + break; + case SigIemax_age: + status |= + dot11f_unpack_ie_max_age( + pCtx, pBufRemaining, len, + (tDot11fIEmax_age *) + (pFrm + pIe->offset + + sizeof(tDot11fIEmax_age) * + countOffset)); + break; + case SigIeneighbor_rpt: + status |= + dot11f_unpack_ie_neighbor_rpt( + pCtx, pBufRemaining, len, + (tDot11fIEneighbor_rpt *) + (pFrm + pIe->offset + + sizeof(tDot11fIEneighbor_rpt) * + countOffset)); + break; + case SigIereq_mac_addr: + status |= + dot11f_unpack_ie_req_mac_addr( + pCtx, pBufRemaining, len, + (tDot11fIEreq_mac_addr *) + (pFrm + pIe->offset + + sizeof(tDot11fIEreq_mac_addr) * + countOffset)); + break; + case SigIetgt_mac_addr: + status |= + dot11f_unpack_ie_tgt_mac_addr( + pCtx, pBufRemaining, len, + (tDot11fIEtgt_mac_addr *) + (pFrm + pIe->offset + + sizeof(tDot11fIEtgt_mac_addr) * + countOffset)); + break; + case SigIevht_transmit_power_env: + status |= + dot11f_unpack_ie_vht_transmit_power_env( + pCtx, pBufRemaining, len, + (tDot11fIEvht_transmit_power_env *) + (pFrm + pIe->offset + + sizeof(tDot11fIEvht_transmit_power_env) * + countOffset)); + break; + case SigIeAID: + status |= + dot11f_unpack_ie_aid( + pCtx, pBufRemaining, len, + (tDot11fIEAID *) + (pFrm + pIe->offset + + sizeof(tDot11fIEAID) * + countOffset)); + break; + case SigIeCFParams: + status |= + dot11f_unpack_ie_cf_params( + pCtx, pBufRemaining, len, + (tDot11fIECFParams *) + (pFrm + pIe->offset + + sizeof(tDot11fIECFParams) * + countOffset)); + break; + case SigIeChallengeText: + status |= + dot11f_unpack_ie_challenge_text( + pCtx, pBufRemaining, len, + (tDot11fIEChallengeText *) + (pFrm + pIe->offset + + sizeof(tDot11fIEChallengeText) * + countOffset)); + break; + case SigIeChanSwitchAnn: + status |= + dot11f_unpack_ie_chan_switch_ann( + pCtx, pBufRemaining, len, + (tDot11fIEChanSwitchAnn *) + (pFrm + pIe->offset + + sizeof(tDot11fIEChanSwitchAnn) * + countOffset)); + break; + case SigIeChannelSwitchWrapper: + status |= + dot11f_unpack_ie_channel_switch_wrapper( + pCtx, pBufRemaining, len, + (tDot11fIEChannelSwitchWrapper *) + (pFrm + pIe->offset + + sizeof(tDot11fIEChannelSwitchWrapper) * + countOffset)); + break; + case SigIeCountry: + status |= + dot11f_unpack_ie_country( + pCtx, pBufRemaining, len, + (tDot11fIECountry *) + (pFrm + pIe->offset + + sizeof(tDot11fIECountry) * + countOffset)); + break; + case SigIeDSParams: + status |= dot11f_unpack_ie_common_func(pCtx, pBufRemaining, len, + (uint8_t *) &(((tDot11fIEDSParams *)(pFrm + pIe->offset + sizeof(tDot11fIEDSParams)*countOffset))->present), + (uint8_t *) &(((tDot11fIEDSParams *)(pFrm + pIe->offset + sizeof(tDot11fIEDSParams)*countOffset))->curr_channel)); + break; + case SigIeEDCAParamSet: + status |= + dot11f_unpack_ie_edca_param_set( + pCtx, pBufRemaining, len, + (tDot11fIEEDCAParamSet *) + (pFrm + pIe->offset + + sizeof(tDot11fIEEDCAParamSet) * + countOffset)); + break; + case SigIeERPInfo: + status |= + dot11f_unpack_ie_erp_info( + pCtx, pBufRemaining, len, + (tDot11fIEERPInfo *) + (pFrm + pIe->offset + + sizeof(tDot11fIEERPInfo) * + countOffset)); + break; + case SigIeESECckmOpaque: + status |= + dot11f_unpack_ie_ese_cckm_opaque( + pCtx, pBufRemaining, len, + (tDot11fIEESECckmOpaque *) + (pFrm + pIe->offset + + sizeof(tDot11fIEESECckmOpaque) * + countOffset)); + break; + case SigIeESERadMgmtCap: + status |= + dot11f_unpack_ie_ese_rad_mgmt_cap( + pCtx, pBufRemaining, len, + (tDot11fIEESERadMgmtCap *) + (pFrm + pIe->offset + + sizeof(tDot11fIEESERadMgmtCap) * + countOffset)); + break; + case SigIeESETrafStrmMet: + status |= + dot11f_unpack_ie_ese_traf_strm_met( + pCtx, pBufRemaining, len, + (tDot11fIEESETrafStrmMet *) + (pFrm + pIe->offset + + sizeof(tDot11fIEESETrafStrmMet) * + countOffset)); + break; + case SigIeESETrafStrmRateSet: + status |= + dot11f_unpack_ie_ese_traf_strm_rate_set( + pCtx, pBufRemaining, len, + (tDot11fIEESETrafStrmRateSet *) + (pFrm + pIe->offset + + sizeof(tDot11fIEESETrafStrmRateSet) * + countOffset)); + break; + case SigIeESETxmitPower: + status |= + dot11f_unpack_ie_ese_txmit_power( + pCtx, pBufRemaining, len, + (tDot11fIEESETxmitPower *) + (pFrm + pIe->offset + + sizeof(tDot11fIEESETxmitPower) * + countOffset)); + break; + case SigIeESEVersion: + status |= + dot11f_unpack_ie_ese_version( + pCtx, pBufRemaining, len, + (tDot11fIEESEVersion *) + (pFrm + pIe->offset + + sizeof(tDot11fIEESEVersion) * + countOffset)); + break; + case SigIeExtCap: + status |= + dot11f_unpack_ie_ext_cap( + pCtx, pBufRemaining, len, + (tDot11fIEExtCap *) + (pFrm + pIe->offset + + sizeof(tDot11fIEExtCap) * + countOffset)); + break; + case SigIeExtSuppRates: + status |= + dot11f_unpack_ie_ext_supp_rates( + pCtx, pBufRemaining, len, + (tDot11fIEExtSuppRates *) + (pFrm + pIe->offset + + sizeof(tDot11fIEExtSuppRates) * + countOffset)); + break; + case SigIeFHParamSet: + status |= + dot11f_unpack_ie_fh_param_set( + pCtx, pBufRemaining, len, + (tDot11fIEFHParamSet *) + (pFrm + pIe->offset + + sizeof(tDot11fIEFHParamSet) * + countOffset)); + break; + case SigIeFHParams: + status |= + dot11f_unpack_ie_fh_params( + pCtx, pBufRemaining, len, + (tDot11fIEFHParams *) + (pFrm + pIe->offset + + sizeof(tDot11fIEFHParams) * + countOffset)); + break; + case SigIeFHPattTable: + status |= + dot11f_unpack_ie_fh_patt_table( + pCtx, pBufRemaining, len, + (tDot11fIEFHPattTable *) + (pFrm + pIe->offset + + sizeof(tDot11fIEFHPattTable) * + countOffset)); + break; + case SigIeFTInfo: + status |= + dot11f_unpack_ie_ft_info( + pCtx, pBufRemaining, len, + (tDot11fIEFTInfo *) + (pFrm + pIe->offset + + sizeof(tDot11fIEFTInfo) * + countOffset)); + break; + case SigIeHTCaps: + status |= + dot11f_unpack_ie_ht_caps( + pCtx, pBufRemaining, len, + (tDot11fIEHTCaps *) + (pFrm + pIe->offset + + sizeof(tDot11fIEHTCaps) * + countOffset)); + break; + case SigIeHTInfo: + status |= + dot11f_unpack_ie_ht_info( + pCtx, pBufRemaining, len, + (tDot11fIEHTInfo *) + (pFrm + pIe->offset + + sizeof(tDot11fIEHTInfo) * + countOffset)); + break; + case SigIeIBSSParams: + status |= + dot11f_unpack_ie_ibss_params( + pCtx, pBufRemaining, len, + (tDot11fIEIBSSParams *) + (pFrm + pIe->offset + + sizeof(tDot11fIEIBSSParams) * + countOffset)); + break; + case SigIeLinkIdentifier: + status |= + dot11f_unpack_ie_link_identifier( + pCtx, pBufRemaining, len, + (tDot11fIELinkIdentifier *) + (pFrm + pIe->offset + + sizeof(tDot11fIELinkIdentifier) * + countOffset)); + break; + case SigIeMBO_IE: + status |= + dot11f_unpack_ie_MBO_IE( + pCtx, pBufRemaining, len, + (tDot11fIEMBO_IE *) + (pFrm + pIe->offset + + sizeof(tDot11fIEMBO_IE) * + countOffset)); + break; + case SigIeMeasurementReport: + status |= + dot11f_unpack_ie_measurement_report( + pCtx, pBufRemaining, len, + (tDot11fIEMeasurementReport *) + (pFrm + pIe->offset + + sizeof(tDot11fIEMeasurementReport) * + countOffset)); + break; + case SigIeMeasurementRequest: + status |= + dot11f_unpack_ie_measurement_request( + pCtx, pBufRemaining, len, + (tDot11fIEMeasurementRequest *) + (pFrm + pIe->offset + + sizeof(tDot11fIEMeasurementRequest) * + countOffset)); + break; + case SigIeMobilityDomain: + status |= + dot11f_unpack_ie_mobility_domain( + pCtx, pBufRemaining, len, + (tDot11fIEMobilityDomain *) + (pFrm + pIe->offset + + sizeof(tDot11fIEMobilityDomain) * + countOffset)); + break; + case SigIeNeighborReport: + status |= + dot11f_unpack_ie_neighbor_report( + pCtx, pBufRemaining, len, + (tDot11fIENeighborReport *) + (pFrm + pIe->offset + + sizeof(tDot11fIENeighborReport) * + countOffset)); + break; + case SigIeOBSSScanParameters: + status |= + dot11f_unpack_ie_obss_scan_parameters( + pCtx, pBufRemaining, len, + (tDot11fIEOBSSScanParameters *) + (pFrm + pIe->offset + + sizeof(tDot11fIEOBSSScanParameters) * + countOffset)); + break; + case SigIeOperatingMode: + status |= + dot11f_unpack_ie_operating_mode( + pCtx, pBufRemaining, len, + (tDot11fIEOperatingMode *) + (pFrm + pIe->offset + + sizeof(tDot11fIEOperatingMode) * + countOffset)); + break; + case SigIeP2PAssocReq: + status |= + dot11f_unpack_ie_p2_p_assoc_req( + pCtx, pBufRemaining, len, + (tDot11fIEP2PAssocReq *) + (pFrm + pIe->offset + + sizeof(tDot11fIEP2PAssocReq) * + countOffset)); + break; + case SigIeP2PAssocRes: + status |= + dot11f_unpack_ie_p2_p_assoc_res( + pCtx, pBufRemaining, len, + (tDot11fIEP2PAssocRes *) + (pFrm + pIe->offset + + sizeof(tDot11fIEP2PAssocRes) * + countOffset)); + break; + case SigIeP2PBeacon: + status |= + dot11f_unpack_ie_p2_p_beacon( + pCtx, pBufRemaining, len, + (tDot11fIEP2PBeacon *) + (pFrm + pIe->offset + + sizeof(tDot11fIEP2PBeacon) * + countOffset)); + break; + case SigIeP2PBeaconProbeRes: + status |= + dot11f_unpack_ie_p2_p_beacon_probe_res( + pCtx, pBufRemaining, len, + (tDot11fIEP2PBeaconProbeRes *) + (pFrm + pIe->offset + + sizeof(tDot11fIEP2PBeaconProbeRes) * + countOffset)); + break; + case SigIeP2PDeAuth: + status |= + dot11f_unpack_ie_p2_p_de_auth( + pCtx, pBufRemaining, len, + (tDot11fIEP2PDeAuth *) + (pFrm + pIe->offset + + sizeof(tDot11fIEP2PDeAuth) * + countOffset)); + break; + case SigIeP2PDisAssoc: + status |= + dot11f_unpack_ie_p2_p_dis_assoc( + pCtx, pBufRemaining, len, + (tDot11fIEP2PDisAssoc *) + (pFrm + pIe->offset + + sizeof(tDot11fIEP2PDisAssoc) * + countOffset)); + break; + case SigIeP2PIEOpaque: + status |= + dot11f_unpack_ie_p2_pie_opaque( + pCtx, pBufRemaining, len, + (tDot11fIEP2PIEOpaque *) + (pFrm + pIe->offset + + sizeof(tDot11fIEP2PIEOpaque) * + countOffset)); + break; + case SigIeP2PProbeReq: + status |= + dot11f_unpack_ie_p2_p_probe_req( + pCtx, pBufRemaining, len, + (tDot11fIEP2PProbeReq *) + (pFrm + pIe->offset + + sizeof(tDot11fIEP2PProbeReq) * + countOffset)); + break; + case SigIeP2PProbeRes: + status |= + dot11f_unpack_ie_p2_p_probe_res( + pCtx, pBufRemaining, len, + (tDot11fIEP2PProbeRes *) + (pFrm + pIe->offset + + sizeof(tDot11fIEP2PProbeRes) * + countOffset)); + break; + case SigIePTIControl: + status |= + dot11f_unpack_ie_pti_control( + pCtx, pBufRemaining, len, + (tDot11fIEPTIControl *) + (pFrm + pIe->offset + + sizeof(tDot11fIEPTIControl) * + countOffset)); + break; + case SigIePUBufferStatus: + status |= + dot11f_unpack_ie_pu_buffer_status( + pCtx, pBufRemaining, len, + (tDot11fIEPUBufferStatus *) + (pFrm + pIe->offset + + sizeof(tDot11fIEPUBufferStatus) * + countOffset)); + break; + case SigIePowerCaps: + status |= + dot11f_unpack_ie_power_caps( + pCtx, pBufRemaining, len, + (tDot11fIEPowerCaps *) + (pFrm + pIe->offset + + sizeof(tDot11fIEPowerCaps) * + countOffset)); + break; + case SigIePowerConstraints: + status |= + dot11f_unpack_ie_power_constraints( + pCtx, pBufRemaining, len, + (tDot11fIEPowerConstraints *) + (pFrm + pIe->offset + + sizeof(tDot11fIEPowerConstraints) * + countOffset)); + break; + case SigIeQBSSLoad: + status |= + dot11f_unpack_ie_qbss_load( + pCtx, pBufRemaining, len, + (tDot11fIEQBSSLoad *) + (pFrm + pIe->offset + + sizeof(tDot11fIEQBSSLoad) * + countOffset)); + break; + case SigIeQCN_IE: + status |= + dot11f_unpack_ie_QCN_IE( + pCtx, pBufRemaining, len, + (tDot11fIEQCN_IE *) + (pFrm + pIe->offset + + sizeof(tDot11fIEQCN_IE) * + countOffset)); + break; + case SigIeQComVendorIE: + status |= + dot11f_unpack_ie_QComVendorIE( + pCtx, pBufRemaining, len, + (tDot11fIEQComVendorIE *) + (pFrm + pIe->offset + + sizeof(tDot11fIEQComVendorIE) * + countOffset)); + break; + case SigIeQOSCapsAp: + status |= + dot11f_unpack_ie_qos_caps_ap( + pCtx, pBufRemaining, len, + (tDot11fIEQOSCapsAp *) + (pFrm + pIe->offset + + sizeof(tDot11fIEQOSCapsAp) * + countOffset)); + break; + case SigIeQOSCapsStation: + status |= + dot11f_unpack_ie_qos_caps_station( + pCtx, pBufRemaining, len, + (tDot11fIEQOSCapsStation *) + (pFrm + pIe->offset + + sizeof(tDot11fIEQOSCapsStation) * + countOffset)); + break; + case SigIeQosMapSet: + status |= + dot11f_unpack_ie_qos_map_set( + pCtx, pBufRemaining, len, + (tDot11fIEQosMapSet *) + (pFrm + pIe->offset + + sizeof(tDot11fIEQosMapSet) * + countOffset)); + break; + case SigIeQuiet: + status |= + dot11f_unpack_ie_quiet( + pCtx, pBufRemaining, len, + (tDot11fIEQuiet *) + (pFrm + pIe->offset + + sizeof(tDot11fIEQuiet) * + countOffset)); + break; + case SigIeRCPIIE: + status |= + dot11f_unpack_ie_rcpiie( + pCtx, pBufRemaining, len, + (tDot11fIERCPIIE *) + (pFrm + pIe->offset + + sizeof(tDot11fIERCPIIE) * + countOffset)); + break; + case SigIeRICDataDesc: + /* reset the pointers back since this is a container IE and it doesnt have its own EID and Len. */ + pBufRemaining -= 2; + nBufRemaining += 2; + if (pIe && pIe->noui) { + pBufRemaining -= pIe->noui; + nBufRemaining += pIe->noui; + len += pIe->noui; + } + status |= get_container_ies_len(pCtx, pBufRemaining, nBufRemaining, &len, IES_RICDataDesc); + if (status != DOT11F_PARSE_SUCCESS && status != DOT11F_UNKNOWN_IES) + break; + status |= + dot11f_unpack_ie_ric_data_desc( + pCtx, pBufRemaining, len, + (tDot11fIERICDataDesc *) + (pFrm + pIe->offset + + sizeof(tDot11fIERICDataDesc) * + countOffset)); + break; + case SigIeRSN: + status |= + dot11f_unpack_ie_rsn( + pCtx, pBufRemaining, len, + (tDot11fIERSN *) + (pFrm + pIe->offset + + sizeof(tDot11fIERSN) * + countOffset)); + break; + case SigIeRSNIIE: + status |= + dot11f_unpack_ie_rsniie( + pCtx, pBufRemaining, len, + (tDot11fIERSNIIE *) + (pFrm + pIe->offset + + sizeof(tDot11fIERSNIIE) * + countOffset)); + break; + case SigIeRSNOpaque: + status |= + dot11f_unpack_ie_rsn_opaque( + pCtx, pBufRemaining, len, + (tDot11fIERSNOpaque *) + (pFrm + pIe->offset + + sizeof(tDot11fIERSNOpaque) * + countOffset)); + break; + case SigIeSuppChannels: + status |= + dot11f_unpack_ie_supp_channels( + pCtx, pBufRemaining, len, + (tDot11fIESuppChannels *) + (pFrm + pIe->offset + + sizeof(tDot11fIESuppChannels) * + countOffset)); + break; + case SigIeSuppOperatingClasses: + status |= + dot11f_unpack_ie_supp_operating_classes( + pCtx, pBufRemaining, len, + (tDot11fIESuppOperatingClasses *) + (pFrm + pIe->offset + + sizeof(tDot11fIESuppOperatingClasses) * + countOffset)); + break; + case SigIeSuppRates: + status |= + dot11f_unpack_ie_supp_rates( + pCtx, pBufRemaining, len, + (tDot11fIESuppRates *) + (pFrm + pIe->offset + + sizeof(tDot11fIESuppRates) * + countOffset)); + break; + case SigIeTIM: + status |= + dot11f_unpack_ie_tim( + pCtx, pBufRemaining, len, + (tDot11fIETIM *) + (pFrm + pIe->offset + + sizeof(tDot11fIETIM) * + countOffset)); + break; + case SigIeTPCReport: + status |= + dot11f_unpack_ie_tpc_report( + pCtx, pBufRemaining, len, + (tDot11fIETPCReport *) + (pFrm + pIe->offset + + sizeof(tDot11fIETPCReport) * + countOffset)); + break; + case SigIeTPCRequest: + status |= + dot11f_unpack_ie_tpc_request( + pCtx, pBufRemaining, len, + (tDot11fIETPCRequest *) + (pFrm + pIe->offset + + sizeof(tDot11fIETPCRequest) * + countOffset)); + break; + case SigIeTimeAdvertisement: + status |= + dot11f_unpack_ie_time_advertisement( + pCtx, pBufRemaining, len, + (tDot11fIETimeAdvertisement *) + (pFrm + pIe->offset + + sizeof(tDot11fIETimeAdvertisement) * + countOffset)); + break; + case SigIeTimeoutInterval: + status |= + dot11f_unpack_ie_timeout_interval( + pCtx, pBufRemaining, len, + (tDot11fIETimeoutInterval *) + (pFrm + pIe->offset + + sizeof(tDot11fIETimeoutInterval) * + countOffset)); + break; + case SigIeVHTExtBssLoad: + status |= + dot11f_unpack_ie_vht_ext_bss_load( + pCtx, pBufRemaining, len, + (tDot11fIEVHTExtBssLoad *) + (pFrm + pIe->offset + + sizeof(tDot11fIEVHTExtBssLoad) * + countOffset)); + break; + case SigIeVendor1IE: + status |= + dot11f_unpack_ie_vendor1_ie( + pCtx, pBufRemaining, len, + (tDot11fIEVendor1IE *) + (pFrm + pIe->offset + + sizeof(tDot11fIEVendor1IE) * + countOffset)); + break; + case SigIeVendor3IE: + status |= + dot11f_unpack_ie_vendor3_ie( + pCtx, pBufRemaining, len, + (tDot11fIEVendor3IE *) + (pFrm + pIe->offset + + sizeof(tDot11fIEVendor3IE) * + countOffset)); + break; + case SigIeWAPI: + status |= + dot11f_unpack_ie_wapi( + pCtx, pBufRemaining, len, + (tDot11fIEWAPI *) + (pFrm + pIe->offset + + sizeof(tDot11fIEWAPI) * + countOffset)); + break; + case SigIeWAPIOpaque: + status |= + dot11f_unpack_ie_wapi_opaque( + pCtx, pBufRemaining, len, + (tDot11fIEWAPIOpaque *) + (pFrm + pIe->offset + + sizeof(tDot11fIEWAPIOpaque) * + countOffset)); + break; + case SigIeWFATPC: + status |= + dot11f_unpack_ie_wfatpc( + pCtx, pBufRemaining, len, + (tDot11fIEWFATPC *) + (pFrm + pIe->offset + + sizeof(tDot11fIEWFATPC) * + countOffset)); + break; + case SigIeWFDIEOpaque: + status |= + dot11f_unpack_ie_wfdie_opaque( + pCtx, pBufRemaining, len, + (tDot11fIEWFDIEOpaque *) + (pFrm + pIe->offset + + sizeof(tDot11fIEWFDIEOpaque) * + countOffset)); + break; + case SigIeWMMCaps: + status |= + dot11f_unpack_ie_wmm_caps( + pCtx, pBufRemaining, len, + (tDot11fIEWMMCaps *) + (pFrm + pIe->offset + + sizeof(tDot11fIEWMMCaps) * + countOffset)); + break; + case SigIeWMMInfoAp: + status |= + dot11f_unpack_ie_wmm_info_ap( + pCtx, pBufRemaining, len, + (tDot11fIEWMMInfoAp *) + (pFrm + pIe->offset + + sizeof(tDot11fIEWMMInfoAp) * + countOffset)); + break; + case SigIeWMMInfoStation: + status |= + dot11f_unpack_ie_wmm_info_station( + pCtx, pBufRemaining, len, + (tDot11fIEWMMInfoStation *) + (pFrm + pIe->offset + + sizeof(tDot11fIEWMMInfoStation) * + countOffset)); + break; + case SigIeWMMParams: + status |= + dot11f_unpack_ie_wmm_params( + pCtx, pBufRemaining, len, + (tDot11fIEWMMParams *) + (pFrm + pIe->offset + + sizeof(tDot11fIEWMMParams) * + countOffset)); + break; + case SigIeWPA: + status |= + dot11f_unpack_ie_wpa( + pCtx, pBufRemaining, len, + (tDot11fIEWPA *) + (pFrm + pIe->offset + + sizeof(tDot11fIEWPA) * + countOffset)); + break; + case SigIeWPAOpaque: + status |= + dot11f_unpack_ie_wpa_opaque( + pCtx, pBufRemaining, len, + (tDot11fIEWPAOpaque *) + (pFrm + pIe->offset + + sizeof(tDot11fIEWPAOpaque) * + countOffset)); + break; + case SigIeWSC: + status |= + dot11f_unpack_ie_wsc( + pCtx, pBufRemaining, len, + (tDot11fIEWSC *) + (pFrm + pIe->offset + + sizeof(tDot11fIEWSC) * + countOffset)); + break; + case SigIeWscAssocReq: + status |= + dot11f_unpack_ie_wsc_assoc_req( + pCtx, pBufRemaining, len, + (tDot11fIEWscAssocReq *) + (pFrm + pIe->offset + + sizeof(tDot11fIEWscAssocReq) * + countOffset)); + break; + case SigIeWscAssocRes: + status |= + dot11f_unpack_ie_wsc_assoc_res( + pCtx, pBufRemaining, len, + (tDot11fIEWscAssocRes *) + (pFrm + pIe->offset + + sizeof(tDot11fIEWscAssocRes) * + countOffset)); + break; + case SigIeWscBeacon: + status |= + dot11f_unpack_ie_wsc_beacon( + pCtx, pBufRemaining, len, + (tDot11fIEWscBeacon *) + (pFrm + pIe->offset + + sizeof(tDot11fIEWscBeacon) * + countOffset)); + break; + case SigIeWscBeaconProbeRes: + status |= + dot11f_unpack_ie_wsc_beacon_probe_res( + pCtx, pBufRemaining, len, + (tDot11fIEWscBeaconProbeRes *) + (pFrm + pIe->offset + + sizeof(tDot11fIEWscBeaconProbeRes) * + countOffset)); + break; + case SigIeWscIEOpaque: + status |= + dot11f_unpack_ie_wsc_ie_opaque( + pCtx, pBufRemaining, len, + (tDot11fIEWscIEOpaque *) + (pFrm + pIe->offset + + sizeof(tDot11fIEWscIEOpaque) * + countOffset)); + break; + case SigIeWscProbeReq: + status |= + dot11f_unpack_ie_wsc_probe_req( + pCtx, pBufRemaining, len, + (tDot11fIEWscProbeReq *) + (pFrm + pIe->offset + + sizeof(tDot11fIEWscProbeReq) * + countOffset)); + break; + case SigIeWscProbeRes: + status |= + dot11f_unpack_ie_wsc_probe_res( + pCtx, pBufRemaining, len, + (tDot11fIEWscProbeRes *) + (pFrm + pIe->offset + + sizeof(tDot11fIEWscProbeRes) * + countOffset)); + break; + case SigIeWscReassocRes: + status |= + dot11f_unpack_ie_wsc_reassoc_res( + pCtx, pBufRemaining, len, + (tDot11fIEWscReassocRes *) + (pFrm + pIe->offset + + sizeof(tDot11fIEWscReassocRes) * + countOffset)); + break; + case SigIeext_chan_switch_ann: + status |= + dot11f_unpack_ie_ext_chan_switch_ann( + pCtx, pBufRemaining, len, + (tDot11fIEext_chan_switch_ann *) + (pFrm + pIe->offset + + sizeof(tDot11fIEext_chan_switch_ann) * + countOffset)); + break; + case SigIehs20vendor_ie: + status |= + dot11f_unpack_ie_hs20vendor_ie( + pCtx, pBufRemaining, len, + (tDot11fIEhs20vendor_ie *) + (pFrm + pIe->offset + + sizeof(tDot11fIEhs20vendor_ie) * + countOffset)); + break; + case SigIeht2040_bss_coexistence: + status |= + dot11f_unpack_ie_ht2040_bss_coexistence( + pCtx, pBufRemaining, len, + (tDot11fIEht2040_bss_coexistence *) + (pFrm + pIe->offset + + sizeof(tDot11fIEht2040_bss_coexistence) * + countOffset)); + break; + case SigIeht2040_bss_intolerant_report: + status |= + dot11f_unpack_ie_ht2040_bss_intolerant_report( + pCtx, pBufRemaining, len, + (tDot11fIEht2040_bss_intolerant_report *) + (pFrm + pIe->offset + + sizeof(tDot11fIEht2040_bss_intolerant_report) * + countOffset)); + break; + case SigIesec_chan_offset_ele: + status |= + dot11f_unpack_ie_sec_chan_offset_ele( + pCtx, pBufRemaining, len, + (tDot11fIEsec_chan_offset_ele *) + (pFrm + pIe->offset + + sizeof(tDot11fIEsec_chan_offset_ele) * + countOffset)); + break; + case SigIevendor_vht_ie: + status |= + dot11f_unpack_ie_vendor_vht_ie( + pCtx, pBufRemaining, len, + (tDot11fIEvendor_vht_ie *) + (pFrm + pIe->offset + + sizeof(tDot11fIEvendor_vht_ie) * + countOffset)); + break; + default: + FRAMES_LOG1(pCtx, FRLOGE, FRFL("INTERNAL ERROR" + ": I don't know about the IE signature %d" + "-- this is most likely a 'framesc' bug.\n"), + pIe->sig); + FRAMES_DBG_BREAK(); + return DOT11F_INTERNAL_ERROR; + } + if (pIe->arraybound) + (++(*(uint16_t *)(pFrm + pIe->countOffset))); + } + } else { + FRAMES_LOG2(pCtx, FRLOG3, FRFL("Skipping unknown IE %d" + " (length %d)\n"), eid, len); + FRAMES_DUMP(pCtx, FRLOG3, pBufRemaining - 2, len); + status |= DOT11F_UNKNOWN_IES; + } + +skip_dup_ie: + pBufRemaining += len; + + if (len > nBufRemaining) { + FRAMES_LOG0(pCtx, FRLOGW, FRFL("This IE extends past " + "the buffer as it was defined to us. This could" + "mean a corrupt frame, or just an incorrect leng" + "th parameter.\n")); + FRAMES_DBG_BREAK(); + status |= DOT11F_LAST_IE_TOO_LONG; + goto MandatoryCheck; + } + + nBufRemaining -= len; + + } + +MandatoryCheck: + pIe = &IEs[0]; + while (0xff != pIe->eid) { + if (pIe->fMandatory) { + pfFound = (tFRAMES_BOOL *)(pFrm + pIe->offset + + pIe->presenceOffset); + if (!*pfFound) { + FRAMES_LOG1(pCtx, FRLOGW, FRFL("ERROR: The mandato" + "ry IE %s wasn't seen.\n"), + pIe->name); + FRAMES_DBG_BREAK(); + status |= DOT11F_MANDATORY_IE_MISSING; + } + } + ++pIe; + } + + return status; +} /* End unpack_core. */ + +static uint32_t unpack_tlv_core(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint32_t nBuf, + const tTLVDefn TLVs[], + uint8_t *pFrm, + size_t nFrm) +{ + const tTLVDefn *pTlv; + uint32_t nBufRemaining, status, npec; + uint16_t id, len; + uint8_t *pBufRemaining, *pfFound; + + (void)pCtx; /* Shutup the compiler */ + (void)nFrm; + status = DOT11F_PARSE_SUCCESS; + pBufRemaining = pBuf; + nBufRemaining = nBuf; + + /* While we have data... */ + while (nBufRemaining) { + if (3 > nBufRemaining) { + FRAMES_LOG0(pCtx, FRLOGE, FRFL("This frame reports " + "fewer three byte(s) remaining.\n")); + status |= DOT11F_INCOMPLETE_TLV; + FRAMES_DBG_BREAK(); + goto MandatoryCheck; + } + + npec = 0U; + + /* Look for a matching TLV definition, */ + pTlv = find_tlv_defn(pCtx, pBufRemaining, nBufRemaining, TLVs); + /* consume the type, */ + if (pTlv) { + if (pTlv->sType == 2) { + framesntohs(pCtx, &id, pBufRemaining, pTlv->fMsb); + pBufRemaining += 2; + nBufRemaining -= 2; + } else { + id = *pBufRemaining; + pBufRemaining += 1; + nBufRemaining -= 1; + } + /* & length, */ + if (pTlv->sLen == 2) { + framesntohs(pCtx, &len, pBufRemaining, pTlv->fMsb); + if (2 > nBufRemaining) { + FRAMES_LOG0(pCtx, FRLOGE, FRFL("This frame reports " + "fewer two byte(s) remaining.\n")); + status |= DOT11F_INCOMPLETE_TLV; + FRAMES_DBG_BREAK(); + goto MandatoryCheck; + } + pBufRemaining += 2; + nBufRemaining -= 2; + } else { + len = *pBufRemaining; + pBufRemaining += 1; + nBufRemaining -= 1; + } + } else { + pBufRemaining += TLVs[0].sType; + nBufRemaining -= TLVs[0].sType; + framesntohs(pCtx, &len, pBufRemaining, (TLVs[0].sType == 2)); + if (2 > nBufRemaining) { + FRAMES_LOG0(pCtx, FRLOGE, FRFL("This frame reports " + "fewer two byte(s) remaining.\n")); + status |= DOT11F_INCOMPLETE_TLV; + FRAMES_DBG_BREAK(); + goto MandatoryCheck; + } + pBufRemaining += 2; + nBufRemaining -= 2; + } + + if (pTlv && pTlv->pec) { + npec = 3U; + if (3 > nBufRemaining) { + FRAMES_LOG2(pCtx, FRLOGW, FRFL("TLV %d reports length" + "%d, but it has a Private Enterprise Code (3 byte" + "s.\n"), id, len); + FRAMES_DUMP(pCtx, FRLOG1, pBuf, nBuf); + FRAMES_LOG2(pCtx, FRLOG1, FRFL("We've parsed %d bytes" + "of this buffer, and show %d left.\n"), + pBufRemaining - pBuf, nBufRemaining); + status |= DOT11F_INCOMPLETE_TLV; + FRAMES_DBG_BREAK(); + goto MandatoryCheck; + } + pBufRemaining += 3; + nBufRemaining -= 3; + len -= 3; + } + + /* Whether we found a hit or not, we can validate the reported */ + /* length of this TLV: */ + if (len > nBufRemaining) { + FRAMES_LOG3(pCtx, FRLOGW, FRFL("TLV %d reports length %" + "d, but there are only %d bytes remaining in this f" + "rame.\n"), id, len, nBufRemaining); + FRAMES_DUMP(pCtx, FRLOG1, pBuf, nBuf); + FRAMES_LOG2(pCtx, FRLOG1, FRFL("We've parsed %d bytes" + " of this buffer, and show %d left.\n"), + pBufRemaining - pBuf, nBufRemaining); + status |= DOT11F_INCOMPLETE_TLV; + FRAMES_DBG_BREAK(); + goto MandatoryCheck; + } + + /* Now, *if* we found a hit... */ + if (pTlv) { + if (len < pTlv->minSize - npec) { + FRAMES_LOG3(pCtx, FRLOGW, FRFL("The IE %s must be " + "at least %d bytes in size, but the size is only " + "%d bytes.\n"), + pTlv->name, pTlv->minSize, len); + FRAMES_DUMP(pCtx, FRLOG1, pBuf, nBuf); + status |= DOT11F_INCOMPLETE_TLV; + FRAMES_DBG_BREAK(); + goto MandatoryCheck; + } + if (nBufRemaining < pTlv->minSize - npec - (pTlv->sType + pTlv->sLen)) { + FRAMES_LOG3(pCtx, FRLOGW, FRFL("The IE %s must be " + "at least %d bytes in size, but there are only " + "%d bytes remaining in this frame.\n"), + pTlv->name, pTlv->minSize, nBufRemaining); + FRAMES_DUMP(pCtx, FRLOG1, pBuf, nBuf); + status |= DOT11F_INCOMPLETE_TLV; + FRAMES_DBG_BREAK(); + goto MandatoryCheck; + } else if (len > pTlv->maxSize - npec - (pTlv->sType + pTlv->sLen)) { + FRAMES_LOG1(pCtx, FRLOGW, FRFL("The TLV %s reports " + "an illegally large size; this TLV is presumably" + "corrupt or otherwise invalid & will be skipped " + "ipped.\n"), pTlv->name); + FRAMES_DUMP(pCtx, FRLOG1, pBuf, nBuf); + FRAMES_LOG2(pCtx, FRLOG1, FRFL("We've parsed %d by" + "tes of this buffer, and show %d left.\n"), + pBufRemaining - pBuf, nBufRemaining); + FRAMES_DBG_BREAK(); + status |= DOT11F_SKIPPED_BAD_TLV; + } else { + switch (pTlv->sig) { + case SigTlvAuthorizedMACs: + status |= + dot11f_unpack_tlv_authorized_ma_cs(pCtx, + pBufRemaining, len, + (tDot11fTLVAuthorizedMACs *) + (pFrm + pTlv->offset)); + break; + case SigTlvRequestToEnroll: + status |= + dot11f_unpack_tlv_common_func(pCtx, + pBufRemaining, len, + (uint8_t *)&(((tDot11fTLVRequestToEnroll *) + (pFrm + pTlv->offset))->present), + (uint8_t *)&(((tDot11fTLVRequestToEnroll *) + (pFrm + pTlv->offset))->req)); + break; + case SigTlvVersion2: + status |= + dot11f_unpack_tlv_version2(pCtx, + pBufRemaining, len, + (tDot11fTLVVersion2 *) + (pFrm + pTlv->offset)); + break; + case SigTlvAPSetupLocked: + status |= + dot11f_unpack_tlv_common_func(pCtx, + pBufRemaining, len, + (uint8_t *)&(((tDot11fTLVAPSetupLocked *) + (pFrm + pTlv->offset))->present), + (uint8_t *)&(((tDot11fTLVAPSetupLocked *) + (pFrm + pTlv->offset))->fLocked)); + break; + case SigTlvAssociationState: + status |= + dot11f_unpack_tlv_common_func2(pCtx, + pBufRemaining, len, + (uint8_t *)&(((tDot11fTLVAssociationState *) + (pFrm + pTlv->offset))->present), + (uint16_t *)&(((tDot11fTLVAssociationState *) + (pFrm + pTlv->offset))->state)); + break; + case SigTlvConfigMethods: + status |= + dot11f_unpack_tlv_common_func2(pCtx, + pBufRemaining, len, + (uint8_t *)&(((tDot11fTLVConfigMethods *) + (pFrm + pTlv->offset))->present), + (uint16_t *)&(((tDot11fTLVConfigMethods *) + (pFrm + pTlv->offset))->methods)); + break; + case SigTlvConfigurationError: + status |= + dot11f_unpack_tlv_common_func2(pCtx, + pBufRemaining, len, + (uint8_t *)&(((tDot11fTLVConfigurationError *) + (pFrm + pTlv->offset))->present), + (uint16_t *)&(((tDot11fTLVConfigurationError *) + (pFrm + pTlv->offset))->error)); + break; + case SigTlvDeviceName: + status |= + dot11f_unpack_tlv_device_name(pCtx, + pBufRemaining, len, + (tDot11fTLVDeviceName *) + (pFrm + pTlv->offset)); + break; + case SigTlvDevicePasswordID: + status |= + dot11f_unpack_tlv_common_func2(pCtx, + pBufRemaining, len, + (uint8_t *)&(((tDot11fTLVDevicePasswordID *) + (pFrm + pTlv->offset))->present), + (uint16_t *)&(((tDot11fTLVDevicePasswordID *) + (pFrm + pTlv->offset))->id)); + break; + case SigTlvExtendedListenTiming: + status |= + dot11f_unpack_tlv_extended_listen_timing(pCtx, + pBufRemaining, len, + (tDot11fTLVExtendedListenTiming *) + (pFrm + pTlv->offset)); + break; + case SigTlvListenChannel: + status |= + dot11f_unpack_tlv_listen_channel(pCtx, + pBufRemaining, len, + (tDot11fTLVListenChannel *) + (pFrm + pTlv->offset)); + break; + case SigTlvManufacturer: + status |= + dot11f_unpack_tlv_manufacturer(pCtx, + pBufRemaining, len, + (tDot11fTLVManufacturer *) + (pFrm + pTlv->offset)); + break; + case SigTlvMinorReasonCode: + status |= + dot11f_unpack_tlv_common_func(pCtx, + pBufRemaining, len, + (uint8_t *)&(((tDot11fTLVMinorReasonCode *) + (pFrm + pTlv->offset))->present), + (uint8_t *)&(((tDot11fTLVMinorReasonCode *) + (pFrm + pTlv->offset))->minorReasonCode)); + break; + case SigTlvModelName: + status |= + dot11f_unpack_tlv_model_name(pCtx, + pBufRemaining, len, + (tDot11fTLVModelName *) + (pFrm + pTlv->offset)); + break; + case SigTlvModelNumber: + status |= + dot11f_unpack_tlv_model_number(pCtx, + pBufRemaining, len, + (tDot11fTLVModelNumber *) + (pFrm + pTlv->offset)); + break; + case SigTlvNoticeOfAbsence: + status |= + dot11f_unpack_tlv_notice_of_absence(pCtx, + pBufRemaining, len, + (tDot11fTLVNoticeOfAbsence *) + (pFrm + pTlv->offset)); + break; + case SigTlvOperatingChannel: + status |= + dot11f_unpack_tlv_operating_channel(pCtx, + pBufRemaining, len, + (tDot11fTLVOperatingChannel *) + (pFrm + pTlv->offset)); + break; + case SigTlvP2PCapability: + status |= + dot11f_unpack_tlv_p2_p_capability(pCtx, + pBufRemaining, len, + (tDot11fTLVP2PCapability *) + (pFrm + pTlv->offset)); + break; + case SigTlvP2PDeviceId: + status |= + dot11f_unpack_tlv_p2_p_device_id(pCtx, + pBufRemaining, len, + (tDot11fTLVP2PDeviceId *) + (pFrm + pTlv->offset)); + break; + case SigTlvP2PDeviceInfo: + status |= + dot11f_unpack_tlv_p2_p_device_info(pCtx, + pBufRemaining, len, + (tDot11fTLVP2PDeviceInfo *) + (pFrm + pTlv->offset)); + break; + case SigTlvP2PGroupInfo: + status |= + dot11f_unpack_tlv_p2_p_group_info(pCtx, + pBufRemaining, len, + (tDot11fTLVP2PGroupInfo *) + (pFrm + pTlv->offset)); + break; + case SigTlvP2PStatus: + status |= + dot11f_unpack_tlv_common_func(pCtx, + pBufRemaining, len, + (uint8_t *)&(((tDot11fTLVP2PStatus *) + (pFrm + pTlv->offset))->present), + (uint8_t *)&(((tDot11fTLVP2PStatus *) + (pFrm + pTlv->offset))->status)); + break; + case SigTlvPrimaryDeviceType: + status |= + dot11f_unpack_tlv_primary_device_type(pCtx, + pBufRemaining, len, + (tDot11fTLVPrimaryDeviceType *) + (pFrm + pTlv->offset)); + break; + case SigTlvRFBands: + status |= + dot11f_unpack_tlv_common_func(pCtx, + pBufRemaining, len, + (uint8_t *)&(((tDot11fTLVRFBands *) + (pFrm + pTlv->offset))->present), + (uint8_t *)&(((tDot11fTLVRFBands *) + (pFrm + pTlv->offset))->bands)); + break; + case SigTlvRequestDeviceType: + status |= + dot11f_unpack_tlv_request_device_type(pCtx, + pBufRemaining, len, + (tDot11fTLVRequestDeviceType *) + (pFrm + pTlv->offset)); + break; + case SigTlvRequestType: + status |= + dot11f_unpack_tlv_common_func(pCtx, + pBufRemaining, len, + (uint8_t *)&(((tDot11fTLVRequestType *) + (pFrm + pTlv->offset))->present), + (uint8_t *)&(((tDot11fTLVRequestType *) + (pFrm + pTlv->offset))->reqType)); + break; + case SigTlvResponseType: + status |= + dot11f_unpack_tlv_common_func(pCtx, + pBufRemaining, len, + (uint8_t *)&(((tDot11fTLVResponseType *) + (pFrm + pTlv->offset))->present), + (uint8_t *)&(((tDot11fTLVResponseType *) + (pFrm + pTlv->offset))->resType)); + break; + case SigTlvSelectedRegistrar: + status |= + dot11f_unpack_tlv_common_func(pCtx, + pBufRemaining, len, + (uint8_t *)&(((tDot11fTLVSelectedRegistrar *) + (pFrm + pTlv->offset))->present), + (uint8_t *)&(((tDot11fTLVSelectedRegistrar *) + (pFrm + pTlv->offset))->selected)); + break; + case SigTlvSelectedRegistrarConfigMethods: + status |= + dot11f_unpack_tlv_common_func2(pCtx, + pBufRemaining, len, + (uint8_t *)&(((tDot11fTLVSelectedRegistrarConfigMethods *) + (pFrm + pTlv->offset))->present), + (uint16_t *)&(((tDot11fTLVSelectedRegistrarConfigMethods *) + (pFrm + pTlv->offset))->methods)); + break; + case SigTlvSerialNumber: + status |= + dot11f_unpack_tlv_serial_number(pCtx, + pBufRemaining, len, + (tDot11fTLVSerialNumber *) + (pFrm + pTlv->offset)); + break; + case SigTlvUUID_E: + status |= + dot11f_unpack_tlv_uuid_e(pCtx, + pBufRemaining, len, + (tDot11fTLVUUID_E *) + (pFrm + pTlv->offset)); + break; + case SigTlvUUID_R: + status |= + dot11f_unpack_tlv_uuid_r(pCtx, + pBufRemaining, len, + (tDot11fTLVUUID_R *) + (pFrm + pTlv->offset)); + break; + case SigTlvVendorExtension: + status |= + dot11f_unpack_tlv_vendor_extension(pCtx, + pBufRemaining, len, + (tDot11fTLVVendorExtension *) + (pFrm + pTlv->offset)); + break; + case SigTlvVersion: + status |= + dot11f_unpack_tlv_version(pCtx, + pBufRemaining, len, + (tDot11fTLVVersion *) + (pFrm + pTlv->offset)); + break; + case SigTlvWPSState: + status |= + dot11f_unpack_tlv_common_func(pCtx, + pBufRemaining, len, + (uint8_t *)&(((tDot11fTLVWPSState *) + (pFrm + pTlv->offset))->present), + (uint8_t *)&(((tDot11fTLVWPSState *) + (pFrm + pTlv->offset))->state)); + break; + case SigTlvP2PInterface: + status |= + dot11f_unpack_tlv_p2_p_interface(pCtx, + pBufRemaining, len, + (tDot11fTLVP2PInterface *) + (pFrm + pTlv->offset)); + break; + case SigTlvP2PManageability: + status |= + dot11f_unpack_tlv_common_func(pCtx, + pBufRemaining, len, + (uint8_t *)&(((tDot11fTLVP2PManageability *) + (pFrm + pTlv->offset))->present), + (uint8_t *)&(((tDot11fTLVP2PManageability *) + (pFrm + pTlv->offset))->manageability)); + break; + default: + FRAMES_LOG1(pCtx, FRLOGE, FRFL("INTERNAL ERROR: I" + " don't know about the TLV signature %d-- thi" + "s is most likely a 'framesc' bug.\n"), + pTlv->sig); + FRAMES_DBG_BREAK(); + return DOT11F_INTERNAL_ERROR; + } /* End switch on sig. */ + } /* End if on length check. */ + + } else { + FRAMES_LOG2(pCtx, FRLOG3, FRFL("Skipping unknown TLV %d (" + "length %d)\n"), id, len); + FRAMES_DUMP(pCtx, FRLOG3, pBufRemaining - (pTlv->sType + pTlv->sLen), len); + status |= DOT11F_UNKNOWN_TLVS; + } + + /* Advance to the next TLV */ + pBufRemaining += len; + + if (len > nBufRemaining) { + FRAMES_LOG0(pCtx, FRLOGW, FRFL("This TLV extends past th" + "e buffer as it was defined to us. This could mean " + "a corrupt frame, or just an incorrect length parame" + "ter.\n")); + FRAMES_DBG_BREAK(); + status |= DOT11F_LAST_TLV_TOO_LONG; + goto MandatoryCheck; + } + + nBufRemaining -= len; + + } /* End iteration over TLVs.*/ + +MandatoryCheck: + pTlv = &TLVs[0]; + while (0xffff != pTlv->id) { + if (pTlv->fMandatory) { + pfFound = (uint8_t *)(pFrm + pTlv->offset + + pTlv->presenceOffset); + if (!*pfFound) { + FRAMES_LOG1(pCtx, FRLOGW, FRFL("ERROR: The mandatory " + "TLV %s wasn't seen.\n"), + pTlv->name); + FRAMES_DBG_BREAK(); + status |= DOT11F_MANDATORY_TLV_MISSING; + } + + } + ++pTlv; + } + + return status; +} /* End UnpacTlvkCore. */ +uint32_t dot11f_get_packed_ietclas(tpAniSirGlobal pCtx, + tDot11fIETCLAS *pIe, uint32_t *pnNeeded) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pCtx; + while (pIe->present) { + *pnNeeded += 1; + *pnNeeded += 1; + *pnNeeded += 1; + switch (pIe->classifier_type) { + case 0: + *pnNeeded += 6; + *pnNeeded += 6; + *pnNeeded += 2; + break; + case 1: + *pnNeeded += 1; + switch (pIe->info.IpParams.version) { + case 4: + *pnNeeded += 4; + *pnNeeded += 4; + *pnNeeded += 2; + *pnNeeded += 2; + *pnNeeded += 1; + *pnNeeded += 1; + *pnNeeded += 1; + break; + case 6: + *pnNeeded += 16; + *pnNeeded += 16; + *pnNeeded += 2; + *pnNeeded += 2; + *pnNeeded += 3; + break; + } + break; + case 2: + *pnNeeded += 2; + break; + } + break; + } + return status; +} /* End dot11f_get_packed_ietclas. */ + +uint32_t dot11f_get_packed_iewmmtclas(tpAniSirGlobal pCtx, + tDot11fIEWMMTCLAS *pIe, uint32_t *pnNeeded) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pCtx; + while (pIe->present) { + *pnNeeded += 1; + *pnNeeded += 1; + *pnNeeded += 1; + *pnNeeded += 1; + switch (pIe->classifier_type) { + case 0: + *pnNeeded += 6; + *pnNeeded += 6; + *pnNeeded += 2; + break; + case 1: + *pnNeeded += 1; + switch (pIe->info.IpParams.version) { + case 4: + *pnNeeded += 4; + *pnNeeded += 4; + *pnNeeded += 2; + *pnNeeded += 2; + *pnNeeded += 1; + *pnNeeded += 1; + *pnNeeded += 1; + break; + case 6: + *pnNeeded += 16; + *pnNeeded += 16; + *pnNeeded += 2; + *pnNeeded += 2; + *pnNeeded += 3; + break; + } + break; + case 2: + *pnNeeded += 2; + break; + } + break; + } + return status; +} /* End dot11f_get_packed_iewmmtclas. */ + +uint32_t dot11f_get_packed_ie_neighbor_rpt(tpAniSirGlobal pCtx, + tDot11fIEneighbor_rpt *pIe, uint32_t *pnNeeded) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pCtx; + while (pIe->present) { + *pnNeeded += 6; + *pnNeeded += 1; + *pnNeeded += 1; + *pnNeeded += 2; + *pnNeeded += 1; + *pnNeeded += 1; + *pnNeeded += 1; + status = get_packed_size_core(pCtx, (uint8_t *)pIe, pnNeeded, + IES_neighbor_rpt); + break; + } + return status; +} /* End dot11f_get_packed_ie_neighbor_rpt. */ + +uint32_t dot11f_get_packed_ie_channel_switch_wrapper(tpAniSirGlobal pCtx, + tDot11fIEChannelSwitchWrapper *pIe, uint32_t *pnNeeded) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pCtx; + while (pIe->present) { + status = get_packed_size_core(pCtx, (uint8_t *)pIe, pnNeeded, + IES_ChannelSwitchWrapper); + break; + } + return status; +} /* End dot11f_get_packed_ie_channel_switch_wrapper. */ + +uint32_t dot11f_get_packed_ie_country(tpAniSirGlobal pCtx, + tDot11fIECountry *pIe, uint32_t *pnNeeded) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pCtx; + while (pIe->present) { + *pnNeeded += 3; + if (pIe->num_triplets) { + *pnNeeded += (pIe->num_triplets * 3); + } else { + break; + } + break; + } + return status; +} /* End dot11f_get_packed_ie_country. */ + +uint32_t dot11f_get_packed_ieft_info(tpAniSirGlobal pCtx, + tDot11fIEFTInfo *pIe, uint32_t *pnNeeded) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pCtx; + while (pIe->present) { + *pnNeeded += 2; + *pnNeeded += 16; + *pnNeeded += 32; + *pnNeeded += 32; + status = get_packed_size_core(pCtx, (uint8_t *)pIe, pnNeeded, + IES_FTInfo); + break; + } + return status; +} /* End dot11f_get_packed_ieft_info. */ + +uint32_t dot11f_get_packed_ie_measurement_report(tpAniSirGlobal pCtx, + tDot11fIEMeasurementReport *pIe, uint32_t *pnNeeded) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pCtx; + while (pIe->present) { + *pnNeeded += 1; + *pnNeeded += 1; + *pnNeeded += 1; + if (pIe->type) { + switch (pIe->type) { + case 0: + *pnNeeded += 1; + *pnNeeded += 8; + *pnNeeded += 2; + *pnNeeded += 1; + break; + case 1: + *pnNeeded += 1; + *pnNeeded += 8; + *pnNeeded += 2; + *pnNeeded += 1; + break; + case 2: + *pnNeeded += 1; + *pnNeeded += 8; + *pnNeeded += 2; + *pnNeeded += 1; + *pnNeeded += 1; + *pnNeeded += 1; + *pnNeeded += 1; + *pnNeeded += 1; + *pnNeeded += 1; + *pnNeeded += 1; + *pnNeeded += 1; + break; + case 5: + *pnNeeded += 1; + *pnNeeded += 1; + *pnNeeded += 8; + *pnNeeded += 2; + *pnNeeded += 1; + *pnNeeded += 1; + *pnNeeded += 1; + *pnNeeded += 6; + *pnNeeded += 1; + *pnNeeded += 4; + status = get_packed_size_core(pCtx, (uint8_t *)pIe, pnNeeded, IES_reportBeacon); + break; + } + } else { + break; + } + break; + } + return status; +} /* End dot11f_get_packed_ie_measurement_report. */ + +uint32_t dot11f_get_packed_ie_measurement_request(tpAniSirGlobal pCtx, + tDot11fIEMeasurementRequest *pIe, uint32_t *pnNeeded) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pCtx; + while (pIe->present) { + *pnNeeded += 1; + *pnNeeded += 1; + *pnNeeded += 1; + switch (pIe->measurement_type) { + case 0: + *pnNeeded += 1; + *pnNeeded += 8; + *pnNeeded += 2; + break; + case 1: + *pnNeeded += 1; + *pnNeeded += 8; + *pnNeeded += 2; + break; + case 2: + *pnNeeded += 1; + *pnNeeded += 8; + *pnNeeded += 2; + break; + case 5: + *pnNeeded += 1; + *pnNeeded += 1; + *pnNeeded += 2; + *pnNeeded += 2; + *pnNeeded += 1; + *pnNeeded += 6; + status = get_packed_size_core(pCtx, (uint8_t *)pIe, pnNeeded, IES_measurement_requestBeacon); + break; + case 8: + *pnNeeded += 1; + status = get_packed_size_core(pCtx, (uint8_t *)pIe, pnNeeded, IES_measurement_requestlci); + break; + case 16: + *pnNeeded += 2; + *pnNeeded += 1; + status = get_packed_size_core(pCtx, (uint8_t *)pIe, pnNeeded, IES_measurement_requestftmrr); + break; + } + break; + } + return status; +} /* End dot11f_get_packed_ie_measurement_request. */ + +uint32_t dot11f_get_packed_ie_neighbor_report(tpAniSirGlobal pCtx, + tDot11fIENeighborReport *pIe, uint32_t *pnNeeded) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pCtx; + while (pIe->present) { + *pnNeeded += 6; + *pnNeeded += 1; + *pnNeeded += 1; + *pnNeeded += 2; + *pnNeeded += 1; + *pnNeeded += 1; + *pnNeeded += 1; + status = get_packed_size_core(pCtx, (uint8_t *)pIe, pnNeeded, + IES_NeighborReport); + break; + } + return status; +} /* End dot11f_get_packed_ie_neighbor_report. */ + +uint32_t dot11f_get_packed_iep2_p_assoc_req(tpAniSirGlobal pCtx, + tDot11fIEP2PAssocReq *pIe, uint32_t *pnNeeded) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pCtx; + while (pIe->present) { + status = get_packed_size_tlv_core(pCtx, (uint8_t *)pIe, pnNeeded, + TLVS_P2PAssocReq); + break; + } + return status; +} /* End dot11f_get_packed_iep2_p_assoc_req. */ + +uint32_t dot11f_get_packed_iep2_p_assoc_res(tpAniSirGlobal pCtx, + tDot11fIEP2PAssocRes *pIe, uint32_t *pnNeeded) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pCtx; + while (pIe->present) { + status = get_packed_size_tlv_core(pCtx, (uint8_t *)pIe, pnNeeded, + TLVS_P2PAssocRes); + break; + } + return status; +} /* End dot11f_get_packed_iep2_p_assoc_res. */ + +uint32_t dot11f_get_packed_iep2_p_beacon(tpAniSirGlobal pCtx, + tDot11fIEP2PBeacon *pIe, uint32_t *pnNeeded) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pCtx; + while (pIe->present) { + status = get_packed_size_tlv_core(pCtx, (uint8_t *)pIe, pnNeeded, + TLVS_P2PBeacon); + break; + } + return status; +} /* End dot11f_get_packed_iep2_p_beacon. */ + +uint32_t dot11f_get_packed_iep2_p_beacon_probe_res(tpAniSirGlobal pCtx, + tDot11fIEP2PBeaconProbeRes *pIe, uint32_t *pnNeeded) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pCtx; + while (pIe->present) { + status = get_packed_size_tlv_core(pCtx, (uint8_t *)pIe, pnNeeded, + TLVS_P2PBeaconProbeRes); + break; + } + return status; +} /* End dot11f_get_packed_iep2_p_beacon_probe_res. */ + +uint32_t dot11f_get_packed_iep2_p_de_auth(tpAniSirGlobal pCtx, + tDot11fIEP2PDeAuth *pIe, uint32_t *pnNeeded) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pCtx; + while (pIe->present) { + status = get_packed_size_tlv_core(pCtx, (uint8_t *)pIe, pnNeeded, + TLVS_P2PDeAuth); + break; + } + return status; +} /* End dot11f_get_packed_iep2_p_de_auth. */ + +uint32_t dot11f_get_packed_iep2_p_dis_assoc(tpAniSirGlobal pCtx, + tDot11fIEP2PDisAssoc *pIe, uint32_t *pnNeeded) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pCtx; + while (pIe->present) { + status = get_packed_size_tlv_core(pCtx, (uint8_t *)pIe, pnNeeded, + TLVS_P2PDisAssoc); + break; + } + return status; +} /* End dot11f_get_packed_iep2_p_dis_assoc. */ + +uint32_t dot11f_get_packed_iep2_p_probe_req(tpAniSirGlobal pCtx, + tDot11fIEP2PProbeReq *pIe, uint32_t *pnNeeded) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pCtx; + while (pIe->present) { + status = get_packed_size_tlv_core(pCtx, (uint8_t *)pIe, pnNeeded, + TLVS_P2PProbeReq); + break; + } + return status; +} /* End dot11f_get_packed_iep2_p_probe_req. */ + +uint32_t dot11f_get_packed_iep2_p_probe_res(tpAniSirGlobal pCtx, + tDot11fIEP2PProbeRes *pIe, uint32_t *pnNeeded) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pCtx; + while (pIe->present) { + status = get_packed_size_tlv_core(pCtx, (uint8_t *)pIe, pnNeeded, + TLVS_P2PProbeRes); + break; + } + return status; +} /* End dot11f_get_packed_iep2_p_probe_res. */ + +uint32_t dot11f_get_packed_ieric_data_desc(tpAniSirGlobal pCtx, + tDot11fIERICDataDesc *pIe, uint32_t *pnNeeded) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pCtx; + while (pIe->present) { + status = get_packed_size_core(pCtx, (uint8_t *)pIe, pnNeeded, + IES_RICDataDesc); + break; + } + return status; +} /* End dot11f_get_packed_ieric_data_desc. */ + +uint32_t dot11f_get_packed_iersn(tpAniSirGlobal pCtx, + tDot11fIERSN *pIe, uint32_t *pnNeeded) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pCtx; + while (pIe->present) { + *pnNeeded += 2; + *pnNeeded += 4; + if (pIe->pwise_cipher_suite_count) { + *pnNeeded += 2; + } else { + break; + } + *pnNeeded += (pIe->pwise_cipher_suite_count * 4); + if (pIe->akm_suite_count) { + *pnNeeded += 2; + } else { + break; + } + *pnNeeded += (pIe->akm_suite_count * 4); + if (pIe->RSN_Cap) { + *pnNeeded += 2; + } else { + break; + } + if (pIe->pmkid_count) { + *pnNeeded += 2; + } else { + break; + } + *pnNeeded += (pIe->pmkid_count * 16); + if (pIe->gp_mgmt_cipher_suite) { + *pnNeeded += 4; + } else { + break; + } + break; + } + return status; +} /* End dot11f_get_packed_iersn. */ + +uint32_t dot11f_get_packed_iewapi(tpAniSirGlobal pCtx, + tDot11fIEWAPI *pIe, uint32_t *pnNeeded) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pCtx; + while (pIe->present) { + *pnNeeded += 2; + *pnNeeded += 2; + *pnNeeded += (pIe->akm_suite_count * 4); + *pnNeeded += 2; + *pnNeeded += (pIe->unicast_cipher_suite_count * 4); + *pnNeeded += 4; + *pnNeeded += 2; + if (pIe->bkid_count) { + *pnNeeded += 2; + } else { + break; + } + *pnNeeded += (pIe->bkid_count * 16); + break; + } + return status; +} /* End dot11f_get_packed_iewapi. */ + +uint32_t dot11f_get_packed_iewpa(tpAniSirGlobal pCtx, + tDot11fIEWPA *pIe, uint32_t *pnNeeded) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pCtx; + while (pIe->present) { + *pnNeeded += 2; + if (pIe->multicast_cipher_present) { + + *pnNeeded += 4; + } else { + break; + } + if (pIe->unicast_cipher_count) { + *pnNeeded += 2; + } else { + break; + } + *pnNeeded += (pIe->unicast_cipher_count * 4); + if (pIe->auth_suite_count) { + *pnNeeded += 2; + } else { + break; + } + *pnNeeded += (pIe->auth_suite_count * 4); + if (pIe->caps) { + *pnNeeded += 2; + } else { + break; + } + break; + } + return status; +} /* End dot11f_get_packed_iewpa. */ + +uint32_t dot11f_get_packed_iewsc(tpAniSirGlobal pCtx, + tDot11fIEWSC *pIe, uint32_t *pnNeeded) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pCtx; + while (pIe->present) { + status = get_packed_size_tlv_core(pCtx, (uint8_t *)pIe, pnNeeded, + TLVS_WSC); + break; + } + return status; +} /* End dot11f_get_packed_iewsc. */ + +uint32_t dot11f_get_packed_ie_wsc_assoc_req(tpAniSirGlobal pCtx, + tDot11fIEWscAssocReq *pIe, uint32_t *pnNeeded) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pCtx; + while (pIe->present) { + status = get_packed_size_tlv_core(pCtx, (uint8_t *)pIe, pnNeeded, + TLVS_WscAssocReq); + break; + } + return status; +} /* End dot11f_get_packed_ie_wsc_assoc_req. */ + +uint32_t dot11f_get_packed_ie_wsc_assoc_res(tpAniSirGlobal pCtx, + tDot11fIEWscAssocRes *pIe, uint32_t *pnNeeded) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pCtx; + while (pIe->present) { + status = get_packed_size_tlv_core(pCtx, (uint8_t *)pIe, pnNeeded, + TLVS_WscAssocRes); + break; + } + return status; +} /* End dot11f_get_packed_ie_wsc_assoc_res. */ + +uint32_t dot11f_get_packed_ie_wsc_beacon(tpAniSirGlobal pCtx, + tDot11fIEWscBeacon *pIe, uint32_t *pnNeeded) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pCtx; + while (pIe->present) { + status = get_packed_size_tlv_core(pCtx, (uint8_t *)pIe, pnNeeded, + TLVS_WscBeacon); + break; + } + return status; +} /* End dot11f_get_packed_ie_wsc_beacon. */ + +uint32_t dot11f_get_packed_ie_wsc_beacon_probe_res(tpAniSirGlobal pCtx, + tDot11fIEWscBeaconProbeRes *pIe, uint32_t *pnNeeded) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pCtx; + while (pIe->present) { + status = get_packed_size_tlv_core(pCtx, (uint8_t *)pIe, pnNeeded, + TLVS_WscBeaconProbeRes); + break; + } + return status; +} /* End dot11f_get_packed_ie_wsc_beacon_probe_res. */ + +uint32_t dot11f_get_packed_ie_wsc_probe_req(tpAniSirGlobal pCtx, + tDot11fIEWscProbeReq *pIe, uint32_t *pnNeeded) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pCtx; + while (pIe->present) { + status = get_packed_size_tlv_core(pCtx, (uint8_t *)pIe, pnNeeded, + TLVS_WscProbeReq); + break; + } + return status; +} /* End dot11f_get_packed_ie_wsc_probe_req. */ + +uint32_t dot11f_get_packed_ie_wsc_probe_res(tpAniSirGlobal pCtx, + tDot11fIEWscProbeRes *pIe, uint32_t *pnNeeded) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pCtx; + while (pIe->present) { + status = get_packed_size_tlv_core(pCtx, (uint8_t *)pIe, pnNeeded, + TLVS_WscProbeRes); + break; + } + return status; +} /* End dot11f_get_packed_ie_wsc_probe_res. */ + +uint32_t dot11f_get_packed_ie_wsc_reassoc_res(tpAniSirGlobal pCtx, + tDot11fIEWscReassocRes *pIe, uint32_t *pnNeeded) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pCtx; + while (pIe->present) { + status = get_packed_size_tlv_core(pCtx, (uint8_t *)pIe, pnNeeded, + TLVS_WscReassocRes); + break; + } + return status; +} /* End dot11f_get_packed_ie_wsc_reassoc_res. */ + +uint32_t dot11f_get_packed_ie_hs20vendor_ie(tpAniSirGlobal pCtx, + tDot11fIEhs20vendor_ie *pIe, uint32_t *pnNeeded) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pCtx; + while (pIe->present) { + *pnNeeded += 1; + if (pIe->hs_id_present) { + switch (pIe->hs_id_present) { + case 1: + *pnNeeded += 2; + break; + case 2: + *pnNeeded += 2; + break; + } + } else { + break; + } + break; + } + return status; +} /* End dot11f_get_packed_ie_hs20vendor_ie. */ + +uint32_t dot11f_get_packed_ie_vendor_vht_ie(tpAniSirGlobal pCtx, + tDot11fIEvendor_vht_ie *pIe, uint32_t *pnNeeded) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pCtx; + while (pIe->present) { + *pnNeeded += 1; + *pnNeeded += 1; + status = get_packed_size_core(pCtx, (uint8_t *)pIe, pnNeeded, + IES_vendor_vht_ie); + break; + } + return status; +} /* End dot11f_get_packed_ie_vendor_vht_ie. */ + +uint32_t dot11f_get_packed_add_ts_request_size(tpAniSirGlobal pCtx, + tDot11fAddTSRequest *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 3; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_AddTSRequest); + return status; +} /* End dot11f_get_packed_add_ts_request_size. */ + +uint32_t dot11f_get_packed_add_ts_response_size(tpAniSirGlobal pCtx, + tDot11fAddTSResponse *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 5; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_AddTSResponse); + return status; +} /* End dot11f_get_packed_add_ts_response_size. */ + +uint32_t dot11f_get_packed_assoc_request_size(tpAniSirGlobal pCtx, + tDot11fAssocRequest *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 4; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_AssocRequest); + return status; +} /* End dot11f_get_packed_assoc_request_size. */ + +uint32_t dot11f_get_packed_assoc_response_size(tpAniSirGlobal pCtx, + tDot11fAssocResponse *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 6; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_AssocResponse); + return status; +} /* End dot11f_get_packed_assoc_response_size. */ + +uint32_t dot11f_get_packed_authentication_size(tpAniSirGlobal pCtx, + tDot11fAuthentication *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 6; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_Authentication); + return status; +} /* End dot11f_get_packed_authentication_size. */ + +uint32_t dot11f_get_packed_beacon_size(tpAniSirGlobal pCtx, + tDot11fBeacon *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 12; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_Beacon); + return status; +} /* End dot11f_get_packed_beacon_size. */ + +uint32_t dot11f_get_packed_beacon1_size(tpAniSirGlobal pCtx, + tDot11fBeacon1 *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 12; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_Beacon1); + return status; +} /* End dot11f_get_packed_beacon1_size. */ + +uint32_t dot11f_get_packed_beacon2_size(tpAniSirGlobal pCtx, + tDot11fBeacon2 *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 0; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_Beacon2); + return status; +} /* End dot11f_get_packed_beacon2_size. */ + +uint32_t dot11f_get_packed_beacon_i_es_size(tpAniSirGlobal pCtx, + tDot11fBeaconIEs *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 0; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_BeaconIEs); + return status; +} /* End dot11f_get_packed_beacon_i_es_size. */ + +uint32_t dot11f_get_packed_channel_switch_size(tpAniSirGlobal pCtx, + tDot11fChannelSwitch *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 2; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_ChannelSwitch); + return status; +} /* End dot11f_get_packed_channel_switch_size. */ + +uint32_t dot11f_get_packed_de_auth_size(tpAniSirGlobal pCtx, + tDot11fDeAuth *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 2; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_DeAuth); + return status; +} /* End dot11f_get_packed_de_auth_size. */ + +uint32_t dot11f_get_packed_del_ts_size(tpAniSirGlobal pCtx, + tDot11fDelTS *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 7; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_DelTS); + return status; +} /* End dot11f_get_packed_del_ts_size. */ + +uint32_t dot11f_get_packed_disassociation_size(tpAniSirGlobal pCtx, + tDot11fDisassociation *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 2; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_Disassociation); + return status; +} /* End dot11f_get_packed_disassociation_size. */ + +uint32_t dot11f_get_packed_link_measurement_report_size(tpAniSirGlobal pCtx, + tDot11fLinkMeasurementReport *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 11; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_LinkMeasurementReport); + return status; +} /* End dot11f_get_packed_link_measurement_report_size. */ + +uint32_t dot11f_get_packed_link_measurement_request_size(tpAniSirGlobal pCtx, + tDot11fLinkMeasurementRequest *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 5; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_LinkMeasurementRequest); + return status; +} /* End dot11f_get_packed_link_measurement_request_size. */ + +uint32_t dot11f_get_packed_measurement_report_size(tpAniSirGlobal pCtx, + tDot11fMeasurementReport *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 3; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_MeasurementReport); + return status; +} /* End dot11f_get_packed_measurement_report_size. */ + +uint32_t dot11f_get_packed_measurement_request_size(tpAniSirGlobal pCtx, + tDot11fMeasurementRequest *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 3; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_MeasurementRequest); + return status; +} /* End dot11f_get_packed_measurement_request_size. */ + +uint32_t dot11f_get_packed_neighbor_report_request_size(tpAniSirGlobal pCtx, + tDot11fNeighborReportRequest *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 3; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_NeighborReportRequest); + return status; +} /* End dot11f_get_packed_neighbor_report_request_size. */ + +uint32_t dot11f_get_packed_neighbor_report_response_size(tpAniSirGlobal pCtx, + tDot11fNeighborReportResponse *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 3; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_NeighborReportResponse); + return status; +} /* End dot11f_get_packed_neighbor_report_response_size. */ + +uint32_t dot11f_get_packed_operating_mode_size(tpAniSirGlobal pCtx, + tDot11fOperatingMode *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 3; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_OperatingMode); + return status; +} /* End dot11f_get_packed_operating_mode_size. */ + +uint32_t dot11f_get_packed_probe_request_size(tpAniSirGlobal pCtx, + tDot11fProbeRequest *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 0; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_ProbeRequest); + return status; +} /* End dot11f_get_packed_probe_request_size. */ + +uint32_t dot11f_get_packed_probe_response_size(tpAniSirGlobal pCtx, + tDot11fProbeResponse *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 12; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_ProbeResponse); + return status; +} /* End dot11f_get_packed_probe_response_size. */ + +uint32_t dot11f_get_packed_qos_map_configure_size(tpAniSirGlobal pCtx, + tDot11fQosMapConfigure *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 2; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_QosMapConfigure); + return status; +} /* End dot11f_get_packed_qos_map_configure_size. */ + +uint32_t dot11f_get_packed_radio_measurement_report_size(tpAniSirGlobal pCtx, + tDot11fRadioMeasurementReport *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 3; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_RadioMeasurementReport); + return status; +} /* End dot11f_get_packed_radio_measurement_report_size. */ + +uint32_t dot11f_get_packed_radio_measurement_request_size(tpAniSirGlobal pCtx, + tDot11fRadioMeasurementRequest *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 5; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_RadioMeasurementRequest); + return status; +} /* End dot11f_get_packed_radio_measurement_request_size. */ + +uint32_t dot11f_get_packed_re_assoc_request_size(tpAniSirGlobal pCtx, + tDot11fReAssocRequest *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 10; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_ReAssocRequest); + return status; +} /* End dot11f_get_packed_re_assoc_request_size. */ + +uint32_t dot11f_get_packed_re_assoc_response_size(tpAniSirGlobal pCtx, + tDot11fReAssocResponse *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 6; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_ReAssocResponse); + return status; +} /* End dot11f_get_packed_re_assoc_response_size. */ + +uint32_t dot11f_get_packed_sm_power_save_size(tpAniSirGlobal pCtx, + tDot11fSMPowerSave *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 3; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_SMPowerSave); + return status; +} /* End dot11f_get_packed_sm_power_save_size. */ + +uint32_t dot11f_get_packed_sa_query_req_size(tpAniSirGlobal pCtx, + tDot11fSaQueryReq *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 4; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_SaQueryReq); + return status; +} /* End dot11f_get_packed_sa_query_req_size. */ + +uint32_t dot11f_get_packed_sa_query_rsp_size(tpAniSirGlobal pCtx, + tDot11fSaQueryRsp *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 4; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_SaQueryRsp); + return status; +} /* End dot11f_get_packed_sa_query_rsp_size. */ + +uint32_t dot11f_get_packed_tdls_dis_req_size(tpAniSirGlobal pCtx, + tDot11fTDLSDisReq *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 3; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_TDLSDisReq); + return status; +} /* End dot11f_get_packed_tdls_dis_req_size. */ + +uint32_t dot11f_get_packed_tdls_dis_rsp_size(tpAniSirGlobal pCtx, + tDot11fTDLSDisRsp *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 5; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_TDLSDisRsp); + return status; +} /* End dot11f_get_packed_tdls_dis_rsp_size. */ + +uint32_t dot11f_get_packed_tdls_peer_traffic_ind_size(tpAniSirGlobal pCtx, + tDot11fTDLSPeerTrafficInd *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 3; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_TDLSPeerTrafficInd); + return status; +} /* End dot11f_get_packed_tdls_peer_traffic_ind_size. */ + +uint32_t dot11f_get_packed_tdls_peer_traffic_rsp_size(tpAniSirGlobal pCtx, + tDot11fTDLSPeerTrafficRsp *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 3; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_TDLSPeerTrafficRsp); + return status; +} /* End dot11f_get_packed_tdls_peer_traffic_rsp_size. */ + +uint32_t dot11f_get_packed_tdls_setup_cnf_size(tpAniSirGlobal pCtx, + tDot11fTDLSSetupCnf *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 5; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_TDLSSetupCnf); + return status; +} /* End dot11f_get_packed_tdls_setup_cnf_size. */ + +uint32_t dot11f_get_packed_tdls_setup_req_size(tpAniSirGlobal pCtx, + tDot11fTDLSSetupReq *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 5; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_TDLSSetupReq); + return status; +} /* End dot11f_get_packed_tdls_setup_req_size. */ + +uint32_t dot11f_get_packed_tdls_setup_rsp_size(tpAniSirGlobal pCtx, + tDot11fTDLSSetupRsp *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 7; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_TDLSSetupRsp); + return status; +} /* End dot11f_get_packed_tdls_setup_rsp_size. */ + +uint32_t dot11f_get_packed_tdls_teardown_size(tpAniSirGlobal pCtx, + tDot11fTDLSTeardown *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 4; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_TDLSTeardown); + return status; +} /* End dot11f_get_packed_tdls_teardown_size. */ + +uint32_t dot11f_get_packed_tpc_report_size(tpAniSirGlobal pCtx, + tDot11fTPCReport *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 3; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_TPCReport); + return status; +} /* End dot11f_get_packed_tpc_report_size. */ + +uint32_t dot11f_get_packed_tpc_request_size(tpAniSirGlobal pCtx, + tDot11fTPCRequest *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 3; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_TPCRequest); + return status; +} /* End dot11f_get_packed_tpc_request_size. */ + +uint32_t dot11f_get_packed_timing_advertisement_frame_size(tpAniSirGlobal pCtx, + tDot11fTimingAdvertisementFrame *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 10; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_TimingAdvertisementFrame); + return status; +} /* End dot11f_get_packed_timing_advertisement_frame_size. */ + +uint32_t dot11f_get_packed_vht_gid_management_action_frame_size(tpAniSirGlobal pCtx, + tDot11fVHTGidManagementActionFrame *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 26; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_VHTGidManagementActionFrame); + return status; +} /* End dot11f_get_packed_vht_gid_management_action_frame_size. */ + +uint32_t dot11f_get_packed_wmm_add_ts_request_size(tpAniSirGlobal pCtx, + tDot11fWMMAddTSRequest *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 4; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_WMMAddTSRequest); + return status; +} /* End dot11f_get_packed_wmm_add_ts_request_size. */ + +uint32_t dot11f_get_packed_wmm_add_ts_response_size(tpAniSirGlobal pCtx, + tDot11fWMMAddTSResponse *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 4; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_WMMAddTSResponse); + return status; +} /* End dot11f_get_packed_wmm_add_ts_response_size. */ + +uint32_t dot11f_get_packed_wmm_del_ts_size(tpAniSirGlobal pCtx, + tDot11fWMMDelTS *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 4; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_WMMDelTS); + return status; +} /* End dot11f_get_packed_wmm_del_ts_size. */ + +uint32_t dot11f_get_packed_ext_channel_switch_action_frame_size(tpAniSirGlobal pCtx, + tDot11fext_channel_switch_action_frame *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 6; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_ext_channel_switch_action_frame); + return status; +} /* End dot11f_get_packed_ext_channel_switch_action_frame_size. */ + +uint32_t dot11f_get_packed_ht2040_bss_coexistence_mgmt_action_frameSize(tpAniSirGlobal pCtx, + tDot11fht2040_bss_coexistence_mgmt_action_frame *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 2; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_ht2040_bss_coexistence_mgmt_action_frame); + return status; +} /* End dot11f_get_packed_ht2040_bss_coexistence_mgmt_action_frameSize. */ + +uint32_t dot11f_get_packed_p2p_oper_chan_change_confirmSize(tpAniSirGlobal pCtx, + tDot11fp2p_oper_chan_change_confirm *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 7; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_p2p_oper_chan_change_confirm); + return status; +} /* End dot11f_get_packed_p2p_oper_chan_change_confirmSize. */ + +static uint32_t get_packed_size_core(tpAniSirGlobal pCtx, + uint8_t *pFrm, + uint32_t *pnNeeded, + const tIEDefn IEs[]) +{ + const tIEDefn *pIe; + uint16_t i, n; + uint32_t status; + tFRAMES_BOOL *pfFound; + uint32_t countOffset = 0; + uint32_t byteCount = 0; + uint8_t pIePresent = 0; + uint32_t offset = 0; + + status = DOT11F_PARSE_SUCCESS; + + (void)pCtx; /* Shutup the compiler if we have no FFs nor IEs... */ + i = 0; + n = 0; + pIe = &(IEs[0]); + while (0xff != pIe->eid) { + pfFound = (tFRAMES_BOOL *)(pFrm + pIe->offset + + pIe->presenceOffset); + if (*pfFound) { + countOffset = ((0 == pIe->arraybound) ? 1 : (*(uint16_t *)(pFrm + pIe->countOffset))); + for (i = 0U; i < countOffset; ++i) { + *pnNeeded += 2U + pIe->noui; + byteCount = 0; + switch (pIe->sig) { + case SigIeGTK: + offset = sizeof(tDot11fIEGTK); + byteCount = ((tDot11fIEGTK *) + (pFrm + pIe->offset + offset * i))-> + num_key + 11; + pIePresent = ((tDot11fIEGTK *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeIGTK: + offset = sizeof(tDot11fIEIGTK); + byteCount = 33; + pIePresent = ((tDot11fIEIGTK *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeR0KH_ID: + offset = sizeof(tDot11fIER0KH_ID); + byteCount = ((tDot11fIER0KH_ID *) + (pFrm + pIe->offset + offset * i))-> + num_PMK_R0_ID; + pIePresent = ((tDot11fIER0KH_ID *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeR1KH_ID: + offset = sizeof(tDot11fIER1KH_ID); + byteCount = 6; + pIePresent = ((tDot11fIER1KH_ID *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeAPChannelReport: + offset = sizeof(tDot11fIEAPChannelReport); + byteCount = ((tDot11fIEAPChannelReport *) + (pFrm + pIe->offset + offset * i))-> + num_channelList + 1; + pIePresent = ((tDot11fIEAPChannelReport *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeBcnReportingDetail: + offset = sizeof(tDot11fIEBcnReportingDetail); + byteCount = 1; + pIePresent = ((tDot11fIEBcnReportingDetail *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeBeaconReportFrmBody: + offset = sizeof(tDot11fIEBeaconReportFrmBody); + byteCount = ((tDot11fIEBeaconReportFrmBody *) + (pFrm + pIe->offset + offset * i))-> + num_reportedFields; + pIePresent = ((tDot11fIEBeaconReportFrmBody *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeBeaconReporting: + offset = sizeof(tDot11fIEBeaconReporting); + byteCount = 2; + pIePresent = ((tDot11fIEBeaconReporting *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeCondensedCountryStr: + offset = sizeof(tDot11fIECondensedCountryStr); + byteCount = 2; + pIePresent = ((tDot11fIECondensedCountryStr *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeMeasurementPilot: + offset = sizeof(tDot11fIEMeasurementPilot); + byteCount = ((tDot11fIEMeasurementPilot *) + (pFrm + pIe->offset + offset * i))-> + num_vendorSpecific + 1; + pIePresent = ((tDot11fIEMeasurementPilot *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeMultiBssid: + offset = sizeof(tDot11fIEMultiBssid); + byteCount = ((tDot11fIEMultiBssid *) + (pFrm + pIe->offset + offset * i))-> + num_vendorSpecific + 1; + pIePresent = ((tDot11fIEMultiBssid *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeRICData: + offset = sizeof(tDot11fIERICData); + byteCount = 4; + pIePresent = ((tDot11fIERICData *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeRICDescriptor: + offset = sizeof(tDot11fIERICDescriptor); + byteCount = ((tDot11fIERICDescriptor *) + (pFrm + pIe->offset + offset * i))-> + num_variableData + 1; + pIePresent = ((tDot11fIERICDescriptor *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeRRMEnabledCap: + offset = sizeof(tDot11fIERRMEnabledCap); + byteCount = 5; + pIePresent = ((tDot11fIERRMEnabledCap *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeRequestedInfo: + offset = sizeof(tDot11fIERequestedInfo); + byteCount = ((tDot11fIERequestedInfo *) + (pFrm + pIe->offset + offset * i))-> + num_requested_eids; + pIePresent = ((tDot11fIERequestedInfo *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeSSID: + offset = sizeof(tDot11fIESSID); + byteCount = ((tDot11fIESSID *) + (pFrm + pIe->offset + offset * i))-> + num_ssid; + pIePresent = ((tDot11fIESSID *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeSchedule: + offset = sizeof(tDot11fIESchedule); + byteCount = 14; + pIePresent = ((tDot11fIESchedule *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeTCLAS: + offset = sizeof(tDot11fIETCLAS); + status |= + dot11f_get_packed_ietclas( + pCtx, (tDot11fIETCLAS *) + (pFrm + pIe->offset + offset * i), + pnNeeded); + break; + case SigIeTCLASSPROC: + offset = sizeof(tDot11fIETCLASSPROC); + byteCount = 1; + pIePresent = ((tDot11fIETCLASSPROC *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeTSDelay: + offset = sizeof(tDot11fIETSDelay); + byteCount = 4; + pIePresent = ((tDot11fIETSDelay *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeTSFInfo: + offset = sizeof(tDot11fIETSFInfo); + byteCount = 4; + pIePresent = ((tDot11fIETSFInfo *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeTSPEC: + offset = sizeof(tDot11fIETSPEC); + byteCount = 55; + pIePresent = ((tDot11fIETSPEC *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeVHTCaps: + offset = sizeof(tDot11fIEVHTCaps); + byteCount = 12; + pIePresent = ((tDot11fIEVHTCaps *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeVHTOperation: + offset = sizeof(tDot11fIEVHTOperation); + byteCount = 5; + pIePresent = ((tDot11fIEVHTOperation *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeWMMSchedule: + offset = sizeof(tDot11fIEWMMSchedule); + byteCount = 15; + pIePresent = ((tDot11fIEWMMSchedule *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeWMMTCLAS: + offset = sizeof(tDot11fIEWMMTCLAS); + status |= + dot11f_get_packed_iewmmtclas( + pCtx, (tDot11fIEWMMTCLAS *) + (pFrm + pIe->offset + offset * i), + pnNeeded); + break; + case SigIeWMMTCLASPROC: + offset = sizeof(tDot11fIEWMMTCLASPROC); + byteCount = 2; + pIePresent = ((tDot11fIEWMMTCLASPROC *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeWMMTSDelay: + offset = sizeof(tDot11fIEWMMTSDelay); + byteCount = 5; + pIePresent = ((tDot11fIEWMMTSDelay *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeWMMTSPEC: + offset = sizeof(tDot11fIEWMMTSPEC); + byteCount = 56; + pIePresent = ((tDot11fIEWMMTSPEC *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeWiderBWChanSwitchAnn: + offset = sizeof(tDot11fIEWiderBWChanSwitchAnn); + byteCount = 3; + pIePresent = ((tDot11fIEWiderBWChanSwitchAnn *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeazimuth_req: + offset = sizeof(tDot11fIEazimuth_req); + byteCount = 1; + pIePresent = ((tDot11fIEazimuth_req *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIemax_age: + offset = sizeof(tDot11fIEmax_age); + byteCount = 2; + pIePresent = ((tDot11fIEmax_age *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeneighbor_rpt: + offset = sizeof(tDot11fIEneighbor_rpt); + status |= + dot11f_get_packed_ie_neighbor_rpt( + pCtx, (tDot11fIEneighbor_rpt *) + (pFrm + pIe->offset + offset * i), + pnNeeded); + break; + case SigIereq_mac_addr: + offset = sizeof(tDot11fIEreq_mac_addr); + byteCount = 6; + pIePresent = ((tDot11fIEreq_mac_addr *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIetgt_mac_addr: + offset = sizeof(tDot11fIEtgt_mac_addr); + byteCount = 6; + pIePresent = ((tDot11fIEtgt_mac_addr *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIevht_transmit_power_env: + offset = sizeof(tDot11fIEvht_transmit_power_env); + byteCount = ((tDot11fIEvht_transmit_power_env *) + (pFrm + pIe->offset + offset * i))-> + num_bytes; + pIePresent = ((tDot11fIEvht_transmit_power_env *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeAID: + offset = sizeof(tDot11fIEAID); + byteCount = 2; + pIePresent = ((tDot11fIEAID *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeCFParams: + offset = sizeof(tDot11fIECFParams); + byteCount = 6; + pIePresent = ((tDot11fIECFParams *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeChallengeText: + offset = sizeof(tDot11fIEChallengeText); + byteCount = ((tDot11fIEChallengeText *) + (pFrm + pIe->offset + offset * i))-> + num_text; + pIePresent = ((tDot11fIEChallengeText *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeChanSwitchAnn: + offset = sizeof(tDot11fIEChanSwitchAnn); + byteCount = 3; + pIePresent = ((tDot11fIEChanSwitchAnn *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeChannelSwitchWrapper: + offset = sizeof(tDot11fIEChannelSwitchWrapper); + status |= + dot11f_get_packed_ie_channel_switch_wrapper( + pCtx, (tDot11fIEChannelSwitchWrapper *) + (pFrm + pIe->offset + offset * i), + pnNeeded); + break; + case SigIeCountry: + offset = sizeof(tDot11fIECountry); + status |= + dot11f_get_packed_ie_country( + pCtx, (tDot11fIECountry *) + (pFrm + pIe->offset + offset * i), + pnNeeded); + break; + case SigIeDSParams: + offset = sizeof(tDot11fIEDSParams); + byteCount = 1; + pIePresent = ((tDot11fIEDSParams *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeEDCAParamSet: + offset = sizeof(tDot11fIEEDCAParamSet); + byteCount = 18; + pIePresent = ((tDot11fIEEDCAParamSet *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeERPInfo: + offset = sizeof(tDot11fIEERPInfo); + byteCount = 1; + pIePresent = ((tDot11fIEERPInfo *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeESECckmOpaque: + offset = sizeof(tDot11fIEESECckmOpaque); + byteCount = ((tDot11fIEESECckmOpaque *) + (pFrm + pIe->offset + offset * i))-> + num_data; + pIePresent = ((tDot11fIEESECckmOpaque *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeESERadMgmtCap: + offset = sizeof(tDot11fIEESERadMgmtCap); + byteCount = 2; + pIePresent = ((tDot11fIEESERadMgmtCap *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeESETrafStrmMet: + offset = sizeof(tDot11fIEESETrafStrmMet); + byteCount = 4; + pIePresent = ((tDot11fIEESETrafStrmMet *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeESETrafStrmRateSet: + offset = sizeof(tDot11fIEESETrafStrmRateSet); + byteCount = ((tDot11fIEESETrafStrmRateSet *) + (pFrm + pIe->offset + offset * i))-> + num_tsrates + 1; + pIePresent = ((tDot11fIEESETrafStrmRateSet *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeESETxmitPower: + offset = sizeof(tDot11fIEESETxmitPower); + byteCount = 2; + pIePresent = ((tDot11fIEESETxmitPower *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeESEVersion: + offset = sizeof(tDot11fIEESEVersion); + byteCount = 1; + pIePresent = ((tDot11fIEESEVersion *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeExtCap: + offset = sizeof(tDot11fIEExtCap); + byteCount = ((tDot11fIEExtCap *) + (pFrm + pIe->offset + offset * i))-> + num_bytes; + pIePresent = ((tDot11fIEExtCap *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeExtSuppRates: + offset = sizeof(tDot11fIEExtSuppRates); + byteCount = ((tDot11fIEExtSuppRates *) + (pFrm + pIe->offset + offset * i))-> + num_rates; + pIePresent = ((tDot11fIEExtSuppRates *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeFHParamSet: + offset = sizeof(tDot11fIEFHParamSet); + byteCount = 5; + pIePresent = ((tDot11fIEFHParamSet *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeFHParams: + offset = sizeof(tDot11fIEFHParams); + byteCount = 2; + pIePresent = ((tDot11fIEFHParams *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeFHPattTable: + offset = sizeof(tDot11fIEFHPattTable); + byteCount = ((tDot11fIEFHPattTable *) + (pFrm + pIe->offset + offset * i))-> + num_randtable + 4; + pIePresent = ((tDot11fIEFHPattTable *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeFTInfo: + offset = sizeof(tDot11fIEFTInfo); + status |= + dot11f_get_packed_ieft_info( + pCtx, (tDot11fIEFTInfo *) + (pFrm + pIe->offset + offset * i), + pnNeeded); + break; + case SigIeHTCaps: + offset = sizeof(tDot11fIEHTCaps); + byteCount = ((tDot11fIEHTCaps *) + (pFrm + pIe->offset + offset * i))-> + num_rsvd + 26; + pIePresent = ((tDot11fIEHTCaps *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeHTInfo: + offset = sizeof(tDot11fIEHTInfo); + byteCount = ((tDot11fIEHTInfo *) + (pFrm + pIe->offset + offset * i))-> + num_rsvd + 22; + pIePresent = ((tDot11fIEHTInfo *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeIBSSParams: + offset = sizeof(tDot11fIEIBSSParams); + byteCount = 2; + pIePresent = ((tDot11fIEIBSSParams *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeLinkIdentifier: + offset = sizeof(tDot11fIELinkIdentifier); + byteCount = 18; + pIePresent = ((tDot11fIELinkIdentifier *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeMBO_IE: + offset = sizeof(tDot11fIEMBO_IE); + byteCount = ((tDot11fIEMBO_IE *) + (pFrm + pIe->offset + offset * i))-> + num_assoc_disallowed + 3; + pIePresent = ((tDot11fIEMBO_IE *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeMeasurementReport: + offset = sizeof(tDot11fIEMeasurementReport); + status |= + dot11f_get_packed_ie_measurement_report( + pCtx, (tDot11fIEMeasurementReport *) + (pFrm + pIe->offset + offset * i), + pnNeeded); + break; + case SigIeMeasurementRequest: + offset = sizeof(tDot11fIEMeasurementRequest); + status |= + dot11f_get_packed_ie_measurement_request( + pCtx, (tDot11fIEMeasurementRequest *) + (pFrm + pIe->offset + offset * i), + pnNeeded); + break; + case SigIeMobilityDomain: + offset = sizeof(tDot11fIEMobilityDomain); + byteCount = 3; + pIePresent = ((tDot11fIEMobilityDomain *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeNeighborReport: + offset = sizeof(tDot11fIENeighborReport); + status |= + dot11f_get_packed_ie_neighbor_report( + pCtx, (tDot11fIENeighborReport *) + (pFrm + pIe->offset + offset * i), + pnNeeded); + break; + case SigIeOBSSScanParameters: + offset = sizeof(tDot11fIEOBSSScanParameters); + byteCount = 14; + pIePresent = ((tDot11fIEOBSSScanParameters *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeOperatingMode: + offset = sizeof(tDot11fIEOperatingMode); + byteCount = 1; + pIePresent = ((tDot11fIEOperatingMode *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeP2PAssocReq: + offset = sizeof(tDot11fIEP2PAssocReq); + status |= + dot11f_get_packed_iep2_p_assoc_req( + pCtx, (tDot11fIEP2PAssocReq *) + (pFrm + pIe->offset + offset * i), + pnNeeded); + break; + case SigIeP2PAssocRes: + offset = sizeof(tDot11fIEP2PAssocRes); + status |= + dot11f_get_packed_iep2_p_assoc_res( + pCtx, (tDot11fIEP2PAssocRes *) + (pFrm + pIe->offset + offset * i), + pnNeeded); + break; + case SigIeP2PBeacon: + offset = sizeof(tDot11fIEP2PBeacon); + status |= + dot11f_get_packed_iep2_p_beacon( + pCtx, (tDot11fIEP2PBeacon *) + (pFrm + pIe->offset + offset * i), + pnNeeded); + break; + case SigIeP2PBeaconProbeRes: + offset = sizeof(tDot11fIEP2PBeaconProbeRes); + status |= + dot11f_get_packed_iep2_p_beacon_probe_res( + pCtx, (tDot11fIEP2PBeaconProbeRes *) + (pFrm + pIe->offset + offset * i), + pnNeeded); + break; + case SigIeP2PDeAuth: + offset = sizeof(tDot11fIEP2PDeAuth); + status |= + dot11f_get_packed_iep2_p_de_auth( + pCtx, (tDot11fIEP2PDeAuth *) + (pFrm + pIe->offset + offset * i), + pnNeeded); + break; + case SigIeP2PDisAssoc: + offset = sizeof(tDot11fIEP2PDisAssoc); + status |= + dot11f_get_packed_iep2_p_dis_assoc( + pCtx, (tDot11fIEP2PDisAssoc *) + (pFrm + pIe->offset + offset * i), + pnNeeded); + break; + case SigIeP2PIEOpaque: + offset = sizeof(tDot11fIEP2PIEOpaque); + byteCount = ((tDot11fIEP2PIEOpaque *) + (pFrm + pIe->offset + offset * i))-> + num_data; + pIePresent = ((tDot11fIEP2PIEOpaque *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeP2PProbeReq: + offset = sizeof(tDot11fIEP2PProbeReq); + status |= + dot11f_get_packed_iep2_p_probe_req( + pCtx, (tDot11fIEP2PProbeReq *) + (pFrm + pIe->offset + offset * i), + pnNeeded); + break; + case SigIeP2PProbeRes: + offset = sizeof(tDot11fIEP2PProbeRes); + status |= + dot11f_get_packed_iep2_p_probe_res( + pCtx, (tDot11fIEP2PProbeRes *) + (pFrm + pIe->offset + offset * i), + pnNeeded); + break; + case SigIePTIControl: + offset = sizeof(tDot11fIEPTIControl); + byteCount = 3; + pIePresent = ((tDot11fIEPTIControl *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIePUBufferStatus: + offset = sizeof(tDot11fIEPUBufferStatus); + byteCount = 1; + pIePresent = ((tDot11fIEPUBufferStatus *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIePowerCaps: + offset = sizeof(tDot11fIEPowerCaps); + byteCount = 2; + pIePresent = ((tDot11fIEPowerCaps *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIePowerConstraints: + offset = sizeof(tDot11fIEPowerConstraints); + byteCount = 1; + pIePresent = ((tDot11fIEPowerConstraints *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeQBSSLoad: + offset = sizeof(tDot11fIEQBSSLoad); + byteCount = 5; + pIePresent = ((tDot11fIEQBSSLoad *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeQCN_IE: + offset = sizeof(tDot11fIEQCN_IE); + byteCount = 4; + pIePresent = ((tDot11fIEQCN_IE *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeQComVendorIE: + offset = sizeof(tDot11fIEQComVendorIE); + byteCount = 2; + pIePresent = ((tDot11fIEQComVendorIE *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeQOSCapsAp: + offset = sizeof(tDot11fIEQOSCapsAp); + byteCount = 1; + pIePresent = ((tDot11fIEQOSCapsAp *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeQOSCapsStation: + offset = sizeof(tDot11fIEQOSCapsStation); + byteCount = 1; + pIePresent = ((tDot11fIEQOSCapsStation *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeQosMapSet: + offset = sizeof(tDot11fIEQosMapSet); + byteCount = ((tDot11fIEQosMapSet *) + (pFrm + pIe->offset + offset * i))-> + num_dscp_exceptions; + pIePresent = ((tDot11fIEQosMapSet *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeQuiet: + offset = sizeof(tDot11fIEQuiet); + byteCount = 6; + pIePresent = ((tDot11fIEQuiet *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeRCPIIE: + offset = sizeof(tDot11fIERCPIIE); + byteCount = 1; + pIePresent = ((tDot11fIERCPIIE *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeRICDataDesc: + offset = sizeof(tDot11fIERICDataDesc); + pnNeeded -= 2 ; /* Subtract the length and Oui as this is our container IE to group Ies and it doesnt have its own length and OUI. */ + status |= + dot11f_get_packed_ieric_data_desc( + pCtx, (tDot11fIERICDataDesc *) + (pFrm + pIe->offset + offset * i), + pnNeeded); + break; + case SigIeRSN: + offset = sizeof(tDot11fIERSN); + status |= + dot11f_get_packed_iersn( + pCtx, (tDot11fIERSN *) + (pFrm + pIe->offset + offset * i), + pnNeeded); + break; + case SigIeRSNIIE: + offset = sizeof(tDot11fIERSNIIE); + byteCount = 1; + pIePresent = ((tDot11fIERSNIIE *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeRSNOpaque: + offset = sizeof(tDot11fIERSNOpaque); + byteCount = ((tDot11fIERSNOpaque *) + (pFrm + pIe->offset + offset * i))-> + num_data; + pIePresent = ((tDot11fIERSNOpaque *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeSuppChannels: + offset = sizeof(tDot11fIESuppChannels); + byteCount = ((tDot11fIESuppChannels *) + (pFrm + pIe->offset + offset * i))-> + num_bands * 2; + pIePresent = ((tDot11fIESuppChannels *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeSuppOperatingClasses: + offset = sizeof(tDot11fIESuppOperatingClasses); + byteCount = ((tDot11fIESuppOperatingClasses *) + (pFrm + pIe->offset + offset * i))-> + num_classes; + pIePresent = ((tDot11fIESuppOperatingClasses *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeSuppRates: + offset = sizeof(tDot11fIESuppRates); + byteCount = ((tDot11fIESuppRates *) + (pFrm + pIe->offset + offset * i))-> + num_rates; + pIePresent = ((tDot11fIESuppRates *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeTIM: + offset = sizeof(tDot11fIETIM); + byteCount = ((tDot11fIETIM *) + (pFrm + pIe->offset + offset * i))-> + num_vbmp + 3; + pIePresent = ((tDot11fIETIM *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeTPCReport: + offset = sizeof(tDot11fIETPCReport); + byteCount = 2; + pIePresent = ((tDot11fIETPCReport *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeTPCRequest: + offset = sizeof(tDot11fIETPCRequest); + byteCount = 0; + pIePresent = ((tDot11fIETPCRequest *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeTimeAdvertisement: + offset = sizeof(tDot11fIETimeAdvertisement); + byteCount = 16; + pIePresent = ((tDot11fIETimeAdvertisement *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeTimeoutInterval: + offset = sizeof(tDot11fIETimeoutInterval); + byteCount = 5; + pIePresent = ((tDot11fIETimeoutInterval *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeVHTExtBssLoad: + offset = sizeof(tDot11fIEVHTExtBssLoad); + byteCount = 5; + pIePresent = ((tDot11fIEVHTExtBssLoad *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeVendor1IE: + offset = sizeof(tDot11fIEVendor1IE); + byteCount = 0; + pIePresent = ((tDot11fIEVendor1IE *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeVendor3IE: + offset = sizeof(tDot11fIEVendor3IE); + byteCount = 0; + pIePresent = ((tDot11fIEVendor3IE *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeWAPI: + offset = sizeof(tDot11fIEWAPI); + status |= + dot11f_get_packed_iewapi( + pCtx, (tDot11fIEWAPI *) + (pFrm + pIe->offset + offset * i), + pnNeeded); + break; + case SigIeWAPIOpaque: + offset = sizeof(tDot11fIEWAPIOpaque); + byteCount = ((tDot11fIEWAPIOpaque *) + (pFrm + pIe->offset + offset * i))-> + num_data; + pIePresent = ((tDot11fIEWAPIOpaque *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeWFATPC: + offset = sizeof(tDot11fIEWFATPC); + byteCount = 2; + pIePresent = ((tDot11fIEWFATPC *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeWFDIEOpaque: + offset = sizeof(tDot11fIEWFDIEOpaque); + byteCount = ((tDot11fIEWFDIEOpaque *) + (pFrm + pIe->offset + offset * i))-> + num_data; + pIePresent = ((tDot11fIEWFDIEOpaque *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeWMMCaps: + offset = sizeof(tDot11fIEWMMCaps); + byteCount = 2; + pIePresent = ((tDot11fIEWMMCaps *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeWMMInfoAp: + offset = sizeof(tDot11fIEWMMInfoAp); + byteCount = 2; + pIePresent = ((tDot11fIEWMMInfoAp *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeWMMInfoStation: + offset = sizeof(tDot11fIEWMMInfoStation); + byteCount = 2; + pIePresent = ((tDot11fIEWMMInfoStation *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeWMMParams: + offset = sizeof(tDot11fIEWMMParams); + byteCount = 19; + pIePresent = ((tDot11fIEWMMParams *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeWPA: + offset = sizeof(tDot11fIEWPA); + status |= + dot11f_get_packed_iewpa( + pCtx, (tDot11fIEWPA *) + (pFrm + pIe->offset + offset * i), + pnNeeded); + break; + case SigIeWPAOpaque: + offset = sizeof(tDot11fIEWPAOpaque); + byteCount = ((tDot11fIEWPAOpaque *) + (pFrm + pIe->offset + offset * i))-> + num_data; + pIePresent = ((tDot11fIEWPAOpaque *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeWSC: + offset = sizeof(tDot11fIEWSC); + status |= + dot11f_get_packed_iewsc( + pCtx, (tDot11fIEWSC *) + (pFrm + pIe->offset + offset * i), + pnNeeded); + break; + case SigIeWscAssocReq: + offset = sizeof(tDot11fIEWscAssocReq); + status |= + dot11f_get_packed_ie_wsc_assoc_req( + pCtx, (tDot11fIEWscAssocReq *) + (pFrm + pIe->offset + offset * i), + pnNeeded); + break; + case SigIeWscAssocRes: + offset = sizeof(tDot11fIEWscAssocRes); + status |= + dot11f_get_packed_ie_wsc_assoc_res( + pCtx, (tDot11fIEWscAssocRes *) + (pFrm + pIe->offset + offset * i), + pnNeeded); + break; + case SigIeWscBeacon: + offset = sizeof(tDot11fIEWscBeacon); + status |= + dot11f_get_packed_ie_wsc_beacon( + pCtx, (tDot11fIEWscBeacon *) + (pFrm + pIe->offset + offset * i), + pnNeeded); + break; + case SigIeWscBeaconProbeRes: + offset = sizeof(tDot11fIEWscBeaconProbeRes); + status |= + dot11f_get_packed_ie_wsc_beacon_probe_res( + pCtx, (tDot11fIEWscBeaconProbeRes *) + (pFrm + pIe->offset + offset * i), + pnNeeded); + break; + case SigIeWscIEOpaque: + offset = sizeof(tDot11fIEWscIEOpaque); + byteCount = ((tDot11fIEWscIEOpaque *) + (pFrm + pIe->offset + offset * i))-> + num_data; + pIePresent = ((tDot11fIEWscIEOpaque *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeWscProbeReq: + offset = sizeof(tDot11fIEWscProbeReq); + status |= + dot11f_get_packed_ie_wsc_probe_req( + pCtx, (tDot11fIEWscProbeReq *) + (pFrm + pIe->offset + offset * i), + pnNeeded); + break; + case SigIeWscProbeRes: + offset = sizeof(tDot11fIEWscProbeRes); + status |= + dot11f_get_packed_ie_wsc_probe_res( + pCtx, (tDot11fIEWscProbeRes *) + (pFrm + pIe->offset + offset * i), + pnNeeded); + break; + case SigIeWscReassocRes: + offset = sizeof(tDot11fIEWscReassocRes); + status |= + dot11f_get_packed_ie_wsc_reassoc_res( + pCtx, (tDot11fIEWscReassocRes *) + (pFrm + pIe->offset + offset * i), + pnNeeded); + break; + case SigIeext_chan_switch_ann: + offset = sizeof(tDot11fIEext_chan_switch_ann); + byteCount = 4; + pIePresent = ((tDot11fIEext_chan_switch_ann *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIehs20vendor_ie: + offset = sizeof(tDot11fIEhs20vendor_ie); + status |= + dot11f_get_packed_ie_hs20vendor_ie( + pCtx, (tDot11fIEhs20vendor_ie *) + (pFrm + pIe->offset + offset * i), + pnNeeded); + break; + case SigIeht2040_bss_coexistence: + offset = sizeof(tDot11fIEht2040_bss_coexistence); + byteCount = 1; + pIePresent = ((tDot11fIEht2040_bss_coexistence *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeht2040_bss_intolerant_report: + offset = sizeof(tDot11fIEht2040_bss_intolerant_report); + byteCount = ((tDot11fIEht2040_bss_intolerant_report *) + (pFrm + pIe->offset + offset * i))-> + num_channel_list + 1; + pIePresent = ((tDot11fIEht2040_bss_intolerant_report *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIesec_chan_offset_ele: + offset = sizeof(tDot11fIEsec_chan_offset_ele); + byteCount = 1; + pIePresent = ((tDot11fIEsec_chan_offset_ele *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIevendor_vht_ie: + offset = sizeof(tDot11fIEvendor_vht_ie); + status |= + dot11f_get_packed_ie_vendor_vht_ie( + pCtx, (tDot11fIEvendor_vht_ie *) + (pFrm + pIe->offset + offset * i), + pnNeeded); + break; + default: + FRAMES_LOG1(pCtx, FRLOGE, FRFL("INTERNAL ERROR-- I don" + "'t know about the IE signature %d; this is most l" + "ikely a bug in 'framesc'.\n"), pIe->sig); + return DOT11F_INTERNAL_ERROR; + } /*End of switch Case*/ + + if (byteCount && pIePresent) + *pnNeeded += byteCount; + } /*End of for loop*/ + } + ++pIe; + } + return status; + +} + +static uint32_t get_packed_size_tlv_core(tpAniSirGlobal pCtx, + uint8_t *pFrm, + uint32_t *pnNeeded, + const tTLVDefn TLVs[]) +{ + const tTLVDefn *pTlv; + uint32_t status; + tFRAMES_BOOL *pfFound; + uint32_t byteCount = 0; + uint8_t pTlvPresent = 0; + + status = DOT11F_PARSE_SUCCESS; + + pTlv = &(TLVs[0]); + while (0xffff != pTlv->id) { + pfFound = (tFRAMES_BOOL *)(pFrm + pTlv->offset + + pTlv->presenceOffset); + if (*pfFound) { + *pnNeeded += (pTlv->sType + pTlv->sLen); + if (pTlv->pec) + *pnNeeded += 3U; + switch (pTlv->sig) { + case SigTlvAuthorizedMACs: + byteCount = 6; + pTlvPresent = ((tDot11fTLVAuthorizedMACs *) + (pFrm + pTlv->offset))->present; + break; + case SigTlvRequestToEnroll: + byteCount = 1; + pTlvPresent = ((tDot11fTLVRequestToEnroll *) + (pFrm + pTlv->offset))->present; + break; + case SigTlvVersion2: + byteCount = 1; + pTlvPresent = ((tDot11fTLVVersion2 *) + (pFrm + pTlv->offset))->present; + break; + case SigTlvAPSetupLocked: + byteCount = 1; + pTlvPresent = ((tDot11fTLVAPSetupLocked *) + (pFrm + pTlv->offset))->present; + break; + case SigTlvAssociationState: + byteCount = 2; + pTlvPresent = ((tDot11fTLVAssociationState *) + (pFrm + pTlv->offset))->present; + break; + case SigTlvConfigMethods: + byteCount = 2; + pTlvPresent = ((tDot11fTLVConfigMethods *) + (pFrm + pTlv->offset))->present; + break; + case SigTlvConfigurationError: + byteCount = 2; + pTlvPresent = ((tDot11fTLVConfigurationError *) + (pFrm + pTlv->offset))->present; + break; + case SigTlvDeviceName: + byteCount = ((tDot11fTLVDeviceName *)(pFrm + pTlv->offset))->num_text; + pTlvPresent = ((tDot11fTLVDeviceName *) + (pFrm + pTlv->offset))->present; + break; + case SigTlvDevicePasswordID: + byteCount = 2; + pTlvPresent = ((tDot11fTLVDevicePasswordID *) + (pFrm + pTlv->offset))->present; + break; + case SigTlvExtendedListenTiming: + byteCount = 4; + pTlvPresent = ((tDot11fTLVExtendedListenTiming *) + (pFrm + pTlv->offset))->present; + break; + case SigTlvListenChannel: + byteCount = 5; + pTlvPresent = ((tDot11fTLVListenChannel *) + (pFrm + pTlv->offset))->present; + break; + case SigTlvManufacturer: + byteCount = ((tDot11fTLVManufacturer *)(pFrm + pTlv->offset))->num_name; + pTlvPresent = ((tDot11fTLVManufacturer *) + (pFrm + pTlv->offset))->present; + break; + case SigTlvMinorReasonCode: + byteCount = 1; + pTlvPresent = ((tDot11fTLVMinorReasonCode *) + (pFrm + pTlv->offset))->present; + break; + case SigTlvModelName: + byteCount = ((tDot11fTLVModelName *)(pFrm + pTlv->offset))->num_text; + pTlvPresent = ((tDot11fTLVModelName *) + (pFrm + pTlv->offset))->present; + break; + case SigTlvModelNumber: + byteCount = ((tDot11fTLVModelNumber *)(pFrm + pTlv->offset))->num_text; + pTlvPresent = ((tDot11fTLVModelNumber *) + (pFrm + pTlv->offset))->present; + break; + case SigTlvNoticeOfAbsence: + byteCount = ((tDot11fTLVNoticeOfAbsence *)(pFrm + pTlv->offset))->num_NoADesc+2; + pTlvPresent = ((tDot11fTLVNoticeOfAbsence *) + (pFrm + pTlv->offset))->present; + break; + case SigTlvOperatingChannel: + byteCount = 5; + pTlvPresent = ((tDot11fTLVOperatingChannel *) + (pFrm + pTlv->offset))->present; + break; + case SigTlvP2PCapability: + byteCount = 2; + pTlvPresent = ((tDot11fTLVP2PCapability *) + (pFrm + pTlv->offset))->present; + break; + case SigTlvP2PDeviceId: + byteCount = 6; + pTlvPresent = ((tDot11fTLVP2PDeviceId *) + (pFrm + pTlv->offset))->present; + break; + case SigTlvP2PDeviceInfo: + status = get_packed_size_tlv_core(pCtx, (uint8_t *)pFrm + pTlv->offset, pnNeeded, TLVS_P2PDeviceInfo); + byteCount = 16; + pTlvPresent = ((tDot11fTLVP2PDeviceInfo *) + (pFrm + pTlv->offset))->present; + break; + case SigTlvP2PGroupInfo: + byteCount = ((tDot11fTLVP2PGroupInfo *)(pFrm + pTlv->offset))->num_P2PClientInfoDesc; + pTlvPresent = ((tDot11fTLVP2PGroupInfo *) + (pFrm + pTlv->offset))->present; + break; + case SigTlvP2PStatus: + byteCount = 1; + pTlvPresent = ((tDot11fTLVP2PStatus *) + (pFrm + pTlv->offset))->present; + break; + case SigTlvPrimaryDeviceType: + byteCount = 8; + pTlvPresent = ((tDot11fTLVPrimaryDeviceType *) + (pFrm + pTlv->offset))->present; + break; + case SigTlvRFBands: + byteCount = 1; + pTlvPresent = ((tDot11fTLVRFBands *) + (pFrm + pTlv->offset))->present; + break; + case SigTlvRequestDeviceType: + byteCount = 8; + pTlvPresent = ((tDot11fTLVRequestDeviceType *) + (pFrm + pTlv->offset))->present; + break; + case SigTlvRequestType: + byteCount = 1; + pTlvPresent = ((tDot11fTLVRequestType *) + (pFrm + pTlv->offset))->present; + break; + case SigTlvResponseType: + byteCount = 1; + pTlvPresent = ((tDot11fTLVResponseType *) + (pFrm + pTlv->offset))->present; + break; + case SigTlvSelectedRegistrar: + byteCount = 1; + pTlvPresent = ((tDot11fTLVSelectedRegistrar *) + (pFrm + pTlv->offset))->present; + break; + case SigTlvSelectedRegistrarConfigMethods: + byteCount = 2; + pTlvPresent = ((tDot11fTLVSelectedRegistrarConfigMethods *) + (pFrm + pTlv->offset))->present; + break; + case SigTlvSerialNumber: + byteCount = ((tDot11fTLVSerialNumber *)(pFrm + pTlv->offset))->num_text; + pTlvPresent = ((tDot11fTLVSerialNumber *) + (pFrm + pTlv->offset))->present; + break; + case SigTlvUUID_E: + byteCount = 16; + pTlvPresent = ((tDot11fTLVUUID_E *) + (pFrm + pTlv->offset))->present; + break; + case SigTlvUUID_R: + byteCount = 16; + pTlvPresent = ((tDot11fTLVUUID_R *) + (pFrm + pTlv->offset))->present; + break; + case SigTlvVendorExtension: + status = get_packed_size_tlv_core(pCtx, (uint8_t *)pFrm + pTlv->offset, pnNeeded, TLVS_VendorExtension); + byteCount = 3; + pTlvPresent = ((tDot11fTLVVendorExtension *) + (pFrm + pTlv->offset))->present; + break; + case SigTlvVersion: + byteCount = 1; + pTlvPresent = ((tDot11fTLVVersion *) + (pFrm + pTlv->offset))->present; + break; + case SigTlvWPSState: + byteCount = 1; + pTlvPresent = ((tDot11fTLVWPSState *) + (pFrm + pTlv->offset))->present; + break; + case SigTlvP2PInterface: + byteCount = 6; + pTlvPresent = ((tDot11fTLVP2PInterface *) + (pFrm + pTlv->offset))->present; + break; + case SigTlvP2PManageability: + byteCount = 1; + pTlvPresent = ((tDot11fTLVP2PManageability *) + (pFrm + pTlv->offset))->present; + break; + default: + FRAMES_LOG1(pCtx, FRLOGE, FRFL("INTERNAL ERROR-- I don" + "'t know about the TLV signature %d; this is most l" + "ikely a bug in 'framesc'.\n"), pTlv->sig); + return DOT11F_INTERNAL_ERROR; + } + if (pTlvPresent) { + *pnNeeded += byteCount; + } + } + ++pTlv; + } + return status; +} +void dot11f_pack_ff_aid(tpAniSirGlobal pCtx, + tDot11fFfAID *pSrc, + uint8_t *pBuf) +{ + frameshtons(pCtx, pBuf, pSrc->associd, 0); + (void)pCtx; +} /* End dot11f_pack_ff_aid. */ + +void dot11f_pack_ff_action(tpAniSirGlobal pCtx, + tDot11fFfAction *pSrc, + uint8_t *pBuf) +{ + *pBuf = pSrc->action; + (void)pCtx; +} /* End dot11f_pack_ff_action. */ + +void dot11f_pack_ff_auth_algo(tpAniSirGlobal pCtx, + tDot11fFfAuthAlgo *pSrc, + uint8_t *pBuf) +{ + frameshtons(pCtx, pBuf, pSrc->algo, 0); + (void)pCtx; +} /* End dot11f_pack_ff_auth_algo. */ + +void dot11f_pack_ff_auth_seq_no(tpAniSirGlobal pCtx, + tDot11fFfAuthSeqNo *pSrc, + uint8_t *pBuf) +{ + frameshtons(pCtx, pBuf, pSrc->no, 0); + (void)pCtx; +} /* End dot11f_pack_ff_auth_seq_no. */ + +void dot11f_pack_ff_beacon_interval(tpAniSirGlobal pCtx, + tDot11fFfBeaconInterval *pSrc, + uint8_t *pBuf) +{ + frameshtons(pCtx, pBuf, pSrc->interval, 0); + (void)pCtx; +} /* End dot11f_pack_ff_beacon_interval. */ + +void dot11f_pack_ff_capabilities(tpAniSirGlobal pCtx, + tDot11fFfCapabilities *pSrc, + uint8_t *pBuf) +{ + uint16_t tmp70__; + tmp70__ = 0U; + tmp70__ |= (pSrc->ess << 0); + tmp70__ |= (pSrc->ibss << 1); + tmp70__ |= (pSrc->cfPollable << 2); + tmp70__ |= (pSrc->cfPollReq << 3); + tmp70__ |= (pSrc->privacy << 4); + tmp70__ |= (pSrc->shortPreamble << 5); + tmp70__ |= (pSrc->pbcc << 6); + tmp70__ |= (pSrc->channelAgility << 7); + tmp70__ |= (pSrc->spectrumMgt << 8); + tmp70__ |= (pSrc->qos << 9); + tmp70__ |= (pSrc->shortSlotTime << 10); + tmp70__ |= (pSrc->apsd << 11); + tmp70__ |= (pSrc->rrm << 12); + tmp70__ |= (pSrc->dsssOfdm << 13); + tmp70__ |= (pSrc->delayedBA << 14); + tmp70__ |= (pSrc->immediateBA << 15); + frameshtons(pCtx, pBuf, tmp70__, 0); + (void)pCtx; +} /* End dot11f_pack_ff_capabilities. */ + +void dot11f_pack_ff_category(tpAniSirGlobal pCtx, + tDot11fFfCategory *pSrc, + uint8_t *pBuf) +{ + *pBuf = pSrc->category; + (void)pCtx; +} /* End dot11f_pack_ff_category. */ + +void dot11f_pack_ff_current_ap_address(tpAniSirGlobal pCtx, + tDot11fFfCurrentAPAddress *pSrc, + uint8_t *pBuf) +{ + DOT11F_MEMCPY(pCtx, pBuf, pSrc->mac, 6); + (void)pCtx; +} /* End dot11f_pack_ff_current_ap_address. */ + +void dot11f_pack_ff_dialog_token(tpAniSirGlobal pCtx, + tDot11fFfDialogToken *pSrc, + uint8_t *pBuf) +{ + *pBuf = pSrc->token; + (void)pCtx; +} /* End dot11f_pack_ff_dialog_token. */ + +void dot11f_pack_ff_link_margin(tpAniSirGlobal pCtx, + tDot11fFfLinkMargin *pSrc, + uint8_t *pBuf) +{ + *pBuf = pSrc->linkMargin; + (void)pCtx; +} /* End dot11f_pack_ff_link_margin. */ + +void dot11f_pack_ff_listen_interval(tpAniSirGlobal pCtx, + tDot11fFfListenInterval *pSrc, + uint8_t *pBuf) +{ + frameshtons(pCtx, pBuf, pSrc->interval, 0); + (void)pCtx; +} /* End dot11f_pack_ff_listen_interval. */ + +void dot11f_pack_ff_max_tx_power(tpAniSirGlobal pCtx, + tDot11fFfMaxTxPower *pSrc, + uint8_t *pBuf) +{ + *pBuf = pSrc->maxTxPower; + (void)pCtx; +} /* End dot11f_pack_ff_max_tx_power. */ + +void dot11f_pack_ff_num_of_repetitions(tpAniSirGlobal pCtx, + tDot11fFfNumOfRepetitions *pSrc, + uint8_t *pBuf) +{ + frameshtons(pCtx, pBuf, pSrc->repetitions, 0); + (void)pCtx; +} /* End dot11f_pack_ff_num_of_repetitions. */ + +void dot11f_pack_ff_operating_mode(tpAniSirGlobal pCtx, + tDot11fFfOperatingMode *pSrc, + uint8_t *pBuf) +{ + uint8_t tmp71__; + tmp71__ = 0U; + tmp71__ |= (pSrc->chanWidth << 0); + tmp71__ |= (pSrc->reserved << 2); + tmp71__ |= (pSrc->rxNSS << 4); + tmp71__ |= (pSrc->rxNSSType << 7); + *pBuf = tmp71__; + (void)pCtx; +} /* End dot11f_pack_ff_operating_mode. */ + +void dot11f_pack_ff_rcpi(tpAniSirGlobal pCtx, + tDot11fFfRCPI *pSrc, + uint8_t *pBuf) +{ + *pBuf = pSrc->rcpi; + (void)pCtx; +} /* End dot11f_pack_ff_rcpi. */ + +void dot11f_pack_ff_rsni(tpAniSirGlobal pCtx, + tDot11fFfRSNI *pSrc, + uint8_t *pBuf) +{ + *pBuf = pSrc->rsni; + (void)pCtx; +} /* End dot11f_pack_ff_rsni. */ + +void dot11f_pack_ff_reason(tpAniSirGlobal pCtx, + tDot11fFfReason *pSrc, + uint8_t *pBuf) +{ + frameshtons(pCtx, pBuf, pSrc->code, 0); + (void)pCtx; +} /* End dot11f_pack_ff_reason. */ + +void dot11f_pack_ff_rx_antenna_id(tpAniSirGlobal pCtx, + tDot11fFfRxAntennaId *pSrc, + uint8_t *pBuf) +{ + *pBuf = pSrc->antennaId; + (void)pCtx; +} /* End dot11f_pack_ff_rx_antenna_id. */ + +void dot11f_pack_ff_sm_power_mode_set(tpAniSirGlobal pCtx, + tDot11fFfSMPowerModeSet *pSrc, + uint8_t *pBuf) +{ + uint8_t tmp72__; + tmp72__ = 0U; + tmp72__ |= (pSrc->PowerSave_En << 0); + tmp72__ |= (pSrc->Mode << 1); + tmp72__ |= (pSrc->reserved << 2); + *pBuf = tmp72__; + (void)pCtx; +} /* End dot11f_pack_ff_sm_power_mode_set. */ + +void dot11f_pack_ff_status(tpAniSirGlobal pCtx, + tDot11fFfStatus *pSrc, + uint8_t *pBuf) +{ + frameshtons(pCtx, pBuf, pSrc->status, 0); + (void)pCtx; +} /* End dot11f_pack_ff_status. */ + +void dot11f_pack_ff_status_code(tpAniSirGlobal pCtx, + tDot11fFfStatusCode *pSrc, + uint8_t *pBuf) +{ + *pBuf = pSrc->statusCode; + (void)pCtx; +} /* End dot11f_pack_ff_status_code. */ + +void dot11f_pack_ff_tpc_ele_id(tpAniSirGlobal pCtx, + tDot11fFfTPCEleID *pSrc, + uint8_t *pBuf) +{ + *pBuf = pSrc->TPCId; + (void)pCtx; +} /* End dot11f_pack_ff_tpc_ele_id. */ + +void dot11f_pack_ff_tpc_ele_len(tpAniSirGlobal pCtx, + tDot11fFfTPCEleLen *pSrc, + uint8_t *pBuf) +{ + *pBuf = pSrc->TPCLen; + (void)pCtx; +} /* End dot11f_pack_ff_tpc_ele_len. */ + +void dot11f_pack_ff_ts_info(tpAniSirGlobal pCtx, + tDot11fFfTSInfo *pSrc, + uint8_t *pBuf) +{ + uint32_t tmp73__; + tmp73__ = 0U; + tmp73__ |= (pSrc->traffic_type << 0); + tmp73__ |= (pSrc->tsid << 1); + tmp73__ |= (pSrc->direction << 5); + tmp73__ |= (pSrc->access_policy << 7); + tmp73__ |= (pSrc->aggregation << 9); + tmp73__ |= (pSrc->psb << 10); + tmp73__ |= (pSrc->user_priority << 11); + tmp73__ |= (pSrc->tsinfo_ack_pol << 14); + tmp73__ |= (pSrc->schedule << 16); + tmp73__ |= (pSrc->unused << 17); + frameshtonl(pCtx, pBuf, tmp73__, 0); + (void)pCtx; +} /* End dot11f_pack_ff_ts_info. */ + +void dot11f_pack_ff_time_stamp(tpAniSirGlobal pCtx, + tDot11fFfTimeStamp *pSrc, + uint8_t *pBuf) +{ + frameshtonq(pCtx, pBuf, pSrc->timestamp, 0); + (void)pCtx; +} /* End dot11f_pack_ff_time_stamp. */ + +void dot11f_pack_ff_transaction_id(tpAniSirGlobal pCtx, + tDot11fFfTransactionId *pSrc, + uint8_t *pBuf) +{ + DOT11F_MEMCPY(pCtx, pBuf, pSrc->transId, 2); + (void)pCtx; +} /* End dot11f_pack_ff_transaction_id. */ + +void dot11f_pack_ff_tx_antenna_id(tpAniSirGlobal pCtx, + tDot11fFfTxAntennaId *pSrc, + uint8_t *pBuf) +{ + *pBuf = pSrc->antennaId; + (void)pCtx; +} /* End dot11f_pack_ff_tx_antenna_id. */ + +void dot11f_pack_ff_tx_power(tpAniSirGlobal pCtx, + tDot11fFfTxPower *pSrc, + uint8_t *pBuf) +{ + *pBuf = pSrc->txPower; + (void)pCtx; +} /* End dot11f_pack_ff_tx_power. */ + +void dot11f_pack_ff_vht_membership_status_array(tpAniSirGlobal pCtx, + tDot11fFfVhtMembershipStatusArray *pSrc, + uint8_t *pBuf) +{ + DOT11F_MEMCPY(pCtx, pBuf, pSrc->membershipStatusArray, 8); + (void)pCtx; +} /* End dot11f_pack_ff_vht_membership_status_array. */ + +void dot11f_pack_ff_vht_user_position_array(tpAniSirGlobal pCtx, + tDot11fFfVhtUserPositionArray *pSrc, + uint8_t *pBuf) +{ + DOT11F_MEMCPY(pCtx, pBuf, pSrc->userPositionArray, 16); + (void)pCtx; +} /* End dot11f_pack_ff_vht_user_position_array. */ + +void dot11f_pack_ff_ext_chan_switch_ann_action(tpAniSirGlobal pCtx, + tDot11fFfext_chan_switch_ann_action *pSrc, + uint8_t *pBuf) +{ + uint32_t tmp74__; + tmp74__ = 0U; + tmp74__ |= (pSrc->switch_mode << 0); + tmp74__ |= (pSrc->op_class << 8); + tmp74__ |= (pSrc->new_channel << 16); + tmp74__ |= (pSrc->switch_count << 24); + frameshtonl(pCtx, pBuf, tmp74__, 0); + (void)pCtx; +} /* End dot11f_pack_ff_ext_chan_switch_ann_action. */ + +void dot11f_pack_ff_p2p_action_oui(tpAniSirGlobal pCtx, + tDot11fFfp2p_action_oui *pSrc, + uint8_t *pBuf) +{ + DOT11F_MEMCPY(pCtx, pBuf, pSrc->oui_data, 4); + (void)pCtx; +} /* End dot11f_pack_ff_p2p_action_oui. */ + +void dot11f_pack_ff_p2p_action_subtype(tpAniSirGlobal pCtx, + tDot11fFfp2p_action_subtype *pSrc, + uint8_t *pBuf) +{ + *pBuf = pSrc->subtype; + (void)pCtx; +} /* End dot11f_pack_ff_p2p_action_subtype. */ + +uint32_t dot11f_pack_tlv_authorized_ma_cs(tpAniSirGlobal pCtx, + tDot11fTLVAuthorizedMACs *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 8; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + *pBuf = 1; + pBuf += 1; *pnConsumed += 1; + pTlvLen = pBuf; + pBuf += 1; *pnConsumed += 1; + DOT11F_MEMCPY(pCtx, pBuf, pSrc->mac, 6); + *pnConsumed += 6; + pBuf += 6; + break; + } + (void)pCtx; + if (pTlvLen) { + *pTlvLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_tlv_authorized_ma_cs. */ + +uint32_t dot11f_pack_tlv_request_to_enroll(tpAniSirGlobal pCtx, + tDot11fTLVRequestToEnroll *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 3; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + *pBuf = 3; + pBuf += 1; *pnConsumed += 1; + pTlvLen = pBuf; + pBuf += 1; *pnConsumed += 1; + *pBuf = pSrc->req; + *pnConsumed += 1; + pBuf += 1; + break; + } + (void)pCtx; + if (pTlvLen) { + *pTlvLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_tlv_request_to_enroll. */ + +uint32_t dot11f_pack_tlv_version2(tpAniSirGlobal pCtx, + tDot11fTLVVersion2 *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint8_t tmp75__; + nNeeded += 3; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + *pBuf = 0; + pBuf += 1; *pnConsumed += 1; + pTlvLen = pBuf; + pBuf += 1; *pnConsumed += 1; + tmp75__ = 0U; + tmp75__ |= (pSrc->minor << 0); + tmp75__ |= (pSrc->major << 4); + *pBuf = tmp75__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + break; + } + (void)pCtx; + if (pTlvLen) { + *pTlvLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_tlv_version2. */ + +uint32_t dot11f_pack_tlv_ap_setup_locked(tpAniSirGlobal pCtx, + tDot11fTLVAPSetupLocked *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 5; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + frameshtons(pCtx, pBuf, 4183, 1); + pBuf += 2; *pnConsumed += 2; + pTlvLen = pBuf; + pBuf += 2; *pnConsumed += 2; + *pBuf = pSrc->fLocked; + *pnConsumed += 1; + pBuf += 1; + break; + } + (void)pCtx; + if (pTlvLen) { + frameshtons(pCtx, pTlvLen, *pnConsumed - nConsumedOnEntry - 4, 1); + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_tlv_ap_setup_locked. */ + +uint32_t dot11f_pack_tlv_association_state(tpAniSirGlobal pCtx, + tDot11fTLVAssociationState *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 6; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + frameshtons(pCtx, pBuf, 4098, 1); + pBuf += 2; *pnConsumed += 2; + pTlvLen = pBuf; + pBuf += 2; *pnConsumed += 2; + frameshtons(pCtx, pBuf, pSrc->state, 1); + *pnConsumed += 2; + pBuf += 2; + break; + } + (void)pCtx; + if (pTlvLen) { + frameshtons(pCtx, pTlvLen, *pnConsumed - nConsumedOnEntry - 4, 1); + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_tlv_association_state. */ + +uint32_t dot11f_pack_tlv_config_methods(tpAniSirGlobal pCtx, + tDot11fTLVConfigMethods *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 6; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + frameshtons(pCtx, pBuf, 4104, 1); + pBuf += 2; *pnConsumed += 2; + pTlvLen = pBuf; + pBuf += 2; *pnConsumed += 2; + frameshtons(pCtx, pBuf, pSrc->methods, 1); + *pnConsumed += 2; + pBuf += 2; + break; + } + (void)pCtx; + if (pTlvLen) { + frameshtons(pCtx, pTlvLen, *pnConsumed - nConsumedOnEntry - 4, 1); + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_tlv_config_methods. */ + +uint32_t dot11f_pack_tlv_configuration_error(tpAniSirGlobal pCtx, + tDot11fTLVConfigurationError *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 6; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + frameshtons(pCtx, pBuf, 4105, 1); + pBuf += 2; *pnConsumed += 2; + pTlvLen = pBuf; + pBuf += 2; *pnConsumed += 2; + frameshtons(pCtx, pBuf, pSrc->error, 1); + *pnConsumed += 2; + pBuf += 2; + break; + } + (void)pCtx; + if (pTlvLen) { + frameshtons(pCtx, pTlvLen, *pnConsumed - nConsumedOnEntry - 4, 1); + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_tlv_configuration_error. */ + +uint32_t dot11f_pack_tlv_device_name(tpAniSirGlobal pCtx, + tDot11fTLVDeviceName *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += (pSrc->num_text + 4) ; + + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + frameshtons(pCtx, pBuf, 4113, 1); + pBuf += 2; *pnConsumed += 2; + pTlvLen = pBuf; + pBuf += 2; *pnConsumed += 2; + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->text), pSrc->num_text); + *pnConsumed += pSrc->num_text; + pBuf += pSrc->num_text; + break; + } + (void)pCtx; + if (pTlvLen) { + frameshtons(pCtx, pTlvLen, *pnConsumed - nConsumedOnEntry - 4, 1); + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_tlv_device_name. */ + +uint32_t dot11f_pack_tlv_device_password_id(tpAniSirGlobal pCtx, + tDot11fTLVDevicePasswordID *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 6; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + frameshtons(pCtx, pBuf, 4114, 1); + pBuf += 2; *pnConsumed += 2; + pTlvLen = pBuf; + pBuf += 2; *pnConsumed += 2; + frameshtons(pCtx, pBuf, pSrc->id, 1); + *pnConsumed += 2; + pBuf += 2; + break; + } + (void)pCtx; + if (pTlvLen) { + frameshtons(pCtx, pTlvLen, *pnConsumed - nConsumedOnEntry - 4, 1); + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_tlv_device_password_id. */ + +uint32_t dot11f_pack_tlv_extended_listen_timing(tpAniSirGlobal pCtx, + tDot11fTLVExtendedListenTiming *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 7; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + *pBuf = 8; + pBuf += 1; *pnConsumed += 1; + pTlvLen = pBuf; + pBuf += 2; *pnConsumed += 2; + frameshtons(pCtx, pBuf, pSrc->availibilityPeriod, 0); + *pnConsumed += 2; + pBuf += 2; + frameshtons(pCtx, pBuf, pSrc->availibilityInterval, 0); + *pnConsumed += 2; + pBuf += 2; + break; + } + (void)pCtx; + if (pTlvLen) { + frameshtons(pCtx, pTlvLen, *pnConsumed - nConsumedOnEntry - 3, 0); + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_tlv_extended_listen_timing. */ + +uint32_t dot11f_pack_tlv_listen_channel(tpAniSirGlobal pCtx, + tDot11fTLVListenChannel *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 8; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + *pBuf = 6; + pBuf += 1; *pnConsumed += 1; + pTlvLen = pBuf; + pBuf += 2; *pnConsumed += 2; + DOT11F_MEMCPY(pCtx, pBuf, pSrc->countryString, 3); + *pnConsumed += 3; + pBuf += 3; + *pBuf = pSrc->regulatoryClass; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->channel; + *pnConsumed += 1; + pBuf += 1; + break; + } + (void)pCtx; + if (pTlvLen) { + frameshtons(pCtx, pTlvLen, *pnConsumed - nConsumedOnEntry - 3, 0); + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_tlv_listen_channel. */ + +uint32_t dot11f_pack_tlv_manufacturer(tpAniSirGlobal pCtx, + tDot11fTLVManufacturer *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += (pSrc->num_name + 4) ; + + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + frameshtons(pCtx, pBuf, 4129, 1); + pBuf += 2; *pnConsumed += 2; + pTlvLen = pBuf; + pBuf += 2; *pnConsumed += 2; + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->name), pSrc->num_name); + *pnConsumed += pSrc->num_name; + pBuf += pSrc->num_name; + break; + } + (void)pCtx; + if (pTlvLen) { + frameshtons(pCtx, pTlvLen, *pnConsumed - nConsumedOnEntry - 4, 1); + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_tlv_manufacturer. */ + +uint32_t dot11f_pack_tlv_minor_reason_code(tpAniSirGlobal pCtx, + tDot11fTLVMinorReasonCode *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 4; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + *pBuf = 1; + pBuf += 1; *pnConsumed += 1; + pTlvLen = pBuf; + pBuf += 2; *pnConsumed += 2; + *pBuf = pSrc->minorReasonCode; + *pnConsumed += 1; + pBuf += 1; + break; + } + (void)pCtx; + if (pTlvLen) { + frameshtons(pCtx, pTlvLen, *pnConsumed - nConsumedOnEntry - 3, 0); + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_tlv_minor_reason_code. */ + +uint32_t dot11f_pack_tlv_model_name(tpAniSirGlobal pCtx, + tDot11fTLVModelName *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += (pSrc->num_text + 4) ; + + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + frameshtons(pCtx, pBuf, 4131, 1); + pBuf += 2; *pnConsumed += 2; + pTlvLen = pBuf; + pBuf += 2; *pnConsumed += 2; + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->text), pSrc->num_text); + *pnConsumed += pSrc->num_text; + pBuf += pSrc->num_text; + break; + } + (void)pCtx; + if (pTlvLen) { + frameshtons(pCtx, pTlvLen, *pnConsumed - nConsumedOnEntry - 4, 1); + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_tlv_model_name. */ + +uint32_t dot11f_pack_tlv_model_number(tpAniSirGlobal pCtx, + tDot11fTLVModelNumber *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += (pSrc->num_text + 4) ; + + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + frameshtons(pCtx, pBuf, 4132, 1); + pBuf += 2; *pnConsumed += 2; + pTlvLen = pBuf; + pBuf += 2; *pnConsumed += 2; + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->text), pSrc->num_text); + *pnConsumed += pSrc->num_text; + pBuf += pSrc->num_text; + break; + } + (void)pCtx; + if (pTlvLen) { + frameshtons(pCtx, pTlvLen, *pnConsumed - nConsumedOnEntry - 4, 1); + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_tlv_model_number. */ + +uint32_t dot11f_pack_tlv_notice_of_absence(tpAniSirGlobal pCtx, + tDot11fTLVNoticeOfAbsence *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += (pSrc->num_NoADesc + 5) ; + + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + *pBuf = 12; + pBuf += 1; *pnConsumed += 1; + pTlvLen = pBuf; + pBuf += 2; *pnConsumed += 2; + *pBuf = pSrc->index; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->CTSWindowOppPS; + *pnConsumed += 1; + pBuf += 1; + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->NoADesc), pSrc->num_NoADesc); + *pnConsumed += pSrc->num_NoADesc; + pBuf += pSrc->num_NoADesc; + break; + } + (void)pCtx; + if (pTlvLen) { + frameshtons(pCtx, pTlvLen, *pnConsumed - nConsumedOnEntry - 3, 0); + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_tlv_notice_of_absence. */ + +uint32_t dot11f_pack_tlv_operating_channel(tpAniSirGlobal pCtx, + tDot11fTLVOperatingChannel *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 8; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + *pBuf = 17; + pBuf += 1; *pnConsumed += 1; + pTlvLen = pBuf; + pBuf += 2; *pnConsumed += 2; + DOT11F_MEMCPY(pCtx, pBuf, pSrc->countryString, 3); + *pnConsumed += 3; + pBuf += 3; + *pBuf = pSrc->regulatoryClass; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->channel; + *pnConsumed += 1; + pBuf += 1; + break; + } + (void)pCtx; + if (pTlvLen) { + frameshtons(pCtx, pTlvLen, *pnConsumed - nConsumedOnEntry - 3, 0); + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_tlv_operating_channel. */ + +uint32_t dot11f_pack_tlv_p2_p_capability(tpAniSirGlobal pCtx, + tDot11fTLVP2PCapability *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 5; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + *pBuf = 2; + pBuf += 1; *pnConsumed += 1; + pTlvLen = pBuf; + pBuf += 2; *pnConsumed += 2; + *pBuf = pSrc->deviceCapability; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->groupCapability; + *pnConsumed += 1; + pBuf += 1; + break; + } + (void)pCtx; + if (pTlvLen) { + frameshtons(pCtx, pTlvLen, *pnConsumed - nConsumedOnEntry - 3, 0); + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_tlv_p2_p_capability. */ + +uint32_t dot11f_pack_tlv_p2_p_device_id(tpAniSirGlobal pCtx, + tDot11fTLVP2PDeviceId *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 9; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + *pBuf = 3; + pBuf += 1; *pnConsumed += 1; + pTlvLen = pBuf; + pBuf += 2; *pnConsumed += 2; + DOT11F_MEMCPY(pCtx, pBuf, pSrc->P2PDeviceAddress, 6); + *pnConsumed += 6; + pBuf += 6; + break; + } + (void)pCtx; + if (pTlvLen) { + frameshtons(pCtx, pTlvLen, *pnConsumed - nConsumedOnEntry - 3, 0); + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_tlv_p2_p_device_id. */ + +uint32_t dot11f_pack_tlv_p2_p_device_info(tpAniSirGlobal pCtx, + tDot11fTLVP2PDeviceInfo *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t status = DOT11F_PARSE_SUCCESS; + uint32_t nNeeded = 0U; + uint32_t idx = 0; + nNeeded += 19; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + *pBuf = 13; + pBuf += 1; nBuf -= 1; *pnConsumed += 1; + pTlvLen = pBuf; + pBuf += 2; nBuf -= 2; *pnConsumed += 2; + DOT11F_MEMCPY(pCtx, pBuf, pSrc->P2PDeviceAddress, 6); + *pnConsumed += 6; + pBuf += 6; + frameshtons(pCtx, pBuf, pSrc->configMethod, 1); + *pnConsumed += 2; + pBuf += 2; + DOT11F_MEMCPY(pCtx, pBuf, pSrc->primaryDeviceType, 8); + *pnConsumed += 8; + pBuf += 8; + status |= pack_tlv_core(pCtx, + (uint8_t *)pSrc, + pBuf, + nBuf, + pnConsumed, + TLVS_P2PDeviceInfo, &idx); + break; + } + (void)pCtx; + if (pTlvLen) { + frameshtons(pCtx, pTlvLen, *pnConsumed - nConsumedOnEntry - 3, 0); + } + return status; +} /* End dot11f_pack_tlv_p2_p_device_info. */ + +uint32_t dot11f_pack_tlv_p2_p_group_info(tpAniSirGlobal pCtx, + tDot11fTLVP2PGroupInfo *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += (pSrc->num_P2PClientInfoDesc + 3) ; + + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + *pBuf = 14; + pBuf += 1; *pnConsumed += 1; + pTlvLen = pBuf; + pBuf += 2; *pnConsumed += 2; + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->P2PClientInfoDesc), pSrc->num_P2PClientInfoDesc); + *pnConsumed += pSrc->num_P2PClientInfoDesc; + pBuf += pSrc->num_P2PClientInfoDesc; + break; + } + (void)pCtx; + if (pTlvLen) { + frameshtons(pCtx, pTlvLen, *pnConsumed - nConsumedOnEntry - 3, 0); + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_tlv_p2_p_group_info. */ + +uint32_t dot11f_pack_tlv_p2_p_status(tpAniSirGlobal pCtx, + tDot11fTLVP2PStatus *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 4; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + *pBuf = 0; + pBuf += 1; *pnConsumed += 1; + pTlvLen = pBuf; + pBuf += 2; *pnConsumed += 2; + *pBuf = pSrc->status; + *pnConsumed += 1; + pBuf += 1; + break; + } + (void)pCtx; + if (pTlvLen) { + frameshtons(pCtx, pTlvLen, *pnConsumed - nConsumedOnEntry - 3, 0); + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_tlv_p2_p_status. */ + +uint32_t dot11f_pack_tlv_primary_device_type(tpAniSirGlobal pCtx, + tDot11fTLVPrimaryDeviceType *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 12; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + frameshtons(pCtx, pBuf, 4180, 1); + pBuf += 2; *pnConsumed += 2; + pTlvLen = pBuf; + pBuf += 2; *pnConsumed += 2; + frameshtons(pCtx, pBuf, pSrc->primary_category, 1); + *pnConsumed += 2; + pBuf += 2; + DOT11F_MEMCPY(pCtx, pBuf, pSrc->oui, 4); + *pnConsumed += 4; + pBuf += 4; + frameshtons(pCtx, pBuf, pSrc->sub_category, 1); + *pnConsumed += 2; + pBuf += 2; + break; + } + (void)pCtx; + if (pTlvLen) { + frameshtons(pCtx, pTlvLen, *pnConsumed - nConsumedOnEntry - 4, 1); + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_tlv_primary_device_type. */ + +uint32_t dot11f_pack_tlv_rf_bands(tpAniSirGlobal pCtx, + tDot11fTLVRFBands *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 5; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + frameshtons(pCtx, pBuf, 4156, 1); + pBuf += 2; *pnConsumed += 2; + pTlvLen = pBuf; + pBuf += 2; *pnConsumed += 2; + *pBuf = pSrc->bands; + *pnConsumed += 1; + pBuf += 1; + break; + } + (void)pCtx; + if (pTlvLen) { + frameshtons(pCtx, pTlvLen, *pnConsumed - nConsumedOnEntry - 4, 1); + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_tlv_rf_bands. */ + +uint32_t dot11f_pack_tlv_request_device_type(tpAniSirGlobal pCtx, + tDot11fTLVRequestDeviceType *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 12; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + frameshtons(pCtx, pBuf, 4202, 1); + pBuf += 2; *pnConsumed += 2; + pTlvLen = pBuf; + pBuf += 2; *pnConsumed += 2; + frameshtons(pCtx, pBuf, pSrc->primary_category, 1); + *pnConsumed += 2; + pBuf += 2; + DOT11F_MEMCPY(pCtx, pBuf, pSrc->oui, 4); + *pnConsumed += 4; + pBuf += 4; + frameshtons(pCtx, pBuf, pSrc->sub_category, 1); + *pnConsumed += 2; + pBuf += 2; + break; + } + (void)pCtx; + if (pTlvLen) { + frameshtons(pCtx, pTlvLen, *pnConsumed - nConsumedOnEntry - 4, 1); + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_tlv_request_device_type. */ + +uint32_t dot11f_pack_tlv_request_type(tpAniSirGlobal pCtx, + tDot11fTLVRequestType *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 5; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + frameshtons(pCtx, pBuf, 4154, 1); + pBuf += 2; *pnConsumed += 2; + pTlvLen = pBuf; + pBuf += 2; *pnConsumed += 2; + *pBuf = pSrc->reqType; + *pnConsumed += 1; + pBuf += 1; + break; + } + (void)pCtx; + if (pTlvLen) { + frameshtons(pCtx, pTlvLen, *pnConsumed - nConsumedOnEntry - 4, 1); + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_tlv_request_type. */ + +uint32_t dot11f_pack_tlv_response_type(tpAniSirGlobal pCtx, + tDot11fTLVResponseType *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 5; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + frameshtons(pCtx, pBuf, 4155, 1); + pBuf += 2; *pnConsumed += 2; + pTlvLen = pBuf; + pBuf += 2; *pnConsumed += 2; + *pBuf = pSrc->resType; + *pnConsumed += 1; + pBuf += 1; + break; + } + (void)pCtx; + if (pTlvLen) { + frameshtons(pCtx, pTlvLen, *pnConsumed - nConsumedOnEntry - 4, 1); + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_tlv_response_type. */ + +uint32_t dot11f_pack_tlv_selected_registrar(tpAniSirGlobal pCtx, + tDot11fTLVSelectedRegistrar *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 5; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + frameshtons(pCtx, pBuf, 4161, 1); + pBuf += 2; *pnConsumed += 2; + pTlvLen = pBuf; + pBuf += 2; *pnConsumed += 2; + *pBuf = pSrc->selected; + *pnConsumed += 1; + pBuf += 1; + break; + } + (void)pCtx; + if (pTlvLen) { + frameshtons(pCtx, pTlvLen, *pnConsumed - nConsumedOnEntry - 4, 1); + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_tlv_selected_registrar. */ + +uint32_t dot11f_pack_tlv_selected_registrar_config_methods(tpAniSirGlobal pCtx, + tDot11fTLVSelectedRegistrarConfigMethods *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 6; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + frameshtons(pCtx, pBuf, 4179, 1); + pBuf += 2; *pnConsumed += 2; + pTlvLen = pBuf; + pBuf += 2; *pnConsumed += 2; + frameshtons(pCtx, pBuf, pSrc->methods, 1); + *pnConsumed += 2; + pBuf += 2; + break; + } + (void)pCtx; + if (pTlvLen) { + frameshtons(pCtx, pTlvLen, *pnConsumed - nConsumedOnEntry - 4, 1); + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_tlv_selected_registrar_config_methods. */ + +uint32_t dot11f_pack_tlv_serial_number(tpAniSirGlobal pCtx, + tDot11fTLVSerialNumber *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += (pSrc->num_text + 4) ; + + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + frameshtons(pCtx, pBuf, 4162, 1); + pBuf += 2; *pnConsumed += 2; + pTlvLen = pBuf; + pBuf += 2; *pnConsumed += 2; + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->text), pSrc->num_text); + *pnConsumed += pSrc->num_text; + pBuf += pSrc->num_text; + break; + } + (void)pCtx; + if (pTlvLen) { + frameshtons(pCtx, pTlvLen, *pnConsumed - nConsumedOnEntry - 4, 1); + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_tlv_serial_number. */ + +uint32_t dot11f_pack_tlv_uuid_e(tpAniSirGlobal pCtx, + tDot11fTLVUUID_E *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 20; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + frameshtons(pCtx, pBuf, 4167, 1); + pBuf += 2; *pnConsumed += 2; + pTlvLen = pBuf; + pBuf += 2; *pnConsumed += 2; + DOT11F_MEMCPY(pCtx, pBuf, pSrc->uuid, 16); + *pnConsumed += 16; + pBuf += 16; + break; + } + (void)pCtx; + if (pTlvLen) { + frameshtons(pCtx, pTlvLen, *pnConsumed - nConsumedOnEntry - 4, 1); + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_tlv_uuid_e. */ + +uint32_t dot11f_pack_tlv_uuid_r(tpAniSirGlobal pCtx, + tDot11fTLVUUID_R *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 20; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + frameshtons(pCtx, pBuf, 4168, 1); + pBuf += 2; *pnConsumed += 2; + pTlvLen = pBuf; + pBuf += 2; *pnConsumed += 2; + DOT11F_MEMCPY(pCtx, pBuf, pSrc->uuid, 16); + *pnConsumed += 16; + pBuf += 16; + break; + } + (void)pCtx; + if (pTlvLen) { + frameshtons(pCtx, pTlvLen, *pnConsumed - nConsumedOnEntry - 4, 1); + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_tlv_uuid_r. */ + +uint32_t dot11f_pack_tlv_vendor_extension(tpAniSirGlobal pCtx, + tDot11fTLVVendorExtension *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t status = DOT11F_PARSE_SUCCESS; + uint32_t nNeeded = 0U; + uint32_t idx = 0; + nNeeded += 7; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + frameshtons(pCtx, pBuf, 4169, 1); + pBuf += 2; nBuf -= 2; *pnConsumed += 2; + pTlvLen = pBuf; + pBuf += 2; nBuf -= 2; *pnConsumed += 2; + DOT11F_MEMCPY(pCtx, pBuf, pSrc->vendorId, 3); + *pnConsumed += 3; + pBuf += 3; + status |= pack_tlv_core(pCtx, + (uint8_t *)pSrc, + pBuf, + nBuf, + pnConsumed, + TLVS_VendorExtension, &idx); + break; + } + (void)pCtx; + if (pTlvLen) { + frameshtons(pCtx, pTlvLen, *pnConsumed - nConsumedOnEntry - 4, 1); + } + return status; +} /* End dot11f_pack_tlv_vendor_extension. */ + +uint32_t dot11f_pack_tlv_version(tpAniSirGlobal pCtx, + tDot11fTLVVersion *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint8_t tmp76__; + nNeeded += 5; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + frameshtons(pCtx, pBuf, 4170, 1); + pBuf += 2; *pnConsumed += 2; + pTlvLen = pBuf; + pBuf += 2; *pnConsumed += 2; + tmp76__ = 0U; + tmp76__ |= (pSrc->minor << 0); + tmp76__ |= (pSrc->major << 4); + *pBuf = tmp76__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + break; + } + (void)pCtx; + if (pTlvLen) { + frameshtons(pCtx, pTlvLen, *pnConsumed - nConsumedOnEntry - 4, 1); + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_tlv_version. */ + +uint32_t dot11f_pack_tlv_wps_state(tpAniSirGlobal pCtx, + tDot11fTLVWPSState *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 5; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + frameshtons(pCtx, pBuf, 4164, 1); + pBuf += 2; *pnConsumed += 2; + pTlvLen = pBuf; + pBuf += 2; *pnConsumed += 2; + *pBuf = pSrc->state; + *pnConsumed += 1; + pBuf += 1; + break; + } + (void)pCtx; + if (pTlvLen) { + frameshtons(pCtx, pTlvLen, *pnConsumed - nConsumedOnEntry - 4, 1); + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_tlv_wps_state. */ + +uint32_t dot11f_pack_tlv_p2_p_interface(tpAniSirGlobal pCtx, + tDot11fTLVP2PInterface *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 9; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + *pBuf = 16; + pBuf += 1; *pnConsumed += 1; + pTlvLen = pBuf; + pBuf += 2; *pnConsumed += 2; + DOT11F_MEMCPY(pCtx, pBuf, pSrc->P2PDeviceAddress, 6); + *pnConsumed += 6; + pBuf += 6; + break; + } + (void)pCtx; + if (pTlvLen) { + frameshtons(pCtx, pTlvLen, *pnConsumed - nConsumedOnEntry - 3, 0); + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_tlv_p2_p_interface. */ + +uint32_t dot11f_pack_tlv_p2_p_manageability(tpAniSirGlobal pCtx, + tDot11fTLVP2PManageability *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 4; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + *pBuf = 10; + pBuf += 1; *pnConsumed += 1; + pTlvLen = pBuf; + pBuf += 2; *pnConsumed += 2; + *pBuf = pSrc->manageability; + *pnConsumed += 1; + pBuf += 1; + break; + } + (void)pCtx; + if (pTlvLen) { + frameshtons(pCtx, pTlvLen, *pnConsumed - nConsumedOnEntry - 3, 0); + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_tlv_p2_p_manageability. */ + +uint32_t dot11f_pack_ie_gtk(tpAniSirGlobal pCtx, + tDot11fIEGTK *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint16_t tmp77__; + nNeeded += (pSrc->num_key + 11); + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 2; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + tmp77__ = 0U; + tmp77__ |= (pSrc->keyId << 0); + tmp77__ |= (pSrc->reserved << 2); + frameshtons(pCtx, pBuf, tmp77__, 0); + *pnConsumed += 2; + pBuf += 2; + nBuf -= 2 ; + *pBuf = pSrc->keyLength; + *pnConsumed += 1; + pBuf += 1; + DOT11F_MEMCPY(pCtx, pBuf, pSrc->RSC, 8); + *pnConsumed += 8; + pBuf += 8; + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->key), pSrc->num_key); + *pnConsumed += pSrc->num_key; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_gtk. */ + +uint32_t dot11f_pack_ie_igtk(tpAniSirGlobal pCtx, + tDot11fIEIGTK *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 33; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 4; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + DOT11F_MEMCPY(pCtx, pBuf, pSrc->keyID, 2); + *pnConsumed += 2; + pBuf += 2; + DOT11F_MEMCPY(pCtx, pBuf, pSrc->IPN, 6); + *pnConsumed += 6; + pBuf += 6; + *pBuf = pSrc->keyLength; + *pnConsumed += 1; + pBuf += 1; + DOT11F_MEMCPY(pCtx, pBuf, pSrc->key, 24); + *pnConsumed += 24; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_igtk. */ + +uint32_t dot11f_pack_ie_r0_kh_id(tpAniSirGlobal pCtx, + tDot11fIER0KH_ID *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += pSrc->num_PMK_R0_ID; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 3; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->PMK_R0_ID), pSrc->num_PMK_R0_ID); + *pnConsumed += pSrc->num_PMK_R0_ID; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_r0_kh_id. */ + +uint32_t dot11f_pack_ie_r1_kh_id(tpAniSirGlobal pCtx, + tDot11fIER1KH_ID *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 6; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 1; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + DOT11F_MEMCPY(pCtx, pBuf, pSrc->PMK_R1_ID, 6); + *pnConsumed += 6; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_r1_kh_id. */ + +uint32_t dot11f_pack_ie_ap_channel_report(tpAniSirGlobal pCtx, + tDot11fIEAPChannelReport *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += (pSrc->num_channelList + 1); + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 51; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->regulatoryClass; + *pnConsumed += 1; + pBuf += 1; + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->channelList), pSrc->num_channelList); + *pnConsumed += pSrc->num_channelList; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_ap_channel_report. */ + +uint32_t dot11f_pack_ie_bcn_reporting_detail(tpAniSirGlobal pCtx, + tDot11fIEBcnReportingDetail *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 1; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 2; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->reportingDetail; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_bcn_reporting_detail. */ + +uint32_t dot11f_pack_ie_beacon_report_frm_body(tpAniSirGlobal pCtx, + tDot11fIEBeaconReportFrmBody *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += pSrc->num_reportedFields; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 1; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->reportedFields), pSrc->num_reportedFields); + *pnConsumed += pSrc->num_reportedFields; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_beacon_report_frm_body. */ + +uint32_t dot11f_pack_ie_beacon_reporting(tpAniSirGlobal pCtx, + tDot11fIEBeaconReporting *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 2; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 1; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->reportingCondition; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->threshold; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_beacon_reporting. */ + +uint32_t dot11f_pack_ie_condensed_country_str(tpAniSirGlobal pCtx, + tDot11fIECondensedCountryStr *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 2; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 2; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + DOT11F_MEMCPY(pCtx, pBuf, pSrc->countryStr, 2); + *pnConsumed += 2; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_condensed_country_str. */ + +uint32_t dot11f_pack_ie_measurement_pilot(tpAniSirGlobal pCtx, + tDot11fIEMeasurementPilot *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += (pSrc->num_vendorSpecific + 1); + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 66; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->measurementPilot; + *pnConsumed += 1; + pBuf += 1; + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->vendorSpecific), pSrc->num_vendorSpecific); + *pnConsumed += pSrc->num_vendorSpecific; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_measurement_pilot. */ + +uint32_t dot11f_pack_ie_multi_bssid(tpAniSirGlobal pCtx, + tDot11fIEMultiBssid *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += (pSrc->num_vendorSpecific + 1); + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 71; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->maxBSSIDIndicator; + *pnConsumed += 1; + pBuf += 1; + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->vendorSpecific), pSrc->num_vendorSpecific); + *pnConsumed += pSrc->num_vendorSpecific; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_multi_bssid. */ + +uint32_t dot11f_pack_ie_ric_data(tpAniSirGlobal pCtx, + tDot11fIERICData *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 4; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 57; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->Identifier; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->resourceDescCount; + *pnConsumed += 1; + pBuf += 1; + frameshtons(pCtx, pBuf, pSrc->statusCode, 0); + *pnConsumed += 2; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_ric_data. */ + +uint32_t dot11f_pack_ie_ric_descriptor(tpAniSirGlobal pCtx, + tDot11fIERICDescriptor *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += (pSrc->num_variableData + 1); + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 75; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->resourceType; + *pnConsumed += 1; + pBuf += 1; + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->variableData), pSrc->num_variableData); + *pnConsumed += pSrc->num_variableData; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_ric_descriptor. */ + +uint32_t dot11f_pack_ie_rrm_enabled_cap(tpAniSirGlobal pCtx, + tDot11fIERRMEnabledCap *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint8_t tmp78__; + uint8_t tmp79__; + uint8_t tmp80__; + uint8_t tmp81__; + uint8_t tmp82__; + nNeeded += 5; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 70; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + tmp78__ = 0U; + tmp78__ |= (pSrc->LinkMeasurement << 0); + tmp78__ |= (pSrc->NeighborRpt << 1); + tmp78__ |= (pSrc->parallel << 2); + tmp78__ |= (pSrc->repeated << 3); + tmp78__ |= (pSrc->BeaconPassive << 4); + tmp78__ |= (pSrc->BeaconActive << 5); + tmp78__ |= (pSrc->BeaconTable << 6); + tmp78__ |= (pSrc->BeaconRepCond << 7); + *pBuf = tmp78__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + tmp79__ = 0U; + tmp79__ |= (pSrc->FrameMeasurement << 0); + tmp79__ |= (pSrc->ChannelLoad << 1); + tmp79__ |= (pSrc->NoiseHistogram << 2); + tmp79__ |= (pSrc->statistics << 3); + tmp79__ |= (pSrc->LCIMeasurement << 4); + tmp79__ |= (pSrc->LCIAzimuth << 5); + tmp79__ |= (pSrc->TCMCapability << 6); + tmp79__ |= (pSrc->triggeredTCM << 7); + *pBuf = tmp79__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + tmp80__ = 0U; + tmp80__ |= (pSrc->APChanReport << 0); + tmp80__ |= (pSrc->RRMMIBEnabled << 1); + tmp80__ |= (pSrc->operatingChanMax << 2); + tmp80__ |= (pSrc->nonOperatinChanMax << 5); + *pBuf = tmp80__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + tmp81__ = 0U; + tmp81__ |= (pSrc->MeasurementPilot << 0); + tmp81__ |= (pSrc->MeasurementPilotEnabled << 3); + tmp81__ |= (pSrc->NeighborTSFOffset << 4); + tmp81__ |= (pSrc->RCPIMeasurement << 5); + tmp81__ |= (pSrc->RSNIMeasurement << 6); + tmp81__ |= (pSrc->BssAvgAccessDelay << 7); + *pBuf = tmp81__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + tmp82__ = 0U; + tmp82__ |= (pSrc->BSSAvailAdmission << 0); + tmp82__ |= (pSrc->AntennaInformation << 1); + tmp82__ |= (pSrc->fine_time_meas_rpt << 2); + tmp82__ |= (pSrc->lci_capability << 3); + tmp82__ |= (pSrc->reserved << 4); + *pBuf = tmp82__; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + nBuf -= 1 ; + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_rrm_enabled_cap. */ + +uint32_t dot11f_pack_ie_requested_info(tpAniSirGlobal pCtx, + tDot11fIERequestedInfo *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += pSrc->num_requested_eids; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 10; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->requested_eids), pSrc->num_requested_eids); + *pnConsumed += pSrc->num_requested_eids; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_requested_info. */ + +uint32_t dot11f_pack_ie_ssid(tpAniSirGlobal pCtx, + tDot11fIESSID *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += pSrc->num_ssid; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 0; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->ssid), pSrc->num_ssid); + *pnConsumed += pSrc->num_ssid; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_ssid. */ + +uint32_t dot11f_pack_ie_schedule(tpAniSirGlobal pCtx, + tDot11fIESchedule *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint16_t tmp83__; + nNeeded += 14; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 15; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + tmp83__ = 0U; + tmp83__ |= (pSrc->aggregation << 0); + tmp83__ |= (pSrc->tsid << 1); + tmp83__ |= (pSrc->direction << 5); + tmp83__ |= (pSrc->reserved << 7); + frameshtons(pCtx, pBuf, tmp83__, 0); + *pnConsumed += 2; + pBuf += 2; + nBuf -= 2 ; + frameshtonl(pCtx, pBuf, pSrc->service_start_time, 0); + *pnConsumed += 4; + pBuf += 4; + frameshtonl(pCtx, pBuf, pSrc->service_interval, 0); + *pnConsumed += 4; + pBuf += 4; + frameshtons(pCtx, pBuf, pSrc->max_service_dur, 0); + *pnConsumed += 2; + pBuf += 2; + frameshtons(pCtx, pBuf, pSrc->spec_interval, 0); + *pnConsumed += 2; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_schedule. */ + +uint32_t dot11f_pack_ie_tclas(tpAniSirGlobal pCtx, + tDot11fIETCLAS *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint32_t status = DOT11F_PARSE_SUCCESS; + status = dot11f_get_packed_ietclas(pCtx, pSrc, &nNeeded); + if (!DOT11F_SUCCEEDED(status)) + return status; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 14; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->user_priority; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->classifier_type; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->classifier_mask; + *pnConsumed += 1; + pBuf += 1; + switch (pSrc->classifier_type) { + case 0: + DOT11F_MEMCPY(pCtx, pBuf, pSrc->info.EthParams.source, 6); + *pnConsumed += 6; + pBuf += 6; + DOT11F_MEMCPY(pCtx, pBuf, pSrc->info.EthParams.dest, 6); + *pnConsumed += 6; + pBuf += 6; + frameshtons(pCtx, pBuf, pSrc->info.EthParams.type, 0); + *pnConsumed += 2; + /* fieldsEndFlag = 1 */ + break; + case 1: + *pBuf = pSrc->info.IpParams.version; + *pnConsumed += 1; + pBuf += 1; + switch (pSrc->info.IpParams.version) { + case 4: + DOT11F_MEMCPY(pCtx, pBuf, pSrc->info.IpParams.params.IpV4Params.source, 4); + *pnConsumed += 4; + pBuf += 4; + DOT11F_MEMCPY(pCtx, pBuf, pSrc->info.IpParams.params.IpV4Params.dest, 4); + *pnConsumed += 4; + pBuf += 4; + frameshtons(pCtx, pBuf, pSrc->info.IpParams.params.IpV4Params.src_port, 0); + *pnConsumed += 2; + pBuf += 2; + frameshtons(pCtx, pBuf, pSrc->info.IpParams.params.IpV4Params.dest_port, 0); + *pnConsumed += 2; + pBuf += 2; + *pBuf = pSrc->info.IpParams.params.IpV4Params.DSCP; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->info.IpParams.params.IpV4Params.proto; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->info.IpParams.params.IpV4Params.reserved; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + break; + case 6: + DOT11F_MEMCPY(pCtx, pBuf, pSrc->info.IpParams.params.IpV6Params.source, 16); + *pnConsumed += 16; + pBuf += 16; + DOT11F_MEMCPY(pCtx, pBuf, pSrc->info.IpParams.params.IpV6Params.dest, 16); + *pnConsumed += 16; + pBuf += 16; + frameshtons(pCtx, pBuf, pSrc->info.IpParams.params.IpV6Params.src_port, 0); + *pnConsumed += 2; + pBuf += 2; + frameshtons(pCtx, pBuf, pSrc->info.IpParams.params.IpV6Params.dest_port, 0); + *pnConsumed += 2; + pBuf += 2; + DOT11F_MEMCPY(pCtx, pBuf, pSrc->info.IpParams.params.IpV6Params.flow_label, 3); + *pnConsumed += 3; + /* fieldsEndFlag = 1 */ + break; + } + break; + case 2: + frameshtons(pCtx, pBuf, pSrc->info.Params8021dq.tag_type, 0); + *pnConsumed += 2; + /* fieldsEndFlag = 1 */ + break; + } + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return status; +} /* End dot11f_pack_ie_tclas. */ + +uint32_t dot11f_pack_ie_tclassproc(tpAniSirGlobal pCtx, + tDot11fIETCLASSPROC *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 1; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 44; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->processing; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_tclassproc. */ + +uint32_t dot11f_pack_ie_ts_delay(tpAniSirGlobal pCtx, + tDot11fIETSDelay *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 4; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 43; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + frameshtonl(pCtx, pBuf, pSrc->delay, 0); + *pnConsumed += 4; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_ts_delay. */ + +uint32_t dot11f_pack_ie_tsf_info(tpAniSirGlobal pCtx, + tDot11fIETSFInfo *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 4; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 1; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + frameshtons(pCtx, pBuf, pSrc->TsfOffset, 0); + *pnConsumed += 2; + pBuf += 2; + frameshtons(pCtx, pBuf, pSrc->BeaconIntvl, 0); + *pnConsumed += 2; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_tsf_info. */ + +uint32_t dot11f_pack_ie_tspec(tpAniSirGlobal pCtx, + tDot11fIETSPEC *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint16_t tmp84__; + uint8_t tmp85__; + uint16_t tmp86__; + nNeeded += 55; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 13; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + tmp84__ = 0U; + tmp84__ |= (pSrc->traffic_type << 0); + tmp84__ |= (pSrc->tsid << 1); + tmp84__ |= (pSrc->direction << 5); + tmp84__ |= (pSrc->access_policy << 7); + tmp84__ |= (pSrc->aggregation << 9); + tmp84__ |= (pSrc->psb << 10); + tmp84__ |= (pSrc->user_priority << 11); + tmp84__ |= (pSrc->tsinfo_ack_pol << 14); + frameshtons(pCtx, pBuf, tmp84__, 0); + *pnConsumed += 2; + pBuf += 2; + nBuf -= 2 ; + tmp85__ = 0U; + tmp85__ |= (pSrc->schedule << 0); + tmp85__ |= (pSrc->unused << 1); + *pBuf = tmp85__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + tmp86__ = 0U; + tmp86__ |= (pSrc->size << 0); + tmp86__ |= (pSrc->fixed << 15); + frameshtons(pCtx, pBuf, tmp86__, 0); + *pnConsumed += 2; + pBuf += 2; + nBuf -= 2 ; + frameshtons(pCtx, pBuf, pSrc->max_msdu_size, 0); + *pnConsumed += 2; + pBuf += 2; + frameshtonl(pCtx, pBuf, pSrc->min_service_int, 0); + *pnConsumed += 4; + pBuf += 4; + frameshtonl(pCtx, pBuf, pSrc->max_service_int, 0); + *pnConsumed += 4; + pBuf += 4; + frameshtonl(pCtx, pBuf, pSrc->inactivity_int, 0); + *pnConsumed += 4; + pBuf += 4; + frameshtonl(pCtx, pBuf, pSrc->suspension_int, 0); + *pnConsumed += 4; + pBuf += 4; + frameshtonl(pCtx, pBuf, pSrc->service_start_time, 0); + *pnConsumed += 4; + pBuf += 4; + frameshtonl(pCtx, pBuf, pSrc->min_data_rate, 0); + *pnConsumed += 4; + pBuf += 4; + frameshtonl(pCtx, pBuf, pSrc->mean_data_rate, 0); + *pnConsumed += 4; + pBuf += 4; + frameshtonl(pCtx, pBuf, pSrc->peak_data_rate, 0); + *pnConsumed += 4; + pBuf += 4; + frameshtonl(pCtx, pBuf, pSrc->burst_size, 0); + *pnConsumed += 4; + pBuf += 4; + frameshtonl(pCtx, pBuf, pSrc->delay_bound, 0); + *pnConsumed += 4; + pBuf += 4; + frameshtonl(pCtx, pBuf, pSrc->min_phy_rate, 0); + *pnConsumed += 4; + pBuf += 4; + frameshtons(pCtx, pBuf, pSrc->surplus_bw_allowance, 0); + *pnConsumed += 2; + pBuf += 2; + frameshtons(pCtx, pBuf, pSrc->medium_time, 0); + *pnConsumed += 2; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_tspec. */ + +uint32_t dot11f_pack_ie_vht_caps(tpAniSirGlobal pCtx, + tDot11fIEVHTCaps *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint32_t tmp87__; + uint16_t tmp88__; + uint16_t tmp89__; + nNeeded += 12; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 191; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + tmp87__ = 0U; + tmp87__ |= (pSrc->maxMPDULen << 0); + tmp87__ |= (pSrc->supportedChannelWidthSet << 2); + tmp87__ |= (pSrc->ldpcCodingCap << 4); + tmp87__ |= (pSrc->shortGI80MHz << 5); + tmp87__ |= (pSrc->shortGI160and80plus80MHz << 6); + tmp87__ |= (pSrc->txSTBC << 7); + tmp87__ |= (pSrc->rxSTBC << 8); + tmp87__ |= (pSrc->suBeamFormerCap << 11); + tmp87__ |= (pSrc->suBeamformeeCap << 12); + tmp87__ |= (pSrc->csnofBeamformerAntSup << 13); + tmp87__ |= (pSrc->numSoundingDim << 16); + tmp87__ |= (pSrc->muBeamformerCap << 19); + tmp87__ |= (pSrc->muBeamformeeCap << 20); + tmp87__ |= (pSrc->vhtTXOPPS << 21); + tmp87__ |= (pSrc->htcVHTCap << 22); + tmp87__ |= (pSrc->maxAMPDULenExp << 23); + tmp87__ |= (pSrc->vhtLinkAdaptCap << 26); + tmp87__ |= (pSrc->rxAntPattern << 28); + tmp87__ |= (pSrc->txAntPattern << 29); + tmp87__ |= (pSrc->reserved1 << 30); + frameshtonl(pCtx, pBuf, tmp87__, 0); + *pnConsumed += 4; + pBuf += 4; + nBuf -= 4 ; + frameshtons(pCtx, pBuf, pSrc->rxMCSMap, 0); + *pnConsumed += 2; + pBuf += 2; + tmp88__ = 0U; + tmp88__ |= (pSrc->rxHighSupDataRate << 0); + tmp88__ |= (pSrc->reserved2 << 13); + frameshtons(pCtx, pBuf, tmp88__, 0); + *pnConsumed += 2; + pBuf += 2; + nBuf -= 2 ; + frameshtons(pCtx, pBuf, pSrc->txMCSMap, 0); + *pnConsumed += 2; + pBuf += 2; + tmp89__ = 0U; + tmp89__ |= (pSrc->txSupDataRate << 0); + tmp89__ |= (pSrc->reserved3 << 13); + frameshtons(pCtx, pBuf, tmp89__, 0); + *pnConsumed += 2; + /* fieldsEndFlag = 1 */ + nBuf -= 2 ; + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_vht_caps. */ + +uint32_t dot11f_pack_ie_vht_operation(tpAniSirGlobal pCtx, + tDot11fIEVHTOperation *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 5; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 192; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->chanWidth; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->chanCenterFreqSeg1; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->chanCenterFreqSeg2; + *pnConsumed += 1; + pBuf += 1; + frameshtons(pCtx, pBuf, pSrc->basicMCSSet, 0); + *pnConsumed += 2; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_vht_operation. */ + +uint32_t dot11f_pack_ie_wmm_schedule(tpAniSirGlobal pCtx, + tDot11fIEWMMSchedule *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint16_t tmp90__; + nNeeded += 15; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 221; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x0; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x50; + ++pBuf; ++(*pnConsumed); + *pBuf = 0xf2; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x2; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x9; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->version; + *pnConsumed += 1; + pBuf += 1; + tmp90__ = 0U; + tmp90__ |= (pSrc->aggregation << 0); + tmp90__ |= (pSrc->tsid << 1); + tmp90__ |= (pSrc->direction << 5); + tmp90__ |= (pSrc->reserved << 7); + frameshtons(pCtx, pBuf, tmp90__, 0); + *pnConsumed += 2; + pBuf += 2; + nBuf -= 2 ; + frameshtonl(pCtx, pBuf, pSrc->service_start_time, 0); + *pnConsumed += 4; + pBuf += 4; + frameshtonl(pCtx, pBuf, pSrc->service_interval, 0); + *pnConsumed += 4; + pBuf += 4; + frameshtons(pCtx, pBuf, pSrc->max_service_dur, 0); + *pnConsumed += 2; + pBuf += 2; + frameshtons(pCtx, pBuf, pSrc->spec_interval, 0); + *pnConsumed += 2; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_wmm_schedule. */ + +uint32_t dot11f_pack_ie_wmmtclas(tpAniSirGlobal pCtx, + tDot11fIEWMMTCLAS *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint32_t status = DOT11F_PARSE_SUCCESS; + status = dot11f_get_packed_iewmmtclas(pCtx, pSrc, &nNeeded); + if (!DOT11F_SUCCEEDED(status)) + return status; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 221; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x0; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x50; + ++pBuf; ++(*pnConsumed); + *pBuf = 0xf2; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x2; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x6; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->version; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->user_priority; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->classifier_type; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->classifier_mask; + *pnConsumed += 1; + pBuf += 1; + switch (pSrc->classifier_type) { + case 0: + DOT11F_MEMCPY(pCtx, pBuf, pSrc->info.EthParams.source, 6); + *pnConsumed += 6; + pBuf += 6; + DOT11F_MEMCPY(pCtx, pBuf, pSrc->info.EthParams.dest, 6); + *pnConsumed += 6; + pBuf += 6; + frameshtons(pCtx, pBuf, pSrc->info.EthParams.type, 0); + *pnConsumed += 2; + /* fieldsEndFlag = 1 */ + break; + case 1: + *pBuf = pSrc->info.IpParams.version; + *pnConsumed += 1; + pBuf += 1; + switch (pSrc->info.IpParams.version) { + case 4: + DOT11F_MEMCPY(pCtx, pBuf, pSrc->info.IpParams.params.IpV4Params.source, 4); + *pnConsumed += 4; + pBuf += 4; + DOT11F_MEMCPY(pCtx, pBuf, pSrc->info.IpParams.params.IpV4Params.dest, 4); + *pnConsumed += 4; + pBuf += 4; + frameshtons(pCtx, pBuf, pSrc->info.IpParams.params.IpV4Params.src_port, 0); + *pnConsumed += 2; + pBuf += 2; + frameshtons(pCtx, pBuf, pSrc->info.IpParams.params.IpV4Params.dest_port, 0); + *pnConsumed += 2; + pBuf += 2; + *pBuf = pSrc->info.IpParams.params.IpV4Params.DSCP; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->info.IpParams.params.IpV4Params.proto; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->info.IpParams.params.IpV4Params.reserved; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + break; + case 6: + DOT11F_MEMCPY(pCtx, pBuf, pSrc->info.IpParams.params.IpV6Params.source, 10); + *pnConsumed += 10; + pBuf += 10; + DOT11F_MEMCPY(pCtx, pBuf, pSrc->info.IpParams.params.IpV6Params.dest, 10); + *pnConsumed += 10; + pBuf += 10; + frameshtons(pCtx, pBuf, pSrc->info.IpParams.params.IpV6Params.src_port, 0); + *pnConsumed += 2; + pBuf += 2; + frameshtons(pCtx, pBuf, pSrc->info.IpParams.params.IpV6Params.dest_port, 0); + *pnConsumed += 2; + pBuf += 2; + DOT11F_MEMCPY(pCtx, pBuf, pSrc->info.IpParams.params.IpV6Params.flow_label, 3); + *pnConsumed += 3; + /* fieldsEndFlag = 1 */ + break; + } + break; + case 2: + frameshtons(pCtx, pBuf, pSrc->info.Params8021dq.tag_type, 0); + *pnConsumed += 2; + /* fieldsEndFlag = 1 */ + break; + } + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return status; +} /* End dot11f_pack_ie_wmmtclas. */ + +uint32_t dot11f_pack_ie_wmmtclasproc(tpAniSirGlobal pCtx, + tDot11fIEWMMTCLASPROC *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 2; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 221; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x0; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x50; + ++pBuf; ++(*pnConsumed); + *pBuf = 0xf2; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x2; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x7; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->version; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->processing; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_wmmtclasproc. */ + +uint32_t dot11f_pack_ie_wmmts_delay(tpAniSirGlobal pCtx, + tDot11fIEWMMTSDelay *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 5; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 221; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x0; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x50; + ++pBuf; ++(*pnConsumed); + *pBuf = 0xf2; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x2; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x8; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->version; + *pnConsumed += 1; + pBuf += 1; + frameshtonl(pCtx, pBuf, pSrc->delay, 0); + *pnConsumed += 4; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_wmmts_delay. */ + +uint32_t dot11f_pack_ie_wmmtspec(tpAniSirGlobal pCtx, + tDot11fIEWMMTSPEC *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint16_t tmp91__; + uint8_t tmp92__; + uint16_t tmp93__; + nNeeded += 38; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 221; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x0; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x50; + ++pBuf; ++(*pnConsumed); + *pBuf = 0xf2; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x2; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x2; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->version; + *pnConsumed += 1; + pBuf += 1; + tmp91__ = 0U; + tmp91__ |= (pSrc->traffic_type << 0); + tmp91__ |= (pSrc->tsid << 1); + tmp91__ |= (pSrc->direction << 5); + tmp91__ |= (pSrc->access_policy << 7); + tmp91__ |= (pSrc->aggregation << 9); + tmp91__ |= (pSrc->psb << 10); + tmp91__ |= (pSrc->user_priority << 11); + tmp91__ |= (pSrc->tsinfo_ack_pol << 14); + frameshtons(pCtx, pBuf, tmp91__, 0); + *pnConsumed += 2; + pBuf += 2; + nBuf -= 2 ; + tmp92__ = 0U; + tmp92__ |= (pSrc->tsinfo_rsvd << 0); + tmp92__ |= (pSrc->burst_size_defn << 7); + *pBuf = tmp92__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + tmp93__ = 0U; + tmp93__ |= (pSrc->size << 0); + tmp93__ |= (pSrc->fixed << 15); + frameshtons(pCtx, pBuf, tmp93__, 0); + *pnConsumed += 2; + pBuf += 2; + nBuf -= 2 ; + frameshtons(pCtx, pBuf, pSrc->max_msdu_size, 0); + *pnConsumed += 2; + pBuf += 2; + frameshtonl(pCtx, pBuf, pSrc->min_service_int, 0); + *pnConsumed += 4; + pBuf += 4; + frameshtonl(pCtx, pBuf, pSrc->max_service_int, 0); + *pnConsumed += 4; + pBuf += 4; + frameshtonl(pCtx, pBuf, pSrc->inactivity_int, 0); + *pnConsumed += 4; + pBuf += 4; + frameshtonl(pCtx, pBuf, pSrc->suspension_int, 0); + *pnConsumed += 4; + pBuf += 4; + frameshtonl(pCtx, pBuf, pSrc->service_start_time, 0); + *pnConsumed += 4; + pBuf += 4; + frameshtonl(pCtx, pBuf, pSrc->min_data_rate, 0); + *pnConsumed += 4; + pBuf += 4; + frameshtonl(pCtx, pBuf, pSrc->mean_data_rate, 0); + *pnConsumed += 4; + pBuf += 4; + frameshtonl(pCtx, pBuf, pSrc->peak_data_rate, 0); + *pnConsumed += 4; + pBuf += 4; + frameshtonl(pCtx, pBuf, pSrc->burst_size, 0); + *pnConsumed += 4; + pBuf += 4; + frameshtonl(pCtx, pBuf, pSrc->delay_bound, 0); + *pnConsumed += 4; + pBuf += 4; + frameshtonl(pCtx, pBuf, pSrc->min_phy_rate, 0); + *pnConsumed += 4; + pBuf += 4; + frameshtons(pCtx, pBuf, pSrc->surplus_bw_allowance, 0); + *pnConsumed += 2; + pBuf += 2; + frameshtons(pCtx, pBuf, pSrc->medium_time, 0); + *pnConsumed += 2; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_wmmtspec. */ + +uint32_t dot11f_pack_ie_wider_bw_chan_switch_ann(tpAniSirGlobal pCtx, + tDot11fIEWiderBWChanSwitchAnn *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 3; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 194; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->newChanWidth; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->newCenterChanFreq0; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->newCenterChanFreq1; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_wider_bw_chan_switch_ann. */ + +uint32_t dot11f_pack_ie_azimuth_req(tpAniSirGlobal pCtx, + tDot11fIEazimuth_req *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 1; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 1; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->request; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_azimuth_req. */ + +uint32_t dot11f_pack_ie_max_age(tpAniSirGlobal pCtx, + tDot11fIEmax_age *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 2; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 4; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + frameshtons(pCtx, pBuf, pSrc->max_age, 0); + *pnConsumed += 2; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_max_age. */ + +uint32_t dot11f_pack_ie_neighbor_rpt(tpAniSirGlobal pCtx, + tDot11fIEneighbor_rpt *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint8_t tmp94__; + uint8_t tmp95__; + uint32_t status = DOT11F_PARSE_SUCCESS; + status = dot11f_get_packed_ie_neighbor_rpt(pCtx, pSrc, &nNeeded); + if (!DOT11F_SUCCEEDED(status)) + return status; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 52; + ++pBuf; --nBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; --nBuf; ++(*pnConsumed); + DOT11F_MEMCPY(pCtx, pBuf, pSrc->bssid, 6); + *pnConsumed += 6; + pBuf += 6; + tmp94__ = 0U; + tmp94__ |= (pSrc->APReachability << 0); + tmp94__ |= (pSrc->Security << 2); + tmp94__ |= (pSrc->KeyScope << 3); + tmp94__ |= (pSrc->SpecMgmtCap << 4); + tmp94__ |= (pSrc->QosCap << 5); + tmp94__ |= (pSrc->apsd << 6); + tmp94__ |= (pSrc->rrm << 7); + *pBuf = tmp94__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + tmp95__ = 0U; + tmp95__ |= (pSrc->DelayedBA << 0); + tmp95__ |= (pSrc->ImmBA << 1); + tmp95__ |= (pSrc->MobilityDomain << 2); + tmp95__ |= (pSrc->reserved << 3); + *pBuf = tmp95__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + frameshtons(pCtx, pBuf, pSrc->reserved1, 0); + *pnConsumed += 2; + pBuf += 2; + *pBuf = pSrc->regulatoryClass; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->channel; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->PhyType; + *pnConsumed += 1; + pBuf += 1; + status = pack_core(pCtx, + (uint8_t *)pSrc, + pBuf, + nBuf, + pnConsumed, + FFS_neighbor_rpt, + IES_neighbor_rpt); + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return status; +} /* End dot11f_pack_ie_neighbor_rpt. */ + +uint32_t dot11f_pack_ie_req_mac_addr(tpAniSirGlobal pCtx, + tDot11fIEreq_mac_addr *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 6; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 2; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + DOT11F_MEMCPY(pCtx, pBuf, pSrc->addr, 6); + *pnConsumed += 6; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_req_mac_addr. */ + +uint32_t dot11f_pack_ie_tgt_mac_addr(tpAniSirGlobal pCtx, + tDot11fIEtgt_mac_addr *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 6; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 3; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + DOT11F_MEMCPY(pCtx, pBuf, pSrc->addr, 6); + *pnConsumed += 6; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_tgt_mac_addr. */ + +uint32_t dot11f_pack_ie_vht_transmit_power_env(tpAniSirGlobal pCtx, + tDot11fIEvht_transmit_power_env *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += pSrc->num_bytes; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 195; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->bytes), pSrc->num_bytes); + *pnConsumed += pSrc->num_bytes; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_vht_transmit_power_env. */ + +uint32_t dot11f_pack_ie_aid(tpAniSirGlobal pCtx, + tDot11fIEAID *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 2; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 197; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + frameshtons(pCtx, pBuf, pSrc->assocId, 0); + *pnConsumed += 2; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_aid. */ + +uint32_t dot11f_pack_ie_cf_params(tpAniSirGlobal pCtx, + tDot11fIECFParams *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 6; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 4; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->cfp_count; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->cfp_period; + *pnConsumed += 1; + pBuf += 1; + frameshtons(pCtx, pBuf, pSrc->cfp_maxduration, 0); + *pnConsumed += 2; + pBuf += 2; + frameshtons(pCtx, pBuf, pSrc->cfp_durremaining, 0); + *pnConsumed += 2; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_cf_params. */ + +uint32_t dot11f_pack_ie_challenge_text(tpAniSirGlobal pCtx, + tDot11fIEChallengeText *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += pSrc->num_text; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 16; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->text), pSrc->num_text); + *pnConsumed += pSrc->num_text; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_challenge_text. */ + +uint32_t dot11f_pack_ie_chan_switch_ann(tpAniSirGlobal pCtx, + tDot11fIEChanSwitchAnn *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 3; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 37; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->switchMode; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->newChannel; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->switchCount; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_chan_switch_ann. */ + +uint32_t dot11f_pack_ie_channel_switch_wrapper(tpAniSirGlobal pCtx, + tDot11fIEChannelSwitchWrapper *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint32_t status = DOT11F_PARSE_SUCCESS; + status = dot11f_get_packed_ie_channel_switch_wrapper(pCtx, pSrc, &nNeeded); + if (!DOT11F_SUCCEEDED(status)) + return status; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 196; + ++pBuf; --nBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; --nBuf; ++(*pnConsumed); + status = pack_core(pCtx, + (uint8_t *)pSrc, + pBuf, + nBuf, + pnConsumed, + FFS_ChannelSwitchWrapper, + IES_ChannelSwitchWrapper); + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return status; +} /* End dot11f_pack_ie_channel_switch_wrapper. */ + +uint32_t dot11f_pack_ie_country(tpAniSirGlobal pCtx, + tDot11fIECountry *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint32_t status = DOT11F_PARSE_SUCCESS; + status = dot11f_get_packed_ie_country(pCtx, pSrc, &nNeeded); + if (!DOT11F_SUCCEEDED(status)) + return status; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 7; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + DOT11F_MEMCPY(pCtx, pBuf, pSrc->country, 3); + *pnConsumed += 3; + pBuf += 3; + if (pSrc->num_triplets) { + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->triplets), (pSrc->num_triplets * 3)); + *pnConsumed += (pSrc->num_triplets * 3); + /* fieldsEndFlag = 1 */ + } else { + break; + } + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return status; +} /* End dot11f_pack_ie_country. */ + +uint32_t dot11f_pack_ie_ds_params(tpAniSirGlobal pCtx, + tDot11fIEDSParams *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 1; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 3; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->curr_channel; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_ds_params. */ + +uint32_t dot11f_pack_ie_edca_param_set(tpAniSirGlobal pCtx, + tDot11fIEEDCAParamSet *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint8_t tmp96__; + uint8_t tmp97__; + uint8_t tmp98__; + uint8_t tmp99__; + uint8_t tmp100__; + uint8_t tmp101__; + uint8_t tmp102__; + uint8_t tmp103__; + nNeeded += 18; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 12; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->qos; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->reserved; + *pnConsumed += 1; + pBuf += 1; + tmp96__ = 0U; + tmp96__ |= (pSrc->acbe_aifsn << 0); + tmp96__ |= (pSrc->acbe_acm << 4); + tmp96__ |= (pSrc->acbe_aci << 5); + tmp96__ |= (pSrc->unused1 << 7); + *pBuf = tmp96__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + tmp97__ = 0U; + tmp97__ |= (pSrc->acbe_acwmin << 0); + tmp97__ |= (pSrc->acbe_acwmax << 4); + *pBuf = tmp97__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + frameshtons(pCtx, pBuf, pSrc->acbe_txoplimit, 0); + *pnConsumed += 2; + pBuf += 2; + tmp98__ = 0U; + tmp98__ |= (pSrc->acbk_aifsn << 0); + tmp98__ |= (pSrc->acbk_acm << 4); + tmp98__ |= (pSrc->acbk_aci << 5); + tmp98__ |= (pSrc->unused2 << 7); + *pBuf = tmp98__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + tmp99__ = 0U; + tmp99__ |= (pSrc->acbk_acwmin << 0); + tmp99__ |= (pSrc->acbk_acwmax << 4); + *pBuf = tmp99__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + frameshtons(pCtx, pBuf, pSrc->acbk_txoplimit, 0); + *pnConsumed += 2; + pBuf += 2; + tmp100__ = 0U; + tmp100__ |= (pSrc->acvi_aifsn << 0); + tmp100__ |= (pSrc->acvi_acm << 4); + tmp100__ |= (pSrc->acvi_aci << 5); + tmp100__ |= (pSrc->unused3 << 7); + *pBuf = tmp100__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + tmp101__ = 0U; + tmp101__ |= (pSrc->acvi_acwmin << 0); + tmp101__ |= (pSrc->acvi_acwmax << 4); + *pBuf = tmp101__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + frameshtons(pCtx, pBuf, pSrc->acvi_txoplimit, 0); + *pnConsumed += 2; + pBuf += 2; + tmp102__ = 0U; + tmp102__ |= (pSrc->acvo_aifsn << 0); + tmp102__ |= (pSrc->acvo_acm << 4); + tmp102__ |= (pSrc->acvo_aci << 5); + tmp102__ |= (pSrc->unused4 << 7); + *pBuf = tmp102__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + tmp103__ = 0U; + tmp103__ |= (pSrc->acvo_acwmin << 0); + tmp103__ |= (pSrc->acvo_acwmax << 4); + *pBuf = tmp103__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + frameshtons(pCtx, pBuf, pSrc->acvo_txoplimit, 0); + *pnConsumed += 2; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_edca_param_set. */ + +uint32_t dot11f_pack_ie_erp_info(tpAniSirGlobal pCtx, + tDot11fIEERPInfo *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint8_t tmp104__; + nNeeded += 1; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 42; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + tmp104__ = 0U; + tmp104__ |= (pSrc->non_erp_present << 0); + tmp104__ |= (pSrc->use_prot << 1); + tmp104__ |= (pSrc->barker_preamble << 2); + tmp104__ |= (pSrc->unused << 3); + *pBuf = tmp104__; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + nBuf -= 1 ; + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_erp_info. */ + +uint32_t dot11f_pack_ie_ese_cckm_opaque(tpAniSirGlobal pCtx, + tDot11fIEESECckmOpaque *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += pSrc->num_data; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 156; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x0; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x40; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x96; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x0; + ++pBuf; ++(*pnConsumed); + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->data), pSrc->num_data); + *pnConsumed += pSrc->num_data; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_ese_cckm_opaque. */ + +uint32_t dot11f_pack_ie_ese_rad_mgmt_cap(tpAniSirGlobal pCtx, + tDot11fIEESERadMgmtCap *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint8_t tmp105__; + nNeeded += 2; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 221; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x0; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x40; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x96; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x1; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->mgmt_state; + *pnConsumed += 1; + pBuf += 1; + tmp105__ = 0U; + tmp105__ |= (pSrc->mbssid_mask << 0); + tmp105__ |= (pSrc->reserved << 3); + *pBuf = tmp105__; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + nBuf -= 1 ; + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_ese_rad_mgmt_cap. */ + +uint32_t dot11f_pack_ie_ese_traf_strm_met(tpAniSirGlobal pCtx, + tDot11fIEESETrafStrmMet *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 4; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 221; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x0; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x40; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x96; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x7; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->tsid; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->state; + *pnConsumed += 1; + pBuf += 1; + frameshtons(pCtx, pBuf, pSrc->msmt_interval, 0); + *pnConsumed += 2; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_ese_traf_strm_met. */ + +uint32_t dot11f_pack_ie_ese_traf_strm_rate_set(tpAniSirGlobal pCtx, + tDot11fIEESETrafStrmRateSet *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += (pSrc->num_tsrates + 1); + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 221; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x0; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x40; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x96; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x8; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->tsid; + *pnConsumed += 1; + pBuf += 1; + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->tsrates), pSrc->num_tsrates); + *pnConsumed += pSrc->num_tsrates; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_ese_traf_strm_rate_set. */ + +uint32_t dot11f_pack_ie_ese_txmit_power(tpAniSirGlobal pCtx, + tDot11fIEESETxmitPower *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 2; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 150; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x0; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x40; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x96; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x0; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->power_limit; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->reserved; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_ese_txmit_power. */ + +uint32_t dot11f_pack_ie_ese_version(tpAniSirGlobal pCtx, + tDot11fIEESEVersion *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 1; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 221; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x0; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x40; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x96; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x3; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->version; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_ese_version. */ + +uint32_t dot11f_pack_ie_ext_cap(tpAniSirGlobal pCtx, + tDot11fIEExtCap *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += pSrc->num_bytes; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 127; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->bytes), pSrc->num_bytes); + *pnConsumed += pSrc->num_bytes; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_ext_cap. */ + +uint32_t dot11f_pack_ie_ext_supp_rates(tpAniSirGlobal pCtx, + tDot11fIEExtSuppRates *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += pSrc->num_rates; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 50; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->rates), pSrc->num_rates); + *pnConsumed += pSrc->num_rates; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_ext_supp_rates. */ + +uint32_t dot11f_pack_ie_fh_param_set(tpAniSirGlobal pCtx, + tDot11fIEFHParamSet *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 5; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 2; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + frameshtons(pCtx, pBuf, pSrc->dwell_time, 0); + *pnConsumed += 2; + pBuf += 2; + *pBuf = pSrc->hop_set; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->hop_pattern; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->hop_index; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_fh_param_set. */ + +uint32_t dot11f_pack_ie_fh_params(tpAniSirGlobal pCtx, + tDot11fIEFHParams *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 2; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 8; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->radix; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->nchannels; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_fh_params. */ + +uint32_t dot11f_pack_ie_fh_patt_table(tpAniSirGlobal pCtx, + tDot11fIEFHPattTable *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += (pSrc->num_randtable + 4); + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 9; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->flag; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->nsets; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->modulus; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->offset; + *pnConsumed += 1; + pBuf += 1; + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->randtable), pSrc->num_randtable); + *pnConsumed += pSrc->num_randtable; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_fh_patt_table. */ + +uint32_t dot11f_pack_ie_ft_info(tpAniSirGlobal pCtx, + tDot11fIEFTInfo *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint16_t tmp106__; + uint32_t status = DOT11F_PARSE_SUCCESS; + status = dot11f_get_packed_ieft_info(pCtx, pSrc, &nNeeded); + if (!DOT11F_SUCCEEDED(status)) + return status; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 55; + ++pBuf; --nBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; --nBuf; ++(*pnConsumed); + tmp106__ = 0U; + tmp106__ |= (pSrc->reserved << 0); + tmp106__ |= (pSrc->IECount << 8); + frameshtons(pCtx, pBuf, tmp106__, 0); + *pnConsumed += 2; + pBuf += 2; + nBuf -= 2 ; + DOT11F_MEMCPY(pCtx, pBuf, pSrc->MIC, 16); + *pnConsumed += 16; + pBuf += 16; + DOT11F_MEMCPY(pCtx, pBuf, pSrc->Anonce, 32); + *pnConsumed += 32; + pBuf += 32; + DOT11F_MEMCPY(pCtx, pBuf, pSrc->Snonce, 32); + *pnConsumed += 32; + pBuf += 32; + status = pack_core(pCtx, + (uint8_t *)pSrc, + pBuf, + nBuf, + pnConsumed, + FFS_FTInfo, + IES_FTInfo); + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return status; +} /* End dot11f_pack_ie_ft_info. */ + +uint32_t dot11f_pack_ie_ht_caps(tpAniSirGlobal pCtx, + tDot11fIEHTCaps *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint16_t tmp107__; + uint8_t tmp108__; + uint16_t tmp109__; + uint32_t tmp110__; + uint8_t tmp111__; + nNeeded += (pSrc->num_rsvd + 26); + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 45; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + tmp107__ = 0U; + tmp107__ |= (pSrc->advCodingCap << 0); + tmp107__ |= (pSrc->supportedChannelWidthSet << 1); + tmp107__ |= (pSrc->mimoPowerSave << 2); + tmp107__ |= (pSrc->greenField << 4); + tmp107__ |= (pSrc->shortGI20MHz << 5); + tmp107__ |= (pSrc->shortGI40MHz << 6); + tmp107__ |= (pSrc->txSTBC << 7); + tmp107__ |= (pSrc->rxSTBC << 8); + tmp107__ |= (pSrc->delayedBA << 10); + tmp107__ |= (pSrc->maximalAMSDUsize << 11); + tmp107__ |= (pSrc->dsssCckMode40MHz << 12); + tmp107__ |= (pSrc->psmp << 13); + tmp107__ |= (pSrc->stbcControlFrame << 14); + tmp107__ |= (pSrc->lsigTXOPProtection << 15); + frameshtons(pCtx, pBuf, tmp107__, 0); + *pnConsumed += 2; + pBuf += 2; + nBuf -= 2 ; + tmp108__ = 0U; + tmp108__ |= (pSrc->maxRxAMPDUFactor << 0); + tmp108__ |= (pSrc->mpduDensity << 2); + tmp108__ |= (pSrc->reserved1 << 5); + *pBuf = tmp108__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + DOT11F_MEMCPY(pCtx, pBuf, pSrc->supportedMCSSet, 16); + *pnConsumed += 16; + pBuf += 16; + tmp109__ = 0U; + tmp109__ |= (pSrc->pco << 0); + tmp109__ |= (pSrc->transitionTime << 1); + tmp109__ |= (pSrc->reserved2 << 3); + tmp109__ |= (pSrc->mcsFeedback << 8); + tmp109__ |= (pSrc->reserved3 << 10); + frameshtons(pCtx, pBuf, tmp109__, 0); + *pnConsumed += 2; + pBuf += 2; + nBuf -= 2 ; + tmp110__ = 0U; + tmp110__ |= (pSrc->txBF << 0); + tmp110__ |= (pSrc->rxStaggeredSounding << 1); + tmp110__ |= (pSrc->txStaggeredSounding << 2); + tmp110__ |= (pSrc->rxZLF << 3); + tmp110__ |= (pSrc->txZLF << 4); + tmp110__ |= (pSrc->implicitTxBF << 5); + tmp110__ |= (pSrc->calibration << 6); + tmp110__ |= (pSrc->explicitCSITxBF << 8); + tmp110__ |= (pSrc->explicitUncompressedSteeringMatrix << 9); + tmp110__ |= (pSrc->explicitBFCSIFeedback << 10); + tmp110__ |= (pSrc->explicitUncompressedSteeringMatrixFeedback << 13); + tmp110__ |= (pSrc->explicitCompressedSteeringMatrixFeedback << 16); + tmp110__ |= (pSrc->csiNumBFAntennae << 19); + tmp110__ |= (pSrc->uncompressedSteeringMatrixBFAntennae << 21); + tmp110__ |= (pSrc->compressedSteeringMatrixBFAntennae << 23); + tmp110__ |= (pSrc->reserved4 << 25); + frameshtonl(pCtx, pBuf, tmp110__, 0); + *pnConsumed += 4; + pBuf += 4; + nBuf -= 4 ; + tmp111__ = 0U; + tmp111__ |= (pSrc->antennaSelection << 0); + tmp111__ |= (pSrc->explicitCSIFeedbackTx << 1); + tmp111__ |= (pSrc->antennaIndicesFeedbackTx << 2); + tmp111__ |= (pSrc->explicitCSIFeedback << 3); + tmp111__ |= (pSrc->antennaIndicesFeedback << 4); + tmp111__ |= (pSrc->rxAS << 5); + tmp111__ |= (pSrc->txSoundingPPDUs << 6); + tmp111__ |= (pSrc->reserved5 << 7); + *pBuf = tmp111__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->rsvd), pSrc->num_rsvd); + *pnConsumed += pSrc->num_rsvd; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_ht_caps. */ + +uint32_t dot11f_pack_ie_ht_info(tpAniSirGlobal pCtx, + tDot11fIEHTInfo *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint8_t tmp112__; + uint16_t tmp113__; + uint16_t tmp114__; + nNeeded += (pSrc->num_rsvd + 22); + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 61; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->primaryChannel; + *pnConsumed += 1; + pBuf += 1; + tmp112__ = 0U; + tmp112__ |= (pSrc->secondaryChannelOffset << 0); + tmp112__ |= (pSrc->recommendedTxWidthSet << 2); + tmp112__ |= (pSrc->rifsMode << 3); + tmp112__ |= (pSrc->controlledAccessOnly << 4); + tmp112__ |= (pSrc->serviceIntervalGranularity << 5); + *pBuf = tmp112__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + tmp113__ = 0U; + tmp113__ |= (pSrc->opMode << 0); + tmp113__ |= (pSrc->nonGFDevicesPresent << 2); + tmp113__ |= (pSrc->transmitBurstLimit << 3); + tmp113__ |= (pSrc->obssNonHTStaPresent << 4); + tmp113__ |= (pSrc->reserved << 5); + frameshtons(pCtx, pBuf, tmp113__, 0); + *pnConsumed += 2; + pBuf += 2; + nBuf -= 2 ; + tmp114__ = 0U; + tmp114__ |= (pSrc->basicSTBCMCS << 0); + tmp114__ |= (pSrc->dualCTSProtection << 7); + tmp114__ |= (pSrc->secondaryBeacon << 8); + tmp114__ |= (pSrc->lsigTXOPProtectionFullSupport << 9); + tmp114__ |= (pSrc->pcoActive << 10); + tmp114__ |= (pSrc->pcoPhase << 11); + tmp114__ |= (pSrc->reserved2 << 12); + frameshtons(pCtx, pBuf, tmp114__, 0); + *pnConsumed += 2; + pBuf += 2; + nBuf -= 2 ; + DOT11F_MEMCPY(pCtx, pBuf, pSrc->basicMCSSet, 16); + *pnConsumed += 16; + pBuf += 16; + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->rsvd), pSrc->num_rsvd); + *pnConsumed += pSrc->num_rsvd; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_ht_info. */ + +uint32_t dot11f_pack_ie_ibss_params(tpAniSirGlobal pCtx, + tDot11fIEIBSSParams *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 2; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 6; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + frameshtons(pCtx, pBuf, pSrc->atim, 0); + *pnConsumed += 2; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_ibss_params. */ + +uint32_t dot11f_pack_ie_link_identifier(tpAniSirGlobal pCtx, + tDot11fIELinkIdentifier *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 18; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 101; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + DOT11F_MEMCPY(pCtx, pBuf, pSrc->bssid, 6); + *pnConsumed += 6; + pBuf += 6; + DOT11F_MEMCPY(pCtx, pBuf, pSrc->InitStaAddr, 6); + *pnConsumed += 6; + pBuf += 6; + DOT11F_MEMCPY(pCtx, pBuf, pSrc->RespStaAddr, 6); + *pnConsumed += 6; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_link_identifier. */ + +uint32_t dot11f_pack_ie_MBO_IE(tpAniSirGlobal pCtx, + tDot11fIEMBO_IE *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += (pSrc->num_assoc_disallowed + 3); + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 221; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x50; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x6f; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x9a; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x16; + ++pBuf; ++(*pnConsumed); + DOT11F_MEMCPY(pCtx, pBuf, pSrc->mbo_cap, 3); + *pnConsumed += 3; + pBuf += 3; + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->assoc_disallowed), pSrc->num_assoc_disallowed); + *pnConsumed += pSrc->num_assoc_disallowed; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_MBO_IE. */ + +uint32_t dot11f_pack_ie_measurement_report(tpAniSirGlobal pCtx, + tDot11fIEMeasurementReport *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint8_t tmp115__; + uint8_t tmp116__; + uint8_t tmp117__; + uint32_t status = DOT11F_PARSE_SUCCESS; + status = dot11f_get_packed_ie_measurement_report(pCtx, pSrc, &nNeeded); + if (!DOT11F_SUCCEEDED(status)) + return status; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 39; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->token; + *pnConsumed += 1; + pBuf += 1; + tmp115__ = 0U; + tmp115__ |= (pSrc->late << 0); + tmp115__ |= (pSrc->incapable << 1); + tmp115__ |= (pSrc->refused << 2); + tmp115__ |= (pSrc->unused << 3); + *pBuf = tmp115__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + *pBuf = pSrc->type; + *pnConsumed += 1; + pBuf += 1; + if (pSrc->type) { + switch (pSrc->type) { + case 0: + *pBuf = pSrc->report.Basic.channel; + *pnConsumed += 1; + pBuf += 1; + frameshtonq(pCtx, pBuf, pSrc->report.Basic.meas_start_time, 0); + *pnConsumed += 8; + pBuf += 8; + frameshtons(pCtx, pBuf, pSrc->report.Basic.meas_duration, 0); + *pnConsumed += 2; + pBuf += 2; + tmp116__ = 0U; + tmp116__ |= (pSrc->report.Basic.bss << 0); + tmp116__ |= (pSrc->report.Basic.ofdm_preamble << 1); + tmp116__ |= (pSrc->report.Basic.unid_signal << 2); + tmp116__ |= (pSrc->report.Basic.rader << 3); + tmp116__ |= (pSrc->report.Basic.unmeasured << 4); + tmp116__ |= (pSrc->report.Basic.unused << 5); + *pBuf = tmp116__; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + nBuf -= 1 ; + break; + case 1: + *pBuf = pSrc->report.CCA.channel; + *pnConsumed += 1; + pBuf += 1; + frameshtonq(pCtx, pBuf, pSrc->report.CCA.meas_start_time, 0); + *pnConsumed += 8; + pBuf += 8; + frameshtons(pCtx, pBuf, pSrc->report.CCA.meas_duration, 0); + *pnConsumed += 2; + pBuf += 2; + *pBuf = pSrc->report.CCA.cca_busy_fraction; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + break; + case 2: + *pBuf = pSrc->report.RPIHistogram.channel; + *pnConsumed += 1; + pBuf += 1; + frameshtonq(pCtx, pBuf, pSrc->report.RPIHistogram.meas_start_time, 0); + *pnConsumed += 8; + pBuf += 8; + frameshtons(pCtx, pBuf, pSrc->report.RPIHistogram.meas_duration, 0); + *pnConsumed += 2; + pBuf += 2; + *pBuf = pSrc->report.RPIHistogram.rpi0_density; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->report.RPIHistogram.rpi1_density; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->report.RPIHistogram.rpi2_density; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->report.RPIHistogram.rpi3_density; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->report.RPIHistogram.rpi4_density; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->report.RPIHistogram.rpi5_density; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->report.RPIHistogram.rpi6_density; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->report.RPIHistogram.rpi7_density; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + break; + case 5: + *pBuf = pSrc->report.Beacon.regClass; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->report.Beacon.channel; + *pnConsumed += 1; + pBuf += 1; + frameshtonq(pCtx, pBuf, pSrc->report.Beacon.meas_start_time, 0); + *pnConsumed += 8; + pBuf += 8; + frameshtons(pCtx, pBuf, pSrc->report.Beacon.meas_duration, 0); + *pnConsumed += 2; + pBuf += 2; + tmp117__ = 0U; + tmp117__ |= (pSrc->report.Beacon.condensed_PHY << 0); + tmp117__ |= (pSrc->report.Beacon.reported_frame_type << 7); + *pBuf = tmp117__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + *pBuf = pSrc->report.Beacon.RCPI; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->report.Beacon.RSNI; + *pnConsumed += 1; + pBuf += 1; + DOT11F_MEMCPY(pCtx, pBuf, pSrc->report.Beacon.BSSID, 6); + *pnConsumed += 6; + pBuf += 6; + *pBuf = pSrc->report.Beacon.antenna_id; + *pnConsumed += 1; + pBuf += 1; + frameshtonl(pCtx, pBuf, pSrc->report.Beacon.parent_TSF, 0); + *pnConsumed += 4; + pBuf += 4; + status = pack_core(pCtx, + (uint8_t *)pSrc, + pBuf, + nBuf, + pnConsumed, + FFS_reportBeacon, + IES_reportBeacon); + break; + } + } else { + break; + } + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return status; +} /* End dot11f_pack_ie_measurement_report. */ + +uint32_t dot11f_pack_ie_measurement_request(tpAniSirGlobal pCtx, + tDot11fIEMeasurementRequest *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint8_t tmp118__; + uint32_t status = DOT11F_PARSE_SUCCESS; + status = dot11f_get_packed_ie_measurement_request(pCtx, pSrc, &nNeeded); + if (!DOT11F_SUCCEEDED(status)) + return status; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 38; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->measurement_token; + *pnConsumed += 1; + pBuf += 1; + tmp118__ = 0U; + tmp118__ |= (pSrc->parallel << 0); + tmp118__ |= (pSrc->enable << 1); + tmp118__ |= (pSrc->request << 2); + tmp118__ |= (pSrc->report << 3); + tmp118__ |= (pSrc->durationMandatory << 4); + tmp118__ |= (pSrc->unused << 5); + *pBuf = tmp118__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + *pBuf = pSrc->measurement_type; + *pnConsumed += 1; + pBuf += 1; + switch (pSrc->measurement_type) { + case 0: + *pBuf = pSrc->measurement_request.Basic.channel_no; + *pnConsumed += 1; + pBuf += 1; + DOT11F_MEMCPY(pCtx, pBuf, pSrc->measurement_request.Basic.meas_start_time, 8); + *pnConsumed += 8; + pBuf += 8; + frameshtons(pCtx, pBuf, pSrc->measurement_request.Basic.meas_duration, 0); + *pnConsumed += 2; + /* fieldsEndFlag = 1 */ + break; + case 1: + *pBuf = pSrc->measurement_request.CCA.channel_no; + *pnConsumed += 1; + pBuf += 1; + DOT11F_MEMCPY(pCtx, pBuf, pSrc->measurement_request.CCA.meas_start_time, 8); + *pnConsumed += 8; + pBuf += 8; + frameshtons(pCtx, pBuf, pSrc->measurement_request.CCA.meas_duration, 0); + *pnConsumed += 2; + /* fieldsEndFlag = 1 */ + break; + case 2: + *pBuf = pSrc->measurement_request.RPIHistogram.channel_no; + *pnConsumed += 1; + pBuf += 1; + DOT11F_MEMCPY(pCtx, pBuf, pSrc->measurement_request.RPIHistogram.meas_start_time, 8); + *pnConsumed += 8; + pBuf += 8; + frameshtons(pCtx, pBuf, pSrc->measurement_request.RPIHistogram.meas_duration, 0); + *pnConsumed += 2; + /* fieldsEndFlag = 1 */ + break; + case 5: + *pBuf = pSrc->measurement_request.Beacon.regClass; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->measurement_request.Beacon.channel; + *pnConsumed += 1; + pBuf += 1; + frameshtons(pCtx, pBuf, pSrc->measurement_request.Beacon.randomization, 0); + *pnConsumed += 2; + pBuf += 2; + frameshtons(pCtx, pBuf, pSrc->measurement_request.Beacon.meas_duration, 0); + *pnConsumed += 2; + pBuf += 2; + *pBuf = pSrc->measurement_request.Beacon.meas_mode; + *pnConsumed += 1; + pBuf += 1; + DOT11F_MEMCPY(pCtx, pBuf, pSrc->measurement_request.Beacon.BSSID, 6); + *pnConsumed += 6; + pBuf += 6; + status = pack_core(pCtx, + (uint8_t *)pSrc, + pBuf, + nBuf, + pnConsumed, + FFS_measurement_requestBeacon, + IES_measurement_requestBeacon); + break; + case 8: + *pBuf = pSrc->measurement_request.lci.loc_subject; + *pnConsumed += 1; + pBuf += 1; + status = pack_core(pCtx, + (uint8_t *)pSrc, + pBuf, + nBuf, + pnConsumed, + FFS_measurement_requestlci, + IES_measurement_requestlci); + break; + case 16: + frameshtons(pCtx, pBuf, pSrc->measurement_request.ftmrr.random_interval, 0); + *pnConsumed += 2; + pBuf += 2; + *pBuf = pSrc->measurement_request.ftmrr.min_ap_count; + *pnConsumed += 1; + pBuf += 1; + status = pack_core(pCtx, + (uint8_t *)pSrc, + pBuf, + nBuf, + pnConsumed, + FFS_measurement_requestftmrr, + IES_measurement_requestftmrr); + break; + } + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return status; +} /* End dot11f_pack_ie_measurement_request. */ + +uint32_t dot11f_pack_ie_mobility_domain(tpAniSirGlobal pCtx, + tDot11fIEMobilityDomain *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint8_t tmp119__; + nNeeded += 3; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 54; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + frameshtons(pCtx, pBuf, pSrc->MDID, 0); + *pnConsumed += 2; + pBuf += 2; + tmp119__ = 0U; + tmp119__ |= (pSrc->overDSCap << 0); + tmp119__ |= (pSrc->resourceReqCap << 1); + tmp119__ |= (pSrc->reserved << 2); + *pBuf = tmp119__; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + nBuf -= 1 ; + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_mobility_domain. */ + +uint32_t dot11f_pack_ie_neighbor_report(tpAniSirGlobal pCtx, + tDot11fIENeighborReport *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint8_t tmp120__; + uint8_t tmp121__; + uint32_t status = DOT11F_PARSE_SUCCESS; + status = dot11f_get_packed_ie_neighbor_report(pCtx, pSrc, &nNeeded); + if (!DOT11F_SUCCEEDED(status)) + return status; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 52; + ++pBuf; --nBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; --nBuf; ++(*pnConsumed); + DOT11F_MEMCPY(pCtx, pBuf, pSrc->bssid, 6); + *pnConsumed += 6; + pBuf += 6; + tmp120__ = 0U; + tmp120__ |= (pSrc->APReachability << 0); + tmp120__ |= (pSrc->Security << 2); + tmp120__ |= (pSrc->KeyScope << 3); + tmp120__ |= (pSrc->SpecMgmtCap << 4); + tmp120__ |= (pSrc->QosCap << 5); + tmp120__ |= (pSrc->apsd << 6); + tmp120__ |= (pSrc->rrm << 7); + *pBuf = tmp120__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + tmp121__ = 0U; + tmp121__ |= (pSrc->DelayedBA << 0); + tmp121__ |= (pSrc->ImmBA << 1); + tmp121__ |= (pSrc->MobilityDomain << 2); + tmp121__ |= (pSrc->reserved << 3); + *pBuf = tmp121__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + frameshtons(pCtx, pBuf, pSrc->reserved1, 0); + *pnConsumed += 2; + pBuf += 2; + *pBuf = pSrc->regulatoryClass; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->channel; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->PhyType; + *pnConsumed += 1; + pBuf += 1; + status = pack_core(pCtx, + (uint8_t *)pSrc, + pBuf, + nBuf, + pnConsumed, + FFS_NeighborReport, + IES_NeighborReport); + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return status; +} /* End dot11f_pack_ie_neighbor_report. */ + +uint32_t dot11f_pack_ie_obss_scan_parameters(tpAniSirGlobal pCtx, + tDot11fIEOBSSScanParameters *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 14; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 74; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + frameshtons(pCtx, pBuf, pSrc->obssScanPassiveDwell, 0); + *pnConsumed += 2; + pBuf += 2; + frameshtons(pCtx, pBuf, pSrc->obssScanActiveDwell, 0); + *pnConsumed += 2; + pBuf += 2; + frameshtons(pCtx, pBuf, pSrc->bssChannelWidthTriggerScanInterval, 0); + *pnConsumed += 2; + pBuf += 2; + frameshtons(pCtx, pBuf, pSrc->obssScanPassiveTotalPerChannel, 0); + *pnConsumed += 2; + pBuf += 2; + frameshtons(pCtx, pBuf, pSrc->obssScanActiveTotalPerChannel, 0); + *pnConsumed += 2; + pBuf += 2; + frameshtons(pCtx, pBuf, pSrc->bssWidthChannelTransitionDelayFactor, 0); + *pnConsumed += 2; + pBuf += 2; + frameshtons(pCtx, pBuf, pSrc->obssScanActivityThreshold, 0); + *pnConsumed += 2; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_obss_scan_parameters. */ + +uint32_t dot11f_pack_ie_operating_mode(tpAniSirGlobal pCtx, + tDot11fIEOperatingMode *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint8_t tmp122__; + nNeeded += 1; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 199; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + tmp122__ = 0U; + tmp122__ |= (pSrc->chanWidth << 0); + tmp122__ |= (pSrc->reserved << 2); + tmp122__ |= (pSrc->rxNSS << 4); + tmp122__ |= (pSrc->rxNSSType << 7); + *pBuf = tmp122__; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + nBuf -= 1 ; + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_operating_mode. */ + +uint32_t dot11f_pack_ie_p2_p_assoc_req(tpAniSirGlobal pCtx, + tDot11fIEP2PAssocReq *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t n, idx = 0, idxlast; + uint32_t nConsumedSoFar, nConsumedNow; + uint32_t status = DOT11F_PARSE_SUCCESS; + uint32_t nNeeded = 0U; + status = dot11f_get_packed_iep2_p_assoc_req(pCtx, pSrc, &nNeeded); + if (!DOT11F_SUCCEEDED(status)) + return status; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + (void)pCtx; + if (pSrc->present) { + do { + nConsumedSoFar = *pnConsumed; + *pBuf = 221; + ++pBuf; --nBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x50; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x6f; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x9a; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x9; + ++pBuf; --nBuf; ++(*pnConsumed); + n = (255 - 4) < nBuf ? (255 - 4) : nBuf; + nConsumedNow = *pnConsumed; + idxlast = idx; + status = pack_tlv_core(pCtx, (uint8_t *)pSrc, pBuf, n, + pnConsumed, + TLVS_P2PAssocReq + + idx, &idx); + nConsumedNow = *pnConsumed - nConsumedNow; + *pIeLen = *pnConsumed - nConsumedSoFar - 2; + pBuf += nConsumedNow; + nBuf -= nConsumedNow; + } while (DOT11F_BUFFER_OVERFLOW == status && idxlast != idx); + } + return status; +} /* End dot11f_pack_ie_p2_p_assoc_req. */ + +uint32_t dot11f_pack_ie_p2_p_assoc_res(tpAniSirGlobal pCtx, + tDot11fIEP2PAssocRes *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t n, idx = 0, idxlast; + uint32_t nConsumedSoFar, nConsumedNow; + uint32_t status = DOT11F_PARSE_SUCCESS; + uint32_t nNeeded = 0U; + status = dot11f_get_packed_iep2_p_assoc_res(pCtx, pSrc, &nNeeded); + if (!DOT11F_SUCCEEDED(status)) + return status; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + (void)pCtx; + if (pSrc->present) { + do { + nConsumedSoFar = *pnConsumed; + *pBuf = 221; + ++pBuf; --nBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x50; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x6f; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x9a; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x9; + ++pBuf; --nBuf; ++(*pnConsumed); + n = (255 - 4) < nBuf ? (255 - 4) : nBuf; + nConsumedNow = *pnConsumed; + idxlast = idx; + status = pack_tlv_core(pCtx, (uint8_t *)pSrc, pBuf, n, + pnConsumed, + TLVS_P2PAssocRes + + idx, &idx); + nConsumedNow = *pnConsumed - nConsumedNow; + *pIeLen = *pnConsumed - nConsumedSoFar - 2; + pBuf += nConsumedNow; + nBuf -= nConsumedNow; + } while (DOT11F_BUFFER_OVERFLOW == status && idxlast != idx); + } + return status; +} /* End dot11f_pack_ie_p2_p_assoc_res. */ + +uint32_t dot11f_pack_ie_p2_p_beacon(tpAniSirGlobal pCtx, + tDot11fIEP2PBeacon *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t n, idx = 0, idxlast; + uint32_t nConsumedSoFar, nConsumedNow; + uint32_t status = DOT11F_PARSE_SUCCESS; + uint32_t nNeeded = 0U; + status = dot11f_get_packed_iep2_p_beacon(pCtx, pSrc, &nNeeded); + if (!DOT11F_SUCCEEDED(status)) + return status; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + (void)pCtx; + if (pSrc->present) { + do { + nConsumedSoFar = *pnConsumed; + *pBuf = 221; + ++pBuf; --nBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x50; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x6f; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x9a; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x9; + ++pBuf; --nBuf; ++(*pnConsumed); + n = (255 - 4) < nBuf ? (255 - 4) : nBuf; + nConsumedNow = *pnConsumed; + idxlast = idx; + status = pack_tlv_core(pCtx, (uint8_t *)pSrc, pBuf, n, + pnConsumed, + TLVS_P2PBeacon + + idx, &idx); + nConsumedNow = *pnConsumed - nConsumedNow; + *pIeLen = *pnConsumed - nConsumedSoFar - 2; + pBuf += nConsumedNow; + nBuf -= nConsumedNow; + } while (DOT11F_BUFFER_OVERFLOW == status && idxlast != idx); + } + return status; +} /* End dot11f_pack_ie_p2_p_beacon. */ + +uint32_t dot11f_pack_ie_p2_p_beacon_probe_res(tpAniSirGlobal pCtx, + tDot11fIEP2PBeaconProbeRes *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t n, idx = 0, idxlast; + uint32_t nConsumedSoFar, nConsumedNow; + uint32_t status = DOT11F_PARSE_SUCCESS; + uint32_t nNeeded = 0U; + status = dot11f_get_packed_iep2_p_beacon_probe_res(pCtx, pSrc, &nNeeded); + if (!DOT11F_SUCCEEDED(status)) + return status; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + (void)pCtx; + if (pSrc->present) { + do { + nConsumedSoFar = *pnConsumed; + *pBuf = 221; + ++pBuf; --nBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x50; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x6f; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x9a; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x9; + ++pBuf; --nBuf; ++(*pnConsumed); + n = (255 - 4) < nBuf ? (255 - 4) : nBuf; + nConsumedNow = *pnConsumed; + idxlast = idx; + status = pack_tlv_core(pCtx, (uint8_t *)pSrc, pBuf, n, + pnConsumed, + TLVS_P2PBeaconProbeRes + + idx, &idx); + nConsumedNow = *pnConsumed - nConsumedNow; + *pIeLen = *pnConsumed - nConsumedSoFar - 2; + pBuf += nConsumedNow; + nBuf -= nConsumedNow; + } while (DOT11F_BUFFER_OVERFLOW == status && idxlast != idx); + } + return status; +} /* End dot11f_pack_ie_p2_p_beacon_probe_res. */ + +uint32_t dot11f_pack_ie_p2_p_de_auth(tpAniSirGlobal pCtx, + tDot11fIEP2PDeAuth *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t n, idx = 0, idxlast; + uint32_t nConsumedSoFar, nConsumedNow; + uint32_t status = DOT11F_PARSE_SUCCESS; + uint32_t nNeeded = 0U; + status = dot11f_get_packed_iep2_p_de_auth(pCtx, pSrc, &nNeeded); + if (!DOT11F_SUCCEEDED(status)) + return status; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + (void)pCtx; + if (pSrc->present) { + do { + nConsumedSoFar = *pnConsumed; + *pBuf = 221; + ++pBuf; --nBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x50; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x6f; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x9a; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x9; + ++pBuf; --nBuf; ++(*pnConsumed); + n = (255 - 4) < nBuf ? (255 - 4) : nBuf; + nConsumedNow = *pnConsumed; + idxlast = idx; + status = pack_tlv_core(pCtx, (uint8_t *)pSrc, pBuf, n, + pnConsumed, + TLVS_P2PDeAuth + + idx, &idx); + nConsumedNow = *pnConsumed - nConsumedNow; + *pIeLen = *pnConsumed - nConsumedSoFar - 2; + pBuf += nConsumedNow; + nBuf -= nConsumedNow; + } while (DOT11F_BUFFER_OVERFLOW == status && idxlast != idx); + } + return status; +} /* End dot11f_pack_ie_p2_p_de_auth. */ + +uint32_t dot11f_pack_ie_p2_p_dis_assoc(tpAniSirGlobal pCtx, + tDot11fIEP2PDisAssoc *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t n, idx = 0, idxlast; + uint32_t nConsumedSoFar, nConsumedNow; + uint32_t status = DOT11F_PARSE_SUCCESS; + uint32_t nNeeded = 0U; + status = dot11f_get_packed_iep2_p_dis_assoc(pCtx, pSrc, &nNeeded); + if (!DOT11F_SUCCEEDED(status)) + return status; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + (void)pCtx; + if (pSrc->present) { + do { + nConsumedSoFar = *pnConsumed; + *pBuf = 221; + ++pBuf; --nBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x50; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x6f; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x9a; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x9; + ++pBuf; --nBuf; ++(*pnConsumed); + n = (255 - 4) < nBuf ? (255 - 4) : nBuf; + nConsumedNow = *pnConsumed; + idxlast = idx; + status = pack_tlv_core(pCtx, (uint8_t *)pSrc, pBuf, n, + pnConsumed, + TLVS_P2PDisAssoc + + idx, &idx); + nConsumedNow = *pnConsumed - nConsumedNow; + *pIeLen = *pnConsumed - nConsumedSoFar - 2; + pBuf += nConsumedNow; + nBuf -= nConsumedNow; + } while (DOT11F_BUFFER_OVERFLOW == status && idxlast != idx); + } + return status; +} /* End dot11f_pack_ie_p2_p_dis_assoc. */ + +uint32_t dot11f_pack_ie_p2_pie_opaque(tpAniSirGlobal pCtx, + tDot11fIEP2PIEOpaque *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += pSrc->num_data; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 221; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x50; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x6f; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x9a; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x9; + ++pBuf; ++(*pnConsumed); + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->data), pSrc->num_data); + *pnConsumed += pSrc->num_data; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_p2_pie_opaque. */ + +uint32_t dot11f_pack_ie_p2_p_probe_req(tpAniSirGlobal pCtx, + tDot11fIEP2PProbeReq *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t n, idx = 0, idxlast; + uint32_t nConsumedSoFar, nConsumedNow; + uint32_t status = DOT11F_PARSE_SUCCESS; + uint32_t nNeeded = 0U; + status = dot11f_get_packed_iep2_p_probe_req(pCtx, pSrc, &nNeeded); + if (!DOT11F_SUCCEEDED(status)) + return status; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + (void)pCtx; + if (pSrc->present) { + do { + nConsumedSoFar = *pnConsumed; + *pBuf = 221; + ++pBuf; --nBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x50; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x6f; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x9a; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x9; + ++pBuf; --nBuf; ++(*pnConsumed); + n = (255 - 4) < nBuf ? (255 - 4) : nBuf; + nConsumedNow = *pnConsumed; + idxlast = idx; + status = pack_tlv_core(pCtx, (uint8_t *)pSrc, pBuf, n, + pnConsumed, + TLVS_P2PProbeReq + + idx, &idx); + nConsumedNow = *pnConsumed - nConsumedNow; + *pIeLen = *pnConsumed - nConsumedSoFar - 2; + pBuf += nConsumedNow; + nBuf -= nConsumedNow; + } while (DOT11F_BUFFER_OVERFLOW == status && idxlast != idx); + } + return status; +} /* End dot11f_pack_ie_p2_p_probe_req. */ + +uint32_t dot11f_pack_ie_p2_p_probe_res(tpAniSirGlobal pCtx, + tDot11fIEP2PProbeRes *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t n, idx = 0, idxlast; + uint32_t nConsumedSoFar, nConsumedNow; + uint32_t status = DOT11F_PARSE_SUCCESS; + uint32_t nNeeded = 0U; + status = dot11f_get_packed_iep2_p_probe_res(pCtx, pSrc, &nNeeded); + if (!DOT11F_SUCCEEDED(status)) + return status; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + (void)pCtx; + if (pSrc->present) { + do { + nConsumedSoFar = *pnConsumed; + *pBuf = 221; + ++pBuf; --nBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x50; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x6f; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x9a; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x9; + ++pBuf; --nBuf; ++(*pnConsumed); + n = (255 - 4) < nBuf ? (255 - 4) : nBuf; + nConsumedNow = *pnConsumed; + idxlast = idx; + status = pack_tlv_core(pCtx, (uint8_t *)pSrc, pBuf, n, + pnConsumed, + TLVS_P2PProbeRes + + idx, &idx); + nConsumedNow = *pnConsumed - nConsumedNow; + *pIeLen = *pnConsumed - nConsumedSoFar - 2; + pBuf += nConsumedNow; + nBuf -= nConsumedNow; + } while (DOT11F_BUFFER_OVERFLOW == status && idxlast != idx); + } + return status; +} /* End dot11f_pack_ie_p2_p_probe_res. */ + +uint32_t dot11f_pack_ie_pti_control(tpAniSirGlobal pCtx, + tDot11fIEPTIControl *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 3; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 105; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->tid; + *pnConsumed += 1; + pBuf += 1; + frameshtons(pCtx, pBuf, pSrc->sequence_control, 0); + *pnConsumed += 2; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_pti_control. */ + +uint32_t dot11f_pack_ie_pu_buffer_status(tpAniSirGlobal pCtx, + tDot11fIEPUBufferStatus *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint8_t tmp123__; + nNeeded += 1; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 106; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + tmp123__ = 0U; + tmp123__ |= (pSrc->ac_bk_traffic_aval << 0); + tmp123__ |= (pSrc->ac_be_traffic_aval << 1); + tmp123__ |= (pSrc->ac_vi_traffic_aval << 2); + tmp123__ |= (pSrc->ac_vo_traffic_aval << 3); + tmp123__ |= (pSrc->reserved << 4); + *pBuf = tmp123__; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + nBuf -= 1 ; + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_pu_buffer_status. */ + +uint32_t dot11f_pack_ie_power_caps(tpAniSirGlobal pCtx, + tDot11fIEPowerCaps *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 2; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 33; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->minTxPower; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->maxTxPower; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_power_caps. */ + +uint32_t dot11f_pack_ie_power_constraints(tpAniSirGlobal pCtx, + tDot11fIEPowerConstraints *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 1; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 32; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->localPowerConstraints; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_power_constraints. */ + +uint32_t dot11f_pack_ie_qbss_load(tpAniSirGlobal pCtx, + tDot11fIEQBSSLoad *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 5; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 11; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + frameshtons(pCtx, pBuf, pSrc->stacount, 0); + *pnConsumed += 2; + pBuf += 2; + *pBuf = pSrc->chautil; + *pnConsumed += 1; + pBuf += 1; + frameshtons(pCtx, pBuf, pSrc->avail, 0); + *pnConsumed += 2; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_qbss_load. */ + +uint32_t dot11f_pack_ie_QCN_IE(tpAniSirGlobal pCtx, + tDot11fIEQCN_IE *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 4; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 221; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x8c; + ++pBuf; ++(*pnConsumed); + *pBuf = 0xfd; + ++pBuf; ++(*pnConsumed); + *pBuf = 0xf0; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x1; + ++pBuf; ++(*pnConsumed); + DOT11F_MEMCPY(pCtx, pBuf, pSrc->version, 4); + *pnConsumed += 4; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_QCN_IE. */ + +uint32_t dot11f_pack_ie_QComVendorIE(tpAniSirGlobal pCtx, + tDot11fIEQComVendorIE *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 2; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 221; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x0; + ++pBuf; ++(*pnConsumed); + *pBuf = 0xa0; + ++pBuf; ++(*pnConsumed); + *pBuf = 0xc6; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->type; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->channel; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_QComVendorIE. */ + +uint32_t dot11f_pack_ie_qos_caps_ap(tpAniSirGlobal pCtx, + tDot11fIEQOSCapsAp *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint8_t tmp124__; + nNeeded += 1; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 46; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + tmp124__ = 0U; + tmp124__ |= (pSrc->count << 0); + tmp124__ |= (pSrc->qack << 4); + tmp124__ |= (pSrc->qreq << 5); + tmp124__ |= (pSrc->txopreq << 6); + tmp124__ |= (pSrc->reserved << 7); + *pBuf = tmp124__; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + nBuf -= 1 ; + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_qos_caps_ap. */ + +uint32_t dot11f_pack_ie_qos_caps_station(tpAniSirGlobal pCtx, + tDot11fIEQOSCapsStation *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint8_t tmp125__; + nNeeded += 1; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 46; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + tmp125__ = 0U; + tmp125__ |= (pSrc->acvo_uapsd << 0); + tmp125__ |= (pSrc->acvi_uapsd << 1); + tmp125__ |= (pSrc->acbk_uapsd << 2); + tmp125__ |= (pSrc->acbe_uapsd << 3); + tmp125__ |= (pSrc->qack << 4); + tmp125__ |= (pSrc->max_sp_length << 5); + tmp125__ |= (pSrc->more_data_ack << 7); + *pBuf = tmp125__; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + nBuf -= 1 ; + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_qos_caps_station. */ + +uint32_t dot11f_pack_ie_qos_map_set(tpAniSirGlobal pCtx, + tDot11fIEQosMapSet *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += pSrc->num_dscp_exceptions; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 110; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->dscp_exceptions), pSrc->num_dscp_exceptions); + *pnConsumed += pSrc->num_dscp_exceptions; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_qos_map_set. */ + +uint32_t dot11f_pack_ie_quiet(tpAniSirGlobal pCtx, + tDot11fIEQuiet *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 6; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 40; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->count; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->period; + *pnConsumed += 1; + pBuf += 1; + frameshtons(pCtx, pBuf, pSrc->duration, 0); + *pnConsumed += 2; + pBuf += 2; + frameshtons(pCtx, pBuf, pSrc->offset, 0); + *pnConsumed += 2; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_quiet. */ + +uint32_t dot11f_pack_ie_rcpiie(tpAniSirGlobal pCtx, + tDot11fIERCPIIE *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 1; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 53; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->rcpi; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_rcpiie. */ + +uint32_t dot11f_pack_ie_ric_data_desc(tpAniSirGlobal pCtx, + tDot11fIERICDataDesc *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint32_t nNeeded = 0U; + uint32_t status = DOT11F_PARSE_SUCCESS; + status = dot11f_get_packed_ieric_data_desc(pCtx, pSrc, &nNeeded); + if (!DOT11F_SUCCEEDED(status)) + return status; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + status = pack_core(pCtx, + (uint8_t *)pSrc, + pBuf, + nBuf, + pnConsumed, + FFS_RICDataDesc, + IES_RICDataDesc); + break; + } + (void)pCtx; + return status; +} /* End dot11f_pack_ie_ric_data_desc. */ + +uint32_t dot11f_pack_ie_rsn(tpAniSirGlobal pCtx, + tDot11fIERSN *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint32_t status = DOT11F_PARSE_SUCCESS; + status = dot11f_get_packed_iersn(pCtx, pSrc, &nNeeded); + if (!DOT11F_SUCCEEDED(status)) + return status; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 48; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + frameshtons(pCtx, pBuf, pSrc->version, 0); + *pnConsumed += 2; + pBuf += 2; + DOT11F_MEMCPY(pCtx, pBuf, pSrc->gp_cipher_suite, 4); + *pnConsumed += 4; + pBuf += 4; + if (pSrc->pwise_cipher_suite_count) { + frameshtons(pCtx, pBuf, pSrc->pwise_cipher_suite_count, 0); + *pnConsumed += 2; + pBuf += 2; + } else { + break; + } + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->pwise_cipher_suites), (pSrc->pwise_cipher_suite_count * 4)); + *pnConsumed += (pSrc->pwise_cipher_suite_count * 4); + pBuf += (pSrc->pwise_cipher_suite_count * 4); + if (pSrc->akm_suite_count) { + frameshtons(pCtx, pBuf, pSrc->akm_suite_count, 0); + *pnConsumed += 2; + pBuf += 2; + } else { + break; + } + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->akm_suites), (pSrc->akm_suite_count * 4)); + *pnConsumed += (pSrc->akm_suite_count * 4); + pBuf += (pSrc->akm_suite_count * 4); + if (pSrc->RSN_Cap) { + DOT11F_MEMCPY(pCtx, pBuf, pSrc->RSN_Cap, 2); + *pnConsumed += 2; + pBuf += 2; + } else { + break; + } + if (pSrc->pmkid_count) { + frameshtons(pCtx, pBuf, pSrc->pmkid_count, 0); + *pnConsumed += 2; + pBuf += 2; + } else { + break; + } + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->pmkid), (pSrc->pmkid_count * 16)); + *pnConsumed += (pSrc->pmkid_count * 16); + pBuf += (pSrc->pmkid_count * 16); + if (pSrc->gp_mgmt_cipher_suite) { + DOT11F_MEMCPY(pCtx, pBuf, pSrc->gp_mgmt_cipher_suite, 4); + *pnConsumed += 4; + /* fieldsEndFlag = 1 */ + } else { + break; + } + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return status; +} /* End dot11f_pack_ie_rsn. */ + +uint32_t dot11f_pack_ie_rsniie(tpAniSirGlobal pCtx, + tDot11fIERSNIIE *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 1; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 65; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->rsni; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_rsniie. */ + +uint32_t dot11f_pack_ie_rsn_opaque(tpAniSirGlobal pCtx, + tDot11fIERSNOpaque *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += pSrc->num_data; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 48; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->data), pSrc->num_data); + *pnConsumed += pSrc->num_data; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_rsn_opaque. */ + +uint32_t dot11f_pack_ie_supp_channels(tpAniSirGlobal pCtx, + tDot11fIESuppChannels *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += pSrc->num_bands * 2; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 36; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->bands), (pSrc->num_bands * 2)); + *pnConsumed += (pSrc->num_bands * 2); + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_supp_channels. */ + +uint32_t dot11f_pack_ie_supp_operating_classes(tpAniSirGlobal pCtx, + tDot11fIESuppOperatingClasses *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += pSrc->num_classes; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 59; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->classes), pSrc->num_classes); + *pnConsumed += pSrc->num_classes; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_supp_operating_classes. */ + +uint32_t dot11f_pack_ie_supp_rates(tpAniSirGlobal pCtx, + tDot11fIESuppRates *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += pSrc->num_rates; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 1; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->rates), pSrc->num_rates); + *pnConsumed += pSrc->num_rates; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_supp_rates. */ + +uint32_t dot11f_pack_ie_tim(tpAniSirGlobal pCtx, + tDot11fIETIM *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += (pSrc->num_vbmp + 3); + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 5; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->dtim_count; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->dtim_period; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->bmpctl; + *pnConsumed += 1; + pBuf += 1; + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->vbmp), pSrc->num_vbmp); + *pnConsumed += pSrc->num_vbmp; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_tim. */ + +uint32_t dot11f_pack_ie_tpc_report(tpAniSirGlobal pCtx, + tDot11fIETPCReport *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 2; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 35; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->tx_power; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->link_margin; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_tpc_report. */ + +uint32_t dot11f_pack_ie_tpc_request(tpAniSirGlobal pCtx, + tDot11fIETPCRequest *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 0; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 34; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_tpc_request. */ + +uint32_t dot11f_pack_ie_time_advertisement(tpAniSirGlobal pCtx, + tDot11fIETimeAdvertisement *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 16; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 69; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->timing_capabilities; + *pnConsumed += 1; + pBuf += 1; + DOT11F_MEMCPY(pCtx, pBuf, pSrc->time_value, 10); + *pnConsumed += 10; + pBuf += 10; + DOT11F_MEMCPY(pCtx, pBuf, pSrc->time_error, 5); + *pnConsumed += 5; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_time_advertisement. */ + +uint32_t dot11f_pack_ie_timeout_interval(tpAniSirGlobal pCtx, + tDot11fIETimeoutInterval *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 5; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 56; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->timeoutType; + *pnConsumed += 1; + pBuf += 1; + frameshtonl(pCtx, pBuf, pSrc->timeoutValue, 0); + *pnConsumed += 4; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_timeout_interval. */ + +uint32_t dot11f_pack_ie_vht_ext_bss_load(tpAniSirGlobal pCtx, + tDot11fIEVHTExtBssLoad *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 5; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 193; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->muMIMOCapStaCount; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->ssUnderUtil; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->FortyMHzUtil; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->EightyMHzUtil; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->OneSixtyMHzUtil; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_vht_ext_bss_load. */ + +uint32_t dot11f_pack_ie_vendor1_ie(tpAniSirGlobal pCtx, + tDot11fIEVendor1IE *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 0; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 221; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x0; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x10; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x18; + ++pBuf; ++(*pnConsumed); + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_vendor1_ie. */ + +uint32_t dot11f_pack_ie_vendor3_ie(tpAniSirGlobal pCtx, + tDot11fIEVendor3IE *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 0; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 221; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x0; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x16; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x32; + ++pBuf; ++(*pnConsumed); + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_vendor3_ie. */ + +uint32_t dot11f_pack_ie_wapi(tpAniSirGlobal pCtx, + tDot11fIEWAPI *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint16_t tmp126__; + uint32_t status = DOT11F_PARSE_SUCCESS; + status = dot11f_get_packed_iewapi(pCtx, pSrc, &nNeeded); + if (!DOT11F_SUCCEEDED(status)) + return status; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 68; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + frameshtons(pCtx, pBuf, pSrc->version, 0); + *pnConsumed += 2; + pBuf += 2; + frameshtons(pCtx, pBuf, pSrc->akm_suite_count, 0); + *pnConsumed += 2; + pBuf += 2; + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->akm_suites), (pSrc->akm_suite_count * 4)); + *pnConsumed += (pSrc->akm_suite_count * 4); + pBuf += (pSrc->akm_suite_count * 4); + frameshtons(pCtx, pBuf, pSrc->unicast_cipher_suite_count, 0); + *pnConsumed += 2; + pBuf += 2; + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->unicast_cipher_suites), (pSrc->unicast_cipher_suite_count * 4)); + *pnConsumed += (pSrc->unicast_cipher_suite_count * 4); + pBuf += (pSrc->unicast_cipher_suite_count * 4); + DOT11F_MEMCPY(pCtx, pBuf, pSrc->multicast_cipher_suite, 4); + *pnConsumed += 4; + pBuf += 4; + tmp126__ = 0U; + tmp126__ |= (pSrc->preauth << 0); + tmp126__ |= (pSrc->reserved << 1); + frameshtons(pCtx, pBuf, tmp126__, 0); + *pnConsumed += 2; + pBuf += 2; + nBuf -= 2 ; + if (pSrc->bkid_count) { + frameshtons(pCtx, pBuf, pSrc->bkid_count, 0); + *pnConsumed += 2; + pBuf += 2; + } else { + break; + } + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->bkid), (pSrc->bkid_count * 16)); + *pnConsumed += (pSrc->bkid_count * 16); + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return status; +} /* End dot11f_pack_ie_wapi. */ + +uint32_t dot11f_pack_ie_wapi_opaque(tpAniSirGlobal pCtx, + tDot11fIEWAPIOpaque *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += pSrc->num_data; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 68; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->data), pSrc->num_data); + *pnConsumed += pSrc->num_data; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_wapi_opaque. */ + +uint32_t dot11f_pack_ie_wfatpc(tpAniSirGlobal pCtx, + tDot11fIEWFATPC *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 2; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 221; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x0; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x50; + ++pBuf; ++(*pnConsumed); + *pBuf = 0xf2; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x8; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x0; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->txPower; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->linkMargin; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_wfatpc. */ + +uint32_t dot11f_pack_ie_wfdie_opaque(tpAniSirGlobal pCtx, + tDot11fIEWFDIEOpaque *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += pSrc->num_data; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 221; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x50; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x6f; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x9a; + ++pBuf; ++(*pnConsumed); + *pBuf = 0xa; + ++pBuf; ++(*pnConsumed); + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->data), pSrc->num_data); + *pnConsumed += pSrc->num_data; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_wfdie_opaque. */ + +uint32_t dot11f_pack_ie_wmm_caps(tpAniSirGlobal pCtx, + tDot11fIEWMMCaps *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint8_t tmp127__; + nNeeded += 2; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 221; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x0; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x50; + ++pBuf; ++(*pnConsumed); + *pBuf = 0xf2; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x2; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x5; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->version; + *pnConsumed += 1; + pBuf += 1; + tmp127__ = 0U; + tmp127__ |= (pSrc->reserved << 0); + tmp127__ |= (pSrc->qack << 4); + tmp127__ |= (pSrc->queue_request << 5); + tmp127__ |= (pSrc->txop_request << 6); + tmp127__ |= (pSrc->more_ack << 7); + *pBuf = tmp127__; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + nBuf -= 1 ; + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_wmm_caps. */ + +uint32_t dot11f_pack_ie_wmm_info_ap(tpAniSirGlobal pCtx, + tDot11fIEWMMInfoAp *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint8_t tmp128__; + nNeeded += 2; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 221; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x0; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x50; + ++pBuf; ++(*pnConsumed); + *pBuf = 0xf2; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x2; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x0; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->version; + *pnConsumed += 1; + pBuf += 1; + tmp128__ = 0U; + tmp128__ |= (pSrc->param_set_count << 0); + tmp128__ |= (pSrc->reserved << 4); + tmp128__ |= (pSrc->uapsd << 7); + *pBuf = tmp128__; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + nBuf -= 1 ; + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_wmm_info_ap. */ + +uint32_t dot11f_pack_ie_wmm_info_station(tpAniSirGlobal pCtx, + tDot11fIEWMMInfoStation *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint8_t tmp129__; + nNeeded += 2; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 221; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x0; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x50; + ++pBuf; ++(*pnConsumed); + *pBuf = 0xf2; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x2; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x0; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->version; + *pnConsumed += 1; + pBuf += 1; + tmp129__ = 0U; + tmp129__ |= (pSrc->acvo_uapsd << 0); + tmp129__ |= (pSrc->acvi_uapsd << 1); + tmp129__ |= (pSrc->acbk_uapsd << 2); + tmp129__ |= (pSrc->acbe_uapsd << 3); + tmp129__ |= (pSrc->reserved1 << 4); + tmp129__ |= (pSrc->max_sp_length << 5); + tmp129__ |= (pSrc->reserved2 << 7); + *pBuf = tmp129__; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + nBuf -= 1 ; + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_wmm_info_station. */ + +uint32_t dot11f_pack_ie_wmm_params(tpAniSirGlobal pCtx, + tDot11fIEWMMParams *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint8_t tmp130__; + uint8_t tmp131__; + uint8_t tmp132__; + uint8_t tmp133__; + uint8_t tmp134__; + uint8_t tmp135__; + uint8_t tmp136__; + uint8_t tmp137__; + nNeeded += 19; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 221; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x0; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x50; + ++pBuf; ++(*pnConsumed); + *pBuf = 0xf2; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x2; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x1; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->version; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->qosInfo; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->reserved2; + *pnConsumed += 1; + pBuf += 1; + tmp130__ = 0U; + tmp130__ |= (pSrc->acbe_aifsn << 0); + tmp130__ |= (pSrc->acbe_acm << 4); + tmp130__ |= (pSrc->acbe_aci << 5); + tmp130__ |= (pSrc->unused1 << 7); + *pBuf = tmp130__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + tmp131__ = 0U; + tmp131__ |= (pSrc->acbe_acwmin << 0); + tmp131__ |= (pSrc->acbe_acwmax << 4); + *pBuf = tmp131__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + frameshtons(pCtx, pBuf, pSrc->acbe_txoplimit, 0); + *pnConsumed += 2; + pBuf += 2; + tmp132__ = 0U; + tmp132__ |= (pSrc->acbk_aifsn << 0); + tmp132__ |= (pSrc->acbk_acm << 4); + tmp132__ |= (pSrc->acbk_aci << 5); + tmp132__ |= (pSrc->unused2 << 7); + *pBuf = tmp132__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + tmp133__ = 0U; + tmp133__ |= (pSrc->acbk_acwmin << 0); + tmp133__ |= (pSrc->acbk_acwmax << 4); + *pBuf = tmp133__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + frameshtons(pCtx, pBuf, pSrc->acbk_txoplimit, 0); + *pnConsumed += 2; + pBuf += 2; + tmp134__ = 0U; + tmp134__ |= (pSrc->acvi_aifsn << 0); + tmp134__ |= (pSrc->acvi_acm << 4); + tmp134__ |= (pSrc->acvi_aci << 5); + tmp134__ |= (pSrc->unused3 << 7); + *pBuf = tmp134__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + tmp135__ = 0U; + tmp135__ |= (pSrc->acvi_acwmin << 0); + tmp135__ |= (pSrc->acvi_acwmax << 4); + *pBuf = tmp135__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + frameshtons(pCtx, pBuf, pSrc->acvi_txoplimit, 0); + *pnConsumed += 2; + pBuf += 2; + tmp136__ = 0U; + tmp136__ |= (pSrc->acvo_aifsn << 0); + tmp136__ |= (pSrc->acvo_acm << 4); + tmp136__ |= (pSrc->acvo_aci << 5); + tmp136__ |= (pSrc->unused4 << 7); + *pBuf = tmp136__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + tmp137__ = 0U; + tmp137__ |= (pSrc->acvo_acwmin << 0); + tmp137__ |= (pSrc->acvo_acwmax << 4); + *pBuf = tmp137__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + frameshtons(pCtx, pBuf, pSrc->acvo_txoplimit, 0); + *pnConsumed += 2; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_wmm_params. */ + +uint32_t dot11f_pack_ie_wpa(tpAniSirGlobal pCtx, + tDot11fIEWPA *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint32_t status = DOT11F_PARSE_SUCCESS; + status = dot11f_get_packed_iewpa(pCtx, pSrc, &nNeeded); + if (!DOT11F_SUCCEEDED(status)) + return status; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 221; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x0; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x50; + ++pBuf; ++(*pnConsumed); + *pBuf = 0xf2; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x1; + ++pBuf; ++(*pnConsumed); + frameshtons(pCtx, pBuf, pSrc->version, 0); + *pnConsumed += 2; + pBuf += 2; + if (pSrc->multicast_cipher_present) { + DOT11F_MEMCPY(pCtx, pBuf, pSrc->multicast_cipher, 4); + *pnConsumed += 4; + pBuf += 4; + } else { + break; + } + if (pSrc->unicast_cipher_count) { + frameshtons(pCtx, pBuf, pSrc->unicast_cipher_count, 0); + *pnConsumed += 2; + pBuf += 2; + } else { + break; + } + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->unicast_ciphers), (pSrc->unicast_cipher_count * 4)); + *pnConsumed += (pSrc->unicast_cipher_count * 4); + pBuf += (pSrc->unicast_cipher_count * 4); + if (pSrc->auth_suite_count) { + frameshtons(pCtx, pBuf, pSrc->auth_suite_count, 0); + *pnConsumed += 2; + pBuf += 2; + } else { + break; + } + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->auth_suites), (pSrc->auth_suite_count * 4)); + *pnConsumed += (pSrc->auth_suite_count * 4); + pBuf += (pSrc->auth_suite_count * 4); + if (pSrc->caps) { + frameshtons(pCtx, pBuf, pSrc->caps, 0); + *pnConsumed += 2; + /* fieldsEndFlag = 1 */ + } else { + break; + } + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return status; +} /* End dot11f_pack_ie_wpa. */ + +uint32_t dot11f_pack_ie_wpa_opaque(tpAniSirGlobal pCtx, + tDot11fIEWPAOpaque *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += pSrc->num_data; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 221; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x0; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x50; + ++pBuf; ++(*pnConsumed); + *pBuf = 0xf2; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x1; + ++pBuf; ++(*pnConsumed); + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->data), pSrc->num_data); + *pnConsumed += pSrc->num_data; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_wpa_opaque. */ + +uint32_t dot11f_pack_ie_wsc(tpAniSirGlobal pCtx, + tDot11fIEWSC *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t n, idx = 0, idxlast; + uint32_t nConsumedSoFar, nConsumedNow; + uint32_t status = DOT11F_PARSE_SUCCESS; + uint32_t nNeeded = 0U; + status = dot11f_get_packed_iewsc(pCtx, pSrc, &nNeeded); + if (!DOT11F_SUCCEEDED(status)) + return status; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + (void)pCtx; + if (pSrc->present) { + do { + nConsumedSoFar = *pnConsumed; + *pBuf = 221; + ++pBuf; --nBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x0; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x50; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0xf2; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x4; + ++pBuf; --nBuf; ++(*pnConsumed); + n = (255 - 4) < nBuf ? (255 - 4) : nBuf; + nConsumedNow = *pnConsumed; + idxlast = idx; + status = pack_tlv_core(pCtx, (uint8_t *)pSrc, pBuf, n, + pnConsumed, + TLVS_WSC + + idx, &idx); + nConsumedNow = *pnConsumed - nConsumedNow; + *pIeLen = *pnConsumed - nConsumedSoFar - 2; + pBuf += nConsumedNow; + nBuf -= nConsumedNow; + } while (DOT11F_BUFFER_OVERFLOW == status && idxlast != idx); + } + return status; +} /* End dot11f_pack_ie_wsc. */ + +uint32_t dot11f_pack_ie_wsc_assoc_req(tpAniSirGlobal pCtx, + tDot11fIEWscAssocReq *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t n, idx = 0, idxlast; + uint32_t nConsumedSoFar, nConsumedNow; + uint32_t status = DOT11F_PARSE_SUCCESS; + uint32_t nNeeded = 0U; + status = dot11f_get_packed_ie_wsc_assoc_req(pCtx, pSrc, &nNeeded); + if (!DOT11F_SUCCEEDED(status)) + return status; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + (void)pCtx; + if (pSrc->present) { + do { + nConsumedSoFar = *pnConsumed; + *pBuf = 221; + ++pBuf; --nBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x0; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x50; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0xf2; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x4; + ++pBuf; --nBuf; ++(*pnConsumed); + n = (255 - 4) < nBuf ? (255 - 4) : nBuf; + nConsumedNow = *pnConsumed; + idxlast = idx; + status = pack_tlv_core(pCtx, (uint8_t *)pSrc, pBuf, n, + pnConsumed, + TLVS_WscAssocReq + + idx, &idx); + nConsumedNow = *pnConsumed - nConsumedNow; + *pIeLen = *pnConsumed - nConsumedSoFar - 2; + pBuf += nConsumedNow; + nBuf -= nConsumedNow; + } while (DOT11F_BUFFER_OVERFLOW == status && idxlast != idx); + } + return status; +} /* End dot11f_pack_ie_wsc_assoc_req. */ + +uint32_t dot11f_pack_ie_wsc_assoc_res(tpAniSirGlobal pCtx, + tDot11fIEWscAssocRes *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t n, idx = 0, idxlast; + uint32_t nConsumedSoFar, nConsumedNow; + uint32_t status = DOT11F_PARSE_SUCCESS; + uint32_t nNeeded = 0U; + status = dot11f_get_packed_ie_wsc_assoc_res(pCtx, pSrc, &nNeeded); + if (!DOT11F_SUCCEEDED(status)) + return status; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + (void)pCtx; + if (pSrc->present) { + do { + nConsumedSoFar = *pnConsumed; + *pBuf = 221; + ++pBuf; --nBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x0; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x50; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0xf2; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x4; + ++pBuf; --nBuf; ++(*pnConsumed); + n = (255 - 4) < nBuf ? (255 - 4) : nBuf; + nConsumedNow = *pnConsumed; + idxlast = idx; + status = pack_tlv_core(pCtx, (uint8_t *)pSrc, pBuf, n, + pnConsumed, + TLVS_WscAssocRes + + idx, &idx); + nConsumedNow = *pnConsumed - nConsumedNow; + *pIeLen = *pnConsumed - nConsumedSoFar - 2; + pBuf += nConsumedNow; + nBuf -= nConsumedNow; + } while (DOT11F_BUFFER_OVERFLOW == status && idxlast != idx); + } + return status; +} /* End dot11f_pack_ie_wsc_assoc_res. */ + +uint32_t dot11f_pack_ie_wsc_beacon(tpAniSirGlobal pCtx, + tDot11fIEWscBeacon *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t n, idx = 0, idxlast; + uint32_t nConsumedSoFar, nConsumedNow; + uint32_t status = DOT11F_PARSE_SUCCESS; + uint32_t nNeeded = 0U; + status = dot11f_get_packed_ie_wsc_beacon(pCtx, pSrc, &nNeeded); + if (!DOT11F_SUCCEEDED(status)) + return status; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + (void)pCtx; + if (pSrc->present) { + do { + nConsumedSoFar = *pnConsumed; + *pBuf = 221; + ++pBuf; --nBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x0; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x50; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0xf2; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x4; + ++pBuf; --nBuf; ++(*pnConsumed); + n = (255 - 4) < nBuf ? (255 - 4) : nBuf; + nConsumedNow = *pnConsumed; + idxlast = idx; + status = pack_tlv_core(pCtx, (uint8_t *)pSrc, pBuf, n, + pnConsumed, + TLVS_WscBeacon + + idx, &idx); + nConsumedNow = *pnConsumed - nConsumedNow; + *pIeLen = *pnConsumed - nConsumedSoFar - 2; + pBuf += nConsumedNow; + nBuf -= nConsumedNow; + } while (DOT11F_BUFFER_OVERFLOW == status && idxlast != idx); + } + return status; +} /* End dot11f_pack_ie_wsc_beacon. */ + +uint32_t dot11f_pack_ie_wsc_beacon_probe_res(tpAniSirGlobal pCtx, + tDot11fIEWscBeaconProbeRes *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t n, idx = 0, idxlast; + uint32_t nConsumedSoFar, nConsumedNow; + uint32_t status = DOT11F_PARSE_SUCCESS; + uint32_t nNeeded = 0U; + status = dot11f_get_packed_ie_wsc_beacon_probe_res(pCtx, pSrc, &nNeeded); + if (!DOT11F_SUCCEEDED(status)) + return status; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + (void)pCtx; + if (pSrc->present) { + do { + nConsumedSoFar = *pnConsumed; + *pBuf = 221; + ++pBuf; --nBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x0; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x50; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0xf2; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x4; + ++pBuf; --nBuf; ++(*pnConsumed); + n = (255 - 4) < nBuf ? (255 - 4) : nBuf; + nConsumedNow = *pnConsumed; + idxlast = idx; + status = pack_tlv_core(pCtx, (uint8_t *)pSrc, pBuf, n, + pnConsumed, + TLVS_WscBeaconProbeRes + + idx, &idx); + nConsumedNow = *pnConsumed - nConsumedNow; + *pIeLen = *pnConsumed - nConsumedSoFar - 2; + pBuf += nConsumedNow; + nBuf -= nConsumedNow; + } while (DOT11F_BUFFER_OVERFLOW == status && idxlast != idx); + } + return status; +} /* End dot11f_pack_ie_wsc_beacon_probe_res. */ + +uint32_t dot11f_pack_ie_wsc_ie_opaque(tpAniSirGlobal pCtx, + tDot11fIEWscIEOpaque *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += pSrc->num_data; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 221; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x0; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x50; + ++pBuf; ++(*pnConsumed); + *pBuf = 0xf2; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x4; + ++pBuf; ++(*pnConsumed); + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->data), pSrc->num_data); + *pnConsumed += pSrc->num_data; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_wsc_ie_opaque. */ + +uint32_t dot11f_pack_ie_wsc_probe_req(tpAniSirGlobal pCtx, + tDot11fIEWscProbeReq *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t n, idx = 0, idxlast; + uint32_t nConsumedSoFar, nConsumedNow; + uint32_t status = DOT11F_PARSE_SUCCESS; + uint32_t nNeeded = 0U; + status = dot11f_get_packed_ie_wsc_probe_req(pCtx, pSrc, &nNeeded); + if (!DOT11F_SUCCEEDED(status)) + return status; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + (void)pCtx; + if (pSrc->present) { + do { + nConsumedSoFar = *pnConsumed; + *pBuf = 221; + ++pBuf; --nBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x0; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x50; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0xf2; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x4; + ++pBuf; --nBuf; ++(*pnConsumed); + n = (255 - 4) < nBuf ? (255 - 4) : nBuf; + nConsumedNow = *pnConsumed; + idxlast = idx; + status = pack_tlv_core(pCtx, (uint8_t *)pSrc, pBuf, n, + pnConsumed, + TLVS_WscProbeReq + + idx, &idx); + nConsumedNow = *pnConsumed - nConsumedNow; + *pIeLen = *pnConsumed - nConsumedSoFar - 2; + pBuf += nConsumedNow; + nBuf -= nConsumedNow; + } while (DOT11F_BUFFER_OVERFLOW == status && idxlast != idx); + } + return status; +} /* End dot11f_pack_ie_wsc_probe_req. */ + +uint32_t dot11f_pack_ie_wsc_probe_res(tpAniSirGlobal pCtx, + tDot11fIEWscProbeRes *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t n, idx = 0, idxlast; + uint32_t nConsumedSoFar, nConsumedNow; + uint32_t status = DOT11F_PARSE_SUCCESS; + uint32_t nNeeded = 0U; + status = dot11f_get_packed_ie_wsc_probe_res(pCtx, pSrc, &nNeeded); + if (!DOT11F_SUCCEEDED(status)) + return status; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + (void)pCtx; + if (pSrc->present) { + do { + nConsumedSoFar = *pnConsumed; + *pBuf = 221; + ++pBuf; --nBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x0; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x50; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0xf2; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x4; + ++pBuf; --nBuf; ++(*pnConsumed); + n = (255 - 4) < nBuf ? (255 - 4) : nBuf; + nConsumedNow = *pnConsumed; + idxlast = idx; + status = pack_tlv_core(pCtx, (uint8_t *)pSrc, pBuf, n, + pnConsumed, + TLVS_WscProbeRes + + idx, &idx); + nConsumedNow = *pnConsumed - nConsumedNow; + *pIeLen = *pnConsumed - nConsumedSoFar - 2; + pBuf += nConsumedNow; + nBuf -= nConsumedNow; + } while (DOT11F_BUFFER_OVERFLOW == status && idxlast != idx); + } + return status; +} /* End dot11f_pack_ie_wsc_probe_res. */ + +uint32_t dot11f_pack_ie_wsc_reassoc_res(tpAniSirGlobal pCtx, + tDot11fIEWscReassocRes *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t n, idx = 0, idxlast; + uint32_t nConsumedSoFar, nConsumedNow; + uint32_t status = DOT11F_PARSE_SUCCESS; + uint32_t nNeeded = 0U; + status = dot11f_get_packed_ie_wsc_reassoc_res(pCtx, pSrc, &nNeeded); + if (!DOT11F_SUCCEEDED(status)) + return status; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + (void)pCtx; + if (pSrc->present) { + do { + nConsumedSoFar = *pnConsumed; + *pBuf = 221; + ++pBuf; --nBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x0; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x50; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0xf2; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x4; + ++pBuf; --nBuf; ++(*pnConsumed); + n = (255 - 4) < nBuf ? (255 - 4) : nBuf; + nConsumedNow = *pnConsumed; + idxlast = idx; + status = pack_tlv_core(pCtx, (uint8_t *)pSrc, pBuf, n, + pnConsumed, + TLVS_WscReassocRes + + idx, &idx); + nConsumedNow = *pnConsumed - nConsumedNow; + *pIeLen = *pnConsumed - nConsumedSoFar - 2; + pBuf += nConsumedNow; + nBuf -= nConsumedNow; + } while (DOT11F_BUFFER_OVERFLOW == status && idxlast != idx); + } + return status; +} /* End dot11f_pack_ie_wsc_reassoc_res. */ + +uint32_t dot11f_pack_ie_ext_chan_switch_ann(tpAniSirGlobal pCtx, + tDot11fIEext_chan_switch_ann *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 4; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 60; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->switch_mode; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->new_reg_class; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->new_channel; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->switch_count; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_ext_chan_switch_ann. */ + +uint32_t dot11f_pack_ie_hs20vendor_ie(tpAniSirGlobal pCtx, + tDot11fIEhs20vendor_ie *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint8_t tmp138__; + uint32_t status = DOT11F_PARSE_SUCCESS; + status = dot11f_get_packed_ie_hs20vendor_ie(pCtx, pSrc, &nNeeded); + if (!DOT11F_SUCCEEDED(status)) + return status; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 221; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x50; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x6f; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x9a; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x10; + ++pBuf; ++(*pnConsumed); + tmp138__ = 0U; + tmp138__ |= (pSrc->dgaf_dis << 0); + tmp138__ |= (pSrc->hs_id_present << 1); + tmp138__ |= (pSrc->reserved << 3); + tmp138__ |= (pSrc->release_num << 4); + *pBuf = tmp138__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + if (pSrc->hs_id_present) { + switch (pSrc->hs_id_present) { + case 1: + frameshtons(pCtx, pBuf, pSrc->hs_id.pps_mo.pps_mo_id, 0); + *pnConsumed += 2; + /* fieldsEndFlag = 1 */ + break; + case 2: + frameshtons(pCtx, pBuf, pSrc->hs_id.anqp_domain.anqp_domain_id, 0); + *pnConsumed += 2; + /* fieldsEndFlag = 1 */ + break; + } + } else { + break; + } + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return status; +} /* End dot11f_pack_ie_hs20vendor_ie. */ + +uint32_t dot11f_pack_ie_ht2040_bss_coexistence(tpAniSirGlobal pCtx, + tDot11fIEht2040_bss_coexistence *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint8_t tmp139__; + nNeeded += 1; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 72; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + tmp139__ = 0U; + tmp139__ |= (pSrc->info_request << 0); + tmp139__ |= (pSrc->forty_mhz_intolerant << 1); + tmp139__ |= (pSrc->twenty_mhz_bsswidth_req << 2); + tmp139__ |= (pSrc->obss_scan_exemption_req << 3); + tmp139__ |= (pSrc->obss_scan_exemption_grant << 4); + tmp139__ |= (pSrc->unused << 5); + *pBuf = tmp139__; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + nBuf -= 1 ; + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_ht2040_bss_coexistence. */ + +uint32_t dot11f_pack_ie_ht2040_bss_intolerant_report(tpAniSirGlobal pCtx, + tDot11fIEht2040_bss_intolerant_report *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += (pSrc->num_channel_list + 1); + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 73; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->operating_class; + *pnConsumed += 1; + pBuf += 1; + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->channel_list), pSrc->num_channel_list); + *pnConsumed += pSrc->num_channel_list; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_ht2040_bss_intolerant_report. */ + +uint32_t dot11f_pack_ie_sec_chan_offset_ele(tpAniSirGlobal pCtx, + tDot11fIEsec_chan_offset_ele *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 1; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 62; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->secondaryChannelOffset; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_sec_chan_offset_ele. */ + +uint32_t dot11f_pack_ie_vendor_vht_ie(tpAniSirGlobal pCtx, + tDot11fIEvendor_vht_ie *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint32_t status = DOT11F_PARSE_SUCCESS; + status = dot11f_get_packed_ie_vendor_vht_ie(pCtx, pSrc, &nNeeded); + if (!DOT11F_SUCCEEDED(status)) + return status; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 221; + ++pBuf; --nBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x0; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x90; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x4c; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = pSrc->type; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->sub_type; + *pnConsumed += 1; + pBuf += 1; + status = pack_core(pCtx, + (uint8_t *)pSrc, + pBuf, + nBuf, + pnConsumed, + FFS_vendor_vht_ie, + IES_vendor_vht_ie); + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return status; +} /* End dot11f_pack_ie_vendor_vht_ie. */ + +uint32_t dot11f_pack_add_ts_request(tpAniSirGlobal pCtx, + tDot11fAddTSRequest *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_AddTSRequest, IES_AddTSRequest); + + return status; + +} /* End dot11f_unpack_add_ts_request. */ + +uint32_t dot11f_pack_add_ts_response(tpAniSirGlobal pCtx, + tDot11fAddTSResponse *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_AddTSResponse, IES_AddTSResponse); + + return status; + +} /* End dot11f_unpack_add_ts_response. */ + +uint32_t dot11f_pack_assoc_request(tpAniSirGlobal pCtx, + tDot11fAssocRequest *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_AssocRequest, IES_AssocRequest); + + return status; + +} /* End dot11f_unpack_assoc_request. */ + +uint32_t dot11f_pack_assoc_response(tpAniSirGlobal pCtx, + tDot11fAssocResponse *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_AssocResponse, IES_AssocResponse); + + return status; + +} /* End dot11f_unpack_assoc_response. */ + +uint32_t dot11f_pack_authentication(tpAniSirGlobal pCtx, + tDot11fAuthentication *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_Authentication, IES_Authentication); + + return status; + +} /* End dot11f_unpack_authentication. */ + +uint32_t dot11f_pack_beacon(tpAniSirGlobal pCtx, + tDot11fBeacon *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_Beacon, IES_Beacon); + + return status; + +} /* End dot11f_unpack_beacon. */ + +uint32_t dot11f_pack_beacon1(tpAniSirGlobal pCtx, + tDot11fBeacon1 *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_Beacon1, IES_Beacon1); + + return status; + +} /* End dot11f_unpack_beacon1. */ + +uint32_t dot11f_pack_beacon2(tpAniSirGlobal pCtx, + tDot11fBeacon2 *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_Beacon2, IES_Beacon2); + + return status; + +} /* End dot11f_unpack_beacon2. */ + +uint32_t dot11f_pack_beacon_i_es(tpAniSirGlobal pCtx, + tDot11fBeaconIEs *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_BeaconIEs, IES_BeaconIEs); + + return status; + +} /* End dot11f_unpack_beacon_i_es. */ + +uint32_t dot11f_pack_channel_switch(tpAniSirGlobal pCtx, + tDot11fChannelSwitch *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_ChannelSwitch, IES_ChannelSwitch); + + return status; + +} /* End dot11f_unpack_channel_switch. */ + +uint32_t dot11f_pack_de_auth(tpAniSirGlobal pCtx, + tDot11fDeAuth *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_DeAuth, IES_DeAuth); + + return status; + +} /* End dot11f_unpack_de_auth. */ + +uint32_t dot11f_pack_del_ts(tpAniSirGlobal pCtx, + tDot11fDelTS *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_DelTS, IES_DelTS); + + return status; + +} /* End dot11f_unpack_del_ts. */ + +uint32_t dot11f_pack_disassociation(tpAniSirGlobal pCtx, + tDot11fDisassociation *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_Disassociation, IES_Disassociation); + + return status; + +} /* End dot11f_unpack_disassociation. */ + +uint32_t dot11f_pack_link_measurement_report(tpAniSirGlobal pCtx, + tDot11fLinkMeasurementReport *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_LinkMeasurementReport, IES_LinkMeasurementReport); + + return status; + +} /* End dot11f_unpack_link_measurement_report. */ + +uint32_t dot11f_pack_link_measurement_request(tpAniSirGlobal pCtx, + tDot11fLinkMeasurementRequest *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_LinkMeasurementRequest, IES_LinkMeasurementRequest); + + return status; + +} /* End dot11f_unpack_link_measurement_request. */ + +uint32_t dot11f_pack_measurement_report(tpAniSirGlobal pCtx, + tDot11fMeasurementReport *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_MeasurementReport, IES_MeasurementReport); + + return status; + +} /* End dot11f_unpack_measurement_report. */ + +uint32_t dot11f_pack_measurement_request(tpAniSirGlobal pCtx, + tDot11fMeasurementRequest *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_MeasurementRequest, IES_MeasurementRequest); + + return status; + +} /* End dot11f_unpack_measurement_request. */ + +uint32_t dot11f_pack_neighbor_report_request(tpAniSirGlobal pCtx, + tDot11fNeighborReportRequest *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_NeighborReportRequest, IES_NeighborReportRequest); + + return status; + +} /* End dot11f_unpack_neighbor_report_request. */ + +uint32_t dot11f_pack_neighbor_report_response(tpAniSirGlobal pCtx, + tDot11fNeighborReportResponse *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_NeighborReportResponse, IES_NeighborReportResponse); + + return status; + +} /* End dot11f_unpack_neighbor_report_response. */ + +uint32_t dot11f_pack_operating_mode(tpAniSirGlobal pCtx, + tDot11fOperatingMode *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_OperatingMode, IES_OperatingMode); + + return status; + +} /* End dot11f_unpack_operating_mode. */ + +uint32_t dot11f_pack_probe_request(tpAniSirGlobal pCtx, + tDot11fProbeRequest *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_ProbeRequest, IES_ProbeRequest); + + return status; + +} /* End dot11f_unpack_probe_request. */ + +uint32_t dot11f_pack_probe_response(tpAniSirGlobal pCtx, + tDot11fProbeResponse *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_ProbeResponse, IES_ProbeResponse); + + return status; + +} /* End dot11f_unpack_probe_response. */ + +uint32_t dot11f_pack_qos_map_configure(tpAniSirGlobal pCtx, + tDot11fQosMapConfigure *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_QosMapConfigure, IES_QosMapConfigure); + + return status; + +} /* End dot11f_unpack_qos_map_configure. */ + +uint32_t dot11f_pack_radio_measurement_report(tpAniSirGlobal pCtx, + tDot11fRadioMeasurementReport *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_RadioMeasurementReport, IES_RadioMeasurementReport); + + return status; + +} /* End dot11f_unpack_radio_measurement_report. */ + +uint32_t dot11f_pack_radio_measurement_request(tpAniSirGlobal pCtx, + tDot11fRadioMeasurementRequest *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_RadioMeasurementRequest, IES_RadioMeasurementRequest); + + return status; + +} /* End dot11f_unpack_radio_measurement_request. */ + +uint32_t dot11f_pack_re_assoc_request(tpAniSirGlobal pCtx, + tDot11fReAssocRequest *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_ReAssocRequest, IES_ReAssocRequest); + + return status; + +} /* End dot11f_unpack_re_assoc_request. */ + +uint32_t dot11f_pack_re_assoc_response(tpAniSirGlobal pCtx, + tDot11fReAssocResponse *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_ReAssocResponse, IES_ReAssocResponse); + + return status; + +} /* End dot11f_unpack_re_assoc_response. */ + +uint32_t dot11f_pack_sm_power_save(tpAniSirGlobal pCtx, + tDot11fSMPowerSave *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_SMPowerSave, IES_SMPowerSave); + + return status; + +} /* End dot11f_unpack_sm_power_save. */ + +uint32_t dot11f_pack_sa_query_req(tpAniSirGlobal pCtx, + tDot11fSaQueryReq *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_SaQueryReq, IES_SaQueryReq); + + return status; + +} /* End dot11f_unpack_sa_query_req. */ + +uint32_t dot11f_pack_sa_query_rsp(tpAniSirGlobal pCtx, + tDot11fSaQueryRsp *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_SaQueryRsp, IES_SaQueryRsp); + + return status; + +} /* End dot11f_unpack_sa_query_rsp. */ + +uint32_t dot11f_pack_tdls_dis_req(tpAniSirGlobal pCtx, + tDot11fTDLSDisReq *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_TDLSDisReq, IES_TDLSDisReq); + + return status; + +} /* End dot11f_unpack_tdls_dis_req. */ + +uint32_t dot11f_pack_tdls_dis_rsp(tpAniSirGlobal pCtx, + tDot11fTDLSDisRsp *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_TDLSDisRsp, IES_TDLSDisRsp); + + return status; + +} /* End dot11f_unpack_tdls_dis_rsp. */ + +uint32_t dot11f_pack_tdls_peer_traffic_ind(tpAniSirGlobal pCtx, + tDot11fTDLSPeerTrafficInd *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_TDLSPeerTrafficInd, IES_TDLSPeerTrafficInd); + + return status; + +} /* End dot11f_unpack_tdls_peer_traffic_ind. */ + +uint32_t dot11f_pack_tdls_peer_traffic_rsp(tpAniSirGlobal pCtx, + tDot11fTDLSPeerTrafficRsp *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_TDLSPeerTrafficRsp, IES_TDLSPeerTrafficRsp); + + return status; + +} /* End dot11f_unpack_tdls_peer_traffic_rsp. */ + +uint32_t dot11f_pack_tdls_setup_cnf(tpAniSirGlobal pCtx, + tDot11fTDLSSetupCnf *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_TDLSSetupCnf, IES_TDLSSetupCnf); + + return status; + +} /* End dot11f_unpack_tdls_setup_cnf. */ + +uint32_t dot11f_pack_tdls_setup_req(tpAniSirGlobal pCtx, + tDot11fTDLSSetupReq *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_TDLSSetupReq, IES_TDLSSetupReq); + + return status; + +} /* End dot11f_unpack_tdls_setup_req. */ + +uint32_t dot11f_pack_tdls_setup_rsp(tpAniSirGlobal pCtx, + tDot11fTDLSSetupRsp *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_TDLSSetupRsp, IES_TDLSSetupRsp); + + return status; + +} /* End dot11f_unpack_tdls_setup_rsp. */ + +uint32_t dot11f_pack_tdls_teardown(tpAniSirGlobal pCtx, + tDot11fTDLSTeardown *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_TDLSTeardown, IES_TDLSTeardown); + + return status; + +} /* End dot11f_unpack_tdls_teardown. */ + +uint32_t dot11f_pack_tpc_report(tpAniSirGlobal pCtx, + tDot11fTPCReport *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_TPCReport, IES_TPCReport); + + return status; + +} /* End dot11f_unpack_tpc_report. */ + +uint32_t dot11f_pack_tpc_request(tpAniSirGlobal pCtx, + tDot11fTPCRequest *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_TPCRequest, IES_TPCRequest); + + return status; + +} /* End dot11f_unpack_tpc_request. */ + +uint32_t dot11f_pack_timing_advertisement_frame(tpAniSirGlobal pCtx, + tDot11fTimingAdvertisementFrame *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_TimingAdvertisementFrame, IES_TimingAdvertisementFrame); + + return status; + +} /* End dot11f_unpack_timing_advertisement_frame. */ + +uint32_t dot11f_pack_vht_gid_management_action_frame(tpAniSirGlobal pCtx, + tDot11fVHTGidManagementActionFrame *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_VHTGidManagementActionFrame, IES_VHTGidManagementActionFrame); + + return status; + +} /* End dot11f_unpack_vht_gid_management_action_frame. */ + +uint32_t dot11f_pack_wmm_add_ts_request(tpAniSirGlobal pCtx, + tDot11fWMMAddTSRequest *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_WMMAddTSRequest, IES_WMMAddTSRequest); + + return status; + +} /* End dot11f_unpack_wmm_add_ts_request. */ + +uint32_t dot11f_pack_wmm_add_ts_response(tpAniSirGlobal pCtx, + tDot11fWMMAddTSResponse *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_WMMAddTSResponse, IES_WMMAddTSResponse); + + return status; + +} /* End dot11f_unpack_wmm_add_ts_response. */ + +uint32_t dot11f_pack_wmm_del_ts(tpAniSirGlobal pCtx, + tDot11fWMMDelTS *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_WMMDelTS, IES_WMMDelTS); + + return status; + +} /* End dot11f_unpack_wmm_del_ts. */ + +uint32_t dot11f_pack_ext_channel_switch_action_frame(tpAniSirGlobal pCtx, + tDot11fext_channel_switch_action_frame *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_ext_channel_switch_action_frame, IES_ext_channel_switch_action_frame); + + return status; + +} /* End dot11f_unpack_ext_channel_switch_action_frame. */ + +uint32_t dot11f_pack_ht2040_bss_coexistence_mgmt_action_frame(tpAniSirGlobal pCtx, + tDot11fht2040_bss_coexistence_mgmt_action_frame *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_ht2040_bss_coexistence_mgmt_action_frame, IES_ht2040_bss_coexistence_mgmt_action_frame); + + return status; + +} /* End dot11f_unpack_ht2040_bss_coexistence_mgmt_action_frame. */ + +uint32_t dot11f_pack_p2p_oper_chan_change_confirm(tpAniSirGlobal pCtx, + tDot11fp2p_oper_chan_change_confirm *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_p2p_oper_chan_change_confirm, IES_p2p_oper_chan_change_confirm); + + return status; + +} /* End dot11f_unpack_p2p_oper_chan_change_confirm. */ + +static uint32_t pack_core(tpAniSirGlobal pCtx, + uint8_t *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed, + const tFFDefn FFs[], + const tIEDefn IEs[]) +{ + const tFFDefn *pFf; + const tIEDefn *pIe; + tFRAMES_BOOL *pfFound; + uint8_t *pBufRemaining; + uint16_t i; + uint32_t nBufRemaining, status, len; + uint32_t countOffset = 0; + + (void)pCtx; /* Shutup the compiler if we have no FFs nor IEs... */ + i = 0; + + DOT11F_PARAMETER_CHECK2(pSrc, pBuf, nBuf, pnConsumed); + + status = DOT11F_PARSE_SUCCESS; + pBufRemaining = pBuf; + nBufRemaining = nBuf; + + pFf = &(FFs[0]); + while (pFf->size) { + if (pFf->size > nBufRemaining) { + FRAMES_LOG3(pCtx, FRLOGE, FRFL("The Fixed Field %s req" + "uires %d bytes, but there are only %d remaining.\n"), + pFf->name, pFf->size, nBufRemaining); + return DOT11F_BUFFER_OVERFLOW; + } + + switch (pFf->sig) { + case SigFfAID: + dot11f_pack_ff_aid( + pCtx, (tDot11fFfAID *) + (pSrc + pFf->offset), pBufRemaining); + break; + case SigFfAction: + dot11f_pack_ff_action( + pCtx, (tDot11fFfAction *) + (pSrc + pFf->offset), pBufRemaining); + break; + case SigFfAuthAlgo: + dot11f_pack_ff_auth_algo( + pCtx, (tDot11fFfAuthAlgo *) + (pSrc + pFf->offset), pBufRemaining); + break; + case SigFfAuthSeqNo: + dot11f_pack_ff_auth_seq_no( + pCtx, (tDot11fFfAuthSeqNo *) + (pSrc + pFf->offset), pBufRemaining); + break; + case SigFfBeaconInterval: + dot11f_pack_ff_beacon_interval( + pCtx, (tDot11fFfBeaconInterval *) + (pSrc + pFf->offset), pBufRemaining); + break; + case SigFfCapabilities: + dot11f_pack_ff_capabilities( + pCtx, (tDot11fFfCapabilities *) + (pSrc + pFf->offset), pBufRemaining); + break; + case SigFfCategory: + dot11f_pack_ff_category( + pCtx, (tDot11fFfCategory *) + (pSrc + pFf->offset), pBufRemaining); + break; + case SigFfCurrentAPAddress: + dot11f_pack_ff_current_ap_address( + pCtx, (tDot11fFfCurrentAPAddress *) + (pSrc + pFf->offset), pBufRemaining); + break; + case SigFfDialogToken: + dot11f_pack_ff_dialog_token( + pCtx, (tDot11fFfDialogToken *) + (pSrc + pFf->offset), pBufRemaining); + break; + case SigFfLinkMargin: + dot11f_pack_ff_link_margin( + pCtx, (tDot11fFfLinkMargin *) + (pSrc + pFf->offset), pBufRemaining); + break; + case SigFfListenInterval: + dot11f_pack_ff_listen_interval( + pCtx, (tDot11fFfListenInterval *) + (pSrc + pFf->offset), pBufRemaining); + break; + case SigFfMaxTxPower: + dot11f_pack_ff_max_tx_power( + pCtx, (tDot11fFfMaxTxPower *) + (pSrc + pFf->offset), pBufRemaining); + break; + case SigFfNumOfRepetitions: + dot11f_pack_ff_num_of_repetitions( + pCtx, (tDot11fFfNumOfRepetitions *) + (pSrc + pFf->offset), pBufRemaining); + break; + case SigFfOperatingMode: + dot11f_pack_ff_operating_mode( + pCtx, (tDot11fFfOperatingMode *) + (pSrc + pFf->offset), pBufRemaining); + break; + case SigFfRCPI: + dot11f_pack_ff_rcpi( + pCtx, (tDot11fFfRCPI *) + (pSrc + pFf->offset), pBufRemaining); + break; + case SigFfRSNI: + dot11f_pack_ff_rsni( + pCtx, (tDot11fFfRSNI *) + (pSrc + pFf->offset), pBufRemaining); + break; + case SigFfReason: + dot11f_pack_ff_reason( + pCtx, (tDot11fFfReason *) + (pSrc + pFf->offset), pBufRemaining); + break; + case SigFfRxAntennaId: + dot11f_pack_ff_rx_antenna_id( + pCtx, (tDot11fFfRxAntennaId *) + (pSrc + pFf->offset), pBufRemaining); + break; + case SigFfSMPowerModeSet: + dot11f_pack_ff_sm_power_mode_set( + pCtx, (tDot11fFfSMPowerModeSet *) + (pSrc + pFf->offset), pBufRemaining); + break; + case SigFfStatus: + dot11f_pack_ff_status( + pCtx, (tDot11fFfStatus *) + (pSrc + pFf->offset), pBufRemaining); + break; + case SigFfStatusCode: + dot11f_pack_ff_status_code( + pCtx, (tDot11fFfStatusCode *) + (pSrc + pFf->offset), pBufRemaining); + break; + case SigFfTPCEleID: + dot11f_pack_ff_tpc_ele_id( + pCtx, (tDot11fFfTPCEleID *) + (pSrc + pFf->offset), pBufRemaining); + break; + case SigFfTPCEleLen: + dot11f_pack_ff_tpc_ele_len( + pCtx, (tDot11fFfTPCEleLen *) + (pSrc + pFf->offset), pBufRemaining); + break; + case SigFfTSInfo: + dot11f_pack_ff_ts_info( + pCtx, (tDot11fFfTSInfo *) + (pSrc + pFf->offset), pBufRemaining); + break; + case SigFfTimeStamp: + dot11f_pack_ff_time_stamp( + pCtx, (tDot11fFfTimeStamp *) + (pSrc + pFf->offset), pBufRemaining); + break; + case SigFfTransactionId: + dot11f_pack_ff_transaction_id( + pCtx, (tDot11fFfTransactionId *) + (pSrc + pFf->offset), pBufRemaining); + break; + case SigFfTxAntennaId: + dot11f_pack_ff_tx_antenna_id( + pCtx, (tDot11fFfTxAntennaId *) + (pSrc + pFf->offset), pBufRemaining); + break; + case SigFfTxPower: + dot11f_pack_ff_tx_power( + pCtx, (tDot11fFfTxPower *) + (pSrc + pFf->offset), pBufRemaining); + break; + case SigFfVhtMembershipStatusArray: + dot11f_pack_ff_vht_membership_status_array( + pCtx, (tDot11fFfVhtMembershipStatusArray *) + (pSrc + pFf->offset), pBufRemaining); + break; + case SigFfVhtUserPositionArray: + dot11f_pack_ff_vht_user_position_array( + pCtx, (tDot11fFfVhtUserPositionArray *) + (pSrc + pFf->offset), pBufRemaining); + break; + case SigFfext_chan_switch_ann_action: + dot11f_pack_ff_ext_chan_switch_ann_action( + pCtx, (tDot11fFfext_chan_switch_ann_action *) + (pSrc + pFf->offset), pBufRemaining); + break; + case SigFfp2p_action_oui: + dot11f_pack_ff_p2p_action_oui( + pCtx, (tDot11fFfp2p_action_oui *) + (pSrc + pFf->offset), pBufRemaining); + break; + case SigFfp2p_action_subtype: + dot11f_pack_ff_p2p_action_subtype( + pCtx, (tDot11fFfp2p_action_subtype *) + (pSrc + pFf->offset), pBufRemaining); + break; + default: + FRAMES_LOG1(pCtx, FRLOGE, FRFL("INTERNAL ERROR-- I don" + "'t know about the Fixed Field %d; this is most l" + "ikely a bug in 'framesg'.\n"), pFf->sig); + return DOT11F_INTERNAL_ERROR; + } + + pBufRemaining += pFf->size; + nBufRemaining -= pFf->size; + *pnConsumed += pFf->size; + ++pFf; + + } + + pIe = &(IEs[0]); + while (0xff != pIe->eid) { + pfFound = (tFRAMES_BOOL *)(pSrc + pIe->offset + + pIe->presenceOffset); + if (*pfFound && pIe->minSize > nBufRemaining) { + FRAMES_LOG3(pCtx, FRLOGE, FRFL("The IE %s takes at le" + "ast %d bytes, but there are only %d left in the b" + "uffer.\n"), pIe->name, pIe->minSize, nBufRemaining); + return DOT11F_BUFFER_OVERFLOW; + } + + + countOffset = ((0 == pIe->arraybound) ? 1 : *(uint16_t *)(pSrc + pIe->countOffset)); + for (i = 0; i < countOffset; ++i) { + len = 0U; + switch (pIe->sig) { + case SigIeGTK: + status |= + dot11f_pack_ie_gtk( + pCtx, (tDot11fIEGTK *) + (pSrc + pIe->offset + + sizeof(tDot11fIEGTK) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeIGTK: + status |= + dot11f_pack_ie_igtk( + pCtx, (tDot11fIEIGTK *) + (pSrc + pIe->offset + + sizeof(tDot11fIEIGTK) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeR0KH_ID: + status |= + dot11f_pack_ie_r0_kh_id( + pCtx, (tDot11fIER0KH_ID *) + (pSrc + pIe->offset + + sizeof(tDot11fIER0KH_ID) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeR1KH_ID: + status |= + dot11f_pack_ie_r1_kh_id( + pCtx, (tDot11fIER1KH_ID *) + (pSrc + pIe->offset + + sizeof(tDot11fIER1KH_ID) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeAPChannelReport: + status |= + dot11f_pack_ie_ap_channel_report( + pCtx, (tDot11fIEAPChannelReport *) + (pSrc + pIe->offset + + sizeof(tDot11fIEAPChannelReport) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeBcnReportingDetail: + status |= + dot11f_pack_ie_bcn_reporting_detail( + pCtx, (tDot11fIEBcnReportingDetail *) + (pSrc + pIe->offset + + sizeof(tDot11fIEBcnReportingDetail) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeBeaconReportFrmBody: + status |= + dot11f_pack_ie_beacon_report_frm_body( + pCtx, (tDot11fIEBeaconReportFrmBody *) + (pSrc + pIe->offset + + sizeof(tDot11fIEBeaconReportFrmBody) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeBeaconReporting: + status |= + dot11f_pack_ie_beacon_reporting( + pCtx, (tDot11fIEBeaconReporting *) + (pSrc + pIe->offset + + sizeof(tDot11fIEBeaconReporting) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeCondensedCountryStr: + status |= + dot11f_pack_ie_condensed_country_str( + pCtx, (tDot11fIECondensedCountryStr *) + (pSrc + pIe->offset + + sizeof(tDot11fIECondensedCountryStr) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeMeasurementPilot: + status |= + dot11f_pack_ie_measurement_pilot( + pCtx, (tDot11fIEMeasurementPilot *) + (pSrc + pIe->offset + + sizeof(tDot11fIEMeasurementPilot) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeMultiBssid: + status |= + dot11f_pack_ie_multi_bssid( + pCtx, (tDot11fIEMultiBssid *) + (pSrc + pIe->offset + + sizeof(tDot11fIEMultiBssid) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeRICData: + status |= + dot11f_pack_ie_ric_data( + pCtx, (tDot11fIERICData *) + (pSrc + pIe->offset + + sizeof(tDot11fIERICData) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeRICDescriptor: + status |= + dot11f_pack_ie_ric_descriptor( + pCtx, (tDot11fIERICDescriptor *) + (pSrc + pIe->offset + + sizeof(tDot11fIERICDescriptor) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeRRMEnabledCap: + status |= + dot11f_pack_ie_rrm_enabled_cap( + pCtx, (tDot11fIERRMEnabledCap *) + (pSrc + pIe->offset + + sizeof(tDot11fIERRMEnabledCap) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeRequestedInfo: + status |= + dot11f_pack_ie_requested_info( + pCtx, (tDot11fIERequestedInfo *) + (pSrc + pIe->offset + + sizeof(tDot11fIERequestedInfo) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeSSID: + status |= + dot11f_pack_ie_ssid( + pCtx, (tDot11fIESSID *) + (pSrc + pIe->offset + + sizeof(tDot11fIESSID) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeSchedule: + status |= + dot11f_pack_ie_schedule( + pCtx, (tDot11fIESchedule *) + (pSrc + pIe->offset + + sizeof(tDot11fIESchedule) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeTCLAS: + status |= + dot11f_pack_ie_tclas( + pCtx, (tDot11fIETCLAS *) + (pSrc + pIe->offset + + sizeof(tDot11fIETCLAS) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeTCLASSPROC: + status |= + dot11f_pack_ie_tclassproc( + pCtx, (tDot11fIETCLASSPROC *) + (pSrc + pIe->offset + + sizeof(tDot11fIETCLASSPROC) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeTSDelay: + status |= + dot11f_pack_ie_ts_delay( + pCtx, (tDot11fIETSDelay *) + (pSrc + pIe->offset + + sizeof(tDot11fIETSDelay) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeTSFInfo: + status |= + dot11f_pack_ie_tsf_info( + pCtx, (tDot11fIETSFInfo *) + (pSrc + pIe->offset + + sizeof(tDot11fIETSFInfo) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeTSPEC: + status |= + dot11f_pack_ie_tspec( + pCtx, (tDot11fIETSPEC *) + (pSrc + pIe->offset + + sizeof(tDot11fIETSPEC) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeVHTCaps: + status |= + dot11f_pack_ie_vht_caps( + pCtx, (tDot11fIEVHTCaps *) + (pSrc + pIe->offset + + sizeof(tDot11fIEVHTCaps) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeVHTOperation: + status |= + dot11f_pack_ie_vht_operation( + pCtx, (tDot11fIEVHTOperation *) + (pSrc + pIe->offset + + sizeof(tDot11fIEVHTOperation) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeWMMSchedule: + status |= + dot11f_pack_ie_wmm_schedule( + pCtx, (tDot11fIEWMMSchedule *) + (pSrc + pIe->offset + + sizeof(tDot11fIEWMMSchedule) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeWMMTCLAS: + status |= + dot11f_pack_ie_wmmtclas( + pCtx, (tDot11fIEWMMTCLAS *) + (pSrc + pIe->offset + + sizeof(tDot11fIEWMMTCLAS) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeWMMTCLASPROC: + status |= + dot11f_pack_ie_wmmtclasproc( + pCtx, (tDot11fIEWMMTCLASPROC *) + (pSrc + pIe->offset + + sizeof(tDot11fIEWMMTCLASPROC) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeWMMTSDelay: + status |= + dot11f_pack_ie_wmmts_delay( + pCtx, (tDot11fIEWMMTSDelay *) + (pSrc + pIe->offset + + sizeof(tDot11fIEWMMTSDelay) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeWMMTSPEC: + status |= + dot11f_pack_ie_wmmtspec( + pCtx, (tDot11fIEWMMTSPEC *) + (pSrc + pIe->offset + + sizeof(tDot11fIEWMMTSPEC) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeWiderBWChanSwitchAnn: + status |= + dot11f_pack_ie_wider_bw_chan_switch_ann( + pCtx, (tDot11fIEWiderBWChanSwitchAnn *) + (pSrc + pIe->offset + + sizeof(tDot11fIEWiderBWChanSwitchAnn) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeazimuth_req: + status |= + dot11f_pack_ie_azimuth_req( + pCtx, (tDot11fIEazimuth_req *) + (pSrc + pIe->offset + + sizeof(tDot11fIEazimuth_req) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIemax_age: + status |= + dot11f_pack_ie_max_age( + pCtx, (tDot11fIEmax_age *) + (pSrc + pIe->offset + + sizeof(tDot11fIEmax_age) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeneighbor_rpt: + status |= + dot11f_pack_ie_neighbor_rpt( + pCtx, (tDot11fIEneighbor_rpt *) + (pSrc + pIe->offset + + sizeof(tDot11fIEneighbor_rpt) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIereq_mac_addr: + status |= + dot11f_pack_ie_req_mac_addr( + pCtx, (tDot11fIEreq_mac_addr *) + (pSrc + pIe->offset + + sizeof(tDot11fIEreq_mac_addr) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIetgt_mac_addr: + status |= + dot11f_pack_ie_tgt_mac_addr( + pCtx, (tDot11fIEtgt_mac_addr *) + (pSrc + pIe->offset + + sizeof(tDot11fIEtgt_mac_addr) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIevht_transmit_power_env: + status |= + dot11f_pack_ie_vht_transmit_power_env( + pCtx, (tDot11fIEvht_transmit_power_env *) + (pSrc + pIe->offset + + sizeof(tDot11fIEvht_transmit_power_env) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeAID: + status |= + dot11f_pack_ie_aid( + pCtx, (tDot11fIEAID *) + (pSrc + pIe->offset + + sizeof(tDot11fIEAID) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeCFParams: + status |= + dot11f_pack_ie_cf_params( + pCtx, (tDot11fIECFParams *) + (pSrc + pIe->offset + + sizeof(tDot11fIECFParams) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeChallengeText: + status |= + dot11f_pack_ie_challenge_text( + pCtx, (tDot11fIEChallengeText *) + (pSrc + pIe->offset + + sizeof(tDot11fIEChallengeText) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeChanSwitchAnn: + status |= + dot11f_pack_ie_chan_switch_ann( + pCtx, (tDot11fIEChanSwitchAnn *) + (pSrc + pIe->offset + + sizeof(tDot11fIEChanSwitchAnn) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeChannelSwitchWrapper: + status |= + dot11f_pack_ie_channel_switch_wrapper( + pCtx, (tDot11fIEChannelSwitchWrapper *) + (pSrc + pIe->offset + + sizeof(tDot11fIEChannelSwitchWrapper) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeCountry: + status |= + dot11f_pack_ie_country( + pCtx, (tDot11fIECountry *) + (pSrc + pIe->offset + + sizeof(tDot11fIECountry) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeDSParams: + status |= + dot11f_pack_ie_ds_params( + pCtx, (tDot11fIEDSParams *) + (pSrc + pIe->offset + + sizeof(tDot11fIEDSParams) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeEDCAParamSet: + status |= + dot11f_pack_ie_edca_param_set( + pCtx, (tDot11fIEEDCAParamSet *) + (pSrc + pIe->offset + + sizeof(tDot11fIEEDCAParamSet) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeERPInfo: + status |= + dot11f_pack_ie_erp_info( + pCtx, (tDot11fIEERPInfo *) + (pSrc + pIe->offset + + sizeof(tDot11fIEERPInfo) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeESECckmOpaque: + status |= + dot11f_pack_ie_ese_cckm_opaque( + pCtx, (tDot11fIEESECckmOpaque *) + (pSrc + pIe->offset + + sizeof(tDot11fIEESECckmOpaque) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeESERadMgmtCap: + status |= + dot11f_pack_ie_ese_rad_mgmt_cap( + pCtx, (tDot11fIEESERadMgmtCap *) + (pSrc + pIe->offset + + sizeof(tDot11fIEESERadMgmtCap) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeESETrafStrmMet: + status |= + dot11f_pack_ie_ese_traf_strm_met( + pCtx, (tDot11fIEESETrafStrmMet *) + (pSrc + pIe->offset + + sizeof(tDot11fIEESETrafStrmMet) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeESETrafStrmRateSet: + status |= + dot11f_pack_ie_ese_traf_strm_rate_set( + pCtx, (tDot11fIEESETrafStrmRateSet *) + (pSrc + pIe->offset + + sizeof(tDot11fIEESETrafStrmRateSet) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeESETxmitPower: + status |= + dot11f_pack_ie_ese_txmit_power( + pCtx, (tDot11fIEESETxmitPower *) + (pSrc + pIe->offset + + sizeof(tDot11fIEESETxmitPower) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeESEVersion: + status |= + dot11f_pack_ie_ese_version( + pCtx, (tDot11fIEESEVersion *) + (pSrc + pIe->offset + + sizeof(tDot11fIEESEVersion) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeExtCap: + status |= + dot11f_pack_ie_ext_cap( + pCtx, (tDot11fIEExtCap *) + (pSrc + pIe->offset + + sizeof(tDot11fIEExtCap) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeExtSuppRates: + status |= + dot11f_pack_ie_ext_supp_rates( + pCtx, (tDot11fIEExtSuppRates *) + (pSrc + pIe->offset + + sizeof(tDot11fIEExtSuppRates) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeFHParamSet: + status |= + dot11f_pack_ie_fh_param_set( + pCtx, (tDot11fIEFHParamSet *) + (pSrc + pIe->offset + + sizeof(tDot11fIEFHParamSet) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeFHParams: + status |= + dot11f_pack_ie_fh_params( + pCtx, (tDot11fIEFHParams *) + (pSrc + pIe->offset + + sizeof(tDot11fIEFHParams) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeFHPattTable: + status |= + dot11f_pack_ie_fh_patt_table( + pCtx, (tDot11fIEFHPattTable *) + (pSrc + pIe->offset + + sizeof(tDot11fIEFHPattTable) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeFTInfo: + status |= + dot11f_pack_ie_ft_info( + pCtx, (tDot11fIEFTInfo *) + (pSrc + pIe->offset + + sizeof(tDot11fIEFTInfo) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeHTCaps: + status |= + dot11f_pack_ie_ht_caps( + pCtx, (tDot11fIEHTCaps *) + (pSrc + pIe->offset + + sizeof(tDot11fIEHTCaps) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeHTInfo: + status |= + dot11f_pack_ie_ht_info( + pCtx, (tDot11fIEHTInfo *) + (pSrc + pIe->offset + + sizeof(tDot11fIEHTInfo) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeIBSSParams: + status |= + dot11f_pack_ie_ibss_params( + pCtx, (tDot11fIEIBSSParams *) + (pSrc + pIe->offset + + sizeof(tDot11fIEIBSSParams) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeLinkIdentifier: + status |= + dot11f_pack_ie_link_identifier( + pCtx, (tDot11fIELinkIdentifier *) + (pSrc + pIe->offset + + sizeof(tDot11fIELinkIdentifier) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeMBO_IE: + status |= + dot11f_pack_ie_MBO_IE( + pCtx, (tDot11fIEMBO_IE *) + (pSrc + pIe->offset + + sizeof(tDot11fIEMBO_IE) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeMeasurementReport: + status |= + dot11f_pack_ie_measurement_report( + pCtx, (tDot11fIEMeasurementReport *) + (pSrc + pIe->offset + + sizeof(tDot11fIEMeasurementReport) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeMeasurementRequest: + status |= + dot11f_pack_ie_measurement_request( + pCtx, (tDot11fIEMeasurementRequest *) + (pSrc + pIe->offset + + sizeof(tDot11fIEMeasurementRequest) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeMobilityDomain: + status |= + dot11f_pack_ie_mobility_domain( + pCtx, (tDot11fIEMobilityDomain *) + (pSrc + pIe->offset + + sizeof(tDot11fIEMobilityDomain) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeNeighborReport: + status |= + dot11f_pack_ie_neighbor_report( + pCtx, (tDot11fIENeighborReport *) + (pSrc + pIe->offset + + sizeof(tDot11fIENeighborReport) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeOBSSScanParameters: + status |= + dot11f_pack_ie_obss_scan_parameters( + pCtx, (tDot11fIEOBSSScanParameters *) + (pSrc + pIe->offset + + sizeof(tDot11fIEOBSSScanParameters) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeOperatingMode: + status |= + dot11f_pack_ie_operating_mode( + pCtx, (tDot11fIEOperatingMode *) + (pSrc + pIe->offset + + sizeof(tDot11fIEOperatingMode) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeP2PAssocReq: + status |= + dot11f_pack_ie_p2_p_assoc_req( + pCtx, (tDot11fIEP2PAssocReq *) + (pSrc + pIe->offset + + sizeof(tDot11fIEP2PAssocReq) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeP2PAssocRes: + status |= + dot11f_pack_ie_p2_p_assoc_res( + pCtx, (tDot11fIEP2PAssocRes *) + (pSrc + pIe->offset + + sizeof(tDot11fIEP2PAssocRes) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeP2PBeacon: + status |= + dot11f_pack_ie_p2_p_beacon( + pCtx, (tDot11fIEP2PBeacon *) + (pSrc + pIe->offset + + sizeof(tDot11fIEP2PBeacon) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeP2PBeaconProbeRes: + status |= + dot11f_pack_ie_p2_p_beacon_probe_res( + pCtx, (tDot11fIEP2PBeaconProbeRes *) + (pSrc + pIe->offset + + sizeof(tDot11fIEP2PBeaconProbeRes) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeP2PDeAuth: + status |= + dot11f_pack_ie_p2_p_de_auth( + pCtx, (tDot11fIEP2PDeAuth *) + (pSrc + pIe->offset + + sizeof(tDot11fIEP2PDeAuth) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeP2PDisAssoc: + status |= + dot11f_pack_ie_p2_p_dis_assoc( + pCtx, (tDot11fIEP2PDisAssoc *) + (pSrc + pIe->offset + + sizeof(tDot11fIEP2PDisAssoc) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeP2PIEOpaque: + status |= + dot11f_pack_ie_p2_pie_opaque( + pCtx, (tDot11fIEP2PIEOpaque *) + (pSrc + pIe->offset + + sizeof(tDot11fIEP2PIEOpaque) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeP2PProbeReq: + status |= + dot11f_pack_ie_p2_p_probe_req( + pCtx, (tDot11fIEP2PProbeReq *) + (pSrc + pIe->offset + + sizeof(tDot11fIEP2PProbeReq) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeP2PProbeRes: + status |= + dot11f_pack_ie_p2_p_probe_res( + pCtx, (tDot11fIEP2PProbeRes *) + (pSrc + pIe->offset + + sizeof(tDot11fIEP2PProbeRes) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIePTIControl: + status |= + dot11f_pack_ie_pti_control( + pCtx, (tDot11fIEPTIControl *) + (pSrc + pIe->offset + + sizeof(tDot11fIEPTIControl) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIePUBufferStatus: + status |= + dot11f_pack_ie_pu_buffer_status( + pCtx, (tDot11fIEPUBufferStatus *) + (pSrc + pIe->offset + + sizeof(tDot11fIEPUBufferStatus) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIePowerCaps: + status |= + dot11f_pack_ie_power_caps( + pCtx, (tDot11fIEPowerCaps *) + (pSrc + pIe->offset + + sizeof(tDot11fIEPowerCaps) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIePowerConstraints: + status |= + dot11f_pack_ie_power_constraints( + pCtx, (tDot11fIEPowerConstraints *) + (pSrc + pIe->offset + + sizeof(tDot11fIEPowerConstraints) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeQBSSLoad: + status |= + dot11f_pack_ie_qbss_load( + pCtx, (tDot11fIEQBSSLoad *) + (pSrc + pIe->offset + + sizeof(tDot11fIEQBSSLoad) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeQCN_IE: + status |= + dot11f_pack_ie_QCN_IE( + pCtx, (tDot11fIEQCN_IE *) + (pSrc + pIe->offset + + sizeof(tDot11fIEQCN_IE) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeQComVendorIE: + status |= + dot11f_pack_ie_QComVendorIE( + pCtx, (tDot11fIEQComVendorIE *) + (pSrc + pIe->offset + + sizeof(tDot11fIEQComVendorIE) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeQOSCapsAp: + status |= + dot11f_pack_ie_qos_caps_ap( + pCtx, (tDot11fIEQOSCapsAp *) + (pSrc + pIe->offset + + sizeof(tDot11fIEQOSCapsAp) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeQOSCapsStation: + status |= + dot11f_pack_ie_qos_caps_station( + pCtx, (tDot11fIEQOSCapsStation *) + (pSrc + pIe->offset + + sizeof(tDot11fIEQOSCapsStation) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeQosMapSet: + status |= + dot11f_pack_ie_qos_map_set( + pCtx, (tDot11fIEQosMapSet *) + (pSrc + pIe->offset + + sizeof(tDot11fIEQosMapSet) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeQuiet: + status |= + dot11f_pack_ie_quiet( + pCtx, (tDot11fIEQuiet *) + (pSrc + pIe->offset + + sizeof(tDot11fIEQuiet) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeRCPIIE: + status |= + dot11f_pack_ie_rcpiie( + pCtx, (tDot11fIERCPIIE *) + (pSrc + pIe->offset + + sizeof(tDot11fIERCPIIE) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeRICDataDesc: + status |= + dot11f_pack_ie_ric_data_desc( + pCtx, (tDot11fIERICDataDesc *) + (pSrc + pIe->offset + + sizeof(tDot11fIERICDataDesc) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeRSN: + status |= + dot11f_pack_ie_rsn( + pCtx, (tDot11fIERSN *) + (pSrc + pIe->offset + + sizeof(tDot11fIERSN) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeRSNIIE: + status |= + dot11f_pack_ie_rsniie( + pCtx, (tDot11fIERSNIIE *) + (pSrc + pIe->offset + + sizeof(tDot11fIERSNIIE) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeRSNOpaque: + status |= + dot11f_pack_ie_rsn_opaque( + pCtx, (tDot11fIERSNOpaque *) + (pSrc + pIe->offset + + sizeof(tDot11fIERSNOpaque) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeSuppChannels: + status |= + dot11f_pack_ie_supp_channels( + pCtx, (tDot11fIESuppChannels *) + (pSrc + pIe->offset + + sizeof(tDot11fIESuppChannels) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeSuppOperatingClasses: + status |= + dot11f_pack_ie_supp_operating_classes( + pCtx, (tDot11fIESuppOperatingClasses *) + (pSrc + pIe->offset + + sizeof(tDot11fIESuppOperatingClasses) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeSuppRates: + status |= + dot11f_pack_ie_supp_rates( + pCtx, (tDot11fIESuppRates *) + (pSrc + pIe->offset + + sizeof(tDot11fIESuppRates) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeTIM: + status |= + dot11f_pack_ie_tim( + pCtx, (tDot11fIETIM *) + (pSrc + pIe->offset + + sizeof(tDot11fIETIM) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeTPCReport: + status |= + dot11f_pack_ie_tpc_report( + pCtx, (tDot11fIETPCReport *) + (pSrc + pIe->offset + + sizeof(tDot11fIETPCReport) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeTPCRequest: + status |= + dot11f_pack_ie_tpc_request( + pCtx, (tDot11fIETPCRequest *) + (pSrc + pIe->offset + + sizeof(tDot11fIETPCRequest) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeTimeAdvertisement: + status |= + dot11f_pack_ie_time_advertisement( + pCtx, (tDot11fIETimeAdvertisement *) + (pSrc + pIe->offset + + sizeof(tDot11fIETimeAdvertisement) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeTimeoutInterval: + status |= + dot11f_pack_ie_timeout_interval( + pCtx, (tDot11fIETimeoutInterval *) + (pSrc + pIe->offset + + sizeof(tDot11fIETimeoutInterval) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeVHTExtBssLoad: + status |= + dot11f_pack_ie_vht_ext_bss_load( + pCtx, (tDot11fIEVHTExtBssLoad *) + (pSrc + pIe->offset + + sizeof(tDot11fIEVHTExtBssLoad) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeVendor1IE: + status |= + dot11f_pack_ie_vendor1_ie( + pCtx, (tDot11fIEVendor1IE *) + (pSrc + pIe->offset + + sizeof(tDot11fIEVendor1IE) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeVendor3IE: + status |= + dot11f_pack_ie_vendor3_ie( + pCtx, (tDot11fIEVendor3IE *) + (pSrc + pIe->offset + + sizeof(tDot11fIEVendor3IE) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeWAPI: + status |= + dot11f_pack_ie_wapi( + pCtx, (tDot11fIEWAPI *) + (pSrc + pIe->offset + + sizeof(tDot11fIEWAPI) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeWAPIOpaque: + status |= + dot11f_pack_ie_wapi_opaque( + pCtx, (tDot11fIEWAPIOpaque *) + (pSrc + pIe->offset + + sizeof(tDot11fIEWAPIOpaque) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeWFATPC: + status |= + dot11f_pack_ie_wfatpc( + pCtx, (tDot11fIEWFATPC *) + (pSrc + pIe->offset + + sizeof(tDot11fIEWFATPC) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeWFDIEOpaque: + status |= + dot11f_pack_ie_wfdie_opaque( + pCtx, (tDot11fIEWFDIEOpaque *) + (pSrc + pIe->offset + + sizeof(tDot11fIEWFDIEOpaque) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeWMMCaps: + status |= + dot11f_pack_ie_wmm_caps( + pCtx, (tDot11fIEWMMCaps *) + (pSrc + pIe->offset + + sizeof(tDot11fIEWMMCaps) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeWMMInfoAp: + status |= + dot11f_pack_ie_wmm_info_ap( + pCtx, (tDot11fIEWMMInfoAp *) + (pSrc + pIe->offset + + sizeof(tDot11fIEWMMInfoAp) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeWMMInfoStation: + status |= + dot11f_pack_ie_wmm_info_station( + pCtx, (tDot11fIEWMMInfoStation *) + (pSrc + pIe->offset + + sizeof(tDot11fIEWMMInfoStation) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeWMMParams: + status |= + dot11f_pack_ie_wmm_params( + pCtx, (tDot11fIEWMMParams *) + (pSrc + pIe->offset + + sizeof(tDot11fIEWMMParams) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeWPA: + status |= + dot11f_pack_ie_wpa( + pCtx, (tDot11fIEWPA *) + (pSrc + pIe->offset + + sizeof(tDot11fIEWPA) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeWPAOpaque: + status |= + dot11f_pack_ie_wpa_opaque( + pCtx, (tDot11fIEWPAOpaque *) + (pSrc + pIe->offset + + sizeof(tDot11fIEWPAOpaque) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeWSC: + status |= + dot11f_pack_ie_wsc( + pCtx, (tDot11fIEWSC *) + (pSrc + pIe->offset + + sizeof(tDot11fIEWSC) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeWscAssocReq: + status |= + dot11f_pack_ie_wsc_assoc_req( + pCtx, (tDot11fIEWscAssocReq *) + (pSrc + pIe->offset + + sizeof(tDot11fIEWscAssocReq) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeWscAssocRes: + status |= + dot11f_pack_ie_wsc_assoc_res( + pCtx, (tDot11fIEWscAssocRes *) + (pSrc + pIe->offset + + sizeof(tDot11fIEWscAssocRes) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeWscBeacon: + status |= + dot11f_pack_ie_wsc_beacon( + pCtx, (tDot11fIEWscBeacon *) + (pSrc + pIe->offset + + sizeof(tDot11fIEWscBeacon) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeWscBeaconProbeRes: + status |= + dot11f_pack_ie_wsc_beacon_probe_res( + pCtx, (tDot11fIEWscBeaconProbeRes *) + (pSrc + pIe->offset + + sizeof(tDot11fIEWscBeaconProbeRes) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeWscIEOpaque: + status |= + dot11f_pack_ie_wsc_ie_opaque( + pCtx, (tDot11fIEWscIEOpaque *) + (pSrc + pIe->offset + + sizeof(tDot11fIEWscIEOpaque) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeWscProbeReq: + status |= + dot11f_pack_ie_wsc_probe_req( + pCtx, (tDot11fIEWscProbeReq *) + (pSrc + pIe->offset + + sizeof(tDot11fIEWscProbeReq) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeWscProbeRes: + status |= + dot11f_pack_ie_wsc_probe_res( + pCtx, (tDot11fIEWscProbeRes *) + (pSrc + pIe->offset + + sizeof(tDot11fIEWscProbeRes) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeWscReassocRes: + status |= + dot11f_pack_ie_wsc_reassoc_res( + pCtx, (tDot11fIEWscReassocRes *) + (pSrc + pIe->offset + + sizeof(tDot11fIEWscReassocRes) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeext_chan_switch_ann: + status |= + dot11f_pack_ie_ext_chan_switch_ann( + pCtx, (tDot11fIEext_chan_switch_ann *) + (pSrc + pIe->offset + + sizeof(tDot11fIEext_chan_switch_ann) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIehs20vendor_ie: + status |= + dot11f_pack_ie_hs20vendor_ie( + pCtx, (tDot11fIEhs20vendor_ie *) + (pSrc + pIe->offset + + sizeof(tDot11fIEhs20vendor_ie) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeht2040_bss_coexistence: + status |= + dot11f_pack_ie_ht2040_bss_coexistence( + pCtx, (tDot11fIEht2040_bss_coexistence *) + (pSrc + pIe->offset + + sizeof(tDot11fIEht2040_bss_coexistence) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeht2040_bss_intolerant_report: + status |= + dot11f_pack_ie_ht2040_bss_intolerant_report( + pCtx, (tDot11fIEht2040_bss_intolerant_report *) + (pSrc + pIe->offset + + sizeof(tDot11fIEht2040_bss_intolerant_report) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIesec_chan_offset_ele: + status |= + dot11f_pack_ie_sec_chan_offset_ele( + pCtx, (tDot11fIEsec_chan_offset_ele *) + (pSrc + pIe->offset + + sizeof(tDot11fIEsec_chan_offset_ele) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIevendor_vht_ie: + status |= + dot11f_pack_ie_vendor_vht_ie( + pCtx, (tDot11fIEvendor_vht_ie *) + (pSrc + pIe->offset + + sizeof(tDot11fIEvendor_vht_ie) * i), + pBufRemaining, nBufRemaining, &len); + break; + default: + FRAMES_LOG1(pCtx, FRLOGE, FRFL("INTERNAL ERROR-- I don" + "'t know about the IE %d; this is most likely a b" + "ug in 'framesc'.\n"), pFf->sig); + return DOT11F_INTERNAL_ERROR; + } + + pBufRemaining += len; + nBufRemaining -= len; + *pnConsumed += len; + } + + ++pIe; + + } + + return status; + +} + +static uint32_t pack_tlv_core(tpAniSirGlobal pCtx, + uint8_t *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed, + const tTLVDefn TLVs[], + uint32_t *pidx) +{ + const tTLVDefn *pTlv; + tFRAMES_BOOL *pfFound; + uint8_t *pBufRemaining; + uint32_t nBufRemaining, status, len; + + DOT11F_PARAMETER_CHECK2(pSrc, pBuf, nBuf, pnConsumed); + + (void)pCtx; + status = DOT11F_PARSE_SUCCESS; + pBufRemaining = pBuf; + nBufRemaining = nBuf; + + pTlv = &(TLVs[0]); + while (0xffff != pTlv->id) { + pfFound = (tFRAMES_BOOL *)(pSrc + pTlv->offset + + pTlv->presenceOffset); + if (*pfFound && pTlv->minSize > nBufRemaining) { + FRAMES_LOG3(pCtx, FRLOGE, FRFL("The TLV %s takes at least" + " %d bytes, but there are only %d left in the buffer." + "\n"), pTlv->name, pTlv->minSize, nBufRemaining); + return DOT11F_BUFFER_OVERFLOW; + } + + len = 0U; + + if (*pfFound) { + switch (pTlv->sig) { + case SigTlvAuthorizedMACs: + status |= + dot11f_pack_tlv_authorized_ma_cs( + pCtx, (tDot11fTLVAuthorizedMACs *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + case SigTlvRequestToEnroll: + status |= + dot11f_pack_tlv_request_to_enroll( + pCtx, (tDot11fTLVRequestToEnroll *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + case SigTlvVersion2: + status |= + dot11f_pack_tlv_version2( + pCtx, (tDot11fTLVVersion2 *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + case SigTlvAPSetupLocked: + status |= + dot11f_pack_tlv_ap_setup_locked( + pCtx, (tDot11fTLVAPSetupLocked *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + case SigTlvAssociationState: + status |= + dot11f_pack_tlv_association_state( + pCtx, (tDot11fTLVAssociationState *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + case SigTlvConfigMethods: + status |= + dot11f_pack_tlv_config_methods( + pCtx, (tDot11fTLVConfigMethods *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + case SigTlvConfigurationError: + status |= + dot11f_pack_tlv_configuration_error( + pCtx, (tDot11fTLVConfigurationError *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + case SigTlvDeviceName: + status |= + dot11f_pack_tlv_device_name( + pCtx, (tDot11fTLVDeviceName *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + case SigTlvDevicePasswordID: + status |= + dot11f_pack_tlv_device_password_id( + pCtx, (tDot11fTLVDevicePasswordID *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + case SigTlvExtendedListenTiming: + status |= + dot11f_pack_tlv_extended_listen_timing( + pCtx, (tDot11fTLVExtendedListenTiming *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + case SigTlvListenChannel: + status |= + dot11f_pack_tlv_listen_channel( + pCtx, (tDot11fTLVListenChannel *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + case SigTlvManufacturer: + status |= + dot11f_pack_tlv_manufacturer( + pCtx, (tDot11fTLVManufacturer *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + case SigTlvMinorReasonCode: + status |= + dot11f_pack_tlv_minor_reason_code( + pCtx, (tDot11fTLVMinorReasonCode *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + case SigTlvModelName: + status |= + dot11f_pack_tlv_model_name( + pCtx, (tDot11fTLVModelName *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + case SigTlvModelNumber: + status |= + dot11f_pack_tlv_model_number( + pCtx, (tDot11fTLVModelNumber *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + case SigTlvNoticeOfAbsence: + status |= + dot11f_pack_tlv_notice_of_absence( + pCtx, (tDot11fTLVNoticeOfAbsence *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + case SigTlvOperatingChannel: + status |= + dot11f_pack_tlv_operating_channel( + pCtx, (tDot11fTLVOperatingChannel *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + case SigTlvP2PCapability: + status |= + dot11f_pack_tlv_p2_p_capability( + pCtx, (tDot11fTLVP2PCapability *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + case SigTlvP2PDeviceId: + status |= + dot11f_pack_tlv_p2_p_device_id( + pCtx, (tDot11fTLVP2PDeviceId *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + case SigTlvP2PDeviceInfo: + status |= + dot11f_pack_tlv_p2_p_device_info( + pCtx, (tDot11fTLVP2PDeviceInfo *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + case SigTlvP2PGroupInfo: + status |= + dot11f_pack_tlv_p2_p_group_info( + pCtx, (tDot11fTLVP2PGroupInfo *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + case SigTlvP2PStatus: + status |= + dot11f_pack_tlv_p2_p_status( + pCtx, (tDot11fTLVP2PStatus *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + case SigTlvPrimaryDeviceType: + status |= + dot11f_pack_tlv_primary_device_type( + pCtx, (tDot11fTLVPrimaryDeviceType *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + case SigTlvRFBands: + status |= + dot11f_pack_tlv_rf_bands( + pCtx, (tDot11fTLVRFBands *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + case SigTlvRequestDeviceType: + status |= + dot11f_pack_tlv_request_device_type( + pCtx, (tDot11fTLVRequestDeviceType *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + case SigTlvRequestType: + status |= + dot11f_pack_tlv_request_type( + pCtx, (tDot11fTLVRequestType *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + case SigTlvResponseType: + status |= + dot11f_pack_tlv_response_type( + pCtx, (tDot11fTLVResponseType *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + case SigTlvSelectedRegistrar: + status |= + dot11f_pack_tlv_selected_registrar( + pCtx, (tDot11fTLVSelectedRegistrar *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + case SigTlvSelectedRegistrarConfigMethods: + status |= + dot11f_pack_tlv_selected_registrar_config_methods( + pCtx, (tDot11fTLVSelectedRegistrarConfigMethods *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + case SigTlvSerialNumber: + status |= + dot11f_pack_tlv_serial_number( + pCtx, (tDot11fTLVSerialNumber *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + case SigTlvUUID_E: + status |= + dot11f_pack_tlv_uuid_e( + pCtx, (tDot11fTLVUUID_E *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + case SigTlvUUID_R: + status |= + dot11f_pack_tlv_uuid_r( + pCtx, (tDot11fTLVUUID_R *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + case SigTlvVendorExtension: + status |= + dot11f_pack_tlv_vendor_extension( + pCtx, (tDot11fTLVVendorExtension *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + case SigTlvVersion: + status |= + dot11f_pack_tlv_version( + pCtx, (tDot11fTLVVersion *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + case SigTlvWPSState: + status |= + dot11f_pack_tlv_wps_state( + pCtx, (tDot11fTLVWPSState *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + case SigTlvP2PInterface: + status |= + dot11f_pack_tlv_p2_p_interface( + pCtx, (tDot11fTLVP2PInterface *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + case SigTlvP2PManageability: + status |= + dot11f_pack_tlv_p2_p_manageability( + pCtx, (tDot11fTLVP2PManageability *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + default: + FRAMES_LOG1(pCtx, FRLOGE, FRFL("INTERNAL ERROR-- I don't " + "know about the TLV %d; this is most likely a bug in " + "'framesc'.\n"), pTlv->sig); + return DOT11F_INTERNAL_ERROR; + } + + } /* End if on *pfFound */ + pBufRemaining += len; + nBufRemaining -= len; + *pnConsumed += len; + ++pTlv; + if (len) + ++*pidx; + } + + return status; + +} diff --git a/drivers/staging/qcacld-3.0/core/mac/src/sys/legacy/src/utils/src/log_api.c b/drivers/staging/qcacld-3.0/core/mac/src/sys/legacy/src/utils/src/log_api.c new file mode 100644 index 0000000000000000000000000000000000000000..44e37cd40f406ec5f5e329a89bcd1e4ac2fd6016 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/sys/legacy/src/utils/src/log_api.c @@ -0,0 +1,195 @@ +/* + * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * log_api.cc - Handles log messages for all the modules. + * Author: Kevin Nguyen + * Date: 02/27/02 + * History:- + * 02/11/02 Created. + * 03/12/02 Rearrange log_debug parameter list and add more params. + * -------------------------------------------------------------------- + * + */ + +#include +#include +#include +#include + +#include +#include "utils_global.h" +#include "mac_init_api.h" + +#include "qdf_trace.h" + +#ifdef ANI_OS_TYPE_ANDROID +#include +#endif + +/* --------------------------------------------------------------------- */ +/** + * log_init() + * + * FUNCTION: + * This function is called to prepare the logging utility. + * + * LOGIC: + * + * ASSUMPTIONS: + * None. + * + * NOTE: + * + * @param tpAniSirGlobal Sirius software parameter strucutre pointer + * @return None + */ +tSirRetStatus log_init(tpAniSirGlobal pMac) +{ + uint32_t i; + + /* Add code to initialize debug level from CFG module */ + /* For now, enable all logging */ + for (i = 0; i < LOG_ENTRY_NUM; i++) { +#ifdef SIR_DEBUG + pMac->utils.gLogEvtLevel[i] = pMac->utils.gLogDbgLevel[i] = + LOG1; +#else + pMac->utils.gLogEvtLevel[i] = pMac->utils.gLogDbgLevel[i] = + LOGW; +#endif + } + return eSIR_SUCCESS; + +} /*** log_init() ***/ + +void log_deinit(tpAniSirGlobal pMac) +{ + return; +} + +/** + * log_dbg() + * + ***FUNCTION: + * This function is called to log a debug message. + * + ***PARAMS: + * + ***LOGIC: + * + ***ASSUMPTIONS: + * None. + * + ***NOTE: + * + * @param tpAniSirGlobal Sirius software parameter strucutre pointer + * @param ModId 8-bit modID + * @param debugLevel debugging level for this message + * @param pStr string parameter pointer + * @return None + */ + +void log_dbg(tpAniSirGlobal pMac, uint8_t modId, uint32_t debugLevel, + const char *pStr, ...) +{ +#ifdef WLAN_DEBUG + if (debugLevel > pMac->utils.gLogDbgLevel[LOG_INDEX_FOR_MODULE(modId)]) + return; + else { + va_list marker; + + va_start(marker, pStr); /* Initialize variable arguments. */ + + log_debug(pMac, modId, debugLevel, pStr, marker); + + va_end(marker); /* Reset variable arguments. */ + } +#endif +} + +QDF_TRACE_LEVEL get_vos_debug_level(uint32_t debugLevel) +{ + switch (debugLevel) { + case LOGP: + return QDF_TRACE_LEVEL_FATAL; + case LOGE: + return QDF_TRACE_LEVEL_ERROR; + case LOGW: + return QDF_TRACE_LEVEL_WARN; + case LOG1: + return QDF_TRACE_LEVEL_INFO; + case LOG2: + return QDF_TRACE_LEVEL_INFO_HIGH; + case LOG3: + return QDF_TRACE_LEVEL_INFO_MED; + case LOG4: + return QDF_TRACE_LEVEL_INFO_LOW; + default: + return QDF_TRACE_LEVEL_INFO_LOW; + } +} + +static inline QDF_MODULE_ID get_vos_module_id(uint8_t modId) +{ + switch (modId) { + case SIR_HAL_MODULE_ID: + return QDF_MODULE_ID_WMA; + + case SIR_LIM_MODULE_ID: + case SIR_SCH_MODULE_ID: + case SIR_CFG_MODULE_ID: + case SIR_MNT_MODULE_ID: + case SIR_DPH_MODULE_ID: + case SIR_DBG_MODULE_ID: + return QDF_MODULE_ID_PE; + + case SIR_SYS_MODULE_ID: + return QDF_MODULE_ID_SYS; + + case SIR_SMS_MODULE_ID: + return QDF_MODULE_ID_SME; + + default: + return QDF_MODULE_ID_SYS; + } +} + +#define LOG_SIZE 256 +void log_debug(tpAniSirGlobal pMac, uint8_t modId, uint32_t debugLevel, + const char *pStr, va_list marker) +{ + QDF_TRACE_LEVEL qdf_debug_level; + QDF_MODULE_ID qdf_module_id; + char logBuffer[LOG_SIZE]; + + qdf_debug_level = get_vos_debug_level(debugLevel); + qdf_module_id = get_vos_module_id(modId); + + vsnprintf(logBuffer, LOG_SIZE - 1, pStr, marker); + QDF_TRACE(qdf_module_id, qdf_debug_level, "%s", logBuffer); +} /*** end log_debug() ***/ diff --git a/drivers/staging/qcacld-3.0/core/mac/src/sys/legacy/src/utils/src/mac_trace.c b/drivers/staging/qcacld-3.0/core/mac/src/sys/legacy/src/utils/src/mac_trace.c new file mode 100644 index 0000000000000000000000000000000000000000..529d2510be4c47979e4a75614efa6e5d8c019c55 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/sys/legacy/src/utils/src/mac_trace.c @@ -0,0 +1,894 @@ +/* + * Copyright (c) 2013-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/**========================================================================= + + \file mac_trace.c + + \brief implementation for trace related APIs + + \author Sunit Bhatia + + ========================================================================*/ + +/*-------------------------------------------------------------------------- + Include Files + ------------------------------------------------------------------------*/ + +#include "mac_trace.h" +#include "wma_types.h" +#include "csr_neighbor_roam.h" +#include "csr_internal.h" +#include "lim_global.h" +#include "lim_types.h" +#include "qdf_mem.h" +#include "qdf_trace.h" +#include "wma_if.h" + +#ifdef TRACE_RECORD +/** + * mac_trace_get_neighbour_roam_state() - Get the neighbor roam state + * @neighbourroamstate: State in numeric form + * + * This function will return a string equivalent of the state. + * + * Return: String equivalent of the state. + **/ +uint8_t *mac_trace_get_neighbour_roam_state(uint16_t neighbourroamstate) +{ + switch (neighbourroamstate) { + CASE_RETURN_STRING(eCSR_NEIGHBOR_ROAM_STATE_CLOSED); + CASE_RETURN_STRING(eCSR_NEIGHBOR_ROAM_STATE_INIT); + CASE_RETURN_STRING(eCSR_NEIGHBOR_ROAM_STATE_CONNECTED); + CASE_RETURN_STRING(eCSR_NEIGHBOR_ROAM_STATE_REASSOCIATING); + CASE_RETURN_STRING(eCSR_NEIGHBOR_ROAM_STATE_PREAUTHENTICATING); + CASE_RETURN_STRING(eCSR_NEIGHBOR_ROAM_STATE_PREAUTH_DONE); + CASE_RETURN_STRING(eNEIGHBOR_STATE_MAX); + + default: + return (uint8_t *) "UNKNOWN"; + break; + } +} + +/** + * mac_trace_getcsr_roam_state() - Get the csr roam state + * @csr_roam_state: State in numeric form + * + * This function will return a string equivalent of the state. + * + * Return: String equivalent of the state. + **/ +uint8_t *mac_trace_getcsr_roam_state(uint16_t csr_roam_state) +{ + switch (csr_roam_state) { + CASE_RETURN_STRING(eCSR_ROAMING_STATE_STOP); + CASE_RETURN_STRING(eCSR_ROAMING_STATE_IDLE); + CASE_RETURN_STRING(eCSR_ROAMING_STATE_JOINING); + CASE_RETURN_STRING(eCSR_ROAMING_STATE_JOINED); + + default: + return (uint8_t *) "UNKNOWN"; + break; + } +} + +/** + * mac_trace_getcsr_roam_sub_state() - Get the csr roam sub state + * @csr_roam_sub_state: State in numeric form + * + * This function will return a string equivalent of the state. + * + * Return: String equivalent of the state. + **/ +uint8_t *mac_trace_getcsr_roam_sub_state(uint16_t csr_roam_sub_state) +{ + switch (csr_roam_sub_state) { + CASE_RETURN_STRING(eCSR_ROAM_SUBSTATE_NONE); + CASE_RETURN_STRING(eCSR_ROAM_SUBSTATE_START_BSS_REQ); + CASE_RETURN_STRING(eCSR_ROAM_SUBSTATE_JOIN_REQ); + CASE_RETURN_STRING(eCSR_ROAM_SUBSTATE_REASSOC_REQ); + CASE_RETURN_STRING(eCSR_ROAM_SUBSTATE_DISASSOC_REQ); + CASE_RETURN_STRING(eCSR_ROAM_SUBSTATE_STOP_BSS_REQ); + CASE_RETURN_STRING + (eCSR_ROAM_SUBSTATE_DISCONNECT_CONTINUE_ROAMING); + CASE_RETURN_STRING(eCSR_ROAM_SUBSTATE_AUTH_REQ); + CASE_RETURN_STRING(eCSR_ROAM_SUBSTATE_CONFIG); + CASE_RETURN_STRING(eCSR_ROAM_SUBSTATE_DEAUTH_REQ); + CASE_RETURN_STRING(eCSR_ROAM_SUBSTATE_DISASSOC_NOTHING_TO_JOIN); + CASE_RETURN_STRING(eCSR_ROAM_SUBSTATE_DISASSOC_REASSOC_FAILURE); + CASE_RETURN_STRING(eCSR_ROAM_SUBSTATE_DISASSOC_FORCED); + CASE_RETURN_STRING(eCSR_ROAM_SUBSTATE_WAIT_FOR_KEY); + CASE_RETURN_STRING(eCSR_ROAM_SUBSTATE_DISASSOC_HANDOFF); + CASE_RETURN_STRING(eCSR_ROAM_SUBSTATE_JOINED_NO_TRAFFIC); + CASE_RETURN_STRING + (eCSR_ROAM_SUBSTATE_JOINED_NON_REALTIME_TRAFFIC); + CASE_RETURN_STRING(eCSR_ROAM_SUBSTATE_JOINED_REALTIME_TRAFFIC); + + default: + return (uint8_t *) "UNKNOWN"; + break; + } +} + +/** + * mac_trace_get_lim_sme_state() - Get the lim sme state + * @lim_state: State in numeric form + * + * This function will return a string equivalent of the state. + * + * Return: String equivalent of the state. + **/ +uint8_t *mac_trace_get_lim_sme_state(uint16_t lim_state) +{ + switch (lim_state) { + CASE_RETURN_STRING(eLIM_SME_OFFLINE_STATE); + CASE_RETURN_STRING(eLIM_SME_IDLE_STATE); + CASE_RETURN_STRING(eLIM_SME_SUSPEND_STATE); + CASE_RETURN_STRING(eLIM_SME_WT_SCAN_STATE); + CASE_RETURN_STRING(eLIM_SME_WT_JOIN_STATE); + CASE_RETURN_STRING(eLIM_SME_WT_AUTH_STATE); + CASE_RETURN_STRING(eLIM_SME_WT_ASSOC_STATE); + CASE_RETURN_STRING(eLIM_SME_WT_REASSOC_STATE); + CASE_RETURN_STRING(eLIM_SME_WT_REASSOC_LINK_FAIL_STATE); + CASE_RETURN_STRING(eLIM_SME_JOIN_FAILURE_STATE); + CASE_RETURN_STRING(eLIM_SME_ASSOCIATED_STATE); + CASE_RETURN_STRING(eLIM_SME_REASSOCIATED_STATE); + CASE_RETURN_STRING(eLIM_SME_LINK_EST_STATE); + CASE_RETURN_STRING(eLIM_SME_LINK_EST_WT_SCAN_STATE); + CASE_RETURN_STRING(eLIM_SME_WT_PRE_AUTH_STATE); + CASE_RETURN_STRING(eLIM_SME_WT_DISASSOC_STATE); + CASE_RETURN_STRING(eLIM_SME_WT_DEAUTH_STATE); + CASE_RETURN_STRING(eLIM_SME_WT_START_BSS_STATE); + CASE_RETURN_STRING(eLIM_SME_WT_STOP_BSS_STATE); + CASE_RETURN_STRING(eLIM_SME_NORMAL_STATE); + CASE_RETURN_STRING(eLIM_SME_CHANNEL_SCAN_STATE); + CASE_RETURN_STRING(eLIM_SME_NORMAL_CHANNEL_SCAN_STATE); + + default: + return (uint8_t *) "UNKNOWN"; + break; + } +} + +/** + * mac_trace_get_lim_mlm_state() - Get the lim mlm state + * @mlmstate: State in numeric form + * + * This function will return a string equivalent of the state. + * + * Return: String equivalent of the state. + **/ +uint8_t *mac_trace_get_lim_mlm_state(uint16_t mlm_state) +{ + switch (mlm_state) { + CASE_RETURN_STRING(eLIM_MLM_OFFLINE_STATE); + CASE_RETURN_STRING(eLIM_MLM_IDLE_STATE); + CASE_RETURN_STRING(eLIM_MLM_WT_PROBE_RESP_STATE); + CASE_RETURN_STRING(eLIM_MLM_PASSIVE_SCAN_STATE); + CASE_RETURN_STRING(eLIM_MLM_WT_JOIN_BEACON_STATE); + CASE_RETURN_STRING(eLIM_MLM_JOINED_STATE); + CASE_RETURN_STRING(eLIM_MLM_BSS_STARTED_STATE); + CASE_RETURN_STRING(eLIM_MLM_WT_AUTH_FRAME2_STATE); + CASE_RETURN_STRING(eLIM_MLM_WT_AUTH_FRAME3_STATE); + CASE_RETURN_STRING(eLIM_MLM_WT_AUTH_FRAME4_STATE); + CASE_RETURN_STRING(eLIM_MLM_AUTH_RSP_TIMEOUT_STATE); + CASE_RETURN_STRING(eLIM_MLM_AUTHENTICATED_STATE); + CASE_RETURN_STRING(eLIM_MLM_WT_ASSOC_RSP_STATE); + CASE_RETURN_STRING(eLIM_MLM_WT_REASSOC_RSP_STATE); + CASE_RETURN_STRING(eLIM_MLM_ASSOCIATED_STATE); + CASE_RETURN_STRING(eLIM_MLM_REASSOCIATED_STATE); + CASE_RETURN_STRING(eLIM_MLM_LINK_ESTABLISHED_STATE); + CASE_RETURN_STRING(eLIM_MLM_WT_ASSOC_CNF_STATE); + CASE_RETURN_STRING(eLIM_MLM_LEARN_STATE); + CASE_RETURN_STRING(eLIM_MLM_WT_ADD_BSS_RSP_STATE); + CASE_RETURN_STRING(eLIM_MLM_WT_DEL_BSS_RSP_STATE); + CASE_RETURN_STRING(eLIM_MLM_WT_ADD_BSS_RSP_ASSOC_STATE); + CASE_RETURN_STRING(eLIM_MLM_WT_ADD_BSS_RSP_REASSOC_STATE); + CASE_RETURN_STRING(eLIM_MLM_WT_ADD_BSS_RSP_PREASSOC_STATE); + CASE_RETURN_STRING(eLIM_MLM_WT_ADD_STA_RSP_STATE); + CASE_RETURN_STRING(eLIM_MLM_WT_DEL_STA_RSP_STATE); + + default: + return (uint8_t *) "UNKNOWN"; + break; + } +} + +/** + * mac_trace_get_sme_msg_string() - Get the msg + * @sme_msg: message type in numeric form + * + * This function will return a string equivalent of the message. + * + * Return: String equivalent of the message type. + **/ +uint8_t *mac_trace_get_sme_msg_string(uint16_t sme_msg) +{ + switch (sme_msg) { + CASE_RETURN_STRING(eWNI_SME_SYS_READY_IND); + CASE_RETURN_STRING(eWNI_SME_SCAN_REQ); + CASE_RETURN_STRING(eWNI_SME_SCAN_ABORT_IND); + CASE_RETURN_STRING(eWNI_SME_SCAN_RSP); + CASE_RETURN_STRING(eWNI_SME_JOIN_REQ); + CASE_RETURN_STRING(eWNI_SME_JOIN_RSP); + CASE_RETURN_STRING(eWNI_SME_SETCONTEXT_REQ); + CASE_RETURN_STRING(eWNI_SME_SETCONTEXT_RSP); + CASE_RETURN_STRING(eWNI_SME_REASSOC_REQ); + CASE_RETURN_STRING(eWNI_SME_REASSOC_RSP); + CASE_RETURN_STRING(eWNI_SME_DISASSOC_REQ); + CASE_RETURN_STRING(eWNI_SME_DISASSOC_RSP); + CASE_RETURN_STRING(eWNI_SME_DISASSOC_IND); + CASE_RETURN_STRING(eWNI_SME_DISASSOC_CNF); + CASE_RETURN_STRING(eWNI_SME_DEAUTH_REQ); + CASE_RETURN_STRING(eWNI_SME_DEAUTH_RSP); + CASE_RETURN_STRING(eWNI_SME_DEAUTH_IND); + CASE_RETURN_STRING(eWNI_SME_DISCONNECT_DONE_IND); + CASE_RETURN_STRING(eWNI_SME_WM_STATUS_CHANGE_NTF); + CASE_RETURN_STRING(eWNI_SME_IBSS_NEW_PEER_IND); + CASE_RETURN_STRING(eWNI_SME_IBSS_PEER_DEPARTED_IND); + CASE_RETURN_STRING(eWNI_SME_START_BSS_REQ); + CASE_RETURN_STRING(eWNI_SME_START_BSS_RSP); + CASE_RETURN_STRING(eWNI_SME_ASSOC_IND); + CASE_RETURN_STRING(eWNI_SME_ASSOC_CNF); + CASE_RETURN_STRING(eWNI_SME_SWITCH_CHL_IND); + CASE_RETURN_STRING(eWNI_SME_STOP_BSS_REQ); + CASE_RETURN_STRING(eWNI_SME_STOP_BSS_RSP); + CASE_RETURN_STRING(eWNI_SME_NEIGHBOR_BSS_IND); + CASE_RETURN_STRING(eWNI_SME_DEAUTH_CNF); + CASE_RETURN_STRING(eWNI_SME_MIC_FAILURE_IND); + CASE_RETURN_STRING(eWNI_SME_ADDTS_REQ); + CASE_RETURN_STRING(eWNI_SME_ADDTS_RSP); + CASE_RETURN_STRING(eWNI_SME_DELTS_REQ); + CASE_RETURN_STRING(eWNI_SME_DELTS_RSP); + CASE_RETURN_STRING(eWNI_SME_DELTS_IND); + CASE_RETURN_STRING(eWNI_SME_GET_STATISTICS_REQ); + CASE_RETURN_STRING(eWNI_SME_GET_STATISTICS_RSP); + CASE_RETURN_STRING(eWNI_SME_GET_RSSI_REQ); + CASE_RETURN_STRING(eWNI_SME_GET_ASSOC_STAS_REQ); + CASE_RETURN_STRING(eWNI_SME_TKIP_CNTR_MEAS_REQ); + CASE_RETURN_STRING(eWNI_SME_UPDATE_APWPSIE_REQ); + CASE_RETURN_STRING(eWNI_SME_GET_WPSPBC_SESSION_REQ); + CASE_RETURN_STRING(eWNI_SME_WPS_PBC_PROBE_REQ_IND); + CASE_RETURN_STRING(eWNI_SME_SET_APWPARSNIEs_REQ); + CASE_RETURN_STRING(eWNI_SME_UPPER_LAYER_ASSOC_CNF); + CASE_RETURN_STRING(eWNI_SME_SESSION_UPDATE_PARAM); + CASE_RETURN_STRING(eWNI_SME_CHNG_MCC_BEACON_INTERVAL); + CASE_RETURN_STRING(eWNI_SME_REMAIN_ON_CHANNEL_REQ); + CASE_RETURN_STRING(eWNI_SME_REMAIN_ON_CHN_RSP); + CASE_RETURN_STRING(eWNI_SME_REMAIN_ON_CHN_RDY_IND); + CASE_RETURN_STRING(eWNI_SME_SEND_ACTION_FRAME_IND); + CASE_RETURN_STRING(eWNI_SME_ABORT_REMAIN_ON_CHAN_IND); + CASE_RETURN_STRING(eWNI_SME_UPDATE_NOA); + CASE_RETURN_STRING(eWNI_SME_CLEAR_DFS_CHANNEL_LIST); + CASE_RETURN_STRING(eWNI_SME_GET_SNR_REQ); + CASE_RETURN_STRING(eWNI_SME_LINK_STATUS_IND); + CASE_RETURN_STRING(eWNI_SME_RRM_MSG_TYPE_BEGIN); + CASE_RETURN_STRING(eWNI_SME_NEIGHBOR_REPORT_REQ_IND); + CASE_RETURN_STRING(eWNI_SME_NEIGHBOR_REPORT_IND); + CASE_RETURN_STRING(eWNI_SME_BEACON_REPORT_REQ_IND); + CASE_RETURN_STRING(eWNI_SME_BEACON_REPORT_RESP_XMIT_IND); + CASE_RETURN_STRING(eWNI_SME_ADD_STA_SELF_RSP); + CASE_RETURN_STRING(eWNI_SME_DEL_STA_SELF_RSP); + CASE_RETURN_STRING(eWNI_SME_FT_PRE_AUTH_REQ); + CASE_RETURN_STRING(eWNI_SME_FT_PRE_AUTH_RSP); + CASE_RETURN_STRING(eWNI_SME_FT_UPDATE_KEY); + CASE_RETURN_STRING(eWNI_SME_FT_AGGR_QOS_REQ); + CASE_RETURN_STRING(eWNI_SME_FT_AGGR_QOS_RSP); +#if defined FEATURE_WLAN_ESE + CASE_RETURN_STRING(eWNI_SME_ESE_ADJACENT_AP_REPORT); +#endif + CASE_RETURN_STRING(eWNI_SME_REGISTER_MGMT_FRAME_REQ); +#ifdef FEATURE_WLAN_SCAN_PNO + CASE_RETURN_STRING(eWNI_SME_PREF_NETWORK_FOUND_IND); +#endif /* FEATURE_WLAN_SCAN_PNO */ + CASE_RETURN_STRING(eWNI_SME_CHANGE_COUNTRY_CODE); + CASE_RETURN_STRING(eWNI_SME_GENERIC_CHANGE_COUNTRY_CODE); + CASE_RETURN_STRING(eWNI_SME_MAX_ASSOC_EXCEEDED); +#ifdef WLAN_FEATURE_GTK_OFFLOAD + CASE_RETURN_STRING(eWNI_PMC_GTK_OFFLOAD_GETINFO_RSP); +#endif /* WLAN_FEATURE_GTK_OFFLOAD */ + CASE_RETURN_STRING(eWNI_SME_ROAM_SCAN_OFFLOAD_RSP); +#ifdef FEATURE_WLAN_LPHB + CASE_RETURN_STRING(eWNI_SME_LPHB_IND); +#endif /* FEATURE_WLAN_LPHB */ + CASE_RETURN_STRING(eWNI_SME_IBSS_PEER_INFO_RSP); +#ifdef FEATURE_WLAN_CH_AVOID + CASE_RETURN_STRING(eWNI_SME_CH_AVOID_IND); +#endif /* FEATURE_WLAN_CH_AVOID */ + CASE_RETURN_STRING(eWNI_SME_DFS_RADAR_FOUND); + CASE_RETURN_STRING(eWNI_SME_CHANNEL_CHANGE_REQ); + CASE_RETURN_STRING(eWNI_SME_CHANNEL_CHANGE_RSP); + CASE_RETURN_STRING(eWNI_SME_START_BEACON_REQ); + CASE_RETURN_STRING(eWNI_SME_DFS_BEACON_CHAN_SW_IE_REQ); + CASE_RETURN_STRING(eWNI_SME_DFS_CSAIE_TX_COMPLETE_IND); + CASE_RETURN_STRING(eWNI_SME_STATS_EXT_EVENT); + CASE_RETURN_STRING(eWNI_SME_CSA_OFFLOAD_EVENT); + CASE_RETURN_STRING(eWNI_SME_UPDATE_ADDITIONAL_IES); + CASE_RETURN_STRING(eWNI_SME_MODIFY_ADDITIONAL_IES); +#ifdef FEATURE_WLAN_AUTO_SHUTDOWN + CASE_RETURN_STRING(eWNI_SME_AUTO_SHUTDOWN_IND); +#endif + CASE_RETURN_STRING(eWNI_SME_SET_HT_2040_MODE); + CASE_RETURN_STRING(eWNI_SME_HO_FAIL_IND); +#ifdef FEATURE_WLAN_TDLS + CASE_RETURN_STRING(eWNI_SME_TDLS_SEND_MGMT_REQ); + CASE_RETURN_STRING(eWNI_SME_TDLS_SEND_MGMT_RSP); + CASE_RETURN_STRING(eWNI_SME_TDLS_ADD_STA_REQ); + CASE_RETURN_STRING(eWNI_SME_TDLS_ADD_STA_RSP); + CASE_RETURN_STRING(eWNI_SME_TDLS_DEL_STA_REQ); + CASE_RETURN_STRING(eWNI_SME_TDLS_DEL_STA_RSP); + CASE_RETURN_STRING(eWNI_SME_TDLS_DEL_STA_IND); + CASE_RETURN_STRING(eWNI_SME_TDLS_DEL_ALL_PEER_IND); + CASE_RETURN_STRING(eWNI_SME_MGMT_FRM_TX_COMPLETION_IND); + CASE_RETURN_STRING(eWNI_SME_TDLS_LINK_ESTABLISH_REQ); + CASE_RETURN_STRING(eWNI_SME_TDLS_LINK_ESTABLISH_RSP); + CASE_RETURN_STRING(eWNI_SME_TDLS_SHOULD_DISCOVER); + CASE_RETURN_STRING(eWNI_SME_TDLS_SHOULD_TEARDOWN); + CASE_RETURN_STRING(eWNI_SME_TDLS_PEER_DISCONNECTED); + CASE_RETURN_STRING + (eWNI_SME_TDLS_CONNECTION_TRACKER_NOTIFICATION); +#endif + CASE_RETURN_STRING(eWNI_SME_SET_BCN_FILTER_REQ); + CASE_RETURN_STRING(eWNI_SME_RESET_AP_CAPS_CHANGED); +#ifdef WLAN_FEATURE_11W + CASE_RETURN_STRING(eWNI_SME_UNPROT_MGMT_FRM_IND); +#endif + CASE_RETURN_STRING(eWNI_SME_CANDIDATE_FOUND_IND); + CASE_RETURN_STRING(eWNI_SME_HANDOFF_REQ); + CASE_RETURN_STRING(eWNI_SME_GET_TSM_STATS_REQ); + CASE_RETURN_STRING(eWNI_SME_GET_TSM_STATS_RSP); + CASE_RETURN_STRING(eWNI_SME_TSM_IE_IND); + CASE_RETURN_STRING(eWNI_SME_READY_TO_SUSPEND_IND); + CASE_RETURN_STRING(eWNI_SME_SET_HW_MODE_REQ); + CASE_RETURN_STRING(eWNI_SME_SET_HW_MODE_RESP); + CASE_RETURN_STRING(eWNI_SME_HW_MODE_TRANS_IND); + CASE_RETURN_STRING(eWNI_SME_NSS_UPDATE_REQ); + CASE_RETURN_STRING(eWNI_SME_NSS_UPDATE_RSP); + CASE_RETURN_STRING(eWNI_SME_SCAN_CMD); + CASE_RETURN_STRING(eWNI_SME_REGISTER_MGMT_FRAME_CB); + CASE_RETURN_STRING(eWNI_SME_HT40_OBSS_SCAN_IND); +#ifdef WLAN_FEATURE_NAN + CASE_RETURN_STRING(eWNI_SME_NAN_EVENT); +#endif +#ifdef WLAN_FEATURE_EXTWOW_SUPPORT + CASE_RETURN_STRING(eWNI_SME_READY_TO_EXTWOW_IND); +#endif + CASE_RETURN_STRING(eWNI_SME_MSG_GET_TEMPERATURE_IND); + CASE_RETURN_STRING(eWNI_SME_SNR_IND); +#ifdef FEATURE_WLAN_EXTSCAN + CASE_RETURN_STRING(eWNI_SME_EXTSCAN_FULL_SCAN_RESULT_IND); + CASE_RETURN_STRING(eWNI_SME_EPNO_NETWORK_FOUND_IND); +#endif + CASE_RETURN_STRING(eWNI_SME_SET_THERMAL_LEVEL_IND); + CASE_RETURN_STRING(eWNI_SME_OCB_SET_CONFIG_RSP); + CASE_RETURN_STRING(eWNI_SME_OCB_GET_TSF_TIMER_RSP); + CASE_RETURN_STRING(eWNI_SME_DCC_GET_STATS_RSP); + CASE_RETURN_STRING(eWNI_SME_DCC_UPDATE_NDL_RSP); + CASE_RETURN_STRING(eWNI_SME_DCC_STATS_EVENT); + CASE_RETURN_STRING(eWNI_SME_SET_DUAL_MAC_CFG_REQ); + CASE_RETURN_STRING(eWNI_SME_SET_DUAL_MAC_CFG_RESP); + CASE_RETURN_STRING(eWNI_SME_ROC_CMD); + CASE_RETURN_STRING(eWNI_SME_SET_IE_REQ); + CASE_RETURN_STRING(eWNI_SME_FW_DUMP_IND); + CASE_RETURN_STRING(eWNI_SME_EXT_CHANGE_CHANNEL); + CASE_RETURN_STRING(eWNI_SME_EXT_CHANGE_CHANNEL_IND); + CASE_RETURN_STRING(eWNI_SME_SET_ANTENNA_MODE_REQ); + CASE_RETURN_STRING(eWNI_SME_SET_ANTENNA_MODE_RESP); + CASE_RETURN_STRING(eWNI_SME_TSF_EVENT); + CASE_RETURN_STRING(eWNI_SME_MON_INIT_SESSION); + CASE_RETURN_STRING(eWNI_SME_PDEV_SET_HT_VHT_IE); + CASE_RETURN_STRING(eWNI_SME_SET_VDEV_IES_PER_BAND); + CASE_RETURN_STRING(eWNI_SME_NDP_INITIATOR_REQ); + CASE_RETURN_STRING(eWNI_SME_NDP_INITIATOR_RSP); + CASE_RETURN_STRING(eWNI_SME_NDP_NEW_PEER_IND); + CASE_RETURN_STRING(eWNI_SME_NDP_CONFIRM_IND); + CASE_RETURN_STRING(eWNI_SME_NDP_INDICATION); + CASE_RETURN_STRING(eWNI_SME_NDP_RESPONDER_REQ); + CASE_RETURN_STRING(eWNI_SME_NDP_RESPONDER_RSP); + CASE_RETURN_STRING(eWNI_SME_NDP_END_REQ); + CASE_RETURN_STRING(eWNI_SME_NDP_END_RSP); + CASE_RETURN_STRING(eWNI_SME_NDP_PEER_DEPARTED_IND); + CASE_RETURN_STRING(eWNI_SME_NDP_END_IND); + CASE_RETURN_STRING(eWNI_SME_REGISTER_P2P_ACK_CB); + CASE_RETURN_STRING(eWNI_SME_SEND_DISASSOC_FRAME); + CASE_RETURN_STRING(eWNI_SME_UPDATE_ACCESS_POLICY_VENDOR_IE); + CASE_RETURN_STRING(eWNI_SME_DEFAULT_SCAN_IE); + CASE_RETURN_STRING(eWNI_SME_ROAM_SCAN_OFFLOAD_REQ); + CASE_RETURN_STRING(eWNI_SME_LOST_LINK_INFO_IND); + CASE_RETURN_STRING(eWNI_SME_RSO_CMD_STATUS_IND); + CASE_RETURN_STRING(eWNI_SME_MSG_TYPES_END); + default: + return (uint8_t *) "UNKNOWN"; + break; + } +} + +/** + * mac_trace_get_wma_msg_string() - Get the msg + * @wma_msg: message type in numeric form + * + * This function will return a string equivalent of the message. + * + * Return: String equivalent of the message type. + **/ +uint8_t *mac_trace_get_wma_msg_string(uint16_t wma_msg) +{ + switch (wma_msg) { + CASE_RETURN_STRING(WMA_ADD_STA_REQ); + CASE_RETURN_STRING(WMA_ADD_STA_RSP); + CASE_RETURN_STRING(WMA_ADD_STA_SELF_RSP); + CASE_RETURN_STRING(WMA_DELETE_STA_REQ); + CASE_RETURN_STRING(WMA_DELETE_STA_RSP); + CASE_RETURN_STRING(WMA_ADD_BSS_REQ); + CASE_RETURN_STRING(WMA_ADD_BSS_RSP); + CASE_RETURN_STRING(WMA_DELETE_BSS_REQ); + CASE_RETURN_STRING(WMA_DELETE_BSS_HO_FAIL_REQ); + CASE_RETURN_STRING(WMA_DELETE_BSS_RSP); + CASE_RETURN_STRING(WMA_DELETE_BSS_HO_FAIL_RSP); + CASE_RETURN_STRING(WMA_SEND_BEACON_REQ); + CASE_RETURN_STRING(WMA_SET_BSSKEY_REQ); + CASE_RETURN_STRING(WMA_SET_BSSKEY_RSP); + CASE_RETURN_STRING(WMA_SET_STAKEY_REQ); + CASE_RETURN_STRING(WMA_SET_STAKEY_RSP); + CASE_RETURN_STRING(WMA_UPDATE_EDCA_PROFILE_IND); + + CASE_RETURN_STRING(WMA_UPDATE_BEACON_IND); + CASE_RETURN_STRING(WMA_UPDATE_CF_IND); + CASE_RETURN_STRING(WMA_CHNL_SWITCH_REQ); + CASE_RETURN_STRING(WMA_ADD_TS_REQ); + CASE_RETURN_STRING(WMA_DEL_TS_REQ); + CASE_RETURN_STRING(WMA_EXIT_PS_REQ); + CASE_RETURN_STRING(WMA_ENTER_PS_REQ); + CASE_RETURN_STRING(WMA_MISSED_BEACON_IND); + + CASE_RETURN_STRING(WMA_SWITCH_CHANNEL_RSP); + CASE_RETURN_STRING(WMA_P2P_NOA_ATTR_IND); + CASE_RETURN_STRING(WMA_P2P_NOA_START_IND); + CASE_RETURN_STRING(WMA_PWR_SAVE_CFG); + CASE_RETURN_STRING(WMA_REGISTER_PE_CALLBACK); + + CASE_RETURN_STRING(WMA_IBSS_STA_ADD); + CASE_RETURN_STRING(WMA_TIMER_ADJUST_ADAPTIVE_THRESHOLD_IND); + CASE_RETURN_STRING(WMA_SET_LINK_STATE); + CASE_RETURN_STRING(WMA_SET_LINK_STATE_RSP); + CASE_RETURN_STRING(WMA_SET_STA_BCASTKEY_REQ); + CASE_RETURN_STRING(WMA_SET_STA_BCASTKEY_RSP); + CASE_RETURN_STRING(WMA_ADD_TS_RSP); + CASE_RETURN_STRING(WMA_DPU_MIC_ERROR); + + CASE_RETURN_STRING(WMA_TIMER_CHIP_MONITOR_TIMEOUT); + CASE_RETURN_STRING(WMA_TIMER_TRAFFIC_ACTIVITY_REQ); + CASE_RETURN_STRING(WMA_TIMER_ADC_RSSI_STATS); +#ifdef FEATURE_WLAN_ESE + CASE_RETURN_STRING(WMA_TSM_STATS_REQ); + CASE_RETURN_STRING(WMA_TSM_STATS_RSP); +#endif + CASE_RETURN_STRING(WMA_HT40_OBSS_SCAN_IND); + CASE_RETURN_STRING(WMA_SET_MIMOPS_REQ); + CASE_RETURN_STRING(WMA_SET_MIMOPS_RSP); + CASE_RETURN_STRING(WMA_SYS_READY_IND); + CASE_RETURN_STRING(WMA_SET_TX_POWER_REQ); + CASE_RETURN_STRING(WMA_SET_TX_POWER_RSP); + CASE_RETURN_STRING(WMA_GET_TX_POWER_REQ); + + CASE_RETURN_STRING(WMA_TRANSMISSION_CONTROL_IND); + CASE_RETURN_STRING(WMA_ENABLE_UAPSD_REQ); + CASE_RETURN_STRING(WMA_DISABLE_UAPSD_REQ); + CASE_RETURN_STRING(WMA_BEACON_FILTER_IND); + CASE_RETURN_STRING(WMA_WOW_ADD_PTRN); + CASE_RETURN_STRING(WMA_WOW_DEL_PTRN); + CASE_RETURN_STRING(WMA_WOWL_ENTER_REQ); + CASE_RETURN_STRING(WMA_WOWL_EXIT_REQ); + CASE_RETURN_STRING(WMA_GET_STATISTICS_REQ); + CASE_RETURN_STRING(WMA_GET_STATISTICS_RSP); + CASE_RETURN_STRING(WMA_SET_KEY_DONE); + + CASE_RETURN_STRING(WMA_BTC_SET_CFG); + CASE_RETURN_STRING(WMA_HANDLE_FW_MBOX_RSP); + CASE_RETURN_STRING(WMA_SEND_PROBE_RSP_TMPL); + CASE_RETURN_STRING(WMA_SET_MAX_TX_POWER_REQ); + CASE_RETURN_STRING(WMA_SET_HOST_OFFLOAD); + CASE_RETURN_STRING(WMA_SET_KEEP_ALIVE); +#ifdef WLAN_NS_OFFLOAD + CASE_RETURN_STRING(WMA_SET_NS_OFFLOAD); +#endif /* WLAN_NS_OFFLOAD */ + CASE_RETURN_STRING(WMA_ADD_STA_SELF_REQ); + CASE_RETURN_STRING(WMA_DEL_STA_SELF_REQ); + CASE_RETURN_STRING(WMA_SET_P2P_GO_NOA_REQ); + CASE_RETURN_STRING(WMA_WLAN_SUSPEND_IND); + CASE_RETURN_STRING(WMA_WLAN_RESUME_REQ); +#ifdef WLAN_FEATURE_EXTWOW_SUPPORT + CASE_RETURN_STRING(WMA_WLAN_EXT_WOW); + CASE_RETURN_STRING(WMA_WLAN_SET_APP_TYPE1_PARAMS); + CASE_RETURN_STRING(WMA_WLAN_SET_APP_TYPE2_PARAMS); +#endif + CASE_RETURN_STRING(WMA_MSG_TYPES_END); + CASE_RETURN_STRING(WMA_RUNTIME_PM_SUSPEND_IND); + CASE_RETURN_STRING(WMA_RUNTIME_PM_RESUME_IND); + CASE_RETURN_STRING(WMA_AGGR_QOS_REQ); + CASE_RETURN_STRING(WMA_AGGR_QOS_RSP); + CASE_RETURN_STRING(WMA_FTM_CMD_REQ); + CASE_RETURN_STRING(WMA_FTM_CMD_RSP); +#ifdef FEATURE_WLAN_SCAN_PNO + CASE_RETURN_STRING(WMA_SET_PNO_REQ); + CASE_RETURN_STRING(WMA_SME_SCAN_CACHE_UPDATED); +#endif /* FEATURE_WLAN_SCAN_PNO */ + CASE_RETURN_STRING(WMA_ROAM_SCAN_OFFLOAD_REQ); +#ifdef WLAN_FEATURE_PACKET_FILTERING + CASE_RETURN_STRING(WMA_8023_MULTICAST_LIST_REQ); + CASE_RETURN_STRING(WMA_RECEIVE_FILTER_SET_FILTER_REQ); + CASE_RETURN_STRING + (WMA_PACKET_COALESCING_FILTER_MATCH_COUNT_REQ); + CASE_RETURN_STRING + (WMA_PACKET_COALESCING_FILTER_MATCH_COUNT_RSP); + CASE_RETURN_STRING(WMA_RECEIVE_FILTER_CLEAR_FILTER_REQ); +#endif /* WLAN_FEATURE_PACKET_FILTERING */ +#ifdef WLAN_FEATURE_GTK_OFFLOAD + CASE_RETURN_STRING(WMA_GTK_OFFLOAD_REQ); + CASE_RETURN_STRING(WMA_GTK_OFFLOAD_GETINFO_REQ); + CASE_RETURN_STRING(WMA_GTK_OFFLOAD_GETINFO_RSP); +#endif /* WLAN_FEATURE_GTK_OFFLOAD */ + CASE_RETURN_STRING(WMA_SET_TM_LEVEL_REQ); + CASE_RETURN_STRING(WMA_UPDATE_OP_MODE); + CASE_RETURN_STRING(WMA_UPDATE_MEMBERSHIP); + CASE_RETURN_STRING(WMA_UPDATE_USERPOS); + CASE_RETURN_STRING(WMA_START_SCAN_OFFLOAD_REQ); + CASE_RETURN_STRING(WMA_STOP_SCAN_OFFLOAD_REQ); + CASE_RETURN_STRING(WMA_UPDATE_CHAN_LIST_REQ); + CASE_RETURN_STRING(WMA_CLI_SET_CMD); +#ifndef REMOVE_PKT_LOG + CASE_RETURN_STRING(WMA_PKTLOG_ENABLE_REQ); +#endif +#ifdef FEATURE_WLAN_ESE + CASE_RETURN_STRING(WMA_SET_PLM_REQ); +#endif + CASE_RETURN_STRING(WMA_CONFIG_PARAM_UPDATE_REQ); + CASE_RETURN_STRING(WMA_RATE_UPDATE_IND); + CASE_RETURN_STRING(WMA_INIT_BAD_PEER_TX_CTL_INFO_CMD); +#ifdef FEATURE_WLAN_TDLS + CASE_RETURN_STRING(WMA_UPDATE_FW_TDLS_STATE); + CASE_RETURN_STRING(WMA_UPDATE_TDLS_PEER_STATE); +#endif + CASE_RETURN_STRING(WMA_ADD_PERIODIC_TX_PTRN_IND); + CASE_RETURN_STRING(WMA_TX_POWER_LIMIT); +#ifdef FEATURE_WLAN_LPHB + CASE_RETURN_STRING(WMA_LPHB_CONF_REQ); +#endif + CASE_RETURN_STRING(WMA_DHCP_START_IND); + CASE_RETURN_STRING(WMA_DHCP_STOP_IND); +#ifdef FEATURE_WLAN_CH_AVOID + CASE_RETURN_STRING(WMA_CH_AVOID_UPDATE_REQ); +#endif +#ifdef FEATURE_WLAN_AUTO_SHUTDOWN + CASE_RETURN_STRING(WMA_SET_AUTO_SHUTDOWN_TIMER_REQ); +#endif + CASE_RETURN_STRING(WMA_IBSS_CESIUM_ENABLE_IND); + CASE_RETURN_STRING(WMA_GET_IBSS_PEER_INFO_REQ); + CASE_RETURN_STRING(WMA_TX_FAIL_MONITOR_IND); + CASE_RETURN_STRING(WMA_RMC_ENABLE_IND); + CASE_RETURN_STRING(WMA_RMC_DISABLE_IND); + CASE_RETURN_STRING(WMA_RMC_ACTION_PERIOD_IND); + CASE_RETURN_STRING(WMA_INIT_THERMAL_INFO_CMD); + CASE_RETURN_STRING(WMA_SET_THERMAL_LEVEL); + CASE_RETURN_STRING(WMA_SET_SAP_INTRABSS_DIS); +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + CASE_RETURN_STRING(WMA_ROAM_OFFLOAD_SYNCH_FAIL); +#endif + CASE_RETURN_STRING(SIR_HAL_SET_BASE_MACADDR_IND); + CASE_RETURN_STRING(WMA_LINK_STATUS_GET_REQ); +#ifdef DHCP_SERVER_OFFLOAD + CASE_RETURN_STRING(WMA_SET_DHCP_SERVER_OFFLOAD_CMD); +#endif + CASE_RETURN_STRING(WMA_OCB_SET_CONFIG_CMD); + CASE_RETURN_STRING(WMA_OCB_SET_UTC_TIME_CMD); + CASE_RETURN_STRING(WMA_OCB_START_TIMING_ADVERT_CMD); + CASE_RETURN_STRING(WMA_OCB_STOP_TIMING_ADVERT_CMD); + CASE_RETURN_STRING(WMA_OCB_GET_TSF_TIMER_CMD); + CASE_RETURN_STRING(WMA_DCC_GET_STATS_CMD); + CASE_RETURN_STRING(WMA_DCC_CLEAR_STATS_CMD); + CASE_RETURN_STRING(WMA_DCC_UPDATE_NDL_CMD); + CASE_RETURN_STRING(WMA_SET_IE_INFO); + CASE_RETURN_STRING(WMA_LRO_CONFIG_CMD); + CASE_RETURN_STRING(WMA_GW_PARAM_UPDATE_REQ); + CASE_RETURN_STRING(WMA_SET_EGAP_CONF_PARAMS); + CASE_RETURN_STRING(WMA_ADD_BCN_FILTER_CMDID); + CASE_RETURN_STRING(WMA_REMOVE_BCN_FILTER_CMDID); + CASE_RETURN_STRING(WMA_SET_ADAPT_DWELLTIME_CONF_PARAMS); + CASE_RETURN_STRING(WDA_BPF_GET_CAPABILITIES_REQ); + CASE_RETURN_STRING(WDA_BPF_SET_INSTRUCTIONS_REQ); + CASE_RETURN_STRING(WMA_SET_PDEV_IE_REQ); + CASE_RETURN_STRING(WMA_UPDATE_WEP_DEFAULT_KEY); + CASE_RETURN_STRING(WMA_SEND_FREQ_RANGE_CONTROL_IND); + CASE_RETURN_STRING(WMA_ENCRYPT_DECRYPT_MSG); + CASE_RETURN_STRING(WMA_POWER_DEBUG_STATS_REQ); + CASE_RETURN_STRING(WNI_CFG_DNLD_REQ); + CASE_RETURN_STRING(SIR_HAL_UNIT_TEST_CMD); +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + CASE_RETURN_STRING(SIR_HAL_ROAM_INVOKE); +#endif + CASE_RETURN_STRING(SIR_HAL_SET_MAS); + CASE_RETURN_STRING(SIR_HAL_SET_MIRACAST); + CASE_RETURN_STRING(SIR_HAL_CONFIG_STATS_FACTOR); + CASE_RETURN_STRING(SIR_HAL_CONFIG_GUARD_TIME); + CASE_RETURN_STRING(SIR_HAL_START_STOP_LOGGING); + CASE_RETURN_STRING(SIR_HAL_FLUSH_LOG_TO_FW); + CASE_RETURN_STRING(SIR_HAL_PDEV_SET_PCL_TO_FW); + CASE_RETURN_STRING(SIR_HAL_PDEV_SET_HW_MODE); + CASE_RETURN_STRING(SIR_HAL_PDEV_DUAL_MAC_CFG_REQ); + CASE_RETURN_STRING(WMA_RADAR_DETECTED_IND); + CASE_RETURN_STRING(WMA_TIMER_TRAFFIC_STATS_IND); +#ifdef WLAN_FEATURE_11W + CASE_RETURN_STRING(WMA_EXCLUDE_UNENCRYPTED_IND); +#endif + CASE_RETURN_STRING(WMA_WOWL_ENTER_RSP); + CASE_RETURN_STRING(WMA_WOWL_EXIT_RSP); + CASE_RETURN_STRING(WMA_SET_MAX_TX_POWER_RSP); + CASE_RETURN_STRING(WMA_SET_DTIM_PERIOD); + CASE_RETURN_STRING(WMA_SET_MAX_TX_POWER_PER_BAND_REQ); +#ifdef FEATURE_WLAN_TDLS + CASE_RETURN_STRING(WMA_SET_TDLS_LINK_ESTABLISH_REQ); + CASE_RETURN_STRING(WMA_SET_TDLS_LINK_ESTABLISH_REQ_RSP); +#endif + CASE_RETURN_STRING(WMA_CSA_OFFLOAD_EVENT); +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + CASE_RETURN_STRING(WMA_ROAM_OFFLOAD_SYNCH_IND); +#endif + CASE_RETURN_STRING(WMA_HIDDEN_SSID_VDEV_RESTART); + CASE_RETURN_STRING(WMA_UPDATE_RX_NSS); +#ifdef WLAN_FEATURE_NAN + CASE_RETURN_STRING(WMA_NAN_REQUEST); +#endif + CASE_RETURN_STRING(WMA_RX_SCAN_EVENT); + CASE_RETURN_STRING(WMA_IBSS_PEER_INACTIVITY_IND); + CASE_RETURN_STRING(WMA_DEL_PERIODIC_TX_PTRN_IND); +#ifdef FEATURE_WLAN_TDLS + CASE_RETURN_STRING(WMA_TDLS_SHOULD_DISCOVER_CMD); + CASE_RETURN_STRING(WMA_TDLS_SHOULD_TEARDOWN_CMD); + CASE_RETURN_STRING(WMA_TDLS_PEER_DISCONNECTED_CMD); + CASE_RETURN_STRING(WMA_TDLS_SET_OFFCHAN_MODE); + CASE_RETURN_STRING + (WMA_TDLS_CONNECTION_TRACKER_NOTIFICATION_CMD); +#endif + CASE_RETURN_STRING(WMA_DFS_RADAR_IND); + CASE_RETURN_STRING(WMA_DFS_BEACON_TX_SUCCESS_IND); + CASE_RETURN_STRING(WMA_DISASSOC_TX_COMP); + CASE_RETURN_STRING(WMA_DEAUTH_TX_COMP); + CASE_RETURN_STRING(WMA_MODEM_POWER_STATE_IND); +#ifdef WLAN_FEATURE_STATS_EXT + CASE_RETURN_STRING(WMA_STATS_EXT_REQUEST); +#endif + CASE_RETURN_STRING(WMA_IPA_OFFLOAD_ENABLE_DISABLE); + CASE_RETURN_STRING(WMA_GET_TEMPERATURE_REQ); +#ifdef FEATURE_WLAN_EXTSCAN + CASE_RETURN_STRING(WMA_EXTSCAN_GET_CAPABILITIES_REQ); + CASE_RETURN_STRING(WMA_EXTSCAN_START_REQ); + CASE_RETURN_STRING(WMA_EXTSCAN_STOP_REQ); + CASE_RETURN_STRING(WMA_EXTSCAN_SET_BSSID_HOTLIST_REQ); + CASE_RETURN_STRING(WMA_EXTSCAN_RESET_BSSID_HOTLIST_REQ); + CASE_RETURN_STRING(WMA_EXTSCAN_SET_SIGNF_CHANGE_REQ); + CASE_RETURN_STRING(WMA_EXTSCAN_RESET_SIGNF_CHANGE_REQ); + CASE_RETURN_STRING(WMA_EXTSCAN_GET_CACHED_RESULTS_REQ); + CASE_RETURN_STRING(WMA_SET_EPNO_LIST_REQ); + CASE_RETURN_STRING(WMA_SET_PASSPOINT_LIST_REQ); + CASE_RETURN_STRING(WMA_RESET_PASSPOINT_LIST_REQ); +#endif /* FEATURE_WLAN_EXTSCAN */ +#ifdef WLAN_FEATURE_LINK_LAYER_STATS + CASE_RETURN_STRING(WMA_LINK_LAYER_STATS_CLEAR_REQ); + CASE_RETURN_STRING(WMA_LINK_LAYER_STATS_SET_REQ); + CASE_RETURN_STRING(WMA_LINK_LAYER_STATS_GET_REQ); + CASE_RETURN_STRING(WMA_LINK_LAYER_STATS_RESULTS_RSP); +#endif /* WLAN_FEATURE_LINK_LAYER_STATS */ + CASE_RETURN_STRING(WMA_SET_SCAN_MAC_OUI_REQ); + CASE_RETURN_STRING(WMA_TSF_GPIO_PIN); +#ifdef WLAN_FEATURE_GPIO_LED_FLASHING + CASE_RETURN_STRING(WMA_LED_FLASHING_REQ); +#endif + CASE_RETURN_STRING(WMA_PROCESS_FW_EVENT); +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE + CASE_RETURN_STRING(WMA_UPDATE_Q2Q_IE_IND); +#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ + CASE_RETURN_STRING(WMA_SET_RSSI_MONITOR_REQ); + CASE_RETURN_STRING(WMA_FW_MEM_DUMP_REQ); + CASE_RETURN_STRING(WMA_SET_WISA_PARAMS); + CASE_RETURN_STRING(WMA_GET_RCPI_REQ); + CASE_RETURN_STRING(WMA_CONF_HW_FILTER); + CASE_RETURN_STRING(WMA_SET_WOW_PULSE_CMD); + CASE_RETURN_STRING(WDA_SET_UDP_RESP_OFFLOAD); + CASE_RETURN_STRING(WMA_SET_PER_ROAM_CONFIG_CMD); + default: + return (uint8_t *) "UNKNOWN"; + break; + } +} + +/** + * mac_trace_get_lim_msg_string() - Get the msg + * @lim_msg: message type in numeric form + * + * This function will return a string equivalent of the message. + * + * Return: String equivalent of the message type. + **/ +uint8_t *mac_trace_get_lim_msg_string(uint16_t lim_msg) +{ + switch (lim_msg) { + CASE_RETURN_STRING(SIR_LIM_RETRY_INTERRUPT_MSG); + CASE_RETURN_STRING(SIR_BB_XPORT_MGMT_MSG); + CASE_RETURN_STRING(SIR_LIM_INV_KEY_INTERRUPT_MSG); + CASE_RETURN_STRING(SIR_LIM_KEY_ID_INTERRUPT_MSG); + CASE_RETURN_STRING(SIR_LIM_REPLAY_THRES_INTERRUPT_MSG); + CASE_RETURN_STRING(SIR_LIM_TD_DUMMY_CALLBACK_MSG); + CASE_RETURN_STRING(SIR_LIM_SCH_CLEAN_MSG); + CASE_RETURN_STRING(SIR_LIM_RADAR_DETECT_IND); + CASE_RETURN_STRING(SIR_LIM_DEL_TS_IND); + CASE_RETURN_STRING(SIR_LIM_DELETE_STA_CONTEXT_IND); + CASE_RETURN_STRING(SIR_LIM_UPDATE_BEACON); + CASE_RETURN_STRING(SIR_LIM_JOIN_FAIL_TIMEOUT); + CASE_RETURN_STRING(SIR_LIM_AUTH_FAIL_TIMEOUT); + CASE_RETURN_STRING(SIR_LIM_AUTH_RSP_TIMEOUT); + CASE_RETURN_STRING(SIR_LIM_ASSOC_FAIL_TIMEOUT); + CASE_RETURN_STRING(SIR_LIM_REASSOC_FAIL_TIMEOUT); + CASE_RETURN_STRING(SIR_LIM_HEART_BEAT_TIMEOUT); + CASE_RETURN_STRING(SIR_LIM_PROBE_HB_FAILURE_TIMEOUT); + CASE_RETURN_STRING(SIR_LIM_ADDTS_RSP_TIMEOUT); + CASE_RETURN_STRING(SIR_LIM_LINK_TEST_DURATION_TIMEOUT); + CASE_RETURN_STRING(SIR_LIM_CNF_WAIT_TIMEOUT); + CASE_RETURN_STRING(SIR_LIM_UPDATE_OLBC_CACHEL_TIMEOUT); + CASE_RETURN_STRING(SIR_LIM_CHANNEL_SWITCH_TIMEOUT); + CASE_RETURN_STRING(SIR_LIM_QUIET_TIMEOUT); + CASE_RETURN_STRING(SIR_LIM_QUIET_BSS_TIMEOUT); + CASE_RETURN_STRING(SIR_LIM_WPS_OVERLAP_TIMEOUT); + CASE_RETURN_STRING(SIR_LIM_FT_PREAUTH_RSP_TIMEOUT); + CASE_RETURN_STRING(SIR_LIM_REMAIN_CHN_TIMEOUT); + CASE_RETURN_STRING(SIR_LIM_INSERT_SINGLESHOT_NOA_TIMEOUT); + CASE_RETURN_STRING(SIR_LIM_CONVERT_ACTIVE_CHANNEL_TO_PASSIVE); + CASE_RETURN_STRING(SIR_LIM_BEACON_GEN_IND); + CASE_RETURN_STRING(SIR_LIM_PERIODIC_PROBE_REQ_TIMEOUT); + CASE_RETURN_STRING(SIR_LIM_DISASSOC_ACK_TIMEOUT); + CASE_RETURN_STRING(SIR_LIM_DEAUTH_ACK_TIMEOUT); + CASE_RETURN_STRING(SIR_LIM_PERIODIC_JOIN_PROBE_REQ_TIMEOUT); + CASE_RETURN_STRING(SIR_LIM_AUTH_RETRY_TIMEOUT); + CASE_RETURN_STRING(SIR_LIM_MSG_TYPES_END); + CASE_RETURN_STRING(LIM_MLM_SCAN_REQ); + CASE_RETURN_STRING(LIM_MLM_SCAN_CNF); + CASE_RETURN_STRING(LIM_MLM_START_REQ); + CASE_RETURN_STRING(LIM_MLM_START_CNF); + CASE_RETURN_STRING(LIM_MLM_JOIN_REQ); + CASE_RETURN_STRING(LIM_MLM_JOIN_CNF); + CASE_RETURN_STRING(LIM_MLM_AUTH_REQ); + CASE_RETURN_STRING(LIM_MLM_AUTH_CNF); + CASE_RETURN_STRING(LIM_MLM_AUTH_IND); + CASE_RETURN_STRING(LIM_MLM_ASSOC_REQ); + CASE_RETURN_STRING(LIM_MLM_ASSOC_CNF); + CASE_RETURN_STRING(LIM_MLM_ASSOC_IND); + CASE_RETURN_STRING(LIM_MLM_DISASSOC_REQ); + CASE_RETURN_STRING(LIM_MLM_DISASSOC_CNF); + CASE_RETURN_STRING(LIM_MLM_DISASSOC_IND); + CASE_RETURN_STRING(LIM_MLM_REASSOC_REQ); + CASE_RETURN_STRING(LIM_MLM_REASSOC_CNF); + CASE_RETURN_STRING(LIM_MLM_REASSOC_IND); + CASE_RETURN_STRING(LIM_MLM_DEAUTH_REQ); + CASE_RETURN_STRING(LIM_MLM_DEAUTH_CNF); + CASE_RETURN_STRING(LIM_MLM_DEAUTH_IND); + CASE_RETURN_STRING(LIM_MLM_TSPEC_REQ); + CASE_RETURN_STRING(LIM_MLM_TSPEC_CNF); + CASE_RETURN_STRING(LIM_MLM_SETKEYS_REQ); + CASE_RETURN_STRING(LIM_MLM_SETKEYS_CNF); + CASE_RETURN_STRING(LIM_MLM_LINK_TEST_STOP_REQ); + CASE_RETURN_STRING(LIM_MLM_PURGE_STA_IND); + default: + return (uint8_t *) "UNKNOWN"; + break; + } +} + +/** + * mac_trace_get_cfg_msg_string() - Get the msg + * @cfg_msg: message type in numeric form + * + * This function will return a string equivalent of the message. + * + * Return: String equivalent of the message type. + **/ +uint8_t *mac_trace_get_cfg_msg_string(uint16_t cfg_msg) +{ + switch (cfg_msg) { + CASE_RETURN_STRING(WNI_CFG_PARAM_UPDATE_IND); + CASE_RETURN_STRING(WNI_CFG_DNLD_REQ); + CASE_RETURN_STRING(WNI_CFG_DNLD_CNF); + CASE_RETURN_STRING(WNI_CFG_GET_RSP); + CASE_RETURN_STRING(WNI_CFG_SET_CNF); + CASE_RETURN_STRING(WNI_CFG_GET_ATTRIB_RSP); + CASE_RETURN_STRING(WNI_CFG_ADD_GRP_ADDR_CNF); + CASE_RETURN_STRING(WNI_CFG_DEL_GRP_ADDR_CNF); + CASE_RETURN_STRING(SIR_CFG_PARAM_UPDATE_IND); + CASE_RETURN_STRING(SIR_CFG_DOWNLOAD_COMPLETE_IND); + CASE_RETURN_STRING(WNI_CFG_DNLD_RSP); + CASE_RETURN_STRING(WNI_CFG_GET_REQ); + CASE_RETURN_STRING(WNI_CFG_SET_REQ); + CASE_RETURN_STRING(WNI_CFG_SET_REQ_NO_RSP); + default: + return (uint8_t *) "UNKNOWN"; + break; + } +} + +/** + * mac_trace_get_info_log_string() - Get the log info + * @info_log: message type in numeric form + * + * This function will return a string equivalent of the message. + * + * Return: String equivalent of the message type. + **/ +uint8_t *mac_trace_get_info_log_string(uint16_t info_log) +{ + switch (info_log) { + CASE_RETURN_STRING(eLOG_NODROP_MISSED_BEACON_SCENARIO); + CASE_RETURN_STRING(eLOG_PROC_DEAUTH_FRAME_SCENARIO); + default: + return (uint8_t *) "UNKNOWN"; + break; + } +} + +/** + * mac_trace() - Main function used for MAC Trace + * @mac_ctx: Global MAC context + * @code: code + * @session: session id + * @data: data to be traced. + * + * Return: None + **/ +void mac_trace(tpAniSirGlobal mac_ctx, uint8_t code, + uint16_t session, uint32_t data) +{ + /* + * Today mac_trace is being invoked by PE only, need to remove this + * function once PE is migrated to using new trace API. + */ + mac_trace_new(mac_ctx, QDF_MODULE_ID_PE, code, session, data); +} + +/** + * mac_trace_new() - New function used for MAC Trace + * @mac_ctx: Global MAC context + * @code: code + * @session: session id + * @data: data to be traced. + * + * Return: None + **/ +void mac_trace_new(tpAniSirGlobal mac_ctx, uint8_t module, uint8_t code, + uint16_t session, uint32_t data) +{ + qdf_trace(module, code, session, data); +} + +#endif diff --git a/drivers/staging/qcacld-3.0/core/mac/src/sys/legacy/src/utils/src/parse_mac_trace.cmm b/drivers/staging/qcacld-3.0/core/mac/src/sys/legacy/src/utils/src/parse_mac_trace.cmm new file mode 100644 index 0000000000000000000000000000000000000000..b54deda08b71f3ff3cd9206d5e601921e1d64f91 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/sys/legacy/src/utils/src/parse_mac_trace.cmm @@ -0,0 +1,1006 @@ +;Copyright (c) 2013-2017 The Linux Foundation. All rights reserved. + +;Previously licensed under the ISC license by Qualcomm Atheros, Inc. + +;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. + +;This file was originally distributed by Qualcomm Atheros, Inc. +;under proprietary terms before Copyright ownership was assigned +;to the Linux Foundation. + +;parsemactrace.cmm - This script parses MAC trace table in UMAC layer +;This script relies on message id's placed in interface header file. +;If some message ID's are changed later, since they do not use enum, this script +;might show incorrect data. So message ID's should always be in sync +;Author: +;Date: 09/09/2013 +;History:- +;Date Modified by Modification Information +;-------------------------------------------------------------------- + + +ENTRY &FILE + +IF "&FILE"=="" +( +DIALOG.file *.txt +ENTRY &FILE +) + +OPEN #1 "&FILE" /Create /Write /Append + + +Var.NEW char [406][50] \halmsgtype + +Var.SET \halmsgtype[0x20]="SIR_HAL_RADAR_DETECTED_IND" +Var.SET \halmsgtype[0x21]="SIR_HAL_ADD_STA_REQ" +Var.SET \halmsgtype[0x22]="SIR_HAL_ADD_STA_RSP" +Var.SET \halmsgtype[0x23]="SIR_HAL_DELETE_STA_REQ" +Var.SET \halmsgtype[0x24]="SIR_HAL_DELETE_STA_RSP" +Var.SET \halmsgtype[0x25]="SIR_HAL_ADD_BSS_REQ" +Var.SET \halmsgtype[0x26]="SIR_HAL_ADD_BSS_RSP" +Var.SET \halmsgtype[0x27]="SIR_HAL_DELETE_BSS_REQ" +Var.SET \halmsgtype[0x28]="SIR_HAL_DELETE_BSS_RSP" +Var.SET \halmsgtype[0x29]="SIR_HAL_INIT_SCAN_REQ" +Var.SET \halmsgtype[0x2A]="SIR_HAL_INIT_SCAN_RSP" +Var.SET \halmsgtype[0x2B]="SIR_HAL_START_SCAN_REQ" +Var.SET \halmsgtype[0x2C]="SIR_HAL_START_SCAN_RSP" +Var.SET \halmsgtype[0x2D]="SIR_HAL_END_SCAN_REQ" +Var.SET \halmsgtype[0x2E]="SIR_HAL_END_SCAN_RSP" +Var.SET \halmsgtype[0x2F]="SIR_HAL_FINISH_SCAN_REQ" +Var.SET \halmsgtype[0x30]="SIR_HAL_FINISH_SCAN_RSP" +Var.SET \halmsgtype[0x31]="SIR_HAL_SEND_BEACON_REQ" +Var.SET \halmsgtype[0x32]="SIR_HAL_SET_BSSKEY_REQ" +Var.SET \halmsgtype[0x33]="SIR_HAL_SET_BSSKEY_RSP" +Var.SET \halmsgtype[0x34]="SIR_HAL_SET_STAKEY_REQ" +Var.SET \halmsgtype[0x35]="SIR_HAL_SET_STAKEY_RSP" +Var.SET \halmsgtype[0x36]="SIR_HAL_UPDATE_EDCA_PROFILE_IND" +Var.SET \halmsgtype[0x37]="SIR_HAL_UPDATE_BEACON_IND" +Var.SET \halmsgtype[0x38]="SIR_HAL_UPDATE_CF_IND" +Var.SET \halmsgtype[0x39]="SIR_HAL_CHNL_SWITCH_REQ" +Var.SET \halmsgtype[0x3A]="SIR_HAL_ADD_TS_REQ" +Var.SET \halmsgtype[0x3B]="SIR_HAL_DEL_TS_REQ" +;28 to 33 macros unused +Var.SET \halmsgtype[0x42]="SIR_HAL_MISSED_BEACON_IND" +Var.SET \halmsgtype[0x43]="SIR_HAL_SWITCH_CHANNEL_RSP" +Var.SET \halmsgtype[0x44]="SIR_HAL_PWR_SAVE_CFG" +Var.SET \halmsgtype[0x45]="SIR_HAL_REGISTER_PE_CALLBACK" +;38 to 42 unused +Var.SET \halmsgtype[0x4A]="SIR_HAL_IBSS_STA_ADD" +Var.SET \halmsgtype[0x4B]="SIR_HAL_TIMER_ADJUST_ADAPTIVE_THRESHOLD_IND" +Var.SET \halmsgtype[0x4C]="SIR_HAL_SET_LINK_STATE" +Var.SET \halmsgtype[0x4D]="SIR_HAL_DELETE_BSS_HO_FAIL_REQ" +Var.SET \halmsgtype[0x4E]="SIR_HAL_DELETE_BSS_HO_FAIL_RSP" +;48 to 57 unused +Var.SET \halmsgtype[0x59]="SIR_HAL_SET_STA_BCASTKEY_REQ" +Var.SET \halmsgtype[0x5A]="SIR_HAL_SET_STA_BCASTKEY_RSP" +Var.SET \halmsgtype[0x5B]="SIR_HAL_ADD_TS_RSP" +Var.SET \halmsgtype[0x5C]="SIR_HAL_DPU_MIC_ERROR" +;62 unused +Var.SET \halmsgtype[0x5E]="SIR_HAL_TIMER_CHIP_MONITOR_TIMEOUT" +Var.SET \halmsgtype[0x5F]="SIR_HAL_TIMER_TRAFFIC_ACTIVITY_REQ" +Var.SET \halmsgtype[0x60]="SIR_HAL_TIMER_ADC_RSSI_STATS" +;66 unused +Var.SET \halmsgtype[0x62]="SIR_HAL_SET_MIMOPS_REQ" +Var.SET \halmsgtype[0x63]="SIR_HAL_SET_MIMOPS_RSP" +Var.SET \halmsgtype[0x64]="SIR_HAL_SYS_READY_IND" +Var.SET \halmsgtype[0x65]="SIR_HAL_SET_TX_POWER_REQ" +Var.SET \halmsgtype[0x66]="SIR_HAL_SET_TX_POWER_RSP" +Var.SET \halmsgtype[0x67]="SIR_HAL_GET_TX_POWER_REQ" +Var.SET \halmsgtype[0x68]="SIR_HAL_GET_TX_POWER_RSP" +Var.SET \halmsgtype[0x69]="SIR_HAL_GET_NOISE_RSP" +Var.SET \halmsgtype[0x6A]="SIR_HAL_TRANSMISSION_CONTROL_IND" +;76 to 79 unused +Var.SET \halmsgtype[0x6F]="SIR_HAL_LOW_RSSI_IND" +Var.SET \halmsgtype[0x70]="SIR_HAL_BEACON_FILTER_IND" +Var.SET \halmsgtype[0x71]="SIR_HAL_WOW_ADD_PTRN" +Var.SET \halmsgtype[0x72]="SIR_HAL_WOW_DEL_PTRN" +Var.SET \halmsgtype[0x73]="SIR_HAL_WOWL_ENTER_REQ" +Var.SET \halmsgtype[0x74]="SIR_HAL_WOWL_ENTER_RSP" +Var.SET \halmsgtype[0x75]="SIR_HAL_WOWL_EXIT_REQ" +Var.SET \halmsgtype[0x76]="SIR_HAL_WOWL_EXIT_RSP" +Var.SET \halmsgtype[0x77]="SIR_HAL_GET_STATISTICS_REQ" +Var.SET \halmsgtype[0x78]="SIR_HAL_GET_STATISTICS_RSP" +Var.SET \halmsgtype[0x79]="SIR_HAL_SET_KEY_DONE" +Var.SET \halmsgtype[0x7A]="SIR_HAL_BTC_SET_CFG" +;92 unused +Var.SET \halmsgtype[0x7C]="SIR_HAL_HANDLE_FW_MBOX_RSP" +Var.SET \halmsgtype[0x7D]="SIR_HAL_SEND_PROBE_RSP_TMPL" +Var.SET \halmsgtype[0x7E]="SIR_LIM_ADDR2_MISS_IND" +Var.SET \halmsgtype[0x7F]="SIR_HAL_START_OEM_DATA_REQ" +Var.SET \halmsgtype[0x80]="SIR_HAL_START_OEM_DATA_RSP" +Var.SET \halmsgtype[0x81]="SIR_HAL_SET_MAX_TX_POWER_REQ" +Var.SET \halmsgtype[0x82]="SIR_HAL_SET_MAX_TX_POWER_RSP" +Var.SET \halmsgtype[0x83]="SIR_HAL_SET_HOST_OFFLOAD" +Var.SET \halmsgtype[0x84]="SIR_HAL_ADD_STA_SELF_REQ" +Var.SET \halmsgtype[0x85]="SIR_HAL_ADD_STA_SELF_RSP" +Var.SET \halmsgtype[0x86]="SIR_HAL_DEL_STA_SELF_REQ" +Var.SET \halmsgtype[0x87]="SIR_HAL_DEL_STA_SELF_RSP" +;105 unused +Var.SET \halmsgtype[0x88]="SIR_HAL_CFG_RXP_FILTER_REQ" +Var.SET \halmsgtype[0x89]="SIR_HAL_AGGR_ADD_TS_REQ" +Var.SET \halmsgtype[0x8A]="SIR_HAL_AGGR_ADD_TS_RSP" +Var.SET \halmsgtype[0x8B]="SIR_HAL_AGGR_QOS_REQ" +Var.SET \halmsgtype[0x8C]="SIR_HAL_AGGR_QOS_RSP" +Var.SET \halmsgtype[0x8D]="SIR_HAL_SET_P2P_GO_NOA_REQ" +Var.SET \halmsgtype[0x8E]="SIR_HAL_P2P_NOA_ATTR_IND" +Var.SET \halmsgtype[0x8F]="SIR_HAL_P2P_NOA_START_IND" +Var.SET \halmsgtype[0x90]="SIR_HAL_SET_LINK_STATE_RSP" +Var.SET \halmsgtype[0x91]="SIR_HAL_WLAN_SUSPEND_IND" +Var.SET \halmsgtype[0x92]="SIR_HAL_WLAN_RESUME_REQ" +Var.SET \halmsgtype[0x93]="SIR_HAL_SET_KEEP_ALIVE" +Var.SET \halmsgtype[0x94]="SIR_HAL_SET_NS_OFFLOAD" +Var.SET \halmsgtype[0x95]="SIR_HAL_SET_PNO_REQ" +Var.SET \halmsgtype[0x96]="SIR_HAL_SOC_ANTENNA_MODE_REQ" +Var.SET \halmsgtype[0x97]="SIR_HAL_SOC_ANTENNA_MODE_RESP" +;122 unused +Var.SET \halmsgtype[0x98]="SIR_HAL_8023_MULTICAST_LIST_REQ" +Var.SET \halmsgtype[0x99]="SIR_HAL_RECEIVE_FILTER_SET_FILTER_REQ" +Var.SET \halmsgtype[0x9A]="SIR_HAL_PACKET_COALESCING_FILTER_MATCH_COUNT_REQ" +Var.SET \halmsgtype[0x9B]="SIR_HAL_PACKET_COALESCING_FILTER_MATCH_COUNT_RSP" +Var.SET \halmsgtype[0x9C]="SIR_HAL_RECEIVE_FILTER_CLEAR_FILTER_REQ" +;128 unused +Var.SET \halmsgtype[0x9F]="SIR_HAL_GTK_OFFLOAD_REQ" +Var.SET \halmsgtype[0xA0]="SIR_HAL_GTK_OFFLOAD_GETINFO_REQ" +Var.SET \halmsgtype[0xA1]="SIR_HAL_GTK_OFFLOAD_GETINFO_RSP" +Var.SET \halmsgtype[0xA2]="SIR_HAL_TSM_STATS_REQ" +Var.SET \halmsgtype[0xA3]="SIR_HAL_TSM_STATS_RSP" +Var.SET \halmsgtype[0xA4]="SIR_HAL_SET_TM_LEVEL_REQ" +Var.SET \halmsgtype[0xA5]="SIR_HAL_UPDATE_OP_MODE" +Var.SET \halmsgtype[0xA6]="SIR_HAL_TDLS_LINK_ESTABLISH" +Var.SET \halmsgtype[0xA7]="SIR_HAL_TDLS_LINK_TEARDOWN" +Var.SET \halmsgtype[0xA8]="SIR_HAL_ROAM_SCAN_OFFLOAD_REQ" +;139 and 140 unused +Var.SET \halmsgtype[0xAB]="SIR_HAL_TRAFFIC_STATS_IND" +Var.SET \halmsgtype[0xAC]="SIR_HAL_EXCLUDE_UNENCRYPTED_IND" +Var.SET \halmsgtype[0xAD]="SIR_HAL_TDLS_LINK_ESTABLISH_REQ" +Var.SET \halmsgtype[0xAE]="SIR_HAL_TDLS_LINK_ESTABLISH_REQ_RSP" +Var.SET \halmsgtype[0xAF]="SIR_HAL_TDLS_IND" +Var.SET \halmsgtype[0xB0]="SIR_HAL_STOP_SCAN_OFFLOAD_REQ" +Var.SET \halmsgtype[0xB1]="SIR_HAL_RX_SCAN_EVENT" +Var.SET \halmsgtype[0xB2]="SIR_HAL_DHCP_START_IND" +Var.SET \halmsgtype[0xB3]="SIR_HAL_DHCP_STOP_IND" +Var.SET \halmsgtype[0xB4]="SIR_HAL_IBSS_PEER_INACTIVITY_IND" +Var.SET \halmsgtype[0xB5]="SIR_HAL_LPHB_CONF_IND" +Var.SET \halmsgtype[0xB6]="SIR_HAL_ADD_PERIODIC_TX_PTRN_IND" +Var.SET \halmsgtype[0xB7]="SIR_HAL_DEL_PERIODIC_TX_PTRN_IND" +Var.SET \halmsgtype[0xB8]="SIR_HAL_PDEV_DUAL_MAC_CFG_REQ" +Var.SET \halmsgtype[0xB9]="SIR_HAL_PDEV_MAC_CFG_RESP" +;156 and 157 unused +Var.SET \halmsgtype[0xBC]="SIR_HAL_IBSS_PEER_INFO_REQ" +Var.SET \halmsgtype[0xBD]="SIR_HAL_RATE_UPDATE_IND" +Var.SET \halmsgtype[0xBE]="SIR_HAL_FLUSH_LOG_TO_FW" +Var.SET \halmsgtype[0xBF]="SIR_HAL_PDEV_SET_PCL_TO_FW" +;162 unused +Var.SET \halmsgtype[0xC1]="SIR_HAL_CLI_SET_CMD" +Var.SET \halmsgtype[0xC2]="SIR_HAL_PKTLOG_ENABLE_REQ" +Var.SET \halmsgtype[0xC3]="SIR_HAL_SME_SCAN_CACHE_UPDATED" +Var.SET \halmsgtype[0xC4]="SIR_HAL_START_SCAN_OFFLOAD_REQ" +Var.SET \halmsgtype[0xC5]="SIR_HAL_UPDATE_CHAN_LIST_REQ" +;168 unused +Var.SET \halmsgtype[0xC7]="SIR_CSA_OFFLOAD_EVENT" +Var.SET \halmsgtype[0xC8]="SIR_HAL_SET_MAX_TX_POWER_PER_BAND_REQ" +Var.SET \halmsgtype[0xC9]="SIR_HAL_TX_FAIL_MONITOR_IND" +Var.SET \halmsgtype[0xCA]="SIR_HAL_UPDATE_MEMBERSHIP" +Var.SET \halmsgtype[0xCB]="SIR_HAL_UPDATE_USERPOS" +Var.SET \halmsgtype[0xCC]="SIR_HAL_UPDATE_FW_TDLS_STATE" +Var.SET \halmsgtype[0xCD]="SIR_HAL_UPDATE_TDLS_PEER_STATE" +Var.SET \halmsgtype[0xCE]="SIR_HAL_TDLS_SHOULD_DISCOVER" +Var.SET \halmsgtype[0xCF]="SIR_HAL_TDLS_SHOULD_TEARDOWN" +Var.SET \halmsgtype[0xD0]="SIR_HAL_TDLS_PEER_DISCONNECTED" +Var.SET \halmsgtype[0xD1]="SIR_HAL_BEACON_TX_SUCCESS_IND" +Var.SET \halmsgtype[0xD2]="SIR_HAL_DFS_RADAR_IND" +Var.SET \halmsgtype[0xD3]="SIR_HAL_IBSS_CESIUM_ENABLE_IND" +Var.SET \halmsgtype[0xD4]="SIR_HAL_RMC_ENABLE_IND" +Var.SET \halmsgtype[0xD5]="SIR_HAL_RMC_DISABLE_IND" +Var.SET \halmsgtype[0xD6]="SIR_HAL_RMC_ACTION_PERIOD_IND" +Var.SET \halmsgtype[0xD7]="SIR_HAL_INIT_THERMAL_INFO_CMD" +Var.SET \halmsgtype[0xD8]="SIR_HAL_SET_THERMAL_LEVEL" +Var.SET \halmsgtype[0xD9]="SIR_HAL_SET_PLM_REQ" +Var.SET \halmsgtype[0xDA]="SIR_HAL_SET_TX_POWER_LIMIT" +Var.SET \halmsgtype[0xDB]="SIR_HAL_SET_SAP_INTRABSS_DIS" +Var.SET \halmsgtype[0xDC]="SIR_HAL_MODEM_POWER_STATE_IND" +Var.SET \halmsgtype[0xDD]="SIR_HAL_DISASSOC_TX_COMP" +Var.SET \halmsgtype[0xDE]="SIR_HAL_DEAUTH_TX_COMP" +Var.SET \halmsgtype[0xDF]="SIR_HAL_UPDATE_RX_NSS" +Var.SET \halmsgtype[0xE0]="SIR_HAL_STATS_EXT_REQUEST" +Var.SET \halmsgtype[0xE1]="SIR_HAL_STATS_EXT_EVENT" +Var.SET \halmsgtype[0xE2]="SIR_HAL_HIDE_SSID_VDEV_RESTART" +Var.SET \halmsgtype[0xE3]="SIR_HAL_GET_LINK_SPEED" +Var.SET \halmsgtype[0xE4]="SIR_HAL_EXTSCAN_GET_CAPABILITIES_REQ" +Var.SET \halmsgtype[0xE5]="SIR_HAL_EXTSCAN_START_REQ" +Var.SET \halmsgtype[0xE6]="SIR_HAL_EXTSCAN_STOP_REQ" +Var.SET \halmsgtype[0xE7]="SIR_HAL_EXTSCAN_SET_BSS_HOTLIST_REQ" +Var.SET \halmsgtype[0xE8]="SIR_HAL_EXTSCAN_RESET_BSS_HOTLIST_REQ" +Var.SET \halmsgtype[0xE9]="SIR_HAL_EXTSCAN_SET_SIGNF_CHANGE_REQ" +Var.SET \halmsgtype[0xEA]="SIR_HAL_EXTSCAN_RESET_SIGNF_CHANGE_REQ" +Var.SET \halmsgtype[0xEB]="SIR_HAL_EXTSCAN_GET_CACHED_RESULTS_REQ" +Var.SET \halmsgtype[0xEC]="SIR_HAL_CH_AVOID_UPDATE_REQ" +Var.SET \halmsgtype[0xED]="SIR_HAL_LL_STATS_CLEAR_REQ" +Var.SET \halmsgtype[0xEE]="SIR_HAL_LL_STATS_SET_REQ" +Var.SET \halmsgtype[0xEF]="SIR_HAL_LL_STATS_GET_REQ" +Var.SET \halmsgtype[0xF0]="SIR_HAL_LL_STATS_RESULTS_RSP" +Var.SET \halmsgtype[0xF1]="SIR_HAL_ROAM_OFFLOAD_SYNCH_CNF" +Var.SET \halmsgtype[0xF2]="SIR_HAL_NAN_REQUEST" +Var.SET \halmsgtype[0xF3]="SIR_HAL_SET_AUTO_SHUTDOWN_TIMER_REQ" +Var.SET \halmsgtype[0xF4]="SIR_HAL_SET_BASE_MACADDR_IND" +Var.SET \halmsgtype[0xF5]="SIR_HAL_SET_BASE_MACADDR_IND" +Var.SET \halmsgtype[0xF6]="SIR_HAL_LINK_STATUS_GET_REQ" +Var.SET \halmsgtype[0xF7]="SIR_HAL_CONFIG_EXT_WOW" +Var.SET \halmsgtype[0xF8]="SIR_HAL_CONFIG_APP_TYPE1_PARAMS" +Var.SET \halmsgtype[0xF9]="SIR_HAL_CONFIG_APP_TYPE2_PARAMS" +Var.SET \halmsgtype[0xFA]="SIR_HAL_GET_TEMPERATURE_REQ" +Var.SET \halmsgtype[0xFB]="SIR_HAL_SET_SCAN_MAC_OUI_REQ" +Var.SET \halmsgtype[0xFC]="SIR_HAL_SET_DHCP_SERVER_OFFLOAD" +Var.SET \halmsgtype[0xFD]="SIR_HAL_LED_FLASHING_REQ" +Var.SET \halmsgtype[0xFE]="SIR_HAL_LED_FLASHING_REQ" +Var.SET \halmsgtype[0xFF]="SIR_HAL_ROAM_OFFLOAD_SYNCH_IND" +Var.SET \halmsgtype[0x100]="SIR_HAL_ROAM_OFFLOAD_SYNCH_FAIL" +Var.SET \halmsgtype[0x101]="SIR_HAL_ROAM_INVOKE" +Var.SET \halmsgtype[0x102]="SIR_HAL_TDLS_SET_OFFCHAN_MODE" +Var.SET \halmsgtype[0x103]="SIR_HAL_TDLS_SET_OFFCHAN_MODE" +Var.SET \halmsgtype[0x104]="SIR_HAL_SET_MIRACAST" +Var.SET \halmsgtype[0x105]="SIR_HAL_UPDATE_Q2Q_IE_IND" +Var.SET \halmsgtype[0x106]="SIR_HAL_UPDATE_Q2Q_IE_IND" +Var.SET \halmsgtype[0x107]="SIR_HAL_CONFIG_GUARD_TIME" +Var.SET \halmsgtype[0x108]="SIR_HAL_IPA_OFFLOAD_ENABLE_DISABLE" +Var.SET \halmsgtype[0x109]="SIR_HAL_ENTER_PS_REQ" +Var.SET \halmsgtype[0x10A]="SIR_HAL_EXIT_PS_REQ" +Var.SET \halmsgtype[0x10B]="SIR_HAL_ENABLE_UAPSD_REQ" +Var.SET \halmsgtype[0x10C]="SIR_HAL_DISABLE_UAPSD_REQ" +Var.SET \halmsgtype[0x10D]="SIR_HAL_GATEWAY_PARAM_UPDATE_REQ" +;240 to 307 unused +Var.SET \halmsgtype[0x152]="SIR_HAL_RUNTIME_PM_SUSPEND_IND" +Var.SET \halmsgtype[0x153]="SIR_HAL_RUNTIME_PM_RESUME_IND" +;310 to 312 unused +Var.SET \halmsgtype[0x157]="SIR_HAL_SET_EPNO_LIST_REQ" +;314 and 315 unused +Var.SET \halmsgtype[0x15A]="SIR_HAL_SET_PASSPOINT_LIST_REQ" +Var.SET \halmsgtype[0x15B]="SIR_HAL_RESET_PASSPOINT_LIST_REQ" +;318 unused +Var.SET \halmsgtype[0x15D]="SIR_HAL_OCB_SET_CONFIG_CMD" +Var.SET \halmsgtype[0x15E]="SIR_HAL_OCB_SET_UTC_TIME_CMD" +Var.SET \halmsgtype[0x15F]="SIR_HAL_OCB_START_TIMING_ADVERT_CMD" +Var.SET \halmsgtype[0x160]="SIR_HAL_OCB_STOP_TIMING_ADVERT_CMD" +Var.SET \halmsgtype[0x161]="SIR_HAL_OCB_GET_TSF_TIMER_CMD" +Var.SET \halmsgtype[0x162]="SIR_HAL_DCC_GET_STATS_CMD" +Var.SET \halmsgtype[0x163]="SIR_HAL_DCC_CLEAR_STATS_CMD" +Var.SET \halmsgtype[0x164]="SIR_HAL_DCC_UPDATE_NDL_CMD" +Var.SET \halmsgtype[0x165]="SIR_HAL_FW_MEM_DUMP_REQ" +Var.SET \halmsgtype[0x166]="SIR_HAL_START_STOP_LOGGING" +Var.SET \halmsgtype[0x167]="SIR_HAL_PDEV_SET_HW_MODE" +Var.SET \halmsgtype[0x168]="SIR_HAL_PDEV_SET_HW_MODE_RESP" +Var.SET \halmsgtype[0x169]="SIR_HAL_PDEV_HW_MODE_TRANS_IND" +Var.SET \halmsgtype[0x169]="SIR_HAL_BAD_PEER_TX_CTL_INI_CMD" +Var.SET \halmsgtype[0x16A]="SIR_HAL_SET_RSSI_MONITOR_REQ" +Var.SET \halmsgtype[0x16B]="SIR_HAL_SET_IE_INFO" +Var.SET \halmsgtype[0x16C]="SIR_HAL_LRO_CONFIG_CMD" +Var.SET \halmsgtype[0x16D]="SIR_HAL_SET_EGAP_CONF_PARAMS" +Var.SET \halmsgtype[0x16E]="SIR_HAL_HT40_OBSS_SCAN_IND" +Var.SET \halmsgtype[0x16F]="SIR_HAL_TSF_GPIO_PIN_REQ" +Var.SET \halmsgtype[0x170]="SIR_HAL_ADD_BCN_FILTER_CMDID" +Var.SET \halmsgtype[0x171]="SIR_HAL_REMOVE_BCN_FILTER_CMDID" +Var.SET \halmsgtype[0x172]="SIR_HAL_BPF_GET_CAPABILITIES_REQ" +Var.SET \halmsgtype[0x173]="SIR_HAL_BPF_SET_INSTRUCTIONS_REQ" +Var.SET \halmsgtype[0x174]="SIR_HAL_SET_WISA_PARAMS" +Var.SET \halmsgtype[0x175]="SIR_HAL_SET_ADAPT_DWELLTIME_PARAMS" +Var.SET \halmsgtype[0x176]="SIR_HAL_SET_PDEV_IE_REQ" +Var.SET \halmsgtype[0x177]="SIR_HAL_TDLS_CONNECTION_TRACKER_NOTIFICATION" +Var.SET \halmsgtype[0x178]="SIR_HAL_NDP_GET_CAP_REQ" +Var.SET \halmsgtype[0x179]="SIR_HAL_NDP_INITIATOR_REQ" +Var.SET \halmsgtype[0x17A]="SIR_HAL_NDP_RESPONDER_REQ" +Var.SET \halmsgtype[0x17B]="SIR_HAL_NDP_END_REQ" +Var.SET \halmsgtype[0x17C]="SIR_HAL_NDI_CAP_RSP" +Var.SET \halmsgtype[0x17D]="SIR_HAL_IBSS_PEER_INFO_RSP" +Var.SET \halmsgtype[0x17E]="SIR_HAL_RATE_UPDATE_IND" +Var.SET \halmsgtype[0x17F]="SIR_HAL_NDP_INITIATOR_RSP" +Var.SET \halmsgtype[0x180]="SIR_HAL_NDP_RESPONDER_RSP" +Var.SET \halmsgtype[0x181]="SIR_HAL_NDP_END_RSP" +Var.SET \halmsgtype[0x182]="SIR_HAL_NDP_INDICATION" +Var.SET \halmsgtype[0x183]="SIR_HAL_NDP_CONFIRM" +Var.SET \halmsgtype[0x184]="SIR_HAL_NDP_END_IND" +Var.SET \halmsgtype[0x185]="SIR_HAL_UPDATE_WEP_DEFAULT_KEY" +;359 unused +Var.SET \halmsgtype[0x187]="SIR_HAL_SEND_FREQ_RANGE_CONTROL_IND" +;361 unused +Var.SET \halmsgtype[0x189]="SIR_HAL_POWER_DBG_CMD" +Var.SET \halmsgtype[0x18A]="SIR_HAL_SET_DTIM_PERIOD" +Var.SET \halmsgtype[0x18B]="SIR_HAL_ENCRYPT_DECRYPT_MSG" +Var.SET \halmsgtype[0x18C]="SIR_HAL_SHORT_RETRY_LIMIT_CNT" +Var.SET \halmsgtype[0x18D]="SIR_HAL_LONG_RETRY_LIMIT_CNT" +Var.SET \halmsgtype[0x18E]="SIR_HAL_UPDATE_TX_FAIL_CNT_TH" +Var.SET \halmsgtype[0x18F]="SIR_HAL_POWER_DEBUG_STATS_REQ" +Var.SET \halmsgtype[0x190]="SIR_HAL_SET_WOW_PULSE_CMD" +Var.SET \halmsgtype[0x191]="SIR_HAL_SET_UDP_RESP_OFFLOAD" +Var.SET \halmsgtype[0x192]="SIR_HAL_SET_PER_ROAM_CONFIG_CMD" +Var.SET \halmsgtype[0x193]="SIR_HAL_GET_RCPI_REQ" +Var.SET \halmsgtype[0x194]="SIR_HAL_ENABLE_BCAST_FILTER" +Var.SET \halmsgtype[0x195]="SIR_HAL_DISABLE_BCAST_FILTER" + + +Var.NEW char [256][100] \smecodetype + +Var.SET \smecodetype[0x00]="TRACE_CODE_SME_RX_HDD_MSG_SCAN_REQ" +Var.SET \smecodetype[0x01]="TRACE_CODE_SME_RX_HDD_MSG_SCAN_GET_RESULTS" +Var.SET \smecodetype[0x02]="TRACE_CODE_SME_RX_HDD_MSG_CONNECT" +Var.SET \smecodetype[0x03]="TRACE_CODE_SME_RX_HDD_MSG_SET_11DINFO" +Var.SET \smecodetype[0x04]="TRACE_CODE_SME_RX_HDD_MSG_GET_SOFTAP_DOMAIN" +Var.SET \smecodetype[0x05]="TRACE_CODE_SME_RX_HDD_MSG_SET_REGINFO" +Var.SET \smecodetype[0x06]="TRACE_CODE_SME_RX_HDD_MSG_UPDATE_CHANNEL_CONFIG" +Var.SET \smecodetype[0x07]="TRACE_CODE_SME_RX_HDD_MSG_UPDATE_CONFIG" +Var.SET \smecodetype[0x08]="TRACE_CODE_SME_RX_HDD_MSG_HDDREADYIND" +Var.SET \smecodetype[0x09]="TRACE_CODE_SME_RX_HDD_MSG_SCAN_FLUSH_RESULTS" +Var.SET \smecodetype[0x0A]="TRACE_CODE_SME_RX_HDD_MSG_SCAN_FLUSH_P2PRESULTS" +Var.SET \smecodetype[0x0B]="TRACE_CODE_SME_RX_HDD_MSG_SCAN_RESULT_GETFIRST" +Var.SET \smecodetype[0x0C]="TRACE_CODE_SME_RX_HDD_MSG_SCAN_RESULT_GETNEXT" +Var.SET \smecodetype[0x0D]="TRACE_CODE_SME_RX_HDD_MSG_SCAN_RESULT_PURGE" +Var.SET \smecodetype[0x0E]="TRACE_CODE_SME_RX_HDD_ROAM_REASSOC" +Var.SET \smecodetype[0x0F]="TRACE_CODE_SME_RX_HDD_ROAM_DISCONNECT" +Var.SET \smecodetype[0x10]="TRACE_CODE_SME_RX_HDD_ROAM_GET_CONNECTPROFILE" +Var.SET \smecodetype[0x11]="TRACE_CODE_SME_RX_HDD_ROAM_FREE_CONNECTPROFILE" +Var.SET \smecodetype[0x12]="TRACE_CODE_SME_RX_HDD_ROAM_SET_PMKIDCACHE" +Var.SET \smecodetype[0x12]="TRACE_CODE_SME_RX_HDD_ROAM_GET_PMKIDCACHE" +Var.SET \smecodetype[0x13]="TRACE_CODE_SME_RX_HDD_GET_CONFIGPARAM" +Var.SET \smecodetype[0x14]="TRACE_CODE_SME_RX_HDD_GET_MODPROFFIELDS" +Var.SET \smecodetype[0x15]="TRACE_CODE_SME_RX_HDD_SET_CONFIG_PWRSAVE" +Var.SET \smecodetype[0x16]="TRACE_CODE_SME_RX_HDD_GET_CONFIG_PWRSAVE" +Var.SET \smecodetype[0x17]="TRACE_CODE_SME_RX_HDD_ENABLE_PWRSAVE" +Var.SET \smecodetype[0x18]="TRACE_CODE_SME_RX_HDD_DISABLE_PWRSAVE" +Var.SET \smecodetype[0x19]="TRACE_CODE_SME_RX_HDD_START_AUTO_BMPSTIMER" +Var.SET \smecodetype[0x1A]="TRACE_CODE_SME_RX_HDD_STOP_AUTO_BMPSTIMER" +Var.SET \smecodetype[0x1B]="TRACE_CODE_SME_RX_HDD_IS_PWRSAVE_ENABLED" +Var.SET \smecodetype[0x1C]="TRACE_CODE_SME_RX_HDD_REQUEST_FULLPOWER" +Var.SET \smecodetype[0x1D]="TRACE_CODE_SME_RX_HDD_REQUEST_BMPS" +Var.SET \smecodetype[0x1E]="TRACE_CODE_SME_RX_HDD_SET_DHCP_FLAG" +Var.SET \smecodetype[0x1F]="TRACE_CODE_SME_RX_HDD_REQUEST_STANDBY" +Var.SET \smecodetype[0x20]="TRACE_CODE_SME_RX_HDD_WOWL_ADDBCAST_PATTERN" +Var.SET \smecodetype[0x21]="TRACE_CODE_SME_RX_HDD_WOWL_DELBCAST_PATTERN" +Var.SET \smecodetype[0x22]="TRACE_CODE_SME_RX_HDD_ENTER_WOWL" +Var.SET \smecodetype[0x23]="TRACE_CODE_SME_RX_HDD_EXIT_WOWL" +Var.SET \smecodetype[0x24]="TRACE_CODE_SME_RX_HDD_SET_KEY" +Var.SET \smecodetype[0x25]="TRACE_CODE_SME_RX_HDD_REMOVE_KEY" +Var.SET \smecodetype[0x26]="TRACE_CODE_SME_RX_HDD_GET_STATS" +Var.SET \smecodetype[0x27]="TRACE_CODE_SME_RX_HDD_GET_RSSI" +Var.SET \smecodetype[0x28]="TRACE_CODE_SME_RX_HDD_GET_CNTRYCODE" +Var.SET \smecodetype[0x29]="TRACE_CODE_SME_RX_HDD_SET_CNTRYCODE" +Var.SET \smecodetype[0x2A]="TRACE_CODE_SME_RX_HDD_CHANGE_CNTRYCODE" +Var.SET \smecodetype[0x2B]="TRACE_CODE_SME_RX_HDD_SET_CFGPRIVACY" +Var.SET \smecodetype[0x2C]="TRACE_CODE_SME_RX_HDD_NEIGHBOR_REPORTREQ" +Var.SET \smecodetype[0x2D]="TRACE_CODE_SME_RX_HDD_DBG_READREG" +Var.SET \smecodetype[0x2E]="TRACE_CODE_SME_RX_HDD_DBG_WRITEREG" +Var.SET \smecodetype[0x2F]="TRACE_CODE_SME_RX_HDD_DBG_READMEM" +Var.SET \smecodetype[0x30]="TRACE_CODE_SME_RX_HDD_DBG_WRITEMEM" +Var.SET \smecodetype[0x31]="TRACE_CODE_SME_RX_HDD_OPEN_SESSION" +Var.SET \smecodetype[0x32]="TRACE_CODE_SME_RX_HDD_CLOSE_SESSION" +Var.SET \smecodetype[0x33]="TRACE_CODE_SME_RX_HDD_SET_HOSTOFFLOAD" +Var.SET \smecodetype[0x34]="TRACE_CODE_SME_RX_HDD_SET_GTKOFFLOAD" +Var.SET \smecodetype[0x35]="TRACE_CODE_SME_RX_HDD_GET_GTKOFFLOAD" +Var.SET \smecodetype[0x36]="TRACE_CODE_SME_RX_HDD_ABORT_MACSCAN" +Var.SET \smecodetype[0x37]="TRACE_CODE_SME_RX_HDD_REGISTER_MGMTFR" +Var.SET \smecodetype[0x38]="TRACE_CODE_SME_RX_HDD_DEREGISTER_MGMTFR" +Var.SET \smecodetype[0x39]="TRACE_CODE_SME_RX_HDD_REMAIN_ONCHAN" +Var.SET \smecodetype[0x3A]="TRACE_CODE_SME_RX_HDD_SEND_ACTION" +Var.SET \smecodetype[0x3B]="TRACE_CODE_SME_RX_HDD_CANCEL_REMAIN_ONCHAN" +Var.SET \smecodetype[0x3C]="TRACE_CODE_SME_RX_HDD_CONFIG_RXPFIL" +Var.SET \smecodetype[0x3D]="TRACE_CODE_SME_RX_HDD_CONFIG_SUSPENDIND" +Var.SET \smecodetype[0x3E]="TRACE_CODE_SME_RX_HDD_CONFIG_RESUMEREQ" +Var.SET \smecodetype[0x3F]="TRACE_CODE_SME_RX_HDD_CONFIG_EXTWOW" +Var.SET \smecodetype[0x40]="TRACE_CODE_SME_RX_HDD_CONFIG_APP_TYPE1" +Var.SET \smecodetype[0x41]="TRACE_CODE_SME_RX_HDD_CONFIG_APP_TYPE2" +Var.SET \smecodetype[0x42]="TRACE_CODE_SME_RX_HDD_SET_MAXTXPOW" +Var.SET \smecodetype[0x43]="TRACE_CODE_SME_RX_HDD_SET_TXPOW" +Var.SET \smecodetype[0x44]="TRACE_CODE_SME_RX_HDD_SET_TMLEVEL" +Var.SET \smecodetype[0x45]="TRACE_CODE_SME_RX_HDD_CAPS_EXCH" +Var.SET \smecodetype[0x46]="TRACE_CODE_SME_RX_HDD_DISABLE_CAP" +Var.SET \smecodetype[0x47]="TRACE_CODE_SME_RX_HDD_GET_DEFCCNV" +Var.SET \smecodetype[0x48]="TRACE_CODE_SME_RX_HDD_GET_CURCC" +Var.SET \smecodetype[0x49]="TRACE_CODE_SME_RX_HDD_RESET_PW5G" +Var.SET \smecodetype[0x4A]="TRACE_CODE_SME_RX_HDD_UPDATE_RP5G" +Var.SET \smecodetype[0x4B]="TRACE_CODE_SME_RX_HDD_SET_ROAMIBAND" +Var.SET \smecodetype[0x4C]="TRACE_CODE_SME_RX_HDD_GET_ROAMIBAND" +Var.SET \smecodetype[0x4D]="TRACE_CODE_SME_RX_HDD_UPDATE_RSSIDIFF" +Var.SET \smecodetype[0x4E]="TRACE_CODE_SME_RX_HDD_UPDATE_IMMRSSIDIFF" +Var.SET \smecodetype[0x4F]="TRACE_CODE_SME_RX_HDD_UPDATE_FTENABLED" +Var.SET \smecodetype[0x50]="TRACE_CODE_SME_RX_HDD_UPDATE_WESMODE" +Var.SET \smecodetype[0x51]="TRACE_CODE_SME_RX_HDD_SET_SCANCTRL" +Var.SET \smecodetype[0x52]="TRACE_CODE_SME_RX_HDD_UPDATE_P2P_IE" +Var.SET \smecodetype[0x53]="TRACE_CODE_SME_RX_HDD_UPDATE_ROAM_SCAN_N_PROBES" +Var.SET \smecodetype[0x54]="TRACE_CODE_SME_RX_HDD_UPDATE_ROAM_SCAN_HOME_AWAY_TIME" +Var.SET \smecodetype[0x55]="TRACE_CODE_SME_RX_HDD_STORE_JOIN_REQ" +Var.SET \smecodetype[0x56]="TRACE_CODE_SME_RX_HDD_CLEAR_JOIN_REQ" +Var.SET \smecodetype[0x57]="TRACE_CODE_SME_RX_HDD_ISSUE_JOIN_REQ" +Var.SET \smecodetype[0x58]="TRACE_CODE_SME_RX_HDD_MSG_DEAUTH_STA" +;#ifdef FEATURE_WLAN_TDLS //assuming this flag is enabled by default +Var.SET \smecodetype[0x59]="TRACE_CODE_SME_RX_HDD_TDLS_LINK_ESTABLISH_PARAM" +Var.SET \smecodetype[0x5A]="TRACE_CODE_SME_RX_HDD_TDLS_CHAN_SWITCH_REQ" +Var.SET \smecodetype[0x5B]="TRACE_CODE_SME_RX_HDD_TDLS_SEND_MGMT_FRAME" +Var.SET \smecodetype[0x5C]="TRACE_CODE_SME_RX_HDD_TDLS_CHANGE_PEER_STA" +Var.SET \smecodetype[0x5D]="TRACE_CODE_SME_RX_HDD_TDLS_ADD_PEER_STA" +Var.SET \smecodetype[0x5E]="TRACE_CODE_SME_RX_HDD_TDLS_DEL_PEER_STA" +;#endif +Var.SET \smecodetype[0x5F]="TRACE_CODE_SME_RX_HDD_PREF_NET_LIST" +;#ifdef FEATURE_WLAN_LPHB //assuming this flag is enabled by default +Var.SET \smecodetype[0x60]="TRACE_CODE_SME_RX_HDD_LPHB_CONFIG_REQ" +;#endif /* FEATURE_WLAN_LPHB */ +Var.SET \smecodetype[0x61]="TRACE_CODE_SME_RX_HDD_ROAM_DEL_PMKIDCACHE" +;From here hardcoded to 250 in host code +Var.SET \smecodetype[0xFA]="TRACE_CODE_SME_COMMAND" +Var.SET \smecodetype[0xFB]="TRACE_CODE_SME_TX_WMA_MSG" +Var.SET \smecodetype[0xFC]="TRACE_CODE_SME_RX_WMA_MSG" + +Var.NEW char [256][50] \cfgmsgtype + +Var.SET \cfgmsgtype[0xB0]="SIR_CFG_PARAM_UPDATE_IND" +Var.SET \cfgmsgtype[0xB1]="SIR_CFG_DOWNLOAD_COMPLETE_IND" + + +Var.NEW char [256][50] \limmsgtype + +Var.SET \limmsgtype[0xB3]="SIR_LIM_RETRY_INTERRUPT_MSG" +Var.SET \limmsgtype[0xB4]="SIR_BB_XPORT_MGMT_MSG" +;5 and 6 unused +Var.SET \limmsgtype[0xB7]="SIR_LIM_INV_KEY_INTERRUPT_MSG" +Var.SET \limmsgtype[0xB8]="SIR_LIM_KEY_ID_INTERRUPT_MSG" +Var.SET \limmsgtype[0xB9]="SIR_LIM_REPLAY_THRES_INTERRUPT_MSG" +Var.SET \limmsgtype[0xBA]="SIR_LIM_TD_DUMMY_CALLBACK_MSG" +Var.SET \limmsgtype[0xBB]="SIR_LIM_SCH_CLEAN_MSG" +Var.SET \limmsgtype[0xBC]="SIR_LIM_RADAR_DETECT_IND" +;0xD unused +Var.SET \limmsgtype[0xBE]="SIR_LIM_DEL_TS_IND" +;0xF and 0x10 unused +Var.SET \limmsgtype[0xC1]="SIR_LIM_DELETE_STA_CONTEXT_IND" +;0x12 unused +Var.SET \limmsgtype[0xC3]="SIR_LIM_UPDATE_BEACON" +;0 and 1 unused +Var.SET \limmsgtype[0xD2]="SIR_LIM_JOIN_FAIL_TIMEOUT" +Var.SET \limmsgtype[0xD3]="SIR_LIM_AUTH_FAIL_TIMEOUT" +Var.SET \limmsgtype[0xD4]="SIR_LIM_AUTH_RSP_TIMEOUT" +Var.SET \limmsgtype[0xD5]="SIR_LIM_ASSOC_FAIL_TIMEOUT" +Var.SET \limmsgtype[0xD6]="SIR_LIM_REASSOC_FAIL_TIMEOUT" +Var.SET \limmsgtype[0xD7]="SIR_LIM_HEART_BEAT_TIMEOUT" +;8, 9 and A unused +Var.SET \limmsgtype[0xDB]="SIR_LIM_PROBE_HB_FAILURE_TIMEOUT" +Var.SET \limmsgtype[0xDC]="SIR_LIM_ADDTS_RSP_TIMEOUT" +;0xD to 0x12 unused +Var.SET \limmsgtype[0xE3]="SIR_LIM_LINK_TEST_DURATION_TIMEOUT" +;0x14 to 0x16 unused +Var.SET \limmsgtype[0xE7]="SIR_LIM_CNF_WAIT_TIMEOUT" +;0x18 unused +Var.SET \limmsgtype[0xE9]="SIR_LIM_UPDATE_OLBC_CACHEL_TIMEOUT" +Var.SET \limmsgtype[0xEA]="SIR_LIM_CHANNEL_SWITCH_TIMEOUT" +Var.SET \limmsgtype[0xEB]="SIR_LIM_QUIET_TIMEOUT" +Var.SET \limmsgtype[0xEC]="SIR_LIM_QUIET_BSS_TIMEOUT" +Var.SET \limmsgtype[0xED]="SIR_LIM_WPS_OVERLAP_TIMEOUT" +Var.SET \limmsgtype[0xEE]="SIR_LIM_FT_PREAUTH_RSP_TIMEOUT" +Var.SET \limmsgtype[0xEF]="SIR_LIM_REMAIN_CHN_TIMEOUT" +Var.SET \limmsgtype[0xF0]="SIR_LIM_INSERT_SINGLESHOT_NOA_TIMEOUT" +;0x21 and 0x22 unused +Var.SET \limmsgtype[0xF3]="SIR_LIM_BEACON_GEN_IND" +Var.SET \limmsgtype[0xF4]="SIR_LIM_PERIODIC_PROBE_REQ_TIMEOUT" +;0x25 unused +Var.SET \limmsgtype[0xF6]="SIR_LIM_DISASSOC_ACK_TIMEOUT" +Var.SET \limmsgtype[0xF7]="SIR_LIM_DEAUTH_ACK_TIMEOUT" +Var.SET \limmsgtype[0xF8]="SIR_LIM_PERIODIC_JOIN_PROBE_REQ_TIMEOUT" +;0x29, 0x2A and 0x2B unused +Var.SET \limmsgtype[0xFC]="SIR_LIM_CONVERT_ACTIVE_CHANNEL_TO_PASSIVE" +Var.SET \limmsgtype[0xFD]="SIR_LIM_AUTH_RETRY_TIMEOUT" +Var.SET \limmsgtype[0xFF]="SIR_LIM_MSG_TYPES_END" + + +Var.NEW char [256][50] \schmsgtype + +Var.SET \schmsgtype[0x0]="SIR_SCH_CHANNEL_SWITCH_REQUEST" +Var.SET \schmsgtype[0x1]="SIR_SCH_START_SCAN_REQ" +Var.SET \schmsgtype[0x2]="SIR_SCH_START_SCAN_RSP" +Var.SET \schmsgtype[0x3]="SIR_SCH_END_SCAN_NTF" +Var.SET \schmsgtype[0xFF]="SIR_SCH_MSG_TYPES_END" + +Var.NEW char [256][50] \pmmmsgtype + +Var.SET \pmmmsgtype[0x0]="SIR_PMM_CHANGE_PM_MODE" +Var.SET \pmmmsgtype[0xFF]="SIR_PMM_MSG_TYPES_END" + + +Var.NEW char [256][50] \mntmsgtype + +Var.SET \mntmsgtype[0x0]="SIR_MNT_RELEASE_BD" +Var.SET \mntmsgtype[0xFF]="SIR_MNT_MSG_TYPES_END" + +Var.NEW char [0x301][50] \pttmsgtype + +Var.SET \pttmsgtype[0x0]="SIR_PTT_MSG_TYPES_BEGIN" +Var.SET \pttmsgtype[0x300]="SIR_PTT_MSG_TYPES_END" + + +Var.NEW char [18][50] \code + +Var.SET \code[0]="TRACE_CODE_MLM_STATE" +Var.SET \code[1]="TRACE_CODE_SME_STATE" +Var.SET \code[2]="TRACE_CODE_TX_MGMT" +Var.SET \code[3]="TRACE_CODE_RX_MGMT" +Var.SET \code[4]="TRACE_CODE_RX_MGMT_TSF" +Var.SET \code[5]="TRACE_CODE_TX_COMPLETE" +Var.SET \code[6]="TRACE_CODE_TX_SME_MSG" +Var.SET \code[7]="TRACE_CODE_RX_SME_MSG" +Var.SET \code[8]="TRACE_CODE_TX_WMA_MSG" +Var.SET \code[9]="TRACE_CODE_RX_WMA_MSG" +Var.SET \code[10]="TRACE_CODE_TX_LIM_MSG" +Var.SET \code[11]="TRACE_CODE_RX_LIM_MSG" +Var.SET \code[12]="TRACE_CODE_TX_CFG_MSG" +Var.SET \code[13]="TRACE_CODE_RX_CFG_MSG" +Var.SET \code[14]="TRACE_CODE_RX_MGMT_DROP" +Var.SET \code[15]="TRACE_CODE_TIMER_ACTIVATE" +Var.SET \code[16]="TRACE_CODE_TIMER_DEACTIVATE" +Var.SET \code[17]="TRACE_CODE_INFO_LOG" + + +Var.NEW char [13][50] \module + +Var.SET \module[1]="QDF_MODULE_ID_TLSHIM" +Var.SET \module[2]="QDF_MODULE_ID_WMI" +Var.SET \module[3]="QDF_MODULE_ID_HTT" +Var.SET \module[4]="QDF_MODULE_ID_RSV4" +Var.SET \module[5]="QDF_MODULE_ID_HDD" +Var.SET \module[6]="QDF_MODULE_ID_SME" +Var.SET \module[7]="QDF_MODULE_ID_PE" +Var.SET \module[8]="QDF_MODULE_ID_WMA" +Var.SET \module[9]="QDF_MODULE_ID_SYS" +Var.SET \module[10]="QDF_MODULE_ID_QDF" +Var.SET \module[11]="QDF_MODULE_ID_SAP" +Var.SET \module[12]="QDF_MODULE_ID_HDD_SOFTAP" + +Var.NEW char [16][50] \mgmttype + +Var.SET \mgmttype[0]="SIR_MAC_MGMT_ASSOC_REQ" +Var.SET \mgmttype[1]="SIR_MAC_MGMT_ASSOC_RSP" +Var.SET \mgmttype[2]="SIR_MAC_MGMT_REASSOC_REQ" +Var.SET \mgmttype[3]="SIR_MAC_MGMT_REASSOC_RSP" +Var.SET \mgmttype[4]="SIR_MAC_MGMT_PROBE_REQ" +Var.SET \mgmttype[5]="SIR_MAC_MGMT_PROBE_RSP" +Var.SET \mgmttype[6]="SIR_MAC_MGMT_TIME_ADVERT" +Var.SET \mgmttype[8]="SIR_MAC_MGMT_BEACON" +Var.SET \mgmttype[9]="SIR_MAC_MGMT_ATIM" +Var.SET \mgmttype[10]="SIR_MAC_MGMT_DISASSOC" +Var.SET \mgmttype[11]="SIR_MAC_MGMT_AUTH" +Var.SET \mgmttype[12]="SIR_MAC_MGMT_DEAUTH" +Var.SET \mgmttype[13]="SIR_MAC_MGMT_ACTION" +Var.SET \mgmttype[15]="SIR_MAC_MGMT_RESERVED15" + +Var.NEW char [30][50] \limtimertype + +Var.SET \limtimertype[0]="eLIM_MIN_CHANNEL_TIMER" +Var.SET \limtimertype[1]="eLIM_MAX_CHANNEL_TIMER" +Var.SET \limtimertype[2]="eLIM_JOIN_FAIL_TIMER" +Var.SET \limtimertype[3]="eLIM_AUTH_FAIL_TIMER" +Var.SET \limtimertype[4]="eLIM_AUTH_RESP_TIMER" +Var.SET \limtimertype[5]="eLIM_ASSOC_FAIL_TIMER" +Var.SET \limtimertype[6]="eLIM_REASSOC_FAIL_TIMER" +Var.SET \limtimertype[7]="eLIM_PRE_AUTH_CLEANUP_TIMER" +Var.SET \limtimertype[8]="eLIM_CNF_WAIT_TIMER" +Var.SET \limtimertype[9]="eLIM_AUTH_RSP_TIMER" +Var.SET \limtimertype[10]="eLIM_UPDATE_OLBC_CACHE_TIMER" +Var.SET \limtimertype[11]="eLIM_PROBE_AFTER_HB_TIMER" +Var.SET \limtimertype[12]="eLIM_ADDTS_RSP_TIMER" +Var.SET \limtimertype[13]="eLIM_CHANNEL_SWITCH_TIMER" +Var.SET \limtimertype[14]="eLIM_LEARN_DURATION_TIMER" +Var.SET \limtimertype[15]="eLIM_QUIET_TIMER" +Var.SET \limtimertype[16]="eLIM_QUIET_BSS_TIMER" +Var.SET \limtimertype[17]="eLIM_WPS_OVERLAP_TIMER" +Var.SET \limtimertype[18]="eLIM_FT_PREAUTH_RSP_TIMER" +Var.SET \limtimertype[19]="eLIM_REMAIN_CHN_TIMER" +Var.SET \limtimertype[20]="eLIM_PERIODIC_PROBE_REQ_TIMER" +;#ifdef FEATURE_WLAN_CCX +;Var.SET \limtimertype[0]="eLIM_TSM_TIMER" +;#endif +Var.SET \limtimertype[22]="eLIM_DISASSOC_ACK_TIMER" +Var.SET \limtimertype[23]="eLIM_DEAUTH_ACK_TIMER" +Var.SET \limtimertype[24]="eLIM_PERIODIC_JOIN_PROBE_REQ_TIMER" +Var.SET \limtimertype[25]="eLIM_INSERT_SINGLESHOT_NOA_TIMER" +Var.SET \limtimertype[26]="eLIM_CONVERT_ACTIVE_CHANNEL_TO_PASSIVE" + + + +Var.NEW char [256][100] \hddcodetype + +Var.SET \hddcodetype[0x00]="TRACE_CODE_HDD_OPEN_REQUEST" +Var.SET \hddcodetype[0x01]="TRACE_CODE_HDD_STOP_REQUEST" +Var.SET \hddcodetype[0x02]="TRACE_CODE_HDD_TX_TIMEOUT" +Var.SET \hddcodetype[0x03]="TRACE_CODE_HDD_P2P_DEV_ADDR_IOCTL" +Var.SET \hddcodetype[0x04]="TRACE_CODE_HDD_SETSUSPENDMODE_IOCTL" +Var.SET \hddcodetype[0x05]="TRACE_CODE_HDD_SETROAMTRIGGER_IOCTL" +Var.SET \hddcodetype[0x06]="TRACE_CODE_HDD_GETROAMTRIGGER_IOCTL" +Var.SET \hddcodetype[0x07]="TRACE_CODE_HDD_SETROAMSCANPERIOD_IOCTL" +Var.SET \hddcodetype[0x08]="TRACE_CODE_HDD_GETROAMSCANPERIOD_IOCTL" +Var.SET \hddcodetype[0x09]="TRACE_CODE_HDD_SETROAMDELTA_IOCTL" +Var.SET \hddcodetype[0x0A]="TRACE_CODE_HDD_GETROAMDELTA_IOCTL" +Var.SET \hddcodetype[0x0B]="TRACE_CODE_HDD_GETBAND_IOCTL" +Var.SET \hddcodetype[0x0C]="TRACE_CODE_HDD_GETCOUNTRYREV_IOCTL" +Var.SET \hddcodetype[0x0D]="TRACE_CODE_HDD_SETROAMSCANCHANNELS_IOCTL" +Var.SET \hddcodetype[0x0E]="TRACE_CODE_HDD_GETROAMSCANCHANNELS_IOCTL" +Var.SET \hddcodetype[0x0F]="TRACE_CODE_HDD_HOSTAPD_OPEN_REQUEST" +Var.SET \hddcodetype[0x10]="TRACE_CODE_HDD_HOSTAPD_STOP_REQUEST" +Var.SET \hddcodetype[0x11]="TRACE_CODE_HDD_HOSTAPD_UNINIT_REQUEST" +Var.SET \hddcodetype[0x12]="TRACE_CODE_HDD_SOFTAP_TX_TIMEOUT" +Var.SET \hddcodetype[0x13]="TRACE_CODE_HDD_HOSTAPD_SET_MAC_ADDR" +Var.SET \hddcodetype[0x14]="TRACE_CODE_HDD_HOSTAPD_P2P_SET_NOA_IOCTL" +Var.SET \hddcodetype[0x15]="TRACE_CODE_HDD_HOSTAPD_P2P_SET_PS_IOCTL" +Var.SET \hddcodetype[0x16]="TRACE_CODE_HDD_HOSTAPD_SET_SAP_CHANNEL_LIST_IOCTL" +Var.SET \hddcodetype[0x17]="TRACE_CODE_HDD_ADD_VIRTUAL_INTF" +Var.SET \hddcodetype[0x18]="TRACE_CODE_HDD_DEL_VIRTUAL_INTF" +Var.SET \hddcodetype[0x19]="TRACE_CODE_HDD_CHANGE_VIRTUAL_INTF" +Var.SET \hddcodetype[0x1A]="TRACE_CODE_HDD_CFG80211_START_AP" +Var.SET \hddcodetype[0x1B]="TRACE_CODE_HDD_CFG80211_CHANGE_BEACON" +Var.SET \hddcodetype[0x1C]="TRACE_CODE_HDD_CFG80211_STOP_AP" +Var.SET \hddcodetype[0x1D]="TRACE_CODE_HDD_CFG80211_CHANGE_BSS" +Var.SET \hddcodetype[0x1E]="TRACE_CODE_HDD_CFG80211_ADD_KEY" +Var.SET \hddcodetype[0x1F]="TRACE_CODE_HDD_CFG80211_GET_KEY" +Var.SET \hddcodetype[0x20]="TRACE_CODE_HDD_CFG80211_SET_DEFAULT_KEY" +Var.SET \hddcodetype[0x21]="TRACE_CODE_HDD_CFG80211_CONNECT" +Var.SET \hddcodetype[0x22]="TRACE_CODE_HDD_CFG80211_DISCONNECT" +Var.SET \hddcodetype[0x23]="TRACE_CODE_HDD_CFG80211_JOIN_IBSS" +Var.SET \hddcodetype[0x24]="TRACE_CODE_HDD_CFG80211_LEAVE_IBSS" +Var.SET \hddcodetype[0x25]="TRACE_CODE_HDD_CFG80211_SET_WIPHY_PARAMS" +Var.SET \hddcodetype[0x26]="TRACE_CODE_HDD_CFG80211_SET_TXPOWER" +Var.SET \hddcodetype[0x27]="TRACE_CODE_HDD_CFG80211_GET_TXPOWER" +Var.SET \hddcodetype[0x28]="TRACE_CODE_HDD_CFG80211_SET_CHANNEL" +Var.SET \hddcodetype[0x29]="TRACE_CODE_HDD_CFG80211_ADD_BEACON" +Var.SET \hddcodetype[0x2A]="TRACE_CODE_HDD_CFG80211_SET_BEACON" +Var.SET \hddcodetype[0x2B]="TRACE_CODE_HDD_CFG80211_CHANGE_IFACE" +Var.SET \hddcodetype[0x2C]="TRACE_CODE_HDD_CHANGE_STATION" +Var.SET \hddcodetype[0x2D]="TRACE_CODE_HDD_CFG80211_UPDATE_BSS" +Var.SET \hddcodetype[0x2E]="TRACE_CODE_HDD_CFG80211_SCAN" +Var.SET \hddcodetype[0x2F]="TRACE_CODE_HDD_REMAIN_ON_CHANNEL" +Var.SET \hddcodetype[0x30]="TRACE_CODE_HDD_REMAINCHANREADYHANDLER" +Var.SET \hddcodetype[0x31]="TRACE_CODE_HDD_CFG80211_CANCEL_REMAIN_ON_CHANNEL" +Var.SET \hddcodetype[0x32]="TRACE_CODE_HDD_ACTION" +Var.SET \hddcodetype[0x33]="TRACE_CODE_HDD_MGMT_TX_CANCEL_WAIT" +Var.SET \hddcodetype[0x34]="TRACE_CODE_HDD_CFG80211_GET_STA" +Var.SET \hddcodetype[0x35]="TRACE_CODE_HDD_CFG80211_SET_POWER_MGMT" +Var.SET \hddcodetype[0x36]="TRACE_CODE_HDD_CFG80211_DEL_STA" +Var.SET \hddcodetype[0x37]="TRACE_CODE_HDD_CFG80211_ADD_STA" +Var.SET \hddcodetype[0x38]="TRACE_CODE_HDD_CFG80211_SET_PMKSA" +Var.SET \hddcodetype[0x39]="TRACE_CODE_HDD_CFG80211_UPDATE_FT_IES" +Var.SET \hddcodetype[0x3A]="TRACE_CODE_HDD_CFG80211_TDLS_MGMT" +Var.SET \hddcodetype[0x3B]="TRACE_CODE_HDD_CFG80211_TDLS_OPER" +Var.SET \hddcodetype[0x3C]="TRACE_CODE_HDD_CFG80211_SET_REKEY_DATA" +Var.SET \hddcodetype[0x3D]="TRACE_CODE_HDD_UNSUPPORTED_IOCTL" +Var.SET \hddcodetype[0x3E]="TRACE_CODE_HDD_SETROAMSCANCHANNELMINTIME_IOCTL" +Var.SET \hddcodetype[0x3F]="TRACE_CODE_HDD_GETROAMSCANCHANNELMINTIME_IOCTL" +Var.SET \hddcodetype[0x40]="TRACE_CODE_HDD_STORE_JOIN_REQ" +Var.SET \hddcodetype[0x41]="TRACE_CODE_HDD_CLEAR_JOIN_REQ" +Var.SET \hddcodetype[0x42]="TRACE_CODE_HDD_ISSUE_JOIN_REQ" +Var.SET \hddcodetype[0x43]="TRACE_CODE_HDD_CFG80211_RESUME_WLAN" +Var.SET \hddcodetype[0x44]="TRACE_CODE_HDD_CFG80211_SUSPEND_WLAN" +Var.SET \hddcodetype[0x45]="TRACE_CODE_HDD_CFG80211_SET_MAC_ACL" +Var.SET \hddcodetype[0x46]="TRACE_CODE_HDD_CFG80211_TESTMODE" +Var.SET \hddcodetype[0x47]="TRACE_CODE_HDD_CFG80211_DUMP_SURVEY" +Var.SET \hddcodetype[0x48]="TRACE_CODE_HDD_CFG80211_SCHED_SCAN_START" +Var.SET \hddcodetype[0x49]="TRACE_CODE_HDD_CFG80211_SCHED_SCAN_STOP" +Var.SET \hddcodetype[0x4A]="TRACE_CODE_HDD_CFG80211_DEL_PMKSA" +;New CFG80211 enums to be added before this comment +;TRACE_CODE_HDD_RX_SME_MSG is used as code for MTRACE commands +;and also update the below index value +Var.SET \hddcodetype[0x4B]="TRACE_CODE_HDD_RX_SME_MSG" + +&TRACETYPESIZE=v.value(sizeof(qdf_trace_record_t)) +&TRACESIZE=v.value(sizeof(g_qdf_trace_tbl)) +&TRACEMAXINDEX=v.value(&TRACESIZE/&TRACETYPESIZE) + +&HEAD=v.value(g_qdf_trace_data.head) +&TAIL=v.value(g_qdf_trace_data.tail) + +IF ((&HEAD>&TRACEMAXINDEX)||(&TAIL>&TRACEMAXINDEX)||(&TAIL==&HEAD)) +( + GOTO ENDSCRIPT +) + +&INDEX=&HEAD + +TRACESTART: + +&TIME=v.value(g_qdf_trace_tbl[&INDEX].time) +&MODULE=v.value(g_qdf_trace_tbl[&INDEX].module) +&CODE=v.value(g_qdf_trace_tbl[&INDEX].code) +&SESSION=v.value(g_qdf_trace_tbl[&INDEX].session) +&DATA=v.value(g_qdf_trace_tbl[&INDEX].data) + + + WRITE #1 "TIME: " &TIME + Var.Write #1 %STRING \module[&MODULE] + +IF (&MODULE==0x7) +( +if (&CODE>=0)&&(&CODE<=0x12) +( + Var.Write #1 %STRING \code[&CODE] " [" %Hex &CODE "]" +) + + IF (&SESSION==0xFF) + ( + WRITE #1 "NO SESSION" + ) + ELSE + ( + WRITE #1 "SESSION: " &SESSION + ) + + +;0 TRACE_CODE_MLM_STATE +IF (&CODE==0x0) +( + Var.NEW tLimMlmStates \mlmstate + Var.Set \mlmstate=&DATA + ;Var.Write #1 \mlmstate " [" %Hex &DATA "]" +) + +;1 TRACE_CODE_SME_STATE +IF (&CODE==0x1) +( + Var.NEW tLimSmeStates \smestate + Var.Set \smestate=&DATA + Var.Write #1 \smestate " [" %Hex &DATA "]" +) + +;2 TRACE_CODE_TX_MGMT +IF (&CODE==0x2) +( + WRITE #1 "DATA: " &DATA +) + +;3 TRACE_CODE_RX_MGMT +IF (&CODE==0x3) +( + &SERIAL=v.value(&DATA>>16) + &SUBTYPE=v.value(&DATA&0xFF) + if (&SUBTYPE<=0xF) + ( + Var.Write #1 %STRING \mgmttype[&SUBTYPE] + WRITE #1 "SEQ NUM: " &SERIAL + ) + else + ( + WRITE #1 "INCORRECT DATA" + ) +) + +;4 TRACE_CODE_RX_MGMT_TSF +IF (&CODE==0x4) +( + WRITE #1 "BEACON TS: " &DATA +) + +;5 TRACE_CODE_TX_COMPLETE +IF (&CODE==0x5) +( + Var.Write #1 %STRING \mgmttype[&DATA] " [" %Hex &DATA "]" +) + +;14 TRACE_CODE_RX_MGMT_DROP +IF (&CODE==0xE) +( + Var.NEW tMgmtFrmDropReason \dropreason + Var.Set \dropreason=&DATA + Var.Write #1 \dropreason " [" %Hex &DATA "]" +) + + +;15 TRACE_CODE_TIMER_ACTIVATE/DEACTIVATE +IF (&CODE==0xF)||(&CODE==0x10) +( + Var.Write #1 %STRING \limtimertype[&DATA] " [" %Hex &DATA "]" +) + +;6 TRACE_CODE_TX_SME_MSG +IF (&CODE==0x6) +( +&MOD=v.value(&DATA>>8) +&MSG=v.value(&DATA&0xFF) +IF (&MOD==0x12)&&(&DATA>=0x12B0) +( +Var.Write #1 %STRING \limmsgtype[&MSG] " [" %Hex &MSG "]" +) +IF (&DATA>=0x1500) +( + Var.NEW enum eWniMsgTypes \smemsg + Var.Set \smemsg=&DATA + Var.Write #1 \smemsg " [" %Hex &DATA "]" + ) +) + +;7 TRACE_CODE_RX_SME_MSG +IF (&CODE==0x7) +( +&MOD=v.value(&DATA>>8) +&MSG=v.value(&DATA&0xFF) +IF (&MOD==0x12)&&(&DATA>=0x12B0) +( +Var.Write #1 %STRING \limmsgtype[&MSG] " [" %Hex &MSG "]" +) +IF (&DATA>=0x1500) +( + Var.NEW enum eWniMsgTypes \smemsg + Var.Set \smemsg=&DATA + Var.Write #1 \smemsg " [" %Hex &DATA "]" +) +) + +;8 TRACE_CODE_TX_WMA_MSG +IF (&CODE==0x8) +( +&MOD=v.value(&DATA>>8) +&MSG=v.value(&DATA&0xFF) +IF (&MOD==0x10) +( +Var.Write #1 %STRING \halmsgtype[&MSG] " [" %Hex &MSG "]" +) +) + +;9 TRACE_CODE_RX_WMA_MSG +IF (&CODE==0x9) +( +&MOD=v.value(&DATA>>8) +&MSG=v.value(&DATA&0xFF) +IF (&MOD==0x10) +( +Var.Write #1 %STRING \halmsgtype[&MSG] " [" %Hex &MSG "]" +) +) + +;10 TRACE_CODE_TX_LIM_MSG +IF (&CODE==0xA) +( +&MOD=v.value(&DATA>>8) +&MSG=v.value(&DATA&0xFF) +IF (&MOD==0x12)&&(&DATA>=0x12B0) +( +Var.Write #1 %STRING \limmsgtype[&MSG] " [" %Hex &MSG "]" +) +IF (&DATA>=0x1500) +( + Var.NEW enum eWniMsgTypes \smemsg + Var.Set \smemsg=&DATA + Var.Write #1 \smemsg " [" %Hex &DATA "]" +) +) + +;11 TRACE_CODE_RX_LIM_MSG +IF (&CODE==0xB) +( +&MOD=v.value(&DATA>>8) +&MSG=v.value(&DATA&0xFF) +IF (&MOD==0x12)&&(&DATA>=0x12B0) +( +Var.Write #1 %STRING \limmsgtype[&MSG] " [" %Hex &MSG "]" +) +IF (&DATA>=0x1500) +( + Var.NEW enum eWniMsgTypes \smemsg + &DATA=v.value(&DATA&0xFFFF) + Var.Set \smemsg=&DATA + Var.Write #1 \smemsg " [" %Hex &DATA "]" +) +) + +;12 TRACE_CODE_TX_CFG_MSG +IF (&CODE==0xC) +( +&MOD=v.value(&DATA>>8) +&MSG=v.value(&DATA&0xFF) +IF (&MOD==0x11)&&(&DATA>=0x11B0) +( +Var.Write #1 %STRING \cfgmsgtype[&MSG] " [" %Hex &MSG "]" +) +) + +;13 TRACE_CODE_RX_CFG_MSG +IF (&CODE==0xD) +( +&MOD=v.value(&DATA>>8) +&MSG=v.value(&DATA&0xFF) +IF (&MOD==0x11)&&(&DATA>=0x11B0) +( +Var.Write #1 %STRING \cfgmsgtype[&MSG] " [" %Hex &MSG "]" +) +) + +IF (&DATA>=0x1500) +( + Var.NEW enum eWniMsgTypes \smemsg + &DATA=v.value(&DATA&0xFFFF) + Var.Set \smemsg=&DATA + Var.Write #1 \smemsg " [" %Hex &DATA "]" +) + +) + + +IF (&MODULE==0x6) +( + + IF ((&CODE>=0x0)&&(&CODE<=0x61)) + ( + Var.Write #1 %STRING \smecodetype[&CODE] " [" %Hex &CODE "]" + ) + ELSE + ( + IF ((&CODE>=0xFA)&&(&CODE<=0xFC)) + ( + Var.Write #1 %STRING \smecodetype[&CODE] " [" %Hex &CODE "]" + ) + ELSE + ( + WRITE #1 "CODE: " &CODE + ) + ) + WRITE #1 "DATA: " &DATA + + IF (&SESSION==0xFF) + ( + WRITE #1 "NO SESSION" + ) + ELSE + ( + WRITE #1 "SESSION: " &SESSION + ) +) + +IF (&MODULE==0x5) +( + + IF ((&CODE>=0x0)&&(&CODE<=0x4A)) + ( + Var.Write #1 %STRING \hddcodetype[&CODE] " [" %Hex &CODE "]" + WRITE #1 "DATA: " &DATA + ) + ELSE + ( + IF (&CODE==0x4B) + ( + Var.Write #1 %STRING \hddcodetype[&CODE] " [" %Hex &CODE "]" + Var.NEW eRoamCmdStatus \csrstatus + Var.Set \csrstatus=&DATA + Var.Write #1 \csrstatus " [" %Hex &DATA "]" + ) + ELSE + ( + WRITE #1 "CODE: " &CODE + WRITE #1 "DATA: " &DATA + ) + ) + + IF (&SESSION==0xFF) + ( + WRITE #1 "NO SESSION" + ) + ELSE + ( + WRITE #1 "SESSION: " &SESSION + ) +) + +WRITE #1 " " + +&INDEX=v.value((&INDEX+1)%(&TRACEMAXINDEX)) + + IF (&INDEX!=&HEAD) + ( + GOTO TRACESTART + ) + + + +ENDSCRIPT: +CLOSE #1 +ENDDO diff --git a/drivers/staging/qcacld-3.0/core/mac/src/sys/legacy/src/utils/src/parser_api.c b/drivers/staging/qcacld-3.0/core/mac/src/sys/legacy/src/utils/src/parser_api.c new file mode 100644 index 0000000000000000000000000000000000000000..872b8b8aa0b9671f022470471a13adf485180ccf --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/sys/legacy/src/utils/src/parser_api.c @@ -0,0 +1,5888 @@ +/* + * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * This file parser_api.cc contains the code for parsing + * 802.11 messages. + * Author: Pierre Vandwalle + * Date: 03/18/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + * + */ + +#include "sir_api.h" +#include "ani_global.h" +#include "parser_api.h" +#include "cfg_api.h" +#include "lim_utils.h" +#include "utils_parser.h" +#include "lim_ser_des_utils.h" +#include "sch_api.h" +#include "wmm_apsd.h" +#include "rrm_api.h" + +#include "cds_regdomain.h" + +/* ////////////////////////////////////////////////////////////////////// */ +void dot11f_log(tpAniSirGlobal pMac, int loglevel, const char *pString, ...) +{ +#ifdef WLAN_DEBUG + if ((uint32_t) loglevel > + pMac->utils.gLogDbgLevel[LOG_INDEX_FOR_MODULE(SIR_DBG_MODULE_ID)]) { + return; + } else { + va_list marker; + + va_start(marker, pString); /* Initialize variable arguments. */ + + log_debug(pMac, SIR_DBG_MODULE_ID, loglevel, pString, marker); + + va_end(marker); /* Reset variable arguments. */ + } +#endif +} + +void swap_bit_field16(uint16_t in, uint16_t *out) +{ +#ifdef ANI_LITTLE_BIT_ENDIAN + *out = in; +#else /* Big-Endian... */ + *out = ((in & 0x8000) >> 15) | + ((in & 0x4000) >> 13) | + ((in & 0x2000) >> 11) | + ((in & 0x1000) >> 9) | + ((in & 0x0800) >> 7) | + ((in & 0x0400) >> 5) | + ((in & 0x0200) >> 3) | + ((in & 0x0100) >> 1) | + ((in & 0x0080) << 1) | + ((in & 0x0040) << 3) | + ((in & 0x0020) << 5) | + ((in & 0x0010) << 7) | + ((in & 0x0008) << 9) | + ((in & 0x0004) << 11) | + ((in & 0x0002) << 13) | ((in & 0x0001) << 15); +#endif /* ANI_LITTLE_BIT_ENDIAN */ +} + +static inline void __print_wmm_params(tpAniSirGlobal pMac, + tDot11fIEWMMParams *pWmm) +{ + lim_log(pMac, LOG1, FL("WMM Parameters Received:")); + lim_log(pMac, LOG1, + FL("BE: aifsn %d, acm %d, aci %d, cwmin %d, cwmax %d, txop %d"), + pWmm->acbe_aifsn, pWmm->acbe_acm, pWmm->acbe_aci, + pWmm->acbe_acwmin, pWmm->acbe_acwmax, pWmm->acbe_txoplimit); + + lim_log(pMac, LOG1, + FL("BK: aifsn %d, acm %d, aci %d, cwmin %d, cwmax %d, txop %d"), + pWmm->acbk_aifsn, pWmm->acbk_acm, pWmm->acbk_aci, + pWmm->acbk_acwmin, pWmm->acbk_acwmax, pWmm->acbk_txoplimit); + + lim_log(pMac, LOG1, + FL("VI: aifsn %d, acm %d, aci %d, cwmin %d, cwmax %d, txop %d"), + pWmm->acvi_aifsn, pWmm->acvi_acm, pWmm->acvi_aci, + pWmm->acvi_acwmin, pWmm->acvi_acwmax, pWmm->acvi_txoplimit); + + lim_log(pMac, LOG1, + FL("VO: aifsn %d, acm %d, aci %d, cwmin %d, cwmax %d, txop %d"), + pWmm->acvo_aifsn, pWmm->acvo_acm, pWmm->acvo_aci, + pWmm->acvo_acwmin, pWmm->acvo_acwmax, pWmm->acvo_txoplimit); + + return; +} + +/* ////////////////////////////////////////////////////////////////////// */ +/* Functions for populating "dot11f" style IEs */ + +/* return: >= 0, the starting location of the IE in rsnIEdata inside tSirRSNie */ +/* < 0, cannot find */ +int find_ie_location(tpAniSirGlobal pMac, tpSirRSNie pRsnIe, uint8_t EID) +{ + int idx, ieLen, bytesLeft; + int ret_val = -1; + + /* Here's what's going on: 'rsnIe' looks like this: */ + + /* typedef struct sSirRSNie */ + /* { */ + /* uint16_t length; */ + /* uint8_t rsnIEdata[SIR_MAC_MAX_IE_LENGTH+2]; */ + /* } tSirRSNie, *tpSirRSNie; */ + + /* other code records both the WPA & RSN IEs (including their EIDs & */ + /* lengths) into the array 'rsnIEdata'. We may have: */ + + /* With WAPI support, there may be 3 IEs here */ + /* It can be only WPA IE, or only RSN IE or only WAPI IE */ + /* Or two or all three of them with no particular ordering */ + + /* The if/then/else statements that follow are here to figure out */ + /* whether we have the WPA IE, and where it is if we *do* have it. */ + + /* Save the first IE length */ + ieLen = pRsnIe->rsnIEdata[1] + 2; + idx = 0; + bytesLeft = pRsnIe->length; + + while (1) { + if (EID == pRsnIe->rsnIEdata[idx]) { + /* Found it */ + return idx; + } else if (EID != pRsnIe->rsnIEdata[idx] && + /* & if no more IE, */ + bytesLeft <= (uint16_t) (ieLen)) { + dot11f_log(pMac, LOG3, + FL("No IE (%d) in find_ie_location."), EID); + return ret_val; + } + bytesLeft -= ieLen; + ieLen = pRsnIe->rsnIEdata[idx + 1] + 2; + idx += ieLen; + } + + return ret_val; +} + +tSirRetStatus +populate_dot11f_capabilities(tpAniSirGlobal pMac, + tDot11fFfCapabilities *pDot11f, + tpPESession psessionEntry) +{ + uint16_t cfg; + tSirRetStatus nSirStatus; + + nSirStatus = cfg_get_capability_info(pMac, &cfg, psessionEntry); + if (eSIR_SUCCESS != nSirStatus) { + dot11f_log(pMac, LOGP, + FL("Failed to retrieve the Capabilities bitfield from CFG (%d)."), + nSirStatus); + return nSirStatus; + } + + swap_bit_field16(cfg, (uint16_t *) pDot11f); + + return eSIR_SUCCESS; +} /* End populate_dot11f_capabilities. */ + +/** + * populate_dot_11_f_ext_chann_switch_ann() - Function to populate ECS + * @mac_ptr: Pointer to PMAC structure + * @dot_11_ptr: ECS element + * @session_entry: PE session entry + * + * This function is used to populate the extended channel switch element + * + * Return: None + */ +void populate_dot_11_f_ext_chann_switch_ann(tpAniSirGlobal mac_ptr, + tDot11fIEext_chan_switch_ann *dot_11_ptr, + tpPESession session_entry) +{ + uint8_t ch_offset; + + if (session_entry->gLimChannelSwitch.ch_width == CH_WIDTH_80MHZ) + ch_offset = BW80; + else + ch_offset = session_entry->gLimChannelSwitch.sec_ch_offset; + + dot_11_ptr->switch_mode = session_entry->gLimChannelSwitch.switchMode; + dot_11_ptr->new_reg_class = cds_reg_dmn_get_opclass_from_channel( + mac_ptr->scan.countryCodeCurrent, + session_entry->gLimChannelSwitch.primaryChannel, + ch_offset); + dot_11_ptr->new_channel = + session_entry->gLimChannelSwitch.primaryChannel; + dot_11_ptr->switch_count = + session_entry->gLimChannelSwitch.switchCount; + dot_11_ptr->present = 1; + + dot11f_log(mac_ptr, LOG1, + FL("country:%s chan:%d width:%d reg:%d off:%d"), + mac_ptr->scan.countryCodeCurrent, + session_entry->gLimChannelSwitch.primaryChannel, + session_entry->gLimChannelSwitch.ch_width, + dot_11_ptr->new_reg_class, + session_entry->gLimChannelSwitch.sec_ch_offset); +} + +void +populate_dot11f_chan_switch_ann(tpAniSirGlobal pMac, + tDot11fIEChanSwitchAnn *pDot11f, + tpPESession psessionEntry) +{ + pDot11f->switchMode = psessionEntry->gLimChannelSwitch.switchMode; + pDot11f->newChannel = psessionEntry->gLimChannelSwitch.primaryChannel; + pDot11f->switchCount = + (uint8_t) psessionEntry->gLimChannelSwitch.switchCount; + + pDot11f->present = 1; +} + +/** + * populate_dot11_supp_operating_classes() - Function to populate supported + * operating class IE + * @mac_ptr: Pointer to PMAC structure + * @dot_11_ptr: Operating class element + * @session_entry: PE session entry + * + * Return: None + */ +void +populate_dot11_supp_operating_classes(tpAniSirGlobal mac_ptr, + tDot11fIESuppOperatingClasses *dot_11_ptr, + tpPESession session_entry) +{ + uint8_t ch_bandwidth; + + if (session_entry->ch_width == CH_WIDTH_80MHZ) { + ch_bandwidth = BW80; + } else { + switch (session_entry->htSecondaryChannelOffset) { + case PHY_DOUBLE_CHANNEL_HIGH_PRIMARY: + ch_bandwidth = BW40_HIGH_PRIMARY; + break; + case PHY_DOUBLE_CHANNEL_LOW_PRIMARY: + ch_bandwidth = BW40_LOW_PRIMARY; + break; + default: + ch_bandwidth = BW20; + break; + } + } + + cds_reg_dmn_get_curr_opclasses(&dot_11_ptr->num_classes, + &dot_11_ptr->classes[1]); + dot_11_ptr->classes[0] = cds_reg_dmn_get_opclass_from_channel( + mac_ptr->scan.countryCodeCurrent, + session_entry->currentOperChannel, + ch_bandwidth); + dot_11_ptr->num_classes++; + dot_11_ptr->present = 1; +} + +void +populate_dot11f_chan_switch_wrapper(tpAniSirGlobal pMac, + tDot11fIEChannelSwitchWrapper *pDot11f, + tpPESession psessionEntry) +{ + uint8_t *ie_ptr = NULL; + + /* + * The new country subelement is present only when + * 1. AP performs Extended Channel switching to new country. + * 2. New Operating Class table or a changed set of operating + * classes relative to the contents of the country element sent + * in the beacons. + * + * In the current scenario Channel Switch wrapper IE is included + * when we a radar is found and the AP does a channel change in + * the same regulatory domain(No country change or Operating class + * table). So, we do not need to include the New Country IE. + * + * Transmit Power Envlope Subelement is optional + * in Channel Switch Wrapper IE. So, not setting + * the TPE subelement. We include only WiderBWChanSwitchAnn. + */ + pDot11f->present = 1; + + /* + * Add the Wide Channel Bandwidth Sublement. + */ + pDot11f->WiderBWChanSwitchAnn.newChanWidth = + psessionEntry->gLimWiderBWChannelSwitch.newChanWidth; + pDot11f->WiderBWChanSwitchAnn.newCenterChanFreq0 = + psessionEntry->gLimWiderBWChannelSwitch.newCenterChanFreq0; + pDot11f->WiderBWChanSwitchAnn.newCenterChanFreq1 = + psessionEntry->gLimWiderBWChannelSwitch.newCenterChanFreq1; + pDot11f->WiderBWChanSwitchAnn.present = 1; + + /* + * Add the VHT Transmit power Envelope Sublement. + */ + ie_ptr = lim_get_ie_ptr_new(pMac, + psessionEntry->addIeParams.probeRespBCNData_buff, + psessionEntry->addIeParams.probeRespBCNDataLen, + DOT11F_EID_VHT_TRANSMIT_POWER_ENV, ONE_BYTE); + if (ie_ptr) { + /* Ignore EID field */ + ie_ptr++; + pDot11f->vht_transmit_power_env.present = 1; + pDot11f->vht_transmit_power_env.num_bytes = *ie_ptr++; + qdf_mem_copy(pDot11f->vht_transmit_power_env.bytes, + ie_ptr, pDot11f->vht_transmit_power_env.num_bytes); + } + +} + +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE +void +populate_dot11f_avoid_channel_ie(tpAniSirGlobal mac_ctx, + tDot11fIEQComVendorIE *dot11f, + tpPESession pe_session) +{ + if (!pe_session->sap_advertise_avoid_ch_ie) + return; + + dot11f->present = true; + dot11f->type = QCOM_VENDOR_IE_MCC_AVOID_CH; + dot11f->channel = pe_session->currentOperChannel; +} +#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ + +void +populate_dot11f_wider_bw_chan_switch_ann(tpAniSirGlobal pMac, + tDot11fIEWiderBWChanSwitchAnn *pDot11f, + tpPESession psessionEntry) +{ + pDot11f->present = 1; + pDot11f->newChanWidth = + psessionEntry->gLimWiderBWChannelSwitch.newChanWidth; + pDot11f->newCenterChanFreq0 = + psessionEntry->gLimWiderBWChannelSwitch.newCenterChanFreq0; + pDot11f->newCenterChanFreq1 = + psessionEntry->gLimWiderBWChannelSwitch.newCenterChanFreq1; +} + +tSirRetStatus +populate_dot11f_country(tpAniSirGlobal pMac, + tDot11fIECountry *pDot11f, tpPESession psessionEntry) +{ + uint32_t len, maxlen, codelen; + uint16_t item; + tSirRetStatus nSirStatus; + tSirRFBand rfBand; + uint8_t temp[CFG_MAX_STR_LEN], code[3]; + + if (psessionEntry->lim11dEnabled) { + lim_get_rf_band_new(pMac, &rfBand, psessionEntry); + if (rfBand == SIR_BAND_5_GHZ) { + item = WNI_CFG_MAX_TX_POWER_5; + maxlen = WNI_CFG_MAX_TX_POWER_5_LEN; + } else { + item = WNI_CFG_MAX_TX_POWER_2_4; + maxlen = WNI_CFG_MAX_TX_POWER_2_4_LEN; + } + + CFG_GET_STR(nSirStatus, pMac, item, temp, len, maxlen); + + if (3 > len) { + /* no limit on tx power, cannot include the IE because at least */ + /* one (channel,num,tx power) must be present */ + return eSIR_SUCCESS; + } + + CFG_GET_STR(nSirStatus, pMac, WNI_CFG_COUNTRY_CODE, + code, codelen, 3); + + qdf_mem_copy(pDot11f->country, code, codelen); + + if (len > MAX_SIZE_OF_TRIPLETS_IN_COUNTRY_IE) { + dot11f_log(pMac, LOGE, + FL("len:%d is out of bounds, resetting."), + len); + len = MAX_SIZE_OF_TRIPLETS_IN_COUNTRY_IE; + } + + pDot11f->num_triplets = (uint8_t) (len / 3); + qdf_mem_copy((uint8_t *) pDot11f->triplets, temp, len); + + pDot11f->present = 1; + } + + return eSIR_SUCCESS; +} /* End populate_dot11f_country. */ + +#ifdef QCA_WIFI_3_0_EMU +/** + * populate_dot11f_ds_params() - To populate DS IE params + * mac_ctx: Pointer to global mac context + * dot11f_param: pointer to DS params IE + * channel: channel number + * + * This routine will populate DS param in management frame like + * beacon, probe response, and etc. + * + * Return: Overall sucess + */ +tSirRetStatus +populate_dot11f_ds_params(tpAniSirGlobal mac_ctx, + tDot11fIEDSParams *dot11f_param, uint8_t channel) +{ + /* .11a/11b/g mode PHY => Include the DS Parameter Set IE: */ + dot11f_param->curr_channel = channel; + dot11f_param->present = 1; + + return eSIR_SUCCESS; +} /* End populate_dot11f_ds_params. */ +#else +/** + * populate_dot11f_ds_params() - To populate DS IE params + * mac_ctx: Pointer to global mac context + * dot11f_param: pointer to DS params IE + * channel: channel number + * + * This routine will populate DS param in management frame like + * beacon, probe response, and etc. + * + * Return: Overall sucess + */ +tSirRetStatus +populate_dot11f_ds_params(tpAniSirGlobal mac_ctx, + tDot11fIEDSParams *dot11f_param, uint8_t channel) +{ + if (IS_24G_CH(channel)) { + /* .11b/g mode PHY => Include the DS Parameter Set IE: */ + dot11f_param->curr_channel = channel; + dot11f_param->present = 1; + } + + return eSIR_SUCCESS; +} +#endif + +#define SET_AIFSN(aifsn) (((aifsn) < 2) ? 2 : (aifsn)) + +void +populate_dot11f_edca_param_set(tpAniSirGlobal pMac, + tDot11fIEEDCAParamSet *pDot11f, + tpPESession psessionEntry) +{ + + if (psessionEntry->limQosEnabled) { + /* change to bitwise operation, after this is fixed in frames. */ + pDot11f->qos = + (uint8_t) (0xf0 & + (psessionEntry->gLimEdcaParamSetCount << 4)); + + /* Fill each EDCA parameter set in order: be, bk, vi, vo */ + pDot11f->acbe_aifsn = + (0xf & + SET_AIFSN(psessionEntry->gLimEdcaParamsBC[0].aci.aifsn)); + pDot11f->acbe_acm = + (0x1 & psessionEntry->gLimEdcaParamsBC[0].aci.acm); + pDot11f->acbe_aci = (0x3 & SIR_MAC_EDCAACI_BESTEFFORT); + pDot11f->acbe_acwmin = + (0xf & psessionEntry->gLimEdcaParamsBC[0].cw.min); + pDot11f->acbe_acwmax = + (0xf & psessionEntry->gLimEdcaParamsBC[0].cw.max); + pDot11f->acbe_txoplimit = + psessionEntry->gLimEdcaParamsBC[0].txoplimit; + + pDot11f->acbk_aifsn = + (0xf & + SET_AIFSN(psessionEntry->gLimEdcaParamsBC[1].aci.aifsn)); + pDot11f->acbk_acm = + (0x1 & psessionEntry->gLimEdcaParamsBC[1].aci.acm); + pDot11f->acbk_aci = (0x3 & SIR_MAC_EDCAACI_BACKGROUND); + pDot11f->acbk_acwmin = + (0xf & psessionEntry->gLimEdcaParamsBC[1].cw.min); + pDot11f->acbk_acwmax = + (0xf & psessionEntry->gLimEdcaParamsBC[1].cw.max); + pDot11f->acbk_txoplimit = + psessionEntry->gLimEdcaParamsBC[1].txoplimit; + + pDot11f->acvi_aifsn = + (0xf & + SET_AIFSN(psessionEntry->gLimEdcaParamsBC[2].aci.aifsn)); + pDot11f->acvi_acm = + (0x1 & psessionEntry->gLimEdcaParamsBC[2].aci.acm); + pDot11f->acvi_aci = (0x3 & SIR_MAC_EDCAACI_VIDEO); + pDot11f->acvi_acwmin = + (0xf & psessionEntry->gLimEdcaParamsBC[2].cw.min); + pDot11f->acvi_acwmax = + (0xf & psessionEntry->gLimEdcaParamsBC[2].cw.max); + pDot11f->acvi_txoplimit = + psessionEntry->gLimEdcaParamsBC[2].txoplimit; + + pDot11f->acvo_aifsn = + (0xf & + SET_AIFSN(psessionEntry->gLimEdcaParamsBC[3].aci.aifsn)); + pDot11f->acvo_acm = + (0x1 & psessionEntry->gLimEdcaParamsBC[3].aci.acm); + pDot11f->acvo_aci = (0x3 & SIR_MAC_EDCAACI_VOICE); + pDot11f->acvo_acwmin = + (0xf & psessionEntry->gLimEdcaParamsBC[3].cw.min); + pDot11f->acvo_acwmax = + (0xf & psessionEntry->gLimEdcaParamsBC[3].cw.max); + pDot11f->acvo_txoplimit = + psessionEntry->gLimEdcaParamsBC[3].txoplimit; + + pDot11f->present = 1; + } + +} /* End PopluateDot11fEDCAParamSet. */ + +tSirRetStatus +populate_dot11f_erp_info(tpAniSirGlobal pMac, + tDot11fIEERPInfo *pDot11f, tpPESession psessionEntry) +{ + tSirRetStatus nSirStatus; + uint32_t val; + tSirRFBand rfBand = SIR_BAND_UNKNOWN; + + lim_get_rf_band_new(pMac, &rfBand, psessionEntry); + if (SIR_BAND_2_4_GHZ == rfBand) { + pDot11f->present = 1; + + val = psessionEntry->cfgProtection.fromllb; + if (!val) { + dot11f_log(pMac, LOGE, + FL("11B protection not enabled. Not populating ERP IE %d"), + val); + return eSIR_SUCCESS; + } + + if (psessionEntry->gLim11bParams.protectionEnabled) { + pDot11f->non_erp_present = 1; + pDot11f->use_prot = 1; + } + + if (psessionEntry->gLimOlbcParams.protectionEnabled) { + /* FIXME_PROTECTION: we should be setting non_erp present also. */ + /* check the test plan first. */ + pDot11f->use_prot = 1; + } + + if ((psessionEntry->gLimNoShortParams.numNonShortPreambleSta) + || !psessionEntry->beaconParams.fShortPreamble) { + pDot11f->barker_preamble = 1; + + } + /* if protection always flag is set, advertise protection enabled */ + /* regardless of legacy stations presence */ + CFG_GET_INT(nSirStatus, pMac, WNI_CFG_11G_PROTECTION_ALWAYS, + val); + + if (val) { + pDot11f->use_prot = 1; + } + } + + return eSIR_SUCCESS; +} /* End populate_dot11f_erp_info. */ + +tSirRetStatus +populate_dot11f_ext_supp_rates(tpAniSirGlobal pMac, uint8_t nChannelNum, + tDot11fIEExtSuppRates *pDot11f, + tpPESession psessionEntry) +{ + tSirRetStatus nSirStatus; + uint32_t nRates = 0; + uint8_t rates[SIR_MAC_RATESET_EID_MAX]; + + /* Use the ext rates present in session entry whenever nChannelNum is set to OPERATIONAL + else use the ext supported rate set from CFG, which is fixed and does not change dynamically and is used for + sending mgmt frames (lile probe req) which need to go out before any session is present. + */ + if (POPULATE_DOT11F_RATES_OPERATIONAL == nChannelNum) { + if (psessionEntry != NULL) { + nRates = psessionEntry->extRateSet.numRates; + qdf_mem_copy(rates, psessionEntry->extRateSet.rate, + nRates); + } else { + dot11f_log(pMac, LOGE, + FL("no session context exists while populating Operational Rate Set")); + } + } else if (HIGHEST_24GHZ_CHANNEL_NUM >= nChannelNum) { + CFG_GET_STR(nSirStatus, pMac, + WNI_CFG_EXTENDED_OPERATIONAL_RATE_SET, rates, + nRates, WNI_CFG_EXTENDED_OPERATIONAL_RATE_SET_LEN); + } + + if (0 != nRates) { + pDot11f->num_rates = (uint8_t) nRates; + qdf_mem_copy(pDot11f->rates, rates, nRates); + pDot11f->present = 1; + } + + return eSIR_SUCCESS; + +} /* End populate_dot11f_ext_supp_rates. */ + +tSirRetStatus +populate_dot11f_ext_supp_rates1(tpAniSirGlobal pMac, + uint8_t nChannelNum, + tDot11fIEExtSuppRates *pDot11f) +{ + uint32_t nRates; + tSirRetStatus nSirStatus; + uint8_t rates[SIR_MAC_MAX_NUMBER_OF_RATES]; + + if (14 < nChannelNum) { + pDot11f->present = 0; + return eSIR_SUCCESS; + } + /* N.B. I have *no* idea why we're calling 'wlan_cfg_get_str' with an argument */ + /* of WNI_CFG_SUPPORTED_RATES_11A here, but that's what was done */ + /* previously & I'm afraid to change it! */ + CFG_GET_STR(nSirStatus, pMac, WNI_CFG_SUPPORTED_RATES_11A, + rates, nRates, SIR_MAC_MAX_NUMBER_OF_RATES); + + if (0 != nRates) { + pDot11f->num_rates = (uint8_t) nRates; + qdf_mem_copy(pDot11f->rates, rates, nRates); + pDot11f->present = 1; + } + + return eSIR_SUCCESS; +} /* populate_dot11f_ext_supp_rates1. */ + +tSirRetStatus +populate_dot11f_ht_caps(tpAniSirGlobal pMac, + tpPESession psessionEntry, tDot11fIEHTCaps *pDot11f) +{ + uint32_t nCfgValue, nCfgLen; + uint8_t nCfgValue8; + tSirRetStatus nSirStatus; + tSirMacHTParametersInfo *pHTParametersInfo; + uint8_t disable_high_ht_mcs_2x2 = 0; + union { + uint16_t nCfgValue16; + tSirMacHTCapabilityInfo htCapInfo; + tSirMacExtendedHTCapabilityInfo extHtCapInfo; + } uHTCapabilityInfo; + + tSirMacTxBFCapabilityInfo *pTxBFCapabilityInfo; + tSirMacASCapabilityInfo *pASCapabilityInfo; + + CFG_GET_INT(nSirStatus, pMac, WNI_CFG_HT_CAP_INFO, nCfgValue); + + uHTCapabilityInfo.nCfgValue16 = nCfgValue & 0xFFFF; + + pDot11f->mimoPowerSave = uHTCapabilityInfo.htCapInfo.mimoPowerSave; + pDot11f->greenField = uHTCapabilityInfo.htCapInfo.greenField; + pDot11f->delayedBA = uHTCapabilityInfo.htCapInfo.delayedBA; + pDot11f->maximalAMSDUsize = + uHTCapabilityInfo.htCapInfo.maximalAMSDUsize; + pDot11f->dsssCckMode40MHz = + uHTCapabilityInfo.htCapInfo.dsssCckMode40MHz; + pDot11f->psmp = uHTCapabilityInfo.htCapInfo.psmp; + pDot11f->stbcControlFrame = + uHTCapabilityInfo.htCapInfo.stbcControlFrame; + pDot11f->lsigTXOPProtection = + uHTCapabilityInfo.htCapInfo.lsigTXOPProtection; + + /* All sessionized entries will need the check below */ + if (psessionEntry == NULL) { /* Only in case of NO session */ + pDot11f->supportedChannelWidthSet = + uHTCapabilityInfo.htCapInfo.supportedChannelWidthSet; + pDot11f->advCodingCap = + uHTCapabilityInfo.htCapInfo.advCodingCap; + pDot11f->txSTBC = uHTCapabilityInfo.htCapInfo.txSTBC; + pDot11f->rxSTBC = uHTCapabilityInfo.htCapInfo.rxSTBC; + pDot11f->shortGI20MHz = + uHTCapabilityInfo.htCapInfo.shortGI20MHz; + pDot11f->shortGI40MHz = + uHTCapabilityInfo.htCapInfo.shortGI40MHz; + } else { + pDot11f->advCodingCap = psessionEntry->htConfig.ht_rx_ldpc; + pDot11f->supportedChannelWidthSet = + psessionEntry->htSupportedChannelWidthSet; + pDot11f->txSTBC = psessionEntry->htConfig.ht_tx_stbc; + pDot11f->rxSTBC = psessionEntry->htConfig.ht_rx_stbc; + pDot11f->shortGI20MHz = psessionEntry->htConfig.ht_sgi20; + pDot11f->shortGI40MHz = psessionEntry->htConfig.ht_sgi40; + } + + /* Ensure that shortGI40MHz is Disabled if supportedChannelWidthSet is + eHT_CHANNEL_WIDTH_20MHZ */ + if (pDot11f->supportedChannelWidthSet == eHT_CHANNEL_WIDTH_20MHZ) { + pDot11f->shortGI40MHz = 0; + } + + CFG_GET_INT(nSirStatus, pMac, WNI_CFG_HT_AMPDU_PARAMS, nCfgValue); + + nCfgValue8 = (uint8_t) nCfgValue; + pHTParametersInfo = (tSirMacHTParametersInfo *) &nCfgValue8; + + pDot11f->maxRxAMPDUFactor = pHTParametersInfo->maxRxAMPDUFactor; + pDot11f->mpduDensity = pHTParametersInfo->mpduDensity; + pDot11f->reserved1 = pHTParametersInfo->reserved; + + CFG_GET_STR(nSirStatus, pMac, WNI_CFG_SUPPORTED_MCS_SET, + pDot11f->supportedMCSSet, nCfgLen, + SIZE_OF_SUPPORTED_MCS_SET); + + if (psessionEntry) { + disable_high_ht_mcs_2x2 = + pMac->roam.configParam.disable_high_ht_mcs_2x2; + pe_debug("disable HT high MCS INI param[%d]", + disable_high_ht_mcs_2x2); + + if (pMac->lteCoexAntShare + && (IS_24G_CH(psessionEntry->currentOperChannel))) { + if (!(IS_2X2_CHAIN(psessionEntry->chainMask))) { + pDot11f->supportedMCSSet[1] = 0; + if (LIM_IS_STA_ROLE(psessionEntry)) { + pDot11f->mimoPowerSave = + psessionEntry->smpsMode; + } + } + } + if (psessionEntry->nss == NSS_1x1_MODE) { + pDot11f->supportedMCSSet[1] = 0; + } else if (IS_24G_CH(psessionEntry->currentOperChannel) && + disable_high_ht_mcs_2x2 && + (psessionEntry->pePersona == QDF_STA_MODE)) { + pe_debug("Disabling high HT MCS [%d]", + disable_high_ht_mcs_2x2); + pDot11f->supportedMCSSet[1] = + (pDot11f->supportedMCSSet[1] >> + disable_high_ht_mcs_2x2); + } + } + + /* If STA mode, session supported NSS > 1 and + * SMPS enabled publish HT SMPS IE + */ + if (psessionEntry && + LIM_IS_STA_ROLE(psessionEntry) && + (psessionEntry->enableHtSmps) && + (!psessionEntry->supported_nss_1x1)) { + lim_log(pMac, LOG1, FL("Add SM power save IE: %d"), + psessionEntry->htSmpsvalue); + pDot11f->mimoPowerSave = psessionEntry->htSmpsvalue; + } + + CFG_GET_INT(nSirStatus, pMac, WNI_CFG_EXT_HT_CAP_INFO, nCfgValue); + + uHTCapabilityInfo.nCfgValue16 = nCfgValue & 0xFFFF; + + pDot11f->pco = uHTCapabilityInfo.extHtCapInfo.pco; + pDot11f->transitionTime = uHTCapabilityInfo.extHtCapInfo.transitionTime; + pDot11f->mcsFeedback = uHTCapabilityInfo.extHtCapInfo.mcsFeedback; + + CFG_GET_INT(nSirStatus, pMac, WNI_CFG_TX_BF_CAP, nCfgValue); + + pTxBFCapabilityInfo = (tSirMacTxBFCapabilityInfo *) &nCfgValue; + pDot11f->txBF = pTxBFCapabilityInfo->txBF; + pDot11f->rxStaggeredSounding = pTxBFCapabilityInfo->rxStaggeredSounding; + pDot11f->txStaggeredSounding = pTxBFCapabilityInfo->txStaggeredSounding; + pDot11f->rxZLF = pTxBFCapabilityInfo->rxZLF; + pDot11f->txZLF = pTxBFCapabilityInfo->txZLF; + pDot11f->implicitTxBF = pTxBFCapabilityInfo->implicitTxBF; + pDot11f->calibration = pTxBFCapabilityInfo->calibration; + pDot11f->explicitCSITxBF = pTxBFCapabilityInfo->explicitCSITxBF; + pDot11f->explicitUncompressedSteeringMatrix = + pTxBFCapabilityInfo->explicitUncompressedSteeringMatrix; + pDot11f->explicitBFCSIFeedback = + pTxBFCapabilityInfo->explicitBFCSIFeedback; + pDot11f->explicitUncompressedSteeringMatrixFeedback = + pTxBFCapabilityInfo->explicitUncompressedSteeringMatrixFeedback; + pDot11f->explicitCompressedSteeringMatrixFeedback = + pTxBFCapabilityInfo->explicitCompressedSteeringMatrixFeedback; + pDot11f->csiNumBFAntennae = pTxBFCapabilityInfo->csiNumBFAntennae; + pDot11f->uncompressedSteeringMatrixBFAntennae = + pTxBFCapabilityInfo->uncompressedSteeringMatrixBFAntennae; + pDot11f->compressedSteeringMatrixBFAntennae = + pTxBFCapabilityInfo->compressedSteeringMatrixBFAntennae; + + CFG_GET_INT(nSirStatus, pMac, WNI_CFG_AS_CAP, nCfgValue); + + nCfgValue8 = (uint8_t) nCfgValue; + + pASCapabilityInfo = (tSirMacASCapabilityInfo *) &nCfgValue8; + pDot11f->antennaSelection = pASCapabilityInfo->antennaSelection; + pDot11f->explicitCSIFeedbackTx = + pASCapabilityInfo->explicitCSIFeedbackTx; + pDot11f->antennaIndicesFeedbackTx = + pASCapabilityInfo->antennaIndicesFeedbackTx; + pDot11f->explicitCSIFeedback = pASCapabilityInfo->explicitCSIFeedback; + pDot11f->antennaIndicesFeedback = + pASCapabilityInfo->antennaIndicesFeedback; + pDot11f->rxAS = pASCapabilityInfo->rxAS; + pDot11f->txSoundingPPDUs = pASCapabilityInfo->txSoundingPPDUs; + + pDot11f->present = 1; + + return eSIR_SUCCESS; + +} /* End populate_dot11f_ht_caps. */ + +void lim_log_vht_cap(tpAniSirGlobal pMac, tDot11fIEVHTCaps *pDot11f) +{ +#ifdef DUMP_MGMT_CNTNTS + lim_log(pMac, LOG1, FL("maxMPDULen (2): %d"), pDot11f->maxMPDULen); + lim_log(pMac, LOG1, FL("supportedChannelWidthSet (2): %d"), + pDot11f->supportedChannelWidthSet); + lim_log(pMac, LOG1, FL("ldpcCodingCap (1): %d"), + pDot11f->ldpcCodingCap); + lim_log(pMac, LOG1, FL("shortGI80MHz (1): %d"), pDot11f->shortGI80MHz); + lim_log(pMac, LOG1, FL("shortGI160and80plus80MHz (1): %d"), + pDot11f->shortGI160and80plus80MHz); + lim_log(pMac, LOG1, FL("txSTBC (1): %d"), pDot11f->txSTBC); + lim_log(pMac, LOG1, FL("rxSTBC (3): %d"), pDot11f->rxSTBC); + lim_log(pMac, LOG1, FL("suBeamFormerCap (1): %d"), + pDot11f->suBeamFormerCap); + lim_log(pMac, LOG1, FL("suBeamformeeCap (1): %d"), + pDot11f->suBeamformeeCap); + lim_log(pMac, LOG1, FL("csnofBeamformerAntSup (3): %d"), + pDot11f->csnofBeamformerAntSup); + lim_log(pMac, LOG1, FL("numSoundingDim (3): %d"), + pDot11f->numSoundingDim); + lim_log(pMac, LOG1, FL("muBeamformerCap (1): %d"), + pDot11f->muBeamformerCap); + lim_log(pMac, LOG1, FL("muBeamformeeCap (1): %d"), + pDot11f->muBeamformeeCap); + lim_log(pMac, LOG1, FL("vhtTXOPPS (1): %d"), pDot11f->vhtTXOPPS); + lim_log(pMac, LOG1, FL("htcVHTCap (1): %d"), pDot11f->htcVHTCap); + lim_log(pMac, LOG1, FL("maxAMPDULenExp (3): %d"), + pDot11f->maxAMPDULenExp); + lim_log(pMac, LOG1, FL("vhtLinkAdaptCap (2): %d"), + pDot11f->vhtLinkAdaptCap); + lim_log(pMac, LOG1, FL("rxAntPattern (1): %d"), + pDot11f->rxAntPattern); + lim_log(pMac, LOG1, FL("txAntPattern (1): %d"), + pDot11f->txAntPattern); + lim_log(pMac, LOG1, FL("reserved1 (2): %d"), pDot11f->reserved1); + lim_log(pMac, LOG1, FL("rxMCSMap (16): %d"), pDot11f->rxMCSMap); + lim_log(pMac, LOG1, FL("rxHighSupDataRate (13): %d"), + pDot11f->rxHighSupDataRate); + lim_log(pMac, LOG1, FL("reserved2(3): %d"), pDot11f->reserved2); + lim_log(pMac, LOG1, FL("txMCSMap (16): %d"), pDot11f->txMCSMap); + lim_log(pMac, LOG1, FL("txSupDataRate (13): %d"), + pDot11f->txSupDataRate); + lim_log(pMac, LOG1, FL("reserved3 (3): %d"), pDot11f->reserved3); +#endif /* DUMP_MGMT_CNTNTS */ +} + +static void lim_log_vht_operation(tpAniSirGlobal pMac, + tDot11fIEVHTOperation *pDot11f) +{ +#ifdef DUMP_MGMT_CNTNTS + lim_log(pMac, LOG1, FL("chanWidth : %d"), pDot11f->chanWidth); + lim_log(pMac, LOG1, FL("chanCenterFreqSeg1: %d"), + pDot11f->chanCenterFreqSeg1); + lim_log(pMac, LOG1, FL("chanCenterFreqSeg2: %d"), + pDot11f->chanCenterFreqSeg2); + lim_log(pMac, LOG1, FL("basicMCSSet: %d"), pDot11f->basicMCSSet); +#endif /* DUMP_MGMT_CNTNTS */ +} + +static void lim_log_vht_ext_bss_load(tpAniSirGlobal pMac, + tDot11fIEVHTExtBssLoad *pDot11f) +{ +#ifdef DUMP_MGMT_CNTNTS + lim_log(pMac, LOG1, FL("muMIMOCapStaCount : %d"), + pDot11f->muMIMOCapStaCount); + lim_log(pMac, LOG1, FL("ssUnderUtil: %d"), pDot11f->ssUnderUtil); + lim_log(pMac, LOG1, FL("FortyMHzUtil: %d"), pDot11f->FortyMHzUtil); + lim_log(pMac, LOG1, FL("EightyMHzUtil: %d"), pDot11f->EightyMHzUtil); + lim_log(pMac, LOG1, FL("OneSixtyMHzUtil: %d"), + pDot11f->OneSixtyMHzUtil); +#endif /* DUMP_MGMT_CNTNTS */ +} + +static void lim_log_operating_mode(tpAniSirGlobal pMac, + tDot11fIEOperatingMode *pDot11f) +{ +#ifdef DUMP_MGMT_CNTNTS + lim_log(pMac, LOG1, FL("ChanWidth : %d"), pDot11f->chanWidth); + lim_log(pMac, LOG1, FL("reserved: %d"), pDot11f->reserved); + lim_log(pMac, LOG1, FL("rxNSS: %d"), pDot11f->rxNSS); + lim_log(pMac, LOG1, FL("rxNSS Type: %d"), pDot11f->rxNSSType); +#endif /* DUMP_MGMT_CNTNTS */ +} + +static void lim_log_qos_map_set(tpAniSirGlobal pMac, tSirQosMapSet *pQosMapSet) +{ + uint8_t i; + if (pQosMapSet->num_dscp_exceptions > QOS_MAP_MAX_EX) + pQosMapSet->num_dscp_exceptions = QOS_MAP_MAX_EX; + lim_log(pMac, LOG1, FL("num of dscp exceptions : %d"), + pQosMapSet->num_dscp_exceptions); + for (i = 0; i < pQosMapSet->num_dscp_exceptions; i++) { + lim_log(pMac, LOG1, FL("dscp value: %d"), + pQosMapSet->dscp_exceptions[i][0]); + lim_log(pMac, LOG1, FL("User priority value: %d"), + pQosMapSet->dscp_exceptions[i][1]); + } + for (i = 0; i < 8; i++) { + lim_log(pMac, LOG1, FL("dscp low for up %d: %d"), i, + pQosMapSet->dscp_range[i][0]); + lim_log(pMac, LOG1, FL("dscp high for up %d: %d"), i, + pQosMapSet->dscp_range[i][1]); + } +} + +tSirRetStatus +populate_dot11f_vht_caps(tpAniSirGlobal pMac, + tpPESession psessionEntry, tDot11fIEVHTCaps *pDot11f) +{ + tSirRetStatus nStatus; + uint32_t nCfgValue = 0; + + pDot11f->present = 1; + + CFG_GET_INT(nStatus, pMac, WNI_CFG_VHT_MAX_MPDU_LENGTH, nCfgValue); + pDot11f->maxMPDULen = (nCfgValue & 0x0003); + + nCfgValue = 0; + CFG_GET_INT(nStatus, pMac, WNI_CFG_VHT_SUPPORTED_CHAN_WIDTH_SET, + nCfgValue); + pDot11f->supportedChannelWidthSet = (nCfgValue & 0x0003); + + nCfgValue = 0; + /* With VHT it suffices if we just examine HT */ + if (psessionEntry) { + if (psessionEntry->htConfig.ht_rx_ldpc) + pDot11f->ldpcCodingCap = + psessionEntry->vht_config.ldpc_coding; + if (psessionEntry->ch_width < CH_WIDTH_80MHZ) { + pDot11f->shortGI80MHz = 0; + } else { + pDot11f->shortGI80MHz = + psessionEntry->vht_config.shortgi80; + } + + if (psessionEntry->ch_width < CH_WIDTH_160MHZ) { + pDot11f->shortGI160and80plus80MHz = 0; + pDot11f->supportedChannelWidthSet = 0; + } else { + pDot11f->shortGI160and80plus80MHz = + psessionEntry->vht_config.shortgi160and80plus80; + } + + if (psessionEntry->htConfig.ht_tx_stbc) + pDot11f->txSTBC = psessionEntry->vht_config.tx_stbc; + + if (psessionEntry->htConfig.ht_rx_stbc) + pDot11f->rxSTBC = psessionEntry->vht_config.rx_stbc; + + pDot11f->suBeamformeeCap = + psessionEntry->vht_config.su_beam_formee; + if (psessionEntry->vht_config.su_beam_formee) { + nCfgValue = 0; + CFG_GET_INT(nStatus, pMac, + WNI_CFG_VHT_MU_BEAMFORMEE_CAP, nCfgValue); + pDot11f->muBeamformeeCap = (nCfgValue & 0x0001); + pDot11f->csnofBeamformerAntSup = + psessionEntry->vht_config.csnof_beamformer_antSup; + } else { + pDot11f->muBeamformeeCap = 0; + } + pDot11f->suBeamFormerCap = + psessionEntry->vht_config.su_beam_former; + + pDot11f->vhtTXOPPS = psessionEntry->vht_config.vht_txops; + + pDot11f->numSoundingDim = + psessionEntry->vht_config.num_soundingdim; + + pDot11f->htcVHTCap = psessionEntry->vht_config.htc_vhtcap; + + pDot11f->rxAntPattern = psessionEntry->vht_config.rx_antpattern; + + pDot11f->txAntPattern = psessionEntry->vht_config.tx_antpattern; + + pDot11f->maxAMPDULenExp = + psessionEntry->vht_config.max_ampdu_lenexp; + + pDot11f->vhtLinkAdaptCap = + psessionEntry->vht_config.vht_link_adapt; + } else { + CFG_GET_INT(nStatus, pMac, WNI_CFG_VHT_LDPC_CODING_CAP, + nCfgValue); + pDot11f->ldpcCodingCap = (nCfgValue & 0x0001); + + nCfgValue = 0; + CFG_GET_INT(nStatus, pMac, WNI_CFG_VHT_SHORT_GI_80MHZ, + nCfgValue); + pDot11f->shortGI80MHz = (nCfgValue & 0x0001); + + nCfgValue = 0; + CFG_GET_INT(nStatus, pMac, + WNI_CFG_VHT_SHORT_GI_160_AND_80_PLUS_80MHZ, + nCfgValue); + pDot11f->shortGI160and80plus80MHz = (nCfgValue & 0x0001); + + nCfgValue = 0; + CFG_GET_INT(nStatus, pMac, WNI_CFG_VHT_TXSTBC, nCfgValue); + pDot11f->txSTBC = (nCfgValue & 0x0001); + + nCfgValue = 0; + CFG_GET_INT(nStatus, pMac, WNI_CFG_VHT_RXSTBC, nCfgValue); + pDot11f->rxSTBC = (nCfgValue & 0x0007); + + nCfgValue = 0; + CFG_GET_INT(nStatus, pMac, + WNI_CFG_VHT_SU_BEAMFORMEE_CAP, nCfgValue); + pDot11f->suBeamformeeCap = (nCfgValue & 0x0001); + + nCfgValue = 0; + CFG_GET_INT(nStatus, pMac, + WNI_CFG_VHT_MU_BEAMFORMEE_CAP, nCfgValue); + pDot11f->muBeamformeeCap = (nCfgValue & 0x0001); + + nCfgValue = 0; + CFG_GET_INT(nStatus, pMac, WNI_CFG_VHT_SU_BEAMFORMER_CAP, + nCfgValue); + pDot11f->suBeamFormerCap = (nCfgValue & 0x0001); + + nCfgValue = 0; + CFG_GET_INT(nStatus, pMac, + WNI_CFG_VHT_CSN_BEAMFORMEE_ANT_SUPPORTED, + nCfgValue); + pDot11f->csnofBeamformerAntSup = (nCfgValue & 0x0007); + + nCfgValue = 0; + CFG_GET_INT(nStatus, pMac, + WNI_CFG_VHT_TXOP_PS, + nCfgValue); + pDot11f->vhtTXOPPS = (nCfgValue & 0x0001); + + nCfgValue = 0; + CFG_GET_INT(nStatus, pMac, + WNI_CFG_VHT_NUM_SOUNDING_DIMENSIONS, + nCfgValue); + pDot11f->numSoundingDim = (nCfgValue & 0x0007); + + nCfgValue = 0; + CFG_GET_INT(nStatus, pMac, + WNI_CFG_VHT_HTC_VHTC_CAP, + nCfgValue); + pDot11f->htcVHTCap = (nCfgValue & 0x0001); + + nCfgValue = 0; + CFG_GET_INT(nStatus, pMac, + WNI_CFG_VHT_RX_ANT_PATTERN, + nCfgValue); + pDot11f->rxAntPattern = nCfgValue; + + nCfgValue = 0; + CFG_GET_INT(nStatus, pMac, + WNI_CFG_VHT_TX_ANT_PATTERN, + nCfgValue); + pDot11f->txAntPattern = nCfgValue; + + nCfgValue = 0; + CFG_GET_INT(nStatus, pMac, + WNI_CFG_VHT_AMPDU_LEN_EXPONENT, + nCfgValue); + pDot11f->maxAMPDULenExp = (nCfgValue & 0x0007); + + nCfgValue = 0; + CFG_GET_INT(nStatus, pMac, + WNI_CFG_VHT_LINK_ADAPTATION_CAP, + nCfgValue); + pDot11f->vhtLinkAdaptCap = (nCfgValue & 0x0003); + + } + + nCfgValue = 0; + CFG_GET_INT(nStatus, pMac, WNI_CFG_VHT_MU_BEAMFORMER_CAP, nCfgValue); + pDot11f->muBeamformerCap = (nCfgValue & 0x0001); + + pDot11f->reserved1 = 0; + + nCfgValue = 0; + CFG_GET_INT(nStatus, pMac, WNI_CFG_VHT_RX_MCS_MAP, nCfgValue); + pDot11f->rxMCSMap = (nCfgValue & 0x0000FFFF); + + nCfgValue = 0; + CFG_GET_INT(nStatus, pMac, WNI_CFG_VHT_RX_HIGHEST_SUPPORTED_DATA_RATE, + nCfgValue); + pDot11f->rxHighSupDataRate = (nCfgValue & 0x00001FFF); + + pDot11f->reserved2 = 0; + + nCfgValue = 0; + CFG_GET_INT(nStatus, pMac, WNI_CFG_VHT_TX_MCS_MAP, nCfgValue); + pDot11f->txMCSMap = (nCfgValue & 0x0000FFFF); + + nCfgValue = 0; + CFG_GET_INT(nStatus, pMac, WNI_CFG_VHT_TX_HIGHEST_SUPPORTED_DATA_RATE, + nCfgValue); + pDot11f->txSupDataRate = (nCfgValue & 0x00001FFF); + + pDot11f->reserved3 = 0; + if (psessionEntry) { + if (pMac->lteCoexAntShare + && (IS_24G_CH(psessionEntry->currentOperChannel))) { + if (!(IS_2X2_CHAIN(psessionEntry->chainMask))) { + pDot11f->txMCSMap |= DISABLE_NSS2_MCS; + pDot11f->rxMCSMap |= DISABLE_NSS2_MCS; + } + } + if (psessionEntry->nss == NSS_1x1_MODE) { + pDot11f->txMCSMap |= DISABLE_NSS2_MCS; + pDot11f->rxMCSMap |= DISABLE_NSS2_MCS; + pDot11f->txSupDataRate = + VHT_TX_HIGHEST_SUPPORTED_DATA_RATE_1_1; + pDot11f->rxHighSupDataRate = + VHT_RX_HIGHEST_SUPPORTED_DATA_RATE_1_1; + } + } + lim_log_vht_cap(pMac, pDot11f); + return eSIR_SUCCESS; +} + +tSirRetStatus +populate_dot11f_vht_operation(tpAniSirGlobal pMac, + tpPESession psessionEntry, + tDot11fIEVHTOperation *pDot11f) +{ + tSirRetStatus nStatus; + uint32_t nCfgValue = 0; + + pDot11f->present = 1; + + if (psessionEntry->ch_width > CH_WIDTH_40MHZ) { + pDot11f->chanWidth = 1; + pDot11f->chanCenterFreqSeg1 = + psessionEntry->ch_center_freq_seg0; + if (psessionEntry->ch_width == CH_WIDTH_80P80MHZ || + psessionEntry->ch_width == CH_WIDTH_160MHZ) + pDot11f->chanCenterFreqSeg2 = + psessionEntry->ch_center_freq_seg1; + else + pDot11f->chanCenterFreqSeg2 = 0; + } else { + pDot11f->chanWidth = 0; + pDot11f->chanCenterFreqSeg1 = 0; + pDot11f->chanCenterFreqSeg2 = 0; + } + + nCfgValue = 0; + CFG_GET_INT(nStatus, pMac, WNI_CFG_VHT_BASIC_MCS_SET, nCfgValue); + pDot11f->basicMCSSet = (uint16_t) nCfgValue; + + lim_log_vht_operation(pMac, pDot11f); + + return eSIR_SUCCESS; + +} + +tSirRetStatus +populate_dot11f_vht_ext_bss_load(tpAniSirGlobal pMac, + tDot11fIEVHTExtBssLoad *pDot11f) +{ + tSirRetStatus nStatus; + uint32_t nCfgValue = 0; + + pDot11f->present = 1; + + CFG_GET_INT(nStatus, pMac, WNI_CFG_VHT_MU_MIMO_CAP_STA_COUNT, + nCfgValue); + pDot11f->muMIMOCapStaCount = (uint8_t) nCfgValue; + + nCfgValue = 0; + CFG_GET_INT(nStatus, pMac, WNI_CFG_VHT_SS_UNDER_UTIL, nCfgValue); + pDot11f->ssUnderUtil = (uint8_t) nCfgValue; + + nCfgValue = 0; + CFG_GET_INT(nStatus, pMac, WNI_CFG_VHT_40MHZ_UTILIZATION, nCfgValue); + pDot11f->FortyMHzUtil = (uint8_t) nCfgValue; + + nCfgValue = 0; + CFG_GET_INT(nStatus, pMac, WNI_CFG_VHT_80MHZ_UTILIZATION, nCfgValue); + pDot11f->EightyMHzUtil = (uint8_t) nCfgValue; + + nCfgValue = 0; + CFG_GET_INT(nStatus, pMac, WNI_CFG_VHT_160MHZ_UTILIZATION, nCfgValue); + pDot11f->EightyMHzUtil = (uint8_t) nCfgValue; + + lim_log_vht_ext_bss_load(pMac, pDot11f); + + return eSIR_SUCCESS; +} + +tSirRetStatus +populate_dot11f_ext_cap(tpAniSirGlobal pMac, + bool isVHTEnabled, tDot11fIEExtCap *pDot11f, + tpPESession psessionEntry) +{ + uint32_t val = 0; + struct s_ext_cap *p_ext_cap; + + pDot11f->present = 1; + + if (!psessionEntry) { + lim_log(pMac, LOG1, FL("11MC - enabled for non-SAP cases")); + pDot11f->num_bytes = DOT11F_IE_EXTCAP_MAX_LEN; + } else if (psessionEntry->sap_dot11mc) { + lim_log(pMac, LOG1, FL("11MC support enabled")); + pDot11f->num_bytes = DOT11F_IE_EXTCAP_MAX_LEN; + } else { + if (eLIM_AP_ROLE != psessionEntry->limSystemRole) { + lim_log(pMac, LOG1, FL("11MC support enabled")); + pDot11f->num_bytes = DOT11F_IE_EXTCAP_MAX_LEN; + } else { + lim_log(pMac, LOG1, FL("11MC support disabled")); + pDot11f->num_bytes = DOT11F_IE_EXTCAP_MIN_LEN; + } + } + + p_ext_cap = (struct s_ext_cap *)pDot11f->bytes; + if (isVHTEnabled == true) + p_ext_cap->oper_mode_notification = 1; + + if (wlan_cfg_get_int(pMac, WNI_CFG_RTT3_ENABLE, &val) != eSIR_SUCCESS) { + lim_log(pMac, LOGE, + FL("could not retrieve RTT3 Variable from DAT File")); + return eSIR_FAILURE; + } + + if (val) { + if (!psessionEntry || LIM_IS_STA_ROLE(psessionEntry)) { + p_ext_cap->fine_time_meas_initiator = + (pMac->fine_time_meas_cap & + WMI_FW_STA_RTT_INITR) ? 1 : 0; + p_ext_cap->fine_time_meas_responder = + (pMac->fine_time_meas_cap & + WMI_FW_STA_RTT_RESPR) ? 1 : 0; + } else if (LIM_IS_AP_ROLE(psessionEntry)) { + p_ext_cap->fine_time_meas_initiator = + (pMac->fine_time_meas_cap & + WMI_FW_AP_RTT_INITR) ? 1 : 0; + p_ext_cap->fine_time_meas_responder = + (pMac->fine_time_meas_cap & + WMI_FW_AP_RTT_RESPR) ? 1 : 0; + } + } +#ifdef QCA_HT_2040_COEX + if (pMac->roam.configParam.obssEnabled) + p_ext_cap->bss_coexist_mgmt_support = 1; +#endif + p_ext_cap->ext_chan_switch = 1; + + if (psessionEntry && psessionEntry->enable_bcast_probe_rsp) + p_ext_cap->fils_capability = 1; + + /* Need to calulate the num_bytes based on bits set */ + if (pDot11f->present) + pDot11f->num_bytes = lim_compute_ext_cap_ie_length(pDot11f); + + return eSIR_SUCCESS; +} + +void populate_dot11f_qcn_ie(tDot11fIEQCN_IE *pDot11f) +{ + pDot11f->present = 1; + pDot11f->version[0] = QCN_IE_VERSION_SUBATTR_ID; + pDot11f->version[1] = QCN_IE_VERSION_SUBATTR_DATA_LEN; + pDot11f->version[2] = QCN_IE_VERSION_SUPPORTED; + pDot11f->version[3] = QCN_IE_SUBVERSION_SUPPORTED; +} + +tSirRetStatus +populate_dot11f_operating_mode(tpAniSirGlobal pMac, + tDot11fIEOperatingMode *pDot11f, + tpPESession psessionEntry) +{ + pDot11f->present = 1; + + pDot11f->chanWidth = psessionEntry->gLimOperatingMode.chanWidth; + pDot11f->rxNSS = psessionEntry->gLimOperatingMode.rxNSS; + pDot11f->rxNSSType = psessionEntry->gLimOperatingMode.rxNSSType; + + return eSIR_SUCCESS; +} + +tSirRetStatus +populate_dot11f_ht_info(tpAniSirGlobal pMac, + tDot11fIEHTInfo *pDot11f, tpPESession psessionEntry) +{ + uint32_t nCfgValue, nCfgLen; + uint8_t htInfoField1; + uint16_t htInfoField2; + tSirRetStatus nSirStatus; + tSirMacHTInfoField1 *pHTInfoField1; + tSirMacHTInfoField2 *pHTInfoField2; + union { + uint16_t nCfgValue16; + tSirMacHTInfoField3 infoField3; + } uHTInfoField; + union { + uint16_t nCfgValue16; + tSirMacHTInfoField2 infoField2; + } uHTInfoField2 = { + 0 + }; + +#if 0 + CFG_GET_INT(nSirStatus, pMac, WNI_CFG_CURRENT_CHANNEL, nCfgValue); +#endif /* TO SUPPORT BT-AMP */ + + if (NULL == psessionEntry) { + lim_log(pMac, LOG1, + FL("Invalid session entry in populate_dot11f_ht_info()")); + return eSIR_FAILURE; + } + + pDot11f->primaryChannel = psessionEntry->currentOperChannel; + + CFG_GET_INT(nSirStatus, pMac, WNI_CFG_HT_INFO_FIELD1, nCfgValue); + + htInfoField1 = (uint8_t) nCfgValue; + + pHTInfoField1 = (tSirMacHTInfoField1 *) &htInfoField1; + pHTInfoField1->rifsMode = psessionEntry->beaconParams.fRIFSMode; + pHTInfoField1->serviceIntervalGranularity = + pMac->lim.gHTServiceIntervalGranularity; + + if (psessionEntry == NULL) { + lim_log(pMac, LOG1, + FL("Keep the value retrieved from cfg for secondary channel offset and recommended Tx Width set")); + } else { + pHTInfoField1->secondaryChannelOffset = + psessionEntry->htSecondaryChannelOffset; + pHTInfoField1->recommendedTxWidthSet = + psessionEntry->htRecommendedTxWidthSet; + } + + if ((psessionEntry) && LIM_IS_AP_ROLE(psessionEntry)) { + CFG_GET_INT(nSirStatus, pMac, WNI_CFG_HT_INFO_FIELD2, + nCfgValue); + + uHTInfoField2.nCfgValue16 = nCfgValue & 0xFFFF; /* this is added for fixing CRs on MDM9K platform - 257951, 259577 */ + + uHTInfoField2.infoField2.opMode = psessionEntry->htOperMode; + uHTInfoField2.infoField2.nonGFDevicesPresent = + psessionEntry->beaconParams.llnNonGFCoexist; + uHTInfoField2.infoField2.obssNonHTStaPresent = psessionEntry->beaconParams.gHTObssMode; /*added for Obss */ + + uHTInfoField2.infoField2.reserved = 0; + + } else { + CFG_GET_INT(nSirStatus, pMac, WNI_CFG_HT_INFO_FIELD2, + nCfgValue); + + htInfoField2 = (uint16_t) nCfgValue; + + pHTInfoField2 = (tSirMacHTInfoField2 *) &htInfoField2; + pHTInfoField2->opMode = pMac->lim.gHTOperMode; + pHTInfoField2->nonGFDevicesPresent = + pMac->lim.gHTNonGFDevicesPresent; + pHTInfoField2->obssNonHTStaPresent = pMac->lim.gHTObssMode; /*added for Obss */ + + pHTInfoField2->reserved = 0; + } + + CFG_GET_INT(nSirStatus, pMac, WNI_CFG_HT_INFO_FIELD3, nCfgValue); + + uHTInfoField.nCfgValue16 = nCfgValue & 0xFFFF; + + uHTInfoField.infoField3.basicSTBCMCS = pMac->lim.gHTSTBCBasicMCS; + uHTInfoField.infoField3.dualCTSProtection = + pMac->lim.gHTDualCTSProtection; + uHTInfoField.infoField3.secondaryBeacon = pMac->lim.gHTSecondaryBeacon; + uHTInfoField.infoField3.lsigTXOPProtectionFullSupport = + psessionEntry->beaconParams.fLsigTXOPProtectionFullSupport; + uHTInfoField.infoField3.pcoActive = pMac->lim.gHTPCOActive; + uHTInfoField.infoField3.pcoPhase = pMac->lim.gHTPCOPhase; + uHTInfoField.infoField3.reserved = 0; + + pDot11f->secondaryChannelOffset = pHTInfoField1->secondaryChannelOffset; + pDot11f->recommendedTxWidthSet = pHTInfoField1->recommendedTxWidthSet; + pDot11f->rifsMode = pHTInfoField1->rifsMode; + pDot11f->controlledAccessOnly = pHTInfoField1->controlledAccessOnly; + pDot11f->serviceIntervalGranularity = + pHTInfoField1->serviceIntervalGranularity; + + pDot11f->opMode = uHTInfoField2.infoField2.opMode; + pDot11f->nonGFDevicesPresent = + uHTInfoField2.infoField2.nonGFDevicesPresent; + pDot11f->obssNonHTStaPresent = + uHTInfoField2.infoField2.obssNonHTStaPresent; + pDot11f->reserved = uHTInfoField2.infoField2.reserved; + + pDot11f->basicSTBCMCS = uHTInfoField.infoField3.basicSTBCMCS; + pDot11f->dualCTSProtection = uHTInfoField.infoField3.dualCTSProtection; + pDot11f->secondaryBeacon = uHTInfoField.infoField3.secondaryBeacon; + pDot11f->lsigTXOPProtectionFullSupport = + uHTInfoField.infoField3.lsigTXOPProtectionFullSupport; + pDot11f->pcoActive = uHTInfoField.infoField3.pcoActive; + pDot11f->pcoPhase = uHTInfoField.infoField3.pcoPhase; + pDot11f->reserved2 = uHTInfoField.infoField3.reserved; + CFG_GET_STR(nSirStatus, pMac, WNI_CFG_BASIC_MCS_SET, + pDot11f->basicMCSSet, nCfgLen, SIZE_OF_BASIC_MCS_SET); + + pDot11f->present = 1; + + return eSIR_SUCCESS; + +} /* End populate_dot11f_ht_info. */ + +void +populate_dot11f_ibss_params(tpAniSirGlobal pMac, + tDot11fIEIBSSParams *pDot11f, + tpPESession psessionEntry) +{ + uint32_t val = 0; + if (LIM_IS_IBSS_ROLE(psessionEntry)) { + if (wlan_cfg_get_int(pMac, + WNI_CFG_IBSS_ATIM_WIN_SIZE, + &val) != eSIR_SUCCESS) { + PELOGE(lim_log + (pMac, LOGE, + FL("could not retrieve IBSS ATIM WIN size")); + ) + } + pDot11f->present = 1; + /* ATIM duration is always set to 0 */ + pDot11f->atim = val; + } + +} /* End populate_dot11f_ibss_params. */ + +#ifdef ANI_SUPPORT_11H +tSirRetStatus +populate_dot11f_measurement_report0(tpAniSirGlobal pMac, + tpSirMacMeasReqActionFrame pReq, + tDot11fIEMeasurementReport *pDot11f) +{ + pDot11f->token = pReq->measReqIE.measToken; + pDot11f->late = 0; + pDot11f->incapable = 0; + pDot11f->refused = 1; + pDot11f->type = SIR_MAC_BASIC_MEASUREMENT_TYPE; + + pDot11f->present = 1; + + return eSIR_SUCCESS; + +} /* End PopulatedDot11fMeasurementReport0. */ +tSirRetStatus +populate_dot11f_measurement_report1(tpAniSirGlobal pMac, + tpSirMacMeasReqActionFrame pReq, + tDot11fIEMeasurementReport *pDot11f) +{ + pDot11f->token = pReq->measReqIE.measToken; + pDot11f->late = 0; + pDot11f->incapable = 0; + pDot11f->refused = 1; + pDot11f->type = SIR_MAC_CCA_MEASUREMENT_TYPE; + pDot11f->present = 1; + return eSIR_SUCCESS; +} /* End PopulatedDot11fMeasurementReport1. */ +tSirRetStatus +populate_dot11f_measurement_report2(tpAniSirGlobal pMac, + tpSirMacMeasReqActionFrame pReq, + tDot11fIEMeasurementReport *pDot11f) +{ + pDot11f->token = pReq->measReqIE.measToken; + pDot11f->late = 0; + pDot11f->incapable = 0; + pDot11f->refused = 1; + pDot11f->type = SIR_MAC_RPI_MEASUREMENT_TYPE; + pDot11f->present = 1; + return eSIR_SUCCESS; +} /* End PopulatedDot11fMeasurementReport2. */ +#endif + +void +populate_dot11f_power_caps(tpAniSirGlobal pMac, + tDot11fIEPowerCaps *pCaps, + uint8_t nAssocType, tpPESession psessionEntry) +{ + if (nAssocType == LIM_REASSOC) { + pCaps->minTxPower = + psessionEntry->pLimReAssocReq->powerCap.minTxPower; + pCaps->maxTxPower = + psessionEntry->pLimReAssocReq->powerCap.maxTxPower; + } else { + pCaps->minTxPower = + psessionEntry->pLimJoinReq->powerCap.minTxPower; + pCaps->maxTxPower = + psessionEntry->pLimJoinReq->powerCap.maxTxPower; + + } + + pCaps->present = 1; +} /* End populate_dot11f_power_caps. */ + +tSirRetStatus +populate_dot11f_power_constraints(tpAniSirGlobal pMac, + tDot11fIEPowerConstraints *pDot11f) +{ + uint32_t cfg; + tSirRetStatus nSirStatus; + + CFG_GET_INT(nSirStatus, pMac, WNI_CFG_LOCAL_POWER_CONSTRAINT, cfg); + + pDot11f->localPowerConstraints = (uint8_t) cfg; + pDot11f->present = 1; + + return eSIR_SUCCESS; +} /* End populate_dot11f_power_constraints. */ + +void +populate_dot11f_qos_caps_ap(tpAniSirGlobal pMac, + tDot11fIEQOSCapsAp *pDot11f, tpPESession psessionEntry) +{ + pDot11f->count = psessionEntry->gLimEdcaParamSetCount; + pDot11f->reserved = 0; + pDot11f->txopreq = 0; + pDot11f->qreq = 0; + pDot11f->qack = 0; + pDot11f->present = 1; +} /* End PopulatedDot11fQOSCaps. */ + +void +populate_dot11f_qos_caps_station(tpAniSirGlobal pMac, tpPESession pe_session, + tDot11fIEQOSCapsStation *pDot11f) +{ + uint32_t val = 0; + + if (wlan_cfg_get_int(pMac, WNI_CFG_MAX_SP_LENGTH, &val) != eSIR_SUCCESS) + lim_log(pMac, LOGE, + FL("could not retrieve Max SP Length")); + + pDot11f->more_data_ack = 0; + pDot11f->max_sp_length = (uint8_t) val; + pDot11f->qack = 0; + + if (pMac->lim.gUapsdEnable) { + pDot11f->acbe_uapsd = + LIM_UAPSD_GET(ACBE, pe_session->gUapsdPerAcBitmask); + pDot11f->acbk_uapsd = + LIM_UAPSD_GET(ACBK, pe_session->gUapsdPerAcBitmask); + pDot11f->acvi_uapsd = + LIM_UAPSD_GET(ACVI, pe_session->gUapsdPerAcBitmask); + pDot11f->acvo_uapsd = + LIM_UAPSD_GET(ACVO, pe_session->gUapsdPerAcBitmask); + } + pDot11f->present = 1; +} /* End PopulatedDot11fQOSCaps. */ + +tSirRetStatus +populate_dot11f_rsn(tpAniSirGlobal pMac, + tpSirRSNie pRsnIe, tDot11fIERSN *pDot11f) +{ + uint32_t status; + int idx; + + if (pRsnIe->length) { + idx = find_ie_location(pMac, pRsnIe, DOT11F_EID_RSN); + if (0 <= idx) { + status = dot11f_unpack_ie_rsn(pMac, pRsnIe->rsnIEdata + idx + 2, /* EID, length */ + pRsnIe->rsnIEdata[idx + 1], + pDot11f); + if (DOT11F_FAILED(status)) { + dot11f_log(pMac, LOGE, + FL("Parse failure in Populate Dot11fRSN (0x%08x)."), + status); + return eSIR_FAILURE; + } + dot11f_log(pMac, LOG2, + FL("dot11f_unpack_ie_rsn returned 0x%08x in populate_dot11f_rsn."), + status); + } + + } + + return eSIR_SUCCESS; +} /* End populate_dot11f_rsn. */ + +tSirRetStatus populate_dot11f_rsn_opaque(tpAniSirGlobal pMac, + tpSirRSNie pRsnIe, + tDot11fIERSNOpaque *pDot11f) +{ + int idx; + + if (pRsnIe->length) { + idx = find_ie_location(pMac, pRsnIe, DOT11F_EID_RSN); + if (0 <= idx) { + pDot11f->present = 1; + pDot11f->num_data = pRsnIe->rsnIEdata[idx + 1]; + qdf_mem_copy(pDot11f->data, pRsnIe->rsnIEdata + idx + 2, /* EID, len */ + pRsnIe->rsnIEdata[idx + 1]); + } + } + + return eSIR_SUCCESS; + +} /* End populate_dot11f_rsn_opaque. */ + +#if defined(FEATURE_WLAN_WAPI) + +tSirRetStatus +populate_dot11f_wapi(tpAniSirGlobal pMac, + tpSirRSNie pRsnIe, tDot11fIEWAPI *pDot11f) +{ + uint32_t status; + int idx; + + if (pRsnIe->length) { + idx = find_ie_location(pMac, pRsnIe, DOT11F_EID_WAPI); + if (0 <= idx) { + status = dot11f_unpack_ie_wapi(pMac, pRsnIe->rsnIEdata + idx + 2, /* EID, length */ + pRsnIe->rsnIEdata[idx + 1], + pDot11f); + if (DOT11F_FAILED(status)) { + dot11f_log(pMac, LOGE, + FL("Parse failure in populate_dot11f_wapi (0x%08x)."), + status); + return eSIR_FAILURE; + } + dot11f_log(pMac, LOG2, + FL("dot11f_unpack_ie_rsn returned 0x%08x in populate_dot11f_wapi."), + status); + } + } + + return eSIR_SUCCESS; +} /* End populate_dot11f_wapi. */ + +tSirRetStatus populate_dot11f_wapi_opaque(tpAniSirGlobal pMac, + tpSirRSNie pRsnIe, + tDot11fIEWAPIOpaque *pDot11f) +{ + int idx; + + if (pRsnIe->length) { + idx = find_ie_location(pMac, pRsnIe, DOT11F_EID_WAPI); + if (0 <= idx) { + pDot11f->present = 1; + pDot11f->num_data = pRsnIe->rsnIEdata[idx + 1]; + qdf_mem_copy(pDot11f->data, pRsnIe->rsnIEdata + idx + 2, /* EID, len */ + pRsnIe->rsnIEdata[idx + 1]); + } + } + + return eSIR_SUCCESS; + +} /* End populate_dot11f_wapi_opaque. */ + +#endif /* defined(FEATURE_WLAN_WAPI) */ + +void +populate_dot11f_ssid(tpAniSirGlobal pMac, + tSirMacSSid *pInternal, tDot11fIESSID *pDot11f) +{ + pDot11f->present = 1; + pDot11f->num_ssid = pInternal->length; + if (pInternal->length) { + qdf_mem_copy((uint8_t *) pDot11f->ssid, + (uint8_t *) &pInternal->ssId, pInternal->length); + } +} /* End populate_dot11f_ssid. */ + +tSirRetStatus populate_dot11f_ssid2(tpAniSirGlobal pMac, tDot11fIESSID *pDot11f) +{ + uint32_t nCfg; + tSirRetStatus nSirStatus; + + CFG_GET_STR(nSirStatus, pMac, WNI_CFG_SSID, pDot11f->ssid, nCfg, 32); + pDot11f->num_ssid = (uint8_t) nCfg; + pDot11f->present = 1; + return eSIR_SUCCESS; +} /* End populate_dot11f_ssid2. */ + +void +populate_dot11f_schedule(tSirMacScheduleIE *pSchedule, + tDot11fIESchedule *pDot11f) +{ + pDot11f->aggregation = pSchedule->info.aggregation; + pDot11f->tsid = pSchedule->info.tsid; + pDot11f->direction = pSchedule->info.direction; + pDot11f->reserved = pSchedule->info.rsvd; + pDot11f->service_start_time = pSchedule->svcStartTime; + pDot11f->service_interval = pSchedule->svcInterval; + pDot11f->max_service_dur = pSchedule->maxSvcDuration; + pDot11f->spec_interval = pSchedule->specInterval; + + pDot11f->present = 1; +} /* End populate_dot11f_schedule. */ + +void +populate_dot11f_supp_channels(tpAniSirGlobal pMac, + tDot11fIESuppChannels *pDot11f, + uint8_t nAssocType, tpPESession psessionEntry) +{ + uint8_t i; + uint8_t *p; + + if (nAssocType == LIM_REASSOC) { + p = (uint8_t *) psessionEntry->pLimReAssocReq-> + supportedChannels.channelList; + pDot11f->num_bands = + psessionEntry->pLimReAssocReq->supportedChannels.numChnl; + } else { + p = (uint8_t *) psessionEntry->pLimJoinReq->supportedChannels. + channelList; + pDot11f->num_bands = + psessionEntry->pLimJoinReq->supportedChannels.numChnl; + } + for (i = 0U; i < pDot11f->num_bands; ++i, ++p) { + pDot11f->bands[i][0] = *p; + pDot11f->bands[i][1] = 1; + } + + pDot11f->present = 1; + +} /* End populate_dot11f_supp_channels. */ + +tSirRetStatus +populate_dot11f_supp_rates(tpAniSirGlobal pMac, + uint8_t nChannelNum, + tDot11fIESuppRates *pDot11f, tpPESession psessionEntry) +{ + tSirRetStatus nSirStatus; + uint32_t nRates; + uint8_t rates[SIR_MAC_MAX_NUMBER_OF_RATES]; + + /* Use the operational rates present in session entry whenever nChannelNum is set to OPERATIONAL + else use the supported rate set from CFG, which is fixed and does not change dynamically and is used for + sending mgmt frames (lile probe req) which need to go out before any session is present. + */ + if (POPULATE_DOT11F_RATES_OPERATIONAL == nChannelNum) { +#if 0 + CFG_GET_STR(nSirStatus, pMac, WNI_CFG_OPERATIONAL_RATE_SET, + rates, nRates, SIR_MAC_MAX_NUMBER_OF_RATES); +#endif /* TO SUPPORT BT-AMP */ + if (psessionEntry != NULL) { + nRates = psessionEntry->rateSet.numRates; + qdf_mem_copy(rates, psessionEntry->rateSet.rate, + nRates); + } else { + dot11f_log(pMac, LOGE, + FL("no session context exists while populating Operational Rate Set")); + nRates = 0; + } + } else if (14 >= nChannelNum) { + CFG_GET_STR(nSirStatus, pMac, WNI_CFG_SUPPORTED_RATES_11B, + rates, nRates, SIR_MAC_MAX_NUMBER_OF_RATES); + } else { + CFG_GET_STR(nSirStatus, pMac, WNI_CFG_SUPPORTED_RATES_11A, + rates, nRates, SIR_MAC_MAX_NUMBER_OF_RATES); + } + + if (0 != nRates) { + pDot11f->num_rates = (uint8_t) nRates; + qdf_mem_copy(pDot11f->rates, rates, nRates); + pDot11f->present = 1; + } + + return eSIR_SUCCESS; + +} /* End populate_dot11f_supp_rates. */ + +/** + * populate_dot11f_rates_tdls() - populate supported rates and + * extended supported rates IE. + * @p_mac gloabl - header. + * @p_supp_rates - pointer to supported rates IE + * @p_ext_supp_rates - pointer to extended supported rates IE + * @curr_oper_channel - current operating channel + * + * This function populates the supported rates and extended supported + * rates IE based in the STA capability. If the number of rates + * supported is less than MAX_NUM_SUPPORTED_RATES, only supported rates + * IE is populated. + * + * Return: tSirRetStatus eSIR_SUCCESS on Success and eSIR_FAILURE + * on failure. + */ + +tSirRetStatus +populate_dot11f_rates_tdls(tpAniSirGlobal p_mac, + tDot11fIESuppRates *p_supp_rates, + tDot11fIEExtSuppRates *p_ext_supp_rates, + uint8_t curr_oper_channel) +{ + tSirMacRateSet temp_rateset; + tSirMacRateSet temp_rateset2; + uint32_t val, i; + uint32_t self_dot11mode = 0; + + wlan_cfg_get_int(p_mac, WNI_CFG_DOT11_MODE, &self_dot11mode); + + /** + * Include 11b rates only when the device configured in + * auto, 11a/b/g or 11b_only and also if current base + * channel is 5 GHz then no need to advertise the 11b rates. + * If devices move to 2.4GHz off-channel then they can communicate + * in 11g rates i.e. (6, 9, 12, 18, 24, 36 and 54). + */ + lim_log(p_mac, LOG1, + FL("Current operating channel %d self_dot11mode = %d"), + curr_oper_channel, self_dot11mode); + + if ((curr_oper_channel <= SIR_11B_CHANNEL_END) && + ((self_dot11mode == WNI_CFG_DOT11_MODE_ALL) || + (self_dot11mode == WNI_CFG_DOT11_MODE_11A) || + (self_dot11mode == WNI_CFG_DOT11_MODE_11AC) || + (self_dot11mode == WNI_CFG_DOT11_MODE_11N) || + (self_dot11mode == WNI_CFG_DOT11_MODE_11G) || + (self_dot11mode == WNI_CFG_DOT11_MODE_11B))) { + val = WNI_CFG_SUPPORTED_RATES_11B_LEN; + wlan_cfg_get_str(p_mac, WNI_CFG_SUPPORTED_RATES_11B, + (uint8_t *)&temp_rateset.rate, &val); + temp_rateset.numRates = (uint8_t) val; + } else { + temp_rateset.numRates = 0; + } + + /* Include 11a rates when the device configured in non-11b mode */ + if (!IS_DOT11_MODE_11B(self_dot11mode)) { + val = WNI_CFG_SUPPORTED_RATES_11A_LEN; + wlan_cfg_get_str(p_mac, WNI_CFG_SUPPORTED_RATES_11A, + (uint8_t *)&temp_rateset2.rate, &val); + temp_rateset2.numRates = (uint8_t) val; + } else { + temp_rateset2.numRates = 0; + } + + if ((temp_rateset.numRates + temp_rateset2.numRates) > + SIR_MAC_MAX_NUMBER_OF_RATES) { + lim_log(p_mac, LOGP, FL("more than %d rates in CFG"), + SIR_MAC_MAX_NUMBER_OF_RATES); + return eSIR_FAILURE; + } + + /** + * copy all rates in temp_rateset, + * there are SIR_MAC_MAX_NUMBER_OF_RATES rates max + */ + for (i = 0; i < temp_rateset2.numRates; i++) + temp_rateset.rate[i + temp_rateset.numRates] = + temp_rateset2.rate[i]; + + temp_rateset.numRates += temp_rateset2.numRates; + + if (temp_rateset.numRates <= MAX_NUM_SUPPORTED_RATES) { + p_supp_rates->num_rates = temp_rateset.numRates; + qdf_mem_copy(p_supp_rates->rates, temp_rateset.rate, + p_supp_rates->num_rates); + p_supp_rates->present = 1; + } else { /* Populate extended capability as well */ + p_supp_rates->num_rates = MAX_NUM_SUPPORTED_RATES; + qdf_mem_copy(p_supp_rates->rates, temp_rateset.rate, + p_supp_rates->num_rates); + p_supp_rates->present = 1; + + p_ext_supp_rates->num_rates = temp_rateset.numRates - + MAX_NUM_SUPPORTED_RATES; + qdf_mem_copy(p_ext_supp_rates->rates, + (uint8_t *)temp_rateset.rate + + MAX_NUM_SUPPORTED_RATES, + p_ext_supp_rates->num_rates); + p_ext_supp_rates->present = 1; + } + + return eSIR_SUCCESS; + +} /* End populate_dot11f_rates_tdls */ + + +tSirRetStatus +populate_dot11f_tpc_report(tpAniSirGlobal pMac, + tDot11fIETPCReport *pDot11f, tpPESession psessionEntry) +{ + uint16_t staid, txPower; + tSirRetStatus nSirStatus; + + nSirStatus = lim_get_mgmt_staid(pMac, &staid, psessionEntry); + if (eSIR_SUCCESS != nSirStatus) { + dot11f_log(pMac, LOG1, + FL("Failed to get the STAID in Populate Dot11fTPCReport; lim_get_mgmt_staid returned status %d."), + nSirStatus); + return eSIR_FAILURE; + } + /* FramesToDo: This function was "misplaced" in the move to Gen4_TVM... */ + /* txPower = halGetRateToPwrValue( pMac, staid, pMac->lim.gLimCurrentChannelId, isBeacon ); */ + txPower = 0; + pDot11f->tx_power = (uint8_t) txPower; + pDot11f->link_margin = 0; + pDot11f->present = 1; + + return eSIR_SUCCESS; +} /* End populate_dot11f_tpc_report. */ + +void populate_dot11f_ts_info(tSirMacTSInfo *pInfo, tDot11fFfTSInfo *pDot11f) +{ + pDot11f->traffic_type = pInfo->traffic.trafficType; + pDot11f->tsid = pInfo->traffic.tsid; + pDot11f->direction = pInfo->traffic.direction; + pDot11f->access_policy = pInfo->traffic.accessPolicy; + pDot11f->aggregation = pInfo->traffic.aggregation; + pDot11f->psb = pInfo->traffic.psb; + pDot11f->user_priority = pInfo->traffic.userPrio; + pDot11f->tsinfo_ack_pol = pInfo->traffic.ackPolicy; + pDot11f->schedule = pInfo->schedule.schedule; +} /* End PopulatedDot11fTSInfo. */ + +void populate_dot11f_wmm(tpAniSirGlobal pMac, + tDot11fIEWMMInfoAp *pInfo, + tDot11fIEWMMParams *pParams, + tDot11fIEWMMCaps *pCaps, tpPESession psessionEntry) +{ + if (psessionEntry->limWmeEnabled) { + if (LIM_IS_IBSS_ROLE(psessionEntry)) { + /* if ( ! sirIsPropCapabilityEnabled( pMac, SIR_MAC_PROP_CAPABILITY_WME ) ) */ + { + populate_dot11f_wmm_info_ap(pMac, pInfo, + psessionEntry); + } + } else { + { + populate_dot11f_wmm_params(pMac, pParams, + psessionEntry); + } + + if (psessionEntry->limWsmEnabled) { + populate_dot11f_wmm_caps(pCaps); + } + } + } +} /* End populate_dot11f_wmm. */ + +void populate_dot11f_wmm_caps(tDot11fIEWMMCaps *pCaps) +{ + pCaps->version = SIR_MAC_OUI_VERSION_1; + pCaps->qack = 0; + pCaps->queue_request = 1; + pCaps->txop_request = 0; + pCaps->more_ack = 0; + pCaps->present = 1; +} /* End PopulateDot11fWmmCaps. */ + +#ifdef FEATURE_WLAN_ESE +void populate_dot11f_re_assoc_tspec(tpAniSirGlobal pMac, + tDot11fReAssocRequest *pReassoc, + tpPESession psessionEntry) +{ + uint8_t numTspecs = 0, idx; + tTspecInfo *pTspec = NULL; + + numTspecs = psessionEntry->pLimReAssocReq->eseTspecInfo.numTspecs; + pTspec = &psessionEntry->pLimReAssocReq->eseTspecInfo.tspec[0]; + pReassoc->num_WMMTSPEC = numTspecs; + if (numTspecs) { + for (idx = 0; idx < numTspecs; idx++) { + populate_dot11f_wmmtspec(&pTspec->tspec, + &pReassoc->WMMTSPEC[idx]); + pTspec->tspec.mediumTime = 0; + pTspec++; + } + } +} + +void ese_populate_wmm_tspec(tSirMacTspecIE *source, + ese_wmm_tspec_ie *dest) +{ + dest->traffic_type = source->tsinfo.traffic.trafficType; + dest->tsid = source->tsinfo.traffic.tsid; + dest->direction = source->tsinfo.traffic.direction; + dest->access_policy = source->tsinfo.traffic.accessPolicy; + dest->aggregation = source->tsinfo.traffic.aggregation; + dest->psb = source->tsinfo.traffic.psb; + dest->user_priority = source->tsinfo.traffic.userPrio; + dest->tsinfo_ack_pol = source->tsinfo.traffic.ackPolicy; + dest->burst_size_defn = source->tsinfo.traffic.burstSizeDefn; + /* As defined in IEEE 802.11-2007, section 7.3.2.30 + * Nominal MSDU size: Bit[0:14]=Size, Bit[15]=Fixed + */ + dest->size = (source->nomMsduSz & SIZE_MASK); + dest->fixed = (source->nomMsduSz & FIXED_MASK) ? 1 : 0; + dest->max_msdu_size = source->maxMsduSz; + dest->min_service_int = source->minSvcInterval; + dest->max_service_int = source->maxSvcInterval; + dest->inactivity_int = source->inactInterval; + dest->suspension_int = source->suspendInterval; + dest->service_start_time = source->svcStartTime; + dest->min_data_rate = source->minDataRate; + dest->mean_data_rate = source->meanDataRate; + dest->peak_data_rate = source->peakDataRate; + dest->burst_size = source->maxBurstSz; + dest->delay_bound = source->delayBound; + dest->min_phy_rate = source->minPhyRate; + dest->surplus_bw_allowance = source->surplusBw; + dest->medium_time = source->mediumTime; +} + +#endif + +void populate_dot11f_wmm_info_ap(tpAniSirGlobal pMac, tDot11fIEWMMInfoAp *pInfo, + tpPESession psessionEntry) +{ + pInfo->version = SIR_MAC_OUI_VERSION_1; + + /* WMM Specification 3.1.3, 3.2.3 + * An IBSS staion shall always use its default WMM parameters. + */ + if (LIM_IS_IBSS_ROLE(psessionEntry)) { + pInfo->param_set_count = 0; + pInfo->uapsd = 0; + } else { + pInfo->param_set_count = + (0xf & psessionEntry->gLimEdcaParamSetCount); + if (LIM_IS_AP_ROLE(psessionEntry)) { + pInfo->uapsd = (0x1 & psessionEntry->apUapsdEnable); + } else + pInfo->uapsd = (0x1 & pMac->lim.gUapsdEnable); + } + pInfo->present = 1; +} + +void populate_dot11f_wmm_info_station_per_session(tpAniSirGlobal pMac, + tpPESession psessionEntry, + tDot11fIEWMMInfoStation *pInfo) +{ + uint32_t val = 0; + + pInfo->version = SIR_MAC_OUI_VERSION_1; + pInfo->acvo_uapsd = + LIM_UAPSD_GET(ACVO, psessionEntry->gUapsdPerAcBitmask); + pInfo->acvi_uapsd = + LIM_UAPSD_GET(ACVI, psessionEntry->gUapsdPerAcBitmask); + pInfo->acbk_uapsd = + LIM_UAPSD_GET(ACBK, psessionEntry->gUapsdPerAcBitmask); + pInfo->acbe_uapsd = + LIM_UAPSD_GET(ACBE, psessionEntry->gUapsdPerAcBitmask); + + if (wlan_cfg_get_int(pMac, WNI_CFG_MAX_SP_LENGTH, &val) != eSIR_SUCCESS) + lim_log(pMac, LOGE, + FL("could not retrieve Max SP Length")); + + pInfo->max_sp_length = (uint8_t) val; + pInfo->present = 1; +} + +void populate_dot11f_wmm_params(tpAniSirGlobal pMac, + tDot11fIEWMMParams *pParams, + tpPESession psessionEntry) +{ + pParams->version = SIR_MAC_OUI_VERSION_1; + + if (LIM_IS_AP_ROLE(psessionEntry)) + pParams->qosInfo = + (psessionEntry-> + apUapsdEnable << 7) | ((uint8_t) (0x0f & psessionEntry-> + gLimEdcaParamSetCount)); + else + pParams->qosInfo = + (pMac->lim. + gUapsdEnable << 7) | ((uint8_t) (0x0f & psessionEntry-> + gLimEdcaParamSetCount)); + + /* Fill each EDCA parameter set in order: be, bk, vi, vo */ + pParams->acbe_aifsn = + (0xf & SET_AIFSN(psessionEntry->gLimEdcaParamsBC[0].aci.aifsn)); + pParams->acbe_acm = (0x1 & psessionEntry->gLimEdcaParamsBC[0].aci.acm); + pParams->acbe_aci = (0x3 & SIR_MAC_EDCAACI_BESTEFFORT); + pParams->acbe_acwmin = + (0xf & psessionEntry->gLimEdcaParamsBC[0].cw.min); + pParams->acbe_acwmax = + (0xf & psessionEntry->gLimEdcaParamsBC[0].cw.max); + pParams->acbe_txoplimit = psessionEntry->gLimEdcaParamsBC[0].txoplimit; + + pParams->acbk_aifsn = + (0xf & SET_AIFSN(psessionEntry->gLimEdcaParamsBC[1].aci.aifsn)); + pParams->acbk_acm = (0x1 & psessionEntry->gLimEdcaParamsBC[1].aci.acm); + pParams->acbk_aci = (0x3 & SIR_MAC_EDCAACI_BACKGROUND); + pParams->acbk_acwmin = + (0xf & psessionEntry->gLimEdcaParamsBC[1].cw.min); + pParams->acbk_acwmax = + (0xf & psessionEntry->gLimEdcaParamsBC[1].cw.max); + pParams->acbk_txoplimit = psessionEntry->gLimEdcaParamsBC[1].txoplimit; + + if (LIM_IS_AP_ROLE(psessionEntry)) + pParams->acvi_aifsn = + (0xf & psessionEntry->gLimEdcaParamsBC[2].aci.aifsn); + else + pParams->acvi_aifsn = + (0xf & + SET_AIFSN(psessionEntry->gLimEdcaParamsBC[2].aci.aifsn)); + + pParams->acvi_acm = (0x1 & psessionEntry->gLimEdcaParamsBC[2].aci.acm); + pParams->acvi_aci = (0x3 & SIR_MAC_EDCAACI_VIDEO); + pParams->acvi_acwmin = + (0xf & psessionEntry->gLimEdcaParamsBC[2].cw.min); + pParams->acvi_acwmax = + (0xf & psessionEntry->gLimEdcaParamsBC[2].cw.max); + pParams->acvi_txoplimit = psessionEntry->gLimEdcaParamsBC[2].txoplimit; + + if (LIM_IS_AP_ROLE(psessionEntry)) + pParams->acvo_aifsn = + (0xf & psessionEntry->gLimEdcaParamsBC[3].aci.aifsn); + else + pParams->acvo_aifsn = + (0xf & + SET_AIFSN(psessionEntry->gLimEdcaParamsBC[3].aci.aifsn)); + + pParams->acvo_acm = (0x1 & psessionEntry->gLimEdcaParamsBC[3].aci.acm); + pParams->acvo_aci = (0x3 & SIR_MAC_EDCAACI_VOICE); + pParams->acvo_acwmin = + (0xf & psessionEntry->gLimEdcaParamsBC[3].cw.min); + pParams->acvo_acwmax = + (0xf & psessionEntry->gLimEdcaParamsBC[3].cw.max); + pParams->acvo_txoplimit = psessionEntry->gLimEdcaParamsBC[3].txoplimit; + + pParams->present = 1; + +} /* End populate_dot11f_wmm_params. */ + +void populate_dot11f_wmm_schedule(tSirMacScheduleIE *pSchedule, + tDot11fIEWMMSchedule *pDot11f) +{ + pDot11f->version = 1; + pDot11f->aggregation = pSchedule->info.aggregation; + pDot11f->tsid = pSchedule->info.tsid; + pDot11f->direction = pSchedule->info.direction; + pDot11f->reserved = pSchedule->info.rsvd; + pDot11f->service_start_time = pSchedule->svcStartTime; + pDot11f->service_interval = pSchedule->svcInterval; + pDot11f->max_service_dur = pSchedule->maxSvcDuration; + pDot11f->spec_interval = pSchedule->specInterval; + + pDot11f->present = 1; +} /* End populate_dot11f_wmm_schedule. */ + +tSirRetStatus +populate_dot11f_wpa(tpAniSirGlobal pMac, + tpSirRSNie pRsnIe, tDot11fIEWPA *pDot11f) +{ + uint32_t status; + int idx; + + if (pRsnIe->length) { + idx = find_ie_location(pMac, pRsnIe, DOT11F_EID_WPA); + if (0 <= idx) { + status = dot11f_unpack_ie_wpa(pMac, pRsnIe->rsnIEdata + idx + 2 + 4, /* EID, length, OUI */ + pRsnIe->rsnIEdata[idx + 1] - 4, /* OUI */ + pDot11f); + if (DOT11F_FAILED(status)) { + dot11f_log(pMac, LOGE, + FL("Parse failure in Populate Dot11fWPA (0x%08x)."), + status); + return eSIR_FAILURE; + } + } + } + + return eSIR_SUCCESS; +} /* End populate_dot11f_wpa. */ + +tSirRetStatus populate_dot11f_wpa_opaque(tpAniSirGlobal pMac, + tpSirRSNie pRsnIe, + tDot11fIEWPAOpaque *pDot11f) +{ + int idx; + + if (pRsnIe->length) { + idx = find_ie_location(pMac, pRsnIe, DOT11F_EID_WPA); + if (0 <= idx) { + pDot11f->present = 1; + pDot11f->num_data = pRsnIe->rsnIEdata[idx + 1] - 4; + qdf_mem_copy(pDot11f->data, pRsnIe->rsnIEdata + idx + 2 + 4, /* EID, len, OUI */ + pRsnIe->rsnIEdata[idx + 1] - 4); /* OUI */ + } + } + + return eSIR_SUCCESS; + +} /* End populate_dot11f_wpa_opaque. */ + +/* ////////////////////////////////////////////////////////////////////// */ + +tSirRetStatus +sir_convert_probe_req_frame2_struct(tpAniSirGlobal pMac, + uint8_t *pFrame, + uint32_t nFrame, tpSirProbeReq pProbeReq) +{ + uint32_t status; + tDot11fProbeRequest pr; + + /* Ok, zero-init our [out] parameter, */ + qdf_mem_set((uint8_t *) pProbeReq, sizeof(tSirProbeReq), 0); + + /* delegate to the framesc-generated code, */ + status = dot11f_unpack_probe_request(pMac, pFrame, nFrame, &pr); + if (DOT11F_FAILED(status)) { + lim_log(pMac, LOGE, + FL("Failed to parse a Probe Request (0x%08x, %d bytes):"), + status, nFrame); + PELOG2(sir_dump_buf + (pMac, SIR_DBG_MODULE_ID, LOG2, pFrame, nFrame); + ) + return eSIR_FAILURE; + } else if (DOT11F_WARNED(status)) { + lim_log(pMac, LOGW, + FL("There were warnings while unpacking a Probe Request (0x%08x, %d bytes):"), + status, nFrame); + } + /* & "transliterate" from a 'tDot11fProbeRequestto' a 'tSirProbeReq'... */ + if (!pr.SSID.present) { + PELOGW(lim_log(pMac, LOGW, + FL("Mandatory IE SSID not present!")); + ) + } else { + pProbeReq->ssidPresent = 1; + convert_ssid(pMac, &pProbeReq->ssId, &pr.SSID); + } + + if (!pr.SuppRates.present) { + PELOGW(lim_log(pMac, LOGW, + FL("Mandatory IE Supported Rates not present!")); + ) + return eSIR_FAILURE; + } else { + pProbeReq->suppRatesPresent = 1; + convert_supp_rates(pMac, &pProbeReq->supportedRates, + &pr.SuppRates); + } + + if (pr.ExtSuppRates.present) { + pProbeReq->extendedRatesPresent = 1; + convert_ext_supp_rates(pMac, &pProbeReq->extendedRates, + &pr.ExtSuppRates); + } + + if (pr.HTCaps.present) { + qdf_mem_copy(&pProbeReq->HTCaps, &pr.HTCaps, + sizeof(tDot11fIEHTCaps)); + } + + if (pr.WscProbeReq.present) { + pProbeReq->wscIePresent = 1; + memcpy(&pProbeReq->probeReqWscIeInfo, &pr.WscProbeReq, + sizeof(tDot11fIEWscProbeReq)); + } + if (pr.VHTCaps.present) { + qdf_mem_copy(&pProbeReq->VHTCaps, &pr.VHTCaps, + sizeof(tDot11fIEVHTCaps)); + } + if (pr.P2PProbeReq.present) { + pProbeReq->p2pIePresent = 1; + } + return eSIR_SUCCESS; +} /* End sir_convert_probe_req_frame2_struct. */ + + +/** + * sir_validate_and_rectify_ies() - API to check malformed frame + * @mac_ctx: mac context + * @mgmt_frame: pointer to management frame + * @frame_bytes: no of bytes in frame + * @missing_rsn_bytes: missing rsn bytes + * + * The frame would contain fixed IEs of 12 bytes followed by variable IEs + * (Tagged elements). Every Tagged IE has tag number, tag length and data. + * Tag length indicates the size of data in bytes. + * This function checks for size of Frame received with the sum of all IEs. + * And also rectifies missing optional fields in IE. + * + * NOTE : Presently this function rectifies RSN capability in RSN IE, can + * be extended to rectify other optional fields in other IEs. + * + * Return: 0 on success, error number otherwise. + */ +tSirRetStatus +sir_validate_and_rectify_ies(tpAniSirGlobal mac_ctx, + uint8_t *mgmt_frame, + uint32_t frame_bytes, + uint32_t *missing_rsn_bytes) +{ + uint32_t length = SIZE_OF_FIXED_PARAM; + uint8_t *ref_frame; + + /* Frame contains atleast one IE */ + if (frame_bytes > (SIZE_OF_FIXED_PARAM + + SIZE_OF_TAG_PARAM_NUM + SIZE_OF_TAG_PARAM_LEN)) { + while (length < frame_bytes) { + /* ref frame points to next IE */ + ref_frame = mgmt_frame + length; + length += (uint32_t)(SIZE_OF_TAG_PARAM_NUM + + SIZE_OF_TAG_PARAM_LEN + + (*(ref_frame + SIZE_OF_TAG_PARAM_NUM))); + } + if (length != frame_bytes) { + /* + * Workaround : Some APs may not include RSN + * Capability but the length of which is included in + * RSN IE length. This may cause in updating RSN + * Capability with junk value. To avoid this, add RSN + * Capability value with default value. + */ + if ((*ref_frame == RSNIEID) && + (length == (frame_bytes + + RSNIE_CAPABILITY_LEN))) { + /* Assume RSN Capability as 00 */ + qdf_mem_set((uint8_t *)(mgmt_frame + + (frame_bytes)), + RSNIE_CAPABILITY_LEN, + DEFAULT_RSNIE_CAP_VAL); + *missing_rsn_bytes = RSNIE_CAPABILITY_LEN; + lim_log(mac_ctx, LOG1, + FL("Added RSN Capability to RSNIE as 0x00 0x00")); + return eSIR_SUCCESS; + } + return eSIR_FAILURE; + } + } + return eSIR_SUCCESS; +} + +tSirRetStatus sir_convert_probe_frame2_struct(tpAniSirGlobal pMac, + uint8_t *pFrame, + uint32_t nFrame, + tpSirProbeRespBeacon pProbeResp) +{ + uint32_t status; + tDot11fProbeResponse *pr; + + /* Ok, zero-init our [out] parameter, */ + qdf_mem_set((uint8_t *) pProbeResp, sizeof(tSirProbeRespBeacon), 0); + + pr = qdf_mem_malloc(sizeof(tDot11fProbeResponse)); + if (NULL == pr) { + lim_log(pMac, LOGE, FL("Failed to allocate memory")); + return eSIR_MEM_ALLOC_FAILED; + } + + /* delegate to the framesc-generated code, */ + status = dot11f_unpack_probe_response(pMac, pFrame, nFrame, pr); + if (DOT11F_FAILED(status)) { + lim_log(pMac, LOGE, + FL("Failed to parse a Probe Response (0x%08x, %d bytes):"), + status, nFrame); + PELOG2(sir_dump_buf + (pMac, SIR_DBG_MODULE_ID, LOG2, pFrame, nFrame); + ) + qdf_mem_free(pr); + return eSIR_FAILURE; + } else if (DOT11F_WARNED(status)) { + lim_log(pMac, LOGW, + FL("There were warnings while unpacking a Probe Response (0x%08x, %d bytes):"), + status, nFrame); + } + /* & "transliterate" from a 'tDot11fProbeResponse' to a 'tSirProbeRespBeacon'... */ + + /* Timestamp */ + qdf_mem_copy((uint8_t *) pProbeResp->timeStamp, + (uint8_t *) &pr->TimeStamp, sizeof(tSirMacTimeStamp)); + + /* Beacon Interval */ + pProbeResp->beaconInterval = pr->BeaconInterval.interval; + + /* Capabilities */ + pProbeResp->capabilityInfo.ess = pr->Capabilities.ess; + pProbeResp->capabilityInfo.ibss = pr->Capabilities.ibss; + pProbeResp->capabilityInfo.cfPollable = pr->Capabilities.cfPollable; + pProbeResp->capabilityInfo.cfPollReq = pr->Capabilities.cfPollReq; + pProbeResp->capabilityInfo.privacy = pr->Capabilities.privacy; + pProbeResp->capabilityInfo.shortPreamble = + pr->Capabilities.shortPreamble; + pProbeResp->capabilityInfo.pbcc = pr->Capabilities.pbcc; + pProbeResp->capabilityInfo.channelAgility = + pr->Capabilities.channelAgility; + pProbeResp->capabilityInfo.spectrumMgt = pr->Capabilities.spectrumMgt; + pProbeResp->capabilityInfo.qos = pr->Capabilities.qos; + pProbeResp->capabilityInfo.shortSlotTime = + pr->Capabilities.shortSlotTime; + pProbeResp->capabilityInfo.apsd = pr->Capabilities.apsd; + pProbeResp->capabilityInfo.rrm = pr->Capabilities.rrm; + pProbeResp->capabilityInfo.dsssOfdm = pr->Capabilities.dsssOfdm; + pProbeResp->capabilityInfo.delayedBA = pr->Capabilities.delayedBA; + pProbeResp->capabilityInfo.immediateBA = pr->Capabilities.immediateBA; + + if (!pr->SSID.present) { + PELOGW(lim_log(pMac, LOGW, + FL("Mandatory IE SSID not present!")); + ) + } else { + pProbeResp->ssidPresent = 1; + convert_ssid(pMac, &pProbeResp->ssId, &pr->SSID); + } + + if (!pr->SuppRates.present) { + PELOGW(lim_log + (pMac, LOGW, + FL("Mandatory IE Supported Rates not present!")); + ) + } else { + pProbeResp->suppRatesPresent = 1; + convert_supp_rates(pMac, &pProbeResp->supportedRates, + &pr->SuppRates); + } + + if (pr->ExtSuppRates.present) { + pProbeResp->extendedRatesPresent = 1; + convert_ext_supp_rates(pMac, &pProbeResp->extendedRates, + &pr->ExtSuppRates); + } + + if (pr->CFParams.present) { + pProbeResp->cfPresent = 1; + convert_cf_params(pMac, &pProbeResp->cfParamSet, &pr->CFParams); + } + + if (pr->Country.present) { + pProbeResp->countryInfoPresent = 1; + convert_country(pMac, &pProbeResp->countryInfoParam, + &pr->Country); + } + + if (pr->EDCAParamSet.present) { + pProbeResp->edcaPresent = 1; + convert_edca_param(pMac, &pProbeResp->edcaParams, + &pr->EDCAParamSet); + } + + if (pr->ChanSwitchAnn.present) { + pProbeResp->channelSwitchPresent = 1; + qdf_mem_copy(&pProbeResp->channelSwitchIE, &pr->ChanSwitchAnn, + sizeof(pProbeResp->channelSwitchIE)); + } + + if (pr->ext_chan_switch_ann.present) { + pProbeResp->ext_chan_switch_present = 1; + qdf_mem_copy(&pProbeResp->ext_chan_switch, + &pr->ext_chan_switch_ann, + sizeof(tDot11fIEext_chan_switch_ann)); + } + + if (pr->SuppOperatingClasses.present) { + pProbeResp->supp_operating_class_present = 1; + qdf_mem_copy(&pProbeResp->supp_operating_classes, + &pr->SuppOperatingClasses, + sizeof(tDot11fIESuppOperatingClasses)); + } + + if (pr->sec_chan_offset_ele.present) { + pProbeResp->sec_chan_offset_present = 1; + qdf_mem_copy(&pProbeResp->sec_chan_offset, + &pr->sec_chan_offset_ele, + sizeof(pProbeResp->sec_chan_offset)); + } + + if (pr->TPCReport.present) { + pProbeResp->tpcReportPresent = 1; + qdf_mem_copy(&pProbeResp->tpcReport, &pr->TPCReport, + sizeof(tDot11fIETPCReport)); + } + + if (pr->PowerConstraints.present) { + pProbeResp->powerConstraintPresent = 1; + qdf_mem_copy(&pProbeResp->localPowerConstraint, + &pr->PowerConstraints, + sizeof(tDot11fIEPowerConstraints)); + } + + if (pr->Quiet.present) { + pProbeResp->quietIEPresent = 1; + qdf_mem_copy(&pProbeResp->quietIE, &pr->Quiet, + sizeof(tDot11fIEQuiet)); + } + + if (pr->HTCaps.present) { + qdf_mem_copy(&pProbeResp->HTCaps, &pr->HTCaps, + sizeof(tDot11fIEHTCaps)); + } + + if (pr->HTInfo.present) { + qdf_mem_copy(&pProbeResp->HTInfo, &pr->HTInfo, + sizeof(tDot11fIEHTInfo)); + } + + if (pr->DSParams.present) { + pProbeResp->dsParamsPresent = 1; + pProbeResp->channelNumber = pr->DSParams.curr_channel; + } else if (pr->HTInfo.present) { + pProbeResp->channelNumber = pr->HTInfo.primaryChannel; + } + + if (pr->RSNOpaque.present) { + pProbeResp->rsnPresent = 1; + convert_rsn_opaque(pMac, &pProbeResp->rsn, &pr->RSNOpaque); + } + + if (pr->WPA.present) { + pProbeResp->wpaPresent = 1; + convert_wpa(pMac, &pProbeResp->wpa, &pr->WPA); + } + + if (pr->WMMParams.present) { + pProbeResp->wmeEdcaPresent = 1; + convert_wmm_params(pMac, &pProbeResp->edcaParams, &pr->WMMParams); + PELOG1(lim_log(pMac, LOG1, + FL("WMM Parameter present in Probe Response Frame!")); + __print_wmm_params(pMac, &pr->WMMParams); + ) + } + + if (pr->WMMInfoAp.present) { + pProbeResp->wmeInfoPresent = 1; + PELOG1(lim_log(pMac, LOG1, + FL("WMM Information Element present in Probe Response Frame!")); + ) + } + + if (pr->WMMCaps.present) { + pProbeResp->wsmCapablePresent = 1; + } + + if (pr->ERPInfo.present) { + pProbeResp->erpPresent = 1; + convert_erp_info(pMac, &pProbeResp->erpIEInfo, &pr->ERPInfo); + } + if (pr->MobilityDomain.present) { + /* MobilityDomain */ + pProbeResp->mdiePresent = 1; + qdf_mem_copy((uint8_t *) &(pProbeResp->mdie[0]), + (uint8_t *) &(pr->MobilityDomain.MDID), + sizeof(uint16_t)); + pProbeResp->mdie[2] = + ((pr->MobilityDomain.overDSCap << 0) | (pr->MobilityDomain. + resourceReqCap << + 1)); + lim_log(pMac, LOG2, FL("mdie=%02x%02x%02x"), + (unsigned int)pProbeResp->mdie[0], + (unsigned int)pProbeResp->mdie[1], + (unsigned int)pProbeResp->mdie[2]); + } + +#if defined FEATURE_WLAN_ESE + if (pr->ESEVersion.present) + pProbeResp->is_ese_ver_ie_present = 1; + if (pr->QBSSLoad.present) { + qdf_mem_copy(&pProbeResp->QBSSLoad, &pr->QBSSLoad, + sizeof(tDot11fIEQBSSLoad)); + } +#endif + if (pr->P2PProbeRes.present) { + qdf_mem_copy(&pProbeResp->P2PProbeRes, &pr->P2PProbeRes, + sizeof(tDot11fIEP2PProbeRes)); + } + if (pr->VHTCaps.present) { + qdf_mem_copy(&pProbeResp->VHTCaps, &pr->VHTCaps, + sizeof(tDot11fIEVHTCaps)); + } + if (pr->VHTOperation.present) { + qdf_mem_copy(&pProbeResp->VHTOperation, &pr->VHTOperation, + sizeof(tDot11fIEVHTOperation)); + } + if (pr->VHTExtBssLoad.present) { + qdf_mem_copy(&pProbeResp->VHTExtBssLoad, &pr->VHTExtBssLoad, + sizeof(tDot11fIEVHTExtBssLoad)); + } + pProbeResp->Vendor1IEPresent = pr->Vendor1IE.present; + pProbeResp->Vendor3IEPresent = pr->Vendor3IE.present; + + pProbeResp->vendor_vht_ie.present = pr->vendor_vht_ie.present; + if (pr->vendor_vht_ie.present) { + pProbeResp->vendor_vht_ie.type = pr->vendor_vht_ie.type; + pProbeResp->vendor_vht_ie.sub_type = pr->vendor_vht_ie.sub_type; + } + if (pr->vendor_vht_ie.VHTCaps.present) { + qdf_mem_copy(&pProbeResp->vendor_vht_ie.VHTCaps, + &pr->vendor_vht_ie.VHTCaps, + sizeof(tDot11fIEVHTCaps)); + } + if (pr->vendor_vht_ie.VHTOperation.present) { + qdf_mem_copy(&pProbeResp->vendor_vht_ie.VHTOperation, + &pr->vendor_vht_ie.VHTOperation, + sizeof(tDot11fIEVHTOperation)); + } + /* Update HS 2.0 Information Element */ + if (pr->hs20vendor_ie.present) { + lim_log(pMac, LOG1, + FL("HS20 Indication Element Present, rel#:%u, id:%u"), + pr->hs20vendor_ie.release_num, + pr->hs20vendor_ie.hs_id_present); + qdf_mem_copy(&pProbeResp->hs20vendor_ie, + &pr->hs20vendor_ie, + sizeof(tDot11fIEhs20vendor_ie) - + sizeof(pr->hs20vendor_ie.hs_id)); + if (pr->hs20vendor_ie.hs_id_present) + qdf_mem_copy(&pProbeResp->hs20vendor_ie.hs_id, + &pr->hs20vendor_ie.hs_id, + sizeof(pr->hs20vendor_ie.hs_id)); + } + if (pr->MBO_IE.present) { + pProbeResp->MBO_IE_present = true; + pProbeResp->MBO_capability = pr->MBO_IE.mbo_cap[2]; + + if (pr->MBO_IE.num_assoc_disallowed && + (pr->MBO_IE.assoc_disallowed[0] == + MBO_IE_ASSOC_DISALLOWED_SUBATTR_ID)) { + pProbeResp->assoc_disallowed = true; + pProbeResp->assoc_disallowed_reason = + pr->MBO_IE.assoc_disallowed[2]; + } + } + + if (pr->QCN_IE.present) { + pProbeResp->QCN_IE.is_present = true; + + if (pr->QCN_IE.version[0] == QCN_IE_VERSION_SUBATTR_ID) { + pProbeResp->QCN_IE.version + = pr->QCN_IE.version[2]; + pProbeResp->QCN_IE.sub_version + = pr->QCN_IE.version[3]; + } + } + + qdf_mem_free(pr); + return eSIR_SUCCESS; + +} /* End sir_convert_probe_frame2_struct. */ + +tSirRetStatus +sir_convert_assoc_req_frame2_struct(tpAniSirGlobal pMac, + uint8_t *pFrame, + uint32_t nFrame, tpSirAssocReq pAssocReq) +{ + tDot11fAssocRequest *ar; + uint32_t status; + + ar = qdf_mem_malloc(sizeof(tDot11fAssocRequest)); + if (NULL == ar) { + lim_log(pMac, LOGE, FL("Failed to allocate memory")); + return eSIR_MEM_ALLOC_FAILED; + } + /* Zero-init our [out] parameter, */ + qdf_mem_set((uint8_t *) pAssocReq, sizeof(tSirAssocReq), 0); + + /* delegate to the framesc-generated code, */ + status = dot11f_unpack_assoc_request(pMac, pFrame, nFrame, ar); + if (DOT11F_FAILED(status)) { + lim_log(pMac, LOGE, + FL("Failed to parse an Association Request (0x%08x, %d bytes):"), + status, nFrame); + PELOG2(sir_dump_buf + (pMac, SIR_DBG_MODULE_ID, LOG2, pFrame, nFrame); + ) + qdf_mem_free(ar); + return eSIR_FAILURE; + } else if (DOT11F_WARNED(status)) { + lim_log(pMac, LOGW, + FL("There were warnings while unpacking an Assoication Request (0x%08x, %d bytes):"), + status, nFrame); + } + /* & "transliterate" from a 'tDot11fAssocRequest' to a 'tSirAssocReq'... */ + + /* make sure this is seen as an assoc request */ + pAssocReq->reassocRequest = 0; + + /* Capabilities */ + pAssocReq->capabilityInfo.ess = ar->Capabilities.ess; + pAssocReq->capabilityInfo.ibss = ar->Capabilities.ibss; + pAssocReq->capabilityInfo.cfPollable = ar->Capabilities.cfPollable; + pAssocReq->capabilityInfo.cfPollReq = ar->Capabilities.cfPollReq; + pAssocReq->capabilityInfo.privacy = ar->Capabilities.privacy; + pAssocReq->capabilityInfo.shortPreamble = + ar->Capabilities.shortPreamble; + pAssocReq->capabilityInfo.pbcc = ar->Capabilities.pbcc; + pAssocReq->capabilityInfo.channelAgility = + ar->Capabilities.channelAgility; + pAssocReq->capabilityInfo.spectrumMgt = ar->Capabilities.spectrumMgt; + pAssocReq->capabilityInfo.qos = ar->Capabilities.qos; + pAssocReq->capabilityInfo.shortSlotTime = + ar->Capabilities.shortSlotTime; + pAssocReq->capabilityInfo.apsd = ar->Capabilities.apsd; + pAssocReq->capabilityInfo.rrm = ar->Capabilities.rrm; + pAssocReq->capabilityInfo.dsssOfdm = ar->Capabilities.dsssOfdm; + pAssocReq->capabilityInfo.delayedBA = ar->Capabilities.delayedBA; + pAssocReq->capabilityInfo.immediateBA = ar->Capabilities.immediateBA; + + /* Listen Interval */ + pAssocReq->listenInterval = ar->ListenInterval.interval; + + /* SSID */ + if (ar->SSID.present) { + pAssocReq->ssidPresent = 1; + convert_ssid(pMac, &pAssocReq->ssId, &ar->SSID); + } + /* Supported Rates */ + if (ar->SuppRates.present) { + pAssocReq->suppRatesPresent = 1; + convert_supp_rates(pMac, &pAssocReq->supportedRates, + &ar->SuppRates); + } + /* Extended Supported Rates */ + if (ar->ExtSuppRates.present) { + pAssocReq->extendedRatesPresent = 1; + convert_ext_supp_rates(pMac, &pAssocReq->extendedRates, + &ar->ExtSuppRates); + } + /* QOS Capabilities: */ + if (ar->QOSCapsStation.present) { + pAssocReq->qosCapabilityPresent = 1; + convert_qos_caps_station(pMac, &pAssocReq->qosCapability, + &ar->QOSCapsStation); + } + /* WPA */ + if (ar->WPAOpaque.present) { + pAssocReq->wpaPresent = 1; + convert_wpa_opaque(pMac, &pAssocReq->wpa, &ar->WPAOpaque); + } +#ifdef FEATURE_WLAN_WAPI + if (ar->WAPIOpaque.present) { + pAssocReq->wapiPresent = 1; + convert_wapi_opaque(pMac, &pAssocReq->wapi, &ar->WAPIOpaque); + } +#endif + /* RSN */ + if (ar->RSNOpaque.present) { + pAssocReq->rsnPresent = 1; + convert_rsn_opaque(pMac, &pAssocReq->rsn, &ar->RSNOpaque); + } + /* WSC IE */ + if (ar->WscIEOpaque.present) { + pAssocReq->addIEPresent = 1; + convert_wsc_opaque(pMac, &pAssocReq->addIE, &ar->WscIEOpaque); + } + + if (ar->P2PIEOpaque.present) { + pAssocReq->addIEPresent = 1; + convert_p2p_opaque(pMac, &pAssocReq->addIE, &ar->P2PIEOpaque); + } +#ifdef WLAN_FEATURE_WFD + if (ar->WFDIEOpaque.present) { + pAssocReq->addIEPresent = 1; + convert_wfd_opaque(pMac, &pAssocReq->addIE, &ar->WFDIEOpaque); + } +#endif + + /* Power Capabilities */ + if (ar->PowerCaps.present) { + pAssocReq->powerCapabilityPresent = 1; + convert_power_caps(pMac, &pAssocReq->powerCapability, + &ar->PowerCaps); + } + /* Supported Channels */ + if (ar->SuppChannels.present) { + pAssocReq->supportedChannelsPresent = 1; + convert_supp_channels(pMac, &pAssocReq->supportedChannels, + &ar->SuppChannels); + } + + if (ar->HTCaps.present) { + qdf_mem_copy(&pAssocReq->HTCaps, &ar->HTCaps, + sizeof(tDot11fIEHTCaps)); + } + + if (ar->WMMInfoStation.present) { + pAssocReq->wmeInfoPresent = 1; + qdf_mem_copy(&pAssocReq->WMMInfoStation, &ar->WMMInfoStation, + sizeof(tDot11fIEWMMInfoStation)); + + } + + if (ar->WMMCaps.present) + pAssocReq->wsmCapablePresent = 1; + + if (!pAssocReq->ssidPresent) { + PELOG2(lim_log(pMac, LOG2, + FL("Received Assoc without SSID IE.")); + ) + qdf_mem_free(ar); + return eSIR_FAILURE; + } + + if (!pAssocReq->suppRatesPresent && !pAssocReq->extendedRatesPresent) { + PELOG2(lim_log + (pMac, LOG2, + FL("Received Assoc without supp rate IE.")); + ) + qdf_mem_free(ar); + return eSIR_FAILURE; + } + if (ar->VHTCaps.present) { + qdf_mem_copy(&pAssocReq->VHTCaps, &ar->VHTCaps, + sizeof(tDot11fIEVHTCaps)); + lim_log(pMac, LOGW, FL("Received Assoc Req with VHT Cap")); + lim_log_vht_cap(pMac, &pAssocReq->VHTCaps); + } + if (ar->OperatingMode.present) { + qdf_mem_copy(&pAssocReq->operMode, &ar->OperatingMode, + sizeof(tDot11fIEOperatingMode)); + lim_log(pMac, LOGW, + FL("Received Assoc Req with Operating Mode IE")); + lim_log_operating_mode(pMac, &pAssocReq->operMode); + } + if (ar->ExtCap.present) { + struct s_ext_cap *ext_cap; + qdf_mem_copy(&pAssocReq->ExtCap, &ar->ExtCap, + sizeof(tDot11fIEExtCap)); + ext_cap = (struct s_ext_cap *)&pAssocReq->ExtCap.bytes; + lim_log(pMac, LOG1, + FL("timingMeas: %d, finetimingMeas Init: %d, Resp: %d"), + ext_cap->timing_meas, ext_cap->fine_time_meas_initiator, + ext_cap->fine_time_meas_responder); + } + + pAssocReq->vendor_vht_ie.present = ar->vendor_vht_ie.present; + if (ar->vendor_vht_ie.present) { + pAssocReq->vendor_vht_ie.type = ar->vendor_vht_ie.type; + pAssocReq->vendor_vht_ie.sub_type = ar->vendor_vht_ie.sub_type; + + if (ar->vendor_vht_ie.VHTCaps.present) { + qdf_mem_copy(&pAssocReq->vendor_vht_ie.VHTCaps, + &ar->vendor_vht_ie.VHTCaps, + sizeof(tDot11fIEVHTCaps)); + lim_log(pMac, LOG1, + FL("Received Assoc Request with Vendor specific VHT Cap")); + lim_log_vht_cap(pMac, &pAssocReq->VHTCaps); + } + } + + qdf_mem_free(ar); + return eSIR_SUCCESS; + +} /* End sir_convert_assoc_req_frame2_struct. */ + +tSirRetStatus +sir_convert_assoc_resp_frame2_struct(tpAniSirGlobal pMac, + uint8_t *pFrame, + uint32_t nFrame, tpSirAssocRsp pAssocRsp) +{ + static tDot11fAssocResponse ar; + uint32_t status; + uint8_t cnt = 0; + + /* Zero-init our [out] parameter, */ + qdf_mem_set((uint8_t *) pAssocRsp, sizeof(tSirAssocRsp), 0); + + /* delegate to the framesc-generated code, */ + status = dot11f_unpack_assoc_response(pMac, pFrame, nFrame, &ar); + if (DOT11F_FAILED(status)) { + lim_log(pMac, LOGE, + FL("Failed to parse an Association Response (0x%08x, %d bytes):"), + status, nFrame); + PELOG2(sir_dump_buf + (pMac, SIR_DBG_MODULE_ID, LOG2, pFrame, nFrame); + ) + return eSIR_FAILURE; + } else if (DOT11F_WARNED(status)) { + lim_log(pMac, LOGW, + FL("There were warnings while unpacking an Association Response (0x%08x, %d bytes):"), + status, nFrame); + } + /* & "transliterate" from a 'tDot11fAssocResponse' a 'tSirAssocRsp'... */ + + /* Capabilities */ + pAssocRsp->capabilityInfo.ess = ar.Capabilities.ess; + pAssocRsp->capabilityInfo.ibss = ar.Capabilities.ibss; + pAssocRsp->capabilityInfo.cfPollable = ar.Capabilities.cfPollable; + pAssocRsp->capabilityInfo.cfPollReq = ar.Capabilities.cfPollReq; + pAssocRsp->capabilityInfo.privacy = ar.Capabilities.privacy; + pAssocRsp->capabilityInfo.shortPreamble = ar.Capabilities.shortPreamble; + pAssocRsp->capabilityInfo.pbcc = ar.Capabilities.pbcc; + pAssocRsp->capabilityInfo.channelAgility = + ar.Capabilities.channelAgility; + pAssocRsp->capabilityInfo.spectrumMgt = ar.Capabilities.spectrumMgt; + pAssocRsp->capabilityInfo.qos = ar.Capabilities.qos; + pAssocRsp->capabilityInfo.shortSlotTime = ar.Capabilities.shortSlotTime; + pAssocRsp->capabilityInfo.apsd = ar.Capabilities.apsd; + pAssocRsp->capabilityInfo.rrm = ar.Capabilities.rrm; + pAssocRsp->capabilityInfo.dsssOfdm = ar.Capabilities.dsssOfdm; + pAssocRsp->capabilityInfo.delayedBA = ar.Capabilities.delayedBA; + pAssocRsp->capabilityInfo.immediateBA = ar.Capabilities.immediateBA; + + pAssocRsp->statusCode = ar.Status.status; + pAssocRsp->aid = ar.AID.associd; +#ifdef WLAN_FEATURE_11W + if (ar.TimeoutInterval.present) { + pAssocRsp->TimeoutInterval.present = 1; + pAssocRsp->TimeoutInterval.timeoutType = + ar.TimeoutInterval.timeoutType; + pAssocRsp->TimeoutInterval.timeoutValue = + ar.TimeoutInterval.timeoutValue; + } +#endif + + if (!ar.SuppRates.present) { + pAssocRsp->suppRatesPresent = 0; + PELOGW(lim_log + (pMac, LOGW, + FL("Mandatory IE Supported Rates not present!")); + ) + } else { + pAssocRsp->suppRatesPresent = 1; + convert_supp_rates(pMac, &pAssocRsp->supportedRates, + &ar.SuppRates); + } + + if (ar.ExtSuppRates.present) { + pAssocRsp->extendedRatesPresent = 1; + convert_ext_supp_rates(pMac, &pAssocRsp->extendedRates, + &ar.ExtSuppRates); + } + + if (ar.EDCAParamSet.present) { + pAssocRsp->edcaPresent = 1; + convert_edca_param(pMac, &pAssocRsp->edca, &ar.EDCAParamSet); + } + + if (ar.WMMParams.present) { + pAssocRsp->wmeEdcaPresent = 1; + convert_wmm_params(pMac, &pAssocRsp->edca, &ar.WMMParams); + lim_log(pMac, LOG1, FL("Received Assoc Resp with WMM Param")); + __print_wmm_params(pMac, &ar.WMMParams); + } + + if (ar.HTCaps.present) { + lim_log(pMac, LOG1, FL("Received Assoc Resp with HT Cap")); + qdf_mem_copy(&pAssocRsp->HTCaps, &ar.HTCaps, + sizeof(tDot11fIEHTCaps)); + } + + if (ar.HTInfo.present) { + lim_log(pMac, LOG1, FL("Received Assoc Resp with HT Info")); + qdf_mem_copy(&pAssocRsp->HTInfo, &ar.HTInfo, + sizeof(tDot11fIEHTInfo)); + } + if (ar.MobilityDomain.present) { + /* MobilityDomain */ + pAssocRsp->mdiePresent = 1; + qdf_mem_copy((uint8_t *) &(pAssocRsp->mdie[0]), + (uint8_t *) &(ar.MobilityDomain.MDID), + sizeof(uint16_t)); + pAssocRsp->mdie[2] = + ((ar.MobilityDomain.overDSCap << 0) | (ar.MobilityDomain. + resourceReqCap << + 1)); + lim_log(pMac, LOG1, FL("new mdie=%02x%02x%02x"), + (unsigned int)pAssocRsp->mdie[0], + (unsigned int)pAssocRsp->mdie[1], + (unsigned int)pAssocRsp->mdie[2]); + } + + if (ar.FTInfo.present) { + lim_log(pMac, LOG1, FL("FT Info present %d %d %d"), + ar.FTInfo.R0KH_ID.num_PMK_R0_ID, + ar.FTInfo.R0KH_ID.present, ar.FTInfo.R1KH_ID.present); + pAssocRsp->ftinfoPresent = 1; + qdf_mem_copy(&pAssocRsp->FTInfo, &ar.FTInfo, + sizeof(tDot11fIEFTInfo)); + } + + if (ar.num_RICDataDesc <= 2) { + for (cnt = 0; cnt < ar.num_RICDataDesc; cnt++) { + if (ar.RICDataDesc[cnt].present) { + qdf_mem_copy(&pAssocRsp->RICData[cnt], + &ar.RICDataDesc[cnt], + sizeof(tDot11fIERICDataDesc)); + } + } + pAssocRsp->num_RICData = ar.num_RICDataDesc; + pAssocRsp->ricPresent = true; + } + +#ifdef FEATURE_WLAN_ESE + if (ar.num_WMMTSPEC) { + pAssocRsp->num_tspecs = ar.num_WMMTSPEC; + for (cnt = 0; cnt < ar.num_WMMTSPEC; cnt++) { + qdf_mem_copy(&pAssocRsp->TSPECInfo[cnt], + &ar.WMMTSPEC[cnt], + (sizeof(tDot11fIEWMMTSPEC) * + ar.num_WMMTSPEC)); + } + pAssocRsp->tspecPresent = true; + } + + if (ar.ESETrafStrmMet.present) { + pAssocRsp->tsmPresent = 1; + qdf_mem_copy(&pAssocRsp->tsmIE.tsid, + &ar.ESETrafStrmMet.tsid, sizeof(tSirMacESETSMIE)); + } +#endif + + if (ar.VHTCaps.present) { + qdf_mem_copy(&pAssocRsp->VHTCaps, &ar.VHTCaps, + sizeof(tDot11fIEVHTCaps)); + lim_log(pMac, LOG1, FL("Received Assoc Response with VHT Cap")); + lim_log_vht_cap(pMac, &pAssocRsp->VHTCaps); + } + if (ar.VHTOperation.present) { + qdf_mem_copy(&pAssocRsp->VHTOperation, &ar.VHTOperation, + sizeof(tDot11fIEVHTOperation)); + lim_log(pMac, LOG1, + FL("Received Assoc Response with VHT Operation")); + lim_log_vht_operation(pMac, &pAssocRsp->VHTOperation); + } + + if (ar.ExtCap.present) { + struct s_ext_cap *ext_cap; + qdf_mem_copy(&pAssocRsp->ExtCap, &ar.ExtCap, + sizeof(tDot11fIEExtCap)); + ext_cap = (struct s_ext_cap *)&pAssocRsp->ExtCap.bytes; + lim_log(pMac, LOG1, + FL("timingMeas: %d, finetimingMeas Init: %d, Resp: %d"), + ext_cap->timing_meas, ext_cap->fine_time_meas_initiator, + ext_cap->fine_time_meas_responder); + } + + if (ar.QosMapSet.present) { + pAssocRsp->QosMapSet.present = 1; + convert_qos_mapset_frame(pMac, &pAssocRsp->QosMapSet, + &ar.QosMapSet); + lim_log(pMac, LOG1, + FL("Received Assoc Response with Qos Map Set")); + lim_log_qos_map_set(pMac, &pAssocRsp->QosMapSet); + } + + pAssocRsp->vendor_vht_ie.present = ar.vendor_vht_ie.present; + if (ar.vendor_vht_ie.present) { + pAssocRsp->vendor_vht_ie.type = ar.vendor_vht_ie.type; + pAssocRsp->vendor_vht_ie.sub_type = ar.vendor_vht_ie.sub_type; + } + if (ar.OBSSScanParameters.present) { + qdf_mem_copy(&pAssocRsp->obss_scanparams, + &ar.OBSSScanParameters, + sizeof(struct sDot11fIEOBSSScanParameters)); + } + if (ar.vendor_vht_ie.VHTCaps.present) { + qdf_mem_copy(&pAssocRsp->vendor_vht_ie.VHTCaps, + &ar.vendor_vht_ie.VHTCaps, + sizeof(tDot11fIEVHTCaps)); + lim_log(pMac, LOG1, + FL("Received Assoc Response with Vendor specific VHT Cap")); + lim_log_vht_cap(pMac, &pAssocRsp->VHTCaps); + } + if (ar.vendor_vht_ie.VHTOperation.present) { + qdf_mem_copy(&pAssocRsp->vendor_vht_ie.VHTOperation, + &ar.vendor_vht_ie.VHTOperation, + sizeof(tDot11fIEVHTOperation)); + lim_log(pMac, LOG1, + FL("Received Assoc Response with Vendor specific VHT Oper")); + lim_log_vht_operation(pMac, &pAssocRsp->VHTOperation); + } + return eSIR_SUCCESS; + +} /* End sir_convert_assoc_resp_frame2_struct. */ + +tSirRetStatus +sir_convert_reassoc_req_frame2_struct(tpAniSirGlobal pMac, + uint8_t *pFrame, + uint32_t nFrame, tpSirAssocReq pAssocReq) +{ + static tDot11fReAssocRequest ar; + uint32_t status; + + /* Zero-init our [out] parameter, */ + qdf_mem_set((uint8_t *) pAssocReq, sizeof(tSirAssocReq), 0); + + /* delegate to the framesc-generated code, */ + status = dot11f_unpack_re_assoc_request(pMac, pFrame, nFrame, &ar); + if (DOT11F_FAILED(status)) { + lim_log(pMac, LOGE, + FL("Failed to parse a Re-association Request (0x%08x, %d bytes):"), + status, nFrame); + PELOG2(sir_dump_buf + (pMac, SIR_DBG_MODULE_ID, LOG2, pFrame, nFrame); + ) + return eSIR_FAILURE; + } else if (DOT11F_WARNED(status)) { + lim_log(pMac, LOGW, + FL("There were warnings while unpacking a Re-association Request (0x%08x, %d bytes):"), + status, nFrame); + } + /* & "transliterate" from a 'tDot11fReAssocRequest' to a 'tSirAssocReq'... */ + + /* make sure this is seen as a re-assoc request */ + pAssocReq->reassocRequest = 1; + + /* Capabilities */ + pAssocReq->capabilityInfo.ess = ar.Capabilities.ess; + pAssocReq->capabilityInfo.ibss = ar.Capabilities.ibss; + pAssocReq->capabilityInfo.cfPollable = ar.Capabilities.cfPollable; + pAssocReq->capabilityInfo.cfPollReq = ar.Capabilities.cfPollReq; + pAssocReq->capabilityInfo.privacy = ar.Capabilities.privacy; + pAssocReq->capabilityInfo.shortPreamble = ar.Capabilities.shortPreamble; + pAssocReq->capabilityInfo.pbcc = ar.Capabilities.pbcc; + pAssocReq->capabilityInfo.channelAgility = + ar.Capabilities.channelAgility; + pAssocReq->capabilityInfo.spectrumMgt = ar.Capabilities.spectrumMgt; + pAssocReq->capabilityInfo.qos = ar.Capabilities.qos; + pAssocReq->capabilityInfo.shortSlotTime = ar.Capabilities.shortSlotTime; + pAssocReq->capabilityInfo.apsd = ar.Capabilities.apsd; + pAssocReq->capabilityInfo.rrm = ar.Capabilities.rrm; + pAssocReq->capabilityInfo.dsssOfdm = ar.Capabilities.dsssOfdm; + pAssocReq->capabilityInfo.delayedBA = ar.Capabilities.delayedBA; + pAssocReq->capabilityInfo.immediateBA = ar.Capabilities.immediateBA; + + /* Listen Interval */ + pAssocReq->listenInterval = ar.ListenInterval.interval; + + /* SSID */ + if (ar.SSID.present) { + pAssocReq->ssidPresent = 1; + convert_ssid(pMac, &pAssocReq->ssId, &ar.SSID); + } + /* Supported Rates */ + if (ar.SuppRates.present) { + pAssocReq->suppRatesPresent = 1; + convert_supp_rates(pMac, &pAssocReq->supportedRates, + &ar.SuppRates); + } + /* Extended Supported Rates */ + if (ar.ExtSuppRates.present) { + pAssocReq->extendedRatesPresent = 1; + convert_ext_supp_rates(pMac, &pAssocReq->extendedRates, + &ar.ExtSuppRates); + } + /* QOS Capabilities: */ + if (ar.QOSCapsStation.present) { + pAssocReq->qosCapabilityPresent = 1; + convert_qos_caps_station(pMac, &pAssocReq->qosCapability, + &ar.QOSCapsStation); + } + /* WPA */ + if (ar.WPAOpaque.present) { + pAssocReq->wpaPresent = 1; + convert_wpa_opaque(pMac, &pAssocReq->wpa, &ar.WPAOpaque); + } + /* RSN */ + if (ar.RSNOpaque.present) { + pAssocReq->rsnPresent = 1; + convert_rsn_opaque(pMac, &pAssocReq->rsn, &ar.RSNOpaque); + } + + /* Power Capabilities */ + if (ar.PowerCaps.present) { + pAssocReq->powerCapabilityPresent = 1; + convert_power_caps(pMac, &pAssocReq->powerCapability, + &ar.PowerCaps); + } + /* Supported Channels */ + if (ar.SuppChannels.present) { + pAssocReq->supportedChannelsPresent = 1; + convert_supp_channels(pMac, &pAssocReq->supportedChannels, + &ar.SuppChannels); + } + + if (ar.HTCaps.present) { + qdf_mem_copy(&pAssocReq->HTCaps, &ar.HTCaps, + sizeof(tDot11fIEHTCaps)); + } + + if (ar.WMMInfoStation.present) { + pAssocReq->wmeInfoPresent = 1; + qdf_mem_copy(&pAssocReq->WMMInfoStation, &ar.WMMInfoStation, + sizeof(tDot11fIEWMMInfoStation)); + + } + + if (ar.WMMCaps.present) + pAssocReq->wsmCapablePresent = 1; + + if (!pAssocReq->ssidPresent) { + PELOG2(lim_log(pMac, LOG2, + FL("Received Assoc without SSID IE."));) + return eSIR_FAILURE; + } + + if (!pAssocReq->suppRatesPresent && !pAssocReq->extendedRatesPresent) { + PELOG2(lim_log + (pMac, LOG2, + FL("Received Assoc without supp rate IE."));) + return eSIR_FAILURE; + } + /* Why no call to 'updateAssocReqFromPropCapability' here, like */ + /* there is in 'sir_convert_assoc_req_frame2_struct'? */ + + /* WSC IE */ + if (ar.WscIEOpaque.present) { + pAssocReq->addIEPresent = 1; + convert_wsc_opaque(pMac, &pAssocReq->addIE, &ar.WscIEOpaque); + } + + if (ar.P2PIEOpaque.present) { + pAssocReq->addIEPresent = 1; + convert_p2p_opaque(pMac, &pAssocReq->addIE, &ar.P2PIEOpaque); + } +#ifdef WLAN_FEATURE_WFD + if (ar.WFDIEOpaque.present) { + pAssocReq->addIEPresent = 1; + convert_wfd_opaque(pMac, &pAssocReq->addIE, &ar.WFDIEOpaque); + } +#endif + + if (ar.VHTCaps.present) { + qdf_mem_copy(&pAssocReq->VHTCaps, &ar.VHTCaps, + sizeof(tDot11fIEVHTCaps)); + } + if (ar.OperatingMode.present) { + qdf_mem_copy(&pAssocReq->operMode, &ar.OperatingMode, + sizeof(tDot11fIEOperatingMode)); + lim_log(pMac, LOGW, + FL("Received Assoc Req with Operating Mode IE")); + lim_log_operating_mode(pMac, &pAssocReq->operMode); + } + if (ar.ExtCap.present) { + struct s_ext_cap *ext_cap; + qdf_mem_copy(&pAssocReq->ExtCap, &ar.ExtCap, + sizeof(tDot11fIEExtCap)); + ext_cap = (struct s_ext_cap *)&pAssocReq->ExtCap.bytes; + lim_log(pMac, LOG1, + FL("timingMeas: %d, finetimingMeas Init: %d, Resp: %d"), + ext_cap->timing_meas, ext_cap->fine_time_meas_initiator, + ext_cap->fine_time_meas_responder); + } + + return eSIR_SUCCESS; + +} /* End sir_convert_reassoc_req_frame2_struct. */ + +#ifdef FEATURE_WLAN_ESE +tSirRetStatus +sir_beacon_ie_ese_bcn_report(tpAniSirGlobal pMac, + uint8_t *pPayload, const uint32_t nPayload, + uint8_t **outIeBuf, uint32_t *pOutIeLen) +{ + tDot11fBeaconIEs *pBies = NULL; + uint32_t status = QDF_STATUS_SUCCESS; + tSirRetStatus retStatus = eSIR_SUCCESS; + tSirEseBcnReportMandatoryIe eseBcnReportMandatoryIe; + + /* To store how many bytes are required to be allocated + for Bcn report mandatory Ies */ + uint16_t numBytes = 0, freeBytes = 0; + uint8_t *pos = NULL; + + /* Zero-init our [out] parameter, */ + qdf_mem_set((uint8_t *) &eseBcnReportMandatoryIe, + sizeof(eseBcnReportMandatoryIe), 0); + pBies = qdf_mem_malloc(sizeof(tDot11fBeaconIEs)); + if (NULL == pBies) { + lim_log(pMac, LOGE, FL("Failed to allocate memory")); + return eSIR_MEM_ALLOC_FAILED; + } + qdf_mem_zero(pBies, sizeof(tDot11fBeaconIEs)); + /* delegate to the framesc-generated code, */ + status = dot11f_unpack_beacon_i_es(pMac, pPayload, nPayload, pBies); + + if (DOT11F_FAILED(status)) { + lim_log(pMac, LOGE, + FL("Failed to parse Beacon IEs (0x%08x, %d bytes):"), + status, nPayload); + qdf_mem_free(pBies); + return eSIR_FAILURE; + } else if (DOT11F_WARNED(status)) { + lim_log(pMac, LOGW, + FL("There were warnings while unpacking Beacon IEs (0x%08x, %d bytes):"), + status, nPayload); + } + /* & "transliterate" from a 'tDot11fBeaconIEs' to a 'eseBcnReportMandatoryIe'... */ + if (!pBies->SSID.present) { + PELOGW(lim_log(pMac, LOGW, + FL("Mandatory IE SSID not present!")); + ) + } else { + eseBcnReportMandatoryIe.ssidPresent = 1; + convert_ssid(pMac, &eseBcnReportMandatoryIe.ssId, &pBies->SSID); + /* 1 for EID, 1 for length and length bytes */ + numBytes += 1 + 1 + eseBcnReportMandatoryIe.ssId.length; + } + + if (!pBies->SuppRates.present) { + PELOGW(lim_log(pMac, LOGW, + FL("Mandatory IE Supported Rates not present!"));) + } else { + eseBcnReportMandatoryIe.suppRatesPresent = 1; + convert_supp_rates(pMac, &eseBcnReportMandatoryIe.supportedRates, + &pBies->SuppRates); + numBytes += + 1 + 1 + eseBcnReportMandatoryIe.supportedRates.numRates; + } + + if (pBies->FHParamSet.present) { + eseBcnReportMandatoryIe.fhParamPresent = 1; + convert_fh_params(pMac, &eseBcnReportMandatoryIe.fhParamSet, + &pBies->FHParamSet); + numBytes += 1 + 1 + SIR_MAC_FH_PARAM_SET_EID_MAX; + } + + if (pBies->DSParams.present) { + eseBcnReportMandatoryIe.dsParamsPresent = 1; + eseBcnReportMandatoryIe.dsParamSet.channelNumber = + pBies->DSParams.curr_channel; + numBytes += 1 + 1 + SIR_MAC_DS_PARAM_SET_EID_MAX; + } + + if (pBies->CFParams.present) { + eseBcnReportMandatoryIe.cfPresent = 1; + convert_cf_params(pMac, &eseBcnReportMandatoryIe.cfParamSet, + &pBies->CFParams); + numBytes += 1 + 1 + SIR_MAC_CF_PARAM_SET_EID_MAX; + } + + if (pBies->IBSSParams.present) { + eseBcnReportMandatoryIe.ibssParamPresent = 1; + eseBcnReportMandatoryIe.ibssParamSet.atim = + pBies->IBSSParams.atim; + numBytes += 1 + 1 + SIR_MAC_IBSS_PARAM_SET_EID_MAX; + } + + if (pBies->TIM.present) { + eseBcnReportMandatoryIe.timPresent = 1; + eseBcnReportMandatoryIe.tim.dtimCount = pBies->TIM.dtim_count; + eseBcnReportMandatoryIe.tim.dtimPeriod = pBies->TIM.dtim_period; + eseBcnReportMandatoryIe.tim.bitmapControl = pBies->TIM.bmpctl; + /* As per the ESE spec, May truncate and report first 4 octets only */ + numBytes += 1 + 1 + SIR_MAC_TIM_EID_MIN; + } + + if (pBies->RRMEnabledCap.present) { + eseBcnReportMandatoryIe.rrmPresent = 1; + qdf_mem_copy(&eseBcnReportMandatoryIe.rmEnabledCapabilities, + &pBies->RRMEnabledCap, + sizeof(tDot11fIERRMEnabledCap)); + numBytes += 1 + 1 + SIR_MAC_RM_ENABLED_CAPABILITY_EID_MAX; + } + + *outIeBuf = qdf_mem_malloc(numBytes); + if (NULL == *outIeBuf) { + lim_log(pMac, LOGP, FL("Memory Allocation failure")); + qdf_mem_free(pBies); + return eSIR_MEM_ALLOC_FAILED; + } + pos = *outIeBuf; + *pOutIeLen = numBytes; + freeBytes = numBytes; + + /* Start filling the output Ie with Mandatory IE information */ + /* Fill SSID IE */ + if (eseBcnReportMandatoryIe.ssidPresent) { + if (freeBytes < (1 + 1 + eseBcnReportMandatoryIe.ssId.length)) { + lim_log(pMac, LOGP, + FL("Insufficient memory to copy SSID")); + retStatus = eSIR_FAILURE; + goto err_bcnrep; + } + *pos = SIR_MAC_SSID_EID; + pos++; + *pos = eseBcnReportMandatoryIe.ssId.length; + pos++; + qdf_mem_copy(pos, + (uint8_t *) eseBcnReportMandatoryIe.ssId.ssId, + eseBcnReportMandatoryIe.ssId.length); + pos += eseBcnReportMandatoryIe.ssId.length; + freeBytes -= (1 + 1 + eseBcnReportMandatoryIe.ssId.length); + } + + /* Fill Supported Rates IE */ + if (eseBcnReportMandatoryIe.suppRatesPresent) { + if (freeBytes < + (1 + 1 + eseBcnReportMandatoryIe.supportedRates.numRates)) { + lim_log(pMac, LOGP, + FL("Insufficient memory to copy Rates IE")); + retStatus = eSIR_FAILURE; + goto err_bcnrep; + } + if (eseBcnReportMandatoryIe.supportedRates.numRates <= + SIR_MAC_RATESET_EID_MAX) { + *pos = SIR_MAC_RATESET_EID; + pos++; + *pos = eseBcnReportMandatoryIe.supportedRates.numRates; + pos++; + qdf_mem_copy(pos, + (uint8_t *) eseBcnReportMandatoryIe.supportedRates. + rate, + eseBcnReportMandatoryIe.supportedRates.numRates); + pos += eseBcnReportMandatoryIe.supportedRates.numRates; + freeBytes -= + (1 + 1 + + eseBcnReportMandatoryIe.supportedRates.numRates); + } + } + + /* Fill FH Parameter set IE */ + if (eseBcnReportMandatoryIe.fhParamPresent) { + if (freeBytes < (1 + 1 + SIR_MAC_FH_PARAM_SET_EID_MAX)) { + lim_log(pMac, LOGP, + FL("Insufficient memory to copy FHIE")); + retStatus = eSIR_FAILURE; + goto err_bcnrep; + } + *pos = SIR_MAC_FH_PARAM_SET_EID; + pos++; + *pos = SIR_MAC_FH_PARAM_SET_EID_MAX; + pos++; + qdf_mem_copy(pos, + (uint8_t *) &eseBcnReportMandatoryIe.fhParamSet, + SIR_MAC_FH_PARAM_SET_EID_MAX); + pos += SIR_MAC_FH_PARAM_SET_EID_MAX; + freeBytes -= (1 + 1 + SIR_MAC_FH_PARAM_SET_EID_MAX); + } + + /* Fill DS Parameter set IE */ + if (eseBcnReportMandatoryIe.dsParamsPresent) { + if (freeBytes < (1 + 1 + SIR_MAC_DS_PARAM_SET_EID_MAX)) { + lim_log(pMac, LOGP, + FL("Insufficient memory to copy DS IE")); + retStatus = eSIR_FAILURE; + goto err_bcnrep; + } + *pos = SIR_MAC_DS_PARAM_SET_EID; + pos++; + *pos = SIR_MAC_DS_PARAM_SET_EID_MAX; + pos++; + *pos = eseBcnReportMandatoryIe.dsParamSet.channelNumber; + pos += SIR_MAC_DS_PARAM_SET_EID_MAX; + freeBytes -= (1 + 1 + SIR_MAC_DS_PARAM_SET_EID_MAX); + } + + /* Fill CF Parameter set */ + if (eseBcnReportMandatoryIe.cfPresent) { + if (freeBytes < (1 + 1 + SIR_MAC_CF_PARAM_SET_EID_MAX)) { + lim_log(pMac, LOGP, + FL("Insufficient memory to copy CF IE")); + retStatus = eSIR_FAILURE; + goto err_bcnrep; + } + *pos = SIR_MAC_CF_PARAM_SET_EID; + pos++; + *pos = SIR_MAC_CF_PARAM_SET_EID_MAX; + pos++; + qdf_mem_copy(pos, + (uint8_t *) &eseBcnReportMandatoryIe.cfParamSet, + SIR_MAC_CF_PARAM_SET_EID_MAX); + pos += SIR_MAC_CF_PARAM_SET_EID_MAX; + freeBytes -= (1 + 1 + SIR_MAC_CF_PARAM_SET_EID_MAX); + } + + /* Fill IBSS Parameter set IE */ + if (eseBcnReportMandatoryIe.ibssParamPresent) { + if (freeBytes < (1 + 1 + SIR_MAC_IBSS_PARAM_SET_EID_MAX)) { + lim_log(pMac, LOGP, + FL("Insufficient memory to copy IBSS IE")); + retStatus = eSIR_FAILURE; + goto err_bcnrep; + } + *pos = SIR_MAC_IBSS_PARAM_SET_EID; + pos++; + *pos = SIR_MAC_IBSS_PARAM_SET_EID_MAX; + pos++; + qdf_mem_copy(pos, + (uint8_t *) &eseBcnReportMandatoryIe.ibssParamSet. + atim, SIR_MAC_IBSS_PARAM_SET_EID_MAX); + pos += SIR_MAC_IBSS_PARAM_SET_EID_MAX; + freeBytes -= (1 + 1 + SIR_MAC_IBSS_PARAM_SET_EID_MAX); + } + + /* Fill TIM IE */ + if (eseBcnReportMandatoryIe.timPresent) { + if (freeBytes < (1 + 1 + SIR_MAC_TIM_EID_MIN)) { + lim_log(pMac, LOGP, + FL("Insufficient memory to copy TIM IE")); + retStatus = eSIR_FAILURE; + goto err_bcnrep; + } + *pos = SIR_MAC_TIM_EID; + pos++; + *pos = SIR_MAC_TIM_EID_MIN; + pos++; + qdf_mem_copy(pos, + (uint8_t *) &eseBcnReportMandatoryIe.tim, + SIR_MAC_TIM_EID_MIN); + pos += SIR_MAC_TIM_EID_MIN; + freeBytes -= (1 + 1 + SIR_MAC_TIM_EID_MIN); + } + + /* Fill RM Capability IE */ + if (eseBcnReportMandatoryIe.rrmPresent) { + if (freeBytes < (1 + 1 + SIR_MAC_RM_ENABLED_CAPABILITY_EID_MAX)) { + lim_log(pMac, LOGP, + FL("Insufficient memory to copy RRM IE")); + retStatus = eSIR_FAILURE; + goto err_bcnrep; + } + *pos = SIR_MAC_RM_ENABLED_CAPABILITY_EID; + pos++; + *pos = SIR_MAC_RM_ENABLED_CAPABILITY_EID_MAX; + pos++; + qdf_mem_copy(pos, + (uint8_t *) &eseBcnReportMandatoryIe. + rmEnabledCapabilities, + SIR_MAC_RM_ENABLED_CAPABILITY_EID_MAX); + freeBytes -= (1 + 1 + SIR_MAC_RM_ENABLED_CAPABILITY_EID_MAX); + } + + if (freeBytes != 0) { + lim_log(pMac, LOGP, + FL + ("Mismatch in allocation and copying of IE in Bcn Rep")); + retStatus = eSIR_FAILURE; + } + +err_bcnrep: + /* The message counter would not be incremented in case of + * returning failure and hence next time, this function gets + * called, it would be using the same msg ctr for a different + * BSS.So, it is good to clear the memory allocated for a BSS + * that is returning failure.On success, the caller would take + * care of freeing up the memory*/ + if (retStatus == eSIR_FAILURE) { + qdf_mem_free(*outIeBuf); + *outIeBuf = NULL; + } + + qdf_mem_free(pBies); + return retStatus; +} + +#endif /* FEATURE_WLAN_ESE */ + +tSirRetStatus +sir_parse_beacon_ie(tpAniSirGlobal pMac, + tpSirProbeRespBeacon pBeaconStruct, + uint8_t *pPayload, uint32_t nPayload) +{ + tDot11fBeaconIEs *pBies; + uint32_t status; + + /* Zero-init our [out] parameter, */ + qdf_mem_set((uint8_t *) pBeaconStruct, sizeof(tSirProbeRespBeacon), 0); + + pBies = qdf_mem_malloc(sizeof(tDot11fBeaconIEs)); + if (NULL == pBies) { + lim_log(pMac, LOGE, FL("Failed to allocate memory")); + return eSIR_MEM_ALLOC_FAILED; + } + qdf_mem_zero(pBies, sizeof(tDot11fBeaconIEs)); + /* delegate to the framesc-generated code, */ + status = dot11f_unpack_beacon_i_es(pMac, pPayload, nPayload, pBies); + + if (DOT11F_FAILED(status)) { + lim_log(pMac, LOGE, + FL("Failed to parse Beacon IEs (0x%08x, %d bytes):"), + status, nPayload); + PELOG2(sir_dump_buf + (pMac, SIR_DBG_MODULE_ID, LOG2, pPayload, nPayload); + ) + qdf_mem_free(pBies); + return eSIR_FAILURE; + } else if (DOT11F_WARNED(status)) { + lim_log(pMac, LOGW, + FL("There were warnings while unpacking Beacon IEs (0x%08x, %d bytes):"), + status, nPayload); + } + /* & "transliterate" from a 'tDot11fBeaconIEs' to a 'tSirProbeRespBeacon'... */ + if (!pBies->SSID.present) { + PELOGW(lim_log(pMac, LOGW, + FL("Mandatory IE SSID not present!"));) + } else { + pBeaconStruct->ssidPresent = 1; + convert_ssid(pMac, &pBeaconStruct->ssId, &pBies->SSID); + } + + if (!pBies->SuppRates.present) { + PELOGW(lim_log(pMac, LOGW, + FL("Mandatory IE Supported Rates not present!")); + ) + } else { + pBeaconStruct->suppRatesPresent = 1; + convert_supp_rates(pMac, &pBeaconStruct->supportedRates, + &pBies->SuppRates); + } + + if (pBies->ExtSuppRates.present) { + pBeaconStruct->extendedRatesPresent = 1; + convert_ext_supp_rates(pMac, &pBeaconStruct->extendedRates, + &pBies->ExtSuppRates); + } + + if (pBies->CFParams.present) { + pBeaconStruct->cfPresent = 1; + convert_cf_params(pMac, &pBeaconStruct->cfParamSet, + &pBies->CFParams); + } + + if (pBies->TIM.present) { + pBeaconStruct->timPresent = 1; + convert_tim(pMac, &pBeaconStruct->tim, &pBies->TIM); + } + + if (pBies->Country.present) { + pBeaconStruct->countryInfoPresent = 1; + convert_country(pMac, &pBeaconStruct->countryInfoParam, + &pBies->Country); + } + /* 11h IEs */ + if (pBies->TPCReport.present) { + pBeaconStruct->tpcReportPresent = 1; + qdf_mem_copy(&pBeaconStruct->tpcReport, + &pBies->TPCReport, sizeof(tDot11fIETPCReport)); + } + + if (pBies->PowerConstraints.present) { + pBeaconStruct->powerConstraintPresent = 1; + qdf_mem_copy(&pBeaconStruct->localPowerConstraint, + &pBies->PowerConstraints, + sizeof(tDot11fIEPowerConstraints)); + } +#ifdef FEATURE_WLAN_ESE + if (pBies->ESEVersion.present) + pBeaconStruct->is_ese_ver_ie_present = 1; + if (pBies->ESETxmitPower.present) { + pBeaconStruct->eseTxPwr.present = 1; + pBeaconStruct->eseTxPwr.power_limit = + pBies->ESETxmitPower.power_limit; + } + if (pBies->QBSSLoad.present) { + qdf_mem_copy(&pBeaconStruct->QBSSLoad, &pBies->QBSSLoad, + sizeof(tDot11fIEQBSSLoad)); + } +#endif + + if (pBies->EDCAParamSet.present) { + pBeaconStruct->edcaPresent = 1; + convert_edca_param(pMac, &pBeaconStruct->edcaParams, + &pBies->EDCAParamSet); + } + /* QOS Capabilities: */ + if (pBies->QOSCapsAp.present) { + pBeaconStruct->qosCapabilityPresent = 1; + convert_qos_caps(pMac, &pBeaconStruct->qosCapability, + &pBies->QOSCapsAp); + } + + if (pBies->ChanSwitchAnn.present) { + pBeaconStruct->channelSwitchPresent = 1; + qdf_mem_copy(&pBeaconStruct->channelSwitchIE, + &pBies->ChanSwitchAnn, + sizeof(pBeaconStruct->channelSwitchIE)); + } + + if (pBies->SuppOperatingClasses.present) { + pBeaconStruct->supp_operating_class_present = 1; + qdf_mem_copy(&pBeaconStruct->supp_operating_classes, + &pBies->SuppOperatingClasses, + sizeof(tDot11fIESuppOperatingClasses)); + } + + if (pBies->ext_chan_switch_ann.present) { + pBeaconStruct->ext_chan_switch_present = 1; + qdf_mem_copy(&pBeaconStruct->ext_chan_switch, + &pBies->ext_chan_switch_ann, + sizeof(tDot11fIEext_chan_switch_ann)); + } + + if (pBies->sec_chan_offset_ele.present) { + pBeaconStruct->sec_chan_offset_present = 1; + qdf_mem_copy(&pBeaconStruct->sec_chan_offset, + &pBies->sec_chan_offset_ele, + sizeof(pBeaconStruct->sec_chan_offset)); + } + + if (pBies->Quiet.present) { + pBeaconStruct->quietIEPresent = 1; + qdf_mem_copy(&pBeaconStruct->quietIE, &pBies->Quiet, + sizeof(tDot11fIEQuiet)); + } + + if (pBies->HTCaps.present) { + qdf_mem_copy(&pBeaconStruct->HTCaps, &pBies->HTCaps, + sizeof(tDot11fIEHTCaps)); + } + + if (pBies->HTInfo.present) { + qdf_mem_copy(&pBeaconStruct->HTInfo, &pBies->HTInfo, + sizeof(tDot11fIEHTInfo)); + } + + if (pBies->DSParams.present) { + pBeaconStruct->dsParamsPresent = 1; + pBeaconStruct->channelNumber = pBies->DSParams.curr_channel; + } else if (pBies->HTInfo.present) { + pBeaconStruct->channelNumber = pBies->HTInfo.primaryChannel; + } + + if (pBies->RSN.present) { + pBeaconStruct->rsnPresent = 1; + convert_rsn(pMac, &pBeaconStruct->rsn, &pBies->RSN); + } + + if (pBies->WPA.present) { + pBeaconStruct->wpaPresent = 1; + convert_wpa(pMac, &pBeaconStruct->wpa, &pBies->WPA); + } + + if (pBies->WMMParams.present) { + pBeaconStruct->wmeEdcaPresent = 1; + convert_wmm_params(pMac, &pBeaconStruct->edcaParams, + &pBies->WMMParams); + } + + if (pBies->WMMInfoAp.present) { + pBeaconStruct->wmeInfoPresent = 1; + } + + if (pBies->WMMCaps.present) { + pBeaconStruct->wsmCapablePresent = 1; + } + + if (pBies->ERPInfo.present) { + pBeaconStruct->erpPresent = 1; + convert_erp_info(pMac, &pBeaconStruct->erpIEInfo, + &pBies->ERPInfo); + } + if (pBies->VHTCaps.present) { + pBeaconStruct->VHTCaps.present = 1; + qdf_mem_copy(&pBeaconStruct->VHTCaps, &pBies->VHTCaps, + sizeof(tDot11fIEVHTCaps)); + } + if (pBies->VHTOperation.present) { + pBeaconStruct->VHTOperation.present = 1; + qdf_mem_copy(&pBeaconStruct->VHTOperation, &pBies->VHTOperation, + sizeof(tDot11fIEVHTOperation)); + } + if (pBies->VHTExtBssLoad.present) { + pBeaconStruct->VHTExtBssLoad.present = 1; + qdf_mem_copy(&pBeaconStruct->VHTExtBssLoad, + &pBies->VHTExtBssLoad, + sizeof(tDot11fIEVHTExtBssLoad)); + } + if (pBies->OperatingMode.present) { + pBeaconStruct->OperatingMode.present = 1; + qdf_mem_copy(&pBeaconStruct->OperatingMode, + &pBies->OperatingMode, + sizeof(tDot11fIEOperatingMode)); + } + if (pBies->MobilityDomain.present) { + pBeaconStruct->mdiePresent = 1; + qdf_mem_copy(pBeaconStruct->mdie, &pBies->MobilityDomain.MDID, + SIR_MDIE_SIZE); + } + + pBeaconStruct->Vendor1IEPresent = pBies->Vendor1IE.present; + pBeaconStruct->Vendor3IEPresent = pBies->Vendor3IE.present; + pBeaconStruct->vendor_vht_ie.present = pBies->vendor_vht_ie.present; + if (pBies->vendor_vht_ie.present) { + pBeaconStruct->vendor_vht_ie.type = pBies->vendor_vht_ie.type; + pBeaconStruct->vendor_vht_ie.sub_type = + pBies->vendor_vht_ie.sub_type; + } + + if (pBies->vendor_vht_ie.VHTCaps.present) { + pBeaconStruct->vendor_vht_ie.VHTCaps.present = 1; + qdf_mem_copy(&pBeaconStruct->vendor_vht_ie.VHTCaps, + &pBies->vendor_vht_ie.VHTCaps, + sizeof(tDot11fIEVHTCaps)); + } + if (pBies->vendor_vht_ie.VHTOperation.present) { + pBeaconStruct->vendor_vht_ie.VHTOperation.present = 1; + qdf_mem_copy(&pBeaconStruct->vendor_vht_ie.VHTOperation, + &pBies->vendor_vht_ie.VHTOperation, + sizeof(tDot11fIEVHTOperation)); + } + if (pBies->ExtCap.present) { + qdf_mem_copy(&pBeaconStruct->ext_cap, &pBies->ExtCap, + sizeof(tDot11fIEExtCap)); + } + /* Update HS 2.0 Information Element */ + if (pBies->hs20vendor_ie.present) { + lim_log(pMac, LOG1, + FL("HS20 Indication Element Present, rel#:%u, id:%u"), + pBies->hs20vendor_ie.release_num, + pBies->hs20vendor_ie.hs_id_present); + qdf_mem_copy(&pBeaconStruct->hs20vendor_ie, + &pBies->hs20vendor_ie, + sizeof(tDot11fIEhs20vendor_ie) - + sizeof(pBies->hs20vendor_ie.hs_id)); + if (pBies->hs20vendor_ie.hs_id_present) + qdf_mem_copy(&pBeaconStruct->hs20vendor_ie.hs_id, + &pBies->hs20vendor_ie.hs_id, + sizeof(pBies->hs20vendor_ie.hs_id)); + } + + if (pBies->MBO_IE.present) { + pBeaconStruct->MBO_IE_present = true; + pBeaconStruct->MBO_capability = pBies->MBO_IE.mbo_cap[2]; + + if (pBies->MBO_IE.num_assoc_disallowed && + (pBies->MBO_IE.assoc_disallowed[0] == + MBO_IE_ASSOC_DISALLOWED_SUBATTR_ID)) { + pBeaconStruct->assoc_disallowed = true; + pBeaconStruct->assoc_disallowed_reason = + pBies->MBO_IE.assoc_disallowed[2]; + } + } + + if (pBies->QCN_IE.present) { + pBeaconStruct->QCN_IE.is_present = true; + if (pBies->QCN_IE.version[0] == QCN_IE_VERSION_SUBATTR_ID) { + pBeaconStruct->QCN_IE.version + = pBies->QCN_IE.version[2]; + pBeaconStruct->QCN_IE.sub_version + = pBies->QCN_IE.version[3]; + } + } + + qdf_mem_free(pBies); + return eSIR_SUCCESS; +} /* End sir_parse_beacon_ie. */ + +tSirRetStatus +sir_convert_beacon_frame2_struct(tpAniSirGlobal pMac, + uint8_t *pFrame, + tpSirProbeRespBeacon pBeaconStruct) +{ + tDot11fBeacon *pBeacon; + uint32_t status, nPayload; + uint8_t *pPayload; + tpSirMacMgmtHdr pHdr; + uint8_t mappedRXCh; + uint8_t rfBand; + + pPayload = WMA_GET_RX_MPDU_DATA(pFrame); + nPayload = WMA_GET_RX_PAYLOAD_LEN(pFrame); + pHdr = WMA_GET_RX_MAC_HEADER(pFrame); + mappedRXCh = WMA_GET_RX_CH(pFrame); + rfBand = WMA_GET_RX_RFBAND(pFrame); + + /* Zero-init our [out] parameter, */ + qdf_mem_set((uint8_t *) pBeaconStruct, sizeof(tSirProbeRespBeacon), 0); + + pBeacon = qdf_mem_malloc(sizeof(tDot11fBeacon)); + if (NULL == pBeacon) { + lim_log(pMac, LOGE, FL("Failed to allocate memory")); + return eSIR_MEM_ALLOC_FAILED; + } + + /* get the MAC address out of the BD, */ + qdf_mem_copy(pBeaconStruct->bssid, pHdr->sa, 6); + + /* delegate to the framesc-generated code, */ + status = dot11f_unpack_beacon(pMac, pPayload, nPayload, pBeacon); + if (DOT11F_FAILED(status)) { + lim_log(pMac, LOGE, + FL("Failed to parse Beacon IEs (0x%08x, %d bytes):"), + status, nPayload); + PELOG2(sir_dump_buf + (pMac, SIR_DBG_MODULE_ID, LOG2, pPayload, nPayload); + ) + qdf_mem_free(pBeacon); + return eSIR_FAILURE; + } else if (DOT11F_WARNED(status)) { + lim_log(pMac, LOGW, + FL("There were warnings while unpacking Beacon IEs (0x%08x, %d bytes):"), + status, nPayload); + } + /* & "transliterate" from a 'tDot11fBeacon' to a 'tSirProbeRespBeacon'... */ + /* Timestamp */ + qdf_mem_copy((uint8_t *) pBeaconStruct->timeStamp, + (uint8_t *) &pBeacon->TimeStamp, + sizeof(tSirMacTimeStamp)); + + /* Beacon Interval */ + pBeaconStruct->beaconInterval = pBeacon->BeaconInterval.interval; + + /* Capabilities */ + pBeaconStruct->capabilityInfo.ess = pBeacon->Capabilities.ess; + pBeaconStruct->capabilityInfo.ibss = pBeacon->Capabilities.ibss; + pBeaconStruct->capabilityInfo.cfPollable = + pBeacon->Capabilities.cfPollable; + pBeaconStruct->capabilityInfo.cfPollReq = + pBeacon->Capabilities.cfPollReq; + pBeaconStruct->capabilityInfo.privacy = pBeacon->Capabilities.privacy; + pBeaconStruct->capabilityInfo.shortPreamble = + pBeacon->Capabilities.shortPreamble; + pBeaconStruct->capabilityInfo.pbcc = pBeacon->Capabilities.pbcc; + pBeaconStruct->capabilityInfo.channelAgility = + pBeacon->Capabilities.channelAgility; + pBeaconStruct->capabilityInfo.spectrumMgt = + pBeacon->Capabilities.spectrumMgt; + pBeaconStruct->capabilityInfo.qos = pBeacon->Capabilities.qos; + pBeaconStruct->capabilityInfo.shortSlotTime = + pBeacon->Capabilities.shortSlotTime; + pBeaconStruct->capabilityInfo.apsd = pBeacon->Capabilities.apsd; + pBeaconStruct->capabilityInfo.rrm = pBeacon->Capabilities.rrm; + pBeaconStruct->capabilityInfo.dsssOfdm = pBeacon->Capabilities.dsssOfdm; + pBeaconStruct->capabilityInfo.delayedBA = + pBeacon->Capabilities.delayedBA; + pBeaconStruct->capabilityInfo.immediateBA = + pBeacon->Capabilities.immediateBA; + + if (!pBeacon->SSID.present) { + PELOGW(lim_log(pMac, LOGW, + FL("Mandatory IE SSID not present!"));) + } else { + pBeaconStruct->ssidPresent = 1; + convert_ssid(pMac, &pBeaconStruct->ssId, &pBeacon->SSID); + } + + if (!pBeacon->SuppRates.present) { + PELOGW(lim_log(pMac, LOGW, + FL("Mandatory IE Supported Rates not present!")); + ) + } else { + pBeaconStruct->suppRatesPresent = 1; + convert_supp_rates(pMac, &pBeaconStruct->supportedRates, + &pBeacon->SuppRates); + } + + if (pBeacon->ExtSuppRates.present) { + pBeaconStruct->extendedRatesPresent = 1; + convert_ext_supp_rates(pMac, &pBeaconStruct->extendedRates, + &pBeacon->ExtSuppRates); + } + + if (pBeacon->CFParams.present) { + pBeaconStruct->cfPresent = 1; + convert_cf_params(pMac, &pBeaconStruct->cfParamSet, + &pBeacon->CFParams); + } + + if (pBeacon->TIM.present) { + pBeaconStruct->timPresent = 1; + convert_tim(pMac, &pBeaconStruct->tim, &pBeacon->TIM); + } + + if (pBeacon->Country.present) { + pBeaconStruct->countryInfoPresent = 1; + convert_country(pMac, &pBeaconStruct->countryInfoParam, + &pBeacon->Country); + } + /* QOS Capabilities: */ + if (pBeacon->QOSCapsAp.present) { + pBeaconStruct->qosCapabilityPresent = 1; + convert_qos_caps(pMac, &pBeaconStruct->qosCapability, + &pBeacon->QOSCapsAp); + } + + if (pBeacon->EDCAParamSet.present) { + pBeaconStruct->edcaPresent = 1; + convert_edca_param(pMac, &pBeaconStruct->edcaParams, + &pBeacon->EDCAParamSet); + } + + if (pBeacon->ChanSwitchAnn.present) { + pBeaconStruct->channelSwitchPresent = 1; + qdf_mem_copy(&pBeaconStruct->channelSwitchIE, + &pBeacon->ChanSwitchAnn, + sizeof(pBeaconStruct->channelSwitchIE)); + } + + if (pBeacon->ext_chan_switch_ann.present) { + pBeaconStruct->ext_chan_switch_present = 1; + qdf_mem_copy(&pBeaconStruct->ext_chan_switch, + &pBeacon->ext_chan_switch_ann, + sizeof(tDot11fIEext_chan_switch_ann)); + } + + if (pBeacon->sec_chan_offset_ele.present) { + pBeaconStruct->sec_chan_offset_present = 1; + qdf_mem_copy(&pBeaconStruct->sec_chan_offset, + &pBeacon->sec_chan_offset_ele, + sizeof(pBeaconStruct->sec_chan_offset)); + } + + if (pBeacon->TPCReport.present) { + pBeaconStruct->tpcReportPresent = 1; + qdf_mem_copy(&pBeaconStruct->tpcReport, &pBeacon->TPCReport, + sizeof(tDot11fIETPCReport)); + } + + if (pBeacon->PowerConstraints.present) { + pBeaconStruct->powerConstraintPresent = 1; + qdf_mem_copy(&pBeaconStruct->localPowerConstraint, + &pBeacon->PowerConstraints, + sizeof(tDot11fIEPowerConstraints)); + } + + if (pBeacon->Quiet.present) { + pBeaconStruct->quietIEPresent = 1; + qdf_mem_copy(&pBeaconStruct->quietIE, &pBeacon->Quiet, + sizeof(tDot11fIEQuiet)); + } + + if (pBeacon->HTCaps.present) { + qdf_mem_copy(&pBeaconStruct->HTCaps, &pBeacon->HTCaps, + sizeof(tDot11fIEHTCaps)); + } + + if (pBeacon->HTInfo.present) { + qdf_mem_copy(&pBeaconStruct->HTInfo, &pBeacon->HTInfo, + sizeof(tDot11fIEHTInfo)); + + } + + if (pBeacon->DSParams.present) { + pBeaconStruct->dsParamsPresent = 1; + pBeaconStruct->channelNumber = pBeacon->DSParams.curr_channel; + } else if (pBeacon->HTInfo.present) { + pBeaconStruct->channelNumber = pBeacon->HTInfo.primaryChannel; + } else { + pBeaconStruct->channelNumber = mappedRXCh; + lim_log(pMac, LOG1, + FL("Channel info is not present in Beacon")); + } + + if (pBeacon->RSN.present) { + pBeaconStruct->rsnPresent = 1; + convert_rsn(pMac, &pBeaconStruct->rsn, &pBeacon->RSN); + } + + if (pBeacon->WPA.present) { + pBeaconStruct->wpaPresent = 1; + convert_wpa(pMac, &pBeaconStruct->wpa, &pBeacon->WPA); + } + + if (pBeacon->WMMParams.present) { + pBeaconStruct->wmeEdcaPresent = 1; + convert_wmm_params(pMac, &pBeaconStruct->edcaParams, + &pBeacon->WMMParams); + PELOG1(lim_log + (pMac, LOG1, + FL("WMM Parameter present in Beacon Frame!")); + __print_wmm_params(pMac, &pBeacon->WMMParams); + ) + } + + if (pBeacon->WMMInfoAp.present) { + pBeaconStruct->wmeInfoPresent = 1; + PELOG1(lim_log(pMac, LOG1, + FL("WMM Info present in Beacon Frame!"));) + } + + if (pBeacon->WMMCaps.present) { + pBeaconStruct->wsmCapablePresent = 1; + } + + if (pBeacon->ERPInfo.present) { + pBeaconStruct->erpPresent = 1; + convert_erp_info(pMac, &pBeaconStruct->erpIEInfo, + &pBeacon->ERPInfo); + } + if (pBeacon->MobilityDomain.present) { + /* MobilityDomain */ + pBeaconStruct->mdiePresent = 1; + qdf_mem_copy((uint8_t *) &(pBeaconStruct->mdie[0]), + (uint8_t *) &(pBeacon->MobilityDomain.MDID), + sizeof(uint16_t)); + pBeaconStruct->mdie[2] = + ((pBeacon->MobilityDomain.overDSCap << 0) | (pBeacon-> + MobilityDomain. + resourceReqCap + << 1)); + + } + +#ifdef FEATURE_WLAN_ESE + if (pBeacon->ESEVersion.present) + pBeaconStruct->is_ese_ver_ie_present = 1; + if (pBeacon->ESETxmitPower.present) { + /* copy ESE TPC info element */ + pBeaconStruct->eseTxPwr.present = 1; + qdf_mem_copy(&pBeaconStruct->eseTxPwr, + &pBeacon->ESETxmitPower, + sizeof(tDot11fIEESETxmitPower)); + } + if (pBeacon->QBSSLoad.present) { + qdf_mem_copy(&pBeaconStruct->QBSSLoad, + &pBeacon->QBSSLoad, sizeof(tDot11fIEQBSSLoad)); + } +#endif + if (pBeacon->VHTCaps.present) { + qdf_mem_copy(&pBeaconStruct->VHTCaps, &pBeacon->VHTCaps, + sizeof(tDot11fIEVHTCaps)); + } + if (pBeacon->VHTOperation.present) { + qdf_mem_copy(&pBeaconStruct->VHTOperation, + &pBeacon->VHTOperation, + sizeof(tDot11fIEVHTOperation)); + } + if (pBeacon->VHTExtBssLoad.present) { + qdf_mem_copy(&pBeaconStruct->VHTExtBssLoad, + &pBeacon->VHTExtBssLoad, + sizeof(tDot11fIEVHTExtBssLoad)); + } + if (pBeacon->OperatingMode.present) { + qdf_mem_copy(&pBeaconStruct->OperatingMode, + &pBeacon->OperatingMode, + sizeof(tDot11fIEOperatingMode)); + } + if (pBeacon->WiderBWChanSwitchAnn.present) { + pBeaconStruct->WiderBWChanSwitchAnnPresent = 1; + qdf_mem_copy(&pBeaconStruct->WiderBWChanSwitchAnn, + &pBeacon->WiderBWChanSwitchAnn, + sizeof(tDot11fIEWiderBWChanSwitchAnn)); + } + /* IBSS Peer Params */ + if (pBeacon->IBSSParams.present) { + pBeaconStruct->IBSSParams.present = 1; + qdf_mem_copy(&pBeaconStruct->IBSSParams, &pBeacon->IBSSParams, + sizeof(tDot11fIEIBSSParams)); + } + + pBeaconStruct->Vendor1IEPresent = pBeacon->Vendor1IE.present; + pBeaconStruct->Vendor3IEPresent = pBeacon->Vendor3IE.present; + + pBeaconStruct->vendor_vht_ie.present = pBeacon->vendor_vht_ie.present; + if (pBeacon->vendor_vht_ie.present) { + pBeaconStruct->vendor_vht_ie.type = pBeacon->vendor_vht_ie.type; + pBeaconStruct->vendor_vht_ie.sub_type = + pBeacon->vendor_vht_ie.sub_type; + } + if (pBeacon->vendor_vht_ie.present) { + PELOG1(lim_log(pMac, LOG1, + FL("Vendor Specific VHT caps present in Beacon Frame!")); + ) + } + if (pBeacon->vendor_vht_ie.VHTCaps.present) { + qdf_mem_copy(&pBeaconStruct->vendor_vht_ie.VHTCaps, + &pBeacon->vendor_vht_ie.VHTCaps, + sizeof(tDot11fIEVHTCaps)); + } + if (pBeacon->vendor_vht_ie.VHTOperation.present) { + qdf_mem_copy(&pBeaconStruct->vendor_vht_ie.VHTOperation, + &pBeacon->VHTOperation, + sizeof(tDot11fIEVHTOperation)); + } + /* Update HS 2.0 Information Element */ + if (pBeacon->hs20vendor_ie.present) { + lim_log(pMac, LOG1, + FL("HS20 Indication Element Present, rel#:%u, id:%u"), + pBeacon->hs20vendor_ie.release_num, + pBeacon->hs20vendor_ie.hs_id_present); + qdf_mem_copy(&pBeaconStruct->hs20vendor_ie, + &pBeacon->hs20vendor_ie, + sizeof(tDot11fIEhs20vendor_ie) - + sizeof(pBeacon->hs20vendor_ie.hs_id)); + if (pBeacon->hs20vendor_ie.hs_id_present) + qdf_mem_copy(&pBeaconStruct->hs20vendor_ie.hs_id, + &pBeacon->hs20vendor_ie.hs_id, + sizeof(pBeacon->hs20vendor_ie.hs_id)); + } +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE + if (pBeacon->QComVendorIE.present) { + pBeaconStruct->AvoidChannelIE.present = + pBeacon->QComVendorIE.present; + pBeaconStruct->AvoidChannelIE.type = + pBeacon->QComVendorIE.type; + pBeaconStruct->AvoidChannelIE.channel = + pBeacon->QComVendorIE.channel; + } +#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ + if (pBeacon->OBSSScanParameters.present) { + qdf_mem_copy(&pBeaconStruct->obss_scanparams, + &pBeacon->OBSSScanParameters, + sizeof(struct sDot11fIEOBSSScanParameters)); + } + if (pBeacon->MBO_IE.present) { + pBeaconStruct->MBO_IE_present = true; + pBeaconStruct->MBO_capability = pBeacon->MBO_IE.mbo_cap[2]; + + if (pBeacon->MBO_IE.num_assoc_disallowed && + (pBeacon->MBO_IE.assoc_disallowed[0] == + MBO_IE_ASSOC_DISALLOWED_SUBATTR_ID)) { + pBeaconStruct->assoc_disallowed = true; + pBeaconStruct->assoc_disallowed_reason = + pBeacon->MBO_IE.assoc_disallowed[2]; + } + } + + if (pBeacon->QCN_IE.present) { + pBeaconStruct->QCN_IE.is_present = true; + if (pBeacon->QCN_IE.version[0] + == QCN_IE_VERSION_SUBATTR_ID) { + pBeaconStruct->QCN_IE.version + = pBeacon->QCN_IE.version[2]; + pBeaconStruct->QCN_IE.sub_version + = pBeacon->QCN_IE.version[3]; + } + } + + qdf_mem_free(pBeacon); + return eSIR_SUCCESS; + +} /* End sir_convert_beacon_frame2_struct. */ + +tSirRetStatus +sir_convert_auth_frame2_struct(tpAniSirGlobal pMac, + uint8_t *pFrame, + uint32_t nFrame, tpSirMacAuthFrameBody pAuth) +{ + static tDot11fAuthentication auth; + uint32_t status; + + /* Zero-init our [out] parameter, */ + qdf_mem_set((uint8_t *) pAuth, sizeof(tSirMacAuthFrameBody), 0); + + /* delegate to the framesc-generated code, */ + status = dot11f_unpack_authentication(pMac, pFrame, nFrame, &auth); + if (DOT11F_FAILED(status)) { + lim_log(pMac, LOGE, + FL("Failed to parse an Authentication frame (0x%08x, %d bytes):"), + status, nFrame); + PELOG2(sir_dump_buf + (pMac, SIR_DBG_MODULE_ID, LOG2, pFrame, nFrame); + ) + return eSIR_FAILURE; + } else if (DOT11F_WARNED(status)) { + lim_log(pMac, LOGW, + FL("There were warnings while unpacking an Authentication frame (0x%08x, %d bytes):"), + status, nFrame); + } + /* & "transliterate" from a 'tDot11fAuthentication' to a 'tSirMacAuthFrameBody'... */ + pAuth->authAlgoNumber = auth.AuthAlgo.algo; + pAuth->authTransactionSeqNumber = auth.AuthSeqNo.no; + pAuth->authStatusCode = auth.Status.status; + + if (auth.ChallengeText.present) { + pAuth->type = SIR_MAC_CHALLENGE_TEXT_EID; + pAuth->length = auth.ChallengeText.num_text; + qdf_mem_copy(pAuth->challengeText, auth.ChallengeText.text, + auth.ChallengeText.num_text); + } + + return eSIR_SUCCESS; + +} /* End sir_convert_auth_frame2_struct. */ + +tSirRetStatus +sir_convert_addts_req2_struct(tpAniSirGlobal pMac, + uint8_t *pFrame, + uint32_t nFrame, tSirAddtsReqInfo *pAddTs) +{ + tDot11fAddTSRequest addts = { {0} }; + tDot11fWMMAddTSRequest wmmaddts = { {0} }; + uint8_t j; + uint16_t i; + uint32_t status; + + if (SIR_MAC_QOS_ADD_TS_REQ != *(pFrame + 1)) { + lim_log(pMac, LOGE, FL("sir_convert_addts_req2_struct invoked " + "with an Action of %d; this is not " + "supported & is probably an error."), + *(pFrame + 1)); + return eSIR_FAILURE; + } + /* Zero-init our [out] parameter, */ + qdf_mem_set((uint8_t *) pAddTs, sizeof(tSirAddtsReqInfo), 0); + + /* delegate to the framesc-generated code, */ + switch (*pFrame) { + case SIR_MAC_ACTION_QOS_MGMT: + status = dot11f_unpack_add_ts_request(pMac, pFrame, nFrame, &addts); + break; + case SIR_MAC_ACTION_WME: + status = + dot11f_unpack_wmm_add_ts_request(pMac, pFrame, nFrame, + &wmmaddts); + break; + default: + lim_log(pMac, LOGE, FL("sir_convert_addts_req2_struct invoked " + "with a Category of %d; this is not" + " supported & is probably an error."), + *pFrame); + return eSIR_FAILURE; + } + + if (DOT11F_FAILED(status)) { + lim_log(pMac, LOGE, + FL("Failed to parse an Add TS Request frame (0x%08x, %d bytes):"), + status, nFrame); + PELOG2(sir_dump_buf + (pMac, SIR_DBG_MODULE_ID, LOG2, pFrame, nFrame); + ) + return eSIR_FAILURE; + } else if (DOT11F_WARNED(status)) { + lim_log(pMac, LOGW, + FL("There were warnings while unpacking an Add TS Request frame (0x%08x,%d bytes):"), + status, nFrame); + } + /* & "transliterate" from a 'tDot11fAddTSRequest' or a */ + /* 'tDot11WMMAddTSRequest' to a 'tSirMacAddtsReqInfo'... */ + if (SIR_MAC_ACTION_QOS_MGMT == *pFrame) { + pAddTs->dialogToken = addts.DialogToken.token; + + if (addts.TSPEC.present) { + convert_tspec(pMac, &pAddTs->tspec, &addts.TSPEC); + } else { + lim_log(pMac, LOGE, + FL("Mandatory TSPEC element missing in Add TS Request.")); + return eSIR_FAILURE; + } + + if (addts.num_TCLAS) { + pAddTs->numTclas = (uint8_t) addts.num_TCLAS; + + for (i = 0U; i < addts.num_TCLAS; ++i) { + if (eSIR_SUCCESS != + convert_tclas(pMac, &(pAddTs->tclasInfo[i]), + &(addts.TCLAS[i]))) { + lim_log(pMac, LOGE, + FL("Failed to convert a TCLAS IE.")); + return eSIR_FAILURE; + } + } + } + + if (addts.TCLASSPROC.present) { + pAddTs->tclasProcPresent = 1; + pAddTs->tclasProc = addts.TCLASSPROC.processing; + } + + if (addts.WMMTSPEC.present) { + pAddTs->wsmTspecPresent = 1; + convert_wmmtspec(pMac, &pAddTs->tspec, &addts.WMMTSPEC); + } + + if (addts.num_WMMTCLAS) { + j = (uint8_t) (pAddTs->numTclas + addts.num_WMMTCLAS); + if (SIR_MAC_TCLASIE_MAXNUM > j) + j = SIR_MAC_TCLASIE_MAXNUM; + + for (i = pAddTs->numTclas; i < j; ++i) { + if (eSIR_SUCCESS != + convert_wmmtclas(pMac, + &(pAddTs->tclasInfo[i]), + &(addts.WMMTCLAS[i]))) { + lim_log(pMac, LOGE, + FL("Failed to convert a TCLAS IE.")); + return eSIR_FAILURE; + } + } + } + + if (addts.WMMTCLASPROC.present) { + pAddTs->tclasProcPresent = 1; + pAddTs->tclasProc = addts.WMMTCLASPROC.processing; + } + + if (1 < pAddTs->numTclas && (!pAddTs->tclasProcPresent)) { + lim_log(pMac, LOGE, + FL("%d TCLAS IE but not TCLASPROC IE."), + pAddTs->numTclas); + return eSIR_FAILURE; + } + } else { + pAddTs->dialogToken = wmmaddts.DialogToken.token; + + if (wmmaddts.WMMTSPEC.present) { + pAddTs->wmeTspecPresent = 1; + convert_wmmtspec(pMac, &pAddTs->tspec, + &wmmaddts.WMMTSPEC); + } else { + lim_log(pMac, LOGE, + FL("Mandatory WME TSPEC element missing!")); + return eSIR_FAILURE; + } + } + + return eSIR_SUCCESS; + +} /* End sir_convert_addts_req2_struct. */ + +tSirRetStatus +sir_convert_addts_rsp2_struct(tpAniSirGlobal pMac, + uint8_t *pFrame, + uint32_t nFrame, tSirAddtsRspInfo *pAddTs) +{ + tDot11fAddTSResponse addts = { {0} }; + tDot11fWMMAddTSResponse wmmaddts = { {0} }; + uint8_t j; + uint16_t i; + uint32_t status; + + if (SIR_MAC_QOS_ADD_TS_RSP != *(pFrame + 1)) { + lim_log(pMac, LOGE, FL("sir_convert_addts_rsp2_struct invoked " + "with an Action of %d; this is not " + "supported & is probably an error."), + *(pFrame + 1)); + return eSIR_FAILURE; + } + /* Zero-init our [out] parameter, */ + qdf_mem_set((uint8_t *) pAddTs, sizeof(tSirAddtsRspInfo), 0); + qdf_mem_set((uint8_t *) &addts, sizeof(tDot11fAddTSResponse), 0); + qdf_mem_set((uint8_t *) &wmmaddts, sizeof(tDot11fWMMAddTSResponse), 0); + + /* delegate to the framesc-generated code, */ + switch (*pFrame) { + case SIR_MAC_ACTION_QOS_MGMT: + status = + dot11f_unpack_add_ts_response(pMac, pFrame, nFrame, &addts); + break; + case SIR_MAC_ACTION_WME: + status = + dot11f_unpack_wmm_add_ts_response(pMac, pFrame, nFrame, + &wmmaddts); + break; + default: + lim_log(pMac, LOGE, FL("sir_convert_addts_rsp2_struct invoked " + "with a Category of %d; this is not" + " supported & is probably an error."), + *pFrame); + return eSIR_FAILURE; + } + + if (DOT11F_FAILED(status)) { + lim_log(pMac, LOGE, + FL("Failed to parse an Add TS Response frame (0x%08x, %d bytes):"), + status, nFrame); + PELOG2(sir_dump_buf + (pMac, SIR_DBG_MODULE_ID, LOG2, pFrame, nFrame); + ) + return eSIR_FAILURE; + } else if (DOT11F_WARNED(status)) { + lim_log(pMac, LOGW, + FL("There were warnings while unpacking an Add TS Response frame (0x%08x,%d bytes):"), + status, nFrame); + } + /* & "transliterate" from a 'tDot11fAddTSResponse' or a */ + /* 'tDot11WMMAddTSResponse' to a 'tSirMacAddtsRspInfo'... */ + if (SIR_MAC_ACTION_QOS_MGMT == *pFrame) { + pAddTs->dialogToken = addts.DialogToken.token; + pAddTs->status = (tSirMacStatusCodes) addts.Status.status; + + if (addts.TSDelay.present) { + convert_ts_delay(pMac, &pAddTs->delay, &addts.TSDelay); + } + /* TS Delay is present iff status indicates its presence */ + if (eSIR_MAC_TS_NOT_CREATED_STATUS == pAddTs->status + && !addts.TSDelay.present) { + lim_log(pMac, LOGW, FL("Missing TSDelay IE.")); + } + + if (addts.TSPEC.present) { + convert_tspec(pMac, &pAddTs->tspec, &addts.TSPEC); + } else { + lim_log(pMac, LOGE, + FL("Mandatory TSPEC element missing in Add TS Response.")); + return eSIR_FAILURE; + } + + if (addts.num_TCLAS) { + pAddTs->numTclas = (uint8_t) addts.num_TCLAS; + + for (i = 0U; i < addts.num_TCLAS; ++i) { + if (eSIR_SUCCESS != + convert_tclas(pMac, &(pAddTs->tclasInfo[i]), + &(addts.TCLAS[i]))) { + lim_log(pMac, LOGE, + FL("Failed to convert a TCLAS IE.")); + return eSIR_FAILURE; + } + } + } + + if (addts.TCLASSPROC.present) { + pAddTs->tclasProcPresent = 1; + pAddTs->tclasProc = addts.TCLASSPROC.processing; + } +#ifdef FEATURE_WLAN_ESE + if (addts.ESETrafStrmMet.present) { + pAddTs->tsmPresent = 1; + qdf_mem_copy(&pAddTs->tsmIE.tsid, + &addts.ESETrafStrmMet.tsid, + sizeof(tSirMacESETSMIE)); + } +#endif + if (addts.Schedule.present) { + pAddTs->schedulePresent = 1; + convert_schedule(pMac, &pAddTs->schedule, + &addts.Schedule); + } + + if (addts.WMMSchedule.present) { + pAddTs->schedulePresent = 1; + convert_wmm_schedule(pMac, &pAddTs->schedule, + &addts.WMMSchedule); + } + + if (addts.WMMTSPEC.present) { + pAddTs->wsmTspecPresent = 1; + convert_wmmtspec(pMac, &pAddTs->tspec, &addts.WMMTSPEC); + } + + if (addts.num_WMMTCLAS) { + j = (uint8_t) (pAddTs->numTclas + addts.num_WMMTCLAS); + if (SIR_MAC_TCLASIE_MAXNUM > j) + j = SIR_MAC_TCLASIE_MAXNUM; + + for (i = pAddTs->numTclas; i < j; ++i) { + if (eSIR_SUCCESS != + convert_wmmtclas(pMac, + &(pAddTs->tclasInfo[i]), + &(addts.WMMTCLAS[i]))) { + lim_log(pMac, LOGE, + FL("Failed to convert a TCLAS IE.")); + return eSIR_FAILURE; + } + } + } + + if (addts.WMMTCLASPROC.present) { + pAddTs->tclasProcPresent = 1; + pAddTs->tclasProc = addts.WMMTCLASPROC.processing; + } + + if (1 < pAddTs->numTclas && (!pAddTs->tclasProcPresent)) { + lim_log(pMac, LOGE, + FL("%d TCLAS IE but not TCLASPROC IE."), + pAddTs->numTclas); + return eSIR_FAILURE; + } + } else { + pAddTs->dialogToken = wmmaddts.DialogToken.token; + pAddTs->status = + (tSirMacStatusCodes) wmmaddts.StatusCode.statusCode; + + if (wmmaddts.WMMTSPEC.present) { + pAddTs->wmeTspecPresent = 1; + convert_wmmtspec(pMac, &pAddTs->tspec, + &wmmaddts.WMMTSPEC); + } else { + lim_log(pMac, LOGE, + FL("Mandatory WME TSPEC element missing!")); + return eSIR_FAILURE; + } + +#ifdef FEATURE_WLAN_ESE + if (wmmaddts.ESETrafStrmMet.present) { + pAddTs->tsmPresent = 1; + qdf_mem_copy(&pAddTs->tsmIE.tsid, + &wmmaddts.ESETrafStrmMet.tsid, + sizeof(tSirMacESETSMIE)); + } +#endif + + } + + return eSIR_SUCCESS; + +} /* End sir_convert_addts_rsp2_struct. */ + +tSirRetStatus +sir_convert_delts_req2_struct(tpAniSirGlobal pMac, + uint8_t *pFrame, + uint32_t nFrame, tSirDeltsReqInfo *pDelTs) +{ + tDot11fDelTS delts = { {0} }; + tDot11fWMMDelTS wmmdelts = { {0} }; + uint32_t status; + + if (SIR_MAC_QOS_DEL_TS_REQ != *(pFrame + 1)) { + lim_log(pMac, LOGE, FL("sirConvertDeltsRsp2Struct invoked " + "with an Action of %d; this is not " + "supported & is probably an error."), + *(pFrame + 1)); + return eSIR_FAILURE; + } + /* Zero-init our [out] parameter, */ + qdf_mem_set((uint8_t *) pDelTs, sizeof(tSirDeltsReqInfo), 0); + + /* delegate to the framesc-generated code, */ + switch (*pFrame) { + case SIR_MAC_ACTION_QOS_MGMT: + status = dot11f_unpack_del_ts(pMac, pFrame, nFrame, &delts); + break; + case SIR_MAC_ACTION_WME: + status = dot11f_unpack_wmm_del_ts(pMac, pFrame, nFrame, &wmmdelts); + break; + default: + lim_log(pMac, LOGE, FL("sirConvertDeltsRsp2Struct invoked " + "with a Category of %d; this is not" + " supported & is probably an error."), + *pFrame); + return eSIR_FAILURE; + } + + if (DOT11F_FAILED(status)) { + lim_log(pMac, LOGE, + FL("Failed to parse an Del TS Request frame (0x%08x, %d bytes):"), + status, nFrame); + PELOG2(sir_dump_buf + (pMac, SIR_DBG_MODULE_ID, LOG2, pFrame, nFrame); + ) + return eSIR_FAILURE; + } else if (DOT11F_WARNED(status)) { + dot11f_log(pMac, LOGW, + FL("There were warnings while unpacking an Del TS Request frame (0x%08x,%d bytes):"), + status, nFrame); + } + /* & "transliterate" from a 'tDot11fDelTSResponse' or a */ + /* 'tDot11WMMDelTSResponse' to a 'tSirMacDeltsReqInfo'... */ + if (SIR_MAC_ACTION_QOS_MGMT == *pFrame) { + pDelTs->tsinfo.traffic.trafficType = + (uint16_t) delts.TSInfo.traffic_type; + pDelTs->tsinfo.traffic.tsid = (uint16_t) delts.TSInfo.tsid; + pDelTs->tsinfo.traffic.direction = + (uint16_t) delts.TSInfo.direction; + pDelTs->tsinfo.traffic.accessPolicy = + (uint16_t) delts.TSInfo.access_policy; + pDelTs->tsinfo.traffic.aggregation = + (uint16_t) delts.TSInfo.aggregation; + pDelTs->tsinfo.traffic.psb = (uint16_t) delts.TSInfo.psb; + pDelTs->tsinfo.traffic.userPrio = + (uint16_t) delts.TSInfo.user_priority; + pDelTs->tsinfo.traffic.ackPolicy = + (uint16_t) delts.TSInfo.tsinfo_ack_pol; + + pDelTs->tsinfo.schedule.schedule = + (uint8_t) delts.TSInfo.schedule; + } else { + if (wmmdelts.WMMTSPEC.present) { + pDelTs->wmeTspecPresent = 1; + convert_wmmtspec(pMac, &pDelTs->tspec, + &wmmdelts.WMMTSPEC); + } else { + dot11f_log(pMac, LOGE, + FL("Mandatory WME TSPEC element missing!")); + return eSIR_FAILURE; + } + } + + return eSIR_SUCCESS; + +} /* End sir_convert_delts_req2_struct. */ + +tSirRetStatus +sir_convert_qos_map_configure_frame2_struct(tpAniSirGlobal pMac, + uint8_t *pFrame, + uint32_t nFrame, + tSirQosMapSet *pQosMapSet) +{ + tDot11fQosMapConfigure mapConfigure; + uint32_t status; + status = + dot11f_unpack_qos_map_configure(pMac, pFrame, nFrame, &mapConfigure); + if (DOT11F_FAILED(status) || !mapConfigure.QosMapSet.present) { + dot11f_log(pMac, LOGE, + FL("Failed to parse Qos Map Configure frame (0x%08x, %d bytes):"), + status, nFrame); + PELOG2(sir_dump_buf + (pMac, SIR_DBG_MODULE_ID, LOG2, pFrame, nFrame); + ) + return eSIR_FAILURE; + } else if (DOT11F_WARNED(status)) { + dot11f_log(pMac, LOGW, + FL("There were warnings while unpacking Qos Map Configure frame (0x%08x, %d bytes):"), + status, nFrame); + } + pQosMapSet->present = mapConfigure.QosMapSet.present; + convert_qos_mapset_frame(pMac->hHdd, pQosMapSet, &mapConfigure.QosMapSet); + lim_log_qos_map_set(pMac, pQosMapSet); + return eSIR_SUCCESS; +} + +#ifdef ANI_SUPPORT_11H +tSirRetStatus +sir_convert_tpc_req_frame2_struct(tpAniSirGlobal pMac, + uint8_t *pFrame, + tpSirMacTpcReqActionFrame pTpcReqFrame, + uint32_t nFrame) +{ + tDot11fTPCRequest req; + uint32_t status; + qdf_mem_set((uint8_t *) pTpcReqFrame, sizeof(tSirMacTpcReqActionFrame), + 0); + status = dot11f_unpack_tpc_request(pMac, pFrame, nFrame, &req); + if (DOT11F_FAILED(status)) { + dot11f_log(pMac, LOGE, + FL("Failed to parse a TPC Request frame (0x%08x, %d bytes):"), + status, nFrame); + PELOG2(sir_dump_buf + (pMac, SIR_DBG_MODULE_ID, LOG2, pFrame, nFrame); + ) + return eSIR_FAILURE; + } else if (DOT11F_WARNED(status)) { + dot11f_log(pMac, LOGW, + FL("There were warnings while unpacking a TPC Request frame (0x%08x, %d bytes):"), + status, nFrame); + } + /* & "transliterate" from a 'tDot11fTPCRequest' to a */ + /* 'tSirMacTpcReqActionFrame'... */ + pTpcReqFrame->actionHeader.category = req.Category.category; + pTpcReqFrame->actionHeader.actionID = req.Action.action; + pTpcReqFrame->actionHeader.dialogToken = req.DialogToken.token; + if (req.TPCRequest.present) { + pTpcReqFrame->type = DOT11F_EID_TPCREQUEST; + pTpcReqFrame->length = 0; + } else { + dot11f_log(pMac, LOGW, FL("!!!Rcv TPC Req of inalid type!")); + return eSIR_FAILURE; + } + return eSIR_SUCCESS; +} /* End sir_convert_tpc_req_frame2_struct. */ +tSirRetStatus +sir_convert_meas_req_frame2_struct(tpAniSirGlobal pMac, + uint8_t *pFrame, + tpSirMacMeasReqActionFrame pMeasReqFrame, + uint32_t nFrame) +{ + tDot11fMeasurementRequest mr; + uint32_t status; + + /* Zero-init our [out] parameter, */ + qdf_mem_set((uint8_t *) pMeasReqFrame, + sizeof(tpSirMacMeasReqActionFrame), 0); + + /* delegate to the framesc-generated code, */ + status = dot11f_unpack_measurement_request(pMac, pFrame, nFrame, &mr); + if (DOT11F_FAILED(status)) { + dot11f_log(pMac, LOGE, + FL("Failed to parse a Measurement Request frame (0x%08x, %d bytes):"), + status, nFrame); + PELOG2(sir_dump_buf + (pMac, SIR_DBG_MODULE_ID, LOG2, pFrame, nFrame); + ) + return eSIR_FAILURE; + } else if (DOT11F_WARNED(status)) { + dot11f_log(pMac, LOGW, + FL("There were warnings while unpacking a Measurement Request frame (0x%08x, %d bytes):"), + status, nFrame); + } + /* & "transliterate" from a 'tDot11fMeasurementRequest' to a */ + /* 'tpSirMacMeasReqActionFrame'... */ + pMeasReqFrame->actionHeader.category = mr.Category.category; + pMeasReqFrame->actionHeader.actionID = mr.Action.action; + pMeasReqFrame->actionHeader.dialogToken = mr.DialogToken.token; + + if (0 == mr.num_MeasurementRequest) { + dot11f_log(pMac, LOGE, + FL("Missing mandatory IE in Measurement Request Frame.")); + return eSIR_FAILURE; + } else if (1 < mr.num_MeasurementRequest) { + lim_log(pMac, LOGW, + FL("Warning: dropping extra Measurement Request IEs!")); + } + + pMeasReqFrame->measReqIE.type = DOT11F_EID_MEASUREMENTREQUEST; + pMeasReqFrame->measReqIE.length = DOT11F_IE_MEASUREMENTREQUEST_MIN_LEN; + pMeasReqFrame->measReqIE.measToken = + mr.MeasurementRequest[0].measurement_token; + pMeasReqFrame->measReqIE.measReqMode = + (mr.MeasurementRequest[0].reserved << 3) | (mr. + MeasurementRequest[0]. + enable << 2) | (mr. + MeasurementRequest + [0]. + request + << 1) | + (mr.MeasurementRequest[0].report /*<< 0 */); + pMeasReqFrame->measReqIE.measType = + mr.MeasurementRequest[0].measurement_type; + + pMeasReqFrame->measReqIE.measReqField.channelNumber = + mr.MeasurementRequest[0].channel_no; + + qdf_mem_copy(pMeasReqFrame->measReqIE.measReqField.measStartTime, + mr.MeasurementRequest[0].meas_start_time, 8); + + pMeasReqFrame->measReqIE.measReqField.measDuration = + mr.MeasurementRequest[0].meas_duration; + + return eSIR_SUCCESS; + +} /* End sir_convert_meas_req_frame2_struct. */ +#endif + +void populate_dot11f_tspec(tSirMacTspecIE *pOld, tDot11fIETSPEC *pDot11f) +{ + pDot11f->traffic_type = pOld->tsinfo.traffic.trafficType; + pDot11f->tsid = pOld->tsinfo.traffic.tsid; + pDot11f->direction = pOld->tsinfo.traffic.direction; + pDot11f->access_policy = pOld->tsinfo.traffic.accessPolicy; + pDot11f->aggregation = pOld->tsinfo.traffic.aggregation; + pDot11f->psb = pOld->tsinfo.traffic.psb; + pDot11f->user_priority = pOld->tsinfo.traffic.userPrio; + pDot11f->tsinfo_ack_pol = pOld->tsinfo.traffic.ackPolicy; + pDot11f->schedule = pOld->tsinfo.schedule.schedule; + /* As defined in IEEE 802.11-2007, section 7.3.2.30 + * Nominal MSDU size: Bit[0:14]=Size, Bit[15]=Fixed + */ + pDot11f->size = (pOld->nomMsduSz & 0x7fff); + pDot11f->fixed = (pOld->nomMsduSz & 0x8000) ? 1 : 0; + pDot11f->max_msdu_size = pOld->maxMsduSz; + pDot11f->min_service_int = pOld->minSvcInterval; + pDot11f->max_service_int = pOld->maxSvcInterval; + pDot11f->inactivity_int = pOld->inactInterval; + pDot11f->suspension_int = pOld->suspendInterval; + pDot11f->service_start_time = pOld->svcStartTime; + pDot11f->min_data_rate = pOld->minDataRate; + pDot11f->mean_data_rate = pOld->meanDataRate; + pDot11f->peak_data_rate = pOld->peakDataRate; + pDot11f->burst_size = pOld->maxBurstSz; + pDot11f->delay_bound = pOld->delayBound; + pDot11f->min_phy_rate = pOld->minPhyRate; + pDot11f->surplus_bw_allowance = pOld->surplusBw; + pDot11f->medium_time = pOld->mediumTime; + + pDot11f->present = 1; + +} /* End populate_dot11f_tspec. */ + +void populate_dot11f_wmmtspec(tSirMacTspecIE *pOld, tDot11fIEWMMTSPEC *pDot11f) +{ + pDot11f->traffic_type = pOld->tsinfo.traffic.trafficType; + pDot11f->tsid = pOld->tsinfo.traffic.tsid; + pDot11f->direction = pOld->tsinfo.traffic.direction; + pDot11f->access_policy = pOld->tsinfo.traffic.accessPolicy; + pDot11f->aggregation = pOld->tsinfo.traffic.aggregation; + pDot11f->psb = pOld->tsinfo.traffic.psb; + pDot11f->user_priority = pOld->tsinfo.traffic.userPrio; + pDot11f->tsinfo_ack_pol = pOld->tsinfo.traffic.ackPolicy; + pDot11f->burst_size_defn = pOld->tsinfo.traffic.burstSizeDefn; + /* As defined in IEEE 802.11-2007, section 7.3.2.30 + * Nominal MSDU size: Bit[0:14]=Size, Bit[15]=Fixed + */ + pDot11f->size = (pOld->nomMsduSz & 0x7fff); + pDot11f->fixed = (pOld->nomMsduSz & 0x8000) ? 1 : 0; + pDot11f->max_msdu_size = pOld->maxMsduSz; + pDot11f->min_service_int = pOld->minSvcInterval; + pDot11f->max_service_int = pOld->maxSvcInterval; + pDot11f->inactivity_int = pOld->inactInterval; + pDot11f->suspension_int = pOld->suspendInterval; + pDot11f->service_start_time = pOld->svcStartTime; + pDot11f->min_data_rate = pOld->minDataRate; + pDot11f->mean_data_rate = pOld->meanDataRate; + pDot11f->peak_data_rate = pOld->peakDataRate; + pDot11f->burst_size = pOld->maxBurstSz; + pDot11f->delay_bound = pOld->delayBound; + pDot11f->min_phy_rate = pOld->minPhyRate; + pDot11f->surplus_bw_allowance = pOld->surplusBw; + pDot11f->medium_time = pOld->mediumTime; + + pDot11f->version = 1; + pDot11f->present = 1; + +} /* End populate_dot11f_wmmtspec. */ + +#if defined(FEATURE_WLAN_ESE) +/* Fill the ESE version currently supported */ +void populate_dot11f_ese_version(tDot11fIEESEVersion *pESEVersion) +{ + pESEVersion->present = 1; + pESEVersion->version = ESE_VERSION_SUPPORTED; +} + +/* Fill the ESE ie for the station. */ +/* The State is Normal (1) */ +/* The MBSSID for station is set to 0. */ +void populate_dot11f_ese_rad_mgmt_cap(tDot11fIEESERadMgmtCap *pESERadMgmtCap) +{ + pESERadMgmtCap->present = 1; + pESERadMgmtCap->mgmt_state = RM_STATE_NORMAL; + pESERadMgmtCap->mbssid_mask = 0; + pESERadMgmtCap->reserved = 0; +} + +tSirRetStatus populate_dot11f_ese_cckm_opaque(tpAniSirGlobal pMac, + tpSirCCKMie pCCKMie, + tDot11fIEESECckmOpaque *pDot11f) +{ + int idx; + if (pCCKMie->length) { + idx = find_ie_location(pMac, (tpSirRSNie) pCCKMie, + DOT11F_EID_ESECCKMOPAQUE); + if (0 <= idx) { + pDot11f->present = 1; + /* Dont include OUI */ + pDot11f->num_data = pCCKMie->cckmIEdata[idx + 1] - 4; + qdf_mem_copy(pDot11f->data, pCCKMie->cckmIEdata + idx + 2 + 4, /* EID,len,OUI */ + pCCKMie->cckmIEdata[idx + 1] - 4); /* Skip OUI */ + } + } + return eSIR_SUCCESS; +} /* End populate_dot11f_ese_cckm_opaque. */ + +void populate_dot11_tsrsie(tpAniSirGlobal pMac, + tSirMacESETSRSIE *pOld, + tDot11fIEESETrafStrmRateSet *pDot11f, + uint8_t rate_length) +{ + pDot11f->tsid = pOld->tsid; + qdf_mem_copy(pDot11f->tsrates, pOld->rates, rate_length); + pDot11f->num_tsrates = rate_length; + pDot11f->present = 1; +} +#endif + +tSirRetStatus +populate_dot11f_tclas(tpAniSirGlobal pMac, + tSirTclasInfo *pOld, tDot11fIETCLAS *pDot11f) +{ + pDot11f->user_priority = pOld->tclas.userPrio; + pDot11f->classifier_type = pOld->tclas.classifierType; + pDot11f->classifier_mask = pOld->tclas.classifierMask; + + switch (pDot11f->classifier_type) { + case SIR_MAC_TCLASTYPE_ETHERNET: + qdf_mem_copy((uint8_t *) &pDot11f->info.EthParams.source, + (uint8_t *) &pOld->tclasParams.eth.srcAddr, 6); + qdf_mem_copy((uint8_t *) &pDot11f->info.EthParams.dest, + (uint8_t *) &pOld->tclasParams.eth.dstAddr, 6); + pDot11f->info.EthParams.type = pOld->tclasParams.eth.type; + break; + case SIR_MAC_TCLASTYPE_TCPUDPIP: + pDot11f->info.IpParams.version = pOld->version; + if (SIR_MAC_TCLAS_IPV4 == pDot11f->info.IpParams.version) { + qdf_mem_copy(pDot11f->info.IpParams.params.IpV4Params. + source, pOld->tclasParams.ipv4.srcIpAddr, + 4); + qdf_mem_copy(pDot11f->info.IpParams.params.IpV4Params. + dest, pOld->tclasParams.ipv4.dstIpAddr, 4); + pDot11f->info.IpParams.params.IpV4Params.src_port = + pOld->tclasParams.ipv4.srcPort; + pDot11f->info.IpParams.params.IpV4Params.dest_port = + pOld->tclasParams.ipv4.dstPort; + pDot11f->info.IpParams.params.IpV4Params.DSCP = + pOld->tclasParams.ipv4.dscp; + pDot11f->info.IpParams.params.IpV4Params.proto = + pOld->tclasParams.ipv4.protocol; + pDot11f->info.IpParams.params.IpV4Params.reserved = + pOld->tclasParams.ipv4.rsvd; + } else { + qdf_mem_copy((uint8_t *) &pDot11f->info.IpParams. + params.IpV6Params.source, + (uint8_t *) pOld->tclasParams.ipv6. + srcIpAddr, 16); + qdf_mem_copy((uint8_t *) &pDot11f->info.IpParams. + params.IpV6Params.dest, + (uint8_t *) pOld->tclasParams.ipv6. + dstIpAddr, 16); + pDot11f->info.IpParams.params.IpV6Params.src_port = + pOld->tclasParams.ipv6.srcPort; + pDot11f->info.IpParams.params.IpV6Params.dest_port = + pOld->tclasParams.ipv6.dstPort; + qdf_mem_copy((uint8_t *) &pDot11f->info.IpParams. + params.IpV6Params.flow_label, + (uint8_t *) pOld->tclasParams.ipv6. + flowLabel, 3); + } + break; + case SIR_MAC_TCLASTYPE_8021DQ: + pDot11f->info.Params8021dq.tag_type = + pOld->tclasParams.t8021dq.tag; + break; + default: + lim_log(pMac, LOGE, + FL("Bad TCLAS type %d in populate_dot11f_tclas."), + pDot11f->classifier_type); + return eSIR_FAILURE; + } + + pDot11f->present = 1; + + return eSIR_SUCCESS; + +} /* End populate_dot11f_tclas. */ + +tSirRetStatus +populate_dot11f_wmmtclas(tpAniSirGlobal pMac, + tSirTclasInfo *pOld, tDot11fIEWMMTCLAS *pDot11f) +{ + pDot11f->version = 1; + pDot11f->user_priority = pOld->tclas.userPrio; + pDot11f->classifier_type = pOld->tclas.classifierType; + pDot11f->classifier_mask = pOld->tclas.classifierMask; + + switch (pDot11f->classifier_type) { + case SIR_MAC_TCLASTYPE_ETHERNET: + qdf_mem_copy((uint8_t *) &pDot11f->info.EthParams.source, + (uint8_t *) &pOld->tclasParams.eth.srcAddr, 6); + qdf_mem_copy((uint8_t *) &pDot11f->info.EthParams.dest, + (uint8_t *) &pOld->tclasParams.eth.dstAddr, 6); + pDot11f->info.EthParams.type = pOld->tclasParams.eth.type; + break; + case SIR_MAC_TCLASTYPE_TCPUDPIP: + pDot11f->info.IpParams.version = pOld->version; + if (SIR_MAC_TCLAS_IPV4 == pDot11f->info.IpParams.version) { + qdf_mem_copy((uint8_t *) &pDot11f->info.IpParams. + params.IpV4Params.source, + (uint8_t *) pOld->tclasParams.ipv4. + srcIpAddr, 4); + qdf_mem_copy((uint8_t *) &pDot11f->info.IpParams. + params.IpV4Params.dest, + (uint8_t *) pOld->tclasParams.ipv4. + dstIpAddr, 4); + pDot11f->info.IpParams.params.IpV4Params.src_port = + pOld->tclasParams.ipv4.srcPort; + pDot11f->info.IpParams.params.IpV4Params.dest_port = + pOld->tclasParams.ipv4.dstPort; + pDot11f->info.IpParams.params.IpV4Params.DSCP = + pOld->tclasParams.ipv4.dscp; + pDot11f->info.IpParams.params.IpV4Params.proto = + pOld->tclasParams.ipv4.protocol; + pDot11f->info.IpParams.params.IpV4Params.reserved = + pOld->tclasParams.ipv4.rsvd; + } else { + qdf_mem_copy((uint8_t *) &pDot11f->info.IpParams. + params.IpV6Params.source, + (uint8_t *) pOld->tclasParams.ipv6. + srcIpAddr, 16); + qdf_mem_copy((uint8_t *) &pDot11f->info.IpParams. + params.IpV6Params.dest, + (uint8_t *) pOld->tclasParams.ipv6. + dstIpAddr, 16); + pDot11f->info.IpParams.params.IpV6Params.src_port = + pOld->tclasParams.ipv6.srcPort; + pDot11f->info.IpParams.params.IpV6Params.dest_port = + pOld->tclasParams.ipv6.dstPort; + qdf_mem_copy((uint8_t *) &pDot11f->info.IpParams. + params.IpV6Params.flow_label, + (uint8_t *) pOld->tclasParams.ipv6. + flowLabel, 3); + } + break; + case SIR_MAC_TCLASTYPE_8021DQ: + pDot11f->info.Params8021dq.tag_type = + pOld->tclasParams.t8021dq.tag; + break; + default: + lim_log(pMac, LOGE, + FL("Bad TCLAS type %d in populate_dot11f_tclas."), + pDot11f->classifier_type); + return eSIR_FAILURE; + } + + pDot11f->present = 1; + + return eSIR_SUCCESS; + +} /* End populate_dot11f_wmmtclas. */ + +tSirRetStatus populate_dot11f_wsc(tpAniSirGlobal pMac, + tDot11fIEWscBeacon *pDot11f) +{ + + uint32_t wpsState; + + pDot11f->Version.present = 1; + pDot11f->Version.major = 0x01; + pDot11f->Version.minor = 0x00; + + if (wlan_cfg_get_int(pMac, (uint16_t) WNI_CFG_WPS_STATE, &wpsState) != + eSIR_SUCCESS) + lim_log(pMac, LOGP, FL("Failed to cfg get id %d"), + WNI_CFG_WPS_STATE); + + pDot11f->WPSState.present = 1; + pDot11f->WPSState.state = (uint8_t) wpsState; + + pDot11f->APSetupLocked.present = 0; + + pDot11f->SelectedRegistrar.present = 0; + + pDot11f->DevicePasswordID.present = 0; + + pDot11f->SelectedRegistrarConfigMethods.present = 0; + + pDot11f->UUID_E.present = 0; + + pDot11f->RFBands.present = 0; + + pDot11f->present = 1; + return eSIR_SUCCESS; +} + +tSirRetStatus populate_dot11f_wsc_registrar_info(tpAniSirGlobal pMac, + tDot11fIEWscBeacon *pDot11f) +{ + const struct sLimWscIeInfo *const pWscIeInfo = &(pMac->lim.wscIeInfo); + uint32_t devicepasswdId; + + pDot11f->APSetupLocked.present = 1; + pDot11f->APSetupLocked.fLocked = pWscIeInfo->apSetupLocked; + + pDot11f->SelectedRegistrar.present = 1; + pDot11f->SelectedRegistrar.selected = pWscIeInfo->selectedRegistrar; + + if (wlan_cfg_get_int + (pMac, (uint16_t) WNI_CFG_WPS_DEVICE_PASSWORD_ID, + &devicepasswdId) != eSIR_SUCCESS) + lim_log(pMac, LOGP, FL("Failed to cfg get id %d"), + WNI_CFG_WPS_DEVICE_PASSWORD_ID); + + pDot11f->DevicePasswordID.present = 1; + pDot11f->DevicePasswordID.id = (uint16_t) devicepasswdId; + + pDot11f->SelectedRegistrarConfigMethods.present = 1; + pDot11f->SelectedRegistrarConfigMethods.methods = + pWscIeInfo->selectedRegistrarConfigMethods; + + /* UUID_E and RF Bands are applicable only for dual band AP */ + + return eSIR_SUCCESS; +} + +tSirRetStatus de_populate_dot11f_wsc_registrar_info(tpAniSirGlobal pMac, + tDot11fIEWscBeacon *pDot11f) +{ + pDot11f->APSetupLocked.present = 0; + pDot11f->SelectedRegistrar.present = 0; + pDot11f->DevicePasswordID.present = 0; + pDot11f->SelectedRegistrarConfigMethods.present = 0; + + return eSIR_SUCCESS; +} + +tSirRetStatus populate_dot11f_probe_res_wpsi_es(tpAniSirGlobal pMac, + tDot11fIEWscProbeRes *pDot11f, + tpPESession psessionEntry) +{ + + tSirWPSProbeRspIE *pSirWPSProbeRspIE; + + pSirWPSProbeRspIE = &psessionEntry->APWPSIEs.SirWPSProbeRspIE; + + if (pSirWPSProbeRspIE->FieldPresent & SIR_WPS_PROBRSP_VER_PRESENT) { + pDot11f->present = 1; + pDot11f->Version.present = 1; + pDot11f->Version.major = + (uint8_t) ((pSirWPSProbeRspIE->Version & 0xF0) >> 4); + pDot11f->Version.minor = + (uint8_t) (pSirWPSProbeRspIE->Version & 0x0F); + } else { + pDot11f->present = 0; + pDot11f->Version.present = 0; + } + + if (pSirWPSProbeRspIE->FieldPresent & SIR_WPS_PROBRSP_STATE_PRESENT) { + + pDot11f->WPSState.present = 1; + pDot11f->WPSState.state = (uint8_t) pSirWPSProbeRspIE->wpsState; + } else + pDot11f->WPSState.present = 0; + + if (pSirWPSProbeRspIE-> + FieldPresent & SIR_WPS_PROBRSP_APSETUPLOCK_PRESENT) { + pDot11f->APSetupLocked.present = 1; + pDot11f->APSetupLocked.fLocked = + pSirWPSProbeRspIE->APSetupLocked; + } else + pDot11f->APSetupLocked.present = 0; + + if (pSirWPSProbeRspIE-> + FieldPresent & SIR_WPS_PROBRSP_SELECTEDREGISTRA_PRESENT) { + pDot11f->SelectedRegistrar.present = 1; + pDot11f->SelectedRegistrar.selected = + pSirWPSProbeRspIE->SelectedRegistra; + } else + pDot11f->SelectedRegistrar.present = 0; + + if (pSirWPSProbeRspIE-> + FieldPresent & SIR_WPS_PROBRSP_DEVICEPASSWORDID_PRESENT) { + pDot11f->DevicePasswordID.present = 1; + pDot11f->DevicePasswordID.id = + pSirWPSProbeRspIE->DevicePasswordID; + } else + pDot11f->DevicePasswordID.present = 0; + + if (pSirWPSProbeRspIE-> + FieldPresent & SIR_WPS_PROBRSP_SELECTEDREGISTRACFGMETHOD_PRESENT) { + pDot11f->SelectedRegistrarConfigMethods.present = 1; + pDot11f->SelectedRegistrarConfigMethods.methods = + pSirWPSProbeRspIE->SelectedRegistraCfgMethod; + } else + pDot11f->SelectedRegistrarConfigMethods.present = 0; + + if (pSirWPSProbeRspIE-> + FieldPresent & SIR_WPS_PROBRSP_RESPONSETYPE_PRESENT) { + pDot11f->ResponseType.present = 1; + pDot11f->ResponseType.resType = pSirWPSProbeRspIE->ResponseType; + } else + pDot11f->ResponseType.present = 0; + + if (pSirWPSProbeRspIE->FieldPresent & SIR_WPS_PROBRSP_UUIDE_PRESENT) { + pDot11f->UUID_E.present = 1; + qdf_mem_copy(pDot11f->UUID_E.uuid, pSirWPSProbeRspIE->UUID_E, + WNI_CFG_WPS_UUID_LEN); + } else + pDot11f->UUID_E.present = 0; + + if (pSirWPSProbeRspIE-> + FieldPresent & SIR_WPS_PROBRSP_MANUFACTURE_PRESENT) { + pDot11f->Manufacturer.present = 1; + pDot11f->Manufacturer.num_name = + pSirWPSProbeRspIE->Manufacture.num_name; + qdf_mem_copy(pDot11f->Manufacturer.name, + pSirWPSProbeRspIE->Manufacture.name, + pSirWPSProbeRspIE->Manufacture.num_name); + } else + pDot11f->Manufacturer.present = 0; + + if (pSirWPSProbeRspIE-> + FieldPresent & SIR_WPS_PROBRSP_MODELNUMBER_PRESENT) { + pDot11f->ModelName.present = 1; + pDot11f->ModelName.num_text = + pSirWPSProbeRspIE->ModelName.num_text; + qdf_mem_copy(pDot11f->ModelName.text, + pSirWPSProbeRspIE->ModelName.text, + pDot11f->ModelName.num_text); + } else + pDot11f->ModelName.present = 0; + + if (pSirWPSProbeRspIE-> + FieldPresent & SIR_WPS_PROBRSP_MODELNUMBER_PRESENT) { + pDot11f->ModelNumber.present = 1; + pDot11f->ModelNumber.num_text = + pSirWPSProbeRspIE->ModelNumber.num_text; + qdf_mem_copy(pDot11f->ModelNumber.text, + pSirWPSProbeRspIE->ModelNumber.text, + pDot11f->ModelNumber.num_text); + } else + pDot11f->ModelNumber.present = 0; + + if (pSirWPSProbeRspIE-> + FieldPresent & SIR_WPS_PROBRSP_SERIALNUMBER_PRESENT) { + pDot11f->SerialNumber.present = 1; + pDot11f->SerialNumber.num_text = + pSirWPSProbeRspIE->SerialNumber.num_text; + qdf_mem_copy(pDot11f->SerialNumber.text, + pSirWPSProbeRspIE->SerialNumber.text, + pDot11f->SerialNumber.num_text); + } else + pDot11f->SerialNumber.present = 0; + + if (pSirWPSProbeRspIE-> + FieldPresent & SIR_WPS_PROBRSP_PRIMARYDEVICETYPE_PRESENT) { + pDot11f->PrimaryDeviceType.present = 1; + qdf_mem_copy(pDot11f->PrimaryDeviceType.oui, + pSirWPSProbeRspIE->PrimaryDeviceOUI, + sizeof(pSirWPSProbeRspIE->PrimaryDeviceOUI)); + pDot11f->PrimaryDeviceType.primary_category = + (uint16_t) pSirWPSProbeRspIE->PrimaryDeviceCategory; + pDot11f->PrimaryDeviceType.sub_category = + (uint16_t) pSirWPSProbeRspIE->DeviceSubCategory; + } else + pDot11f->PrimaryDeviceType.present = 0; + + if (pSirWPSProbeRspIE-> + FieldPresent & SIR_WPS_PROBRSP_DEVICENAME_PRESENT) { + pDot11f->DeviceName.present = 1; + pDot11f->DeviceName.num_text = + pSirWPSProbeRspIE->DeviceName.num_text; + qdf_mem_copy(pDot11f->DeviceName.text, + pSirWPSProbeRspIE->DeviceName.text, + pDot11f->DeviceName.num_text); + } else + pDot11f->DeviceName.present = 0; + + if (pSirWPSProbeRspIE-> + FieldPresent & SIR_WPS_PROBRSP_CONFIGMETHODS_PRESENT) { + pDot11f->ConfigMethods.present = 1; + pDot11f->ConfigMethods.methods = + pSirWPSProbeRspIE->ConfigMethod; + } else + pDot11f->ConfigMethods.present = 0; + + if (pSirWPSProbeRspIE->FieldPresent & SIR_WPS_PROBRSP_RF_BANDS_PRESENT) { + pDot11f->RFBands.present = 1; + pDot11f->RFBands.bands = pSirWPSProbeRspIE->RFBand; + } else + pDot11f->RFBands.present = 0; + + return eSIR_SUCCESS; +} + +tSirRetStatus populate_dot11f_assoc_res_wpsi_es(tpAniSirGlobal pMac, + tDot11fIEWscAssocRes *pDot11f, + tpPESession psessionEntry) +{ + tSirWPSProbeRspIE *pSirWPSProbeRspIE; + + pSirWPSProbeRspIE = &psessionEntry->APWPSIEs.SirWPSProbeRspIE; + + if (pSirWPSProbeRspIE->FieldPresent & SIR_WPS_PROBRSP_VER_PRESENT) { + pDot11f->present = 1; + pDot11f->Version.present = 1; + pDot11f->Version.major = + (uint8_t) ((pSirWPSProbeRspIE->Version & 0xF0) >> 4); + pDot11f->Version.minor = + (uint8_t) (pSirWPSProbeRspIE->Version & 0x0F); + } else { + pDot11f->present = 0; + pDot11f->Version.present = 0; + } + + if (pSirWPSProbeRspIE-> + FieldPresent & SIR_WPS_PROBRSP_RESPONSETYPE_PRESENT) { + pDot11f->ResponseType.present = 1; + pDot11f->ResponseType.resType = pSirWPSProbeRspIE->ResponseType; + } else + pDot11f->ResponseType.present = 0; + + return eSIR_SUCCESS; +} + +tSirRetStatus populate_dot11f_beacon_wpsi_es(tpAniSirGlobal pMac, + tDot11fIEWscBeacon *pDot11f, + tpPESession psessionEntry) +{ + + tSirWPSBeaconIE *pSirWPSBeaconIE; + + pSirWPSBeaconIE = &psessionEntry->APWPSIEs.SirWPSBeaconIE; + + if (pSirWPSBeaconIE->FieldPresent & SIR_WPS_PROBRSP_VER_PRESENT) { + pDot11f->present = 1; + pDot11f->Version.present = 1; + pDot11f->Version.major = + (uint8_t) ((pSirWPSBeaconIE->Version & 0xF0) >> 4); + pDot11f->Version.minor = + (uint8_t) (pSirWPSBeaconIE->Version & 0x0F); + } else { + pDot11f->present = 0; + pDot11f->Version.present = 0; + } + + if (pSirWPSBeaconIE->FieldPresent & SIR_WPS_BEACON_STATE_PRESENT) { + + pDot11f->WPSState.present = 1; + pDot11f->WPSState.state = (uint8_t) pSirWPSBeaconIE->wpsState; + } else + pDot11f->WPSState.present = 0; + + if (pSirWPSBeaconIE->FieldPresent & SIR_WPS_BEACON_APSETUPLOCK_PRESENT) { + pDot11f->APSetupLocked.present = 1; + pDot11f->APSetupLocked.fLocked = pSirWPSBeaconIE->APSetupLocked; + } else + pDot11f->APSetupLocked.present = 0; + + if (pSirWPSBeaconIE-> + FieldPresent & SIR_WPS_BEACON_SELECTEDREGISTRA_PRESENT) { + pDot11f->SelectedRegistrar.present = 1; + pDot11f->SelectedRegistrar.selected = + pSirWPSBeaconIE->SelectedRegistra; + } else + pDot11f->SelectedRegistrar.present = 0; + + if (pSirWPSBeaconIE-> + FieldPresent & SIR_WPS_BEACON_DEVICEPASSWORDID_PRESENT) { + pDot11f->DevicePasswordID.present = 1; + pDot11f->DevicePasswordID.id = + pSirWPSBeaconIE->DevicePasswordID; + } else + pDot11f->DevicePasswordID.present = 0; + + if (pSirWPSBeaconIE-> + FieldPresent & SIR_WPS_BEACON_SELECTEDREGISTRACFGMETHOD_PRESENT) { + pDot11f->SelectedRegistrarConfigMethods.present = 1; + pDot11f->SelectedRegistrarConfigMethods.methods = + pSirWPSBeaconIE->SelectedRegistraCfgMethod; + } else + pDot11f->SelectedRegistrarConfigMethods.present = 0; + + if (pSirWPSBeaconIE->FieldPresent & SIR_WPS_BEACON_UUIDE_PRESENT) { + pDot11f->UUID_E.present = 1; + qdf_mem_copy(pDot11f->UUID_E.uuid, pSirWPSBeaconIE->UUID_E, + WNI_CFG_WPS_UUID_LEN); + } else + pDot11f->UUID_E.present = 0; + + if (pSirWPSBeaconIE->FieldPresent & SIR_WPS_BEACON_RF_BANDS_PRESENT) { + pDot11f->RFBands.present = 1; + pDot11f->RFBands.bands = pSirWPSBeaconIE->RFBand; + } else + pDot11f->RFBands.present = 0; + + return eSIR_SUCCESS; +} + +tSirRetStatus populate_dot11f_wsc_in_probe_res(tpAniSirGlobal pMac, + tDot11fIEWscProbeRes *pDot11f) +{ + uint32_t cfgMethods; + uint32_t cfgStrLen; + uint32_t val; + uint32_t wpsVersion, wpsState; + + if (wlan_cfg_get_int(pMac, (uint16_t) WNI_CFG_WPS_VERSION, &wpsVersion) != + eSIR_SUCCESS) + lim_log(pMac, LOGP, FL("Failed to cfg get id %d"), + WNI_CFG_WPS_VERSION); + + pDot11f->Version.present = 1; + pDot11f->Version.major = (uint8_t) ((wpsVersion & 0xF0) >> 4); + pDot11f->Version.minor = (uint8_t) (wpsVersion & 0x0F); + + if (wlan_cfg_get_int(pMac, (uint16_t) WNI_CFG_WPS_STATE, &wpsState) != + eSIR_SUCCESS) + lim_log(pMac, LOGP, FL("Failed to cfg get id %d"), + WNI_CFG_WPS_STATE); + + pDot11f->WPSState.present = 1; + pDot11f->WPSState.state = (uint8_t) wpsState; + + pDot11f->APSetupLocked.present = 0; + + pDot11f->SelectedRegistrar.present = 0; + + pDot11f->DevicePasswordID.present = 0; + + pDot11f->SelectedRegistrarConfigMethods.present = 0; + + pDot11f->ResponseType.present = 1; + if ((pMac->lim.wscIeInfo.reqType == REQ_TYPE_REGISTRAR) || + (pMac->lim.wscIeInfo.reqType == REQ_TYPE_WLAN_MANAGER_REGISTRAR)) { + pDot11f->ResponseType.resType = RESP_TYPE_ENROLLEE_OPEN_8021X; + } else { + pDot11f->ResponseType.resType = RESP_TYPE_AP; + } + + /* UUID is a 16 byte long binary. Still use wlan_cfg_get_str to get it. */ + pDot11f->UUID_E.present = 1; + cfgStrLen = WNI_CFG_WPS_UUID_LEN; + if (wlan_cfg_get_str(pMac, + WNI_CFG_WPS_UUID, + pDot11f->UUID_E.uuid, &cfgStrLen) != eSIR_SUCCESS) { + *(pDot11f->UUID_E.uuid) = '\0'; + } + + pDot11f->Manufacturer.present = 1; + cfgStrLen = WNI_CFG_MANUFACTURER_NAME_LEN; + if (wlan_cfg_get_str(pMac, + WNI_CFG_MANUFACTURER_NAME, + pDot11f->Manufacturer.name, + &cfgStrLen) != eSIR_SUCCESS) { + pDot11f->Manufacturer.num_name = 0; + } else { + pDot11f->Manufacturer.num_name = + (uint8_t) (cfgStrLen & 0x000000FF); + } + + pDot11f->ModelName.present = 1; + cfgStrLen = WNI_CFG_MODEL_NAME_LEN; + if (wlan_cfg_get_str(pMac, + WNI_CFG_MODEL_NAME, + pDot11f->ModelName.text, + &cfgStrLen) != eSIR_SUCCESS) { + pDot11f->ModelName.num_text = 0; + } else { + pDot11f->ModelName.num_text = + (uint8_t) (cfgStrLen & 0x000000FF); + } + + pDot11f->ModelNumber.present = 1; + cfgStrLen = WNI_CFG_MODEL_NUMBER_LEN; + if (wlan_cfg_get_str(pMac, + WNI_CFG_MODEL_NUMBER, + pDot11f->ModelNumber.text, + &cfgStrLen) != eSIR_SUCCESS) { + pDot11f->ModelNumber.num_text = 0; + } else { + pDot11f->ModelNumber.num_text = + (uint8_t) (cfgStrLen & 0x000000FF); + } + + pDot11f->SerialNumber.present = 1; + cfgStrLen = WNI_CFG_MANUFACTURER_PRODUCT_VERSION_LEN; + if (wlan_cfg_get_str(pMac, + WNI_CFG_MANUFACTURER_PRODUCT_VERSION, + pDot11f->SerialNumber.text, + &cfgStrLen) != eSIR_SUCCESS) { + pDot11f->SerialNumber.num_text = 0; + } else { + pDot11f->SerialNumber.num_text = + (uint8_t) (cfgStrLen & 0x000000FF); + } + + pDot11f->PrimaryDeviceType.present = 1; + + if (wlan_cfg_get_int(pMac, WNI_CFG_WPS_PRIMARY_DEVICE_CATEGORY, &val) != + eSIR_SUCCESS) { + lim_log(pMac, LOGP, FL("cfg get prim device category failed")); + } else + pDot11f->PrimaryDeviceType.primary_category = (uint16_t) val; + + if (wlan_cfg_get_int(pMac, WNI_CFG_WPS_PIMARY_DEVICE_OUI, &val) != + eSIR_SUCCESS) { + lim_log(pMac, LOGP, FL("cfg get prim device OUI failed")); + } else { + *(pDot11f->PrimaryDeviceType.oui) = + (uint8_t) ((val >> 24) & 0xff); + *(pDot11f->PrimaryDeviceType.oui + 1) = + (uint8_t) ((val >> 16) & 0xff); + *(pDot11f->PrimaryDeviceType.oui + 2) = + (uint8_t) ((val >> 8) & 0xff); + *(pDot11f->PrimaryDeviceType.oui + 3) = + (uint8_t) ((val & 0xff)); + } + + if (wlan_cfg_get_int(pMac, WNI_CFG_WPS_DEVICE_SUB_CATEGORY, &val) != + eSIR_SUCCESS) { + lim_log(pMac, LOGP, + FL("cfg get prim device sub category failed")); + } else + pDot11f->PrimaryDeviceType.sub_category = (uint16_t) val; + + pDot11f->DeviceName.present = 1; + cfgStrLen = WNI_CFG_MANUFACTURER_PRODUCT_NAME_LEN; + if (wlan_cfg_get_str(pMac, + WNI_CFG_MANUFACTURER_PRODUCT_NAME, + pDot11f->DeviceName.text, + &cfgStrLen) != eSIR_SUCCESS) { + pDot11f->DeviceName.num_text = 0; + } else { + pDot11f->DeviceName.num_text = + (uint8_t) (cfgStrLen & 0x000000FF); + } + + if (wlan_cfg_get_int(pMac, + WNI_CFG_WPS_CFG_METHOD, + &cfgMethods) != eSIR_SUCCESS) { + pDot11f->ConfigMethods.present = 0; + pDot11f->ConfigMethods.methods = 0; + } else { + pDot11f->ConfigMethods.present = 1; + pDot11f->ConfigMethods.methods = + (uint16_t) (cfgMethods & 0x0000FFFF); + } + + pDot11f->RFBands.present = 0; + + pDot11f->present = 1; + return eSIR_SUCCESS; +} + +tSirRetStatus populate_dot11f_wsc_registrar_info_in_probe_res(tpAniSirGlobal pMac, + tDot11fIEWscProbeRes * + pDot11f) +{ + const struct sLimWscIeInfo *const pWscIeInfo = &(pMac->lim.wscIeInfo); + uint32_t devicepasswdId; + + pDot11f->APSetupLocked.present = 1; + pDot11f->APSetupLocked.fLocked = pWscIeInfo->apSetupLocked; + + pDot11f->SelectedRegistrar.present = 1; + pDot11f->SelectedRegistrar.selected = pWscIeInfo->selectedRegistrar; + + if (wlan_cfg_get_int + (pMac, (uint16_t) WNI_CFG_WPS_DEVICE_PASSWORD_ID, + &devicepasswdId) != eSIR_SUCCESS) + lim_log(pMac, LOGP, FL("Failed to cfg get id %d"), + WNI_CFG_WPS_DEVICE_PASSWORD_ID); + + pDot11f->DevicePasswordID.present = 1; + pDot11f->DevicePasswordID.id = (uint16_t) devicepasswdId; + + pDot11f->SelectedRegistrarConfigMethods.present = 1; + pDot11f->SelectedRegistrarConfigMethods.methods = + pWscIeInfo->selectedRegistrarConfigMethods; + + /* UUID_E and RF Bands are applicable only for dual band AP */ + + return eSIR_SUCCESS; +} + +tSirRetStatus de_populate_dot11f_wsc_registrar_info_in_probe_res(tpAniSirGlobal pMac, + tDot11fIEWscProbeRes * + pDot11f) +{ + pDot11f->APSetupLocked.present = 0; + pDot11f->SelectedRegistrar.present = 0; + pDot11f->DevicePasswordID.present = 0; + pDot11f->SelectedRegistrarConfigMethods.present = 0; + + return eSIR_SUCCESS; +} + +tSirRetStatus populate_dot11f_assoc_res_wsc_ie(tpAniSirGlobal pMac, + tDot11fIEWscAssocRes *pDot11f, + tpSirAssocReq pRcvdAssocReq) +{ + tDot11fIEWscAssocReq parsedWscAssocReq = { 0, }; + uint8_t *wscIe; + + wscIe = + limGetWscIEPtr(pMac, pRcvdAssocReq->addIE.addIEdata, + pRcvdAssocReq->addIE.length); + if (wscIe != NULL) { + /* retreive WSC IE from given AssocReq */ + dot11f_unpack_ie_wsc_assoc_req(pMac, wscIe + 2 + 4, /* EID, length, OUI */ + wscIe[1] - 4, /* length without OUI */ + &parsedWscAssocReq); + pDot11f->present = 1; + /* version has to be 0x10 */ + pDot11f->Version.present = 1; + pDot11f->Version.major = 0x1; + pDot11f->Version.minor = 0x0; + + pDot11f->ResponseType.present = 1; + + if ((parsedWscAssocReq.RequestType.reqType == + REQ_TYPE_REGISTRAR) + || (parsedWscAssocReq.RequestType.reqType == + REQ_TYPE_WLAN_MANAGER_REGISTRAR)) { + pDot11f->ResponseType.resType = + RESP_TYPE_ENROLLEE_OPEN_8021X; + } else { + pDot11f->ResponseType.resType = RESP_TYPE_AP; + } + /* Version infomration should be taken from our capability as well as peers */ + /* TODO: currently it takes from peers only */ + if (parsedWscAssocReq.VendorExtension.present && + parsedWscAssocReq.VendorExtension.Version2.present) { + pDot11f->VendorExtension.present = 1; + pDot11f->VendorExtension.vendorId[0] = 0x00; + pDot11f->VendorExtension.vendorId[1] = 0x37; + pDot11f->VendorExtension.vendorId[2] = 0x2A; + pDot11f->VendorExtension.Version2.present = 1; + pDot11f->VendorExtension.Version2.major = + parsedWscAssocReq.VendorExtension.Version2.major; + pDot11f->VendorExtension.Version2.minor = + parsedWscAssocReq.VendorExtension.Version2.minor; + } + } + return eSIR_SUCCESS; +} + +tSirRetStatus populate_dot11_assoc_res_p2p_ie(tpAniSirGlobal pMac, + tDot11fIEP2PAssocRes *pDot11f, + tpSirAssocReq pRcvdAssocReq) +{ + uint8_t *p2pIe; + + p2pIe = + limGetP2pIEPtr(pMac, pRcvdAssocReq->addIE.addIEdata, + pRcvdAssocReq->addIE.length); + if (p2pIe != NULL) { + pDot11f->present = 1; + pDot11f->P2PStatus.present = 1; + pDot11f->P2PStatus.status = eSIR_SUCCESS; + pDot11f->ExtendedListenTiming.present = 0; + } + return eSIR_SUCCESS; +} + + +tSirRetStatus populate_dot11f_wfatpc(tpAniSirGlobal pMac, + tDot11fIEWFATPC *pDot11f, uint8_t txPower, + uint8_t linkMargin) +{ + pDot11f->txPower = txPower; + pDot11f->linkMargin = linkMargin; + pDot11f->present = 1; + + return eSIR_SUCCESS; +} + +tSirRetStatus populate_dot11f_beacon_report(tpAniSirGlobal pMac, + tDot11fIEMeasurementReport *pDot11f, + tSirMacBeaconReport *pBeaconReport) +{ + + pDot11f->report.Beacon.regClass = pBeaconReport->regClass; + pDot11f->report.Beacon.channel = pBeaconReport->channel; + qdf_mem_copy(pDot11f->report.Beacon.meas_start_time, + pBeaconReport->measStartTime, + sizeof(pDot11f->report.Beacon.meas_start_time)); + pDot11f->report.Beacon.meas_duration = pBeaconReport->measDuration; + pDot11f->report.Beacon.condensed_PHY = pBeaconReport->phyType; + pDot11f->report.Beacon.reported_frame_type = + !pBeaconReport->bcnProbeRsp; + pDot11f->report.Beacon.RCPI = pBeaconReport->rcpi; + pDot11f->report.Beacon.RSNI = pBeaconReport->rsni; + qdf_mem_copy(pDot11f->report.Beacon.BSSID, pBeaconReport->bssid, + sizeof(tSirMacAddr)); + pDot11f->report.Beacon.antenna_id = pBeaconReport->antennaId; + pDot11f->report.Beacon.parent_TSF = pBeaconReport->parentTSF; + + if (pBeaconReport->numIes) { + pDot11f->report.Beacon.BeaconReportFrmBody.present = 1; + qdf_mem_copy(pDot11f->report.Beacon.BeaconReportFrmBody. + reportedFields, pBeaconReport->Ies, + pBeaconReport->numIes); + pDot11f->report.Beacon.BeaconReportFrmBody.num_reportedFields = + pBeaconReport->numIes; + } + + return eSIR_SUCCESS; + +} + +tSirRetStatus populate_dot11f_rrm_ie(tpAniSirGlobal pMac, + tDot11fIERRMEnabledCap *pDot11f, + tpPESession psessionEntry) +{ + tpRRMCaps pRrmCaps; + uint8_t *bytes; + + pRrmCaps = rrm_get_capabilities(pMac, psessionEntry); + + pDot11f->LinkMeasurement = pRrmCaps->LinkMeasurement; + pDot11f->NeighborRpt = pRrmCaps->NeighborRpt; + pDot11f->parallel = pRrmCaps->parallel; + pDot11f->repeated = pRrmCaps->repeated; + pDot11f->BeaconPassive = pRrmCaps->BeaconPassive; + pDot11f->BeaconActive = pRrmCaps->BeaconActive; + pDot11f->BeaconTable = pRrmCaps->BeaconTable; + pDot11f->BeaconRepCond = pRrmCaps->BeaconRepCond; + pDot11f->FrameMeasurement = pRrmCaps->FrameMeasurement; + pDot11f->ChannelLoad = pRrmCaps->ChannelLoad; + pDot11f->NoiseHistogram = pRrmCaps->NoiseHistogram; + pDot11f->statistics = pRrmCaps->statistics; + pDot11f->LCIMeasurement = pRrmCaps->LCIMeasurement; + pDot11f->LCIAzimuth = pRrmCaps->LCIAzimuth; + pDot11f->TCMCapability = pRrmCaps->TCMCapability; + pDot11f->triggeredTCM = pRrmCaps->triggeredTCM; + pDot11f->APChanReport = pRrmCaps->APChanReport; + pDot11f->RRMMIBEnabled = pRrmCaps->RRMMIBEnabled; + pDot11f->operatingChanMax = pRrmCaps->operatingChanMax; + pDot11f->nonOperatinChanMax = pRrmCaps->nonOperatingChanMax; + pDot11f->MeasurementPilot = pRrmCaps->MeasurementPilot; + pDot11f->MeasurementPilotEnabled = pRrmCaps->MeasurementPilotEnabled; + pDot11f->NeighborTSFOffset = pRrmCaps->NeighborTSFOffset; + pDot11f->RCPIMeasurement = pRrmCaps->RCPIMeasurement; + pDot11f->RSNIMeasurement = pRrmCaps->RSNIMeasurement; + pDot11f->BssAvgAccessDelay = pRrmCaps->BssAvgAccessDelay; + pDot11f->BSSAvailAdmission = pRrmCaps->BSSAvailAdmission; + pDot11f->AntennaInformation = pRrmCaps->AntennaInformation; + pDot11f->fine_time_meas_rpt = pRrmCaps->fine_time_meas_rpt; + pDot11f->lci_capability = pRrmCaps->lci_capability; + pDot11f->reserved = pRrmCaps->reserved; + + bytes = (uint8_t *) pDot11f + 1; /* ignore present field */ + lim_log(pMac, LOG1, FL("RRM Enabled Cap IE: %02x %02x %02x %02x %02x"), + bytes[0], bytes[1], bytes[2], bytes[3], bytes[4]); + + pDot11f->present = 1; + return eSIR_SUCCESS; +} + +void populate_mdie(tpAniSirGlobal pMac, + tDot11fIEMobilityDomain *pDot11f, + uint8_t mdie[SIR_MDIE_SIZE]) +{ + pDot11f->present = 1; + pDot11f->MDID = (uint16_t) ((mdie[1] << 8) | (mdie[0])); + + /* Plugfest fix */ + pDot11f->overDSCap = (mdie[2] & 0x01); + pDot11f->resourceReqCap = ((mdie[2] >> 1) & 0x01); + +} + +void populate_ft_info(tpAniSirGlobal pMac, tDot11fIEFTInfo *pDot11f) +{ + pDot11f->present = 1; + pDot11f->IECount = 0; /* TODO: put valid data during reassoc. */ + /* All other info is zero. */ + +} + +void populate_dot11f_assoc_rsp_rates(tpAniSirGlobal pMac, + tDot11fIESuppRates *pSupp, + tDot11fIEExtSuppRates *pExt, + uint16_t *_11bRates, uint16_t *_11aRates) +{ + uint8_t num_supp = 0, num_ext = 0; + uint8_t i, j; + + for (i = 0; (i < SIR_NUM_11B_RATES && _11bRates[i]); i++, num_supp++) { + pSupp->rates[num_supp] = (uint8_t) _11bRates[i]; + } + for (j = 0; (j < SIR_NUM_11A_RATES && _11aRates[j]); j++) { + if (num_supp < 8) + pSupp->rates[num_supp++] = (uint8_t) _11aRates[j]; + else + pExt->rates[num_ext++] = (uint8_t) _11aRates[j]; + } + + if (num_supp) { + pSupp->num_rates = num_supp; + pSupp->present = 1; + } + if (num_ext) { + pExt->num_rates = num_ext; + pExt->present = 1; + } +} + +void populate_dot11f_timeout_interval(tpAniSirGlobal pMac, + tDot11fIETimeoutInterval *pDot11f, + uint8_t type, uint32_t value) +{ + pDot11f->present = 1; + pDot11f->timeoutType = type; + pDot11f->timeoutValue = value; +} + +/** + * populate_dot11f_timing_advert_frame() - Populate the TA mgmt frame fields + * @pMac: the MAC context + * @frame: pointer to the TA frame + * + * Return: The SIR status. + */ +tSirRetStatus populate_dot11f_timing_advert_frame(tpAniSirGlobal mac_ctx, + tDot11fTimingAdvertisementFrame *frame) +{ + uint32_t val, codelen, len; + uint16_t item; + uint8_t temp[CFG_MAX_STR_LEN], code[3]; + tSirRetStatus nSirStatus; + + /* Capabilities */ + wlan_cfg_get_int(mac_ctx, WNI_CFG_PRIVACY_ENABLED, &val); + if (val) + frame->Capabilities.privacy = 1; + + wlan_cfg_get_int(mac_ctx, WNI_CFG_SHORT_PREAMBLE, &val); + if (val) + frame->Capabilities.shortPreamble = 1; + + wlan_cfg_get_int(mac_ctx, WNI_CFG_11H_ENABLED, &val); + if (val) + frame->Capabilities.spectrumMgt = 1; + + wlan_cfg_get_int(mac_ctx, WNI_CFG_QOS_ENABLED, &val); + if (val) + frame->Capabilities.qos = 1; + + wlan_cfg_get_int(mac_ctx, WNI_CFG_APSD_ENABLED, &val); + if (val) + frame->Capabilities.apsd = 1; + + wlan_cfg_get_int(mac_ctx, WNI_CFG_BLOCK_ACK_ENABLED, &val); + frame->Capabilities.delayedBA = + (uint16_t)((val >> WNI_CFG_BLOCK_ACK_ENABLED_DELAYED) & 1); + frame->Capabilities.immediateBA = + (uint16_t)((val >> WNI_CFG_BLOCK_ACK_ENABLED_IMMEDIATE) & 1); + + /* Country */ + item = WNI_CFG_MAX_TX_POWER_5; + CFG_GET_STR(nSirStatus, mac_ctx, item, temp, len, + WNI_CFG_MAX_TX_POWER_5_LEN); + item = WNI_CFG_COUNTRY_CODE; + CFG_GET_STR(nSirStatus, mac_ctx, item, code, codelen, 3); + qdf_mem_copy(&frame->Country, code, codelen); + if (len > MAX_SIZE_OF_TRIPLETS_IN_COUNTRY_IE) + len = MAX_SIZE_OF_TRIPLETS_IN_COUNTRY_IE; + + frame->Country.num_triplets = (uint8_t)(len / 3); + qdf_mem_copy((uint8_t *)&frame->Country.triplets, temp, len); + frame->Country.present = 1; + + /* PowerConstraints */ + wlan_cfg_get_int(mac_ctx, WNI_CFG_LOCAL_POWER_CONSTRAINT, &val); + frame->PowerConstraints.localPowerConstraints = (uint8_t)val; + frame->PowerConstraints.present = 1; + + /* TimeAdvertisement */ + frame->TimeAdvertisement.present = 1; + frame->TimeAdvertisement.timing_capabilities = 1; + + return nSirStatus; +} + +/* parser_api.c ends here. */ diff --git a/drivers/staging/qcacld-3.0/core/mac/src/sys/legacy/src/utils/src/utils_api.c b/drivers/staging/qcacld-3.0/core/mac/src/sys/legacy/src/utils/src/utils_api.c new file mode 100644 index 0000000000000000000000000000000000000000..524bbd217fd687a50a9388d08cb2e9c2e2349c42 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/sys/legacy/src/utils/src/utils_api.c @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2013-2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* ================================================================== */ +/* */ +/* File: utils_api.cc */ +/* */ +/* Description: Implemention of a few utility routines. */ +/* */ +/* Author: Neelay Das */ +/* */ +/* // */ +/* Change gHistory: */ +/* 12/15/2003 - NDA - Initial version. */ +/* */ +/* =================================================================== */ + +#include "utils_api.h" + +/* ------------------------------------------------------------------- */ +/** + * sir_dump_buf() + * + * FUNCTION: + * This function is called to dump a buffer with a certain level + * + * LOGIC: + * + * ASSUMPTIONS: + * None. + * + * NOTE: + * + * @param pBuf: buffer pointer + * @return None. + */ +void +sir_dump_buf(tpAniSirGlobal pMac, uint8_t modId, uint32_t level, uint8_t *buf, + uint32_t size) +{ + uint32_t i; + + if (level > pMac->utils.gLogDbgLevel[LOG_INDEX_FOR_MODULE(modId)]) + return; + + log_dbg(pMac, modId, level, FL("Dumping %d bytes in host order\n"), + size); + + for (i = 0; (i + 7) < size; i += 8) { + log_dbg(pMac, modId, level, + "%02x %02x %02x %02x %02x %02x %02x %02x \n", + buf[i], + buf[i + 1], + buf[i + 2], + buf[i + 3], + buf[i + 4], buf[i + 5], buf[i + 6], buf[i + 7]); + } + + /* Dump the bytes in the last line */ + for (; i < size; i++) { + log_dbg(pMac, modId, level, "%02x ", buf[i]); + + if ((i + 1) == size) + log_dbg(pMac, modId, level, "\n"); + } + +} /*** end sir_dump_buf() ***/ diff --git a/drivers/staging/qcacld-3.0/core/mac/src/sys/legacy/src/utils/src/utils_parser.c b/drivers/staging/qcacld-3.0/core/mac/src/sys/legacy/src/utils/src/utils_parser.c new file mode 100644 index 0000000000000000000000000000000000000000..d8c4c5a1e8b5f663d8e384bab6901a5b91553504 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/mac/src/sys/legacy/src/utils/src/utils_parser.c @@ -0,0 +1,839 @@ +/* + * Copyright (c) 2011-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * + * This file utils_parser.cc contains the code for parsing + * 802.11 messages. + * Author: Pierre Vandwalle + * Date: 03/18/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + * + */ + +#include "ani_global.h" +#include "utils_parser.h" +#include "lim_ser_des_utils.h" + +void convert_ssid(tpAniSirGlobal pMac, tSirMacSSid *pOld, tDot11fIESSID *pNew) +{ + pOld->length = pNew->num_ssid; + qdf_mem_copy(pOld->ssId, pNew->ssid, pNew->num_ssid); +} + +void convert_supp_rates(tpAniSirGlobal pMac, + tSirMacRateSet *pOld, tDot11fIESuppRates *pNew) +{ + pOld->numRates = pNew->num_rates; + qdf_mem_copy(pOld->rate, pNew->rates, pNew->num_rates); +} + +void convert_ext_supp_rates(tpAniSirGlobal pMac, + tSirMacRateSet *pOld, tDot11fIEExtSuppRates *pNew) +{ + pOld->numRates = pNew->num_rates; + qdf_mem_copy(pOld->rate, pNew->rates, pNew->num_rates); +} + +void convert_qos_caps(tpAniSirGlobal pMac, + tSirMacQosCapabilityIE *pOld, tDot11fIEQOSCapsAp *pNew) +{ + pOld->type = 46; + pOld->length = 1; + + pOld->qosInfo.count = pNew->count; +} + +void convert_qos_caps_station(tpAniSirGlobal pMac, + tSirMacQosCapabilityStaIE *pOld, + tDot11fIEQOSCapsStation *pNew) +{ + pOld->type = 46; + pOld->length = 1; + + pOld->qosInfo.moreDataAck = pNew->more_data_ack; + pOld->qosInfo.maxSpLen = pNew->max_sp_length; + pOld->qosInfo.qack = pNew->qack; + pOld->qosInfo.acbe_uapsd = pNew->acbe_uapsd; + pOld->qosInfo.acbk_uapsd = pNew->acbk_uapsd; + pOld->qosInfo.acvi_uapsd = pNew->acvi_uapsd; + pOld->qosInfo.acvo_uapsd = pNew->acvo_uapsd; +} + +tSirRetStatus convert_wpa(tpAniSirGlobal pMac, + tSirMacWpaInfo *pOld, tDot11fIEWPA *pNew) +{ + /* This is awful, I know, but the old code just rammed the IE into an */ + /* array... */ + uint8_t buffer[257]; + uint32_t status, written = 0, nbuffer = 257; + status = dot11f_pack_ie_wpa(pMac, pNew, buffer, nbuffer, &written); + if (DOT11F_FAILED(status)) { + dot11f_log(pMac, LOG2, FL("Failed to re-pack the WPA IE (0x%0x" + "8).\n"), status); + return eSIR_FAILURE; + } + + pOld->length = (uint8_t) written - 2; + qdf_mem_copy(pOld->info, buffer + 2, pOld->length); + + return eSIR_SUCCESS; +} + +tSirRetStatus convert_wpa_opaque(tpAniSirGlobal pMac, + tSirMacWpaInfo *pOld, tDot11fIEWPAOpaque *pNew) +{ + /* This is awful, I know, but the old code just rammed the IE into */ + /* an opaque array. Note that we need to explicitly add the OUI! */ + pOld->length = pNew->num_data + 4; + pOld->info[0] = 0x00; + pOld->info[1] = 0x50; + pOld->info[2] = 0xf2; + pOld->info[3] = 0x01; + qdf_mem_copy(pOld->info + 4, pNew->data, pNew->num_data); + + return eSIR_SUCCESS; +} + +#ifdef FEATURE_WLAN_WAPI +tSirRetStatus convert_wapi_opaque(tpAniSirGlobal pMac, + tSirMacWapiInfo *pOld, + tDot11fIEWAPIOpaque *pNew) +{ + /* This is awful, I know, but the old code just rammed the IE into */ + /* an opaque array. Note that we need to explicitly add the OUI! */ + pOld->length = pNew->num_data; + qdf_mem_copy(pOld->info, pNew->data, pNew->num_data); + + return eSIR_SUCCESS; +} +#endif + +tSirRetStatus convert_wsc_opaque(tpAniSirGlobal pMac, + tSirAddie *pOld, tDot11fIEWscIEOpaque *pNew) +{ + /* This is awful, I know, but the old code just rammed the IE into */ + /* an opaque array. Note that we need to explicitly add the vendorIE and OUI ! */ + uint8_t curAddIELen = pOld->length; + + pOld->length = curAddIELen + pNew->num_data + 6; + pOld->addIEdata[curAddIELen++] = 0xdd; + pOld->addIEdata[curAddIELen++] = pNew->num_data + 4; + pOld->addIEdata[curAddIELen++] = 0x00; + pOld->addIEdata[curAddIELen++] = 0x50; + pOld->addIEdata[curAddIELen++] = 0xf2; + pOld->addIEdata[curAddIELen++] = 0x04; + qdf_mem_copy(pOld->addIEdata + curAddIELen, pNew->data, pNew->num_data); + + return eSIR_SUCCESS; +} + +tSirRetStatus convert_p2p_opaque(tpAniSirGlobal pMac, + tSirAddie *pOld, tDot11fIEP2PIEOpaque *pNew) +{ + /* This is awful, I know, but the old code just rammed the IE into */ + /* an opaque array. Note that we need to explicitly add the vendorIE and OUI ! */ + uint8_t curAddIELen = pOld->length; + + pOld->length = curAddIELen + pNew->num_data + 6; + pOld->addIEdata[curAddIELen++] = 0xdd; + pOld->addIEdata[curAddIELen++] = pNew->num_data + 4; + pOld->addIEdata[curAddIELen++] = 0x50; + pOld->addIEdata[curAddIELen++] = 0x6f; + pOld->addIEdata[curAddIELen++] = 0x9A; + pOld->addIEdata[curAddIELen++] = 0x09; + qdf_mem_copy(pOld->addIEdata + curAddIELen, pNew->data, pNew->num_data); + + return eSIR_SUCCESS; +} + +#ifdef WLAN_FEATURE_WFD +tSirRetStatus convert_wfd_opaque(tpAniSirGlobal pMac, + tSirAddie *pOld, tDot11fIEWFDIEOpaque *pNew) +{ + /* This is awful, I know, but the old code just rammed the IE into */ + /* an opaque array. Note that we need to explicitly add the vendorIE and OUI ! */ + uint8_t curAddIELen = pOld->length; + + pOld->length = curAddIELen + pNew->num_data + 6; + pOld->addIEdata[curAddIELen++] = 0xdd; + pOld->addIEdata[curAddIELen++] = pNew->num_data + 4; + pOld->addIEdata[curAddIELen++] = 0x50; + pOld->addIEdata[curAddIELen++] = 0x6f; + pOld->addIEdata[curAddIELen++] = 0x9A; + pOld->addIEdata[curAddIELen++] = 0x0a; + qdf_mem_copy(pOld->addIEdata + curAddIELen, pNew->data, pNew->num_data); + + return eSIR_SUCCESS; +} +#endif + +tSirRetStatus convert_rsn(tpAniSirGlobal pMac, + tSirMacRsnInfo *pOld, tDot11fIERSN *pNew) +{ + uint8_t buffer[257]; + uint32_t status, written = 0, nbuffer = 257; + status = dot11f_pack_ie_rsn(pMac, pNew, buffer, nbuffer, &written); + if (DOT11F_FAILED(status)) { + dot11f_log(pMac, LOG2, FL("Failed to re-pack the RSN IE (0x%0x" + "8).\n"), status); + return eSIR_FAILURE; + } + + pOld->length = (uint8_t) written - 2; + qdf_mem_copy(pOld->info, buffer + 2, pOld->length); + + return eSIR_SUCCESS; +} + +tSirRetStatus convert_rsn_opaque(tpAniSirGlobal pMac, + tSirMacRsnInfo *pOld, tDot11fIERSNOpaque *pNew) +{ + /* This is awful, I know, but the old code just rammed the IE into */ + /* an opaque array. */ + pOld->length = pNew->num_data; + qdf_mem_copy(pOld->info, pNew->data, pOld->length); + + return eSIR_SUCCESS; +} + +void convert_power_caps(tpAniSirGlobal pMac, + tSirMacPowerCapabilityIE *pOld, + tDot11fIEPowerCaps *pNew) +{ + pOld->type = 33; + pOld->length = 2; + pOld->minTxPower = pNew->minTxPower; + pOld->maxTxPower = pNew->maxTxPower; +} + +void convert_supp_channels(tpAniSirGlobal pMac, + tSirMacSupportedChannelIE *pOld, + tDot11fIESuppChannels *pNew) +{ + pOld->type = 36; + pOld->length = (pNew->num_bands * 2); + qdf_mem_copy((uint8_t *) pOld->supportedChannels, + (uint8_t *) pNew->bands, pOld->length); +} + +void convert_cf_params(tpAniSirGlobal pMac, + tSirMacCfParamSet *pOld, tDot11fIECFParams *pNew) +{ + pOld->cfpCount = pNew->cfp_count; + pOld->cfpPeriod = pNew->cfp_period; + pOld->cfpMaxDuration = pNew->cfp_maxduration; + pOld->cfpDurRemaining = pNew->cfp_durremaining; +} + +void convert_fh_params(tpAniSirGlobal pMac, + tSirMacFHParamSet *pOld, tDot11fIEFHParamSet *pNew) +{ + pOld->dwellTime = pNew->dwell_time; + pOld->hopSet = pNew->hop_set; + pOld->hopPattern = pNew->hop_pattern; + pOld->hopIndex = pNew->hop_index; +} + +void convert_tim(tpAniSirGlobal pMac, tSirMacTim *pOld, tDot11fIETIM *pNew) +{ + pOld->dtimCount = pNew->dtim_count; + pOld->dtimPeriod = pNew->dtim_period; + pOld->bitmapControl = pNew->bmpctl; + pOld->bitmapLength = pNew->num_vbmp; + + qdf_mem_copy(pOld->bitmap, pNew->vbmp, pNew->num_vbmp); +} + +void convert_country(tpAniSirGlobal pMac, + tSirCountryInformation *pOld, tDot11fIECountry *pNew) +{ + int i; + + qdf_mem_copy(pOld->countryString, pNew->country, COUNTRY_STRING_LENGTH); + + pOld->numIntervals = pNew->num_triplets; + + for (i = 0; i < pNew->num_triplets; ++i) { + pOld->channelTransmitPower[i].channelNumber = + pNew->triplets[i][0]; + pOld->channelTransmitPower[i].numChannel = pNew->triplets[i][1]; + pOld->channelTransmitPower[i].maxTransmitPower = + pNew->triplets[i][2]; + } +} + +void convert_wmm_params(tpAniSirGlobal pMac, + tSirMacEdcaParamSetIE *pOld, tDot11fIEWMMParams *pNew) +{ + pOld->type = 221; + pOld->length = 24; + + qdf_mem_copy((uint8_t *) &pOld->qosInfo, (uint8_t *) &pNew->qosInfo, + 1); + + pOld->acbe.aci.aifsn = pNew->acbe_aifsn; + pOld->acbe.aci.acm = pNew->acbe_acm; + pOld->acbe.aci.aci = pNew->acbe_aci; + pOld->acbe.cw.min = pNew->acbe_acwmin; + pOld->acbe.cw.max = pNew->acbe_acwmax; + pOld->acbe.txoplimit = pNew->acbe_txoplimit; + + pOld->acbk.aci.aifsn = pNew->acbk_aifsn; + pOld->acbk.aci.acm = pNew->acbk_acm; + pOld->acbk.aci.aci = pNew->acbk_aci; + pOld->acbk.cw.min = pNew->acbk_acwmin; + pOld->acbk.cw.max = pNew->acbk_acwmax; + pOld->acbk.txoplimit = pNew->acbk_txoplimit; + + pOld->acvi.aci.aifsn = pNew->acvi_aifsn; + pOld->acvi.aci.acm = pNew->acvi_acm; + pOld->acvi.aci.aci = pNew->acvi_aci; + pOld->acvi.cw.min = pNew->acvi_acwmin; + pOld->acvi.cw.max = pNew->acvi_acwmax; + pOld->acvi.txoplimit = pNew->acvi_txoplimit; + + pOld->acvo.aci.aifsn = pNew->acvo_aifsn; + pOld->acvo.aci.acm = pNew->acvo_acm; + pOld->acvo.aci.aci = pNew->acvo_aci; + pOld->acvo.cw.min = pNew->acvo_acwmin; + pOld->acvo.cw.max = pNew->acvo_acwmax; + pOld->acvo.txoplimit = pNew->acvo_txoplimit; +} + +void convert_erp_info(tpAniSirGlobal pMac, + tSirMacErpInfo *pOld, tDot11fIEERPInfo *pNew) +{ + pOld->nonErpPresent = pNew->non_erp_present; + pOld->useProtection = pNew->use_prot; + pOld->barkerPreambleMode = pNew->barker_preamble; +} + +void convert_edca_param(tpAniSirGlobal pMac, + tSirMacEdcaParamSetIE *pOld, + tDot11fIEEDCAParamSet *pNew) +{ + pOld->type = 12; + pOld->length = 20; + + qdf_mem_copy((uint8_t *) &pOld->qosInfo, (uint8_t *) &pNew->qos, 1); + + pOld->acbe.aci.aifsn = pNew->acbe_aifsn; + pOld->acbe.aci.acm = pNew->acbe_acm; + pOld->acbe.aci.aci = pNew->acbe_aci; + pOld->acbe.cw.min = pNew->acbe_acwmin; + pOld->acbe.cw.max = pNew->acbe_acwmax; + pOld->acbe.txoplimit = pNew->acbe_txoplimit; + + pOld->acbk.aci.aifsn = pNew->acbk_aifsn; + pOld->acbk.aci.acm = pNew->acbk_acm; + pOld->acbk.aci.aci = pNew->acbk_aci; + pOld->acbk.cw.min = pNew->acbk_acwmin; + pOld->acbk.cw.max = pNew->acbk_acwmax; + pOld->acbk.txoplimit = pNew->acbk_txoplimit; + + pOld->acvi.aci.aifsn = pNew->acvi_aifsn; + pOld->acvi.aci.acm = pNew->acvi_acm; + pOld->acvi.aci.aci = pNew->acvi_aci; + pOld->acvi.cw.min = pNew->acvi_acwmin; + pOld->acvi.cw.max = pNew->acvi_acwmax; + pOld->acvi.txoplimit = pNew->acvi_txoplimit; + + pOld->acvo.aci.aifsn = pNew->acvo_aifsn; + pOld->acvo.aci.acm = pNew->acvo_acm; + pOld->acvo.aci.aci = pNew->acvo_aci; + pOld->acvo.cw.min = pNew->acvo_acwmin; + pOld->acvo.cw.max = pNew->acvo_acwmax; + pOld->acvo.txoplimit = pNew->acvo_txoplimit; + +} + +void convert_tspec(tpAniSirGlobal pMac, + tSirMacTspecIE *pOld, tDot11fIETSPEC *pNew) +{ + pOld->tsinfo.traffic.trafficType = (uint16_t) pNew->traffic_type; + pOld->tsinfo.traffic.tsid = (uint16_t) pNew->tsid; + pOld->tsinfo.traffic.direction = (uint16_t) pNew->direction; + pOld->tsinfo.traffic.accessPolicy = (uint16_t) pNew->access_policy; + pOld->tsinfo.traffic.aggregation = (uint16_t) pNew->aggregation; + pOld->tsinfo.traffic.psb = (uint16_t) pNew->psb; + pOld->tsinfo.traffic.userPrio = (uint16_t) pNew->user_priority; + pOld->tsinfo.traffic.ackPolicy = (uint16_t) pNew->tsinfo_ack_pol; + + pOld->tsinfo.schedule.schedule = (uint8_t) pNew->schedule; + + pOld->nomMsduSz = pNew->size; + pOld->maxMsduSz = pNew->max_msdu_size; + pOld->minSvcInterval = pNew->min_service_int; + pOld->maxSvcInterval = pNew->max_service_int; + pOld->inactInterval = pNew->inactivity_int; + pOld->suspendInterval = pNew->suspension_int; + pOld->svcStartTime = pNew->service_start_time; + pOld->minDataRate = pNew->min_data_rate; + pOld->meanDataRate = pNew->mean_data_rate; + pOld->peakDataRate = pNew->peak_data_rate; + pOld->maxBurstSz = pNew->burst_size; + pOld->delayBound = pNew->delay_bound; + pOld->minPhyRate = pNew->min_phy_rate; + pOld->surplusBw = pNew->surplus_bw_allowance; + pOld->mediumTime = pNew->medium_time; +} + +tSirRetStatus convert_tclas(tpAniSirGlobal pMac, + tSirTclasInfo *pOld, tDot11fIETCLAS *pNew) +{ + uint32_t length = 0; + + if (DOT11F_FAILED(dot11f_get_packed_ietclas(pMac, pNew, &length))) { + return eSIR_FAILURE; + } + + pOld->tclas.type = DOT11F_EID_TCLAS; + pOld->tclas.length = (uint8_t) length; + pOld->tclas.userPrio = pNew->user_priority; + pOld->tclas.classifierType = pNew->classifier_type; + pOld->tclas.classifierMask = pNew->classifier_mask; + + switch (pNew->classifier_type) { + case 0: + qdf_mem_copy(pOld->tclasParams.eth.srcAddr, + pNew->info.EthParams.source, 6); + qdf_mem_copy(pOld->tclasParams.eth.dstAddr, + pNew->info.EthParams.dest, 6); + pOld->tclasParams.eth.type = pNew->info.EthParams.type; + break; + case 1: + pOld->version = pNew->info.IpParams.version; + if (4 == pNew->info.IpParams.version) { + pOld->tclasParams.ipv4.version = 4; + qdf_mem_copy(pOld->tclasParams.ipv4.srcIpAddr, + pNew->info.IpParams.params.IpV4Params. + source, 4); + qdf_mem_copy(pOld->tclasParams.ipv4.dstIpAddr, + pNew->info.IpParams.params.IpV4Params.dest, + 4); + pOld->tclasParams.ipv4.srcPort = + pNew->info.IpParams.params.IpV4Params.src_port; + pOld->tclasParams.ipv4.dstPort = + pNew->info.IpParams.params.IpV4Params.dest_port; + pOld->tclasParams.ipv4.dscp = + pNew->info.IpParams.params.IpV4Params.DSCP; + pOld->tclasParams.ipv4.protocol = + pNew->info.IpParams.params.IpV4Params.proto; + pOld->tclasParams.ipv4.rsvd = + pNew->info.IpParams.params.IpV4Params.reserved; + } else if (6 == pNew->info.IpParams.version) { + pOld->tclasParams.ipv6.version = 6; + qdf_mem_copy((uint8_t *) pOld->tclasParams.ipv6. + srcIpAddr, + (uint8_t *) pNew->info.IpParams.params. + IpV6Params.source, 16); + qdf_mem_copy((uint8_t *) pOld->tclasParams.ipv6. + dstIpAddr, + (uint8_t *) pNew->info.IpParams.params. + IpV6Params.dest, 16); + pOld->tclasParams.ipv6.srcPort = + pNew->info.IpParams.params.IpV6Params.src_port; + pOld->tclasParams.ipv6.dstPort = + pNew->info.IpParams.params.IpV6Params.dest_port; + qdf_mem_copy((uint8_t *) pOld->tclasParams.ipv6. + flowLabel, + (uint8_t *) pNew->info.IpParams.params. + IpV6Params.flow_label, 3); + } else { + return eSIR_FAILURE; + } + break; + case 2: + pOld->tclasParams.t8021dq.tag = + pNew->info.Params8021dq.tag_type; + break; + default: + return eSIR_FAILURE; + } + + return eSIR_SUCCESS; +} + +void convert_wmmtspec(tpAniSirGlobal pMac, + tSirMacTspecIE *pOld, tDot11fIEWMMTSPEC *pNew) +{ + pOld->tsinfo.traffic.trafficType = (uint16_t) pNew->traffic_type; + pOld->tsinfo.traffic.tsid = (uint16_t) pNew->tsid; + pOld->tsinfo.traffic.direction = (uint16_t) pNew->direction; + pOld->tsinfo.traffic.accessPolicy = (uint16_t) pNew->access_policy; + pOld->tsinfo.traffic.aggregation = (uint16_t) pNew->aggregation; + pOld->tsinfo.traffic.psb = (uint16_t) pNew->psb; + pOld->tsinfo.traffic.userPrio = (uint16_t) pNew->user_priority; + pOld->tsinfo.traffic.ackPolicy = (uint16_t) pNew->tsinfo_ack_pol; + pOld->nomMsduSz = (pNew->fixed << 15) | pNew->size; + pOld->maxMsduSz = pNew->max_msdu_size; + pOld->minSvcInterval = pNew->min_service_int; + pOld->maxSvcInterval = pNew->max_service_int; + pOld->inactInterval = pNew->inactivity_int; + pOld->suspendInterval = pNew->suspension_int; + pOld->svcStartTime = pNew->service_start_time; + pOld->minDataRate = pNew->min_data_rate; + pOld->meanDataRate = pNew->mean_data_rate; + pOld->peakDataRate = pNew->peak_data_rate; + pOld->maxBurstSz = pNew->burst_size; + pOld->delayBound = pNew->delay_bound; + pOld->minPhyRate = pNew->min_phy_rate; + pOld->surplusBw = pNew->surplus_bw_allowance; + pOld->mediumTime = pNew->medium_time; +} + +tSirRetStatus convert_wmmtclas(tpAniSirGlobal pMac, + tSirTclasInfo *pOld, tDot11fIEWMMTCLAS *pNew) +{ + uint32_t length = 0; + + if (DOT11F_FAILED(dot11f_get_packed_iewmmtclas(pMac, pNew, &length))) { + return eSIR_FAILURE; + } + + pOld->tclas.type = DOT11F_EID_WMMTCLAS; + pOld->tclas.length = (uint8_t) length; + pOld->tclas.userPrio = pNew->user_priority; + pOld->tclas.classifierType = pNew->classifier_type; + pOld->tclas.classifierMask = pNew->classifier_mask; + + switch (pNew->classifier_type) { + case 0: + qdf_mem_copy(pOld->tclasParams.eth.srcAddr, + pNew->info.EthParams.source, 6); + qdf_mem_copy(pOld->tclasParams.eth.dstAddr, + pNew->info.EthParams.dest, 6); + pOld->tclasParams.eth.type = pNew->info.EthParams.type; + break; + case 1: + pOld->version = pNew->info.IpParams.version; + if (4 == pNew->info.IpParams.version) { + pOld->tclasParams.ipv4.version = 4; + qdf_mem_copy(pOld->tclasParams.ipv4.srcIpAddr, + pNew->info.IpParams.params.IpV4Params. + source, 4); + qdf_mem_copy(pOld->tclasParams.ipv4.dstIpAddr, + pNew->info.IpParams.params.IpV4Params.dest, + 4); + pOld->tclasParams.ipv4.srcPort = + pNew->info.IpParams.params.IpV4Params.src_port; + pOld->tclasParams.ipv4.dstPort = + pNew->info.IpParams.params.IpV4Params.dest_port; + pOld->tclasParams.ipv4.dscp = + pNew->info.IpParams.params.IpV4Params.DSCP; + pOld->tclasParams.ipv4.protocol = + pNew->info.IpParams.params.IpV4Params.proto; + pOld->tclasParams.ipv4.rsvd = + pNew->info.IpParams.params.IpV4Params.reserved; + } else if (6 == pNew->info.IpParams.version) { + pOld->tclasParams.ipv6.version = 6; + qdf_mem_copy((uint8_t *) pOld->tclasParams.ipv6. + srcIpAddr, + (uint8_t *) pNew->info.IpParams.params. + IpV6Params.source, 16); + qdf_mem_copy((uint8_t *) pOld->tclasParams.ipv6. + dstIpAddr, + (uint8_t *) pNew->info.IpParams.params. + IpV6Params.dest, 16); + pOld->tclasParams.ipv6.srcPort = + pNew->info.IpParams.params.IpV6Params.src_port; + pOld->tclasParams.ipv6.dstPort = + pNew->info.IpParams.params.IpV6Params.dest_port; + qdf_mem_copy((uint8_t *) pOld->tclasParams.ipv6. + flowLabel, + (uint8_t *) pNew->info.IpParams.params. + IpV6Params.flow_label, 3); + } else { + return eSIR_FAILURE; + } + break; + case 2: + pOld->tclasParams.t8021dq.tag = + pNew->info.Params8021dq.tag_type; + break; + default: + return eSIR_FAILURE; + } + + return eSIR_SUCCESS; +} + +void convert_ts_delay(tpAniSirGlobal pMac, + tSirMacTsDelayIE *pOld, tDot11fIETSDelay *pNew) +{ + pOld->type = DOT11F_EID_TSDELAY; + pOld->length = 4U; + pOld->delay = pNew->delay; +} + +void convert_schedule(tpAniSirGlobal pMac, + tSirMacScheduleIE *pOld, tDot11fIESchedule *pNew) +{ + pOld->type = DOT11F_EID_SCHEDULE; + pOld->length = DOT11F_IE_SCHEDULE_MIN_LEN; + + pOld->info.aggregation = pNew->aggregation; + pOld->info.tsid = pNew->tsid; + pOld->info.direction = pNew->direction; + + pOld->svcStartTime = pNew->service_start_time; + pOld->svcInterval = pNew->service_interval; + pOld->specInterval = pNew->spec_interval; +} + +void convert_wmm_schedule(tpAniSirGlobal pMac, + tSirMacScheduleIE *pOld, tDot11fIEWMMSchedule *pNew) +{ + pOld->type = DOT11F_EID_WMMSCHEDULE; + pOld->length = DOT11F_IE_WMMSCHEDULE_MIN_LEN; + + pOld->info.aggregation = pNew->aggregation; + pOld->info.tsid = pNew->tsid; + pOld->info.direction = pNew->direction; + + pOld->svcStartTime = pNew->service_start_time; + pOld->svcInterval = pNew->service_interval; + pOld->specInterval = pNew->spec_interval; +} + +/** + @brief : This functions converts the given buffer till given size to + Big endian format assuming the bus is 32 bit. The size should + be four byte aligned. + @param : ptr to be converted, size + @return : void + */ + +void convertto_big_endian(void *ptr, uint16_t size) +{ + uint8_t *temp_ptr; + uint32_t *dest_ptr; + + dest_ptr = (uint32_t *) ptr; + while (size) { + temp_ptr = (uint8_t *) dest_ptr; + *dest_ptr = + (temp_ptr[0] << 24) | (temp_ptr[1] << 16) | (temp_ptr[2] << + 8) | + temp_ptr[3]; + dest_ptr++; + size -= 4; + } +} + +void create_scan_data_null_frame(tpAniSirGlobal pMac, tSirMacMgmtHdr *macMgmtHdr, + uint8_t pwrMgmt, tSirMacAddr bssid, + tSirMacAddr selfMacAddr) +{ + + macMgmtHdr->fc.type = SIR_MAC_DATA_FRAME; + macMgmtHdr->fc.subType = SIR_MAC_DATA_NULL; + macMgmtHdr->fc.protVer = SIR_MAC_PROTOCOL_VERSION; + macMgmtHdr->fc.order = 0; + macMgmtHdr->fc.wep = 0; + macMgmtHdr->fc.moreData = 0; + macMgmtHdr->fc.powerMgmt = pwrMgmt; + macMgmtHdr->fc.retry = 0; + macMgmtHdr->fc.moreFrag = 0; + macMgmtHdr->fc.fromDS = 0; + macMgmtHdr->fc.toDS = 0; + macMgmtHdr->durationLo = + (uint8_t) (SIR_MAC_MAX_DURATION_MICRO_SECONDS & 0xff); + macMgmtHdr->durationHi = + (uint8_t) ((SIR_MAC_MAX_DURATION_MICRO_SECONDS & 0xff00) >> 8); + macMgmtHdr->seqControl.fragNum = 0; + macMgmtHdr->seqControl.seqNumLo = 0; + macMgmtHdr->seqControl.seqNumHi = 2; + qdf_mem_copy((void *)&macMgmtHdr->da, + (void *)bssid, sizeof(tSirMacAddr)); + qdf_mem_copy((void *)&macMgmtHdr->sa, + (void *)selfMacAddr, sizeof(tSirMacAddr)); + qdf_mem_copy((void *)&macMgmtHdr->bssId, + (void *)bssid, sizeof(tSirMacAddr)); + + return; +} + +void create_scan_cts_frame(tpAniSirGlobal pMac, tSirMacMgmtHdr *macMgmtHdr, + tSirMacAddr selfMac) +{ + macMgmtHdr->fc.type = SIR_MAC_CTRL_FRAME; + macMgmtHdr->fc.subType = SIR_MAC_CTRL_CTS; + macMgmtHdr->fc.order = 0; + macMgmtHdr->fc.wep = 0; + macMgmtHdr->fc.moreData = 0; + macMgmtHdr->fc.powerMgmt = 0; + macMgmtHdr->fc.retry = 0; + macMgmtHdr->fc.moreFrag = 0; + macMgmtHdr->fc.fromDS = 0; + macMgmtHdr->fc.toDS = 0; + macMgmtHdr->durationLo = + (uint8_t) (SIR_MAC_MAX_DURATION_MICRO_SECONDS & 0xff); + macMgmtHdr->durationHi = + (uint8_t) ((SIR_MAC_MAX_DURATION_MICRO_SECONDS & 0xff00) >> 8); + qdf_mem_copy((void *)macMgmtHdr->da, (void *)selfMac, + sizeof(tSirMacAddr)); + + return; +} + +void convert_qos_mapset_frame(tpAniSirGlobal pMac, tSirQosMapSet *Qos, + tDot11fIEQosMapSet *dot11fIE) +{ + uint8_t i, j = 0; + uint8_t qos_dscp_sz, dot11_dscp_sz; + + qos_dscp_sz = (sizeof(Qos->dscp_exceptions)/2); + dot11_dscp_sz = sizeof(dot11fIE->dscp_exceptions); + if (dot11fIE->num_dscp_exceptions > QOS_MAP_LEN_MAX) + dot11fIE->num_dscp_exceptions = QOS_MAP_LEN_MAX; + Qos->num_dscp_exceptions = + (dot11fIE->num_dscp_exceptions - QOS_MAP_LEN_MIN) / 2; + + for (i = 0; + i < Qos->num_dscp_exceptions && + i < qos_dscp_sz && j < dot11_dscp_sz; + i++) { + Qos->dscp_exceptions[i][0] = dot11fIE->dscp_exceptions[j]; + j++; + Qos->dscp_exceptions[i][1] = dot11fIE->dscp_exceptions[j]; + j++; + } + for (i = 0; i < 8 && j < dot11_dscp_sz; i++) { + Qos->dscp_range[i][0] = dot11fIE->dscp_exceptions[j]; + j++; + Qos->dscp_range[i][1] = dot11fIE->dscp_exceptions[j]; + j++; + } +} + +/** + @brief : This functions creates a DATA_NULL/CTS2SELF frame in Big endian format + @param : Global MAC structure, pointer to return the created packet, role which is Station/AP + @return : void + */ + +void create_init_scan_raw_frame(tpAniSirGlobal pMac, tSirMacMgmtHdr *macMgmtHdr, + tBssSystemRole role) +{ +#if 0 + tpStaStruct pSta = (tpStaStruct) pMac->hal.halMac.staTable; + + if (role == eSYSTEM_STA_ROLE) { + macMgmtHdr->fc.type = SIR_MAC_DATA_FRAME; + macMgmtHdr->fc.subType = SIR_MAC_DATA_NULL; + macMgmtHdr->fc.protVer = SIR_MAC_PROTOCOL_VERSION; + macMgmtHdr->fc.order = 0; + macMgmtHdr->fc.wep = 0; + macMgmtHdr->fc.moreData = 0; + macMgmtHdr->fc.powerMgmt = 1; /* Needed for station */ + macMgmtHdr->fc.retry = 0; + macMgmtHdr->fc.moreFrag = 0; + macMgmtHdr->fc.fromDS = 0; + macMgmtHdr->fc.toDS = 1; + macMgmtHdr->durationLo = + (uint8_t) (SIR_MAC_MAX_DURATION_MICRO_SECONDS & 0xff); + macMgmtHdr->durationHi = + (uint8_t) ((SIR_MAC_MAX_DURATION_MICRO_SECONDS & 0xff00) >> + 8); + macMgmtHdr->seqControl.fragNum = 0; + macMgmtHdr->seqControl.seqNumLo = 0; + macMgmtHdr->seqControl.seqNumHi = 2; + qdf_mem_copy((void *)&macMgmtHdr->da, (void *)pSta[0].bssId, 6); + qdf_mem_copy(&macMgmtHdr->sa, pSta[0].staAddr, 6); + qdf_mem_copy((void *)&macMgmtHdr->bssId, (void *)pSta[0].bssId, + 6); + } else if (role == eSYSTEM_AP_ROLE || role == eSYSTEM_STA_IN_IBSS_ROLE) { + macMgmtHdr->fc.type = SIR_MAC_CTRL_FRAME; + macMgmtHdr->fc.subType = SIR_MAC_CTRL_CTS; + macMgmtHdr->fc.order = 0; + macMgmtHdr->fc.wep = 0; + macMgmtHdr->fc.moreData = 0; + macMgmtHdr->fc.powerMgmt = 0; /* Needed for station */ + macMgmtHdr->fc.retry = 0; + macMgmtHdr->fc.moreFrag = 0; + macMgmtHdr->fc.fromDS = 0; + macMgmtHdr->fc.toDS = 0; + macMgmtHdr->durationLo = + (uint8_t) (SIR_MAC_MAX_DURATION_MICRO_SECONDS & 0xff); + macMgmtHdr->durationHi = + (uint8_t) ((SIR_MAC_MAX_DURATION_MICRO_SECONDS & 0xff00) >> + 8); + qdf_mem_copy((void *)macMgmtHdr->da, (void *)pSta[0].staAddr, + 6); + } + return; +#endif +} + +/** + @brief : This functions creates a DATA_NULL frame in Big endian format + @param : Global MAC structure, pointer to return the created packet, role which is Station/AP + @return : void + */ + +void create_finish_scan_raw_frame(tpAniSirGlobal pMac, tSirMacMgmtHdr *macMgmtHdr, + tBssSystemRole role) +{ +#if 0 + tpStaStruct pSta = (tpStaStruct) pMac->hal.halMac.staTable; + + if (role == eSYSTEM_STA_ROLE) { + macMgmtHdr->fc.type = SIR_MAC_DATA_FRAME; + macMgmtHdr->fc.subType = SIR_MAC_DATA_NULL; + macMgmtHdr->fc.protVer = SIR_MAC_PROTOCOL_VERSION; + macMgmtHdr->fc.order = 0; + macMgmtHdr->fc.wep = 0; + macMgmtHdr->fc.moreData = 0; + macMgmtHdr->fc.powerMgmt = 0; /* Needed for station */ + macMgmtHdr->fc.retry = 0; + macMgmtHdr->fc.moreFrag = 0; + macMgmtHdr->fc.fromDS = 0; + macMgmtHdr->fc.toDS = 1; + macMgmtHdr->durationLo = + (uint8_t) (SIR_MAC_MAX_DURATION_MICRO_SECONDS & 0xff); + macMgmtHdr->durationHi = + (uint8_t) ((SIR_MAC_MAX_DURATION_MICRO_SECONDS & 0xff00) >> + 8); + macMgmtHdr->seqControl.fragNum = 0; + macMgmtHdr->seqControl.seqNumLo = 0; + macMgmtHdr->seqControl.seqNumHi = 2; + qdf_mem_copy((void *)macMgmtHdr->da, (void *)pSta[0].bssId, 6); + qdf_mem_copy(macMgmtHdr->sa, pSta[0].staAddr, 6); + qdf_mem_copy((void *)macMgmtHdr->bssId, (void *)pSta[0].bssId, + 6); + + } + + return; +#endif +} + +/* utils_parser.c ends here. */ diff --git a/drivers/staging/qcacld-3.0/core/pld/inc/pld_common.h b/drivers/staging/qcacld-3.0/core/pld/inc/pld_common.h new file mode 100644 index 0000000000000000000000000000000000000000..756b69a41fb92d24c9e4a09bd2f4633234051359 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/pld/inc/pld_common.h @@ -0,0 +1,392 @@ +/* + * Copyright (c) 2016-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef __PLD_COMMON_H__ +#define __PLD_COMMON_H__ + +#include +#include +#include + +#define PLD_IMAGE_FILE "athwlan.bin" +#define PLD_UTF_FIRMWARE_FILE "utf.bin" +#define PLD_BOARD_DATA_FILE "fakeboar.bin" +#define PLD_OTP_FILE "otp.bin" +#define PLD_SETUP_FILE "athsetup.bin" +#define PLD_EPPING_FILE "epping.bin" +#define PLD_EVICTED_FILE "" + +/** + * enum pld_bus_type - bus type + * @PLD_BUS_TYPE_NONE: invalid bus type, only return in error cases + * @PLD_BUS_TYPE_PCIE: PCIE bus + * @PLD_BUS_TYPE_SNOC: SNOC bus + */ +enum pld_bus_type { + PLD_BUS_TYPE_NONE = -1, + PLD_BUS_TYPE_PCIE = 0, + PLD_BUS_TYPE_SNOC, + PLD_BUS_TYPE_SDIO, + PLD_BUS_TYPE_USB +}; + +#define PLD_MAX_FIRMWARE_SIZE (1 * 1024 * 1024) + +/** + * enum pld_bus_width_type - bus bandwith + * @PLD_BUS_WIDTH_NONE: don't vote for bus bandwidth + * @PLD_BUS_WIDTH_LOW: vote for low bus bandwidth + * @PLD_BUS_WIDTH_MEDIUM: vote for medium bus bandwidth + * @PLD_BUS_WIDTH_HIGH: vote for high bus bandwidth + */ +enum pld_bus_width_type { + PLD_BUS_WIDTH_NONE, + PLD_BUS_WIDTH_LOW, + PLD_BUS_WIDTH_MEDIUM, + PLD_BUS_WIDTH_HIGH +}; + +#define PLD_MAX_FILE_NAME 20 + +/** + * struct pld_fw_file - WLAN FW file names + * @image_file: WLAN FW image file + * @board_data: WLAN FW board data file + * @otp_data: WLAN FW OTP file + * @utf_file: WLAN FW UTF file + * @utf_board_data: WLAN FW UTF board data file + * @epping_file: WLAN FW EPPING mode file + * @evicted_data: WLAN FW evicted file + * @setup_file: WLAN FW setup file + * + * pld_fw_files is used to store WLAN FW file names + */ +struct pld_fw_files { + char image_file[PLD_MAX_FILE_NAME]; + char board_data[PLD_MAX_FILE_NAME]; + char otp_data[PLD_MAX_FILE_NAME]; + char utf_file[PLD_MAX_FILE_NAME]; + char utf_board_data[PLD_MAX_FILE_NAME]; + char epping_file[PLD_MAX_FILE_NAME]; + char evicted_data[PLD_MAX_FILE_NAME]; + char setup_file[PLD_MAX_FILE_NAME]; + char ibss_image_file[PLD_MAX_FILE_NAME]; +}; + +/** + * enum pld_platform_cap_flag - platform capability flag + * @PLD_HAS_EXTERNAL_SWREG: has external regulator + * @PLD_HAS_UART_ACCESS: has UART access + */ +enum pld_platform_cap_flag { + PLD_HAS_EXTERNAL_SWREG = 0x01, + PLD_HAS_UART_ACCESS = 0x02, +}; + +/** + * struct pld_platform_cap - platform capabilities + * @cap_flag: capabilities flag + * + * pld_platform_cap provides platform capabilities which are + * extracted from DTS. + */ +struct pld_platform_cap { + u32 cap_flag; +}; + +/** + * enum pld_driver_status - WLAN driver status + * @PLD_UNINITIALIZED: driver is uninitialized + * @PLD_INITIALIZED: driver is initialized + * @PLD_LOAD_UNLOADL: driver is in load-unload status + */ +enum pld_driver_status { + PLD_UNINITIALIZED, + PLD_INITIALIZED, + PLD_LOAD_UNLOAD, +}; + +/** + * enum pld_uevent - WLAN FW status + * @PLD_RECOVERY: driver is recovering + * @PLD_FW_DOWN: FW is down + */ +enum pld_uevent { + PLD_RECOVERY, + PLD_FW_DOWN, +}; + +/** + * struct pld_uevent_data - uevent status received from platform driver + * @uevent: uevent type + * @fw_down: FW down info + */ +struct pld_uevent_data { + enum pld_uevent uevent; + union { + struct { + bool crashed; + } fw_down; + }; +}; + +/** + * struct pld_ce_tgt_pipe_cfg - copy engine target pipe configuration + * @pipe_num: pipe number + * @pipe_dir: pipe direction + * @nentries: number of entries + * @nbytes_max: max number of bytes + * @flags: flags + * @reserved: reserved + * + * pld_ce_tgt_pipe_cfg is used to store copy engine target pipe + * configuration. + */ +struct pld_ce_tgt_pipe_cfg { + u32 pipe_num; + u32 pipe_dir; + u32 nentries; + u32 nbytes_max; + u32 flags; + u32 reserved; +}; + +/** + * struct pld_ce_svc_pipe_cfg - copy engine service pipe configuration + * @service_id: service ID + * @pipe_dir: pipe direction + * @pipe_num: pipe number + * + * pld_ce_svc_pipe_cfg is used to store copy engine service pipe + * configuration. + */ +struct pld_ce_svc_pipe_cfg { + u32 service_id; + u32 pipe_dir; + u32 pipe_num; +}; + +/** + * struct pld_shadow_reg_cfg - shadow register configuration + * @ce_id: copy engine ID + * @reg_offset: register offset + * + * pld_shadow_reg_cfg is used to store shadow register configuration. + */ +struct pld_shadow_reg_cfg { + u16 ce_id; + u16 reg_offset; +}; + +/** + * struct pld_wlan_enable_cfg - WLAN FW configuration + * @num_ce_tgt_cfg: number of CE target configuration + * @ce_tgt_cfg: CE target configuration + * @num_ce_svc_pipe_cfg: number of CE service configuration + * @ce_svc_cfg: CE service configuration + * @num_shadow_reg_cfg: number of shadow register configuration + * @shadow_reg_cfg: shadow register configuration + * + * pld_wlan_enable_cfg stores WLAN FW configurations. It will be + * passed to WLAN FW when WLAN host driver calls wlan_enable. + */ +struct pld_wlan_enable_cfg { + u32 num_ce_tgt_cfg; + struct pld_ce_tgt_pipe_cfg *ce_tgt_cfg; + u32 num_ce_svc_pipe_cfg; + struct pld_ce_svc_pipe_cfg *ce_svc_cfg; + u32 num_shadow_reg_cfg; + struct pld_shadow_reg_cfg *shadow_reg_cfg; +}; + +/** + * enum pld_driver_mode - WLAN host driver mode + * @PLD_MISSION: mission mode + * @PLD_FTM: FTM mode + * @PLD_EPPING: EPPING mode + * @PLD_WALTEST: WAL test mode, FW standalone test mode + * @PLD_OFF: OFF mode + */ +enum pld_driver_mode { + PLD_MISSION, + PLD_FTM, + PLD_EPPING, + PLD_WALTEST, + PLD_OFF +}; + +#define PLD_MAX_TIMESTAMP_LEN 32 + +/** + * struct pld_soc_info - SOC information + * @v_addr: virtual address of preallocated memory + * @p_addr: physical address of preallcoated memory + * @chip_id: chip ID + * @chip_family: chip family + * @board_id: board ID + * @soc_id: SOC ID + * @fw_version: FW version + * @fw_build_timestamp: FW build timestamp + * + * pld_soc_info is used to store WLAN SOC information. + */ +struct pld_soc_info { + void __iomem *v_addr; + phys_addr_t p_addr; + u32 chip_id; + u32 chip_family; + u32 board_id; + u32 soc_id; + u32 fw_version; + char fw_build_timestamp[PLD_MAX_TIMESTAMP_LEN + 1]; +}; + +/** + * struct pld_driver_ops - driver callback functions + * @probe: required operation, will be called when device is detected + * @remove: required operation, will be called when device is removed + * @shutdown: optional operation, will be called during SSR + * @reinit: optional operation, will be called during SSR + * @crash_shutdown: optional operation, will be called when a crash is + * detected + * @suspend: required operation, will be called for power management + * is enabled + * @resume: required operation, will be called for power management + * is enabled + * @modem_status: optional operation, will be called when platform driver + * sending modem power status to WLAN FW + * @uevent: optional operation, will be called when platform driver + * updating driver status + * @runtime_suspend: optional operation, prepare the device for a condition + * in which it won't be able to communicate with the CPU(s) + * and RAM due to power management. + * @runtime_resume: optional operation, put the device into the fully + * active state in response to a wakeup event generated by + * hardware or at the request of software. + * @suspend_noirq: optional operation, complete the actions started by suspend(). + * @resume_noirq: optional operation, prepare for the execution of resume() + */ +struct pld_driver_ops { + int (*probe)(struct device *dev, + enum pld_bus_type bus_type, + void *bdev, void *id); + void (*remove)(struct device *dev, + enum pld_bus_type bus_type); + void (*shutdown)(struct device *dev, + enum pld_bus_type bus_type); + int (*reinit)(struct device *dev, + enum pld_bus_type bus_type, + void *bdev, void *id); + void (*crash_shutdown)(struct device *dev, + enum pld_bus_type bus_type); + int (*suspend)(struct device *dev, + enum pld_bus_type bus_type, + pm_message_t state); + int (*resume)(struct device *dev, + enum pld_bus_type bus_type); + int (*reset_resume)(struct device *dev, + enum pld_bus_type bus_type); + void (*modem_status)(struct device *dev, + enum pld_bus_type bus_type, + int state); + void (*uevent)(struct device *dev, struct pld_uevent_data *uevent); + int (*runtime_suspend)(struct device *dev, + enum pld_bus_type bus_type); + int (*runtime_resume)(struct device *dev, + enum pld_bus_type bus_type); + int (*suspend_noirq)(struct device *dev, + enum pld_bus_type bus_type); + int (*resume_noirq)(struct device *dev, + enum pld_bus_type bus_type); +}; + +int pld_init(void); +void pld_deinit(void); + +int pld_register_driver(struct pld_driver_ops *ops); +void pld_unregister_driver(void); + +int pld_wlan_enable(struct device *dev, struct pld_wlan_enable_cfg *config, + enum pld_driver_mode mode, const char *host_version); +int pld_wlan_disable(struct device *dev, enum pld_driver_mode mode); +int pld_set_fw_log_mode(struct device *dev, u8 fw_log_mode); +void pld_get_default_fw_files(struct pld_fw_files *pfw_files); +int pld_get_fw_files_for_target(struct device *dev, + struct pld_fw_files *pfw_files, + u32 target_type, u32 target_version); +void pld_is_pci_link_down(struct device *dev); +int pld_shadow_control(struct device *dev, bool enable); +int pld_set_wlan_unsafe_channel(struct device *dev, u16 *unsafe_ch_list, + u16 ch_count); +int pld_get_wlan_unsafe_channel(struct device *dev, u16 *unsafe_ch_list, + u16 *ch_count, u16 buf_len); +int pld_wlan_set_dfs_nol(struct device *dev, void *info, u16 info_len); +int pld_wlan_get_dfs_nol(struct device *dev, void *info, u16 info_len); +void pld_schedule_recovery_work(struct device *dev); +int pld_wlan_pm_control(struct device *dev, bool vote); +void *pld_get_virt_ramdump_mem(struct device *dev, unsigned long *size); +void pld_device_crashed(struct device *dev); +void pld_device_self_recovery(struct device *dev); +void pld_intr_notify_q6(struct device *dev); +void pld_request_pm_qos(struct device *dev, u32 qos_val); +void pld_remove_pm_qos(struct device *dev); +int pld_request_bus_bandwidth(struct device *dev, int bandwidth); +int pld_get_platform_cap(struct device *dev, struct pld_platform_cap *cap); +void pld_set_driver_status(struct device *dev, enum pld_driver_status status); +int pld_get_sha_hash(struct device *dev, const u8 *data, + u32 data_len, u8 *hash_idx, u8 *out); +void *pld_get_fw_ptr(struct device *dev); +int pld_auto_suspend(struct device *dev); +int pld_auto_resume(struct device *dev); + +int pld_ce_request_irq(struct device *dev, unsigned int ce_id, + irqreturn_t (*handler)(int, void *), + unsigned long flags, const char *name, void *ctx); +int pld_ce_free_irq(struct device *dev, unsigned int ce_id, void *ctx); +void pld_enable_irq(struct device *dev, unsigned int ce_id); +void pld_disable_irq(struct device *dev, unsigned int ce_id); +int pld_get_soc_info(struct device *dev, struct pld_soc_info *info); +int pld_get_ce_id(struct device *dev, int irq); +int pld_get_irq(struct device *dev, int ce_id); +void pld_lock_pm_sem(struct device *dev); +void pld_release_pm_sem(struct device *dev); +int pld_power_on(struct device *dev); +int pld_power_off(struct device *dev); +int pld_athdiag_read(struct device *dev, uint32_t offset, uint32_t memtype, + uint32_t datalen, uint8_t *output); +int pld_athdiag_write(struct device *dev, uint32_t offset, uint32_t memtype, + uint32_t datalen, uint8_t *input); +void *pld_smmu_get_mapping(struct device *dev); +int pld_smmu_map(struct device *dev, phys_addr_t paddr, + uint32_t *iova_addr, size_t size); +unsigned int pld_socinfo_get_serial_number(struct device *dev); +uint8_t *pld_get_wlan_mac_address(struct device *dev, uint32_t *num); +int pld_is_qmi_disable(struct device *dev); +int pld_force_assert_target(struct device *dev); +void pld_increment_driver_load_cnt(struct device *dev); +int pld_get_driver_load_cnt(struct device *dev); +#endif diff --git a/drivers/staging/qcacld-3.0/core/pld/src/pld_common.c b/drivers/staging/qcacld-3.0/core/pld/src/pld_common.c new file mode 100644 index 0000000000000000000000000000000000000000..00d34e1bf87bf1f332f40416aa72ee3d8ea5a13b --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/pld/src/pld_common.c @@ -0,0 +1,1665 @@ +/* + * Copyright (c) 2016-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#define pr_fmt(fmt) "wlan_pld:%s:%d:: " fmt, __func__, __LINE__ + +#include +#include +#include +#include +#include +#include + +#if defined(CONFIG_PLD_PCIE_CNSS) || defined(CONFIG_PLD_SDIO_CNSS) +#include +#endif +#ifdef CONFIG_PLD_SNOC_ICNSS +#include +#endif + +#include "pld_pcie.h" +#include "pld_snoc.h" +#include "pld_sdio.h" +#include "pld_usb.h" + +#define PLD_PCIE_REGISTERED BIT(0) +#define PLD_SNOC_REGISTERED BIT(1) +#define PLD_SDIO_REGISTERED BIT(2) +#define PLD_USB_REGISTERED BIT(3) +#define PLD_BUS_MASK 0xf + +static struct pld_context *pld_ctx; + +/** + * pld_init() - Initialize PLD module + * + * Return: 0 for success + * Non zero failure code for errors + */ +int pld_init(void) +{ + struct pld_context *pld_context; + + pld_context = kzalloc(sizeof(*pld_context), GFP_KERNEL); + if (!pld_context) + return -ENOMEM; + + spin_lock_init(&pld_context->pld_lock); + + INIT_LIST_HEAD(&pld_context->dev_list); + + pld_ctx = pld_context; + + return 0; +} + +/** + * pld_deinit() - Uninitialize PLD module + * + * Return: void + */ +void pld_deinit(void) +{ + struct dev_node *dev_node; + struct pld_context *pld_context; + unsigned long flags; + + pld_context = pld_ctx; + if (!pld_context) { + pld_ctx = NULL; + return; + } + + spin_lock_irqsave(&pld_context->pld_lock, flags); + while (!list_empty(&pld_context->dev_list)) { + dev_node = list_first_entry(&pld_context->dev_list, + struct dev_node, list); + list_del(&dev_node->list); + kfree(dev_node); + } + spin_unlock_irqrestore(&pld_context->pld_lock, flags); + + kfree(pld_context); + + pld_ctx = NULL; +} + +/** + * pld_get_global_context() - Get global context of PLD + * + * Return: PLD global context + */ +struct pld_context *pld_get_global_context(void) +{ + return pld_ctx; +} + +/** + * pld_add_dev() - Add dev node to global context + * @pld_context: PLD global context + * @dev: device + * @type: Bus type + * + * Return: 0 for success + * Non zero failure code for errors + */ +int pld_add_dev(struct pld_context *pld_context, + struct device *dev, enum pld_bus_type type) +{ + unsigned long flags; + struct dev_node *dev_node; + + dev_node = kzalloc(sizeof(*dev_node), GFP_KERNEL); + if (dev_node == NULL) + return -ENOMEM; + + dev_node->dev = dev; + dev_node->bus_type = type; + + spin_lock_irqsave(&pld_context->pld_lock, flags); + list_add_tail(&dev_node->list, &pld_context->dev_list); + spin_unlock_irqrestore(&pld_context->pld_lock, flags); + + return 0; +} + +/** + * pld_del_dev() - Delete dev node from global context + * @pld_context: PLD global context + * @dev: device + * + * Return: void + */ +void pld_del_dev(struct pld_context *pld_context, + struct device *dev) +{ + unsigned long flags; + struct dev_node *dev_node, *tmp; + + spin_lock_irqsave(&pld_context->pld_lock, flags); + list_for_each_entry_safe(dev_node, tmp, &pld_context->dev_list, list) { + if (dev_node->dev == dev) { + list_del(&dev_node->list); + kfree(dev_node); + } + } + spin_unlock_irqrestore(&pld_context->pld_lock, flags); +} + +/** + * pld_get_bus_type() - Bus type of the device + * @dev: device + * + * Return: PLD bus type + */ +static enum pld_bus_type pld_get_bus_type(struct device *dev) +{ + struct pld_context *pld_context; + struct dev_node *dev_node; + unsigned long flags; + + pld_context = pld_get_global_context(); + + if (dev == NULL || pld_context == NULL) { + pr_err("Invalid info: dev %p, context %p\n", + dev, pld_context); + return PLD_BUS_TYPE_NONE; + } + + spin_lock_irqsave(&pld_context->pld_lock, flags); + list_for_each_entry(dev_node, &pld_context->dev_list, list) { + if (dev_node->dev == dev) { + spin_unlock_irqrestore(&pld_context->pld_lock, flags); + return dev_node->bus_type; + } + } + spin_unlock_irqrestore(&pld_context->pld_lock, flags); + + return PLD_BUS_TYPE_NONE; +} + +/** + * pld_register_driver() - Register driver to kernel + * @ops: Callback functions that will be registered to kernel + * + * This function should be called when other modules want to + * register platform driver callback functions to kernel. The + * probe() is expected to be called after registration if the + * device is online. + * + * Return: 0 for success + * Non zero failure code for errors + */ +int pld_register_driver(struct pld_driver_ops *ops) +{ + int ret = 0; + struct pld_context *pld_context; + + pld_context = pld_get_global_context(); + + if (pld_context == NULL) { + pr_err("global context is NULL\n"); + ret = -ENODEV; + goto out; + } + + if (pld_context->ops) { + pr_err("driver already registered\n"); + ret = -EEXIST; + goto out; + } + + if (!ops || !ops->probe || !ops->remove || + !ops->suspend || !ops->resume) { + pr_err("Required callback functions are missing\n"); + ret = -EINVAL; + goto out; + } + + pld_context->ops = ops; + pld_context->pld_driver_state = 0; + + ret = pld_pcie_register_driver(); + if (ret) { + pr_err("Fail to register pcie driver\n"); + goto fail_pcie; + } + pld_context->pld_driver_state |= PLD_PCIE_REGISTERED; + + ret = pld_snoc_register_driver(); + if (ret) { + pr_err("Fail to register snoc driver\n"); + goto fail_snoc; + } + pld_context->pld_driver_state |= PLD_SNOC_REGISTERED; + + ret = pld_sdio_register_driver(); + if (ret) { + pr_err("Fail to register sdio driver\n"); + goto fail_sdio; + } + pld_context->pld_driver_state |= PLD_SDIO_REGISTERED; + + ret = pld_usb_register_driver(); + if (ret) { + pr_err("Fail to register usb driver\n"); + goto fail_usb; + } + pld_context->pld_driver_state |= PLD_USB_REGISTERED; + + return ret; + +fail_usb: + pld_sdio_unregister_driver(); +fail_sdio: + pld_snoc_unregister_driver(); +fail_snoc: + pld_pcie_unregister_driver(); +fail_pcie: + pld_context->pld_driver_state = 0; + pld_context->ops = NULL; +out: + return ret; +} + +/** + * pld_unregister_driver() - Unregister driver to kernel + * + * This function should be called when other modules want to + * unregister callback functions from kernel. The remove() is + * expected to be called after registration. + * + * Return: void + */ +void pld_unregister_driver(void) +{ + struct pld_context *pld_context; + + pld_context = pld_get_global_context(); + + if (pld_context == NULL) { + pr_err("global context is NULL\n"); + return; + } + + if (pld_context->ops == NULL) { + pr_err("driver not registered\n"); + return; + } + + pld_pcie_unregister_driver(); + pld_snoc_unregister_driver(); + pld_sdio_unregister_driver(); + pld_usb_unregister_driver(); + + pld_context->pld_driver_state = 0; + + pld_context->ops = NULL; +} + +/** + * pld_wlan_enable() - Enable WLAN + * @dev: device + * @config: WLAN configuration data + * @mode: WLAN mode + * @host_version: host software version + * + * This function enables WLAN FW. It passed WLAN configuration data, + * WLAN mode and host software version to FW. + * + * Return: 0 for success + * Non zero failure code for errors + */ +int pld_wlan_enable(struct device *dev, struct pld_wlan_enable_cfg *config, + enum pld_driver_mode mode, const char *host_version) +{ + int ret = 0; + + switch (pld_get_bus_type(dev)) { + case PLD_BUS_TYPE_PCIE: + ret = pld_pcie_wlan_enable(config, mode, host_version); + break; + case PLD_BUS_TYPE_SNOC: + ret = pld_snoc_wlan_enable(config, mode, host_version); + break; + case PLD_BUS_TYPE_SDIO: + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} + +/** + * pld_wlan_disable() - Disable WLAN + * @dev: device + * @mode: WLAN mode + * + * This function disables WLAN FW. It passes WLAN mode to FW. + * + * Return: 0 for success + * Non zero failure code for errors + */ +int pld_wlan_disable(struct device *dev, enum pld_driver_mode mode) +{ + int ret = 0; + + switch (pld_get_bus_type(dev)) { + case PLD_BUS_TYPE_PCIE: + ret = pld_pcie_wlan_disable(mode); + break; + case PLD_BUS_TYPE_SNOC: + ret = pld_snoc_wlan_disable(mode); + break; + case PLD_BUS_TYPE_SDIO: + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} + +/** + * pld_set_fw_log_mode() - Set FW debug log mode + * @dev: device + * @fw_log_mode: 0 for No log, 1 for WMI, 2 for DIAG + * + * Switch Fw debug log mode between DIAG logging and WMI logging. + * + * Return: 0 for success + * Non zero failure code for errors + */ +int pld_set_fw_log_mode(struct device *dev, u8 fw_log_mode) +{ + int ret = 0; + + switch (pld_get_bus_type(dev)) { + case PLD_BUS_TYPE_PCIE: + ret = pld_pcie_set_fw_log_mode(fw_log_mode); + break; + case PLD_BUS_TYPE_SNOC: + ret = pld_snoc_set_fw_log_mode(fw_log_mode); + break; + case PLD_BUS_TYPE_SDIO: + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} + +/** + * pld_get_default_fw_files() - Get default FW file names + * @pfw_files: buffer for FW file names + * + * Return default FW file names to the buffer. + * + * Return: void + */ +void pld_get_default_fw_files(struct pld_fw_files *pfw_files) +{ + memset(pfw_files, 0, sizeof(*pfw_files)); + + strlcpy(pfw_files->image_file, PLD_IMAGE_FILE, + PLD_MAX_FILE_NAME); + strlcpy(pfw_files->board_data, PLD_BOARD_DATA_FILE, + PLD_MAX_FILE_NAME); + strlcpy(pfw_files->otp_data, PLD_OTP_FILE, + PLD_MAX_FILE_NAME); + strlcpy(pfw_files->utf_file, PLD_UTF_FIRMWARE_FILE, + PLD_MAX_FILE_NAME); + strlcpy(pfw_files->utf_board_data, PLD_BOARD_DATA_FILE, + PLD_MAX_FILE_NAME); + strlcpy(pfw_files->epping_file, PLD_EPPING_FILE, + PLD_MAX_FILE_NAME); + strlcpy(pfw_files->setup_file, PLD_SETUP_FILE, + PLD_MAX_FILE_NAME); +} + +/** + * pld_get_fw_files_for_target() - Get FW file names + * @dev: device + * @pfw_files: buffer for FW file names + * @target_type: target type + * @target_version: target version + * + * Return target specific FW file names to the buffer. + * + * Return: 0 for success + * Non zero failure code for errors + */ +int pld_get_fw_files_for_target(struct device *dev, + struct pld_fw_files *pfw_files, + u32 target_type, u32 target_version) +{ + int ret = 0; + + switch (pld_get_bus_type(dev)) { + case PLD_BUS_TYPE_PCIE: + ret = pld_pcie_get_fw_files_for_target(pfw_files, + target_type, target_version); + break; + case PLD_BUS_TYPE_SNOC: + break; + case PLD_BUS_TYPE_SDIO: + ret = pld_sdio_get_fw_files_for_target(pfw_files, + target_type, target_version); + break; + case PLD_BUS_TYPE_USB: + ret = pld_usb_get_fw_files_for_target(pfw_files, + target_type, target_version); + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} + +/** + * pld_is_pci_link_down() - Notification for pci link down event + * @dev: device + * + * Notify platform that pci link is down. + * + * Return: void + */ +void pld_is_pci_link_down(struct device *dev) +{ + switch (pld_get_bus_type(dev)) { + case PLD_BUS_TYPE_PCIE: + pld_pcie_link_down(); + break; + case PLD_BUS_TYPE_SNOC: + break; + default: + pr_err("Invalid device type\n"); + break; + } +} + +/** + * pld_shadow_control() - Control pci shadow registers + * @dev: device + * @enable: 0 for disable, 1 for enable + * + * This function is for suspend/resume. It can control if we + * use pci shadow registers (for saving config space) or not. + * During suspend we disable it to avoid config space corruption. + * + * Return: 0 for success + * Non zero failure code for errors + */ +int pld_shadow_control(struct device *dev, bool enable) +{ + int ret = 0; + + switch (pld_get_bus_type(dev)) { + case PLD_BUS_TYPE_PCIE: + ret = pld_pcie_shadow_control(enable); + break; + case PLD_BUS_TYPE_SNOC: + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} + +/** + * pld_set_wlan_unsafe_channel() - Set unsafe channel + * @dev: device + * @unsafe_ch_list: unsafe channel list + * @ch_count: number of channel + * + * Return: 0 for success + * Non zero failure code for errors + */ +int pld_set_wlan_unsafe_channel(struct device *dev, + u16 *unsafe_ch_list, u16 ch_count) +{ + int ret = 0; + + switch (pld_get_bus_type(dev)) { + case PLD_BUS_TYPE_PCIE: + ret = pld_pcie_set_wlan_unsafe_channel(unsafe_ch_list, + ch_count); + break; + case PLD_BUS_TYPE_SNOC: + ret = pld_snoc_set_wlan_unsafe_channel(unsafe_ch_list, + ch_count); + break; + case PLD_BUS_TYPE_SDIO: + /* To do get unsafe channel via cnss sdio API */ + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} + +/** + * pld_get_wlan_unsafe_channel() - Get unsafe channel + * @dev: device + * @unsafe_ch_list: buffer to unsafe channel list + * @ch_count: number of channel + * @buf_len: buffer length + * + * Return WLAN unsafe channel to the buffer. + * + * Return: 0 for success + * Non zero failure code for errors + */ +int pld_get_wlan_unsafe_channel(struct device *dev, u16 *unsafe_ch_list, + u16 *ch_count, u16 buf_len) +{ + int ret = 0; + + switch (pld_get_bus_type(dev)) { + case PLD_BUS_TYPE_PCIE: + ret = pld_pcie_get_wlan_unsafe_channel(unsafe_ch_list, + ch_count, buf_len); + break; + case PLD_BUS_TYPE_SNOC: + ret = pld_snoc_get_wlan_unsafe_channel(unsafe_ch_list, + ch_count, buf_len); + break; + case PLD_BUS_TYPE_SDIO: + /* To do get unsafe channel via cnss sdio API */ + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} + +/** + * pld_wlan_set_dfs_nol() - Set DFS info + * @dev: device + * @info: DFS info + * @info_len: info length + * + * Return: 0 for success + * Non zero failure code for errors + */ +int pld_wlan_set_dfs_nol(struct device *dev, void *info, u16 info_len) +{ + int ret = 0; + + switch (pld_get_bus_type(dev)) { + case PLD_BUS_TYPE_PCIE: + ret = pld_pcie_wlan_set_dfs_nol(info, info_len); + break; + case PLD_BUS_TYPE_SNOC: + ret = pld_snoc_wlan_set_dfs_nol(info, info_len); + break; + case PLD_BUS_TYPE_SDIO: + /* To do get nol via cnss sdio API */ + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} + +/** + * pld_wlan_get_dfs_nol() - Get DFS info + * @dev: device + * @info: buffer to DFS info + * @info_len: info length + * + * Return DFS info to the buffer. + * + * Return: 0 for success + * Non zero failure code for errors + */ +int pld_wlan_get_dfs_nol(struct device *dev, void *info, u16 info_len) +{ + int ret = 0; + + switch (pld_get_bus_type(dev)) { + case PLD_BUS_TYPE_PCIE: + ret = pld_pcie_wlan_get_dfs_nol(info, info_len); + break; + case PLD_BUS_TYPE_SNOC: + ret = pld_snoc_wlan_get_dfs_nol(info, info_len); + break; + case PLD_BUS_TYPE_SDIO: + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} + +/** + * pld_schedule_recovery_work() - Schedule recovery work + * @dev: device + * + * Schedule a system self recovery work. + * + * Return: void + */ +void pld_schedule_recovery_work(struct device *dev) +{ + switch (pld_get_bus_type(dev)) { + case PLD_BUS_TYPE_PCIE: + pld_pcie_schedule_recovery_work(); + break; + case PLD_BUS_TYPE_SNOC: + break; + default: + pr_err("Invalid device type\n"); + break; + } +} + +/** + * pld_wlan_pm_control() - WLAN PM control on PCIE + * @dev: device + * @vote: 0 for enable PCIE PC, 1 for disable PCIE PC + * + * This is for PCIE power collaps control during suspend/resume. + * When PCIE power collaps is disabled, WLAN FW can access memory + * through PCIE when system is suspended. + * + * Return: 0 for success + * Non zero failure code for errors + */ +int pld_wlan_pm_control(struct device *dev, bool vote) +{ + int ret = 0; + + switch (pld_get_bus_type(dev)) { + case PLD_BUS_TYPE_PCIE: + ret = pld_pcie_wlan_pm_control(vote); + break; + case PLD_BUS_TYPE_SNOC: + break; + case PLD_BUS_TYPE_SDIO: + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} + +/** + * pld_get_virt_ramdump_mem() - Get virtual ramdump memory + * @dev: device + * @size: buffer to virtual memory size + * + * Return: virtual ramdump memory address + */ +void *pld_get_virt_ramdump_mem(struct device *dev, unsigned long *size) +{ + void *mem = NULL; + + switch (pld_get_bus_type(dev)) { + case PLD_BUS_TYPE_PCIE: + mem = pld_pcie_get_virt_ramdump_mem(size); + break; + case PLD_BUS_TYPE_SNOC: + break; + case PLD_BUS_TYPE_SDIO: + break; + default: + pr_err("Invalid device type\n"); + break; + } + + return mem; +} + +/** + * pld_device_crashed() - Notification for device crash event + * @dev: device + * + * Notify subsystem a device crashed event. A subsystem restart + * is expected to happen after calling this function. + * + * Return: void + */ +void pld_device_crashed(struct device *dev) +{ + switch (pld_get_bus_type(dev)) { + case PLD_BUS_TYPE_PCIE: + pld_pcie_device_crashed(); + break; + case PLD_BUS_TYPE_SNOC: + break; + case PLD_BUS_TYPE_SDIO: + break; + default: + pr_err("Invalid device type\n"); + break; + } +} + +/** + * pld_device_self_recovery() - Device self recovery + * @dev: device + * + * Return: void + */ +void pld_device_self_recovery(struct device *dev) +{ + switch (pld_get_bus_type(dev)) { + case PLD_BUS_TYPE_PCIE: + pld_pcie_device_self_recovery(); + break; + case PLD_BUS_TYPE_SNOC: + break; + case PLD_BUS_TYPE_SDIO: + break; + default: + pr_err("Invalid device type\n"); + break; + } +} + +/** + * pld_intr_notify_q6() - Notify Q6 FW interrupts + * @dev: device + * + * Notify Q6 that a FW interrupt is triggered. + * + * Return: void + */ +void pld_intr_notify_q6(struct device *dev) +{ + switch (pld_get_bus_type(dev)) { + case PLD_BUS_TYPE_PCIE: + pld_pcie_intr_notify_q6(); + break; + case PLD_BUS_TYPE_SNOC: + break; + default: + pr_err("Invalid device type\n"); + break; + } +} + +/** + * pld_request_pm_qos() - Request system PM + * @dev: device + * @qos_val: request value + * + * It votes for the value of aggregate QoS expectations. + * + * Return: void + */ +void pld_request_pm_qos(struct device *dev, u32 qos_val) +{ + switch (pld_get_bus_type(dev)) { + case PLD_BUS_TYPE_PCIE: + pld_pcie_request_pm_qos(qos_val); + break; + case PLD_BUS_TYPE_SNOC: + break; + case PLD_BUS_TYPE_SDIO: + /* To do Add call cns API */ + break; + case PLD_BUS_TYPE_USB: + break; + default: + pr_err("Invalid device type\n"); + break; + } +} + +/** + * pld_remove_pm_qos() - Remove system PM + * @dev: device + * + * Remove the vote request for Qos expectations. + * + * Return: void + */ +void pld_remove_pm_qos(struct device *dev) +{ + switch (pld_get_bus_type(dev)) { + case PLD_BUS_TYPE_PCIE: + pld_pcie_remove_pm_qos(); + break; + case PLD_BUS_TYPE_SNOC: + break; + case PLD_BUS_TYPE_SDIO: + /* To do Add call cns API */ + break; + default: + pr_err("Invalid device type\n"); + break; + } +} + +/** + * pld_request_bus_bandwidth() - Request bus bandwidth + * @dev: device + * @bandwidth: bus bandwidth + * + * Votes for HIGH/MEDIUM/LOW bus bandwidth. + * + * Return: 0 for success + * Non zero failure code for errors + */ +int pld_request_bus_bandwidth(struct device *dev, int bandwidth) +{ + int ret = 0; + + switch (pld_get_bus_type(dev)) { + case PLD_BUS_TYPE_PCIE: + ret = pld_pcie_request_bus_bandwidth(bandwidth); + break; + case PLD_BUS_TYPE_SNOC: + break; + case PLD_BUS_TYPE_SDIO: + /* To do Add call cns API */ + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} + +/** + * pld_get_platform_cap() - Get platform capabilities + * @dev: device + * @cap: buffer to the capabilities + * + * Return capabilities to the buffer. + * + * Return: 0 for success + * Non zero failure code for errors + */ +int pld_get_platform_cap(struct device *dev, struct pld_platform_cap *cap) +{ + int ret = 0; + + switch (pld_get_bus_type(dev)) { + case PLD_BUS_TYPE_PCIE: + ret = pld_pcie_get_platform_cap(cap); + break; + case PLD_BUS_TYPE_SNOC: + break; + case PLD_BUS_TYPE_SDIO: + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} + +/** + * pld_set_driver_status() - Set driver status + * @dev: device + * @status: driver status + * + * Return: void + */ +void pld_set_driver_status(struct device *dev, enum pld_driver_status status) +{ + switch (pld_get_bus_type(dev)) { + case PLD_BUS_TYPE_PCIE: + pld_pcie_set_driver_status(status); + break; + case PLD_BUS_TYPE_SNOC: + break; + case PLD_BUS_TYPE_SDIO: + break; + default: + pr_err("Invalid device type\n"); + break; + } +} + +/** + * pld_get_sha_hash() - Get sha hash number + * @dev: device + * @data: input data + * @data_len: data length + * @hash_idx: hash index + * @out: output buffer + * + * Return computed hash to the out buffer. + * + * Return: 0 for success + * Non zero failure code for errors + */ +int pld_get_sha_hash(struct device *dev, const u8 *data, + u32 data_len, u8 *hash_idx, u8 *out) +{ + int ret = 0; + + switch (pld_get_bus_type(dev)) { + case PLD_BUS_TYPE_PCIE: + ret = pld_pcie_get_sha_hash(data, data_len, + hash_idx, out); + break; + case PLD_BUS_TYPE_SNOC: + break; + case PLD_BUS_TYPE_SDIO: + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} + +/** + * pld_get_fw_ptr() - Get secure FW memory address + * @dev: device + * + * Return: secure memory address + */ +void *pld_get_fw_ptr(struct device *dev) +{ + void *ptr = NULL; + + switch (pld_get_bus_type(dev)) { + case PLD_BUS_TYPE_PCIE: + ptr = pld_pcie_get_fw_ptr(); + break; + case PLD_BUS_TYPE_SNOC: + break; + case PLD_BUS_TYPE_SDIO: + break; + default: + pr_err("Invalid device type\n"); + break; + } + + return ptr; +} + +/** + * pld_auto_suspend() - Auto suspend + * @dev: device + * + * Return: 0 for success + * Non zero failure code for errors + */ +int pld_auto_suspend(struct device *dev) +{ + int ret = 0; + + switch (pld_get_bus_type(dev)) { + case PLD_BUS_TYPE_PCIE: + ret = pld_pcie_auto_suspend(); + break; + case PLD_BUS_TYPE_SNOC: + break; + case PLD_BUS_TYPE_SDIO: + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} + +/** + * pld_auto_resume() - Auto resume + * @dev: device + * + * Return: 0 for success + * Non zero failure code for errors + */ +int pld_auto_resume(struct device *dev) +{ + int ret = 0; + + switch (pld_get_bus_type(dev)) { + case PLD_BUS_TYPE_PCIE: + ret = pld_pcie_auto_resume(); + break; + case PLD_BUS_TYPE_SNOC: + break; + case PLD_BUS_TYPE_SDIO: + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} + +/** + * pld_ce_request_irq() - Register IRQ for CE + * @dev: device + * @ce_id: CE number + * @handler: IRQ callback function + * @flags: IRQ flags + * @name: IRQ name + * @ctx: IRQ context + * + * Return: 0 for success + * Non zero failure code for errors + */ +int pld_ce_request_irq(struct device *dev, unsigned int ce_id, + irqreturn_t (*handler)(int, void *), + unsigned long flags, const char *name, void *ctx) +{ + int ret = 0; + + switch (pld_get_bus_type(dev)) { + case PLD_BUS_TYPE_SNOC: + ret = pld_snoc_ce_request_irq(ce_id, handler, flags, name, ctx); + break; + case PLD_BUS_TYPE_PCIE: + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} + +/** + * pld_ce_free_irq() - Free IRQ for CE + * @dev: device + * @ce_id: CE number + * @ctx: IRQ context + * + * Return: 0 for success + * Non zero failure code for errors + */ +int pld_ce_free_irq(struct device *dev, unsigned int ce_id, void *ctx) +{ + int ret = 0; + + switch (pld_get_bus_type(dev)) { + case PLD_BUS_TYPE_SNOC: + ret = pld_snoc_ce_free_irq(ce_id, ctx); + break; + case PLD_BUS_TYPE_PCIE: + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} + +/** + * pld_enable_irq() - Enable IRQ for CE + * @dev: device + * @ce_id: CE number + * + * Return: void + */ +void pld_enable_irq(struct device *dev, unsigned int ce_id) +{ + switch (pld_get_bus_type(dev)) { + case PLD_BUS_TYPE_SNOC: + pld_snoc_enable_irq(ce_id); + break; + case PLD_BUS_TYPE_PCIE: + break; + case PLD_BUS_TYPE_SDIO: + break; + default: + pr_err("Invalid device type\n"); + break; + } +} + +/** + * pld_disable_irq() - Disable IRQ for CE + * @dev: device + * @ce_id: CE number + * + * Return: void + */ +void pld_disable_irq(struct device *dev, unsigned int ce_id) +{ + switch (pld_get_bus_type(dev)) { + case PLD_BUS_TYPE_SNOC: + pld_snoc_disable_irq(ce_id); + break; + case PLD_BUS_TYPE_PCIE: + break; + case PLD_BUS_TYPE_SDIO: + break; + default: + pr_err("Invalid device type\n"); + break; + } +} + +/** + * pld_increment_driver_load_cnt() - Maintain driver load count + * @dev: device + * + * This function maintain a count which get increase whenever wiphy + * is registered + * + * Return: void + */ +void pld_increment_driver_load_cnt(struct device *dev) +{ + switch (pld_get_bus_type(dev)) { + case PLD_BUS_TYPE_PCIE: + pld_pcie_increment_driver_load_cnt(); + break; + case PLD_BUS_TYPE_SNOC: + pld_snoc_increment_driver_load_cnt(); + break; + case PLD_BUS_TYPE_SDIO: + break; + default: + pr_err("Invalid device type\n"); + break; + } +} + +/** + * pld_get_driver_load_cnt() - get driver load count + * @dev: device + * + * This function provide total wiphy registration count from starting + * + * Return: int + */ +int pld_get_driver_load_cnt(struct device *dev) +{ + int ret = 0; + + switch (pld_get_bus_type(dev)) { + case PLD_BUS_TYPE_PCIE: + ret = pld_pcie_get_driver_load_cnt(); + break; + case PLD_BUS_TYPE_SNOC: + ret = pld_snoc_get_driver_load_cnt(); + break; + case PLD_BUS_TYPE_SDIO: + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} + +/** + * pld_get_soc_info() - Get SOC information + * @dev: device + * @info: buffer to SOC information + * + * Return SOC info to the buffer. + * + * Return: 0 for success + * Non zero failure code for errors + */ +int pld_get_soc_info(struct device *dev, struct pld_soc_info *info) +{ + int ret = 0; + + switch (pld_get_bus_type(dev)) { + case PLD_BUS_TYPE_SNOC: + ret = pld_snoc_get_soc_info(info); + break; + case PLD_BUS_TYPE_PCIE: + break; + case PLD_BUS_TYPE_SDIO: + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} + +/** + * pld_get_ce_id() - Get CE number for the provided IRQ + * @dev: device + * @irq: IRQ number + * + * Return: CE number + */ +int pld_get_ce_id(struct device *dev, int irq) +{ + int ret = 0; + + switch (pld_get_bus_type(dev)) { + case PLD_BUS_TYPE_SNOC: + ret = pld_snoc_get_ce_id(irq); + break; + case PLD_BUS_TYPE_PCIE: + ret = pld_pcie_get_ce_id(irq); + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} + +/** + * pld_get_irq() - Get IRQ number for given CE ID + * @dev: device + * @ce_id: CE ID + * + * Return: IRQ number + */ +int pld_get_irq(struct device *dev, int ce_id) +{ + int ret = 0; + + switch (pld_get_bus_type(dev)) { + case PLD_BUS_TYPE_SNOC: + ret = pld_snoc_get_irq(ce_id); + break; + case PLD_BUS_TYPE_PCIE: + default: + ret = -EINVAL; + break; + } + + return ret; +} + +/** + * pld_lock_pm_sem() - Lock PM semaphore + * @dev: device + * + * Return: void + */ +void pld_lock_pm_sem(struct device *dev) +{ + switch (pld_get_bus_type(dev)) { + case PLD_BUS_TYPE_PCIE: + pld_pcie_lock_pm_sem(); + break; + case PLD_BUS_TYPE_SNOC: + break; + case PLD_BUS_TYPE_SDIO: + break; + case PLD_BUS_TYPE_USB: + break; + default: + pr_err("Invalid device type\n"); + break; + } +} + +/** + * pld_release_pm_sem() - Release PM semaphore + * @dev: device + * + * Return: void + */ +void pld_release_pm_sem(struct device *dev) +{ + switch (pld_get_bus_type(dev)) { + case PLD_BUS_TYPE_PCIE: + pld_pcie_release_pm_sem(); + break; + case PLD_BUS_TYPE_SNOC: + break; + case PLD_BUS_TYPE_SDIO: + break; + case PLD_BUS_TYPE_USB: + break; + default: + pr_err("Invalid device type\n"); + break; + } +} + +/** + * pld_power_on() - Power on WLAN hardware + * @dev: device + * + * Return: 0 for success + * Non zero failure code for errors + */ +int pld_power_on(struct device *dev) +{ + int ret = 0; + + switch (pld_get_bus_type(dev)) { + case PLD_BUS_TYPE_PCIE: + ret = pld_pcie_power_on(dev); + break; + case PLD_BUS_TYPE_SNOC: + ret = pld_snoc_power_on(dev); + break; + default: + pr_err("Invalid device type\n"); + break; + } + + return ret; +} + +/** + * pld_power_off() - Power off WLAN hardware + * @dev: device + * + * Return: 0 for success + * Non zero failure code for errors + */ +int pld_power_off(struct device *dev) +{ + int ret = 0; + + switch (pld_get_bus_type(dev)) { + case PLD_BUS_TYPE_PCIE: + ret = pld_pcie_power_off(dev); + break; + case PLD_BUS_TYPE_SNOC: + ret = pld_snoc_power_off(dev); + break; + default: + pr_err("Invalid device type\n"); + break; + } + + return ret; +} + +/** + * pld_athdiag_read() - Read data from WLAN FW + * @dev: device + * @offset: address offset + * @memtype: memory type + * @datalen: data length + * @output: output buffer + * + * Return: 0 for success + * Non zero failure code for errors + */ +int pld_athdiag_read(struct device *dev, uint32_t offset, + uint32_t memtype, uint32_t datalen, + uint8_t *output) +{ + int ret = 0; + + switch (pld_get_bus_type(dev)) { + case PLD_BUS_TYPE_SNOC: + ret = pld_snoc_athdiag_read(dev, offset, memtype, + datalen, output); + break; + case PLD_BUS_TYPE_PCIE: + case PLD_BUS_TYPE_SDIO: + case PLD_BUS_TYPE_USB: + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} + +/** + * pld_athdiag_write() - Write data to WLAN FW + * @dev: device + * @offset: address offset + * @memtype: memory type + * @datalen: data length + * @input: input buffer + * + * Return: 0 for success + * Non zero failure code for errors + */ +int pld_athdiag_write(struct device *dev, uint32_t offset, + uint32_t memtype, uint32_t datalen, + uint8_t *input) +{ + int ret = 0; + + switch (pld_get_bus_type(dev)) { + case PLD_BUS_TYPE_SNOC: + ret = pld_snoc_athdiag_write(dev, offset, memtype, + datalen, input); + break; + case PLD_BUS_TYPE_PCIE: + case PLD_BUS_TYPE_SDIO: + case PLD_BUS_TYPE_USB: + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} + +/** + * pld_smmu_get_mapping() - Get SMMU mapping context + * @dev: device + * + * Return: Pointer to the mapping context + */ +void *pld_smmu_get_mapping(struct device *dev) +{ + void *ptr = NULL; + enum pld_bus_type type = pld_get_bus_type(dev); + + switch (type) { + case PLD_BUS_TYPE_SNOC: + ptr = pld_snoc_smmu_get_mapping(dev); + break; + case PLD_BUS_TYPE_PCIE: + pr_err("Not supported on type %d\n", type); + break; + default: + pr_err("Invalid device type %d\n", type); + break; + } + + return ptr; +} + +/** + * pld_smmu_map() - Map SMMU + * @dev: device + * @paddr: physical address that needs to map to + * @iova_addr: IOVA address + * @size: size to be mapped + * + * Return: 0 for success + * Non zero failure code for errors + */ +int pld_smmu_map(struct device *dev, phys_addr_t paddr, + uint32_t *iova_addr, size_t size) +{ + int ret = 0; + enum pld_bus_type type = pld_get_bus_type(dev); + + switch (type) { + case PLD_BUS_TYPE_SNOC: + ret = pld_snoc_smmu_map(dev, paddr, iova_addr, size); + break; + case PLD_BUS_TYPE_PCIE: + pr_err("Not supported on type %d\n", type); + ret = -ENODEV; + break; + default: + pr_err("Invalid device type %d\n", type); + ret = -EINVAL; + break; + } + + return ret; +} + +/** + * pld_socinfo_get_serial_number() - Get SOC serial number + * @dev: device + * + * Return: SOC serial number + */ +unsigned int pld_socinfo_get_serial_number(struct device *dev) +{ + unsigned int ret = 0; + enum pld_bus_type type = pld_get_bus_type(dev); + + switch (type) { + case PLD_BUS_TYPE_SNOC: + ret = pld_snoc_socinfo_get_serial_number(dev); + break; + case PLD_BUS_TYPE_PCIE: + pr_err("Not supported on type %d\n", type); + break; + default: + pr_err("Invalid device type %d\n", type); + break; + } + + return ret; +} + +/* + * pld_get_wlan_mac_address() - API to query MAC address from Platform + * Driver + * @dev: Device Structure + * @num: Pointer to number of MAC address supported + * + * Platform Driver can have MAC address stored. This API needs to be used + * to get those MAC address + * + * Return: Pointer to the list of MAC address + */ +uint8_t *pld_get_wlan_mac_address(struct device *dev, uint32_t *num) +{ + enum pld_bus_type type = pld_get_bus_type(dev); + + switch (type) { + case PLD_BUS_TYPE_PCIE: + return pld_pcie_get_wlan_mac_address(dev, num); + case PLD_BUS_TYPE_SDIO: + return pld_sdio_get_wlan_mac_address(dev, num); + case PLD_BUS_TYPE_SNOC: + return pld_snoc_get_wlan_mac_address(dev, num); + case PLD_BUS_TYPE_USB: + pr_err("Not supported on type %d\n", type); + break; + default: + pr_err("Invalid device type\n"); + break; + } + + *num = 0; + return NULL; +} + +/** + * pld_is_qmi_disable() - Check QMI support is present or not + * @dev: device + * + * Return: 1 QMI is not supported + * 0 QMI is supported + * Non zero failure code for errors + */ +int pld_is_qmi_disable(struct device *dev) +{ + int ret = 0; + enum pld_bus_type type = pld_get_bus_type(dev); + + switch (type) { + case PLD_BUS_TYPE_SNOC: + ret = pld_snoc_is_qmi_disable(); + break; + case PLD_BUS_TYPE_PCIE: + case PLD_BUS_TYPE_SDIO: + pr_err("Not supported on type %d\n", type); + ret = -EINVAL; + break; + default: + pr_err("Invalid device type %d\n", type); + ret = -EINVAL; + break; + } + + return ret; +} + +/** + * pld_force_assert_target() - Send a force assert to FW. + * This can use various sideband requests available at platform to + * initiate a FW assert. + * @dev: device + * + * Return: 0 if force assert of target was triggered successfully + * Non zero failure code for errors + */ +int pld_force_assert_target(struct device *dev) +{ + int ret = 0; + enum pld_bus_type type = pld_get_bus_type(dev); + + switch (type) { + case PLD_BUS_TYPE_SNOC: + ret = pld_snoc_force_assert_target(dev); + break; + + case PLD_BUS_TYPE_PCIE: + case PLD_BUS_TYPE_SDIO: + ret = -EINVAL; + break; + default: + pr_err("Invalid device type %d\n", type); + ret = -EINVAL; + break; + } + return ret; +} diff --git a/drivers/staging/qcacld-3.0/core/pld/src/pld_internal.h b/drivers/staging/qcacld-3.0/core/pld/src/pld_internal.h new file mode 100644 index 0000000000000000000000000000000000000000..315fb6f07a672f373f7b8d6c5c280fb5479d249f --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/pld/src/pld_internal.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef __PLD_COMMON_I_H__ +#define __PLD_COMMON_I_H__ + +#include "pld_common.h" + +struct dev_node { + struct device *dev; + struct list_head list; + enum pld_bus_type bus_type; +}; + +struct pld_context { + struct pld_driver_ops *ops; + spinlock_t pld_lock; + struct list_head dev_list; + uint32_t pld_driver_state; +}; + +struct pld_context *pld_get_global_context(void); +int pld_add_dev(struct pld_context *pld_context, + struct device *dev, enum pld_bus_type type); +void pld_del_dev(struct pld_context *pld_context, + struct device *dev); + +#endif diff --git a/drivers/staging/qcacld-3.0/core/pld/src/pld_pcie.c b/drivers/staging/qcacld-3.0/core/pld/src/pld_pcie.c new file mode 100644 index 0000000000000000000000000000000000000000..23265b50c9417012cd3b830378c4d9207c83fd6e --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/pld/src/pld_pcie.c @@ -0,0 +1,537 @@ +/* + * Copyright (c) 2016-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#include +#include +#include +#include +#include + +#ifdef CONFIG_PLD_PCIE_CNSS +#include +#endif + +#include "pld_internal.h" +#include "pld_pcie.h" + +#ifdef CONFIG_PCI + +#ifdef QCA_WIFI_3_0_ADRASTEA +#define CE_COUNT_MAX 12 +#else +#define CE_COUNT_MAX 8 +#endif + +/** + * pld_pcie_probe() - Probe function for PCIE platform driver + * @pdev: PCIE device + * @id: PCIE device ID table + * + * The probe function will be called when PCIE device provided + * in the ID table is detected. + * + * Return: int + */ +static int pld_pcie_probe(struct pci_dev *pdev, + const struct pci_device_id *id) +{ + struct pld_context *pld_context; + int ret = 0; + + pld_context = pld_get_global_context(); + if (!pld_context) { + ret = -ENODEV; + goto out; + } + + ret = pld_add_dev(pld_context, &pdev->dev, PLD_BUS_TYPE_PCIE); + if (ret) + goto out; + + return pld_context->ops->probe(&pdev->dev, + PLD_BUS_TYPE_PCIE, pdev, (void *)id); + +out: + return ret; +} + + +/** + * pld_pcie_remove() - Remove function for PCIE device + * @pdev: PCIE device + * + * The remove function will be called when PCIE device is disconnected + * + * Return: void + */ +static void pld_pcie_remove(struct pci_dev *pdev) +{ + struct pld_context *pld_context; + + pld_context = pld_get_global_context(); + + if (!pld_context) + return; + + pld_context->ops->remove(&pdev->dev, PLD_BUS_TYPE_PCIE); + + pld_del_dev(pld_context, &pdev->dev); +} + +#ifdef CONFIG_PLD_PCIE_CNSS +/** + * pld_pcie_reinit() - SSR re-initialize function for PCIE device + * @pdev: PCIE device + * @id: PCIE device ID + * + * During subsystem restart(SSR), this function will be called to + * re-initialize PCIE device. + * + * Return: int + */ +static int pld_pcie_reinit(struct pci_dev *pdev, + const struct pci_device_id *id) +{ + struct pld_context *pld_context; + + pld_context = pld_get_global_context(); + if (pld_context->ops->reinit) + return pld_context->ops->reinit(&pdev->dev, + PLD_BUS_TYPE_PCIE, pdev, (void *)id); + + return -ENODEV; +} + +/** + * pld_pcie_shutdown() - SSR shutdown function for PCIE device + * @pdev: PCIE device + * + * During SSR, this function will be called to shutdown PCIE device. + * + * Return: void + */ +static void pld_pcie_shutdown(struct pci_dev *pdev) +{ + struct pld_context *pld_context; + + pld_context = pld_get_global_context(); + if (pld_context->ops->shutdown) + pld_context->ops->shutdown(&pdev->dev, PLD_BUS_TYPE_PCIE); +} + +/** + * pld_pcie_crash_shutdown() - Crash shutdown function for PCIE device + * @pdev: PCIE device + * + * This function will be called when a crash is detected, it will shutdown + * the PCIE device. + * + * Return: void + */ +static void pld_pcie_crash_shutdown(struct pci_dev *pdev) +{ + struct pld_context *pld_context; + + pld_context = pld_get_global_context(); + if (pld_context->ops->crash_shutdown) + pld_context->ops->crash_shutdown(&pdev->dev, PLD_BUS_TYPE_PCIE); +} + +/** + * pld_pcie_notify_handler() - Modem state notification callback function + * @pdev: PCIE device + * @state: modem power state + * + * This function will be called when there's a modem power state change. + * + * Return: void + */ +static void pld_pcie_notify_handler(struct pci_dev *pdev, int state) +{ + struct pld_context *pld_context; + + pld_context = pld_get_global_context(); + if (pld_context->ops->modem_status) + pld_context->ops->modem_status(&pdev->dev, + PLD_BUS_TYPE_PCIE, state); +} + +/** + * pld_pcie_uevent() - update wlan driver status callback function + * @pdev: PCIE device + * @status driver uevent status + * + * This function will be called when platform driver wants to update wlan + * driver's status. + * + * Return: void + */ +static void pld_pcie_uevent(struct pci_dev *pdev, uint32_t status) +{ + struct pld_context *pld_context; + struct pld_uevent_data data; + + pld_context = pld_get_global_context(); + if (!pld_context) + return; + + data.uevent = status; + + if (!pld_context->ops->uevent) + pld_context->ops->uevent(&pdev->dev, &data); + + return; +} + +#ifdef FEATURE_RUNTIME_PM +/** + * pld_pcie_runtime_suspend() - PM runtime suspend + * @pdev: PCIE device + * + * PM runtime suspend callback function. + * + * Return: int + */ +static int pld_pcie_runtime_suspend(struct pci_dev *pdev) +{ + struct pld_context *pld_context; + + pld_context = pld_get_global_context(); + if (pld_context->ops->runtime_suspend) + return pld_context->ops->runtime_suspend(&pdev->dev, + PLD_BUS_TYPE_PCIE); + + return -ENODEV; +} + +/** + * pld_pcie_runtime_resume() - PM runtime resume + * @pdev: PCIE device + * + * PM runtime resume callback function. + * + * Return: int + */ +static int pld_pcie_runtime_resume(struct pci_dev *pdev) +{ + struct pld_context *pld_context; + + pld_context = pld_get_global_context(); + if (pld_context->ops->runtime_resume) + return pld_context->ops->runtime_resume(&pdev->dev, + PLD_BUS_TYPE_PCIE); + + return -ENODEV; +} +#endif +#endif + +#ifdef CONFIG_PM +/** + * pld_pcie_suspend() - Suspend callback function for power management + * @pdev: PCIE device + * @state: power state + * + * This function is to suspend the PCIE device when power management is + * enabled. + * + * Return: void + */ +static int pld_pcie_suspend(struct pci_dev *pdev, pm_message_t state) +{ + struct pld_context *pld_context; + + pld_context = pld_get_global_context(); + return pld_context->ops->suspend(&pdev->dev, + PLD_BUS_TYPE_PCIE, state); +} + +/** + * pld_pcie_resume() - Resume callback function for power management + * @pdev: PCIE device + * + * This function is to resume the PCIE device when power management is + * enabled. + * + * Return: void + */ +static int pld_pcie_resume(struct pci_dev *pdev) +{ + struct pld_context *pld_context; + + pld_context = pld_get_global_context(); + return pld_context->ops->resume(&pdev->dev, PLD_BUS_TYPE_PCIE); +} +#endif + +static struct pci_device_id pld_pcie_id_table[] = { + { 0x168c, 0x003c, PCI_ANY_ID, PCI_ANY_ID }, + { 0x168c, 0x003e, PCI_ANY_ID, PCI_ANY_ID }, + { 0x168c, 0x0041, PCI_ANY_ID, PCI_ANY_ID }, + { 0x168c, 0xabcd, PCI_ANY_ID, PCI_ANY_ID }, + { 0x168c, 0x7021, PCI_ANY_ID, PCI_ANY_ID }, + { 0 } +}; + +#ifdef CONFIG_PLD_PCIE_CNSS +#ifdef FEATURE_RUNTIME_PM +struct cnss_wlan_runtime_ops runtime_pm_ops = { + .runtime_suspend = pld_pcie_runtime_suspend, + .runtime_resume = pld_pcie_runtime_resume, +}; +#endif + +struct cnss_wlan_driver pld_pcie_ops = { + .name = "pld_pcie", + .id_table = pld_pcie_id_table, + .probe = pld_pcie_probe, + .remove = pld_pcie_remove, + .reinit = pld_pcie_reinit, + .shutdown = pld_pcie_shutdown, + .crash_shutdown = pld_pcie_crash_shutdown, + .modem_status = pld_pcie_notify_handler, + .update_status = pld_pcie_uevent, +#ifdef CONFIG_PM + .suspend = pld_pcie_suspend, + .resume = pld_pcie_resume, +#endif +#ifdef FEATURE_RUNTIME_PM + .runtime_ops = &runtime_pm_ops, +#endif +}; + +/** + * pld_pcie_register_driver() - Register PCIE device callback functions + * + * Return: int + */ +int pld_pcie_register_driver(void) +{ + return cnss_wlan_register_driver(&pld_pcie_ops); +} + +/** + * pld_pcie_unregister_driver() - Unregister PCIE device callback functions + * + * Return: void + */ +void pld_pcie_unregister_driver(void) +{ + cnss_wlan_unregister_driver(&pld_pcie_ops); +} +#else +struct pci_driver pld_pcie_ops = { + .name = "pld_pcie", + .id_table = pld_pcie_id_table, + .probe = pld_pcie_probe, + .remove = pld_pcie_remove, +#ifdef CONFIG_PM + .suspend = pld_pcie_suspend, + .resume = pld_pcie_resume, +#endif +}; + +int pld_pcie_register_driver(void) +{ + return pci_register_driver(&pld_pcie_ops); +} + +void pld_pcie_unregister_driver(void) +{ + pci_unregister_driver(&pld_pcie_ops); +} +#endif + +/** + * pld_pcie_get_ce_id() - Get CE number for the provided IRQ + * @irq: IRQ number + * + * Return: CE number + */ +int pld_pcie_get_ce_id(int irq) +{ + int ce_id = irq - 100; + if (ce_id < CE_COUNT_MAX && ce_id >= 0) + return ce_id; + + return -EINVAL; +} + +#ifdef CONFIG_PLD_PCIE_CNSS +#ifdef QCA_WIFI_3_0_ADRASTEA +/** + * pld_pcie_wlan_enable() - Enable WLAN + * @config: WLAN configuration data + * @mode: WLAN mode + * @host_version: host software version + * + * This function enables WLAN FW. It passed WLAN configuration data, + * WLAN mode and host software version to FW. + * + * Return: 0 for success + * Non zero failure code for errors + */ +int pld_pcie_wlan_enable(struct pld_wlan_enable_cfg *config, + enum pld_driver_mode mode, const char *host_version) +{ + struct cnss_wlan_enable_cfg cfg; + enum cnss_driver_mode cnss_mode; + + cfg.num_ce_tgt_cfg = config->num_ce_tgt_cfg; + cfg.ce_tgt_cfg = (struct cnss_ce_tgt_pipe_cfg *) + config->ce_tgt_cfg; + cfg.num_ce_svc_pipe_cfg = config->num_ce_svc_pipe_cfg; + cfg.ce_svc_cfg = (struct cnss_ce_svc_pipe_cfg *) + config->ce_svc_cfg; + cfg.num_shadow_reg_cfg = config->num_shadow_reg_cfg; + cfg.shadow_reg_cfg = (struct cnss_shadow_reg_cfg *) + config->shadow_reg_cfg; + + switch (mode) { + case PLD_FTM: + cnss_mode = CNSS_FTM; + break; + case PLD_EPPING: + cnss_mode = CNSS_EPPING; + break; + default: + cnss_mode = CNSS_MISSION; + break; + } + return cnss_wlan_enable(&cfg, cnss_mode, host_version); +} + +/** + * pld_pcie_wlan_disable() - Disable WLAN + * @mode: WLAN mode + * + * This function disables WLAN FW. It passes WLAN mode to FW. + * + * Return: 0 for success + * Non zero failure code for errors + */ +int pld_pcie_wlan_disable(enum pld_driver_mode mode) +{ + return cnss_wlan_disable(CNSS_OFF); +} +#endif + +/** + * pld_pcie_get_fw_files_for_target() - Get FW file names + * @pfw_files: buffer for FW file names + * @target_type: target type + * @target_version: target version + * + * Return target specific FW file names to the buffer. + * + * Return: 0 for success + * Non zero failure code for errors + */ +int pld_pcie_get_fw_files_for_target(struct pld_fw_files *pfw_files, + u32 target_type, u32 target_version) +{ + int ret = 0; + struct cnss_fw_files cnss_fw_files; + + if (pfw_files == NULL) + return -ENODEV; + + memset(pfw_files, 0, sizeof(*pfw_files)); + + ret = cnss_get_fw_files_for_target(&cnss_fw_files, + target_type, target_version); + if (0 != ret) + return ret; + + strlcpy(pfw_files->image_file, cnss_fw_files.image_file, + PLD_MAX_FILE_NAME); + strlcpy(pfw_files->board_data, cnss_fw_files.board_data, + PLD_MAX_FILE_NAME); + strlcpy(pfw_files->otp_data, cnss_fw_files.otp_data, + PLD_MAX_FILE_NAME); + strlcpy(pfw_files->utf_file, cnss_fw_files.utf_file, + PLD_MAX_FILE_NAME); + strlcpy(pfw_files->utf_board_data, cnss_fw_files.utf_board_data, + PLD_MAX_FILE_NAME); + strlcpy(pfw_files->epping_file, cnss_fw_files.epping_file, + PLD_MAX_FILE_NAME); + strlcpy(pfw_files->evicted_data, cnss_fw_files.evicted_data, + PLD_MAX_FILE_NAME); + + return 0; +} + +/** + * pld_pcie_get_platform_cap() - Get platform capabilities + * @cap: buffer to the capabilities + * + * Return capabilities to the buffer. + * + * Return: 0 for success + * Non zero failure code for errors + */ +int pld_pcie_get_platform_cap(struct pld_platform_cap *cap) +{ + int ret = 0; + struct cnss_platform_cap cnss_cap; + + if (cap == NULL) + return -ENODEV; + + ret = cnss_get_platform_cap(&cnss_cap); + if (0 != ret) + return ret; + + memcpy(cap, &cnss_cap, sizeof(*cap)); + return 0; +} + +/** + * pld_pcie_set_driver_status() - Set driver status + * @status: driver status + * + * Return: void + */ +void pld_pcie_set_driver_status(enum pld_driver_status status) +{ + enum cnss_driver_status cnss_status; + + switch (status) { + case PLD_UNINITIALIZED: + cnss_status = CNSS_UNINITIALIZED; + break; + case PLD_INITIALIZED: + cnss_status = CNSS_INITIALIZED; + break; + default: + cnss_status = CNSS_LOAD_UNLOAD; + break; + } + cnss_set_driver_status(cnss_status); +} +#endif +#endif diff --git a/drivers/staging/qcacld-3.0/core/pld/src/pld_pcie.h b/drivers/staging/qcacld-3.0/core/pld/src/pld_pcie.h new file mode 100644 index 0000000000000000000000000000000000000000..7f430fc54da548c2e4a124c3fb758beb52baebf9 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/pld/src/pld_pcie.h @@ -0,0 +1,335 @@ +/* + * Copyright (c) 2016-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef __PLD_PCIE_H__ +#define __PLD_PCIE_H__ + +#ifdef CONFIG_PLD_PCIE_CNSS +#include +#endif +#include "pld_internal.h" + +#ifndef CONFIG_PCI +static inline int pld_pcie_register_driver(void) +{ + return 0; +} + +static inline void pld_pcie_unregister_driver(void) +{ + return; +} + +static inline int pld_pcie_get_ce_id(int irq) +{ + return 0; +} +#else +int pld_pcie_register_driver(void); +void pld_pcie_unregister_driver(void); +int pld_pcie_get_ce_id(int irq); +#endif + +#if (!defined(CONFIG_PLD_PCIE_CNSS)) || (!defined(QCA_WIFI_3_0_ADRASTEA)) +static inline int pld_pcie_wlan_enable(struct pld_wlan_enable_cfg *config, + enum pld_driver_mode mode, const char *host_version) +{ + return 0; +} +static inline int pld_pcie_wlan_disable(enum pld_driver_mode mode) +{ + return 0; +} +static inline int pld_pcie_set_fw_log_mode(u8 fw_log_mode) +{ + return 0; +} +static inline void pld_pcie_intr_notify_q6(void) +{ + return; +} +#else +int pld_pcie_wlan_enable(struct pld_wlan_enable_cfg *config, + enum pld_driver_mode mode, const char *host_version); +int pld_pcie_wlan_disable(enum pld_driver_mode mode); +static inline int pld_pcie_set_fw_log_mode(u8 fw_log_mode) +{ + return cnss_set_fw_debug_mode(fw_log_mode); +} +static inline void pld_pcie_intr_notify_q6(void) +{ + cnss_intr_notify_q6(); +} +#endif + +#if (!defined(CONFIG_PLD_PCIE_CNSS)) || (!defined(CONFIG_CNSS_SECURE_FW)) +static inline int pld_pcie_get_sha_hash(const u8 *data, + u32 data_len, u8 *hash_idx, u8 *out) +{ + return 0; +} +static inline void *pld_pcie_get_fw_ptr(void) +{ + return NULL; +} +#else +static inline int pld_pcie_get_sha_hash(const u8 *data, + u32 data_len, u8 *hash_idx, u8 *out) +{ + return cnss_get_sha_hash(data, data_len, hash_idx, out); +} +static inline void *pld_pcie_get_fw_ptr(void) +{ + return cnss_get_fw_ptr(); +} +#endif + +#if (!defined(CONFIG_PLD_PCIE_CNSS)) || (!defined(CONFIG_PCI_MSM)) +static inline int pld_pcie_wlan_pm_control(bool vote) +{ + return 0; +} +#else +static inline int pld_pcie_wlan_pm_control(bool vote) +{ + return cnss_wlan_pm_control(vote); +} +#endif + +#ifndef CONFIG_PLD_PCIE_CNSS +static inline int +pld_pcie_get_fw_files_for_target(struct pld_fw_files *pfw_files, + u32 target_type, u32 target_version) +{ + pld_get_default_fw_files(pfw_files); + return 0; +} +static inline void pld_pcie_link_down(void) +{ + return; +} +static inline int pld_pcie_shadow_control(bool enable) +{ + return 0; +} +static inline int +pld_pcie_set_wlan_unsafe_channel(u16 *unsafe_ch_list, u16 ch_count) +{ + return 0; +} +static inline int +pld_pcie_get_wlan_unsafe_channel(u16 *unsafe_ch_list, + u16 *ch_count, u16 buf_len) +{ + return 0; +} +static inline int pld_pcie_wlan_set_dfs_nol(void *info, u16 info_len) +{ + return 0; +} +static inline int pld_pcie_wlan_get_dfs_nol(void *info, u16 info_len) +{ + return 0; +} +static inline void pld_pcie_schedule_recovery_work(void) +{ + return; +} +static inline void *pld_pcie_get_virt_ramdump_mem(unsigned long *size) +{ + return NULL; +} +static inline void pld_pcie_device_crashed(void) +{ + return; +} +static inline void pld_pcie_device_self_recovery(void) +{ + return; +} +static inline void pld_pcie_request_pm_qos(u32 qos_val) +{ + return; +} +static inline void pld_pcie_remove_pm_qos(void) +{ + return; +} +static inline int pld_pcie_request_bus_bandwidth(int bandwidth) +{ + return 0; +} +static inline int pld_pcie_get_platform_cap(struct pld_platform_cap *cap) +{ + return 0; +} +static inline void pld_pcie_set_driver_status(enum pld_driver_status status) +{ + return; +} +static inline int pld_pcie_auto_suspend(void) +{ + return 0; +} +static inline int pld_pcie_auto_resume(void) +{ + return 0; +} +static inline void pld_pcie_lock_pm_sem(void) +{ + return; +} +static inline void pld_pcie_release_pm_sem(void) +{ + return; +} +static inline int pld_pcie_power_on(struct device *dev) +{ + return 0; +} +static inline int pld_pcie_power_off(struct device *dev) +{ + return 0; +} + +static inline uint8_t *pld_pcie_get_wlan_mac_address(struct device *dev, + uint32_t *num) +{ + *num = 0; + return NULL; +} + +static inline void pld_pcie_increment_driver_load_cnt(void) +{ +} + +static inline int pld_pcie_get_driver_load_cnt(void) +{ + return 0; +} +#else +int pld_pcie_get_fw_files_for_target(struct pld_fw_files *pfw_files, + u32 target_type, u32 target_version); +int pld_pcie_get_platform_cap(struct pld_platform_cap *cap); +void pld_pcie_set_driver_status(enum pld_driver_status status); + +static inline void pld_pcie_link_down(void) +{ + cnss_wlan_pci_link_down(); +} +static inline int pld_pcie_shadow_control(bool enable) +{ + return 0; +} +static inline int pld_pcie_set_wlan_unsafe_channel(u16 *unsafe_ch_list, + u16 ch_count) +{ + return cnss_set_wlan_unsafe_channel(unsafe_ch_list, ch_count); +} +static inline int pld_pcie_get_wlan_unsafe_channel(u16 *unsafe_ch_list, + u16 *ch_count, u16 buf_len) +{ + return cnss_get_wlan_unsafe_channel(unsafe_ch_list, ch_count, buf_len); +} +static inline int pld_pcie_wlan_set_dfs_nol(void *info, u16 info_len) +{ + return cnss_wlan_set_dfs_nol(info, info_len); +} +static inline int pld_pcie_wlan_get_dfs_nol(void *info, u16 info_len) +{ + return cnss_wlan_get_dfs_nol(info, info_len); +} +static inline void pld_pcie_schedule_recovery_work(void) +{ + cnss_schedule_recovery_work(); +} +static inline void *pld_pcie_get_virt_ramdump_mem(unsigned long *size) +{ + return cnss_get_virt_ramdump_mem(size); +} +static inline void pld_pcie_device_crashed(void) +{ + cnss_device_crashed(); +} +static inline void pld_pcie_device_self_recovery(void) +{ + cnss_device_self_recovery(); +} +static inline void pld_pcie_request_pm_qos(u32 qos_val) +{ + cnss_request_pm_qos(qos_val); +} +static inline void pld_pcie_remove_pm_qos(void) +{ + cnss_remove_pm_qos(); +} +static inline int pld_pcie_request_bus_bandwidth(int bandwidth) +{ + return cnss_request_bus_bandwidth(bandwidth); +} +static inline int pld_pcie_auto_suspend(void) +{ + return cnss_auto_suspend(); +} +static inline int pld_pcie_auto_resume(void) +{ + return cnss_auto_resume(); +} +static inline void pld_pcie_lock_pm_sem(void) +{ + cnss_lock_pm_sem(); +} +static inline void pld_pcie_release_pm_sem(void) +{ + cnss_release_pm_sem(); +} +static inline int pld_pcie_power_on(struct device *dev) +{ + return cnss_power_up(dev); +} +static inline int pld_pcie_power_off(struct device *dev) +{ + return cnss_power_down(dev); +} + +static inline uint8_t *pld_pcie_get_wlan_mac_address(struct device *dev, + uint32_t *num) +{ + return cnss_common_get_wlan_mac_address(dev, num); +} + +static inline void pld_pcie_increment_driver_load_cnt(void) +{ +} + +static inline int pld_pcie_get_driver_load_cnt(void) +{ + return 0; +} + +#endif +#endif diff --git a/drivers/staging/qcacld-3.0/core/pld/src/pld_sdio.c b/drivers/staging/qcacld-3.0/core/pld/src/pld_sdio.c new file mode 100644 index 0000000000000000000000000000000000000000..14b17f989b262ba97620d4adac12fff862261fe2 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/pld/src/pld_sdio.c @@ -0,0 +1,384 @@ +/* + * Copyright (c) 2016 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 +#include +#include +#include +#include + +#ifdef CONFIG_PLD_SDIO_CNSS +#include +#endif + +#include "pld_common.h" +#include "pld_internal.h" + +#ifdef CONFIG_SDIO +/* SDIO manufacturer ID and Codes */ +#define MANUFACTURER_ID_AR6320_BASE 0x500 +#define MANUFACTURER_ID_QCA9377_BASE 0x700 +#define MANUFACTURER_CODE 0x271 + +/** + * pld_sdio_probe() - Probe function for SDIO platform driver + * sdio_func: pointer to sdio device function + * @id: SDIO device ID table + * + * The probe function will be called when SDIO device provided + * in the ID table is detected. + * + * Return: int + */ +static int pld_sdio_probe(struct sdio_func *sdio_func, + const struct sdio_device_id *id) +{ + struct pld_context *pld_context; + struct device *dev = &sdio_func->dev; + int ret = 0; + + pld_context = pld_get_global_context(); + if (!pld_context) { + ret = -ENODEV; + goto out; + } + + ret = pld_add_dev(pld_context, dev, PLD_BUS_TYPE_SDIO); + if (ret) + goto out; + + return pld_context->ops->probe(dev, PLD_BUS_TYPE_SDIO, + sdio_func, (void *)id); + +out: + return ret; +} + + +/** + * pld_sdio_remove() - Remove function for SDIO device + * @sdio_func: pointer to sdio device function + * + * The remove function will be called when SDIO device is disconnected + * + * Return: void + */ +static void pld_sdio_remove(struct sdio_func *sdio_func) +{ + struct pld_context *pld_context; + struct device *dev = &sdio_func->dev; + + pld_context = pld_get_global_context(); + + if (!pld_context) + return; + + pld_context->ops->remove(dev, PLD_BUS_TYPE_SDIO); + pld_del_dev(pld_context, dev); +} + +#ifdef CONFIG_PLD_SDIO_CNSS +/** + * pld_sdio_reinit() - SSR re-initialize function for SDIO device + * @sdio_func: pointer to sdio device function + * @id: SDIO device ID + * + * During subsystem restart(SSR), this function will be called to + * re-initialize SDIO device. + * + * Return: int + */ +static int pld_sdio_reinit(struct sdio_func *sdio_func, + const struct sdio_device_id *id) +{ + struct pld_context *pld_context; + struct device *dev = &sdio_func->dev; + + pld_context = pld_get_global_context(); + if (pld_context->ops->reinit) + return pld_context->ops->reinit(dev, PLD_BUS_TYPE_SDIO, + sdio_func, (void *)id); + + return -ENODEV; +} + +/** + * pld_sdio_shutdown() - SSR shutdown function for SDIO device + * @sdio_func: pointer to sdio device function + * + * During SSR, this function will be called to shutdown SDIO device. + * + * Return: void + */ +static void pld_sdio_shutdown(struct sdio_func *sdio_func) +{ + struct pld_context *pld_context; + struct device *dev = &sdio_func->dev; + + pld_context = pld_get_global_context(); + if (pld_context->ops->shutdown) + pld_context->ops->shutdown(dev, PLD_BUS_TYPE_SDIO); +} + +/** + * pld_sdio_crash_shutdown() - Crash shutdown function for SDIO device + * @sdio_func: pointer to sdio device function + * + * This function will be called when a crash is detected, it will shutdown + * the SDIO device. + * + * Return: void + */ +static void pld_sdio_crash_shutdown(struct sdio_func *sdio_func) +{ + struct pld_context *pld_context; + struct device *dev = &sdio_func->dev; + + pld_context = pld_get_global_context(); + if (pld_context->ops->crash_shutdown) + pld_context->ops->crash_shutdown(dev, PLD_BUS_TYPE_SDIO); +} + +#endif + +#ifdef CONFIG_PM +/** + * pld_sdio_suspend() - Suspend callback function for power management + * @dev: SDIO device + * + * This function is to suspend the SDIO device when power management is + * enabled. + * + * Return: void + */ +static int pld_sdio_suspend(struct device *dev) +{ + struct pld_context *pld_context; + pm_message_t state = { .event = PM_EVENT_SUSPEND }; + + pld_context = pld_get_global_context(); + return pld_context->ops->suspend(dev, + PLD_BUS_TYPE_SDIO, state); +} + +/** + * pld_sdio_resume() - Resume callback function for power management + * @dev: SDIO device + * + * This function is to resume the SDIO device when power management is + * enabled. + * + * Return: void + */ +static int pld_sdio_resume(struct device *dev) +{ + struct pld_context *pld_context; + + pld_context = pld_get_global_context(); + return pld_context->ops->resume(dev, PLD_BUS_TYPE_SDIO); +} +#endif + +static struct sdio_device_id pld_sdio_id_table[] = { + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0x0))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0x1))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0x2))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0x3))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0x4))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0x5))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0x6))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0x7))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0x8))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0x9))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0xA))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0xB))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0xC))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0xD))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0xE))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0xF))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0x0))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0x1))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0x2))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0x3))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0x4))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0x5))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0x6))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0x7))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0x8))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0x9))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0xA))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0xB))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0xC))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0xD))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0xE))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0xF))}, + {}, +}; + +#ifdef CONFIG_PLD_SDIO_CNSS +struct cnss_sdio_wlan_driver pld_sdio_ops = { + .name = "pld_sdio", + .id_table = pld_sdio_id_table, + .probe = pld_sdio_probe, + .remove = pld_sdio_remove, + .reinit = pld_sdio_reinit, + .shutdown = pld_sdio_shutdown, + .crash_shutdown = pld_sdio_crash_shutdown, +#ifdef CONFIG_PM + .suspend = pld_sdio_suspend, + .resume = pld_sdio_resume, +#endif +}; + +/** + * pld_sdio_register_driver() - Register SDIO device callback functions + * + * Return: int + */ +int pld_sdio_register_driver(void) +{ + return cnss_sdio_wlan_register_driver(&pld_sdio_ops); +} + +/** + * pld_sdio_unregister_driver() - Unregister SDIO device callback functions + * + * Return: void + */ +void pld_sdio_unregister_driver(void) +{ + cnss_sdio_wlan_unregister_driver(&pld_sdio_ops); +} +#else +struct sdio_driver pld_sdio_ops = { + .name = "pld_sdio", + .id_table = pld_sdio_id_table, + .probe = pld_sdio_probe, + .remove = pld_sdio_remove, +#ifdef CONFIG_PM + .suspend = pld_sdio_suspend, + .resume = pld_sdio_resume, +#endif +}; + +int pld_sdio_register_driver(void) +{ + return sdio_register_driver(&pld_sdio_ops); +} + +void pld_sdio_unregister_driver(void) +{ + sdio_unregister_driver(&pld_sdio_ops); +} +#endif + +#ifdef CONFIG_PLD_SDIO_CNSS +/** + * pld_sdio_get_fw_files_for_target() - Get FW file names + * @pfw_files: buffer for FW file names + * @target_type: target type + * @target_version: target version + * + * Return target specific FW file names to the buffer. + * + * Return: 0 for success + * Non zero failure code for errors + */ +int pld_sdio_get_fw_files_for_target(struct pld_fw_files *pfw_files, + u32 target_type, u32 target_version) +{ + int ret = 0; + struct cnss_fw_files cnss_fw_files; + + if (pfw_files == NULL) + return -ENODEV; + + memset(pfw_files, 0, sizeof(*pfw_files)); + + ret = cnss_get_fw_files_for_target(&cnss_fw_files, + target_type, target_version); + if (0 != ret) + return ret; + + strlcpy(pfw_files->image_file, cnss_fw_files.image_file, + PLD_MAX_FILE_NAME); + strlcpy(pfw_files->board_data, cnss_fw_files.board_data, + PLD_MAX_FILE_NAME); + strlcpy(pfw_files->otp_data, cnss_fw_files.otp_data, + PLD_MAX_FILE_NAME); + strlcpy(pfw_files->utf_file, cnss_fw_files.utf_file, + PLD_MAX_FILE_NAME); + strlcpy(pfw_files->utf_board_data, cnss_fw_files.utf_board_data, + PLD_MAX_FILE_NAME); + strlcpy(pfw_files->epping_file, cnss_fw_files.epping_file, + PLD_MAX_FILE_NAME); + strlcpy(pfw_files->evicted_data, cnss_fw_files.evicted_data, + PLD_MAX_FILE_NAME); + + return ret; +} +#else +#ifdef CONFIG_TUFELLO_DUAL_FW_SUPPORT +static inline void get_qca9377_fw_files(struct pld_fw_files *pfw_files, + u32 size) +{ + memcpy(pfw_files, &fw_files_default, sizeof(*pfw_files)); +} +#else +static inline void get_qca9377_fw_files(struct pld_fw_files *pfw_files, + u32 size) +{ + memcpy(pfw_files, &fw_files_qca6174_fw_3_0, sizeof(*pfw_files)); +} +#endif + +int pld_sdio_get_fw_files_for_target(struct pld_fw_files *pfw_files, + u32 target_type, u32 target_version) +{ + if (!pfw_files) + return -ENODEV; + + switch (target_version) { + case PLD_AR6320_REV1_VERSION: + case PLD_AR6320_REV1_1_VERSION: + memcpy(pfw_files, &fw_files_qca6174_fw_1_1, sizeof(*pfw_files)); + break; + case PLD_AR6320_REV1_3_VERSION: + memcpy(pfw_files, &fw_files_qca6174_fw_1_3, sizeof(*pfw_files)); + break; + case PLD_AR6320_REV2_1_VERSION: + memcpy(pfw_files, &fw_files_qca6174_fw_2_0, sizeof(*pfw_files)); + break; + case PLD_AR6320_REV3_VERSION: + case PLD_AR6320_REV3_2_VERSION: + memcpy(pfw_files, &fw_files_qca6174_fw_3_0, sizeof(*pfw_files)); + break; + case PLD_QCA9377_REV1_1_VERSION: + get_qca9377_fw_files(pfw_files, sizeof(*pfw_files)); + break; + default: + memcpy(pfw_files, &fw_files_default, sizeof(*pfw_files)); + pr_err("%s version mismatch 0x%X ", + __func__, target_version); + break; + } + + return 0; +} +#endif +#endif diff --git a/drivers/staging/qcacld-3.0/core/pld/src/pld_sdio.h b/drivers/staging/qcacld-3.0/core/pld/src/pld_sdio.h new file mode 100644 index 0000000000000000000000000000000000000000..2ac4ceafa11ffafb7794987d710df1a88304869a --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/pld/src/pld_sdio.h @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2016 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 __PLD_SDIO_H__ +#define __PLD_SDIO_H__ + +#include "pld_common.h" + +#ifndef CONFIG_CNSS +#define PLD_AR6004_VERSION_REV1_3 0x31c8088a +#define PLD_AR9888_REV2_VERSION 0x4100016c +#define PLD_AR6320_REV1_VERSION 0x5000000 +#define PLD_AR6320_REV1_1_VERSION 0x5000001 +#define PLD_AR6320_REV1_3_VERSION 0x5000003 +#define PLD_AR6320_REV2_1_VERSION 0x5010000 +#define PLD_AR6320_REV3_VERSION 0x5020000 +#define PLD_AR6320_REV3_2_VERSION 0x5030000 +#define PLD_AR6320_DEV_VERSION 0x1000000 +#define PLD_QCA9377_REV1_1_VERSION 0x5020001 + +#ifdef MULTI_IF_NAME +#define PREFIX MULTI_IF_NAME +#else +#define PREFIX "" +#endif + +struct pld_fw_files fw_files_qca6174_fw_1_1 = { + PREFIX "qwlan11.bin", PREFIX "bdwlan11.bin", PREFIX "otp11.bin", + PREFIX "utf11.bin", PREFIX "utfbd11.bin", PREFIX "qsetup11.bin", + PREFIX "epping11.bin", ""}; +struct pld_fw_files fw_files_qca6174_fw_2_0 = { + PREFIX "qwlan20.bin", PREFIX "bdwlan20.bin", PREFIX "otp20.bin", + PREFIX "utf20.bin", PREFIX "utfbd20.bin", PREFIX "qsetup20.bin", + PREFIX "epping20.bin", ""}; +struct pld_fw_files fw_files_qca6174_fw_1_3 = { + PREFIX "qwlan13.bin", PREFIX "bdwlan13.bin", PREFIX "otp13.bin", + PREFIX "utf13.bin", PREFIX "utfbd13.bin", PREFIX "qsetup13.bin", + PREFIX "epping13.bin", ""}; +struct pld_fw_files fw_files_qca6174_fw_3_0 = { + PREFIX "qwlan30.bin", PREFIX "bdwlan30.bin", PREFIX "otp30.bin", + PREFIX "utf30.bin", PREFIX "utfbd30.bin", PREFIX "qsetup30.bin", + PREFIX "epping30.bin", PREFIX "qwlan30i.bin"}; +struct pld_fw_files fw_files_default = { + PREFIX "qwlan.bin", PREFIX "bdwlan.bin", PREFIX "otp.bin", + PREFIX "utf.bin", PREFIX "utfbd.bin", PREFIX "qsetup.bin", + PREFIX "epping.bin", ""}; +#endif + +#ifndef CONFIG_SDIO +static inline int pld_sdio_register_driver(void) +{ + return 0; +} + +static inline void pld_sdio_unregister_driver(void) +{ +} + +static inline +int pld_sdio_get_fw_files_for_target(struct pld_fw_files *pfw_files, + u32 target_type, u32 target_version) +{ + return 0; +} +static inline uint8_t *pld_sdio_get_wlan_mac_address(struct device *dev, + uint32_t *num) +{ + *num = 0; + return NULL; +} +#else +int pld_sdio_register_driver(void); +void pld_sdio_unregister_driver(void); +int pld_sdio_get_fw_files_for_target(struct pld_fw_files *pfw_files, + u32 target_type, u32 target_version); +static inline uint8_t *pld_sdio_get_wlan_mac_address(struct device *dev, + uint32_t *num) +{ + return cnss_common_get_wlan_mac_address(dev, num); +} +#endif + +#endif diff --git a/drivers/staging/qcacld-3.0/core/pld/src/pld_snoc.c b/drivers/staging/qcacld-3.0/core/pld/src/pld_snoc.c new file mode 100644 index 0000000000000000000000000000000000000000..3b29a01d7f9b402e786e6f670bdeccbf5606bbf4 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/pld/src/pld_snoc.c @@ -0,0 +1,388 @@ +/* + * Copyright (c) 2016-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#include +#include +#include +#include + +#ifdef CONFIG_PLD_SNOC_ICNSS +#include +#endif + +#include "pld_internal.h" +#include "pld_snoc.h" + +#ifdef CONFIG_PLD_SNOC_ICNSS +/** + * pld_snoc_probe() - Probe function for platform driver + * @dev: device + * + * The probe function will be called when platform device + * is detected. + * + * Return: int + */ +static int pld_snoc_probe(struct device *dev) +{ + struct pld_context *pld_context; + int ret = 0; + + pld_context = pld_get_global_context(); + if (!pld_context) { + ret = -ENODEV; + goto out; + } + + ret = pld_add_dev(pld_context, dev, PLD_BUS_TYPE_SNOC); + if (ret) + goto out; + + return pld_context->ops->probe(dev, PLD_BUS_TYPE_SNOC, + NULL, NULL); + +out: + return ret; +} + +/** + * pld_snoc_remove() - Remove function for platform device + * @dev: device + * + * The remove function will be called when platform device + * is disconnected + * + * Return: void + */ +static void pld_snoc_remove(struct device *dev) +{ + struct pld_context *pld_context; + + pld_context = pld_get_global_context(); + + if (!pld_context) + return; + + pld_context->ops->remove(dev, PLD_BUS_TYPE_SNOC); + + pld_del_dev(pld_context, dev); +} + +/** + * pld_snoc_reinit() - SSR re-initialize function for platform device + * @dev: device + * + * During subsystem restart(SSR), this function will be called to + * re-initialize platform device. + * + * Return: int + */ +static int pld_snoc_reinit(struct device *dev) +{ + struct pld_context *pld_context; + + pld_context = pld_get_global_context(); + if (pld_context->ops->reinit) + return pld_context->ops->reinit(dev, PLD_BUS_TYPE_SNOC, + NULL, NULL); + + return -ENODEV; +} + +/** + * pld_snoc_shutdown() - SSR shutdown function for platform device + * @dev: device + * + * During SSR, this function will be called to shutdown platform device. + * + * Return: void + */ +static void pld_snoc_shutdown(struct device *dev) +{ + struct pld_context *pld_context; + + pld_context = pld_get_global_context(); + if (pld_context->ops->shutdown) + pld_context->ops->shutdown(dev, PLD_BUS_TYPE_SNOC); +} + +/** + * pld_snoc_crash_shutdown() - Crash shutdown function for platform device + * @dev: device + * + * This function will be called when a crash is detected, it will shutdown + * platform device. + * + * Return: void + */ +static void pld_snoc_crash_shutdown(void *dev) +{ + struct pld_context *pld_context; + + pld_context = pld_get_global_context(); + if (pld_context->ops->crash_shutdown) + pld_context->ops->crash_shutdown(dev, PLD_BUS_TYPE_SNOC); +} + +/** + * pld_snoc_pm_suspend() - PM suspend callback function for power management + * @dev: device + * + * This function is to suspend the platform device when power management + * is enabled. + * + * Return: void + */ +static int pld_snoc_pm_suspend(struct device *dev) +{ + struct pld_context *pld_context; + pm_message_t state; + + state.event = PM_EVENT_SUSPEND; + pld_context = pld_get_global_context(); + return pld_context->ops->suspend(dev, PLD_BUS_TYPE_SNOC, state); +} + +/** + * pld_snoc_pm_resume() - PM resume callback function for power management + * @pdev: device + * + * This function is to resume the platform device when power management + * is enabled. + * + * Return: void + */ +static int pld_snoc_pm_resume(struct device *dev) +{ + struct pld_context *pld_context; + + pld_context = pld_get_global_context(); + return pld_context->ops->resume(dev, PLD_BUS_TYPE_SNOC); +} + +/** + * pld_snoc_suspend_noirq() - Complete the actions started by suspend() + * @dev: device + * + * Complete the actions started by suspend(). Carry out any + * additional operations required for suspending the device that might be + * racing with its driver's interrupt handler, which is guaranteed not to + * run while suspend_noirq() is being executed. + * + * Return: 0 for success + * Non zero failure code for errors + */ +static int pld_snoc_suspend_noirq(struct device *dev) +{ + struct pld_context *pld_context; + + pld_context = pld_get_global_context(); + if (!pld_context) + return -EINVAL; + + if (pld_context->ops->suspend_noirq) + return pld_context->ops->suspend_noirq(dev, PLD_BUS_TYPE_SNOC); + return 0; +} + +/** + * pld_snoc_resume_noirq() - Prepare for the execution of resume() + * @pdev: device + * + * Prepare for the execution of resume() by carrying out any + * operations required for resuming the device that might be racing with + * its driver's interrupt handler, which is guaranteed not to run while + * resume_noirq() is being executed. + * + * Return: 0 for success + * Non zero failure code for errors + */ +static int pld_snoc_resume_noirq(struct device *dev) +{ + struct pld_context *pld_context; + + pld_context = pld_get_global_context(); + if (!pld_context) + return -EINVAL; + + if (pld_context->ops->resume_noirq) + return pld_context->ops->resume_noirq(dev, PLD_BUS_TYPE_SNOC); + + return 0; +} + +static int pld_snoc_uevent(struct device *dev, + struct icnss_uevent_data *uevent) +{ + struct pld_context *pld_context; + struct icnss_uevent_fw_down_data *uevent_data = NULL; + struct pld_uevent_data data; + + pld_context = pld_get_global_context(); + if (!pld_context) + return -EINVAL; + + if (!pld_context->ops->uevent) + return 0; + + if (!uevent) + return -EINVAL; + + switch (uevent->uevent) { + case ICNSS_UEVENT_FW_CRASHED: + data.uevent = PLD_RECOVERY; + break; + case ICNSS_UEVENT_FW_DOWN: + if (uevent->data == NULL) + return -EINVAL; + uevent_data = (struct icnss_uevent_fw_down_data *)uevent->data; + data.uevent = PLD_FW_DOWN; + data.fw_down.crashed = uevent_data->crashed; + break; + default: + return 0; + } + + pld_context->ops->uevent(dev, &data); + return 0; +} + +struct icnss_driver_ops pld_snoc_ops = { + .name = "pld_snoc", + .probe = pld_snoc_probe, + .remove = pld_snoc_remove, + .shutdown = pld_snoc_shutdown, + .reinit = pld_snoc_reinit, + .crash_shutdown = pld_snoc_crash_shutdown, + .pm_suspend = pld_snoc_pm_suspend, + .pm_resume = pld_snoc_pm_resume, + .suspend_noirq = pld_snoc_suspend_noirq, + .resume_noirq = pld_snoc_resume_noirq, + .uevent = pld_snoc_uevent, +}; + +/** + * pld_snoc_register_driver() - Register platform device callback functions + * + * Return: int + */ +int pld_snoc_register_driver(void) +{ + return icnss_register_driver(&pld_snoc_ops); +} + +/** + * pld_snoc_unregister_driver() - Unregister platform device callback functions + * + * Return: void + */ +void pld_snoc_unregister_driver(void) +{ + icnss_unregister_driver(&pld_snoc_ops); +} + +/** + * pld_snoc_wlan_enable() - Enable WLAN + * @config: WLAN configuration data + * @mode: WLAN mode + * @host_version: host software version + * + * This function enables WLAN FW. It passed WLAN configuration data, + * WLAN mode and host software version to FW. + * + * Return: 0 for success + * Non zero failure code for errors + */ +int pld_snoc_wlan_enable(struct pld_wlan_enable_cfg *config, + enum pld_driver_mode mode, const char *host_version) +{ + struct icnss_wlan_enable_cfg cfg; + enum icnss_driver_mode icnss_mode; + + cfg.num_ce_tgt_cfg = config->num_ce_tgt_cfg; + cfg.ce_tgt_cfg = (struct ce_tgt_pipe_cfg *) + config->ce_tgt_cfg; + cfg.num_ce_svc_pipe_cfg = config->num_ce_svc_pipe_cfg; + cfg.ce_svc_cfg = (struct ce_svc_pipe_cfg *) + config->ce_svc_cfg; + cfg.num_shadow_reg_cfg = config->num_shadow_reg_cfg; + cfg.shadow_reg_cfg = (struct icnss_shadow_reg_cfg *) + config->shadow_reg_cfg; + + switch (mode) { + case PLD_FTM: + icnss_mode = ICNSS_FTM; + break; + case PLD_EPPING: + icnss_mode = ICNSS_EPPING; + break; + default: + icnss_mode = ICNSS_MISSION; + break; + } + return icnss_wlan_enable(&cfg, icnss_mode, host_version); +} + +/** + * pld_snoc_wlan_disable() - Disable WLAN + * @mode: WLAN mode + * + * This function disables WLAN FW. It passes WLAN mode to FW. + * + * Return: 0 for success + * Non zero failure code for errors + */ +int pld_snoc_wlan_disable(enum pld_driver_mode mode) +{ + return icnss_wlan_disable(ICNSS_OFF); +} + +/** + * pld_snoc_get_soc_info() - Get SOC information + * @info: buffer to SOC information + * + * Return SOC info to the buffer. + * + * Return: 0 for success + * Non zero failure code for errors + */ +int pld_snoc_get_soc_info(struct pld_soc_info *info) +{ + int ret = 0; + struct icnss_soc_info icnss_info; + + if (info == NULL) + return -ENODEV; + + ret = icnss_get_soc_info(&icnss_info); + if (0 != ret) + return ret; + + memcpy(info, &icnss_info, sizeof(*info)); + return 0; +} +#endif diff --git a/drivers/staging/qcacld-3.0/core/pld/src/pld_snoc.h b/drivers/staging/qcacld-3.0/core/pld/src/pld_snoc.h new file mode 100644 index 0000000000000000000000000000000000000000..bd0e89f0699f8b0c5d7899fabaa5107dbaa6caed --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/pld/src/pld_snoc.h @@ -0,0 +1,283 @@ +/* + * Copyright (c) 2016-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef __PLD_SNOC_H__ +#define __PLD_SNOC_H__ + +#ifdef CONFIG_PLD_SNOC_ICNSS +#include +#endif +#include "pld_internal.h" + +#ifndef CONFIG_PLD_SNOC_ICNSS +static inline int pld_snoc_register_driver(void) +{ + return 0; +} + +static inline void pld_snoc_unregister_driver(void) +{ + return; +} +static inline int pld_snoc_wlan_enable(struct pld_wlan_enable_cfg *config, + enum pld_driver_mode mode, const char *host_version) +{ + return 0; +} +static inline int pld_snoc_wlan_disable(enum pld_driver_mode mode) +{ + return 0; +} +static inline int pld_snoc_ce_request_irq(unsigned int ce_id, + irqreturn_t (*handler)(int, void *), + unsigned long flags, const char *name, void *ctx) +{ + return 0; +} +static inline int pld_snoc_ce_free_irq(unsigned int ce_id, void *ctx) +{ + return 0; +} +static inline void pld_snoc_enable_irq(unsigned int ce_id) +{ + return; +} +static inline void pld_snoc_disable_irq(unsigned int ce_id) +{ + return; +} +static inline int pld_snoc_get_soc_info(struct pld_soc_info *info) +{ + return 0; +} +static inline int pld_snoc_get_ce_id(int irq) +{ + return 0; +} +static inline int pld_snoc_power_on(struct device *dev) +{ + return 0; +} +static inline int pld_snoc_power_off(struct device *dev) +{ + return 0; +} +static inline int pld_snoc_get_irq(int ce_id) +{ + return 0; +} +static inline int pld_snoc_set_wlan_unsafe_channel(u16 *unsafe_ch_list, + u16 ch_count) +{ + return 0; +} +static inline int pld_snoc_get_wlan_unsafe_channel(u16 *unsafe_ch_list, + u16 *ch_count, + u16 buf_len) +{ + return 0; +} +static inline int pld_snoc_wlan_set_dfs_nol(const void *info, u16 info_len) +{ + return 0; +} +static inline int pld_snoc_wlan_get_dfs_nol(void *info, u16 info_len) +{ + return 0; +} +static inline int pld_snoc_athdiag_read(struct device *dev, uint32_t offset, + uint32_t memtype, uint32_t datalen, + uint8_t *output) +{ + return 0; +} +static inline int pld_snoc_athdiag_write(struct device *dev, uint32_t offset, + uint32_t memtype, uint32_t datalen, + uint8_t *input) +{ + return 0; +} +static inline void *pld_snoc_smmu_get_mapping(struct device *dev) +{ + return NULL; +} +static inline int pld_snoc_smmu_map(struct device *dev, phys_addr_t paddr, + uint32_t *iova_addr, size_t size) +{ + return 0; +} +static inline +unsigned int pld_snoc_socinfo_get_serial_number(struct device *dev) +{ + return 0; +} +static inline int pld_snoc_is_qmi_disable(void) +{ + return 0; +} +static inline uint8_t *pld_snoc_get_wlan_mac_address(struct device *dev, + uint32_t *num) +{ + *num = 0; + return NULL; +} +static inline int pld_snoc_force_assert_target(struct device *dev) +{ + return 0; +} +static inline int pld_snoc_set_fw_log_mode(u8 fw_log_mode) +{ + return 0; +} + +static inline void pld_snoc_increment_driver_load_cnt(void) +{ +} + +static inline int pld_snoc_get_driver_load_cnt(void) +{ + return 0; +} +#else +int pld_snoc_register_driver(void); +void pld_snoc_unregister_driver(void); +int pld_snoc_wlan_enable(struct pld_wlan_enable_cfg *config, + enum pld_driver_mode mode, const char *host_version); +int pld_snoc_wlan_disable(enum pld_driver_mode mode); +int pld_snoc_get_soc_info(struct pld_soc_info *info); +static inline int pld_snoc_ce_request_irq(unsigned int ce_id, + irqreturn_t (*handler)(int, void *), + unsigned long flags, + const char *name, void *ctx) +{ + return icnss_ce_request_irq(ce_id, handler, flags, name, ctx); +} +static inline int pld_snoc_ce_free_irq(unsigned int ce_id, void *ctx) +{ + return icnss_ce_free_irq(ce_id, ctx); +} +static inline void pld_snoc_enable_irq(unsigned int ce_id) +{ + icnss_enable_irq(ce_id); +} +static inline void pld_snoc_disable_irq(unsigned int ce_id) +{ + icnss_disable_irq(ce_id); +} +static inline int pld_snoc_get_ce_id(int irq) +{ + return icnss_get_ce_id(irq); +} +static inline int pld_snoc_power_on(struct device *dev) +{ + return icnss_power_on(dev); +} +static inline int pld_snoc_power_off(struct device *dev) +{ + return icnss_power_off(dev); +} +static inline int pld_snoc_get_irq(int ce_id) +{ + return icnss_get_irq(ce_id); +} +static inline int pld_snoc_set_wlan_unsafe_channel(u16 *unsafe_ch_list, + u16 ch_count) +{ + return icnss_set_wlan_unsafe_channel(unsafe_ch_list, ch_count); +} +static inline int pld_snoc_get_wlan_unsafe_channel(u16 *unsafe_ch_list, + u16 *ch_count, + u16 buf_len) +{ + return icnss_get_wlan_unsafe_channel(unsafe_ch_list, ch_count, + buf_len); +} +static inline int pld_snoc_wlan_set_dfs_nol(const void *info, u16 info_len) +{ + return icnss_wlan_set_dfs_nol(info, info_len); +} +static inline int pld_snoc_wlan_get_dfs_nol(void *info, u16 info_len) +{ + return icnss_wlan_get_dfs_nol(info, info_len); +} +static inline int pld_snoc_athdiag_read(struct device *dev, uint32_t offset, + uint32_t memtype, uint32_t datalen, + uint8_t *output) +{ + return icnss_athdiag_read(dev, offset, memtype, datalen, output); +} +static inline int pld_snoc_athdiag_write(struct device *dev, uint32_t offset, + uint32_t memtype, uint32_t datalen, + uint8_t *input) +{ + return icnss_athdiag_write(dev, offset, memtype, datalen, input); +} +static inline void *pld_snoc_smmu_get_mapping(struct device *dev) +{ + return icnss_smmu_get_mapping(dev); +} +static inline int pld_snoc_smmu_map(struct device *dev, phys_addr_t paddr, + uint32_t *iova_addr, size_t size) +{ + return icnss_smmu_map(dev, paddr, iova_addr, size); +} +static inline +unsigned int pld_snoc_socinfo_get_serial_number(struct device *dev) +{ + return icnss_socinfo_get_serial_number(dev); +} +static inline int pld_snoc_is_qmi_disable(void) +{ + return icnss_is_qmi_disable(); +} +static inline uint8_t *pld_snoc_get_wlan_mac_address(struct device *dev, + uint32_t *num) +{ + return icnss_get_wlan_mac_address(dev, num); +} + +static inline int pld_snoc_force_assert_target(struct device *dev) +{ + return icnss_trigger_recovery(dev); +} + +static inline int pld_snoc_set_fw_log_mode(u8 fw_log_mode) +{ + return icnss_set_fw_log_mode(fw_log_mode); +} + +static inline void pld_snoc_increment_driver_load_cnt(void) +{ + icnss_increment_driver_load_cnt(); +} + +static inline int pld_snoc_get_driver_load_cnt(void) +{ + return icnss_get_driver_load_cnt(); +} +#endif +#endif diff --git a/drivers/staging/qcacld-3.0/core/pld/src/pld_usb.c b/drivers/staging/qcacld-3.0/core/pld/src/pld_usb.c new file mode 100644 index 0000000000000000000000000000000000000000..07f87f5f1d1690d256362df955288043c65f25af --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/pld/src/pld_usb.c @@ -0,0 +1,211 @@ +/* + * Copyright (c) 2016 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 "pld_usb.h" +#include "pld_internal.h" + +#include +#include +#include +#include +#include +#include + + +#define VENDOR_ATHR 0x0CF3 +static struct usb_device_id pld_usb_id_table[] = { + {USB_DEVICE_AND_INTERFACE_INFO(VENDOR_ATHR, 0x9378, 0xFF, 0xFF, 0xFF)}, + {USB_DEVICE_AND_INTERFACE_INFO(VENDOR_ATHR, 0x9379, 0xFF, 0xFF, 0xFF)}, + {} /* Terminating entry */ +}; + +atomic_t pld_usb_reg_done; + +/** + * pld_usb_probe() - pld_usb_probe + * @interface: pointer to usb_interface structure + * @id: pointer to usb_device_id obtained from the enumerated device + + * Return: int 0 on success and errno on failure. + */ +static int pld_usb_probe(struct usb_interface *interface, + const struct usb_device_id *id) +{ + struct usb_device *pdev = interface_to_usbdev(interface); + struct pld_context *pld_context; + int ret = 0; + + pld_context = pld_get_global_context(); + if (!pld_context) { + ret = -ENODEV; + goto out; + } + + ret = pld_add_dev(pld_context, &pdev->dev, PLD_BUS_TYPE_USB); + if (ret) + goto out; + + ret = pld_context->ops->probe(&pdev->dev, + PLD_BUS_TYPE_USB, interface, (void *)id); + if (ret != 0) { + pr_err("%s, probe returned %d", __func__, ret); + atomic_set(&pld_usb_reg_done, false); + } else { + atomic_set(&pld_usb_reg_done, true); + } + +out: + return ret; +} + +/** + * pld_usb_remove() - Remove function for USB device + * @interface: pointer to usb_interface for the usb device being removed + * + * Return: void + */ +static void pld_usb_remove(struct usb_interface *interface) +{ + struct usb_device *pdev = interface_to_usbdev(interface); + struct pld_context *pld_context; + + pld_context = pld_get_global_context(); + + if (!pld_context) + return; + + if (atomic_read(&pld_usb_reg_done) != true) { + pr_info("%s: already de-registered!\n", __func__); + return; + } + + pld_context->ops->remove(&pdev->dev, PLD_BUS_TYPE_USB); + + pld_del_dev(pld_context, &pdev->dev); + + atomic_set(&pld_usb_reg_done, false); + pr_info("%s: done!\n", __func__); +} + +/** + * pld_usb_suspend() - Suspend callback function for power management + * @interface: pointer to usb_interface for the usb device + * @state: power state + * + * This function is to suspend the PCIE device when power management is + * enabled. + * + * Return: void + */ +static int pld_usb_suspend(struct usb_interface *interface, + pm_message_t state) +{ + struct usb_device *pdev = interface_to_usbdev(interface); + struct pld_context *pld_context; + + pld_context = pld_get_global_context(); + return pld_context->ops->suspend(&pdev->dev, PLD_BUS_TYPE_USB, state); +} + +/** + * pld_usb_resume() - Resume callback function for power management + * @interface: pointer to usb_interface for the usb device + * + * This function is to resume the USB device when power management is + * enabled. + * + * Return: void + */ +static int pld_usb_resume(struct usb_interface *interface) +{ + struct pld_context *pld_context; + struct usb_device *pdev = interface_to_usbdev(interface); + + pld_context = pld_get_global_context(); + return pld_context->ops->resume(&pdev->dev, PLD_BUS_TYPE_USB); +} + +/** + * pld_usb_reset_resume() - pld_usb_reset_resume + * @interface: pointer to usb_interface for the usb device + * + * Return: void + */ +static int pld_usb_reset_resume(struct usb_interface *interface) +{ + struct pld_context *pld_context; + struct usb_device *pdev = interface_to_usbdev(interface); + + pld_context = pld_get_global_context(); + return pld_context->ops->reset_resume(&pdev->dev, PLD_BUS_TYPE_USB); +} + +struct usb_driver pld_usb_ops = { + .name = "pld_usb", + .id_table = pld_usb_id_table, + .probe = pld_usb_probe, + .disconnect = pld_usb_remove, +#ifdef CONFIG_PM + .suspend = pld_usb_suspend, + .resume = pld_usb_resume, + .reset_resume = pld_usb_reset_resume, +#endif + .supports_autosuspend = true, +}; + +/** + * pld_usb_register_driver() - registration routine for wlan usb driver + * + * Return: int negative error code on failure and 0 on success + */ +int pld_usb_register_driver(void) +{ + int status; + + usb_register(&pld_usb_ops); + + if (atomic_read(&pld_usb_reg_done) == true) + status = 0; + else + status = -1; + + pr_info("%s usb_register %s, status %d\n", __func__, + (status == 0) ? "done" : "failed", status); + + return status; +} + +/** + * pld_usb_unregister_driver() - de-registration routine for wlan usb driver + * + * Return: void + */ +void pld_usb_unregister_driver(void) +{ + struct pld_context *pld_context; + pld_context = pld_get_global_context(); + + if (atomic_read(&pld_usb_reg_done) == false) + return; + + pld_context->ops->remove(NULL, PLD_BUS_TYPE_USB); + + atomic_set(&pld_usb_reg_done, false); + usb_deregister(&pld_usb_ops); + pr_info("%s usb_deregister done!\n", __func__); +} diff --git a/drivers/staging/qcacld-3.0/core/pld/src/pld_usb.h b/drivers/staging/qcacld-3.0/core/pld/src/pld_usb.h new file mode 100644 index 0000000000000000000000000000000000000000..ad44d2a0ea635f53b50c95019cbb67b412ded088 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/pld/src/pld_usb.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2016 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 __PLD_USB_H__ +#define __PLD_USB_H__ + +#include "pld_common.h" + +#if !defined(CONFIG_PLD_USB_CNSS) +static inline int pld_usb_register_driver(void) +{ + return 0; +} + +static inline void pld_usb_unregister_driver(void) +{ + return; +} + +static inline int pld_usb_get_ce_id(int irq) +{ + return 0; +} +#else +int pld_usb_register_driver(void); +void pld_usb_unregister_driver(void); +int pld_usb_get_ce_id(int irq); +#endif + +static inline int +pld_usb_get_fw_files_for_target(struct pld_fw_files *pfw_files, + u32 target_type, u32 target_version) +{ + pld_get_default_fw_files(pfw_files); + return 0; +} + +#endif /*__PLD_USB_H__*/ diff --git a/drivers/staging/qcacld-3.0/core/sap/dfs/inc/ath_dfs_structs.h b/drivers/staging/qcacld-3.0/core/sap/dfs/inc/ath_dfs_structs.h new file mode 100644 index 0000000000000000000000000000000000000000..83c0655262cae3c94c4a43d6d74c82388c688670 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/sap/dfs/inc/ath_dfs_structs.h @@ -0,0 +1,257 @@ +/* + * Copyright (c) 2011-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/*=========================================================================== + + ath_dfs_structs.h + + OVERVIEW: + + Source code borrowed from QCA_MAIN DFS module + + DEPENDENCIES: + + Are listed for each API below. + + ===========================================================================*/ + +/*=========================================================================== + + EDIT HISTORY FOR FILE + + This section contains comments describing changes made to the module. + Notice that changes are listed in reverse chronological order. + + when who what, where, why + ---------- --- -------------------------------------------------------- + + ===========================================================================*/ + +#ifndef _DFS__STRUCTS_H_ +#define _DFS__STRUCTS_H_ +#include + +#ifdef ANDROID +#include +#endif + +/* + * For the dfs_nol_clist_update() method - this is the + * update command. + */ +enum { + DFS_NOL_CLIST_CMD_NONE = 0x0, + DFS_NOL_CLIST_CMD_UPDATE = 0x1, +}; + +struct ath_dfs_caps { + uint32_t ath_dfs_ext_chan_ok:1, + /* Can radar be detected on the extension chan? */ + ath_dfs_combined_rssi_ok:1, + /* Can use combined radar RSSI? + * the following flag is used to indicate if radar detection + * scheme should use enhanced chirping detection algorithm. + * This flag also determines if certain radar data should be + * discarded to minimize false detection of radar. + */ + ath_dfs_use_enhancement:1, + ath_strong_signal_diversiry:1, + ath_chip_is_bb_tlv:1; + + /* + * goes with ath_strong_signal_diversiry: + * If we have fast diversity capability, read off + * Strong Signal fast diversity count set in the ini + * file, and store so we can restore the value when + * radar is disabled + */ + uint32_t ath_fastdiv_val; +}; + +/* + * These are defined in the HAL for now, and must be migrated outside + * of there in order to be used by the new partial offload data path. + */ + +struct dfs_pulse { + uint32_t rp_numpulses; /* Num of pulses in radar burst */ + uint32_t rp_pulsedur; /* Duration of each pulse in usecs */ + uint32_t rp_pulsefreq; /* Frequency of pulses in burst */ + uint32_t rp_max_pulsefreq; /* Frequency of pulses in burst */ + uint32_t rp_patterntype; /* fixed or variable pattern type */ + uint32_t rp_pulsevar; /* Time variation of pulse duration for + matched filter (single-sided) in usecs */ + uint32_t rp_threshold; /* Threshold for MF output to indicateC + radar match */ + uint32_t rp_mindur; /* Min pulse duration to be considered for + this pulse type */ + uint32_t rp_maxdur; /* Max pusle duration to be considered for + this pulse type */ + uint32_t rp_rssithresh; /* Min rssi to be considered a radar pulse */ + uint32_t rp_meanoffset; /* Offset for timing adjustment */ + int32_t rp_rssimargin; /* rssi threshold margin. In Turbo Mode HW + * reports rssi 3dBm lower than in non TURBO + * mode. This will be used to offset that + * diff. + */ + uint32_t rp_ignore_pri_window; + uint32_t rp_pulseid; /* Unique ID for identifying filter */ +}; + +struct dfs_staggered_pulse { + uint32_t rp_numpulses; /* Num of pulses in radar burst */ + uint32_t rp_pulsedur; /* Duration of each pulse in usecs */ + uint32_t rp_min_pulsefreq; /* Frequency of pulses in burst */ + uint32_t rp_max_pulsefreq; /* Frequency of pulses in burst */ + uint32_t rp_patterntype; /* fixed or variable pattern type */ + uint32_t rp_pulsevar; /* Time variation of pulse duration for + matched filter (single-sided) in usecs */ + uint32_t rp_threshold; /* Thershold for MF output to indicateC + radar match */ + uint32_t rp_mindur; /* Min pulse duration to be considered for + this pulse type */ + uint32_t rp_maxdur; /* Max pusle duration to be considered for + this pulse type */ + uint32_t rp_rssithresh; /* Min rssi to be considered a radar pulse */ + uint32_t rp_meanoffset; /* Offset for timing adjustment */ + int32_t rp_rssimargin; /* rssi threshold margin. In Turbo Mode HW + reports rssi 3dBm lower than in non TURBO + mode. This will be used to offset that + diff. */ + uint32_t rp_pulseid; /* Unique ID for identifying filter */ +}; + +struct dfs_bin5pulse { + uint32_t b5_threshold; /* Num of bin5 pulses to indicate detection */ + uint32_t b5_mindur; /* Min duration for a bin5 pulse */ + uint32_t b5_maxdur; /* Max duration for a bin5 pulse */ + uint32_t b5_timewindow; /* Window over which to count bin5 pulses */ + uint32_t b5_rssithresh; /* Min rssi to be considered a pulse */ + uint32_t b5_rssimargin; /* rssi threshold margin. In Turbo Mode HW + * reports rssi 3dB + */ +}; + +/* + * DFS NOL representation. + * + * This is used to represent the DFS NOL information between the + * NOL code in lmac/dfs/dfs_nol.c and any driver layer wishing + * to use it. + */ +struct dfs_nol_chan_entry { + uint32_t nol_chfreq; /* Centre frequency, MHz */ + uint32_t nol_chwidth; /* Width, MHz */ + unsigned long nol_start_ticks; /* start ticks, OS specific */ + uint32_t nol_timeout_ms; /* timeout, mS */ +}; + +/* HAL_PHYERR_PARAM; */ + +/* + * This represents the general case of the radar PHY configuration, + * across all chips. + * + * It's then up to each chip layer to translate to/from this + * (eg to HAL_PHYERR_PARAM for the HAL case.) + */ + +#define ATH_DFS_PHYERR_PARAM_NOVAL 0xFFFF +#define ATH_DFS_PHYERR_PARAM_ENABLE 0x8000 + +struct ath_dfs_phyerr_param { + int32_t pe_firpwr; /* FIR pwr out threshold */ + int32_t pe_rrssi; /* Radar rssi thresh */ + int32_t pe_height; /* Pulse height thresh */ + int32_t pe_prssi; /* Pulse rssi thresh */ + int32_t pe_inband; /* Inband thresh */ + + /* The following params are only for AR5413 and later */ + /* + * Relative power threshold in 0.5dB steps + */ + uint32_t pe_relpwr; + + /* + * Pulse Relative step threshold in 0.5dB steps + */ + uint32_t pe_relstep; + + /* + * Max length of radar sign in 0.8us units + */ + uint32_t pe_maxlen; + + /* + * Use the average in-band power measured over 128 cycles + */ + bool pe_usefir128; + + /* + * Enable to block radar check if pkt detect is done via OFDM + * weak signal detect or pkt is detected immediately after tx + * to rx transition + */ + bool pe_blockradar; + + /* + * Enable to use the max rssi instead of the last rssi during + * fine gain changes for radar detection + */ + bool pe_enmaxrssi; +}; + +static inline void ath_dfs_phyerr_param_copy(struct ath_dfs_phyerr_param *dst, + struct ath_dfs_phyerr_param *src) +{ + qdf_mem_copy(dst, src, sizeof(*dst)); +} + +static inline void ath_dfs_phyerr_init_noval(struct ath_dfs_phyerr_param *pe) +{ + pe->pe_firpwr = ATH_DFS_PHYERR_PARAM_NOVAL; + pe->pe_rrssi = ATH_DFS_PHYERR_PARAM_NOVAL; + pe->pe_height = ATH_DFS_PHYERR_PARAM_NOVAL; + pe->pe_prssi = ATH_DFS_PHYERR_PARAM_NOVAL; + pe->pe_inband = ATH_DFS_PHYERR_PARAM_NOVAL; + pe->pe_relpwr = ATH_DFS_PHYERR_PARAM_NOVAL; + pe->pe_relstep = ATH_DFS_PHYERR_PARAM_NOVAL; + pe->pe_maxlen = ATH_DFS_PHYERR_PARAM_NOVAL; + + /* XXX what about usefir128, blockradar, enmaxrssi? */ +} + +struct ath_dfs_radar_tab_info { + uint32_t dfsdomain; + int numradars; + struct dfs_pulse *dfs_radars; + int numb5radars; + struct dfs_bin5pulse *b5pulses; + struct ath_dfs_phyerr_param dfs_defaultparams; + int dfs_pri_multiplier; +}; +#endif /* _DFS__STRUCTS_H_ */ diff --git a/drivers/staging/qcacld-3.0/core/sap/dfs/inc/dfs.h b/drivers/staging/qcacld-3.0/core/sap/dfs/inc/dfs.h new file mode 100644 index 0000000000000000000000000000000000000000..0cb01d7deda99996fdafcbaba49b6e9acc13448f --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/sap/dfs/inc/dfs.h @@ -0,0 +1,922 @@ +/* + * Copyright (c) 2005-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/*=========================================================================== + + dfs.h + + OVERVIEW: + + Source code borrowed from QCA_MAIN DFS module + + DEPENDENCIES: + + Are listed for each API below. + + ===========================================================================*/ + +#ifndef _DFS_H_ +#define _DFS_H_ + +/* + *TO DO DFS- Need to include this file later on + *#include "ath_internal.h" + */ +/*DFS New Include Start*/ + +#include /* QDF_NBUF_EXEMPT_NO_EXEMPTION, etc. */ +#include /* qdf_nbuf_t, etc. */ +#include /* qdf_assert */ +#include /* qdf_spinlock */ +#include /* TAILQ */ +#include +#include +#include +#include +/*DFS Utility Include END*/ + +/* From wlan_modules/include/ */ +#include "ath_dfs_structs.h" +/*DFS - Newly added File to interface cld UMAC and dfs data structures*/ +#include +/* + *TO DO DFS- Need to include this file later on + #include "ah.h" + */ +/* #include "ah_desc.h" */ +#include "dfs_ioctl.h" +#include "dfs_ioctl_private.h" +#include "dfs_interface.h" +#include "cds_ieee80211_common.h" +#include "cds_api.h" + +#define ATH_SUPPORT_DFS 1 +#define CHANNEL_TURBO 0x00010 +#define DFS_PRINTK(_fmt, ...) printk((_fmt), __VA_ARGS__) +#define DFS_DPRINTK(dfs, _m, _fmt, ...) do { \ + if (((dfs) == NULL) || \ + ((dfs) != NULL && \ + ((_m) & (dfs)->dfs_debug_mask))) { \ + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_DEBUG, \ + _fmt, __VA_ARGS__); \ + } \ +} while (0) + +#define DFS_MIN(a, b) ((a) < (b) ? (a) : (b)) +#define DFS_MAX(a, b) ((a) > (b) ? (a) : (b)) +#define DFS_DIFF(a, b) (DFS_MAX(a, b) - DFS_MIN(a, b)) +/* + * Maximum number of radar events to be processed in a single iteration. + * Allows soft watchdog to run. + */ +#define MAX_EVENTS 100 + +#define DFS_STATUS_SUCCESS 0 +#define DFS_STATUS_FAIL 1 + +#define DFS_80P80_SEG0 0 +#define DFS_80P80_SEG1 1 + +/** + * @DFS_RADAR_SUMMARY_REPORT_VERSION_2: DFS-2 radar summary report + * @DFS_RADAR_SUMMARY_REPORT_VERSION_3: DFS-3 radar summary report + */ +enum { + DFS_RADAR_SUMMARY_REPORT_VERSION_2 = 1, + DFS_RADAR_SUMMARY_REPORT_VERSION_3 = 2, +}; + + +/* + * Constants to use for chirping detection. + * + * All are unconverted as HW reports them. + * + * XXX Are these constants with or without fast clock 5GHz operation? + * XXX Peregrine reports pulses in microseconds, not hardware clocks! + */ +#define MIN_BIN5_DUR 63 /* 50 * 1.25 */ +#define MIN_BIN5_DUR_MICROSEC 50 +#define MAYBE_BIN5_DUR 35 /* 28 * 1.25 */ +#define MAYBE_BIN5_DUR_MICROSEC 28 +/* #define MAX_BIN5_DUR 131 / * 105 * 1.25* / */ +/* use 145 for osprey conversion is already done using dfs->dur_multiplier */ +#define MAX_BIN5_DUR 145 +#define MAX_BIN5_DUR_MICROSEC 105 +#define MAX_DFS_RADAR_TABLE_TYPE 256 + +#define DFS_BIN5_TIME_WINDOW_UNITS_MULTIPLIER 1000000 + +#define DFS_MARGIN_EQUAL(a, b, margin) ((DFS_DIFF(a, b)) <= margin) +#define DFS_MAX_STAGGERED_BURSTS 3 + +/* + * All filter thresholds in the radar filter tables + * are effective at a 50% channel loading + */ +#define DFS_CHAN_LOADING_THRESH 50 +#define DFS_EXT_CHAN_LOADING_THRESH 30 +#define DFS_DEFAULT_PRI_MARGIN 6 +#define DFS_DEFAULT_FIXEDPATTERN_PRI_MARGIN 4 +#define ATH_DFSQ_LOCK(_dfs) qdf_spin_lock_bh((&(_dfs)->dfs_radarqlock)) +#define ATH_DFSQ_UNLOCK(_dfs) qdf_spin_unlock_bh((&(_dfs)->dfs_radarqlock)) +#define ATH_DFSQ_LOCK_INIT(_dfs) qdf_spinlock_create(&(_dfs)->dfs_radarqlock) + +#define ATH_ARQ_LOCK(_dfs) qdf_spin_lock_bh((&(_dfs)->dfs_arqlock)) +#define ATH_ARQ_UNLOCK(_dfs) qdf_spin_unlock_bh((&(_dfs)->dfs_arqlock)) +#define ATH_ARQ_LOCK_INIT(_dfs) qdf_spinlock_create(&(_dfs)->dfs_arqlock) + +#define ATH_DFSEVENTQ_LOCK(_dfs) qdf_spin_lock_bh((&(_dfs)->dfs_eventqlock)) +#define ATH_DFSEVENTQ_UNLOCK(_dfs) qdf_spin_unlock_bh((&(_dfs)->dfs_eventqlock)) +#define ATH_DFSEVENTQ_LOCK_INIT(_dfs) \ + qdf_spinlock_create((&(_dfs)->dfs_eventqlock)) +/* Mask for time stamp from descriptor */ +#define DFS_TSMASK 0xFFFFFFFF +/* Shift for time stamp from descriptor */ +#define DFS_TSSHIFT 32 +/* 64 bit TSF wrap value */ +#define DFS_TSF_WRAP 0xFFFFFFFFFFFFFFFFULL +/* TS mask for 64 bit value */ +#define DFS_64BIT_TSFMASK 0x0000000000007FFFULL + +#define DFS_AR_RADAR_RSSI_THR 5 /* in dB */ +#define DFS_AR_RADAR_RESET_INT 1 /* in secs */ +#define DFS_AR_RADAR_MAX_HISTORY 500 +#define DFS_AR_REGION_WIDTH 128 +#define DFS_AR_RSSI_THRESH_STRONG_PKTS 17 /* in dB */ +#define DFS_AR_RSSI_DOUBLE_THRESHOLD 15 /* in dB */ +#define DFS_AR_MAX_NUM_ACK_REGIONS 9 +#define DFS_AR_ACK_DETECT_PAR_THRESH 20 +#define DFS_AR_PKT_COUNT_THRESH 20 + +#define DFS_MAX_DL_SIZE 64 +#define DFS_MAX_DL_MASK 0x3F + +#define DFS_NOL_TIME DFS_NOL_TIMEOUT_US +/* 30 minutes in usecs */ + +#define DFS_WAIT_TIME (60 * 1000000) /* 1 minute in usecs */ + +#define DFS_DISABLE_TIME (3 * 60 * 1000000) /* 3 minutes in usecs */ + +#define DFS_MAX_B5_SIZE 128 +#define DFS_MAX_B5_MASK 0x0000007F /* 128 */ + +#define DFS_MAX_RADAR_OVERLAP 16 /* Max number of overlapping filters */ +/* Max number of dfs events which can be q'd */ +#define DFS_MAX_EVENTS 1024 + +#define DFS_RADAR_EN 0x80000000 /* Radar detect is capable */ +#define DFS_AR_EN 0x40000000 /* AR detect is capable */ +#define DFS_MAX_RSSI_VALUE 0x7fffffff /* Max rssi value */ +/* max num of pulses in a burst */ +#define DFS_BIN_MAX_PULSES 60 +#define DFS_BIN5_PRI_LOWER_LIMIT 990 /* us */ + +/* to cover the single pusle burst case, change from 2010 us to 2010000 us */ + +/* + * this is reverted back to 2010 as larger value causes false + * bin5 detect (EV76432, EV76320) + */ +#define DFS_BIN5_PRI_HIGHER_LIMIT 2010 /* us */ + +#define DFS_BIN5_WIDTH_MARGIN 4 /* us */ +#define DFS_BIN5_RSSI_MARGIN 5 /* dBm */ +/*Following threshold is not specified but should be okay statistically*/ +#define DFS_BIN5_BRI_LOWER_LIMIT 300000 /* us */ +#define DFS_BIN5_BRI_UPPER_LIMIT 12000000 /* us */ +/* Max number of pulses kept in buffer */ +#define DFS_MAX_PULSE_BUFFER_SIZE 1024 +#define DFS_MAX_PULSE_BUFFER_MASK 0x3ff + +#define DFS_FAST_CLOCK_MULTIPLIER (800/11) +#define DFS_NO_FAST_CLOCK_MULTIPLIER (80) + +#define DFS_WAR_PLUS_30_MHZ_SEPARATION 30 +#define DFS_WAR_MINUS_30_MHZ_SEPARATION -30 +#define DFS_WAR_PEAK_INDEX_ZERO 0 +#define DFS_TYPE4_WAR_PULSE_DURATION_LOWER_LIMIT 11 +#define DFS_TYPE4_WAR_PULSE_DURATION_UPPER_LIMIT 33 +#define DFS_TYPE4_WAR_PRI_LOWER_LIMIT 200 +#define DFS_TYPE4_WAR_PRI_UPPER_LIMIT 500 +#define DFS_TYPE4_WAR_VALID_PULSE_DURATION 12 +#define DFS_ETSI_TYPE2_TYPE3_WAR_PULSE_DUR_LOWER_LIMIT 15 +#define DFS_ETSI_TYPE2_TYPE3_WAR_PULSE_DUR_UPPER_LIMIT 33 +#define DFS_ETSI_TYPE2_WAR_PRI_LOWER_LIMIT 625 +#define DFS_ETSI_TYPE2_WAR_PRI_UPPER_LIMIT 5000 +#define DFS_ETSI_TYPE3_WAR_PRI_LOWER_LIMIT 250 +#define DFS_ETSI_TYPE3_WAR_PRI_UPPER_LIMIT 435 +#define DFS_ETSI_WAR_VALID_PULSE_DURATION 15 + +typedef qdf_spinlock_t dfsq_lock_t; + +#ifdef WIN32 +#pragma pack(push, dfs_pulseparams, 1) +#endif +struct dfs_pulseparams { + uint64_t p_time; /* time for start of pulse in usecs */ + uint8_t p_dur; /* Duration of pulse in usecs */ + uint8_t p_rssi; /* Duration of pulse in usecs */ +} qdf_packed; +#ifdef WIN32 +#pragma pack(pop, dfs_pulseparams) +#endif + +#ifdef WIN32 +#pragma pack(push, dfs_pulseline, 1) +#endif +struct dfs_pulseline { + /* pl_elems - array of pulses in delay line */ + struct dfs_pulseparams pl_elems[DFS_MAX_PULSE_BUFFER_SIZE]; + uint32_t pl_firstelem; /* Index of the first element */ + uint32_t pl_lastelem; /* Index of the last element */ + uint32_t pl_numelems; /* Number of elements in the delay line */ +} qdf_packed; +#ifdef WIN32 +#pragma pack(pop, dfs_pulseline) +#endif + +#ifdef WIN32 +#pragma pack(push, dfs_event, 1) +#endif + +#define DFS_EVENT_CHECKCHIRP 0x01 /* Whether to check the chirp flag */ +#define DFS_EVENT_HW_CHIRP 0x02 /* hardware chirp */ +#define DFS_EVENT_SW_CHIRP 0x04 /* software chirp */ + +/* + * Use this only if the event has CHECKCHIRP set. + */ +#define DFS_EVENT_ISCHIRP(e) \ + ((e)->re_flags & (DFS_EVENT_HW_CHIRP | DFS_EVENT_SW_CHIRP)) + +/* + * Check if the given event is to be rejected as not possibly + * a chirp. This means: + * (a) it's a hardware or software checked chirp, and + * (b) the HW/SW chirp bits are both 0. + */ +#define DFS_EVENT_NOTCHIRP(e) \ + (((e)->re_flags & (DFS_EVENT_CHECKCHIRP)) && \ + (!DFS_EVENT_ISCHIRP((e)))) + +/** + * struct dfs_event - to hold dfs events + * @re_full_ts: 64-bit full timestamp from interrupt time + * @re_ts: Original 15 bit recv timestamp + * @re_rssi: rssi of radar event + * @re_dur: duration of radar pulse + * @re_chanindex: Channel of event + * @re_flags: Event flags + * @re_freq: Centre frequency of event, KHz + * @re_freq_lo: Lower bounds of frequency, KHz + * @re_freq_hi: Upper bounds of frequency, KHz + * @sidx: Pulse Index as in radar summary report + * @radar_80p80_segid: 80p80 segment ID as in radar sum report + * @delta_peak: delta peak reported in radar summary + * @delta_diff: delta diff reported in radar summary + * @agc_total_gain: agc total gain reported in radar summary + * @agc_mb_gain: agc mb gain reported in radar summary + * @radar_subchan_mask: subchan mask reported in radar summary + * @pulse_height: pulse height reported in radar summary + * @triggering_agc_event: triggering agc reported in radar summary + * @pulse_rssi: rssi of phyerr reported in radar summary + * @radar_fft_pri80_inband_power: Pri80MHz pwr reported in summary + * @radar_fft_ext80_inband_power: Ext80MHz pwr reported in summary + * @rsu_version: Radar summary report version + * @dfs_phyerr_eventq_serial_num: phyerr seq num queued for pattern matching + * @peak_mag: Peak mag reported in radar search FFT report + * @re_list: List of radar events + * + * To Process radar events + */ +struct dfs_event { + uint64_t re_full_ts; + uint32_t re_ts; + uint8_t re_rssi; + uint8_t re_dur; + uint8_t re_chanindex; + uint8_t re_flags; + uint32_t re_freq; + uint32_t re_freq_lo; + uint32_t re_freq_hi; + int sidx; + int radar_80p80_segid; + uint8_t delta_peak; + uint8_t delta_diff; + uint8_t agc_total_gain; + uint8_t agc_mb_gain; + uint8_t radar_subchan_mask; + uint8_t pulse_height; + uint8_t triggering_agc_event; + uint8_t pulse_rssi; + uint8_t radar_fft_pri80_inband_power; + uint8_t radar_fft_ext80_inband_power; + uint8_t rsu_version; + uint8_t dfs_phyerr_eventq_serial_num; + uint8_t peak_mag; + STAILQ_ENTRY(dfs_event) re_list; +} qdf_packed; +#ifdef WIN32 +#pragma pack(pop, dfs_event) +#endif + +#define DFS_AR_MAX_ACK_RADAR_DUR 511 +#define DFS_AR_MAX_NUM_PEAKS 3 +#define DFS_AR_ARQ_SIZE 2048 /* 8K AR events for buffer size */ +#define DFS_AR_ARQ_SEQSIZE 2049 /* Sequence counter wrap for AR */ + +#define DFS_RADARQ_SIZE 512 /* 1K radar events for buffer size */ +#define DFS_RADARQ_SEQSIZE 513 /* Sequence counter wrap for radar */ +/* Number of radar channels we keep state for */ +#define DFS_NUM_RADAR_STATES 64 +/* Max number radar filters for each type */ +#define DFS_MAX_NUM_RADAR_FILTERS 10 +/* Number of different radar types */ +#define DFS_MAX_RADAR_TYPES 32 + +struct dfs_ar_state { + uint32_t ar_prevwidth; + uint32_t ar_phyerrcount[DFS_AR_MAX_ACK_RADAR_DUR]; + uint32_t ar_acksum; + uint32_t ar_packetthreshold; /* Thresh to determine traffic load */ + uint32_t ar_parthreshold; /* Thresh to determine peak */ + uint32_t ar_radarrssi; /* Rssi threshold for AR event */ + uint16_t ar_prevtimestamp; + uint16_t ar_peaklist[DFS_AR_MAX_NUM_PEAKS]; +}; + +#ifdef WIN32 +#pragma pack(push, dfs_delayelem, 1) +#endif +struct dfs_delayelem { + /* Current "filter" time for start of pulse in usecs */ + uint32_t de_time; + /* Duration of pulse in usecs */ + uint8_t de_dur; + /* rssi of pulse in dB */ + uint8_t de_rssi; + /* time stamp for this delay element */ + uint64_t de_ts; +} qdf_packed; +#ifdef WIN32 +#pragma pack(pop, dfs_delayelem) +#endif + +/* NB: The first element in the circular buffer is the oldest element */ + +#ifdef WIN32 +#pragma pack(push, dfs_delayline, 1) +#endif +struct dfs_delayline { + /* Array of pulses in delay line */ + struct dfs_delayelem dl_elems[DFS_MAX_DL_SIZE]; + /* Last timestamp the delay line was used (in usecs) */ + uint64_t dl_last_ts; + /* Index of the first element */ + uint32_t dl_firstelem; + /* Index of the last element */ + uint32_t dl_lastelem; + /* Number of elements in the delay line */ + uint32_t dl_numelems; +} qdf_packed; +#ifdef WIN32 +#pragma pack(pop, dfs_delayline) +#endif + +#ifdef WIN32 +#pragma pack(push, dfs_filter, 1) +#endif +struct dfs_filter { + /* Delay line of pulses for this filter */ + struct dfs_delayline rf_dl; + /* Delay line of pulses for this filter in 80p80 */ + struct dfs_delayline rf_dl_ext_seg; + /* Number of pulses in the filter */ + uint32_t rf_numpulses; + /* min pri to be considered for this filter */ + uint32_t rf_minpri; + /* max pri to be considered for this filter */ + uint32_t rf_maxpri; + /* match filter output threshold for radar detect */ + uint32_t rf_threshold; + /* Length (in usecs) of the filter */ + uint32_t rf_filterlen; + /* fixed or variable pattern type */ + uint32_t rf_patterntype; + /* indicates if it is a fixed pri pulse */ + uint32_t rf_fixed_pri_radar_pulse; + /* Min duration for this radar filter */ + uint32_t rf_mindur; + /* Max duration for this radar filter */ + uint32_t rf_maxdur; + uint32_t rf_ignore_pri_window; + /* Unique ID corresponding to the original filter ID */ + uint32_t rf_pulseid; +} qdf_packed; +#ifdef WIN32 +#pragma pack(pop, dfs_filter) +#endif + +struct dfs_filtertype { + struct dfs_filter *ft_filters[DFS_MAX_NUM_RADAR_FILTERS]; + /* Duration of pulse which specifies filter type */ + uint32_t ft_filterdur; + /* Num filters of this type */ + uint32_t ft_numfilters; + /* Last timestamp this filtertype was used(in usecs) */ + uint64_t ft_last_ts; + /* min pulse duration to be considered for this filter type */ + uint32_t ft_mindur; + /* max pulse duration to be considered for this filter type */ + uint32_t ft_maxdur; + /* min rssi to be considered for this filter type */ + uint32_t ft_rssithresh; + /* Num pulses in each filter of this type */ + uint32_t ft_numpulses; + /* fixed or variable pattern type */ + uint32_t ft_patterntype; + /* min pri to be considered for this type */ + uint32_t ft_minpri; + /* rssi threshold margin. In Turbo Mode HW + * reports rssi 3dB lower than in non TURBO + * mode. This will offset that diff. + */ + uint32_t ft_rssimargin; +}; + +struct dfs_state { + struct dfs_ieee80211_channel rs_chan; /* Channel info */ + uint8_t rs_chanindex; /* Channel index in radar structure */ + uint32_t rs_numradarevents; /* Number of radar events */ + + struct ath_dfs_phyerr_param rs_param; +}; + +/* 30 minutes in seconds */ +#define DFS_NOL_TIMEOUT_S (30*60) +/* 5 minutes in seconds - debugging */ +/* #define DFS_NOL_TIMEOUT_S (5*60) */ +#define DFS_NOL_TIMEOUT_MS (DFS_NOL_TIMEOUT_S * 1000) +#define DFS_NOL_TIMEOUT_US (DFS_NOL_TIMEOUT_MS * 1000) + +#ifdef WIN32 +#pragma pack(push, dfs_nolelem, 1) +#endif +struct dfs_nolelem { + uint32_t nol_freq; /* centre frequency */ + uint32_t nol_chwidth; /* event width (MHz) */ + unsigned long nol_start_ticks; /* NOL start time in OS ticks */ + uint32_t nol_timeout_ms; /* NOL timeout value in msec */ + os_timer_t nol_timer; /* per element NOL timer */ + struct dfs_nolelem *nol_next; /* next element pointer */ +} qdf_packed; +#ifdef WIN32 +#pragma pack(pop, dfs_nolelem) +#endif + +/* Pass structure to DFS NOL timer */ +struct dfs_nol_timer_arg { + struct ath_dfs *dfs; + uint16_t delfreq; + uint16_t delchwidth; +}; + +#ifdef WIN32 +#pragma pack(push, dfs_info, 1) +#endif +struct dfs_info { + /* Use the NOL when radar found (default: true) */ + int rn_use_nol; + /* Number of different types of radars */ + uint32_t rn_numradars; + /* Last 64 bit timstamp from recv interrupt */ + uint64_t rn_lastfull_ts; + /* last 15 bit ts from recv descriptor */ + uint16_t rn_last_ts; + /* last unique 32 bit ts from recv descriptor */ + uint32_t rn_last_unique_ts; + /* Prefix to prepend to 15 bit recv ts */ + uint64_t rn_ts_prefix; + /* Number of bin5 radar pulses to search for */ + uint32_t rn_numbin5radars; + /* Value of fast diversity gc limit from init file */ + uint32_t rn_fastdivGCval; + /* Min rssi for all radar types */ + int32_t rn_minrssithresh; + /* Max pulse width in TSF ticks */ + uint32_t rn_maxpulsedur; + + uint8_t dfs_ext_chan_busy; + uint64_t ext_chan_busy_ts; + + uint64_t dfs_bin5_chirp_ts; + uint8_t dfs_last_bin5_dur; + uint8_t dfs_last_bin5_dur_ext_seg; +} qdf_packed; +#ifdef WIN32 +#pragma pack(pop, dfs_info) +#endif + +struct dfs_bin5elem { + uint64_t be_ts; /* Timestamp for the bin5 element */ + uint32_t be_rssi; /* Rssi for the bin5 element */ + uint32_t be_dur; /* Duration of bin5 element */ +}; + +struct dfs_bin5radars { + /* List of bin5 elems that fall within the time window */ + struct dfs_bin5elem br_elems[DFS_MAX_B5_SIZE]; + /* Index of the first element */ + uint32_t br_firstelem; + /* Index of the last element */ + uint32_t br_lastelem; + /* Number of elements in the delay line */ + uint32_t br_numelems; + /* Original info about bin5 pulse */ + struct dfs_bin5pulse br_pulse; +}; + +struct dfs_stats { + uint32_t num_radar_detects; /* total num. of radar detects */ + uint32_t total_phy_errors; + uint32_t owl_phy_errors; + uint32_t pri_phy_errors; + uint32_t ext_phy_errors; + uint32_t dc_phy_errors; + uint32_t early_ext_phy_errors; + uint32_t bwinfo_errors; + uint32_t datalen_discards; + uint32_t rssi_discards; + uint64_t last_reset_tstamp; +}; + +/* + * This is for debuggin DFS as console log interferes with (helps) + * radar detection + */ + +#define DFS_EVENT_LOG_SIZE 256 +struct dfs_event_log { + uint64_t ts; /* 64-bit full timestamp from interrupt time */ + uint32_t diff_ts; /* diff timestamp */ + uint8_t rssi; /* rssi of radar event */ + uint8_t dur; /* duration of radar pulse */ +}; + +#define ATH_DFS_RESET_TIME_S 7 +#define ATH_DFS_WAIT (60 + ATH_DFS_RESET_TIME_S) /* 60 seconds */ +#define ATH_DFS_WAIT_MS ((ATH_DFS_WAIT) * 1000) /*in MS */ + +#define ATH_DFS_WEATHER_CHANNEL_WAIT_MIN 10 /*10 minutes */ +#define ATH_DFS_WEATHER_CHANNEL_WAIT_S (ATH_DFS_WEATHER_CHANNEL_WAIT_MIN * 60) +#define ATH_DFS_WEATHER_CHANNEL_WAIT_MS \ + ((ATH_DFS_WEATHER_CHANNEL_WAIT_S) * 1000) /*in MS */ + +#define ATH_DFS_WAIT_POLL_PERIOD 2 /* 2 seconds */ +/*in MS */ +#define ATH_DFS_WAIT_POLL_PERIOD_MS ((ATH_DFS_WAIT_POLL_PERIOD) * 1000) +#define ATH_DFS_TEST_RETURN_PERIOD 2 /* 2 seconds */ +/* n MS */ +#define ATH_DFS_TEST_RETURN_PERIOD_MS ((ATH_DFS_TEST_RETURN_PERIOD) * 1000) +#define IS_CHANNEL_WEATHER_RADAR(chan) ((chan->ic_freq >= 5600) && \ + (chan->ic_freq <= 5650)) + +#define DFS_DEBUG_TIMEOUT_S 30 /* debug timeout is 30 seconds */ +#define DFS_DEBUG_TIMEOUT_MS (DFS_DEBUG_TIMEOUT_S * 1000) + +#define RSSI_POSSIBLY_FALSE 50 +#define SEARCH_FFT_REPORT_PEAK_MAG_THRSH 40 + +struct ath_dfs { + uint32_t dfs_debug_mask; /* current debug bitmask */ + int16_t dfs_curchan_radindex; /* cur. channel radar index */ + int16_t dfs_extchan_radindex; /* extension channel radar index */ + uint32_t dfsdomain; /* cur. DFS domain */ + uint32_t dfs_proc_phyerr; /* Flags for Phy Errs to process */ + struct ieee80211com *ic; + STAILQ_HEAD(, dfs_event) dfs_eventq; /* Q of free dfs event objects */ + dfsq_lock_t dfs_eventqlock; /* Lock for free dfs event list */ + STAILQ_HEAD(, dfs_event) dfs_radarq; /* Q of radar events */ + dfsq_lock_t dfs_radarqlock; /* Lock for dfs q */ + STAILQ_HEAD(, dfs_event) dfs_arq; /* Q of AR events */ + dfsq_lock_t dfs_arqlock; /* Lock for AR q */ + + struct dfs_ar_state dfs_ar_state; /* AR state */ + + /* dfs_radar - Per-Channel Radar detector state */ + struct dfs_state dfs_radar[DFS_NUM_RADAR_STATES]; + + /* dfs_radarf - One filter for each radar pulse type */ + struct dfs_filtertype *dfs_radarf[DFS_MAX_RADAR_TYPES]; + + struct dfs_info dfs_rinfo; /* State vars for radar processing */ + struct dfs_bin5radars *dfs_b5radars; /* array of bin5 radar events */ + /* array of bin5 radar events on extension segment in 80p80 */ + struct dfs_bin5radars *dfs_b5radars_ext_seg; + int8_t **dfs_radartable; /* map of radar durs to filter types */ +#ifndef ATH_DFS_RADAR_DETECTION_ONLY + struct dfs_nolelem *dfs_nol; /* Non occupancy list for radar */ + int dfs_nol_count; /* How many items? */ +#endif + /* Default phy params per radar state */ + struct ath_dfs_phyerr_param dfs_defaultparams; + struct dfs_stats ath_dfs_stats; /* DFS related stats */ + struct dfs_pulseline *pulses; /* pulse history */ + struct dfs_pulseline *pulses_ext_seg; /* pulse history ext 80p80 seg */ + struct dfs_event *events; /* Events structure */ + + uint32_t ath_radar_tasksched:1, /* radar task is scheduled */ + ath_dfswait:1, /* waiting on channel for radar detect */ + ath_dfstest:1; /* Test timer in progress */ + struct ath_dfs_caps dfs_caps; + /* IEEE chan num to return to after + * a dfs mute test + */ + uint8_t ath_dfstest_ieeechan; +#ifndef ATH_DFS_RADAR_DETECTION_ONLY + uint32_t ath_dfs_cac_time; /* CAC period */ + uint32_t ath_dfstesttime; /* Time to stay off chan during dfs test */ + os_timer_t ath_dfswaittimer; /* dfs wait timer */ + os_timer_t ath_dfstesttimer; /* dfs mute test timer */ + os_timer_t ath_dfs_debug_timer; /* dfs debug timer */ + uint8_t dfs_bangradar; +#endif + os_timer_t ath_dfs_task_timer; /* dfs wait timer */ + int dur_multiplier; + + uint16_t ath_dfs_isdfsregdomain; /* true when we are DFS domain */ + int ath_dfs_false_rssi_thres; + int ath_dfs_peak_mag; + + struct dfs_event_log radar_log[DFS_EVENT_LOG_SIZE]; + int dfs_event_log_count; + int dfs_event_log_on; + int dfs_phyerr_count; /* same as number of PHY radar interrupts */ + /* + * when TLV is supported, # of radar events ignored after TLV is parsed + */ + int dfs_phyerr_reject_count; + /* number of radar events queued for matching the filters */ + int dfs_phyerr_queued_count; + int dfs_phyerr_freq_min; + int dfs_phyerr_freq_max; + int dfs_phyerr_w53_counter; + /* allow pulse if they are within multiple of PRI for the radar type */ + int dfs_pri_multiplier; + int ath_dfs_nol_timeout; + int dfs_pri_multiplier_ini; /* dfs pri configuration from ini */ + /* + * Flag to indicate if DFS test mode is enabled and + * channel switch is disabled. + */ + int8_t disable_dfs_ch_switch; + uint32_t test_ts; /* to capture timestamps on primary segment */ + uint32_t test_ts_ext_seg; /* to capture timestamps on ext segment */ +}; + +/* This should match the table from if_ath.c */ +enum { + ATH_DEBUG_DFS = 0x00000100, /* Minimal DFS debug */ + ATH_DEBUG_DFS1 = 0x00000200, /* Normal DFS debug */ + ATH_DEBUG_DFS2 = 0x00000400, /* Maximal DFS debug */ + ATH_DEBUG_DFS3 = 0x00000800, /* matched filterID display */ + + ATH_DEBUG_DFS_PHYERR = 0x00001000, /* phy error parsing */ + ATH_DEBUG_DFS_NOL = 0x00002000, /* NOL related entries */ + ATH_DEBUG_DFS_PHYERR_SUM = 0x00004000, /* PHY error summary */ + ATH_DEBUG_DFS_PHYERR_PKT = 0x00008000, /* PHY error payload */ + + ATH_DEBUG_DFS_BIN5 = 0x00010000, /* bin5 checks */ + ATH_DEBUG_DFS_BIN5_FFT = 0x00020000, /* bin5 FFT check */ + ATH_DEBUG_DFS_BIN5_PULSE = 0x00040000, /* bin5 pulse check */ +}; + +#define IS_CHAN_HT40(_c) IEEE80211_IS_CHAN_11N_HT40(_c) +#define IS_CHAN_HT40_PLUS(_c) IEEE80211_IS_CHAN_11N_HT40PLUS(_c) +#define IS_CHAN_HT40_MINUS(_c) IEEE80211_IS_CHAN_11N_HT40MINUS(_c) + +/* + * chirp notes! + * + * Pre-Sowl chips don't do FFT reports, so chirp pulses simply show up + * as long duration pulses. + * + * The bin5 checking code would simply look for a chirp pulse of the correct + * duration (within MIN_BIN5_DUR and MAX_BIN5_DUR) and add it to the "chirp" + * pattern. + * + * For Sowl and later, an FFT was done on longer duration frames. If those + * frames looked like a chirp, their duration was adjusted to fall within + * the chirp duration limits. If the pulse failed the chirp test (it had + * no FFT data or the FFT didn't meet the chirping requirements) then the + * pulse duration was adjusted to be greater than MAX_BIN5_DUR, so it + * would always fail chirp detection. + * + * This is pretty horrible. + * + * The eventual goal for chirp handling is thus: + * + * + In case someone ever wants to do chirp detection with this code on + * chips that don't support chirp detection, you can still do it based + * on pulse duration. That's your problem to solve. + * + * + For chips that do hardware chirp detection or FFT, the "do_check_chirp" + * bit should be set. + * + * + Then, either is_hw_chirp or is_sw_chirp is set, indicating that + * the hardware or software post-processing of the chirp event found + * that indeed it was a chirp. + * + * + Finally, the bin5 code should just check whether the chirp bits are + * set and behave appropriately, falling back onto the duration checks + * if someone wishes to use this on older hardware (or with disabled + * FFTs, for whatever reason.) + */ +/* + * XXX TODO: + * + * + add duration in uS and raw duration, so the PHY error parsing + * code is responsible for doing the duration calculation; + * + add ts in raw and corrected, so the PHY error parsing + * code is responsible for doing the offsetting, not the radar + * event code. + */ +struct dfs_phy_err { + uint64_t fulltsf; /* 64-bit TSF as read from MAC */ + + uint32_t is_pri:1, /* detected on primary channel */ + is_ext:1, /* detected on extension channel */ + is_dc:1, /* detected at DC */ + is_early:1, /* early detect */ + do_check_chirp:1, /* whether to check hw_chirp/sw_chirp */ + is_hw_chirp:1, /* hardware-detected chirp */ + is_sw_chirp:1; /* software detected chirp */ + + uint32_t rs_tstamp; /* 32 bit TSF from RX descriptor (event) */ + uint32_t freq; /* Centre frequency of event - KHz */ + uint32_t freq_lo; /* Lower bounds of frequency - KHz */ + uint32_t freq_hi; /* Upper bounds of frequency - KHz */ + + uint8_t rssi; /* pulse RSSI */ + uint8_t dur; /* pulse duration, raw (not uS) */ + int sidx; /* Pulse Index as in radar summary report */ + /* + * Indicates segment ID on which the phyerror is received + * when SAP is operating in 80p80 channel width. + */ + int radar_80p80_segid; + /* delta peak reported in radar summary */ + int delta_peak; + /* delta diff reported in radar summary */ + int delta_diff; + /* agc total gain reported in radar summary */ + int agc_total_gain; + /* agc mb gain reported in radar summary */ + int agc_mb_gain; + /* subchan mask reported in radar summary */ + int radar_subchan_mask; + /* pulse height reported in radar summary */ + int pulse_height; + /* triggering agc reported in radar summary */ + int triggering_agc_event; + /* rssi of phyerr reported in radar summary */ + int pulse_rssi; + /* Pri80MHz pwr reported in summary */ + int radar_fft_pri80_inband_power; + /* Ext80MHz pwr reported in summary */ + int radar_fft_ext80_inband_power; + /* Peak mag reported in radar search FFT report */ + int peak_mag; + /* Radar summary report version */ + int rsu_version; +}; + +/* Attach, detach, handle ioctl prototypes */ + +int dfs_get_thresholds(struct ieee80211com *ic, + struct ath_dfs_phyerr_param *param); +int dfs_set_thresholds(struct ieee80211com *ic, + const uint32_t threshtype, const uint32_t value); + +/* PHY error and radar event handling */ +int dfs_process_radarevent(struct ath_dfs *dfs, + struct dfs_ieee80211_channel *chan); + +/* Non occupancy (NOL) handling prototypes */ +void dfs_nol_addchan(struct ath_dfs *dfs, struct dfs_ieee80211_channel *chan, + uint32_t dfs_nol_timeout); +void dfs_get_nol(struct ath_dfs *dfs, struct dfsreq_nolelem *dfs_nol, + int *nchan); +void dfs_set_nol(struct ath_dfs *dfs, struct dfsreq_nolelem *dfs_nol, + int nchan); +void dfs_nol_update(struct ath_dfs *dfs); +void dfs_nol_timer_cleanup(struct ath_dfs *dfs); + +/* FCC Bin5 detection prototypes */ +int dfs_bin5_check_pulse(struct ath_dfs *dfs, struct dfs_event *re, + struct dfs_bin5radars *br); +int dfs_bin5_addpulse(struct ath_dfs *dfs, struct dfs_bin5radars *br, + struct dfs_event *re, uint64_t thists); +int dfs_bin5_check(struct ath_dfs *dfs, int seg_id); +int dfs_check_chirping(struct ath_dfs *dfs, void *buf, + uint16_t datalen, int is_ctl, + int is_ext, int *slope, int *is_dc); +uint8_t dfs_retain_bin5_burst_pattern(struct ath_dfs *dfs, uint32_t diff_ts, + uint8_t old_dur, int seg_id); +uint8_t dfs_retain_bin5_burst_pattern(struct ath_dfs *dfs, uint32_t diff_ts, + uint8_t old_dur, int seg_id); +int dfs_get_random_bin5_dur(struct ath_dfs *dfs, uint64_t tstamp); + +/* Debug prototypes */ +void dfs_print_delayline(struct ath_dfs *dfs, struct dfs_delayline *dl); +void dfs_print_nol(struct ath_dfs *dfs); +void dfs_print_filters(struct ath_dfs *dfs); +void dfs_print_activity(struct ath_dfs *dfs); +os_timer_func(dfs_debug_timeout); +void dfs_print_filter(struct ath_dfs *dfs, struct dfs_filter *rf); + +/* Misc prototypes */ +uint32_t dfs_round(int32_t val); +struct dfs_state *dfs_getchanstate(struct ath_dfs *dfs, uint8_t *index, + int ext_ch_flag); + +/* Reset and init data structures */ + +int dfs_init_radar_filters(struct ieee80211com *ic, + struct ath_dfs_radar_tab_info *radar_info); +void dfs_reset_alldelaylines(struct ath_dfs *dfs, int seg_id); +void dfs_reset_delayline(struct dfs_delayline *dl); +void dfs_reset_radarq(struct ath_dfs *dfs); + +/* Detection algorithm prototypes */ +void dfs_add_pulse(struct ath_dfs *dfs, struct dfs_filter *rf, + struct dfs_event *re, uint32_t deltaT, uint64_t this_ts, + int seg_id); + +int dfs_bin_fixedpattern_check(struct ath_dfs *dfs, struct dfs_filter *rf, + uint32_t dur, int ext_chan_flag, int seg_id); +int dfs_bin_check(struct ath_dfs *dfs, struct dfs_filter *rf, + uint32_t deltaT, uint32_t dur, int ext_chan_flag, int seg_id); + +int dfs_bin_pri_check(struct ath_dfs *dfs, struct dfs_filter *rf, + struct dfs_delayline *dl, uint32_t score, + uint32_t refpri, uint32_t refdur, int ext_chan_flag, + int fundamentalpri); +int dfs_staggered_check(struct ath_dfs *dfs, struct dfs_filter *rf, + uint32_t deltaT, uint32_t width, int seg_id); +/* False detection reduction */ +int dfs_get_pri_margin(struct ath_dfs *dfs, int is_extchan_detect, + int is_fixed_pattern); +int dfs_get_filter_threshold(struct ath_dfs *dfs, struct dfs_filter *rf, + int is_extchan_detect); + +/* AR related prototypes */ + +/* Commenting out since all the ar functions are obsolete and + * the function definition has been removed as part of dfs_ar.c + * void dfs_process_ar_event(struct ath_dfs *dfs, + * struct dfs_ieee80211_channel *chan); + */ +/* Commenting out since all the ar functions are obsolete and + * the function definition has been removed as part of dfs_ar.c + * void ath_ar_disable(struct ath_dfs *dfs); + */ +/* Commenting out since all the ar functions are obsolete and + * the function definition has been removed as part of dfs_ar.c + * void ath_ar_enable(struct ath_dfs *dfs); + */ +void dfs_reset_ar(struct ath_dfs *dfs); +/* Commenting out since all the ar functions are obsolete and + * the function definition has been removed as part of dfs_ar.c + * void dfs_reset_arq(struct ath_dfs *dfs); + */ + +struct dfs_ieee80211_channel *ieee80211_get_extchan(struct ieee80211com *ic); + +#endif /* _DFS_H_ */ diff --git a/drivers/staging/qcacld-3.0/core/sap/dfs/inc/dfs_interface.h b/drivers/staging/qcacld-3.0/core/sap/dfs/inc/dfs_interface.h new file mode 100644 index 0000000000000000000000000000000000000000..e0bbf90bf285987d6d709c0df3253934c20f03b1 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/sap/dfs/inc/dfs_interface.h @@ -0,0 +1,171 @@ +/* + * Copyright (c) 2011-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/*=========================================================================== + + dfs_interface.h + + OVERVIEW: + + Source code borrowed from QCA_MAIN DFS module + + DEPENDENCIES: + + Are listed for each API below. + + ===========================================================================*/ + +#ifndef _DFS__INTERFACE_H_ +#define _DFS__INTERFACE_H_ + +/* + * These are the only functions exported to the upper (device) layer. + */ + +/* + * EXPORT_SYMBOL(dfs_attach); + * EXPORT_SYMBOL(dfs_detach); + * EXPORT_SYMBOL(dfs_radar_enable); + * EXPORT_SYMBOL(dfs_process_phyerr); + * EXPORT_SYMBOL(dfs_control); + * EXPORT_SYMBOL(dfs_clear_stats); + * EXPORT_SYMBOL(dfs_usenol); + * EXPORT_SYMBOL(dfs_isdfsregdomain); + */ + +/* + * These are exported but not currently defined here; these should be + * evaluated. + * + * EXPORT_SYMBOL(dfs_process_ar_event); -- legacy adaptive radio processing + * EXPORT_SYMBOL(ath_ar_disable); + * EXPORT_SYMBOL(ath_ar_enable); + * EXPORT_SYMBOL(dfs_get_thresholds); + * EXPORT_SYMBOL(dfs_init_radar_filters); + * EXPORT_SYMBOL(dfs_getchanstate); + */ +uint16_t dfs_usenol(struct ieee80211com *ic); +uint16_t dfs_isdfsregdomain(struct ieee80211com *ic); +int dfs_attach(struct ieee80211com *ic); +void dfs_detach(struct ieee80211com *ic); +int dfs_radar_enable(struct ieee80211com *ic, + struct ath_dfs_radar_tab_info *ri); +int dfs_radar_disable(struct ieee80211com *ic); +extern void dfs_process_phyerr(struct ieee80211com *ic, void *buf, + uint16_t datalen, uint8_t rssi, uint8_t ext_rssi, + uint32_t rs_tstamp, uint64_t fulltsf, + bool enable_log); +int dfs_control(struct ieee80211com *ic, u_int id, void *indata, + uint32_t insize, void *outdata, uint32_t *outsize); +void dfs_clear_stats(struct ieee80211com *ic); +#if 0 +/* The following are for FCC Bin 1-4 pulses */ +struct dfs_pulse dfs_fcc_radars[] = { + /* FCC TYPE 1 */ + /* {18, 1, 325, 1930, 0, 6, 7, 0, 1, 18, 0, 3, 0}, // 518 to 3066 */ + {18, 1, 700, 700, 0, 6, 5, 0, 1, 18, 0, 3, 1, 0}, + {18, 1, 350, 350, 0, 6, 5, 0, 1, 18, 0, 3, 0, 0}, + + /* FCC TYPE 6 */ + /* {9, 1, 3003, 3003, 1, 7, 5, 0, 1, 18, 0, 0, 1}, // 333 +/- 7 us */ + {9, 1, 3003, 3003, 1, 7, 5, 0, 1, 18, 0, 0, 1, 1}, + + /* FCC TYPE 2 */ + {23, 5, 4347, 6666, 0, 18, 11, 0, 7, 22, 0, 3, 0, 2}, + + /* FCC TYPE 3 */ + {18, 10, 2000, 5000, 0, 23, 8, 6, 13, 22, 0, 3, 0, 5}, + + /* FCC TYPE 4 */ + {16, 15, 2000, 5000, 0, 25, 7, 11, 23, 22, 0, 3, 0, 11}, +}; + +struct dfs_pulse dfs_mkk4_radars[] = { + /* following two filters are specific to Japan/MKK4 */ +/* {18, 1, 720, 720, 1, 6, 6, 0, 1, 18, 0, 3, 17}, // 1389 +/- 6 us */ +/* {18, 4, 250, 250, 1, 10, 5, 1, 6, 18, 0, 3, 18}, // 4000 +/- 6 us */ +/* {18, 5, 260, 260, 1, 10, 6, 1, 6, 18, 0, 3, 19}, // 3846 +/- 7 us */ + {18, 1, 720, 720, 0, 6, 6, 0, 1, 18, 0, 3, 0, 17}, /* 1389 +/- 6 us */ + {18, 4, 250, 250, 0, 10, 5, 1, 6, 18, 0, 3, 0, 18}, /* 4000 +/- 6 us */ + {18, 5, 260, 260, 0, 10, 6, 1, 6, 18, 0, 3, 1, 19}, /* 3846 +/- 7 us */ + + /* following filters are common to both FCC and JAPAN */ + + /* FCC TYPE 1 */ + /* {18, 1, 325, 1930, 0, 6, 7, 0, 1, 18, 0, 3, 0}, // 518 to 3066 */ + {18, 1, 700, 700, 0, 6, 5, 0, 1, 18, 0, 3, 1, 0}, + {18, 1, 350, 350, 0, 6, 5, 0, 1, 18, 0, 3, 0, 0}, + + /* FCC TYPE 6 */ + /* {9, 1, 3003, 3003, 1, 7, 5, 0, 1, 18, 0, 0, 1}, // 333 +/- 7 us */ + {9, 1, 3003, 3003, 1, 7, 5, 0, 1, 18, 0, 0, 1, 1}, + + /* FCC TYPE 2 */ + {23, 5, 4347, 6666, 0, 18, 11, 0, 7, 22, 0, 3, 0, 2}, + + /* FCC TYPE 3 */ + {18, 10, 2000, 5000, 0, 23, 8, 6, 13, 22, 0, 3, 0, 5}, + + /* FCC TYPE 4 */ + {16, 15, 2000, 5000, 0, 25, 7, 11, 23, 22, 0, 3, 0, 11}, +}; + +struct dfs_bin5pulse dfs_fcc_bin5pulses[] = { + {4, 28, 105, 12, 22, 5}, +}; + +struct dfs_bin5pulse dfs_jpn_bin5pulses[] = { + {5, 28, 105, 12, 22, 5}, +}; + +struct dfs_pulse dfs_etsi_radars[] = { + + /* TYPE staggered pulse */ + /* 0.8-2us, 2-3 bursts,300-400 PRF, 10 pulses each */ + {30, 2, 300, 400, 2, 30, 3, 0, 5, 15, 0, 0, 1, 31}, /* Type 5 */ + /* 0.8-2us, 2-3 bursts, 400-1200 PRF, 15 pulses each */ + {30, 2, 400, 1200, 2, 30, 7, 0, 5, 15, 0, 0, 0, 32}, /* Type 6 */ + + /* constant PRF based */ + /* 0.8-5us, 200 300 PRF, 10 pulses */ + {10, 5, 200, 400, 0, 24, 5, 0, 8, 15, 0, 0, 2, 33}, /* Type 1 */ + {10, 5, 400, 600, 0, 24, 5, 0, 8, 15, 0, 0, 2, 37}, /* Type 1 */ + {10, 5, 600, 800, 0, 24, 5, 0, 8, 15, 0, 0, 2, 38}, /* Type 1 */ + {10, 5, 800, 1000, 0, 24, 5, 0, 8, 15, 0, 0, 2, 39}, /* Type 1 */ +/* {10, 5, 200, 1000, 0, 24, 5, 0, 8, 15, 0, 0, 2, 33}, */ + + /* 0.8-15us, 200-1600 PRF, 15 pulses */ + {15, 15, 200, 1600, 0, 24, 8, 0, 18, 24, 0, 0, 0, 34}, /* Type 2 */ + + /* 0.8-15us, 2300-4000 PRF, 25 pulses */ + {25, 15, 2300, 4000, 0, 24, 10, 0, 18, 24, 0, 0, 0, 35}, /* Type 3 */ + + /* 20-30us, 2000-4000 PRF, 20 pulses */ + {20, 30, 2000, 4000, 0, 24, 6, 19, 33, 24, 0, 0, 0, 36}, /* Type 4 */ +}; +#endif +#endif /* _DFS__INTERFACE_H_ */ diff --git a/drivers/staging/qcacld-3.0/core/sap/dfs/inc/radar_filters.h b/drivers/staging/qcacld-3.0/core/sap/dfs/inc/radar_filters.h new file mode 100644 index 0000000000000000000000000000000000000000..0d1b6563ea508e267c94268369b43ddb1660fb4e --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/sap/dfs/inc/radar_filters.h @@ -0,0 +1,195 @@ +/* + * Copyright (c) 2011-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/*=========================================================================== + + radar_filters.h + + OVERVIEW: + + Source code borrowed from QCA_MAIN DFS module + + DEPENDENCIES: + + Are listed for each API below. + + ===========================================================================*/ + +struct dfs_pulse dfs_fcc_radars[] = { + /* FCC NEW TYPE 0 */ + /* {18, 1, 325, 1930, 0, 6, 7, 0, 1, 18, 0, 3, 0}, // 518 to 3066 */ + {18, 1, 700, 700, 0, 6, 5, 0, 1, 18, 0, 3, 1, 0}, + {18, 1, 350, 350, 0, 6, 5, 0, 1, 18, 0, 3, 0, 0}, + + /* FCC TYPE 6 */ + /* {9, 1, 3003, 3003, 1, 7, 5, 0, 1, 18, 0, 0, 1}, // 333 +/- 7 us */ + {9, 1, 3003, 3003, 1, 7, 5, 0, 1, 18, 0, 0, 1, 1}, + + /* FCC TYPE 2 */ + {23, 5, 4347, 6666, 0, 18, 8, 0, 7, 22, 0, 3, 0, 2}, + + /* FCC TYPE 3 */ + {18, 10, 2000, 5000, 0, 23, 6, 6, 13, 22, 0, 3, 0, 5}, + + /* FCC TYPE 4 */ + {16, 15, 2000, 5000, 0, 25, 5, 11, 23, 22, 0, 3, 0, 11}, + + /* + * FCC NEW TYPE 1 + * 518us to 938us pulses (min 56 pulses) + */ + {57, 1, 1066, 1930, 0, 6, 20, 0, 1, 22, 0, 3, 0, 21}, + + /* + * FCC NEW TYPE 1 + * 938us to 2000 pulses (min 26 pulses) + */ + {27, 1, 500, 1066, 0, 6, 13, 0, 1, 22, 0, 3, 0, 22}, + + /* + * FCC NEW TYPE 1 + * 2000 to 3067us pulses (min 17 pulses) + */ + {18, 1, 325, 500, 0, 6, 9, 0, 1, 22, 0, 3, 0, 23}, +}; + +struct dfs_pulse dfs_mkk4_radars[] = { + /* following two filters are specific to Japan/MKK4 */ +/* {18, 1, 720, 720, 1, 6, 6, 0, 1, 18, 0, 3, 17}, // 1389 +/- 6 us */ +/* {18, 4, 250, 250, 1, 10, 5, 1, 6, 18, 0, 3, 18}, // 4000 +/- 6 us */ +/* {18, 5, 260, 260, 1, 10, 6, 1, 6, 18, 0, 3, 19}, // 3846 +/- 7 us */ + {18, 1, 720, 720, 0, 6, 6, 0, 1, 18, 0, 3, 0, 17}, /* 1389 +/- 6 us */ + {18, 4, 250, 250, 0, 10, 5, 1, 6, 18, 0, 3, 0, 18}, /* 4000 +/- 6 us */ + {18, 5, 260, 260, 0, 10, 6, 1, 6, 18, 0, 3, 1, 19}, /* 3846 +/- 7 us */ + + /* following filters are common to both FCC and JAPAN */ + + /* FCC TYPE 1 */ + /* {18, 1, 325, 1930, 0, 6, 7, 0, 1, 18, 0, 3, 0}, // 518 to 3066 */ + {18, 1, 700, 700, 0, 6, 5, 0, 1, 18, 0, 3, 1, 0}, + {18, 1, 350, 350, 0, 6, 5, 0, 1, 18, 0, 3, 0, 0}, + + /* FCC TYPE 6 */ + /* {9, 1, 3003, 3003, 1, 7, 5, 0, 1, 18, 0, 0, 1}, // 333 +/- 7 us */ + {9, 1, 3003, 3003, 1, 7, 5, 0, 1, 18, 0, 0, 1, 1}, + + /* FCC TYPE 2 */ + {23, 5, 4347, 6666, 0, 18, 8, 0, 7, 22, 0, 3, 0, 2}, + + /* FCC TYPE 3 */ + {18, 10, 2000, 5000, 0, 23, 6, 6, 13, 22, 0, 3, 0, 5}, + + /* FCC TYPE 4 */ + {16, 15, 2000, 5000, 0, 25, 5, 11, 23, 22, 0, 3, 0, 11}, +}; + +struct dfs_bin5pulse dfs_fcc_bin5pulses[] = { + {4, 28, 105, 12, 17, 5}, +}; + +struct dfs_bin5pulse dfs_jpn_bin5pulses[] = { + {5, 28, 105, 12, 22, 5}, +}; + +struct dfs_pulse dfs_etsi_radars[] = { + + /* TYPE staggered pulse */ + /* 0.8-2us, 2-3 bursts,300-400 PRF, 10 pulses each */ + {30, 2, 300, 400, 2, 30, 3, 0, 5, 15, 0, 0, 1, 31}, /* Type 5 */ + /* 0.8-2us, 2-3 bursts, 400-1200 PRF, 15 pulses each */ + {30, 2, 400, 1200, 2, 30, 7, 0, 5, 15, 0, 0, 0, 32}, /* Type 6 */ + + /* constant PRF based */ + /* 0.8-5us, 200 300 PRF, 10 pulses */ + {10, 5, 200, 400, 0, 24, 5, 0, 8, 15, 0, 0, 2, 33}, /* Type 1 */ + {10, 5, 400, 600, 0, 24, 5, 0, 8, 15, 0, 0, 2, 37}, /* Type 1 */ + {10, 5, 600, 800, 0, 24, 5, 0, 8, 15, 0, 0, 2, 38}, /* Type 1 */ + {10, 5, 800, 1000, 0, 24, 5, 0, 8, 15, 0, 0, 2, 39}, /* Type 1 */ +/* {10, 5, 200, 1000, 0, 24, 5, 0, 8, 15, 0, 0, 2, 33}, */ + + /* 0.8-15us, 200-1600 PRF, 15 pulses */ + {15, 15, 200, 1600, 0, 24, 8, 0, 18, 22, 0, 0, 0, 34}, /* Type 2 */ + + /* 0.8-15us, 2300-4000 PRF, 25 pulses */ + {25, 15, 2300, 4000, 0, 24, 10, 0, 18, 22, 0, 0, 0, 35}, /* Type 3 */ + + /* 20-30us, 2000-4000 PRF, 20 pulses */ + {20, 30, 2000, 4000, 0, 24, 6, 19, 33, 24, 0, 0, 0, 36}, /* Type 4 */ +}; + +struct dfs_pulse dfs_korea_radars[] = { + /* Korea Type 1 */ + {18, 1, 700, 700, 0, 6, 5, 0, 1, 18, 0, 3, 1, 40}, + + /* Korea Type 2 */ + {10, 1, 1800, 1800, 0, 6, 4, 0, 1, 18, 0, 3, 1, 41}, + + /* Korea Type 3 */ + {70, 1, 330, 330, 0, 6, 20, 0, 2, 18, 0, 3, 1, 42}, + + /* Korea Type 4 */ + {3, 1, 3003, 3003, 1, 7, 2, 0, 1, 18, 0, 0, 1, 43}, +}; + +struct dfs_pulse dfs_china_radars[] = { + /* FCC NEW TYPE 0 */ + {18, 1, 700, 700, 0, 6, 5, 0, 1, 18, 0, 3, 1, 0}, + {18, 1, 350, 350, 0, 6, 5, 0, 1, 18, 0, 3, 0, 0}, + + /* FCC TYPE 6 */ + { 9, 1, 3003, 3003, 1, 7, 5, 0, 1, 18, 0, 0, 1, 1}, + + /* FCC TYPE 2 */ + {23, 5, 4347, 6666, 0, 18, 8, 0, 7, 22, 0, 3, 0, 2}, + + /* FCC TYPE 3 */ + {18, 10, 2000, 5000, 0, 23, 6, 6, 13, 22, 0, 3, 0, 5}, + + /* FCC TYPE 4 */ + {16, 15, 2000, 5000, 0, 25, 5, 11, 23, 22, 0, 3, 0, 11}, + + /* + * FCC NEW TYPE 1 + * 518us to 938us pulses (min 56 pulses) + */ + {57, 1, 1066, 1930, 0, 6, 20, 0, 1, 22, 0, 3, 0, 21}, + + /* + * FCC NEW TYPE 1 + * 938us to 2000 pulses (min 26 pulses) + */ + {27, 1, 500, 1066, 0, 6, 13, 0, 1, 22, 0, 3, 0, 22}, + + /* + * FCC NEW TYPE 1 + * 2000 to 3067us pulses (min 17 pulses) + */ + {18, 1, 325, 500, 0, 6, 9, 0, 1, 22, 0, 3, 0, 23}, + + /* CN TYPE 1 */ + {20, 1, 1000, 1000, 0, 6, 5, 0, 1, 18, 0, 3, 1, 24}, +}; diff --git a/drivers/staging/qcacld-3.0/core/sap/dfs/sources b/drivers/staging/qcacld-3.0/core/sap/dfs/sources new file mode 100644 index 0000000000000000000000000000000000000000..3899f4156c92deb45dfa53858173f6c6b70e9502 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/sap/dfs/sources @@ -0,0 +1,62 @@ +# +# sources file for DFS module +# +LMAC=.. +TOP=$(LMAC)\.. +INC=$(TOP)\include +HAL=$(TOP)\hal +ATH=$(LMAC)\ath_dev + +!IFDEF BUILD_UMAC +MP=$(TOP)\os\win_nwf +INC_MP=$(MP)\include +IF_ATH=$(TOP)\umac\if_lmac +!ELSE +MP=$(TOP)\winvista +INC_MP=$(INC)\winvista +IF_ATH=$(TOP)\if_ath_net80211 +!ENDIF + +!include $(INC_MP)\sources.inc + +TARGETNAME=ath_dfs +TARGETPATH=$(TOP)\lib +TARGETTYPE=LIBRARY + +!IFDEF BUILD_HTC +# Put htc include dirs at the head of the list. +# This ensures that the htc/cdf header files will preempt any +# header files of the same names from the regular cdf directories. +INCLUDES= $(INCLUDES) \ + $(TOP)\htc\inc; \ + $(TOP)\htc\adf\include; \ + $(TOP)\htc\adf\winvista\nbuf; \ + $(TOP)\htc\adf\winvista\include; +!ENDIF + +INCLUDES= $(INCLUDES) \ + $(TOP); \ + $(ATH); \ + $(ATH_DFS); \ + $(TOP)\ath\winvista; \ + $(TOP)\ath\winvista; \ + $(HAL); \ + $(HAL)\winvista; \ + $(IF_ATH); \ + $(INC); \ + $(INC_MP); \ + $(SDXROOT)\net\inc; \ + $(DDK_INC_PATH) + +SOURCES=$(SOURCES) \ + dfs_staggered.c \ + dfs_bindetects.c \ + dfs_misc.c \ + dfs_debug.c \ + dfs_process_radarevent.c \ + dfs_process_phyerr.c \ + dfs_nol.c \ + dfs_ar.c \ + dfs_fcc_bin5.c \ + dfs_init.c \ + dfs.c diff --git a/drivers/staging/qcacld-3.0/core/sap/dfs/src/dfs.c b/drivers/staging/qcacld-3.0/core/sap/dfs/src/dfs.c new file mode 100644 index 0000000000000000000000000000000000000000..a19d946b8058871f99796d601a7c05e269867114 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/sap/dfs/src/dfs.c @@ -0,0 +1,1030 @@ +/* + * Copyright (c) 2002-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/*=========================================================================== + + dfs.c + + OVERVIEW: + + Source code borrowed from QCA_MAIN DFS module + + DEPENDENCIES: + + Are listed for each API below. + + ===========================================================================*/ + +/*=========================================================================== + + EDIT HISTORY FOR FILE + + This section contains comments describing changes made to the module. + Notice that changes are listed in reverse chronological order. + + when who what, where, why + ---------- --- -------------------------------------------------------- + + ===========================================================================*/ + +#include + +#ifndef ATH_SUPPORT_DFS +#define ATH_SUPPORT_DFS 1 + +/* #include "if_athioctl.h" */ +/* #include "if_athvar.h" */ +#include "dfs_ioctl.h" +#include "dfs.h" + +int domainoverride = DFS_UNINIT_REGION; +static struct ath_dfs global_dfs; +static struct dfs_event global_dfs_event[DFS_MAX_EVENTS]; +static struct dfs_pulseline global_dfs_pulseline; +static struct dfs_pulseline global_dfs_pulseline_ext; + +/* +** channel switch announcement (CSA) +** usenol=1 (default) make CSA and switch to a new channel on radar detect +** usenol=0, make CSA with next channel same as current on radar detect +** usenol=2, no CSA and stay on the same channel on radar detect +**/ + +int usenol = 1; +uint32_t dfs_debug_level = ATH_DEBUG_DFS; + +#if 0 /* the code to call this is curently commented-out below */ +/* + * Mark a channel as having interference detected upon it. + * + * This adds the interference marker to both the primary and + * extension channel. + * + * XXX TODO: make the NOL and channel interference logic a bit smarter + * so only the channel with the radar event is marked, rather than + * both the primary and extension. + */ +static void +dfs_channel_mark_radar(struct ath_dfs *dfs, struct dfs_ieee80211_channel *chan) +{ + struct ieee80211_channel_list chan_info; + int i; + + /* chan->ic_flagext |= CHANNEL_INTERFERENCE; */ + + /* + * If radar is detected in 40MHz mode, add both the primary and the + * extension channels to the NOL. chan is the channel data we return + * to the ath_dev layer which passes it on to the 80211 layer. + * As we want the AP to change channels and send out a CSA, + * we always pass back the primary channel data to the ath_dev layer. + */ + if ((dfs->dfs_rinfo.rn_use_nol == 1) && + (dfs->ic->ic_opmode == IEEE80211_M_HOSTAP || + dfs->ic->ic_opmode == IEEE80211_M_IBSS)) { + chan_info.cl_nchans = 0; + dfs->ic->ic_get_ext_chan_info(dfs->ic, &chan_info); + + for (i = 0; i < chan_info.cl_nchans; i++) { + if (chan_info.cl_channels[i] == NULL) { + DFS_PRINTK("%s: NULL channel\n", __func__); + } else { + chan_info.cl_channels[i]->ic_flagext |= + CHANNEL_INTERFERENCE; + dfs_nol_addchan(dfs, chan_info.cl_channels[i], + dfs->ath_dfs_nol_timeout); + } + } + + /* + * Update the umac/driver channels with the new NOL information. + */ + dfs_nol_update(dfs); + } +} +#endif /* #if 0 */ + +static os_timer_func(dfs_task) +{ + struct ieee80211com *ic; + struct ath_dfs *dfs = NULL; + + OS_GET_TIMER_ARG(ic, struct ieee80211com *); + dfs = (struct ath_dfs *)ic->ic_dfs; + /* + * XXX no locking?! + */ + if (dfs_process_radarevent(dfs, ic->ic_curchan)) { +#ifndef ATH_DFS_RADAR_DETECTION_ONLY + + /* + * This marks the channel (and the extension channel, if HT40) as + * having seen a radar event. It marks CHAN_INTERFERENCE and + * will add it to the local NOL implementation. + * + * This is only done for 'usenol=1', as the other two modes + * don't do radar notification or CAC/CSA/NOL; it just notes + * there was a radar. + */ + + if (dfs->dfs_rinfo.rn_use_nol == 1) { + /* dfs_channel_mark_radar(dfs, ic->ic_curchan); */ + } +#endif /* ATH_DFS_RADAR_DETECTION_ONLY */ + + /* + * This calls into the umac DFS code, which sets the umac related + * radar flags and begins the channel change machinery. + * + * XXX TODO: the umac NOL code isn't used, but IEEE80211_CHAN_RADAR + * still gets set. Since the umac NOL code isn't used, that flag + * is never cleared. This needs to be fixed. See EV 105776. + */ + if (dfs->dfs_rinfo.rn_use_nol == 1) { + ic->ic_dfs_notify_radar(ic, ic->ic_curchan); + } else if (dfs->dfs_rinfo.rn_use_nol == 0) { + /* + * For the test mode, don't do a CSA here; but setup the + * test timer so we get a CSA _back_ to the original channel. + */ + OS_CANCEL_TIMER(&dfs->ath_dfstesttimer); + dfs->ath_dfstest = 1; + qdf_spin_lock_bh(&ic->chan_lock); + dfs->ath_dfstest_ieeechan = ic->ic_curchan->ic_ieee; + qdf_spin_unlock_bh(&ic->chan_lock); + dfs->ath_dfstesttime = 1; /* 1ms */ + OS_SET_TIMER(&dfs->ath_dfstesttimer, + dfs->ath_dfstesttime); + } + } + dfs->ath_radar_tasksched = 0; +} + +static os_timer_func(dfs_testtimer_task) +{ + struct ieee80211com *ic; + struct ath_dfs *dfs = NULL; + + OS_GET_TIMER_ARG(ic, struct ieee80211com *); + dfs = (struct ath_dfs *)ic->ic_dfs; + + /* XXX no locking? */ + dfs->ath_dfstest = 0; + + /* + * Flip the channel back to the original channel. + * Make sure this is done properly with a CSA. + */ + DFS_PRINTK("%s: go back to channel %d\n", + __func__, dfs->ath_dfstest_ieeechan); + + /* + * XXX The mere existence of this method indirection + * to a umac function means this code belongs in + * the driver, _not_ here. Please fix this! + */ + ic->ic_start_csa(ic, dfs->ath_dfstest_ieeechan); +} + +static int dfs_get_debug_info(struct ieee80211com *ic, int type, void *data) +{ + struct ath_dfs *dfs = (struct ath_dfs *)ic->ic_dfs; + if (data) { + *(uint32_t *) data = dfs->dfs_proc_phyerr; + } + return (int)dfs->dfs_proc_phyerr; +} + +/** + * dfs_alloc_mem_filter() - allocate memory for dfs ft_filters + * @radarf: pointer holding ft_filters + * + * Return: 0-success and 1-failure +*/ +static int dfs_alloc_mem_filter(struct dfs_filtertype *radarf) +{ + int status = 0, n, i; + + for (i = 0; i < DFS_MAX_NUM_RADAR_FILTERS; i++) { + radarf->ft_filters[i] = qdf_mem_malloc(sizeof(struct + dfs_filter)); + if (NULL == radarf->ft_filters[i]) { + DFS_PRINTK("%s[%d]: mem alloc failed\n", + __func__, __LINE__); + status = 1; + goto error; + } + } + + return status; + +error: + /* free up allocated memory */ + for (n = 0; n < i; n++) { + if (radarf->ft_filters[n]) { + qdf_mem_free(radarf->ft_filters[n]); + radarf->ft_filters[i] = NULL; + } + } + + DFS_PRINTK("%s[%d]: cannot allocate memory for radar filter types\n", + __func__, __LINE__); + + return status; +} + +/** + * dfs_free_filter() - free memory allocated for dfs ft_filters + * @radarf: pointer holding ft_filters + * + * Return: NA +*/ +static void dfs_free_filter(struct dfs_filtertype *radarf) +{ + int i; + + for (i = 0; i < DFS_MAX_NUM_RADAR_FILTERS; i++) { + if (radarf->ft_filters[i]) { + qdf_mem_free(radarf->ft_filters[i]); + radarf->ft_filters[i] = NULL; + } + } +} + +int dfs_attach(struct ieee80211com *ic) +{ + int i, n; + struct ath_dfs *dfs = &global_dfs; + struct ath_dfs_radar_tab_info radar_info; + + OS_MEMZERO(dfs, sizeof(struct ath_dfs)); + ic->ic_dfs = (void *)dfs; + dfs->ic = ic; + ic->ic_dfs_debug = dfs_get_debug_info; +#ifndef ATH_DFS_RADAR_DETECTION_ONLY + dfs->dfs_nol = NULL; +#endif + + /* + * Zero out radar_info. It's possible that the attach function won't + * fetch an initial regulatory configuration; you really do want to + * ensure that the contents indicates there aren't any filters. + */ + OS_MEMZERO(&radar_info, sizeof(radar_info)); + ic->ic_dfs_attach(ic, &dfs->dfs_caps, &radar_info); + dfs_clear_stats(ic); + dfs->dfs_event_log_on = 0; + OS_INIT_TIMER(NULL, &(dfs->ath_dfs_task_timer), dfs_task, (void *)(ic), + QDF_TIMER_TYPE_SW); +#ifndef ATH_DFS_RADAR_DETECTION_ONLY + OS_INIT_TIMER(NULL, &(dfs->ath_dfstesttimer), dfs_testtimer_task, + (void *)ic, QDF_TIMER_TYPE_SW); + dfs->ath_dfs_cac_time = ATH_DFS_WAIT_MS; + dfs->ath_dfstesttime = ATH_DFS_TEST_RETURN_PERIOD_MS; +#endif + ATH_DFSQ_LOCK_INIT(dfs); + STAILQ_INIT(&dfs->dfs_radarq); + ATH_ARQ_LOCK_INIT(dfs); + STAILQ_INIT(&dfs->dfs_arq); + STAILQ_INIT(&(dfs->dfs_eventq)); + ATH_DFSEVENTQ_LOCK_INIT(dfs); + dfs->events = global_dfs_event; + dfs->pulses = &global_dfs_pulseline; + dfs->pulses->pl_lastelem = DFS_MAX_PULSE_BUFFER_MASK; + + for (i = 0; i < DFS_MAX_EVENTS; i++) { + STAILQ_INSERT_TAIL(&(dfs->dfs_eventq), &dfs->events[i], + re_list); + } + + /* + * If the chip supports DFS-3 then allocate + * memory for pulses for extension segment. + */ + if (ic->dfs_hw_bd_id != DFS_HWBD_QCA6174) { + dfs->pulses_ext_seg = &global_dfs_pulseline_ext; + dfs->pulses_ext_seg->pl_lastelem = DFS_MAX_PULSE_BUFFER_MASK; + } + + /* Allocate memory for radar filters */ + for (n = 0; n < DFS_MAX_RADAR_TYPES; n++) { + dfs->dfs_radarf[n] = (struct dfs_filtertype *) + os_malloc(NULL, sizeof(struct dfs_filtertype), + GFP_ATOMIC); + if (dfs->dfs_radarf[n] == NULL) { + DFS_PRINTK + ("%s: cannot allocate memory for radar filter types\n", + __func__); + goto bad1; + } else { + qdf_mem_zero(dfs->dfs_radarf[n], + sizeof(struct dfs_filtertype)); + if (0 != dfs_alloc_mem_filter(dfs->dfs_radarf[n])) + goto bad1; + } + } + /* Allocate memory for radar table */ + dfs->dfs_radartable = + (int8_t **) os_malloc(NULL, + MAX_DFS_RADAR_TABLE_TYPE * sizeof(int8_t *), GFP_ATOMIC); + if (dfs->dfs_radartable == NULL) { + DFS_PRINTK("%s: cannot allocate memory for radar table\n", + __func__); + goto bad1; + } + for (n = 0; n < MAX_DFS_RADAR_TABLE_TYPE; n++) { + dfs->dfs_radartable[n] = + os_malloc(NULL, DFS_MAX_RADAR_OVERLAP * sizeof(int8_t), + GFP_ATOMIC); + if (dfs->dfs_radartable[n] == NULL) { + DFS_PRINTK + ("%s: cannot allocate memory for radar table entry\n", + __func__); + goto bad2; + } + } + + if (usenol == 0) + DFS_PRINTK("%s: NOL disabled\n", __func__); + else if (usenol == 2) + DFS_PRINTK("%s: NOL disabled; no CSA\n", __func__); + + dfs->dfs_rinfo.rn_use_nol = usenol; + + /* Init the cached extension channel busy for false alarm reduction */ + dfs->dfs_rinfo.ext_chan_busy_ts = ic->ic_get_TSF64(ic); + dfs->dfs_rinfo.dfs_ext_chan_busy = 0; + /* Init the Bin5 chirping related data */ + dfs->dfs_rinfo.dfs_bin5_chirp_ts = dfs->dfs_rinfo.ext_chan_busy_ts; + dfs->dfs_rinfo.dfs_last_bin5_dur = MAX_BIN5_DUR; + dfs->dfs_b5radars = NULL; + if (ic->dfs_hw_bd_id != DFS_HWBD_QCA6174) { + dfs->dfs_rinfo.dfs_last_bin5_dur_ext_seg = MAX_BIN5_DUR; + dfs->dfs_b5radars_ext_seg = NULL; + } + + /* + * If dfs_init_radar_filters() fails, we can abort here and + * reconfigure when the first valid channel + radar config + * is available. + */ + if (dfs_init_radar_filters(ic, &radar_info)) { + DFS_PRINTK(" %s: Radar Filter Intialization Failed \n", + __func__); + return 1; + } + + dfs->ath_dfs_false_rssi_thres = RSSI_POSSIBLY_FALSE; + dfs->ath_dfs_peak_mag = SEARCH_FFT_REPORT_PEAK_MAG_THRSH; + dfs->dfs_phyerr_freq_min = 0x7fffffff; + dfs->dfs_phyerr_freq_max = 0; + dfs->dfs_phyerr_queued_count = 0; + dfs->dfs_phyerr_w53_counter = 0; + dfs->dfs_pri_multiplier = 2; + + dfs->ath_dfs_nol_timeout = DFS_NOL_TIMEOUT_S; + return 0; + +bad2: + for (n = 0; n < MAX_DFS_RADAR_TABLE_TYPE; n++) { + if (dfs->dfs_radartable[n] != NULL) { + OS_FREE(dfs->dfs_radartable[n]); + dfs->dfs_radartable[n] = NULL; + } + } + OS_FREE(dfs->dfs_radartable); + dfs->dfs_radartable = NULL; +bad1: + for (n = 0; n < DFS_MAX_RADAR_TYPES; n++) { + if (dfs->dfs_radarf[n] != NULL) { + dfs_free_filter(dfs->dfs_radarf[n]); + OS_FREE(dfs->dfs_radarf[n]); + dfs->dfs_radarf[n] = NULL; + } + } + + ic->ic_dfs = NULL; + return 1; +#undef N +} + +void dfs_detach(struct ieee80211com *ic) +{ + struct ath_dfs *dfs = (struct ath_dfs *)ic->ic_dfs; + int n, empty; + + if (dfs == NULL) { + DFS_DPRINTK(dfs, ATH_DEBUG_DFS1, "%s: ic_dfs is NULL\n", + __func__); + return; + } + + /* Bug 29099 make sure all outstanding timers are cancelled */ + + if (dfs->ath_radar_tasksched) { + OS_CANCEL_TIMER(&dfs->ath_dfs_task_timer); + dfs->ath_radar_tasksched = 0; + } + + if (dfs->ath_dfstest) { + OS_CANCEL_TIMER(&dfs->ath_dfstesttimer); + dfs->ath_dfstest = 0; + } +#if 0 +#ifndef ATH_DFS_RADAR_DETECTION_ONLY + if (dfs->ic_dfswait) { + OS_CANCEL_TIMER(&dfs->ic_dfswaittimer); + dfs->ath_dfswait = 0; + } + + OS_CANCEL_TIMER(&dfs->sc_dfs_war_timer); + if (dfs->dfs_nol != NULL) { + struct dfs_nolelem *nol, *next; + nol = dfs->dfs_nol; + /* Bug 29099 - each NOL element has its own timer, cancel it and + free the element */ + while (nol != NULL) { + OS_CANCEL_TIMER(&nol->nol_timer); + next = nol->nol_next; + OS_FREE(nol); + nol = next; + } + dfs->dfs_nol = NULL; + } +#endif +#endif + + /* Return radar events to free q */ + dfs_reset_radarq(dfs); + dfs_reset_alldelaylines(dfs, DFS_80P80_SEG0); + if (ic->dfs_hw_bd_id != DFS_HWBD_QCA6174) + dfs_reset_alldelaylines(dfs, DFS_80P80_SEG1); + + for (n = 0; n < DFS_MAX_RADAR_TYPES; n++) { + if (dfs->dfs_radarf[n] != NULL) { + dfs_free_filter(dfs->dfs_radarf[n]); + OS_FREE(dfs->dfs_radarf[n]); + dfs->dfs_radarf[n] = NULL; + } + } + + if (dfs->dfs_radartable != NULL) { + for (n = 0; n < MAX_DFS_RADAR_TABLE_TYPE; n++) { + if (dfs->dfs_radartable[n] != NULL) { + OS_FREE(dfs->dfs_radartable[n]); + dfs->dfs_radartable[n] = NULL; + } + } + OS_FREE(dfs->dfs_radartable); + dfs->dfs_radartable = NULL; +#ifndef ATH_DFS_RADAR_DETECTION_ONLY + dfs->ath_dfs_isdfsregdomain = 0; +#endif + } + + if (dfs->dfs_b5radars != NULL) { + OS_FREE(dfs->dfs_b5radars); + dfs->dfs_b5radars = NULL; + } + if (dfs->dfs_b5radars_ext_seg != NULL) { + OS_FREE(dfs->dfs_b5radars_ext_seg); + dfs->dfs_b5radars_ext_seg = NULL; + } + +/* Commenting out since all the ar functions are obsolete and + * the function definition has been removed as part of dfs_ar.c + * dfs_reset_ar(dfs); + */ + ATH_ARQ_LOCK(dfs); + empty = STAILQ_EMPTY(&(dfs->dfs_arq)); + ATH_ARQ_UNLOCK(dfs); + if (!empty) { +/* + * Commenting out since all the ar functions are obsolete and + * the function definition has been removed as part of dfs_ar.c + * + * dfs_reset_arq(dfs); + */ + } + dfs_nol_timer_cleanup(dfs); + + /* XXX? */ + ic->ic_dfs = NULL; +} + +/* + * This is called each time a channel change occurs, to (potentially) enable + * the radar code. + */ +int dfs_radar_disable(struct ieee80211com *ic) +{ + struct ath_dfs *dfs = (struct ath_dfs *)ic->ic_dfs; +#ifdef ATH_ENABLE_AR + dfs->dfs_proc_phyerr &= ~DFS_AR_EN; +#endif + dfs->dfs_proc_phyerr &= ~DFS_RADAR_EN; + return 0; +} + +/* + * This is called each time a channel change occurs, to (potentially) enable + * the radar code. + */ +int dfs_radar_enable(struct ieee80211com *ic, + struct ath_dfs_radar_tab_info *radar_info) +{ + int is_ext_ch; + int is_fastclk = 0; + int radar_filters_init_status = 0; + /* uint32_t rfilt; */ + struct ath_dfs *dfs; + struct dfs_state *rs_pri, *rs_ext; + struct dfs_ieee80211_channel *chan = ic->ic_curchan, *ext_ch = NULL; + + dfs = (struct ath_dfs *)ic->ic_dfs; + rs_pri = NULL; + rs_ext = NULL; + if (dfs == NULL) { + DFS_DPRINTK(dfs, ATH_DEBUG_DFS, "%s: ic_dfs is NULL\n", + __func__); + + return -EIO; + } + ic->ic_dfs_disable(ic); + + /* + * Setting country code might change the DFS domain + * so initialize the DFS Radar filters + */ + radar_filters_init_status = dfs_init_radar_filters(ic, radar_info); + + /* + * dfs_init_radar_filters() returns 1 on failure and + * 0 on success. + */ + if (DFS_STATUS_FAIL == radar_filters_init_status) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s[%d]: DFS Radar Filters Initialization Failed", + __func__, __LINE__); + return -EIO; + } + + if ((ic->ic_opmode == IEEE80211_M_HOSTAP + || ic->ic_opmode == IEEE80211_M_IBSS)) { + + qdf_spin_lock_bh(&ic->chan_lock); + is_ext_ch = IEEE80211_IS_CHAN_11N_HT40(ic->ic_curchan); + if (IEEE80211_IS_CHAN_DFS(chan)) { + + uint8_t index_pri, index_ext; +#ifdef ATH_ENABLE_AR + dfs->dfs_proc_phyerr |= DFS_AR_EN; +#endif + dfs->dfs_proc_phyerr |= DFS_RADAR_EN; + + if (is_ext_ch) { + ext_ch = ieee80211_get_extchan(ic); + } + dfs_reset_alldelaylines(dfs, DFS_80P80_SEG0); + /* + * Extension segment delaylines will be + * enabled only when SAP operates in 80p80 + * and both the channels are DFS. + */ + if (chan->ic_80p80_both_dfs) + dfs_reset_alldelaylines(dfs, DFS_80P80_SEG1); + + rs_pri = dfs_getchanstate(dfs, &index_pri, 0); + if (ext_ch) { + rs_ext = dfs_getchanstate(dfs, &index_ext, 1); + } + if (rs_pri != NULL + && ((ext_ch == NULL) || (rs_ext != NULL))) { + struct ath_dfs_phyerr_param pe; + + OS_MEMSET(&pe, '\0', sizeof(pe)); + + dfs->dfs_curchan_radindex = (int16_t) index_pri; + dfs->dfs_pri_multiplier_ini = + radar_info->dfs_pri_multiplier; + + if (rs_ext) + dfs->dfs_extchan_radindex = + (int16_t) index_ext; + + qdf_spin_unlock_bh(&ic->chan_lock); + ath_dfs_phyerr_param_copy(&pe, + &rs_pri->rs_param); + DFS_DPRINTK(dfs, ATH_DEBUG_DFS3, + "%s: firpwr=%d, rssi=%d, height=%d, " + "prssi=%d, inband=%d, relpwr=%d, " + "relstep=%d, maxlen=%d\n", + __func__, + pe.pe_firpwr, + pe.pe_rrssi, + pe.pe_height, + pe.pe_prssi, + pe.pe_inband, + pe.pe_relpwr, + pe.pe_relstep, pe.pe_maxlen); + + ic->ic_dfs_enable(ic, &is_fastclk, &pe); + DFS_DPRINTK(dfs, ATH_DEBUG_DFS, + "Enabled radar detection on channel %d\n", + chan->ic_freq); + dfs->dur_multiplier = + is_fastclk ? DFS_FAST_CLOCK_MULTIPLIER : + DFS_NO_FAST_CLOCK_MULTIPLIER; + DFS_DPRINTK(dfs, ATH_DEBUG_DFS3, + "%s: duration multiplier is %d\n", + __func__, dfs->dur_multiplier); + } else { + qdf_spin_unlock_bh(&ic->chan_lock); + DFS_DPRINTK(dfs, ATH_DEBUG_DFS, + "%s: No more radar states left\n", + __func__); + } + } else + qdf_spin_unlock_bh(&ic->chan_lock); + } + + return DFS_STATUS_SUCCESS; +} + +int +dfs_control(struct ieee80211com *ic, u_int id, + void *indata, uint32_t insize, void *outdata, uint32_t *outsize) +{ + int error = 0; + struct ath_dfs_phyerr_param peout; + struct ath_dfs *dfs = (struct ath_dfs *)ic->ic_dfs; + struct dfs_ioctl_params *dfsparams; + uint32_t val = 0; +#ifndef ATH_DFS_RADAR_DETECTION_ONLY + struct dfsreq_nolinfo *nol; + uint32_t *data = NULL; +#endif /* ATH_DFS_RADAR_DETECTION_ONLY */ + int i; + + if (dfs == NULL) { + error = -EINVAL; + DFS_DPRINTK(dfs, ATH_DEBUG_DFS1, "%s DFS is null\n", __func__); + goto bad; + } + + switch (id) { + case DFS_SET_THRESH: + if (insize < sizeof(struct dfs_ioctl_params) || !indata) { + DFS_DPRINTK(dfs, ATH_DEBUG_DFS1, + "%s: insize=%d, expected=%zu bytes, indata=%p\n", + __func__, insize, + sizeof(struct dfs_ioctl_params), indata); + error = -EINVAL; + break; + } + dfsparams = (struct dfs_ioctl_params *)indata; + if (!dfs_set_thresholds + (ic, DFS_PARAM_FIRPWR, dfsparams->dfs_firpwr)) + error = -EINVAL; + if (!dfs_set_thresholds + (ic, DFS_PARAM_RRSSI, dfsparams->dfs_rrssi)) + error = -EINVAL; + if (!dfs_set_thresholds + (ic, DFS_PARAM_HEIGHT, dfsparams->dfs_height)) + error = -EINVAL; + if (!dfs_set_thresholds + (ic, DFS_PARAM_PRSSI, dfsparams->dfs_prssi)) + error = -EINVAL; + if (!dfs_set_thresholds + (ic, DFS_PARAM_INBAND, dfsparams->dfs_inband)) + error = -EINVAL; + /* 5413 speicfic */ + if (!dfs_set_thresholds + (ic, DFS_PARAM_RELPWR, dfsparams->dfs_relpwr)) + error = -EINVAL; + if (!dfs_set_thresholds + (ic, DFS_PARAM_RELSTEP, dfsparams->dfs_relstep)) + error = -EINVAL; + if (!dfs_set_thresholds + (ic, DFS_PARAM_MAXLEN, dfsparams->dfs_maxlen)) + error = -EINVAL; + break; + case DFS_GET_THRESH: + if (!outdata || !outsize + || *outsize < sizeof(struct dfs_ioctl_params)) { + error = -EINVAL; + break; + } + *outsize = sizeof(struct dfs_ioctl_params); + dfsparams = (struct dfs_ioctl_params *)outdata; + + /* + * Fetch the DFS thresholds using the internal representation. + */ + (void)dfs_get_thresholds(ic, &peout); + + /* + * Convert them to the dfs IOCTL representation. + */ + ath_dfs_dfsparam_to_ioctlparam(&peout, dfsparams); + break; + case DFS_RADARDETECTS: + if (!outdata || !outsize || *outsize < sizeof(uint32_t)) { + error = -EINVAL; + break; + } + *outsize = sizeof(uint32_t); + *((uint32_t *) outdata) = dfs->ath_dfs_stats.num_radar_detects; + break; + case DFS_DISABLE_DETECT: + dfs->dfs_proc_phyerr &= ~DFS_RADAR_EN; + dfs->ic->ic_dfs_state.ignore_dfs = 1; + DFS_PRINTK("%s enable detects, ignore_dfs %d\n", + __func__, dfs->ic->ic_dfs_state.ignore_dfs); + break; + case DFS_ENABLE_DETECT: + dfs->dfs_proc_phyerr |= DFS_RADAR_EN; + dfs->ic->ic_dfs_state.ignore_dfs = 0; + DFS_PRINTK("%s enable detects, ignore_dfs %d\n", + __func__, dfs->ic->ic_dfs_state.ignore_dfs); + break; + case DFS_DISABLE_FFT: + /* UMACDFS: TODO: val = ath_hal_dfs_config_fft(sc->sc_ah, false); */ + DFS_PRINTK("%s TODO disable FFT val=0x%x \n", __func__, val); + break; + case DFS_ENABLE_FFT: + /* UMACDFS TODO: val = ath_hal_dfs_config_fft(sc->sc_ah, true); */ + DFS_PRINTK("%s TODO enable FFT val=0x%x \n", __func__, val); + break; + case DFS_SET_DEBUG_LEVEL: + if (insize < sizeof(uint32_t) || !indata) { + error = -EINVAL; + break; + } + dfs->dfs_debug_mask = *(uint32_t *) indata; + DFS_PRINTK("%s debug level now = 0x%x \n", + __func__, dfs->dfs_debug_mask); + if (dfs->dfs_debug_mask & ATH_DEBUG_DFS3) { + /* Enable debug Radar Event */ + dfs->dfs_event_log_on = 1; + } else { + dfs->dfs_event_log_on = 0; + } + break; + case DFS_SET_FALSE_RSSI_THRES: + if (insize < sizeof(uint32_t) || !indata) { + error = -EINVAL; + break; + } + dfs->ath_dfs_false_rssi_thres = *(uint32_t *) indata; + DFS_PRINTK("%s false RSSI threshold now = 0x%x \n", + __func__, dfs->ath_dfs_false_rssi_thres); + break; + case DFS_SET_PEAK_MAG: + if (insize < sizeof(uint32_t) || !indata) { + error = -EINVAL; + break; + } + dfs->ath_dfs_peak_mag = *(uint32_t *) indata; + DFS_PRINTK("%s peak_mag now = 0x%x \n", + __func__, dfs->ath_dfs_peak_mag); + break; + case DFS_IGNORE_CAC: + if (insize < sizeof(uint32_t) || !indata) { + error = -EINVAL; + break; + } + if (*(uint32_t *) indata) { + dfs->ic->ic_dfs_state.ignore_cac = 1; + } else { + dfs->ic->ic_dfs_state.ignore_cac = 0; + } + DFS_PRINTK("%s ignore cac = 0x%x \n", + __func__, dfs->ic->ic_dfs_state.ignore_cac); + break; + case DFS_SET_NOL_TIMEOUT: + if (insize < sizeof(uint32_t) || !indata) { + error = -EINVAL; + break; + } + if (*(int *)indata) { + dfs->ath_dfs_nol_timeout = *(int *)indata; + } else { + dfs->ath_dfs_nol_timeout = DFS_NOL_TIMEOUT_S; + } + DFS_PRINTK("%s nol timeout = %d sec \n", + __func__, dfs->ath_dfs_nol_timeout); + break; +#ifndef ATH_DFS_RADAR_DETECTION_ONLY + case DFS_MUTE_TIME: + if (insize < sizeof(uint32_t) || !indata) { + error = -EINVAL; + break; + } + data = (uint32_t *) indata; + dfs->ath_dfstesttime = *data; + dfs->ath_dfstesttime *= (1000); /* convert sec into ms */ + break; + case DFS_GET_USENOL: + if (!outdata || !outsize || *outsize < sizeof(uint32_t)) { + error = -EINVAL; + break; + } + *outsize = sizeof(uint32_t); + *((uint32_t *) outdata) = dfs->dfs_rinfo.rn_use_nol; + + for (i = 0; + (i < DFS_EVENT_LOG_SIZE) && (i < dfs->dfs_event_log_count); + i++) { + /* DFS_DPRINTK(sc, ATH_DEBUG_DFS,"ts=%llu diff_ts=%u rssi=%u dur=%u\n", dfs->radar_log[i].ts, dfs->radar_log[i].diff_ts, dfs->radar_log[i].rssi, dfs->radar_log[i].dur); */ + + } + dfs->dfs_event_log_count = 0; + dfs->dfs_phyerr_count = 0; + dfs->dfs_phyerr_reject_count = 0; + dfs->dfs_phyerr_queued_count = 0; + dfs->dfs_phyerr_freq_min = 0x7fffffff; + dfs->dfs_phyerr_freq_max = 0; + break; + case DFS_SET_USENOL: + if (insize < sizeof(uint32_t) || !indata) { + error = -EINVAL; + break; + } + dfs->dfs_rinfo.rn_use_nol = *(uint32_t *) indata; + /* iwpriv markdfs in linux can do the same thing... */ + break; + case DFS_GET_NOL: + if (!outdata || !outsize + || *outsize < sizeof(struct dfsreq_nolinfo)) { + error = -EINVAL; + break; + } + *outsize = sizeof(struct dfsreq_nolinfo); + nol = (struct dfsreq_nolinfo *)outdata; + dfs_get_nol(dfs, (struct dfsreq_nolelem *)nol->dfs_nol, + &nol->ic_nchans); + dfs_print_nol(dfs); + break; + case DFS_SET_NOL: + if (insize < sizeof(struct dfsreq_nolinfo) || !indata) { + error = -EINVAL; + break; + } + nol = (struct dfsreq_nolinfo *)indata; + dfs_set_nol(dfs, (struct dfsreq_nolelem *)nol->dfs_nol, + nol->ic_nchans); + break; + + case DFS_SHOW_NOL: + dfs_print_nol(dfs); + break; + case DFS_BANGRADAR: +#if 0 /* MERGE_TBD */ + if (sc->sc_nostabeacons) { + printk("No radar detection Enabled \n"); + break; + } +#endif + dfs->dfs_bangradar = 1; + dfs->ath_radar_tasksched = 1; + OS_SET_TIMER(&dfs->ath_dfs_task_timer, 0); + break; +#endif /* ATH_DFS_RADAR_DETECTION_ONLY */ + default: + error = -EINVAL; + } +bad: + return error; +} + +int +dfs_set_thresholds(struct ieee80211com *ic, const uint32_t threshtype, + const uint32_t value) +{ + struct ath_dfs *dfs = (struct ath_dfs *)ic->ic_dfs; + int16_t chanindex; + struct dfs_state *rs; + struct ath_dfs_phyerr_param pe; + int is_fastclk = 0; /* XXX throw-away */ + + if (dfs == NULL) { + DFS_DPRINTK(dfs, ATH_DEBUG_DFS1, "%s: ic_dfs is NULL\n", + __func__); + return 0; + } + + chanindex = dfs->dfs_curchan_radindex; + if ((chanindex < 0) || (chanindex >= DFS_NUM_RADAR_STATES)) { + DFS_DPRINTK(dfs, ATH_DEBUG_DFS1, + "%s: chanindex = %d, DFS_NUM_RADAR_STATES=%d\n", + __func__, chanindex, DFS_NUM_RADAR_STATES); + return 0; + } + + DFS_DPRINTK(dfs, ATH_DEBUG_DFS, + "%s: threshtype=%d, value=%d\n", __func__, threshtype, + value); + + ath_dfs_phyerr_init_noval(&pe); + + rs = &(dfs->dfs_radar[chanindex]); + switch (threshtype) { + case DFS_PARAM_FIRPWR: + rs->rs_param.pe_firpwr = (int32_t) value; + pe.pe_firpwr = value; + break; + case DFS_PARAM_RRSSI: + rs->rs_param.pe_rrssi = value; + pe.pe_rrssi = value; + break; + case DFS_PARAM_HEIGHT: + rs->rs_param.pe_height = value; + pe.pe_height = value; + break; + case DFS_PARAM_PRSSI: + rs->rs_param.pe_prssi = value; + pe.pe_prssi = value; + break; + case DFS_PARAM_INBAND: + rs->rs_param.pe_inband = value; + pe.pe_inband = value; + break; + /* 5413 specific */ + case DFS_PARAM_RELPWR: + rs->rs_param.pe_relpwr = value; + pe.pe_relpwr = value; + break; + case DFS_PARAM_RELSTEP: + rs->rs_param.pe_relstep = value; + pe.pe_relstep = value; + break; + case DFS_PARAM_MAXLEN: + rs->rs_param.pe_maxlen = value; + pe.pe_maxlen = value; + break; + default: + DFS_DPRINTK(dfs, ATH_DEBUG_DFS1, + "%s: unknown threshtype (%d)\n", + __func__, threshtype); + break; + } + + /* + * The driver layer dfs_enable routine is tasked with translating + * values from the global format to the per-device (HAL, offload) + * format. + */ + ic->ic_dfs_enable(ic, &is_fastclk, &pe); + return 1; +} + +int +dfs_get_thresholds(struct ieee80211com *ic, struct ath_dfs_phyerr_param *param) +{ + /* UMACDFS : TODO:ath_hal_getdfsthresh(sc->sc_ah, param); */ + + OS_MEMZERO(param, sizeof(*param)); + + (void)ic->ic_dfs_get_thresholds(ic, param); + + return 1; +} + +uint16_t dfs_usenol(struct ieee80211com *ic) +{ + struct ath_dfs *dfs = (struct ath_dfs *)ic->ic_dfs; + return dfs ? (uint16_t) dfs->dfs_rinfo.rn_use_nol : 0; +} + +uint16_t dfs_isdfsregdomain(struct ieee80211com *ic) +{ + struct ath_dfs *dfs = (struct ath_dfs *)ic->ic_dfs; + return dfs ? dfs->dfsdomain : 0; +} + +#endif /* ATH_UPPORT_DFS */ diff --git a/drivers/staging/qcacld-3.0/core/sap/dfs/src/dfs_bindetects.c b/drivers/staging/qcacld-3.0/core/sap/dfs/src/dfs_bindetects.c new file mode 100644 index 0000000000000000000000000000000000000000..dc3acf6dabd67f2304305151ce87d42cfe11a04a --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/sap/dfs/src/dfs_bindetects.c @@ -0,0 +1,504 @@ +/* + * Copyright (c) 2002-2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/*=========================================================================== + + dfs_bindetects.c + + OVERVIEW: + + Source code borrowed from QCA_MAIN DFS module + + DEPENDENCIES: + + Are listed for each API below. + + ===========================================================================*/ + +/*=========================================================================== + + EDIT HISTORY FOR FILE + + This section contains comments describing changes made to the module. + Notice that changes are listed in reverse chronological order. + + when who what, where, why + ---------- --- -------------------------------------------------------- + + ===========================================================================*/ + +#include "dfs.h" +/*TO DO DFS removing + #include + */ +#ifdef ATH_SUPPORT_DFS + +int +dfs_bin_fixedpattern_check(struct ath_dfs *dfs, struct dfs_filter *rf, + uint32_t dur, int ext_chan_flag, int seg_id) +{ + struct dfs_pulseline *pl; + int i, n, refpri, primargin, numpulses = 0; + uint64_t start_ts, end_ts, event_ts, prev_event_ts, next_event_ts, + window_start, window_end; + uint32_t index, next_index, deltadur; + + if (dfs->ic->ic_curchan->ic_80p80_both_dfs) + pl = (seg_id == 0) ? dfs->pulses : dfs->pulses_ext_seg; + else + pl = dfs->pulses; + + /* For fixed pattern types, rf->rf_patterntype=1 */ + primargin = + dfs_get_pri_margin(dfs, ext_chan_flag, (rf->rf_patterntype == 1)); + + refpri = (rf->rf_minpri + rf->rf_maxpri) / 2; + index = pl->pl_lastelem; + end_ts = pl->pl_elems[index].p_time; + start_ts = end_ts - (refpri * rf->rf_numpulses); + + DFS_DPRINTK(dfs, ATH_DEBUG_DFS3, + "lastelem ts=%llu start_ts=%llu, end_ts=%llu\n", + (unsigned long long)pl->pl_elems[index].p_time, + (unsigned long long)start_ts, (unsigned long long)end_ts); + + /* find the index of first element in our window of interest */ + for (i = 0; i < pl->pl_numelems; i++) { + index = (index - 1) & DFS_MAX_PULSE_BUFFER_MASK; + if (pl->pl_elems[index].p_time >= start_ts) + continue; + else { + index = (index) & DFS_MAX_PULSE_BUFFER_MASK; + break; + } + } + for (n = 0; n <= rf->rf_numpulses; n++) { + window_start = (start_ts + (refpri * n)) - (primargin + n); + window_end = window_start + 2 * (primargin + n); + DFS_DPRINTK(dfs, ATH_DEBUG_DFS2, + "window_start %u window_end %u \n", + (uint32_t) window_start, (uint32_t) window_end); + for (i = 0; i < pl->pl_numelems; i++) { + prev_event_ts = pl->pl_elems[index].p_time; + index = (index + 1) & DFS_MAX_PULSE_BUFFER_MASK; + event_ts = pl->pl_elems[index].p_time; + next_index = (index + 1) & DFS_MAX_PULSE_BUFFER_MASK; + next_event_ts = pl->pl_elems[next_index].p_time; + DFS_DPRINTK(dfs, ATH_DEBUG_DFS2, + "ts %u \n", (uint32_t) event_ts); + if ((event_ts <= window_end) + && (event_ts >= window_start)) { + deltadur = + DFS_DIFF(pl->pl_elems[index].p_dur, dur); + if ((pl->pl_elems[index].p_dur == 1) + || ((dur != 1) && (deltadur <= 2))) { + numpulses++; + DFS_DPRINTK(dfs, ATH_DEBUG_DFS2, + "numpulses %u \n", + numpulses); + break; + } + } else if (event_ts > window_end) { + index = (index - 1) & DFS_MAX_PULSE_BUFFER_MASK; + break; + } else if (event_ts == prev_event_ts) { + if (((next_event_ts - event_ts) > refpri) || + ((next_event_ts - event_ts) == 0)) { + deltadur = + DFS_DIFF(pl->pl_elems[index].p_dur, + dur); + if ((pl->pl_elems[index].p_dur == 1) + || ((pl->pl_elems[index].p_dur != 1) + && (deltadur <= 2))) { + numpulses++; + DFS_DPRINTK(dfs, ATH_DEBUG_DFS2, + "zero PRI: numpulses %u \n", + numpulses); + break; + } + } + } + } + } + if (numpulses >= dfs_get_filter_threshold(dfs, rf, ext_chan_flag)) { + DFS_DPRINTK(dfs, ATH_DEBUG_DFS1, + "%s FOUND filterID=%u numpulses=%d unadj thresh=%d\n", + __func__, rf->rf_pulseid, numpulses, + rf->rf_threshold); + return 1; + } else + return 0; +} + +void +dfs_add_pulse(struct ath_dfs *dfs, struct dfs_filter *rf, struct dfs_event *re, + uint32_t deltaT, uint64_t this_ts, int seg_id) +{ + uint32_t index, n, window; + struct dfs_delayline *dl; + + if (dfs->ic->ic_curchan->ic_80p80_both_dfs) + dl = (seg_id == 0) ? &rf->rf_dl : &rf->rf_dl_ext_seg; + else + dl = &rf->rf_dl; + /* Circular buffer of size 2^n */ + index = (dl->dl_lastelem + 1) & DFS_MAX_DL_MASK; + /* if ((dl->dl_numelems+1) == DFS_MAX_DL_SIZE) */ + if ((dl->dl_numelems) == DFS_MAX_DL_SIZE) + dl->dl_firstelem = (dl->dl_firstelem + 1) & DFS_MAX_DL_MASK; + else + dl->dl_numelems++; + dl->dl_lastelem = index; + dl->dl_elems[index].de_time = deltaT; + dl->dl_elems[index].de_ts = this_ts; + window = deltaT; + dl->dl_elems[index].de_dur = re->re_dur; + dl->dl_elems[index].de_rssi = re->re_rssi; + + DFS_DPRINTK(dfs, ATH_DEBUG_DFS2, + "%s: adding: filter id %d, dur=%d, rssi=%d, ts=%llu\n", + __func__, + rf->rf_pulseid, + re->re_dur, re->re_rssi, (unsigned long long int)this_ts); + + for (n = 0; n < dl->dl_numelems - 1; n++) { + index = (index - 1) & DFS_MAX_DL_MASK; + /* + * calculate window based on full time stamp instead of deltaT + * deltaT (de_time) may result in incorrect window value + */ + window = (uint32_t) (this_ts - dl->dl_elems[index].de_ts); + + if (window > rf->rf_filterlen) { + dl->dl_firstelem = (index + 1) & DFS_MAX_DL_MASK; + dl->dl_numelems = n + 1; + } + } + DFS_DPRINTK(dfs, ATH_DEBUG_DFS2, + "dl firstElem = %d lastElem = %d\n", dl->dl_firstelem, + dl->dl_lastelem); +} + +int +dfs_bin_check(struct ath_dfs *dfs, struct dfs_filter *rf, uint32_t deltaT, + uint32_t width, int ext_chan_flag, int seg_id) +{ + uint32_t refpri, refdur, searchpri, deltapri, deltapri_2, deltapri_3, + averagerefpri; + uint32_t n, i, primargin, durmargin, highscore, highscoreindex; + int score[DFS_MAX_DL_SIZE], delayindex, dindex, found = 0; + struct dfs_delayline *dl; + uint32_t scoreindex, lowpriindex = 0, lowpri = 0xffff; + int numpulses = 0; + int lowprichk = 3, pri_match = 0; + + if (dfs->ic->ic_curchan->ic_80p80_both_dfs) + dl = (seg_id == 0) ? &rf->rf_dl : &rf->rf_dl_ext_seg; + else + dl = &rf->rf_dl; + + if (dl->dl_numelems < (rf->rf_threshold - 1)) { + return 0; + } + if (deltaT > rf->rf_filterlen) + return 0; + + primargin = + dfs_get_pri_margin(dfs, ext_chan_flag, (rf->rf_patterntype == 1)); + + if (rf->rf_maxdur < 10) { + durmargin = 4; + } else { + durmargin = 6; + } + + if (rf->rf_patterntype == 1) { + found = + dfs_bin_fixedpattern_check(dfs, rf, width, + ext_chan_flag, seg_id); + if (found) { + dl->dl_numelems = 0; + } + return found; + } + + OS_MEMZERO(score, sizeof(int) * DFS_MAX_DL_SIZE); + /* find out the lowest pri */ + for (n = 0; n < dl->dl_numelems; n++) { + delayindex = (dl->dl_firstelem + n) & DFS_MAX_DL_MASK; + refpri = dl->dl_elems[delayindex].de_time; + if (refpri == 0) + continue; + else if (refpri < lowpri) { + lowpri = dl->dl_elems[delayindex].de_time; + lowpriindex = n; + } + } + /* find out the each delay element's pri score */ + for (n = 0; n < dl->dl_numelems; n++) { + delayindex = (dl->dl_firstelem + n) & DFS_MAX_DL_MASK; + refpri = dl->dl_elems[delayindex].de_time; + if (refpri == 0) + continue; + if (refpri < rf->rf_maxpri) { /* use only valid PRI range for high score */ + for (i = 0; i < dl->dl_numelems; i++) { + dindex = + (dl->dl_firstelem + i) & DFS_MAX_DL_MASK; + searchpri = dl->dl_elems[dindex].de_time; + deltapri = DFS_DIFF(searchpri, refpri); + deltapri_2 = DFS_DIFF(searchpri, 2 * refpri); + deltapri_3 = DFS_DIFF(searchpri, 3 * refpri); + if (rf->rf_ignore_pri_window == 2) { + pri_match = ((deltapri < primargin) + || (deltapri_2 < primargin) + || (deltapri_3 < + primargin)); + } else { + pri_match = (deltapri < primargin); + } + + if (pri_match) + score[n]++; + } + } else { + score[n] = 0; + } + if (score[n] > rf->rf_threshold) { + /* we got the most possible candidate, + * no need to continue further */ + break; + } + } + /* find out the high scorer */ + highscore = 0; + highscoreindex = 0; + for (n = 0; n < dl->dl_numelems; n++) { + if (score[n] > highscore) { + highscore = score[n]; + highscoreindex = n; + } else if (score[n] == highscore) { + /*more than one pri has highscore take the least pri */ + delayindex = + (dl->dl_firstelem + + highscoreindex) & DFS_MAX_DL_MASK; + dindex = (dl->dl_firstelem + n) & DFS_MAX_DL_MASK; + if (dl->dl_elems[dindex].de_time <= + dl->dl_elems[delayindex].de_time) { + highscoreindex = n; + } + } + } + /* find the average pri of pulses around the pri of highscore or + * the pulses around the lowest pri */ + if (rf->rf_ignore_pri_window > 0) { + lowprichk = (rf->rf_threshold >> 1) + 1; + } else { + lowprichk = 3; + } + + if (highscore < lowprichk) { + scoreindex = lowpriindex; + } else { + scoreindex = highscoreindex; + } + /* We got the possible pri, save its parameters as reference */ + delayindex = (dl->dl_firstelem + scoreindex) & DFS_MAX_DL_MASK; + refdur = dl->dl_elems[delayindex].de_dur; + refpri = dl->dl_elems[delayindex].de_time; + averagerefpri = 0; + + if (rf->rf_fixed_pri_radar_pulse) { + refpri = (rf->rf_minpri + rf->rf_maxpri) / 2; + } + + numpulses = dfs_bin_pri_check(dfs, rf, dl, score[scoreindex], refpri, + refdur, ext_chan_flag, refpri); + if (numpulses >= dfs_get_filter_threshold(dfs, rf, ext_chan_flag)) { + found = 1; + DFS_DPRINTK(dfs, ATH_DEBUG_DFS1, + "ext_flag=%d MATCH filter=%u numpulses=%u thresh=%u refdur=%d refpri=%d primargin=%d\n", + ext_chan_flag, rf->rf_pulseid, numpulses, + rf->rf_threshold, refdur, refpri, primargin); + + if (dfs->ic->ic_curchan->ic_80p80_both_dfs) + dfs_print_delayline(dfs, + (seg_id == 0) ? &rf->rf_dl : &rf->rf_dl_ext_seg); + else + dfs_print_delayline(dfs, &rf->rf_dl); + + dfs_print_filter(dfs, rf); + } + return found; +} + +int +dfs_bin_pri_check(struct ath_dfs *dfs, struct dfs_filter *rf, + struct dfs_delayline *dl, uint32_t score, uint32_t refpri, + uint32_t refdur, int ext_chan_flag, int fundamentalpri) +{ + uint32_t searchpri, searchdur, searchrssi, deltapri = 0, deltapri1 = + 0, deltapri2 = 0, deltadur, averagerefpri = 0, MatchCount = 0; + uint32_t delta_ts_variance, delta_time_stamps, prev_good_timestamp = 0; + int delayindex, dindex; + uint32_t i, j = 0, primargin, durmargin, highscore = + score, highscoreindex = 0; + int numpulses = 1; /* first pulse in the burst is most likely being filtered out based on maxfilterlen */ + int priscorechk = 1, numpulsetochk = 2, primatch = 0; + + /* Use the adjusted PRI margin to reduce false alarms */ + /* For non fixed pattern types, rf->rf_patterntype=0 */ + primargin = + dfs_get_pri_margin(dfs, ext_chan_flag, (rf->rf_patterntype == 1)); + + if ((refpri > rf->rf_maxpri) || (refpri < rf->rf_minpri)) { + numpulses = 0; + return numpulses; + } + + if (rf->rf_maxdur < 10) { + durmargin = 4; + } else { + durmargin = 6; + } + + if ((!rf->rf_fixed_pri_radar_pulse)) { + if (rf->rf_ignore_pri_window == 1) { + priscorechk = (rf->rf_threshold >> 1); + } else { + priscorechk = 1; + } + + MatchCount = 0; + if (score > priscorechk) { + for (i = 0; i < dl->dl_numelems; i++) { + dindex = + (dl->dl_firstelem + i) & DFS_MAX_DL_MASK; + searchpri = dl->dl_elems[dindex].de_time; + deltapri = DFS_DIFF(searchpri, refpri); + if (deltapri < primargin) { + averagerefpri += searchpri; + MatchCount++; + } + } + if (rf->rf_patterntype != 2) { + if (MatchCount > 0) + refpri = (averagerefpri / MatchCount); /* average */ + } else { + refpri = (averagerefpri / score); + } + } + } + /* Note: Following primultiple calculation should be done once per filter + * during initialization stage (dfs_attach) and stored in its array + * atleast for fixed frequency types like FCC Bin1 to save some CPU cycles. + * multiplication, devide operators in the following code are left as it is + * for readability hoping the complier will use left/right shifts wherever possible + */ + DFS_DPRINTK(dfs, ATH_DEBUG_DFS2, + "refpri = %d high score = %d index = %d numpulses = %d\n", + refpri, highscore, highscoreindex, numpulses); + /* Count the other delay elements that have pri and dur with in the + * acceptable range from the reference one */ + for (i = 0; i < dl->dl_numelems; i++) { + delayindex = (dl->dl_firstelem + i) & DFS_MAX_DL_MASK; + searchpri = dl->dl_elems[delayindex].de_time; + if (searchpri == 0) { + /* This events PRI is zero, take it as a + * valid pulse but decrement next event's PRI by refpri + */ + dindex = (delayindex + 1) & DFS_MAX_DL_MASK; + dl->dl_elems[dindex].de_time -= refpri; + searchpri = refpri; + } + searchdur = dl->dl_elems[delayindex].de_dur; + searchrssi = dl->dl_elems[delayindex].de_rssi; + deltadur = DFS_DIFF(searchdur, refdur); + deltapri = DFS_DIFF(searchpri, refpri); + + /* deltapri3 = DFS_DIFF(searchpri, 3 * refpri); */ + primatch = 0; + + if ((rf->rf_ignore_pri_window > 0) && (rf->rf_patterntype != 2)) { + for (j = 0; j < rf->rf_numpulses; j++) { + deltapri1 = + DFS_DIFF(searchpri, (j + 1) * refpri); + if (deltapri1 < (2 * primargin)) { + primatch = 1; + break; + } + } + } else { + if ((deltapri1 < primargin) || (deltapri2 < primargin)) { + primatch = 1; + } + } + + if (primatch && (deltadur < durmargin)) { + if ((numpulses == 1)) { + numpulses++; + } else { + delta_time_stamps = + dl->dl_elems[delayindex].de_ts - + prev_good_timestamp; + if ((rf->rf_ignore_pri_window > 0)) { + numpulsetochk = rf->rf_numpulses; + + if ((rf->rf_patterntype == 2) + && (fundamentalpri < + refpri + 100)) { + numpulsetochk = 4; + } + } else { + numpulsetochk = 4; + } + for (j = 0; j < numpulsetochk; j++) { + delta_ts_variance = + DFS_DIFF(delta_time_stamps, + ((j + + 1) * fundamentalpri)); + if (delta_ts_variance < + (2 * (j + 1) * primargin)) { + numpulses++; + if (rf->rf_ignore_pri_window > + 0) { + break; + } + } + } + } + prev_good_timestamp = dl->dl_elems[delayindex].de_ts; + + DFS_DPRINTK(dfs, ATH_DEBUG_DFS2, + "rf->minpri=%d rf->maxpri=%d searchpri = %d index = %d numpulses = %d deltapri=%d j=%d\n", + rf->rf_minpri, rf->rf_maxpri, searchpri, i, + numpulses, deltapri, j); + } + + } + return numpulses; +} +#endif /* ATH_SUPPORT_DFS */ diff --git a/drivers/staging/qcacld-3.0/core/sap/dfs/src/dfs_debug.c b/drivers/staging/qcacld-3.0/core/sap/dfs/src/dfs_debug.c new file mode 100644 index 0000000000000000000000000000000000000000..1a5aa2be2e989a1e30d3f6a607864c79ccfd2488 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/sap/dfs/src/dfs_debug.c @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2002-2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/*=========================================================================== + + dfs_debug.c + + OVERVIEW: + + Source code borrowed from QCA_MAIN DFS module + + DEPENDENCIES: + + Are listed for each API below. + + ===========================================================================*/ + +/*=========================================================================== + + EDIT HISTORY FOR FILE + + This section contains comments describing changes made to the module. + Notice that changes are listed in reverse chronological order. + + when who what, where, why + ---------- --- -------------------------------------------------------- + + ===========================================================================*/ + +#include "dfs.h" +/* TO DO DFS + #include + */ +#ifdef ATH_SUPPORT_DFS + +void dfs_print_delayline(struct ath_dfs *dfs, struct dfs_delayline *dl) +{ + int i = 0, index; + struct dfs_delayelem *de; + + index = dl->dl_lastelem; + for (i = 0; i < dl->dl_numelems; i++) { + de = &dl->dl_elems[index]; + DFS_DPRINTK(dfs, ATH_DEBUG_DFS2, + "Elem %d: ts = %u (0x%x) dur=%u\n", i, + de->de_time, de->de_time, de->de_dur); + index = (index - 1) & DFS_MAX_DL_MASK; + } +} + +void dfs_print_filter(struct ath_dfs *dfs, struct dfs_filter *rf) +{ + + DFS_DPRINTK(dfs, ATH_DEBUG_DFS1, + "filterID[%d] rf_numpulses=%u; rf->rf_minpri=%u; " + "rf->rf_maxpri=%u; rf->rf_threshold=%u; rf->rf_filterlen=%u; " + "rf->rf_mindur=%u; rf->rf_maxdur=%u\n", + rf->rf_pulseid, + rf->rf_numpulses, + rf->rf_minpri, + rf->rf_maxpri, + rf->rf_threshold, + rf->rf_filterlen, rf->rf_mindur, rf->rf_maxdur); +} + +void dfs_print_filters(struct ath_dfs *dfs) +{ + struct dfs_filtertype *ft = NULL; + struct dfs_filter *rf; + int i, j; + + if (dfs == NULL) { + DFS_DPRINTK(dfs, ATH_DEBUG_DFS, "%s: sc_dfs is NULL\n", + __func__); + return; + } + for (i = 0; i < DFS_MAX_RADAR_TYPES; i++) { + if (dfs->dfs_radarf[i] != NULL) { + ft = dfs->dfs_radarf[i]; + if ((ft->ft_numfilters > DFS_MAX_NUM_RADAR_FILTERS) + || (!ft->ft_numfilters)) + continue; + DFS_PRINTK + ("===========ft->ft_numfilters=%u===========\n", + ft->ft_numfilters); + for (j = 0; j < ft->ft_numfilters; j++) { + rf = ft->ft_filters[j]; + DFS_PRINTK + ("filter[%d] filterID = %d rf_numpulses=%u; rf->rf_minpri=%u; rf->rf_maxpri=%u; rf->rf_threshold=%u; rf->rf_filterlen=%u; rf->rf_mindur=%u; rf->rf_maxdur=%u\n", + j, rf->rf_pulseid, rf->rf_numpulses, + rf->rf_minpri, rf->rf_maxpri, + rf->rf_threshold, rf->rf_filterlen, + rf->rf_mindur, rf->rf_maxdur); + } + } + } +} + +void dfs_print_activity(struct ath_dfs *dfs) +{ + int chan_busy = 0, ext_chan_busy = 0; + uint32_t rxclear = 0, rxframe = 0, txframe = 0, cycles = 0; + + cycles = + dfs->ic->ic_get_mib_cycle_counts_pct(dfs->ic, &rxclear, &rxframe, + &txframe); + chan_busy = cycles; + + ext_chan_busy = dfs->ic->ic_get_ext_busy(dfs->ic); + + DFS_DPRINTK(dfs, ATH_DEBUG_DFS, "cycles=%d rxclear=%d rxframe=%d" + " txframe=%d extchanbusy=%d\n", cycles, rxclear, + rxframe, txframe, ext_chan_busy); + return; +} + +/* + * XXX migrate this to use ath_dfs as the arg, not ieee80211com! + */ +#ifndef ATH_DFS_RADAR_DETECTION_ONLY +os_timer_func(dfs_debug_timeout) +{ + struct ieee80211com *ic; + struct ath_dfs *dfs; + + OS_GET_TIMER_ARG(ic, struct ieee80211com *); + + dfs = (struct ath_dfs *)ic->ic_dfs; + + dfs_print_activity(dfs); + + OS_SET_TIMER(&dfs->ath_dfs_debug_timer, DFS_DEBUG_TIMEOUT_MS); +} +#endif + +#endif /* ATH_SUPPORT_DFS */ diff --git a/drivers/staging/qcacld-3.0/core/sap/dfs/src/dfs_fcc_bin5.c b/drivers/staging/qcacld-3.0/core/sap/dfs/src/dfs_fcc_bin5.c new file mode 100644 index 0000000000000000000000000000000000000000..9d8dd76c5a340385a69be68ad4a1114414b8803f --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/sap/dfs/src/dfs_fcc_bin5.c @@ -0,0 +1,894 @@ +/* + * Copyright (c) 2002-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/*=========================================================================== + + dfs_fcc_bin5.c + + OVERVIEW: + + Source code borrowed from QCA_MAIN DFS module + + DEPENDENCIES: + + Are listed for each API below. + + ===========================================================================*/ + +/*=========================================================================== + + EDIT HISTORY FOR FILE + + This section contains comments describing changes made to the module. + Notice that changes are listed in reverse chronological order. + + when who what, where, why + ---------- --- -------------------------------------------------------- + + ===========================================================================*/ + +#include "dfs.h" +/* TO DO DFS + #include + */ +#ifdef ATH_SUPPORT_DFS + +/* + * Reject the pulse if: + * + It's outside the RSSI threshold; + * + It's outside the pulse duration; + * + It's been verified by HW/SW chirp checking + * and neither of those found a chirp. + */ +int +dfs_bin5_check_pulse(struct ath_dfs *dfs, struct dfs_event *re, + struct dfs_bin5radars *br) +{ + int b5_rssithresh = br->br_pulse.b5_rssithresh; + + DFS_DPRINTK(dfs, ATH_DEBUG_DFS_BIN5_PULSE, + "%s: re_dur=%d, rssi=%d, check_chirp=%d, " + "hw_chirp=%d, sw_chirp=%d\n", + __func__, + (int)re->re_dur, + (int)re->re_rssi, + !!(re->re_flags & DFS_EVENT_CHECKCHIRP), + !!(re->re_flags & DFS_EVENT_HW_CHIRP), + !!(re->re_flags & DFS_EVENT_SW_CHIRP)); + + /* + * If the sw/hw chirp detection says to fail the pulse, + * do so. + */ + if (DFS_EVENT_NOTCHIRP(re)) { + DFS_DPRINTK(dfs, ATH_DEBUG_DFS_BIN5, + "%s: rejecting chirp: ts=%llu, dur=%d, rssi=%d " + "checkchirp=%d, hwchirp=%d, swchirp=%d\n", + __func__, + (unsigned long long)re->re_full_ts, + (int)re->re_dur, + (int)re->re_rssi, + !!(re->re_flags & DFS_EVENT_CHECKCHIRP), + !!(re->re_flags & DFS_EVENT_HW_CHIRP), + !!(re->re_flags & DFS_EVENT_SW_CHIRP)); + return 0; + } + + /* Adjust the filter threshold for rssi in non TURBO mode */ + qdf_spin_lock_bh(&dfs->ic->chan_lock); + if (!(dfs->ic->ic_curchan->ic_flags & CHANNEL_TURBO)) + b5_rssithresh += br->br_pulse.b5_rssimargin; + + qdf_spin_unlock_bh(&dfs->ic->chan_lock); + + /* + * Check if the pulse is within duration and rssi + * thresholds. + */ + if ((re->re_dur >= br->br_pulse.b5_mindur) && + (re->re_dur <= br->br_pulse.b5_maxdur) && + (re->re_rssi >= b5_rssithresh)) { + DFS_DPRINTK(dfs, ATH_DEBUG_DFS_BIN5, + "%s: dur=%d, rssi=%d - adding!\n", + __func__, (int)re->re_dur, (int)re->re_rssi); + return 1; + } + + DFS_DPRINTK(dfs, ATH_DEBUG_DFS_BIN5, + "%s: too low to be Bin5 pulse tsf=%llu, dur=%d, rssi=%d\n", + __func__, + (unsigned long long)re->re_full_ts, + (int)re->re_dur, (int)re->re_rssi); + + return 0; +} + +int dfs_bin5_addpulse(struct ath_dfs *dfs, struct dfs_bin5radars *br, + struct dfs_event *re, uint64_t thists) +{ + uint32_t index, stop; + uint64_t tsDelta; + + /* Check if this pulse is a valid pulse in terms of repetition, + * if not, return without adding it to the queue. + * PRI : Pulse Repitetion Interval + * BRI : Burst Repitetion Interval */ + if (br->br_numelems != 0) { + index = br->br_lastelem; + tsDelta = thists - br->br_elems[index].be_ts; + if ((tsDelta < DFS_BIN5_PRI_LOWER_LIMIT) || + ((tsDelta > DFS_BIN5_PRI_HIGHER_LIMIT) && + (tsDelta < DFS_BIN5_BRI_LOWER_LIMIT))) { + return 0; + } + } + /* Circular buffer of size 2^n */ + index = (br->br_lastelem + 1) & DFS_MAX_B5_MASK; + br->br_lastelem = index; + if (br->br_numelems == DFS_MAX_B5_SIZE) + br->br_firstelem = (br->br_firstelem + 1) & DFS_MAX_B5_MASK; + else + br->br_numelems++; + br->br_elems[index].be_ts = thists; + br->br_elems[index].be_rssi = re->re_rssi; + br->br_elems[index].be_dur = re->re_dur; /* please note that this is in u-sec */ + stop = 0; + index = br->br_firstelem; + while ((!stop) && (br->br_numelems - 1) > 0) { + if ((thists - br->br_elems[index].be_ts) > + ((uint64_t) br->br_pulse.b5_timewindow)) { + br->br_numelems--; + br->br_firstelem = + (br->br_firstelem + 1) & DFS_MAX_B5_MASK; + index = br->br_firstelem; + } else + stop = 1; + } + return 1; +} + +/* + * If the dfs structure is NULL (which should be illegal if everyting is working + * properly, then signify that a bin5 radar was found + */ + +int dfs_bin5_check(struct ath_dfs *dfs, int seg_id) +{ + struct dfs_bin5radars *br; + int index[DFS_MAX_B5_SIZE]; + uint32_t n = 0, i = 0, i1 = 0, this = 0, prev = 0, rssi_diff = + 0, width_diff = 0, bursts = 0; + uint32_t total_diff = 0, average_diff = 0, total_width = + 0, average_width = 0, numevents = 0; + uint64_t pri; + + if (dfs == NULL) { + DFS_PRINTK("%s: ic_dfs is NULL\n", __func__); + return 1; + } + for (n = 0; n < dfs->dfs_rinfo.rn_numbin5radars; n++) { + if (dfs->ic->ic_curchan->ic_80p80_both_dfs) + br = (seg_id == 0) ? &(dfs->dfs_b5radars[n]) : + &(dfs->dfs_b5radars_ext_seg[n]); + else + br = &(dfs->dfs_b5radars[n]); + DFS_DPRINTK(dfs, ATH_DEBUG_DFS_BIN5, + "Num elems = %d\n", br->br_numelems); + + /* find a valid bin 5 pulse and use it as reference */ + for (i1 = 0; i1 < br->br_numelems; i1++) { + this = ((br->br_firstelem + i1) & DFS_MAX_B5_MASK); + if ((br->br_elems[this].be_dur >= MIN_BIN5_DUR_MICROSEC) + && (br->br_elems[this].be_dur <= + MAX_BIN5_DUR_MICROSEC)) { + break; + } + } + + prev = this; + for (i = i1 + 1; i < br->br_numelems; i++) { + this = ((br->br_firstelem + i) & DFS_MAX_B5_MASK); + + /* first make sure it is a bin 5 pulse by checking the duration */ + if ((br->br_elems[this].be_dur < MIN_BIN5_DUR_MICROSEC) + || (br->br_elems[this].be_dur > + MAX_BIN5_DUR_MICROSEC)) { + continue; + } + + /* Rule 1: 1000 <= PRI <= 2000 + some margin */ + if (br->br_elems[this].be_ts >= + br->br_elems[prev].be_ts) { + pri = + br->br_elems[this].be_ts - + br->br_elems[prev].be_ts; + } else { /* roll over case */ + /* pri = (0xffffffffffffffff - br->br_elems[prev].be_ts) + br->br_elems[this].be_ts; */ + pri = br->br_elems[this].be_ts; + } + DFS_DPRINTK(dfs, ATH_DEBUG_DFS_BIN5, + " pri=%llu this.ts=%llu this.dur=%d this.rssi=%d prev.ts=%llu\n", + (unsigned long long)pri, + (unsigned long long)br->br_elems[this]. + be_ts, (int)br->br_elems[this].be_dur, + (int)br->br_elems[this].be_rssi, + (unsigned long long)br->br_elems[prev]. + be_ts); + if (((pri >= DFS_BIN5_PRI_LOWER_LIMIT) && (pri <= DFS_BIN5_PRI_HIGHER_LIMIT))) { /* pri: pulse repitition interval in us */ + /* Rule 2: pulse width of the pulses in the burst should be same (+/- margin) */ + if (br->br_elems[this].be_dur >= + br->br_elems[prev].be_dur) { + width_diff = + br->br_elems[this].be_dur - + br->br_elems[prev].be_dur; + } else { + width_diff = + br->br_elems[prev].be_dur - + br->br_elems[this].be_dur; + } + if (width_diff <= DFS_BIN5_WIDTH_MARGIN) { + /* Rule 3: RSSI of the pulses in the burst should be same (+/- margin) */ + if (br->br_elems[this].be_rssi >= + br->br_elems[prev].be_rssi) { + rssi_diff = + br->br_elems[this].be_rssi - + br->br_elems[prev].be_rssi; + } else { + rssi_diff = + br->br_elems[prev].be_rssi - + br->br_elems[this].be_rssi; + } + if (rssi_diff <= DFS_BIN5_RSSI_MARGIN) { + bursts++; + /* Save the indexes of this pair for later width variance check */ + if (numevents >= 2) { + /* make sure the event is not duplicated, + * possible in a 3 pulse burst */ + if (index[numevents - 1] + != prev) { + index + [numevents++] + = prev; + } + } else { + index[numevents++] = + prev; + } + index[numevents++] = this; + } else { + DFS_DPRINTK(dfs, + ATH_DEBUG_DFS_BIN5, + "%s %d Bin5 rssi_diff=%d\n", + __func__, __LINE__, + rssi_diff); + } + } else { + DFS_DPRINTK(dfs, + ATH_DEBUG_DFS_BIN5, + "%s %d Bin5 width_diff=%d\n", + __func__, __LINE__, + width_diff); + } + } else if ((pri >= DFS_BIN5_BRI_LOWER_LIMIT) && + (pri <= DFS_BIN5_BRI_UPPER_LIMIT)) { + /* check pulse width to make sure it is in range of bin 5 */ + /* if ((br->br_elems[this].be_dur >= MIN_BIN5_DUR_MICROSEC) && (br->br_elems[this].be_dur <= MAX_BIN5_DUR_MICROSEC)) { */ + bursts++; + /* } */ + } else { + DFS_DPRINTK(dfs, ATH_DEBUG_DFS_BIN5, + "%s %d Bin5 PRI check fail pri=%llu\n", + __func__, __LINE__, + (unsigned long long)pri); + } + prev = this; + } + + DFS_DPRINTK(dfs, ATH_DEBUG_DFS_BIN5, "bursts=%u numevents=%u\n", + bursts, numevents); + if (bursts >= br->br_pulse.b5_threshold) { + if ((br->br_elems[br->br_lastelem].be_ts - + br->br_elems[br->br_firstelem].be_ts) < 3000000) { + return 0; + } else { + /* + * don't do this check since not all the cases have this kind of burst width variation. + * + for (i=0; ibr_elems[index[i]].be_dur; + } + average_width = total_width/bursts; + for (i=0; ibr_elems[index[i]].be_dur, average_width); + } + average_diff = total_diff/bursts; + if( average_diff > DFS_BIN5_WIDTH_MARGIN ) { + return 1; + } else { + + DFS_DPRINTK(ic, ATH_DEBUG_DFS_BIN5, "bursts=%u numevents=%u total_width=%d average_width=%d total_diff=%d average_diff=%d\n", bursts, numevents, total_width, average_width, total_diff, average_diff); + + } + */ + DFS_DPRINTK(dfs, ATH_DEBUG_DFS_BIN5, + "bursts=%u numevents=%u total_width=%d average_width=%d total_diff=%d average_diff=%d\n", + bursts, numevents, total_width, + average_width, total_diff, + average_diff); + DFS_PRINTK("bin 5 radar detected, bursts=%d\n", + bursts); + return 1; + } + } + } + + return 0; +} + +/* Return true if chirping pulse, false if not. + Decision is made based on processing the FFT data included with the PHY error. + Calculate the slope using the maximum bin index reported in the FFT data. + Calculate slope between FFT packet 0 and packet n-1. Also calculate slope between + packet 1 and packet n. + If a pulse is chirping, a slope of 5 and greater is seen. + Non-chirping pulses have slopes of 0, 1, 2 or 3. + */ + +/* + * Chirp detection for Sowl/Howl. + */ +static int +dfs_check_chirping_sowl(struct ath_dfs *dfs, void *buf, + uint16_t datalen, int is_ctl, int is_ext, int *slope, + int *is_dc) +{ +#define FFT_LEN 70 +#define FFT_LOWER_BIN_MAX_INDEX_BYTE 66 +#define FFT_UPPER_BIN_MAX_INDEX_BYTE 69 +#define MIN_CHIRPING_SLOPE 4 + int is_chirp = 0; + int p, num_fft_packets = 0; + int ctl_slope = 0, ext_slope = 0; + int ctl_high0, ctl_low0, ctl_slope0 = + 0, ext_high0, ext_low0, ext_slope0 = 0; + int ctl_high1, ctl_low1, ctl_slope1 = + 0, ext_high1, ext_low1, ext_slope1 = 0; + uint8_t *fft_data_ptr; + + *slope = 0; + *is_dc = 0; + + num_fft_packets = datalen / FFT_LEN; + fft_data_ptr = ((uint8_t *) buf); + + /* DEBUG - Print relevant portions of the FFT data */ + for (p = 0; p < num_fft_packets; p++) { + + DFS_DPRINTK(dfs, ATH_DEBUG_DFS_BIN5_FFT, "fft_data_ptr=0x%p\t", + fft_data_ptr); + DFS_DPRINTK(dfs, ATH_DEBUG_DFS_BIN5_FFT, "[66]=%d [69]=%d\n", + *(fft_data_ptr + FFT_LOWER_BIN_MAX_INDEX_BYTE) >> 2, + *(fft_data_ptr + + FFT_UPPER_BIN_MAX_INDEX_BYTE) >> 2); + + fft_data_ptr += FFT_LEN; + } + + DFS_DPRINTK(dfs, ATH_DEBUG_DFS_BIN5_FFT, + "datalen=%d num_fft_packets=%d\n", datalen, + num_fft_packets); + + /* There is not enough FFT data to figure out whether the pulse is chirping or not */ + if (num_fft_packets < 4) { + return 0; + } + + fft_data_ptr = ((uint8_t *) buf); + + if (is_ctl) { + + fft_data_ptr = ((uint8_t *) buf); + ctl_low0 = *(fft_data_ptr + FFT_LOWER_BIN_MAX_INDEX_BYTE) >> 2; + fft_data_ptr += FFT_LEN; + ctl_low1 = *(fft_data_ptr + FFT_LOWER_BIN_MAX_INDEX_BYTE) >> 2; + + /* last packet with first packet */ + fft_data_ptr = + ((uint8_t *) buf) + (FFT_LEN * (num_fft_packets - 1)); + ctl_high1 = *(fft_data_ptr + FFT_LOWER_BIN_MAX_INDEX_BYTE) >> 2; + + /* second last packet with 0th packet */ + fft_data_ptr = + ((uint8_t *) buf) + (FFT_LEN * (num_fft_packets - 2)); + ctl_high0 = *(fft_data_ptr + FFT_LOWER_BIN_MAX_INDEX_BYTE) >> 2; + + ctl_slope0 = ctl_high0 - ctl_low0; + if (ctl_slope0 < 0) + ctl_slope0 *= (-1); + + ctl_slope1 = ctl_high1 - ctl_low1; + if (ctl_slope1 < 0) + ctl_slope1 *= (-1); + + ctl_slope = + ((ctl_slope0 > ctl_slope1) ? ctl_slope0 : ctl_slope1); + *slope = ctl_slope; + DFS_DPRINTK(dfs, ATH_DEBUG_DFS_BIN5_FFT, + "ctl_slope0=%d ctl_slope1=%d ctl_slope=%d\n", + ctl_slope0, ctl_slope1, ctl_slope); + + } else if (is_ext) { + + fft_data_ptr = ((uint8_t *) buf); + ext_low0 = *(fft_data_ptr + FFT_UPPER_BIN_MAX_INDEX_BYTE) >> 2; + + fft_data_ptr += FFT_LEN; + ext_low1 = *(fft_data_ptr + FFT_UPPER_BIN_MAX_INDEX_BYTE) >> 2; + + fft_data_ptr = + ((uint8_t *) buf) + (FFT_LEN * (num_fft_packets - 1)); + ext_high1 = *(fft_data_ptr + FFT_UPPER_BIN_MAX_INDEX_BYTE) >> 2; + fft_data_ptr = + ((uint8_t *) buf) + (FFT_LEN * (num_fft_packets - 2)); + ext_high0 = *(fft_data_ptr + FFT_UPPER_BIN_MAX_INDEX_BYTE) >> 2; + + ext_slope0 = ext_high0 - ext_low0; + if (ext_slope0 < 0) + ext_slope0 *= (-1); + + ext_slope1 = ext_high1 - ext_low1; + if (ext_slope1 < 0) + ext_slope1 *= (-1); + + ext_slope = + ((ext_slope0 > ext_slope1) ? ext_slope0 : ext_slope1); + *slope = ext_slope; + DFS_DPRINTK(dfs, ATH_DEBUG_DFS_BIN5_FFT | ATH_DEBUG_DFS_BIN5, + "ext_slope0=%d ext_slope1=%d ext_slope=%d\n", + ext_slope0, ext_slope1, ext_slope); + } else + return 0; + + if ((ctl_slope >= MIN_CHIRPING_SLOPE) + || (ext_slope >= MIN_CHIRPING_SLOPE)) { + is_chirp = 1; + DFS_DPRINTK(dfs, ATH_DEBUG_DFS_BIN5 | ATH_DEBUG_DFS_BIN5_FFT | + ATH_DEBUG_DFS_PHYERR_SUM, + "is_chirp=%d is_dc=%d\n", is_chirp, *is_dc); + } + return is_chirp; + +#undef FFT_LEN +#undef FFT_LOWER_BIN_MAX_INDEX_BYTE +#undef FFT_UPPER_BIN_MAX_INDEX_BYTE +#undef MIN_CHIRPING_SLOPE +} + +/* + * Merlin (and Osprey, etc) chirp radar chirp detection. + */ +static int +dfs_check_chirping_merlin(struct ath_dfs *dfs, void *buf, uint16_t datalen, + int is_ctl, int is_ext, int *slope, int *is_dc) +{ +#define ABS_DIFF(_x, _y) ((int)_x > (int)_y ? (int)_x - (int)_y : (int)_y - (int)_x) +#define ABS(_x) ((int)_x > 0 ? (int)_x : -(int)_x) + +#define DELTA_STEP 1 /* This should be between 1 and 3. Default is 1. */ +#define NUM_DIFFS 3 /* Number of Diffs to compute. valid range is 2-4 */ +#define MAX_DIFF 2 /* Threshold for difference of delta peaks */ +#define BIN_COUNT_MAX 6 /* Max. number of strong bins for narrow band */ + +/* + * Dynamic 20/40 mode FFT packet format related definition + */ + +#define NUM_FFT_BYTES_HT40 70 +#define NUM_BIN_BYTES_HT40 64 +#define NUM_SUBCHAN_BINS_HT40 64 +#define LOWER_INDEX_BYTE_HT40 66 +#define UPPER_INDEX_BYTE_HT40 69 +#define LOWER_WEIGHT_BYTE_HT40 64 +#define UPPER_WEIGHT_BYTE_HT40 67 +#define LOWER_MAG_BYTE_HT40 65 +#define UPPER_MAG_BYTE_HT40 68 + +/* + * Static 20 mode FFT packet format related definition + */ + +#define NUM_FFT_BYTES_HT20 31 +#define NUM_BIN_BYTES_HT20 28 +#define NUM_SUBCHAN_BINS_HT20 56 +#define LOWER_INDEX_BYTE_HT20 30 +#define UPPER_INDEX_BYTE_HT20 30 +#define LOWER_WEIGHT_BYTE_HT20 28 +#define UPPER_WEIGHT_BYTE_HT20 28 +#define LOWER_MAG_BYTE_HT20 29 +#define UPPER_MAG_BYTE_HT20 29 + + int num_fft_packets; /* number of FFT packets reported to software */ + int num_fft_bytes; + int num_bin_bytes; + int num_subchan_bins; + int lower_index_byte; + int upper_index_byte; + int lower_weight_byte; + int upper_weight_byte; + int lower_mag_byte; + int upper_mag_byte; + + int max_index_lower[DELTA_STEP + NUM_DIFFS]; + int max_index_upper[DELTA_STEP + NUM_DIFFS]; + int max_mag_lower[DELTA_STEP + NUM_DIFFS]; + int max_mag_upper[DELTA_STEP + NUM_DIFFS]; + int bin_wt_lower[DELTA_STEP + NUM_DIFFS]; + int bin_wt_upper[DELTA_STEP + NUM_DIFFS]; + int max_mag_sel[DELTA_STEP + NUM_DIFFS]; + int max_mag[DELTA_STEP + NUM_DIFFS]; + int max_index[DELTA_STEP + NUM_DIFFS]; + + int max_d[] = { 10, 19, 28 }; + int min_d[] = { 1, 2, 3 }; + + uint8_t *ptr; /* pointer to FFT data */ + int i; + int fft_start; + int chirp_found; + int delta_peak[NUM_DIFFS]; + int j; + int bin_count; + int bw_mask; + int delta_diff; + int same_sign; + int temp; + + qdf_spin_lock_bh(&dfs->ic->chan_lock); + if (IS_CHAN_HT40(dfs->ic->ic_curchan)) { + num_fft_bytes = NUM_FFT_BYTES_HT40; + num_bin_bytes = NUM_BIN_BYTES_HT40; + num_subchan_bins = NUM_SUBCHAN_BINS_HT40; + lower_index_byte = LOWER_INDEX_BYTE_HT40; + upper_index_byte = UPPER_INDEX_BYTE_HT40; + lower_weight_byte = LOWER_WEIGHT_BYTE_HT40; + upper_weight_byte = UPPER_WEIGHT_BYTE_HT40; + lower_mag_byte = LOWER_MAG_BYTE_HT40; + upper_mag_byte = UPPER_MAG_BYTE_HT40; + + /* if we are in HT40MINUS then swap primary and extension */ + if (IS_CHAN_HT40_MINUS(dfs->ic->ic_curchan)) { + temp = is_ctl; + is_ctl = is_ext; + is_ext = temp; + } + + } else { + num_fft_bytes = NUM_FFT_BYTES_HT20; + num_bin_bytes = NUM_BIN_BYTES_HT20; + num_subchan_bins = NUM_SUBCHAN_BINS_HT20; + lower_index_byte = LOWER_INDEX_BYTE_HT20; + upper_index_byte = UPPER_INDEX_BYTE_HT20; + lower_weight_byte = LOWER_WEIGHT_BYTE_HT20; + upper_weight_byte = UPPER_WEIGHT_BYTE_HT20; + lower_mag_byte = LOWER_MAG_BYTE_HT20; + upper_mag_byte = UPPER_MAG_BYTE_HT20; + } + + qdf_spin_unlock_bh(&dfs->ic->chan_lock); + ptr = (uint8_t *) buf; + /* + * sanity check for FFT buffer + */ + + if ((ptr == NULL) || (datalen == 0)) { + DFS_DPRINTK(dfs, ATH_DEBUG_DFS_BIN5_FFT, + "%s: FFT buffer pointer is null or size is 0\n", + __func__); + return 0; + } + + num_fft_packets = (datalen - 3) / num_fft_bytes; + if (num_fft_packets < (NUM_DIFFS + DELTA_STEP)) { + DFS_DPRINTK(dfs, ATH_DEBUG_DFS_BIN5_FFT, + "datalen = %d, num_fft_packets = %d, too few packets... (exiting)\n", + datalen, num_fft_packets); + return 0; + } + + if ((((datalen - 3) % num_fft_bytes) == 2) && (datalen > num_fft_bytes)) { + /* FIXME !!! */ + ptr += 2; + datalen -= 2; + } + + for (i = 0; i < (NUM_DIFFS + DELTA_STEP); i++) { + fft_start = i * num_fft_bytes; + bin_wt_lower[i] = ptr[fft_start + lower_weight_byte] & 0x3f; + bin_wt_upper[i] = ptr[fft_start + upper_weight_byte] & 0x3f; + + max_index_lower[i] = ptr[fft_start + lower_index_byte] >> 2; + max_index_upper[i] = + (ptr[fft_start + upper_index_byte] >> 2) + num_subchan_bins; + + qdf_spin_lock_bh(&dfs->ic->chan_lock); + if (!IS_CHAN_HT40(dfs->ic->ic_curchan)) { + /* + * for HT20 mode indices are 6 bit signed number + */ + max_index_lower[i] ^= 0x20; + max_index_upper[i] = 0; + } + + qdf_spin_unlock_bh(&dfs->ic->chan_lock); + /* + * Reconstruct the maximum magnitude for each sub-channel. Also select + * and flag the max overall magnitude between the two sub-channels. + */ + + max_mag_lower[i] = + ((ptr[fft_start + lower_index_byte] & 0x03) << 8) + + ptr[fft_start + lower_mag_byte]; + max_mag_upper[i] = + ((ptr[fft_start + upper_index_byte] & 0x03) << 8) + + ptr[fft_start + upper_mag_byte]; + bw_mask = + ((bin_wt_lower[i] == + 0) ? 0 : is_ctl) + (((bin_wt_upper[i] == + 0) ? 0 : is_ext) << 1); + + /* + * Limit the max bin based on channel bandwidth + * If the upper sub-channel max index is stuck at '1', the signal is dominated + * by residual DC (or carrier leak) and should be ignored. + */ + + if (bw_mask == 1) { + max_mag_sel[i] = 0; + max_mag[i] = max_mag_lower[i]; + max_index[i] = max_index_lower[i]; + } else if (bw_mask == 2) { + max_mag_sel[i] = 1; + max_mag[i] = max_mag_upper[i]; + max_index[i] = max_index_upper[i]; + } else if (max_index_upper[i] == num_subchan_bins) { + max_mag_sel[i] = 0; /* Ignore DC bin. */ + max_mag[i] = max_mag_lower[i]; + max_index[i] = max_index_lower[i]; + } else { + if (max_mag_upper[i] > max_mag_lower[i]) { + max_mag_sel[i] = 1; + max_mag[i] = max_mag_upper[i]; + max_index[i] = max_index_upper[i]; + } else { + max_mag_sel[i] = 0; + max_mag[i] = max_mag_lower[i]; + max_index[i] = max_index_lower[i]; + } + } + DFS_DPRINTK(dfs, ATH_DEBUG_DFS_BIN5_FFT, + "i=%d, max_index[i]=%d, max_index_lower[i]=%d, " + "max_index_upper[i]=%d\n", + i, max_index[i], max_index_lower[i], + max_index_upper[i]); + } + + chirp_found = 1; + delta_diff = 0; + same_sign = 1; + + /* + delta_diff computation -- look for movement in peak. + make sure that the chirp direction (i.e. sign) is always the same, + i.e. sign of the two peaks should be same. + */ + for (i = 0; i < NUM_DIFFS; i++) { + delta_peak[i] = max_index[i + DELTA_STEP] - max_index[i]; + if (i > 0) { + delta_diff = delta_peak[i] - delta_peak[i - 1]; + same_sign = + !((delta_peak[i] & 0x80) ^ + (delta_peak[i - 1] & 0x80)); + } + chirp_found &= (ABS(delta_peak[i]) >= min_d[DELTA_STEP - 1]) && + (ABS(delta_peak[i]) <= max_d[DELTA_STEP - 1]) && + same_sign && (ABS(delta_diff) <= MAX_DIFF); + DFS_DPRINTK(dfs, ATH_DEBUG_DFS_BIN5_FFT, + "i=%d, delta_peak[i]=%d, delta_diff=%d\n", + i, delta_peak[i], delta_diff); + } + + if (chirp_found) { + DFS_DPRINTK(dfs, ATH_DEBUG_DFS_BIN5_FFT, + "%s: CHIRPING_BEFORE_STRONGBIN_YES\n", __func__); + } else { + DFS_DPRINTK(dfs, ATH_DEBUG_DFS_BIN5_FFT, + "%s: CHIRPING_BEFORE_STRONGBIN_NO\n", __func__); + } + + /* + Work around for potential hardware data corruption bug. Check for + wide band signal by counting strong bins indicated by bitmap flags. + This check is done if chirp_found is true. We do this as a final check + to weed out corrupt FFTs bytes. This looks expensive but in most cases it + will exit early. + */ + + for (i = 0; (i < (NUM_DIFFS + DELTA_STEP)) && (chirp_found == 1); i++) { + bin_count = 0; + /* point to the start of the 1st byte of the selected sub-channel. */ + fft_start = + (i * num_fft_bytes) + + (max_mag_sel[i] ? (num_subchan_bins >> 1) : 0); + for (j = 0; j < (num_subchan_bins >> 1); j++) { + /* + * If either bin is flagged "strong", accumulate the bin_count. + * It's not accurate, but good enough... + */ + bin_count += (ptr[fft_start + j] & 0x88) ? 1 : 0; + } + chirp_found &= (bin_count > BIN_COUNT_MAX) ? 0 : 1; + DFS_DPRINTK(dfs, ATH_DEBUG_DFS_BIN5_FFT, + "i=%d, computed bin_count=%d\n", i, bin_count); + } + + if (chirp_found) { + DFS_DPRINTK(dfs, + ATH_DEBUG_DFS_BIN5_FFT | ATH_DEBUG_DFS_PHYERR_SUM, + "%s: CHIRPING_YES\n", __func__); + } else { + DFS_DPRINTK(dfs, + ATH_DEBUG_DFS_BIN5_FFT | ATH_DEBUG_DFS_PHYERR_SUM, + "%s: CHIRPING_NO\n", __func__); + } + return chirp_found; + +#undef ABS_DIFF +#undef ABS +#undef DELTA_STEP +#undef NUM_DIFFS +#undef MAX_DIFF +#undef BIN_COUNT_MAX + +#undef NUM_FFT_BYTES_HT40 +#undef NUM_BIN_BYTES_HT40 +#undef NUM_SUBCHAN_BINS_HT40 +#undef LOWER_INDEX_BYTE_HT40 +#undef UPPER_INDEX_BYTE_HT40 +#undef LOWER_WEIGHT_BYTE_HT40 +#undef UPPER_WEIGHT_BYTE_HT40 +#undef LOWER_MAG_BYTE_HT40 +#undef UPPER_MAG_BYTE_HT40 + +#undef NUM_FFT_BYTES_HT40 +#undef NUM_BIN_BYTES_HT40 +#undef NUM_SUBCHAN_BINS_HT40 +#undef LOWER_INDEX_BYTE_HT40 +#undef UPPER_INDEX_BYTE_HT40 +#undef LOWER_WEIGHT_BYTE_HT40 +#undef UPPER_WEIGHT_BYTE_HT40 +#undef LOWER_MAG_BYTE_HT40 +#undef UPPER_MAG_BYTE_HT40 +} + +int +dfs_check_chirping(struct ath_dfs *dfs, void *buf, + uint16_t datalen, int is_ctl, int is_ext, int *slope, + int *is_dc) +{ + + if (dfs->dfs_caps.ath_dfs_use_enhancement) + return dfs_check_chirping_merlin(dfs, buf, datalen, is_ctl, + is_ext, slope, is_dc); + else + return dfs_check_chirping_sowl(dfs, buf, datalen, is_ctl, + is_ext, slope, is_dc); +} + +uint8_t +dfs_retain_bin5_burst_pattern(struct ath_dfs *dfs, uint32_t diff_ts, + uint8_t old_dur, int seg_id) +{ + + u_int8_t dfs_last_bin5_dur; + + if (dfs->ic->ic_curchan->ic_80p80_both_dfs) + dfs_last_bin5_dur = (seg_id == 0) ? + dfs->dfs_rinfo.dfs_last_bin5_dur : + dfs->dfs_rinfo.dfs_last_bin5_dur_ext_seg; + else + dfs_last_bin5_dur = dfs->dfs_rinfo.dfs_last_bin5_dur; + + /* + * Pulses may get split into 2 during chirping, this print is only + * to show that it happened, we do not handle this condition if we + * cannot detect the chirping. + */ + /* + * SPLIT pulses will have a time stamp difference of < 50 + */ + if (diff_ts < 50) { + DFS_DPRINTK(dfs, ATH_DEBUG_DFS_BIN5, + "%s SPLIT pulse diffTs=%u dur=%d (old_dur=%d)\n", + __func__, diff_ts, + dfs_last_bin5_dur, old_dur); + } + /* + * Check if this is the 2nd or 3rd pulse in the same burst, + * PRI will be between 1000 and 2000 us + */ + if (((diff_ts >= DFS_BIN5_PRI_LOWER_LIMIT) && + (diff_ts <= DFS_BIN5_PRI_HIGHER_LIMIT))) { + /* + * This pulse belongs to the same burst as the pulse before, + * so return the same random duration for it + */ + DFS_DPRINTK(dfs, ATH_DEBUG_DFS_BIN5, + "%s this pulse belongs to the same burst as before, give " + "it same dur=%d (old_dur=%d)\n", + __func__, dfs_last_bin5_dur, old_dur); + + return dfs_last_bin5_dur; + } + /* + * This pulse does not belong to this burst, return unchanged + * duration. + */ + return old_dur; +} + +/* + * Chirping pulses may get cut off at DC and report lower durations. + * + * This function will compute a suitable random duration for each pulse. + * Duration must be between 50 and 100 us, but remember that in + * ath_process_phyerr() which calls this function, we are dealing with the + * HW reported duration (unconverted). dfs_process_radarevent() will + * actually convert the duration into the correct value. + * + * XXX This function doesn't take into account whether the hardware + * is operating in 5GHz fast clock mode or not. + * + * XXX And this function doesn't take into account whether the hardware + * is peregrine or not. Grr. + */ +int dfs_get_random_bin5_dur(struct ath_dfs *dfs, uint64_t tstamp) +{ + uint8_t new_dur = MIN_BIN5_DUR; + int range; + + get_random_bytes(&new_dur, sizeof(uint8_t)); + + range = (MAX_BIN5_DUR - MIN_BIN5_DUR + 1); + + new_dur %= range; + + new_dur += MIN_BIN5_DUR; + + return new_dur; +} + +#endif /* ATH_SUPPORT_DFS */ diff --git a/drivers/staging/qcacld-3.0/core/sap/dfs/src/dfs_init.c b/drivers/staging/qcacld-3.0/core/sap/dfs/src/dfs_init.c new file mode 100644 index 0000000000000000000000000000000000000000..512e8ac9cf17353e77cccb43f39d39c205ffe34a --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/sap/dfs/src/dfs_init.c @@ -0,0 +1,495 @@ +/* + * Copyright (c) 2002-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/*=========================================================================== + + dfs_init.c + + OVERVIEW: + + Source code borrowed from QCA_MAIN DFS module + + DEPENDENCIES: + + Are listed for each API below. + + ===========================================================================*/ + +/*=========================================================================== + + EDIT HISTORY FOR FILE + + This section contains comments describing changes made to the module. + Notice that changes are listed in reverse chronological order. + + when who what, where, why + ---------- --- -------------------------------------------------------- + + ===========================================================================*/ + +#include "dfs.h" +/* TO DO DFS + #include + */ +#ifdef ATH_SUPPORT_DFS + +extern int domainoverride; + +/* + * Clear all delay lines for all filter types + * + * This may be called before any radar pulses are configured + * (eg on a non-DFS channel, with radar PHY errors still showing up.) + * In that case, just drop out early. + */ +void dfs_reset_alldelaylines(struct ath_dfs *dfs, int seg_id) +{ + struct dfs_filtertype *ft = NULL; + struct dfs_filter *rf; + struct dfs_delayline *dl; + struct dfs_pulseline *pl; + int i, j; + + if (dfs == NULL) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s[%d]: sc_dfs is NULL", __func__, __LINE__); + return; + } + + if (dfs->ic->dfs_hw_bd_id != DFS_HWBD_QCA6174) + pl = (seg_id == 0) ? dfs->pulses : dfs->pulses_ext_seg; + else + pl = dfs->pulses; + + if (pl == NULL) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s[%d]: pl==NULL, dfs=%p", __func__, __LINE__, dfs); + return; + } + + if (dfs->ic->dfs_hw_bd_id != DFS_HWBD_QCA6174) { + if (((seg_id == 0) ? + dfs->dfs_b5radars : dfs->dfs_b5radars_ext_seg) == NULL) { + DFS_DPRINTK(dfs, ATH_DEBUG_DFS, + "%s: pl==NULL, b5radars=%p\n", + __func__, + (seg_id == 0) ? dfs->dfs_b5radars : + dfs->dfs_b5radars_ext_seg); + return; + } + } else { + if (dfs->dfs_b5radars == NULL) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s[%d]: pl==NULL, b5radars=%p", __func__, __LINE__, + dfs->dfs_b5radars); + return; + } + } + /* reset the pulse log */ + pl->pl_firstelem = pl->pl_numelems = 0; + pl->pl_lastelem = DFS_MAX_PULSE_BUFFER_MASK; + + for (i = 0; i < DFS_MAX_RADAR_TYPES; i++) { + if (dfs->dfs_radarf[i] != NULL) { + ft = dfs->dfs_radarf[i]; + if (NULL != ft) { + for (j = 0; j < ft->ft_numfilters; j++) { + rf = ft->ft_filters[j]; + if (dfs->ic->dfs_hw_bd_id != + DFS_HWBD_QCA6174) + dl = (seg_id == 0) ? + &(rf->rf_dl) : + &(rf->rf_dl_ext_seg); + else + dl = &(rf->rf_dl); + if (dl != NULL) { + OS_MEMZERO(dl, + sizeof(struct + dfs_delayline)); + dl->dl_lastelem = + (0xFFFFFFFF) & + DFS_MAX_DL_MASK; + } + } + } + } + } + for (i = 0; i < dfs->dfs_rinfo.rn_numbin5radars; i++) { + if (dfs->ic->dfs_hw_bd_id != DFS_HWBD_QCA6174) { + if (seg_id == DFS_80P80_SEG0) { + OS_MEMZERO(&(dfs->dfs_b5radars[i].br_elems[0]), + sizeof(struct dfs_bin5elem) * + DFS_MAX_B5_SIZE); + dfs->dfs_b5radars[i].br_firstelem = 0; + dfs->dfs_b5radars[i].br_numelems = 0; + dfs->dfs_b5radars[i].br_lastelem = + (0xFFFFFFFF) & DFS_MAX_B5_MASK; + } else { + OS_MEMZERO( + &(dfs->dfs_b5radars_ext_seg[i].br_elems[0]), + sizeof(struct dfs_bin5elem)* + DFS_MAX_B5_SIZE); + dfs->dfs_b5radars_ext_seg[i].br_firstelem = 0; + dfs->dfs_b5radars_ext_seg[i].br_numelems = 0; + dfs->dfs_b5radars_ext_seg[i].br_lastelem = + (0xFFFFFFFF)&DFS_MAX_B5_MASK; + } + + } else { + OS_MEMZERO(&(dfs->dfs_b5radars[i].br_elems[0]), + sizeof(struct dfs_bin5elem) * DFS_MAX_B5_SIZE); + dfs->dfs_b5radars[i].br_firstelem = 0; + dfs->dfs_b5radars[i].br_numelems = 0; + dfs->dfs_b5radars[i].br_lastelem = + (0xFFFFFFFF) & DFS_MAX_B5_MASK; + } + } +} + +/* + * Clear only a single delay line + */ + +void dfs_reset_delayline(struct dfs_delayline *dl) +{ + OS_MEMZERO(&(dl->dl_elems[0]), sizeof(dl->dl_elems)); + dl->dl_lastelem = (0xFFFFFFFF) & DFS_MAX_DL_MASK; +} + +void dfs_reset_radarq(struct ath_dfs *dfs) +{ + struct dfs_event *event; + if (dfs == NULL) { + DFS_DPRINTK(dfs, ATH_DEBUG_DFS, "%s: sc_dfs is NULL", __func__); + return; + } + ATH_DFSQ_LOCK(dfs); + ATH_DFSEVENTQ_LOCK(dfs); + while (!STAILQ_EMPTY(&(dfs->dfs_radarq))) { + event = STAILQ_FIRST(&(dfs->dfs_radarq)); + STAILQ_REMOVE_HEAD(&(dfs->dfs_radarq), re_list); + OS_MEMZERO(event, sizeof(struct dfs_event)); + STAILQ_INSERT_TAIL(&(dfs->dfs_eventq), event, re_list); + } + ATH_DFSEVENTQ_UNLOCK(dfs); + ATH_DFSQ_UNLOCK(dfs); +} + +/* This function Initialize the radar filter tables + * if the ath dfs domain is uninitalized or + * ath dfs domain is different from hal dfs domain + */ +int dfs_init_radar_filters(struct ieee80211com *ic, + struct ath_dfs_radar_tab_info *radar_info) +{ + uint32_t T, Tmax; + int numpulses, p, n, i; + int numradars = 0, numb5radars = 0; + struct ath_dfs *dfs = (struct ath_dfs *)ic->ic_dfs; + struct dfs_filtertype *ft = NULL; + struct dfs_filter *rf = NULL; + struct dfs_pulse *dfs_radars; + struct dfs_bin5pulse *b5pulses = NULL; + int32_t min_rssithresh = DFS_MAX_RSSI_VALUE; + uint32_t max_pulsedur = 0; + uint32_t b5_rssithresh; + uint32_t b5_maxdur; + + if (dfs == NULL) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s[%d]: dfs is NULL", __func__, __LINE__); + return DFS_STATUS_FAIL; + } + /* clear up the dfs domain flag first */ +#ifndef ATH_DFS_RADAR_DETECTION_ONLY + dfs->ath_dfs_isdfsregdomain = 0; +#endif + + /* + * If radar_info is NULL or dfsdomain is NULL, treat + * the rest of the radar configuration as suspect. + */ + if (radar_info == NULL || radar_info->dfsdomain == 0) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s[%d]: Unknown dfs domain %d ", + __func__, __LINE__, dfs->dfsdomain); + /* Disable radar detection since we don't have a radar domain */ + dfs->dfs_proc_phyerr &= ~DFS_RADAR_EN; + /* Returning success though we are not completing init. A failure + * will fail dfs_attach also. + */ + return DFS_STATUS_SUCCESS; + } + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO, + "%s[%d]:dfsdomain=%d, numradars=%d, numb5radars=%d", + __func__, __LINE__, radar_info->dfsdomain, + radar_info->numradars, radar_info->numb5radars); + dfs->dfsdomain = radar_info->dfsdomain; + dfs_radars = radar_info->dfs_radars; + numradars = radar_info->numradars; + b5pulses = radar_info->b5pulses; + numb5radars = radar_info->numb5radars; + + /* XXX this should be an explicit copy of some sort! */ + dfs->dfs_defaultparams = radar_info->dfs_defaultparams; + +#ifndef ATH_DFS_RADAR_DETECTION_ONLY + dfs->ath_dfs_isdfsregdomain = 1; +#endif + + dfs->dfs_rinfo.rn_numradars = 0; + /* Clear filter type table */ + for (n = 0; n < 256; n++) { + for (i = 0; i < DFS_MAX_RADAR_OVERLAP; i++) + (dfs->dfs_radartable[n])[i] = -1; + } + /* Now, initialize the radar filters */ + for (p = 0; p < numradars; p++) { + ft = NULL; + for (n = 0; n < dfs->dfs_rinfo.rn_numradars; n++) { + if ((dfs_radars[p].rp_pulsedur == + dfs->dfs_radarf[n]->ft_filterdur) + && (dfs_radars[p].rp_numpulses == + dfs->dfs_radarf[n]->ft_numpulses) + && (dfs_radars[p].rp_mindur == + dfs->dfs_radarf[n]->ft_mindur) + && (dfs_radars[p].rp_maxdur == + dfs->dfs_radarf[n]->ft_maxdur)) { + ft = dfs->dfs_radarf[n]; + break; + } + } + if (ft == NULL) { + /* No filter of the appropriate dur was found */ + if ((dfs->dfs_rinfo.rn_numradars + 1) > + DFS_MAX_RADAR_TYPES) { + DFS_DPRINTK(dfs, ATH_DEBUG_DFS, + "%s: Too many filter types", + __func__); + goto bad4; + } + ft = dfs->dfs_radarf[dfs->dfs_rinfo.rn_numradars]; + ft->ft_numfilters = 0; + ft->ft_numpulses = dfs_radars[p].rp_numpulses; + ft->ft_patterntype = dfs_radars[p].rp_patterntype; + ft->ft_mindur = dfs_radars[p].rp_mindur; + ft->ft_maxdur = dfs_radars[p].rp_maxdur; + ft->ft_filterdur = dfs_radars[p].rp_pulsedur; + ft->ft_rssithresh = dfs_radars[p].rp_rssithresh; + ft->ft_rssimargin = dfs_radars[p].rp_rssimargin; + ft->ft_minpri = 1000000; + + if (ft->ft_rssithresh < min_rssithresh) + min_rssithresh = ft->ft_rssithresh; + if (ft->ft_maxdur > max_pulsedur) + max_pulsedur = ft->ft_maxdur; + for (i = ft->ft_mindur; i <= ft->ft_maxdur; i++) { + uint32_t stop = 0, tableindex = 0; + while ((tableindex < DFS_MAX_RADAR_OVERLAP) + && (!stop)) { + if ((dfs-> + dfs_radartable[i])[tableindex] == + -1) + stop = 1; + else + tableindex++; + } + if (stop) { + (dfs->dfs_radartable[i])[tableindex] = + (int8_t) (dfs->dfs_rinfo. + rn_numradars); + } else { + DFS_DPRINTK(dfs, ATH_DEBUG_DFS, + "%s: Too many overlapping radar filters", + __func__); + goto bad4; + } + } + dfs->dfs_rinfo.rn_numradars++; + } + rf = ft->ft_filters[ft->ft_numfilters++]; + dfs_reset_delayline(&rf->rf_dl); + + if (ic->dfs_hw_bd_id != DFS_HWBD_QCA6174) + dfs_reset_delayline(&rf->rf_dl_ext_seg); + + numpulses = dfs_radars[p].rp_numpulses; + + rf->rf_numpulses = numpulses; + rf->rf_patterntype = dfs_radars[p].rp_patterntype; + rf->rf_pulseid = dfs_radars[p].rp_pulseid; + rf->rf_mindur = dfs_radars[p].rp_mindur; + rf->rf_maxdur = dfs_radars[p].rp_maxdur; + rf->rf_numpulses = dfs_radars[p].rp_numpulses; + rf->rf_ignore_pri_window = dfs_radars[p].rp_ignore_pri_window; + T = (100000000 / dfs_radars[p].rp_max_pulsefreq) - + 100 * (dfs_radars[p].rp_meanoffset); + rf->rf_minpri = + dfs_round((int32_t) T - + (100 * (dfs_radars[p].rp_pulsevar))); + Tmax = + (100000000 / dfs_radars[p].rp_pulsefreq) - + 100 * (dfs_radars[p].rp_meanoffset); + rf->rf_maxpri = + dfs_round((int32_t) Tmax + + (100 * (dfs_radars[p].rp_pulsevar))); + + if (rf->rf_minpri < ft->ft_minpri) + ft->ft_minpri = rf->rf_minpri; + + rf->rf_fixed_pri_radar_pulse = + (dfs_radars[p].rp_max_pulsefreq == + dfs_radars[p].rp_pulsefreq) ? 1 : 0; + rf->rf_threshold = dfs_radars[p].rp_threshold; + rf->rf_filterlen = rf->rf_maxpri * rf->rf_numpulses; + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO, + "%s[%d]: minprf = %d maxprf = %d pulsevar = %d thresh=%d", + __func__, __LINE__, dfs_radars[p].rp_pulsefreq, + dfs_radars[p].rp_max_pulsefreq, + dfs_radars[p].rp_pulsevar, rf->rf_threshold); + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO, + "%s[%d]:minpri = %d maxpri = %d filterlen = %d filterID = %d", + __func__, __LINE__, rf->rf_minpri, rf->rf_maxpri, + rf->rf_filterlen, rf->rf_pulseid); + + } + +#ifdef DFS_DEBUG + dfs_print_filters(ic); +#endif + dfs->dfs_rinfo.rn_numbin5radars = numb5radars; + if (dfs->dfs_b5radars != NULL) { + OS_FREE(dfs->dfs_b5radars); + dfs->dfs_b5radars = NULL; + } + + if (dfs->dfs_b5radars_ext_seg != NULL) { + OS_FREE(dfs->dfs_b5radars_ext_seg); + dfs->dfs_b5radars_ext_seg = NULL; + } + + if (numb5radars) { + dfs->dfs_b5radars = (struct dfs_bin5radars *)os_malloc(NULL, + numb5radars * + sizeof(struct dfs_bin5radars), + GFP_KERNEL); + if (dfs->dfs_b5radars == NULL) { + DFS_DPRINTK(dfs, ATH_DEBUG_DFS, + "%s: cannot allocate memory for bin5 radars", + __func__); + goto bad4; + } + + if (ic->dfs_hw_bd_id != DFS_HWBD_QCA6174) { + dfs->dfs_b5radars_ext_seg = + (struct dfs_bin5radars *)os_malloc(NULL, + numb5radars * + sizeof(struct dfs_bin5radars), + GFP_KERNEL); + if (dfs->dfs_b5radars_ext_seg == NULL) { + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_ERROR, + "%s:Fail allocate memory for ext bin5 radars", + __func__); + goto bad4; + } + } + + for (n = 0; n < numb5radars; n++) { + dfs->dfs_b5radars[n].br_pulse = b5pulses[n]; + dfs->dfs_b5radars[n].br_pulse.b5_timewindow *= + DFS_BIN5_TIME_WINDOW_UNITS_MULTIPLIER; + if (dfs->dfs_b5radars[n].br_pulse.b5_rssithresh < + min_rssithresh) + min_rssithresh = + dfs->dfs_b5radars[n].br_pulse.b5_rssithresh; + + if (dfs->dfs_b5radars[n].br_pulse.b5_maxdur > + max_pulsedur) + max_pulsedur = + dfs->dfs_b5radars[n].br_pulse.b5_maxdur; + } + + if (ic->dfs_hw_bd_id != DFS_HWBD_QCA6174) { + for (n = 0; n < numb5radars; n++) { + dfs->dfs_b5radars_ext_seg[n].br_pulse = + b5pulses[n]; + dfs->dfs_b5radars_ext_seg[n].br_pulse.b5_timewindow *= + DFS_BIN5_TIME_WINDOW_UNITS_MULTIPLIER; + b5_rssithresh = + dfs->dfs_b5radars_ext_seg[n].br_pulse.b5_rssithresh; + + if (b5_rssithresh < min_rssithresh) + min_rssithresh = b5_rssithresh; + + b5_maxdur = + dfs->dfs_b5radars_ext_seg[n].br_pulse.b5_maxdur; + if (b5_maxdur > max_pulsedur) + max_pulsedur = b5_maxdur; + + } + } + } + + dfs_reset_alldelaylines(dfs, DFS_80P80_SEG0); + + if (ic->dfs_hw_bd_id != DFS_HWBD_QCA6174) + dfs_reset_alldelaylines(dfs, DFS_80P80_SEG1); + + dfs_reset_radarq(dfs); + dfs->dfs_curchan_radindex = -1; + dfs->dfs_extchan_radindex = -1; + dfs->dfs_rinfo.rn_minrssithresh = min_rssithresh; + /* Convert durations to TSF ticks */ + dfs->dfs_rinfo.rn_maxpulsedur = + dfs_round((int32_t) ((max_pulsedur * 100 / 80) * 100)); + /* relax the max pulse duration a little bit due to inaccuracy caused by chirping. */ + dfs->dfs_rinfo.rn_maxpulsedur = dfs->dfs_rinfo.rn_maxpulsedur + 20; + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO, + "%s[%d]: DFS min filter rssiThresh = %d", + __func__, __LINE__, min_rssithresh); + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO, + "%s[%d]:DFS max pulse dur = %d ticks", + __func__, __LINE__, dfs->dfs_rinfo.rn_maxpulsedur); + return DFS_STATUS_SUCCESS; + +bad4: + return DFS_STATUS_FAIL; +} + +void dfs_clear_stats(struct ieee80211com *ic) +{ + struct ath_dfs *dfs = (struct ath_dfs *)ic->ic_dfs; + if (dfs == NULL) + return; + OS_MEMZERO(&dfs->ath_dfs_stats, sizeof(struct dfs_stats)); + dfs->ath_dfs_stats.last_reset_tstamp = ic->ic_get_TSF64(ic); +} + +#endif /* ATH_SUPPORT_DFS */ diff --git a/drivers/staging/qcacld-3.0/core/sap/dfs/src/dfs_ioctl.h b/drivers/staging/qcacld-3.0/core/sap/dfs/src/dfs_ioctl.h new file mode 100644 index 0000000000000000000000000000000000000000..abe6c0c8c75e709f7ccb73d68e722562d94749f7 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/sap/dfs/src/dfs_ioctl.h @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2010-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/*=========================================================================== + + dfs_ioctl.h + + OVERVIEW: + + Source code borrowed from QCA_MAIN DFS module + + DEPENDENCIES: + + Are listed for each API below. + + ===========================================================================*/ + +/* + * ioctl defines + */ + +#ifndef _DFS_IOCTL_H_ +#define _DFS_IOCTL_H_ + +#define DFS_MUTE_TIME 1 +#define DFS_SET_THRESH 2 +#define DFS_GET_THRESH 3 +#define DFS_GET_USENOL 4 +#define DFS_SET_USENOL 5 +#define DFS_RADARDETECTS 6 +#define DFS_BANGRADAR 7 +#define DFS_SHOW_NOL 8 +#define DFS_DISABLE_DETECT 9 +#define DFS_ENABLE_DETECT 10 +#define DFS_DISABLE_FFT 11 +#define DFS_ENABLE_FFT 12 +#define DFS_SET_DEBUG_LEVEL 13 +#define DFS_GET_NOL 14 +#define DFS_SET_NOL 15 + +#define DFS_SET_FALSE_RSSI_THRES 16 +#define DFS_SET_PEAK_MAG 17 +#define DFS_IGNORE_CAC 18 +#define DFS_SET_NOL_TIMEOUT 19 +#define DFS_LAST_IOCTL 20 +#ifndef IEEE80211_CHAN_MAX +#define IEEE80211_CHAN_MAX 255 +#endif + +struct dfsreq_nolelem { + uint16_t nol_freq; /* NOL channel frequency */ + uint16_t nol_chwidth; + unsigned long nol_start_ticks; /* OS ticks when the NOL timer started */ + uint32_t nol_timeout_ms; /* Nol timeout value in msec */ +}; + +struct dfsreq_nolinfo { + uint32_t ic_nchans; + struct dfsreq_nolelem dfs_nol[IEEE80211_CHAN_MAX]; +}; + +/* + * ioctl parameter types + */ + +#define DFS_PARAM_FIRPWR 1 +#define DFS_PARAM_RRSSI 2 +#define DFS_PARAM_HEIGHT 3 +#define DFS_PARAM_PRSSI 4 +#define DFS_PARAM_INBAND 5 +/* 5413 specific parameters */ +#define DFS_PARAM_RELPWR 7 +#define DFS_PARAM_RELSTEP 8 +#define DFS_PARAM_MAXLEN 9 + +struct dfs_ioctl_params { + int32_t dfs_firpwr; /* FIR pwr out threshold */ + int32_t dfs_rrssi; /* Radar rssi thresh */ + int32_t dfs_height; /* Pulse height thresh */ + int32_t dfs_prssi; /* Pulse rssi thresh */ + int32_t dfs_inband; /* Inband thresh */ + int32_t dfs_relpwr; /* pulse relative pwr thresh */ + int32_t dfs_relstep; /* pulse relative step thresh */ + int32_t dfs_maxlen; /* pulse max duration */ +}; + +/* + * XXX keep these in sync with ath_dfs_phyerr_param! + */ +#define DFS_IOCTL_PARAM_NOVAL 65535 +#define DFS_IOCTL_PARAM_ENABLE 0x8000 + +#endif /* _DFS_IOCTL_H_ */ diff --git a/drivers/staging/qcacld-3.0/core/sap/dfs/src/dfs_ioctl_private.h b/drivers/staging/qcacld-3.0/core/sap/dfs/src/dfs_ioctl_private.h new file mode 100644 index 0000000000000000000000000000000000000000..6b268b713e86db7df0d5d11d375d27049f920d10 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/sap/dfs/src/dfs_ioctl_private.h @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2010-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/*=========================================================================== + + dfs_ioctl_private.h + + OVERVIEW: + + Source code borrowed from QCA_MAIN DFS module + + DEPENDENCIES: + + Are listed for each API below. + + ===========================================================================*/ + +/* + * ioctl defines + */ + +#ifndef _DFS_IOCTL_PRIVATE_H_ +#define _DFS_IOCTL_PRIVATE_H_ + +/* + * Assert that the NOVAL values match. + */ +#if (ATH_DFS_PHYERR_PARAM_NOVAL != DFS_IOCTL_PARAM_NOVAL) +#error "ATH_DFS_PHYERR_PARAM_NOVAL != DFS_IOCTL_PARAM_NOVAL" +#endif + +/* + * Assert that the ENABLE values match. + */ +#if (ATH_DFS_PHYERR_PARAM_ENABLE != DFS_IOCTL_PARAM_ENABLE) +#error "ATH_DFS_PHYERR_PARAM_ENABLE != DFS_IOCTL_PARAM_ENABLE" +#endif + +/* + * These two methods are used by the lmac glue to copy between + * the DFS and HAL PHY configuration. + * + * I'm "cheating" here and assuming that the ENABLE and NOVAL + * values match - see the above macros. + */ +static inline void +ath_dfs_ioctlparam_to_dfsparam(const struct dfs_ioctl_params *src, + struct ath_dfs_phyerr_param *dst) +{ + + dst->pe_firpwr = src->dfs_firpwr; + dst->pe_rrssi = src->dfs_rrssi; + dst->pe_height = src->dfs_height; + dst->pe_prssi = src->dfs_prssi; + dst->pe_inband = src->dfs_inband; + dst->pe_relpwr = src->dfs_relpwr; + dst->pe_relstep = src->dfs_relstep; + dst->pe_maxlen = src->dfs_maxlen; +} + +static inline void +ath_dfs_dfsparam_to_ioctlparam(struct ath_dfs_phyerr_param *src, + struct dfs_ioctl_params *dst) +{ + + dst->dfs_firpwr = src->pe_firpwr; + dst->dfs_rrssi = src->pe_rrssi; + dst->dfs_height = src->pe_height; + dst->dfs_prssi = src->pe_prssi; + dst->dfs_inband = src->pe_inband; + dst->dfs_relpwr = src->pe_relpwr; + dst->dfs_relstep = src->pe_relstep; + dst->dfs_maxlen = src->pe_maxlen; +} + +#endif /* _DFS_IOCTL_PRIVATE_H_ */ diff --git a/drivers/staging/qcacld-3.0/core/sap/dfs/src/dfs_misc.c b/drivers/staging/qcacld-3.0/core/sap/dfs/src/dfs_misc.c new file mode 100644 index 0000000000000000000000000000000000000000..c06d790d4833b35b3ec9d1a8b9f19bf2c155324e --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/sap/dfs/src/dfs_misc.c @@ -0,0 +1,284 @@ +/* + * Copyright (c) 2002-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/*=========================================================================== + + dfs_misc.c + + OVERVIEW: + + Source code borrowed from QCA_MAIN DFS module + + DEPENDENCIES: + + Are listed for each API below. + + ===========================================================================*/ + +/*=========================================================================== + + EDIT HISTORY FOR FILE + + This section contains comments describing changes made to the module. + Notice that changes are listed in reverse chronological order. + + when who what, where, why + ---------- --- -------------------------------------------------------- + + ===========================================================================*/ + +#include "dfs.h" +/* TO DO DFS + #include + */ +#ifndef UNINET +/* TO DO DFS + #include + */ +#endif +#ifdef ATH_SUPPORT_DFS + +static int adjust_pri_per_chan_busy(int ext_chan_busy, int pri_margin) +{ + int adjust_pri = 0; + + if (ext_chan_busy > DFS_EXT_CHAN_LOADING_THRESH) { + + adjust_pri = + (ext_chan_busy - + DFS_EXT_CHAN_LOADING_THRESH) * (pri_margin); + adjust_pri /= 100; + + } + return adjust_pri; +} + +static int adjust_thresh_per_chan_busy(int ext_chan_busy, int thresh) +{ + int adjust_thresh = 0; + + if (ext_chan_busy > DFS_EXT_CHAN_LOADING_THRESH) { + + adjust_thresh = + (ext_chan_busy - DFS_EXT_CHAN_LOADING_THRESH) * thresh; + adjust_thresh /= 100; + + } + return adjust_thresh; +} + +/* For the extension channel, if legacy traffic is present, we see a lot of false alarms, + so make the PRI margin narrower depending on the busy % for the extension channel.*/ + +int +dfs_get_pri_margin(struct ath_dfs *dfs, int is_extchan_detect, + int is_fixed_pattern) +{ + + int adjust_pri = 0, ext_chan_busy = 0; + int pri_margin; + + if (is_fixed_pattern) + pri_margin = DFS_DEFAULT_FIXEDPATTERN_PRI_MARGIN; + else + pri_margin = DFS_DEFAULT_PRI_MARGIN; + + qdf_spin_lock_bh(&dfs->ic->chan_lock); + if (IS_CHAN_HT40(dfs->ic->ic_curchan)) { + qdf_spin_unlock_bh(&dfs->ic->chan_lock); + ext_chan_busy = dfs->ic->ic_get_ext_busy(dfs->ic); + if (ext_chan_busy >= 0) { + dfs->dfs_rinfo.ext_chan_busy_ts = + dfs->ic->ic_get_TSF64(dfs->ic); + dfs->dfs_rinfo.dfs_ext_chan_busy = ext_chan_busy; + } else { + /* Check to see if the cached value of ext_chan_busy can be used */ + ext_chan_busy = 0; + if (dfs->dfs_rinfo.dfs_ext_chan_busy) { + if (dfs->dfs_rinfo.rn_lastfull_ts < + dfs->dfs_rinfo.ext_chan_busy_ts) { + ext_chan_busy = + dfs->dfs_rinfo.dfs_ext_chan_busy; + DFS_DPRINTK(dfs, ATH_DEBUG_DFS2, + " PRI Use cached copy of ext_chan_busy extchanbusy=%d \n", + ext_chan_busy); + } + } + } + adjust_pri = + adjust_pri_per_chan_busy(ext_chan_busy, pri_margin); + + pri_margin -= adjust_pri; + } else { + qdf_spin_unlock_bh(&dfs->ic->chan_lock); + } + return pri_margin; +} + +/* For the extension channel, if legacy traffic is present, we see a lot of false alarms, + so make the thresholds higher depending on the busy % for the extension channel.*/ + +int dfs_get_filter_threshold(struct ath_dfs *dfs, struct dfs_filter *rf, + int is_extchan_detect) +{ + int ext_chan_busy = 0; + int thresh, adjust_thresh = 0; + + thresh = rf->rf_threshold; + + qdf_spin_lock_bh(&dfs->ic->chan_lock); + if (IS_CHAN_HT40(dfs->ic->ic_curchan)) { + qdf_spin_unlock_bh(&dfs->ic->chan_lock); + ext_chan_busy = dfs->ic->ic_get_ext_busy(dfs->ic); + if (ext_chan_busy >= 0) { + dfs->dfs_rinfo.ext_chan_busy_ts = + dfs->ic->ic_get_TSF64(dfs->ic); + dfs->dfs_rinfo.dfs_ext_chan_busy = ext_chan_busy; + } else { + /* Check to see if the cached value of ext_chan_busy can be used */ + ext_chan_busy = 0; + if (dfs->dfs_rinfo.dfs_ext_chan_busy) { + if (dfs->dfs_rinfo.rn_lastfull_ts < + dfs->dfs_rinfo.ext_chan_busy_ts) { + ext_chan_busy = + dfs->dfs_rinfo.dfs_ext_chan_busy; + DFS_DPRINTK(dfs, ATH_DEBUG_DFS2, + " THRESH Use cached copy of ext_chan_busy extchanbusy=%d rn_lastfull_ts=%llu ext_chan_busy_ts=%llu\n", + ext_chan_busy, + (unsigned long long)dfs-> + dfs_rinfo.rn_lastfull_ts, + (unsigned long long)dfs-> + dfs_rinfo.ext_chan_busy_ts); + } + } + } + + adjust_thresh = + adjust_thresh_per_chan_busy(ext_chan_busy, thresh); + + DFS_DPRINTK(dfs, ATH_DEBUG_DFS2, + " filterID=%d extchanbusy=%d adjust_thresh=%d\n", + rf->rf_pulseid, ext_chan_busy, adjust_thresh); + + thresh += adjust_thresh; + } else { + qdf_spin_unlock_bh(&dfs->ic->chan_lock); + } + return thresh; +} + +uint32_t dfs_round(int32_t val) +{ + uint32_t ival, rem; + + if (val < 0) + return 0; + ival = val / 100; + rem = val - (ival * 100); + if (rem < 50) + return ival; + else + return ival + 1; +} + +struct dfs_ieee80211_channel *ieee80211_get_extchan(struct ieee80211com *ic) +{ + int chan_offset = 0; + if (IEEE80211_IS_CHAN_HT40PLUS_CAPABLE(ic->ic_curchan)) { + chan_offset = 20; + } else if (IEEE80211_IS_CHAN_HT40MINUS_CAPABLE(ic->ic_curchan)) { + chan_offset = -20; + } else { + return NULL; + } + return (ic-> + ic_find_channel(ic, ic->ic_curchan->ic_freq + chan_offset, + IEEE80211_CHAN_11NA_HT20)); +} + +/* + * Finds the radar state entry that matches the current channel + */ +struct dfs_state *dfs_getchanstate(struct ath_dfs *dfs, uint8_t *index, + int ext_chan_flag) +{ + struct dfs_state *rs = NULL; + int i; + struct dfs_ieee80211_channel *cmp_ch; + + if (dfs == NULL) { + printk("%s[%d]: sc_dfs is NULL\n", __func__, __LINE__); + /* DFS_DPRINTK(dfs, ATH_DEBUG_DFS,"%s: sc_dfs is NULL\n",__func__); */ + return NULL; + } + + if (ext_chan_flag) { + cmp_ch = ieee80211_get_extchan(dfs->ic); + if (cmp_ch) { + DFS_DPRINTK(dfs, ATH_DEBUG_DFS2, + "Extension channel freq = %u flags=0x%x\n", + cmp_ch->ic_freq, cmp_ch->ic_flagext); + } else { + return NULL; + } + + } else { + cmp_ch = dfs->ic->ic_curchan; + DFS_DPRINTK(dfs, ATH_DEBUG_DFS2, + "Primary channel freq = %u flags=0x%x\n", + cmp_ch->ic_freq, cmp_ch->ic_flagext); + } + for (i = 0; i < DFS_NUM_RADAR_STATES; i++) { + if ((dfs->dfs_radar[i].rs_chan.ic_freq == cmp_ch->ic_freq) && + (dfs->dfs_radar[i].rs_chan.ic_flags == cmp_ch->ic_flags)) { + if (index != NULL) + *index = (uint8_t) i; + return &(dfs->dfs_radar[i]); + } + } + /* No existing channel found, look for first free channel state entry */ + for (i = 0; i < DFS_NUM_RADAR_STATES; i++) { + if (dfs->dfs_radar[i].rs_chan.ic_freq == 0) { + rs = &(dfs->dfs_radar[i]); + /* Found one, set channel info and default thresholds */ + rs->rs_chan = *cmp_ch; + + /* Copy the parameters from the default set */ + ath_dfs_phyerr_param_copy(&rs->rs_param, + &dfs->dfs_defaultparams); + + if (index != NULL) + *index = (uint8_t) i; + return rs; + } + } + DFS_DPRINTK(dfs, ATH_DEBUG_DFS2, "%s: No more radar states left.\n", + __func__); + return NULL; +} + +#endif /* ATH_SUPPORT_DFS */ diff --git a/drivers/staging/qcacld-3.0/core/sap/dfs/src/dfs_nol.c b/drivers/staging/qcacld-3.0/core/sap/dfs/src/dfs_nol.c new file mode 100644 index 0000000000000000000000000000000000000000..85810bcd2b058c22732377a943a291de65f86695 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/sap/dfs/src/dfs_nol.c @@ -0,0 +1,405 @@ +/* + * Copyright (c) 2002-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/*=========================================================================== + + dfs_nol.c + + OVERVIEW: + + Source code borrowed from QCA_MAIN DFS module + + DEPENDENCIES: + + Are listed for each API below. + + ===========================================================================*/ + +/*=========================================================================== + + EDIT HISTORY FOR FILE + + This section contains comments describing changes made to the module. + Notice that changes are listed in reverse chronological order. + + when who what, where, why + ---------- --- -------------------------------------------------------- + + ===========================================================================*/ + +#include "dfs.h" +/* TO DO DFS + #include + */ +#ifndef UNINET +/*TO DO DFS + #include + */ +#endif +#if defined(ATH_SUPPORT_DFS) && !defined(ATH_DFS_RADAR_DETECTION_ONLY) +#include "dfs_ioctl.h" +#include "dfs_ioctl_private.h" +#include "qdf_time.h" /* qdf_time_t, qdf_system_time_after */ + +static void +dfs_nol_delete(struct ath_dfs *dfs, uint16_t delfreq, uint16_t delchwidth); + +static os_timer_func(dfs_remove_from_nol) +{ + struct dfs_nol_timer_arg *nol_arg; + struct ath_dfs *dfs; + struct ieee80211com *ic; + uint16_t delfreq; + uint16_t delchwidth; + + OS_GET_TIMER_ARG(nol_arg, struct dfs_nol_timer_arg *); + + dfs = nol_arg->dfs; + ic = dfs->ic; + delfreq = nol_arg->delfreq; + delchwidth = nol_arg->delchwidth; + + /* Only operate in HOSTAP/IBSS */ + if (ic->ic_opmode != IEEE80211_M_HOSTAP && + ic->ic_opmode != IEEE80211_M_IBSS) + goto done; + + /* Delete the given NOL entry */ + dfs_nol_delete(dfs, delfreq, delchwidth); + + /* Update the wireless stack with the new NOL */ + dfs_nol_update(dfs); + +done: + OS_FREE(nol_arg); + return; +} + +void dfs_print_nol(struct ath_dfs *dfs) +{ + struct dfs_nolelem *nol; + uint32_t diff_ms, remaining_sec; + + if (dfs == NULL) { + DFS_DPRINTK(dfs, ATH_DEBUG_DFS_NOL, "%s: sc_dfs is NULL", + __func__); + return; + } + nol = dfs->dfs_nol; + DFS_DPRINTK(dfs, ATH_DEBUG_DFS_NOL, "%s: NOL", __func__); + while (nol != NULL) { + diff_ms = + qdf_system_ticks_to_msecs(qdf_system_ticks() - + nol->nol_start_ticks); + diff_ms = (nol->nol_timeout_ms - diff_ms); + remaining_sec = diff_ms / 1000; /* convert to seconds */ + nol = nol->nol_next; + } +} + +void +dfs_get_nol(struct ath_dfs *dfs, struct dfsreq_nolelem *dfs_nol, int *nchan) +{ + struct dfs_nolelem *nol; + + *nchan = 0; + + if (dfs == NULL) { + DFS_DPRINTK(dfs, ATH_DEBUG_DFS_NOL, "%s: sc_dfs is NULL", + __func__); + return; + } + + nol = dfs->dfs_nol; + while (nol != NULL) { + dfs_nol[*nchan].nol_freq = nol->nol_freq; + dfs_nol[*nchan].nol_chwidth = nol->nol_chwidth; + dfs_nol[*nchan].nol_start_ticks = nol->nol_start_ticks; + dfs_nol[*nchan].nol_timeout_ms = nol->nol_timeout_ms; + ++(*nchan); + nol = nol->nol_next; + } +} + +void dfs_set_nol(struct ath_dfs *dfs, struct dfsreq_nolelem *dfs_nol, int nchan) +{ +#define TIME_IN_MS 1000 + uint32_t nol_time_left_ms; + struct dfs_ieee80211_channel chan; + int i; + + if (dfs == NULL) { + DFS_DPRINTK(dfs, ATH_DEBUG_DFS_NOL, "%s: sc_dfs is NULL", + __func__); + return; + } + + for (i = 0; i < nchan; i++) { + nol_time_left_ms = + qdf_system_ticks_to_msecs(qdf_system_ticks() - + dfs_nol[i].nol_start_ticks); + if (nol_time_left_ms < dfs_nol[i].nol_timeout_ms) { + chan.ic_freq = dfs_nol[i].nol_freq; + chan.ic_flags = 0; + chan.ic_flagext = 0; + nol_time_left_ms = + (dfs_nol[i].nol_timeout_ms - nol_time_left_ms); + dfs_nol_addchan(dfs, &chan, + (nol_time_left_ms / TIME_IN_MS)); + } + } +#undef TIME_IN_MS + dfs_nol_update(dfs); +} + +void +dfs_nol_addchan(struct ath_dfs *dfs, struct dfs_ieee80211_channel *chan, + uint32_t dfs_nol_timeout) +{ +#define TIME_IN_MS 1000 +#define TIME_IN_US (TIME_IN_MS * 1000) + struct dfs_nolelem *nol, *elem, *prev; + struct dfs_nol_timer_arg *dfs_nol_arg; + /* XXX for now, assume all events are 20MHz wide */ + int ch_width = 20; + + if (dfs == NULL) { + DFS_DPRINTK(dfs, ATH_DEBUG_DFS_NOL, "%s: sc_dfs is NULL", + __func__); + return; + } + nol = dfs->dfs_nol; + prev = dfs->dfs_nol; + elem = NULL; + while (nol != NULL) { + if ((nol->nol_freq == chan->ic_freq) && + (nol->nol_chwidth == ch_width)) { + nol->nol_start_ticks = qdf_system_ticks(); + nol->nol_timeout_ms = dfs_nol_timeout * TIME_IN_MS; + DFS_DPRINTK(dfs, ATH_DEBUG_DFS_NOL, + "%s: Update OS Ticks for NOL %d MHz / %d MHz", + __func__, nol->nol_freq, nol->nol_chwidth); + OS_CANCEL_TIMER(&nol->nol_timer); + OS_SET_TIMER(&nol->nol_timer, + dfs_nol_timeout * TIME_IN_MS); + return; + } + prev = nol; + nol = nol->nol_next; + } + /* Add a new element to the NOL */ + elem = + (struct dfs_nolelem *)os_malloc(NULL, sizeof(struct dfs_nolelem), + GFP_ATOMIC); + if (elem == NULL) { + goto bad; + } + dfs_nol_arg = (struct dfs_nol_timer_arg *)os_malloc(NULL, + sizeof(struct + dfs_nol_timer_arg), + GFP_ATOMIC); + if (dfs_nol_arg == NULL) { + OS_FREE(elem); + goto bad; + } + elem->nol_freq = chan->ic_freq; + elem->nol_chwidth = ch_width; + elem->nol_start_ticks = qdf_system_ticks(); + elem->nol_timeout_ms = dfs_nol_timeout * TIME_IN_MS; + elem->nol_next = NULL; + if (prev) { + prev->nol_next = elem; + } else { + /* This is the first element in the NOL */ + dfs->dfs_nol = elem; + } + dfs_nol_arg->dfs = dfs; + dfs_nol_arg->delfreq = elem->nol_freq; + dfs_nol_arg->delchwidth = elem->nol_chwidth; + + OS_INIT_TIMER(NULL, &elem->nol_timer, dfs_remove_from_nol, + dfs_nol_arg, QDF_TIMER_TYPE_SW); + OS_SET_TIMER(&elem->nol_timer, dfs_nol_timeout * TIME_IN_MS); + + /* Update the NOL counter */ + dfs->dfs_nol_count++; + + DFS_DPRINTK(dfs, ATH_DEBUG_DFS_NOL, + "%s: new NOL channel %d MHz / %d MHz", + __func__, elem->nol_freq, elem->nol_chwidth); + return; + +bad: + DFS_DPRINTK(dfs, ATH_DEBUG_DFS_NOL | ATH_DEBUG_DFS, + "%s: failed to allocate memory for nol entry", __func__); + +#undef TIME_IN_MS +#undef TIME_IN_US +} + +/* + * Delete the given frequency/chwidth from the NOL. + */ +static void +dfs_nol_delete(struct ath_dfs *dfs, uint16_t delfreq, uint16_t delchwidth) +{ + struct dfs_nolelem *nol, **prev_next; + + if (dfs == NULL) { + DFS_DPRINTK(dfs, ATH_DEBUG_DFS, "%s: sc_dfs is NULL", __func__); + return; + } + + DFS_DPRINTK(dfs, ATH_DEBUG_DFS_NOL, + "%s: remove channel=%d/%d MHz from NOL", + __func__, delfreq, delchwidth); + prev_next = &(dfs->dfs_nol); + nol = dfs->dfs_nol; + while (nol != NULL) { + if (nol->nol_freq == delfreq && nol->nol_chwidth == delchwidth) { + *prev_next = nol->nol_next; + DFS_DPRINTK(dfs, ATH_DEBUG_DFS_NOL, + "%s removing channel %d/%dMHz from NOL tstamp=%d", + __func__, nol->nol_freq, nol->nol_chwidth, + (qdf_system_ticks_to_msecs + (qdf_system_ticks()) / 1000)); + OS_CANCEL_TIMER(&nol->nol_timer); + OS_FREE(nol); + nol = NULL; + nol = *prev_next; + + /* Update the NOL counter */ + dfs->dfs_nol_count--; + + /* Be paranoid! */ + if (dfs->dfs_nol_count < 0) { + DFS_PRINTK("%s: dfs_nol_count < 0; eek!", + __func__); + dfs->dfs_nol_count = 0; + } + + } else { + prev_next = &(nol->nol_next); + nol = nol->nol_next; + } + } +} + +/* + * notify the driver/umac that it should update the channel radar/NOL + * flags based on the current NOL list. + */ +void dfs_nol_update(struct ath_dfs *dfs) +{ + struct ieee80211com *ic = dfs->ic; + struct dfs_nol_chan_entry *dfs_nol; + struct dfs_nolelem *nol; + int nlen; + + /* + * Allocate enough entries to store the NOL. + * + * At least on Linux (don't ask why), if you allocate a 0 entry + * array, the returned pointer is 0x10. Make sure you're + * aware of this when you start debugging. + */ + dfs_nol = (struct dfs_nol_chan_entry *)os_malloc(NULL, + sizeof(struct + dfs_nol_chan_entry) + * dfs->dfs_nol_count, + GFP_ATOMIC); + + if (dfs_nol == NULL) { + /* + * XXX TODO: if this fails, just schedule a task to retry + * updating the NOL at a later stage. That way the NOL + * update _DOES_ happen - hopefully the failure was just + * temporary. + */ + DFS_PRINTK("%s: failed to allocate NOL update memory!", + __func__); + return; + } + + /* populate the nol array */ + nlen = 0; + + nol = dfs->dfs_nol; + while (nol != NULL && nlen < dfs->dfs_nol_count) { + dfs_nol[nlen].nol_chfreq = nol->nol_freq; + dfs_nol[nlen].nol_chwidth = nol->nol_chwidth; + dfs_nol[nlen].nol_start_ticks = nol->nol_start_ticks; + dfs_nol[nlen].nol_timeout_ms = nol->nol_timeout_ms; + nlen++; + nol = nol->nol_next; + } + + /* Be suitably paranoid for now */ + if (nlen != dfs->dfs_nol_count) + DFS_PRINTK("%s: nlen (%d) != dfs->dfs_nol_count (%d)!", + __func__, nlen, dfs->dfs_nol_count); + + /* + * Call the driver layer to have it recalculate the NOL flags for + * each driver/umac channel. + * + * If the list is empty, pass NULL instead of dfs_nol. + * + * The operating system may have some special representation for + * "malloc a 0 byte memory region" - for example, + * Linux 2.6.38-13 (ubuntu) returns 0x10 rather than a valid + * allocation (and is likely not NULL so the pointer doesn't + * match NULL checks in any later code. + */ + ic->ic_dfs_clist_update(ic, DFS_NOL_CLIST_CMD_UPDATE, + (nlen > 0) ? dfs_nol : NULL, nlen); + + /* + * .. and we're done. + */ + OS_FREE(dfs_nol); +} + +void dfs_nol_timer_cleanup(struct ath_dfs *dfs) +{ + struct dfs_nolelem *nol = dfs->dfs_nol, *prev; + + /* First Cancel timer */ + while (nol) { + OS_CANCEL_TIMER(&nol->nol_timer); + nol = nol->nol_next; + } + /* Free NOL elem, don't mix this while loop with above loop */ + nol = dfs->dfs_nol; + while (nol) { + prev = nol; + nol = nol->nol_next; + OS_FREE(prev); + } + return; +} +#endif /* defined(ATH_SUPPORT_DFS) && !defined(ATH_DFS_RADAR_DETECTION_ONLY) */ diff --git a/drivers/staging/qcacld-3.0/core/sap/dfs/src/dfs_phyerr.h b/drivers/staging/qcacld-3.0/core/sap/dfs/src/dfs_phyerr.h new file mode 100644 index 0000000000000000000000000000000000000000..22a900f2e06003b7d5d084747d682d1d58390164 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/sap/dfs/src/dfs_phyerr.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * dfs_phyerr.h + * + * OVERVIEW: + * + * Source code borrowed from QCA_MAIN DFS module + * + * DEPENDENCIES: + * + * Are listed for each API below. + */ + + +#ifndef __DFS_PHYERR_H__ +#define __DFS_PHYERR_H__ + +extern int dfs_process_phyerr_bb_tlv(struct ath_dfs *dfs, void *buf, + uint16_t datalen, uint8_t rssi, + uint8_t ext_rssi, uint32_t rs_tstamp, + uint64_t fulltsf, struct dfs_phy_err *e, + bool enable_log); + +#endif /* __DFS_PHYERR_H__ */ diff --git a/drivers/staging/qcacld-3.0/core/sap/dfs/src/dfs_phyerr_tlv.c b/drivers/staging/qcacld-3.0/core/sap/dfs/src/dfs_phyerr_tlv.c new file mode 100644 index 0000000000000000000000000000000000000000..e232efee541bb67b4ccdc540f24fde709d513ba8 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/sap/dfs/src/dfs_phyerr_tlv.c @@ -0,0 +1,946 @@ +/* + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#include "dfs.h" +/* TO DO DFS + #include + */ +/* TO DO DFS + #include + */ +#include "dfs_phyerr.h" +#include "dfs_phyerr_tlv.h" + +/* + * Parsed radar status + */ +struct rx_radar_status { + uint32_t raw_tsf; + uint32_t tsf_offset; + int rssi; + int pulse_duration; + int is_chirp:1; + int delta_peak; + int delta_diff; + int sidx; + int freq_offset; /* in KHz */ + int agc_total_gain; + int agc_mb_gain; + /*Parsed only for DFS-3*/ + int radar_subchan_mask; + int rsu_version; + /* + * The parameters below are present only in + * DFS-3 radar summary report and need to be + * parsed only for DFS-3. + */ + /* DFS-3 Only */ + int pulse_height; + /* DFS-3 Only */ + int triggering_agc_event; + /* DFS-3 Only */ + int pulse_rssi; + /* DFS-3 Only */ + int radar_fft_pri80_inband_power; + /* DFS-3 Only */ + int radar_fft_ext80_inband_power; + /* DFS-3 Only */ + int radar_80p80_segid; +}; + +struct rx_search_fft_report { + uint32_t total_gain_db; + uint32_t base_pwr_db; + int fft_chn_idx; + int peak_sidx; + int relpwr_db; + int avgpwr_db; + int peak_mag; + int num_str_bins_ib; +}; + +/* + * XXX until "fastclk" is stored in the DFS configuration.. + */ +#define PERE_IS_OVERSAMPLING(_dfs) (1) + +/* + * XXX there _has_ to be a better way of doing this! + * -adrian + */ +static int32_t sign_extend_32(uint32_t v, int nb) +{ + uint32_t m = 1U << (nb - 1); + + /* Chop off high bits, just in case */ + v &= v & ((1U << nb) - 1); + + /* Extend */ + return (v ^ m) - m; +} + +/* + * Calculate the frequency offset from the given signed bin index + * from the radar summary report. + * + * This takes the oversampling mode into account. + * + * For oversampling, each bin has resolution 44MHz/128. + * For non-oversampling, each bin has resolution 40MHz/128. + * + * It returns kHz - ie, 1000th's of MHz. + */ +static int calc_freq_offset(int sindex, int is_oversampling) +{ + + if (is_oversampling) + return sindex * (44000 / 128); + else + return sindex * (40000 / 128); +} + +static void +radar_summary_print(struct ath_dfs *dfs, + struct rx_radar_status *rsu, + bool enable_log) +{ + int is_chip_oversampling; + + if (!enable_log) + return; + + /* + * Oversampling needs to be turned on for + * older chipsets that support DFS-2. + * it needs to be turned off for chips + * that support DFS-3. + */ + if (dfs->ic->dfs_hw_bd_id != DFS_HWBD_QCA6174) + is_chip_oversampling = 0; + else + is_chip_oversampling = PERE_IS_OVERSAMPLING(dfs); + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO, + "\n ############ Radar Summary ############\n"); + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO, + "%s: Radar Summary - pulsedur = %d micro seconds\n", __func__, + rsu->pulse_duration); + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO, + "%s: Radar Summary - rssi = %d dbm\n", __func__, + rsu->rssi); + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO, + "%s: Radar Summary - ischirp = %d\n", __func__, + rsu->is_chirp); + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO, + "%s: Radar Summary - sidx = %d\n", __func__, + rsu->sidx); + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO, + "%s: Radar Summary - delta_peak = %d\n", __func__, + rsu->delta_peak); + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO, + "%s: Radar Summary - delta_diff = %d\n", __func__, + rsu->delta_diff); + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO, + "%s: Radar Summary - raw tsf = %d\n", __func__, + rsu->raw_tsf); + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO, + "%s: Radar Summary - tsf_offset = %d micro seconds\n", + __func__, rsu->tsf_offset); + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO, + "%s: Radar Summary - cooked tsf = %d\n", __func__, + (rsu->raw_tsf - rsu->tsf_offset)); + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO, + "%s: frequency offset = %d.%d MHz (oversampling = %d)\n", + __func__, (int) (rsu->freq_offset / 1000), + (int) abs(rsu->freq_offset % 1000), + is_chip_oversampling); + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO, + "\n ###################################\n"); +} + +/* + * Parse the radar summary frame. + * + * The frame contents _minus_ the TLV are passed in. + */ +static void +radar_summary_parse(struct ath_dfs *dfs, const char *buf, size_t len, + struct rx_radar_status *rsu) +{ + uint32_t rs[2]; + uint32_t dfs3_rs[5]; + int freq_centre, freq; + int is_chip_oversampling; + + /* + * Drop out if we have < 2 DWORDs available for DFS-2 + * and drop out if we have < 5 DWORDS available for DFS-3 + */ + if ((dfs->ic->dfs_hw_bd_id == DFS_HWBD_QCA6174) && + (len < sizeof(rs))) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: DFS-2 radar summary len = (%zu) wrong, expected = (%zu)", + __func__, len, sizeof(rs)); + } else if ((dfs->ic->dfs_hw_bd_id != DFS_HWBD_QCA6174) && + (len < sizeof(dfs3_rs))) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: DFS-3 radar summary len = (%zu) wrong, expected = (%zu)", + __func__, len, sizeof(dfs3_rs)); + } + + /* + * If the length of TLV is equal to + * DFS3_RADAR_PULSE_SUMMARY_TLV_LENGTH + * then it means the radar summary report + * has 5 DWORDS and we need to parse the + * report accordingly. + * Else if the length is equal to + * DFS2_RADAR_PULSE_SUMMARY_TLV_LENGTH then + * it the radar summary report will have only + * two DWORDS so we parse for only two DWORDS. + */ + if (len == DFS3_RADAR_PULSE_SUMMARY_TLV_LENGTH) { + /* + * Since the TLVs may be unaligned for some reason + * we take a private copy into aligned memory. + * This enables us to use the HAL-like accessor macros + * into the DWORDs to access sub-DWORD fields. + */ + OS_MEMCPY(dfs3_rs, buf, sizeof(dfs3_rs)); + + /* + * Oversampling is only needed to be + * turned on for older chips that support + * DFS-2. It needs to be turned off for chips + * that support DFS-3. + */ + is_chip_oversampling = 0; + + /* + * populate the version of the radar summary report + * based on the TLV length to differentiate between + * DFS-2 and DFS-3 radar summary report. + */ + rsu->rsu_version = DFS_RADAR_SUMMARY_REPORT_VERSION_3; + + /* Populate the fields from the summary report */ + rsu->tsf_offset = MS(dfs3_rs[RADAR_REPORT_PULSE_REG_2], + RADAR_REPORT_PULSE_TSF_OFFSET); + rsu->pulse_duration = MS(dfs3_rs[RADAR_REPORT_PULSE_REG_2], + RADAR_REPORT_PULSE_DUR); + rsu->is_chirp = MS(dfs3_rs[RADAR_REPORT_PULSE_REG_1], + RADAR_REPORT_PULSE_IS_CHIRP); + rsu->sidx = sign_extend_32(MS(dfs3_rs[RADAR_REPORT_PULSE_REG_1], + RADAR_REPORT_PULSE_SIDX), 10); + rsu->freq_offset = calc_freq_offset(rsu->sidx, + is_chip_oversampling); + /* These are only relevant if the pulse is a chirp */ + rsu->delta_peak = sign_extend_32( + MS(dfs3_rs[RADAR_REPORT_PULSE_REG_1], + RADAR_REPORT_PULSE_DELTA_PEAK), + 6); + rsu->delta_diff = MS(dfs3_rs[RADAR_REPORT_PULSE_REG_1], + RADAR_REPORT_PULSE_DELTA_DIFF); + /* For false detection Debug */ + rsu->agc_total_gain = MS(dfs3_rs[RADAR_REPORT_PULSE_REG_1], + RADAR_REPORT_AGC_TOTAL_GAIN); + rsu->agc_mb_gain = MS(dfs3_rs[RADAR_REPORT_PULSE_REG_2], + RADAR_REPORT_PULSE_AGC_MB_GAIN); + /* + * radar_subchan_mask will be used in the future to identify the + * sub channel that encoutered radar pulses and block those + * channels in NOL accordingly. + */ + rsu->radar_subchan_mask = MS(dfs3_rs[RADAR_REPORT_PULSE_REG_2], + RADAR_REPORT_PULSE_SUBCHAN_MASK); + + rsu->pulse_height = MS(dfs3_rs[RADAR_REPORT_PULSE_REG_3], + RADAR_REPORT_PULSE_HEIGHT); + rsu->triggering_agc_event = + MS(dfs3_rs[RADAR_REPORT_PULSE_REG_4], + RADAR_REPORT_TRIGGERING_AGC_EVENT); + rsu->pulse_rssi = MS(dfs3_rs[RADAR_REPORT_PULSE_REG_4], + RADAR_REPORT_PULSE_RSSI); + rsu->radar_fft_pri80_inband_power = + MS(dfs3_rs[RADAR_REPORT_PULSE_REG_5], + RADAR_REPORT_FFT_PRI80_INBAND_POWER); + rsu->radar_fft_ext80_inband_power = + MS(dfs3_rs[RADAR_REPORT_PULSE_REG_5], + RADAR_REPORT_FFT_EXT80_INBAND_POWER); + rsu->radar_80p80_segid = MS(dfs3_rs[RADAR_REPORT_PULSE_REG_5], + RADAR_REPORT_80P80_SEGID); + } else { + /* + * Since the TLVs may be unaligned for some reason + * we take a private copy into aligned memory. + * This enables us to use the HAL-like accessor macros + * into the DWORDs to access sub-DWORD fields. + */ + OS_MEMCPY(rs, buf, sizeof(rs)); + + DFS_DPRINTK(dfs, ATH_DEBUG_DFS_PHYERR, + "%s: two 32 bit values are: %08x %08x", __func__, rs[0], + rs[1]); + /* + * DFS_DPRINTK(dfs, ATH_DEBUG_DFS_PHYERR, + "%s (p=%p):", __func__, buf); + */ + + is_chip_oversampling = PERE_IS_OVERSAMPLING(dfs); + /* + * populate the version of the radar summary report + * based on the TLV length to differentiate between + * DFS-2 and DFS-3 radar summary report. + */ + rsu->rsu_version = DFS_RADAR_SUMMARY_REPORT_VERSION_2; + + /* Populate the fields from the summary report */ + rsu->tsf_offset = + MS(rs[RADAR_REPORT_PULSE_REG_2], + RADAR_REPORT_PULSE_TSF_OFFSET); + rsu->pulse_duration = + MS(rs[RADAR_REPORT_PULSE_REG_2], + RADAR_REPORT_PULSE_DUR); + rsu->is_chirp = + MS(rs[RADAR_REPORT_PULSE_REG_1], + RADAR_REPORT_PULSE_IS_CHIRP); + rsu->sidx = + sign_extend_32(MS(rs[RADAR_REPORT_PULSE_REG_1], + RADAR_REPORT_PULSE_SIDX), 10); + rsu->freq_offset = + calc_freq_offset(rsu->sidx, is_chip_oversampling); + + /* These are only relevant if the pulse is a chirp */ + rsu->delta_peak = + sign_extend_32(MS(rs[RADAR_REPORT_PULSE_REG_1], + RADAR_REPORT_PULSE_DELTA_PEAK), 6); + rsu->delta_diff = + MS(rs[RADAR_REPORT_PULSE_REG_1], + RADAR_REPORT_PULSE_DELTA_DIFF); + + /* For false detection Debug */ + rsu->agc_total_gain = + MS(rs[RADAR_REPORT_PULSE_REG_1], + RADAR_REPORT_AGC_TOTAL_GAIN); + rsu->agc_mb_gain = + MS(rs[RADAR_REPORT_PULSE_REG_2], + RADAR_REPORT_PULSE_AGC_MB_GAIN); + + } + + /* WAR for FCC Type 4 */ + /* + * HW is giving longer pulse duration (in case of VHT80, with traffic) + * which fails to detect FCC type4 radar pulses. Added a work around to + * fix the pulse duration and duration delta. + * + * IF VHT80 + * && (primary_channel==30MHz || primary_channel== -30MHz) + * && -4 <= pulse_index <= 4 + * && !chirp + * && pulse duration > 20 us + * THEN + * Set pulse duration to 20 us + */ + + qdf_spin_lock_bh(&dfs->ic->chan_lock); + freq = ieee80211_chan2freq(dfs->ic, dfs->ic->ic_curchan); + freq_centre = dfs->ic->ic_curchan->ic_vhtop_ch_freq_seg1; + + if ((IEEE80211_IS_CHAN_11AC_VHT80(dfs->ic->ic_curchan) && + (abs(freq - freq_centre) == 30) && + !rsu->is_chirp && + abs(rsu->sidx) <= 4 && rsu->pulse_duration > 20)) { + rsu->pulse_duration = 20; + } + + qdf_spin_unlock_bh(&dfs->ic->chan_lock); +} + +static void +radar_fft_search_report_parse(struct ath_dfs *dfs, const char *buf, size_t len, + struct rx_search_fft_report *rsfr) +{ + uint32_t rs[2]; + + /* Drop out if we have < 2 DWORDs available */ + if (len < sizeof(rs)) { + DFS_DPRINTK(dfs, ATH_DEBUG_DFS_PHYERR | + ATH_DEBUG_DFS_PHYERR_SUM, + "%s: len (%zu) < expected (%zu)!", + __func__, len, sizeof(rs)); + } + + /* + * Since the TLVs may be unaligned for some reason + * we take a private copy into aligned memory. + * This enables us to use the HAL-like accessor macros + * into the DWORDs to access sub-DWORD fields. + */ + OS_MEMCPY(rs, buf, sizeof(rs)); + rsfr->total_gain_db = + MS(rs[SEARCH_FFT_REPORT_REG_1], + SEARCH_FFT_REPORT_TOTAL_GAIN_DB); + rsfr->base_pwr_db = + MS(rs[SEARCH_FFT_REPORT_REG_1], SEARCH_FFT_REPORT_BASE_PWR_DB); + rsfr->fft_chn_idx = + MS(rs[SEARCH_FFT_REPORT_REG_1], SEARCH_FFT_REPORT_FFT_CHN_IDX); + rsfr->peak_sidx = + sign_extend_32(MS + (rs[SEARCH_FFT_REPORT_REG_1], + SEARCH_FFT_REPORT_PEAK_SIDX), 12); + rsfr->relpwr_db = + MS(rs[SEARCH_FFT_REPORT_REG_2], SEARCH_FFT_REPORT_RELPWR_DB); + rsfr->avgpwr_db = + MS(rs[SEARCH_FFT_REPORT_REG_2], SEARCH_FFT_REPORT_AVGPWR_DB); + rsfr->peak_mag = + MS(rs[SEARCH_FFT_REPORT_REG_2], SEARCH_FFT_REPORT_PEAK_MAG); + rsfr->num_str_bins_ib = + MS(rs[SEARCH_FFT_REPORT_REG_2], + SEARCH_FFT_REPORT_NUM_STR_BINS_IB); + + DFS_DPRINTK(dfs, ATH_DEBUG_DFS_PHYERR, + "%s: two 32 bit values are: %08x %08x", __func__, rs[0], + rs[1]); + DFS_DPRINTK(dfs, ATH_DEBUG_DFS_PHYERR, "%s: rsfr->total_gain_db = %d", + __func__, rsfr->total_gain_db); + DFS_DPRINTK(dfs, ATH_DEBUG_DFS_PHYERR, "%s: rsfr->base_pwr_db = %d", + __func__, rsfr->base_pwr_db); + DFS_DPRINTK(dfs, ATH_DEBUG_DFS_PHYERR, "%s: rsfr->fft_chn_idx = %d", + __func__, rsfr->fft_chn_idx); + DFS_DPRINTK(dfs, ATH_DEBUG_DFS_PHYERR, "%s: rsfr->peak_sidx = %d", + __func__, rsfr->peak_sidx); + DFS_DPRINTK(dfs, ATH_DEBUG_DFS_PHYERR, "%s: rsfr->relpwr_db = %d", + __func__, rsfr->relpwr_db); + DFS_DPRINTK(dfs, ATH_DEBUG_DFS_PHYERR, "%s: rsfr->avgpwr_db = %d", + __func__, rsfr->avgpwr_db); + DFS_DPRINTK(dfs, ATH_DEBUG_DFS_PHYERR, "%s: rsfr->peak_mag = %d", + __func__, rsfr->peak_mag); + DFS_DPRINTK(dfs, ATH_DEBUG_DFS_PHYERR, "%s: rsfr->num_str_bins_ib = %d", + __func__, rsfr->num_str_bins_ib); +} + +/* + * Parse a Peregrine BB TLV frame. + * + * This routine parses each TLV, prints out what's going on and + * calls an appropriate sub-function. + * + * Since the TLV format doesn't _specify_ all TLV components are + * DWORD aligned, we must treat them as not and access the fields + * appropriately. + */ +static int +tlv_parse_frame(struct ath_dfs *dfs, struct rx_radar_status *rs, + struct rx_search_fft_report *rsfr, const char *buf, size_t len, + uint8_t rssi) +{ + int i = 0; + uint32_t tlv_hdr[1]; + bool first_tlv = true; + bool false_detect = false; + + DFS_DPRINTK(dfs, ATH_DEBUG_DFS_PHYERR, + "%s: total length = %zu bytes", __func__, len); + while ((i < len) && (false_detect == false)) { + /* Ensure we at least have four bytes */ + if ((len - i) < sizeof(tlv_hdr)) { + DFS_DPRINTK(dfs, ATH_DEBUG_DFS_PHYERR | + ATH_DEBUG_DFS_PHYERR_SUM, + "%s: ran out of bytes, len=%zu, i=%d", + __func__, len, i); + return 0; + } + + /* + * Copy the offset into the header, + * so the DWORD style access macros + * can be used. + */ + OS_MEMCPY(&tlv_hdr, buf + i, sizeof(tlv_hdr)); + + DFS_DPRINTK(dfs, ATH_DEBUG_DFS_PHYERR, + "%s: HDR: TLV SIG=0x%x, TAG=0x%x, LEN=%d bytes", + __func__, + MS(tlv_hdr[TLV_REG], TLV_SIG), + MS(tlv_hdr[TLV_REG], TLV_TAG), + MS(tlv_hdr[TLV_REG], TLV_LEN)); + + /* + * Sanity check the length field is available in + * the remaining frame. Drop out if this isn't + * the case - we can't trust the rest of the TLV + * entries. + */ + if (MS(tlv_hdr[TLV_REG], TLV_LEN) + i >= len) { + DFS_DPRINTK(dfs, ATH_DEBUG_DFS_PHYERR, + "%s: TLV oversize: LEN=%d, avail=%zu, i=%d", + __func__, + MS(tlv_hdr[TLV_REG], TLV_LEN), len, i); + break; + } + + /* Skip the TLV header - one DWORD */ + i += sizeof(tlv_hdr); + + /* Handle the payload */ + /* XXX TODO! */ + switch (MS(tlv_hdr[TLV_REG], TLV_SIG)) { + case TAG_ID_RADAR_PULSE_SUMMARY: /* Radar pulse summary */ + /* XXX TODO verify return value */ + /* XXX TODO validate only seeing one of these */ + radar_summary_parse(dfs, buf + i, + MS(tlv_hdr[TLV_REG], TLV_LEN), rs); + break; + case TAG_ID_SEARCH_FFT_REPORT: + radar_fft_search_report_parse(dfs, buf + i, + MS(tlv_hdr[TLV_REG], + TLV_LEN), rsfr); + /* + * we examine search FFT report and make the following + * assumption as per algorithms group's input: + * (1) There may be multiple TLV + * (2) We make false detection decison solely based on + * the first TLV + * (3) If the first TLV is a serch FFT report then we + * check the peak_mag value. When RSSI is equal to + * dfs->ath_dfs_false_rssI_thres (default 50) and + * peak_mag is less than 2 * dfs->ath_dfs_peak_mag + * (default 40) we treat it as false detect. + * Please note that 50 is not a true RSSI estimate, + * but value indicated by HW for RF saturation event. + */ + + if ((first_tlv == true) && + (rssi == dfs->ath_dfs_false_rssi_thres) && + (rsfr->peak_mag < (2 * dfs->ath_dfs_peak_mag))) { + false_detect = true; + DFS_DPRINTK(dfs, ATH_DEBUG_DFS_PHYERR, + "%s: setting false_detect to true", + __func__); + } + + break; + default: + DFS_DPRINTK(dfs, ATH_DEBUG_DFS_PHYERR, + "%s: unknown entry, SIG=0x%02x", + __func__, MS(tlv_hdr[TLV_REG], TLV_SIG)); + } + + /* Skip the payload */ + i += MS(tlv_hdr[TLV_REG], TLV_LEN); + first_tlv = false; + } + DFS_DPRINTK(dfs, ATH_DEBUG_DFS_PHYERR, "%s: done", __func__); + + return false_detect ? 0 : 1; +} + +/* + * Calculate the channel centre in MHz. + */ +static int tlv_calc_freq_info(struct ath_dfs *dfs, struct rx_radar_status *rs) +{ + uint32_t chan_centre; + uint32_t chan_width; + int chan_offset; + + /* + * For now, just handle up to VHT80 correctly. + */ + if (dfs->ic == NULL || dfs->ic->ic_curchan == NULL) { + DFS_PRINTK("%s: dfs->ic=%p, that or curchan is null?", + __func__, dfs->ic); + return 0; + } + + qdf_spin_lock_bh(&dfs->ic->chan_lock); + /* + * calculate the channel center frequency for + * 160MHz and 80p80 MHz including the legacy + * channel widths. + */ + if (IEEE80211_IS_CHAN_11AC_VHT160(dfs->ic->ic_curchan)) { + chan_centre = dfs->ic->ic_curchan->ic_vhtop_ch_freq_seg1; + } else if (IEEE80211_IS_CHAN_11AC_VHT80P80(dfs->ic->ic_curchan)) { + if (rs->radar_80p80_segid == DFS_80P80_SEG0) + chan_centre = + dfs->ic->ic_curchan->ic_vhtop_ch_freq_seg1; + else + chan_centre = + dfs->ic->ic_curchan->ic_vhtop_ch_freq_seg2; + } else if (IEEE80211_IS_CHAN_11AC_VHT80(dfs->ic->ic_curchan)) { + /* 11AC, so cfreq1/cfreq2 are setup */ + chan_centre = dfs->ic->ic_curchan->ic_vhtop_ch_freq_seg1; + } else { + /* HT20/HT40 */ + + /* + * XXX this is hard-coded - it should be 5 or 10 for + * half/quarter appropriately. + */ + chan_width = 20; + + /* Grab default channel centre */ + chan_centre = ieee80211_chan2freq(dfs->ic, dfs->ic->ic_curchan); + + /* Calculate offset based on HT40U/HT40D and VHT40U/VHT40D */ + if (IEEE80211_IS_CHAN_11N_HT40PLUS(dfs->ic->ic_curchan) || + dfs->ic->ic_curchan->ic_flags & IEEE80211_CHAN_VHT40PLUS) + chan_offset = chan_width; + else if (IEEE80211_IS_CHAN_11N_HT40MINUS(dfs->ic->ic_curchan) || + dfs->ic->ic_curchan-> + ic_flags & IEEE80211_CHAN_VHT40MINUS) + chan_offset = -chan_width; + else + chan_offset = 0; + + /* Calculate new _real_ channel centre */ + chan_centre += (chan_offset / 2); + } + + qdf_spin_unlock_bh(&dfs->ic->chan_lock); + /* + * XXX half/quarter rate support! + */ + + /* Return ev_chan_centre in MHz */ + return chan_centre; +} + +/* + * Calculate the centre frequency and low/high range for a radar pulse event. + * + * XXX TODO: Handle half/quarter rates correctly! + * XXX TODO: handle VHT160 correctly! + * XXX TODO: handle VHT80+80 correctly! + */ +static int +tlv_calc_event_freq_pulse(struct ath_dfs *dfs, struct rx_radar_status *rs, + uint32_t *freq_centre, uint32_t *freq_lo, + uint32_t *freq_hi) +{ + int chan_width; + int chan_centre; + int is_chip_oversampling; + + /* + * Oversampling needs to be turned on for + * older chipsets that support DFS-2. + * it needs to be turned off for chips + * that support DFS-3. + */ + if (dfs->ic->dfs_hw_bd_id != DFS_HWBD_QCA6174) + is_chip_oversampling = 0; + else + is_chip_oversampling = PERE_IS_OVERSAMPLING(dfs); + + /* Fetch the channel centre frequency in MHz */ + chan_centre = tlv_calc_freq_info(dfs, rs); + + /* Convert to KHz */ + chan_centre *= 1000; + + /* + * XXX hard-code event width to be 2 * bin size for now; + * XXX this needs to take into account the core clock speed + * XXX for half/quarter rate mode. + */ + if (is_chip_oversampling) + chan_width = (44000 * 2 / 128); + else + chan_width = (40000 * 2 / 128); + + /* XXX adjust chan_width for half/quarter rate! */ + + /* + * Now we can do the math to figure out the correct channel range. + */ + (*freq_centre) = (uint32_t) (chan_centre + rs->freq_offset); + (*freq_lo) = (uint32_t) ((chan_centre + rs->freq_offset) + - chan_width); + (*freq_hi) = (uint32_t) ((chan_centre + rs->freq_offset) + + chan_width); + + return 1; +} + +/* + * The chirp bandwidth in KHz is defined as: + * + * totalBW(KHz) = delta_peak(mean) + * * [ (bin resolution in KHz) / (radar_fft_long_period in uS) ] + * * pulse_duration (us) + * + * The bin resolution depends upon oversampling. + * + * For now, we treat the radar_fft_long_period as a hard-coded 8uS. + */ +static int +tlv_calc_event_freq_chirp(struct ath_dfs *dfs, struct rx_radar_status *rs, + uint32_t *freq_centre, uint32_t *freq_lo, + uint32_t *freq_hi) +{ + int32_t bin_resolution; /* KHz * 100 */ + int32_t radar_fft_long_period = 8; /* microseconds */ + int32_t delta_peak; + int32_t pulse_duration; + int32_t total_bw; + int32_t chan_centre; + int32_t freq_1, freq_2; + int is_chip_oversampling; + + /* + * Oversampling needs to be turned on for + * older chipsets that support DFS-2. + * it needs to be turned off for chips + * that support DFS-3. + */ + if (dfs->ic->dfs_hw_bd_id != DFS_HWBD_QCA6174) + is_chip_oversampling = 0; + else + is_chip_oversampling = PERE_IS_OVERSAMPLING(dfs); + + /* + * KHz isn't enough resolution here! + * So treat it as deci-hertz (10Hz) and convert back to KHz + * later. + */ + if (is_chip_oversampling) + bin_resolution = (44000 * 100) / 128; + else + bin_resolution = (40000 * 100) / 128; + + delta_peak = rs->delta_peak; + pulse_duration = rs->pulse_duration; + + total_bw = delta_peak * (bin_resolution / radar_fft_long_period) * + pulse_duration; + + DFS_DPRINTK(dfs, ATH_DEBUG_DFS_PHYERR | ATH_DEBUG_DFS_PHYERR_SUM, + "%s: delta_peak=%d, pulse_duration=%d, bin_resolution=%d.%dKHz, " + "radar_fft_long_period=%d, total_bw=%d.%dKHz", + __func__, + delta_peak, + pulse_duration, + bin_resolution / 1000, + bin_resolution % 1000, + radar_fft_long_period, + total_bw / 100, + (int)abs(total_bw % 100)); + + total_bw /= 100; /* back to KHz */ + + /* Grab the channel centre frequency in MHz */ + chan_centre = tlv_calc_freq_info(dfs, rs); + + /* Early abort! */ + if (chan_centre == 0) { + (*freq_centre) = 0; + return 0; + } + + /* Convert to KHz */ + chan_centre *= 1000; + + /* + * sidx is the starting frequency; total_bw is a signed value and + * for negative chirps (ie, moving down in frequency rather than up) + * the end frequency may be less than the start frequency. + */ + if (total_bw > 0) { + freq_1 = chan_centre + rs->freq_offset; + freq_2 = chan_centre + rs->freq_offset + total_bw; + } else { + freq_1 = chan_centre + rs->freq_offset + total_bw; + freq_2 = chan_centre + rs->freq_offset; + } + + (*freq_lo) = (uint32_t) (freq_1); + (*freq_hi) = (uint32_t) (freq_2); + (*freq_centre) = (uint32_t) (freq_1 + (abs(total_bw) / 2)); + + return 1; +} + +/* + * Calculate the centre and band edge frequencies of the given radar + * event. + */ +static int +tlv_calc_event_freq(struct ath_dfs *dfs, struct rx_radar_status *rs, + uint32_t *freq_centre, uint32_t *freq_lo, + uint32_t *freq_hi) +{ + if (rs->is_chirp) + return tlv_calc_event_freq_chirp(dfs, rs, freq_centre, + freq_lo, freq_hi); + else + return tlv_calc_event_freq_pulse(dfs, rs, freq_centre, + freq_lo, freq_hi); +} + +/* + * This is the public facing function which parses the PHY error + * and populates the dfs_phy_err struct. + */ +int +dfs_process_phyerr_bb_tlv(struct ath_dfs *dfs, void *buf, uint16_t datalen, + uint8_t rssi, uint8_t ext_rssi, uint32_t rs_tstamp, + uint64_t fulltsf, struct dfs_phy_err *e, + bool enable_log) +{ + struct rx_radar_status rs; + struct rx_search_fft_report rsfr; + static int invalid_phyerr_count; + + OS_MEMZERO(&rs, sizeof(rs)); + + /* + * Add the ppdu_start/ppdu_end fields given to us by the upper + * layers. The firmware gives us a summary set of parameters rather + * than the whole PPDU_START/PPDU_END descriptor contenst. + */ + rs.rssi = rssi; + rs.raw_tsf = rs_tstamp; + /* + * Try parsing the TLV set. + */ + qdf_mem_zero(&rsfr, sizeof(rsfr)); + if (!tlv_parse_frame(dfs, &rs, &rsfr, buf, datalen, rssi)) { + invalid_phyerr_count++; + /* + * Print only at every 2 power times + * to avoid flushing of the kernel + * logs, since the frequency of + * invalid phyerrors is very high + * in noisy environments. + */ + if (!(invalid_phyerr_count & 0xFF)) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_DEBUG, + "%s[%d]:parse failed invalid phyerror cnt = %d", + __func__, __LINE__, invalid_phyerr_count); + } + return 0; + } + /* For debugging, print what we have parsed */ + radar_summary_print(dfs, &rs, enable_log); + + /* Populate dfs_phy_err from rs */ + OS_MEMSET(e, 0, sizeof(*e)); + e->rssi = rs.rssi; + e->dur = rs.pulse_duration; + e->sidx = rs.sidx; + e->is_pri = 1; /* XXX always PRI for now */ + e->is_ext = 0; + e->is_dc = 0; + e->is_early = 0; + + /* + * Copy the segment ID from the radar summary report + * only when radar summary report version is DFS-3. + */ + if (rs.rsu_version == DFS_RADAR_SUMMARY_REPORT_VERSION_3) { + e->radar_80p80_segid = rs.radar_80p80_segid; + e->delta_peak = rs.delta_peak; + e->delta_diff = rs.delta_diff; + e->agc_total_gain = rs.agc_total_gain; + e->agc_mb_gain = rs.agc_mb_gain; + e->radar_subchan_mask = rs.radar_subchan_mask; + e->pulse_height = rs.pulse_height; + e->triggering_agc_event = rs.triggering_agc_event; + e->pulse_rssi = rs.pulse_rssi; + e->radar_fft_pri80_inband_power = + rs.radar_fft_pri80_inband_power; + e->radar_fft_ext80_inband_power = + rs.radar_fft_ext80_inband_power; + e->rsu_version = rs.rsu_version; + e->peak_mag = rsfr.peak_mag; + + /* + * RSSI_COMB is not reliable indicator of RSSI + * for extension80 when operating in 80p80 + * non-contiguous mode due to existing hardware + * bug. Added workaround in software to use + * pulse_rssi instead of RSSI_COMB. + */ + + if ((dfs->ic->ic_curchan->ic_flags & + IEEE80211_CHAN_VHT80P80) && + (rs.radar_80p80_segid == DFS_80P80_SEG1)) + e->rssi = rs.pulse_rssi; + } + /* + * XXX TODO: add a "chirp detection enabled" capability or config + * bit somewhere, in case for some reason the hardware chirp + * detection AND FFTs are disabled. + */ + /* For now, assume this hardware always does chirp detection */ + e->do_check_chirp = 1; + e->is_hw_chirp = !!(rs.is_chirp); + e->is_sw_chirp = 0; /* We don't yet do software chirp checking */ + + e->fulltsf = fulltsf; + e->rs_tstamp = rs.raw_tsf - rs.tsf_offset; + + /* XXX error check */ + (void)tlv_calc_event_freq(dfs, &rs, &e->freq, &e->freq_lo, &e->freq_hi); + + DFS_DPRINTK(dfs, ATH_DEBUG_DFS_PHYERR_SUM, + "%s: fbin=%d, freq=%d.%d MHz, raw tsf=%u, offset=%d, " + "cooked tsf=%u, rssi=%d, dur=%d, is_chirp=%d, fulltsf=%llu, " + "freq=%d.%d MHz, freq_lo=%d.%dMHz, freq_hi=%d.%d MHz", + __func__, + rs.sidx, + (int)(rs.freq_offset / 1000), + (int)abs(rs.freq_offset % 1000), + rs.raw_tsf, + rs.tsf_offset, + e->rs_tstamp, + rs.rssi, + rs.pulse_duration, + (int)rs.is_chirp, + (unsigned long long)fulltsf, + (int)e->freq / 1000, + (int)abs(e->freq) % 1000, + (int)e->freq_lo / 1000, + (int)abs(e->freq_lo) % 1000, + (int)e->freq_hi / 1000, (int)abs(e->freq_hi) % 1000); + + return 1; +} diff --git a/drivers/staging/qcacld-3.0/core/sap/dfs/src/dfs_phyerr_tlv.h b/drivers/staging/qcacld-3.0/core/sap/dfs/src/dfs_phyerr_tlv.h new file mode 100644 index 0000000000000000000000000000000000000000..aa3383302e22e0fa9cf28632670a68baf660725f --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/sap/dfs/src/dfs_phyerr_tlv.h @@ -0,0 +1,246 @@ +/* + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/*=========================================================================== + + dfs_phyerr_tlv.h + + OVERVIEW: + + Source code borrowed from QCA_MAIN DFS module + + DEPENDENCIES: + + Are listed for each API below. + + ===========================================================================*/ + +#ifndef __DFS_PHYERR_PEREGRINE_H__ +#define __DFS_PHYERR_PEREGRINE_H__ + +/* + * Register manipulation macros that expect bit field defines + * to follow the convention that an _S suffix is appended for + * a shift count, while the field mask has no suffix. + */ +#undef SM +#undef MS +#define SM(_v, _f) (((_v) << _f ## _S) & _f) +#define MS(_v, _f) (((_v) & _f) >> _f ## _S) + +/* + * The TLV dword is at the beginning of each TLV section. + */ +#define TLV_REG 0x00 + +#define TLV_LEN 0x0000FFFF +#define TLV_LEN_S 0 + +#define TLV_SIG 0x00FF0000 +#define TLV_SIG_S 16 + +#define TLV_TAG 0xFF000000 +#define TLV_TAG_S 24 + +#define TAG_ID_SEARCH_FFT_REPORT 0xFB +#define TAG_ID_RADAR_PULSE_SUMMARY 0xF8 + +/* DFS-2 Radar pulse summary Length */ +#define DFS2_RADAR_PULSE_SUMMARY_TLV_LENGTH 8 + +/* DFS-3 Radar pulse summary length */ +#define DFS3_RADAR_PULSE_SUMMARY_TLV_LENGTH 20 + +/* + * Radar pulse summary + * + * + TYPE=0xF8 (Radar pulse summary reprot) + * + SIG=0xBB (baseband PHY generated TLV components) + */ + +#define RADAR_REPORT_PULSE_REG_1 0x00 + +#define RADAR_REPORT_PULSE_IS_CHIRP 0x80000000 +#define RADAR_REPORT_PULSE_IS_CHIRP_S 31 + +#define RADAR_REPORT_PULSE_IS_MAX_WIDTH 0x40000000 +#define RADAR_REPORT_PULSE_IS_MAX_WIDTH_S 30 + +#define RADAR_REPORT_AGC_TOTAL_GAIN 0x3FF00000 +#define RADAR_REPORT_AGC_TOTAL_GAIN_S 20 + +#define RADAR_REPORT_PULSE_DELTA_DIFF 0x000F0000 +#define RADAR_REPORT_PULSE_DELTA_DIFF_S 16 + +#define RADAR_REPORT_PULSE_DELTA_PEAK 0x0000FC00 +#define RADAR_REPORT_PULSE_DELTA_PEAK_S 10 + +#define RADAR_REPORT_PULSE_SIDX 0x000003FF +#define RADAR_REPORT_PULSE_SIDX_S 0x0 + +#define RADAR_REPORT_PULSE_REG_2 0x01 + +#define RADAR_REPORT_PULSE_SRCH_FFT_A_VALID 0x80000000 +#define RADAR_REPORT_PULSE_SRCH_FFT_A_VALID_S 31 + +#define RADAR_REPORT_PULSE_AGC_MB_GAIN 0x7F000000 +#define RADAR_REPORT_PULSE_AGC_MB_GAIN_S 24 + +#define RADAR_REPORT_PULSE_SUBCHAN_MASK 0x00FF0000 +#define RADAR_REPORT_PULSE_SUBCHAN_MASK_S 16 + +#define RADAR_REPORT_PULSE_TSF_OFFSET 0x0000FF00 +#define RADAR_REPORT_PULSE_TSF_OFFSET_S 8 + +#define RADAR_REPORT_PULSE_DUR 0x000000FF +#define RADAR_REPORT_PULSE_DUR_S 0 + +/* + * These are the new TLV's in the DFS-3 + * radar summary report. Three new DWORDS + * have been added to radar summary report + * as part of DFS-3 as defined below. + */ + +#define RADAR_REPORT_PULSE_REG_3 0x02 + +#define RADAR_REPORT_PULSE_HEIGHT 0x000003FF +#define RADAR_REPORT_PULSE_HEIGHT_S 0 + +#define RADAR_REPORT_PULSE_REG_4 0x03 + +#define RADAR_REPORT_TRIGGERING_AGC_EVENT 0xC0000000 +#define RADAR_REPORT_TRIGGERING_AGC_EVENT_S 30 + +#define RADAR_REPORT_PULSE_RSSI 0X3FFC0000 +#define RADAR_REPORT_PULSE_RSSI_S 18 + +#define RADAR_REPORT_PULSE_REG_5 0x04 + +#define RADAR_REPORT_FFT_PRI80_INBAND_POWER 0x1FFF8000 +#define RADAR_REPORT_FFT_PRI80_INBAND_POWER_S 15 + +#define RADAR_REPORT_FFT_EXT80_INBAND_POWER 0x00007FFE +#define RADAR_REPORT_FFT_EXT80_INBAND_POWER_S 1 + +#define RADAR_REPORT_80P80_SEGID 0x00000001 +#define RADAR_REPORT_80P80_SEGID_S 0 + +#define SEARCH_FFT_REPORT_REG_1 0x00 + +#define SEARCH_FFT_REPORT_TOTAL_GAIN_DB 0xFF800000 +#define SEARCH_FFT_REPORT_TOTAL_GAIN_DB_S 23 + +#define SEARCH_FFT_REPORT_BASE_PWR_DB 0x007FC000 +#define SEARCH_FFT_REPORT_BASE_PWR_DB_S 14 + +#define SEARCH_FFT_REPORT_FFT_CHN_IDX 0x00003000 +#define SEARCH_FFT_REPORT_FFT_CHN_IDX_S 12 + +#define SEARCH_FFT_REPORT_PEAK_SIDX 0x00000FFF +#define SEARCH_FFT_REPORT_PEAK_SIDX_S 0 + +#define SEARCH_FFT_REPORT_REG_2 0x01 + +#define SEARCH_FFT_REPORT_RELPWR_DB 0xFC000000 +#define SEARCH_FFT_REPORT_RELPWR_DB_S 26 + +#define SEARCH_FFT_REPORT_AVGPWR_DB 0x03FC0000 +#define SEARCH_FFT_REPORT_AVGPWR_DB_S 18 + +#define SEARCH_FFT_REPORT_PEAK_MAG 0x0003FF00 +#define SEARCH_FFT_REPORT_PEAK_MAG_S 8 + +#define SEARCH_FFT_REPORT_NUM_STR_BINS_IB 0x000000FF +#define SEARCH_FFT_REPORT_NUM_STR_BINS_IB_S 0 + +/* + * Although this code is now not parsing the whole frame (descriptor + * and all), the relevant fields are still useful information + * for anyone who is working on the PHY error part of DFS pattern + * matching. + * + * However, to understand _where_ these descriptors start, you + * should do some digging into the peregrine descriptor format. + * The 30 second version: each RX ring has a bitmap listing which + * descriptors are to be included, and then a set of offsets + * into the RX buffer for where each descriptor will be written. + * It's not like the 802.11n generation hardware which has + * a fixed descriptor format. + */ + +/* + * RX_PPDU_START + */ +#define RX_PPDU_START_LEN (10*4) + +#define RX_PPDU_START_REG_4 0x0004 +#define RX_PPDU_START_RSSI_COMB 0x000000FF +#define RX_PPDU_START_RSSI_COMB_S 0 + +/* + * RX_PPDU_END + */ +#define RX_PPDU_END_LEN (21*4) + +#define RX_PPDU_END_REG_16 16 +#define RX_PPDU_END_TSF_TIMESTAMP 0xFFFFFFFF +#define RX_PPDU_END_TSF_TIMESTAMP_S 0 + +#define RX_PPDU_END_REG_18 18 +#define RX_PPDU_END_PHY_ERR_CODE 0x0000FF00 +#define RX_PPDU_END_PHY_ERR_CODE_S 8 +#define RX_PPDU_END_PHY_ERR 0x00010000 +#define RX_PPDU_END_PHY_ERR_S 16 + +/* + * The RSSI values can have "special meanings". + * + * If rssi=50, it means that the peak detector triggered. + */ +#define RSSI_PEAK_DETECTOR_SAT 50 + +/* + * + * If rssi=25, it means that the ADC was saturated, but that only is + * valid when there is one ADC gain change. For short pulses this + * is true - you won't have time to do a gain change before the pulse + * goes away. But for longer pulses, ADC gain changes can occur, so + * you'll get a more accurate RSSI figure. + * + * For short pulses (and the definition of "short" still isn't clear + * at the time of writing) there isn't any real time to do a gain change + * (or two, or three..) in order to get an accurate estimation of signal + * sizing. Thus, RSSI will not be very accurate for short duration pulses. + * All you can really say for certain is that yes, there's a pulse that + * met the requirements of the pulse detector. + * + * For more information, see the 802.11ac Microarchitecture guide. + * (TODO: add a twiki reference.) + */ + +#endif /* __DFS_PHYERR_PEREGRINE_H__ */ diff --git a/drivers/staging/qcacld-3.0/core/sap/dfs/src/dfs_process_phyerr.c b/drivers/staging/qcacld-3.0/core/sap/dfs/src/dfs_process_phyerr.c new file mode 100644 index 0000000000000000000000000000000000000000..b385b5670b3de53f806f810e97773dae0390901c --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/sap/dfs/src/dfs_process_phyerr.c @@ -0,0 +1,943 @@ +/* + * Copyright (c) 2002-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#include "dfs.h" +#include "dfs_phyerr.h" /* For chip-specific phyerr func declarations */ +/* TO DO DFS + #include + */ +#ifndef UNINET +/* TO DO DFS + #include + */ +#endif +#ifdef ATH_SUPPORT_DFS + +/* + * Return the frequency width for the current operating channel. + * + * This isn't the channel width - it's how wide the reported event + * may be. For HT20 this is 20MHz. For HT40 on Howl and later it'll + * still be 20MHz - the hardware returns either pri or ext channel. + */ +static inline int dfs_get_event_freqwidth(struct ath_dfs *dfs) +{ + + /* Handle edge cases during startup/transition, shouldn't happen! */ + if (dfs == NULL) + return 0; + if (dfs->ic == NULL || dfs->ic->ic_curchan == NULL) + return 0; + + /* + * XXX For now, assume 20MHz wide - but this is incorrect when + * operating in half/quarter mode! + */ + return 20; +} + +/* + * Return the centre frequency for the current operating channel and + * event. + * + * This is for post-Owl 11n chips which report pri/extension channel + * events. + */ +static inline uint16_t +dfs_get_event_freqcentre(struct ath_dfs *dfs, int is_pri, int is_ext, int is_dc) +{ + struct ieee80211com *ic; + int chan_offset = 0, chan_width; + uint16_t freq; + + /* Handle edge cases during startup/transition, shouldn't happen! */ + if (dfs == NULL) + return 0; + if (dfs->ic == NULL || dfs->ic->ic_curchan == NULL) + return 0; + + ic = dfs->ic; + + /* + * + * For wide channels, DC and ext frequencies need a bit of hand-holding + * based on whether it's an upper or lower channel. + */ + chan_width = dfs_get_event_freqwidth(dfs); + qdf_spin_lock_bh(&ic->chan_lock); + if (IEEE80211_IS_CHAN_11N_HT40PLUS(ic->ic_curchan)) + chan_offset = chan_width; + else if (IEEE80211_IS_CHAN_11N_HT40MINUS(ic->ic_curchan)) + chan_offset = -chan_width; + else + chan_offset = 0; + + qdf_spin_unlock_bh(&ic->chan_lock); + + /* + * Check for DC events first - the sowl code may just set all + * the bits together.. + */ + if (is_dc) { + /* + * XXX TODO: Should DC events be considered 40MHz wide here? + */ + qdf_spin_lock_bh(&ic->chan_lock); + freq = ieee80211_chan2freq(ic, ic->ic_curchan) + + (chan_offset / 2); + qdf_spin_unlock_bh(&ic->chan_lock); + return freq; + } + + /* + * For non-wide channels, the centre frequency is just ic_freq. + * The centre frequency for pri events is still ic_freq. + */ + if (is_pri) { + qdf_spin_lock_bh(&ic->chan_lock); + freq = ieee80211_chan2freq(ic, ic->ic_curchan); + qdf_spin_unlock_bh(&ic->chan_lock); + return freq; + } + + if (is_ext) { + qdf_spin_lock_bh(&ic->chan_lock); + freq = ieee80211_chan2freq(ic, ic->ic_curchan) + chan_width; + qdf_spin_unlock_bh(&ic->chan_lock); + return freq; + } + + /* XXX shouldn't get here */ + qdf_spin_lock_bh(&ic->chan_lock); + freq = ieee80211_chan2freq(ic, ic->ic_curchan); + qdf_spin_unlock_bh(&ic->chan_lock); + return freq; +} + +/* + * Process an Owl-style phy error. + * + * Return 1 on success or 0 on failure. + */ +static int +dfs_process_phyerr_owl(struct ath_dfs *dfs, void *buf, uint16_t datalen, + uint8_t rssi, uint8_t ext_rssi, uint32_t rs_tstamp, + uint64_t fulltsf, struct dfs_phy_err *e) +{ + const char *cbuf = (const char *)buf; + uint8_t dur; + int event_width; + + /* XXX this shouldn't be kept count here */ + dfs->ath_dfs_stats.owl_phy_errors++; + + /* + * HW cannot detect extension channel radar so it only passes us + * primary channel radar data + */ + if (datalen == 0) + dur = 0; + else + dur = ((uint8_t *) cbuf)[0]; + + /* + * This is a spurious event; toss. + */ + if (rssi == 0 && dur == 0) + dfs->ath_dfs_stats.datalen_discards++; + return 0; + + /* + * Fill out dfs_phy_err with the information we have + * at hand. + */ + OS_MEMSET(e, 0, sizeof(*e)); + e->rssi = rssi; + e->dur = dur; + e->is_pri = 1; + e->is_ext = 0; + e->is_dc = 0; + e->is_early = 1; + e->fulltsf = fulltsf; + e->rs_tstamp = rs_tstamp; + + /* + * Owl only ever reports events on the primary channel; + * it doesn't even see events on the secondary channel. + */ + event_width = dfs_get_event_freqwidth(dfs); + e->freq = dfs_get_event_freqcentre(dfs, 1, 0, 0) * 1000; + e->freq_lo = e->freq - (event_width / 2) * 1000; + e->freq_hi = e->freq + (event_width / 2) * 1000; + + DFS_DPRINTK(dfs, ATH_DEBUG_DFS_PHYERR_SUM, + "%s: rssi=%u dur=%u,freq=%dMHz, freq_lo=%dMHz, freq_hi=%dMHz\n", + __func__, rssi, dur, e->freq / 1000, e->freq_lo / 1000, + e->freq_hi / 1000); + + return 1; +} + +/* + * Process a Sowl/Howl style phy error. + */ +static int +dfs_process_phyerr_sowl(struct ath_dfs *dfs, void *buf, uint16_t datalen, + uint8_t rssi, uint8_t ext_rssi, uint32_t rs_tstamp, + uint64_t fulltsf, struct dfs_phy_err *e) +{ +#define EXT_CH_RADAR_FOUND 0x02 +#define PRI_CH_RADAR_FOUND 0x01 +#define EXT_CH_RADAR_EARLY_FOUND 0x04 + const char *cbuf = (const char *)buf; + uint8_t dur = 0; + uint8_t pulse_bw_info, pulse_length_ext, pulse_length_pri; + int pri_found = 0, ext_found = 0; + int early_ext = 0; + int event_width; + + /* + * If radar can be detected on the extension channel, datalen zero + * pulses are bogus, discard them. + */ + if (!datalen) { + dfs->ath_dfs_stats.datalen_discards++; + return 0; + } + + /* Ensure that we have at least three bytes of payload */ + if (datalen < 3) { + DFS_DPRINTK(dfs, ATH_DEBUG_DFS, + "%s: short error frame (%d bytes)\n", + __func__, datalen); + dfs->ath_dfs_stats.datalen_discards++; + return 0; + } + + /* + * Fetch the payload directly - the compiler will happily generate + * byte-read instructions with a const char * cbuf pointer. + */ + pulse_length_pri = cbuf[datalen - 3]; + pulse_length_ext = cbuf[datalen - 2]; + pulse_bw_info = cbuf[datalen - 1]; + + /* + * Only the last 3 bits of the BW info are relevant, they indicate + * which channel the radar was detected in. + */ + pulse_bw_info &= 0x07; + + /* + * If pulse on DC, both primary and extension flags will be set + */ + if (((pulse_bw_info & EXT_CH_RADAR_FOUND) && + (pulse_bw_info & PRI_CH_RADAR_FOUND))) { + /* + * Conducted testing, when pulse is on DC, both + * pri and ext durations are reported to be same. + * + * Radiated testing, when pulse is on DC, different + * pri and ext durations are reported, so take the + * larger of the two + */ + if (pulse_length_ext >= pulse_length_pri) { + dur = pulse_length_ext; + ext_found = 1; + } else { + dur = pulse_length_pri; + pri_found = 1; + } + dfs->ath_dfs_stats.dc_phy_errors++; + } else { + if (pulse_bw_info & EXT_CH_RADAR_FOUND) { + dur = pulse_length_ext; + pri_found = 0; + ext_found = 1; + dfs->ath_dfs_stats.ext_phy_errors++; + } + if (pulse_bw_info & PRI_CH_RADAR_FOUND) { + dur = pulse_length_pri; + pri_found = 1; + ext_found = 0; + dfs->ath_dfs_stats.pri_phy_errors++; + } + if (pulse_bw_info & EXT_CH_RADAR_EARLY_FOUND) { + dur = pulse_length_ext; + pri_found = 0; + ext_found = 1; + early_ext = 1; + dfs->ath_dfs_stats.early_ext_phy_errors++; + DFS_DPRINTK(dfs, ATH_DEBUG_DFS_PHYERR, + "EARLY ext channel dur=%u rssi=%u datalen=%d\n", + dur, rssi, datalen); + } + if (!pulse_bw_info) { + DFS_DPRINTK(dfs, ATH_DEBUG_DFS_PHYERR, + "dur=%u rssi=%u bw_info=0x%x datalen = %d\n", + dur, rssi, pulse_bw_info, (datalen & 0x3)); + /* + * Bogus bandwidth info received in descriptor, + * so ignore this PHY error + */ + dfs->ath_dfs_stats.bwinfo_errors++; + return 0; + } + } + + /* + * Always use combined RSSI reported, unless RSSI reported on + * extension is stronger + */ + if ((ext_rssi > rssi) && (ext_rssi < 128)) + rssi = ext_rssi; + + /* + * Fill out the rssi/duration fields from above. + */ + OS_MEMSET(e, 0, sizeof(*e)); + e->rssi = rssi; + e->dur = dur; + e->is_pri = pri_found; + e->is_ext = ext_found; + e->is_dc = !!(((pulse_bw_info & EXT_CH_RADAR_FOUND) && + (pulse_bw_info & PRI_CH_RADAR_FOUND))); + e->is_early = early_ext; + e->fulltsf = fulltsf; + e->rs_tstamp = rs_tstamp; + + /* + * Sowl and later can report pri/ext events. + */ + event_width = dfs_get_event_freqwidth(dfs); + e->freq = dfs_get_event_freqcentre(dfs, e->is_pri, e->is_ext, e->is_dc) + * 1000; + e->freq_lo = e->freq - (event_width / 2) * 1000; + e->freq_hi = e->freq + (event_width / 2) * 1000; + + DFS_DPRINTK(dfs, ATH_DEBUG_DFS_PHYERR_SUM, + "%s: pulse_bw_info=0x%x pulse_length_ext=%u pulse_length_pri=%u " + "rssi=%u ext_rssi=%u, freq=%d MHz, freq_lo=%d MHz, " + "freq_hi=%d MHz\n", + __func__, + pulse_bw_info, + pulse_length_ext, + pulse_length_pri, + rssi, + ext_rssi, + e->freq / 1000, e->freq_lo / 1000, e->freq_hi / 1000); + + return 1; +} + +/* + * Process a Merlin/Osprey style phy error. + */ +static int +dfs_process_phyerr_merlin(struct ath_dfs *dfs, void *buf, + uint16_t datalen, uint8_t rssi, uint8_t ext_rssi, + uint32_t rs_tstamp, uint64_t fulltsf, + struct dfs_phy_err *e) +{ + const char *cbuf = (const char *)buf; + uint8_t pulse_bw_info = 0; + + /* + * Process using the sowl code + */ + if (!dfs_process_phyerr_sowl(dfs, buf, datalen, rssi, ext_rssi, + rs_tstamp, fulltsf, e)) { + return 0; + } + + /* + * For osprey (and Merlin) bw_info has implication for selecting + * RSSI value. So re-fetch the bw_info field so the RSSI values + * can be appropriately overridden. + */ + pulse_bw_info = cbuf[datalen - 1]; + + switch (pulse_bw_info & 0x03) { + case 0x00: + /* No radar in ctrl or ext channel */ + rssi = 0; + break; + case 0x01: + /* radar in ctrl channel */ + DFS_DPRINTK(dfs, ATH_DEBUG_DFS_PHYERR, + "RAW RSSI: rssi=%u ext_rssi=%u\n", rssi, ext_rssi); + if (ext_rssi >= (rssi + 3)) { + /* + * cannot use ctrl channel RSSI if + * extension channel is stronger + */ + rssi = 0; + } + break; + case 0x02: + /* radar in extension channel */ + DFS_DPRINTK(dfs, ATH_DEBUG_DFS_PHYERR, + "RAW RSSI: rssi=%u ext_rssi=%u\n", rssi, ext_rssi); + if (rssi >= (ext_rssi + 12)) { + /* + * cannot use extension channel RSSI if control channel + * is stronger + */ + rssi = 0; + } else { + rssi = ext_rssi; + } + break; + case 0x03: + /* when both are present use stronger one */ + if (rssi < ext_rssi) + rssi = ext_rssi; + break; + } + + /* + * Override the rssi decision made by the sowl code. + * The rest of the fields (duration, timestamp, etc) + * are left untouched. + */ + e->rssi = rssi; + + return 1; +} + +static void dump_phyerr_contents(const char *d, int len) +{ +#ifdef CONFIG_ENABLE_DUMP_PHYERR_CONTENTS + int i, n, bufsize = 64; + + /* + * This is statically sized for a 4-digit address + 16 * 2 digit + * data string. + * + * It's done so the printk() passed to the kernel is an entire + * line, so the kernel logging code will atomically print it. + * Otherwise we'll end up with interleaved lines with output + * from other kernel threads. + */ + char buf[64]; + + /* Initial conditions */ + buf[0] = '\n'; + n = 0; + + for (i = 0; i < len; i++) { + if (i % 16 == 0) + n += snprintf(buf + n, bufsize - n, "%04x: ", i); + n += snprintf(buf + n, bufsize - n, "%02x ", d[i] & 0xff); + if (i % 16 == 15) { + n = 0; + buf[0] = '\0'; + } + } + + /* + * Print the final line if we didn't print it above. + */ + if (n != 0) + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO, "%s: %s", + __func__, buf); +#endif /* def CONFIG_ENABLE_DUMP_PHYERR_CONTENTS */ +} + +void +dfs_process_phyerr(struct ieee80211com *ic, void *buf, uint16_t datalen, + uint8_t r_rssi, uint8_t r_ext_rssi, uint32_t r_rs_tstamp, + uint64_t r_fulltsf, bool enable_log) +{ + struct ath_dfs *dfs = (struct ath_dfs *)ic->ic_dfs; + struct dfs_ieee80211_channel *chan = ic->ic_curchan; + struct dfs_event *event; + struct dfs_phy_err e; + int empty; + + if (dfs == NULL) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: sc_dfs is NULL", __func__); + return; + } + + dfs->dfs_phyerr_count++; + dump_phyerr_contents(buf, datalen); + /* + * XXX The combined_rssi_ok support has been removed. + * This was only clear for Owl. + * + * XXX TODO: re-add this; it requires passing in the ctl/ext + * RSSI set from the RX status descriptor. + * + * XXX TODO TODO: this may be done for us from the legacy + * phy error path in ath_dev; please review that code. + */ + + /* + * At this time we have a radar pulse that we need to examine and + * queue. But if dfs_process_radarevent already detected radar and set + * CHANNEL_INTERFERENCE flag then do not queue any more radar data. + * When we are in a new channel this flag will be clear and we will + * start queueing data for new channel. (EV74162) + */ + if (dfs->dfs_debug_mask & ATH_DEBUG_DFS_PHYERR_PKT) + dump_phyerr_contents(buf, datalen); + + if (chan == NULL) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO, + "%s: chan is NULL", __func__); + return; + } + + qdf_spin_lock_bh(&ic->chan_lock); + if (IEEE80211_IS_CHAN_RADAR(chan)) { + qdf_spin_unlock_bh(&ic->chan_lock); + DFS_DPRINTK(dfs, ATH_DEBUG_DFS1, + "%s: Radar already found in the channel, " + " do not queue radar data\n", __func__); + return; + } + + qdf_spin_unlock_bh(&ic->chan_lock); + dfs->ath_dfs_stats.total_phy_errors++; + DFS_DPRINTK(dfs, ATH_DEBUG_DFS2, + "%s[%d] phyerr %d len %d\n", + __func__, __LINE__, + dfs->ath_dfs_stats.total_phy_errors, datalen); + + /* + * hardware stores this as 8 bit signed value. + * we will cap it at 0 if it is a negative number + */ + if (r_rssi & 0x80) + r_rssi = 0; + + if (r_ext_rssi & 0x80) + r_ext_rssi = 0; + + OS_MEMSET(&e, 0, sizeof(e)); + + /* + * This is a bit evil - instead of just passing in + * the chip version, the existing code uses a set + * of HAL capability bits to determine what is + * possible. + * + * The way I'm decoding it is thus: + * + * + DFS enhancement? Merlin or later + * + DFS extension channel? Sowl or later. (Howl?) + * + otherwise, Owl (and legacy.) + */ + if (dfs->dfs_caps.ath_chip_is_bb_tlv) { + if (dfs_process_phyerr_bb_tlv(dfs, buf, datalen, r_rssi, + r_ext_rssi, r_rs_tstamp, + r_fulltsf, &e, + enable_log) == 0) { + dfs->dfs_phyerr_reject_count++; + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO, + "%s:Rejected phyerr count after parsing=%d", + __func__, dfs->dfs_phyerr_reject_count); + return; + } else { + if (dfs->dfs_phyerr_freq_min > e.freq) + dfs->dfs_phyerr_freq_min = e.freq; + + if (dfs->dfs_phyerr_freq_max < e.freq) + dfs->dfs_phyerr_freq_max = e.freq; + } + } else if (dfs->dfs_caps.ath_dfs_use_enhancement) { + if (dfs_process_phyerr_merlin(dfs, buf, datalen, r_rssi, + r_ext_rssi, r_rs_tstamp, + r_fulltsf, &e) == 0) { + return; + } + } else if (dfs->dfs_caps.ath_dfs_ext_chan_ok) { + if (dfs_process_phyerr_sowl(dfs, buf, datalen, r_rssi, + r_ext_rssi, r_rs_tstamp, r_fulltsf, + &e) == 0) { + return; + } + } else { + if (dfs_process_phyerr_owl(dfs, buf, datalen, r_rssi, + r_ext_rssi, r_rs_tstamp, r_fulltsf, + &e) == 0) { + return; + } + } + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO, + "%s: Frequency at which the phyerror was injected = %d", + __func__, e.freq); + /* + * If the hardware supports radar reporting on the extension channel + * it will supply FFT data for longer radar pulses. + * + * TLV chips don't go through this software check - the hardware + * check should be enough. If we want to do software checking + * later on then someone will have to craft an FFT parser + * suitable for the TLV FFT data format. + */ + if ((!dfs->dfs_caps.ath_chip_is_bb_tlv) && + dfs->dfs_caps.ath_dfs_ext_chan_ok) { + /* + * HW has a known issue with chirping pulses injected at or + * around DC in 40MHz mode. Such pulses are reported with + * much lower durations and SW then discards them because + * they do not fit the minimum bin5 pulse duration. + * + * To work around this issue, if a pulse is within a 10us + * range of the bin5 min duration, check if the pulse is + * chirping. If the pulse is chirping, bump up the duration + * to the minimum bin5 duration. + * + * This makes sure that a valid chirping pulse will not be + * discarded because of incorrect low duration. + * + * TBD - Is it possible to calculate the 'real' duration of + * the pulse using the slope of the FFT data? + * + * TBD - Use FFT data to differentiate between radar pulses + * and false PHY errors. + * This will let us reduce the number of false alarms seen. + * + * BIN 5 chirping pulses are only for FCC or Japan MMK4 domain + */ + if (((dfs->dfsdomain == DFS_FCC_REGION) || + (dfs->dfsdomain == DFS_MKK_REGION)) && + (e.dur >= MAYBE_BIN5_DUR) && (e.dur < MAX_BIN5_DUR)) { + int add_dur; + int slope = 0, dc_found = 0; + + /* + * Set the event chirping flags; as we're doing + * an actual chirp check. + */ + e.do_check_chirp = 1; + e.is_hw_chirp = 0; + e.is_sw_chirp = 0; + + /* + * dfs_check_chirping() expects is_pri and is_ext + * to be '1' for true and '0' for false for now, + * as the function itself uses these values in + * constructing things rather than testing them + * for 'true' or 'false'. + */ + add_dur = dfs_check_chirping(dfs, buf, datalen, + (e.is_pri ? 1 : 0), + (e.is_ext ? 1 : 0), + &slope, &dc_found); + if (add_dur) { + DFS_DPRINTK(dfs, ATH_DEBUG_DFS_PHYERR, + "old dur %d slope =%d\n", e.dur, + slope); + e.is_sw_chirp = 1; + /* bump up to a random bin5 pulse duration */ + if (e.dur < MIN_BIN5_DUR) { + e.dur = dfs_get_random_bin5_dur(dfs, + e.fulltsf); + } + DFS_DPRINTK(dfs, ATH_DEBUG_DFS_PHYERR, + "new dur %d\n", e.dur); + } else { + /* set the duration so that it is rejected */ + e.is_sw_chirp = 0; + e.dur = MAX_BIN5_DUR + 100; + DFS_DPRINTK(dfs, ATH_DEBUG_DFS_PHYERR, + "is_chirping = %d dur=%d\n", + add_dur, e.dur); + } + } else { + /* + * We have a pulse that is either bigger than + * MAX_BIN5_DUR or * less than MAYBE_BIN5_DUR + */ + if ((dfs->dfsdomain == DFS_FCC_REGION) || + (dfs->dfsdomain == DFS_MKK_REGION)) { + /* + * XXX Would this result in very large pulses + * wrapping around to become short pulses? + */ + if (e.dur >= MAX_BIN5_DUR) { + /* + * set the duration so that it is + * rejected + */ + e.dur = MAX_BIN5_DUR + 50; + } + } + } + } + + /* + * Add the parsed, checked and filtered entry to the radar pulse + * event list. This is then checked by dfs_radar_processevent(). + * + * XXX TODO: some filtering is still done below this point - fix + * XXX this! + */ + ATH_DFSEVENTQ_LOCK(dfs); + empty = STAILQ_EMPTY(&(dfs->dfs_eventq)); + ATH_DFSEVENTQ_UNLOCK(dfs); + if (empty) { + return; + } + + /* + * If the channel is a turbo G channel, then the event is + * for the adaptive radio (AR) pattern matching rather than + * radar detection. + */ + qdf_spin_lock_bh(&ic->chan_lock); + if ((chan->ic_flags & CHANNEL_108G) == CHANNEL_108G) { + qdf_spin_unlock_bh(&ic->chan_lock); + if (!(dfs->dfs_proc_phyerr & DFS_AR_EN)) { + DFS_DPRINTK(dfs, ATH_DEBUG_DFS2, + "%s: DFS_AR_EN not enabled\n", __func__); + return; + } + ATH_DFSEVENTQ_LOCK(dfs); + event = STAILQ_FIRST(&(dfs->dfs_eventq)); + if (event == NULL) { + ATH_DFSEVENTQ_UNLOCK(dfs); + DFS_DPRINTK(dfs, ATH_DEBUG_DFS, + "%s: no more events space left\n", + __func__); + return; + } + STAILQ_REMOVE_HEAD(&(dfs->dfs_eventq), re_list); + ATH_DFSEVENTQ_UNLOCK(dfs); + event->re_rssi = e.rssi; + event->re_dur = e.dur; + event->re_full_ts = e.fulltsf; + event->re_ts = (e.rs_tstamp) & DFS_TSMASK; + event->re_chanindex = dfs->dfs_curchan_radindex; + event->re_flags = 0; + event->sidx = e.sidx; + if (e.rsu_version == DFS_RADAR_SUMMARY_REPORT_VERSION_3) { + event->delta_peak = e.delta_peak; + event->delta_diff = e.delta_diff; + event->agc_total_gain = e.agc_total_gain; + event->agc_mb_gain = e.agc_mb_gain; + event->radar_subchan_mask = e.radar_subchan_mask; + event->pulse_height = e.pulse_height; + event->triggering_agc_event = e.triggering_agc_event; + event->pulse_rssi = e.pulse_rssi; + event->radar_fft_pri80_inband_power = + e.radar_fft_pri80_inband_power; + event->radar_fft_ext80_inband_power = + e.radar_fft_ext80_inband_power; + event->rsu_version = e.rsu_version; + event->peak_mag = e.peak_mag; + } + /* + * Copy the segment ID of the phyerror + * from the radar summary report only + * if SAP is operating in 80p80 mode + * and both primary and extension segments + * are DFS. + */ + if (chan->ic_80p80_both_dfs) + event->radar_80p80_segid = e.radar_80p80_segid; + + /* + * Handle chirp flags. + */ + if (e.do_check_chirp) { + event->re_flags |= DFS_EVENT_CHECKCHIRP; + if (e.is_hw_chirp) + event->re_flags |= DFS_EVENT_HW_CHIRP; + if (e.is_sw_chirp) + event->re_flags |= DFS_EVENT_SW_CHIRP; + } + + ATH_ARQ_LOCK(dfs); + STAILQ_INSERT_TAIL(&(dfs->dfs_arq), event, re_list); + ATH_ARQ_UNLOCK(dfs); + } else { + if (IEEE80211_IS_CHAN_DFS(chan)) { + qdf_spin_unlock_bh(&ic->chan_lock); + if (!(dfs->dfs_proc_phyerr & DFS_RADAR_EN)) { + DFS_DPRINTK(dfs, ATH_DEBUG_DFS3, + "%s: DFS_RADAR_EN not enabled\n", + __func__); + return; + } + /* + * rssi is not accurate for short pulses, so do + * not filter based on that for short duration pulses + * + * XXX do this filtering above? + */ + if (dfs->dfs_caps.ath_dfs_ext_chan_ok) { + if ((e.rssi < dfs->dfs_rinfo.rn_minrssithresh && + (e.dur > 4)) || + e.dur > (dfs->dfs_rinfo.rn_maxpulsedur)) { + dfs->ath_dfs_stats.rssi_discards++; + DFS_DPRINTK(dfs, ATH_DEBUG_DFS1, + "Extension channel pulse is " + "discarded: dur=%d, " + "maxpulsedur=%d, rssi=%d, " + "minrssi=%d\n", + e.dur, + dfs->dfs_rinfo. + rn_maxpulsedur, e.rssi, + dfs->dfs_rinfo. + rn_minrssithresh); + return; + } + } else if (e.rssi < dfs->dfs_rinfo.rn_minrssithresh || + e.dur > dfs->dfs_rinfo.rn_maxpulsedur) { + + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_INFO, + "%s [%d] : Rejecting: dur = %d maxpulsedur = %d, rssi = %d minrssithresh = %d", + __func__, __LINE__, + e.dur, dfs->dfs_rinfo.rn_maxpulsedur, + e.rssi, + dfs->dfs_rinfo.rn_minrssithresh); + + dfs->ath_dfs_stats.rssi_discards++; + return; + } + + /* + * Add the event to the list, if there's space. + */ + ATH_DFSEVENTQ_LOCK(dfs); + event = STAILQ_FIRST(&(dfs->dfs_eventq)); + if (event == NULL) { + ATH_DFSEVENTQ_UNLOCK(dfs); + DFS_DPRINTK(dfs, ATH_DEBUG_DFS, + "%s: no more events space left\n", + __func__); + return; + } + STAILQ_REMOVE_HEAD(&(dfs->dfs_eventq), re_list); + ATH_DFSEVENTQ_UNLOCK(dfs); + + dfs->dfs_phyerr_queued_count++; + dfs->dfs_phyerr_w53_counter++; + + event->re_dur = e.dur; + event->re_full_ts = e.fulltsf; + event->re_ts = (e.rs_tstamp) & DFS_TSMASK; + event->re_rssi = e.rssi; + event->sidx = e.sidx; + if (e.rsu_version == + DFS_RADAR_SUMMARY_REPORT_VERSION_3) { + event->delta_peak = e.delta_peak; + event->delta_diff = e.delta_diff; + event->agc_total_gain = e.agc_total_gain; + event->agc_mb_gain = e.agc_mb_gain; + event->radar_subchan_mask = e.radar_subchan_mask; + event->pulse_height = e.pulse_height; + event->triggering_agc_event = + e.triggering_agc_event; + event->pulse_rssi = e.pulse_rssi; + event->radar_fft_pri80_inband_power = + e.radar_fft_pri80_inband_power; + event->radar_fft_ext80_inband_power = + e.radar_fft_ext80_inband_power; + event->rsu_version = e.rsu_version; + event->dfs_phyerr_eventq_serial_num = + dfs->dfs_phyerr_queued_count; + event->peak_mag = e.peak_mag; + } + /* + * Copy the segment ID of the phyerror + * from the radar summary report only + * if SAP is operating in 80p80 mode + * and both primary and extension segments + * are DFS. + */ + if (chan->ic_80p80_both_dfs) + event->radar_80p80_segid = e.radar_80p80_segid; + + /* + * Handle chirp flags. + */ + if (e.do_check_chirp) { + event->re_flags |= DFS_EVENT_CHECKCHIRP; + if (e.is_hw_chirp) + event->re_flags |= DFS_EVENT_HW_CHIRP; + if (e.is_sw_chirp) + event->re_flags |= DFS_EVENT_SW_CHIRP; + } + + /* + * Correctly set which channel is being reported on + */ + if (e.is_pri) { + event->re_chanindex = dfs->dfs_curchan_radindex; + } else { + if (dfs->dfs_extchan_radindex == -1) { + DFS_DPRINTK(dfs, ATH_DEBUG_DFS_PHYERR, + "%s - phyerr on ext channel\n", + __func__); + } + event->re_chanindex = dfs->dfs_extchan_radindex; + DFS_DPRINTK(dfs, ATH_DEBUG_DFS_PHYERR, + "%s New extension channel event is added " + "to queue\n", __func__); + } + ATH_DFSQ_LOCK(dfs); + STAILQ_INSERT_TAIL(&(dfs->dfs_radarq), event, re_list); + ATH_DFSQ_UNLOCK(dfs); + } else { + qdf_spin_unlock_bh(&ic->chan_lock); + } + } + + /* + * Schedule the radar/AR task as appropriate. + * + * XXX isn't a lock needed for ath_radar_tasksched? + */ + +/* + * Commenting out the dfs_process_ar_event() since the function is never + * called at run time as dfs_arq will be empty and the function + * dfs_process_ar_event is obsolete and function definition is removed + * as part of dfs_ar.c file + * + * if (!STAILQ_EMPTY(&dfs->dfs_arq)) + * // XXX shouldn't this be a task/timer too? + * dfs_process_ar_event(dfs, ic->ic_curchan); + */ + + if (!STAILQ_EMPTY(&dfs->dfs_radarq) && !dfs->ath_radar_tasksched) { + dfs->ath_radar_tasksched = 1; + OS_SET_TIMER(&dfs->ath_dfs_task_timer, 0); + } +#undef EXT_CH_RADAR_FOUND +#undef PRI_CH_RADAR_FOUND +#undef EXT_CH_RADAR_EARLY_FOUND +} +#endif /* ATH_SUPPORT_DFS */ diff --git a/drivers/staging/qcacld-3.0/core/sap/dfs/src/dfs_process_radarevent.c b/drivers/staging/qcacld-3.0/core/sap/dfs/src/dfs_process_radarevent.c new file mode 100644 index 0000000000000000000000000000000000000000..c40ada404d92ddc2003eddbf70398a6ed58c7657 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/sap/dfs/src/dfs_process_radarevent.c @@ -0,0 +1,887 @@ +/* + * Copyright (c) 2002-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/*=========================================================================== + + dfs_radarevent.c + + OVERVIEW: + + Source code borrowed from QCA_MAIN DFS module + + DEPENDENCIES: + + Are listed for each API below. + + ===========================================================================*/ + +/*=========================================================================== + + EDIT HISTORY FOR FILE + + This section contains comments describing changes made to the module. + Notice that changes are listed in reverse chronological order. + + when who what, where, why + ---------- --- -------------------------------------------------------- + + ===========================================================================*/ + +#include "dfs.h" +/* TO DO DFS + #include + */ +#ifdef ATH_SUPPORT_DFS + +#define FREQ_5500_MHZ 5500 +#define FREQ_5500_MHZ 5500 + +#define DFS_MAX_FREQ_SPREAD 1375 * 1 + +static char debug_dup[33]; +static int debug_dup_cnt; + +/* + * Convert the hardware provided duration to TSF ticks (usecs) + * taking the clock (fast or normal) into account. + * + * Legacy (pre-11n, Owl, Sowl, Howl) operate 5GHz using a 40MHz + * clock. Later 11n chips (Merlin, Osprey, etc) operate 5GHz using + * a 44MHz clock, so the reported pulse durations are different. + * + * Peregrine reports the pulse duration in microseconds regardless + * of the operating mode. (XXX TODO: verify this, obviously.) + */ +static inline uint8_t dfs_process_pulse_dur(struct ath_dfs *dfs, uint8_t re_dur) +{ + /* + * Short pulses are sometimes returned as having a duration of 0, + * so round those up to 1. + * + * XXX This holds true for BB TLV chips too, right? + */ + if (re_dur == 0) + return 1; + + /* + * For BB TLV chips, the hardware always returns microsecond + * pulse durations. + */ + if (dfs->dfs_caps.ath_chip_is_bb_tlv) + return re_dur; + + /* + * This is for 11n and legacy chips, which may or may not + * use the 5GHz fast clock mode. + */ + /* Convert 0.8us durations to TSF ticks (usecs) */ + return (uint8_t) dfs_round((int32_t) ((dfs->dur_multiplier) * re_dur)); +} + +/* + * Process a radar event. + * + * If a radar event is found, return 1. Otherwise, return 0. + * + * There is currently no way to specify that a radar event has occured on + * a specific channel, so the current methodology is to mark both the pri + * and ext channels as being unavailable. This should be fixed for 802.11ac + * or we'll quickly run out of valid channels to use. + */ +int dfs_process_radarevent(struct ath_dfs *dfs, + struct dfs_ieee80211_channel *chan) +{ + struct dfs_event re, *event; + struct dfs_state *rs = NULL; + struct dfs_filtertype *ft; + struct dfs_filter *rf; + int found, retval = 0, p, empty; + int events_processed = 0; + uint32_t tabledepth, index; + uint64_t deltafull_ts = 0, this_ts, deltaT; + struct dfs_ieee80211_channel *thischan; + struct dfs_pulseline *pl; + static uint32_t diff_ts; + int ext_chan_event_flag = 0; + int is_hw_chirp = 0; + int i; + int seg_id = DFS_80P80_SEG0; + struct dfs_delayline *dl; + + if (dfs == NULL) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s[%d]: dfs is NULL", __func__, __LINE__); + return 0; + } + qdf_spin_lock_bh(&dfs->ic->chan_lock); + if (!(IEEE80211_IS_CHAN_DFS(dfs->ic->ic_curchan))) { + qdf_spin_unlock_bh(&dfs->ic->chan_lock); + DFS_DPRINTK(dfs, ATH_DEBUG_DFS2, + "%s: radar event on non-DFS chan", __func__); + dfs_reset_radarq(dfs); + dfs_reset_alldelaylines(dfs, DFS_80P80_SEG0); + + if (dfs->ic->ic_curchan->ic_80p80_both_dfs) + dfs_reset_alldelaylines(dfs, DFS_80P80_SEG1); + + return 0; + } + + qdf_spin_unlock_bh(&dfs->ic->chan_lock); +#ifndef ATH_DFS_RADAR_DETECTION_ONLY + /* TEST : Simulate radar bang, make sure we add the channel to NOL (bug 29968) */ + if (dfs->dfs_bangradar) { + /* bangradar will always simulate radar found on the primary channel */ + rs = &dfs->dfs_radar[dfs->dfs_curchan_radindex]; + dfs->dfs_bangradar = 0; /* reset */ + DFS_DPRINTK(dfs, ATH_DEBUG_DFS, "%s: bangradar", __func__); + retval = 1; + goto dfsfound; + } +#endif + + /* + The HW may miss some pulses especially with high channel loading. + This is true for Japan W53 where channel loaoding is 50%. Also + for ETSI where channel loading is 30% this can be an issue too. + To take care of missing pulses, we introduce pri_margin multiplie. + This is normally 2 but can be higher for W53. + */ + + if ((dfs->dfsdomain == DFS_MKK_REGION) && + (dfs->dfs_caps.ath_chip_is_bb_tlv) && + (chan->ic_freq < FREQ_5500_MHZ)) { + + dfs->dfs_pri_multiplier = dfs->dfs_pri_multiplier_ini; + + /* do not process W53 pulses, + unless we have a minimum number of them + */ + if (dfs->dfs_phyerr_w53_counter >= 5) { + DFS_DPRINTK(dfs, ATH_DEBUG_DFS1, + "%s: w53_counter=%d, freq_max=%d, " + "freq_min=%d, pri_multiplier=%d", + __func__, + dfs->dfs_phyerr_w53_counter, + dfs->dfs_phyerr_freq_max, + dfs->dfs_phyerr_freq_min, + dfs->dfs_pri_multiplier); + dfs->dfs_phyerr_freq_min = 0x7fffffff; + dfs->dfs_phyerr_freq_max = 0; + } else { + return 0; + } + } + DFS_DPRINTK(dfs, ATH_DEBUG_DFS1, + "%s: pri_multiplier=%d", __func__, dfs->dfs_pri_multiplier); + + ATH_DFSQ_LOCK(dfs); + empty = STAILQ_EMPTY(&(dfs->dfs_radarq)); + ATH_DFSQ_UNLOCK(dfs); + + while ((!empty) && (!retval) && (events_processed < MAX_EVENTS)) { + ATH_DFSQ_LOCK(dfs); + event = STAILQ_FIRST(&(dfs->dfs_radarq)); + if (event != NULL) + STAILQ_REMOVE_HEAD(&(dfs->dfs_radarq), re_list); + ATH_DFSQ_UNLOCK(dfs); + + if (event == NULL) { + empty = 1; + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s[%d]: event is NULL ", __func__, __LINE__); + break; + } + events_processed++; + re = *event; + if (dfs->ic->ic_curchan->ic_80p80_both_dfs) + seg_id = re.radar_80p80_segid; + else + seg_id = DFS_80P80_SEG0; + + pl = (seg_id == 0) ? dfs->pulses : dfs->pulses_ext_seg; + + OS_MEMZERO(event, sizeof(struct dfs_event)); + ATH_DFSEVENTQ_LOCK(dfs); + STAILQ_INSERT_TAIL(&(dfs->dfs_eventq), event, re_list); + ATH_DFSEVENTQ_UNLOCK(dfs); + + found = 0; + qdf_spin_lock_bh(&dfs->ic->chan_lock); + if (dfs->ic->disable_phy_err_processing) { + ATH_DFSQ_LOCK(dfs); + empty = STAILQ_EMPTY(&(dfs->dfs_radarq)); + ATH_DFSQ_UNLOCK(dfs); + qdf_spin_unlock_bh(&dfs->ic->chan_lock); + continue; + } + + qdf_spin_unlock_bh(&dfs->ic->chan_lock); + if (re.re_chanindex < DFS_NUM_RADAR_STATES) + rs = &dfs->dfs_radar[re.re_chanindex]; + else { + ATH_DFSQ_LOCK(dfs); + empty = STAILQ_EMPTY(&(dfs->dfs_radarq)); + ATH_DFSQ_UNLOCK(dfs); + continue; + } + if (rs->rs_chan.ic_flagext & CHANNEL_INTERFERENCE) { + ATH_DFSQ_LOCK(dfs); + empty = STAILQ_EMPTY(&(dfs->dfs_radarq)); + ATH_DFSQ_UNLOCK(dfs); + continue; + } + + if (dfs->dfs_rinfo.rn_lastfull_ts == 0) { + /* + * Either not started, or 64-bit rollover exactly to zero + * Just prepend zeros to the 15-bit ts + */ + dfs->dfs_rinfo.rn_ts_prefix = 0; + } else { + /* WAR 23031- patch duplicate ts on very short pulses */ + /* This pacth has two problems in linux environment. + * 1)The time stamp created and hence PRI depends entirely on the latency. + * If the latency is high, it possibly can split two consecutive + * pulses in the same burst so far away (the same amount of latency) + * that make them look like they are from differenct bursts. It is + * observed to happen too often. It sure makes the detection fail. + * 2)Even if the latency is not that bad, it simply shifts the duplicate + * timestamps to a new duplicate timestamp based on how they are processed. + * This is not worse but not good either. + * + * Take this pulse as a good one and create a probable PRI later + */ + if (re.re_dur == 0 + && re.re_ts == dfs->dfs_rinfo.rn_last_unique_ts) { + debug_dup[debug_dup_cnt++] = '1'; + DFS_DPRINTK(dfs, ATH_DEBUG_DFS1, + " %s deltaT is 0 ", __func__); + } else { + dfs->dfs_rinfo.rn_last_unique_ts = re.re_ts; + debug_dup[debug_dup_cnt++] = '0'; + } + if (debug_dup_cnt >= 32) { + debug_dup_cnt = 0; + } + + if (re.re_ts <= dfs->dfs_rinfo.rn_last_ts) { + dfs->dfs_rinfo.rn_ts_prefix += + (((uint64_t) 1) << DFS_TSSHIFT); + /* Now, see if it's been more than 1 wrap */ + deltafull_ts = + re.re_full_ts - + dfs->dfs_rinfo.rn_lastfull_ts; + if (deltafull_ts > + ((uint64_t) + ((DFS_TSMASK - dfs->dfs_rinfo.rn_last_ts) + + 1 + re.re_ts))) + deltafull_ts -= + (DFS_TSMASK - + dfs->dfs_rinfo.rn_last_ts) + 1 + + re.re_ts; + deltafull_ts = deltafull_ts >> DFS_TSSHIFT; + if (deltafull_ts > 1) { + dfs->dfs_rinfo.rn_ts_prefix += + ((deltafull_ts - 1) << DFS_TSSHIFT); + } + } else { + deltafull_ts = + re.re_full_ts - + dfs->dfs_rinfo.rn_lastfull_ts; + if (deltafull_ts > (uint64_t) DFS_TSMASK) { + deltafull_ts = + deltafull_ts >> DFS_TSSHIFT; + dfs->dfs_rinfo.rn_ts_prefix += + ((deltafull_ts - 1) << DFS_TSSHIFT); + } + } + } + /* + * At this stage rn_ts_prefix has either been blanked or + * calculated, so it's safe to use. + */ + this_ts = dfs->dfs_rinfo.rn_ts_prefix | ((uint64_t) re.re_ts); + dfs->dfs_rinfo.rn_lastfull_ts = re.re_full_ts; + dfs->dfs_rinfo.rn_last_ts = re.re_ts; + + /* + * The hardware returns the duration in a variety of formats, + * so it's converted from the hardware format to TSF (usec) + * values here. + * + * XXX TODO: this should really be done when the PHY error + * is processed, rather than way out here.. + */ + re.re_dur = dfs_process_pulse_dur(dfs, re.re_dur); + + /* + * Calculate the start of the radar pulse. + * + * The TSF is stamped by the MAC upon reception of the + * event, which is (typically?) at the end of the event. + * But the pattern matching code expects the event timestamps + * to be at the start of the event. So to fake it, we + * subtract the pulse duration from the given TSF. + * + * This is done after the 64-bit timestamp has been calculated + * so long pulses correctly under-wrap the counter. Ie, if + * this was done on the 32 (or 15!) bit TSF when the TSF + * value is closed to 0, it will underflow to 0xfffffXX, which + * would mess up the logical "OR" operation done above. + * + * This isn't valid for Peregrine as the hardware gives us + * the actual TSF offset of the radar event, not just the MAC + * TSF of the completed receive. + * + * XXX TODO: ensure that the TLV PHY error processing + * code will correctly calculate the TSF to be the start + * of the radar pulse. + * + * XXX TODO TODO: modify the TLV parsing code to subtract + * the duration from the TSF, based on the current fast clock + * value. + */ + if ((!dfs->dfs_caps.ath_chip_is_bb_tlv) && re.re_dur != 1) { + this_ts -= re.re_dur; + } + + /* Save the pulse parameters in the pulse buffer(pulse line) */ + index = (pl->pl_lastelem + 1) & DFS_MAX_PULSE_BUFFER_MASK; + if (pl->pl_numelems == DFS_MAX_PULSE_BUFFER_SIZE) + pl->pl_firstelem = + (pl->pl_firstelem + 1) & DFS_MAX_PULSE_BUFFER_MASK; + else + pl->pl_numelems++; + pl->pl_lastelem = index; + pl->pl_elems[index].p_time = this_ts; + pl->pl_elems[index].p_dur = re.re_dur; + pl->pl_elems[index].p_rssi = re.re_rssi; + if (seg_id == 0) { + diff_ts = (uint32_t) this_ts - dfs->test_ts; + dfs->test_ts = (uint32_t) this_ts; + } else { + diff_ts = (u_int32_t)this_ts - dfs->test_ts_ext_seg; + dfs->test_ts_ext_seg = (u_int32_t)this_ts; + } + DFS_DPRINTK(dfs, ATH_DEBUG_DFS1, + "ts%u %u %u diff %u pl->pl_lastelem.p_time=%llu", + (uint32_t) this_ts, re.re_dur, re.re_rssi, diff_ts, + (unsigned long long)pl->pl_elems[index].p_time); + if (dfs->dfs_event_log_on) { + i = dfs->dfs_event_log_count % DFS_EVENT_LOG_SIZE; + dfs->radar_log[i].ts = this_ts; + dfs->radar_log[i].diff_ts = diff_ts; + dfs->radar_log[i].rssi = re.re_rssi; + dfs->radar_log[i].dur = re.re_dur; + dfs->dfs_event_log_count++; + } + if (re.rsu_version == DFS_RADAR_SUMMARY_REPORT_VERSION_3) { + if ((re.re_flags & DFS_EVENT_HW_CHIRP) == + DFS_EVENT_HW_CHIRP) + is_hw_chirp = 1; + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO, + "\n %s[%d]:PHYERR# = %d ts = %u diff_ts = %u ppdu_rssi = %u dur = %u is_hw_chirp = %d segid = %d sidx = %d peak_mag = %d delta_peak = %d delta_diff = %d agc_total_gain = %d agc_mb_gain = %d radar_subchan_mask = 0x%x pulse_height = %d triggering_agc_event = %d rs_pulse_rssi = %d pri80_inband_power = %d ext80_inband_power = %d\n", + __func__, __LINE__, + re.dfs_phyerr_eventq_serial_num, + (uint32_t) this_ts, + diff_ts, re.re_rssi, re.re_dur, is_hw_chirp, + re.radar_80p80_segid, re.sidx, re.peak_mag, + re.delta_peak, re.delta_diff, + re.agc_total_gain, re.agc_mb_gain, + re.radar_subchan_mask, re.pulse_height, + re.triggering_agc_event, re.pulse_rssi, + re.radar_fft_pri80_inband_power, + re.radar_fft_ext80_inband_power); + } else { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO, + "%s[%d]:xxxxx ts =%u re.re_dur=%u re.re_rssi =%u diff =%u pl->pl_lastelem.p_time=%llu xxxxx", + __func__, __LINE__, (uint32_t) this_ts, re.re_dur, + re.re_rssi, diff_ts, + (unsigned long long)pl->pl_elems[index].p_time); + } + + /* If diff_ts is very small, we might be getting false pulse detects + * due to heavy interference. We might be getting spectral splatter + * from adjacent channel. In order to prevent false alarms we + * clear the delay-lines. This might impact positive detections under + * harsh environments, but helps with false detects. */ + + if (diff_ts < 100) { + dfs_reset_alldelaylines(dfs, seg_id); + dfs_reset_radarq(dfs); + } + found = 0; + + /* + * Use this fix only when device is not in test mode, as + * it drops some valid phyerrors. + * In FCC or JAPAN domain,if the follwing signature matches + * its likely that this is a false radar pulse pattern + * so process the next pulse in the queue. + */ + if ((dfs->disable_dfs_ch_switch == false) && + (DFS_FCC_REGION == dfs->dfsdomain || + DFS_MKK_REGION == dfs->dfsdomain) && + (re.re_dur >= 11 && re.re_dur <= 20) && + (diff_ts > 500 || diff_ts <= 305) && + (re.sidx == -4)) { + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO, + "\n%s: Rejecting on Peak Index = %d,re.re_dur = %d,diff_ts = %d\n", + __func__, re.sidx, re.re_dur, diff_ts); + + ATH_DFSQ_LOCK(dfs); + empty = STAILQ_EMPTY(&(dfs->dfs_radarq)); + ATH_DFSQ_UNLOCK(dfs); + continue; + } + + /* + * Modifying the pulse duration for FCC Type 4 + * or JAPAN W56 Type 6 radar pulses when the + * following condition is reported in radar + * summary report. + */ + if ((DFS_FCC_REGION == dfs->dfsdomain || + DFS_MKK_REGION == dfs->dfsdomain) && + ((chan->ic_flags & IEEE80211_CHAN_VHT80) == + IEEE80211_CHAN_VHT80) && + (chan->ic_pri_freq_center_freq_mhz_separation == + DFS_WAR_PLUS_30_MHZ_SEPARATION || + chan->ic_pri_freq_center_freq_mhz_separation == + DFS_WAR_MINUS_30_MHZ_SEPARATION) && + (re.sidx == DFS_WAR_PEAK_INDEX_ZERO) && + (re.re_dur > DFS_TYPE4_WAR_PULSE_DURATION_LOWER_LIMIT && + re.re_dur < DFS_TYPE4_WAR_PULSE_DURATION_UPPER_LIMIT) && + (diff_ts > DFS_TYPE4_WAR_PRI_LOWER_LIMIT && + diff_ts < DFS_TYPE4_WAR_PRI_UPPER_LIMIT)) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO, + "%s:chan->ic_flags=0x%x, MHz separation=%d\n", + __func__, chan->ic_flags, + chan->ic_pri_freq_center_freq_mhz_separation); + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO, + "%s: Peak Idx =%d,re.re_dur =%d,diff_ts =%d\n", + __func__, re.sidx, re.re_dur, diff_ts); + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO, + "\n%s: Modify pulse dur to fit valid range \n", + __func__); + + re.re_dur = DFS_TYPE4_WAR_VALID_PULSE_DURATION; + } + + /* + * Modifying the pulse duration for ETSI Type 2 + * and ETSI type 3 radar pulses when the following + * condition is reported in radar summary report. + */ + if ((DFS_ETSI_REGION == dfs->dfsdomain) && + ((chan->ic_flags & IEEE80211_CHAN_VHT80) == + IEEE80211_CHAN_VHT80) && + (chan->ic_pri_freq_center_freq_mhz_separation == + DFS_WAR_PLUS_30_MHZ_SEPARATION || + chan->ic_pri_freq_center_freq_mhz_separation == + DFS_WAR_MINUS_30_MHZ_SEPARATION) && + (re.sidx == DFS_WAR_PEAK_INDEX_ZERO) && + (re.re_dur > + DFS_ETSI_TYPE2_TYPE3_WAR_PULSE_DUR_LOWER_LIMIT && + re.re_dur < + DFS_ETSI_TYPE2_TYPE3_WAR_PULSE_DUR_UPPER_LIMIT) && + ((diff_ts > DFS_ETSI_TYPE2_WAR_PRI_LOWER_LIMIT && + diff_ts < DFS_ETSI_TYPE2_WAR_PRI_UPPER_LIMIT) || + (diff_ts > DFS_ETSI_TYPE3_WAR_PRI_LOWER_LIMIT && + diff_ts < DFS_ETSI_TYPE3_WAR_PRI_UPPER_LIMIT))) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO, + "\n%s:chan->ic_flags=0x%x,MHz Separation=%d\n", + __func__, chan->ic_flags, + chan->ic_pri_freq_center_freq_mhz_separation); + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO, + "%s:Peak Index =%d,re.re_dur =%d,diff_ts =%d\n", + __func__, re.sidx, re.re_dur, diff_ts); + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO, + "%s:Modify ETSI pulse dur to valid range \n", + __func__); + + re.re_dur = DFS_ETSI_WAR_VALID_PULSE_DURATION; + } + + /* BIN5 pulses are FCC and Japan specific */ + + if ((dfs->dfsdomain == DFS_FCC_REGION) + || (dfs->dfsdomain == DFS_MKK_REGION)) { + for (p = 0; + (p < dfs->dfs_rinfo.rn_numbin5radars) && (!found); + p++) { + struct dfs_bin5radars *br; + + br = (seg_id == 0) ? + &(dfs->dfs_b5radars[p]) : + &(dfs->dfs_b5radars_ext_seg[p]); + + if (dfs_bin5_check_pulse(dfs, &re, br)) { + /* + * This is a valid Bin5 pulse, + * check if it belongs to a burst + */ + re.re_dur = + dfs_retain_bin5_burst_pattern(dfs, + diff_ts, re.re_dur, seg_id); + /* + * Remember our computed duration for + * the next pulse in the burst + * (if needed) + */ + if (seg_id == 0) + dfs->dfs_rinfo. + dfs_last_bin5_dur = + re.re_dur; + else + dfs->dfs_rinfo. + dfs_last_bin5_dur_ext_seg = + re.re_dur; + + if (dfs_bin5_addpulse + (dfs, br, &re, this_ts)) { + found |= dfs_bin5_check(dfs, + seg_id); + } + } else { + DFS_DPRINTK(dfs, + ATH_DEBUG_DFS_BIN5_PULSE, + "%s not a BIN5 pulse (dur=%d)", + __func__, re.re_dur); + } + } + } + + if (found) { + DFS_DPRINTK(dfs, ATH_DEBUG_DFS, "%s: Found bin5 radar", + __func__); + retval |= found; + goto dfsfound; + } + + tabledepth = 0; + rf = NULL; + DFS_DPRINTK(dfs, ATH_DEBUG_DFS1, + " *** chan freq (%d): ts %llu dur %u rssi %u", + rs->rs_chan.ic_freq, (unsigned long long)this_ts, + re.re_dur, re.re_rssi); + + while ((tabledepth < DFS_MAX_RADAR_OVERLAP) && + ((dfs->dfs_radartable[re.re_dur])[tabledepth] != -1) && + (!retval)) { + ft = dfs-> + dfs_radarf[((dfs-> + dfs_radartable[re. + re_dur])[tabledepth])]; + DFS_DPRINTK(dfs, ATH_DEBUG_DFS2, + " ** RD (%d): ts %x dur %u rssi %u", + rs->rs_chan.ic_freq, re.re_ts, re.re_dur, + re.re_rssi); + + if (re.re_rssi < ft->ft_rssithresh && re.re_dur > 4) { + DFS_DPRINTK(dfs, ATH_DEBUG_DFS2, + "%s : Rejecting on rssi rssi=%u thresh=%u", + __func__, re.re_rssi, + ft->ft_rssithresh); + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_INFO, + "%s[%d]: Rejecting on rssi rssi=%u thresh=%u", + __func__, __LINE__, re.re_rssi, + ft->ft_rssithresh); + tabledepth++; + ATH_DFSQ_LOCK(dfs); + empty = STAILQ_EMPTY(&(dfs->dfs_radarq)); + ATH_DFSQ_UNLOCK(dfs); + continue; + } + deltaT = this_ts - ft->ft_last_ts; + DFS_DPRINTK(dfs, ATH_DEBUG_DFS2, + "deltaT = %lld (ts: 0x%llx) (last ts: 0x%llx)", + (unsigned long long)deltaT, + (unsigned long long)this_ts, + (unsigned long long)ft->ft_last_ts); + if ((deltaT < ft->ft_minpri) && (deltaT != 0)) { + /* This check is for the whole filter type. Individual filters + will check this again. This is first line of filtering. */ + DFS_DPRINTK(dfs, ATH_DEBUG_DFS2, + "%s: Rejecting on pri pri=%lld minpri=%u", + __func__, + (unsigned long long)deltaT, + ft->ft_minpri); + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_INFO, + "%s[%d]:Rejecting on pri pri=%lld minpri=%u", + __func__, __LINE__, + (unsigned long long)deltaT, + ft->ft_minpri); + tabledepth++; + continue; + } + for (p = 0, found = 0; + (p < ft->ft_numfilters) && (!found); p++) { + rf = ft->ft_filters[p]; + dl = (seg_id == 0) ? &rf->rf_dl : + &rf->rf_dl_ext_seg; + if ((re.re_dur >= rf->rf_mindur) + && (re.re_dur <= rf->rf_maxdur)) { + /* The above check is probably not necessary */ + deltaT = + (this_ts < dl->dl_last_ts) ? + (int64_t) + ((DFS_TSF_WRAP - + dl->dl_last_ts) + + this_ts + 1) : + this_ts - dl->dl_last_ts; + + if ((deltaT < rf->rf_minpri) + && (deltaT != 0)) { + /* Second line of PRI filtering. */ + DFS_DPRINTK(dfs, ATH_DEBUG_DFS2, + "filterID %d : Rejecting on individual filter min PRI deltaT=%lld rf->rf_minpri=%u", + rf->rf_pulseid, + (unsigned long long) + deltaT, + rf->rf_minpri); + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_INFO, + "%s[%d]:filterID= %d::Rejecting on individual filter min PRI deltaT=%lld rf->rf_minpri=%u", + __func__, __LINE__, + rf->rf_pulseid, + (unsigned long long) + deltaT, + rf->rf_minpri); + continue; + } + + if (rf->rf_ignore_pri_window > 0) { + if (deltaT < rf->rf_minpri) { + DFS_DPRINTK(dfs, + ATH_DEBUG_DFS2, + "filterID %d : Rejecting on individual filter max PRI deltaT=%lld rf->rf_minpri=%u", + rf-> + rf_pulseid, + (unsigned + long long) + deltaT, + rf-> + rf_minpri); + QDF_TRACE + (QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_INFO, + "%s[%d]:filterID= %d :: Rejecting on individual filter max PRI deltaT=%lld rf->rf_minpri=%u", + __func__, __LINE__, + rf->rf_pulseid, + (unsigned long + long)deltaT, + rf->rf_minpri); + /* But update the last time stamp */ + dl->dl_last_ts = + this_ts; + continue; + } + } else { + + /* + The HW may miss some pulses especially with high channel loading. + This is true for Japan W53 where channel loaoding is 50%. Also + for ETSI where channel loading is 30% this can be an issue too. + To take care of missing pulses, we introduce pri_margin multiplie. + This is normally 2 but can be higher for W53. + */ + + if ((deltaT > + ((u_int64_t)dfs-> + dfs_pri_multiplier * + rf->rf_maxpri)) + || (deltaT < + rf->rf_minpri)) { + DFS_DPRINTK(dfs, + ATH_DEBUG_DFS2, + "filterID %d : Rejecting on individual filter max PRI deltaT=%lld rf->rf_minpri=%u", + rf-> + rf_pulseid, + (unsigned + long long) + deltaT, + rf-> + rf_minpri); + QDF_TRACE + (QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_INFO, + "%s[%d]:filterID= %d :: Rejecting on individual filter max PRI deltaT=%lld rf->rf_minpri=%u", + __func__, __LINE__, + rf->rf_pulseid, + (unsigned long + long)deltaT, + rf->rf_minpri); + /* But update the last time stamp */ + dl->dl_last_ts = + this_ts; + continue; + } + } + dfs_add_pulse(dfs, rf, &re, deltaT, + this_ts, seg_id); + + /* If this is an extension channel event, flag it for false alarm reduction */ + if (re.re_chanindex == + dfs->dfs_extchan_radindex) { + ext_chan_event_flag = 1; + } + if (rf->rf_patterntype == 2) { + found = + dfs_staggered_check(dfs, + rf, + (uint32_t)deltaT, + re.re_dur, seg_id); + } else { + found = + dfs_bin_check(dfs, rf, + (uint32_t)deltaT, + re.re_dur, + ext_chan_event_flag, + seg_id); + } + if (dfs-> + dfs_debug_mask & ATH_DEBUG_DFS2) { + dfs_print_delayline(dfs, dl); + } + dl->dl_last_ts = this_ts; + } + } + ft->ft_last_ts = this_ts; + retval |= found; + if (found) { + DFS_DPRINTK(dfs, ATH_DEBUG_DFS3, + "Found on channel minDur = %d, filterId = %d", + ft->ft_mindur, + rf != NULL ? rf->rf_pulseid : -1); + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO, + "%s[%d]:### Found on channel minDur = %d, filterId = %d seg_id = %d ###", + __func__, __LINE__, ft->ft_mindur, + rf != NULL ? rf->rf_pulseid : -1, + seg_id); + } + tabledepth++; + } + ATH_DFSQ_LOCK(dfs); + empty = STAILQ_EMPTY(&(dfs->dfs_radarq)); + ATH_DFSQ_UNLOCK(dfs); + } +dfsfound: + if (retval) { + /* Collect stats */ + dfs->ath_dfs_stats.num_radar_detects++; + thischan = &rs->rs_chan; + + /* + * Since we support 80p80 mode, indicate the + * segment on which the radar has been detected. + * only if both segments are dfs in 80p80 mode + * and the radar is found on ext the segment + * ic_radar_found_segid is to 1, in all other + * cases it is set to 0. + */ + dfs->ic->ic_curchan->ic_radar_found_segid = seg_id; + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s[%d]:### RADAR FOUND ON CHANNEL %d (%d MHz),seg_id=%d ###", + __func__, __LINE__, thischan->ic_ieee, + thischan->ic_freq, seg_id); + DFS_PRINTK("Radar found on channel %d (%d MHz)", + thischan->ic_ieee, thischan->ic_freq); + +#if 0 /* UMACDFS : TODO */ + /* Disable radar for now */ + rfilt = ath_hal_getrxfilter(ah); + rfilt &= ~HAL_RX_FILTER_PHYRADAR; + ath_hal_setrxfilter(ah, rfilt); +#endif + dfs_reset_radarq(dfs); + + /* + * For now reset both segments + * until we have changes for us + * to do sub-channel marking which + * enables SAP to continue to use the 80 + * segment where radar was not detected + * and as a result CAC can be avoided on + * that segment. Currently we do not support + * sub-channel marking. + */ + dfs_reset_alldelaylines(dfs, DFS_80P80_SEG0); + + if (dfs->ic->ic_curchan->ic_80p80_both_dfs) + dfs_reset_alldelaylines(dfs, DFS_80P80_SEG1); + + /* XXX Should we really enable again? Maybe not... */ +/* No reason to re-enable so far - Ajay*/ +#if 0 + pe.pe_firpwr = rs->rs_firpwr; + pe.pe_rrssi = rs->rs_radarrssi; + pe.pe_height = rs->rs_height; + pe.pe_prssi = rs->rs_pulserssi; + pe.pe_inband = rs->rs_inband; + /* 5413 specific */ + pe.pe_relpwr = rs->rs_relpwr; + pe.pe_relstep = rs->rs_relstep; + pe.pe_maxlen = rs->rs_maxlen; + + ath_hal_enabledfs(ah, &pe); + rfilt |= HAL_RX_FILTER_PHYRADAR; + ath_hal_setrxfilter(ah, rfilt); +#endif + DFS_DPRINTK(dfs, ATH_DEBUG_DFS1, + "Primary channel freq = %u flags=0x%x", + chan->ic_freq, chan->ic_flagext); + qdf_spin_lock_bh(&dfs->ic->chan_lock); + if ((dfs->ic->ic_curchan->ic_freq != thischan->ic_freq)) { + qdf_spin_unlock_bh(&dfs->ic->chan_lock); + DFS_DPRINTK(dfs, ATH_DEBUG_DFS1, + "Ext channel freq = %u flags=0x%x", + thischan->ic_freq, thischan->ic_flagext); + } + + qdf_spin_unlock_bh(&dfs->ic->chan_lock); + dfs->dfs_phyerr_freq_min = 0x7fffffff; + dfs->dfs_phyerr_freq_max = 0; + dfs->dfs_phyerr_w53_counter = 0; + } + /* QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO, "IN FUNC %s[%d]: retval = %d ",__func__,__LINE__,retval); */ + return retval; +/* #endif */ +/* return 1; */ +} + +#endif /* ATH_SUPPORT_DFS */ diff --git a/drivers/staging/qcacld-3.0/core/sap/dfs/src/dfs_staggered.c b/drivers/staging/qcacld-3.0/core/sap/dfs/src/dfs_staggered.c new file mode 100644 index 0000000000000000000000000000000000000000..cf00e741d1ad6753a5a5be2e29517ba19ebe8228 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/sap/dfs/src/dfs_staggered.c @@ -0,0 +1,312 @@ +/* + * Copyright (c) 2002-2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/*=========================================================================== + + dfs_staggered.c + + OVERVIEW: + + Source code borrowed from QCA_MAIN DFS module + + DEPENDENCIES: + + Are listed for each API below. + + ===========================================================================*/ + +/*=========================================================================== + + EDIT HISTORY FOR FILE + + This section contains comments describing changes made to the module. + Notice that changes are listed in reverse chronological order. + + when who what, where, why + ---------- --- -------------------------------------------------------- + + ===========================================================================*/ + +#include "dfs.h" +/* TO DO DFS + #include + */ +#ifdef ATH_SUPPORT_DFS + +static int is_pri_multiple(uint32_t sample_pri, uint32_t refpri) +{ +#define MAX_ALLOWED_MISSED 3 + int i; + + if (sample_pri < refpri || (!refpri)) + return 0; + + for (i = 1; i <= MAX_ALLOWED_MISSED; i++) { + if ((sample_pri % (i * refpri) <= 5)) { + /* printk("sample_pri=%d is a multiple of refpri=%d\n", sample_pri, refpri); */ + return 1; + } + } + return 0; +#undef MAX_ALLOWED_MISSED +} + +static int is_unique_pri(uint32_t highestpri, uint32_t midpri, + uint32_t lowestpri, uint32_t refpri) +{ +#define DFS_STAGGERED_PRI_MARGIN_MIN 20 +#define DFS_STAGGERED_PRI_MARGIN_MAX 400 + if ((DFS_DIFF(lowestpri, refpri) >= DFS_STAGGERED_PRI_MARGIN_MIN) && + (DFS_DIFF(midpri, refpri) >= DFS_STAGGERED_PRI_MARGIN_MIN) && + (DFS_DIFF(highestpri, refpri) >= DFS_STAGGERED_PRI_MARGIN_MIN)) { + return 1; + } else { + if ((is_pri_multiple(refpri, highestpri)) + || (is_pri_multiple(refpri, lowestpri)) + || (is_pri_multiple(refpri, midpri))) + return 0; + } + return 0; +#undef DFS_STAGGERED_PRI_MARGIN_MIN +#undef DFS_STAGGERED_PRI_MARGIN_MAX +} + +int dfs_staggered_check(struct ath_dfs *dfs, struct dfs_filter *rf, + uint32_t deltaT, uint32_t width, int seg_id) +{ + uint32_t refpri, refdur, searchpri = 0, deltapri; /* , averagerefpri; */ + uint32_t n, i, primargin, durmargin; + int score[DFS_MAX_DL_SIZE], delayindex, dindex, found = 0; + struct dfs_delayline *dl; + uint32_t scoreindex, lowpriindex = 0, lowpri = 0xffff; +#if 0 + int numpulses = 0; +#endif + int higherthan, lowerthan, numscores; + int numpulseshigh = 0, numpulsesmid = 0, numpulsestemp = 0; + uint32_t lowestscore = 0, lowestscoreindex = 0, lowestpri = 0; + uint32_t midscore = 0, midscoreindex = 0, midpri = 0; + uint32_t highestscore = 0, highestscoreindex = 0, highestpri = 0; + + if (dfs->ic->ic_curchan->ic_80p80_both_dfs) + dl = (seg_id == 0) ? &rf->rf_dl : &rf->rf_dl_ext_seg; + else + dl = &rf->rf_dl; + + if (dl->dl_numelems < (rf->rf_threshold - 1)) { + DFS_DPRINTK(dfs, ATH_DEBUG_DFS2, + "numelems %d < threshold for filter %d\n", + dl->dl_numelems, rf->rf_pulseid); + return 0; + } + if (deltaT > rf->rf_filterlen) { + DFS_DPRINTK(dfs, ATH_DEBUG_DFS2, + "numelems %d < threshold for filter %d\n", + dl->dl_numelems, rf->rf_pulseid); + return 0; + } + primargin = 6; + if (rf->rf_maxdur < 10) { + durmargin = 4; + } else { + durmargin = 6; + } + + OS_MEMZERO(score, sizeof(int) * DFS_MAX_DL_SIZE); + /* find out the lowest pri */ + for (n = 0; n < dl->dl_numelems; n++) { + delayindex = (dl->dl_firstelem + n) & DFS_MAX_DL_MASK; + refpri = dl->dl_elems[delayindex].de_time; + if (refpri == 0) + continue; + else if (refpri < lowpri) { + lowpri = dl->dl_elems[delayindex].de_time; + lowpriindex = n; + } + } + /* find out the each delay element's pri score */ + for (n = 0; n < dl->dl_numelems; n++) { + delayindex = (dl->dl_firstelem + n) & DFS_MAX_DL_MASK; + refpri = dl->dl_elems[delayindex].de_time; + if (refpri == 0) { + continue; + } + + if ((refpri > rf->rf_maxpri) || (refpri < rf->rf_minpri)) { + score[n] = 0; + continue; + } + + for (i = 0; i < dl->dl_numelems; i++) { + dindex = (dl->dl_firstelem + i) & DFS_MAX_DL_MASK; + searchpri = dl->dl_elems[dindex].de_time; + deltapri = DFS_DIFF(searchpri, refpri); + if (deltapri < primargin) + score[n]++; + } + } + for (n = 0; n < dl->dl_numelems; n++) { + delayindex = (dl->dl_firstelem + n) & DFS_MAX_DL_MASK; + refdur = dl->dl_elems[delayindex].de_time; + DFS_DPRINTK(dfs, ATH_DEBUG_DFS2, "score[%d]=%d pri=%d\n", n, + score[n], refdur); + } + + /* find out the 2 or 3 highest scorers */ + scoreindex = 0; + highestscore = 0; + highestscoreindex = 0; + highestpri = 0; + numscores = 0; + lowestscore = 0; + + for (n = 0; n < dl->dl_numelems; n++) { + higherthan = 0; + lowerthan = 0; + delayindex = (dl->dl_firstelem + n) & DFS_MAX_DL_MASK; + refpri = dl->dl_elems[delayindex].de_time; + + if ((score[n] >= highestscore) && + (is_unique_pri(highestpri, midpri, lowestpri, refpri))) { + lowestscore = midscore; + lowestpri = midpri; + lowestscoreindex = midscoreindex; + midscore = highestscore; + midpri = highestpri; + midscoreindex = highestscoreindex; + highestscore = score[n]; + highestpri = refpri; + highestscoreindex = n; + } else { + if ((score[n] >= midscore) && + (is_unique_pri + (highestpri, midpri, lowestpri, refpri))) { + lowestscore = midscore; + lowestpri = midpri; + lowestscoreindex = midscoreindex; + midscore = score[n]; + midpri = refpri; + midscoreindex = n; + } else if ((score[n] >= lowestscore) && + (is_unique_pri + (highestpri, midpri, lowestpri, refpri))) { + lowestscore = score[n]; + lowestpri = refpri; + lowestscoreindex = n; + } + } + + } + + if (midscore == 0) { + /* This means we have only 1 pulse type. It can not be staggered! */ + return 0; + } + + DFS_DPRINTK(dfs, ATH_DEBUG_DFS1, + "FINAL highestscore=%d highestscoreindex=%d highestpri=%d\n", + highestscore, highestscoreindex, highestpri); + DFS_DPRINTK(dfs, ATH_DEBUG_DFS1, + "FINAL lowestscore=%d lowestscoreindex=%d lowpri=%d\n", + lowestscore, lowestscoreindex, lowestpri); + DFS_DPRINTK(dfs, ATH_DEBUG_DFS1, + "FINAL midscore=%d midscoreindex=%d midpri=%d\n", + midscore, midscoreindex, midpri); + + delayindex = (dl->dl_firstelem + highestscoreindex) & DFS_MAX_DL_MASK; + refdur = dl->dl_elems[delayindex].de_dur; + refpri = dl->dl_elems[delayindex].de_time; + DFS_DPRINTK(dfs, ATH_DEBUG_DFS1, + "highscoreindex=%d refdur=%d refpri=%d\n", + highestscoreindex, refdur, refpri); + + numpulsestemp = + dfs_bin_pri_check(dfs, rf, dl, highestscore, refpri, refdur, 0, + highestpri); + numpulseshigh = numpulsestemp; + numpulsestemp = + dfs_bin_pri_check(dfs, rf, dl, highestscore, refpri, refdur, 0, + highestpri + midpri); + if (numpulsestemp > numpulseshigh) { + numpulseshigh = numpulsestemp; + } + numpulsestemp = + dfs_bin_pri_check(dfs, rf, dl, highestscore, refpri, refdur, 0, + highestpri + midpri + lowestpri); + if (numpulsestemp > numpulseshigh) { + numpulseshigh = numpulsestemp; + } + + delayindex = (dl->dl_firstelem + midscoreindex) & DFS_MAX_DL_MASK; + refdur = dl->dl_elems[delayindex].de_dur; + refpri = dl->dl_elems[delayindex].de_time; + DFS_DPRINTK(dfs, ATH_DEBUG_DFS1, + "midscoreindex=%d refdur=%d refpri=%d\n", + midscoreindex, refdur, refpri); + + /* numpulsesmid = dfs_bin_pri_check(dfs, rf, dl, midscore, refpri, refdur,0, 1); */ + numpulsestemp = + dfs_bin_pri_check(dfs, rf, dl, midscore, refpri, refdur, 0, midpri); + numpulsesmid = numpulsestemp; + numpulsestemp = + dfs_bin_pri_check(dfs, rf, dl, midscore, refpri, refdur, 0, + highestpri + midpri); + if (numpulsestemp > numpulsesmid) { + numpulsesmid = numpulsestemp; + } + numpulsestemp = + dfs_bin_pri_check(dfs, rf, dl, midscore, refpri, refdur, 0, + highestpri + midpri + lowestpri); + if (numpulsestemp > numpulsesmid) { + numpulsesmid = numpulsestemp; + } + + /*delayindex = (dl->dl_firstelem + lowestscoreindex) & DFS_MAX_DL_MASK; + refdur = dl->dl_elems[delayindex].de_dur; + refpri = dl->dl_elems[delayindex].de_time; + DFS_DPRINTK(ic, ATH_DEBUG_DFS1, "lowestscoreindex=%d refdur=%d refpri=%d\n", lowestscoreindex, refdur, refpri); + + numpulseslow = dfs_bin_pri_check(dfs, rf, dl, lowestscore, refpri, refdur,0, 1); + */ + DFS_DPRINTK(dfs, ATH_DEBUG_DFS2, + "numpulseshigh=%d, numpulsesmid=%d\n", + numpulseshigh, numpulsesmid); +/* printf("numpulseshigh=%d, numpulsesmid=%d, numpulseslow %d\n",numpulseshigh, numpulsesmid, numpulseslow); */ + + if ((numpulseshigh >= rf->rf_threshold) + && (numpulsesmid >= rf->rf_threshold)) { + /*if (numpulses >= rf->rf_threshold) { */ + found = 1; + DFS_DPRINTK(dfs, ATH_DEBUG_DFS2, + "MATCH filter=%u numpulseshigh=%u numpulsesmid= %u thresh=%u\n", + rf->rf_pulseid, numpulseshigh, numpulsesmid, + rf->rf_threshold); + } + return found; +} + +#endif /* ATH_SUPPORT_DFS */ diff --git a/drivers/staging/qcacld-3.0/core/sap/inc/sap_api.h b/drivers/staging/qcacld-3.0/core/sap/inc/sap_api.h new file mode 100644 index 0000000000000000000000000000000000000000..43ab6ff32bc40308ee320d532e15182b767f6413 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/sap/inc/sap_api.h @@ -0,0 +1,992 @@ +/* + * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef WLAN_QCT_WLANSAP_H +#define WLAN_QCT_WLANSAP_H + +/** + * W L A N S O F T A P P A L L A Y E R + * E X T E R N A L A P I + * + * DESCRIPTION + * This file contains the external API exposed by the wlan SAP PAL layer + * module. + */ + +/*---------------------------------------------------------------------------- + * Include Files + * -------------------------------------------------------------------------*/ +#include "cds_api.h" +#include "cds_packet.h" +#include "qdf_types.h" + +#include "p2p_api.h" +#include "sme_api.h" +/*---------------------------------------------------------------------------- + * Preprocessor Definitions and Constants + * -------------------------------------------------------------------------*/ +#ifdef __cplusplus +extern "C" { +#endif + +/*--------------------------------------------------------------------------- + * defines and enum + *--------------------------------------------------------------------------*/ +#define MAX_SSID_LEN 32 +#define MAX_ACL_MAC_ADDRESS 32 +#define AUTO_CHANNEL_SELECT 0 +#define MAX_ASSOC_IND_IE_LEN 255 + +/* defines for WPS config states */ +#define SAP_WPS_DISABLED 0 +#define SAP_WPS_ENABLED_UNCONFIGURED 1 +#define SAP_WPS_ENABLED_CONFIGURED 2 +#define MAX_NAME_SIZE 64 +#define MAX_TEXT_SIZE 32 + +#define MAX_CHANNEL_LIST_LEN 256 +#define QDF_MAX_NO_OF_SAP_MODE 2 /* max # of SAP */ +#define SAP_MAX_NUM_SESSION 5 +#define SAP_MAX_OBSS_STA_CNT 1 /* max # of OBSS STA */ +#define SAP_ACS_WEIGHT_MAX (4444) + +/*-------------------------------------------------------------------------- + * reasonCode taken from 802.11 standard. + * ------------------------------------------------------------------------*/ + +typedef enum { + eSAP_RC_RESERVED0, /*0 */ + eSAP_RC_UNSPECIFIED, /*1 */ + eSAP_RC_PREV_AUTH_INVALID, /*2 */ + eSAP_RC_STA_LEFT_DEAUTH, /*3 */ + eSAP_RC_INACTIVITY_DISASSOC, /*4 */ + eSAP_RC_AP_CAPACITY_FULL, /*5 */ + eSAP_RC_CLS2_FROM_NON_AUTH_STA, /*6 */ + eSAP_RC_CLS3_FROM_NON_AUTH_STA, /*7 */ + eSAP_RC_STA_LEFT_DISASSOC, /*8 */ + eSAP_RC_STA_NOT_AUTH, /*9 */ + eSAP_RC_PC_UNACCEPTABLE, /*10 */ + eSAP_RC_SC_UNACCEPTABLE, /*11 */ + eSAP_RC_RESERVED1, /*12 */ + eSAP_RC_INVALID_IE, /*13 */ + eSAP_RC_MIC_FAIL, /*14 */ + eSAP_RC_4_WAY_HANDSHAKE_TO, /*15 */ + eSAP_RC_GO_KEY_HANDSHAKE_TO, /*16 */ + eSAP_RC_IE_MISMATCH, /*17 */ + eSAP_RC_INVALID_GRP_CHIPHER, /*18 */ + eSAP_RC_INVALID_PAIR_CHIPHER, /*19 */ + eSAP_RC_INVALID_AKMP, /*20 */ + eSAP_RC_UNSUPPORTED_RSN, /*21 */ + eSAP_RC_INVALID_RSN, /*22 */ + eSAP_RC_1X_AUTH_FAILED, /*23 */ + eSAP_RC_CHIPER_SUITE_REJECTED, /*24 */ +} eSapReasonCode; + +typedef enum { + eSAP_ACCEPT_UNLESS_DENIED = 0, + eSAP_DENY_UNLESS_ACCEPTED = 1, + /* this type is added to support accept & deny list at the same time */ + eSAP_SUPPORT_ACCEPT_AND_DENY = 2, + /*In this mode all MAC addresses are allowed to connect */ + eSAP_ALLOW_ALL = 3, +} eSapMacAddrACL; + +typedef enum { + eSAP_BLACK_LIST = 0, /* List of mac addresses NOT allowed to assoc */ + eSAP_WHITE_LIST = 1, /* List of mac addresses allowed to assoc */ +} eSapACLType; + +typedef enum { + ADD_STA_TO_ACL = 0, /* cmd to add STA to access control list */ + DELETE_STA_FROM_ACL = 1, /* cmd to del STA from access control list */ +} eSapACLCmdType; + +typedef enum { + eSAP_START_BSS_EVENT = 0, /* Event sent when BSS is started */ + eSAP_STOP_BSS_EVENT, /* Event sent when BSS is stopped */ + eSAP_STA_ASSOC_IND, /* Indicate assoc req to upper layers */ + /* + * Event sent when we have successfully associated a station and + * upper layer neeeds to allocate a context + */ + eSAP_STA_ASSOC_EVENT, + /* + * Event sent when we have successfully reassociated a station and + * upper layer neeeds to allocate a context + */ + eSAP_STA_REASSOC_EVENT, + /* + * Event sent when associated a station has disassociated as a + * result of various conditions + */ + eSAP_STA_DISASSOC_EVENT, + /* Event sent when user called wlansap_set_key_sta */ + eSAP_STA_SET_KEY_EVENT, + /* Event sent whenever there is MIC failure detected */ + eSAP_STA_MIC_FAILURE_EVENT, + /* Event sent when user called wlansap_get_assoc_stations */ + eSAP_ASSOC_STA_CALLBACK_EVENT, + /* Event send when user call wlansap_get_wps_session_overlap */ + eSAP_GET_WPSPBC_SESSION_EVENT, + /* Event send on WPS PBC probe request is received */ + eSAP_WPS_PBC_PROBE_REQ_EVENT, + eSAP_REMAIN_CHAN_READY, + eSAP_DISCONNECT_ALL_P2P_CLIENT, + eSAP_MAC_TRIG_STOP_BSS_EVENT, + /* + * Event send when a STA in neither white list or black list tries to + * associate in softap mode + */ + eSAP_UNKNOWN_STA_JOIN, + /* Event send when a new STA is rejected association since softAP + * max assoc limit has reached + */ + eSAP_MAX_ASSOC_EXCEEDED, + eSAP_CHANNEL_CHANGE_EVENT, + eSAP_DFS_CAC_START, + eSAP_DFS_CAC_INTERRUPTED, + eSAP_DFS_CAC_END, + eSAP_DFS_PRE_CAC_END, + eSAP_DFS_RADAR_DETECT, + eSAP_DFS_RADAR_DETECT_DURING_PRE_CAC, + /* Event sent when user need to get the DFS NOL from CNSS */ + eSAP_DFS_NOL_GET, + /* Event sent when user need to set the DFS NOL to CNSS */ + eSAP_DFS_NOL_SET, + /* No ch available after DFS RADAR detect */ + eSAP_DFS_NO_AVAILABLE_CHANNEL, + eSAP_ACS_SCAN_SUCCESS_EVENT, + eSAP_ACS_CHANNEL_SELECTED, + eSAP_ECSA_CHANGE_CHAN_IND, + eSAP_UPDATE_SCAN_RESULT, +} eSapHddEvent; + +typedef enum { + eSAP_OPEN_SYSTEM, + eSAP_SHARED_KEY, + eSAP_AUTO_SWITCH +} eSapAuthType; + +typedef enum { + /* Disassociation was internally initated from CORE stack */ + eSAP_MAC_INITATED_DISASSOC = 0x10000, + /* + * Disassociation was internally initated from host by + * invoking wlansap_disassoc_sta call + */ + eSAP_USR_INITATED_DISASSOC +} eSapDisassocReason; + +/*Handle bool over here*/ +typedef enum { + eSAP_FALSE, + eSAP_TRUE, +} eSapBool; + +typedef enum { + eSAP_DFS_NOL_CLEAR, + eSAP_DFS_NOL_RANDOMIZE, +} eSapDfsNolType; + +/*--------------------------------------------------------------------------- + SAP PAL "status" and "reason" error code defines + ---------------------------------------------------------------------------*/ +typedef enum { + eSAP_STATUS_SUCCESS, /* Success. */ + eSAP_STATUS_FAILURE, /* General Failure. */ + /* Channel not selected during intial scan. */ + eSAP_START_BSS_CHANNEL_NOT_SELECTED, + eSAP_ERROR_MAC_START_FAIL, /* Failed to start Infra BSS */ +} eSapStatus; + +/*--------------------------------------------------------------------------- + SAP PAL "status" and "reason" error code defines + ---------------------------------------------------------------------------*/ +typedef enum { + eSAP_WPSPBC_OVERLAP_IN120S, /* Overlap */ + /* no WPS probe request in 120 second */ + eSAP_WPSPBC_NO_WPSPBC_PROBE_REQ_IN120S, + /* One WPS probe request in 120 second */ + eSAP_WPSPBC_ONE_WPSPBC_PROBE_REQ_IN120S, +} eWPSPBCOverlap; + +/*---------------------------------------------------------------------------- + * Typedefs + * -------------------------------------------------------------------------*/ +typedef struct sap_StartBssCompleteEvent_s { + uint8_t status; + uint8_t operatingChannel; + uint16_t staId; /* self StaID */ + uint8_t sessionId; /* SoftAP SME session ID */ +} tSap_StartBssCompleteEvent; + +typedef struct sap_StopBssCompleteEvent_s { + uint8_t status; +} tSap_StopBssCompleteEvent; + +typedef struct sap_StationAssocIndication_s { + struct qdf_mac_addr staMac; + uint8_t assoId; + uint8_t staId; + uint8_t status; + /* Required for indicating the frames to upper layer */ + uint32_t beaconLength; + uint8_t *beaconPtr; + uint32_t assocReqLength; + uint8_t *assocReqPtr; + bool fWmmEnabled; + eCsrAuthType negotiatedAuthType; + eCsrEncryptionType negotiatedUCEncryptionType; + eCsrEncryptionType negotiatedMCEncryptionType; + bool fAuthRequired; +} tSap_StationAssocIndication; + +typedef struct sap_StationAssocReassocCompleteEvent_s { + struct qdf_mac_addr staMac; + uint8_t staId; + uint8_t status; + uint8_t ies[MAX_ASSOC_IND_IE_LEN]; + uint16_t iesLen; + uint32_t statusCode; + eSapAuthType SapAuthType; + bool wmmEnabled; + /* Required for indicating the frames to upper layer */ + uint32_t beaconLength; + uint8_t *beaconPtr; + uint32_t assocReqLength; + uint8_t *assocReqPtr; + uint32_t assocRespLength; + uint8_t *assocRespPtr; + uint8_t timingMeasCap; + tSirSmeChanInfo chan_info; +} tSap_StationAssocReassocCompleteEvent; + +typedef struct sap_StationDisassocCompleteEvent_s { + struct qdf_mac_addr staMac; + uint8_t staId; /* STAID should not be used */ + uint8_t status; + uint32_t statusCode; + eSapDisassocReason reason; +} tSap_StationDisassocCompleteEvent; + +typedef struct sap_StationSetKeyCompleteEvent_s { + uint8_t status; + struct qdf_mac_addr peerMacAddr; +} tSap_StationSetKeyCompleteEvent; + +/*struct corresponding to SAP_STA_MIC_FAILURE_EVENT */ +typedef struct sap_StationMICFailureEvent_s { + struct qdf_mac_addr srcMacAddr; /* address used to compute MIC */ + struct qdf_mac_addr staMac; /* taMacAddr transmitter address */ + struct qdf_mac_addr dstMacAddr; + eSapBool multicast; + uint8_t IV1; /* first byte of IV */ + uint8_t keyId; /* second byte of IV */ + uint8_t TSC[SIR_CIPHER_SEQ_CTR_SIZE]; /* sequence number */ + +} tSap_StationMICFailureEvent; +/*Structure to return MAC address of associated stations */ +typedef struct sap_AssocMacAddr_s { + struct qdf_mac_addr staMac; /* Associated station's MAC address */ + uint8_t assocId; /* Associated station's Association ID */ + uint8_t staId; /* Allocated station Id */ + uint8_t ShortGI40Mhz; + uint8_t ShortGI20Mhz; + uint8_t Support40Mhz; + uint32_t requestedMCRate; + tSirSupportedRates supportedRates; +} tSap_AssocMacAddr, *tpSap_AssocMacAddr; + +/*struct corresponding to SAP_ASSOC_STA_CALLBACK_EVENT */ +typedef struct sap_AssocStaListEvent_s { + QDF_MODULE_ID module; + /* module id that was passed in wlansap_get_assoc_stations API */ + uint8_t noOfAssocSta; /* Number of associated stations */ + tpSap_AssocMacAddr pAssocStas; + /* + * Pointer to pre allocated memory to obtain list of + * associated stations passed in wlansap_get_assoc_stations API + */ +} tSap_AssocStaListEvent; + +typedef struct sap_GetWPSPBCSessionEvent_s { + uint8_t status; + /* module id that was passed in wlansap_get_assoc_stations API */ + QDF_MODULE_ID module; + uint8_t UUID_E[16]; /* Unique identifier of the AP. */ + struct qdf_mac_addr addr; + eWPSPBCOverlap wpsPBCOverlap; +} tSap_GetWPSPBCSessionEvent; + +typedef struct sap_WPSPBCProbeReqEvent_s { + uint8_t status; + /* module id that was passed in wlansap_get_assoc_stations API */ + QDF_MODULE_ID module; + tSirWPSPBCProbeReq WPSPBCProbeReq; +} tSap_WPSPBCProbeReqEvent; + +typedef struct sap_ManagementFrameInfo_s { + uint32_t nFrameLength; + uint8_t frameType; + uint32_t rxChan; /* Channel of where packet is received */ + /* + * Point to a buffer contain the beacon, assoc req, assoc rsp frame, + * in that order user needs to use nBeaconLength, nAssocReqLength, + * nAssocRspLength to desice where each frame starts and ends. + */ + uint8_t *pbFrames; +} tSap_ManagementFrameInfo; + +typedef struct sap_SendActionCnf_s { + eSapStatus actionSendSuccess; +} tSap_SendActionCnf; + +typedef struct sap_UnknownSTAJoinEvent_s { + struct qdf_mac_addr macaddr; +} tSap_UnknownSTAJoinEvent; + +typedef struct sap_MaxAssocExceededEvent_s { + struct qdf_mac_addr macaddr; +} tSap_MaxAssocExceededEvent; + +typedef struct sap_DfsNolInfo_s { + uint16_t sDfsList; /* size of pDfsList in byte */ + void *pDfsList; /* pointer to pDfsList buffer */ +} tSap_DfsNolInfo; + +/** + * sap_acs_ch_selected_s - the structure to hold the selected channels + * @pri_channel: Holds the ACS selected primary channel + * @sec_channel: Holds the ACS selected secondary channel + * + * Holds the primary and secondary channel selected by ACS and is + * used to send it to the HDD. + */ +struct sap_ch_selected_s { + uint16_t pri_ch; + uint16_t ht_sec_ch; + uint16_t vht_seg0_center_ch; + uint16_t vht_seg1_center_ch; + uint16_t ch_width; +}; + +/** + * sap_roc_ready_ind_s - the structure to hold the scan id + * @scan_id: scan identifier + * + * Holds scan identifier + */ +struct sap_roc_ready_ind_s { + uint32_t scan_id; +}; + +/** + * struct sap_acs_scan_complete_event - acs scan complete event + * @status: status of acs scan + * @channellist: acs scan channels + * @num_of_channels: number of channels + */ +struct sap_acs_scan_complete_event{ + uint8_t status; + uint8_t *channellist; + uint8_t num_of_channels; +}; + +/** + * struct sap_ch_change_ind - channel change indication + * @new_chan: channel to change + */ +struct sap_ch_change_ind { + uint16_t new_chan; +}; + +/* + * This struct will be filled in and passed to tpWLAN_SAPEventCB that is + * provided during wlansap_start_bss call The event id corresponding to + * structure in the union is defined in comment next to the structure + */ + +typedef struct sap_Event_s { + eSapHddEvent sapHddEventCode; + union { + /*SAP_START_BSS_EVENT */ + tSap_StartBssCompleteEvent sapStartBssCompleteEvent; + /*SAP_STOP_BSS_EVENT */ + tSap_StopBssCompleteEvent sapStopBssCompleteEvent; + /*SAP_ASSOC_INDICATION */ + tSap_StationAssocIndication sapAssocIndication; + /*SAP_STA_ASSOC_EVENT, SAP_STA_REASSOC_EVENT */ + tSap_StationAssocReassocCompleteEvent + sapStationAssocReassocCompleteEvent; + /*SAP_STA_DISASSOC_EVENT */ + tSap_StationDisassocCompleteEvent + sapStationDisassocCompleteEvent; + /*SAP_STA_SET_KEY_EVENT */ + tSap_StationSetKeyCompleteEvent sapStationSetKeyCompleteEvent; + /*SAP_STA_MIC_FAILURE_EVENT */ + tSap_StationMICFailureEvent sapStationMICFailureEvent; + /*SAP_ASSOC_STA_CALLBACK_EVENT */ + tSap_AssocStaListEvent sapAssocStaListEvent; + /*SAP_GET_WPSPBC_SESSION_EVENT */ + tSap_GetWPSPBCSessionEvent sapGetWPSPBCSessionEvent; + /*eSAP_WPS_PBC_PROBE_REQ_EVENT */ + tSap_WPSPBCProbeReqEvent sapPBCProbeReqEvent; + tSap_SendActionCnf sapActionCnf; + /* eSAP_UNKNOWN_STA_JOIN */ + tSap_UnknownSTAJoinEvent sapUnknownSTAJoin; + /* eSAP_MAX_ASSOC_EXCEEDED */ + tSap_MaxAssocExceededEvent sapMaxAssocExceeded; + /*eSAP_DFS_NOL_XXX */ + tSap_DfsNolInfo sapDfsNolInfo; + struct sap_ch_selected_s sap_ch_selected; + struct sap_roc_ready_ind_s sap_roc_ind; + struct sap_ch_change_ind sap_chan_cng_ind; + struct sap_acs_scan_complete_event sap_acs_scan_comp; + tSirBssDescription *bss_desc; + } sapevt; +} tSap_Event, *tpSap_Event; + +typedef struct sap_SSID { + uint8_t length; + uint8_t ssId[MAX_SSID_LEN]; +} qdf_packed tSap_SSID_t; + +typedef struct sap_SSIDInfo { + tSap_SSID_t ssid; /* SSID of the AP */ + /* SSID should/shouldn't be bcast in probe RSP & beacon */ + uint8_t ssidHidden; +} qdf_packed tSap_SSIDInfo_t; + +struct sap_acs_cfg { + /* ACS Algo Input */ + uint8_t acs_mode; + uint32_t hw_mode; + uint8_t start_ch; + uint8_t end_ch; + uint8_t *ch_list; + uint8_t ch_list_count; +#ifdef FEATURE_WLAN_AP_AP_ACS_OPTIMIZE + uint8_t skip_scan_status; + uint8_t skip_scan_range1_stch; + uint8_t skip_scan_range1_endch; + uint8_t skip_scan_range2_stch; + uint8_t skip_scan_range2_endch; +#endif + + uint16_t ch_width; + uint8_t pcl_channels[QDF_MAX_NUM_CHAN]; + uint32_t pcl_ch_count; + /* ACS Algo Output */ + uint8_t pri_ch; + uint8_t ht_sec_ch; + uint8_t vht_seg0_center_ch; + uint8_t vht_seg1_center_ch; +}; + +/* + * enum vendor_ie_access_policy- access policy + * @ACCESS_POLICY_NONE: access policy attribute is not valid + * @ACCESS_POLICY_RESPOND_IF_IE_IS_PRESENT: respond to probe req/assoc req + * only if ie is present + * @ACCESS_POLICY_DONOT_RESPOND_IF_IE_IS_PRESENT: do not respond to probe req/ + * assoc req if ie is present +*/ +enum vendor_ie_access_policy { + ACCESS_POLICY_NONE, + ACCESS_POLICY_RESPOND_IF_IE_IS_PRESENT, + ACCESS_POLICY_DONOT_RESPOND_IF_IE_IS_PRESENT, +}; + +/* + * enum sap_acs_dfs_mode- state of DFS mode + * @ACS_DFS_MODE_NONE: DFS mode attribute is not valid + * @ACS_DFS_MODE_ENABLE: DFS mode is enabled + * @ACS_DFS_MODE_DISABLE: DFS mode is disabled + * @ACS_DFS_MODE_DEPRIORITIZE: Deprioritize DFS channels in scanning + */ +enum sap_acs_dfs_mode { + ACS_DFS_MODE_NONE, + ACS_DFS_MODE_ENABLE, + ACS_DFS_MODE_DISABLE, + ACS_DFS_MODE_DEPRIORITIZE +}; + +typedef struct sap_Config { + tSap_SSIDInfo_t SSIDinfo; + eCsrPhyMode SapHw_mode; /* Wireless Mode */ + eSapMacAddrACL SapMacaddr_acl; + struct qdf_mac_addr accept_mac[MAX_ACL_MAC_ADDRESS]; /* MAC filtering */ + bool ieee80211d; /* Specify if 11D is enabled or disabled */ + bool protEnabled; /* Specify if protection is enabled or disabled */ + /* Specify if OBSS protection is enabled or disabled */ + bool obssProtEnabled; + struct qdf_mac_addr deny_mac[MAX_ACL_MAC_ADDRESS]; /* MAC filtering */ + struct qdf_mac_addr self_macaddr; /* self macaddress or BSSID */ + uint8_t channel; /* Operation channel */ + uint8_t sec_ch; + struct ch_params_s ch_params; + uint32_t ch_width_orig; + uint8_t max_num_sta; /* maximum number of STAs in station table */ + uint8_t dtim_period; /* dtim interval */ + uint8_t num_accept_mac; + uint8_t num_deny_mac; + /* Max ie length 255 * 2(WPA+RSN) + 2 bytes(vendor specific ID) * 2 */ + uint8_t RSNWPAReqIE[(SIR_MAC_MAX_IE_LENGTH * 2) + 4]; + /* it is ignored if [0] is 0. */ + uint8_t countryCode[WNI_CFG_COUNTRY_CODE_LEN]; + uint8_t RSNAuthType; + uint8_t RSNEncryptType; + uint8_t mcRSNEncryptType; + eSapAuthType authType; + bool privacy; + bool UapsdEnable; + bool fwdWPSPBCProbeReq; + /* 0 - disabled, 1 - not configured , 2 - configured */ + uint8_t wps_state; + uint16_t ht_capab; + uint16_t RSNWPAReqIELength; /* The byte count in the pWPAReqIE */ + uint32_t beacon_int; /* Beacon Interval */ + uint32_t ap_table_max_size; + uint32_t ap_table_expiration_time; + uint32_t ht_op_mode_fixed; + enum tQDF_ADAPTER_MODE persona; /* Tells us which persona, GO or AP */ + uint8_t disableDFSChSwitch; + bool enOverLapCh; +#ifdef WLAN_FEATURE_11W + bool mfpRequired; + bool mfpCapable; +#endif +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH + uint8_t cc_switch_mode; +#endif + struct sap_acs_cfg acs_cfg; + uint16_t probeRespIEsBufferLen; + /* buffer for addn ies comes from hostapd */ + void *pProbeRespIEsBuffer; + uint16_t assocRespIEsLen; + /* buffer for addn ies comes from hostapd */ + void *pAssocRespIEsBuffer; + uint16_t probeRespBcnIEsLen; + /* buffer for addn ies comes from hostapd */ + void *pProbeRespBcnIEsBuffer; + uint8_t sap_dot11mc; /* Specify if 11MC is enabled or disabled*/ + uint8_t beacon_tx_rate; + uint8_t *vendor_ie; + enum vendor_ie_access_policy vendor_ie_access_policy; + uint16_t sta_inactivity_timeout; + uint16_t tx_pkt_fail_cnt_threshold; + uint8_t short_retry_limit; + uint8_t long_retry_limit; + uint8_t ampdu_size; + tSirMacRateSet supported_rates; + tSirMacRateSet extended_rates; + enum sap_acs_dfs_mode acs_dfs_mode; +} tsap_Config_t; + +#ifdef FEATURE_WLAN_AP_AP_ACS_OPTIMIZE +typedef enum { + eSAP_DO_NEW_ACS_SCAN, + eSAP_DO_PAR_ACS_SCAN, + eSAP_SKIP_ACS_SCAN +} tSap_skip_acs_scan; +#endif + +typedef enum { + eSAP_WPS_PROBE_RSP_IE, + eSAP_WPS_BEACON_IE, + eSAP_WPS_ASSOC_RSP_IE +} eSapWPSIE_CODE; + +typedef struct sSapName { + uint8_t num_name; + uint8_t name[MAX_NAME_SIZE]; +} tSapName; + +typedef struct sSapText { + uint8_t num_text; + uint8_t text[MAX_TEXT_SIZE]; +} tSapText; + +typedef enum { + eSAP_DFS_DO_NOT_SKIP_CAC, + eSAP_DFS_SKIP_CAC +} eSapDfsCACState_t; + +typedef enum { + eSAP_DFS_CHANNEL_USABLE, + eSAP_DFS_CHANNEL_AVAILABLE, + eSAP_DFS_CHANNEL_UNAVAILABLE +} eSapDfsChanStatus_t; + +typedef struct sSapDfsNolInfo { + uint8_t dfs_channel_number; + eSapDfsChanStatus_t radar_status_flag; + uint64_t radar_found_timestamp; +} tSapDfsNolInfo; + +typedef struct sSapDfsInfo { + qdf_mc_timer_t sap_dfs_cac_timer; + uint8_t sap_radar_found_status; + /* + * New channel to move to when a Radar is + * detected on current Channel + */ + uint8_t target_channel; + uint8_t last_radar_found_channel; + uint8_t ignore_cac; + eSapDfsCACState_t cac_state; + uint8_t user_provided_target_channel; + + /* + * Requests for Channel Switch Announcement IE + * generation and transmission + */ + uint8_t csaIERequired; + uint8_t numCurrentRegDomainDfsChannels; + tSapDfsNolInfo sapDfsChannelNolList[NUM_5GHZ_CHANNELS]; + uint8_t is_dfs_cac_timer_running; + /* + * New channel width and new channel bonding mode + * will only be updated via channel fallback mechanism + */ + enum phy_ch_width orig_chanWidth; + enum phy_ch_width new_chanWidth; + struct ch_params_s new_ch_params; + + /* + * INI param to enable/disable SAP W53 + * channel operation. + */ + uint8_t is_dfs_w53_disabled; + + /* + * sap_operating_channel_location holds SAP indoor, + * outdoor location information. Currently, if this + * param is set this Indoor/outdoor channel interop + * restriction will only be implemented for JAPAN + * regulatory domain. + * + * 0 - Indicates that location unknown + * (or) SAP Indoor/outdoor interop is allowed + * + * 1 - Indicates device is operating on Indoor channels + * and SAP cannot pick next random channel from outdoor + * list of channels when a radar is found on current operating + * DFS channel. + * + * 2 - Indicates device is operating on Outdoor Channels + * and SAP cannot pick next random channel from indoor + * list of channels when a radar is found on current + * operating DFS channel. + */ + uint8_t sap_operating_chan_preferred_location; + + /* + * Flag to indicate if DFS test mode is enabled and + * channel switch is disabled. + */ + uint8_t disable_dfs_ch_switch; + uint16_t tx_leakage_threshold; +} tSapDfsInfo; + +typedef struct tagSapCtxList { + uint8_t sessionID; + void *pSapContext; + enum tQDF_ADAPTER_MODE sapPersona; +} tSapCtxList, tpSapCtxList; + +typedef struct tagSapStruct { + /* Information Required for SAP DFS Master mode */ + tSapDfsInfo SapDfsInfo; + tSapCtxList sapCtxList[SAP_MAX_NUM_SESSION]; +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE + bool sap_channel_avoidance; +#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ + bool enable_dfs_phy_error_logs; +} tSapStruct, *tpSapStruct; + +#define WPS_PROBRSP_VER_PRESENT 0x00000001 +#define WPS_PROBRSP_STATE_PRESENT 0x00000002 +#define WPS_PROBRSP_APSETUPLOCK_PRESENT 0x00000004 +#define WPS_PROBRSP_SELECTEDREGISTRA_PRESENT 0x00000008 +#define WPS_PROBRSP_DEVICEPASSWORDID_PRESENT 0x00000010 +#define WPS_PROBRSP_SELECTEDREGISTRACFGMETHOD_PRESENT 0x00000020 +#define WPS_PROBRSP_RESPONSETYPE_PRESENT 0x00000040 +#define WPS_PROBRSP_UUIDE_PRESENT 0x00000080 +#define WPS_PROBRSP_MANUFACTURE_PRESENT 0x00000100 +#define WPS_PROBRSP_MODELNAME_PRESENT 0x00000200 +#define WPS_PROBRSP_MODELNUMBER_PRESENT 0x00000400 +#define WPS_PROBRSP_SERIALNUMBER_PRESENT 0x00000800 +#define WPS_PROBRSP_PRIMARYDEVICETYPE_PRESENT 0x00001000 +#define WPS_PROBRSP_DEVICENAME_PRESENT 0x00002000 +#define WPS_PROBRSP_CONFIGMETHODS_PRESENT 0x00004000 +#define WPS_PROBRSP_RF_BANDS_PRESENT 0x00008000 + +typedef struct sap_WPSProbeRspIE_s { + uint32_t FieldPresent; + uint32_t Version; /* Version. 0x10 = version 1.0, 0x11 = etc. */ + uint32_t wpsState; /* 1 = unconfigured, 2 = configured. */ + bool APSetupLocked; /* Must be included if value is true */ + /* indicates if user has recently activated a reg to add an Enrollee. */ + bool SelectedRegistra; + uint16_t DevicePasswordID; /* Device Password ID */ + /* Selected Registrar config method */ + uint16_t SelectedRegistraCfgMethod; + uint8_t ResponseType; /* Response type */ + uint8_t UUID_E[16]; /* Unique identifier of the AP. */ + tSapName Manufacture; + tSapText ModelName; + tSapText ModelNumber; + tSapText SerialNumber; + /* Device Category ID: 1Computer, 2Input Device, ... */ + uint32_t PrimaryDeviceCategory; + /* Vendor specific OUI for Device Sub Category */ + uint8_t PrimaryDeviceOUI[4]; + /* + * Device Sub Category ID: 1-PC, + * 2-Server if Device Category is computer + */ + uint32_t DeviceSubCategory; + tSapText DeviceName; + uint16_t ConfigMethod; /* Configuaration method */ + uint8_t RFBand; /* RF bands available on the AP */ +} tSap_WPSProbeRspIE; + +#define WPS_BEACON_VER_PRESENT 0x00000001 +#define WPS_BEACON_STATE_PRESENT 0x00000002 +#define WPS_BEACON_APSETUPLOCK_PRESENT 0x00000004 +#define WPS_BEACON_SELECTEDREGISTRA_PRESENT 0x00000008 +#define WPS_BEACON_DEVICEPASSWORDID_PRESENT 0x00000010 +#define WPS_BEACON_SELECTEDREGISTRACFGMETHOD_PRESENT 0x00000020 +#define WPS_BEACON_UUIDE_PRESENT 0x00000080 +#define WPS_BEACON_RF_BANDS_PRESENT 0x00000100 + +typedef struct sap_WPSBeaconIE_s { + uint32_t FieldPresent; + uint32_t Version; /* Version. 0x10 = version 1.0, 0x11 = etc. */ + uint32_t wpsState; /* 1 = unconfigured, 2 = configured. */ + bool APSetupLocked; /* Must be included if value is true */ + /* indicates if user has recently activated a reg to add an Enrollee. */ + bool SelectedRegistra; + uint16_t DevicePasswordID; /* Device Password ID */ + uint16_t SelectedRegistraCfgMethod; /* Selected reg config method */ + uint8_t UUID_E[16]; /* Unique identifier of the AP. */ + uint8_t RFBand; /* RF bands available on the AP */ +} tSap_WPSBeaconIE; + +#define WPS_ASSOCRSP_VER_PRESENT 0x00000001 +#define WPS_ASSOCRSP_RESPONSETYPE_PRESENT 0x00000002 + +typedef struct sap_WPSAssocRspIE_s { + uint32_t FieldPresent; + uint32_t Version; + uint8_t ResposeType; +} tSap_WPSAssocRspIE; + +typedef struct sap_WPSIE_s { + eSapWPSIE_CODE sapWPSIECode; + union { + tSap_WPSProbeRspIE sapWPSProbeRspIE; /* WPS Set Probe Resp IE */ + tSap_WPSBeaconIE sapWPSBeaconIE; /* WPS Set Beacon IE */ + tSap_WPSAssocRspIE sapWPSAssocRspIE; /* WPS Set Assoc Resp IE */ + } sapwpsie; +} tSap_WPSIE, *tpSap_WPSIE; + +#ifdef WLANTL_DEBUG +#define MAX_RATE_INDEX 136 +#define MAX_NUM_RSSI 100 +#define MAX_RSSI_INTERVAL 5 +#endif + +typedef struct sap_SoftapStats_s { + uint32_t txUCFcnt; + uint32_t txMCFcnt; + uint32_t txBCFcnt; + uint32_t txUCBcnt; + uint32_t txMCBcnt; + uint32_t txBCBcnt; + uint32_t rxUCFcnt; + uint32_t rxMCFcnt; + uint32_t rxBCFcnt; + uint32_t rxUCBcnt; + uint32_t rxMCBcnt; + uint32_t rxBCBcnt; + uint32_t rxBcnt; + uint32_t rxBcntCRCok; + uint32_t rxRate; +#ifdef WLANTL_DEBUG + uint32_t pktCounterRateIdx[MAX_RATE_INDEX]; + uint32_t pktCounterRssi[MAX_NUM_RSSI]; +#endif +} tSap_SoftapStats, *tpSap_SoftapStats; + +#ifdef FEATURE_WLAN_CH_AVOID +/* Store channel safety information */ +typedef struct { + uint16_t channelNumber; + bool isSafe; +} sapSafeChannelType; +#endif /* FEATURE_WLAN_CH_AVOID */ +void sap_cleanup_channel_list(void *sapContext); +void sapCleanupAllChannelList(void); + +/** + * sap_is_auto_channel_select() - is channel AUTO_CHANNEL_SELECT + * @pvos_gctx: Pointer to vos global context structure + * + * Return: true on AUTO_CHANNEL_SELECT, false otherwise + */ +bool sap_is_auto_channel_select(void *pvos_gctx); + +QDF_STATUS wlansap_set_wps_ie(void *p_cds_gctx, tSap_WPSIE *pWPSIe); +QDF_STATUS wlansap_update_wps_ie(void *p_cds_gctx); +QDF_STATUS wlansap_stop_Wps(void *p_cds_gctx); +QDF_STATUS wlansap_get_wps_state(void *p_cds_gctx, bool *pbWPSState); +void *wlansap_open(void *p_cds_gctx); +QDF_STATUS wlansap_global_init(void); +QDF_STATUS wlansap_global_deinit(void); +QDF_STATUS wlansap_stop(void *p_cds_gctx); +QDF_STATUS wlansap_close(void *p_cds_gctx); +typedef QDF_STATUS (*tpWLAN_SAPEventCB)(tpSap_Event pSapEvent, + void *pUsrContext); +QDF_STATUS wlansap_start(void *p_cds_gctx, tpWLAN_SAPEventCB pSapEventCallback, + enum tQDF_ADAPTER_MODE mode, uint8_t *addr, + uint32_t *session_id, void *pUsrContext); +uint8_t wlansap_get_state(void *p_cds_gctx); + +QDF_STATUS wlansap_start_bss(void *p_cds_gctx, + tpWLAN_SAPEventCB pSapEventCallback, + tsap_Config_t *pConfig, void *pUsrContext); +QDF_STATUS wlan_sap_set_pre_cac_status(void *ctx, bool status, + tHalHandle handle); +QDF_STATUS wlan_sap_set_chan_before_pre_cac(void *ctx, + uint8_t chan_before_pre_cac); +QDF_STATUS wlan_sap_set_pre_cac_complete_status(void *ctx, bool status); +bool wlan_sap_is_pre_cac_active(tHalHandle handle); +QDF_STATUS wlan_sap_get_pre_cac_vdev_id(tHalHandle handle, uint8_t *vdev_id); +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH +uint16_t wlansap_check_cc_intf(void *Ctx); +#endif +QDF_STATUS wlansap_set_mac_acl(void *p_cds_gctx, tsap_Config_t *pConfig); +QDF_STATUS wlansap_stop_bss(void *p_cds_gctx); +QDF_STATUS wlansap_disassoc_sta(void *p_cds_gctx, + struct tagCsrDelStaParams *p_del_sta_params); +QDF_STATUS wlansap_deauth_sta(void *p_cds_gctx, + struct tagCsrDelStaParams *pDelStaParams); +QDF_STATUS wlansap_set_channel_change_with_csa(void *p_cds_gctx, + uint32_t targetChannel, enum phy_ch_width target_bw); +QDF_STATUS wlansap_set_key_sta(void *p_cds_gctx, + tCsrRoamSetKey *pSetKeyInfo); +QDF_STATUS wlansap_get_assoc_stations(void *p_cds_gctx, + QDF_MODULE_ID module, tpSap_AssocMacAddr pAssocStas); +QDF_STATUS wlansap_remove_wps_session_overlap(void *p_cds_gctx, + struct qdf_mac_addr pRemoveMac); +QDF_STATUS wlansap_get_wps_session_overlap(void *p_cds_gctx); +QDF_STATUS wlansap_set_counter_measure(void *p_cds_gctx, bool bEnable); +QDF_STATUS wlan_sap_getstation_ie_information(void *p_cds_gctx, + uint32_t *pLen, uint8_t *pBuf); +QDF_STATUS wlansap_clear_acl(void *p_cds_gctx); +QDF_STATUS wlansap_get_acl_accept_list(void *p_cds_gctx, + struct qdf_mac_addr *pAcceptList, uint8_t *nAcceptList); +QDF_STATUS wlansap_get_acl_deny_list(void *pCtx, + struct qdf_mac_addr *pDenyList, uint8_t *nDenyList); +QDF_STATUS wlansap_set_mode(void *p_cds_gctx, uint32_t mode); +QDF_STATUS wlansap_get_acl_mode(void *p_cds_gctx, eSapMacAddrACL *mode); +QDF_STATUS wlansap_modify_acl(void *p_cds_gctx, + uint8_t *pPeerStaMac, eSapACLType listType, eSapACLCmdType cmd); +QDF_STATUS wlansap_set_wparsn_ies + (void *p_cds_gctx, uint8_t *pWPARSNIEs, uint32_t WPARSNIEsLen); +QDF_STATUS wlansap_send_action + (void *p_cds_gctx, + const uint8_t *pBuf, uint32_t len, uint16_t wait, uint16_t channel_freq); +QDF_STATUS wlansap_remain_on_channel + (void *p_cds_gctx, + uint8_t channel, + uint32_t duration, remainOnChanCallback callback, void *pContext, + uint32_t *scan_id); +QDF_STATUS wlansap_cancel_remain_on_channel(void *p_cds_gctx, + uint32_t scan_id); +QDF_STATUS wlansap_register_mgmt_frame + (void *p_cds_gctx, + uint16_t frameType, uint8_t *matchData, uint16_t matchLen); +QDF_STATUS wlansap_de_register_mgmt_frame + (void *p_cds_gctx, + uint16_t frameType, uint8_t *matchData, uint16_t matchLen); +QDF_STATUS wlansap_channel_change_request(void *p_cds_gctx, + uint8_t tArgetChannel); +QDF_STATUS wlansap_start_beacon_req(void *pSapCtx); +QDF_STATUS wlansap_dfs_send_csa_ie_request(void *pSapCtx); +QDF_STATUS wlansap_get_dfs_ignore_cac(tHalHandle hHal, uint8_t *pIgnore_cac); +QDF_STATUS wlansap_set_dfs_ignore_cac(tHalHandle hHal, uint8_t ignore_cac); +QDF_STATUS wlansap_set_dfs_restrict_japan_w53(tHalHandle hHal, + uint8_t disable_Dfs_JapanW3); + +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE +QDF_STATUS +wlan_sap_set_channel_avoidance(tHalHandle hal, bool sap_channel_avoidance); +#endif + +QDF_STATUS wlansap_set_dfs_preferred_channel_location(tHalHandle hHal, + uint8_t dfs_Preferred_Channels_location); +QDF_STATUS wlansap_set_dfs_target_chnl(tHalHandle hHal, + uint8_t target_channel); +uint32_t wlan_sap_get_vht_ch_width(void *ctx); +void wlan_sap_set_vht_ch_width(void *ctx, uint32_t vht_channel_width); +QDF_STATUS wlansap_update_sap_config_add_ie(tsap_Config_t *pConfig, + const uint8_t * + pAdditionIEBuffer, + uint16_t additionIELength, + eUpdateIEsType updateType); +QDF_STATUS wlansap_reset_sap_config_add_ie(tsap_Config_t *pConfig, + eUpdateIEsType updateType); +void wlansap_extend_to_acs_range(uint8_t *startChannelNum, + uint8_t *endChannelNum, + uint8_t *bandStartChannel, + uint8_t *bandEndChannel); +QDF_STATUS wlansap_get_dfs_nol(void *pSapCtx, uint8_t *nol, uint32_t *nol_len); +QDF_STATUS wlansap_set_dfs_nol(void *pSapCtx, eSapDfsNolType conf); +void wlansap_populate_del_sta_params(const uint8_t *mac, + uint16_t reason_code, + uint8_t subtype, + struct tagCsrDelStaParams *pDelStaParams); +QDF_STATUS wlansap_acs_chselect(void *pvos_gctx, + tpWLAN_SAPEventCB pacs_event_callback, + tsap_Config_t *pconfig, + void *pusr_context); + +uint32_t wlansap_get_chan_width(void *cds_ctx); + +QDF_STATUS wlansap_set_tx_leakage_threshold(tHalHandle hal, + uint16_t tx_leakage_threshold); + +QDF_STATUS wlansap_set_invalid_session(void *cds_ctx); +QDF_STATUS sap_roam_session_close_callback(void *pContext); + +#ifdef __cplusplus +} +#endif +#endif /* #ifndef WLAN_QCT_WLANSAP_H */ diff --git a/drivers/staging/qcacld-3.0/core/sap/src/sap_api_link_cntl.c b/drivers/staging/qcacld-3.0/core/sap/src/sap_api_link_cntl.c new file mode 100644 index 0000000000000000000000000000000000000000..16a134d5bcd22d236736d36ce7b7c1c113c7574e --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/sap/src/sap_api_link_cntl.c @@ -0,0 +1,1258 @@ +/* + * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/*=========================================================================== + + s a p A p i L i n k C n t l . C + + OVERVIEW: + + This software unit holds the implementation of the WLAN SAP modules + Link Control functions. + + The functions externalized by this module are to be called ONLY by other + WLAN modules (HDD) + + DEPENDENCIES: + + Are listed for each API below. + ===========================================================================*/ + +/*---------------------------------------------------------------------------- + * Include Files + * -------------------------------------------------------------------------*/ +#include "qdf_trace.h" +/* Pick up the CSR callback definition */ +#include "csr_api.h" +#include "ani_global.h" +#include "csr_inside_api.h" +#include "sme_api.h" +/* SAP Internal API header file */ +#include "sap_internal.h" +#include "cds_concurrency.h" +#include "wma.h" + +/*---------------------------------------------------------------------------- + * Preprocessor Definitions and Constants + * -------------------------------------------------------------------------*/ +#define SAP_DEBUG + +/*---------------------------------------------------------------------------- + * Type Declarations + * -------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------- + * Global Data Definitions + * -------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------- + * Static Variable Definitions + * -------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------- + * Static Function Declarations and Definitions + * -------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------- + * Externalized Function Definitions + * -------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------- + * Function Declarations and Documentation + * -------------------------------------------------------------------------*/ + +/* + * wlansap_scan_callback() - Callback for Scan (scan results) Events + * + * @hal_handle : tHalHandle passed in with the scan request + * @ctx : The second context pass in for the caller (sapContext) + * @scanID : scanID got after the scan + * + * Callback for Scan (scan results) Events + * + * Return: Status + */ +QDF_STATUS wlansap_scan_callback(tHalHandle hal_handle, + void *ctx, /* Opaque SAP handle */ + uint8_t session_id, + uint32_t scan_id, eCsrScanStatus scan_status) { + tScanResultHandle result = NULL; + QDF_STATUS get_result_status = QDF_STATUS_E_FAILURE; + ptSapContext sap_ctx = (ptSapContext) ctx; + tWLAN_SAPEvent sapEvent; /* State machine event */ + uint8_t operChannel = 0; + QDF_STATUS sap_sm_status; + uint32_t event; + + + if (NULL == hal_handle) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "In %s invalid hHal", __func__); + return QDF_STATUS_E_FAILURE; + } + if (sap_ctx->sapsMachine == eSAP_DISCONNECTED) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_WARN, + "In %s BSS already stopped", __func__); + return QDF_STATUS_E_FAILURE; + } + + switch (scan_status) { + case eCSR_SCAN_SUCCESS: + /* sapScanCompleteCallback with eCSR_SCAN_SUCCESS */ + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + "In %s, CSR scanStatus = %s (%d)", __func__, + "eCSR_SCAN_SUCCESS", scan_status); + + /** + * Get scan results, Run channel selection algorithm, + * select channel and keep in sap_ctx->Channel + */ + get_result_status = + sme_scan_get_result(hal_handle, sap_ctx->sessionId, NULL, + &result); + + event = eSAP_MAC_SCAN_COMPLETE; + + if ((get_result_status != QDF_STATUS_SUCCESS) + && (get_result_status != QDF_STATUS_E_NULL_VALUE)) { + /* No scan results */ + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "In %s, Get scan result failed! ret = %d", + __func__, get_result_status); + break; + } +#ifdef FEATURE_WLAN_AP_AP_ACS_OPTIMIZE + if (scan_id != 0) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: Sending ACS Scan skip event", __func__); + sap_signal_hdd_event(sap_ctx, NULL, + eSAP_ACS_SCAN_SUCCESS_EVENT, + (void *) eSAP_STATUS_SUCCESS); + } else + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: ACS scan id: %d (skipped ACS SCAN)", + __func__, scan_id); +#endif + operChannel = sap_select_channel(hal_handle, sap_ctx, result); + if (!operChannel) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + "No channel was selected from preferred channel for Operating channel"); + + operChannel = sap_ctx->acs_cfg->start_ch; + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + "Selecting operating channel as starting channel from preferred channel list: %d", + operChannel); + } + sme_scan_result_purge(hal_handle, result); + break; + + default: + event = eSAP_CHANNEL_SELECTION_FAILED; + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + "In %s, CSR scanStatus = %s (%d)", __func__, + "eCSR_SCAN_ABORT/FAILURE", scan_status); + } + + if (operChannel == SAP_CHANNEL_NOT_SELECTED) +#ifdef SOFTAP_CHANNEL_RANGE + { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: No suitable channel selected due to DFS, LTE" + "COEX and concurrent mode restrictions", __func__); + + sap_ctx->sapsMachine = eSAP_CH_SELECT; + event = eSAP_CHANNEL_SELECTION_FAILED; + } +#else + sap_ctx->channel = SAP_DEFAULT_24GHZ_CHANNEL; +#endif + else { + sap_ctx->channel = operChannel; + } + + sap_ctx->ch_params.ch_width = sap_ctx->acs_cfg->ch_width; + cds_set_channel_params(sap_ctx->channel, + sap_ctx->secondary_ch, + &sap_ctx->ch_params); +#ifdef SOFTAP_CHANNEL_RANGE + if (sap_ctx->channelList != NULL) { + /* Always free up the memory for channel selection whatever + * the result */ + qdf_mem_free(sap_ctx->channelList); + sap_ctx->channelList = NULL; + sap_ctx->num_of_channel = 0; + } +#endif + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + "In %s, Channel selected = %d", __func__, + sap_ctx->channel); + + /* Fill in the event structure */ + sapEvent.event = event; + /* pCsrRoamInfo; */ + sapEvent.params = 0; + /* roamstatus */ + sapEvent.u1 = scan_status; + /* roamResult */ + sapEvent.u2 = 0; + + /* Handle event */ + sap_sm_status = sap_fsm(sap_ctx, &sapEvent); + + return sap_sm_status; +} /* wlansap_scan_callback */ + + +/** + * sap_config_acs_result : Generate ACS result params based on ch constraints + * @sap_ctx: pointer to SAP context data struct + * @hal: HAL Handle pointer + * + * This function calculates the ACS result params: ht sec channel, vht channel + * information and channel bonding based on selected ACS channel. + * + * Return: None + */ + +void sap_config_acs_result(tHalHandle hal, ptSapContext sap_ctx, + uint32_t sec_ch) +{ + uint32_t channel = sap_ctx->acs_cfg->pri_ch; + struct ch_params_s ch_params = {0}; + + ch_params.ch_width = sap_ctx->acs_cfg->ch_width; + cds_set_channel_params(channel, sec_ch, &ch_params); + sap_ctx->acs_cfg->ch_width = ch_params.ch_width; + if (sap_ctx->acs_cfg->ch_width > CH_WIDTH_40MHZ) + sap_ctx->acs_cfg->vht_seg0_center_ch = + ch_params.center_freq_seg0; + else + sap_ctx->acs_cfg->vht_seg0_center_ch = 0; + + if (sap_ctx->acs_cfg->ch_width == CH_WIDTH_80P80MHZ) + sap_ctx->acs_cfg->vht_seg1_center_ch = + ch_params.center_freq_seg1; + else + sap_ctx->acs_cfg->vht_seg1_center_ch = 0; + + if (ch_params.sec_ch_offset == PHY_DOUBLE_CHANNEL_HIGH_PRIMARY) + sap_ctx->acs_cfg->ht_sec_ch = sap_ctx->acs_cfg->pri_ch - 4; + else if (ch_params.sec_ch_offset == PHY_DOUBLE_CHANNEL_LOW_PRIMARY) + sap_ctx->acs_cfg->ht_sec_ch = sap_ctx->acs_cfg->pri_ch + 4; + else + sap_ctx->acs_cfg->ht_sec_ch = 0; +} + +/** + * sap_hdd_signal_event_handler() - routine to inform hostapd via callback + * + * ctx: pointer to sap context which was passed to callback + * + * this routine will be registered as callback to sme_close_session, so upon + * closure of sap session it notifies the hostapd + * + * Return: QDF_STATUS + */ +static QDF_STATUS sap_hdd_signal_event_handler(void *ctx) +{ + ptSapContext sap_ctx = (struct sSapContext *)ctx; + QDF_STATUS status; + if (NULL == sap_ctx) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("sap context is not valid")); + return QDF_STATUS_E_FAILURE; + } + status = sap_signal_hdd_event(sap_ctx, NULL, + sap_ctx->sap_state, + (void *) sap_ctx->sap_status); + return status; +} + +/** + * + * wlansap_pre_start_bss_acs_scan_callback() - callback for scan results + * + * hal_handle: the hal_handle passed in with the scan request + * pcontext: the second context pass in for the caller, opaque sap Handle. + * scanid: scan id passed + * sessionid: session identifier + * status: status of scan -success, failure or abort + * + * Api for scan callback. This function is invoked as a result of scan + * completion and reports the scan results. + * + * Return: The QDF_STATUS code associated with performing the operation + */ +QDF_STATUS +wlansap_pre_start_bss_acs_scan_callback(tHalHandle hal_handle, void *pcontext, + uint8_t sessionid, uint32_t scanid, + eCsrScanStatus scan_status) +{ + tScanResultHandle presult = NULL; + QDF_STATUS scan_get_result_status = QDF_STATUS_E_FAILURE; + ptSapContext sap_ctx = (ptSapContext)pcontext; + uint8_t oper_channel = 0; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + + if (eCSR_SCAN_SUCCESS != scan_status) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("CSR scan_status = eCSR_SCAN_ABORT/FAILURE (%d), choose default channel"), + scan_status); + sap_ctx->channel = + sap_select_default_oper_chan(hal_handle, + sap_ctx->acs_cfg->hw_mode); + sap_ctx->sap_state = eSAP_ACS_CHANNEL_SELECTED; + sap_ctx->sap_status = eSAP_STATUS_SUCCESS; + goto close_session; + } + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + FL("CSR scan_status = eCSR_SCAN_SUCCESS (%d)"), scan_status); + /* + * Now do + * 1. Get scan results + * 2. Run channel selection algorithm + * select channel and store in pSapContext->Channel + */ + scan_get_result_status = sme_scan_get_result(hal_handle, + sap_ctx->sessionId, + NULL, &presult); + if ((scan_get_result_status != QDF_STATUS_SUCCESS) && + (scan_get_result_status != QDF_STATUS_E_NULL_VALUE)) { + /* + * No scan results So, set the operation channel not selected + * to allow the default channel to be set when reporting to HDD + */ + oper_channel = SAP_CHANNEL_NOT_SELECTED; + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("Get scan result failed! ret = %d"), + scan_get_result_status); + } else { +#ifdef FEATURE_WLAN_AP_AP_ACS_OPTIMIZE + if (scanid != 0) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + FL("Sending ACS Scan skip event")); + sap_signal_hdd_event(sap_ctx, NULL, + eSAP_ACS_SCAN_SUCCESS_EVENT, + (void *) eSAP_STATUS_SUCCESS); + } else { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + FL("ACS scanid: %d (skipped ACS SCAN)"), + scanid); + } +#endif + oper_channel = sap_select_channel(hal_handle, sap_ctx, presult); + if (!oper_channel) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + "No channel was selected from preferred channel for Operating channel"); + + oper_channel = sap_ctx->acs_cfg->start_ch; + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + "Selecting operating channel as starting channel from preferred channel list: %d", + oper_channel); + } + sme_scan_result_purge(hal_handle, presult); + } + + if (oper_channel == SAP_CHANNEL_NOT_SELECTED) { +#ifdef SOFTAP_CHANNEL_RANGE + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO, + FL("No suitable channel selected")); + + sap_ctx->sap_state = eSAP_ACS_CHANNEL_SELECTED; + sap_ctx->sap_status = eSAP_STATUS_FAILURE; + goto close_session; + } else { +#else + sap_ctx->channel = + sap_select_default_oper_chan(hal_handle, + sap_ctx->acs_cfg->hw_mode); + } else { +#endif + /* Valid Channel Found from scan results. */ + sap_ctx->acs_cfg->pri_ch = oper_channel; + sap_ctx->channel = oper_channel; + } + sap_config_acs_result(hal_handle, sap_ctx, + sap_ctx->acs_cfg->ht_sec_ch); + +#ifdef SOFTAP_CHANNEL_RANGE + if (sap_ctx->channelList != NULL) { + /* + * Always free up the memory for + * channel selection whatever + * the result + */ + qdf_mem_free(sap_ctx->channelList); + sap_ctx->channelList = NULL; + sap_ctx->num_of_channel = 0; + } +#endif + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + FL("Channel selected = %d"), sap_ctx->channel); + sap_ctx->sap_state = eSAP_ACS_CHANNEL_SELECTED; + sap_ctx->sap_status = eSAP_STATUS_SUCCESS; +close_session: + sap_hdd_signal_event_handler(sap_ctx); + return status; +} + +/** + * wlansap_roam_process_ch_change_success() - handles the case for + * eCSR_ROAM_RESULT_CHANNEL_CHANGE_SUCCESS in function wlansap_roam_callback() + * + * @mac_ctx: mac global context + * @sap_ctx: sap context + * @csr_roam_info: raom info struct + * @ret_status: update return status + * + * Return: void + */ +static void +wlansap_roam_process_ch_change_success(tpAniSirGlobal mac_ctx, + ptSapContext sap_ctx, + tCsrRoamInfo *csr_roam_info, + QDF_STATUS *ret_status) +{ + tWLAN_SAPEvent sap_event; + QDF_STATUS qdf_status; + bool is_ch_dfs = false; + /* + * Channel change is successful. If the new channel is a DFS channel, + * then we will to perform channel availability check for 60 seconds + */ + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_MED, + FL("sapdfs: changing target channel to [%d]"), + mac_ctx->sap.SapDfsInfo.target_channel); + sap_ctx->channel = mac_ctx->sap.SapDfsInfo.target_channel; + /* Identify if this is channel change in radar detected state */ + if (eSAP_DISCONNECTING != sap_ctx->sapsMachine) + return; + + if (sap_ctx->ch_params.ch_width == CH_WIDTH_160MHZ) { + is_ch_dfs = true; + } else if (sap_ctx->ch_params.ch_width == CH_WIDTH_80P80MHZ) { + if (cds_get_channel_state(sap_ctx->channel) == + CHANNEL_STATE_DFS || + cds_get_channel_state(sap_ctx->ch_params.center_freq_seg1 - + SIR_80MHZ_START_CENTER_CH_DIFF) == + CHANNEL_STATE_DFS) + is_ch_dfs = true; + } else { + if (cds_get_channel_state(sap_ctx->channel) == + CHANNEL_STATE_DFS) + is_ch_dfs = true; + } + + /* check if currently selected channel is a DFS channel */ + if (is_ch_dfs && sap_ctx->pre_cac_complete) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_MED, FL( + "sapdfs: eSAP_DISCONNECTING => eSAP_STARTING, on pre cac")); + /* Start beaconing on the new pre cac channel */ + wlansap_start_beacon_req(sap_ctx); + sap_ctx->sapsMachine = eSAP_STARTING; + mac_ctx->sap.SapDfsInfo.sap_radar_found_status = false; + sap_event.event = eSAP_MAC_START_BSS_SUCCESS; + sap_event.params = csr_roam_info; + sap_event.u1 = eCSR_ROAM_INFRA_IND; + sap_event.u2 = eCSR_ROAM_RESULT_INFRA_STARTED; + } else if (is_ch_dfs) { + if ((false == mac_ctx->sap.SapDfsInfo.ignore_cac) + && (eSAP_DFS_DO_NOT_SKIP_CAC == + mac_ctx->sap.SapDfsInfo.cac_state)) { + sap_ctx->sapsMachine = eSAP_DISCONNECTED; + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_MED, + FL("sapdfs: from state eSAP_DISCONNECTING => DISCONNECTED with ignore cac false on sapctx[%p]"), + sap_ctx); + /* DFS Channel */ + sap_event.event = eSAP_DFS_CHANNEL_CAC_START; + sap_event.params = csr_roam_info; + sap_event.u1 = 0; + sap_event.u2 = 0; + } else { + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_INFO_MED, + FL("sapdfs: from state eSAP_DISCONNECTING => eSAP_STARTING with ignore cac true on sapctx[%p]"), + sap_ctx); + + /* Start beaconing on the new channel */ + wlansap_start_beacon_req(sap_ctx); + sap_ctx->sapsMachine = eSAP_STARTING; + mac_ctx->sap.SapDfsInfo.sap_radar_found_status = false; + sap_event.event = eSAP_MAC_START_BSS_SUCCESS; + sap_event.params = csr_roam_info; + sap_event.u1 = eCSR_ROAM_INFRA_IND; + sap_event.u2 = eCSR_ROAM_RESULT_INFRA_STARTED; + } + } else { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_MED, + FL("sapdfs: from state eSAP_DISCONNECTING => eSAP_STARTING on sapctx[%p]"), + sap_ctx); + /* non-DFS channel */ + sap_ctx->sapsMachine = eSAP_STARTING; + mac_ctx->sap.SapDfsInfo.sap_radar_found_status = false; + sap_event.event = eSAP_MAC_START_BSS_SUCCESS; + sap_event.params = csr_roam_info; + sap_event.u1 = eCSR_ROAM_INFRA_IND; + sap_event.u2 = eCSR_ROAM_RESULT_INFRA_STARTED; + } + + /* Handle the event */ + qdf_status = sap_fsm(sap_ctx, &sap_event); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) + *ret_status = QDF_STATUS_E_FAILURE; +} + +/** + * wlansap_roam_process_dfs_chansw_update() - handles the case for + * eCSR_ROAM_RESULT_DFS_CHANSW_UPDATE_SUCCESS in wlansap_roam_callback() + * + * @hal: hal global context + * @sap_ctx: sap context + * @ret_status: update return status + * + * Return: void + */ +static void +wlansap_roam_process_dfs_chansw_update(tHalHandle hHal, + ptSapContext sap_ctx, + QDF_STATUS *ret_status) +{ + tWLAN_SAPEvent sap_event; + uint8_t intf; + QDF_STATUS qdf_status; + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hHal); + uint8_t dfs_beacon_start_req = 0; + + if (sap_ctx->csr_roamProfile.disableDFSChSwitch) { + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_ERROR, + FL("sapdfs: DFS channel switch disabled")); + /* + * Send a beacon start request to PE. CSA IE required flag from + * beacon template will be cleared by now. A new beacon template + * with no CSA IE will be sent to firmware. + */ + dfs_beacon_start_req = eSAP_TRUE; + sap_ctx->pre_cac_complete = false; + *ret_status = sme_roam_start_beacon_req(hHal, sap_ctx->bssid, + dfs_beacon_start_req); + return; + } + /* + * Irrespective of whether the channel switch IE was sent out + * successfully or not, SAP should still vacate the channel immediately + */ + if (eSAP_STARTED != sap_ctx->sapsMachine) { + /* Further actions to be taken here */ + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_WARN, + FL("eCSR_ROAM_RESULT_DFS_RADAR_FOUND_IND received in (%d) state"), + sap_ctx->sapsMachine); + return; + } + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_MED, + FL("sapdfs: from state eSAP_STARTED => eSAP_DISCONNECTING")); + /* SAP to be moved to DISCONNECTING state */ + sap_ctx->sapsMachine = eSAP_DISCONNECTING; + /* + * The associated stations have been informed to move to a different + * channel. However, the AP may not always select the advertised channel + * for operation if the radar is seen. In that case, the stations will + * experience link-loss and return back through scanning if they wish to + */ + + /* + * Send channel change request. From spec it is required that the AP + * should continue to operate in the same mode as it is operating + * currently. For e.g. 20/40/80 MHz operation + */ + if (mac_ctx->sap.SapDfsInfo.target_channel) + cds_set_channel_params(mac_ctx->sap.SapDfsInfo.target_channel, + 0, &sap_ctx->ch_params); + + /* + * Fetch the number of SAP interfaces. If the number of sap Interface + * more than one then we will make is_sap_ready_for_chnl_chng to true + * for that sapctx. If there is only one SAP interface then process + * immediately + */ + if (sap_get_total_number_sap_intf(hHal) <= 1) { + /* Send channel switch request */ + sap_event.event = eWNI_SME_CHANNEL_CHANGE_REQ; + sap_event.params = 0; + sap_event.u1 = 0; + sap_event.u2 = 0; + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_INFO_MED, + FL("sapdfs: Posting event eWNI_SME_CHANNEL_CHANGE_REQ to sapFSM")); + /* Handle event */ + qdf_status = sap_fsm(sap_ctx, &sap_event); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) + *ret_status = QDF_STATUS_E_FAILURE; + return; + } + + sap_ctx->is_sap_ready_for_chnl_chng = true; + /* + * now check if the con-current sap interface is ready + * for channel change. If yes then we issue channel change for + * both the SAPs. If no then simply return success & we will + * issue channel change when second AP's 5 CSA beacon Tx is + * completed. + */ + if (false == + is_concurrent_sap_ready_for_channel_change(hHal, sap_ctx)) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_MED, + FL("sapdfs: sapctx[%p] ready but not concurrent sap"), + sap_ctx); + *ret_status = QDF_STATUS_SUCCESS; + return; + } + + /* Issue channel change req for each sapctx */ + for (intf = 0; intf < SAP_MAX_NUM_SESSION; intf++) { + ptSapContext pSapContext; + if (!((QDF_SAP_MODE == mac_ctx->sap.sapCtxList[intf].sapPersona) + && (mac_ctx->sap.sapCtxList[intf].pSapContext != NULL))) + continue; + + pSapContext = mac_ctx->sap.sapCtxList[intf].pSapContext; + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_MED, + FL("sapdfs:issue chnl change for sapctx[%p]"), + pSapContext); + /* Send channel switch request */ + sap_event.event = eWNI_SME_CHANNEL_CHANGE_REQ; + sap_event.params = 0; + sap_event.u1 = 0; + sap_event.u2 = 0; + /* Handle event */ + qdf_status = sap_fsm(pSapContext, &sap_event); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("post chnl chng req failed, sap[%p]"), + sap_ctx); + *ret_status = QDF_STATUS_E_FAILURE; + } else { + pSapContext->is_sap_ready_for_chnl_chng = false; + } + } + return; +} + +/** + * wlansap_roam_process_dfs_radar_found() - handles the case for + * eCSR_ROAM_RESULT_DFS_RADAR_FOUND_IND in wlansap_roam_callback() + * + * @mac_ctx: mac global context + * @sap_ctx: sap context + * @ret_status: update return status + * + * Return: result of operation + */ +static void +wlansap_roam_process_dfs_radar_found(tpAniSirGlobal mac_ctx, + ptSapContext sap_ctx, + QDF_STATUS *ret_status) +{ + QDF_STATUS qdf_status; + tWLAN_SAPEvent sap_event; + if (eSAP_DFS_CAC_WAIT == sap_ctx->sapsMachine) { + if (sap_ctx->csr_roamProfile.disableDFSChSwitch) { + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_ERROR, + "sapdfs: DFS channel switch disabled"); + return; + } + if (false == mac_ctx->sap.SapDfsInfo.sap_radar_found_status) { + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_ERROR, + "sapdfs: sap_radar_found_status is false"); + return; + } + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_INFO_MED, + FL("sapdfs:Posting event eSAP_DFS_CHANNEL_CAC_RADAR_FOUND")); + /* + * If Radar is found, while in DFS CAC WAIT State then post stop + * and destroy the CAC timer and post a + * eSAP_DFS_CHANNEL_CAC_RADAR_FOUND to sapFsm. + */ + qdf_mc_timer_stop(&mac_ctx->sap.SapDfsInfo.sap_dfs_cac_timer); + qdf_mc_timer_destroy(&mac_ctx->sap.SapDfsInfo.sap_dfs_cac_timer); + mac_ctx->sap.SapDfsInfo.is_dfs_cac_timer_running = false; + + /* + * User space is already indicated the CAC start and if + * CAC end on this channel is not indicated, the user + * space will be in some undefined state (e.g., UI frozen) + */ + qdf_status = sap_signal_hdd_event(sap_ctx, NULL, + eSAP_DFS_CAC_INTERRUPTED, + (void *) eSAP_STATUS_SUCCESS); + if (QDF_STATUS_SUCCESS != qdf_status) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("Failed to send CAC end")); + /* Want to still proceed and try to switch channel. + * Lets try not to be on the DFS channel + */ + } + + sap_event.event = eSAP_DFS_CHANNEL_CAC_RADAR_FOUND; + sap_event.params = 0; + sap_event.u1 = 0; + sap_event.u2 = 0; + qdf_status = sap_fsm(sap_ctx, &sap_event); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) + *ret_status = QDF_STATUS_E_FAILURE; + return; + } + if (eSAP_STARTED == sap_ctx->sapsMachine) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_MED, + FL("sapdfs:Posting event eSAP_DFS_CHNL_SWITCH_ANNOUNCEMENT_START")); + + /* + * Radar found on the operating channel in STARTED state, + * new operating channel has already been selected. Send + * request to SME-->PE for sending CSA IE + */ + sap_event.event = eSAP_DFS_CHNL_SWITCH_ANNOUNCEMENT_START; + sap_event.params = 0; + sap_event.u1 = 0; + sap_event.u2 = 0; + qdf_status = sap_fsm(sap_ctx, &sap_event); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) + *ret_status = QDF_STATUS_E_FAILURE; + return; + } + /* Further actions to be taken here */ + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("eCSR_ROAM_RESULT_DFS_RADAR_FOUND_IND received in (%d) state"), + sap_ctx->sapsMachine); + + return; +} + +/** + * wlansap_roam_process_infra_assoc_ind() - handles the case for + * eCSR_ROAM_RESULT_INFRA_ASSOCIATION_IND in wlansap_roam_callback() + * + * @sap_ctx: sap context + * @roam_result: roam result + * @csr_roam_info: roam info struct + * @ret_status: update return status + * + * Return: result of operation + */ +static void +wlansap_roam_process_infra_assoc_ind(ptSapContext sap_ctx, + eCsrRoamResult roam_result, + tCsrRoamInfo *csr_roam_info, + QDF_STATUS *ret_status) +{ + QDF_STATUS qdf_status; + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + FL("CSR roam_result = eCSR_ROAM_RESULT_INFRA_ASSOCIATION_IND (%d)"), + roam_result); + sap_ctx->nStaWPARSnReqIeLength = csr_roam_info->rsnIELen; + if (sap_ctx->nStaWPARSnReqIeLength) + qdf_mem_copy(sap_ctx->pStaWpaRsnReqIE, csr_roam_info->prsnIE, + sap_ctx->nStaWPARSnReqIeLength); +#ifdef FEATURE_WLAN_WAPI + sap_ctx->nStaWAPIReqIeLength = csr_roam_info->wapiIELen; + if (sap_ctx->nStaWAPIReqIeLength) + qdf_mem_copy(sap_ctx->pStaWapiReqIE, csr_roam_info->pwapiIE, + sap_ctx->nStaWAPIReqIeLength); +#endif + sap_ctx->nStaAddIeLength = csr_roam_info->addIELen; + if (sap_ctx->nStaAddIeLength) + qdf_mem_copy(sap_ctx->pStaAddIE, csr_roam_info->paddIE, + sap_ctx->nStaAddIeLength); + sap_ctx->SapQosCfg.WmmIsEnabled = csr_roam_info->wmmEnabledSta; + /* MAC filtering */ + qdf_status = sap_is_peer_mac_allowed(sap_ctx, + (uint8_t *) csr_roam_info->peerMac.bytes); + + if (QDF_STATUS_SUCCESS == qdf_status) { + qdf_status = sap_signal_hdd_event(sap_ctx, + csr_roam_info, eSAP_STA_ASSOC_IND, + (void *) eSAP_STATUS_SUCCESS); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("CSR roam_result = (%d) MAC ("MAC_ADDRESS_STR") fail"), + roam_result, MAC_ADDR_ARRAY( + csr_roam_info->peerMac.bytes)); + *ret_status = QDF_STATUS_E_FAILURE; + } + } else { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_WARN, + FL("CSR roam_result = (%d) MAC ("MAC_ADDRESS_STR") not allowed"), + roam_result, + MAC_ADDR_ARRAY(csr_roam_info->peerMac.bytes)); + *ret_status = QDF_STATUS_E_FAILURE; + } + return; +} + +/** + * wlansap_roam_callback() - Callback for Roam (connection status) Events + * @ctx : pContext passed in with the roam request + * @csr_roam_info : Pointer to a tCsrRoamInfo + * @roamId : to identify the callback related roam request. + * 0 means unsolicit + * @roam_status : Flag indicating the status of the callback + * @roam_result : Result + * + * This function finds dot11 mode based on current mode, operating channel and + * fw supported modes. + * + * Return: Status of operation + */ +QDF_STATUS +wlansap_roam_callback(void *ctx, tCsrRoamInfo *csr_roam_info, uint32_t roamId, + eRoamCmdStatus roam_status, eCsrRoamResult roam_result) +{ + /* sap_ctx value */ + ptSapContext sap_ctx; + /* State machine event */ + tWLAN_SAPEvent sap_event; + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + QDF_STATUS qdf_ret_status = QDF_STATUS_SUCCESS; + tHalHandle hal; + tpAniSirGlobal mac_ctx = NULL; + uint8_t intf; + + if (QDF_IS_STATUS_ERROR(wlansap_context_get((ptSapContext)ctx))) + return QDF_STATUS_E_FAILURE; + + sap_ctx = (ptSapContext) ctx; + hal = CDS_GET_HAL_CB(sap_ctx->p_cds_gctx); + if (!hal) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("Invalid handle")); + wlansap_context_put(sap_ctx); + return QDF_STATUS_E_NOMEM; + } + + mac_ctx = PMAC_STRUCT(hal); + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + FL("Before switch on roam_status = %d"), roam_status); + switch (roam_status) { + case eCSR_ROAM_SESSION_OPENED: + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + FL("Session %d opened successfully"), + sap_ctx->sessionId); + sap_ctx->isSapSessionOpen = eSAP_TRUE; + qdf_event_set(&sap_ctx->sap_session_opened_evt); + break; + case eCSR_ROAM_INFRA_IND: + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + FL("CSR roam_status = eCSR_ROAM_INFRA_IND (%d)"), + roam_status); + if (roam_result == eCSR_ROAM_RESULT_INFRA_START_FAILED) { + /* Fill in the event structure */ + sap_event.event = eSAP_MAC_START_FAILS; + sap_event.params = csr_roam_info; + sap_event.u1 = roam_status; + sap_event.u2 = roam_result; + /* Handle event */ + qdf_status = sap_fsm(sap_ctx, &sap_event); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) + qdf_ret_status = QDF_STATUS_E_FAILURE; + } + break; + case eCSR_ROAM_LOSTLINK: + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + FL("CSR roam_status = eCSR_ROAM_LOSTLINK (%d)"), + roam_status); + break; + case eCSR_ROAM_MIC_ERROR_IND: + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + FL("CSR roam_status = eCSR_ROAM_MIC_ERROR_IND (%d)"), + roam_status); + break; + case eCSR_ROAM_SET_KEY_COMPLETE: + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + FL("CSR roam_status = eCSR_ROAM_SET_KEY_COMPLETE (%d)"), + roam_status); + if (roam_result == eCSR_ROAM_RESULT_FAILURE) + sap_signal_hdd_event(sap_ctx, csr_roam_info, + eSAP_STA_SET_KEY_EVENT, + (void *) eSAP_STATUS_FAILURE); + break; + case eCSR_ROAM_ASSOCIATION_COMPLETION: + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + FL("CSR roam_status = eCSR_ROAM_ASSOCIATION_COMPLETION (%d)"), + roam_status); + if (roam_result == eCSR_ROAM_RESULT_FAILURE) + sap_signal_hdd_event(sap_ctx, csr_roam_info, + eSAP_STA_REASSOC_EVENT, + (void *) eSAP_STATUS_FAILURE); + break; + case eCSR_ROAM_DISASSOCIATED: + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + FL("CSR roam_status = eCSR_ROAM_DISASSOCIATED (%d)"), + roam_status); + if (roam_result == eCSR_ROAM_RESULT_MIC_FAILURE) + sap_signal_hdd_event(sap_ctx, csr_roam_info, + eSAP_STA_MIC_FAILURE_EVENT, + (void *) eSAP_STATUS_FAILURE); + break; + case eCSR_ROAM_WPS_PBC_PROBE_REQ_IND: + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + FL("CSR roam_status = eCSR_ROAM_WPS_PBC_PROBE_REQ_IND (%d)"), + roam_status); + break; + case eCSR_ROAM_REMAIN_CHAN_READY: + /* roamId contains scan identifier */ + sap_ctx->roc_ind_scan_id = csr_roam_info->roc_scan_id; + sap_signal_hdd_event(sap_ctx, csr_roam_info, + eSAP_REMAIN_CHAN_READY, + (void *) eSAP_STATUS_SUCCESS); + break; + case eCSR_ROAM_DISCONNECT_ALL_P2P_CLIENTS: + sap_signal_hdd_event(sap_ctx, csr_roam_info, + eSAP_DISCONNECT_ALL_P2P_CLIENT, + (void *) eSAP_STATUS_SUCCESS); + break; + case eCSR_ROAM_SEND_P2P_STOP_BSS: + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + FL("Received stopbss")); + sap_signal_hdd_event(sap_ctx, csr_roam_info, + eSAP_MAC_TRIG_STOP_BSS_EVENT, + (void *) eSAP_STATUS_SUCCESS); + break; + case eCSR_ROAM_DFS_RADAR_IND: + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + FL("Received Radar Indication")); + + if (sap_ctx->is_pre_cac_on) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_MED, + FL("sapdfs: Radar detect on pre cac:%d"), + sap_ctx->sessionId); + qdf_mc_timer_stop( + &mac_ctx->sap.SapDfsInfo.sap_dfs_cac_timer); + qdf_mc_timer_destroy( + &mac_ctx->sap.SapDfsInfo.sap_dfs_cac_timer); + mac_ctx->sap.SapDfsInfo.is_dfs_cac_timer_running = + false; + sap_signal_hdd_event(sap_ctx, NULL, + eSAP_DFS_RADAR_DETECT_DURING_PRE_CAC, + (void *) eSAP_STATUS_SUCCESS); + break; + } + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_MED, + FL("sapdfs: Indicate eSAP_DFS_RADAR_DETECT to HDD")); + sap_signal_hdd_event(sap_ctx, NULL, eSAP_DFS_RADAR_DETECT, + (void *) eSAP_STATUS_SUCCESS); + /* sync to latest DFS-NOL */ + sap_signal_hdd_event(sap_ctx, NULL, eSAP_DFS_NOL_GET, + (void *) eSAP_STATUS_SUCCESS); + mac_ctx->sap.SapDfsInfo.target_channel = + sap_indicate_radar(sap_ctx, &csr_roam_info->dfs_event); + /* if there is an assigned next channel hopping */ + if (0 < mac_ctx->sap.SapDfsInfo.user_provided_target_channel) { + mac_ctx->sap.SapDfsInfo.target_channel = + mac_ctx->sap.SapDfsInfo.user_provided_target_channel; + mac_ctx->sap.SapDfsInfo.user_provided_target_channel = + 0; + } + if (mac_ctx->sap.SapDfsInfo.target_channel != 0) { + mac_ctx->sap.SapDfsInfo.cac_state = + eSAP_DFS_DO_NOT_SKIP_CAC; + sap_cac_reset_notify(hal); + /* set DFS-NOL back to keep it update-to-date in CNSS */ + sap_signal_hdd_event(sap_ctx, NULL, eSAP_DFS_NOL_SET, + (void *) eSAP_STATUS_SUCCESS); + break; + } + /* Issue stopbss for each sapctx */ + for (intf = 0; intf < SAP_MAX_NUM_SESSION; intf++) { + ptSapContext pSapContext; + if (((QDF_SAP_MODE == + mac_ctx->sap.sapCtxList[intf].sapPersona) || + (QDF_P2P_GO_MODE == + mac_ctx->sap.sapCtxList[intf].sapPersona)) && + mac_ctx->sap.sapCtxList[intf].pSapContext != + NULL) { + pSapContext = + mac_ctx->sap.sapCtxList[intf].pSapContext; + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_ERROR, + FL("sapdfs: no available channel for sapctx[%p], StopBss"), + pSapContext); + wlansap_stop_bss(pSapContext); + } + } + break; + case eCSR_ROAM_DFS_CHAN_SW_NOTIFY: + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + FL("Received Chan Sw Update Notification")); + break; + case eCSR_ROAM_SET_CHANNEL_RSP: + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + FL("Received set channel response")); + break; + case eCSR_ROAM_EXT_CHG_CHNL_IND: + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + FL("Received set channel Indication")); + break; + case eCSR_ROAM_UPDATE_SCAN_RESULT: + sap_signal_hdd_event(sap_ctx, csr_roam_info, + eSAP_UPDATE_SCAN_RESULT, + (void *) eSAP_STATUS_SUCCESS); + break; + default: + break; + } + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + FL("Before switch on roam_result = %d"), roam_result); + + switch (roam_result) { + case eCSR_ROAM_RESULT_INFRA_ASSOCIATION_IND: + wlansap_roam_process_infra_assoc_ind(sap_ctx, roam_result, + csr_roam_info, &qdf_ret_status); + break; + case eCSR_ROAM_RESULT_INFRA_ASSOCIATION_CNF: + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + FL("CSR roam_result = eCSR_ROAM_RESULT_INFRA_ASSOCIATION_CNF (%d)"), + roam_result); + sap_ctx->nStaWPARSnReqIeLength = csr_roam_info->rsnIELen; + if (sap_ctx->nStaWPARSnReqIeLength) + qdf_mem_copy(sap_ctx->pStaWpaRsnReqIE, + csr_roam_info->prsnIE, + sap_ctx->nStaWPARSnReqIeLength); + + sap_ctx->nStaAddIeLength = csr_roam_info->addIELen; + if (sap_ctx->nStaAddIeLength) + qdf_mem_copy(sap_ctx->pStaAddIE, + csr_roam_info->paddIE, + sap_ctx->nStaAddIeLength); + + sap_ctx->SapQosCfg.WmmIsEnabled = + csr_roam_info->wmmEnabledSta; + /* Fill in the event structure */ + qdf_status = sap_signal_hdd_event(sap_ctx, csr_roam_info, + eSAP_STA_ASSOC_EVENT, + (void *) eSAP_STATUS_SUCCESS); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) + qdf_ret_status = QDF_STATUS_E_FAILURE; + break; + case eCSR_ROAM_RESULT_DEAUTH_IND: + case eCSR_ROAM_RESULT_DISASSOC_IND: + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + FL("CSR roam_result = eCSR_ROAM_RESULT_DEAUTH/DISASSOC_IND (%d)"), + roam_result); + /* Fill in the event structure */ + qdf_status = sap_signal_hdd_event(sap_ctx, csr_roam_info, + eSAP_STA_DISASSOC_EVENT, + (void *) eSAP_STATUS_SUCCESS); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) + qdf_ret_status = QDF_STATUS_E_FAILURE; + break; + case eCSR_ROAM_RESULT_MIC_ERROR_GROUP: + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + FL("CSR roam_result = eCSR_ROAM_RESULT_MIC_ERROR_GROUP (%d)"), + roam_result); + /* + * Fill in the event structure + * TODO: support for group key MIC failure event to be handled + */ + qdf_status = sap_signal_hdd_event(sap_ctx, csr_roam_info, + eSAP_STA_MIC_FAILURE_EVENT, + (void *) NULL); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) + qdf_ret_status = QDF_STATUS_E_FAILURE; + break; + case eCSR_ROAM_RESULT_MIC_ERROR_UNICAST: + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + FL("CSR roam_result = eCSR_ROAM_RESULT_MIC_ERROR_UNICAST (%d)"), + roam_result); + /* + * Fill in the event structure + * TODO: support for unicast key MIC failure event to be handled + */ + qdf_status = + sap_signal_hdd_event(sap_ctx, csr_roam_info, + eSAP_STA_MIC_FAILURE_EVENT, + (void *) NULL); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + qdf_ret_status = QDF_STATUS_E_FAILURE; + } + break; + case eCSR_ROAM_RESULT_AUTHENTICATED: + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + FL("CSR roam_result = eCSR_ROAM_RESULT_AUTHENTICATED (%d)"), + roam_result); + /* Fill in the event structure */ + sap_signal_hdd_event(sap_ctx, csr_roam_info, + eSAP_STA_SET_KEY_EVENT, + (void *) eSAP_STATUS_SUCCESS); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) + qdf_ret_status = QDF_STATUS_E_FAILURE; + break; + case eCSR_ROAM_RESULT_ASSOCIATED: + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + FL("CSR roam_result = eCSR_ROAM_RESULT_ASSOCIATED (%d)"), + roam_result); + /* Fill in the event structure */ + sap_signal_hdd_event(sap_ctx, csr_roam_info, + eSAP_STA_REASSOC_EVENT, + (void *) eSAP_STATUS_SUCCESS); + break; + case eCSR_ROAM_RESULT_INFRA_STARTED: + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + FL("CSR roam_result = eCSR_ROAM_RESULT_INFRA_STARTED (%d)"), + roam_result); + /* + * In the current implementation, hostapd is not aware that + * drive will support DFS. Hence, driver should inform + * eSAP_MAC_START_BSS_SUCCESS to upper layers and then perform + * CAC underneath + */ + sap_event.event = eSAP_MAC_START_BSS_SUCCESS; + sap_event.params = csr_roam_info; + sap_event.u1 = roam_status; + sap_event.u2 = roam_result; + qdf_status = sap_fsm(sap_ctx, &sap_event); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) + qdf_ret_status = QDF_STATUS_E_FAILURE; + break; + case eCSR_ROAM_RESULT_INFRA_STOPPED: + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + FL("CSR roam_result = eCSR_ROAM_RESULT_INFRA_STOPPED (%d)"), + roam_result); + /* Fill in the event structure */ + sap_event.event = eSAP_MAC_READY_FOR_CONNECTIONS; + sap_event.params = csr_roam_info; + sap_event.u1 = roam_status; + sap_event.u2 = roam_result; + /* Handle event */ + qdf_status = sap_fsm(sap_ctx, &sap_event); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) + qdf_ret_status = QDF_STATUS_E_FAILURE; + break; + case eCSR_ROAM_RESULT_WPS_PBC_PROBE_REQ_IND: + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + FL("CSR roam_result = eCSR_ROAM_RESULT_WPS_PBC_PROBE_REQ_IND (%d)"), + roam_result); + /* + * Fill in the event structure + * TODO: support for group key MIC failure event to be handled + */ + qdf_status = sap_signal_hdd_event(sap_ctx, csr_roam_info, + eSAP_WPS_PBC_PROBE_REQ_EVENT, + (void *) NULL); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) + qdf_ret_status = QDF_STATUS_E_FAILURE; + break; + case eCSR_ROAM_RESULT_FORCED: + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + FL("CSR roam_result = eCSR_ROAM_RESULT_FORCED (%d)"), + roam_result); + /* + * This event can be used to inform hdd about user triggered + * disassoc event + * Fill in the event structure + */ + sap_signal_hdd_event(sap_ctx, csr_roam_info, + eSAP_STA_DISASSOC_EVENT, + (void *) eSAP_STATUS_SUCCESS); + break; + case eCSR_ROAM_RESULT_NONE: + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + FL("CSR roam_result = eCSR_ROAM_RESULT_NONE (%d)"), + roam_result); + /* + * This event can be used to inform hdd about user triggered + * disassoc event + * Fill in the event structure + */ + if (roam_status == eCSR_ROAM_SET_KEY_COMPLETE) + sap_signal_hdd_event(sap_ctx, csr_roam_info, + eSAP_STA_SET_KEY_EVENT, + (void *) eSAP_STATUS_SUCCESS); + break; + case eCSR_ROAM_RESULT_MAX_ASSOC_EXCEEDED: + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + FL("CSR roam_result = eCSR_ROAM_RESULT_MAX_ASSOC_EXCEEDED (%d)"), + roam_result); + /* Fill in the event structure */ + qdf_status = sap_signal_hdd_event(sap_ctx, csr_roam_info, + eSAP_MAX_ASSOC_EXCEEDED, + NULL); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) + qdf_ret_status = QDF_STATUS_E_FAILURE; + + break; + case eCSR_ROAM_RESULT_DFS_RADAR_FOUND_IND: + wlansap_roam_process_dfs_radar_found(mac_ctx, sap_ctx, + &qdf_ret_status); + break; + case eCSR_ROAM_RESULT_DFS_CHANSW_UPDATE_SUCCESS: + wlansap_roam_process_dfs_chansw_update(hal, sap_ctx, + &qdf_ret_status); + break; + case eCSR_ROAM_RESULT_CHANNEL_CHANGE_SUCCESS: + wlansap_roam_process_ch_change_success(mac_ctx, sap_ctx, + csr_roam_info, &qdf_ret_status); + break; + case eCSR_ROAM_RESULT_CHANNEL_CHANGE_FAILURE: + /* This is much more serious issue, we have to vacate the + * channel due to the presence of radar but our channel change + * failed, stop the BSS operation completely and inform hostapd + */ + sap_event.event = eWNI_SME_CHANNEL_CHANGE_RSP; + sap_event.params = 0; + sap_event.u1 = eCSR_ROAM_INFRA_IND; + sap_event.u2 = eCSR_ROAM_RESULT_CHANNEL_CHANGE_FAILURE; + + qdf_status = sap_fsm(sap_ctx, &sap_event); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) + qdf_ret_status = QDF_STATUS_E_FAILURE; + break; + case eCSR_ROAM_EXT_CHG_CHNL_UPDATE_IND: + qdf_status = sap_signal_hdd_event(sap_ctx, csr_roam_info, + eSAP_ECSA_CHANGE_CHAN_IND, NULL); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) + qdf_ret_status = QDF_STATUS_E_FAILURE; + break; + default: + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("CSR roam_result = %s (%d) not handled"), + get_e_csr_roam_result_str(roam_result), + roam_result); + break; + } + wlansap_context_put(sap_ctx); + return qdf_ret_status; +} diff --git a/drivers/staging/qcacld-3.0/core/sap/src/sap_ch_select.c b/drivers/staging/qcacld-3.0/core/sap/src/sap_ch_select.c new file mode 100644 index 0000000000000000000000000000000000000000..6dc64ecf70226d1bc265d801edad5a539c4bb81d --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/sap/src/sap_ch_select.c @@ -0,0 +1,2379 @@ +/* + * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/*=========================================================================== + + s a p C h S e l e c t . C + OVERVIEW: + + This software unit holds the implementation of the WLAN SAP modules + functions for channel selection. + + DEPENDENCIES: + + Are listed for each API below. + ===========================================================================*/ + +/*-------------------------------------------------------------------------- + Include Files + ------------------------------------------------------------------------*/ +#include "qdf_trace.h" +#include "csr_api.h" +#include "sme_api.h" +#include "sap_ch_select.h" +#include "sap_internal.h" +#ifdef ANI_OS_TYPE_QNX +#include "stdio.h" +#endif +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE +#include "lim_utils.h" +#include "parser_api.h" +#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ +#include "cds_utils.h" +#include "pld_common.h" + +/*-------------------------------------------------------------------------- + Function definitions + --------------------------------------------------------------------------*/ + +/*-------------------------------------------------------------------------- + Defines + --------------------------------------------------------------------------*/ +#define SAP_DEBUG + +#define IS_RSSI_VALID(extRssi, rssi) \ + ( \ + ((extRssi < rssi) ? true : false) \ + ) + +#define SET_ACS_BAND(acs_band, pSapCtx) \ +{ \ + if (pSapCtx->acs_cfg->start_ch <= 14 && \ + pSapCtx->acs_cfg->end_ch <= 14) \ + acs_band = eCSR_DOT11_MODE_11g; \ + else if (pSapCtx->acs_cfg->start_ch >= 14)\ + acs_band = eCSR_DOT11_MODE_11a; \ + else \ + acs_band = eCSR_DOT11_MODE_abg; \ +} + +#define GET_IE_LEN_IN_BSS_DESC(lenInBss) (lenInBss + sizeof(lenInBss) - \ + ((uintptr_t)OFFSET_OF(tSirBssDescription, ieFields))) + +#ifdef FEATURE_WLAN_CH_AVOID +sapSafeChannelType safe_channels[NUM_CHANNELS] = { + {1, true}, + {2, true}, + {3, true}, + {4, true}, + {5, true}, + {6, true}, + {7, true}, + {8, true}, + {9, true}, + {10, true}, + {11, true}, + {12, true}, + {13, true}, + {14, true}, + {36, true}, + {40, true}, + {44, true}, + {48, true}, + {52, true}, + {56, true}, + {60, true}, + {64, true}, + {100, true}, + {104, true}, + {108, true}, + {112, true}, + {116, true}, + {120, true}, + {124, true}, + {128, true}, + {132, true}, + {136, true}, + {140, true}, + {144, true}, + {149, true}, + {153, true}, + {157, true}, + {161, true}, + {165, true}, +}; +#endif + +typedef struct { + uint16_t chStartNum; + uint32_t weight; +} sapAcsChannelInfo; + +sapAcsChannelInfo acs_ht40_channels5_g[] = { + {36, SAP_ACS_WEIGHT_MAX}, + {44, SAP_ACS_WEIGHT_MAX}, + {52, SAP_ACS_WEIGHT_MAX}, + {60, SAP_ACS_WEIGHT_MAX}, + {100, SAP_ACS_WEIGHT_MAX}, + {108, SAP_ACS_WEIGHT_MAX}, + {116, SAP_ACS_WEIGHT_MAX}, + {124, SAP_ACS_WEIGHT_MAX}, + {132, SAP_ACS_WEIGHT_MAX}, + {140, SAP_ACS_WEIGHT_MAX}, + {149, SAP_ACS_WEIGHT_MAX}, + {157, SAP_ACS_WEIGHT_MAX}, +}; + +sapAcsChannelInfo acs_ht80_channels[] = { + {36, SAP_ACS_WEIGHT_MAX}, + {52, SAP_ACS_WEIGHT_MAX}, + {100, SAP_ACS_WEIGHT_MAX}, + {116, SAP_ACS_WEIGHT_MAX}, + {132, SAP_ACS_WEIGHT_MAX}, + {149, SAP_ACS_WEIGHT_MAX}, +}; + +sapAcsChannelInfo acs_vht160_channels[] = { + {36, SAP_ACS_WEIGHT_MAX}, + {100, SAP_ACS_WEIGHT_MAX}, +}; + +sapAcsChannelInfo acs_ht40_channels24_g[] = { + {1, SAP_ACS_WEIGHT_MAX}, + {2, SAP_ACS_WEIGHT_MAX}, + {3, SAP_ACS_WEIGHT_MAX}, + {4, SAP_ACS_WEIGHT_MAX}, + {9, SAP_ACS_WEIGHT_MAX}, +}; + +#define CHANNEL_165 165 + +/* rssi discount for channels in PCL */ +#define PCL_RSSI_DISCOUNT 10 + +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE +/** + * sap_check_n_add_channel() - checks and add given channel in sap context's + * avoid_channels_info struct + * @sap_ctx: sap context. + * @new_channel: channel to be added to sap_ctx's avoid ch info + * + * sap_ctx contains sap_avoid_ch_info strcut containing the list of channels on + * which MDM device's AP with MCC was detected. This function will add channels + * to that list after checking for duplicates. + * + * Return: true: if channel was added or already present + * else false: if channel list was already full. + */ +static bool +sap_check_n_add_channel(ptSapContext sap_ctx, + uint8_t new_channel) +{ + uint8_t i = 0; + struct sap_avoid_channels_info *ie_info = + &sap_ctx->sap_detected_avoid_ch_ie; + + for (i = 0; i < sizeof(ie_info->channels); i++) { + if (ie_info->channels[i] == new_channel) + break; + + if (ie_info->channels[i] == 0) { + ie_info->channels[i] = new_channel; + break; + } + } + if (i == sizeof(ie_info->channels)) + return false; + else + return true; +} +/** + * sap_check_n_add_overlapped_chnls() - checks & add overlapped channels + * to primary channel in 2.4Ghz band. + * @sap_ctx: sap context. + * @primary_chnl: primary channel to be avoided. + * + * sap_ctx contains sap_avoid_ch_info struct containing the list of channels on + * which MDM device's AP with MCC was detected. This function will add channels + * to that list after checking for duplicates. + * + * Return: true: if channel was added or already present + * else false: if channel list was already full. + */ +static bool +sap_check_n_add_overlapped_chnls(ptSapContext sap_ctx, uint8_t primary_channel) +{ + uint8_t i = 0, j = 0, upper_chnl = 0, lower_chnl = 0; + struct sap_avoid_channels_info *ie_info = + &sap_ctx->sap_detected_avoid_ch_ie; + /* + * if primary channel less than channel 1 or out of 2g band then + * no further process is required. return true in this case. + */ + if (primary_channel < CHANNEL_1 || primary_channel > CHANNEL_14) + return true; + + /* lower channel is one channel right before primary channel */ + lower_chnl = primary_channel - 1; + /* upper channel is one channel right after primary channel */ + upper_chnl = primary_channel + 1; + + /* lower channel needs to be non-zero, zero is not valid channel */ + if (lower_chnl > (CHANNEL_1 - 1)) { + for (i = 0; i < sizeof(ie_info->channels); i++) { + if (ie_info->channels[i] == lower_chnl) + break; + if (ie_info->channels[i] == 0) { + ie_info->channels[i] = lower_chnl; + break; + } + } + } + /* upper channel needs to be atleast last channel in 2.4Ghz band */ + if (upper_chnl < (CHANNEL_14 + 1)) { + for (j = 0; j < sizeof(ie_info->channels); j++) { + if (ie_info->channels[j] == upper_chnl) + break; + if (ie_info->channels[j] == 0) { + ie_info->channels[j] = upper_chnl; + break; + } + } + } + if (i == sizeof(ie_info->channels) || j == sizeof(ie_info->channels)) + return false; + else + return true; +} + +/** + * sap_process_avoid_ie() - processes the detected Q2Q IE + * context's avoid_channels_info struct + * @hal: hal handle + * @sap_ctx: sap context. + * @scan_result: scan results for ACS scan. + * @spect_info: spectrum weights array to update + * + * Detection of Q2Q IE indicates presence of another MDM device with its AP + * operating in MCC mode. This function parses the scan results and processes + * the Q2Q IE if found. It then extracts the channels and populates them in + * sap_ctx struct. It also increases the weights of those channels so that + * ACS logic will avoid those channels in its selection algorithm. + * + * Return: void + */ +static void sap_process_avoid_ie(tHalHandle hal, + ptSapContext sap_ctx, + tScanResultHandle scan_result, + tSapChSelSpectInfo *spect_info) +{ + uint32_t total_ie_len = 0; + uint8_t *temp_ptr = NULL; + uint8_t i = 0; + struct sAvoidChannelIE *avoid_ch_ie; + tCsrScanResultInfo *node = NULL; + tpAniSirGlobal mac_ctx = NULL; + tSapSpectChInfo *spect_ch = NULL; + + mac_ctx = PMAC_STRUCT(hal); + spect_ch = spect_info->pSpectCh; + node = sme_scan_result_get_first(hal, scan_result); + + while (node) { + total_ie_len = + GET_IE_LEN_IN_BSS_DESC(node->BssDescriptor.length); + temp_ptr = cfg_get_vendor_ie_ptr_from_oui(mac_ctx, + SIR_MAC_QCOM_VENDOR_OUI, + SIR_MAC_QCOM_VENDOR_SIZE, + ((uint8_t *)&node->BssDescriptor.ieFields), + total_ie_len); + + if (temp_ptr) { + avoid_ch_ie = (struct sAvoidChannelIE *)temp_ptr; + if (avoid_ch_ie->type != QCOM_VENDOR_IE_MCC_AVOID_CH) + continue; + + sap_ctx->sap_detected_avoid_ch_ie.present = 1; + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_DEBUG, + "Q2Q IE - avoid ch %d", + avoid_ch_ie->channel); + /* add this channel to to_avoid channel list */ + sap_check_n_add_channel(sap_ctx, + avoid_ch_ie->channel); + sap_check_n_add_overlapped_chnls(sap_ctx, + avoid_ch_ie->channel); + /* + * Mark weight of these channel present in IE to MAX + * so that ACS logic will to avoid thse channels + */ + for (i = 0; i < spect_info->numSpectChans; i++) + if (spect_ch[i].chNum == avoid_ch_ie->channel) { + /* + * weight is set more than max so that, + * in the case of other channels being + * assigned max weight due to noise, + * they may be preferred over channels + * with Q2Q IE. + */ + spect_ch[i].weight = SAP_ACS_WEIGHT_MAX + 1; + spect_ch[i].weight_copy = + SAP_ACS_WEIGHT_MAX + 1; + break; + } + } /* if (temp_ptr) */ + node = sme_scan_result_get_next(hal, scan_result); + } +} +#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ + +#ifdef FEATURE_WLAN_CH_AVOID +/*========================================================================== + FUNCTION sap_update_unsafe_channel_list + + DESCRIPTION + Function Undate unsafe channel list table + + DEPENDENCIES + NA. + + IN + SapContext pointer + + RETURN VALUE + NULL + ============================================================================*/ +void sap_update_unsafe_channel_list(ptSapContext pSapCtx) +{ + uint16_t i, j; + uint16_t unsafe_channel_list[NUM_CHANNELS]; + uint16_t unsafe_channel_count = 0; + qdf_device_t qdf_ctx = cds_get_context(QDF_MODULE_ID_QDF_DEVICE); + + if (!qdf_ctx) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_FATAL, + "qdf_ctx is NULL"); + return; + } + + /* Flush, default set all channel safe */ + for (i = 0; i < NUM_CHANNELS; i++) { + safe_channels[i].isSafe = true; + } + + /* Try to find unsafe channel */ +#if defined(FEATURE_WLAN_STA_AP_MODE_DFS_DISABLE) + for (i = 0; i < NUM_CHANNELS; i++) { + if (pSapCtx->dfs_ch_disable == true) { + if (CDS_IS_DFS_CH(safe_channels[i].channelNumber)) { + safe_channels[i].isSafe = false; + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_INFO_HIGH, + "%s: DFS Ch %d is not safe in" + " Concurrent mode", + __func__, + safe_channels[i].channelNumber); + } + } + } +#endif + pld_get_wlan_unsafe_channel(qdf_ctx->dev, + unsafe_channel_list, + &unsafe_channel_count, + sizeof(unsafe_channel_list)); + + for (i = 0; i < unsafe_channel_count; i++) { + for (j = 0; j < NUM_CHANNELS; j++) { + if (safe_channels[j].channelNumber == + unsafe_channel_list[i]) { + /* Found unsafe channel, update it */ + safe_channels[j].isSafe = false; + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_ERROR, + FL("CH %d is not safe"), + unsafe_channel_list[i]); + break; + } + } + } + + return; +} + +#endif /* FEATURE_WLAN_CH_AVOID */ + +/*========================================================================== + FUNCTION sap_cleanup_channel_list + + DESCRIPTION + Function sap_cleanup_channel_list frees up the memory allocated to the channel list. + + DEPENDENCIES + NA. + + PARAMETERS + + IN + NULL + + RETURN VALUE + NULL + ============================================================================*/ + +void sap_cleanup_channel_list(void *p_cds_gctx) +{ + ptSapContext pSapCtx; + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO, + "Cleaning up the channel list structure"); + + if (NULL == p_cds_gctx) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_FATAL, + "SAP Global Context is NULL"); + return; + } + + pSapCtx = CDS_GET_SAP_CB(p_cds_gctx); + if (NULL == pSapCtx) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_FATAL, + "SAP Context is NULL"); + return; + } + + pSapCtx->SapChnlList.numChannel = 0; + if (pSapCtx->SapChnlList.channelList) { + qdf_mem_free(pSapCtx->SapChnlList.channelList); + pSapCtx->SapChnlList.channelList = NULL; + } + + pSapCtx->SapAllChnlList.numChannel = 0; + if (pSapCtx->SapAllChnlList.channelList) { + qdf_mem_free(pSapCtx->SapAllChnlList.channelList); + pSapCtx->SapAllChnlList.channelList = NULL; + } +} + +/** + * sap_select_preferred_channel_from_channel_list() - to calc best cahnnel + * @best_chnl: best channel already calculated among all the chanels + * @sap_ctx: sap context + * @spectinfo_param: Pointer to tSapChSelSpectInfo structure + * + * This function calculates the best channel among the configured channel list. + * If channel list not configured then returns the best channel calculated + * among all the channel list. + * + * Return: uint8_t best channel + */ +static +uint8_t sap_select_preferred_channel_from_channel_list(uint8_t best_chnl, + ptSapContext sap_ctx, + tSapChSelSpectInfo *spectinfo_param) +{ + uint8_t i = 0; + + /* + * If Channel List is not Configured don't do anything + * Else return the Best Channel from the Channel List + */ + if ((NULL == sap_ctx->acs_cfg->ch_list) || + (NULL == spectinfo_param) || + (0 == sap_ctx->acs_cfg->ch_list_count)) + return best_chnl; + + if (best_chnl <= 0 || best_chnl > 252) + return SAP_CHANNEL_NOT_SELECTED; + + /* Select the best channel from allowed list */ + for (i = 0; i < sap_ctx->acs_cfg->ch_list_count; i++) { + if (sap_ctx->acs_cfg->ch_list[i] == best_chnl) { + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_INFO_HIGH, + "Best channel is: %d", + best_chnl); + return best_chnl; + } + } + + return SAP_CHANNEL_NOT_SELECTED; +} + +/*========================================================================== + FUNCTION sap_chan_sel_init + + DESCRIPTION + Function sap_chan_sel_init allocates the memory, intializes the + structures used by the channel selection algorithm + + DEPENDENCIES + NA. + + PARAMETERS + + IN + halHandle : Pointer to tHalHandle + *pSpectInfoParams : Pointer to tSapChSelSpectInfo structure + pSapCtx : Pointer to SAP Context + + RETURN VALUE + bool: Success or FAIL + + SIDE EFFECTS + ============================================================================*/ +static bool sap_chan_sel_init(tHalHandle halHandle, + tSapChSelSpectInfo *pSpectInfoParams, + ptSapContext pSapCtx) +{ + tSapSpectChInfo *pSpectCh = NULL; + uint8_t *pChans = NULL; + uint16_t channelnum = 0; + tpAniSirGlobal pMac = PMAC_STRUCT(halHandle); + bool chSafe = true; +#ifdef FEATURE_WLAN_CH_AVOID + uint16_t i; +#endif + uint32_t dfs_master_cap_enabled; + bool include_dfs_ch = true; + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, "In %s", + __func__); + + pSpectInfoParams->numSpectChans = + pMac->scan.base_channels.numChannels; + + /* Allocate memory for weight computation of 2.4GHz */ + pSpectCh = + (tSapSpectChInfo *) qdf_mem_malloc((pSpectInfoParams->numSpectChans) + * sizeof(*pSpectCh)); + + if (pSpectCh == NULL) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "In %s, QDF_MALLOC_ERR", __func__); + return eSAP_FALSE; + } + + /* Initialize the pointers in the DfsParams to the allocated memory */ + pSpectInfoParams->pSpectCh = pSpectCh; + + pChans = pMac->scan.base_channels.channelList; + +#if defined(FEATURE_WLAN_STA_AP_MODE_DFS_DISABLE) + if (pSapCtx->dfs_ch_disable == true) + include_dfs_ch = false; +#endif + sme_cfg_get_int(halHandle, WNI_CFG_DFS_MASTER_ENABLED, + &dfs_master_cap_enabled); + if (dfs_master_cap_enabled == 0 || + ACS_DFS_MODE_DISABLE == pSapCtx->dfs_mode) + include_dfs_ch = false; + + /* Fill the channel number in the spectrum in the operating freq band */ + for (channelnum = 0; + channelnum < pSpectInfoParams->numSpectChans; + channelnum++, pChans++, pSpectCh++) { + chSafe = true; + + /* check if the channel is in NOL blacklist */ + if (sap_dfs_is_channel_in_nol_list(pSapCtx, *pChans, + PHY_SINGLE_CHANNEL_CENTERED)) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + "In %s, Ch %d is in NOL list", __func__, + *pChans); + chSafe = false; + continue; + } + + if (include_dfs_ch == false) { + if (CDS_IS_DFS_CH(*pChans)) { + chSafe = false; + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_INFO_HIGH, + "In %s, DFS Ch %d not considered for ACS", + __func__, *pChans); + continue; + } + } + +#ifdef FEATURE_WLAN_CH_AVOID + for (i = 0; i < NUM_CHANNELS; i++) { + if ((safe_channels[i].channelNumber == *pChans) && + (false == safe_channels[i].isSafe)) { + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_INFO_HIGH, + "In %s, Ch %d is not safe", __func__, + *pChans); + chSafe = false; + break; + } + } +#endif /* FEATURE_WLAN_CH_AVOID */ + + /* OFDM rates are not supported on channel 14 */ + if (*pChans == 14 && + eCSR_DOT11_MODE_11b != pSapCtx->csr_roamProfile.phyMode) { + continue; + } + + /* Skip DSRC channels */ + if (cds_is_dsrc_channel(cds_chan_to_freq(*pChans))) + continue; + + if (true == chSafe) { + pSpectCh->chNum = *pChans; + pSpectCh->valid = eSAP_TRUE; + pSpectCh->rssiAgr = SOFTAP_MIN_RSSI; /* Initialise for all channels */ + pSpectCh->channelWidth = SOFTAP_HT20_CHANNELWIDTH; /* Initialise 20MHz for all the Channels */ + } + } + return eSAP_TRUE; +} + +/*========================================================================== + FUNCTION sapweight_rssi_count + + DESCRIPTION + Function weightRssiCount calculates the channel weight due to rssi + and data count(here number of BSS observed) + + DEPENDENCIES + NA. + + PARAMETERS + + IN + rssi : Max signal strength receieved from a BSS for the channel + count : Number of BSS observed in the channel + + RETURN VALUE + uint32_t : Calculated channel weight based on above two + + SIDE EFFECTS + ============================================================================*/ +static uint32_t sapweight_rssi_count(int8_t rssi, uint16_t count) +{ + int32_t rssiWeight = 0; + int32_t countWeight = 0; + uint32_t rssicountWeight = 0; + + /* Weight from RSSI */ + rssiWeight = SOFTAP_RSSI_WEIGHT * (rssi - SOFTAP_MIN_RSSI) + / (SOFTAP_MAX_RSSI - SOFTAP_MIN_RSSI); + + if (rssiWeight > SOFTAP_RSSI_WEIGHT) + rssiWeight = SOFTAP_RSSI_WEIGHT; + else if (rssiWeight < 0) + rssiWeight = 0; + + /* Weight from data count */ + countWeight = SOFTAP_COUNT_WEIGHT * (count - SOFTAP_MIN_COUNT) + / (SOFTAP_MAX_COUNT - SOFTAP_MIN_COUNT); + + if (countWeight > SOFTAP_COUNT_WEIGHT) + countWeight = SOFTAP_COUNT_WEIGHT; + + rssicountWeight = rssiWeight + countWeight; + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + "In %s, rssiWeight=%d, countWeight=%d, rssicountWeight=%d", + __func__, rssiWeight, countWeight, rssicountWeight); + + return rssicountWeight; +} + +/** + * sap_update_rssi_bsscount() - updates bss count and rssi effect. + * + * @pSpectCh: Channel Information + * @offset: Channel Offset + * @sap_24g: Channel is in 2.4G or 5G + * @spectch_start: the start of spect ch array + * @spectch_end: the end of spect ch array + * + * sap_update_rssi_bsscount updates bss count and rssi effect based + * on the channel offset. + * + * Return: None. + */ + +static void sap_update_rssi_bsscount(tSapSpectChInfo *pSpectCh, int32_t offset, + bool sap_24g, tSapSpectChInfo *spectch_start, + tSapSpectChInfo *spectch_end) +{ + tSapSpectChInfo *pExtSpectCh = NULL; + int32_t rssi, rsssi_effect; + + pExtSpectCh = (pSpectCh + offset); + if (pExtSpectCh != NULL && + pExtSpectCh >= spectch_start && + pExtSpectCh < spectch_end) { + ++pExtSpectCh->bssCount; + switch (offset) { + case -1: + case 1: + rsssi_effect = sap_24g ? + SAP_24GHZ_FIRST_OVERLAP_CHAN_RSSI_EFFECT_PRIMARY : + SAP_SUBBAND1_RSSI_EFFECT_PRIMARY; + break; + case -2: + case 2: + rsssi_effect = sap_24g ? + SAP_24GHZ_SEC_OVERLAP_CHAN_RSSI_EFFECT_PRIMARY : + SAP_SUBBAND2_RSSI_EFFECT_PRIMARY; + break; + case -3: + case 3: + rsssi_effect = sap_24g ? + SAP_24GHZ_THIRD_OVERLAP_CHAN_RSSI_EFFECT_PRIMARY : + SAP_SUBBAND3_RSSI_EFFECT_PRIMARY; + break; + case -4: + case 4: + rsssi_effect = sap_24g ? + SAP_24GHZ_FOURTH_OVERLAP_CHAN_RSSI_EFFECT_PRIMARY : + SAP_SUBBAND4_RSSI_EFFECT_PRIMARY; + break; + case -5: + case 5: + rsssi_effect = SAP_SUBBAND5_RSSI_EFFECT_PRIMARY; + break; + case -6: + case 6: + rsssi_effect = SAP_SUBBAND6_RSSI_EFFECT_PRIMARY; + break; + case -7: + case 7: + rsssi_effect = SAP_SUBBAND7_RSSI_EFFECT_PRIMARY; + break; + default: + rsssi_effect = 0; + break; + } + + rssi = pSpectCh->rssiAgr + rsssi_effect; + if (IS_RSSI_VALID(pExtSpectCh->rssiAgr, rssi)) + pExtSpectCh->rssiAgr = rssi; + if (pExtSpectCh->rssiAgr < SOFTAP_MIN_RSSI) + pExtSpectCh->rssiAgr = SOFTAP_MIN_RSSI; + } +} + +/** + * sap_upd_chan_spec_params() - sap_upd_chan_spec_params + * updates channel parameters obtained from Beacon + * @pBeaconStruct Beacon strucutre populated by parse_beacon function + * @channelWidth Channel width + * @secondaryChannelOffset Secondary Channel Offset + * @vhtSupport If channel supports VHT + * @centerFreq Central frequency for the given channel. + * + * sap_upd_chan_spec_params updates the spectrum channels based on the + * pBeaconStruct obtained from Beacon IE + * + * Return: NA. + */ + +static void sap_upd_chan_spec_params(tSirProbeRespBeacon *pBeaconStruct, + uint16_t *channelWidth, + uint16_t *secondaryChannelOffset, + uint16_t *vhtSupport, + uint16_t *centerFreq, + uint16_t *centerFreq_2) +{ + if (NULL == pBeaconStruct) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("pBeaconStruct is NULL")); + return; + } + + if (pBeaconStruct->HTCaps.present && pBeaconStruct->HTInfo.present) { + *channelWidth = pBeaconStruct->HTCaps.supportedChannelWidthSet; + *secondaryChannelOffset = + pBeaconStruct->HTInfo.secondaryChannelOffset; + if (!pBeaconStruct->VHTOperation.present) + return; + *vhtSupport = pBeaconStruct->VHTOperation.present; + if (pBeaconStruct->VHTOperation.chanWidth) { + *centerFreq = + pBeaconStruct->VHTOperation.chanCenterFreqSeg1; + *centerFreq_2 = + pBeaconStruct->VHTOperation.chanCenterFreqSeg2; + /* + * LHS follows tSirMacHTChannelWidth, while RHS follows + * WNI_CFG_VHT_CHANNEL_WIDTH_X format hence following + * adjustment + */ + *channelWidth = + pBeaconStruct->VHTOperation.chanWidth + 1; + + } + } +} + +/** + * sap_update_rssi_bsscount_vht_5G() - updates bss count and rssi effect. + * + * @spect_ch: Channel Information + * @offset: Channel Offset + * @num_ch: no.of channels + * @spectch_start: the start of spect ch array + * @spectch_end: the end of spect ch array + * + * sap_update_rssi_bsscount_vht_5G updates bss count and rssi effect based + * on the channel offset. + * + * Return: None. + */ + +static void sap_update_rssi_bsscount_vht_5G(tSapSpectChInfo *spect_ch, + int32_t offset, + uint16_t num_ch, + tSapSpectChInfo *spectch_start, + tSapSpectChInfo *spectch_end) +{ + int32_t ch_offset; + uint16_t i, cnt; + + if (!offset) + return; + if (offset > 0) + cnt = num_ch; + else + cnt = num_ch + 1; + for (i = 0; i < cnt; i++) { + ch_offset = offset + i; + if (ch_offset == 0) + continue; + sap_update_rssi_bsscount(spect_ch, ch_offset, false, + spectch_start, spectch_end); + } +} +/** + * sap_interference_rssi_count_5G() - sap_interference_rssi_count + * considers the Adjacent channel rssi and + * data count(here number of BSS observed) + * @spect_ch: Channel Information + * @chan_width: Channel width parsed from beacon IE + * @sec_chan_offset: Secondary Channel Offset + * @center_freq: Central frequency for the given channel. + * @channel_id: channel_id + * @spectch_start: the start of spect ch array + * @spectch_end: the end of spect ch array + * + * sap_interference_rssi_count_5G considers the Adjacent channel rssi + * and data count(here number of BSS observed) + * + * Return: NA. + */ + +static void sap_interference_rssi_count_5G(tSapSpectChInfo *spect_ch, + uint16_t chan_width, + uint16_t sec_chan_offset, + uint16_t center_freq, + uint16_t center_freq_2, + uint8_t channel_id, + tSapSpectChInfo *spectch_start, + tSapSpectChInfo *spectch_end) +{ + uint16_t num_ch; + int32_t offset = 0; + if (NULL == spect_ch) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("spect_ch is NULL")); + return; + } + + /* Updating the received ChannelWidth */ + if (spect_ch->channelWidth != chan_width) + spect_ch->channelWidth = chan_width; + /* If received ChannelWidth is other than HT20, + * we need to update the extension channel Params as well + * chan_width == 0, HT20 + * chan_width == 1, HT40 + * chan_width == 2, VHT80 + * chan_width == 3, VHT160 + */ + + switch (spect_ch->channelWidth) { + case eHT_CHANNEL_WIDTH_40MHZ: /* HT40 */ + switch (sec_chan_offset) { + /* Above the Primary Channel */ + case PHY_DOUBLE_CHANNEL_LOW_PRIMARY: + sap_update_rssi_bsscount(spect_ch, 1, false, + spectch_start, spectch_end); + return; + + /* Below the Primary channel */ + case PHY_DOUBLE_CHANNEL_HIGH_PRIMARY: + sap_update_rssi_bsscount(spect_ch, -1, false, + spectch_start, spectch_end); + return; + } + return; + case eHT_CHANNEL_WIDTH_80MHZ: /* VHT80 */ + num_ch = 3; + if ((center_freq - channel_id) == 6) { + offset = 1; + } else if ((center_freq - channel_id) == 2) { + offset = -1; + } else if ((center_freq - channel_id) == -2) { + offset = -2; + } else if ((center_freq - channel_id) == -6) { + offset = -3; + } + break; + case eHT_CHANNEL_WIDTH_160MHZ: /* VHT160 */ + num_ch = 7; + if ((center_freq - channel_id) == 14) + offset = 1; + else if ((center_freq - channel_id) == 10) + offset = -1; + else if ((center_freq - channel_id) == 6) + offset = -2; + else if ((center_freq - channel_id) == 2) + offset = -3; + else if ((center_freq - channel_id) == -2) + offset = -4; + else if ((center_freq - channel_id) == -6) + offset = -5; + else if ((center_freq - channel_id) == -10) + offset = -6; + else if ((center_freq - channel_id) == -14) + offset = -7; + break; + default: + return; + } + sap_update_rssi_bsscount_vht_5G(spect_ch, offset, num_ch, + spectch_start, spectch_end); +} + +/** + * sap_interference_rssi_count() - sap_interference_rssi_count + * considers the Adjacent channel rssi + * and data count(here number of BSS observed) + * @spect_ch Channel Information + * @spectch_start: the start of spect ch array + * @spectch_end: the end of spect ch array + * + * sap_interference_rssi_count considers the Adjacent channel rssi + * and data count(here number of BSS observed) + * + * Return: None. + */ + +static void sap_interference_rssi_count(tSapSpectChInfo *spect_ch, + tSapSpectChInfo *spectch_start, + tSapSpectChInfo *spectch_end) +{ + if (NULL == spect_ch) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: spect_ch is NULL", __func__); + return; + } + + switch (spect_ch->chNum) { + case CHANNEL_1: + sap_update_rssi_bsscount(spect_ch, 1, true, + spectch_start, spectch_end); + sap_update_rssi_bsscount(spect_ch, 2, true, + spectch_start, spectch_end); + sap_update_rssi_bsscount(spect_ch, 3, true, + spectch_start, spectch_end); + sap_update_rssi_bsscount(spect_ch, 4, true, + spectch_start, spectch_end); + break; + + case CHANNEL_2: + sap_update_rssi_bsscount(spect_ch, -1, true, + spectch_start, spectch_end); + sap_update_rssi_bsscount(spect_ch, 1, true, + spectch_start, spectch_end); + sap_update_rssi_bsscount(spect_ch, 2, true, + spectch_start, spectch_end); + sap_update_rssi_bsscount(spect_ch, 3, true, + spectch_start, spectch_end); + sap_update_rssi_bsscount(spect_ch, 4, true, + spectch_start, spectch_end); + break; + case CHANNEL_3: + sap_update_rssi_bsscount(spect_ch, -2, true, + spectch_start, spectch_end); + sap_update_rssi_bsscount(spect_ch, -1, true, + spectch_start, spectch_end); + sap_update_rssi_bsscount(spect_ch, 1, true, + spectch_start, spectch_end); + sap_update_rssi_bsscount(spect_ch, 2, true, + spectch_start, spectch_end); + sap_update_rssi_bsscount(spect_ch, 3, true, + spectch_start, spectch_end); + sap_update_rssi_bsscount(spect_ch, 4, true, + spectch_start, spectch_end); + break; + case CHANNEL_4: + sap_update_rssi_bsscount(spect_ch, -3, true, + spectch_start, spectch_end); + sap_update_rssi_bsscount(spect_ch, -2, true, + spectch_start, spectch_end); + sap_update_rssi_bsscount(spect_ch, -1, true, + spectch_start, spectch_end); + sap_update_rssi_bsscount(spect_ch, 1, true, + spectch_start, spectch_end); + sap_update_rssi_bsscount(spect_ch, 2, true, + spectch_start, spectch_end); + sap_update_rssi_bsscount(spect_ch, 3, true, + spectch_start, spectch_end); + sap_update_rssi_bsscount(spect_ch, 4, true, + spectch_start, spectch_end); + break; + + case CHANNEL_5: + case CHANNEL_6: + case CHANNEL_7: + case CHANNEL_8: + case CHANNEL_9: + case CHANNEL_10: + sap_update_rssi_bsscount(spect_ch, -4, true, + spectch_start, spectch_end); + sap_update_rssi_bsscount(spect_ch, -3, true, + spectch_start, spectch_end); + sap_update_rssi_bsscount(spect_ch, -2, true, + spectch_start, spectch_end); + sap_update_rssi_bsscount(spect_ch, -1, true, + spectch_start, spectch_end); + sap_update_rssi_bsscount(spect_ch, 1, true, + spectch_start, spectch_end); + sap_update_rssi_bsscount(spect_ch, 2, true, + spectch_start, spectch_end); + sap_update_rssi_bsscount(spect_ch, 3, true, + spectch_start, spectch_end); + sap_update_rssi_bsscount(spect_ch, 4, true, + spectch_start, spectch_end); + break; + + case CHANNEL_11: + sap_update_rssi_bsscount(spect_ch, -4, true, + spectch_start, spectch_end); + sap_update_rssi_bsscount(spect_ch, -3, true, + spectch_start, spectch_end); + sap_update_rssi_bsscount(spect_ch, -2, true, + spectch_start, spectch_end); + sap_update_rssi_bsscount(spect_ch, -1, true, + spectch_start, spectch_end); + sap_update_rssi_bsscount(spect_ch, 1, true, + spectch_start, spectch_end); + sap_update_rssi_bsscount(spect_ch, 2, true, + spectch_start, spectch_end); + sap_update_rssi_bsscount(spect_ch, 3, true, + spectch_start, spectch_end); + break; + + case CHANNEL_12: + sap_update_rssi_bsscount(spect_ch, -4, true, + spectch_start, spectch_end); + sap_update_rssi_bsscount(spect_ch, -3, true, + spectch_start, spectch_end); + sap_update_rssi_bsscount(spect_ch, -2, true, + spectch_start, spectch_end); + sap_update_rssi_bsscount(spect_ch, -1, true, + spectch_start, spectch_end); + sap_update_rssi_bsscount(spect_ch, 1, true, + spectch_start, spectch_end); + sap_update_rssi_bsscount(spect_ch, 2, true, + spectch_start, spectch_end); + break; + + case CHANNEL_13: + sap_update_rssi_bsscount(spect_ch, -4, true, + spectch_start, spectch_end); + sap_update_rssi_bsscount(spect_ch, -3, true, + spectch_start, spectch_end); + sap_update_rssi_bsscount(spect_ch, -2, true, + spectch_start, spectch_end); + sap_update_rssi_bsscount(spect_ch, -1, true, + spectch_start, spectch_end); + sap_update_rssi_bsscount(spect_ch, 1, true, + spectch_start, spectch_end); + break; + + case CHANNEL_14: + sap_update_rssi_bsscount(spect_ch, -4, true, + spectch_start, spectch_end); + sap_update_rssi_bsscount(spect_ch, -3, true, + spectch_start, spectch_end); + sap_update_rssi_bsscount(spect_ch, -2, true, + spectch_start, spectch_end); + sap_update_rssi_bsscount(spect_ch, -1, true, + spectch_start, spectch_end); + break; + + default: + break; + } +} + +/** + * ch_in_pcl() - Is channel in the Preferred Channel List (PCL) + * @sap_ctx: SAP context which contains the current PCL + * @channel: Input channel number to be checked + * + * Check if a channel is in the preferred channel list + * + * Return: + * true: channel is in PCL, + * false: channel is not in PCL + */ +static bool ch_in_pcl(ptSapContext sap_ctx, uint8_t channel) +{ + uint32_t i; + + for (i = 0; i < sap_ctx->acs_cfg->pcl_ch_count; i++) { + if (channel == sap_ctx->acs_cfg->pcl_channels[i]) + return true; + } + + return false; +} + +/** + * sap_compute_spect_weight() - Compute spectrum weight + * @pSpectInfoParams: Pointer to the tSpectInfoParams structure + * @halHandle: Pointer to HAL handle + * @pResult: Pointer to tScanResultHandle + * @sap_ctx: Context of the SAP + * + * Main function for computing the weight of each channel in the + * spectrum based on the RSSI value of the BSSes on the channel + * and number of BSS + */ +static void sap_compute_spect_weight(tSapChSelSpectInfo *pSpectInfoParams, + tHalHandle halHandle, + tScanResultHandle pResult, + ptSapContext sap_ctx) +{ + int8_t rssi = 0; + uint8_t chn_num = 0; + uint8_t channel_id = 0; + + tCsrScanResultInfo *pScanResult; + tSapSpectChInfo *pSpectCh = pSpectInfoParams->pSpectCh; + uint32_t operatingBand; + uint16_t channelWidth; + uint16_t secondaryChannelOffset; + uint16_t centerFreq; + uint16_t centerFreq_2 = 0; + uint16_t vhtSupport; + uint32_t ieLen = 0; + tSirProbeRespBeacon *pBeaconStruct; + tpAniSirGlobal pMac = (tpAniSirGlobal) halHandle; + tSapSpectChInfo *spectch_start = pSpectInfoParams->pSpectCh; + tSapSpectChInfo *spectch_end = pSpectInfoParams->pSpectCh + + pSpectInfoParams->numSpectChans; + + pBeaconStruct = qdf_mem_malloc(sizeof(tSirProbeRespBeacon)); + if (NULL == pBeaconStruct) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + "Unable to allocate memory in sap_compute_spect_weight"); + return; + } + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + "In %s, Computing spectral weight", __func__); + + /** + * Soft AP specific channel weight calculation using DFS formula + */ + SET_ACS_BAND(operatingBand, sap_ctx); + + pScanResult = sme_scan_result_get_first(halHandle, pResult); + + while (pScanResult) { + pSpectCh = pSpectInfoParams->pSpectCh; + /* Defining the default values, so that any value will hold the default values */ + channelWidth = eHT_CHANNEL_WIDTH_20MHZ; + secondaryChannelOffset = PHY_SINGLE_CHANNEL_CENTERED; + vhtSupport = 0; + centerFreq = 0; + + + ieLen = GET_IE_LEN_IN_BSS( + pScanResult->BssDescriptor.length); + qdf_mem_set((uint8_t *) pBeaconStruct, + sizeof(tSirProbeRespBeacon), 0); + + + if ((sir_parse_beacon_ie + (pMac, pBeaconStruct, (uint8_t *) + (pScanResult->BssDescriptor.ieFields), + ieLen)) == eSIR_SUCCESS) + sap_upd_chan_spec_params( + pBeaconStruct, + &channelWidth, + &secondaryChannelOffset, + &vhtSupport, ¢erFreq, + ¢erFreq_2); + + /* Processing for each tCsrScanResultInfo in the tCsrScanResult DLink list */ + for (chn_num = 0; chn_num < pSpectInfoParams->numSpectChans; + chn_num++) { + + /* + * if the Beacon has channel ID, use it other wise we will + * rely on the channelIdSelf + */ + if (pScanResult->BssDescriptor.channelId == 0) + channel_id = + pScanResult->BssDescriptor.channelIdSelf; + else + channel_id = + pScanResult->BssDescriptor.channelId; + + if (pSpectCh && (channel_id == pSpectCh->chNum)) { + if (pSpectCh->rssiAgr < + pScanResult->BssDescriptor.rssi) + pSpectCh->rssiAgr = + pScanResult->BssDescriptor.rssi; + + ++pSpectCh->bssCount; /* Increment the count of BSS */ + + /* + * Connsidering the Extension Channel + * only in a channels + */ + switch (operatingBand) { + case eCSR_DOT11_MODE_11a: + sap_interference_rssi_count_5G( + pSpectCh, channelWidth, + secondaryChannelOffset, + centerFreq, + centerFreq_2, + channel_id, + spectch_start, + spectch_end); + break; + + case eCSR_DOT11_MODE_11g: + sap_interference_rssi_count(pSpectCh, + spectch_start, spectch_end); + break; + + case eCSR_DOT11_MODE_abg: + sap_interference_rssi_count_5G( + pSpectCh, channelWidth, + secondaryChannelOffset, + centerFreq, + centerFreq_2, + channel_id, + spectch_start, + spectch_end); + sap_interference_rssi_count(pSpectCh, + spectch_start, spectch_end); + break; + } + + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_INFO_HIGH, + "In %s, bssdes.ch_self=%d, bssdes.ch_ID=%d, bssdes.rssi=%d, SpectCh.bssCount=%d, pScanResult=%p, ChannelWidth %d, secondaryChanOffset %d, center frequency %d", + __func__, + pScanResult->BssDescriptor. + channelIdSelf, + pScanResult->BssDescriptor.channelId, + pScanResult->BssDescriptor.rssi, + pSpectCh->bssCount, pScanResult, + pSpectCh->channelWidth, + secondaryChannelOffset, centerFreq); + pSpectCh++; + break; + } else { + pSpectCh++; + } + } + + pScanResult = sme_scan_result_get_next(halHandle, pResult); + } + + /* Calculate the weights for all channels in the spectrum pSpectCh */ + pSpectCh = pSpectInfoParams->pSpectCh; + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + "In %s, Spectrum Channels Weight", __func__); + + for (chn_num = 0; chn_num < (pSpectInfoParams->numSpectChans); + chn_num++) { + + /* + rssi : Maximum received signal strength among all BSS on that channel + bssCount : Number of BSS on that channel + */ + + rssi = (int8_t) pSpectCh->rssiAgr; + if (ch_in_pcl(sap_ctx, chn_num)) + rssi -= PCL_RSSI_DISCOUNT; + + pSpectCh->weight = + SAPDFS_NORMALISE_1000 * sapweight_rssi_count(rssi, + pSpectCh-> + bssCount); + pSpectCh->weight_copy = pSpectCh->weight; + + /* ------ Debug Info ------ */ + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + "In %s, Chan=%d Weight= %d rssiAgr=%d bssCount=%d", + __func__, pSpectCh->chNum, pSpectCh->weight, + pSpectCh->rssiAgr, pSpectCh->bssCount); + /* ------ Debug Info ------ */ + pSpectCh++; + } + qdf_mem_free(pBeaconStruct); +} + +/*========================================================================== + FUNCTION sap_chan_sel_exit + + DESCRIPTION + Exit function for free out the allocated memory, to be called + at the end of the dfsSelectChannel function + + DEPENDENCIES + NA. + + PARAMETERS + + IN + pSpectInfoParams : Pointer to the tSapChSelSpectInfo structure + + RETURN VALUE + void : NULL + + SIDE EFFECTS + ============================================================================*/ +static void sap_chan_sel_exit(tSapChSelSpectInfo *pSpectInfoParams) +{ + /* Free all the allocated memory */ + qdf_mem_free(pSpectInfoParams->pSpectCh); +} + +/*========================================================================== + FUNCTION sap_sort_chl_weight + + DESCRIPTION + Funtion to sort the channels with the least weight first for 20MHz channels + + DEPENDENCIES + NA. + + PARAMETERS + + IN + pSpectInfoParams : Pointer to the tSapChSelSpectInfo structure + + RETURN VALUE + void : NULL + + SIDE EFFECTS + ============================================================================*/ +static void sap_sort_chl_weight(tSapChSelSpectInfo *pSpectInfoParams) +{ + tSapSpectChInfo temp; + + tSapSpectChInfo *pSpectCh = NULL; + uint32_t i = 0, j = 0, minWeightIndex = 0; + + pSpectCh = pSpectInfoParams->pSpectCh; + for (i = 0; i < pSpectInfoParams->numSpectChans; i++) { + minWeightIndex = i; + for (j = i + 1; j < pSpectInfoParams->numSpectChans; j++) { + if (pSpectCh[j].weight < + pSpectCh[minWeightIndex].weight) { + minWeightIndex = j; + } + } + if (minWeightIndex != i) { + qdf_mem_copy(&temp, &pSpectCh[minWeightIndex], + sizeof(*pSpectCh)); + qdf_mem_copy(&pSpectCh[minWeightIndex], &pSpectCh[i], + sizeof(*pSpectCh)); + qdf_mem_copy(&pSpectCh[i], &temp, sizeof(*pSpectCh)); + } + } +} + +/** + * set_ht80_chl_bit() - to set availabe channel to ht80 channel bitmap + * @channel_bitmap: Pointer to the chan_bonding_bitmap structure + * @spect_info_params: Pointer to the tSapChSelSpectInfo structure + * + * Return: none + */ +static void set_ht80_chl_bit(chan_bonding_bitmap *channel_bitmap, + tSapChSelSpectInfo *spec_info_params) +{ + uint8_t i, j; + tSapSpectChInfo *spec_info; + int start_channel = 0; + channel_bitmap->chanBondingSet[0].startChannel = + acs_ht80_channels[0].chStartNum; + channel_bitmap->chanBondingSet[1].startChannel = + acs_ht80_channels[1].chStartNum; + channel_bitmap->chanBondingSet[2].startChannel = + acs_ht80_channels[2].chStartNum; + channel_bitmap->chanBondingSet[3].startChannel = + acs_ht80_channels[3].chStartNum; + channel_bitmap->chanBondingSet[4].startChannel = + acs_ht80_channels[4].chStartNum; + channel_bitmap->chanBondingSet[5].startChannel = + acs_ht80_channels[5].chStartNum; + + spec_info = spec_info_params->pSpectCh; + for (j = 0; j < spec_info_params->numSpectChans; j++) { + for (i = 0; i < MAX_80MHZ_BANDS; i++) { + start_channel = + channel_bitmap->chanBondingSet[i].startChannel; + if (spec_info[j].chNum >= start_channel && + (spec_info[j].chNum <= + start_channel + 12)) { + channel_bitmap->chanBondingSet[i].channelMap |= + 1 << ((spec_info[j].chNum - + start_channel)/4); + break; + } + } + } +} + +/** + * sap_sort_chl_weight_ht80() - to sort the channels with the least weight + * @pSpectInfoParams: Pointer to the tSapChSelSpectInfo structure + * + * Funtion to sort the channels with the least weight first for HT80 channels + * + * Return: none + */ +static void sap_sort_chl_weight_ht80(tSapChSelSpectInfo *pSpectInfoParams) +{ + uint8_t i, j, n; + tSapSpectChInfo *pSpectInfo; + uint8_t minIdx; + int start_channel = 0; + chan_bonding_bitmap *channel_bitmap; + + channel_bitmap = qdf_mem_malloc(sizeof(chan_bonding_bitmap)); + if (NULL == channel_bitmap) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: Failed to allocate memory", __func__); + return; + } + pSpectInfo = pSpectInfoParams->pSpectCh; + /* for each HT80 channel, calculate the combined weight of the + four 20MHz weight */ + for (i = 0; i < ARRAY_SIZE(acs_ht80_channels); i++) { + for (j = 0; j < pSpectInfoParams->numSpectChans; j++) { + if (pSpectInfo[j].chNum == + acs_ht80_channels[i].chStartNum) + break; + } + if (j == pSpectInfoParams->numSpectChans) + continue; + + if (!(((pSpectInfo[j].chNum + 4) == pSpectInfo[j + 1].chNum) && + ((pSpectInfo[j].chNum + 8) == + pSpectInfo[j + 2].chNum) && + ((pSpectInfo[j].chNum + 12) == + pSpectInfo[j + 3].chNum))) { + /* + * some channels does not exist in pSectInfo array, + * skip this channel and those in the same HT80 width + */ + pSpectInfo[j].weight = SAP_ACS_WEIGHT_MAX * 4; + if ((pSpectInfo[j].chNum + 4) == + pSpectInfo[j + 1].chNum) + pSpectInfo[j + 1].weight = + SAP_ACS_WEIGHT_MAX * 4; + if ((pSpectInfo[j].chNum + 8) == + pSpectInfo[j + 2].chNum) + pSpectInfo[j + 2].weight = + SAP_ACS_WEIGHT_MAX * 4; + if ((pSpectInfo[j].chNum + 12) == + pSpectInfo[j + 3].chNum) + pSpectInfo[j + 3].weight = + SAP_ACS_WEIGHT_MAX * 4; + continue; + } + /*found the channel, add the 4 adjacent channels' weight */ + acs_ht80_channels[i].weight = pSpectInfo[j].weight + + pSpectInfo[j + 1].weight + pSpectInfo[j + 2].weight + + pSpectInfo[j + 3].weight; + /* find best channel among 4 channels as the primary channel */ + if ((pSpectInfo[j].weight + pSpectInfo[j + 1].weight) < + (pSpectInfo[j + 2].weight + pSpectInfo[j + 3].weight)) { + /* lower 2 channels are better choice */ + if (pSpectInfo[j].weight < pSpectInfo[j + 1].weight) + minIdx = 0; + else + minIdx = 1; + } else if (pSpectInfo[j + 2].weight <= + pSpectInfo[j + 3].weight) { + /* upper 2 channels are better choice */ + minIdx = 2; + } else { + minIdx = 3; + } + + /* + * set all 4 channels to max value first, then reset the + * best channel as the selected primary channel, update its + * weightage with the combined weight value + */ + for (n = 0; n < 4; n++) + pSpectInfo[j + n].weight = SAP_ACS_WEIGHT_MAX * 4; + + pSpectInfo[j + minIdx].weight = acs_ht80_channels[i].weight; + } + + /* + * mark the weight of the channel that can't satisfy 80MHZ + * as max value, so that it will be sorted to the bottom + */ + set_ht80_chl_bit(channel_bitmap, pSpectInfoParams); + for (j = 0; j < pSpectInfoParams->numSpectChans; j++) { + for (i = 0; i < MAX_80MHZ_BANDS; i++) { + start_channel = + channel_bitmap->chanBondingSet[i].startChannel; + if (pSpectInfo[j].chNum >= start_channel && + (pSpectInfo[j].chNum <= + start_channel + 12) && + channel_bitmap->chanBondingSet[i].channelMap != + SAP_80MHZ_MASK) + pSpectInfo[j].weight = SAP_ACS_WEIGHT_MAX * 4; + } + } + + pSpectInfo = pSpectInfoParams->pSpectCh; + for (j = 0; j < pSpectInfoParams->numSpectChans; j++) { + if (CHANNEL_165 == pSpectInfo[j].chNum) { + pSpectInfo[j].weight = SAP_ACS_WEIGHT_MAX * 4; + break; + } + } + + sap_sort_chl_weight(pSpectInfoParams); + + pSpectInfo = pSpectInfoParams->pSpectCh; + for (j = 0; j < (pSpectInfoParams->numSpectChans); j++) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + FL("Channel=%d Weight= %d rssi=%d bssCount=%d"), + pSpectInfo->chNum, pSpectInfo->weight, + pSpectInfo->rssiAgr, pSpectInfo->bssCount); + pSpectInfo++; + } + qdf_mem_free(channel_bitmap); +} + +/** + * sap_sort_chl_weight_vht160() - to sort the channels with the least weight + * @pSpectInfoParams: Pointer to the tSapChSelSpectInfo structure + * + * Funtion to sort the channels with the least weight first for VHT160 channels + * + * Return: none + */ +static void sap_sort_chl_weight_vht160(tSapChSelSpectInfo *pSpectInfoParams) +{ + uint8_t i, j, n, idx; + tSapSpectChInfo *pSpectInfo; + uint8_t minIdx; + + pSpectInfo = pSpectInfoParams->pSpectCh; + /* for each VHT160 channel, calculate the combined weight of the + 8 20MHz weight */ + for (i = 0; i < ARRAY_SIZE(acs_vht160_channels); i++) { + for (j = 0; j < pSpectInfoParams->numSpectChans; j++) { + if (pSpectInfo[j].chNum == + acs_vht160_channels[i].chStartNum) + break; + } + if (j == pSpectInfoParams->numSpectChans) + continue; + + if (!(((pSpectInfo[j].chNum + 4) == pSpectInfo[j + 1].chNum) && + ((pSpectInfo[j].chNum + 8) == + pSpectInfo[j + 2].chNum) && + ((pSpectInfo[j].chNum + 12) == + pSpectInfo[j + 3].chNum) && + ((pSpectInfo[j].chNum + 16) == + pSpectInfo[j + 4].chNum) && + ((pSpectInfo[j].chNum + 20) == + pSpectInfo[j + 5].chNum) && + ((pSpectInfo[j].chNum + 24) == + pSpectInfo[j + 6].chNum) && + ((pSpectInfo[j].chNum + 28) == + pSpectInfo[j + 7].chNum))) { + /* + * some channels does not exist in pSectInfo array, + * skip this channel and those in the same VHT160 width + */ + pSpectInfo[j].weight = SAP_ACS_WEIGHT_MAX * 8; + if ((pSpectInfo[j].chNum + 4) == + pSpectInfo[j + 1].chNum) + pSpectInfo[j + 1].weight = + SAP_ACS_WEIGHT_MAX * 8; + if ((pSpectInfo[j].chNum + 8) == + pSpectInfo[j + 2].chNum) + pSpectInfo[j + 2].weight = + SAP_ACS_WEIGHT_MAX * 8; + if ((pSpectInfo[j].chNum + 12) == + pSpectInfo[j + 3].chNum) + pSpectInfo[j + 3].weight = + SAP_ACS_WEIGHT_MAX * 8; + if ((pSpectInfo[j].chNum + 16) == + pSpectInfo[j + 4].chNum) + pSpectInfo[j + 4].weight = + SAP_ACS_WEIGHT_MAX * 8; + if ((pSpectInfo[j].chNum + 20) == + pSpectInfo[j + 5].chNum) + pSpectInfo[j + 5].weight = + SAP_ACS_WEIGHT_MAX * 8; + if ((pSpectInfo[j].chNum + 24) == + pSpectInfo[j + 6].chNum) + pSpectInfo[j + 6].weight = + SAP_ACS_WEIGHT_MAX * 8; + if ((pSpectInfo[j].chNum + 28) == + pSpectInfo[j + 7].chNum) + pSpectInfo[j + 7].weight = + SAP_ACS_WEIGHT_MAX * 8; + continue; + } + /*found the channel, add the 7 adjacent channels' weight */ + acs_vht160_channels[i].weight = pSpectInfo[j].weight + + pSpectInfo[j + 1].weight + pSpectInfo[j + 2].weight + + pSpectInfo[j + 3].weight + pSpectInfo[j + 4].weight + + pSpectInfo[j + 5].weight + pSpectInfo[j + 6].weight + + pSpectInfo[j + 7].weight; + + /* find best channel among 8 channels as the primary channel */ + if ((pSpectInfo[j].weight + pSpectInfo[j + 1].weight + + pSpectInfo[j + 2].weight + pSpectInfo[j + 3].weight) > + (pSpectInfo[j + 4].weight + pSpectInfo[j + 5].weight + + pSpectInfo[j + 6].weight + pSpectInfo[j + 7].weight)) + idx = 4; + else + idx = 0; + /* find best channel among 4 channels as the primary channel */ + if ((pSpectInfo[j + idx].weight + + pSpectInfo[j + idx + 1].weight) < + (pSpectInfo[j + idx + 2].weight + + pSpectInfo[j + idx + 3].weight)) { + /* lower 2 channels are better choice */ + if (pSpectInfo[j + idx].weight < + pSpectInfo[j + idx + 1].weight) + minIdx = 0 + idx; + else + minIdx = 1 + idx; + } else if (pSpectInfo[j + idx + 2].weight <= + pSpectInfo[j + idx + 3].weight) { + /* upper 2 channels are better choice */ + minIdx = 2 + idx; + } else { + minIdx = 3 + idx; + } + + /* + * set all 8 channels to max value first, then reset the + * best channel as the selected primary channel, update its + * weightage with the combined weight value + */ + for (n = 0; n < 8; n++) + pSpectInfo[j + n].weight = SAP_ACS_WEIGHT_MAX * 8; + + pSpectInfo[j + minIdx].weight = acs_vht160_channels[i].weight; + } + + pSpectInfo = pSpectInfoParams->pSpectCh; + for (j = 0; j < pSpectInfoParams->numSpectChans; j++) { + if (CHANNEL_165 == pSpectInfo[j].chNum) { + pSpectInfo[j].weight = SAP_ACS_WEIGHT_MAX * 8; + break; + } + } + + sap_sort_chl_weight(pSpectInfoParams); + + pSpectInfo = pSpectInfoParams->pSpectCh; + for (j = 0; j < (pSpectInfoParams->numSpectChans); j++) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + FL("Channel=%d Weight= %d rssi=%d bssCount=%d"), + pSpectInfo->chNum, pSpectInfo->weight, + pSpectInfo->rssiAgr, pSpectInfo->bssCount); + pSpectInfo++; + } +} + +/** + * sap_sort_chl_weight_ht40_24_g() - to sort channel with the least weight + * @pSpectInfoParams: Pointer to the tSapChSelSpectInfo structure + * + * Funtion to sort the channels with the least weight first for HT40 channels + * + * Return: none + */ +static void sap_sort_chl_weight_ht40_24_g(tSapChSelSpectInfo *pSpectInfoParams) +{ + uint8_t i, j; + tSapSpectChInfo *pSpectInfo; + uint32_t tmpWeight1, tmpWeight2; + uint32_t ht40plus2gendch = 0; + + pSpectInfo = pSpectInfoParams->pSpectCh; + /* + * for each HT40 channel, calculate the combined weight of the + * two 20MHz weight + */ + for (i = 0; i < ARRAY_SIZE(acs_ht40_channels24_g); i++) { + for (j = 0; j < pSpectInfoParams->numSpectChans; j++) { + if (pSpectInfo[j].chNum == + acs_ht40_channels24_g[i].chStartNum) + break; + } + if (j == pSpectInfoParams->numSpectChans) + continue; + + if (!((pSpectInfo[j].chNum + 4) == pSpectInfo[j + 4].chNum)) { + pSpectInfo[j].weight = SAP_ACS_WEIGHT_MAX * 2; + continue; + } + /* + * check if there is another channel combination possiblity + * e.g., {1, 5} & {5, 9} + */ + if ((pSpectInfo[j + 4].chNum + 4) == pSpectInfo[j + 8].chNum) { + /* need to compare two channel pairs */ + tmpWeight1 = pSpectInfo[j].weight + + pSpectInfo[j + 4].weight; + tmpWeight2 = pSpectInfo[j + 4].weight + + pSpectInfo[j + 8].weight; + if (tmpWeight1 <= tmpWeight2) { + if (pSpectInfo[j].weight <= + pSpectInfo[j + 4].weight) { + pSpectInfo[j].weight = + tmpWeight1; + pSpectInfo[j + 4].weight = + SAP_ACS_WEIGHT_MAX * 2; + pSpectInfo[j + 8].weight = + SAP_ACS_WEIGHT_MAX * 2; + } else { + pSpectInfo[j + 4].weight = + tmpWeight1; + /* for secondary channel selection */ + pSpectInfo[j].weight = + SAP_ACS_WEIGHT_MAX * 2 + - 1; + pSpectInfo[j + 8].weight = + SAP_ACS_WEIGHT_MAX * 2; + } + } else { + if (pSpectInfo[j + 4].weight <= + pSpectInfo[j + 8].weight) { + pSpectInfo[j + 4].weight = + tmpWeight2; + pSpectInfo[j].weight = + SAP_ACS_WEIGHT_MAX * 2; + /* for secondary channel selection */ + pSpectInfo[j + 8].weight = + SAP_ACS_WEIGHT_MAX * 2 + - 1; + } else { + pSpectInfo[j + 8].weight = + tmpWeight2; + pSpectInfo[j].weight = + SAP_ACS_WEIGHT_MAX * 2; + pSpectInfo[j + 4].weight = + SAP_ACS_WEIGHT_MAX * 2; + } + } + } else { + tmpWeight1 = pSpectInfo[j].weight + + pSpectInfo[j + 4].weight; + if (pSpectInfo[j].weight <= + pSpectInfo[j + 4].weight) { + pSpectInfo[j].weight = tmpWeight1; + pSpectInfo[j + 4].weight = + SAP_ACS_WEIGHT_MAX * 2; + } else { + pSpectInfo[j + 4].weight = tmpWeight1; + pSpectInfo[j].weight = + SAP_ACS_WEIGHT_MAX * 2; + } + } + } + /* + * Every channel should be checked. Add the check for the omissive + * channel. Mark the channel whose combination can't satisfy 40MHZ + * as max value, so that it will be sorted to the bottom. + */ + if (cds_is_fcc_regdomain()) + ht40plus2gendch = HT40PLUS_2G_FCC_CH_END; + else + ht40plus2gendch = HT40PLUS_2G_EURJAP_CH_END; + for (i = HT40MINUS_2G_CH_START; i <= ht40plus2gendch; i++) { + for (j = 0; j < pSpectInfoParams->numSpectChans; j++) { + if (pSpectInfo[j].chNum == i && + ((pSpectInfo[j].chNum + 4) != + pSpectInfo[j+4].chNum) && + ((pSpectInfo[j].chNum - 4) != + pSpectInfo[j-4].chNum)) + pSpectInfo[j].weight = SAP_ACS_WEIGHT_MAX * 2; + } + } + for (i = ht40plus2gendch + 1; i <= HT40MINUS_2G_CH_END; i++) { + for (j = 0; j < pSpectInfoParams->numSpectChans; j++) { + if (pSpectInfo[j].chNum == i && + (pSpectInfo[j].chNum - 4) != + pSpectInfo[j-4].chNum) + pSpectInfo[j].weight = SAP_ACS_WEIGHT_MAX * 2; + } + } + sap_sort_chl_weight(pSpectInfoParams); +} + +/*========================================================================== + FUNCTION sap_sort_chl_weight_ht40_5_g + + DESCRIPTION + Funtion to sort the channels with the least weight first for HT40 channels + + DEPENDENCIES + NA. + + PARAMETERS + + IN + pSpectInfoParams : Pointer to the tSapChSelSpectInfo structure + + RETURN VALUE + void : NULL + + SIDE EFFECTS + ============================================================================*/ +static void sap_sort_chl_weight_ht40_5_g(tSapChSelSpectInfo *pSpectInfoParams) +{ + uint8_t i, j; + tSapSpectChInfo *pSpectInfo; + + pSpectInfo = pSpectInfoParams->pSpectCh; + /*for each HT40 channel, calculate the combined weight of the + two 20MHz weight */ + for (i = 0; i < ARRAY_SIZE(acs_ht40_channels5_g); i++) { + for (j = 0; j < pSpectInfoParams->numSpectChans; j++) { + if (pSpectInfo[j].chNum == + acs_ht40_channels5_g[i].chStartNum) + break; + } + if (j == pSpectInfoParams->numSpectChans) + continue; + + /* found the channel, add the two adjacent channels' weight */ + if ((pSpectInfo[j].chNum + 4) == pSpectInfo[j + 1].chNum) { + acs_ht40_channels5_g[i].weight = pSpectInfo[j].weight + + pSpectInfo[j + 1].weight; + /* select better of the adjact channel as the primary channel */ + if (pSpectInfo[j].weight <= pSpectInfo[j + 1].weight) { + pSpectInfo[j].weight = + acs_ht40_channels5_g[i].weight; + /* mark the adjacent channel's weight as max value so + that it will be sorted to the bottom */ + pSpectInfo[j + 1].weight = + SAP_ACS_WEIGHT_MAX * 2; + } else { + pSpectInfo[j + 1].weight = + acs_ht40_channels5_g[i].weight; + /* mark the adjacent channel's weight as max value so + that it will be sorted to the bottom */ + pSpectInfo[j].weight = SAP_ACS_WEIGHT_MAX * 2; + } + + } else + pSpectInfo[j].weight = SAP_ACS_WEIGHT_MAX * 2; + } + + /* + *Every channel should be checked. Add the check for the omissive + * channel. Mark the channel whose combination can't satisfy 40MHZ + * as max value, so that it will be sorted to the bottom + */ + for (j = 1; j < pSpectInfoParams->numSpectChans; j++) { + for (i = 0; i < ARRAY_SIZE(acs_ht40_channels5_g); i++) { + if (pSpectInfo[j].chNum == + (acs_ht40_channels5_g[i].chStartNum + 4) && + pSpectInfo[j-1].chNum != + acs_ht40_channels5_g[i].chStartNum) { + pSpectInfo[j].weight = SAP_ACS_WEIGHT_MAX * 2; + break; + } + } + } + /* avoid channel 165 by setting its weight to max */ + pSpectInfo = pSpectInfoParams->pSpectCh; + for (j = 0; j < pSpectInfoParams->numSpectChans; j++) { + if (CHANNEL_165 == pSpectInfo[j].chNum) { + pSpectInfo[j].weight = SAP_ACS_WEIGHT_MAX * 2; + break; + } + } + + pSpectInfo = pSpectInfoParams->pSpectCh; + for (j = 0; j < (pSpectInfoParams->numSpectChans); j++) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + "In %s, Channel=%d Weight= %d rssi=%d bssCount=%d", + __func__, pSpectInfo->chNum, pSpectInfo->weight, + pSpectInfo->rssiAgr, pSpectInfo->bssCount); + pSpectInfo++; + } + + sap_sort_chl_weight(pSpectInfoParams); +} + +/*========================================================================== + FUNCTION sap_sort_chl_weight_all + + DESCRIPTION + Funtion to sort the channels with the least weight first + + DEPENDENCIES + NA. + + PARAMETERS + + IN + ptSapContext : Pointer to the ptSapContext structure + pSpectInfoParams : Pointer to the tSapChSelSpectInfo structure + + RETURN VALUE + void : NULL + + SIDE EFFECTS + ============================================================================*/ +static void sap_sort_chl_weight_all(ptSapContext pSapCtx, + tSapChSelSpectInfo *pSpectInfoParams, + uint32_t operatingBand) +{ + tSapSpectChInfo *pSpectCh = NULL; + uint32_t j = 0; +#ifndef SOFTAP_CHANNEL_RANGE + uint32_t i = 0; +#endif + + pSpectCh = pSpectInfoParams->pSpectCh; +#ifdef SOFTAP_CHANNEL_RANGE + + switch (pSapCtx->acs_cfg->ch_width) { + case CH_WIDTH_40MHZ: + if (eCSR_DOT11_MODE_11g == operatingBand) + sap_sort_chl_weight_ht40_24_g(pSpectInfoParams); + else if (eCSR_DOT11_MODE_11a == operatingBand) + sap_sort_chl_weight_ht40_5_g(pSpectInfoParams); + else { + sap_sort_chl_weight_ht40_24_g(pSpectInfoParams); + sap_sort_chl_weight_ht40_5_g(pSpectInfoParams); + } + break; + case CH_WIDTH_80MHZ: + case CH_WIDTH_80P80MHZ: + sap_sort_chl_weight_ht80(pSpectInfoParams); + break; + case CH_WIDTH_160MHZ: + sap_sort_chl_weight_vht160(pSpectInfoParams); + break; + case CH_WIDTH_20MHZ: + default: + /* Sorting the channels as per weights as 20MHz channels */ + sap_sort_chl_weight(pSpectInfoParams); + } + +#else + /* Sorting the channels as per weights */ + for (i = 0; i < SPECT_24GHZ_CH_COUNT; i++) { + minWeightIndex = i; + for (j = i + 1; j < SPECT_24GHZ_CH_COUNT; j++) { + if (pSpectCh[j].weight < + pSpectCh[minWeightIndex].weight) { + minWeightIndex = j; + } + } + if (minWeightIndex != i) { + qdf_mem_copy(&temp, &pSpectCh[minWeightIndex], + sizeof(*pSpectCh)); + qdf_mem_copy(&pSpectCh[minWeightIndex], &pSpectCh[i], + sizeof(*pSpectCh)); + qdf_mem_copy(&pSpectCh[i], &temp, sizeof(*pSpectCh)); + } + } +#endif + + /* For testing */ + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + "In %s, Sorted Spectrum Channels Weight", __func__); + pSpectCh = pSpectInfoParams->pSpectCh; + for (j = 0; j < (pSpectInfoParams->numSpectChans); j++) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + "In %s, Channel=%d Weight= %d rssi=%d bssCount=%d", + __func__, pSpectCh->chNum, pSpectCh->weight, + pSpectCh->rssiAgr, pSpectCh->bssCount); + pSpectCh++; + } + +} + +/*========================================================================== + FUNCTION sap_filter_over_lap_ch + + DESCRIPTION + return true if ch is acceptable. + This function will decide if we will filter over lap channel or not. + + DEPENDENCIES + shall called after ap start. + + PARAMETERS + + IN + pSapCtx : Pointer to ptSapContext. + chNum : Filter channel number. + + RETURN VALUE + bool : true if channel is accepted. + + SIDE EFFECTS + ============================================================================*/ +static bool sap_filter_over_lap_ch(ptSapContext pSapCtx, uint16_t chNum) +{ + if (pSapCtx->enableOverLapCh) + return eSAP_TRUE; + else if ((chNum == CHANNEL_1) || + (chNum == CHANNEL_6) || (chNum == CHANNEL_11)) + return eSAP_TRUE; + + return eSAP_FALSE; +} + +#ifdef FEATURE_WLAN_CH_AVOID +/** + * sap_select_channel_no_scan_result() - select SAP channel when no scan results + * are available. + * @sap_ctx: Sap context + * + * Returns: channel number if success, 0 otherwise + */ +static uint8_t sap_select_channel_no_scan_result(tHalHandle hal, + ptSapContext sap_ctx) +{ + enum channel_state ch_type; + uint8_t i, first_safe_ch_in_range = SAP_CHANNEL_NOT_SELECTED; + uint32_t dfs_master_cap_enabled; + uint32_t start_ch_num = sap_ctx->acs_cfg->start_ch; + uint32_t end_ch_num = sap_ctx->acs_cfg->end_ch; + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + FL("start - end: %d - %d"), start_ch_num, end_ch_num); + + sme_cfg_get_int(hal, WNI_CFG_DFS_MASTER_ENABLED, + &dfs_master_cap_enabled); + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: dfs_master %x", __func__, dfs_master_cap_enabled); + + /* get a channel in PCL and within the range */ + for (i = 0; i < sap_ctx->acs_cfg->pcl_ch_count; i++) { + if ((sap_ctx->acs_cfg->pcl_channels[i] < start_ch_num) || + (sap_ctx->acs_cfg->pcl_channels[i] > end_ch_num)) + continue; + + first_safe_ch_in_range = sap_ctx->acs_cfg->pcl_channels[i]; + break; + } + + if (SAP_CHANNEL_NOT_SELECTED != first_safe_ch_in_range) + return first_safe_ch_in_range; + + for (i = 0; i < NUM_CHANNELS; i++) { + if ((safe_channels[i].channelNumber < start_ch_num) || + (safe_channels[i].channelNumber > end_ch_num)) + continue; + + ch_type = cds_get_channel_state(safe_channels[i].channelNumber); + + if ((ch_type == CHANNEL_STATE_DISABLE) || + (ch_type == CHANNEL_STATE_INVALID)) + continue; + if ((!dfs_master_cap_enabled) && + (CHANNEL_STATE_DFS == ch_type)) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: DFS master mode disabled. Skip DFS channel %d", + __func__, safe_channels[i].channelNumber); + continue; + } + if ((sap_ctx->dfs_mode == ACS_DFS_MODE_DISABLE) && + (CHANNEL_STATE_DFS == ch_type)) + continue; + + if (safe_channels[i].isSafe == true) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + FL("channel %d in the configuration is safe"), + safe_channels[i].channelNumber); + first_safe_ch_in_range = safe_channels[i].channelNumber; + break; + } + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + FL("channel %d in the configuration is unsafe"), + safe_channels[i].channelNumber); + } + + /* if no channel selected return SAP_CHANNEL_NOT_SELECTED */ + return first_safe_ch_in_range; +} +#else +static uint8_t sap_select_channel_no_scan_result(tHalHandle hal, + ptSapContext sap_ctx) +{ + uint32_t start_ch_num = sap_ctx->acs_cfg->start_ch; + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + FL("start - end: %d - %d"), + start_ch_num, + sap_ctx->acs_cfg->end_ch); + + sap_ctx->acs_cfg->pri_ch = start_ch_num; + sap_ctx->acs_cfg->ht_sec_ch = 0; + + /* pick the first channel in configured range */ + return start_ch_num; +} +#endif /* FEATURE_WLAN_CH_AVOID */ + +/** + * sap_select_channel() - select SAP channel + * @hal: Pointer to HAL handle + * @sap_ctx: Sap context + * @scan_result: Pointer to tScanResultHandle + * + * Runs a algorithm to select the best channel to operate in based on BSS + * rssi and bss count on each channel + * + * Returns: channel number if success, 0 otherwise + */ +uint8_t sap_select_channel(tHalHandle hal, ptSapContext sap_ctx, + tScanResultHandle scan_result) +{ + /* DFS param object holding all the data req by the algo */ + tSapChSelSpectInfo spect_info_obj = { NULL, 0 }; + tSapChSelSpectInfo *spect_info = &spect_info_obj; + uint8_t best_ch_num = SAP_CHANNEL_NOT_SELECTED; + uint32_t ht40plus2gendch = 0; +#ifdef SOFTAP_CHANNEL_RANGE + uint8_t count; + uint32_t start_ch_num, end_ch_num, tmp_ch_num, operating_band = 0; +#endif + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + "In %s, Running SAP Ch Select", __func__); + +#ifdef FEATURE_WLAN_CH_AVOID + sap_update_unsafe_channel_list(sap_ctx); +#endif + + if (NULL == scan_result) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + FL("No external AP present")); + +#ifndef SOFTAP_CHANNEL_RANGE + return SAP_CHANNEL_NOT_SELECTED; +#else + return sap_select_channel_no_scan_result(hal, sap_ctx); +#endif + } + + /* Initialize the structure pointed by spect_info */ + if (sap_chan_sel_init(hal, spect_info, sap_ctx) != eSAP_TRUE) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("Ch Select initialization failed")); + return SAP_CHANNEL_NOT_SELECTED; + } + /* Compute the weight of the entire spectrum in the operating band */ + sap_compute_spect_weight(spect_info, hal, scan_result, sap_ctx); + +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE + /* process avoid channel IE to collect all channels to avoid */ + sap_process_avoid_ie(hal, sap_ctx, scan_result, spect_info); +#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ + +#ifdef SOFTAP_CHANNEL_RANGE + start_ch_num = sap_ctx->acs_cfg->start_ch; + end_ch_num = sap_ctx->acs_cfg->end_ch; + SET_ACS_BAND(operating_band, sap_ctx); + + sap_ctx->acsBestChannelInfo.channelNum = 0; + sap_ctx->acsBestChannelInfo.weight = SAP_ACS_WEIGHT_MAX; + + /* Sort the ch lst as per the computed weights, lesser weight first. */ + sap_sort_chl_weight_all(sap_ctx, spect_info, operating_band); + + /*Loop till get the best channel in the given range */ + for (count = 0; count < spect_info->numSpectChans; count++) { + if ((start_ch_num > spect_info->pSpectCh[count].chNum) || + (end_ch_num < spect_info->pSpectCh[count].chNum)) + continue; + + if (best_ch_num == SAP_CHANNEL_NOT_SELECTED) { + best_ch_num = spect_info->pSpectCh[count].chNum; + /* check if best_ch_num is in preferred channel list */ + best_ch_num = + sap_select_preferred_channel_from_channel_list( + best_ch_num, sap_ctx, spect_info); + /* if not in preferred ch lst, go to nxt best ch */ + if (best_ch_num == SAP_CHANNEL_NOT_SELECTED) + continue; + +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE + /* + * Weight of the channels(device's AP is operating) + * increased to MAX+1 so that they will be choosen only + * when there is no other best channel to choose + */ + if (sap_check_in_avoid_ch_list(sap_ctx, best_ch_num)) { + best_ch_num = SAP_CHANNEL_NOT_SELECTED; + continue; + } +#endif + + sap_ctx->acsBestChannelInfo.channelNum = best_ch_num; + sap_ctx->acsBestChannelInfo.weight = + spect_info->pSpectCh[count].weight_copy; + } + + if (best_ch_num == SAP_CHANNEL_NOT_SELECTED) + continue; + + if (operating_band != eCSR_DOT11_MODE_11g) + continue; + + /* Give preference to Non-overlap channels */ + if (false == sap_filter_over_lap_ch(sap_ctx, + spect_info->pSpectCh[count].chNum)) + continue; + + tmp_ch_num = spect_info->pSpectCh[count].chNum; + tmp_ch_num = sap_select_preferred_channel_from_channel_list( + tmp_ch_num, sap_ctx, spect_info); + if (tmp_ch_num == SAP_CHANNEL_NOT_SELECTED) + continue; + + best_ch_num = tmp_ch_num; + break; + } +#else + /* Sort the ch lst as per the computed weights, lesser weight first. */ + sap_sort_chl_weight_all(sap_ctx, hal, spect_info); + /* Get the first channel in sorted array as best 20M Channel */ + best_ch_num = (uint8_t) spect_info->pSpectCh[0].chNum; + /* Select Best Channel from Channel List if Configured */ + best_ch_num = sap_select_preferred_channel_from_channel_list( + best_ch_num, sap_ctx, spect_info); +#endif + + /* + * in case the best channel seleted is not in PCL and there is another + * channel which has same weightage and is in PCL, choose the one in + * PCL + */ + for (count = 0; count < spect_info->numSpectChans; count++) { + if (!ch_in_pcl(sap_ctx, spect_info->pSpectCh[count].chNum) || + (spect_info->pSpectCh[count].weight != + sap_ctx->acsBestChannelInfo.weight)) + continue; + + if (sap_select_preferred_channel_from_channel_list( + spect_info->pSpectCh[count].chNum, sap_ctx, spect_info) + == SAP_CHANNEL_NOT_SELECTED) + continue; + +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE + if (sap_check_in_avoid_ch_list(sap_ctx, best_ch_num)) + continue; +#endif + best_ch_num = spect_info->pSpectCh[count].chNum; + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + FL("change best channel to %d in PCL"), best_ch_num); + break; + } + + sap_ctx->acs_cfg->pri_ch = best_ch_num; + /* determine secondary channel for 2.4G channel 5, 6, 7 in HT40 */ + if ((operating_band != eCSR_DOT11_MODE_11g) || + (sap_ctx->acs_cfg->ch_width != CH_WIDTH_40MHZ)) + goto sap_ch_sel_end; + + if (cds_is_fcc_regdomain()) + ht40plus2gendch = HT40PLUS_2G_FCC_CH_END; + else + ht40plus2gendch = HT40PLUS_2G_EURJAP_CH_END; + if ((best_ch_num >= HT40MINUS_2G_CH_START) && + (best_ch_num <= ht40plus2gendch)) { + int weight_below, weight_above, i; + tSapSpectChInfo *pspect_info; + + weight_below = weight_above = SAP_ACS_WEIGHT_MAX; + pspect_info = spect_info->pSpectCh; + for (i = 0; i < spect_info->numSpectChans; i++) { + if (pspect_info[i].chNum == (best_ch_num - 4)) + weight_below = pspect_info[i].weight; + if (pspect_info[i].chNum == (best_ch_num + 4)) + weight_above = pspect_info[i].weight; + } + + if (weight_below < weight_above) + sap_ctx->acs_cfg->ht_sec_ch = + sap_ctx->acs_cfg->pri_ch - 4; + else + sap_ctx->acs_cfg->ht_sec_ch = + sap_ctx->acs_cfg->pri_ch + 4; + } else if (best_ch_num >= 1 && best_ch_num <= 4) { + sap_ctx->acs_cfg->ht_sec_ch = sap_ctx->acs_cfg->pri_ch + 4; + } else if (best_ch_num > ht40plus2gendch && best_ch_num <= HT40MINUS_2G_CH_END) { + sap_ctx->acs_cfg->ht_sec_ch = sap_ctx->acs_cfg->pri_ch - 4; + } else if (best_ch_num == 14) { + sap_ctx->acs_cfg->ht_sec_ch = 0; + } + sap_ctx->secondary_ch = sap_ctx->acs_cfg->ht_sec_ch; + +sap_ch_sel_end: + /* Free all the allocated memory */ + sap_chan_sel_exit(spect_info); + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + FL("Running SAP Ch select Completed, Ch=%d"), best_ch_num); + if (best_ch_num > 0 && best_ch_num <= 252) + return best_ch_num; + else + return SAP_CHANNEL_NOT_SELECTED; +} diff --git a/drivers/staging/qcacld-3.0/core/sap/src/sap_ch_select.h b/drivers/staging/qcacld-3.0/core/sap/src/sap_ch_select.h new file mode 100644 index 0000000000000000000000000000000000000000..8fe2d1738c6ed1bbbeebfbdaca07a83149ff2f1a --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/sap/src/sap_ch_select.h @@ -0,0 +1,198 @@ +/* + * Copyright (c) 2012-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#if !defined(__SAP_CH_SELECT_H) +#define __SAP_CH_SELECT_H + +/*=========================================================================== + + sapChSelect.h + + OVERVIEW: + + This software unit holds the implementation of the WLAN SAP modules + functions for channel selection. + + DEPENDENCIES: + + Are listed for each API below. + ===========================================================================*/ + +/*-------------------------------------------------------------------------- + Include Files + ------------------------------------------------------------------------*/ +#include "ani_global.h" +/*-------------------------------------------------------------------------- + defines and enum + --------------------------------------------------------------------------*/ + +#define SPECT_24GHZ_CH_COUNT (11) /* USA regulatory domain */ +#define SAPDFS_NORMALISE_1000 (1000/9) /* Case of spec20 with channel diff = 0 */ +/* Gen 5 values + #define SOFTAP_MIN_RSSI (-85) + #define SOFTAP_MAX_RSSI (-45) + */ +#define SOFTAP_MIN_RSSI (-100) +#define SOFTAP_MAX_RSSI (0) +#define SOFTAP_MIN_COUNT (0) +#define SOFTAP_MAX_COUNT (60) +#define SOFTAP_RSSI_WEIGHT (20) +#define SOFTAP_COUNT_WEIGHT (20) + +#define SAP_DEFAULT_24GHZ_CHANNEL (6) +#define SAP_DEFAULT_5GHZ_CHANNEL (40) +#define SAP_CHANNEL_NOT_SELECTED (0) + +#define SOFTAP_HT20_CHANNELWIDTH 0 +/* In HT40/VHT80, Effect of primary Channel RSSi on Subband1 */ +#define SAP_SUBBAND1_RSSI_EFFECT_PRIMARY (-20) +/* In VHT80, Effect of primary Channel RSSI on Subband2 */ +#define SAP_SUBBAND2_RSSI_EFFECT_PRIMARY (-30) +/* In VHT80, Effect of Primary Channel RSSI on Subband3 */ +#define SAP_SUBBAND3_RSSI_EFFECT_PRIMARY (-40) +/* In VHT80, Effect of Primary Channel RSSI on Subband4 */ +#define SAP_SUBBAND4_RSSI_EFFECT_PRIMARY (-50) +/* In VHT80, Effect of Primary Channel RSSI on Subband5 */ +#define SAP_SUBBAND5_RSSI_EFFECT_PRIMARY (-60) +/* In VHT80, Effect of Primary Channel RSSI on Subband6 */ +#define SAP_SUBBAND6_RSSI_EFFECT_PRIMARY (-70) +/* In VHT80, Effect of Primary Channel RSSI on Subband7 */ +#define SAP_SUBBAND7_RSSI_EFFECT_PRIMARY (-80) + +#define SAP_24GHZ_FIRST_OVERLAP_CHAN_RSSI_EFFECT_PRIMARY (-10) /* In 2.4GHZ, Effect of Primary Channel RSSI on First Overlapping Channel */ +#define SAP_24GHZ_SEC_OVERLAP_CHAN_RSSI_EFFECT_PRIMARY (-20) /* In 2.4GHZ, Effect of Primary Channel RSSI on Second Overlapping Channel */ +#define SAP_24GHZ_THIRD_OVERLAP_CHAN_RSSI_EFFECT_PRIMARY (-30) /* In 2.4GHZ, Effect of Primary Channel RSSI on Third Overlapping Channel */ +#define SAP_24GHZ_FOURTH_OVERLAP_CHAN_RSSI_EFFECT_PRIMARY (-40) /* In 2.4GHZ, Effect of Primary Channel RSSI on Fourth Overlapping Channel */ + +typedef enum { + CHANNEL_1 = 1, + CHANNEL_2, + CHANNEL_3, + CHANNEL_4, + CHANNEL_5, + CHANNEL_6, + CHANNEL_7, + CHANNEL_8, + CHANNEL_9, + CHANNEL_10, + CHANNEL_11, + CHANNEL_12, + CHANNEL_13, + CHANNEL_14 +} tSapChannel; + +#define MAX_80MHZ_BANDS 6 +#define SAP_80MHZ_MASK 0x0F +#define SAP_40MHZ_MASK_L 0x03 +#define SAP_40MHZ_MASK_H 0x0C + +/* + * structs for holding channel bonding bitmap + * used for finding new channel when SAP is on + * DFS channel and radar is detected. + */ +typedef struct sChannelBondingInfo { + uint8_t channelMap:4; + uint8_t rsvd:4; + uint8_t startChannel; +} tChannelBondingInfo; + +typedef struct __chan_bonding_bitmap { + tChannelBondingInfo chanBondingSet[MAX_80MHZ_BANDS]; +} chan_bonding_bitmap; + +/** + * Structure holding information of each channel in the spectrum, + * it contains the channel number, the computed weight + */ +typedef struct sChannelInfo { + uint8_t channel; + bool valid; /* if the channel is valid to be picked as new channel */ +} tChannelInfo; + +typedef struct sAll5GChannelList { + uint8_t numChannel; + tChannelInfo *channelList; +} tAll5GChannelList; + +typedef struct sSapChannelListInfo { + uint8_t numChannel; + uint8_t *channelList; +} tSapChannelListInfo; + +typedef struct { + uint16_t chNum; /* Channel Number */ + uint16_t channelWidth; /* Channel Width */ + uint16_t bssCount; /* bss found in scanresult for this channel */ + int32_t rssiAgr; /* Max value of rssi among all BSS(es) from scanresult for this channel */ + uint32_t weight; /* Weightage of this channel */ + uint32_t weight_copy; /* copy of the orignal weight */ + bool valid; /* Is this a valid center frequency for regulatory domain */ +} tSapSpectChInfo; /* tDfsSpectChInfo; */ + +/** + * Structure holding all the information required to make a + * decision for the best operating channel based on dfs formula + */ + +typedef struct { + tSapSpectChInfo *pSpectCh; /* tDfsSpectChInfo *pSpectCh; // Ptr to the channels in the entire spectrum band */ + uint8_t numSpectChans; /* Total num of channels in the spectrum */ +} tSapChSelSpectInfo; /* tDfsChSelParams; */ + +/** + * Structure for channel weight calculation parameters + */ +typedef struct sSapChSelParams { + void *pSpectInfoParams; /**pDfsParams; // Filled with tSapChSelSpectInfo */ + uint16_t numChannels; +} tSapChSelParams; + +#define SAP_TX_LEAKAGE_THRES 310 +#define SAP_TX_LEAKAGE_MAX 1000 +#define SAP_TX_LEAKAGE_MIN 200 + +/* + * This define is used to block additional channels + * based on the new data gathered on auto platforms + * and to differentiate the leakage data among different + * platforms. + */ + +#define SAP_TX_LEAKAGE_AUTO_MIN 210 + +typedef struct sSapTxLeakInfo { + uint8_t leak_chan; /* leak channel */ + uint32_t leak_lvl; /* tx leakage lvl */ +} tSapTxLeakInfo; + +typedef struct sSapChanMatrixInfo { + uint8_t channel; /* channel to switch from */ + tSapTxLeakInfo chan_matrix[CHAN_ENUM_144 - CHAN_ENUM_36 + 1]; +} tSapChanMatrixInfo; + +#endif /* if !defined __SAP_CH_SELECT_H */ diff --git a/drivers/staging/qcacld-3.0/core/sap/src/sap_fsm.c b/drivers/staging/qcacld-3.0/core/sap/src/sap_fsm.c new file mode 100644 index 0000000000000000000000000000000000000000..74d2b30900aff5abf7479effd6a74b3a084d6a7f --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/sap/src/sap_fsm.c @@ -0,0 +1,5245 @@ +/* + * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/*=========================================================================== + + s a p F s m . C + + OVERVIEW: + + This software unit holds the implementation of the WLAN SAP Finite + State Machine modules + + DEPENDENCIES: + + Are listed for each API below. + ===========================================================================*/ + +/*---------------------------------------------------------------------------- + * Include Files + * -------------------------------------------------------------------------*/ +#include "sap_internal.h" +/* Pick up the SME API definitions */ +#include "sme_api.h" +/* Pick up the PMC API definitions */ +#include "cds_utils.h" +#include "cds_ieee80211_common_i.h" +#include "cds_reg_service.h" +#include "qdf_util.h" +#include "cds_concurrency.h" + +/*---------------------------------------------------------------------------- + * Preprocessor Definitions and Constants + * -------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------- + * Type Declarations + * -------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------- + * Global Data Definitions + * -------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------- + * External declarations for global context + * -------------------------------------------------------------------------*/ +#ifdef FEATURE_WLAN_CH_AVOID +extern sapSafeChannelType safe_channels[]; +#endif /* FEATURE_WLAN_CH_AVOID */ + +/*---------------------------------------------------------------------------- + * Static Variable Definitions + * -------------------------------------------------------------------------*/ + +#ifdef WLAN_ENABLE_CHNL_MATRIX_RESTRICTION +/* + * TODO: At present SAP Channel leakage matrix for ch 144 + * is not available from system's team. So to play it safe + * and avoid crash if channel 144 is request, in following + * matix channel 144 is added such that it will cause code + * to avoid selecting channel 144. + * + * THESE ENTRIES SHOULD BE REPLACED WITH CORRECT VALUES AS + * PROVIDED BY SYSTEM'S TEAM. + */ + +/* channel tx leakage table - ht80 */ +tSapChanMatrixInfo ht80_chan[] = { + {52, + {{36, 148}, {40, 199}, + {44, 193}, {48, 197}, + {52, SAP_TX_LEAKAGE_MIN}, {56, 153}, + {60, 137}, {64, 134}, + {100, 358}, {104, 350}, + {108, 404}, {112, 344}, + {116, 424}, {120, 429}, + {124, 437}, {128, 435}, + {132, SAP_TX_LEAKAGE_MAX}, {136, SAP_TX_LEAKAGE_MAX}, + {140, SAP_TX_LEAKAGE_MAX}, + {144, SAP_TX_LEAKAGE_MIN} + } }, + + + {56, + {{36, 171}, {40, 178}, + {44, 171}, {48, 178}, + {52, SAP_TX_LEAKAGE_MIN}, {56, SAP_TX_LEAKAGE_MIN}, + {60, SAP_TX_LEAKAGE_MIN}, {64, 280}, + {100, 351}, {104, 376}, + {108, 362}, {112, 362}, + {116, 403}, {120, 397}, + {124, SAP_TX_LEAKAGE_MAX}, {128, SAP_TX_LEAKAGE_MAX}, + {132, SAP_TX_LEAKAGE_MAX}, {136, SAP_TX_LEAKAGE_MAX}, + {140, SAP_TX_LEAKAGE_MAX}, + {144, SAP_TX_LEAKAGE_MIN} + } }, + + {60, + {{36, 156}, {40, 146}, + {44, SAP_TX_LEAKAGE_MIN}, {48, SAP_TX_LEAKAGE_MIN}, + {52, 180}, {56, SAP_TX_LEAKAGE_MIN}, + {60, SAP_TX_LEAKAGE_MIN}, {64, SAP_TX_LEAKAGE_MIN}, + {100, 376}, {104, 360}, + {108, SAP_TX_LEAKAGE_MAX}, {112, SAP_TX_LEAKAGE_MAX}, + {116, 395}, {120, 399}, + {124, SAP_TX_LEAKAGE_MAX}, {128, SAP_TX_LEAKAGE_MAX}, + {132, SAP_TX_LEAKAGE_MAX}, {136, SAP_TX_LEAKAGE_MAX}, + {140, SAP_TX_LEAKAGE_MAX}, + {144, SAP_TX_LEAKAGE_MIN} + } }, + + {64, + {{36, 217}, {40, 221}, + {44, SAP_TX_LEAKAGE_MIN}, {48, SAP_TX_LEAKAGE_MIN}, + {52, 176}, {56, 176}, + {60, SAP_TX_LEAKAGE_MIN}, {64, SAP_TX_LEAKAGE_MIN}, + {100, 384}, {104, 390}, + {108, SAP_TX_LEAKAGE_MAX}, {112, SAP_TX_LEAKAGE_MAX}, + {116, 375}, {120, 374}, + {124, SAP_TX_LEAKAGE_MAX}, {128, SAP_TX_LEAKAGE_MAX}, + {132, SAP_TX_LEAKAGE_MAX}, {136, SAP_TX_LEAKAGE_MAX}, + {140, SAP_TX_LEAKAGE_MAX}, + {144, SAP_TX_LEAKAGE_MIN} + } }, + + {100, + {{36, 357}, {40, 326}, + {44, 321}, {48, 326}, + {52, 378}, {56, 396}, + {60, SAP_TX_LEAKAGE_MAX}, {64, SAP_TX_LEAKAGE_MAX}, + {100, SAP_TX_LEAKAGE_MIN}, {104, SAP_TX_LEAKAGE_MIN}, + {108, 196}, {112, 116}, + {116, 166}, {120, SAP_TX_LEAKAGE_MIN}, + {124, SAP_TX_LEAKAGE_MIN}, {128, SAP_TX_LEAKAGE_MIN}, + {132, SAP_TX_LEAKAGE_MIN}, {136, SAP_TX_LEAKAGE_MIN}, + {140, SAP_TX_LEAKAGE_MIN}, + {144, SAP_TX_LEAKAGE_MIN} + } }, + + {104, + {{36, 325}, {40, 325}, + {44, 305}, {48, 352}, + {52, 411}, {56, 411}, + {60, SAP_TX_LEAKAGE_MAX}, {64, SAP_TX_LEAKAGE_MAX}, + {100, SAP_TX_LEAKAGE_MIN}, {104, SAP_TX_LEAKAGE_MIN}, + {108, SAP_TX_LEAKAGE_MIN}, {112, 460}, + {116, 198}, {120, SAP_TX_LEAKAGE_MIN}, + {124, SAP_TX_LEAKAGE_MIN}, {128, SAP_TX_LEAKAGE_MIN}, + {132, SAP_TX_LEAKAGE_MIN}, {136, SAP_TX_LEAKAGE_MIN}, + {140, SAP_TX_LEAKAGE_MIN}, + {144, SAP_TX_LEAKAGE_MIN} + } }, + + {108, + {{36, 304}, {40, 332}, + {44, 310}, {48, 335}, + {52, 431}, {56, 391}, + {60, SAP_TX_LEAKAGE_MAX}, {64, SAP_TX_LEAKAGE_MAX}, + {100, 280}, {104, SAP_TX_LEAKAGE_MIN}, + {108, SAP_TX_LEAKAGE_MIN}, {112, SAP_TX_LEAKAGE_MIN}, + {116, 185}, {120, SAP_TX_LEAKAGE_MIN}, + {124, SAP_TX_LEAKAGE_MIN}, {128, SAP_TX_LEAKAGE_MIN}, + {132, SAP_TX_LEAKAGE_MIN}, {136, SAP_TX_LEAKAGE_MIN}, + {140, SAP_TX_LEAKAGE_MIN}, + {144, SAP_TX_LEAKAGE_MIN} + } }, + + {112, + {{36, 327}, {40, 335}, + {44, 331}, {48, 345}, + {52, 367}, {56, 401}, + {60, SAP_TX_LEAKAGE_MAX}, {64, SAP_TX_LEAKAGE_MAX}, + {100, 131}, {104, 132}, + {108, SAP_TX_LEAKAGE_MIN}, {112, SAP_TX_LEAKAGE_MIN}, + {116, 189}, {120, SAP_TX_LEAKAGE_MIN}, + {124, SAP_TX_LEAKAGE_MIN}, {128, SAP_TX_LEAKAGE_MIN}, + {132, SAP_TX_LEAKAGE_MIN}, {136, SAP_TX_LEAKAGE_MIN}, + {140, SAP_TX_LEAKAGE_MIN}, + {144, SAP_TX_LEAKAGE_MIN} + } }, + + {116, + {{36, 384}, {40, 372}, + {44, 389}, {48, 396}, + {52, 348}, {56, 336}, + {60, SAP_TX_LEAKAGE_MAX}, {64, SAP_TX_LEAKAGE_MAX}, + {100, 172}, {104, 169}, + {108, SAP_TX_LEAKAGE_MIN}, {112, SAP_TX_LEAKAGE_MIN}, + {116, SAP_TX_LEAKAGE_MIN}, {120, SAP_TX_LEAKAGE_MIN}, + {124, SAP_TX_LEAKAGE_MIN}, {128, SAP_TX_LEAKAGE_MIN}, + {132, SAP_TX_LEAKAGE_MIN}, {136, SAP_TX_LEAKAGE_MIN}, + {140, SAP_TX_LEAKAGE_MIN}, + {144, SAP_TX_LEAKAGE_MIN} + } }, + + {120, + {{36, 395}, {40, 419}, + {44, 439}, {48, 407}, + {52, 321}, {56, 334}, + {60, SAP_TX_LEAKAGE_MAX}, {64, SAP_TX_LEAKAGE_MAX}, + {100, 134}, {104, 186}, + {108, SAP_TX_LEAKAGE_MIN}, {112, SAP_TX_LEAKAGE_MIN}, + {116, SAP_TX_LEAKAGE_MIN}, {120, SAP_TX_LEAKAGE_MIN}, + {124, SAP_TX_LEAKAGE_MIN}, {128, 159}, + {132, SAP_TX_LEAKAGE_MIN}, {136, SAP_TX_LEAKAGE_MIN}, + {140, SAP_TX_LEAKAGE_MIN}, + {144, SAP_TX_LEAKAGE_MIN} + } }, + + {124, + {{36, 469}, {40, 433}, + {44, 434}, {48, 435}, + {52, 332}, {56, 345}, + {60, SAP_TX_LEAKAGE_MAX}, {64, SAP_TX_LEAKAGE_MAX}, + {100, 146}, {104, 177}, + {108, SAP_TX_LEAKAGE_MIN}, {112, SAP_TX_LEAKAGE_MIN}, + {116, 350}, {120, SAP_TX_LEAKAGE_MIN}, + {124, SAP_TX_LEAKAGE_MIN}, {128, 138}, + {132, SAP_TX_LEAKAGE_MIN}, {136, SAP_TX_LEAKAGE_MIN}, + {140, SAP_TX_LEAKAGE_MIN}, + {144, SAP_TX_LEAKAGE_MIN} + } }, + + {128, + {{36, 408}, {40, 434}, + {44, 449}, {48, 444}, + {52, 341}, {56, 374}, + {60, SAP_TX_LEAKAGE_MAX}, {64, SAP_TX_LEAKAGE_MAX}, + {100, 205}, {104, 208}, + {108, SAP_TX_LEAKAGE_MIN}, {112, SAP_TX_LEAKAGE_MIN}, + {116, 142}, {120, SAP_TX_LEAKAGE_MIN}, + {124, SAP_TX_LEAKAGE_MIN}, {128, SAP_TX_LEAKAGE_MIN}, + {132, SAP_TX_LEAKAGE_MIN}, {136, SAP_TX_LEAKAGE_MIN}, + {140, SAP_TX_LEAKAGE_MIN}, + {144, SAP_TX_LEAKAGE_MIN} + } }, + + {132, + {{36, SAP_TX_LEAKAGE_MAX}, {40, SAP_TX_LEAKAGE_MAX}, + {44, SAP_TX_LEAKAGE_MAX}, {48, SAP_TX_LEAKAGE_MAX}, + {52, SAP_TX_LEAKAGE_MAX}, {56, SAP_TX_LEAKAGE_MAX}, + {60, SAP_TX_LEAKAGE_MIN}, {64, SAP_TX_LEAKAGE_MIN}, + {100, SAP_TX_LEAKAGE_MIN}, {104, SAP_TX_LEAKAGE_MIN}, + {108, SAP_TX_LEAKAGE_MIN}, {112, SAP_TX_LEAKAGE_MIN}, + {116, SAP_TX_LEAKAGE_MIN}, {120, SAP_TX_LEAKAGE_MIN}, + {124, SAP_TX_LEAKAGE_MIN}, {128, SAP_TX_LEAKAGE_MIN}, + {132, SAP_TX_LEAKAGE_MIN}, {136, SAP_TX_LEAKAGE_MIN}, + {140, SAP_TX_LEAKAGE_MIN}, + {144, SAP_TX_LEAKAGE_MIN} + } }, + + {136, + {{36, SAP_TX_LEAKAGE_MAX}, {40, SAP_TX_LEAKAGE_MAX}, + {44, SAP_TX_LEAKAGE_MAX}, {48, SAP_TX_LEAKAGE_MAX}, + {52, SAP_TX_LEAKAGE_MAX}, {56, SAP_TX_LEAKAGE_MAX}, + {60, SAP_TX_LEAKAGE_MIN}, {64, SAP_TX_LEAKAGE_MIN}, + {100, SAP_TX_LEAKAGE_MIN}, {104, SAP_TX_LEAKAGE_MIN}, + {108, SAP_TX_LEAKAGE_MIN}, {112, SAP_TX_LEAKAGE_MIN}, + {116, SAP_TX_LEAKAGE_MIN}, {120, SAP_TX_LEAKAGE_MIN}, + {124, SAP_TX_LEAKAGE_MIN}, {128, SAP_TX_LEAKAGE_MIN}, + {132, SAP_TX_LEAKAGE_MIN}, {136, SAP_TX_LEAKAGE_MIN}, + {140, SAP_TX_LEAKAGE_MIN}, + {144, SAP_TX_LEAKAGE_MIN} + } }, + + {140, + {{36, SAP_TX_LEAKAGE_MAX}, {40, SAP_TX_LEAKAGE_MAX}, + {44, SAP_TX_LEAKAGE_MAX}, {48, SAP_TX_LEAKAGE_MAX}, + {52, SAP_TX_LEAKAGE_MAX}, {56, SAP_TX_LEAKAGE_MAX}, + {60, SAP_TX_LEAKAGE_MIN}, {64, SAP_TX_LEAKAGE_MIN}, + {100, SAP_TX_LEAKAGE_MIN}, {104, SAP_TX_LEAKAGE_MIN}, + {108, SAP_TX_LEAKAGE_MIN}, {112, SAP_TX_LEAKAGE_MIN}, + {116, SAP_TX_LEAKAGE_MIN}, {120, SAP_TX_LEAKAGE_MIN}, + {124, SAP_TX_LEAKAGE_MIN}, {128, SAP_TX_LEAKAGE_MIN}, + {132, SAP_TX_LEAKAGE_MIN}, {136, SAP_TX_LEAKAGE_MIN}, + {144, SAP_TX_LEAKAGE_MIN} + } }, + + {144, + {{36, SAP_TX_LEAKAGE_MAX}, {40, SAP_TX_LEAKAGE_MAX}, + {44, SAP_TX_LEAKAGE_MAX}, {48, SAP_TX_LEAKAGE_MAX}, + {52, SAP_TX_LEAKAGE_MAX}, {56, SAP_TX_LEAKAGE_MAX}, + {60, SAP_TX_LEAKAGE_MIN}, {64, SAP_TX_LEAKAGE_MIN}, + {100, SAP_TX_LEAKAGE_MIN}, {104, SAP_TX_LEAKAGE_MIN}, + {108, SAP_TX_LEAKAGE_MIN}, {112, SAP_TX_LEAKAGE_MIN}, + {116, SAP_TX_LEAKAGE_MIN}, {120, SAP_TX_LEAKAGE_MIN}, + {124, SAP_TX_LEAKAGE_MIN}, {128, SAP_TX_LEAKAGE_MIN}, + {132, SAP_TX_LEAKAGE_MIN}, {136, SAP_TX_LEAKAGE_MIN}, + {144, SAP_TX_LEAKAGE_MIN} + } }, +}; + +/* channel tx leakage table - ht40 */ +tSapChanMatrixInfo ht40_chan[] = { + {52, + {{36, SAP_TX_LEAKAGE_AUTO_MIN}, {40, SAP_TX_LEAKAGE_AUTO_MIN}, + {44, 230}, {48, 230}, + {52, SAP_TX_LEAKAGE_MIN}, {56, SAP_TX_LEAKAGE_MIN}, + {60, SAP_TX_LEAKAGE_AUTO_MIN}, {64, SAP_TX_LEAKAGE_AUTO_MIN}, + {100, 625}, {104, 323}, + {108, 646}, {112, 646}, + {116, SAP_TX_LEAKAGE_MAX}, {120, SAP_TX_LEAKAGE_MAX}, + {124, SAP_TX_LEAKAGE_MAX}, {128, SAP_TX_LEAKAGE_MAX}, + {132, SAP_TX_LEAKAGE_MAX}, {136, SAP_TX_LEAKAGE_MAX}, + {140, SAP_TX_LEAKAGE_MAX}, + {144, SAP_TX_LEAKAGE_MIN} + } }, + + {56, + {{36, SAP_TX_LEAKAGE_AUTO_MIN}, {40, SAP_TX_LEAKAGE_AUTO_MIN}, + {44, SAP_TX_LEAKAGE_AUTO_MIN}, {48, SAP_TX_LEAKAGE_AUTO_MIN}, + {52, SAP_TX_LEAKAGE_MIN}, {56, SAP_TX_LEAKAGE_MIN}, + {60, SAP_TX_LEAKAGE_MIN}, {64, SAP_TX_LEAKAGE_MIN}, + {100, 611}, {104, 611}, + {108, 617}, {112, 617}, + {116, SAP_TX_LEAKAGE_MAX}, {120, SAP_TX_LEAKAGE_MAX}, + {124, SAP_TX_LEAKAGE_MAX}, {128, SAP_TX_LEAKAGE_MAX}, + {132, SAP_TX_LEAKAGE_MAX}, {136, SAP_TX_LEAKAGE_MAX}, + {140, SAP_TX_LEAKAGE_MAX}, + {144, SAP_TX_LEAKAGE_MIN} + } }, + + {60, + {{36, SAP_TX_LEAKAGE_AUTO_MIN}, {40, SAP_TX_LEAKAGE_AUTO_MIN}, + {44, SAP_TX_LEAKAGE_AUTO_MIN}, {48, SAP_TX_LEAKAGE_AUTO_MIN}, + {52, 190}, {56, 190}, + {60, SAP_TX_LEAKAGE_MIN}, {64, SAP_TX_LEAKAGE_MIN}, + {100, 608}, {104, 608}, + {108, 623}, {112, 623}, + {116, SAP_TX_LEAKAGE_MAX}, {120, SAP_TX_LEAKAGE_MAX}, + {124, SAP_TX_LEAKAGE_MAX}, {128, SAP_TX_LEAKAGE_MAX}, + {132, SAP_TX_LEAKAGE_MAX}, {136, SAP_TX_LEAKAGE_MAX}, + {140, SAP_TX_LEAKAGE_MAX}, + {144, SAP_TX_LEAKAGE_MIN} + } }, + + {64, + {{36, SAP_TX_LEAKAGE_AUTO_MIN}, {40, SAP_TX_LEAKAGE_AUTO_MIN}, + {44, SAP_TX_LEAKAGE_AUTO_MIN}, {48, SAP_TX_LEAKAGE_AUTO_MIN}, + {52, 295}, {56, 295}, + {60, SAP_TX_LEAKAGE_MIN}, {64, SAP_TX_LEAKAGE_MIN}, + {100, 594}, {104, 594}, + {108, 625}, {112, 625}, + {116, SAP_TX_LEAKAGE_MAX}, {120, SAP_TX_LEAKAGE_MAX}, + {124, SAP_TX_LEAKAGE_MAX}, {128, SAP_TX_LEAKAGE_MAX}, + {132, SAP_TX_LEAKAGE_MAX}, {136, SAP_TX_LEAKAGE_MAX}, + {140, SAP_TX_LEAKAGE_MAX}, + {144, SAP_TX_LEAKAGE_MIN} + } }, + + {100, + {{36, 618}, {40, 618}, + {44, 604}, {48, 604}, + {52, 596}, {56, 596}, + {60, 584}, {64, 584}, + {100, SAP_TX_LEAKAGE_MIN}, {104, SAP_TX_LEAKAGE_MIN}, + {108, 299}, {112, 299}, + {116, SAP_TX_LEAKAGE_AUTO_MIN}, {120, SAP_TX_LEAKAGE_AUTO_MIN}, + {124, SAP_TX_LEAKAGE_AUTO_MIN}, {128, SAP_TX_LEAKAGE_AUTO_MIN}, + {132, 538}, {136, 538}, + {140, 598}, + {144, SAP_TX_LEAKAGE_MIN} + } }, + + {104, + {{36, 636}, {40, 636}, + {44, 601}, {48, 601}, + {52, 616}, {56, 616}, + {60, 584}, {64, 584}, + {100, SAP_TX_LEAKAGE_MIN}, {104, SAP_TX_LEAKAGE_MIN}, + {108, SAP_TX_LEAKAGE_MIN}, {112, SAP_TX_LEAKAGE_MIN}, + {116, SAP_TX_LEAKAGE_AUTO_MIN}, {120, SAP_TX_LEAKAGE_AUTO_MIN}, + {124, SAP_TX_LEAKAGE_AUTO_MIN}, {128, SAP_TX_LEAKAGE_AUTO_MIN}, + {132, 553}, {136, 553}, + {140, 568}, + {144, SAP_TX_LEAKAGE_MIN} + } }, + + {108, + {{36, 600}, {40, 600}, + {44, 627}, {48, 627}, + {52, 611}, {56, 611}, + {60, 611}, {64, 611}, + {100, 214}, {104, 214}, + {108, SAP_TX_LEAKAGE_MIN}, {112, SAP_TX_LEAKAGE_MIN}, + {116, SAP_TX_LEAKAGE_AUTO_MIN}, {120, SAP_TX_LEAKAGE_AUTO_MIN}, + {124, SAP_TX_LEAKAGE_AUTO_MIN}, {128, SAP_TX_LEAKAGE_AUTO_MIN}, + {132, SAP_TX_LEAKAGE_AUTO_MIN}, {136, SAP_TX_LEAKAGE_AUTO_MIN}, + {140, 534}, + {144, SAP_TX_LEAKAGE_MIN} + } }, + + {112, + {{36, 645}, {40, 645}, + {44, 641}, {48, 641}, + {52, 618}, {56, 618}, + {60, 612}, {64, 612}, + {100, 293}, {104, 293}, + {108, SAP_TX_LEAKAGE_MIN}, {112, SAP_TX_LEAKAGE_MIN}, + {116, SAP_TX_LEAKAGE_MIN}, {120, SAP_TX_LEAKAGE_MIN}, + {124, SAP_TX_LEAKAGE_AUTO_MIN}, {128, SAP_TX_LEAKAGE_AUTO_MIN}, + {132, SAP_TX_LEAKAGE_AUTO_MIN}, {136, SAP_TX_LEAKAGE_AUTO_MIN}, + {140, 521}, + {144, SAP_TX_LEAKAGE_MIN} + } }, + + {116, + {{36, 661}, {40, 661}, + {44, 624}, {48, 624}, + {52, 634}, {56, 634}, + {60, 611}, {64, 611}, + {100, SAP_TX_LEAKAGE_AUTO_MIN}, {104, SAP_TX_LEAKAGE_AUTO_MIN}, + {108, 217}, {112, 217}, + {116, SAP_TX_LEAKAGE_MIN}, {120, SAP_TX_LEAKAGE_MIN}, + {124, SAP_TX_LEAKAGE_AUTO_MIN}, {128, SAP_TX_LEAKAGE_AUTO_MIN}, + {132, SAP_TX_LEAKAGE_AUTO_MIN}, {136, SAP_TX_LEAKAGE_AUTO_MIN}, + {140, SAP_TX_LEAKAGE_AUTO_MIN}, + {144, SAP_TX_LEAKAGE_MIN} + } }, + + {120, + {{36, 667}, {40, 667}, + {44, 645}, {48, 645}, + {52, 633}, {56, 633}, + {60, 619}, {64, 619}, + {100, SAP_TX_LEAKAGE_AUTO_MIN}, {104, SAP_TX_LEAKAGE_AUTO_MIN}, + {108, 291}, {112, 291}, + {116, SAP_TX_LEAKAGE_MIN}, {120, SAP_TX_LEAKAGE_MIN}, + {124, SAP_TX_LEAKAGE_MIN}, {128, SAP_TX_LEAKAGE_MIN}, + {132, SAP_TX_LEAKAGE_AUTO_MIN}, {136, SAP_TX_LEAKAGE_AUTO_MIN}, + {140, SAP_TX_LEAKAGE_AUTO_MIN}, + {144, SAP_TX_LEAKAGE_MIN} + } }, + + {124, + {{36, 676}, {40, 676}, + {44, 668}, {48, 668}, + {52, 595}, {56, 595}, + {60, 622}, {64, 622}, + {100, SAP_TX_LEAKAGE_AUTO_MIN}, {104, SAP_TX_LEAKAGE_AUTO_MIN}, + {108, SAP_TX_LEAKAGE_AUTO_MIN}, {112, SAP_TX_LEAKAGE_AUTO_MIN}, + {116, 225}, {120, 225}, + {124, SAP_TX_LEAKAGE_MIN}, {128, SAP_TX_LEAKAGE_MIN}, + {132, SAP_TX_LEAKAGE_AUTO_MIN}, {136, SAP_TX_LEAKAGE_AUTO_MIN}, + {140, SAP_TX_LEAKAGE_AUTO_MIN}, + {144, SAP_TX_LEAKAGE_MIN} + } }, + + {128, + {{36, 678}, {40, 678}, + {44, 664}, {48, 664}, + {52, 651}, {56, 651}, + {60, 643}, {64, 643}, + {100, SAP_TX_LEAKAGE_AUTO_MIN}, {104, SAP_TX_LEAKAGE_AUTO_MIN}, + {108, SAP_TX_LEAKAGE_AUTO_MIN}, {112, SAP_TX_LEAKAGE_AUTO_MIN}, + {116, 293}, {120, 293}, + {124, SAP_TX_LEAKAGE_MIN}, {128, SAP_TX_LEAKAGE_MIN}, + {132, SAP_TX_LEAKAGE_MIN}, {136, SAP_TX_LEAKAGE_MIN}, + {140, SAP_TX_LEAKAGE_AUTO_MIN}, + {144, SAP_TX_LEAKAGE_MIN} + } }, + + {132, + {{36, 689}, {40, 689}, + {44, 669}, {48, 669}, + {52, 662}, {56, 662}, + {60, 609}, {64, 609}, + {100, 538}, {104, 538}, + {108, SAP_TX_LEAKAGE_AUTO_MIN}, {112, SAP_TX_LEAKAGE_AUTO_MIN}, + {116, SAP_TX_LEAKAGE_AUTO_MIN}, {120, SAP_TX_LEAKAGE_AUTO_MIN}, + {124, 247}, {128, 247}, + {132, SAP_TX_LEAKAGE_MIN}, {136, SAP_TX_LEAKAGE_MIN}, + {140, SAP_TX_LEAKAGE_MIN}, + {144, SAP_TX_LEAKAGE_MIN} + } }, + + {136, + {{36, 703}, {40, 703}, + {44, 688}, {48, SAP_TX_LEAKAGE_MIN}, + {52, 671}, {56, 671}, + {60, 658}, {64, 658}, + {100, 504}, {104, 504}, + {108, SAP_TX_LEAKAGE_AUTO_MIN}, {112, SAP_TX_LEAKAGE_AUTO_MIN}, + {116, SAP_TX_LEAKAGE_AUTO_MIN}, {120, SAP_TX_LEAKAGE_AUTO_MIN}, + {124, 289}, {128, 289}, + {132, SAP_TX_LEAKAGE_MIN}, {136, SAP_TX_LEAKAGE_MIN}, + {140, SAP_TX_LEAKAGE_MIN}, + {144, SAP_TX_LEAKAGE_MIN} + } }, + + {140, + {{36, 695}, {40, 695}, + {44, 684}, {48, 684}, + {52, 664}, {56, 664}, + {60, 658}, {64, 658}, + {100, 601}, {104, 601}, + {108, 545}, {112, 545}, + {116, SAP_TX_LEAKAGE_AUTO_MIN}, {120, SAP_TX_LEAKAGE_AUTO_MIN}, + {124, SAP_TX_LEAKAGE_AUTO_MIN}, {128, SAP_TX_LEAKAGE_AUTO_MIN}, + {132, 262}, {136, 262}, + {140, SAP_TX_LEAKAGE_MIN}, + {144, SAP_TX_LEAKAGE_MIN} + } }, + + {144, + {{36, 695}, {40, 695}, + {44, 684}, {48, 684}, + {52, 664}, {56, 664}, + {60, 658}, {64, 658}, + {100, 601}, {104, 601}, + {108, 545}, {112, 545}, + {116, SAP_TX_LEAKAGE_AUTO_MIN}, {120, SAP_TX_LEAKAGE_AUTO_MIN}, + {124, SAP_TX_LEAKAGE_AUTO_MIN}, {128, SAP_TX_LEAKAGE_AUTO_MIN}, + {132, 262}, {136, 262}, + {140, SAP_TX_LEAKAGE_MIN}, + {144, SAP_TX_LEAKAGE_MIN} + } }, +}; + +/* channel tx leakage table - ht20 */ +tSapChanMatrixInfo ht20_chan[] = { + {52, + {{36, SAP_TX_LEAKAGE_AUTO_MIN}, {40, 286}, + {44, 225}, {48, 121}, + {52, SAP_TX_LEAKAGE_MIN}, {56, SAP_TX_LEAKAGE_MIN}, + {60, 300}, {64, SAP_TX_LEAKAGE_AUTO_MIN}, + {100, 637}, {104, SAP_TX_LEAKAGE_MAX}, + {108, SAP_TX_LEAKAGE_MAX}, {112, SAP_TX_LEAKAGE_MAX}, + {116, SAP_TX_LEAKAGE_MAX}, {120, SAP_TX_LEAKAGE_MAX}, + {124, SAP_TX_LEAKAGE_MAX}, {128, SAP_TX_LEAKAGE_MAX}, + {132, SAP_TX_LEAKAGE_MAX}, {136, SAP_TX_LEAKAGE_MAX}, + {140, SAP_TX_LEAKAGE_MAX}, + {144, SAP_TX_LEAKAGE_MIN} + } }, + + {56, + {{36, 468}, {40, SAP_TX_LEAKAGE_AUTO_MIN}, + {44, SAP_TX_LEAKAGE_AUTO_MIN}, {48, 206}, + {52, SAP_TX_LEAKAGE_MIN}, {56, SAP_TX_LEAKAGE_MIN}, + {60, SAP_TX_LEAKAGE_MIN}, {64, SAP_TX_LEAKAGE_MIN}, + {100, SAP_TX_LEAKAGE_MAX}, {104, SAP_TX_LEAKAGE_MAX}, + {108, SAP_TX_LEAKAGE_MAX}, {112, SAP_TX_LEAKAGE_MAX}, + {116, SAP_TX_LEAKAGE_MAX}, {120, SAP_TX_LEAKAGE_MAX}, + {124, SAP_TX_LEAKAGE_MAX}, {128, SAP_TX_LEAKAGE_MAX}, + {132, SAP_TX_LEAKAGE_MAX}, {136, SAP_TX_LEAKAGE_MAX}, + {140, SAP_TX_LEAKAGE_MAX}, + {144, SAP_TX_LEAKAGE_MIN} + } }, + + {60, + {{36, 507}, {40, 440}, + {44, SAP_TX_LEAKAGE_AUTO_MIN}, {48, 313}, + {52, SAP_TX_LEAKAGE_MIN}, {56, SAP_TX_LEAKAGE_MIN}, + {60, SAP_TX_LEAKAGE_MIN}, {64, SAP_TX_LEAKAGE_MIN}, + {100, SAP_TX_LEAKAGE_MAX}, {104, SAP_TX_LEAKAGE_MAX}, + {108, SAP_TX_LEAKAGE_MAX}, {112, SAP_TX_LEAKAGE_MAX}, + {116, SAP_TX_LEAKAGE_MAX}, {120, SAP_TX_LEAKAGE_MAX}, + {124, SAP_TX_LEAKAGE_MAX}, {128, SAP_TX_LEAKAGE_MAX}, + {132, SAP_TX_LEAKAGE_MAX}, {136, SAP_TX_LEAKAGE_MAX}, + {140, SAP_TX_LEAKAGE_MAX}, + {144, SAP_TX_LEAKAGE_MIN} + } }, + + {64, + {{36, 516}, {40, 520}, + {44, 506}, {48, SAP_TX_LEAKAGE_AUTO_MIN}, + {52, 301}, {56, 258}, + {60, SAP_TX_LEAKAGE_MIN}, {64, SAP_TX_LEAKAGE_MIN}, + {100, 620}, {104, 617}, + {108, SAP_TX_LEAKAGE_MAX}, {112, SAP_TX_LEAKAGE_MAX}, + {116, SAP_TX_LEAKAGE_MAX}, {120, SAP_TX_LEAKAGE_MAX}, + {124, SAP_TX_LEAKAGE_MAX}, {128, SAP_TX_LEAKAGE_MAX}, + {132, SAP_TX_LEAKAGE_MAX}, {136, SAP_TX_LEAKAGE_MAX}, + {140, SAP_TX_LEAKAGE_MAX}, + {144, SAP_TX_LEAKAGE_MIN} + } }, + + {100, + {{36, 616}, {40, 601}, + {44, 604}, {48, 589}, + {52, 612}, {56, 592}, + {60, 590}, {64, 582}, + {100, SAP_TX_LEAKAGE_MIN}, {104, 131}, + {108, SAP_TX_LEAKAGE_AUTO_MIN}, {112, SAP_TX_LEAKAGE_AUTO_MIN}, + {116, SAP_TX_LEAKAGE_AUTO_MIN}, {120, 522}, + {124, 571}, {128, 589}, + {132, 593}, {136, 598}, + {140, 594}, + {144, SAP_TX_LEAKAGE_MIN}, + } }, + + {104, + {{36, 622}, {40, 624}, + {44, 618}, {48, 610}, + {52, SAP_TX_LEAKAGE_MAX}, {56, SAP_TX_LEAKAGE_MAX}, + {60, SAP_TX_LEAKAGE_MAX}, {64, SAP_TX_LEAKAGE_MAX}, + {100, SAP_TX_LEAKAGE_MIN}, {104, SAP_TX_LEAKAGE_MIN}, + {108, SAP_TX_LEAKAGE_MIN}, {112, 463}, + {116, 483}, {120, 503}, + {124, 523}, {128, 565}, + {132, 570}, {136, 588}, + {140, 585}, + {144, SAP_TX_LEAKAGE_MIN}, + } }, + + {108, + {{36, 620}, {40, 638}, + {44, 611}, {48, 614}, + {52, SAP_TX_LEAKAGE_MAX}, {56, SAP_TX_LEAKAGE_MAX}, + {60, SAP_TX_LEAKAGE_MAX}, {64, SAP_TX_LEAKAGE_MAX}, + {100, 477}, {104, SAP_TX_LEAKAGE_MIN}, + {108, SAP_TX_LEAKAGE_MIN}, {112, SAP_TX_LEAKAGE_MIN}, + {116, 477}, {120, 497}, + {124, 517}, {128, 537}, + {132, 557}, {136, 577}, + {140, 603}, + {144, SAP_TX_LEAKAGE_MIN}, + } }, + + {112, + {{36, 636}, {40, 623}, + {44, 638}, {48, 628}, + {52, SAP_TX_LEAKAGE_MAX}, {56, SAP_TX_LEAKAGE_MAX}, + {60, SAP_TX_LEAKAGE_MAX}, {64, 606}, + {100, 501}, {104, 481}, + {108, SAP_TX_LEAKAGE_MIN}, {112, SAP_TX_LEAKAGE_MIN}, + {116, SAP_TX_LEAKAGE_MIN}, {120, 481}, + {124, 501}, {128, 421}, + {132, 541}, {136, 561}, + {140, 583}, + {144, SAP_TX_LEAKAGE_MIN}, + } }, + + {116, + {{36, 646}, {40, 648}, + {44, 633}, {48, 634}, + {52, SAP_TX_LEAKAGE_MAX}, {56, SAP_TX_LEAKAGE_MAX}, + {60, 615}, {64, 594}, + {100, 575}, {104, 554}, + {108, 534}, {112, SAP_TX_LEAKAGE_MIN}, + {116, SAP_TX_LEAKAGE_MIN}, {120, SAP_TX_LEAKAGE_MIN}, + {124, SAP_TX_LEAKAGE_MIN}, {128, SAP_TX_LEAKAGE_MIN}, + {132, 534}, {136, 554}, + {140, 574}, + {144, SAP_TX_LEAKAGE_MIN}, + } }, + + {120, + {{36, 643}, {40, 649}, + {44, 654}, {48, 629}, + {52, SAP_TX_LEAKAGE_MAX}, {56, 621}, + {60, SAP_TX_LEAKAGE_MAX}, {64, SAP_TX_LEAKAGE_MAX}, + {100, 565}, {104, 545}, + {108, 525}, {112, 505}, + {116, SAP_TX_LEAKAGE_MIN}, {120, SAP_TX_LEAKAGE_MIN}, + {124, SAP_TX_LEAKAGE_MIN}, {128, 505}, + {132, 525}, {136, 545}, + {140, 565}, + {144, SAP_TX_LEAKAGE_MIN}, + } }, + + {124, + {{36, 638}, {40, 657}, + {44, 663}, {48, 649}, + {52, SAP_TX_LEAKAGE_MAX}, {56, SAP_TX_LEAKAGE_MAX}, + {60, SAP_TX_LEAKAGE_MAX}, {64, SAP_TX_LEAKAGE_MAX}, + {100, 581}, {104, 561}, + {108, 541}, {112, 521}, + {116, 499}, {120, SAP_TX_LEAKAGE_MIN}, + {124, SAP_TX_LEAKAGE_MIN}, {128, SAP_TX_LEAKAGE_MIN}, + {132, 499}, {136, 519}, + {140, 539}, + {144, SAP_TX_LEAKAGE_MIN} + } }, + + {128, + {{36, 651}, {40, 651}, + {44, 674}, {48, 640}, + {52, SAP_TX_LEAKAGE_MAX}, {56, SAP_TX_LEAKAGE_MAX}, + {60, SAP_TX_LEAKAGE_MAX}, {64, SAP_TX_LEAKAGE_MAX}, + {100, 603}, {104, 560}, + {108, 540}, {112, 520}, + {116, 499}, {120, 479}, + {124, SAP_TX_LEAKAGE_MIN}, {128, SAP_TX_LEAKAGE_MIN}, + {132, SAP_TX_LEAKAGE_MIN}, {136, 479}, + {140, 499}, + {144, SAP_TX_LEAKAGE_MIN} + } }, + + {132, + {{36, 643}, {40, 668}, + {44, 651}, {48, 657}, + {52, SAP_TX_LEAKAGE_MAX}, {56, SAP_TX_LEAKAGE_MAX}, + {60, SAP_TX_LEAKAGE_MAX}, {64, SAP_TX_LEAKAGE_MAX}, + {100, SAP_TX_LEAKAGE_MAX}, {104, 602}, + {108, 578}, {112, 570}, + {116, 550}, {120, 530}, + {124, 510}, {128, SAP_TX_LEAKAGE_MIN}, + {132, SAP_TX_LEAKAGE_MIN}, {136, SAP_TX_LEAKAGE_MIN}, + {140, 490}, + {144, SAP_TX_LEAKAGE_MIN} + } }, + + {136, + {{36, 654}, {40, 667}, + {44, 666}, {48, 642}, + {52, SAP_TX_LEAKAGE_MAX}, {56, SAP_TX_LEAKAGE_MAX}, + {60, SAP_TX_LEAKAGE_MAX}, {64, SAP_TX_LEAKAGE_MAX}, + {100, SAP_TX_LEAKAGE_MAX}, {104, SAP_TX_LEAKAGE_MAX}, + {108, SAP_TX_LEAKAGE_MAX}, {112, 596}, + {116, 555}, {120, 535}, + {124, 515}, {128, 495}, + {132, SAP_TX_LEAKAGE_MIN}, {136, SAP_TX_LEAKAGE_MIN}, + {140, SAP_TX_LEAKAGE_MIN}, + {144, SAP_TX_LEAKAGE_MIN} + } }, + + {140, + {{36, 679}, {40, 673}, + {44, 667}, {48, 656}, + {52, 634}, {56, 663}, + {60, 662}, {64, 660}, + {100, SAP_TX_LEAKAGE_MAX}, {104, SAP_TX_LEAKAGE_MAX}, + {108, SAP_TX_LEAKAGE_MAX}, {112, 590}, + {116, 573}, {120, 553}, + {124, 533}, {128, 513}, + {132, 490}, {136, SAP_TX_LEAKAGE_MIN}, + {140, SAP_TX_LEAKAGE_MIN}, + {144, SAP_TX_LEAKAGE_MIN} + } }, + + {144, + {{36, 679}, {40, 673}, + {44, 667}, {48, 656}, + {52, 634}, {56, 663}, + {60, 662}, {64, 660}, + {100, SAP_TX_LEAKAGE_MAX}, {104, SAP_TX_LEAKAGE_MAX}, + {108, SAP_TX_LEAKAGE_MAX}, {112, 590}, + {116, 573}, {120, 553}, + {124, 533}, {128, 513}, + {132, 490}, {136, SAP_TX_LEAKAGE_MIN}, + {140, SAP_TX_LEAKAGE_MIN}, + {144, SAP_TX_LEAKAGE_MIN} + } }, +}; +#endif /* WLAN_ENABLE_CHNL_MATRIX_RESTRICTION */ + +/*---------------------------------------------------------------------------- + * Static Function Declarations and Definitions + * -------------------------------------------------------------------------*/ +#ifdef SOFTAP_CHANNEL_RANGE +static QDF_STATUS sap_get_channel_list(ptSapContext sapContext, + uint8_t **channelList, + uint8_t *numberOfChannels); +#endif + +/*========================================================================== + FUNCTION sap_get_5ghz_channel_list + + DESCRIPTION + Function for initializing list of 2.4/5 Ghz [NON-DFS/DFS] available + channels in the current regulatory domain. + + DEPENDENCIES + NA. + + PARAMETERS + + IN + sapContext: SAP Context + + RETURN VALUE + NA + + SIDE EFFECTS + ============================================================================*/ +static QDF_STATUS sap_get_5ghz_channel_list(ptSapContext sapContext); + +/*========================================================================== + FUNCTION sapStopDfsCacTimer + + DESCRIPTION + Function to sttop the DFS CAC timer when SAP is stopped + DEPENDENCIES + NA. + + PARAMETERS + + IN + sapContext: SAP Context + RETURN VALUE + DFS Timer start status + SIDE EFFECTS + ============================================================================*/ + +static int sap_stop_dfs_cac_timer(ptSapContext sapContext); + +/*========================================================================== + FUNCTION sapStartDfsCacTimer + + DESCRIPTION + Function to start the DFS CAC timer when SAP is started on DFS Channel + DEPENDENCIES + NA. + + PARAMETERS + + IN + sapContext: SAP Context + RETURN VALUE + DFS Timer start status + SIDE EFFECTS + ============================================================================*/ + +int sap_start_dfs_cac_timer(ptSapContext sapContext); + +/** sap_hdd_event_to_string() - convert hdd event to string + * @event: eSapHddEvent event type + * + * This function converts eSapHddEvent into string + * + * Return: string for the @event. + */ +static uint8_t *sap_hdd_event_to_string(eSapHddEvent event) +{ + switch (event) { + CASE_RETURN_STRING(eSAP_START_BSS_EVENT); + CASE_RETURN_STRING(eSAP_STOP_BSS_EVENT); + CASE_RETURN_STRING(eSAP_STA_ASSOC_IND); + CASE_RETURN_STRING(eSAP_STA_ASSOC_EVENT); + CASE_RETURN_STRING(eSAP_STA_REASSOC_EVENT); + CASE_RETURN_STRING(eSAP_STA_DISASSOC_EVENT); + CASE_RETURN_STRING(eSAP_STA_SET_KEY_EVENT); + CASE_RETURN_STRING(eSAP_STA_MIC_FAILURE_EVENT); + CASE_RETURN_STRING(eSAP_ASSOC_STA_CALLBACK_EVENT); + CASE_RETURN_STRING(eSAP_GET_WPSPBC_SESSION_EVENT); + CASE_RETURN_STRING(eSAP_WPS_PBC_PROBE_REQ_EVENT); + CASE_RETURN_STRING(eSAP_REMAIN_CHAN_READY); + CASE_RETURN_STRING(eSAP_DISCONNECT_ALL_P2P_CLIENT); + CASE_RETURN_STRING(eSAP_MAC_TRIG_STOP_BSS_EVENT); + CASE_RETURN_STRING(eSAP_UNKNOWN_STA_JOIN); + CASE_RETURN_STRING(eSAP_MAX_ASSOC_EXCEEDED); + CASE_RETURN_STRING(eSAP_CHANNEL_CHANGE_EVENT); + CASE_RETURN_STRING(eSAP_DFS_CAC_START); + CASE_RETURN_STRING(eSAP_DFS_CAC_END); + CASE_RETURN_STRING(eSAP_DFS_PRE_CAC_END); + CASE_RETURN_STRING(eSAP_DFS_RADAR_DETECT); + CASE_RETURN_STRING(eSAP_DFS_RADAR_DETECT_DURING_PRE_CAC); + CASE_RETURN_STRING(eSAP_DFS_NOL_GET); + CASE_RETURN_STRING(eSAP_DFS_NOL_SET); + CASE_RETURN_STRING(eSAP_DFS_NO_AVAILABLE_CHANNEL); +#ifdef FEATURE_WLAN_AP_AP_ACS_OPTIMIZE + CASE_RETURN_STRING(eSAP_ACS_SCAN_SUCCESS_EVENT); +#endif + CASE_RETURN_STRING(eSAP_ACS_CHANNEL_SELECTED); + default: + return "eSAP_HDD_EVENT_UNKNOWN"; + } +} + +/*---------------------------------------------------------------------------- + * Externalized Function Definitions + * -------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------- + * Function Declarations and Documentation + * -------------------------------------------------------------------------*/ + +/*========================================================================== + FUNCTION sap_event_init + + DESCRIPTION + Function for initializing sWLAN_SAPEvent structure + + DEPENDENCIES + NA. + + PARAMETERS + + IN + sapEvent : State machine event + + RETURN VALUE + + None + + SIDE EFFECTS + ============================================================================*/ +static inline void sap_event_init(ptWLAN_SAPEvent sapEvent) +{ + sapEvent->event = eSAP_MAC_SCAN_COMPLETE; + sapEvent->params = 0; + sapEvent->u1 = 0; + sapEvent->u2 = 0; +} + +#ifdef WLAN_ENABLE_CHNL_MATRIX_RESTRICTION +/* + * sap_find_target_channel_in_channel_matrix() - finds the leakage matrix + * @sapContext: Pointer to vos global context structure + * @ch_width: target channel width + * @NOL_channel: the NOL channel whose leakage matrix is required + * @pTarget_chnl_mtrx: pointer to target channel matrix returned. + * + * This function gives the leakage matrix for given NOL channel and ch_width + * + * Return: TRUE or FALSE + */ +static bool +sap_find_target_channel_in_channel_matrix(ptSapContext sapContext, + enum phy_ch_width ch_width, + uint8_t NOL_channel, + tSapTxLeakInfo **pTarget_chnl_mtrx) +{ + tSapTxLeakInfo *target_chan_matrix = NULL; + tSapChanMatrixInfo *pchan_matrix = NULL; + uint32_t nchan_matrix; + int i = 0; + + switch (ch_width) { + case CH_WIDTH_20MHZ: + /* HT20 */ + pchan_matrix = ht20_chan; + nchan_matrix = QDF_ARRAY_SIZE(ht20_chan); + break; + case CH_WIDTH_40MHZ: + /* HT40 */ + pchan_matrix = ht40_chan; + nchan_matrix = QDF_ARRAY_SIZE(ht40_chan); + break; + case CH_WIDTH_80MHZ: + /* HT80 */ + pchan_matrix = ht80_chan; + nchan_matrix = QDF_ARRAY_SIZE(ht80_chan); + break; + default: + /* handle exception and fall back to HT20 table */ + pchan_matrix = ht20_chan; + nchan_matrix = QDF_ARRAY_SIZE(ht20_chan); + break; + } + + for (i = 0; i < nchan_matrix; i++) { + /* find the SAP channel to map the leakage matrix */ + if (NOL_channel == pchan_matrix[i].channel) { + target_chan_matrix = pchan_matrix[i].chan_matrix; + break; + } + } + + if (NULL == target_chan_matrix) { + return false; + } else { + *pTarget_chnl_mtrx = target_chan_matrix; + return true; + } +} + +/** + * sap_mark_leaking_ch() - to mark channel leaking in to nol + * @sap_ctx: pointer to SAP context + * @ch_width: channel width + * @nol: nol info + * @temp_ch_lst_sz: the target channel list + * @temp_ch_lst: the target channel list + * + * This function removes the channels from temp channel list that + * (if selected as target channel) will cause leakage in one of + * the NOL channels + * + * Return: QDF_STATUS + */ + +static QDF_STATUS +sap_mark_leaking_ch(ptSapContext sap_ctx, + enum phy_ch_width ch_width, + tSapDfsNolInfo *nol, + uint8_t temp_ch_lst_sz, + uint8_t *temp_ch_lst) +{ + tSapTxLeakInfo *target_chan_matrix = NULL; + uint32_t num_channel = (CHAN_ENUM_144 - CHAN_ENUM_36) + 1; + uint32_t i = 0; + uint32_t j = 0; + uint32_t k = 0; + uint8_t dfs_nol_channel; + tHalHandle hal = CDS_GET_HAL_CB(sap_ctx->pvosGCtx); + tpAniSirGlobal mac; + + if (NULL == hal) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid hal pointer", __func__); + return QDF_STATUS_E_FAULT; + } + + mac = PMAC_STRUCT(hal); + + + /* traverse target_chan_matrix and */ + for (i = 0; i < NUM_5GHZ_CHANNELS ; i++) { + dfs_nol_channel = nol[i].dfs_channel_number; + if (nol[i].radar_status_flag == eSAP_DFS_CHANNEL_USABLE || + nol[i].radar_status_flag == eSAP_DFS_CHANNEL_AVAILABLE) { + /* not present in NOL */ + continue; + } + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_DEBUG, + FL("sapdfs: processing NOL channel: %d"), + dfs_nol_channel); + if (false == sap_find_target_channel_in_channel_matrix( + sap_ctx, ch_width, dfs_nol_channel, + &target_chan_matrix)) { + /* + * should never happen, we should always find a table + * here, if we don't, need a fix here! + */ + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("Couldn't find target channel matrix!")); + QDF_ASSERT(0); + return QDF_STATUS_E_FAILURE; + } + /* + * following is based on assumption that both temp_ch_lst + * and target channel matrix are in increasing order of + * ch_id + */ + for (j = 0, k = 0; j < temp_ch_lst_sz && k < num_channel;) { + if (temp_ch_lst[j] == 0) { + j++; + continue; + } + if (target_chan_matrix[k].leak_chan != temp_ch_lst[j]) { + k++; + continue; + } + /* + * check leakage from candidate channel + * to NOL channel + */ + if (target_chan_matrix[k].leak_lvl <= + mac->sap.SapDfsInfo.tx_leakage_threshold) { + /* + * candidate channel will have + * bad leakage in NOL channel, + * remove from temp list + */ + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_INFO_LOW, + FL("sapdfs: channel: %d will have bad leakage due to channel: %d\n"), + dfs_nol_channel, temp_ch_lst[j]); + temp_ch_lst[j] = 0; + } + j++; + k++; + } + } /* end of loop that selects each NOL */ + return QDF_STATUS_SUCCESS; +} +#endif /* end of WLAN_ENABLE_CHNL_MATRIX_RESTRICTION */ + +/* + * This function adds availabe channel to bitmap + * + * PARAMETERS + * IN + * pBitmap: bitmap to populate + * channel: channel to set in bitmap + */ +static void sap_set_bitmap(chan_bonding_bitmap *pBitmap, uint8_t channel) +{ + int i = 0; + int start_channel = 0; + for (i = 0; i < MAX_80MHZ_BANDS; i++) { + start_channel = pBitmap->chanBondingSet[i].startChannel; + if (channel >= start_channel && channel <= start_channel + 12) { + pBitmap->chanBondingSet[i].channelMap |= + 1 << ((channel - start_channel) / 4); + return; + } + } + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("Channel=%d is not in the bitmap"), channel); +} + +/** + * sap_populate_available_channels() - To populate available channel + * @bitmap: bitmap to populate + * @ch_width: channel width + * @avail_chnl: available channel list to populate + * + * This function reads the bitmap and populates available channel + * list according to channel bonding mode. This will be called for + * 80 MHz and 40 Mhz only. For 20 MHz no need for bitmap hence list + * is directly created while parsing the main list + * + * Return: number of channels found + */ +static uint8_t sap_populate_available_channels(chan_bonding_bitmap *bitmap, + enum phy_ch_width ch_width, + uint8_t *avail_chnl) +{ + uint8_t i = 0; + uint8_t chnl_count = 0; + uint8_t start_channel = 0; + + switch (ch_width) { + /* VHT80 */ + case CH_WIDTH_160MHZ: + case CH_WIDTH_80P80MHZ: + case CH_WIDTH_80MHZ: + for (i = 0; i < MAX_80MHZ_BANDS; i++) { + start_channel = bitmap->chanBondingSet[i].startChannel; + if (bitmap->chanBondingSet[i].channelMap == + SAP_80MHZ_MASK) { + avail_chnl[chnl_count++] = start_channel; + avail_chnl[chnl_count++] = start_channel + 4; + avail_chnl[chnl_count++] = start_channel + 8; + avail_chnl[chnl_count++] = start_channel + 12; + } + } + break; + /* HT40 */ + case CH_WIDTH_40MHZ: + for (i = 0; i < MAX_80MHZ_BANDS; i++) { + start_channel = bitmap->chanBondingSet[i].startChannel; + if ((bitmap->chanBondingSet[i].channelMap & + SAP_40MHZ_MASK_L) == SAP_40MHZ_MASK_L) { + avail_chnl[chnl_count++] = start_channel; + avail_chnl[chnl_count++] = start_channel + 4; + } + if ((bitmap->chanBondingSet[i].channelMap & + SAP_40MHZ_MASK_H) == SAP_40MHZ_MASK_H) { + avail_chnl[chnl_count++] = start_channel + 8; + avail_chnl[chnl_count++] = start_channel + 12; + } + } + break; + default: + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("Invalid case.")); + break; + } + + return chnl_count; +} + +/* + * FUNCTION sap_dfs_is_w53_invalid + * + * DESCRIPTION Checks if the passed channel is W53 and returns if + * SAP W53 opearation is allowed. + * + * DEPENDENCIES PARAMETERS + * IN hHAL : HAL pointer + * channelID: Channel Number to be verified + * + * RETURN VALUE : bool + * true: If W53 operation is disabled + * false: If W53 operation is enabled + * + * SIDE EFFECTS + */ +bool sap_dfs_is_w53_invalid(tHalHandle hHal, uint8_t channelID) +{ + tpAniSirGlobal pMac; + + pMac = PMAC_STRUCT(hHal); + if (NULL == pMac) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("invalid pMac")); + return false; + } + + /* + * Check for JAPAN W53 Channel operation capability + */ + if (true == pMac->sap.SapDfsInfo.is_dfs_w53_disabled && + true == IS_CHAN_JAPAN_W53(channelID)) { + return true; + } + + return false; +} + +/* + * FUNCTION sap_dfs_is_channel_in_preferred_location + * + * DESCRIPTION Checks if the passed channel is in accordance with preferred + * Channel location settings. + * + * DEPENDENCIES PARAMETERS + * IN hHAL : HAL pointer + * channelID: Channel Number to be verified + * + * RETURN VALUE :bool + * true:If Channel location is same as the preferred location + * false:If Channel location is not same as the preferred location + * + * SIDE EFFECTS + */ +bool sap_dfs_is_channel_in_preferred_location(tHalHandle hHal, uint8_t channelID) +{ + tpAniSirGlobal pMac; + + pMac = PMAC_STRUCT(hHal); + if (NULL == pMac) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("invalid pMac")); + return true; + } + if ((SAP_CHAN_PREFERRED_INDOOR == + pMac->sap.SapDfsInfo.sap_operating_chan_preferred_location) && + (true == IS_CHAN_JAPAN_OUTDOOR(channelID))) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_LOW, + FL + ("CHAN=%d is Outdoor so invalid,preferred Indoor only"), + channelID); + return false; + } else if ((SAP_CHAN_PREFERRED_OUTDOOR == + pMac->sap.SapDfsInfo.sap_operating_chan_preferred_location) + && (true == IS_CHAN_JAPAN_INDOOR(channelID))) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_LOW, + FL + ("CHAN=%d is Indoor so invalid,preferred Outdoor only"), + channelID); + return false; + } + + return true; +} + +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE +/** + * sap_check_in_avoid_ch_list() - checks if given channel present is channel + * avoidance list + * + * @sap_ctx: sap context. + * @channel: channel to be checked in sap_ctx's avoid ch list + * + * sap_ctx contains sap_avoid_ch_info strcut containing the list of channels on + * which MDM device's AP with MCC was detected. This function checks if given + * channel is present in that list. + * + * Return: true, if channel was present, false othersie. + */ +bool sap_check_in_avoid_ch_list(ptSapContext sap_ctx, uint8_t channel) +{ + uint8_t i = 0; + struct sap_avoid_channels_info *ie_info = + &sap_ctx->sap_detected_avoid_ch_ie; + for (i = 0; i < sizeof(ie_info->channels); i++) + if (ie_info->channels[i] == channel) + return true; + return false; +} +#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ + +/** + * sap_is_valid_acs_channel() - checks if given channel is in acs channel range + * @sap_ctx: sap context. + * @channel: channel to be checked in acs range + * + * Return: true, if channel is valid, false otherwise. + */ +static bool sap_is_valid_acs_channel(ptSapContext sap_ctx, uint8_t channel) +{ + int i = 0; + + /* Check whether acs is enabled */ + if (!sap_ctx->acs_cfg->acs_mode) + return true; + + if ((channel < sap_ctx->acs_cfg->start_ch) || + (channel > sap_ctx->acs_cfg->end_ch)) { + return false; + } + if (!sap_ctx->acs_cfg->ch_list) { + /* List not present, return */ + return true; + } else { + for (i = 0; i < sap_ctx->acs_cfg->ch_list_count; i++) + if (channel == sap_ctx->acs_cfg->ch_list[i]) + return true; + } + + return false; +} + +/** + * sap_apply_rules() - validates channels in sap_ctx channel list + * @sap_ctx: sap context pointer + * + * This function takes the channel list in sap_ctx and marks invalid channel + * based on following rules: + * -> invalid due to different reg domain dfs channel list + * -> already present in NOL + * -> outside ACS range or not + * -> not usable due to another SAP operating MCC mode in same channel + * -> preferred location is indoors or outdoors + * + * Return: number of valid channels after applying all the rules + */ +static uint8_t sap_apply_rules(ptSapContext sap_ctx) +{ + uint8_t num_valid_ch, i = 0, ch_id; + tAll5GChannelList *sap_all_ch = &sap_ctx->SapAllChnlList; + bool is_ch_nol = false; + bool is_valid_acs_chan = false; + tpAniSirGlobal mac_ctx; + tHalHandle hal = CDS_GET_HAL_CB(sap_ctx->p_cds_gctx); + uint8_t preferred_location; + enum dfs_region dfs_region; + + if (NULL == hal) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("hal pointer NULL")); + return 0; + } + + mac_ctx = PMAC_STRUCT(hal); + if (NULL == mac_ctx) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("mac_ctx pointer NULL")); + return 0; + } + + preferred_location = + mac_ctx->sap.SapDfsInfo.sap_operating_chan_preferred_location; + cds_get_dfs_region(&dfs_region); + /* loop to check ACS range or NOL channels */ + num_valid_ch = sap_all_ch->numChannel; + for (i = 0; i < sap_all_ch->numChannel; i++) { + ch_id = sap_all_ch->channelList[i].channel; + + /* + * IN MKK DFS REGION CHECK IF THE FOLLOWING TWO + * TWO RULES APPLY AND FILTER THE AVAILABLE CHANNELS + * ACCORDINGLY. + * + * 1. If we are operating in Japan regulatory domain + * Check if Japan W53 Channel operation is NOT + * allowed and if its not allowed then mark all the + * W53 channels as Invalid. + * + * 2. If we are operating in Japan regulatory domain + * Check if channel switch between Indoor/Outdoor + * is allowed. If it is not allowed then limit + * the avaiable channels to Indoor or Outdoor + * channels only based up on the SAP Channel location + * indicated by "sap_operating_channel_location" param. + */ + if (DFS_MKK_REGION == dfs_region) { + /* + * Check for JAPAN W53 Channel operation capability + */ + if (true == sap_dfs_is_w53_invalid(hal, ch_id)) { + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_INFO_LOW, + FL("index:%d, Channel=%d Invalid,Japan W53 Disabled"), + i, ch_id); + sap_all_ch->channelList[i].valid = false; + num_valid_ch--; + continue; + } + + /* + * If SAP's preferred channel location is Indoor + * then set all the outdoor channels in the domain + * to invalid.If the preferred channel location is + * outdoor then set all the Indoor channels in the + * domain to Invalid. + */ + if (false == + sap_dfs_is_channel_in_preferred_location(hal, + ch_id)) { + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_INFO_LOW, + FL("CHAN=%d is invalid,preferred Channel Location %d Only"), + ch_id, preferred_location); + sap_all_ch->channelList[i].valid = false; + num_valid_ch--; + continue; + } + } + + if (cds_get_channel_state(ch_id) == CHANNEL_STATE_DFS) { + is_ch_nol = sap_dfs_is_channel_in_nol_list(sap_ctx, + ch_id, PHY_SINGLE_CHANNEL_CENTERED); + if (true == is_ch_nol) { + /* + * Mark this channel invalid since it is still + * in DFS Non-Occupancy-Period which is 30 mins. + */ + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_INFO_LOW, + FL("index: %d, Channel = %d Present in NOL LIST"), + i, ch_id); + sap_all_ch->channelList[i].valid = false; + num_valid_ch--; + continue; + } + } + +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE + /* avoid ch on which another MDM AP in MCC mode is detected */ + if (mac_ctx->sap.sap_channel_avoidance + && sap_ctx->sap_detected_avoid_ch_ie.present) { + if (sap_check_in_avoid_ch_list(sap_ctx, ch_id)) { + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_INFO_LOW, + FL("index: %d, Channel = %d, avoided due to presence of another AP+AP MCC device in same channel."), + i, ch_id); + sap_all_ch->channelList[i].valid = false; + } + } +#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ + + /* check if the channel is within ACS channel range */ + is_valid_acs_chan = sap_is_valid_acs_channel(sap_ctx, ch_id); + if (is_valid_acs_chan == false) { + /* + * mark this channel invalid since it is out of ACS + * channel range + */ + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_LOW, + FL("index=%d, Channel=%d out of ACS chan range %d-%d"), + i, ch_id, sap_ctx->acs_cfg->start_ch, + sap_ctx->acs_cfg->end_ch); + sap_all_ch->channelList[i].valid = false; + num_valid_ch--; + continue; + } + } /* end of check for NOL or ACS channels */ + return num_valid_ch; +} + +/** + * select_rand_from_lst() - selects random channel from given list + * @mac_ctx: mac context pointer + * @ch_lst: channel list + * @num_ch: number of channels + * + * Return: new target channel randomly selected + */ +static uint8_t select_rand_from_lst(tpAniSirGlobal mac_ctx, uint8_t *ch_lst, + uint8_t num_ch) +{ + uint32_t rand_byte = 0; + uint8_t i, target_channel, non_dfs_num_ch = 0, dfs_num_ch = 0; + uint8_t dfs_ch[WNI_CFG_VALID_CHANNEL_LIST_LEN] = {0}; + uint8_t non_dfs_ch[WNI_CFG_VALID_CHANNEL_LIST_LEN] = {0}; + if (num_ch) { + for (i = 0; i < num_ch; i++) { + if (CDS_IS_DFS_CH(ch_lst[i])) + dfs_ch[dfs_num_ch++] = ch_lst[i]; + else + non_dfs_ch[non_dfs_num_ch++] = ch_lst[i]; + } + } else { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_LOW, + FL("No target channel found")); + return 0; + } + + cds_rand_get_bytes(0, (uint8_t *)&rand_byte, 1); + + /* Give preference to non-DFS channel */ + if (!mac_ctx->f_prefer_non_dfs_on_radar) { + i = (rand_byte + qdf_mc_timer_get_system_ticks()) % num_ch; + target_channel = ch_lst[i]; + } else if (non_dfs_num_ch) { + i = (rand_byte + qdf_mc_timer_get_system_ticks()) % + non_dfs_num_ch; + target_channel = non_dfs_ch[i]; + } else { + i = (rand_byte + qdf_mc_timer_get_system_ticks()) % dfs_num_ch; + target_channel = dfs_ch[i]; + } + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_LOW, + FL("sapdfs: New Channel width = %d"), + mac_ctx->sap.SapDfsInfo.new_chanWidth); + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_LOW, + FL("sapdfs: target_channel = %d"), target_channel); + + return target_channel; +} + +/** + * sap_find_ch_wh_fallback() - find given channel width from given list of + * channels + * @mac_ctx: mac context pointer + * @ch_wd: channel width to find + * @ch_lst: list of channels + * @num_ch: number of channels + * + * This function tries to find given channel width and returns new target ch. + * If not found updates ch_wd to next lower channel width. + * + * Return: new target channel if successful, 0 otherwise + */ +static uint8_t sap_find_ch_wh_fallback(tpAniSirGlobal mac_ctx, + enum phy_ch_width *ch_wd, + uint8_t *ch_lst, + uint8_t num_ch) +{ + bool flag = false; + uint32_t rand_byte = 0; + chan_bonding_bitmap ch_map = { { {0} } }; + uint8_t count = 0, i, index = 0, final_cnt = 0, target_channel = 0; + uint8_t primary_seg_start_ch = 0, sec_seg_ch = 0, new_160_start_ch = 0; + uint8_t final_lst[WNI_CFG_VALID_CHANNEL_LIST_LEN] = {0}; + + /* initialize ch_map for all 80 MHz bands: we have 6 80MHz bands */ + ch_map.chanBondingSet[0].startChannel = 36; + ch_map.chanBondingSet[1].startChannel = 52; + ch_map.chanBondingSet[2].startChannel = 100; + ch_map.chanBondingSet[3].startChannel = 116; + ch_map.chanBondingSet[4].startChannel = 132; + ch_map.chanBondingSet[5].startChannel = 149; + + /* now loop through leakage free list */ + for (i = 0; i < num_ch; i++) { + /* add tmp ch to bitmap */ + if (ch_lst[i] == 0) + continue; + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_DEBUG, + FL("sapdfs: Channel=%d added to bitmap"), + ch_lst[i]); + sap_set_bitmap(&ch_map, ch_lst[i]); + } + + /* populate available channel list from bitmap */ + final_cnt = sap_populate_available_channels(&ch_map, *ch_wd, final_lst); + /* If no valid ch bonding found, fallback */ + if (final_cnt == 0) { + if ((*ch_wd == CH_WIDTH_160MHZ) || + (*ch_wd == CH_WIDTH_80P80MHZ) || + (*ch_wd == CH_WIDTH_80MHZ)) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_WARN, + FL("sapdfs:Changing chanWidth from [%d] to 40Mhz"), + *ch_wd); + *ch_wd = CH_WIDTH_40MHZ; + } else if (*ch_wd == CH_WIDTH_40MHZ) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_WARN, + FL("sapdfs:No 40MHz cb found, falling to 20MHz")); + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_WARN, + FL("sapdfs:Changing chanWidth from [%d] to [%d]"), + *ch_wd, CH_WIDTH_20MHZ); + *ch_wd = CH_WIDTH_20MHZ; + } + return 0; + } + + /* ch count should be > 8 to switch new channel in 160Mhz band */ + if (((*ch_wd == CH_WIDTH_160MHZ) || (*ch_wd == CH_WIDTH_80P80MHZ)) && + (final_cnt < SIR_DFS_MAX_20M_SUB_CH)) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_WARN, + FL("sapdfs:Changing chanWidth from [%d] to [%d]"), + *ch_wd, CH_WIDTH_80MHZ); + *ch_wd = CH_WIDTH_80MHZ; + return 0; + } + if (*ch_wd == CH_WIDTH_160MHZ) { + /* + * NA supports only 2 blocks for 160Mhz bandwidth i.e 36-64 & + * 100-128 and all the channels in these blocks are continuous + * and seperated by 4Mhz. + */ + for (i = 1; ((i < final_cnt)); i++) { + if ((final_lst[i] - final_lst[i-1]) == 4) + count++; + else + count = 0; + if (count == SIR_DFS_MAX_20M_SUB_CH - 1) { + flag = true; + new_160_start_ch = final_lst[i-7]; + break; + } + } + } else if (*ch_wd == CH_WIDTH_80P80MHZ) { + flag = true; + } + if ((flag == false) && (*ch_wd > CH_WIDTH_80MHZ)) { + *ch_wd = CH_WIDTH_80MHZ; + return 0; + } + + if (*ch_wd == CH_WIDTH_160MHZ) { + cds_rand_get_bytes(0, (uint8_t *)&rand_byte, 1); + rand_byte = (rand_byte + qdf_mc_timer_get_system_ticks()) + % SIR_DFS_MAX_20M_SUB_CH; + target_channel = new_160_start_ch + (rand_byte * 4); + } else if (*ch_wd == CH_WIDTH_80P80MHZ) { + cds_rand_get_bytes(0, (uint8_t *)&rand_byte, 1); + index = (rand_byte + qdf_mc_timer_get_system_ticks()) % + final_cnt; + target_channel = final_lst[index]; + index -= (index % 4); + primary_seg_start_ch = final_lst[index]; + + /* reset channels associate with primary 80Mhz */ + for (i = 0; i < 4; i++) + final_lst[i + index] = 0; + /* select and calculate center freq for secondary segement */ + for (i = 0; i < final_cnt / 4; i++) { + if (final_lst[i * 4] && + (abs(primary_seg_start_ch - final_lst[i * 4]) > + (SIR_DFS_MAX_20M_SUB_CH * 2))) { + sec_seg_ch = final_lst[i * 4] + + SIR_80MHZ_START_CENTER_CH_DIFF; + break; + } + } + if (!sec_seg_ch && (final_cnt == SIR_DFS_MAX_20M_SUB_CH)) + *ch_wd = CH_WIDTH_160MHZ; + else if (!sec_seg_ch) + *ch_wd = CH_WIDTH_80MHZ; + + mac_ctx->sap.SapDfsInfo.new_ch_params.center_freq_seg1 + = sec_seg_ch; + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_LOW, + FL("sapdfs: New Center Freq Seg1 = %d"), sec_seg_ch); + } else { + target_channel = select_rand_from_lst(mac_ctx, final_lst, + final_cnt); + } + return target_channel; +} + +/** + * sap_random_channel_sel() - This function randomly pick up an available + * channel + * @sap_ctx: sap context. + * + * This function first eliminates invalid channel, then selects random channel + * using following algorithm: + * PASS: 1 - invalidate ch in sap_ctx->all_ch_lst as per rules + * PASS: 2 - now mark channels that will leak into NOL + * PASS: 3 - from leakage_adjusted_lst, either select random channel (for 20MHz) + * or find given channel width possible. if not found fallback to + * lower channel width and try again. once given channel width found + * use random channel from give possibilities. + * Return: channel number picked + */ +static uint8_t sap_random_channel_sel(ptSapContext sap_ctx) +{ + uint8_t j = 0, i = 0, final_cnt = 0, target_channel = 0; + /* count and ch list after applying all rules */ + uint8_t rule_adjusted_cnt, *rule_adjusted_lst; + /* ch list after invalidating channels leaking into NOL */ + uint8_t *leakage_adjusted_lst; + /* final list of channel from which random channel will be selected */ + uint8_t final_lst[QDF_MAX_NUM_CHAN] = {0}; + tAll5GChannelList *all_ch = &sap_ctx->SapAllChnlList; + tHalHandle hal = CDS_GET_HAL_CB(sap_ctx->p_cds_gctx); + tpAniSirGlobal mac_ctx; + /* channel width for current iteration */ + enum phy_ch_width ch_wd; +#ifdef WLAN_ENABLE_CHNL_MATRIX_RESTRICTION + tSapDfsNolInfo *nol; +#endif + + if (NULL == hal) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("invalid hal")); + return 0; + } + + mac_ctx = PMAC_STRUCT(hal); + if (NULL == mac_ctx) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("invalid mac_ctx")); + return 0; + } + + /* + * Retrieve the original one and store it. + * use the stored original value when you call this function next time + * so fall back mechanism always starts with original ini value. + */ + if (mac_ctx->sap.SapDfsInfo.orig_chanWidth == 0) { + ch_wd = sap_ctx->ch_width_orig; + mac_ctx->sap.SapDfsInfo.orig_chanWidth = ch_wd; + } else { + ch_wd = mac_ctx->sap.SapDfsInfo.orig_chanWidth; + } + + if (sap_get_5ghz_channel_list(sap_ctx)) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_LOW, + FL("Getting 5Ghz channel list failed")); + return 0; + } + + /* PASS: 1 - invalidate ch in sap_ctx->all_ch_lst as per rules */ + rule_adjusted_cnt = sap_apply_rules(sap_ctx); + if (0 == rule_adjusted_cnt) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("No channels left after applying rules.")); + return 0; + } + + /* this is list we get after applying all rules */ + rule_adjusted_lst = qdf_mem_malloc(rule_adjusted_cnt); + + /* list adjusted after leakage has been marked */ + leakage_adjusted_lst = qdf_mem_malloc(rule_adjusted_cnt); + if (rule_adjusted_lst == NULL || leakage_adjusted_lst == NULL) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("sapdfs: memory alloc failed")); + qdf_mem_free(rule_adjusted_lst); + qdf_mem_free(leakage_adjusted_lst); + return 0; + } + + /* copy valid ch from sap_ctx->all_ch_lst into rule_adjusted_lst */ + for (i = 0, j = 0; i < all_ch->numChannel; i++) { + if (!all_ch->channelList[i].valid) + continue; + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_LOW, + FL("sapdfs: Adding Channel = %d to temp List"), + all_ch->channelList[i].channel); + rule_adjusted_lst[j++] = all_ch->channelList[i].channel; + } + + /* + * do - while loop for fallback mechanism. at each channel width this + * will try to find channel bonding, if not fall back to lower ch width + */ + do { + /* save rules adjusted lst */ + qdf_mem_copy(leakage_adjusted_lst, rule_adjusted_lst, + rule_adjusted_cnt); +#ifdef WLAN_ENABLE_CHNL_MATRIX_RESTRICTION + nol = mac_ctx->sap.SapDfsInfo.sapDfsChannelNolList; + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("sapdfs: Processing tmp ch list against NOL.")); + /* PASS: 2 - now mark channels that will leak into NOL */ + if (sap_mark_leaking_ch(sap_ctx, ch_wd, nol, rule_adjusted_cnt, + leakage_adjusted_lst) != QDF_STATUS_SUCCESS) { + qdf_mem_free(rule_adjusted_lst); + qdf_mem_free(leakage_adjusted_lst); + return 0; + } +#endif + if (ch_wd == CH_WIDTH_20MHZ) { + /* + * PASS: 3 - from leakage_adjusted_lst, prepare valid + * ch list and use random number from that + */ + for (i = 0; i < rule_adjusted_cnt; i++) { + if (leakage_adjusted_lst[i] == 0) + continue; + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_DEBUG, + FL("sapdfs: Channel=%d added to available list"), + leakage_adjusted_lst[i]); + final_lst[final_cnt] = leakage_adjusted_lst[i]; + final_cnt++; + } + target_channel = select_rand_from_lst(mac_ctx, + final_lst, final_cnt); + break; + } + + /* + * PASS: 3 - following function will check from valid channels + * left if given ch_wd can be supported. if not reduce ch_wd + * (fallback), then continue with reduced ch_wd + */ + target_channel = sap_find_ch_wh_fallback(mac_ctx, &ch_wd, + leakage_adjusted_lst, + rule_adjusted_cnt); + /* + * if target channel is 0, no channel bonding was found + * ch_wd would have been updated for fallback + */ + if (0 == target_channel) + continue; + else + break; + } while (true); + + if (target_channel) { + mac_ctx->sap.SapDfsInfo.new_chanWidth = ch_wd; + mac_ctx->sap.SapDfsInfo.new_ch_params.ch_width = ch_wd; + } + + qdf_mem_free(rule_adjusted_lst); + qdf_mem_free(leakage_adjusted_lst); + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_LOW, + FL("sapdfs: New Channel width = %d"), + mac_ctx->sap.SapDfsInfo.new_chanWidth); + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_LOW, + FL("sapdfs: target_channel = %d"), + target_channel); + return target_channel; +} + +/** + * sap_mark_dfs_channels() - to mark dfs channel + * @sapContext: pointer sap context + * @channels: list of channels + * @numChannels: number of channels + * @time: time + * + * Mark the channels in NOL with time and eSAP_DFS_CHANNEL_UNAVAILABLE + * + * Return: none + */ +static void sap_mark_dfs_channels(ptSapContext sapContext, uint8_t *channels, + uint8_t numChannels, uint64_t time) +{ + int i, j; + tSapDfsNolInfo *psapDfsChannelNolList = NULL; + uint8_t nRegDomainDfsChannels; + tHalHandle hHal; + tpAniSirGlobal pMac; + uint64_t time_elapsed_since_last_radar; + uint64_t time_when_radar_found; + + hHal = CDS_GET_HAL_CB(sapContext->p_cds_gctx); + if (NULL == channels) + return; + if (NULL == hHal) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("invalid hHal")); + return; + } + pMac = PMAC_STRUCT(hHal); + if (NULL == pMac) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("invalid pMac")); + return; + } + + /* + * Mark the current channel on which Radar is found + * in the NOL list as eSAP_DFS_CHANNEL_UNAVAILABLE. + */ + psapDfsChannelNolList = pMac->sap.SapDfsInfo.sapDfsChannelNolList; + nRegDomainDfsChannels = + pMac->sap.SapDfsInfo.numCurrentRegDomainDfsChannels; + + for (i = 0; i < numChannels; i++) { + for (j = 0; j <= nRegDomainDfsChannels; j++) { + if (!(psapDfsChannelNolList[j].dfs_channel_number == + channels[i])) + continue; + + time_when_radar_found = + psapDfsChannelNolList[j].radar_found_timestamp; + time_elapsed_since_last_radar = time - + time_when_radar_found; + /* + * If channel is already in NOL, don't update it again. + * This is useful when marking bonding channels which + * are already unavailable. + */ + if ((psapDfsChannelNolList[j].radar_status_flag == + eSAP_DFS_CHANNEL_UNAVAILABLE) && + (time_elapsed_since_last_radar < + SAP_DFS_NON_OCCUPANCY_PERIOD)) { + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_INFO_HIGH, + FL("Channel=%d already in NOL"), + channels[i]); + continue; + } + /* + * Capture the Radar Found timestamp on the + * Current Channel in ms. + */ + psapDfsChannelNolList[j].radar_found_timestamp = time; + /* Mark the Channel to be unavailble for next 30 mins */ + psapDfsChannelNolList[j].radar_status_flag = + eSAP_DFS_CHANNEL_UNAVAILABLE; + + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_INFO_HIGH, + FL("Channel=%d Added to NOL LIST"), + channels[i]); + } + } +} + +/* + * This Function is to get bonding channels from primary channel. + * + */ +static uint8_t sap_get_bonding_channels(ptSapContext sapContext, + uint8_t channel, + uint8_t *channels, uint8_t size, + ePhyChanBondState chanBondState) +{ + tHalHandle hHal = CDS_GET_HAL_CB(sapContext->p_cds_gctx); + tpAniSirGlobal pMac; + uint8_t numChannel; + + if (channels == NULL) + return 0; + + if (size < MAX_BONDED_CHANNELS) + return 0; + + if (NULL != hHal) { + pMac = PMAC_STRUCT(hHal); + } else + return 0; + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO, + FL("cbmode: %d, channel: %d"), chanBondState, channel); + + switch (chanBondState) { + case PHY_SINGLE_CHANNEL_CENTERED: + numChannel = 1; + channels[0] = channel; + break; + case PHY_DOUBLE_CHANNEL_HIGH_PRIMARY: + numChannel = 2; + channels[0] = channel - 4; + channels[1] = channel; + break; + case PHY_DOUBLE_CHANNEL_LOW_PRIMARY: + numChannel = 2; + channels[0] = channel; + channels[1] = channel + 4; + break; + case PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_LOW: + numChannel = 4; + channels[0] = channel; + channels[1] = channel + 4; + channels[2] = channel + 8; + channels[3] = channel + 12; + break; + case PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_LOW: + numChannel = 4; + channels[0] = channel - 4; + channels[1] = channel; + channels[2] = channel + 4; + channels[3] = channel + 8; + break; + case PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_HIGH: + numChannel = 4; + channels[0] = channel - 8; + channels[1] = channel - 4; + channels[2] = channel; + channels[3] = channel + 4; + break; + case PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_HIGH: + numChannel = 4; + channels[0] = channel - 12; + channels[1] = channel - 8; + channels[2] = channel - 4; + channels[3] = channel; + break; + default: + numChannel = 1; + channels[0] = channel; + break; + } + + return numChannel; +} + +/** + * sap_dfs_check_if_channel_avaialable() - Check if a channel is out of NOL + * @nol: Pointer to the Non-Occupancy List. + * + * This function Checks if a given channel is available or + * usable or unavailable based on the time lapse since the + * last radar time stamp. + * + * Return: true if channel available or usable, false if unavailable. + */ +static bool sap_dfs_check_if_channel_avaialable(tSapDfsNolInfo *nol) +{ + uint64_t time_since_last_radar, time_when_radar_found, current_time = 0; + uint64_t max_jiffies; + + if ((nol->radar_status_flag == eSAP_DFS_CHANNEL_USABLE) || + (nol->radar_status_flag == eSAP_DFS_CHANNEL_AVAILABLE)) { + /* + * Allow SAP operation on this channel + * either the DFS channel has not been used + * for SAP operation or it is available for + * SAP operation since it is past + * Non-Occupancy-Period so, return false. + */ + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_LOW, + FL("Chan=%d not in NOL,CHAN AVAILABLE"), + nol->dfs_channel_number); + return true; + } else if (nol->radar_status_flag == eSAP_DFS_CHANNEL_UNAVAILABLE) { + /* + * If a DFS Channel is UNAVAILABLE then + * check to see if it is past + * Non-occupancy-period + * of 30 minutes. If it is past 30 mins then + * mark the channel as AVAILABLE and return + * false as the channel is not anymore in + * NON-Occupancy-Period. + */ + time_when_radar_found = nol->radar_found_timestamp; + current_time = cds_get_monotonic_boottime(); + if (current_time < time_when_radar_found) { + /* cds_get_monotonic_boottime() can overflow. + * Jiffies is initialized such that 32 bit jiffies + * value wrap 5 minutes after boot so jiffies wrap bugs + * show up earlier + */ + max_jiffies = (uint64_t)UINT_MAX * 1000; + time_since_last_radar = (max_jiffies - + time_when_radar_found) + (current_time); + } else { + time_since_last_radar = current_time - + time_when_radar_found; + } + if (time_since_last_radar >= SAP_DFS_NON_OCCUPANCY_PERIOD) { + nol->radar_status_flag = eSAP_DFS_CHANNEL_AVAILABLE; + nol->radar_found_timestamp = 0; + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_LOW, + FL("Chan=%d not in NOL, Channel AVAILABLE"), + nol->dfs_channel_number); + return true; + } else { + /* + * Channel is not still available for + * SAP operation so return true; As the + * Channel is still in + * Non-occupancy-Period. + */ + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_LOW, + FL("Chan=%d in NOL, Channel UNAVAILBLE"), + nol->dfs_channel_number); + return false; + } + } else { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("Invalid Radar Status Flag")); + } + return true; +} + +/** + * sap_dfs_is_channel_in_nol_list() - given bonded channel is available + * @sap_context: Handle to SAP context. + * @channel_number: Channel on which availability should be checked. + * @chan_bondState: The channel bonding mode of the passed channel. + * + * This function Checks if a given bonded channel is available or + * usable for DFS operation. + * + * Return: false if channel is available, true if channel is in NOL. + */ +bool +sap_dfs_is_channel_in_nol_list(ptSapContext sap_context, + uint8_t channel_number, + ePhyChanBondState chan_bondState) +{ + int i, j; + tHalHandle h_hal = CDS_GET_HAL_CB(sap_context->p_cds_gctx); + tpAniSirGlobal mac_ctx; + uint8_t channels[MAX_BONDED_CHANNELS]; + uint8_t num_channels; + tSapDfsNolInfo *nol; + tSapDfsInfo *dfs_info; + bool channel_available; + + if (NULL == h_hal) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("invalid h_hal")); + return false; + } else { + mac_ctx = PMAC_STRUCT(h_hal); + } + + dfs_info = &mac_ctx->sap.SapDfsInfo; + if ((dfs_info->numCurrentRegDomainDfsChannels == 0) || + (dfs_info->numCurrentRegDomainDfsChannels > + NUM_5GHZ_CHANNELS)) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_LOW, + FL("invalid dfs channel count %d"), + dfs_info->numCurrentRegDomainDfsChannels); + return false; + } + + /* get the bonded channels */ + num_channels = sap_get_bonding_channels(sap_context, channel_number, + channels, MAX_BONDED_CHANNELS, chan_bondState); + + /* check for NOL, first on will break the loop */ + for (j = 0; j < num_channels; j++) { + for (i = 0; i < dfs_info->numCurrentRegDomainDfsChannels; i++) { + nol = &dfs_info->sapDfsChannelNolList[i]; + if (nol->dfs_channel_number != channels[j]) + continue; + + channel_available = + sap_dfs_check_if_channel_avaialable(nol); + + if (channel_available == false) + break; + + } /* loop for dfs channels */ + + if (i < dfs_info->numCurrentRegDomainDfsChannels) + break; + + } /* loop for bonded channels */ + + /* + * if any of the channel is not available, mark all available channels + * as unavailable with same time stamp. + */ + if (j < num_channels && + i < dfs_info->numCurrentRegDomainDfsChannels) { + if (num_channels > MAX_BONDED_CHANNELS) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_WARN, + FL("num_channel>MAX_BONDED_CHANNEL, reset")); + num_channels = MAX_BONDED_CHANNELS; + } + nol = &dfs_info->sapDfsChannelNolList[i]; + sap_mark_dfs_channels(sap_context, channels, num_channels, + nol->radar_found_timestamp); + + /* set DFS-NOL back to keep it update-to-date in CNSS */ + sap_signal_hdd_event(sap_context, NULL, eSAP_DFS_NOL_SET, + (void *) eSAP_STATUS_SUCCESS); + + return true; + } + + return false; +} + +/** + * sap_select_default_oper_chan() - Select operating channel based on acs hwmode + * @hal: pointer to HAL + * @acs_hwmode: HW mode of ACS + * + * Return: selected operating channel + */ +uint8_t sap_select_default_oper_chan(tHalHandle hal, uint32_t acs_hwmode) +{ + uint8_t channel; + + if ((acs_hwmode == QCA_ACS_MODE_IEEE80211A) || + (acs_hwmode == QCA_ACS_MODE_IEEE80211AD)) + channel = SAP_DEFAULT_5GHZ_CHANNEL; + else + channel = SAP_DEFAULT_24GHZ_CHANNEL; + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO, + FL("channel selected to start bss %d"), channel); + return channel; +} + +/** + * sap_goto_channel_sel - Function for initiating scan request for SME + * @sap_context: Sap Context value. + * @sap_event: State machine event + * @sap_do_acs_pre_start_bss: true, if ACS scan is issued pre start BSS + * false, if ACS scan is issued post start BSS. + * @check_for_connection_update: true, check and wait for connection update + * false, do not perform connection update + * + * Initiates sme scan for ACS to pick a channel. + * + * Return: The QDF_STATUS code associated with performing the operation. + */ +QDF_STATUS sap_goto_channel_sel(ptSapContext sap_context, + ptWLAN_SAPEvent sap_event, + bool sap_do_acs_pre_start_bss, + bool check_for_connection_update) +{ + + /* Initiate a SCAN request */ + QDF_STATUS qdf_ret_status; + /* To be initialised if scan is required */ + tCsrScanRequest scan_request; + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + tpAniSirGlobal mac_ctx; + +#ifdef SOFTAP_CHANNEL_RANGE + uint8_t *channel_list = NULL; + uint8_t num_of_channels = 0; +#endif + tHalHandle h_hal; + uint8_t con_ch; + + h_hal = cds_get_context(QDF_MODULE_ID_SME); + if (NULL == h_hal) { + /* we have a serious problem */ + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_FATAL, + FL("invalid h_hal")); + return QDF_STATUS_E_FAULT; + } + + mac_ctx = PMAC_STRUCT(h_hal); + if (NULL == mac_ctx) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("Invalid MAC context")); + return QDF_STATUS_E_FAILURE; + } + + if (cds_concurrent_beaconing_sessions_running()) { + con_ch = + sme_get_concurrent_operation_channel(h_hal); +#ifdef FEATURE_WLAN_STA_AP_MODE_DFS_DISABLE + if (con_ch && sap_context->channel == AUTO_CHANNEL_SELECT) { + sap_context->dfs_ch_disable = true; + } else if (con_ch && sap_context->channel != con_ch && + CDS_IS_DFS_CH(sap_context->channel)) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_WARN, + FL("MCC DFS not supported in AP_AP Mode")); + return QDF_STATUS_E_ABORTED; + } +#endif +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH + if (sap_context->cc_switch_mode != + QDF_MCC_TO_SCC_SWITCH_DISABLE && + sap_context->channel) { + /* + * For ACS request ,the sapContext->channel is 0, + * we skip below overlap checking. When the ACS + * finish and SAPBSS start, the sapContext->channel + * will not be 0. Then the overlap checking will be + * reactivated.If we use sapContext->channel = 0 + * to perform the overlap checking, an invalid overlap + * channel con_ch could becreated. That may cause + * SAP start failed. + */ + con_ch = sme_check_concurrent_channel_overlap(h_hal, + sap_context->channel, + sap_context->csr_roamProfile.phyMode, + sap_context->cc_switch_mode); + if (con_ch) { + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_ERROR, + "%s: Override ch %d to %d due to CC Intf", + __func__, sap_context->channel, con_ch); + sap_context->channel = con_ch; + cds_set_channel_params(sap_context->channel, 0, + &sap_context->ch_params); + } + } +#endif + } + + if (cds_get_concurrency_mode() == (QDF_STA_MASK | QDF_SAP_MASK)) { +#ifdef FEATURE_WLAN_STA_AP_MODE_DFS_DISABLE + if (sap_context->channel == AUTO_CHANNEL_SELECT) + sap_context->dfs_ch_disable = true; + else if (CDS_IS_DFS_CH(sap_context->channel)) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_WARN, + FL("DFS not supported in STA_AP Mode")); + return QDF_STATUS_E_ABORTED; + } +#endif +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH + if (sap_context->cc_switch_mode != + QDF_MCC_TO_SCC_SWITCH_DISABLE && + sap_context->channel) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO, + FL("check for overlap: chan:%d mode:%d"), + sap_context->channel, + sap_context->csr_roamProfile.phyMode); + con_ch = sme_check_concurrent_channel_overlap(h_hal, + sap_context->channel, + sap_context->csr_roamProfile.phyMode, + sap_context->cc_switch_mode); + if (con_ch && !CDS_IS_DFS_CH(con_ch)) { + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_ERROR, + "%s: Override ch %d to %d due to CC Intf", + __func__, sap_context->channel, con_ch); + sap_context->channel = con_ch; + cds_set_channel_params(sap_context->channel, 0, + &sap_context->ch_params); + } + } +#endif + } + + if (sap_context->channel == AUTO_CHANNEL_SELECT) { +#ifdef FEATURE_WLAN_AP_AP_ACS_OPTIMIZE + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + FL("%s skip_acs_status = %d "), __func__, + sap_context->acs_cfg->skip_scan_status); + if (sap_context->acs_cfg->skip_scan_status != + eSAP_SKIP_ACS_SCAN) { +#endif + qdf_mem_zero(&scan_request, sizeof(scan_request)); + + /* + * Set scanType to Active scan. FW takes care of using passive + * scan for DFS and active for non DFS channels. + */ + scan_request.scanType = eSIR_ACTIVE_SCAN; + + /* Set min and max channel time to zero */ + scan_request.minChnTime = 0; + scan_request.maxChnTime = 0; + + /* Set BSSType to default type */ + scan_request.BSSType = eCSR_BSS_TYPE_ANY; + +#ifndef SOFTAP_CHANNEL_RANGE + /*Scan all the channels */ + scan_request.ChannelInfo.num_of_channels = 0; + + scan_request.ChannelInfo.ChannelList = NULL; + + scan_request.requestType = eCSR_SCAN_REQUEST_FULL_SCAN; + /* eCSR_SCAN_REQUEST_11D_SCAN; */ + +#else + + sap_get_channel_list(sap_context, &channel_list, + &num_of_channels); +#ifdef FEATURE_WLAN_AP_AP_ACS_OPTIMIZE + if (num_of_channels != 0) { +#endif + /*Scan the channels in the list */ + scan_request.ChannelInfo.numOfChannels = + num_of_channels; + + scan_request.ChannelInfo.ChannelList = + channel_list; + + scan_request.requestType = + eCSR_SCAN_SOFTAP_CHANNEL_RANGE; + + sap_context->channelList = channel_list; + sap_context->num_of_channel = num_of_channels; +#endif + /* Set requestType to Full scan */ + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + FL("calling sme_scan_request")); +#ifdef FEATURE_WLAN_AP_AP_ACS_OPTIMIZE + if (sap_context->acs_cfg->skip_scan_status == + eSAP_DO_NEW_ACS_SCAN) +#endif + sme_scan_flush_result(h_hal); + if (true == sap_do_acs_pre_start_bss) { + /* + * when ID == 0 11D scan/active scan with callback, + * min-maxChntime set in csrScanRequest()? + * csrScanCompleteCallback callback + * pContext scan_request_id filled up + */ + qdf_ret_status = sme_scan_request(h_hal, + sap_context->sessionId, + &scan_request, + &wlansap_pre_start_bss_acs_scan_callback, + sap_context); + } else { + /* + * when ID == 0 11D scan/active scan with callback, + * min-maxChntime set in csrScanRequest()? + * csrScanCompleteCallback callback, + * pContext scan_request_id filled up + */ + qdf_ret_status = sme_scan_request(h_hal, + sap_context->sessionId, + &scan_request, + &wlansap_scan_callback, + sap_context); + } + if (QDF_STATUS_SUCCESS != qdf_ret_status) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("sme_scan_request fail %d!!!"), + qdf_ret_status); + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + FL("SAP Configuring default channel, Ch=%d"), + sap_context->channel); + sap_context->channel = + sap_select_default_oper_chan(h_hal, + sap_context->acs_cfg->hw_mode); + +#ifdef SOFTAP_CHANNEL_RANGE + if (sap_context->channelList != NULL) { + sap_context->channel = + sap_context->channelList[0]; + qdf_mem_free(sap_context-> + channelList); + sap_context->channelList = NULL; + sap_context->num_of_channel = 0; + } +#endif + if (true == sap_do_acs_pre_start_bss) { + /* + * In case of ACS req before start Bss, + * return failure so that the calling + * fucntion can use the default channel. + */ + return QDF_STATUS_E_FAILURE; + } else { + /* Fill in the event structure */ + sap_event_init(sap_event); + /* Handle event */ + qdf_status = sap_fsm(sap_context, sap_event); + } + } else { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + FL("return sme_ScanReq, scanID=%d, Ch=%d"), + scan_request.scan_id, sap_context->channel); + } +#ifdef FEATURE_WLAN_AP_AP_ACS_OPTIMIZE + } + } else { + sap_context->acs_cfg->skip_scan_status = eSAP_SKIP_ACS_SCAN; + } + + if (sap_context->acs_cfg->skip_scan_status == eSAP_SKIP_ACS_SCAN) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("## %s SKIPPED ACS SCAN"), __func__); + wlansap_scan_callback(h_hal, sap_context, + sap_context->sessionId, 0, eCSR_SCAN_SUCCESS); + } +#endif + } else { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + FL("for configured channel, Ch= %d"), + sap_context->channel); + + if (check_for_connection_update) { + /* This wait happens in the hostapd context. The event + * is set in the MC thread context. + */ + qdf_status = cds_update_and_wait_for_connection_update( + sap_context->sessionId, + sap_context->channel, + SIR_UPDATE_REASON_START_AP); + if (QDF_IS_STATUS_ERROR(qdf_status)) + return qdf_status; + } + + if (sap_do_acs_pre_start_bss == true) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO, + FL("ACS end due to Ch override. Sel Ch = %d"), + sap_context->channel); + sap_context->acs_cfg->pri_ch = sap_context->channel; + sap_context->acs_cfg->ch_width = + sap_context->ch_width_orig; + sap_config_acs_result(h_hal, sap_context, 0); + return QDF_STATUS_E_CANCELED; + } else { + /* + * Fill in the event structure + * Eventhough scan was not done, + * means a user set channel was chosen + */ + sap_event_init(sap_event); + /* Handle event */ + qdf_status = sap_fsm(sap_context, sap_event); + } + } + + /* + * If scan failed, get default channel and advance state + * machine as success with default channel + * + * Have to wait for the call back to be called to get the + * channel cannot advance state machine here as said above + */ + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + FL("before exiting sap_goto_channel_sel channel=%d"), + sap_context->channel); + + return QDF_STATUS_SUCCESS; +} + +/** + * sap_open_session() - Opens a SAP session + * @hHal: Hal handle + * @sapContext: Sap Context value + * @session_id: Pointer to the session id + * + * Function for opening SME and SAP sessions when system is in SoftAP role + * + * Return: QDF_STATUS + */ +QDF_STATUS sap_open_session(tHalHandle hHal, ptSapContext sapContext, + uint32_t *session_id) +{ + uint32_t type, subType; + QDF_STATUS qdf_ret_status; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + if (sapContext->csr_roamProfile.csrPersona == QDF_P2P_GO_MODE) + status = cds_get_vdev_types(QDF_P2P_GO_MODE, &type, &subType); + else + status = cds_get_vdev_types(QDF_SAP_MODE, &type, &subType); + + if (QDF_STATUS_SUCCESS != status) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_FATAL, + "failed to get vdev type"); + return QDF_STATUS_E_FAILURE; + } + + qdf_event_reset(&sapContext->sap_session_opened_evt); + /* Open SME Session for Softap */ + qdf_ret_status = sme_open_session(hHal, + &wlansap_roam_callback, + sapContext, + sapContext->self_mac_addr, + &sapContext->sessionId, type, subType); + + if (QDF_STATUS_SUCCESS != qdf_ret_status) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "Error: In %s calling sme_roam_connect status = %d", + __func__, qdf_ret_status); + + return QDF_STATUS_E_FAILURE; + } + + status = qdf_wait_single_event(&sapContext->sap_session_opened_evt, + SME_CMD_TIMEOUT_VALUE); + + if (!QDF_IS_STATUS_SUCCESS(status)) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "wait for sap open session event timed out"); + return QDF_STATUS_E_FAILURE; + } + + pMac->sap.sapCtxList[sapContext->sessionId].sessionID = + sapContext->sessionId; + pMac->sap.sapCtxList[sapContext->sessionId].pSapContext = sapContext; + pMac->sap.sapCtxList[sapContext->sessionId].sapPersona = + sapContext->csr_roamProfile.csrPersona; + *session_id = sapContext->sessionId; + sapContext->isSapSessionOpen = eSAP_TRUE; + sapContext->is_pre_cac_on = false; + sapContext->pre_cac_complete = false; + sapContext->chan_before_pre_cac = 0; + return QDF_STATUS_SUCCESS; +} + +/*========================================================================== + FUNCTION sapGotoStarting + + DESCRIPTION + Function for initiating start bss request for SME + + DEPENDENCIES + NA. + + PARAMETERS + + IN + sapContext : Sap Context value + sapEvent : State machine event + bssType : Type of bss to start, INRA AP + status : Return the SAP status here + + RETURN VALUE + The QDF_STATUS code associated with performing the operation + + QDF_STATUS_SUCCESS: Success + + SIDE EFFECTS + ============================================================================*/ +static QDF_STATUS sap_goto_starting(ptSapContext sapContext, + ptWLAN_SAPEvent sapEvent, + eCsrRoamBssType bssType) +{ + /* tHalHandle */ + tHalHandle hHal = CDS_GET_HAL_CB(sapContext->p_cds_gctx); + QDF_STATUS qdf_ret_status; + + /*- - - - - - - - TODO:once configs from hdd available - - - - - - - - -*/ + char key_material[32] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, + 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, }; + sapContext->key_type = 0x05; + sapContext->key_length = 32; + /* Need a key size define */ + qdf_mem_copy(sapContext->key_material, key_material, + sizeof(key_material)); + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, "In %s", + __func__); + + if (NULL == hHal) { + /* we have a serious problem */ + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_FATAL, + "In %s, invalid hHal", __func__); + return QDF_STATUS_E_FAULT; + } + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO, "%s: session: %d", + __func__, sapContext->sessionId); + + qdf_ret_status = sme_roam_connect(hHal, sapContext->sessionId, + &sapContext->csr_roamProfile, + &sapContext->csr_roamId); + if (QDF_STATUS_SUCCESS != qdf_ret_status) + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Failed to issue sme_roam_connect", __func__); + + return qdf_ret_status; +} /* sapGotoStarting */ + +/*========================================================================== + FUNCTION sapGotoDisconnecting + + DESCRIPTION + Processing of SAP FSM Disconnecting state + + DEPENDENCIES + NA. + + PARAMETERS + + IN + sapContext : Sap Context value + status : Return the SAP status here + + RETURN VALUE + The QDF_STATUS code associated with performing the operation + + QDF_STATUS_SUCCESS: Success + + SIDE EFFECTS + ============================================================================*/ +static QDF_STATUS sap_goto_disconnecting(ptSapContext sapContext) +{ + QDF_STATUS qdf_ret_status; + tHalHandle hHal; + + hHal = CDS_GET_HAL_CB(sapContext->p_cds_gctx); + if (NULL == hHal) { + /* we have a serious problem */ + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "In %s, invalid hHal", __func__); + return QDF_STATUS_E_FAULT; + } + + sap_free_roam_profile(&sapContext->csr_roamProfile); + qdf_ret_status = sme_roam_stop_bss(hHal, sapContext->sessionId); + if (QDF_STATUS_SUCCESS != qdf_ret_status) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "Error: In %s calling sme_roam_stop_bss status = %d", + __func__, qdf_ret_status); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS sap_roam_session_close_callback(void *pContext) +{ + ptSapContext sapContext = (ptSapContext) pContext; + QDF_STATUS status; + + status = wlansap_context_get(pContext); + if (status != QDF_STATUS_SUCCESS) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: sap context has already been freed", __func__); + return status; + } + + status = sap_signal_hdd_event(sapContext, NULL, + eSAP_STOP_BSS_EVENT, + (void *) eSAP_STATUS_SUCCESS); + + wlansap_context_put(pContext); + return status; +} + +/*========================================================================== + FUNCTION sapGotoDisconnected + + DESCRIPTION + Function for setting the SAP FSM to Disconnection state + + DEPENDENCIES + NA. + + PARAMETERS + + IN + sapContext : Sap Context value + sapEvent : State machine event + status : Return the SAP status here + + RETURN VALUE + The QDF_STATUS code associated with performing the operation + + QDF_STATUS_SUCCESS: Success + + SIDE EFFECTS + ============================================================================*/ +static QDF_STATUS sap_goto_disconnected(ptSapContext sapContext) +{ + QDF_STATUS qdf_status = QDF_STATUS_E_FAILURE; + tWLAN_SAPEvent sapEvent; + /* Processing has to be coded */ + /* Clean up stations from TL etc as AP BSS is shut down then set event */ + sapEvent.event = eSAP_MAC_READY_FOR_CONNECTIONS; /* hardcoded */ + sapEvent.params = 0; + sapEvent.u1 = 0; + sapEvent.u2 = 0; + /* Handle event */ + qdf_status = sap_fsm(sapContext, &sapEvent); + + return qdf_status; +} + +#ifdef FEATURE_WLAN_AP_AP_ACS_OPTIMIZE +/** + * sap_handle_acs_scan_event() - handle acs scan event for SAP + * @sap_context: ptSapContext + * @sap_event: tSap_Event + * @status: status of acs scan + * + * The function is to handle the eSAP_ACS_SCAN_SUCCESS_EVENT event. + * + * Return: void + */ +static void sap_handle_acs_scan_event(ptSapContext sap_context, + tSap_Event *sap_event, eSapStatus status) +{ + sap_event->sapHddEventCode = eSAP_ACS_SCAN_SUCCESS_EVENT; + sap_event->sapevt.sap_acs_scan_comp.status = status; + sap_event->sapevt.sap_acs_scan_comp.num_of_channels = + sap_context->num_of_channel; + sap_event->sapevt.sap_acs_scan_comp.channellist = + sap_context->channelList; +} +#else +static void sap_handle_acs_scan_event(ptSapContext sap_context, + tSap_Event *sap_event, eSapStatus status) +{ +} +#endif + +/** + * sap_signal_hdd_event() - send event notification + * @sap_ctx: Sap Context + * @csr_roaminfo: Pointer to CSR roam information + * @sap_hddevent: SAP HDD event + * @context: to pass the element for future support + * + * Function for HDD to send the event notification using callback + * + * Return: QDF_STATUS + */ +QDF_STATUS sap_signal_hdd_event(ptSapContext sap_ctx, + tCsrRoamInfo *csr_roaminfo, eSapHddEvent sap_hddevent, + void *context) +{ + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + tSap_Event sap_ap_event; /* This now encodes ALL event types */ + tHalHandle hal = CDS_GET_HAL_CB(sap_ctx->p_cds_gctx); + tpAniSirGlobal mac_ctx; + tSirSmeChanInfo *chaninfo; + tSap_StationAssocIndication *assoc_ind; + tSap_StartBssCompleteEvent *bss_complete; + struct sap_ch_selected_s *acs_selected; + tSap_StationAssocReassocCompleteEvent *reassoc_complete; + tSap_StationDisassocCompleteEvent *disassoc_comp; + tSap_StationSetKeyCompleteEvent *key_complete; + tSap_StationMICFailureEvent *mic_failure; + + /* Format the Start BSS Complete event to return... */ + if (NULL == sap_ctx->pfnSapEventCallback) { + QDF_ASSERT(0); + return QDF_STATUS_E_FAILURE; + } + if (NULL == hal) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("Invalid hal")); + return QDF_STATUS_E_FAILURE; + } + mac_ctx = PMAC_STRUCT(hal); + if (NULL == mac_ctx) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("Invalid MAC context")); + return QDF_STATUS_E_FAILURE; + } + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + FL("SAP event callback event = %s"), + sap_hdd_event_to_string(sap_hddevent)); + + switch (sap_hddevent) { + case eSAP_STA_ASSOC_IND: + if (!csr_roaminfo) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("Invalid CSR Roam Info")); + return QDF_STATUS_E_INVAL; + } + /* TODO - Indicate the assoc request indication to OS */ + sap_ap_event.sapHddEventCode = eSAP_STA_ASSOC_IND; + assoc_ind = &sap_ap_event.sapevt.sapAssocIndication; + + qdf_copy_macaddr(&assoc_ind->staMac, &csr_roaminfo->peerMac); + assoc_ind->staId = csr_roaminfo->staId; + assoc_ind->status = 0; + /* Required for indicating the frames to upper layer */ + assoc_ind->beaconLength = csr_roaminfo->beaconLength; + assoc_ind->beaconPtr = csr_roaminfo->beaconPtr; + assoc_ind->assocReqLength = csr_roaminfo->assocReqLength; + assoc_ind->assocReqPtr = csr_roaminfo->assocReqPtr; + assoc_ind->fWmmEnabled = csr_roaminfo->wmmEnabledSta; + if (csr_roaminfo->u.pConnectedProfile != NULL) { + assoc_ind->negotiatedAuthType = + csr_roaminfo->u.pConnectedProfile->AuthType; + assoc_ind->negotiatedUCEncryptionType = + csr_roaminfo->u.pConnectedProfile->EncryptionType; + assoc_ind->negotiatedMCEncryptionType = + csr_roaminfo->u.pConnectedProfile->mcEncryptionType; + assoc_ind->fAuthRequired = csr_roaminfo->fAuthRequired; + } + break; + case eSAP_START_BSS_EVENT: + sap_ap_event.sapHddEventCode = eSAP_START_BSS_EVENT; + bss_complete = &sap_ap_event.sapevt.sapStartBssCompleteEvent; + + bss_complete->status = (eSapStatus) context; + if (csr_roaminfo != NULL) + bss_complete->staId = csr_roaminfo->staId; + else + bss_complete->staId = 0; + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + FL("(eSAP_START_BSS_EVENT): staId = %d"), + bss_complete->staId); + + bss_complete->operatingChannel = (uint8_t) sap_ctx->channel; + bss_complete->sessionId = sap_ctx->sessionId; + break; + case eSAP_DFS_CAC_START: + case eSAP_DFS_CAC_INTERRUPTED: + case eSAP_DFS_CAC_END: + case eSAP_DFS_PRE_CAC_END: + case eSAP_DFS_RADAR_DETECT: + case eSAP_DFS_RADAR_DETECT_DURING_PRE_CAC: + case eSAP_DFS_NO_AVAILABLE_CHANNEL: + sap_ap_event.sapHddEventCode = sap_hddevent; + sap_ap_event.sapevt.sapStopBssCompleteEvent.status = + (eSapStatus) context; + break; + case eSAP_ACS_SCAN_SUCCESS_EVENT: + sap_handle_acs_scan_event(sap_ctx, &sap_ap_event, + (eSapStatus)context); + break; + case eSAP_ACS_CHANNEL_SELECTED: + sap_ap_event.sapHddEventCode = sap_hddevent; + acs_selected = &sap_ap_event.sapevt.sap_ch_selected; + if (eSAP_STATUS_SUCCESS == (eSapStatus)context) { + acs_selected->pri_ch = sap_ctx->acs_cfg->pri_ch; + acs_selected->ht_sec_ch = sap_ctx->acs_cfg->ht_sec_ch; + acs_selected->ch_width = sap_ctx->acs_cfg->ch_width; + acs_selected->vht_seg0_center_ch = + sap_ctx->acs_cfg->vht_seg0_center_ch; + acs_selected->vht_seg1_center_ch = + sap_ctx->acs_cfg->vht_seg1_center_ch; + } else if (eSAP_STATUS_FAILURE == (eSapStatus)context) { + acs_selected->pri_ch = 0; + } + break; + + case eSAP_STOP_BSS_EVENT: + sap_ap_event.sapHddEventCode = eSAP_STOP_BSS_EVENT; + sap_ap_event.sapevt.sapStopBssCompleteEvent.status = + (eSapStatus) context; + break; + + case eSAP_STA_ASSOC_EVENT: + case eSAP_STA_REASSOC_EVENT: + + if (!csr_roaminfo) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("Invalid CSR Roam Info")); + return QDF_STATUS_E_INVAL; + } + reassoc_complete = + &sap_ap_event.sapevt.sapStationAssocReassocCompleteEvent; + + if (csr_roaminfo->fReassocReq) + sap_ap_event.sapHddEventCode = eSAP_STA_REASSOC_EVENT; + else + sap_ap_event.sapHddEventCode = eSAP_STA_ASSOC_EVENT; + + qdf_copy_macaddr(&reassoc_complete->staMac, + &csr_roaminfo->peerMac); + reassoc_complete->staId = csr_roaminfo->staId; + reassoc_complete->statusCode = csr_roaminfo->statusCode; + reassoc_complete->iesLen = csr_roaminfo->rsnIELen; + qdf_mem_copy(reassoc_complete->ies, csr_roaminfo->prsnIE, + csr_roaminfo->rsnIELen); + +#ifdef FEATURE_WLAN_WAPI + if (csr_roaminfo->wapiIELen) { + uint8_t len = reassoc_complete->iesLen; + reassoc_complete->iesLen += csr_roaminfo->wapiIELen; + qdf_mem_copy(&reassoc_complete->ies[len], + csr_roaminfo->pwapiIE, + csr_roaminfo->wapiIELen); + } +#endif + if (csr_roaminfo->addIELen) { + uint8_t len = reassoc_complete->iesLen; + reassoc_complete->iesLen += csr_roaminfo->addIELen; + qdf_mem_copy(&reassoc_complete->ies[len], + csr_roaminfo->paddIE, + csr_roaminfo->addIELen); + } + + /* also fill up the channel info from the csr_roamInfo */ + chaninfo = &reassoc_complete->chan_info; + + chaninfo->chan_id = csr_roaminfo->chan_info.chan_id; + chaninfo->mhz = csr_roaminfo->chan_info.mhz; + chaninfo->info = csr_roaminfo->chan_info.info; + chaninfo->band_center_freq1 = + csr_roaminfo->chan_info.band_center_freq1; + chaninfo->band_center_freq2 = + csr_roaminfo->chan_info.band_center_freq2; + chaninfo->reg_info_1 = + csr_roaminfo->chan_info.reg_info_1; + chaninfo->reg_info_2 = + csr_roaminfo->chan_info.reg_info_2; + chaninfo->nss = csr_roaminfo->chan_info.nss; + chaninfo->rate_flags = csr_roaminfo->chan_info.rate_flags; + + reassoc_complete->wmmEnabled = csr_roaminfo->wmmEnabledSta; + reassoc_complete->status = (eSapStatus) context; + reassoc_complete->timingMeasCap = csr_roaminfo->timingMeasCap; + break; + + case eSAP_STA_DISASSOC_EVENT: + + if (!csr_roaminfo) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("Invalid CSR Roam Info")); + return QDF_STATUS_E_INVAL; + } + sap_ap_event.sapHddEventCode = eSAP_STA_DISASSOC_EVENT; + disassoc_comp = + &sap_ap_event.sapevt.sapStationDisassocCompleteEvent; + + qdf_copy_macaddr(&disassoc_comp->staMac, + &csr_roaminfo->peerMac); + disassoc_comp->staId = csr_roaminfo->staId; + if (csr_roaminfo->reasonCode == eCSR_ROAM_RESULT_FORCED) + disassoc_comp->reason = eSAP_USR_INITATED_DISASSOC; + else + disassoc_comp->reason = eSAP_MAC_INITATED_DISASSOC; + + disassoc_comp->statusCode = csr_roaminfo->statusCode; + disassoc_comp->status = (eSapStatus) context; + break; + + case eSAP_STA_SET_KEY_EVENT: + + if (!csr_roaminfo) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("Invalid CSR Roam Info")); + return QDF_STATUS_E_INVAL; + } + sap_ap_event.sapHddEventCode = eSAP_STA_SET_KEY_EVENT; + key_complete = + &sap_ap_event.sapevt.sapStationSetKeyCompleteEvent; + key_complete->status = (eSapStatus) context; + qdf_copy_macaddr(&key_complete->peerMacAddr, + &csr_roaminfo->peerMac); + break; + + case eSAP_STA_MIC_FAILURE_EVENT: + + if (!csr_roaminfo) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("Invalid CSR Roam Info")); + return QDF_STATUS_E_INVAL; + } + sap_ap_event.sapHddEventCode = eSAP_STA_MIC_FAILURE_EVENT; + mic_failure = &sap_ap_event.sapevt.sapStationMICFailureEvent; + + qdf_mem_copy(&mic_failure->srcMacAddr, + csr_roaminfo->u.pMICFailureInfo->srcMacAddr, + sizeof(tSirMacAddr)); + qdf_mem_copy(&mic_failure->staMac.bytes, + csr_roaminfo->u.pMICFailureInfo->taMacAddr, + sizeof(tSirMacAddr)); + qdf_mem_copy(&mic_failure->dstMacAddr.bytes, + csr_roaminfo->u.pMICFailureInfo->dstMacAddr, + sizeof(tSirMacAddr)); + mic_failure->multicast = + csr_roaminfo->u.pMICFailureInfo->multicast; + mic_failure->IV1 = csr_roaminfo->u.pMICFailureInfo->IV1; + mic_failure->keyId = csr_roaminfo->u.pMICFailureInfo->keyId; + qdf_mem_copy(mic_failure->TSC, + csr_roaminfo->u.pMICFailureInfo->TSC, + SIR_CIPHER_SEQ_CTR_SIZE); + break; + + case eSAP_ASSOC_STA_CALLBACK_EVENT: + break; + + case eSAP_WPS_PBC_PROBE_REQ_EVENT: + + if (!csr_roaminfo) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("Invalid CSR Roam Info")); + return QDF_STATUS_E_INVAL; + } + sap_ap_event.sapHddEventCode = eSAP_WPS_PBC_PROBE_REQ_EVENT; + + qdf_mem_copy(&sap_ap_event.sapevt.sapPBCProbeReqEvent. + WPSPBCProbeReq, csr_roaminfo->u.pWPSPBCProbeReq, + sizeof(tSirWPSPBCProbeReq)); + break; + + case eSAP_REMAIN_CHAN_READY: + sap_ap_event.sapHddEventCode = eSAP_REMAIN_CHAN_READY; + sap_ap_event.sapevt.sap_roc_ind.scan_id = + sap_ctx->roc_ind_scan_id; + break; + + case eSAP_DISCONNECT_ALL_P2P_CLIENT: + sap_ap_event.sapHddEventCode = eSAP_DISCONNECT_ALL_P2P_CLIENT; + sap_ap_event.sapevt.sapActionCnf.actionSendSuccess = + (eSapStatus) context; + break; + + case eSAP_MAC_TRIG_STOP_BSS_EVENT: + sap_ap_event.sapHddEventCode = eSAP_MAC_TRIG_STOP_BSS_EVENT; + sap_ap_event.sapevt.sapActionCnf.actionSendSuccess = + (eSapStatus) context; + break; + + case eSAP_UNKNOWN_STA_JOIN: + sap_ap_event.sapHddEventCode = eSAP_UNKNOWN_STA_JOIN; + qdf_mem_copy((void *) sap_ap_event.sapevt.sapUnknownSTAJoin. + macaddr.bytes, (void *) context, + QDF_MAC_ADDR_SIZE); + break; + + case eSAP_MAX_ASSOC_EXCEEDED: + + if (!csr_roaminfo) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("Invalid CSR Roam Info")); + return QDF_STATUS_E_INVAL; + } + sap_ap_event.sapHddEventCode = eSAP_MAX_ASSOC_EXCEEDED; + qdf_copy_macaddr(&sap_ap_event.sapevt. + sapMaxAssocExceeded.macaddr, + &csr_roaminfo->peerMac); + break; + + case eSAP_CHANNEL_CHANGE_EVENT: + /* + * Reconfig ACS result info. For DFS AP-AP Mode Sec AP ACS + * follows pri AP + */ + sap_ctx->acs_cfg->pri_ch = sap_ctx->channel; + sap_ctx->acs_cfg->ch_width = + sap_ctx->csr_roamProfile.ch_params.ch_width; + sap_config_acs_result(hal, sap_ctx, + sap_ctx->csr_roamProfile.ch_params.sec_ch_offset); + + sap_ap_event.sapHddEventCode = eSAP_CHANNEL_CHANGE_EVENT; + + acs_selected = &sap_ap_event.sapevt.sap_ch_selected; + acs_selected->pri_ch = sap_ctx->acs_cfg->pri_ch; + acs_selected->ht_sec_ch = + sap_ctx->csr_roamProfile.ch_params.sec_ch_offset; + acs_selected->ch_width = + sap_ctx->csr_roamProfile.ch_params.ch_width; + acs_selected->vht_seg0_center_ch = + sap_ctx->csr_roamProfile.ch_params.center_freq_seg0; + acs_selected->vht_seg1_center_ch = + sap_ctx->csr_roamProfile.ch_params.center_freq_seg1; + break; + + case eSAP_DFS_NOL_GET: + sap_ap_event.sapHddEventCode = eSAP_DFS_NOL_GET; + sap_ap_event.sapevt.sapDfsNolInfo.sDfsList = + NUM_5GHZ_CHANNELS * sizeof(tSapDfsNolInfo); + sap_ap_event.sapevt.sapDfsNolInfo.pDfsList = (void *) + (&mac_ctx->sap.SapDfsInfo.sapDfsChannelNolList[0]); + break; + + case eSAP_DFS_NOL_SET: + sap_ap_event.sapHddEventCode = eSAP_DFS_NOL_SET; + sap_ap_event.sapevt.sapDfsNolInfo.sDfsList = + mac_ctx->sap.SapDfsInfo.numCurrentRegDomainDfsChannels * + sizeof(tSapDfsNolInfo); + sap_ap_event.sapevt.sapDfsNolInfo.pDfsList = (void *) + (&mac_ctx->sap.SapDfsInfo.sapDfsChannelNolList[0]); + break; + case eSAP_ECSA_CHANGE_CHAN_IND: + + if (!csr_roaminfo) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("Invalid CSR Roam Info")); + return QDF_STATUS_E_INVAL; + } + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + "In %s, SAP event callback event = %s", + __func__, "eSAP_ECSA_CHANGE_CHAN_IND"); + sap_ap_event.sapHddEventCode = eSAP_ECSA_CHANGE_CHAN_IND; + sap_ap_event.sapevt.sap_chan_cng_ind.new_chan = + csr_roaminfo->target_channel; + break; + case eSAP_UPDATE_SCAN_RESULT: + if (!csr_roaminfo) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("Invalid CSR Roam Info")); + return QDF_STATUS_E_INVAL; + } + sap_ap_event.sapHddEventCode = eSAP_UPDATE_SCAN_RESULT; + sap_ap_event.sapevt.bss_desc = csr_roaminfo->pBssDesc; + break; + default: + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("SAP Unknown callback event = %d"), + sap_hddevent); + break; + } + qdf_status = (*sap_ctx->pfnSapEventCallback) + (&sap_ap_event, sap_ctx->pUsrContext); + + return qdf_status; + +} + +/*========================================================================== + FUNCTION sap_find_valid_concurrent_session + + DESCRIPTION + This function will return sapcontext of any valid sap session. + + PARAMETERS + + IN + hHal : HAL pointer + + RETURN VALUE + ptSapContext : valid sap context + + SIDE EFFECTS + NA + ============================================================================*/ +static ptSapContext sap_find_valid_concurrent_session(tHalHandle hHal) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + uint8_t intf = 0; + ptSapContext sapContext; + + for (intf = 0; intf < SAP_MAX_NUM_SESSION; intf++) { + if (((QDF_SAP_MODE == pMac->sap.sapCtxList[intf].sapPersona) + || + (QDF_P2P_GO_MODE == pMac->sap.sapCtxList[intf].sapPersona)) && + pMac->sap.sapCtxList[intf].pSapContext != NULL) { + sapContext = pMac->sap.sapCtxList[intf].pSapContext; + if (sapContext->sapsMachine != eSAP_DISCONNECTED) + return sapContext; + } + } + + return NULL; +} + +/** + * sap_find_cac_wait_session() - Get context of a SAP session in CAC wait state + * @handle: Global MAC handle + * + * Finds and gets the context of a SAP session in CAC wait state. + * + * Return: Valid SAP context on success, else NULL + */ +static ptSapContext sap_find_cac_wait_session(tHalHandle handle) +{ + tpAniSirGlobal mac = PMAC_STRUCT(handle); + uint8_t i = 0; + ptSapContext sapContext; + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_MED, + "%s", __func__); + + for (i = 0; i < SAP_MAX_NUM_SESSION; i++) { + sapContext = (ptSapContext) mac->sap.sapCtxList[i].pSapContext; + if (((QDF_SAP_MODE == mac->sap.sapCtxList[i].sapPersona) + || + (QDF_P2P_GO_MODE == mac->sap.sapCtxList[i].sapPersona)) && + (sapContext) && + (sapContext->sapsMachine == eSAP_DFS_CAC_WAIT)) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_MED, + "%s: found SAP in cac wait state", __func__); + return sapContext; + } + if (sapContext) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_MED, + "sapdfs: mode:%d intf:%d state:%d", + mac->sap.sapCtxList[i].sapPersona, i, + sapContext->sapsMachine); + } + } + + return NULL; +} + +/*========================================================================== + FUNCTION sap_close_session + + DESCRIPTION + This function will close all the sme sessions as well as zero-out the + sap global structure + + PARAMETERS + + IN + hHal : HAL pointer + sapContext : Sap Context value + callback : Roam Session close callback + valid : Sap context is valid or no + + RETURN VALUE + The QDF_STATUS code associated with performing the operation + QDF_STATUS_SUCCESS: Success + + SIDE EFFECTS + NA + ============================================================================*/ +QDF_STATUS sap_close_session(tHalHandle hHal, + ptSapContext sapContext, + csr_roamSessionCloseCallback callback, bool valid) +{ + QDF_STATUS qdf_status; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + if (false == valid) { + qdf_status = sme_close_session(hHal, + sapContext->sessionId, + callback, NULL); + } else { + qdf_status = sme_close_session(hHal, + sapContext->sessionId, + callback, sapContext); + } + + sapContext->isCacStartNotified = false; + sapContext->isCacEndNotified = false; + pMac->sap.sapCtxList[sapContext->sessionId].pSapContext = NULL; + sapContext->isSapSessionOpen = false; + sapContext->pre_cac_complete = false; + sapContext->is_pre_cac_on = false; + sapContext->chan_before_pre_cac = 0; + + if (NULL == sap_find_valid_concurrent_session(hHal)) { + /* If timer is running then stop the timer and destory it */ + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_MED, + "sapdfs: no session are valid, so clearing dfs global structure"); + /* + * CAC timer will be initiated and started only when SAP starts + * on DFS channel and it will be stopped and destroyed + * immediately once the radar detected or timedout. So + * as per design CAC timer should be destroyed after stop + */ + if (pMac->sap.SapDfsInfo.is_dfs_cac_timer_running) { + qdf_mc_timer_stop(&pMac->sap.SapDfsInfo. + sap_dfs_cac_timer); + pMac->sap.SapDfsInfo.is_dfs_cac_timer_running = 0; + qdf_mc_timer_destroy( + &pMac->sap.SapDfsInfo.sap_dfs_cac_timer); + } + pMac->sap.SapDfsInfo.cac_state = eSAP_DFS_DO_NOT_SKIP_CAC; + sap_cac_reset_notify(hHal); + qdf_mem_zero(&pMac->sap, sizeof(pMac->sap)); + } + + return qdf_status; +} + +/*========================================================================== + FUNCTION sap_cac_reset_notify + + DESCRIPTION Function will be called up on stop bss indication to clean up + DFS global structure. + + DEPENDENCIES PARAMETERS + IN hHAL : HAL pointer + + RETURN VALUE : void. + + SIDE EFFECTS + ============================================================================*/ +void sap_cac_reset_notify(tHalHandle hHal) +{ + uint8_t intf = 0; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + for (intf = 0; intf < SAP_MAX_NUM_SESSION; intf++) { + ptSapContext pSapContext = + (ptSapContext) pMac->sap.sapCtxList[intf].pSapContext; + if (((QDF_SAP_MODE == pMac->sap.sapCtxList[intf].sapPersona) + || + (QDF_P2P_GO_MODE == pMac->sap.sapCtxList[intf].sapPersona)) + && pMac->sap.sapCtxList[intf].pSapContext != NULL) { + pSapContext->isCacStartNotified = false; + pSapContext->isCacEndNotified = false; + } + } +} + +/*========================================================================== + FUNCTION sap_cac_start_notify + + DESCRIPTION Function will be called to notify eSAP_DFS_CAC_START event + to HDD + + DEPENDENCIES PARAMETERS + IN hHAL : HAL pointer + + RETURN VALUE : QDF_STATUS. + + SIDE EFFECTS + ============================================================================*/ +static QDF_STATUS sap_cac_start_notify(tHalHandle hHal) +{ + uint8_t intf = 0; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + QDF_STATUS qdf_status = QDF_STATUS_E_FAILURE; + + for (intf = 0; intf < SAP_MAX_NUM_SESSION; intf++) { + ptSapContext pSapContext = + (ptSapContext) pMac->sap.sapCtxList[intf].pSapContext; + if (((QDF_SAP_MODE == pMac->sap.sapCtxList[intf].sapPersona) + || + (QDF_P2P_GO_MODE == pMac->sap.sapCtxList[intf].sapPersona)) + && pMac->sap.sapCtxList[intf].pSapContext != NULL && + (false == pSapContext->isCacStartNotified)) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_MED, + "sapdfs: Signaling eSAP_DFS_CAC_START to HDD for sapctx[%p]", + pSapContext); + + qdf_status = sap_signal_hdd_event(pSapContext, NULL, + eSAP_DFS_CAC_START, + (void *) + eSAP_STATUS_SUCCESS); + if (QDF_STATUS_SUCCESS != qdf_status) { + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_ERROR, + "In %s, failed setting isCacStartNotified on interface[%d]", + __func__, intf); + return qdf_status; + } + pSapContext->isCacStartNotified = true; + } + } + return qdf_status; +} + +/** + * wlansap_update_pre_cac_end() - Update pre cac end to upper layer + * @sap_context: SAP context + * @mac: Global MAC structure + * @intf: Interface number + * + * Notifies pre cac end to upper layer + * + * Return: QDF_STATUS + */ +static QDF_STATUS wlansap_update_pre_cac_end(ptSapContext sap_context, + tpAniSirGlobal mac, uint8_t intf) +{ + QDF_STATUS qdf_status; + + sap_context->isCacEndNotified = true; + mac->sap.SapDfsInfo.sap_radar_found_status = false; + sap_context->sapsMachine = eSAP_STARTED; + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "In %s, pre cac end notify on %d: from state %s => %s", + __func__, intf, "eSAP_DFS_CAC_WAIT", + "eSAP_STARTED"); + + qdf_status = sap_signal_hdd_event(sap_context, + NULL, eSAP_DFS_PRE_CAC_END, + (void *)eSAP_STATUS_SUCCESS); + if (QDF_IS_STATUS_ERROR(qdf_status)) { + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_ERROR, + "In %s, pre cac notify failed on intf %d", + __func__, intf); + return qdf_status; + } + + return QDF_STATUS_SUCCESS; +} + +/*========================================================================== + FUNCTION sap_cac_end_notify + + DESCRIPTION Function will be called to notify eSAP_DFS_CAC_END event + to HDD + + DEPENDENCIES PARAMETERS + IN hHAL : HAL pointer + + RETURN VALUE : QDF_STATUS. + + SIDE EFFECTS + ============================================================================*/ +static QDF_STATUS sap_cac_end_notify(tHalHandle hHal, tCsrRoamInfo *roamInfo) +{ + uint8_t intf; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + QDF_STATUS qdf_status = QDF_STATUS_E_FAILURE; + + /* + * eSAP_DFS_CHANNEL_CAC_END: + * CAC Period elapsed and there was no radar + * found so, SAP can continue beaconing. + * sap_radar_found_status is set to 0 + */ + for (intf = 0; intf < SAP_MAX_NUM_SESSION; intf++) { + ptSapContext pSapContext = + (ptSapContext) pMac->sap.sapCtxList[intf].pSapContext; + if (((QDF_SAP_MODE == pMac->sap.sapCtxList[intf].sapPersona) + || + (QDF_P2P_GO_MODE == pMac->sap.sapCtxList[intf].sapPersona)) + && pMac->sap.sapCtxList[intf].pSapContext != NULL && + (false == pSapContext->isCacEndNotified) && + (pSapContext->sapsMachine == eSAP_DFS_CAC_WAIT)) { + pSapContext = pMac->sap.sapCtxList[intf].pSapContext; + + /* If this is an end notification of a pre cac, the + * SAP must not start beaconing and must delete the + * temporary interface created for pre cac and switch + * the original SAP to the pre CAC channel. + */ + if (pSapContext->is_pre_cac_on) { + qdf_status = wlansap_update_pre_cac_end( + pSapContext, pMac, intf); + if (QDF_IS_STATUS_ERROR(qdf_status)) + return qdf_status; + /* pre CAC is not allowed with any concurrency. + * So, we can break from here. + */ + break; + } + + qdf_status = sap_signal_hdd_event(pSapContext, NULL, + eSAP_DFS_CAC_END, + (void *) + eSAP_STATUS_SUCCESS); + if (QDF_STATUS_SUCCESS != qdf_status) { + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_ERROR, + "In %s, failed setting isCacEndNotified on interface[%d]", + __func__, intf); + return qdf_status; + } + pSapContext->isCacEndNotified = true; + pMac->sap.SapDfsInfo.sap_radar_found_status = false; + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_MED, + "sapdfs: Start beacon request on sapctx[%p]", + pSapContext); + + /* Start beaconing on the new channel */ + wlansap_start_beacon_req(pSapContext); + + /* Transition from eSAP_STARTING to eSAP_STARTED + * (both without substates) + */ + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_MED, + "sapdfs: channel[%d] from state %s => %s", + pSapContext->channel, "eSAP_STARTING", + "eSAP_STARTED"); + + pSapContext->sapsMachine = eSAP_STARTED; + + /*Action code for transition */ + qdf_status = sap_signal_hdd_event(pSapContext, roamInfo, + eSAP_START_BSS_EVENT, + (void *) + eSAP_STATUS_SUCCESS); + if (QDF_STATUS_SUCCESS != qdf_status) { + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_ERROR, + "In %s, failed setting isCacEndNotified on interface[%d]", + __func__, intf); + return qdf_status; + } + + /* Transition from eSAP_STARTING to eSAP_STARTED + * (both without substates) + */ + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + "In %s, from state %s => %s", + __func__, "eSAP_DFS_CAC_WAIT", + "eSAP_STARTED"); + } + } + /* + * All APs are done with CAC timer, all APs should start beaconing. + * Lets assume AP1 and AP2 started beaconing on DFS channel, Now lets + * say AP1 goes down and comes back on same DFS channel. In this case + * AP1 shouldn't start CAC timer and start beacon immediately beacause + * AP2 is already beaconing on this channel. This case will be handled + * by checking against eSAP_DFS_SKIP_CAC while starting the timer. + */ + pMac->sap.SapDfsInfo.cac_state = eSAP_DFS_SKIP_CAC; + return qdf_status; +} + +/** + * sap_fsm_state_disconnected() - utility function called from sap fsm + * @sap_ctx: SAP context + * @sap_event: SAP event buffer + * @mac_ctx: global MAC context + * @hal: HAL handle + * + * This function is called for state transition from "eSAP_DISCONNECTED" + * + * Return: QDF_STATUS + */ +static QDF_STATUS sap_fsm_state_disconnected(ptSapContext sap_ctx, + ptWLAN_SAPEvent sap_event, tpAniSirGlobal mac_ctx, + tHalHandle hal) +{ + uint32_t msg = sap_event->event; + QDF_STATUS qdf_status = QDF_STATUS_E_FAILURE; + + if (msg == eSAP_HDD_START_INFRA_BSS) { + /* + * Transition from eSAP_DISCONNECTED to eSAP_CH_SELECT + * (both without substates) + */ + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + FL("new from state %s => %s: session:%d"), + "eSAP_DISCONNECTED", "eSAP_CH_SELECT", + sap_ctx->sessionId); + + if (sap_ctx->isSapSessionOpen == eSAP_FALSE) { + uint32_t type, subtype; + if (sap_ctx->csr_roamProfile.csrPersona == + QDF_P2P_GO_MODE) + qdf_status = cds_get_vdev_types(QDF_P2P_GO_MODE, + &type, &subtype); + else + qdf_status = cds_get_vdev_types(QDF_SAP_MODE, + &type, + &subtype); + + if (QDF_STATUS_SUCCESS != qdf_status) { + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_FATAL, + "failed to get vdev type"); + return QDF_STATUS_E_FAILURE; + } + qdf_status = sme_open_session(hal, + &wlansap_roam_callback, + sap_ctx, sap_ctx->self_mac_addr, + &sap_ctx->sessionId, type, subtype); + if (QDF_STATUS_SUCCESS != qdf_status) { + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_ERROR, + FL("Error: calling sme_open_session")); + return QDF_STATUS_E_FAILURE; + } + + sap_ctx->isSapSessionOpen = eSAP_TRUE; + } + + /* init dfs channel nol */ + sap_init_dfs_channel_nol_list(sap_ctx); + + /* Set SAP device role */ + sap_ctx->sapsMachine = eSAP_CH_SELECT; + + /* + * Perform sme_ScanRequest. This scan request is post start bss + * request so, set the third to false. + */ + qdf_status = sap_goto_channel_sel(sap_ctx, sap_event, false, + true); + } else if (msg == eSAP_DFS_CHANNEL_CAC_START) { + /* + * No need of state check here, caller is expected to perform + * the checks before sending the event + */ + sap_ctx->sapsMachine = eSAP_DFS_CAC_WAIT; + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_MED, + FL("from state eSAP_DISCONNECTED => SAP_DFS_CAC_WAIT")); + if (mac_ctx->sap.SapDfsInfo.is_dfs_cac_timer_running != true) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_MED, + FL("sapdfs: starting dfs cac timer on sapctx[%p]"), + sap_ctx); + sap_start_dfs_cac_timer(sap_ctx); + } + + qdf_status = sap_cac_start_notify(hal); + } else if (msg == eSAP_CHANNEL_SELECTION_RETRY) { + /* Set SAP device role */ + sap_ctx->sapsMachine = eSAP_CH_SELECT; + + /* + * Perform sme_ScanRequest. This scan request is post start bss + * request so, set the third to false. + */ + qdf_status = sap_goto_channel_sel(sap_ctx, sap_event, false, + false); + } else { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("in state %s, event msg %d"), + "eSAP_DISCONNECTED", msg); + } + + return qdf_status; +} + +/** + * sap_fsm_state_ch_select() - utility function called from sap fsm + * @sap_ctx: SAP context + * @sap_event: SAP event buffer + * @mac_ctx: global MAC context + * @hal: HAL handle + * + * This function is called for state transition from "eSAP_CH_SELECT" + * + * Return: QDF_STATUS + */ +static QDF_STATUS sap_fsm_state_ch_select(ptSapContext sap_ctx, + ptWLAN_SAPEvent sap_event, tpAniSirGlobal mac_ctx, + tHalHandle hal) +{ + uint32_t msg = sap_event->event; + QDF_STATUS qdf_status = QDF_STATUS_E_FAILURE; + uint32_t cbmode; + bool b_leak_chan = false; +#ifdef WLAN_ENABLE_CHNL_MATRIX_RESTRICTION + uint8_t temp_chan; + tSapDfsNolInfo *p_nol; +#endif + + if (msg == eSAP_MAC_SCAN_COMPLETE) { + /* get the bonding mode */ + if (sap_ctx->channel <= 14) + cbmode = sme_get_cb_phy_state_from_cb_ini_value( + sme_get_channel_bonding_mode24_g(hal)); + else + cbmode = sme_get_cb_phy_state_from_cb_ini_value( + sme_get_channel_bonding_mode5_g(hal)); + +#ifdef WLAN_ENABLE_CHNL_MATRIX_RESTRICTION + temp_chan = sap_ctx->channel; + p_nol = mac_ctx->sap.SapDfsInfo.sapDfsChannelNolList; + + sap_mark_leaking_ch(sap_ctx, + cbmode, p_nol, 1, &temp_chan); + + /* + * if selelcted channel has leakage to channels + * in NOL, the temp_chan will be reset + */ + b_leak_chan = (temp_chan != sap_ctx->channel); +#endif + /* + * check if channel is in DFS_NOL or if the channel + * has leakage to the channels in NOL + */ + if (sap_dfs_is_channel_in_nol_list(sap_ctx, sap_ctx->channel, + cbmode) || b_leak_chan) { + uint8_t ch; + + /* find a new available channel */ + ch = sap_random_channel_sel(sap_ctx); + if (ch == 0) { + /* No available channel found */ + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_ERROR, + FL("No available channel found!!!")); + sap_signal_hdd_event(sap_ctx, NULL, + eSAP_DFS_NO_AVAILABLE_CHANNEL, + (void *)eSAP_STATUS_SUCCESS); + return QDF_STATUS_E_FAULT; + } + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + FL("channel %d is in NOL, StartBss on new channel %d"), + sap_ctx->channel, ch); + + sap_ctx->channel = ch; + cds_set_channel_params(sap_ctx->channel, + sap_ctx->secondary_ch, &sap_ctx->ch_params); + } + if (sap_ctx->channel > 14 && + (sap_ctx->csr_roamProfile.phyMode == eCSR_DOT11_MODE_11g || + sap_ctx->csr_roamProfile.phyMode == + eCSR_DOT11_MODE_11g_ONLY)) + sap_ctx->csr_roamProfile.phyMode = eCSR_DOT11_MODE_11a; + + /* + * when AP2 is started while AP1 is performing ACS, we may not + * have the AP1 channel yet.So here after the completion of AP2 + * ACS check if AP1 ACS resulting channel is DFS and if yes + * override AP2 ACS scan result with AP1 DFS channel + */ + if (cds_concurrent_beaconing_sessions_running()) { + uint16_t con_ch; + + con_ch = sme_get_concurrent_operation_channel(hal); + if (con_ch && CDS_IS_DFS_CH(con_ch)) + sap_ctx->channel = con_ch; + } + + /* + * Transition from eSAP_CH_SELECT to eSAP_STARTING + * (both without substates) + */ + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + FL("from state %s => %s"), + "eSAP_CH_SELECT", "eSAP_STARTING"); + /* Channel selected. Now can sap_goto_starting */ + sap_ctx->sapsMachine = eSAP_STARTING; + /* Specify the channel */ + sap_ctx->csr_roamProfile.ChannelInfo.numOfChannels = + 1; + sap_ctx->csr_roamProfile.ChannelInfo.ChannelList = + &sap_ctx->csr_roamProfile.operationChannel; + sap_ctx->csr_roamProfile.operationChannel = + (uint8_t) sap_ctx->channel; + sap_ctx->csr_roamProfile.ch_params.ch_width = + sap_ctx->ch_params.ch_width; + sap_ctx->csr_roamProfile.ch_params.center_freq_seg0 = + sap_ctx->ch_params.center_freq_seg0; + sap_ctx->csr_roamProfile.ch_params.center_freq_seg1 = + sap_ctx->ch_params.center_freq_seg1; + sap_ctx->csr_roamProfile.ch_params.sec_ch_offset = + sap_ctx->ch_params.sec_ch_offset; + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + FL("notify hostapd about channel selection: %d"), + sap_ctx->channel); + sap_signal_hdd_event(sap_ctx, NULL, + eSAP_CHANNEL_CHANGE_EVENT, + (void *) eSAP_STATUS_SUCCESS); + qdf_status = sap_goto_starting(sap_ctx, sap_event, + eCSR_BSS_TYPE_INFRA_AP); + } else if (msg == eSAP_CHANNEL_SELECTION_FAILED) { + sap_ctx->sapsMachine = eSAP_DISCONNECTED; + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("Cannot start BSS, ACS Fail")); + sap_signal_hdd_event(sap_ctx, NULL, eSAP_START_BSS_EVENT, + (void *)eSAP_STATUS_FAILURE); + } else if (msg == eSAP_HDD_STOP_INFRA_BSS) { + sap_ctx->sapsMachine = eSAP_DISCONNECTED; + sap_signal_hdd_event(sap_ctx, NULL, eSAP_START_BSS_EVENT, + (void *)eSAP_STATUS_FAILURE); + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO, + "%s: BSS stopped when Ch select in Progress", __func__); + } else { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("in state %s, invalid event msg %d"), + "eSAP_CH_SELECT", msg); + } + + return qdf_status; +} + +/** + * sap_fsm_state_dfs_cac_wait() - utility function called from sap fsm + * @sap_ctx: SAP context + * @sap_event: SAP event buffer + * @mac_ctx: global MAC context + * @hal: HAL handle + * + * This function is called for state transition from "eSAP_DFS_CAC_WAIT" + * + * Return: QDF_STATUS + */ +static QDF_STATUS sap_fsm_state_dfs_cac_wait(ptSapContext sap_ctx, + ptWLAN_SAPEvent sap_event, tpAniSirGlobal mac_ctx, + tHalHandle hal) +{ + uint32_t msg = sap_event->event; + tCsrRoamInfo *roam_info = (tCsrRoamInfo *) (sap_event->params); + QDF_STATUS qdf_status = QDF_STATUS_E_FAILURE; + + if (msg == eSAP_DFS_CHANNEL_CAC_START) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + FL("from state %s => %s"), + "eSAP_CH_SELECT", "eSAP_DFS_CAC_WAIT"); + if (mac_ctx->sap.SapDfsInfo.is_dfs_cac_timer_running != true) + sap_start_dfs_cac_timer(sap_ctx); + qdf_status = sap_cac_start_notify(hal); + } else if (msg == eSAP_DFS_CHANNEL_CAC_RADAR_FOUND) { + uint8_t intf; + /* + * Radar found while performing channel availability + * check, need to switch the channel again + */ + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO, + "ENTERTRED CAC WAIT STATE-->eSAP_DISCONNECTING\n"); + if (mac_ctx->sap.SapDfsInfo.target_channel) { + cds_set_channel_params( + mac_ctx->sap.SapDfsInfo.target_channel, 0, + &sap_ctx->ch_params); + } + + for (intf = 0; intf < SAP_MAX_NUM_SESSION; intf++) { + ptSapContext t_sap_ctx; + t_sap_ctx = mac_ctx->sap.sapCtxList[intf].pSapContext; + if (((QDF_SAP_MODE == + mac_ctx->sap.sapCtxList[intf].sapPersona) || + (QDF_P2P_GO_MODE == + mac_ctx->sap.sapCtxList[intf].sapPersona)) && + t_sap_ctx != NULL && + t_sap_ctx->sapsMachine != eSAP_DISCONNECTED) { + /* SAP to be moved to DISCONNECTING state */ + sap_ctx->sapsMachine = eSAP_DISCONNECTING; + /* + * eSAP_DFS_CHANNEL_CAC_RADAR_FOUND: + * A Radar is found on current DFS Channel + * while in CAC WAIT period So, do a channel + * switch to randomly selected target channel. + * Send the Channel change message to SME/PE. + * sap_radar_found_status is set to 1 + */ + sap_signal_hdd_event(t_sap_ctx, NULL, + eSAP_DFS_RADAR_DETECT, + (void *)eSAP_STATUS_SUCCESS); + + wlansap_channel_change_request( + (void *)t_sap_ctx, + mac_ctx->sap.SapDfsInfo.target_channel); + } + } + } else if (msg == eSAP_DFS_CHANNEL_CAC_END) { + qdf_status = sap_cac_end_notify(hal, roam_info); + } else if (msg == eSAP_HDD_STOP_INFRA_BSS) { + /* Transition from eSAP_DFS_CAC_WAIT to eSAP_DISCONNECTING */ + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + FL("from state %s => %s"), + "eSAP_DFS_CAC_WAIT", "eSAP_DISCONNECTING"); + + /* + * Stop the CAC timer only in following conditions + * single AP: if there is a single AP then stop the timer + * mulitple APs: incase of multiple APs, make sure that + * all APs are down. + */ + if (NULL == sap_find_valid_concurrent_session(hal)) { + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_INFO_MED, + FL("sapdfs: no sessions are valid, stopping timer")); + sap_stop_dfs_cac_timer(sap_ctx); + } + + sap_ctx->sapsMachine = eSAP_DISCONNECTING; + qdf_status = sap_goto_disconnecting(sap_ctx); + } else { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("in state %s, invalid event msg %d"), + "eSAP_DFS_CAC_WAIT", msg); + } + + return qdf_status; +} + +/** + * sap_fsm_state_starting() - utility function called from sap fsm + * @sap_ctx: SAP context + * @sap_event: SAP event buffer + * @mac_ctx: global MAC context + * @hal: HAL handle + * + * This function is called for state transition from "eSAP_STARTING" + * + * Return: QDF_STATUS + */ +static QDF_STATUS sap_fsm_state_starting(ptSapContext sap_ctx, + ptWLAN_SAPEvent sap_event, tpAniSirGlobal mac_ctx, + tHalHandle hal) +{ + uint32_t msg = sap_event->event; + tCsrRoamInfo *roam_info = (tCsrRoamInfo *) (sap_event->params); + tSapDfsInfo *sap_dfs_info; + QDF_STATUS qdf_status = QDF_STATUS_E_FAILURE; + uint8_t is_dfs = false; + + if (msg == eSAP_MAC_START_BSS_SUCCESS) { + /* + * Transition from eSAP_STARTING to eSAP_STARTED + * (both without substates) + */ + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + FL("from state channel = %d %s => %s ch_width %d"), + sap_ctx->channel, "eSAP_STARTING", "eSAP_STARTED", + sap_ctx->ch_params.ch_width); + sap_ctx->sapsMachine = eSAP_STARTED; + + /* Action code for transition */ + qdf_status = sap_signal_hdd_event(sap_ctx, roam_info, + eSAP_START_BSS_EVENT, + (void *) eSAP_STATUS_SUCCESS); + + /* + * The upper layers have been informed that AP is up and + * running, however, the AP is still not beaconing, until + * CAC is done if the operating channel is DFS + */ + if (sap_ctx->ch_params.ch_width == CH_WIDTH_160MHZ) { + is_dfs = true; + } else if (sap_ctx->ch_params.ch_width == CH_WIDTH_80P80MHZ) { + if (cds_get_channel_state(sap_ctx->channel) == + CHANNEL_STATE_DFS || + cds_get_channel_state(sap_ctx-> + ch_params.center_freq_seg1 - + SIR_80MHZ_START_CENTER_CH_DIFF) == + CHANNEL_STATE_DFS) + is_dfs = true; + } else { + if (cds_get_channel_state(sap_ctx->channel) == + CHANNEL_STATE_DFS) + is_dfs = true; + } + + if (is_dfs) { + sap_dfs_info = &mac_ctx->sap.SapDfsInfo; + if ((false == sap_dfs_info->ignore_cac) && + (eSAP_DFS_DO_NOT_SKIP_CAC == + sap_dfs_info->cac_state) && + !sap_ctx->pre_cac_complete) { + /* Move the device in CAC_WAIT_STATE */ + sap_ctx->sapsMachine = eSAP_DFS_CAC_WAIT; + + /* + * Need to stop the OS transmit queues, + * so that no traffic can flow down the stack + */ + + /* Start CAC wait timer */ + if (sap_dfs_info->is_dfs_cac_timer_running != + true) + sap_start_dfs_cac_timer(sap_ctx); + qdf_status = sap_cac_start_notify(hal); + + } else { + wlansap_start_beacon_req(sap_ctx); + } + } + } else if (msg == eSAP_MAC_START_FAILS || + msg == eSAP_HDD_STOP_INFRA_BSS) { + /* + * Transition from eSAP_STARTING to eSAP_DISCONNECTED + * (both without substates) + */ + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + FL("from state %s => %s"), + "eSAP_STARTING", "eSAP_DISCONNECTED"); + + /* Advance outer statevar */ + sap_ctx->sapsMachine = eSAP_DISCONNECTED; + qdf_status = sap_signal_hdd_event(sap_ctx, NULL, + eSAP_START_BSS_EVENT, + (void *) eSAP_STATUS_FAILURE); + qdf_status = sap_goto_disconnected(sap_ctx); + /* Close the SME session */ + + if (eSAP_TRUE == sap_ctx->isSapSessionOpen) { + if (QDF_STATUS_SUCCESS == sap_close_session(hal, + sap_ctx, NULL, false)) + sap_ctx->isSapSessionOpen = eSAP_FALSE; + } + } else if (msg == eSAP_OPERATING_CHANNEL_CHANGED) { + /* The operating channel has changed, update hostapd */ + sap_ctx->channel = + (uint8_t) mac_ctx->sap.SapDfsInfo.target_channel; + + sap_ctx->sapsMachine = eSAP_STARTED; + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + FL("from state %s => %s"), + "eSAP_STARTING", "eSAP_STARTED"); + + /* Indicate change in the state to upper layers */ + qdf_status = sap_signal_hdd_event(sap_ctx, roam_info, + eSAP_START_BSS_EVENT, + (void *)eSAP_STATUS_SUCCESS); + } else { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("in state %s, invalid event msg %d"), + "eSAP_STARTING", msg); + } + + return qdf_status; +} + +/** + * sap_fsm_state_started() - utility function called from sap fsm + * @sap_ctx: SAP context + * @sap_event: SAP event buffer + * @mac_ctx: global MAC context + * + * This function is called for state transition from "eSAP_STARTED" + * + * Return: QDF_STATUS + */ +static QDF_STATUS sap_fsm_state_started(ptSapContext sap_ctx, + ptWLAN_SAPEvent sap_event, tpAniSirGlobal mac_ctx) +{ + uint32_t msg = sap_event->event; + QDF_STATUS qdf_status = QDF_STATUS_E_FAILURE; + + if (msg == eSAP_HDD_STOP_INFRA_BSS) { + /* + * Transition from eSAP_STARTED to eSAP_DISCONNECTING + * (both without substates) + */ + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + FL("from state %s => %s"), + "eSAP_STARTED", "eSAP_DISCONNECTING"); + sap_ctx->sapsMachine = eSAP_DISCONNECTING; + qdf_status = sap_goto_disconnecting(sap_ctx); + } else if (eSAP_DFS_CHNL_SWITCH_ANNOUNCEMENT_START == msg) { + uint8_t intf; + /* + * Radar is seen on the current operating channel + * send CSA IE for all associated stations + * Request for CSA IE transmission + */ + for (intf = 0; intf < SAP_MAX_NUM_SESSION; intf++) { + ptSapContext temp_sap_ctx; + if (((QDF_SAP_MODE == + mac_ctx->sap.sapCtxList[intf].sapPersona) || + (QDF_P2P_GO_MODE == + mac_ctx->sap.sapCtxList[intf].sapPersona)) && + mac_ctx->sap.sapCtxList[intf].pSapContext != NULL) { + temp_sap_ctx = + mac_ctx->sap.sapCtxList[intf].pSapContext; + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_INFO_MED, + FL("sapdfs: Sending CSAIE for sapctx[%p]"), + temp_sap_ctx); + + qdf_status = wlansap_dfs_send_csa_ie_request( + (void *) temp_sap_ctx); + } + } + } else if (eSAP_CHANNEL_SWITCH_ANNOUNCEMENT_START == msg) { + enum tQDF_ADAPTER_MODE persona; + + if (!sap_ctx) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("Invalid sap_ctx")); + return qdf_status; + } + + persona = mac_ctx->sap.sapCtxList[sap_ctx->sessionId]. + sapPersona; + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_MED, + FL("app trigger chan switch: mode:%d vdev:%d"), + persona, sap_ctx->sessionId); + + if ((QDF_SAP_MODE == persona) || (QDF_P2P_GO_MODE == persona)) + qdf_status = wlansap_dfs_send_csa_ie_request( + (void *) sap_ctx); + } else { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("in state %s, invalid event msg %d"), + "eSAP_STARTED", msg); + } + + return qdf_status; +} + +/** + * sap_fsm_state_disconnecting() - utility function called from sap fsm + * @sap_ctx: SAP context + * @sap_event: SAP event buffer + * @mac_ctx: global MAC context + * + * This function is called for state transition from "eSAP_DISCONNECTING" + * + * Return: QDF_STATUS + */ +static QDF_STATUS sap_fsm_state_disconnecting(ptSapContext sap_ctx, + ptWLAN_SAPEvent sap_event, tpAniSirGlobal mac_ctx, + tHalHandle hal) +{ + uint32_t msg = sap_event->event; + QDF_STATUS qdf_status = QDF_STATUS_E_FAILURE; + + if (msg == eSAP_MAC_READY_FOR_CONNECTIONS) { + /* + * Transition from eSAP_DISCONNECTING to eSAP_DISCONNECTED + * (both without substates) + */ + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + FL("from state %s => %s"), + "eSAP_DISCONNECTING", "eSAP_DISCONNECTED"); + sap_ctx->sapsMachine = eSAP_DISCONNECTED; + + /* Close the SME session */ + if (eSAP_TRUE == sap_ctx->isSapSessionOpen) { + sap_ctx->isSapSessionOpen = eSAP_FALSE; + qdf_status = sap_close_session(hal, sap_ctx, + sap_roam_session_close_callback, true); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + qdf_status = sap_signal_hdd_event(sap_ctx, NULL, + eSAP_STOP_BSS_EVENT, + (void *)eSAP_STATUS_SUCCESS); + } + } + } else if (msg == eWNI_SME_CHANNEL_CHANGE_REQ) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_MED, + FL("sapdfs: Send channel change request on sapctx[%p]"), + sap_ctx); + /* + * Most likely, radar has been detected and SAP wants to + * change the channel + */ + qdf_status = wlansap_channel_change_request((void *) sap_ctx, + mac_ctx->sap.SapDfsInfo.target_channel); + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO, + FL("Sending DFS eWNI_SME_CHANNEL_CHANGE_REQ")); + } else if (msg == eWNI_SME_CHANNEL_CHANGE_RSP) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO, + FL("in state %s, event msg %d result %d"), + "eSAP_DISCONNECTING ", msg, sap_event->u2); + if (sap_event->u2 == eCSR_ROAM_RESULT_CHANNEL_CHANGE_FAILURE) + qdf_status = sap_goto_disconnecting(sap_ctx); + } else { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("in state %s, invalid event msg %d"), + "eSAP_DISCONNECTING", msg); + } + + return qdf_status; +} + +/** + * sap_fsm() - SAP statem machine entry function + * @sap_ctx: SAP context + * @sap_event: SAP event + * + * SAP statem machine entry function + * + * Return: QDF_STATUS + */ +QDF_STATUS sap_fsm(ptSapContext sap_ctx, ptWLAN_SAPEvent sap_event) +{ + /* + * Retrieve the phy link state machine structure + * from the sap_ctx value + * state var that keeps track of state machine + */ + eSapFsmStates_t state_var = sap_ctx->sapsMachine; + uint32_t msg = sap_event->event; /* State machine input event message */ + QDF_STATUS qdf_status = QDF_STATUS_E_FAILURE; + tHalHandle hal = CDS_GET_HAL_CB(sap_ctx->p_cds_gctx); + tpAniSirGlobal mac_ctx; + + if (NULL == hal) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("Invalid hal")); + return QDF_STATUS_E_FAILURE; + } + + mac_ctx = PMAC_STRUCT(hal); + if (NULL == mac_ctx) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("Invalid MAC context")); + return QDF_STATUS_E_FAILURE; + } + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_DEBUG, + FL("sap_ctx=%p, state_var=%d, msg=0x%x"), + sap_ctx, state_var, msg); + + switch (state_var) { + case eSAP_DISCONNECTED: + qdf_status = sap_fsm_state_disconnected(sap_ctx, sap_event, + mac_ctx, hal); + break; + + case eSAP_CH_SELECT: + qdf_status = sap_fsm_state_ch_select(sap_ctx, sap_event, + mac_ctx, hal); + break; + + case eSAP_DFS_CAC_WAIT: + qdf_status = sap_fsm_state_dfs_cac_wait(sap_ctx, sap_event, + mac_ctx, hal); + break; + + case eSAP_STARTING: + qdf_status = sap_fsm_state_starting(sap_ctx, sap_event, + mac_ctx, hal); + break; + + case eSAP_STARTED: + qdf_status = sap_fsm_state_started(sap_ctx, sap_event, + mac_ctx); + break; + + case eSAP_DISCONNECTING: + qdf_status = sap_fsm_state_disconnecting(sap_ctx, sap_event, + mac_ctx, hal); + break; + } + return qdf_status; +} + +eSapStatus +sapconvert_to_csr_profile(tsap_Config_t *pconfig_params, eCsrRoamBssType bssType, + tCsrRoamProfile *profile) +{ + /* Create Roam profile for SoftAP to connect */ + profile->BSSType = eCSR_BSS_TYPE_INFRA_AP; + profile->SSIDs.numOfSSIDs = 1; + profile->csrPersona = pconfig_params->persona; + profile->disableDFSChSwitch = pconfig_params->disableDFSChSwitch; + + qdf_mem_zero(profile->SSIDs.SSIDList[0].SSID.ssId, + sizeof(profile->SSIDs.SSIDList[0].SSID.ssId)); + + /* Flag to not broadcast the SSID information */ + profile->SSIDs.SSIDList[0].ssidHidden = + pconfig_params->SSIDinfo.ssidHidden; + + profile->SSIDs.SSIDList[0].SSID.length = + pconfig_params->SSIDinfo.ssid.length; + qdf_mem_copy(&profile->SSIDs.SSIDList[0].SSID.ssId, + pconfig_params->SSIDinfo.ssid.ssId, + sizeof(pconfig_params->SSIDinfo.ssid.ssId)); + + profile->negotiatedAuthType = eCSR_AUTH_TYPE_OPEN_SYSTEM; + + if (pconfig_params->authType == eSAP_OPEN_SYSTEM) { + profile->negotiatedAuthType = eCSR_AUTH_TYPE_OPEN_SYSTEM; + } else if (pconfig_params->authType == eSAP_SHARED_KEY) { + profile->negotiatedAuthType = eCSR_AUTH_TYPE_SHARED_KEY; + } else { + profile->negotiatedAuthType = eCSR_AUTH_TYPE_AUTOSWITCH; + } + + profile->AuthType.numEntries = 1; + profile->AuthType.authType[0] = eCSR_AUTH_TYPE_OPEN_SYSTEM; + + /* Always set the Encryption Type */ + profile->EncryptionType.numEntries = 1; + profile->EncryptionType.encryptionType[0] = + pconfig_params->RSNEncryptType; + + profile->mcEncryptionType.numEntries = 1; + profile->mcEncryptionType.encryptionType[0] = + pconfig_params->mcRSNEncryptType; + + if (pconfig_params->privacy & eSAP_SHARED_KEY) { + profile->AuthType.authType[0] = eCSR_AUTH_TYPE_SHARED_KEY; + } + + profile->privacy = pconfig_params->privacy; + profile->fwdWPSPBCProbeReq = pconfig_params->fwdWPSPBCProbeReq; + + if (pconfig_params->authType == eSAP_SHARED_KEY) { + profile->csr80211AuthType = eSIR_SHARED_KEY; + } else if (pconfig_params->authType == eSAP_OPEN_SYSTEM) { + profile->csr80211AuthType = eSIR_OPEN_SYSTEM; + } else { + profile->csr80211AuthType = eSIR_AUTO_SWITCH; + } + + /* Initialize we are not going to use it */ + profile->pWPAReqIE = NULL; + profile->nWPAReqIELength = 0; + + /* set the RSN/WPA IE */ + profile->pRSNReqIE = NULL; + profile->nRSNReqIELength = pconfig_params->RSNWPAReqIELength; + if (pconfig_params->RSNWPAReqIELength) { + profile->pRSNReqIE = + qdf_mem_malloc(pconfig_params->RSNWPAReqIELength); + if (NULL == profile->pRSNReqIE) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + " %s Fail to alloc memory", __func__); + return eSAP_STATUS_FAILURE; + } + qdf_mem_copy(profile->pRSNReqIE, pconfig_params->RSNWPAReqIE, + pconfig_params->RSNWPAReqIELength); + profile->nRSNReqIELength = pconfig_params->RSNWPAReqIELength; + } + /* Turn off CB mode */ + profile->CBMode = eCSR_CB_OFF; + + /* set the phyMode to accept anything */ + /* Best means everything because it covers all the things we support */ + /* eCSR_DOT11_MODE_BEST */ + profile->phyMode = pconfig_params->SapHw_mode; + + /* Configure beaconInterval */ + profile->beaconInterval = (uint16_t) pconfig_params->beacon_int; + + /* set DTIM period */ + profile->dtimPeriod = pconfig_params->dtim_period; + + /* set Uapsd enable bit */ + profile->ApUapsdEnable = pconfig_params->UapsdEnable; + + /* Enable protection parameters */ + profile->protEnabled = pconfig_params->protEnabled; + profile->obssProtEnabled = pconfig_params->obssProtEnabled; + profile->cfg_protection = pconfig_params->ht_capab; + + /* country code */ + if (pconfig_params->countryCode[0]) + qdf_mem_copy(profile->countryCode, pconfig_params->countryCode, + WNI_CFG_COUNTRY_CODE_LEN); + profile->ieee80211d = pconfig_params->ieee80211d; + /* wps config info */ + profile->wps_state = pconfig_params->wps_state; + +#ifdef WLAN_FEATURE_11W + /* MFP capable/required */ + profile->MFPCapable = pconfig_params->mfpCapable ? 1 : 0; + profile->MFPRequired = pconfig_params->mfpRequired ? 1 : 0; +#endif + + if (pconfig_params->probeRespIEsBufferLen > 0 && + pconfig_params->pProbeRespIEsBuffer != NULL) { + profile->addIeParams.probeRespDataLen = + pconfig_params->probeRespIEsBufferLen; + profile->addIeParams.probeRespData_buff = + pconfig_params->pProbeRespIEsBuffer; + } else { + profile->addIeParams.probeRespDataLen = 0; + profile->addIeParams.probeRespData_buff = NULL; + } + /*assoc resp IE */ + if (pconfig_params->assocRespIEsLen > 0 && + pconfig_params->pAssocRespIEsBuffer != NULL) { + profile->addIeParams.assocRespDataLen = + pconfig_params->assocRespIEsLen; + profile->addIeParams.assocRespData_buff = + pconfig_params->pAssocRespIEsBuffer; + } else { + profile->addIeParams.assocRespDataLen = 0; + profile->addIeParams.assocRespData_buff = NULL; + } + + if (pconfig_params->probeRespBcnIEsLen > 0 && + pconfig_params->pProbeRespBcnIEsBuffer != NULL) { + profile->addIeParams.probeRespBCNDataLen = + pconfig_params->probeRespBcnIEsLen; + profile->addIeParams.probeRespBCNData_buff = + pconfig_params->pProbeRespBcnIEsBuffer; + } else { + profile->addIeParams.probeRespBCNDataLen = 0; + profile->addIeParams.probeRespBCNData_buff = NULL; + } + profile->sap_dot11mc = pconfig_params->sap_dot11mc; + + if (pconfig_params->supported_rates.numRates) { + qdf_mem_copy(profile->supported_rates.rate, + pconfig_params->supported_rates.rate, + pconfig_params->supported_rates.numRates); + profile->supported_rates.numRates = + pconfig_params->supported_rates.numRates; + } + + if (pconfig_params->extended_rates.numRates) { + qdf_mem_copy(profile->extended_rates.rate, + pconfig_params->extended_rates.rate, + pconfig_params->extended_rates.numRates); + profile->extended_rates.numRates = + pconfig_params->extended_rates.numRates; + } + + return eSAP_STATUS_SUCCESS; /* Success. */ +} + +void sap_free_roam_profile(tCsrRoamProfile *profile) +{ + if (profile->pRSNReqIE) { + qdf_mem_free(profile->pRSNReqIE); + profile->pRSNReqIE = NULL; + } +} + +void sap_sort_mac_list(struct qdf_mac_addr *macList, uint8_t size) +{ + uint8_t outer, inner; + struct qdf_mac_addr temp; + int32_t nRes = -1; + + if ((NULL == macList) || (size > MAX_ACL_MAC_ADDRESS)) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + FL("either buffer is NULL or size = %d is more"), size); + return; + } + + for (outer = 0; outer < size; outer++) { + for (inner = 0; inner < size - 1; inner++) { + nRes = + qdf_mem_cmp((macList + inner)->bytes, + (macList + inner + 1)->bytes, + QDF_MAC_ADDR_SIZE); + if (nRes > 0) { + qdf_mem_copy(temp.bytes, + (macList + inner + 1)->bytes, + QDF_MAC_ADDR_SIZE); + qdf_mem_copy((macList + inner + 1)->bytes, + (macList + inner)->bytes, + QDF_MAC_ADDR_SIZE); + qdf_mem_copy((macList + inner)->bytes, + temp.bytes, QDF_MAC_ADDR_SIZE); + } + } + } +} + +eSapBool +sap_search_mac_list(struct qdf_mac_addr *macList, + uint8_t num_mac, uint8_t *peerMac, + uint8_t *index) +{ + int32_t nRes = -1; + int8_t nStart = 0, nEnd, nMiddle; + nEnd = num_mac - 1; + + if ((NULL == macList) || (num_mac > MAX_ACL_MAC_ADDRESS)) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + FL("either buffer is NULL or size = %d is more."), num_mac); + return eSAP_FALSE; + } + + while (nStart <= nEnd) { + nMiddle = (nStart + nEnd) / 2; + nRes = + qdf_mem_cmp(&macList[nMiddle], peerMac, + QDF_MAC_ADDR_SIZE); + + if (0 == nRes) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + "search SUCC"); + /* "index equals NULL" means the caller does not need the */ + /* index value of the peerMac being searched */ + if (index != NULL) { + *index = (uint8_t) nMiddle; + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_INFO_HIGH, "index %d", + *index); + } + return eSAP_TRUE; + } + if (nRes < 0) + nStart = nMiddle + 1; + else + nEnd = nMiddle - 1; + } + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + "search not succ"); + return eSAP_FALSE; +} + +void sap_add_mac_to_acl(struct qdf_mac_addr *macList, + uint8_t *size, uint8_t *peerMac) +{ + int32_t nRes = -1; + int i; + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + "add acl entered"); + + if (NULL == macList || *size > MAX_ACL_MAC_ADDRESS) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + FL("either buffer is NULL or size = %d is incorrect."), + *size); + return; + } + + for (i = ((*size) - 1); i >= 0; i--) { + nRes = + qdf_mem_cmp(&macList[i], peerMac, QDF_MAC_ADDR_SIZE); + if (nRes > 0) { + /* Move alphabetically greater mac addresses one index down to allow for insertion + of new mac in sorted order */ + qdf_mem_copy((macList + i + 1)->bytes, + (macList + i)->bytes, QDF_MAC_ADDR_SIZE); + } else { + break; + } + } + /* This should also take care of if the element is the first to be added in the list */ + qdf_mem_copy((macList + i + 1)->bytes, peerMac, QDF_MAC_ADDR_SIZE); + /* increment the list size */ + (*size)++; +} + +void sap_remove_mac_from_acl(struct qdf_mac_addr *macList, + uint8_t *size, uint8_t index) +{ + int i; + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + "remove acl entered"); + /* + * Return if the list passed is empty. Ideally this should never happen + * since this funcn is always called after sap_search_mac_list to get + * the index of the mac addr to be removed and this will only get + * called if the search is successful. Still no harm in having the check + */ + if ((macList == NULL) || (*size == 0) || + (*size > MAX_ACL_MAC_ADDRESS)) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + FL("either buffer is NULL or size %d is incorrect."), + *size); + return; + } + for (i = index; i < ((*size) - 1); i++) { + /* Move mac addresses starting from "index" passed one index up to delete the void + created by deletion of a mac address in ACL */ + qdf_mem_copy((macList + i)->bytes, (macList + i + 1)->bytes, + QDF_MAC_ADDR_SIZE); + } + /* The last space should be made empty since all mac addesses moved one step up */ + qdf_mem_zero((macList + (*size) - 1)->bytes, QDF_MAC_ADDR_SIZE); + /* reduce the list size by 1 */ + (*size)--; +} + +void sap_print_acl(struct qdf_mac_addr *macList, uint8_t size) +{ + int i; + uint8_t *macArray; + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + "print acl entered"); + + if ((NULL == macList) || (size == 0) || (size >= MAX_ACL_MAC_ADDRESS)) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + "In %s, either buffer is NULL or size %d is incorrect.", + __func__, size); + return; + } + + for (i = 0; i < size; i++) { + macArray = (macList + i)->bytes; + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + "** ACL entry %i - " MAC_ADDRESS_STR, i, + MAC_ADDR_ARRAY(macArray)); + } + return; +} + +QDF_STATUS sap_is_peer_mac_allowed(ptSapContext sapContext, uint8_t *peerMac) +{ + if (eSAP_ALLOW_ALL == sapContext->eSapMacAddrAclMode) + return QDF_STATUS_SUCCESS; + + if (sap_search_mac_list + (sapContext->acceptMacList, sapContext->nAcceptMac, peerMac, NULL)) + return QDF_STATUS_SUCCESS; + + if (sap_search_mac_list + (sapContext->denyMacList, sapContext->nDenyMac, peerMac, NULL)) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + "In %s, Peer " MAC_ADDRESS_STR " in deny list", + __func__, MAC_ADDR_ARRAY(peerMac)); + return QDF_STATUS_E_FAILURE; + } + /* A new station CAN associate, unless in deny list. Less stringent mode */ + if (eSAP_ACCEPT_UNLESS_DENIED == sapContext->eSapMacAddrAclMode) + return QDF_STATUS_SUCCESS; + + /* A new station CANNOT associate, unless in accept list. More stringent mode */ + if (eSAP_DENY_UNLESS_ACCEPTED == sapContext->eSapMacAddrAclMode) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + "In %s, Peer " MAC_ADDRESS_STR + " denied, Mac filter mode is eSAP_DENY_UNLESS_ACCEPTED", + __func__, MAC_ADDR_ARRAY(peerMac)); + return QDF_STATUS_E_FAILURE; + } + + /* The new STA is neither in accept list nor in deny list. In this case, deny the association + * but send a wifi event notification indicating the mac address being denied + */ + if (eSAP_SUPPORT_ACCEPT_AND_DENY == sapContext->eSapMacAddrAclMode) { + sap_signal_hdd_event(sapContext, NULL, eSAP_UNKNOWN_STA_JOIN, + (void *) peerMac); + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + "In %s, Peer " MAC_ADDRESS_STR + " denied, Mac filter mode is eSAP_SUPPORT_ACCEPT_AND_DENY", + __func__, MAC_ADDR_ARRAY(peerMac)); + return QDF_STATUS_E_FAILURE; + } + return QDF_STATUS_SUCCESS; +} + +#ifdef SOFTAP_CHANNEL_RANGE +/** + * sap_get_channel_list() - get the list of channels + * @sap_ctx: sap context + * @ch_list: pointer to channel list array + * @num_ch: pointer to number of channels. + * + * This function populates the list of channels for scanning. + * + * Return: QDF_STATUS + */ +static QDF_STATUS sap_get_channel_list(ptSapContext sap_ctx, + uint8_t **ch_list, + uint8_t *num_ch) +{ + uint8_t loop_count; + uint8_t *list; + uint8_t ch_count; + uint8_t start_ch_num, band_start_ch; + uint8_t end_ch_num, band_end_ch; + uint32_t en_lte_coex; + tHalHandle hal = CDS_GET_HAL_CB(sap_ctx->p_cds_gctx); +#ifdef FEATURE_WLAN_CH_AVOID + uint8_t i; +#endif + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + + if (NULL == hal) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("Invalid HAL pointer from p_cds_gctx")); + *num_ch = 0; + *ch_list = NULL; + return QDF_STATUS_E_FAULT; + } + + start_ch_num = sap_ctx->acs_cfg->start_ch; + end_ch_num = sap_ctx->acs_cfg->end_ch; + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO, + FL("startChannel %d, EndChannel %d, HW:%d"), + start_ch_num, end_ch_num, + sap_ctx->acs_cfg->hw_mode); + + wlansap_extend_to_acs_range(&start_ch_num, &end_ch_num, + &band_start_ch, &band_end_ch); + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO, + FL("expanded startChannel %d,EndChannel %d"), + start_ch_num, end_ch_num); + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO, + FL("band_start_ch %d, band_end_ch %d"), + band_start_ch, band_end_ch); + + sme_cfg_get_int(hal, WNI_CFG_ENABLE_LTE_COEX, &en_lte_coex); + + /* Check if LTE coex is enabled and 2.4GHz is selected */ + if (en_lte_coex && (band_start_ch == CHAN_ENUM_1) && + (band_end_ch == CHAN_ENUM_14)) { + /* Set 2.4GHz upper limit to channel 9 for LTE COEX */ + band_end_ch = CHAN_ENUM_9; + } + + /* Allocate the max number of channel supported */ + list = (uint8_t *) qdf_mem_malloc(NUM_5GHZ_CHANNELS + + NUM_24GHZ_CHANNELS); + if (NULL == list) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("Unable to allocate channel list")); + *num_ch = 0; + *ch_list = NULL; + return QDF_STATUS_E_NOMEM; + } + + /* Search for the Active channels in the given range */ + ch_count = 0; + for (loop_count = band_start_ch; loop_count <= band_end_ch; + loop_count++) { + /* go to next channel if rf_channel is out of range */ + if ((start_ch_num > CDS_CHANNEL_NUM(loop_count)) || + (end_ch_num < CDS_CHANNEL_NUM(loop_count))) + continue; + /* + * go to next channel if none of these condition pass + * - DFS scan enabled and chan not in CHANNEL_STATE_DISABLE + * - DFS scan disable but chan in CHANNEL_STATE_ENABLE + */ + if (!(((eSAP_TRUE == mac_ctx->scan.fEnableDFSChnlScan) && + CDS_CHANNEL_STATE(loop_count)) || + ((eSAP_FALSE == mac_ctx->scan.fEnableDFSChnlScan) && + (CHANNEL_STATE_ENABLE == + CDS_CHANNEL_STATE(loop_count))))) + continue; + +#ifdef FEATURE_WLAN_CH_AVOID + for (i = 0; i < NUM_CHANNELS; i++) { + if ((safe_channels[i].channelNumber == + CDS_CHANNEL_NUM(loop_count))) { + /* Check if channel is safe */ + if (true == safe_channels[i].isSafe) { +#endif +#ifdef FEATURE_WLAN_AP_AP_ACS_OPTIMIZE + uint8_t ch; + ch = CDS_CHANNEL_NUM(loop_count); + if ((sap_ctx->acs_cfg->skip_scan_status == + eSAP_DO_PAR_ACS_SCAN)) { + if ((ch >= sap_ctx->acs_cfg->skip_scan_range1_stch && + ch <= sap_ctx->acs_cfg->skip_scan_range1_endch) || + (ch >= sap_ctx->acs_cfg->skip_scan_range2_stch && + ch <= sap_ctx->acs_cfg->skip_scan_range2_endch)) { + list[ch_count] = + CDS_CHANNEL_NUM(loop_count); + ch_count++; + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_INFO, + FL("%d %d added to ACS ch range"), + ch_count, ch); + } else { + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_INFO_HIGH, + FL("%d %d skipped from ACS ch range"), + ch_count, ch); + } + } else { + list[ch_count] = + CDS_CHANNEL_NUM(loop_count); + ch_count++; + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_INFO, + FL("%d %d added to ACS ch range"), + ch_count, ch); + } +#else + list[ch_count] = CDS_CHANNEL_NUM(loop_count); + ch_count++; +#endif +#ifdef FEATURE_WLAN_CH_AVOID + } + break; + } + } +#endif + } + if (0 == ch_count) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("No active channels present for the current region")); + /* + * LTE COEX: channel range outside the restricted 2.4GHz + * band limits + */ + if (en_lte_coex && (start_ch_num > band_end_ch)) + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_FATAL, + FL("SAP can't be started as due to LTE COEX")); + } + + /* return the channel list and number of channels to scan */ + *num_ch = ch_count; + if (ch_count != 0) { + *ch_list = list; + } else { + *ch_list = NULL; + qdf_mem_free(list); + } + + for (loop_count = 0; loop_count < ch_count; loop_count++) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_DEBUG, + FL("channel number: %d"), list[loop_count]); + } + return QDF_STATUS_SUCCESS; +} +#endif + +/* + * Function for initializing list of 2.4/5 Ghz [NON-DFS/DFS] + * available channels in the current regulatory domain. + */ +static QDF_STATUS sap_get_5ghz_channel_list(ptSapContext sapContext) +{ + uint8_t count = 0; + int i; + struct sir_pcl_list pcl; + QDF_STATUS status; + enum channel_state ch_state; + pcl.pcl_len = 0; + if (NULL == sapContext) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "Invalid sapContext pointer on sap_get_channel_list"); + return QDF_STATUS_E_FAULT; + } + + if (sapContext->SapAllChnlList.channelList) { + qdf_mem_free(sapContext->SapAllChnlList.channelList); + sapContext->SapAllChnlList.channelList = NULL; + } + + sapContext->SapAllChnlList.channelList = + (tChannelInfo *) qdf_mem_malloc(WNI_CFG_VALID_CHANNEL_LIST_LEN * + sizeof(tChannelInfo)); + if (NULL == sapContext->SapAllChnlList.channelList) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + " Memory Allocation failed sap_get_channel_list"); + return QDF_STATUS_E_NOMEM; + } + if (cds_mode_specific_connection_count(CDS_SAP_MODE, NULL) == 0) { + status = cds_get_pcl(CDS_SAP_MODE, + pcl.pcl_list, &pcl.pcl_len, pcl.weight_list, + QDF_ARRAY_SIZE(pcl.weight_list)); + } else { + status = cds_get_pcl_for_existing_conn(CDS_SAP_MODE, + pcl.pcl_list, &pcl.pcl_len, pcl.weight_list, + QDF_ARRAY_SIZE(pcl.weight_list)); + } + if (status != QDF_STATUS_SUCCESS) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "Get PCL failed"); + return status; + } + for (i = 0; i <= pcl.pcl_len; i++) { + if (CDS_IS_CHANNEL_5GHZ(pcl.pcl_list[i])) { + ch_state = cds_get_channel_state(pcl.pcl_list[i]); + if (!(ch_state == CHANNEL_STATE_ENABLE || + ch_state == CHANNEL_STATE_DFS)) + continue; + sapContext->SapAllChnlList.channelList[count].channel = + pcl.pcl_list[i]; + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_LOW, + "%s[%d] CHANNEL = %d", __func__, __LINE__, + pcl.pcl_list[i]); + sapContext->SapAllChnlList.channelList[count].valid = + true; + count++; + } + } + + sapContext->SapAllChnlList.numChannel = count; + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_LOW, + "%s[%d] NUMBER OF CHANNELS count = %d" + "sapContext->SapAllChnlList.numChannel = %d", + __func__, __LINE__, count, + sapContext->SapAllChnlList.numChannel); + return QDF_STATUS_SUCCESS; +} + +/* + * This function randomly selects the channel to switch after the detection + * of radar + * param sapContext - sap context + * dfs_event - Dfs information from DFS + * return - channel to which AP wishes to switch + */ +uint8_t sap_indicate_radar(ptSapContext sapContext, + tSirSmeDfsEventInd *dfs_event) +{ + uint8_t target_channel = 0; + tHalHandle hHal; + tpAniSirGlobal pMac; + + if (NULL == sapContext || NULL == dfs_event) { + /* Invalid sap context of dfs event passed */ + return 0; + } + hHal = CDS_GET_HAL_CB(sapContext->p_cds_gctx); + + if (NULL == hHal) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "In %s invalid hHal", __func__); + return 0; + } + pMac = PMAC_STRUCT(hHal); + + if (!dfs_event->dfs_radar_status) { + /*dfs status does not indicate a radar on the channel-- False Alarm */ + return 0; + } + + /* + * SAP needs to generate Channel Switch IE + * if the radar is found in the STARTED state + */ + if (eSAP_STARTED == sapContext->sapsMachine) + pMac->sap.SapDfsInfo.csaIERequired = eSAP_TRUE; + + if (sapContext->csr_roamProfile.disableDFSChSwitch) { + return sapContext->channel; + } + + /* set the Radar Found flag in SapDfsInfo */ + pMac->sap.SapDfsInfo.sap_radar_found_status = true; + + if (dfs_event->chan_list.nchannels > SIR_DFS_MAX_20M_SUB_CH) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_WARN, + FL("nchannels >SIR_DFS_MAX_20M_SUB_CH so resetting")); + dfs_event->chan_list.nchannels = SIR_DFS_MAX_20M_SUB_CH; + } + + sap_mark_dfs_channels(sapContext, dfs_event->chan_list.channels, + dfs_event->chan_list.nchannels, + cds_get_monotonic_boottime()); + + if (sapContext->chan_before_pre_cac) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO, + FL("sapdfs: set chan before pre cac %d as target chan"), + sapContext->chan_before_pre_cac); + return sapContext->chan_before_pre_cac; + } + + /* + * (1) skip static turbo channel as it will require STA to be in + * static turbo to work. + * (2) skip channel which's marked with radar detction + * (3) WAR: we allow user to config not to use any DFS channel + * (4) When we pick a channel, skip excluded 11D channels + * (5) Create the available channel list with the above rules + */ + + target_channel = sap_random_channel_sel(sapContext); + if (0 == target_channel) { + sap_signal_hdd_event(sapContext, NULL, + eSAP_DFS_NO_AVAILABLE_CHANNEL, + (void *) eSAP_STATUS_SUCCESS); + } + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_WARN, + FL("sapdfs: New selected target channel is [%d]"), + target_channel); + return target_channel; +} + +/* + * CAC timer callback function. + * Post eSAP_DFS_CHANNEL_CAC_END event to sap_fsm(). + */ +void sap_dfs_cac_timer_callback(void *data) +{ + ptSapContext sapContext; + tWLAN_SAPEvent sapEvent; + tHalHandle hHal = (tHalHandle) data; + tpAniSirGlobal pMac; + + if (NULL == hHal) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "In %s invalid hHal", __func__); + return; + } + pMac = PMAC_STRUCT(hHal); + sapContext = sap_find_cac_wait_session(hHal); + if (NULL == sapContext) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: no SAP contexts in wait state", __func__); + return; + } + + /* + * SAP may not be in CAC wait state, when the timer runs out. + * if following flag is set, then timer is in initialized state, + * destroy timer here. + */ + if (pMac->sap.SapDfsInfo.is_dfs_cac_timer_running == true) { + qdf_mc_timer_destroy(&pMac->sap.SapDfsInfo.sap_dfs_cac_timer); + pMac->sap.SapDfsInfo.is_dfs_cac_timer_running = false; + } + + /* + * CAC Complete, post eSAP_DFS_CHANNEL_CAC_END to sap_fsm + */ + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_MED, + "sapdfs: Sending eSAP_DFS_CHANNEL_CAC_END for target_channel = %d on sapctx[%p]", + sapContext->channel, sapContext); + + sapEvent.event = eSAP_DFS_CHANNEL_CAC_END; + sapEvent.params = 0; + sapEvent.u1 = 0; + sapEvent.u2 = 0; + + sap_fsm(sapContext, &sapEvent); +} + +/* + * Function to stop the DFS CAC Timer + */ +static int sap_stop_dfs_cac_timer(ptSapContext sapContext) +{ + tHalHandle hHal; + tpAniSirGlobal pMac; + if (sapContext == NULL) + return 0; + + hHal = CDS_GET_HAL_CB(sapContext->p_cds_gctx); + if (NULL == hHal) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "In %s invalid hHal", __func__); + return 0; + } + pMac = PMAC_STRUCT(hHal); + + if (QDF_TIMER_STATE_RUNNING != + qdf_mc_timer_get_current_state(&pMac->sap.SapDfsInfo. + sap_dfs_cac_timer)) { + return 0; + } + + qdf_mc_timer_stop(&pMac->sap.SapDfsInfo.sap_dfs_cac_timer); + pMac->sap.SapDfsInfo.is_dfs_cac_timer_running = 0; + qdf_mc_timer_destroy(&pMac->sap.SapDfsInfo.sap_dfs_cac_timer); + + return 0; +} + + +/** + * sap_is_channel_bonding_etsi_weather_channel() - check weather chan bonding. + * @sap_context: SAP context + * + * Check if the current SAP operating channel is bonded to weather radar + * channel in ETSI domain. + * + * Return: True if bonded to weather channel in ETSI + */ +static bool +sap_is_channel_bonding_etsi_weather_channel(ptSapContext sap_context) +{ + if (IS_CH_BONDING_WITH_WEATHER_CH(sap_context->channel) && + (sap_context->ch_params.ch_width != CH_WIDTH_20MHZ)) + return true; + + return false; +} + +/* + * Function to start the DFS CAC Timer + * when SAP is started on a DFS channel + */ +int sap_start_dfs_cac_timer(ptSapContext sapContext) +{ + QDF_STATUS status; + uint32_t cacTimeOut; + tHalHandle hHal = NULL; + tpAniSirGlobal pMac = NULL; + enum dfs_region dfs_region; + + if (sapContext == NULL) { + return 0; + } + hHal = CDS_GET_HAL_CB(sapContext->p_cds_gctx); + + if (NULL == hHal) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "In %s invalid hHal", __func__); + return 0; + } + pMac = PMAC_STRUCT(hHal); + + if (pMac->sap.SapDfsInfo.ignore_cac) { + /* + * If User has set to ignore the CAC + * so, continue without CAC Timer. + */ + return 2; + } + cacTimeOut = DEFAULT_CAC_TIMEOUT; + + cds_get_dfs_region(&dfs_region); + + if ((dfs_region == DFS_ETSI_REGION) + && ((IS_ETSI_WEATHER_CH(sapContext->channel)) || + (sap_is_channel_bonding_etsi_weather_channel(sapContext)))) { + cacTimeOut = ETSI_WEATHER_CH_CAC_TIMEOUT; + } + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_MED, + "sapdfs: SAP_DFS_CHANNEL_CAC_START on CH - %d, CAC TIMEOUT - %d sec", + sapContext->channel, cacTimeOut / 1000); + + qdf_mc_timer_init(&pMac->sap.SapDfsInfo.sap_dfs_cac_timer, + QDF_TIMER_TYPE_SW, + sap_dfs_cac_timer_callback, (void *) hHal); + + /*Start the CAC timer */ + status = + qdf_mc_timer_start(&pMac->sap.SapDfsInfo.sap_dfs_cac_timer, + cacTimeOut); + if (status == QDF_STATUS_SUCCESS) { + pMac->sap.SapDfsInfo.is_dfs_cac_timer_running = true; + return 1; + } else { + pMac->sap.SapDfsInfo.is_dfs_cac_timer_running = false; + qdf_mc_timer_destroy(&pMac->sap.SapDfsInfo.sap_dfs_cac_timer); + return 0; + } +} + +/* + * This function initializes the NOL list + * parameters required to track the radar + * found DFS channels in the current Reg. Domain . + */ +QDF_STATUS sap_init_dfs_channel_nol_list(ptSapContext sapContext) +{ + uint8_t count = 0; + int i; + bool bFound = false; + tHalHandle hHal; + tpAniSirGlobal pMac; + + if (NULL == sapContext) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "Invalid sapContext pointer on sap_init_dfs_channel_nol_list"); + return QDF_STATUS_E_FAULT; + } + hHal = CDS_GET_HAL_CB(sapContext->p_cds_gctx); + + if (NULL == hHal) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "In %s invalid hHal", __func__); + return QDF_STATUS_E_FAULT; + } + pMac = PMAC_STRUCT(hHal); + + /* to indicate hdd to get cnss dfs nol */ + if (QDF_STATUS_SUCCESS == sap_signal_hdd_event(sapContext, NULL, + eSAP_DFS_NOL_GET, + (void *) + eSAP_STATUS_SUCCESS)) { + bFound = true; + } + + for (i = CHAN_ENUM_36; i <= CHAN_ENUM_165; i++) { + if (CDS_CHANNEL_STATE(i) == CHANNEL_STATE_DFS) { + /* if dfs nol is not found, initialize it */ + if (!bFound) { + pMac->sap.SapDfsInfo.sapDfsChannelNolList[count] + .dfs_channel_number = + CDS_CHANNEL_NUM(i); + + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_INFO_LOW, + "%s: CHANNEL = %d", __func__, + pMac->sap.SapDfsInfo. + sapDfsChannelNolList[count]. + dfs_channel_number); + + pMac->sap.SapDfsInfo.sapDfsChannelNolList[count] + .radar_status_flag = + eSAP_DFS_CHANNEL_USABLE; + pMac->sap.SapDfsInfo.sapDfsChannelNolList[count] + .radar_found_timestamp = 0; + } + count++; + } + } + + pMac->sap.SapDfsInfo.numCurrentRegDomainDfsChannels = count; + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_LOW, + "%s[%d] NUMBER OF DFS CHANNELS = %d", + __func__, __LINE__, + pMac->sap.SapDfsInfo.numCurrentRegDomainDfsChannels); + + return QDF_STATUS_SUCCESS; +} + +/* + * This function will calculate how many interfaces + * have sap persona and returns total number of sap persona. + */ +uint8_t sap_get_total_number_sap_intf(tHalHandle hHal) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + uint8_t intf = 0; + uint8_t intf_count = 0; + + for (intf = 0; intf < SAP_MAX_NUM_SESSION; intf++) { + if (((QDF_SAP_MODE == pMac->sap.sapCtxList[intf].sapPersona) + || + (QDF_P2P_GO_MODE == pMac->sap.sapCtxList[intf].sapPersona)) + && pMac->sap.sapCtxList[intf].pSapContext != NULL) { + intf_count++; + } + } + return intf_count; +} + +/* + * This function will find the concurrent sap context apart from + * passed sap context and return its channel change ready status + */ +bool is_concurrent_sap_ready_for_channel_change(tHalHandle hHal, + ptSapContext sapContext) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + ptSapContext pSapContext; + uint8_t intf = 0; + + for (intf = 0; intf < SAP_MAX_NUM_SESSION; intf++) { + if (((QDF_SAP_MODE == pMac->sap.sapCtxList[intf].sapPersona) + || + (QDF_P2P_GO_MODE == pMac->sap.sapCtxList[intf].sapPersona)) + && pMac->sap.sapCtxList[intf].pSapContext != NULL) { + pSapContext = + (ptSapContext) pMac->sap.sapCtxList[intf]. + pSapContext; + if (pSapContext == sapContext) { + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_ERROR, + FL("sapCtx matched [%p]"), + sapContext); + continue; + } else { + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_ERROR, + FL + ("concurrent sapCtx[%p] didn't matche with [%p]"), + pSapContext, sapContext); + return pSapContext->is_sap_ready_for_chnl_chng; + } + } + } + return false; +} diff --git a/drivers/staging/qcacld-3.0/core/sap/src/sap_fsm_ext.h b/drivers/staging/qcacld-3.0/core/sap/src/sap_fsm_ext.h new file mode 100644 index 0000000000000000000000000000000000000000..170f1f5bd0a91981af44d4ff5784c84c6895fc79 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/sap/src/sap_fsm_ext.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* This file is generated from btampFsm.cdd - do not edit manually*/ +/* Generated on: Thu Oct 16 15:40:39 PDT 2008 */ + +#ifndef __SAPFSM_EXT_H__ +#define __SAPFSM_EXT_H__ + +/* Events that can be sent to the SAP state-machine */ +typedef enum { + eSAP_TIMER_CONNECT_ACCEPT_TIMEOUT = 0U, + eSAP_MAC_CONNECT_COMPLETED, + eSAP_CHANNEL_SELECTION_FAILED, + eSAP_MAC_CONNECT_INDICATION, + eSAP_MAC_KEY_SET_SUCCESS, + eSAP_RSN_FAILURE, + eSAP_MAC_SCAN_COMPLETE, + eSAP_HDD_START_INFRA_BSS, + eSAP_MAC_READY_FOR_CONNECTIONS, + eSAP_MAC_START_BSS_SUCCESS, + eSAP_MAC_START_BSS_FAILURE, + eSAP_RSN_SUCCESS, + eSAP_MAC_START_FAILS, + eSAP_HDD_STOP_INFRA_BSS, + eSAP_WRITE_REMOTE_AMP_ASSOC, + eSAP_DFS_CHANNEL_CAC_START, + eSAP_DFS_CHANNEL_CAC_RADAR_FOUND, + eSAP_DFS_CHANNEL_CAC_END, + eSAP_DFS_CHNL_SWITCH_ANNOUNCEMENT_START, + eSAP_OPERATING_CHANNEL_CHANGED, + eSAP_CHANNEL_SELECTION_RETRY, + eSAP_CHANNEL_SWITCH_ANNOUNCEMENT_START, + + eSAP_NO_MSG +} eSapMsg_t; + +#endif diff --git a/drivers/staging/qcacld-3.0/core/sap/src/sap_internal.h b/drivers/staging/qcacld-3.0/core/sap/src/sap_internal.h new file mode 100644 index 0000000000000000000000000000000000000000..c73bae8aee1e90c344da5483d3f1b6c013641e7a --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/sap/src/sap_internal.h @@ -0,0 +1,438 @@ +/* + * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef WLAN_QCT_WLANSAP_INTERNAL_H +#define WLAN_QCT_WLANSAP_INTERNAL_H + +/* + * This file contains the internal API exposed by the wlan SAP PAL layer + * module. + */ + +#include "cds_api.h" +#include "cds_packet.h" + +/* Pick up the CSR API definitions */ +#include "csr_api.h" +#include "sap_api.h" +#include "sap_fsm_ext.h" +#include "sap_ch_select.h" + +/*---------------------------------------------------------------------------- + * Preprocessor Definitions and Constants + * -------------------------------------------------------------------------*/ +#ifdef __cplusplus +extern "C" { +#endif + +/*---------------------------------------------------------------------------- + * Defines + * -------------------------------------------------------------------------*/ +/* DFS Non Occupancy Period =30 minutes, in microseconds */ +#define SAP_DFS_NON_OCCUPANCY_PERIOD (30 * 60 * 1000 * 1000) + +#define SAP_DEBUG +/* Used to enable or disable security on the BT-AMP link */ +#define WLANSAP_SECURITY_ENABLED_STATE true + +/* When MBSSID feature is enabled, SAP context is directly passed to SAP APIs */ +#define CDS_GET_SAP_CB(ctx) (ptSapContext)(ctx) + +#define CDS_GET_HAL_CB(ctx) cds_get_context(QDF_MODULE_ID_PE) +/* MAC Address length */ +#define ANI_EAPOL_KEY_RSN_NONCE_SIZE 32 + +#define IS_ETSI_WEATHER_CH(_ch) ((_ch >= 120) && (_ch <= 130)) +#define IS_CH_BONDING_WITH_WEATHER_CH(_ch) (_ch == 116) +#define IS_CHAN_JAPAN_W53(_ch) ((_ch >= 52) && (_ch <= 64)) +#define IS_CHAN_JAPAN_INDOOR(_ch) ((_ch >= 36) && (_ch <= 64)) +#define IS_CHAN_JAPAN_OUTDOOR(_ch)((_ch >= 100) && (_ch <= 140)) +#define DEFAULT_CAC_TIMEOUT (60 * 1000) /* msecs - 1 min */ +#define ETSI_WEATHER_CH_CAC_TIMEOUT (10 * 60 * 1000) /* msecs - 10 min */ +#define SAP_CHAN_PREFERRED_INDOOR 1 +#define SAP_CHAN_PREFERRED_OUTDOOR 2 + +/*---------------------------------------------------------------------------- + * Typedefs + * -------------------------------------------------------------------------*/ +typedef struct sSapContext tSapContext; +/* tSapContext, *ptSapContext; */ +/*---------------------------------------------------------------------------- + * Type Declarations - For internal SAP context information + * -------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------- + * Opaque SAP context Type Declaration + * -------------------------------------------------------------------------*/ +/* We were only using this syntax, when this was truly opaque. */ +/* (I.E., it was defined in a different file.) */ + +/* SAP FSM states for Access Point role */ +typedef enum { + eSAP_DISCONNECTED, + eSAP_CH_SELECT, + eSAP_DFS_CAC_WAIT, + eSAP_STARTING, + eSAP_STARTED, + eSAP_DISCONNECTING +} eSapFsmStates_t; + +/*---------------------------------------------------------------------------- + * SAP context Data Type Declaration + * -------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------- + * Type Declarations - QOS related + * -------------------------------------------------------------------------*/ +/* SAP QOS config */ +typedef struct sSapQosCfg { + uint8_t WmmIsEnabled; +} tSapQosCfg; + +typedef struct sSapAcsChannelInfo { + uint32_t channelNum; + uint32_t weight; +} tSapAcsChannelInfo; + +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE +/* + * In a setup having two MDM both operating in AP+AP MCC scenario + * if both the AP decides to use same or close channel set, CTS to + * self, mechanism is causing issues with connectivity. For this, its + * proposed that 2nd MDM devices which comes up later should detect + * presence of first MDM device via special Q2Q IE present in becon + * and avoid those channels mentioned in IE. + * + * Following struct will keep this info in sapCtx struct, and will be used + * to avoid such channels in Random Channel Select in case of radar ind. + */ +struct sap_avoid_channels_info { + bool present; + uint8_t channels[WNI_CFG_VALID_CHANNEL_LIST_LEN]; +}; +#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ + +typedef struct sSapContext { + + qdf_mutex_t SapGlobalLock; + + /* Include the current channel of AP */ + uint32_t channel; + uint32_t secondary_ch; + + /* Include the SME(CSR) sessionId here */ + uint8_t sessionId; + + /* Include the key material for this physical link */ + uint8_t key_type; + uint8_t key_length; + uint8_t key_material[32]; + + /* Include the associations MAC addresses */ + uint8_t self_mac_addr[CDS_MAC_ADDRESS_LEN]; + + /* Own SSID */ + uint8_t ownSsid[MAX_SSID_LEN]; + uint32_t ownSsidLen; + + /* Flag for signaling if security is enabled */ + uint8_t ucSecEnabled; + + /* Include the SME(CSR) context here */ + tCsrRoamProfile csr_roamProfile; + uint32_t csr_roamId; + + /* Sap session */ + bool isSapSessionOpen; + + /* SAP event Callback to hdd */ + tpWLAN_SAPEventCB pfnSapEventCallback; + + /* Include the enclosing CDS context here */ + void *p_cds_gctx; + + /* + * Include the state machine structure here, state var that keeps + * track of state machine + */ + eSapFsmStates_t sapsMachine; + + /* Actual storage for AP and self (STA) SSID */ + tCsrSSIDInfo SSIDList[2]; + + /* Actual storage for AP bssid */ + struct qdf_mac_addr bssid; + + /* Mac filtering settings */ + eSapMacAddrACL eSapMacAddrAclMode; + struct qdf_mac_addr acceptMacList[MAX_ACL_MAC_ADDRESS]; + uint8_t nAcceptMac; + struct qdf_mac_addr denyMacList[MAX_ACL_MAC_ADDRESS]; + uint8_t nDenyMac; + + /* QOS config */ + tSapQosCfg SapQosCfg; + + void *pUsrContext; + + uint32_t nStaWPARSnReqIeLength; + uint8_t pStaWpaRsnReqIE[MAX_ASSOC_IND_IE_LEN]; + tSirAPWPSIEs APWPSIEs; + tSirRSNie APWPARSNIEs; + +#ifdef FEATURE_WLAN_WAPI + uint32_t nStaWAPIReqIeLength; + uint8_t pStaWapiReqIE[MAX_ASSOC_IND_IE_LEN]; +#endif + + uint32_t nStaAddIeLength; + uint8_t pStaAddIE[MAX_ASSOC_IND_IE_LEN]; + uint8_t *channelList; + uint8_t num_of_channel; + tSapChannelListInfo SapChnlList; + uint16_t ch_width_orig; + struct ch_params_s ch_params; + + /* session to scan */ + bool isScanSessionOpen; + /* + * This list of channels will hold 5Ghz enabled,DFS in the + * Current RegDomain.This list will be used to select a channel, + * for SAP to start including any DFS channel and also to select + * any random channel[5Ghz-(NON-DFS/DFS)],if SAP is operating + * on a DFS channel and a RADAR is detected on the channel. + */ + tAll5GChannelList SapAllChnlList; + + tSapAcsChannelInfo acsBestChannelInfo; + bool enableOverLapCh; + struct sap_acs_cfg *acs_cfg; + +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH + uint8_t cc_switch_mode; +#endif + +#if defined(FEATURE_WLAN_STA_AP_MODE_DFS_DISABLE) + bool dfs_ch_disable; +#endif + bool isCacEndNotified; + bool isCacStartNotified; + bool is_sap_ready_for_chnl_chng; + +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE + /* + * In a setup having two MDM both operating in AP+AP MCC scenario + * if both the AP decides to use same or close channel set, CTS to + * self, mechanism is causing issues with connectivity. For this, its + * proposed that 2nd MDM devices which comes up later should detect + * presence of first MDM device via special Q2Q IE present in becon + * and avoid those channels mentioned in IE. + * + * this struct contains the list of channels on which another MDM AP + * in MCC mode were detected. + */ + struct sap_avoid_channels_info sap_detected_avoid_ch_ie; +#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ + /* + * sap_state, sap_status are created + * to inform upper layers about ACS scan status. + * Don't use these members for anyother purposes. + */ + eSapHddEvent sap_state; + eSapStatus sap_status; + uint32_t roc_ind_scan_id; + + qdf_event_t sap_session_opened_evt; + bool is_pre_cac_on; + bool pre_cac_complete; + uint8_t chan_before_pre_cac; + uint8_t beacon_tx_rate; + tSirMacRateSet supp_rate_set; + tSirMacRateSet extended_rate_set; + enum sap_acs_dfs_mode dfs_mode; +} *ptSapContext; + +/*---------------------------------------------------------------------------- + * External declarations for global context + * -------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------- + * SAP state machine event definition + * -------------------------------------------------------------------------*/ +/* The event structure */ +typedef struct sWLAN_SAPEvent { + /* A VOID pointer type for all possible inputs */ + void *params; + /* State machine input event message */ + uint32_t event; + /* introduced to handle csr_roam_completeCallback roamStatus */ + uint32_t u1; + /* introduced to handle csr_roam_completeCallback roamResult */ + uint32_t u2; +} tWLAN_SAPEvent, *ptWLAN_SAPEvent; + +/*---------------------------------------------------------------------------- + * Function Declarations and Documentation + * -------------------------------------------------------------------------*/ +QDF_STATUS wlansap_context_get(ptSapContext ctx); +void wlansap_context_put(ptSapContext ctx); + +QDF_STATUS +wlansap_scan_callback + (tHalHandle halHandle, + void *pContext, + uint8_t sessionId, uint32_t scanID, eCsrScanStatus scanStatus); + +QDF_STATUS +wlansap_pre_start_bss_acs_scan_callback( + tHalHandle hal_handle, + void *pcontext, + uint8_t sessionid, + uint32_t scanid, + eCsrScanStatus scan_status +); + +QDF_STATUS +wlansap_roam_callback + (void *pContext, + tCsrRoamInfo *pCsrRoamInfo, + uint32_t roamId, + eRoamCmdStatus roamStatus, eCsrRoamResult roamResult); + +QDF_STATUS wlansap_clean_cb(ptSapContext pSapCtx, uint32_t freeFlag); +QDF_STATUS SapFsm(ptSapContext sapContext, ptWLAN_SAPEvent sapEvent, + uint8_t *status); + +void +wlansap_pmc_full_pwr_req_cb(void *callbackContext, QDF_STATUS status); + +uint8_t sap_select_channel(tHalHandle halHandle, ptSapContext pSapCtx, + tScanResultHandle pScanResult); + +QDF_STATUS +sap_signal_hdd_event(ptSapContext sapContext, + tCsrRoamInfo *pCsrRoamInfo, + eSapHddEvent sapHddevent, void *); + +QDF_STATUS sap_fsm(ptSapContext sapContext, ptWLAN_SAPEvent sapEvent); + +eSapStatus +sapconvert_to_csr_profile(tsap_Config_t *pconfig_params, + eCsrRoamBssType bssType, + tCsrRoamProfile *profile); + +void sap_free_roam_profile(tCsrRoamProfile *profile); + +QDF_STATUS +sap_is_peer_mac_allowed(ptSapContext sapContext, uint8_t *peerMac); + +void +sap_sort_mac_list(struct qdf_mac_addr *macList, uint8_t size); + +void +sap_add_mac_to_acl(struct qdf_mac_addr *macList, uint8_t *size, + uint8_t *peerMac); + +void +sap_remove_mac_from_acl(struct qdf_mac_addr *macList, uint8_t *size, + uint8_t index); + +void +sap_print_acl(struct qdf_mac_addr *macList, uint8_t size); + +eSapBool +sap_search_mac_list(struct qdf_mac_addr *macList, uint8_t num_mac, + uint8_t *peerMac, uint8_t *index); + +QDF_STATUS sap_acquire_global_lock(ptSapContext pSapCtx); + +QDF_STATUS sap_release_global_lock(ptSapContext pSapCtx); + +#ifdef FEATURE_WLAN_CH_AVOID +void sap_update_unsafe_channel_list(ptSapContext pSapCtx); +#endif /* FEATURE_WLAN_CH_AVOID */ + +uint8_t +sap_indicate_radar(ptSapContext sapContext, + tSirSmeDfsEventInd *dfs_event); + +QDF_STATUS sap_init_dfs_channel_nol_list(ptSapContext sapContext); + +bool sap_dfs_is_channel_in_nol_list(ptSapContext sapContext, + uint8_t channelNumber, + ePhyChanBondState chanBondState); +void sap_dfs_cac_timer_callback(void *data); + +void sap_cac_reset_notify(tHalHandle hHal); + +bool +sap_channel_matrix_check(ptSapContext sapContext, + ePhyChanBondState cbMode, + uint8_t target_channel); + +bool is_concurrent_sap_ready_for_channel_change(tHalHandle hHal, + ptSapContext + sapContext); + +uint8_t sap_get_total_number_sap_intf(tHalHandle hHal); + +bool sap_dfs_is_w53_invalid(tHalHandle hHal, uint8_t channelID); + +bool sap_dfs_is_channel_in_preferred_location(tHalHandle hHal, + uint8_t channelID); + +QDF_STATUS sap_goto_channel_sel( + ptSapContext sapContext, + ptWLAN_SAPEvent sapEvent, + bool sap_do_acs_pre_start_bss, + bool check_for_connection_update); + +void sap_config_acs_result(tHalHandle hal, ptSapContext sap_ctx, + uint32_t sec_ch); +/** + * sap_check_in_avoid_ch_list() - checks if given channel present is channel + * avoidance list + * avoid_channels_info struct + * @sap_ctx: sap context. + * @channel: channel to be checked in sap_ctx's avoid ch list + * + * sap_ctx contains sap_avoid_ch_info strcut containing the list of channels on + * which MDM device's AP with MCC was detected. This function checks if given + * channel is present in that list. + * + * Return: true, if channel was present, false othersie. + */ +bool +sap_check_in_avoid_ch_list(ptSapContext sap_ctx, uint8_t channel); +QDF_STATUS sap_open_session(tHalHandle hHal, ptSapContext sapContext, + uint32_t *session_id); +QDF_STATUS sap_close_session(tHalHandle hHal, + ptSapContext sapContext, + csr_roamSessionCloseCallback callback, bool valid); +#ifdef __cplusplus +} +#endif +uint8_t sap_select_default_oper_chan(tHalHandle hal, uint32_t acs_hwmode); +#endif diff --git a/drivers/staging/qcacld-3.0/core/sap/src/sap_module.c b/drivers/staging/qcacld-3.0/core/sap/src/sap_module.c new file mode 100644 index 0000000000000000000000000000000000000000..44349c12e90586021c0f943839d643c79c52b00f --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/sap/src/sap_module.c @@ -0,0 +1,3717 @@ +/* + * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * =========================================================================== + * sapModule.C + * OVERVIEW: + * This software unit holds the implementation of the WLAN SAP modules + * functions providing EXTERNAL APIs. It is also where the global SAP module + * context gets initialised + * DEPENDENCIES: + * Are listed for each API below. + * =========================================================================== + */ + +/* $Header$ */ + +/*---------------------------------------------------------------------------- + * Include Files + * -------------------------------------------------------------------------*/ +#include "qdf_trace.h" +#include "qdf_util.h" +#include "qdf_atomic.h" +/* Pick up the sme callback registration API */ +#include "sme_api.h" + +/* SAP API header file */ + +#include "sap_internal.h" +#include "sme_inside.h" +#include "cds_ieee80211_common_i.h" +#include "cds_regdomain.h" +#include "cds_concurrency.h" + +/*---------------------------------------------------------------------------- + * Preprocessor Definitions and Constants + * -------------------------------------------------------------------------*/ +#define SAP_DEBUG + +/*---------------------------------------------------------------------------- + * Type Declarations + * -------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------- + * Global Data Definitions + * -------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------- + * External declarations for global context + * -------------------------------------------------------------------------*/ +/* No! Get this from CDS. */ +/* The main per-Physical Link (per WLAN association) context. */ +static ptSapContext gp_sap_ctx[SAP_MAX_NUM_SESSION]; +static qdf_atomic_t sap_ctx_ref_count[SAP_MAX_NUM_SESSION]; + +/*---------------------------------------------------------------------------- + * Static Variable Definitions + * -------------------------------------------------------------------------*/ +static qdf_mutex_t sap_context_lock; + +/*---------------------------------------------------------------------------- + * Static Function Declarations and Definitions + * -------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------- + * Externalized Function Definitions + * -------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------- + * Function Declarations and Documentation + * -------------------------------------------------------------------------*/ + +/** + * wlansap_global_init() - Initialize SAP globals + * + * Initializes the SAP global data structures + * + * Return: QDF_STATUS + */ +QDF_STATUS wlansap_global_init(void) +{ + uint32_t i; + + if (QDF_IS_STATUS_ERROR(qdf_mutex_create(&sap_context_lock))) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "failed to init sap_context_lock"); + return QDF_STATUS_E_FAULT; + } + + for (i = 0; i < SAP_MAX_NUM_SESSION; i++) { + gp_sap_ctx[i] = NULL; + qdf_atomic_init(&sap_ctx_ref_count[i]); + } + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO, + "%s: sap global context initialized", __func__); + + return QDF_STATUS_SUCCESS; +} + +/** + * wlansap_global_deinit() - De-initialize SAP globals + * + * De-initializes the SAP global data structures + * + * Return: QDF_STATUS + */ +QDF_STATUS wlansap_global_deinit(void) +{ + uint32_t i; + + for (i = 0; i < SAP_MAX_NUM_SESSION; i++) { + if (gp_sap_ctx[i]) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "we could be leaking context:%d", i); + } + gp_sap_ctx[i] = NULL; + qdf_atomic_init(&sap_ctx_ref_count[i]); + } + + if (QDF_IS_STATUS_ERROR(qdf_mutex_destroy(&sap_context_lock))) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "failed to destroy sap_context_lock"); + return QDF_STATUS_E_FAULT; + } + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO, + "%s: sap global context deinitialized", __func__); + + return QDF_STATUS_SUCCESS; +} + +/** + * wlansap_save_context() - Save the context in global SAP context + * @ctx: SAP context to be stored + * + * Stores the given SAP context in the global SAP context array + * + * Return: QDF_STATUS + */ +static QDF_STATUS wlansap_save_context(ptSapContext ctx) +{ + uint32_t i; + + qdf_mutex_acquire(&sap_context_lock); + for (i = 0; i < SAP_MAX_NUM_SESSION; i++) { + if (gp_sap_ctx[i] == NULL) { + gp_sap_ctx[i] = ctx; + qdf_atomic_inc(&sap_ctx_ref_count[i]); + qdf_mutex_release(&sap_context_lock); + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO, + "%s: sap context saved at index:%d", + __func__, i); + return QDF_STATUS_SUCCESS; + } + } + qdf_mutex_release(&sap_context_lock); + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: failed to save sap context", __func__); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wlansap_context_get() - Verify SAP context and increment ref count + * @ctx: Context to be checked + * + * Verifies the SAP context and increments the reference count maintained for + * the corresponding SAP context. + * + * Return: QDF_STATUS + */ +QDF_STATUS wlansap_context_get(ptSapContext ctx) +{ + uint32_t i; + + qdf_mutex_acquire(&sap_context_lock); + for (i = 0; i < SAP_MAX_NUM_SESSION; i++) { + if (ctx && (gp_sap_ctx[i] == ctx)) { + qdf_atomic_inc(&sap_ctx_ref_count[i]); + qdf_mutex_release(&sap_context_lock); + return QDF_STATUS_SUCCESS; + } + } + qdf_mutex_release(&sap_context_lock); + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: sap session is not valid", __func__); + return QDF_STATUS_E_FAILURE; +} + +/** + * wlansap_context_put() - Check the reference count and free SAP context + * @ctx: SAP context to be checked and freed + * + * Checks the reference count and frees the SAP context + * + * Return: None + */ +void wlansap_context_put(ptSapContext ctx) +{ + uint32_t i; + + if (!ctx) + return; + + qdf_mutex_acquire(&sap_context_lock); + for (i = 0; i < SAP_MAX_NUM_SESSION; i++) { + if (gp_sap_ctx[i] == ctx) { + if (qdf_atomic_dec_and_test(&sap_ctx_ref_count[i])) { + qdf_mem_free(ctx); + gp_sap_ctx[i] = NULL; + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_INFO, + "%s: sap session freed: %d", + __func__, i); + } + qdf_mutex_release(&sap_context_lock); + return; + } + } + qdf_mutex_release(&sap_context_lock); +} + +/** + * wlansap_open() - WLAN SAP open function call + * @p_cds_gctx: Pointer to the global cds context; a handle to SAP's + * + * Called at driver initialization (cds_open). SAP will initialize + * all its internal resources and will wait for the call to start to + * register with the other modules. + * + * Return: Pointer to the SAP context + */ +void *wlansap_open(void *p_cds_gctx) +{ + ptSapContext pSapCtx = NULL; + QDF_STATUS status; + + /* dynamically allocate the sapContext */ + pSapCtx = (ptSapContext) qdf_mem_malloc(sizeof(tSapContext)); + + if (NULL == pSapCtx) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid SAP pointer from p_cds_gctx", __func__); + return NULL; + } + + /* Clean up SAP control block, initialize all values */ + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, "wlansap_open"); + + wlansap_clean_cb(pSapCtx, 0); /*do not empty */ + + /* Setup the "link back" to the CDS context */ + pSapCtx->p_cds_gctx = p_cds_gctx; + + /* Save the SAP context pointer */ + status = wlansap_save_context(pSapCtx); + if (QDF_IS_STATUS_ERROR(status)) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: failed to save SAP context", __func__); + qdf_mem_free(pSapCtx); + return NULL; + } + + return pSapCtx; +} /* wlansap_open */ + +/** + * wlansap_start() - wlan start SAP. + * @pCtx: Pointer to the global cds context; a handle to SAP's + * control block can be extracted from its context + * When MBSSID feature is enabled, SAP context is directly + * passed to SAP APIs + * @pSapEventCallback: Callback function to register + * @mode: Device mode + * @addr: MAC address of the SAP + * @session_id: Pointer to the session id + * @pUsrContext: user context to be used in callback @pSapEventCallback + * + * Called as part of the overall start procedure (cds_enable). SAP will + * use this call to register with TL as the SAP entity for SAP RSN frames. + * + * Return: The result code associated with performing the operation + * QDF_STATUS_E_FAULT: Pointer to SAP cb is NULL; + * access would cause a page fault. + * QDF_STATUS_SUCCESS: Success + */ +QDF_STATUS wlansap_start(void *pCtx, tpWLAN_SAPEventCB pSapEventCallback, + enum tQDF_ADAPTER_MODE mode, uint8_t *addr, + uint32_t *session_id, void *pUsrContext) +{ + ptSapContext pSapCtx = NULL; + QDF_STATUS qdf_ret_status; + tHalHandle hal; + + /*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/ + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + "wlansap_start invoked successfully"); + /*------------------------------------------------------------------------ + Sanity check + Extract SAP control block + ------------------------------------------------------------------------*/ + pSapCtx = CDS_GET_SAP_CB(pCtx); + + if (NULL == pSapCtx) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid SAP pointer from pCtx", __func__); + return QDF_STATUS_E_FAULT; + } + + /*------------------------------------------------------------------------ + For now, presume security is not enabled. + -----------------------------------------------------------------------*/ + pSapCtx->ucSecEnabled = WLANSAP_SECURITY_ENABLED_STATE; + + /*------------------------------------------------------------------------ + Now configure the roaming profile links. To SSID and bssid. + ------------------------------------------------------------------------*/ + /* We have room for two SSIDs. */ + pSapCtx->csr_roamProfile.SSIDs.numOfSSIDs = 1; /* This is true for now. */ + pSapCtx->csr_roamProfile.SSIDs.SSIDList = pSapCtx->SSIDList; /* Array of two */ + pSapCtx->csr_roamProfile.SSIDs.SSIDList[0].SSID.length = 0; + pSapCtx->csr_roamProfile.SSIDs.SSIDList[0].handoffPermitted = false; + pSapCtx->csr_roamProfile.SSIDs.SSIDList[0].ssidHidden = + pSapCtx->SSIDList[0].ssidHidden; + + pSapCtx->csr_roamProfile.BSSIDs.numOfBSSIDs = 1; /* This is true for now. */ + pSapCtx->csr_roamProfile.BSSIDs.bssid = &pSapCtx->bssid; + pSapCtx->csr_roamProfile.csrPersona = mode; + qdf_mem_copy(pSapCtx->self_mac_addr, addr, QDF_MAC_ADDR_SIZE); + qdf_event_create(&pSapCtx->sap_session_opened_evt); + + /* Now configure the auth type in the roaming profile. To open. */ + pSapCtx->csr_roamProfile.negotiatedAuthType = eCSR_AUTH_TYPE_OPEN_SYSTEM; /* open is the default */ + + pSapCtx->pfnSapEventCallback = pSapEventCallback; + pSapCtx->pUsrContext = pUsrContext; + + if (!QDF_IS_STATUS_SUCCESS(qdf_mutex_create(&pSapCtx->SapGlobalLock))) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "wlansap_start failed init lock"); + return QDF_STATUS_E_FAULT; + } + + hal = (tHalHandle) CDS_GET_HAL_CB(pSapCtx->p_cds_gctx); + if (!hal) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid HAL pointer", __func__); + return QDF_STATUS_E_INVAL; + } + + qdf_ret_status = sap_open_session(hal, pSapCtx, session_id); + + if (QDF_STATUS_SUCCESS != qdf_ret_status) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "Error: In %s calling sap_open_session status = %d", + __func__, qdf_ret_status); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * wlansap_stop() - stop SAP module. + * @pCtx: Pointer to the global cds context; a handle to SAP's control block + * can be extracted from its context. When MBSSID feature is enabled, + * SAP context is directly passed to SAP APIs + * + * Called by cds_disable to stop operation in SAP, before close. SAP will + * suspend all BT-AMP Protocol Adaption Layer operation and will wait for the + * close request to clean up its resources. + * + * Return: The result code associated with performing the operation + * QDF_STATUS_E_FAULT: Pointer to SAP cb is NULL; + * access would cause a page fault. + * QDF_STATUS_SUCCESS: Success + */ +QDF_STATUS wlansap_stop(void *pCtx) +{ + ptSapContext pSapCtx = NULL; + + /* Sanity check - Extract SAP control block */ + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + "wlansap_stop invoked successfully "); + + pSapCtx = CDS_GET_SAP_CB(pCtx); + if (NULL == pSapCtx) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid SAP pointer from pCtx", __func__); + return QDF_STATUS_E_FAULT; + } + + sap_free_roam_profile(&pSapCtx->csr_roamProfile); + + if (!QDF_IS_STATUS_SUCCESS(qdf_mutex_destroy(&pSapCtx->SapGlobalLock))) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "wlansap_stop failed destroy lock"); + return QDF_STATUS_E_FAULT; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * wlansap_close - close SAP module. + * @pCtx: Pointer to the global cds context; a handle to SAP's control block + * can be extracted from its context. When MBSSID feature is enabled, + * SAP context is directly passed to SAP APIs. + * + * Called by cds_close during general driver close procedure. SAP will clean up + * all the internal resources. + * + * Return: The result code associated with performing the operation + * QDF_STATUS_E_FAULT: Pointer to SAP cb is NULL; + * access would cause a page fault + * QDF_STATUS_SUCCESS: Success + */ +QDF_STATUS wlansap_close(void *pCtx) +{ + ptSapContext pSapCtx = NULL; + + /* Sanity check - Extract SAP control block */ + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + "wlansap_close invoked"); + + pSapCtx = CDS_GET_SAP_CB(pCtx); + if (NULL == pSapCtx) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid SAP pointer from pCtx", __func__); + return QDF_STATUS_E_FAULT; + } + + /* Cleanup SAP control block */ + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + "wlansap_close"); + + sap_cleanup_channel_list(pCtx); + + /* empty queues/lists/pkts if any */ + wlansap_clean_cb(pSapCtx, true); + + wlansap_context_put(pSapCtx); + + return QDF_STATUS_SUCCESS; +} /* wlansap_close */ + +/*---------------------------------------------------------------------------- + * Utility Function implementations + * -------------------------------------------------------------------------*/ + +/** + * wlansap_clean_cb() - clean SAP callback function. + * @pCtx: Pointer to the global cds context; a handle to SAP's control block + * can be extracted from its context. When MBSSID feature is enabled, + * SAP context is directly passed to SAP APIs. + * + * Clear out all fields in the SAP context. + * + * Return: The result code associated with performing the operation + * QDF_STATUS_E_FAULT: Pointer to SAP cb is NULL; + * access would cause a page fault + * QDF_STATUS_SUCCESS: Success + */ +QDF_STATUS wlansap_clean_cb(ptSapContext pSapCtx, uint32_t freeFlag /* 0 / *do not empty* /); */ + ) { + tHalHandle hal; + + /*------------------------------------------------------------------------ + Sanity check SAP control block + ------------------------------------------------------------------------*/ + + if (NULL == pSapCtx) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid SAP pointer", __func__); + return QDF_STATUS_E_FAULT; + } + + /*------------------------------------------------------------------------ + Clean up SAP control block, initialize all values + ------------------------------------------------------------------------*/ + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + "wlansap_clean_cb"); + + hal = (tHalHandle) CDS_GET_HAL_CB(pSapCtx->p_cds_gctx); + if (eSAP_TRUE == pSapCtx->isSapSessionOpen && hal) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO, + "close existing SAP session"); + sap_close_session(hal, pSapCtx, sap_roam_session_close_callback, + pSapCtx); + } + + qdf_mem_zero(pSapCtx, sizeof(tSapContext)); + + pSapCtx->p_cds_gctx = NULL; + + pSapCtx->sapsMachine = eSAP_DISCONNECTED; + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: Initializing State: %d, sapContext value = %p", __func__, + pSapCtx->sapsMachine, pSapCtx); + pSapCtx->sessionId = 0; + pSapCtx->channel = 0; + + return QDF_STATUS_SUCCESS; +} /* wlansap_clean_cb */ + +/*========================================================================== + FUNCTION wlansap_pmc_full_pwr_req_cb + + DESCRIPTION + Callback provide to PMC in the pmc_request_full_power API. + + DEPENDENCIES + + PARAMETERS + + IN + callbackContext: The user passed in a context to identify + status : The qdf_ret_status + + RETURN VALUE + None + + SIDE EFFECTS + ============================================================================*/ +void +wlansap_pmc_full_pwr_req_cb(void *callbackContext, QDF_STATUS status) +{ + if (QDF_IS_STATUS_SUCCESS(status)) { + /* If success what else to be handled??? */ + } else { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_FATAL, + "wlansap_pmc_full_pwr_req_cb: PMC failed to put the chip in Full power"); + + } + +} /* wlansap_pmc_full_pwr_req_cb */ + +/** + * wlansap_get_state() - get SAP state + * @pCtx: Pointer to the global cds context; a handle to SAP's control block + * can be extracted from its context. When MBSSID feature is enabled, + * SAP context is directly passed to SAP APIs. + * + * This api returns the current SAP state to the caller. + * + * Return: uint8_t - the SAP FSM state. + */ +uint8_t wlansap_get_state(void *pCtx) +{ + ptSapContext pSapCtx = NULL; + + pSapCtx = CDS_GET_SAP_CB(pCtx); + + if (NULL == pSapCtx) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: Invalid SAP pointer from pCtx", __func__); + return QDF_STATUS_E_FAULT; + } + return pSapCtx->sapsMachine; +} + +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH +/*========================================================================== + FUNCTION wlansap_check_cc_intf + + DESCRIPTION Restart SAP if Concurrent Channel interfering + + DEPENDENCIES NA. + + PARAMETERS + IN + Ctx: Pointer to cds Context or Sap Context based on MBSSID + + RETURN VALUE NONE + + SIDE EFFECTS + ============================================================================*/ +uint16_t wlansap_check_cc_intf(void *Ctx) +{ + tHalHandle hHal; + uint16_t intf_ch; + ptSapContext pSapCtx = CDS_GET_SAP_CB(Ctx); + + hHal = (tHalHandle) CDS_GET_HAL_CB(pSapCtx->p_cds_gctx); + if (NULL == hHal) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid MAC context from p_cds_gctx", __func__); + return 0; + } + intf_ch = sme_check_concurrent_channel_overlap(hHal, 0, 0, + pSapCtx->cc_switch_mode); + return intf_ch; +} +#endif + + /** + * wlansap_set_scan_acs_channel_params() - Config scan and channel parameters. + * pconfig: Pointer to the SAP config + * psap_ctx: Pointer to the SAP Context. + * pusr_context: Parameter that will be passed + * back in all the SAP callback events. + * + * This api function is used to copy Scan and Channel parameters from sap + * config to sap context. + * + * Return: The result code associated with + * performing the operation + */ +static QDF_STATUS +wlansap_set_scan_acs_channel_params(tsap_Config_t *pconfig, + ptSapContext psap_ctx, + void *pusr_context) +{ + tHalHandle h_hal = NULL; + + if (NULL == pconfig) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid pconfig passed ", __func__); + return QDF_STATUS_E_FAULT; + } + + if (NULL == psap_ctx) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid pconfig passed ", __func__); + return QDF_STATUS_E_FAULT; + } + + /* Channel selection is auto or configured */ + psap_ctx->channel = pconfig->channel; + psap_ctx->dfs_mode = pconfig->acs_dfs_mode; +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH + psap_ctx->cc_switch_mode = pconfig->cc_switch_mode; +#endif + psap_ctx->pUsrContext = pusr_context; + psap_ctx->enableOverLapCh = pconfig->enOverLapCh; + psap_ctx->acs_cfg = &pconfig->acs_cfg; + psap_ctx->ch_width_orig = pconfig->acs_cfg.ch_width; + psap_ctx->secondary_ch = pconfig->sec_ch; + + /* + * Set the BSSID to your "self MAC Addr" read + * the mac address from Configuation ITEM received + * from HDD + */ + psap_ctx->csr_roamProfile.BSSIDs.numOfBSSIDs = 1; + + /* Save a copy to SAP context */ + qdf_mem_copy(psap_ctx->csr_roamProfile.BSSIDs.bssid, + pconfig->self_macaddr.bytes, QDF_MAC_ADDR_SIZE); + qdf_mem_copy(psap_ctx->self_mac_addr, + pconfig->self_macaddr.bytes, QDF_MAC_ADDR_SIZE); + + h_hal = (tHalHandle)CDS_GET_HAL_CB(psap_ctx->p_cds_gctx); + if (NULL == h_hal) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: Invalid MAC context from pvosGCtx", __func__); + } else { + /* + * If concurrent session is running that is already associated + * then we just follow that sessions country info (whether + * present or not doesn't maater as we have to follow whatever + * STA session does) + */ + if ((0 == sme_get_concurrent_operation_channel(h_hal)) && + pconfig->ieee80211d) { + /* Setting the region/country information */ + sme_set_reg_info(h_hal, pconfig->countryCode); + sme_apply_channel_power_info_to_fw(h_hal); + } + } + + return QDF_STATUS_SUCCESS; +} +/** + * wlan_sap_get_vht_ch_width() - Returns SAP VHT channel width. + * @ctx: Pointer to cds Context or Sap Context based on MBSSID + * + * This function provides the SAP current VHT channel with. + * + * Return: VHT channel width + */ +uint32_t wlan_sap_get_vht_ch_width(void *ctx) +{ + ptSapContext sap_ctx = CDS_GET_SAP_CB(ctx); + + if (!sap_ctx) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("Invalid SAP pointer from ctx")); + return 0; + } + + return sap_ctx->ch_params.ch_width; +} + +/** + * wlan_sap_set_vht_ch_width() - Sets SAP VHT channel width. + * @ctx: Pointer to cds Context or Sap Context based on MBSSID + * @vht_channel_width: SAP VHT channel width value. + * + * This function sets the SAP current VHT channel with. + * + * Return: None + */ +void wlan_sap_set_vht_ch_width(void *ctx, uint32_t vht_channel_width) +{ + ptSapContext sap_ctx = CDS_GET_SAP_CB(ctx); + + if (!sap_ctx) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("Invalid SAP pointer from ctx")); + return; + } + + sap_ctx->ch_params.ch_width = vht_channel_width; +} + +/** + * wlan_sap_validate_channel_switch() - validate target channel switch w.r.t + * concurreny rules set to avoid channel interference. + * @hal - Hal context + * @sap_ch - channel to switch + * @sap_context - sap session context + * + * Return: true if there is no channel interference else return false + */ +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH +static bool wlan_sap_validate_channel_switch(tHalHandle hal, uint16_t sap_ch, + ptSapContext sap_context) +{ + return sme_validate_sap_channel_switch( + hal, + sap_ch, + sap_context->csr_roamProfile.phyMode, + sap_context->cc_switch_mode, + sap_context->sessionId); +} +#else +static inline bool wlan_sap_validate_channel_switch(tHalHandle hal, + uint16_t sap_ch, ptSapContext sap_context) +{ + return true; +} +#endif +/** + * wlansap_start_bss() - start BSS + * @pCtx: Pointer to the global cds context; a handle to SAP's control block + * can be extracted from its context. When MBSSID feature is enabled, + * SAP context is directly passed to SAP APIs. + * @pQctCommitConfig: Pointer to configuration structure passed down from + * HDD(HostApd for Android) + * @hdd_SapEventCallback: Callback function in HDD called by SAP to inform HDD + * about SAP results + * @pUsrContext: Parameter that will be passed back in all the SAP callback + * events. + * + * This api function provides SAP FSM event eWLAN_SAP_PHYSICAL_LINK_CREATE for + * starting AP BSS + * + * Return: The result code associated with performing the operation + * QDF_STATUS_E_FAULT: Pointer to SAP cb is NULL; + * access would cause a page fault + * QDF_STATUS_SUCCESS: Success + */ +QDF_STATUS wlansap_start_bss(void *pCtx, /* pwextCtx */ + tpWLAN_SAPEventCB pSapEventCallback, + tsap_Config_t *pConfig, void *pUsrContext) { + tWLAN_SAPEvent sapEvent; /* State machine event */ + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + ptSapContext pSapCtx = NULL; + tHalHandle hHal; + tpAniSirGlobal pmac = NULL; + + /*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/ + + /*------------------------------------------------------------------------ + Sanity check + Extract SAP control block + ------------------------------------------------------------------------*/ + pSapCtx = CDS_GET_SAP_CB(pCtx); + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + "wlansap_start_bss: sapContext=%p", pSapCtx); + + if (NULL == pSapCtx) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: Invalid SAP pointer from pCtx", + __func__); + return QDF_STATUS_E_FAULT; + } + pSapCtx->sapsMachine = eSAP_DISCONNECTED; + + /* Channel selection is auto or configured */ + pSapCtx->channel = pConfig->channel; + pSapCtx->dfs_mode = pConfig->acs_dfs_mode; + pSapCtx->ch_params.ch_width = pConfig->ch_params.ch_width; + pSapCtx->ch_params.center_freq_seg0 = + pConfig->ch_params.center_freq_seg0; + pSapCtx->ch_params.center_freq_seg1 = + pConfig->ch_params.center_freq_seg1; + pSapCtx->ch_params.sec_ch_offset = + pConfig->ch_params.sec_ch_offset; + pSapCtx->ch_width_orig = pConfig->ch_width_orig; +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH + pSapCtx->cc_switch_mode = pConfig->cc_switch_mode; +#endif + pSapCtx->pUsrContext = pUsrContext; + pSapCtx->enableOverLapCh = pConfig->enOverLapCh; + pSapCtx->acs_cfg = &pConfig->acs_cfg; + /* Set the BSSID to your "self MAC Addr" read the mac address + from Configuation ITEM received from HDD */ + pSapCtx->csr_roamProfile.BSSIDs.numOfBSSIDs = 1; + qdf_mem_copy(pSapCtx->csr_roamProfile.BSSIDs.bssid, + pSapCtx->self_mac_addr, sizeof(struct qdf_mac_addr)); + + /* Save a copy to SAP context */ + qdf_mem_copy(pSapCtx->csr_roamProfile.BSSIDs.bssid, + pConfig->self_macaddr.bytes, QDF_MAC_ADDR_SIZE); + qdf_mem_copy(pSapCtx->self_mac_addr, + pConfig->self_macaddr.bytes, QDF_MAC_ADDR_SIZE); + + /* copy the configuration items to csrProfile */ + sapconvert_to_csr_profile(pConfig, eCSR_BSS_TYPE_INFRA_AP, + &pSapCtx->csr_roamProfile); + hHal = (tHalHandle) CDS_GET_HAL_CB(pSapCtx->p_cds_gctx); + if (NULL == hHal) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: Invalid MAC context from p_cds_gctx", + __func__); + return QDF_STATUS_E_FAULT; + } else { + /* If concurrent session is running that is already associated + * then we just follow that sessions country info (whether + * present or not doesn't maater as we have to follow whatever + * STA session does) */ + if ((0 == sme_get_concurrent_operation_channel(hHal)) && + pConfig->ieee80211d) { + /* Setting the region/country information */ + sme_set_reg_info(hHal, pConfig->countryCode); + sme_apply_channel_power_info_to_fw(hHal); + } + } + + pmac = PMAC_STRUCT(hHal); + if (NULL == pmac) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: Invalid MAC context from p_cds_gctx", + __func__); + return QDF_STATUS_E_FAULT; + } + /* + * Copy the DFS Test Mode setting to pmac for + * access in lower layers + */ + pmac->sap.SapDfsInfo.disable_dfs_ch_switch = + pConfig->disableDFSChSwitch; + + /* Copy MAC filtering settings to sap context */ + pSapCtx->eSapMacAddrAclMode = pConfig->SapMacaddr_acl; + qdf_mem_copy(pSapCtx->acceptMacList, pConfig->accept_mac, + sizeof(pConfig->accept_mac)); + pSapCtx->nAcceptMac = pConfig->num_accept_mac; + sap_sort_mac_list(pSapCtx->acceptMacList, pSapCtx->nAcceptMac); + qdf_mem_copy(pSapCtx->denyMacList, pConfig->deny_mac, + sizeof(pConfig->deny_mac)); + pSapCtx->nDenyMac = pConfig->num_deny_mac; + sap_sort_mac_list(pSapCtx->denyMacList, pSapCtx->nDenyMac); + /* Fill in the event structure for FSM */ + sapEvent.event = eSAP_HDD_START_INFRA_BSS; + sapEvent.params = 0; /* pSapPhysLinkCreate */ + + /* Store the HDD callback in SAP context */ + pSapCtx->pfnSapEventCallback = pSapEventCallback; + + /* Handle event */ + qdf_status = sap_fsm(pSapCtx, &sapEvent); + + return qdf_status; +} /* wlansap_start_bss */ + +/** + * wlansap_set_mac_acl() - set MAC list entry in ACL. + * @pCtx: Pointer to the global cds context; a handle to SAP's control block + * can be extracted from its context. When MBSSID feature is enabled, + * SAP context is directly passed to SAP APIs. + * @pConfig: Pointer to SAP config. + * + * This api function provides SAP to set mac list entry in accept list as well + * as deny list + * + * Return: The result code associated with performing the operation + * QDF_STATUS_E_FAULT: Pointer to SAP cb is NULL; + * access would cause a page fault + * QDF_STATUS_SUCCESS: Success + */ +QDF_STATUS wlansap_set_mac_acl(void *pCtx, /* pwextCtx */ + tsap_Config_t *pConfig) { + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + ptSapContext pSapCtx = NULL; + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + "wlansap_set_mac_acl"); + + pSapCtx = CDS_GET_SAP_CB(pCtx); + if (NULL == pSapCtx) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: Invalid SAP pointer from pCtx", + __func__); + return QDF_STATUS_E_FAULT; + } + /* Copy MAC filtering settings to sap context */ + pSapCtx->eSapMacAddrAclMode = pConfig->SapMacaddr_acl; + + if (eSAP_DENY_UNLESS_ACCEPTED == pSapCtx->eSapMacAddrAclMode) { + qdf_mem_copy(pSapCtx->acceptMacList, + pConfig->accept_mac, + sizeof(pConfig->accept_mac)); + pSapCtx->nAcceptMac = pConfig->num_accept_mac; + sap_sort_mac_list(pSapCtx->acceptMacList, + pSapCtx->nAcceptMac); + } else if (eSAP_ACCEPT_UNLESS_DENIED == + pSapCtx->eSapMacAddrAclMode) { + qdf_mem_copy(pSapCtx->denyMacList, pConfig->deny_mac, + sizeof(pConfig->deny_mac)); + pSapCtx->nDenyMac = pConfig->num_deny_mac; + sap_sort_mac_list(pSapCtx->denyMacList, pSapCtx->nDenyMac); + } + + return qdf_status; +} /* wlansap_set_mac_acl */ + +/** + * wlansap_stop_bss() - stop BSS. + * @pCtx: Pointer to the global cds context; a handle to SAP's control block + * can be extracted from its context. When MBSSID feature is enabled, + * SAP context is directly passed to SAP APIs. + * + * This api function provides SAP FSM event eSAP_HDD_STOP_INFRA_BSS for + * stopping AP BSS + * + * Return: The result code associated with performing the operation + * QDF_STATUS_E_FAULT: Pointer to SAP cb is NULL; + * access would cause a page fault + * QDF_STATUS_SUCCESS: Success + */ +QDF_STATUS wlansap_stop_bss(void *pCtx) +{ + tWLAN_SAPEvent sapEvent; /* State machine event */ + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + ptSapContext pSapCtx = NULL; + /*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/ + + /*------------------------------------------------------------------------ + Sanity check + Extract SAP control block + ------------------------------------------------------------------------*/ + if (NULL == pCtx) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid Global CDS handle", __func__); + return QDF_STATUS_E_FAULT; + } + + pSapCtx = CDS_GET_SAP_CB(pCtx); + + if (NULL == pSapCtx) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid SAP pointer from pCtx", __func__); + return QDF_STATUS_E_FAULT; + } + + /* Fill in the event structure for FSM */ + sapEvent.event = eSAP_HDD_STOP_INFRA_BSS; + sapEvent.params = 0; + + /* Handle event */ + qdf_status = sap_fsm(pSapCtx, &sapEvent); + + return qdf_status; +} + +/** + * wlansap_get_assoc_stations() - get list of associated stations. + * @pCtx: Pointer to the global cds context; a handle to SAP's control block + * can be extracted from its context. When MBSSID feature is enabled, + * SAP context is directly passed to SAP APIs. + * @modId: Module from whom list of associtated stations is supposed to be + * probed. If an invalid module is passed then by default + * QDF_MODULE_ID_PE will be probed + * @pAssocStas: Pointer to list of associated stations that are known to the + * module specified in mod parameter + * + * This api function is used to probe the list of associated stations from + * various modules of CORE stack + * NOTE: The memory for this list will be allocated by the caller of this API + * + * Return: The result code associated with performing the operation + * QDF_STATUS_SUCCESS: Success + */ +QDF_STATUS +wlansap_get_assoc_stations + (void *pCtx, QDF_MODULE_ID modId, tpSap_AssocMacAddr pAssocStas) { + ptSapContext pSapCtx = CDS_GET_SAP_CB(pCtx); + + /*------------------------------------------------------------------------ + Sanity check + Extract SAP control block + ------------------------------------------------------------------------*/ + if (NULL == pSapCtx) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid SAP pointer from pCtx", __func__); + return QDF_STATUS_E_FAULT; + } + + sme_roam_get_associated_stas(CDS_GET_HAL_CB(pSapCtx->p_cds_gctx), + pSapCtx->sessionId, modId, + pSapCtx->pUsrContext, + (void **) pSapCtx->pfnSapEventCallback, + (uint8_t *) pAssocStas); + + return QDF_STATUS_SUCCESS; +} + +/** + * wlansap_remove_wps_session_overlap() - remove overlapping wps session. + * @pCtx: Pointer to the global cds context; a handle to SAP's control block + * can be extracted from its context. When MBSSID feature is enabled, + * SAP context is directly passed to SAP APIs. + * @pRemoveMac: pointer to struct qdf_mac_addr for session MAC address + * + * This api function provides for Ap App/HDD to remove an entry from session + * overlap info. + * + * Return: The QDF_STATUS code associated with performing the operation + * QDF_STATUS_SUCCESS: Success + * QDF_STATUS_E_FAULT: Session is not dectected. + * The parameter is function not valid. + */ +QDF_STATUS +wlansap_remove_wps_session_overlap(void *pCtx, + struct qdf_mac_addr pRemoveMac) +{ + ptSapContext pSapCtx = CDS_GET_SAP_CB(pCtx); + + /*------------------------------------------------------------------------ + Sanity check + Extract SAP control block + ------------------------------------------------------------------------*/ + if (NULL == pSapCtx) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid SAP pointer from pCtx", __func__); + return QDF_STATUS_E_FAULT; + } + + sme_roam_get_wps_session_overlap(CDS_GET_HAL_CB(pSapCtx->p_cds_gctx), + pSapCtx->sessionId, pSapCtx->pUsrContext, + (void **) pSapCtx->pfnSapEventCallback, + pRemoveMac); + + return QDF_STATUS_SUCCESS; +} + +/** + * wlansap_get_wps_session_overlap() - get overlapping wps session. + * @pCtx: Pointer to the global cds context; a handle to SAP's control block + * can be extracted from its context. When MBSSID feature is enabled, + * SAP context is directly passed to SAP APIs. + * + * This api function provides for Ap App/HDD to get WPS session overlap info. + * + * Return: The QDF_STATUS code associated with performing the operation + * QDF_STATUS_SUCCESS: Success + */ +QDF_STATUS wlansap_get_wps_session_overlap(void *pCtx) +{ + struct qdf_mac_addr pRemoveMac = QDF_MAC_ADDR_ZERO_INITIALIZER; + + ptSapContext pSapCtx = CDS_GET_SAP_CB(pCtx); + + /*------------------------------------------------------------------------ + Sanity check + Extract SAP control block + ------------------------------------------------------------------------*/ + if (NULL == pSapCtx) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid SAP pointer from pCtx", __func__); + return QDF_STATUS_E_FAULT; + } + + sme_roam_get_wps_session_overlap(CDS_GET_HAL_CB(pSapCtx->p_cds_gctx), + pSapCtx->sessionId, pSapCtx->pUsrContext, + (void **) pSapCtx->pfnSapEventCallback, + pRemoveMac); + + return QDF_STATUS_SUCCESS; +} + +/* This routine will set the mode of operation for ACL dynamically*/ +QDF_STATUS wlansap_set_mode(void *pCtx, uint32_t mode) +{ + ptSapContext pSapCtx = CDS_GET_SAP_CB(pCtx); + + if (NULL == pSapCtx) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid SAP pointer from pCtx", __func__); + return QDF_STATUS_E_FAULT; + } + + pSapCtx->eSapMacAddrAclMode = (eSapMacAddrACL) mode; + return QDF_STATUS_SUCCESS; +} + +/* Get ACL Mode */ +QDF_STATUS wlansap_get_acl_mode(void *pCtx, eSapMacAddrACL *mode) +{ + ptSapContext pSapCtx = CDS_GET_SAP_CB(pCtx); + + if (NULL == pSapCtx) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid SAP pointer from pCtx", __func__); + return QDF_STATUS_E_FAULT; + } + + *mode = pSapCtx->eSapMacAddrAclMode; + return QDF_STATUS_SUCCESS; +} + +/* API to get ACL Accept List */ +QDF_STATUS +wlansap_get_acl_accept_list(void *pCtx, struct qdf_mac_addr *pAcceptList, + uint8_t *nAcceptList) +{ + ptSapContext pSapCtx = CDS_GET_SAP_CB(pCtx); + if (NULL == pSapCtx) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid SAP pointer from p_cds_gctx", __func__); + return QDF_STATUS_E_FAULT; + } + + memcpy((void *)pAcceptList, (void *)pSapCtx->acceptMacList, + (pSapCtx->nAcceptMac * QDF_MAC_ADDR_SIZE)); + *nAcceptList = pSapCtx->nAcceptMac; + return QDF_STATUS_SUCCESS; +} + +/* API to get Deny List */ +QDF_STATUS +wlansap_get_acl_deny_list(void *pCtx, struct qdf_mac_addr *pDenyList, + uint8_t *nDenyList) +{ + ptSapContext pSapCtx = CDS_GET_SAP_CB(pCtx); + if (NULL == pSapCtx) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid SAP pointer from p_cds_gctx", __func__); + return QDF_STATUS_E_FAULT; + } + + memcpy((void *)pDenyList, (void *)pSapCtx->denyMacList, + (pSapCtx->nDenyMac * QDF_MAC_ADDR_SIZE)); + *nDenyList = pSapCtx->nDenyMac; + return QDF_STATUS_SUCCESS; +} + +/* This routine will clear all the entries in accept list as well as deny list */ + +QDF_STATUS wlansap_clear_acl(void *pCtx) +{ + ptSapContext pSapCtx = CDS_GET_SAP_CB(pCtx); + uint8_t i; + + if (NULL == pSapCtx) { + return QDF_STATUS_E_RESOURCES; + } + + for (i = 0; i < (pSapCtx->nDenyMac - 1); i++) { + qdf_mem_zero((pSapCtx->denyMacList + i)->bytes, + QDF_MAC_ADDR_SIZE); + } + + sap_print_acl(pSapCtx->denyMacList, pSapCtx->nDenyMac); + pSapCtx->nDenyMac = 0; + + for (i = 0; i < (pSapCtx->nAcceptMac - 1); i++) { + qdf_mem_zero((pSapCtx->acceptMacList + i)->bytes, + QDF_MAC_ADDR_SIZE); + } + + sap_print_acl(pSapCtx->acceptMacList, pSapCtx->nAcceptMac); + pSapCtx->nAcceptMac = 0; + + return QDF_STATUS_SUCCESS; +} + +/* + * wlansap_modify_acl() -Update ACL entries + * + * @ctx: Global context + * @peer_sta_mac: peer sta mac to be updated. + * @list_type: white/Black list type. + * @cmd: command to be executed on ACL. + * + * This function is called when a peer needs to be added or deleted from the + * white/black ACL + * + * Return: Status + */ + +QDF_STATUS +wlansap_modify_acl + (void *ctx, + uint8_t *peer_sta_mac, eSapACLType list_type, eSapACLCmdType cmd) { + eSapBool sta_white_list = eSAP_FALSE, sta_black_list = eSAP_FALSE; + uint8_t staWLIndex, staBLIndex; + ptSapContext sap_ctx = CDS_GET_SAP_CB(ctx); + + if (NULL == sap_ctx) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid SAP Context", __func__); + return QDF_STATUS_E_FAULT; + } + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_LOW, + "Modify ACL entered\n" "Before modification of ACL\n" + "size of accept and deny lists %d %d", sap_ctx->nAcceptMac, + sap_ctx->nDenyMac); + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + "*** WHITE LIST ***"); + sap_print_acl(sap_ctx->acceptMacList, sap_ctx->nAcceptMac); + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + "*** BLACK LIST ***"); + sap_print_acl(sap_ctx->denyMacList, sap_ctx->nDenyMac); + + /* the expectation is a mac addr will not be in both the lists at the same time. + It is the responsiblity of userspace to ensure this */ + sta_white_list = + sap_search_mac_list(sap_ctx->acceptMacList, sap_ctx->nAcceptMac, + peer_sta_mac, &staWLIndex); + sta_black_list = + sap_search_mac_list(sap_ctx->denyMacList, sap_ctx->nDenyMac, + peer_sta_mac, &staBLIndex); + + if (sta_white_list && sta_black_list) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "Peer mac " MAC_ADDRESS_STR + " found in white and black lists." + "Initial lists passed incorrect. Cannot execute this command.", + MAC_ADDR_ARRAY(peer_sta_mac)); + return QDF_STATUS_E_FAILURE; + + } + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_LOW, + "cmd %d", cmd); + + switch (list_type) { + case eSAP_WHITE_LIST: + if (cmd == ADD_STA_TO_ACL) { + /* error check */ + /* if list is already at max, return failure */ + if (sap_ctx->nAcceptMac == MAX_ACL_MAC_ADDRESS) { + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_ERROR, + "White list is already maxed out. Cannot accept " + MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(peer_sta_mac)); + return QDF_STATUS_E_FAILURE; + } + if (sta_white_list) { + /* Do nothing if already present in white list. Just print a warning */ + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_WARN, + "MAC address already present in white list " + MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(peer_sta_mac)); + return QDF_STATUS_SUCCESS; + } + if (sta_black_list) { + /* remove it from black list before adding to the white list */ + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_WARN, + "STA present in black list so first remove from it"); + sap_remove_mac_from_acl(sap_ctx-> + denyMacList, + &sap_ctx->nDenyMac, + staBLIndex); + } + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_INFO, + "... Now add to the white list"); + sap_add_mac_to_acl(sap_ctx->acceptMacList, + &sap_ctx->nAcceptMac, + peer_sta_mac); + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_INFO_LOW, + "size of accept and deny lists %d %d", + sap_ctx->nAcceptMac, + sap_ctx->nDenyMac); + } else if (cmd == DELETE_STA_FROM_ACL) { + if (sta_white_list) { + + struct tagCsrDelStaParams delStaParams; + + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_INFO, + "Delete from white list"); + sap_remove_mac_from_acl(sap_ctx->acceptMacList, + &sap_ctx->nAcceptMac, + staWLIndex); + /* If a client is deleted from white list and it is connected, send deauth */ + wlansap_populate_del_sta_params(peer_sta_mac, + eCsrForcedDeauthSta, + (SIR_MAC_MGMT_DEAUTH >> 4), + &delStaParams); + wlansap_deauth_sta(ctx, &delStaParams); + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_INFO_LOW, + "size of accept and deny lists %d %d", + sap_ctx->nAcceptMac, + sap_ctx->nDenyMac); + } else { + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_WARN, + "MAC address to be deleted is not present in the white list " + MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(peer_sta_mac)); + return QDF_STATUS_E_FAILURE; + } + } else { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "Invalid cmd type passed"); + return QDF_STATUS_E_FAILURE; + } + break; + + case eSAP_BLACK_LIST: + + if (cmd == ADD_STA_TO_ACL) { + struct tagCsrDelStaParams delStaParams; + /* error check */ + /* if list is already at max, return failure */ + if (sap_ctx->nDenyMac == MAX_ACL_MAC_ADDRESS) { + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_ERROR, + "Black list is already maxed out. Cannot accept " + MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(peer_sta_mac)); + return QDF_STATUS_E_FAILURE; + } + if (sta_black_list) { + /* Do nothing if already present in white list */ + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_WARN, + "MAC address already present in black list " + MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(peer_sta_mac)); + return QDF_STATUS_SUCCESS; + } + if (sta_white_list) { + /* remove it from white list before adding to the black list */ + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_WARN, + "Present in white list so first remove from it"); + sap_remove_mac_from_acl(sap_ctx-> + acceptMacList, + &sap_ctx-> + nAcceptMac, + staWLIndex); + } + /* If we are adding a client to the black list; if its connected, send deauth */ + wlansap_populate_del_sta_params(peer_sta_mac, + eCsrForcedDeauthSta, + (SIR_MAC_MGMT_DEAUTH >> 4), + &delStaParams); + wlansap_deauth_sta(ctx, &delStaParams); + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_INFO, + "... Now add to black list"); + sap_add_mac_to_acl(sap_ctx->denyMacList, + &sap_ctx->nDenyMac, peer_sta_mac); + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_INFO_LOW, + "size of accept and deny lists %d %d", + sap_ctx->nAcceptMac, + sap_ctx->nDenyMac); + } else if (cmd == DELETE_STA_FROM_ACL) { + if (sta_black_list) { + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_INFO, + "Delete from black list"); + sap_remove_mac_from_acl(sap_ctx->denyMacList, + &sap_ctx->nDenyMac, + staBLIndex); + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_INFO_LOW, + "no accept and deny mac %d %d", + sap_ctx->nAcceptMac, + sap_ctx->nDenyMac); + } else { + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_WARN, + "MAC address to be deleted is not present in the black list " + MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(peer_sta_mac)); + return QDF_STATUS_E_FAILURE; + } + } else { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "Invalid cmd type passed"); + return QDF_STATUS_E_FAILURE; + } + break; + + default: + { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "Invalid list type passed %d", list_type); + return QDF_STATUS_E_FAILURE; + } + } + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_LOW, + "After modification of ACL"); + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + "*** WHITE LIST ***"); + sap_print_acl(sap_ctx->acceptMacList, sap_ctx->nAcceptMac); + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + "*** BLACK LIST ***"); + sap_print_acl(sap_ctx->denyMacList, sap_ctx->nDenyMac); + return QDF_STATUS_SUCCESS; +} + +/** + * wlansap_disassoc_sta() - initiate disassociation of station. + * @pCtx: Pointer to the global cds context; a handle to SAP's control block + * can be extracted from its context. When MBSSID feature is enabled, + * SAP context is directly passed to SAP APIs. + * @p_del_sta_params: pointer to station deletion parameters + * + * This api function provides for Ap App/HDD initiated disassociation of station + * + * Return: The QDF_STATUS code associated with performing the operation + * QDF_STATUS_SUCCESS: Success + */ +QDF_STATUS wlansap_disassoc_sta(void *pCtx, + struct tagCsrDelStaParams *p_del_sta_params) +{ + ptSapContext pSapCtx = CDS_GET_SAP_CB(pCtx); + + /*------------------------------------------------------------------------ + Sanity check + Extract SAP control block + ------------------------------------------------------------------------*/ + if (NULL == pSapCtx) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid SAP pointer from pCtx", __func__); + return QDF_STATUS_E_FAULT; + } + + sme_roam_disconnect_sta(CDS_GET_HAL_CB(pSapCtx->p_cds_gctx), + pSapCtx->sessionId, p_del_sta_params); + + return QDF_STATUS_SUCCESS; +} + +/** + * wlansap_deauth_sta() - Ap App/HDD initiated deauthentication of station + * @pCtx : Pointer to the global cds context; a handle to SAP's + * control block can be extracted from its context + * When MBSSID feature is enabled, SAP context is directly + * passed to SAP APIs + * @pDelStaParams : Pointer to parameters of the station to deauthenticate + * + * This api function provides for Ap App/HDD initiated deauthentication of + * station + * + * Return: The QDF_STATUS code associated with performing the operation + */ +QDF_STATUS wlansap_deauth_sta(void *pCtx, + struct tagCsrDelStaParams *pDelStaParams) +{ + QDF_STATUS qdf_ret_status = QDF_STATUS_E_FAILURE; + QDF_STATUS qdf_status = QDF_STATUS_E_FAULT; + ptSapContext pSapCtx = CDS_GET_SAP_CB(pCtx); + + /*------------------------------------------------------------------------ + Sanity check + Extract SAP control block + ------------------------------------------------------------------------*/ + if (NULL == pSapCtx) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid SAP pointer from pCtx", __func__); + return qdf_status; + } + + qdf_ret_status = + sme_roam_deauth_sta(CDS_GET_HAL_CB(pSapCtx->p_cds_gctx), + pSapCtx->sessionId, pDelStaParams); + + if (qdf_ret_status == QDF_STATUS_SUCCESS) { + qdf_status = QDF_STATUS_SUCCESS; + } + return qdf_status; +} + +/** + * wlansap_update_bw80_cbmode() - fucntion to update channel bonding mode for + * VHT80 channel. + * @channel: target channel + * @sme_config: sme configuration context + * + * Return: none + */ +static inline void wlansap_update_bw80_cbmode(uint32_t channel, + tSmeConfigParams *sme_config) +{ + if (channel == 36 || channel == 52 || channel == 100 || + channel == 116 || channel == 149 || channel == 132) { + sme_config->csrConfig.channelBondingMode5GHz = + eCSR_INI_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_LOW; + } else if (channel == 40 || channel == 56 || channel == 104 || + channel == 120 || channel == 153 || channel == 136) { + sme_config->csrConfig.channelBondingMode5GHz = + eCSR_INI_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_LOW; + } else if (channel == 44 || channel == 60 || channel == 108 || + channel == 124 || channel == 157 || channel == 140) { + sme_config->csrConfig.channelBondingMode5GHz = + eCSR_INI_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_HIGH; + } else if (channel == 48 || channel == 64 || channel == 112 || + channel == 128 || channel == 144 || channel == 161) { + sme_config->csrConfig.channelBondingMode5GHz = + eCSR_INI_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_HIGH; + } +} + +/** + * wlansap_update_csa_channel_params() - fucntion to populate channel width and + * bonding modes. + * @sap_context: sap adapter context + * @channel: target channel + * + * Return: The QDF_STATUS code associated with performing the operation + */ +static QDF_STATUS wlansap_update_csa_channel_params(ptSapContext sap_context, + uint32_t channel) +{ + void *hal; + tpAniSirGlobal mac_ctx; + uint8_t bw; + + hal = CDS_GET_HAL_CB(sap_context->p_cds_gctx); + if (!hal) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid hal pointer from p_cds_gctx", __func__); + return QDF_STATUS_E_FAULT; + } + + mac_ctx = PMAC_STRUCT(hal); + + if (channel <= CHAN_ENUM_14) { + /* + * currently OBSS scan is done in hostapd, so to avoid + * SAP coming up in HT40 on channel switch we are + * disabling channel bonding in 2.4Ghz. + */ + mac_ctx->sap.SapDfsInfo.new_chanWidth = 0; + + } else { + + if (sap_context->ch_width_orig >= CH_WIDTH_80MHZ) + bw = BW80; + else if (sap_context->ch_width_orig == CH_WIDTH_40MHZ) + bw = BW40_HIGH_PRIMARY; + else + bw = BW20; + + for (; bw >= BW20; bw--) { + uint16_t op_class; + + op_class = cds_reg_dmn_get_opclass_from_channel( + mac_ctx->scan.countryCodeCurrent, + channel, bw); + if (!op_class) + continue; + + if (bw == BW80) { + mac_ctx->sap.SapDfsInfo.new_chanWidth = + CH_WIDTH_80MHZ; + } else if (bw == BW40_HIGH_PRIMARY) { + mac_ctx->sap.SapDfsInfo.new_chanWidth = + CH_WIDTH_40MHZ; + } else if (bw == BW40_LOW_PRIMARY) { + mac_ctx->sap.SapDfsInfo.new_chanWidth = + CH_WIDTH_40MHZ; + } else { + mac_ctx->sap.SapDfsInfo.new_chanWidth = + CH_WIDTH_20MHZ; + } + break; + } + + } + + return QDF_STATUS_SUCCESS; +} + +/** + * wlansap_set_channel_change_with_csa() - Set channel change with CSA + * @p_cds_gctx: Pointer to cds global context structure + * @targetChannel: Target channel + * @target_bw: Target bandwidth + * + * This api function does a channel change to the target channel specified. + * CSA IE is included in the beacons before doing a channel change. + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlansap_set_channel_change_with_csa(void *p_cds_gctx, uint32_t targetChannel, + enum phy_ch_width target_bw) +{ + + ptSapContext sapContext = NULL; + tWLAN_SAPEvent sapEvent; + tpAniSirGlobal pMac = NULL; + void *hHal = NULL; + bool valid; + QDF_STATUS status; + + sapContext = CDS_GET_SAP_CB(p_cds_gctx); + if (NULL == sapContext) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid SAP pointer from p_cds_gctx", __func__); + + return QDF_STATUS_E_FAULT; + } + + hHal = CDS_GET_HAL_CB(sapContext->p_cds_gctx); + if (NULL == hHal) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid HAL pointer from p_cds_gctx", __func__); + return QDF_STATUS_E_FAULT; + } + pMac = PMAC_STRUCT(hHal); + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO, + "%s: sap chan:%d target:%d conn on 5GHz:%d", + __func__, sapContext->channel, targetChannel, + cds_is_any_mode_active_on_band_along_with_session( + sapContext->sessionId, CDS_BAND_5)); + + /* + * Now, validate if the passed channel is valid in the + * current regulatory domain. + */ + if (sapContext->channel != targetChannel && + ((cds_get_channel_state(targetChannel) == + CHANNEL_STATE_ENABLE) || + (cds_get_channel_state(targetChannel) == + CHANNEL_STATE_DFS && + !cds_is_any_mode_active_on_band_along_with_session( + sapContext->sessionId, CDS_BAND_5)))) { + /* + * validate target channel switch w.r.t various concurrency + * rules set. + */ + valid = wlan_sap_validate_channel_switch(hHal, targetChannel, + sapContext); + if (!valid) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("Channel switch to %u is not allowed due to concurrent channel interference"), + targetChannel); + return QDF_STATUS_E_FAULT; + } + /* + * Post a CSA IE request to SAP state machine with + * target channel information and also CSA IE required + * flag set in sapContext only, if SAP is in eSAP_STARTED + * state. + */ + if (eSAP_STARTED == sapContext->sapsMachine) { + status = wlansap_update_csa_channel_params(sapContext, + targetChannel); + if (status != QDF_STATUS_SUCCESS) + return status; + + /* + * Copy the requested target channel + * to sap context. + */ + pMac->sap.SapDfsInfo.target_channel = targetChannel; + pMac->sap.SapDfsInfo.new_ch_params.ch_width = + pMac->sap.SapDfsInfo.new_chanWidth; + + /* By this time, the best bandwidth is calculated for + * the given target channel. Now, if there was a + * request from user to move to a selected bandwidth, + * we can see if it can be honored. + * + * Ex1: BW80 was selected for the target channel and + * user wants BW40, it can be allowed + * Ex2: BW40 was selected for the target channel and + * user wants BW80, it cannot be allowed for the given + * target channel. + * + * So, the MIN of the selected channel bandwidth and + * user input is used for the bandwidth + */ + if (target_bw != CH_WIDTH_MAX) { + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_INFO, + "%s: target bw:%d new width:%d", + __func__, target_bw, + pMac->sap.SapDfsInfo. + new_ch_params.ch_width); + pMac->sap.SapDfsInfo.new_ch_params.ch_width = + pMac->sap.SapDfsInfo.new_chanWidth = + QDF_MIN(pMac->sap.SapDfsInfo. + new_ch_params.ch_width, + target_bw); + } + cds_set_channel_params(targetChannel, + 0, &pMac->sap.SapDfsInfo.new_ch_params); + /* + * Set the CSA IE required flag. + */ + pMac->sap.SapDfsInfo.csaIERequired = true; + + /* + * Set the radar found status to allow the channel + * change to happen same as in the case of a radar + * detection. Since, this will allow SAP to be in + * correct state and also resume the netif queues + * that were suspended in HDD before the channel + * request was issued. + */ + pMac->sap.SapDfsInfo.sap_radar_found_status = true; + pMac->sap.SapDfsInfo.cac_state = + eSAP_DFS_DO_NOT_SKIP_CAC; + sap_cac_reset_notify(hHal); + + /* + * Post the eSAP_CHANNEL_SWITCH_ANNOUNCEMENT_START + * to SAP state machine to process the channel + * request with CSA IE set in the beacons. + */ + sapEvent.event = + eSAP_CHANNEL_SWITCH_ANNOUNCEMENT_START; + sapEvent.params = 0; + sapEvent.u1 = 0; + sapEvent.u2 = 0; + + sap_fsm(sapContext, &sapEvent); + + } else { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Failed to request Channel Change, since" + "SAP is not in eSAP_STARTED state", __func__); + return QDF_STATUS_E_FAULT; + } + + } else { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Channel = %d is not valid in the current" + "regulatory domain", __func__, targetChannel); + + return QDF_STATUS_E_FAULT; + } + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: Posted eSAP_CHANNEL_SWITCH_ANNOUNCEMENT_START successfully to sap_fsm for Channel = %d", + __func__, targetChannel); + + return QDF_STATUS_SUCCESS; +} + +/** + * wlansap_set_counter_measure() - set counter measure. + * @pCtx: Pointer to the global cds context; a handle to SAP's control block + * can be extracted from its context. When MBSSID feature is enabled, + * SAP context is directly passed to SAP APIs. + * @bEnable: If true than all stations will be disassociated and no more + * will be allowed to associate. If false than CORE will come out + * of this state. + * + * This api function is used to disassociate all the stations and prevent + * association for any other station.Whenever Authenticator receives 2 mic + * failures within 60 seconds, Authenticator will enable counter measure at + * SAP Layer. Authenticator will start the 60 seconds timer. Core stack will + * not allow any STA to associate till HDD disables counter meassure. Core + * stack shall kick out all the STA which are currently associated and DIASSOC + * Event will be propogated to HDD for each STA to clean up the HDD STA table. + * Once the 60 seconds timer expires, Authenticator will disable the counter + * meassure at core stack. Now core stack can allow STAs to associate. + * + * Return: The QDF_STATUS code associated with performing the operation + * QDF_STATUS_SUCCESS: Success + */ +QDF_STATUS wlansap_set_counter_measure(void *pCtx, bool bEnable) +{ + ptSapContext pSapCtx = CDS_GET_SAP_CB(pCtx); + + /*------------------------------------------------------------------------ + Sanity check + Extract SAP control block + ------------------------------------------------------------------------*/ + if (NULL == pSapCtx) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid SAP pointer from pCtx", __func__); + return QDF_STATUS_E_FAULT; + } + + sme_roam_tkip_counter_measures(CDS_GET_HAL_CB(pSapCtx->p_cds_gctx), + pSapCtx->sessionId, bEnable); + + return QDF_STATUS_SUCCESS; +} + +/** + * wlansap_set_key_sta() - set keys for a stations. + * @pCtx: Pointer to the global cds context; a handle to SAP's control block + * can be extracted from its context. When MBSSID feature is enabled, + * SAP context is directly passed to SAP APIs. + * @pSetKeyInfo : tCsrRoamSetKey structure for the station + * + * This api function provides for Ap App/HDD to set key for a station. + * + * Return: The QDF_STATUS code associated with performing the operation + * QDF_STATUS_SUCCESS: Success + */ +QDF_STATUS wlansap_set_key_sta(void *pCtx, tCsrRoamSetKey *pSetKeyInfo) +{ + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + ptSapContext pSapCtx = NULL; + void *hHal = NULL; + QDF_STATUS qdf_ret_status = QDF_STATUS_E_FAILURE; + uint32_t roamId = 0xFF; + + pSapCtx = CDS_GET_SAP_CB(pCtx); + if (NULL == pSapCtx) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid SAP pointer from pCtx", + __func__); + return QDF_STATUS_E_FAULT; + } + hHal = CDS_GET_HAL_CB(pSapCtx->p_cds_gctx); + if (NULL == hHal) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid HAL pointer from p_cds_gctx", + __func__); + return QDF_STATUS_E_FAULT; + } + qdf_ret_status = + sme_roam_set_key(hHal, pSapCtx->sessionId, pSetKeyInfo, + &roamId); + + if (qdf_ret_status == QDF_STATUS_SUCCESS) + qdf_status = QDF_STATUS_SUCCESS; + else + qdf_status = QDF_STATUS_E_FAULT; + + return qdf_status; +} + +/** + * wlan_sap_getstation_ie_information() - RSNIE Population + * + * @ctx: Global context + * @len: Length of @buf + * @buf: RSNIE IE data + * + * Populate RSN IE from CSR to HDD context + * + * Return: QDF_STATUS enumeration + */ + +QDF_STATUS +wlan_sap_getstation_ie_information + (void *ctx, uint32_t *len, uint8_t *buf) { + QDF_STATUS qdf_status = QDF_STATUS_E_FAILURE; + ptSapContext sap_ctx = NULL; + uint32_t ie_len = 0; + + sap_ctx = CDS_GET_SAP_CB(ctx); + if (NULL == sap_ctx) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("Invalid SAP pointer from pCtx")); + return QDF_STATUS_E_FAULT; + } + + if (len) { + ie_len = *len; + *len = sap_ctx->nStaWPARSnReqIeLength; + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO, + FL("WPAIE len : %x"), *len); + if ((buf) && (ie_len >= sap_ctx->nStaWPARSnReqIeLength)) { + qdf_mem_copy(buf, + sap_ctx->pStaWpaRsnReqIE, + sap_ctx->nStaWPARSnReqIeLength); + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO, + FL("WPAIE: %02x:%02x:%02x:%02x:%02x:%02x"), + buf[0], buf[1], buf[2], buf[3], buf[4], + buf[5]); + qdf_status = QDF_STATUS_SUCCESS; + } + } + return qdf_status; +} + +/** + * wlansap_set_wps_ie() - set WPI IE + * @pCtx: Pointer to the global cds context; a handle to SAP's control block + * can be extracted from its context. When MBSSID feature is enabled, + * SAP context is directly passed to SAP APIs. + * @pWPSIE: tSap_WPSIE structure that include WPS IEs + * + * This api function provides API for App/HDD to set WPS IE. + * + * Return: The QDF_STATUS code associated with performing the operation + * QDF_STATUS_SUCCESS: Success and error code otherwise. + */ +QDF_STATUS wlansap_set_wps_ie(void *pCtx, tSap_WPSIE *pSap_WPSIe) +{ + ptSapContext pSapCtx = NULL; + void *hHal = NULL; + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO, + "%s, %d", __func__, __LINE__); + + pSapCtx = CDS_GET_SAP_CB(pCtx); + if (NULL == pSapCtx) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid SAP pointer from pCtx", + __func__); + return QDF_STATUS_E_FAULT; + } + + hHal = CDS_GET_HAL_CB(pSapCtx->p_cds_gctx); + if (NULL == hHal) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid HAL pointer from p_cds_gctx", + __func__); + return QDF_STATUS_E_FAULT; + } + + if (sap_acquire_global_lock(pSapCtx) == QDF_STATUS_SUCCESS) { + if (pSap_WPSIe->sapWPSIECode == eSAP_WPS_BEACON_IE) { + qdf_mem_copy(&pSapCtx->APWPSIEs.SirWPSBeaconIE, + &pSap_WPSIe->sapwpsie. + sapWPSBeaconIE, + sizeof(tSap_WPSBeaconIE)); + } else if (pSap_WPSIe->sapWPSIECode == + eSAP_WPS_PROBE_RSP_IE) { + qdf_mem_copy(&pSapCtx->APWPSIEs. + SirWPSProbeRspIE, + &pSap_WPSIe->sapwpsie. + sapWPSProbeRspIE, + sizeof(tSap_WPSProbeRspIE)); + } else { + sap_release_global_lock(pSapCtx); + return QDF_STATUS_E_FAULT; + } + sap_release_global_lock(pSapCtx); + return QDF_STATUS_SUCCESS; + } else + return QDF_STATUS_E_FAULT; +} + +/** + * wlansap_update_wps_ie() - update WPI IE + * @pCtx: Pointer to the global cds context; a handle to SAP's control block + * can be extracted from its context. When MBSSID feature is enabled, + * SAP context is directly passed to SAP APIs. + * + * This api function provides API for App/HDD to update WPS IE. + * + * Return: The QDF_STATUS code associated with performing the operation + * QDF_STATUS_SUCCESS: Success and error code otherwise. + */ +QDF_STATUS wlansap_update_wps_ie(void *pCtx) +{ + QDF_STATUS qdf_status = QDF_STATUS_E_FAULT; + ptSapContext pSapCtx = NULL; + QDF_STATUS qdf_ret_status = QDF_STATUS_E_FAILURE; + void *hHal = NULL; + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s, %d", __func__, __LINE__); + + pSapCtx = CDS_GET_SAP_CB(pCtx); + if (NULL == pSapCtx) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid SAP pointer from pCtx", + __func__); + return QDF_STATUS_E_FAULT; + } + + hHal = CDS_GET_HAL_CB(pSapCtx->p_cds_gctx); + if (NULL == hHal) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid HAL pointer from p_cds_gctx", + __func__); + return QDF_STATUS_E_FAULT; + } + + qdf_ret_status = + sme_roam_update_apwpsie(hHal, pSapCtx->sessionId, + &pSapCtx->APWPSIEs); + + if (qdf_ret_status == QDF_STATUS_SUCCESS) + qdf_status = QDF_STATUS_SUCCESS; + else + qdf_status = QDF_STATUS_E_FAULT; + + return qdf_status; +} + +/** + * wlansap_get_wps_state() - get WPS session state + * @pCtx: Pointer to the global cds context; a handle to SAP's control block + * can be extracted from its context. When MBSSID feature is enabled, + * SAP context is directly passed to SAP APIs. + * @pbWPSState: Pointer to variable to indicate if device is in + * WPS Registration state + * + * This api function provides for Ap App/HDD to check if WPS session in process. + * + * Return: The QDF_STATUS code associated with performing the operation + * QDF_STATUS_SUCCESS: Success + */ +QDF_STATUS wlansap_get_wps_state(void *pCtx, bool *bWPSState) +{ + ptSapContext pSapCtx = NULL; + void *hHal = NULL; + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO, + "%s, %d", __func__, __LINE__); + + pSapCtx = CDS_GET_SAP_CB(pCtx); + if (NULL == pSapCtx) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid SAP pointer from pCtx", + __func__); + return QDF_STATUS_E_FAULT; + } + + hHal = CDS_GET_HAL_CB(pSapCtx->p_cds_gctx); + if (NULL == hHal) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid HAL pointer from p_cds_gctx", + __func__); + return QDF_STATUS_E_FAULT; + } + + if (sap_acquire_global_lock(pSapCtx) == QDF_STATUS_SUCCESS) { + if (pSapCtx->APWPSIEs.SirWPSProbeRspIE. + FieldPresent & + SIR_WPS_PROBRSP_SELECTEDREGISTRA_PRESENT) + *bWPSState = true; + else + *bWPSState = false; + + sap_release_global_lock(pSapCtx); + + return QDF_STATUS_SUCCESS; + } else + return QDF_STATUS_E_FAULT; + +} + +QDF_STATUS sap_acquire_global_lock(ptSapContext pSapCtx) +{ + QDF_STATUS qdf_status = QDF_STATUS_E_FAULT; + + if (QDF_IS_STATUS_SUCCESS(qdf_mutex_acquire(&pSapCtx->SapGlobalLock))) { + qdf_status = QDF_STATUS_SUCCESS; + } + + return qdf_status; +} + +QDF_STATUS sap_release_global_lock(ptSapContext pSapCtx) +{ + QDF_STATUS qdf_status = QDF_STATUS_E_FAULT; + + if (QDF_IS_STATUS_SUCCESS(qdf_mutex_release(&pSapCtx->SapGlobalLock))) { + qdf_status = QDF_STATUS_SUCCESS; + } + + return qdf_status; +} + +/** + * wlansap_set_wparsn_ies() - set WPA RSN IEs + * @pCtx: Pointer to the global cds context; a handle to SAP's control block + * can be extracted from its context. When MBSSID feature is enabled, + * SAP context is directly passed to SAP APIs. + * @pWPARSNIEs : buffer to the WPA/RSN IEs + * @WPARSNIEsLen: length of WPA/RSN IEs + * + * This api function provides for Ap App/HDD to set AP WPA and RSN IE in its + * beacon and probe response. + * + * Return: The QDF_STATUS code associated with performing the operation + * QDF_STATUS_SUCCESS: Success and error code otherwise + */ +QDF_STATUS wlansap_set_wparsn_ies + (void *pCtx, uint8_t *pWPARSNIEs, uint32_t WPARSNIEsLen) { + ptSapContext pSapCtx = NULL; + QDF_STATUS qdf_ret_status = QDF_STATUS_E_FAILURE; + void *hHal = NULL; + + pSapCtx = CDS_GET_SAP_CB(pCtx); + if (NULL == pSapCtx) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid SAP pointer from pCtx", + __func__); + return QDF_STATUS_E_FAULT; + } + + hHal = CDS_GET_HAL_CB(pSapCtx->p_cds_gctx); + if (NULL == hHal) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid HAL pointer from p_cds_gctx", + __func__); + return QDF_STATUS_E_FAULT; + } + + pSapCtx->APWPARSNIEs.length = (uint16_t) WPARSNIEsLen; + qdf_mem_copy(pSapCtx->APWPARSNIEs.rsnIEdata, pWPARSNIEs, + WPARSNIEsLen); + + qdf_ret_status = + sme_roam_update_apwparsni_es(hHal, pSapCtx->sessionId, + &pSapCtx->APWPARSNIEs); + + if (qdf_ret_status == QDF_STATUS_SUCCESS) + return QDF_STATUS_SUCCESS; + else + return QDF_STATUS_E_FAULT; + + return QDF_STATUS_E_FAULT; +} + +/** + * wlansap_send_action() - send action frame + * @pCtx: Pointer to the global cds context; a handle to SAP's control block + * can be extracted from its context. When MBSSID feature is enabled, + * SAP context is directly passed to SAP APIs. + * @pBuf: Pointer of the action frame to be transmitted + * @len: Length of the action frame + * + * This api function provides to send action frame sent by upper layer. + * + * Return: The QDF_STATUS code associated with performing the operation +* QDF_STATUS_SUCCESS: Success and error code otherwise + */ +QDF_STATUS wlansap_send_action(void *pCtx, const uint8_t *pBuf, + uint32_t len, uint16_t wait, uint16_t channel_freq) +{ + ptSapContext pSapCtx = NULL; + void *hHal = NULL; + QDF_STATUS qdf_ret_status = QDF_STATUS_E_FAILURE; + + pSapCtx = CDS_GET_SAP_CB(pCtx); + if (NULL == pSapCtx) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid SAP pointer from pCtx", + __func__); + return QDF_STATUS_E_FAULT; + } + hHal = CDS_GET_HAL_CB(pSapCtx->p_cds_gctx); + if ((NULL == hHal) || (eSAP_TRUE != pSapCtx->isSapSessionOpen)) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: HAL pointer (%p) NULL OR SME session is not open (%d)", + __func__, hHal, pSapCtx->isSapSessionOpen); + return QDF_STATUS_E_FAULT; + } + + qdf_ret_status = + sme_send_action(hHal, pSapCtx->sessionId, pBuf, len, 0, + 0, channel_freq); + + if (QDF_STATUS_SUCCESS == qdf_ret_status) { + return QDF_STATUS_SUCCESS; + } + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "Failed to Send Action Frame"); + + return QDF_STATUS_E_FAULT; +} + +/** + * wlansap_remain_on_channel() - set remain on channel + * @pCtx: Pointer to the global cds context; a handle to SAP's control block + * can be extracted from its context. When MBSSID feature is enabled, + * SAP context is directly passed to SAP APIs. + * @channel: Channel on which driver has to listen + * @duration: Duration for which driver has to listen on specified channel + * @callback: Callback function to be called once Listen is done. + * @pContext: Context needs to be called in callback function. + * @scan_id: scan identifier + * + * This api function provides to set Remain On channel on specified channel + * for specified duration. + * + * Return: The QDF_STATUS code associated with performing the operation + * QDF_STATUS_SUCCESS: Success and error code otherwise + */ +QDF_STATUS wlansap_remain_on_channel(void *pCtx, + uint8_t channel, uint32_t duration, remainOnChanCallback callback, + void *pContext, uint32_t *scan_id) +{ + ptSapContext pSapCtx = NULL; + void *hHal = NULL; + QDF_STATUS qdf_ret_status = QDF_STATUS_E_FAILURE; + + pSapCtx = CDS_GET_SAP_CB(pCtx); + if (NULL == pSapCtx) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid SAP pointer from pCtx", + __func__); + return QDF_STATUS_E_FAULT; + } + hHal = CDS_GET_HAL_CB(pSapCtx->p_cds_gctx); + if ((NULL == hHal) || (eSAP_TRUE != pSapCtx->isSapSessionOpen)) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: HAL pointer (%p) NULL OR SME session is not open (%d)", + __func__, hHal, pSapCtx->isSapSessionOpen); + return QDF_STATUS_E_FAULT; + } + + qdf_ret_status = sme_remain_on_channel(hHal, pSapCtx->sessionId, + channel, duration, callback, pContext, + true, scan_id); + + if (QDF_STATUS_SUCCESS == qdf_ret_status) { + return QDF_STATUS_SUCCESS; + } + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "Failed to Set Remain on Channel"); + + return QDF_STATUS_E_FAULT; +} + +/** + * wlansap_cancel_remain_on_channel() - cancel remain on channel + * @pCtx: Pointer to the global cds context; a handle to SAP's control block + * can be extracted from its context. When MBSSID feature is enabled, + * SAP context is directly passed to SAP APIs. + * + * This api cancel previous remain on channel request. + * + * Return: The QDF_STATUS code associated with performing the operation + * QDF_STATUS_SUCCESS: Success and error code otherwie + */ +QDF_STATUS wlansap_cancel_remain_on_channel(void *pCtx, + uint32_t scan_id) +{ + ptSapContext pSapCtx = NULL; + void *hHal = NULL; + QDF_STATUS qdf_ret_status = QDF_STATUS_E_FAILURE; + + pSapCtx = CDS_GET_SAP_CB(pCtx); + if (NULL == pSapCtx) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid SAP pointer from pCtx", + __func__); + return QDF_STATUS_E_FAULT; + } + hHal = CDS_GET_HAL_CB(pSapCtx->p_cds_gctx); + if ((NULL == hHal) || + (eSAP_TRUE != pSapCtx->isSapSessionOpen)) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: HAL pointer (%p) NULL OR SME session is not open (%d)", + __func__, hHal, pSapCtx->isSapSessionOpen); + return QDF_STATUS_E_FAULT; + } + + qdf_ret_status = + sme_cancel_remain_on_channel(hHal, pSapCtx->sessionId, + scan_id); + + if (QDF_STATUS_SUCCESS == qdf_ret_status) { + return QDF_STATUS_SUCCESS; + } + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "Failed to Cancel Remain on Channel"); + + return QDF_STATUS_E_FAULT; +} + +/** + * wlan_sap_set_pre_cac_status() - Set the pre cac status + * @ctx: SAP context + * @status: Status of pre cac + * @handle: Global MAC handle + * + * Sets the pre cac status in the MAC context and updates the state + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_sap_set_pre_cac_status(void *ctx, bool status, + tHalHandle handle) +{ + ptSapContext sap_ctx = CDS_GET_SAP_CB(ctx); + tpAniSirGlobal mac_ctx = PMAC_STRUCT(handle); + + if (!mac_ctx) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid mac pointer", __func__); + return QDF_STATUS_E_FAULT; + } + + if (!sap_ctx) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid SAP pointer", __func__); + return QDF_STATUS_E_FAULT; + } + + sap_ctx->is_pre_cac_on = status; + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_DEBUG, + "%s: is_pre_cac_on:%d", __func__, sap_ctx->is_pre_cac_on); + + return QDF_STATUS_SUCCESS; +} + +/** + * wlan_sap_set_chan_before_pre_cac() - Save the channel before pre cac + * @ctx: SAP context + * @chan_before_pre_cac: Channel before pre cac + * + * Saves the channel that was in use before pre cac operation + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_sap_set_chan_before_pre_cac(void *ctx, + uint8_t chan_before_pre_cac) +{ + ptSapContext sap_ctx = CDS_GET_SAP_CB(ctx); + + if (!sap_ctx) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid SAP pointer", __func__); + return QDF_STATUS_E_FAULT; + } + + sap_ctx->chan_before_pre_cac = chan_before_pre_cac; + return QDF_STATUS_SUCCESS; +} + +/** + * wlan_sap_set_pre_cac_complete_status() - Sets pre cac complete status + * @ctx: SAP context + * @status: Status of pre cac complete + * + * Sets the status of pre cac i.e., whether pre cac is complete or not + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_sap_set_pre_cac_complete_status(void *ctx, bool status) +{ + ptSapContext sap_ctx = CDS_GET_SAP_CB(ctx); + + if (!sap_ctx) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid SAP pointer", __func__); + return QDF_STATUS_E_FAULT; + } + + sap_ctx->pre_cac_complete = status; + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_DEBUG, + "%s: pre cac complete status:%d session:%d", + __func__, status, sap_ctx->sessionId); + + return QDF_STATUS_SUCCESS; +} + +/** + * wlan_sap_is_pre_cac_active() - Checks if pre cac in in progress + * @handle: Global MAC handle + * + * Checks if pre cac is in progress in any of the SAP contexts + * + * Return: True is pre cac is active, false otherwise + */ +bool wlan_sap_is_pre_cac_active(tHalHandle handle) +{ + tpAniSirGlobal mac = NULL; + int i; + + mac = PMAC_STRUCT(handle); + if (!mac) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: Invalid mac context", __func__); + return false; + } + + for (i = 0; i < SAP_MAX_NUM_SESSION; i++) { + ptSapContext context = + (ptSapContext) mac->sap.sapCtxList[i].pSapContext; + if (context && context->is_pre_cac_on) + return true; + } + return false; +} + +/** + * wlan_sap_get_pre_cac_vdev_id() - Get vdev id of the pre cac interface + * @handle: Global handle + * @vdev_id: vdev id + * + * Fetches the vdev id of the pre cac interface + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_sap_get_pre_cac_vdev_id(tHalHandle handle, uint8_t *vdev_id) +{ + tpAniSirGlobal mac = NULL; + uint8_t i; + + mac = PMAC_STRUCT(handle); + if (!mac) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: Invalid mac context", __func__); + return QDF_STATUS_E_FAULT; + } + + for (i = 0; i < SAP_MAX_NUM_SESSION; i++) { + ptSapContext context = + (ptSapContext) mac->sap.sapCtxList[i].pSapContext; + if (context && context->is_pre_cac_on) { + *vdev_id = i; + return QDF_STATUS_SUCCESS; + } + } + return QDF_STATUS_E_FAILURE; +} + +/** + * wlansap_register_mgmt_frame() - register management frame + * @pCtx: Pointer to the global cds context; a handle to SAP's control block + * can be extracted from its context. When MBSSID feature is enabled, + * SAP context is directly passed to SAP APIs. + * @frameType: frameType that needs to be registered with PE. + * @matchData: Data pointer which should be matched after frame type is matched. + * @matchLen: Length of the matchData + * + * HDD use this API to register specified type of frame with CORE stack. + * On receiving such kind of frame CORE stack should pass this frame to HDD + * + * Return: The QDF_STATUS code associated with performing the operation + * QDF_STATUS_SUCCESS: Success and error code otherwise + */ +QDF_STATUS wlansap_register_mgmt_frame + (void *pCtx, + uint16_t frameType, uint8_t *matchData, uint16_t matchLen) { + ptSapContext pSapCtx = NULL; + void *hHal = NULL; + QDF_STATUS qdf_ret_status = QDF_STATUS_E_FAILURE; + + pSapCtx = CDS_GET_SAP_CB(pCtx); + if (NULL == pSapCtx) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid SAP pointer from pCtx", + __func__); + return QDF_STATUS_E_FAULT; + } + hHal = CDS_GET_HAL_CB(pSapCtx->p_cds_gctx); + if ((NULL == hHal) || (eSAP_TRUE != pSapCtx->isSapSessionOpen)) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: HAL pointer (%p) NULL OR SME session is not open (%d)", + __func__, hHal, pSapCtx->isSapSessionOpen); + return QDF_STATUS_E_FAULT; + } + + qdf_ret_status = sme_register_mgmt_frame(hHal, pSapCtx->sessionId, + frameType, matchData, + matchLen); + + if (QDF_STATUS_SUCCESS == qdf_ret_status) { + return QDF_STATUS_SUCCESS; + } + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "Failed to Register MGMT frame"); + + return QDF_STATUS_E_FAULT; +} + +/** + * wlansap_de_register_mgmt_frame() - de register management frame + * @pCtx: Pointer to the global cds context; a handle to SAP's control block + * can be extracted from its context. When MBSSID feature is enabled, + * SAP context is directly passed to SAP APIs. + * @frameType: frameType that needs to be De-registered with PE. + * @matchData: Data pointer which should be matched after frame type is matched. + * @matchLen: Length of the matchData + * + * This API is used to deregister previously registered frame. + * + * Return: The QDF_STATUS code associated with performing the operation + * QDF_STATUS_SUCCESS: Success and error code otherwise + */ +QDF_STATUS wlansap_de_register_mgmt_frame + (void *pCtx, + uint16_t frameType, uint8_t *matchData, uint16_t matchLen) { + ptSapContext pSapCtx = NULL; + void *hHal = NULL; + QDF_STATUS qdf_ret_status = QDF_STATUS_E_FAILURE; + + pSapCtx = CDS_GET_SAP_CB(pCtx); + if (NULL == pSapCtx) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid SAP pointer from pCtx", + __func__); + return QDF_STATUS_E_FAULT; + } + hHal = CDS_GET_HAL_CB(pSapCtx->p_cds_gctx); + if ((NULL == hHal) || (eSAP_TRUE != pSapCtx->isSapSessionOpen)) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: HAL pointer (%p) NULL OR SME session is not open (%d)", + __func__, hHal, pSapCtx->isSapSessionOpen); + return QDF_STATUS_E_FAULT; + } + + qdf_ret_status = + sme_deregister_mgmt_frame(hHal, pSapCtx->sessionId, frameType, + matchData, matchLen); + + if (QDF_STATUS_SUCCESS == qdf_ret_status) { + return QDF_STATUS_SUCCESS; + } + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "Failed to Deregister MGMT frame"); + + return QDF_STATUS_E_FAULT; +} + +/*========================================================================== + FUNCTION wlansap_channel_change_request + + DESCRIPTION + This API is used to send an Indication to SME/PE to change the + current operating channel to a different target channel. + + The Channel change will be issued by SAP under the following + scenarios. + 1. A radar indication is received during SAP CAC WAIT STATE and + channel change is required. + 2. A radar indication is received during SAP STARTED STATE and + channel change is required. + DEPENDENCIES + NA. + + PARAMETERS + IN + pSapCtx: Pointer to cds global context structure + + RETURN VALUE + The QDF_STATUS code associated with performing the operation + + QDF_STATUS_SUCCESS: Success + + SIDE EFFECTS + ============================================================================*/ +QDF_STATUS +wlansap_channel_change_request(void *pSapCtx, uint8_t target_channel) +{ + ptSapContext sapContext = NULL; + QDF_STATUS qdf_ret_status = QDF_STATUS_E_FAILURE; + void *hHal = NULL; + tpAniSirGlobal mac_ctx = NULL; + eCsrPhyMode phy_mode; + struct ch_params_s *ch_params; + sapContext = (ptSapContext) pSapCtx; + + if (NULL == sapContext) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid SAP pointer", __func__); + return QDF_STATUS_E_FAULT; + } + + hHal = CDS_GET_HAL_CB(sapContext->p_cds_gctx); + if (NULL == hHal) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid HAL pointer from p_cds_gctx", __func__); + return QDF_STATUS_E_FAULT; + } + mac_ctx = PMAC_STRUCT(hHal); + phy_mode = sapContext->csr_roamProfile.phyMode; + + if (sapContext->csr_roamProfile.ChannelInfo.numOfChannels == 0 || + sapContext->csr_roamProfile.ChannelInfo.ChannelList == NULL) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("Invalid channel list")); + return QDF_STATUS_E_FAULT; + } + sapContext->csr_roamProfile.ChannelInfo.ChannelList[0] = target_channel; + /* + * We are getting channel bonding mode from sapDfsInfor structure + * because we've implemented channel width fallback mechanism for DFS + * which will result in channel width changing dynamically. + */ + ch_params = &mac_ctx->sap.SapDfsInfo.new_ch_params; + cds_set_channel_params(target_channel, 0, ch_params); + sapContext->ch_params.ch_width = ch_params->ch_width; + /* Update the channel as this will be used to + * send event to supplicant + */ + sapContext->channel = target_channel; + sapContext->csr_roamProfile.ch_params.ch_width = ch_params->ch_width; + sapContext->csr_roamProfile.ch_params.sec_ch_offset = + ch_params->sec_ch_offset; + sapContext->csr_roamProfile.ch_params.center_freq_seg0 = + ch_params->center_freq_seg0; + sapContext->csr_roamProfile.ch_params.center_freq_seg1 = + ch_params->center_freq_seg1; + sapContext->csr_roamProfile.supported_rates.numRates = 0; + sapContext->csr_roamProfile.extended_rates.numRates = 0; + + qdf_ret_status = sme_roam_channel_change_req(hHal, sapContext->bssid, + ch_params, &sapContext->csr_roamProfile); + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO, + "%s: chan:%d width:%d offset:%d seg0:%d seg1:%d", + __func__, sapContext->channel, ch_params->ch_width, + ch_params->sec_ch_offset, ch_params->center_freq_seg0, + ch_params->center_freq_seg1); + + if (qdf_ret_status == QDF_STATUS_SUCCESS) { + sap_signal_hdd_event(sapContext, NULL, + eSAP_CHANNEL_CHANGE_EVENT, + (void *) eSAP_STATUS_SUCCESS); + + return QDF_STATUS_SUCCESS; + } + return QDF_STATUS_E_FAULT; +} + +/*========================================================================== + + FUNCTION wlansap_start_beacon_req + DESCRIPTION + This API is used to send an Indication to SME/PE to start + beaconing on the current operating channel. + + Brief:When SAP is started on DFS channel and when ADD BSS RESP is received + LIM temporarily holds off Beaconing for SAP to do CAC WAIT. When + CAC WAIT is done SAP resumes the Beacon Tx by sending a start beacon + request to LIM. + + DEPENDENCIES + NA. + + PARAMETERS + + IN + pSapCtx: Pointer to cds global context structure + + RETURN VALUE + The QDF_STATUS code associated with performing the operation + + QDF_STATUS_SUCCESS: Success + + SIDE EFFECTS + ============================================================================*/ +QDF_STATUS wlansap_start_beacon_req(void *pSapCtx) +{ + ptSapContext sapContext = NULL; + QDF_STATUS qdf_ret_status = QDF_STATUS_E_FAILURE; + void *hHal = NULL; + uint8_t dfsCacWaitStatus = 0; + tpAniSirGlobal pMac = NULL; + sapContext = (ptSapContext) pSapCtx; + + if (NULL == sapContext) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid SAP pointer", __func__); + return QDF_STATUS_E_FAULT; + } + + hHal = CDS_GET_HAL_CB(sapContext->p_cds_gctx); + if (NULL == hHal) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid HAL pointer from p_cds_gctx", __func__); + return QDF_STATUS_E_FAULT; + } + pMac = PMAC_STRUCT(hHal); + + /* No Radar was found during CAC WAIT, So start Beaconing */ + if (pMac->sap.SapDfsInfo.sap_radar_found_status == false) { + /* CAC Wait done without any Radar Detection */ + dfsCacWaitStatus = true; + sapContext->pre_cac_complete = false; + qdf_ret_status = sme_roam_start_beacon_req(hHal, + sapContext->bssid, + dfsCacWaitStatus); + if (qdf_ret_status == QDF_STATUS_SUCCESS) { + return QDF_STATUS_SUCCESS; + } + return QDF_STATUS_E_FAULT; + } + + return QDF_STATUS_E_FAULT; +} + +/*========================================================================== + FUNCTION wlansap_dfs_send_csa_ie_request + + DESCRIPTION + This API is used to send channel switch announcement request to PE + DEPENDENCIES + NA. + + PARAMETERS + IN + pSapCtx: Pointer to cds global context structure + + RETURN VALUE + The QDF_STATUS code associated with performing the operation + + QDF_STATUS_SUCCESS: Success + + SIDE EFFECTS + ============================================================================*/ +QDF_STATUS wlansap_dfs_send_csa_ie_request(void *pSapCtx) +{ + ptSapContext sapContext = NULL; + QDF_STATUS qdf_ret_status = QDF_STATUS_E_FAILURE; + void *hHal = NULL; + tpAniSirGlobal pMac = NULL; + sapContext = (ptSapContext) pSapCtx; + + if (NULL == sapContext) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid SAP pointer", __func__); + return QDF_STATUS_E_FAULT; + } + + hHal = CDS_GET_HAL_CB(sapContext->p_cds_gctx); + if (NULL == hHal) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid HAL pointer from p_cds_gctx", __func__); + return QDF_STATUS_E_FAULT; + } + pMac = PMAC_STRUCT(hHal); + + pMac->sap.SapDfsInfo.new_ch_params.ch_width = + pMac->sap.SapDfsInfo.new_chanWidth; + cds_set_channel_params(pMac->sap.SapDfsInfo.target_channel, + 0, &pMac->sap.SapDfsInfo.new_ch_params); + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO, + "%s: chan:%d req:%d width:%d off:%d", + __func__, pMac->sap.SapDfsInfo.target_channel, + pMac->sap.SapDfsInfo.csaIERequired, + pMac->sap.SapDfsInfo.new_ch_params.ch_width, + pMac->sap.SapDfsInfo.new_ch_params.sec_ch_offset); + + qdf_ret_status = sme_roam_csa_ie_request(hHal, + sapContext->bssid, + pMac->sap.SapDfsInfo.target_channel, + pMac->sap.SapDfsInfo.csaIERequired, + &pMac->sap.SapDfsInfo.new_ch_params); + + if (qdf_ret_status == QDF_STATUS_SUCCESS) { + return QDF_STATUS_SUCCESS; + } + + return QDF_STATUS_E_FAULT; +} + +/*========================================================================== + FUNCTION wlansap_get_dfs_ignore_cac + + DESCRIPTION + This API is used to get the value of ignore_cac value + + DEPENDENCIES + NA. + + PARAMETERS + IN + hHal : HAL pointer + pIgnore_cac : pointer to ignore_cac variable + + RETURN VALUE + The QDF_STATUS code associated with performing the operation + + QDF_STATUS_SUCCESS: Success + + SIDE EFFECTS + ============================================================================*/ +QDF_STATUS wlansap_get_dfs_ignore_cac(tHalHandle hHal, uint8_t *pIgnore_cac) +{ + tpAniSirGlobal pMac = NULL; + + if (NULL != hHal) { + pMac = PMAC_STRUCT(hHal); + } else { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid hHal pointer", __func__); + return QDF_STATUS_E_FAULT; + } + + *pIgnore_cac = pMac->sap.SapDfsInfo.ignore_cac; + return QDF_STATUS_SUCCESS; +} + +/*========================================================================== + FUNCTION wlansap_set_dfs_ignore_cac + + DESCRIPTION + This API is used to Set the value of ignore_cac value + + DEPENDENCIES + NA. + + PARAMETERS + IN + hHal : HAL pointer + ignore_cac : value to set for ignore_cac variable in DFS global structure. + + RETURN VALUE + The QDF_STATUS code associated with performing the operation + + QDF_STATUS_SUCCESS: Success + + SIDE EFFECTS + ============================================================================*/ +QDF_STATUS wlansap_set_dfs_ignore_cac(tHalHandle hHal, uint8_t ignore_cac) +{ + tpAniSirGlobal pMac = NULL; + + if (NULL != hHal) { + pMac = PMAC_STRUCT(hHal); + } else { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid hHal pointer", __func__); + return QDF_STATUS_E_FAULT; + } + + pMac->sap.SapDfsInfo.ignore_cac = (ignore_cac >= true) ? + true : false; + return QDF_STATUS_SUCCESS; +} + +/** + * wlansap_set_dfs_restrict_japan_w53() - enable/disable dfS for japan + * @hHal : HAL pointer + * @disable_Dfs_JapanW3 :Indicates if Japan W53 is disabled when set to 1 + * Indicates if Japan W53 is enabled when set to 0 + * + * This API is used to enable or disable Japan W53 Band + * Return: The QDF_STATUS code associated with performing the operation + * QDF_STATUS_SUCCESS: Success + */ +QDF_STATUS +wlansap_set_dfs_restrict_japan_w53(tHalHandle hHal, uint8_t disable_Dfs_W53) +{ + tpAniSirGlobal pMac = NULL; + QDF_STATUS status; + enum dfs_region dfs_region; + + if (NULL != hHal) { + pMac = PMAC_STRUCT(hHal); + } else { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid hHal pointer", __func__); + return QDF_STATUS_E_FAULT; + } + + cds_get_dfs_region(&dfs_region); + + /* + * Set the JAPAN W53 restriction only if the current + * regulatory domain is JAPAN. + */ + if (DFS_MKK_REGION == dfs_region) { + pMac->sap.SapDfsInfo.is_dfs_w53_disabled = disable_Dfs_W53; + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_INFO_LOW, + FL("sapdfs: SET DFS JAPAN W53 DISABLED = %d"), + pMac->sap.SapDfsInfo.is_dfs_w53_disabled); + + status = QDF_STATUS_SUCCESS; + } else { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL + ("Regdomain not japan, set disable JP W53 not valid")); + + status = QDF_STATUS_E_FAULT; + } + + return status; +} + +bool sap_is_auto_channel_select(void *pvos_gctx) +{ + ptSapContext sapcontext = CDS_GET_SAP_CB(pvos_gctx); + + if (NULL == sapcontext) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid SAP pointer", __func__); + return 0; + } + return sapcontext->channel == AUTO_CHANNEL_SELECT; +} + +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE +/** + * wlan_sap_set_channel_avoidance() - sets sap mcc channel avoidance ini param + * @hal: hal handle + * @sap_channel_avoidance: ini parameter value + * + * sets sap mcc channel avoidance ini param, to be called in sap_start + * + * Return: success of failure of operation + */ +QDF_STATUS +wlan_sap_set_channel_avoidance(tHalHandle hal, bool sap_channel_avoidance) +{ + tpAniSirGlobal mac_ctx = NULL; + if (NULL != hal) + mac_ctx = PMAC_STRUCT(hal); + if (mac_ctx == NULL || hal == NULL) { + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_ERROR, + FL("hal or mac_ctx pointer NULL")); + return QDF_STATUS_E_FAULT; + } + mac_ctx->sap.sap_channel_avoidance = sap_channel_avoidance; + return QDF_STATUS_SUCCESS; +} +#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ + +/** + * wlansap_set_dfs_preferred_channel_location() - set dfs preferred channel + * @hHal : HAL pointer + * @dfs_Preferred_Channels_location : + * 0 - Indicates No preferred channel location restrictions + * 1 - Indicates SAP Indoor Channels operation only. + * 2 - Indicates SAP Outdoor Channels operation only. + * + * This API is used to set sap preferred channels location + * to resetrict the DFS random channel selection algorithm + * either Indoor/Outdoor channels only. + * + * Return: The QDF_STATUS code associated with performing the operation + * QDF_STATUS_SUCCESS: Success and error code otherwise. + */ +QDF_STATUS +wlansap_set_dfs_preferred_channel_location(tHalHandle hHal, + uint8_t + dfs_Preferred_Channels_location) +{ + tpAniSirGlobal pMac = NULL; + QDF_STATUS status; + enum dfs_region dfs_region; + + if (NULL != hHal) { + pMac = PMAC_STRUCT(hHal); + } else { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid hHal pointer", __func__); + return QDF_STATUS_E_FAULT; + } + + cds_get_dfs_region(&dfs_region); + + /* + * The Indoor/Outdoor only random channel selection + * restriction is currently enforeced only for + * JAPAN regulatory domain. + */ + if (DFS_MKK_REGION == dfs_region) { + pMac->sap.SapDfsInfo.sap_operating_chan_preferred_location = + dfs_Preferred_Channels_location; + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_INFO_LOW, + FL + ("sapdfs:Set Preferred Operating Channel location=%d"), + pMac->sap.SapDfsInfo. + sap_operating_chan_preferred_location); + + status = QDF_STATUS_SUCCESS; + } else { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL + ("sapdfs:NOT JAPAN REG, Invalid Set preferred chans location")); + + status = QDF_STATUS_E_FAULT; + } + + return status; +} + +/*========================================================================== + FUNCTION wlansap_set_dfs_target_chnl + + DESCRIPTION + This API is used to set next target chnl as provided channel. + you can provide any valid channel to this API. + + DEPENDENCIES + NA. + + PARAMETERS + IN + hHal : HAL pointer + target_channel : target channel to be set + + RETURN VALUE + The QDF_STATUS code associated with performing the operation + + QDF_STATUS_SUCCESS: Success + + SIDE EFFECTS + ============================================================================*/ +QDF_STATUS wlansap_set_dfs_target_chnl(tHalHandle hHal, uint8_t target_channel) +{ + tpAniSirGlobal pMac = NULL; + + if (NULL != hHal) { + pMac = PMAC_STRUCT(hHal); + } else { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid hHal pointer", __func__); + return QDF_STATUS_E_FAULT; + } + if (target_channel > 0) { + pMac->sap.SapDfsInfo.user_provided_target_channel = + target_channel; + } else { + pMac->sap.SapDfsInfo.user_provided_target_channel = 0; + } + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlansap_update_sap_config_add_ie(tsap_Config_t *pConfig, + const uint8_t *pAdditionIEBuffer, + uint16_t additionIELength, + eUpdateIEsType updateType) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + uint8_t bufferValid = false; + uint16_t bufferLength = 0; + uint8_t *pBuffer = NULL; + + if (NULL == pConfig) { + return QDF_STATUS_E_FAULT; + } + + if ((pAdditionIEBuffer != NULL) && (additionIELength != 0)) { + /* initialize the buffer pointer so that pe can copy */ + if (additionIELength > 0) { + bufferLength = additionIELength; + pBuffer = qdf_mem_malloc(bufferLength); + if (NULL == pBuffer) { + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_ERROR, + FL("Could not allocate the buffer ")); + return QDF_STATUS_E_NOMEM; + } + qdf_mem_copy(pBuffer, pAdditionIEBuffer, bufferLength); + bufferValid = true; + } + } + + switch (updateType) { + case eUPDATE_IE_PROBE_BCN: + if (bufferValid) { + pConfig->probeRespBcnIEsLen = bufferLength; + pConfig->pProbeRespBcnIEsBuffer = pBuffer; + } else { + qdf_mem_free(pConfig->pProbeRespBcnIEsBuffer); + pConfig->probeRespBcnIEsLen = 0; + pConfig->pProbeRespBcnIEsBuffer = NULL; + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO, + FL + ("No Probe Resp beacone IE received in set beacon")); + } + break; + case eUPDATE_IE_PROBE_RESP: + if (bufferValid) { + pConfig->probeRespIEsBufferLen = bufferLength; + pConfig->pProbeRespIEsBuffer = pBuffer; + } else { + qdf_mem_free(pConfig->pProbeRespIEsBuffer); + pConfig->probeRespIEsBufferLen = 0; + pConfig->pProbeRespIEsBuffer = NULL; + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO, + FL + ("No Probe Response IE received in set beacon")); + } + break; + case eUPDATE_IE_ASSOC_RESP: + if (bufferValid) { + pConfig->assocRespIEsLen = bufferLength; + pConfig->pAssocRespIEsBuffer = pBuffer; + } else { + qdf_mem_free(pConfig->pAssocRespIEsBuffer); + pConfig->assocRespIEsLen = 0; + pConfig->pAssocRespIEsBuffer = NULL; + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO, + FL + ("No Assoc Response IE received in set beacon")); + } + break; + default: + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO, + FL("No matching buffer type %d"), updateType); + if (pBuffer != NULL) + qdf_mem_free(pBuffer); + break; + } + + return status; +} + +QDF_STATUS +wlansap_reset_sap_config_add_ie(tsap_Config_t *pConfig, eUpdateIEsType updateType) +{ + if (NULL == pConfig) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid Config pointer", __func__); + return QDF_STATUS_E_FAULT; + } + + switch (updateType) { + case eUPDATE_IE_ALL: /*only used to reset */ + case eUPDATE_IE_PROBE_RESP: + qdf_mem_free(pConfig->pProbeRespIEsBuffer); + pConfig->probeRespIEsBufferLen = 0; + pConfig->pProbeRespIEsBuffer = NULL; + if (eUPDATE_IE_ALL != updateType) + break; + + case eUPDATE_IE_ASSOC_RESP: + qdf_mem_free(pConfig->pAssocRespIEsBuffer); + pConfig->assocRespIEsLen = 0; + pConfig->pAssocRespIEsBuffer = NULL; + if (eUPDATE_IE_ALL != updateType) + break; + + case eUPDATE_IE_PROBE_BCN: + qdf_mem_free(pConfig->pProbeRespBcnIEsBuffer); + pConfig->probeRespBcnIEsLen = 0; + pConfig->pProbeRespBcnIEsBuffer = NULL; + if (eUPDATE_IE_ALL != updateType) + break; + + default: + if (eUPDATE_IE_ALL != updateType) + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("Invalid buffer type %d"), updateType); + break; + } + return QDF_STATUS_SUCCESS; +} + +/*========================================================================== + FUNCTION wlansap_extend_to_acs_range + + DESCRIPTION Function extends give channel range to consider ACS chan bonding + + DEPENDENCIES PARAMETERS + + IN /OUT + *startChannelNum : ACS extend start ch + *endChannelNum : ACS extended End ch + *bandStartChannel: Band start ch + *bandEndChannel : Band end ch + + RETURN VALUE NONE + + SIDE EFFECTS + ============================================================================*/ +void wlansap_extend_to_acs_range(uint8_t *startChannelNum, + uint8_t *endChannelNum, + uint8_t *bandStartChannel, + uint8_t *bandEndChannel) +{ +#define ACS_WLAN_20M_CH_INC 4 +#define ACS_2G_EXTEND ACS_WLAN_20M_CH_INC +#define ACS_5G_EXTEND (ACS_WLAN_20M_CH_INC * 3) + + uint8_t tmp_startChannelNum = 0, tmp_endChannelNum = 0; + + if (*startChannelNum <= 14 && *endChannelNum <= 14) { + *bandStartChannel = CHAN_ENUM_1; + *bandEndChannel = CHAN_ENUM_14; + tmp_startChannelNum = *startChannelNum > 5 ? + (*startChannelNum - ACS_2G_EXTEND) : 1; + tmp_endChannelNum = (*endChannelNum + ACS_2G_EXTEND) <= 14 ? + (*endChannelNum + ACS_2G_EXTEND) : 14; + } else if (*startChannelNum >= 36 && *endChannelNum >= 36) { + *bandStartChannel = CHAN_ENUM_36; + *bandEndChannel = CHAN_ENUM_165; + tmp_startChannelNum = (*startChannelNum - ACS_5G_EXTEND) > 36 ? + (*startChannelNum - ACS_5G_EXTEND) : 36; + tmp_endChannelNum = (*endChannelNum + ACS_5G_EXTEND) <= 165 ? + (*endChannelNum + ACS_5G_EXTEND) : 165; + } else { + *bandStartChannel = CHAN_ENUM_1; + *bandEndChannel = CHAN_ENUM_165; + tmp_startChannelNum = *startChannelNum > 5 ? + (*startChannelNum - ACS_2G_EXTEND) : 1; + tmp_endChannelNum = (*endChannelNum + ACS_5G_EXTEND) <= 165 ? + (*endChannelNum + ACS_5G_EXTEND) : 165; + } + + /* Note if the ACS range include only DFS channels, do not cross range + * Active scanning in adjacent non DFS channels results in transmission + * spikes in DFS specturm channels which is due to emission spill. + * Remove the active channels from extend ACS range for DFS only range + */ + if (CDS_IS_DFS_CH(*startChannelNum)) { + while (!CDS_IS_DFS_CH(tmp_startChannelNum) && + tmp_startChannelNum < *startChannelNum) + tmp_startChannelNum += ACS_WLAN_20M_CH_INC; + + *startChannelNum = tmp_startChannelNum; + } + if (CDS_IS_DFS_CH(*endChannelNum)) { + while (!CDS_IS_DFS_CH(tmp_endChannelNum) && + tmp_endChannelNum > *endChannelNum) + tmp_endChannelNum -= ACS_WLAN_20M_CH_INC; + + *endChannelNum = tmp_endChannelNum; + } +} + +/** + * wlansap_get_dfs_nol() - Get the DFS NOL + * @pSapCtx: SAP context + * @nol: Pointer to the NOL + * @nol_len: Length of the NOL + * + * Provides the DFS NOL + * + * Return: QDF_STATUS + */ +QDF_STATUS wlansap_get_dfs_nol(void *pSapCtx, uint8_t *nol, uint32_t *nol_len) +{ + int i = 0, j = 0; + ptSapContext sapContext = (ptSapContext) pSapCtx; + void *hHal = NULL; + tpAniSirGlobal pMac = NULL; + uint64_t current_time, found_time, elapsed_time; + unsigned long left_time; + tSapDfsNolInfo *dfs_nol = NULL; + bool bAvailable = false; + *nol_len = 0; + + if (NULL == sapContext) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid SAP pointer from p_cds_gctx", __func__); + return QDF_STATUS_E_FAULT; + } + hHal = CDS_GET_HAL_CB(sapContext->p_cds_gctx); + if (NULL == hHal) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid HAL pointer from p_cds_gctx", __func__); + return QDF_STATUS_E_FAULT; + } + pMac = PMAC_STRUCT(hHal); + + if (!pMac->sap.SapDfsInfo.numCurrentRegDomainDfsChannels) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO, + "%s: DFS NOL is empty", __func__); + return QDF_STATUS_SUCCESS; + } + + dfs_nol = pMac->sap.SapDfsInfo.sapDfsChannelNolList; + + if (!dfs_nol) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO, + "%s: DFS NOL context is null", __func__); + return QDF_STATUS_E_FAULT; + } + + for (i = 0; i < pMac->sap.SapDfsInfo.numCurrentRegDomainDfsChannels; + i++) { + if (!dfs_nol[i].dfs_channel_number) + continue; + + current_time = cds_get_monotonic_boottime(); + found_time = dfs_nol[i].radar_found_timestamp; + + elapsed_time = current_time - found_time; + + /* check if channel is available + * if either channel is usable or available, or timer expired 30mins + */ + bAvailable = + ((dfs_nol[i].radar_status_flag == + eSAP_DFS_CHANNEL_AVAILABLE) + || (dfs_nol[i].radar_status_flag == + eSAP_DFS_CHANNEL_USABLE) + || (elapsed_time >= SAP_DFS_NON_OCCUPANCY_PERIOD)); + + if (bAvailable) { + dfs_nol[i].radar_status_flag = + eSAP_DFS_CHANNEL_AVAILABLE; + dfs_nol[i].radar_found_timestamp = 0; + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Channel[%d] is AVAILABLE", + __func__, dfs_nol[i].dfs_channel_number); + } else { + + /* the time left in min */ + left_time = SAP_DFS_NON_OCCUPANCY_PERIOD - elapsed_time; + left_time = left_time / (60 * 1000 * 1000); + + nol[j++] = dfs_nol[i].dfs_channel_number; + (*nol_len)++; + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Channel[%d] is UNAVAILABLE [%lu min left]", + __func__, + dfs_nol[i].dfs_channel_number, left_time); + } + } + + return QDF_STATUS_SUCCESS; +} + +/*========================================================================== + FUNCTION wlansap_set_dfs_nol + + DESCRIPTION + This API is used to set the dfs nol + DEPENDENCIES + NA. + + PARAMETERS + IN + sapContext: Pointer to cds global context structure + conf: set type + + RETURN VALUE + The QDF_STATUS code associated with performing the operation + + QDF_STATUS_SUCCESS: Success + + SIDE EFFECTS + ============================================================================*/ +QDF_STATUS wlansap_set_dfs_nol(void *pSapCtx, eSapDfsNolType conf) +{ + int i = 0; + ptSapContext sapContext = (ptSapContext) pSapCtx; + void *hHal = NULL; + tpAniSirGlobal pMac = NULL; + + if (NULL == sapContext) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid SAP pointer from p_cds_gctx", __func__); + return QDF_STATUS_E_FAULT; + } + hHal = CDS_GET_HAL_CB(sapContext->p_cds_gctx); + if (NULL == hHal) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid HAL pointer from p_cds_gctx", __func__); + return QDF_STATUS_E_FAULT; + } + pMac = PMAC_STRUCT(hHal); + + if (!pMac->sap.SapDfsInfo.numCurrentRegDomainDfsChannels) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO, + "%s: DFS NOL is empty", __func__); + return QDF_STATUS_SUCCESS; + } + + if (conf == eSAP_DFS_NOL_CLEAR) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: clear the DFS NOL", __func__); + + for (i = 0; + i < pMac->sap.SapDfsInfo.numCurrentRegDomainDfsChannels; + i++) { + if (!pMac->sap.SapDfsInfo. + sapDfsChannelNolList[i].dfs_channel_number) + continue; + + pMac->sap.SapDfsInfo. + sapDfsChannelNolList[i].radar_status_flag = + eSAP_DFS_CHANNEL_AVAILABLE; + pMac->sap.SapDfsInfo. + sapDfsChannelNolList[i].radar_found_timestamp = 0; + } + } else if (conf == eSAP_DFS_NOL_RANDOMIZE) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Randomize the DFS NOL", __func__); + + /* random 1/0 to decide to put the channel into NOL */ + for (i = 0; + i < pMac->sap.SapDfsInfo.numCurrentRegDomainDfsChannels; + i++) { + uint32_t random_bytes = 0; + get_random_bytes(&random_bytes, 1); + + if (!pMac->sap.SapDfsInfo. + sapDfsChannelNolList[i].dfs_channel_number) + continue; + + if ((random_bytes + jiffies) % 2) { + /* mark the channel unavailable */ + pMac->sap.SapDfsInfo.sapDfsChannelNolList[i] + .radar_status_flag = + eSAP_DFS_CHANNEL_UNAVAILABLE; + + /* mark the timestamp */ + pMac->sap.SapDfsInfo.sapDfsChannelNolList[i] + .radar_found_timestamp = + cds_get_monotonic_boottime(); + } else { + /* mark the channel available */ + pMac->sap.SapDfsInfo. + sapDfsChannelNolList[i].radar_status_flag = + eSAP_DFS_CHANNEL_AVAILABLE; + + /* clear the timestamp */ + pMac->sap.SapDfsInfo. + sapDfsChannelNolList + [i].radar_found_timestamp = 0; + } + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Set channel[%d] %s", + __func__, + pMac->sap.SapDfsInfo.sapDfsChannelNolList[i] + .dfs_channel_number, + (pMac->sap.SapDfsInfo. + sapDfsChannelNolList[i].radar_status_flag > + eSAP_DFS_CHANNEL_AVAILABLE) ? "UNAVAILABLE" : + "AVAILABLE"); + } + } else { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: unsupport type %d", __func__, conf); + } + + /* set DFS-NOL back to keep it update-to-date in CNSS */ + sap_signal_hdd_event(sapContext, NULL, eSAP_DFS_NOL_SET, + (void *) eSAP_STATUS_SUCCESS); + + return QDF_STATUS_SUCCESS; +} + +/** + * wlansap_populate_del_sta_params() - populate delete station parameter + * @mac: Pointer to peer mac address. + * @reason_code: Reason code for the disassoc/deauth. + * @subtype: Subtype points to either disassoc/deauth frame. + * @pDelStaParams: Address where parameters to be populated. + * + * This API is used to populate delete station parameter structure + * + * Return: none + */ + +void wlansap_populate_del_sta_params(const uint8_t *mac, + uint16_t reason_code, + uint8_t subtype, + struct tagCsrDelStaParams *pDelStaParams) +{ + if (NULL == mac) + qdf_set_macaddr_broadcast(&pDelStaParams->peerMacAddr); + else + qdf_mem_copy(pDelStaParams->peerMacAddr.bytes, mac, + QDF_MAC_ADDR_SIZE); + + if (reason_code == 0) + pDelStaParams->reason_code = eSIR_MAC_DEAUTH_LEAVING_BSS_REASON; + else + pDelStaParams->reason_code = reason_code; + + if (subtype == (SIR_MAC_MGMT_DEAUTH >> 4) || + subtype == (SIR_MAC_MGMT_DISASSOC >> 4)) + pDelStaParams->subtype = subtype; + else + pDelStaParams->subtype = (SIR_MAC_MGMT_DEAUTH >> 4); + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO, + FL( + "Delete STA with RC:%hu subtype:%hhu MAC::" + MAC_ADDRESS_STR), + pDelStaParams->reason_code, pDelStaParams->subtype, + MAC_ADDR_ARRAY(pDelStaParams->peerMacAddr.bytes)); +} + +/** + * wlansap_acs_chselect() - Initiates acs channel selection + * @pvos_gctx: Pointer to vos global context structure + * @pacs_event_callback: Callback function in hdd called by sap + * to inform hdd about channel section result + * @pconfig: Pointer to configuration structure + * passed down from hdd + * @pusr_context: Parameter that will be passed back in all + * the sap callback events. + * + * This function serves as an api for hdd to initiate acs scan pre + * start bss. + * + * Return: The QDF_STATUS code associated with performing the operation. + */ +QDF_STATUS +wlansap_acs_chselect(void *pvos_gctx, + tpWLAN_SAPEventCB pacs_event_callback, + tsap_Config_t *pconfig, + void *pusr_context) +{ + ptSapContext sap_context = NULL; + tHalHandle h_hal = NULL; + QDF_STATUS qdf_status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal pmac = NULL; + + sap_context = CDS_GET_SAP_CB(pvos_gctx); + if (NULL == sap_context) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid SAP pointer from pvos_gctx", __func__); + + return QDF_STATUS_E_FAULT; + } + + h_hal = (tHalHandle)CDS_GET_HAL_CB(sap_context->p_cds_gctx); + if (NULL == h_hal) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid MAC context from pvosGCtx", __func__); + return QDF_STATUS_E_FAULT; + } + + pmac = PMAC_STRUCT(h_hal); + sap_context->acs_cfg = &pconfig->acs_cfg; + sap_context->ch_width_orig = pconfig->acs_cfg.ch_width; + sap_context->csr_roamProfile.phyMode = pconfig->acs_cfg.hw_mode; + + /* + * Now, configure the scan and ACS channel params + * to issue a scan request. + */ + wlansap_set_scan_acs_channel_params(pconfig, sap_context, + pusr_context); + + /* + * Copy the HDD callback function to report the + * ACS result after scan in SAP context callback function. + */ + sap_context->pfnSapEventCallback = pacs_event_callback; + /* + * init dfs channel nol + */ + sap_init_dfs_channel_nol_list(sap_context); + + /* + * Issue the scan request. This scan request is + * issued before the start BSS is done so + * + * 1. No need to pass the second parameter + * as the SAP state machine is not started yet + * and there is no need for any event posting. + * + * 2. Set third parameter to TRUE to indicate the + * channel selection function to register a + * different scan callback fucntion to process + * the results pre start BSS. + */ + qdf_status = sap_goto_channel_sel(sap_context, NULL, true, false); + + if (QDF_STATUS_E_ABORTED == qdf_status) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "In %s,DFS not supported in the current operating mode", + __func__); + return QDF_STATUS_E_FAILURE; + } else if (QDF_STATUS_E_CANCELED == qdf_status) { + /* + * ERROR is returned when either the SME scan request + * failed or ACS is overridden due to other constrainst + * So send selected channel to HDD + */ + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("Scan Req Failed/ACS Overridden")); + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("Selected channel = %d"), + sap_context->channel); + + return sap_signal_hdd_event(sap_context, NULL, + eSAP_ACS_CHANNEL_SELECTED, + (void *) eSAP_STATUS_SUCCESS); + } else if (QDF_STATUS_SUCCESS == qdf_status) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + FL("Successfully Issued a Pre Start Bss Scan Request")); + } + return qdf_status; +} + +/** + * wlan_sap_enable_phy_error_logs() - Enable DFS phy error logs + * @hal: global hal handle + * @enable_log: value to set + * + * Since the frequency of DFS phy error is very high, enabling logs for them + * all the times can cause crash and will also create lot of useless logs + * causing difficulties in debugging other issue. This function will be called + * from iwpriv cmd to eanble such logs temporarily. + * + * Return: void + */ +void wlan_sap_enable_phy_error_logs(tHalHandle hal, bool enable_log) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + mac_ctx->sap.enable_dfs_phy_error_logs = enable_log; +} + +/** + * wlansap_get_chan_width() - get sap channel width. + * @cds_ctx: pointer of global cds context + * + * This function get channel width of sap. + * + * Return: sap channel width + */ +uint32_t wlansap_get_chan_width(void *cds_ctx) +{ + ptSapContext sapcontext; + + sapcontext = CDS_GET_SAP_CB(cds_ctx); + return wlan_sap_get_vht_ch_width(sapcontext); +} + +/** + * wlansap_set_tx_leakage_threshold() - set sap tx leakage threshold. + * @hal: HAL pointer + * @tx_leakage_threshold: sap tx leakage threshold + * + * This function set sap tx leakage threshold. + * + * Return: QDF_STATUS. + */ +QDF_STATUS wlansap_set_tx_leakage_threshold(tHalHandle hal, + uint16_t tx_leakage_threshold) +{ + tpAniSirGlobal mac; + + if (NULL == hal) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid hal pointer", __func__); + return QDF_STATUS_E_FAULT; + } + + mac = PMAC_STRUCT(hal); + mac->sap.SapDfsInfo.tx_leakage_threshold = tx_leakage_threshold; + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO, + "%s: leakage_threshold %d", __func__, + mac->sap.SapDfsInfo.tx_leakage_threshold); + return QDF_STATUS_SUCCESS; +} + +/* + * wlansap_set_invalid_session() - set session ID to invalid + * @cds_ctx: pointer of global context + * + * This function sets session ID to invalid + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlansap_set_invalid_session(void *cds_ctx) +{ + ptSapContext psapctx; + + psapctx = CDS_GET_SAP_CB(cds_ctx); + if (NULL == psapctx) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + FL("Invalid SAP pointer from pctx")); + return QDF_STATUS_E_FAILURE; + } + + psapctx->sessionId = CSR_SESSION_ID_INVALID; + psapctx->isSapSessionOpen = eSAP_FALSE; + + return QDF_STATUS_SUCCESS; +} diff --git a/drivers/staging/qcacld-3.0/core/sme/inc/csr_api.h b/drivers/staging/qcacld-3.0/core/sme/inc/csr_api.h new file mode 100644 index 0000000000000000000000000000000000000000..38439921be543d2bfd9bd3aee93156d37ceccedb --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/sme/inc/csr_api.h @@ -0,0 +1,1776 @@ +/* + * Copyright (c) 2011-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * \file csr_api.h + * + * Exports and types for the Common Scan and Roaming Module interfaces. + */ + +#ifndef CSRAPI_H__ +#define CSRAPI_H__ + +#include "sir_api.h" +#include "sir_mac_prot_def.h" +#include "csr_link_list.h" + +#define CSR_INVALID_SCANRESULT_HANDLE (NULL) + +typedef enum { + /* never used */ + eCSR_AUTH_TYPE_NONE, + /* MAC layer authentication types */ + eCSR_AUTH_TYPE_OPEN_SYSTEM, + eCSR_AUTH_TYPE_SHARED_KEY, + eCSR_AUTH_TYPE_AUTOSWITCH, + + /* Upper layer authentication types */ + eCSR_AUTH_TYPE_WPA, + eCSR_AUTH_TYPE_WPA_PSK, + eCSR_AUTH_TYPE_WPA_NONE, + + eCSR_AUTH_TYPE_RSN, + eCSR_AUTH_TYPE_RSN_PSK, + eCSR_AUTH_TYPE_FT_RSN, + eCSR_AUTH_TYPE_FT_RSN_PSK, +#ifdef FEATURE_WLAN_WAPI + eCSR_AUTH_TYPE_WAPI_WAI_CERTIFICATE, + eCSR_AUTH_TYPE_WAPI_WAI_PSK, +#endif /* FEATURE_WLAN_WAPI */ + eCSR_AUTH_TYPE_CCKM_WPA, + eCSR_AUTH_TYPE_CCKM_RSN, +#ifdef WLAN_FEATURE_11W + eCSR_AUTH_TYPE_RSN_PSK_SHA256, + eCSR_AUTH_TYPE_RSN_8021X_SHA256, +#endif + eCSR_NUM_OF_SUPPORT_AUTH_TYPE, + eCSR_AUTH_TYPE_FAILED = 0xff, + eCSR_AUTH_TYPE_UNKNOWN = eCSR_AUTH_TYPE_FAILED, + +} eCsrAuthType; + +typedef enum { + eCSR_ENCRYPT_TYPE_NONE, + eCSR_ENCRYPT_TYPE_WEP40_STATICKEY, + eCSR_ENCRYPT_TYPE_WEP104_STATICKEY, + eCSR_ENCRYPT_TYPE_WEP40, + eCSR_ENCRYPT_TYPE_WEP104, + eCSR_ENCRYPT_TYPE_TKIP, + eCSR_ENCRYPT_TYPE_AES, +#ifdef FEATURE_WLAN_WAPI + /* WAPI */ + eCSR_ENCRYPT_TYPE_WPI, +#endif /* FEATURE_WLAN_WAPI */ +#ifdef FEATURE_WLAN_ESE + eCSR_ENCRYPT_TYPE_KRK, +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + eCSR_ENCRYPT_TYPE_BTK, +#endif +#endif /* FEATURE_WLAN_ESE */ +#ifdef WLAN_FEATURE_11W + /* 11w BIP */ + eCSR_ENCRYPT_TYPE_AES_CMAC, +#endif + eCSR_ENCRYPT_TYPE_ANY, + eCSR_NUM_OF_ENCRYPT_TYPE = eCSR_ENCRYPT_TYPE_ANY, + + eCSR_ENCRYPT_TYPE_FAILED = 0xff, + eCSR_ENCRYPT_TYPE_UNKNOWN = eCSR_ENCRYPT_TYPE_FAILED, + +} eCsrEncryptionType; + +/*--------------------------------------------------------------------------- + Enumeration of the various Security types + ---------------------------------------------------------------------------*/ +typedef enum { + eCSR_SECURITY_TYPE_WPA, + eCSR_SECURITY_TYPE_RSN, +#ifdef FEATURE_WLAN_WAPI + eCSR_SECURITY_TYPE_WAPI, +#endif /* FEATURE_WLAN_WAPI */ + eCSR_SECURITY_TYPE_UNKNOWN, + +} eCsrSecurityType; + +typedef enum { + /* 11a/b/g only, no HT, no proprietary */ + eCSR_DOT11_MODE_abg = 0x0001, + eCSR_DOT11_MODE_11a = 0x0002, + eCSR_DOT11_MODE_11b = 0x0004, + eCSR_DOT11_MODE_11g = 0x0008, + eCSR_DOT11_MODE_11n = 0x0010, + eCSR_DOT11_MODE_11g_ONLY = 0x0020, + eCSR_DOT11_MODE_11n_ONLY = 0x0040, + eCSR_DOT11_MODE_11b_ONLY = 0x0080, + eCSR_DOT11_MODE_11ac = 0x0100, + eCSR_DOT11_MODE_11ac_ONLY = 0x0200, + /* + * This is for WIFI test. It is same as eWNIAPI_MAC_PROTOCOL_ALL + * except when it starts IBSS in 11B of 2.4GHz + * It is for CSR internal use + */ + eCSR_DOT11_MODE_AUTO = 0x0400, + + /* specify the number of maximum bits for phyMode */ + eCSR_NUM_PHY_MODE = 16, +} eCsrPhyMode; + +/** + * enum eCsrRoamBssType - BSS type in CSR operations + * @eCSR_BSS_TYPE_INFRASTRUCTURE: Infrastructure station + * @eCSR_BSS_TYPE_INFRA_AP: SoftAP + * @eCSR_BSS_TYPE_IBSS: IBSS network we'll not start + * @eCSR_BSS_TYPE_START_IBSS: IBSS network we'll start if no partners found + * @eCSR_BSS_TYPE_NDI: NAN datapath interface + * @eCSR_BSS_TYPE_ANY: any BSS type (IBSS or Infrastructure) + */ +typedef enum { + eCSR_BSS_TYPE_INFRASTRUCTURE, + eCSR_BSS_TYPE_INFRA_AP, + eCSR_BSS_TYPE_IBSS, + eCSR_BSS_TYPE_START_IBSS, + eCSR_BSS_TYPE_NDI, + eCSR_BSS_TYPE_ANY, +} eCsrRoamBssType; + +typedef enum { + eCSR_SCAN_REQUEST_11D_SCAN = 1, + eCSR_SCAN_REQUEST_FULL_SCAN, + eCSR_SCAN_IDLE_MODE_SCAN, + eCSR_SCAN_HO_PROBE_SCAN, /* direct probe on entry from candidate list */ + eCSR_SCAN_P2P_DISCOVERY, + + eCSR_SCAN_SOFTAP_CHANNEL_RANGE, + eCSR_SCAN_P2P_FIND_PEER, +} eCsrRequestType; + +typedef enum { + eCSR_SCAN_RESULT_GET = 0, + eCSR_SCAN_RESULT_FLUSH = 1, /* to delete all cached scan results */ +} eCsrScanResultCmd; + +typedef enum { + eCSR_SCAN_SUCCESS, + eCSR_SCAN_FAILURE, + eCSR_SCAN_ABORT, + eCSR_SCAN_FOUND_PEER, +} eCsrScanStatus; + +/* + * Reason to abort the scan + * The reason can used later to decide whether to update the scan results + * to upper layer or not + */ +typedef enum { + eCSR_SCAN_ABORT_DEFAULT = 1, + eCSR_SCAN_ABORT_DUE_TO_BAND_CHANGE, /* Scan abort due to band change */ + eCSR_SCAN_ABORT_SSID_ONLY +} eCsrAbortReason; + +typedef enum { + eCSR_BW_20MHz_VAL = 20, + eCSR_BW_40MHz_VAL = 40, + eCSR_BW_80MHz_VAL = 80, + eCSR_BW_160MHz_VAL = 160 +} eCSR_BW_Val; + +typedef enum { + eCSR_INI_SINGLE_CHANNEL_CENTERED = 0, + eCSR_INI_DOUBLE_CHANNEL_HIGH_PRIMARY, + eCSR_INI_DOUBLE_CHANNEL_LOW_PRIMARY, + eCSR_INI_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_CENTERED, + eCSR_INI_QUADRUPLE_CHANNEL_20MHZ_CENTERED_40MHZ_CENTERED, + eCSR_INI_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_CENTERED, + eCSR_INI_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_LOW, + eCSR_INI_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_LOW, + eCSR_INI_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_HIGH, + eCSR_INI_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_HIGH, + eCSR_INI_CHANNEL_BONDING_STATE_MAX +} eIniChanBondState; + +#define CSR_RSN_PMKID_SIZE 16 +#define CSR_MAX_PMKID_ALLOWED 32 +#define CSR_WEP40_KEY_LEN 5 +#define CSR_WEP104_KEY_LEN 13 +#define CSR_TKIP_KEY_LEN 32 +#define CSR_AES_KEY_LEN 16 +#define CSR_MAX_TX_POWER (WNI_CFG_CURRENT_TX_POWER_LEVEL_STAMAX) +#define CSR_MAX_RSC_LEN 16 +#ifdef FEATURE_WLAN_WAPI +#define CSR_WAPI_BKID_SIZE 16 +#define CSR_MAX_BKID_ALLOWED 16 +#define CSR_WAPI_KEY_LEN 32 +#define CSR_MAX_KEY_LEN (CSR_WAPI_KEY_LEN) /* longest one is for WAPI */ +#else +#define CSR_MAX_KEY_LEN (CSR_TKIP_KEY_LEN) /* longest one is for TKIP */ +#endif /* FEATURE_WLAN_WAPI */ +#ifdef FEATURE_WLAN_ESE +#define CSR_KRK_KEY_LEN 16 +#endif + +typedef struct tagCsrChannelInfo { + uint8_t numOfChannels; + uint8_t *ChannelList; /* it will be an array of channels */ +} tCsrChannelInfo, *tpCsrChannelInfo; + +typedef struct tagCsrSSIDInfo { + tSirMacSSid SSID; + bool handoffPermitted; + bool ssidHidden; +} tCsrSSIDInfo; + +typedef struct tagCsrSSIDs { + uint32_t numOfSSIDs; + tCsrSSIDInfo *SSIDList; /* To be allocated for array of SSIDs */ +} tCsrSSIDs; + +typedef struct tagCsrBSSIDs { + uint32_t numOfBSSIDs; + struct qdf_mac_addr *bssid; +} tCsrBSSIDs; + +typedef struct tagCsrStaParams { + uint16_t capability; + uint8_t extn_capability[SIR_MAC_MAX_EXTN_CAP]; + uint8_t supported_rates_len; + uint8_t supported_rates[SIR_MAC_MAX_SUPP_RATES]; + uint8_t htcap_present; + tSirHTCap HTCap; + uint8_t vhtcap_present; + tSirVHTCap VHTCap; + uint8_t uapsd_queues; + uint8_t max_sp; + uint8_t supported_channels_len; + uint8_t supported_channels[SIR_MAC_MAX_SUPP_CHANNELS]; + uint8_t supported_oper_classes_len; + uint8_t supported_oper_classes[CDS_MAX_SUPP_OPER_CLASSES]; +} tCsrStaParams; + +typedef struct tagCsrScanRequest { + tSirScanType scanType; + struct qdf_mac_addr bssid; + eCsrRoamBssType BSSType; + tCsrSSIDs SSIDs; + tCsrChannelInfo ChannelInfo; + uint32_t minChnTime; /* in units of milliseconds */ + uint32_t maxChnTime; /* in units of milliseconds */ + /* In units of milliseconds, ignored when not connected */ + uint32_t restTime; + /* In units of milliseconds, ignored when not connected */ + uint32_t min_rest_time; + /* In units of milliseconds, ignored when not connected */ + uint32_t idle_time; + uint32_t uIEFieldLen; + uint8_t *pIEField; + enum wmi_dwelltime_adaptive_mode scan_adaptive_dwell_mode; + eCsrRequestType requestType; /* 11d scan or full scan */ + bool p2pSearch; + bool skipDfsChnlInP2pSearch; + bool bcnRptReqScan; /* is Scan issued by Beacon Report Request */ + uint32_t scan_id; + uint32_t timestamp; + + bool enable_scan_randomization; + uint8_t mac_addr[QDF_MAC_ADDR_SIZE]; + uint8_t mac_addr_mask[QDF_MAC_ADDR_SIZE]; +} tCsrScanRequest; + +typedef struct tagCsrScanResultInfo { + /* + * Carry the IEs for the current BSSDescription. + * A pointer to tDot11fBeaconIEs. Maybe NULL for start BSS. + */ + void *pvIes; + tAniSSID ssId; + unsigned long timer; /* timer is variable for hidden SSID timer */ + /* + * This member must be the last in the structure because the + * end of tSirBssDescription is an + * array with nonknown size at this time */ + tSirBssDescription BssDescriptor; +} tCsrScanResultInfo; + +typedef struct tagCsrEncryptionList { + + uint32_t numEntries; + eCsrEncryptionType encryptionType[eCSR_NUM_OF_ENCRYPT_TYPE]; + +} tCsrEncryptionList, *tpCsrEncryptionList; + +typedef struct tagCsrAuthList { + uint32_t numEntries; + eCsrAuthType authType[eCSR_NUM_OF_SUPPORT_AUTH_TYPE]; +} tCsrAuthList, *tpCsrAuthList; + +typedef struct tagCsrMobilityDomainInfo { + uint8_t mdiePresent; + uint16_t mobilityDomain; +} tCsrMobilityDomainInfo; + +#ifdef FEATURE_WLAN_ESE +typedef struct tagCsrEseCckmInfo { + uint32_t reassoc_req_num; + bool krk_plumbed; + uint8_t krk[SIR_KRK_KEY_LEN]; +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + uint8_t btk[SIR_BTK_KEY_LEN]; +#endif +} tCsrEseCckmInfo; + +#define CSR_DOT11F_IE_RSN_MAX_LEN (114) +typedef struct tagCsrEseCckmIe { + uint8_t cckmIe[CSR_DOT11F_IE_RSN_MAX_LEN]; + uint8_t cckmIeLen; +} tCsrEseCckmIe; +#endif /* FEATURE_WLAN_ESE */ + +typedef struct sCsrChannel_ { + uint8_t numChannels; + uint8_t channelList[WNI_CFG_VALID_CHANNEL_LIST_LEN]; +} sCsrChannel; + +typedef struct tagCsrScanResultFilter { + tCsrBSSIDs BSSIDs; + tCsrSSIDs SSIDs; + tCsrChannelInfo ChannelInfo; + tCsrAuthList authType; + tCsrEncryptionList EncryptionType; + /* + * eCSR_ENCRYPT_TYPE_ANY cannot be set in multicast encryption type. + * If caller doesn't case, put all supported encryption types in here + */ + tCsrEncryptionList mcEncryptionType; + eCsrRoamBssType BSSType; + /* its a bit mask of all the needed phy mode defined in eCsrPhyMode */ + eCsrPhyMode phyMode; + /* + * If countryCode[0] is not 0, countryCode is checked + * independent of fCheckUnknownCountryCode + */ + uint8_t countryCode[WNI_CFG_COUNTRY_CODE_LEN]; + uint8_t uapsd_mask; + /* For WPS filtering if true => auth and ecryption should be ignored */ + bool bWPSAssociation; + bool bOSENAssociation; + /* + * For measurement reports --> if set, only SSID, + * BSSID and channel is considered for filtering. + */ + bool fMeasurement; + tCsrMobilityDomainInfo MDID; + bool p2pResult; +#ifdef WLAN_FEATURE_11W + /* Management Frame Protection */ + bool MFPEnabled; + uint8_t MFPRequired; + uint8_t MFPCapable; +#endif + /* The following flag is used to distinguish the + * roaming case while building the scan filter and + * applying it on to the scan results. This is mainly + * used to support whitelist ssid feature. + */ + uint8_t scan_filter_for_roam; + struct sCsrChannel_ pcl_channels; + struct qdf_mac_addr bssid_hint; + enum tQDF_ADAPTER_MODE csrPersona; +} tCsrScanResultFilter; + +typedef struct sCsrChnPower_ { + uint8_t firstChannel; + uint8_t numChannels; + uint8_t maxtxPower; +} sCsrChnPower; + +typedef struct tagCsr11dinfo { + sCsrChannel Channels; + uint8_t countryCode[WNI_CFG_COUNTRY_CODE_LEN + 1]; + /* max power channel list */ + sCsrChnPower ChnPower[WNI_CFG_VALID_CHANNEL_LIST_LEN]; +} tCsr11dinfo; + +typedef enum { + eCSR_ROAM_CANCELLED = 1, + /* it means error happens before assoc_start/roaming_start is called. */ + eCSR_ROAM_FAILED, + /* + * a CSR trigger roaming operation starts, + * callback may get a pointer to tCsrConnectedProfile + */ + eCSR_ROAM_ROAMING_START, + /* a CSR trigger roaming operation is completed */ + eCSR_ROAM_ROAMING_COMPLETION, + /* Connection completed status. */ + eCSR_ROAM_CONNECT_COMPLETION, + /* + * an association or start_IBSS operation starts, + * callback may get a pointer to tCsrRoamProfile and + * a pointer to tSirBssDescription + */ + eCSR_ROAM_ASSOCIATION_START, + /* + * a roaming operation is finish, see eCsrRoamResult for + * possible data passed back + */ + eCSR_ROAM_ASSOCIATION_COMPLETION, + eCSR_ROAM_DISASSOCIATED, + eCSR_ROAM_ASSOCIATION_FAILURE, + /* when callback with this flag. it gets a pointer to the BSS desc. */ + eCSR_ROAM_SHOULD_ROAM, + /* A new candidate for PMKID is found */ + eCSR_ROAM_SCAN_FOUND_NEW_BSS, + /* CSR is done lostlink roaming and still cannot reconnect */ + eCSR_ROAM_LOSTLINK, + /* a link lost is detected. CSR starts roaming. */ + eCSR_ROAM_LOSTLINK_DETECTED, + /* + * TKIP MIC error detected, callback gets a pointer + * to tpSirSmeMicFailureInd + */ + eCSR_ROAM_MIC_ERROR_IND, + /* IBSS indications. */ + eCSR_ROAM_IBSS_IND, + /* + * Update the connection status, useful for IBSS: new peer added, + * network is active etc. + */ + eCSR_ROAM_CONNECT_STATUS_UPDATE, + eCSR_ROAM_GEN_INFO, + eCSR_ROAM_SET_KEY_COMPLETE, + eCSR_ROAM_IBSS_LEAVE, /* IBSS indications. */ + /* BSS in SoftAP mode status indication */ + eCSR_ROAM_INFRA_IND, + eCSR_ROAM_WPS_PBC_PROBE_REQ_IND, + eCSR_ROAM_FT_RESPONSE, + eCSR_ROAM_FT_START, + eCSR_ROAM_REMAIN_CHAN_READY, + /* this mean error happens before assoc_start/roam_start is called. */ + eCSR_ROAM_SESSION_OPENED, + eCSR_ROAM_FT_REASSOC_FAILED, + eCSR_ROAM_PMK_NOTIFY, + /* + * Following 4 enums are used by FEATURE_WLAN_LFR_METRICS + * but they are needed for compilation even when + * FEATURE_WLAN_LFR_METRICS is not defined. + */ + eCSR_ROAM_PREAUTH_INIT_NOTIFY, + eCSR_ROAM_PREAUTH_STATUS_SUCCESS, + eCSR_ROAM_PREAUTH_STATUS_FAILURE, + eCSR_ROAM_HANDOVER_SUCCESS, + /* + * TDLS callback events + */ + eCSR_ROAM_TDLS_STATUS_UPDATE, + eCSR_ROAM_RESULT_MGMT_TX_COMPLETE_IND, + + /* Disaconnect all the clients */ + eCSR_ROAM_DISCONNECT_ALL_P2P_CLIENTS, + /* Stopbss triggered from SME due to different */ + eCSR_ROAM_SEND_P2P_STOP_BSS, + /* beacon interval */ +#ifdef WLAN_FEATURE_11W + eCSR_ROAM_UNPROT_MGMT_FRAME_IND, +#endif + + eCSR_ROAM_IBSS_PEER_INFO_COMPLETE, + +#ifdef FEATURE_WLAN_ESE + eCSR_ROAM_TSM_IE_IND, + eCSR_ROAM_CCKM_PREAUTH_NOTIFY, + eCSR_ROAM_ESE_ADJ_AP_REPORT_IND, + eCSR_ROAM_ESE_BCN_REPORT_IND, +#endif /* FEATURE_WLAN_ESE */ + + /* Radar indication from lower layers */ + eCSR_ROAM_DFS_RADAR_IND, + eCSR_ROAM_SET_CHANNEL_RSP, + + /* Channel sw update notification */ + eCSR_ROAM_DFS_CHAN_SW_NOTIFY, + eCSR_ROAM_EXT_CHG_CHNL_IND, + eCSR_ROAM_STA_CHANNEL_SWITCH, + eCSR_ROAM_NDP_STATUS_UPDATE, + eCSR_ROAM_UPDATE_SCAN_RESULT, + eCSR_ROAM_START, + eCSR_ROAM_ABORT, + eCSR_ROAM_NAPI_OFF, +} eRoamCmdStatus; + +/* comment inside indicates what roaming callback gets */ +typedef enum { + eCSR_ROAM_RESULT_NONE, + /* + * If roamStatus is eCSR_ROAM_ASSOCIATION_COMPLETION, + * tCsrRoamInfo's pBssDesc may pass back + */ + eCSR_ROAM_RESULT_FAILURE, + /* Pass back pointer to tCsrRoamInfo */ + eCSR_ROAM_RESULT_ASSOCIATED, + eCSR_ROAM_RESULT_NOT_ASSOCIATED, + eCSR_ROAM_RESULT_MIC_FAILURE, + eCSR_ROAM_RESULT_FORCED, + eCSR_ROAM_RESULT_DISASSOC_IND, + eCSR_ROAM_RESULT_DEAUTH_IND, + eCSR_ROAM_RESULT_CAP_CHANGED, + /* + * This means we starts an IBSS tCsrRoamInfo's + * pBssDesc may pass back + */ + eCSR_ROAM_RESULT_IBSS_STARTED, + eCSR_ROAM_RESULT_IBSS_START_FAILED, + eCSR_ROAM_RESULT_IBSS_JOIN_SUCCESS, + eCSR_ROAM_RESULT_IBSS_JOIN_FAILED, + eCSR_ROAM_RESULT_IBSS_CONNECT, + eCSR_ROAM_RESULT_IBSS_INACTIVE, + /* + * If roamStatus is eCSR_ROAM_ASSOCIATION_COMPLETION + * tCsrRoamInfo's pBssDesc may pass back and the peer's MAC address + * in peerMacOrBssid. If roamStatus is eCSR_ROAM_IBSS_IND, + * the peer's MAC address in peerMacOrBssid and a beacon frame + * of the IBSS in pbFrames + */ + eCSR_ROAM_RESULT_IBSS_NEW_PEER, + /* + * Peer departed from IBSS, Callback may get a pointer tSmeIbssPeerInd + * in pIbssPeerInd + */ + eCSR_ROAM_RESULT_IBSS_PEER_DEPARTED, + /* + * Coalescing in the IBSS network (joined an IBSS network) + * Callback pass a BSSID in peerMacOrBssid + */ + eCSR_ROAM_RESULT_IBSS_COALESCED, + /* + * If roamStatus is eCSR_ROAM_ROAMING_START, callback may get a pointer + * to tCsrConnectedProfile used to connect. + */ + eCSR_ROAM_RESULT_IBSS_STOP, + eCSR_ROAM_RESULT_LOSTLINK, + eCSR_ROAM_RESULT_MIC_ERROR_UNICAST, + eCSR_ROAM_RESULT_MIC_ERROR_GROUP, + eCSR_ROAM_RESULT_AUTHENTICATED, + eCSR_ROAM_RESULT_NEW_RSN_BSS, +#ifdef FEATURE_WLAN_WAPI + eCSR_ROAM_RESULT_NEW_WAPI_BSS, +#endif /* FEATURE_WLAN_WAPI */ + /* INFRA started successfully */ + eCSR_ROAM_RESULT_INFRA_STARTED, + /* INFRA start failed */ + eCSR_ROAM_RESULT_INFRA_START_FAILED, + /* INFRA stopped */ + eCSR_ROAM_RESULT_INFRA_STOPPED, + /* A station joining INFRA AP */ + eCSR_ROAM_RESULT_INFRA_ASSOCIATION_IND, + /* A station joined INFRA AP */ + eCSR_ROAM_RESULT_INFRA_ASSOCIATION_CNF, + /* INFRA disassociated */ + eCSR_ROAM_RESULT_INFRA_DISASSOCIATED, + eCSR_ROAM_RESULT_WPS_PBC_PROBE_REQ_IND, + eCSR_ROAM_RESULT_SEND_ACTION_FAIL, + /* peer rejected assoc because max assoc limit reached */ + eCSR_ROAM_RESULT_MAX_ASSOC_EXCEEDED, + /* Assoc rejected due to concurrent session running on a diff channel */ + eCSR_ROAM_RESULT_ASSOC_FAIL_CON_CHANNEL, + /* TDLS events */ + eCSR_ROAM_RESULT_ADD_TDLS_PEER, + eCSR_ROAM_RESULT_UPDATE_TDLS_PEER, + eCSR_ROAM_RESULT_DELETE_TDLS_PEER, + eCSR_ROAM_RESULT_TEARDOWN_TDLS_PEER_IND, + eCSR_ROAM_RESULT_DELETE_ALL_TDLS_PEER_IND, + eCSR_ROAM_RESULT_LINK_ESTABLISH_REQ_RSP, + eCSR_ROAM_RESULT_TDLS_SHOULD_DISCOVER, + eCSR_ROAM_RESULT_TDLS_SHOULD_TEARDOWN, + eCSR_ROAM_RESULT_TDLS_SHOULD_PEER_DISCONNECTED, + eCSR_ROAM_RESULT_TDLS_CONNECTION_TRACKER_NOTIFICATION, + + eCSR_ROAM_RESULT_IBSS_PEER_INFO_SUCCESS, + eCSR_ROAM_RESULT_IBSS_PEER_INFO_FAILED, + eCSR_ROAM_RESULT_DFS_RADAR_FOUND_IND, + eCSR_ROAM_RESULT_CHANNEL_CHANGE_SUCCESS, + eCSR_ROAM_RESULT_CHANNEL_CHANGE_FAILURE, + eCSR_ROAM_RESULT_DFS_CHANSW_UPDATE_SUCCESS, + eCSR_ROAM_EXT_CHG_CHNL_UPDATE_IND, + + eCSR_ROAM_RESULT_NDI_CREATE_RSP, + eCSR_ROAM_RESULT_NDI_DELETE_RSP, + eCSR_ROAM_RESULT_NDP_INITIATOR_RSP, + eCSR_ROAM_RESULT_NDP_NEW_PEER_IND, + eCSR_ROAM_RESULT_NDP_CONFIRM_IND, + eCSR_ROAM_RESULT_NDP_INDICATION, + eCSR_ROAM_RESULT_NDP_SCHED_UPDATE_RSP, + eCSR_ROAM_RESULT_NDP_RESPONDER_RSP, + eCSR_ROAM_RESULT_NDP_END_RSP, + eCSR_ROAM_RESULT_NDP_PEER_DEPARTED_IND, + eCSR_ROAM_RESULT_NDP_END_IND, + /* If Scan for SSID failed to found proper BSS */ + eCSR_ROAM_RESULT_SCAN_FOR_SSID_FAILURE, + eCSR_ROAM_RESULT_INVOKE_FAILED, +} eCsrRoamResult; + +/*---------------------------------------------------------------------------- + List of link quality indications HDD can receive from SME + --------------------------------------------------------------------------*/ +typedef enum { + eCSR_ROAM_LINK_QUAL_MIN_IND = -1, + + eCSR_ROAM_LINK_QUAL_POOR_IND = 0, /* bad link */ + eCSR_ROAM_LINK_QUAL_GOOD_IND = 1, /* acceptable for voice */ + eCSR_ROAM_LINK_QUAL_VERY_GOOD_IND = 2, /* suitable for voice */ + eCSR_ROAM_LINK_QUAL_EXCELLENT_IND = 3, /* suitable for voice */ + + eCSR_ROAM_LINK_QUAL_MAX_IND /* invalid value */ +} eCsrRoamLinkQualityInd; + +typedef enum { + eCSR_DISCONNECT_REASON_UNSPECIFIED = 0, + eCSR_DISCONNECT_REASON_MIC_ERROR, + eCSR_DISCONNECT_REASON_DISASSOC, + eCSR_DISCONNECT_REASON_DEAUTH, + eCSR_DISCONNECT_REASON_HANDOFF, + eCSR_DISCONNECT_REASON_IBSS_JOIN_FAILURE, + eCSR_DISCONNECT_REASON_IBSS_LEAVE, + eCSR_DISCONNECT_REASON_STA_HAS_LEFT, + eCSR_DISCONNECT_REASON_NDI_DELETE, + eCSR_DISCONNECT_REASON_ROAM_HO_FAIL, +} eCsrRoamDisconnectReason; + +typedef enum { + /* Not associated in Infra or participating in an IBSS/Ad-hoc */ + eCSR_ASSOC_STATE_TYPE_NOT_CONNECTED, + /* Associated in an Infrastructure network. */ + eCSR_ASSOC_STATE_TYPE_INFRA_ASSOCIATED, + /* Participating in IBSS network though disconnection */ + eCSR_ASSOC_STATE_TYPE_IBSS_DISCONNECTED, + /* Participating in IBSS network with partner stations also present */ + eCSR_ASSOC_STATE_TYPE_IBSS_CONNECTED, + /* Participating in WDS network in AP/STA mode but not connected yet */ + eCSR_ASSOC_STATE_TYPE_WDS_DISCONNECTED, + /* Participating in a WDS network and connected peer to peer */ + eCSR_ASSOC_STATE_TYPE_WDS_CONNECTED, + /* Participating in a Infra network in AP not yet in connected state */ + eCSR_ASSOC_STATE_TYPE_INFRA_DISCONNECTED, + /* Participating in a Infra network and connected to a peer */ + eCSR_ASSOC_STATE_TYPE_INFRA_CONNECTED, + /* Disconnecting with AP or stop connecting process */ + eCSR_ASSOC_STATE_TYPE_INFRA_DISCONNECTING, + /* NAN Data interface not started */ + eCSR_CONNECT_STATE_TYPE_NDI_NOT_STARTED, + /* NAN Data inteface started */ + eCSR_CONNECT_STATE_TYPE_NDI_STARTED, + +} eCsrConnectState; + +/* + * This parameter is no longer supported in the Profile. + * Need to set this in the global properties for the adapter. + */ +typedef enum eCSR_MEDIUM_ACCESS { + eCSR_MEDIUM_ACCESS_AUTO = 0, + eCSR_MEDIUM_ACCESS_DCF, + eCSR_MEDIUM_ACCESS_eDCF, + eCSR_MEDIUM_ACCESS_HCF, + + eCSR_MEDIUM_ACCESS_WMM_eDCF_802dot1p, + eCSR_MEDIUM_ACCESS_WMM_eDCF_DSCP, + eCSR_MEDIUM_ACCESS_WMM_eDCF_NoClassify, + eCSR_MEDIUM_ACCESS_11e_eDCF = eCSR_MEDIUM_ACCESS_eDCF, + eCSR_MEDIUM_ACCESS_11e_HCF = eCSR_MEDIUM_ACCESS_HCF, +} eCsrMediaAccessType; + +typedef enum { + eCSR_TX_RATE_AUTO = 0, /* use rate adaption to determine Tx rate. */ + eCSR_TX_RATE_1Mbps = 0x00000001, + eCSR_TX_RATE_2Mbps = 0x00000002, + eCSR_TX_RATE_5_5Mbps = 0x00000004, + eCSR_TX_RATE_6Mbps = 0x00000008, + eCSR_TX_RATE_9Mbps = 0x00000010, + eCSR_TX_RATE_11Mbps = 0x00000020, + eCSR_TX_RATE_12Mbps = 0x00000040, + eCSR_TX_RATE_18Mbps = 0x00000080, + eCSR_TX_RATE_24Mbps = 0x00000100, + eCSR_TX_RATE_36Mbps = 0x00000200, + eCSR_TX_RATE_42Mbps = 0x00000400, + eCSR_TX_RATE_48Mbps = 0x00000800, + eCSR_TX_RATE_54Mbps = 0x00001000, + eCSR_TX_RATE_72Mbps = 0x00002000, + eCSR_TX_RATE_84Mbps = 0x00004000, + eCSR_TX_RATE_96Mbps = 0x00008000, + eCSR_TX_RATE_108Mbps = 0x00010000, + eCSR_TX_RATE_126Mbps = 0x00020000, + eCSR_TX_RATE_144Mbps = 0x00040000, + eCSR_TX_RATE_168Mbps = 0x00080000, + eCSR_TX_RATE_192Mbps = 0x00100000, + eCSR_TX_RATE_216Mbps = 0x00200000, + eCSR_TX_RATE_240Mbps = 0x00400000, + +} eCsrExposedTxRate; + +typedef enum { + eCSR_OPERATING_CHANNEL_ALL = 0, + eCSR_OPERATING_CHANNEL_AUTO = eCSR_OPERATING_CHANNEL_ALL, + eCSR_OPERATING_CHANNEL_ANY = eCSR_OPERATING_CHANNEL_ALL, +} eOperationChannel; + +typedef enum { + eCSR_DOT11_FRAG_THRESH_AUTO = -1, + eCSR_DOT11_FRAG_THRESH_MIN = 256, + eCSR_DOT11_FRAG_THRESH_MAX = 2346, + eCSR_DOT11_FRAG_THRESH_DEFAULT = 2000 +} eCsrDot11FragThresh; + +/* for channel bonding for ibss */ +typedef enum { + eCSR_CB_OFF = 0, + eCSR_CB_AUTO = 1, + eCSR_CB_DOWN = 2, + eCSR_CB_UP = 3, +} eCsrCBChoice; + +/* + * For channel bonding, the channel number gap is 4, either up or down. + * For both 11a and 11g mode. + */ +#define CSR_CB_CHANNEL_GAP 4 +#define CSR_CB_CENTER_CHANNEL_OFFSET 2 + +/* WEP keysize (in bits) */ +typedef enum { + /* 40 bit key + 24bit IV = 64bit WEP */ + eCSR_SECURITY_WEP_KEYSIZE_40 = 40, + /* 104bit key + 24bit IV = 128bit WEP */ + eCSR_SECURITY_WEP_KEYSIZE_104 = 104, + eCSR_SECURITY_WEP_KEYSIZE_MIN = eCSR_SECURITY_WEP_KEYSIZE_40, + eCSR_SECURITY_WEP_KEYSIZE_MAX = eCSR_SECURITY_WEP_KEYSIZE_104, + eCSR_SECURITY_WEP_KEYSIZE_MAX_BYTES = + (eCSR_SECURITY_WEP_KEYSIZE_MAX / 8), +} eCsrWEPKeySize; + +/* Possible values for the WEP static key ID */ +typedef enum { + + eCSR_SECURITY_WEP_STATIC_KEY_ID_MIN = 0, + eCSR_SECURITY_WEP_STATIC_KEY_ID_MAX = 3, + eCSR_SECURITY_WEP_STATIC_KEY_ID_DEFAULT = 0, + + eCSR_SECURITY_WEP_STATIC_KEY_ID_INVALID = -1, + +} eCsrWEPStaticKeyID; + +/* Two extra key indicies are used for the IGTK (which is used by BIP) */ +#define CSR_MAX_NUM_KEY (eCSR_SECURITY_WEP_STATIC_KEY_ID_MAX + 2 + 1) + +typedef enum { + eCSR_SECURITY_SET_KEY_ACTION_NO_CHANGE, + eCSR_SECURITY_SET_KEY_ACTION_SET_KEY, + eCSR_SECURITY_SET_KEY_ACTION_DELETE_KEY, +} eCsrSetKeyAction; + +typedef enum { + eCSR_BAND_ALL, + eCSR_BAND_24, + eCSR_BAND_5G, + eCSR_BAND_MAX, +} eCsrBand; + +typedef enum { + /* + * Roaming because HDD requested for reassoc by changing one of the + * fields in tCsrRoamModifyProfileFields. OR Roaming because SME + * requested for reassoc by changing one of the fields in + * tCsrRoamModifyProfileFields. + */ + eCsrRoamReasonStaCapabilityChanged, + /* + * Roaming because SME requested for reassoc to a different AP, + * as part of inter AP handoff. + */ + eCsrRoamReasonBetterAP, + /* + * Roaming because SME requested it as the link is lost - placeholder, + * will clean it up once handoff code gets in + */ + eCsrRoamReasonSmeIssuedForLostLink, + +} eCsrRoamReasonCodes; + +typedef enum { + eCsrRoamWmmAuto = 0, + eCsrRoamWmmQbssOnly = 1, + eCsrRoamWmmNoQos = 2, + +} eCsrRoamWmmUserModeType; + +typedef enum { + eCSR_REQUESTER_MIN = 0, + eCSR_DIAG, + eCSR_UMA_GAN, + eCSR_HDD +} eCsrStatsRequesterType; + +/** + * enum csr_hi_rssi_scan_id - Parameter ids for hi rssi scan feature + * + * @eCSR_HI_RSSI_SCAN_MAXCOUNT_ID: how many times scan can be performed + * @eCSR_HI_RSSI_SCAN_RSSI_DELTA_ID: rssi difference to trigger scan + * @eCSR_HI_RSSI_SCAN_DELAY_ID: delay in millseconds between scans + * @eCSR_HI_RSSI_SCAN_RSSI_UB_ID: rssi upper bound for scan trigger + */ +enum csr_hi_rssi_scan_id { + eCSR_HI_RSSI_SCAN_MAXCOUNT_ID, + eCSR_HI_RSSI_SCAN_RSSI_DELTA_ID, + eCSR_HI_RSSI_SCAN_DELAY_ID, + eCSR_HI_RSSI_SCAN_RSSI_UB_ID +}; + +typedef struct tagPmkidCandidateInfo { + struct qdf_mac_addr BSSID; + bool preAuthSupported; +} tPmkidCandidateInfo; + +typedef struct tagPmkidCacheInfo { + struct qdf_mac_addr BSSID; + uint8_t PMKID[CSR_RSN_PMKID_SIZE]; +} tPmkidCacheInfo; + +#ifdef FEATURE_WLAN_WAPI +typedef struct tagBkidCandidateInfo { + struct qdf_mac_addr BSSID; + bool preAuthSupported; +} tBkidCandidateInfo; + +typedef struct tagBkidCacheInfo { + struct qdf_mac_addr BSSID; + uint8_t BKID[CSR_WAPI_BKID_SIZE]; +} tBkidCacheInfo; +#endif /* FEATURE_WLAN_WAPI */ + +typedef struct tagCsrKeys { + /* Also use to indicate whether the key index is set */ + uint8_t KeyLength[CSR_MAX_NUM_KEY]; + uint8_t KeyMaterial[CSR_MAX_NUM_KEY][CSR_MAX_KEY_LEN]; + uint8_t defaultIndex; +} tCsrKeys; + +/* + * Following fields which're part of tCsrRoamConnectedProfile might need + * modification dynamically once STA is up & running & this'd trigger reassoc + */ +typedef struct tagCsrRoamModifyProfileFields { + /* + * during connect this specifies ACs U-APSD is to be setup + * for (Bit0:VO; Bit1:VI; Bit2:BK; Bit3:BE all other bits are ignored). + * During assoc response this COULD carry confirmation of what + * ACs U-APSD got setup for. Later if an APP looking for APSD, + * SME-QoS might need to modify this field + */ + uint8_t uapsd_mask; + /* HDD might ask to modify this field */ + uint16_t listen_interval; +} tCsrRoamModifyProfileFields; + +typedef struct tagCsrRoamProfile { + tCsrSSIDs SSIDs; + tCsrBSSIDs BSSIDs; + /* this is bit mask of all the needed phy mode defined in eCsrPhyMode */ + uint32_t phyMode; + eCsrRoamBssType BSSType; + tCsrAuthList AuthType; + eCsrAuthType negotiatedAuthType; + tCsrEncryptionList EncryptionType; + /* This field is for output only, not for input */ + eCsrEncryptionType negotiatedUCEncryptionType; + /* + * eCSR_ENCRYPT_TYPE_ANY cannot be set in multicast encryption type. + * If caller doesn't case, put all supported encryption types in here + */ + tCsrEncryptionList mcEncryptionType; + /* This field is for output only, not for input */ + eCsrEncryptionType negotiatedMCEncryptionType; +#ifdef WLAN_FEATURE_11W + /* Management Frame Protection */ + bool MFPEnabled; + uint8_t MFPRequired; + uint8_t MFPCapable; +#endif + tCsrKeys Keys; + eCsrCBChoice CBMode; + tCsrChannelInfo ChannelInfo; + uint8_t operationChannel; + struct ch_params_s ch_params; + /* If this is 0, SME will fill in for caller. */ + uint16_t beaconInterval; + /* + * during connect this specifies ACs U-APSD is to be setup + * for (Bit0:VO; Bit1:VI; Bit2:BK; Bit3:BE all other bits are ignored). + * During assoc resp this'd carry cnf of what ACs U-APSD got setup for + */ + uint8_t uapsd_mask; + uint32_t nWPAReqIELength; /* The byte count in the pWPAReqIE */ + uint8_t *pWPAReqIE; /* If not null,it's IE byte stream for WPA */ + uint32_t nRSNReqIELength; /* The byte count in the pRSNReqIE */ + uint8_t *pRSNReqIE; /* If not null,it's IE byte stream for RSN */ +#ifdef FEATURE_WLAN_WAPI + uint32_t nWAPIReqIELength;/* The byte count in the pWAPIReqIE */ + uint8_t *pWAPIReqIE; /* If not null,it's IE byte stream for WAPI */ +#endif /* FEATURE_WLAN_WAPI */ + + uint32_t nAddIEScanLength;/* pAddIE for scan (at the time of join) */ + /* + * If not null,it's the IE byte stream for additional IE, + * which can be WSC IE and/or P2P IE + */ + uint8_t *pAddIEScan; + uint32_t nAddIEAssocLength; /* The byte count in the pAddIE for assoc */ + /* + * If not null, it has the IE byte stream for additional IE, + * which can be WSC IE and/or P2P IE + */ + uint8_t *pAddIEAssoc; + /* it is ignored if [0] is 0. */ + uint8_t countryCode[WNI_CFG_COUNTRY_CODE_LEN]; + /* WPS Association if true => auth and ecryption should be ignored */ + bool bWPSAssociation; + bool bOSENAssociation; + uint32_t nWSCReqIELength; /* The byte count in the pWSCReqIE */ + uint8_t *pWSCReqIE; /* If not null,it's IE byte stream for WSC */ + uint8_t ieee80211d; + uint8_t privacy; + bool fwdWPSPBCProbeReq; + tAniAuthType csr80211AuthType; + uint32_t dtimPeriod; + bool ApUapsdEnable; + bool protEnabled; + bool obssProtEnabled; + uint16_t cfg_protection; + uint8_t wps_state; + tCsrMobilityDomainInfo MDID; + enum tQDF_ADAPTER_MODE csrPersona; + uint8_t disableDFSChSwitch; + /* addIe params */ + tSirAddIeParams addIeParams; + uint8_t sap_dot11mc; + uint8_t beacon_tx_rate; + tSirMacRateSet supported_rates; + tSirMacRateSet extended_rates; + struct qdf_mac_addr bssid_hint; + bool do_not_roam; + +} tCsrRoamProfile; + +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH +typedef struct tagCsrRoamHTProfile { + uint8_t phymode; + uint8_t htCapability; + uint8_t htSupportedChannelWidthSet; + uint8_t htRecommendedTxWidthSet; + ePhyChanBondState htSecondaryChannelOffset; + uint8_t vhtCapability; + uint8_t apCenterChan; + uint8_t apChanWidth; +} tCsrRoamHTProfile; +#endif +typedef struct tagCsrRoamConnectedProfile { + tSirMacSSid SSID; + bool handoffPermitted; + bool ssidHidden; + struct qdf_mac_addr bssid; + eCsrRoamBssType BSSType; + eCsrAuthType AuthType; + tCsrAuthList AuthInfo; + eCsrEncryptionType EncryptionType; + tCsrEncryptionList EncryptionInfo; + eCsrEncryptionType mcEncryptionType; + tCsrEncryptionList mcEncryptionInfo; + eCsrCBChoice CBMode; + uint8_t operationChannel; + uint32_t vht_channel_width; + uint16_t beaconInterval; + tCsrKeys Keys; + /* + * meaningless on connect. It's an OUT param from CSR's point of view + * During assoc response carries the ACM bit-mask i.e. what + * ACs have ACM=1 (if any),(Bit0:VO; Bit1:VI; Bit2:BK; Bit3:BE + * all other bits are ignored) + */ + uint8_t acm_mask; + tCsrRoamModifyProfileFields modifyProfileFields; + uint32_t nAddIEAssocLength; + /* + * If not null,it's IE byte stream for additional IE, + * which can be WSC IE and/or P2P IE + */ + uint8_t *pAddIEAssoc; + tSirBssDescription *pBssDesc; + bool qap; /* AP supports QoS */ + bool qosConnection; /* A connection is QoS enabled */ + tCsrMobilityDomainInfo MDID; +#ifdef FEATURE_WLAN_ESE + tCsrEseCckmInfo eseCckmInfo; + bool isESEAssoc; +#endif + uint32_t dot11Mode; + uint8_t proxyARPService; +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH + tCsrRoamHTProfile HTProfile; +#endif +#ifdef WLAN_FEATURE_11W + /* Management Frame Protection */ + bool MFPEnabled; + uint8_t MFPRequired; + uint8_t MFPCapable; +#endif +} tCsrRoamConnectedProfile; + +typedef struct tagCsr11rConfigParams { + bool IsFTResourceReqSupported; +} tCsr11rConfigParams; + +typedef struct tagCsrNeighborRoamConfigParams { + + uint32_t nNeighborScanTimerPeriod; + uint8_t nNeighborLookupRssiThreshold; + uint16_t nNeighborScanMinChanTime; + uint16_t nNeighborScanMaxChanTime; + sCsrChannel neighborScanChanList; + uint8_t nMaxNeighborRetries; + uint16_t nNeighborResultsRefreshPeriod; + uint16_t nEmptyScanRefreshPeriod; + uint8_t nOpportunisticThresholdDiff; + uint8_t nRoamRescanRssiDiff; + uint8_t nRoamBmissFirstBcnt; + uint8_t nRoamBmissFinalBcnt; + uint8_t nRoamBeaconRssiWeight; + uint8_t delay_before_vdev_stop; + uint32_t nhi_rssi_scan_max_count; + uint32_t nhi_rssi_scan_rssi_delta; + uint32_t nhi_rssi_scan_delay; + int32_t nhi_rssi_scan_rssi_ub; +} tCsrNeighborRoamConfigParams; + +/** + * enum sta_roam_policy_dfs_mode - state of DFS mode for STA ROME policy + * @CSR_STA_ROAM_POLICY_NONE: DFS mode attribute is not valid + * @CSR_STA_ROAM_POLICY_DFS_ENABLED: DFS mode is enabled + * @CSR_STA_ROAM_POLICY_DFS_DISABLED: DFS mode is disabled + * @CSR_STA_ROAM_POLICY_DFS_DEPRIORITIZE: Deprioritize DFS channels in scanning + */ +enum sta_roam_policy_dfs_mode { + CSR_STA_ROAM_POLICY_NONE, + CSR_STA_ROAM_POLICY_DFS_ENABLED, + CSR_STA_ROAM_POLICY_DFS_DISABLED, + CSR_STA_ROAM_POLICY_DFS_DEPRIORITIZE +}; + +/** + * struct csr_sta_roam_policy_params - sta roam policy params for station + * @dfs_mode: tell is DFS channels needs to be skipped while scanning + * @skip_unsafe_channels: tells if unsafe channels needs to be skip in scanning + * @sap_operating_band: Opearting band for SAP + */ +struct csr_sta_roam_policy_params { + enum sta_roam_policy_dfs_mode dfs_mode; + bool skip_unsafe_channels; + uint8_t sap_operating_band; +}; + +typedef struct tagCsrConfigParam { + uint32_t FragmentationThreshold; + /* keep this uint32_t. This gets converted to ePhyChannelBondState */ + uint32_t channelBondingMode24GHz; + uint32_t channelBondingMode5GHz; + eCsrPhyMode phyMode; + eCsrBand eBand; + uint32_t RTSThreshold; + uint32_t HeartbeatThresh50; + uint32_t HeartbeatThresh24; + eCsrCBChoice cbChoice; + eCsrBand bandCapability; /* indicate hw capability */ + uint16_t TxRate; + eCsrRoamWmmUserModeType WMMSupportMode; + bool Is11eSupportEnabled; + bool Is11dSupportEnabled; + bool Is11dSupportEnabledOriginal; + bool Is11hSupportEnabled; + bool shortSlotTime; + bool ProprietaryRatesEnabled; + uint8_t AdHocChannel24; + uint8_t AdHocChannel5G; + /* + * this number minus one is the number of times a scan doesn't find it + * before it is removed + */ + uint32_t nScanResultAgeCount; + /* to set the RSSI difference for each category */ + uint8_t bCatRssiOffset; + /* to set MCC Enable/Disable mode */ + uint8_t fEnableMCCMode; + bool mcc_rts_cts_prot_enable; + bool mcc_bcast_prob_resp_enable; + /* + * To allow MCC GO different B.I than STA's. + * NOTE: make sure if RIVA firmware can handle this combination before + * enabling this at the moment, this flag is provided only to pass + * Wi-Fi Cert. 5.1.12 + */ + uint8_t fAllowMCCGODiffBI; + tCsr11dinfo Csr11dinfo; + + /* Country Code Priority */ + bool fSupplicantCountryCodeHasPriority; + uint16_t vccRssiThreshold; + uint32_t vccUlMacLossThreshold; + uint32_t nPassiveMinChnTime; /* in units of milliseconds */ + uint32_t nPassiveMaxChnTime; /* in units of milliseconds */ + uint32_t nActiveMinChnTime; /* in units of milliseconds */ + uint32_t nActiveMaxChnTime; /* in units of milliseconds */ + uint32_t nInitialDwellTime; /* in units of milliseconds */ + bool initial_scan_no_dfs_chnl; +#ifdef WLAN_AP_STA_CONCURRENCY + uint32_t nPassiveMinChnTimeConc; /* in units of milliseconds */ + uint32_t nPassiveMaxChnTimeConc; /* in units of milliseconds */ + uint32_t nActiveMinChnTimeConc; /* in units of milliseconds */ + uint32_t nActiveMaxChnTimeConc; /* in units of milliseconds */ + uint32_t nRestTimeConc; /* in units of milliseconds */ + /* num of channels combined for STA in each split scan operation */ + uint8_t nNumStaChanCombinedConc; + /* number of channels combined for P2P in each split scan operation */ + uint8_t nNumP2PChanCombinedConc; +#endif + /*In units of milliseconds*/ + uint32_t min_rest_time_conc; + /*In units of milliseconds*/ + uint32_t idle_time_conc; + + /* + * in dBm, the maximum TX power The actual TX power is the lesser of + * this value and 11d. If 11d is disable, the lesser of this and + * default setting. + */ + uint8_t nTxPowerCap; + bool allow_tpc_from_ap; + /* stats request frequency from PE while in full power */ + uint32_t statsReqPeriodicity; + /* stats request frequency from PE while in power save */ + uint32_t statsReqPeriodicityInPS; + tCsr11rConfigParams csr11rConfig; +#ifdef FEATURE_WLAN_ESE + uint8_t isEseIniFeatureEnabled; +#endif + uint8_t isFastRoamIniFeatureEnabled; + uint8_t MAWCEnabled; + uint8_t isFastTransitionEnabled; + uint8_t RoamRssiDiff; + bool isWESModeEnabled; + tCsrNeighborRoamConfigParams neighborRoamConfig; + /* + * Instead of Reassoc, send ADDTS/DELTS even when ACM is off for that AC + * This is mandated by WMM-AC certification + */ + bool addTSWhenACMIsOff; + /* + * channelPowerInfoList24 has been seen corrupted. Set this flag to true + * trying to detect when it happens. Adding this into code because we + * can't reproduce it easily. We don't know when it happens. + */ + bool fValidateList; + /* + * Customer wants to start with an active scan based on the default + * country code. This optimization will minimize the driver load to + * association time. Based on this flag we will bypass the initial + * passive scan needed for 11d to determine the country code & domain + */ + bool fEnableBypass11d; + /* + * Customer wants to optimize the scan time. Avoiding scans(passive) + * on DFS channels while swipping through both bands can save some time + * (apprx 1.3 sec) + */ + uint8_t fEnableDFSChnlScan; + /* + * To enable/disable scanning 2.4Ghz channels twice on a single scan + * request from HDD + */ + bool fScanTwice; + uint32_t nVhtChannelWidth; + uint8_t enableTxBF; + uint8_t enable_txbf_sap_mode; + uint8_t enable2x2; + bool enableVhtFor24GHz; + bool vendor_vht_sap; + uint8_t enableMuBformee; + uint8_t enableVhtpAid; + uint8_t enableVhtGid; + uint8_t enableAmpduPs; + uint8_t enableHtSmps; + uint8_t htSmps; + bool send_smps_action; + bool ignore_peer_erp_info; + /* + * To enable/disable scanning only 2.4Ghz channels on first scan + */ + bool fFirstScanOnly2GChnl; + bool nRoamPrefer5GHz; + bool nRoamIntraBand; + uint8_t nProbes; + uint16_t nRoamScanHomeAwayTime; + + bool isRoamOffloadScanEnabled; + bool bFastRoamInConIniFeatureEnabled; + uint8_t scanCfgAgingTime; + uint8_t enableTxLdpc; + uint8_t enableRxLDPC; + uint8_t disable_high_ht_mcs_2x2; + uint8_t max_amsdu_num; + uint8_t nSelect5GHzMargin; + uint8_t isCoalesingInIBSSAllowed; +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH + uint8_t cc_switch_mode; +#endif + uint8_t allowDFSChannelRoam; +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + bool isRoamOffloadEnabled; +#endif + bool obssEnabled; + uint8_t conc_custom_rule1; + uint8_t conc_custom_rule2; + uint8_t is_sta_connection_in_5gz_enabled; + bool sendDeauthBeforeCon; + + /* 802.11p enable */ + bool enable_dot11p; + uint8_t max_scan_count; +#ifdef FEATURE_WLAN_SCAN_PNO + bool pno_channel_prediction; + uint8_t top_k_num_of_channels; + uint8_t stationary_thresh; + enum wmi_dwelltime_adaptive_mode pnoscan_adaptive_dwell_mode; + uint32_t channel_prediction_full_scan; +#endif + bool early_stop_scan_enable; + int8_t early_stop_scan_min_threshold; + int8_t early_stop_scan_max_threshold; + int8_t first_scan_bucket_threshold; + bool pnoOffload; + uint8_t fEnableDebugLog; + uint8_t max_intf_count; + bool enable5gEBT; + bool enableSelfRecovery; + uint32_t f_sta_miracast_mcc_rest_time_val; +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE + bool sap_channel_avoidance; +#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ + uint8_t f_prefer_non_dfs_on_radar; + bool is_ps_enabled; + uint32_t auto_bmps_timer_val; + uint32_t fine_time_meas_cap; + uint32_t dual_mac_feature_disable; + uint32_t roam_dense_traffic_thresh; + uint32_t roam_dense_rssi_thresh_offset; + uint32_t roam_dense_min_aps; + uint32_t obss_width_interval; + uint32_t obss_active_dwelltime; + uint32_t obss_passive_dwelltime; + bool ignore_peer_ht_opmode; + bool enable_edca_params; + uint32_t edca_vo_cwmin; + uint32_t edca_vi_cwmin; + uint32_t edca_bk_cwmin; + uint32_t edca_be_cwmin; + uint32_t edca_vo_cwmax; + uint32_t edca_vi_cwmax; + uint32_t edca_bk_cwmax; + uint32_t edca_be_cwmax; + uint32_t edca_vo_aifs; + uint32_t edca_vi_aifs; + uint32_t edca_bk_aifs; + uint32_t edca_be_aifs; + bool enable_fatal_event; + enum wmi_dwelltime_adaptive_mode scan_adaptive_dwell_mode; + enum wmi_dwelltime_adaptive_mode roamscan_adaptive_dwell_mode; + struct csr_sta_roam_policy_params sta_roam_policy_params; + uint32_t tx_aggregation_size; + uint32_t rx_aggregation_size; + struct wmi_per_roam_config per_roam_config; + bool enable_bcast_probe_rsp; + bool qcn_ie_support; + uint8_t fils_max_chan_guard_time; + uint16_t pkt_err_disconn_th; + bool is_bssid_hint_priority; + bool is_force_1x1; + uint16_t num_11b_tx_chains; + uint16_t num_11ag_tx_chains; + uint32_t scan_probe_repeat_time; + uint32_t scan_num_probes; +} tCsrConfigParam; + +/* Tush */ +typedef struct tagCsrUpdateConfigParam { + tCsr11dinfo Csr11dinfo; +} tCsrUpdateConfigParam; +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +#define csr_roamIsRoamOffloadEnabled(pMac) \ + (pMac->roam.configParam.isRoamOffloadEnabled) +#define DEFAULT_REASSOC_FAILURE_TIMEOUT 1000 +#endif + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +/* connected but not authenticated */ +#define CSR_ROAM_AUTH_STATUS_CONNECTED 0x1 +/* connected and authenticated */ +#define CSR_ROAM_AUTH_STATUS_AUTHENTICATED 0x2 +#endif + +typedef struct tagCsrRoamInfo { + tCsrRoamProfile *pProfile; + tSirBssDescription *pBssDesc; + uint32_t nBeaconLength; + uint32_t nAssocReqLength; + uint32_t nAssocRspLength; + uint32_t nFrameLength; + uint8_t frameType; + /* + * Point to a buffer contain the beacon, assoc req, assoc rsp frame, + * in that order user needs to use nBeaconLength, nAssocReqLength, + * nAssocRspLength to desice where each frame starts and ends. + */ + uint8_t *pbFrames; + bool fReassocReq; /* set to true if for re-association */ + bool fReassocRsp; /* set to true if for re-association */ + struct qdf_mac_addr bssid; + /* + * Only valid in IBSS. this is the peers MAC address for + * eCSR_ROAM_RESULT_IBSS_NEW_PEER or PEER_DEPARTED + */ + struct qdf_mac_addr peerMac; + tSirResultCodes statusCode; + /* this'd be our own defined or sent from otherBSS(per 802.11spec) */ + uint32_t reasonCode; + uint8_t staId; /* Peer stationId when connected */ + /* + * The DPU signatures will be sent eventually to TL to help it + * determine the assoc to which a packet belongs to unicast DPU sign + */ + uint8_t ucastSig; + uint8_t bcastSig; /* Broadcast DPU signature */ + /* false means auth needed from supplicant. true means authenticated */ + bool fAuthRequired; + uint8_t sessionId; + uint8_t rsnIELen; + uint8_t *prsnIE; + uint8_t wapiIELen; + uint8_t *pwapiIE; + uint8_t addIELen; + uint8_t *paddIE; + union { + tSirMicFailureInfo *pMICFailureInfo; + tCsrRoamConnectedProfile *pConnectedProfile; + tSirWPSPBCProbeReq *pWPSPBCProbeReq; + } u; + bool wmmEnabledSta; /* set to true if WMM enabled STA */ + uint32_t dtimPeriod; +#ifdef FEATURE_WLAN_ESE + bool isESEAssoc; + tSirTsmIE tsmIe; + uint32_t timestamp[2]; + uint16_t tsmRoamDelay; + tSirEseBcnReportRsp *pEseBcnReportRsp; +#endif + void *pRemainCtx; + uint32_t roc_scan_id; + uint32_t rxChan; +#ifdef FEATURE_WLAN_TDLS + /* + * TDLS parameters to check whether TDLS + * and TDLS channel switch is allowed in the + * AP network + */ + uint8_t staType; + bool tdls_prohibited; /* per ExtCap in Assoc/Reassoc resp */ + bool tdls_chan_swit_prohibited; /* per ExtCap in Assoc/Reassoc resp */ +#endif + /* Required for indicating the frames to upper layer */ + uint32_t beaconLength; + uint8_t *beaconPtr; + uint32_t assocReqLength; + uint8_t *assocReqPtr; + int8_t rxRssi; + tSirSmeDfsEventInd dfs_event; + tSirChanChangeResponse *channelChangeRespEvent; + /* Timing and fine Timing measurement capability clubbed together */ + uint8_t timingMeasCap; +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + uint8_t roamSynchInProgress; + uint8_t synchAuthStatus; + uint8_t kck[SIR_KCK_KEY_LEN]; + uint8_t kek[SIR_KEK_KEY_LEN]; + uint8_t replay_ctr[SIR_REPLAY_CTR_LEN]; + uint8_t subnet_change_status; +#endif + tSirSmeChanInfo chan_info; + uint8_t target_channel; + +#ifdef WLAN_FEATURE_NAN_DATAPATH + union { + struct sme_ndp_peer_ind ndp_peer_ind_params; + struct ndp_schedule_update_rsp ndp_sched_upd_rsp_params; + struct ndp_end_indication_event *ndp_end_ind_params; + struct ndp_end_rsp_event *ndp_end_rsp_params; + struct ndp_confirm_event ndp_confirm_params; + struct ndp_responder_rsp_event ndp_responder_rsp_params; + struct ndp_indication_event ndp_indication_params; + struct ndp_initiator_rsp ndp_init_rsp_params; + struct ndi_create_rsp ndi_create_params; + struct ndi_delete_rsp ndi_delete_params; + } ndp; +#endif + tDot11fIEHTCaps ht_caps; + tDot11fIEVHTCaps vht_caps; + tDot11fIEhs20vendor_ie hs20vendor_ie; + tDot11fIEVHTOperation vht_operation; + tDot11fIEHTInfo ht_operation; + bool reassoc; +} tCsrRoamInfo; + +typedef struct tagCsrFreqScanInfo { + uint32_t nStartFreq; /* in unit of MHz */ + uint32_t nEndFreq; /* in unit of MHz */ + tSirScanType scanType; +} tCsrFreqScanInfo; + +typedef struct sSirSmeAssocIndToUpperLayerCnf { + uint16_t messageType; /* eWNI_SME_ASSOC_CNF */ + uint16_t length; + uint8_t sessionId; + tSirResultCodes statusCode; + tSirMacAddr bssId; /* Self BSSID */ + tSirMacAddr peerMacAddr; + uint16_t aid; + tSirMacAddr alternateBssId; + uint8_t alternateChannelId; + uint8_t wmmEnabledSta; /* set to true if WMM enabled STA */ + tSirRSNie rsnIE; /* RSN IE received from peer */ + tSirWAPIie wapiIE; /* WAPI IE received from peer */ + tSirAddie addIE; /* this can be WSC and/or P2P IE */ + uint8_t reassocReq; /* set to true if reassoc */ + /* Timing and fine Timing measurement capability clubbed together */ + uint8_t timingMeasCap; + tSirSmeChanInfo chan_info; + uint8_t target_channel; +} tSirSmeAssocIndToUpperLayerCnf, *tpSirSmeAssocIndToUpperLayerCnf; + +typedef struct tagCsrSummaryStatsInfo { + uint32_t snr; + uint32_t rssi; + uint32_t retry_cnt[4]; + uint32_t multiple_retry_cnt[4]; + uint32_t tx_frm_cnt[4]; + /* uint32_t num_rx_frm_crc_err; same as rx_error_cnt */ + /* uint32_t num_rx_frm_crc_ok; same as rx_frm_cnt */ + uint32_t rx_frm_cnt; + uint32_t frm_dup_cnt; + uint32_t fail_cnt[4]; + uint32_t rts_fail_cnt; + uint32_t ack_fail_cnt; + uint32_t rts_succ_cnt; + uint32_t rx_discard_cnt; + uint32_t rx_error_cnt; + uint32_t tx_byte_cnt; + +} tCsrSummaryStatsInfo; + +typedef struct tagCsrGlobalClassAStatsInfo { + uint32_t rx_frag_cnt; + uint32_t promiscuous_rx_frag_cnt; + /* uint32_t rx_fcs_err; */ + uint32_t rx_input_sensitivity; + uint32_t max_pwr; + /* uint32_t default_pwr; */ + uint32_t sync_fail_cnt; + uint32_t tx_rate; + /* mcs index for HT20 and HT40 rates */ + uint32_t mcs_index; + /* to diff between HT20 & HT40 rates;short & long guard interval */ + uint32_t tx_rate_flags; + +} tCsrGlobalClassAStatsInfo; + +typedef struct tagCsrGlobalClassBStatsInfo { + uint32_t uc_rx_wep_unencrypted_frm_cnt; + uint32_t uc_rx_mic_fail_cnt; + uint32_t uc_tkip_icv_err; + uint32_t uc_aes_ccmp_format_err; + uint32_t uc_aes_ccmp_replay_cnt; + uint32_t uc_aes_ccmp_decrpt_err; + uint32_t uc_wep_undecryptable_cnt; + uint32_t uc_wep_icv_err; + uint32_t uc_rx_decrypt_succ_cnt; + uint32_t uc_rx_decrypt_fail_cnt; + uint32_t mcbc_rx_wep_unencrypted_frm_cnt; + uint32_t mcbc_rx_mic_fail_cnt; + uint32_t mcbc_tkip_icv_err; + uint32_t mcbc_aes_ccmp_format_err; + uint32_t mcbc_aes_ccmp_replay_cnt; + uint32_t mcbc_aes_ccmp_decrpt_err; + uint32_t mcbc_wep_undecryptable_cnt; + uint32_t mcbc_wep_icv_err; + uint32_t mcbc_rx_decrypt_succ_cnt; + uint32_t mcbc_rx_decrypt_fail_cnt; + +} tCsrGlobalClassBStatsInfo; + +typedef struct tagCsrGlobalClassCStatsInfo { + uint32_t rx_amsdu_cnt; + uint32_t rx_ampdu_cnt; + uint32_t tx_20_frm_cnt; + uint32_t rx_20_frm_cnt; + uint32_t rx_mpdu_in_ampdu_cnt; + uint32_t ampdu_delimiter_crc_err; + +} tCsrGlobalClassCStatsInfo; + +typedef struct tagCsrGlobalClassDStatsInfo { + uint32_t tx_uc_frm_cnt; + uint32_t tx_mc_frm_cnt; + uint32_t tx_bc_frm_cnt; + uint32_t rx_uc_frm_cnt; + uint32_t rx_mc_frm_cnt; + uint32_t rx_bc_frm_cnt; + uint32_t tx_uc_byte_cnt[4]; + uint32_t tx_mc_byte_cnt; + uint32_t tx_bc_byte_cnt; + uint32_t rx_uc_byte_cnt[4]; + uint32_t rx_mc_byte_cnt; + uint32_t rx_bc_byte_cnt; + uint32_t rx_byte_cnt; + uint32_t num_rx_bytes_crc_ok; + uint32_t rx_rate; + +} tCsrGlobalClassDStatsInfo; + +typedef struct tagCsrPerStaStatsInfo { + uint32_t tx_frag_cnt[4]; + uint32_t tx_ampdu_cnt; + uint32_t tx_mpdu_in_ampdu_cnt; +} tCsrPerStaStatsInfo; + +/** + * struct csr_per_chain_rssi_stats_info - stores chain rssi + * @rssi: array containing rssi for all chains + * @peer_mac_addr: peer mac address + */ +struct csr_per_chain_rssi_stats_info { + int8_t rssi[NUM_CHAINS_MAX]; + tSirMacAddr peer_mac_addr; +}; + +typedef struct tagCsrRoamSetKey { + eCsrEncryptionType encType; + tAniKeyDirection keyDirection; /* Tx, Rx or Tx-and-Rx */ + struct qdf_mac_addr peerMac; /* Peer MAC. ALL 1's for group key */ + uint8_t paeRole; /* 0 for supplicant */ + uint8_t keyId; /* Key index */ + uint16_t keyLength; /* Number of bytes containing the key in pKey */ + uint8_t Key[CSR_MAX_KEY_LEN]; + uint8_t keyRsc[CSR_MAX_RSC_LEN]; +} tCsrRoamSetKey; + +typedef struct tagCsrRoamRemoveKey { + eCsrEncryptionType encType; + struct qdf_mac_addr peerMac; /* Peer MAC. ALL 1's for group key */ + uint8_t keyId; /* key index */ +} tCsrRoamRemoveKey; + +#ifdef FEATURE_WLAN_TDLS + +typedef struct tagCsrLinkEstablishParams { + tSirMacAddr peerMac; + uint8_t uapsdQueues; + uint8_t maxSp; + uint8_t isBufSta; + uint8_t isOffChannelSupported; + uint8_t isResponder; + uint8_t supportedChannelsLen; + uint8_t supportedChannels[SIR_MAC_MAX_SUPP_CHANNELS]; + uint8_t supportedOperClassesLen; + uint8_t supportedOperClasses[CDS_MAX_SUPP_OPER_CLASSES]; + uint8_t qos; +} tCsrTdlsLinkEstablishParams; + +typedef struct tagCsrTdlsSendMgmt { + tSirMacAddr peerMac; + uint8_t frameType; + uint8_t dialog; + uint16_t statusCode; + uint8_t responder; + uint32_t peerCapability; + uint8_t *buf; + uint8_t len; + enum sir_wifi_traffic_ac ac; +} tCsrTdlsSendMgmt; +#endif + +typedef void *tScanResultHandle; + +typedef enum { + REASSOC = 0, + FASTREASSOC = 1, + CONNECT_CMD_USERSPACE = 2, +} handoff_src; + +typedef struct tagCsrHandoffRequest { + struct qdf_mac_addr bssid; + uint8_t channel; + uint8_t src; /* To check if its a REASSOC or a FASTREASSOC IOCTL */ +} tCsrHandoffRequest; + +#ifdef FEATURE_WLAN_ESE +typedef struct tagCsrEseBeaconReqParams { + uint16_t measurementToken; + uint8_t channel; + uint8_t scanMode; + uint16_t measurementDuration; +} tCsrEseBeaconReqParams, *tpCsrEseBeaconReqParams; + +typedef struct tagCsrEseBeaconReq { + uint8_t numBcnReqIe; + tCsrEseBeaconReqParams bcnReq[SIR_ESE_MAX_MEAS_IE_REQS]; +} tCsrEseBeaconReq, *tpCsrEseBeaconReq; +#endif /* FEATURE_WLAN_ESE */ + +struct tagCsrDelStaParams { + struct qdf_mac_addr peerMacAddr; + uint16_t reason_code; + uint8_t subtype; +}; + +/** + * struct wep_update_default_key_idx: wep default key index structure + * @session_id: session ID for the connection session + * @default_idx: default key index for wep + * + * structure includes sesssion id for connection and default key + * index used for wep + */ +struct wep_update_default_key_idx { + uint8_t session_id; + uint8_t default_idx; +}; + +/* + * NOTE: p2 is the second context pass in for the caller + * NOTE: what if callback is called before requester gets the scanId?? + */ +typedef QDF_STATUS (*csr_scan_completeCallback)(tHalHandle, void *p2, + uint8_t sessionId, + uint32_t scanID, + eCsrScanStatus status); +typedef QDF_STATUS (*csr_roam_completeCallback)(void *pContext, + tCsrRoamInfo * pParam, + uint32_t roamId, + eRoamCmdStatus roamStatus, + eCsrRoamResult roamResult); +typedef QDF_STATUS (*csr_roamSessionCloseCallback)(void *pContext); + +#define CSR_IS_START_IBSS(pProfile) (eCSR_BSS_TYPE_START_IBSS == \ + (pProfile)->BSSType) +#define CSR_IS_JOIN_TO_IBSS(pProfile) (eCSR_BSS_TYPE_IBSS == \ + (pProfile)->BSSType) +#define CSR_IS_IBSS(pProfile) (CSR_IS_START_IBSS(pProfile) || \ + CSR_IS_JOIN_TO_IBSS(pProfile)) +#define CSR_IS_INFRASTRUCTURE(pProfile) (eCSR_BSS_TYPE_INFRASTRUCTURE == \ + (pProfile)->BSSType) +#define CSR_IS_ANY_BSS_TYPE(pProfile) (eCSR_BSS_TYPE_ANY == \ + (pProfile)->BSSType) +#define CSR_IS_INFRA_AP(pProfile) (eCSR_BSS_TYPE_INFRA_AP == \ + (pProfile)->BSSType) +#ifdef WLAN_FEATURE_NAN_DATAPATH +#define CSR_IS_NDI(profile) (eCSR_BSS_TYPE_NDI == (profile)->BSSType) +#else +#define CSR_IS_NDI(profile) (false) +#endif +#define CSR_IS_CONN_INFRA_AP(pProfile) (eCSR_BSS_TYPE_INFRA_AP == \ + (pProfile)->BSSType) +#ifdef WLAN_FEATURE_NAN_DATAPATH +#define CSR_IS_CONN_NDI(profile) (eCSR_BSS_TYPE_NDI == (profile)->BSSType) +#else +#define CSR_IS_CONN_NDI(profile) (false) +#endif + +#define CSR_IS_CLOSE_SESSION_COMMAND(pCommand) \ + ((pCommand)->command == eSmeCommandDelStaSession) + +QDF_STATUS csr_set_channels(tHalHandle hHal, tCsrConfigParam *pParam); + +QDF_STATUS csr_set_reg_info(tHalHandle hHal, uint8_t *apCntryCode); + +/* enum to string conversion for debug output */ +const char *get_e_roam_cmd_status_str(eRoamCmdStatus val); +const char *get_e_csr_roam_result_str(eCsrRoamResult val); +QDF_STATUS csr_set_phy_mode(tHalHandle hHal, uint32_t phyMode, eCsrBand eBand, + bool *pfRestartNeeded); +typedef void (*csr_roamLinkQualityIndCallback) + (eCsrRoamLinkQualityInd ind, void *pContext); +typedef void (*tCsrStatsCallback)(void *stats, void *pContext); +typedef void (*tCsrRssiCallback)(int8_t rssi, uint32_t staId, void *pContext); + +#ifdef FEATURE_WLAN_ESE +typedef void (*tCsrTsmStatsCallback)(tAniTrafStrmMetrics tsmMetrics, + uint32_t staId, void *pContext); +#endif /* FEATURE_WLAN_ESE */ +typedef void (*tCsrSnrCallback)(int8_t snr, uint32_t staId, void *pContext); +#ifdef WLAN_FEATURE_HOST_ROAM +QDF_STATUS csr_roam_issue_ft_preauth_req(tHalHandle hHal, uint32_t sessionId, + tpSirBssDescription pBssDescription); +#else +static inline QDF_STATUS csr_roam_issue_ft_preauth_req(tHalHandle hHal, + uint32_t sessionId, tpSirBssDescription pBssDescription) +{ + return QDF_STATUS_E_NOSUPPORT; +} +#endif +QDF_STATUS csr_set_band(tHalHandle hHal, uint8_t sessionId, eCsrBand eBand); +eCsrBand csr_get_current_band(tHalHandle hHal); +typedef void (*csr_readyToSuspendCallback)(void *pContext, bool suspended); +#ifdef WLAN_FEATURE_EXTWOW_SUPPORT +typedef void (*csr_readyToExtWoWCallback)(void *pContext, bool status); +#endif +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +QDF_STATUS csr_roam_issue_ft_roam_offload_synch(tHalHandle hHal, + uint32_t sessionId, tSirBssDescription *pBssDescription); +#endif +typedef void (*tCsrLinkStatusCallback)(uint8_t status, void *pContext); +#ifdef FEATURE_WLAN_TDLS +void csr_roam_fill_tdls_info(tpAniSirGlobal mac_ctx, tCsrRoamInfo *roam_info, + tpSirSmeJoinRsp join_rsp); +#else +static inline void csr_roam_fill_tdls_info(tpAniSirGlobal mac_ctx, tCsrRoamInfo *roam_info, + tpSirSmeJoinRsp join_rsp) +{} +#endif +void csr_packetdump_timer_stop(void); + +#endif diff --git a/drivers/staging/qcacld-3.0/core/sme/inc/csr_internal.h b/drivers/staging/qcacld-3.0/core/sme/inc/csr_internal.h new file mode 100644 index 0000000000000000000000000000000000000000..834aefdc661a1784988e7ded5e15872de9e227fb --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/sme/inc/csr_internal.h @@ -0,0 +1,1452 @@ +/* + * Copyright (c) 2011-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * \file csr_internal.h + * + * Define internal data structure for MAC. + */ +#ifndef CSRINTERNAL_H__ +#define CSRINTERNAL_H__ + +#include "qdf_status.h" +#include "qdf_lock.h" + +#include "qdf_mc_timer.h" +#include "csr_support.h" +#include "cds_reg_service.h" + +#include "csr_neighbor_roam.h" + +#include "sir_types.h" + +#define CSR_MAX_STA (HAL_NUM_STA) + +/* define scan return criteria. LIM should use these define as well */ +#define CSR_SCAN_RETURN_AFTER_ALL_CHANNELS (0) +#define CSR_SCAN_RETURN_AFTER_FIRST_MATCH (0x01) +#define CSR_NUM_RSSI_CAT 15 +#define CSR_ROAM_SCAN_CHANNEL_SWITCH_TIME 3 + +/* session ID invalid */ +#define CSR_SESSION_ID_INVALID 0xFF +/* No of sessions to be supported, and a session is for Infra, IBSS or BT-AMP */ +#define CSR_ROAM_SESSION_MAX 5 +#define CSR_IS_SESSION_VALID(pMac, sessionId) \ + (((sessionId) < CSR_ROAM_SESSION_MAX) && \ + ((pMac)->roam.roamSession[(sessionId)].sessionActive)) + +#define CSR_GET_SESSION(pMac, sessionId) \ + ( \ + (sessionId < CSR_ROAM_SESSION_MAX) ? \ + (&(pMac)->roam.roamSession[(sessionId)]) : NULL \ + ) + +#define CSR_IS_SESSION_ANY(sessionId) (sessionId == SME_SESSION_ID_ANY) +#define CSR_MAX_NUM_COUNTRY_CODE 100 +#define CSR_IS_DFS_CH_ROAM_ALLOWED(mac_ctx) \ + ( \ + (((mac_ctx)->roam.configParam.allowDFSChannelRoam) ? true : false) \ + ) +#define CSR_IS_SELECT_5GHZ_MARGIN(pMac) \ + ( \ + (((pMac)->roam.configParam.nSelect5GHzMargin) ? true : false) \ + ) +#define CSR_IS_SELECT_5G_PREFERRED(pMac) \ + ( \ + (((pMac)->roam.configParam.roam_params.is_5g_pref_enabled) ? \ + true : false) \ + ) +#define CSR_IS_ROAM_PREFER_5GHZ(pMac) \ + ( \ + (((pMac)->roam.configParam.nRoamPrefer5GHz) ? true : false) \ + ) +#define CSR_IS_ROAM_INTRA_BAND_ENABLED(pMac) \ + ( \ + (((pMac)->roam.configParam.nRoamIntraBand) ? true : false) \ + ) +#define CSR_IS_FASTROAM_IN_CONCURRENCY_INI_FEATURE_ENABLED(pMac) \ + ( \ + (((pMac)->roam.configParam.bFastRoamInConIniFeatureEnabled) ? \ + true : false) \ + ) +#define CSR_IS_CHANNEL_24GHZ(chnNum) \ + (((chnNum) > 0) && ((chnNum) <= 14)) +/* Support for "Fast roaming" (i.e., ESE, LFR, or 802.11r.) */ +#define CSR_BG_SCAN_OCCUPIED_CHANNEL_LIST_LEN 15 + +/* Used to determine what to set to the WNI_CFG_DOT11_MODE */ +typedef enum { + eCSR_CFG_DOT11_MODE_ABG, + eCSR_CFG_DOT11_MODE_11A, + eCSR_CFG_DOT11_MODE_11B, + eCSR_CFG_DOT11_MODE_11G, + eCSR_CFG_DOT11_MODE_11N, + eCSR_CFG_DOT11_MODE_11AC, + eCSR_CFG_DOT11_MODE_11G_ONLY, + eCSR_CFG_DOT11_MODE_11N_ONLY, + eCSR_CFG_DOT11_MODE_11AC_ONLY, + /* This value can never set to CFG. Its for CSR's internal use */ + eCSR_CFG_DOT11_MODE_AUTO, +} eCsrCfgDot11Mode; + +typedef enum etCsrRoamCommands { + eCsrRoamNoCommand, + eCsrRoamCommandScan, + eCsrRoamCommandRoam, + eCsrRoamCommandWmStatusChange, + eCsrRoamCommandSetKey, + eCsrRoamCommandRemoveKey, + +} eCsrRoamCommands; + +typedef enum { + eCsrScanOther = 1, + eCsrScanLostLink1, + eCsrScanLostLink2, + eCsrScanLostLink3, + eCsrScanLostLink4, + eCsrScan11d1, /* First 11d scan */ + eCsrScan11d2, /* First 11d scan has failed */ + eCsrScan11dDone, /* 11d scan succeed, try rest of the channels */ + eCsrScanUserRequest, + eCsrScanForSsid, + eCsrScanIdleScan, + eCsrScanProbeBss, /* direct prb on entry from candidate list-HO */ + eCsrScanAbortNormalScan,/* aborting a normal scan */ + eCsrScanP2PFindPeer, + eCsrScanCandidateFound, +} eCsrScanReason; + +typedef enum { + /* Roaming because we've not established the initial connection. */ + eCsrNoConnection, + /* roaming because LIM reported a cap change in the associated AP. */ + eCsrCapsChange, + /* roaming because someone asked us to Disassoc & stay disassociated. */ + eCsrForcedDisassoc, + /* roaming because an 802.11 request was issued to the driver. */ + eCsrHddIssued, + /* roaming because we lost link to an associated AP */ + eCsrLostLink1, + eCsrLostLink2, + eCsrLostLink3, + /* roaming because we need to force a Disassoc due to MIC failure */ + eCsrForcedDisassocMICFailure, + eCsrHddIssuedReassocToSameAP, + eCsrSmeIssuedReassocToSameAP, + eCsrSmeIssuedReassocToDiffAP, + /* roaming becuase someone asked us to deauth and stay disassociated. */ + eCsrForcedDeauth, + /* will be issued by Handoff logic to disconect from current AP */ + eCsrSmeIssuedDisassocForHandoff, + /* will be issued by Handoff logic to join a new AP with same profile */ + eCsrSmeIssuedAssocToSimilarAP, + /* ibss jointimer fired before any peer showedup, so shutdown network */ + eCsrSmeIssuedIbssJoinFailure, + eCsrForcedIbssLeave, + eCsrStopBss, + eCsrSmeIssuedFTReassoc, + eCsrForcedDisassocSta, + eCsrForcedDeauthSta, + eCsrPerformPreauth, + eCsrLostLink1Abort, + eCsrLostLink2Abort, + eCsrLostLink3Abort, +} eCsrRoamReason; + +typedef enum { + eCSR_ROAM_SUBSTATE_NONE = 0, + eCSR_ROAM_SUBSTATE_START_BSS_REQ, + eCSR_ROAM_SUBSTATE_JOIN_REQ, + eCSR_ROAM_SUBSTATE_REASSOC_REQ, + eCSR_ROAM_SUBSTATE_DISASSOC_REQ, + eCSR_ROAM_SUBSTATE_STOP_BSS_REQ, + /* Continue the current roam command after disconnect */ + eCSR_ROAM_SUBSTATE_DISCONNECT_CONTINUE_ROAMING, + eCSR_ROAM_SUBSTATE_AUTH_REQ, + eCSR_ROAM_SUBSTATE_CONFIG, + eCSR_ROAM_SUBSTATE_DEAUTH_REQ, + eCSR_ROAM_SUBSTATE_DISASSOC_NOTHING_TO_JOIN, + eCSR_ROAM_SUBSTATE_DISASSOC_REASSOC_FAILURE, + eCSR_ROAM_SUBSTATE_DISASSOC_FORCED, + eCSR_ROAM_SUBSTATE_WAIT_FOR_KEY, + eCSR_ROAM_SUBSTATE_DISASSOC_HANDOFF, + eCSR_ROAM_SUBSTATE_JOINED_NO_TRAFFIC, + eCSR_ROAM_SUBSTATE_JOINED_NON_REALTIME_TRAFFIC, + eCSR_ROAM_SUBSTATE_JOINED_REALTIME_TRAFFIC, + eCSR_ROAM_SUBSTATE_DISASSOC_STA_HAS_LEFT, + /* max is 15 unless the bitfield is expanded... */ +} eCsrRoamSubState; + +typedef enum { + eCSR_ROAMING_STATE_STOP = 0, + eCSR_ROAMING_STATE_IDLE, + eCSR_ROAMING_STATE_JOINING, + eCSR_ROAMING_STATE_JOINED, +} eCsrRoamState; + +typedef enum { + eCsrContinueRoaming, + eCsrStopRoaming, + eCsrStartIbss, + eCsrStartIbssSameIbss, + eCsrReassocToSelfNoCapChange, + eCsrStopRoamingDueToConcurrency, + +} eCsrJoinState; + +typedef enum { + eCsrNotRoaming, + eCsrLostlinkRoamingDisassoc, + eCsrLostlinkRoamingDeauth, + eCsrDynamicRoaming, + eCsrReassocRoaming, +} eCsrRoamingReason; + +typedef enum { + eCsrDisassociated, + eCsrDeauthenticated +} eCsrRoamWmStatusChangeTypes; + +typedef enum { + eCsrSummaryStats = 0, + eCsrGlobalClassAStats, + eCsrGlobalClassBStats, + eCsrGlobalClassCStats, + eCsrGlobalClassDStats, + eCsrPerStaStats, + csr_per_chain_rssi_stats, + eCsrMaxStats +} eCsrRoamStatsClassTypes; + +#ifdef FEATURE_WLAN_DIAG_SUPPORT +typedef enum { + eCSR_WLAN_STATUS_CONNECT = 0, + eCSR_WLAN_STATUS_DISCONNECT +} eCsrDiagWlanStatusEventSubtype; + +typedef enum { + eCSR_REASON_UNSPECIFIED = 0, + eCSR_REASON_USER_REQUESTED, + eCSR_REASON_MIC_ERROR, + eCSR_REASON_DISASSOC, + eCSR_REASON_DEAUTH, + eCSR_REASON_HANDOFF, + eCSR_REASON_ROAM_SYNCH_IND, + eCSR_REASON_ROAM_SYNCH_CNF, + eCSR_REASON_ROAM_HO_FAIL, + +} eCsrDiagWlanStatusEventReason; + +/** + * enum eCSR_WLAN_DIAG_EVENT_TYPE - enum for DIAG events + * @eCSR_EVENT_SCAN_COMPLETE - scan complete + * @eCSR_EVENT_SCAN_RES_FOUND - scan result found + */ +typedef enum { + eCSR_EVENT_TYPE_INVALID = 0, + eCSR_EVENT_SCAN_COMPLETE = 64, + eCSR_EVENT_SCAN_RES_FOUND = 65, +} eCSR_WLAN_DIAG_EVENT_TYPE; + +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + +typedef struct tagCsrChannel { + uint8_t numChannels; + uint8_t channelList[WNI_CFG_VALID_CHANNEL_LIST_LEN]; +} tCsrChannel; + +typedef struct tagScanProfile { + uint32_t minChnTime; + uint32_t maxChnTime; + /* In units of milliseconds, ignored when not connected */ + uint32_t restTime; + /* In units of milliseconds, ignored when not connected */ + uint32_t min_rest_time; + /* In units of milliseconds, ignored when not connected */ + uint32_t idle_time; + uint32_t numOfChannels; + uint8_t *pChannelList; + tSirScanType scanType; + eCsrRoamBssType bssType; + uint8_t ssid[WNI_CFG_SSID_LEN]; + uint8_t bReturnAfter1stMatch; + uint8_t fUniqueResult; + uint8_t freshScan; + struct qdf_mac_addr bssid; +} tScanProfile; + +typedef struct tagBssConfigParam { + eCsrMediaAccessType qosType; + tSirMacSSid SSID; + uint32_t uRTSThresh; + uint32_t uDeferThresh; + eCsrCfgDot11Mode uCfgDot11Mode; + eCsrBand eBand; + uint8_t standardRate[CSR_DOT11_SUPPORTED_RATES_MAX]; + uint8_t extendedRate[CSR_DOT11_EXTENDED_SUPPORTED_RATES_MAX]; + eCsrExposedTxRate txRate; + tAniAuthType authType; + eCsrEncryptionType encType; + uint32_t uShortSlotTime; + uint32_t uHTSupport; + uint32_t uPowerLimit; + uint32_t uHeartBeatThresh; + uint32_t uJoinTimeOut; + tSirMacCapabilityInfo BssCap; + bool f11hSupport; + ePhyChanBondState cbMode; +} tBssConfigParam; + +typedef struct tagCsrRoamStartBssParams { + tSirMacSSid ssId; + + /* + * This is the BSSID for the party we want to + * join (only use for IBSS or WDS). + */ + struct qdf_mac_addr bssid; + tSirNwType sirNwType; + ePhyChanBondState cbMode; + tSirMacRateSet operationalRateSet; + tSirMacRateSet extendedRateSet; + uint8_t operationChn; + struct ch_params_s ch_params; + eCsrCfgDot11Mode uCfgDot11Mode; + uint8_t privacy; + bool fwdWPSPBCProbeReq; + bool protEnabled; + bool obssProtEnabled; + tAniAuthType authType; + uint16_t beaconInterval; /* If this is 0, SME'll fill in for caller */ + uint16_t ht_protection; + uint32_t dtimPeriod; + uint8_t ApUapsdEnable; + uint8_t ssidHidden; + uint8_t wps_state; + enum tQDF_ADAPTER_MODE bssPersona; + uint16_t nRSNIELength; /* If 0, pRSNIE is ignored. */ + uint8_t *pRSNIE; /* If not null, it has IE byte stream for RSN */ + /* Flag used to indicate update beaconInterval */ + bool updatebeaconInterval; +#ifdef WLAN_FEATURE_11W + bool mfpCapable; + bool mfpRequired; +#endif + tSirAddIeParams addIeParams; + uint8_t sap_dot11mc; + uint8_t beacon_tx_rate; +} tCsrRoamStartBssParams; + +typedef struct tagScanCmd { + uint32_t scanID; + csr_scan_completeCallback callback; + void *pContext; + eCsrScanReason reason; + eCsrRoamState lastRoamState[CSR_ROAM_SESSION_MAX]; + tCsrRoamProfile *pToRoamProfile; + /* this is the ID related to the pToRoamProfile */ + uint32_t roamId; + union { + tCsrScanRequest scanRequest; + /* tCsrBGScanRequest bgScanRequest is no longer used */ + } u; + /* This flag will be set while aborting the scan due to band change */ + eCsrAbortReason abort_scan_indication; + qdf_mc_timer_t csr_scan_timer; +} tScanCmd; + +typedef struct tagRoamCmd { + uint32_t roamId; + eCsrRoamReason roamReason; + tCsrRoamProfile roamProfile; + tScanResultHandle hBSSList; /* BSS list fits the profile */ + /* + * point to the current BSS in the list that is roaming. + * It starts from head to tail + * */ + tListElem *pRoamBssEntry; + tSirBssDescription *pLastRoamBss; /* the last BSS we try and failed */ + bool fReleaseBssList; /* whether to free hBSSList */ + bool fReleaseProfile; /* whether to free roamProfile */ + bool fReassoc; /* whether this cmd is for reassoc */ + /* whether pMac->roam.pCurRoamProfile needs to be updated */ + bool fUpdateCurRoamProfile; + /* + * this is for CSR internal used only. And it should not be assigned + * when creating the command. This causes the roam cmd not todo anything + */ + bool fReassocToSelfNoCapChange; + + bool fStopWds; + tSirMacAddr peerMac; + tSirMacReasonCodes reason; + eCsrRoamDisconnectReason disconnect_reason; +} tRoamCmd; + +typedef struct tagSetKeyCmd { + uint32_t roamId; + eCsrEncryptionType encType; + eCsrAuthType authType; + tAniKeyDirection keyDirection; /* Tx, Rx or Tx-and-Rx */ + struct qdf_mac_addr peermac; /* Peer's MAC address. ALL 1's for group key */ + uint8_t paeRole; /* 0 for supplicant */ + uint8_t keyId; /* Kye index */ + uint8_t keyLength; /* Number of bytes containing the key in pKey */ + uint8_t Key[CSR_MAX_KEY_LEN]; + uint8_t keyRsc[CSR_MAX_RSC_LEN]; +} tSetKeyCmd; + +typedef struct tagWmStatusChangeCmd { + eCsrRoamWmStatusChangeTypes Type; + union { + tSirSmeDeauthInd DeauthIndMsg; + tSirSmeDisassocInd DisassocIndMsg; + } u; + +} tWmStatusChangeCmd; + +typedef struct tagAddStaForSessionCmd { + /* Session self mac addr */ + tSirMacAddr selfMacAddr; + enum tQDF_ADAPTER_MODE currDeviceMode; + uint32_t type; + uint32_t subType; + uint8_t sessionId; +} tAddStaForSessionCmd; + +typedef struct tagDelStaForSessionCmd { + /* Session self mac addr */ + tSirMacAddr selfMacAddr; + csr_roamSessionCloseCallback callback; + void *pContext; +} tDelStaForSessionCmd; + +/* This structure represents one scan request */ +typedef struct tagCsrCmd { + tListElem Link; + eCsrRoamCommands command; + uint8_t sessionId; /* Session ID for this command */ + union { + tScanCmd scanCmd; + tRoamCmd roamCmd; + tWmStatusChangeCmd wmStatusChangeCmd; + tSetKeyCmd setKeyCmd; + tAddStaForSessionCmd addStaSessionCmd; + tDelStaForSessionCmd delStaSessionCmd; + } u; +} tCsrCmd; + +typedef struct tagCsr11rConfig { + bool IsFTResourceReqSupported; +} tCsr11rConfig; + +typedef struct tagCsrNeighborRoamConfig { + uint32_t nNeighborScanTimerPeriod; + uint8_t nNeighborLookupRssiThreshold; + uint16_t nNeighborScanMinChanTime; + uint16_t nNeighborScanMaxChanTime; + sCsrChannel neighborScanChanList; + uint8_t nMaxNeighborRetries; + uint16_t nNeighborResultsRefreshPeriod; + uint16_t nEmptyScanRefreshPeriod; + uint8_t nOpportunisticThresholdDiff; + uint8_t nRoamRescanRssiDiff; + uint8_t nRoamBmissFirstBcnt; + uint8_t nRoamBmissFinalBcnt; + uint8_t nRoamBeaconRssiWeight; + uint8_t delay_before_vdev_stop; + uint32_t nhi_rssi_scan_max_count; + uint32_t nhi_rssi_scan_rssi_delta; + uint32_t nhi_rssi_scan_delay; + int32_t nhi_rssi_scan_rssi_ub; +} tCsrNeighborRoamConfig; + +typedef struct tagCsrConfig { + uint32_t agingCount; + uint32_t FragmentationThreshold; + uint32_t channelBondingMode24GHz; + uint32_t channelBondingMode5GHz; + uint32_t RTSThreshold; + eCsrPhyMode phyMode; + eCsrCfgDot11Mode uCfgDot11Mode; + eCsrBand eBand; + uint32_t HeartbeatThresh50; + uint32_t HeartbeatThresh24; + eCsrCBChoice cbChoice; + eCsrBand bandCapability; /* indicate hw capability */ + eCsrRoamWmmUserModeType WMMSupportMode; + bool Is11eSupportEnabled; + bool Is11dSupportEnabled; + bool Is11dSupportEnabledOriginal; + bool Is11hSupportEnabled; + bool shortSlotTime; + bool ProprietaryRatesEnabled; + bool fenableMCCMode; + bool mcc_rts_cts_prot_enable; + bool mcc_bcast_prob_resp_enable; + uint16_t TxRate; + uint8_t fAllowMCCGODiffBI; + uint8_t AdHocChannel24; + uint8_t AdHocChannel5G; + /* each RSSI category has one value */ + uint32_t BssPreferValue[CSR_NUM_RSSI_CAT]; + int RSSICat[CSR_NUM_RSSI_CAT]; + uint8_t bCatRssiOffset; /* to set RSSI difference for each category */ + /* + * Whether to limit the channels to the ones set in Csr11dInfo. + * If true, the opertaional channels are limited to the default channel + * list. It is an "AND" operation between the default channels and + * the channels in the 802.11d IE. + */ + /* Country Code Priority */ + bool fSupplicantCountryCodeHasPriority; + + uint16_t vccRssiThreshold; + uint32_t vccUlMacLossThreshold; + + uint32_t nPassiveMinChnTime; /* in units of milliseconds */ + uint32_t nPassiveMaxChnTime; /* in units of milliseconds */ + uint32_t nActiveMinChnTime; /* in units of milliseconds */ + uint32_t nActiveMaxChnTime; /* in units of milliseconds */ + + uint32_t nInitialDwellTime; /* in units of milliseconds */ + bool initial_scan_no_dfs_chnl; +#ifdef WLAN_AP_STA_CONCURRENCY + uint32_t nPassiveMinChnTimeConc;/* in units of milliseconds */ + uint32_t nPassiveMaxChnTimeConc;/* in units of milliseconds */ + uint32_t nActiveMinChnTimeConc; /* in units of milliseconds */ + uint32_t nActiveMaxChnTimeConc; /* in units of milliseconds */ + uint32_t nRestTimeConc; /* in units of milliseconds */ + /* In units of milliseconds */ + uint32_t min_rest_time_conc; + /* In units of milliseconds */ + uint32_t idle_time_conc; + + /* number of channels combined for Sta in each split scan operation */ + uint8_t nNumStaChanCombinedConc; + /* number of channels combined for P2P in each split scan operation */ + uint8_t nNumP2PChanCombinedConc; +#endif + /* + * in dBm, the max TX power. The actual TX power is the lesser of this + * value & 11d. If 11d is disable, the lesser of this & default setting. + */ + uint8_t nTxPowerCap; + bool allow_tpc_from_ap; + uint32_t statsReqPeriodicity; /* stats req freq while in fullpower */ + uint32_t statsReqPeriodicityInPS;/* stats req freq while in powersave */ + uint32_t dtimPeriod; + bool ssidHidden; + tCsr11rConfig csr11rConfig; + uint8_t isFastRoamIniFeatureEnabled; + uint8_t MAWCEnabled; + uint8_t isRoamOffloadScanEnabled; + bool bFastRoamInConIniFeatureEnabled; +#ifdef FEATURE_WLAN_ESE + uint8_t isEseIniFeatureEnabled; +#endif + uint8_t isFastTransitionEnabled; + uint8_t RoamRssiDiff; + bool nRoamPrefer5GHz; + bool nRoamIntraBand; + bool isWESModeEnabled; + bool nRoamScanControl; + uint8_t nProbes; + uint16_t nRoamScanHomeAwayTime; + + tCsrNeighborRoamConfig neighborRoamConfig; + + /* + * Instead of Reassoc, send ADDTS/DELTS even when ACM is off for + * that AC This is mandated by WMM-AC certification + */ + bool addTSWhenACMIsOff; + bool fValidateList; + /* + * Remove this code once SLM_Sessionization is supported + * BMPS_WORKAROUND_NOT_NEEDED + */ + bool doBMPSWorkaround; + /* To enable scanning 2g channels twice on single scan req from HDD */ + bool fScanTwice; + uint32_t nVhtChannelWidth; + uint8_t enable_txbf_sap_mode; + uint8_t enable2x2; + bool enableVhtFor24GHz; + uint8_t enableVhtpAid; + uint8_t enableVhtGid; + uint8_t enableAmpduPs; + uint8_t enableHtSmps; + uint8_t htSmps; + bool send_smps_action; + uint8_t txLdpcEnable; + uint8_t rxLdpcEnable; + uint8_t disable_high_ht_mcs_2x2; + /* + * Enable/Disable heartbeat offload + */ + bool enableHeartBeatOffload; + uint8_t max_amsdu_num; + uint8_t nSelect5GHzMargin; + uint8_t isCoalesingInIBSSAllowed; +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH + uint8_t cc_switch_mode; +#endif + uint8_t allowDFSChannelRoam; +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + bool isRoamOffloadEnabled; +#endif + bool obssEnabled; + bool ignore_peer_erp_info; + uint8_t conc_custom_rule1; + uint8_t conc_custom_rule2; + uint8_t is_sta_connection_in_5gz_enabled; + struct roam_ext_params roam_params; + bool sendDeauthBeforeCon; +#ifdef FEATURE_WLAN_SCAN_PNO + bool pno_channel_prediction; + uint8_t top_k_num_of_channels; + uint8_t stationary_thresh; + enum wmi_dwelltime_adaptive_mode pnoscan_adaptive_dwell_mode; + uint32_t channel_prediction_full_scan; +#endif + bool early_stop_scan_enable; + int8_t early_stop_scan_min_threshold; + int8_t early_stop_scan_max_threshold; + uint32_t obss_width_interval; + uint32_t obss_active_dwelltime; + uint32_t obss_passive_dwelltime; + bool ignore_peer_ht_opmode; + bool enable_edca_params; + uint32_t edca_vo_cwmin; + uint32_t edca_vi_cwmin; + uint32_t edca_bk_cwmin; + uint32_t edca_be_cwmin; + uint32_t edca_vo_cwmax; + uint32_t edca_vi_cwmax; + uint32_t edca_bk_cwmax; + uint32_t edca_be_cwmax; + uint32_t edca_vo_aifs; + uint32_t edca_vi_aifs; + uint32_t edca_bk_aifs; + uint32_t edca_be_aifs; + bool enable_fatal_event; + bool vendor_vht_sap; + enum wmi_dwelltime_adaptive_mode scan_adaptive_dwell_mode; + enum wmi_dwelltime_adaptive_mode roamscan_adaptive_dwell_mode; + struct csr_sta_roam_policy_params sta_roam_policy; + uint32_t tx_aggregation_size; + uint32_t rx_aggregation_size; + struct wmi_per_roam_config per_roam_config; + bool enable_bcast_probe_rsp; + bool qcn_ie_support; + uint8_t fils_max_chan_guard_time; + uint16_t pkt_err_disconn_th; + bool is_bssid_hint_priority; + bool is_force_1x1; + uint16_t num_11b_tx_chains; + uint16_t num_11ag_tx_chains; + uint32_t scan_probe_repeat_time; + uint32_t scan_num_probes; +} tCsrConfig; + +typedef struct tagCsrChannelPowerInfo { + tListElem link; + uint8_t firstChannel; + uint8_t numChannels; + uint8_t txPower; + uint8_t interChannelOffset; +} tCsrChannelPowerInfo; + +typedef struct tagRoamJoinStatus { + tSirResultCodes statusCode; + /* + * this is set to unspecified if statusCode indicates timeout. + * Or it is the failed reason from the other BSS(per 802.11 spec) + */ + uint32_t reasonCode; + tSirMacAddr bssId; +} tCsrRoamJoinStatus; + +typedef struct tagCsrOsChannelMask { + uint8_t numChannels; + bool scanEnabled[WNI_CFG_VALID_CHANNEL_LIST_LEN]; + uint8_t channelList[WNI_CFG_VALID_CHANNEL_LIST_LEN]; +} tCsrOsChannelMask; + +typedef struct tagCsrVotes11d { + uint8_t votes; + uint8_t countryCode[WNI_CFG_COUNTRY_CODE_LEN]; +} tCsrVotes11d; + +typedef struct tagCsrScanStruct { + tScanProfile scanProfile; + tDblLinkList scanResultList; + tDblLinkList tempScanResults; + bool fScanEnable; + bool fFullScanIssued; +#ifdef WLAN_AP_STA_CONCURRENCY + qdf_mc_timer_t hTimerStaApConcTimer; +#endif + qdf_mc_timer_t hTimerIdleScan; + /* + * changes on every scan, it is used as a flag for whether 11d info is + * found on every scan + */ + uint8_t channelOf11dInfo; + uint8_t scanResultCfgAgingTime; + tSirScanType curScanType; + tCsrChannel channels11d; + struct channel_power defaultPowerTable[WNI_CFG_VALID_CHANNEL_LIST_LEN]; + uint32_t numChannelsDefault; + tCsrChannel base_channels; /* The channel base to work on */ + tDblLinkList channelPowerInfoList24; + tDblLinkList channelPowerInfoList5G; + uint32_t nLastAgeTimeOut; + uint32_t nAgingCountDown; + uint8_t countryCodeDefault[WNI_CFG_COUNTRY_CODE_LEN]; + uint8_t countryCodeCurrent[WNI_CFG_COUNTRY_CODE_LEN]; + uint8_t countryCode11d[WNI_CFG_COUNTRY_CODE_LEN]; + v_REGDOMAIN_t domainIdDefault; /* default regulatory domain */ + v_REGDOMAIN_t domainIdCurrent; /* current regulatory domain */ + + /* Bssid for current country code */ + struct qdf_mac_addr currentCountryBssid; + + int8_t currentCountryRSSI; /* RSSI for current country code */ + bool fCancelIdleScan; + uint8_t countryCodeCount; + /* counts for various advertized country codes */ + tCsrVotes11d votes11d[CSR_MAX_NUM_COUNTRY_CODE]; + /* + * in 11d IE from probe rsp or beacons of neighboring APs + * will use the most popular one (max count) + */ + uint8_t countryCodeElected[WNI_CFG_COUNTRY_CODE_LEN]; + bool fRestartIdleScan; + uint32_t nIdleScanTimeGap; + /* keep a track of channels to be scnned while in traffic condition */ + tCsrOsChannelMask osScanChannelMask; + uint16_t nBssLimit; /* the maximum number of BSS in scan cache */ + /* + * channelPowerInfoList24 has been seen corrupted. Set this flag to true + * trying to detect when it happens. Adding this into code because we + * can't reproduce it easily. We don't know when it happens. + */ + bool fValidateList; + /* + * Customer wants to start with an active scan based on the default + * country code. This optimization will minimize the driver load to + * association time. Based on this flag we will bypass the initial + * passive scan needed for 11d to determine the country code & domain + */ + bool fEnableBypass11d; + /* + * Customer wants to optimize the scan time. Avoiding scans(passive) + * on DFS channels while swipping through both bands can save some time + * (apprx 1.3 sec) + */ + uint8_t fEnableDFSChnlScan; + /* + * To enable/disable scanning only 2.4Ghz channels on first scan + */ + bool fFirstScanOnly2GChnl; + bool fDropScanCmd; /* true means we don't accept scan commands */ + +#ifdef WLAN_AP_STA_CONCURRENCY + tDblLinkList scanCmdPendingList; +#endif + /* This includes all channels on which candidate APs are found */ + tCsrChannel occupiedChannels[CSR_ROAM_SESSION_MAX]; + int8_t roam_candidate_count[CSR_ROAM_SESSION_MAX]; + int8_t inScanResultBestAPRssi; + csr_scan_completeCallback callback11dScanDone; + bool fcc_constraint; + uint8_t max_scan_count; + bool defer_update_channel_list; +} tCsrScanStruct; + +/* + * Save the connected information. This structure + connectedProfile + * should contain all information about the connection + */ +typedef struct tagRoamCsrConnectedInfo { + uint32_t nBeaconLength; + uint32_t nAssocReqLength; + uint32_t nAssocRspLength; + /* len of the parsed RIC resp IEs received in reassoc response */ + uint32_t nRICRspLength; +#ifdef FEATURE_WLAN_ESE + uint32_t nTspecIeLength; +#endif + /* + * Point to a buffer contain the beacon, assoc req, assoc rsp frame, in + * that order user needs to use nBeaconLength, nAssocReqLength, + * nAssocRspLength to desice where each frame starts and ends. + */ + uint8_t *pbFrames; + uint8_t staId; +} tCsrRoamConnectedInfo; + +typedef struct tagCsrLinkQualityIndInfo { + csr_roamLinkQualityIndCallback callback; + void *context; +} tCsrLinkQualityIndInfo; + +typedef struct tagCsrPeStatsReqInfo { + tListElem link; /* list links */ + uint32_t statsMask; + uint32_t periodicity; + bool rspPending; + qdf_mc_timer_t hPeStatsTimer; + bool timerRunning; + uint8_t staId; + uint8_t numClient; + tpAniSirGlobal pMac; + /* To remember if the peStats timer is stopped successfully or not */ + bool timerStopFailed; + uint8_t sessionId; + +} tCsrPeStatsReqInfo; + +typedef struct tagCsrStatsClientReqInfo { + tListElem link; /* list links */ + eCsrStatsRequesterType requesterId; + tCsrStatsCallback callback; + uint32_t periodicity; + void *pContext; + uint32_t statsMask; + tCsrPeStatsReqInfo *pPeStaEntry; + uint8_t staId; + qdf_mc_timer_t timer; + bool timerExpired; + tpAniSirGlobal pMac; /* TODO: Confirm this change BTAMP */ + uint8_t sessionId; +} tCsrStatsClientReqInfo; + +typedef struct tagCsrTlStatsReqInfo { + uint32_t periodicity; + bool timerRunning; + qdf_mc_timer_t hTlStatsTimer; + uint8_t numClient; +} tCsrTlStatsReqInfo; + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +typedef enum { + /* reassociation is done but couldn't finish security handshake */ + eSIR_ROAM_AUTH_STATUS_CONNECTED = 1, + /* roam successfully completed by firmware */ + eSIR_ROAM_AUTH_STATUS_AUTHENTICATED = 2, + /* unknown error */ + eSIR_ROAM_AUTH_STATUS_UNKNOWN = 0xff +} tCsrRoamOffloadAuthStatus; +typedef struct tagCsrRoamOffloadSynchStruct { + uint8_t roamedVdevId; /* vdevId after roaming */ + int8_t txMgmtPower; /* HAL fills in the tx power used for */ + uint8_t rssi; /* RSSI */ + uint8_t roamReason; /* Roam reason */ + uint8_t nss; /* no of spatial streams */ + uint16_t chainMask; /* chainmask */ + uint16_t smpsMode; /* smps.mode */ + struct qdf_mac_addr bssid; /* MAC address of roamed AP */ + tCsrRoamOffloadAuthStatus authStatus; /* auth status */ + uint8_t kck[SIR_KCK_KEY_LEN]; + uint8_t kek[SIR_KEK_KEY_LEN]; + uint8_t replay_ctr[SIR_REPLAY_CTR_LEN]; + tpSirBssDescription bss_desc_ptr; /*BSS descriptor*/ +} csr_roam_offload_synch_params; +#endif + +struct csr_roam_stored_profile { + uint32_t session_id; + tCsrRoamProfile profile; + tScanResultHandle bsslist_handle; + eCsrRoamReason reason; + uint32_t roam_id; + bool imediate_flag; + bool clear_flag; +}; + +typedef struct tagCsrRoamSession { + uint8_t sessionId; /* Session ID */ + bool sessionActive; /* true if it is used */ + + /* For BT-AMP station, this serve as BSSID for self-BSS. */ + struct qdf_mac_addr selfMacAddr; + + csr_roam_completeCallback callback; + void *pContext; + eCsrConnectState connectState; + tCsrRoamConnectedProfile connectedProfile; + tCsrRoamConnectedInfo connectedInfo; + tCsrRoamProfile *pCurRoamProfile; + tSirBssDescription *pConnectBssDesc; + uint16_t NumPmkidCache; /* valid number of pmkid in the cache*/ + uint16_t curr_cache_idx; /* the index in pmkidcache to write next to */ + tPmkidCacheInfo PmkidCacheInfo[CSR_MAX_PMKID_ALLOWED]; + uint8_t cJoinAttemps; + /* + * This may or may not have the up-to-date valid channel list. It is + * used to get WNI_CFG_VALID_CHANNEL_LIST and not alloc memory all time + */ + tSirMacChanNum validChannelList[WNI_CFG_VALID_CHANNEL_LIST_LEN]; + int32_t sPendingCommands; /* 0 means CSR is ok to low power */ +#ifdef FEATURE_WLAN_WAPI + uint16_t NumBkidCache; + tBkidCacheInfo BkidCacheInfo[CSR_MAX_BKID_ALLOWED]; +#endif /* FEATURE_WLAN_WAPI */ + /* + * indicate whether CSR is roaming + * (either via lostlink or dynamic roaming) + */ + bool fRoaming; + /* + * to remember some parameters needed for START_BSS. + * All member must be set every time we try to join or start an IBSS + */ + tCsrRoamStartBssParams bssParams; + /* the byte count of pWpaRsnIE; */ + uint32_t nWpaRsnReqIeLength; + /* contain the WPA/RSN IE in assoc req or one sent in beacon(IBSS) */ + uint8_t *pWpaRsnReqIE; + /* the byte count for pWpaRsnRspIE */ + uint32_t nWpaRsnRspIeLength; + /* this contain the WPA/RSN IE in beacon/probe rsp */ + uint8_t *pWpaRsnRspIE; +#ifdef FEATURE_WLAN_WAPI + /* the byte count of pWapiReqIE; */ + uint32_t nWapiReqIeLength; + /* this contain the WAPI IE in assoc req or one sent in beacon (IBSS) */ + uint8_t *pWapiReqIE; + /* the byte count for pWapiRspIE */ + uint32_t nWapiRspIeLength; + /* this contain the WAPI IE in beacon/probe rsp */ + uint8_t *pWapiRspIE; +#endif /* FEATURE_WLAN_WAPI */ + uint32_t nAddIEScanLength; /* the byte count of pAddIeScanIE; */ + /* contains the additional IE in (unicast) probe req at time of join */ + uint8_t *pAddIEScan; + uint32_t nAddIEAssocLength; /* the byte count for pAddIeAssocIE */ + uint8_t *pAddIEAssoc; + tCsrTimerInfo roamingTimerInfo; + eCsrRoamingReason roamingReason; + bool fCancelRoaming; + qdf_mc_timer_t hTimerRoaming; + /* the roamResult that is used when the roaming timer fires */ + eCsrRoamResult roamResult; + /* This is the reason code for join(assoc) failure */ + tCsrRoamJoinStatus joinFailStatusCode; + /* status from PE for deauth/disassoc(lostlink) or our own dyn roam */ + uint32_t roamingStatusCode; + uint16_t NumPmkidCandidate; + tPmkidCandidateInfo PmkidCandidateInfo[CSR_MAX_PMKID_ALLOWED]; +#ifdef FEATURE_WLAN_WAPI + uint16_t NumBkidCandidate; + tBkidCandidateInfo BkidCandidateInfo[CSR_MAX_BKID_ALLOWED]; +#endif + bool fWMMConnection; + bool fQOSConnection; +#ifdef FEATURE_WLAN_ESE + tCsrEseCckmInfo eseCckmInfo; + bool isPrevApInfoValid; + tSirMacSSid prevApSSID; + struct qdf_mac_addr prevApBssid; + uint8_t prevOpChannel; + uint16_t clientDissSecs; + uint32_t roamTS1; + tCsrEseCckmIe suppCckmIeInfo; +#endif + uint8_t bRefAssocStartCnt; /* Tracking assoc start indication */ + tSirHTConfig htConfig; + struct sir_vht_config vht_config; +#ifdef FEATURE_WLAN_SCAN_PNO + bool pnoStarted; +#endif +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + csr_roam_offload_synch_params roamOffloadSynchParams; + uint8_t psk_pmk[SIR_ROAM_SCAN_PSK_SIZE]; + size_t pmk_len; + uint8_t RoamKeyMgmtOffloadEnabled; + roam_offload_synch_ind *roam_synch_data; + struct pmkid_mode_bits pmkid_modes; +#endif + tftSMEContext ftSmeContext; + /* This count represents the number of bssid's we try to join. */ + uint8_t join_bssid_count; + struct csr_roam_stored_profile stored_roam_profile; + bool ch_switch_in_progress; + bool roam_synch_in_progress; + bool supported_nss_1x1; + bool disable_hi_rssi; + bool dhcp_done; + uint8_t disconnect_reason; + uint8_t uapsd_mask; + qdf_mc_timer_t roaming_offload_timer; + bool ignore_assoc_disallowed; +} tCsrRoamSession; + +typedef struct tagCsrRoamStruct { + uint32_t nextRoamId; + tDblLinkList roamCmdPendingList; + tDblLinkList channelList5G; + tDblLinkList channelList24; + tCsrConfig configParam; + uint32_t numChannelsEeprom; /* total channels of eeprom */ + tCsrChannel baseChannels; /* The channel base to work on */ + eCsrRoamState curState[CSR_ROAM_SESSION_MAX]; + eCsrRoamSubState curSubState[CSR_ROAM_SESSION_MAX]; + /* + * This may or may not have the up-to-date valid channel list. It is + * used to get WNI_CFG_VALID_CHANNEL_LIST and not alloc mem all time + */ + tSirMacChanNum validChannelList[WNI_CFG_VALID_CHANNEL_LIST_LEN]; + uint32_t numValidChannels; /* total number of channels in CFG */ + int32_t sPendingCommands; + qdf_mc_timer_t hTimerWaitForKey; /* support timeout for WaitForKey */ + tCsrSummaryStatsInfo summaryStatsInfo; + tCsrGlobalClassAStatsInfo classAStatsInfo; + tCsrGlobalClassBStatsInfo classBStatsInfo; + tCsrGlobalClassCStatsInfo classCStatsInfo; + tCsrGlobalClassDStatsInfo classDStatsInfo; + tCsrPerStaStatsInfo perStaStatsInfo[CSR_MAX_STA]; + struct csr_per_chain_rssi_stats_info per_chain_rssi_stats; + tDblLinkList statsClientReqList; + tDblLinkList peStatsReqList; + tCsrTlStatsReqInfo tlStatsReqInfo; + eCsrRoamLinkQualityInd vccLinkQuality; + tCsrLinkQualityIndInfo linkQualityIndInfo; + v_CONTEXT_t g_cds_context; /* used for interaction with TL */ + tCsrTimerInfo WaitForKeyTimerInfo; + tCsrRoamSession *roamSession; + uint32_t transactionId; /* Current transaction ID for internal use. */ + tCsrNeighborRoamControlInfo neighborRoamInfo[CSR_ROAM_SESSION_MAX]; + uint8_t isFastRoamIniFeatureEnabled; +#ifdef FEATURE_WLAN_ESE + uint8_t isEseIniFeatureEnabled; +#endif + uint8_t RoamRssiDiff; + bool isWESModeEnabled; + uint32_t deauthRspStatus; + uint8_t *pReassocResp; /* reassociation response from new AP */ + uint16_t reassocRespLen; /* length of reassociation response */ + qdf_mc_timer_t packetdump_timer; +} tCsrRoamStruct; + +#define GET_NEXT_ROAM_ID(pRoamStruct) (((pRoamStruct)->nextRoamId + 1 == 0) ? \ + 1 : (pRoamStruct)->nextRoamId) +#define CSR_IS_ROAM_STATE(pMac, state, sessionId) \ + ((state) == (pMac)->roam.curState[sessionId]) +#define CSR_IS_ROAM_STOP(pMac, sessionId) \ + CSR_IS_ROAM_STATE((pMac), eCSR_ROAMING_STATE_STOP, sessionId) +#define CSR_IS_ROAM_INIT(pMac, sessionId) \ + CSR_IS_ROAM_STATE((pMac), eCSR_ROAMING_STATE_INIT, sessionId) +#define CSR_IS_ROAM_JOINING(pMac, sessionId) \ + CSR_IS_ROAM_STATE(pMac, eCSR_ROAMING_STATE_JOINING, sessionId) +#define CSR_IS_ROAM_IDLE(pMac, sessionId) \ + CSR_IS_ROAM_STATE(pMac, eCSR_ROAMING_STATE_IDLE, sessionId) +#define CSR_IS_ROAM_JOINED(pMac, sessionId) \ + CSR_IS_ROAM_STATE(pMac, eCSR_ROAMING_STATE_JOINED, sessionId) +#define CSR_IS_ROAM_SUBSTATE(pMac, subState, sessionId) \ + ((subState) == (pMac)->roam.curSubState[sessionId]) +#define CSR_IS_ROAM_SUBSTATE_JOIN_REQ(pMac, sessionId) \ + CSR_IS_ROAM_SUBSTATE((pMac), eCSR_ROAM_SUBSTATE_JOIN_REQ, sessionId) +#define CSR_IS_ROAM_SUBSTATE_AUTH_REQ(pMac, sessionId) \ + CSR_IS_ROAM_SUBSTATE((pMac), eCSR_ROAM_SUBSTATE_AUTH_REQ, sessionId) +#define CSR_IS_ROAM_SUBSTATE_REASSOC_REQ(pMac, sessionId) \ + CSR_IS_ROAM_SUBSTATE((pMac), eCSR_ROAM_SUBSTATE_REASSOC_REQ, sessionId) +#define CSR_IS_ROAM_SUBSTATE_DISASSOC_REQ(pMac, sessionId) \ + CSR_IS_ROAM_SUBSTATE((pMac), eCSR_ROAM_SUBSTATE_DISASSOC_REQ, sessionId) +#define CSR_IS_ROAM_SUBSTATE_DISASSOC_NO_JOIN(pMac, sessionId) \ + CSR_IS_ROAM_SUBSTATE((pMac), \ + eCSR_ROAM_SUBSTATE_DISASSOC_NOTHING_TO_JOIN, sessionId) +#define CSR_IS_ROAM_SUBSTATE_REASSOC_FAIL(pMac, sessionId) \ + CSR_IS_ROAM_SUBSTATE((pMac), \ + eCSR_ROAM_SUBSTATE_DISASSOC_REASSOC_FAILURE, sessionId) +#define CSR_IS_ROAM_SUBSTATE_DISASSOC_FORCED(pMac, sessionId) \ + CSR_IS_ROAM_SUBSTATE((pMac), \ + eCSR_ROAM_SUBSTATE_DISASSOC_FORCED, sessionId) +#define CSR_IS_ROAM_SUBSTATE_DEAUTH_REQ(pMac, sessionId) \ + CSR_IS_ROAM_SUBSTATE((pMac), \ + eCSR_ROAM_SUBSTATE_DEAUTH_REQ, sessionId) +#define CSR_IS_ROAM_SUBSTATE_START_BSS_REQ(pMac, sessionId) \ + CSR_IS_ROAM_SUBSTATE((pMac), \ + eCSR_ROAM_SUBSTATE_START_BSS_REQ, sessionId) +#define CSR_IS_ROAM_SUBSTATE_STOP_BSS_REQ(pMac, sessionId) \ + CSR_IS_ROAM_SUBSTATE((pMac), \ + eCSR_ROAM_SUBSTATE_STOP_BSS_REQ, sessionId) +#define CSR_IS_ROAM_SUBSTATE_DISCONNECT_CONTINUE(pMac, sessionId) \ + CSR_IS_ROAM_SUBSTATE((pMac), \ + eCSR_ROAM_SUBSTATE_DISCONNECT_CONTINUE_ROAMING, sessionId) +#define CSR_IS_ROAM_SUBSTATE_CONFIG(pMac, sessionId) \ + CSR_IS_ROAM_SUBSTATE((pMac), \ + eCSR_ROAM_SUBSTATE_CONFIG, sessionId) +#define CSR_IS_ROAM_SUBSTATE_WAITFORKEY(pMac, sessionId) \ + CSR_IS_ROAM_SUBSTATE((pMac), \ + eCSR_ROAM_SUBSTATE_WAIT_FOR_KEY, sessionId) +#define CSR_IS_ROAM_SUBSTATE_DISASSOC_HO(pMac, sessionId) \ + CSR_IS_ROAM_SUBSTATE((pMac), \ + eCSR_ROAM_SUBSTATE_DISASSOC_HANDOFF, sessionId) +#define CSR_IS_ROAM_SUBSTATE_HO_NT(pMac, sessionId) \ + CSR_IS_ROAM_SUBSTATE((pMac), \ + eCSR_ROAM_SUBSTATE_JOINED_NO_TRAFFIC, sessionId) +#define CSR_IS_ROAM_SUBSTATE_HO_NRT(pMac, sessionId) \ + CSR_IS_ROAM_SUBSTATE((pMac), \ + eCSR_ROAM_SUBSTATE_JOINED_NON_REALTIME_TRAFFIC,\ + sessionId) +#define CSR_IS_ROAM_SUBSTATE_HO_RT(pMac, sessionId) \ + CSR_IS_ROAM_SUBSTATE((pMac),\ + eCSR_ROAM_SUBSTATE_JOINED_REALTIME_TRAFFIC, sessionId) +#define CSR_IS_PHY_MODE_B_ONLY(pMac) \ + ((eCSR_DOT11_MODE_11b == (pMac)->roam.configParam.phyMode) || \ + (eCSR_DOT11_MODE_11b_ONLY == (pMac)->roam.configParam.phyMode)) + +#define CSR_IS_PHY_MODE_G_ONLY(pMac) \ + (eCSR_DOT11_MODE_11g == (pMac)->roam.configParam.phyMode \ + || eCSR_DOT11_MODE_11g_ONLY == (pMac)->roam.configParam.phyMode) + +#define CSR_IS_PHY_MODE_A_ONLY(pMac) \ + (eCSR_DOT11_MODE_11a == (pMac)->roam.configParam.phyMode) + +#define CSR_IS_PHY_MODE_DUAL_BAND(phyMode) \ + ((eCSR_DOT11_MODE_abg & (phyMode)) || \ + (eCSR_DOT11_MODE_11n & (phyMode)) || \ + (eCSR_DOT11_MODE_11ac & (phyMode)) || \ + (eCSR_DOT11_MODE_AUTO & (phyMode))) + +#define CSR_IS_PHY_MODE_11n(phy_mode) \ + ((eCSR_DOT11_MODE_11n == phy_mode) || \ + (eCSR_DOT11_MODE_11n_ONLY == phy_mode) || \ + (eCSR_DOT11_MODE_11ac == phy_mode) || \ + (eCSR_DOT11_MODE_11ac_ONLY == phy_mode)) + +#define CSR_IS_PHY_MODE_11ac(phy_mode) \ + ((eCSR_DOT11_MODE_11ac == phy_mode) || \ + (eCSR_DOT11_MODE_11ac_ONLY == phy_mode)) +/* + * this function returns true if the NIC is operating exclusively in + * the 2.4 GHz band, meaning. it is NOT operating in the 5.0 GHz band. + */ +#define CSR_IS_24_BAND_ONLY(pMac) \ + (eCSR_BAND_24 == (pMac)->roam.configParam.eBand) + +#define CSR_IS_5G_BAND_ONLY(pMac) \ + (eCSR_BAND_5G == (pMac)->roam.configParam.eBand) + +#define CSR_IS_RADIO_DUAL_BAND(pMac) \ + (eCSR_BAND_ALL == (pMac)->roam.configParam.bandCapability) + +#define CSR_IS_RADIO_BG_ONLY(pMac) \ + (eCSR_BAND_24 == (pMac)->roam.configParam.bandCapability) + +/* + * this function returns true if the NIC is operating exclusively in the 5.0 GHz + * band, meaning. it is NOT operating in the 2.4 GHz band + */ +#define CSR_IS_RADIO_A_ONLY(pMac) \ + (eCSR_BAND_5G == (pMac)->roam.configParam.bandCapability) +/* this function returns true if the NIC is operating in both bands. */ +#define CSR_IS_OPEARTING_DUAL_BAND(pMac) \ + ((eCSR_BAND_ALL == (pMac)->roam.configParam.bandCapability) && \ + (eCSR_BAND_ALL == (pMac)->roam.configParam.eBand)) +/* + * this function returns true if the NIC can operate in the 5.0 GHz band + * (could operate in the 2.4 GHz band also) + */ +#define CSR_IS_OPERATING_A_BAND(pMac) \ + (CSR_IS_OPEARTING_DUAL_BAND((pMac)) || \ + CSR_IS_RADIO_A_ONLY((pMac)) || CSR_IS_5G_BAND_ONLY((pMac))) + +/* + * this function returns true if the NIC can operate in the 2.4 GHz band + * (could operate in the 5.0 GHz band also). + */ +#define CSR_IS_OPERATING_BG_BAND(pMac) \ + (CSR_IS_OPEARTING_DUAL_BAND((pMac)) || \ + CSR_IS_RADIO_BG_ONLY((pMac)) || CSR_IS_24_BAND_ONLY((pMac))) +#define CSR_GET_BAND(ch_num) \ + ((CDS_IS_CHANNEL_24GHZ(ch_num)) ? eCSR_BAND_24 : eCSR_BAND_5G) +#define CSR_IS_11D_INFO_FOUND(pMac) \ + (0 != (pMac)->scan.channelOf11dInfo) +#define CSR_IS_ROAMING(pSession) \ + ((CSR_IS_LOSTLINK_ROAMING((pSession)->roamingReason)) || \ + (eCsrDynamicRoaming == (pSession)->roamingReason) || \ + (eCsrReassocRoaming == (pSession)->roamingReason)) +#define CSR_IS_SET_KEY_COMMAND(pCommand) \ + (eSmeCommandSetKey == (pCommand)->command) +#define CSR_IS_ADDTS_WHEN_ACMOFF_SUPPORTED(pMac) \ + (pMac->roam.configParam.addTSWhenACMIsOff) +#define CSR_IS_LOSTLINK_ROAMING(reason) \ + ((eCsrLostlinkRoamingDisassoc == (reason)) || \ + (eCsrLostlinkRoamingDeauth == (reason))) + +#define CSR_IS_ROAMING_COMMAND(pCommand) \ + ((eCsrLostLink1 == (pCommand)->u.roamCmd.roamReason) || \ + (eCsrLostLink2 == (pCommand)->u.roamCmd.roamReason) || \ + (eCsrLostLink3 == (pCommand)->u.roamCmd.roamReason)) + +#ifdef FEATURE_LFR_SUBNET_DETECTION +/* bit-4 and bit-5 indicate the subnet status */ +#define CSR_GET_SUBNET_STATUS(roam_reason) (((roam_reason) & 0x30) >> 4) +#else +#define CSR_GET_SUBNET_STATUS(roam_reason) (0) +#endif + +QDF_STATUS csr_get_channel_and_power_list(tpAniSirGlobal pMac); +QDF_STATUS csrScanFilter11dResult(tpAniSirGlobal pMac); + +QDF_STATUS csr_scan_filter_results(tpAniSirGlobal pMac); + +QDF_STATUS csr_set_modify_profile_fields(tpAniSirGlobal pMac, + uint32_t sessionId, tCsrRoamModifyProfileFields * + pModifyProfileFields); +QDF_STATUS csr_get_modify_profile_fields(tpAniSirGlobal pMac, + uint32_t sessionId, tCsrRoamModifyProfileFields * + pModifyProfileFields); +void csr_set_global_cfgs(tpAniSirGlobal pMac); +void csr_set_default_dot11_mode(tpAniSirGlobal pMac); +void csrScanSetChannelMask(tpAniSirGlobal pMac, tCsrChannelInfo *pChannelInfo); +bool csr_is_conn_state_disconnected(tpAniSirGlobal pMac, uint32_t sessionId); +bool csr_is_conn_state_connected_ibss(tpAniSirGlobal pMac, uint32_t sessionId); +bool csr_is_conn_state_disconnected_ibss(tpAniSirGlobal pMac, + uint32_t sessionId); +bool csr_is_conn_state_connected_infra(tpAniSirGlobal pMac, uint32_t sessionId); +bool csr_is_conn_state_connected(tpAniSirGlobal pMac, uint32_t sessionId); +bool csr_is_conn_state_infra(tpAniSirGlobal pMac, uint32_t sessionId); +bool csr_is_conn_state_ibss(tpAniSirGlobal pMac, uint32_t sessionId); +bool csr_is_conn_state_wds(tpAniSirGlobal pMac, uint32_t sessionId); +bool csr_is_conn_state_connected_wds(tpAniSirGlobal pMac, uint32_t sessionId); +bool csr_is_conn_state_disconnected_wds(tpAniSirGlobal pMac, + uint32_t sessionId); +bool csr_is_any_session_in_connect_state(tpAniSirGlobal pMac); +bool csr_is_all_session_disconnected(tpAniSirGlobal pMac); +bool csr_is_sta_session_connected(tpAniSirGlobal pMac); +bool csr_is_p2p_session_connected(tpAniSirGlobal pMac); +bool csr_is_any_session_connected(tpAniSirGlobal pMac); +bool csr_is_infra_connected(tpAniSirGlobal pMac); +bool csr_is_concurrent_infra_connected(tpAniSirGlobal pMac); +bool csr_is_concurrent_session_running(tpAniSirGlobal pMac); +bool csr_is_infra_ap_started(tpAniSirGlobal pMac); +bool csr_is_ibss_started(tpAniSirGlobal pMac); +bool csr_is_valid_mc_concurrent_session(tpAniSirGlobal pMac, uint32_t sessionId, + tSirBssDescription *pBssDesc); +bool csr_is_conn_state_connected_infra_ap(tpAniSirGlobal pMac, + uint32_t sessionId); +QDF_STATUS csr_get_statistics(tpAniSirGlobal pMac, + eCsrStatsRequesterType requesterId, + uint32_t statsMask, tCsrStatsCallback callback, + uint32_t periodicity, bool cache, uint8_t staId, + void *pContext, uint8_t sessionId); +QDF_STATUS csr_get_rssi(tpAniSirGlobal pMac, tCsrRssiCallback callback, + uint8_t staId, struct qdf_mac_addr bssId, int8_t lastRSSI, + void *pContext, void *p_cds_context); +QDF_STATUS csr_get_snr(tpAniSirGlobal pMac, tCsrSnrCallback callback, + uint8_t staId, struct qdf_mac_addr bssId, void *pContext); +QDF_STATUS csr_get_config_param(tpAniSirGlobal pMac, tCsrConfigParam *pParam); +QDF_STATUS csr_change_default_config_param(tpAniSirGlobal pMac, + tCsrConfigParam *pParam); +QDF_STATUS csr_msg_processor(tpAniSirGlobal pMac, void *pMsgBuf); +QDF_STATUS csr_open(tpAniSirGlobal pMac); +QDF_STATUS csr_init_chan_list(tpAniSirGlobal mac, uint8_t *alpha2); +QDF_STATUS csr_close(tpAniSirGlobal pMac); +QDF_STATUS csr_start(tpAniSirGlobal pMac); +QDF_STATUS csr_stop(tpAniSirGlobal pMac, tHalStopType stopType); +QDF_STATUS csr_ready(tpAniSirGlobal pMac); + +#ifdef FEATURE_WLAN_WAPI +QDF_STATUS csr_scan_get_bkid_candidate_list(tpAniSirGlobal pMac, + uint32_t sessionId, tBkidCandidateInfo * pBkidList, + uint32_t *pNumItems); +QDF_STATUS csr_roam_get_wapi_req_ie(tpAniSirGlobal pMac, + uint32_t sessionId, uint32_t *pLen, uint8_t *pBuf); +QDF_STATUS csr_roam_get_wapi_rsp_ie(tpAniSirGlobal pMac, uint32_t sessionId, + uint32_t *pLen, uint8_t *pBuf); +uint8_t csr_construct_wapi_ie(tpAniSirGlobal pMac, uint32_t sessionId, + tCsrRoamProfile *pProfile, + tSirBssDescription *pSirBssDesc, + tDot11fBeaconIEs *pIes, tCsrWapiIe *pWapiIe); +#endif /* FEATURE_WLAN_WAPI */ + +QDF_STATUS csr_roam_update_apwpsie(tpAniSirGlobal pMac, uint32_t sessionId, + tSirAPWPSIEs * pAPWPSIES); +QDF_STATUS csr_roam_update_wparsni_es(tpAniSirGlobal pMac, uint32_t sessionId, + tSirRSNie *pAPSirRSNie); +void csr_set_cfg_privacy(tpAniSirGlobal pMac, tCsrRoamProfile *pProfile, + bool fPrivacy); +int8_t csr_get_infra_session_id(tpAniSirGlobal pMac); +uint8_t csr_get_infra_operation_channel(tpAniSirGlobal pMac, uint8_t sessionId); +bool csr_is_session_client_and_connected(tpAniSirGlobal pMac, + uint8_t sessionId); +uint8_t csr_get_concurrent_operation_channel(tpAniSirGlobal pMac); + +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH +uint16_t csr_check_concurrent_channel_overlap(tpAniSirGlobal pMac, + uint16_t sap_ch, eCsrPhyMode sap_phymode, + uint8_t cc_switch_mode); +#endif +QDF_STATUS csr_roam_copy_connect_profile(tpAniSirGlobal pMac, + uint32_t sessionId, tCsrRoamConnectedProfile *pProfile); +bool csr_is_set_key_allowed(tpAniSirGlobal pMac, uint32_t sessionId); + +void csr_set_opposite_band_channel_info(tpAniSirGlobal pMac); +#ifdef FEATURE_WLAN_SCAN_PNO +QDF_STATUS csr_scan_save_preferred_network_found(tpAniSirGlobal pMac, + tSirPrefNetworkFoundInd * + pPrefNetworkFoundInd); +#endif + +/* Returns whether the current association is a 11r assoc or not */ +bool csr_roam_is11r_assoc(tpAniSirGlobal pMac, uint8_t sessionId); + +#ifdef FEATURE_WLAN_ESE +/* Returns whether the current association is a ESE assoc or not */ +bool csr_roam_is_ese_assoc(tpAniSirGlobal pMac, uint32_t sessionId); +bool csr_roam_is_ese_ini_feature_enabled(tpAniSirGlobal pMac); +QDF_STATUS csr_get_tsm_stats(tpAniSirGlobal pMac, + tCsrTsmStatsCallback callback, + uint8_t staId, + struct qdf_mac_addr bssId, + void *pContext, void *p_cds_context, uint8_t tid); +#endif + +/* Remove this code once SLM_Sessionization is supported */ +void csr_disconnect_all_active_sessions(tpAniSirGlobal pMac); + +/* Returns whether "Legacy Fast Roaming" is enabled...or not */ +bool csr_roam_is_fast_roam_enabled(tpAniSirGlobal pMac, uint32_t sessionId); +bool csr_roam_is_roam_offload_scan_enabled(tpAniSirGlobal pMac); +bool csr_is_channel_present_in_list(uint8_t *pChannelList, int numChannels, + uint8_t channel); +QDF_STATUS csr_add_to_channel_list_front(uint8_t *pChannelList, int numChannels, + uint8_t channel); +#if defined(WLAN_FEATURE_HOST_ROAM) || defined(WLAN_FEATURE_ROAM_OFFLOAD) +QDF_STATUS csr_roam_offload_scan_rsp_hdlr(tpAniSirGlobal pMac, + tpSirRoamOffloadScanRsp scanOffloadRsp); +#else +static inline QDF_STATUS csr_roam_offload_scan_rsp_hdlr(tpAniSirGlobal pMac, + tpSirRoamOffloadScanRsp scanOffloadRsp) +{ + return QDF_STATUS_E_NOSUPPORT; +} +#endif +QDF_STATUS csr_handoff_request(tpAniSirGlobal pMac, uint8_t sessionId, + tCsrHandoffRequest *pHandoffInfo); +bool csr_roam_is_sta_mode(tpAniSirGlobal pMac, uint32_t sessionId); + +/* Post Channel Change Indication */ +QDF_STATUS csr_roam_channel_change_req(tpAniSirGlobal pMac, struct qdf_mac_addr + bssid, struct ch_params_s *ch_params, + tCsrRoamProfile *profile); + +/* Post Beacon Tx Start Indication */ +QDF_STATUS csr_roam_start_beacon_req(tpAniSirGlobal pMac, + struct qdf_mac_addr bssid, uint8_t dfsCacWaitStatus); + +QDF_STATUS csr_roam_send_chan_sw_ie_request(tpAniSirGlobal pMac, + struct qdf_mac_addr bssid, + uint8_t targetChannel, + uint8_t csaIeReqd, + struct ch_params_s *ch_params); +QDF_STATUS csr_roam_modify_add_ies(tpAniSirGlobal pMac, tSirModifyIE *pModifyIE, + eUpdateIEsType updateType); +QDF_STATUS +csr_roam_update_add_ies(tpAniSirGlobal pMac, + tSirUpdateIE *pUpdateIE, eUpdateIEsType updateType); +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +QDF_STATUS csr_scan_save_roam_offload_ap_to_scan_cache(tpAniSirGlobal pMac, + struct sSirSmeRoamOffloadSynchInd *roam_synch_ind_ptr, + tpSirBssDescription bss_desc_ptr); +void csr_process_ho_fail_ind(tpAniSirGlobal pMac, void *pMsgBuf); +#endif +#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR +void csr_roaming_report_diag_event(tpAniSirGlobal mac_ctx, + roam_offload_synch_ind *roam_synch_ind_ptr, + eCsrDiagWlanStatusEventReason reason); +#else +static inline void csr_roaming_report_diag_event(tpAniSirGlobal mac_ctx, + roam_offload_synch_ind *roam_synch_ind_ptr, + eCsrDiagWlanStatusEventReason reason) +{} +#endif + +bool csr_store_joinreq_param(tpAniSirGlobal mac_ctx, + tCsrRoamProfile *profile, + tScanResultHandle scan_cache, + uint32_t *roam_id, + uint32_t session_id); +bool csr_clear_joinreq_param(tpAniSirGlobal mac_ctx, + uint32_t session_id); +QDF_STATUS csr_issue_stored_joinreq(tpAniSirGlobal mac_ctx, + uint32_t *roam_id, + uint32_t session_id); +#ifdef FEATURE_WLAN_DIAG_SUPPORT +void csr_diag_event_report(tpAniSirGlobal pmac, uint16_t event_type, + uint16_t status, uint16_t reasoncode); +#endif +QDF_STATUS csr_get_channels_and_power(tpAniSirGlobal pMac); + +/* csr_scan_process_single_bssdescr() - Add a bssdescriptor to scan table + * + * @mac_ctx - MAC context + * @bssdescr - Pointer to BSS description structure that contains + * everything from beacon/probe response frame and additional + * information. + * @scan_id - Scan identifier of the scan request that was running + * when this beacon was received. Reserved for future when + * firmware provides that information. + * @flags - Reserved for future use. + * + * Callback routine called by LIM when it receives a beacon or probe response + * from the device. 802.11 frame is already converted to internal + * tSirBssDescription data structure. + * + * Return: 0 or other error codes. + */ + +QDF_STATUS csr_scan_process_single_bssdescr(tpAniSirGlobal pMac, + tSirBssDescription *pSirBssDescription, + uint32_t scan_id, uint32_t flags); + +bool csr_wait_for_connection_update(tpAniSirGlobal mac, + bool do_release_reacquire_lock); +enum tQDF_ADAPTER_MODE csr_get_session_persona(tpAniSirGlobal pmac, + uint32_t session_id); +void csr_roam_substate_change(tpAniSirGlobal pMac, eCsrRoamSubState NewSubstate, + uint32_t sessionId); + +void csr_neighbor_roam_process_scan_results(tpAniSirGlobal mac_ctx, + uint8_t sessionid, tScanResultHandle *scan_results_list); + +void csr_neighbor_roam_trigger_handoff(tpAniSirGlobal mac_ctx, + uint8_t session_id); +bool csr_is_ndi_started(tpAniSirGlobal mac_ctx, uint32_t session_id); + +QDF_STATUS csr_roam_update_config(tpAniSirGlobal mac_ctx, uint8_t session_id, + uint16_t capab, uint32_t value); + +#endif diff --git a/drivers/staging/qcacld-3.0/core/sme/inc/csr_link_list.h b/drivers/staging/qcacld-3.0/core/sme/inc/csr_link_list.h new file mode 100644 index 0000000000000000000000000000000000000000..1944aceea2b5deeb0ba85e707009283cbfe9ba28 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/sme/inc/csr_link_list.h @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2011-2012, 2014-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * \file csr_link_list.h + * + * Exports and types for the Common link list interfaces. + */ + +#ifndef CSR_LINK_LIST_H__ +#define CSR_LINK_LIST_H__ + +#include "qdf_lock.h" +#include "qdf_mc_timer.h" +#include "cds_api.h" +#include "sir_types.h" + +#define LL_ACCESS_LOCK true +#define LL_ACCESS_NOLOCK false + +typedef struct tagListElem { + struct tagListElem *last; + struct tagListElem *next; +} tListElem; + +typedef enum { + LIST_FLAG_CLOSE = 0, + LIST_FLAG_OPEN = 0xa1b2c4d7, +} tListFlag; + +/* This is a circular double link list */ +typedef struct tagDblLinkList { + tListElem ListHead; + qdf_mutex_t Lock; + uint32_t Count; + tHddHandle hHdd; + tListFlag Flag; + /*command debugging */ + uint32_t cmdTimeoutDuration; /* command timeout duration */ + qdf_mc_timer_t *cmdTimeoutTimer; /*command timeout Timer */ +} tDblLinkList; + +/* + * To get the address of an object of (type) base on the (address) + * of one of its (field) + */ +#define GET_BASE_ADDR(address, type, field) ((type *)( \ + (uint8_t *)(address) - \ + (uint8_t *)(&((type *)0)->field))) +/* To get the offset of (field) inside structure (type) */ +#define GET_FIELD_OFFSET(type, field) ((uintptr_t)(&(((type *)0)->field))) +#define GET_ROUND_UP(_Field, _Boundary) \ + (((_Field) + ((_Boundary) - 1)) & ~((_Boundary) - 1)) +#define BITS_ON(_Field, _Bitmask) ((_Field) |= (_Bitmask)) +#define BITS_OFF(_Field, _Bitmask) ((_Field) &= ~(_Bitmask)) +#define CSR_MAX(a, b) ((a) > (b) ? (a) : (b)) +#define CSR_MIN(a, b) ((a) < (b) ? (a) : (b)) +#define csrIsListEmpty(pHead) ((pHead)->next == (pHead)) + +uint32_t csr_ll_count(tDblLinkList *pList); +QDF_STATUS csr_ll_open(tHddHandle hHdd, tDblLinkList *pList); +void csr_ll_close(tDblLinkList *pList); +void csr_ll_lock(tDblLinkList *pList); +void csr_ll_unlock(tDblLinkList *pList); +bool csr_ll_is_list_empty(tDblLinkList *pList, bool fInterlocked); +void csr_ll_insert_head(tDblLinkList *pList, tListElem *pEntry, + bool fInterlocked); +void csr_ll_insert_tail(tDblLinkList *pList, tListElem *pEntry, + bool fInterlocked); +/* This function put pNewEntry before pEntry. Caller should have found pEntry */ +void csr_ll_insert_entry(tDblLinkList *pList, tListElem *pEntry, + tListElem *pNewEntry, bool fInterlocked); +tListElem *csr_ll_peek_head(tDblLinkList *pList, bool fInterlocked); +tListElem *csr_ll_peek_tail(tDblLinkList *pList, bool fInterlocked); +tListElem *csr_ll_remove_head(tDblLinkList *pList, bool fInterlocked); +tListElem *csr_ll_remove_tail(tDblLinkList *pList, bool fInterlocked); +bool csr_ll_remove_entry(tDblLinkList *pList, tListElem *pEntryToRemove, + bool fInterlocked); +void csr_ll_purge(tDblLinkList *pList, bool fInterlocked); +/* csr_ll_next return NULL if reaching the end or list is empty */ +tListElem *csr_ll_next(tDblLinkList *pList, tListElem *pEntry, + bool fInterlocked); +tListElem *csr_ll_previous(tDblLinkList *pList, tListElem *pEntry, + bool fInterlocked); +bool csr_ll_find_entry(tDblLinkList *pList, tListElem *pEntryToFind); +#endif diff --git a/drivers/staging/qcacld-3.0/core/sme/inc/csr_neighbor_roam.h b/drivers/staging/qcacld-3.0/core/sme/inc/csr_neighbor_roam.h new file mode 100644 index 0000000000000000000000000000000000000000..6de55e1ae56cbd5135f4fec0f67ad1a2fdae4974 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/sme/inc/csr_neighbor_roam.h @@ -0,0 +1,395 @@ +/* + * Copyright (c) 2011-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * \file csr_neighbor_roam.h + * + * Exports and types for the neighbor roaming algorithm which is sepcifically + * designed for Android. + */ + +#ifndef CSR_NEIGHBOR_ROAM_H +#define CSR_NEIGHBOR_ROAM_H + +#include "sme_api.h" + +#define ROAM_AP_AGE_LIMIT_MS 10000 + +/* Enumeration of various states in neighbor roam algorithm */ +typedef enum { + eCSR_NEIGHBOR_ROAM_STATE_CLOSED, + eCSR_NEIGHBOR_ROAM_STATE_INIT, + eCSR_NEIGHBOR_ROAM_STATE_CONNECTED, + eCSR_NEIGHBOR_ROAM_STATE_REASSOCIATING, + eCSR_NEIGHBOR_ROAM_STATE_PREAUTHENTICATING, + eCSR_NEIGHBOR_ROAM_STATE_PREAUTH_DONE, + eNEIGHBOR_STATE_MAX +} eCsrNeighborRoamState; + +/* Parameters that are obtained from CFG */ +typedef struct sCsrNeighborRoamCfgParams { + uint8_t maxNeighborRetries; + uint32_t neighborScanPeriod; + tCsrChannelInfo channelInfo; + uint8_t neighborLookupThreshold; + uint8_t neighborReassocThreshold; + uint32_t minChannelScanTime; + uint32_t maxChannelScanTime; + uint16_t neighborResultsRefreshPeriod; + uint16_t emptyScanRefreshPeriod; + uint8_t nOpportunisticThresholdDiff; + uint8_t nRoamRescanRssiDiff; + uint8_t nRoamBmissFirstBcnt; + uint8_t nRoamBmissFinalBcnt; + uint8_t nRoamBeaconRssiWeight; + uint8_t delay_before_vdev_stop; + uint32_t hi_rssi_scan_max_count; + uint32_t hi_rssi_scan_rssi_delta; + uint32_t hi_rssi_scan_delay; + int32_t hi_rssi_scan_rssi_ub; +} tCsrNeighborRoamCfgParams, *tpCsrNeighborRoamCfgParams; + +#define CSR_NEIGHBOR_ROAM_INVALID_CHANNEL_INDEX 255 +typedef struct sCsrNeighborRoamChannelInfo { + /* Flag to mark reception of IAPP Neighbor list */ + bool IAPPNeighborListReceived; + /* Current channel index that is being scanned */ + uint8_t currentChanIndex; + /* Max number of channels in channel list and the list of channels */ + tCsrChannelInfo currentChannelListInfo; +} tCsrNeighborRoamChannelInfo, *tpCsrNeighborRoamChannelInfo; + +typedef struct sCsrNeighborRoamBSSInfo { + tListElem List; + uint8_t apPreferenceVal; + tpSirBssDescription pBssDescription; +} tCsrNeighborRoamBSSInfo, *tpCsrNeighborRoamBSSInfo; + +#define CSR_NEIGHBOR_ROAM_REPORT_QUERY_TIMEOUT 1000 /* in milliseconds */ +#define CSR_NEIGHBOR_ROAM_PREAUTH_RSP_WAIT_MULTIPLIER 10 /* in milliseconds */ +/* Max number of MAC addresses with which the pre-auth was failed */ +#define MAX_NUM_PREAUTH_FAIL_LIST_ADDRESS 10 +#define MAX_BSS_IN_NEIGHBOR_RPT 15 +#define CSR_NEIGHBOR_ROAM_MAX_NUM_PREAUTH_RETRIES 3 + +/* Black listed APs. List of MAC Addresses with which the Preauth was failed */ +typedef struct sCsrPreauthFailListInfo { + uint8_t numMACAddress; + tSirMacAddr macAddress[MAX_NUM_PREAUTH_FAIL_LIST_ADDRESS]; +} tCsrPreauthFailListInfo, *tpCsrPreauthFailListInfo; + +typedef struct sCsrNeighborReportBssInfo { + uint8_t channelNum; + uint8_t neighborScore; + tSirMacAddr neighborBssId; +} tCsrNeighborReportBssInfo, *tpCsrNeighborReportBssInfo; + +typedef struct sCsr11rAssocNeighborInfo { + bool preauthRspPending; + bool neighborRptPending; + uint8_t currentNeighborRptRetryNum; + tCsrPreauthFailListInfo preAuthFailList; + uint32_t neighborReportTimeout; + uint32_t PEPreauthRespTimeout; + uint8_t numPreAuthRetries; + tDblLinkList preAuthDoneList; /* llist which consists/preauth nodes */ + uint8_t numBssFromNeighborReport; + /* Contains info needed during REPORT_SCAN State */ + tCsrNeighborReportBssInfo neighboReportBssInfo[MAX_BSS_IN_NEIGHBOR_RPT]; +} tCsr11rAssocNeighborInfo, *tpCsr11rAssocNeighborInfo; + +typedef enum { + eFirstEmptyScan = 1, + eSecondEmptyScan, + eThirdEmptyScan, + eFourthEmptyScan, + eFifthEmptyScan, + eMaxEmptyScan = eFifthEmptyScan, +} eNeighborRoamEmptyScanCount; + +typedef enum { + DEFAULT_SCAN = 0, + SPLIT_SCAN_OCCUPIED_LIST = 1, +} eNeighborRoamScanMode; + +/* Complete control information for neighbor roam algorithm */ +typedef struct sCsrNeighborRoamControlInfo { + eCsrNeighborRoamState neighborRoamState; + eCsrNeighborRoamState prevNeighborRoamState; + tCsrNeighborRoamCfgParams cfgParams; + struct qdf_mac_addr currAPbssid; /* current assoc AP */ + uint8_t currAPoperationChannel; /* current assoc AP */ + tCsrNeighborRoamChannelInfo roamChannelInfo; + uint8_t currentNeighborLookupThreshold; + uint8_t currentOpportunisticThresholdDiff; + uint8_t currentRoamRescanRssiDiff; + tDblLinkList roamableAPList; /* List of current FT candidates */ + tCsrRoamProfile csrNeighborRoamProfile; + bool is11rAssoc; + tCsr11rAssocNeighborInfo FTRoamInfo; +#ifdef FEATURE_WLAN_ESE + bool isESEAssoc; + bool isVOAdmitted; + uint16_t MinQBssLoadRequired; +#endif + /* + * Previous connected profile. + * If the new profile does not match previous we re-initialize + * occupied channel list + */ + tCsrRoamConnectedProfile prevConnProfile; + /* upper layer requested a reassoc */ + uint8_t uOsRequestedHandoff; + /* handoff related info came with upper layer's req for reassoc */ + tCsrHandoffRequest handoffReqInfo; + uint8_t currentRoamBmissFirstBcnt; + uint8_t currentRoamBmissFinalBcnt; + uint8_t currentRoamBeaconRssiWeight; + uint8_t last_sent_cmd; +} tCsrNeighborRoamControlInfo, *tpCsrNeighborRoamControlInfo; + +/* All the necessary Function declarations are here */ +QDF_STATUS csr_neighbor_roam_indicate_connect(tpAniSirGlobal pMac, + uint8_t sessionId, QDF_STATUS status); +QDF_STATUS csr_neighbor_roam_indicate_disconnect(tpAniSirGlobal pMac, + uint8_t sessionId); +QDF_STATUS csr_neighbor_roam_init(tpAniSirGlobal pMac, uint8_t sessionId); +void csr_neighbor_roam_close(tpAniSirGlobal pMac, uint8_t sessionId); +QDF_STATUS csr_neighbor_roam_transit_to_cfg_chan_scan(tpAniSirGlobal pMac, + uint8_t sessionId); +QDF_STATUS csrNeighborRoamTransitionToPreauthDone(tpAniSirGlobal pMac); +QDF_STATUS csr_neighbor_roam_prepare_scan_profile_filter(tpAniSirGlobal pMac, + tCsrScanResultFilter *pScanFilter, uint8_t sessionId); +QDF_STATUS csr_neighbor_roam_preauth_rsp_handler(tpAniSirGlobal pMac, + uint8_t sessionId, tSirRetStatus limStatus); +bool csr_neighbor_roam_is11r_assoc(tpAniSirGlobal pMac, uint8_t sessionId); +#ifdef WLAN_FEATURE_HOST_ROAM +void csr_neighbor_roam_tranistion_preauth_done_to_disconnected( + tpAniSirGlobal pMac, uint8_t sessionId); +bool csr_neighbor_roam_state_preauth_done(tpAniSirGlobal pMac, + uint8_t sessionId); +QDF_STATUS csr_roam_issue_reassociate_cmd(tpAniSirGlobal pMac, + uint32_t sessionId); +void csr_neighbor_roam_free_roamable_bss_list(tpAniSirGlobal mac_ctx, + tDblLinkList *llist); +bool csr_neighbor_roam_get_handoff_ap_info(tpAniSirGlobal pMac, + tpCsrNeighborRoamBSSInfo pHandoffNode, uint8_t sessionId); +QDF_STATUS csr_roam_issue_reassociate(tpAniSirGlobal pMac, + uint32_t sessionId, tSirBssDescription *pSirBssDesc, + tDot11fBeaconIEs *pIes, tCsrRoamProfile *pProfile); +void csr_neighbor_roam_request_handoff(tpAniSirGlobal pMac, uint8_t sessionId); +QDF_STATUS csr_neighbor_roam_candidate_found_ind_hdlr(tpAniSirGlobal pMac, + void *pMsg); +QDF_STATUS csr_neighbor_roam_process_scan_complete(tpAniSirGlobal pMac, + uint8_t sessionId); +bool csr_neighbor_roam_is_handoff_in_progress(tpAniSirGlobal pMac, + uint8_t sessionId); +void csr_neighbor_roam_reset_preauth_control_info( + tpAniSirGlobal mac_ctx, uint8_t session_id); +void csr_neighbor_roam_purge_preauth_failed_list(tpAniSirGlobal pMac); +#else +static inline bool csr_neighbor_roam_state_preauth_done(tpAniSirGlobal pMac, + uint8_t sessionId) +{ + return false; +} +static inline QDF_STATUS csr_roam_issue_reassociate_cmd(tpAniSirGlobal pMac, + uint32_t sessionId) +{ + return QDF_STATUS_E_NOSUPPORT; +} +static inline QDF_STATUS csr_roam_issue_reassociate(tpAniSirGlobal pMac, + uint32_t sessionId, tSirBssDescription *pSirBssDesc, + tDot11fBeaconIEs *pIes, tCsrRoamProfile *pProfile) +{ + return QDF_STATUS_E_NOSUPPORT; +} +static inline QDF_STATUS csr_neighbor_roam_candidate_found_ind_hdlr( + tpAniSirGlobal pMac, void *pMsg) +{ + return QDF_STATUS_E_NOSUPPORT; +} +static inline QDF_STATUS csr_neighbor_roam_process_scan_complete( + tpAniSirGlobal pMac, uint8_t sessionId) +{ + return QDF_STATUS_E_NOSUPPORT; +} +static inline void csr_neighbor_roam_tranistion_preauth_done_to_disconnected( + tpAniSirGlobal pMac, uint8_t sessionId) +{} +static inline void csr_neighbor_roam_free_roamable_bss_list( + tpAniSirGlobal mac_ctx, tDblLinkList *llist) +{} +static inline void csr_neighbor_roam_request_handoff(tpAniSirGlobal pMac, + uint8_t sessionId) +{} +static inline void csr_neighbor_roam_reset_preauth_control_info( + tpAniSirGlobal mac_ctx, uint8_t session_id) +{} +static inline void csr_neighbor_roam_purge_preauth_failed_list( + tpAniSirGlobal pMac) +{} +static inline bool csr_neighbor_roam_get_handoff_ap_info(tpAniSirGlobal pMac, + tpCsrNeighborRoamBSSInfo pHandoffNode, uint8_t sessionId) +{ + return false; +} +static inline bool csr_neighbor_roam_is_handoff_in_progress(tpAniSirGlobal pMac, + uint8_t sessionId) +{ + return false; +} +#endif +bool csr_neighbor_middle_of_roaming(tpAniSirGlobal pMac, uint8_t sessionId); +QDF_STATUS csr_neighbor_roam_update_config(tpAniSirGlobal mac_ctx, + uint8_t session_id, uint8_t value, uint8_t reason); +QDF_STATUS csr_neighbor_roam_update_fast_roaming_enabled(tpAniSirGlobal pMac, + uint8_t sessionId, const bool fastRoamEnabled); +QDF_STATUS csr_neighbor_roam_channels_filter_by_current_band( + tpAniSirGlobal pMac, uint8_t sessionId, + uint8_t *pInputChannelList, + uint8_t inputNumOfChannels, + uint8_t *pOutputChannelList, + uint8_t *pMergedOutputNumOfChannels); +QDF_STATUS csr_neighbor_roam_merge_channel_lists(tpAniSirGlobal pMac, + uint8_t *pInputChannelList, + uint8_t inputNumOfChannels, + uint8_t *pOutputChannelList, + uint8_t outputNumOfChannels, + uint8_t *pMergedOutputNumOfChannels); +void csr_roam_reset_roam_params(tpAniSirGlobal mac_ptr); +#define ROAM_SCAN_OFFLOAD_START 1 +#define ROAM_SCAN_OFFLOAD_STOP 2 +#define ROAM_SCAN_OFFLOAD_RESTART 3 +#define ROAM_SCAN_OFFLOAD_UPDATE_CFG 4 +#define ROAM_SCAN_OFFLOAD_ABORT_SCAN 5 + +#define REASON_CONNECT 1 +#define REASON_CHANNEL_LIST_CHANGED 2 +#define REASON_LOOKUP_THRESH_CHANGED 3 +#define REASON_DISCONNECTED 4 +#define REASON_RSSI_DIFF_CHANGED 5 +#define REASON_ESE_INI_CFG_CHANGED 6 +#define REASON_NEIGHBOR_SCAN_REFRESH_PERIOD_CHANGED 7 +#define REASON_VALID_CHANNEL_LIST_CHANGED 8 +#define REASON_FLUSH_CHANNEL_LIST 9 +#define REASON_EMPTY_SCAN_REF_PERIOD_CHANGED 10 +#define REASON_PREAUTH_FAILED_FOR_ALL 11 +#define REASON_NO_CAND_FOUND_OR_NOT_ROAMING_NOW 12 +#define REASON_NPROBES_CHANGED 13 +#define REASON_HOME_AWAY_TIME_CHANGED 14 +#define REASON_OS_REQUESTED_ROAMING_NOW 15 +#define REASON_SCAN_CH_TIME_CHANGED 16 +#define REASON_SCAN_HOME_TIME_CHANGED 17 +#define REASON_OPPORTUNISTIC_THRESH_DIFF_CHANGED 18 +#define REASON_ROAM_RESCAN_RSSI_DIFF_CHANGED 19 +#define REASON_ROAM_BMISS_FIRST_BCNT_CHANGED 20 +#define REASON_ROAM_BMISS_FINAL_BCNT_CHANGED 21 +#define REASON_ROAM_BEACON_RSSI_WEIGHT_CHANGED 22 +#define REASON_ROAM_DFS_SCAN_MODE_CHANGED 23 +#define REASON_ROAM_ABORT_ROAM_SCAN 24 +#define REASON_ROAM_EXT_SCAN_PARAMS_CHANGED 25 +#define REASON_ROAM_SET_SSID_ALLOWED 26 +#define REASON_ROAM_SET_FAVORED_BSSID 27 +#define REASON_ROAM_GOOD_RSSI_CHANGED 28 +#define REASON_ROAM_SET_BLACKLIST_BSSID 29 +#define REASON_ROAM_SCAN_HI_RSSI_MAXCOUNT_CHANGED 30 +#define REASON_ROAM_SCAN_HI_RSSI_DELTA_CHANGED 31 +#define REASON_ROAM_SCAN_HI_RSSI_DELAY_CHANGED 32 +#define REASON_ROAM_SCAN_HI_RSSI_UB_CHANGED 33 +#define REASON_CONNECT_IES_CHANGED 34 +#define REASON_ROAM_SCAN_STA_ROAM_POLICY_CHANGED 35 +#define REASON_ROAM_SYNCH_FAILED 36 +#define REASON_ROAM_PSK_PMK_CHANGED 37 +#define REASON_ROAM_STOP_ALL 38 + + + +#if defined(WLAN_FEATURE_HOST_ROAM) || defined(WLAN_FEATURE_ROAM_OFFLOAD) +QDF_STATUS csr_roam_offload_scan(tpAniSirGlobal pMac, uint8_t sessionId, + uint8_t command, uint8_t reason); +#else +static inline QDF_STATUS csr_roam_offload_scan(tpAniSirGlobal pMac, + uint8_t sessionId, uint8_t command, uint8_t reason) +{ + return QDF_STATUS_E_NOSUPPORT; +} +#endif +QDF_STATUS csr_neighbor_roam_handoff_req_hdlr(tpAniSirGlobal pMac, void *pMsg); +QDF_STATUS csr_neighbor_roam_proceed_with_handoff_req(tpAniSirGlobal pMac, + uint8_t sessionId); +QDF_STATUS csr_neighbor_roam_sssid_scan_done(tpAniSirGlobal pMac, + uint8_t sessionId, QDF_STATUS status); +QDF_STATUS csr_neighbor_roam_start_lfr_scan(tpAniSirGlobal pMac, + uint8_t sessionId); + +#ifdef FEATURE_WLAN_ESE +QDF_STATUS csr_set_cckm_ie(tpAniSirGlobal pMac, const uint8_t sessionId, + const uint8_t *pCckmIe, const uint8_t ccKmIeLen); +QDF_STATUS csr_roam_read_tsf(tpAniSirGlobal pMac, uint8_t *pTimestamp, + const uint8_t sessionId); +#endif /* FEATURE_WLAN_ESE */ +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +QDF_STATUS csr_roam_synch_callback(tpAniSirGlobal mac, + roam_offload_synch_ind *roam_synch_data, + tpSirBssDescription bss_desc_ptr, enum sir_roam_op_code reason); +#else +static inline QDF_STATUS csr_roam_synch_callback(tpAniSirGlobal mac, + roam_offload_synch_ind *roam_synch_data, + tpSirBssDescription bss_desc_ptr, enum sir_roam_op_code reason) +{ + return QDF_STATUS_E_NOSUPPORT; +} +#endif +void csr_neighbor_roam_state_transition(tpAniSirGlobal mac_ctx, + uint8_t newstate, uint8_t session); +uint8_t *csr_neighbor_roam_state_to_string(uint8_t state); +tpCsrNeighborRoamBSSInfo csr_neighbor_roam_next_roamable_ap( + tpAniSirGlobal mac_ctx, tDblLinkList *llist, + tpCsrNeighborRoamBSSInfo neighbor_entry); +bool csr_neighbor_roam_remove_roamable_ap_list_entry(tpAniSirGlobal pMac, + tDblLinkList *pList, tpCsrNeighborRoamBSSInfo pNeighborEntry); +void csr_neighbor_roam_free_neighbor_roam_bss_node(tpAniSirGlobal pMac, + tpCsrNeighborRoamBSSInfo neighborRoamBSSNode); +QDF_STATUS csr_neighbor_roam_issue_preauth_req(tpAniSirGlobal pMac, + uint8_t sessionId); +bool csr_neighbor_roam_is_preauth_candidate(tpAniSirGlobal pMac, + uint8_t sessionId, tSirMacAddr bssId); +#ifdef FEATURE_WLAN_LFR_METRICS +void csr_neighbor_roam_send_lfr_metric_event(tpAniSirGlobal mac_ctx, + uint8_t session_id, tSirMacAddr bssid, eRoamCmdStatus status); +#else +static inline void csr_neighbor_roam_send_lfr_metric_event( + tpAniSirGlobal mac_ctx, uint8_t session_id, + tSirMacAddr bssid, eRoamCmdStatus status) +{} +#endif +QDF_STATUS csr_roam_stop_wait_for_key_timer(tpAniSirGlobal pMac); +QDF_STATUS csr_roam_copy_connected_profile(tpAniSirGlobal pMac, + uint32_t sessionId, tCsrRoamProfile *pDstProfile); + +#endif /* CSR_NEIGHBOR_ROAM_H */ diff --git a/drivers/staging/qcacld-3.0/core/sme/inc/csr_support.h b/drivers/staging/qcacld-3.0/core/sme/inc/csr_support.h new file mode 100644 index 0000000000000000000000000000000000000000..c0bab6dbb780377665fa087d4fc5d88337e34071 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/sme/inc/csr_support.h @@ -0,0 +1,369 @@ +/* + * Copyright (c) 2011-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * \file csr_support.h + * + * Exports and types for the Common Scan and Roaming supporting interfaces. + */ +#ifndef CSR_SUPPORT_H__ +#define CSR_SUPPORT_H__ + +#include "csr_link_list.h" +#include "csr_api.h" +#include "cds_reg_service.h" + +#ifdef FEATURE_WLAN_WAPI +#define CSR_WAPI_OUI_SIZE (4) +#define CSR_WAPI_VERSION_SUPPORTED (1) +#define CSR_WAPI_MAX_AUTH_SUITES (2) +#define CSR_WAPI_MAX_CYPHERS (5) +#define CSR_WAPI_MAX_UNICAST_CYPHERS (5) +#define CSR_WAPI_MAX_MULTICAST_CYPHERS (1) +#endif /* FEATURE_WLAN_WAPI */ + +#define CSR_RSN_OUI_SIZE (4) +#define CSR_RSN_VERSION_SUPPORTED (1) +#define CSR_RSN_MAX_AUTH_SUITES (4) +#define CSR_RSN_MAX_CYPHERS (5) +#define CSR_RSN_MAX_UNICAST_CYPHERS (5) +#define CSR_RSN_MAX_MULTICAST_CYPHERS (1) + +#define CSR_WPA_OUI_SIZE (4) +#define CSR_WPA_VERSION_SUPPORTED (1) +#define CSR_WME_OUI_SIZE (4) +#define CSR_WPA_MAX_AUTH_SUITES (2) +#define CSR_WPA_MAX_CYPHERS (5) +#define CSR_WPA_MAX_UNICAST_CYPHERS (5) +#define CSR_WPA_MAX_MULTICAST_CYPHERS (1) +/* minimum size of the IE->length is the size of the Oui + Version. */ +#define CSR_WPA_IE_MIN_SIZE (6) +#define CSR_WPA_IE_MIN_SIZE_W_MULTICAST (HDD_WPA_IE_MIN_SIZE + HDD_WPA_OUI_SIZE) +#define CSR_WPA_IE_MIN_SIZE_W_UNICAST (HDD_WPA_IE_MIN_SIZE + \ + HDD_WPA_OUI_SIZE + sizeof(pWpaIe->cUnicastCyphers)) + +#define CSR_DOT11_SUPPORTED_RATES_MAX (12) +#define CSR_DOT11_EXTENDED_SUPPORTED_RATES_MAX (8) + +#define CSR_DOT11_BASIC_RATE_MASK (0x80) + +#define CSR_OUI_USE_GROUP_CIPHER_INDEX 0x00 +#define CSR_OUI_WEP40_OR_1X_INDEX 0x01 +#define CSR_OUI_TKIP_OR_PSK_INDEX 0x02 +#define CSR_OUI_RESERVED_INDEX 0x03 +#define CSR_OUI_AES_INDEX 0x04 +#define CSR_OUI_WEP104_INDEX 0x05 + +#ifdef FEATURE_WLAN_WAPI +#define CSR_OUI_WAPI_RESERVED_INDEX 0x00 +#define CSR_OUI_WAPI_WAI_CERT_OR_SMS4_INDEX 0x01 +#define CSR_OUI_WAPI_WAI_PSK_INDEX 0x02 +/* max idx, should be last & highest */ +#define CSR_OUI_WAPI_WAI_MAX_INDEX 0x03 +#endif /* FEATURE_WLAN_WAPI */ + +typedef enum { + /* 11b rates */ + eCsrSuppRate_1Mbps = 1 * 2, + eCsrSuppRate_2Mbps = 2 * 2, + eCsrSuppRate_5_5Mbps = 11, /* 5.5 * 2 */ + eCsrSuppRate_11Mbps = 11 * 2, + + /* 11a / 11g rates */ + eCsrSuppRate_6Mbps = 6 * 2, + eCsrSuppRate_9Mbps = 9 * 2, + eCsrSuppRate_12Mbps = 12 * 2, + eCsrSuppRate_18Mbps = 18 * 2, + eCsrSuppRate_24Mbps = 24 * 2, + eCsrSuppRate_36Mbps = 36 * 2, + eCsrSuppRate_48Mbps = 48 * 2, + eCsrSuppRate_54Mbps = 54 * 2, + + /* airgo proprietary rates */ + eCsrSuppRate_10Mbps = 10 * 2, + eCsrSuppRate_10_5Mbps = 21, /* 10.5 * 2 */ + eCsrSuppRate_20Mbps = 20 * 2, + eCsrSuppRate_21Mbps = 21 * 2, + eCsrSuppRate_40Mbps = 40 * 2, + eCsrSuppRate_42Mbps = 42 * 2, + eCsrSuppRate_60Mbps = 60 * 2, + eCsrSuppRate_63Mbps = 63 * 2, + eCsrSuppRate_72Mbps = 72 * 2, + eCsrSuppRate_80Mbps = 80 * 2, + eCsrSuppRate_84Mbps = 84 * 2, + eCsrSuppRate_96Mbps = 96 * 2, + eCsrSuppRate_108Mbps = 108 * 2, + eCsrSuppRate_120Mbps = 120 * 2, + eCsrSuppRate_126Mbps = 126 * 2, + eCsrSuppRate_144Mbps = 144 * 2, + eCsrSuppRate_160Mbps = 160 * 2, + eCsrSuppRate_168Mbps = 168 * 2, + eCsrSuppRate_192Mbps = 192 * 2, + eCsrSuppRate_216Mbps = 216 * 2, + eCsrSuppRate_240Mbps = 240 * 2 +} eCsrSupportedRates; + +/* Generic Information Element Structure */ +typedef struct sDot11IEHeader { + uint8_t ElementID; + uint8_t Length; +} qdf_packed tDot11IEHeader; + +typedef struct tagCsrWpaIe { + tDot11IEHeader IeHeader; + uint8_t Oui[CSR_WPA_OUI_SIZE]; + uint16_t Version; + uint8_t MulticastOui[CSR_WPA_OUI_SIZE]; + uint16_t cUnicastCyphers; + struct { + uint8_t Oui[CSR_WPA_OUI_SIZE]; + } qdf_packed UnicastOui[1]; +} qdf_packed tCsrWpaIe; + +typedef struct tagCsrWpaAuthIe { + uint16_t cAuthenticationSuites; + struct { + uint8_t Oui[CSR_WPA_OUI_SIZE]; + } qdf_packed AuthOui[1]; +} qdf_packed tCsrWpaAuthIe; + +typedef struct tagCsrRSNIe { + tDot11IEHeader IeHeader; + uint16_t Version; + uint8_t MulticastOui[CSR_RSN_OUI_SIZE]; + uint16_t cUnicastCyphers; + struct { + uint8_t Oui[CSR_RSN_OUI_SIZE]; + } qdf_packed UnicastOui[1]; +} qdf_packed tCsrRSNIe; + +typedef struct tagCsrRSNAuthIe { + uint16_t cAuthenticationSuites; + struct { + uint8_t Oui[CSR_RSN_OUI_SIZE]; + } qdf_packed AuthOui[1]; +} qdf_packed tCsrRSNAuthIe; + +typedef struct tagCsrRSNCapabilities { + uint16_t PreAuthSupported:1; + uint16_t NoPairwise:1; + uint16_t PTKSAReplayCounter:2; + uint16_t GTKSAReplayCounter:2; + uint16_t MFPRequired:1; + uint16_t MFPCapable:1; + uint16_t Reserved:8; +} qdf_packed tCsrRSNCapabilities; + +typedef struct tagCsrRSNPMKIe { + uint16_t cPMKIDs; + struct { + uint8_t PMKID[CSR_RSN_PMKID_SIZE]; + } qdf_packed PMKIDList[1]; +} qdf_packed tCsrRSNPMKIe; + +typedef struct tCsrIELenInfo { + uint8_t min; + uint8_t max; +} qdf_packed tCsrIELenInfo; + +#ifdef FEATURE_WLAN_WAPI +typedef struct tagCsrWapiIe { + tDot11IEHeader IeHeader; + uint16_t Version; + uint16_t cAuthenticationSuites; + struct { + uint8_t Oui[CSR_WAPI_OUI_SIZE]; + } qdf_packed AuthOui[1]; + uint16_t cUnicastCyphers; + struct { + uint8_t Oui[CSR_WAPI_OUI_SIZE]; + } qdf_packed UnicastOui[1]; + uint8_t MulticastOui[CSR_WAPI_OUI_SIZE]; + struct { + uint16_t PreAuthSupported:1; + uint16_t Reserved:15; + } qdf_packed tCsrWapiCapabilities; +} qdf_packed tCsrWapiIe; +#endif /* FEATURE_WLAN_WAPI */ + +typedef struct tagRoamingTimerInfo { + tpAniSirGlobal pMac; + uint8_t sessionId; +} tCsrTimerInfo; + +#define CSR_IS_11A_BSS(pBssDesc) (eSIR_11A_NW_TYPE == (pBssDesc)->nwType) +#define CSR_IS_BASIC_RATE(rate) ((rate) & CSR_DOT11_BASIC_RATE_MASK) +#define CSR_IS_QOS_BSS(pIes) \ + ((pIes)->WMMParams.present || (pIes)->WMMInfoAp.present) +#define CSR_IS_UAPSD_BSS(pIes) \ + (((pIes)->WMMParams.present && \ + ((pIes)->WMMParams.qosInfo & SME_QOS_AP_SUPPORTS_APSD)) || \ + ((pIes)->WMMInfoAp.present && (pIes)->WMMInfoAp.uapsd)) + +bool csr_get_bss_id_bss_desc(tHalHandle hHal, tSirBssDescription *pSirBssDesc, + struct qdf_mac_addr *pBssId); +bool csr_is_bss_id_equal(tHalHandle hHal, tSirBssDescription *pSirBssDesc1, + tSirBssDescription *pSirBssDesc2); +eCsrMediaAccessType csr_get_qo_s_from_bss_desc(tHalHandle hHal, + tSirBssDescription *pSirBssDesc, + tDot11fBeaconIEs *pIes); +bool csr_is_nullssid(uint8_t *pBssSsid, uint8_t len); +bool csr_is_infra_bss_desc(tSirBssDescription *pSirBssDesc); +bool csr_is_ibss_bss_desc(tSirBssDescription *pSirBssDesc); +bool csr_is_privacy(tSirBssDescription *pSirBssDesc); +tSirResultCodes csr_get_disassoc_rsp_status_code(tSirSmeDisassocRsp * + pSmeDisassocRsp); +tSirResultCodes csr_get_de_auth_rsp_status_code(tSirSmeDeauthRsp *pSmeRsp); +uint32_t csr_get_frag_thresh(tHalHandle hHal); +uint32_t csr_get_rts_thresh(tHalHandle hHal); +eCsrPhyMode csr_get_phy_mode_from_bssDesc(tSirBssDescription *pSirBssDesc); +uint32_t csr_get11h_power_constraint(tHalHandle hHal, + tDot11fIEPowerConstraints *pPowerConstraint); +uint8_t csr_construct_rsn_ie(tHalHandle hHal, uint32_t sessionId, + tCsrRoamProfile *pProfile, + tSirBssDescription *pSirBssDesc, + tDot11fBeaconIEs *pIes, tCsrRSNIe *pRSNIe); +uint8_t csr_construct_wpa_ie(tHalHandle hHal, tCsrRoamProfile *pProfile, + tSirBssDescription *pSirBssDesc, + tDot11fBeaconIEs *pIes, tCsrWpaIe *pWpaIe); +#ifdef FEATURE_WLAN_WAPI +bool csr_is_profile_wapi(tCsrRoamProfile *pProfile); +#endif /* FEATURE_WLAN_WAPI */ +/* + * If a WPAIE exists in the profile, just use it. + * Or else construct one from the BSS Caller allocated memory for pWpaIe and + * guarrantee it can contain a max length WPA IE + */ +uint8_t csr_retrieve_wpa_ie(tHalHandle hHal, tCsrRoamProfile *pProfile, + tSirBssDescription *pSirBssDesc, + tDot11fBeaconIEs *pIes, tCsrWpaIe *pWpaIe); +bool csr_is_ssid_equal(tHalHandle hHal, tSirBssDescription *pSirBssDesc1, + tSirBssDescription *pSirBssDesc2, + tDot11fBeaconIEs *pIes2); +/* Null ssid means match */ +bool csr_is_ssid_in_list(tHalHandle hHal, tSirMacSSid *pSsid, + tCsrSSIDs *pSsidList); +bool csr_is_profile_wpa(tCsrRoamProfile *pProfile); +bool csr_is_profile_rsn(tCsrRoamProfile *pProfile); +/* + * If a RSNIE exists in the profile, just use it. Or + * else construct one from the BSS Caller allocated memory for pWpaIe and + * guarrantee it can contain a max length WPA IE + */ +uint8_t csr_retrieve_rsn_ie(tHalHandle hHal, uint32_t sessionId, + tCsrRoamProfile *pProfile, + tSirBssDescription *pSirBssDesc, + tDot11fBeaconIEs *pIes, tCsrRSNIe *pRsnIe); +#ifdef FEATURE_WLAN_WAPI +/* + * If a WAPI IE exists in the profile, just use it. + * Or else construct one from the BSS. Caller allocated memory for pWapiIe and + * guarrantee it can contain a max length WAPI IE + */ +uint8_t csr_retrieve_wapi_ie(tHalHandle hHal, uint32_t sessionId, + tCsrRoamProfile *pProfile, + tSirBssDescription *pSirBssDesc, + tDot11fBeaconIEs *pIes, tCsrWapiIe *pWapiIe); +#endif /* FEATURE_WLAN_WAPI */ +bool csr_rates_is_dot11_rate11b_supported_rate(uint8_t dot11Rate); +bool csr_rates_is_dot11_rate11a_supported_rate(uint8_t dot11Rate); +tAniEdType csr_translate_encrypt_type_to_ed_type( + eCsrEncryptionType EncryptType); +/* + * pIes shall contain IEs from pSirBssDesc. + * It shall be returned from function csr_get_parsed_bss_description_ies + */ +bool csr_is_security_match(tHalHandle hHal, tCsrAuthList *authType, + tCsrEncryptionList *pUCEncryptionType, + tCsrEncryptionList *pMCEncryptionType, bool *pMFPEnabled, + uint8_t *pMFPRequired, uint8_t *pMFPCapable, + tSirBssDescription *pSirBssDesc, tDot11fBeaconIEs *pIes, + eCsrAuthType *negotiatedAuthtype, + eCsrEncryptionType *negotiatedUCCipher, + eCsrEncryptionType *negotiatedMCCipher); +bool csr_is_bss_type_match(eCsrRoamBssType bssType1, eCsrRoamBssType bssType2); +bool csr_is_bss_type_ibss(eCsrRoamBssType bssType); +/* + * ppIes can be NULL. If caller want to get the *ppIes allocated by + * this function, pass in *ppIes = NULL. Caller needs to free the memory + * in this case + */ +bool csr_match_bss(tHalHandle hHal, tSirBssDescription *pBssDesc, + tCsrScanResultFilter *pFilter, eCsrAuthType *pNegAuth, + eCsrEncryptionType *pNegUc, eCsrEncryptionType *pNegMc, + tDot11fBeaconIEs **ppIes); +bool csr_is_bssid_match(tHalHandle hHal, struct qdf_mac_addr *pProfBssid, + struct qdf_mac_addr *BssBssid); +bool csr_match_bss_to_connect_profile(tHalHandle hHal, + tCsrRoamConnectedProfile *pProfile, + tSirBssDescription *pBssDesc, tDot11fBeaconIEs *pIes); +void csr_add_rate_bitmap(uint8_t rate, uint16_t *pRateBitmap); +bool csr_check_rate_bitmap(uint8_t rate, uint16_t RateBitmap); +bool csr_rates_is_dot11_rate_supported(tHalHandle hHal, uint8_t rate); +uint16_t csr_rates_find_best_rate(tSirMacRateSet *pSuppRates, + tSirMacRateSet *pExtRates, tSirMacPropRateSet *pPropRates); +tSirBssType csr_translate_bsstype_to_mac_type(eCsrRoamBssType csrtype); +/* Caller allocates memory for pIEStruct */ +QDF_STATUS csr_parse_bss_description_ies(tHalHandle hHal, + tSirBssDescription *pBssDesc, tDot11fBeaconIEs *pIEStruct); +/* + * This function will allocate memory for the parsed IEs to the caller. + * Caller must free the memory. after it is done with the data only if + * this function succeeds + */ +QDF_STATUS csr_get_parsed_bss_description_ies(tHalHandle hHal, + tSirBssDescription *pBssDesc, tDot11fBeaconIEs **ppIEStruct); + +bool csrValidateCountryString(tHalHandle hHal, uint8_t *pCountryString); +tSirScanType csr_get_scan_type(tpAniSirGlobal pMac, uint8_t chnId); +uint8_t csr_to_upper(uint8_t ch); +QDF_STATUS csr_get_phy_mode_from_bss(tpAniSirGlobal pMac, + tSirBssDescription *pBSSDescription, + eCsrPhyMode *pPhyMode, tDot11fBeaconIEs *pIes); +/* + * fForce -- force reassoc regardless of whether there is any change. + * The reason is that for UAPSD-bypass, the code underneath this call determine + * whether to allow UAPSD. The information in pModProfileFields reflects what + * the user wants. There may be discrepency in it. UAPSD-bypass logic should + * decide if it needs to reassoc + */ +QDF_STATUS csr_reassoc(tpAniSirGlobal pMac, uint32_t sessionId, + tCsrRoamModifyProfileFields *pModProfileFields, + uint32_t *pRoamId, bool fForce); + +/* BeaconInterval validation for MCC support */ +QDF_STATUS csr_validate_mcc_beacon_interval(tpAniSirGlobal pMac, uint8_t channelId, + uint16_t *beaconInterval, uint32_t cursessionId, + enum tQDF_ADAPTER_MODE currBssPersona); +bool csr_is_profile11r(tCsrRoamProfile *pProfile); +bool csr_is_auth_type11r(eCsrAuthType AuthType, uint8_t mdiePresent); +#ifdef FEATURE_WLAN_ESE +bool csr_is_auth_type_ese(eCsrAuthType AuthType); +bool csr_is_profile_ese(tCsrRoamProfile *pProfile); +#endif + +#endif diff --git a/drivers/staging/qcacld-3.0/core/sme/inc/nan_api.h b/drivers/staging/qcacld-3.0/core/sme/inc/nan_api.h new file mode 100644 index 0000000000000000000000000000000000000000..759dd407849a56a79de02bf372ff2e359b754594 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/sme/inc/nan_api.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2014-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * + * Name: nan_api.h + * + * Description: NAN FSM defines. + * + */ + +#ifndef __NAN_API_H__ +#define __NAN_API_H__ + +#include "qdf_types.h" + +typedef void (*nan_callback)(void *, tSirNanEvent *); + +#ifdef WLAN_FEATURE_NAN +typedef struct sNanRequestReq { + uint16_t request_data_len; + const uint8_t *request_data; +} tNanRequestReq, *tpNanRequestReq; + +void sme_nan_register_callback(tHalHandle hHal, nan_callback callback); +void sme_nan_deregister_callback(tHalHandle hHal); +QDF_STATUS sme_nan_request(tpNanRequestReq input); +#else +static inline void sme_nan_register_callback(tHalHandle hHal, + nan_callback callback) +{ +} +static inline void sme_nan_deregister_callback(tHalHandle hHal) +{ +} +#endif /* WLAN_FEATURE_NAN */ + +#endif /* __NAN_API_H__ */ diff --git a/drivers/staging/qcacld-3.0/core/sme/inc/p2p_api.h b/drivers/staging/qcacld-3.0/core/sme/inc/p2p_api.h new file mode 100644 index 0000000000000000000000000000000000000000..df356869484658f90061a131bfd4ced9486b454b --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/sme/inc/p2p_api.h @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2011-2012, 2014-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * + * Name: p2p_api.h + * + * Description: P2P FSM defines. + * + * + */ + +#ifndef __P2P_API_H__ +#define __P2P_API_H__ + +#include "qdf_types.h" +#include "qdf_mc_timer.h" +#include "qdf_lock.h" + +typedef struct sP2pPsConfig { + uint8_t opp_ps; + uint32_t ctWindow; + uint8_t count; + uint32_t duration; + uint32_t interval; + uint32_t single_noa_duration; + uint8_t psSelection; + uint8_t sessionid; +} tP2pPsConfig, *tpP2pPsConfig; + +typedef QDF_STATUS (*remainOnChanCallback)(tHalHandle, void *context, + QDF_STATUS status, uint32_t scan_id); + +typedef struct sRemainOnChn { + uint8_t chn; + uint32_t duration; + remainOnChanCallback callback; + void *pCBContext; +} tRemainOnChn, tpRemainOnChn; + +#define SIZE_OF_NOA_DESCRIPTOR 13 +#define MAX_NOA_PERIOD_IN_MICROSECS 3000000 + +#define P2P_CLEAR_POWERSAVE 0 +#define P2P_OPPORTUNISTIC_PS 1 +#define P2P_PERIODIC_NOA 2 +#define P2P_SINGLE_NOA 4 + +typedef struct sp2pContext { + v_CONTEXT_t cds_context; + tHalHandle hHal; + uint8_t sessionId; /* Session id corresponding to P2P */ + uint8_t SMEsessionId; + uint8_t probeReqForwarding; + uint8_t *probeRspIe; + uint32_t probeRspIeLength; +} tp2pContext, *tPp2pContext; + +QDF_STATUS sme_remain_on_chn_rsp(tpAniSirGlobal pMac, uint8_t *pMsg); +QDF_STATUS sme_remain_on_chn_ready(tHalHandle hHal, uint8_t *pMsg); +QDF_STATUS sme_remain_on_channel(tHalHandle hHal, uint8_t sessionId, + uint8_t channel, uint32_t duration, + remainOnChanCallback callback, + void *pContext, uint8_t isP2PProbeReqAllowed, + uint32_t *scan_id); +QDF_STATUS sme_report_probe_req(tHalHandle hHal, uint8_t flag); +QDF_STATUS sme_update_p2p_ie(tHalHandle hHal, void *p2pIe, + uint32_t p2pIeLength); +QDF_STATUS sme_send_action(tHalHandle hHal, uint8_t sessionId, + const uint8_t *pBuf, uint32_t len, uint16_t wait, bool noack, + uint16_t channel_freq); +QDF_STATUS sme_cancel_remain_on_channel(tHalHandle hHal, + uint8_t sessionId, uint32_t scan_id); +QDF_STATUS sme_p2p_open(tHalHandle hHal); +QDF_STATUS p2p_stop(tHalHandle hHal); +QDF_STATUS sme_p2p_close(tHalHandle hHal); +QDF_STATUS sme_p2p_set_ps(tHalHandle hHal, tP2pPsConfig *data); +QDF_STATUS p2p_remain_on_channel(tHalHandle hHal, uint8_t sessionId, + uint8_t channel, uint32_t duration, + remainOnChanCallback callback, + void *pContext, uint8_t isP2PProbeReqAllowed, + uint32_t scan_id); +QDF_STATUS p2p_send_action(tHalHandle hHal, uint8_t sessionId, + const uint8_t *pBuf, uint32_t len, uint16_t wait, bool noack, + uint16_t channel_freq); +QDF_STATUS p2p_cancel_remain_on_channel(tHalHandle hHal, + uint8_t sessionId, uint32_t scan_id); +QDF_STATUS p2p_set_ps(tHalHandle hHal, tP2pPsConfig *pNoA); +tSirRFBand get_rf_band(uint8_t channel); +#endif /* __P2P_API_H__ */ diff --git a/drivers/staging/qcacld-3.0/core/sme/inc/sme_api.h b/drivers/staging/qcacld-3.0/core/sme/inc/sme_api.h new file mode 100644 index 0000000000000000000000000000000000000000..a30902d548c0009d08f4ad1a6a2250e37f15be75 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/sme/inc/sme_api.h @@ -0,0 +1,1582 @@ +/* + * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#if !defined(__SME_API_H) +#define __SME_API_H + +/** + * file smeApi.h + * + * brief prototype for SME APIs + */ + +/*-------------------------------------------------------------------------- + Include Files + ------------------------------------------------------------------------*/ +#include "csr_api.h" +#include "cds_mq.h" +#include "qdf_lock.h" +#include "qdf_types.h" +#include "sir_api.h" +#include "cds_reg_service.h" +#include "p2p_api.h" +#include "cds_regdomain.h" +#include "sme_internal.h" +#include "wma_tgt_cfg.h" + +#include "sme_rrm_internal.h" +#include "sir_types.h" +/*-------------------------------------------------------------------------- + Preprocessor definitions and constants + ------------------------------------------------------------------------*/ + +#define SME_SUMMARY_STATS 1 +#define SME_GLOBAL_CLASSA_STATS 2 +#define SME_GLOBAL_CLASSB_STATS 4 +#define SME_GLOBAL_CLASSC_STATS 8 +#define SME_GLOBAL_CLASSD_STATS 16 +#define SME_PER_STA_STATS 32 +#define SME_PER_CHAIN_RSSI_STATS 64 + +#define SME_SESSION_ID_ANY 50 + +#define SME_INVALID_COUNTRY_CODE "XX" + +#define SME_SET_CHANNEL_REG_POWER(reg_info_1, val) do { \ + reg_info_1 &= 0xff00ffff; \ + reg_info_1 |= ((val & 0xff) << 16); \ +} while (0) + +#define SME_SET_CHANNEL_MAX_TX_POWER(reg_info_2, val) do { \ + reg_info_2 &= 0xffff00ff; \ + reg_info_2 |= ((val & 0xff) << 8); \ +} while (0) + +#define SME_CONFIG_TO_ROAM_CONFIG 1 +#define ROAM_CONFIG_TO_SME_CONFIG 2 + +#define NUM_OF_BANDS 2 + +#define SME_ACTIVE_LIST_CMD_TIMEOUT_VALUE (30*1000) +#define SME_CMD_TIMEOUT_VALUE (SME_ACTIVE_LIST_CMD_TIMEOUT_VALUE + 1000) + +#define sme_err(format, args...) \ + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, FL(format), ## args) + +/*-------------------------------------------------------------------------- + Type declarations + ------------------------------------------------------------------------*/ +typedef void (*hdd_ftm_msg_processor)(void *); +typedef struct _smeConfigParams { + tCsrConfigParam csrConfig; + struct rrm_config_param rrmConfig; +} tSmeConfigParams, *tpSmeConfigParams; + +#ifdef FEATURE_WLAN_TDLS +#define SME_TDLS_MAX_SUPP_CHANNELS 128 +#define SME_TDLS_MAX_SUPP_OPER_CLASSES 32 + +typedef struct _smeTdlsPeerCapParams { + uint8_t isPeerResponder; + uint8_t peerUapsdQueue; + uint8_t peerMaxSp; + uint8_t peerBuffStaSupport; + uint8_t peerOffChanSupport; + uint8_t peerCurrOperClass; + uint8_t selfCurrOperClass; + uint8_t peerChanLen; + uint8_t peerChan[SME_TDLS_MAX_SUPP_CHANNELS]; + uint8_t peerOperClassLen; + uint8_t peerOperClass[SME_TDLS_MAX_SUPP_OPER_CLASSES]; + uint8_t prefOffChanNum; + uint8_t prefOffChanBandwidth; + uint8_t opClassForPrefOffChan; +} tSmeTdlsPeerCapParams; + +/** + * eSmeTdlsPeerState - tdls peer state + * @eSME_TDLS_PEER_STATE_PEERING: tdls connection in progress + * @eSME_TDLS_PEER_STATE_CONNECTED: tdls peer is connected + * @eSME_TDLS_PEER_STATE_TEARDOWN: tdls peer is tear down + * @eSME_TDLS_PEER_ADD_MAC_ADDR: add peer mac into connection table + * @eSME_TDLS_PEER_REMOVE_MAC_ADDR: remove peer mac from connection table + */ +typedef enum { + eSME_TDLS_PEER_STATE_PEERING, + eSME_TDLS_PEER_STATE_CONNECTED, + eSME_TDLS_PEER_STATE_TEARDOWN, + eSME_TDLS_PEER_ADD_MAC_ADDR, + eSME_TDLS_PEER_REMOVE_MAC_ADDR, +} eSmeTdlsPeerState; + +typedef struct _smeTdlsPeerStateParams { + uint32_t vdevId; + tSirMacAddr peerMacAddr; + uint32_t peerState; + tSmeTdlsPeerCapParams peerCap; +} tSmeTdlsPeerStateParams; + +#define ENABLE_CHANSWITCH 1 +#define DISABLE_CHANSWITCH 2 +#define BW_20_OFFSET_BIT 0 +#define BW_40_OFFSET_BIT 1 +#define BW_80_OFFSET_BIT 2 +#define BW_160_OFFSET_BIT 3 +typedef struct sme_tdls_chan_switch_params_struct { + uint32_t vdev_id; + tSirMacAddr peer_mac_addr; + uint16_t tdls_off_ch_bw_offset;/* Target Off Channel Bandwidth offset */ + uint8_t tdls_off_channel; /* Target Off Channel */ + uint8_t tdls_off_ch_mode; /* TDLS Off Channel Mode */ + uint8_t is_responder; /* is peer responder or initiator */ + uint8_t opclass; /* tdls operating class */ +} sme_tdls_chan_switch_params; +#endif /* FEATURE_WLAN_TDLS */ + +/* Thermal Mitigation*/ +typedef struct { + uint16_t smeMinTempThreshold; + uint16_t smeMaxTempThreshold; +} tSmeThermalLevelInfo; + +#define SME_MAX_THERMAL_LEVELS (4) +#define SME_MAX_THROTTLE_LEVELS (4) + +typedef struct { + /* Array of thermal levels */ + tSmeThermalLevelInfo smeThermalLevels[SME_MAX_THERMAL_LEVELS]; + uint8_t smeThermalMgmtEnabled; + uint32_t smeThrottlePeriod; + uint8_t sme_throttle_duty_cycle_tbl[SME_MAX_THROTTLE_LEVELS]; +} tSmeThermalParams; + +typedef enum { + SME_AC_BK = 0, + SME_AC_BE = 1, + SME_AC_VI = 2, + SME_AC_VO = 3 +} sme_ac_enum_type; + +/* TSPEC Direction Enum Type */ +typedef enum { + /* uplink */ + SME_TX_DIR = 0, + /* downlink */ + SME_RX_DIR = 1, + /* bidirectional */ + SME_BI_DIR = 2, +} sme_tspec_dir_type; + +/** + * struct sme_oem_capability - OEM capability to be exchanged between host + * and userspace + * @ftm_rr: FTM range report capability bit + * @lci_capability: LCI capability bit + * @reserved1: reserved + * @reserved2: reserved + */ +struct sme_oem_capability { + uint32_t ftm_rr:1; + uint32_t lci_capability:1; + uint32_t reserved1:30; + uint32_t reserved2; +}; + +/** + * struct sme_5g_pref_params : 5G preference params to be read from ini + * @rssi_boost_threshold_5g: RSSI threshold above which 5 GHz is favored + * @rssi_boost_factor_5g: Factor by which 5GHz RSSI is boosted + * @max_rssi_boost_5g: Maximum boost that can be applied to 5GHz RSSI + * @rssi_penalize_threshold_5g: RSSI threshold below which 5G is not favored + * @rssi_penalize_factor_5g: Factor by which 5GHz RSSI is penalized + * @max_rssi_penalize_5g: Maximum penalty that can be applied to 5G RSSI + */ +struct sme_5g_band_pref_params { + int8_t rssi_boost_threshold_5g; + uint8_t rssi_boost_factor_5g; + uint8_t max_rssi_boost_5g; + int8_t rssi_penalize_threshold_5g; + uint8_t rssi_penalize_factor_5g; + uint8_t max_rssi_penalize_5g; +}; + +/*------------------------------------------------------------------------- + Function declarations and documenation + ------------------------------------------------------------------------*/ +QDF_STATUS sme_open(tHalHandle hHal); +QDF_STATUS sme_init_chan_list(tHalHandle hal, uint8_t *alpha2, + enum country_src cc_src); +QDF_STATUS sme_close(tHalHandle hHal); +QDF_STATUS sme_start(tHalHandle hHal); +QDF_STATUS sme_stop(tHalHandle hHal, tHalStopType stopType); +QDF_STATUS sme_open_session(tHalHandle hHal, csr_roam_completeCallback callback, + void *pContext, uint8_t *pSelfMacAddr, + uint8_t *pbSessionId, uint32_t type, + uint32_t subType); +void sme_set_curr_device_mode(tHalHandle hHal, + enum tQDF_ADAPTER_MODE currDeviceMode); +QDF_STATUS sme_close_session(tHalHandle hHal, uint8_t sessionId, + csr_roamSessionCloseCallback callback, + void *pContext); +QDF_STATUS sme_update_roam_params(tHalHandle hHal, uint8_t session_id, + struct roam_ext_params roam_params_src, int update_param); +#ifdef FEATURE_WLAN_SCAN_PNO +void sme_update_roam_pno_channel_prediction_config( + tHalHandle hal, tCsrConfigParam *csr_config, + uint8_t copy_from_to); +#else +static inline void sme_update_roam_pno_channel_prediction_config( + tHalHandle hal, tCsrConfigParam *csr_config, + uint8_t copy_from_to) +{} +#endif +QDF_STATUS sme_update_config(tHalHandle hHal, + tpSmeConfigParams pSmeConfigParams); + +QDF_STATUS sme_set11dinfo(tHalHandle hHal, tpSmeConfigParams pSmeConfigParams); +QDF_STATUS sme_get_soft_ap_domain(tHalHandle hHal, + v_REGDOMAIN_t *domainIdSoftAp); +QDF_STATUS sme_set_reg_info(tHalHandle hHal, uint8_t *apCntryCode); +QDF_STATUS sme_hdd_ready_ind(tHalHandle hHal); +QDF_STATUS sme_process_msg(tHalHandle hHal, cds_msg_t *pMsg); +void sme_free_msg(tHalHandle hHal, cds_msg_t *pMsg); +QDF_STATUS sme_scan_request(tHalHandle hHal, uint8_t sessionId, + tCsrScanRequest *, csr_scan_completeCallback callback, + void *pContext); +QDF_STATUS sme_scan_get_result(tHalHandle hHal, uint8_t sessionId, + tCsrScanResultFilter *pFilter, + tScanResultHandle *phResult); +QDF_STATUS sme_get_ap_channel_from_scan_cache(tHalHandle hHal, + tCsrRoamProfile *profile, + tScanResultHandle *scan_cache, + uint8_t *ap_chnl_id); +bool sme_store_joinreq_param(tHalHandle hal_handle, + tCsrRoamProfile *profile, + tScanResultHandle scan_cache, + uint32_t *roam_id, + uint32_t session_id); +bool sme_clear_joinreq_param(tHalHandle hal_handle, + uint32_t session_id); +QDF_STATUS sme_issue_stored_joinreq(tHalHandle hal_handle, + uint32_t *roam_id, + uint32_t session_id); +QDF_STATUS sme_scan_flush_result(tHalHandle hHal); +QDF_STATUS sme_filter_scan_results(tHalHandle hHal, uint8_t sessionId); +QDF_STATUS sme_scan_flush_p2p_result(tHalHandle hHal, uint8_t sessionId); +tCsrScanResultInfo *sme_scan_result_get_first(tHalHandle, + tScanResultHandle hScanResult); +tCsrScanResultInfo *sme_scan_result_get_next(tHalHandle, + tScanResultHandle hScanResult); +QDF_STATUS sme_scan_result_purge(tHalHandle hHal, + tScanResultHandle hScanResult); +QDF_STATUS sme_scan_get_pmkid_candidate_list(tHalHandle hHal, uint8_t sessionId, + tPmkidCandidateInfo *pPmkidList, + uint32_t *pNumItems); +QDF_STATUS sme_roam_connect(tHalHandle hHal, uint8_t sessionId, + tCsrRoamProfile *pProfile, uint32_t *pRoamId); +QDF_STATUS sme_roam_reassoc(tHalHandle hHal, uint8_t sessionId, + tCsrRoamProfile *pProfile, + tCsrRoamModifyProfileFields modProfileFields, + uint32_t *pRoamId, bool fForce); +QDF_STATUS sme_roam_connect_to_last_profile(tHalHandle hHal, uint8_t sessionId); +QDF_STATUS sme_roam_disconnect(tHalHandle hHal, uint8_t sessionId, + eCsrRoamDisconnectReason reason); +void sme_dhcp_done_ind(tHalHandle hal, uint8_t session_id); +QDF_STATUS sme_roam_stop_bss(tHalHandle hHal, uint8_t sessionId); +QDF_STATUS sme_roam_get_associated_stas(tHalHandle hHal, uint8_t sessionId, + QDF_MODULE_ID modId, void *pUsrContext, + void *pfnSapEventCallback, + uint8_t *pAssocStasBuf); +QDF_STATUS sme_roam_disconnect_sta(tHalHandle hHal, uint8_t sessionId, + struct tagCsrDelStaParams *p_del_sta_params); +QDF_STATUS sme_roam_deauth_sta(tHalHandle hHal, uint8_t sessionId, + struct tagCsrDelStaParams *pDelStaParams); +QDF_STATUS sme_roam_tkip_counter_measures(tHalHandle hHal, uint8_t sessionId, + bool bEnable); +QDF_STATUS sme_roam_get_wps_session_overlap(tHalHandle hHal, uint8_t sessionId, + void *pUsrContext, + void *pfnSapEventCallback, + struct qdf_mac_addr pRemoveMac); +QDF_STATUS sme_roam_get_connect_state(tHalHandle hHal, uint8_t sessionId, + eCsrConnectState *pState); +QDF_STATUS sme_roam_get_connect_profile(tHalHandle hHal, uint8_t sessionId, + tCsrRoamConnectedProfile *pProfile); +void sme_roam_free_connect_profile(tCsrRoamConnectedProfile *profile); +QDF_STATUS sme_roam_set_pmkid_cache(tHalHandle hHal, uint8_t sessionId, + tPmkidCacheInfo *pPMKIDCache, + uint32_t numItems, + bool update_entire_cache); + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +QDF_STATUS sme_roam_set_psk_pmk(tHalHandle hHal, uint8_t sessionId, + uint8_t *pPSK_PMK, size_t pmk_len); +#endif +QDF_STATUS sme_roam_get_security_req_ie(tHalHandle hHal, uint8_t sessionId, + uint32_t *pLen, uint8_t *pBuf, + eCsrSecurityType secType); +QDF_STATUS sme_roam_get_security_rsp_ie(tHalHandle hHal, uint8_t sessionId, + uint32_t *pLen, uint8_t *pBuf, + eCsrSecurityType secType); +uint32_t sme_roam_get_num_pmkid_cache(tHalHandle hHal, uint8_t sessionId); +QDF_STATUS sme_roam_get_pmkid_cache(tHalHandle hHal, uint8_t sessionId, + uint32_t *pNum, + tPmkidCacheInfo *pPmkidCache); +QDF_STATUS sme_get_config_param(tHalHandle hHal, tSmeConfigParams *pParam); +QDF_STATUS sme_get_statistics(tHalHandle hHal, + eCsrStatsRequesterType requesterId, + uint32_t statsMask, tCsrStatsCallback callback, + uint32_t periodicity, bool cache, uint8_t staId, + void *pContext, uint8_t sessionId); +QDF_STATUS sme_get_rssi(tHalHandle hHal, + tCsrRssiCallback callback, + uint8_t staId, struct qdf_mac_addr bssId, int8_t lastRSSI, + void *pContext, void *p_cds_context); +QDF_STATUS sme_get_snr(tHalHandle hHal, + tCsrSnrCallback callback, + uint8_t staId, struct qdf_mac_addr bssId, void *pContext); +#ifdef FEATURE_WLAN_ESE +QDF_STATUS sme_get_tsm_stats(tHalHandle hHal, + tCsrTsmStatsCallback callback, + uint8_t staId, struct qdf_mac_addr bssId, + void *pContext, void *p_cds_context, uint8_t tid); +QDF_STATUS sme_set_cckm_ie(tHalHandle hHal, + uint8_t sessionId, + uint8_t *pCckmIe, uint8_t cckmIeLen); +QDF_STATUS sme_set_ese_beacon_request(tHalHandle hHal, const uint8_t sessionId, + const tCsrEseBeaconReq *pEseBcnReq); +QDF_STATUS sme_set_plm_request(tHalHandle hHal, tpSirPlmReq pPlm); +#endif /*FEATURE_WLAN_ESE */ +QDF_STATUS sme_cfg_set_int(tHalHandle hal, uint16_t cfg_id, uint32_t value); +QDF_STATUS sme_cfg_set_str(tHalHandle hal, uint16_t cfg_id, uint8_t *str, + uint32_t length); +QDF_STATUS sme_cfg_get_int(tHalHandle hal, uint16_t cfg_id, + uint32_t *cfg_value); +QDF_STATUS sme_cfg_get_str(tHalHandle hal, uint16_t cfg_id, uint8_t *str, + uint32_t *length); +QDF_STATUS sme_get_modify_profile_fields(tHalHandle hHal, uint8_t sessionId, + tCsrRoamModifyProfileFields * + pModifyProfileFields); + +extern QDF_STATUS sme_set_host_power_save(tHalHandle hHal, bool psMode); + +void sme_set_dhcp_till_power_active_flag(tHalHandle hHal, uint8_t flag); +extern QDF_STATUS sme_register11d_scan_done_callback(tHalHandle hHal, + csr_scan_completeCallback); +void sme_deregister11d_scan_done_callback(tHalHandle hHal); + +#ifdef FEATURE_OEM_DATA_SUPPORT +extern QDF_STATUS sme_register_oem_data_rsp_callback(tHalHandle h_hal, + sme_send_oem_data_rsp_msg callback); +void sme_deregister_oem_data_rsp_callback(tHalHandle h_hal); + +#else +static inline QDF_STATUS sme_register_oem_data_rsp_callback(tHalHandle h_hal, + sme_send_oem_data_rsp_msg callback) +{ + return QDF_STATUS_SUCCESS; +} +static inline void sme_deregister_oem_data_rsp_callback(tHalHandle h_hal) +{ +} + +#endif + +extern QDF_STATUS sme_wow_add_pattern(tHalHandle hHal, + struct wow_add_pattern *pattern, uint8_t sessionId); +extern QDF_STATUS sme_wow_delete_pattern(tHalHandle hHal, + struct wow_delete_pattern *pattern, uint8_t sessionId); + +void sme_register_ftm_msg_processor(tHalHandle hal, + hdd_ftm_msg_processor callback); + +extern QDF_STATUS sme_enter_wowl(tHalHandle hHal, + void (*enter_wowl_callback_routine)(void + *callbackContext, + QDF_STATUS status), + void *enter_wowl_callback_context, +#ifdef WLAN_WAKEUP_EVENTS + void (*wake_reason_ind_cb)(void *callbackContext, + tpSirWakeReasonInd + wake_reason_ind), + void *wake_reason_ind_cb_ctx, +#endif /* WLAN_WAKEUP_EVENTS */ + tpSirSmeWowlEnterParams wowl_enter_params, + uint8_t sessionId); + +extern QDF_STATUS sme_exit_wowl(tHalHandle hHal, + tpSirSmeWowlExitParams wowl_exit_params); +QDF_STATUS sme_roam_set_key(tHalHandle, uint8_t sessionId, + tCsrRoamSetKey *pSetKey, uint32_t *pRoamId); +QDF_STATUS sme_get_country_code(tHalHandle hHal, uint8_t *pBuf, uint8_t *pbLen); + + +void sme_apply_channel_power_info_to_fw(tHalHandle hHal); + +/* some support functions */ +bool sme_is11d_supported(tHalHandle hHal); +bool sme_is11h_supported(tHalHandle hHal); +bool sme_is_wmm_supported(tHalHandle hHal); + +typedef void (*tSmeChangeCountryCallback)(void *pContext); +QDF_STATUS sme_change_country_code(tHalHandle hHal, + tSmeChangeCountryCallback callback, + uint8_t *pCountry, + void *pContext, + void *p_cds_context, + tAniBool countryFromUserSpace, + tAniBool sendRegHint); +QDF_STATUS sme_generic_change_country_code(tHalHandle hHal, + uint8_t *pCountry); +QDF_STATUS sme_tx_fail_monitor_start_stop_ind(tHalHandle hHal, + uint8_t tx_fail_count, + void *txFailIndCallback); +QDF_STATUS sme_dhcp_start_ind(tHalHandle hHal, + uint8_t device_mode, + uint8_t *macAddr, uint8_t sessionId); +QDF_STATUS sme_dhcp_stop_ind(tHalHandle hHal, + uint8_t device_mode, + uint8_t *macAddr, uint8_t sessionId); +void sme_set_cfg_privacy(tHalHandle hHal, tCsrRoamProfile *pProfile, + bool fPrivacy); +void sme_get_recovery_stats(tHalHandle hHal); +QDF_STATUS sme_neighbor_report_request(tHalHandle hHal, uint8_t sessionId, + tpRrmNeighborReq pRrmNeighborReq, + tpRrmNeighborRspCallbackInfo callbackInfo); +QDF_STATUS sme_get_wcnss_wlan_compiled_version(tHalHandle hHal, + tSirVersionType * pVersion); +QDF_STATUS sme_get_wcnss_wlan_reported_version(tHalHandle hHal, + tSirVersionType *pVersion); +QDF_STATUS sme_get_wcnss_software_version(tHalHandle hHal, + uint8_t *pVersion, uint32_t versionBufferSize); +QDF_STATUS sme_get_wcnss_hardware_version(tHalHandle hHal, + uint8_t *pVersion, uint32_t versionBufferSize); +#ifdef FEATURE_WLAN_WAPI +QDF_STATUS sme_scan_get_bkid_candidate_list(tHalHandle hHal, uint32_t sessionId, + tBkidCandidateInfo * pBkidList, + uint32_t *pNumItems); +#endif /* FEATURE_WLAN_WAPI */ +#ifdef FEATURE_OEM_DATA_SUPPORT +QDF_STATUS sme_oem_data_req(tHalHandle hHal, struct oem_data_req *); +QDF_STATUS sme_oem_update_capability(tHalHandle hHal, + struct sme_oem_capability *cap); +QDF_STATUS sme_oem_get_capability(tHalHandle hHal, + struct sme_oem_capability *cap); +#endif /*FEATURE_OEM_DATA_SUPPORT */ +QDF_STATUS sme_roam_update_apwpsie(tHalHandle, uint8_t sessionId, + tSirAPWPSIEs * pAPWPSIES); +QDF_STATUS sme_roam_update_apwparsni_es(tHalHandle hHal, uint8_t sessionId, + tSirRSNie *pAPSirRSNie); +QDF_STATUS sme_change_mcc_beacon_interval(tHalHandle hHal, uint8_t sessionId); +QDF_STATUS sme_set_host_offload(tHalHandle hHal, uint8_t sessionId, + tpSirHostOffloadReq pRequest); + +/** + * sme_conf_hw_filter_mode() - configure the given mode for the given session + * @hal: internal hal handle + * @session_id: the Id of the session to configure the hw filter for + * @mode_bitmap: the hw filter mode to configure + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_conf_hw_filter_mode(tHalHandle hal, uint8_t session_id, + uint8_t mode_bitmap); + +QDF_STATUS sme_set_keep_alive(tHalHandle hHal, uint8_t sessionId, + tpSirKeepAliveReq pRequest); +QDF_STATUS sme_get_operation_channel(tHalHandle hHal, uint32_t *pChannel, + uint8_t sessionId); +QDF_STATUS sme_register_mgmt_frame(tHalHandle hHal, uint8_t sessionId, + uint16_t frameType, uint8_t *matchData, + uint16_t matchLen); +QDF_STATUS sme_deregister_mgmt_frame(tHalHandle hHal, uint8_t sessionId, + uint16_t frameType, uint8_t *matchData, + uint16_t matchLen); +QDF_STATUS sme_ConfigureAppsCpuWakeupState(tHalHandle hHal, bool isAppsAwake); +QDF_STATUS sme_configure_suspend_ind(tHalHandle hHal, + uint32_t conn_state_mask, + csr_readyToSuspendCallback, + void *callbackContext); +QDF_STATUS sme_configure_resume_req(tHalHandle hHal, + tpSirWlanResumeParam wlanResumeParam); +#ifdef WLAN_FEATURE_EXTWOW_SUPPORT +QDF_STATUS sme_configure_ext_wow(tHalHandle hHal, + tpSirExtWoWParams wlanExtParams, + csr_readyToSuspendCallback callback, + void *callbackContext); +QDF_STATUS sme_configure_app_type1_params(tHalHandle hHal, + tpSirAppType1Params wlanAppType1Params); +QDF_STATUS sme_configure_app_type2_params(tHalHandle hHal, + tpSirAppType2Params wlanAppType2Params); +#endif +int8_t sme_get_infra_session_id(tHalHandle hHal); +uint8_t sme_get_infra_operation_channel(tHalHandle hHal, uint8_t sessionId); +uint8_t sme_get_concurrent_operation_channel(tHalHandle hHal); +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH +uint16_t sme_check_concurrent_channel_overlap(tHalHandle hHal, uint16_t sap_ch, + eCsrPhyMode sapPhyMode, + uint8_t cc_switch_mode); +#endif +/** + * sme_abort_mac_scan() - API to cancel MAC scan + * @hHal: The handle returned by mac_open + * @sessionId: sessionId on which we need to abort scan + * @scan_id: scan id on which we need to abort scan + * @reason: Reason to abort the scan + * + * This function aborts MAC scan. + * + * Return: QDF_STATUS_E_FAILURE for failure, QDF_STATUS_SUCCESS for + * success + */ +QDF_STATUS sme_abort_mac_scan(tHalHandle hHal, uint8_t sessionId, + uint32_t scan_id, eCsrAbortReason reason); +QDF_STATUS sme_get_cfg_valid_channels(tHalHandle hHal, uint8_t *aValidChannels, + uint32_t *len); +#ifdef FEATURE_WLAN_SCAN_PNO +QDF_STATUS sme_set_preferred_network_list(tHalHandle hHal, + tpSirPNOScanReq pRequest, + uint8_t sessionId, + preferred_network_found_ind_cb + callbackRoutine, void *callbackContext); + +QDF_STATUS sme_preferred_network_found_ind(tHalHandle hHal, void *pMsg); +#endif /* FEATURE_WLAN_SCAN_PNO */ +#ifdef WLAN_FEATURE_PACKET_FILTERING +QDF_STATUS sme_8023_multicast_list(tHalHandle hHal, uint8_t sessionId, + tpSirRcvFltMcAddrList pMulticastAddrs); +QDF_STATUS sme_receive_filter_set_filter(tHalHandle hHal, + tpSirRcvPktFilterCfgType pRcvPktFilterCfg, + uint8_t sessionId); +QDF_STATUS sme_receive_filter_clear_filter(tHalHandle hHal, + tpSirRcvFltPktClearParam pRcvFltPktClearParam, + uint8_t sessionId); +#endif /* WLAN_FEATURE_PACKET_FILTERING */ +bool sme_is_channel_valid(tHalHandle hHal, uint8_t channel); +QDF_STATUS sme_set_freq_band(tHalHandle hHal, uint8_t sessionId, + eCsrBand eBand); +QDF_STATUS sme_get_freq_band(tHalHandle hHal, eCsrBand *pBand); +#ifdef WLAN_FEATURE_GTK_OFFLOAD +QDF_STATUS sme_set_gtk_offload(tHalHandle hal_ctx, + tpSirGtkOffloadParams request, + uint8_t session_id); +QDF_STATUS sme_get_gtk_offload(tHalHandle hal_ctx, + gtk_offload_get_info_callback callback_routine, + void *callback_context, uint8_t session_id); +#endif /* WLAN_FEATURE_GTK_OFFLOAD */ +uint16_t sme_chn_to_freq(uint8_t chanNum); +bool sme_is_channel_valid(tHalHandle hHal, uint8_t channel); +QDF_STATUS sme_set_max_tx_power(tHalHandle hHal, struct qdf_mac_addr pBssid, + struct qdf_mac_addr pSelfMacAddress, int8_t dB); +QDF_STATUS sme_set_max_tx_power_per_band(eCsrBand band, int8_t db); +QDF_STATUS sme_set_tx_power(tHalHandle hHal, uint8_t sessionId, + struct qdf_mac_addr bssid, + enum tQDF_ADAPTER_MODE dev_mode, int power); +QDF_STATUS sme_set_custom_mac_addr(tSirMacAddr customMacAddr); +QDF_STATUS sme_hide_ssid(tHalHandle hHal, uint8_t sessionId, + uint8_t ssidHidden); +QDF_STATUS sme_set_tm_level(tHalHandle hHal, uint16_t newTMLevel, + uint16_t tmMode); +void sme_feature_caps_exchange(tHalHandle hHal); +void sme_disable_feature_capablity(uint8_t feature_index); +void sme_reset_power_values_for5_g(tHalHandle hHal); +QDF_STATUS sme_update_roam_prefer5_g_hz(tHalHandle hHal, bool nRoamPrefer5GHz); +QDF_STATUS sme_set_roam_intra_band(tHalHandle hHal, const bool nRoamIntraBand); +QDF_STATUS sme_update_roam_scan_n_probes(tHalHandle hHal, uint8_t sessionId, + const uint8_t nProbes); +QDF_STATUS sme_update_roam_scan_home_away_time(tHalHandle hHal, + uint8_t sessionId, + const uint16_t nRoamScanHomeAwayTime, + const bool bSendOffloadCmd); + +bool sme_get_roam_intra_band(tHalHandle hHal); +uint8_t sme_get_roam_scan_n_probes(tHalHandle hHal); +uint16_t sme_get_roam_scan_home_away_time(tHalHandle hHal); +QDF_STATUS sme_update_roam_rssi_diff(tHalHandle hHal, uint8_t sessionId, + uint8_t RoamRssiDiff); +QDF_STATUS sme_update_fast_transition_enabled(tHalHandle hHal, + bool isFastTransitionEnabled); +QDF_STATUS sme_update_wes_mode(tHalHandle hHal, bool isWESModeEnabled, + uint8_t sessionId); +QDF_STATUS sme_set_roam_scan_control(tHalHandle hHal, uint8_t sessionId, + bool roamScanControl); + +QDF_STATUS sme_update_is_fast_roam_ini_feature_enabled(tHalHandle hHal, + uint8_t sessionId, + const bool + isFastRoamIniFeatureEnabled); + +QDF_STATUS sme_config_fast_roaming(tHalHandle hal, uint8_t session_id, + const bool is_fast_roam_enabled); + +QDF_STATUS sme_update_is_mawc_ini_feature_enabled(tHalHandle hHal, + const bool MAWCEnabled); +QDF_STATUS sme_stop_roaming(tHalHandle hHal, uint8_t sessionId, uint8_t reason); +QDF_STATUS sme_start_roaming(tHalHandle hHal, uint8_t sessionId, + uint8_t reason); +QDF_STATUS sme_update_enable_fast_roam_in_concurrency(tHalHandle hHal, + bool bFastRoamInConIniFeatureEnabled); +#ifdef FEATURE_WLAN_ESE +QDF_STATUS sme_update_is_ese_feature_enabled(tHalHandle hHal, uint8_t sessionId, + const bool isEseIniFeatureEnabled); +#endif /* FEATURE_WLAN_ESE */ +QDF_STATUS sme_update_config_fw_rssi_monitoring(tHalHandle hHal, + bool fEnableFwRssiMonitoring); +QDF_STATUS sme_set_roam_rescan_rssi_diff(tHalHandle hHal, + uint8_t sessionId, + const uint8_t nRoamRescanRssiDiff); +uint8_t sme_get_roam_rescan_rssi_diff(tHalHandle hHal); + +QDF_STATUS sme_set_roam_opportunistic_scan_threshold_diff(tHalHandle hHal, + uint8_t sessionId, + const uint8_t nOpportunisticThresholdDiff); +uint8_t sme_get_roam_opportunistic_scan_threshold_diff(tHalHandle hHal); +QDF_STATUS sme_set_neighbor_lookup_rssi_threshold(tHalHandle hHal, + uint8_t sessionId, uint8_t neighborLookupRssiThreshold); +QDF_STATUS sme_set_delay_before_vdev_stop(tHalHandle hHal, + uint8_t sessionId, uint8_t delay_before_vdev_stop); +uint8_t sme_get_neighbor_lookup_rssi_threshold(tHalHandle hHal); +QDF_STATUS sme_set_neighbor_scan_refresh_period(tHalHandle hHal, + uint8_t sessionId, uint16_t neighborScanResultsRefreshPeriod); +uint16_t sme_get_neighbor_scan_refresh_period(tHalHandle hHal); +uint16_t sme_get_empty_scan_refresh_period(tHalHandle hHal); +QDF_STATUS sme_update_empty_scan_refresh_period(tHalHandle hHal, + uint8_t sessionId, uint16_t nEmptyScanRefreshPeriod); +QDF_STATUS sme_set_neighbor_scan_min_chan_time(tHalHandle hHal, + const uint16_t nNeighborScanMinChanTime, + uint8_t sessionId); +QDF_STATUS sme_set_neighbor_scan_max_chan_time(tHalHandle hHal, + uint8_t sessionId, const uint16_t nNeighborScanMaxChanTime); +uint16_t sme_get_neighbor_scan_min_chan_time(tHalHandle hHal, + uint8_t sessionId); +uint32_t sme_get_neighbor_roam_state(tHalHandle hHal, uint8_t sessionId); +uint32_t sme_get_current_roam_state(tHalHandle hHal, uint8_t sessionId); +uint32_t sme_get_current_roam_sub_state(tHalHandle hHal, uint8_t sessionId); +uint32_t sme_get_lim_sme_state(tHalHandle hHal); +uint32_t sme_get_lim_mlm_state(tHalHandle hHal); +bool sme_is_lim_session_valid(tHalHandle hHal, uint8_t sessionId); +uint32_t sme_get_lim_sme_session_state(tHalHandle hHal, uint8_t sessionId); +uint32_t sme_get_lim_mlm_session_state(tHalHandle hHal, uint8_t sessionId); +uint16_t sme_get_neighbor_scan_max_chan_time(tHalHandle hHal, + uint8_t sessionId); +QDF_STATUS sme_set_neighbor_scan_period(tHalHandle hHal, uint8_t sessionId, + const uint16_t nNeighborScanPeriod); +uint16_t sme_get_neighbor_scan_period(tHalHandle hHal, uint8_t sessionId); +QDF_STATUS sme_set_roam_bmiss_first_bcnt(tHalHandle hHal, + uint8_t sessionId, const uint8_t nRoamBmissFirstBcnt); +uint8_t sme_get_roam_bmiss_first_bcnt(tHalHandle hHal); +QDF_STATUS sme_set_roam_bmiss_final_bcnt(tHalHandle hHal, uint8_t sessionId, + const uint8_t nRoamBmissFinalBcnt); +uint8_t sme_get_roam_bmiss_final_bcnt(tHalHandle hHal); +QDF_STATUS sme_set_roam_beacon_rssi_weight(tHalHandle hHal, uint8_t sessionId, + const uint8_t nRoamBeaconRssiWeight); +uint8_t sme_get_roam_beacon_rssi_weight(tHalHandle hHal); +uint8_t sme_get_roam_rssi_diff(tHalHandle hHal); +QDF_STATUS sme_change_roam_scan_channel_list(tHalHandle hHal, uint8_t sessionId, + uint8_t *pChannelList, + uint8_t numChannels); +QDF_STATUS sme_set_ese_roam_scan_channel_list(tHalHandle hHal, + uint8_t sessionId, uint8_t *pChannelList, + uint8_t numChannels); +QDF_STATUS sme_get_roam_scan_channel_list(tHalHandle hHal, + uint8_t *pChannelList, uint8_t *pNumChannels, + uint8_t sessionId); +bool sme_get_is_ese_feature_enabled(tHalHandle hHal); +bool sme_get_wes_mode(tHalHandle hHal); +bool sme_get_roam_scan_control(tHalHandle hHal); +bool sme_get_is_lfr_feature_enabled(tHalHandle hHal); +bool sme_get_is_ft_feature_enabled(tHalHandle hHal); +QDF_STATUS sme_update_roam_scan_offload_enabled(tHalHandle hHal, + bool nRoamScanOffloadEnabled); +uint8_t sme_is_feature_supported_by_fw(uint8_t featEnumValue); +#ifdef FEATURE_WLAN_TDLS +QDF_STATUS sme_send_tdls_link_establish_params(tHalHandle hHal, + uint8_t sessionId, + const tSirMacAddr peerMac, + tCsrTdlsLinkEstablishParams * + tdlsLinkEstablishParams); +QDF_STATUS sme_send_tdls_mgmt_frame(tHalHandle hHal, uint8_t sessionId, + const tSirMacAddr peerMac, uint8_t frame_type, + uint8_t dialog, uint16_t status, + uint32_t peerCapability, uint8_t *buf, + uint8_t len, uint8_t responder, enum sir_wifi_traffic_ac ac); +QDF_STATUS sme_change_tdls_peer_sta(tHalHandle hHal, uint8_t sessionId, + const tSirMacAddr peerMac, + tCsrStaParams *pstaParams); +QDF_STATUS sme_add_tdls_peer_sta(tHalHandle hHal, uint8_t sessionId, + const tSirMacAddr peerMac); +QDF_STATUS sme_delete_tdls_peer_sta(tHalHandle hHal, uint8_t sessionId, + const tSirMacAddr peerMac); +void sme_set_tdls_power_save_prohibited(tHalHandle hHal, uint32_t sessionId, + bool val); +QDF_STATUS sme_send_tdls_chan_switch_req( + tHalHandle hal, + sme_tdls_chan_switch_params *ch_switch_params); +#endif + +/* + * SME API to enable/disable WLAN driver initiated SSR + */ +void sme_update_enable_ssr(tHalHandle hHal, bool enableSSR); +QDF_STATUS sme_set_phy_mode(tHalHandle hHal, eCsrPhyMode phyMode); +eCsrPhyMode sme_get_phy_mode(tHalHandle hHal); +QDF_STATUS sme_handoff_request(tHalHandle hHal, uint8_t sessionId, + tCsrHandoffRequest *pHandoffInfo); +QDF_STATUS sme_is_sta_p2p_client_connected(tHalHandle hHal); +#ifdef FEATURE_WLAN_LPHB +QDF_STATUS sme_lphb_config_req(tHalHandle hHal, + tSirLPHBReq * lphdReq, + void (*pCallbackfn)(void *pHddCtx, + tSirLPHBInd * indParam)); +#endif /* FEATURE_WLAN_LPHB */ +QDF_STATUS sme_add_periodic_tx_ptrn(tHalHandle hHal, tSirAddPeriodicTxPtrn + *addPeriodicTxPtrnParams); +QDF_STATUS sme_del_periodic_tx_ptrn(tHalHandle hHal, tSirDelPeriodicTxPtrn + *delPeriodicTxPtrnParams); +void sme_enable_disable_split_scan(tHalHandle hHal, uint8_t nNumStaChan, + uint8_t nNumP2PChan); +QDF_STATUS sme_send_rate_update_ind(tHalHandle hHal, + tSirRateUpdateInd *rateUpdateParams); +QDF_STATUS sme_roam_del_pmkid_from_cache(tHalHandle hHal, uint8_t sessionId, + const uint8_t *pBSSId, bool flush_cache); +void sme_get_command_q_status(tHalHandle hHal); + +QDF_STATUS sme_enable_rmc(tHalHandle hHal, uint32_t sessionId); +QDF_STATUS sme_disable_rmc(tHalHandle hHal, uint32_t sessionId); +QDF_STATUS sme_send_rmc_action_period(tHalHandle hHal, uint32_t sessionId); +QDF_STATUS sme_request_ibss_peer_info(tHalHandle hHal, void *pUserData, + pIbssPeerInfoCb peerInfoCbk, bool allPeerInfoReqd, uint8_t staIdx); +QDF_STATUS sme_send_cesium_enable_ind(tHalHandle hHal, uint32_t sessionId); + +/* + * SME API to enable/disable idle mode powersave + * This should be called only if powersave offload + * is enabled + */ +QDF_STATUS sme_set_idle_powersave_config(bool value); +QDF_STATUS sme_notify_modem_power_state(tHalHandle hHal, uint32_t value); + +/*SME API to convert convert the ini value to the ENUM used in csr and MAC*/ +ePhyChanBondState sme_get_cb_phy_state_from_cb_ini_value(uint32_t cb_ini_value); +int sme_update_ht_config(tHalHandle hHal, uint8_t sessionId, uint16_t htCapab, + int value); +int16_t sme_get_ht_config(tHalHandle hHal, uint8_t session_id, + uint16_t ht_capab); +#ifdef QCA_HT_2040_COEX +QDF_STATUS sme_notify_ht2040_mode(tHalHandle hHal, uint16_t staId, + struct qdf_mac_addr macAddrSTA, + uint8_t sessionId, + uint8_t channel_type); +QDF_STATUS sme_set_ht2040_mode(tHalHandle hHal, uint8_t sessionId, + uint8_t channel_type, bool obssEnabled); +#endif +QDF_STATUS sme_get_reg_info(tHalHandle hHal, uint8_t chanId, + uint32_t *regInfo1, uint32_t *regInfo2); +#ifdef FEATURE_WLAN_TDLS +QDF_STATUS sme_update_fw_tdls_state(tHalHandle hHal, void *psmeTdlsParams, + bool useSmeLock); +QDF_STATUS sme_update_tdls_peer_state(tHalHandle hHal, + tSmeTdlsPeerStateParams *pPeerStateParams); +#endif /* FEATURE_WLAN_TDLS */ +#ifdef FEATURE_WLAN_CH_AVOID +QDF_STATUS sme_add_ch_avoid_callback(tHalHandle hHal, + void (*pCallbackfn)(void *hdd_context, void *indi_param)); +QDF_STATUS sme_ch_avoid_update_req(tHalHandle hHal); +#else +static inline +QDF_STATUS sme_add_ch_avoid_callback(tHalHandle hHal, + void (*pCallbackfn)(void *hdd_context, void *indi_param)) +{ + return QDF_STATUS_E_NOSUPPORT; +} + +static inline +QDF_STATUS sme_ch_avoid_update_req(tHalHandle hHal) +{ + return QDF_STATUS_E_NOSUPPORT; +} +#endif /* FEATURE_WLAN_CH_AVOID */ +#ifdef FEATURE_WLAN_AUTO_SHUTDOWN +QDF_STATUS sme_set_auto_shutdown_cb(tHalHandle hHal, void (*pCallbackfn)(void)); +QDF_STATUS sme_set_auto_shutdown_timer(tHalHandle hHal, uint32_t timer_value); +#endif +QDF_STATUS sme_roam_channel_change_req(tHalHandle hHal, + struct qdf_mac_addr bssid, + struct ch_params_s *ch_params, + tCsrRoamProfile *profile); + +QDF_STATUS sme_roam_start_beacon_req(tHalHandle hHal, + struct qdf_mac_addr bssid, uint8_t dfsCacWaitStatus); +QDF_STATUS sme_roam_csa_ie_request(tHalHandle hHal, struct qdf_mac_addr bssid, + uint8_t targetChannel, uint8_t csaIeReqd, + struct ch_params_s *ch_params); + +QDF_STATUS sme_init_thermal_info(tHalHandle hHal, + tSmeThermalParams thermalParam); + +QDF_STATUS sme_set_thermal_level(tHalHandle hHal, uint8_t level); +QDF_STATUS sme_txpower_limit(tHalHandle hHal, tSirTxPowerLimit *psmetx); +QDF_STATUS sme_get_link_speed(tHalHandle hHal, tSirLinkSpeedInfo *lsReq, + void *plsContext, + void (*pCallbackfn)(tSirLinkSpeedInfo *indParam, + void *pContext)); +QDF_STATUS sme_modify_add_ie(tHalHandle hHal, + tSirModifyIE *pModifyIE, eUpdateIEsType updateType); +QDF_STATUS sme_update_add_ie(tHalHandle hHal, + tSirUpdateIE *pUpdateIE, eUpdateIEsType updateType); +QDF_STATUS sme_update_connect_debug(tHalHandle hHal, uint32_t set_value); +const char *sme_request_type_to_string(const uint8_t request_type); +const char *sme_scan_type_to_string(const uint8_t scan_type); +const char *sme_bss_type_to_string(const uint8_t bss_type); +QDF_STATUS sme_ap_disable_intra_bss_fwd(tHalHandle hHal, uint8_t sessionId, + bool disablefwd); +uint32_t sme_get_channel_bonding_mode5_g(tHalHandle hHal); +uint32_t sme_get_channel_bonding_mode24_g(tHalHandle hHal); +#ifdef WLAN_FEATURE_STATS_EXT +typedef struct sStatsExtRequestReq { + uint32_t request_data_len; + uint8_t *request_data; +} tStatsExtRequestReq, *tpStatsExtRequestReq; +typedef void (*StatsExtCallback)(void *, tStatsExtEvent *); +void sme_stats_ext_register_callback(tHalHandle hHal, + StatsExtCallback callback); +void sme_stats_ext_deregister_callback(tHalHandle hhal); +QDF_STATUS sme_stats_ext_request(uint8_t session_id, + tpStatsExtRequestReq input); +QDF_STATUS sme_stats_ext_event(tHalHandle hHal, void *pMsg); +#endif +QDF_STATUS sme_update_dfs_scan_mode(tHalHandle hHal, + uint8_t sessionId, + uint8_t allowDFSChannelRoam); +uint8_t sme_get_dfs_scan_mode(tHalHandle hHal); + +#ifdef FEATURE_WLAN_EXTSCAN +QDF_STATUS sme_get_valid_channels_by_band(tHalHandle hHal, uint8_t wifiBand, + uint32_t *aValidChannels, + uint8_t *pNumChannels); +QDF_STATUS sme_ext_scan_get_capabilities(tHalHandle hHal, + tSirGetExtScanCapabilitiesReqParams *pReq); +QDF_STATUS sme_ext_scan_start(tHalHandle hHal, + tSirWifiScanCmdReqParams *pStartCmd); +QDF_STATUS sme_ext_scan_stop(tHalHandle hHal, + tSirExtScanStopReqParams *pStopReq); +QDF_STATUS sme_set_bss_hotlist(tHalHandle hHal, + tSirExtScanSetBssidHotListReqParams * + pSetHotListReq); +QDF_STATUS sme_reset_bss_hotlist(tHalHandle hHal, + tSirExtScanResetBssidHotlistReqParams * + pResetReq); +QDF_STATUS sme_set_significant_change(tHalHandle hHal, + tSirExtScanSetSigChangeReqParams * + pSetSignificantChangeReq); +QDF_STATUS sme_reset_significant_change(tHalHandle hHal, + tSirExtScanResetSignificantChangeReqParams + *pResetReq); +QDF_STATUS sme_get_cached_results(tHalHandle hHal, + tSirExtScanGetCachedResultsReqParams * + pCachedResultsReq); + +QDF_STATUS sme_set_epno_list(tHalHandle hal, + struct wifi_epno_params *req_msg); +QDF_STATUS sme_set_passpoint_list(tHalHandle hal, + struct wifi_passpoint_req *req_msg); +QDF_STATUS sme_reset_passpoint_list(tHalHandle hal, + struct wifi_passpoint_req *req_msg); + +QDF_STATUS sme_ext_scan_register_callback(tHalHandle hHal, + void (*pExtScanIndCb)(void *, const uint16_t, void *)); +#else +static inline QDF_STATUS sme_ext_scan_register_callback(tHalHandle hHal, + void (*pExtScanIndCb)(void *, const uint16_t, void *)) +{ + return QDF_STATUS_SUCCESS; +} +#endif /* FEATURE_WLAN_EXTSCAN */ +QDF_STATUS sme_abort_roam_scan(tHalHandle hHal, uint8_t sessionId); +#ifdef WLAN_FEATURE_LINK_LAYER_STATS +QDF_STATUS sme_ll_stats_clear_req(tHalHandle hHal, + tSirLLStatsClearReq * pclearStatsReq); +QDF_STATUS sme_ll_stats_set_req(tHalHandle hHal, + tSirLLStatsSetReq *psetStatsReq); +QDF_STATUS sme_ll_stats_get_req(tHalHandle hHal, + tSirLLStatsGetReq *pgetStatsReq); +QDF_STATUS sme_set_link_layer_stats_ind_cb(tHalHandle hHal, + void (*callbackRoutine)(void *callbackCtx, + int indType, void *pRsp)); +QDF_STATUS sme_reset_link_layer_stats_ind_cb(tHalHandle hhal); +#endif /* WLAN_FEATURE_LINK_LAYER_STATS */ + +QDF_STATUS sme_fw_mem_dump(tHalHandle hHal, void *recvd_req); +QDF_STATUS sme_fw_mem_dump_register_cb(tHalHandle hHal, + void (*callback_routine)(void *cb_context, + struct fw_dump_rsp *rsp)); +QDF_STATUS sme_fw_mem_dump_unregister_cb(tHalHandle hHal); +QDF_STATUS sme_set_wisa_params(tHalHandle hal, + struct sir_wisa_params *wisa_params); +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +QDF_STATUS sme_update_roam_offload_enabled(tHalHandle hHal, + bool nRoamOffloadEnabled); +QDF_STATUS sme_update_roam_key_mgmt_offload_enabled(tHalHandle hal_ctx, + uint8_t session_id, + bool key_mgmt_offload_enabled, + struct pmkid_mode_bits *pmkid_modes); +#endif +#ifdef WLAN_FEATURE_NAN +QDF_STATUS sme_nan_event(tHalHandle hHal, void *pMsg); +#endif /* WLAN_FEATURE_NAN */ +QDF_STATUS sme_get_link_status(tHalHandle hHal, + tCsrLinkStatusCallback callback, + void *pContext, uint8_t sessionId); +QDF_STATUS sme_get_temperature(tHalHandle hHal, + void *tempContext, + void (*pCallbackfn)(int temperature, + void *pContext)); +QDF_STATUS sme_set_scanning_mac_oui(tHalHandle hHal, + tSirScanMacOui *pScanMacOui); + +#ifdef IPA_OFFLOAD +/* --------------------------------------------------------------------------- + \fn sme_ipa_offload_enable_disable + \brief API to enable/disable IPA offload + \param hHal - The handle returned by macOpen. + \param sessionId - Session Identifier + \param pRequest - Pointer to the offload request. + \return QDF_STATUS + ---------------------------------------------------------------------------*/ +QDF_STATUS sme_ipa_offload_enable_disable(tHalHandle hal, + uint8_t session_id, + struct sir_ipa_offload_enable_disable *request); +#else +static inline QDF_STATUS sme_ipa_offload_enable_disable(tHalHandle hal, + uint8_t session_id, + struct sir_ipa_offload_enable_disable *request) +{ + return QDF_STATUS_SUCCESS; +} +#endif /* IPA_OFFLOAD */ + +#ifdef DHCP_SERVER_OFFLOAD +QDF_STATUS sme_set_dhcp_srv_offload(tHalHandle hHal, + tSirDhcpSrvOffloadInfo * pDhcpSrvInfo); +#endif /* DHCP_SERVER_OFFLOAD */ +#ifdef WLAN_FEATURE_GPIO_LED_FLASHING +QDF_STATUS sme_set_led_flashing(tHalHandle hHal, uint8_t type, + uint32_t x0, uint32_t x1); +#endif +QDF_STATUS sme_handle_dfs_chan_scan(tHalHandle hHal, uint8_t dfs_flag); +QDF_STATUS sme_set_mas(uint32_t val); +QDF_STATUS sme_set_miracast(tHalHandle hal, uint8_t filter_type); +QDF_STATUS sme_ext_change_channel(tHalHandle hHal, uint32_t channel, + uint8_t session_id); + +QDF_STATUS sme_configure_modulated_dtim(tHalHandle hal, uint8_t session_id, + uint32_t modulated_dtim); + +QDF_STATUS sme_configure_stats_avg_factor(tHalHandle hal, uint8_t session_id, + uint16_t stats_avg_factor); + +QDF_STATUS sme_configure_guard_time(tHalHandle hal, uint8_t session_id, + uint32_t guard_time); + +QDF_STATUS sme_wifi_start_logger(tHalHandle hal, + struct sir_wifi_start_log start_log); + +bool sme_neighbor_middle_of_roaming(tHalHandle hHal, + uint8_t sessionId); + +QDF_STATUS sme_enable_uapsd_for_ac(void *cds_ctx, uint8_t sta_id, + sme_ac_enum_type ac, uint8_t tid, + uint8_t pri, uint32_t srvc_int, + uint32_t sus_int, + sme_tspec_dir_type dir, + uint8_t psb, uint32_t sessionId, + uint32_t delay_interval); + +QDF_STATUS sme_disable_uapsd_for_ac(void *cds_ctx, uint8_t sta_id, + sme_ac_enum_type ac, + uint32_t sessionId); + +QDF_STATUS sme_set_rssi_monitoring(tHalHandle hal, + struct rssi_monitor_req *input); +QDF_STATUS sme_set_rssi_threshold_breached_cb(tHalHandle hal, + void (*cb)(void *, struct rssi_breach_event *)); +QDF_STATUS sme_reset_rssi_threshold_breached_cb(tHalHandle hal); + +QDF_STATUS sme_register_mgmt_frame_ind_callback(tHalHandle hal, + sir_mgmt_frame_ind_callback callback); + +QDF_STATUS sme_update_nss(tHalHandle h_hal, uint8_t nss); +void sme_update_user_configured_nss(tHalHandle hal, uint8_t nss); + +bool sme_is_any_session_in_connected_state(tHalHandle h_hal); + +QDF_STATUS sme_pdev_set_pcl(tHalHandle hal, + struct sir_pcl_list msg); +QDF_STATUS sme_pdev_set_hw_mode(tHalHandle hal, + struct sir_hw_mode msg); +void sme_register_hw_mode_trans_cb(tHalHandle hal, + hw_mode_transition_cb callback); +QDF_STATUS sme_nss_update_request(tHalHandle hHal, uint32_t vdev_id, + uint8_t new_nss, void *cback, + uint8_t next_action, void *hdd_context, + enum sir_conn_update_reason reason); + +typedef void (*sme_peer_authorized_fp) (uint32_t vdev_id); +QDF_STATUS sme_set_peer_authorized(uint8_t *peer_addr, + sme_peer_authorized_fp auth_fp, + uint32_t vdev_id); +QDF_STATUS sme_soc_set_dual_mac_config(tHalHandle hal, + struct sir_dual_mac_config msg); +QDF_STATUS sme_soc_set_antenna_mode(tHalHandle hal, + struct sir_antenna_mode_param *msg); + +void sme_set_scan_disable(tHalHandle h_hal, int value); +void sme_setdef_dot11mode(tHalHandle hal); + +QDF_STATUS sme_handle_set_fcc_channel(tHalHandle hHal, + bool fcc_constraint, + bool scan_pending); + +QDF_STATUS sme_update_roam_scan_hi_rssi_scan_params(tHalHandle hal_handle, + uint8_t session_id, + uint32_t notify_id, + int32_t val); + +void wlan_sap_enable_phy_error_logs(tHalHandle hal, bool enable_log); +#ifdef WLAN_FEATURE_DSRC +void sme_set_dot11p_config(tHalHandle hal, bool enable_dot11p); + +QDF_STATUS sme_ocb_set_config(tHalHandle hHal, void *context, + ocb_callback callback, + struct sir_ocb_config *config); + +QDF_STATUS sme_ocb_set_utc_time(tHalHandle hHal, struct sir_ocb_utc *utc); + +QDF_STATUS sme_ocb_start_timing_advert(tHalHandle hHal, + struct sir_ocb_timing_advert *timing_advert); + +QDF_STATUS sme_ocb_stop_timing_advert(tHalHandle hHal, + struct sir_ocb_timing_advert *timing_advert); + +int sme_ocb_gen_timing_advert_frame(tHalHandle hHal, tSirMacAddr self_addr, + uint8_t **buf, uint32_t *timestamp_offset, + uint32_t *time_value_offset); + +QDF_STATUS sme_ocb_get_tsf_timer(tHalHandle hHal, void *context, + ocb_callback callback, + struct sir_ocb_get_tsf_timer *request); + +QDF_STATUS sme_dcc_get_stats(tHalHandle hHal, void *context, + ocb_callback callback, + struct sir_dcc_get_stats *request); + +QDF_STATUS sme_dcc_clear_stats(tHalHandle hHal, uint32_t vdev_id, + uint32_t dcc_stats_bitmap); + +QDF_STATUS sme_dcc_update_ndl(tHalHandle hHal, void *context, + ocb_callback callback, + struct sir_dcc_update_ndl *request); + +QDF_STATUS sme_register_for_dcc_stats_event(tHalHandle hHal, void *context, + ocb_callback callback); +QDF_STATUS sme_deregister_for_dcc_stats_event(tHalHandle hHal); + +#else +static inline void sme_set_dot11p_config(tHalHandle hal, bool enable_dot11p) +{ + return; +} + +static inline QDF_STATUS sme_ocb_set_config(tHalHandle hHal, void *context, + ocb_callback callback, + struct sir_ocb_config *config) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS sme_ocb_set_utc_time(struct sir_ocb_utc *utc) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS sme_ocb_start_timing_advert( + struct sir_ocb_timing_advert *timing_advert) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS sme_ocb_stop_timing_advert(struct sir_ocb_timing_advert + *timing_advert) +{ + return QDF_STATUS_SUCCESS; +} + +static inline int sme_ocb_gen_timing_advert_frame(tHalHandle hHal, + tSirMacAddr self_addr, uint8_t **buf, + uint32_t *timestamp_offset, + uint32_t *time_value_offset) +{ + return 0; +} + +static inline QDF_STATUS sme_ocb_get_tsf_timer(tHalHandle hHal, void *context, + ocb_callback callback, + struct sir_ocb_get_tsf_timer *request) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS sme_dcc_get_stats(tHalHandle hHal, void *context, + ocb_callback callback, + struct sir_dcc_get_stats *request) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS sme_dcc_clear_stats(uint32_t vdev_id, + uint32_t dcc_stats_bitmap) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS sme_dcc_update_ndl(tHalHandle hHal, void *context, + ocb_callback callback, + struct sir_dcc_update_ndl *request) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS sme_register_for_dcc_stats_event(tHalHandle hHal, + void *context, ocb_callback callback) +{ + return QDF_STATUS_SUCCESS; +} +static inline QDF_STATUS sme_deregister_for_dcc_stats_event(tHalHandle hHal) +{ + return QDF_STATUS_SUCCESS; +} +#endif +void sme_add_set_thermal_level_callback(tHalHandle hal, + sme_set_thermal_level_callback callback); + +void sme_update_tgt_services(tHalHandle hal, struct wma_tgt_services *cfg); +bool sme_validate_sap_channel_switch(tHalHandle hal, + uint16_t sap_ch, eCsrPhyMode sap_phy_mode, + uint8_t cc_switch_mode, uint8_t session_id); + +bool sme_is_session_id_valid(tHalHandle hal, uint32_t session_id); + +#ifdef FEATURE_WLAN_TDLS +void sme_get_opclass(tHalHandle hal, uint8_t channel, uint8_t bw_offset, + uint8_t *opclass); +#else +static inline void +sme_get_opclass(tHalHandle hal, uint8_t channel, uint8_t bw_offset, + uint8_t *opclass) +{ +} +#endif + +#ifdef FEATURE_LFR_SUBNET_DETECTION +QDF_STATUS sme_gateway_param_update(tHalHandle hHal, + struct gateway_param_update_req *request); +#endif + +#ifdef FEATURE_GREEN_AP +QDF_STATUS sme_send_egap_conf_params(uint32_t enable, + uint32_t inactivity_time, + uint32_t wait_time, + uint32_t flags); +#else +static inline QDF_STATUS sme_send_egap_conf_params(uint32_t enable, + uint32_t inactivity_time, + uint32_t wait_time, + uint32_t flags) +{ + return QDF_STATUS_E_NOSUPPORT; +} +#endif + +void sme_update_fine_time_measurement_capab(tHalHandle hal, uint8_t session_id, + uint32_t val); +QDF_STATUS sme_ht40_stop_obss_scan(tHalHandle hHal, uint32_t vdev_id); +QDF_STATUS sme_set_fw_test(struct set_fwtest_params *fw_test); +QDF_STATUS sme_set_tsfcb(tHalHandle hHal, + int (*cb_fn)(void *cb_ctx, struct stsf *ptsf), void *cb_ctx); + +QDF_STATUS sme_reset_tsfcb(tHalHandle h_hal); + +#ifdef WLAN_FEATURE_TSF +QDF_STATUS sme_set_tsf_gpio(tHalHandle h_hal, uint32_t pinvalue); +QDF_STATUS sme_reset_tsf_gpio(tHalHandle h_hal); + +#else +static inline QDF_STATUS sme_set_tsf_gpio(tHalHandle h_hal, uint32_t pinvalue) +{ + return QDF_STATUS_E_FAILURE; +} +static inline QDF_STATUS sme_reset_tsf_gpio(tHalHandle h_hal) +{ + return QDF_STATUS_E_FAILURE; +} + +#endif + +QDF_STATUS sme_update_mimo_power_save(tHalHandle hHal, + uint8_t is_ht_smps_enabled, + uint8_t ht_smps_mode, + bool send_smps_action); + +bool sme_is_sta_smps_allowed(tHalHandle hHal, uint8_t session_id); +QDF_STATUS sme_add_beacon_filter(tHalHandle hal, + uint32_t session_id, uint32_t *ie_map); +QDF_STATUS sme_remove_beacon_filter(tHalHandle hal, uint32_t session_id); +QDF_STATUS sme_bpf_offload_register_callback(tHalHandle hal, + void (*pbpf_get_offload_cb)(void *, + struct sir_bpf_get_offload *)); +QDF_STATUS sme_bpf_offload_deregister_callback(tHalHandle hal); + +QDF_STATUS sme_get_bpf_offload_capabilities(tHalHandle hal); +QDF_STATUS sme_set_bpf_instructions(tHalHandle hal, + struct sir_bpf_set_offload *); +uint32_t sme_get_wni_dot11_mode(tHalHandle hal); +QDF_STATUS sme_create_mon_session(tHalHandle hal_handle, uint8_t *bssid); +QDF_STATUS sme_set_adaptive_dwelltime_config(tHalHandle hal, + struct adaptive_dwelltime_params *dwelltime_params); + +void sme_set_vdev_ies_per_band(tHalHandle hal, uint8_t vdev_id); +void sme_set_pdev_ht_vht_ies(tHalHandle hHal, bool enable2x2); + +void sme_update_vdev_type_nss(tHalHandle hal, uint8_t max_supp_nss, + uint32_t vdev_type_nss, eCsrBand band); +void sme_update_hw_dbs_capable(tHalHandle hal, uint8_t hw_dbs_capable); +void sme_register_p2p_lo_event(tHalHandle hHal, void *context, + p2p_lo_callback callback); + +QDF_STATUS sme_remove_bssid_from_scan_list(tHalHandle hal, + tSirMacAddr bssid); + +QDF_STATUS sme_process_mac_pwr_dbg_cmd(tHalHandle hal, uint32_t session_id, + struct sir_mac_pwr_dbg_cmd* + dbg_args); + +void sme_get_vdev_type_nss(tHalHandle hal, enum tQDF_ADAPTER_MODE dev_mode, + uint8_t *nss_2g, uint8_t *nss_5g); +QDF_STATUS sme_roam_set_default_key_index(tHalHandle hal, uint8_t session_id, + uint8_t default_idx); +QDF_STATUS sme_register_p2p_ack_ind_callback(tHalHandle hal, + sir_p2p_ack_ind_callback callback); +void sme_send_disassoc_req_frame(tHalHandle hal, uint8_t session_id, uint8_t + *peer_mac, uint16_t reason, uint8_t + wait_for_ack); +QDF_STATUS sme_update_access_policy_vendor_ie(tHalHandle hal, + uint8_t session_id, uint8_t *vendor_ie, + int access_policy); + +QDF_STATUS sme_update_sta_roam_policy(tHalHandle hal, + enum sta_roam_policy_dfs_mode dfs_mode, + bool skip_unsafe_channels, + uint8_t session_id, uint8_t sap_operating_band); +QDF_STATUS sme_enable_disable_chanavoidind_event(tHalHandle hal, + uint8_t set_value); +QDF_STATUS sme_set_default_scan_ie(tHalHandle hal, uint16_t session_id, + uint8_t *ie_data, uint16_t ie_len); +/** + * sme_update_session_param() - API to update PE session param + * @hal: HAL handle for device + * @session_id: Session ID + * @param_type: Param type to be updated + * @param_val: Param value to be update + * + * Note: this setting will not persist over reboots. + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_update_session_param(tHalHandle hal, uint8_t session_id, + uint32_t param_type, uint32_t param_val); + +#ifdef WLAN_FEATURE_DISA +/** + * sme_encrypt_decrypt_msg_register_callback() - Registers + * encrypt/decrypt message callback + * + * @hal - MAC global handle + * @callback_routine - callback routine from HDD + * + * This API is invoked by HDD to register its callback in SME + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_encrypt_decrypt_msg_register_callback(tHalHandle hal, + void (*encrypt_decrypt_cb)(void *hdd_context, + struct sir_encrypt_decrypt_rsp_params + *encrypt_decrypt_rsp_params)); + +/** + * sme_encrypt_decrypt_msg_deregister_callback() - Registers + * encrypt/decrypt message callback + * + * @h_hal - MAC global handle + * @callback_routine - callback routine from HDD + * + * This API is invoked by HDD to de-register its callback in SME + * + * Return: QDF_STATUS Enumeration + */ +QDF_STATUS sme_encrypt_decrypt_msg_deregister_callback(tHalHandle h_hal); + +/** + * sme_encrypt_decrypt_msg() - handles encrypt/decrypt mesaage + * @hal: HAL handle + * @encrypt_decrypt_params: struct to set encryption/decryption params. + * + * Return: QDF_STATUS enumeration. + */ +QDF_STATUS sme_encrypt_decrypt_msg(tHalHandle hal, + struct encrypt_decrypt_req_params *encrypt_decrypt_params); +#endif + +/** + * sme_set_cts2self_for_p2p_go() - sme function to set ini parms to FW. + * @hal: reference to the HAL + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_set_cts2self_for_p2p_go(tHalHandle hal); +void sme_set_prefer_80MHz_over_160MHz(tHalHandle hal, + bool sta_prefer_80MHz_over_160MHz); +void sme_set_allow_adj_ch_bcn(tHalHandle hal, bool allow_adj_ch_bcn); +QDF_STATUS sme_update_tx_fail_cnt_threshold(tHalHandle hal_handle, + uint8_t session_id, uint32_t tx_fail_count); +QDF_STATUS sme_update_short_retry_limit_threshold(tHalHandle hal_handle, + struct sme_short_retry_limit *short_retry_limit_th); +QDF_STATUS sme_update_long_retry_limit_threshold(tHalHandle hal_handle, + struct sme_long_retry_limit *long_retry_limit_th); +/** + * sme_roam_is_ese_assoc() - Check if association type is ESE + * @roam_info: Pointer to roam info + * + * Return: true if ESE Association, false otherwise. + */ +#ifdef FEATURE_WLAN_ESE +bool sme_roam_is_ese_assoc(tCsrRoamInfo *roam_info); +#else +static inline bool sme_roam_is_ese_assoc(tCsrRoamInfo *roam_info) +{ + return false; +} +#endif +/** + * sme_neighbor_roam_is11r_assoc() - Check if association type is 11R + * @hal_ctx: HAL handle + * @session_id: session id + * + * Return: true if 11r Association, false otherwise. + */ +bool sme_neighbor_roam_is11r_assoc(tHalHandle hal_ctx, uint8_t session_id); +/** + * sme_update_sta_inactivity_timeout(): Update sta_inactivity_timeout to FW + * @hal: Handle returned by mac_open + * @sta_inactivity_timer: struct for sta inactivity timer + * + * If a station does not send anything in sta_inactivity_timeout seconds, an + * empty data frame is sent to it in order to verify whether it is + * still in range. If this frame is not ACKed, the station will be + * disassociated and then deauthenticated. + * + * Return: QDF_STATUS_SUCCESS or non-zero on failure. +*/ +QDF_STATUS sme_update_sta_inactivity_timeout(tHalHandle hal_handle, + struct sme_sta_inactivity_timeout *sta_inactivity_timer); + +/** + * sme_set_lost_link_info_cb() - plug in callback function for receiving + * @hal: HAL handle + * @cb: callback function + * + * Return: HAL status + */ +QDF_STATUS sme_set_lost_link_info_cb(tHalHandle hal, + void (*cb)(void *, struct sir_lost_link_info *)); + +#ifdef WLAN_POWER_DEBUGFS +QDF_STATUS sme_power_debug_stats_req(tHalHandle hal, void (*callback_fn) + (struct power_stats_response *response, + void *context), void *power_stats_context); +#endif +/** + * sme_set_sar_power_limits() - set sar limits + * @hal: HAL handle + * @sar_limit_cmd: struct to send sar limit cmd. + * + * Return: QDF_STATUS enumeration. + */ +QDF_STATUS sme_set_sar_power_limits(tHalHandle hal, + struct sar_limit_cmd_params *sar_limit_cmd); +void sme_set_cc_src(tHalHandle hal_handle, enum country_src); + + +#ifdef WLAN_FEATURE_WOW_PULSE +QDF_STATUS sme_set_wow_pulse(struct wow_pulse_mode *wow_pulse_set_info); +#endif +/* ARP DEBUG STATS */ +QDF_STATUS sme_set_nud_debug_stats(tHalHandle hal, + struct set_arp_stats_params + *set_stats_param); +QDF_STATUS sme_get_nud_debug_stats(tHalHandle hal, + struct get_arp_stats_params + *get_stats_param); +QDF_STATUS sme_set_nud_debug_stats_cb(tHalHandle hal, + void (*cb)(void *, struct rsp_stats *)); + + +#ifdef WLAN_FEATURE_UDP_RESPONSE_OFFLOAD +QDF_STATUS sme_set_udp_resp_offload(struct udp_resp_offload *pudp_resp_cmd); +#else +static inline QDF_STATUS sme_set_udp_resp_offload(struct udp_resp_offload + *pudp_resp_cmd) +{ + return QDF_STATUS_E_FAILURE; +} +#endif + +/** + * sme_get_rcpi() - gets the rcpi value for peer mac addr + * @hal: handle returned by mac_open + * @rcpi: rcpi request containing peer mac addr, callback and related info + * + * This function posts the rcpi measurement request message to wma queue + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_get_rcpi(tHalHandle hal, struct sme_rcpi_req *rcpi); + +/** + * sme_get_rssi_snr_by_bssid() - gets the rssi and snr by bssid from scan cache + * @hal: handle returned by mac_open + * @profile: current connected profile + * @bssid: bssid to look for in scan cache + * @rssi: rssi value found + * @snr: snr value found + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_get_rssi_snr_by_bssid(tHalHandle hal, tCsrRoamProfile *profile, + const uint8_t *bssid, int8_t *rssi, + int8_t *snr); + +/** + * sme_get_beacon_frm() - gets the bss descriptor from scan cache and prepares + * beacon frame + * @hal: handle returned by mac_open + * @profile: current connected profile + * @bssid: bssid to look for in scan cache + * @frame_buf: frame buffer to populate + * @frame_len: length of constructed frame + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_get_beacon_frm(tHalHandle hal, tCsrRoamProfile *profile, + const tSirMacAddr bssid, + uint8_t **frame_buf, uint32_t *frame_len); + +/** + * sme_rso_cmd_status_cb() - Set RSO cmd status callback + * @hal: HAL Handle + * @cb: HDD Callback to rso comman status read + * + * This function is used to save HDD RSO Command status callback in MAC + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_rso_cmd_status_cb(tHalHandle hal, + void (*cb)(void *, struct rso_cmd_status *)); + +void sme_set_5g_band_pref(tHalHandle hal_handle, + struct sme_5g_band_pref_params *pref_params); + +/** + * sme_congestion_register_callback(): registers congestion callback + * @hal: handler for HAL + * @congestion_cb: congestion callback + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_congestion_register_callback(tHalHandle hal, + void (*congestion_cb)(void *, uint32_t congestion, uint32_t vdev_id)); + +QDF_STATUS sme_delete_all_tdls_peers(tHalHandle hal, uint8_t session_id); + +/** + * sme_set_chip_pwr_save_fail_cb() - set chip power save failure callback + * @hal: global hal handle + * @cb: callback function pointer + * + * This function stores the chip power save failure callback function. + * + * Return: QDF_STATUS enumeration. + */ +QDF_STATUS sme_set_chip_pwr_save_fail_cb(tHalHandle hal, void (*cb)(void *, + struct chip_pwr_save_fail_detected_params *)); +/** + * sme_process_msg_callback() - process callback message from LIM + * @hal: global hal handle + * @msg: cds message + * + * This function process the callback messages from LIM. + * + * Return: QDF_STATUS enumeration. + */ +QDF_STATUS sme_process_msg_callback(tHalHandle hal, cds_msg_t *msg); + +/** + * sme_ipa_uc_stat_request() - set ipa config parameters + * @vdev_id: virtual device for the command + * @param_id: parameter id + * @param_val: parameter value + * @req_cat: parameter category + * + * Return: QDF_STATUS_SUCCESS or non-zero on failure + */ +QDF_STATUS sme_ipa_uc_stat_request(tHalHandle hal, + uint32_t vdev_id, uint32_t param_id, + uint32_t param_val, uint32_t req_cat); + +/** + * sme_cli_set_command() - SME wrapper API over WMA "set" command + * processor cmd + * @vdev_id: virtual device for the command + * @param_id: parameter id + * @sval: parameter value + * @vpdev: parameter category + * + * Command handler for set operations + * + * Return: 0 on success, errno on failure + */ +int sme_cli_set_command(int vdev_id, int param_id, int sval, int vpdev); + +#endif /* #if !defined( __SME_API_H ) */ diff --git a/drivers/staging/qcacld-3.0/core/sme/inc/sme_ft_api.h b/drivers/staging/qcacld-3.0/core/sme/inc/sme_ft_api.h new file mode 100644 index 0000000000000000000000000000000000000000..3b0ff3aaf19c02dd8f99ff7034ae3036ace0b541 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/sme/inc/sme_ft_api.h @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2013-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#if !defined(__SME_FTAPI_H) +#define __SME_FTAPI_H + +typedef enum eFTIEState { + eFT_START_READY, /* Start before and after 11r assoc */ + eFT_AUTH_REQ_READY, /* When we have recvd the 1st or nth auth req */ + /* + * Sent auth1 and waiting auth2 We are now ready for FT phase, + * send auth1, recd auth2 + */ + eFT_WAIT_AUTH2, + eFT_AUTH_COMPLETE, + /* Now we have sent Auth Rsp to the supplicant and waiting */ + /* Reassoc Req from the supplicant. */ + eFT_REASSOC_REQ_WAIT, + /* + * We have received the Reassoc request from supplicant. + * Waiting for the keys. + */ + eFT_SET_KEY_WAIT, +} tFTIEStates; + +/* FT neighbor roam callback user context */ +typedef struct sFTRoamCallbackUsrCtx { + tpAniSirGlobal pMac; + uint8_t sessionId; +} tFTRoamCallbackUsrCtx, *tpFTRoamCallbackUsrCtx; + +typedef struct sFTSMEContext { + /* Received and processed during pre-auth */ + uint8_t *auth_ft_ies; + uint32_t auth_ft_ies_length; + /* Received and processed during re-assoc */ + uint8_t *reassoc_ft_ies; + uint16_t reassoc_ft_ies_length; + /* Pre-Auth info */ + tFTIEStates FTState; /* The state of FT in the current 11rAssoc */ + tSirMacAddr preAuthbssId; /* BSSID to preauth to */ + uint32_t smeSessionId; + /* Saved pFTPreAuthRsp */ + tpSirFTPreAuthRsp psavedFTPreAuthRsp; + bool setFTPreAuthState; + bool setFTPTKState; + /* Time to trigger reassoc once pre-auth is successful */ + qdf_mc_timer_t preAuthReassocIntvlTimer; + bool addMDIE; +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + uint32_t r0kh_id_len; + uint8_t r0kh_id[SIR_ROAM_R0KH_ID_MAX_LEN]; +#endif + /* User context for the timer callback */ + tpFTRoamCallbackUsrCtx pUsrCtx; +} tftSMEContext, *tpftSMEContext; + +/*-------------------------------------------------------------------------- + Prototype functions + ------------------------------------------------------------------------*/ +void sme_ft_open(tHalHandle hHal, uint32_t sessionId); +void sme_ft_close(tHalHandle hHal, uint32_t sessionId); +void sme_ft_reset(tHalHandle hHal, uint32_t sessionId); +void sme_set_ft_ies(tHalHandle hHal, uint32_t sessionId, const uint8_t *ft_ies, + uint16_t ft_ies_length); +QDF_STATUS sme_ft_update_key(tHalHandle hHal, uint32_t sessionId, + tCsrRoamSetKey *pFTKeyInfo); +void sme_get_ft_pre_auth_response(tHalHandle hHal, uint32_t sessionId, + uint8_t *ft_ies, uint32_t ft_ies_ip_len, + uint16_t *ft_ies_length); +void sme_get_rici_es(tHalHandle hHal, uint32_t sessionId, uint8_t *ric_ies, + uint32_t ric_ies_ip_len, uint32_t *ric_ies_length); +void sme_preauth_reassoc_intvl_timer_callback(void *context); +void sme_set_ft_pre_auth_state(tHalHandle hHal, uint32_t sessionId, bool state); +bool sme_get_ft_pre_auth_state(tHalHandle hHal, uint32_t sessionId); +bool sme_get_ftptk_state(tHalHandle hHal, uint32_t sessionId); +void sme_set_ftptk_state(tHalHandle hHal, uint32_t sessionId, bool state); +#endif diff --git a/drivers/staging/qcacld-3.0/core/sme/inc/sme_inside.h b/drivers/staging/qcacld-3.0/core/sme/inc/sme_inside.h new file mode 100644 index 0000000000000000000000000000000000000000..01c0e4e406ce1054a9df422185e77a66c488938b --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/sme/inc/sme_inside.h @@ -0,0 +1,287 @@ +/* + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#if !defined(__SMEINSIDE_H) +#define __SMEINSIDE_H + +/** + * \file sme_inside.h + * + * \brief prototype for SME structures and APIs used insside SME + */ + +/*-------------------------------------------------------------------------- + Include Files + ------------------------------------------------------------------------*/ +#include "qdf_status.h" +#include "qdf_lock.h" +#include "qdf_trace.h" +#include "qdf_mem.h" +#include "qdf_types.h" +#include "sir_api.h" +#include "csr_internal.h" +#include "sme_qos_api.h" +#include "sme_qos_internal.h" + +#include "sme_rrm_api.h" +ePhyChanBondState csr_convert_cb_ini_value_to_phy_cb_state(uint32_t cbIniValue); + +/*-------------------------------------------------------------------------- + Type declarations + ------------------------------------------------------------------------*/ +/* + * In case MAX num of STA are connected to SAP, switching off SAP causes + * two SME cmd to be enqueued for each STA. Keeping SME total cmds as following + * to make sure we have space for these cmds + some additional cmds. + */ +#define SME_TOTAL_COMMAND (HAL_NUM_STA * 3) + +typedef struct sGenericPmcCmd { + uint32_t size; /* sizeof the data in the union, if any */ + uint32_t sessionId; + /* if true, the cmd shalln't put back to the queue, free mem instead. */ + bool fReleaseWhenDone; + union { + tSirSmeWowlEnterParams enterWowlInfo; + tSirSmeWowlExitParams exitWowlInfo; + } u; +} tGenericPmcCmd; + +typedef struct sGenericQosCmd { + sme_QosWmmTspecInfo tspecInfo; + sme_QosEdcaAcType ac; + uint8_t tspec_mask; +} tGenericQosCmd; + +typedef struct sRemainChlCmd { + uint8_t chn; + uint8_t phyMode; + uint32_t duration; + uint8_t isP2PProbeReqAllowed; + uint32_t scan_id; + void *callback; + void *callbackCtx; +} tRemainChlCmd; + +typedef struct sNoACmd { + tP2pPsConfig NoA; +} tNoACmd; +#ifdef FEATURE_WLAN_TDLS +typedef struct TdlsSendMgmtInfo { + tSirMacAddr peerMac; + uint8_t frameType; + uint8_t dialog; + uint16_t statusCode; + uint8_t responder; + uint32_t peerCapability; + uint8_t *buf; + uint8_t len; + enum sir_wifi_traffic_ac ac; +} tTdlsSendMgmtCmdInfo; + +typedef struct TdlsLinkEstablishInfo { + struct qdf_mac_addr peermac; + uint8_t uapsdQueues; + uint8_t maxSp; + uint8_t isBufSta; + uint8_t isOffChannelSupported; + uint8_t isResponder; + uint8_t supportedChannelsLen; + uint8_t supportedChannels[SIR_MAC_MAX_SUPP_CHANNELS]; + uint8_t supportedOperClassesLen; + uint8_t supportedOperClasses[CDS_MAX_SUPP_OPER_CLASSES]; +} tTdlsLinkEstablishCmdInfo; + +typedef struct TdlsAddStaInfo { + eTdlsAddOper tdlsAddOper; + struct qdf_mac_addr peermac; + uint16_t capability; + uint8_t extnCapability[SIR_MAC_MAX_EXTN_CAP]; + uint8_t supportedRatesLen; + uint8_t supportedRates[SIR_MAC_MAX_SUPP_RATES]; + uint8_t htcap_present; + tSirHTCap HTCap; + uint8_t vhtcap_present; + tSirVHTCap VHTCap; + uint8_t uapsdQueues; + uint8_t maxSp; +} tTdlsAddStaCmdInfo; + +typedef struct TdlsDelStaInfo { + struct qdf_mac_addr peermac; +} tTdlsDelStaCmdInfo; +/* + * TDLS cmd info, CMD from SME to PE. + */ +typedef struct s_tdls_cmd { + uint32_t size; + union { + tTdlsLinkEstablishCmdInfo tdlsLinkEstablishCmdInfo; + tTdlsSendMgmtCmdInfo tdlsSendMgmtCmdInfo; + tTdlsAddStaCmdInfo tdlsAddStaCmdInfo; + tTdlsDelStaCmdInfo tdlsDelStaCmdInfo; + } u; +} tTdlsCmd; +#endif /* FEATURE_WLAN_TDLS */ + +/** + * struct s_nss_update_cmd - Format of nss update request + * @new_nss: new nss value + * @session_id: Session ID + * @set_hw_mode_cb: HDD nss update callback + * @context: Adapter context + */ +struct s_nss_update_cmd { + uint32_t new_nss; + uint32_t session_id; + void *nss_update_cb; + void *context; + uint8_t next_action; + enum sir_conn_update_reason reason; +}; + +typedef struct tagSmeCmd { + tListElem Link; + eSmeCommandType command; + uint32_t sessionId; + union { + tScanCmd scanCmd; + tRoamCmd roamCmd; + tWmStatusChangeCmd wmStatusChangeCmd; + tSetKeyCmd setKeyCmd; + tGenericPmcCmd pmcCmd; + tGenericQosCmd qosCmd; + tRemainChlCmd remainChlCmd; + tNoACmd NoACmd; + tAddStaForSessionCmd addStaSessionCmd; + tDelStaForSessionCmd delStaSessionCmd; +#ifdef FEATURE_WLAN_TDLS + tTdlsCmd tdlsCmd; +#endif + struct sir_hw_mode set_hw_mode_cmd; + struct s_nss_update_cmd nss_update_cmd; + struct sir_dual_mac_config set_dual_mac_cmd; + struct sir_antenna_mode_param set_antenna_mode_cmd; +#ifdef WLAN_FEATURE_NAN_DATAPATH + struct ndp_initiator_req initiator_req; + struct ndp_responder_req responder_req; + struct ndp_end_req *data_end_req; +#endif + } u; +} tSmeCmd; + +/*-------------------------------------------------------------------------- + Internal to SME + ------------------------------------------------------------------------*/ +tSmeCmd *sme_get_command_buffer(tpAniSirGlobal pMac); +void sme_push_command(tpAniSirGlobal pMac, tSmeCmd *pCmd, bool fHighPriority); +void sme_process_pending_queue(tpAniSirGlobal pMac); +void sme_release_command(tpAniSirGlobal pMac, tSmeCmd *pCmd); +void purge_sme_session_cmd_list(tpAniSirGlobal pMac, uint32_t sessionId, + tDblLinkList *pList); +bool sme_command_pending(tpAniSirGlobal pMac); +bool qos_process_command(tpAniSirGlobal pMac, tSmeCmd *pCommand); +void qos_release_command(tpAniSirGlobal pMac, tSmeCmd *pCommand); +QDF_STATUS csr_process_scan_command(tpAniSirGlobal pMac, tSmeCmd *pCommand); +QDF_STATUS csr_roam_process_command(tpAniSirGlobal pMac, tSmeCmd *pCommand); +void csr_roam_process_wm_status_change_command(tpAniSirGlobal pMac, + tSmeCmd *pCommand); +void csr_reinit_roam_cmd(tpAniSirGlobal pMac, tSmeCmd *pCommand); +void csr_reinit_wm_status_change_cmd(tpAniSirGlobal pMac, tSmeCmd *pCommand); +void csr_reinit_set_key_cmd(tpAniSirGlobal pMac, tSmeCmd *pCommand); +QDF_STATUS csr_roam_process_set_key_command(tpAniSirGlobal pMac, + tSmeCmd *pCommand); +void csr_release_command_set_key(tpAniSirGlobal pMac, tSmeCmd *pCommand); +void csr_abort_command(tpAniSirGlobal pMac, tSmeCmd *pCommand, bool fStopping); + +QDF_STATUS csr_is_valid_channel(tpAniSirGlobal pMac, uint8_t chnNum); +bool csr_roam_is_valid40_mhz_channel(tpAniSirGlobal pmac, uint8_t channel); + +QDF_STATUS sme_acquire_global_lock(tSmeStruct *psSme); +QDF_STATUS sme_release_global_lock(tSmeStruct *psSme); + +QDF_STATUS csr_process_add_sta_session_command(tpAniSirGlobal pMac, + tSmeCmd *pCommand); +QDF_STATUS csr_process_add_sta_session_rsp(tpAniSirGlobal pMac, uint8_t *pMsg); +QDF_STATUS csr_process_del_sta_session_command(tpAniSirGlobal pMac, + tSmeCmd *pCommand); +QDF_STATUS csr_process_del_sta_session_rsp(tpAniSirGlobal pMac, uint8_t *pMsg); + +#ifdef FEATURE_WLAN_SCAN_PNO +QDF_STATUS pmc_set_preferred_network_list(tHalHandle hHal, + tpSirPNOScanReq pRequest, + uint8_t sessionId, + preferred_network_found_ind_cb + callbackRoutine, void *callbackContext); +#endif /* FEATURE_WLAN_SCAN_PNO */ +bool csr_roamGetConcurrencyConnectStatusForBmps(tpAniSirGlobal pMac); +#ifdef FEATURE_WLAN_TDLS +QDF_STATUS csr_tdls_send_mgmt_req(tHalHandle hHal, uint8_t sessionId, + tCsrTdlsSendMgmt * tdlsSendMgmt); +QDF_STATUS csr_tdls_send_link_establish_params(tHalHandle hHal, + uint8_t sessionId, const tSirMacAddr peerMac, + tCsrTdlsLinkEstablishParams *tdlsLinkEstablishParams); +QDF_STATUS csr_tdls_add_peer_sta(tHalHandle hHal, uint8_t sessionId, + const tSirMacAddr peerMac); +QDF_STATUS csr_tdls_change_peer_sta(tHalHandle hHal, uint8_t sessionId, + const tSirMacAddr peerMac, + tCsrStaParams *pstaParams); +QDF_STATUS csr_tdls_del_peer_sta(tHalHandle hHal, uint8_t sessionId, + const tSirMacAddr peerMac); +QDF_STATUS csr_tdls_process_cmd(tpAniSirGlobal pMac, tSmeCmd *pCommand); +QDF_STATUS csr_tdls_process_link_establish(tpAniSirGlobal pMac, tSmeCmd *cmd); +QDF_STATUS tdls_msg_processor(tpAniSirGlobal pMac, uint16_t msg_type, + void *pMsgBuf); +#endif /* FEATURE_WLAN_TDLS */ + +QDF_STATUS csr_flush_cfg_bg_scan_roam_channel_list(tpAniSirGlobal pMac, + uint8_t sessionId); +QDF_STATUS csr_create_bg_scan_roam_channel_list(tpAniSirGlobal pMac, + uint8_t sessionId, const uint8_t *pChannelList, + const uint8_t numChannels); + +#ifdef FEATURE_WLAN_ESE +QDF_STATUS csr_create_roam_scan_channel_list(tpAniSirGlobal pMac, + uint8_t sessionId, + uint8_t *pChannelList, + uint8_t numChannels, + const eCsrBand eBand); +#endif + +QDF_STATUS p2p_process_remain_on_channel_cmd(tpAniSirGlobal pMac, + tSmeCmd *p2pRemainonChn); +ePhyChanBondState csr_convert_cb_ini_value_to_phy_cb_state(uint32_t cbIniValue); +void active_list_cmd_timeout_handle(void *userData); +void csr_process_set_dual_mac_config(tpAniSirGlobal mac, tSmeCmd *command); +void csr_process_set_antenna_mode(tpAniSirGlobal mac, tSmeCmd *command); +void csr_process_set_hw_mode(tpAniSirGlobal mac, tSmeCmd *command); +void csr_process_nss_update_req(tpAniSirGlobal mac, tSmeCmd *command); + +QDF_STATUS sme_check_ch_in_band(tpAniSirGlobal mac_ctx, uint8_t start_ch, + uint8_t ch_cnt); + +#endif /* #if !defined( __SMEINSIDE_H ) */ diff --git a/drivers/staging/qcacld-3.0/core/sme/inc/sme_internal.h b/drivers/staging/qcacld-3.0/core/sme/inc/sme_internal.h new file mode 100644 index 0000000000000000000000000000000000000000..5388a90777dfd7eb888888115e6d013a83c40b39 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/sme/inc/sme_internal.h @@ -0,0 +1,265 @@ +/* + * Copyright (c) 2011-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#if !defined(__SMEINTERNAL_H) +#define __SMEINTERNAL_H + +/** + * \file sme_internal.h + * + * \brief prototype for SME internal structures and APIs used for SME and MAC + */ + +/*-------------------------------------------------------------------------- + Include Files + ------------------------------------------------------------------------*/ +#include "qdf_status.h" +#include "qdf_lock.h" +#include "qdf_trace.h" +#include "qdf_mem.h" +#include "qdf_types.h" +#include "host_diag_core_event.h" +#include "csr_link_list.h" +#include "sme_power_save.h" + +/*-------------------------------------------------------------------------- + Type declarations + ------------------------------------------------------------------------*/ + +/* Mask can be only have one bit set */ +typedef enum eSmeCommandType { + eSmeNoCommand = 0, + eSmeDropCommand, + /* this is not a command, it is to identify this is a CSR command */ + eSmeCsrCommandMask = 0x10000, + eSmeCommandScan, + eSmeCommandRoam, + eSmeCommandWmStatusChange, + eSmeCommandSetKey, + eSmeCommandAddStaSession, + eSmeCommandDelStaSession, +#ifdef FEATURE_WLAN_TDLS + /* + * eSmeTdlsCommandMask = 0x80000, + * To identify TDLS commands + * These can be considered as csr commands. + */ + eSmeCommandTdlsSendMgmt, + eSmeCommandTdlsAddPeer, + eSmeCommandTdlsDelPeer, + eSmeCommandTdlsLinkEstablish, +#endif + /* PMC */ + eSmePmcCommandMask = 0x20000, /* To identify PMC commands */ + eSmeCommandEnterBmps, + eSmeCommandExitBmps, + eSmeCommandEnterUapsd, + eSmeCommandExitUapsd, + eSmeCommandExitWowl, + eSmeCommandEnterStandby, + /* QOS */ + eSmeQosCommandMask = 0x40000, /* To identify Qos commands */ + eSmeCommandAddTs, + eSmeCommandDelTs, +#ifdef FEATURE_OEM_DATA_SUPPORT + eSmeCommandOemDataReq = 0x80000, /* To identify the oem data commands */ +#endif + eSmeCommandRemainOnChannel, + e_sme_command_set_hw_mode, + e_sme_command_nss_update, + e_sme_command_set_dual_mac_config, + e_sme_command_set_antenna_mode, + eSmeCommandNdpInitiatorRequest, + eSmeCommandNdpResponderRequest, + eSmeCommandNdpDataEndInitiatorRequest, +} eSmeCommandType; + +typedef enum eSmeState { + SME_STATE_STOP, + SME_STATE_START, + SME_STATE_READY, +} eSmeState; + +#define SME_IS_START(pMac) (SME_STATE_STOP != (pMac)->sme.state) +#define SME_IS_READY(pMac) (SME_STATE_READY == (pMac)->sme.state) + +/* HDD Callback function */ +typedef void (*pIbssPeerInfoCb)(void *pUserData, + tSirPeerInfoRspParams *infoParam); + +/* Peer info */ +typedef struct tagSmePeerInfoHddCbkInfo { + void *pUserData; + pIbssPeerInfoCb peerInfoCbk; +} tSmePeerInfoHddCbkInfo; + +typedef struct sStatsExtEvent { + uint32_t vdev_id; + uint32_t event_data_len; + uint8_t event_data[]; +} tStatsExtEvent, *tpStatsExtEvent; + +#define MAX_ACTIVE_CMD_STATS 16 + +typedef struct sActiveCmdStats { + eSmeCommandType command; + uint32_t reason; + uint32_t sessionId; + uint64_t timestamp; +} tActiveCmdStats; + +typedef struct sSelfRecoveryStats { + tActiveCmdStats activeCmdStats[MAX_ACTIVE_CMD_STATS]; + uint8_t cmdStatsIndx; +} tSelfRecoveryStats; + +#ifdef WLAN_FEATURE_GTK_OFFLOAD +/* GTK Offload Information Callback declaration */ +typedef void (*gtk_offload_get_info_callback)(void *callback_context, + tpSirGtkOffloadGetInfoRspParams + pGtkOffloadGetInfoRsp); +#endif +#ifdef FEATURE_WLAN_SCAN_PNO +/*Pref netw found Cb declaration*/ +typedef void (*preferred_network_found_ind_cb)(void *callback_context, + tpSirPrefNetworkFoundInd + pPrefNetworkFoundInd); +#endif + +typedef void (*ocb_callback)(void *context, void *response); +typedef void (*sme_set_thermal_level_callback)(void *context, u_int8_t level); +typedef void (*p2p_lo_callback)(void *context, void *event); +typedef void (*sme_send_oem_data_rsp_msg)(struct oem_data_rsp *); + +typedef struct tagSmeStruct { + eSmeState state; + qdf_mutex_t lkSmeGlobalLock; + uint32_t totalSmeCmd; + /* following pointer contains array of pointers for tSmeCmd* */ + void **pSmeCmdBufAddr; + tDblLinkList smeCmdActiveList; + tDblLinkList smeCmdPendingList; + tDblLinkList smeCmdFreeList; /* preallocated roam cmd list */ + enum tQDF_ADAPTER_MODE currDeviceMode; +#ifdef FEATURE_WLAN_LPHB + void (*pLphbIndCb)(void *pHddCtx, tSirLPHBInd *indParam); +#endif /* FEATURE_WLAN_LPHB */ + /* pending scan command list */ + tDblLinkList smeScanCmdPendingList; + /* active scan command list */ + tDblLinkList smeScanCmdActiveList; + tSmePeerInfoHddCbkInfo peerInfoParams; +#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR + host_event_wlan_status_payload_type eventPayload; +#endif +#ifdef FEATURE_WLAN_CH_AVOID + void (*pChAvoidNotificationCb)(void *hdd_context, void *indi_param); +#endif /* FEATURE_WLAN_CH_AVOID */ +#ifdef WLAN_FEATURE_LINK_LAYER_STATS + void (*pLinkLayerStatsIndCallback)(void *callbackContext, + int indType, void *pRsp); +#endif /* WLAN_FEATURE_LINK_LAYER_STATS */ + +#ifdef WLAN_POWER_DEBUGFS + void *power_debug_stats_context; + void (*power_stats_resp_callback)(struct power_stats_response *rsp, + void *callback_context); +#endif +#ifdef FEATURE_WLAN_AUTO_SHUTDOWN + void (*pAutoShutdownNotificationCb)(void); +#endif + /* Maximum interfaces allowed by the host */ + uint8_t max_intf_count; + void (*StatsExtCallback)(void *, tStatsExtEvent *); + /* linkspeed callback */ + void (*pLinkSpeedIndCb)(tSirLinkSpeedInfo *indParam, + void *pDevContext); + void *pLinkSpeedCbContext; +#ifdef FEATURE_WLAN_EXTSCAN + void (*pExtScanIndCb)(void *, const uint16_t, void *); +#endif /* FEATURE_WLAN_EXTSCAN */ +#ifdef WLAN_FEATURE_NAN + void (*nanCallback)(void *, tSirNanEvent *); +#endif + bool enableSelfRecovery; + tCsrLinkStatusCallback linkStatusCallback; + void *linkStatusContext; + int (*get_tsf_cb)(void *pcb_cxt, struct stsf *ptsf); + void *get_tsf_cxt; + /* get temperature event context and callback */ + void *pTemperatureCbContext; + void (*pGetTemperatureCb)(int temperature, void *context); + uint8_t miracast_value; + struct ps_global_info ps_global_info; +#ifdef WLAN_FEATURE_GTK_OFFLOAD + /* routine to call for GTK Offload Information */ + gtk_offload_get_info_callback gtk_offload_get_info_cb; + /* value to be passed as parameter to routine specified above */ + void *gtk_offload_get_info_cb_context; +#endif /* WLAN_FEATURE_GTK_OFFLOAD */ +#ifdef FEATURE_WLAN_SCAN_PNO + /* routine to call for Preferred Network Found Indication */ + preferred_network_found_ind_cb pref_netw_found_cb; + /* value to be passed as parameter to routine specified above */ + void *preferred_network_found_ind_cb_ctx; +#endif /* FEATURE_WLAN_SCAN_PNO */ + void (*rssi_threshold_breached_cb)(void *, struct rssi_breach_event *); +#ifdef WLAN_FEATURE_MEMDUMP + void (*fw_dump_callback)(void *context, struct fw_dump_rsp *rsp); +#endif + hw_mode_transition_cb sme_hw_mode_trans_cb; + /* OCB callbacks */ + void *ocb_set_config_context; + ocb_callback ocb_set_config_callback; + void *ocb_get_tsf_timer_context; + ocb_callback ocb_get_tsf_timer_callback; + void *dcc_get_stats_context; + ocb_callback dcc_get_stats_callback; + void *dcc_update_ndl_context; + ocb_callback dcc_update_ndl_callback; + void *dcc_stats_event_context; + ocb_callback dcc_stats_event_callback; + sme_set_thermal_level_callback set_thermal_level_cb; + void *saved_scan_cmd; + void (*pbpf_get_offload_cb)(void *context, + struct sir_bpf_get_offload *); + p2p_lo_callback p2p_lo_event_callback; + void *p2p_lo_event_context; + sme_send_oem_data_rsp_msg oem_data_rsp_callback; + void (*encrypt_decrypt_cb)(void *, + struct sir_encrypt_decrypt_rsp_params *); + void (*lost_link_info_cb)(void *context, + struct sir_lost_link_info *lost_link_info); + void (*rso_cmd_status_cb)(void *hdd_context, + struct rso_cmd_status *rso_status); + void (*get_arp_stats_cb)(void *, struct rsp_stats *); + void (*chip_power_save_fail_cb)(void *, + struct chip_pwr_save_fail_detected_params *); + void (*congestion_cb)(void *, uint32_t congestion, uint32_t vdev_id); +} tSmeStruct, *tpSmeStruct; + +#endif /* #if !defined( __SMEINTERNAL_H ) */ diff --git a/drivers/staging/qcacld-3.0/core/sme/inc/sme_nan_datapath.h b/drivers/staging/qcacld-3.0/core/sme/inc/sme_nan_datapath.h new file mode 100644 index 0000000000000000000000000000000000000000..ff3dee1e2ac1c4abdc1c403d71bac9e3c5d50568 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/sme/inc/sme_nan_datapath.h @@ -0,0 +1,190 @@ +/* + * Copyright (c) 2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * 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. + */ + +/** + * DOC: sme_nan_datapath.h + * + * SME NAN Data path API specification + */ + +#ifndef __SME_NAN_DATAPATH_H +#define __SME_NAN_DATAPATH_H + +#include "csr_inside_api.h" + +#ifdef WLAN_FEATURE_NAN_DATAPATH +#include "qdf_types.h" +#include "sir_api.h" +#include "ani_global.h" +#include "sme_inside.h" + +/** + * struct sir_sme_ndp_initiator_req - sme request struct for ndp initiator req + * @mesgType: SME msg type(eWNI_SME_NDP_INITIATOR_REQ) + * @mesgLen: lenght of message + * @req: actual ndp initiator request + * + */ +struct sir_sme_ndp_initiator_req { + uint16_t msg_type; + uint16_t msg_len; + struct ndp_initiator_req req; +}; + +/** + * struct sir_sme_ndp_responder_req - Wraper of responder's response + * to ndp create request + * @msg_type: SME msg type + * @msg_len: Length of msg + * @req: responder's response to ndp create request + * + */ +struct sir_sme_ndp_responder_req { + uint16_t msg_type; + uint16_t msg_len; + struct ndp_responder_req req; +}; + +/* + * struct sir_sme_ndp_end_req - sme request struct for ndp end req + * @msg_type: SME msg type(sir_sme_ndp_initiator_req) + * @msg_len: lenght of message + * @req: actual ndp initiator request + * + */ +struct sir_sme_ndp_end_req { + uint16_t msg_type; + uint16_t msg_len; + struct ndp_end_req *req; +}; + +/* NaN initiator request handler */ +QDF_STATUS sme_ndp_initiator_req_handler(tHalHandle hal, + struct ndp_initiator_req *req_params); + +/* NaN responder request handler */ +QDF_STATUS sme_ndp_responder_req_handler(tHalHandle hal, + struct ndp_responder_req *req_params); + +/* NAN indication response handler */ +QDF_STATUS sme_ndp_end_req_handler(tHalHandle hal, struct ndp_end_req *req); + +/* Start NDI BSS */ +QDF_STATUS csr_roam_start_ndi(tpAniSirGlobal mac_ctx, uint32_t session_id, + tCsrRoamProfile *profile); + +void csr_roam_save_ndi_connected_info(tpAniSirGlobal mac_ctx, + uint32_t session_id, + tCsrRoamProfile *roam_profile, + tSirBssDescription *bss_desc); + +void csr_roam_update_ndp_return_params(tpAniSirGlobal mac_ctx, + uint32_t result, + uint32_t *roam_status, + uint32_t *roam_result, + struct tagCsrRoamInfo *roam_info); +QDF_STATUS csr_process_ndp_initiator_request(tpAniSirGlobal mac_ctx, + tSmeCmd *cmd); +QDF_STATUS csr_process_ndp_data_end_request(tpAniSirGlobal mac_ctx, + tSmeCmd *cmd); + +void sme_ndp_msg_processor(tpAniSirGlobal mac_ctx, cds_msg_t *msg); + +QDF_STATUS csr_process_ndp_responder_request(tpAniSirGlobal mac_ctx, + tSmeCmd *cmd); + +void csr_release_ndp_initiator_req(tpAniSirGlobal mac_ctx, tSmeCmd *cmd); +void csr_release_ndp_responder_req(tpAniSirGlobal mac_ctx, tSmeCmd *cmd); +void csr_release_ndp_data_end_req(tpAniSirGlobal mac_ctx, tSmeCmd *cmd); + +#else + +/* NAN initiator request handler */ +static inline QDF_STATUS sme_ndp_initiator_req_handler(tHalHandle hal, + void *req_params) { + return QDF_STATUS_SUCCESS; +} + +/* NAN responder request handler */ +static inline QDF_STATUS sme_ndp_responder_req_handler(tHalHandle hal, + void *req_params) { + return QDF_STATUS_SUCCESS; +} + +/* Start NDI BSS */ +static inline QDF_STATUS csr_roam_start_ndi(tpAniSirGlobal mac_ctx, + uint32_t session_id, + tCsrRoamProfile *profile) +{ + return QDF_STATUS_SUCCESS; +} + +static inline void csr_roam_save_ndi_connected_info(tpAniSirGlobal mac_ctx, + uint32_t session_id, + tCsrRoamProfile *roam_profile, + tSirBssDescription *bss_desc) +{ +} + +static inline void csr_roam_update_ndp_return_params(tpAniSirGlobal mac_ctx, + uint32_t result, + uint32_t *roam_status, + uint32_t *roam_result, + struct tagCsrRoamInfo *roam_info) +{ +} + +/* NAN indication response handler */ +static inline QDF_STATUS sme_ndp_end_req_handler(uint32_t session_id, + void *req_params) { + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS csr_process_ndp_initiator_request( + tpAniSirGlobal mac_ctx, tSmeCmd *cmd) +{ + return QDF_STATUS_SUCCESS; +} + +static inline void sme_ndp_msg_processor(tpAniSirGlobal mac_ctx, cds_msg_t *msg) +{ +} + +static inline QDF_STATUS csr_process_ndp_responder_request( + tpAniSirGlobal mac_ctx, tSmeCmd *cmd) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS csr_process_ndp_data_end_request( + tpAniSirGlobal mac_ctx, tSmeCmd *cmd) +{ + return QDF_STATUS_SUCCESS; +} + +static inline void csr_release_ndp_initiator_req(tpAniSirGlobal mac_ctx, + tSmeCmd *cmd) {} +static inline void csr_release_ndp_responder_req(tpAniSirGlobal mac_ctx, + tSmeCmd *cmd) {} +static inline void csr_release_ndp_data_end_req(tpAniSirGlobal mac_ctx, + tSmeCmd *cmd) {} + +#endif /* WLAN_FEATURE_NAN_DATAPATH */ +#endif /* __SME_NAN_DATAPATH_H */ diff --git a/drivers/staging/qcacld-3.0/core/sme/inc/sme_power_save.h b/drivers/staging/qcacld-3.0/core/sme/inc/sme_power_save.h new file mode 100644 index 0000000000000000000000000000000000000000..2e7936cde8ed540f1126d8621d28272d2aaba6cc --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/sme/inc/sme_power_save.h @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2015-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#if !defined(__SME_POWER_SAVE_H) +#define __SME_POWER_SAVE_H +#include "qdf_lock.h" +#include "qdf_trace.h" +#include "qdf_mem.h" +#include "qdf_types.h" +#include "ani_system_defs.h" +#include "sir_api.h" + +#define MAX_SME_SESSIONS 5 +/* Auto Ps Entry Timer Default value - 1000 ms */ +#define AUTO_PS_ENTRY_TIMER_DEFAULT_VALUE 1000 + +/* Auto Deferred Ps Entry Timer value - 20000 ms */ +#define AUTO_DEFERRED_PS_ENTRY_TIMER_DEFAULT_VALUE 20000 + +/* + * Auto Ps Entry User default timeout value, used instead of negative timeouts + * from user space - 5000ms + */ +#define AUTO_PS_ENTRY_USER_TIMER_DEFAULT_VALUE 5000 + + +/** + * enum ps_state - State of the power save + * @FULL_POWER_MODE: for Full power mode + * @LEGACY_POWER_SAVE_MODE: For Legacy Power Save mode + * @UAPSD_MODE: for UAPSD power save + */ + +enum ps_state { + FULL_POWER_MODE, + LEGACY_POWER_SAVE_MODE, + UAPSD_MODE +}; + +/** + * struct ps_params - maintain power save state and USAPD params + * @mac_ctx: mac_ctx + * @session_id: Session Id. + * @ps_state : State of the power save + * @uapsd_per_ac_trigger_enable_mask: dynamic UPASD mask setting + * derived from AddTS Rsp and DelTS frame. + * If a particular AC bit is set, it means AC is trigger enabled. + * @uapsd_per_ac_delivery_enable_mask: dynamic UPASD mask setting + * derived from AddTS Rsp and DelTs frame. + * If a particular AC bit is set, it means AC is delivery enabled. + * @ac_admit_mask: used for AC downgrade. This is a dynamic mask + * setting which keep tracks of ACs being admitted. + * If bit is set to 0: That particular AC is not admitted + * If bit is set to 1: That particular AC is admitted + * @ uapsd_per_ac_bit_mask: This is a static UAPSD mask setting + * derived from SME_JOIN_REQ and SME_REASSOC_REQ. + * If a particular AC bit is set, it means the AC is both + * trigger enabled and delivery enabled. + * @enter_wowl_callback_routine: routine to call for wowl request. + * @enter_wowl_callback_context: value to be passed as parameter to + * routine specified above. + * @wowl_enter_params: WOWL mode configuration. + * @wake_reason_ind_cb: routine to call for wake reason indication. + * @wake_reason_ind_cb_ctx: value to be passed as parameter to + * routine specified above. + */ + +struct ps_params { + void *mac_ctx; + uint32_t session_id; + enum ps_state ps_state; + uint8_t uapsd_per_ac_trigger_enable_mask; + uint8_t uapsd_per_ac_delivery_enable_mask; + uint8_t ac_admit_mask[SIR_MAC_DIRECTION_DIRECT]; + uint8_t uapsd_per_ac_bit_mask; + /* WOWL param */ + void (*enter_wowl_callback_routine)(void *callback_context, + QDF_STATUS status); + void *enter_wowl_callback_context; + tSirSmeWowlEnterParams wowl_enter_params; +#ifdef WLAN_WAKEUP_EVENTS + void (*wake_reason_ind_cb)(void *callback_context, + tpSirWakeReasonInd wake_reason_ind); + void *wake_reason_ind_cb_ctx; +#endif /* WLAN_WAKEUP_EVENTS */ +#ifdef FEATURE_WLAN_TDLS + bool is_tdls_power_save_prohibited; +#endif + /* + * Auto Sta Ps Enable Timer + * Upon expiration of this timer + * Power Save Offload module will + * try to enable sta mode ps + */ + qdf_mc_timer_t auto_ps_enable_timer; + +}; + +/** + * struct ps_global_info - global struct for Power save information + * @ps_enabled: Power Save is enabled or not in ini + * @ps_params: maintain power save state and USAPD params + */ +struct ps_global_info { + bool ps_enabled; + uint32_t auto_bmps_timer_val; + struct ps_params ps_params[MAX_SME_SESSIONS]; + /* Remain in Power active till DHCP completes */ + bool remain_in_power_active_till_dhcp; +}; + +/** + * enum sme_ps_cmd: power save message to send WMA + * @SME_PS_ENABLE: For power save enable. + * @SME_PS_DISABLE: for Power save disable. + * @SME_PS_UAPSD_ENABLE; for UAPSD enable. + * @SME_PS_UAPSD_DISABLE: for UAPSD disable. + * @SME_PS_WOWL_ENTER: for WOWL Enter. + * @SME_PS_WOWL_EXIT: for WOWL Exit. + * @SME_PS_WOWL_ADD_BCAST_PTRN: Add bcst WOWL pattern. + * @SME_PS_WOWL_DEL_BCAST_PTRN: Del Bcsr Wowl Pattern. + */ +enum sme_ps_cmd { + SME_PS_ENABLE = 0, + SME_PS_DISABLE, + SME_PS_UAPSD_ENABLE, + SME_PS_UAPSD_DISABLE, + SME_PS_WOWL_ENTER, + SME_PS_WOWL_EXIT, + SME_PS_WOWL_ADD_BCAST_PTRN, + SME_PS_WOWL_DEL_BCAST_PTRN, +}; + +#endif diff --git a/drivers/staging/qcacld-3.0/core/sme/inc/sme_power_save_api.h b/drivers/staging/qcacld-3.0/core/sme/inc/sme_power_save_api.h new file mode 100644 index 0000000000000000000000000000000000000000..1f71ecbb23bdf9945ab3b8dfb4e61fcb1439815b --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/sme/inc/sme_power_save_api.h @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2015-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#if !defined(__SME_POWER_SAVE_API_H) +#define __SME_POWER_SAVE_API_H + +#include "sme_power_save.h" +#include "ani_global.h" +#include "sme_inside.h" + +QDF_STATUS sme_ps_enable_disable(tHalHandle hal_ctx, uint32_t session_id, + enum sme_ps_cmd command); + +QDF_STATUS sme_ps_uapsd_enable(tHalHandle hal_ctx, uint32_t session_id); + +QDF_STATUS sme_ps_uapsd_disable(tHalHandle hal_ctx, uint32_t session_id); + +/* Condition check if driver is ready to enter in PS */ +QDF_STATUS sme_enable_sta_ps_check(tpAniSirGlobal mac_ctx, uint32_t session_id); + +QDF_STATUS sme_ps_process_command(tpAniSirGlobal mac_ctx, + uint32_t session_id, + enum sme_ps_cmd command); + +void sme_set_tspec_uapsd_mask_per_session(tpAniSirGlobal mac_ctx, + tSirMacTSInfo *ts_info, + uint8_t session_id); +/* Full Power Req Callback */ +typedef void (*uapsd_start_indication_cb)(void *callback_context, + uint32_t session_id, QDF_STATUS status); + +QDF_STATUS sme_ps_start_uapsd(tHalHandle hal_ctx, uint32_t session_id, + uapsd_start_indication_cb uapsd_start_ind_cb, + void *callback_context); +QDF_STATUS sme_set_ps_host_offload(tHalHandle hal_ctx, + tpSirHostOffloadReq request, + uint8_t session_id); + +#ifdef WLAN_NS_OFFLOAD +QDF_STATUS sme_set_ps_ns_offload(tHalHandle hal_ctx, + tpSirHostOffloadReq request, + uint8_t session_id); + +#endif /* WLAN_NS_OFFLOAD */ +/* / Post a message to PE module */ +tSirRetStatus sme_post_pe_message(tpAniSirGlobal mac_ctx, tpSirMsgQ pMsg); + +/** + * sme_ps_enable_auto_ps_timer(): Enable power-save auto timer with timeout + * @hal_ctx: HAL context + * @session_id: adapter session Id + * @timeout: timeout period in ms + * @force_trigger: forcing power-save timer to trigger + * + * Returns: 0 on success, non-zero on failure + */ +QDF_STATUS sme_ps_enable_auto_ps_timer(tHalHandle hal_ctx, + uint32_t sessionId, uint32_t timeout, bool force_trigger); +QDF_STATUS sme_ps_disable_auto_ps_timer(tHalHandle hal_ctx, + uint32_t sessionId); + +QDF_STATUS sme_ps_open(tHalHandle hal_ctx); + +QDF_STATUS sme_ps_open_per_session(tHalHandle hal_ctx, uint32_t session_id); + +void sme_auto_ps_entry_timer_expired(void *ps_param); +QDF_STATUS sme_ps_close(tHalHandle hal_ctx); +QDF_STATUS sme_ps_close_per_session(tHalHandle hal_ctx, uint32_t sessionId); +#ifdef FEATURE_WLAN_SCAN_PNO +void sme_set_pno_channel_prediction(tpSirPNOScanReq request_buf, + tpAniSirGlobal mac_ctx); +QDF_STATUS sme_set_ps_preferred_network_list(tHalHandle hal_ctx, + tpSirPNOScanReq request, + uint8_t session_id, + preferred_network_found_ind_cb callback_routine, + void *callback_context); +#else +static inline void sme_set_pno_channel_prediction(void *request_buf, + tpAniSirGlobal mac_ctx) +{} +#endif + +bool sme_is_auto_ps_timer_running(tHalHandle hal_ctx, + uint32_t session_id); + +#endif /* #if !defined(__SME_POWER_SAVE_API_H) */ diff --git a/drivers/staging/qcacld-3.0/core/sme/inc/sme_qos_api.h b/drivers/staging/qcacld-3.0/core/sme/inc/sme_qos_api.h new file mode 100644 index 0000000000000000000000000000000000000000..9ffb46053a96f9388d646ccb08b1f14b627d057c --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/sme/inc/sme_qos_api.h @@ -0,0 +1,257 @@ +/* + * Copyright (c) 2014-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#if !defined(__SME_QOSAPI_H) +#define __SME_QOSAPI_H + +/** + * \file sme_qos_api.h + * + * \brief prototype for SME QoS APIs + */ + +/*-------------------------------------------------------------------------- + Include Files + ------------------------------------------------------------------------*/ +#include "qdf_lock.h" +#include "qdf_trace.h" +#include "qdf_mem.h" +#include "qdf_types.h" +#include "ani_global.h" +#include "sir_api.h" + +/*-------------------------------------------------------------------------- + Pre-processor Definitions + ------------------------------------------------------------------------*/ +#define SME_QOS_UAPSD_VO 0x01 +#define SME_QOS_UAPSD_VI 0x02 +#define SME_QOS_UAPSD_BE 0x08 +#define SME_QOS_UAPSD_BK 0x04 + +/*--------------------------------------------------------------------------- + Enumeration of the various QoS status types that would be reported to HDD + ---------------------------------------------------------------------------*/ +typedef enum { + /* + * async: once PE notifies successful TSPEC negotiation, or CSR notifies + * for successful reassoc, notifies HDD with current QoS Params + */ + SME_QOS_STATUS_SETUP_SUCCESS_IND = 0, + /* sync: only when App asked for APSD & it's already set with ACM = 0 */ + SME_QOS_STATUS_SETUP_SUCCESS_APSD_SET_ALREADY, + /* sync or async: in case of async notify HDD with current QoS Params */ + SME_QOS_STATUS_SETUP_FAILURE_RSP, + /* sync */ + SME_QOS_STATUS_SETUP_INVALID_PARAMS_RSP, + /* sync: AP doesn't support QoS (WMM) */ + SME_QOS_STATUS_SETUP_NOT_QOS_AP_RSP, + /* sync: either req has been sent down to PE or just buffered in SME */ + SME_QOS_STATUS_SETUP_REQ_PENDING_RSP, + /* + * async: in case of flow aggregation, if the new TSPEC negotiation + * is successful, OR, notify existing flows that TSPEC is modified with + * current QoS Params + */ + SME_QOS_STATUS_SETUP_MODIFIED_IND, + /* sync: no APSD asked for & ACM = 0 */ + SME_QOS_STATUS_SETUP_SUCCESS_NO_ACM_NO_APSD_RSP, + /* + * async: In case of UAPSD, once PE notifies successful TSPEC + * negotiation, or CSR notifies for successful reassoc to SME-QoS, + * notify HDD if PMC can't put the module in UAPSD mode right away + * (QDF_STATUS_PMC_PENDING) + */ + SME_QOS_STATUS_SETUP_SUCCESS_IND_APSD_PENDING, + /* + * async: In case of UAPSD, once PE notifies successful TSPEC + * negotiation, or CSR notifies for successful reassoc to SME-QoS, + * notify HDD if PMC can't put the module in UAPSD mode at all + * (QDF_STATUS_E_FAILURE) + */ + SME_QOS_STATUS_SETUP_SUCCESS_IND_APSD_SET_FAILED, + /* + * sync: req has been sent down to PE in case of delts or addts + * for remain flows, OR if the AC doesn't have APSD or ACM + * async: once the downgrade req for QoS params is successful + */ + SME_QOS_STATUS_RELEASE_SUCCESS_RSP = 100, + /* sync or async: in case of async notify HDD with current QoS Param */ + SME_QOS_STATUS_RELEASE_FAILURE_RSP, + /* async: AP sent DELTS indication */ + SME_QOS_STATUS_RELEASE_QOS_LOST_IND, + /* + * sync: an addts req has been sent down to PE to downgrade the + * QoS params or just buffered in SME + */ + SME_QOS_STATUS_RELEASE_REQ_PENDING_RSP, + /* sync */ + SME_QOS_STATUS_RELEASE_INVALID_PARAMS_RSP, + /* + * async: for QoS modify request if modification is successful, + * notifies HDD with current QoS Params + */ + SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_IND = 200, + /* sync: only when App asked for APSD & it's already set with ACM = 0 */ + SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_APSD_SET_ALREADY, + /* sync or async: in case of async notify HDD with current QoS Param */ + SME_QOS_STATUS_MODIFY_SETUP_FAILURE_RSP, + /* sync: either req has been sent down to PE or just buffered in SME */ + SME_QOS_STATUS_MODIFY_SETUP_PENDING_RSP, + /* sync: no APSD asked for & ACM = 0 */ + SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_NO_ACM_NO_APSD_RSP, + /* sync */ + SME_QOS_STATUS_MODIFY_SETUP_INVALID_PARAMS_RSP, + /* + * async: In case of UAPSD, once PE notifies successful TSPEC + * negotiation or CSR notifies for successful reassoc to SME-QoS, + * notify HDD if PMC can't put the module in UAPSD mode right away + * (QDF_STATUS_PMC_PENDING) + */ + SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_IND_APSD_PENDING, + /* + * async: In case of UAPSD, once PE notifies successful TSPEC + * negotiation, or CSR notifies for successful reassoc to SME-QoS, + * notify HDD if PMC can't put the module in UAPSD mode at all + * (QDF_STATUS_E_FAILURE) + */ + SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_IND_APSD_SET_FAILED, + /* sync: STA is handing off to a new AP */ + SME_QOS_STATUS_HANDING_OFF = 300, + /* async:powersave mode changed by PMC from UAPSD to Full power */ + SME_QOS_STATUS_OUT_OF_APSD_POWER_MODE_IND = 400, + /* async:powersave mode changed by PMC from Full power to UAPSD */ + SME_QOS_STATUS_INTO_APSD_POWER_MODE_IND, + +} sme_QosStatusType; + +/*--------------------------------------------------------------------------- + Enumeration of the various User priority (UP) types + + From 802.1D/802.11e/WMM specifications (all refer to same table) + ---------------------------------------------------------------------------*/ +typedef enum { + SME_QOS_WMM_UP_BE = 0, + SME_QOS_WMM_UP_BK = 1, + SME_QOS_WMM_UP_RESV = 2, /* Reserved */ + SME_QOS_WMM_UP_EE = 3, + SME_QOS_WMM_UP_CL = 4, + SME_QOS_WMM_UP_VI = 5, + SME_QOS_WMM_UP_VO = 6, + SME_QOS_WMM_UP_NC = 7, + SME_QOS_WMM_UP_MAX +} sme_QosWmmUpType; + +/*--------------------------------------------------------------------------- + Enumeration of the various TSPEC directions + + From 802.11e/WMM specifications + ---------------------------------------------------------------------------*/ + +typedef enum { + SME_QOS_WMM_TS_DIR_UPLINK = 0, + SME_QOS_WMM_TS_DIR_DOWNLINK = 1, + SME_QOS_WMM_TS_DIR_RESV = 2, /* Reserved */ + SME_QOS_WMM_TS_DIR_BOTH = 3, +} sme_QosWmmDirType; + +/*--------------------------------------------------------------------------- + Enumeration of the various TSPEC ack policies. + + From 802.11 WMM specification + ---------------------------------------------------------------------------*/ + +typedef enum { + SME_QOS_WMM_TS_ACK_POLICY_NORMAL_ACK = 0, + SME_QOS_WMM_TS_ACK_POLICY_RESV1 = 1, + SME_QOS_WMM_TS_ACK_POLICY_RESV2 = 2, /* Reserved */ + SME_QOS_WMM_TS_ACK_POLICY_HT_IMMEDIATE_BLOCK_ACK = 3, + +} sme_QosWmmAckPolicyType; + +/*--------------------------------------------------------------------------- + TS Info field in the WMM TSPEC + + See suggestive values above + ---------------------------------------------------------------------------*/ +typedef struct { + uint8_t burst_size_defn; + sme_QosWmmAckPolicyType ack_policy; + sme_QosWmmUpType up; /* User priority */ + uint8_t psb; /* power-save bit */ + sme_QosWmmDirType direction; /* Direction */ + uint8_t tid; /* TID : To be filled up by SME-QoS */ +} sme_QosWmmTsInfoType; + +/*--------------------------------------------------------------------------- + The WMM TSPEC Element (from the WMM spec) + ---------------------------------------------------------------------------*/ +typedef struct { + sme_QosWmmTsInfoType ts_info; + uint16_t nominal_msdu_size; + uint16_t maximum_msdu_size; + uint32_t min_service_interval; + uint32_t max_service_interval; + uint32_t inactivity_interval; + uint32_t suspension_interval; + uint32_t svc_start_time; + uint32_t min_data_rate; + uint32_t mean_data_rate; + uint32_t peak_data_rate; + uint32_t max_burst_size; + uint32_t delay_bound; + uint32_t min_phy_rate; + uint16_t surplus_bw_allowance; + uint16_t medium_time; +} sme_QosWmmTspecInfo; + +/*-------------------------------------------------------------------------- + External APIs + ------------------------------------------------------------------------*/ +typedef QDF_STATUS (*sme_QosCallback)(tHalHandle hHal, void *HDDcontext, + sme_QosWmmTspecInfo *pCurrentQoSInfo, + sme_QosStatusType status, uint32_t QosFlowID); +sme_QosStatusType sme_qos_setup_req(tHalHandle hHal, uint32_t sessionId, + sme_QosWmmTspecInfo *pQoSInfo, + sme_QosCallback QoSCallback, void *HDDcontext, + sme_QosWmmUpType UPType, uint32_t *pQosFlowID); +sme_QosStatusType sme_qos_modify_req(tHalHandle hHal, + sme_QosWmmTspecInfo *pQoSInfo, uint32_t QosFlowID); +sme_QosStatusType sme_qos_release_req(tHalHandle hHal, uint8_t session_id, + uint32_t QosFlowID); +bool sme_qos_is_ts_info_ack_policy_valid(tpAniSirGlobal pMac, + sme_QosWmmTspecInfo *pQoSInfo, uint8_t sessionId); +void sme_qos_update_hand_off(uint8_t sessionId, bool updateHandOff); +QDF_STATUS sme_update_dsc_pto_up_mapping(tHalHandle hHal, + sme_QosWmmUpType *dscpmapping, uint8_t sessionId); + +QDF_STATUS sme_offload_qos_process_out_of_uapsd_mode(tpAniSirGlobal mac_ctx, + uint32_t session_id); +QDF_STATUS sme_offload_qos_process_into_uapsd_mode(tpAniSirGlobal mac_ctx, + uint32_t session_id); + + +#endif /* #if !defined( __SME_QOSAPI_H ) */ diff --git a/drivers/staging/qcacld-3.0/core/sme/inc/sme_qos_internal.h b/drivers/staging/qcacld-3.0/core/sme/inc/sme_qos_internal.h new file mode 100644 index 0000000000000000000000000000000000000000..109fd50cfa67250a2f380284e18d8b2fb92a492c --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/sme/inc/sme_qos_internal.h @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2014-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#if !defined(__SMEQOSINTERNAL_H) +#define __SMEQOSINTERNAL_H + +/** + * \file sme_qos_internal.h + * + * \brief prototype for SME QoS APIs + */ + +/*-------------------------------------------------------------------------- + Include Files + ------------------------------------------------------------------------*/ +#include "qdf_lock.h" +#include "qdf_trace.h" +#include "qdf_mem.h" +#include "qdf_types.h" +#include "ani_global.h" +#include "sir_api.h" +#include "sme_qos_api.h" +#include "sme_internal.h" + +/*-------------------------------------------------------------------------- + Type declarations + ------------------------------------------------------------------------*/ +#define SME_QOS_AP_SUPPORTS_APSD 0x80 + +/*--------------------------------------------------------------------------- + Enumeration of the various EDCA Access Categories: + Based on AC to ACI mapping in 802.11e spec (identical to WMM) + ---------------------------------------------------------------------------*/ +typedef enum { + SME_QOS_EDCA_AC_BE = 0, /* Best effort access category */ + SME_QOS_EDCA_AC_BK = 1, /* Background access category */ + SME_QOS_EDCA_AC_VI = 2, /* Video access category */ + SME_QOS_EDCA_AC_VO = 3, /* Voice access category */ + + SME_QOS_EDCA_AC_MAX +} sme_QosEdcaAcType; + +/*--------------------------------------------------------------------------- + Enumeration of the various CSR event indication types that would be reported + by CSR + ---------------------------------------------------------------------------*/ +typedef enum { + SME_QOS_CSR_JOIN_REQ = 0, + SME_QOS_CSR_ASSOC_COMPLETE, + SME_QOS_CSR_REASSOC_REQ, + SME_QOS_CSR_REASSOC_COMPLETE, + SME_QOS_CSR_REASSOC_FAILURE, + SME_QOS_CSR_DISCONNECT_REQ, + SME_QOS_CSR_DISCONNECT_IND, + SME_QOS_CSR_HANDOFF_ASSOC_REQ, + SME_QOS_CSR_HANDOFF_COMPLETE, + SME_QOS_CSR_HANDOFF_FAILURE, + SME_QOS_CSR_PREAUTH_SUCCESS_IND, + SME_QOS_CSR_SET_KEY_SUCCESS_IND, +} sme_qos_csr_event_indType; + +#ifdef FEATURE_WLAN_DIAG_SUPPORT +typedef enum { + SME_QOS_DIAG_ADDTS_REQ = 0, + SME_QOS_DIAG_ADDTS_RSP, + SME_QOS_DIAG_DELTS +} sme_QosDiagQosEventSubtype; + +typedef enum { + SME_QOS_DIAG_ADDTS_ADMISSION_ACCEPTED = 0, + SME_QOS_DIAG_ADDTS_INVALID_PARAMS, + SME_QOS_DIAG_ADDTS_RESERVED, + SME_QOS_DIAG_ADDTS_REFUSED, + SME_QOS_DIAG_USER_REQUESTED, + SME_QOS_DIAG_DELTS_IND_FROM_AP, + +} sme_QosDiagQosEventReasonCode; + +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ +/*--------------------------------------------------------------------------- + The association information structure to be passed by CSR after assoc or + reassoc is done + ---------------------------------------------------------------------------*/ +typedef struct { + tSirBssDescription *pBssDesc; + tCsrRoamProfile *pProfile; +} sme_QosAssocInfo; + +/*-------------------------------------------------------------------------- + External APIs for CSR - Internal to SME + ------------------------------------------------------------------------*/ +QDF_STATUS sme_qos_open(tpAniSirGlobal pMac); +QDF_STATUS sme_qos_close(tpAniSirGlobal pMac); +QDF_STATUS sme_qos_msg_processor(tpAniSirGlobal pMac, uint16_t msg_type, + void *pMsgBuf); + +/*-------------------------------------------------------------------------- + Internal APIs for CSR + ------------------------------------------------------------------------*/ +QDF_STATUS sme_qos_validate_params(tpAniSirGlobal pMac, + tSirBssDescription *pBssDesc); +/** + * sme_qos_remove_addts_delts_cmd - Remove addts/delts command + * @mac_ctx: Pointer to the global MAC structure. + * @session_id: Session id + * + * This function is used to remove addts/delts command + * during csr roam sync callback. + * + * Return: void + */ +void sme_qos_remove_addts_delts_cmd(tpAniSirGlobal mac_ctx, uint8_t session_id); +QDF_STATUS sme_qos_csr_event_ind(tpAniSirGlobal pMac, + uint8_t sessionId, + sme_qos_csr_event_indType ind, void *pEvent_info); +uint8_t sme_qos_get_acm_mask(tpAniSirGlobal pMac, + tSirBssDescription *pSirBssDesc, tDot11fBeaconIEs *pIes); +#ifdef FEATURE_WLAN_ESE +uint8_t sme_qos_ese_retrieve_tspec_info(tpAniSirGlobal pMac, uint8_t sessionId, + tTspecInfo * pTspecInfo); +#endif + +#endif /* #if !defined( __SMEQOSINTERNAL_H ) */ diff --git a/drivers/staging/qcacld-3.0/core/sme/inc/sme_rrm_api.h b/drivers/staging/qcacld-3.0/core/sme/inc/sme_rrm_api.h new file mode 100644 index 0000000000000000000000000000000000000000..049a558995078172f4d403c64da3f70aa33a7cb7 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/sme/inc/sme_rrm_api.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2014-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#if !defined(__SMERRMAPI_H) +#define __SMERRMAPI_H + +/** + * \file sme_rrm_api.h + * + * \brief prototype for SME RRM APIs + */ + +/*-------------------------------------------------------------------------- + Include Files + ------------------------------------------------------------------------*/ +#include "qdf_lock.h" +#include "qdf_trace.h" +#include "qdf_mem.h" +#include "qdf_types.h" +#include "ani_global.h" +#include "sir_api.h" +#include "sme_internal.h" +#include "sme_rrm_internal.h" + +QDF_STATUS sme_rrm_msg_processor(tpAniSirGlobal pMac, uint16_t msg_type, + void *pMsgBuf); +QDF_STATUS rrm_close(tpAniSirGlobal pMac); +QDF_STATUS rrm_ready(tpAniSirGlobal pMac); +QDF_STATUS rrm_open(tpAniSirGlobal pMac); +QDF_STATUS rrm_change_default_config_param(tpAniSirGlobal pMac, + struct rrm_config_param *rrm_config); +QDF_STATUS sme_rrm_neighbor_report_request(tpAniSirGlobal pMac, + uint8_t sessionId, tpRrmNeighborReq pNeighborReq, + tpRrmNeighborRspCallbackInfo callbackInfo); +QDF_STATUS sme_rrm_process_beacon_report_req_ind(tpAniSirGlobal pMac, + void *pMsgBuf); + +#endif diff --git a/drivers/staging/qcacld-3.0/core/sme/inc/sme_rrm_internal.h b/drivers/staging/qcacld-3.0/core/sme/inc/sme_rrm_internal.h new file mode 100644 index 0000000000000000000000000000000000000000..d172894acb3fc06217601d36d82fc4f492e84fb2 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/sme/inc/sme_rrm_internal.h @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2011-2012, 2014-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#if !defined(__SMERRMINTERNAL_H) +#define __SMERRMINTERNAL_H + +/** + * \file sme_rrm_internal.h + * + * \brief prototype for SME RRM APIs + */ + +/*-------------------------------------------------------------------------- + Include Files + ------------------------------------------------------------------------*/ +#include "qdf_lock.h" +#include "qdf_trace.h" +#include "qdf_mem.h" +#include "qdf_types.h" +#include "rrm_global.h" + +/*-------------------------------------------------------------------------- + Type declarations + ------------------------------------------------------------------------*/ +typedef struct sRrmNeighborReportDesc { + tListElem List; + tSirNeighborBssDescription *pNeighborBssDescription; + uint32_t roamScore; + uint8_t sessionId; +} tRrmNeighborReportDesc, *tpRrmNeighborReportDesc; + +typedef void (*NeighborReportRspCallback)(void *context, + QDF_STATUS qdf_status); + +typedef struct sRrmNeighborRspCallbackInfo { + uint32_t timeout; /* in ms.. min value is 10 (10ms) */ + NeighborReportRspCallback neighborRspCallback; + void *neighborRspCallbackContext; +} tRrmNeighborRspCallbackInfo, *tpRrmNeighborRspCallbackInfo; + +typedef struct sRrmNeighborRequestControlInfo { + /* To check whether a neighbor req is already sent & response pending */ + bool isNeighborRspPending; + qdf_mc_timer_t neighborRspWaitTimer; + tRrmNeighborRspCallbackInfo neighborRspCallbackInfo; +} tRrmNeighborRequestControlInfo, *tpRrmNeighborRequestControlInfo; + +typedef struct sRrmSMEContext { + uint16_t token; + struct qdf_mac_addr sessionBssId; + uint8_t regClass; + /* list of all channels to be measured. */ + tCsrChannelInfo channelList; + uint8_t currentIndex; + /* SSID used in the measuring beacon report. */ + tAniSSID ssId; + tSirMacAddr bssId; /* bssid used for beacon report measurement. */ + /* Randomization interval to be used in subsequent measurements. */ + uint16_t randnIntvl; + uint16_t duration[SIR_ESE_MAX_MEAS_IE_REQS]; + uint8_t measMode[SIR_ESE_MAX_MEAS_IE_REQS]; + struct rrm_config_param rrmConfig; + qdf_mc_timer_t IterMeasTimer; + tDblLinkList neighborReportCache; + tRrmNeighborRequestControlInfo neighborReqControlInfo; + +#ifdef FEATURE_WLAN_ESE + tCsrEseBeaconReq eseBcnReqInfo; + bool eseBcnReqInProgress; +#endif /* FEATURE_WLAN_ESE */ + tRrmMsgReqSource msgSource; +} tRrmSMEContext, *tpRrmSMEContext; + +typedef struct sRrmNeighborReq { + uint8_t no_ssid; + tSirMacSSid ssid; +} tRrmNeighborReq, *tpRrmNeighborReq; + +#endif /* #if !defined( __SMERRMINTERNAL_H ) */ diff --git a/drivers/staging/qcacld-3.0/core/sme/inc/sme_trace.h b/drivers/staging/qcacld-3.0/core/sme/inc/sme_trace.h new file mode 100644 index 0000000000000000000000000000000000000000..61ea3d2d4c6c8659c156d220abb0f1431fab2366 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/sme/inc/sme_trace.h @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2013-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * \sme_trace.h + * + * \brief definition for trace related APIs + */ + +#ifndef __SME_TRACE_H__ +#define __SME_TRACE_H__ + +#include "mac_trace.h" + +#define NO_SESSION 0xFF +enum { + TRACE_CODE_SME_RX_HDD_MSG_SCAN_REQ, + TRACE_CODE_SME_RX_HDD_MSG_SCAN_GET_RESULTS, + TRACE_CODE_SME_RX_HDD_MSG_CONNECT, + TRACE_CODE_SME_RX_HDD_MSG_SET_11DINFO, + TRACE_CODE_SME_RX_HDD_MSG_GET_SOFTAP_DOMAIN, + TRACE_CODE_SME_RX_HDD_MSG_SET_REGINFO, + TRACE_CODE_SME_RX_HDD_MSG_UPDATE_CHANNEL_CONFIG, + TRACE_CODE_SME_RX_HDD_MSG_UPDATE_CONFIG, + TRACE_CODE_SME_RX_HDD_MSG_HDDREADYIND, + TRACE_CODE_SME_RX_HDD_MSG_SCAN_FLUSH_RESULTS, + TRACE_CODE_SME_RX_HDD_MSG_SCAN_FLUSH_P2PRESULTS, + TRACE_CODE_SME_RX_HDD_MSG_SCAN_RESULT_GETFIRST, + TRACE_CODE_SME_RX_HDD_MSG_SCAN_RESULT_GETNEXT, + TRACE_CODE_SME_RX_HDD_MSG_SCAN_RESULT_PURGE, + TRACE_CODE_SME_RX_HDD_ROAM_REASSOC, + TRACE_CODE_SME_RX_HDD_ROAM_DISCONNECT, + TRACE_CODE_SME_RX_HDD_ROAM_GET_CONNECTPROFILE, + TRACE_CODE_SME_RX_HDD_ROAM_FREE_CONNECTPROFILE, + TRACE_CODE_SME_RX_HDD_ROAM_SET_PMKIDCACHE, + TRACE_CODE_SME_RX_HDD_ROAM_GET_PMKIDCACHE, + TRACE_CODE_SME_RX_HDD_GET_CONFIGPARAM, + TRACE_CODE_SME_RX_HDD_GET_MODPROFFIELDS, + TRACE_CODE_SME_RX_HDD_SET_CONFIG_PWRSAVE, + TRACE_CODE_SME_RX_HDD_GET_CONFIG_PWRSAVE, + TRACE_CODE_SME_RX_HDD_ENABLE_PWRSAVE, + TRACE_CODE_SME_RX_HDD_DISABLE_PWRSAVE, + TRACE_CODE_SME_RX_HDD_SIGNAL_POWER_EVENT, + TRACE_CODE_SME_RX_HDD_START_AUTO_BMPSTIMER, + TRACE_CODE_SME_RX_HDD_STOP_AUTO_BMPSTIMER, + TRACE_CODE_SME_RX_HDD_IS_PWRSAVE_ENABLED, + TRACE_CODE_SME_RX_HDD_REQUEST_FULLPOWER, + TRACE_CODE_SME_RX_HDD_REQUEST_BMPS, + TRACE_CODE_SME_RX_HDD_SET_DHCP_FLAG, + TRACE_CODE_SME_RX_HDD_REQUEST_STANDBY, + TRACE_CODE_SME_RX_HDD_WOWL_ADDBCAST_PATTERN, + TRACE_CODE_SME_RX_HDD_WOWL_DELBCAST_PATTERN, + TRACE_CODE_SME_RX_HDD_ENTER_WOWL, + TRACE_CODE_SME_RX_HDD_EXIT_WOWL, + TRACE_CODE_SME_RX_HDD_SET_KEY, + TRACE_CODE_SME_RX_HDD_REMOVE_KEY, + TRACE_CODE_SME_RX_HDD_GET_STATS, + TRACE_CODE_SME_RX_HDD_GET_RSSI, + TRACE_CODE_SME_RX_HDD_GET_CNTRYCODE, + TRACE_CODE_SME_RX_HDD_SET_CNTRYCODE, + TRACE_CODE_SME_RX_HDD_CHANGE_CNTRYCODE, + TRACE_CODE_SME_RX_HDD_SET_CFGPRIVACY, + TRACE_CODE_SME_RX_HDD_NEIGHBOR_REPORTREQ, + TRACE_CODE_SME_RX_HDD_DBG_READREG, + TRACE_CODE_SME_RX_HDD_DBG_WRITEREG, + TRACE_CODE_SME_RX_HDD_DBG_READMEM, + TRACE_CODE_SME_RX_HDD_DBG_WRITEMEM, + TRACE_CODE_SME_RX_HDD_OPEN_SESSION, + TRACE_CODE_SME_RX_HDD_CLOSE_SESSION, + TRACE_CODE_SME_RX_HDD_SET_HOSTOFFLOAD, + TRACE_CODE_SME_RX_HDD_SET_GTKOFFLOAD, + TRACE_CODE_SME_RX_HDD_GET_GTKOFFLOAD, + TRACE_CODE_SME_RX_HDD_ABORT_MACSCAN, + TRACE_CODE_SME_RX_HDD_REGISTER_MGMTFR, + TRACE_CODE_SME_RX_HDD_DEREGISTER_MGMTFR, + TRACE_CODE_SME_RX_HDD_REMAIN_ONCHAN, + TRACE_CODE_SME_RX_HDD_SEND_ACTION, + TRACE_CODE_SME_RX_HDD_CANCEL_REMAIN_ONCHAN, + TRACE_CODE_SME_RX_HDD_CONFIG_RXPFIL, + TRACE_CODE_SME_RX_HDD_CONFIG_SUSPENDIND, + TRACE_CODE_SME_RX_HDD_CONFIG_RESUMEREQ, +#ifdef WLAN_FEATURE_EXTWOW_SUPPORT + TRACE_CODE_SME_RX_HDD_CONFIG_EXTWOW, + TRACE_CODE_SME_RX_HDD_CONFIG_APP_TYPE1, + TRACE_CODE_SME_RX_HDD_CONFIG_APP_TYPE2, +#endif + TRACE_CODE_SME_RX_HDD_SET_MAXTXPOW, + TRACE_CODE_SME_RX_HDD_SET_TXPOW, + TRACE_CODE_SME_RX_HDD_SET_TMLEVEL, + TRACE_CODE_SME_RX_HDD_CAPS_EXCH, + TRACE_CODE_SME_RX_HDD_DISABLE_CAP, + TRACE_CODE_SME_RX_HDD_GET_DEFCCNV, + TRACE_CODE_SME_RX_HDD_GET_CURCC, + TRACE_CODE_SME_RX_HDD_RESET_PW5G, + TRACE_CODE_SME_RX_HDD_UPDATE_RP5G, + TRACE_CODE_SME_RX_HDD_SET_ROAMIBAND, + TRACE_CODE_SME_RX_HDD_GET_ROAMIBAND, + TRACE_CODE_SME_RX_HDD_UPDATE_RSSIDIFF, + TRACE_CODE_SME_RX_HDD_UPDATE_IMMRSSIDIFF, + TRACE_CODE_SME_RX_HDD_UPDATE_FTENABLED, + TRACE_CODE_SME_RX_HDD_UPDATE_WESMODE, + TRACE_CODE_SME_RX_HDD_SET_SCANCTRL, + TRACE_CODE_SME_RX_HDD_UPDATE_P2P_IE, + TRACE_CODE_SME_RX_HDD_UPDATE_ROAM_SCAN_N_PROBES, + TRACE_CODE_SME_RX_HDD_UPDATE_ROAM_SCAN_HOME_AWAY_TIME, + TRACE_CODE_SME_RX_HDD_STORE_JOIN_REQ, + TRACE_CODE_SME_RX_HDD_CLEAR_JOIN_REQ, + TRACE_CODE_SME_RX_HDD_ISSUE_JOIN_REQ, + TRACE_CODE_SME_RX_HDD_MSG_DEAUTH_STA, +#ifdef FEATURE_WLAN_TDLS + TRACE_CODE_SME_RX_HDD_TDLS_LINK_ESTABLISH_PARAM, + TRACE_CODE_SME_RX_HDD_TDLS_CHAN_SWITCH_REQ, + TRACE_CODE_SME_RX_HDD_TDLS_SEND_MGMT_FRAME, + TRACE_CODE_SME_RX_HDD_TDLS_CHANGE_PEER_STA, + TRACE_CODE_SME_RX_HDD_TDLS_ADD_PEER_STA, + TRACE_CODE_SME_RX_HDD_TDLS_DEL_PEER_STA, +#endif + TRACE_CODE_SME_RX_HDD_PREF_NET_LIST, +#ifdef FEATURE_WLAN_LPHB + TRACE_CODE_SME_RX_HDD_LPHB_CONFIG_REQ, +#endif /* FEATURE_WLAN_LPHB */ + TRACE_CODE_SME_RX_HDD_ROAM_DEL_PMKIDCACHE, + /* + * New trace commands to be added before this comment not at the end + * Trace codes for SME commands + */ + TRACE_CODE_SME_COMMAND = 250, + TRACE_CODE_SME_TX_WMA_MSG, + TRACE_CODE_SME_RX_WMA_MSG, +}; + +void sme_trace_init(tpAniSirGlobal pMac); +#endif /* __SME_TRACE_H__ */ diff --git a/drivers/staging/qcacld-3.0/core/sme/inc/sms_debug.h b/drivers/staging/qcacld-3.0/core/sme/inc/sms_debug.h new file mode 100644 index 0000000000000000000000000000000000000000..adebc13604be55824822a1ce8a0747eb42b2077a --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/sme/inc/sms_debug.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2011, 2013-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * \file cssDebug.h + * + * Define debug log interface for SMS. + */ + +#ifndef SMS_DEBUG_H__ +#define SMS_DEBUG_H__ + +#include "utils_api.h" +#include "sir_debug.h" + +#if !defined(__printf) +#define __printf(a, b) +#endif + +void __printf(3, 4) + sms_log(tpAniSirGlobal pMac, uint32_t loglevel, + const char *pString, ...); + +#endif /* __SMS_DEBUG_H__ */ diff --git a/drivers/staging/qcacld-3.0/core/sme/inc/wlan_ps_wow_diag.h b/drivers/staging/qcacld-3.0/core/sme/inc/wlan_ps_wow_diag.h new file mode 100644 index 0000000000000000000000000000000000000000..3d1cbc3d2b9187646129e8dc99d23b3fcec3b1d8 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/sme/inc/wlan_ps_wow_diag.h @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2013-2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef _WLAN_PS_WOW_DIAG_H_ +#define _WLAN_PS_WOW_DIAG_H_ + +#include "host_diag_core_event.h" +#include "host_diag_core_log.h" + +#ifdef FEATURE_WLAN_DIAG_SUPPORT + +typedef enum { + WLAN_BMPS_ENTER_REQ = 0, + WLAN_UAPSD_START_REQ = 1, + WLAN_UAPSD_STOP_REQ = 2, + WLAN_ENTER_STANDBY_REQ = 3, + WLAN_ENTER_DEEP_SLEEP_REQ = 4, + WLAN_START_BMPS_AUTO_TIMER_REQ = 5, + WLAN_STOP_BMPS_AUTO_TIMER_REQ = 6, + WLAN_ENTER_FULL_POWER_REQ = 7, + WLAN_PMC_CURRENT_STATE = 8, + WLAN_PS_MODE_ENABLE_REQ = 9, + WLAN_PS_MODE_DISABLE_REQ = 10, + WLAN_WINMOB_D_POWER_STATE = 11, + WLAN_BMPS_DTIM_PERIOD = 12, + WLAN_BMPS_FINAL_LI = 13, + WLAN_BMPS_SET_CONFIG = 14, + +} wlan_ps_evt_subtype_t; + +/* maps directly to eRequestFullPowerReason */ +typedef enum { + /* PE received a MAX_MISSED_BEACON_IND */ + WLAN_MISSED_BEACON_IND_RCVD, + /* PE received a SIR_HAL_BMPS_STATUS_IND */ + WLAN_BMPS_STATUS_IND_RCVD, + /* BMPS mode was disabled by HDD in SME */ + WLAN_BMPS_MODE_DISABLED, + /* Link has been disconnected requested by HDD */ + WLAN_LINK_DISCONNECTED_BY_HDD, + /* Disconnect due to linklost or requested by peer */ + WLAN_LINK_DISCONNECTED_BY_OTHER, + /* HDD request full power for some reason */ + WLAN_FULL_PWR_NEEDED_BY_HDD, + /* BAP request full power for BT_AMP */ + WLAN_FULL_PWR_NEEDED_BY_BAP, + /* CSR requests full power */ + WLAN_FULL_PWR_NEEDED_BY_CSR, + /* QOS requests full power */ + WLAN_FULL_PWR_NEEDED_BY_QOS, + /* No specific reason. General reason code */ + WLAN_REASON_OTHER +} wlan_ps_full_power_request_reason_t; + +/* maps directly to ePmcState */ +typedef enum { + WLAN_PMC_STOPPED, /* PMC is stopped */ + WLAN_PMC_FULL_POWER, /* full power */ + WLAN_PMC_LOW_POWER, /* low power */ + WLAN_PMC_REQUEST_BMPS, /* requesting BMPS */ + WLAN_PMC_BMPS, /* in BMPS */ + WLAN_PMC_REQUEST_FULL_POWER, /* requesting full power */ + WLAN_PMC_REQUEST_START_UAPSD, /* requesting Start UAPSD */ + WLAN_PMC_REQUEST_STOP_UAPSD, /* requesting Stop UAPSD */ + WLAN_PMC_UAPSD, /* in UAPSD */ + WLAN_PMC_REQUEST_STANDBY, /* requesting standby mode */ + WLAN_PMC_STANDBY, /* in standby mode */ + WLAN_PMC_REQUEST_ENTER_WOWL, /* requesting enter WOWL */ + WLAN_PMC_REQUEST_EXIT_WOWL, /* requesting exit WOWL */ + WLAN_PMC_WOWL /* Chip in WOWL mode */ +} wlan_ps_pmc_current_state_t; + +/* maps directly to ePmcPowerSavingMode */ +typedef enum { + WLAN_IDLE_MODE_POWER_SAVE, /* Idle Mode Power Save (IMPS) */ + WLAN_BEACON_MODE_POWER_SAVE, /* Beacon Mode Power Save (BMPS) */ + WLAN_SPATIAL_MULTIPLEX_POWER_SAVE, /* Spatial Multiplexing Power Save */ + WLAN_UAPSD_MODE_POWER_SAVE, /* Unscheduled Auto PS Delivery Mode */ + WLAN_STANDBY_MODE_POWER_SAVE, /* Standby Power Save Mode */ + WLAN_WOWL_MODE_POWER_SAVE /* Wake-on-Wireless Power Save Mode */ +} wlan_ps_enable_disable_ps_mode_t; + +typedef enum { + WLAN_D0, + WLAN_D1, + WLAN_D2, + WLAN_D3, + WLAN_D4 +} wlan_ps_winmob_d_power_state_t; + +typedef enum { + WLAN_WOW_ENTER_REQ = 0, + WLAN_WOW_EXIT_REQ = 1, + WLAN_WOW_DEL_PTRN_REQ = 2, + WLAN_WOW_WAKEUP = 3 +} wlan_ps_wow_evt_subtype_t; + +typedef enum { + WLAN_WOW_TYPE_NONE, + WLAN_WOW_TYPE_MAGIC_PKT_ONLY, + WLAN_WOW_TYPE_PTRN_BYTE_MATCH_ONLY, + WLAN_WOW_TYPE_MAGIC_PKT_PTRN_BYTE_MATCH, +} wlan_ps_wow_type_t; + +typedef enum { + WLAN_WOW_MAGIC_PKT_MATCH, + WLAN_WOW_PTRN_BYTE_MATCH +} wlan_ps_wos_wakeup_cause_t; + +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + +#endif /* _WLAN_PS_WOW_DIAG_H_ */ diff --git a/drivers/staging/qcacld-3.0/core/sme/src/common/sme_api.c b/drivers/staging/qcacld-3.0/core/sme/src/common/sme_api.c new file mode 100644 index 0000000000000000000000000000000000000000..622259019fdff4dc2e9c446a05ffb61e8dc18529 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/sme/src/common/sme_api.c @@ -0,0 +1,17797 @@ +/* + * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/**========================================================================= + + \file smeApi.c + + \brief Definitions for SME APIs + + ========================================================================*/ + +/*-------------------------------------------------------------------------- + Include Files + ------------------------------------------------------------------------*/ + +#include "sms_debug.h" +#include "sme_api.h" +#include "csr_inside_api.h" +#include "sme_inside.h" +#include "csr_internal.h" +#include "wma_types.h" +#include "wma_if.h" +#include "qdf_trace.h" +#include "sme_trace.h" +#include "qdf_types.h" +#include "qdf_trace.h" +#include "cds_utils.h" +#include "sap_api.h" +#include "mac_trace.h" +#ifdef WLAN_FEATURE_NAN +#include "nan_api.h" +#endif +#include "cds_regdomain.h" +#include "cfg_api.h" +#include "sme_power_save_api.h" +#include "wma.h" +#include "sch_api.h" +#include "sme_nan_datapath.h" +#include "csr_api.h" + +#define LOG_SIZE 256 + +static tSelfRecoveryStats g_self_recovery_stats; + +static QDF_STATUS init_sme_cmd_list(tpAniSirGlobal pMac); +static void sme_abort_command(tpAniSirGlobal pMac, tSmeCmd *pCommand, + bool fStopping); + +eCsrPhyMode sme_get_phy_mode(tHalHandle hHal); + +QDF_STATUS sme_handle_change_country_code(tpAniSirGlobal pMac, void *pMsgBuf); + +void sme_disconnect_connected_sessions(tpAniSirGlobal pMac); + +QDF_STATUS sme_handle_generic_change_country_code(tpAniSirGlobal pMac, + void *pMsgBuf); + +QDF_STATUS sme_process_nss_update_resp(tpAniSirGlobal mac, uint8_t *msg); + +#ifdef FEATURE_WLAN_ESE +bool csr_is_supported_channel(tpAniSirGlobal pMac, uint8_t channelId); +#endif + +#ifdef WLAN_FEATURE_11W +QDF_STATUS sme_unprotected_mgmt_frm_ind(tHalHandle hHal, + tpSirSmeUnprotMgmtFrameInd pSmeMgmtFrm); +#endif + +/* Message processor for events from DFS */ +QDF_STATUS dfs_msg_processor(tpAniSirGlobal pMac, + uint16_t msg_type, void *pMsgBuf); + +/* Channel Change Response Indication Handler */ +QDF_STATUS sme_process_channel_change_resp(tpAniSirGlobal pMac, + uint16_t msg_type, void *pMsgBuf); + +/* Internal SME APIs */ +QDF_STATUS sme_acquire_global_lock(tSmeStruct *psSme) +{ + QDF_STATUS status = QDF_STATUS_E_INVAL; + + if (psSme) { + if (QDF_IS_STATUS_SUCCESS + (qdf_mutex_acquire(&psSme->lkSmeGlobalLock))) { + status = QDF_STATUS_SUCCESS; + } + } + + return status; +} + +QDF_STATUS sme_release_global_lock(tSmeStruct *psSme) +{ + QDF_STATUS status = QDF_STATUS_E_INVAL; + + if (psSme) { + if (QDF_IS_STATUS_SUCCESS + (qdf_mutex_release(&psSme->lkSmeGlobalLock))) { + status = QDF_STATUS_SUCCESS; + } + } + + return status; +} + +/** + * sme_process_set_hw_mode_resp() - Process set HW mode response + * @mac: Global MAC pointer + * @msg: HW mode response + * + * Processes the HW mode response and invokes the HDD callback + * to process further + */ +static QDF_STATUS sme_process_set_hw_mode_resp(tpAniSirGlobal mac, uint8_t *msg) +{ + tListElem *entry = NULL; + tSmeCmd *command = NULL; + bool found; + hw_mode_cb callback = NULL; + struct sir_set_hw_mode_resp *param; + enum sir_conn_update_reason reason; + tSmeCmd *saved_cmd; + + sms_log(mac, LOG1, FL("%s"), __func__); + param = (struct sir_set_hw_mode_resp *)msg; + if (!param) { + sms_log(mac, LOGE, FL("HW mode resp param is NULL")); + /* Not returning. Need to check if active command list + * needs to be freed + */ + } + + entry = csr_ll_peek_head(&mac->sme.smeCmdActiveList, + LL_ACCESS_LOCK); + if (!entry) { + sms_log(mac, LOGE, FL("No cmd found in active list")); + return QDF_STATUS_E_FAILURE; + } + + command = GET_BASE_ADDR(entry, tSmeCmd, Link); + if (!command) { + sms_log(mac, LOGE, FL("Base address is NULL")); + return QDF_STATUS_E_FAILURE; + } + + if (e_sme_command_set_hw_mode != command->command) { + sms_log(mac, LOGE, FL("Command mismatch!")); + return QDF_STATUS_E_FAILURE; + } + + callback = command->u.set_hw_mode_cmd.set_hw_mode_cb; + reason = command->u.set_hw_mode_cmd.reason; + + sms_log(mac, LOG1, FL("reason:%d session:%d"), + command->u.set_hw_mode_cmd.reason, + command->u.set_hw_mode_cmd.session_id); + + if (!callback) { + sms_log(mac, LOGE, FL("Callback does not exist")); + goto end; + } + + if (!param) { + sms_log(mac, LOGE, + FL("Callback failed since HW mode params is NULL")); + goto end; + } + + /* Irrespective of the reason for which the hw mode change request + * was issued, the policy manager connection table needs to be updated + * with the new vdev-mac id mapping, tx/rx spatial streams etc., if the + * set hw mode was successful. + */ + callback(param->status, + param->cfgd_hw_mode_index, + param->num_vdev_mac_entries, + param->vdev_mac_map); + + if (reason == SIR_UPDATE_REASON_HIDDEN_STA) { + /* In the case of hidden SSID, connection update + * (set hw mode) is done after the scan with reason + * code eCsrScanForSsid completes. The connect/failure + * needs to be handled after the response of set hw + * mode + */ + saved_cmd = (tSmeCmd *)mac->sme.saved_scan_cmd; + if (!saved_cmd) { + sms_log(mac, LOGP, + FL("saved cmd is NULL, Check this")); + goto end; + } + if (param->status == SET_HW_MODE_STATUS_OK) { + sms_log(mac, LOG1, + FL("search for ssid success")); + csr_scan_handle_search_for_ssid(mac, + saved_cmd); + } else { + sms_log(mac, LOG1, + FL("search for ssid failure")); + csr_scan_handle_search_for_ssid_failure(mac, + saved_cmd); + } + if (saved_cmd->u.roamCmd.pRoamBssEntry) + qdf_mem_free( + saved_cmd->u.roamCmd.pRoamBssEntry); + if (saved_cmd->u.scanCmd.u.scanRequest.SSIDs.SSIDList) + qdf_mem_free(saved_cmd->u.scanCmd.u. + scanRequest.SSIDs.SSIDList); + if (saved_cmd->u.scanCmd.pToRoamProfile) { + csr_release_profile(mac, saved_cmd-> + u.scanCmd.pToRoamProfile); + qdf_mem_free(saved_cmd->u.scanCmd.pToRoamProfile); + saved_cmd->u.scanCmd.pToRoamProfile = NULL; + } + if (saved_cmd) { + qdf_mem_free(saved_cmd); + saved_cmd = NULL; + mac->sme.saved_scan_cmd = NULL; + } + } + +end: + found = csr_ll_remove_entry(&mac->sme.smeCmdActiveList, entry, + LL_ACCESS_LOCK); + if (found) { + /* Now put this command back on the avilable command list */ + sme_release_command(mac, command); + } + sme_process_pending_queue(mac); + return QDF_STATUS_SUCCESS; +} + +/** + * sme_process_hw_mode_trans_ind() - Process HW mode transition indication + * @mac: Global MAC pointer + * @msg: HW mode transition response + * + * Processes the HW mode transition indication and invoke the HDD callback + * to process further + */ +static QDF_STATUS sme_process_hw_mode_trans_ind(tpAniSirGlobal mac, + uint8_t *msg) +{ + hw_mode_transition_cb callback = NULL; + struct sir_hw_mode_trans_ind *param; + + param = (struct sir_hw_mode_trans_ind *)msg; + if (!param) { + sms_log(mac, LOGE, FL("HW mode trans ind param is NULL")); + return QDF_STATUS_E_FAILURE; + } + + callback = mac->sme.sme_hw_mode_trans_cb; + if (callback) { + sms_log(mac, LOGE, FL("Calling registered callback...")); + callback(param->old_hw_mode_index, + param->new_hw_mode_index, + param->num_vdev_mac_entries, + param->vdev_mac_map); + } + + return QDF_STATUS_SUCCESS; +} + +/** + * free_sme_cmds() - This function frees memory allocated for SME commands + * @mac_ctx: Pointer to Global MAC structure + * + * This function frees memory allocated for SME commands + * + * @Return: void + */ +static void free_sme_cmds(tpAniSirGlobal mac_ctx) +{ + uint32_t idx; + if (NULL == mac_ctx->sme.pSmeCmdBufAddr) + return; + + for (idx = 0; idx < mac_ctx->sme.totalSmeCmd; idx++) + qdf_mem_free(mac_ctx->sme.pSmeCmdBufAddr[idx]); + + qdf_mem_free(mac_ctx->sme.pSmeCmdBufAddr); + mac_ctx->sme.pSmeCmdBufAddr = NULL; +} + +static QDF_STATUS init_sme_cmd_list(tpAniSirGlobal pMac) +{ + QDF_STATUS status; + tSmeCmd *pCmd; + uint32_t cmd_idx; + QDF_STATUS qdf_status; + qdf_mc_timer_t *cmdTimeoutTimer = NULL; + uint32_t sme_cmd_ptr_ary_sz; + + pMac->sme.totalSmeCmd = SME_TOTAL_COMMAND; + + status = csr_ll_open(pMac->hHdd, &pMac->sme.smeCmdActiveList); + if (!QDF_IS_STATUS_SUCCESS(status)) + goto end; + + status = csr_ll_open(pMac->hHdd, &pMac->sme.smeCmdPendingList); + if (!QDF_IS_STATUS_SUCCESS(status)) + goto end; + + status = csr_ll_open(pMac->hHdd, &pMac->sme.smeScanCmdActiveList); + if (!QDF_IS_STATUS_SUCCESS(status)) + goto end; + + status = csr_ll_open(pMac->hHdd, &pMac->sme.smeScanCmdPendingList); + if (!QDF_IS_STATUS_SUCCESS(status)) + goto end; + + status = csr_ll_open(pMac->hHdd, &pMac->sme.smeCmdFreeList); + if (!QDF_IS_STATUS_SUCCESS(status)) + goto end; + + /* following pointer contains array of pointers for tSmeCmd* */ + sme_cmd_ptr_ary_sz = sizeof(void *) * pMac->sme.totalSmeCmd; + pMac->sme.pSmeCmdBufAddr = qdf_mem_malloc(sme_cmd_ptr_ary_sz); + if (NULL == pMac->sme.pSmeCmdBufAddr) { + status = QDF_STATUS_E_NOMEM; + goto end; + } + + status = QDF_STATUS_SUCCESS; + for (cmd_idx = 0; cmd_idx < pMac->sme.totalSmeCmd; cmd_idx++) { + /* + * Since total size of all commands together can be huge chunk + * of memory, allocate SME cmd individually. These SME CMDs are + * moved between pending and active queues. And these freeing of + * these queues just manipulates the list but does not actually + * frees SME CMD pointers. Hence store each SME CMD address in + * the array, sme.pSmeCmdBufAddr. This will later facilitate + * freeing up of all SME CMDs with just a for loop. + */ + pMac->sme.pSmeCmdBufAddr[cmd_idx] = + qdf_mem_malloc(sizeof(tSmeCmd)); + if (NULL == pMac->sme.pSmeCmdBufAddr[cmd_idx]) { + status = QDF_STATUS_E_NOMEM; + free_sme_cmds(pMac); + goto end; + } + pCmd = (tSmeCmd *)pMac->sme.pSmeCmdBufAddr[cmd_idx]; + csr_ll_insert_tail(&pMac->sme.smeCmdFreeList, + &pCmd->Link, LL_ACCESS_LOCK); + } + + /* This timer is only to debug the active list command timeout */ + + cmdTimeoutTimer = + (qdf_mc_timer_t *) qdf_mem_malloc(sizeof(qdf_mc_timer_t)); + if (cmdTimeoutTimer) { + pMac->sme.smeCmdActiveList.cmdTimeoutTimer = cmdTimeoutTimer; + qdf_status = + qdf_mc_timer_init(pMac->sme.smeCmdActiveList. + cmdTimeoutTimer, QDF_TIMER_TYPE_SW, + active_list_cmd_timeout_handle, (void *)pMac); + + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "Init Timer fail for active list command process time out"); + qdf_mem_free(pMac->sme.smeCmdActiveList. + cmdTimeoutTimer); + pMac->sme.smeCmdActiveList.cmdTimeoutTimer = NULL; + } else { + pMac->sme.smeCmdActiveList.cmdTimeoutDuration = + SME_ACTIVE_LIST_CMD_TIMEOUT_VALUE; + } + } + +end: + if (!QDF_IS_STATUS_SUCCESS(status)) + sms_log(pMac, LOGE, "failed to initialize sme command list:%d\n", + status); + + return status; +} + +void sme_release_command(tpAniSirGlobal pMac, tSmeCmd *pCmd) +{ + pCmd->command = eSmeNoCommand; + csr_ll_insert_tail(&pMac->sme.smeCmdFreeList, &pCmd->Link, LL_ACCESS_LOCK); +} + +static void sme_release_cmd_list(tpAniSirGlobal pMac, tDblLinkList *pList) +{ + tListElem *pEntry; + tSmeCmd *pCommand; + + while ((pEntry = csr_ll_remove_head(pList, LL_ACCESS_LOCK)) != NULL) { + /* TODO: base on command type to call release functions */ + /* reinitialize different command types so they can be reused */ + pCommand = GET_BASE_ADDR(pEntry, tSmeCmd, Link); + sme_abort_command(pMac, pCommand, true); + } +} + +static void purge_sme_cmd_list(tpAniSirGlobal pMac) +{ + /* release any out standing commands back to free command list */ + sme_release_cmd_list(pMac, &pMac->sme.smeCmdPendingList); + sme_release_cmd_list(pMac, &pMac->sme.smeCmdActiveList); + sme_release_cmd_list(pMac, &pMac->sme.smeScanCmdPendingList); + sme_release_cmd_list(pMac, &pMac->sme.smeScanCmdActiveList); +} + +void purge_sme_session_cmd_list(tpAniSirGlobal pMac, uint32_t sessionId, + tDblLinkList *pList) +{ + /* release any out standing commands back to free command list */ + tListElem *pEntry, *pNext; + tSmeCmd *pCommand; + tDblLinkList localList; + + qdf_mem_zero(&localList, sizeof(tDblLinkList)); + if (!QDF_IS_STATUS_SUCCESS(csr_ll_open(pMac->hHdd, &localList))) { + sms_log(pMac, LOGE, FL(" failed to open list")); + return; + } + + csr_ll_lock(pList); + pEntry = csr_ll_peek_head(pList, LL_ACCESS_NOLOCK); + while (pEntry != NULL) { + pNext = csr_ll_next(pList, pEntry, LL_ACCESS_NOLOCK); + pCommand = GET_BASE_ADDR(pEntry, tSmeCmd, Link); + if (pCommand->sessionId == sessionId) { + if (csr_ll_remove_entry(pList, pEntry, LL_ACCESS_NOLOCK)) { + csr_ll_insert_tail(&localList, pEntry, + LL_ACCESS_NOLOCK); + } + } + pEntry = pNext; + } + csr_ll_unlock(pList); + + while ((pEntry = csr_ll_remove_head(&localList, LL_ACCESS_NOLOCK))) { + pCommand = GET_BASE_ADDR(pEntry, tSmeCmd, Link); + sme_abort_command(pMac, pCommand, true); + } + csr_ll_close(&localList); +} + +static QDF_STATUS free_sme_cmd_list(tpAniSirGlobal pMac) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + + purge_sme_cmd_list(pMac); + csr_ll_close(&pMac->sme.smeCmdPendingList); + csr_ll_close(&pMac->sme.smeCmdActiveList); + csr_ll_close(&pMac->sme.smeScanCmdPendingList); + csr_ll_close(&pMac->sme.smeScanCmdActiveList); + csr_ll_close(&pMac->sme.smeCmdFreeList); + + /*destroy active list command time out timer */ + qdf_mc_timer_destroy(pMac->sme.smeCmdActiveList.cmdTimeoutTimer); + qdf_mem_free(pMac->sme.smeCmdActiveList.cmdTimeoutTimer); + pMac->sme.smeCmdActiveList.cmdTimeoutTimer = NULL; + + status = qdf_mutex_acquire(&pMac->sme.lkSmeGlobalLock); + if (status != QDF_STATUS_SUCCESS) { + sms_log(pMac, LOGE, + FL("Failed to acquire the lock status = %d"), status); + goto done; + } + + free_sme_cmds(pMac); + + status = qdf_mutex_release(&pMac->sme.lkSmeGlobalLock); + if (status != QDF_STATUS_SUCCESS) { + sms_log(pMac, LOGE, + FL("Failed to release the lock status = %d"), status); + } +done: + return status; +} + +static void dump_csr_command_info(tpAniSirGlobal mac_ctx, + tSmeCmd *cmd) +{ + switch (cmd->command) { + case eSmeCommandScan: + sms_log(mac_ctx, LOGW, " scan command reason is %d session %d", + cmd->u.scanCmd.reason, + cmd->sessionId); + break; + + case eSmeCommandRoam: + sms_log(mac_ctx, LOGW, " roam command reason is %d session %d", + cmd->u.roamCmd.roamReason, + cmd->sessionId); + break; + + case eSmeCommandWmStatusChange: + sms_log(mac_ctx, LOGW, + " WMStatusChange command type is %d session %d", + cmd->u.wmStatusChangeCmd.Type, + cmd->sessionId); + break; + + case eSmeCommandSetKey: + sms_log(mac_ctx, LOGW, + " setKey command auth(%d) enc(%d) session %d", + cmd->u.setKeyCmd.authType, cmd->u.setKeyCmd.encType, + cmd->sessionId); + break; + + default: + sms_log(mac_ctx, LOGW, + " default: Unhandled command %d session %d", + cmd->command, + cmd->sessionId); + break; + } +} + +tSmeCmd *sme_get_command_buffer(tpAniSirGlobal pMac) +{ + tSmeCmd *pRetCmd = NULL, *pTempCmd = NULL; + tListElem *pEntry; + static int sme_command_queue_full; + + pEntry = csr_ll_remove_head(&pMac->sme.smeCmdFreeList, LL_ACCESS_LOCK); + + /* If we can get another MS Msg buffer, then we are ok. Just link */ + /* the entry onto the linked list. (We are using the linked list */ + /* to keep track of tfhe message buffers). */ + if (pEntry) { + pRetCmd = GET_BASE_ADDR(pEntry, tSmeCmd, Link); + /* reset when free list is available */ + sme_command_queue_full = 0; + } else { + int idx = 1; + + /* Cannot change pRetCmd here since it needs to return later. */ + pEntry = + csr_ll_peek_head(&pMac->sme.smeCmdActiveList, LL_ACCESS_LOCK); + if (pEntry) { + pTempCmd = GET_BASE_ADDR(pEntry, tSmeCmd, Link); + } + sms_log(pMac, LOGE, + "Out of command buffer.... command (0x%X) stuck", + (pTempCmd) ? pTempCmd->command : eSmeNoCommand); + if (pTempCmd) { + if (eSmeCsrCommandMask & pTempCmd->command) { + /* CSR command is stuck. See what the reason code is for that command */ + dump_csr_command_info(pMac, pTempCmd); + } + } /* if(pTempCmd) */ + + /* dump what is in the pending queue */ + csr_ll_lock(&pMac->sme.smeCmdPendingList); + pEntry = + csr_ll_peek_head(&pMac->sme.smeCmdPendingList, + LL_ACCESS_NOLOCK); + while (pEntry && !sme_command_queue_full) { + pTempCmd = GET_BASE_ADDR(pEntry, tSmeCmd, Link); + /* Print only 1st five commands from pending queue. */ + if (idx <= 5) + sms_log(pMac, LOGE, + "Out of command buffer.... SME pending command #%d (0x%X)", + idx, pTempCmd->command); + idx++; + if (eSmeCsrCommandMask & pTempCmd->command) { + /* CSR command is stuck. See what the reason code is for that command */ + dump_csr_command_info(pMac, pTempCmd); + } + pEntry = + csr_ll_next(&pMac->sme.smeCmdPendingList, pEntry, + LL_ACCESS_NOLOCK); + } + csr_ll_unlock(&pMac->sme.smeCmdPendingList); + + idx = 1; + /* There may be some more command in CSR's own pending queue */ + csr_ll_lock(&pMac->roam.roamCmdPendingList); + pEntry = + csr_ll_peek_head(&pMac->roam.roamCmdPendingList, + LL_ACCESS_NOLOCK); + while (pEntry && !sme_command_queue_full) { + pTempCmd = GET_BASE_ADDR(pEntry, tSmeCmd, Link); + /* Print only 1st five commands from CSR pending queue */ + if (idx <= 5) + sms_log(pMac, LOGE, + "Out of command buffer.... " + "CSR roamCmdPendingList command #%d (0x%X)", + idx, pTempCmd->command); + idx++; + dump_csr_command_info(pMac, pTempCmd); + pEntry = + csr_ll_next(&pMac->roam.roamCmdPendingList, pEntry, + LL_ACCESS_NOLOCK); + } + + /* Increment static variable so that it prints + * pending command only once + */ + sme_command_queue_full++; + csr_ll_unlock(&pMac->roam.roamCmdPendingList); + + if (pMac->roam.configParam.enable_fatal_event) + cds_flush_logs(WLAN_LOG_TYPE_FATAL, + WLAN_LOG_INDICATOR_HOST_DRIVER, + WLAN_LOG_REASON_SME_OUT_OF_CMD_BUF, + false, + pMac->sme.enableSelfRecovery ? true : false); + else if (pMac->sme.enableSelfRecovery) + cds_trigger_recovery(false); + else + QDF_BUG(0); + } + + /* memset to zero */ + if (pRetCmd) { + qdf_mem_set((uint8_t *)&pRetCmd->command, + sizeof(pRetCmd->command), 0); + qdf_mem_set((uint8_t *)&pRetCmd->sessionId, + sizeof(pRetCmd->sessionId), 0); + qdf_mem_set((uint8_t *)&pRetCmd->u, sizeof(pRetCmd->u), 0); + } + + return pRetCmd; +} + +void sme_push_command(tpAniSirGlobal pMac, tSmeCmd *pCmd, bool fHighPriority) +{ + if (!SME_IS_START(pMac)) { + sms_log(pMac, LOGE, FL("Sme in stop state")); + QDF_ASSERT(0); + return; + } + + if (fHighPriority) { + csr_ll_insert_head(&pMac->sme.smeCmdPendingList, &pCmd->Link, + LL_ACCESS_LOCK); + } else { + csr_ll_insert_tail(&pMac->sme.smeCmdPendingList, &pCmd->Link, + LL_ACCESS_LOCK); + } + + /* process the command queue... */ + sme_process_pending_queue(pMac); + + return; +} + +/* For commands that need to do extra cleanup. */ +static void sme_abort_command(tpAniSirGlobal pMac, tSmeCmd *pCommand, + bool fStopping) +{ + if (eSmePmcCommandMask & pCommand->command) { + sms_log(pMac, LOG1, + "No need to process PMC commands"); + return; + } + if (eSmeCsrCommandMask & pCommand->command) { + csr_abort_command(pMac, pCommand, fStopping); + return; + } + switch (pCommand->command) { + case eSmeCommandRemainOnChannel: + if (NULL != pCommand->u.remainChlCmd.callback) { + remainOnChanCallback callback = + pCommand->u.remainChlCmd.callback; + /* process the msg */ + if (callback) { + callback(pMac, pCommand->u.remainChlCmd. + callbackCtx, eCSR_SCAN_ABORT, + pCommand->u.remainChlCmd.scan_id); + } + } + sme_release_command(pMac, pCommand); + break; + default: + sme_release_command(pMac, pCommand); + break; + } + +} + +static +tListElem *csr_get_cmd_to_process(tpAniSirGlobal pMac, tDblLinkList *pList, + uint8_t sessionId, bool fInterlocked) +{ + tListElem *pCurEntry = NULL; + tSmeCmd *pCommand; + + /* Go through the list and return the command whose session id is not + * matching with the current ongoing scan cmd sessionId */ + pCurEntry = csr_ll_peek_head(pList, LL_ACCESS_LOCK); + while (pCurEntry) { + pCommand = GET_BASE_ADDR(pCurEntry, tSmeCmd, Link); + if (pCommand->sessionId != sessionId) { + sms_log(pMac, LOG1, + "selected the command with different sessionId"); + return pCurEntry; + } + + pCurEntry = csr_ll_next(pList, pCurEntry, fInterlocked); + } + + sms_log(pMac, LOG1, "No command pending with different sessionId"); + return NULL; +} + +static bool sme_process_scan_queue(tpAniSirGlobal pMac) +{ + tListElem *pEntry; + tSmeCmd *pCommand; + tListElem *pSmeEntry = NULL; + tSmeCmd *pSmeCommand = NULL; + bool status = true; + + if ((!csr_ll_is_list_empty(&pMac->sme.smeCmdActiveList, + LL_ACCESS_LOCK))) { + pSmeEntry = csr_ll_peek_head(&pMac->sme.smeCmdActiveList, + LL_ACCESS_LOCK); + if (pSmeEntry) + pSmeCommand = GET_BASE_ADDR(pSmeEntry, tSmeCmd, Link); + } + csr_ll_lock(&pMac->sme.smeScanCmdActiveList); + if (csr_ll_is_list_empty(&pMac->sme.smeScanCmdPendingList, + LL_ACCESS_LOCK)) + goto end; + pEntry = csr_ll_peek_head(&pMac->sme.smeScanCmdPendingList, + LL_ACCESS_LOCK); + if (!pEntry) + goto end; + + sms_log(pMac, LOG1, + FL("scan_count in active scanlist %d "), + pMac->sme.smeScanCmdActiveList.Count); + + pCommand = GET_BASE_ADDR(pEntry, tSmeCmd, Link); + if (pSmeCommand != NULL) { + /* + * if scan is running on one interface and SME receives + * the next command on the same interface then + * dont the allow the command to be queued to + * smeCmdPendingList. If next scan is allowed on + * the same interface the CSR state machine will + * get screwed up. + */ + if (pSmeCommand->sessionId == pCommand->sessionId) { + status = false; + goto end; + } + } + /* + * We cannot execute any command in wait-for-key state until setKey is + * through. + */ + if (CSR_IS_WAIT_FOR_KEY(pMac, pCommand->sessionId)) { + if (!CSR_IS_SET_KEY_COMMAND(pCommand)) { + sms_log(pMac, LOGE, + FL("Can't process cmd(%d), waiting for key"), + pCommand->command); + status = false; + goto end; + } + } + if (csr_ll_remove_entry(&pMac->sme.smeScanCmdPendingList, pEntry, + LL_ACCESS_LOCK)) { + csr_ll_insert_head(&pMac->sme.smeScanCmdActiveList, + &pCommand->Link, LL_ACCESS_NOLOCK); + switch (pCommand->command) { + case eSmeCommandScan: + sms_log(pMac, LOG1, FL("Processing scan offload cmd.")); + qdf_mc_timer_start(&pCommand->u.scanCmd.csr_scan_timer, + CSR_ACTIVE_SCAN_LIST_CMD_TIMEOUT); + csr_process_scan_command(pMac, pCommand); + break; + case eSmeCommandRemainOnChannel: + sms_log(pMac, LOG1, + FL("Processing remain on channel offload cmd")); + p2p_process_remain_on_channel_cmd(pMac, pCommand); + break; + default: + sms_log(pMac, LOGE, + FL("Wrong cmd enqueued to ScanCmdPendingList")); + pEntry = csr_ll_remove_head( + &pMac->sme.smeScanCmdActiveList, + LL_ACCESS_NOLOCK); + pCommand = GET_BASE_ADDR(pEntry, tSmeCmd, Link); + sme_release_command(pMac, pCommand); + break; + } + } +end: + csr_ll_unlock(&pMac->sme.smeScanCmdActiveList); + return status; +} + +/** + * sme_process_command() - processes SME commnd + * @mac_ctx: mac global context + * + * This function is called by sme_process_pending_queue() in a while loop + * + * Return: true indicates that caller function can proceed to next cmd + * false otherwise. + */ +static bool sme_process_command(tpAniSirGlobal pMac) +{ + bool fContinue = false; + QDF_STATUS status = QDF_STATUS_SUCCESS; + tListElem *pEntry; + tSmeCmd *pCommand; + tListElem *pSmeEntry; + tSmeCmd *pSmeCommand; + + /* + * if the ActiveList is empty, then nothing is active so we can process + * a pending command... + * alwasy lock active list before locking pending list + */ + csr_ll_lock(&pMac->sme.smeCmdActiveList); + if (!csr_ll_is_list_empty(&pMac->sme.smeCmdActiveList, + LL_ACCESS_NOLOCK)) { + pEntry = csr_ll_peek_head(&pMac->sme.smeCmdActiveList, false); + pCommand = GET_BASE_ADDR(pEntry, tSmeCmd, Link); + dump_csr_command_info(pMac, pCommand); + csr_ll_unlock(&pMac->sme.smeCmdActiveList); + goto process_scan_q; + } + + if (csr_ll_is_list_empty(&pMac->sme.smeCmdPendingList, + LL_ACCESS_LOCK)) { + /* No command waiting */ + csr_ll_unlock(&pMac->sme.smeCmdActiveList); + goto process_scan_q; + } + + /* + * If scan command is pending in the smeScanCmdActive list then pick the + * command from smeCmdPendingList which is not matching with the scan + * command session id. At any point of time only one command will be + * allowed on a single session. + */ + if (!csr_ll_is_list_empty( + &pMac->sme.smeScanCmdActiveList, LL_ACCESS_LOCK)) { + pSmeEntry = csr_ll_peek_head(&pMac->sme.smeScanCmdActiveList, + LL_ACCESS_LOCK); + if (pSmeEntry) { + pSmeCommand = GET_BASE_ADDR(pSmeEntry, tSmeCmd, Link); + pEntry = csr_get_cmd_to_process(pMac, + &pMac->sme.smeCmdPendingList, + pSmeCommand->sessionId, + LL_ACCESS_LOCK); + goto sme_process_cmd; + } + } + + /* Peek the command */ + pEntry = csr_ll_peek_head(&pMac->sme.smeCmdPendingList, LL_ACCESS_LOCK); +sme_process_cmd: + if (!pEntry) { + csr_ll_unlock(&pMac->sme.smeCmdActiveList); + goto process_scan_q; + } + pCommand = GET_BASE_ADDR(pEntry, tSmeCmd, Link); + /* + * Allow only disconnect command in wait-for-key state until setKey is + * through. + */ + if (CSR_IS_WAIT_FOR_KEY(pMac, pCommand->sessionId) + && !CSR_IS_DISCONNECT_COMMAND(pCommand) + && !CSR_IS_SET_KEY_COMMAND(pCommand)) { + if (CSR_IS_CLOSE_SESSION_COMMAND(pCommand)) { + tSmeCmd *sme_cmd = NULL; + + sms_log(pMac, LOGE, + FL("SessionId %d: close session command issued while waiting for key, issue disconnect first"), + pCommand->sessionId); + status = csr_prepare_disconnect_command(pMac, + pCommand->sessionId, &sme_cmd); + if (status == QDF_STATUS_SUCCESS && sme_cmd) { + csr_ll_lock(&pMac->sme.smeCmdPendingList); + csr_ll_insert_head(&pMac->sme.smeCmdPendingList, + &sme_cmd->Link, LL_ACCESS_NOLOCK); + pEntry = csr_ll_peek_head( + &pMac->sme.smeCmdPendingList, + LL_ACCESS_NOLOCK); + csr_ll_unlock(&pMac->sme.smeCmdPendingList); + goto sme_process_cmd; + } + } + + csr_ll_unlock(&pMac->sme.smeCmdActiveList); + sms_log(pMac, LOGE, + FL("SessionId %d: Can't process cmd(%d), waiting for key"), + pCommand->sessionId, pCommand->command); + fContinue = false; + goto process_scan_q; + } + + if (!csr_ll_remove_entry(&pMac->sme.smeCmdPendingList, pEntry, + LL_ACCESS_LOCK)) { + /* This is odd. Some one else pull off the command. */ + csr_ll_unlock(&pMac->sme.smeCmdActiveList); + goto process_scan_q; + } + /* we can reuse the pCommand. Insert the command onto the ActiveList */ + csr_ll_insert_head(&pMac->sme.smeCmdActiveList, &pCommand->Link, + LL_ACCESS_NOLOCK); + /* .... and process the command. */ + MTRACE(qdf_trace(QDF_MODULE_ID_SME, TRACE_CODE_SME_COMMAND, + pCommand->sessionId, pCommand->command)); + + dump_csr_command_info(pMac, pCommand); + switch (pCommand->command) { + case eSmeCommandScan: + csr_ll_unlock(&pMac->sme.smeCmdActiveList); + status = csr_process_scan_command(pMac, pCommand); + break; + case eSmeCommandRoam: + csr_ll_unlock(&pMac->sme.smeCmdActiveList); + status = csr_roam_process_command(pMac, pCommand); + if (!QDF_IS_STATUS_SUCCESS(status) + && csr_ll_remove_entry(&pMac->sme.smeCmdActiveList, + &pCommand->Link, LL_ACCESS_LOCK)) + csr_release_command_roam(pMac, pCommand); + break; + case eSmeCommandWmStatusChange: + csr_ll_unlock(&pMac->sme.smeCmdActiveList); + csr_roam_process_wm_status_change_command(pMac, pCommand); + break; + case eSmeCommandSetKey: + csr_ll_unlock(&pMac->sme.smeCmdActiveList); + status = csr_roam_process_set_key_command(pMac, pCommand); + if (!QDF_IS_STATUS_SUCCESS(status) + && csr_ll_remove_entry(&pMac->sme.smeCmdActiveList, + &pCommand->Link, LL_ACCESS_LOCK)) { + csr_release_command_set_key(pMac, pCommand); + } + break; + case eSmeCommandAddStaSession: + csr_ll_unlock(&pMac->sme.smeCmdActiveList); + csr_process_add_sta_session_command(pMac, pCommand); + break; + case eSmeCommandNdpInitiatorRequest: + csr_ll_unlock(&pMac->sme.smeCmdActiveList); + if (csr_process_ndp_initiator_request(pMac, pCommand) != + QDF_STATUS_SUCCESS) + if (csr_ll_remove_entry( + &pMac->sme.smeCmdActiveList, + &pCommand->Link, LL_ACCESS_LOCK)) + csr_release_command(pMac, pCommand); + break; + case eSmeCommandNdpResponderRequest: + csr_ll_unlock(&pMac->sme.smeCmdActiveList); + status = csr_process_ndp_responder_request(pMac, pCommand); + if (status != QDF_STATUS_SUCCESS) { + if (csr_ll_remove_entry(&pMac->sme.smeCmdActiveList, + &pCommand->Link, LL_ACCESS_LOCK)) + csr_release_command(pMac, pCommand); + } + break; + case eSmeCommandNdpDataEndInitiatorRequest: + csr_ll_unlock(&pMac->sme.smeCmdActiveList); + status = csr_process_ndp_data_end_request(pMac, pCommand); + if (status != QDF_STATUS_SUCCESS) { + if (csr_ll_remove_entry(&pMac->sme.smeCmdActiveList, + &pCommand->Link, LL_ACCESS_LOCK)) + csr_release_command(pMac, pCommand); + } + break; + case eSmeCommandDelStaSession: + csr_ll_unlock(&pMac->sme.smeCmdActiveList); + csr_process_del_sta_session_command(pMac, pCommand); + break; + case eSmeCommandRemainOnChannel: + csr_ll_unlock(&pMac->sme.smeCmdActiveList); + p2p_process_remain_on_channel_cmd(pMac, pCommand); + break; + /* + * Treat standby differently here because caller may not be able + * to handle the failure so we do our best here + */ + case eSmeCommandEnterStandby: + break; + case eSmeCommandAddTs: + case eSmeCommandDelTs: + csr_ll_unlock(&pMac->sme.smeCmdActiveList); +#ifndef WLAN_MDM_CODE_REDUCTION_OPT + fContinue = qos_process_command(pMac, pCommand); + if (fContinue && csr_ll_remove_entry( + &pMac->sme.smeCmdActiveList, + &pCommand->Link, LL_ACCESS_NOLOCK)) { + /* The command failed, remove it */ + qos_release_command(pMac, pCommand); + } +#endif + break; +#ifdef FEATURE_WLAN_TDLS + case eSmeCommandTdlsSendMgmt: + case eSmeCommandTdlsAddPeer: + case eSmeCommandTdlsDelPeer: + case eSmeCommandTdlsLinkEstablish: + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO, + FL("sending TDLS Command 0x%x to PE"), + pCommand->command); + csr_ll_unlock(&pMac->sme.smeCmdActiveList); + status = csr_tdls_process_cmd(pMac, pCommand); + if (!QDF_IS_STATUS_SUCCESS(status)) { + if (csr_ll_remove_entry(&pMac->sme.smeCmdActiveList, + &pCommand->Link, + LL_ACCESS_LOCK)) { + qdf_mem_zero(&pCommand->u.tdlsCmd, + sizeof(tTdlsCmd)); + csr_release_command(pMac, pCommand); + } + } + break; +#endif + case e_sme_command_set_hw_mode: + csr_ll_unlock(&pMac->sme.smeCmdActiveList); + csr_process_set_hw_mode(pMac, pCommand); + break; + case e_sme_command_nss_update: + csr_ll_unlock(&pMac->sme.smeCmdActiveList); + csr_process_nss_update_req(pMac, pCommand); + break; + case e_sme_command_set_dual_mac_config: + csr_ll_unlock(&pMac->sme.smeCmdActiveList); + csr_process_set_dual_mac_config(pMac, pCommand); + break; + case e_sme_command_set_antenna_mode: + csr_ll_unlock(&pMac->sme.smeCmdActiveList); + csr_process_set_antenna_mode(pMac, pCommand); + break; + default: + /* something is wrong */ + /* remove it from the active list */ + sms_log(pMac, LOGE, FL("unknown command %d"), + pCommand->command); + pEntry = csr_ll_remove_head(&pMac->sme.smeCmdActiveList, + LL_ACCESS_NOLOCK); + csr_ll_unlock(&pMac->sme.smeCmdActiveList); + pCommand = GET_BASE_ADDR(pEntry, tSmeCmd, Link); + sme_release_command(pMac, pCommand); + status = QDF_STATUS_E_FAILURE; + break; + } + if (!QDF_IS_STATUS_SUCCESS(status)) + fContinue = true; +process_scan_q: + if (!(sme_process_scan_queue(pMac))) + fContinue = false; + return fContinue; +} + +void sme_process_pending_queue(tpAniSirGlobal pMac) +{ + while (sme_process_command(pMac)) + ; +} + +bool sme_command_pending(tpAniSirGlobal pMac) +{ + return !csr_ll_is_list_empty(&pMac->sme.smeCmdActiveList, LL_ACCESS_NOLOCK) + || !csr_ll_is_list_empty(&pMac->sme.smeCmdPendingList, + LL_ACCESS_NOLOCK); +} + +/** + * sme_get_sessionid_from_activelist() - gets session id + * @mac: mac context + * + * This function is used to get session id from sme command + * active list + * + * Return: returns session id + */ +static uint32_t sme_get_sessionid_from_activelist(tpAniSirGlobal mac) +{ + tListElem *entry; + tSmeCmd *command; + uint32_t session_id = CSR_SESSION_ID_INVALID; + + entry = csr_ll_peek_head(&mac->sme.smeCmdActiveList, LL_ACCESS_LOCK); + if (entry) { + command = GET_BASE_ADDR(entry, tSmeCmd, Link); + session_id = command->sessionId; + } + + return session_id; +} + +/** + * sme_state_info_dump() - prints state information of sme layer + * @buf: buffer pointer + * @size: size of buffer to be filled + * + * This function is used to dump state information of sme layer + * + * Return: None + */ +static void sme_state_info_dump(char **buf_ptr, uint16_t *size) +{ + uint32_t session_id, active_session_id; + tHalHandle hal; + tpAniSirGlobal mac; + uint16_t len = 0; + char *buf = *buf_ptr; + eCsrConnectState connect_state; + + hal = cds_get_context(QDF_MODULE_ID_SME); + if (hal == NULL) { + QDF_ASSERT(0); + return; + } + + mac = PMAC_STRUCT(hal); + sms_log(mac, LOG1, FL("size of buffer: %d"), *size); + + active_session_id = sme_get_sessionid_from_activelist(mac); + if (active_session_id != CSR_SESSION_ID_INVALID) { + len += qdf_scnprintf(buf + len, *size - len, + "\n active command sessionid %d", active_session_id); + } + + for (session_id = 0; session_id < CSR_ROAM_SESSION_MAX; session_id++) { + if (CSR_IS_SESSION_VALID(mac, session_id)) { + connect_state = + mac->roam.roamSession[session_id].connectState; + if ((eCSR_ASSOC_STATE_TYPE_INFRA_ASSOCIATED == + connect_state) + || (eCSR_ASSOC_STATE_TYPE_INFRA_CONNECTED == + connect_state)) { + len += qdf_scnprintf(buf + len, *size - len, + "\n NeighborRoamState: %d", + mac->roam.neighborRoamInfo[session_id]. + neighborRoamState); + len += qdf_scnprintf(buf + len, *size - len, + "\n RoamState: %d", mac->roam. + curState[session_id]); + len += qdf_scnprintf(buf + len, *size - len, + "\n RoamSubState: %d", mac->roam. + curSubState[session_id]); + len += qdf_scnprintf(buf + len, *size - len, + "\n ConnectState: %d", + connect_state); + } + } + } + + *size -= len; + *buf_ptr += len; +} + +/** + * sme_register_debug_callback() - registration function sme layer + * to print sme state information + * + * Return: None + */ +static void sme_register_debug_callback(void) +{ + qdf_register_debug_callback(QDF_MODULE_ID_SME, &sme_state_info_dump); +} + + +/* Global APIs */ + +/** + * sme_open() - Initialze all SME modules and put them at idle state + * @hHal: The handle returned by mac_open + * + * The function initializes each module inside SME, PMC, CSR, etc. Upon + * successfully return, all modules are at idle state ready to start. + * smeOpen must be called before any other SME APIs can be involved. + * smeOpen must be called after mac_open. + * + * Return: QDF_STATUS_SUCCESS - SME is successfully initialized. + * Other status means SME is failed to be initialized + */ +QDF_STATUS sme_open(tHalHandle hHal) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + pMac->sme.state = SME_STATE_STOP; + pMac->sme.currDeviceMode = QDF_STA_MODE; + if (!QDF_IS_STATUS_SUCCESS(qdf_mutex_create( + &pMac->sme.lkSmeGlobalLock))) { + sms_log(pMac, LOGE, FL("sme_open failed init lock")); + return QDF_STATUS_E_FAILURE; + } + status = csr_open(pMac); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOGE, FL("csr_open failed, status=%d"), status); + return status; + } + + status = sme_ps_open(hHal); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOGE, + FL("sme_ps_open failed during initialization with status=%d"), + status); + return status; + } +#ifdef FEATURE_WLAN_TDLS + pMac->is_tdls_power_save_prohibited = 0; +#endif + +#ifndef WLAN_MDM_CODE_REDUCTION_OPT + status = sme_qos_open(pMac); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOGE, FL("Qos open, status=%d"), status); + return status; + } +#endif + status = init_sme_cmd_list(pMac); + if (!QDF_IS_STATUS_SUCCESS(status)) + return status; + + status = rrm_open(pMac); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOGE, FL("rrm_open failed, status=%d"), status); + return status; + } + sme_p2p_open(pMac); + sme_trace_init(pMac); + sme_register_debug_callback(); + return status; +} + +/* + * sme_init_chan_list, triggers channel setup based on country code. + */ +QDF_STATUS sme_init_chan_list(tHalHandle hal, uint8_t *alpha2, + enum country_src cc_src) +{ + tpAniSirGlobal pmac = PMAC_STRUCT(hal); + + if ((cc_src == SOURCE_USERSPACE) && + (pmac->roam.configParam.fSupplicantCountryCodeHasPriority)) { + pmac->roam.configParam.Is11dSupportEnabled = false; + } + + return csr_init_chan_list(pmac, alpha2); +} + +/*-------------------------------------------------------------------------- + + \brief sme_set11dinfo() - Set the 11d information about valid channels + and there power using information from nvRAM + This function is called only for AP. + + This is a synchronous call + + \param hHal - The handle returned by mac_open. + \Param pSmeConfigParams - a pointer to a caller allocated object of + typedef struct _smeConfigParams. + + \return QDF_STATUS_SUCCESS - SME update the config parameters successfully. + + Other status means SME is failed to update the config parameters. + \sa + --------------------------------------------------------------------------*/ + +QDF_STATUS sme_set11dinfo(tHalHandle hHal, tpSmeConfigParams pSmeConfigParams) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + MTRACE(qdf_trace(QDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_MSG_SET_11DINFO, NO_SESSION, 0)); + if (NULL == pSmeConfigParams) { + sms_log(pMac, LOGE, + "Empty config param structure for SME, nothing to update"); + return status; + } + + status = csr_set_channels(hHal, &pSmeConfigParams->csrConfig); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOGE, + "csr_change_default_config_param failed with status=%d", + status); + } + return status; +} + +/** + * sme_set_scan_disable() - Dynamically enable/disable scan + * @h_hal: Handle to HAL + * + * This command gives the user an option to dynamically + * enable or disable scans. + * + * Return: None + */ +void sme_set_scan_disable(tHalHandle h_hal, int value) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(h_hal); + mac_ctx->lim.scan_disabled = value; + sms_log(mac_ctx, LOG1, FL("value=%d"), value); +} +/*-------------------------------------------------------------------------- + + \brief sme_get_soft_ap_domain() - Get the current regulatory domain of softAp. + + This is a synchronous call + + \param hHal - The handle returned by HostapdAdapter. + \Param v_REGDOMAIN_t - The current Regulatory Domain requested for SoftAp. + + \return QDF_STATUS_SUCCESS - SME successfully completed the request. + + Other status means, failed to get the current regulatory domain. + \sa + --------------------------------------------------------------------------*/ + +QDF_STATUS sme_get_soft_ap_domain(tHalHandle hHal, v_REGDOMAIN_t *domainIdSoftAp) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + MTRACE(qdf_trace(QDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_MSG_GET_SOFTAP_DOMAIN, + NO_SESSION, 0)); + if (NULL == domainIdSoftAp) { + sms_log(pMac, LOGE, "Uninitialized domain Id"); + return status; + } + + *domainIdSoftAp = pMac->scan.domainIdCurrent; + status = QDF_STATUS_SUCCESS; + + return status; +} + +QDF_STATUS sme_set_reg_info(tHalHandle hHal, uint8_t *apCntryCode) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + int32_t ctry_val; + + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + MTRACE(qdf_trace(QDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_MSG_SET_REGINFO, NO_SESSION, 0)); + + if (NULL == apCntryCode) { + sms_log(pMac, LOGE, "Empty Country Code, nothing to update"); + return status; + } + + ctry_val = cds_get_country_from_alpha2(apCntryCode); + if (ctry_val == CTRY_DEFAULT) { + sms_log(pMac, LOGE, "invalid AP alpha2"); + return status; + } + + status = csr_set_reg_info(hHal, apCntryCode); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOGE, "csr_set_reg_info failed with status=%d", + status); + } + return status; +} + +/** + * sme_update_fine_time_measurement_capab() - Update the FTM capabitlies from + * incoming val + * @hal: Handle for Hal layer + * @val: New FTM capability value + * + * Return: None + */ +void sme_update_fine_time_measurement_capab(tHalHandle hal, uint8_t session_id, + uint32_t val) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + mac_ctx->fine_time_meas_cap = val; + + if (!val) { + mac_ctx->rrm.rrmPEContext.rrmEnabledCaps.fine_time_meas_rpt = 0; + ((tpRRMCaps)mac_ctx->rrm.rrmSmeContext. + rrmConfig.rm_capability)->fine_time_meas_rpt = 0; + } else { + mac_ctx->rrm.rrmPEContext.rrmEnabledCaps.fine_time_meas_rpt = 1; + ((tpRRMCaps)mac_ctx->rrm.rrmSmeContext. + rrmConfig.rm_capability)->fine_time_meas_rpt = 1; + } + + /* Inform this RRM IE change to FW */ + csr_roam_offload_scan(mac_ctx, session_id, + ROAM_SCAN_OFFLOAD_UPDATE_CFG, + REASON_CONNECT_IES_CHANGED); +} + +/*-------------------------------------------------------------------------- + + \brief sme_update_config() - Change configurations for all SME moduels + + The function updates some configuration for modules in SME, CSR, etc + during SMEs close open sequence. + + Modules inside SME apply the new configuration at the next transaction. + + This is a synchronous call + + \param hHal - The handle returned by mac_open. + \Param pSmeConfigParams - a pointer to a caller allocated object of + typedef struct _smeConfigParams. + + \return QDF_STATUS_SUCCESS - SME update the config parameters successfully. + + Other status means SME is failed to update the config parameters. + \sa + + --------------------------------------------------------------------------*/ +QDF_STATUS sme_update_config(tHalHandle hHal, tpSmeConfigParams pSmeConfigParams) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + MTRACE(qdf_trace(QDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_MSG_UPDATE_CONFIG, NO_SESSION, + 0)); + if (NULL == pSmeConfigParams) { + sms_log(pMac, LOGE, + "Empty config param structure for SME, nothing to update"); + return status; + } + + status = + csr_change_default_config_param(pMac, &pSmeConfigParams->csrConfig); + + if (!QDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOGE, + "csr_change_default_config_param failed with status=%d", + status); + } + status = + rrm_change_default_config_param(hHal, &pSmeConfigParams->rrmConfig); + + if (!QDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOGE, + "rrm_change_default_config_param failed with status=%d", + status); + } + /* For SOC, CFG is set before start */ + /* We don't want to apply global CFG in connect state because that may cause some side affect */ + if (csr_is_all_session_disconnected(pMac)) { + csr_set_global_cfgs(pMac); + } + + /* + * If scan offload is enabled then lim has allow the sending of + * scan request to firmware even in powersave mode. The firmware has + * to take care of exiting from power save mode + */ + status = sme_cfg_set_int(hHal, WNI_CFG_SCAN_IN_POWERSAVE, true); + + if (QDF_STATUS_SUCCESS != status) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "Could not pass on WNI_CFG_SCAN_IN_POWERSAVE to CFG"); + } + return status; +} + +/** + * sme_update_roam_params() - Store/Update the roaming params + * @hal: Handle for Hal layer + * @session_id: SME Session ID + * @roam_params_src: The source buffer to copy + * @update_param: Type of parameter to be updated + * + * Return: Return the status of the updation. + */ +QDF_STATUS sme_update_roam_params(tHalHandle hal, + uint8_t session_id, struct roam_ext_params roam_params_src, + int update_param) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + struct roam_ext_params *roam_params_dst; + uint8_t i; + + roam_params_dst = &mac_ctx->roam.configParam.roam_params; + switch (update_param) { + case REASON_ROAM_EXT_SCAN_PARAMS_CHANGED: + roam_params_dst->raise_rssi_thresh_5g = + roam_params_src.raise_rssi_thresh_5g; + roam_params_dst->drop_rssi_thresh_5g = + roam_params_src.drop_rssi_thresh_5g; + roam_params_dst->raise_factor_5g = + roam_params_src.raise_factor_5g; + roam_params_dst->drop_factor_5g = + roam_params_src.drop_factor_5g; + roam_params_dst->max_raise_rssi_5g = + roam_params_src.max_raise_rssi_5g; + roam_params_dst->max_drop_rssi_5g = + roam_params_src.max_drop_rssi_5g; + roam_params_dst->alert_rssi_threshold = + roam_params_src.alert_rssi_threshold; + roam_params_dst->is_5g_pref_enabled = true; + break; + case REASON_ROAM_SET_SSID_ALLOWED: + qdf_mem_set(&roam_params_dst->ssid_allowed_list, 0, + sizeof(tSirMacSSid) * MAX_SSID_ALLOWED_LIST); + roam_params_dst->num_ssid_allowed_list = + roam_params_src.num_ssid_allowed_list; + for (i = 0; i < roam_params_dst->num_ssid_allowed_list; i++) { + roam_params_dst->ssid_allowed_list[i].length = + roam_params_src.ssid_allowed_list[i].length; + qdf_mem_copy(roam_params_dst->ssid_allowed_list[i].ssId, + roam_params_src.ssid_allowed_list[i].ssId, + roam_params_dst->ssid_allowed_list[i].length); + } + break; + case REASON_ROAM_SET_FAVORED_BSSID: + qdf_mem_set(&roam_params_dst->bssid_favored, 0, + sizeof(tSirMacAddr) * MAX_BSSID_FAVORED); + roam_params_dst->num_bssid_favored = + roam_params_src.num_bssid_favored; + for (i = 0; i < roam_params_dst->num_bssid_favored; i++) { + qdf_mem_copy(&roam_params_dst->bssid_favored[i], + &roam_params_src.bssid_favored[i], + sizeof(tSirMacAddr)); + roam_params_dst->bssid_favored_factor[i] = + roam_params_src.bssid_favored_factor[i]; + } + break; + case REASON_ROAM_SET_BLACKLIST_BSSID: + qdf_mem_set(&roam_params_dst->bssid_avoid_list, 0, + QDF_MAC_ADDR_SIZE * MAX_BSSID_AVOID_LIST); + roam_params_dst->num_bssid_avoid_list = + roam_params_src.num_bssid_avoid_list; + for (i = 0; i < roam_params_dst->num_bssid_avoid_list; i++) { + qdf_copy_macaddr(&roam_params_dst->bssid_avoid_list[i], + &roam_params_src.bssid_avoid_list[i]); + } + break; + case REASON_ROAM_GOOD_RSSI_CHANGED: + roam_params_dst->good_rssi_roam = + roam_params_src.good_rssi_roam; + break; + default: + break; + } + csr_roam_offload_scan(mac_ctx, session_id, ROAM_SCAN_OFFLOAD_UPDATE_CFG, + update_param); + return 0; +} + +#ifdef WLAN_FEATURE_GTK_OFFLOAD +static void sme_process_get_gtk_info_rsp(tHalHandle hHal, + tpSirGtkOffloadGetInfoRspParams + pGtkOffloadGetInfoRsp) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + if (NULL == pMac) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_FATAL, + "%s: pMac is null", __func__); + return; + } + if (pMac->sme.gtk_offload_get_info_cb == NULL) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: HDD callback is null", __func__); + return; + } + pMac->sme.gtk_offload_get_info_cb( + pMac->sme.gtk_offload_get_info_cb_context, + pGtkOffloadGetInfoRsp); +} +#endif + +/*-------------------------------------------------------------------------- + + \fn - sme_process_ready_to_suspend + \brief - On getting ready to suspend indication, this function calls + callback registered (HDD callbacks) with SME to inform + ready to suspend indication. + + \param hHal - Handle returned by mac_open. + pReadyToSuspend - Parameter received along with ready to suspend + indication from WMA. + + \return None + + \sa + + --------------------------------------------------------------------------*/ +static void sme_process_ready_to_suspend(tHalHandle hHal, + tpSirReadyToSuspendInd pReadyToSuspend) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + if (NULL == pMac) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_FATAL, + "%s: pMac is null", __func__); + return; + } + + if (NULL != pMac->readyToSuspendCallback) { + pMac->readyToSuspendCallback(pMac->readyToSuspendContext, + pReadyToSuspend->suspended); + pMac->readyToSuspendCallback = NULL; + } +} + +#ifdef WLAN_FEATURE_EXTWOW_SUPPORT + +/** + * sme_process_ready_to_ext_wow() - inform ready to ExtWoW indication. + * @hHal - Handle returned by mac_open. + * @pReadyToExtWoW - Parameter received along with ready to Ext WoW + * indication from WMA. + * + * On getting ready to Ext WoW indication, this function calls callback + * registered (HDD callback)with SME to inform ready to ExtWoW indication. + * + * Return: None + */ +static void sme_process_ready_to_ext_wow(tHalHandle hHal, + tpSirReadyToExtWoWInd pReadyToExtWoW) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + if (NULL == pMac) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_FATAL, + "%s: pMac is null", __func__); + return; + } + + if (NULL != pMac->readyToExtWoWCallback) { + pMac->readyToExtWoWCallback(pMac->readyToExtWoWContext, + pReadyToExtWoW->status); + pMac->readyToExtWoWCallback = NULL; + pMac->readyToExtWoWContext = NULL; + } + +} +#endif + +/*-------------------------------------------------------------------------- + + \brief sme_hdd_ready_ind() - SME sends eWNI_SME_SYS_READY_IND to PE to inform + that the NIC is ready tio run. + + The function is called by HDD at the end of initialization stage so PE/HAL can + enable the NIC to running state. + + This is a synchronous call + \param hHal - The handle returned by mac_open. + + \return QDF_STATUS_SUCCESS - eWNI_SME_SYS_READY_IND is sent to PE + successfully. + + Other status means SME failed to send the message to PE. + \sa + + --------------------------------------------------------------------------*/ +QDF_STATUS sme_hdd_ready_ind(tHalHandle hHal) +{ + tSirSmeReadyReq *msg; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + MTRACE(qdf_trace(QDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_MSG_HDDREADYIND, NO_SESSION, 0)); + do { + msg = qdf_mem_malloc(sizeof(*msg)); + if (!msg) { + sme_err("Memory allocation failed! for msg"); + return QDF_STATUS_E_NOMEM; + } + msg->messageType = eWNI_SME_SYS_READY_IND; + msg->length = sizeof(*msg); + msg->add_bssdescr_cb = csr_scan_process_single_bssdescr; + msg->csr_roam_synch_cb = csr_roam_synch_callback; + msg->sme_msg_cb = sme_process_msg_callback; + + if (eSIR_FAILURE != u_mac_post_ctrl_msg(hHal, (tSirMbMsg *) + msg)) { + status = QDF_STATUS_SUCCESS; + } else { + sms_log(pMac, LOGE, + "u_mac_post_ctrl_msg failed to send eWNI_SME_SYS_READY_IND"); + break; + } + + status = csr_ready(pMac); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOGE, + "csr_ready failed with status=%d", + status); + break; + } + + if (QDF_STATUS_SUCCESS != rrm_ready(hHal)) { + status = QDF_STATUS_E_FAILURE; + sms_log(pMac, LOGE, "rrm_ready failed"); + break; + } + pMac->sme.state = SME_STATE_READY; + } while (0); + + return status; +} + +/*-------------------------------------------------------------------------- + + \brief sme_start() - Put all SME modules at ready state. + + The function starts each module in SME, PMC, CSR, etc. . Upon + successfully return, all modules are ready to run. + This is a synchronous call + \param hHal - The handle returned by mac_open. + + \return QDF_STATUS_SUCCESS - SME is ready. + + Other status means SME is failed to start + \sa + + --------------------------------------------------------------------------*/ +QDF_STATUS sme_start(tHalHandle hHal) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + do { + status = csr_start(pMac); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOGE, + "csr_start failed during smeStart with status=%d", + status); + break; + } + pMac->sme.state = SME_STATE_START; + } while (0); + + return status; +} + +/** + * sme_handle_scan_req() - Scan request handler + * @mac_ctx: MAC global context + * @msg: message buffer + * + * Scan request message from upper layer is handled as + * part of this API + * + * Return: QDF_STATUS + */ +static QDF_STATUS sme_handle_scan_req(tpAniSirGlobal mac_ctx, + void *msg) +{ + struct ani_scan_req *scan_msg; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + uint16_t session_id; + csr_scan_completeCallback callback; + + scan_msg = msg; + session_id = scan_msg->session_id; + callback = scan_msg->callback; + status = csr_scan_request(mac_ctx, session_id, + scan_msg->scan_param, + callback, scan_msg->ctx); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sms_log(mac_ctx, LOGE, + FL("scan request failed. session_id %d"), session_id); + } + csr_scan_free_request(mac_ctx, scan_msg->scan_param); + qdf_mem_free(scan_msg->scan_param); + return status; +} + +/** + * sme_handle_roc_req() - Roc request handler + * @mac_ctx: MAC global context + * @msg: message buffer + * + * Roc request message from upper layer is handled as + * part of this API + * + * Return: QDF_STATUS + */ +static QDF_STATUS sme_handle_roc_req(tHalHandle hal, + void *msg) +{ + struct ani_roc_req *roc_msg; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + remainOnChanCallback callback; + + if (msg == NULL) { + sms_log(mac_ctx, LOGE, FL("ROC request is NULL")); + return status; + } + + roc_msg = msg; + callback = roc_msg->callback; + status = p2p_remain_on_channel(hal, roc_msg->session_id, + roc_msg->channel, roc_msg->duration, callback, + roc_msg->ctx, roc_msg->is_p2pprobe_allowed, + roc_msg->scan_id); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sms_log(mac_ctx, LOGE, + FL("scan request failed. session_id %d scan_id %d"), + roc_msg->session_id, roc_msg->scan_id); + } + return status; +} + +#ifdef WLAN_FEATURE_11W +/*------------------------------------------------------------------ + * + * Handle the unprotected management frame indication from LIM and + * forward it to HDD. + * + *------------------------------------------------------------------*/ + +QDF_STATUS sme_unprotected_mgmt_frm_ind(tHalHandle hHal, + tpSirSmeUnprotMgmtFrameInd pSmeMgmtFrm) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + QDF_STATUS status = QDF_STATUS_SUCCESS; + tCsrRoamInfo pRoamInfo = { 0 }; + uint32_t SessionId = pSmeMgmtFrm->sessionId; + + pRoamInfo.nFrameLength = pSmeMgmtFrm->frameLen; + pRoamInfo.pbFrames = pSmeMgmtFrm->frameBuf; + pRoamInfo.frameType = pSmeMgmtFrm->frameType; + + /* forward the mgmt frame to HDD */ + csr_roam_call_callback(pMac, SessionId, &pRoamInfo, 0, + eCSR_ROAM_UNPROT_MGMT_FRAME_IND, 0); + + return status; +} +#endif + +/*------------------------------------------------------------------ + * + * Handle the DFS Radar Event and indicate it to the SAP + * + *------------------------------------------------------------------*/ +QDF_STATUS dfs_msg_processor(tpAniSirGlobal pMac, uint16_t msgType, void *pMsgBuf) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tCsrRoamInfo roamInfo = { 0 }; + tSirSmeDfsEventInd *dfs_event; + tSirSmeCSAIeTxCompleteRsp *csaIeTxCompleteRsp; + uint32_t sessionId = 0; + eRoamCmdStatus roamStatus; + eCsrRoamResult roamResult; + int i; + + switch (msgType) { + case eWNI_SME_DFS_RADAR_FOUND: + { + /* Radar found !! */ + dfs_event = (tSirSmeDfsEventInd *) pMsgBuf; + if (NULL == dfs_event) { + sms_log(pMac, LOGE, + "%s: pMsg is NULL for eWNI_SME_DFS_RADAR_FOUND message", + __func__); + return QDF_STATUS_E_FAILURE; + } + sessionId = dfs_event->sessionId; + roamInfo.dfs_event.sessionId = sessionId; + roamInfo.dfs_event.chan_list.nchannels = + dfs_event->chan_list.nchannels; + for (i = 0; i < dfs_event->chan_list.nchannels; i++) { + roamInfo.dfs_event.chan_list.channels[i] = + dfs_event->chan_list.channels[i]; + } + + roamInfo.dfs_event.dfs_radar_status = + dfs_event->dfs_radar_status; + roamInfo.dfs_event.use_nol = dfs_event->use_nol; + + roamStatus = eCSR_ROAM_DFS_RADAR_IND; + roamResult = eCSR_ROAM_RESULT_DFS_RADAR_FOUND_IND; + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO_MED, + "sapdfs: Radar indication event occurred"); + break; + } + case eWNI_SME_DFS_CSAIE_TX_COMPLETE_IND: + { + csaIeTxCompleteRsp = + (tSirSmeCSAIeTxCompleteRsp *) pMsgBuf; + if (NULL == csaIeTxCompleteRsp) { + sms_log(pMac, LOGE, + "%s: pMsg is NULL for eWNI_SME_DFS_CSAIE_TX_COMPLETE_IND", + __func__); + return QDF_STATUS_E_FAILURE; + } + sessionId = csaIeTxCompleteRsp->sessionId; + roamStatus = eCSR_ROAM_DFS_CHAN_SW_NOTIFY; + roamResult = eCSR_ROAM_RESULT_DFS_CHANSW_UPDATE_SUCCESS; + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO_MED, + "sapdfs: Received eWNI_SME_DFS_CSAIE_TX_COMPLETE_IND for session id [%d]", + sessionId); + break; + } + default: + { + sms_log(pMac, LOG1, "%s: Invalid DFS message = 0x%x", + __func__, msgType); + status = QDF_STATUS_E_FAILURE; + return status; + } + } + + /* Indicate Radar Event to SAP */ + csr_roam_call_callback(pMac, sessionId, &roamInfo, 0, + roamStatus, roamResult); + return status; +} + +/** + * sme_extended_change_channel_ind()- function to indicate ECSA + * action frame is received in lim to SAP + * @mac_ctx: pointer to global mac structure + * @msg_buf: contain new channel and session id. + * + * This function is called to post ECSA action frame + * receive event to SAP. + * + * Return: success if msg indicated to SAP else return failure + */ +static QDF_STATUS sme_extended_change_channel_ind(tpAniSirGlobal mac_ctx, + void *msg_buf) +{ + struct sir_sme_ext_cng_chan_ind *ext_chan_ind; + QDF_STATUS status = QDF_STATUS_SUCCESS; + uint32_t session_id = 0; + tCsrRoamInfo roamInfo = {0}; + eRoamCmdStatus roam_status; + eCsrRoamResult roam_result; + + + ext_chan_ind = msg_buf; + if (NULL == ext_chan_ind) { + sms_log(mac_ctx, LOGE, + FL("pMsg is NULL for eWNI_SME_EXT_CHANGE_CHANNEL_IND")); + return QDF_STATUS_E_FAILURE; + } + session_id = ext_chan_ind->session_id; + roamInfo.target_channel = ext_chan_ind->new_channel; + roam_status = eCSR_ROAM_EXT_CHG_CHNL_IND; + roam_result = eCSR_ROAM_EXT_CHG_CHNL_UPDATE_IND; + sms_log(mac_ctx, LOG1, + FL("sapdfs: Received eWNI_SME_EXT_CHANGE_CHANNEL_IND for session id [%d]"), + session_id); + + /* Indicate Ext Channel Change event to SAP */ + csr_roam_call_callback(mac_ctx, session_id, &roamInfo, 0, + roam_status, roam_result); + return status; +} + +/** + * sme_process_fw_mem_dump_rsp - process fw memory dump response from WMA + * + * @mac_ctx: pointer to MAC handle. + * @msg: pointer to received SME msg. + * + * This function process the received SME message and calls the corresponding + * callback which was already registered with SME. + * + * Return: None + */ +#ifdef WLAN_FEATURE_MEMDUMP +static void sme_process_fw_mem_dump_rsp(tpAniSirGlobal mac_ctx, cds_msg_t *msg) +{ + if (msg->bodyptr) { + if (mac_ctx->sme.fw_dump_callback) + mac_ctx->sme.fw_dump_callback(mac_ctx->hHdd, + (struct fw_dump_rsp *) msg->bodyptr); + qdf_mem_free(msg->bodyptr); + } +} +#else +static void sme_process_fw_mem_dump_rsp(tpAniSirGlobal mac_ctx, cds_msg_t *msg) +{ +} +#endif + +#ifdef FEATURE_WLAN_ESE +/** + * sme_update_is_ese_feature_enabled() - enable/disable ESE support at runtime + * @hHal: HAL handle + * @sessionId: session id + * @isEseIniFeatureEnabled: ese ini enabled + * + * It is used at in the REG_DYNAMIC_VARIABLE macro definition of + * isEseIniFeatureEnabled. This is a synchronous call + * + * Return: QDF_STATUS enumeration + */ +QDF_STATUS sme_update_is_ese_feature_enabled(tHalHandle hHal, + uint8_t sessionId, const bool isEseIniFeatureEnabled) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + if (pMac->roam.configParam.isEseIniFeatureEnabled == + isEseIniFeatureEnabled) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO, + "%s: ESE Mode is already enabled or disabled, nothing to do (returning) old(%d) new(%d)", + __func__, + pMac->roam.configParam.isEseIniFeatureEnabled, + isEseIniFeatureEnabled); + return QDF_STATUS_SUCCESS; + } + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO, + "%s: EseEnabled is changed from %d to %d", __func__, + pMac->roam.configParam.isEseIniFeatureEnabled, + isEseIniFeatureEnabled); + pMac->roam.configParam.isEseIniFeatureEnabled = isEseIniFeatureEnabled; + csr_neighbor_roam_update_fast_roaming_enabled( + pMac, sessionId, isEseIniFeatureEnabled); + + if (true == isEseIniFeatureEnabled) + sme_update_fast_transition_enabled(hHal, true); + + if (pMac->roam.configParam.isRoamOffloadScanEnabled) + csr_roam_offload_scan(pMac, sessionId, + ROAM_SCAN_OFFLOAD_UPDATE_CFG, + REASON_ESE_INI_CFG_CHANGED); + + return QDF_STATUS_SUCCESS; +} + +/** + * sme_set_plm_request() - set plm request + * @hHal: HAL handle + * @pPlmReq: Pointer to input plm request + * + * Return: QDF_STATUS enumeration + */ +QDF_STATUS sme_set_plm_request(tHalHandle hHal, tpSirPlmReq pPlmReq) +{ + QDF_STATUS status; + bool ret = false; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + uint8_t ch_list[WNI_CFG_VALID_CHANNEL_LIST] = { 0 }; + uint8_t count, valid_count = 0; + cds_msg_t msg; + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, pPlmReq->sessionId); + + status = sme_acquire_global_lock(&pMac->sme); + if (!QDF_IS_STATUS_SUCCESS(status)) + return status; + + if (!pSession) { + sms_log(pMac, LOGE, FL("session %d not found"), + pPlmReq->sessionId); + sme_release_global_lock(&pMac->sme); + return QDF_STATUS_E_FAILURE; + } + + if (!pSession->sessionActive) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Invalid Sessionid")); + sme_release_global_lock(&pMac->sme); + return QDF_STATUS_E_FAILURE; + } + + if (!pPlmReq->enable) + goto send_plm_start; + /* validating channel numbers */ + for (count = 0; count < pPlmReq->plmNumCh; count++) { + ret = csr_is_supported_channel(pMac, pPlmReq->plmChList[count]); + if (ret && pPlmReq->plmChList[count] > 14) { + if (CHANNEL_STATE_DFS == cds_get_channel_state( + pPlmReq->plmChList[count])) { + /* DFS channel is provided, no PLM bursts can be + * transmitted. Ignoring these channels. + */ + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_INFO, + FL("DFS channel %d ignored for PLM"), + pPlmReq->plmChList[count]); + continue; + } + } else if (!ret) { + /* Not supported, ignore the channel */ + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO, + FL("Unsupported channel %d ignored for PLM"), + pPlmReq->plmChList[count]); + continue; + } + ch_list[valid_count] = pPlmReq->plmChList[count]; + valid_count++; + } /* End of for () */ + + /* Copying back the valid channel list to plm struct */ + qdf_mem_set((void *)pPlmReq->plmChList, + pPlmReq->plmNumCh, 0); + if (valid_count) + qdf_mem_copy(pPlmReq->plmChList, ch_list, + valid_count); + /* All are invalid channels, FW need to send the PLM + * report with "incapable" bit set. + */ + pPlmReq->plmNumCh = valid_count; + +send_plm_start: + /* PLM START */ + msg.type = WMA_SET_PLM_REQ; + msg.reserved = 0; + msg.bodyptr = pPlmReq; + + if (!QDF_IS_STATUS_SUCCESS(cds_mq_post_message(QDF_MODULE_ID_WMA, + &msg))) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Not able to post WMA_SET_PLM_REQ to WMA")); + sme_release_global_lock(&pMac->sme); + return QDF_STATUS_E_FAILURE; + } + + sme_release_global_lock(&pMac->sme); + return status; +} + +/** + * sme_tsm_ie_ind() - sme tsm ie indication + * @hHal: HAL handle + * @pSmeTsmIeInd: Pointer to tsm ie indication + * + * Handle the tsm ie indication from LIM and forward it to HDD. + * + * Return: QDF_STATUS enumeration + */ +static QDF_STATUS sme_tsm_ie_ind(tHalHandle hHal, tSirSmeTsmIEInd *pSmeTsmIeInd) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + QDF_STATUS status = QDF_STATUS_SUCCESS; + tCsrRoamInfo pRoamInfo = { 0 }; + uint32_t SessionId = pSmeTsmIeInd->sessionId; + pRoamInfo.tsmIe.tsid = pSmeTsmIeInd->tsmIe.tsid; + pRoamInfo.tsmIe.state = pSmeTsmIeInd->tsmIe.state; + pRoamInfo.tsmIe.msmt_interval = pSmeTsmIeInd->tsmIe.msmt_interval; + /* forward the tsm ie information to HDD */ + csr_roam_call_callback(pMac, + SessionId, &pRoamInfo, 0, eCSR_ROAM_TSM_IE_IND, 0); + return status; +} + +/** + * sme_set_cckm_ie() - set cckm ie + * @hHal: HAL handle + * @sessionId: session id + * @pCckmIe: Pointer to CCKM Ie + * @cckmIeLen: Length of @pCckmIe + * + * Function to store the CCKM IE passed from supplicant and use + * it while packing reassociation request. + * + * Return: QDF_STATUS enumeration + */ +QDF_STATUS sme_set_cckm_ie(tHalHandle hHal, uint8_t sessionId, + uint8_t *pCckmIe, uint8_t cckmIeLen) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + QDF_STATUS status = QDF_STATUS_SUCCESS; + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + csr_set_cckm_ie(pMac, sessionId, pCckmIe, cckmIeLen); + sme_release_global_lock(&pMac->sme); + } + return status; +} + +/** + * sme_set_ese_beacon_request() - set ese beacon request + * @hHal: HAL handle + * @sessionId: session id + * @pEseBcnReq: Ese beacon report + * + * function to set ESE beacon request parameters + * + * Return: QDF_STATUS enumeration + */ +QDF_STATUS sme_set_ese_beacon_request(tHalHandle hHal, const uint8_t sessionId, + const tCsrEseBeaconReq *pEseBcnReq) +{ + QDF_STATUS status = eSIR_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + tpSirBeaconReportReqInd pSmeBcnReportReq = NULL; + tCsrEseBeaconReqParams *pBeaconReq = NULL; + uint8_t counter = 0; + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + tpRrmSMEContext pSmeRrmContext = &pMac->rrm.rrmSmeContext; + + if (pSmeRrmContext->eseBcnReqInProgress == true) { + sms_log(pMac, LOGE, + "A Beacon Report Req is already in progress"); + return QDF_STATUS_E_RESOURCES; + } + + /* Store the info in RRM context */ + qdf_mem_copy(&pSmeRrmContext->eseBcnReqInfo, pEseBcnReq, + sizeof(tCsrEseBeaconReq)); + + /* Prepare the request to send to SME. */ + pSmeBcnReportReq = qdf_mem_malloc(sizeof(tSirBeaconReportReqInd)); + if (NULL == pSmeBcnReportReq) { + sms_log(pMac, LOGP, + "Memory Allocation Failure!!! ESE BcnReq Ind to SME"); + return QDF_STATUS_E_NOMEM; + } + + pSmeRrmContext->eseBcnReqInProgress = true; + + sms_log(pMac, LOGE, "Sending Beacon Report Req to SME"); + + pSmeBcnReportReq->messageType = eWNI_SME_BEACON_REPORT_REQ_IND; + pSmeBcnReportReq->length = sizeof(tSirBeaconReportReqInd); + qdf_mem_copy(pSmeBcnReportReq->bssId, + pSession->connectedProfile.bssid.bytes, + sizeof(tSirMacAddr)); + pSmeBcnReportReq->channelInfo.channelNum = 255; + pSmeBcnReportReq->channelList.numChannels = pEseBcnReq->numBcnReqIe; + pSmeBcnReportReq->msgSource = eRRM_MSG_SOURCE_ESE_UPLOAD; + + for (counter = 0; counter < pEseBcnReq->numBcnReqIe; counter++) { + pBeaconReq = + (tCsrEseBeaconReqParams *) &pEseBcnReq->bcnReq[counter]; + pSmeBcnReportReq->fMeasurementtype[counter] = + pBeaconReq->scanMode; + pSmeBcnReportReq->measurementDuration[counter] = + SYS_TU_TO_MS(pBeaconReq->measurementDuration); + pSmeBcnReportReq->channelList.channelNumber[counter] = + pBeaconReq->channel; + } + + status = sme_rrm_process_beacon_report_req_ind(pMac, pSmeBcnReportReq); + + if (status != QDF_STATUS_SUCCESS) + pSmeRrmContext->eseBcnReqInProgress = false; + + qdf_mem_free(pSmeBcnReportReq); + + return status; +} + +/** + * sme_get_tsm_stats() - SME get tsm stats + * @hHal: HAL handle + * @callback: SME sends back the requested stats using the callback + * @staId: The station ID for which the stats is requested for + * @bssId: bssid + * @pContext: user context to be passed back along with the callback + * @p_cds_context: CDS context + * @tid: Traffic id + * + * API register a callback to get TSM Stats. + * + * Return: QDF_STATUS enumeration + */ +QDF_STATUS sme_get_tsm_stats(tHalHandle hHal, + tCsrTsmStatsCallback callback, + uint8_t staId, struct qdf_mac_addr bssId, + void *pContext, void *p_cds_context, uint8_t tid) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + status = csr_get_tsm_stats(pMac, callback, + staId, bssId, pContext, + p_cds_context, tid); + sme_release_global_lock(&pMac->sme); + } + return status; +} + +/** + * sme_set_ese_roam_scan_channel_list() - To set ese roam scan channel list + * @hHal: pointer HAL handle returned by mac_open + * @sessionId: sme session id + * @pChannelList: Output channel list + * @numChannels: Output number of channels + * + * This routine is called to set ese roam scan channel list. + * This is a synchronous call + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_set_ese_roam_scan_channel_list(tHalHandle hHal, + uint8_t sessionId, + uint8_t *pChannelList, + uint8_t numChannels) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpCsrNeighborRoamControlInfo pNeighborRoamInfo = NULL; + tpCsrChannelInfo curchnl_list_info = NULL; + uint8_t oldChannelList[WNI_CFG_VALID_CHANNEL_LIST_LEN * 2] = { 0 }; + uint8_t newChannelList[128] = { 0 }; + uint8_t i = 0, j = 0; + + if (sessionId >= CSR_ROAM_SESSION_MAX) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Invalid sme session id: %d"), sessionId); + return QDF_STATUS_E_INVAL; + } + + pNeighborRoamInfo = &pMac->roam.neighborRoamInfo[sessionId]; + curchnl_list_info = + &pNeighborRoamInfo->roamChannelInfo.currentChannelListInfo; + + status = sme_acquire_global_lock(&pMac->sme); + if (!QDF_IS_STATUS_SUCCESS(status)) { + if (pMac->roam.configParam.isRoamOffloadScanEnabled) + csr_roam_offload_scan(pMac, sessionId, + ROAM_SCAN_OFFLOAD_UPDATE_CFG, + REASON_CHANNEL_LIST_CHANGED); + return status; + } + if (NULL != curchnl_list_info->ChannelList) { + for (i = 0; i < curchnl_list_info->numOfChannels; i++) { + j += snprintf(oldChannelList + j, + sizeof(oldChannelList) - j, "%d", + curchnl_list_info->ChannelList[i]); + } + } + status = csr_create_roam_scan_channel_list(pMac, sessionId, + pChannelList, numChannels, + csr_get_current_band(hHal)); + if (QDF_IS_STATUS_SUCCESS(status)) { + if (NULL != curchnl_list_info->ChannelList) { + j = 0; + for (i = 0; i < curchnl_list_info->numOfChannels; i++) { + j += snprintf(newChannelList + j, + sizeof(newChannelList) - j, "%d", + curchnl_list_info->ChannelList[i]); + } + } + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "ESE roam scan chnl list successfully set to %s-old value is %s-roam state is %d", + newChannelList, oldChannelList, + pNeighborRoamInfo->neighborRoamState); + } + sme_release_global_lock(&pMac->sme); + if (pMac->roam.configParam.isRoamOffloadScanEnabled) + csr_roam_offload_scan(pMac, sessionId, + ROAM_SCAN_OFFLOAD_UPDATE_CFG, + REASON_CHANNEL_LIST_CHANGED); + return status; +} + +#endif /* FEATURE_WLAN_ESE */ + +static +QDF_STATUS sme_ibss_peer_info_response_handler(tHalHandle hHal, + tpSirIbssGetPeerInfoRspParams + pIbssPeerInfoParams) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + if (NULL == pMac) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_FATAL, + "%s: pMac is null", __func__); + return QDF_STATUS_E_FAILURE; + } + if (pMac->sme.peerInfoParams.peerInfoCbk == NULL) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: HDD callback is null", __func__); + return QDF_STATUS_E_FAILURE; + } + pMac->sme.peerInfoParams.peerInfoCbk(pMac->sme.peerInfoParams.pUserData, + &pIbssPeerInfoParams-> + ibssPeerInfoRspParams); + return QDF_STATUS_SUCCESS; +} + +/** + * sme_process_dual_mac_config_resp() - Process set Dual mac config response + * @mac: Global MAC pointer + * @msg: Dual mac config response + * + * Processes the dual mac configuration response and invokes the HDD callback + * to process further + */ +static QDF_STATUS sme_process_dual_mac_config_resp(tpAniSirGlobal mac, + uint8_t *msg) +{ + tListElem *entry = NULL; + tSmeCmd *command = NULL; + bool found; + dual_mac_cb callback = NULL; + struct sir_dual_mac_config_resp *param; + + param = (struct sir_dual_mac_config_resp *)msg; + if (!param) { + sms_log(mac, LOGE, FL("Dual mac config resp param is NULL")); + /* Not returning. Need to check if active command list + * needs to be freed + */ + } + + entry = csr_ll_peek_head(&mac->sme.smeCmdActiveList, + LL_ACCESS_LOCK); + if (!entry) { + sms_log(mac, LOGE, FL("No cmd found in active list")); + return QDF_STATUS_E_FAILURE; + } + + command = GET_BASE_ADDR(entry, tSmeCmd, Link); + if (!command) { + sms_log(mac, LOGE, FL("Base address is NULL")); + return QDF_STATUS_E_FAILURE; + } + + if (e_sme_command_set_dual_mac_config != command->command) { + sms_log(mac, LOGE, FL("Command mismatch!")); + return QDF_STATUS_E_FAILURE; + } + + callback = command->u.set_dual_mac_cmd.set_dual_mac_cb; + if (callback) { + if (!param) { + sms_log(mac, LOGE, + FL("Callback failed-Dual mac config is NULL")); + } else { + sms_log(mac, LOG1, + FL("Calling HDD callback for Dual mac config")); + callback(param->status, + command->u.set_dual_mac_cmd.scan_config, + command->u.set_dual_mac_cmd.fw_mode_config); + } + } else { + sms_log(mac, LOGE, FL("Callback does not exist")); + } + + found = csr_ll_remove_entry(&mac->sme.smeCmdActiveList, entry, + LL_ACCESS_LOCK); + if (found) + /* Now put this command back on the available command list */ + sme_release_command(mac, command); + + sme_process_pending_queue(mac); + return QDF_STATUS_SUCCESS; +} + +/** + * sme_process_antenna_mode_resp() - Process set antenna mode + * response + * @mac: Global MAC pointer + * @msg: antenna mode response + * + * Processes the antenna mode response and invokes the HDD + * callback to process further + */ +static QDF_STATUS sme_process_antenna_mode_resp(tpAniSirGlobal mac, + uint8_t *msg) +{ + tListElem *entry; + tSmeCmd *command; + bool found; + antenna_mode_cb callback; + struct sir_antenna_mode_resp *param; + + param = (struct sir_antenna_mode_resp *)msg; + if (!param) { + sms_log(mac, LOGE, FL("set antenna mode resp is NULL")); + /* Not returning. Need to check if active command list + * needs to be freed + */ + } + + entry = csr_ll_peek_head(&mac->sme.smeCmdActiveList, + LL_ACCESS_LOCK); + if (!entry) { + sms_log(mac, LOGE, FL("No cmd found in active list")); + return QDF_STATUS_E_FAILURE; + } + + command = GET_BASE_ADDR(entry, tSmeCmd, Link); + if (!command) { + sms_log(mac, LOGE, FL("Base address is NULL")); + return QDF_STATUS_E_FAILURE; + } + + if (e_sme_command_set_antenna_mode != command->command) { + sms_log(mac, LOGE, FL("Command mismatch!")); + return QDF_STATUS_E_FAILURE; + } + + callback = + command->u.set_antenna_mode_cmd.set_antenna_mode_resp; + if (callback) { + if (!param) { + sms_log(mac, LOGE, + FL("Set antenna mode call back is NULL")); + } else { + sms_log(mac, LOG1, + FL("HDD callback for set antenna mode")); + callback(param->status); + } + } else { + sms_log(mac, LOGE, FL("Callback does not exist")); + } + + found = csr_ll_remove_entry(&mac->sme.smeCmdActiveList, entry, + LL_ACCESS_LOCK); + if (found) + /* Now put this command back on the available command list */ + sme_release_command(mac, command); + + sme_process_pending_queue(mac); + return QDF_STATUS_SUCCESS; +} + +/*-------------------------------------------------------------------------- + + \brief sme_process_msg() - The main message processor for SME. + + The function is called by a message dispatcher when to process a message + targeted for SME. + + This is a synchronous call + \param hHal - The handle returned by mac_open. + \param pMsg - A pointer to a caller allocated object of tSirMsgQ. + + \return QDF_STATUS_SUCCESS - SME successfully process the message. + + Other status means SME failed to process the message to HAL. + \sa + + --------------------------------------------------------------------------*/ +QDF_STATUS sme_process_msg(tHalHandle hHal, cds_msg_t *pMsg) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + if (pMsg == NULL) { + sms_log(pMac, LOGE, "Empty message for SME"); + return status; + } + status = sme_acquire_global_lock(&pMac->sme); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOGW, FL("Locking failed, bailing out")); + if (pMsg->bodyptr) + qdf_mem_free(pMsg->bodyptr); + return status; + } + if (!SME_IS_START(pMac)) { + sms_log(pMac, LOGW, FL("message type %d in stop state ignored"), + pMsg->type); + if (pMsg->bodyptr) + qdf_mem_free(pMsg->bodyptr); + goto release_lock; + } + switch (pMsg->type) { +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + case eWNI_SME_HO_FAIL_IND: + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("LFR3: Rcvd eWNI_SME_HO_FAIL_IND")); + csr_process_ho_fail_ind(pMac, pMsg->bodyptr); + qdf_mem_free(pMsg->bodyptr); + break; +#endif + case WNI_CFG_SET_CNF: + case WNI_CFG_DNLD_CNF: + case WNI_CFG_GET_RSP: + case WNI_CFG_ADD_GRP_ADDR_CNF: + case WNI_CFG_DEL_GRP_ADDR_CNF: + break; + case eWNI_SME_ADDTS_RSP: + case eWNI_SME_DELTS_RSP: + case eWNI_SME_DELTS_IND: + case eWNI_SME_FT_AGGR_QOS_RSP: + /* QoS */ + if (pMsg->bodyptr) { +#ifndef WLAN_MDM_CODE_REDUCTION_OPT + status = sme_qos_msg_processor(pMac, pMsg->type, + pMsg->bodyptr); + qdf_mem_free(pMsg->bodyptr); +#endif + } else { + sms_log(pMac, LOGE, FL("Empty message for %d"), + pMsg->type); + } + break; + case eWNI_SME_NEIGHBOR_REPORT_IND: + case eWNI_SME_BEACON_REPORT_REQ_IND: + if (pMsg->bodyptr) { + status = sme_rrm_msg_processor(pMac, pMsg->type, + pMsg->bodyptr); + qdf_mem_free(pMsg->bodyptr); + } else { + sms_log(pMac, LOGE, FL("Empty message for %d"), + pMsg->type); + } + break; + case eWNI_SME_ADD_STA_SELF_RSP: + if (pMsg->bodyptr) { + status = csr_process_add_sta_session_rsp(pMac, + pMsg->bodyptr); + qdf_mem_free(pMsg->bodyptr); + } else { + sms_log(pMac, LOGE, FL("Empty message for %d"), + pMsg->type); + } + break; + case eWNI_SME_DEL_STA_SELF_RSP: + if (pMsg->bodyptr) { + status = csr_process_del_sta_session_rsp(pMac, + pMsg->bodyptr); + qdf_mem_free(pMsg->bodyptr); + } else { + sms_log(pMac, LOGE, FL("Empty message for %d"), + pMsg->type); + } + break; + case eWNI_SME_REMAIN_ON_CHN_RSP: + if (pMsg->bodyptr) { + status = sme_remain_on_chn_rsp(pMac, pMsg->bodyptr); + qdf_mem_free(pMsg->bodyptr); + } else { + sms_log(pMac, LOGE, FL("Empty message for %d"), + pMsg->type); + } + break; + case eWNI_SME_REMAIN_ON_CHN_RDY_IND: + if (pMsg->bodyptr) { + status = sme_remain_on_chn_ready(pMac, pMsg->bodyptr); + qdf_mem_free(pMsg->bodyptr); + } else { + sms_log(pMac, LOGE, FL("Empty message for %d"), + pMsg->type); + } + break; +#ifdef FEATURE_WLAN_SCAN_PNO + case eWNI_SME_PREF_NETWORK_FOUND_IND: + MTRACE(qdf_trace(QDF_MODULE_ID_SME, TRACE_CODE_SME_RX_WMA_MSG, + NO_SESSION, pMsg->type)); + if (pMsg->bodyptr) { + status = sme_preferred_network_found_ind((void *)pMac, + pMsg->bodyptr); + qdf_mem_free(pMsg->bodyptr); + } else { + sms_log(pMac, LOGE, FL("Empty message for %d"), + pMsg->type); + } + break; +#endif /* FEATURE_WLAN_SCAN_PNO */ + case eWNI_SME_CHANGE_COUNTRY_CODE: + if (pMsg->bodyptr) { + status = sme_handle_change_country_code((void *)pMac, + pMsg->bodyptr); + qdf_mem_free(pMsg->bodyptr); + } else { + sms_log(pMac, LOGE, FL("Empty message for %d"), + pMsg->type); + } + break; + case eWNI_SME_GENERIC_CHANGE_COUNTRY_CODE: + if (pMsg->bodyptr) { + status = sme_handle_generic_change_country_code( + (void *)pMac, pMsg->bodyptr); + qdf_mem_free(pMsg->bodyptr); + } else { + sms_log(pMac, LOGE, FL("Empty message for %d"), + pMsg->type); + } + break; + case eWNI_SME_SCAN_CMD: + if (pMsg->bodyptr) { + status = sme_handle_scan_req(pMac, pMsg->bodyptr); + qdf_mem_free(pMsg->bodyptr); + } else { + sms_log(pMac, LOGE, FL("Empty message for %d"), + pMsg->type); + } + break; + case eWNI_SME_ROC_CMD: + if (pMsg->bodyptr) { + status = sme_handle_roc_req(hHal, pMsg->bodyptr); + qdf_mem_free(pMsg->bodyptr); + } else { + sms_log(pMac, LOGE, FL("Empty message for %d"), + pMsg->type); + } + break; +#ifdef FEATURE_WLAN_TDLS + /* + * command rescived from PE, SME tdls msg processor shall be called + * to process commands recieved from PE + */ + case eWNI_SME_TDLS_SEND_MGMT_RSP: + case eWNI_SME_TDLS_ADD_STA_RSP: + case eWNI_SME_TDLS_DEL_STA_RSP: + case eWNI_SME_TDLS_DEL_STA_IND: + case eWNI_SME_TDLS_DEL_ALL_PEER_IND: + case eWNI_SME_MGMT_FRM_TX_COMPLETION_IND: + case eWNI_SME_TDLS_LINK_ESTABLISH_RSP: + case eWNI_SME_TDLS_SHOULD_DISCOVER: + case eWNI_SME_TDLS_SHOULD_TEARDOWN: + case eWNI_SME_TDLS_PEER_DISCONNECTED: + if (pMsg->bodyptr) { + status = tdls_msg_processor(pMac, pMsg->type, + pMsg->bodyptr); + qdf_mem_free(pMsg->bodyptr); + } else { + sms_log(pMac, LOGE, FL("Empty message for %d"), + pMsg->type); + } + break; +#endif +#ifdef WLAN_FEATURE_11W + case eWNI_SME_UNPROT_MGMT_FRM_IND: + if (pMsg->bodyptr) { + sme_unprotected_mgmt_frm_ind(pMac, pMsg->bodyptr); + qdf_mem_free(pMsg->bodyptr); + } else { + sms_log(pMac, LOGE, FL("Empty message for %d"), + pMsg->type); + } + break; +#endif +#ifdef FEATURE_WLAN_ESE + case eWNI_SME_TSM_IE_IND: + if (pMsg->bodyptr) { + sme_tsm_ie_ind(pMac, pMsg->bodyptr); + qdf_mem_free(pMsg->bodyptr); + } else { + sms_log(pMac, LOGE, FL("Empty message for %d"), + pMsg->type); + } + break; +#endif /* FEATURE_WLAN_ESE */ + case eWNI_SME_ROAM_SCAN_OFFLOAD_RSP: + status = csr_roam_offload_scan_rsp_hdlr((void *)pMac, + pMsg->bodyptr); + qdf_mem_free(pMsg->bodyptr); + break; +#ifdef WLAN_FEATURE_GTK_OFFLOAD + case eWNI_PMC_GTK_OFFLOAD_GETINFO_RSP: + MTRACE(qdf_trace(QDF_MODULE_ID_SME, TRACE_CODE_SME_RX_WMA_MSG, + NO_SESSION, pMsg->type)); + if (pMsg->bodyptr) { + sme_process_get_gtk_info_rsp(pMac, pMsg->bodyptr); + qdf_mem_free(pMsg->bodyptr); + } else { + sms_log(pMac, LOGE, FL("Empty message for %d"), + pMsg->type); + } + break; +#endif +#ifdef FEATURE_WLAN_LPHB + /* LPHB timeout indication arrived, send IND to client */ + case eWNI_SME_LPHB_IND: + MTRACE(qdf_trace(QDF_MODULE_ID_SME, TRACE_CODE_SME_RX_WMA_MSG, + NO_SESSION, pMsg->type)); + if (pMac->sme.pLphbIndCb) + pMac->sme.pLphbIndCb(pMac->hHdd, pMsg->bodyptr); + qdf_mem_free(pMsg->bodyptr); + break; +#endif /* FEATURE_WLAN_LPHB */ + case eWNI_SME_IBSS_PEER_INFO_RSP: + if (pMsg->bodyptr) { + sme_ibss_peer_info_response_handler(pMac, + pMsg->bodyptr); + qdf_mem_free(pMsg->bodyptr); + } else { + sms_log(pMac, LOGE, FL("Empty message for %d"), + pMsg->type); + } + break; + case eWNI_SME_READY_TO_SUSPEND_IND: + if (pMsg->bodyptr) { + sme_process_ready_to_suspend(pMac, pMsg->bodyptr); + qdf_mem_free(pMsg->bodyptr); + } else { + sms_log(pMac, LOGE, FL("Empty message for %d"), + pMsg->type); + } + break; +#ifdef WLAN_FEATURE_EXTWOW_SUPPORT + case eWNI_SME_READY_TO_EXTWOW_IND: + if (pMsg->bodyptr) { + sme_process_ready_to_ext_wow(pMac, pMsg->bodyptr); + qdf_mem_free(pMsg->bodyptr); + } else { + sms_log(pMac, LOGE, FL("Empty message for %d"), + pMsg->type); + } + break; +#endif +#ifdef FEATURE_WLAN_CH_AVOID + /* channel avoid message arrived, send IND to client */ + case eWNI_SME_CH_AVOID_IND: + MTRACE(qdf_trace(QDF_MODULE_ID_SME, TRACE_CODE_SME_RX_WMA_MSG, + NO_SESSION, pMsg->type)); + if (pMac->sme.pChAvoidNotificationCb) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO, + FL("CH avoid notification")); + pMac->sme.pChAvoidNotificationCb(pMac->hHdd, + pMsg->bodyptr); + } + qdf_mem_free(pMsg->bodyptr); + break; +#endif /* FEATURE_WLAN_CH_AVOID */ +#ifdef FEATURE_WLAN_AUTO_SHUTDOWN + case eWNI_SME_AUTO_SHUTDOWN_IND: + if (pMac->sme.pAutoShutdownNotificationCb) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO, + FL("Auto shutdown notification")); + pMac->sme.pAutoShutdownNotificationCb(); + } + qdf_mem_free(pMsg->bodyptr); + break; +#endif + case eWNI_SME_DFS_RADAR_FOUND: + case eWNI_SME_DFS_CSAIE_TX_COMPLETE_IND: + status = dfs_msg_processor(pMac, pMsg->type, pMsg->bodyptr); + qdf_mem_free(pMsg->bodyptr); + break; + case eWNI_SME_CHANNEL_CHANGE_RSP: + if (pMsg->bodyptr) { + status = sme_process_channel_change_resp(pMac, + pMsg->type, + pMsg->bodyptr); + qdf_mem_free(pMsg->bodyptr); + } else { + sms_log(pMac, LOGE, FL("Empty message for %d"), + pMsg->type); + } + break; +#ifdef WLAN_FEATURE_STATS_EXT + case eWNI_SME_STATS_EXT_EVENT: + if (pMsg->bodyptr) { + status = sme_stats_ext_event(hHal, pMsg->bodyptr); + qdf_mem_free(pMsg->bodyptr); + } else { + sms_log(pMac, LOGE, FL("Empty message for %d"), + pMsg->type); + } + break; +#endif + case eWNI_SME_CSA_OFFLOAD_EVENT: + if (pMsg->bodyptr) { + csr_scan_flush_bss_entry(pMac, pMsg->bodyptr); + qdf_mem_free(pMsg->bodyptr); + } + break; + case eWNI_SME_TSF_EVENT: + if (pMac->sme.get_tsf_cb) { + pMac->sme.get_tsf_cb(pMac->sme.get_tsf_cxt, + (struct stsf *)pMsg->bodyptr); + } + if (pMsg->bodyptr) + qdf_mem_free(pMsg->bodyptr); + break; +#ifdef WLAN_FEATURE_NAN + case eWNI_SME_NAN_EVENT: + MTRACE(qdf_trace(QDF_MODULE_ID_SME, TRACE_CODE_SME_RX_WMA_MSG, + NO_SESSION, pMsg->type)); + if (pMsg->bodyptr) { + sme_nan_event(hHal, pMsg->bodyptr); + qdf_mem_free(pMsg->bodyptr); + } + break; +#endif /* WLAN_FEATURE_NAN */ + case eWNI_SME_LINK_STATUS_IND: + { + tAniGetLinkStatus *pLinkStatus = + (tAniGetLinkStatus *) pMsg->bodyptr; + if (pLinkStatus) { + if (pMac->sme.linkStatusCallback) { + pMac->sme.linkStatusCallback( + pLinkStatus->linkStatus, + pMac->sme.linkStatusContext); + } + pMac->sme.linkStatusCallback = NULL; + pMac->sme.linkStatusContext = NULL; + qdf_mem_free(pLinkStatus); + } + break; + } + case eWNI_SME_MSG_GET_TEMPERATURE_IND: + if (pMac->sme.pGetTemperatureCb) { + pMac->sme.pGetTemperatureCb(pMsg->bodyval, + pMac->sme.pTemperatureCbContext); + } + break; + case eWNI_SME_SNR_IND: + { + tAniGetSnrReq *pSnrReq = (tAniGetSnrReq *) pMsg->bodyptr; + if (pSnrReq) { + if (pSnrReq->snrCallback) { + ((tCsrSnrCallback) + (pSnrReq->snrCallback)) + (pSnrReq->snr, pSnrReq->staId, + pSnrReq->pDevContext); + } + qdf_mem_free(pSnrReq); + } + break; + } +#ifdef FEATURE_WLAN_EXTSCAN + case eWNI_SME_EXTSCAN_FULL_SCAN_RESULT_IND: + if (pMac->sme.pExtScanIndCb) + pMac->sme.pExtScanIndCb(pMac->hHdd, + eSIR_EXTSCAN_FULL_SCAN_RESULT_IND, + pMsg->bodyptr); + else + sms_log(pMac, LOGE, + FL("callback not registered to process %d"), + pMsg->type); + + qdf_mem_free(pMsg->bodyptr); + break; + case eWNI_SME_EPNO_NETWORK_FOUND_IND: + if (pMac->sme.pExtScanIndCb) + pMac->sme.pExtScanIndCb(pMac->hHdd, + eSIR_EPNO_NETWORK_FOUND_IND, + pMsg->bodyptr); + else + sms_log(pMac, LOGE, + FL("callback not registered to process %d"), + pMsg->type); + + qdf_mem_free(pMsg->bodyptr); + break; +#endif + case eWNI_SME_FW_DUMP_IND: + sme_process_fw_mem_dump_rsp(pMac, pMsg); + break; + case eWNI_SME_SET_HW_MODE_RESP: + if (pMsg->bodyptr) { + status = sme_process_set_hw_mode_resp(pMac, + pMsg->bodyptr); + qdf_mem_free(pMsg->bodyptr); + } else { + sms_log(pMac, LOGE, FL("Empty message for %d"), + pMsg->type); + } + break; + case eWNI_SME_HW_MODE_TRANS_IND: + if (pMsg->bodyptr) { + status = sme_process_hw_mode_trans_ind(pMac, + pMsg->bodyptr); + qdf_mem_free(pMsg->bodyptr); + } else { + sms_log(pMac, LOGE, FL("Empty message for %d"), + pMsg->type); + } + break; + case eWNI_SME_NSS_UPDATE_RSP: + if (pMsg->bodyptr) { + status = sme_process_nss_update_resp(pMac, + pMsg->bodyptr); + qdf_mem_free(pMsg->bodyptr); + } else { + sms_log(pMac, LOGE, FL("Empty message for %d"), + pMsg->type); + } + break; + case eWNI_SME_OCB_SET_CONFIG_RSP: + if (pMac->sme.ocb_set_config_callback) { + pMac->sme.ocb_set_config_callback( + pMac->sme.ocb_set_config_context, + pMsg->bodyptr); + } else { + sms_log(pMac, LOGE, FL( + "Message error. The callback is NULL.")); + } + pMac->sme.ocb_set_config_callback = NULL; + pMac->sme.ocb_set_config_context = NULL; + qdf_mem_free(pMsg->bodyptr); + break; + case eWNI_SME_OCB_GET_TSF_TIMER_RSP: + if (pMac->sme.ocb_get_tsf_timer_callback) { + pMac->sme.ocb_get_tsf_timer_callback( + pMac->sme.ocb_get_tsf_timer_context, + pMsg->bodyptr); + } else { + sms_log(pMac, LOGE, FL( + "Message error. The callback is NULL.")); + } + pMac->sme.ocb_get_tsf_timer_callback = NULL; + pMac->sme.ocb_get_tsf_timer_context = NULL; + qdf_mem_free(pMsg->bodyptr); + break; + case eWNI_SME_DCC_GET_STATS_RSP: + if (pMac->sme.dcc_get_stats_callback) { + pMac->sme.dcc_get_stats_callback( + pMac->sme.dcc_get_stats_context, + pMsg->bodyptr); + } else { + sms_log(pMac, LOGE, FL( + "Message error. The callback is NULL.")); + } + pMac->sme.dcc_get_stats_callback = NULL; + pMac->sme.dcc_get_stats_context = NULL; + qdf_mem_free(pMsg->bodyptr); + break; + case eWNI_SME_DCC_UPDATE_NDL_RSP: + if (pMac->sme.dcc_update_ndl_callback) { + pMac->sme.dcc_update_ndl_callback( + pMac->sme.dcc_update_ndl_context, + pMsg->bodyptr); + } else { + sms_log(pMac, LOGE, FL( + "Message error. The callback is NULL.")); + } + pMac->sme.dcc_update_ndl_callback = NULL; + pMac->sme.dcc_update_ndl_context = NULL; + qdf_mem_free(pMsg->bodyptr); + break; + case eWNI_SME_DCC_STATS_EVENT: + if (pMac->sme.dcc_stats_event_callback) { + pMac->sme.dcc_stats_event_callback( + pMac->sme.dcc_stats_event_context, + pMsg->bodyptr); + } else { + sms_log(pMac, LOGE, FL( + "Message error. The callback is NULL.")); + } + qdf_mem_free(pMsg->bodyptr); + break; + case eWNI_SME_SET_DUAL_MAC_CFG_RESP: + if (pMsg->bodyptr) { + status = sme_process_dual_mac_config_resp(pMac, + pMsg->bodyptr); + qdf_mem_free(pMsg->bodyptr); + } else { + sms_log(pMac, LOGE, FL("Empty message for %d"), + pMsg->type); + } + case eWNI_SME_SET_THERMAL_LEVEL_IND: + if (pMac->sme.set_thermal_level_cb) + pMac->sme.set_thermal_level_cb(pMac->hHdd, + pMsg->bodyval); + break; + case eWNI_SME_EXT_CHANGE_CHANNEL_IND: + status = sme_extended_change_channel_ind(pMac, pMsg->bodyptr); + qdf_mem_free(pMsg->bodyptr); + break; + case eWNI_SME_SET_ANTENNA_MODE_RESP: + if (pMsg->bodyptr) { + status = sme_process_antenna_mode_resp(pMac, + pMsg->bodyptr); + qdf_mem_free(pMsg->bodyptr); + } else { + sms_log(pMac, LOGE, FL("Empty message for %d"), + pMsg->type); + } + break; + case eWNI_SME_NDP_CONFIRM_IND: + case eWNI_SME_NDP_NEW_PEER_IND: + case eWNI_SME_NDP_INITIATOR_RSP: + case eWNI_SME_NDP_INDICATION: + case eWNI_SME_NDP_RESPONDER_RSP: + case eWNI_SME_NDP_END_RSP: + case eWNI_SME_NDP_END_IND: + case eWNI_SME_NDP_PEER_DEPARTED_IND: + sme_ndp_msg_processor(pMac, pMsg); + break; + case eWNI_SME_LOST_LINK_INFO_IND: + if (pMac->sme.lost_link_info_cb) + pMac->sme.lost_link_info_cb(pMac->hHdd, + (struct sir_lost_link_info *)pMsg->bodyptr); + qdf_mem_free(pMsg->bodyptr); + break; + case eWNI_SME_RSO_CMD_STATUS_IND: + if (pMac->sme.rso_cmd_status_cb) + pMac->sme.rso_cmd_status_cb(pMac->hHdd, pMsg->bodyptr); + qdf_mem_free(pMsg->bodyptr); + break; + + default: + + if ((pMsg->type >= eWNI_SME_MSG_TYPES_BEGIN) + && (pMsg->type <= eWNI_SME_MSG_TYPES_END)) { + /* CSR */ + if (pMsg->bodyptr) { + status = csr_msg_processor(hHal, pMsg->bodyptr); + qdf_mem_free(pMsg->bodyptr); + } else { + sms_log(pMac, LOGE, FL("Empty message for %d"), + pMsg->type); + } + } else { + sms_log(pMac, LOGW, FL("Unknown message type %d"), + pMsg->type); + if (pMsg->bodyptr) + qdf_mem_free(pMsg->bodyptr); + } + } /* switch */ +release_lock: + sme_release_global_lock(&pMac->sme); + return status; +} + +/** + * sme_process_nss_update_resp() - Process nss update response + * @mac: Global MAC pointer + * @msg: nss update response + * + * Processes the nss update response and invokes the HDD + * callback to process further + */ +QDF_STATUS sme_process_nss_update_resp(tpAniSirGlobal mac, uint8_t *msg) +{ + tListElem *entry = NULL; + tSmeCmd *command = NULL; + bool found; + nss_update_cb callback = NULL; + struct sir_beacon_tx_complete_rsp *param; + + param = (struct sir_beacon_tx_complete_rsp *)msg; + if (!param) { + sms_log(mac, LOGE, FL("nss update resp param is NULL")); + /* Not returning. Need to check if active command list + * needs to be freed + */ + } + + entry = csr_ll_peek_head(&mac->sme.smeCmdActiveList, + LL_ACCESS_LOCK); + if (!entry) { + sms_log(mac, LOGE, FL("No cmd found in active list")); + return QDF_STATUS_E_FAILURE; + } + + command = GET_BASE_ADDR(entry, tSmeCmd, Link); + if (!command) { + sms_log(mac, LOGE, FL("Base address is NULL")); + return QDF_STATUS_E_FAILURE; + } + + if (e_sme_command_nss_update != command->command) { + sms_log(mac, LOGE, FL("Command mismatch!")); + return QDF_STATUS_E_FAILURE; + } + + callback = command->u.nss_update_cmd.nss_update_cb; + if (callback) { + if (!param) { + sms_log(mac, LOGE, + FL("Callback failed since nss update params is NULL")); + } else { + sms_log(mac, LOGE, + FL("Calling HDD callback for nss update response")); + callback(command->u.nss_update_cmd.context, + param->tx_status, + param->session_id, + command->u.nss_update_cmd.next_action, + command->u.nss_update_cmd.reason); + } + } else { + sms_log(mac, LOGE, FL("Callback does not exisit")); + } + + found = csr_ll_remove_entry(&mac->sme.smeCmdActiveList, entry, + LL_ACCESS_LOCK); + if (found) { + /* Now put this command back on the avilable command list */ + sme_release_command(mac, command); + } + sme_process_pending_queue(mac); + return QDF_STATUS_SUCCESS; +} + +/* No need to hold the global lock here because this function can only be called */ +/* after sme_stop. */ +void sme_free_msg(tHalHandle hHal, cds_msg_t *pMsg) +{ + if (pMsg) { + if (pMsg->bodyptr) { + qdf_mem_free(pMsg->bodyptr); + } + } + +} + +/*-------------------------------------------------------------------------- + + \brief sme_stop() - Stop all SME modules and put them at idle state + + The function stops each module in SME, PMC, CSR, etc. . Upon + return, all modules are at idle state ready to start. + + This is a synchronous call + \param hHal - The handle returned by mac_open + \param tHalStopType - reason for stopping + + \return QDF_STATUS_SUCCESS - SME is stopped. + + Other status means SME is failed to stop but caller should still + consider SME is stopped. + \sa + + --------------------------------------------------------------------------*/ +QDF_STATUS sme_stop(tHalHandle hHal, tHalStopType stopType) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + QDF_STATUS fail_status = QDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + p2p_stop(hHal); + + status = csr_stop(pMac, stopType); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOGE, + "csr_stop failed during smeStop with status=%d", status); + fail_status = status; + } + + purge_sme_cmd_list(pMac); + + if (!QDF_IS_STATUS_SUCCESS(fail_status)) { + status = fail_status; + } + + pMac->sme.state = SME_STATE_STOP; + + return status; +} + +/*-------------------------------------------------------------------------- + + \brief sme_close() - Release all SME modules and their resources. + + The function release each module in SME, PMC, CSR, etc. . Upon + return, all modules are at closed state. + + No SME APIs can be involved after smeClose except smeOpen. + smeClose must be called before mac_close. + This is a synchronous call + \param hHal - The handle returned by mac_open + + \return QDF_STATUS_SUCCESS - SME is successfully close. + + Other status means SME is failed to be closed but caller still cannot + call any other SME functions except smeOpen. + \sa + + --------------------------------------------------------------------------*/ +QDF_STATUS sme_close(tHalHandle hHal) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + QDF_STATUS fail_status = QDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + if (!pMac) + return QDF_STATUS_E_FAILURE; + + /* Note: pSession will be invalid from here on, do not access */ + status = csr_close(pMac); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOGE, + "csr_close failed during sme close with status=%d", + status); + fail_status = status; + } +#ifndef WLAN_MDM_CODE_REDUCTION_OPT + status = sme_qos_close(pMac); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOGE, + "Qos close failed during sme close with status=%d", + status); + fail_status = status; + } +#endif + status = sme_ps_close(hHal); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOGE, + "sme_ps_close failed during smeClose status=%d", + status); + fail_status = status; + } + + status = rrm_close(hHal); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOGE, + "RRM close failed during sme close with status=%d", + status); + fail_status = status; + } + + sme_p2p_close(hHal); + + free_sme_cmd_list(pMac); + + if (!QDF_IS_STATUS_SUCCESS + (qdf_mutex_destroy(&pMac->sme.lkSmeGlobalLock))) { + fail_status = QDF_STATUS_E_FAILURE; + } + + if (!QDF_IS_STATUS_SUCCESS(fail_status)) { + status = fail_status; + } + + pMac->sme.state = SME_STATE_STOP; + + return status; +} + +/** + * sme_remove_bssid_from_scan_list() - wrapper to remove the bssid from + * scan list + * @hal: hal context. + * @bssid: bssid to be removed + * + * This function remove the given bssid from scan list. + * + * Return: QDF status. + */ +QDF_STATUS sme_remove_bssid_from_scan_list(tHalHandle hal, + tSirMacAddr bssid) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + + status = sme_acquire_global_lock(&mac_ctx->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + csr_remove_bssid_from_scan_list(mac_ctx, bssid); + sme_release_global_lock(&mac_ctx->sme); + } + + return status; +} + +/** + * sme_scan_request() - wrapper function to Request a 11d or full scan from CSR. + * @hal: hal global context + * @session_id: session id + * @scan_req: scan req + * @callback: a callback function that scan calls upon finish, will not + * be called if csr_scan_request returns error + * @ctx: a pointer passed in for the callback + * + * This is a wrapper function to Request a 11d or full scan from CSR. This is + * an asynchronous call + * + * Return: Status of operation + */ +QDF_STATUS sme_scan_request(tHalHandle hal, uint8_t session_id, + tCsrScanRequest *scan_req, + csr_scan_completeCallback callback, void *ctx) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + struct ani_scan_req *scan_msg; + cds_msg_t msg; + uint32_t scan_req_id, scan_count; + + MTRACE(qdf_trace(QDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_MSG_SCAN_REQ, session_id, + scan_req->scanType)); + + if (!CSR_IS_SESSION_VALID(mac_ctx, session_id)) { + sms_log(mac_ctx, LOGE, FL("Invalid session id:%d"), + session_id); + return status; + } + + if (!mac_ctx->scan.fScanEnable) { + sms_log(mac_ctx, LOGE, FL("fScanEnable false")); + return status; + } + + scan_count = csr_ll_count(&mac_ctx->sme.smeScanCmdActiveList); + if (scan_count >= mac_ctx->scan.max_scan_count) { + sms_log(mac_ctx, LOGE, FL("Max scan reached")); + return QDF_STATUS_E_FAILURE; + } + wma_get_scan_id(&scan_req_id); + scan_req->scan_id = scan_req_id; + + status = sme_acquire_global_lock(&mac_ctx->sme); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sms_log(mac_ctx, LOGE, FL("Unable to acquire lock")); + return status; + } + sms_log(mac_ctx, LOG1, FL(" called")); + scan_msg = qdf_mem_malloc(sizeof(struct ani_scan_req)); + if (NULL == scan_msg) { + sms_log(mac_ctx, LOGE, + " scan_req: failed to allocate mem for msg"); + sme_release_global_lock(&mac_ctx->sme); + return QDF_STATUS_E_NOMEM; + } + scan_msg->msg_type = eWNI_SME_SCAN_CMD; + scan_msg->msg_len = (uint16_t) sizeof(struct ani_scan_req); + scan_msg->session_id = session_id; + scan_msg->callback = callback; + scan_msg->ctx = ctx; + scan_msg->scan_param = qdf_mem_malloc(sizeof(tCsrScanRequest)); + if (NULL == scan_msg->scan_param) { + sms_log(mac_ctx, LOGE, + "scan_req:failed to allocate mem for scanreq"); + sme_release_global_lock(&mac_ctx->sme); + qdf_mem_free(scan_msg); + return QDF_STATUS_E_NOMEM; + } + csr_scan_copy_request(mac_ctx, scan_msg->scan_param, scan_req); + msg.type = eWNI_SME_SCAN_CMD; + msg.bodyptr = scan_msg; + msg.reserved = 0; + msg.bodyval = 0; + if (QDF_STATUS_SUCCESS != + cds_mq_post_message(CDS_MQ_ID_SME, &msg)) { + sms_log(mac_ctx, LOGE, + " sme_scan_req failed to post msg"); + csr_scan_free_request(mac_ctx, scan_msg->scan_param); + qdf_mem_free(scan_msg->scan_param); + qdf_mem_free(scan_msg); + status = QDF_STATUS_E_FAILURE; + } + sme_release_global_lock(&mac_ctx->sme); + return status; +} + +/* --------------------------------------------------------------------------- + \fn sme_scan_get_result + \brief a wrapper function to request scan results from CSR. + This is a synchronous call + \param pFilter - If pFilter is NULL, all cached results are returned + \param phResult - an object for the result. + \return QDF_STATUS + ---------------------------------------------------------------------------*/ +QDF_STATUS sme_scan_get_result(tHalHandle hHal, uint8_t sessionId, + tCsrScanResultFilter *pFilter, + tScanResultHandle *phResult) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + MTRACE(qdf_trace(QDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_MSG_SCAN_GET_RESULTS, sessionId, + 0)); + sms_log(pMac, LOG2, FL("enter")); + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + status = csr_scan_get_result(hHal, pFilter, phResult); + sme_release_global_lock(&pMac->sme); + } + sms_log(pMac, LOG2, FL("exit status %d"), status); + + return status; +} + +/** + * sme_get_ap_channel_from_scan_cache() - a wrapper function to get AP's + * channel id from CSR by filtering the + * result which matches our roam profile. + * @profile: SAP adapter + * @ap_chnl_id: pointer to channel id of SAP. Fill the value after finding the + * best ap from scan cache. + * + * This function is written to get AP's channel id from CSR by filtering + * the result which matches our roam profile. This is a synchronous call. + * + * Return: QDF_STATUS. + */ +QDF_STATUS sme_get_ap_channel_from_scan_cache(tHalHandle hal_handle, + tCsrRoamProfile *profile, + tScanResultHandle *scan_cache, + uint8_t *ap_chnl_id) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal_handle); + tCsrScanResultFilter *scan_filter = NULL; + tScanResultHandle filtered_scan_result = NULL; + tSirBssDescription first_ap_profile; + + if (NULL == mac_ctx) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("mac_ctx is NULL")); + return QDF_STATUS_E_FAILURE; + } + scan_filter = qdf_mem_malloc(sizeof(tCsrScanResultFilter)); + if (NULL == scan_filter) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("scan_filter mem alloc failed")); + return QDF_STATUS_E_FAILURE; + } else { + qdf_mem_set(&first_ap_profile, sizeof(tSirBssDescription), 0); + + if (NULL == profile) { + scan_filter->EncryptionType.numEntries = 1; + scan_filter->EncryptionType.encryptionType[0] + = eCSR_ENCRYPT_TYPE_NONE; + } else { + /* Here is the profile we need to connect to */ + status = csr_roam_prepare_filter_from_profile(mac_ctx, + profile, + scan_filter); + } + + if (QDF_STATUS_SUCCESS == status) { + /* Save the WPS info */ + if (NULL != profile) { + scan_filter->bWPSAssociation = + profile->bWPSAssociation; + scan_filter->bOSENAssociation = + profile->bOSENAssociation; + } else { + scan_filter->bWPSAssociation = 0; + scan_filter->bOSENAssociation = 0; + } + } else { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Preparing the profile filter failed")); + qdf_mem_free(scan_filter); + return QDF_STATUS_E_FAILURE; + } + } + status = sme_acquire_global_lock(&mac_ctx->sme); + if (QDF_STATUS_SUCCESS == status) { + status = csr_scan_get_result(hal_handle, scan_filter, + &filtered_scan_result); + if (QDF_STATUS_SUCCESS == status) { + csr_get_bssdescr_from_scan_handle(filtered_scan_result, + &first_ap_profile); + *scan_cache = filtered_scan_result; + if (0 != first_ap_profile.channelId) { + *ap_chnl_id = first_ap_profile.channelId; + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_ERROR, + FL("Found best AP & its on chnl[%d]"), + first_ap_profile.channelId); + } else { + /* + * This means scan result is empty + * so set the channel to zero, caller should + * take of zero channel id case. + */ + *ap_chnl_id = 0; + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_ERROR, + FL("Scan is empty, set chnl to 0")); + status = QDF_STATUS_E_FAILURE; + } + } else { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Failed to get scan get result")); + status = QDF_STATUS_E_FAILURE; + } + csr_free_scan_filter(mac_ctx, scan_filter); + sme_release_global_lock(&mac_ctx->sme); + } else { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Aquiring lock failed")); + csr_free_scan_filter(mac_ctx, scan_filter); + status = QDF_STATUS_E_FAILURE; + } + qdf_mem_free(scan_filter); + return status; +} + +/** + * sme_store_joinreq_param() - This function will pass station's join + * request to store to csr. + * @hal_handle: pointer to hal context. + * @profile: pointer to station's roam profile. + * @scan_cache: pointer to station's scan cache. + * @roam_id: reference to roam_id variable being passed. + * @session_id: station's session id. + * + * This function will pass station's join request further down to csr + * to store it. this stored parameter will be used later. + * + * Return: true or false based on function's overall success. + **/ +bool sme_store_joinreq_param(tHalHandle hal_handle, + tCsrRoamProfile *profile, + tScanResultHandle scan_cache, + uint32_t *roam_id, + uint32_t session_id) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal_handle); + QDF_STATUS status = QDF_STATUS_E_FAILURE; + bool ret_status = true; + + MTRACE(qdf_trace(QDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_STORE_JOIN_REQ, + session_id, 0)); + status = sme_acquire_global_lock(&mac_ctx->sme); + if (QDF_STATUS_SUCCESS == status) { + if (false == csr_store_joinreq_param(mac_ctx, profile, + scan_cache, roam_id, session_id)) { + ret_status = false; + } + sme_release_global_lock(&mac_ctx->sme); + } else { + ret_status = false; + } + + return ret_status; +} + +/** + * sme_clear_joinreq_param() - This function will pass station's clear + * the join request to csr. + * @hal_handle: pointer to hal context. + * @session_id: station's session id. + * + * This function will pass station's clear join request further down to csr + * to cleanup. + * + * Return: true or false based on function's overall success. + **/ +bool sme_clear_joinreq_param(tHalHandle hal_handle, + uint32_t session_id) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal_handle); + QDF_STATUS status = QDF_STATUS_E_FAILURE; + bool ret_status = true; + + MTRACE(qdf_trace(QDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_CLEAR_JOIN_REQ, + session_id, 0)); + status = sme_acquire_global_lock(&mac_ctx->sme); + if (QDF_STATUS_SUCCESS == status) { + if (false == csr_clear_joinreq_param(mac_ctx, + session_id)) { + ret_status = false; + } + sme_release_global_lock(&mac_ctx->sme); + } else { + ret_status = false; + } + + return ret_status; +} + +/** + * sme_issue_stored_joinreq() - This function will issues station's stored + * the join request to csr. + * @hal_handle: pointer to hal context. + * @roam_id: reference to roam_id variable being passed. + * @session_id: station's session id. + * + * This function will issue station's stored join request further down to csr + * to proceed forward. + * + * Return: QDF_STATUS_SUCCESS or QDF_STATUS_E_FAILURE. + **/ +QDF_STATUS sme_issue_stored_joinreq(tHalHandle hal_handle, + uint32_t *roam_id, + uint32_t session_id) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal_handle); + QDF_STATUS status = QDF_STATUS_E_FAILURE; + QDF_STATUS ret_status = QDF_STATUS_SUCCESS; + + MTRACE(qdf_trace(QDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_ISSUE_JOIN_REQ, + session_id, 0)); + status = sme_acquire_global_lock(&mac_ctx->sme); + if (QDF_STATUS_SUCCESS == status) { + if (QDF_STATUS_SUCCESS != csr_issue_stored_joinreq(mac_ctx, + roam_id, + session_id)) { + ret_status = QDF_STATUS_E_FAILURE; + } + sme_release_global_lock(&mac_ctx->sme); + } else { + csr_clear_joinreq_param(mac_ctx, session_id); + ret_status = QDF_STATUS_E_FAILURE; + } + return ret_status; +} + +/* --------------------------------------------------------------------------- + \fn sme_scan_flush_result + \brief a wrapper function to request CSR to clear scan results. + This is a synchronous call + \return QDF_STATUS + ---------------------------------------------------------------------------*/ +QDF_STATUS sme_scan_flush_result(tHalHandle hHal) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + MTRACE(qdf_trace(QDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_MSG_SCAN_FLUSH_RESULTS, + 0, 0)); + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + status = csr_scan_flush_result(hHal); + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +/* --------------------------------------------------------------------------- + \fn sme_filter_scan_results + \brief a wrapper function to request CSR to clear scan results. + This is a synchronous call + \param tHalHandle - HAL context handle + \param sessionId - session id + \return QDF_STATUS + ---------------------------------------------------------------------------*/ +QDF_STATUS sme_filter_scan_results(tHalHandle hHal, uint8_t sessionId) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + MTRACE(qdf_trace(QDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_MSG_SCAN_FLUSH_RESULTS, + sessionId, 0)); + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + csr_scan_filter_results(pMac); + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +QDF_STATUS sme_scan_flush_p2p_result(tHalHandle hHal, uint8_t sessionId) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + MTRACE(qdf_trace(QDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_MSG_SCAN_FLUSH_P2PRESULTS, + sessionId, 0)); + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + status = csr_scan_flush_selective_result(hHal, true); + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +/* --------------------------------------------------------------------------- + \fn sme_scan_result_get_first + \brief a wrapper function to request CSR to returns the first element of + scan result. + This is a synchronous call + \param hScanResult - returned from csr_scan_get_result + \return tCsrScanResultInfo * - NULL if no result + ---------------------------------------------------------------------------*/ +tCsrScanResultInfo *sme_scan_result_get_first(tHalHandle hHal, + tScanResultHandle hScanResult) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + tCsrScanResultInfo *pRet = NULL; + + MTRACE(qdf_trace(QDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_MSG_SCAN_RESULT_GETFIRST, + NO_SESSION, 0)); + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + pRet = csr_scan_result_get_first(pMac, hScanResult); + sme_release_global_lock(&pMac->sme); + } + + return pRet; +} + +/* --------------------------------------------------------------------------- + \fn sme_scan_result_get_next + \brief a wrapper function to request CSR to returns the next element of + scan result. It can be called without calling csr_scan_result_get_first + first + This is a synchronous call + \param hScanResult - returned from csr_scan_get_result + \return Null if no result or reach the end + ---------------------------------------------------------------------------*/ +tCsrScanResultInfo *sme_scan_result_get_next(tHalHandle hHal, + tScanResultHandle hScanResult) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + tCsrScanResultInfo *pRet = NULL; + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + pRet = csr_scan_result_get_next(pMac, hScanResult); + sme_release_global_lock(&pMac->sme); + } + + return pRet; +} + +/* --------------------------------------------------------------------------- + \fn sme_scan_result_purge + \brief a wrapper function to request CSR to remove all items(tCsrScanResult) + in the list and free memory for each item + This is a synchronous call + \param hScanResult - returned from csr_scan_get_result. hScanResult is + considered gone by + calling this function and even before this function reutrns. + \return QDF_STATUS + ---------------------------------------------------------------------------*/ +QDF_STATUS sme_scan_result_purge(tHalHandle hHal, tScanResultHandle hScanResult) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + MTRACE(qdf_trace(QDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_MSG_SCAN_RESULT_PURGE, + NO_SESSION, 0)); + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + status = csr_scan_result_purge(hHal, hScanResult); + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +/* --------------------------------------------------------------------------- + \fn sme_scan_get_pmkid_candidate_list + \brief a wrapper function to return the PMKID candidate list + This is a synchronous call + \param pPmkidList - caller allocated buffer point to an array of + tPmkidCandidateInfo + \param pNumItems - pointer to a variable that has the number of + tPmkidCandidateInfo allocated when retruning, this is + either the number needed or number of items put into + pPmkidList + \return QDF_STATUS - when fail, it usually means the buffer allocated is not + big enough and pNumItems + has the number of tPmkidCandidateInfo. + \Note: pNumItems is a number of tPmkidCandidateInfo, + not sizeof(tPmkidCandidateInfo) * something + ---------------------------------------------------------------------------*/ +QDF_STATUS sme_scan_get_pmkid_candidate_list(tHalHandle hHal, uint8_t sessionId, + tPmkidCandidateInfo *pPmkidList, + uint32_t *pNumItems) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + status = + csr_scan_get_pmkid_candidate_list(pMac, sessionId, + pPmkidList, + pNumItems); + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +eCsrPhyMode sme_get_phy_mode(tHalHandle hHal) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + return pMac->roam.configParam.phyMode; +} + +/* --------------------------------------------------------------------------- + \fn sme_get_channel_bonding_mode5_g + \brief get the channel bonding mode for 5G band + \param hHal - HAL handle + \return channel bonding mode for 5G + ---------------------------------------------------------------------------*/ +uint32_t sme_get_channel_bonding_mode5_g(tHalHandle hHal) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + tSmeConfigParams smeConfig; + + sme_get_config_param(pMac, &smeConfig); + + return smeConfig.csrConfig.channelBondingMode5GHz; +} + +/* --------------------------------------------------------------------------- + \fn sme_get_channel_bonding_mode24_g + \brief get the channel bonding mode for 2.4G band + \param hHal - HAL handle + \return channel bonding mode for 2.4G + ---------------------------------------------------------------------------*/ +uint32_t sme_get_channel_bonding_mode24_g(tHalHandle hHal) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + tSmeConfigParams smeConfig; + + sme_get_config_param(pMac, &smeConfig); + + return smeConfig.csrConfig.channelBondingMode24GHz; +} + +/* --------------------------------------------------------------------------- + \fn sme_roam_connect + \brief a wrapper function to request CSR to inititiate an association + This is an asynchronous call. + \param sessionId - the sessionId returned by sme_open_session. + \param pProfile - description of the network to which to connect + \param hBssListIn - a list of BSS descriptor to roam to. It is returned + from csr_scan_get_result + \param pRoamId - to get back the request ID + \return QDF_STATUS + ---------------------------------------------------------------------------*/ +QDF_STATUS sme_roam_connect(tHalHandle hHal, uint8_t sessionId, + tCsrRoamProfile *pProfile, uint32_t *pRoamId) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + if (!pMac) { + return QDF_STATUS_E_FAILURE; + } + + MTRACE(qdf_trace(QDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_MSG_CONNECT, sessionId, 0)); + sms_log(pMac, LOG2, FL("enter")); + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + if (CSR_IS_SESSION_VALID(pMac, sessionId)) { + status = + csr_roam_connect(pMac, sessionId, pProfile, + pRoamId); + } else { + sms_log(pMac, LOGE, FL("invalid sessionID %d"), + sessionId); + status = QDF_STATUS_E_INVAL; + } + sme_release_global_lock(&pMac->sme); + } else { + sms_log(pMac, LOGE, FL("sme_acquire_global_lock failed")); + } + + return status; +} + +/* --------------------------------------------------------------------------- + + \fn sme_set_phy_mode + + \brief Changes the PhyMode. + + \param hHal - The handle returned by mac_open. + + \param phyMode new phyMode which is to set + + \return QDF_STATUS SUCCESS. + + -------------------------------------------------------------------------------*/ +QDF_STATUS sme_set_phy_mode(tHalHandle hHal, eCsrPhyMode phyMode) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + if (NULL == pMac) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: invalid context", __func__); + return QDF_STATUS_E_FAILURE; + } + + pMac->roam.configParam.phyMode = phyMode; + pMac->roam.configParam.uCfgDot11Mode = + csr_get_cfg_dot11_mode_from_csr_phy_mode(NULL, + pMac->roam.configParam.phyMode, + pMac->roam.configParam. + ProprietaryRatesEnabled); + + return QDF_STATUS_SUCCESS; +} + +/* --------------------------------------------------------------------------- + \fn sme_roam_reassoc + \brief a wrapper function to request CSR to inititiate a re-association + \param pProfile - can be NULL to join the currently connected AP. In that + case modProfileFields should carry the modified field(s) which could trigger + reassoc + \param modProfileFields - fields which are part of tCsrRoamConnectedProfile + that might need modification dynamically once STA is up & running and this + could trigger a reassoc + \param pRoamId - to get back the request ID + \return QDF_STATUS + -------------------------------------------------------------------------------*/ +QDF_STATUS sme_roam_reassoc(tHalHandle hHal, uint8_t sessionId, + tCsrRoamProfile *pProfile, + tCsrRoamModifyProfileFields modProfileFields, + uint32_t *pRoamId, bool fForce) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + MTRACE(qdf_trace(QDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_ROAM_REASSOC, sessionId, 0)); + sms_log(pMac, LOG2, FL("enter")); + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + if (CSR_IS_SESSION_VALID(pMac, sessionId)) { + if ((NULL == pProfile) && (fForce == 1)) { + status = + csr_reassoc(pMac, sessionId, + &modProfileFields, pRoamId, + fForce); + } else { + status = + csr_roam_reassoc(pMac, sessionId, pProfile, + modProfileFields, pRoamId); + } + } else { + status = QDF_STATUS_E_INVAL; + } + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +/* --------------------------------------------------------------------------- + \fn sme_roam_connect_to_last_profile + \brief a wrapper function to request CSR to disconnect and reconnect with + the same profile + This is an asynchronous call. + \return QDF_STATUS. It returns fail if currently connected + ---------------------------------------------------------------------------*/ +QDF_STATUS sme_roam_connect_to_last_profile(tHalHandle hHal, uint8_t sessionId) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + MTRACE(qdf_trace(QDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_ROAM_GET_CONNECTPROFILE, + sessionId, 0)); + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + if (CSR_IS_SESSION_VALID(pMac, sessionId)) { + status = csr_roam_connect_to_last_profile(pMac, sessionId); + } else { + status = QDF_STATUS_E_INVAL; + } + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +/* --------------------------------------------------------------------------- + \fn sme_roam_disconnect + \brief a wrapper function to request CSR to disconnect from a network + This is an asynchronous call. + \param reason -- To indicate the reason for disconnecting. Currently, only + eCSR_DISCONNECT_REASON_MIC_ERROR is meanful. + \return QDF_STATUS + ---------------------------------------------------------------------------*/ +QDF_STATUS sme_roam_disconnect(tHalHandle hHal, uint8_t sessionId, + eCsrRoamDisconnectReason reason) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + MTRACE(qdf_trace(QDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_ROAM_DISCONNECT, sessionId, + reason)); + sms_log(pMac, LOG2, FL("enter")); + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + if (CSR_IS_SESSION_VALID(pMac, sessionId)) { + status = csr_roam_disconnect(pMac, sessionId, reason); + } else { + status = QDF_STATUS_E_INVAL; + } + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +/* sme_dhcp_done_ind() - send dhcp done ind + * @hal: hal context + * @session_id: session id + * + * Return: void. + */ +void sme_dhcp_done_ind(tHalHandle hal, uint8_t session_id) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + tCsrRoamSession *session; + + if (!mac_ctx) + return; + + session = CSR_GET_SESSION(mac_ctx, session_id); + if (!session) { + sms_log(mac_ctx, LOGE, + FL("session %d not found"), session_id); + return; + } + session->dhcp_done = true; +} + +/* --------------------------------------------------------------------------- + \fn sme_roam_stop_bss + \brief To stop BSS for Soft AP. This is an asynchronous API. + \param hHal - Global structure + \param sessionId - sessionId of SoftAP + \return QDF_STATUS SUCCESS Roam callback will be called to indicate actual results + -------------------------------------------------------------------------------*/ +QDF_STATUS sme_roam_stop_bss(tHalHandle hHal, uint8_t sessionId) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + sms_log(pMac, LOG2, FL("enter")); + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + if (CSR_IS_SESSION_VALID(pMac, sessionId)) { + status = csr_roam_issue_stop_bss_cmd(pMac, sessionId, true); + } else { + status = QDF_STATUS_E_INVAL; + } + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +/** + * sme_roam_disconnect_sta() - disassociate a station + * @hHal: Global structure + * @sessionId: SessionId of SoftAP + * @p_del_sta_params: Pointer to parameters of the station to disassoc + * + * To disassociate a station. This is an asynchronous API. + * + * Return: QDF_STATUS_SUCCESS on success.Roam callback will + * be called to indicate actual result. + */ +QDF_STATUS sme_roam_disconnect_sta(tHalHandle hHal, uint8_t sessionId, + struct tagCsrDelStaParams *p_del_sta_params) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + if (NULL == pMac) { + QDF_ASSERT(0); + return status; + } + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + if (CSR_IS_SESSION_VALID(pMac, sessionId)) { + status = csr_roam_issue_disassociate_sta_cmd(pMac, + sessionId, p_del_sta_params); + } else { + status = QDF_STATUS_E_INVAL; + } + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +/** + * sme_roam_deauth_sta() - deauthenticate a station + * @hHal: Global structure + * @sessionId: SessionId of SoftAP + * @pDelStaParams: Pointer to parameters of the station to deauthenticate + * + * To disassociate a station. This is an asynchronous API. + * + * Return: QDF_STATUS_SUCCESS on success or another QDF_STATUS error + * code on error. Roam callback will be called to indicate actual + * result + */ +QDF_STATUS sme_roam_deauth_sta(tHalHandle hHal, uint8_t sessionId, + struct tagCsrDelStaParams *pDelStaParams) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + if (NULL == pMac) { + QDF_ASSERT(0); + return status; + } + + MTRACE(qdf_trace(QDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_MSG_DEAUTH_STA, + sessionId, pDelStaParams->reason_code)); + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + if (CSR_IS_SESSION_VALID(pMac, sessionId)) { + status = + csr_roam_issue_deauth_sta_cmd(pMac, sessionId, + pDelStaParams); + } else { + status = QDF_STATUS_E_INVAL; + } + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +/* --------------------------------------------------------------------------- + \fn sme_roam_tkip_counter_measures + \brief To start or stop TKIP counter measures. This is an asynchronous API. + \param sessionId - sessionId of SoftAP + \param pPeerMacAddr - Caller allocated memory filled with peer MAC address (6 bytes) + \return QDF_STATUS + -------------------------------------------------------------------------------*/ +QDF_STATUS sme_roam_tkip_counter_measures(tHalHandle hHal, uint8_t sessionId, + bool bEnable) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + if (NULL == pMac) { + QDF_ASSERT(0); + return status; + } + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + if (CSR_IS_SESSION_VALID(pMac, sessionId)) { + status = + csr_roam_issue_tkip_counter_measures(pMac, sessionId, + bEnable); + } else { + status = QDF_STATUS_E_INVAL; + } + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +/* --------------------------------------------------------------------------- + \fn sme_roam_get_associated_stas + \brief To probe the list of associated stations from various modules + of CORE stack. + \This is an asynchronous API. + \param sessionId - sessionId of SoftAP + \param modId - Module from whom list of associtated stations is + to be probed. If an invalid module is passed then + by default QDF_MODULE_ID_PE will be probed. + \param pUsrContext - Opaque HDD context + \param pfnSapEventCallback - Sap event callback in HDD + \param pAssocBuf - Caller allocated memory to be filled with associatd + stations info + \return QDF_STATUS + -------------------------------------------------------------------------------*/ +QDF_STATUS sme_roam_get_associated_stas(tHalHandle hHal, uint8_t sessionId, + QDF_MODULE_ID modId, void *pUsrContext, + void *pfnSapEventCallback, + uint8_t *pAssocStasBuf) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + if (NULL == pMac) { + QDF_ASSERT(0); + return status; + } + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + if (CSR_IS_SESSION_VALID(pMac, sessionId)) { + status = + csr_roam_get_associated_stas(pMac, sessionId, modId, + pUsrContext, + pfnSapEventCallback, + pAssocStasBuf); + } else { + status = QDF_STATUS_E_INVAL; + } + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +/* --------------------------------------------------------------------------- + \fn sme_roam_get_wps_session_overlap + \brief To get the WPS PBC session overlap information. + \This is an asynchronous API. + \param sessionId - sessionId of SoftAP + \param pUsrContext - Opaque HDD context + \param pfnSapEventCallback - Sap event callback in HDD + \pRemoveMac - pointer to Mac address which needs to be removed from session + \return QDF_STATUS + -------------------------------------------------------------------------------*/ +QDF_STATUS sme_roam_get_wps_session_overlap(tHalHandle hHal, uint8_t sessionId, + void *pUsrContext, void + *pfnSapEventCallback, + struct qdf_mac_addr pRemoveMac) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + if (NULL == pMac) { + QDF_ASSERT(0); + return status; + } + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + if (CSR_IS_SESSION_VALID(pMac, sessionId)) { + status = + csr_roam_get_wps_session_overlap(pMac, sessionId, + pUsrContext, + pfnSapEventCallback, + pRemoveMac); + } else { + status = QDF_STATUS_E_INVAL; + } + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +/* --------------------------------------------------------------------------- + \fn sme_roam_get_connect_state + \brief a wrapper function to request CSR to return the current connect state + of Roaming + This is a synchronous call. + \return QDF_STATUS + ---------------------------------------------------------------------------*/ +QDF_STATUS sme_roam_get_connect_state(tHalHandle hHal, uint8_t sessionId, + eCsrConnectState *pState) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + if (CSR_IS_SESSION_VALID(pMac, sessionId)) { + status = + csr_roam_get_connect_state(pMac, sessionId, pState); + } else { + status = QDF_STATUS_E_INVAL; + } + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +/* --------------------------------------------------------------------------- + \fn sme_roam_get_connect_profile + \brief a wrapper function to request CSR to return the current connect + profile. Caller must call csr_roam_free_connect_profile after it is done + and before reuse for another csr_roam_get_connect_profile call. + This is a synchronous call. + \param pProfile - pointer to a caller allocated structure + tCsrRoamConnectedProfile + \return QDF_STATUS. Failure if not connected + ---------------------------------------------------------------------------*/ +QDF_STATUS sme_roam_get_connect_profile(tHalHandle hHal, uint8_t sessionId, + tCsrRoamConnectedProfile *pProfile) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + MTRACE(qdf_trace(QDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_ROAM_GET_CONNECTPROFILE, + sessionId, 0)); + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + if (CSR_IS_SESSION_VALID(pMac, sessionId)) { + status = + csr_roam_get_connect_profile(pMac, sessionId, pProfile); + } else { + status = QDF_STATUS_E_INVAL; + } + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +/** + * sme_roam_free_connect_profile - a wrapper function to request CSR to free and + * reinitialize the profile returned previously by csr_roam_get_connect_profile. + * + * @profile - pointer to a caller allocated structure tCsrRoamConnectedProfile + * + * Return: none + */ +void sme_roam_free_connect_profile(tCsrRoamConnectedProfile *profile) +{ + MTRACE(qdf_trace(QDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_ROAM_FREE_CONNECTPROFILE, + NO_SESSION, 0)); + csr_roam_free_connect_profile(profile); +} + +/* --------------------------------------------------------------------------- + \fn sme_roam_set_pmkid_cache + \brief a wrapper function to request CSR to return the PMKID candidate list + This is a synchronous call. + \param pPMKIDCache - caller allocated buffer point to an array of + tPmkidCacheInfo + \param numItems - a variable that has the number of tPmkidCacheInfo + allocated when retruning, this is either the number needed + or number of items put into pPMKIDCache + \param update_entire_cache - this bool value specifies if the entire pmkid + cache should be overwritten or should it be + updated entry by entry. + \return QDF_STATUS - when fail, it usually means the buffer allocated is not + big enough and pNumItems has the number of + tPmkidCacheInfo. + \Note: pNumItems is a number of tPmkidCacheInfo, + not sizeof(tPmkidCacheInfo) * something + ---------------------------------------------------------------------------*/ +QDF_STATUS sme_roam_set_pmkid_cache(tHalHandle hHal, uint8_t sessionId, + tPmkidCacheInfo *pPMKIDCache, + uint32_t numItems, bool update_entire_cache) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + MTRACE(qdf_trace(QDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_ROAM_SET_PMKIDCACHE, sessionId, + numItems)); + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + if (CSR_IS_SESSION_VALID(pMac, sessionId)) { + status = + csr_roam_set_pmkid_cache(pMac, sessionId, pPMKIDCache, + numItems, update_entire_cache); + } else { + status = QDF_STATUS_E_INVAL; + } + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +QDF_STATUS sme_roam_del_pmkid_from_cache(tHalHandle hHal, uint8_t sessionId, + const uint8_t *pBSSId, bool flush_cache) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + MTRACE(qdf_trace(QDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_ROAM_DEL_PMKIDCACHE, + sessionId, flush_cache)); + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + if (CSR_IS_SESSION_VALID(pMac, sessionId)) { + status = csr_roam_del_pmkid_from_cache(pMac, sessionId, + pBSSId, flush_cache); + } else { + status = QDF_STATUS_E_INVAL; + } + sme_release_global_lock(&pMac->sme); + } + return status; +} + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +/* --------------------------------------------------------------------------- + * \fn sme_roam_set_psk_pmk + * \brief a wrapper function to request CSR to save PSK/PMK + * This is a synchronous call. + * \param hHal - Global structure + * \param sessionId - SME sessionId + * \param pPSK_PMK - pointer to an array of Psk[]/Pmk + * \param pmk_len - Length could be only 16 bytes in case if LEAP + * connections. Need to pass this information to + * firmware. + * \return QDF_STATUS -status whether PSK/PMK is set or not + *--------------------------------------------------------------------------- + */ +QDF_STATUS sme_roam_set_psk_pmk(tHalHandle hHal, uint8_t sessionId, + uint8_t *pPSK_PMK, size_t pmk_len) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + if (CSR_IS_SESSION_VALID(pMac, sessionId)) { + status = + csr_roam_set_psk_pmk(pMac, sessionId, pPSK_PMK, + pmk_len); + } else { + status = QDF_STATUS_E_INVAL; + } + sme_release_global_lock(&pMac->sme); + } + return status; +} +#endif +/* --------------------------------------------------------------------------- + \fn sme_roam_get_security_req_ie + \brief a wrapper function to request CSR to return the WPA or RSN or WAPI IE CSR + passes to PE to JOIN request or START_BSS request + This is a synchronous call. + \param pLen - caller allocated memory that has the length of pBuf as input. + Upon returned, *pLen has the needed or IE length in pBuf. + \param pBuf - Caller allocated memory that contain the IE field, if any, + upon return + \param secType - Specifies whether looking for WPA/WPA2/WAPI IE + \return QDF_STATUS - when fail, it usually means the buffer allocated is not + big enough + ---------------------------------------------------------------------------*/ +QDF_STATUS sme_roam_get_security_req_ie(tHalHandle hHal, uint8_t sessionId, + uint32_t *pLen, uint8_t *pBuf, + eCsrSecurityType secType) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + if (CSR_IS_SESSION_VALID(pMac, sessionId)) { + status = + csr_roam_get_wpa_rsn_req_ie(hHal, sessionId, pLen, pBuf); + } else { + status = QDF_STATUS_E_INVAL; + } + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +/* --------------------------------------------------------------------------- + \fn sme_roam_get_security_rsp_ie + \brief a wrapper function to request CSR to return the WPA or RSN or + WAPI IE from the beacon or probe rsp if connected + This is a synchronous call. + \param pLen - caller allocated memory that has the length of pBuf as input. + Upon returned, *pLen has the needed or IE length in pBuf. + \param pBuf - Caller allocated memory that contain the IE field, if any, + upon return + \param secType - Specifies whether looking for WPA/WPA2/WAPI IE + \return QDF_STATUS - when fail, it usually means the buffer allocated is not + big enough + ---------------------------------------------------------------------------*/ +QDF_STATUS sme_roam_get_security_rsp_ie(tHalHandle hHal, uint8_t sessionId, + uint32_t *pLen, uint8_t *pBuf, + eCsrSecurityType secType) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + if (CSR_IS_SESSION_VALID(pMac, sessionId)) { + status = + csr_roam_get_wpa_rsn_rsp_ie(pMac, sessionId, pLen, pBuf); + } else { + status = QDF_STATUS_E_INVAL; + } + sme_release_global_lock(&pMac->sme); + } + + return status; + +} + +/* --------------------------------------------------------------------------- + \fn sme_roam_get_num_pmkid_cache + \brief a wrapper function to request CSR to return number of PMKID cache + entries + This is a synchronous call. + \return uint32_t - the number of PMKID cache entries + ---------------------------------------------------------------------------*/ +uint32_t sme_roam_get_num_pmkid_cache(tHalHandle hHal, uint8_t sessionId) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + uint32_t numPmkidCache = 0; + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + if (CSR_IS_SESSION_VALID(pMac, sessionId)) { + numPmkidCache = + csr_roam_get_num_pmkid_cache(pMac, sessionId); + status = QDF_STATUS_SUCCESS; + } else { + status = QDF_STATUS_E_INVAL; + } + sme_release_global_lock(&pMac->sme); + } + + return numPmkidCache; +} + +/* --------------------------------------------------------------------------- + \fn sme_roam_get_pmkid_cache + \brief a wrapper function to request CSR to return PMKID cache from CSR + This is a synchronous call. + \param pNum - caller allocated memory that has the space of the number of + pBuf tPmkidCacheInfo as input. Upon returned, *pNum has the + needed or actually number in tPmkidCacheInfo. + \param pPmkidCache - Caller allocated memory that contains PMKID cache, if + any, upon return + \return QDF_STATUS - when fail, it usually means the buffer allocated is not + big enough + ---------------------------------------------------------------------------*/ +QDF_STATUS sme_roam_get_pmkid_cache(tHalHandle hHal, uint8_t sessionId, + uint32_t *pNum, tPmkidCacheInfo *pPmkidCache) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + MTRACE(qdf_trace(QDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_ROAM_GET_PMKIDCACHE, sessionId, + 0)); + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + if (CSR_IS_SESSION_VALID(pMac, sessionId)) { + status = + csr_roam_get_pmkid_cache(pMac, sessionId, pNum, + pPmkidCache); + } else { + status = QDF_STATUS_E_INVAL; + } + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +/* --------------------------------------------------------------------------- + \fn sme_get_config_param + \brief a wrapper function that HDD calls to get the global settings + currently maintained by CSR. + This is a synchronous call. + \param pParam - caller allocated memory + \return QDF_STATUS + ---------------------------------------------------------------------------*/ +QDF_STATUS sme_get_config_param(tHalHandle hHal, tSmeConfigParams *pParam) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + MTRACE(qdf_trace(QDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_GET_CONFIGPARAM, NO_SESSION, 0)); + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + status = csr_get_config_param(pMac, &pParam->csrConfig); + if (status != QDF_STATUS_SUCCESS) { + sms_log(pMac, LOGE, "%s csr_get_config_param failed", + __func__); + sme_release_global_lock(&pMac->sme); + return status; + } + qdf_mem_copy(&pParam->rrmConfig, + &pMac->rrm.rrmSmeContext.rrmConfig, + sizeof(pMac->rrm.rrmSmeContext.rrmConfig)); + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +/** + * sme_cfg_set_int() - Sets the cfg parameter value. + * @hal: Handle to hal. + * @cfg_id: Configuration parameter ID. + * @value: value to be saved in the cfg parameter. + * + * This function sets the string value in cfg parameter. + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_cfg_set_int(tHalHandle hal, uint16_t cfg_id, uint32_t value) +{ + tpAniSirGlobal pmac = PMAC_STRUCT(hal); + QDF_STATUS status = QDF_STATUS_SUCCESS; + + if (eSIR_SUCCESS != cfg_set_int(pmac, cfg_id, value)) + status = QDF_STATUS_E_FAILURE; + + return status; +} + +/** + * sme_cfg_set_str() - Sets the cfg parameter string. + * @hal: Handle to hal. + * @cfg_id: Configuration parameter ID. + * @str: Pointer to the string buffer. + * @length: Length of the string. + * + * This function sets the string value in cfg parameter. + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_cfg_set_str(tHalHandle hal, uint16_t cfg_id, uint8_t *str, + uint32_t length) +{ + tpAniSirGlobal pmac = PMAC_STRUCT(hal); + QDF_STATUS status = QDF_STATUS_SUCCESS; + + if (eSIR_SUCCESS != cfg_set_str(pmac, cfg_id, str, length)) + status = QDF_STATUS_E_FAILURE; + + return status; +} + +/** + * sme_cfg_get_int() - Gets the cfg parameter value. + * @hal: Handle to hal. + * @cfg_id: Configuration parameter ID. + * @cfg_value: Pointer to variable in which cfg value + * will be saved. + * + * This function gets the value of the cfg parameter. + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_cfg_get_int(tHalHandle hal, uint16_t cfg_id, uint32_t *cfg_value) +{ + tpAniSirGlobal pmac = PMAC_STRUCT(hal); + QDF_STATUS status = QDF_STATUS_SUCCESS; + + if (eSIR_SUCCESS != wlan_cfg_get_int(pmac, cfg_id, cfg_value)) + status = QDF_STATUS_E_FAILURE; + + return status; +} + +/** + * sme_cfg_get_str() - Gets the cfg parameter string. + * @hal: Handle to hal. + * @cfg_id: Configuration parameter ID. + * @str: Pointer to the string buffer. + * @length: Pointer to length of the string. + * + * This function gets the string value of the cfg parameter. + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_cfg_get_str(tHalHandle hal, uint16_t cfg_id, uint8_t *str, + uint32_t *length) +{ + tpAniSirGlobal pmac = PMAC_STRUCT(hal); + QDF_STATUS status = QDF_STATUS_SUCCESS; + + if (eSIR_SUCCESS != wlan_cfg_get_str(pmac, cfg_id, str, length)) + status = QDF_STATUS_E_INVAL; + + return status; +} + +/* --------------------------------------------------------------------------- + \fn sme_get_modify_profile_fields + \brief HDD or SME - QOS calls this function to get the current values of + connected profile fields, changing which can cause reassoc. + This function must be called after CFG is downloaded and STA is in connected + state. Also, make sure to call this function to get the current profile + fields before calling the reassoc. So that pModifyProfileFields will have + all the latest values plus the one(s) has been updated as part of reassoc + request. + \param pModifyProfileFields - pointer to the connected profile fields + changing which can cause reassoc + + \return QDF_STATUS + -------------------------------------------------------------------------------*/ +QDF_STATUS sme_get_modify_profile_fields(tHalHandle hHal, uint8_t sessionId, + tCsrRoamModifyProfileFields * + pModifyProfileFields) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + MTRACE(qdf_trace(QDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_GET_MODPROFFIELDS, sessionId, + 0)); + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + if (CSR_IS_SESSION_VALID(pMac, sessionId)) { + status = + csr_get_modify_profile_fields(pMac, sessionId, + pModifyProfileFields); + } else { + status = QDF_STATUS_E_INVAL; + } + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +/* --------------------------------------------------------------------------- + \fn sme_set_dhcp_till_power_active_flag + \brief Sets/Clears DHCP related flag to disable/enable auto PS + \param hal - The handle returned by mac_open. + ---------------------------------------------------------------------------*/ +void sme_set_dhcp_till_power_active_flag(tHalHandle hal, uint8_t flag) +{ + tpAniSirGlobal mac = PMAC_STRUCT(hal); + struct ps_global_info *ps_global_info = &mac->sme.ps_global_info; + + MTRACE(qdf_trace(QDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_SET_DHCP_FLAG, NO_SESSION, + flag)); + /* Set/Clear the DHCP flag which will disable/enable auto PS */ + ps_global_info->remain_in_power_active_till_dhcp = flag; +} + +/* --------------------------------------------------------------------------- + \fn sme_register11d_scan_done_callback + \brief Register a routine of type csr_scan_completeCallback which is + called whenever an 11d scan is done + \param hHal - The handle returned by mac_open. + \param callback - 11d scan complete routine to be registered + \return QDF_STATUS + ---------------------------------------------------------------------------*/ +QDF_STATUS sme_register11d_scan_done_callback(tHalHandle hHal, + csr_scan_completeCallback callback) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + pMac->scan.callback11dScanDone = callback; + + return status; +} + +/** + * sme_deregister11d_scan_done_callback() - De-register scandone callback + * @h_hal: Handler return by mac_open + * + * This function De-registers the scandone callback to SME + * + * Return: None + */ +void sme_deregister11d_scan_done_callback(tHalHandle h_hal) +{ + tpAniSirGlobal pmac; + + if (!h_hal) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("hHal is not valid")); + return; + } + + pmac = PMAC_STRUCT(h_hal); + pmac->scan.callback11dScanDone = NULL; +} + + +#ifdef FEATURE_OEM_DATA_SUPPORT +/** + * sme_register_oem_data_rsp_callback() - Register a routine of + * type send_oem_data_rsp_msg + * @h_hal: Handle returned by mac_open. + * @callback: Callback to send response + * to oem application. + * + * sme_oem_data_rsp_callback is used to register sme_send_oem_data_rsp_msg + * callback function. + * + * Return: QDF_STATUS. + */ +QDF_STATUS sme_register_oem_data_rsp_callback(tHalHandle h_hal, + sme_send_oem_data_rsp_msg callback) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpAniSirGlobal pmac = PMAC_STRUCT(h_hal); + + pmac->sme.oem_data_rsp_callback = callback; + + return status; + +} + +/** + * sme_deregister_oem_data_rsp_callback() - De-register OEM datarsp callback + * @h_hal: Handler return by mac_open + * This function De-registers the OEM data response callback to SME + * + * Return: None + */ +void sme_deregister_oem_data_rsp_callback(tHalHandle h_hal) +{ + tpAniSirGlobal pmac; + + if (!h_hal) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("hHal is not valid")); + return; + } + pmac = PMAC_STRUCT(h_hal); + + pmac->sme.oem_data_rsp_callback = NULL; +} +#endif + +/** + * sme_oem_update_capability() - update UMAC's oem related capability. + * @hal: Handle returned by mac_open + * @oem_cap: pointer to oem_capability + * + * This function updates OEM capability to UMAC. Currently RTT + * related capabilities are updated. More capabilities can be + * added in future. + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_oem_update_capability(tHalHandle hal, + struct sme_oem_capability *cap) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpAniSirGlobal pmac = PMAC_STRUCT(hal); + uint8_t *bytes; + + bytes = pmac->rrm.rrmSmeContext.rrmConfig.rm_capability; + + if (cap->ftm_rr) + bytes[4] |= RM_CAP_FTM_RANGE_REPORT; + if (cap->lci_capability) + bytes[4] |= RM_CAP_CIVIC_LOC_MEASUREMENT; + + return status; +} + +/** + * sme_oem_get_capability() - get oem capability + * @hal: Handle returned by mac_open + * @oem_cap: pointer to oem_capability + * + * This function is used to get the OEM capability from UMAC. + * Currently RTT related capabilities are received. More + * capabilities can be added in future. + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_oem_get_capability(tHalHandle hal, + struct sme_oem_capability *cap) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpAniSirGlobal pmac = PMAC_STRUCT(hal); + uint8_t *bytes; + + bytes = pmac->rrm.rrmSmeContext.rrmConfig.rm_capability; + + cap->ftm_rr = bytes[4] & RM_CAP_FTM_RANGE_REPORT; + cap->lci_capability = bytes[4] & RM_CAP_CIVIC_LOC_MEASUREMENT; + + return status; +} + +/** + * sme_register_ftm_msg_processor() - registers hdd ftm message processor + * function to MAC/SYS + * + * @hal: hal handle + * @callback: hdd function that has to be registered + * + * Return: void + */ +void sme_register_ftm_msg_processor(tHalHandle hal, + hdd_ftm_msg_processor callback) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + + if (mac_ctx == NULL) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("mac ctx is NULL")); + return; + } + + mac_ctx->ftm_msg_processor_callback = callback; + return; +} + +/** + * sme_wow_add_pattern() - add a wow pattern in fw + * @hHal: handle returned by mac_open + * @pattern: pointer to input pattern + * + * Add a pattern for Pattern Byte Matching in WoW mode. Firmware will + * do a pattern match on these patterns when WoW is enabled during system + * suspend. + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_wow_add_pattern(tHalHandle hal, + struct wow_add_pattern *pattern, + uint8_t session_id) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hal); + struct wow_add_pattern *ptrn; + tSirRetStatus ret_code = eSIR_SUCCESS; + tSirMsgQ msg_q; + MTRACE(qdf_trace(QDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_WOWL_ADDBCAST_PATTERN, session_id, + 0)); + ptrn = qdf_mem_malloc(sizeof(*ptrn)); + if (NULL == ptrn) { + sms_log(pMac, LOGP, + FL("Fail to allocate memory for WoWLAN Add Bcast Pattern ")); + return QDF_STATUS_E_NOMEM; + } + (void)qdf_mem_copy(ptrn, pattern, sizeof(*ptrn)); + + msg_q.type = WMA_WOW_ADD_PTRN; + msg_q.reserved = 0; + msg_q.bodyptr = ptrn; + msg_q.bodyval = 0; + + sms_log(pMac, LOG1, FL("Sending WMA_WOWL_ADD_BCAST_PTRN to HAL")); + ret_code = wma_post_ctrl_msg(pMac, &msg_q); + if (eSIR_SUCCESS != ret_code) { + sms_log(pMac, LOGE, + FL("Posting WMA_WOWL_ADD_BCAST_PTRN failed, reason=%X"), + ret_code); + } + return ret_code; +} + +/** + * sme_wow_delete_pattern() - delete user configured wow pattern in target + * @hHal: handle returned by mac_open. + * @pattern: pointer to delete pattern parameter + * @sessionId: session id + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_wow_delete_pattern(tHalHandle hal, + struct wow_delete_pattern *pattern, uint8_t sessionId) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hal); + struct wow_delete_pattern *delete_ptrn; + tSirRetStatus ret_code = eSIR_SUCCESS; + tSirMsgQ msg_q; + MTRACE(qdf_trace(QDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_WOWL_DELBCAST_PATTERN, sessionId, + 0)); + delete_ptrn = qdf_mem_malloc(sizeof(*delete_ptrn)); + if (NULL == delete_ptrn) { + sms_log(pMac, LOGP, + FL("Fail to allocate memory for WoWLAN Delete Bcast Pattern ")); + return QDF_STATUS_E_NOMEM; + } + (void)qdf_mem_copy(delete_ptrn, pattern, sizeof(*delete_ptrn)); + msg_q.type = WMA_WOW_DEL_PTRN; + msg_q.reserved = 0; + msg_q.bodyptr = delete_ptrn; + msg_q.bodyval = 0; + + sms_log(pMac, LOG1, FL("Sending WMA_WOWL_DEL_BCAST_PTRN")); + + ret_code = wma_post_ctrl_msg(pMac, &msg_q); + if (eSIR_SUCCESS != ret_code) { + sms_log(pMac, LOGE, + FL("Posting WMA_WOWL_DEL_BCAST_PTRN failed, reason=%X"), + ret_code); + } + return ret_code; +} + +/** + * sme_enter_wowl(): SME API exposed to HDD to request enabling of WOWL mode. + * @hal_ctx - The handle returned by mac_open. + * @enter_wowl_callback_routine - Callback routine provided by HDD. + * Used for success/failure notification by SME + * @enter_wowl_callback_context - A cookie passed by HDD, that is passed + * back to HDD at the time of callback. + * @wake_reason_ind_cb - Callback routine provided by HDD. + * Used for Wake Reason Indication by SME + * @wake_reason_ind_cb_ctx - A cookie passed by HDD, that is passed + * back to HDD at the time of callback. + * + * WoWLAN works on top of BMPS mode. + * If the device is not in BMPS mode, + * SME will will cache the information that + * WOWL has been enabled and attempt to put the device + * in BMPS. On entry into BMPS, SME will enable the + * WOWL mode. + * Note 1: If we exit BMPS mode (someone requests full power), + * we will NOT resume WOWL when we go back to BMPS again. + * Request for full power (while in WOWL mode) means disable + * WOWL and go to full power. + * Note 2: Both UAPSD and WOWL work on top of BMPS. + * On entry into BMPS, SME will give priority to UAPSD and + * enable only UAPSD if both UAPSD and WOWL are required. + * Currently there is no requirement or use case to support + * UAPSD and WOWL at the same time. + * + * Return: QDF_STATUS + * QDF_STATUS_SUCCESS Device is already in WoWLAN mode + * QDF_STATUS_E_FAILURE Device cannot enter WoWLAN mode. + * QDF_STATUS_PMC_PENDING Request accepted. SME will enable + * WOWL after BMPS mode is entered. + */ +QDF_STATUS sme_enter_wowl(tHalHandle hal_ctx, + void (*enter_wowl_callback_routine)(void + *callback_context, + QDF_STATUS status), + void *enter_wowl_callback_context, +#ifdef WLAN_WAKEUP_EVENTS + void (*wakeIndicationCB)(void *callback_context, + tpSirWakeReasonInd + wake_reason_ind), + void *wakeIndicationCBContext, +#endif /* WLAN_WAKEUP_EVENTS */ + tpSirSmeWowlEnterParams wowl_enter_params, + uint8_t session_id) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal_ctx); + struct ps_global_info *ps_global_info = &mac_ctx->sme.ps_global_info; + MTRACE(qdf_trace(QDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_ENTER_WOWL, session_id, 0)); + + /* cache the WOWL information */ + ps_global_info->ps_params[session_id].wowl_enter_params = + *wowl_enter_params; + ps_global_info->ps_params[session_id].enter_wowl_callback_routine = + enter_wowl_callback_routine; + ps_global_info->ps_params[session_id].enter_wowl_callback_context = + enter_wowl_callback_context; +#ifdef WLAN_WAKEUP_EVENTS + /* Cache the Wake Reason Indication callback information */ + ps_global_info->ps_params[session_id].wake_reason_ind_cb = + wakeIndicationCB; + ps_global_info->ps_params[session_id].wake_reason_ind_cb_ctx = + wakeIndicationCBContext; +#endif /* WLAN_WAKEUP_EVENTS */ + + status = sme_ps_process_command(mac_ctx, session_id, SME_PS_WOWL_ENTER); + return status; +} +/** + *sme_exit_wowl(): SME API exposed to HDD to request exit from WoWLAN mode. + * @hal_ctx - The handle returned by mac_open. + * @wowl_exit_params - Carries info on which smesession + * wowl exit is requested. + * + * SME will initiate exit from WoWLAN mode and device will be + * put in BMPS mode. + * Return QDF_STATUS + * QDF_STATUS_E_FAILURE Device cannot exit WoWLAN mode. + * QDF_STATUS_SUCCESS Request accepted to exit WoWLAN mode. + */ +QDF_STATUS sme_exit_wowl(tHalHandle hal_ctx, + tpSirSmeWowlExitParams wowl_exit_params) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal_ctx); + uint8_t session_id; + MTRACE(qdf_trace(QDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_EXIT_WOWL, NO_SESSION, 0)); + session_id = wowl_exit_params->sessionId; + status = sme_ps_process_command(mac_ctx, session_id, SME_PS_WOWL_EXIT); + return status; +} + +/** + * sme_roam_set_key() - To set encryption key. + * @hal: hal global context + * @session_id: session id + * @set_key: pointer to a caller allocated object of tCsrSetContextInfo + * @ptr_roam_id: Upon success return, this is the id caller can use to + * identify the request in roamcallback + * + * This function should be called only when connected. This is an asynchronous + * API. + * + * Return: Status of operation + */ +QDF_STATUS sme_roam_set_key(tHalHandle hal, uint8_t session_id, + tCsrRoamSetKey *set_key, uint32_t *ptr_roam_id) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + uint32_t roam_id; + uint32_t i; + tCsrRoamSession *session = NULL; + struct ps_global_info *ps_global_info = &mac_ctx->sme.ps_global_info; + + MTRACE(qdf_trace(QDF_MODULE_ID_SME, TRACE_CODE_SME_RX_HDD_SET_KEY, + session_id, 0)); + if (set_key->keyLength > CSR_MAX_KEY_LEN) { + sms_log(mac_ctx, LOGE, FL("Invalid key length %d"), + set_key->keyLength); + return QDF_STATUS_E_FAILURE; + } + /*Once Setkey is done, we can go in BMPS */ + if (set_key->keyLength) + ps_global_info->remain_in_power_active_till_dhcp = false; + + status = sme_acquire_global_lock(&mac_ctx->sme); + if (!QDF_IS_STATUS_SUCCESS(status)) + return status; + + roam_id = GET_NEXT_ROAM_ID(&mac_ctx->roam); + if (ptr_roam_id) + *ptr_roam_id = roam_id; + + sms_log(mac_ctx, LOG2, FL("keyLength %d"), set_key->keyLength); + for (i = 0; i < set_key->keyLength; i++) + sms_log(mac_ctx, LOG2, FL("%02x"), set_key->Key[i]); + + sms_log(mac_ctx, LOG2, "\n session_id=%d roam_id=%d", session_id, + roam_id); + session = CSR_GET_SESSION(mac_ctx, session_id); + if (!session) { + sms_log(mac_ctx, LOGE, FL("session %d not found"), session_id); + sme_release_global_lock(&mac_ctx->sme); + return QDF_STATUS_E_FAILURE; + } + if (CSR_IS_INFRA_AP(&session->connectedProfile) + && set_key->keyDirection == eSIR_TX_DEFAULT) { + if ((eCSR_ENCRYPT_TYPE_WEP40 == set_key->encType) + || (eCSR_ENCRYPT_TYPE_WEP40_STATICKEY == + set_key->encType)) { + session->pCurRoamProfile->negotiatedUCEncryptionType = + eCSR_ENCRYPT_TYPE_WEP40_STATICKEY; + } + if ((eCSR_ENCRYPT_TYPE_WEP104 == set_key->encType) + || (eCSR_ENCRYPT_TYPE_WEP104_STATICKEY == + set_key->encType)) { + session->pCurRoamProfile->negotiatedUCEncryptionType = + eCSR_ENCRYPT_TYPE_WEP104_STATICKEY; + } + } + status = csr_roam_set_key(mac_ctx, session_id, set_key, roam_id); + sme_release_global_lock(&mac_ctx->sme); + return status; +} + +/** + * sme_roam_set_default_key_index - To set default wep key idx + * @hal: pointer to hal handler + * @session_id: session id + * @default_idx: default wep key index + * + * This function prepares a message and post to WMA to set wep default + * key index + * + * Return: Success:QDF_STATUS_SUCCESS Failure: Error value + */ +QDF_STATUS sme_roam_set_default_key_index(tHalHandle hal, uint8_t session_id, + uint8_t default_idx) +{ + cds_msg_t msg; + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + struct wep_update_default_key_idx *update_key; + + update_key = qdf_mem_malloc(sizeof(*update_key)); + if (!update_key) { + sms_log(mac_ctx, LOGE, + FL("Failed to allocate memory for update key")); + return QDF_STATUS_E_NOMEM; + } + + update_key->session_id = session_id; + update_key->default_idx = default_idx; + + msg.type = WMA_UPDATE_WEP_DEFAULT_KEY; + msg.reserved = 0; + msg.bodyptr = (void *)update_key; + + if (QDF_STATUS_SUCCESS != + cds_mq_post_message(QDF_MODULE_ID_WMA, &msg)) { + sms_log(mac_ctx, LOGE, + FL("Failed to post WMA_UPDATE_WEP_DEFAULT_KEY to WMA")); + qdf_mem_free(update_key); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + + +/* --------------------------------------------------------------------------- + \fn sme_get_rssi + \brief a wrapper function that client calls to register a callback to get + RSSI + + \param hHal - HAL handle for device + \param callback - SME sends back the requested stats using the callback + \param staId - The station ID for which the stats is requested for + \param bssid - The bssid of the connected session + \param lastRSSI - RSSI value at time of request. In case fw cannot provide + RSSI, do not hold up but return this value. + \param pContext - user context to be passed back along with the callback + \param p_cds_context - cds context + \return QDF_STATUS + ---------------------------------------------------------------------------*/ +QDF_STATUS sme_get_rssi(tHalHandle hHal, + tCsrRssiCallback callback, + uint8_t staId, struct qdf_mac_addr bssId, int8_t lastRSSI, + void *pContext, void *p_cds_context) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + MTRACE(qdf_trace(QDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_GET_RSSI, NO_SESSION, 0)); + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + status = csr_get_rssi(pMac, callback, + staId, bssId, lastRSSI, + pContext, p_cds_context); + sme_release_global_lock(&pMac->sme); + } + return status; +} + +/* --------------------------------------------------------------------------- + \fn sme_get_snr + \brief a wrapper function that client calls to register a callback to + get SNR + + \param callback - SME sends back the requested stats using the callback + \param staId - The station ID for which the stats is requested for + \param pContext - user context to be passed back along with the callback + \param p_cds_context - cds context + \return QDF_STATUS + ---------------------------------------------------------------------------*/ +QDF_STATUS sme_get_snr(tHalHandle hHal, + tCsrSnrCallback callback, + uint8_t staId, struct qdf_mac_addr bssId, void *pContext) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + status = csr_get_snr(pMac, callback, staId, bssId, pContext); + sme_release_global_lock(&pMac->sme); + } + return status; +} + +/* --------------------------------------------------------------------------- + \fn sme_get_statistics + \brief a wrapper function that client calls to register a callback to get + different PHY level statistics from CSR. + + \param requesterId - different client requesting for statistics, + HDD, UMA/GAN etc + \param statsMask - The different category/categories of stats requester + is looking for + \param callback - SME sends back the requested stats using the callback + \param periodicity - If requester needs periodic update in millisec, 0 means + it's an one time request + \param cache - If requester is happy with cached stats + \param staId - The station ID for which the stats is requested for + \param pContext - user context to be passed back along with the callback + \param sessionId - sme session interface + \return QDF_STATUS + ---------------------------------------------------------------------------*/ +QDF_STATUS sme_get_statistics(tHalHandle hHal, + eCsrStatsRequesterType requesterId, + uint32_t statsMask, tCsrStatsCallback callback, + uint32_t periodicity, bool cache, uint8_t staId, + void *pContext, uint8_t sessionId) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + MTRACE(qdf_trace(QDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_GET_STATS, NO_SESSION, + periodicity)); + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + status = + csr_get_statistics(pMac, requesterId, statsMask, callback, + periodicity, cache, staId, pContext, + sessionId); + sme_release_global_lock(&pMac->sme); + } + + return status; + +} + +QDF_STATUS sme_get_link_status(tHalHandle hHal, + tCsrLinkStatusCallback callback, + void *pContext, uint8_t sessionId) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + tAniGetLinkStatus *pMsg; + cds_msg_t cds_message; + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + pMsg = qdf_mem_malloc(sizeof(tAniGetLinkStatus)); + if (NULL == pMsg) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Not able to allocate memory for link status", + __func__); + sme_release_global_lock(&pMac->sme); + return QDF_STATUS_E_NOMEM; + } + + pMsg->msgType = WMA_LINK_STATUS_GET_REQ; + pMsg->msgLen = (uint16_t) sizeof(tAniGetLinkStatus); + pMsg->sessionId = sessionId; + pMac->sme.linkStatusContext = pContext; + pMac->sme.linkStatusCallback = callback; + + cds_message.type = WMA_LINK_STATUS_GET_REQ; + cds_message.bodyptr = pMsg; + cds_message.reserved = 0; + + if (!QDF_IS_STATUS_SUCCESS + (cds_mq_post_message(QDF_MODULE_ID_WMA, &cds_message))) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Post LINK STATUS MSG fail", __func__); + qdf_mem_free(pMsg); + pMac->sme.linkStatusContext = NULL; + pMac->sme.linkStatusCallback = NULL; + status = QDF_STATUS_E_FAILURE; + } + + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +/* --------------------------------------------------------------------------- + + \fn sme_get_country_code + + \brief To return the current country code. If no country code is applied, + default country code is used to fill the buffer. + If 11d supported is turned off, an error is return and the last + applied/default country code is used. + This is a synchronous API. + + \param pBuf - pointer to a caller allocated buffer for returned country code. + + \param pbLen For input, this parameter indicates how big is the buffer. + Upon return, this parameter has the number of bytes for + country. If pBuf doesn't have enough space, this function + returns fail status and this parameter contains the number + that is needed. + + \return QDF_STATUS SUCCESS. + + FAILURE or RESOURCES The API finished and failed. + + -------------------------------------------------------------------------------*/ +QDF_STATUS sme_get_country_code(tHalHandle hHal, uint8_t *pBuf, uint8_t *pbLen) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + MTRACE(qdf_trace(QDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_GET_CNTRYCODE, NO_SESSION, 0)); + + return csr_get_country_code(pMac, pBuf, pbLen); +} + +/** + * sme_apply_channel_power_info_to_fw() - sends channel info to fw + * @hHal: hal handle + * + * This function sends the channel power info to firmware + * + * Return: none + */ +void sme_apply_channel_power_info_to_fw(tHalHandle hHal) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + csr_apply_channel_power_info_wrapper(pMac); +} + +/* some support functions */ +bool sme_is11d_supported(tHalHandle hHal) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + return csr_is11d_supported(pMac); +} + +bool sme_is11h_supported(tHalHandle hHal) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + return csr_is11h_supported(pMac); +} + +bool sme_is_wmm_supported(tHalHandle hHal) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + return csr_is_wmm_supported(pMac); +} + +/* --------------------------------------------------------------------------- + + \fn sme_change_country_code + + \brief Change Country code from upperlayer during WLAN driver operation. + This is a synchronous API. + + \param hHal - The handle returned by mac_open. + + \param pCountry New Country Code String + + \param sendRegHint If we want to send reg hint to nl80211 + + \return QDF_STATUS SUCCESS. + + FAILURE or RESOURCES The API finished and failed. + + -------------------------------------------------------------------------------*/ +QDF_STATUS sme_change_country_code(tHalHandle hHal, + tSmeChangeCountryCallback callback, + uint8_t *pCountry, + void *pContext, + void *p_cds_context, + tAniBool countryFromUserSpace, + tAniBool sendRegHint) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + cds_msg_t msg; + tAniChangeCountryCodeReq *pMsg; + + MTRACE(qdf_trace(QDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_CHANGE_CNTRYCODE, NO_SESSION, + 0)); + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOG1, FL(" called")); + + if ((pMac->roam.configParam.Is11dSupportEnabledOriginal == true) + && (!pMac->roam.configParam. + fSupplicantCountryCodeHasPriority)) { + + sms_log(pMac, LOGW, + "Set Country Code Fail since the STA is associated and userspace does not have priority "); + + sme_release_global_lock(&pMac->sme); + status = QDF_STATUS_E_FAILURE; + return status; + } + + pMsg = qdf_mem_malloc(sizeof(tAniChangeCountryCodeReq)); + if (NULL == pMsg) { + sms_log(pMac, LOGE, + " csrChangeCountryCode: failed to allocate mem for req"); + sme_release_global_lock(&pMac->sme); + return QDF_STATUS_E_NOMEM; + } + + pMsg->msgType = eWNI_SME_CHANGE_COUNTRY_CODE; + pMsg->msgLen = (uint16_t) sizeof(tAniChangeCountryCodeReq); + qdf_mem_copy(pMsg->countryCode, pCountry, 3); + pMsg->countryFromUserSpace = countryFromUserSpace; + pMsg->sendRegHint = sendRegHint; + pMsg->changeCCCallback = callback; + pMsg->pDevContext = pContext; + pMsg->p_cds_context = p_cds_context; + + msg.type = eWNI_SME_CHANGE_COUNTRY_CODE; + msg.bodyptr = pMsg; + msg.reserved = 0; + + if (QDF_STATUS_SUCCESS != + cds_mq_post_message(CDS_MQ_ID_SME, &msg)) { + sms_log(pMac, LOGE, + " sme_change_country_code failed to post msg to self "); + qdf_mem_free((void *)pMsg); + status = QDF_STATUS_E_FAILURE; + } + sms_log(pMac, LOG1, FL(" returned")); + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +/*-------------------------------------------------------------------------- + + \fn sme_generic_change_country_code + + \brief Change Country code from upperlayer during WLAN driver operation. + This is a synchronous API. + + \param hHal - The handle returned by mac_open. + + \param pCountry New Country Code String + + \param reg_domain regulatory domain + + \return QDF_STATUS SUCCESS. + + FAILURE or RESOURCES The API finished and failed. + + -----------------------------------------------------------------------------*/ +QDF_STATUS sme_generic_change_country_code(tHalHandle hHal, + uint8_t *pCountry) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + cds_msg_t msg; + tAniGenericChangeCountryCodeReq *pMsg; + + if (NULL == pMac) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_FATAL, + "%s: pMac is null", __func__); + return status; + } + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOG1, FL(" called")); + pMsg = qdf_mem_malloc(sizeof(tAniGenericChangeCountryCodeReq)); + + if (NULL == pMsg) { + sms_log(pMac, LOGE, + " sme_generic_change_country_code: failed to allocate mem for req"); + sme_release_global_lock(&pMac->sme); + return QDF_STATUS_E_NOMEM; + } + + pMsg->msgType = eWNI_SME_GENERIC_CHANGE_COUNTRY_CODE; + pMsg->msgLen = + (uint16_t) sizeof(tAniGenericChangeCountryCodeReq); + qdf_mem_copy(pMsg->countryCode, pCountry, 2); + pMsg->countryCode[2] = ' '; + + msg.type = eWNI_SME_GENERIC_CHANGE_COUNTRY_CODE; + msg.bodyptr = pMsg; + msg.reserved = 0; + + if (QDF_STATUS_SUCCESS != + cds_mq_post_message(CDS_MQ_ID_SME, &msg)) { + sms_log(pMac, LOGE, + "sme_generic_change_country_code failed to post msg to self"); + qdf_mem_free(pMsg); + status = QDF_STATUS_E_FAILURE; + } + sms_log(pMac, LOG1, FL(" returned")); + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +/* --------------------------------------------------------------------------- + + \fn sme_dhcp_start_ind + + \brief API to signal the FW about the DHCP Start event. + + \param hHal - HAL handle for device. + + \param device_mode - mode(AP,SAP etc) of the device. + + \param macAddr - MAC address of the adapter. + + \param sessionId - session ID. + + \return QDF_STATUS SUCCESS. + + FAILURE or RESOURCES The API finished and failed. + --------------------------------------------------------------------------*/ +QDF_STATUS sme_dhcp_start_ind(tHalHandle hHal, + uint8_t device_mode, + uint8_t *macAddr, uint8_t sessionId) +{ + QDF_STATUS status; + QDF_STATUS qdf_status; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + cds_msg_t cds_message; + tAniDHCPInd *pMsg; + tCsrRoamSession *pSession; + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_STATUS_SUCCESS == status) { + pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!pSession) { + sms_log(pMac, LOGE, FL("session %d not found "), + sessionId); + sme_release_global_lock(&pMac->sme); + return QDF_STATUS_E_FAILURE; + } + pSession->dhcp_done = false; + + pMsg = (tAniDHCPInd *) qdf_mem_malloc(sizeof(tAniDHCPInd)); + if (NULL == pMsg) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Not able to allocate memory for dhcp start", + __func__); + sme_release_global_lock(&pMac->sme); + return QDF_STATUS_E_NOMEM; + } + pMsg->msgType = WMA_DHCP_START_IND; + pMsg->msgLen = (uint16_t) sizeof(tAniDHCPInd); + pMsg->device_mode = device_mode; + qdf_mem_copy(pMsg->adapterMacAddr.bytes, macAddr, + QDF_MAC_ADDR_SIZE); + qdf_copy_macaddr(&pMsg->peerMacAddr, + &pSession->connectedProfile.bssid); + + cds_message.type = WMA_DHCP_START_IND; + cds_message.bodyptr = pMsg; + cds_message.reserved = 0; + MTRACE(qdf_trace(QDF_MODULE_ID_SME, TRACE_CODE_SME_TX_WMA_MSG, + sessionId, cds_message.type)); + qdf_status = cds_mq_post_message(CDS_MQ_ID_WMA, &cds_message); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Post DHCP Start MSG fail", __func__); + qdf_mem_free(pMsg); + status = QDF_STATUS_E_FAILURE; + } + sme_release_global_lock(&pMac->sme); + } + return status; +} + +/* --------------------------------------------------------------------------- + \fn sme_dhcp_stop_ind + + \brief API to signal the FW about the DHCP complete event. + + \param hHal - HAL handle for device. + + \param device_mode - mode(AP, SAP etc) of the device. + + \param macAddr - MAC address of the adapter. + + \param sessionId - session ID. + + \return QDF_STATUS SUCCESS. + FAILURE or RESOURCES The API finished and failed. + --------------------------------------------------------------------------*/ +QDF_STATUS sme_dhcp_stop_ind(tHalHandle hHal, + uint8_t device_mode, + uint8_t *macAddr, uint8_t sessionId) +{ + QDF_STATUS status; + QDF_STATUS qdf_status; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + cds_msg_t cds_message; + tAniDHCPInd *pMsg; + tCsrRoamSession *pSession; + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_STATUS_SUCCESS == status) { + pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!pSession) { + sms_log(pMac, LOGE, FL("session %d not found "), + sessionId); + sme_release_global_lock(&pMac->sme); + return QDF_STATUS_E_FAILURE; + } + pSession->dhcp_done = true; + + pMsg = (tAniDHCPInd *) qdf_mem_malloc(sizeof(tAniDHCPInd)); + if (NULL == pMsg) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Not able to allocate memory for dhcp stop", + __func__); + sme_release_global_lock(&pMac->sme); + return QDF_STATUS_E_NOMEM; + } + + pMsg->msgType = WMA_DHCP_STOP_IND; + pMsg->msgLen = (uint16_t) sizeof(tAniDHCPInd); + pMsg->device_mode = device_mode; + qdf_mem_copy(pMsg->adapterMacAddr.bytes, macAddr, + QDF_MAC_ADDR_SIZE); + qdf_copy_macaddr(&pMsg->peerMacAddr, + &pSession->connectedProfile.bssid); + + cds_message.type = WMA_DHCP_STOP_IND; + cds_message.bodyptr = pMsg; + cds_message.reserved = 0; + MTRACE(qdf_trace(QDF_MODULE_ID_SME, TRACE_CODE_SME_TX_WMA_MSG, + sessionId, cds_message.type)); + qdf_status = cds_mq_post_message(CDS_MQ_ID_WMA, &cds_message); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Post DHCP Stop MSG fail", __func__); + qdf_mem_free(pMsg); + status = QDF_STATUS_E_FAILURE; + } + + sme_release_global_lock(&pMac->sme); + } + return status; +} + +/*--------------------------------------------------------------------------- + + \fn sme_TXFailMonitorStopInd + + \brief API to signal the FW to start monitoring TX failures + + \return QDF_STATUS SUCCESS. + + FAILURE or RESOURCES The API finished and failed. + --------------------------------------------------------------------------*/ +QDF_STATUS sme_tx_fail_monitor_start_stop_ind(tHalHandle hHal, uint8_t tx_fail_count, + void *txFailIndCallback) +{ + QDF_STATUS status; + QDF_STATUS qdf_status; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + cds_msg_t cds_message; + tAniTXFailMonitorInd *pMsg; + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_STATUS_SUCCESS == status) { + pMsg = (tAniTXFailMonitorInd *) + qdf_mem_malloc(sizeof(tAniTXFailMonitorInd)); + if (NULL == pMsg) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Failed to allocate memory", __func__); + sme_release_global_lock(&pMac->sme); + return QDF_STATUS_E_NOMEM; + } + + pMsg->msgType = WMA_TX_FAIL_MONITOR_IND; + pMsg->msgLen = (uint16_t) sizeof(tAniTXFailMonitorInd); + + /* tx_fail_count = 0 should disable the Monitoring in FW */ + pMsg->tx_fail_count = tx_fail_count; + pMsg->txFailIndCallback = txFailIndCallback; + + cds_message.type = WMA_TX_FAIL_MONITOR_IND; + cds_message.bodyptr = pMsg; + cds_message.reserved = 0; + + qdf_status = cds_mq_post_message(CDS_MQ_ID_WMA, &cds_message); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Post TX Fail monitor Start MSG fail", + __func__); + qdf_mem_free(pMsg); + status = QDF_STATUS_E_FAILURE; + } + sme_release_global_lock(&pMac->sme); + } + return status; +} + +/* --------------------------------------------------------------------------- + \fn sme_set_cfg_privacy + \brief API to set configure privacy parameters + \param hHal - The handle returned by mac_open. + \param pProfile - Pointer CSR Roam profile. + \param fPrivacy - This parameter indicates status of privacy + + \return void + ---------------------------------------------------------------------------*/ +void sme_set_cfg_privacy(tHalHandle hHal, + tCsrRoamProfile *pProfile, bool fPrivacy) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + MTRACE(qdf_trace(QDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_SET_CFGPRIVACY, NO_SESSION, 0)); + if (QDF_STATUS_SUCCESS == sme_acquire_global_lock(&pMac->sme)) { + csr_set_cfg_privacy(pMac, pProfile, fPrivacy); + sme_release_global_lock(&pMac->sme); + } +} + +/* --------------------------------------------------------------------------- + \fn sme_neighbor_report_request + \brief API to request neighbor report. + \param hHal - The handle returned by mac_open. + \param pRrmNeighborReq - Pointer to a caller allocated object of type + tRrmNeighborReq. Caller owns the memory and is + responsible for freeing it. + \return QDF_STATUS + QDF_STATUS_E_FAILURE - failure + QDF_STATUS_SUCCESS success + ---------------------------------------------------------------------------*/ +QDF_STATUS sme_neighbor_report_request(tHalHandle hHal, uint8_t sessionId, + tpRrmNeighborReq pRrmNeighborReq, + tpRrmNeighborRspCallbackInfo callbackInfo) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + MTRACE(qdf_trace(QDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_NEIGHBOR_REPORTREQ, NO_SESSION, + 0)); + + if (QDF_STATUS_SUCCESS == sme_acquire_global_lock(&pMac->sme)) { + status = + sme_rrm_neighbor_report_request(hHal, sessionId, + pRrmNeighborReq, callbackInfo); + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +void sms_log(tpAniSirGlobal pMac, uint32_t loglevel, const char *pString, ...) +{ +#ifdef WLAN_DEBUG + /* Verify against current log level */ + if (loglevel > + pMac->utils.gLogDbgLevel[LOG_INDEX_FOR_MODULE(SIR_SMS_MODULE_ID)]) + return; + else { + va_list marker; + + va_start(marker, pString); /* Initialize variable arguments. */ + + log_debug(pMac, SIR_SMS_MODULE_ID, loglevel, pString, marker); + + va_end(marker); /* Reset variable arguments. */ + } +#endif +} + +/* --------------------------------------------------------------------------- + \fn sme_get_wcnss_wlan_compiled_version + \brief This API returns the version of the WCNSS WLAN API with + which the HOST driver was built + \param hHal - The handle returned by mac_open. + \param pVersion - Points to the Version structure to be filled + \return QDF_STATUS + QDF_STATUS_E_INVAL - failure + QDF_STATUS_SUCCESS success + ---------------------------------------------------------------------------*/ +QDF_STATUS sme_get_wcnss_wlan_compiled_version(tHalHandle hHal, + tSirVersionType *pVersion) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + if (QDF_STATUS_SUCCESS == sme_acquire_global_lock(&pMac->sme)) { + if (pVersion != NULL) + status = QDF_STATUS_SUCCESS; + else + status = QDF_STATUS_E_INVAL; + + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +/* --------------------------------------------------------------------------- + \fn sme_get_wcnss_wlan_reported_version + \brief This API returns the version of the WCNSS WLAN API with + which the WCNSS driver reports it was built + \param hHal - The handle returned by mac_open. + \param pVersion - Points to the Version structure to be filled + \return QDF_STATUS + QDF_STATUS_E_INVAL - failure + QDF_STATUS_SUCCESS success + ---------------------------------------------------------------------------*/ +QDF_STATUS sme_get_wcnss_wlan_reported_version(tHalHandle hHal, + tSirVersionType *pVersion) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + if (QDF_STATUS_SUCCESS == sme_acquire_global_lock(&pMac->sme)) { + if (pVersion != NULL) + status = QDF_STATUS_SUCCESS; + else + status = QDF_STATUS_E_INVAL; + + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +/* --------------------------------------------------------------------------- + \fn sme_get_wcnss_software_version + \brief This API returns the version string of the WCNSS driver + \param hHal - The handle returned by mac_open. + \param pVersion - Points to the Version string buffer to be filled + \param versionBufferSize - THe size of the Version string buffer + \return QDF_STATUS + QDF_STATUS_E_INVAL - failure + QDF_STATUS_SUCCESS success + ---------------------------------------------------------------------------*/ +QDF_STATUS sme_get_wcnss_software_version(tHalHandle hHal, + uint8_t *pVersion, + uint32_t versionBufferSize) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + v_CONTEXT_t cds_context = cds_get_global_context(); + + if (QDF_STATUS_SUCCESS == sme_acquire_global_lock(&pMac->sme)) { + if (pVersion != NULL) { + status = + wma_get_wcnss_software_version(cds_context, + pVersion, + versionBufferSize); + } else { + status = QDF_STATUS_E_INVAL; + } + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +/* --------------------------------------------------------------------------- + \fn sme_get_wcnss_hardware_version + \brief This API returns the version string of the WCNSS hardware + \param hHal - The handle returned by mac_open. + \param pVersion - Points to the Version string buffer to be filled + \param versionBufferSize - THe size of the Version string buffer + \return QDF_STATUS + QDF_STATUS_E_INVAL - failure + QDF_STATUS_SUCCESS success + ---------------------------------------------------------------------------*/ +QDF_STATUS sme_get_wcnss_hardware_version(tHalHandle hHal, + uint8_t *pVersion, + uint32_t versionBufferSize) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + if (QDF_STATUS_SUCCESS == sme_acquire_global_lock(&pMac->sme)) { + if (pVersion != NULL) + status = QDF_STATUS_SUCCESS; + else + status = QDF_STATUS_E_INVAL; + + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +#ifdef FEATURE_WLAN_WAPI + +/* --------------------------------------------------------------------------- + \fn sme_scan_get_bkid_candidate_list + \brief a wrapper function to return the BKID candidate list + \param pBkidList - caller allocated buffer point to an array of + tBkidCandidateInfo + \param pNumItems - pointer to a variable that has the number of + tBkidCandidateInfo allocated when retruning, this is + either the number needed or number of items put into + pPmkidList + \return QDF_STATUS - when fail, it usually means the buffer allocated is not + big enough and pNumItems + has the number of tBkidCandidateInfo. + \Note: pNumItems is a number of tBkidCandidateInfo, + not sizeof(tBkidCandidateInfo) * something + ---------------------------------------------------------------------------*/ +QDF_STATUS sme_scan_get_bkid_candidate_list(tHalHandle hHal, uint32_t sessionId, + tBkidCandidateInfo *pBkidList, + uint32_t *pNumItems) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + status = + csr_scan_get_bkid_candidate_list(pMac, sessionId, pBkidList, + pNumItems); + sme_release_global_lock(&pMac->sme); + } + + return status; +} +#endif /* FEATURE_WLAN_WAPI */ + +#ifdef FEATURE_OEM_DATA_SUPPORT +/** + * sme_oem_data_req() - send oem data request to WMA + * @hal: HAL handle + * @hdd_oem_req: OEM data request from HDD + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_oem_data_req(tHalHandle hal, struct oem_data_req *hdd_oem_req) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + struct oem_data_req *oem_data_req; + void *wma_handle; + + sms_log(mac_ctx, LOG1, FL("enter")); + wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma_handle) { + sms_log(mac_ctx, LOGE, FL("wma_handle is NULL")); + return QDF_STATUS_E_FAILURE; + } + + oem_data_req = qdf_mem_malloc(sizeof(*oem_data_req)); + if (!oem_data_req) { + sms_log(mac_ctx, LOGE, FL("mem alloc failed")); + return QDF_STATUS_E_NOMEM; + } + + oem_data_req->data_len = hdd_oem_req->data_len; + oem_data_req->data = qdf_mem_malloc(oem_data_req->data_len); + if (!oem_data_req->data) { + sms_log(mac_ctx, LOGE, FL("mem alloc failed")); + return QDF_STATUS_E_NOMEM; + } + + qdf_mem_copy(oem_data_req->data, hdd_oem_req->data, + oem_data_req->data_len); + + status = wma_start_oem_data_req(wma_handle, oem_data_req); + + if (!QDF_IS_STATUS_SUCCESS(status)) { + sms_log(mac_ctx, LOGE, FL("Post oem data request msg fail")); + } else { + sms_log(mac_ctx, LOG1, + FL("OEM request(length: %d) sent to WMA"), + oem_data_req->data_len); + } + + if (oem_data_req->data_len) + qdf_mem_free(oem_data_req->data); + qdf_mem_free(oem_data_req); + + sms_log(mac_ctx, LOG1, FL("exit")); + return status; +} +#endif /*FEATURE_OEM_DATA_SUPPORT */ + +/*-------------------------------------------------------------------------- + + \brief sme_open_session() - Open a session for scan/roam operation. + + This is a synchronous API. + + \param hHal - The handle returned by mac_open. + \param callback - A pointer to the function caller specifies for + roam/connect status indication + \param pContext - The context passed with callback + \param pSelfMacAddr - Caller allocated memory filled with self MAC address + (6 bytes) + \param pbSessionId - pointer to a caller allocated buffer for returned session ID + + \return QDF_STATUS_SUCCESS - session is opened. sessionId returned. + + Other status means SME is failed to open the session. + QDF_STATUS_E_RESOURCES - no more session available. + \sa + + --------------------------------------------------------------------------*/ +QDF_STATUS sme_open_session(tHalHandle hHal, csr_roam_completeCallback callback, + void *pContext, + uint8_t *pSelfMacAddr, uint8_t *pbSessionId, + uint32_t type, uint32_t subType) +{ + QDF_STATUS status = QDF_STATUS_E_INVAL; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + ol_txrx_pdev_handle pdev; + ol_txrx_peer_handle peer; + uint8_t peer_id; + + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: type=%d, subType=%d addr:%pM", + __func__, type, subType, pSelfMacAddr); + + pdev = cds_get_context(QDF_MODULE_ID_TXRX); + + if (NULL == pdev) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_ERROR, + "%s: Failed to get pdev handler", __func__); + return status; + } + + if (pbSessionId) { + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + peer = ol_txrx_find_peer_by_addr(pdev, pSelfMacAddr, + &peer_id); + if (peer) { + + QDF_TRACE(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_ERROR, + "%s: Peer=%d exist with same MAC", + __func__, peer_id); + + status = QDF_STATUS_E_INVAL; + + } else { + status = csr_roam_open_session(pMac, callback, pContext, + pSelfMacAddr, pbSessionId, type, subType); + } + + sme_release_global_lock(&pMac->sme); + } + } + if (NULL != pbSessionId) + MTRACE(qdf_trace(QDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_OPEN_SESSION, + *pbSessionId, 0)); + + return status; +} + +/*-------------------------------------------------------------------------- + + \brief sme_close_session() - Open a session for scan/roam operation. + + This is a synchronous API. + + \param hHal - The handle returned by mac_open. + + \param sessionId - A previous opened session's ID. + + \return QDF_STATUS_SUCCESS - session is closed. + + Other status means SME is failed to open the session. + QDF_STATUS_E_INVAL - session is not opened. + \sa + + --------------------------------------------------------------------------*/ +QDF_STATUS sme_close_session(tHalHandle hHal, uint8_t sessionId, + csr_roamSessionCloseCallback callback, + void *pContext) +{ + QDF_STATUS status; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + MTRACE(qdf_trace(QDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_CLOSE_SESSION, sessionId, 0)); + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + status = csr_roam_close_session(pMac, sessionId, false, + callback, pContext); + + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +/* --------------------------------------------------------------------------- + + \fn sme_roam_update_apwpsie + + \brief To update AP's WPS IE. This function should be called after SME AP session is created + This is an asynchronous API. + + \param pAPWPSIES - pointer to a caller allocated object of tSirAPWPSIEs + + \return QDF_STATUS – SUCCESS – + + FAILURE or RESOURCES – The API finished and failed. + + -------------------------------------------------------------------------------*/ +QDF_STATUS sme_roam_update_apwpsie(tHalHandle hHal, uint8_t sessionId, + tSirAPWPSIEs *pAPWPSIES) +{ + + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + + status = csr_roam_update_apwpsie(pMac, sessionId, pAPWPSIES); + + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +/* --------------------------------------------------------------------------- + + \fn sme_roam_update_apwparsni_es + + \brief To update AP's WPA/RSN IEs. This function should be called after SME AP session is created + This is an asynchronous API. + + \param pAPSirRSNie - pointer to a caller allocated object of tSirRSNie with WPS/RSN IEs + + \return QDF_STATUS – SUCCESS – + + FAILURE or RESOURCES – The API finished and failed. + + -------------------------------------------------------------------------------*/ +QDF_STATUS sme_roam_update_apwparsni_es(tHalHandle hHal, uint8_t sessionId, + tSirRSNie *pAPSirRSNie) +{ + + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + + status = csr_roam_update_wparsni_es(pMac, sessionId, pAPSirRSNie); + + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +/* --------------------------------------------------------------------------- + + \fn sme_change_mcc_beacon_interval + + \brief To update P2P-GO beaconInterval. This function should be called after + disassociating all the station is done + This is an asynchronous API. + + \param + + \return QDF_STATUS SUCCESS + FAILURE or RESOURCES + The API finished and failed. + + -------------------------------------------------------------------------------*/ +QDF_STATUS sme_change_mcc_beacon_interval(tHalHandle hHal, uint8_t sessionId) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + sms_log(pMac, LOG1, FL("Update Beacon PARAMS ")); + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + status = csr_send_chng_mcc_beacon_interval(pMac, sessionId); + sme_release_global_lock(&pMac->sme); + } + return status; +} + +/** + * sme_set_host_offload(): API to set the host offload feature. + * @hHal: The handle returned by mac_open. + * @sessionId: Session Identifier + * @request: Pointer to the offload request. + * + * Return QDF_STATUS + */ +QDF_STATUS sme_set_host_offload(tHalHandle hHal, uint8_t sessionId, + tpSirHostOffloadReq request) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + QDF_STATUS status = QDF_STATUS_E_FAILURE; + + MTRACE(qdf_trace(QDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_SET_HOSTOFFLOAD, sessionId, 0)); + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { +#ifdef WLAN_NS_OFFLOAD + if (SIR_IPV6_NS_OFFLOAD == request->offloadType) { + status = sme_set_ps_ns_offload(hHal, request, + sessionId); + } else +#endif /* WLAN_NS_OFFLOAD */ + { + status = sme_set_ps_host_offload(hHal, request, + sessionId); + } + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +QDF_STATUS sme_conf_hw_filter_mode(tHalHandle hal, uint8_t session_id, + uint8_t mode_bitmap) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hal); + QDF_STATUS status; + tCsrRoamSession *session; + struct hw_filter_request *req; + cds_msg_t msg; + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_ERROR(status)) { + sme_err("sme_acquire_global_lock failed"); + return status; + } + + session = CSR_GET_SESSION(pMac, session_id); + if (!session) { + sme_release_global_lock(&pMac->sme); + sme_err("Session not found"); + return QDF_STATUS_E_FAILURE; + } + + req = qdf_mem_malloc(sizeof(*req)); + if (!req) { + sme_release_global_lock(&pMac->sme); + sme_err("Out of memory"); + return QDF_STATUS_E_NOMEM; + } + + req->mode_bitmap = mode_bitmap; + qdf_copy_macaddr(&req->bssid, &session->connectedProfile.bssid); + + msg.type = WMA_CONF_HW_FILTER; + msg.reserved = 0; + msg.bodyptr = req; + MTRACE(qdf_trace(QDF_MODULE_ID_SME, TRACE_CODE_SME_TX_WMA_MSG, + session_id, msg.type)); + + status = cds_mq_post_message(QDF_MODULE_ID_WMA, &msg); + sme_release_global_lock(&pMac->sme); + if (QDF_IS_STATUS_ERROR(status)) { + sme_err("Failed to post WMA_CONF_HW_FILTER message"); + qdf_mem_free(req); + } + + return status; +} + +#ifdef WLAN_FEATURE_GTK_OFFLOAD +/** + * sme_set_gtk_offload(): API to set GTK offload information. + * @hHal: The handle returned by mac_open. + * @sessionId: Session Identifier + * @pGtkOffload: Pointer to the GTK offload request.. + * + * Return QDF_STATUS + */ +QDF_STATUS sme_set_gtk_offload(tHalHandle hHal, + tpSirGtkOffloadParams pGtkOffload, + uint8_t sessionId) +{ + tpSirGtkOffloadParams request_buf; + cds_msg_t msg; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + + QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO, + "%s: KeyReplayCounter: 0x%llx", __func__, + pGtkOffload->ullKeyReplayCounter); + + if (NULL == pSession) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Session not found ", __func__); + return QDF_STATUS_E_FAILURE; + } + + request_buf = qdf_mem_malloc(sizeof(*request_buf)); + if (NULL == request_buf) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Not able to allocate memory for GTK offload request")); + return QDF_STATUS_E_NOMEM; + } + + qdf_copy_macaddr(&pGtkOffload->bssid, + &pSession->connectedProfile.bssid); + + *request_buf = *pGtkOffload; + + msg.type = WMA_GTK_OFFLOAD_REQ; + msg.reserved = 0; + msg.bodyptr = request_buf; + MTRACE(qdf_trace(QDF_MODULE_ID_SME, TRACE_CODE_SME_TX_WMA_MSG, + sessionId, msg.type)); + if (!QDF_IS_STATUS_SUCCESS + (cds_mq_post_message(QDF_MODULE_ID_WMA, &msg))) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Not able to post SIR_HAL_SET_GTK_OFFLOAD message to HAL")); + qdf_mem_free(request_buf); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * sme_get_gtk_offload(): API to get GTK offload information + * @hHal: The handle returned by mac_open. + * @callback_routine: callback_routine. + * @sessionId: Session Identifier. + * callback_context: callback_context. + * + * Return QDF_STATUS + */ +QDF_STATUS sme_get_gtk_offload(tHalHandle hHal, + gtk_offload_get_info_callback callback_routine, + void *callback_context, uint8_t session_id) +{ + tpSirGtkOffloadGetInfoRspParams request_buf; + cds_msg_t msg; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, session_id); + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO, "%s: Entered", + __func__); + + if (NULL == pSession) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Session not found", __func__); + return QDF_STATUS_E_FAILURE; + } + + request_buf = qdf_mem_malloc(sizeof(*request_buf)); + if (NULL == request_buf) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Not able to allocate memory for Get GTK offload request")); + return QDF_STATUS_E_NOMEM; + } + + qdf_copy_macaddr(&request_buf->bssid, + &pSession->connectedProfile.bssid); + + msg.type = WMA_GTK_OFFLOAD_GETINFO_REQ; + msg.reserved = 0; + msg.bodyptr = request_buf; + + /* Cache the Get GTK Offload callback information */ + if (NULL != pMac->sme.gtk_offload_get_info_cb) { + + /* Do we need to check if the callback is in use? */ + /* Because we are not sending the same message again + * when it is pending, + * the only case when the callback is not NULL is that + * the previous message was timed out or failed. + * So, it will be safe to set the callback in this case. + */ + } + + pMac->sme.gtk_offload_get_info_cb = callback_routine; + pMac->sme.gtk_offload_get_info_cb_context = callback_context; + MTRACE(qdf_trace(QDF_MODULE_ID_SME, TRACE_CODE_SME_TX_WMA_MSG, + session_id, msg.type)); + if (!QDF_IS_STATUS_SUCCESS + (cds_mq_post_message(QDF_MODULE_ID_WMA, &msg))) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Not able to post WMA_GTK_OFFLOAD_GETINFO_REQ message to WMA")); + qdf_mem_free(request_buf); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} +#endif /* WLAN_FEATURE_GTK_OFFLOAD */ + +/* --------------------------------------------------------------------------- + \fn sme_set_keep_alive + \brief API to set the Keep Alive feature. + \param hHal - The handle returned by mac_open. + \param request - Pointer to the Keep Alive request. + \return QDF_STATUS + ---------------------------------------------------------------------------*/ +QDF_STATUS sme_set_keep_alive(tHalHandle hHal, uint8_t session_id, + tpSirKeepAliveReq request) +{ + tpSirKeepAliveReq request_buf; + cds_msg_t msg; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, session_id); + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO_LOW, + FL("WMA_SET_KEEP_ALIVE message")); + + if (pSession == NULL) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Session not Found")); + return QDF_STATUS_E_FAILURE; + } + request_buf = qdf_mem_malloc(sizeof(tSirKeepAliveReq)); + if (NULL == request_buf) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Not able to allocate memory for keep alive request")); + return QDF_STATUS_E_NOMEM; + } + + qdf_copy_macaddr(&request->bssid, &pSession->connectedProfile.bssid); + qdf_mem_copy(request_buf, request, sizeof(tSirKeepAliveReq)); + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO_LOW, + "buff TP %d input TP %d ", request_buf->timePeriod, + request->timePeriod); + request_buf->sessionId = session_id; + + msg.type = WMA_SET_KEEP_ALIVE; + msg.reserved = 0; + msg.bodyptr = request_buf; + MTRACE(qdf_trace(QDF_MODULE_ID_SME, TRACE_CODE_SME_TX_WMA_MSG, + session_id, msg.type)); + if (QDF_STATUS_SUCCESS != + cds_mq_post_message(QDF_MODULE_ID_WMA, &msg)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Not able to post WMA_SET_KEEP_ALIVE message to WMA")); + qdf_mem_free(request_buf); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +#ifdef FEATURE_WLAN_SCAN_PNO +/* --------------------------------------------------------------------------- + \fn sme_set_preferred_network_list + \brief API to set the Preferred Network List Offload feature. + \param hHal - The handle returned by mac_open. + \param request - Pointer to the offload request. + \return QDF_STATUS + ---------------------------------------------------------------------------*/ +QDF_STATUS sme_set_preferred_network_list(tHalHandle hHal, + tpSirPNOScanReq request, + uint8_t sessionId, + void (*callback_routine)(void *callback_context, + tSirPrefNetworkFoundInd + *pPrefNetworkFoundInd), + void *callback_context) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + QDF_STATUS status; + + MTRACE(qdf_trace(QDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_PREF_NET_LIST, + sessionId, request->ucNetworksCount)); + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + status = sme_set_ps_preferred_network_list(hHal, request, + sessionId, + callback_routine, + callback_context); + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +#endif /* FEATURE_WLAN_SCAN_PNO */ + +QDF_STATUS sme_abort_mac_scan(tHalHandle hHal, uint8_t sessionId, + uint32_t scan_id, eCsrAbortReason reason) +{ + QDF_STATUS status; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + MTRACE(qdf_trace(QDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_ABORT_MACSCAN, NO_SESSION, 0)); + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + status = csr_scan_abort_mac_scan(pMac, sessionId, + scan_id, reason); + + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +/* ---------------------------------------------------------------------------- + \fn sme_get_operation_channel + \brief API to get current channel on which STA is parked + this function gives channel information only of infra station or IBSS station + \param hHal, pointer to memory location and sessionId + \returns QDF_STATUS_SUCCESS + QDF_STATUS_E_FAILURE + -------------------------------------------------------------------------------*/ +QDF_STATUS sme_get_operation_channel(tHalHandle hHal, uint32_t *pChannel, + uint8_t sessionId) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + tCsrRoamSession *pSession; + + if (CSR_IS_SESSION_VALID(pMac, sessionId)) { + pSession = CSR_GET_SESSION(pMac, sessionId); + + if ((pSession->connectedProfile.BSSType == + eCSR_BSS_TYPE_INFRASTRUCTURE) + || (pSession->connectedProfile.BSSType == + eCSR_BSS_TYPE_IBSS) + || (pSession->connectedProfile.BSSType == + eCSR_BSS_TYPE_INFRA_AP) + || (pSession->connectedProfile.BSSType == + eCSR_BSS_TYPE_START_IBSS)) { + *pChannel = pSession->connectedProfile.operationChannel; + return QDF_STATUS_SUCCESS; + } + } + return QDF_STATUS_E_FAILURE; +} /* sme_get_operation_channel ends here */ + +/** + * sme_register_p2p_ack_ind_callback() - p2p ack indication callback + * @hal: hal pointer + * @callback: callback pointer to be registered + * + * This function is used to register a callback to PE for p2p ack + * indication + * + * Return: Success if msg is posted to PE else Failure. + */ +QDF_STATUS sme_register_p2p_ack_ind_callback(tHalHandle hal, + sir_p2p_ack_ind_callback callback) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + struct sir_sme_p2p_ack_ind_cb_req *msg; + QDF_STATUS status = QDF_STATUS_SUCCESS; + sms_log(mac_ctx, LOG1, FL(": ENTER")); + status = sme_acquire_global_lock(&mac_ctx->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + msg = qdf_mem_malloc(sizeof(*msg)); + if (NULL == msg) { + sms_log(mac_ctx, LOGE, + FL("Failed to allocate memory")); + sme_release_global_lock(&mac_ctx->sme); + return QDF_STATUS_E_NOMEM; + } + msg->message_type = eWNI_SME_REGISTER_P2P_ACK_CB; + msg->length = sizeof(*msg); + + msg->callback = callback; + status = cds_send_mb_message_to_mac(msg); + sme_release_global_lock(&mac_ctx->sme); + return status; + } + return status; +} + +/** + * sme_register_mgmt_frame_ind_callback() - Register a callback for + * management frame indication to PE. + * + * @hal: hal pointer + * @callback: callback pointer to be registered + * + * This function is used to register a callback for management + * frame indication to PE. + * + * Return: Success if msg is posted to PE else Failure. + */ +QDF_STATUS sme_register_mgmt_frame_ind_callback(tHalHandle hal, + sir_mgmt_frame_ind_callback callback) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + struct sir_sme_mgmt_frame_cb_req *msg; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + sms_log(mac_ctx, LOG1, FL(": ENTER")); + + if (QDF_STATUS_SUCCESS == + sme_acquire_global_lock(&mac_ctx->sme)) { + msg = qdf_mem_malloc(sizeof(*msg)); + if (NULL == msg) { + sms_log(mac_ctx, LOGE, + FL("Not able to allocate memory for eWNI_SME_REGISTER_MGMT_FRAME_CB")); + sme_release_global_lock(&mac_ctx->sme); + return QDF_STATUS_E_NOMEM; + } + msg->message_type = eWNI_SME_REGISTER_MGMT_FRAME_CB; + msg->length = sizeof(*msg); + + msg->callback = callback; + status = cds_send_mb_message_to_mac(msg); + sme_release_global_lock(&mac_ctx->sme); + return status; + } + return QDF_STATUS_E_FAILURE; +} + +/* --------------------------------------------------------------------------- + + \fn sme_RegisterMgtFrame + + \brief To register managment frame of specified type and subtype. + \param frameType - type of the frame that needs to be passed to HDD. + \param matchData - data which needs to be matched before passing frame + to HDD. + \param matchDataLen - Length of matched data. + \return QDF_STATUS + -------------------------------------------------------------------------------*/ +QDF_STATUS sme_register_mgmt_frame(tHalHandle hHal, uint8_t sessionId, + uint16_t frameType, uint8_t *matchData, + uint16_t matchLen) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + tSirRegisterMgmtFrame *pMsg; + uint16_t len; + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!CSR_IS_SESSION_ANY(sessionId) && !pSession) { + sms_log(pMac, LOGE, FL(" session %d not found "), + sessionId); + sme_release_global_lock(&pMac->sme); + return QDF_STATUS_E_FAILURE; + } + + if (!CSR_IS_SESSION_ANY(sessionId) && !pSession->sessionActive) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s Invalid Sessionid", __func__); + sme_release_global_lock(&pMac->sme); + return QDF_STATUS_E_FAILURE; + } + + len = sizeof(tSirRegisterMgmtFrame) + matchLen; + + pMsg = qdf_mem_malloc(len); + if (NULL == pMsg) + status = QDF_STATUS_E_NOMEM; + else { + pMsg->messageType = eWNI_SME_REGISTER_MGMT_FRAME_REQ; + pMsg->length = len; + pMsg->sessionId = sessionId; + pMsg->registerFrame = true; + pMsg->frameType = frameType; + pMsg->matchLen = matchLen; + qdf_mem_copy(pMsg->matchData, matchData, matchLen); + status = cds_send_mb_message_to_mac(pMsg); + } + sme_release_global_lock(&pMac->sme); + } + return status; +} + +/* --------------------------------------------------------------------------- + + \fn sme_DeregisterMgtFrame + + \brief To De-register managment frame of specified type and subtype. + \param frameType - type of the frame that needs to be passed to HDD. + \param matchData - data which needs to be matched before passing frame + to HDD. + \param matchDataLen - Length of matched data. + \return QDF_STATUS + -------------------------------------------------------------------------------*/ +QDF_STATUS sme_deregister_mgmt_frame(tHalHandle hHal, uint8_t sessionId, + uint16_t frameType, uint8_t *matchData, + uint16_t matchLen) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + MTRACE(qdf_trace(QDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_DEREGISTER_MGMTFR, sessionId, + 0)); + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + tSirRegisterMgmtFrame *pMsg; + uint16_t len; + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!CSR_IS_SESSION_ANY(sessionId) && !pSession) { + sms_log(pMac, LOGE, FL(" session %d not found "), + sessionId); + sme_release_global_lock(&pMac->sme); + return QDF_STATUS_E_FAILURE; + } + + if (!CSR_IS_SESSION_ANY(sessionId) && !pSession->sessionActive) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s Invalid Sessionid", __func__); + sme_release_global_lock(&pMac->sme); + return QDF_STATUS_E_FAILURE; + } + + len = sizeof(tSirRegisterMgmtFrame) + matchLen; + + pMsg = qdf_mem_malloc(len); + if (NULL == pMsg) + status = QDF_STATUS_E_NOMEM; + else { + pMsg->messageType = eWNI_SME_REGISTER_MGMT_FRAME_REQ; + pMsg->length = len; + pMsg->registerFrame = false; + pMsg->frameType = frameType; + pMsg->matchLen = matchLen; + qdf_mem_copy(pMsg->matchData, matchData, matchLen); + status = cds_send_mb_message_to_mac(pMsg); + } + sme_release_global_lock(&pMac->sme); + } + return status; +} + +/** + * sme_remain_on_channel - API to request remain on channel for 'x' duration + * + * @hHal: pointer to MAC handle + * @session_id: Session identifier + * @channel: channel information + * @duration: duration in ms + * @callback: HDD registered callback to process reaminOnChannelRsp + * @context: HDD Callback param + * @scan_id: scan identifier + * + * This function process the roc request and generates scan identifier.s + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_remain_on_channel(tHalHandle hHal, uint8_t session_id, + uint8_t channel, uint32_t duration, + remainOnChanCallback callback, + void *pContext, uint8_t isP2PProbeReqAllowed, + uint32_t *scan_id) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hHal); + uint32_t san_req_id, scan_count; + struct ani_roc_req *roc_msg; + cds_msg_t msg; + + + MTRACE(qdf_trace(QDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_REMAIN_ONCHAN, session_id, 0)); + + scan_count = csr_ll_count(&mac_ctx->sme.smeScanCmdActiveList); + if (scan_count >= mac_ctx->scan.max_scan_count) { + sms_log(mac_ctx, LOGE, FL("Max scan reached")); + return QDF_STATUS_E_FAILURE; + } + + wma_get_scan_id(&san_req_id); + *scan_id = san_req_id; + status = sme_acquire_global_lock(&mac_ctx->sme); + + sms_log(mac_ctx, LOG1, FL(" called")); + roc_msg = qdf_mem_malloc(sizeof(struct ani_roc_req)); + if (NULL == roc_msg) { + sms_log(mac_ctx, LOGE, + " scan_req: failed to allocate mem for msg"); + sme_release_global_lock(&mac_ctx->sme); + return QDF_STATUS_E_NOMEM; + } + roc_msg->msg_type = eWNI_SME_ROC_CMD; + roc_msg->msg_len = (uint16_t) sizeof(struct ani_roc_req); + roc_msg->session_id = session_id; + roc_msg->callback = callback; + roc_msg->duration = duration; + roc_msg->channel = channel; + roc_msg->is_p2pprobe_allowed = isP2PProbeReqAllowed; + roc_msg->ctx = pContext; + roc_msg->scan_id = *scan_id; + msg.type = eWNI_SME_ROC_CMD; + msg.bodyptr = roc_msg; + msg.reserved = 0; + msg.bodyval = 0; + if (QDF_STATUS_SUCCESS != + cds_mq_post_message(CDS_MQ_ID_SME, &msg)) { + sms_log(mac_ctx, LOGE, + " sme_scan_req failed to post msg"); + qdf_mem_free(roc_msg); + status = QDF_STATUS_E_FAILURE; + } + sme_release_global_lock(&mac_ctx->sme); + return status; +} + +/* --------------------------------------------------------------------------- + \fn sme_report_probe_req + \brief API to enable/disable forwarding of probeReq to apps in p2p. + \param hHal - The handle returned by mac_open. + \param falg: to set the Probe request forarding to wpa_supplicant in listen state in p2p + \return QDF_STATUS + ---------------------------------------------------------------------------*/ + +#ifndef WLAN_FEATURE_CONCURRENT_P2P +QDF_STATUS sme_report_probe_req(tHalHandle hHal, uint8_t flag) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + do { + /* acquire the lock for the sme object */ + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + /* call set in context */ + pMac->p2pContext.probeReqForwarding = flag; + /* release the lock for the sme object */ + sme_release_global_lock(&pMac->sme); + } + } while (0); + + sms_log(pMac, LOGW, "exiting function %s", __func__); + + return status; +} + +/* --------------------------------------------------------------------------- + \fn sme_update_p2p_ie + \brief API to set the P2p Ie in p2p context + \param hHal - The handle returned by mac_open. + \param p2pIe - Ptr to p2pIe from HDD. + \param p2pIeLength: length of p2pIe + \return QDF_STATUS + ---------------------------------------------------------------------------*/ + +QDF_STATUS sme_update_p2p_ie(tHalHandle hHal, void *p2pIe, uint32_t p2pIeLength) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + MTRACE(qdf_trace(QDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_UPDATE_P2P_IE, NO_SESSION, 0)); + /* acquire the lock for the sme object */ + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + if (NULL != pMac->p2pContext.probeRspIe) { + qdf_mem_free(pMac->p2pContext.probeRspIe); + pMac->p2pContext.probeRspIeLength = 0; + } + + pMac->p2pContext.probeRspIe = qdf_mem_malloc(p2pIeLength); + if (NULL == pMac->p2pContext.probeRspIe) { + sms_log(pMac, LOGE, "%s: Unable to allocate P2P IE", + __func__); + pMac->p2pContext.probeRspIeLength = 0; + status = QDF_STATUS_E_NOMEM; + } else { + pMac->p2pContext.probeRspIeLength = p2pIeLength; + + sir_dump_buf(pMac, SIR_LIM_MODULE_ID, LOG2, + pMac->p2pContext.probeRspIe, + pMac->p2pContext.probeRspIeLength); + qdf_mem_copy((uint8_t *) pMac->p2pContext.probeRspIe, + p2pIe, p2pIeLength); + } + + /* release the lock for the sme object */ + sme_release_global_lock(&pMac->sme); + } + + sms_log(pMac, LOG2, "exiting function %s", __func__); + + return status; +} +#endif + +/* --------------------------------------------------------------------------- + \fn sme_send_action + \brief API to send action frame from supplicant. + \param hHal - The handle returned by mac_open. + \return QDF_STATUS + ---------------------------------------------------------------------------*/ + +QDF_STATUS sme_send_action(tHalHandle hHal, uint8_t sessionId, + const uint8_t *pBuf, uint32_t len, + uint16_t wait, bool noack, + uint16_t channel_freq) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + MTRACE(qdf_trace(QDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_SEND_ACTION, sessionId, 0)); + /* acquire the lock for the sme object */ + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + p2p_send_action(hHal, sessionId, pBuf, len, wait, noack, + channel_freq); + /* release the lock for the sme object */ + sme_release_global_lock(&pMac->sme); + } + + sms_log(pMac, LOGW, "exiting function %s", __func__); + + return status; +} + +QDF_STATUS sme_cancel_remain_on_channel(tHalHandle hHal, + uint8_t sessionId, uint32_t scan_id) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + MTRACE(qdf_trace(QDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_CANCEL_REMAIN_ONCHAN, sessionId, + 0)); + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + status = p2p_cancel_remain_on_channel(hHal, sessionId, scan_id); + sme_release_global_lock(&pMac->sme); + } + return status; +} + +/* Power Save Related */ +QDF_STATUS sme_p2p_set_ps(tHalHandle hHal, tP2pPsConfig *data) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + status = p2p_set_ps(hHal, data); + sme_release_global_lock(&pMac->sme); + } + return status; +} + +/* --------------------------------------------------------------------------- + + \fn sme_configure_suspend_ind + + \brief + SME will pass this request to lower mac to Indicate that the wlan needs to + be suspended + + \param + + hHal - The handle returned by mac_open. + + wlanSuspendParam- Depicts the wlan suspend params + + csr_readyToSuspendCallback - Callback to be called when ready to suspend + event is received. + callback_context - Context associated with csr_readyToSuspendCallback. + + \return QDF_STATUS + + --------------------------------------------------------------------------- */ +QDF_STATUS sme_configure_suspend_ind(tHalHandle hHal, + uint32_t conn_state_mask, + csr_readyToSuspendCallback callback, + void *callback_context) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + cds_msg_t cds_message = {0}; + + MTRACE(qdf_trace(QDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_CONFIG_SUSPENDIND, NO_SESSION, + 0)); + + pMac->readyToSuspendCallback = callback; + pMac->readyToSuspendContext = callback_context; + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + /* serialize the req through MC thread */ + cds_message.bodyval = conn_state_mask; + cds_message.type = WMA_WLAN_SUSPEND_IND; + MTRACE(qdf_trace(QDF_MODULE_ID_SME, TRACE_CODE_SME_TX_WMA_MSG, + NO_SESSION, cds_message.type)); + qdf_status = cds_mq_post_message(CDS_MQ_ID_WMA, &cds_message); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + pMac->readyToSuspendCallback = NULL; + pMac->readyToSuspendContext = NULL; + status = QDF_STATUS_E_FAILURE; + } + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +/* --------------------------------------------------------------------------- + + \fn sme_configure_resume_req + + \brief + SME will pass this request to lower mac to Indicate that the wlan needs to + be Resumed + + \param + + hHal - The handle returned by mac_open. + + wlanResumeParam- Depicts the wlan resume params + + \return QDF_STATUS + + --------------------------------------------------------------------------- */ +QDF_STATUS sme_configure_resume_req(tHalHandle hHal, + tpSirWlanResumeParam wlanResumeParam) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + cds_msg_t cds_message; + + MTRACE(qdf_trace(QDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_CONFIG_RESUMEREQ, NO_SESSION, + 0)); + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + /* serialize the req through MC thread */ + cds_message.bodyptr = wlanResumeParam; + cds_message.type = WMA_WLAN_RESUME_REQ; + MTRACE(qdf_trace(QDF_MODULE_ID_SME, TRACE_CODE_SME_TX_WMA_MSG, + NO_SESSION, cds_message.type)); + qdf_status = cds_mq_post_message(CDS_MQ_ID_WMA, &cds_message); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + status = QDF_STATUS_E_FAILURE; + } + sme_release_global_lock(&pMac->sme); + } + return status; +} + +#ifdef WLAN_FEATURE_EXTWOW_SUPPORT +/** + * sme_configure_ext_wow() - configure Extr WoW + * @hHal - The handle returned by mac_open. + * @wlanExtParams - Depicts the wlan Ext params. + * @callback - ext_wow callback to be registered. + * @callback_context - ext_wow callback context + * + * SME will pass this request to lower mac to configure Extr WoW + * Return: QDF_STATUS + */ +QDF_STATUS sme_configure_ext_wow(tHalHandle hHal, + tpSirExtWoWParams wlanExtParams, + csr_readyToExtWoWCallback callback, + void *callback_context) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + cds_msg_t cds_message; + tpSirExtWoWParams MsgPtr = qdf_mem_malloc(sizeof(*MsgPtr)); + + if (!MsgPtr) + return QDF_STATUS_E_NOMEM; + + MTRACE(qdf_trace(QDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_CONFIG_EXTWOW, NO_SESSION, 0)); + + pMac->readyToExtWoWCallback = callback; + pMac->readyToExtWoWContext = callback_context; + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + + /* serialize the req through MC thread */ + qdf_mem_copy(MsgPtr, wlanExtParams, sizeof(*MsgPtr)); + cds_message.bodyptr = MsgPtr; + cds_message.type = WMA_WLAN_EXT_WOW; + qdf_status = cds_mq_post_message(CDS_MQ_ID_WMA, &cds_message); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + pMac->readyToExtWoWCallback = NULL; + pMac->readyToExtWoWContext = NULL; + qdf_mem_free(MsgPtr); + status = QDF_STATUS_E_FAILURE; + } + sme_release_global_lock(&pMac->sme); + } else { + pMac->readyToExtWoWCallback = NULL; + pMac->readyToExtWoWContext = NULL; + qdf_mem_free(MsgPtr); + } + + return status; +} + +/* --------------------------------------------------------------------------- + + \fn sme_configure_app_type1_params + + \brief + SME will pass this request to lower mac to configure Indoor WoW parameters. + + \param + + hHal - The handle returned by mac_open. + + wlanAppType1Params- Depicts the wlan App Type 1(Indoor) params + + \return QDF_STATUS + + --------------------------------------------------------------------------- */ +QDF_STATUS sme_configure_app_type1_params(tHalHandle hHal, + tpSirAppType1Params wlanAppType1Params) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + cds_msg_t cds_message; + tpSirAppType1Params MsgPtr = qdf_mem_malloc(sizeof(*MsgPtr)); + + if (!MsgPtr) + return QDF_STATUS_E_NOMEM; + + MTRACE(qdf_trace(QDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_CONFIG_APP_TYPE1, NO_SESSION, + 0)); + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + /* serialize the req through MC thread */ + qdf_mem_copy(MsgPtr, wlanAppType1Params, sizeof(*MsgPtr)); + cds_message.bodyptr = MsgPtr; + cds_message.type = WMA_WLAN_SET_APP_TYPE1_PARAMS; + qdf_status = cds_mq_post_message(CDS_MQ_ID_WMA, &cds_message); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + qdf_mem_free(MsgPtr); + status = QDF_STATUS_E_FAILURE; + } + sme_release_global_lock(&pMac->sme); + } else { + qdf_mem_free(MsgPtr); + } + + return status; +} + +/* --------------------------------------------------------------------------- + + \fn sme_configure_app_type2_params + + \brief + SME will pass this request to lower mac to configure Indoor WoW parameters. + + \param + + hHal - The handle returned by mac_open. + + wlanAppType2Params- Depicts the wlan App Type 2 (Outdoor) params + + \return QDF_STATUS + + --------------------------------------------------------------------------- */ +QDF_STATUS sme_configure_app_type2_params(tHalHandle hHal, + tpSirAppType2Params wlanAppType2Params) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + cds_msg_t cds_message; + tpSirAppType2Params MsgPtr = qdf_mem_malloc(sizeof(*MsgPtr)); + + if (!MsgPtr) + return QDF_STATUS_E_NOMEM; + + MTRACE(qdf_trace(QDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_CONFIG_APP_TYPE2, NO_SESSION, + 0)); + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + /* serialize the req through MC thread */ + qdf_mem_copy(MsgPtr, wlanAppType2Params, sizeof(*MsgPtr)); + cds_message.bodyptr = MsgPtr; + cds_message.type = WMA_WLAN_SET_APP_TYPE2_PARAMS; + qdf_status = cds_mq_post_message(CDS_MQ_ID_WMA, &cds_message); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + qdf_mem_free(MsgPtr); + status = QDF_STATUS_E_FAILURE; + } + sme_release_global_lock(&pMac->sme); + } else { + qdf_mem_free(MsgPtr); + } + + return status; +} +#endif + +/* --------------------------------------------------------------------------- + + \fn sme_get_infra_session_id + + \brief To get the session ID for infra session, if connected + This is a synchronous API. + + \param hHal - The handle returned by mac_open. + + \return sessionid, -1 if infra session is not connected + + -------------------------------------------------------------------------------*/ +int8_t sme_get_infra_session_id(tHalHandle hHal) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + int8_t sessionid = -1; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + + sessionid = csr_get_infra_session_id(pMac); + + sme_release_global_lock(&pMac->sme); + } + + return sessionid; +} + +/* --------------------------------------------------------------------------- + + \fn sme_get_infra_operation_channel + + \brief To get the operating channel for infra session, if connected + This is a synchronous API. + + \param hHal - The handle returned by mac_open. + \param sessionId - the sessionId returned by sme_open_session. + + \return operating channel, 0 if infra session is not connected + + -------------------------------------------------------------------------------*/ +uint8_t sme_get_infra_operation_channel(tHalHandle hHal, uint8_t sessionId) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + uint8_t channel = 0; + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + + channel = csr_get_infra_operation_channel(pMac, sessionId); + + sme_release_global_lock(&pMac->sme); + } + + return channel; +} + +/* This routine will return poerating channel on which other BSS is operating to be used for concurrency mode. */ +/* If other BSS is not up or not connected it will return 0 */ +uint8_t sme_get_concurrent_operation_channel(tHalHandle hHal) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + uint8_t channel = 0; + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + + channel = csr_get_concurrent_operation_channel(pMac); + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO_HIGH, "%s: " + " Other Concurrent Channel = %d", __func__, channel); + sme_release_global_lock(&pMac->sme); + } + + return channel; +} + +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH +uint16_t sme_check_concurrent_channel_overlap(tHalHandle hHal, uint16_t sap_ch, + eCsrPhyMode sapPhyMode, + uint8_t cc_switch_mode) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + uint16_t channel = 0; + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + channel = + csr_check_concurrent_channel_overlap(pMac, sap_ch, sapPhyMode, + cc_switch_mode); + sme_release_global_lock(&pMac->sme); + } + + return channel; +} +#endif + +#ifdef FEATURE_WLAN_SCAN_PNO +/** + * sme_update_roam_pno_channel_prediction_config() - Update PNO config + * @csr_config: config from SME context + * @hal: Global Hal handle + * @copy_from_to: Used to specify the source and destination + * + * Copy the PNO channel prediction configuration parameters from + * SME context to MAC context or vice-versa + * + * Return: None + */ +void sme_update_roam_pno_channel_prediction_config( + tHalHandle hal, tCsrConfigParam *csr_config, + uint8_t copy_from_to) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + if (copy_from_to == SME_CONFIG_TO_ROAM_CONFIG) { + mac_ctx->roam.configParam.pno_channel_prediction = + csr_config->pno_channel_prediction; + mac_ctx->roam.configParam.top_k_num_of_channels = + csr_config->top_k_num_of_channels; + mac_ctx->roam.configParam.stationary_thresh = + csr_config->stationary_thresh; + mac_ctx->roam.configParam.channel_prediction_full_scan = + csr_config->channel_prediction_full_scan; + mac_ctx->roam.configParam.pnoscan_adaptive_dwell_mode = + csr_config->pnoscan_adaptive_dwell_mode; + } else if (copy_from_to == ROAM_CONFIG_TO_SME_CONFIG) { + csr_config->pno_channel_prediction = + mac_ctx->roam.configParam.pno_channel_prediction; + csr_config->top_k_num_of_channels = + mac_ctx->roam.configParam.top_k_num_of_channels; + csr_config->stationary_thresh = + mac_ctx->roam.configParam.stationary_thresh; + csr_config->channel_prediction_full_scan = + mac_ctx->roam.configParam.channel_prediction_full_scan; + csr_config->pnoscan_adaptive_dwell_mode = + mac_ctx->roam.configParam.pnoscan_adaptive_dwell_mode; + } + +} +/****************************************************************************** +* +* Name: sme_preferred_network_found_ind +* +* Description: +* Invoke Preferred Network Found Indication +* +* Parameters: +* hHal - HAL handle for device +* pMsg - found network description +* +* Returns: QDF_STATUS +* +******************************************************************************/ +QDF_STATUS sme_preferred_network_found_ind(tHalHandle hHal, void *pMsg) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + QDF_STATUS status = QDF_STATUS_SUCCESS; + tSirPrefNetworkFoundInd *pPrefNetworkFoundInd = + (tSirPrefNetworkFoundInd *) pMsg; + uint8_t dumpSsId[SIR_MAC_MAX_SSID_LENGTH + 1]; + uint8_t ssIdLength = 0; + + if (NULL == pMsg) { + sms_log(pMac, LOGE, "in %s msg ptr is NULL", __func__); + return QDF_STATUS_E_FAILURE; + } + + if (pMac->pnoOffload) { + /* Call Preferred Network Found Indication callback routine. */ + if (pMac->sme.pref_netw_found_cb != NULL) { + pMac->sme.pref_netw_found_cb(pMac->sme. + preferred_network_found_ind_cb_ctx, + pPrefNetworkFoundInd); + } + return status; + } + + if (pPrefNetworkFoundInd->ssId.length > 0) { + ssIdLength = CSR_MIN(SIR_MAC_MAX_SSID_LENGTH, + pPrefNetworkFoundInd->ssId.length); + qdf_mem_copy(dumpSsId, pPrefNetworkFoundInd->ssId.ssId, + ssIdLength); + dumpSsId[ssIdLength] = 0; + sms_log(pMac, LOG2, "%s:SSID=%s frame length %d", + __func__, dumpSsId, pPrefNetworkFoundInd->frameLength); + + /* Flush scan results, So as to avoid indication/updation of + * stale entries, which may not have aged out during APPS collapse + */ + sme_scan_flush_result(hHal); + + /* Save the frame to scan result */ + if (pPrefNetworkFoundInd->mesgLen > + sizeof(tSirPrefNetworkFoundInd)) { + /* we may have a frame */ + status = csr_scan_save_preferred_network_found(pMac, + pPrefNetworkFoundInd); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOGE, + FL(" fail to save preferred network")); + } + } else { + sms_log(pMac, LOGE, + FL(" not enough data length %d needed %zu"), + pPrefNetworkFoundInd->mesgLen, + sizeof(tSirPrefNetworkFoundInd)); + } + + /* Call Preferred Netowrk Found Indication callback routine. */ + if (QDF_IS_STATUS_SUCCESS(status) + && (pMac->sme.pref_netw_found_cb != NULL)) { + pMac->sme.pref_netw_found_cb(pMac->sme. + preferred_network_found_ind_cb_ctx, + pPrefNetworkFoundInd); + } + } else { + sms_log(pMac, LOGE, "%s: callback failed - SSID is NULL", + __func__); + status = QDF_STATUS_E_FAILURE; + } + + return status; +} + +#endif /* FEATURE_WLAN_SCAN_PNO */ + +/** + * sme_set_tsfcb() - Set callback for TSF capture + * @h_hal: Handler return by mac_open + * @cb_fn: Callback function pointer + * @db_ctx: Callback data + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_set_tsfcb(tHalHandle h_hal, + int (*cb_fn)(void *cb_ctx, struct stsf *ptsf), void *cb_ctx) +{ + tpAniSirGlobal mac = PMAC_STRUCT(h_hal); + QDF_STATUS status; + + status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + mac->sme.get_tsf_cb = cb_fn; + mac->sme.get_tsf_cxt = cb_ctx; + sme_release_global_lock(&mac->sme); + } + return status; +} + +/** + * sme_reset_tsfcb() - Reset callback for TSF capture + * @h_hal: Handler return by mac_open + * + * This function reset the tsf capture callback to SME + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_reset_tsfcb(tHalHandle h_hal) +{ + tpAniSirGlobal mac; + QDF_STATUS status; + + if (!h_hal) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("h_hal is not valid")); + return QDF_STATUS_E_INVAL; + } + mac = PMAC_STRUCT(h_hal); + + status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + mac->sme.get_tsf_cb = NULL; + mac->sme.get_tsf_cxt = NULL; + sme_release_global_lock(&mac->sme); + } + return status; +} + +#ifdef WLAN_FEATURE_TSF +/* + * sme_set_tsf_gpio() - set gpio pin that be toggled when capture tef + * @h_hal: Handler return by mac_open + * @pinvalue: gpio pin id + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_set_tsf_gpio(tHalHandle h_hal, uint32_t pinvalue) +{ + QDF_STATUS status; + cds_msg_t tsf_msg = {0}; + tpAniSirGlobal mac = PMAC_STRUCT(h_hal); + + status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + tsf_msg.type = WMA_TSF_GPIO_PIN; + tsf_msg.reserved = 0; + tsf_msg.bodyval = pinvalue; + + status = cds_mq_post_message(CDS_MQ_ID_WMA, &tsf_msg); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sms_log(mac, LOGE, "Unable to post WMA_TSF_GPIO_PIN"); + status = QDF_STATUS_E_FAILURE; + } + sme_release_global_lock(&mac->sme); + } + return status; +} +#endif + +QDF_STATUS sme_get_cfg_valid_channels(tHalHandle hHal, uint8_t *aValidChannels, + uint32_t *len) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + status = csr_get_cfg_valid_channels(pMac, aValidChannels, len); + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +void sme_set_cc_src(tHalHandle hHal, enum country_src cc_src) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hHal); + + mac_ctx->reg_hint_src = cc_src; +} +/* --------------------------------------------------------------------------- + + \fn sme_handle_change_country_code + + \brief Change Country code, Reg Domain and channel list + + \details Country Code Priority + If Supplicant country code is priority than 11d is disabled. + If 11D is enabled, we update the country code after every scan. + Hence when Supplicant country code is priority, we don't need 11D info. + Country code from Supplicant is set as current courtry code. + User can send reset command XX (instead of country code) to reset the + country code to default values. + If 11D is priority, + Than Supplicant country code code is set to default code. But 11D code is set as current country code + + \param pMac - The handle returned by mac_open. + \param pMsgBuf - MSG Buffer + + \return QDF_STATUS + + -------------------------------------------------------------------------------*/ +QDF_STATUS sme_handle_change_country_code(tpAniSirGlobal pMac, void *pMsgBuf) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tAniChangeCountryCodeReq *pMsg; + v_REGDOMAIN_t domainIdIoctl; + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + static uint8_t default_country[CDS_COUNTRY_CODE_LEN + 1]; + pMsg = (tAniChangeCountryCodeReq *) pMsgBuf; + + /* + * if the reset Supplicant country code command is triggered, + * enable 11D, reset the country code and return + */ + if (!qdf_mem_cmp(pMsg->countryCode, SME_INVALID_COUNTRY_CODE, 2)) { + pMac->roam.configParam.Is11dSupportEnabled = + pMac->roam.configParam.Is11dSupportEnabledOriginal; + + qdf_status = cds_read_default_country(default_country); + + /* read the country code and use it */ + if (QDF_IS_STATUS_SUCCESS(qdf_status)) { + qdf_mem_copy(pMsg->countryCode, + default_country, + WNI_CFG_COUNTRY_CODE_LEN); + } else { + status = QDF_STATUS_E_FAILURE; + return status; + } + /* + * Update the 11d country to default country so that when + * callback is received for this default country, driver will + * not disable the 11d taking it as valid country by user. + */ + sms_log(pMac, LOG1, + FL("Set default country code (%c%c) as invalid country received"), + pMsg->countryCode[0], pMsg->countryCode[1]); + qdf_mem_copy(pMac->scan.countryCode11d, + pMsg->countryCode, + WNI_CFG_COUNTRY_CODE_LEN); + } else { + /* if Supplicant country code has priority, disable 11d */ + if (pMac->roam.configParam.fSupplicantCountryCodeHasPriority && + pMsg->countryFromUserSpace) { + pMac->roam.configParam.Is11dSupportEnabled = false; + } + } + + if (pMac->roam.configParam.Is11dSupportEnabled) + return QDF_STATUS_SUCCESS; + + /* Set Current Country code and Current Regulatory domain */ + status = csr_set_country_code(pMac, pMsg->countryCode); + if (QDF_STATUS_SUCCESS != status) { + /* Supplicant country code failed. So give 11D priority */ + pMac->roam.configParam.Is11dSupportEnabled = + pMac->roam.configParam.Is11dSupportEnabledOriginal; + sms_log(pMac, LOGE, "Set Country Code Fail %d", status); + return status; + } + + /* overwrite the defualt country code */ + qdf_mem_copy(pMac->scan.countryCodeDefault, + pMac->scan.countryCodeCurrent, WNI_CFG_COUNTRY_CODE_LEN); + + /* Get Domain ID from country code */ + status = csr_get_regulatory_domain_for_country(pMac, + pMac->scan.countryCodeCurrent, + (v_REGDOMAIN_t *) & + domainIdIoctl, + SOURCE_QUERY); + if (status != QDF_STATUS_SUCCESS) { + sms_log(pMac, LOGE, FL(" fail to get regId %d"), domainIdIoctl); + return status; + } else if (REGDOMAIN_WORLD == domainIdIoctl) { + /* Supplicant country code is invalid, so we are on world mode now. So + give 11D chance to update */ + pMac->roam.configParam.Is11dSupportEnabled = + pMac->roam.configParam.Is11dSupportEnabledOriginal; + sms_log(pMac, LOG1, FL("Country Code unrecognized by driver")); + } + + status = wma_set_reg_domain(pMac, domainIdIoctl); + + if (status != QDF_STATUS_SUCCESS) { + sms_log(pMac, LOGE, FL(" fail to set regId %d"), domainIdIoctl); + return status; + } else { + /* if 11d has priority, clear currentCountryBssid & countryCode11d to get */ + /* set again if we find AP with 11d info during scan */ + if (!pMac->roam.configParam.fSupplicantCountryCodeHasPriority) { + sms_log(pMac, LOGW, + FL + ("Clearing currentCountryBssid, countryCode11d")); + qdf_mem_zero(&pMac->scan.currentCountryBssid, + sizeof(struct qdf_mac_addr)); + qdf_mem_zero(pMac->scan.countryCode11d, + sizeof(pMac->scan.countryCode11d)); + } + } + + if (pMsg->changeCCCallback) { + ((tSmeChangeCountryCallback) (pMsg->changeCCCallback))((void *) + pMsg-> + pDevContext); + } + + return QDF_STATUS_SUCCESS; +} + +/** + * sme_handle_generic_change_country_code() - handles country ch req + * @mac_ctx: mac global context + * @msg: request msg packet + * + * If Supplicant country code is priority than 11d is disabled. + * If 11D is enabled, we update the country code after every scan. + * Hence when Supplicant country code is priority, we don't need 11D info. + * Country code from Supplicant is set as current country code. + * + * Return: status of operation + */ +QDF_STATUS +sme_handle_generic_change_country_code(tpAniSirGlobal mac_ctx, + void *pMsgBuf) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + v_REGDOMAIN_t reg_domain_id = 0; + bool user_ctry_priority = + mac_ctx->roam.configParam.fSupplicantCountryCodeHasPriority; + tAniGenericChangeCountryCodeReq *msg = pMsgBuf; + + sms_log(mac_ctx, LOG1, FL(" called")); + + if (SOURCE_11D != mac_ctx->reg_hint_src) { + if (SOURCE_DRIVER != mac_ctx->reg_hint_src) { + if (user_ctry_priority) + mac_ctx->roam.configParam.Is11dSupportEnabled = + false; + else { + if (mac_ctx->roam.configParam.Is11dSupportEnabled && + mac_ctx->scan.countryCode11d[0] != 0) { + + sms_log(mac_ctx, LOGW, + FL("restore 11d")); + + status = csr_get_regulatory_domain_for_country( + mac_ctx, + mac_ctx->scan.countryCode11d, + ®_domain_id, + SOURCE_11D); + return QDF_STATUS_E_FAILURE; + } + } + } + } else { + /* if kernel gets invalid country code; it + * resets the country code to world + */ + if (('0' != msg->countryCode[0]) || + ('0' != msg->countryCode[1])) + qdf_mem_copy(mac_ctx->scan.countryCode11d, + msg->countryCode, + WNI_CFG_COUNTRY_CODE_LEN); + } + + qdf_mem_copy(mac_ctx->scan.countryCodeCurrent, + msg->countryCode, + WNI_CFG_COUNTRY_CODE_LEN); + + /* get the channels based on new cc */ + status = csr_get_channel_and_power_list(mac_ctx); + + if (status != QDF_STATUS_SUCCESS) { + sms_log(mac_ctx, LOGE, FL("fail to get Channels")); + return status; + } + + /* reset info based on new cc, and we are done */ + csr_apply_channel_power_info_wrapper(mac_ctx); + + csr_scan_filter_results(mac_ctx); + + /* scans after the country is set by User hints or + * Country IE + */ + mac_ctx->scan.curScanType = eSIR_ACTIVE_SCAN; + + mac_ctx->reg_hint_src = SOURCE_UNKNOWN; + + sme_disconnect_connected_sessions(mac_ctx); + + sms_log(mac_ctx, LOG1, FL(" returned")); + return QDF_STATUS_SUCCESS; +} + +static bool +sme_search_in_base_ch_lst(tpAniSirGlobal mac_ctx, uint8_t curr_ch) +{ + uint8_t i; + tCsrChannel *ch_lst_info; + ch_lst_info = &mac_ctx->scan.base_channels; + for (i = 0; i < ch_lst_info->numChannels; i++) { + if (ch_lst_info->channelList[i] == curr_ch) + return true; + } + + return false; +} +/** + * sme_disconnect_connected_sessions() - Disconnect STA and P2P client session + * if channel is not supported + * @mac_ctx: mac global context + * + * If new country code does not support the channel on which STA/P2P client + * is connetced, it sends the disconnect to the AP/P2P GO + * + * Return: void + */ +void sme_disconnect_connected_sessions(tpAniSirGlobal mac_ctx) +{ + uint8_t session_id, found = false; + uint8_t curr_ch; + + for (session_id = 0; session_id < CSR_ROAM_SESSION_MAX; session_id++) { + if (!csr_is_session_client_and_connected(mac_ctx, session_id)) + continue; + found = false; + /* Session is connected.Check the channel */ + curr_ch = csr_get_infra_operation_channel(mac_ctx, + session_id); + sms_log(mac_ctx, LOGW, + FL("Current Operating channel : %d, session :%d"), + curr_ch, session_id); + found = sme_search_in_base_ch_lst(mac_ctx, curr_ch); + if (!found) { + sms_log(mac_ctx, LOGW, FL("Disconnect Session :%d"), + session_id); + csr_roam_disconnect(mac_ctx, session_id, + eCSR_DISCONNECT_REASON_UNSPECIFIED); + } + } +} + +#ifdef WLAN_FEATURE_PACKET_FILTERING +QDF_STATUS sme_8023_multicast_list(tHalHandle hHal, uint8_t sessionId, + tpSirRcvFltMcAddrList pMulticastAddrs) +{ + tpSirRcvFltMcAddrList request_buf; + cds_msg_t msg; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + tCsrRoamSession *pSession = NULL; + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO, "%s: " + "ulMulticastAddrCnt=%d, multicastAddr[0]=%p", __func__, + pMulticastAddrs->ulMulticastAddrCnt, + pMulticastAddrs->multicastAddr[0].bytes); + + /* Find the connected Infra / P2P_client connected session */ + + pSession = CSR_GET_SESSION(pMac, sessionId); + if (!CSR_IS_SESSION_VALID(pMac, sessionId) || + (!csr_is_conn_state_infra(pMac, sessionId) && + !csr_is_ndi_started(pMac, sessionId))) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid session: %d", __func__, sessionId); + return QDF_STATUS_E_FAILURE; + } + + request_buf = qdf_mem_malloc(sizeof(tSirRcvFltMcAddrList)); + if (NULL == request_buf) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Not able to " + "allocate memory for 8023 Multicast List request", + __func__); + return QDF_STATUS_E_NOMEM; + } + + if (!csr_is_conn_state_connected_infra(pMac, sessionId) && + !csr_is_ndi_started(pMac, sessionId)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Request ignored, session %d is not connected or started", + __func__, sessionId); + qdf_mem_free(request_buf); + return QDF_STATUS_E_FAILURE; + } + + qdf_mem_copy(request_buf, pMulticastAddrs, + sizeof(tSirRcvFltMcAddrList)); + + qdf_copy_macaddr(&request_buf->self_macaddr, &pSession->selfMacAddr); + qdf_copy_macaddr(&request_buf->bssid, + &pSession->connectedProfile.bssid); + + msg.type = WMA_8023_MULTICAST_LIST_REQ; + msg.reserved = 0; + msg.bodyptr = request_buf; + MTRACE(qdf_trace(QDF_MODULE_ID_SME, TRACE_CODE_SME_TX_WMA_MSG, + sessionId, msg.type)); + if (QDF_STATUS_SUCCESS != cds_mq_post_message(QDF_MODULE_ID_WMA, &msg)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Not able to " + "post WMA_8023_MULTICAST_LIST message to WMA", + __func__); + qdf_mem_free(request_buf); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS sme_receive_filter_set_filter(tHalHandle hHal, + tpSirRcvPktFilterCfgType pRcvPktFilterCfg, + uint8_t sessionId) +{ + tpSirRcvPktFilterCfgType request_buf; + int32_t allocSize; + cds_msg_t msg; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + uint8_t idx = 0; + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO, "%s: filterType=%d, " + "filterId = %d", __func__, + pRcvPktFilterCfg->filterType, pRcvPktFilterCfg->filterId); + + allocSize = sizeof(tSirRcvPktFilterCfgType); + + request_buf = qdf_mem_malloc(allocSize); + + if (NULL == request_buf) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Not able to " + "allocate memory for Receive Filter Set Filter request", + __func__); + return QDF_STATUS_E_NOMEM; + } + + if (NULL == pSession) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Session Not found ", __func__); + qdf_mem_free(request_buf); + return QDF_STATUS_E_FAILURE; + } + + qdf_copy_macaddr(&pRcvPktFilterCfg->self_macaddr, + &pSession->selfMacAddr); + qdf_copy_macaddr(&pRcvPktFilterCfg->bssid, + &pSession->connectedProfile.bssid); + qdf_mem_copy(request_buf, pRcvPktFilterCfg, allocSize); + + msg.type = WMA_RECEIVE_FILTER_SET_FILTER_REQ; + msg.reserved = 0; + msg.bodyptr = request_buf; + MTRACE(qdf_trace(QDF_MODULE_ID_SME, TRACE_CODE_SME_TX_WMA_MSG, + sessionId, msg.type)); + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO, "Pkt Flt Req : " + "FT %d FID %d ", + request_buf->filterType, request_buf->filterId); + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO, "Pkt Flt Req : " + "params %d CT %d", + request_buf->numFieldParams, request_buf->coalesceTime); + + for (idx = 0; idx < request_buf->numFieldParams; idx++) { + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO, + "Proto %d Comp Flag %d ", + request_buf->paramsData[idx].protocolLayer, + request_buf->paramsData[idx].cmpFlag); + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO, + "Data Offset %d Data Len %d", + request_buf->paramsData[idx].dataOffset, + request_buf->paramsData[idx].dataLength); + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO, + "CData: %d:%d:%d:%d:%d:%d", + request_buf->paramsData[idx].compareData[0], + request_buf->paramsData[idx].compareData[1], + request_buf->paramsData[idx].compareData[2], + request_buf->paramsData[idx].compareData[3], + request_buf->paramsData[idx].compareData[4], + request_buf->paramsData[idx].compareData[5]); + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO, + "MData: %d:%d:%d:%d:%d:%d", + request_buf->paramsData[idx].dataMask[0], + request_buf->paramsData[idx].dataMask[1], + request_buf->paramsData[idx].dataMask[2], + request_buf->paramsData[idx].dataMask[3], + request_buf->paramsData[idx].dataMask[4], + request_buf->paramsData[idx].dataMask[5]); + + } + + if (QDF_STATUS_SUCCESS != cds_mq_post_message(QDF_MODULE_ID_WMA, &msg)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Not able to post " + "WMA_RECEIVE_FILTER_SET_FILTER message to WMA", + __func__); + qdf_mem_free(request_buf); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS sme_receive_filter_clear_filter(tHalHandle hHal, + tpSirRcvFltPktClearParam + pRcvFltPktClearParam, uint8_t sessionId) +{ + tpSirRcvFltPktClearParam request_buf; + cds_msg_t msg; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO, "%s: filterId = %d", + __func__, pRcvFltPktClearParam->filterId); + + if (NULL == pSession) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Session Not found", __func__); + return QDF_STATUS_E_FAILURE; + } + + request_buf = qdf_mem_malloc(sizeof(tSirRcvFltPktClearParam)); + if (NULL == request_buf) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Not able to allocate memory for Receive Filter " + "Clear Filter request", __func__); + return QDF_STATUS_E_NOMEM; + } + + qdf_copy_macaddr(&pRcvFltPktClearParam->self_macaddr, + &pSession->selfMacAddr); + qdf_copy_macaddr(&pRcvFltPktClearParam->bssid, + &pSession->connectedProfile.bssid); + + qdf_mem_copy(request_buf, pRcvFltPktClearParam, + sizeof(tSirRcvFltPktClearParam)); + + msg.type = WMA_RECEIVE_FILTER_CLEAR_FILTER_REQ; + msg.reserved = 0; + msg.bodyptr = request_buf; + MTRACE(qdf_trace(QDF_MODULE_ID_SME, TRACE_CODE_SME_TX_WMA_MSG, + sessionId, msg.type)); + if (QDF_STATUS_SUCCESS != cds_mq_post_message(QDF_MODULE_ID_WMA, &msg)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Not able to post " + "WMA_RECEIVE_FILTER_CLEAR_FILTER message to WMA", + __func__); + qdf_mem_free(request_buf); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} +#endif /* WLAN_FEATURE_PACKET_FILTERING */ + +/* --------------------------------------------------------------------------- + + \fn sme_is_channel_valid + + \brief To check if the channel is valid for currently established domain + This is a synchronous API. + + \param hHal - The handle returned by mac_open. + \param channel - channel to verify + + \return true/false, true if channel is valid + + -------------------------------------------------------------------------------*/ +bool sme_is_channel_valid(tHalHandle hHal, uint8_t channel) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + bool valid = false; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + + valid = csr_roam_is_channel_valid(pMac, channel); + + sme_release_global_lock(&pMac->sme); + } + + return valid; +} + +/* --------------------------------------------------------------------------- + \fn sme_set_freq_band + \brief Used to set frequency band. + \param hHal + \param sessionId - Session Identifier + \eBand band value to be configured + \- return QDF_STATUS + -------------------------------------------------------------------------*/ +QDF_STATUS sme_set_freq_band(tHalHandle hHal, uint8_t sessionId, eCsrBand eBand) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + status = csr_set_band(hHal, sessionId, eBand); + sme_release_global_lock(&pMac->sme); + } + return status; +} + +/* --------------------------------------------------------------------------- + \fn sme_get_freq_band + \brief Used to get the current band settings. + \param hHal + \pBand pointer to hold band value + \- return QDF_STATUS + -------------------------------------------------------------------------*/ +QDF_STATUS sme_get_freq_band(tHalHandle hHal, eCsrBand *pBand) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + *pBand = csr_get_current_band(hHal); + sme_release_global_lock(&pMac->sme); + } + return status; +} + +/* --------------------------------------------------------------------------- + \fn sme_set_max_tx_power_per_band + + \brief Set the Maximum Transmit Power specific to band dynamically. + Note: this setting will not persist over reboots. + + \param band + \param power to set in dB + \- return QDF_STATUS + + ----------------------------------------------------------------------------*/ +QDF_STATUS sme_set_max_tx_power_per_band(eCsrBand band, int8_t dB) +{ + cds_msg_t msg; + tpMaxTxPowerPerBandParams pMaxTxPowerPerBandParams = NULL; + + pMaxTxPowerPerBandParams = + qdf_mem_malloc(sizeof(tMaxTxPowerPerBandParams)); + if (NULL == pMaxTxPowerPerBandParams) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s:Not able to allocate memory for pMaxTxPowerPerBandParams", + __func__); + return QDF_STATUS_E_NOMEM; + } + + pMaxTxPowerPerBandParams->power = dB; + pMaxTxPowerPerBandParams->bandInfo = band; + + msg.type = WMA_SET_MAX_TX_POWER_PER_BAND_REQ; + msg.reserved = 0; + msg.bodyptr = pMaxTxPowerPerBandParams; + MTRACE(qdf_trace(QDF_MODULE_ID_SME, TRACE_CODE_SME_TX_WMA_MSG, + NO_SESSION, msg.type)); + if (QDF_STATUS_SUCCESS != cds_mq_post_message(QDF_MODULE_ID_WMA, &msg)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s:Not able to post WMA_SET_MAX_TX_POWER_PER_BAND_REQ", + __func__); + qdf_mem_free(pMaxTxPowerPerBandParams); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/* --------------------------------------------------------------------------- + + \fn sme_set_max_tx_power + + \brief Set the Maximum Transmit Power dynamically. Note: this setting will + not persist over reboots. + + \param hHal + \param pBssid BSSID to set the power cap for + \param pBssid pSelfMacAddress self MAC Address + \param pBssid power to set in dB + \- return QDF_STATUS + + -------------------------------------------------------------------------------*/ +QDF_STATUS sme_set_max_tx_power(tHalHandle hHal, struct qdf_mac_addr pBssid, + struct qdf_mac_addr pSelfMacAddress, int8_t dB) +{ + cds_msg_t msg; + tpMaxTxPowerParams pMaxTxParams = NULL; + + MTRACE(qdf_trace(QDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_SET_MAXTXPOW, NO_SESSION, 0)); + pMaxTxParams = qdf_mem_malloc(sizeof(tMaxTxPowerParams)); + if (NULL == pMaxTxParams) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Not able to allocate memory for pMaxTxParams", + __func__); + return QDF_STATUS_E_NOMEM; + } + + qdf_copy_macaddr(&pMaxTxParams->bssId, &pBssid); + qdf_copy_macaddr(&pMaxTxParams->selfStaMacAddr, &pSelfMacAddress); + pMaxTxParams->power = dB; + + msg.type = WMA_SET_MAX_TX_POWER_REQ; + msg.reserved = 0; + msg.bodyptr = pMaxTxParams; + + if (QDF_STATUS_SUCCESS != cds_mq_post_message(QDF_MODULE_ID_WMA, &msg)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Not able to post WMA_SET_MAX_TX_POWER_REQ message to WMA", + __func__); + qdf_mem_free(pMaxTxParams); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/* --------------------------------------------------------------------------- + + \fn sme_set_custom_mac_addr + + \brief Set the customer Mac Address. + + \param customMacAddr customer MAC Address + \- return QDF_STATUS + + ---------------------------------------------------------------------------*/ +QDF_STATUS sme_set_custom_mac_addr(tSirMacAddr customMacAddr) +{ + cds_msg_t msg; + tSirMacAddr *pBaseMacAddr; + + pBaseMacAddr = qdf_mem_malloc(sizeof(tSirMacAddr)); + if (NULL == pBaseMacAddr) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Not able to allocate memory for pBaseMacAddr")); + return QDF_STATUS_E_NOMEM; + } + + qdf_mem_copy(*pBaseMacAddr, customMacAddr, sizeof(tSirMacAddr)); + + msg.type = SIR_HAL_SET_BASE_MACADDR_IND; + msg.reserved = 0; + msg.bodyptr = pBaseMacAddr; + + if (QDF_STATUS_SUCCESS != cds_mq_post_message(QDF_MODULE_ID_WMA, &msg)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL + ("Not able to post SIR_HAL_SET_BASE_MACADDR_IND message to WMA")); + qdf_mem_free(pBaseMacAddr); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/* ---------------------------------------------------------------------------- + \fn sme_set_tx_power + \brief Set Transmit Power dynamically. + \param hHal + \param sessionId Target Session ID + \pBSSId BSSID + \dev_mode dev_mode such as station, P2PGO, SAP + \param dBm power to set + \- return QDF_STATUS + ---------------------------------------------------------------------------*/ +QDF_STATUS sme_set_tx_power(tHalHandle hHal, uint8_t sessionId, + struct qdf_mac_addr pBSSId, + enum tQDF_ADAPTER_MODE dev_mode, int dBm) +{ + cds_msg_t msg; + tpMaxTxPowerParams pTxParams = NULL; + int8_t power = (int8_t) dBm; + + MTRACE(qdf_trace(QDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_SET_TXPOW, sessionId, 0)); + + /* make sure there is no overflow */ + if ((int)power != dBm) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: error, invalid power = %d", __func__, dBm); + return QDF_STATUS_E_FAILURE; + } + + pTxParams = qdf_mem_malloc(sizeof(tMaxTxPowerParams)); + if (NULL == pTxParams) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Not able to allocate memory for pTxParams", + __func__); + return QDF_STATUS_E_NOMEM; + } + + qdf_copy_macaddr(&pTxParams->bssId, &pBSSId); + pTxParams->power = power; /* unit is dBm */ + pTxParams->dev_mode = dev_mode; + msg.type = WMA_SET_TX_POWER_REQ; + msg.reserved = 0; + msg.bodyptr = pTxParams; + + if (QDF_STATUS_SUCCESS != cds_mq_post_message(QDF_MODULE_ID_WMA, &msg)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: failed to post WMA_SET_TX_POWER_REQ to WMA", + __func__); + qdf_mem_free(pTxParams); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS sme_update_session_param(tHalHandle hal, uint8_t session_id, + uint32_t param_type, uint32_t param_val) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + uint16_t len; + + status = sme_acquire_global_lock(&mac_ctx->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + struct sir_update_session_param *msg; + tCsrRoamSession *session = CSR_GET_SESSION(mac_ctx, session_id); + + if (!session) { + sms_log(mac_ctx, LOGE, FL("session %d not found"), + session_id); + sme_release_global_lock(&mac_ctx->sme); + return status; + } + + if (param_type == SIR_PARAM_IGNORE_ASSOC_DISALLOWED) + session->ignore_assoc_disallowed = param_val; + + if (!session->sessionActive) + QDF_ASSERT(0); + + len = sizeof(*msg); + msg = qdf_mem_malloc(len); + if (!msg) + status = QDF_STATUS_E_NOMEM; + else { + msg->message_type = eWNI_SME_SESSION_UPDATE_PARAM; + msg->length = len; + msg->session_id = session_id; + msg->param_type = param_type; + msg->param_val = param_val; + status = cds_send_mb_message_to_mac(msg); + } + sme_release_global_lock(&mac_ctx->sme); + } + return status; +} + +/* --------------------------------------------------------------------------- + + \fn sme_set_tm_level + \brief Set Thermal Mitigation Level to RIVA + \param hHal - The handle returned by mac_open. + \param newTMLevel - new Thermal Mitigation Level + \param tmMode - Thermal Mitigation handle mode, default 0 + \return QDF_STATUS + ---------------------------------------------------------------------------*/ +QDF_STATUS sme_set_tm_level(tHalHandle hHal, uint16_t newTMLevel, uint16_t tmMode) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + cds_msg_t cds_message; + tAniSetTmLevelReq *setTmLevelReq = NULL; + + MTRACE(qdf_trace(QDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_SET_TMLEVEL, NO_SESSION, 0)); + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + setTmLevelReq = + (tAniSetTmLevelReq *) + qdf_mem_malloc(sizeof(tAniSetTmLevelReq)); + if (NULL == setTmLevelReq) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Not able to allocate memory for sme_set_tm_level", + __func__); + sme_release_global_lock(&pMac->sme); + return QDF_STATUS_E_NOMEM; + } + + setTmLevelReq->tmMode = tmMode; + setTmLevelReq->newTmLevel = newTMLevel; + + /* serialize the req through MC thread */ + cds_message.bodyptr = setTmLevelReq; + cds_message.type = WMA_SET_TM_LEVEL_REQ; + MTRACE(qdf_trace(QDF_MODULE_ID_SME, TRACE_CODE_SME_TX_WMA_MSG, + NO_SESSION, cds_message.type)); + qdf_status = cds_mq_post_message(CDS_MQ_ID_WMA, &cds_message); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Post Set TM Level MSG fail", __func__); + qdf_mem_free(setTmLevelReq); + status = QDF_STATUS_E_FAILURE; + } + sme_release_global_lock(&pMac->sme); + } + return status; +} + +/*--------------------------------------------------------------------------- + + \brief sme_feature_caps_exchange() - SME interface to exchange capabilities between + Host and FW. + + \param hHal - HAL handle for device + + \return NONE + + ---------------------------------------------------------------------------*/ +void sme_feature_caps_exchange(tHalHandle hHal) +{ + MTRACE(qdf_trace + (QDF_MODULE_ID_SME, TRACE_CODE_SME_RX_HDD_CAPS_EXCH, NO_SESSION, + 0)); +} + +/*--------------------------------------------------------------------------- + + \brief sme_disable_feature_capablity() - SME interface to disable Active mode offload capablity + in Host. + + \param hHal - HAL handle for device + + \return NONE + + ---------------------------------------------------------------------------*/ +void sme_disable_feature_capablity(uint8_t feature_index) +{ +} + +/* --------------------------------------------------------------------------- + \fn sme_reset_power_values_for5_g + \brief Reset the power values for 5G band with default power values. + \param hHal - HAL handle for device + \- return NONE + -------------------------------------------------------------------------*/ +void sme_reset_power_values_for5_g(tHalHandle hHal) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + MTRACE(qdf_trace(QDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_RESET_PW5G, NO_SESSION, 0)); + csr_save_channel_power_for_band(pMac, true); + csr_apply_power2_current(pMac); /* Store the channel+power info in the global place: Cfg */ +} + +/* --------------------------------------------------------------------------- + \fn sme_update_roam_prefer5_g_hz + \brief enable/disable Roam prefer 5G runtime option + This function is called through dynamic setConfig callback function + to configure the Roam prefer 5G runtime option + \param hHal - HAL handle for device + \param nRoamPrefer5GHz Enable/Disable Roam prefer 5G runtime option + \- return Success or failure + -------------------------------------------------------------------------*/ + +QDF_STATUS sme_update_roam_prefer5_g_hz(tHalHandle hHal, bool nRoamPrefer5GHz) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + QDF_STATUS status = QDF_STATUS_SUCCESS; + + MTRACE(qdf_trace(QDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_UPDATE_RP5G, NO_SESSION, 0)); + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO, + "%s: gRoamPrefer5GHz is changed from %d to %d", + __func__, pMac->roam.configParam.nRoamPrefer5GHz, + nRoamPrefer5GHz); + pMac->roam.configParam.nRoamPrefer5GHz = nRoamPrefer5GHz; + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +/* --------------------------------------------------------------------------- + \fn sme_set_roam_intra_band + \brief enable/disable Intra band roaming + This function is called through dynamic setConfig callback function + to configure the intra band roaming + \param hHal - HAL handle for device + \param nRoamIntraBand Enable/Disable Intra band roaming + \- return Success or failure + -------------------------------------------------------------------------*/ +QDF_STATUS sme_set_roam_intra_band(tHalHandle hHal, const bool nRoamIntraBand) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + QDF_STATUS status = QDF_STATUS_SUCCESS; + + MTRACE(qdf_trace(QDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_SET_ROAMIBAND, NO_SESSION, 0)); + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO, + "%s: gRoamIntraBand is changed from %d to %d", + __func__, pMac->roam.configParam.nRoamIntraBand, + nRoamIntraBand); + pMac->roam.configParam.nRoamIntraBand = nRoamIntraBand; + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +/* --------------------------------------------------------------------------- + \fn sme_update_roam_scan_n_probes + \brief function to update roam scan N probes + This function is called through dynamic setConfig callback function + to update roam scan N probes + \param hHal - HAL handle for device + \param sessionId - Session Identifier + \param nProbes number of probe requests to be sent out + \- return Success or failure + -------------------------------------------------------------------------*/ +QDF_STATUS sme_update_roam_scan_n_probes(tHalHandle hHal, uint8_t sessionId, + const uint8_t nProbes) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + QDF_STATUS status = QDF_STATUS_SUCCESS; + + MTRACE(qdf_trace(QDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_UPDATE_ROAM_SCAN_N_PROBES, + NO_SESSION, 0)); + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO, + "%s: gRoamScanNProbes is changed from %d to %d", + __func__, pMac->roam.configParam.nProbes, nProbes); + pMac->roam.configParam.nProbes = nProbes; + sme_release_global_lock(&pMac->sme); + } + if (pMac->roam.configParam.isRoamOffloadScanEnabled) { + csr_roam_offload_scan(pMac, sessionId, + ROAM_SCAN_OFFLOAD_UPDATE_CFG, + REASON_NPROBES_CHANGED); + } + return status; +} + +/* --------------------------------------------------------------------------- + \fn sme_update_roam_scan_home_away_time + \brief function to update roam scan Home away time + This function is called through dynamic setConfig callback function + to update roam scan home away time + \param hHal - HAL handle for device + \param sessionId - Session Identifier + \param nRoamScanAwayTime Scan home away time + \param bSendOffloadCmd If true then send offload command to firmware + If false then command is not sent to firmware + \- return Success or failure + -------------------------------------------------------------------------*/ +QDF_STATUS sme_update_roam_scan_home_away_time(tHalHandle hHal, + uint8_t sessionId, + const uint16_t nRoamScanHomeAwayTime, + const bool bSendOffloadCmd) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + QDF_STATUS status = QDF_STATUS_SUCCESS; + + MTRACE(qdf_trace(QDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_UPDATE_ROAM_SCAN_HOME_AWAY_TIME, + NO_SESSION, 0)); + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO, + "%s: gRoamScanHomeAwayTime is changed from %d to %d", + __func__, + pMac->roam.configParam.nRoamScanHomeAwayTime, + nRoamScanHomeAwayTime); + pMac->roam.configParam.nRoamScanHomeAwayTime = + nRoamScanHomeAwayTime; + sme_release_global_lock(&pMac->sme); + } + if (pMac->roam.configParam.isRoamOffloadScanEnabled && bSendOffloadCmd) { + csr_roam_offload_scan(pMac, sessionId, + ROAM_SCAN_OFFLOAD_UPDATE_CFG, + REASON_HOME_AWAY_TIME_CHANGED); + } + return status; +} + +/** + * sme_ext_change_channel()- function to post send ECSA + * action frame to csr. + * @hHal: Hal context + * @channel: new channel to switch + * @session_id: senssion it should be sent on. + * + * This function is called to post ECSA frame to csr. + * + * Return: success if msg is sent else return failure + */ +QDF_STATUS sme_ext_change_channel(tHalHandle h_hal, uint32_t channel, + uint8_t session_id) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpAniSirGlobal mac_ctx = PMAC_STRUCT(h_hal); + uint8_t channel_state; + + sms_log(mac_ctx, LOGE, FL(" Set Channel %d "), channel); + channel_state = + cds_get_channel_state(channel); + + if (CHANNEL_STATE_DISABLE == channel_state) { + sms_log(mac_ctx, LOGE, FL(" Invalid channel %d "), channel); + return QDF_STATUS_E_INVAL; + } + + status = sme_acquire_global_lock(&mac_ctx->sme); + + if (QDF_STATUS_SUCCESS == status) { + /* update the channel list to the firmware */ + status = csr_send_ext_change_channel(mac_ctx, + channel, session_id); + sme_release_global_lock(&mac_ctx->sme); + } + + return status; +} + +/* --------------------------------------------------------------------------- + \fn sme_get_roam_intra_band + \brief get Intra band roaming + \param hHal - HAL handle for device + \- return Success or failure + -------------------------------------------------------------------------*/ +bool sme_get_roam_intra_band(tHalHandle hHal) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + MTRACE(qdf_trace(QDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_GET_ROAMIBAND, NO_SESSION, 0)); + return pMac->roam.configParam.nRoamIntraBand; +} + +/* --------------------------------------------------------------------------- + \fn sme_get_roam_scan_n_probes + \brief get N Probes + \param hHal - HAL handle for device + \- return Success or failure + -------------------------------------------------------------------------*/ +uint8_t sme_get_roam_scan_n_probes(tHalHandle hHal) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + return pMac->roam.configParam.nProbes; +} + +/* --------------------------------------------------------------------------- + \fn sme_get_roam_scan_home_away_time + \brief get Roam scan home away time + \param hHal - HAL handle for device + \- return Success or failure + -------------------------------------------------------------------------*/ +uint16_t sme_get_roam_scan_home_away_time(tHalHandle hHal) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + return pMac->roam.configParam.nRoamScanHomeAwayTime; +} + +/* --------------------------------------------------------------------------- + \fn sme_update_roam_rssi_diff + \brief Update RoamRssiDiff + This function is called through dynamic setConfig callback function + to configure RoamRssiDiff + Usage: adb shell iwpriv wlan0 setConfig RoamRssiDiff=[0 .. 125] + \param hHal - HAL handle for device + \param sessionId - Session Identifier + \param RoamRssiDiff - minimum rssi difference between potential + candidate and current AP. + \- return Success or failure + -------------------------------------------------------------------------*/ + +QDF_STATUS sme_update_roam_rssi_diff(tHalHandle hHal, uint8_t sessionId, + uint8_t RoamRssiDiff) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + QDF_STATUS status = QDF_STATUS_SUCCESS; + + if (sessionId >= CSR_ROAM_SESSION_MAX) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Invalid sme session id: %d"), sessionId); + return QDF_STATUS_E_INVAL; + } + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "LFR runtime successfully set roam rssi diff to %d - old value is %d - roam state is %s", + RoamRssiDiff, + pMac->roam.configParam.RoamRssiDiff, + mac_trace_get_neighbour_roam_state(pMac->roam. + neighborRoamInfo + [sessionId]. + neighborRoamState)); + pMac->roam.configParam.RoamRssiDiff = RoamRssiDiff; + sme_release_global_lock(&pMac->sme); + } + + if (pMac->roam.configParam.isRoamOffloadScanEnabled) { + csr_roam_offload_scan(pMac, sessionId, + ROAM_SCAN_OFFLOAD_UPDATE_CFG, + REASON_RSSI_DIFF_CHANGED); + } + return status; +} + +/*-------------------------------------------------------------------------- + \brief sme_update_fast_transition_enabled() - enable/disable Fast Transition + support at runtime + It is used at in the REG_DYNAMIC_VARIABLE macro definition of + isFastTransitionEnabled. + This is a synchronous call + \param hHal - The handle returned by mac_open. + \return QDF_STATUS_SUCCESS - SME update isFastTransitionEnabled config + successfully. + Other status means SME is failed to update isFastTransitionEnabled. + \sa + --------------------------------------------------------------------------*/ +QDF_STATUS sme_update_fast_transition_enabled(tHalHandle hHal, + bool isFastTransitionEnabled) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + QDF_STATUS status = QDF_STATUS_SUCCESS; + + MTRACE(qdf_trace(QDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_UPDATE_FTENABLED, NO_SESSION, + 0)); + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO, + "%s: FastTransitionEnabled is changed from %d to %d", + __func__, + pMac->roam.configParam.isFastTransitionEnabled, + isFastTransitionEnabled); + pMac->roam.configParam.isFastTransitionEnabled = + isFastTransitionEnabled; + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +/* --------------------------------------------------------------------------- + \fn sme_update_wes_mode + \brief Update WES Mode + This function is called through dynamic setConfig callback function + to configure isWESModeEnabled + \param hHal - HAL handle for device + \param isWESModeEnabled - WES mode + \param sessionId - Session Identifier + \return QDF_STATUS_SUCCESS - SME update isWESModeEnabled config successfully. + Other status means SME is failed to update isWESModeEnabled. + -------------------------------------------------------------------------*/ + +QDF_STATUS sme_update_wes_mode(tHalHandle hHal, bool isWESModeEnabled, + uint8_t sessionId) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + QDF_STATUS status = QDF_STATUS_SUCCESS; + + if (sessionId >= CSR_ROAM_SESSION_MAX) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Invalid sme session id: %d"), sessionId); + return QDF_STATUS_E_INVAL; + } + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "LFR runtime successfully set WES Mode to %d - old value is %d - roam state is %s", + isWESModeEnabled, + pMac->roam.configParam.isWESModeEnabled, + mac_trace_get_neighbour_roam_state(pMac->roam. + neighborRoamInfo + [sessionId]. + neighborRoamState)); + pMac->roam.configParam.isWESModeEnabled = isWESModeEnabled; + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +/* --------------------------------------------------------------------------- + \fn sme_set_roam_scan_control + \brief Set roam scan control + This function is called to set roam scan control + if roam scan control is set to 0, roaming scan cache is cleared + any value other than 0 is treated as invalid value + \param hHal - HAL handle for device + \param sessionId - Session Identifier + \return QDF_STATUS_SUCCESS - SME update config successfully. + Other status means SME failure to update + -------------------------------------------------------------------------*/ +QDF_STATUS sme_set_roam_scan_control(tHalHandle hHal, uint8_t sessionId, + bool roamScanControl) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + QDF_STATUS status = QDF_STATUS_SUCCESS; + + MTRACE(qdf_trace(QDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_SET_SCANCTRL, NO_SESSION, 0)); + + if (sessionId >= CSR_ROAM_SESSION_MAX) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Invalid sme session id: %d"), sessionId); + return QDF_STATUS_E_INVAL; + } + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "LFR runtime successfully set roam scan control to %d - old value is %d - roam state is %s", + roamScanControl, + pMac->roam.configParam.nRoamScanControl, + mac_trace_get_neighbour_roam_state(pMac->roam. + neighborRoamInfo + [sessionId]. + neighborRoamState)); + pMac->roam.configParam.nRoamScanControl = roamScanControl; + if (0 == roamScanControl) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "LFR runtime successfully cleared roam scan cache"); + csr_flush_cfg_bg_scan_roam_channel_list(pMac, sessionId); + if (pMac->roam.configParam.isRoamOffloadScanEnabled) { + csr_roam_offload_scan(pMac, sessionId, + ROAM_SCAN_OFFLOAD_UPDATE_CFG, + REASON_FLUSH_CHANNEL_LIST); + } + } + sme_release_global_lock(&pMac->sme); + } + return status; +} + +/*-------------------------------------------------------------------------- + \brief sme_update_is_fast_roam_ini_feature_enabled() - enable/disable LFR + support at runtime + It is used at in the REG_DYNAMIC_VARIABLE macro definition of + isFastRoamIniFeatureEnabled. + This is a synchronous call + \param hHal - The handle returned by mac_open. + \param sessionId - Session Identifier + \return QDF_STATUS_SUCCESS - SME update isFastRoamIniFeatureEnabled config + successfully. + Other status means SME is failed to update isFastRoamIniFeatureEnabled. + \sa + --------------------------------------------------------------------------*/ +QDF_STATUS sme_update_is_fast_roam_ini_feature_enabled + (tHalHandle hHal, + uint8_t sessionId, const bool isFastRoamIniFeatureEnabled) { + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + if (pMac->roam.configParam.isFastRoamIniFeatureEnabled == + isFastRoamIniFeatureEnabled) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "%s: FastRoam is already enabled or disabled, nothing to do (returning) old(%d) new(%d)", + __func__, + pMac->roam.configParam.isFastRoamIniFeatureEnabled, + isFastRoamIniFeatureEnabled); + return QDF_STATUS_SUCCESS; + } + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "%s: FastRoamEnabled is changed from %d to %d", __func__, + pMac->roam.configParam.isFastRoamIniFeatureEnabled, + isFastRoamIniFeatureEnabled); + pMac->roam.configParam.isFastRoamIniFeatureEnabled = + isFastRoamIniFeatureEnabled; + csr_neighbor_roam_update_fast_roaming_enabled(pMac, sessionId, + isFastRoamIniFeatureEnabled); + + return QDF_STATUS_SUCCESS; +} + +/** + * sme_config_fast_roaming() - enable/disable LFR support at runtime + * @hal - The handle returned by macOpen. + * @session_id - Session Identifier + * @is_fast_roam_enabled - flag to enable/disable roaming + * + * When Supplicant issues enabled/disable fast roaming on the basis + * of the Bssid modification in network block (e.g. AutoJoin mode N/W block) + * + * Return: QDF_STATUS + */ + +QDF_STATUS sme_config_fast_roaming(tHalHandle hal, uint8_t session_id, + const bool is_fast_roam_enabled) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + tCsrRoamSession *session = CSR_GET_SESSION(mac_ctx, session_id); + QDF_STATUS status; + + /* do_not_roam flag is set in wlan_hdd_cfg80211_connect_start + * when supplicant initiate connect request with BSSID. + * This flag reset when supplicant sends vendor command to enable + * roaming after association. + * + * This request from wpa_supplicant will be skipped in this function + * if roaming is disabled using driver command or INI and do_not_roam + * flag remains set. So make sure to set do_not_roam flag as per + * wpa_supplicant even if roam request from wpa_supplicant ignored. + */ + if (session && session->pCurRoamProfile) + session->pCurRoamProfile->do_not_roam = !is_fast_roam_enabled; + + if (!mac_ctx->roam.configParam.isFastRoamIniFeatureEnabled) { + sms_log(mac_ctx, LOGE, FL("Fast roam is disabled through ini")); + if (!is_fast_roam_enabled) + return QDF_STATUS_SUCCESS; + return QDF_STATUS_E_FAILURE; + } + + status = csr_neighbor_roam_update_fast_roaming_enabled(mac_ctx, + session_id, is_fast_roam_enabled); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sms_log(mac_ctx, LOGE, + FL("csr_neighbor_roam_update_fast_roaming_enabled failed")); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/*-------------------------------------------------------------------------- + \brief sme_update_is_mawc_ini_feature_enabled() - + Enable/disable LFR MAWC support at runtime + It is used at in the REG_DYNAMIC_VARIABLE macro definition of + isMAWCIniFeatureEnabled. + This is a synchronous call + \param hHal - The handle returned by mac_open. + \return QDF_STATUS_SUCCESS - SME update MAWCEnabled config successfully. + Other status means SME is failed to update MAWCEnabled. + \sa + --------------------------------------------------------------------------*/ +QDF_STATUS sme_update_is_mawc_ini_feature_enabled(tHalHandle hHal, + const bool MAWCEnabled) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + QDF_STATUS status = QDF_STATUS_SUCCESS; + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO, + "%s: MAWCEnabled is changed from %d to %d", __func__, + pMac->roam.configParam.MAWCEnabled, MAWCEnabled); + pMac->roam.configParam.MAWCEnabled = MAWCEnabled; + sme_release_global_lock(&pMac->sme); + } + + return status; + +} + +/*-------------------------------------------------------------------------- + \brief sme_stop_roaming() - Stop roaming for a given sessionId + This is a synchronous call + \param hHal - The handle returned by mac_open + \param sessionId - Session Identifier + \return QDF_STATUS_SUCCESS on success + Other status on failure + \sa + --------------------------------------------------------------------------*/ +QDF_STATUS sme_stop_roaming(tHalHandle hHal, uint8_t sessionId, uint8_t reason) +{ + tSirMsgQ wma_msg; + tSirRetStatus status; + tSirRoamOffloadScanReq *req; + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hHal); + void *wma = cds_get_context(QDF_MODULE_ID_WMA); + + if (!wma) { + sms_log(mac_ctx, LOGE, "wma is null"); + return QDF_STATUS_E_NULL_VALUE; + } + + req = qdf_mem_malloc(sizeof(*req)); + if (!req) { + sms_log(mac_ctx, LOGE, "failed to allocated memory"); + return QDF_STATUS_E_NOMEM; + } + + req->Command = ROAM_SCAN_OFFLOAD_STOP; + if (reason == eCsrForcedDisassoc) + req->reason = REASON_ROAM_STOP_ALL; + else + req->reason = REASON_ROAM_SYNCH_FAILED; + req->sessionId = sessionId; + if (csr_neighbor_middle_of_roaming(mac_ctx, sessionId)) + req->middle_of_roaming = 1; + else + csr_roam_reset_roam_params(mac_ctx); + + wma_msg.type = WMA_ROAM_SCAN_OFFLOAD_REQ; + wma_msg.bodyptr = req; + + status = wma_post_ctrl_msg(mac_ctx, &wma_msg); + if (eSIR_SUCCESS != status) { + sms_log(mac_ctx, LOGE, + "Posting WMA_ROAM_SCAN_OFFLOAD_REQ failed"); + qdf_mem_free(req); + return QDF_STATUS_E_FAULT; + } + + return QDF_STATUS_SUCCESS; +} + +/*-------------------------------------------------------------------------- + \brief sme_start_roaming() - Start roaming for a given sessionId + This is a synchronous call + \param hHal - The handle returned by mac_open + \param sessionId - Session Identifier + \return QDF_STATUS_SUCCESS on success + Other status on failure + \sa + --------------------------------------------------------------------------*/ +QDF_STATUS sme_start_roaming(tHalHandle hHal, uint8_t sessionId, uint8_t reason) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + QDF_STATUS status = QDF_STATUS_SUCCESS; + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + csr_roam_offload_scan(pMac, sessionId, ROAM_SCAN_OFFLOAD_START, + reason); + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +/*-------------------------------------------------------------------------- + \brief sme_update_enable_fast_roam_in_concurrency() - enable/disable LFR if + Concurrent session exists + This is a synchronuous call + \param hHal - The handle returned by mac_open. + \return QDF_STATUS_SUCCESS + Other status means SME is failed + \sa + --------------------------------------------------------------------------*/ + +QDF_STATUS sme_update_enable_fast_roam_in_concurrency(tHalHandle hHal, + bool + bFastRoamInConIniFeatureEnabled) +{ + + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + QDF_STATUS status = QDF_STATUS_SUCCESS; + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + pMac->roam.configParam.bFastRoamInConIniFeatureEnabled = + bFastRoamInConIniFeatureEnabled; + if (0 == pMac->roam.configParam.isRoamOffloadScanEnabled) { + pMac->roam.configParam.bFastRoamInConIniFeatureEnabled = + 0; + } + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +/*-------------------------------------------------------------------------- + \brief sme_update_config_fw_rssi_monitoring() - enable/disable firmware RSSI + Monitoring at runtime + It is used at in the REG_DYNAMIC_VARIABLE macro definition of + fEnableFwRssiMonitoring. + This is a synchronous call + \param hHal - The handle returned by mac_open. + \return QDF_STATUS_SUCCESS - SME update fEnableFwRssiMonitoring. + config successfully. + Other status means SME is failed to update fEnableFwRssiMonitoring. + \sa + --------------------------------------------------------------------------*/ + +QDF_STATUS sme_update_config_fw_rssi_monitoring(tHalHandle hHal, + bool fEnableFwRssiMonitoring) +{ + QDF_STATUS qdf_ret_status = QDF_STATUS_SUCCESS; + + if (sme_cfg_set_int (hHal, WNI_CFG_PS_ENABLE_RSSI_MONITOR, + fEnableFwRssiMonitoring) == QDF_STATUS_E_FAILURE) { + qdf_ret_status = QDF_STATUS_E_FAILURE; + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "Could not pass on WNI_CFG_PS_RSSI_MONITOR to CFG"); + } + + return qdf_ret_status; +} + +/* --------------------------------------------------------------------------- + \fn sme_set_roam_opportunistic_scan_threshold_diff + \brief Update Opportunistic Scan threshold diff + This function is called through dynamic setConfig callback function + to configure nOpportunisticThresholdDiff + \param hHal - HAL handle for device + \param sessionId - Session Identifier + \param nOpportunisticThresholdDiff - Opportunistic Scan threshold diff + \return QDF_STATUS_SUCCESS - SME update nOpportunisticThresholdDiff config + successfully. + else SME is failed to update nOpportunisticThresholdDiff. + -------------------------------------------------------------------------*/ +QDF_STATUS sme_set_roam_opportunistic_scan_threshold_diff(tHalHandle hHal, + uint8_t sessionId, + const uint8_t + nOpportunisticThresholdDiff) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + QDF_STATUS status = QDF_STATUS_SUCCESS; + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + status = csr_neighbor_roam_update_config(pMac, sessionId, + nOpportunisticThresholdDiff, + REASON_OPPORTUNISTIC_THRESH_DIFF_CHANGED); + if (QDF_IS_STATUS_SUCCESS(status)) { + pMac->roam.configParam.neighborRoamConfig. + nOpportunisticThresholdDiff = + nOpportunisticThresholdDiff; + } + sme_release_global_lock(&pMac->sme); + } + return status; +} + +/*-------------------------------------------------------------------------- + \fn sme_get_roam_opportunistic_scan_threshold_diff() + \brief gets Opportunistic Scan threshold diff + This is a synchronous call + \param hHal - The handle returned by mac_open + \return uint8_t - nOpportunisticThresholdDiff + \sa + --------------------------------------------------------------------------*/ +uint8_t sme_get_roam_opportunistic_scan_threshold_diff(tHalHandle hHal) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + return pMac->roam.configParam.neighborRoamConfig. + nOpportunisticThresholdDiff; +} + +/* --------------------------------------------------------------------------- + \fn sme_set_roam_rescan_rssi_diff + \brief Update roam rescan rssi diff + This function is called through dynamic setConfig callback function + to configure nRoamRescanRssiDiff + \param hHal - HAL handle for device + \param sessionId - Session Identifier + \param nRoamRescanRssiDiff - roam rescan rssi diff + \return QDF_STATUS_SUCCESS - SME update nRoamRescanRssiDiff config + successfully. + else SME is failed to update nRoamRescanRssiDiff. + -------------------------------------------------------------------------*/ +QDF_STATUS sme_set_roam_rescan_rssi_diff(tHalHandle hHal, + uint8_t sessionId, + const uint8_t nRoamRescanRssiDiff) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + QDF_STATUS status = QDF_STATUS_SUCCESS; + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + status = csr_neighbor_roam_update_config(pMac, sessionId, + nRoamRescanRssiDiff, + REASON_ROAM_RESCAN_RSSI_DIFF_CHANGED); + if (QDF_IS_STATUS_SUCCESS(status)) { + pMac->roam.configParam.neighborRoamConfig. + nRoamRescanRssiDiff = nRoamRescanRssiDiff; + } + sme_release_global_lock(&pMac->sme); + } + return status; +} + +/*-------------------------------------------------------------------------- + \fn sme_get_roam_rescan_rssi_diff + \brief gets roam rescan rssi diff + This is a synchronous call + \param hHal - The handle returned by mac_open + \return int8_t - nRoamRescanRssiDiff + \sa + --------------------------------------------------------------------------*/ +uint8_t sme_get_roam_rescan_rssi_diff(tHalHandle hHal) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + return pMac->roam.configParam.neighborRoamConfig.nRoamRescanRssiDiff; +} + +/* --------------------------------------------------------------------------- + \fn sme_set_roam_bmiss_first_bcnt + \brief Update Roam count for first beacon miss + This function is called through dynamic setConfig callback function + to configure nRoamBmissFirstBcnt + \param hHal - HAL handle for device + \param sessionId - Session Identifier + \param nRoamBmissFirstBcnt - Roam first bmiss count + \return QDF_STATUS_SUCCESS - SME update nRoamBmissFirstBcnt + successfully. + else SME is failed to update nRoamBmissFirstBcnt + -------------------------------------------------------------------------*/ +QDF_STATUS sme_set_roam_bmiss_first_bcnt(tHalHandle hHal, + uint8_t sessionId, + const uint8_t nRoamBmissFirstBcnt) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + QDF_STATUS status = QDF_STATUS_SUCCESS; + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + status = csr_neighbor_roam_update_config(pMac, sessionId, + nRoamBmissFirstBcnt, + REASON_ROAM_BMISS_FIRST_BCNT_CHANGED); + if (QDF_IS_STATUS_SUCCESS(status)) { + pMac->roam.configParam.neighborRoamConfig. + nRoamBmissFirstBcnt = nRoamBmissFirstBcnt; + } + sme_release_global_lock(&pMac->sme); + } + return status; +} + +/* --------------------------------------------------------------------------- + \fn sme_get_roam_bmiss_first_bcnt + \brief get neighbor roam beacon miss first count + \param hHal - The handle returned by mac_open. + \return uint8_t - neighbor roam beacon miss first count + -------------------------------------------------------------------------*/ +uint8_t sme_get_roam_bmiss_first_bcnt(tHalHandle hHal) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + return pMac->roam.configParam.neighborRoamConfig.nRoamBmissFirstBcnt; +} + +/* --------------------------------------------------------------------------- + \fn sme_set_roam_bmiss_final_bcnt + \brief Update Roam count for final beacon miss + This function is called through dynamic setConfig callback function + to configure nRoamBmissFinalBcnt + \param hHal - HAL handle for device + \param sessionId - Session Identifier + \param nRoamBmissFinalBcnt - Roam final bmiss count + \return QDF_STATUS_SUCCESS - SME update nRoamBmissFinalBcnt + successfully. + else SME is failed to update nRoamBmissFinalBcnt + -------------------------------------------------------------------------*/ +QDF_STATUS sme_set_roam_bmiss_final_bcnt(tHalHandle hHal, + uint8_t sessionId, + const uint8_t nRoamBmissFinalBcnt) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + QDF_STATUS status = QDF_STATUS_SUCCESS; + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + status = csr_neighbor_roam_update_config(pMac, sessionId, + nRoamBmissFinalBcnt, + REASON_ROAM_BMISS_FINAL_BCNT_CHANGED); + if (QDF_IS_STATUS_SUCCESS(status)) { + pMac->roam.configParam.neighborRoamConfig. + nRoamBmissFinalBcnt = nRoamBmissFinalBcnt; + } + sme_release_global_lock(&pMac->sme); + } + return status; +} + +/*-------------------------------------------------------------------------- + \fn sme_get_roam_bmiss_final_bcnt + \brief gets Roam count for final beacon miss + This is a synchronous call + \param hHal - The handle returned by mac_open + \return uint8_t - nRoamBmissFinalBcnt + \sa + --------------------------------------------------------------------------*/ +uint8_t sme_get_roam_bmiss_final_bcnt(tHalHandle hHal) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + return pMac->roam.configParam.neighborRoamConfig.nRoamBmissFinalBcnt; +} + +/* --------------------------------------------------------------------------- + \fn sme_set_roam_beacon_rssi_weight + \brief Update Roam beacon rssi weight + This function is called through dynamic setConfig callback function + to configure nRoamBeaconRssiWeight + \param hHal - HAL handle for device + \param sessionId - Session Identifier + \param nRoamBeaconRssiWeight - Roam beacon rssi weight + \return QDF_STATUS_SUCCESS - SME update nRoamBeaconRssiWeight config + successfully. + else SME is failed to update nRoamBeaconRssiWeight + -------------------------------------------------------------------------*/ +QDF_STATUS sme_set_roam_beacon_rssi_weight(tHalHandle hHal, + uint8_t sessionId, + const uint8_t nRoamBeaconRssiWeight) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + QDF_STATUS status = QDF_STATUS_SUCCESS; + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + status = csr_neighbor_roam_update_config(pMac, sessionId, + nRoamBeaconRssiWeight, + REASON_ROAM_BEACON_RSSI_WEIGHT_CHANGED); + if (QDF_IS_STATUS_SUCCESS(status)) { + pMac->roam.configParam.neighborRoamConfig. + nRoamBeaconRssiWeight = nRoamBeaconRssiWeight; + } + sme_release_global_lock(&pMac->sme); + } + return status; +} + +/*-------------------------------------------------------------------------- + \fn sme_get_roam_beacon_rssi_weight + \brief gets Roam beacon rssi weight + This is a synchronous call + \param hHal - The handle returned by mac_open + \return uint8_t - nRoamBeaconRssiWeight + \sa + --------------------------------------------------------------------------*/ +uint8_t sme_get_roam_beacon_rssi_weight(tHalHandle hHal) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + return pMac->roam.configParam.neighborRoamConfig.nRoamBeaconRssiWeight; +} + +/*-------------------------------------------------------------------------- + \brief sme_set_neighbor_lookup_rssi_threshold() - update neighbor lookup + rssi threshold + This is a synchronous call + \param hHal - The handle returned by mac_open. + \param sessionId - Session Identifier + \return QDF_STATUS_SUCCESS - SME update config successful. + Other status means SME is failed to update + \sa + --------------------------------------------------------------------------*/ +QDF_STATUS sme_set_neighbor_lookup_rssi_threshold + (tHalHandle hHal, uint8_t sessionId, uint8_t neighborLookupRssiThreshold) { + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + QDF_STATUS status = QDF_STATUS_SUCCESS; + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + status = csr_neighbor_roam_update_config(pMac, + sessionId, neighborLookupRssiThreshold, + REASON_LOOKUP_THRESH_CHANGED); + if (QDF_IS_STATUS_SUCCESS(status)) { + pMac->roam.configParam.neighborRoamConfig. + nNeighborLookupRssiThreshold = + neighborLookupRssiThreshold; + } + sme_release_global_lock(&pMac->sme); + } + return status; +} + +/*-------------------------------------------------------------------------- + \brief sme_set_delay_before_vdev_stop() - update delay before VDEV_STOP + This is a synchronous call + \param hal - The handle returned by macOpen. + \param session_id - Session Identifier + \param delay_before_vdev_stop - value to be set + \return QDF_STATUS_SUCCESS - SME update config successful. + Other status means SME is failed to update + \sa + --------------------------------------------------------------------------*/ +QDF_STATUS sme_set_delay_before_vdev_stop(tHalHandle hal, + uint8_t session_id, + uint8_t delay_before_vdev_stop) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hal); + QDF_STATUS status = QDF_STATUS_SUCCESS; + + if (session_id >= CSR_ROAM_SESSION_MAX) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Invalid sme session id: %d"), session_id); + return QDF_STATUS_E_INVAL; + } + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_DEBUG, + FL("LFR param delay_before_vdev_stop changed from %d to %d"), + pMac->roam.configParam.neighborRoamConfig. + delay_before_vdev_stop, + delay_before_vdev_stop); + pMac->roam.neighborRoamInfo[session_id].cfgParams. + delay_before_vdev_stop = delay_before_vdev_stop; + pMac->roam.configParam.neighborRoamConfig. + delay_before_vdev_stop = delay_before_vdev_stop; + sme_release_global_lock(&pMac->sme); + } + return status; +} + +/*-------------------------------------------------------------------------- + \brief sme_get_neighbor_lookup_rssi_threshold() - get neighbor lookup + rssi threshold + This is a synchronous call + \param hHal - The handle returned by mac_open. + \return QDF_STATUS_SUCCESS - SME update config successful. + Other status means SME is failed to update + \sa + --------------------------------------------------------------------------*/ +uint8_t sme_get_neighbor_lookup_rssi_threshold(tHalHandle hHal) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + return pMac->roam.configParam.neighborRoamConfig. + nNeighborLookupRssiThreshold; +} + +/*-------------------------------------------------------------------------- + \brief sme_set_neighbor_scan_refresh_period() - set neighbor scan results + refresh period + This is a synchronous call + \param hHal - The handle returned by mac_open. + \param sessionId - Session Identifier + \return QDF_STATUS_SUCCESS - SME update config successful. + Other status means SME is failed to update + \sa + --------------------------------------------------------------------------*/ +QDF_STATUS sme_set_neighbor_scan_refresh_period + (tHalHandle hHal, + uint8_t sessionId, uint16_t neighborScanResultsRefreshPeriod) { + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + QDF_STATUS status = QDF_STATUS_SUCCESS; + tCsrNeighborRoamConfig *pNeighborRoamConfig = NULL; + tpCsrNeighborRoamControlInfo pNeighborRoamInfo = NULL; + + if (sessionId >= CSR_ROAM_SESSION_MAX) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Invalid sme session id: %d"), sessionId); + return QDF_STATUS_E_INVAL; + } + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + pNeighborRoamConfig = + &pMac->roam.configParam.neighborRoamConfig; + pNeighborRoamInfo = &pMac->roam.neighborRoamInfo[sessionId]; + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "LFR runtime successfully set roam scan refresh period to %d- old value is %d - roam state is %s", + neighborScanResultsRefreshPeriod, + pMac->roam.configParam.neighborRoamConfig. + nNeighborResultsRefreshPeriod, + mac_trace_get_neighbour_roam_state(pMac->roam. + neighborRoamInfo + [sessionId]. + neighborRoamState)); + pNeighborRoamConfig->nNeighborResultsRefreshPeriod = + neighborScanResultsRefreshPeriod; + pNeighborRoamInfo->cfgParams.neighborResultsRefreshPeriod = + neighborScanResultsRefreshPeriod; + + sme_release_global_lock(&pMac->sme); + } + if (pMac->roam.configParam.isRoamOffloadScanEnabled) { + csr_roam_offload_scan(pMac, sessionId, + ROAM_SCAN_OFFLOAD_UPDATE_CFG, + REASON_NEIGHBOR_SCAN_REFRESH_PERIOD_CHANGED); + } + return status; +} + +/*-------------------------------------------------------------------------- + \brief sme_update_roam_scan_offload_enabled() - enable/disable roam scan + offload feaure + It is used at in the REG_DYNAMIC_VARIABLE macro definition of + gRoamScanOffloadEnabled. + This is a synchronous call + \param hHal - The handle returned by mac_open. + \return QDF_STATUS_SUCCESS - SME update config successfully. + Other status means SME is failed to update. + \sa + --------------------------------------------------------------------------*/ + +QDF_STATUS sme_update_roam_scan_offload_enabled(tHalHandle hHal, + bool nRoamScanOffloadEnabled) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + QDF_STATUS status = QDF_STATUS_SUCCESS; + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + FL + ("gRoamScanOffloadEnabled is changed from %d to %d"), + pMac->roam.configParam.isRoamOffloadScanEnabled, + nRoamScanOffloadEnabled); + pMac->roam.configParam.isRoamOffloadScanEnabled = + nRoamScanOffloadEnabled; + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +/*-------------------------------------------------------------------------- + \brief sme_get_neighbor_scan_refresh_period() - get neighbor scan results + refresh period + This is a synchronous call + \param hHal - The handle returned by mac_open. + \return uint16_t - Neighbor scan results refresh period value + \sa + --------------------------------------------------------------------------*/ +uint16_t sme_get_neighbor_scan_refresh_period(tHalHandle hHal) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + return pMac->roam.configParam.neighborRoamConfig. + nNeighborResultsRefreshPeriod; +} + +/*-------------------------------------------------------------------------- + \brief sme_get_empty_scan_refresh_period() - get empty scan refresh period + This is a synchronuous call + \param hHal - The handle returned by mac_open. + \return QDF_STATUS_SUCCESS - SME update config successful. + Other status means SME is failed to update + \sa + --------------------------------------------------------------------------*/ +uint16_t sme_get_empty_scan_refresh_period(tHalHandle hHal) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + return pMac->roam.configParam.neighborRoamConfig. + nEmptyScanRefreshPeriod; +} + +/* --------------------------------------------------------------------------- + \fn sme_update_empty_scan_refresh_period + \brief Update nEmptyScanRefreshPeriod + This function is called through dynamic setConfig callback function + to configure nEmptyScanRefreshPeriod + Usage: adb shell iwpriv wlan0 setConfig + nEmptyScanRefreshPeriod=[0 .. 60] + \param hHal - HAL handle for device + \param sessionId - Session Identifier + \param nEmptyScanRefreshPeriod - scan period following empty scan results. + \- return Success or failure + -------------------------------------------------------------------------*/ + +QDF_STATUS sme_update_empty_scan_refresh_period(tHalHandle hHal, uint8_t sessionId, + uint16_t nEmptyScanRefreshPeriod) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + QDF_STATUS status = QDF_STATUS_SUCCESS; + tCsrNeighborRoamConfig *pNeighborRoamConfig = NULL; + tpCsrNeighborRoamControlInfo pNeighborRoamInfo = NULL; + + if (sessionId >= CSR_ROAM_SESSION_MAX) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Invalid sme session id: %d"), sessionId); + return QDF_STATUS_E_INVAL; + } + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + pNeighborRoamConfig = + &pMac->roam.configParam.neighborRoamConfig; + pNeighborRoamInfo = &pMac->roam.neighborRoamInfo[sessionId]; + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "LFR runtime successfully set roam scan period to %d -old value is %d - roam state is %s", + nEmptyScanRefreshPeriod, + pMac->roam.configParam.neighborRoamConfig. + nEmptyScanRefreshPeriod, + mac_trace_get_neighbour_roam_state(pMac->roam. + neighborRoamInfo + [sessionId]. + neighborRoamState)); + pNeighborRoamConfig->nEmptyScanRefreshPeriod = + nEmptyScanRefreshPeriod; + pNeighborRoamInfo->cfgParams.emptyScanRefreshPeriod = + nEmptyScanRefreshPeriod; + sme_release_global_lock(&pMac->sme); + } + if (pMac->roam.configParam.isRoamOffloadScanEnabled) { + csr_roam_offload_scan(pMac, sessionId, + ROAM_SCAN_OFFLOAD_UPDATE_CFG, + REASON_EMPTY_SCAN_REF_PERIOD_CHANGED); + } + return status; +} + +/* --------------------------------------------------------------------------- + \fn sme_set_neighbor_scan_min_chan_time + \brief Update nNeighborScanMinChanTime + This function is called through dynamic setConfig callback function + to configure gNeighborScanChannelMinTime + Usage: adb shell iwpriv wlan0 setConfig + gNeighborScanChannelMinTime=[0 .. 60] + \param hHal - HAL handle for device + \param nNeighborScanMinChanTime - Channel minimum dwell time + \param sessionId - Session Identifier + \- return Success or failure + -------------------------------------------------------------------------*/ +QDF_STATUS sme_set_neighbor_scan_min_chan_time(tHalHandle hHal, + const uint16_t + nNeighborScanMinChanTime, + uint8_t sessionId) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + QDF_STATUS status = QDF_STATUS_SUCCESS; + + if (sessionId >= CSR_ROAM_SESSION_MAX) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Invalid sme session id: %d"), sessionId); + return QDF_STATUS_E_INVAL; + } + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "LFR runtime successfully set channel min dwell time to %d - old value is %d - roam state is %s", + nNeighborScanMinChanTime, + pMac->roam.configParam.neighborRoamConfig. + nNeighborScanMinChanTime, + mac_trace_get_neighbour_roam_state(pMac->roam. + neighborRoamInfo + [sessionId]. + neighborRoamState)); + + pMac->roam.configParam.neighborRoamConfig. + nNeighborScanMinChanTime = nNeighborScanMinChanTime; + pMac->roam.neighborRoamInfo[sessionId].cfgParams. + minChannelScanTime = nNeighborScanMinChanTime; + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +/* --------------------------------------------------------------------------- + \fn sme_set_neighbor_scan_max_chan_time + \brief Update nNeighborScanMaxChanTime + This function is called through dynamic setConfig callback function + to configure gNeighborScanChannelMaxTime + Usage: adb shell iwpriv wlan0 setConfig + gNeighborScanChannelMaxTime=[0 .. 60] + \param hHal - HAL handle for device + \param sessionId - Session Identifier + \param nNeighborScanMinChanTime - Channel maximum dwell time + \- return Success or failure + -------------------------------------------------------------------------*/ +QDF_STATUS sme_set_neighbor_scan_max_chan_time(tHalHandle hHal, uint8_t sessionId, + const uint16_t + nNeighborScanMaxChanTime) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + QDF_STATUS status = QDF_STATUS_SUCCESS; + tCsrNeighborRoamConfig *pNeighborRoamConfig = NULL; + tpCsrNeighborRoamControlInfo pNeighborRoamInfo = NULL; + + if (sessionId >= CSR_ROAM_SESSION_MAX) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Invalid sme session id: %d"), sessionId); + return QDF_STATUS_E_INVAL; + } + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + pNeighborRoamConfig = + &pMac->roam.configParam.neighborRoamConfig; + pNeighborRoamInfo = &pMac->roam.neighborRoamInfo[sessionId]; + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "LFR runtime successfully set channel max dwell time to %d - old value is %d - roam state is %s", + nNeighborScanMaxChanTime, + pMac->roam.configParam.neighborRoamConfig. + nNeighborScanMaxChanTime, + mac_trace_get_neighbour_roam_state(pMac->roam. + neighborRoamInfo + [sessionId]. + neighborRoamState)); + pNeighborRoamConfig->nNeighborScanMaxChanTime = + nNeighborScanMaxChanTime; + pNeighborRoamInfo->cfgParams.maxChannelScanTime = + nNeighborScanMaxChanTime; + sme_release_global_lock(&pMac->sme); + } + if (pMac->roam.configParam.isRoamOffloadScanEnabled) { + csr_roam_offload_scan(pMac, sessionId, + ROAM_SCAN_OFFLOAD_UPDATE_CFG, + REASON_SCAN_CH_TIME_CHANGED); + } + + return status; +} + +/* --------------------------------------------------------------------------- + \fn sme_get_neighbor_scan_min_chan_time + \brief get neighbor scan min channel time + \param hHal - The handle returned by mac_open. + \param sessionId - Session Identifier + \return uint16_t - channel min time value + -------------------------------------------------------------------------*/ +uint16_t sme_get_neighbor_scan_min_chan_time(tHalHandle hHal, uint8_t sessionId) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + if (sessionId >= CSR_ROAM_SESSION_MAX) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Invalid sme session id: %d"), sessionId); + return 0; + } + + return pMac->roam.neighborRoamInfo[sessionId].cfgParams. + minChannelScanTime; +} + +/* --------------------------------------------------------------------------- + \fn sme_get_neighbor_roam_state + \brief get neighbor roam state + \param hHal - The handle returned by mac_open. + \param sessionId - Session Identifier + \return uint32_t - neighbor roam state + -------------------------------------------------------------------------*/ +uint32_t sme_get_neighbor_roam_state(tHalHandle hHal, uint8_t sessionId) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + if (sessionId >= CSR_ROAM_SESSION_MAX) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Invalid sme session id: %d"), sessionId); + return 0; + } + + return pMac->roam.neighborRoamInfo[sessionId].neighborRoamState; +} + +/* --------------------------------------------------------------------------- + \fn sme_get_current_roam_state + \brief get current roam state + \param hHal - The handle returned by mac_open. + \param sessionId - Session Identifier + \return uint32_t - current roam state + -------------------------------------------------------------------------*/ +uint32_t sme_get_current_roam_state(tHalHandle hHal, uint8_t sessionId) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + return pMac->roam.curState[sessionId]; +} + +/* --------------------------------------------------------------------------- + \fn sme_get_current_roam_sub_state + \brief get neighbor roam sub state + \param hHal - The handle returned by mac_open. + \param sessionId - Session Identifier + \return uint32_t - current roam sub state + -------------------------------------------------------------------------*/ +uint32_t sme_get_current_roam_sub_state(tHalHandle hHal, uint8_t sessionId) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + return pMac->roam.curSubState[sessionId]; +} + +/* --------------------------------------------------------------------------- + \fn sme_get_lim_sme_state + \brief get Lim Sme state + \param hHal - The handle returned by mac_open. + \return uint32_t - Lim Sme state + -------------------------------------------------------------------------*/ +uint32_t sme_get_lim_sme_state(tHalHandle hHal) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + return pMac->lim.gLimSmeState; +} + +/* --------------------------------------------------------------------------- + \fn sme_get_lim_mlm_state + \brief get Lim Mlm state + \param hHal - The handle returned by mac_open. + \return uint32_t - Lim Mlm state + -------------------------------------------------------------------------*/ +uint32_t sme_get_lim_mlm_state(tHalHandle hHal) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + return pMac->lim.gLimMlmState; +} + +/* --------------------------------------------------------------------------- + \fn sme_is_lim_session_valid + \brief is Lim session valid + \param hHal - The handle returned by mac_open. + \param sessionId - Session Identifier + \return bool - true or false + -------------------------------------------------------------------------*/ +bool sme_is_lim_session_valid(tHalHandle hHal, uint8_t sessionId) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + if (sessionId > pMac->lim.maxBssId) + return false; + + return pMac->lim.gpSession[sessionId].valid; +} + +/* --------------------------------------------------------------------------- + \fn sme_get_lim_sme_session_state + \brief get Lim Sme session state + \param hHal - The handle returned by mac_open. + \param sessionId - Session Identifier + \return uint32_t - Lim Sme session state + -------------------------------------------------------------------------*/ +uint32_t sme_get_lim_sme_session_state(tHalHandle hHal, uint8_t sessionId) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + return pMac->lim.gpSession[sessionId].limSmeState; +} + +/* --------------------------------------------------------------------------- + \fn sme_get_lim_mlm_session_state + \brief get Lim Mlm session state + \param hHal - The handle returned by mac_open. + \param sessionId - Session Identifier + \return uint32_t - Lim Mlm session state + -------------------------------------------------------------------------*/ +uint32_t sme_get_lim_mlm_session_state(tHalHandle hHal, uint8_t sessionId) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + return pMac->lim.gpSession[sessionId].limMlmState; +} + +/* --------------------------------------------------------------------------- + \fn sme_get_neighbor_scan_max_chan_time + \brief get neighbor scan max channel time + \param hHal - The handle returned by mac_open. + \param sessionId - Session Identifier + \return uint16_t - channel max time value + -------------------------------------------------------------------------*/ +uint16_t sme_get_neighbor_scan_max_chan_time(tHalHandle hHal, uint8_t sessionId) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + if (sessionId >= CSR_ROAM_SESSION_MAX) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Invalid sme session id: %d"), sessionId); + return 0; + } + + return pMac->roam.neighborRoamInfo[sessionId].cfgParams. + maxChannelScanTime; +} + +/* --------------------------------------------------------------------------- + \fn sme_set_neighbor_scan_period + \brief Update nNeighborScanPeriod + This function is called through dynamic setConfig callback function + to configure nNeighborScanPeriod + Usage: adb shell iwpriv wlan0 setConfig + nNeighborScanPeriod=[0 .. 1000] + \param hHal - HAL handle for device + \param sessionId - Session Identifier + \param nNeighborScanPeriod - neighbor scan period + \- return Success or failure + -------------------------------------------------------------------------*/ +QDF_STATUS sme_set_neighbor_scan_period(tHalHandle hHal, uint8_t sessionId, + const uint16_t nNeighborScanPeriod) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + QDF_STATUS status = QDF_STATUS_SUCCESS; + tCsrNeighborRoamConfig *pNeighborRoamConfig = NULL; + tpCsrNeighborRoamControlInfo pNeighborRoamInfo = NULL; + + if (sessionId >= CSR_ROAM_SESSION_MAX) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Invalid sme session id: %d"), sessionId); + return QDF_STATUS_E_INVAL; + } + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + pNeighborRoamConfig = + &pMac->roam.configParam.neighborRoamConfig; + pNeighborRoamInfo = &pMac->roam.neighborRoamInfo[sessionId]; + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "LFR runtime successfully set neighbor scan period to %d" + " - old value is %d - roam state is %s", + nNeighborScanPeriod, + pMac->roam.configParam.neighborRoamConfig. + nNeighborScanTimerPeriod, + mac_trace_get_neighbour_roam_state(pMac->roam. + neighborRoamInfo + [sessionId]. + neighborRoamState)); + pNeighborRoamConfig->nNeighborScanTimerPeriod = + nNeighborScanPeriod; + pNeighborRoamInfo->cfgParams.neighborScanPeriod = + nNeighborScanPeriod; + sme_release_global_lock(&pMac->sme); + } + if (pMac->roam.configParam.isRoamOffloadScanEnabled) { + csr_roam_offload_scan(pMac, sessionId, + ROAM_SCAN_OFFLOAD_UPDATE_CFG, + REASON_SCAN_HOME_TIME_CHANGED); + } + + return status; +} + +/* --------------------------------------------------------------------------- + \fn sme_get_neighbor_scan_period + \brief get neighbor scan period + \param hHal - The handle returned by mac_open. + \param sessionId - Session Identifier + \return uint16_t - neighbor scan period + -------------------------------------------------------------------------*/ +uint16_t sme_get_neighbor_scan_period(tHalHandle hHal, uint8_t sessionId) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + if (sessionId >= CSR_ROAM_SESSION_MAX) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Invalid sme session id: %d"), sessionId); + return 0; + } + + return pMac->roam.neighborRoamInfo[sessionId].cfgParams. + neighborScanPeriod; +} + + + +/*-------------------------------------------------------------------------- + \brief sme_get_roam_rssi_diff() - get Roam rssi diff + This is a synchronous call + \param hHal - The handle returned by mac_open. + \return uint16_t - Rssi diff value + \sa + --------------------------------------------------------------------------*/ +uint8_t sme_get_roam_rssi_diff(tHalHandle hHal) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + return pMac->roam.configParam.RoamRssiDiff; +} + +/** + * sme_change_roam_scan_channel_list() - to change scan channel list + * @hHal: pointer HAL handle returned by mac_open + * @sessionId: sme session id + * @pChannelList: Output channel list + * @numChannels: Output number of channels + * + * This routine is called to Change roam scan channel list. + * This is a synchronous call + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_change_roam_scan_channel_list(tHalHandle hHal, uint8_t sessionId, + uint8_t *pChannelList, + uint8_t numChannels) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpCsrNeighborRoamControlInfo pNeighborRoamInfo = NULL; + uint8_t oldChannelList[WNI_CFG_VALID_CHANNEL_LIST_LEN * 2] = { 0 }; + uint8_t newChannelList[WNI_CFG_VALID_CHANNEL_LIST_LEN * 2] = { 0 }; + uint8_t i = 0, j = 0; + tCsrChannelInfo *chan_info; + + if (sessionId >= CSR_ROAM_SESSION_MAX) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Invalid sme session id: %d"), sessionId); + return QDF_STATUS_E_INVAL; + } + + pNeighborRoamInfo = &pMac->roam.neighborRoamInfo[sessionId]; + status = sme_acquire_global_lock(&pMac->sme); + if (!QDF_IS_STATUS_SUCCESS(status)) { + if (pMac->roam.configParam.isRoamOffloadScanEnabled) + csr_roam_offload_scan(pMac, sessionId, + ROAM_SCAN_OFFLOAD_UPDATE_CFG, + REASON_CHANNEL_LIST_CHANGED); + return status; + } + chan_info = &pNeighborRoamInfo->cfgParams.channelInfo; + + if (NULL != chan_info->ChannelList) { + for (i = 0; i < chan_info->numOfChannels; i++) { + if (j < sizeof(oldChannelList)) + j += snprintf(oldChannelList + j, + sizeof(oldChannelList) - + j, "%d", + chan_info->ChannelList[i]); + else + break; + } + } + csr_flush_cfg_bg_scan_roam_channel_list(pMac, sessionId); + csr_create_bg_scan_roam_channel_list(pMac, sessionId, pChannelList, + numChannels); + sme_set_roam_scan_control(hHal, sessionId, 1); + if (NULL != chan_info->ChannelList) { + j = 0; + for (i = 0; i < chan_info->numOfChannels; i++) { + if (j < sizeof(newChannelList)) + j += snprintf(newChannelList + j, + sizeof(newChannelList) - + j, " %d", + chan_info->ChannelList[i]); + else + break; + } + } + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + FL("LFR runtime successfully set roam scan channels to %s - old value is %s - roam state is %d"), + newChannelList, oldChannelList, + pMac->roam.neighborRoamInfo[sessionId].neighborRoamState); + sme_release_global_lock(&pMac->sme); + + if (pMac->roam.configParam.isRoamOffloadScanEnabled) + csr_roam_offload_scan(pMac, sessionId, + ROAM_SCAN_OFFLOAD_UPDATE_CFG, + REASON_CHANNEL_LIST_CHANGED); + return status; +} + +/** + * sme_get_roam_scan_channel_list() - To get roam scan channel list + * @hHal: HAL pointer + * @pChannelList: Output channel list + * @pNumChannels: Output number of channels + * @sessionId: Session Identifier + * + * To get roam scan channel list This is a synchronous call + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_get_roam_scan_channel_list(tHalHandle hHal, + uint8_t *pChannelList, uint8_t *pNumChannels, + uint8_t sessionId) +{ + int i = 0; + uint8_t *pOutPtr = pChannelList; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + tpCsrNeighborRoamControlInfo pNeighborRoamInfo = NULL; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + if (sessionId >= CSR_ROAM_SESSION_MAX) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Invalid sme session id: %d"), sessionId); + return QDF_STATUS_E_INVAL; + } + + pNeighborRoamInfo = &pMac->roam.neighborRoamInfo[sessionId]; + status = sme_acquire_global_lock(&pMac->sme); + if (!QDF_IS_STATUS_SUCCESS(status)) + return status; + if (NULL == pNeighborRoamInfo->cfgParams.channelInfo.ChannelList) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_WARN, + FL("Roam Scan channel list is NOT yet initialized")); + *pNumChannels = 0; + sme_release_global_lock(&pMac->sme); + return status; + } + + *pNumChannels = pNeighborRoamInfo->cfgParams.channelInfo.numOfChannels; + for (i = 0; i < (*pNumChannels); i++) { + pOutPtr[i] = + pNeighborRoamInfo->cfgParams.channelInfo.ChannelList[i]; + } + pOutPtr[i] = '\0'; + sme_release_global_lock(&pMac->sme); + return status; +} + +/*-------------------------------------------------------------------------- + \brief sme_get_is_ese_feature_enabled() - get ESE feature enabled or not + This is a synchronuous call + \param hHal - The handle returned by mac_open. + \return true (1) - if the ESE feature is enabled + false (0) - if feature is disabled (compile or runtime) + \sa + --------------------------------------------------------------------------*/ +bool sme_get_is_ese_feature_enabled(tHalHandle hHal) +{ +#ifdef FEATURE_WLAN_ESE + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + return csr_roam_is_ese_ini_feature_enabled(pMac); +#else + return false; +#endif +} + +/*-------------------------------------------------------------------------- + \brief sme_get_wes_mode() - get WES Mode + This is a synchronous call + \param hHal - The handle returned by mac_open + \return uint8_t - WES Mode Enabled(1)/Disabled(0) + \sa + --------------------------------------------------------------------------*/ +bool sme_get_wes_mode(tHalHandle hHal) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + return pMac->roam.configParam.isWESModeEnabled; +} + +/*-------------------------------------------------------------------------- + \brief sme_get_roam_scan_control() - get scan control + This is a synchronous call + \param hHal - The handle returned by mac_open. + \return bool - Enabled(1)/Disabled(0) + \sa + --------------------------------------------------------------------------*/ +bool sme_get_roam_scan_control(tHalHandle hHal) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + return pMac->roam.configParam.nRoamScanControl; +} + +/*-------------------------------------------------------------------------- + \brief sme_get_is_lfr_feature_enabled() - get LFR feature enabled or not + This is a synchronuous call + \param hHal - The handle returned by mac_open. + \return true (1) - if the feature is enabled + false (0) - if feature is disabled (compile or runtime) + \sa + --------------------------------------------------------------------------*/ +bool sme_get_is_lfr_feature_enabled(tHalHandle hHal) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + return pMac->roam.configParam.isFastRoamIniFeatureEnabled; +} + +/*-------------------------------------------------------------------------- + \brief sme_get_is_ft_feature_enabled() - get FT feature enabled or not + This is a synchronuous call + \param hHal - The handle returned by mac_open. + \return true (1) - if the feature is enabled + false (0) - if feature is disabled (compile or runtime) + \sa + --------------------------------------------------------------------------*/ +bool sme_get_is_ft_feature_enabled(tHalHandle hHal) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + return pMac->roam.configParam.isFastTransitionEnabled; +} + +/* --------------------------------------------------------------------------- + \fn sme_is_feature_supported_by_fw + \brief Check if an feature is enabled by FW + + \param feattEnumValue - Enumeration value from placeHolderInCapBitmap + \- return 1/0 (true/false) + -------------------------------------------------------------------------*/ +uint8_t sme_is_feature_supported_by_fw(uint8_t featEnumValue) +{ + return IS_FEATURE_SUPPORTED_BY_FW(featEnumValue); +} + +#ifdef FEATURE_WLAN_TDLS + +/* --------------------------------------------------------------------------- + \fn sme_send_tdls_link_establish_params + \brief API to send TDLS Peer Link Establishment Parameters. + + \param peerMac - peer's Mac Adress. + \param tdlsLinkEstablishParams - TDLS Peer Link Establishment Parameters + \- return QDF_STATUS_SUCCES + -------------------------------------------------------------------------*/ +QDF_STATUS sme_send_tdls_link_establish_params(tHalHandle hHal, + uint8_t sessionId, + const tSirMacAddr peerMac, + tCsrTdlsLinkEstablishParams * + tdlsLinkEstablishParams) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + MTRACE(qdf_trace(QDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_TDLS_LINK_ESTABLISH_PARAM, + sessionId, + tdlsLinkEstablishParams->isOffChannelSupported)); + status = sme_acquire_global_lock(&pMac->sme); + + if (QDF_IS_STATUS_SUCCESS(status)) { + status = csr_tdls_send_link_establish_params(hHal, sessionId, + peerMac, tdlsLinkEstablishParams); + sme_release_global_lock(&pMac->sme); + } + return status; +} + +/** + * sme_send_tdls_mgmt_frame() - API to send TDLS management frames. + * + * @peerMac - peer's Mac Adress. + * @frame_type - Type of TDLS mgmt frame to be sent. + * @dialog - dialog token used in the frame. + * @status - status to be incuded in the frame. + * @peerCapability - peer cpabilities + * @buf - additional IEs to be included + * @len - lenght of additional Ies + * @responder - Tdls request type + * @ac - access category + * Return QDF_STATUS_SUCCES + */ +QDF_STATUS sme_send_tdls_mgmt_frame(tHalHandle hHal, uint8_t sessionId, + const tSirMacAddr peerMac, + uint8_t frame_type, + uint8_t dialog, uint16_t statusCode, + uint32_t peerCapability, uint8_t *buf, + uint8_t len, uint8_t responder, + enum sir_wifi_traffic_ac ac) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tCsrTdlsSendMgmt sendTdlsReq = { {0} }; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + MTRACE(qdf_trace(QDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_TDLS_SEND_MGMT_FRAME, + sessionId, statusCode)); + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + qdf_mem_copy(sendTdlsReq.peerMac, peerMac, sizeof(tSirMacAddr)); + sendTdlsReq.frameType = frame_type; + sendTdlsReq.buf = buf; + sendTdlsReq.len = len; + sendTdlsReq.dialog = dialog; + sendTdlsReq.statusCode = statusCode; + sendTdlsReq.responder = responder; + sendTdlsReq.peerCapability = peerCapability; + sendTdlsReq.ac = ac; + + status = csr_tdls_send_mgmt_req(hHal, sessionId, &sendTdlsReq); + + sme_release_global_lock(&pMac->sme); + } + + return status; + +} + +/* --------------------------------------------------------------------------- + \fn sme_change_tdls_peer_sta + \brief API to Update TDLS peer sta parameters. + + \param peerMac - peer's Mac Adress. + \param staParams - Peer Station Parameters + \- return QDF_STATUS_SUCCES + -------------------------------------------------------------------------*/ +QDF_STATUS sme_change_tdls_peer_sta(tHalHandle hHal, uint8_t sessionId, + const tSirMacAddr peerMac, + tCsrStaParams *pstaParams) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + if (NULL == pstaParams) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s :pstaParams is NULL", __func__); + return QDF_STATUS_E_FAILURE; + } + MTRACE(qdf_trace(QDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_TDLS_CHANGE_PEER_STA, + sessionId, pstaParams->capability)); + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + status = csr_tdls_change_peer_sta(hHal, sessionId, peerMac, + pstaParams); + + sme_release_global_lock(&pMac->sme); + } + + return status; + +} + +/* --------------------------------------------------------------------------- + \fn sme_add_tdls_peer_sta + \brief API to Add TDLS peer sta entry. + + \param peerMac - peer's Mac Adress. + \- return QDF_STATUS_SUCCES + -------------------------------------------------------------------------*/ +QDF_STATUS sme_add_tdls_peer_sta(tHalHandle hHal, uint8_t sessionId, + const tSirMacAddr peerMac) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + MTRACE(qdf_trace(QDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_TDLS_ADD_PEER_STA, + sessionId, 0)); + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + status = csr_tdls_add_peer_sta(hHal, sessionId, peerMac); + + sme_release_global_lock(&pMac->sme); + } + + return status; + +} + +/* --------------------------------------------------------------------------- + \fn sme_delete_tdls_peer_sta + \brief API to Delete TDLS peer sta entry. + + \param peerMac - peer's Mac Adress. + \- return QDF_STATUS_SUCCES + -------------------------------------------------------------------------*/ +QDF_STATUS sme_delete_tdls_peer_sta(tHalHandle hHal, uint8_t sessionId, + const tSirMacAddr peerMac) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + MTRACE(qdf_trace(QDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_TDLS_DEL_PEER_STA, + sessionId, 0)); + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + status = csr_tdls_del_peer_sta(hHal, sessionId, peerMac); + + sme_release_global_lock(&pMac->sme); + } + + return status; + +} + +/* --------------------------------------------------------------------------- + \fn sme_set_tdls_power_save_prohibited + \API to set/reset the is_tdls_power_save_prohibited. + + \- return void + -------------------------------------------------------------------------*/ +void sme_set_tdls_power_save_prohibited(tHalHandle hHal, uint32_t sessionId, + bool val) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + struct ps_global_info *ps_global_info = &pMac->sme.ps_global_info; + struct ps_params *ps_param = &ps_global_info->ps_params[sessionId]; + ps_param->is_tdls_power_save_prohibited = val; + return; +} + +/* --------------------------------------------------------------------------- + \fn sme_update_fw_tdls_state + + \brief + SME will send message to WMA to set TDLS state in f/w + + \param + + hHal - The handle returned by mac_open + + psmeTdlsParams - TDLS state info to update in f/w + + useSmeLock - Need to acquire SME Global Lock before state update or not + + \return QDF_STATUS + --------------------------------------------------------------------------- */ +QDF_STATUS sme_update_fw_tdls_state(tHalHandle hHal, void *psmeTdlsParams, + bool useSmeLock) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = NULL; + cds_msg_t cds_message; + + pMac = PMAC_STRUCT(hHal); + if (NULL == pMac) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("pMac is Null")); + return QDF_STATUS_E_FAILURE; + } + + /* only acquire sme global lock before state update if asked to */ + if (useSmeLock) { + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_STATUS_SUCCESS != status) + return status; + } + + /* serialize the req through MC thread */ + cds_message.bodyptr = psmeTdlsParams; + cds_message.type = WMA_UPDATE_FW_TDLS_STATE; + qdf_status = cds_mq_post_message(CDS_MQ_ID_WMA, &cds_message); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) + status = QDF_STATUS_E_FAILURE; + + /* release the lock if it was acquired */ + if (useSmeLock) + sme_release_global_lock(&pMac->sme); + + return status; +} + +/** + * sme_update_tdls_peer_state() - to update the state of TDLS peer + * @hHal: The handle returned by mac_open + * @peerStateParams: TDLS Peer state info to update in f/w + * + * SME will send message to WMA to set TDLS Peer state in f/w + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_update_tdls_peer_state(tHalHandle hHal, + tSmeTdlsPeerStateParams *peerStateParams) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + tTdlsPeerStateParams *pTdlsPeerStateParams = NULL; + tTdlsPeerCapParams *peer_cap = NULL; + cds_msg_t cds_message; + uint8_t num; + uint8_t peer_chan_len; + uint8_t chanId; + uint8_t i; + + status = sme_acquire_global_lock(&pMac->sme); + if (!QDF_IS_STATUS_SUCCESS(status)) + return status; + pTdlsPeerStateParams = qdf_mem_malloc(sizeof(*pTdlsPeerStateParams)); + if (NULL == pTdlsPeerStateParams) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("failed to allocate mem for tdls peer state param")); + sme_release_global_lock(&pMac->sme); + return QDF_STATUS_E_NOMEM; + } + + qdf_mem_copy(&pTdlsPeerStateParams->peerMacAddr, + &peerStateParams->peerMacAddr, sizeof(tSirMacAddr)); + pTdlsPeerStateParams->vdevId = peerStateParams->vdevId; + pTdlsPeerStateParams->peerState = peerStateParams->peerState; + + switch (peerStateParams->peerState) { + case eSME_TDLS_PEER_STATE_PEERING: + pTdlsPeerStateParams->peerState = + WMA_TDLS_PEER_STATE_PEERING; + break; + + case eSME_TDLS_PEER_STATE_CONNECTED: + pTdlsPeerStateParams->peerState = + WMA_TDLS_PEER_STATE_CONNECTED; + break; + + case eSME_TDLS_PEER_STATE_TEARDOWN: + pTdlsPeerStateParams->peerState = + WMA_TDLS_PEER_STATE_TEARDOWN; + pTdlsPeerStateParams->resp_reqd = false; + break; + + case eSME_TDLS_PEER_ADD_MAC_ADDR: + pTdlsPeerStateParams->peerState = WMA_TDLS_PEER_ADD_MAC_ADDR; + break; + + case eSME_TDLS_PEER_REMOVE_MAC_ADDR: + pTdlsPeerStateParams->peerState = WMA_TDLS_PEER_REMOVE_MAC_ADDR; + break; + + default: + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("invalid peer state param (%d)"), + peerStateParams->peerState); + goto error_return; + } + peer_cap = &(pTdlsPeerStateParams->peerCap); + peer_cap->isPeerResponder = + peerStateParams->peerCap.isPeerResponder; + peer_cap->peerUapsdQueue = + peerStateParams->peerCap.peerUapsdQueue; + peer_cap->peerMaxSp = + peerStateParams->peerCap.peerMaxSp; + peer_cap->peerBuffStaSupport = + peerStateParams->peerCap.peerBuffStaSupport; + peer_cap->peerOffChanSupport = + peerStateParams->peerCap.peerOffChanSupport; + peer_cap->peerCurrOperClass = + peerStateParams->peerCap.peerCurrOperClass; + peer_cap->selfCurrOperClass = + peerStateParams->peerCap.selfCurrOperClass; + + num = 0; + peer_chan_len = peerStateParams->peerCap.peerChanLen; + + if (peer_chan_len >= 0 && + peer_chan_len <= SME_TDLS_MAX_SUPP_CHANNELS) { + for (i = 0; i < peerStateParams->peerCap.peerChanLen; i++) { + chanId = peerStateParams->peerCap.peerChan[i]; + if (csr_roam_is_channel_valid(pMac, chanId) && + !(cds_get_channel_state(chanId) == + CHANNEL_STATE_DFS) && + !cds_is_dsrc_channel(cds_chan_to_freq(chanId))) { + peer_cap->peerChan[num].chanId = chanId; + peer_cap->peerChan[num].pwr = + csr_get_cfg_max_tx_power(pMac, chanId); + peer_cap->peerChan[num].dfsSet = false; + num++; + } + } + } else { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("invalid peer channel len (%d)"), + peer_chan_len); + goto error_return; + } + + peer_cap->peerChanLen = num; + peer_cap->peerOperClassLen = + peerStateParams->peerCap.peerOperClassLen; + for (i = 0; i < HAL_TDLS_MAX_SUPP_OPER_CLASSES; i++) { + peer_cap->peerOperClass[i] = + peerStateParams->peerCap.peerOperClass[i]; + } + + peer_cap->prefOffChanNum = + peerStateParams->peerCap.prefOffChanNum; + peer_cap->prefOffChanBandwidth = + peerStateParams->peerCap.prefOffChanBandwidth; + peer_cap->opClassForPrefOffChan = + peerStateParams->peerCap.opClassForPrefOffChan; + + cds_message.type = WMA_UPDATE_TDLS_PEER_STATE; + cds_message.reserved = 0; + cds_message.bodyptr = pTdlsPeerStateParams; + + qdf_status = cds_mq_post_message(CDS_MQ_ID_WMA, &cds_message); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("cds_mq_post_message failed ")); + goto error_return; + } else { + goto success_return; + } + +error_return: + status = QDF_STATUS_E_FAILURE; + qdf_mem_free(pTdlsPeerStateParams); +success_return: + sme_release_global_lock(&pMac->sme); + return status; +} + +/** + * sme_send_tdls_chan_switch_req() - send tdls channel switch request + * @hal: UMAC handler + * @ch_switch_params: Pointer to the chan switch parameter structure + * + * API to set tdls channel switch parameters. + * + * Return: QDF_STATUS_SUCCESS on success; another QDF_STATUS_** code otherwise + */ +QDF_STATUS sme_send_tdls_chan_switch_req(tHalHandle hal, + sme_tdls_chan_switch_params *ch_switch_params) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + tpAniSirGlobal mac = PMAC_STRUCT(hal); + tdls_chan_switch_params *chan_switch_params = NULL; + cds_msg_t cds_message; + + MTRACE(qdf_trace(QDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_TDLS_CHAN_SWITCH_REQ, + NO_SESSION, ch_switch_params->tdls_off_channel)); + status = sme_acquire_global_lock(&mac->sme); + if (QDF_STATUS_SUCCESS != status) + return status; + chan_switch_params = qdf_mem_malloc(sizeof(*chan_switch_params)); + if (NULL == chan_switch_params) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("fail to alloc mem for tdls chan switch param")); + sme_release_global_lock(&mac->sme); + return QDF_STATUS_E_FAILURE; + } + + switch (ch_switch_params->tdls_off_ch_mode) { + case ENABLE_CHANSWITCH: + chan_switch_params->tdls_sw_mode = WMA_TDLS_ENABLE_OFFCHANNEL; + break; + + case DISABLE_CHANSWITCH: + chan_switch_params->tdls_sw_mode = WMA_TDLS_DISABLE_OFFCHANNEL; + break; + + default: + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("invalid off channel command (%d)"), + ch_switch_params->tdls_off_ch_mode); + qdf_mem_free(chan_switch_params); + sme_release_global_lock(&mac->sme); + return QDF_STATUS_E_FAILURE; + } + + qdf_mem_copy(&chan_switch_params->peer_mac_addr, + &ch_switch_params->peer_mac_addr, sizeof(tSirMacAddr)); + chan_switch_params->vdev_id = ch_switch_params->vdev_id; + chan_switch_params->tdls_off_ch = ch_switch_params->tdls_off_channel; + chan_switch_params->tdls_off_ch_bw_offset = + ch_switch_params->tdls_off_ch_bw_offset; + chan_switch_params->is_responder = ch_switch_params->is_responder; + chan_switch_params->oper_class = ch_switch_params->opclass; + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO, + FL("Country Code=%s, Req offset=%d, Selected Operate Class=%d"), + mac->scan.countryCodeCurrent, + chan_switch_params->tdls_off_ch_bw_offset, + chan_switch_params->oper_class); + + cds_message.type = WMA_TDLS_SET_OFFCHAN_MODE; + cds_message.reserved = 0; + cds_message.bodyptr = chan_switch_params; + + qdf_status = cds_mq_post_message(CDS_MQ_ID_WMA, &cds_message); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Message Post failed status=%d"), + qdf_status); + qdf_mem_free(chan_switch_params); + status = QDF_STATUS_E_FAILURE; + } + sme_release_global_lock(&mac->sme); + return status; +} +#endif /* FEATURE_WLAN_TDLS */ + +QDF_STATUS sme_get_link_speed(tHalHandle hHal, tSirLinkSpeedInfo *lsReq, + void *plsContext, + void (*pCallbackfn)(tSirLinkSpeedInfo *indParam, + void *pContext)) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + void *wma_handle; + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_STATUS_SUCCESS == status) { + if ((NULL == pCallbackfn) && + (NULL == pMac->sme.pLinkSpeedIndCb)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Indication Call back did not registered", + __func__); + sme_release_global_lock(&pMac->sme); + return QDF_STATUS_E_FAILURE; + } else if (NULL != pCallbackfn) { + pMac->sme.pLinkSpeedCbContext = plsContext; + pMac->sme.pLinkSpeedIndCb = pCallbackfn; + } + wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma_handle) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "wma handle is NULL"); + status = QDF_STATUS_E_FAILURE; + } else + status = wma_get_link_speed(wma_handle, lsReq); + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +/* + * SME API to enable/disable WLAN driver initiated SSR + */ +void sme_update_enable_ssr(tHalHandle hHal, bool enableSSR) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + QDF_STATUS status = QDF_STATUS_SUCCESS; + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "SSR level is changed %d", enableSSR); + /* not serializing this messsage, as this is only going + * to set a variable in WMA/WDI + */ + WMA_SetEnableSSR(enableSSR); + sme_release_global_lock(&pMac->sme); + } + return; +} + +QDF_STATUS sme_check_ch_in_band(tpAniSirGlobal mac_ctx, uint8_t start_ch, + uint8_t ch_cnt) +{ + uint8_t i; + for (i = 0; i < ch_cnt; i++) { + if (QDF_STATUS_SUCCESS != csr_is_valid_channel(mac_ctx, + (start_ch + i*4))) + return QDF_STATUS_E_FAILURE; + } + return QDF_STATUS_SUCCESS; +} + +/*convert the ini value to the ENUM used in csr and MAC for CB state*/ +ePhyChanBondState sme_get_cb_phy_state_from_cb_ini_value(uint32_t cb_ini_value) +{ + return csr_convert_cb_ini_value_to_phy_cb_state(cb_ini_value); +} + +/*-------------------------------------------------------------------------- + + \brief sme_set_curr_device_mode() - Sets the current operating device mode. + \param hHal - The handle returned by mac_open. + \param currDeviceMode - Current operating device mode. + --------------------------------------------------------------------------*/ + +void sme_set_curr_device_mode(tHalHandle hHal, + enum tQDF_ADAPTER_MODE currDeviceMode) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + pMac->sme.currDeviceMode = currDeviceMode; + return; +} + +/*-------------------------------------------------------------------------- + \brief sme_handoff_request() - a wrapper function to Request a handoff + from CSR. + This is a synchronous call + \param hHal - The handle returned by mac_open + \param sessionId - Session Identifier + \param pHandoffInfo - info provided by HDD with the handoff request (namely: + BSSID, channel etc.) + \return QDF_STATUS_SUCCESS - SME passed the request to CSR successfully. + Other status means SME is failed to send the request. + \sa + --------------------------------------------------------------------------*/ + +QDF_STATUS sme_handoff_request(tHalHandle hHal, + uint8_t sessionId, + tCsrHandoffRequest *pHandoffInfo) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + QDF_STATUS status = QDF_STATUS_SUCCESS; + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO, + "%s: invoked", __func__); + status = csr_handoff_request(pMac, sessionId, pHandoffInfo); + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +#ifdef IPA_OFFLOAD +/* --------------------------------------------------------------------------- + \fn sme_ipa_offload_enable_disable + \brief API to enable/disable IPA offload + \param hal - The handle returned by macOpen. + \param session_id - Session Identifier + \param request - Pointer to the offload request. + \return QDF_STATUS + ---------------------------------------------------------------------------*/ +QDF_STATUS sme_ipa_offload_enable_disable(tHalHandle hal, uint8_t session_id, + struct sir_ipa_offload_enable_disable *request) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hal); + QDF_STATUS status = QDF_STATUS_E_FAILURE; + struct sir_ipa_offload_enable_disable *request_buf; + cds_msg_t msg; + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_STATUS_SUCCESS == status) { + request_buf = qdf_mem_malloc(sizeof(*request_buf)); + if (NULL == request_buf) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Not able to allocate memory for IPA_OFFLOAD_ENABLE_DISABLE")); + sme_release_global_lock(&pMac->sme); + return QDF_STATUS_E_NOMEM; + } + + request_buf->offload_type = request->offload_type; + request_buf->vdev_id = request->vdev_id; + request_buf->enable = request->enable; + + msg.type = WMA_IPA_OFFLOAD_ENABLE_DISABLE; + msg.reserved = 0; + msg.bodyptr = request_buf; + if (!QDF_IS_STATUS_SUCCESS( + cds_mq_post_message(CDS_MQ_ID_WMA, &msg))) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Not able to post WMA_IPA_OFFLOAD_ENABLE_DISABLE message to WMA")); + qdf_mem_free(request_buf); + sme_release_global_lock(&pMac->sme); + return QDF_STATUS_E_FAILURE; + } + + sme_release_global_lock(&pMac->sme); + } + + return QDF_STATUS_SUCCESS; +} +#endif /* IPA_OFFLOAD */ + +/* + * SME API to check if there is any infra station or + * P2P client is connected + */ +QDF_STATUS sme_is_sta_p2p_client_connected(tHalHandle hHal) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + if (csr_is_infra_connected(pMac)) { + return QDF_STATUS_SUCCESS; + } + return QDF_STATUS_E_FAILURE; +} + +#ifdef FEATURE_WLAN_LPHB +/* --------------------------------------------------------------------------- + \fn sme_lphb_config_req + \API to make configuration LPHB within FW. + \param hHal - The handle returned by mac_open + \param lphdReq - LPHB request argument by client + \param pCallbackfn - LPHB timeout notification callback function pointer + \- return Configuration message posting status, SUCCESS or Fail + -------------------------------------------------------------------------*/ +QDF_STATUS sme_lphb_config_req + (tHalHandle hHal, + tSirLPHBReq *lphdReq, + void (*pCallbackfn)(void *pHddCtx, tSirLPHBInd * indParam) + ) { + QDF_STATUS status = QDF_STATUS_SUCCESS; + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + cds_msg_t cds_message; + + MTRACE(qdf_trace(QDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_LPHB_CONFIG_REQ, + NO_SESSION, lphdReq->cmd)); + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_STATUS_SUCCESS == status) { + if ((LPHB_SET_EN_PARAMS_INDID == lphdReq->cmd) && + (NULL == pCallbackfn) && (NULL == pMac->sme.pLphbIndCb)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Indication Call back did not registered", + __func__); + sme_release_global_lock(&pMac->sme); + return QDF_STATUS_E_FAILURE; + } else if (NULL != pCallbackfn) { + pMac->sme.pLphbIndCb = pCallbackfn; + } + + /* serialize the req through MC thread */ + cds_message.bodyptr = lphdReq; + cds_message.type = WMA_LPHB_CONF_REQ; + MTRACE(qdf_trace(QDF_MODULE_ID_SME, TRACE_CODE_SME_TX_WMA_MSG, + NO_SESSION, cds_message.type)); + qdf_status = cds_mq_post_message(CDS_MQ_ID_WMA, &cds_message); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Post Config LPHB MSG fail", __func__); + status = QDF_STATUS_E_FAILURE; + } + sme_release_global_lock(&pMac->sme); + } + + return status; +} +#endif /* FEATURE_WLAN_LPHB */ +/*-------------------------------------------------------------------------- + \brief sme_enable_disable_split_scan() - a wrapper function to set the split + scan parameter. + This is a synchronous call + \param hHal - The handle returned by mac_open + \return NONE. + \sa + --------------------------------------------------------------------------*/ +void sme_enable_disable_split_scan(tHalHandle hHal, uint8_t nNumStaChan, + uint8_t nNumP2PChan) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + pMac->roam.configParam.nNumStaChanCombinedConc = nNumStaChan; + pMac->roam.configParam.nNumP2PChanCombinedConc = nNumP2PChan; + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO, + "%s: SCAN nNumStaChanCombinedConc : %d," + "nNumP2PChanCombinedConc : %d ", + __func__, nNumStaChan, nNumP2PChan); + + return; + +} + +/** + * sme_add_periodic_tx_ptrn() - Add Periodic TX Pattern + * @hal: global hal handle + * @addPeriodicTxPtrnParams: request message + * + * Return: QDF_STATUS enumeration + */ +QDF_STATUS +sme_add_periodic_tx_ptrn(tHalHandle hal, + struct sSirAddPeriodicTxPtrn *addPeriodicTxPtrnParams) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpAniSirGlobal mac = PMAC_STRUCT(hal); + struct sSirAddPeriodicTxPtrn *req_msg; + cds_msg_t msg; + + sms_log(mac, LOG1, FL("enter")); + + req_msg = qdf_mem_malloc(sizeof(*req_msg)); + if (!req_msg) { + sms_log(mac, LOGE, FL("memory allocation failed")); + return QDF_STATUS_E_NOMEM; + } + + *req_msg = *addPeriodicTxPtrnParams; + + status = sme_acquire_global_lock(&mac->sme); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sms_log(mac, LOGE, + FL("sme_acquire_global_lock failed!(status=%d)"), + status); + qdf_mem_free(req_msg); + return status; + } + + /* Serialize the req through MC thread */ + msg.bodyptr = req_msg; + msg.type = WMA_ADD_PERIODIC_TX_PTRN_IND; + MTRACE(qdf_trace(QDF_MODULE_ID_SME, TRACE_CODE_SME_TX_WMA_MSG, + NO_SESSION, msg.type)); + status = cds_mq_post_message(QDF_MODULE_ID_WMA, &msg); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sms_log(mac, LOGE, + FL("cds_mq_post_message failed!(err=%d)"), + status); + qdf_mem_free(req_msg); + } + sme_release_global_lock(&mac->sme); + return status; +} + +/** + * sme_del_periodic_tx_ptrn() - Delete Periodic TX Pattern + * @hal: global hal handle + * @delPeriodicTxPtrnParams: request message + * + * Return: QDF_STATUS enumeration + */ +QDF_STATUS +sme_del_periodic_tx_ptrn(tHalHandle hal, + struct sSirDelPeriodicTxPtrn *delPeriodicTxPtrnParams) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpAniSirGlobal mac = PMAC_STRUCT(hal); + struct sSirDelPeriodicTxPtrn *req_msg; + cds_msg_t msg; + + sms_log(mac, LOG1, FL("enter")); + + req_msg = qdf_mem_malloc(sizeof(*req_msg)); + if (!req_msg) { + sms_log(mac, LOGE, FL("memory allocation failed")); + return QDF_STATUS_E_NOMEM; + } + + *req_msg = *delPeriodicTxPtrnParams; + + status = sme_acquire_global_lock(&mac->sme); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sms_log(mac, LOGE, + FL("sme_acquire_global_lock failed!(status=%d)"), + status); + qdf_mem_free(req_msg); + return status; + } + + /* Serialize the req through MC thread */ + msg.bodyptr = req_msg; + msg.type = WMA_DEL_PERIODIC_TX_PTRN_IND; + MTRACE(qdf_trace(QDF_MODULE_ID_SME, TRACE_CODE_SME_TX_WMA_MSG, + NO_SESSION, msg.type)); + status = cds_mq_post_message(QDF_MODULE_ID_WMA, &msg); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sms_log(mac, LOGE, + FL("cds_mq_post_message failed!(err=%d)"), + status); + qdf_mem_free(req_msg); + } + sme_release_global_lock(&mac->sme); + return status; +} + +/** + * sme_enable_rmc() - enables RMC + * @hHal : Pointer to global HAL handle + * @sessionId : Session ID + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_enable_rmc(tHalHandle hHal, uint32_t sessionId) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + cds_msg_t cds_message; + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + + sms_log(pMac, LOG1, FL("enable RMC")); + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + cds_message.bodyptr = NULL; + cds_message.type = WMA_RMC_ENABLE_IND; + qdf_status = cds_mq_post_message(CDS_MQ_ID_WMA, &cds_message); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: failed to post message to WMA", + __func__); + status = QDF_STATUS_E_FAILURE; + } + sme_release_global_lock(&pMac->sme); + } + return status; +} + +/** + * sme_disable_rmc() - disables RMC + * @hHal : Pointer to global HAL handle + * @sessionId : Session ID + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_disable_rmc(tHalHandle hHal, uint32_t sessionId) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + cds_msg_t cds_message; + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + + sms_log(pMac, LOG1, FL("disable RMC")); + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + cds_message.bodyptr = NULL; + cds_message.type = WMA_RMC_DISABLE_IND; + qdf_status = cds_mq_post_message(CDS_MQ_ID_WMA, &cds_message); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: failed to post message to WMA", + __func__); + status = QDF_STATUS_E_FAILURE; + } + sme_release_global_lock(&pMac->sme); + } + return status; +} + +/** + * sme_send_rmc_action_period() - sends RMC action period param to target + * @hHal : Pointer to global HAL handle + * @sessionId : Session ID + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_send_rmc_action_period(tHalHandle hHal, uint32_t sessionId) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + cds_msg_t cds_message; + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_STATUS_SUCCESS == status) { + cds_message.bodyptr = NULL; + cds_message.type = WMA_RMC_ACTION_PERIOD_IND; + qdf_status = cds_mq_post_message(CDS_MQ_ID_WMA, &cds_message); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: failed to post message to WMA", + __func__); + status = QDF_STATUS_E_FAILURE; + } + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +/** + * sme_request_ibss_peer_info() - request ibss peer info + * @hHal : Pointer to global HAL handle + * @pUserData : Pointer to user data + * @peerInfoCbk : Peer info callback + * @allPeerInfoReqd : All peer info required or not + * @staIdx : sta index + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_request_ibss_peer_info(tHalHandle hHal, void *pUserData, + pIbssPeerInfoCb peerInfoCbk, + bool allPeerInfoReqd, uint8_t staIdx) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + QDF_STATUS qdf_status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + cds_msg_t cds_message; + tSirIbssGetPeerInfoReqParams *pIbssInfoReqParams; + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_STATUS_SUCCESS == status) { + pMac->sme.peerInfoParams.peerInfoCbk = peerInfoCbk; + pMac->sme.peerInfoParams.pUserData = pUserData; + + pIbssInfoReqParams = (tSirIbssGetPeerInfoReqParams *) + qdf_mem_malloc(sizeof(tSirIbssGetPeerInfoReqParams)); + if (NULL == pIbssInfoReqParams) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Not able to allocate memory for dhcp start", + __func__); + sme_release_global_lock(&pMac->sme); + return QDF_STATUS_E_NOMEM; + } + pIbssInfoReqParams->allPeerInfoReqd = allPeerInfoReqd; + pIbssInfoReqParams->staIdx = staIdx; + + cds_message.type = WMA_GET_IBSS_PEER_INFO_REQ; + cds_message.bodyptr = pIbssInfoReqParams; + cds_message.reserved = 0; + + qdf_status = cds_mq_post_message(CDS_MQ_ID_WMA, &cds_message); + if (QDF_STATUS_SUCCESS != qdf_status) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Post WMA_GET_IBSS_PEER_INFO_REQ MSG failed", + __func__); + qdf_mem_free(pIbssInfoReqParams); + qdf_status = QDF_STATUS_E_FAILURE; + } + sme_release_global_lock(&pMac->sme); + } + + return qdf_status; +} + +/* --------------------------------------------------------------------------- + \fn sme_send_cesium_enable_ind + \brief Used to send proprietary cesium enable indication to fw + \param hHal + \param sessionId + \- return QDF_STATUS + -------------------------------------------------------------------------*/ +QDF_STATUS sme_send_cesium_enable_ind(tHalHandle hHal, uint32_t sessionId) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + cds_msg_t cds_message; + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_STATUS_SUCCESS == status) { + cds_message.bodyptr = NULL; + cds_message.type = WMA_IBSS_CESIUM_ENABLE_IND; + qdf_status = cds_mq_post_message(CDS_MQ_ID_WMA, &cds_message); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: failed to post message to WMA", + __func__); + status = QDF_STATUS_E_FAILURE; + } + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +void sme_get_command_q_status(tHalHandle hHal) +{ + tSmeCmd *pTempCmd = NULL; + tListElem *pEntry; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + if (NULL == pMac) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: pMac is NULL", __func__); + return; + } + + pEntry = csr_ll_peek_head(&pMac->sme.smeCmdActiveList, LL_ACCESS_LOCK); + if (pEntry) { + pTempCmd = GET_BASE_ADDR(pEntry, tSmeCmd, Link); + } + sms_log(pMac, LOGE, "Currently smeCmdActiveList has command (0x%X)", + (pTempCmd) ? pTempCmd->command : eSmeNoCommand); + if (pTempCmd) { + if (eSmeCsrCommandMask & pTempCmd->command) { + /* CSR command is stuck. See what the reason code is for that command */ + dump_csr_command_info(pMac, pTempCmd); + } + } /* if(pTempCmd) */ + + sms_log(pMac, LOGE, "Currently smeCmdPendingList has %d commands", + csr_ll_count(&pMac->sme.smeCmdPendingList)); + + sms_log(pMac, LOGE, "Currently roamCmdPendingList has %d commands", + csr_ll_count(&pMac->roam.roamCmdPendingList)); + + return; +} +/** + * sme_set_prefer_80MHz_over_160MHz() - API to set sta_prefer_80MHz_over_160MHz + * @hal: The handle returned by macOpen + * @sta_prefer_80MHz_over_160MHz: sta_prefer_80MHz_over_160MHz config param + */ +void sme_set_prefer_80MHz_over_160MHz(tHalHandle hal, + bool sta_prefer_80MHz_over_160MHz) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + mac_ctx->sta_prefer_80MHz_over_160MHz = sta_prefer_80MHz_over_160MHz; +} + +/** + * sme_set_allow_adj_ch_bcn() - API to set allow_adj_ch_bcn + * @hal: The handle returned by macOpen + * @allow_adj_ch_bcn: allow_adj_ch_bcn config param + */ +void sme_set_allow_adj_ch_bcn(tHalHandle hal, bool allow_adj_ch_bcn) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + + mac_ctx->allow_adj_ch_bcn = allow_adj_ch_bcn; +} +#ifdef WLAN_FEATURE_DSRC +/** + * sme_set_dot11p_config() - API to set the 802.11p config + * @hHal: The handle returned by macOpen + * @enable_dot11p: 802.11p config param + */ +void sme_set_dot11p_config(tHalHandle hHal, bool enable_dot11p) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + pMac->enable_dot11p = enable_dot11p; +} + +/** + * copy_sir_ocb_config() - Performs deep copy of an OCB configuration + * @src: the source configuration + * + * Return: pointer to the copied OCB configuration + */ +static struct sir_ocb_config *sme_copy_sir_ocb_config( + struct sir_ocb_config *src) +{ + struct sir_ocb_config *dst; + uint32_t length; + void *cursor; + + length = sizeof(*src) + + src->channel_count * sizeof(*src->channels) + + src->schedule_size * sizeof(*src->schedule) + + src->dcc_ndl_chan_list_len + + src->dcc_ndl_active_state_list_len + + src->def_tx_param_size; + + dst = qdf_mem_malloc(length); + if (!dst) + return NULL; + + *dst = *src; + + cursor = dst; + cursor += sizeof(*dst); + dst->channels = cursor; + cursor += src->channel_count * sizeof(*src->channels); + qdf_mem_copy(dst->channels, src->channels, + src->channel_count * sizeof(*src->channels)); + dst->schedule = cursor; + cursor += src->schedule_size * sizeof(*src->schedule); + qdf_mem_copy(dst->schedule, src->schedule, + src->schedule_size * sizeof(*src->schedule)); + dst->dcc_ndl_chan_list = cursor; + cursor += src->dcc_ndl_chan_list_len; + qdf_mem_copy(dst->dcc_ndl_chan_list, src->dcc_ndl_chan_list, + src->dcc_ndl_chan_list_len); + dst->dcc_ndl_active_state_list = cursor; + cursor += src->dcc_ndl_active_state_list_len; + qdf_mem_copy(dst->dcc_ndl_active_state_list, + src->dcc_ndl_active_state_list, + src->dcc_ndl_active_state_list_len); + cursor += src->dcc_ndl_active_state_list_len; + if (src->def_tx_param && src->def_tx_param_size) { + dst->def_tx_param = cursor; + qdf_mem_copy(dst->def_tx_param, src->def_tx_param, + src->def_tx_param_size); + } + return dst; +} + +/** + * sme_ocb_set_config() - Set the OCB configuration + * @hHal: reference to the HAL + * @context: the context of the call + * @callback: the callback to hdd + * @config: the OCB configuration + * + * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_FAILURE on failure + */ +QDF_STATUS sme_ocb_set_config(tHalHandle hHal, void *context, + ocb_callback callback, + struct sir_ocb_config *config) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + cds_msg_t msg = {0}; + struct sir_ocb_config *msg_body; + + /* Lock the SME structure */ + status = sme_acquire_global_lock(&pMac->sme); + if (!QDF_IS_STATUS_SUCCESS(status)) + return status; + + /* + * Check if there is a pending request and return an error if one + * exists + */ + if (pMac->sme.ocb_set_config_callback) { + status = QDF_STATUS_E_BUSY; + goto end; + } + + msg_body = sme_copy_sir_ocb_config(config); + + if (!msg_body) { + status = QDF_STATUS_E_NOMEM; + goto end; + } + + msg.type = WMA_OCB_SET_CONFIG_CMD; + msg.bodyptr = msg_body; + + /* Set the request callback and context */ + pMac->sme.ocb_set_config_callback = callback; + pMac->sme.ocb_set_config_context = context; + + status = cds_mq_post_message(QDF_MODULE_ID_WMA, &msg); + if (!QDF_IS_STATUS_SUCCESS(status)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Error posting message to WDA: %d"), status); + pMac->sme.ocb_set_config_callback = callback; + pMac->sme.ocb_set_config_context = context; + qdf_mem_free(msg_body); + goto end; + } + +end: + sme_release_global_lock(&pMac->sme); + + return status; +} + +/** + * sme_ocb_set_utc_time() - Set the OCB UTC time + * @hHal: reference to the HAL + * @utc: the UTC time struct + * + * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_FAILURE on failure + */ +QDF_STATUS sme_ocb_set_utc_time(tHalHandle hHal, struct sir_ocb_utc *utc) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + cds_msg_t msg = {0}; + struct sir_ocb_utc *sme_utc; + + /* Lock the SME structure */ + status = sme_acquire_global_lock(&pMac->sme); + if (!QDF_IS_STATUS_SUCCESS(status)) + return status; + + sme_utc = qdf_mem_malloc(sizeof(*sme_utc)); + if (!sme_utc) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Malloc failed")); + status = QDF_STATUS_E_NOMEM; + goto end; + } + *sme_utc = *utc; + + msg.type = WMA_OCB_SET_UTC_TIME_CMD; + msg.reserved = 0; + msg.bodyptr = sme_utc; + status = cds_mq_post_message(QDF_MODULE_ID_WMA, &msg); + if (!QDF_IS_STATUS_SUCCESS(status)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Not able to post message to WDA")); + qdf_mem_free(utc); + goto end; + } + +end: + sme_release_global_lock(&pMac->sme); + + return status; +} + +/** + * sme_ocb_start_timing_advert() - Start sending timing advert frames + * @hHal: reference to the HAL + * @timing_advert: the timing advertisement struct + * + * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_FAILURE on failure + */ +QDF_STATUS sme_ocb_start_timing_advert(tHalHandle hHal, + struct sir_ocb_timing_advert *timing_advert) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + cds_msg_t msg = {0}; + void *buf; + struct sir_ocb_timing_advert *sme_timing_advert; + + /* Lock the SME structure */ + status = sme_acquire_global_lock(&pMac->sme); + if (!QDF_IS_STATUS_SUCCESS(status)) + return status; + + buf = qdf_mem_malloc(sizeof(*sme_timing_advert) + + timing_advert->template_length); + if (!buf) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Not able to allocate memory for start TA")); + status = QDF_STATUS_E_NOMEM; + goto end; + } + + sme_timing_advert = (struct sir_ocb_timing_advert *)buf; + *sme_timing_advert = *timing_advert; + sme_timing_advert->template_value = buf + sizeof(*sme_timing_advert); + qdf_mem_copy(sme_timing_advert->template_value, + timing_advert->template_value, timing_advert->template_length); + + msg.type = WMA_OCB_START_TIMING_ADVERT_CMD; + msg.reserved = 0; + msg.bodyptr = buf; + status = cds_mq_post_message(QDF_MODULE_ID_WMA, &msg); + if (!QDF_IS_STATUS_SUCCESS(status)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Not able to post msg to WDA")); + goto end; + } + +end: + sme_release_global_lock(&pMac->sme); + + return status; +} + +/** + * sme_ocb_stop_timing_advert() - Stop sending timing advert frames on a channel + * @hHal: reference to the HAL + * @timing_advert: the timing advertisement struct + * + * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_FAILURE on failure + */ +QDF_STATUS sme_ocb_stop_timing_advert(tHalHandle hHal, + struct sir_ocb_timing_advert *timing_advert) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + cds_msg_t msg = {0}; + struct sir_ocb_timing_advert *sme_timing_advert; + + /* Lock the SME structure */ + status = sme_acquire_global_lock(&pMac->sme); + if (!QDF_IS_STATUS_SUCCESS(status)) + return status; + + sme_timing_advert = qdf_mem_malloc(sizeof(*timing_advert)); + if (!sme_timing_advert) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Not able to allocate memory for stop TA")); + status = QDF_STATUS_E_NOMEM; + goto end; + } + *sme_timing_advert = *timing_advert; + + msg.type = WMA_OCB_STOP_TIMING_ADVERT_CMD; + msg.reserved = 0; + msg.bodyptr = sme_timing_advert; + status = cds_mq_post_message(QDF_MODULE_ID_WMA, &msg); + if (!QDF_IS_STATUS_SUCCESS(status)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Not able to post msg to WDA")); + goto end; + } + +end: + sme_release_global_lock(&pMac->sme); + + return status; +} + +/** + * sme_ocb_gen_timing_advert_frame() - generate TA frame and populate the buffer + * @hal_handle: reference to the HAL + * @self_addr: the self MAC address + * @buf: the buffer that will contain the frame + * @timestamp_offset: return for the offset of the timestamp field + * @time_value_offset: return for the time_value field in the TA IE + * + * Return: the length of the buffer. + */ +int sme_ocb_gen_timing_advert_frame(tHalHandle hal_handle, + tSirMacAddr self_addr, uint8_t **buf, + uint32_t *timestamp_offset, + uint32_t *time_value_offset) +{ + int template_length; + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal_handle); + + template_length = sch_gen_timing_advert_frame(mac_ctx, self_addr, buf, + timestamp_offset, + time_value_offset); + return template_length; +} +/** + * sme_ocb_get_tsf_timer() - Get the TSF timer value + * @hHal: reference to the HAL + * @context: the context of the call + * @callback: the callback to hdd + * @request: the TSF timer request + * + * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_FAILURE on failure + */ +QDF_STATUS sme_ocb_get_tsf_timer(tHalHandle hHal, void *context, + ocb_callback callback, + struct sir_ocb_get_tsf_timer *request) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + cds_msg_t msg = {0}; + struct sir_ocb_get_tsf_timer *msg_body; + + /* Lock the SME structure */ + status = sme_acquire_global_lock(&pMac->sme); + if (!QDF_IS_STATUS_SUCCESS(status)) + return status; + + /* Allocate memory for the WMI request, and copy the parameter */ + msg_body = qdf_mem_malloc(sizeof(*msg_body)); + if (!msg_body) { + status = QDF_STATUS_E_NOMEM; + goto end; + } + *msg_body = *request; + + msg.type = WMA_OCB_GET_TSF_TIMER_CMD; + msg.bodyptr = msg_body; + + /* Set the request callback and the context */ + pMac->sme.ocb_get_tsf_timer_callback = callback; + pMac->sme.ocb_get_tsf_timer_context = context; + + /* Post the message to WDA */ + status = cds_mq_post_message(QDF_MODULE_ID_WMA, &msg); + if (!QDF_IS_STATUS_SUCCESS(status)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Error posting message to WDA: %d"), status); + pMac->sme.ocb_get_tsf_timer_callback = NULL; + pMac->sme.ocb_get_tsf_timer_context = NULL; + qdf_mem_free(msg_body); + goto end; + } + +end: + sme_release_global_lock(&pMac->sme); + + return status; +} + +/** + * sme_dcc_get_stats() - Get the DCC stats + * @hHal: reference to the HAL + * @context: the context of the call + * @callback: the callback to hdd + * @request: the get DCC stats request + * + * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_FAILURE on failure + */ +QDF_STATUS sme_dcc_get_stats(tHalHandle hHal, void *context, + ocb_callback callback, + struct sir_dcc_get_stats *request) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + cds_msg_t msg = {0}; + struct sir_dcc_get_stats *msg_body; + + /* Lock the SME structure */ + status = sme_acquire_global_lock(&pMac->sme); + if (!QDF_IS_STATUS_SUCCESS(status)) + return status; + + /* Allocate memory for the WMI request, and copy the parameter */ + msg_body = qdf_mem_malloc(sizeof(*msg_body) + + request->request_array_len); + if (!msg_body) { + status = QDF_STATUS_E_NOMEM; + goto end; + } + *msg_body = *request; + msg_body->request_array = (void *)msg_body + sizeof(*msg_body); + qdf_mem_copy(msg_body->request_array, request->request_array, + request->request_array_len); + + msg.type = WMA_DCC_GET_STATS_CMD; + msg.bodyptr = msg_body; + + /* Set the request callback and context */ + pMac->sme.dcc_get_stats_callback = callback; + pMac->sme.dcc_get_stats_context = context; + + status = cds_mq_post_message(QDF_MODULE_ID_WMA, &msg); + if (!QDF_IS_STATUS_SUCCESS(status)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Error posting message to WDA: %d"), status); + pMac->sme.dcc_get_stats_callback = callback; + pMac->sme.dcc_get_stats_context = context; + qdf_mem_free(msg_body); + goto end; + } + +end: + sme_release_global_lock(&pMac->sme); + + return status; +} + +/** + * sme_dcc_clear_stats() - Clear the DCC stats + * @hHal: reference to the HAL + * @vdev_id: vdev id for OCB interface + * @dcc_stats_bitmap: the entries in the stats to clear + * + * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_FAILURE on failure + */ +QDF_STATUS sme_dcc_clear_stats(tHalHandle hHal, uint32_t vdev_id, + uint32_t dcc_stats_bitmap) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + cds_msg_t msg = {0}; + struct sir_dcc_clear_stats *request; + + /* Lock the SME structure */ + status = sme_acquire_global_lock(&pMac->sme); + if (!QDF_IS_STATUS_SUCCESS(status)) + return status; + + request = qdf_mem_malloc(sizeof(struct sir_dcc_clear_stats)); + if (!request) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Not able to allocate memory")); + status = QDF_STATUS_E_NOMEM; + goto end; + } + + request->vdev_id = vdev_id; + request->dcc_stats_bitmap = dcc_stats_bitmap; + + msg.type = WMA_DCC_CLEAR_STATS_CMD; + msg.bodyptr = request; + + status = cds_mq_post_message(QDF_MODULE_ID_WMA, &msg); + if (!QDF_IS_STATUS_SUCCESS(status)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Not able to post msg to WDA")); + qdf_mem_free(request); + goto end; + } + +end: + sme_release_global_lock(&pMac->sme); + + return status; +} + +/** + * sme_dcc_update_ndl() - Update the DCC settings + * @hHal: reference to the HAL + * @context: the context of the call + * @callback: the callback to hdd + * @request: the update DCC request + * + * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_FAILURE on failure + */ +QDF_STATUS sme_dcc_update_ndl(tHalHandle hHal, void *context, + ocb_callback callback, + struct sir_dcc_update_ndl *request) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + cds_msg_t msg = {0}; + struct sir_dcc_update_ndl *msg_body; + + /* Lock the SME structure */ + status = sme_acquire_global_lock(&pMac->sme); + if (!QDF_IS_STATUS_SUCCESS(status)) + return status; + + /* Allocate memory for the WMI request, and copy the parameter */ + msg_body = qdf_mem_malloc(sizeof(*msg_body) + + request->dcc_ndl_chan_list_len + + request->dcc_ndl_active_state_list_len); + if (!msg_body) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Failed to allocate memory")); + status = QDF_STATUS_E_NOMEM; + goto end; + } + + *msg_body = *request; + + msg_body->dcc_ndl_chan_list = (void *)msg_body + sizeof(*msg_body); + msg_body->dcc_ndl_active_state_list = msg_body->dcc_ndl_chan_list + + request->dcc_ndl_chan_list_len; + qdf_mem_copy(msg_body->dcc_ndl_chan_list, request->dcc_ndl_chan_list, + request->dcc_ndl_active_state_list_len); + qdf_mem_copy(msg_body->dcc_ndl_active_state_list, + request->dcc_ndl_active_state_list, + request->dcc_ndl_active_state_list_len); + + msg.type = WMA_DCC_UPDATE_NDL_CMD; + msg.bodyptr = msg_body; + + /* Set the request callback and the context */ + pMac->sme.dcc_update_ndl_callback = callback; + pMac->sme.dcc_update_ndl_context = context; + + status = cds_mq_post_message(QDF_MODULE_ID_WMA, &msg); + if (!QDF_IS_STATUS_SUCCESS(status)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Error posting message to WDA: %d"), status); + pMac->sme.dcc_update_ndl_callback = NULL; + pMac->sme.dcc_update_ndl_context = NULL; + qdf_mem_free(msg_body); + goto end; + } + +end: + sme_release_global_lock(&pMac->sme); + + return status; +} + +/** + * sme_register_for_dcc_stats_event() - Register for the periodic DCC stats + * event + * @hHal: reference to the HAL + * @context: the context of the call + * @callback: the callback to hdd + * + * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_FAILURE on failure + */ +QDF_STATUS sme_register_for_dcc_stats_event(tHalHandle hHal, void *context, + ocb_callback callback) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + QDF_STATUS status = QDF_STATUS_E_FAILURE; + + status = sme_acquire_global_lock(&pMac->sme); + pMac->sme.dcc_stats_event_callback = callback; + pMac->sme.dcc_stats_event_context = context; + sme_release_global_lock(&pMac->sme); + + return 0; +} + +/** + * sme_deregister_for_dcc_stats_event() - De-Register for the periodic DCC stats + * event + * @h_hal: Hal Handle + * + * This function de-registers the DCC perioc stats callback + * + * Return: QDF_STATUS Enumeration + */ +QDF_STATUS sme_deregister_for_dcc_stats_event(tHalHandle h_hal) +{ + tpAniSirGlobal mac; + QDF_STATUS status; + + if (!h_hal) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("h_hal is not valid")); + return QDF_STATUS_E_INVAL; + } + mac = PMAC_STRUCT(h_hal); + + status = sme_acquire_global_lock(&mac->sme); + if (!QDF_IS_STATUS_SUCCESS(status)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Failed to acquire global lock")); + return status; + } + mac->sme.dcc_stats_event_callback = NULL; + mac->sme.dcc_stats_event_context = NULL; + sme_release_global_lock(&mac->sme); + + return status; +} +#endif + +void sme_get_recovery_stats(tHalHandle hHal) +{ + uint8_t i; + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "Self Recovery Stats"); + for (i = 0; i < MAX_ACTIVE_CMD_STATS; i++) { + if (eSmeNoCommand != + g_self_recovery_stats.activeCmdStats[i].command) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "timestamp %llu: command 0x%0X: reason %d: session %d", + g_self_recovery_stats.activeCmdStats[i]. + timestamp, + g_self_recovery_stats.activeCmdStats[i].command, + g_self_recovery_stats.activeCmdStats[i].reason, + g_self_recovery_stats.activeCmdStats[i]. + sessionId); + } + } +} + +/** + * sme_save_active_cmd_stats() - To save active command stats + * @hHal: HAL context + * + * This routine is to save active command stats + * + * Return: None + */ +static void sme_save_active_cmd_stats(tHalHandle hHal) +{ + tSmeCmd *pTempCmd = NULL; + tListElem *pEntry; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + uint8_t statidx = 0; + tActiveCmdStats *actv_cmd_stat = NULL; + + if (NULL == pMac) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("pMac is NULL")); + return; + } + + pEntry = csr_ll_peek_head(&pMac->sme.smeCmdActiveList, LL_ACCESS_LOCK); + if (pEntry) + pTempCmd = GET_BASE_ADDR(pEntry, tSmeCmd, Link); + + if (!pTempCmd) + return; + + if (eSmeCsrCommandMask & pTempCmd->command) { + statidx = g_self_recovery_stats.cmdStatsIndx; + actv_cmd_stat = &g_self_recovery_stats.activeCmdStats[statidx]; + actv_cmd_stat->command = pTempCmd->command; + actv_cmd_stat->sessionId = pTempCmd->sessionId; + actv_cmd_stat->timestamp = cds_get_monotonic_boottime(); + if (eSmeCommandRoam == pTempCmd->command) + actv_cmd_stat->reason = pTempCmd->u.roamCmd.roamReason; + else if (eSmeCommandScan == pTempCmd->command) + actv_cmd_stat->reason = pTempCmd->u.scanCmd.reason; + else + actv_cmd_stat->reason = 0xFF; + + g_self_recovery_stats.cmdStatsIndx = + ((g_self_recovery_stats.cmdStatsIndx + 1) & + (MAX_ACTIVE_CMD_STATS - 1)); + } + return; +} + +void active_list_cmd_timeout_handle(void *userData) +{ + tHalHandle hal = (tHalHandle)userData; + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + tListElem *entry; + tSmeCmd *temp_cmd = NULL; + + if (NULL == mac_ctx) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: mac_ctx is null", __func__); + return; + } + /* Return if no cmd pending in active list as + * in this case we should not be here. + */ + if (0 == csr_ll_count(&mac_ctx->sme.smeCmdActiveList)) + return; + sms_log(mac_ctx, LOGE, + FL("Active List command timeout Cmd List Count %d"), + csr_ll_count(&mac_ctx->sme.smeCmdActiveList)); + sme_get_command_q_status(hal); + + if (mac_ctx->roam.configParam.enable_fatal_event) + cds_flush_logs(WLAN_LOG_TYPE_FATAL, + WLAN_LOG_INDICATOR_HOST_DRIVER, + WLAN_LOG_REASON_SME_COMMAND_STUCK, + false, + mac_ctx->sme.enableSelfRecovery ? true : false); + else + qdf_trace_dump_all(mac_ctx, 0, 0, 500, 0); + + entry = csr_ll_peek_head(&mac_ctx->sme.smeCmdActiveList, + LL_ACCESS_LOCK); + if (entry) + temp_cmd = GET_BASE_ADDR(entry, tSmeCmd, Link); + /* Ignore if ROC took more than 120 sec */ + if (temp_cmd && (eSmeCommandRemainOnChannel == temp_cmd->command)) + return; + + if (mac_ctx->sme.enableSelfRecovery) { + sme_save_active_cmd_stats(hal); + cds_trigger_recovery(false); + } else { + if (!mac_ctx->roam.configParam.enable_fatal_event && + !(cds_is_load_or_unload_in_progress() || + cds_is_driver_recovering())) + QDF_BUG(0); + } +} + +QDF_STATUS sme_notify_modem_power_state(tHalHandle hHal, uint32_t value) +{ + cds_msg_t msg; + tpSirModemPowerStateInd request_buf; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + if (NULL == pMac) { + return QDF_STATUS_E_FAILURE; + } + + request_buf = qdf_mem_malloc(sizeof(tSirModemPowerStateInd)); + if (NULL == request_buf) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Not able to allocate memory for MODEM POWER STATE IND", + __func__); + return QDF_STATUS_E_NOMEM; + } + + request_buf->param = value; + + msg.type = WMA_MODEM_POWER_STATE_IND; + msg.reserved = 0; + msg.bodyptr = request_buf; + if (!QDF_IS_STATUS_SUCCESS + (cds_mq_post_message(QDF_MODULE_ID_WMA, &msg))) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Not able to post WMA_MODEM_POWER_STATE_IND message" + " to WMA", __func__); + qdf_mem_free(request_buf); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +#ifdef QCA_HT_2040_COEX +QDF_STATUS sme_notify_ht2040_mode(tHalHandle hHal, uint16_t staId, + struct qdf_mac_addr macAddrSTA, + uint8_t sessionId, + uint8_t channel_type) +{ + cds_msg_t msg; + tUpdateVHTOpMode *pHtOpMode = NULL; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + if (NULL == pMac) { + return QDF_STATUS_E_FAILURE; + } + + pHtOpMode = qdf_mem_malloc(sizeof(tUpdateVHTOpMode)); + if (NULL == pHtOpMode) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Not able to allocate memory for setting OP mode", + __func__); + return QDF_STATUS_E_NOMEM; + } + + switch (channel_type) { + case eHT_CHAN_HT20: + pHtOpMode->opMode = eHT_CHANNEL_WIDTH_20MHZ; + break; + + case eHT_CHAN_HT40MINUS: + case eHT_CHAN_HT40PLUS: + pHtOpMode->opMode = eHT_CHANNEL_WIDTH_40MHZ; + break; + + default: + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid OP mode", __func__); + return QDF_STATUS_E_FAILURE; + } + + pHtOpMode->dot11_mode = sme_get_wni_dot11_mode(hHal); + pHtOpMode->staId = staId; + qdf_mem_copy(pHtOpMode->peer_mac, macAddrSTA.bytes, + sizeof(tSirMacAddr)); + pHtOpMode->smesessionId = sessionId; + + msg.type = WMA_UPDATE_OP_MODE; + msg.reserved = 0; + msg.bodyptr = pHtOpMode; + if (!QDF_IS_STATUS_SUCCESS + (cds_mq_post_message(QDF_MODULE_ID_WMA, &msg))) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Not able to post WMA_UPDATE_OP_MODE message" + " to WMA", __func__); + qdf_mem_free(pHtOpMode); + return QDF_STATUS_E_FAILURE; + } + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO, + "%s: Notifed FW about OP mode: %d for staId=%d", + __func__, pHtOpMode->opMode, staId); + + return QDF_STATUS_SUCCESS; +} + +/* --------------------------------------------------------------------------- + + \fn sme_set_ht2040_mode + + \brief To update HT Operation beacon IE. + + \param + + \return QDF_STATUS SUCCESS + FAILURE or RESOURCES + The API finished and failed. + + -------------------------------------------------------------------------------*/ +QDF_STATUS sme_set_ht2040_mode(tHalHandle hHal, uint8_t sessionId, + uint8_t channel_type, bool obssEnabled) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + ePhyChanBondState cbMode; + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO, + "%s: Update HT operation beacon IE, channel_type=%d", + __func__, channel_type); + + switch (channel_type) { + case eHT_CHAN_HT20: + cbMode = PHY_SINGLE_CHANNEL_CENTERED; + break; + case eHT_CHAN_HT40MINUS: + cbMode = PHY_DOUBLE_CHANNEL_HIGH_PRIMARY; + break; + case eHT_CHAN_HT40PLUS: + cbMode = PHY_DOUBLE_CHANNEL_LOW_PRIMARY; + break; + default: + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s:Error!!! Invalid HT20/40 mode !", __func__); + return QDF_STATUS_E_FAILURE; + } + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + status = csr_set_ht2040_mode(pMac, sessionId, + cbMode, obssEnabled); + sme_release_global_lock(&pMac->sme); + } + return status; +} + +#endif + +/* + * SME API to enable/disable idle mode powersave + * This should be called only if powersave offload + * is enabled + */ +QDF_STATUS sme_set_idle_powersave_config(bool value) +{ + void *wmaContext = cds_get_context(QDF_MODULE_ID_WMA); + + if (NULL == wmaContext) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: wmaContext is NULL", __func__); + return QDF_STATUS_E_FAILURE; + } + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + " Idle Ps Set Value %d", value); + + if (QDF_STATUS_SUCCESS != wma_set_idle_ps_config(wmaContext, value)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + " Failed to Set Idle Ps Value %d", value); + return QDF_STATUS_E_FAILURE; + } + return QDF_STATUS_SUCCESS; +} + +int16_t sme_get_ht_config(tHalHandle hHal, uint8_t session_id, uint16_t ht_capab) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, session_id); + + if (NULL == pSession) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: pSession is NULL", __func__); + return -EIO; + } + switch (ht_capab) { + case WNI_CFG_HT_CAP_INFO_ADVANCE_CODING: + return pSession->htConfig.ht_rx_ldpc; + case WNI_CFG_HT_CAP_INFO_TX_STBC: + return pSession->htConfig.ht_tx_stbc; + case WNI_CFG_HT_CAP_INFO_RX_STBC: + return pSession->htConfig.ht_rx_stbc; + case WNI_CFG_HT_CAP_INFO_SHORT_GI_20MHZ: + return pSession->htConfig.ht_sgi20; + case WNI_CFG_HT_CAP_INFO_SHORT_GI_40MHZ: + return pSession->htConfig.ht_sgi40; + default: + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "invalid ht capability"); + return -EIO; + } +} + +int sme_update_ht_config(tHalHandle hHal, uint8_t sessionId, uint16_t htCapab, + int value) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + + if (NULL == pSession) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: pSession is NULL", __func__); + return -EIO; + } + + if (QDF_STATUS_SUCCESS != wma_set_htconfig(sessionId, htCapab, value)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "Failed to set ht capability in target"); + return -EIO; + } + + switch (htCapab) { + case WNI_CFG_HT_CAP_INFO_ADVANCE_CODING: + pSession->htConfig.ht_rx_ldpc = value; + break; + case WNI_CFG_HT_CAP_INFO_TX_STBC: + pSession->htConfig.ht_tx_stbc = value; + break; + case WNI_CFG_HT_CAP_INFO_RX_STBC: + pSession->htConfig.ht_rx_stbc = value; + break; + case WNI_CFG_HT_CAP_INFO_SHORT_GI_20MHZ: + pSession->htConfig.ht_sgi20 = value; + break; + case WNI_CFG_HT_CAP_INFO_SHORT_GI_40MHZ: + pSession->htConfig.ht_sgi40 = value; + break; + } + + csr_roam_update_config(pMac, sessionId, htCapab, value); + return 0; +} + +#define HT20_SHORT_GI_MCS7_RATE 722 +/* --------------------------------------------------------------------------- + \fn sme_send_rate_update_ind + \brief API to Update rate + \param hHal - The handle returned by mac_open + \param rateUpdateParams - Pointer to rate update params + \return QDF_STATUS + ---------------------------------------------------------------------------*/ +QDF_STATUS sme_send_rate_update_ind(tHalHandle hHal, + tSirRateUpdateInd *rateUpdateParams) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + QDF_STATUS status; + cds_msg_t msg; + tSirRateUpdateInd *rate_upd = qdf_mem_malloc(sizeof(tSirRateUpdateInd)); + + if (rate_upd == NULL) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "Rate update struct alloc failed"); + return QDF_STATUS_E_FAILURE; + } + *rate_upd = *rateUpdateParams; + + if (rate_upd->mcastDataRate24GHz == HT20_SHORT_GI_MCS7_RATE) + rate_upd->mcastDataRate24GHzTxFlag = + eHAL_TX_RATE_HT20 | eHAL_TX_RATE_SGI; + else if (rate_upd->reliableMcastDataRate == + HT20_SHORT_GI_MCS7_RATE) + rate_upd->reliableMcastDataRateTxFlag = + eHAL_TX_RATE_HT20 | eHAL_TX_RATE_SGI; + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_STATUS_SUCCESS == status) { + msg.type = WMA_RATE_UPDATE_IND; + msg.bodyptr = rate_upd; + MTRACE(qdf_trace(QDF_MODULE_ID_SME, TRACE_CODE_SME_TX_WMA_MSG, + NO_SESSION, msg.type)); + if (!QDF_IS_STATUS_SUCCESS + (cds_mq_post_message(QDF_MODULE_ID_WMA, &msg))) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Not able " + "to post WMA_SET_RMC_RATE_IND to WMA!", + __func__); + + sme_release_global_lock(&pMac->sme); + qdf_mem_free(rate_upd); + return QDF_STATUS_E_FAILURE; + } + + sme_release_global_lock(&pMac->sme); + return QDF_STATUS_SUCCESS; + } + + return status; +} + +/** + * sme_update_access_policy_vendor_ie() - update vendor ie and access policy. + * @hal: Pointer to the mac context + * @session_id: sme session id + * @vendor_ie: vendor ie + * @access_policy: vendor ie access policy + * + * This function updates the vendor ie and access policy to lim. + * + * Return: success or failure. + */ +QDF_STATUS sme_update_access_policy_vendor_ie(tHalHandle hal, + uint8_t session_id, uint8_t *vendor_ie, int access_policy) +{ + struct sme_update_access_policy_vendor_ie *msg; + uint16_t msg_len; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal mac = PMAC_STRUCT(hal); + + msg_len = sizeof(*msg); + + msg = qdf_mem_malloc(msg_len); + if (!msg) { + sms_log(mac, LOGE, + "failed to allocate memory for sme_update_access_policy_vendor_ie"); + return QDF_STATUS_E_FAILURE; + } + + msg->msg_type = (uint16_t)eWNI_SME_UPDATE_ACCESS_POLICY_VENDOR_IE; + msg->length = (uint16_t)msg_len; + + qdf_mem_copy(&msg->ie[0], vendor_ie, sizeof(msg->ie)); + + msg->sme_session_id = session_id; + msg->access_policy = access_policy; + + sms_log(mac, LOG1, "sme_session_id %hu, access_policy %d", session_id, + access_policy); + + status = cds_send_mb_message_to_mac(msg); + + return status; +} + +/** + * sme_update_short_retry_limit_threshold() - update short frame retry limit TH + * @hal: Handle returned by mac_open + * @session_id: Session ID on which short frame retry limit needs to be + * updated to FW + * @short_limit_count_th: Retry count TH to retry short frame. + * + * This function is used to configure count to retry short frame. + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_update_short_retry_limit_threshold(tHalHandle hal_handle, + struct sme_short_retry_limit *short_retry_limit_th) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal_handle); + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct sme_short_retry_limit *srl; + cds_msg_t msg; + + srl = qdf_mem_malloc(sizeof(*srl)); + if (NULL == srl) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: fail to alloc short retry limit", __func__); + return QDF_STATUS_E_FAILURE; + } + sms_log(mac_ctx, LOG1, FL("session_id %d short retry limit count: %d"), + short_retry_limit_th->session_id, + short_retry_limit_th->short_retry_limit); + + srl->session_id = short_retry_limit_th->session_id; + srl->short_retry_limit = short_retry_limit_th->short_retry_limit; + + qdf_mem_zero(&msg, sizeof(msg)); + msg.type = SIR_HAL_SHORT_RETRY_LIMIT_CNT; + msg.reserved = 0; + msg.bodyptr = srl; + status = cds_mq_post_message(QDF_MODULE_ID_WMA, &msg); + if (status != QDF_STATUS_SUCCESS) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Not able to post short retry limit count to WDA")); + qdf_mem_free(srl); + return QDF_STATUS_E_FAILURE; + } + + return status; +} + +/** + * sme_update_long_retry_limit_threshold() - update long retry limit TH + * @hal: Handle returned by mac_open + * @session_id: Session ID on which long frames retry TH needs to be updated + * to FW + * @long_limit_count_th: Retry count to retry long frame. + * + * This function is used to configure TH to retry long frame. + * + * Return: QDF_STATUS +*/ +QDF_STATUS sme_update_long_retry_limit_threshold(tHalHandle hal_handle, + struct sme_long_retry_limit *long_retry_limit_th) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal_handle); + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct sme_long_retry_limit *lrl; + cds_msg_t msg; + + lrl = qdf_mem_malloc(sizeof(*lrl)); + if (NULL == lrl) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: fail to alloc long retry limit", __func__); + return QDF_STATUS_E_FAILURE; + } + sms_log(mac_ctx, LOG1, FL("session_id %d long retry limit count: %d"), + long_retry_limit_th->session_id, + long_retry_limit_th->long_retry_limit); + + lrl->session_id = long_retry_limit_th->session_id; + lrl->long_retry_limit = long_retry_limit_th->long_retry_limit; + + qdf_mem_zero(&msg, sizeof(msg)); + msg.type = SIR_HAL_LONG_RETRY_LIMIT_CNT; + msg.reserved = 0; + msg.bodyptr = lrl; + status = cds_mq_post_message(QDF_MODULE_ID_WMA, &msg); + + if (status != QDF_STATUS_SUCCESS) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Not able to post long retry limit count to WDA")); + qdf_mem_free(lrl); + return QDF_STATUS_E_FAILURE; + } + + return status; +} + +/** + * sme_update_sta_inactivity_timeout(): Update sta_inactivity_timeout to FW + * @hal: Handle returned by mac_open + * @session_id: Session ID on which sta_inactivity_timeout needs + * to be updated to FW + * @sta_inactivity_timeout: sta inactivity timeout. + * + * If a station does not send anything in sta_inactivity_timeout seconds, an + * empty data frame is sent to it in order to verify whether it is + * still in range. If this frame is not ACKed, the station will be + * disassociated and then deauthenticated. + * + * Return: QDF_STATUS_SUCCESS or non-zero on failure. +*/ +QDF_STATUS sme_update_sta_inactivity_timeout(tHalHandle hal_handle, + struct sme_sta_inactivity_timeout *sta_inactivity_timer) +{ + struct sme_sta_inactivity_timeout *inactivity_time; + void *wma_handle; + + wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + inactivity_time = qdf_mem_malloc(sizeof(*inactivity_time)); + if (NULL == inactivity_time) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: fail to alloc inactivity_time", __func__); + return QDF_STATUS_E_FAILURE; + } + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO, + FL("sta_inactivity_timeout: %d"), + sta_inactivity_timer->sta_inactivity_timeout); + inactivity_time->session_id = sta_inactivity_timer->session_id; + inactivity_time->sta_inactivity_timeout = + sta_inactivity_timer->sta_inactivity_timeout; + + wma_update_sta_inactivity_timeout(wma_handle, + inactivity_time); + return QDF_STATUS_SUCCESS; +} + +/** + * sme_get_reg_info() - To get registration info + * @hHal: HAL context + * @chanId: channel id + * @regInfo1: first reg info to fill + * @regInfo2: second reg info to fill + * + * This routine will give you reg info + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_get_reg_info(tHalHandle hHal, uint8_t chanId, + uint32_t *regInfo1, uint32_t *regInfo2) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + QDF_STATUS status; + uint8_t i; + bool found = false; + + status = sme_acquire_global_lock(&pMac->sme); + *regInfo1 = 0; + *regInfo2 = 0; + if (!QDF_IS_STATUS_SUCCESS(status)) + return status; + + for (i = 0; i < WNI_CFG_VALID_CHANNEL_LIST_LEN; i++) { + if (pMac->scan.defaultPowerTable[i].chan_num == chanId) { + SME_SET_CHANNEL_REG_POWER(*regInfo1, + pMac->scan.defaultPowerTable[i].power); + + SME_SET_CHANNEL_MAX_TX_POWER(*regInfo2, + pMac->scan.defaultPowerTable[i].power); + found = true; + break; + } + } + if (!found) + status = QDF_STATUS_E_FAILURE; + + sme_release_global_lock(&pMac->sme); + return status; +} + +#ifdef FEATURE_WLAN_AUTO_SHUTDOWN +/* --------------------------------------------------------------------------- + \fn sme_auto_shutdown_cb + \brief Used to plug in callback function for receiving auto shutdown evt + \param hHal + \param pCallbackfn : callback function pointer should be plugged in + \- return QDF_STATUS + -------------------------------------------------------------------------*/ +QDF_STATUS sme_set_auto_shutdown_cb(tHalHandle hHal, void (*pCallbackfn)(void) + ) { + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Plug in Auto shutdown event callback", __func__); + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_STATUS_SUCCESS == status) { + if (NULL != pCallbackfn) { + pMac->sme.pAutoShutdownNotificationCb = pCallbackfn; + } + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +/* --------------------------------------------------------------------------- + \fn sme_set_auto_shutdown_timer + \API to set auto shutdown timer value in FW. + \param hHal - The handle returned by mac_open + \param timer_val - The auto shutdown timer value to be set + \- return Configuration message posting status, SUCCESS or Fail + -------------------------------------------------------------------------*/ +QDF_STATUS sme_set_auto_shutdown_timer(tHalHandle hHal, uint32_t timer_val) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + tSirAutoShutdownCmdParams *auto_sh_cmd; + cds_msg_t cds_message; + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_STATUS_SUCCESS == status) { + auto_sh_cmd = (tSirAutoShutdownCmdParams *) + qdf_mem_malloc(sizeof(tSirAutoShutdownCmdParams)); + if (auto_sh_cmd == NULL) { + QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR, + "%s Request Buffer Alloc Fail", __func__); + sme_release_global_lock(&pMac->sme); + return QDF_STATUS_E_NOMEM; + } + + auto_sh_cmd->timer_val = timer_val; + + /* serialize the req through MC thread */ + cds_message.bodyptr = auto_sh_cmd; + cds_message.type = WMA_SET_AUTO_SHUTDOWN_TIMER_REQ; + qdf_status = cds_mq_post_message(CDS_MQ_ID_WMA, &cds_message); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Post Auto shutdown MSG fail", __func__); + qdf_mem_free(auto_sh_cmd); + sme_release_global_lock(&pMac->sme); + return QDF_STATUS_E_FAILURE; + } + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO, + "%s: Posted Auto shutdown MSG", __func__); + sme_release_global_lock(&pMac->sme); + } + + return status; +} +#endif + +#ifdef FEATURE_WLAN_CH_AVOID +/* --------------------------------------------------------------------------- + \fn sme_add_ch_avoid_callback + \brief Used to plug in callback function + Which notify channel may not be used with SAP or P2PGO mode. + Notification come from FW. + \param hHal + \param pCallbackfn : callback function pointer should be plugged in + \- return QDF_STATUS + -------------------------------------------------------------------------*/ +QDF_STATUS sme_add_ch_avoid_callback + (tHalHandle hHal, void (*pCallbackfn)(void *pAdapter, void *indParam) + ) { + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Plug in CH AVOID CB", __func__); + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_STATUS_SUCCESS == status) { + if (NULL != pCallbackfn) { + pMac->sme.pChAvoidNotificationCb = pCallbackfn; + } + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +/* --------------------------------------------------------------------------- + \fn sme_ch_avoid_update_req + \API to request channel avoidance update from FW. + \param hHal - The handle returned by mac_open + \param update_type - The udpate_type parameter of this request call + \- return Configuration message posting status, SUCCESS or Fail + -------------------------------------------------------------------------*/ +QDF_STATUS sme_ch_avoid_update_req(tHalHandle hHal) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + tSirChAvoidUpdateReq *cauReq; + cds_msg_t cds_message; + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_STATUS_SUCCESS == status) { + cauReq = (tSirChAvoidUpdateReq *) + qdf_mem_malloc(sizeof(tSirChAvoidUpdateReq)); + if (NULL == cauReq) { + QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR, + "%s Request Buffer Alloc Fail", __func__); + sme_release_global_lock(&pMac->sme); + return QDF_STATUS_E_NOMEM; + } + + cauReq->reserved_param = 0; + + /* serialize the req through MC thread */ + cds_message.bodyptr = cauReq; + cds_message.type = WMA_CH_AVOID_UPDATE_REQ; + qdf_status = cds_mq_post_message(CDS_MQ_ID_WMA, &cds_message); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Post Ch Avoid Update MSG fail", + __func__); + qdf_mem_free(cauReq); + sme_release_global_lock(&pMac->sme); + return QDF_STATUS_E_FAILURE; + } + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO, + "%s: Posted Ch Avoid Update MSG", __func__); + sme_release_global_lock(&pMac->sme); + } + + return status; +} +#endif /* FEATURE_WLAN_CH_AVOID */ + +/** + * sme_set_miracast() - Function to set miracast value to UMAC + * @hal: Handle returned by macOpen + * @filter_type: 0-Disabled, 1-Source, 2-sink + * + * This function passes down the value of miracast set by + * framework to UMAC + * + * Return: Configuration message posting status, SUCCESS or Fail + * + */ +QDF_STATUS sme_set_miracast(tHalHandle hal, uint8_t filter_type) +{ + cds_msg_t msg; + uint32_t *val; + tpAniSirGlobal mac_ptr = PMAC_STRUCT(hal); + + val = qdf_mem_malloc(sizeof(*val)); + if (NULL == val || NULL == mac_ptr) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid pointer", __func__); + return QDF_STATUS_E_NOMEM; + } + + *val = filter_type; + + msg.type = SIR_HAL_SET_MIRACAST; + msg.reserved = 0; + msg.bodyptr = val; + + if (!QDF_IS_STATUS_SUCCESS( + cds_mq_post_message(QDF_MODULE_ID_WMA, &msg))) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Not able to post WDA_SET_MAS_ENABLE_DISABLE to WMA!", + __func__); + qdf_mem_free(val); + return QDF_STATUS_E_FAILURE; + } + + mac_ptr->sme.miracast_value = filter_type; + return QDF_STATUS_SUCCESS; +} + +/** + * sme_set_mas() - Function to set MAS value to UMAC + * @val: 1-Enable, 0-Disable + * + * This function passes down the value of MAS to the UMAC. A + * value of 1 will enable MAS and a value of 0 will disable MAS + * + * Return: Configuration message posting status, SUCCESS or Fail + * + */ +QDF_STATUS sme_set_mas(uint32_t val) +{ + cds_msg_t msg; + uint32_t *ptr_val; + + ptr_val = qdf_mem_malloc(sizeof(*ptr_val)); + if (NULL == ptr_val) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: could not allocate ptr_val", __func__); + return QDF_STATUS_E_NOMEM; + } + + *ptr_val = val; + + msg.type = SIR_HAL_SET_MAS; + msg.reserved = 0; + msg.bodyptr = ptr_val; + + if (!QDF_IS_STATUS_SUCCESS( + cds_mq_post_message(QDF_MODULE_ID_WMA, &msg))) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Not able to post WDA_SET_MAS_ENABLE_DISABLE to WMA!", + __func__); + qdf_mem_free(ptr_val); + return QDF_STATUS_E_FAILURE; + } + return QDF_STATUS_SUCCESS; +} + +/** + * sme_roam_channel_change_req() - Channel change to new target channel + * @hHal: handle returned by mac_open + * @bssid: mac address of BSS + * @ch_params: target channel information + * @profile: CSR profile + * + * API to Indicate Channel change to new target channel + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_roam_channel_change_req(tHalHandle hHal, + struct qdf_mac_addr bssid, + struct ch_params_s *ch_params, + tCsrRoamProfile *profile) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + + status = csr_roam_channel_change_req(pMac, bssid, ch_params, + profile); + sme_release_global_lock(&pMac->sme); + } + return status; +} + +/* ------------------------------------------------------------------------- + \fn sme_process_channel_change_resp + \brief API to Indicate Channel change response message to SAP. + \return QDF_STATUS + ---------------------------------------------------------------------------*/ +QDF_STATUS sme_process_channel_change_resp(tpAniSirGlobal pMac, + uint16_t msg_type, void *pMsgBuf) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tCsrRoamInfo proam_info = { 0 }; + eCsrRoamResult roamResult; + tpSwitchChannelParams pChnlParams = (tpSwitchChannelParams) pMsgBuf; + uint32_t SessionId = pChnlParams->peSessionId; + + proam_info.channelChangeRespEvent = + (tSirChanChangeResponse *) + qdf_mem_malloc(sizeof(tSirChanChangeResponse)); + if (NULL == proam_info.channelChangeRespEvent) { + status = QDF_STATUS_E_NOMEM; + sms_log(pMac, LOGE, + "Channel Change Event Allocation Failed: %d\n", status); + return status; + } + if (msg_type == eWNI_SME_CHANNEL_CHANGE_RSP) { + proam_info.channelChangeRespEvent->sessionId = SessionId; + proam_info.channelChangeRespEvent->newChannelNumber = + pChnlParams->channelNumber; + proam_info.channelChangeRespEvent->secondaryChannelOffset = + pChnlParams->ch_width; + + if (pChnlParams->status == QDF_STATUS_SUCCESS) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO_MED, + "sapdfs: Received success eWNI_SME_CHANNEL_CHANGE_RSP for sessionId[%d]", + SessionId); + proam_info.channelChangeRespEvent->channelChangeStatus = + 1; + roamResult = eCSR_ROAM_RESULT_CHANNEL_CHANGE_SUCCESS; + } else { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO_MED, + "sapdfs: Received failure eWNI_SME_CHANNEL_CHANGE_RSP for sessionId[%d]", + SessionId); + proam_info.channelChangeRespEvent->channelChangeStatus = + 0; + roamResult = eCSR_ROAM_RESULT_CHANNEL_CHANGE_FAILURE; + } + + csr_roam_call_callback(pMac, SessionId, &proam_info, 0, + eCSR_ROAM_SET_CHANNEL_RSP, roamResult); + + } else { + status = QDF_STATUS_E_FAILURE; + sms_log(pMac, LOGE, "Invalid Channel Change Resp Message: %d\n", + status); + } + qdf_mem_free(proam_info.channelChangeRespEvent); + + return status; +} + +/* ------------------------------------------------------------------------- + \fn sme_roam_start_beacon_req + \brief API to Indicate LIM to start Beacon Tx + \after SAP CAC Wait is completed. + \param hHal - The handle returned by mac_open + \param sessionId - session ID + \param dfsCacWaitStatus - CAC WAIT status flag + \return QDF_STATUS + ---------------------------------------------------------------------------*/ +QDF_STATUS sme_roam_start_beacon_req(tHalHandle hHal, struct qdf_mac_addr bssid, + uint8_t dfsCacWaitStatus) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + status = sme_acquire_global_lock(&pMac->sme); + + if (QDF_IS_STATUS_SUCCESS(status)) { + status = csr_roam_start_beacon_req(pMac, bssid, dfsCacWaitStatus); + sme_release_global_lock(&pMac->sme); + } + return status; +} + +/** + * sme_roam_csa_ie_request() - request CSA IE transmission from PE + * @hHal: handle returned by mac_open + * @bssid: SAP bssid + * @targetChannel: target channel information + * @csaIeReqd: CSA IE Request + * @ch_params: channel information + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_roam_csa_ie_request(tHalHandle hHal, struct qdf_mac_addr bssid, + uint8_t targetChannel, uint8_t csaIeReqd, + struct ch_params_s *ch_params) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + status = csr_roam_send_chan_sw_ie_request(pMac, bssid, + targetChannel, csaIeReqd, ch_params); + sme_release_global_lock(&pMac->sme); + } + return status; +} + +/* --------------------------------------------------------------------------- + \fn sme_init_thermal_info + \brief SME API to initialize the thermal mitigation parameters + \param hHal + \param thermalParam : thermal mitigation parameters + \- return QDF_STATUS + -------------------------------------------------------------------------*/ +QDF_STATUS sme_init_thermal_info(tHalHandle hHal, tSmeThermalParams thermalParam) +{ + t_thermal_mgmt *pWmaParam; + cds_msg_t msg; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + pWmaParam = (t_thermal_mgmt *) qdf_mem_malloc(sizeof(t_thermal_mgmt)); + if (NULL == pWmaParam) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: could not allocate tThermalMgmt", __func__); + return QDF_STATUS_E_NOMEM; + } + + pWmaParam->thermalMgmtEnabled = thermalParam.smeThermalMgmtEnabled; + pWmaParam->throttlePeriod = thermalParam.smeThrottlePeriod; + + pWmaParam->throttle_duty_cycle_tbl[0] = + thermalParam.sme_throttle_duty_cycle_tbl[0]; + pWmaParam->throttle_duty_cycle_tbl[1] = + thermalParam.sme_throttle_duty_cycle_tbl[1]; + pWmaParam->throttle_duty_cycle_tbl[2] = + thermalParam.sme_throttle_duty_cycle_tbl[2]; + pWmaParam->throttle_duty_cycle_tbl[3] = + thermalParam.sme_throttle_duty_cycle_tbl[3]; + + pWmaParam->thermalLevels[0].minTempThreshold = + thermalParam.smeThermalLevels[0].smeMinTempThreshold; + pWmaParam->thermalLevels[0].maxTempThreshold = + thermalParam.smeThermalLevels[0].smeMaxTempThreshold; + pWmaParam->thermalLevels[1].minTempThreshold = + thermalParam.smeThermalLevels[1].smeMinTempThreshold; + pWmaParam->thermalLevels[1].maxTempThreshold = + thermalParam.smeThermalLevels[1].smeMaxTempThreshold; + pWmaParam->thermalLevels[2].minTempThreshold = + thermalParam.smeThermalLevels[2].smeMinTempThreshold; + pWmaParam->thermalLevels[2].maxTempThreshold = + thermalParam.smeThermalLevels[2].smeMaxTempThreshold; + pWmaParam->thermalLevels[3].minTempThreshold = + thermalParam.smeThermalLevels[3].smeMinTempThreshold; + pWmaParam->thermalLevels[3].maxTempThreshold = + thermalParam.smeThermalLevels[3].smeMaxTempThreshold; + + if (QDF_STATUS_SUCCESS == sme_acquire_global_lock(&pMac->sme)) { + msg.type = WMA_INIT_THERMAL_INFO_CMD; + msg.bodyptr = pWmaParam; + + if (!QDF_IS_STATUS_SUCCESS + (cds_mq_post_message(QDF_MODULE_ID_WMA, &msg))) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Not able to post WMA_SET_THERMAL_INFO_CMD to WMA!", + __func__); + qdf_mem_free(pWmaParam); + sme_release_global_lock(&pMac->sme); + return QDF_STATUS_E_FAILURE; + } + sme_release_global_lock(&pMac->sme); + return QDF_STATUS_SUCCESS; + } + qdf_mem_free(pWmaParam); + return QDF_STATUS_E_FAILURE; +} + +/** + * sme_add_set_thermal_level_callback() - Plug in set thermal level callback + * @hal: Handle returned by macOpen + * @callback: sme_set_thermal_level_callback + * + * Plug in set thermal level callback + * + * Return: none + */ +void sme_add_set_thermal_level_callback(tHalHandle hal, + sme_set_thermal_level_callback callback) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hal); + + pMac->sme.set_thermal_level_cb = callback; +} + +/** + * sme_set_thermal_level() - SME API to set the thermal mitigation level + * @hal: Handler to HAL + * @level: Thermal mitigation level + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_set_thermal_level(tHalHandle hal, uint8_t level) +{ + cds_msg_t msg; + tpAniSirGlobal pMac = PMAC_STRUCT(hal); + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + + if (QDF_STATUS_SUCCESS == sme_acquire_global_lock(&pMac->sme)) { + qdf_mem_set(&msg, sizeof(msg), 0); + msg.type = WMA_SET_THERMAL_LEVEL; + msg.bodyval = level; + + qdf_status = cds_mq_post_message(QDF_MODULE_ID_WMA, &msg); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Not able to post WMA_SET_THERMAL_LEVEL to WMA!", + __func__); + sme_release_global_lock(&pMac->sme); + return QDF_STATUS_E_FAILURE; + } + sme_release_global_lock(&pMac->sme); + return QDF_STATUS_SUCCESS; + } + return QDF_STATUS_E_FAILURE; +} + +/* --------------------------------------------------------------------------- + \fn sme_txpower_limit + \brief SME API to set txpower limits + \param hHal + \param psmetx : power limits for 2g/5g + \- return QDF_STATUS + -------------------------------------------------------------------------*/ +QDF_STATUS sme_txpower_limit(tHalHandle hHal, tSirTxPowerLimit *psmetx) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + cds_msg_t cds_message; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + tSirTxPowerLimit *tx_power_limit; + + tx_power_limit = qdf_mem_malloc(sizeof(*tx_power_limit)); + if (!tx_power_limit) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Memory allocation for TxPowerLimit failed!", + __func__); + return QDF_STATUS_E_FAILURE; + } + + *tx_power_limit = *psmetx; + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + cds_message.type = WMA_TX_POWER_LIMIT; + cds_message.reserved = 0; + cds_message.bodyptr = tx_power_limit; + + qdf_status = cds_mq_post_message(CDS_MQ_ID_WMA, &cds_message); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: not able to post WMA_TX_POWER_LIMIT", + __func__); + status = QDF_STATUS_E_FAILURE; + qdf_mem_free(tx_power_limit); + } + sme_release_global_lock(&pMac->sme); + } + return status; +} + +QDF_STATUS sme_update_connect_debug(tHalHandle hHal, uint32_t set_value) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + pMac->fEnableDebugLog = set_value; + return status; +} + +/* --------------------------------------------------------------------------- + \fn sme_ap_disable_intra_bss_fwd + + \brief + SME will send message to WMA to set Intra BSS in txrx + + \param + + hHal - The handle returned by mac_open + + sessionId - session id ( vdev id) + + disablefwd - bool value that indicate disable intrabss fwd disable + + \return QDF_STATUS + --------------------------------------------------------------------------- */ +QDF_STATUS sme_ap_disable_intra_bss_fwd(tHalHandle hHal, uint8_t sessionId, + bool disablefwd) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + int status = QDF_STATUS_SUCCESS; + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + cds_msg_t cds_message; + tpDisableIntraBssFwd pSapDisableIntraFwd = NULL; + + /* Prepare the request to send to SME. */ + pSapDisableIntraFwd = qdf_mem_malloc(sizeof(tDisableIntraBssFwd)); + if (NULL == pSapDisableIntraFwd) { + sms_log(pMac, LOGP, "Memory Allocation Failure!!! %s", __func__); + return QDF_STATUS_E_NOMEM; + } + + pSapDisableIntraFwd->sessionId = sessionId; + pSapDisableIntraFwd->disableintrabssfwd = disablefwd; + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + /* serialize the req through MC thread */ + cds_message.bodyptr = pSapDisableIntraFwd; + cds_message.type = WMA_SET_SAP_INTRABSS_DIS; + qdf_status = cds_mq_post_message(CDS_MQ_ID_WMA, &cds_message); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + status = QDF_STATUS_E_FAILURE; + qdf_mem_free(pSapDisableIntraFwd); + } + sme_release_global_lock(&pMac->sme); + } + return status; +} + +#ifdef WLAN_FEATURE_STATS_EXT + +/****************************************************************************** + \fn sme_stats_ext_register_callback + + \brief + a function called to register the callback that send vendor event for stats + ext + + \param callback - callback to be registered +******************************************************************************/ +void sme_stats_ext_register_callback(tHalHandle hHal, StatsExtCallback callback) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + pMac->sme.StatsExtCallback = callback; +} + +/** + * sme_stats_ext_deregister_callback() - De-register ext stats callback + * @h_hal: Hal Handle + * + * This function is called to de initialize the HDD NAN feature. Currently + * the only operation required is to de-register a callback with SME. + * + * Return: None + */ +void sme_stats_ext_deregister_callback(tHalHandle h_hal) +{ + tpAniSirGlobal pmac; + + if (!h_hal) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("hHal is not valid")); + return; + } + + pmac = PMAC_STRUCT(h_hal); + pmac->sme.StatsExtCallback = NULL; +} + + +/****************************************************************************** + \fn sme_stats_ext_request + + \brief + a function called when HDD receives STATS EXT vendor command from userspace + + \param sessionID - vdevID for the stats ext request + + \param input - Stats Ext Request structure ptr + + \return QDF_STATUS +******************************************************************************/ +QDF_STATUS sme_stats_ext_request(uint8_t session_id, tpStatsExtRequestReq input) +{ + cds_msg_t msg; + tpStatsExtRequest data; + size_t data_len; + + data_len = sizeof(tStatsExtRequest) + input->request_data_len; + data = qdf_mem_malloc(data_len); + + if (data == NULL) { + return QDF_STATUS_E_NOMEM; + } + data->vdev_id = session_id; + data->request_data_len = input->request_data_len; + if (input->request_data_len) { + qdf_mem_copy(data->request_data, + input->request_data, input->request_data_len); + } + + msg.type = WMA_STATS_EXT_REQUEST; + msg.reserved = 0; + msg.bodyptr = data; + + if (QDF_STATUS_SUCCESS != cds_mq_post_message(QDF_MODULE_ID_WMA, &msg)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Not able to post WMA_STATS_EXT_REQUEST message to WMA", + __func__); + qdf_mem_free(data); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/****************************************************************************** + \fn sme_stats_ext_event + + \brief + a callback function called when SME received eWNI_SME_STATS_EXT_EVENT + response from WMA + + \param hHal - HAL handle for device + \param pMsg - Message body passed from WMA; includes NAN header + \return QDF_STATUS +******************************************************************************/ +QDF_STATUS sme_stats_ext_event(tHalHandle hHal, void *pMsg) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + QDF_STATUS status = QDF_STATUS_SUCCESS; + + if (NULL == pMsg) { + sms_log(pMac, LOGE, "in %s msg ptr is NULL", __func__); + status = QDF_STATUS_E_FAILURE; + } else { + sms_log(pMac, LOG2, "SME: entering %s", __func__); + + if (pMac->sme.StatsExtCallback) { + pMac->sme.StatsExtCallback(pMac->hHdd, + (tpStatsExtEvent) pMsg); + } + } + + return status; +} + +#endif + +/* --------------------------------------------------------------------------- + \fn sme_update_dfs_scan_mode + \brief Update DFS roam scan mode + This function is called through dynamic setConfig callback function + to configure allowDFSChannelRoam. + \param hHal - HAL handle for device + \param sessionId - Session Identifier + \param allowDFSChannelRoam - DFS roaming scan mode 0 (disable), + 1 (passive), 2 (active) + \return QDF_STATUS_SUCCESS - SME update DFS roaming scan config + successfully. + Other status means SME failed to update DFS roaming scan config. + \sa + -------------------------------------------------------------------------*/ +QDF_STATUS sme_update_dfs_scan_mode(tHalHandle hHal, uint8_t sessionId, + uint8_t allowDFSChannelRoam) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + QDF_STATUS status = QDF_STATUS_SUCCESS; + + if (sessionId >= CSR_ROAM_SESSION_MAX) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Invalid sme session id: %d"), sessionId); + return QDF_STATUS_E_INVAL; + } + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "LFR runtime successfully set AllowDFSChannelRoam Mode to " + "%d - old value is %d - roam state is %s", + allowDFSChannelRoam, + pMac->roam.configParam.allowDFSChannelRoam, + mac_trace_get_neighbour_roam_state(pMac->roam. + neighborRoamInfo + [sessionId]. + neighborRoamState)); + pMac->roam.configParam.allowDFSChannelRoam = + allowDFSChannelRoam; + sme_release_global_lock(&pMac->sme); + } + if (pMac->roam.configParam.isRoamOffloadScanEnabled) { + csr_roam_offload_scan(pMac, sessionId, + ROAM_SCAN_OFFLOAD_UPDATE_CFG, + REASON_ROAM_DFS_SCAN_MODE_CHANGED); + } + + return status; +} + +/*-------------------------------------------------------------------------- + \brief sme_get_dfs_scan_mode() - get DFS roam scan mode + This is a synchronous call + \param hHal - The handle returned by mac_open. + \return DFS roaming scan mode 0 (disable), 1 (passive), 2 (active) + \sa + --------------------------------------------------------------------------*/ +uint8_t sme_get_dfs_scan_mode(tHalHandle hHal) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + return pMac->roam.configParam.allowDFSChannelRoam; +} + +/*---------------------------------------------------------------------------- + \fn sme_modify_add_ie + \brief This function sends msg to updates the additional IE buffers in PE + \param hHal - global structure + \param pModifyIE - pointer to tModifyIE structure + \param updateType - type of buffer + \- return Success or failure + -----------------------------------------------------------------------------*/ +QDF_STATUS sme_modify_add_ie(tHalHandle hHal, + tSirModifyIE *pModifyIE, eUpdateIEsType updateType) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + status = sme_acquire_global_lock(&pMac->sme); + + if (QDF_IS_STATUS_SUCCESS(status)) { + status = csr_roam_modify_add_ies(pMac, pModifyIE, updateType); + sme_release_global_lock(&pMac->sme); + } + return status; +} + +/*---------------------------------------------------------------------------- + \fn sme_update_add_ie + \brief This function sends msg to updates the additional IE buffers in PE + \param hHal - global structure + \param pUpdateIE - pointer to structure tUpdateIE + \param updateType - type of buffer + \- return Success or failure + -----------------------------------------------------------------------------*/ +QDF_STATUS sme_update_add_ie(tHalHandle hHal, + tSirUpdateIE *pUpdateIE, eUpdateIEsType updateType) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + status = sme_acquire_global_lock(&pMac->sme); + + if (QDF_IS_STATUS_SUCCESS(status)) { + status = csr_roam_update_add_ies(pMac, pUpdateIE, updateType); + sme_release_global_lock(&pMac->sme); + } + return status; +} + +/** + * sme_update_dsc_pto_up_mapping() + * @hHal: HAL context + * @dscpmapping: pointer to DSCP mapping structure + * @sessionId: SME session id + * + * This routine is called to update dscp mapping + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_update_dsc_pto_up_mapping(tHalHandle hHal, + sme_QosWmmUpType *dscpmapping, + uint8_t sessionId) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + QDF_STATUS status = QDF_STATUS_SUCCESS; + uint8_t i, j, peSessionId; + tCsrRoamSession *pCsrSession = NULL; + tpPESession pSession = NULL; + + status = sme_acquire_global_lock(&pMac->sme); + if (!QDF_IS_STATUS_SUCCESS(status)) + return status; + pCsrSession = CSR_GET_SESSION(pMac, sessionId); + if (pCsrSession == NULL) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Session lookup fails for CSR session")); + sme_release_global_lock(&pMac->sme); + return QDF_STATUS_E_FAILURE; + } + if (!CSR_IS_SESSION_VALID(pMac, sessionId)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Invalid session Id %u"), sessionId); + sme_release_global_lock(&pMac->sme); + return QDF_STATUS_E_FAILURE; + } + + pSession = pe_find_session_by_bssid(pMac, + pCsrSession->connectedProfile.bssid.bytes, + &peSessionId); + + if (pSession == NULL) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL(" Session lookup fails for BSSID")); + sme_release_global_lock(&pMac->sme); + return QDF_STATUS_E_FAILURE; + } + + if (!pSession->QosMapSet.present) { + hdd_notice("QOS Mapping IE not present"); + sme_release_global_lock(&pMac->sme); + return QDF_STATUS_E_FAILURE; + } + for (i = 0; i < SME_QOS_WMM_UP_MAX; i++) { + for (j = pSession->QosMapSet.dscp_range[i][0]; + j <= pSession->QosMapSet.dscp_range[i][1]; + j++) { + if ((pSession->QosMapSet.dscp_range[i][0] == 255) + && (pSession->QosMapSet.dscp_range[i][1] == + 255)) { + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_ERROR, + FL("User Priority %d isn't used"), i); + break; + } else { + dscpmapping[j] = i; + } + } + } + for (i = 0; i < pSession->QosMapSet.num_dscp_exceptions; i++) + if (pSession->QosMapSet.dscp_exceptions[i][0] != 255) + dscpmapping[pSession->QosMapSet.dscp_exceptions[i][0]] = + pSession->QosMapSet.dscp_exceptions[i][1]; + + sme_release_global_lock(&pMac->sme); + return status; +} + +/* --------------------------------------------------------------------------- + \fn sme_abort_roam_scan + \brief API to abort current roam scan cycle by roam scan offload module. + \param hHal - The handle returned by mac_open. + \param sessionId - Session Identifier + \return QDF_STATUS + ---------------------------------------------------------------------------*/ + +QDF_STATUS sme_abort_roam_scan(tHalHandle hHal, uint8_t sessionId) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + sms_log(pMac, LOGW, "entering function %s", __func__); + if (pMac->roam.configParam.isRoamOffloadScanEnabled) { + /* acquire the lock for the sme object */ + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + csr_roam_offload_scan(pMac, sessionId, + ROAM_SCAN_OFFLOAD_ABORT_SCAN, + REASON_ROAM_ABORT_ROAM_SCAN); + /* release the lock for the sme object */ + sme_release_global_lock(&pMac->sme); + } + } + + return status; +} + +#ifdef FEATURE_WLAN_EXTSCAN +/** + * sme_get_valid_channels_by_band() - to fetch valid channels filtered by band + * @hHal: HAL context + * @wifiBand: RF band information + * @aValidChannels: output array to store channel info + * @pNumChannels: output number of channels + * + * SME API to fetch all valid channels filtered by band + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_get_valid_channels_by_band(tHalHandle hHal, + uint8_t wifiBand, + uint32_t *aValidChannels, + uint8_t *pNumChannels) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + uint8_t chanList[WNI_CFG_VALID_CHANNEL_LIST_LEN] = { 0 }; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + uint8_t numChannels = 0; + uint8_t i = 0; + uint32_t totValidChannels = WNI_CFG_VALID_CHANNEL_LIST_LEN; + + if (!aValidChannels || !pNumChannels) { + sms_log(pMac, QDF_TRACE_LEVEL_ERROR, + FL("Output channel list/NumChannels is NULL")); + return QDF_STATUS_E_INVAL; + } + + if ((wifiBand < WIFI_BAND_UNSPECIFIED) || (wifiBand >= WIFI_BAND_MAX)) { + sms_log(pMac, QDF_TRACE_LEVEL_ERROR, + FL("Invalid wifiBand (%d)"), wifiBand); + return QDF_STATUS_E_INVAL; + } + + status = sme_get_cfg_valid_channels(hHal, &chanList[0], + &totValidChannels); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, QDF_TRACE_LEVEL_ERROR, + FL("Fail to get valid channel list (err=%d)"), status); + return status; + } + + switch (wifiBand) { + case WIFI_BAND_UNSPECIFIED: + sms_log(pMac, QDF_TRACE_LEVEL_INFO, + FL("Unspec Band, return all (%d) valid channels"), + totValidChannels); + numChannels = totValidChannels; + for (i = 0; i < totValidChannels; i++) { + aValidChannels[i] = cds_chan_to_freq(chanList[i]); + } + break; + + case WIFI_BAND_BG: + sms_log(pMac, QDF_TRACE_LEVEL_INFO, + FL("WIFI_BAND_BG (2.4 GHz)")); + for (i = 0; i < totValidChannels; i++) { + if (CDS_IS_CHANNEL_24GHZ(chanList[i])) { + aValidChannels[numChannels++] = + cds_chan_to_freq(chanList[i]); + } + } + break; + + case WIFI_BAND_A: + sms_log(pMac, QDF_TRACE_LEVEL_INFO, + FL("WIFI_BAND_A (5 GHz without DFS)")); + for (i = 0; i < totValidChannels; i++) { + if (CDS_IS_CHANNEL_5GHZ(chanList[i]) && + !CDS_IS_DFS_CH(chanList[i])) { + aValidChannels[numChannels++] = + cds_chan_to_freq(chanList[i]); + } + } + break; + + case WIFI_BAND_ABG: + sms_log(pMac, QDF_TRACE_LEVEL_INFO, + FL("WIFI_BAND_ABG (2.4 GHz + 5 GHz; no DFS)")); + for (i = 0; i < totValidChannels; i++) { + if ((CDS_IS_CHANNEL_24GHZ(chanList[i]) || + CDS_IS_CHANNEL_5GHZ(chanList[i])) && + !CDS_IS_DFS_CH(chanList[i])) { + aValidChannels[numChannels++] = + cds_chan_to_freq(chanList[i]); + } + } + break; + + case WIFI_BAND_A_DFS_ONLY: + sms_log(pMac, QDF_TRACE_LEVEL_INFO, + FL("WIFI_BAND_A_DFS (5 GHz DFS only)")); + for (i = 0; i < totValidChannels; i++) { + if (CDS_IS_CHANNEL_5GHZ(chanList[i]) && + CDS_IS_DFS_CH(chanList[i])) { + aValidChannels[numChannels++] = + cds_chan_to_freq(chanList[i]); + } + } + break; + + case WIFI_BAND_A_WITH_DFS: + sms_log(pMac, QDF_TRACE_LEVEL_INFO, + FL("WIFI_BAND_A_WITH_DFS (5 GHz with DFS)")); + for (i = 0; i < totValidChannels; i++) { + if (CDS_IS_CHANNEL_5GHZ(chanList[i])) { + aValidChannels[numChannels++] = + cds_chan_to_freq(chanList[i]); + } + } + break; + + case WIFI_BAND_ABG_WITH_DFS: + sms_log(pMac, QDF_TRACE_LEVEL_INFO, + FL("WIFI_BAND_ABG_WITH_DFS (2.4 GHz+5 GHz with DFS)")); + for (i = 0; i < totValidChannels; i++) { + if (CDS_IS_CHANNEL_24GHZ(chanList[i]) || + CDS_IS_CHANNEL_5GHZ(chanList[i])) { + aValidChannels[numChannels++] = + cds_chan_to_freq(chanList[i]); + } + } + break; + + default: + sms_log(pMac, QDF_TRACE_LEVEL_ERROR, + FL("Unknown wifiBand (%d))"), wifiBand); + return QDF_STATUS_E_INVAL; + break; + } + *pNumChannels = numChannels; + + return status; +} + +/* --------------------------------------------------------------------------- + \fn sme_ext_scan_get_capabilities + \brief SME API to fetch extscan capabilities + \param hHal + \param pReq: extscan capabilities structure + \- return QDF_STATUS + -------------------------------------------------------------------------*/ +QDF_STATUS sme_ext_scan_get_capabilities(tHalHandle hHal, + tSirGetExtScanCapabilitiesReqParams * + pReq) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + cds_msg_t cds_message; + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + /* Serialize the req through MC thread */ + cds_message.bodyptr = pReq; + cds_message.type = WMA_EXTSCAN_GET_CAPABILITIES_REQ; + MTRACE(qdf_trace(QDF_MODULE_ID_SME, TRACE_CODE_SME_TX_WMA_MSG, + NO_SESSION, cds_message.type)); + qdf_status = cds_mq_post_message(CDS_MQ_ID_WMA, &cds_message); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) + status = QDF_STATUS_E_FAILURE; + + sme_release_global_lock(&pMac->sme); + } + return status; +} + +/* --------------------------------------------------------------------------- + \fn sme_ext_scan_start + \brief SME API to issue extscan start + \param hHal + \param pStartCmd: extscan start structure + \- return QDF_STATUS + -------------------------------------------------------------------------*/ +QDF_STATUS sme_ext_scan_start(tHalHandle hHal, + tSirWifiScanCmdReqParams *pStartCmd) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + cds_msg_t cds_message; + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + /* Serialize the req through MC thread */ + cds_message.bodyptr = pStartCmd; + cds_message.type = WMA_EXTSCAN_START_REQ; + MTRACE(qdf_trace(QDF_MODULE_ID_SME, TRACE_CODE_SME_TX_WMA_MSG, + NO_SESSION, cds_message.type)); + qdf_status = cds_mq_post_message(CDS_MQ_ID_WMA, &cds_message); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) + status = QDF_STATUS_E_FAILURE; + + sme_release_global_lock(&pMac->sme); + } + return status; +} + +/* --------------------------------------------------------------------------- + \fn sme_ext_scan_stop + \brief SME API to issue extscan stop + \param hHal + \param pStopReq: extscan stop structure + \- return QDF_STATUS + -------------------------------------------------------------------------*/ +QDF_STATUS sme_ext_scan_stop(tHalHandle hHal, tSirExtScanStopReqParams *pStopReq) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + cds_msg_t cds_message; + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + /* Serialize the req through MC thread */ + cds_message.bodyptr = pStopReq; + cds_message.type = WMA_EXTSCAN_STOP_REQ; + MTRACE(qdf_trace(QDF_MODULE_ID_SME, TRACE_CODE_SME_TX_WMA_MSG, + NO_SESSION, cds_message.type)); + qdf_status = cds_mq_post_message(CDS_MQ_ID_WMA, &cds_message); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) + status = QDF_STATUS_E_FAILURE; + sme_release_global_lock(&pMac->sme); + } + return status; +} + +/* --------------------------------------------------------------------------- + \fn sme_set_bss_hotlist + \brief SME API to set BSSID hotlist + \param hHal + \param pSetHotListReq: extscan set hotlist structure + \- return QDF_STATUS + -------------------------------------------------------------------------*/ +QDF_STATUS sme_set_bss_hotlist(tHalHandle hHal, + tSirExtScanSetBssidHotListReqParams * + pSetHotListReq) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + cds_msg_t cds_message; + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + /* Serialize the req through MC thread */ + cds_message.bodyptr = pSetHotListReq; + cds_message.type = WMA_EXTSCAN_SET_BSSID_HOTLIST_REQ; + MTRACE(qdf_trace(QDF_MODULE_ID_SME, TRACE_CODE_SME_TX_WMA_MSG, + NO_SESSION, cds_message.type)); + qdf_status = cds_mq_post_message(CDS_MQ_ID_WMA, &cds_message); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) + status = QDF_STATUS_E_FAILURE; + + sme_release_global_lock(&pMac->sme); + } + return status; +} + +/* --------------------------------------------------------------------------- + \fn sme_reset_bss_hotlist + \brief SME API to reset BSSID hotlist + \param hHal + \param pSetHotListReq: extscan set hotlist structure + \- return QDF_STATUS + -------------------------------------------------------------------------*/ +QDF_STATUS sme_reset_bss_hotlist(tHalHandle hHal, + tSirExtScanResetBssidHotlistReqParams * + pResetReq) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + cds_msg_t cds_message; + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + /* Serialize the req through MC thread */ + cds_message.bodyptr = pResetReq; + cds_message.type = WMA_EXTSCAN_RESET_BSSID_HOTLIST_REQ; + MTRACE(qdf_trace(QDF_MODULE_ID_SME, TRACE_CODE_SME_TX_WMA_MSG, + NO_SESSION, cds_message.type)); + qdf_status = cds_mq_post_message(CDS_MQ_ID_WMA, &cds_message); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) + status = QDF_STATUS_E_FAILURE; + + sme_release_global_lock(&pMac->sme); + } + return status; +} + +/** + * sme_send_wisa_params(): Pass WISA mode to WMA + * @hal: HAL context + * @wisa_params: pointer to WISA params struct + * @sessionId: SME session id + * + * Pass WISA params to WMA + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_set_wisa_params(tHalHandle hal, + struct sir_wisa_params *wisa_params) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpAniSirGlobal mac = PMAC_STRUCT(hal); + cds_msg_t cds_message; + struct sir_wisa_params *cds_msg_wisa_params; + + cds_msg_wisa_params = qdf_mem_malloc(sizeof(struct sir_wisa_params)); + if (!cds_msg_wisa_params) + return QDF_STATUS_E_NOMEM; + + *cds_msg_wisa_params = *wisa_params; + status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + cds_message.bodyptr = cds_msg_wisa_params; + cds_message.type = WMA_SET_WISA_PARAMS; + status = cds_mq_post_message(CDS_MQ_ID_WMA, &cds_message); + sme_release_global_lock(&mac->sme); + } + return status; +} + +/* --------------------------------------------------------------------------- + \fn sme_set_significant_change + \brief SME API to set significant change + \param hHal + \param pSetSignificantChangeReq: extscan set significant change structure + \- return QDF_STATUS + -------------------------------------------------------------------------*/ +QDF_STATUS sme_set_significant_change(tHalHandle hHal, + tSirExtScanSetSigChangeReqParams * + pSetSignificantChangeReq) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + cds_msg_t cds_message; + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + /* Serialize the req through MC thread */ + cds_message.bodyptr = pSetSignificantChangeReq; + cds_message.type = WMA_EXTSCAN_SET_SIGNF_CHANGE_REQ; + MTRACE(qdf_trace(QDF_MODULE_ID_SME, TRACE_CODE_SME_TX_WMA_MSG, + NO_SESSION, cds_message.type)); + qdf_status = cds_mq_post_message(CDS_MQ_ID_WMA, &cds_message); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) + status = QDF_STATUS_E_FAILURE; + + sme_release_global_lock(&pMac->sme); + } + return status; +} + +/* --------------------------------------------------------------------------- + \fn sme_reset_significant_change + \brief SME API to reset significant change + \param hHal + \param pResetReq: extscan reset significant change structure + \- return QDF_STATUS + -------------------------------------------------------------------------*/ +QDF_STATUS sme_reset_significant_change(tHalHandle hHal, + tSirExtScanResetSignificantChangeReqParams + *pResetReq) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + cds_msg_t cds_message; + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + /* Serialize the req through MC thread */ + cds_message.bodyptr = pResetReq; + cds_message.type = WMA_EXTSCAN_RESET_SIGNF_CHANGE_REQ; + MTRACE(qdf_trace(QDF_MODULE_ID_SME, TRACE_CODE_SME_TX_WMA_MSG, + NO_SESSION, cds_message.type)); + qdf_status = cds_mq_post_message(CDS_MQ_ID_WMA, &cds_message); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) + status = QDF_STATUS_E_FAILURE; + + sme_release_global_lock(&pMac->sme); + } + return status; +} + +/* --------------------------------------------------------------------------- + \fn sme_get_cached_results + \brief SME API to get cached results + \param hHal + \param pCachedResultsReq: extscan get cached results structure + \- return QDF_STATUS + -------------------------------------------------------------------------*/ +QDF_STATUS sme_get_cached_results(tHalHandle hHal, + tSirExtScanGetCachedResultsReqParams * + pCachedResultsReq) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + cds_msg_t cds_message; + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + /* Serialize the req through MC thread */ + cds_message.bodyptr = pCachedResultsReq; + cds_message.type = WMA_EXTSCAN_GET_CACHED_RESULTS_REQ; + MTRACE(qdf_trace(QDF_MODULE_ID_SME, TRACE_CODE_SME_TX_WMA_MSG, + NO_SESSION, cds_message.type)); + qdf_status = cds_mq_post_message(CDS_MQ_ID_WMA, &cds_message); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) + status = QDF_STATUS_E_FAILURE; + + sme_release_global_lock(&pMac->sme); + } + return status; +} + +/** + * sme_set_epno_list() - set epno network list + * @hal: global hal handle + * @input: request message + * + * This function constructs the cds message and fill in message type, + * bodyptr with %input and posts it to WDA queue. + * + * Return: QDF_STATUS enumeration + */ +QDF_STATUS sme_set_epno_list(tHalHandle hal, + struct wifi_epno_params *input) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpAniSirGlobal mac = PMAC_STRUCT(hal); + cds_msg_t cds_message; + struct wifi_epno_params *req_msg; + int len, i; + + sms_log(mac, LOG1, FL("enter")); + len = sizeof(*req_msg) + + (input->num_networks * sizeof(struct wifi_epno_network)); + + req_msg = qdf_mem_malloc(len); + if (!req_msg) { + sms_log(mac, LOGE, FL("qdf_mem_malloc failed")); + return QDF_STATUS_E_NOMEM; + } + + req_msg->num_networks = input->num_networks; + req_msg->request_id = input->request_id; + req_msg->session_id = input->session_id; + + /* Fill only when num_networks are non zero */ + if (req_msg->num_networks) { + req_msg->min_5ghz_rssi = input->min_5ghz_rssi; + req_msg->min_24ghz_rssi = input->min_24ghz_rssi; + req_msg->initial_score_max = input->initial_score_max; + req_msg->same_network_bonus = input->same_network_bonus; + req_msg->secure_bonus = input->secure_bonus; + req_msg->band_5ghz_bonus = input->band_5ghz_bonus; + req_msg->current_connection_bonus = + input->current_connection_bonus; + + for (i = 0; i < req_msg->num_networks; i++) { + req_msg->networks[i].flags = input->networks[i].flags; + req_msg->networks[i].auth_bit_field = + input->networks[i].auth_bit_field; + req_msg->networks[i].ssid.length = + input->networks[i].ssid.length; + qdf_mem_copy(req_msg->networks[i].ssid.ssId, + input->networks[i].ssid.ssId, + req_msg->networks[i].ssid.length); + } + } + + status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + sms_log(mac, LOGE, + FL("sme_acquire_global_lock failed!(status=%d)"), + status); + qdf_mem_free(req_msg); + return status; + } + + /* Serialize the req through MC thread */ + cds_message.bodyptr = req_msg; + cds_message.type = WMA_SET_EPNO_LIST_REQ; + status = cds_mq_post_message(CDS_MQ_ID_WMA, &cds_message); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sms_log(mac, LOGE, + FL("cds_mq_post_message failed!(err=%d)"), + status); + qdf_mem_free(req_msg); + status = QDF_STATUS_E_FAILURE; + } + sme_release_global_lock(&mac->sme); + return status; +} + +/** + * sme_set_passpoint_list() - set passpoint network list + * @hal: global hal handle + * @input: request message + * + * This function constructs the cds message and fill in message type, + * bodyptr with @input and posts it to WDA queue. + * + * Return: QDF_STATUS enumeration + */ +QDF_STATUS sme_set_passpoint_list(tHalHandle hal, + struct wifi_passpoint_req *input) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpAniSirGlobal mac = PMAC_STRUCT(hal); + cds_msg_t cds_message; + struct wifi_passpoint_req *req_msg; + int len, i; + + sms_log(mac, LOG1, FL("enter")); + len = sizeof(*req_msg) + + (input->num_networks * sizeof(struct wifi_passpoint_network)); + req_msg = qdf_mem_malloc(len); + if (!req_msg) { + sms_log(mac, LOGE, FL("qdf_mem_malloc failed")); + return QDF_STATUS_E_NOMEM; + } + + req_msg->num_networks = input->num_networks; + req_msg->request_id = input->request_id; + req_msg->session_id = input->session_id; + for (i = 0; i < req_msg->num_networks; i++) { + req_msg->networks[i].id = + input->networks[i].id; + qdf_mem_copy(req_msg->networks[i].realm, + input->networks[i].realm, + strlen(input->networks[i].realm) + 1); + qdf_mem_copy(req_msg->networks[i].plmn, + input->networks[i].plmn, + SIR_PASSPOINT_PLMN_LEN); + qdf_mem_copy(req_msg->networks[i].roaming_consortium_ids, + input->networks[i].roaming_consortium_ids, + sizeof(req_msg->networks[i].roaming_consortium_ids)); + } + + status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + sms_log(mac, LOGE, + FL("sme_acquire_global_lock failed!(status=%d)"), + status); + qdf_mem_free(req_msg); + return status; + } + + /* Serialize the req through MC thread */ + cds_message.bodyptr = req_msg; + cds_message.type = WMA_SET_PASSPOINT_LIST_REQ; + status = cds_mq_post_message(CDS_MQ_ID_WMA, &cds_message); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sms_log(mac, LOGE, + FL("cds_mq_post_message failed!(err=%d)"), + status); + qdf_mem_free(req_msg); + status = QDF_STATUS_E_FAILURE; + } + sme_release_global_lock(&mac->sme); + return status; +} + +/** + * sme_reset_passpoint_list() - reset passpoint network list + * @hHal: global hal handle + * @input: request message + * + * Return: QDF_STATUS enumeration + */ +QDF_STATUS sme_reset_passpoint_list(tHalHandle hal, + struct wifi_passpoint_req *input) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpAniSirGlobal mac = PMAC_STRUCT(hal); + cds_msg_t cds_message; + struct wifi_passpoint_req *req_msg; + + sms_log(mac, LOG1, FL("enter")); + req_msg = qdf_mem_malloc(sizeof(*req_msg)); + if (!req_msg) { + sms_log(mac, LOGE, FL("qdf_mem_malloc failed")); + return QDF_STATUS_E_NOMEM; + } + + req_msg->request_id = input->request_id; + req_msg->session_id = input->session_id; + + status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + sms_log(mac, LOGE, + FL("sme_acquire_global_lock failed!(status=%d)"), + status); + qdf_mem_free(req_msg); + return status; + } + + /* Serialize the req through MC thread */ + cds_message.bodyptr = req_msg; + cds_message.type = WMA_RESET_PASSPOINT_LIST_REQ; + status = cds_mq_post_message(CDS_MQ_ID_WMA, &cds_message); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sms_log(mac, LOGE, + FL("cds_mq_post_message failed!(err=%d)"), + status); + qdf_mem_free(req_msg); + status = QDF_STATUS_E_FAILURE; + } + sme_release_global_lock(&mac->sme); + return status; +} + +QDF_STATUS sme_ext_scan_register_callback(tHalHandle hHal, + void (*pExtScanIndCb)(void *, + const uint16_t, + void *)) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + pMac->sme.pExtScanIndCb = pExtScanIndCb; + sme_release_global_lock(&pMac->sme); + } + return status; +} +#endif /* FEATURE_WLAN_EXTSCAN */ + +#ifdef WLAN_FEATURE_LINK_LAYER_STATS + +/* --------------------------------------------------------------------------- + \fn sme_ll_stats_clear_req + \brief SME API to clear Link Layer Statistics + \param hHal + \param pclearStatsReq: Link Layer clear stats request params structure + \- return QDF_STATUS + -------------------------------------------------------------------------*/ +QDF_STATUS sme_ll_stats_clear_req(tHalHandle hHal, + tSirLLStatsClearReq *pclearStatsReq) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + cds_msg_t cds_message; + tSirLLStatsClearReq *clear_stats_req; + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO, + "staId = %u", pclearStatsReq->staId); + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO, + "statsClearReqMask = 0x%X", + pclearStatsReq->statsClearReqMask); + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO, + "stopReq = %u", pclearStatsReq->stopReq); + + clear_stats_req = qdf_mem_malloc(sizeof(*clear_stats_req)); + + if (!clear_stats_req) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Not able to allocate memory for WMA_LL_STATS_CLEAR_REQ", + __func__); + return QDF_STATUS_E_NOMEM; + } + + *clear_stats_req = *pclearStatsReq; + + if (QDF_STATUS_SUCCESS == sme_acquire_global_lock(&pMac->sme)) { + /* Serialize the req through MC thread */ + cds_message.bodyptr = clear_stats_req; + cds_message.type = WMA_LINK_LAYER_STATS_CLEAR_REQ; + MTRACE(qdf_trace(QDF_MODULE_ID_SME, TRACE_CODE_SME_TX_WMA_MSG, + NO_SESSION, cds_message.type)); + qdf_status = cds_mq_post_message(CDS_MQ_ID_WMA, &cds_message); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: not able to post WMA_LL_STATS_CLEAR_REQ", + __func__); + qdf_mem_free(clear_stats_req); + status = QDF_STATUS_E_FAILURE; + } + sme_release_global_lock(&pMac->sme); + } else { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, "%s: " + "sme_acquire_global_lock error", __func__); + qdf_mem_free(clear_stats_req); + status = QDF_STATUS_E_FAILURE; + } + + return status; +} + +/* --------------------------------------------------------------------------- + \fn sme_ll_stats_set_req + \brief SME API to set the Link Layer Statistics + \param hHal + \param psetStatsReq: Link Layer set stats request params structure + \- return QDF_STATUS + -------------------------------------------------------------------------*/ +QDF_STATUS sme_ll_stats_set_req(tHalHandle hHal, tSirLLStatsSetReq *psetStatsReq) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + cds_msg_t cds_message; + tSirLLStatsSetReq *set_stats_req; + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO, + "%s: MPDU Size = %u", __func__, + psetStatsReq->mpduSizeThreshold); + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO, + " Aggressive Stats Collections = %u", + psetStatsReq->aggressiveStatisticsGathering); + + set_stats_req = qdf_mem_malloc(sizeof(*set_stats_req)); + + if (!set_stats_req) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Not able to allocate memory for WMA_LL_STATS_SET_REQ", + __func__); + return QDF_STATUS_E_NOMEM; + } + + *set_stats_req = *psetStatsReq; + + if (QDF_STATUS_SUCCESS == sme_acquire_global_lock(&pMac->sme)) { + /* Serialize the req through MC thread */ + cds_message.bodyptr = set_stats_req; + cds_message.type = WMA_LINK_LAYER_STATS_SET_REQ; + MTRACE(qdf_trace(QDF_MODULE_ID_SME, TRACE_CODE_SME_TX_WMA_MSG, + NO_SESSION, cds_message.type)); + qdf_status = cds_mq_post_message(CDS_MQ_ID_WMA, &cds_message); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: not able to post WMA_LL_STATS_SET_REQ", + __func__); + qdf_mem_free(set_stats_req); + status = QDF_STATUS_E_FAILURE; + } + sme_release_global_lock(&pMac->sme); + } else { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, "%s: " + "sme_acquire_global_lock error", __func__); + qdf_mem_free(set_stats_req); + status = QDF_STATUS_E_FAILURE; + } + + return status; +} + +/* --------------------------------------------------------------------------- + \fn sme_ll_stats_get_req + \brief SME API to get the Link Layer Statistics + \param hHal + \param pgetStatsReq: Link Layer get stats request params structure + \- return QDF_STATUS + -------------------------------------------------------------------------*/ +QDF_STATUS sme_ll_stats_get_req(tHalHandle hHal, tSirLLStatsGetReq *pgetStatsReq) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + cds_msg_t cds_message; + tSirLLStatsGetReq *get_stats_req; + + get_stats_req = qdf_mem_malloc(sizeof(*get_stats_req)); + + if (!get_stats_req) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Not able to allocate memory for WMA_LL_STATS_GET_REQ", + __func__); + return QDF_STATUS_E_NOMEM; + } + + *get_stats_req = *pgetStatsReq; + + if (QDF_STATUS_SUCCESS == sme_acquire_global_lock(&pMac->sme)) { + /* Serialize the req through MC thread */ + cds_message.bodyptr = get_stats_req; + cds_message.type = WMA_LINK_LAYER_STATS_GET_REQ; + MTRACE(qdf_trace(QDF_MODULE_ID_SME, TRACE_CODE_SME_TX_WMA_MSG, + NO_SESSION, cds_message.type)); + qdf_status = cds_mq_post_message(CDS_MQ_ID_WMA, &cds_message); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: not able to post WMA_LL_STATS_GET_REQ", + __func__); + + qdf_mem_free(get_stats_req); + status = QDF_STATUS_E_FAILURE; + + } + sme_release_global_lock(&pMac->sme); + } else { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, "%s: " + "sme_acquire_global_lock error", __func__); + qdf_mem_free(get_stats_req); + status = QDF_STATUS_E_FAILURE; + } + + return status; +} + +/* --------------------------------------------------------------------------- + \fn sme_set_link_layer_stats_ind_cb + \brief SME API to trigger the stats are available after get request + \param hHal + \param callback_routine - HDD callback which needs to be invoked after + getting status notification from FW + \- return QDF_STATUS + -------------------------------------------------------------------------*/ +QDF_STATUS sme_set_link_layer_stats_ind_cb + (tHalHandle hHal, + void (*callback_routine)(void *callbackCtx, int indType, void *pRsp) + ) { + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + pMac->sme.pLinkLayerStatsIndCallback = callback_routine; + sme_release_global_lock(&pMac->sme); + } else { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, "%s: " + "sme_acquire_global_lock error", __func__); + } + + return status; +} + +/** + * sme_reset_link_layer_stats_ind_cb() - SME API to reset link layer stats + * indication + * @h_hal: Hal Handle + * + * This function reset's the link layer stats indication + * + * Return: QDF_STATUS Enumeration + */ + +QDF_STATUS sme_reset_link_layer_stats_ind_cb(tHalHandle h_hal) +{ + QDF_STATUS status; + tpAniSirGlobal pmac; + + if (!h_hal) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("hHal is not valid")); + return QDF_STATUS_E_INVAL; + } + pmac = PMAC_STRUCT(h_hal); + + status = sme_acquire_global_lock(&pmac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + pmac->sme.pLinkLayerStatsIndCallback = NULL; + sme_release_global_lock(&pmac->sme); + } else { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, "%s: sme_acquire_global_lock error", + __func__); + } + + return status; +} + + +#endif /* WLAN_FEATURE_LINK_LAYER_STATS */ + +#ifdef WLAN_POWER_DEBUGFS +/** + * sme_power_debug_stats_req() - SME API to collect Power debug stats + * @callback_fn: Pointer to the callback function for Power stats event + * @power_stats_context: Pointer to context + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_power_debug_stats_req(tHalHandle hal, void (*callback_fn) + (struct power_stats_response *response, + void *context), void *power_stats_context) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + cds_msg_t msg; + + status = sme_acquire_global_lock(&mac_ctx->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + if (!callback_fn) { + sms_log(mac_ctx, LOGE, + FL("Indication callback did not registered")); + sme_release_global_lock(&mac_ctx->sme); + return QDF_STATUS_E_FAILURE; + } + + mac_ctx->sme.power_debug_stats_context = power_stats_context; + mac_ctx->sme.power_stats_resp_callback = callback_fn; + msg.bodyptr = NULL; + msg.type = WMA_POWER_DEBUG_STATS_REQ; + status = cds_mq_post_message(QDF_MODULE_ID_WMA, &msg); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sms_log(mac_ctx, LOGE, + FL("not able to post WDA_POWER_DEBUG_STATS_REQ")); + } + sme_release_global_lock(&mac_ctx->sme); + } + return status; +} +#endif + +/** + * sme_fw_mem_dump_register_cb() - Register fw memory dump callback + * + * @hal - MAC global handle + * @callback_routine - callback routine from HDD + * + * This API is invoked by HDD to register its callback in SME + * + * Return: QDF_STATUS + */ +#ifdef WLAN_FEATURE_MEMDUMP +QDF_STATUS sme_fw_mem_dump_register_cb(tHalHandle hal, + void (*callback_routine)(void *cb_context, + struct fw_dump_rsp *rsp)) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpAniSirGlobal pmac = PMAC_STRUCT(hal); + + status = sme_acquire_global_lock(&pmac->sme); + if (QDF_STATUS_SUCCESS == status) { + pmac->sme.fw_dump_callback = callback_routine; + sme_release_global_lock(&pmac->sme); + } else { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("sme_acquire_global_lock error")); + } + + return status; +} +#else +QDF_STATUS sme_fw_mem_dump_register_cb(tHalHandle hal, + void (*callback_routine)(void *cb_context, + struct fw_dump_rsp *rsp)) +{ + return QDF_STATUS_SUCCESS; +} +#endif /* WLAN_FEATURE_MEMDUMP */ + +/** + * sme_fw_mem_dump_unregister_cb() - Unregister fw memory dump callback + * + * @hHal - MAC global handle + * + * This API is invoked by HDD to unregister its callback in SME + * + * Return: QDF_STATUS + */ +#ifdef WLAN_FEATURE_MEMDUMP +QDF_STATUS sme_fw_mem_dump_unregister_cb(tHalHandle hal) +{ + QDF_STATUS status; + tpAniSirGlobal pmac = PMAC_STRUCT(hal); + + status = sme_acquire_global_lock(&pmac->sme); + if (QDF_STATUS_SUCCESS == status) { + pmac->sme.fw_dump_callback = NULL; + sme_release_global_lock(&pmac->sme); + } else { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("sme_acquire_global_lock error")); + } + + return status; +} +#else +QDF_STATUS sme_fw_mem_dump_unregister_cb(tHalHandle hal) +{ + return QDF_STATUS_SUCCESS; +} +#endif /* WLAN_FEATURE_MEMDUMP */ + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +/*-------------------------------------------------------------------------- + \brief sme_update_roam_offload_enabled() - enable/disable roam offload feaure + It is used at in the REG_DYNAMIC_VARIABLE macro definition of + \param hHal - The handle returned by mac_open. + \param nRoamOffloadEnabled - The bool to update with + \return QDF_STATUS_SUCCESS - SME update config successfully. + Other status means SME is failed to update. + \sa + --------------------------------------------------------------------------*/ + +QDF_STATUS sme_update_roam_offload_enabled(tHalHandle hHal, + bool nRoamOffloadEnabled) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + QDF_STATUS status = QDF_STATUS_SUCCESS; + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO, + "%s: LFR3:gRoamOffloadEnabled is changed from %d to %d", + __func__, pMac->roam.configParam.isRoamOffloadEnabled, + nRoamOffloadEnabled); + pMac->roam.configParam.isRoamOffloadEnabled = + nRoamOffloadEnabled; + sme_release_global_lock(&pMac->sme); + } + + return status; +} + +/** + * sme_update_roam_key_mgmt_offload_enabled() - enable/disable key mgmt offload + * This is a synchronous call + * @hal_ctx: The handle returned by mac_open. + * @session_id: Session Identifier + * @key_mgmt_offload_enabled: key mgmt enable/disable flag + * @pmkid_modes: PMKID modes of PMKSA caching and OKC + * Return: QDF_STATUS_SUCCESS - SME updated config successfully. + * Other status means SME is failed to update. + */ + +QDF_STATUS sme_update_roam_key_mgmt_offload_enabled(tHalHandle hal_ctx, + uint8_t session_id, + bool key_mgmt_offload_enabled, + struct pmkid_mode_bits *pmkid_modes) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal_ctx); + QDF_STATUS status = QDF_STATUS_SUCCESS; + + status = sme_acquire_global_lock(&mac_ctx->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + if (CSR_IS_SESSION_VALID(mac_ctx, session_id)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO, + "%s: LFR3: key_mgmt_offload_enabled changed to %d", + __func__, key_mgmt_offload_enabled); + status = csr_roam_set_key_mgmt_offload(mac_ctx, + session_id, + key_mgmt_offload_enabled, + pmkid_modes); + } else { + status = QDF_STATUS_E_INVAL; + } + sme_release_global_lock(&mac_ctx->sme); + } + + return status; +} +#endif + +/* --------------------------------------------------------------------------- + \fn sme_get_temperature + \brief SME API to get the pdev temperature + \param hHal + \param temperature context + \param pCallbackfn: callback fn with response (temperature) + \- return QDF_STATUS + -------------------------------------------------------------------------*/ +QDF_STATUS sme_get_temperature(tHalHandle hHal, + void *tempContext, + void (*pCallbackfn)(int temperature, + void *pContext)) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + cds_msg_t cds_message; + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_STATUS_SUCCESS == status) { + if ((NULL == pCallbackfn) && + (NULL == pMac->sme.pGetTemperatureCb)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL + ("Indication Call back did not registered")); + sme_release_global_lock(&pMac->sme); + return QDF_STATUS_E_FAILURE; + } else if (NULL != pCallbackfn) { + pMac->sme.pTemperatureCbContext = tempContext; + pMac->sme.pGetTemperatureCb = pCallbackfn; + } + /* serialize the req through MC thread */ + cds_message.bodyptr = NULL; + cds_message.type = WMA_GET_TEMPERATURE_REQ; + qdf_status = cds_mq_post_message(CDS_MQ_ID_WMA, &cds_message); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Post Get Temperature msg fail")); + status = QDF_STATUS_E_FAILURE; + } + sme_release_global_lock(&pMac->sme); + } + return status; +} + +/* --------------------------------------------------------------------------- + \fn sme_set_scanning_mac_oui + \brief SME API to set scanning mac oui + \param hHal + \param pScanMacOui: Scanning Mac Oui (input 3 bytes) + \- return QDF_STATUS + -------------------------------------------------------------------------*/ +QDF_STATUS sme_set_scanning_mac_oui(tHalHandle hHal, tSirScanMacOui *pScanMacOui) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + cds_msg_t cds_message; + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_STATUS_SUCCESS == status) { + /* Serialize the req through MC thread */ + cds_message.bodyptr = pScanMacOui; + cds_message.type = WMA_SET_SCAN_MAC_OUI_REQ; + qdf_status = cds_mq_post_message(CDS_MQ_ID_WMA, &cds_message); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Msg post Set Scan Mac OUI failed")); + status = QDF_STATUS_E_FAILURE; + } + sme_release_global_lock(&pMac->sme); + } + return status; +} + +#ifdef DHCP_SERVER_OFFLOAD +/* --------------------------------------------------------------------------- + \fn sme_set_dhcp_srv_offload + \brief SME API to set DHCP server offload info + \param hHal + \param pDhcpSrvInfo : DHCP server offload info struct + \- return QDF_STATUS + -------------------------------------------------------------------------*/ +QDF_STATUS sme_set_dhcp_srv_offload(tHalHandle hHal, + tSirDhcpSrvOffloadInfo *pDhcpSrvInfo) +{ + cds_msg_t cds_message; + tSirDhcpSrvOffloadInfo *pSmeDhcpSrvInfo; + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + pSmeDhcpSrvInfo = qdf_mem_malloc(sizeof(*pSmeDhcpSrvInfo)); + + if (!pSmeDhcpSrvInfo) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Not able to allocate memory for WMA_SET_DHCP_SERVER_OFFLOAD_CMD", + __func__); + return QDF_STATUS_E_NOMEM; + } + + *pSmeDhcpSrvInfo = *pDhcpSrvInfo; + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_STATUS_SUCCESS == status) { + /* serialize the req through MC thread */ + cds_message.type = WMA_SET_DHCP_SERVER_OFFLOAD_CMD; + cds_message.bodyptr = pSmeDhcpSrvInfo; + + if (!QDF_IS_STATUS_SUCCESS + (cds_mq_post_message(QDF_MODULE_ID_WMA, &cds_message))) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Not able to post WMA_SET_DHCP_SERVER_OFFLOAD_CMD to WMA!", + __func__); + qdf_mem_free(pSmeDhcpSrvInfo); + status = QDF_STATUS_E_FAILURE; + } + sme_release_global_lock(&pMac->sme); + } else { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: sme_acquire_global_lock error!", __func__); + qdf_mem_free(pSmeDhcpSrvInfo); + } + + return status; +} +#endif /* DHCP_SERVER_OFFLOAD */ + +#ifdef WLAN_FEATURE_GPIO_LED_FLASHING +/* --------------------------------------------------------------------------- + \fn sme_set_led_flashing + \brief API to set the Led flashing parameters. + \param hHal - The handle returned by mac_open. + \param x0, x1 - led flashing parameters + \return QDF_STATUS + ---------------------------------------------------------------------------*/ +QDF_STATUS sme_set_led_flashing(tHalHandle hHal, uint8_t type, + uint32_t x0, uint32_t x1) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + cds_msg_t cds_message; + tSirLedFlashingReq *ledflashing; + + ledflashing = qdf_mem_malloc(sizeof(*ledflashing)); + if (!ledflashing) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL + ("Not able to allocate memory for WMA_LED_TIMING_REQ")); + return QDF_STATUS_E_NOMEM; + } + + ledflashing->pattern_id = type; + ledflashing->led_x0 = x0; + ledflashing->led_x1 = x1; + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + /* Serialize the req through MC thread */ + cds_message.bodyptr = ledflashing; + cds_message.type = WMA_LED_FLASHING_REQ; + qdf_status = cds_mq_post_message(CDS_MQ_ID_WMA, &cds_message); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) + status = QDF_STATUS_E_FAILURE; + sme_release_global_lock(&pMac->sme); + } + return status; +} +#endif + +/** + * sme_handle_dfS_chan_scan() - handle DFS channel configuration + * @h_hal: corestack handler + * @dfs_flag: flag indicating dfs channel enable/disable + * Return: QDF_STATUS + */ +QDF_STATUS sme_handle_dfs_chan_scan(tHalHandle h_hal, uint8_t dfs_flag) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpAniSirGlobal mac = PMAC_STRUCT(h_hal); + + status = sme_acquire_global_lock(&mac->sme); + + if (QDF_STATUS_SUCCESS == status) { + + mac->scan.fEnableDFSChnlScan = dfs_flag; + + /* update the channel list to the firmware */ + status = csr_update_channel_list(mac); + + sme_release_global_lock(&mac->sme); + } + + return status; +} + +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH +/** + * sme_validate_sap_channel_switch() - validate target channel switch w.r.t + * concurreny rules set to avoid channel interference. + * @hal - Hal context + * @sap_ch - channel to switch + * @sap_phy_mode - phy mode of SAP + * @cc_switch_mode - concurreny switch mode + * @session_id - sme session id. + * + * Return: true if there is no channel interference else return false + */ +bool sme_validate_sap_channel_switch(tHalHandle hal, + uint16_t sap_ch, eCsrPhyMode sap_phy_mode, uint8_t cc_switch_mode, + uint8_t session_id) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal mac = PMAC_STRUCT(hal); + tCsrRoamSession *session = CSR_GET_SESSION(mac, session_id); + uint16_t intf_channel = 0; + + if (!session) + return false; + + session->ch_switch_in_progress = true; + status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + intf_channel = csr_check_concurrent_channel_overlap(mac, sap_ch, + sap_phy_mode, + cc_switch_mode); + sme_release_global_lock(&mac->sme); + } else { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("sme_acquire_global_lock error!")); + session->ch_switch_in_progress = false; + return false; + } + + session->ch_switch_in_progress = false; + return (intf_channel == 0) ? true : false; +} +#endif + +/** + * sme_configure_stats_avg_factor() - function to config avg. stats factor + * @hal: hal + * @session_id: session ID + * @stats_avg_factor: average stats factor + * + * This function configures the stats avg factor in firmware + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_configure_stats_avg_factor(tHalHandle hal, uint8_t session_id, + uint16_t stats_avg_factor) +{ + cds_msg_t msg; + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpAniSirGlobal mac = PMAC_STRUCT(hal); + struct sir_stats_avg_factor *stats_factor; + + stats_factor = qdf_mem_malloc(sizeof(*stats_factor)); + + if (!stats_factor) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Not able to allocate memory for SIR_HAL_CONFIG_STATS_FACTOR", + __func__); + return QDF_STATUS_E_NOMEM; + } + + status = sme_acquire_global_lock(&mac->sme); + + if (QDF_STATUS_SUCCESS == status) { + + stats_factor->vdev_id = session_id; + stats_factor->stats_avg_factor = stats_avg_factor; + + /* serialize the req through MC thread */ + msg.type = SIR_HAL_CONFIG_STATS_FACTOR; + msg.bodyptr = stats_factor; + + if (!QDF_IS_STATUS_SUCCESS( + cds_mq_post_message(QDF_MODULE_ID_WMA, &msg))) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Not able to post SIR_HAL_CONFIG_STATS_FACTOR to WMA!", + __func__); + qdf_mem_free(stats_factor); + status = QDF_STATUS_E_FAILURE; + } + sme_release_global_lock(&mac->sme); + } else { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: sme_acquire_global_lock error!", + __func__); + qdf_mem_free(stats_factor); + } + + return status; +} + +/** + * sme_configure_guard_time() - function to configure guard time + * @hal: hal + * @session_id: session id + * @guard_time: guard time + * + * This function configures the guard time in firmware + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_configure_guard_time(tHalHandle hal, uint8_t session_id, + uint32_t guard_time) +{ + cds_msg_t msg; + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpAniSirGlobal mac = PMAC_STRUCT(hal); + struct sir_guard_time_request *g_time; + + g_time = qdf_mem_malloc(sizeof(*g_time)); + + if (!g_time) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Not able to allocate memory for SIR_HAL_CONFIG_GUARD_TIME", + __func__); + return QDF_STATUS_E_NOMEM; + } + + status = sme_acquire_global_lock(&mac->sme); + + if (QDF_STATUS_SUCCESS == status) { + + g_time->vdev_id = session_id; + g_time->guard_time = guard_time; + + /* serialize the req through MC thread */ + msg.type = SIR_HAL_CONFIG_GUARD_TIME; + msg.bodyptr = g_time; + + if (!QDF_IS_STATUS_SUCCESS( + cds_mq_post_message(QDF_MODULE_ID_WMA, &msg))) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Not able to post SIR_HAL_CONFIG_GUARD_TIME to WMA!", + __func__); + qdf_mem_free(g_time); + status = QDF_STATUS_E_FAILURE; + } + sme_release_global_lock(&mac->sme); + } else { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: sme_acquire_global_lock error!", + __func__); + qdf_mem_free(g_time); + } + + return status; +} + +/** + * sme_configure_modulated_dtim() - function to configure modulated dtim + * @h_hal: SME API to enable/disable modulated DTIM instantaneously + * @session_id: session ID + * @modulated_dtim: modulated dtim value + * + * This function configures the modulated dtim in firmware + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_configure_modulated_dtim(tHalHandle h_hal, uint8_t session_id, + uint32_t modulated_dtim) +{ + cds_msg_t msg; + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpAniSirGlobal mac = PMAC_STRUCT(h_hal); + wma_cli_set_cmd_t *iwcmd; + + iwcmd = qdf_mem_malloc(sizeof(*iwcmd)); + if (NULL == iwcmd) { + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_FATAL, + "%s: qdf_mem_malloc failed", __func__); + return QDF_STATUS_E_NOMEM; + } + + status = sme_acquire_global_lock(&mac->sme); + + if (QDF_STATUS_SUCCESS == status) { + + iwcmd->param_value = modulated_dtim; + iwcmd->param_vdev_id = session_id; + iwcmd->param_id = GEN_PARAM_MODULATED_DTIM; + iwcmd->param_vp_dev = GEN_CMD; + msg.type = WMA_CLI_SET_CMD; + msg.reserved = 0; + msg.bodyptr = (void *)iwcmd; + + if (!QDF_IS_STATUS_SUCCESS( + cds_mq_post_message(QDF_MODULE_ID_WMA, &msg))) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Not able to post GEN_PARAM_DYNAMIC_DTIM to WMA!", + __func__); + qdf_mem_free(iwcmd); + status = QDF_STATUS_E_FAILURE; + } + sme_release_global_lock(&mac->sme); + } else { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: sme_acquire_global_lock error!", + __func__); + qdf_mem_free(iwcmd); + } + + return status; +} + +/* + * sme_wifi_start_logger() - Send the start/stop logging command to WMA + * to either start/stop logging + * @hal: HAL context + * @start_log: Structure containing the wifi start logger params + * + * This function sends the start/stop logging command to WMA + * + * Return: QDF_STATUS_SUCCESS on successful posting + */ +QDF_STATUS sme_wifi_start_logger(tHalHandle hal, + struct sir_wifi_start_log start_log) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpAniSirGlobal mac = PMAC_STRUCT(hal); + cds_msg_t cds_message; + struct sir_wifi_start_log *req_msg; + uint32_t len; + + len = sizeof(*req_msg); + req_msg = qdf_mem_malloc(len); + if (!req_msg) { + sms_log(mac, LOGE, FL("qdf_mem_malloc failed")); + return QDF_STATUS_E_NOMEM; + } + + req_msg->verbose_level = start_log.verbose_level; + req_msg->is_iwpriv_command = start_log.is_iwpriv_command; + req_msg->ring_id = start_log.ring_id; + req_msg->ini_triggered = start_log.ini_triggered; + req_msg->user_triggered = start_log.user_triggered; + req_msg->size = start_log.size; + req_msg->is_pktlog_buff_clear = start_log.is_pktlog_buff_clear; + + status = sme_acquire_global_lock(&mac->sme); + if (status != QDF_STATUS_SUCCESS) { + sms_log(mac, LOGE, + FL("sme_acquire_global_lock failed(status=%d)"), + status); + qdf_mem_free(req_msg); + return status; + } + + /* Serialize the req through MC thread */ + cds_message.bodyptr = req_msg; + cds_message.type = SIR_HAL_START_STOP_LOGGING; + status = cds_mq_post_message(CDS_MQ_ID_WMA, &cds_message); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sms_log(mac, LOGE, + FL("cds_mq_post_message failed!(err=%d)"), + status); + qdf_mem_free(req_msg); + status = QDF_STATUS_E_FAILURE; + } + sme_release_global_lock(&mac->sme); + + return status; +} + +/** + * sme_neighbor_middle_of_roaming() - Function to know if + * STA is in the middle of roaming states + * @hal: Handle returned by macOpen + * @sessionId: sessionId of the STA session + * + * This function is a wrapper to call + * csr_neighbor_middle_of_roaming to know STA is in the + * middle of roaming states + * + * Return: True or False + * + */ +bool sme_neighbor_middle_of_roaming(tHalHandle hHal, uint8_t sessionId) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hHal); + bool val = false; + + if (CSR_IS_SESSION_VALID(mac_ctx, sessionId)) + val = csr_neighbor_middle_of_roaming(mac_ctx, sessionId); + else + sms_log(mac_ctx, LOGE, FL("Invalid Sesion = %d"), sessionId); + return val; +} + +/* + * sme_send_flush_logs_cmd_to_fw() - Flush FW logs + * @mac: MAC handle + * + * This function is used to send the command that will + * be used to flush the logs in the firmware + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_send_flush_logs_cmd_to_fw(tpAniSirGlobal mac) +{ + QDF_STATUS status; + cds_msg_t message; + + /* Serialize the req through MC thread */ + message.bodyptr = NULL; + message.type = SIR_HAL_FLUSH_LOG_TO_FW; + status = cds_mq_post_message(CDS_MQ_ID_WMA, &message); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sms_log(mac, LOGE, + FL("cds_mq_post_message failed!(err=%d)"), + status); + status = QDF_STATUS_E_FAILURE; + } + return status; +} + +/** + * sme_enable_uapsd_for_ac() - enable uapsd for access catagory requerst to WMA + * @cds_ctx: cds context + * @sta_id: station id + * @ac: access catagory + * @tid: tid value + * @pri: user priority + * @srvc_int: service interval + * @sus_int: suspend interval + * @dir: tspec direction + * @psb: PSB value + * @sessionId: session id + * @delay_interval: delay interval + * + * Return: QDF status + */ +QDF_STATUS sme_enable_uapsd_for_ac(void *cds_ctx, uint8_t sta_id, + sme_ac_enum_type ac, uint8_t tid, + uint8_t pri, uint32_t srvc_int, + uint32_t sus_int, + sme_tspec_dir_type dir, + uint8_t psb, uint32_t sessionId, + uint32_t delay_interval) +{ + void *wma_handle; + t_wma_trigger_uapsd_params uapsd_params; + enum uapsd_ac access_category; + + if (!psb) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "No need to configure auto trigger:psb is 0"); + return QDF_STATUS_SUCCESS; + } + + wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma_handle) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "wma_handle is NULL"); + return QDF_STATUS_E_FAILURE; + } + + switch (ac) { + case SME_AC_BK: + access_category = UAPSD_BK; + break; + case SME_AC_BE: + access_category = UAPSD_BE; + break; + case SME_AC_VI: + access_category = UAPSD_VI; + break; + case SME_AC_VO: + access_category = UAPSD_VO; + break; + default: + return QDF_STATUS_E_FAILURE; + } + + uapsd_params.wmm_ac = access_category; + uapsd_params.user_priority = pri; + uapsd_params.service_interval = srvc_int; + uapsd_params.delay_interval = delay_interval; + uapsd_params.suspend_interval = sus_int; + + if (QDF_STATUS_SUCCESS != + wma_trigger_uapsd_params(wma_handle, sessionId, &uapsd_params)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "Failed to Trigger Uapsd params for sessionId %d", + sessionId); + return QDF_STATUS_E_FAILURE; + } + return QDF_STATUS_SUCCESS; +} + +/** + * sme_disable_uapsd_for_ac() - disable uapsed access catagory request to WMA + * @cds_ctx: cds context + * @sta_id: station id + * @ac: access catagory + * @sessionId: session id + * + * Return: QDF status + */ +QDF_STATUS sme_disable_uapsd_for_ac(void *cds_ctx, uint8_t sta_id, + sme_ac_enum_type ac, + uint32_t sessionId) +{ + void *wma_handle; + enum uapsd_ac access_category; + + switch (ac) { + case SME_AC_BK: + access_category = UAPSD_BK; + break; + case SME_AC_BE: + access_category = UAPSD_BE; + break; + case SME_AC_VI: + access_category = UAPSD_VI; + break; + case SME_AC_VO: + access_category = UAPSD_VO; + break; + default: + return QDF_STATUS_E_FAILURE; + } + + wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma_handle) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "wma handle is NULL"); + return QDF_STATUS_E_FAILURE; + } + if (QDF_STATUS_SUCCESS != + wma_disable_uapsd_per_ac(wma_handle, sessionId, access_category)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "Failed to disable uapsd for ac %d for sessionId %d", + ac, sessionId); + return QDF_STATUS_E_FAILURE; + } + return QDF_STATUS_SUCCESS; +} + +/** + * sme_update_nss() - SME API to change the number for spatial streams + * (1 or 2) + * @hal: Handle returned by mac open + * @nss: Number of spatial streams + * + * This function is used to update the number of spatial streams supported. + * + * Return: Success upon successfully changing nss else failure + * + */ +QDF_STATUS sme_update_nss(tHalHandle h_hal, uint8_t nss) +{ + QDF_STATUS status; + tpAniSirGlobal mac_ctx = PMAC_STRUCT(h_hal); + uint32_t i, value = 0; + union { + uint16_t cfg_value16; + tSirMacHTCapabilityInfo ht_cap_info; + } uHTCapabilityInfo; + tCsrRoamSession *csr_session; + + status = sme_acquire_global_lock(&mac_ctx->sme); + + if (QDF_STATUS_SUCCESS == status) { + mac_ctx->roam.configParam.enable2x2 = (nss == 1) ? 0 : 1; + + /* get the HT capability info*/ + sme_cfg_get_int(mac_ctx, WNI_CFG_HT_CAP_INFO, &value); + uHTCapabilityInfo.cfg_value16 = (0xFFFF & value); + + for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) { + if (CSR_IS_SESSION_VALID(mac_ctx, i)) { + csr_session = &mac_ctx->roam.roamSession[i]; + csr_session->htConfig.ht_tx_stbc = + uHTCapabilityInfo.ht_cap_info.txSTBC; + } + } + + sme_release_global_lock(&mac_ctx->sme); + } + return status; +} + +/** + * sme_update_user_configured_nss() - sets the nss based on user request + * @hal: Pointer to HAL + * @nss: number of streams + * + * Return: None + */ +void sme_update_user_configured_nss(tHalHandle hal, uint8_t nss) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + + mac_ctx->user_configured_nss = nss; +} + +/** + * sme_set_rssi_threshold_breached_cb() - set rssi threshold breached callback + * @h_hal: global hal handle + * @cb: callback function pointer + * + * This function stores the rssi threshold breached callback function. + * + * Return: QDF_STATUS enumeration. + */ +QDF_STATUS sme_set_rssi_threshold_breached_cb(tHalHandle h_hal, + void (*cb)(void *, struct rssi_breach_event *)) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpAniSirGlobal mac; + + if (!h_hal) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("hHal is not valid")); + return QDF_STATUS_E_INVAL; + } + mac = PMAC_STRUCT(h_hal); + + status = sme_acquire_global_lock(&mac->sme); + if (!QDF_IS_STATUS_SUCCESS(status)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("sme_acquire_global_lock failed!(status=%d)"), + status); + return status; + } + + mac->sme.rssi_threshold_breached_cb = cb; + sme_release_global_lock(&mac->sme); + return status; +} + +/** + * sme_set_nud_debug_stats_cb() - set nud debug stats callback + * @hal: global hal handle + * @cb: callback function pointer + * + * This function stores nud debug stats callback function. + * + * Return: QDF_STATUS enumeration. + */ +QDF_STATUS sme_set_nud_debug_stats_cb(tHalHandle hal, + void (*cb)(void *, struct rsp_stats *)) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpAniSirGlobal mac; + + if (!hal) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("hal is not valid")); + return QDF_STATUS_E_INVAL; + } + mac = PMAC_STRUCT(hal); + + status = sme_acquire_global_lock(&mac->sme); + if (!QDF_IS_STATUS_SUCCESS(status)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("sme_acquire_global_lock failed!(status=%d)"), + status); + return status; + } + + mac->sme.get_arp_stats_cb = cb; + sme_release_global_lock(&mac->sme); + return status; +} + +/** + * sme_set_rssi_threshold_breached_cb() - Reset rssi threshold breached callback + * @hal: global hal handle + * + * This function de-registers the rssi threshold breached callback function. + * + * Return: QDF_STATUS enumeration. + */ +QDF_STATUS sme_reset_rssi_threshold_breached_cb(tHalHandle hal) +{ + QDF_STATUS status; + tpAniSirGlobal mac = PMAC_STRUCT(hal); + + status = sme_acquire_global_lock(&mac->sme); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sms_log(mac, LOGE, + FL("sme_acquire_global_lock failed!(status=%d)"), + status); + return status; + } + + mac->sme.rssi_threshold_breached_cb = NULL; + sme_release_global_lock(&mac->sme); + return status; +} + +/** + * sme_is_any_session_in_connected_state() - SME wrapper API to + * check if any session is in connected state or not. + * + * @hal: Handle returned by mac open + * + * This function is used to check if any valid sme session is in + * connected state or not. + * + * Return: true if any session is connected, else false. + * + */ +bool sme_is_any_session_in_connected_state(tHalHandle h_hal) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(h_hal); + QDF_STATUS status; + bool ret = false; + + status = sme_acquire_global_lock(&mac_ctx->sme); + if (QDF_STATUS_SUCCESS == status) { + ret = csr_is_any_session_in_connect_state(mac_ctx); + sme_release_global_lock(&mac_ctx->sme); + } + return ret; +} + +QDF_STATUS sme_set_chip_pwr_save_fail_cb(tHalHandle hal, + void (*cb)(void *, + struct chip_pwr_save_fail_detected_params *)) +{ + + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpAniSirGlobal mac = PMAC_STRUCT(hal); + + status = sme_acquire_global_lock(&mac->sme); + if (status != QDF_STATUS_SUCCESS) { + sms_log(mac, LOGE, + FL("sme_AcquireGlobalLock failed!(status=%d)"), + status); + return status; + } + mac->sme.chip_power_save_fail_cb = cb; + sme_release_global_lock(&mac->sme); + + return status; +} + +/** + * sme_set_rssi_monitoring() - set rssi monitoring + * @hal: global hal handle + * @input: request message + * + * This function constructs the vos message and fill in message type, + * bodyptr with @input and posts it to WDA queue. + * + * Return: QDF_STATUS enumeration + */ +QDF_STATUS sme_set_rssi_monitoring(tHalHandle hal, + struct rssi_monitor_req *input) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpAniSirGlobal mac = PMAC_STRUCT(hal); + cds_msg_t cds_message; + struct rssi_monitor_req *req_msg; + + sms_log(mac, LOG1, FL("enter")); + req_msg = qdf_mem_malloc(sizeof(*req_msg)); + if (!req_msg) { + sms_log(mac, LOGE, FL("memory allocation failed")); + return QDF_STATUS_E_NOMEM; + } + + *req_msg = *input; + + status = sme_acquire_global_lock(&mac->sme); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sms_log(mac, LOGE, + FL("sme_acquire_global_lock failed!(status=%d)"), + status); + qdf_mem_free(req_msg); + return status; + } + + /* Serialize the req through MC thread */ + cds_message.bodyptr = req_msg; + cds_message.type = WMA_SET_RSSI_MONITOR_REQ; + status = cds_mq_post_message(CDS_MQ_ID_WMA, &cds_message); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sms_log(mac, LOGE, + FL("cds_mq_post_message failed!(err=%d)"), + status); + qdf_mem_free(req_msg); + } + sme_release_global_lock(&mac->sme); + + return status; +} + +/** + * sme_fw_mem_dump() - Get FW memory dump + * @hHal: hal handle + * @recvd_req: received memory dump request. + * + * This API is invoked by HDD to indicate FW to start + * dumping firmware memory. + * + * Return: QDF_STATUS + */ +#ifdef WLAN_FEATURE_MEMDUMP +QDF_STATUS sme_fw_mem_dump(tHalHandle hHal, void *recvd_req) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + cds_msg_t msg; + struct fw_dump_req *send_req; + struct fw_dump_seg_req seg_req; + int loop; + + send_req = qdf_mem_malloc(sizeof(*send_req)); + if (!send_req) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Memory allocation failed for WDA_FW_MEM_DUMP")); + return QDF_STATUS_E_FAILURE; + } + qdf_mem_copy(send_req, recvd_req, sizeof(*send_req)); + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO, + FL("request_id:%d num_seg:%d"), + send_req->request_id, send_req->num_seg); + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO, + FL("Segment Information")); + for (loop = 0; loop < send_req->num_seg; loop++) { + seg_req = send_req->segment[loop]; + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO, + FL("seg_number:%d"), loop); + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO, + FL("seg_id:%d start_addr_lo:0x%x start_addr_hi:0x%x"), + seg_req.seg_id, seg_req.seg_start_addr_lo, + seg_req.seg_start_addr_hi); + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO, + FL("seg_length:%d dst_addr_lo:0x%x dst_addr_hi:0x%x"), + seg_req.seg_length, seg_req.dst_addr_lo, + seg_req.dst_addr_hi); + } + + if (QDF_STATUS_SUCCESS == sme_acquire_global_lock(&pMac->sme)) { + msg.bodyptr = send_req; + msg.type = WMA_FW_MEM_DUMP_REQ; + msg.reserved = 0; + + qdf_status = cds_mq_post_message(QDF_MODULE_ID_WMA, &msg); + if (QDF_STATUS_SUCCESS != qdf_status) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Not able to post WMA_FW_MEM_DUMP")); + qdf_mem_free(send_req); + status = QDF_STATUS_E_FAILURE; + } + sme_release_global_lock(&pMac->sme); + } else { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Failed to acquire SME Global Lock")); + qdf_mem_free(send_req); + status = QDF_STATUS_E_FAILURE; + } + + return status; +} +#else +QDF_STATUS sme_fw_mem_dump(tHalHandle hHal, void *recvd_req) +{ + return QDF_STATUS_SUCCESS; +} +#endif /* WLAN_FEATURE_MEMDUMP */ + +/* + * sme_pdev_set_pcl() - Send WMI_PDEV_SET_PCL_CMDID to the WMA + * @hal: Handle returned by macOpen + * @msg: PCL channel list and length structure + * + * Sends the command to WMA to send WMI_PDEV_SET_PCL_CMDID to FW + * Return: QDF_STATUS_SUCCESS on successful posting + */ +QDF_STATUS sme_pdev_set_pcl(tHalHandle hal, + struct sir_pcl_list msg) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpAniSirGlobal mac = PMAC_STRUCT(hal); + cds_msg_t cds_message; + struct wmi_pcl_chan_weights *req_msg; + uint32_t len, i; + + len = sizeof(*req_msg); + + req_msg = qdf_mem_malloc(len); + if (!req_msg) { + sms_log(mac, LOGE, FL("qdf_mem_malloc failed")); + return QDF_STATUS_E_NOMEM; + } + + for (i = 0; i < msg.pcl_len; i++) { + req_msg->pcl_list[i] = msg.pcl_list[i]; + req_msg->weight_list[i] = msg.weight_list[i]; + } + + req_msg->pcl_len = msg.pcl_len; + + status = sme_acquire_global_lock(&mac->sme); + if (status != QDF_STATUS_SUCCESS) { + sms_log(mac, LOGE, + FL("sme_acquire_global_lock failed!(status=%d)"), + status); + qdf_mem_free(req_msg); + return status; + } + + /* Serialize the req through MC thread */ + cds_message.bodyptr = req_msg; + cds_message.type = SIR_HAL_PDEV_SET_PCL_TO_FW; + status = cds_mq_post_message(CDS_MQ_ID_WMA, &cds_message); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sms_log(mac, LOGE, + FL("cds_mq_post_message failed!(err=%d)"), + status); + qdf_mem_free(req_msg); + status = QDF_STATUS_E_FAILURE; + } + sme_release_global_lock(&mac->sme); + + return status; +} + +/* + * sme_pdev_set_hw_mode() - Send WMI_PDEV_SET_HW_MODE_CMDID to the WMA + * @hal: Handle returned by macOpen + * @msg: HW mode structure containing hw mode and callback details + * + * Sends the command to CSR to send WMI_PDEV_SET_HW_MODE_CMDID to FW + * Return: QDF_STATUS_SUCCESS on successful posting + */ +QDF_STATUS sme_pdev_set_hw_mode(tHalHandle hal, + struct sir_hw_mode msg) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpAniSirGlobal mac = PMAC_STRUCT(hal); + tSmeCmd *cmd = NULL; + + status = sme_acquire_global_lock(&mac->sme); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sms_log(mac, LOGE, FL("Failed to acquire lock")); + return QDF_STATUS_E_RESOURCES; + } + + cmd = sme_get_command_buffer(mac); + if (!cmd) { + sms_log(mac, LOGE, FL("Get command buffer failed")); + sme_release_global_lock(&mac->sme); + return QDF_STATUS_E_NULL_VALUE; + } + + cmd->command = e_sme_command_set_hw_mode; + cmd->sessionId = msg.session_id; + + cmd->u.set_hw_mode_cmd.hw_mode_index = msg.hw_mode_index; + cmd->u.set_hw_mode_cmd.set_hw_mode_cb = msg.set_hw_mode_cb; + cmd->u.set_hw_mode_cmd.reason = msg.reason; + cmd->u.set_hw_mode_cmd.session_id = msg.session_id; + + sms_log(mac, LOG1, + FL("Queuing set hw mode to CSR, session:%d reason:%d"), + cmd->u.set_hw_mode_cmd.session_id, + cmd->u.set_hw_mode_cmd.reason); + csr_queue_sme_command(mac, cmd, false); + + sme_release_global_lock(&mac->sme); + return QDF_STATUS_SUCCESS; +} + +/** + * sme_register_hw_mode_trans_cb() - HW mode transition callback registration + * @hal: Handle returned by macOpen + * @callback: HDD callback to be registered + * + * Registers the HDD callback with SME. This callback will be invoked when + * HW mode transition event is received from the FW + * + * Return: None + */ +void sme_register_hw_mode_trans_cb(tHalHandle hal, + hw_mode_transition_cb callback) +{ + tpAniSirGlobal mac = PMAC_STRUCT(hal); + + mac->sme.sme_hw_mode_trans_cb = callback; + sms_log(mac, LOG1, FL("HW mode transition callback registered")); +} + +/** + * sme_nss_update_request() - Send beacon templete update to FW with new + * nss value + * @hal: Handle returned by macOpen + * @vdev_id: the session id + * @new_nss: the new nss value + * @cback: hdd callback + * @next_action: next action to happen at policy mgr after beacon update + * + * Sends the command to CSR to send to PE + * Return: QDF_STATUS_SUCCESS on successful posting + */ +QDF_STATUS sme_nss_update_request(tHalHandle hHal, uint32_t vdev_id, + uint8_t new_nss, void *cback, uint8_t next_action, + void *hdd_context, + enum sir_conn_update_reason reason) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal mac = PMAC_STRUCT(hHal); + tSmeCmd *cmd = NULL; + + status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + cmd = sme_get_command_buffer(mac); + if (!cmd) { + sms_log(mac, LOGE, FL("Get command buffer failed")); + sme_release_global_lock(&mac->sme); + return QDF_STATUS_E_NULL_VALUE; + } + cmd->command = e_sme_command_nss_update; + /* Sessionized modules may require this info */ + cmd->sessionId = vdev_id; + cmd->u.nss_update_cmd.new_nss = new_nss; + cmd->u.nss_update_cmd.session_id = vdev_id; + cmd->u.nss_update_cmd.nss_update_cb = cback; + cmd->u.nss_update_cmd.context = hdd_context; + cmd->u.nss_update_cmd.next_action = next_action; + cmd->u.nss_update_cmd.reason = reason; + + sms_log(mac, LOG1, FL("Queuing e_sme_command_nss_update to CSR")); + csr_queue_sme_command(mac, cmd, false); + sme_release_global_lock(&mac->sme); + } + return status; +} + +/** + * sme_soc_set_dual_mac_config() - Set dual mac configurations + * @hal: Handle returned by macOpen + * @msg: Structure containing the dual mac config parameters + * + * Queues configuration information to CSR to configure + * WLAN firmware for the dual MAC features + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_soc_set_dual_mac_config(tHalHandle hal, + struct sir_dual_mac_config msg) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpAniSirGlobal mac = PMAC_STRUCT(hal); + tSmeCmd *cmd; + + status = sme_acquire_global_lock(&mac->sme); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sms_log(mac, LOGE, FL("Failed to acquire lock")); + return QDF_STATUS_E_RESOURCES; + } + + cmd = sme_get_command_buffer(mac); + if (!cmd) { + sms_log(mac, LOGE, FL("Get command buffer failed")); + sme_release_global_lock(&mac->sme); + return QDF_STATUS_E_NULL_VALUE; + } + + cmd->command = e_sme_command_set_dual_mac_config; + cmd->u.set_dual_mac_cmd.scan_config = msg.scan_config; + cmd->u.set_dual_mac_cmd.fw_mode_config = msg.fw_mode_config; + cmd->u.set_dual_mac_cmd.set_dual_mac_cb = msg.set_dual_mac_cb; + + sms_log(mac, LOG1, + FL("Queuing e_sme_command_set_dual_mac_config to CSR: %x %x"), + cmd->u.set_dual_mac_cmd.scan_config, + cmd->u.set_dual_mac_cmd.fw_mode_config); + csr_queue_sme_command(mac, cmd, false); + + sme_release_global_lock(&mac->sme); + return QDF_STATUS_SUCCESS; +} + +#ifdef FEATURE_LFR_SUBNET_DETECTION +/** + * sme_gateway_param_update() - to update gateway parameters with WMA + * @Hal: hal handle + * @gw_params: request parameters from HDD + * + * Return: QDF_STATUS + * + * This routine will update gateway parameters to WMA + */ +QDF_STATUS sme_gateway_param_update(tHalHandle Hal, + struct gateway_param_update_req *gw_params) +{ + QDF_STATUS qdf_status; + cds_msg_t cds_message; + struct gateway_param_update_req *request_buf; + + request_buf = qdf_mem_malloc(sizeof(*request_buf)); + if (NULL == request_buf) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Not able to allocate memory for gw param update request")); + return QDF_STATUS_E_NOMEM; + } + + *request_buf = *gw_params; + + cds_message.type = WMA_GW_PARAM_UPDATE_REQ; + cds_message.reserved = 0; + cds_message.bodyptr = request_buf; + qdf_status = cds_mq_post_message(CDS_MQ_ID_WMA, &cds_message); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Not able to post WMA_GW_PARAM_UPDATE_REQ message to HAL")); + qdf_mem_free(request_buf); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} +#endif /* FEATURE_LFR_SUBNET_DETECTION */ + +/** + * sme_soc_set_antenna_mode() - set antenna mode + * @hal: Handle returned by macOpen + * @msg: Structure containing the antenna mode parameters + * + * Send the command to CSR to send + * WMI_SOC_SET_ANTENNA_MODE_CMDID to FW + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_soc_set_antenna_mode(tHalHandle hal, + struct sir_antenna_mode_param *msg) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpAniSirGlobal mac = PMAC_STRUCT(hal); + tSmeCmd *cmd; + + if (NULL == msg) { + sms_log(mac, LOGE, FL("antenna mode mesg is NULL")); + return QDF_STATUS_E_FAILURE; + } + + status = sme_acquire_global_lock(&mac->sme); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sms_log(mac, LOGE, FL("Failed to acquire lock")); + return QDF_STATUS_E_RESOURCES; + } + + cmd = sme_get_command_buffer(mac); + if (!cmd) { + sme_release_global_lock(&mac->sme); + sms_log(mac, LOGE, FL("Get command buffer failed")); + return QDF_STATUS_E_NULL_VALUE; + } + + cmd->command = e_sme_command_set_antenna_mode; + cmd->u.set_antenna_mode_cmd = *msg; + + sms_log(mac, LOG1, + FL("Queuing e_sme_command_set_antenna_mode to CSR: %d %d"), + cmd->u.set_antenna_mode_cmd.num_rx_chains, + cmd->u.set_antenna_mode_cmd.num_tx_chains); + + csr_queue_sme_command(mac, cmd, false); + sme_release_global_lock(&mac->sme); + + return QDF_STATUS_SUCCESS; +} + +/** + * sme_set_peer_authorized() - call peer authorized callback + * @peer_addr: peer mac address + * @auth_cb: auth callback + * @vdev_id: vdev id + * + * Return: QDF Status + */ +QDF_STATUS sme_set_peer_authorized(uint8_t *peer_addr, + sme_peer_authorized_fp auth_cb, + uint32_t vdev_id) +{ + void *wma_handle; + + wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma_handle) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "wma handle is NULL"); + return QDF_STATUS_E_FAILURE; + } + + wma_set_peer_authorized_cb(wma_handle, auth_cb); + return wma_set_peer_param(wma_handle, peer_addr, WMI_PEER_AUTHORIZE, + 1, vdev_id); +} + +/* + * sme_handle_set_fcc_channel() - set spec. tx power for non-fcc channel + * @hal: HAL pointer + * @fcc_constraint: flag to enable/disable the constraint + * @scan_pending: whether there is pending scan + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_handle_set_fcc_channel(tHalHandle hal, bool fcc_constraint, + bool scan_pending) +{ + QDF_STATUS status; + tpAniSirGlobal mac_ptr = PMAC_STRUCT(hal); + + status = sme_acquire_global_lock(&mac_ptr->sme); + + if (QDF_STATUS_SUCCESS == status) { + + if (fcc_constraint != mac_ptr->scan.fcc_constraint) { + mac_ptr->scan.fcc_constraint = fcc_constraint; + if (scan_pending) + mac_ptr->scan.defer_update_channel_list = true; + else + status = csr_update_channel_list(mac_ptr); + } + + sme_release_global_lock(&mac_ptr->sme); + } + + return status; +} +/** + * sme_setdef_dot11mode() - Updates pMac with default dot11mode + * @hal: Global MAC pointer + * + * Return: NULL. + */ +void sme_setdef_dot11mode(tHalHandle hal) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + csr_set_default_dot11_mode(mac_ctx); +} + +/** + * sme_update_roam_scan_hi_rssi_scan_params() - update high rssi scan + * params + * @hal_handle - The handle returned by macOpen. + * @session_id - Session Identifier + * @notify_id - Identifies 1 of the 4 parameters to be modified + * @val New value of the parameter + * + * Return: QDF_STATUS - SME update config successful. + * Other status means SME failed to update + */ + +QDF_STATUS sme_update_roam_scan_hi_rssi_scan_params(tHalHandle hal_handle, + uint8_t session_id, + uint32_t notify_id, + int32_t val) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal_handle); + QDF_STATUS status = QDF_STATUS_SUCCESS; + tCsrNeighborRoamConfig *nr_config = NULL; + tpCsrNeighborRoamControlInfo nr_info = NULL; + uint32_t reason = 0; + + if (session_id >= CSR_ROAM_SESSION_MAX) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Invalid sme session id: %d"), session_id); + return QDF_STATUS_E_INVAL; + } + + status = sme_acquire_global_lock(&mac_ctx->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + nr_config = &mac_ctx->roam.configParam.neighborRoamConfig; + nr_info = &mac_ctx->roam.neighborRoamInfo[session_id]; + switch (notify_id) { + case eCSR_HI_RSSI_SCAN_MAXCOUNT_ID: + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO, + "%s: gRoamScanHirssiMaxCount %d => %d", + __func__, nr_config->nhi_rssi_scan_max_count, + val); + nr_config->nhi_rssi_scan_max_count = val; + nr_info->cfgParams.hi_rssi_scan_max_count = val; + reason = REASON_ROAM_SCAN_HI_RSSI_MAXCOUNT_CHANGED; + break; + + case eCSR_HI_RSSI_SCAN_RSSI_DELTA_ID: + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO, + FL("gRoamScanHiRssiDelta %d => %d"), + nr_config->nhi_rssi_scan_rssi_delta, + val); + nr_config->nhi_rssi_scan_rssi_delta = val; + nr_info->cfgParams.hi_rssi_scan_rssi_delta = val; + reason = REASON_ROAM_SCAN_HI_RSSI_DELTA_CHANGED; + break; + + case eCSR_HI_RSSI_SCAN_DELAY_ID: + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO, + FL("gRoamScanHiRssiDelay %d => %d"), + nr_config->nhi_rssi_scan_delay, + val); + nr_config->nhi_rssi_scan_delay = val; + nr_info->cfgParams.hi_rssi_scan_delay = val; + reason = REASON_ROAM_SCAN_HI_RSSI_DELAY_CHANGED; + break; + + case eCSR_HI_RSSI_SCAN_RSSI_UB_ID: + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO, + FL("gRoamScanHiRssiUpperBound %d => %d"), + nr_config->nhi_rssi_scan_rssi_ub, + val); + nr_config->nhi_rssi_scan_rssi_ub = val; + nr_info->cfgParams.hi_rssi_scan_rssi_ub = val; + reason = REASON_ROAM_SCAN_HI_RSSI_UB_CHANGED; + break; + + default: + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO, + FL("invalid parameter notify_id %d"), + notify_id); + status = QDF_STATUS_E_INVAL; + break; + } + sme_release_global_lock(&mac_ctx->sme); + } + if (mac_ctx->roam.configParam.isRoamOffloadScanEnabled && + status == QDF_STATUS_SUCCESS) { + csr_roam_offload_scan(mac_ctx, session_id, + ROAM_SCAN_OFFLOAD_UPDATE_CFG, reason); + } + + return status; +} + +/** + * sme_update_tgt_services() - update the target services config. + * @hal: HAL pointer. + * @cfg: wma_tgt_services parameters. + * + * update the target services config. + * + * Return: None. + */ +void sme_update_tgt_services(tHalHandle hal, struct wma_tgt_services *cfg) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + + mac_ctx->lteCoexAntShare = cfg->lte_coex_ant_share; + mac_ctx->beacon_offload = cfg->beacon_offload; + mac_ctx->pmf_offload = cfg->pmf_offload; + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO, + FL("mac_ctx->pmf_offload: %d"), mac_ctx->pmf_offload); + + return; +} + +/** + * sme_is_session_id_valid() - Check if the session id is valid + * @hal: Pointer to HAL + * @session_id: Session id + * + * Checks if the session id is valid or not + * + * Return: True is the session id is valid, false otherwise + */ +bool sme_is_session_id_valid(tHalHandle hal, uint32_t session_id) +{ + tpAniSirGlobal mac = PMAC_STRUCT(hal); + if (!mac) { + /* Using QDF_TRACE since mac is not available for sms_log */ + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: null mac pointer", __func__); + return false; + } + + if (CSR_IS_SESSION_VALID(mac, session_id)) { + return true; + } else { + sms_log(mac, LOGE, + FL("invalid session id:%d"), session_id); + return false; + } +} + +#ifdef FEATURE_WLAN_TDLS + +/** + * sme_get_opclass() - determine operating class + * @hal: Pointer to HAL + * @channel: channel id + * @bw_offset: bandwidth offset + * @opclass: pointer to operating class + * + * Function will determine operating class from regdm_get_opclass_from_channel + * + * Return: none + */ +void sme_get_opclass(tHalHandle hal, uint8_t channel, uint8_t bw_offset, + uint8_t *opclass) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + + /* redgm opclass table contains opclass for 40MHz low primary, + * 40MHz high primary and 20MHz. No support for 80MHz yet. So + * first we will check if bit for 40MHz is set and if so find + * matching opclass either with low primary or high primary + * (a channel would never be in both) and then search for opclass + * matching 20MHz, else for any BW. + */ + if (bw_offset & (1 << BW_40_OFFSET_BIT)) { + *opclass = cds_reg_dmn_get_opclass_from_channel( + mac_ctx->scan.countryCodeCurrent, + channel, BW40_LOW_PRIMARY); + if (!(*opclass)) { + *opclass = cds_reg_dmn_get_opclass_from_channel( + mac_ctx->scan.countryCodeCurrent, + channel, BW40_HIGH_PRIMARY); + } + } else if (bw_offset & (1 << BW_20_OFFSET_BIT)) { + *opclass = cds_reg_dmn_get_opclass_from_channel( + mac_ctx->scan.countryCodeCurrent, + channel, BW20); + } else { + *opclass = cds_reg_dmn_get_opclass_from_channel( + mac_ctx->scan.countryCodeCurrent, + channel, BWALL); + } +} +#endif + +#ifdef FEATURE_GREEN_AP +/** + * sme_send_egap_conf_params() - set the enhanced green ap configuration params + * @enable: enable/disable the enhanced green ap feature + * @inactivity_time: inactivity timeout value + * @wait_time: wait timeout value + * @flag: feature flag in bitmasp + * + * Return: Return QDF_STATUS, otherwise appropriate failure code + */ +QDF_STATUS sme_send_egap_conf_params(uint32_t enable, uint32_t inactivity_time, + uint32_t wait_time, uint32_t flags) +{ + cds_msg_t message; + QDF_STATUS status; + struct egap_conf_params *egap_params; + + egap_params = qdf_mem_malloc(sizeof(*egap_params)); + if (NULL == egap_params) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: fail to alloc egap_params", __func__); + return QDF_STATUS_E_NOMEM; + } + + egap_params->enable = enable; + egap_params->inactivity_time = inactivity_time; + egap_params->wait_time = wait_time; + egap_params->flags = flags; + + message.type = WMA_SET_EGAP_CONF_PARAMS; + message.bodyptr = egap_params; + status = cds_mq_post_message(QDF_MODULE_ID_WMA, &message); + if (!QDF_IS_STATUS_SUCCESS(status)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Not able to post msg to WMA!", __func__); + + qdf_mem_free(egap_params); + } + return status; +} +#endif + +/** + * sme_set_fw_test() - set fw test + * @fw_test: fw test param + * + * Return: Return QDF_STATUS, otherwise appropriate failure code + */ +QDF_STATUS sme_set_fw_test(struct set_fwtest_params *fw_test) +{ + void *wma_handle; + + wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma_handle) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "wma handle is NULL"); + return QDF_STATUS_E_FAILURE; + } + wma_process_fw_test_cmd(wma_handle, fw_test); + return QDF_STATUS_SUCCESS; +} + +/** + * sme_ht40_stop_obss_scan() - ht40 obss stop scan + * @hal: mac handel + * @vdev_id: vdev identifier + * + * Return: Return QDF_STATUS, otherwise appropriate failure code + */ +QDF_STATUS sme_ht40_stop_obss_scan(tHalHandle hal, uint32_t vdev_id) +{ + void *wma_handle; + + wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma_handle) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "wma handle is NULL"); + return QDF_STATUS_E_FAILURE; + } + wma_ht40_stop_obss_scan(wma_handle, vdev_id); + return QDF_STATUS_SUCCESS; +} + +/** + * sme_update_mimo_power_save() - Update MIMO power save + * configuration + * @hal: The handle returned by macOpen + * @is_ht_smps_enabled: enable/disable ht smps + * @ht_smps_mode: smps mode disabled/static/dynamic + * @send_smps_action: flag to send smps force mode command + * to FW + * + * Return: QDF_STATUS if SME update mimo power save + * configuration sucsess else failue status + */ +QDF_STATUS sme_update_mimo_power_save(tHalHandle hal, + uint8_t is_ht_smps_enabled, + uint8_t ht_smps_mode, + bool send_smps_action) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + + sms_log(mac_ctx, LOG1, + "SMPS enable: %d mode: %d send action: %d", + is_ht_smps_enabled, ht_smps_mode, + send_smps_action); + mac_ctx->roam.configParam.enableHtSmps = + is_ht_smps_enabled; + mac_ctx->roam.configParam.htSmps = ht_smps_mode; + mac_ctx->roam.configParam.send_smps_action = + send_smps_action; + + return QDF_STATUS_SUCCESS; +} + +/** + * sme_is_sta_smps_allowed() - check if the supported nss for + * the session is greater than 1x1 to enable sta SMPS + * @hal: The handle returned by macOpen + * @session_id: session id + * + * Return: bool returns true if supported nss is greater than + * 1x1 else false + */ +bool sme_is_sta_smps_allowed(tHalHandle hal, uint8_t session_id) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + tCsrRoamSession *csr_session; + + csr_session = CSR_GET_SESSION(mac_ctx, session_id); + if (NULL == csr_session) { + sms_log(mac_ctx, LOGE, + FL("SME session not valid: %d"), session_id); + return false; + } + + if (!CSR_IS_SESSION_VALID(mac_ctx, session_id)) { + sms_log(mac_ctx, LOGE, + FL("CSR session not valid: %d"), session_id); + return false; + } + + return (csr_session->supported_nss_1x1 == true) ? false : true; +} + +/** + * sme_add_beacon_filter() - set the beacon filter configuration + * @hal: The handle returned by macOpen + * @session_id: session id + * @ie_map: bitwise array of IEs + * + * Return: Return QDF_STATUS, otherwise appropriate failure code + */ +QDF_STATUS sme_add_beacon_filter(tHalHandle hal, + uint32_t session_id, + uint32_t *ie_map) +{ + cds_msg_t message; + QDF_STATUS qdf_status; + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + struct beacon_filter_param *filter_param; + + if (!CSR_IS_SESSION_VALID(mac_ctx, session_id)) { + sms_log(mac_ctx, LOGE, + "CSR session not valid: %d", + session_id); + return QDF_STATUS_E_FAILURE; + } + + filter_param = qdf_mem_malloc(sizeof(*filter_param)); + if (NULL == filter_param) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: fail to alloc filter_param", __func__); + return QDF_STATUS_E_FAILURE; + } + + filter_param->vdev_id = session_id; + + qdf_mem_copy(filter_param->ie_map, ie_map, + BCN_FLT_MAX_ELEMS_IE_LIST * sizeof(uint32_t)); + + message.type = WMA_ADD_BCN_FILTER_CMDID; + message.bodyptr = filter_param; + qdf_status = cds_mq_post_message(QDF_MODULE_ID_WMA, + &message); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Not able to post msg to WDA!", + __func__); + + qdf_mem_free(filter_param); + } + return qdf_status; +} + +/** + * sme_remove_beacon_filter() - set the beacon filter configuration + * @hal: The handle returned by macOpen + * @session_id: session id + * + * Return: Return QDF_STATUS, otherwise appropriate failure code + */ +QDF_STATUS sme_remove_beacon_filter(tHalHandle hal, uint32_t session_id) +{ + cds_msg_t message; + QDF_STATUS qdf_status; + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + struct beacon_filter_param *filter_param; + + if (!CSR_IS_SESSION_VALID(mac_ctx, session_id)) { + sms_log(mac_ctx, LOGE, + "CSR session not valid: %d", + session_id); + return QDF_STATUS_E_FAILURE; + } + + filter_param = qdf_mem_malloc(sizeof(*filter_param)); + if (NULL == filter_param) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: fail to alloc filter_param", __func__); + return QDF_STATUS_E_FAILURE; + } + + filter_param->vdev_id = session_id; + + message.type = WMA_REMOVE_BCN_FILTER_CMDID; + message.bodyptr = filter_param; + qdf_status = cds_mq_post_message(QDF_MODULE_ID_WMA, + &message); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Not able to post msg to WDA!", + __func__); + + qdf_mem_free(filter_param); + } + return qdf_status; +} + +/** + * sme_send_disassoc_req_frame - send disassoc req + * @hal: handler to hal + * @session_id: session id + * @peer_mac: peer mac address + * @reason: reason for disassociation + * wait_for_ack: wait for acknowledgment + * + * function to send disassoc request to lim + * + * return: none + */ +void sme_send_disassoc_req_frame(tHalHandle hal, uint8_t session_id, + uint8_t *peer_mac, uint16_t reason, uint8_t wait_for_ack) +{ + struct sme_send_disassoc_frm_req *msg; + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + A_UINT8 *buf; + A_UINT16 tmp; + + msg = qdf_mem_malloc(sizeof(struct sme_send_disassoc_frm_req)); + + if (NULL == msg) + qdf_status = QDF_STATUS_E_FAILURE; + else + qdf_status = QDF_STATUS_SUCCESS; + + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) + return; + + msg->msg_type = (uint16_t) eWNI_SME_SEND_DISASSOC_FRAME; + + msg->length = (uint16_t) sizeof(struct sme_send_disassoc_frm_req); + + buf = &msg->session_id; + + /* session id */ + *buf = (A_UINT8) session_id; + buf += sizeof(A_UINT8); + + /* transaction id */ + *buf = 0; + *(buf + 1) = 0; + buf += sizeof(A_UINT16); + + /* Set the peer MAC address before sending the message to LIM */ + qdf_mem_copy(buf, peer_mac, QDF_MAC_ADDR_SIZE); + + buf += QDF_MAC_ADDR_SIZE; + + /* reasoncode */ + tmp = (uint16_t) reason; + qdf_mem_copy(buf, &tmp, sizeof(uint16_t)); + buf += sizeof(uint16_t); + + *buf = wait_for_ack; + buf += sizeof(uint8_t); + + qdf_status = cds_send_mb_message_to_mac(msg); + + if (qdf_status != QDF_STATUS_SUCCESS) + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("cds_send_mb_message Failed")); +} + +/** + * sme_get_bpf_offload_capabilities() - Get length for BPF offload + * @hal: Global HAL handle + * This function constructs the cds message and fill in message type, + * post the same to WDA. + * Return: QDF_STATUS enumeration + */ +QDF_STATUS sme_get_bpf_offload_capabilities(tHalHandle hal) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + cds_msg_t cds_msg; + + sms_log(mac_ctx, LOG1, FL("enter")); + + status = sme_acquire_global_lock(&mac_ctx->sme); + if (QDF_STATUS_SUCCESS == status) { + /* Serialize the req through MC thread */ + cds_msg.bodyptr = NULL; + cds_msg.type = WDA_BPF_GET_CAPABILITIES_REQ; + status = cds_mq_post_message(QDF_MODULE_ID_WMA, &cds_msg); + if (!QDF_IS_STATUS_SUCCESS(status)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Post bpf get offload msg fail")); + status = QDF_STATUS_E_FAILURE; + } + sme_release_global_lock(&mac_ctx->sme); + } else { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("sme_acquire_global_lock error")); + } + sms_log(mac_ctx, LOG1, FL("exit")); + return status; +} + + +/** + * sme_set_bpf_instructions() - Set BPF bpf filter instructions. + * @hal: HAL handle + * @bpf_set_offload: struct to set bpf filter instructions. + * + * Return: QDF_STATUS enumeration. + */ +QDF_STATUS sme_set_bpf_instructions(tHalHandle hal, + struct sir_bpf_set_offload *req) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + cds_msg_t cds_msg; + struct sir_bpf_set_offload *set_offload; + + set_offload = qdf_mem_malloc(sizeof(*set_offload) + + req->current_length); + + if (NULL == set_offload) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Failed to alloc set_offload")); + return QDF_STATUS_E_NOMEM; + } + + set_offload->session_id = req->session_id; + set_offload->filter_id = req->filter_id; + set_offload->current_offset = req->current_offset; + set_offload->total_length = req->total_length; + set_offload->current_length = req->current_length; + if (set_offload->total_length) { + set_offload->program = ((uint8_t *)set_offload) + + sizeof(*set_offload); + qdf_mem_copy(set_offload->program, req->program, + set_offload->current_length); + } + status = sme_acquire_global_lock(&mac_ctx->sme); + if (QDF_STATUS_SUCCESS == status) { + /* Serialize the req through MC thread */ + cds_msg.bodyptr = set_offload; + cds_msg.type = WDA_BPF_SET_INSTRUCTIONS_REQ; + status = cds_mq_post_message(QDF_MODULE_ID_WMA, &cds_msg); + + if (!QDF_IS_STATUS_SUCCESS(status)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Post BPF set offload msg fail")); + status = QDF_STATUS_E_FAILURE; + qdf_mem_free(set_offload); + } + sme_release_global_lock(&mac_ctx->sme); + } else { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("sme_acquire_global_lock failed")); + qdf_mem_free(set_offload); + } + return status; +} + +/** + * sme_bpf_offload_register_callback() - Register get bpf offload callbacK + * + * @hal - MAC global handle + * @callback_routine - callback routine from HDD + * + * This API is invoked by HDD to register its callback in SME + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_bpf_offload_register_callback(tHalHandle hal, + void (*pbpf_get_offload_cb)(void *context, + struct sir_bpf_get_offload *)) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpAniSirGlobal mac = PMAC_STRUCT(hal); + + status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + mac->sme.pbpf_get_offload_cb = pbpf_get_offload_cb; + sme_release_global_lock(&mac->sme); + } else { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("sme_acquire_global_lock failed")); + } + return status; +} + +/** + * sme_get_wni_dot11_mode() - return configured wni dot11mode + * @hal: hal pointer + * + * Return: wni dot11 mode. + */ +uint32_t sme_get_wni_dot11_mode(tHalHandle hal) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + + return csr_translate_to_wni_cfg_dot11_mode(mac_ctx, + mac_ctx->roam.configParam.uCfgDot11Mode); +} + +/** + * sme_bpf_offload_deregister_callback() - Register get bpf offload callbacK + * + * @h_hal - MAC global handle + * @callback_routine - callback routine from HDD + * + * This API is invoked by HDD to de-register its callback in SME + * + * Return: QDF_STATUS Enumeration + */ +QDF_STATUS sme_bpf_offload_deregister_callback(tHalHandle h_hal) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpAniSirGlobal mac; + + if (!h_hal) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("hHal is not valid")); + return QDF_STATUS_E_INVAL; + } + + mac = PMAC_STRUCT(h_hal); + + status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + mac->sme.pbpf_get_offload_cb = NULL; + sme_release_global_lock(&mac->sme); + } else { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("sme_acquire_global_lock failed")); + } + return status; +} + + +/** + * sme_create_mon_session() - post message to create PE session for monitormode + * operation + * @hal_handle: Handle to the HAL + * @bssid: pointer to bssid + * + * Return: QDF_STATUS_SUCCESS on success, non-zero error code on failure. + */ +QDF_STATUS sme_create_mon_session(tHalHandle hal_handle, tSirMacAddr bss_id) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + struct sir_create_session *msg; + + msg = qdf_mem_malloc(sizeof(*msg)); + if (NULL != msg) { + msg->type = eWNI_SME_MON_INIT_SESSION; + msg->msg_len = sizeof(*msg); + qdf_mem_copy(msg->bss_id.bytes, bss_id, QDF_MAC_ADDR_SIZE); + status = cds_send_mb_message_to_mac(msg); + } + return status; +} + +/** + * sme_set_adaptive_dwelltime_config() - Update Adaptive dwelltime configuration + * @hal: The handle returned by macOpen + * @params: adaptive_dwelltime_params config + * + * Return: QDF_STATUS if adaptive dwell time update + * configuration sucsess else failure status + */ +QDF_STATUS sme_set_adaptive_dwelltime_config(tHalHandle hal, + struct adaptive_dwelltime_params *params) +{ + cds_msg_t message; + QDF_STATUS status; + struct adaptive_dwelltime_params *dwelltime_params; + + dwelltime_params = qdf_mem_malloc(sizeof(*dwelltime_params)); + if (NULL == dwelltime_params) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: fail to alloc dwelltime_params", __func__); + return QDF_STATUS_E_NOMEM; + } + + dwelltime_params->is_enabled = params->is_enabled; + dwelltime_params->dwelltime_mode = params->dwelltime_mode; + dwelltime_params->lpf_weight = params->lpf_weight; + dwelltime_params->passive_mon_intval = params->passive_mon_intval; + dwelltime_params->wifi_act_threshold = params->wifi_act_threshold; + + message.type = WMA_SET_ADAPT_DWELLTIME_CONF_PARAMS; + message.bodyptr = dwelltime_params; + status = cds_mq_post_message(QDF_MODULE_ID_WMA, &message); + if (!QDF_IS_STATUS_SUCCESS(status)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Not able to post msg to WMA!", __func__); + + qdf_mem_free(dwelltime_params); + } + return status; +} + +/** + * sme_set_vdev_ies_per_band() - sends the per band IEs to vdev + * @hal: Pointer to HAL + * @vdev_id: vdev_id for which IE is targeted + * + * Return: None + */ +void sme_set_vdev_ies_per_band(tHalHandle hal, uint8_t vdev_id) +{ + tpAniSirGlobal p_mac = PMAC_STRUCT(hal); + struct sir_set_vdev_ies_per_band *p_msg; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + + p_msg = qdf_mem_malloc(sizeof(*p_msg)); + if (NULL == p_msg) { + sms_log(p_mac, LOGE, FL("mem alloc failed for sme msg")); + return; + } + + p_msg->vdev_id = vdev_id; + p_msg->msg_type = eWNI_SME_SET_VDEV_IES_PER_BAND; + p_msg->len = sizeof(*p_msg); + sms_log(p_mac, LOG1, + FL("sending eWNI_SME_SET_VDEV_IES_PER_BAND: vdev_id: %d "), + vdev_id); + status = cds_send_mb_message_to_mac(p_msg); + if (QDF_STATUS_SUCCESS != status) + sms_log(p_mac, LOGE, + FL("Send eWNI_SME_SET_VDEV_IES_PER_BAND fail")); +} + +/** + * sme_set_pdev_ht_vht_ies() - sends the set pdev IE req + * @hal: Pointer to HAL + * @enable2x2: 1x1 or 2x2 mode. + * + * Sends the set pdev IE req with Nss value. + * + * Return: None + */ +void sme_set_pdev_ht_vht_ies(tHalHandle hal, bool enable2x2) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + struct sir_set_ht_vht_cfg *ht_vht_cfg; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + + if (!((mac_ctx->roam.configParam.uCfgDot11Mode == + eCSR_CFG_DOT11_MODE_AUTO) || + (mac_ctx->roam.configParam.uCfgDot11Mode == + eCSR_CFG_DOT11_MODE_11N) || + (mac_ctx->roam.configParam.uCfgDot11Mode == + eCSR_CFG_DOT11_MODE_11N_ONLY) || + (mac_ctx->roam.configParam.uCfgDot11Mode == + eCSR_CFG_DOT11_MODE_11AC) || + (mac_ctx->roam.configParam.uCfgDot11Mode == + eCSR_CFG_DOT11_MODE_11AC_ONLY))) + return; + + status = sme_acquire_global_lock(&mac_ctx->sme); + if (QDF_STATUS_SUCCESS == status) { + ht_vht_cfg = qdf_mem_malloc(sizeof(*ht_vht_cfg)); + if (NULL == ht_vht_cfg) { + sms_log(mac_ctx, LOGE, + "%s: mem alloc failed for ht_vht_cfg", + __func__); + sme_release_global_lock(&mac_ctx->sme); + return; + } + + ht_vht_cfg->pdev_id = 0; + if (enable2x2) + ht_vht_cfg->nss = 2; + else + ht_vht_cfg->nss = 1; + ht_vht_cfg->dot11mode = + (uint8_t)csr_translate_to_wni_cfg_dot11_mode(mac_ctx, + mac_ctx->roam.configParam.uCfgDot11Mode); + + ht_vht_cfg->msg_type = eWNI_SME_PDEV_SET_HT_VHT_IE; + ht_vht_cfg->len = sizeof(*ht_vht_cfg); + sms_log(mac_ctx, LOG1, + FL("SET_HT_VHT_IE with nss %d, dot11mode %d"), + ht_vht_cfg->nss, + ht_vht_cfg->dot11mode); + status = cds_send_mb_message_to_mac(ht_vht_cfg); + if (QDF_STATUS_SUCCESS != status) { + sms_log(mac_ctx, LOGE, FL( + "Send SME_PDEV_SET_HT_VHT_IE fail")); + } + sme_release_global_lock(&mac_ctx->sme); + } + return; +} + +/** + * sme_update_vdev_type_nss() - sets the nss per vdev type + * @hal: Pointer to HAL + * @max_supp_nss: max_supported Nss + * @band: 5G or 2.4G band + * + * Sets the per band Nss for each vdev type based on INI and configured + * chain mask value. + * + * Return: None + */ +void sme_update_vdev_type_nss(tHalHandle hal, uint8_t max_supp_nss, + uint32_t vdev_type_nss, eCsrBand band) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + struct vdev_type_nss *vdev_nss; + + if (eCSR_BAND_5G == band) + vdev_nss = &mac_ctx->vdev_type_nss_5g; + else + vdev_nss = &mac_ctx->vdev_type_nss_2g; + + vdev_nss->sta = QDF_MIN(max_supp_nss, CFG_STA_NSS(vdev_type_nss)); + vdev_nss->sap = QDF_MIN(max_supp_nss, CFG_SAP_NSS(vdev_type_nss)); + vdev_nss->p2p_go = QDF_MIN(max_supp_nss, + CFG_P2P_GO_NSS(vdev_type_nss)); + vdev_nss->p2p_cli = QDF_MIN(max_supp_nss, + CFG_P2P_CLI_NSS(vdev_type_nss)); + vdev_nss->p2p_dev = QDF_MIN(max_supp_nss, + CFG_P2P_DEV_NSS(vdev_type_nss)); + vdev_nss->ibss = QDF_MIN(max_supp_nss, CFG_IBSS_NSS(vdev_type_nss)); + vdev_nss->tdls = QDF_MIN(max_supp_nss, CFG_TDLS_NSS(vdev_type_nss)); + vdev_nss->ocb = QDF_MIN(max_supp_nss, CFG_OCB_NSS(vdev_type_nss)); + + sms_log(mac_ctx, LOG1, + "band %d NSS:sta %d sap %d cli %d go %d dev %d ibss %d tdls %d ocb %d", + band, vdev_nss->sta, vdev_nss->sap, vdev_nss->p2p_cli, + vdev_nss->p2p_go, vdev_nss->p2p_dev, vdev_nss->ibss, + vdev_nss->tdls, vdev_nss->ocb); +} + +/** + * sme_update_hw_dbs_capable() - sets the HW DBS capability + * @hal: Pointer to HAL + * @hw_dbs_capable: HW DBS capability + * + * Sets HW DBS capability based on INI and fw capability. + * + * Return: None + */ +void sme_update_hw_dbs_capable(tHalHandle hal, uint8_t hw_dbs_capable) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + mac_ctx->hw_dbs_capable = hw_dbs_capable; +} + +/** + * sme_register_p2p_lo_event() - Register for the p2p lo event + * @hHal: reference to the HAL + * @context: the context of the call + * @callback: the callback to hdd + * + * This function registers the callback function for P2P listen + * offload stop event. + * + * Return: none + */ +void sme_register_p2p_lo_event(tHalHandle hHal, void *context, + p2p_lo_callback callback) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + QDF_STATUS status = QDF_STATUS_E_FAILURE; + + status = sme_acquire_global_lock(&pMac->sme); + pMac->sme.p2p_lo_event_callback = callback; + pMac->sme.p2p_lo_event_context = context; + sme_release_global_lock(&pMac->sme); +} + +/** + * sme_process_mac_pwr_dbg_cmd() - enable mac pwr debugging + * @hal: The handle returned by macOpen + * @session_id: session id + * @dbg_args: args for mac pwr debug command + * Return: Return QDF_STATUS, otherwise appropriate failure code + */ +QDF_STATUS sme_process_mac_pwr_dbg_cmd(tHalHandle hal, uint32_t session_id, + struct sir_mac_pwr_dbg_cmd* + dbg_args) +{ + cds_msg_t message; + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + struct sir_mac_pwr_dbg_cmd *req; + int i; + + if (!CSR_IS_SESSION_VALID(mac_ctx, session_id)) { + sms_log(mac_ctx, LOGE, + "CSR session not valid: %d", + session_id); + return QDF_STATUS_E_FAILURE; + } + + req = qdf_mem_malloc(sizeof(*req)); + if (NULL == req) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: fail to alloc mac_pwr_dbg_args", __func__); + return QDF_STATUS_E_FAILURE; + } + req->module_id = dbg_args->module_id; + req->pdev_id = dbg_args->pdev_id; + req->num_args = dbg_args->num_args; + for (i = 0; i < req->num_args; i++) + req->args[i] = dbg_args->args[i]; + + message.type = SIR_HAL_POWER_DBG_CMD; + message.bodyptr = req; + + if (!QDF_IS_STATUS_SUCCESS(cds_mq_post_message + (QDF_MODULE_ID_WMA, &message))) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Not able to post msg to WDA!", + __func__); + qdf_mem_free(req); + } + return QDF_STATUS_SUCCESS; +} +/** + * sme_get_vdev_type_nss() - gets the nss per vdev type + * @hal: Pointer to HAL + * @dev_mode: connection type. + * @nss2g: Pointer to the 2G Nss parameter. + * @nss5g: Pointer to the 5G Nss parameter. + * + * Fills the 2G and 5G Nss values based on connection type. + * + * Return: None + */ +void sme_get_vdev_type_nss(tHalHandle hal, enum tQDF_ADAPTER_MODE dev_mode, + uint8_t *nss_2g, uint8_t *nss_5g) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + csr_get_vdev_type_nss(mac_ctx, dev_mode, nss_2g, nss_5g); +} + +/** + * sme_update_sta_roam_policy() - update sta roam policy for + * unsafe and DFS channels. + * @hal_handle: hal handle for getting global mac struct + * @dfs_mode: dfs mode which tell if dfs channel needs to be + * skipped or not + * @skip_unsafe_channels: Param to tell if driver needs to + * skip unsafe channels or not. + * @param session_id: sme_session_id + * @sap_operating_band: Band on which SAP is operating + * + * sme_update_sta_roam_policy update sta rome policies to csr + * this function will call csrUpdateChannelList as well + * to include/exclude DFS channels and unsafe channels. + * + * Return: eHAL_STATUS_SUCCESS or non-zero on failure. + */ +QDF_STATUS sme_update_sta_roam_policy(tHalHandle hal_handle, + enum sta_roam_policy_dfs_mode dfs_mode, + bool skip_unsafe_channels, + uint8_t session_id, uint8_t sap_operating_band) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal_handle); + QDF_STATUS status = QDF_STATUS_SUCCESS; + tSmeConfigParams sme_config; + + if (!mac_ctx) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_FATAL, + "%s: mac_ctx is null", __func__); + return QDF_STATUS_E_FAILURE; + } + qdf_mem_zero(&sme_config, sizeof(sme_config)); + sme_get_config_param(hal_handle, &sme_config); + + sme_config.csrConfig.sta_roam_policy_params.dfs_mode = + dfs_mode; + sme_config.csrConfig.sta_roam_policy_params.skip_unsafe_channels = + skip_unsafe_channels; + sme_config.csrConfig.sta_roam_policy_params.sap_operating_band = + sap_operating_band; + + sme_update_config(hal_handle, &sme_config); + + status = csr_update_channel_list(mac_ctx); + if (QDF_STATUS_SUCCESS != status) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("failed to update the supported channel list")); + } + if (mac_ctx->roam.configParam.isRoamOffloadScanEnabled) + csr_roam_offload_scan(mac_ctx, session_id, + ROAM_SCAN_OFFLOAD_UPDATE_CFG, + REASON_ROAM_SCAN_STA_ROAM_POLICY_CHANGED); + return status; +} + +/** + * sme_enable_disable_chanavoidind_event - configure ca event ind + * @hal: handler to hal + * @set_value: enable/disable + * + * function to enable/disable chan avoidance indication + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_enable_disable_chanavoidind_event(tHalHandle hal, + uint8_t set_value) +{ + QDF_STATUS status; + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + cds_msg_t msg; + + sms_log(mac_ctx, LOG1, FL("set_value: %d"), set_value); + status = sme_acquire_global_lock(&mac_ctx->sme); + if (QDF_STATUS_SUCCESS == status) { + qdf_mem_zero(&msg, sizeof(cds_msg_t)); + msg.type = WMA_SEND_FREQ_RANGE_CONTROL_IND; + msg.bodyval = set_value; + status = cds_mq_post_message(QDF_MODULE_ID_WMA, &msg); + sme_release_global_lock(&mac_ctx->sme); + return status; + } + return status; +} + +/* + * sme_set_default_scan_ie() - API to send default scan IE to LIM + * @hal: reference to the HAL + * @session_id: current session ID + * @ie_data: Pointer to Scan IE data + * @ie_len: Length of @ie_data + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_set_default_scan_ie(tHalHandle hal, uint16_t session_id, + uint8_t *ie_data, uint16_t ie_len) +{ + QDF_STATUS status; + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + struct hdd_default_scan_ie *set_ie_params; + + status = sme_acquire_global_lock(&mac_ctx->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + set_ie_params = qdf_mem_malloc(sizeof(*set_ie_params)); + if (!set_ie_params) + status = QDF_STATUS_E_NOMEM; + else { + set_ie_params->message_type = eWNI_SME_DEFAULT_SCAN_IE; + set_ie_params->length = sizeof(*set_ie_params); + set_ie_params->session_id = session_id; + set_ie_params->ie_len = ie_len; + qdf_mem_copy(set_ie_params->ie_data, ie_data, ie_len); + status = cds_send_mb_message_to_mac(set_ie_params); + } + sme_release_global_lock(&mac_ctx->sme); + } + sms_log(mac_ctx, LOG1, FL("Set default scan IE status %d"), status); + return status; +} + +QDF_STATUS sme_set_sar_power_limits(tHalHandle hal, + struct sar_limit_cmd_params *sar_limit_cmd) +{ + void *wma_handle; + + wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma_handle) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "wma handle is NULL"); + return QDF_STATUS_E_FAILURE; + } + + return wma_set_sar_limit(wma_handle, sar_limit_cmd); +} + +#ifdef WLAN_FEATURE_DISA +/** + * sme_encrypt_decrypt_msg() - handles encrypt/decrypt mesaage + * @hal: HAL handle + * @encrypt_decrypt_params: struct to set encryption/decryption params. + * + * Return: QDF_STATUS enumeration. + */ +QDF_STATUS sme_encrypt_decrypt_msg(tHalHandle hal, + struct encrypt_decrypt_req_params *encrypt_decrypt_params) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + cds_msg_t cds_msg; + struct encrypt_decrypt_req_params *params; + uint8_t *ptr; + + ptr = qdf_mem_malloc(sizeof(*params) + + encrypt_decrypt_params->data_len); + if (ptr == NULL) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Failed to alloc memory for encrypt/decrypt params")); + return QDF_STATUS_E_NOMEM; + } + + params = (struct encrypt_decrypt_req_params *)ptr; + + *params = *encrypt_decrypt_params; + + if (params->data_len) { + params->data = ptr + sizeof(*params); + + qdf_mem_copy(params->data, encrypt_decrypt_params->data, + params->data_len); + } + + status = sme_acquire_global_lock(&mac_ctx->sme); + if (status == QDF_STATUS_SUCCESS) { + /* Serialize the req through MC thread */ + cds_msg.bodyptr = params; + cds_msg.type = WMA_ENCRYPT_DECRYPT_MSG; + status = cds_mq_post_message(QDF_MODULE_ID_WMA, &cds_msg); + + if (!QDF_IS_STATUS_SUCCESS(status)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Post encrypt/decrypt msg fail")); + status = QDF_STATUS_E_FAILURE; + qdf_mem_free(params); + } + sme_release_global_lock(&mac_ctx->sme); + } else { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("sme_acquire_global_lock failed")); + qdf_mem_free(params); + } + return status; + +} + +/** + * sme_encrypt_decrypt_msg_register_callback() - Registers + * encrypt/decrypt message callback + * + * @hal - MAC global handle + * @callback_routine - callback routine from HDD + * + * This API is invoked by HDD to register its callback in SME + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_encrypt_decrypt_msg_register_callback(tHalHandle hal, + void (*encrypt_decrypt_cb)(void *hdd_context, + struct sir_encrypt_decrypt_rsp_params + *encrypt_decrypt_rsp_params)) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpAniSirGlobal mac; + + if (!hal) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("hHal is not valid")); + return QDF_STATUS_E_INVAL; + } + + mac = PMAC_STRUCT(hal); + + status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + mac->sme.encrypt_decrypt_cb = encrypt_decrypt_cb; + sme_release_global_lock(&mac->sme); + } else { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("sme_acquire_global_lock failed")); + } + return status; +} + +/** + * sme_encrypt_decrypt_msg_deregister_callback() - Registers + * encrypt/decrypt message callback + * + * @h_hal - MAC global handle + * @callback_routine - callback routine from HDD + * + * This API is invoked by HDD to de-register its callback in SME + * + * Return: QDF_STATUS Enumeration + */ +QDF_STATUS sme_encrypt_decrypt_msg_deregister_callback(tHalHandle h_hal) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpAniSirGlobal mac; + + if (!h_hal) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("hHal is not valid")); + return QDF_STATUS_E_INVAL; + } + + mac = PMAC_STRUCT(h_hal); + + status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + mac->sme.encrypt_decrypt_cb = NULL; + sme_release_global_lock(&mac->sme); + } else { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("sme_acquire_global_lock failed")); + } + return status; +} +#endif + +QDF_STATUS sme_set_cts2self_for_p2p_go(tHalHandle hal_handle) +{ + void *wma_handle; + + wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma_handle) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "wma_handle is NULL"); + return QDF_STATUS_E_FAILURE; + } + if (QDF_STATUS_SUCCESS != + wma_set_cts2self_for_p2p_go(wma_handle, true)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Failed to set cts2self for p2p GO to firmware", + __func__); + return QDF_STATUS_E_FAILURE; + } + return QDF_STATUS_SUCCESS; +} + +/** + * sme_update_tx_fail_cnt_threshold() - update tx fail count Threshold + * @hal: Handle returned by mac_open + * @session_id: Session ID on which tx fail count needs to be updated to FW + * @tx_fail_count: Count for tx fail threshold after which FW will disconnect + * + * This function is used to set tx fail count threshold to firmware. + * firmware will issue disocnnect with peer device once this threshold is + * reached. + * + * Return: Return QDF_STATUS, otherwise appropriate failure code + */ +QDF_STATUS sme_update_tx_fail_cnt_threshold(tHalHandle hal_handle, + uint8_t session_id, uint32_t tx_fail_count) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal_handle); + QDF_STATUS status = QDF_STATUS_E_FAILURE; + struct sme_tx_fail_cnt_threshold *tx_fail_cnt; + cds_msg_t msg; + + tx_fail_cnt = qdf_mem_malloc(sizeof(*tx_fail_cnt)); + if (NULL == tx_fail_cnt) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: fail to alloc filter_param", __func__); + return QDF_STATUS_E_FAILURE; + } + sms_log(mac_ctx, LOG1, + FL("session_id %d tx_fail_count: %d"), + session_id, tx_fail_count); + tx_fail_cnt->session_id = session_id; + tx_fail_cnt->tx_fail_cnt_threshold = tx_fail_count; + + qdf_mem_zero(&msg, sizeof(cds_msg_t)); + msg.type = SIR_HAL_UPDATE_TX_FAIL_CNT_TH; + msg.reserved = 0; + msg.bodyptr = tx_fail_cnt; + status = cds_mq_post_message(QDF_MODULE_ID_WMA, &msg); + + if (!QDF_IS_STATUS_SUCCESS(status)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Not able to post Tx fail count message to WDA")); + qdf_mem_free(tx_fail_cnt); + } + return status; +} + +QDF_STATUS sme_set_lost_link_info_cb(tHalHandle hal, + void (*cb)(void *, struct sir_lost_link_info *)) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpAniSirGlobal mac = PMAC_STRUCT(hal); + + status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + mac->sme.lost_link_info_cb = cb; + sme_release_global_lock(&mac->sme); + sms_log(mac, LOG1, FL("set lost link info callback")); + } else { + sms_log(mac, LOGE, + FL("sme_acquire_global_lock error status %d"), + status); + } + return status; +} +#ifdef FEATURE_WLAN_ESE +bool sme_roam_is_ese_assoc(tCsrRoamInfo *roam_info) +{ + return roam_info->isESEAssoc; +} +#endif +/** + * sme_set_5g_band_pref(): If 5G preference is enabled,set boost/drop + * params from ini. + * @hal_handle: Handle returned by mac_open + * @5g_pref_params: pref params from ini. + * + * Returns: None + */ +void sme_set_5g_band_pref(tHalHandle hal_handle, + struct sme_5g_band_pref_params *pref_params) +{ + + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal_handle); + struct roam_ext_params *roam_params; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + if (!pref_params) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "Invalid 5G pref params!"); + return; + } + status = sme_acquire_global_lock(&mac_ctx->sme); + if (QDF_STATUS_SUCCESS == status) { + roam_params = &mac_ctx->roam.configParam.roam_params; + roam_params->raise_rssi_thresh_5g = + pref_params->rssi_boost_threshold_5g; + roam_params->raise_factor_5g = + pref_params->rssi_boost_factor_5g; + roam_params->max_raise_rssi_5g = + pref_params->max_rssi_boost_5g; + roam_params->drop_rssi_thresh_5g = + pref_params->rssi_penalize_threshold_5g; + roam_params->drop_factor_5g = + pref_params->rssi_penalize_factor_5g; + roam_params->max_drop_rssi_5g = + pref_params->max_rssi_penalize_5g; + + sme_release_global_lock(&mac_ctx->sme); + } else + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "Unable to acquire global sme lock"); +} + + +bool sme_neighbor_roam_is11r_assoc(tHalHandle hal_ctx, + uint8_t session_id) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal_ctx); + return csr_neighbor_roam_is11r_assoc(mac_ctx, session_id); + +} + +#ifdef WLAN_FEATURE_WOW_PULSE +/** + * sme_set_wow_pulse() - set wow pulse info + * @wow_pulse_set_info: wow_pulse_mode structure pointer + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_set_wow_pulse(struct wow_pulse_mode *wow_pulse_set_info) +{ + cds_msg_t message; + QDF_STATUS status; + struct wow_pulse_mode *wow_pulse_set_cmd; + + if (!wow_pulse_set_info) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: invalid wow_pulse_set_info pointer", __func__); + return QDF_STATUS_E_FAILURE; + } + + wow_pulse_set_cmd = qdf_mem_malloc(sizeof(*wow_pulse_set_cmd)); + if (NULL == wow_pulse_set_cmd) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: fail to alloc wow_pulse_set_cmd", __func__); + return QDF_STATUS_E_NOMEM; + } + + *wow_pulse_set_cmd = *wow_pulse_set_info; + + message.type = WMA_SET_WOW_PULSE_CMD; + message.bodyptr = wow_pulse_set_cmd; + + status = cds_mq_post_message(QDF_MODULE_ID_WMA, + &message); + if (!QDF_IS_STATUS_SUCCESS(status)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Not able to post msg to WDA!", + __func__); + qdf_mem_free(wow_pulse_set_cmd); + status = QDF_STATUS_E_FAILURE; + } + + return status; +} +#endif + +#ifdef WLAN_FEATURE_UDP_RESPONSE_OFFLOAD +/** + * sme_set_udp_resp_offload() - set udp response payload. + * @pudp_resp_cmd: specific udp and response udp payload struct pointer + * + * This function set specific udp and response udp payload info + * including enable dest_port,udp_payload, resp_payload. + * + * Return: Return QDF_STATUS. + */ +QDF_STATUS sme_set_udp_resp_offload(struct udp_resp_offload *pudp_resp_cmd) +{ + cds_msg_t message; + QDF_STATUS status; + struct udp_resp_offload *udp_resp_cmd; + + if (!pudp_resp_cmd) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: invalid pudp_resp_cmd pointer", __func__); + return QDF_STATUS_E_FAILURE; + } + + udp_resp_cmd = qdf_mem_malloc(sizeof(*udp_resp_cmd)); + if (NULL == udp_resp_cmd) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: fail to alloc sudp_cmd", __func__); + return QDF_STATUS_E_FAILURE; + } + + *udp_resp_cmd = *pudp_resp_cmd; + + message.type = WDA_SET_UDP_RESP_OFFLOAD; + message.bodyptr = udp_resp_cmd; + + status = cds_mq_post_message(QDF_MODULE_ID_WMA, + &message); + if (!QDF_IS_STATUS_SUCCESS(status)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Not able to post msg to WDA!", + __func__); + qdf_mem_free(udp_resp_cmd); + status = QDF_STATUS_E_FAILURE; + } + + return status; +} + +#endif + +QDF_STATUS sme_get_rcpi(tHalHandle hal, struct sme_rcpi_req *rcpi) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hal); + cds_msg_t cds_msg; + struct sme_rcpi_req *rcpi_req; + + rcpi_req = qdf_mem_malloc(sizeof(*rcpi_req)); + if (rcpi_req == NULL) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Not able to allocate memory for rcpi req", + __func__); + return QDF_STATUS_E_NOMEM; + } + qdf_mem_copy(rcpi_req, rcpi, sizeof(*rcpi_req)); + + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + cds_msg.bodyptr = rcpi_req; + cds_msg.type = WMA_GET_RCPI_REQ; + status = cds_mq_post_message(QDF_MODULE_ID_WMA, &cds_msg); + sme_release_global_lock(&pMac->sme); + if (!QDF_IS_STATUS_SUCCESS(status)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("post get rcpi req failed")); + status = QDF_STATUS_E_FAILURE; + qdf_mem_free(rcpi_req); + } + } else { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("sme_acquire_global_lock failed")); + qdf_mem_free(rcpi_req); + } + return status; +} + +QDF_STATUS sme_rso_cmd_status_cb(tHalHandle hal, + void (*cb)(void *, struct rso_cmd_status *)) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpAniSirGlobal mac = PMAC_STRUCT(hal); + + mac->sme.rso_cmd_status_cb = cb; + sms_log(mac, LOG1, FL("Registered RSO command status callback")); + return status; +} + +/** + * sme_prepare_beacon_from_bss_descp() - prepares beacon frame by populating + * different fields and IEs from bss descriptor. + * @frame_buf: frame buffer to populate + * @bss_descp: bss descriptor + * @bssid: bssid of the beacon frame to populate + * @ie_len: length of IE fields + * + * Return: None + */ +static void sme_prepare_beacon_from_bss_descp(uint8_t *frame_buf, + tSirBssDescription *bss_descp, + const tSirMacAddr bssid, + uint32_t ie_len) +{ + tDot11fBeacon1 *bcn_fixed; + tpSirMacMgmtHdr mac_hdr = (tpSirMacMgmtHdr)frame_buf; + + /* populate mac header first to indicate beacon */ + mac_hdr->fc.protVer = SIR_MAC_PROTOCOL_VERSION; + mac_hdr->fc.type = SIR_MAC_MGMT_FRAME; + mac_hdr->fc.subType = SIR_MAC_MGMT_BEACON; + qdf_mem_copy((uint8_t *) mac_hdr->da, + (uint8_t *) "\xFF\xFF\xFF\xFF\xFF\xFF", + sizeof(struct qdf_mac_addr)); + qdf_mem_copy((uint8_t *) mac_hdr->sa, bssid, + sizeof(struct qdf_mac_addr)); + qdf_mem_copy((uint8_t *) mac_hdr->bssId, bssid, + sizeof(struct qdf_mac_addr)); + + /* now populate fixed params */ + bcn_fixed = (tDot11fBeacon1 *)(frame_buf + SIR_MAC_HDR_LEN_3A); + /* populate timestamp */ + qdf_mem_copy(&bcn_fixed->TimeStamp.timestamp, &bss_descp->timeStamp, + sizeof(bss_descp->timeStamp)); + /* populate beacon interval */ + bcn_fixed->BeaconInterval.interval = bss_descp->beaconInterval; + /* populate capability */ + qdf_mem_copy(&bcn_fixed->Capabilities, &bss_descp->capabilityInfo, + sizeof(bss_descp->capabilityInfo)); + + /* copy IEs now */ + qdf_mem_copy(frame_buf + SIR_MAC_HDR_LEN_3A + + SIR_MAC_B_PR_SSID_OFFSET, + &bss_descp->ieFields, ie_len); +} + +QDF_STATUS sme_get_rssi_snr_by_bssid(tHalHandle hal, + tCsrRoamProfile *profile, + const uint8_t *bssid, + int8_t *rssi, int8_t *snr) +{ + tSirBssDescription *bss_descp; + tCsrScanResultFilter *scan_filter; + struct scan_result_list *bss_list; + tScanResultHandle result_handle = NULL; + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + + scan_filter = qdf_mem_malloc(sizeof(tCsrScanResultFilter)); + if (NULL == scan_filter) { + sme_err("memory allocation failed"); + status = QDF_STATUS_E_NOMEM; + goto free_scan_flter; + } + + status = csr_roam_prepare_filter_from_profile(mac_ctx, + profile, scan_filter); + if (QDF_STATUS_SUCCESS != status) { + sme_err("prepare_filter failed"); + goto free_scan_flter; + } + + /* update filter to get scan result with just target BSSID */ + if (NULL == scan_filter->BSSIDs.bssid) { + scan_filter->BSSIDs.bssid = + qdf_mem_malloc(sizeof(struct qdf_mac_addr)); + if (scan_filter->BSSIDs.bssid == NULL) { + sme_err("malloc failed"); + status = QDF_STATUS_E_NOMEM; + goto free_scan_flter; + } + } + + scan_filter->BSSIDs.numOfBSSIDs = 1; + qdf_mem_copy(scan_filter->BSSIDs.bssid[0].bytes, + bssid, sizeof(struct qdf_mac_addr)); + + status = csr_scan_get_result(mac_ctx, scan_filter, &result_handle); + if (QDF_STATUS_SUCCESS != status) { + sme_err("parse_scan_result failed"); + goto free_scan_flter; + } + + bss_list = (struct scan_result_list *)result_handle; + bss_descp = csr_get_fst_bssdescr_ptr(bss_list); + if (!bss_descp) { + sme_err("unable to fetch bss descriptor"); + status = QDF_STATUS_E_FAULT; + goto free_scan_flter; + } + + sms_log(mac_ctx, LOGE, "snr: %d, rssi: %d, raw_rssi: %d", + bss_descp->sinr, bss_descp->rssi, bss_descp->rssi_raw); + + if (rssi) + *rssi = bss_descp->rssi; + if (snr) + *snr = bss_descp->sinr; + +free_scan_flter: + /* free scan filter and exit */ + if (scan_filter) { + csr_free_scan_filter(mac_ctx, scan_filter); + qdf_mem_free(scan_filter); + } + + if (result_handle) + csr_scan_result_purge(mac_ctx, result_handle); + + return status; +} + +QDF_STATUS sme_get_beacon_frm(tHalHandle hal, tCsrRoamProfile *profile, + const tSirMacAddr bssid, + uint8_t **frame_buf, uint32_t *frame_len) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tScanResultHandle result_handle = NULL; + tCsrScanResultFilter *scan_filter; + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + tSirBssDescription *bss_descp; + tScanResultList *bss_list; + uint32_t ie_len; + + scan_filter = qdf_mem_malloc(sizeof(tCsrScanResultFilter)); + if (NULL == scan_filter) { + sms_log(mac_ctx, LOGE, FL("memory allocation failed")); + status = QDF_STATUS_E_NOMEM; + goto free_scan_flter; + } + status = csr_roam_prepare_filter_from_profile(mac_ctx, + profile, scan_filter); + if (QDF_STATUS_SUCCESS != status) { + sms_log(mac_ctx, LOGE, FL("prepare_filter failed")); + goto free_scan_flter; + } + + /* update filter to get scan result with just target BSSID */ + if (NULL == scan_filter->BSSIDs.bssid) { + scan_filter->BSSIDs.bssid = + qdf_mem_malloc(sizeof(struct qdf_mac_addr)); + if (scan_filter->BSSIDs.bssid == NULL) { + sms_log(mac_ctx, LOGE, FL("malloc failed")); + status = QDF_STATUS_E_NOMEM; + goto free_scan_flter; + } + } + scan_filter->BSSIDs.numOfBSSIDs = 1; + qdf_mem_copy(scan_filter->BSSIDs.bssid[0].bytes, + bssid, sizeof(struct qdf_mac_addr)); + + status = csr_scan_get_result(mac_ctx, scan_filter, &result_handle); + if (QDF_STATUS_SUCCESS != status) { + sms_log(mac_ctx, LOGE, FL("parse_scan_result failed")); + goto free_scan_flter; + } + + bss_list = (tScanResultList *)result_handle; + bss_descp = csr_get_fst_bssdescr_ptr(bss_list); + if (!bss_descp) { + sms_log(mac_ctx, LOGE, FL("unable to fetch bss descriptor")); + status = QDF_STATUS_E_FAULT; + goto free_scan_flter; + } + + /** + * Length of BSS descriptor is without length of + * length itself and length of pointer that holds ieFields. + * + * tSirBssDescription + * +--------+---------------------------------+---------------+ + * | length | other fields | pointer to IEs| + * +--------+---------------------------------+---------------+ + * ^ + * ieFields + */ + ie_len = bss_descp->length + sizeof(bss_descp->length) + - (uint16_t)(offsetof(tSirBssDescription, ieFields[0])); + sms_log(mac_ctx, LOG1, FL("found bss_descriptor ie_len: %d"), + ie_len); + + /* include mac header and fixed params along with IEs in frame */ + *frame_len = SIR_MAC_HDR_LEN_3A + SIR_MAC_B_PR_SSID_OFFSET + ie_len; + *frame_buf = qdf_mem_malloc(*frame_len); + if (NULL == *frame_buf) { + sms_log(mac_ctx, LOGE, FL("memory allocation failed")); + status = QDF_STATUS_E_NOMEM; + goto free_scan_flter; + } + qdf_mem_zero(*frame_buf, *frame_len); + sme_prepare_beacon_from_bss_descp(*frame_buf, bss_descp, bssid, ie_len); + +free_scan_flter: + /* free scan filter and exit */ + if (scan_filter) { + csr_free_scan_filter(mac_ctx, scan_filter); + qdf_mem_free(scan_filter); + } + if (result_handle) + csr_scan_result_purge(mac_ctx, result_handle); + + return status; +} + +/* ARP DEBUG STATS */ + +/** + * sme_set_nud_debug_stats() - sme api to set nud debug stats + * @hal: handle to hal + * @set_stats_param: pointer to set stats param + * + * Return: Return QDF_STATUS. + */ +QDF_STATUS sme_set_nud_debug_stats(tHalHandle hal, + struct set_arp_stats_params + *set_stats_param) +{ + struct set_arp_stats_params *arp_set_param; + cds_msg_t msg; + + arp_set_param = qdf_mem_malloc(sizeof(*arp_set_param)); + if (arp_set_param == NULL) { + hdd_err("Memory allocation failure"); + return QDF_STATUS_E_NOMEM; + } + + qdf_mem_copy(arp_set_param, set_stats_param, sizeof(*arp_set_param)); + + msg.type = WMA_SET_ARP_STATS_REQ; + msg.reserved = 0; + msg.bodyptr = arp_set_param; + + if (QDF_STATUS_SUCCESS != + cds_mq_post_message(QDF_MODULE_ID_WMA, &msg)) { + hdd_err("Not able to post message to WDA"); + qdf_mem_free(arp_set_param); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * sme_get_nud_debug_stats() - sme api to get nud debug stats + * @hal: handle to hal + * @get_stats_param: pointer to set stats param + * + * Return: Return QDF_STATUS. + */ +QDF_STATUS sme_get_nud_debug_stats(tHalHandle hal, + struct get_arp_stats_params + *get_stats_param) +{ + struct get_arp_stats_params *arp_get_param; + cds_msg_t msg; + + arp_get_param = qdf_mem_malloc(sizeof(*arp_get_param)); + if (arp_get_param == NULL) { + hdd_err("Memory allocation failure"); + return QDF_STATUS_E_NOMEM; + } + + qdf_mem_copy(arp_get_param, get_stats_param, sizeof(*arp_get_param)); + + msg.type = WMA_GET_ARP_STATS_REQ; + msg.reserved = 0; + msg.bodyptr = arp_get_param; + + if (QDF_STATUS_SUCCESS != + cds_mq_post_message(QDF_MODULE_ID_WMA, &msg)) { + hdd_err("Not able to post message to WDA"); + qdf_mem_free(arp_get_param); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * sme_delete_all_tdls_peers(): send request to delete tdls peers + * @hal: handler for HAL + * @session_id: session id + * + * This function sends request to lim to delete tdls peers + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_delete_all_tdls_peers(tHalHandle hal, uint8_t session_id) +{ + struct sir_del_all_tdls_peers *msg; + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpAniSirGlobal p_mac = PMAC_STRUCT(hal); + tCsrRoamSession *session = CSR_GET_SESSION(p_mac, session_id); + + msg = qdf_mem_malloc(sizeof(*msg)); + if (NULL == msg) { + sms_log(p_mac, LOGE, FL("memory alloc failed")); + return QDF_STATUS_E_FAILURE; + } + + qdf_mem_zero(msg, sizeof(*msg)); + + msg->msg_type = eWNI_SME_DEL_ALL_TDLS_PEERS; + msg->msg_len = (uint16_t) sizeof(*msg); + + qdf_mem_copy(msg->bssid.bytes, session->connectedProfile.bssid.bytes, + sizeof(struct qdf_mac_addr)); + + status = cds_send_mb_message_to_mac(msg); + + if (status != QDF_STATUS_SUCCESS) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("cds_send_mb_message_to_mac Failed")); + status = QDF_STATUS_E_FAILURE; + } + + return status; +} + +QDF_STATUS sme_process_msg_callback(tHalHandle hal, cds_msg_t *msg) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + + if (msg == NULL) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Empty message for SME Msg callback")); + return status; + } + status = sme_process_msg(hal, msg); + return status; +} + +QDF_STATUS sme_congestion_register_callback(tHalHandle hal, + void (*congestion_cb)(void *, uint32_t congestion, uint32_t vdev_id)) +{ + QDF_STATUS status; + tpAniSirGlobal mac = PMAC_STRUCT(hal); + + status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + mac->sme.congestion_cb = congestion_cb; + sme_release_global_lock(&mac->sme); + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO, + FL("congestion callback set")); + } else { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("sme_acquire_global_lock failed %d"), status); + } + + return status; +} + +QDF_STATUS sme_ipa_uc_stat_request(tHalHandle hal, uint32_t vdev_id, + uint32_t param_id, uint32_t param_val, uint32_t req_cat) +{ + wma_cli_set_cmd_t *iwcmd; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + iwcmd = qdf_mem_malloc(sizeof(*iwcmd)); + if (!iwcmd) { + sme_err("Failed alloc memory for iwcmd"); + return QDF_STATUS_E_NOMEM; + } + + qdf_mem_zero(iwcmd, sizeof(*iwcmd)); + iwcmd->param_sec_value = 0; + iwcmd->param_vdev_id = vdev_id; + iwcmd->param_id = param_id; + iwcmd->param_vp_dev = req_cat; + iwcmd->param_value = param_val; + + wma_ipa_uc_stat_request(iwcmd); + qdf_mem_free(iwcmd); + + return status; +} + +int sme_cli_set_command(int vdev_id, int param_id, int sval, int vpdev) +{ + return wma_cli_set_command(vdev_id, param_id, sval, vpdev); +} diff --git a/drivers/staging/qcacld-3.0/core/sme/src/common/sme_ft_api.c b/drivers/staging/qcacld-3.0/core/sme/src/common/sme_ft_api.c new file mode 100644 index 0000000000000000000000000000000000000000..48421fb273916bc5ee6fcfed9a49fbf5f6e0bc9c --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/sme/src/common/sme_ft_api.c @@ -0,0 +1,565 @@ +/* + * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#include +#include +#include + +/*-------------------------------------------------------------------------- + Initialize the FT context. + ------------------------------------------------------------------------*/ +void sme_ft_open(tHalHandle hHal, uint32_t sessionId) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + QDF_STATUS status = QDF_STATUS_SUCCESS; + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + + if (NULL != pSession) { + /* Clean up the context */ + qdf_mem_set(&pSession->ftSmeContext, sizeof(tftSMEContext), 0); + + pSession->ftSmeContext.pUsrCtx = + qdf_mem_malloc(sizeof(tFTRoamCallbackUsrCtx)); + + if (NULL == pSession->ftSmeContext.pUsrCtx) { + sms_log(pMac, LOGE, FL("Memory allocation failure")); + return; + } + pSession->ftSmeContext.pUsrCtx->pMac = pMac; + pSession->ftSmeContext.pUsrCtx->sessionId = sessionId; + + status = + qdf_mc_timer_init(&pSession->ftSmeContext. + preAuthReassocIntvlTimer, + QDF_TIMER_TYPE_SW, + sme_preauth_reassoc_intvl_timer_callback, + (void *)pSession->ftSmeContext.pUsrCtx); + + if (QDF_STATUS_SUCCESS != status) { + sms_log(pMac, LOGE, + FL + ("Preauth Reassoc interval Timer allocation failed")); + qdf_mem_free(pSession->ftSmeContext.pUsrCtx); + pSession->ftSmeContext.pUsrCtx = NULL; + return; + } + } +} + +/*-------------------------------------------------------------------------- + Cleanup the SME FT Global context. + ------------------------------------------------------------------------*/ +void sme_ft_close(tHalHandle hHal, uint32_t sessionId) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + tCsrRoamSession *pSession = NULL; + + /* Clear the FT Context */ + sme_ft_reset(hHal, sessionId); + + pSession = CSR_GET_SESSION(pMac, sessionId); + if (NULL != pSession) { + /* check if the timer is running */ + if (QDF_TIMER_STATE_RUNNING == + qdf_mc_timer_get_current_state(&pSession->ftSmeContext. + preAuthReassocIntvlTimer)) { + qdf_mc_timer_stop(&pSession->ftSmeContext. + preAuthReassocIntvlTimer); + } + + if (QDF_STATUS_SUCCESS != + qdf_mc_timer_destroy(&pSession->ftSmeContext. + preAuthReassocIntvlTimer)) { + sms_log(pMac, LOGE, + FL("preAuthReAssocTimer destroy failed")); + } + + if (pSession->ftSmeContext.pUsrCtx != NULL) { + sms_log(pMac, LOG1, + FL + ("Freeing ftSmeContext.pUsrCtx and setting to NULL")); + qdf_mem_free(pSession->ftSmeContext.pUsrCtx); + pSession->ftSmeContext.pUsrCtx = NULL; + } + } +} + +void sme_set_ft_pre_auth_state(tHalHandle hHal, uint32_t sessionId, bool state) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + if (pSession) + pSession->ftSmeContext.setFTPreAuthState = state; +} + +bool sme_get_ft_pre_auth_state(tHalHandle hHal, uint32_t sessionId) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + if (pSession) + return pSession->ftSmeContext.setFTPreAuthState; + + return false; +} + +/** + * sme_set_ft_ies() - to set FT IEs + * @hal_ptr: pointer to HAL + * @session_id: sme session id + * @ft_ies: pointer to FT IEs + * @ft_ies_length: length of FT IEs + * + * Each time the supplicant sends down the FT IEs to the driver. This function + * is called in SME. This fucntion packages and sends the FT IEs to PE. + * + * Return: none + */ +void sme_set_ft_ies(tHalHandle hal_ptr, uint32_t session_id, + const uint8_t *ft_ies, uint16_t ft_ies_length) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal_ptr); + tCsrRoamSession *session = CSR_GET_SESSION(mac_ctx, session_id); + QDF_STATUS status = QDF_STATUS_E_FAILURE; + + if (NULL == session || NULL == ft_ies) { + sms_log(mac_ctx, LOGE, FL(" ft ies or session is NULL")); + return; + } + + status = sme_acquire_global_lock(&mac_ctx->sme); + if (!(QDF_IS_STATUS_SUCCESS(status))) + return; + + sms_log(mac_ctx, LOG1, "FT IEs Req is received in state %d", + session->ftSmeContext.FTState); + + /* Global Station FT State */ + switch (session->ftSmeContext.FTState) { + case eFT_START_READY: + case eFT_AUTH_REQ_READY: + sms_log(mac_ctx, LOG1, + FL("ft_ies_length=%d"), ft_ies_length); + if ((session->ftSmeContext.auth_ft_ies) && + (session->ftSmeContext.auth_ft_ies_length)) { + /* Free the one we recvd last from supplicant */ + qdf_mem_free(session->ftSmeContext.auth_ft_ies); + session->ftSmeContext.auth_ft_ies_length = 0; + session->ftSmeContext.auth_ft_ies = NULL; + } + ft_ies_length = QDF_MIN(ft_ies_length, MAX_FTIE_SIZE); + /* Save the FT IEs */ + session->ftSmeContext.auth_ft_ies = + qdf_mem_malloc(ft_ies_length); + if (NULL == session->ftSmeContext.auth_ft_ies) { + sms_log(mac_ctx, LOGE, + FL("Mem alloc failed for auth_ft_ies")); + sme_release_global_lock(&mac_ctx->sme); + return; + } + session->ftSmeContext.auth_ft_ies_length = ft_ies_length; + qdf_mem_copy((uint8_t *)session->ftSmeContext.auth_ft_ies, + ft_ies, ft_ies_length); + session->ftSmeContext.FTState = eFT_AUTH_REQ_READY; + break; + + case eFT_AUTH_COMPLETE: + /* + * We will need to re-start preauth. If we received FT + * IEs in eFT_PRE_AUTH_DONE state, it implies there was + * a rekey in our pre-auth state. Hence this implies we + * need Pre-auth again. OK now inform SME we have no + * pre-auth list. Delete the pre-auth node locally. Set + * your self back to restart pre-auth + */ + sms_log(mac_ctx, LOG1, + FL("Preauth done & rcving AUTHREQ in state %d"), + session->ftSmeContext.FTState); + sms_log(mac_ctx, LOG1, + FL("Unhandled reception of FT IES in state %d"), + session->ftSmeContext.FTState); + break; + + case eFT_REASSOC_REQ_WAIT: + /* + * We are done with pre-auth, hence now waiting for + * reassoc req. This is the new FT Roaming in place At + * this juncture we'r ready to start sending Reassoc req + */ + sms_log(mac_ctx, LOG1, FL("New Reassoc Req=%p in state %d"), + ft_ies, session->ftSmeContext.FTState); + if ((session->ftSmeContext.reassoc_ft_ies) && + (session->ftSmeContext.reassoc_ft_ies_length)) { + /* Free the one we recvd last from supplicant */ + qdf_mem_free(session->ftSmeContext.reassoc_ft_ies); + session->ftSmeContext.reassoc_ft_ies_length = 0; + } + /* Save the FT IEs */ + session->ftSmeContext.reassoc_ft_ies = + qdf_mem_malloc(ft_ies_length); + if (NULL == session->ftSmeContext.reassoc_ft_ies) { + sms_log(mac_ctx, LOGE, + FL("Mem alloc fail for reassoc_ft_ie")); + sme_release_global_lock(&mac_ctx->sme); + return; + } + session->ftSmeContext.reassoc_ft_ies_length = + ft_ies_length; + qdf_mem_copy((uint8_t *)session->ftSmeContext.reassoc_ft_ies, + ft_ies, ft_ies_length); + + session->ftSmeContext.FTState = eFT_SET_KEY_WAIT; + sms_log(mac_ctx, LOG1, + FL("ft_ies_length=%d state=%d"), ft_ies_length, + session->ftSmeContext.FTState); + + break; + + default: + sms_log(mac_ctx, LOGE, FL("Unhandled state=%d"), + session->ftSmeContext.FTState); + break; + } + sme_release_global_lock(&mac_ctx->sme); +} + +/** + * sme_ft_send_update_key_ind() - To send key update indication for FT session + * @hal: pointer to HAL + * @session_id: sme session id + * @ftkey_info: FT key information + * + * To send key update indication for FT session + * + * Return: QDF_STATUS + */ +static +QDF_STATUS sme_ft_send_update_key_ind(tHalHandle hal, uint32_t session_id, + tCsrRoamSetKey *ftkey_info) +{ + tSirFTUpdateKeyInfo *msg; + uint16_t msglen; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tSirKeyMaterial *keymaterial = NULL; + tAniEdType ed_type; + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + + sms_log(mac_ctx, LOG1, FL("keyLength %d"), ftkey_info->keyLength); + + if (ftkey_info->keyLength > CSR_MAX_KEY_LEN) { + sms_log(mac_ctx, LOGE, FL("invalid keyLength %d"), + ftkey_info->keyLength); + return QDF_STATUS_E_FAILURE; + } + msglen = sizeof(tSirFTUpdateKeyInfo); + + msg = qdf_mem_malloc(msglen); + if (NULL == msg) + return QDF_STATUS_E_NOMEM; + + msg->messageType = eWNI_SME_FT_UPDATE_KEY; + msg->length = msglen; + + keymaterial = &msg->keyMaterial; + keymaterial->length = ftkey_info->keyLength; + ed_type = csr_translate_encrypt_type_to_ed_type(ftkey_info->encType); + keymaterial->edType = ed_type; + keymaterial->numKeys = 1; + keymaterial->key[0].keyId = ftkey_info->keyId; + keymaterial->key[0].unicast = (uint8_t) true; + keymaterial->key[0].keyDirection = ftkey_info->keyDirection; + + qdf_mem_copy(&keymaterial->key[0].keyRsc, + ftkey_info->keyRsc, CSR_MAX_RSC_LEN); + keymaterial->key[0].paeRole = ftkey_info->paeRole; + keymaterial->key[0].keyLength = ftkey_info->keyLength; + + if (ftkey_info->keyLength) + qdf_mem_copy(&keymaterial->key[0].key, ftkey_info->Key, + ftkey_info->keyLength); + + qdf_copy_macaddr(&msg->bssid, &ftkey_info->peerMac); + msg->smeSessionId = session_id; + sms_log(mac_ctx, LOG1, "BSSID = " MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(msg->bssid.bytes)); + status = cds_send_mb_message_to_mac(msg); + + return status; +} + +bool sme_get_ftptk_state(tHalHandle hHal, uint32_t sessionId) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!pSession) { + sms_log(pMac, LOGE, FL("pSession is NULL")); + return false; + } + return pSession->ftSmeContext.setFTPTKState; +} + +void sme_set_ftptk_state(tHalHandle hHal, uint32_t sessionId, bool state) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!pSession) { + sms_log(pMac, LOGE, FL("pSession is NULL")); + return; + } + pSession->ftSmeContext.setFTPTKState = state; +} + +QDF_STATUS sme_ft_update_key(tHalHandle hHal, uint32_t sessionId, + tCsrRoamSetKey *pFTKeyInfo) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + QDF_STATUS status = QDF_STATUS_E_FAILURE; + + if (!pSession) { + sms_log(pMac, LOGE, FL("pSession is NULL")); + return QDF_STATUS_E_FAILURE; + } + + if (pFTKeyInfo == NULL) { + sms_log(pMac, LOGE, "%s: pFTKeyInfo is NULL", __func__); + return QDF_STATUS_E_FAILURE; + } + + status = sme_acquire_global_lock(&pMac->sme); + if (!(QDF_IS_STATUS_SUCCESS(status))) { + return QDF_STATUS_E_FAILURE; + } + sms_log(pMac, LOG1, "sme_ft_update_key is received in state %d", + pSession->ftSmeContext.FTState); + + /* Global Station FT State */ + switch (pSession->ftSmeContext.FTState) { + case eFT_SET_KEY_WAIT: + if (sme_get_ft_pre_auth_state(hHal, sessionId) == true) { + status = + sme_ft_send_update_key_ind(pMac, sessionId, pFTKeyInfo); + if (status != 0) { + sms_log(pMac, LOGE, "%s: Key set failure %d", + __func__, status); + pSession->ftSmeContext.setFTPTKState = false; + status = QDF_STATUS_FT_PREAUTH_KEY_FAILED; + } else { + pSession->ftSmeContext.setFTPTKState = true; + status = QDF_STATUS_FT_PREAUTH_KEY_SUCCESS; + sms_log(pMac, LOG1, "%s: Key set success", + __func__); + } + sme_set_ft_pre_auth_state(hHal, sessionId, false); + } + + pSession->ftSmeContext.FTState = eFT_START_READY; + sms_log(pMac, LOG1, "%s: state changed to %d status %d", + __func__, pSession->ftSmeContext.FTState, status); + break; + + default: + sms_log(pMac, LOGW, "%s: Unhandled state=%d", __func__, + pSession->ftSmeContext.FTState); + status = QDF_STATUS_E_FAILURE; + break; + } + sme_release_global_lock(&pMac->sme); + + return status; +} + +/*-------------------------------------------------------------------------- + * + * HDD Interface to SME. SME now sends the Auth 2 and RIC IEs up to the supplicant. + * The supplicant will then proceed to send down the + * Reassoc Req. + * + *------------------------------------------------------------------------*/ +void sme_get_ft_pre_auth_response(tHalHandle hHal, uint32_t sessionId, + uint8_t *ft_ies, uint32_t ft_ies_ip_len, + uint16_t *ft_ies_length) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + QDF_STATUS status = QDF_STATUS_E_FAILURE; + + if (!pSession) { + sms_log(pMac, LOGE, FL("pSession is NULL")); + return; + } + + *ft_ies_length = 0; + + status = sme_acquire_global_lock(&pMac->sme); + if (!(QDF_IS_STATUS_SUCCESS(status))) + return; + + /* All or nothing - proceed only if both BSSID and FT IE fit */ + if ((QDF_MAC_ADDR_SIZE + + pSession->ftSmeContext.psavedFTPreAuthRsp->ft_ies_length) > + ft_ies_ip_len) { + sme_release_global_lock(&pMac->sme); + return; + } + /* hdd needs to pack the bssid also along with the */ + /* auth response to supplicant */ + qdf_mem_copy(ft_ies, pSession->ftSmeContext.preAuthbssId, + QDF_MAC_ADDR_SIZE); + + /* Copy the auth resp FTIEs */ + qdf_mem_copy(&(ft_ies[QDF_MAC_ADDR_SIZE]), + pSession->ftSmeContext.psavedFTPreAuthRsp->ft_ies, + pSession->ftSmeContext.psavedFTPreAuthRsp->ft_ies_length); + + *ft_ies_length = QDF_MAC_ADDR_SIZE + + pSession->ftSmeContext.psavedFTPreAuthRsp->ft_ies_length; + + pSession->ftSmeContext.FTState = eFT_REASSOC_REQ_WAIT; + + sms_log(pMac, LOG1, FL(" Filled auth resp = %d"), *ft_ies_length); + sme_release_global_lock(&pMac->sme); + return; +} + +/*-------------------------------------------------------------------------- + * + * SME now sends the RIC IEs up to the supplicant. + * The supplicant will then proceed to send down the + * Reassoc Req. + * + *------------------------------------------------------------------------*/ +void sme_get_rici_es(tHalHandle hHal, uint32_t sessionId, uint8_t *ric_ies, + uint32_t ric_ies_ip_len, uint32_t *ric_ies_length) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + QDF_STATUS status = QDF_STATUS_E_FAILURE; + + if (!pSession) { + sms_log(pMac, LOGE, FL("pSession is NULL")); + return; + } + + *ric_ies_length = 0; + + status = sme_acquire_global_lock(&pMac->sme); + if (!(QDF_IS_STATUS_SUCCESS(status))) + return; + + /* All or nothing */ + if (pSession->ftSmeContext.psavedFTPreAuthRsp->ric_ies_length > + ric_ies_ip_len) { + sme_release_global_lock(&pMac->sme); + return; + } + + qdf_mem_copy(ric_ies, + pSession->ftSmeContext.psavedFTPreAuthRsp->ric_ies, + pSession->ftSmeContext.psavedFTPreAuthRsp->ric_ies_length); + + *ric_ies_length = + pSession->ftSmeContext.psavedFTPreAuthRsp->ric_ies_length; + + sms_log(pMac, LOG1, FL(" Filled ric ies = %d"), *ric_ies_length); + + sme_release_global_lock(&pMac->sme); + return; +} + +/*-------------------------------------------------------------------------- + * + * Timer callback for the timer that is started between the preauth completion and + * reassoc request to the PE. In this interval, it is expected that the pre-auth response + * and RIC IEs are passed up to the WPA supplicant and received back the necessary FTIEs + * required to be sent in the reassoc request + * + *------------------------------------------------------------------------*/ +void sme_preauth_reassoc_intvl_timer_callback(void *context) +{ + tFTRoamCallbackUsrCtx *pUsrCtx = (tFTRoamCallbackUsrCtx *) context; + + if (pUsrCtx) { + csr_neighbor_roam_request_handoff(pUsrCtx->pMac, + pUsrCtx->sessionId); + } + return; +} + +/*-------------------------------------------------------------------------- + Reset the FT context. + ------------------------------------------------------------------------*/ +void sme_ft_reset(tHalHandle hHal, uint32_t sessionId) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + tCsrRoamSession *pSession = NULL; + + if (pMac == NULL) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("pMac is NULL")); + return; + } + + pSession = CSR_GET_SESSION(pMac, sessionId); + if (NULL != pSession) { + if (pSession->ftSmeContext.auth_ft_ies != NULL) { + sms_log(pMac, LOG1, + FL("Free FT Auth IE %p and set to NULL"), + pSession->ftSmeContext.auth_ft_ies); + qdf_mem_free(pSession->ftSmeContext.auth_ft_ies); + pSession->ftSmeContext.auth_ft_ies = NULL; + } + pSession->ftSmeContext.auth_ft_ies_length = 0; + + if (pSession->ftSmeContext.reassoc_ft_ies != NULL) { + sms_log(pMac, LOG1, + FL("Free FT Reassoc IE %p and set to NULL"), + pSession->ftSmeContext.reassoc_ft_ies); + qdf_mem_free(pSession->ftSmeContext.reassoc_ft_ies); + pSession->ftSmeContext.reassoc_ft_ies = NULL; + } + pSession->ftSmeContext.reassoc_ft_ies_length = 0; + + if (pSession->ftSmeContext.psavedFTPreAuthRsp != NULL) { + sms_log(pMac, LOG1, + FL("Free FtPreAuthRsp %p and set to NULL"), + pSession->ftSmeContext.psavedFTPreAuthRsp); + qdf_mem_free(pSession->ftSmeContext.psavedFTPreAuthRsp); + pSession->ftSmeContext.psavedFTPreAuthRsp = NULL; + } + pSession->ftSmeContext.setFTPreAuthState = false; + pSession->ftSmeContext.setFTPTKState = false; + + qdf_mem_zero(pSession->ftSmeContext.preAuthbssId, + QDF_MAC_ADDR_SIZE); + pSession->ftSmeContext.FTState = eFT_START_READY; + } +} + +/* End of File */ diff --git a/drivers/staging/qcacld-3.0/core/sme/src/common/sme_power_save.c b/drivers/staging/qcacld-3.0/core/sme/src/common/sme_power_save.c new file mode 100644 index 0000000000000000000000000000000000000000..fb0f15b168143767e90c08dca68823760dbd53ae --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/sme/src/common/sme_power_save.c @@ -0,0 +1,1161 @@ +/* + * Copyright (c) 2015-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#include "sme_power_save.h" +#include "sme_power_save_api.h" +#include "sms_debug.h" +#include "sme_trace.h" +#include "qdf_mem.h" +#include "qdf_types.h" +#include "wma_types.h" +#include "wmm_apsd.h" +#include "cfg_api.h" +#include "csr_inside_api.h" + +/** + * sme_post_ps_msg_to_wma(): post message to WMA. + * @type: type + * @body: body pointer + * + * Return: QDF_STATUS + */ +static QDF_STATUS sme_post_ps_msg_to_wma(uint16_t type, void *body) +{ + cds_msg_t msg; + + msg.type = type; + msg.reserved = 0; + msg.bodyptr = body; + msg.bodyval = 0; + + if (QDF_STATUS_SUCCESS != cds_mq_post_message( + QDF_MODULE_ID_WMA, &msg)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Posting message %d failed", + __func__, type); + qdf_mem_free(body); + return QDF_STATUS_E_FAILURE; + } + return QDF_STATUS_SUCCESS; +} + +/** + * sme_ps_enable_uapsd_req_params(): enables UASPD req params + * @mac_ctx: global mac context + * @session_id: session id + * + * Return: QDF_STATUS + */ +static void sme_ps_fill_uapsd_req_params(tpAniSirGlobal mac_ctx, + tUapsd_Params *uapsdParams, uint32_t session_id, + enum ps_state *ps_state) +{ + + uint8_t uapsd_delivery_mask = 0; + uint8_t uapsd_trigger_mask = 0; + struct ps_global_info *ps_global_info = &mac_ctx->sme.ps_global_info; + struct ps_params *ps_param = &ps_global_info->ps_params[session_id]; + + uapsd_delivery_mask = + ps_param->uapsd_per_ac_bit_mask & + ps_param->uapsd_per_ac_delivery_enable_mask; + + uapsd_trigger_mask = + ps_param->uapsd_per_ac_bit_mask & + ps_param->uapsd_per_ac_trigger_enable_mask; + + uapsdParams->bkDeliveryEnabled = + LIM_UAPSD_GET(ACBK, uapsd_delivery_mask); + + uapsdParams->beDeliveryEnabled = + LIM_UAPSD_GET(ACBE, uapsd_delivery_mask); + + uapsdParams->viDeliveryEnabled = + LIM_UAPSD_GET(ACVI, uapsd_delivery_mask); + + uapsdParams->voDeliveryEnabled = + LIM_UAPSD_GET(ACVO, uapsd_delivery_mask); + + uapsdParams->bkTriggerEnabled = + LIM_UAPSD_GET(ACBK, uapsd_trigger_mask); + + uapsdParams->beTriggerEnabled = + LIM_UAPSD_GET(ACBE, uapsd_trigger_mask); + + uapsdParams->viTriggerEnabled = + LIM_UAPSD_GET(ACVI, uapsd_trigger_mask); + + uapsdParams->voTriggerEnabled = + LIM_UAPSD_GET(ACVO, uapsd_trigger_mask); + if (ps_param->ps_state != FULL_POWER_MODE) { + uapsdParams->enable_ps = true; + *ps_state = UAPSD_MODE; + } else { + uapsdParams->enable_ps = false; + *ps_state = FULL_POWER_MODE; + } +} + +static void sme_set_ps_state(tpAniSirGlobal mac_ctx, + uint32_t session_id, enum ps_state ps_state) +{ + struct ps_global_info *ps_global_info = &mac_ctx->sme.ps_global_info; + struct ps_params *ps_param = &ps_global_info->ps_params[session_id]; + ps_param->ps_state = ps_state; +} + +static void sme_get_ps_state(tpAniSirGlobal mac_ctx, + uint32_t session_id, enum ps_state *ps_state) +{ + struct ps_global_info *ps_global_info = &mac_ctx->sme.ps_global_info; + struct ps_params *ps_param = &ps_global_info->ps_params[session_id]; + *ps_state = ps_param->ps_state; +} +/** + * sme_ps_enable_ps_req_params(): enables power save req params + * @mac_ctx: global mac context + * @session_id: session id + * + * Return: QDF_STATUS + */ +static QDF_STATUS sme_ps_enable_ps_req_params(tpAniSirGlobal mac_ctx, + uint32_t session_id) +{ + struct sEnablePsParams *enable_ps_req_params; + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct ps_global_info *ps_global_info = &mac_ctx->sme.ps_global_info; + struct ps_params *ps_param = &ps_global_info->ps_params[session_id]; + enum ps_state ps_state; + + enable_ps_req_params = qdf_mem_malloc(sizeof(*enable_ps_req_params)); + if (NULL == enable_ps_req_params) { + sms_log(mac_ctx, LOGE, + FL("Memory allocation failed for enable_ps_req_params")); + return QDF_STATUS_E_NOMEM; + } + if (ps_param->uapsd_per_ac_bit_mask) { + enable_ps_req_params->psSetting = eSIR_ADDON_ENABLE_UAPSD; + sme_ps_fill_uapsd_req_params(mac_ctx, + &enable_ps_req_params->uapsdParams, + session_id, &ps_state); + ps_state = UAPSD_MODE; + enable_ps_req_params->uapsdParams.enable_ps = true; + } else { + enable_ps_req_params->psSetting = eSIR_ADDON_NOTHING; + ps_state = LEGACY_POWER_SAVE_MODE; + } + enable_ps_req_params->sessionid = session_id; + + status = sme_post_ps_msg_to_wma(WMA_ENTER_PS_REQ, enable_ps_req_params); + if (!QDF_IS_STATUS_SUCCESS(status)) + return QDF_STATUS_E_FAILURE; + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO, + FL("Message WMA_ENTER_PS_REQ Successfully sent to WMA")); + ps_param->ps_state = ps_state; + return QDF_STATUS_SUCCESS; +} + +/** + * sme_ps_disable_ps_req_params(): Disable power save req params + * @mac_ctx: global mac context + * @session_id: session id + * + * Return: QDF_STATUS + */ +static QDF_STATUS sme_ps_disable_ps_req_params(tpAniSirGlobal mac_ctx, + uint32_t session_id) +{ + struct sDisablePsParams *disable_ps_req_params; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + disable_ps_req_params = qdf_mem_malloc(sizeof(*disable_ps_req_params)); + if (NULL == disable_ps_req_params) { + sms_log(mac_ctx, LOGE, + FL("Memory allocation failed for sDisablePsParams")); + return QDF_STATUS_E_NOMEM; + } + + disable_ps_req_params->psSetting = eSIR_ADDON_NOTHING; + disable_ps_req_params->sessionid = session_id; + + status = sme_post_ps_msg_to_wma(WMA_EXIT_PS_REQ, disable_ps_req_params); + if (!QDF_IS_STATUS_SUCCESS(status)) + return QDF_STATUS_E_FAILURE; + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO, + FL("Message WMA_EXIT_PS_REQ Successfully sent to WMA")); + sme_set_ps_state(mac_ctx, session_id, FULL_POWER_MODE); + return QDF_STATUS_SUCCESS; +} + +/** + * sme_ps_enable_uapsd_req_params(): enables UASPD req params + * @mac_ctx: global mac context + * @session_id: session id + * + * Return: QDF_STATUS + */ +static QDF_STATUS sme_ps_enable_uapsd_req_params(tpAniSirGlobal mac_ctx, + uint32_t session_id) +{ + + struct sEnableUapsdParams *enable_uapsd_req_params; + QDF_STATUS status = QDF_STATUS_SUCCESS; + enum ps_state ps_state; + + enable_uapsd_req_params = + qdf_mem_malloc(sizeof(*enable_uapsd_req_params)); + if (NULL == enable_uapsd_req_params) { + sms_log(mac_ctx, LOGE, + FL("Memory allocation failed for enable_uapsd_req_params")); + return QDF_STATUS_E_NOMEM; + } + + sme_ps_fill_uapsd_req_params(mac_ctx, + &enable_uapsd_req_params->uapsdParams, + session_id, &ps_state); + enable_uapsd_req_params->sessionid = session_id; + + status = sme_post_ps_msg_to_wma(WMA_ENABLE_UAPSD_REQ, + enable_uapsd_req_params); + if (!QDF_IS_STATUS_SUCCESS(status)) + return QDF_STATUS_E_FAILURE; + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO, + FL("Msg WMA_ENABLE_UAPSD_REQ Successfully sent to WMA")); + sme_set_ps_state(mac_ctx, session_id, ps_state); + return QDF_STATUS_SUCCESS; +} + +/** + * sme_ps_disable_uapsd_req_params(): disables UASPD req params + * @mac_ctx: global mac context + * @session_id: session id + * + * Return: QDF_STATUS + */ +static QDF_STATUS sme_ps_disable_uapsd_req_params(tpAniSirGlobal mac_ctx, + uint32_t session_id) +{ + struct sDisableUapsdParams *disable_uapsd_req_params; + QDF_STATUS status = QDF_STATUS_SUCCESS; + enum ps_state ps_state; + + sme_get_ps_state(mac_ctx, session_id, &ps_state); + if (ps_state != UAPSD_MODE) { + sms_log(mac_ctx, LOGE, FL("UAPSD is already disabled")); + return QDF_STATUS_SUCCESS; + } + disable_uapsd_req_params = + qdf_mem_malloc(sizeof(*disable_uapsd_req_params)); + if (NULL == disable_uapsd_req_params) { + sms_log(mac_ctx, LOGE, + FL("Mem alloc failed for disable_uapsd_req_params")); + return QDF_STATUS_E_NOMEM; + } + + disable_uapsd_req_params->sessionid = session_id; + status = sme_post_ps_msg_to_wma(WMA_DISABLE_UAPSD_REQ, + disable_uapsd_req_params); + if (!QDF_IS_STATUS_SUCCESS(status)) + return QDF_STATUS_E_FAILURE; + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO, + FL("Message WMA_DISABLE_UAPSD_REQ Successfully sent to WMA")); + sme_set_ps_state(mac_ctx, session_id, LEGACY_POWER_SAVE_MODE); + return QDF_STATUS_SUCCESS; +} + +/** + * sme_ps_enter_wowl_req_params(): enable WOWL req Parama + * @mac_ctx: global mac context + * @session_id: session id + * + * Return: QDF_STATUS + */ +static QDF_STATUS sme_ps_enter_wowl_req_params(tpAniSirGlobal mac_ctx, + uint32_t session_id) +{ + struct sSirHalWowlEnterParams *hal_wowl_params; + struct sSirSmeWowlEnterParams *sme_wowl_params; + uint32_t cfg_value = 0; + struct ps_global_info *ps_global_info = &mac_ctx->sme.ps_global_info; + + sme_wowl_params = + &ps_global_info->ps_params[session_id].wowl_enter_params; + + hal_wowl_params = qdf_mem_malloc(sizeof(*hal_wowl_params)); + if (NULL == hal_wowl_params) { + sms_log(mac_ctx, LOGP, + FL("Fail to allocate memory for Enter Wowl Request")); + return QDF_STATUS_E_NOMEM; + } + + /* fill in the message field */ + hal_wowl_params->ucMagicPktEnable = sme_wowl_params->ucMagicPktEnable; + hal_wowl_params->ucPatternFilteringEnable = + sme_wowl_params->ucPatternFilteringEnable; + qdf_copy_macaddr(&hal_wowl_params->magic_ptrn, + &sme_wowl_params->magic_ptrn); + +#ifdef WLAN_WAKEUP_EVENTS + hal_wowl_params->ucWoWEAPIDRequestEnable = + sme_wowl_params->ucWoWEAPIDRequestEnable; + hal_wowl_params->ucWoWEAPOL4WayEnable = + sme_wowl_params->ucWoWEAPOL4WayEnable; + hal_wowl_params->ucWowNetScanOffloadMatch = + sme_wowl_params->ucWowNetScanOffloadMatch; + hal_wowl_params->ucWowGTKRekeyError = + sme_wowl_params->ucWowGTKRekeyError; + hal_wowl_params->ucWoWBSSConnLoss = + sme_wowl_params->ucWoWBSSConnLoss; +#endif /* WLAN_WAKEUP_EVENTS */ + + if (wlan_cfg_get_int + (mac_ctx, WNI_CFG_WOWLAN_UCAST_PATTERN_FILTER_ENABLE, + &cfg_value) != eSIR_SUCCESS) { + sms_log(mac_ctx, LOGP, + FL("cfgGet failed for WNI_CFG_WOWLAN_UCAST_PATTERN_FILTER_ENABLE")); + goto end; + } + hal_wowl_params->ucUcastPatternFilteringEnable = (uint8_t) cfg_value; + + if (wlan_cfg_get_int + (mac_ctx, WNI_CFG_WOWLAN_CHANNEL_SWITCH_ENABLE, + &cfg_value) != eSIR_SUCCESS) { + sms_log(mac_ctx, LOGP, + FL("cfgGet failed for WNI_CFG_WOWLAN_CHANNEL_SWITCH_ENABLE")); + goto end; + } + hal_wowl_params->ucWowChnlSwitchRcv = (uint8_t) cfg_value; + + if (wlan_cfg_get_int + (mac_ctx, WNI_CFG_WOWLAN_DEAUTH_ENABLE, &cfg_value) != + eSIR_SUCCESS) { + sms_log(mac_ctx, LOGP, + FL("cfgGet failed for WNI_CFG_WOWLAN_DEAUTH_ENABLE ")); + goto end; + } + hal_wowl_params->ucWowDeauthRcv = (uint8_t) cfg_value; + + if (wlan_cfg_get_int + (mac_ctx, WNI_CFG_WOWLAN_DISASSOC_ENABLE, &cfg_value) != + eSIR_SUCCESS) { + sms_log(mac_ctx, LOGP, + FL("cfgGet failed for WNI_CFG_WOWLAN_DISASSOC_ENABLE ")); + goto end; + } + hal_wowl_params->ucWowDisassocRcv = (uint8_t) cfg_value; + + if (wlan_cfg_get_int(mac_ctx, WNI_CFG_WOWLAN_MAX_MISSED_BEACON, + &cfg_value) != eSIR_SUCCESS) { + sms_log(mac_ctx, LOGP, + FL("cfgGet failed for WNI_CFG_WOWLAN_MAX_MISSED_BEACON ")); + goto end; + } + hal_wowl_params->ucWowMaxMissedBeacons = (uint8_t) cfg_value; + + if (wlan_cfg_get_int(mac_ctx, WNI_CFG_WOWLAN_MAX_SLEEP_PERIOD, + &cfg_value) != eSIR_SUCCESS) { + sms_log(mac_ctx, LOGP, + FL("cfgGet failed for WNI_CFG_WOWLAN_MAX_SLEEP_PERIOD ")); + goto end; + } + hal_wowl_params->ucWowMaxSleepUsec = (uint8_t) cfg_value; + + hal_wowl_params->sessionId = sme_wowl_params->sessionId; + + if (QDF_STATUS_SUCCESS == sme_post_ps_msg_to_wma(WMA_WOWL_ENTER_REQ, + hal_wowl_params)){ + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO, + FL("Msg WMA_WOWL_ENTER_REQ Successfully sent to WMA")); + return QDF_STATUS_SUCCESS; + } else { + return QDF_STATUS_E_FAILURE; + } + +end: + if (hal_wowl_params != NULL) + qdf_mem_free(hal_wowl_params); + return QDF_STATUS_E_FAILURE; +} + +/** + * sme_ps_exit_wowl_req_params(): Exit WOWL req params + * @mac_ctx: global mac context + * @session_id: session id + * + * Return: QDF_STATUS + */ +static QDF_STATUS sme_ps_exit_wowl_req_params(tpAniSirGlobal mac_ctx, + uint32_t session_id) +{ + struct sSirHalWowlExitParams *hal_wowl_msg; + hal_wowl_msg = qdf_mem_malloc(sizeof(*hal_wowl_msg)); + if (NULL == hal_wowl_msg) { + sms_log(mac_ctx, LOGP, + FL("Fail to allocate memory for WoWLAN Add Bcast Pattern ")); + return QDF_STATUS_E_NOMEM; + } + hal_wowl_msg->sessionId = session_id; + + if (QDF_STATUS_SUCCESS == sme_post_ps_msg_to_wma(WMA_WOWL_EXIT_REQ, + hal_wowl_msg)){ + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO, + FL("Msg WMA_WOWL_EXIT_REQ Successfully sent to WMA")); + return QDF_STATUS_SUCCESS; + } else { + return QDF_STATUS_E_FAILURE; + } +} + +/** + * sme_ps_process_command(): Sme process power save messages + * and pass messages to WMA. + * @mac_ctx: global mac context + * @session_id: session id + * sme_ps_cmd: power save message + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_ps_process_command(tpAniSirGlobal mac_ctx, uint32_t session_id, + enum sme_ps_cmd command) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + + if (!CSR_IS_SESSION_VALID(mac_ctx, session_id)) { + sms_log(mac_ctx, LOGE, "Invalid Session_id %x", session_id); + return eSIR_FAILURE; + } + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO, + FL("Power Save command %d"), command); + switch (command) { + case SME_PS_ENABLE: + status = sme_ps_enable_ps_req_params(mac_ctx, session_id); + break; + case SME_PS_DISABLE: + status = sme_ps_disable_ps_req_params(mac_ctx, session_id); + break; + case SME_PS_UAPSD_ENABLE: + status = sme_ps_enable_uapsd_req_params(mac_ctx, session_id); + break; + case SME_PS_UAPSD_DISABLE: + status = sme_ps_disable_uapsd_req_params(mac_ctx, session_id); + break; + case SME_PS_WOWL_ENTER: + status = sme_ps_enter_wowl_req_params(mac_ctx, session_id); + break; + case SME_PS_WOWL_EXIT: + status = sme_ps_exit_wowl_req_params(mac_ctx, session_id); + break; + + default: + sms_log(mac_ctx, LOGE, FL("Invalid command type %d"), + command); + status = QDF_STATUS_E_FAILURE; + break; + } + if (status != QDF_STATUS_SUCCESS) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Not able to enter in PS, Command: %d"), command); + } + return status; +} + +/** + * sme_enable_sta_ps_check(): Checks if it is ok to enable power save or not. + * @mac_ctx: global mac context + * @session_id: session id + * + *Pre Condition for enabling sta mode power save + *1) Sta Mode Ps should be enabled in ini file. + *2) Session should be in infra mode and in connected state. + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_enable_sta_ps_check(tpAniSirGlobal mac_ctx, uint32_t session_id) +{ + struct ps_global_info *ps_global_info = &mac_ctx->sme.ps_global_info; + + /* Check if Sta Ps is enabled. */ + if (!ps_global_info->ps_enabled) { + sms_log(mac_ctx, LOG1, + "Cannot initiate PS. PS is disabled in ini"); + return QDF_STATUS_E_FAILURE; + } + + /* Check whether the given session is Infra and in Connected State */ + if (!csr_is_conn_state_connected_infra(mac_ctx, session_id)) { + sms_log(mac_ctx, LOG1, "Sta not infra/connected state %d", + session_id); + return QDF_STATUS_E_FAILURE; + } + return QDF_STATUS_SUCCESS; + +} + +/** + * sme_ps_enable_disable(): function to enable/disable PS. + * @hal_ctx: global hal_handle + * @session_id: session id + * sme_ps_cmd: power save message + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_ps_enable_disable(tHalHandle hal_ctx, uint32_t session_id, + enum sme_ps_cmd command) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal_ctx); + status = sme_enable_sta_ps_check(mac_ctx, session_id); + if (status != QDF_STATUS_SUCCESS) + return status; + status = sme_ps_process_command(mac_ctx, session_id, command); + return status; +} + +/** + * sme_ps_uapsd_enable(): function to enable UAPSD. + * @hal_ctx: global hal_handle + * @session_id: session id + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_ps_uapsd_enable(tHalHandle hal_ctx, uint32_t session_id) +{ + + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal_ctx); + status = sme_enable_sta_ps_check(mac_ctx, session_id); + if (status != QDF_STATUS_SUCCESS) + return status; + status = sme_ps_process_command(mac_ctx, session_id, + SME_PS_UAPSD_ENABLE); + if (status == QDF_STATUS_SUCCESS) + sme_offload_qos_process_into_uapsd_mode(mac_ctx, session_id); + + return status; +} + +/** + * sme_ps_uapsd_disable(): function to disable UAPSD. + * @hal_ctx: global hal_handle + * @session_id: session id + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_ps_uapsd_disable(tHalHandle hal_ctx, uint32_t session_id) +{ + + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal_ctx); + status = sme_enable_sta_ps_check(mac_ctx, session_id); + if (status != QDF_STATUS_SUCCESS) + return status; + status = sme_ps_process_command(mac_ctx, session_id, + SME_PS_UAPSD_DISABLE); + if (status == QDF_STATUS_SUCCESS) + sme_offload_qos_process_out_of_uapsd_mode(mac_ctx, session_id); + + return status; +} + +/** + * sme_set_tspec_uapsd_mask_per_session(): set tspec UAPSD mask per session + * @mac_ctx: global mac context + * @ts_info: tspec info. + * @session_id: session id + * + * Return: QDF_STATUS + */ +void sme_set_tspec_uapsd_mask_per_session(tpAniSirGlobal mac_ctx, + tSirMacTSInfo *ts_info, + uint8_t session_id) +{ + uint8_t user_prio = (uint8_t) ts_info->traffic.userPrio; + uint16_t direction = ts_info->traffic.direction; + uint8_t ac = upToAc(user_prio); + struct ps_global_info *ps_global_info = &mac_ctx->sme.ps_global_info; + struct ps_params *ps_param = &ps_global_info->ps_params[session_id]; + sms_log(mac_ctx, LOGE, FL("Set UAPSD mask for AC %d, dir %d, action=%d") + , ac, direction, ts_info->traffic.psb); + + /* Converting AC to appropriate Uapsd Bit Mask + * AC_BE(0) --> UAPSD_BITOFFSET_ACVO(3) + * AC_BK(1) --> UAPSD_BITOFFSET_ACVO(2) + * AC_VI(2) --> UAPSD_BITOFFSET_ACVO(1) + * AC_VO(3) --> UAPSD_BITOFFSET_ACVO(0) + */ + ac = ((~ac) & 0x3); + if (ts_info->traffic.psb) { + ps_param->uapsd_per_ac_bit_mask |= (1 << ac); + if (direction == SIR_MAC_DIRECTION_UPLINK) + ps_param->uapsd_per_ac_trigger_enable_mask |= + (1 << ac); + else if (direction == SIR_MAC_DIRECTION_DNLINK) + ps_param->uapsd_per_ac_delivery_enable_mask |= + (1 << ac); + else if (direction == SIR_MAC_DIRECTION_BIDIR) { + ps_param->uapsd_per_ac_trigger_enable_mask |= + (1 << ac); + ps_param->uapsd_per_ac_delivery_enable_mask |= + (1 << ac); + } + } else { + ps_param->uapsd_per_ac_bit_mask &= ~(1 << ac); + if (direction == SIR_MAC_DIRECTION_UPLINK) + ps_param->uapsd_per_ac_trigger_enable_mask &= + ~(1 << ac); + else if (direction == SIR_MAC_DIRECTION_DNLINK) + ps_param->uapsd_per_ac_delivery_enable_mask &= + ~(1 << ac); + else if (direction == SIR_MAC_DIRECTION_BIDIR) { + ps_param->uapsd_per_ac_trigger_enable_mask &= + ~(1 << ac); + ps_param->uapsd_per_ac_delivery_enable_mask &= + ~(1 << ac); + } + } + + /* + * ADDTS success, so AC is now admitted. We shall now use the default + * EDCA parameters as advertised by AP and send the updated EDCA params + * to HAL. + */ + if (direction == SIR_MAC_DIRECTION_UPLINK) { + ps_param->ac_admit_mask[SIR_MAC_DIRECTION_UPLINK] |= + (1 << ac); + } else if (direction == SIR_MAC_DIRECTION_DNLINK) { + ps_param->ac_admit_mask[SIR_MAC_DIRECTION_DNLINK] |= + (1 << ac); + } else if (direction == SIR_MAC_DIRECTION_BIDIR) { + ps_param->ac_admit_mask[SIR_MAC_DIRECTION_UPLINK] |= + (1 << ac); + ps_param->ac_admit_mask[SIR_MAC_DIRECTION_DNLINK] |= + (1 << ac); + } + + sms_log(mac_ctx, LOG1, + FL("New ps_param->uapsd_per_ac_trigger_enable_mask = 0x%x "), + ps_param->uapsd_per_ac_trigger_enable_mask); + sms_log(mac_ctx, LOG1, + FL("New ps_param->uapsd_per_ac_delivery_enable_mask = 0x%x "), + ps_param->uapsd_per_ac_delivery_enable_mask); + sms_log(mac_ctx, LOG1, + FL("New ps_param->ac_admit_mask[SIR_MAC_DIRECTION_UPLINK] = 0x%x "), + ps_param->ac_admit_mask[SIR_MAC_DIRECTION_UPLINK]); + return; +} + +/** + * sme_ps_start_uapsd(): function to start UAPSD. + * @hal_ctx: global hal_handle + * @session_id: session id + * @uapsd_start_ind_cb: uapsd start indiation cb + * @callback_context: callback context + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_ps_start_uapsd(tHalHandle hal_ctx, uint32_t session_id, + uapsd_start_indication_cb uapsd_start_ind_cb, + void *callback_context) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + status = sme_ps_uapsd_enable(hal_ctx, session_id); + return status; +} + +#ifdef FEATURE_WLAN_SCAN_PNO +/** + * sme_set_pno_channel_prediction() - Prepare PNO buffer + * @request_buf: Buffer to be filled up to send to WMA + * @mac_ctx: MAC context + * + * Fill up the PNO buffer with the channel prediction configuration + * parameters and send them to WMA + * + * Return: None + **/ +void sme_set_pno_channel_prediction(tpSirPNOScanReq request_buf, + tpAniSirGlobal mac_ctx) +{ + request_buf->pno_channel_prediction = + mac_ctx->roam.configParam.pno_channel_prediction; + request_buf->top_k_num_of_channels = + mac_ctx->roam.configParam.top_k_num_of_channels; + request_buf->stationary_thresh = + mac_ctx->roam.configParam.stationary_thresh; + request_buf->channel_prediction_full_scan = + mac_ctx->roam.configParam.channel_prediction_full_scan; + request_buf->pnoscan_adaptive_dwell_mode = + mac_ctx->roam.configParam.pnoscan_adaptive_dwell_mode; + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + FL("channel_prediction: %d, top_k_num_of_channels: %d"), + request_buf->pno_channel_prediction, + request_buf->top_k_num_of_channels); + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + FL("stationary_thresh: %d, ch_predict_full_scan: %d"), + request_buf->stationary_thresh, + request_buf->channel_prediction_full_scan); +} +QDF_STATUS sme_set_ps_preferred_network_list(tHalHandle hal_ctx, + tpSirPNOScanReq request, + uint8_t session_id, + preferred_network_found_ind_cb callback_routine, + void *callback_context) +{ + tpSirPNOScanReq request_buf; + cds_msg_t msg; + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal_ctx); + tCsrRoamSession *session = CSR_GET_SESSION(mac_ctx, session_id); + uint8_t uc_dot11_mode; + + if (NULL == session) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: session is NULL", __func__); + return QDF_STATUS_E_FAILURE; + } + + /* save some work if PNO is already disabled */ + if (!session->pnoStarted && !request->enable) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO, + "%s: PNO already disabled", __func__); + return QDF_STATUS_SUCCESS; + } + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO, + "%s: SSID = 0x%08x%08x%08x%08x%08x%08x%08x%08x, 0x%08x%08x%08x%08x%08x%08x%08x%08x", __func__, + *((uint32_t *) &request->aNetworks[0].ssId.ssId[0]), + *((uint32_t *) &request->aNetworks[0].ssId.ssId[4]), + *((uint32_t *) &request->aNetworks[0].ssId.ssId[8]), + *((uint32_t *) &request->aNetworks[0].ssId.ssId[12]), + *((uint32_t *) &request->aNetworks[0].ssId.ssId[16]), + *((uint32_t *) &request->aNetworks[0].ssId.ssId[20]), + *((uint32_t *) &request->aNetworks[0].ssId.ssId[24]), + *((uint32_t *) &request->aNetworks[0].ssId.ssId[28]), + *((uint32_t *) &request->aNetworks[1].ssId.ssId[0]), + *((uint32_t *) &request->aNetworks[1].ssId.ssId[4]), + *((uint32_t *) &request->aNetworks[1].ssId.ssId[8]), + *((uint32_t *) &request->aNetworks[1].ssId.ssId[12]), + *((uint32_t *) &request->aNetworks[1].ssId.ssId[16]), + *((uint32_t *) &request->aNetworks[1].ssId.ssId[20]), + *((uint32_t *) &request->aNetworks[1].ssId.ssId[24]), + *((uint32_t *) &request->aNetworks[1].ssId.ssId[28])); + + if (!session) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: session is NULL", __func__); + return QDF_STATUS_E_FAILURE; + } + + request_buf = qdf_mem_malloc(sizeof(tSirPNOScanReq)); + if (NULL == request_buf) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Not able to allocate memory for PNO request")); + return QDF_STATUS_E_NOMEM; + } + + qdf_mem_copy(request_buf, request, sizeof(tSirPNOScanReq)); + + /*Must translate the mode first */ + uc_dot11_mode = (uint8_t) csr_translate_to_wni_cfg_dot11_mode(mac_ctx, + csr_find_best_phy_mode + (mac_ctx, + mac_ctx->roam. + configParam. + phyMode)); + + + if (mac_ctx->pnoOffload) { + if (request_buf->enable) + session->pnoStarted = true; + else + session->pnoStarted = false; + + request_buf->sessionId = session_id; + } + sme_set_pno_channel_prediction(request_buf, mac_ctx); + + if (csr_is_p2p_session_connected(mac_ctx)) { + /* if AP-STA concurrency is active */ + request_buf->active_max_time = + mac_ctx->roam.configParam.nActiveMaxChnTimeConc; + request_buf->active_min_time = + mac_ctx->roam.configParam.nActiveMinChnTimeConc; + request_buf->passive_max_time = + mac_ctx->roam.configParam.nPassiveMaxChnTimeConc; + request_buf->passive_min_time = + mac_ctx->roam.configParam.nPassiveMinChnTimeConc; + request_buf->pnoscan_adaptive_dwell_mode = + mac_ctx->roam.configParam.pnoscan_adaptive_dwell_mode; + } else { + request_buf->active_max_time = + mac_ctx->roam.configParam.nActiveMaxChnTime; + request_buf->active_min_time = + mac_ctx->roam.configParam.nActiveMinChnTime; + request_buf->passive_max_time = + mac_ctx->roam.configParam.nPassiveMaxChnTime; + request_buf->passive_min_time = + mac_ctx->roam.configParam.nPassiveMinChnTime; + request_buf->pnoscan_adaptive_dwell_mode = + mac_ctx->roam.configParam.pnoscan_adaptive_dwell_mode; + } + + msg.type = WMA_SET_PNO_REQ; + msg.reserved = 0; + msg.bodyptr = request_buf; + if (!QDF_IS_STATUS_SUCCESS + (cds_mq_post_message(QDF_MODULE_ID_WMA, &msg))) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Not able to post WMA_SET_PNO_REQ message to WMA")); + qdf_mem_free(request_buf); + return QDF_STATUS_E_FAILURE; + } + + /* Cache the Preferred Network Found Indication callback information */ + mac_ctx->sme.pref_netw_found_cb = + callback_routine; + mac_ctx->sme.preferred_network_found_ind_cb_ctx = + callback_context; + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO, "-%s", __func__); + + return QDF_STATUS_SUCCESS; +} +#endif /* FEATURE_WLAN_SCAN_PNO */ + +/** + * sme_set_ps_host_offload(): Set the host offload feature. + * @hal_ctx - The handle returned by mac_open. + * @request - Pointer to the offload request. + * + * Return QDF_STATUS + * QDF_STATUS_E_FAILURE Cannot set the offload. + * QDF_STATUS_SUCCESS Request accepted. + */ +QDF_STATUS sme_set_ps_host_offload(tHalHandle hal_ctx, + tpSirHostOffloadReq request, + uint8_t session_id) +{ + tpSirHostOffloadReq request_buf; + cds_msg_t msg; + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal_ctx); + tCsrRoamSession *session = CSR_GET_SESSION(mac_ctx, session_id); + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO, + "%s: IP address = %d.%d.%d.%d", __func__, + request->params.hostIpv4Addr[0], + request->params.hostIpv4Addr[1], + request->params.hostIpv4Addr[2], + request->params.hostIpv4Addr[3]); + + if (NULL == session) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: SESSION not Found", __func__); + return QDF_STATUS_E_FAILURE; + } + + request_buf = qdf_mem_malloc(sizeof(tSirHostOffloadReq)); + if (NULL == request_buf) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Not able to allocate memory for host offload request")); + return QDF_STATUS_E_NOMEM; + } + + qdf_copy_macaddr(&request->bssid, &session->connectedProfile.bssid); + + qdf_mem_copy(request_buf, request, sizeof(tSirHostOffloadReq)); + + msg.type = WMA_SET_HOST_OFFLOAD; + msg.reserved = 0; + msg.bodyptr = request_buf; + MTRACE(qdf_trace(QDF_MODULE_ID_SME, TRACE_CODE_SME_TX_WMA_MSG, + session_id, msg.type)); + if (QDF_STATUS_SUCCESS != + cds_mq_post_message(QDF_MODULE_ID_WMA, &msg)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Not able to post WMA_SET_HOST_OFFLOAD msg to WMA")); + qdf_mem_free(request_buf); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +#ifdef WLAN_NS_OFFLOAD +/** + * sme_set_ps_ns_offload(): Set the host offload feature. + * @hal_ctx - The handle returned by mac_open. + * @request - Pointer to the offload request. + * + * Return QDF_STATUS + * QDF_STATUS_E_FAILURE Cannot set the offload. + * QDF_STATUS_SUCCESS Request accepted. + */ +QDF_STATUS sme_set_ps_ns_offload(tHalHandle hal_ctx, + tpSirHostOffloadReq request, + uint8_t session_id) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal_ctx); + tpSirHostOffloadReq request_buf; + cds_msg_t msg; + tCsrRoamSession *session = CSR_GET_SESSION(mac_ctx, session_id); + + if (NULL == session) { + sms_log(mac_ctx, LOGE, FL("Session not found ")); + return QDF_STATUS_E_FAILURE; + } + + qdf_copy_macaddr(&request->bssid, &session->connectedProfile.bssid); + + request_buf = qdf_mem_malloc(sizeof(*request_buf)); + if (NULL == request_buf) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Not able to allocate memory for NS offload request")); + return QDF_STATUS_E_NOMEM; + } + *request_buf = *request; + + msg.type = WMA_SET_NS_OFFLOAD; + msg.reserved = 0; + msg.bodyptr = request_buf; + MTRACE(qdf_trace(QDF_MODULE_ID_SME, TRACE_CODE_SME_TX_WMA_MSG, + session_id, msg.type)); + if (QDF_STATUS_SUCCESS != + cds_mq_post_message(QDF_MODULE_ID_WMA, &msg)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Not able to post SIR_HAL_SET_HOST_OFFLOAD message to HAL")); + qdf_mem_free(request_buf); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +#endif /* WLAN_NS_OFFLOAD */ +/* -------------------------------------------------------------------- */ +/** + * sme_post_pe_message + * + * FUNCTION: + * Post a message to the pmm message queue + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param msg pointer to message + * @return None + */ + +tSirRetStatus sme_post_pe_message(tpAniSirGlobal mac_ctx, tpSirMsgQ msg) +{ + QDF_STATUS qdf_status; + qdf_status = cds_mq_post_message(CDS_MQ_ID_PE, (cds_msg_t *) msg); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + sms_log(mac_ctx, LOGP, + FL("cds_mq_post_message failed with status code %d"), + qdf_status); + return eSIR_FAILURE; + } + + return eSIR_SUCCESS; +} + +QDF_STATUS sme_ps_enable_auto_ps_timer(tHalHandle hal_ctx, + uint32_t session_id, uint32_t timeout, bool force_trigger) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal_ctx); + struct ps_global_info *ps_global_info = &mac_ctx->sme.ps_global_info; + struct ps_params *ps_param = &ps_global_info->ps_params[session_id]; + QDF_STATUS qdf_status; + + if (!ps_global_info->auto_bmps_timer_val && !force_trigger) { + sms_log(mac_ctx, LOGE, + FL("auto_ps_timer disabled in INI, force_trigger %d"), + force_trigger); + return QDF_STATUS_SUCCESS; + } + + sms_log(mac_ctx, LOGE, FL("Start auto_ps_timer for %d ms"), + timeout); + + qdf_status = qdf_mc_timer_start(&ps_param->auto_ps_enable_timer, + timeout); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + if (QDF_STATUS_E_ALREADY == qdf_status) { + /* Consider this ok since the timer is already started*/ + sms_log(mac_ctx, LOGW, + FL("auto_ps_timer is already started")); + } else { + sms_log(mac_ctx, LOGP, + FL("Cannot start auto_ps_timer")); + return QDF_STATUS_E_FAILURE; + } + } + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS sme_ps_disable_auto_ps_timer(tHalHandle hal_ctx, + uint32_t session_id) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal_ctx); + struct ps_global_info *ps_global_info = &mac_ctx->sme.ps_global_info; + struct ps_params *ps_param = &ps_global_info->ps_params[session_id]; + /* + * Stop the auto ps entry timer if runnin + */ + if (QDF_TIMER_STATE_RUNNING == + qdf_mc_timer_get_current_state( + &ps_param->auto_ps_enable_timer)) { + sms_log(mac_ctx, LOGE, + FL("Stop auto_ps_enable_timer Timer for session ID:%d "), + session_id); + qdf_mc_timer_stop(&ps_param->auto_ps_enable_timer); + } + return QDF_STATUS_SUCCESS; +} + + +QDF_STATUS sme_ps_open(tHalHandle hal_ctx) +{ + + uint32_t i; + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal_ctx); + + sms_log(mac_ctx, LOG1, FL("Enter")); + + for (i = 0; i < MAX_SME_SESSIONS; i++) { + if (QDF_STATUS_SUCCESS != sme_ps_open_per_session(hal_ctx, i)) { + sms_log(mac_ctx, LOGE, + FL("PMC Init Failed for session %d"), i); + return QDF_STATUS_E_FAILURE; + } + } + return QDF_STATUS_SUCCESS; +} + + +QDF_STATUS sme_ps_open_per_session(tHalHandle hal_ctx, uint32_t session_id) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal_ctx); + struct ps_global_info *ps_global_info = &mac_ctx->sme.ps_global_info; + struct ps_params *ps_param = &ps_global_info->ps_params[session_id]; + ps_param->session_id = session_id; + ps_param->mac_ctx = mac_ctx; + + sms_log(mac_ctx, LOG1, FL("Enter")); + /* Allocate a timer to enable ps automatically */ + if (!QDF_IS_STATUS_SUCCESS(qdf_mc_timer_init( + &ps_param->auto_ps_enable_timer, + QDF_TIMER_TYPE_SW, + sme_auto_ps_entry_timer_expired, + ps_param))) { + sms_log(mac_ctx, LOGE, + FL("Cannot allocate timer for auto ps entry")); + return QDF_STATUS_E_FAILURE; + } + return QDF_STATUS_SUCCESS; + +} + +void sme_auto_ps_entry_timer_expired(void *data) +{ + struct ps_params *ps_params = (struct ps_params *)data; + tpAniSirGlobal mac_ctx = (tpAniSirGlobal)ps_params->mac_ctx; + uint32_t session_id = ps_params->session_id; + QDF_STATUS status = QDF_STATUS_SUCCESS; + status = sme_enable_sta_ps_check(mac_ctx, session_id); + + if (QDF_STATUS_SUCCESS == status) { + sme_ps_enable_disable((tHalHandle)mac_ctx, session_id, + SME_PS_ENABLE); + } else { + status = + qdf_mc_timer_start(&ps_params->auto_ps_enable_timer, + AUTO_PS_ENTRY_TIMER_DEFAULT_VALUE); + if (!QDF_IS_STATUS_SUCCESS(status) + && (QDF_STATUS_E_ALREADY != status)) { + sms_log(mac_ctx, LOGP, + FL("Cannot start traffic timer")); + } + } +} + +QDF_STATUS sme_ps_close(tHalHandle hal_ctx) +{ + uint32_t i; + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal_ctx); + + sms_log(mac_ctx, LOG2, FL("Enter")); + + for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) + sme_ps_close_per_session(hal_ctx, i); + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS sme_ps_close_per_session(tHalHandle hal_ctx, uint32_t session_id) +{ + + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal_ctx); + struct ps_global_info *ps_global_info = &mac_ctx->sme.ps_global_info; + struct ps_params *ps_param = &ps_global_info->ps_params[session_id]; + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + + /* + * Stop the auto ps entry timer if running + */ + if (QDF_TIMER_STATE_RUNNING == + qdf_mc_timer_get_current_state( + &ps_param->auto_ps_enable_timer)) { + qdf_mc_timer_stop(&ps_param->auto_ps_enable_timer); + } + qdf_status = + qdf_mc_timer_destroy(&ps_param->auto_ps_enable_timer); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) + sms_log(mac_ctx, LOGE, FL("Cannot deallocate suto PS timer")); + return qdf_status; +} + +bool sme_is_auto_ps_timer_running(tHalHandle hal_ctx, + uint32_t session_id) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal_ctx); + struct ps_global_info *ps_global_info = &mac_ctx->sme.ps_global_info; + struct ps_params *ps_param = &ps_global_info->ps_params[session_id]; + bool status = false; + /* + * Check if the auto ps entry timer if running + */ + if (QDF_TIMER_STATE_RUNNING == + qdf_mc_timer_get_current_state( + &ps_param->auto_ps_enable_timer)) { + status = true; + } + return status; +} diff --git a/drivers/staging/qcacld-3.0/core/sme/src/common/sme_trace.c b/drivers/staging/qcacld-3.0/core/sme/src/common/sme_trace.c new file mode 100644 index 0000000000000000000000000000000000000000..24fb31f1f312d8812ce49906e5a4eb383ac2d46d --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/sme/src/common/sme_trace.c @@ -0,0 +1,259 @@ +/* + * Copyright (c) 2013-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/************************************************************************ + smeTrace.c + + \brief implementation for trace related APIs + + \author Kiran Kumar Reddy CH L V + + ========================================================================*/ +#include "ani_global.h" /* for tpAniSirGlobal */ +#include "sms_debug.h" +#include "mac_trace.h" +#include "sme_trace.h" +#include "sme_internal.h" +#ifndef SME_TRACE_RECORD +void sme_trace_init(tpAniSirGlobal pMac) +{ + return; +} +#endif +#ifdef SME_TRACE_RECORD + +static uint8_t *sme_trace_get_rx_msg_string(uint32_t code) +{ + switch (code) { + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_MSG_SCAN_REQ); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_MSG_SCAN_GET_RESULTS); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_MSG_CONNECT); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_MSG_SET_11DINFO); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_MSG_GET_SOFTAP_DOMAIN); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_MSG_SET_REGINFO); + CASE_RETURN_STRING + (TRACE_CODE_SME_RX_HDD_MSG_UPDATE_CHANNEL_CONFIG); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_MSG_UPDATE_CONFIG); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_MSG_HDDREADYIND); + CASE_RETURN_STRING + (TRACE_CODE_SME_RX_HDD_MSG_SCAN_FLUSH_RESULTS); + CASE_RETURN_STRING + (TRACE_CODE_SME_RX_HDD_MSG_SCAN_FLUSH_P2PRESULTS); + CASE_RETURN_STRING + (TRACE_CODE_SME_RX_HDD_MSG_SCAN_RESULT_GETFIRST); + CASE_RETURN_STRING + (TRACE_CODE_SME_RX_HDD_MSG_SCAN_RESULT_GETNEXT); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_MSG_SCAN_RESULT_PURGE); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_ROAM_REASSOC); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_ROAM_DISCONNECT); + CASE_RETURN_STRING + (TRACE_CODE_SME_RX_HDD_ROAM_GET_CONNECTPROFILE); + CASE_RETURN_STRING + (TRACE_CODE_SME_RX_HDD_ROAM_FREE_CONNECTPROFILE); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_ROAM_SET_PMKIDCACHE); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_ROAM_DEL_PMKIDCACHE); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_ROAM_GET_PMKIDCACHE); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_GET_CONFIGPARAM); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_GET_MODPROFFIELDS); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_SET_CONFIG_PWRSAVE); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_GET_CONFIG_PWRSAVE); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_ENABLE_PWRSAVE); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_DISABLE_PWRSAVE); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_SIGNAL_POWER_EVENT); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_START_AUTO_BMPSTIMER); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_STOP_AUTO_BMPSTIMER); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_IS_PWRSAVE_ENABLED); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_REQUEST_FULLPOWER); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_REQUEST_BMPS); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_SET_DHCP_FLAG); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_REQUEST_STANDBY); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_WOWL_ADDBCAST_PATTERN); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_WOWL_DELBCAST_PATTERN); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_ENTER_WOWL); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_EXIT_WOWL); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_SET_KEY); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_REMOVE_KEY); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_GET_STATS); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_GET_RSSI); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_GET_CNTRYCODE); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_SET_CNTRYCODE); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_CHANGE_CNTRYCODE); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_SET_CFGPRIVACY); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_NEIGHBOR_REPORTREQ); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_DBG_READREG); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_DBG_WRITEREG); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_DBG_READMEM); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_DBG_WRITEMEM); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_OPEN_SESSION); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_CLOSE_SESSION); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_SET_HOSTOFFLOAD); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_SET_GTKOFFLOAD); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_GET_GTKOFFLOAD); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_ABORT_MACSCAN); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_REGISTER_MGMTFR); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_DEREGISTER_MGMTFR); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_REMAIN_ONCHAN); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_SEND_ACTION); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_CANCEL_REMAIN_ONCHAN); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_CONFIG_RXPFIL); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_CONFIG_SUSPENDIND); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_CONFIG_RESUMEREQ); +#ifdef WLAN_FEATURE_EXTWOW_SUPPORT + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_CONFIG_EXTWOW); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_CONFIG_APP_TYPE1); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_CONFIG_APP_TYPE2); +#endif + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_SET_MAXTXPOW); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_SET_TXPOW); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_SET_TMLEVEL); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_CAPS_EXCH); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_DISABLE_CAP); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_GET_DEFCCNV); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_GET_CURCC); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_RESET_PW5G); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_UPDATE_RP5G); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_SET_ROAMIBAND); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_GET_ROAMIBAND); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_UPDATE_RSSIDIFF); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_UPDATE_IMMRSSIDIFF); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_UPDATE_FTENABLED); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_UPDATE_WESMODE); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_SET_SCANCTRL); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_UPDATE_P2P_IE); + CASE_RETURN_STRING + (TRACE_CODE_SME_RX_HDD_UPDATE_ROAM_SCAN_N_PROBES); + CASE_RETURN_STRING + (TRACE_CODE_SME_RX_HDD_UPDATE_ROAM_SCAN_HOME_AWAY_TIME); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_STORE_JOIN_REQ); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_CLEAR_JOIN_REQ); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_ISSUE_JOIN_REQ); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_MSG_DEAUTH_STA); +#ifdef FEATURE_WLAN_TDLS + CASE_RETURN_STRING + (TRACE_CODE_SME_RX_HDD_TDLS_LINK_ESTABLISH_PARAM); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_TDLS_CHAN_SWITCH_REQ); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_TDLS_SEND_MGMT_FRAME); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_TDLS_CHANGE_PEER_STA); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_TDLS_ADD_PEER_STA); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_TDLS_DEL_PEER_STA); +#endif + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_PREF_NET_LIST); +#ifdef FEATURE_WLAN_LPHB + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_LPHB_CONFIG_REQ); +#endif /* FEATURE_WLAN_LPHB */ + + default: + return "UNKNOWN"; + break; + } +} + +static uint8_t *sme_trace_get_command_string(uint32_t command) +{ + switch (command) { + CASE_RETURN_STRING(eSmeNoCommand); + CASE_RETURN_STRING(eSmeDropCommand); + CASE_RETURN_STRING(eSmeCsrCommandMask); + CASE_RETURN_STRING(eSmeCommandScan); + CASE_RETURN_STRING(eSmeCommandRoam); + CASE_RETURN_STRING(eSmeCommandWmStatusChange); + CASE_RETURN_STRING(eSmeCommandSetKey); + CASE_RETURN_STRING(eSmeCommandAddStaSession); + CASE_RETURN_STRING(eSmeCommandDelStaSession); +#ifdef FEATURE_WLAN_TDLS + CASE_RETURN_STRING(eSmeCommandTdlsSendMgmt); + CASE_RETURN_STRING(eSmeCommandTdlsAddPeer); + CASE_RETURN_STRING(eSmeCommandTdlsDelPeer); + CASE_RETURN_STRING(eSmeCommandTdlsLinkEstablish); +#endif + CASE_RETURN_STRING(eSmePmcCommandMask); + CASE_RETURN_STRING(eSmeCommandEnterBmps); + CASE_RETURN_STRING(eSmeCommandExitBmps); + CASE_RETURN_STRING(eSmeCommandEnterUapsd); + CASE_RETURN_STRING(eSmeCommandExitUapsd); + CASE_RETURN_STRING(eSmeCommandExitWowl); + CASE_RETURN_STRING(eSmeCommandEnterStandby); + CASE_RETURN_STRING(eSmeQosCommandMask); + CASE_RETURN_STRING(eSmeCommandAddTs); + CASE_RETURN_STRING(eSmeCommandDelTs); +#ifdef FEATURE_OEM_DATA_SUPPORT + CASE_RETURN_STRING(eSmeCommandOemDataReq); +#endif + CASE_RETURN_STRING(eSmeCommandRemainOnChannel); + CASE_RETURN_STRING(e_sme_command_set_hw_mode); + CASE_RETURN_STRING(e_sme_command_nss_update); + CASE_RETURN_STRING(e_sme_command_set_dual_mac_config); + CASE_RETURN_STRING(e_sme_command_set_antenna_mode); + CASE_RETURN_STRING(eSmeCommandNdpInitiatorRequest); + CASE_RETURN_STRING(eSmeCommandNdpResponderRequest); + CASE_RETURN_STRING(eSmeCommandNdpDataEndInitiatorRequest); + default: + return "UNKNOWN"; + break; + } +} + +static void sme_trace_dump(tpAniSirGlobal mac_ctx, tp_qdf_trace_record record, + uint16_t rec_index) +{ + switch (record->code) { + case TRACE_CODE_SME_COMMAND: + sms_log(mac_ctx, LOG1, "%04d %012llu %s S%d %-14s %-30s(0x%x)", + rec_index, record->qtime, record->time, record->session, + "SME COMMAND:", + sme_trace_get_command_string(record->data), + record->data); + break; + case TRACE_CODE_SME_TX_WMA_MSG: + sms_log(mac_ctx, LOG1, "%04d %012llu %s S%d %-14s %-30s(0x%x)", + rec_index, record->qtime, record->time, record->session, + "TX WMA Msg:", + mac_trace_get_wma_msg_string((uint16_t)record->data), + record->data); + break; + case TRACE_CODE_SME_RX_WMA_MSG: + sms_log(mac_ctx, LOG1, "%04d %012llu %s S%d %-14s %-30s(0x%x)", + rec_index, record->qtime, record->time, record->session, + "RX WMA Msg:", + mac_trace_get_sme_msg_string((uint16_t)record->data), + record->data); + break; + default: + sms_log(mac_ctx, LOG1, "%04d %012llu %s S%d %-14s %-30s(0x%x)", + rec_index, record->qtime, record->time, record->session, + "RX HDD MSG:", + sme_trace_get_rx_msg_string(record->code), + record->data); + break; + } +} + +void sme_trace_init(tpAniSirGlobal pMac) +{ + qdf_trace_register(QDF_MODULE_ID_SME, (tp_qdf_trace_cb) &sme_trace_dump); +} +#endif diff --git a/drivers/staging/qcacld-3.0/core/sme/src/csr/csr_api_roam.c b/drivers/staging/qcacld-3.0/core/sme/src/csr/csr_api_roam.c new file mode 100644 index 0000000000000000000000000000000000000000..3523500e70ca85a869b6deb6a069ac00d1507160 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/sme/src/csr/csr_api_roam.c @@ -0,0 +1,20410 @@ +/* + * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** ------------------------------------------------------------------------- * + ------------------------------------------------------------------------- * + + \file csr_api_roam.c + + Implementation for the Common Roaming interfaces. + ========================================================================== */ +#include "ani_global.h" /* for tpAniSirGlobal */ +#include "wma_types.h" +#include "wma_if.h" /* for STA_INVALID_IDX. */ +#include "cds_mq.h" +#include "csr_inside_api.h" +#include "sms_debug.h" +#include "sme_trace.h" +#include "sme_qos_internal.h" +#include "sme_inside.h" +#include "host_diag_core_event.h" +#include "host_diag_core_log.h" +#include "csr_api.h" +#include "csr_internal.h" +#include "cds_reg_service.h" +#include "mac_trace.h" +#include "csr_neighbor_roam.h" +#include "cds_regdomain.h" +#include "cds_utils.h" +#include "sir_types.h" +#include "cfg_api.h" +#include "sme_power_save_api.h" +#include "wma.h" +#include "cds_concurrency.h" +#include "sme_nan_datapath.h" +#include "pld_common.h" +#include + +#define MAX_PWR_FCC_CHAN_12 8 +#define MAX_PWR_FCC_CHAN_13 2 + +#define CSR_NUM_IBSS_START_CHANNELS_50 4 +#define CSR_NUM_IBSS_START_CHANNELS_24 3 +/* 75 seconds, for WPA, WPA2, CCKM */ +#define CSR_WAIT_FOR_KEY_TIMEOUT_PERIOD (75 * QDF_MC_TIMER_TO_SEC_UNIT) +/* 120 seconds, for WPS */ +#define CSR_WAIT_FOR_WPS_KEY_TIMEOUT_PERIOD (120 * QDF_MC_TIMER_TO_SEC_UNIT) + +/*--------------------------------------------------------------------------- + OBIWAN recommends [8 10]% : pick 9% + ---------------------------------------------------------------------------*/ +#define CSR_VCC_UL_MAC_LOSS_THRESHOLD 9 +/*--------------------------------------------------------------------------- + OBIWAN recommends -85dBm + ---------------------------------------------------------------------------*/ +#define CSR_VCC_RSSI_THRESHOLD 80 +#define CSR_MIN_GLOBAL_STAT_QUERY_PERIOD 500 /* ms */ +#define CSR_MIN_GLOBAL_STAT_QUERY_PERIOD_IN_BMPS 2000 /* ms */ +#define CSR_MIN_TL_STAT_QUERY_PERIOD 500 /* ms */ +/* Flag to send/do not send disassoc frame over the air */ +#define CSR_DONT_SEND_DISASSOC_OVER_THE_AIR 1 +#define RSSI_HACK_BMPS (-40) +#define MAX_CB_VALUE_IN_INI (2) + +#define MAX_SOCIAL_CHANNELS 3 + +/* packet dump timer duration of 60 secs */ +#define PKT_DUMP_TIMER_DURATION 60 + +/* Choose the largest possible value that can be accomodates in 8 bit signed */ +/* variable. */ +#define SNR_HACK_BMPS (127) + +/* + * ROAMING_OFFLOAD_TIMER_START - Indicates the action to start the timer + * ROAMING_OFFLOAD_TIMER_STOP - Indicates the action to stop the timer + * CSR_ROAMING_OFFLOAD_TIMEOUT_PERIOD - Timeout value for roaming offload timer + */ +#define ROAMING_OFFLOAD_TIMER_START 1 +#define ROAMING_OFFLOAD_TIMER_STOP 2 +#define CSR_ROAMING_OFFLOAD_TIMEOUT_PERIOD (5 * QDF_MC_TIMER_TO_SEC_UNIT) + +static bool b_roam_scan_offload_started; + +/*-------------------------------------------------------------------------- + Static Type declarations + ------------------------------------------------------------------------*/ +static tCsrRoamSession csr_roam_roam_session[CSR_ROAM_SESSION_MAX]; + +#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR +int diag_auth_type_from_csr_type(eCsrAuthType authType) +{ + int n = AUTH_OPEN; + switch (authType) { + case eCSR_AUTH_TYPE_SHARED_KEY: + n = AUTH_SHARED; + break; + case eCSR_AUTH_TYPE_WPA: + n = AUTH_WPA_EAP; + break; + case eCSR_AUTH_TYPE_WPA_PSK: + n = AUTH_WPA_PSK; + break; + case eCSR_AUTH_TYPE_RSN: +#ifdef WLAN_FEATURE_11W + case eCSR_AUTH_TYPE_RSN_8021X_SHA256: +#endif + n = AUTH_WPA2_EAP; + break; + case eCSR_AUTH_TYPE_RSN_PSK: +#ifdef WLAN_FEATURE_11W + case eCSR_AUTH_TYPE_RSN_PSK_SHA256: +#endif + n = AUTH_WPA2_PSK; + break; +#ifdef FEATURE_WLAN_WAPI + case eCSR_AUTH_TYPE_WAPI_WAI_CERTIFICATE: + n = AUTH_WAPI_CERT; + break; + case eCSR_AUTH_TYPE_WAPI_WAI_PSK: + n = AUTH_WAPI_PSK; + break; +#endif /* FEATURE_WLAN_WAPI */ + default: + break; + } + return n; +} + +int diag_enc_type_from_csr_type(eCsrEncryptionType encType) +{ + int n = ENC_MODE_OPEN; + switch (encType) { + case eCSR_ENCRYPT_TYPE_WEP40_STATICKEY: + case eCSR_ENCRYPT_TYPE_WEP40: + n = ENC_MODE_WEP40; + break; + case eCSR_ENCRYPT_TYPE_WEP104_STATICKEY: + case eCSR_ENCRYPT_TYPE_WEP104: + n = ENC_MODE_WEP104; + break; + case eCSR_ENCRYPT_TYPE_TKIP: + n = ENC_MODE_TKIP; + break; + case eCSR_ENCRYPT_TYPE_AES: + n = ENC_MODE_AES; + break; +#ifdef FEATURE_WLAN_WAPI + case eCSR_ENCRYPT_TYPE_WPI: + n = ENC_MODE_SMS4; + break; +#endif /* FEATURE_WLAN_WAPI */ + default: + break; + } + return n; +} +#endif /* #ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR */ +static const uint8_t + csr_start_ibss_channels50[CSR_NUM_IBSS_START_CHANNELS_50] = { 36, 40, 44, 48 }; +static const uint8_t + csr_start_ibss_channels24[CSR_NUM_IBSS_START_CHANNELS_24] = { 1, 6, 11 }; +static void init_config_param(tpAniSirGlobal pMac); +static bool csr_roam_process_results(tpAniSirGlobal pMac, tSmeCmd *pCommand, + eCsrRoamCompleteResult Result, + void *Context); +static QDF_STATUS csr_roam_start_ibss(tpAniSirGlobal pMac, uint32_t sessionId, + tCsrRoamProfile *pProfile, + bool *pfSameIbss); +static void csr_roam_update_connected_profile_from_new_bss(tpAniSirGlobal pMac, + uint32_t sessionId, + tSirSmeNewBssInfo * + pNewBss); +static ePhyChanBondState csr_get_cb_mode_from_ies(tpAniSirGlobal pMac, + uint8_t primaryChn, + tDot11fBeaconIEs *pIes); + +static void csr_roaming_state_config_cnf_processor(tpAniSirGlobal pMac, + uint32_t result); +QDF_STATUS csr_roam_open(tpAniSirGlobal pMac); +QDF_STATUS csr_roam_close(tpAniSirGlobal pMac); +void csr_roamMICErrorTimerHandler(void *pv); +void csr_roamTKIPCounterMeasureTimerHandler(void *pv); +bool csr_roam_is_same_profile_keys(tpAniSirGlobal pMac, + tCsrRoamConnectedProfile *pConnProfile, + tCsrRoamProfile *pProfile2); + +static QDF_STATUS csr_roam_start_roaming_timer(tpAniSirGlobal pMac, + uint32_t sessionId, + uint32_t interval); +static QDF_STATUS csr_roam_stop_roaming_timer(tpAniSirGlobal pMac, + uint32_t sessionId); +static void csr_roam_roaming_timer_handler(void *pv); +static void csr_roam_roaming_offload_timer_action(tpAniSirGlobal mac_ctx, + uint32_t interval, uint8_t session_id, uint8_t action); +static void csr_roam_roaming_offload_timeout_handler(void *timer_data); +QDF_STATUS csr_roam_start_wait_for_key_timer(tpAniSirGlobal pMac, uint32_t interval); +static void csr_roam_wait_for_key_time_out_handler(void *pv); +static QDF_STATUS csr_init11d_info(tpAniSirGlobal pMac, tCsr11dinfo *ps11dinfo); +static QDF_STATUS csr_init_channel_power_list(tpAniSirGlobal pMac, + tCsr11dinfo *ps11dinfo); +static QDF_STATUS csr_roam_free_connected_info(tpAniSirGlobal pMac, + tCsrRoamConnectedInfo * + pConnectedInfo); +QDF_STATUS csr_send_mb_set_context_req_msg(tpAniSirGlobal pMac, uint32_t sessionId, + struct qdf_mac_addr peer_macaddr, + uint8_t numKeys, + tAniEdType edType, bool fUnicast, + tAniKeyDirection aniKeyDirection, + uint8_t keyId, uint8_t keyLength, + uint8_t *pKey, uint8_t paeRole, + uint8_t *pKeyRsc); +void csr_roamStatisticsTimerHandler(void *pv); +void csr_roamStatsGlobalClassDTimerHandler(void *pv); +static void csr_roam_link_up(tpAniSirGlobal pMac, struct qdf_mac_addr bssid); +static void csr_roam_link_down(tpAniSirGlobal pMac, uint32_t sessionId); +void csr_roam_vcc_trigger(tpAniSirGlobal pMac); +QDF_STATUS csr_send_mb_stats_req_msg(tpAniSirGlobal pMac, uint32_t statsMask, + uint8_t staId, uint8_t sessionId); +/* + pStaEntry is no longer invalid upon the return of this function. + */ +static void csr_roam_remove_stat_list_entry(tpAniSirGlobal pMac, tListElem *pEntry); +static eCsrCfgDot11Mode csr_roam_get_phy_mode_band_for_bss(tpAniSirGlobal pMac, + tCsrRoamProfile *pProfile, + uint8_t operationChn, + eCsrBand *pBand); +static QDF_STATUS csr_roam_get_qos_info_from_bss(tpAniSirGlobal pMac, + tSirBssDescription *pBssDesc); +tCsrStatsClientReqInfo *csr_roam_insert_entry_into_list(tpAniSirGlobal pMac, + tDblLinkList *pStaList, + tCsrStatsClientReqInfo * + pStaEntry); +void csr_roam_stats_client_timer_handler(void *pv); +tCsrPeStatsReqInfo *csr_roam_check_pe_stats_req_list(tpAniSirGlobal pMac, + uint32_t statsMask, + uint32_t periodicity, + bool *pFound, uint8_t staId, + uint8_t sessionId); +void csr_roam_report_statistics(tpAniSirGlobal pMac, uint32_t statsMask, + tCsrStatsCallback callback, uint8_t staId, + void *pContext); +void csr_roam_tl_stats_timer_handler(void *pv); +void csr_roam_pe_stats_timer_handler(void *pv); +tListElem *csr_roam_check_client_req_list(tpAniSirGlobal pMac, uint32_t statsMask); +void csr_roam_remove_entry_from_pe_stats_req_list(tpAniSirGlobal pMac, + tCsrPeStatsReqInfo *pPeStaEntry); +tListElem *csr_roam_find_in_pe_stats_req_list(tpAniSirGlobal pMac, uint32_t statsMask); +QDF_STATUS csr_roam_dereg_statistics_req(tpAniSirGlobal pMac); +static uint32_t csr_find_ibss_session(tpAniSirGlobal pMac); +static uint32_t csr_find_session_by_type(tpAniSirGlobal, + enum tQDF_ADAPTER_MODE); +static bool csr_is_conn_allow_2g_band(tpAniSirGlobal pMac, uint32_t chnl); +static bool csr_is_conn_allow_5g_band(tpAniSirGlobal pMac, uint32_t chnl); +static QDF_STATUS csr_roam_start_wds(tpAniSirGlobal pMac, uint32_t sessionId, + tCsrRoamProfile *pProfile, + tSirBssDescription *pBssDesc); +static void csr_init_session(tpAniSirGlobal pMac, uint32_t sessionId); +static QDF_STATUS csr_roam_issue_set_key_command(tpAniSirGlobal pMac, + uint32_t sessionId, + tCsrRoamSetKey *pSetKey, + uint32_t roamId); +static QDF_STATUS csr_roam_get_qos_info_from_bss(tpAniSirGlobal pMac, + tSirBssDescription *pBssDesc); +void csr_roam_reissue_roam_command(tpAniSirGlobal pMac); +static void csr_ser_des_unpack_diassoc_rsp(uint8_t *pBuf, + tSirSmeDisassocRsp *pRsp); +void csr_init_operating_classes(tHalHandle hHal); + +/* Initialize global variables */ +static void csr_roam_init_globals(tpAniSirGlobal pMac) +{ + if (pMac) { + qdf_mem_zero(&csr_roam_roam_session, sizeof(csr_roam_roam_session)); + pMac->roam.roamSession = csr_roam_roam_session; + } + return; +} + +static void csr_roam_de_init_globals(tpAniSirGlobal pMac) +{ + uint8_t i; + if (pMac) { + for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) { + if (pMac->roam.roamSession[i].pCurRoamProfile) + csr_release_profile(pMac, + pMac->roam.roamSession[i]. + pCurRoamProfile); + csr_release_profile(pMac, + &pMac->roam.roamSession[i]. + stored_roam_profile.profile); + } + pMac->roam.roamSession = NULL; + } + return; +} + +QDF_STATUS csr_open(tpAniSirGlobal pMac) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + uint32_t i; + + do { + /* Initialize CSR Roam Globals */ + csr_roam_init_globals(pMac); + for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) + csr_roam_state_change(pMac, eCSR_ROAMING_STATE_STOP, i); + + init_config_param(pMac); + status = csr_scan_open(pMac); + if (!QDF_IS_STATUS_SUCCESS(status)) + break; + status = csr_roam_open(pMac); + if (!QDF_IS_STATUS_SUCCESS(status)) + break; + pMac->roam.nextRoamId = 1; /* Must not be 0 */ + if (!QDF_IS_STATUS_SUCCESS + (csr_ll_open(pMac->hHdd, + &pMac->roam.statsClientReqList))) + break; + if (!QDF_IS_STATUS_SUCCESS + (csr_ll_open(pMac->hHdd, + &pMac->roam.peStatsReqList))) + break; + if (!QDF_IS_STATUS_SUCCESS + (csr_ll_open(pMac->hHdd, + &pMac->roam.roamCmdPendingList))) + break; + } while (0); + + return status; +} + +QDF_STATUS csr_init_chan_list(tpAniSirGlobal mac, uint8_t *alpha2) +{ + QDF_STATUS status; + + mac->scan.countryCodeDefault[0] = alpha2[0]; + mac->scan.countryCodeDefault[1] = alpha2[1]; + mac->scan.countryCodeDefault[2] = alpha2[2]; + + sms_log(mac, LOG1, FL("init time country code %.2s"), + mac->scan.countryCodeDefault); + + mac->scan.domainIdDefault = 0; + mac->scan.domainIdCurrent = 0; + + qdf_mem_copy(mac->scan.countryCodeCurrent, + mac->scan.countryCodeDefault, WNI_CFG_COUNTRY_CODE_LEN); + qdf_mem_copy(mac->scan.countryCodeElected, + mac->scan.countryCodeDefault, WNI_CFG_COUNTRY_CODE_LEN); + status = csr_get_channel_and_power_list(mac); + csr_clear_votes_for_country_info(mac); + return status; +} + +QDF_STATUS csr_set_reg_info(tHalHandle hHal, uint8_t *apCntryCode) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + v_REGDOMAIN_t regId; + uint8_t cntryCodeLength; + if (NULL == apCntryCode) { + sms_log(pMac, LOGE, FL(" Invalid country Code Pointer")); + return QDF_STATUS_E_FAILURE; + } + sms_log(pMac, LOG1, FL(" country Code %.2s"), apCntryCode); + + cntryCodeLength = WNI_CFG_COUNTRY_CODE_LEN; + status = csr_get_regulatory_domain_for_country(pMac, apCntryCode, ®Id, + SOURCE_USERSPACE); + if (status != QDF_STATUS_SUCCESS) { + sms_log(pMac, LOGE, + FL(" fail to get regId for country Code %.2s"), + apCntryCode); + return status; + } + status = wma_set_reg_domain(hHal, regId); + if (status != QDF_STATUS_SUCCESS) { + sms_log(pMac, LOGE, + FL(" fail to get regId for country Code %.2s"), + apCntryCode); + return status; + } + pMac->scan.domainIdDefault = regId; + pMac->scan.domainIdCurrent = pMac->scan.domainIdDefault; + /* Clear CC field */ + qdf_mem_set(pMac->scan.countryCodeDefault, WNI_CFG_COUNTRY_CODE_LEN, 0); + + /* Copy 2 or 3 bytes country code */ + qdf_mem_copy(pMac->scan.countryCodeDefault, apCntryCode, + cntryCodeLength); + + /* If 2 bytes country code, 3rd byte must be filled with space */ + if ((WNI_CFG_COUNTRY_CODE_LEN - 1) == cntryCodeLength) { + qdf_mem_set(pMac->scan.countryCodeDefault + 2, 1, 0x20); + } + qdf_mem_copy(pMac->scan.countryCodeCurrent, + pMac->scan.countryCodeDefault, WNI_CFG_COUNTRY_CODE_LEN); + status = csr_get_channel_and_power_list(pMac); + return status; +} + +QDF_STATUS csr_set_channels(tHalHandle hHal, tCsrConfigParam *pParam) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + uint8_t index = 0; + qdf_mem_copy(pParam->Csr11dinfo.countryCode, + pMac->scan.countryCodeCurrent, WNI_CFG_COUNTRY_CODE_LEN); + for (index = 0; index < pMac->scan.base_channels.numChannels; + index++) { + pParam->Csr11dinfo.Channels.channelList[index] = + pMac->scan.base_channels.channelList[index]; + pParam->Csr11dinfo.ChnPower[index].firstChannel = + pMac->scan.base_channels.channelList[index]; + pParam->Csr11dinfo.ChnPower[index].numChannels = 1; + pParam->Csr11dinfo.ChnPower[index].maxtxPower = + pMac->scan.defaultPowerTable[index].power; + } + pParam->Csr11dinfo.Channels.numChannels = + pMac->scan.base_channels.numChannels; + + return status; +} + +QDF_STATUS csr_close(tpAniSirGlobal pMac) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tSmeCmd *saved_scan_cmd; + + csr_roam_close(pMac); + csr_scan_close(pMac); + csr_ll_close(&pMac->roam.statsClientReqList); + csr_ll_close(&pMac->roam.peStatsReqList); + csr_ll_close(&pMac->roam.roamCmdPendingList); + saved_scan_cmd = (tSmeCmd *)pMac->sme.saved_scan_cmd; + if (saved_scan_cmd) { + csr_release_profile(pMac, saved_scan_cmd->u.scanCmd. + pToRoamProfile); + if (saved_scan_cmd->u.scanCmd.pToRoamProfile) { + qdf_mem_free(saved_scan_cmd->u.scanCmd.pToRoamProfile); + saved_scan_cmd->u.scanCmd.pToRoamProfile = NULL; + } + if (saved_scan_cmd->u.scanCmd.u.scanRequest.SSIDs.SSIDList) { + qdf_mem_free(saved_scan_cmd->u.scanCmd.u.scanRequest. + SSIDs.SSIDList); + saved_scan_cmd->u.scanCmd.u.scanRequest.SSIDs. + SSIDList = NULL; + } + if (saved_scan_cmd->u.roamCmd.pRoamBssEntry) { + qdf_mem_free(saved_scan_cmd->u.roamCmd.pRoamBssEntry); + saved_scan_cmd->u.roamCmd.pRoamBssEntry = NULL; + } + qdf_mem_free(saved_scan_cmd); + saved_scan_cmd = NULL; + } + /* DeInit Globals */ + csr_roam_de_init_globals(pMac); + return status; +} + +static int8_t csr_find_channel_pwr(struct channel_power * + pdefaultPowerTable, + uint8_t ChannelNum) +{ + uint8_t i; + /* TODO: if defaultPowerTable is guaranteed to be in ascending */ + /* order of channel numbers, we can employ binary search */ + for (i = 0; i < WNI_CFG_VALID_CHANNEL_LIST_LEN; i++) { + if (pdefaultPowerTable[i].chan_num == ChannelNum) + return pdefaultPowerTable[i].power; + } + /* could not find the channel list in default list */ + /* this should not have occured */ + QDF_ASSERT(0); + return 0; +} + +/** + * csr_roam_arrange_ch_list() - Updates the channel list modified with greedy + * order for 5 Ghz preference and DFS channels. + * @mac_ctx: pointer to mac context. + * @chan_list: channel list updated with greedy channel order. + * @num_channel: Number of channels in list + * + * To allow Early Stop Roaming Scan feature to co-exist with 5G preference, + * this function moves 5G channels ahead of 2G channels. This function can + * also move 2G channels, ahead of DFS channel or vice versa. Order is + * maintained among same category channels + * + * Return: None + */ +static void csr_roam_arrange_ch_list(tpAniSirGlobal mac_ctx, + tSirUpdateChanParam *chan_list, uint8_t num_channel) +{ + bool prefer_5g = CSR_IS_ROAM_PREFER_5GHZ(mac_ctx); + bool prefer_dfs = CSR_IS_DFS_CH_ROAM_ALLOWED(mac_ctx); + int i, j = 0; + tSirUpdateChanParam *tmp_list = NULL; + + if (!prefer_5g) + return; + + tmp_list = (tSirUpdateChanParam *) + qdf_mem_malloc(sizeof(tSirUpdateChanParam) * num_channel); + if (tmp_list == NULL) { + sms_log(mac_ctx, LOGE, FL("Memory allocation failed")); + return; + } + + /* Fist copy Non-DFS 5g channels */ + for (i = 0; i < num_channel; i++) { + if (CDS_IS_CHANNEL_5GHZ(chan_list[i].chanId) && + !CDS_IS_DFS_CH(chan_list[i].chanId)) { + qdf_mem_copy(&tmp_list[j++], + &chan_list[i], sizeof(tSirUpdateChanParam)); + chan_list[i].chanId = INVALID_CHANNEL_ID; + } + } + if (prefer_dfs) { + /* next copy DFS channels (remaining channels in 5G) */ + for (i = 0; i < num_channel; i++) { + if (CDS_IS_CHANNEL_5GHZ(chan_list[i].chanId)) { + qdf_mem_copy(&tmp_list[j++], &chan_list[i], + sizeof(tSirUpdateChanParam)); + chan_list[i].chanId = INVALID_CHANNEL_ID; + } + } + } else { + /* next copy 2G channels */ + for (i = 0; i < num_channel; i++) { + if (CDS_IS_CHANNEL_24GHZ(chan_list[i].chanId)) { + qdf_mem_copy(&tmp_list[j++], &chan_list[i], + sizeof(tSirUpdateChanParam)); + chan_list[i].chanId = INVALID_CHANNEL_ID; + } + } + } + /* copy rest of the channels in same order to tmp list */ + for (i = 0; i < num_channel; i++) { + if (chan_list[i].chanId != INVALID_CHANNEL_ID) { + qdf_mem_copy(&tmp_list[j++], &chan_list[i], + sizeof(tSirUpdateChanParam)); + chan_list[i].chanId = INVALID_CHANNEL_ID; + } + } + /* copy tmp list to original channel list buffer */ + qdf_mem_copy(chan_list, tmp_list, + sizeof(tSirUpdateChanParam) * num_channel); + qdf_mem_free(tmp_list); +} + +/** + * csr_roam_sort_channel_for_early_stop() - Sort the channels + * @mac_ctx: mac global context + * @chan_list: Original channel list from the upper layers + * @num_channel: Number of original channels + * + * For Early stop scan feature, the channel list should be in an order, + * where-in there is a maximum chance to detect an AP in the initial + * channels in the list so that the scanning can be stopped early as the + * feature demands. + * Below fixed greedy channel list has been provided + * based on most of the enterprise wifi installations across the globe. + * + * Identify all the greedy channels within the channel list from user space. + * Identify all the non-greedy channels in the user space channel list. + * Merge greedy channels followed by non-greedy channels back into the + * chan_list. + * + * Return: None + */ +static void csr_roam_sort_channel_for_early_stop(tpAniSirGlobal mac_ctx, + tSirUpdateChanList *chan_list, uint8_t num_channel) +{ + tSirUpdateChanList *chan_list_greedy, *chan_list_non_greedy; + uint8_t i, j; + static const uint8_t fixed_greedy_chan_list[] = {1, 6, 11, 36, 48, 40, + 44, 10, 2, 9, 149, 157, 161, 3, 4, 8, 153, 165, 7, 5, 136, 140, + 52, 116, 56, 104, 64, 60, 100, 120, 13, 14, 112, 132, 151, 155}; + uint8_t num_fixed_greedy_chan; + uint8_t num_greedy_chan = 0; + uint8_t num_non_greedy_chan = 0; + uint8_t match_found = false; + uint32_t buf_size; + + buf_size = sizeof(tSirUpdateChanList) + + (sizeof(tSirUpdateChanParam) * num_channel); + chan_list_greedy = qdf_mem_malloc(buf_size); + chan_list_non_greedy = qdf_mem_malloc(buf_size); + if (!chan_list_greedy || !chan_list_non_greedy) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "Failed to allocate memory for tSirUpdateChanList"); + return; + } + /* + * fixed_greedy_chan_list is an evaluated channel list based on most of + * the enterprise wifi deployments and the order of the channels + * determines the highest possibility of finding an AP. + * chan_list is the channel list provided by upper layers based on the + * regulatory domain. + */ + num_fixed_greedy_chan = sizeof(fixed_greedy_chan_list)/sizeof(uint8_t); + /* + * Browse through the chan_list and put all the non-greedy channels + * into a seperate list by name chan_list_non_greedy + */ + for (i = 0; i < num_channel; i++) { + for (j = 0; j < num_fixed_greedy_chan; j++) { + if (chan_list->chanParam[i].chanId == + fixed_greedy_chan_list[j]) { + match_found = true; + break; + } + } + if (!match_found) { + qdf_mem_copy( + &chan_list_non_greedy->chanParam[num_non_greedy_chan], + &chan_list->chanParam[i], + sizeof(tSirUpdateChanParam)); + num_non_greedy_chan++; + } else { + match_found = false; + } + } + /* + * Browse through the fixed_greedy_chan_list and put all the greedy + * channels in the chan_list into a seperate list by name + * chan_list_greedy + */ + for (i = 0; i < num_fixed_greedy_chan; i++) { + for (j = 0; j < num_channel; j++) { + if (fixed_greedy_chan_list[i] == + chan_list->chanParam[j].chanId) { + qdf_mem_copy( + &chan_list_greedy->chanParam[num_greedy_chan], + &chan_list->chanParam[j], + sizeof(tSirUpdateChanParam)); + num_greedy_chan++; + break; + } + } + } + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_DEBUG, + "greedy=%d, non-greedy=%d, tot=%d", + num_greedy_chan, num_non_greedy_chan, num_channel); + if ((num_greedy_chan + num_non_greedy_chan) != num_channel) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "incorrect sorting of channels"); + goto scan_list_sort_error; + } + /* Copy the Greedy channels first */ + i = 0; + qdf_mem_copy(&chan_list->chanParam[i], + &chan_list_greedy->chanParam[i], + num_greedy_chan * sizeof(tSirUpdateChanParam)); + /* Copy the remaining Non Greedy channels */ + i = num_greedy_chan; + j = 0; + qdf_mem_copy(&chan_list->chanParam[i], + &chan_list_non_greedy->chanParam[j], + num_non_greedy_chan * sizeof(tSirUpdateChanParam)); + + /* Update channel list for 5g preference and allow DFS roam */ + csr_roam_arrange_ch_list(mac_ctx, chan_list->chanParam, num_channel); +scan_list_sort_error: + qdf_mem_free(chan_list_greedy); + qdf_mem_free(chan_list_non_greedy); +} + +QDF_STATUS csr_update_channel_list(tpAniSirGlobal pMac) +{ + tSirUpdateChanList *pChanList; + tCsrScanStruct *pScan = &pMac->scan; + uint8_t numChan = pScan->base_channels.numChannels; + uint8_t num_channel = 0; + uint32_t bufLen; + cds_msg_t msg; + uint8_t i, j, social_channel[MAX_SOCIAL_CHANNELS] = { 1, 6, 11 }; + uint8_t channel_state; + uint16_t unsafe_chan[NUM_CHANNELS]; + uint16_t unsafe_chan_cnt = 0; + uint16_t cnt = 0; + uint8_t channel; + bool is_unsafe_chan; + qdf_device_t qdf_ctx = cds_get_context(QDF_MODULE_ID_QDF_DEVICE); + + if (!qdf_ctx) { + cds_err("qdf_ctx is NULL"); + return QDF_STATUS_E_FAILURE; + } + + pld_get_wlan_unsafe_channel(qdf_ctx->dev, unsafe_chan, + &unsafe_chan_cnt, + sizeof(unsafe_chan)); + + if (CSR_IS_5G_BAND_ONLY(pMac)) { + for (i = 0; i < MAX_SOCIAL_CHANNELS; i++) { + if (cds_get_channel_state(social_channel[i]) + == CHANNEL_STATE_ENABLE) + numChan++; + } + } + + bufLen = sizeof(tSirUpdateChanList) + + (sizeof(tSirUpdateChanParam) * (numChan)); + + csr_init_operating_classes((tHalHandle) pMac); + pChanList = (tSirUpdateChanList *) qdf_mem_malloc(bufLen); + if (!pChanList) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "Failed to allocate memory for tSirUpdateChanList"); + return QDF_STATUS_E_NOMEM; + } + + for (i = 0; i < pScan->base_channels.numChannels; i++) { + struct csr_sta_roam_policy_params *roam_policy = + &pMac->roam.configParam.sta_roam_policy; + /* Scan is not performed on DSRC channels*/ + if (pScan->base_channels.channelList[i] >= CDS_MIN_11P_CHANNEL) + continue; + channel = pScan->base_channels.channelList[i]; + + channel_state = + cds_get_channel_state( + pScan->base_channels.channelList[i]); + if ((CHANNEL_STATE_ENABLE == channel_state) || + pMac->scan.fEnableDFSChnlScan) { + if ((pMac->roam.configParam.sta_roam_policy.dfs_mode == + CSR_STA_ROAM_POLICY_DFS_DISABLED) && + (channel_state == CHANNEL_STATE_DFS)) { + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_INFO, + FL("skip dfs channel %d"), + channel); + continue; + } + if (pMac->roam.configParam.sta_roam_policy. + skip_unsafe_channels && + unsafe_chan_cnt) { + is_unsafe_chan = false; + for (cnt = 0; cnt < unsafe_chan_cnt; cnt++) { + if (unsafe_chan[cnt] == channel) { + is_unsafe_chan = true; + break; + } + } + if ((is_unsafe_chan) && + ((CDS_IS_CHANNEL_24GHZ(channel) && + roam_policy->sap_operating_band == + eCSR_BAND_24) || + (CDS_IS_CHANNEL_5GHZ(channel) && + roam_policy->sap_operating_band == + eCSR_BAND_5G))) { + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_INFO, + FL("ignoring unsafe channel %d"), + channel); + continue; + } + } + pChanList->chanParam[num_channel].chanId = + pScan->base_channels.channelList[i]; + pChanList->chanParam[num_channel].pwr = + csr_find_channel_pwr(pScan->defaultPowerTable, + pChanList->chanParam[num_channel].chanId); + + if (pScan->fcc_constraint) { + if (12 == pChanList->chanParam[num_channel].chanId) { + pChanList->chanParam[num_channel].pwr = + MAX_PWR_FCC_CHAN_12; + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_INFO, + "txpow for channel 12 is %d", + MAX_PWR_FCC_CHAN_12); + } + if (13 == pChanList->chanParam[num_channel].chanId) { + pChanList->chanParam[num_channel].pwr = + MAX_PWR_FCC_CHAN_13; + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_INFO, + "txpow for channel 13 is %d", + MAX_PWR_FCC_CHAN_13); + } + } + + + if (CHANNEL_STATE_ENABLE == channel_state) + pChanList->chanParam[num_channel].dfsSet = + false; + else + pChanList->chanParam[num_channel].dfsSet = + true; + if (cds_is_5_mhz_enabled()) + pChanList->chanParam[num_channel].quarter_rate + = 1; + else if (cds_is_10_mhz_enabled()) + pChanList->chanParam[num_channel].half_rate = 1; + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO, + "channel:%d, pwr=%d, DFS=%d qrate %d hrate %d ", + pChanList->chanParam[num_channel].chanId, + pChanList->chanParam[num_channel].pwr, + pChanList->chanParam[num_channel].dfsSet, + pChanList->chanParam[num_channel].quarter_rate, + pChanList->chanParam[num_channel].half_rate); + num_channel++; + } + } + + if (CSR_IS_5G_BAND_ONLY(pMac)) { + for (j = 0; j < MAX_SOCIAL_CHANNELS; j++) { + if (cds_get_channel_state(social_channel[j]) + != CHANNEL_STATE_ENABLE) + continue; + pChanList->chanParam[num_channel].chanId = + social_channel[j]; + pChanList->chanParam[num_channel].pwr = + csr_find_channel_pwr(pScan->defaultPowerTable, + social_channel[j]); + pChanList->chanParam[num_channel].dfsSet = false; + if (cds_is_5_mhz_enabled()) + pChanList->chanParam[num_channel].quarter_rate + = 1; + else if (cds_is_10_mhz_enabled()) + pChanList->chanParam[num_channel].half_rate = 1; + num_channel++; + } + } + if (pMac->roam.configParam.early_stop_scan_enable) + csr_roam_sort_channel_for_early_stop(pMac, pChanList, + num_channel); + else + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO, + FL("Early Stop Scan Feature not supported")); + + if ((pMac->roam.configParam.uCfgDot11Mode == + eCSR_CFG_DOT11_MODE_AUTO) || + (pMac->roam.configParam.uCfgDot11Mode == + eCSR_CFG_DOT11_MODE_11AC) || + (pMac->roam.configParam.uCfgDot11Mode == + eCSR_CFG_DOT11_MODE_11AC_ONLY)) { + pChanList->vht_en = true; + if (pMac->roam.configParam.enableVhtFor24GHz) + pChanList->vht_24_en = true; + } + if ((pMac->roam.configParam.uCfgDot11Mode == + eCSR_CFG_DOT11_MODE_AUTO) || + (pMac->roam.configParam.uCfgDot11Mode == + eCSR_CFG_DOT11_MODE_11N) || + (pMac->roam.configParam.uCfgDot11Mode == + eCSR_CFG_DOT11_MODE_11N_ONLY)) { + pChanList->ht_en = true; + } + msg.type = WMA_UPDATE_CHAN_LIST_REQ; + msg.reserved = 0; + msg.bodyptr = pChanList; + pChanList->numChan = num_channel; + MTRACE(qdf_trace(QDF_MODULE_ID_SME, TRACE_CODE_SME_TX_WMA_MSG, + NO_SESSION, msg.type)); + if (QDF_STATUS_SUCCESS != cds_mq_post_message(QDF_MODULE_ID_WMA, &msg)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_FATAL, + "%s: Failed to post msg to WMA", __func__); + qdf_mem_free(pChanList); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS csr_start(tpAniSirGlobal pMac) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + uint32_t i; + + do { + /* save the global cds context */ + pMac->roam.g_cds_context = cds_get_global_context(); + for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) + csr_roam_state_change(pMac, eCSR_ROAMING_STATE_IDLE, i); + + status = csr_roam_start(pMac); + if (!QDF_IS_STATUS_SUCCESS(status)) + break; + + pMac->roam.sPendingCommands = 0; + csr_scan_enable(pMac); + for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) + status = csr_neighbor_roam_init(pMac, i); + pMac->roam.tlStatsReqInfo.numClient = 0; + pMac->roam.tlStatsReqInfo.periodicity = 0; + pMac->roam.tlStatsReqInfo.timerRunning = false; + /* init the link quality indication also */ + pMac->roam.vccLinkQuality = eCSR_ROAM_LINK_QUAL_MIN_IND; + if (!QDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOGW, + " csr_start: Couldn't Init HO control blk "); + break; + } + } while (0); + return status; +} + +QDF_STATUS csr_stop(tpAniSirGlobal pMac, tHalStopType stopType) +{ + uint32_t sessionId; + + for (sessionId = 0; sessionId < CSR_ROAM_SESSION_MAX; sessionId++) { + csr_roam_close_session(pMac, sessionId, true, NULL, NULL); + } + csr_scan_disable(pMac); + pMac->scan.fCancelIdleScan = false; + pMac->scan.fRestartIdleScan = false; + csr_ll_purge(&pMac->roam.roamCmdPendingList, true); + + for (sessionId = 0; sessionId < CSR_ROAM_SESSION_MAX; sessionId++) + csr_neighbor_roam_close(pMac, sessionId); + for (sessionId = 0; sessionId < CSR_ROAM_SESSION_MAX; sessionId++) + if (CSR_IS_SESSION_VALID(pMac, sessionId)) + csr_scan_flush_result(pMac); + + /* Reset the domain back to the deault */ + pMac->scan.domainIdCurrent = pMac->scan.domainIdDefault; + + for (sessionId = 0; sessionId < CSR_ROAM_SESSION_MAX; sessionId++) { + csr_roam_state_change(pMac, eCSR_ROAMING_STATE_STOP, sessionId); + pMac->roam.curSubState[sessionId] = eCSR_ROAM_SUBSTATE_NONE; + } + + /* When HAL resets all the context information + * in HAL is lost, so we might need to send the + * scan offload request again when it comes + * out of reset for scan offload to be functional + */ + if (HAL_STOP_TYPE_SYS_RESET == stopType) { + b_roam_scan_offload_started = false; + } + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS csr_ready(tpAniSirGlobal pMac) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + /* If the gScanAgingTime is set to '0' then scan results aging timeout + based on timer feature is not enabled */ + + status = csr_apply_channel_and_power_list(pMac); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOGE, + "csr_apply_channel_and_power_list failed during csr_ready with status=%d", + status); + } + return status; +} + +void csr_set_default_dot11_mode(tpAniSirGlobal pMac) +{ + uint32_t wniDot11mode = 0; + wniDot11mode = + csr_translate_to_wni_cfg_dot11_mode(pMac, + pMac->roam.configParam.uCfgDot11Mode); + cfg_set_int(pMac, WNI_CFG_DOT11_MODE, wniDot11mode); +} + +void csr_set_global_cfgs(tpAniSirGlobal pMac) +{ + + cfg_set_int(pMac, WNI_CFG_FRAGMENTATION_THRESHOLD, + csr_get_frag_thresh(pMac)); + cfg_set_int(pMac, WNI_CFG_RTS_THRESHOLD, csr_get_rts_thresh(pMac)); + cfg_set_int(pMac, WNI_CFG_11D_ENABLED, + ((pMac->roam.configParam.Is11hSupportEnabled) ? pMac->roam. + configParam.Is11dSupportEnabled : pMac->roam.configParam. + Is11dSupportEnabled)); + cfg_set_int(pMac, WNI_CFG_11H_ENABLED, + pMac->roam.configParam.Is11hSupportEnabled); + /* For now we will just use the 5GHz CB mode ini parameter to decide whether CB supported or not in Probes when there is no session + * Once session is established we will use the session related params stored in PE session for CB mode + */ + cfg_set_int(pMac, WNI_CFG_CHANNEL_BONDING_MODE, + !!(pMac->roam.configParam.channelBondingMode5GHz)); + cfg_set_int(pMac, WNI_CFG_HEART_BEAT_THRESHOLD, + pMac->roam.configParam.HeartbeatThresh24); + + /* Update the operating mode to configured value during initialization, */ + /* So that client can advertise full capabilities in Probe request frame. */ + csr_set_default_dot11_mode(pMac); +} + +/** + * csr_packetdump_timer_handler() - packet dump timer + * handler + * @pv: user data + * + * This function is used to handle packet dump timer + * + * Return: None + * + */ +static void csr_packetdump_timer_handler(void *pv) +{ + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO, + "%s Invoking packetdump deregistration API", __func__); + wlan_deregister_txrx_packetdump(); +} + +/** + * csr_packetdump_timer_stop() - stops packet dump timer + * + * This function is used to stop packet dump timer + * + * Return: None + * + */ +void csr_packetdump_timer_stop(void) +{ + QDF_STATUS status; + tHalHandle hal; + tpAniSirGlobal mac; + v_CONTEXT_t vos_ctx_ptr; + + /* get the global voss context */ + vos_ctx_ptr = cds_get_global_context(); + if (vos_ctx_ptr == NULL) { + QDF_ASSERT(0); + return; + } + + hal = cds_get_context(QDF_MODULE_ID_SME); + if (hal == NULL) { + QDF_ASSERT(0); + return; + } + + mac = PMAC_STRUCT(hal); + status = qdf_mc_timer_stop(&mac->roam.packetdump_timer); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sms_log(mac, LOGE, FL("cannot stop packetdump timer")); + } +} + +QDF_STATUS csr_roam_open(tpAniSirGlobal pMac) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + uint32_t i; + tCsrRoamSession *pSession; + do { + for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) { + pSession = CSR_GET_SESSION(pMac, i); + pSession->roamingTimerInfo.pMac = pMac; + pSession->roamingTimerInfo.sessionId = + CSR_SESSION_ID_INVALID; + } + pMac->roam.WaitForKeyTimerInfo.pMac = pMac; + pMac->roam.WaitForKeyTimerInfo.sessionId = + CSR_SESSION_ID_INVALID; + status = + qdf_mc_timer_init(&pMac->roam.hTimerWaitForKey, + QDF_TIMER_TYPE_SW, + csr_roam_wait_for_key_time_out_handler, + &pMac->roam.WaitForKeyTimerInfo); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOGE, + FL + ("cannot allocate memory for WaitForKey time out timer")); + break; + } + status = qdf_mc_timer_init(&pMac->roam.packetdump_timer, + QDF_TIMER_TYPE_SW, csr_packetdump_timer_handler, + pMac); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOGE, + FL("cannot allocate memory for packetdump timer")); + break; + } + status = + qdf_mc_timer_init(&pMac->roam.tlStatsReqInfo.hTlStatsTimer, + QDF_TIMER_TYPE_SW, + csr_roam_tl_stats_timer_handler, pMac); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOGE, + FL + ("cannot allocate memory for summary Statistics timer")); + return QDF_STATUS_E_FAILURE; + } + } while (0); + return status; +} + +QDF_STATUS csr_roam_close(tpAniSirGlobal pMac) +{ + uint32_t sessionId; + for (sessionId = 0; sessionId < CSR_ROAM_SESSION_MAX; sessionId++) { + csr_roam_close_session(pMac, sessionId, true, NULL, NULL); + } + qdf_mc_timer_stop(&pMac->roam.hTimerWaitForKey); + qdf_mc_timer_destroy(&pMac->roam.hTimerWaitForKey); + qdf_mc_timer_stop(&pMac->roam.tlStatsReqInfo.hTlStatsTimer); + qdf_mc_timer_destroy(&pMac->roam.tlStatsReqInfo.hTlStatsTimer); + qdf_mc_timer_stop(&pMac->roam.packetdump_timer); + qdf_mc_timer_destroy(&pMac->roam.packetdump_timer); + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS csr_roam_start(tpAniSirGlobal pMac) +{ + (void)pMac; + return QDF_STATUS_SUCCESS; +} + +void csr_roam_stop(tpAniSirGlobal pMac, uint32_t sessionId) +{ + csr_roam_stop_roaming_timer(pMac, sessionId); + /* deregister the clients requesting stats from PE/TL & also stop the corresponding timers */ + csr_roam_dereg_statistics_req(pMac); +} + +QDF_STATUS csr_roam_get_connect_state(tpAniSirGlobal pMac, uint32_t sessionId, + eCsrConnectState *pState) +{ + QDF_STATUS status = QDF_STATUS_E_INVAL; + if (CSR_IS_SESSION_VALID(pMac, sessionId) && (NULL != pState)) { + status = QDF_STATUS_SUCCESS; + *pState = pMac->roam.roamSession[sessionId].connectState; + } + return status; +} + +QDF_STATUS csr_roam_copy_connect_profile(tpAniSirGlobal pMac, + uint32_t sessionId, tCsrRoamConnectedProfile *pProfile) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + uint32_t size = 0; + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + tCsrRoamConnectedProfile *connected_prof; + + if (!pSession) { + sms_log(pMac, LOGE, FL(" session %d not found "), sessionId); + return QDF_STATUS_E_FAILURE; + } + if (!pProfile) { + sms_log(pMac, LOGE, FL("profile not found")); + return QDF_STATUS_E_FAILURE; + } + + if (pSession->pConnectBssDesc) { + size = pSession->pConnectBssDesc->length + + sizeof(pSession->pConnectBssDesc->length); + if (size) { + pProfile->pBssDesc = qdf_mem_malloc(size); + if (NULL != pProfile->pBssDesc) { + qdf_mem_copy(pProfile->pBssDesc, + pSession->pConnectBssDesc, + size); + status = QDF_STATUS_SUCCESS; + } else { + return QDF_STATUS_E_FAILURE; + } + } else { + pProfile->pBssDesc = NULL; + } + connected_prof = &(pSession->connectedProfile); + pProfile->AuthType = connected_prof->AuthType; + pProfile->EncryptionType = connected_prof->EncryptionType; + pProfile->mcEncryptionType = connected_prof->mcEncryptionType; + pProfile->BSSType = connected_prof->BSSType; + pProfile->operationChannel = connected_prof->operationChannel; + pProfile->CBMode = connected_prof->CBMode; + qdf_mem_copy(&pProfile->bssid, &connected_prof->bssid, + sizeof(struct qdf_mac_addr)); + qdf_mem_copy(&pProfile->SSID, &connected_prof->SSID, + sizeof(tSirMacSSid)); + if (connected_prof->MDID.mdiePresent) { + pProfile->MDID.mdiePresent = 1; + pProfile->MDID.mobilityDomain = + connected_prof->MDID.mobilityDomain; + } else { + pProfile->MDID.mdiePresent = 0; + pProfile->MDID.mobilityDomain = 0; + } +#ifdef FEATURE_WLAN_ESE + pProfile->isESEAssoc = connected_prof->isESEAssoc; + if (csr_is_auth_type_ese(connected_prof->AuthType)) { + qdf_mem_copy(pProfile->eseCckmInfo.krk, + connected_prof->eseCckmInfo.krk, + SIR_KRK_KEY_LEN); +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + qdf_mem_copy(pProfile->eseCckmInfo.btk, + connected_prof->eseCckmInfo.btk, + SIR_BTK_KEY_LEN); +#endif + pProfile->eseCckmInfo.reassoc_req_num = + connected_prof->eseCckmInfo.reassoc_req_num; + pProfile->eseCckmInfo.krk_plumbed = + connected_prof->eseCckmInfo.krk_plumbed; + } +#endif +#ifdef WLAN_FEATURE_11W + pProfile->MFPEnabled = connected_prof->MFPEnabled; + pProfile->MFPRequired = connected_prof->MFPRequired; + pProfile->MFPCapable = connected_prof->MFPCapable; +#endif + } + return status; +} + +QDF_STATUS csr_roam_get_connect_profile(tpAniSirGlobal pMac, uint32_t sessionId, + tCsrRoamConnectedProfile *pProfile) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + + if ((csr_is_conn_state_connected(pMac, sessionId)) || + (csr_is_conn_state_ibss(pMac, sessionId))) { + if (pProfile) { + status = + csr_roam_copy_connect_profile(pMac, sessionId, + pProfile); + } + } + return status; +} + +void csr_roam_free_connect_profile(tCsrRoamConnectedProfile *profile) +{ + if (profile->pBssDesc) + qdf_mem_free(profile->pBssDesc); + if (profile->pAddIEAssoc) + qdf_mem_free(profile->pAddIEAssoc); + qdf_mem_set(profile, sizeof(tCsrRoamConnectedProfile), 0); + profile->AuthType = eCSR_AUTH_TYPE_UNKNOWN; +} + +static QDF_STATUS csr_roam_free_connected_info(tpAniSirGlobal pMac, + tCsrRoamConnectedInfo * + pConnectedInfo) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + if (pConnectedInfo->pbFrames) { + qdf_mem_free(pConnectedInfo->pbFrames); + pConnectedInfo->pbFrames = NULL; + } + pConnectedInfo->nBeaconLength = 0; + pConnectedInfo->nAssocReqLength = 0; + pConnectedInfo->nAssocRspLength = 0; + pConnectedInfo->staId = 0; + pConnectedInfo->nRICRspLength = 0; +#ifdef FEATURE_WLAN_ESE + pConnectedInfo->nTspecIeLength = 0; +#endif + return status; +} + +void csr_release_command_roam(tpAniSirGlobal pMac, tSmeCmd *pCommand) +{ + csr_reinit_roam_cmd(pMac, pCommand); + csr_release_command(pMac, pCommand); +} + +void csr_release_command_scan(tpAniSirGlobal pMac, tSmeCmd *pCommand) +{ + qdf_mc_timer_stop(&pCommand->u.scanCmd.csr_scan_timer); + qdf_mc_timer_destroy(&pCommand->u.scanCmd.csr_scan_timer); + csr_reinit_scan_cmd(pMac, pCommand); + csr_release_command(pMac, pCommand); +} + +void csr_release_command_wm_status_change(tpAniSirGlobal pMac, tSmeCmd *pCommand) +{ + csr_reinit_wm_status_change_cmd(pMac, pCommand); + csr_release_command(pMac, pCommand); +} + +void csr_reinit_set_key_cmd(tpAniSirGlobal pMac, tSmeCmd *pCommand) +{ + qdf_mem_set(&pCommand->u.setKeyCmd, sizeof(tSetKeyCmd), 0); +} + +void csr_release_command_set_key(tpAniSirGlobal pMac, tSmeCmd *pCommand) +{ + csr_reinit_set_key_cmd(pMac, pCommand); + csr_release_command(pMac, pCommand); +} + +/** + * csr_release_roc_req_cmd() - Release the command + * @mac_ctx: Global MAC Context + * + * Release the remain on channel request command from the queue + * + * Return: None + */ +void csr_release_roc_req_cmd(tpAniSirGlobal mac_ctx) +{ + tListElem *entry; + tSmeCmd *cmd = NULL; + + entry = csr_ll_peek_head(&mac_ctx->sme.smeCmdActiveList, + LL_ACCESS_LOCK); + if (entry) { + cmd = GET_BASE_ADDR(entry, tSmeCmd, Link); + if (eSmeCommandRemainOnChannel == cmd->command) { + remainOnChanCallback callback = + cmd->u.remainChlCmd.callback; + /* process the msg */ + if (callback) + callback(mac_ctx, + cmd->u.remainChlCmd.callbackCtx, 0, + cmd->u.remainChlCmd.scan_id); + sms_log(mac_ctx, LOGE, + FL("Remove RoC Request from Active Cmd List")); + /* Put this cmd back on the available command list */ + if (csr_ll_remove_entry(&mac_ctx->sme.smeCmdActiveList, + entry, LL_ACCESS_LOCK)) + sme_release_command(mac_ctx, cmd); + } + } +} + +void csr_abort_command(tpAniSirGlobal pMac, tSmeCmd *pCommand, bool fStopping) +{ + + if (eSmeCsrCommandMask & pCommand->command) { + switch (pCommand->command) { + case eSmeCommandScan: + /* We need to inform the requester before dropping the scan command */ + sms_log(pMac, LOGW, + "%s: Drop scan reason %d callback %p", __func__, + pCommand->u.scanCmd.reason, + pCommand->u.scanCmd.callback); + if (NULL != pCommand->u.scanCmd.callback) { + sms_log(pMac, LOGW, "%s callback scan requester", + __func__); + csr_scan_call_callback(pMac, pCommand, + eCSR_SCAN_ABORT); + } + csr_release_command_scan(pMac, pCommand); + break; + case eSmeCommandRoam: + csr_release_command_roam(pMac, pCommand); + break; + + case eSmeCommandWmStatusChange: + csr_release_command_wm_status_change(pMac, pCommand); + break; + + case eSmeCommandSetKey: + csr_release_command_set_key(pMac, pCommand); + break; + + case eSmeCommandNdpInitiatorRequest: + csr_release_ndp_initiator_req(pMac, pCommand); + break; + + case eSmeCommandNdpResponderRequest: + csr_release_ndp_responder_req(pMac, pCommand); + break; + + case eSmeCommandNdpDataEndInitiatorRequest: + csr_release_ndp_data_end_req(pMac, pCommand); + break; + + default: + sms_log(pMac, LOGW, " CSR abort standard command %d", + pCommand->command); + csr_release_command(pMac, pCommand); + break; + } + } +} + +void csr_roam_substate_change(tpAniSirGlobal pMac, eCsrRoamSubState NewSubstate, + uint32_t sessionId) +{ + sms_log(pMac, LOG1, FL("CSR RoamSubstate: [ %s <== %s ]"), + mac_trace_getcsr_roam_sub_state(NewSubstate), + mac_trace_getcsr_roam_sub_state(pMac->roam.curSubState[sessionId])); + if (pMac->roam.curSubState[sessionId] == NewSubstate) { + return; + } + pMac->roam.curSubState[sessionId] = NewSubstate; +} + +eCsrRoamState csr_roam_state_change(tpAniSirGlobal pMac, + eCsrRoamState NewRoamState, uint8_t sessionId) +{ + eCsrRoamState PreviousState; + + sms_log(pMac, LOG1, FL("CSR RoamState[%hu]: [ %s <== %s ]"), sessionId, + mac_trace_getcsr_roam_state(NewRoamState), + mac_trace_getcsr_roam_state(pMac->roam.curState[sessionId])); + PreviousState = pMac->roam.curState[sessionId]; + + if (NewRoamState != pMac->roam.curState[sessionId]) { + /* Whenever we transition OUT of the Roaming state, clear the Roaming substate... */ + if (CSR_IS_ROAM_JOINING(pMac, sessionId)) { + csr_roam_substate_change(pMac, eCSR_ROAM_SUBSTATE_NONE, + sessionId); + } + + pMac->roam.curState[sessionId] = NewRoamState; + } + return PreviousState; +} + +void csr_assign_rssi_for_category(tpAniSirGlobal pMac, int8_t bestApRssi, + uint8_t catOffset) +{ + int i; + sms_log(pMac, LOG2, FL("best AP RSSI:%d, cat offset:%d"), + bestApRssi, catOffset); + if (catOffset) { + pMac->roam.configParam.bCatRssiOffset = catOffset; + for (i = 0; i < CSR_NUM_RSSI_CAT; i++) { + pMac->roam.configParam.RSSICat[CSR_NUM_RSSI_CAT - i - + 1] = + (int)bestApRssi - + pMac->roam.configParam.nSelect5GHzMargin - + (int)(i * catOffset); + } + } +} + +static void init_config_param(tpAniSirGlobal pMac) +{ + int i; + pMac->roam.configParam.agingCount = CSR_AGING_COUNT; + pMac->roam.configParam.channelBondingMode24GHz = + WNI_CFG_CHANNEL_BONDING_MODE_DISABLE; + pMac->roam.configParam.channelBondingMode5GHz = + WNI_CFG_CHANNEL_BONDING_MODE_ENABLE; + + pMac->roam.configParam.phyMode = eCSR_DOT11_MODE_AUTO; + pMac->roam.configParam.eBand = eCSR_BAND_ALL; + pMac->roam.configParam.uCfgDot11Mode = eCSR_CFG_DOT11_MODE_AUTO; + pMac->roam.configParam.FragmentationThreshold = + eCSR_DOT11_FRAG_THRESH_DEFAULT; + pMac->roam.configParam.HeartbeatThresh24 = 40; + pMac->roam.configParam.HeartbeatThresh50 = 40; + pMac->roam.configParam.Is11dSupportEnabled = false; + pMac->roam.configParam.Is11dSupportEnabledOriginal = false; + pMac->roam.configParam.Is11eSupportEnabled = true; + pMac->roam.configParam.Is11hSupportEnabled = true; + pMac->roam.configParam.RTSThreshold = 2346; + pMac->roam.configParam.shortSlotTime = true; + pMac->roam.configParam.WMMSupportMode = eCsrRoamWmmAuto; + pMac->roam.configParam.ProprietaryRatesEnabled = true; + pMac->roam.configParam.TxRate = eCSR_TX_RATE_AUTO; + for (i = 0; i < CSR_NUM_RSSI_CAT; i++) { + pMac->roam.configParam.BssPreferValue[i] = i; + } + csr_assign_rssi_for_category(pMac, CSR_BEST_RSSI_VALUE, + CSR_DEFAULT_RSSI_DB_GAP); + pMac->roam.configParam.fSupplicantCountryCodeHasPriority = false; + pMac->roam.configParam.nActiveMaxChnTime = CSR_ACTIVE_MAX_CHANNEL_TIME; + pMac->roam.configParam.nActiveMinChnTime = CSR_ACTIVE_MIN_CHANNEL_TIME; + pMac->roam.configParam.nPassiveMaxChnTime = + CSR_PASSIVE_MAX_CHANNEL_TIME; + pMac->roam.configParam.nPassiveMinChnTime = + CSR_PASSIVE_MIN_CHANNEL_TIME; +#ifdef WLAN_AP_STA_CONCURRENCY + pMac->roam.configParam.nActiveMaxChnTimeConc = + CSR_ACTIVE_MAX_CHANNEL_TIME_CONC; + pMac->roam.configParam.nActiveMinChnTimeConc = + CSR_ACTIVE_MIN_CHANNEL_TIME_CONC; + pMac->roam.configParam.nPassiveMaxChnTimeConc = + CSR_PASSIVE_MAX_CHANNEL_TIME_CONC; + pMac->roam.configParam.nPassiveMinChnTimeConc = + CSR_PASSIVE_MIN_CHANNEL_TIME_CONC; + pMac->roam.configParam.nRestTimeConc = CSR_REST_TIME_CONC; + pMac->roam.configParam.min_rest_time_conc = CSR_MIN_REST_TIME_CONC; + pMac->roam.configParam.idle_time_conc = CSR_IDLE_TIME_CONC; + pMac->roam.configParam.nNumStaChanCombinedConc = + CSR_NUM_STA_CHAN_COMBINED_CONC; + pMac->roam.configParam.nNumP2PChanCombinedConc = + CSR_NUM_P2P_CHAN_COMBINED_CONC; +#endif + pMac->roam.configParam.nTxPowerCap = CSR_MAX_TX_POWER; + pMac->roam.configParam.allow_tpc_from_ap = true; + pMac->roam.configParam.statsReqPeriodicity = + CSR_MIN_GLOBAL_STAT_QUERY_PERIOD; + pMac->roam.configParam.statsReqPeriodicityInPS = + CSR_MIN_GLOBAL_STAT_QUERY_PERIOD_IN_BMPS; + pMac->roam.configParam.csr11rConfig.IsFTResourceReqSupported = 0; + pMac->roam.configParam.neighborRoamConfig.nMaxNeighborRetries = 3; + pMac->roam.configParam.neighborRoamConfig.nNeighborLookupRssiThreshold = + 120; + pMac->roam.configParam.neighborRoamConfig.nOpportunisticThresholdDiff = + 30; + pMac->roam.configParam.neighborRoamConfig.nRoamRescanRssiDiff = 5; + pMac->roam.configParam.neighborRoamConfig.nNeighborScanMinChanTime = 20; + pMac->roam.configParam.neighborRoamConfig.nNeighborScanMaxChanTime = 40; + pMac->roam.configParam.neighborRoamConfig.nNeighborScanTimerPeriod = + 200; + pMac->roam.configParam.neighborRoamConfig.neighborScanChanList. + numChannels = 3; + pMac->roam.configParam.neighborRoamConfig.neighborScanChanList. + channelList[0] = 1; + pMac->roam.configParam.neighborRoamConfig.neighborScanChanList. + channelList[1] = 6; + pMac->roam.configParam.neighborRoamConfig.neighborScanChanList. + channelList[2] = 11; + pMac->roam.configParam.neighborRoamConfig.nNeighborResultsRefreshPeriod = 20000; /* 20 seconds */ + pMac->roam.configParam.neighborRoamConfig.nEmptyScanRefreshPeriod = 0; + pMac->roam.configParam.neighborRoamConfig.nRoamBmissFirstBcnt = 10; + pMac->roam.configParam.neighborRoamConfig.nRoamBmissFinalBcnt = 10; + pMac->roam.configParam.neighborRoamConfig.nRoamBeaconRssiWeight = 14; + pMac->roam.configParam.nVhtChannelWidth = + WNI_CFG_VHT_CHANNEL_WIDTH_80MHZ + 1; + + pMac->roam.configParam.addTSWhenACMIsOff = 0; + pMac->roam.configParam.fScanTwice = false; + + /* Remove this code once SLM_Sessionization is supported */ + /* BMPS_WORKAROUND_NOT_NEEDED */ + pMac->roam.configParam.doBMPSWorkaround = 0; + + pMac->roam.configParam.nInitialDwellTime = 0; + pMac->roam.configParam.initial_scan_no_dfs_chnl = 0; +} + +eCsrBand csr_get_current_band(tHalHandle hHal) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + return pMac->roam.configParam.bandCapability; +} + +/* + This function flushes the roam scan cache + */ +QDF_STATUS csr_flush_cfg_bg_scan_roam_channel_list(tpAniSirGlobal pMac, + uint8_t sessionId) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpCsrNeighborRoamControlInfo pNeighborRoamInfo = + &pMac->roam.neighborRoamInfo[sessionId]; + + /* Free up the memory first (if required) */ + if (NULL != pNeighborRoamInfo->cfgParams.channelInfo.ChannelList) { + qdf_mem_free(pNeighborRoamInfo->cfgParams.channelInfo. + ChannelList); + pNeighborRoamInfo->cfgParams.channelInfo.ChannelList = NULL; + pNeighborRoamInfo->cfgParams.channelInfo.numOfChannels = 0; + } + return status; +} + +/* + This function flushes the roam scan cache and creates fresh cache + based on the input channel list + */ +QDF_STATUS csr_create_bg_scan_roam_channel_list(tpAniSirGlobal pMac, + uint8_t sessionId, + const uint8_t *pChannelList, + const uint8_t numChannels) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpCsrNeighborRoamControlInfo pNeighborRoamInfo = + &pMac->roam.neighborRoamInfo[sessionId]; + + pNeighborRoamInfo->cfgParams.channelInfo.numOfChannels = numChannels; + + pNeighborRoamInfo->cfgParams.channelInfo.ChannelList = + qdf_mem_malloc(pNeighborRoamInfo->cfgParams.channelInfo. + numOfChannels); + + if (NULL == pNeighborRoamInfo->cfgParams.channelInfo.ChannelList) { + sms_log(pMac, LOGE, + FL("Memory Allocation for CFG Channel List failed")); + pNeighborRoamInfo->cfgParams.channelInfo.numOfChannels = 0; + return QDF_STATUS_E_NOMEM; + } + + /* Update the roam global structure */ + qdf_mem_copy(pNeighborRoamInfo->cfgParams.channelInfo.ChannelList, + pChannelList, + pNeighborRoamInfo->cfgParams.channelInfo.numOfChannels); + return status; +} + + +#ifdef FEATURE_WLAN_ESE +/** + * csr_create_roam_scan_channel_list() - create roam scan channel list + * @pMac: Global mac pointer + * @sessionId: session id + * @pChannelList: pointer to channel list + * @numChannels: number of channels + * @eBand: band enumeration + * + * This function modifies the roam scan channel list as per AP neighbor + * report; AP neighbor report may be empty or may include only other AP + * channels; in any case, we merge the channel list with the learned occupied + * channels list. + * if the band is 2.4G, then make sure channel list contains only 2.4G + * valid channels if the band is 5G, then make sure channel list contains + * only 5G valid channels + * + * Return: QDF_STATUS enumeration + */ +QDF_STATUS csr_create_roam_scan_channel_list(tpAniSirGlobal pMac, + uint8_t sessionId, + uint8_t *pChannelList, + uint8_t numChannels, + const eCsrBand eBand) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpCsrNeighborRoamControlInfo pNeighborRoamInfo + = &pMac->roam.neighborRoamInfo[sessionId]; + uint8_t outNumChannels = 0; + uint8_t inNumChannels = numChannels; + uint8_t *inPtr = pChannelList; + uint8_t i = 0; + uint8_t ChannelList[WNI_CFG_VALID_CHANNEL_LIST_LEN] = { 0 }; + uint8_t tmpChannelList[WNI_CFG_VALID_CHANNEL_LIST_LEN] = { 0 }; + uint8_t mergedOutputNumOfChannels = 0; + tpCsrChannelInfo currChannelListInfo + = &pNeighborRoamInfo->roamChannelInfo.currentChannelListInfo; + /* + * Create a Union of occupied channel list learnt by the DUT along + * with the Neighbor report Channels. This increases the chances of + * the DUT to get a candidate AP while roaming even if the Neighbor + * Report is not able to provide sufficient information. + */ + if (pMac->scan.occupiedChannels[sessionId].numChannels) { + csr_neighbor_roam_merge_channel_lists(pMac, + &pMac->scan. + occupiedChannels[sessionId]. + channelList[0], + pMac->scan. + occupiedChannels[sessionId]. + numChannels, inPtr, + inNumChannels, + &mergedOutputNumOfChannels); + inNumChannels = mergedOutputNumOfChannels; + } + if (eCSR_BAND_24 == eBand) { + for (i = 0; i < inNumChannels; i++) { + if (CDS_IS_CHANNEL_24GHZ(inPtr[i]) + && csr_roam_is_channel_valid(pMac, inPtr[i])) { + ChannelList[outNumChannels++] = inPtr[i]; + } + } + } else if (eCSR_BAND_5G == eBand) { + for (i = 0; i < inNumChannels; i++) { + /* Add 5G Non-DFS channel */ + if (CDS_IS_CHANNEL_5GHZ(inPtr[i]) && + csr_roam_is_channel_valid(pMac, inPtr[i]) && + !CDS_IS_DFS_CH(inPtr[i])) { + ChannelList[outNumChannels++] = inPtr[i]; + } + } + } else if (eCSR_BAND_ALL == eBand) { + for (i = 0; i < inNumChannels; i++) { + if (csr_roam_is_channel_valid(pMac, inPtr[i]) && + !CDS_IS_DFS_CH(inPtr[i])) { + ChannelList[outNumChannels++] = inPtr[i]; + } + } + } else { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_WARN, + "Invalid band, No operation carried out (Band %d)", + eBand); + return QDF_STATUS_E_INVAL; + } + /* + * if roaming within band is enabled, then select only the + * in band channels . + * This is required only if the band capability is set to ALL, + * E.g., if band capability is only 2.4G then all the channels in the + * list are already filtered for 2.4G channels, hence ignore this check + */ + if ((eCSR_BAND_ALL == eBand) && CSR_IS_ROAM_INTRA_BAND_ENABLED(pMac)) { + csr_neighbor_roam_channels_filter_by_current_band(pMac, + sessionId, + ChannelList, + outNumChannels, + tmpChannelList, + &outNumChannels); + qdf_mem_copy(ChannelList, tmpChannelList, outNumChannels); + } + /* Prepare final roam scan channel list */ + if (outNumChannels) { + /* Clear the channel list first */ + if (NULL != currChannelListInfo->ChannelList) { + qdf_mem_free(currChannelListInfo->ChannelList); + currChannelListInfo->ChannelList = NULL; + currChannelListInfo->numOfChannels = 0; + } + currChannelListInfo->ChannelList + = qdf_mem_malloc(outNumChannels * sizeof(uint8_t)); + if (NULL == currChannelListInfo->ChannelList) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_FATAL, + "Failed to allocate memory for roam scan channel list"); + currChannelListInfo->numOfChannels = 0; + return QDF_STATUS_E_NOMEM; + } + qdf_mem_copy(currChannelListInfo->ChannelList, + ChannelList, outNumChannels); + } + return status; +} + +/** + * csr_roam_is_ese_assoc() - is this ese association + * @mac_ctx: Global MAC context + * @session_id: session identifier + * + * Returns whether the current association is a ESE assoc or not. + * + * Return: true if ese association; false otherwise + */ +bool csr_roam_is_ese_assoc(tpAniSirGlobal mac_ctx, uint32_t session_id) +{ + return mac_ctx->roam.neighborRoamInfo[session_id].isESEAssoc; +} + + +/** + * csr_roam_is_ese_ini_feature_enabled() - is ese feature enabled + * @mac_ctx: Global MAC context + * + * Return: true if ese feature is enabled; false otherwise + */ +bool csr_roam_is_ese_ini_feature_enabled(tpAniSirGlobal pMac) +{ + return pMac->roam.configParam.isEseIniFeatureEnabled; +} + +/** + * csr_tsm_stats_rsp_processor() - tsm stats response processor + * @pMac: Global MAC context + * @pMsg: Message pointer + * + * Return: None + */ +static void csr_tsm_stats_rsp_processor(tpAniSirGlobal pMac, void *pMsg) +{ + tAniGetTsmStatsRsp *pTsmStatsRsp = (tAniGetTsmStatsRsp *) pMsg; + + if (NULL != pTsmStatsRsp) { + /* + * Get roam Rssi request is backed up and passed back + * to the response, Extract the request message + * to fetch callback. + */ + tpAniGetTsmStatsReq reqBkp + = (tAniGetTsmStatsReq *) pTsmStatsRsp->tsmStatsReq; + + if (NULL != reqBkp) { + if (NULL != reqBkp->tsmStatsCallback) { + ((tCsrTsmStatsCallback) + (reqBkp->tsmStatsCallback))(pTsmStatsRsp-> + tsmMetrics, + pTsmStatsRsp-> + staId, + reqBkp-> + pDevContext); + reqBkp->tsmStatsCallback = NULL; + } + qdf_mem_free(reqBkp); + pTsmStatsRsp->tsmStatsReq = NULL; + } else { + sms_log(pMac, LOGE, FL("reqBkp is NULL")); + if (NULL != reqBkp) { + qdf_mem_free(reqBkp); + pTsmStatsRsp->tsmStatsReq = NULL; + } + } + } else { + sms_log(pMac, LOGE, FL("pTsmStatsRsp is NULL")); + } + return; +} + +/** + * csr_send_ese_adjacent_ap_rep_ind() - ese send adjacent ap report + * @pMac: Global MAC context + * @pSession: Session pointer + * + * Return: None + */ +static void csr_send_ese_adjacent_ap_rep_ind(tpAniSirGlobal pMac, + tCsrRoamSession *pSession) +{ + uint32_t roamTS2 = 0; + tCsrRoamInfo roamInfo; + tpPESession pSessionEntry = NULL; + uint8_t sessionId = CSR_SESSION_ID_INVALID; + + if (NULL == pSession) { + sms_log(pMac, LOGE, FL("pSession is NULL")); + return; + } + + roamTS2 = qdf_mc_timer_get_system_time(); + roamInfo.tsmRoamDelay = roamTS2 - pSession->roamTS1; + sms_log(pMac, LOG1, "Bssid(" MAC_ADDRESS_STR ") Roaming Delay(%u ms)", + MAC_ADDR_ARRAY(pSession->connectedProfile.bssid.bytes), + roamInfo.tsmRoamDelay); + + pSessionEntry = pe_find_session_by_bssid(pMac, + pSession->connectedProfile.bssid.bytes, + &sessionId); + if (NULL == pSessionEntry) { + sms_log(pMac, LOGE, FL("session %d not found"), sessionId); + return; + } + + pSessionEntry->eseContext.tsm.tsmMetrics.RoamingDly + = roamInfo.tsmRoamDelay; + + csr_roam_call_callback(pMac, pSession->sessionId, &roamInfo, + 0, eCSR_ROAM_ESE_ADJ_AP_REPORT_IND, 0); +} + +/** + * csr_get_tsm_stats() - get tsm stats + * @pMac: Global MAC context + * @callback: TSM stats callback + * @staId: Station id + * @bssId: bssid + * @pContext: pointer to context + * @p_cds_context: cds context + * @tid: traffic id + * + * Return: QDF_STATUS enumeration + */ +QDF_STATUS csr_get_tsm_stats(tpAniSirGlobal pMac, + tCsrTsmStatsCallback callback, + uint8_t staId, + struct qdf_mac_addr bssId, + void *pContext, void *p_cds_context, uint8_t tid) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tAniGetTsmStatsReq *pMsg = NULL; + pMsg = qdf_mem_malloc(sizeof(tAniGetTsmStatsReq)); + if (!pMsg) { + sms_log(pMac, LOGE, + "csr_get_tsm_stats: failed to allocate mem for req"); + return QDF_STATUS_E_NOMEM; + } + /* need to initiate a stats request to PE */ + pMsg->msgType = eWNI_SME_GET_TSM_STATS_REQ; + pMsg->msgLen = (uint16_t) sizeof(tAniGetTsmStatsReq); + pMsg->staId = staId; + pMsg->tid = tid; + qdf_copy_macaddr(&pMsg->bssId, &bssId); + pMsg->tsmStatsCallback = callback; + pMsg->pDevContext = pContext; + pMsg->p_cds_context = p_cds_context; + status = cds_send_mb_message_to_mac(pMsg); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOG1, + " csr_get_tsm_stats: failed to send down the rssi req"); + /* pMsg is freed by cds_send_mb_message_to_mac */ + status = QDF_STATUS_E_FAILURE; + } + return status; +} + +/** + * csr_fetch_ch_lst_from_received_list() - fetch channel list from received list + * and update req msg + * paramters + * @mac_ctx: global mac ctx + * @roam_info: roam info struct + * @curr_ch_lst_info: current channel list info + * @req_buf: out param, roam offload scan request packet + * + * Return: void + */ +static void +csr_fetch_ch_lst_from_received_list(tpAniSirGlobal mac_ctx, + tpCsrNeighborRoamControlInfo roam_info, + tpCsrChannelInfo curr_ch_lst_info, + tSirRoamOffloadScanReq *req_buf) +{ + uint8_t i = 0; + uint8_t num_channels = 0; + uint8_t *ch_lst = NULL; + uint16_t unsafe_chan[NUM_CHANNELS]; + uint16_t unsafe_chan_cnt = 0; + uint16_t cnt = 0; + bool is_unsafe_chan; + qdf_device_t qdf_ctx = cds_get_context(QDF_MODULE_ID_QDF_DEVICE); + + if (!qdf_ctx) { + cds_err("qdf_ctx is NULL"); + return; + } + pld_get_wlan_unsafe_channel(qdf_ctx->dev, unsafe_chan, + &unsafe_chan_cnt, + sizeof(unsafe_chan)); + + if (curr_ch_lst_info->numOfChannels == 0) + return; + + ch_lst = curr_ch_lst_info->ChannelList; + for (i = 0; i < curr_ch_lst_info->numOfChannels; i++) { + if ((!mac_ctx->roam.configParam.allowDFSChannelRoam || + (mac_ctx->roam.configParam.sta_roam_policy.dfs_mode == + CSR_STA_ROAM_POLICY_DFS_DISABLED)) && + (CDS_IS_DFS_CH(*ch_lst))) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO, + FL("ignoring dfs channel %d"), *ch_lst); + ch_lst++; + continue; + } + + if (mac_ctx->roam.configParam.sta_roam_policy. + skip_unsafe_channels && + unsafe_chan_cnt) { + is_unsafe_chan = false; + for (cnt = 0; cnt < unsafe_chan_cnt; cnt++) { + if (unsafe_chan[cnt] == *ch_lst) { + is_unsafe_chan = true; + break; + } + } + if (is_unsafe_chan) { + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_INFO, + FL("ignoring unsafe channel %d"), + *ch_lst); + ch_lst++; + continue; + } + } + req_buf->ConnectedNetwork.ChannelCache[num_channels++] = + *ch_lst; + ch_lst++; + } + req_buf->ConnectedNetwork.ChannelCount = num_channels; + req_buf->ChannelCacheType = CHANNEL_LIST_DYNAMIC_UPDATE; +} + +/** + * csr_set_cckm_ie() - set CCKM IE + * @pMac: Global MAC context + * @sessionId: session identifier + * @pCckmIe: Pointer to input CCKM IE data + * @ccKmIeLen: Length of @pCckmIe + * + * This function stores the CCKM IE passed by the supplicant + * in a place holder data structure and this IE will be packed inside + * reassociation request + * + * Return: QDF_STATUS enumeration + */ +QDF_STATUS csr_set_cckm_ie(tpAniSirGlobal pMac, const uint8_t sessionId, + const uint8_t *pCckmIe, const uint8_t ccKmIeLen) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + if (!pSession) { + sms_log(pMac, LOGE, FL(" session %d not found "), sessionId); + return QDF_STATUS_E_FAILURE; + } + qdf_mem_copy(pSession->suppCckmIeInfo.cckmIe, pCckmIe, ccKmIeLen); + pSession->suppCckmIeInfo.cckmIeLen = ccKmIeLen; + return status; +} + +/** + * csr_roam_read_tsf() - read TSF + * @pMac: Global MAC context + * @sessionId: session identifier + * @pTimestamp: output TSF timestamp + * + * This function reads the TSF; and also add the time elapsed since + * last beacon or probe response reception from the hand off AP to arrive at + * the latest TSF value. + * + * Return: QDF_STATUS enumeration + */ +QDF_STATUS csr_roam_read_tsf(tpAniSirGlobal pMac, uint8_t *pTimestamp, + uint8_t sessionId) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tCsrNeighborRoamBSSInfo handoffNode = {{0} }; + uint64_t timer_diff = 0; + uint32_t timeStamp[2]; + tpSirBssDescription pBssDescription = NULL; + csr_neighbor_roam_get_handoff_ap_info(pMac, &handoffNode, sessionId); + pBssDescription = handoffNode.pBssDescription; + /* Get the time diff in nano seconds */ + timer_diff = (qdf_get_monotonic_boottime_ns() - + pBssDescription->scansystimensec); + /* Convert msec to micro sec timer */ + timer_diff = do_div(timer_diff, SYSTEM_TIME_NSEC_TO_USEC); + timeStamp[0] = pBssDescription->timeStamp[0]; + timeStamp[1] = pBssDescription->timeStamp[1]; + update_cckmtsf(&(timeStamp[0]), &(timeStamp[1]), &timer_diff); + qdf_mem_copy(pTimestamp, (void *)&timeStamp[0], sizeof(uint32_t) * 2); + return status; +} + +#endif /* FEATURE_WLAN_ESE */ + +/** + * csr_roam_is_roam_offload_scan_enabled() - is roam offload enabled + * @mac_ctx: Global MAC context + * + * Returns whether firmware based background scan is currently enabled or not. + * + * Return: true if roam offload scan enabled; false otherwise + */ +bool csr_roam_is_roam_offload_scan_enabled(tpAniSirGlobal mac_ctx) +{ + return mac_ctx->roam.configParam.isRoamOffloadScanEnabled; +} + +QDF_STATUS csr_set_band(tHalHandle hHal, uint8_t sessionId, eCsrBand eBand) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + QDF_STATUS status = QDF_STATUS_SUCCESS; + if (CSR_IS_PHY_MODE_A_ONLY(pMac) && (eBand == eCSR_BAND_24)) { + /* DOT11 mode configured to 11a only and received + request to change the band to 2.4 GHz */ + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "failed to set band cfg80211 = %u, band = %u", + pMac->roam.configParam.uCfgDot11Mode, eBand); + return QDF_STATUS_E_INVAL; + } + if ((CSR_IS_PHY_MODE_B_ONLY(pMac) || + CSR_IS_PHY_MODE_G_ONLY(pMac)) && (eBand == eCSR_BAND_5G)) { + /* DOT11 mode configured to 11b/11g only and received + request to change the band to 5 GHz */ + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "failed to set band dot11mode = %u, band = %u", + pMac->roam.configParam.uCfgDot11Mode, eBand); + return QDF_STATUS_E_INVAL; + } + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO, + "Band changed to %u (0 - ALL, 1 - 2.4 GHZ, 2 - 5GHZ)", eBand); + pMac->roam.configParam.eBand = eBand; + pMac->roam.configParam.bandCapability = eBand; + + status = csr_get_channel_and_power_list(pMac); + if (QDF_STATUS_SUCCESS == status) + csr_apply_channel_and_power_list(pMac); + return status; +} + +/* The funcns csr_convert_cb_ini_value_to_phy_cb_state and csr_convert_phy_cb_state_to_ini_value have been + * introduced to convert the ini value to the ENUM used in csr and MAC for CB state + * Ideally we should have kept the ini value and enum value same and representing the same + * cb values as in 11n standard i.e. + * Set to 1 (SCA) if the secondary channel is above the primary channel + * Set to 3 (SCB) if the secondary channel is below the primary channel + * Set to 0 (SCN) if no secondary channel is present + * However, since our driver is already distributed we will keep the ini definition as it is which is: + * 0 - secondary none + * 1 - secondary LOW + * 2 - secondary HIGH + * and convert to enum value used within the driver in csr_change_default_config_param using this funcn + * The enum values are as follows: + * PHY_SINGLE_CHANNEL_CENTERED = 0 + * PHY_DOUBLE_CHANNEL_LOW_PRIMARY = 1 + * PHY_DOUBLE_CHANNEL_HIGH_PRIMARY = 3 + */ +ePhyChanBondState csr_convert_cb_ini_value_to_phy_cb_state(uint32_t cbIniValue) +{ + + ePhyChanBondState phyCbState; + switch (cbIniValue) { + /* secondary none */ + case eCSR_INI_SINGLE_CHANNEL_CENTERED: + phyCbState = PHY_SINGLE_CHANNEL_CENTERED; + break; + /* secondary LOW */ + case eCSR_INI_DOUBLE_CHANNEL_HIGH_PRIMARY: + phyCbState = PHY_DOUBLE_CHANNEL_HIGH_PRIMARY; + break; + /* secondary HIGH */ + case eCSR_INI_DOUBLE_CHANNEL_LOW_PRIMARY: + phyCbState = PHY_DOUBLE_CHANNEL_LOW_PRIMARY; + break; + case eCSR_INI_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_CENTERED: + phyCbState = PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_CENTERED; + break; + case eCSR_INI_QUADRUPLE_CHANNEL_20MHZ_CENTERED_40MHZ_CENTERED: + phyCbState = + PHY_QUADRUPLE_CHANNEL_20MHZ_CENTERED_40MHZ_CENTERED; + break; + case eCSR_INI_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_CENTERED: + phyCbState = PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_CENTERED; + break; + case eCSR_INI_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_LOW: + phyCbState = PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_LOW; + break; + case eCSR_INI_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_LOW: + phyCbState = PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_LOW; + break; + case eCSR_INI_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_HIGH: + phyCbState = PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_HIGH; + break; + case eCSR_INI_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_HIGH: + phyCbState = PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_HIGH; + break; + default: + /* If an invalid value is passed, disable CHANNEL BONDING */ + phyCbState = PHY_SINGLE_CHANNEL_CENTERED; + break; + } + return phyCbState; +} + +static +uint32_t csr_convert_phy_cb_state_to_ini_value(ePhyChanBondState phyCbState) +{ + + uint32_t cbIniValue; + switch (phyCbState) { + /* secondary none */ + case PHY_SINGLE_CHANNEL_CENTERED: + cbIniValue = eCSR_INI_SINGLE_CHANNEL_CENTERED; + break; + /* secondary LOW */ + case PHY_DOUBLE_CHANNEL_HIGH_PRIMARY: + cbIniValue = eCSR_INI_DOUBLE_CHANNEL_HIGH_PRIMARY; + break; + /* secondary HIGH */ + case PHY_DOUBLE_CHANNEL_LOW_PRIMARY: + cbIniValue = eCSR_INI_DOUBLE_CHANNEL_LOW_PRIMARY; + break; + case PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_CENTERED: + cbIniValue = + eCSR_INI_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_CENTERED; + break; + case PHY_QUADRUPLE_CHANNEL_20MHZ_CENTERED_40MHZ_CENTERED: + cbIniValue = + eCSR_INI_QUADRUPLE_CHANNEL_20MHZ_CENTERED_40MHZ_CENTERED; + break; + case PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_CENTERED: + cbIniValue = + eCSR_INI_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_CENTERED; + break; + case PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_LOW: + cbIniValue = eCSR_INI_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_LOW; + break; + case PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_LOW: + cbIniValue = eCSR_INI_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_LOW; + break; + case PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_HIGH: + cbIniValue = eCSR_INI_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_HIGH; + break; + case PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_HIGH: + cbIniValue = eCSR_INI_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_HIGH; + break; + default: + /* return some invalid value */ + cbIniValue = eCSR_INI_CHANNEL_BONDING_STATE_MAX; + break; + } + return cbIniValue; +} + +QDF_STATUS csr_change_default_config_param(tpAniSirGlobal pMac, + tCsrConfigParam *pParam) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + + if (pParam) { + pMac->roam.configParam.pkt_err_disconn_th = + pParam->pkt_err_disconn_th; + pMac->roam.configParam.is_force_1x1 = + pParam->is_force_1x1; + pMac->roam.configParam.WMMSupportMode = pParam->WMMSupportMode; + cfg_set_int(pMac, WNI_CFG_WME_ENABLED, + (pParam->WMMSupportMode == eCsrRoamWmmNoQos) ? 0 : 1); + pMac->roam.configParam.Is11eSupportEnabled = + pParam->Is11eSupportEnabled; + pMac->roam.configParam.FragmentationThreshold = + pParam->FragmentationThreshold; + pMac->roam.configParam.Is11dSupportEnabled = + pParam->Is11dSupportEnabled; + pMac->roam.configParam.Is11dSupportEnabledOriginal = + pParam->Is11dSupportEnabled; + pMac->roam.configParam.Is11hSupportEnabled = + pParam->Is11hSupportEnabled; + + pMac->roam.configParam.fenableMCCMode = pParam->fEnableMCCMode; + pMac->roam.configParam.mcc_rts_cts_prot_enable = + pParam->mcc_rts_cts_prot_enable; + pMac->roam.configParam.mcc_bcast_prob_resp_enable = + pParam->mcc_bcast_prob_resp_enable; + pMac->roam.configParam.fAllowMCCGODiffBI = + pParam->fAllowMCCGODiffBI; + + /* channelBondingMode5GHz plays a dual role right now + * INFRA STA will use this non zero value as CB enabled and SOFTAP will use this non-zero value to determine the secondary channel offset + * This is how channelBondingMode5GHz works now and this is kept intact to avoid any cfg.ini change + */ + if (pParam->channelBondingMode24GHz > MAX_CB_VALUE_IN_INI) { + sms_log(pMac, LOGW, + "Invalid CB value from ini in 2.4GHz band %d, CB DISABLED", + pParam->channelBondingMode24GHz); + } + pMac->roam.configParam.channelBondingMode24GHz = + csr_convert_cb_ini_value_to_phy_cb_state(pParam-> + channelBondingMode24GHz); + if (pParam->channelBondingMode5GHz > MAX_CB_VALUE_IN_INI) { + sms_log(pMac, LOGW, + "Invalid CB value from ini in 5GHz band %d, CB DISABLED", + pParam->channelBondingMode5GHz); + } + pMac->roam.configParam.channelBondingMode5GHz = + csr_convert_cb_ini_value_to_phy_cb_state(pParam-> + channelBondingMode5GHz); + pMac->roam.configParam.RTSThreshold = pParam->RTSThreshold; + pMac->roam.configParam.phyMode = pParam->phyMode; + pMac->roam.configParam.shortSlotTime = pParam->shortSlotTime; + pMac->roam.configParam.HeartbeatThresh24 = + pParam->HeartbeatThresh24; + pMac->roam.configParam.HeartbeatThresh50 = + pParam->HeartbeatThresh50; + pMac->roam.configParam.ProprietaryRatesEnabled = + pParam->ProprietaryRatesEnabled; + pMac->roam.configParam.TxRate = pParam->TxRate; + pMac->roam.configParam.AdHocChannel24 = pParam->AdHocChannel24; + pMac->roam.configParam.AdHocChannel5G = pParam->AdHocChannel5G; + pMac->roam.configParam.bandCapability = pParam->bandCapability; + pMac->roam.configParam.cbChoice = pParam->cbChoice; + pMac->roam.configParam.neighborRoamConfig. + delay_before_vdev_stop = + pParam->neighborRoamConfig.delay_before_vdev_stop; + + /* if HDD passed down non zero values then only update, */ + /* otherwise keep using the defaults */ + if (pParam->initial_scan_no_dfs_chnl) { + pMac->roam.configParam.initial_scan_no_dfs_chnl = + pParam->initial_scan_no_dfs_chnl; + } + if (pParam->nInitialDwellTime) { + pMac->roam.configParam.nInitialDwellTime = + pParam->nInitialDwellTime; + } + if (pParam->nActiveMaxChnTime) { + pMac->roam.configParam.nActiveMaxChnTime = + pParam->nActiveMaxChnTime; + cfg_set_int(pMac, WNI_CFG_ACTIVE_MAXIMUM_CHANNEL_TIME, + pParam->nActiveMaxChnTime); + } + if (pParam->nActiveMinChnTime) { + pMac->roam.configParam.nActiveMinChnTime = + pParam->nActiveMinChnTime; + cfg_set_int(pMac, WNI_CFG_ACTIVE_MINIMUM_CHANNEL_TIME, + pParam->nActiveMinChnTime); + } + if (pParam->nPassiveMaxChnTime) { + pMac->roam.configParam.nPassiveMaxChnTime = + pParam->nPassiveMaxChnTime; + cfg_set_int(pMac, WNI_CFG_PASSIVE_MAXIMUM_CHANNEL_TIME, + pParam->nPassiveMaxChnTime); + } + if (pParam->nPassiveMinChnTime) { + pMac->roam.configParam.nPassiveMinChnTime = + pParam->nPassiveMinChnTime; + cfg_set_int(pMac, WNI_CFG_PASSIVE_MINIMUM_CHANNEL_TIME, + pParam->nPassiveMinChnTime); + } + pMac->roam.configParam.scan_probe_repeat_time = + pParam->scan_probe_repeat_time; + pMac->roam.configParam.scan_num_probes = + pParam->scan_num_probes; +#ifdef WLAN_AP_STA_CONCURRENCY + if (pParam->nActiveMaxChnTimeConc) { + pMac->roam.configParam.nActiveMaxChnTimeConc = + pParam->nActiveMaxChnTimeConc; + } + if (pParam->nActiveMinChnTimeConc) { + pMac->roam.configParam.nActiveMinChnTimeConc = + pParam->nActiveMinChnTimeConc; + } + if (pParam->nPassiveMaxChnTimeConc) { + pMac->roam.configParam.nPassiveMaxChnTimeConc = + pParam->nPassiveMaxChnTimeConc; + } + if (pParam->nPassiveMinChnTimeConc) { + pMac->roam.configParam.nPassiveMinChnTimeConc = + pParam->nPassiveMinChnTimeConc; + } + pMac->roam.configParam.nRestTimeConc = pParam->nRestTimeConc; + pMac->roam.configParam.min_rest_time_conc = + pParam->min_rest_time_conc; + pMac->roam.configParam.idle_time_conc = pParam->idle_time_conc; + + if (pParam->nNumStaChanCombinedConc) { + pMac->roam.configParam.nNumStaChanCombinedConc = + pParam->nNumStaChanCombinedConc; + } + if (pParam->nNumP2PChanCombinedConc) { + pMac->roam.configParam.nNumP2PChanCombinedConc = + pParam->nNumP2PChanCombinedConc; + } +#endif + pMac->roam.configParam.eBand = pParam->eBand; + pMac->roam.configParam.uCfgDot11Mode = + csr_get_cfg_dot11_mode_from_csr_phy_mode(NULL, + pMac->roam.configParam. + phyMode, + pMac->roam.configParam. + ProprietaryRatesEnabled); + /* if HDD passed down non zero values for age params, then only update, */ + /* otherwise keep using the defaults */ + if (pParam->nScanResultAgeCount) { + pMac->roam.configParam.agingCount = + pParam->nScanResultAgeCount; + } + if (pParam->obss_width_interval) { + pMac->roam.configParam.obss_width_interval = + pParam->obss_width_interval; + cfg_set_int(pMac, + WNI_CFG_OBSS_HT40_SCAN_WIDTH_TRIGGER_INTERVAL, + pParam->obss_width_interval); + } + if (pParam->obss_active_dwelltime) { + pMac->roam.configParam.obss_active_dwelltime = + pParam->obss_active_dwelltime; + cfg_set_int(pMac, + WNI_CFG_OBSS_HT40_SCAN_ACTIVE_DWELL_TIME, + pParam->obss_active_dwelltime); + } + if (pParam->obss_passive_dwelltime) { + pMac->roam.configParam.obss_passive_dwelltime = + pParam->obss_passive_dwelltime; + cfg_set_int(pMac, + WNI_CFG_OBSS_HT40_SCAN_PASSIVE_DWELL_TIME, + pParam->obss_passive_dwelltime); + } + + pMac->first_scan_bucket_threshold = + pParam->first_scan_bucket_threshold; + csr_assign_rssi_for_category(pMac, + pMac->first_scan_bucket_threshold, + pParam->bCatRssiOffset); + pMac->roam.configParam.fSupplicantCountryCodeHasPriority = + pParam->fSupplicantCountryCodeHasPriority; + pMac->roam.configParam.vccRssiThreshold = + pParam->vccRssiThreshold; + pMac->roam.configParam.vccUlMacLossThreshold = + pParam->vccUlMacLossThreshold; + pMac->roam.configParam.statsReqPeriodicity = + pParam->statsReqPeriodicity; + pMac->roam.configParam.statsReqPeriodicityInPS = + pParam->statsReqPeriodicityInPS; + /* Assign this before calling csr_init11d_info */ + pMac->roam.configParam.nTxPowerCap = pParam->nTxPowerCap; + pMac->roam.configParam.allow_tpc_from_ap = + pParam->allow_tpc_from_ap; + if (csr_is11d_supported(pMac)) { + status = csr_init11d_info(pMac, &pParam->Csr11dinfo); + } else { + pMac->scan.curScanType = eSIR_ACTIVE_SCAN; + } + + /* Initialize the power + channel information if 11h is enabled. + If 11d is enabled this information has already been initialized */ + if (csr_is11h_supported(pMac) && !csr_is11d_supported(pMac)) { + csr_init_channel_power_list(pMac, &pParam->Csr11dinfo); + } + + qdf_mem_copy(&pMac->roam.configParam.csr11rConfig, + &pParam->csr11rConfig, + sizeof(tCsr11rConfigParams)); + sms_log(pMac, LOG1, "IsFTResourceReqSupp = %d", + pMac->roam.configParam.csr11rConfig. + IsFTResourceReqSupported); + pMac->roam.configParam.isFastTransitionEnabled = + pParam->isFastTransitionEnabled; + pMac->roam.configParam.RoamRssiDiff = pParam->RoamRssiDiff; + pMac->roam.configParam.nRoamPrefer5GHz = + pParam->nRoamPrefer5GHz; + pMac->roam.configParam.nRoamIntraBand = pParam->nRoamIntraBand; + pMac->roam.configParam.isWESModeEnabled = + pParam->isWESModeEnabled; + pMac->roam.configParam.nProbes = pParam->nProbes; + pMac->roam.configParam.nRoamScanHomeAwayTime = + pParam->nRoamScanHomeAwayTime; + pMac->roam.configParam.isRoamOffloadScanEnabled = + pParam->isRoamOffloadScanEnabled; + pMac->roam.configParam.bFastRoamInConIniFeatureEnabled = + pParam->bFastRoamInConIniFeatureEnabled; + pMac->roam.configParam.isFastRoamIniFeatureEnabled = + pParam->isFastRoamIniFeatureEnabled; + pMac->roam.configParam.MAWCEnabled = pParam->MAWCEnabled; + +#ifdef FEATURE_WLAN_ESE + pMac->roam.configParam.isEseIniFeatureEnabled = + pParam->isEseIniFeatureEnabled; +#endif + qdf_mem_copy(&pMac->roam.configParam.neighborRoamConfig, + &pParam->neighborRoamConfig, + sizeof(tCsrNeighborRoamConfigParams)); + sms_log(pMac, LOG1, "nNeighborScanTimerPerioid = %d", + pMac->roam.configParam.neighborRoamConfig. + nNeighborScanTimerPeriod); + sms_log(pMac, LOG1, "nNeighborLookupRssiThreshold = %d", + pMac->roam.configParam.neighborRoamConfig. + nNeighborLookupRssiThreshold); + sms_log(pMac, LOG1, "nOpportunisticThresholdDiff = %d", + pMac->roam.configParam.neighborRoamConfig. + nOpportunisticThresholdDiff); + sms_log(pMac, LOG1, "nRoamRescanRssiDiff = %d", + pMac->roam.configParam.neighborRoamConfig. + nRoamRescanRssiDiff); + sms_log(pMac, LOG1, "nNeighborScanMinChanTime = %d", + pMac->roam.configParam.neighborRoamConfig. + nNeighborScanMinChanTime); + sms_log(pMac, LOG1, "nNeighborScanMaxChanTime = %d", + pMac->roam.configParam.neighborRoamConfig. + nNeighborScanMaxChanTime); + sms_log(pMac, LOG1, "nMaxNeighborRetries = %d", + pMac->roam.configParam.neighborRoamConfig. + nMaxNeighborRetries); + sms_log(pMac, LOG1, "nNeighborResultsRefreshPeriod = %d", + pMac->roam.configParam.neighborRoamConfig. + nNeighborResultsRefreshPeriod); + sms_log(pMac, LOG1, "nEmptyScanRefreshPeriod = %d", + pMac->roam.configParam.neighborRoamConfig. + nEmptyScanRefreshPeriod); + { + int i; + sms_log(pMac, LOG1, + FL("Num of Channels in CFG Channel List: %d"), + pMac->roam.configParam.neighborRoamConfig. + neighborScanChanList.numChannels); + for (i = 0; + i < + pMac->roam.configParam.neighborRoamConfig. + neighborScanChanList.numChannels; i++) { + sms_log(pMac, LOG1, "%d ", + pMac->roam.configParam. + neighborRoamConfig.neighborScanChanList. + channelList[i]); + } + } + sms_log(pMac, LOG1, "nRoamBmissFirstBcnt = %d", + pMac->roam.configParam.neighborRoamConfig. + nRoamBmissFirstBcnt); + sms_log(pMac, LOG1, "nRoamBmissFinalBcnt = %d", + pMac->roam.configParam.neighborRoamConfig. + nRoamBmissFinalBcnt); + sms_log(pMac, LOG1, "nRoamBeaconRssiWeight = %d", + pMac->roam.configParam.neighborRoamConfig. + nRoamBeaconRssiWeight); + pMac->roam.configParam.addTSWhenACMIsOff = + pParam->addTSWhenACMIsOff; + pMac->scan.fValidateList = pParam->fValidateList; + pMac->scan.fEnableBypass11d = pParam->fEnableBypass11d; + pMac->scan.fEnableDFSChnlScan = pParam->fEnableDFSChnlScan; + pMac->scan.scanResultCfgAgingTime = pParam->scanCfgAgingTime; + pMac->roam.configParam.fScanTwice = pParam->fScanTwice; + pMac->scan.fFirstScanOnly2GChnl = pParam->fFirstScanOnly2GChnl; + pMac->scan.max_scan_count = pParam->max_scan_count; + /* This parameter is not available in cfg and not passed from upper layers. Instead it is initialized here + * This paramtere is used in concurrency to determine if there are concurrent active sessions. + * Is used as a temporary fix to disconnect all active sessions when BMPS enabled so the active session if Infra STA + * will automatically connect back and resume BMPS since resume BMPS is not working when moving from concurrent to + * single session + */ + /* Remove this code once SLM_Sessionization is supported */ + /* BMPS_WORKAROUND_NOT_NEEDED */ + pMac->roam.configParam.doBMPSWorkaround = 0; + + pMac->roam.configParam.nVhtChannelWidth = + pParam->nVhtChannelWidth; + pMac->roam.configParam.enable_txbf_sap_mode = + pParam->enable_txbf_sap_mode; + pMac->roam.configParam.enable2x2 = pParam->enable2x2; + pMac->roam.configParam.enableVhtFor24GHz = + pParam->enableVhtFor24GHz; + pMac->roam.configParam.enableVhtpAid = pParam->enableVhtpAid; + pMac->roam.configParam.enableVhtGid = pParam->enableVhtGid; + pMac->roam.configParam.enableAmpduPs = pParam->enableAmpduPs; + pMac->roam.configParam.enableHtSmps = pParam->enableHtSmps; + pMac->roam.configParam.htSmps = pParam->htSmps; + pMac->roam.configParam.send_smps_action = + pParam->send_smps_action; + pMac->roam.configParam.txLdpcEnable = pParam->enableTxLdpc; + pMac->roam.configParam.rxLdpcEnable = pParam->enableRxLDPC; + pMac->roam.configParam.disable_high_ht_mcs_2x2 = + pParam->disable_high_ht_mcs_2x2; + pMac->roam.configParam.ignore_peer_erp_info = + pParam->ignore_peer_erp_info; + pMac->roam.configParam.max_amsdu_num = + pParam->max_amsdu_num; + pMac->roam.configParam.nSelect5GHzMargin = + pParam->nSelect5GHzMargin; + pMac->roam.configParam.isCoalesingInIBSSAllowed = + pParam->isCoalesingInIBSSAllowed; +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH + pMac->roam.configParam.cc_switch_mode = pParam->cc_switch_mode; +#endif + pMac->roam.configParam.allowDFSChannelRoam = + pParam->allowDFSChannelRoam; +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + pMac->roam.configParam.isRoamOffloadEnabled = + pParam->isRoamOffloadEnabled; +#endif + pMac->roam.configParam.obssEnabled = pParam->obssEnabled; + pMac->roam.configParam.vendor_vht_sap = + pParam->vendor_vht_sap; + pMac->roam.configParam.conc_custom_rule1 = + pParam->conc_custom_rule1; + pMac->roam.configParam.conc_custom_rule2 = + pParam->conc_custom_rule2; + pMac->roam.configParam.is_sta_connection_in_5gz_enabled = + pParam->is_sta_connection_in_5gz_enabled; + pMac->roam.configParam.sendDeauthBeforeCon = + pParam->sendDeauthBeforeCon; + + pMac->enable_dot11p = pParam->enable_dot11p; + pMac->roam.configParam.early_stop_scan_enable = + pParam->early_stop_scan_enable; + pMac->roam.configParam.early_stop_scan_min_threshold = + pParam->early_stop_scan_min_threshold; + pMac->roam.configParam.early_stop_scan_max_threshold = + pParam->early_stop_scan_max_threshold; + pMac->isCoalesingInIBSSAllowed = + pParam->isCoalesingInIBSSAllowed; + + pMac->roam.configParam.roam_params.dense_rssi_thresh_offset = + pParam->roam_dense_rssi_thresh_offset; + pMac->roam.configParam.roam_params.dense_min_aps_cnt = + pParam->roam_dense_min_aps; + pMac->roam.configParam.roam_params.traffic_threshold = + pParam->roam_dense_traffic_thresh; + + pMac->roam.configParam.scan_adaptive_dwell_mode = + pParam->scan_adaptive_dwell_mode; + pMac->roam.configParam.roamscan_adaptive_dwell_mode = + pParam->roamscan_adaptive_dwell_mode; + + pMac->roam.configParam.per_roam_config.enable = + pParam->per_roam_config.enable; + pMac->roam.configParam.per_roam_config.tx_high_rate_thresh = + pParam->per_roam_config.tx_high_rate_thresh; + pMac->roam.configParam.per_roam_config.rx_high_rate_thresh = + pParam->per_roam_config.rx_high_rate_thresh; + pMac->roam.configParam.per_roam_config.tx_low_rate_thresh = + pParam->per_roam_config.tx_low_rate_thresh; + pMac->roam.configParam.per_roam_config.rx_low_rate_thresh = + pParam->per_roam_config.rx_low_rate_thresh; + pMac->roam.configParam.per_roam_config.tx_rate_thresh_percnt = + pParam->per_roam_config.tx_rate_thresh_percnt; + pMac->roam.configParam.per_roam_config.rx_rate_thresh_percnt = + pParam->per_roam_config.rx_rate_thresh_percnt; + pMac->roam.configParam.per_roam_config.per_rest_time = + pParam->per_roam_config.per_rest_time; + pMac->roam.configParam.per_roam_config.tx_per_mon_time = + pParam->per_roam_config.tx_per_mon_time; + pMac->roam.configParam.per_roam_config.rx_per_mon_time = + pParam->per_roam_config.rx_per_mon_time; + pMac->roam.configParam.per_roam_config.min_candidate_rssi = + pParam->per_roam_config.min_candidate_rssi; + + /* update p2p offload status */ + pMac->pnoOffload = pParam->pnoOffload; + + pMac->fEnableDebugLog = pParam->fEnableDebugLog; + + /* update interface configuration */ + pMac->sme.max_intf_count = pParam->max_intf_count; + + pMac->enable5gEBT = pParam->enable5gEBT; + pMac->sme.enableSelfRecovery = pParam->enableSelfRecovery; + + pMac->f_sta_miracast_mcc_rest_time_val = + pParam->f_sta_miracast_mcc_rest_time_val; +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE + pMac->sap.sap_channel_avoidance = + pParam->sap_channel_avoidance; +#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ + + pMac->f_prefer_non_dfs_on_radar = + pParam->f_prefer_non_dfs_on_radar; + + pMac->sme.ps_global_info.ps_enabled = + pParam->is_ps_enabled; + pMac->sme.ps_global_info.auto_bmps_timer_val = + pParam->auto_bmps_timer_val; + pMac->roam.configParam.ignore_peer_ht_opmode = + pParam->ignore_peer_ht_opmode; + pMac->fine_time_meas_cap = pParam->fine_time_meas_cap; + pMac->dual_mac_feature_disable = + pParam->dual_mac_feature_disable; + sme_update_roam_pno_channel_prediction_config(pMac, pParam, + SME_CONFIG_TO_ROAM_CONFIG); + pMac->roam.configParam.early_stop_scan_enable = + pParam->early_stop_scan_enable; + pMac->roam.configParam.early_stop_scan_min_threshold = + pParam->early_stop_scan_min_threshold; + pMac->roam.configParam.early_stop_scan_max_threshold = + pParam->early_stop_scan_max_threshold; + pMac->roam.configParam.enable_edca_params = + pParam->enable_edca_params; + pMac->roam.configParam.edca_vo_cwmin = pParam->edca_vo_cwmin; + pMac->roam.configParam.edca_vi_cwmin = pParam->edca_vi_cwmin; + pMac->roam.configParam.edca_bk_cwmin = pParam->edca_bk_cwmin; + pMac->roam.configParam.edca_be_cwmin = pParam->edca_be_cwmin; + + pMac->roam.configParam.edca_vo_cwmax = pParam->edca_vo_cwmax; + pMac->roam.configParam.edca_vi_cwmax = pParam->edca_vi_cwmax; + pMac->roam.configParam.edca_bk_cwmax = pParam->edca_bk_cwmax; + pMac->roam.configParam.edca_be_cwmax = pParam->edca_be_cwmax; + + pMac->roam.configParam.edca_vo_aifs = pParam->edca_vo_aifs; + pMac->roam.configParam.edca_vi_aifs = pParam->edca_vi_aifs; + pMac->roam.configParam.edca_bk_aifs = pParam->edca_bk_aifs; + pMac->roam.configParam.edca_be_aifs = pParam->edca_be_aifs; + + pMac->roam.configParam.enable_fatal_event = + pParam->enable_fatal_event; + pMac->roam.configParam.sta_roam_policy.dfs_mode = + pParam->sta_roam_policy_params.dfs_mode; + pMac->roam.configParam.sta_roam_policy.skip_unsafe_channels = + pParam->sta_roam_policy_params.skip_unsafe_channels; + + pMac->roam.configParam.tx_aggregation_size = + pParam->tx_aggregation_size; + pMac->roam.configParam.rx_aggregation_size = + pParam->rx_aggregation_size; + pMac->roam.configParam.enable_bcast_probe_rsp = + pParam->enable_bcast_probe_rsp; + pMac->roam.configParam.qcn_ie_support = + pParam->qcn_ie_support; + pMac->roam.configParam.fils_max_chan_guard_time = + pParam->fils_max_chan_guard_time; + pMac->roam.configParam.is_bssid_hint_priority = + pParam->is_bssid_hint_priority; + + + } + return status; +} + +QDF_STATUS csr_get_config_param(tpAniSirGlobal pMac, tCsrConfigParam *pParam) +{ + int i; + tCsrConfig *cfg_params = &pMac->roam.configParam; + + if (!pParam) + return QDF_STATUS_E_INVAL; + + pParam->pkt_err_disconn_th = cfg_params->pkt_err_disconn_th; + pParam->is_force_1x1 = cfg_params->is_force_1x1; + pParam->WMMSupportMode = cfg_params->WMMSupportMode; + pParam->Is11eSupportEnabled = cfg_params->Is11eSupportEnabled; + pParam->FragmentationThreshold = cfg_params->FragmentationThreshold; + pParam->Is11dSupportEnabled = cfg_params->Is11dSupportEnabled; + pParam->Is11dSupportEnabledOriginal = + cfg_params->Is11dSupportEnabledOriginal; + pParam->Is11hSupportEnabled = cfg_params->Is11hSupportEnabled; + pParam->channelBondingMode24GHz = csr_convert_phy_cb_state_to_ini_value( + cfg_params->channelBondingMode24GHz); + pParam->channelBondingMode5GHz = csr_convert_phy_cb_state_to_ini_value( + cfg_params->channelBondingMode5GHz); + pParam->RTSThreshold = cfg_params->RTSThreshold; + pParam->phyMode = cfg_params->phyMode; + pParam->shortSlotTime = cfg_params->shortSlotTime; + pParam->HeartbeatThresh24 = cfg_params->HeartbeatThresh24; + pParam->HeartbeatThresh50 = cfg_params->HeartbeatThresh50; + pParam->ProprietaryRatesEnabled = cfg_params->ProprietaryRatesEnabled; + pParam->TxRate = cfg_params->TxRate; + pParam->AdHocChannel24 = cfg_params->AdHocChannel24; + pParam->AdHocChannel5G = cfg_params->AdHocChannel5G; + pParam->bandCapability = cfg_params->bandCapability; + pParam->cbChoice = cfg_params->cbChoice; + pParam->nActiveMaxChnTime = cfg_params->nActiveMaxChnTime; + pParam->nActiveMinChnTime = cfg_params->nActiveMinChnTime; + pParam->nPassiveMaxChnTime = cfg_params->nPassiveMaxChnTime; + pParam->nPassiveMinChnTime = cfg_params->nPassiveMinChnTime; + pParam->scan_probe_repeat_time = cfg_params->scan_probe_repeat_time; + pParam->scan_num_probes = cfg_params->scan_num_probes; +#ifdef WLAN_AP_STA_CONCURRENCY + pParam->nActiveMaxChnTimeConc = cfg_params->nActiveMaxChnTimeConc; + pParam->nActiveMinChnTimeConc = cfg_params->nActiveMinChnTimeConc; + pParam->nPassiveMaxChnTimeConc = cfg_params->nPassiveMaxChnTimeConc; + pParam->nPassiveMinChnTimeConc = cfg_params->nPassiveMinChnTimeConc; + pParam->nRestTimeConc = cfg_params->nRestTimeConc; + pParam->min_rest_time_conc = cfg_params->min_rest_time_conc; + pParam->idle_time_conc = cfg_params->idle_time_conc; + pParam->nNumStaChanCombinedConc = cfg_params->nNumStaChanCombinedConc; + pParam->nNumP2PChanCombinedConc = cfg_params->nNumP2PChanCombinedConc; +#endif + pParam->eBand = cfg_params->eBand; + pParam->nScanResultAgeCount = cfg_params->agingCount; + pParam->bCatRssiOffset = cfg_params->bCatRssiOffset; + pParam->fSupplicantCountryCodeHasPriority = + cfg_params->fSupplicantCountryCodeHasPriority; + pParam->vccRssiThreshold = cfg_params->vccRssiThreshold; + pParam->vccUlMacLossThreshold = cfg_params->vccUlMacLossThreshold; + pParam->nTxPowerCap = cfg_params->nTxPowerCap; + pParam->allow_tpc_from_ap = cfg_params->allow_tpc_from_ap; + pParam->statsReqPeriodicity = cfg_params->statsReqPeriodicity; + pParam->statsReqPeriodicityInPS = cfg_params->statsReqPeriodicityInPS; + pParam->addTSWhenACMIsOff = cfg_params->addTSWhenACMIsOff; + pParam->fValidateList = cfg_params->fValidateList; + pParam->fEnableBypass11d = pMac->scan.fEnableBypass11d; + pParam->fEnableDFSChnlScan = pMac->scan.fEnableDFSChnlScan; + pParam->fScanTwice = cfg_params->fScanTwice; + pParam->fFirstScanOnly2GChnl = pMac->scan.fFirstScanOnly2GChnl; + pParam->fEnableMCCMode = cfg_params->fenableMCCMode; + pParam->fAllowMCCGODiffBI = cfg_params->fAllowMCCGODiffBI; + pParam->scanCfgAgingTime = pMac->scan.scanResultCfgAgingTime; + qdf_mem_copy(&pParam->neighborRoamConfig, + &cfg_params->neighborRoamConfig, + sizeof(tCsrNeighborRoamConfigParams)); + pParam->nVhtChannelWidth = cfg_params->nVhtChannelWidth; + pParam->enable_txbf_sap_mode = + cfg_params->enable_txbf_sap_mode; + pParam->enableVhtFor24GHz = cfg_params->enableVhtFor24GHz; + pParam->ignore_peer_erp_info = cfg_params->ignore_peer_erp_info; + pParam->enable2x2 = cfg_params->enable2x2; + qdf_mem_copy(&cfg_params->csr11rConfig, &pParam->csr11rConfig, + sizeof(tCsr11rConfigParams)); + pParam->isFastTransitionEnabled = cfg_params->isFastTransitionEnabled; + pParam->RoamRssiDiff = cfg_params->RoamRssiDiff; + pParam->nRoamPrefer5GHz = cfg_params->nRoamPrefer5GHz; + pParam->nRoamIntraBand = cfg_params->nRoamIntraBand; + pParam->isWESModeEnabled = cfg_params->isWESModeEnabled; + pParam->nProbes = cfg_params->nProbes; + pParam->nRoamScanHomeAwayTime = cfg_params->nRoamScanHomeAwayTime; + pParam->isRoamOffloadScanEnabled = cfg_params->isRoamOffloadScanEnabled; + pParam->bFastRoamInConIniFeatureEnabled = + cfg_params->bFastRoamInConIniFeatureEnabled; + pParam->isFastRoamIniFeatureEnabled = + cfg_params->isFastRoamIniFeatureEnabled; +#ifdef FEATURE_WLAN_ESE + pParam->isEseIniFeatureEnabled = cfg_params->isEseIniFeatureEnabled; +#endif + qdf_mem_copy(&pParam->neighborRoamConfig, + &cfg_params->neighborRoamConfig, + sizeof(tCsrNeighborRoamConfigParams)); + sms_log(pMac, LOG1, + FL("Num of Channels in CFG Channel List: %d"), + cfg_params->neighborRoamConfig. + neighborScanChanList.numChannels); + for (i = 0; i < cfg_params->neighborRoamConfig. + neighborScanChanList.numChannels; i++) { + sms_log(pMac, LOG1, "%d ", + cfg_params->neighborRoamConfig. + neighborScanChanList.channelList[i]); + } + +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH + pParam->cc_switch_mode = cfg_params->cc_switch_mode; +#endif + pParam->enableTxLdpc = cfg_params->txLdpcEnable; + pParam->enableRxLDPC = cfg_params->rxLdpcEnable; + pParam->disable_high_ht_mcs_2x2 = cfg_params->disable_high_ht_mcs_2x2; + pParam->max_amsdu_num = cfg_params->max_amsdu_num; + pParam->nSelect5GHzMargin = cfg_params->nSelect5GHzMargin; + pParam->isCoalesingInIBSSAllowed = cfg_params->isCoalesingInIBSSAllowed; + pParam->allowDFSChannelRoam = cfg_params->allowDFSChannelRoam; + pParam->nInitialDwellTime = cfg_params->nInitialDwellTime; + pParam->initial_scan_no_dfs_chnl = cfg_params->initial_scan_no_dfs_chnl; +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + pParam->isRoamOffloadEnabled = cfg_params->isRoamOffloadEnabled; +#endif + pParam->enable_dot11p = pMac->enable_dot11p; + csr_set_channels(pMac, pParam); + pParam->obssEnabled = cfg_params->obssEnabled; + pParam->vendor_vht_sap = + pMac->roam.configParam.vendor_vht_sap; + pParam->roam_dense_rssi_thresh_offset = + cfg_params->roam_params.dense_rssi_thresh_offset; + pParam->roam_dense_min_aps = + cfg_params->roam_params.dense_min_aps_cnt; + pParam->roam_dense_traffic_thresh = + cfg_params->roam_params.traffic_threshold; + + pParam->scan_adaptive_dwell_mode = + cfg_params->scan_adaptive_dwell_mode; + pParam->roamscan_adaptive_dwell_mode = + cfg_params->roamscan_adaptive_dwell_mode; + + pParam->per_roam_config.enable = cfg_params->per_roam_config.enable; + pParam->per_roam_config.tx_high_rate_thresh = + cfg_params->per_roam_config.tx_high_rate_thresh; + pParam->per_roam_config.rx_high_rate_thresh = + cfg_params->per_roam_config.rx_high_rate_thresh; + pParam->per_roam_config.tx_low_rate_thresh = + cfg_params->per_roam_config.tx_low_rate_thresh; + pParam->per_roam_config.rx_low_rate_thresh = + cfg_params->per_roam_config.rx_low_rate_thresh; + pParam->per_roam_config.tx_rate_thresh_percnt = + cfg_params->per_roam_config.tx_rate_thresh_percnt; + pParam->per_roam_config.rx_rate_thresh_percnt = + cfg_params->per_roam_config.rx_rate_thresh_percnt; + pParam->per_roam_config.per_rest_time = + cfg_params->per_roam_config.per_rest_time; + pParam->per_roam_config.tx_per_mon_time = + cfg_params->per_roam_config.tx_per_mon_time; + pParam->per_roam_config.rx_per_mon_time = + cfg_params->per_roam_config.rx_per_mon_time; + pParam->per_roam_config.min_candidate_rssi = + cfg_params->per_roam_config.min_candidate_rssi; + + pParam->conc_custom_rule1 = cfg_params->conc_custom_rule1; + pParam->conc_custom_rule2 = cfg_params->conc_custom_rule2; + pParam->is_sta_connection_in_5gz_enabled = + cfg_params->is_sta_connection_in_5gz_enabled; + pParam->sendDeauthBeforeCon = + cfg_params->sendDeauthBeforeCon; + pParam->max_scan_count = pMac->scan.max_scan_count; + pParam->first_scan_bucket_threshold = + pMac->first_scan_bucket_threshold; +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE + pParam->sap_channel_avoidance = pMac->sap.sap_channel_avoidance; +#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ + pParam->max_intf_count = pMac->sme.max_intf_count; + pParam->enableSelfRecovery = pMac->sme.enableSelfRecovery; + pParam->pnoOffload = pMac->pnoOffload; + pParam->f_prefer_non_dfs_on_radar = + pMac->f_prefer_non_dfs_on_radar; + pParam->fine_time_meas_cap = pMac->fine_time_meas_cap; + pParam->dual_mac_feature_disable = + pMac->dual_mac_feature_disable; + pParam->is_ps_enabled = pMac->sme.ps_global_info.ps_enabled; + pParam->auto_bmps_timer_val = + pMac->sme.ps_global_info.auto_bmps_timer_val; + pParam->fEnableDebugLog = pMac->fEnableDebugLog; + pParam->enable5gEBT = pMac->enable5gEBT; + pParam->f_sta_miracast_mcc_rest_time_val = + pMac->f_sta_miracast_mcc_rest_time_val; + sme_update_roam_pno_channel_prediction_config(pMac, pParam, + ROAM_CONFIG_TO_SME_CONFIG); + pParam->early_stop_scan_enable = + pMac->roam.configParam.early_stop_scan_enable; + pParam->early_stop_scan_min_threshold = + pMac->roam.configParam.early_stop_scan_min_threshold; + pParam->early_stop_scan_max_threshold = + pMac->roam.configParam.early_stop_scan_max_threshold; + pParam->obss_width_interval = + pMac->roam.configParam.obss_width_interval; + pParam->obss_active_dwelltime = + pMac->roam.configParam.obss_active_dwelltime; + pParam->obss_passive_dwelltime = + pMac->roam.configParam.obss_passive_dwelltime; + pParam->ignore_peer_ht_opmode = + pMac->roam.configParam.ignore_peer_ht_opmode; + pParam->enableHtSmps = pMac->roam.configParam.enableHtSmps; + pParam->htSmps = pMac->roam.configParam.htSmps; + pParam->send_smps_action = pMac->roam.configParam.send_smps_action; + + pParam->enable_edca_params = + pMac->roam.configParam.enable_edca_params; + pParam->edca_vo_cwmin = pMac->roam.configParam.edca_vo_cwmin; + pParam->edca_vi_cwmin = pMac->roam.configParam.edca_vi_cwmin; + pParam->edca_bk_cwmin = pMac->roam.configParam.edca_bk_cwmin; + pParam->edca_be_cwmin = pMac->roam.configParam.edca_be_cwmin; + + pParam->edca_vo_cwmax = pMac->roam.configParam.edca_vo_cwmax; + pParam->edca_vi_cwmax = pMac->roam.configParam.edca_vi_cwmax; + pParam->edca_bk_cwmax = pMac->roam.configParam.edca_bk_cwmax; + pParam->edca_be_cwmax = pMac->roam.configParam.edca_be_cwmax; + + pParam->edca_vo_aifs = pMac->roam.configParam.edca_vo_aifs; + pParam->edca_vi_aifs = pMac->roam.configParam.edca_vi_aifs; + pParam->edca_bk_aifs = pMac->roam.configParam.edca_bk_aifs; + pParam->edca_be_aifs = pMac->roam.configParam.edca_be_aifs; + pParam->enable_fatal_event = + pMac->roam.configParam.enable_fatal_event; + pParam->sta_roam_policy_params.dfs_mode = + pMac->roam.configParam.sta_roam_policy.dfs_mode; + pParam->sta_roam_policy_params.skip_unsafe_channels = + pMac->roam.configParam.sta_roam_policy.skip_unsafe_channels; + pParam->tx_aggregation_size = + pMac->roam.configParam.tx_aggregation_size; + pParam->rx_aggregation_size = + pMac->roam.configParam.rx_aggregation_size; + pParam->enable_bcast_probe_rsp = + pMac->roam.configParam.enable_bcast_probe_rsp; + pParam->qcn_ie_support = + pMac->roam.configParam.qcn_ie_support; + pParam->fils_max_chan_guard_time = + pMac->roam.configParam.fils_max_chan_guard_time; + pParam->is_bssid_hint_priority = + pMac->roam.configParam.is_bssid_hint_priority; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS csr_set_phy_mode(tHalHandle hHal, uint32_t phyMode, eCsrBand eBand, + bool *pfRestartNeeded) +{ + QDF_STATUS status = QDF_STATUS_E_INVAL; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + bool fRestartNeeded = false; + eCsrPhyMode newPhyMode = eCSR_DOT11_MODE_AUTO; + if (eCSR_BAND_24 == eBand) { + if (CSR_IS_RADIO_A_ONLY(pMac)) + goto end; + if (eCSR_DOT11_MODE_11a & phyMode) + goto end; + } + if (eCSR_BAND_5G == eBand) { + if (CSR_IS_RADIO_BG_ONLY(pMac)) + goto end; + if ((eCSR_DOT11_MODE_11b & phyMode) + || (eCSR_DOT11_MODE_11b_ONLY & phyMode) + || (eCSR_DOT11_MODE_11g & phyMode) + || (eCSR_DOT11_MODE_11g_ONLY & phyMode)) + goto end; + } + if (eCSR_DOT11_MODE_AUTO & phyMode) + newPhyMode = eCSR_DOT11_MODE_AUTO; + else { + /* Check for dual band and higher capability first */ + if (eCSR_DOT11_MODE_11n_ONLY & phyMode) { + if (eCSR_DOT11_MODE_11n_ONLY != phyMode) + goto end; + newPhyMode = eCSR_DOT11_MODE_11n_ONLY; + } else if (eCSR_DOT11_MODE_11g_ONLY & phyMode) { + if (eCSR_DOT11_MODE_11g_ONLY != phyMode) + goto end; + if (eCSR_BAND_5G == eBand) + goto end; + newPhyMode = eCSR_DOT11_MODE_11g_ONLY; + eBand = eCSR_BAND_24; + } else if (eCSR_DOT11_MODE_11b_ONLY & phyMode) { + if (eCSR_DOT11_MODE_11b_ONLY != phyMode) + goto end; + if (eCSR_BAND_5G == eBand) + goto end; + newPhyMode = eCSR_DOT11_MODE_11b_ONLY; + eBand = eCSR_BAND_24; + } else if (eCSR_DOT11_MODE_11n & phyMode) { + newPhyMode = eCSR_DOT11_MODE_11n; + } else if (eCSR_DOT11_MODE_abg & phyMode) { + newPhyMode = eCSR_DOT11_MODE_abg; + } else if (eCSR_DOT11_MODE_11a & phyMode) { + if ((eCSR_DOT11_MODE_11g & phyMode) + || (eCSR_DOT11_MODE_11b & phyMode)) { + if (eCSR_BAND_ALL == eBand) + newPhyMode = eCSR_DOT11_MODE_abg; + else + goto end; + } else { + newPhyMode = eCSR_DOT11_MODE_11a; + eBand = eCSR_BAND_5G; + } + } else if (eCSR_DOT11_MODE_11g & phyMode) { + newPhyMode = eCSR_DOT11_MODE_11g; + eBand = eCSR_BAND_24; + } else if (eCSR_DOT11_MODE_11b & phyMode) { + newPhyMode = eCSR_DOT11_MODE_11b; + eBand = eCSR_BAND_24; + } else { + /* We will never be here */ + sms_log(pMac, LOGE, + FL("can't recognize phymode 0x%08X"), + phyMode); + newPhyMode = eCSR_DOT11_MODE_AUTO; + } + } + /* Done validating */ + status = QDF_STATUS_SUCCESS; + /* Now we need to check whether a restart is needed. */ + if (eBand != pMac->roam.configParam.eBand) { + fRestartNeeded = true; + goto end; + } + if (newPhyMode != pMac->roam.configParam.phyMode) { + fRestartNeeded = true; + goto end; + } +end: + if (QDF_IS_STATUS_SUCCESS(status)) { + pMac->roam.configParam.eBand = eBand; + pMac->roam.configParam.phyMode = newPhyMode; + if (pfRestartNeeded) + *pfRestartNeeded = fRestartNeeded; + } + return status; +} + +/** + * csr_prune_ch_list() - prunes the channel list to keep only a type of channels + * @ch_lst: existing channel list + * @is_24_GHz: indicates if 2.5 GHz or 5 GHz channels are required + * + * Return: void + */ +static void csr_prune_ch_list(tCsrChannel *ch_lst, bool is_24_GHz) +{ + uint8_t idx = 0, num_channels = 0; + for ( ; idx < ch_lst->numChannels; idx++) { + if (is_24_GHz) { + if (CDS_IS_CHANNEL_24GHZ(ch_lst->channelList[idx])) { + ch_lst->channelList[num_channels] = + ch_lst->channelList[idx]; + num_channels++; + } + } else { + if (CDS_IS_CHANNEL_5GHZ(ch_lst->channelList[idx])) { + ch_lst->channelList[num_channels] = + ch_lst->channelList[idx]; + num_channels++; + } + } + } + /* + * Cleanup the rest of channels. Note we only need to clean up the + * channels if we had to trim the list. Calling qdf_mem_set() with a 0 + * size is going to throw asserts on the debug builds so let's be a bit + * smarter about that. Zero out the reset of the channels only if we + * need to. The amount of memory to clear is the number of channesl that + * we trimmed (ch_lst->numChannels - num_channels) times the size of a + * channel in the structure. + */ + if (ch_lst->numChannels > num_channels) { + qdf_mem_set(&ch_lst->channelList[num_channels], + sizeof(ch_lst->channelList[0]) * + (ch_lst->numChannels - num_channels), 0); + } + ch_lst->numChannels = num_channels; +} + +/** + * csr_prune_channel_list_for_mode() - prunes the channel list + * @mac_ctx: global mac context + * @ch_lst: existing channel list + * + * Prunes the channel list according to band stored in mac_ctx + * + * Return: void + */ +void csr_prune_channel_list_for_mode(tpAniSirGlobal mac_ctx, + tCsrChannel *ch_lst) +{ + /* for dual band NICs, don't need to trim the channel list.... */ + if (CSR_IS_OPEARTING_DUAL_BAND(mac_ctx)) + return; + /* + * 2.4 GHz band operation requires the channel list to be trimmed to + * the 2.4 GHz channels only + */ + if (CSR_IS_24_BAND_ONLY(mac_ctx)) + csr_prune_ch_list(ch_lst, true); + else if (CSR_IS_5G_BAND_ONLY(mac_ctx)) + csr_prune_ch_list(ch_lst, false); +} + +#define INFRA_AP_DEFAULT_CHANNEL 6 +QDF_STATUS csr_is_valid_channel(tpAniSirGlobal pMac, uint8_t chnNum) +{ + uint8_t index = 0; + QDF_STATUS status = QDF_STATUS_E_NOSUPPORT; + + /* regulatory check */ + for (index = 0; index < pMac->scan.base_channels.numChannels; + index++) { + if (pMac->scan.base_channels.channelList[index] == chnNum) { + status = QDF_STATUS_SUCCESS; + break; + } + } + + if (status == QDF_STATUS_SUCCESS) { + /* dfs nol */ + for (index = 0; + index < + pMac->sap.SapDfsInfo.numCurrentRegDomainDfsChannels; + index++) { + tSapDfsNolInfo *dfsChan = + &pMac->sap.SapDfsInfo.sapDfsChannelNolList[index]; + if ((dfsChan->dfs_channel_number == chnNum) + && (dfsChan->radar_status_flag == + eSAP_DFS_CHANNEL_UNAVAILABLE)) { + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_ERROR, + FL("channel %d is in dfs nol"), + chnNum); + status = QDF_STATUS_E_FAILURE; + break; + } + } + } + + if (QDF_STATUS_SUCCESS != status) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("channel %d is not available"), chnNum); + } + + return status; +} + +QDF_STATUS csr_get_channel_and_power_list(tpAniSirGlobal pMac) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + uint8_t num20MHzChannelsFound = 0; + QDF_STATUS qdf_status; + uint8_t Index = 0; + + qdf_status = + cds_get_channel_list_with_power(pMac->scan.defaultPowerTable, + &num20MHzChannelsFound); + + if ((QDF_STATUS_SUCCESS != qdf_status) || + (num20MHzChannelsFound == 0)) { + sms_log(pMac, LOGE, FL("failed to get channels ")); + status = QDF_STATUS_E_FAILURE; + } else { + if (num20MHzChannelsFound > WNI_CFG_VALID_CHANNEL_LIST_LEN) { + num20MHzChannelsFound = WNI_CFG_VALID_CHANNEL_LIST_LEN; + } + pMac->scan.numChannelsDefault = num20MHzChannelsFound; + /* Move the channel list to the global data */ + /* structure -- this will be used as the scan list */ + for (Index = 0; Index < num20MHzChannelsFound; Index++) { + pMac->scan.base_channels.channelList[Index] = + pMac->scan.defaultPowerTable[Index].chan_num; + } + pMac->scan.base_channels.numChannels = + num20MHzChannelsFound; + } + return status; +} + +QDF_STATUS csr_apply_channel_and_power_list(tpAniSirGlobal pMac) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + + csr_prune_channel_list_for_mode(pMac, &pMac->scan.base_channels); + csr_save_channel_power_for_band(pMac, false); + csr_save_channel_power_for_band(pMac, true); + csr_apply_channel_power_info_to_fw(pMac, + &pMac->scan.base_channels, + pMac->scan.countryCodeCurrent); + + csr_init_operating_classes((tHalHandle) pMac); + return status; +} + +static QDF_STATUS csr_init11d_info(tpAniSirGlobal pMac, tCsr11dinfo *ps11dinfo) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + uint8_t index; + uint32_t count = 0; + tSirMacChanInfo *pChanInfo; + tSirMacChanInfo *pChanInfoStart; + bool applyConfig = true; + + pMac->scan.currentCountryRSSI = -128; + if (!ps11dinfo) { + return status; + } + if (ps11dinfo->Channels.numChannels + && (WNI_CFG_VALID_CHANNEL_LIST_LEN >= + ps11dinfo->Channels.numChannels)) { + pMac->scan.base_channels.numChannels = + ps11dinfo->Channels.numChannels; + qdf_mem_copy(pMac->scan.base_channels.channelList, + ps11dinfo->Channels.channelList, + ps11dinfo->Channels.numChannels); + } else { + /* No change */ + return QDF_STATUS_SUCCESS; + } + /* legacy maintenance */ + + qdf_mem_copy(pMac->scan.countryCodeDefault, ps11dinfo->countryCode, + WNI_CFG_COUNTRY_CODE_LEN); + + /* Tush: at csropen get this initialized with default, during csr reset if this */ + /* already set with some value no need initilaize with default again */ + if (0 == pMac->scan.countryCodeCurrent[0]) { + qdf_mem_copy(pMac->scan.countryCodeCurrent, + ps11dinfo->countryCode, WNI_CFG_COUNTRY_CODE_LEN); + } + /* need to add the max power channel list */ + pChanInfo = + qdf_mem_malloc(sizeof(tSirMacChanInfo) * + WNI_CFG_VALID_CHANNEL_LIST_LEN); + if (pChanInfo != NULL) { + pChanInfoStart = pChanInfo; + for (index = 0; index < ps11dinfo->Channels.numChannels; + index++) { + pChanInfo->firstChanNum = + ps11dinfo->ChnPower[index].firstChannel; + pChanInfo->numChannels = + ps11dinfo->ChnPower[index].numChannels; + pChanInfo->maxTxPower = + QDF_MIN(ps11dinfo->ChnPower[index].maxtxPower, + pMac->roam.configParam.nTxPowerCap); + pChanInfo++; + count++; + } + if (count) { + status = csr_save_to_channel_power2_g_5_g(pMac, + count * + sizeof(tSirMacChanInfo), + pChanInfoStart); + } + qdf_mem_free(pChanInfoStart); + } + /* Only apply them to CFG when not in STOP state. Otherwise they will be applied later */ + if (QDF_IS_STATUS_SUCCESS(status)) { + for (index = 0; index < CSR_ROAM_SESSION_MAX; index++) { + if ((CSR_IS_SESSION_VALID(pMac, index)) + && CSR_IS_ROAM_STOP(pMac, index)) { + applyConfig = false; + } + } + + if (true == applyConfig) { + /* Apply the base channel list, power info, and set the Country code... */ + csr_apply_channel_power_info_to_fw(pMac, + &pMac->scan. + base_channels, + pMac->scan. + countryCodeCurrent); + } + } + return status; +} + +/* Initialize the Channel + Power List in the local cache and in the CFG */ +QDF_STATUS csr_init_channel_power_list(tpAniSirGlobal pMac, tCsr11dinfo *ps11dinfo) +{ + uint8_t index; + uint32_t count = 0; + tSirMacChanInfo *pChanInfo; + tSirMacChanInfo *pChanInfoStart; + + if (!ps11dinfo || !pMac) { + return QDF_STATUS_E_FAILURE; + } + + pChanInfo = + qdf_mem_malloc(sizeof(tSirMacChanInfo) * + WNI_CFG_VALID_CHANNEL_LIST_LEN); + if (pChanInfo != NULL) { + pChanInfoStart = pChanInfo; + + for (index = 0; index < ps11dinfo->Channels.numChannels; + index++) { + pChanInfo->firstChanNum = + ps11dinfo->ChnPower[index].firstChannel; + pChanInfo->numChannels = + ps11dinfo->ChnPower[index].numChannels; + pChanInfo->maxTxPower = + QDF_MIN(ps11dinfo->ChnPower[index].maxtxPower, + pMac->roam.configParam.nTxPowerCap); + pChanInfo++; + count++; + } + if (count) { + csr_save_to_channel_power2_g_5_g(pMac, + count * + sizeof(tSirMacChanInfo), + pChanInfoStart); + } + qdf_mem_free(pChanInfoStart); + } + + return QDF_STATUS_SUCCESS; +} + +/** + * csr_roam_remove_duplicate_cmd_from_list()- Remove duplicate roam cmd from + * list + * + * @mac_ctx: pointer to global mac + * @session_id: session id for the cmd + * @list: pending list from which cmd needs to be removed + * @command: cmd to be removed, can be NULL + * @roam_reason: cmd with reason to be removed + * + * Remove duplicate command from the pending list. + * + * Return: void + */ +static void csr_roam_remove_duplicate_cmd_from_list(tpAniSirGlobal mac_ctx, + uint32_t session_id, tDblLinkList *list, + tSmeCmd *command, eCsrRoamReason roam_reason) +{ + tListElem *entry, *next_entry; + tSmeCmd *dup_cmd; + tDblLinkList local_list; + + qdf_mem_zero(&local_list, sizeof(tDblLinkList)); + if (!QDF_IS_STATUS_SUCCESS(csr_ll_open(mac_ctx->hHdd, &local_list))) { + sms_log(mac_ctx, LOGE, FL(" failed to open list")); + return; + } + csr_ll_lock(list); + entry = csr_ll_peek_head(list, LL_ACCESS_NOLOCK); + while (entry) { + next_entry = csr_ll_next(list, entry, LL_ACCESS_NOLOCK); + dup_cmd = GET_BASE_ADDR(entry, tSmeCmd, Link); + /* + * Remove the previous command if.. + * - the new roam command is for the same RoamReason... + * - the new roam command is a NewProfileList. + * - the new roam command is a Forced Dissoc + * - the new roam command is from an 802.11 OID + * (OID_SSID or OID_BSSID). + */ + if ((command && (command->sessionId == dup_cmd->sessionId) && + ((command->command == dup_cmd->command) && + /* + * This peermac check is requried for Softap/GO + * scenarios. for STA scenario below OR check will + * suffice as command will always be NULL for + * STA scenarios + */ + (!qdf_mem_cmp(dup_cmd->u.roamCmd.peerMac, + command->u.roamCmd.peerMac, + sizeof(QDF_MAC_ADDR_SIZE))) && + ((command->u.roamCmd.roamReason == + dup_cmd->u.roamCmd.roamReason) || + (eCsrForcedDisassoc == + command->u.roamCmd.roamReason) || + (eCsrHddIssued == + command->u.roamCmd.roamReason)))) || + /* OR if pCommand is NULL */ + ((session_id == dup_cmd->sessionId) && + (eSmeCommandRoam == dup_cmd->command) && + ((eCsrForcedDisassoc == roam_reason) || + (eCsrHddIssued == roam_reason)))) { + sms_log(mac_ctx, LOGW, FL("RoamReason = %d"), + dup_cmd->u.roamCmd.roamReason); + /* Remove the roam command from the pending list */ + if (csr_ll_remove_entry(list, entry, LL_ACCESS_NOLOCK)) + csr_ll_insert_tail(&local_list, entry, + LL_ACCESS_NOLOCK); + } + entry = next_entry; + } + csr_ll_unlock(list); + + while ((entry = csr_ll_remove_head(&local_list, LL_ACCESS_NOLOCK))) { + dup_cmd = GET_BASE_ADDR(entry, tSmeCmd, Link); + /* Tell caller that the command is cancelled */ + csr_roam_call_callback(mac_ctx, dup_cmd->sessionId, NULL, + dup_cmd->u.roamCmd.roamId, + eCSR_ROAM_CANCELLED, eCSR_ROAM_RESULT_NONE); + csr_release_command_roam(mac_ctx, dup_cmd); + } + csr_ll_close(&local_list); +} + +/** + * csr_roam_remove_duplicate_command()- Remove duplicate roam cmd + * from pending lists. + * + * @mac_ctx: pointer to global mac + * @session_id: session id for the cmd + * @command: cmd to be removed, can be null + * @roam_reason: cmd with reason to be removed + * + * Remove duplicate command from the sme and roam pending list. + * + * Return: void + */ +void csr_roam_remove_duplicate_command(tpAniSirGlobal mac_ctx, + uint32_t session_id, tSmeCmd *command, + eCsrRoamReason roam_reason) +{ + /* Always lock active list before locking pending lists */ + csr_ll_lock(&mac_ctx->sme.smeCmdActiveList); + csr_roam_remove_duplicate_cmd_from_list(mac_ctx, + session_id, &mac_ctx->sme.smeCmdPendingList, + command, roam_reason); + csr_roam_remove_duplicate_cmd_from_list(mac_ctx, + session_id, &mac_ctx->roam.roamCmdPendingList, + command, roam_reason); + csr_ll_unlock(&mac_ctx->sme.smeCmdActiveList); +} + +/** + * csr_roam_populate_channels() - Helper function to populate channels + * @beacon_ies: pointer to beacon ie + * @roam_info: Roaming related information + * @chan1: center freq 1 + * @chan2: center freq2 + * + * This function will issue populate chan1 and chan2 based on beacon ie + * + * Return: none. + */ +static void csr_roam_populate_channels(tDot11fBeaconIEs *beacon_ies, + tCsrRoamInfo *roam_info, + uint8_t *chan1, uint8_t *chan2) +{ + ePhyChanBondState phy_state; + if (beacon_ies->VHTOperation.present) { + *chan1 = beacon_ies->VHTOperation.chanCenterFreqSeg1; + *chan2 = beacon_ies->VHTOperation.chanCenterFreqSeg2; + roam_info->chan_info.info = MODE_11AC_VHT80; + } else if (beacon_ies->HTInfo.present) { + if (beacon_ies->HTInfo.recommendedTxWidthSet == + eHT_CHANNEL_WIDTH_40MHZ) { + phy_state = beacon_ies->HTInfo.secondaryChannelOffset; + if (phy_state == PHY_DOUBLE_CHANNEL_LOW_PRIMARY) + *chan1 = beacon_ies->HTInfo.primaryChannel + + CSR_CB_CENTER_CHANNEL_OFFSET; + else if (phy_state == PHY_DOUBLE_CHANNEL_HIGH_PRIMARY) + *chan1 = beacon_ies->HTInfo.primaryChannel - + CSR_CB_CENTER_CHANNEL_OFFSET; + else + *chan1 = beacon_ies->HTInfo.primaryChannel; + + roam_info->chan_info.info = MODE_11NA_HT40; + } else { + *chan1 = beacon_ies->HTInfo.primaryChannel; + roam_info->chan_info.info = MODE_11NA_HT20; + } + *chan2 = 0; + } else { + *chan1 = 0; + *chan2 = 0; + roam_info->chan_info.info = MODE_11A; + } +} + +QDF_STATUS csr_roam_call_callback(tpAniSirGlobal pMac, uint32_t sessionId, + tCsrRoamInfo *pRoamInfo, uint32_t roamId, + eRoamCmdStatus u1, eCsrRoamResult u2) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; +#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR + uint32_t rssi = 0; + WLAN_HOST_DIAG_EVENT_DEF(connectionStatus, + host_event_wlan_status_payload_type); +#endif + tCsrRoamSession *pSession; + tDot11fBeaconIEs *beacon_ies = NULL; + uint8_t chan1, chan2; + + if (!CSR_IS_SESSION_VALID(pMac, sessionId)) { + sms_log(pMac, LOGE, "Session ID:%d is not valid", sessionId); + QDF_ASSERT(0); + return QDF_STATUS_E_FAILURE; + } + pSession = CSR_GET_SESSION(pMac, sessionId); + + if (false == pSession->sessionActive) { + sms_log(pMac, LOG1, "%s Session is not Active", __func__); + return QDF_STATUS_E_FAILURE; + } + + sms_log(pMac, LOG4, "Received RoamCmdStatus %d with Roam Result %d", u1, + u2); + + if (eCSR_ROAM_ASSOCIATION_COMPLETION == u1 && + eCSR_ROAM_RESULT_ASSOCIATED == u2 && pRoamInfo) { + sms_log(pMac, LOGW, + FL("Assoc complete result=%d status=%d reason=%d"), + u2, pRoamInfo->statusCode, pRoamInfo->reasonCode); + beacon_ies = qdf_mem_malloc(sizeof(tDot11fBeaconIEs)); + if ((NULL != beacon_ies) && (NULL != pRoamInfo->pBssDesc)) { + status = csr_parse_bss_description_ies( + (tHalHandle) pMac, pRoamInfo->pBssDesc, + beacon_ies); + csr_roam_populate_channels(beacon_ies, pRoamInfo, + &chan1, &chan2); + if (0 != chan1) + pRoamInfo->chan_info.band_center_freq1 = + cds_chan_to_freq(chan1); + else + pRoamInfo->chan_info.band_center_freq1 = 0; + if (0 != chan2) + pRoamInfo->chan_info.band_center_freq2 = + cds_chan_to_freq(chan2); + else + pRoamInfo->chan_info.band_center_freq2 = 0; + } else { + pRoamInfo->chan_info.band_center_freq1 = 0; + pRoamInfo->chan_info.band_center_freq2 = 0; + pRoamInfo->chan_info.info = 0; + } + pRoamInfo->chan_info.chan_id = + pRoamInfo->u.pConnectedProfile->operationChannel; + pRoamInfo->chan_info.mhz = + cds_chan_to_freq(pRoamInfo->chan_info.chan_id); + pRoamInfo->chan_info.reg_info_1 = + (csr_get_cfg_max_tx_power(pMac, + pRoamInfo->chan_info.chan_id) << 16); + pRoamInfo->chan_info.reg_info_2 = + (csr_get_cfg_max_tx_power(pMac, + pRoamInfo->chan_info.chan_id) << 8); + qdf_mem_free(beacon_ies); + } else if ((u1 == eCSR_ROAM_FT_REASSOC_FAILED) + && (pSession->bRefAssocStartCnt)) { + /* + * Decrement bRefAssocStartCnt for FT reassoc failure. + * Reason: For FT reassoc failures, we first call + * csr_roam_call_callback before notifying a failed roam + * completion through csr_roam_complete. The latter in + * turn calls csr_roam_process_results which tries to + * once again call csr_roam_call_callback if bRefAssocStartCnt + * is non-zero. Since this is redundant for FT reassoc + * failure, decrement bRefAssocStartCnt. + */ + pSession->bRefAssocStartCnt--; + } else if (u1 == eCSR_ROAM_SET_CHANNEL_RSP && u2 == + eCSR_ROAM_RESULT_CHANNEL_CHANGE_SUCCESS) + pSession->connectedProfile.operationChannel = + pRoamInfo->channelChangeRespEvent->newChannelNumber; + + if (NULL != pSession->callback) { + if (pRoamInfo) { + pRoamInfo->sessionId = (uint8_t) sessionId; + /* + * the reasonCode will be passed to supplicant by + * cfg80211_disconnected. Based on the document, + * the reason code passed to supplicant needs to set + * to 0 if unknow. eSIR_BEACON_MISSED reason code is not + * recognizable so that we set to 0 instead. + */ + pRoamInfo->reasonCode = + (pRoamInfo->reasonCode == eSIR_BEACON_MISSED) ? + 0 : pRoamInfo->reasonCode; + } + status = pSession->callback(pSession->pContext, pRoamInfo, + roamId, u1, u2); + } + /* + * EVENT_WLAN_STATUS_V2: eCSR_ROAM_ASSOCIATION_COMPLETION, + * eCSR_ROAM_LOSTLINK, + * eCSR_ROAM_DISASSOCIATED, + */ +#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR + qdf_mem_set(&connectionStatus, + sizeof(host_event_wlan_status_payload_type), 0); + + if ((eCSR_ROAM_ASSOCIATION_COMPLETION == u1) + && (eCSR_ROAM_RESULT_ASSOCIATED == u2) && pRoamInfo) { + connectionStatus.eventId = eCSR_WLAN_STATUS_CONNECT; + connectionStatus.bssType = + pRoamInfo->u.pConnectedProfile->BSSType; + + if (NULL != pRoamInfo->pBssDesc) { + connectionStatus.rssi = + pRoamInfo->pBssDesc->rssi * (-1); + connectionStatus.channel = + pRoamInfo->pBssDesc->channelId; + } + if (cfg_set_int(pMac, WNI_CFG_CURRENT_RSSI, + connectionStatus.rssi) == eSIR_FAILURE) + sms_log(pMac, LOGE, + FL("Can't pass WNI_CFG_CURRENT_RSSI to cfg")); + + connectionStatus.qosCapability = + pRoamInfo->u.pConnectedProfile->qosConnection; + connectionStatus.authType = + (uint8_t) diag_auth_type_from_csr_type( + pRoamInfo->u.pConnectedProfile->AuthType); + connectionStatus.encryptionType = + (uint8_t) diag_enc_type_from_csr_type( + pRoamInfo->u.pConnectedProfile->EncryptionType); + qdf_mem_copy(connectionStatus.ssid, + pRoamInfo->u.pConnectedProfile->SSID.ssId, + pRoamInfo->u.pConnectedProfile->SSID.length); + + connectionStatus.reason = eCSR_REASON_UNSPECIFIED; + qdf_mem_copy(&pMac->sme.eventPayload, &connectionStatus, + sizeof(host_event_wlan_status_payload_type)); + WLAN_HOST_DIAG_EVENT_REPORT(&connectionStatus, + EVENT_WLAN_STATUS_V2); + } + if ((eCSR_ROAM_MIC_ERROR_IND == u1) + || (eCSR_ROAM_RESULT_MIC_FAILURE == u2)) { + qdf_mem_copy(&connectionStatus, &pMac->sme.eventPayload, + sizeof(host_event_wlan_status_payload_type)); + if (IS_SIR_STATUS_SUCCESS(wlan_cfg_get_int(pMac, + WNI_CFG_CURRENT_RSSI, &rssi))) + connectionStatus.rssi = rssi; + + connectionStatus.eventId = eCSR_WLAN_STATUS_DISCONNECT; + connectionStatus.reason = eCSR_REASON_MIC_ERROR; + WLAN_HOST_DIAG_EVENT_REPORT(&connectionStatus, + EVENT_WLAN_STATUS_V2); + } + if (eCSR_ROAM_RESULT_FORCED == u2) { + qdf_mem_copy(&connectionStatus, &pMac->sme.eventPayload, + sizeof(host_event_wlan_status_payload_type)); + if (IS_SIR_STATUS_SUCCESS(wlan_cfg_get_int(pMac, + WNI_CFG_CURRENT_RSSI, &rssi))) + connectionStatus.rssi = rssi; + + connectionStatus.eventId = eCSR_WLAN_STATUS_DISCONNECT; + connectionStatus.reason = eCSR_REASON_USER_REQUESTED; + WLAN_HOST_DIAG_EVENT_REPORT(&connectionStatus, + EVENT_WLAN_STATUS_V2); + } + if (eCSR_ROAM_RESULT_DISASSOC_IND == u2) { + qdf_mem_copy(&connectionStatus, &pMac->sme.eventPayload, + sizeof(host_event_wlan_status_payload_type)); + if (IS_SIR_STATUS_SUCCESS(wlan_cfg_get_int(pMac, + WNI_CFG_CURRENT_RSSI, &rssi))) + connectionStatus.rssi = rssi; + + connectionStatus.eventId = eCSR_WLAN_STATUS_DISCONNECT; + connectionStatus.reason = eCSR_REASON_DISASSOC; + if (pRoamInfo) + connectionStatus.reasonDisconnect = + pRoamInfo->reasonCode; + + WLAN_HOST_DIAG_EVENT_REPORT(&connectionStatus, + EVENT_WLAN_STATUS_V2); + } + if (eCSR_ROAM_RESULT_DEAUTH_IND == u2) { + qdf_mem_copy(&connectionStatus, &pMac->sme.eventPayload, + sizeof(host_event_wlan_status_payload_type)); + if (IS_SIR_STATUS_SUCCESS(wlan_cfg_get_int(pMac, + WNI_CFG_CURRENT_RSSI, &rssi))) + connectionStatus.rssi = rssi; + + connectionStatus.eventId = eCSR_WLAN_STATUS_DISCONNECT; + connectionStatus.reason = eCSR_REASON_DEAUTH; + if (pRoamInfo) + connectionStatus.reasonDisconnect = + pRoamInfo->reasonCode; + WLAN_HOST_DIAG_EVENT_REPORT(&connectionStatus, + EVENT_WLAN_STATUS_V2); + } +#endif /* FEATURE_WLAN_DIAG_SUPPORT_CSR */ + return status; +} + +/* Returns whether handoff is currently in progress or not */ +static +bool csr_roam_is_handoff_in_progress(tpAniSirGlobal pMac, uint8_t sessionId) +{ + return csr_neighbor_roam_is_handoff_in_progress(pMac, sessionId); +} + +static +QDF_STATUS csr_roam_issue_disassociate(tpAniSirGlobal pMac, uint32_t sessionId, + eCsrRoamSubState NewSubstate, + bool fMICFailure) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct qdf_mac_addr bssId = QDF_MAC_ADDR_BROADCAST_INITIALIZER; + uint16_t reasonCode; + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!pSession) { + sms_log(pMac, LOGE, FL(" session %d not found "), sessionId); + return QDF_STATUS_E_FAILURE; + } + + if (fMICFailure) { + reasonCode = eSIR_MAC_MIC_FAILURE_REASON; + } else if (NewSubstate == eCSR_ROAM_SUBSTATE_DISASSOC_HANDOFF) { + reasonCode = eSIR_MAC_DISASSOC_DUE_TO_FTHANDOFF_REASON; + } else if (eCSR_ROAM_SUBSTATE_DISASSOC_STA_HAS_LEFT == NewSubstate) { + reasonCode = eSIR_MAC_DISASSOC_LEAVING_BSS_REASON; + NewSubstate = eCSR_ROAM_SUBSTATE_DISASSOC_FORCED; + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO, + FL + ("set to reason code eSIR_MAC_DISASSOC_LEAVING_BSS_REASON" + " and set back NewSubstate")); + } else { + reasonCode = eSIR_MAC_UNSPEC_FAILURE_REASON; + } + if ((csr_roam_is_handoff_in_progress(pMac, sessionId)) && + (NewSubstate != eCSR_ROAM_SUBSTATE_DISASSOC_HANDOFF)) { + tpCsrNeighborRoamControlInfo pNeighborRoamInfo = + &pMac->roam.neighborRoamInfo[sessionId]; + qdf_copy_macaddr(&bssId, + pNeighborRoamInfo->csrNeighborRoamProfile.BSSIDs. + bssid); + } else if (pSession->pConnectBssDesc) { + qdf_mem_copy(&bssId.bytes, pSession->pConnectBssDesc->bssId, + sizeof(struct qdf_mac_addr)); + } + + sms_log(pMac, LOG1, + FL("CSR Attempting to Disassociate Bssid=" MAC_ADDRESS_STR + " subState = %s reason=%d"), MAC_ADDR_ARRAY(bssId.bytes), + mac_trace_getcsr_roam_sub_state(NewSubstate), reasonCode); + + csr_roam_substate_change(pMac, NewSubstate, sessionId); + + status = csr_send_mb_disassoc_req_msg(pMac, sessionId, bssId.bytes, + reasonCode); + + if (QDF_IS_STATUS_SUCCESS(status)) { + csr_roam_link_down(pMac, sessionId); +#ifndef WLAN_MDM_CODE_REDUCTION_OPT + /* no need to tell QoS that we are disassociating, it will be taken care off in assoc req for HO */ + if (eCSR_ROAM_SUBSTATE_DISASSOC_HANDOFF != NewSubstate) { + /* notify QoS module that disassoc happening */ + sme_qos_csr_event_ind(pMac, (uint8_t) sessionId, + SME_QOS_CSR_DISCONNECT_REQ, NULL); + } +#endif + } else { + sms_log(pMac, LOGW, + FL("csr_send_mb_disassoc_req_msg failed with status %d"), + status); + } + + return status; +} + +/** + * csr_roam_issue_disassociate_sta_cmd() - disassociate a associated station + * @sessionId: Session Id for Soft AP + * @p_del_sta_params: Pointer to parameters of the station to disassoc + * + * CSR function that HDD calls to delete a associated station + * + * Return: QDF_STATUS_SUCCESS on success or another QDF_STATUS_* on error + */ +QDF_STATUS csr_roam_issue_disassociate_sta_cmd(tpAniSirGlobal pMac, + uint32_t sessionId, + struct tagCsrDelStaParams + *p_del_sta_params) + +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tSmeCmd *pCommand; + + do { + pCommand = csr_get_command_buffer(pMac); + if (!pCommand) { + sms_log(pMac, LOGE, FL(" fail to get command buffer")); + status = QDF_STATUS_E_RESOURCES; + break; + } + pCommand->command = eSmeCommandRoam; + pCommand->sessionId = (uint8_t) sessionId; + pCommand->u.roamCmd.roamReason = eCsrForcedDisassocSta; + qdf_mem_copy(pCommand->u.roamCmd.peerMac, + p_del_sta_params->peerMacAddr.bytes, + sizeof(pCommand->u.roamCmd.peerMac)); + pCommand->u.roamCmd.reason = + (tSirMacReasonCodes)p_del_sta_params->reason_code; + status = csr_queue_sme_command(pMac, pCommand, false); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOGE, + FL(" fail to send message status = %d"), status); + csr_release_command_roam(pMac, pCommand); + } + } while (0); + + return status; +} + +/** + * csr_roam_issue_deauthSta() - delete a associated station + * @sessionId: Session Id for Soft AP + * @pDelStaParams: Pointer to parameters of the station to deauthenticate + * + * CSR function that HDD calls to delete a associated station + * + * Return: QDF_STATUS_SUCCESS on success or another QDF_STATUS_** on error + */ +QDF_STATUS csr_roam_issue_deauth_sta_cmd(tpAniSirGlobal pMac, + uint32_t sessionId, + struct tagCsrDelStaParams *pDelStaParams) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tSmeCmd *pCommand; + + do { + pCommand = csr_get_command_buffer(pMac); + if (!pCommand) { + sms_log(pMac, LOGE, FL(" fail to get command buffer")); + status = QDF_STATUS_E_RESOURCES; + break; + } + pCommand->command = eSmeCommandRoam; + pCommand->sessionId = (uint8_t) sessionId; + pCommand->u.roamCmd.roamReason = eCsrForcedDeauthSta; + qdf_mem_copy(pCommand->u.roamCmd.peerMac, + pDelStaParams->peerMacAddr.bytes, + sizeof(tSirMacAddr)); + pCommand->u.roamCmd.reason = + (tSirMacReasonCodes)pDelStaParams->reason_code; + status = csr_queue_sme_command(pMac, pCommand, false); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOGE, + FL(" fail to send message status = %d"), status); + csr_release_command_roam(pMac, pCommand); + } + } while (0); + + return status; +} + +static QDF_STATUS +csr_send_mb_tkip_counter_measures_req_msg(tpAniSirGlobal pMac, + uint32_t sessionId, bool bEnable, + struct qdf_mac_addr *bssId) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tSirSmeTkipCntrMeasReq *pMsg; + do { + pMsg = qdf_mem_malloc(sizeof(tSirSmeTkipCntrMeasReq)); + if (NULL == pMsg) + status = QDF_STATUS_E_NOMEM; + else + status = QDF_STATUS_SUCCESS; + if (!QDF_IS_STATUS_SUCCESS(status)) + break; + pMsg->messageType = eWNI_SME_TKIP_CNTR_MEAS_REQ; + pMsg->length = sizeof(tSirSmeTkipCntrMeasReq); + pMsg->sessionId = sessionId; + pMsg->transactionId = 0; + qdf_copy_macaddr(&pMsg->bssId, bssId); + pMsg->bEnable = bEnable; + status = cds_send_mb_message_to_mac(pMsg); + } while (0); + return status; +} + +QDF_STATUS +csr_roam_issue_tkip_counter_measures(tpAniSirGlobal pMac, uint32_t sessionId, + bool bEnable) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + struct qdf_mac_addr bssId = QDF_MAC_ADDR_BROADCAST_INITIALIZER; + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + if (!pSession) { + sms_log(pMac, LOGE, + "csr_roam_issue_tkip_counter_measures:CSR Session not found"); + return status; + } + if (pSession->pConnectBssDesc) { + qdf_mem_copy(bssId.bytes, pSession->pConnectBssDesc->bssId, + sizeof(struct qdf_mac_addr)); + } else { + sms_log(pMac, LOGE, + "csr_roam_issue_tkip_counter_measures:Connected BSS Description in CSR Session not found"); + return status; + } + sms_log(pMac, LOG2, + "CSR issuing tkip counter measures for Bssid = " MAC_ADDRESS_STR + ", Enable = %d", MAC_ADDR_ARRAY(bssId.bytes), bEnable); + status = + csr_send_mb_tkip_counter_measures_req_msg(pMac, sessionId, + bEnable, &bssId); + return status; +} + +QDF_STATUS +csr_roam_get_associated_stas(tpAniSirGlobal pMac, uint32_t sessionId, + QDF_MODULE_ID modId, void *pUsrContext, + void *pfnSapEventCallback, uint8_t *pAssocStasBuf) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct qdf_mac_addr bssId = QDF_MAC_ADDR_BROADCAST_INITIALIZER; + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + if (!pSession) { + sms_log(pMac, LOGE, + "csr_roam_get_associated_stas:CSR Session not found"); + return status; + } + if (pSession->pConnectBssDesc) { + qdf_mem_copy(bssId.bytes, pSession->pConnectBssDesc->bssId, + sizeof(struct qdf_mac_addr)); + } else { + sms_log(pMac, LOGE, + "csr_roam_get_associated_stas:Connected BSS Description in CSR Session not found"); + return status; + } + sms_log(pMac, LOG2, + "CSR getting associated stations for Bssid = " MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(bssId.bytes)); + status = + csr_send_mb_get_associated_stas_req_msg(pMac, sessionId, modId, + bssId, + pUsrContext, + pfnSapEventCallback, + pAssocStasBuf); + return status; +} + +QDF_STATUS +csr_roam_get_wps_session_overlap(tpAniSirGlobal pMac, uint32_t sessionId, + void *pUsrContext, void *pfnSapEventCallback, + struct qdf_mac_addr pRemoveMac) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct qdf_mac_addr bssId = QDF_MAC_ADDR_BROADCAST_INITIALIZER; + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!pSession) { + sms_log(pMac, LOGE, + "csr_roam_get_wps_session_overlap:CSR Session not found"); + return status; + } + if (pSession->pConnectBssDesc) { + qdf_mem_copy(bssId.bytes, pSession->pConnectBssDesc->bssId, + sizeof(struct qdf_mac_addr)); + } else { + sms_log(pMac, LOGE, + "csr_roam_get_wps_session_overlap:Connected BSS Description in CSR Session not found"); + return status; + } + sms_log(pMac, LOG2, + "CSR getting WPS Session Overlap for Bssid = " MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(bssId.bytes)); + + status = csr_send_mb_get_wpspbc_sessions(pMac, sessionId, bssId, + pUsrContext, pfnSapEventCallback, pRemoveMac); + + return status; +} + +static +QDF_STATUS csr_roam_issue_deauth(tpAniSirGlobal pMac, uint32_t sessionId, + eCsrRoamSubState NewSubstate) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct qdf_mac_addr bssId = QDF_MAC_ADDR_BROADCAST_INITIALIZER; + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!pSession) { + sms_log(pMac, LOGE, FL(" session %d not found "), sessionId); + return QDF_STATUS_E_FAILURE; + } + + if (pSession->pConnectBssDesc) { + qdf_mem_copy(bssId.bytes, pSession->pConnectBssDesc->bssId, + sizeof(struct qdf_mac_addr)); + } + sms_log(pMac, LOG2, "CSR Attempting to Deauth Bssid= " MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(bssId.bytes)); + csr_roam_substate_change(pMac, NewSubstate, sessionId); + + status = + csr_send_mb_deauth_req_msg(pMac, sessionId, bssId.bytes, + eSIR_MAC_DEAUTH_LEAVING_BSS_REASON); + if (QDF_IS_STATUS_SUCCESS(status)) + csr_roam_link_down(pMac, sessionId); + else { + sms_log(pMac, LOGE, + FL + ("csr_send_mb_deauth_req_msg failed with status %d Session ID: %d" + MAC_ADDRESS_STR), status, sessionId, + MAC_ADDR_ARRAY(bssId.bytes)); + } + + return status; +} + +QDF_STATUS csr_roam_save_connected_bss_desc(tpAniSirGlobal pMac, uint32_t sessionId, + tSirBssDescription *pBssDesc) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + uint32_t size; + + if (!pSession) { + sms_log(pMac, LOGE, FL(" session %d not found "), sessionId); + return QDF_STATUS_E_FAILURE; + } + /* If no BSS description was found in this connection (happens with start IBSS), then */ + /* nix the BSS description that we keep around for the connected BSS) and get out... */ + if (NULL == pBssDesc) { + csr_free_connect_bss_desc(pMac, sessionId); + } else { + size = pBssDesc->length + sizeof(pBssDesc->length); + if (NULL != pSession->pConnectBssDesc) { + if (((pSession->pConnectBssDesc->length) + + sizeof(pSession->pConnectBssDesc->length)) < + size) { + /* not enough room for the new BSS, pMac->roam.pConnectBssDesc is freed inside */ + csr_free_connect_bss_desc(pMac, sessionId); + } + } + if (NULL == pSession->pConnectBssDesc) { + pSession->pConnectBssDesc = qdf_mem_malloc(size); + } + if (NULL == pSession->pConnectBssDesc) + status = QDF_STATUS_E_NOMEM; + else + qdf_mem_copy(pSession->pConnectBssDesc, pBssDesc, size); + } + return status; +} + +static +QDF_STATUS csr_roam_prepare_bss_config(tpAniSirGlobal pMac, + tCsrRoamProfile *pProfile, + tSirBssDescription *pBssDesc, + tBssConfigParam *pBssConfig, + tDot11fBeaconIEs *pIes) +{ + eCsrCfgDot11Mode cfgDot11Mode; + QDF_ASSERT(pIes != NULL); + if (pIes == NULL) + return QDF_STATUS_E_FAILURE; + + qdf_mem_copy(&pBssConfig->BssCap, &pBssDesc->capabilityInfo, + sizeof(tSirMacCapabilityInfo)); + /* get qos */ + pBssConfig->qosType = csr_get_qo_s_from_bss_desc(pMac, pBssDesc, pIes); + /* get SSID */ + if (pIes->SSID.present) { + qdf_mem_copy(&pBssConfig->SSID.ssId, pIes->SSID.ssid, + pIes->SSID.num_ssid); + pBssConfig->SSID.length = pIes->SSID.num_ssid; + } else + pBssConfig->SSID.length = 0; + if (csr_is_nullssid(pBssConfig->SSID.ssId, pBssConfig->SSID.length)) { + sms_log(pMac, LOGW, FL("BSS desc SSID is a wild card")); + /* Return failed if profile doesn't have an SSID either. */ + if (pProfile->SSIDs.numOfSSIDs == 0) { + sms_log(pMac, LOGW, + FL("BSS desc and profile doesn't have SSID")); + return QDF_STATUS_E_FAILURE; + } + } + if (CDS_IS_CHANNEL_5GHZ(pBssDesc->channelId)) + pBssConfig->eBand = eCSR_BAND_5G; + else + pBssConfig->eBand = eCSR_BAND_24; + /* phymode */ + if (csr_is_phy_mode_match(pMac, pProfile->phyMode, pBssDesc, + pProfile, &cfgDot11Mode, pIes)) { + pBssConfig->uCfgDot11Mode = cfgDot11Mode; + } else { + sms_log(pMac, LOGW, "Can not find match phy mode"); + /* force it */ + if (eCSR_BAND_24 == pBssConfig->eBand) + pBssConfig->uCfgDot11Mode = eCSR_CFG_DOT11_MODE_11G; + else + pBssConfig->uCfgDot11Mode = eCSR_CFG_DOT11_MODE_11A; + } + /* Qos */ + if ((pBssConfig->uCfgDot11Mode != eCSR_CFG_DOT11_MODE_11N) && + (pMac->roam.configParam.WMMSupportMode == eCsrRoamWmmNoQos)) { + /* + * Joining BSS is not 11n capable and WMM is disabled on client. + * Disable QoS and WMM + */ + pBssConfig->qosType = eCSR_MEDIUM_ACCESS_DCF; + } + + if (((pBssConfig->uCfgDot11Mode == eCSR_CFG_DOT11_MODE_11N) + || (pBssConfig->uCfgDot11Mode == eCSR_CFG_DOT11_MODE_11AC)) + && ((pBssConfig->qosType != eCSR_MEDIUM_ACCESS_WMM_eDCF_DSCP) + || (pBssConfig->qosType != eCSR_MEDIUM_ACCESS_11e_HCF) + || (pBssConfig->qosType != eCSR_MEDIUM_ACCESS_11e_eDCF))) { + /* Joining BSS is 11n capable and WMM is disabled on AP. */ + /* Assume all HT AP's are QOS AP's and enable WMM */ + pBssConfig->qosType = eCSR_MEDIUM_ACCESS_WMM_eDCF_DSCP; + } + /* auth type */ + switch (pProfile->negotiatedAuthType) { + default: + case eCSR_AUTH_TYPE_WPA: + case eCSR_AUTH_TYPE_WPA_PSK: + case eCSR_AUTH_TYPE_WPA_NONE: + case eCSR_AUTH_TYPE_OPEN_SYSTEM: + pBssConfig->authType = eSIR_OPEN_SYSTEM; + break; + case eCSR_AUTH_TYPE_SHARED_KEY: + pBssConfig->authType = eSIR_SHARED_KEY; + break; + case eCSR_AUTH_TYPE_AUTOSWITCH: + pBssConfig->authType = eSIR_AUTO_SWITCH; + break; + } + /* short slot time */ + if (eCSR_CFG_DOT11_MODE_11B != cfgDot11Mode) + pBssConfig->uShortSlotTime = + pMac->roam.configParam.shortSlotTime; + else + pBssConfig->uShortSlotTime = 0; + + if (pBssConfig->BssCap.ibss) + /* We don't support 11h on IBSS */ + pBssConfig->f11hSupport = false; + else + pBssConfig->f11hSupport = + pMac->roam.configParam.Is11hSupportEnabled; + /* power constraint */ + pBssConfig->uPowerLimit = + csr_get11h_power_constraint(pMac, &pIes->PowerConstraints); + /* heartbeat */ + if (CSR_IS_11A_BSS(pBssDesc)) + pBssConfig->uHeartBeatThresh = + pMac->roam.configParam.HeartbeatThresh50; + else + pBssConfig->uHeartBeatThresh = + pMac->roam.configParam.HeartbeatThresh24; + + /* + * Join timeout: if we find a BeaconInterval in the BssDescription, + * then set the Join Timeout to be 10 x the BeaconInterval. + */ + if (pBssDesc->beaconInterval) + /* Make sure it is bigger than the minimal */ + pBssConfig->uJoinTimeOut = + QDF_MAX(10 * pBssDesc->beaconInterval, + CSR_JOIN_FAILURE_TIMEOUT_MIN); + else + pBssConfig->uJoinTimeOut = + CSR_JOIN_FAILURE_TIMEOUT_DEFAULT; + /* validate CB */ + if ((pBssConfig->uCfgDot11Mode == eCSR_CFG_DOT11_MODE_11N) + || (pBssConfig->uCfgDot11Mode == eCSR_CFG_DOT11_MODE_11AC) + || (pBssConfig->uCfgDot11Mode == eCSR_CFG_DOT11_MODE_11AC_ONLY) + || (pBssConfig->uCfgDot11Mode == eCSR_CFG_DOT11_MODE_11N_ONLY)) + pBssConfig->cbMode = csr_get_cb_mode_from_ies(pMac, + pBssDesc->channelId, pIes); + else + pBssConfig->cbMode = PHY_SINGLE_CHANNEL_CENTERED; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS csr_roam_prepare_bss_config_from_profile(tpAniSirGlobal pMac, + tCsrRoamProfile *pProfile, + tBssConfigParam * + pBssConfig, + tSirBssDescription * + pBssDesc) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + uint8_t operationChannel = 0; + uint8_t qAPisEnabled = false; + /* SSID */ + pBssConfig->SSID.length = 0; + if (pProfile->SSIDs.numOfSSIDs) { + /* only use the first one */ + qdf_mem_copy(&pBssConfig->SSID, + &pProfile->SSIDs.SSIDList[0].SSID, + sizeof(tSirMacSSid)); + } else { + /* SSID must present */ + return QDF_STATUS_E_FAILURE; + } + /* Settomg up the capabilities */ + if (csr_is_bss_type_ibss(pProfile->BSSType)) { + pBssConfig->BssCap.ibss = 1; + } else { + pBssConfig->BssCap.ess = 1; + } + if (eCSR_ENCRYPT_TYPE_NONE != + pProfile->EncryptionType.encryptionType[0]) { + pBssConfig->BssCap.privacy = 1; + } + pBssConfig->eBand = pMac->roam.configParam.eBand; + /* phymode */ + if (pProfile->ChannelInfo.ChannelList) { + operationChannel = pProfile->ChannelInfo.ChannelList[0]; + } + pBssConfig->uCfgDot11Mode = + csr_roam_get_phy_mode_band_for_bss(pMac, pProfile, operationChannel, + &pBssConfig->eBand); + /* QOS */ + /* Is this correct to always set to this // *** */ + if (pBssConfig->BssCap.ess == 1) { + /*For Softap case enable WMM */ + if (CSR_IS_INFRA_AP(pProfile) + && (eCsrRoamWmmNoQos != + pMac->roam.configParam.WMMSupportMode)) { + qAPisEnabled = true; + } else + if (csr_roam_get_qos_info_from_bss(pMac, pBssDesc) == + QDF_STATUS_SUCCESS) { + qAPisEnabled = true; + } else { + qAPisEnabled = false; + } + } else { + qAPisEnabled = true; + } + if ((eCsrRoamWmmNoQos != pMac->roam.configParam.WMMSupportMode && + qAPisEnabled) || + ((eCSR_CFG_DOT11_MODE_11N == pBssConfig->uCfgDot11Mode && + qAPisEnabled))) { + pBssConfig->qosType = eCSR_MEDIUM_ACCESS_WMM_eDCF_DSCP; + } else { + pBssConfig->qosType = eCSR_MEDIUM_ACCESS_DCF; + } + + /* auth type */ + /* Take the preferred Auth type. */ + switch (pProfile->AuthType.authType[0]) { + default: + case eCSR_AUTH_TYPE_WPA: + case eCSR_AUTH_TYPE_WPA_PSK: + case eCSR_AUTH_TYPE_WPA_NONE: + case eCSR_AUTH_TYPE_OPEN_SYSTEM: + pBssConfig->authType = eSIR_OPEN_SYSTEM; + break; + case eCSR_AUTH_TYPE_SHARED_KEY: + pBssConfig->authType = eSIR_SHARED_KEY; + break; + case eCSR_AUTH_TYPE_AUTOSWITCH: + pBssConfig->authType = eSIR_AUTO_SWITCH; + break; + } + /* short slot time */ + if (WNI_CFG_PHY_MODE_11B != pBssConfig->uCfgDot11Mode) { + pBssConfig->uShortSlotTime = + pMac->roam.configParam.shortSlotTime; + } else { + pBssConfig->uShortSlotTime = 0; + } + /* power constraint. We don't support 11h on IBSS */ + pBssConfig->f11hSupport = false; + pBssConfig->uPowerLimit = 0; + /* heartbeat */ + if (eCSR_BAND_5G == pBssConfig->eBand) { + pBssConfig->uHeartBeatThresh = + pMac->roam.configParam.HeartbeatThresh50; + } else { + pBssConfig->uHeartBeatThresh = + pMac->roam.configParam.HeartbeatThresh24; + } + /* Join timeout */ + pBssConfig->uJoinTimeOut = CSR_JOIN_FAILURE_TIMEOUT_DEFAULT; + + return status; +} + +static QDF_STATUS csr_roam_get_qos_info_from_bss(tpAniSirGlobal pMac, + tSirBssDescription *pBssDesc) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tDot11fBeaconIEs *pIes = NULL; + + do { + if (!QDF_IS_STATUS_SUCCESS( + csr_get_parsed_bss_description_ies( + pMac, pBssDesc, &pIes))) { + /* err msg */ + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "csr_roam_get_qos_info_from_bss() failed"); + break; + } + /* check if the AP is QAP & it supports APSD */ + if (CSR_IS_QOS_BSS(pIes)) { + status = QDF_STATUS_SUCCESS; + } + } while (0); + + if (NULL != pIes) { + qdf_mem_free(pIes); + } + + return status; +} + +void csr_set_cfg_privacy(tpAniSirGlobal pMac, tCsrRoamProfile *pProfile, + bool fPrivacy) +{ + /* + * the only difference between this function and + * the csr_set_cfg_privacyFromProfile() is the setting of the privacy + * CFG based on the advertised privacy setting from the AP for WPA + * associations. See note below in this function... + */ + uint32_t PrivacyEnabled = 0, RsnEnabled = 0, WepDefaultKeyId = 0; + uint32_t WepKeyLength = WNI_CFG_WEP_KEY_LENGTH_5; + uint32_t Key0Length = 0, Key1Length = 0, Key2Length = 0, Key3Length = 0; + + /* Reserve for the biggest key */ + uint8_t Key0[WNI_CFG_WEP_DEFAULT_KEY_1_LEN]; + uint8_t Key1[WNI_CFG_WEP_DEFAULT_KEY_2_LEN]; + uint8_t Key2[WNI_CFG_WEP_DEFAULT_KEY_3_LEN]; + uint8_t Key3[WNI_CFG_WEP_DEFAULT_KEY_4_LEN]; + + switch (pProfile->negotiatedUCEncryptionType) { + case eCSR_ENCRYPT_TYPE_NONE: + /* for NO encryption, turn off Privacy and Rsn. */ + PrivacyEnabled = 0; + RsnEnabled = 0; + /* clear out the WEP keys that may be hanging around. */ + Key0Length = 0; + Key1Length = 0; + Key2Length = 0; + Key3Length = 0; + break; + + case eCSR_ENCRYPT_TYPE_WEP40_STATICKEY: + case eCSR_ENCRYPT_TYPE_WEP40: + + /* Privacy is ON. NO RSN for Wep40 static key. */ + PrivacyEnabled = 1; + RsnEnabled = 0; + /* Set the Wep default key ID. */ + WepDefaultKeyId = pProfile->Keys.defaultIndex; + /* Wep key size if 5 bytes (40 bits). */ + WepKeyLength = WNI_CFG_WEP_KEY_LENGTH_5; + /* + * set encryption keys in the CFG database or + * clear those that are not present in this profile. + */ + if (pProfile->Keys.KeyLength[0]) { + qdf_mem_copy(Key0, + pProfile->Keys.KeyMaterial[0], + WNI_CFG_WEP_KEY_LENGTH_5); + Key0Length = WNI_CFG_WEP_KEY_LENGTH_5; + } else { + Key0Length = 0; + } + + if (pProfile->Keys.KeyLength[1]) { + qdf_mem_copy(Key1, + pProfile->Keys.KeyMaterial[1], + WNI_CFG_WEP_KEY_LENGTH_5); + Key1Length = WNI_CFG_WEP_KEY_LENGTH_5; + } else { + Key1Length = 0; + } + + if (pProfile->Keys.KeyLength[2]) { + qdf_mem_copy(Key2, + pProfile->Keys.KeyMaterial[2], + WNI_CFG_WEP_KEY_LENGTH_5); + Key2Length = WNI_CFG_WEP_KEY_LENGTH_5; + } else { + Key2Length = 0; + } + + if (pProfile->Keys.KeyLength[3]) { + qdf_mem_copy(Key3, + pProfile->Keys.KeyMaterial[3], + WNI_CFG_WEP_KEY_LENGTH_5); + Key3Length = WNI_CFG_WEP_KEY_LENGTH_5; + } else { + Key3Length = 0; + } + break; + + case eCSR_ENCRYPT_TYPE_WEP104_STATICKEY: + case eCSR_ENCRYPT_TYPE_WEP104: + + /* Privacy is ON. NO RSN for Wep40 static key. */ + PrivacyEnabled = 1; + RsnEnabled = 0; + /* Set the Wep default key ID. */ + WepDefaultKeyId = pProfile->Keys.defaultIndex; + /* Wep key size if 13 bytes (104 bits). */ + WepKeyLength = WNI_CFG_WEP_KEY_LENGTH_13; + /* + * set encryption keys in the CFG database or clear + * those that are not present in this profile. + */ + if (pProfile->Keys.KeyLength[0]) { + qdf_mem_copy(Key0, + pProfile->Keys.KeyMaterial[0], + WNI_CFG_WEP_KEY_LENGTH_13); + Key0Length = WNI_CFG_WEP_KEY_LENGTH_13; + } else { + Key0Length = 0; + } + + if (pProfile->Keys.KeyLength[1]) { + qdf_mem_copy(Key1, + pProfile->Keys.KeyMaterial[1], + WNI_CFG_WEP_KEY_LENGTH_13); + Key1Length = WNI_CFG_WEP_KEY_LENGTH_13; + } else { + Key1Length = 0; + } + + if (pProfile->Keys.KeyLength[2]) { + qdf_mem_copy(Key2, + pProfile->Keys.KeyMaterial[2], + WNI_CFG_WEP_KEY_LENGTH_13); + Key2Length = WNI_CFG_WEP_KEY_LENGTH_13; + } else { + Key2Length = 0; + } + + if (pProfile->Keys.KeyLength[3]) { + qdf_mem_copy(Key3, + pProfile->Keys.KeyMaterial[3], + WNI_CFG_WEP_KEY_LENGTH_13); + Key3Length = WNI_CFG_WEP_KEY_LENGTH_13; + } else { + Key3Length = 0; + } + break; + + case eCSR_ENCRYPT_TYPE_TKIP: + case eCSR_ENCRYPT_TYPE_AES: +#ifdef FEATURE_WLAN_WAPI + case eCSR_ENCRYPT_TYPE_WPI: +#endif /* FEATURE_WLAN_WAPI */ + /* + * this is the only difference between this function and + * the csr_set_cfg_privacyFromProfile(). + * (setting of the privacy CFG based on the advertised + * privacy setting from AP for WPA/WAPI associations). + */ + PrivacyEnabled = (0 != fPrivacy); + /* turn on RSN enabled for WPA associations */ + RsnEnabled = 1; + /* clear static WEP keys that may be hanging around. */ + Key0Length = 0; + Key1Length = 0; + Key2Length = 0; + Key3Length = 0; + break; + default: + PrivacyEnabled = 0; + RsnEnabled = 0; + break; + } + + cfg_set_int(pMac, WNI_CFG_PRIVACY_ENABLED, PrivacyEnabled); + cfg_set_int(pMac, WNI_CFG_RSN_ENABLED, RsnEnabled); + cfg_set_str(pMac, WNI_CFG_WEP_DEFAULT_KEY_1, Key0, Key0Length); + cfg_set_str(pMac, WNI_CFG_WEP_DEFAULT_KEY_2, Key1, Key1Length); + cfg_set_str(pMac, WNI_CFG_WEP_DEFAULT_KEY_3, Key2, Key2Length); + cfg_set_str(pMac, WNI_CFG_WEP_DEFAULT_KEY_4, Key3, Key3Length); + cfg_set_int(pMac, WNI_CFG_WEP_KEY_LENGTH, WepKeyLength); + cfg_set_int(pMac, WNI_CFG_WEP_DEFAULT_KEYID, WepDefaultKeyId); +} + +static void csr_set_cfg_ssid(tpAniSirGlobal pMac, tSirMacSSid *pSSID) +{ + uint32_t len = 0; + if (pSSID->length <= WNI_CFG_SSID_LEN) { + len = pSSID->length; + } + cfg_set_str(pMac, WNI_CFG_SSID, (uint8_t *) pSSID->ssId, len); +} + +static QDF_STATUS csr_set_qos_to_cfg(tpAniSirGlobal pMac, uint32_t sessionId, + eCsrMediaAccessType qosType) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + uint32_t QoSEnabled; + uint32_t WmeEnabled; + /* set the CFG enable/disable variables based on the qosType being configured... */ + switch (qosType) { + case eCSR_MEDIUM_ACCESS_WMM_eDCF_802dot1p: + QoSEnabled = false; + WmeEnabled = true; + break; + case eCSR_MEDIUM_ACCESS_WMM_eDCF_DSCP: + QoSEnabled = false; + WmeEnabled = true; + break; + case eCSR_MEDIUM_ACCESS_WMM_eDCF_NoClassify: + QoSEnabled = false; + WmeEnabled = true; + break; + case eCSR_MEDIUM_ACCESS_11e_eDCF: + QoSEnabled = true; + WmeEnabled = false; + break; + case eCSR_MEDIUM_ACCESS_11e_HCF: + QoSEnabled = true; + WmeEnabled = false; + break; + default: + case eCSR_MEDIUM_ACCESS_DCF: + QoSEnabled = false; + WmeEnabled = false; + break; + } + /* save the WMM setting for later use */ + pMac->roam.roamSession[sessionId].fWMMConnection = (bool) WmeEnabled; + pMac->roam.roamSession[sessionId].fQOSConnection = (bool) QoSEnabled; + return status; +} + +static QDF_STATUS csr_get_rate_set(tpAniSirGlobal pMac, + tCsrRoamProfile *pProfile, eCsrPhyMode phyMode, + tSirBssDescription *pBssDesc, + tDot11fBeaconIEs *pIes, + tSirMacRateSet *pOpRateSet, + tSirMacRateSet *pExRateSet) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + int i; + eCsrCfgDot11Mode cfgDot11Mode; + uint8_t *pDstRate; + uint16_t rateBitmap = 0; + qdf_mem_set(pOpRateSet, sizeof(tSirMacRateSet), 0); + qdf_mem_set(pExRateSet, sizeof(tSirMacRateSet), 0); + QDF_ASSERT(pIes != NULL); + + if (NULL == pIes) { + sms_log(pMac, LOGE, FL("failed to parse BssDesc")); + return status; + } + + csr_is_phy_mode_match(pMac, phyMode, pBssDesc, pProfile, + &cfgDot11Mode, pIes); + /* + * Originally, we thought that for 11a networks, the 11a rates + * are always in the Operational Rate set & for 11b and 11g + * networks, the 11b rates appear in the Operational Rate set. + * Consequently, in either case, we would blindly put the rates + * we support into our Operational Rate set. + * (including the basic rates, which we've already verified are + * supported earlier in the roaming decision). + * However, it turns out that this is not always the case. + * Some AP's (e.g. D-Link DI-784) ram 11g rates into the + * Operational Rate set too. Now, we're a little more careful. + */ + pDstRate = pOpRateSet->rate; + if (pIes->SuppRates.present) { + for (i = 0; i < pIes->SuppRates.num_rates; i++) { + if (csr_rates_is_dot11_rate_supported(pMac, + pIes->SuppRates.rates[i]) && + !csr_check_rate_bitmap( + pIes->SuppRates.rates[i], + rateBitmap)) { + csr_add_rate_bitmap(pIes->SuppRates. + rates[i], &rateBitmap); + *pDstRate++ = pIes->SuppRates.rates[i]; + pOpRateSet->numRates++; + } + } + } + /* + * If there are Extended Rates in the beacon, we will reflect the + * extended rates that we support in our Extended Operational Rate + * set. + */ + if (pIes->ExtSuppRates.present) { + pDstRate = pExRateSet->rate; + for (i = 0; i < pIes->ExtSuppRates.num_rates; i++) { + if (csr_rates_is_dot11_rate_supported(pMac, + pIes->ExtSuppRates.rates[i]) && + !csr_check_rate_bitmap( + pIes->ExtSuppRates.rates[i], + rateBitmap)) { + *pDstRate++ = pIes->ExtSuppRates.rates[i]; + pExRateSet->numRates++; + } + } + } + if (pOpRateSet->numRates > 0 || pExRateSet->numRates > 0) + status = QDF_STATUS_SUCCESS; + return status; +} + +static void csr_set_cfg_rate_set(tpAniSirGlobal pMac, eCsrPhyMode phyMode, + tCsrRoamProfile *pProfile, + tSirBssDescription *pBssDesc, + tDot11fBeaconIEs *pIes) +{ + int i; + uint8_t *pDstRate; + eCsrCfgDot11Mode cfgDot11Mode; + uint8_t OperationalRates[CSR_DOT11_SUPPORTED_RATES_MAX]; /* leave enough room for the max number of rates */ + uint32_t OperationalRatesLength = 0; + uint8_t ExtendedOperationalRates[CSR_DOT11_EXTENDED_SUPPORTED_RATES_MAX]; /* leave enough room for the max number of rates */ + uint32_t ExtendedOperationalRatesLength = 0; + uint8_t MCSRateIdxSet[SIZE_OF_SUPPORTED_MCS_SET]; + uint32_t MCSRateLength = 0; + QDF_ASSERT(pIes != NULL); + if (NULL != pIes) { + csr_is_phy_mode_match(pMac, phyMode, pBssDesc, pProfile, + &cfgDot11Mode, pIes); + /* Originally, we thought that for 11a networks, the 11a rates are always */ + /* in the Operational Rate set & for 11b and 11g networks, the 11b rates */ + /* appear in the Operational Rate set. Consequently, in either case, we */ + /* would blindly put the rates we support into our Operational Rate set */ + /* (including the basic rates, which we have already verified are */ + /* supported earlier in the roaming decision). */ + /* However, it turns out that this is not always the case. Some AP's */ + /* (e.g. D-Link DI-784) ram 11g rates into the Operational Rate set, */ + /* too. Now, we're a little more careful: */ + pDstRate = OperationalRates; + if (pIes->SuppRates.present) { + for (i = 0; i < pIes->SuppRates.num_rates; i++) { + if (csr_rates_is_dot11_rate_supported + (pMac, pIes->SuppRates.rates[i]) + && (OperationalRatesLength < + CSR_DOT11_SUPPORTED_RATES_MAX)) { + *pDstRate++ = pIes->SuppRates.rates[i]; + OperationalRatesLength++; + } + } + } + if (eCSR_CFG_DOT11_MODE_11G == cfgDot11Mode || + eCSR_CFG_DOT11_MODE_11N == cfgDot11Mode || + eCSR_CFG_DOT11_MODE_ABG == cfgDot11Mode) { + /* If there are Extended Rates in the beacon, we will reflect those */ + /* extended rates that we support in out Extended Operational Rate */ + /* set: */ + pDstRate = ExtendedOperationalRates; + if (pIes->ExtSuppRates.present) { + for (i = 0; i < pIes->ExtSuppRates.num_rates; + i++) { + if (csr_rates_is_dot11_rate_supported + (pMac, pIes->ExtSuppRates.rates[i]) + && (ExtendedOperationalRatesLength < + CSR_DOT11_EXTENDED_SUPPORTED_RATES_MAX)) { + *pDstRate++ = + pIes->ExtSuppRates.rates[i]; + ExtendedOperationalRatesLength++; + } + } + } + } + /* Enable proprietary MAC features if peer node is Airgo node and STA */ + /* user wants to use them */ + /* For ANI network companions, we need to populate the proprietary rate */ + /* set with any proprietary rates we found in the beacon, only if user */ + /* allows them... */ + /* No proprietary modes... */ + /* Get MCS Rate */ + pDstRate = MCSRateIdxSet; + if (pIes->HTCaps.present) { + for (i = 0; i < VALID_MAX_MCS_INDEX; i++) { + if ((unsigned int)pIes->HTCaps. + supportedMCSSet[0] & (1 << i)) { + MCSRateLength++; + *pDstRate++ = i; + } + } + } + /* Set the operational rate set CFG variables... */ + cfg_set_str(pMac, WNI_CFG_OPERATIONAL_RATE_SET, + OperationalRates, OperationalRatesLength); + cfg_set_str(pMac, WNI_CFG_EXTENDED_OPERATIONAL_RATE_SET, + ExtendedOperationalRates, + ExtendedOperationalRatesLength); + cfg_set_str(pMac, WNI_CFG_CURRENT_MCS_SET, MCSRateIdxSet, + MCSRateLength); + } /* Parsing BSSDesc */ + else { + sms_log(pMac, LOGE, FL("failed to parse BssDesc")); + } +} + +static void csr_set_cfg_rate_set_from_profile(tpAniSirGlobal pMac, + tCsrRoamProfile *pProfile) +{ + tSirMacRateSetIE DefaultSupportedRates11a = { SIR_MAC_RATESET_EID, + {8, + {SIR_MAC_RATE_6, + SIR_MAC_RATE_9, + SIR_MAC_RATE_12, + SIR_MAC_RATE_18, + SIR_MAC_RATE_24, + SIR_MAC_RATE_36, + SIR_MAC_RATE_48, + SIR_MAC_RATE_54} } }; + tSirMacRateSetIE DefaultSupportedRates11b = { SIR_MAC_RATESET_EID, + {4, + {SIR_MAC_RATE_1, + SIR_MAC_RATE_2, + SIR_MAC_RATE_5_5, + SIR_MAC_RATE_11} } }; + + tSirMacPropRateSet DefaultSupportedPropRates = { 3, + {SIR_MAC_RATE_72, + SIR_MAC_RATE_96, + SIR_MAC_RATE_108} }; + eCsrCfgDot11Mode cfgDot11Mode; + eCsrBand eBand; + /* leave enough room for the max number of rates */ + uint8_t OperationalRates[CSR_DOT11_SUPPORTED_RATES_MAX]; + uint32_t OperationalRatesLength = 0; + /* leave enough room for the max number of rates */ + uint8_t ExtendedOperationalRates[CSR_DOT11_EXTENDED_SUPPORTED_RATES_MAX]; + uint32_t ExtendedOperationalRatesLength = 0; + /* leave enough room for the max number of proprietary rates */ + uint8_t ProprietaryOperationalRates[4]; + uint32_t ProprietaryOperationalRatesLength = 0; + uint32_t PropRatesEnable = 0; + uint8_t operationChannel = 0; + if (pProfile->ChannelInfo.ChannelList) { + operationChannel = pProfile->ChannelInfo.ChannelList[0]; + } + cfgDot11Mode = + csr_roam_get_phy_mode_band_for_bss(pMac, pProfile, operationChannel, + &eBand); + /* For 11a networks, the 11a rates go into the Operational Rate set. For 11b and 11g */ + /* networks, the 11b rates appear in the Operational Rate set. In either case, */ + /* we can blindly put the rates we support into our Operational Rate set */ + /* (including the basic rates, which we have already verified are supported */ + /* earlier in the roaming decision). */ + if (eCSR_BAND_5G == eBand) { + /* 11a rates into the Operational Rate Set. */ + OperationalRatesLength = + DefaultSupportedRates11a.supportedRateSet.numRates * + sizeof(*DefaultSupportedRates11a.supportedRateSet.rate); + qdf_mem_copy(OperationalRates, + DefaultSupportedRates11a.supportedRateSet.rate, + OperationalRatesLength); + + /* Nothing in the Extended rate set. */ + ExtendedOperationalRatesLength = 0; + /* populate proprietary rates if user allows them */ + if (pMac->roam.configParam.ProprietaryRatesEnabled) { + ProprietaryOperationalRatesLength = + DefaultSupportedPropRates.numPropRates * + sizeof(*DefaultSupportedPropRates.propRate); + qdf_mem_copy(ProprietaryOperationalRates, + DefaultSupportedPropRates.propRate, + ProprietaryOperationalRatesLength); + } else { + /* No proprietary modes */ + ProprietaryOperationalRatesLength = 0; + } + } else if (eCSR_CFG_DOT11_MODE_11B == cfgDot11Mode) { + /* 11b rates into the Operational Rate Set. */ + OperationalRatesLength = + DefaultSupportedRates11b.supportedRateSet.numRates * + sizeof(*DefaultSupportedRates11b.supportedRateSet.rate); + qdf_mem_copy(OperationalRates, + DefaultSupportedRates11b.supportedRateSet.rate, + OperationalRatesLength); + /* Nothing in the Extended rate set. */ + ExtendedOperationalRatesLength = 0; + /* No proprietary modes */ + ProprietaryOperationalRatesLength = 0; + } else { + /* 11G */ + + /* 11b rates into the Operational Rate Set. */ + OperationalRatesLength = + DefaultSupportedRates11b.supportedRateSet.numRates * + sizeof(*DefaultSupportedRates11b.supportedRateSet.rate); + qdf_mem_copy(OperationalRates, + DefaultSupportedRates11b.supportedRateSet.rate, + OperationalRatesLength); + + /* 11a rates go in the Extended rate set. */ + ExtendedOperationalRatesLength = + DefaultSupportedRates11a.supportedRateSet.numRates * + sizeof(*DefaultSupportedRates11a.supportedRateSet.rate); + qdf_mem_copy(ExtendedOperationalRates, + DefaultSupportedRates11a.supportedRateSet.rate, + ExtendedOperationalRatesLength); + + /* populate proprietary rates if user allows them */ + if (pMac->roam.configParam.ProprietaryRatesEnabled) { + ProprietaryOperationalRatesLength = + DefaultSupportedPropRates.numPropRates * + sizeof(*DefaultSupportedPropRates.propRate); + qdf_mem_copy(ProprietaryOperationalRates, + DefaultSupportedPropRates.propRate, + ProprietaryOperationalRatesLength); + } else { + /* No proprietary modes */ + ProprietaryOperationalRatesLength = 0; + } + } + /* set this to 1 if prop. rates need to be advertised in to the IBSS beacon and user wants to use them */ + if (ProprietaryOperationalRatesLength + && pMac->roam.configParam.ProprietaryRatesEnabled) { + PropRatesEnable = 1; + } else { + PropRatesEnable = 0; + } + + /* Set the operational rate set CFG variables... */ + cfg_set_str(pMac, WNI_CFG_OPERATIONAL_RATE_SET, OperationalRates, + OperationalRatesLength); + cfg_set_str(pMac, WNI_CFG_EXTENDED_OPERATIONAL_RATE_SET, + ExtendedOperationalRates, ExtendedOperationalRatesLength); + cfg_set_str(pMac, WNI_CFG_PROPRIETARY_OPERATIONAL_RATE_SET, + ProprietaryOperationalRates, + ProprietaryOperationalRatesLength); +} + +void csr_roam_ccm_cfg_set_callback(tpAniSirGlobal pMac, int32_t result) +{ + tListElem *pEntry = + csr_ll_peek_head(&pMac->sme.smeCmdActiveList, LL_ACCESS_LOCK); + uint32_t sessionId; + tSmeCmd *pCommand = NULL; +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + tCsrRoamSession *pSession = NULL; +#endif + if (NULL == pEntry) { + sms_log(pMac, LOGW, "CFG_CNF with active list empty"); + return; + } + pCommand = GET_BASE_ADDR(pEntry, tSmeCmd, Link); + sessionId = pCommand->sessionId; +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + pSession = &pMac->roam.roamSession[sessionId]; + if (pSession->roam_synch_in_progress) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "LFR3:csr_roam_cfg_set_callback"); + } +#endif + + if (CSR_IS_ROAM_JOINING(pMac, sessionId) + && CSR_IS_ROAM_SUBSTATE_CONFIG(pMac, sessionId)) { + csr_roaming_state_config_cnf_processor(pMac, (uint32_t) result); + } +} + +/* pIes may be NULL */ +QDF_STATUS csr_roam_set_bss_config_cfg(tpAniSirGlobal pMac, uint32_t sessionId, + tCsrRoamProfile *pProfile, + tSirBssDescription *pBssDesc, + tBssConfigParam *pBssConfig, + tDot11fBeaconIEs *pIes, bool resetCountry) +{ + tSirRetStatus status; + uint32_t cfgCb = WNI_CFG_CHANNEL_BONDING_MODE_DISABLE; + uint8_t channel = 0; + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + + /* Make sure we have the domain info for the BSS we try to connect to. */ + /* Do we need to worry about sequence for OSs that are not Windows?? */ + if (pBssDesc) { + if ((QDF_SAP_MODE != + csr_get_session_persona(pMac, sessionId)) && + csr_learn_11dcountry_information( + pMac, pBssDesc, pIes, true)) { + csr_apply_country_information(pMac); + } + if ((csr_is11d_supported(pMac)) && pIes) { + if (!pIes->Country.present) { + csr_apply_channel_power_info_wrapper(pMac); + } else { + /* Let's also update the below to make sure we don't update CC while */ + /* connected to an AP which is advertising some CC */ + qdf_mem_copy(pMac->scan.currentCountryBssid.bytes, + pBssDesc->bssId, + sizeof(tSirMacAddr)); + } + } + } + /* Qos */ + csr_set_qos_to_cfg(pMac, sessionId, pBssConfig->qosType); + /* SSID */ + csr_set_cfg_ssid(pMac, &pBssConfig->SSID); + + /* Auth type */ + cfg_set_int(pMac, WNI_CFG_AUTHENTICATION_TYPE, pBssConfig->authType); + /* encryption type */ + csr_set_cfg_privacy(pMac, pProfile, (bool) pBssConfig->BssCap.privacy); + /* short slot time */ + cfg_set_int(pMac, WNI_CFG_11G_SHORT_SLOT_TIME_ENABLED, + pBssConfig->uShortSlotTime); + /* 11d */ + cfg_set_int(pMac, WNI_CFG_11D_ENABLED, + ((pBssConfig->f11hSupport) ? pBssConfig->f11hSupport : + pProfile->ieee80211d)); + cfg_set_int(pMac, WNI_CFG_LOCAL_POWER_CONSTRAINT, + pBssConfig->uPowerLimit); + /* CB */ + + if (CSR_IS_INFRA_AP(pProfile) || CSR_IS_IBSS(pProfile)) { + channel = pProfile->operationChannel; + } else { + if (pBssDesc) { + channel = pBssDesc->channelId; + } + } + if (0 != channel) { + if (CDS_IS_CHANNEL_24GHZ(channel)) { /* for now if we are on 2.4 Ghz, CB will be always disabled */ + cfgCb = WNI_CFG_CHANNEL_BONDING_MODE_DISABLE; + } else { + cfgCb = pBssConfig->cbMode; + } + } + /* Rate */ + /* Fixed Rate */ + if (pBssDesc) { + csr_set_cfg_rate_set(pMac, (eCsrPhyMode) pProfile->phyMode, + pProfile, pBssDesc, pIes); + } else { + csr_set_cfg_rate_set_from_profile(pMac, pProfile); + } + status = cfg_set_int(pMac, WNI_CFG_JOIN_FAILURE_TIMEOUT, + pBssConfig->uJoinTimeOut); + /* Any roaming related changes should be above this line */ + if (pSession && pSession->roam_synch_in_progress) { + sms_log(pMac, LOG4, FL("Roam synch is in progress %d"), + sessionId); + return QDF_STATUS_SUCCESS; + } + /* Make this the last CFG to set. The callback will trigger a join_req */ + /* Join time out */ + csr_roam_substate_change(pMac, eCSR_ROAM_SUBSTATE_CONFIG, sessionId); + + csr_roam_ccm_cfg_set_callback(pMac, status); + return QDF_STATUS_SUCCESS; +} + +static +QDF_STATUS csr_roam_stop_network(tpAniSirGlobal pMac, uint32_t sessionId, + tCsrRoamProfile *pProfile, + tSirBssDescription *pBssDesc, + tDot11fBeaconIEs *pIes) +{ + QDF_STATUS status; + tBssConfigParam *pBssConfig; + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!pSession) { + sms_log(pMac, LOGE, FL(" session %d not found "), sessionId); + return QDF_STATUS_E_FAILURE; + } + + pBssConfig = qdf_mem_malloc(sizeof(tBssConfigParam)); + if (NULL == pBssConfig) + return QDF_STATUS_E_NOMEM; + + sms_log(pMac, LOG1, FL("session id %d "), sessionId); + + status = csr_roam_prepare_bss_config(pMac, pProfile, pBssDesc, + pBssConfig, pIes); + if (QDF_IS_STATUS_SUCCESS(status)) { + eCsrRoamSubState substate; + substate = eCSR_ROAM_SUBSTATE_DISCONNECT_CONTINUE_ROAMING; + pSession->bssParams.uCfgDot11Mode = pBssConfig->uCfgDot11Mode; + /* This will allow to pass cbMode during join req */ + pSession->bssParams.cbMode = pBssConfig->cbMode; + /* For IBSS, we need to prepare some more information */ + if (csr_is_bss_type_ibss(pProfile->BSSType) || + CSR_IS_INFRA_AP(pProfile)) + csr_roam_prepare_bss_params(pMac, sessionId, pProfile, + pBssDesc, pBssConfig, pIes); + + /* + * If we are in an IBSS, then stop the IBSS... + * Not worry about WDS connection for now + */ + if (csr_is_conn_state_ibss(pMac, sessionId)) { + status = csr_roam_issue_stop_bss(pMac, sessionId, + substate); + } else if (csr_is_conn_state_infra(pMac, sessionId)) { + /* + * the new Bss is an Ibss OR we are roaming from + * Infra to Infra across SSIDs + * (roaming to a new SSID)... + * Not worry about WDS connection for now + */ + if (pBssDesc && (csr_is_ibss_bss_desc(pBssDesc) || + !csr_is_ssid_equal(pMac, + pSession->pConnectBssDesc, + pBssDesc, pIes))) + status = csr_roam_issue_disassociate(pMac, + sessionId, substate, false); + else if (pBssDesc) + /* + * In an infra & going to an infra network with + * the same SSID. This calls for a reassoc seq. + * So issue the CFG sets for this new AP. Set + * parameters for this Bss. + */ + status = csr_roam_set_bss_config_cfg(pMac, + sessionId, pProfile, pBssDesc, + pBssConfig, pIes, false); + } else if (pBssDesc || + CSR_IS_INFRA_AP(pProfile)) { + /* + * Neither in IBSS nor in Infra. We can go ahead and set + * the cfg for tne new network... nothing to stop. + */ + bool is11rRoamingFlag = false; + is11rRoamingFlag = csr_roam_is11r_assoc(pMac, + sessionId); + /* Set parameters for this Bss. */ + status = csr_roam_set_bss_config_cfg(pMac, sessionId, + pProfile, pBssDesc, pBssConfig, pIes, + is11rRoamingFlag); + } + } /* Success getting BSS config info */ + qdf_mem_free(pBssConfig); + return status; +} + +/** + * csr_roam_state_for_same_profile() - Determine roam state for same profile + * @mac_ctx: pointer to mac context + * @profile: Roam profile + * @session: Roam session + * @session_id: session id + * @ies_local: local ies + * @bss_descr: bss description + * + * This function will determine the roam state for same profile + * + * Return: Roaming state. + */ +static eCsrJoinState csr_roam_state_for_same_profile(tpAniSirGlobal mac_ctx, + tCsrRoamProfile *profile, tCsrRoamSession *session, + uint32_t session_id, tDot11fBeaconIEs *ies_local, + tSirBssDescription *bss_descr) +{ + QDF_STATUS status; + tBssConfigParam bssConfig; + if (csr_roam_is_same_profile_keys(mac_ctx, &session->connectedProfile, + profile)) + return eCsrReassocToSelfNoCapChange; + /* The key changes */ + qdf_mem_set(&bssConfig, sizeof(bssConfig), 0); + status = csr_roam_prepare_bss_config(mac_ctx, profile, bss_descr, + &bssConfig, ies_local); + if (QDF_IS_STATUS_SUCCESS(status)) { + session->bssParams.uCfgDot11Mode = + bssConfig.uCfgDot11Mode; + session->bssParams.cbMode = + bssConfig.cbMode; + /* reapply the cfg including keys so reassoc happens. */ + status = csr_roam_set_bss_config_cfg(mac_ctx, session_id, + profile, bss_descr, &bssConfig, + ies_local, false); + if (QDF_IS_STATUS_SUCCESS(status)) + return eCsrContinueRoaming; + } + + return eCsrStopRoaming; + +} + +static eCsrJoinState csr_roam_join(tpAniSirGlobal pMac, uint32_t sessionId, + tCsrScanResultInfo *pScanResult, + tCsrRoamProfile *pProfile) +{ + eCsrJoinState eRoamState = eCsrContinueRoaming; + tSirBssDescription *pBssDesc = &pScanResult->BssDescriptor; + tDot11fBeaconIEs *pIesLocal = (tDot11fBeaconIEs *) (pScanResult->pvIes); + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!pSession) { + sms_log(pMac, LOGE, FL("session %d not found"), sessionId); + return eCsrStopRoaming; + } + + if (!pIesLocal && + !QDF_IS_STATUS_SUCCESS(csr_get_parsed_bss_description_ies(pMac, + pBssDesc, &pIesLocal))) { + sms_log(pMac, LOGE, FL("fail to parse IEs")); + return eCsrStopRoaming; + } + if (csr_is_infra_bss_desc(pBssDesc)) { + /* + * If we are connected in infra mode and the join bss descr is + * for the same BssID, then we are attempting to join the AP we + * are already connected with. In that case, see if the Bss or + * sta capabilities have changed and handle the changes + * without disturbing the current association + */ + + if (csr_is_conn_state_connected_infra(pMac, sessionId) && + csr_is_bss_id_equal(pMac, + pBssDesc, pSession->pConnectBssDesc) && + csr_is_ssid_equal(pMac, pSession->pConnectBssDesc, + pBssDesc, pIesLocal)) { + /* + * Check to see if the Auth type has changed in the + * profile. If so, we don't want to reassociate with + * authenticating first. To force this, stop the + * current association (Disassociate) and then re 'Join' + * the AP, wihch will force an Authentication (with the + * new Auth type) followed by a new Association. + */ + if (csr_is_same_profile(pMac, + &pSession->connectedProfile, pProfile)) { + sms_log(pMac, LOGW, + FL("detect same profile")); + eRoamState = + csr_roam_state_for_same_profile(pMac, + pProfile, pSession, sessionId, + pIesLocal, pBssDesc); + } else if (!QDF_IS_STATUS_SUCCESS( + csr_roam_issue_disassociate(pMac, + sessionId, + eCSR_ROAM_SUBSTATE_DISASSOC_REQ, + false))) { + sms_log(pMac, LOGE, + FL("fail disassoc session %d"), + sessionId); + eRoamState = eCsrStopRoaming; + } + } else if (!QDF_IS_STATUS_SUCCESS(csr_roam_stop_network(pMac, + sessionId, pProfile, pBssDesc, pIesLocal))) { + /* we used to pre-auth here with open auth + * networks but that wasn't working so well. + * stop the existing network before attempting + * to join the new network... */ + eRoamState = eCsrStopRoaming; + } + } else if (!QDF_IS_STATUS_SUCCESS(csr_roam_stop_network(pMac, sessionId, + pProfile, pBssDesc, + pIesLocal))) { + eRoamState = eCsrStopRoaming; + } + + if (pIesLocal && !pScanResult->pvIes) + qdf_mem_free(pIesLocal); + return eRoamState; +} + +static +QDF_STATUS csr_roam_should_roam(tpAniSirGlobal pMac, uint32_t sessionId, + tSirBssDescription *pBssDesc, uint32_t roamId) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tCsrRoamInfo roamInfo; + qdf_mem_set(&roamInfo, sizeof(tCsrRoamInfo), 0); + roamInfo.pBssDesc = pBssDesc; + status = + csr_roam_call_callback(pMac, sessionId, &roamInfo, roamId, + eCSR_ROAM_SHOULD_ROAM, eCSR_ROAM_RESULT_NONE); + return status; +} + +/* In case no matching BSS is found, use whatever default we can find */ +static void csr_roam_assign_default_param(tpAniSirGlobal pMac, tSmeCmd *pCommand) +{ + /* Need to get all negotiated types in place first */ + /* auth type */ + /* Take the preferred Auth type. */ + switch (pCommand->u.roamCmd.roamProfile.AuthType.authType[0]) { + default: + case eCSR_AUTH_TYPE_WPA: + case eCSR_AUTH_TYPE_WPA_PSK: + case eCSR_AUTH_TYPE_WPA_NONE: + case eCSR_AUTH_TYPE_OPEN_SYSTEM: + pCommand->u.roamCmd.roamProfile.negotiatedAuthType = + eCSR_AUTH_TYPE_OPEN_SYSTEM; + break; + + case eCSR_AUTH_TYPE_SHARED_KEY: + pCommand->u.roamCmd.roamProfile.negotiatedAuthType = + eCSR_AUTH_TYPE_SHARED_KEY; + break; + + case eCSR_AUTH_TYPE_AUTOSWITCH: + pCommand->u.roamCmd.roamProfile.negotiatedAuthType = + eCSR_AUTH_TYPE_AUTOSWITCH; + break; + } + pCommand->u.roamCmd.roamProfile.negotiatedUCEncryptionType = + pCommand->u.roamCmd.roamProfile.EncryptionType.encryptionType[0]; + /* In this case, the multicast encryption needs to follow the uncast ones. */ + pCommand->u.roamCmd.roamProfile.negotiatedMCEncryptionType = + pCommand->u.roamCmd.roamProfile.EncryptionType.encryptionType[0]; +} + +static void csr_set_abort_roaming_command(tpAniSirGlobal pMac, tSmeCmd *pCommand) +{ + switch (pCommand->u.roamCmd.roamReason) { + case eCsrLostLink1: + pCommand->u.roamCmd.roamReason = eCsrLostLink1Abort; + break; + case eCsrLostLink2: + pCommand->u.roamCmd.roamReason = eCsrLostLink2Abort; + break; + case eCsrLostLink3: + pCommand->u.roamCmd.roamReason = eCsrLostLink3Abort; + break; + default: + sms_log(pMac, LOGE, + FL(" aborting roaming reason %d not recognized"), + pCommand->u.roamCmd.roamReason); + break; + } +} + +/** + * csr_roam_select_bss() - Handle join scenario based on profile + * @mac_ctx: Global MAC Context + * @roam_bss_entry: The next BSS to join + * @csr_result_info: Result of join + * @csr_scan_result: Global scan result + * @session_id: SME Session ID + * @roam_id: Roaming ID + * @roam_state: Current roaming state + * @bss_list: BSS List + * + * Return: true if the entire BSS list is done, false otherwise. + */ +static bool csr_roam_select_bss(tpAniSirGlobal mac_ctx, + tListElem *roam_bss_entry, tCsrScanResultInfo **csr_result_info, + tCsrScanResult **csr_scan_result, uint32_t session_id, + uint32_t roam_id, eCsrJoinState *roam_state, + tScanResultList *bss_list) +{ + uint8_t conc_channel = 0; + bool status = false; + tCsrScanResult *scan_result = NULL; + tCsrScanResultInfo *result = NULL; + + while (roam_bss_entry) { + scan_result = GET_BASE_ADDR(roam_bss_entry, tCsrScanResult, + Link); + /* + * If concurrency enabled take the + * concurrent connected channel first. + * Valid multichannel concurrent + * sessions exempted + */ + result = &scan_result->Result; + if (cds_concurrent_open_sessions_running() && + !csr_is_valid_mc_concurrent_session(mac_ctx, + session_id, &result->BssDescriptor)) { + conc_channel = csr_get_concurrent_operation_channel( + mac_ctx); + sms_log(mac_ctx, LOG1, FL("csr Conc Channel = %d"), + conc_channel); + if ((conc_channel) && (conc_channel == + result->BssDescriptor.channelId)) { + /* + * make this 0 because we do not want the below + * check to pass as we don't want to connect on + * other channel + */ + sms_log(mac_ctx, LOG1, FL("Conc chnl match=%d"), + conc_channel); + conc_channel = 0; + } + } + + /* Ok to roam this */ + if (!conc_channel && + QDF_IS_STATUS_SUCCESS(csr_roam_should_roam(mac_ctx, + session_id, &result->BssDescriptor, roam_id))) { + status = false; + break; + } else { + *roam_state = eCsrStopRoamingDueToConcurrency; + status = true; + } + roam_bss_entry = csr_ll_next(&bss_list->List, roam_bss_entry, + LL_ACCESS_LOCK); + } + *csr_result_info = result; + *csr_scan_result = scan_result; + return status; +} + +/** + * csr_roam_join_handle_profile() - Handle join scenario based on profile + * @mac_ctx: Global MAC Context + * @session_id: SME Session ID + * @cmd: Command + * @roam_info_ptr: Pointed to the roaming info for join + * @roam_state: Current roaming state + * @result: Result of join + * @scan_result: Global scan result + * + * Return: None + */ +static void csr_roam_join_handle_profile(tpAniSirGlobal mac_ctx, + uint32_t session_id, tSmeCmd *cmd, tCsrRoamInfo *roam_info_ptr, + eCsrJoinState *roam_state, tCsrScanResultInfo *result, + tCsrScanResult *scan_result) +{ +#ifndef WLAN_MDM_CODE_REDUCTION_OPT + uint8_t acm_mask = 0; +#endif + QDF_STATUS status; + tCsrRoamSession *session; + tCsrRoamProfile *profile = &cmd->u.roamCmd.roamProfile; + tDot11fBeaconIEs *ies_local = NULL; + + if (!CSR_IS_SESSION_VALID(mac_ctx, session_id)) { + sms_log(mac_ctx, LOGE, FL("Invalid session id %d"), session_id); + return; + } + session = CSR_GET_SESSION(mac_ctx, session_id); + + /* + * We have something to roam, tell HDD when it is infra. + * For IBSS, the indication goes back to HDD via eCSR_ROAM_IBSS_IND + */ + if (CSR_IS_INFRASTRUCTURE(profile) && roam_info_ptr) { + if (session->bRefAssocStartCnt) { + session->bRefAssocStartCnt--; + roam_info_ptr->pProfile = profile; + /* + * Complete the last assoc attempt as a + * new one is about to be tried + */ + csr_roam_call_callback(mac_ctx, session_id, + roam_info_ptr, cmd->u.roamCmd.roamId, + eCSR_ROAM_ASSOCIATION_COMPLETION, + eCSR_ROAM_RESULT_NOT_ASSOCIATED); + } + /* If roaming has stopped, don't continue the roaming command */ + if (!CSR_IS_ROAMING(session) && CSR_IS_ROAMING_COMMAND(cmd)) { + /* No need to complete roaming as it already complete */ + sms_log(mac_ctx, LOGW, + FL( + "Roam cmd(reason %d)aborted as roam complete"), + cmd->u.roamCmd.roamReason); + *roam_state = eCsrStopRoaming; + csr_set_abort_roaming_command(mac_ctx, cmd); + return; + } + qdf_mem_set(roam_info_ptr, sizeof(tCsrRoamInfo), 0); + if (!scan_result) + cmd->u.roamCmd.roamProfile.uapsd_mask = 0; + else + ies_local = scan_result->Result.pvIes; + + if (!result) { + sms_log(mac_ctx, LOGE, FL(" cannot parse IEs")); + *roam_state = eCsrStopRoaming; + return; + } else if (scan_result && !ies_local && + (!QDF_IS_STATUS_SUCCESS( + csr_get_parsed_bss_description_ies( + mac_ctx, &result->BssDescriptor, + &ies_local)))) { + sms_log(mac_ctx, LOGE, FL(" cannot parse IEs")); + *roam_state = eCsrStopRoaming; + return; + } + roam_info_ptr->pBssDesc = &result->BssDescriptor; + cmd->u.roamCmd.pLastRoamBss = roam_info_ptr->pBssDesc; + /* dont put uapsd_mask if BSS doesn't support uAPSD */ + if (scan_result && cmd->u.roamCmd.roamProfile.uapsd_mask + && CSR_IS_QOS_BSS(ies_local) + && CSR_IS_UAPSD_BSS(ies_local)) { +#ifndef WLAN_MDM_CODE_REDUCTION_OPT + acm_mask = sme_qos_get_acm_mask(mac_ctx, + &result->BssDescriptor, ies_local); +#endif /* WLAN_MDM_CODE_REDUCTION_OPT */ + } else { + cmd->u.roamCmd.roamProfile.uapsd_mask = 0; + } + if (ies_local && !scan_result->Result.pvIes) + qdf_mem_free(ies_local); + roam_info_ptr->pProfile = profile; + session->bRefAssocStartCnt++; + csr_roam_call_callback(mac_ctx, session_id, roam_info_ptr, + cmd->u.roamCmd.roamId, eCSR_ROAM_ASSOCIATION_START, + eCSR_ROAM_RESULT_NONE); + } + if (NULL != cmd->u.roamCmd.pRoamBssEntry) { + /* + * We have BSS + * Need to assign these value because + * they are used in csr_is_same_profile + */ + scan_result = GET_BASE_ADDR(cmd->u.roamCmd.pRoamBssEntry, + tCsrScanResult, Link); + /* + * The OSEN IE doesn't provide the cipher suite.Therefore set + * to constant value of AES + */ + if (cmd->u.roamCmd.roamProfile.bOSENAssociation) { + cmd->u.roamCmd.roamProfile.negotiatedUCEncryptionType = + eCSR_ENCRYPT_TYPE_AES; + cmd->u.roamCmd.roamProfile.negotiatedMCEncryptionType = + eCSR_ENCRYPT_TYPE_AES; + } else { + /* Negotiated while building scan result. */ + cmd->u.roamCmd.roamProfile.negotiatedUCEncryptionType = + scan_result->ucEncryptionType; + cmd->u.roamCmd.roamProfile.negotiatedMCEncryptionType = + scan_result->mcEncryptionType; + } + cmd->u.roamCmd.roamProfile.negotiatedAuthType = + scan_result->authType; + if (CSR_IS_START_IBSS(&cmd->u.roamCmd.roamProfile)) { + if (csr_is_same_profile(mac_ctx, + &session->connectedProfile, profile)) { + *roam_state = eCsrStartIbssSameIbss; + return; + } + } + if (cmd->u.roamCmd.fReassocToSelfNoCapChange) { + /* trying to connect to the one already connected */ + cmd->u.roamCmd.fReassocToSelfNoCapChange = false; + *roam_state = eCsrReassocToSelfNoCapChange; + return; + } + /* Attempt to Join this Bss... */ + *roam_state = csr_roam_join(mac_ctx, session_id, + &scan_result->Result, profile); + return; + } + + /* For an IBSS profile, then we need to start the IBSS. */ + if (CSR_IS_START_IBSS(profile)) { + bool same_ibss = false; + /* Attempt to start this IBSS... */ + csr_roam_assign_default_param(mac_ctx, cmd); + status = csr_roam_start_ibss(mac_ctx, session_id, + profile, &same_ibss); + if (QDF_IS_STATUS_SUCCESS(status)) { + if (same_ibss) + *roam_state = eCsrStartIbssSameIbss; + else + *roam_state = eCsrContinueRoaming; + } else { + /* it somehow fail need to stop */ + *roam_state = eCsrStopRoaming; + } + return; + } else if (CSR_IS_INFRA_AP(profile)) { + /* Attempt to start this WDS... */ + csr_roam_assign_default_param(mac_ctx, cmd); + /* For AP WDS, we dont have any BSSDescription */ + status = csr_roam_start_wds(mac_ctx, session_id, profile, NULL); + if (QDF_IS_STATUS_SUCCESS(status)) + *roam_state = eCsrContinueRoaming; + else + *roam_state = eCsrStopRoaming; + } else if (CSR_IS_NDI(profile)) { + csr_roam_assign_default_param(mac_ctx, cmd); + status = csr_roam_start_ndi(mac_ctx, session_id, profile); + if (QDF_IS_STATUS_SUCCESS(status)) + *roam_state = eCsrContinueRoaming; + else + *roam_state = eCsrStopRoaming; + } else { + /* Nothing we can do */ + sms_log(mac_ctx, LOGW, FL("cannot continue without BSS list")); + *roam_state = eCsrStopRoaming; + return; + } + +} +/** + * csr_roam_join_next_bss() - Pick the next BSS for join + * @mac_ctx: Global MAC Context + * @cmd: Command + * @use_same_bss: Use Same BSS to Join + * + * Return: The Join State + */ +static eCsrJoinState csr_roam_join_next_bss(tpAniSirGlobal mac_ctx, + tSmeCmd *cmd, bool use_same_bss) +{ + tCsrScanResult *scan_result = NULL; + eCsrJoinState roam_state = eCsrStopRoaming; + tScanResultList *bss_list = + (tScanResultList *) cmd->u.roamCmd.hBSSList; + bool done = false; + tCsrRoamInfo roam_info, *roam_info_ptr = NULL; + uint32_t session_id = cmd->sessionId; + tCsrRoamSession *session = CSR_GET_SESSION(mac_ctx, session_id); + tCsrRoamProfile *profile = &cmd->u.roamCmd.roamProfile; + tCsrRoamJoinStatus *join_status; + tCsrScanResultInfo *result = NULL; + + if (!session) { + sms_log(mac_ctx, LOGE, FL("session %d not found"), session_id); + return eCsrStopRoaming; + } + + qdf_mem_set(&roam_info, sizeof(roam_info), 0); + qdf_mem_copy(&roam_info.bssid, &session->joinFailStatusCode.bssId, + sizeof(tSirMacAddr)); + /* + * When handling AP's capability change, continue to associate + * to same BSS and make sure pRoamBssEntry is not Null. + */ + if ((NULL != bss_list) && + ((false == use_same_bss) || + (cmd->u.roamCmd.pRoamBssEntry == NULL))) { + if (cmd->u.roamCmd.pRoamBssEntry == NULL) { + /* Try the first BSS */ + cmd->u.roamCmd.pLastRoamBss = NULL; + cmd->u.roamCmd.pRoamBssEntry = + csr_ll_peek_head(&bss_list->List, + LL_ACCESS_LOCK); + } else { + cmd->u.roamCmd.pRoamBssEntry = + csr_ll_next(&bss_list->List, + cmd->u.roamCmd.pRoamBssEntry, + LL_ACCESS_LOCK); + /* + * Done with all the BSSs. + * In this case, will tell HDD the + * completion + */ + if (NULL == cmd->u.roamCmd.pRoamBssEntry) + goto end; + /* + * We need to indicate to HDD that we + * are done with this one. + */ + roam_info.pBssDesc = cmd->u.roamCmd.pLastRoamBss; + join_status = &session->joinFailStatusCode; + roam_info.statusCode = join_status->statusCode; + roam_info.reasonCode = join_status->reasonCode; + roam_info_ptr = &roam_info; + } + done = csr_roam_select_bss(mac_ctx, + cmd->u.roamCmd.pRoamBssEntry, &result, + &scan_result, session_id, cmd->u.roamCmd.roamId, + &roam_state, bss_list); + if (done) + goto end; + } + if (!roam_info_ptr) + roam_info_ptr = &roam_info; + roam_info_ptr->u.pConnectedProfile = &session->connectedProfile; + + csr_roam_join_handle_profile(mac_ctx, session_id, cmd, roam_info_ptr, + &roam_state, result, scan_result); +end: + if ((eCsrStopRoaming == roam_state) && CSR_IS_INFRASTRUCTURE(profile) && + (session->bRefAssocStartCnt > 0)) { + /* + * Need to indicate association_completion if association_start + * has been done + */ + session->bRefAssocStartCnt--; + /* + * Complete the last assoc attempte as a + * new one is about to be tried + */ + roam_info_ptr = &roam_info; + roam_info_ptr->pProfile = profile; + csr_roam_call_callback(mac_ctx, session_id, + roam_info_ptr, cmd->u.roamCmd.roamId, + eCSR_ROAM_ASSOCIATION_COMPLETION, + eCSR_ROAM_RESULT_NOT_ASSOCIATED); + } + + return roam_state; +} + +static QDF_STATUS csr_roam(tpAniSirGlobal pMac, tSmeCmd *pCommand) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + eCsrJoinState RoamState; + eCsrRoamSubState substate; + uint32_t sessionId = pCommand->sessionId; + + /* Attept to join a Bss... */ + RoamState = csr_roam_join_next_bss(pMac, pCommand, false); + + /* if nothing to join.. */ + if ((eCsrStopRoaming == RoamState) || + (eCsrStopRoamingDueToConcurrency == RoamState)) { + bool fComplete = false; + /* and if connected in Infrastructure mode... */ + if (csr_is_conn_state_infra(pMac, sessionId)) { + /* ... then we need to issue a disassociation */ + substate = eCSR_ROAM_SUBSTATE_DISASSOC_NOTHING_TO_JOIN; + status = csr_roam_issue_disassociate(pMac, sessionId, + substate, false); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOGW, + FL("fail issuing disassoc status = %d"), + status); + /* + * roam command is completed by caller in the + * failed case + */ + fComplete = true; + } + } else if (csr_is_conn_state_ibss(pMac, sessionId)) { + status = csr_roam_issue_stop_bss(pMac, sessionId, + eCSR_ROAM_SUBSTATE_STOP_BSS_REQ); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOGW, + FL("fail issuing stop bss status = %d"), + status); + /* + * roam command is completed by caller in the + * failed case + */ + fComplete = true; + } + } else if (csr_is_conn_state_connected_infra_ap(pMac, + sessionId)) { + substate = eCSR_ROAM_SUBSTATE_STOP_BSS_REQ; + status = csr_roam_issue_stop_bss(pMac, sessionId, + substate); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOGW, + FL("fail issuing stop bss status = %d"), + status); + /* + * roam command is completed by caller in the + * failed case + */ + fComplete = true; + } + } else { + fComplete = true; + } + + if (fComplete) { + /* otherwise, we can complete the Roam command here. */ + if (eCsrStopRoamingDueToConcurrency == RoamState) + csr_roam_complete(pMac, + eCsrJoinFailureDueToConcurrency, NULL); + else + csr_roam_complete(pMac, + eCsrNothingToJoin, NULL); + } + } else if (eCsrReassocToSelfNoCapChange == RoamState) { + csr_roam_complete(pMac, eCsrSilentlyStopRoamingSaveState, + NULL); + } else if (eCsrStartIbssSameIbss == RoamState) { + csr_roam_complete(pMac, eCsrSilentlyStopRoaming, NULL); + } + + return status; +} + +static +QDF_STATUS csr_process_ft_reassoc_roam_command(tpAniSirGlobal pMac, + tSmeCmd *pCommand) +{ + uint32_t sessionId; + tCsrRoamSession *pSession; + tCsrScanResult *pScanResult = NULL; + tSirBssDescription *pBssDesc = NULL; + QDF_STATUS status = QDF_STATUS_SUCCESS; + sessionId = pCommand->sessionId; + pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!pSession) { + sms_log(pMac, LOGE, FL(" session %d not found "), sessionId); + return QDF_STATUS_E_FAILURE; + } + + if (CSR_IS_ROAMING(pSession) && pSession->fCancelRoaming) { + /* the roaming is cancelled. Simply complete the command */ + sms_log(pMac, LOG1, FL("Roam command canceled")); + csr_roam_complete(pMac, eCsrNothingToJoin, NULL); + return QDF_STATUS_E_FAILURE; + } + if (pCommand->u.roamCmd.pRoamBssEntry) { + pScanResult = + GET_BASE_ADDR(pCommand->u.roamCmd.pRoamBssEntry, + tCsrScanResult, Link); + pBssDesc = &pScanResult->Result.BssDescriptor; + } else { + /* the roaming is cancelled. Simply complete the command */ + sms_log(pMac, LOG1, FL("Roam command canceled")); + csr_roam_complete(pMac, eCsrNothingToJoin, NULL); + return QDF_STATUS_E_FAILURE; + } + status = csr_roam_issue_reassociate(pMac, sessionId, pBssDesc, + (tDot11fBeaconIEs *) (pScanResult-> + Result.pvIes), + &pCommand->u.roamCmd.roamProfile); + return status; +} + +/** + * csr_roam_trigger_reassociate() - Helper function to trigger reassociate + * @mac_ctx: pointer to mac context + * @cmd: sme command + * @roam_info: Roaming infor structure + * @session_ptr: session pointer + * @session_id: session id + * + * This function will trigger reassociate. + * + * Return: QDF_STATUS for success or failure. + */ +static QDF_STATUS csr_roam_trigger_reassociate(tpAniSirGlobal mac_ctx, + tSmeCmd *cmd, tCsrRoamInfo *roam_info, + tCsrRoamSession *session_ptr, uint32_t session_id) +{ + tDot11fBeaconIEs *pIes = NULL; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + if (session_ptr->pConnectBssDesc) { + status = csr_get_parsed_bss_description_ies(mac_ctx, + session_ptr->pConnectBssDesc, &pIes); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sms_log(mac_ctx, LOGE, FL("fail to parse IEs")); + } else { + roam_info->reasonCode = + eCsrRoamReasonStaCapabilityChanged; + csr_roam_call_callback(mac_ctx, session_ptr->sessionId, + roam_info, 0, eCSR_ROAM_ROAMING_START, + eCSR_ROAM_RESULT_NONE); + session_ptr->roamingReason = eCsrReassocRoaming; + roam_info->pBssDesc = session_ptr->pConnectBssDesc; + roam_info->pProfile = &cmd->u.roamCmd.roamProfile; + session_ptr->bRefAssocStartCnt++; + csr_roam_call_callback(mac_ctx, session_id, roam_info, + cmd->u.roamCmd.roamId, + eCSR_ROAM_ASSOCIATION_START, + eCSR_ROAM_RESULT_NONE); + + sms_log(mac_ctx, LOG1, + FL("calling csr_roam_issue_reassociate")); + status = csr_roam_issue_reassociate(mac_ctx, session_id, + session_ptr->pConnectBssDesc, pIes, + &cmd->u.roamCmd.roamProfile); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sms_log(mac_ctx, LOGE, FL("failed status %d"), + status); + csr_release_command_roam(mac_ctx, cmd); + } + + qdf_mem_free(pIes); + pIes = NULL; + } + } else { + sms_log(mac_ctx, LOGE, FL + ("reassoc to same AP failed as connected BSS is NULL")); + status = QDF_STATUS_E_FAILURE; + } + return status; +} + +QDF_STATUS csr_roam_process_command(tpAniSirGlobal pMac, tSmeCmd *pCommand) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tCsrRoamInfo roamInfo; + uint32_t sessionId = pCommand->sessionId; + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!pSession) { + sms_log(pMac, LOGE, FL("session %d not found"), sessionId); + return QDF_STATUS_E_FAILURE; + } + sms_log(pMac, LOG1, FL("Roam Reason : %d, sessionId: %d"), + pCommand->u.roamCmd.roamReason, sessionId); + + pSession->disconnect_reason = pCommand->u.roamCmd.disconnect_reason; + + switch (pCommand->u.roamCmd.roamReason) { + case eCsrForcedDisassoc: + if (eCSR_ROAMING_STATE_IDLE == pMac->roam.curState[sessionId]) { + sms_log(pMac, LOGE, + FL("Ignore eCsrForcedDisassoc cmd on roam state" + " %d"), eCSR_ROAMING_STATE_IDLE); + return QDF_STATUS_E_FAILURE; + } + status = csr_roam_process_disassoc_deauth(pMac, pCommand, + true, false); + csr_free_roam_profile(pMac, sessionId); + break; + case eCsrSmeIssuedDisassocForHandoff: + /* Not to free pMac->roam.pCurRoamProfile (via + * csr_free_roam_profile) because its needed after disconnect */ + status = csr_roam_process_disassoc_deauth(pMac, pCommand, + true, false); + + break; + case eCsrForcedDisassocMICFailure: + status = csr_roam_process_disassoc_deauth(pMac, pCommand, + true, true); + csr_free_roam_profile(pMac, sessionId); + break; + case eCsrForcedDeauth: + status = csr_roam_process_disassoc_deauth(pMac, pCommand, + false, false); + csr_free_roam_profile(pMac, sessionId); + break; + case eCsrHddIssuedReassocToSameAP: + case eCsrSmeIssuedReassocToSameAP: + status = csr_roam_trigger_reassociate(pMac, pCommand, &roamInfo, + pSession, sessionId); + break; + case eCsrCapsChange: + sms_log(pMac, LOGE, FL("received eCsrCapsChange ")); + csr_roam_state_change(pMac, eCSR_ROAMING_STATE_JOINING, + sessionId); + status = csr_roam_issue_disassociate(pMac, sessionId, + eCSR_ROAM_SUBSTATE_DISCONNECT_CONTINUE_ROAMING, + false); + break; + case eCsrSmeIssuedFTReassoc: + sms_log(pMac, LOG1, FL("received FT Reassoc Req ")); + status = csr_process_ft_reassoc_roam_command(pMac, pCommand); + break; + + case eCsrStopBss: + csr_roam_state_change(pMac, eCSR_ROAMING_STATE_JOINING, + sessionId); + status = csr_roam_issue_stop_bss(pMac, sessionId, + eCSR_ROAM_SUBSTATE_STOP_BSS_REQ); + break; + + case eCsrForcedDisassocSta: + csr_roam_state_change(pMac, eCSR_ROAMING_STATE_JOINING, + sessionId); + csr_roam_substate_change(pMac, eCSR_ROAM_SUBSTATE_DISASSOC_REQ, + sessionId); + sms_log(pMac, LOG1, FL("Disassociate issued with reason: %d"), + pCommand->u.roamCmd.reason); + status = csr_send_mb_disassoc_req_msg(pMac, sessionId, + pCommand->u.roamCmd.peerMac, + pCommand->u.roamCmd.reason); + break; + + case eCsrForcedDeauthSta: + csr_roam_state_change(pMac, eCSR_ROAMING_STATE_JOINING, + sessionId); + csr_roam_substate_change(pMac, eCSR_ROAM_SUBSTATE_DEAUTH_REQ, + sessionId); + status = csr_send_mb_deauth_req_msg(pMac, sessionId, + pCommand->u.roamCmd.peerMac, + pCommand->u.roamCmd.reason); + break; + + case eCsrPerformPreauth: + sms_log(pMac, LOG1, FL("Attempting FT PreAuth Req")); + status = csr_roam_issue_ft_preauth_req(pMac, sessionId, + pCommand->u.roamCmd.pLastRoamBss); + break; + default: + csr_roam_state_change(pMac, eCSR_ROAMING_STATE_JOINING, + sessionId); + + if (pCommand->u.roamCmd.fUpdateCurRoamProfile) { + /* Remember the roaming profile */ + csr_free_roam_profile(pMac, sessionId); + pSession->pCurRoamProfile = + qdf_mem_malloc(sizeof(tCsrRoamProfile)); + if (NULL != pSession->pCurRoamProfile) { + csr_roam_copy_profile(pMac, + pSession->pCurRoamProfile, + &pCommand->u.roamCmd.roamProfile); + } + } + /* + * At this point original uapsd_mask is saved in + * pCurRoamProfile. uapsd_mask in the pCommand may change from + * this point on. Attempt to roam with the new scan results + * (if we need to..) + */ + status = csr_roam(pMac, pCommand); + if (!QDF_IS_STATUS_SUCCESS(status)) + sms_log(pMac, LOGW, + FL("csr_roam() failed with status = 0x%08X"), + status); + break; + } + return status; +} + +void csr_reinit_roam_cmd(tpAniSirGlobal pMac, tSmeCmd *pCommand) +{ + if (pCommand->u.roamCmd.fReleaseBssList) { + csr_scan_result_purge(pMac, pCommand->u.roamCmd.hBSSList); + pCommand->u.roamCmd.fReleaseBssList = false; + pCommand->u.roamCmd.hBSSList = CSR_INVALID_SCANRESULT_HANDLE; + } + if (pCommand->u.roamCmd.fReleaseProfile) { + csr_release_profile(pMac, &pCommand->u.roamCmd.roamProfile); + pCommand->u.roamCmd.fReleaseProfile = false; + } + pCommand->u.roamCmd.pRoamBssEntry = NULL; + /* Because u.roamCmd is union and share with scanCmd and StatusChange */ + qdf_mem_set(&pCommand->u.roamCmd, sizeof(tRoamCmd), 0); +} + +void csr_reinit_wm_status_change_cmd(tpAniSirGlobal pMac, tSmeCmd *pCommand) +{ + qdf_mem_set(&pCommand->u.wmStatusChangeCmd, sizeof(tWmStatusChangeCmd), + 0); +} + +void csr_roam_complete(tpAniSirGlobal pMac, eCsrRoamCompleteResult Result, + void *Context) +{ + tListElem *pEntry; + tSmeCmd *pCommand; + bool fReleaseCommand = true; + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "%s: Roam Completion ...", __func__); + pEntry = csr_ll_peek_head(&pMac->sme.smeCmdActiveList, LL_ACCESS_LOCK); + if (pEntry) { + pCommand = GET_BASE_ADDR(pEntry, tSmeCmd, Link); + /* If the head of the queue is Active and it is a ROAM command, remove */ + /* and put this on the Free queue. */ + if (eSmeCommandRoam == pCommand->command) { + /* we need to process the result first before removing it from active list because state changes */ + /* still happening insides roamQProcessRoamResults so no other roam command should be issued */ + fReleaseCommand = + csr_roam_process_results(pMac, pCommand, Result, + Context); + if (fReleaseCommand) { + if (csr_ll_remove_entry + (&pMac->sme.smeCmdActiveList, pEntry, + LL_ACCESS_LOCK)) { + csr_release_command_roam(pMac, pCommand); + } else { + sms_log(pMac, LOGE, + " **********csr_roam_complete fail to release command reason %d", + pCommand->u.roamCmd.roamReason); + } + } else { + sms_log(pMac, LOGE, + " **********csr_roam_complete fail to release command reason %d", + pCommand->u.roamCmd.roamReason); + } + } else { + sms_log(pMac, LOGW, + "CSR: Roam Completion called but ROAM command is not ACTIVE ..."); + } + } else { + sms_log(pMac, LOGW, + "CSR: Roam Completion called but NO commands are ACTIVE ..."); + } + if (fReleaseCommand) { + sme_process_pending_queue(pMac); + } +} + +void csr_reset_pmkid_candidate_list(tpAniSirGlobal pMac, uint32_t sessionId) +{ + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + if (!pSession) { + sms_log(pMac, LOGE, FL(" session %d not found "), sessionId); + return; + } + qdf_mem_set(&(pSession->PmkidCandidateInfo[0]), + sizeof(tPmkidCandidateInfo) * CSR_MAX_PMKID_ALLOWED, 0); + pSession->NumPmkidCandidate = 0; +} + +#ifdef FEATURE_WLAN_WAPI +void csr_reset_bkid_candidate_list(tpAniSirGlobal pMac, uint32_t sessionId) +{ + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + if (!pSession) { + sms_log(pMac, LOGE, FL(" session %d not found "), sessionId); + return; + } + qdf_mem_set(&(pSession->BkidCandidateInfo[0]), + sizeof(tBkidCandidateInfo) * CSR_MAX_BKID_ALLOWED, 0); + pSession->NumBkidCandidate = 0; +} +#endif /* FEATURE_WLAN_WAPI */ +extern uint8_t csr_wpa_oui[][CSR_WPA_OUI_SIZE]; + +/** + * csr_roam_save_params() - Helper function to save params + * @mac_ctx: pointer to mac context + * @session_ptr: Session pointer + * @auth_type: auth type + * @ie_ptr: pointer to ie + * @ie_local: pointr to local ie + * + * This function will save params to session + * + * Return: none. + */ +static QDF_STATUS csr_roam_save_params(tpAniSirGlobal mac_ctx, + tCsrRoamSession *session_ptr, + eCsrAuthType auth_type, + tDot11fBeaconIEs *ie_ptr, + tDot11fBeaconIEs *ie_local) +{ + uint32_t nIeLen; + uint8_t *pIeBuf; + + if ((eCSR_AUTH_TYPE_RSN == auth_type) || + (eCSR_AUTH_TYPE_FT_RSN == auth_type) || + (eCSR_AUTH_TYPE_FT_RSN_PSK == auth_type) || +#if defined WLAN_FEATURE_11W + (eCSR_AUTH_TYPE_RSN_PSK_SHA256 == auth_type) || + (eCSR_AUTH_TYPE_RSN_8021X_SHA256 == auth_type) || +#endif + (eCSR_AUTH_TYPE_RSN_PSK == auth_type)) { + if (ie_local->RSN.present) { + tDot11fIERSN *rsnie = &ie_local->RSN; + /* + * Calculate the actual length + * version + gp_cipher_suite + pwise_cipher_suite_count + * + akm_suite_count + reserved + pwise_cipher_suites + */ + nIeLen = 8 + 2 + 2 + + (rsnie->pwise_cipher_suite_count * 4) + + (rsnie->akm_suite_count * 4); + if (rsnie->pmkid_count) + /* pmkid */ + nIeLen += 2 + rsnie->pmkid_count * 4; + + /* nIeLen doesn't count EID and length fields */ + session_ptr->pWpaRsnRspIE = qdf_mem_malloc(nIeLen + 2); + if (NULL == session_ptr->pWpaRsnRspIE) + return QDF_STATUS_E_NOMEM; + + session_ptr->pWpaRsnRspIE[0] = DOT11F_EID_RSN; + session_ptr->pWpaRsnRspIE[1] = (uint8_t) nIeLen; + /* copy upto akm_suites */ + pIeBuf = session_ptr->pWpaRsnRspIE + 2; + qdf_mem_copy(pIeBuf, &rsnie->version, + sizeof(rsnie->version)); + pIeBuf += sizeof(rsnie->version); + qdf_mem_copy(pIeBuf, &rsnie->gp_cipher_suite, + sizeof(rsnie->gp_cipher_suite)); + pIeBuf += sizeof(rsnie->gp_cipher_suite); + qdf_mem_copy(pIeBuf, &rsnie->pwise_cipher_suite_count, + sizeof(rsnie->pwise_cipher_suite_count)); + pIeBuf += sizeof(rsnie->pwise_cipher_suite_count); + if (rsnie->pwise_cipher_suite_count) { + /* copy pwise_cipher_suites */ + qdf_mem_copy(pIeBuf, rsnie->pwise_cipher_suites, + rsnie->pwise_cipher_suite_count * 4); + pIeBuf += rsnie->pwise_cipher_suite_count * 4; + } + qdf_mem_copy(pIeBuf, &rsnie->akm_suite_count, 2); + pIeBuf += 2; + if (rsnie->akm_suite_count) { + /* copy akm_suites */ + qdf_mem_copy(pIeBuf, rsnie->akm_suites, + rsnie->akm_suite_count * 4); + pIeBuf += rsnie->akm_suite_count * 4; + } + /* copy the rest */ + qdf_mem_copy(pIeBuf, rsnie->akm_suites + + rsnie->akm_suite_count * 4, + 2 + rsnie->pmkid_count * 4); + session_ptr->nWpaRsnRspIeLength = nIeLen + 2; + } + } else if ((eCSR_AUTH_TYPE_WPA == auth_type) || + (eCSR_AUTH_TYPE_WPA_PSK == auth_type)) { + if (ie_local->WPA.present) { + tDot11fIEWPA *wpaie = &ie_local->WPA; + /* Calculate the actual length wpaie */ + nIeLen = 12 + 2 /* auth_suite_count */ + + wpaie->unicast_cipher_count * 4 + + wpaie->auth_suite_count * 4; + + /* The WPA capabilities follows the Auth Suite + * (two octects)-- this field is optional, and + * we always "send" zero, so just remove it. This is + * consistent with our assumptions in the frames + * compiler; nIeLen doesn't count EID & length fields */ + session_ptr->pWpaRsnRspIE = qdf_mem_malloc(nIeLen + 2); + if (NULL == session_ptr->pWpaRsnRspIE) + return QDF_STATUS_E_NOMEM; + session_ptr->pWpaRsnRspIE[0] = DOT11F_EID_WPA; + session_ptr->pWpaRsnRspIE[1] = (uint8_t) nIeLen; + pIeBuf = session_ptr->pWpaRsnRspIE + 2; + /* Copy WPA OUI */ + qdf_mem_copy(pIeBuf, &csr_wpa_oui[1], 4); + pIeBuf += 4; + qdf_mem_copy(pIeBuf, &wpaie->version, + 8 + wpaie->unicast_cipher_count * 4); + pIeBuf += 8 + wpaie->unicast_cipher_count * 4; + qdf_mem_copy(pIeBuf, &wpaie->auth_suite_count, + 2 + wpaie->auth_suite_count * 4); + pIeBuf += wpaie->auth_suite_count * 4; + session_ptr->nWpaRsnRspIeLength = nIeLen + 2; + } + } +#ifdef FEATURE_WLAN_WAPI + else if ((eCSR_AUTH_TYPE_WAPI_WAI_PSK == auth_type) || + (eCSR_AUTH_TYPE_WAPI_WAI_CERTIFICATE == + auth_type)) { + if (ie_local->WAPI.present) { + tDot11fIEWAPI *wapi_ie = &ie_local->WAPI; + /* Calculate the actual length of wapi ie*/ + nIeLen = 4 + 2 /* pwise_cipher_suite_count */ + + wapi_ie->akm_suite_count * 4 + + wapi_ie->unicast_cipher_suite_count * 4 + + 6; /* gp_cipher_suite + preauth + reserved */ + + if (wapi_ie->bkid_count) + nIeLen += 2 + wapi_ie->bkid_count * 4; + + /* nIeLen doesn't count EID and length fields */ + session_ptr->pWapiRspIE = + qdf_mem_malloc(nIeLen + 2); + if (NULL == session_ptr->pWapiRspIE) + return QDF_STATUS_E_NOMEM; + session_ptr->pWapiRspIE[0] = DOT11F_EID_WAPI; + session_ptr->pWapiRspIE[1] = (uint8_t) nIeLen; + pIeBuf = session_ptr->pWapiRspIE + 2; + /* copy upto akm_suite_count */ + qdf_mem_copy(pIeBuf, &wapi_ie->version, 2); + pIeBuf += 4; + if (wapi_ie->akm_suite_count) { + /* copy akm_suites */ + qdf_mem_copy(pIeBuf, + wapi_ie->akm_suites, + wapi_ie->akm_suite_count * 4); + pIeBuf += wapi_ie->akm_suite_count * 4; + } + qdf_mem_copy(pIeBuf, + &wapi_ie->unicast_cipher_suite_count, 2); + pIeBuf += 2; + if (wapi_ie->unicast_cipher_suite_count) { + uint16_t suite_size = + wapi_ie->unicast_cipher_suite_count * 4; + /* copy pwise_cipher_suites */ + qdf_mem_copy(pIeBuf, + wapi_ie->unicast_cipher_suites, + suite_size); + pIeBuf += suite_size; + } + /* gp_cipher_suite */ + qdf_mem_copy(pIeBuf, + wapi_ie->multicast_cipher_suite, 4); + pIeBuf += 4; + /* preauth + reserved */ + qdf_mem_copy(pIeBuf, + wapi_ie->multicast_cipher_suite + 4, 2); + pIeBuf += 2; + if (wapi_ie->bkid_count) { + /* bkid_count */ + qdf_mem_copy(pIeBuf, &wapi_ie->bkid_count, 2); + pIeBuf += 2; + /* copy akm_suites */ + qdf_mem_copy(pIeBuf, wapi_ie->bkid, + wapi_ie->bkid_count * 4); + pIeBuf += wapi_ie->bkid_count * 4; + } + session_ptr->nWapiRspIeLength = nIeLen + 2; + } + } +#endif /* FEATURE_WLAN_WAPI */ + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS csr_roam_save_security_rsp_ie(tpAniSirGlobal pMac, + uint32_t sessionId, + eCsrAuthType authType, + tSirBssDescription *pSirBssDesc, + tDot11fBeaconIEs *pIes) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + tDot11fBeaconIEs *pIesLocal = pIes; + + if (!pSession) { + sms_log(pMac, LOGE, FL("session %d not found"), sessionId); + return QDF_STATUS_E_FAILURE; + } + + sms_log(pMac, LOG1, FL("authType %d session %d"), authType, sessionId); + if ((eCSR_AUTH_TYPE_WPA == authType) || + (eCSR_AUTH_TYPE_WPA_PSK == authType) || + (eCSR_AUTH_TYPE_RSN == authType) || + (eCSR_AUTH_TYPE_RSN_PSK == authType) + || (eCSR_AUTH_TYPE_FT_RSN == authType) || + (eCSR_AUTH_TYPE_FT_RSN_PSK == authType) +#ifdef FEATURE_WLAN_WAPI + || (eCSR_AUTH_TYPE_WAPI_WAI_PSK == authType) || + (eCSR_AUTH_TYPE_WAPI_WAI_CERTIFICATE == authType) +#endif /* FEATURE_WLAN_WAPI */ +#ifdef WLAN_FEATURE_11W + || (eCSR_AUTH_TYPE_RSN_PSK_SHA256 == authType) || + (eCSR_AUTH_TYPE_RSN_8021X_SHA256 == authType) +#endif /* FEATURE_WLAN_WAPI */ + ) { + if (!pIesLocal && !QDF_IS_STATUS_SUCCESS + (csr_get_parsed_bss_description_ies(pMac, + pSirBssDesc, &pIesLocal))) + sms_log(pMac, LOGE, FL(" cannot parse IEs")); + if (pIesLocal) { + status = csr_roam_save_params(pMac, pSession, authType, + pIes, pIesLocal); + if (!pIes) + /* locally allocated */ + qdf_mem_free(pIesLocal); + } + } + return status; +} + +/* Returns whether the current association is a 11r assoc or not */ +bool csr_roam_is11r_assoc(tpAniSirGlobal pMac, uint8_t sessionId) +{ + return csr_neighbor_roam_is11r_assoc(pMac, sessionId); +} + +/* Returns whether "Legacy Fast Roaming" is currently enabled...or not */ +bool csr_roam_is_fast_roam_enabled(tpAniSirGlobal pMac, uint32_t sessionId) +{ + tCsrRoamSession *pSession = NULL; + + if (CSR_IS_SESSION_VALID(pMac, sessionId)) { + pSession = CSR_GET_SESSION(pMac, sessionId); + if (NULL != pSession->pCurRoamProfile) { + if (pSession->pCurRoamProfile->csrPersona != + QDF_STA_MODE) { + return false; + } + } + } + if (true == CSR_IS_FASTROAM_IN_CONCURRENCY_INI_FEATURE_ENABLED(pMac)) { + return pMac->roam.configParam.isFastRoamIniFeatureEnabled; + } else { + return pMac->roam.configParam.isFastRoamIniFeatureEnabled && + (!csr_is_concurrent_session_running(pMac)); + } +} + +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH +static eCsrPhyMode csr_roamdot11mode_to_phymode(uint8_t dot11mode) +{ + eCsrPhyMode phymode = eCSR_DOT11_MODE_abg; + + switch (dot11mode) { + case WNI_CFG_DOT11_MODE_ALL: + phymode = eCSR_DOT11_MODE_abg; + break; + case WNI_CFG_DOT11_MODE_11A: + phymode = eCSR_DOT11_MODE_11a; + break; + case WNI_CFG_DOT11_MODE_11B: + phymode = eCSR_DOT11_MODE_11b; + break; + case WNI_CFG_DOT11_MODE_11G: + phymode = eCSR_DOT11_MODE_11g; + break; + case WNI_CFG_DOT11_MODE_11N: + phymode = eCSR_DOT11_MODE_11n; + break; + case WNI_CFG_DOT11_MODE_11G_ONLY: + phymode = eCSR_DOT11_MODE_11g_ONLY; + break; + case WNI_CFG_DOT11_MODE_11N_ONLY: + phymode = eCSR_DOT11_MODE_11n_ONLY; + break; + case WNI_CFG_DOT11_MODE_11AC: + phymode = eCSR_DOT11_MODE_11ac; + break; + case WNI_CFG_DOT11_MODE_11AC_ONLY: + phymode = eCSR_DOT11_MODE_11ac_ONLY; + break; + default: + break; + } + + return phymode; +} +#endif + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +static void csr_roam_synch_clean_up (tpAniSirGlobal mac, uint8_t session_id) +{ + cds_msg_t msg; + struct roam_offload_synch_fail *roam_offload_failed = NULL; + tCsrRoamSession *session = &mac->roam.roamSession[session_id]; + + /* Clean up the roam synch in progress for LFR3 */ + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Roam Synch Failed, Clean Up", __func__); + session->roam_synch_in_progress = false; + + roam_offload_failed = qdf_mem_malloc( + sizeof(struct roam_offload_synch_fail)); + if (NULL == roam_offload_failed) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: unable to allocate memory for roam synch fail" , + __func__); + return; + } + + roam_offload_failed->session_id = session_id; + msg.type = WMA_ROAM_OFFLOAD_SYNCH_FAIL; + msg.reserved = 0; + msg.bodyptr = roam_offload_failed; + if (!QDF_IS_STATUS_SUCCESS(cds_mq_post_message(QDF_MODULE_ID_WMA, + &msg))) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "%s: Unable to post WMA_ROAM_OFFLOAD_SYNCH_FAIL to WMA", + __func__); + qdf_mem_free(roam_offload_failed); + } +} +#endif + +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH +/** + * csr_roam_copy_ht_profile() - Copy from src to dst + * @dst_profile: Destination HT profile + * @src_profile: Source HT profile + * + * Copy the HT profile from the given source to destination + * + * Return: None + */ +static void csr_roam_copy_ht_profile(tCsrRoamHTProfile *dst_profile, + tSirSmeHTProfile *src_profile) +{ + dst_profile->phymode = + csr_roamdot11mode_to_phymode(src_profile->dot11mode); + dst_profile->htCapability = src_profile->htCapability; + dst_profile->htSupportedChannelWidthSet = + src_profile->htSupportedChannelWidthSet; + dst_profile->htRecommendedTxWidthSet = + src_profile->htRecommendedTxWidthSet; + dst_profile->htSecondaryChannelOffset = + src_profile->htSecondaryChannelOffset; + dst_profile->vhtCapability = src_profile->vhtCapability; + dst_profile->apCenterChan = src_profile->apCenterChan; + dst_profile->apChanWidth = src_profile->apChanWidth; +} +#endif + +/** + * csr_roam_process_results_default() - Process the result for start bss + * @mac_ctx: Global MAC Context + * @cmd: Command to be processed + * @context: Additional data in context of the cmd + * + * Return: None + */ +static void csr_roam_process_results_default(tpAniSirGlobal mac_ctx, + tSmeCmd *cmd, void *context, eCsrRoamCompleteResult res) +{ + uint32_t session_id = cmd->sessionId; + tCsrRoamSession *session; + tCsrRoamInfo roam_info; + QDF_STATUS status; + + if (!CSR_IS_SESSION_VALID(mac_ctx, session_id)) { + sms_log(mac_ctx, LOGE, FL("Invalid session id %d"), session_id); + return; + } + session = CSR_GET_SESSION(mac_ctx, session_id); + + sms_log(mac_ctx, LOGW, FL("receives no association indication")); + sms_log(mac_ctx, LOG1, FL("Assoc ref count %d"), + session->bRefAssocStartCnt); + if (CSR_IS_INFRASTRUCTURE(&session->connectedProfile) + || CSR_IS_ROAM_SUBSTATE_STOP_BSS_REQ(mac_ctx, session_id)) { + /* + * do not free for the other profiles as we need + * to send down stop BSS later + */ + csr_free_connect_bss_desc(mac_ctx, session_id); + csr_roam_free_connect_profile(&session->connectedProfile); + csr_roam_free_connected_info(mac_ctx, &session->connectedInfo); + csr_set_default_dot11_mode(mac_ctx); + } + + switch (cmd->u.roamCmd.roamReason) { + /* + * If this transition is because of an 802.11 OID, then we + * transition back to INIT state so we sit waiting for more + * OIDs to be issued and we don't start the IDLE timer. + */ + case eCsrSmeIssuedFTReassoc: + case eCsrSmeIssuedAssocToSimilarAP: + case eCsrHddIssued: + case eCsrSmeIssuedDisassocForHandoff: + csr_roam_state_change(mac_ctx, eCSR_ROAMING_STATE_IDLE, + session_id); + qdf_mem_set(&roam_info, sizeof(tCsrRoamInfo), 0); + roam_info.pBssDesc = cmd->u.roamCmd.pLastRoamBss; + roam_info.pProfile = &cmd->u.roamCmd.roamProfile; + roam_info.statusCode = session->joinFailStatusCode.statusCode; + roam_info.reasonCode = session->joinFailStatusCode.reasonCode; + qdf_mem_copy(&roam_info.bssid, + &session->joinFailStatusCode.bssId, + sizeof(struct qdf_mac_addr)); + + /* + * If Join fails while Handoff is in progress, indicate + * disassociated event to supplicant to reconnect + */ + if (csr_roam_is_handoff_in_progress(mac_ctx, session_id)) { + csr_neighbor_roam_indicate_connect(mac_ctx, + (uint8_t)session_id, QDF_STATUS_E_FAILURE); + } + if (session->bRefAssocStartCnt > 0) { + session->bRefAssocStartCnt--; + if (eCsrJoinFailureDueToConcurrency == res) + csr_roam_call_callback(mac_ctx, session_id, + &roam_info, cmd->u.roamCmd.roamId, + eCSR_ROAM_ASSOCIATION_COMPLETION, + eCSR_ROAM_RESULT_ASSOC_FAIL_CON_CHANNEL); + else + csr_roam_call_callback(mac_ctx, session_id, + &roam_info, cmd->u.roamCmd.roamId, + eCSR_ROAM_ASSOCIATION_COMPLETION, + eCSR_ROAM_RESULT_FAILURE); + } else { + /* + * bRefAssocStartCnt is not incremented when + * eRoamState == eCsrStopRoamingDueToConcurrency + * in csr_roam_join_next_bss API. so handle this in + * else case by sending assoc failure + */ + csr_roam_call_callback(mac_ctx, session_id, + &roam_info, cmd->u.scanCmd.roamId, + eCSR_ROAM_ASSOCIATION_FAILURE, + eCSR_ROAM_RESULT_FAILURE); + } + sms_log(mac_ctx, LOG1, FL("roam(reason %d) failed"), + cmd->u.roamCmd.roamReason); +#ifndef WLAN_MDM_CODE_REDUCTION_OPT + sme_qos_update_hand_off((uint8_t) session_id, false); + sme_qos_csr_event_ind(mac_ctx, (uint8_t) session_id, + SME_QOS_CSR_DISCONNECT_IND, NULL); +#endif + csr_roam_completion(mac_ctx, session_id, NULL, cmd, + eCSR_ROAM_RESULT_FAILURE, false); + break; + case eCsrHddIssuedReassocToSameAP: + case eCsrSmeIssuedReassocToSameAP: + csr_roam_state_change(mac_ctx, eCSR_ROAMING_STATE_IDLE, + session_id); + + csr_roam_call_callback(mac_ctx, session_id, NULL, + cmd->u.roamCmd.roamId, eCSR_ROAM_DISASSOCIATED, + eCSR_ROAM_RESULT_FORCED); +#ifndef WLAN_MDM_CODE_REDUCTION_OPT + sme_qos_csr_event_ind(mac_ctx, (uint8_t) session_id, + SME_QOS_CSR_DISCONNECT_IND, NULL); +#endif + csr_roam_completion(mac_ctx, session_id, NULL, cmd, + eCSR_ROAM_RESULT_FAILURE, false); + break; + case eCsrForcedDisassoc: + case eCsrForcedDeauth: + case eCsrSmeIssuedIbssJoinFailure: + csr_roam_state_change(mac_ctx, eCSR_ROAMING_STATE_IDLE, + session_id); + + if (eCsrSmeIssuedIbssJoinFailure == cmd->u.roamCmd.roamReason) + /* notify HDD that IBSS join failed */ + csr_roam_call_callback(mac_ctx, session_id, NULL, 0, + eCSR_ROAM_IBSS_IND, + eCSR_ROAM_RESULT_IBSS_JOIN_FAILED); + else + csr_roam_call_callback(mac_ctx, session_id, NULL, + cmd->u.roamCmd.roamId, eCSR_ROAM_DISASSOCIATED, + eCSR_ROAM_RESULT_FORCED); +#ifndef WLAN_MDM_CODE_REDUCTION_OPT + sme_qos_csr_event_ind(mac_ctx, (uint8_t) session_id, + SME_QOS_CSR_DISCONNECT_IND, + NULL); +#endif + csr_roam_link_down(mac_ctx, session_id); + + if (mac_ctx->roam.deauthRspStatus == eSIR_SME_DEAUTH_STATUS) { + sms_log(mac_ctx, LOGW, + FL("FW still in connected state")); + break; + } + break; + case eCsrForcedIbssLeave: + csr_roam_call_callback(mac_ctx, session_id, NULL, + cmd->u.roamCmd.roamId, eCSR_ROAM_IBSS_LEAVE, + eCSR_ROAM_RESULT_IBSS_STOP); + session->connectState = eCSR_ASSOC_STATE_TYPE_IBSS_DISCONNECTED; + break; + case eCsrForcedDisassocMICFailure: + csr_roam_state_change(mac_ctx, eCSR_ROAMING_STATE_IDLE, + session_id); + + csr_roam_call_callback(mac_ctx, session_id, NULL, + cmd->u.roamCmd.roamId, eCSR_ROAM_DISASSOCIATED, + eCSR_ROAM_RESULT_MIC_FAILURE); +#ifndef WLAN_MDM_CODE_REDUCTION_OPT + sme_qos_csr_event_ind(mac_ctx, (uint8_t) session_id, + SME_QOS_CSR_DISCONNECT_REQ, NULL); +#endif + break; + case eCsrStopBss: + csr_roam_call_callback(mac_ctx, session_id, NULL, + cmd->u.roamCmd.roamId, eCSR_ROAM_INFRA_IND, + eCSR_ROAM_RESULT_INFRA_STOPPED); + break; + case eCsrForcedDisassocSta: + case eCsrForcedDeauthSta: + csr_roam_state_change(mac_ctx, eCSR_ROAMING_STATE_JOINED, + session_id); + session = CSR_GET_SESSION(mac_ctx, session_id); + if (CSR_IS_SESSION_VALID(mac_ctx, session_id) && + CSR_IS_INFRA_AP(&session->connectedProfile)) { + roam_info.u.pConnectedProfile = + &session->connectedProfile; + qdf_mem_copy(roam_info.peerMac.bytes, + cmd->u.roamCmd.peerMac, + sizeof(tSirMacAddr)); + roam_info.reasonCode = eCSR_ROAM_RESULT_FORCED; + roam_info.statusCode = eSIR_SME_SUCCESS; + status = csr_roam_call_callback(mac_ctx, session_id, + &roam_info, cmd->u.roamCmd.roamId, + eCSR_ROAM_LOSTLINK, + eCSR_ROAM_RESULT_FORCED); + } + break; + case eCsrLostLink1: + /* if lost link roam1 failed, then issue lost link Scan2 ... */ + csr_scan_request_lost_link2(mac_ctx, session_id); + break; + case eCsrLostLink2: + /* if lost link roam2 failed, then issue lost link scan3 ... */ + csr_scan_request_lost_link3(mac_ctx, session_id); + break; + case eCsrLostLink3: + default: + csr_roam_state_change(mac_ctx, + eCSR_ROAMING_STATE_IDLE, session_id); + + /* We are done with one round of lostlink roaming here */ + csr_scan_handle_failed_lostlink3(mac_ctx, session_id); + break; + } +} + +/** + * csr_roam_process_start_bss_success() - Process the result for start bss + * @mac_ctx: Global MAC Context + * @cmd: Command to be processed + * @context: Additional data in context of the cmd + * + * Return: None + */ +static void csr_roam_process_start_bss_success(tpAniSirGlobal mac_ctx, + tSmeCmd *cmd, void *context) +{ + uint32_t session_id = cmd->sessionId; + tCsrRoamProfile *profile = &cmd->u.roamCmd.roamProfile; + tCsrRoamSession *session; + tSirBssDescription *bss_desc = NULL; + tCsrRoamInfo roam_info; + tSirSmeStartBssRsp *start_bss_rsp = NULL; + tCsrScanResult *scan_res = NULL; + eRoamCmdStatus roam_status; + eCsrRoamResult roam_result; + tDot11fBeaconIEs *ies_ptr = NULL; + tSirMacAddr bcast_mac = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + QDF_STATUS status; + host_log_ibss_pkt_type *ibss_log; + uint32_t bi; +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH + tSirSmeHTProfile *src_profile = NULL; + tCsrRoamHTProfile *dst_profile = NULL; +#endif + + if (!CSR_IS_SESSION_VALID(mac_ctx, session_id)) { + sms_log(mac_ctx, LOGE, FL("Invalid session id %d"), session_id); + return; + } + session = CSR_GET_SESSION(mac_ctx, session_id); + + /* + * on the StartBss Response, LIM is returning the Bss Description that + * we are beaconing. Add this Bss Description to our scan results and + * chain the Profile to this Bss Description. On a Start BSS, there was + * no detected Bss description (no partner) so we issued the Start Bss + * to start the Ibss without any Bss description. Lim was kind enough + * to return the Bss Description that we start beaconing for the newly + * started Ibss. + */ + sms_log(mac_ctx, LOG2, FL("receives start BSS ok indication")); + status = QDF_STATUS_E_FAILURE; + start_bss_rsp = (tSirSmeStartBssRsp *) context; + qdf_mem_set(&roam_info, sizeof(tCsrRoamInfo), 0); + if (CSR_IS_IBSS(profile)) + session->connectState = eCSR_ASSOC_STATE_TYPE_IBSS_DISCONNECTED; + else if (CSR_IS_INFRA_AP(profile)) + session->connectState = + eCSR_ASSOC_STATE_TYPE_INFRA_DISCONNECTED; + else if (CSR_IS_NDI(profile)) + session->connectState = eCSR_CONNECT_STATE_TYPE_NDI_STARTED; + else + session->connectState = eCSR_ASSOC_STATE_TYPE_WDS_DISCONNECTED; + + bss_desc = &start_bss_rsp->bssDescription; + if (CSR_IS_NDI(profile)) { + csr_roam_state_change(mac_ctx, eCSR_ROAMING_STATE_JOINED, + session_id); + csr_roam_save_ndi_connected_info(mac_ctx, session_id, profile, + bss_desc); + roam_info.u.pConnectedProfile = &session->connectedProfile; + qdf_mem_copy(&roam_info.bssid, &bss_desc->bssId, + sizeof(struct qdf_mac_addr)); + } else { + csr_roam_state_change(mac_ctx, eCSR_ROAMING_STATE_JOINED, + session_id); + if (!QDF_IS_STATUS_SUCCESS + (csr_get_parsed_bss_description_ies(mac_ctx, bss_desc, + &ies_ptr))) { + sms_log(mac_ctx, LOGW, FL("cannot parse IBSS IEs")); + roam_info.pBssDesc = bss_desc; + csr_roam_call_callback(mac_ctx, session_id, &roam_info, + cmd->u.roamCmd.roamId, eCSR_ROAM_IBSS_IND, + eCSR_ROAM_RESULT_IBSS_START_FAILED); + return; + } + } + if (!CSR_IS_INFRA_AP(profile)) { + scan_res = + csr_scan_append_bss_description(mac_ctx, + bss_desc, ies_ptr, + session_id); + } + csr_roam_save_connected_bss_desc(mac_ctx, session_id, bss_desc); + csr_roam_free_connect_profile(&session->connectedProfile); + csr_roam_free_connected_info(mac_ctx, &session->connectedInfo); + csr_roam_save_connected_infomation(mac_ctx, session_id, + profile, bss_desc, ies_ptr); + qdf_mem_copy(&roam_info.bssid, &bss_desc->bssId, + sizeof(struct qdf_mac_addr)); + /* We are done with the IEs so free it */ + qdf_mem_free(ies_ptr); +#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR + WLAN_HOST_DIAG_LOG_ALLOC(ibss_log, + host_log_ibss_pkt_type, LOG_WLAN_IBSS_C); + if (ibss_log) { + if (CSR_INVALID_SCANRESULT_HANDLE == + cmd->u.roamCmd.hBSSList) { + /* + * We start the IBSS (didn't find any + * matched IBSS out there) + */ + ibss_log->eventId = + WLAN_IBSS_EVENT_START_IBSS_RSP; + } else { + ibss_log->eventId = + WLAN_IBSS_EVENT_JOIN_IBSS_RSP; + } + if (bss_desc) { + qdf_mem_copy(ibss_log->bssid.bytes, + bss_desc->bssId, QDF_MAC_ADDR_SIZE); + ibss_log->operatingChannel = + bss_desc->channelId; + } + if (IS_SIR_STATUS_SUCCESS(wlan_cfg_get_int( + mac_ctx, + WNI_CFG_BEACON_INTERVAL, + &bi))) + /* U8 is not enough for BI */ + ibss_log->beaconInterval = (uint8_t) bi; + WLAN_HOST_DIAG_LOG_REPORT(ibss_log); + } +#endif + /* + * Only set context for non-WDS_STA. We don't even need it for + * WDS_AP. But since the encryption. + * is WPA2-PSK so it won't matter. + */ + if (CSR_IS_ENC_TYPE_STATIC(profile->negotiatedUCEncryptionType) + && session->pCurRoamProfile + && !CSR_IS_INFRA_AP(session->pCurRoamProfile)) { + /* + * Issue the set Context request to LIM to establish + * the Broadcast STA context for the Ibss. In Rome IBSS + * case, dummy key installation will break proper BSS + * key installation, so skip it. + */ + if (!CSR_IS_IBSS(session->pCurRoamProfile)) { + /* NO keys. these key parameters don't matter */ + csr_roam_issue_set_context_req(mac_ctx, + session_id, + profile->negotiatedMCEncryptionType, + bss_desc, &bcast_mac, false, + false, eSIR_TX_RX, 0, 0, NULL, 0); + } + } + /* + * Only tell upper layer is we start the BSS because Vista doesn't like + * multiple connection indications. If we don't start the BSS ourself, + * handler of eSIR_SME_JOINED_NEW_BSS will trigger the connection start + * indication in Vista + */ + if (!CSR_IS_JOIN_TO_IBSS(profile)) { + roam_status = eCSR_ROAM_IBSS_IND; + roam_result = eCSR_ROAM_RESULT_IBSS_STARTED; + if (CSR_IS_INFRA_AP(profile)) { + roam_status = eCSR_ROAM_INFRA_IND; + roam_result = eCSR_ROAM_RESULT_INFRA_STARTED; + } + roam_info.staId = (uint8_t) start_bss_rsp->staId; + if (CSR_IS_NDI(profile)) { + csr_roam_update_ndp_return_params(mac_ctx, + eCsrStartBssSuccess, + &roam_status, + &roam_result, + &roam_info); + } + /* + * Only tell upper layer is we start the BSS because Vista + * doesn't like multiple connection indications. If we don't + * start the BSS ourself, handler of eSIR_SME_JOINED_NEW_BSS + * will trigger the connection start indication in Vista + */ + roam_info.statusCode = session->joinFailStatusCode.statusCode; + roam_info.reasonCode = session->joinFailStatusCode.reasonCode; + /* We start the IBSS (didn't find any matched IBSS out there) */ + roam_info.pBssDesc = bss_desc; + if (bss_desc) + qdf_mem_copy(roam_info.bssid.bytes, bss_desc->bssId, + sizeof(struct qdf_mac_addr)); + if (!IS_FEATURE_SUPPORTED_BY_FW(SLM_SESSIONIZATION) && + (csr_is_concurrent_session_running(mac_ctx))) { + mac_ctx->roam.configParam.doBMPSWorkaround = 1; + } +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH + dst_profile = &session->connectedProfile.HTProfile; + src_profile = &start_bss_rsp->HTProfile; + if (mac_ctx->roam.configParam.cc_switch_mode + != QDF_MCC_TO_SCC_SWITCH_DISABLE) + csr_roam_copy_ht_profile(dst_profile, src_profile); +#endif + csr_roam_call_callback(mac_ctx, session_id, &roam_info, + cmd->u.roamCmd.roamId, + roam_status, roam_result); + } + +} + +/** + * csr_roam_process_join_res() - Process the Join results + * @mac_ctx: Global MAC Context + * @result: Result after the command was processed + * @cmd: Command to be processed + * @context: Additional data in context of the cmd + * + * Process the join results which are obtained in a succesful join + * + * Return: None + */ +static void csr_roam_process_join_res(tpAniSirGlobal mac_ctx, + eCsrRoamCompleteResult res, tSmeCmd *cmd, void *context) +{ + tSirMacAddr bcast_mac = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + sme_QosAssocInfo assoc_info; + uint32_t key_timeout_interval = 0; + uint8_t acm_mask = 0; /* HDD needs ACM mask in assoc rsp callback */ + uint32_t session_id = cmd->sessionId; + tCsrRoamProfile *profile = &cmd->u.roamCmd.roamProfile; + tCsrRoamSession *session; + tSirBssDescription *bss_desc = NULL; + tCsrScanResult *scan_res = NULL; + sme_qos_csr_event_indType ind_qos; +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH + tSirSmeHTProfile *src_profile = NULL; + tCsrRoamHTProfile *dst_profile = NULL; +#endif + tCsrRoamConnectedProfile *conn_profile = NULL; + tDot11fBeaconIEs *ies_ptr = NULL; + tCsrRoamInfo roam_info; + struct ps_global_info *ps_global_info = &mac_ctx->sme.ps_global_info; + tSirSmeJoinRsp *join_rsp = (tSirSmeJoinRsp *) context; + uint32_t len; + + if (!CSR_IS_SESSION_VALID(mac_ctx, session_id)) { + sms_log(mac_ctx, LOGE, FL("Invalid session id %d"), session_id); + return; + } + session = CSR_GET_SESSION(mac_ctx, session_id); + + conn_profile = &session->connectedProfile; + if (eCsrReassocSuccess == res) { + roam_info.reassoc = true; + ind_qos = SME_QOS_CSR_REASSOC_COMPLETE; + } else { + roam_info.reassoc = false; + ind_qos = SME_QOS_CSR_ASSOC_COMPLETE; + } + sms_log(mac_ctx, LOGW, FL("receives association indication")); + qdf_mem_set(&roam_info, sizeof(roam_info), 0); + /* always free the memory here */ + if (session->pWpaRsnRspIE) { + session->nWpaRsnRspIeLength = 0; + qdf_mem_free(session->pWpaRsnRspIE); + session->pWpaRsnRspIE = NULL; + } +#ifdef FEATURE_WLAN_WAPI + if (session->pWapiRspIE) { + session->nWapiRspIeLength = 0; + qdf_mem_free(session->pWapiRspIE); + session->pWapiRspIE = NULL; + } +#endif /* FEATURE_WLAN_WAPI */ +#ifdef FEATURE_WLAN_BTAMP_UT_RF + session->maxRetryCount = 0; + csr_roam_stop_join_retry_timer(mac_ctx, session_id); +#endif + /* + * Reset remain_in_power_active_till_dhcp as + * it might have been set by last failed secured connection. + * It should be set only for secured connection. + */ + ps_global_info->remain_in_power_active_till_dhcp = false; + if (CSR_IS_INFRASTRUCTURE(profile)) + session->connectState = eCSR_ASSOC_STATE_TYPE_INFRA_ASSOCIATED; + else + session->connectState = eCSR_ASSOC_STATE_TYPE_WDS_CONNECTED; + /* + * Use the last connected bssdesc for reassoc-ing to the same AP. + * NOTE: What to do when reassoc to a different AP??? + */ + if ((eCsrHddIssuedReassocToSameAP == cmd->u.roamCmd.roamReason) + || (eCsrSmeIssuedReassocToSameAP == + cmd->u.roamCmd.roamReason)) { + bss_desc = session->pConnectBssDesc; + if (bss_desc) + qdf_mem_copy(&roam_info.bssid, &bss_desc->bssId, + sizeof(struct qdf_mac_addr)); + } else { + if (cmd->u.roamCmd.pRoamBssEntry) { + scan_res = GET_BASE_ADDR(cmd->u.roamCmd.pRoamBssEntry, + tCsrScanResult, Link); + if (scan_res != NULL) { + bss_desc = &scan_res->Result.BssDescriptor; + ies_ptr = (tDot11fBeaconIEs *) + (scan_res->Result.pvIes); + qdf_mem_copy(&roam_info.bssid, &bss_desc->bssId, + sizeof(struct qdf_mac_addr)); + } + } + } + if (bss_desc) { + roam_info.staId = STA_INVALID_IDX; + csr_roam_save_connected_infomation(mac_ctx, session_id, + profile, bss_desc, ies_ptr); + /* Save WPA/RSN IE */ + csr_roam_save_security_rsp_ie(mac_ctx, session_id, + profile->negotiatedAuthType, bss_desc, ies_ptr); +#ifdef FEATURE_WLAN_ESE + roam_info.isESEAssoc = conn_profile->isESEAssoc; +#endif + + /* + * csr_roam_state_change also affects sub-state. + * Hence, csr_roam_state_change happens first and then + * substate change. + * Moving even save profile above so that below + * mentioned conditon is also met. + * JEZ100225: Moved to after saving the profile. + * Fix needed in main/latest + */ + csr_roam_state_change(mac_ctx, + eCSR_ROAMING_STATE_JOINED, session_id); + + /* + * Make sure the Set Context is issued before link + * indication to NDIS. After link indication is + * made to NDIS, frames could start flowing. + * If we have not set context with LIM, the frames + * will be dropped for the security context may not + * be set properly. + * + * this was causing issues in the 2c_wlan_wep WHQL test + * when the SetContext was issued after the link + * indication. (Link Indication happens in the + * profFSMSetConnectedInfra call). + * + * this reordering was done on titan_prod_usb branch + * and is being replicated here. + */ + + if (CSR_IS_ENC_TYPE_STATIC + (profile->negotiatedUCEncryptionType) && + !profile->bWPSAssociation) { + /* + * Issue the set Context request to LIM to establish + * the Unicast STA context + */ + if (!QDF_IS_STATUS_SUCCESS( + csr_roam_issue_set_context_req(mac_ctx, + session_id, + profile->negotiatedUCEncryptionType, + bss_desc, &(bss_desc->bssId), + false, true, + eSIR_TX_RX, 0, 0, NULL, 0))) { + /* NO keys. these key parameters don't matter */ + sms_log(mac_ctx, LOGE, + FL("Set context for unicast fail")); + csr_roam_substate_change(mac_ctx, + eCSR_ROAM_SUBSTATE_NONE, session_id); + } + /* + * Issue the set Context request to LIM + * to establish the Broadcast STA context + * NO keys. these key parameters don't matter + */ + csr_roam_issue_set_context_req(mac_ctx, session_id, + profile->negotiatedMCEncryptionType, + bss_desc, &bcast_mac, false, false, + eSIR_TX_RX, 0, 0, NULL, 0); + } else { + /* Need to wait for supplicant authtication */ + roam_info.fAuthRequired = true; + /* + * Set the substate to WaitForKey in case + * authentiation is needed + */ + csr_roam_substate_change(mac_ctx, + eCSR_ROAM_SUBSTATE_WAIT_FOR_KEY, + session_id); + + /* + * Set remain_in_power_active_till_dhcp to make + * sure we wait for until keys are set before + * going into BMPS. + */ + ps_global_info->remain_in_power_active_till_dhcp + = true; + + if (profile->bWPSAssociation) + key_timeout_interval = + CSR_WAIT_FOR_WPS_KEY_TIMEOUT_PERIOD; + else + key_timeout_interval = + CSR_WAIT_FOR_KEY_TIMEOUT_PERIOD; + + /* Save session_id in case of timeout */ + mac_ctx->roam.WaitForKeyTimerInfo.sessionId = + (uint8_t) session_id; + /* + * This time should be long enough for the rest + * of the process plus setting key + */ + if (!QDF_IS_STATUS_SUCCESS + (csr_roam_start_wait_for_key_timer( + mac_ctx, key_timeout_interval)) + ) { + /* Reset state so nothing is blocked. */ + sms_log(mac_ctx, LOGE, FL + ("Failed preauth timer start")); + csr_roam_substate_change(mac_ctx, + eCSR_ROAM_SUBSTATE_NONE, + session_id); + } + } + + assoc_info.pBssDesc = bss_desc; /* could be NULL */ + assoc_info.pProfile = profile; + if (context) { +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + if (session->roam_synch_in_progress) + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_DEBUG, + FL("LFR3:Clear Connected info")); +#endif + csr_roam_free_connected_info(mac_ctx, + &session->connectedInfo); + len = join_rsp->assocReqLength + + join_rsp->assocRspLength + + join_rsp->beaconLength; + len += join_rsp->parsedRicRspLen; +#ifdef FEATURE_WLAN_ESE + len += join_rsp->tspecIeLen; +#endif + if (len) { + session->connectedInfo.pbFrames = + qdf_mem_malloc(len); + if (session->connectedInfo.pbFrames != + NULL) { + qdf_mem_copy( + session->connectedInfo.pbFrames, + join_rsp->frames, len); + session->connectedInfo.nAssocReqLength = + join_rsp->assocReqLength; + session->connectedInfo.nAssocRspLength = + join_rsp->assocRspLength; + session->connectedInfo.nBeaconLength = + join_rsp->beaconLength; + session->connectedInfo.nRICRspLength = + join_rsp->parsedRicRspLen; +#ifdef FEATURE_WLAN_ESE + session->connectedInfo.nTspecIeLength = + join_rsp->tspecIeLen; +#endif + roam_info.nAssocReqLength = + join_rsp->assocReqLength; + roam_info.nAssocRspLength = + join_rsp->assocRspLength; + roam_info.nBeaconLength = + join_rsp->beaconLength; + roam_info.pbFrames = + session->connectedInfo.pbFrames; + } + } + if (cmd->u.roamCmd.fReassoc) + roam_info.fReassocReq = + roam_info.fReassocRsp = true; + conn_profile->vht_channel_width = + join_rsp->vht_channel_width; + session->connectedInfo.staId = + (uint8_t) join_rsp->staId; + roam_info.staId = (uint8_t) join_rsp->staId; + roam_info.ucastSig = (uint8_t) join_rsp->ucastSig; + roam_info.bcastSig = (uint8_t) join_rsp->bcastSig; + roam_info.timingMeasCap = join_rsp->timingMeasCap; + roam_info.chan_info.nss = join_rsp->nss; + roam_info.chan_info.rate_flags = + join_rsp->max_rate_flags; +#ifdef FEATURE_WLAN_TDLS + roam_info.tdls_prohibited = join_rsp->tdls_prohibited; + roam_info.tdls_chan_swit_prohibited = + join_rsp->tdls_chan_swit_prohibited; + sms_log(mac_ctx, LOG1, + FL("tdls:prohibit: %d, chan_swit_prohibit: %d"), + roam_info.tdls_prohibited, + roam_info.tdls_chan_swit_prohibited); +#endif +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH + src_profile = &join_rsp->HTProfile; + dst_profile = &conn_profile->HTProfile; + if (mac_ctx->roam.configParam.cc_switch_mode + != QDF_MCC_TO_SCC_SWITCH_DISABLE) + csr_roam_copy_ht_profile(dst_profile, + src_profile); +#endif + roam_info.vht_caps = join_rsp->vht_caps; + roam_info.ht_caps = join_rsp->ht_caps; + roam_info.hs20vendor_ie = join_rsp->hs20vendor_ie; + roam_info.ht_operation = join_rsp->ht_operation; + roam_info.vht_operation = join_rsp->vht_operation; + } else { + if (cmd->u.roamCmd.fReassoc) { + roam_info.fReassocReq = + roam_info.fReassocRsp = true; + roam_info.nAssocReqLength = + session->connectedInfo.nAssocReqLength; + roam_info.nAssocRspLength = + session->connectedInfo.nAssocRspLength; + roam_info.nBeaconLength = + session->connectedInfo.nBeaconLength; + roam_info.pbFrames = + session->connectedInfo.pbFrames; + } + } + /* + * Update the staId from the previous connected profile info + * as the reassociation is triggred at SME/HDD + */ + + if ((eCsrHddIssuedReassocToSameAP == + cmd->u.roamCmd.roamReason) || + (eCsrSmeIssuedReassocToSameAP == + cmd->u.roamCmd.roamReason)) + roam_info.staId = session->connectedInfo.staId; + +#ifndef WLAN_MDM_CODE_REDUCTION_OPT + /* + * Indicate SME-QOS with reassoc success event, + * only after copying the frames + */ + sme_qos_csr_event_ind(mac_ctx, (uint8_t) session_id, ind_qos, + &assoc_info); +#endif + roam_info.pBssDesc = bss_desc; + roam_info.statusCode = + session->joinFailStatusCode.statusCode; + roam_info.reasonCode = + session->joinFailStatusCode.reasonCode; +#ifndef WLAN_MDM_CODE_REDUCTION_OPT + acm_mask = sme_qos_get_acm_mask(mac_ctx, bss_desc, NULL); +#endif + conn_profile->acm_mask = acm_mask; + /* + * start UAPSD if uapsd_mask is not 0 because HDD will + * configure for trigger frame It may be better to let QoS do + * this???? + */ + if (conn_profile->modifyProfileFields.uapsd_mask) { + sms_log(mac_ctx, LOGE, + " uapsd_mask (0x%X) set, request UAPSD now", + conn_profile->modifyProfileFields.uapsd_mask); + sme_ps_start_uapsd(mac_ctx, session_id, + NULL, NULL); + } + conn_profile->dot11Mode = session->bssParams.uCfgDot11Mode; + roam_info.u.pConnectedProfile = conn_profile; + + if (session->bRefAssocStartCnt > 0) { + session->bRefAssocStartCnt--; + if (!IS_FEATURE_SUPPORTED_BY_FW + (SLM_SESSIONIZATION) && + (csr_is_concurrent_session_running(mac_ctx))) { + mac_ctx->roam.configParam.doBMPSWorkaround = 1; + } + csr_roam_call_callback(mac_ctx, session_id, &roam_info, + cmd->u.roamCmd.roamId, + eCSR_ROAM_ASSOCIATION_COMPLETION, + eCSR_ROAM_RESULT_ASSOCIATED); + } + + csr_roam_completion(mac_ctx, session_id, NULL, cmd, + eCSR_ROAM_RESULT_NONE, true); + csr_reset_pmkid_candidate_list(mac_ctx, session_id); +#ifdef FEATURE_WLAN_WAPI + csr_reset_bkid_candidate_list(mac_ctx, session_id); +#endif + } else { + sms_log(mac_ctx, LOGW, + "Roam command doesn't have a BSS desc"); + } + /* Not to signal link up because keys are yet to be set. + * The linkup function will overwrite the sub-state that + * we need to keep at this point. + */ + if (!CSR_IS_WAIT_FOR_KEY(mac_ctx, session_id)) { +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + if (session->roam_synch_in_progress) { + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_DEBUG, + FL + ("NO CSR_IS_WAIT_FOR_KEY -> csr_roam_link_up")); + } +#endif + csr_roam_link_up(mac_ctx, conn_profile->bssid); + } +} + +/** + * csr_roam_process_results() - Process the Roam Results + * @mac_ctx: Global MAC Context + * @cmd: Command that has been processed + * @res: Results available after processing the command + * @context: Context + * + * Process the available results and make an appropriate decision + * + * Return: true if the command can be released, else not. + */ +static bool csr_roam_process_results(tpAniSirGlobal mac_ctx, tSmeCmd *cmd, + eCsrRoamCompleteResult res, void *context) +{ + bool release_cmd = true; + tSirBssDescription *bss_desc = NULL; + tCsrRoamInfo roam_info; + uint32_t session_id = cmd->sessionId; + tCsrRoamSession *session = CSR_GET_SESSION(mac_ctx, session_id); + tCsrRoamProfile *profile = &cmd->u.roamCmd.roamProfile; + eRoamCmdStatus roam_status; + eCsrRoamResult roam_result; + host_log_ibss_pkt_type *ibss_log; + tSirSmeStartBssRsp *start_bss_rsp = NULL; + + if (!session) { + sms_log(mac_ctx, LOGE, FL("session %d not found "), session_id); + return false; + } + sms_log(mac_ctx, LOG1, FL("Processing ROAM results...")); + switch (res) { + case eCsrJoinSuccess: + case eCsrReassocSuccess: + csr_roam_process_join_res(mac_ctx, res, cmd, context); + break; + case eCsrStartBssSuccess: + csr_roam_process_start_bss_success(mac_ctx, cmd, context); + break; + case eCsrStartBssFailure: +#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR + WLAN_HOST_DIAG_LOG_ALLOC(ibss_log, + host_log_ibss_pkt_type, LOG_WLAN_IBSS_C); + if (ibss_log) { + ibss_log->status = WLAN_IBSS_STATUS_FAILURE; + WLAN_HOST_DIAG_LOG_REPORT(ibss_log); + } +#endif + start_bss_rsp = (tSirSmeStartBssRsp *)context; + qdf_mem_set(&roam_info, sizeof(roam_info), 0); + roam_status = eCSR_ROAM_IBSS_IND; + roam_result = eCSR_ROAM_RESULT_IBSS_STARTED; + if (CSR_IS_INFRA_AP(profile)) { + roam_status = eCSR_ROAM_INFRA_IND; + roam_result = eCSR_ROAM_RESULT_INFRA_START_FAILED; + } + if (CSR_IS_NDI(profile)) { + csr_roam_update_ndp_return_params(mac_ctx, + eCsrStartBssFailure, + &roam_status, &roam_result, &roam_info); + } + + if (context) { + bss_desc = (tSirBssDescription *) context; + } else { + bss_desc = NULL; + } + roam_info.pBssDesc = bss_desc; + csr_roam_call_callback(mac_ctx, session_id, &roam_info, + cmd->u.roamCmd.roamId, roam_status, + roam_result); + csr_set_default_dot11_mode(mac_ctx); + break; + case eCsrSilentlyStopRoaming: + /* + * We are here because we try to start the same IBSS. + * No message to PE. return the roaming state to Joined. + */ + sms_log(mac_ctx, LOGW, FL("receives silently stop roam ind")); + csr_roam_state_change(mac_ctx, eCSR_ROAMING_STATE_JOINED, + session_id); + csr_roam_substate_change(mac_ctx, eCSR_ROAM_SUBSTATE_NONE, + session_id); + qdf_mem_set(&roam_info, sizeof(tCsrRoamInfo), 0); + roam_info.pBssDesc = session->pConnectBssDesc; + if (roam_info.pBssDesc) + qdf_mem_copy(&roam_info.bssid, + &roam_info.pBssDesc->bssId, + sizeof(struct qdf_mac_addr)); + /* + * Since there is no change in the current state, simply pass + * back no result otherwise HDD may be mistakenly mark to + * disconnected state. + */ + csr_roam_call_callback(mac_ctx, session_id, &roam_info, + cmd->u.roamCmd.roamId, + eCSR_ROAM_IBSS_IND, eCSR_ROAM_RESULT_NONE); + break; + case eCsrSilentlyStopRoamingSaveState: + /* We are here because we try to connect to the same AP */ + /* No message to PE */ + sms_log(mac_ctx, LOGW, + FL("receives silently stop roaming indication")); + qdf_mem_set(&roam_info, sizeof(roam_info), 0); + + /* to aviod resetting the substate to NONE */ + mac_ctx->roam.curState[session_id] = eCSR_ROAMING_STATE_JOINED; + /* + * No need to change substate to wai_for_key because there + * is no state change + */ + roam_info.pBssDesc = session->pConnectBssDesc; + if (roam_info.pBssDesc) + qdf_mem_copy(&roam_info.bssid, + &roam_info.pBssDesc->bssId, + sizeof(struct qdf_mac_addr)); + roam_info.statusCode = session->joinFailStatusCode.statusCode; + roam_info.reasonCode = session->joinFailStatusCode.reasonCode; + roam_info.nBeaconLength = session->connectedInfo.nBeaconLength; + roam_info.nAssocReqLength = + session->connectedInfo.nAssocReqLength; + roam_info.nAssocRspLength = + session->connectedInfo.nAssocRspLength; + roam_info.pbFrames = session->connectedInfo.pbFrames; + roam_info.staId = session->connectedInfo.staId; + roam_info.u.pConnectedProfile = &session->connectedProfile; + if (0 == roam_info.staId) + QDF_ASSERT(0); + + session->bRefAssocStartCnt--; + csr_roam_call_callback(mac_ctx, session_id, &roam_info, + cmd->u.roamCmd.roamId, + eCSR_ROAM_ASSOCIATION_COMPLETION, + eCSR_ROAM_RESULT_ASSOCIATED); + csr_roam_completion(mac_ctx, session_id, NULL, cmd, + eCSR_ROAM_RESULT_ASSOCIATED, true); + break; + case eCsrReassocFailure: + /* + * Currently Reassoc failure is handled through eCsrJoinFailure + * Need to revisit for eCsrReassocFailure handling + */ +#ifndef WLAN_MDM_CODE_REDUCTION_OPT + sme_qos_csr_event_ind(mac_ctx, (uint8_t) session_id, + SME_QOS_CSR_REASSOC_FAILURE, NULL); +#endif + break; + case eCsrStopBssSuccess: + if (CSR_IS_NDI(profile)) { + csr_roam_update_ndp_return_params(mac_ctx, res, + &roam_status, &roam_result, &roam_info); + csr_roam_call_callback(mac_ctx, session_id, &roam_info, + cmd->u.roamCmd.roamId, + roam_status, roam_result); + } + break; + case eCsrStopBssFailure: + if (CSR_IS_NDI(profile)) { + csr_roam_update_ndp_return_params(mac_ctx, res, + &roam_status, &roam_result, &roam_info); + csr_roam_call_callback(mac_ctx, session_id, &roam_info, + cmd->u.roamCmd.roamId, + roam_status, roam_result); + } + break; + case eCsrJoinFailure: + case eCsrNothingToJoin: + case eCsrJoinFailureDueToConcurrency: + default: + csr_roam_process_results_default(mac_ctx, cmd, context, res); + break; + } + return release_cmd; +} + +QDF_STATUS csr_roam_copy_profile(tpAniSirGlobal pMac, + tCsrRoamProfile *pDstProfile, + tCsrRoamProfile *pSrcProfile) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + uint32_t size = 0; + + qdf_mem_set(pDstProfile, sizeof(tCsrRoamProfile), 0); + if (pSrcProfile->BSSIDs.numOfBSSIDs) { + size = sizeof(struct qdf_mac_addr) * pSrcProfile->BSSIDs.numOfBSSIDs; + pDstProfile->BSSIDs.bssid = qdf_mem_malloc(size); + if (NULL == pDstProfile->BSSIDs.bssid) { + status = QDF_STATUS_E_NOMEM; + goto end; + } + pDstProfile->BSSIDs.numOfBSSIDs = + pSrcProfile->BSSIDs.numOfBSSIDs; + qdf_mem_copy(pDstProfile->BSSIDs.bssid, + pSrcProfile->BSSIDs.bssid, size); + } + if (pSrcProfile->SSIDs.numOfSSIDs) { + size = sizeof(tCsrSSIDInfo) * pSrcProfile->SSIDs.numOfSSIDs; + pDstProfile->SSIDs.SSIDList = qdf_mem_malloc(size); + if (NULL == pDstProfile->SSIDs.SSIDList) { + status = QDF_STATUS_E_NOMEM; + goto end; + } + pDstProfile->SSIDs.numOfSSIDs = + pSrcProfile->SSIDs.numOfSSIDs; + qdf_mem_copy(pDstProfile->SSIDs.SSIDList, + pSrcProfile->SSIDs.SSIDList, size); + } + if (pSrcProfile->nWPAReqIELength) { + pDstProfile->pWPAReqIE = + qdf_mem_malloc(pSrcProfile->nWPAReqIELength); + if (NULL == pDstProfile->pWPAReqIE) { + status = QDF_STATUS_E_NOMEM; + goto end; + } + pDstProfile->nWPAReqIELength = + pSrcProfile->nWPAReqIELength; + qdf_mem_copy(pDstProfile->pWPAReqIE, pSrcProfile->pWPAReqIE, + pSrcProfile->nWPAReqIELength); + } + if (pSrcProfile->nRSNReqIELength) { + pDstProfile->pRSNReqIE = + qdf_mem_malloc(pSrcProfile->nRSNReqIELength); + if (NULL == pDstProfile->pRSNReqIE) { + status = QDF_STATUS_E_NOMEM; + goto end; + } + pDstProfile->nRSNReqIELength = + pSrcProfile->nRSNReqIELength; + qdf_mem_copy(pDstProfile->pRSNReqIE, pSrcProfile->pRSNReqIE, + pSrcProfile->nRSNReqIELength); + } +#ifdef FEATURE_WLAN_WAPI + if (pSrcProfile->nWAPIReqIELength) { + pDstProfile->pWAPIReqIE = + qdf_mem_malloc(pSrcProfile->nWAPIReqIELength); + if (NULL == pDstProfile->pWAPIReqIE) { + status = QDF_STATUS_E_NOMEM; + goto end; + } + pDstProfile->nWAPIReqIELength = + pSrcProfile->nWAPIReqIELength; + qdf_mem_copy(pDstProfile->pWAPIReqIE, pSrcProfile->pWAPIReqIE, + pSrcProfile->nWAPIReqIELength); + } +#endif /* FEATURE_WLAN_WAPI */ + if (pSrcProfile->nAddIEScanLength) { + pDstProfile->pAddIEScan = + qdf_mem_malloc(pSrcProfile->nAddIEScanLength); + if (NULL == pDstProfile->pAddIEScan) { + status = QDF_STATUS_E_NOMEM; + goto end; + } + pDstProfile->nAddIEScanLength = + pSrcProfile->nAddIEScanLength; + qdf_mem_copy(pDstProfile->pAddIEScan, pSrcProfile->pAddIEScan, + pSrcProfile->nAddIEScanLength); + } + if (pSrcProfile->nAddIEAssocLength) { + pDstProfile->pAddIEAssoc = + qdf_mem_malloc(pSrcProfile->nAddIEAssocLength); + if (NULL == pDstProfile->pAddIEAssoc) { + status = QDF_STATUS_E_NOMEM; + goto end; + } + pDstProfile->nAddIEAssocLength = + pSrcProfile->nAddIEAssocLength; + qdf_mem_copy(pDstProfile->pAddIEAssoc, pSrcProfile->pAddIEAssoc, + pSrcProfile->nAddIEAssocLength); + } + if (pSrcProfile->ChannelInfo.ChannelList) { + pDstProfile->ChannelInfo.ChannelList = + qdf_mem_malloc(pSrcProfile->ChannelInfo. + numOfChannels); + if (NULL == pDstProfile->ChannelInfo.ChannelList) { + status = QDF_STATUS_E_NOMEM; + goto end; + } + pDstProfile->ChannelInfo.numOfChannels = + pSrcProfile->ChannelInfo.numOfChannels; + qdf_mem_copy(pDstProfile->ChannelInfo.ChannelList, + pSrcProfile->ChannelInfo.ChannelList, + pSrcProfile->ChannelInfo.numOfChannels); + } + pDstProfile->AuthType = pSrcProfile->AuthType; + pDstProfile->EncryptionType = pSrcProfile->EncryptionType; + pDstProfile->mcEncryptionType = pSrcProfile->mcEncryptionType; + pDstProfile->negotiatedUCEncryptionType = + pSrcProfile->negotiatedUCEncryptionType; + pDstProfile->negotiatedMCEncryptionType = + pSrcProfile->negotiatedMCEncryptionType; + pDstProfile->negotiatedAuthType = pSrcProfile->negotiatedAuthType; +#ifdef WLAN_FEATURE_11W + pDstProfile->MFPEnabled = pSrcProfile->MFPEnabled; + pDstProfile->MFPRequired = pSrcProfile->MFPRequired; + pDstProfile->MFPCapable = pSrcProfile->MFPCapable; +#endif + pDstProfile->BSSType = pSrcProfile->BSSType; + pDstProfile->phyMode = pSrcProfile->phyMode; + pDstProfile->csrPersona = pSrcProfile->csrPersona; + +#ifdef FEATURE_WLAN_WAPI + if (csr_is_profile_wapi(pSrcProfile)) + if (pDstProfile->phyMode & eCSR_DOT11_MODE_11n) + pDstProfile->phyMode &= ~eCSR_DOT11_MODE_11n; +#endif /* FEATURE_WLAN_WAPI */ + pDstProfile->CBMode = pSrcProfile->CBMode; + pDstProfile->ch_params.ch_width = pSrcProfile->ch_params.ch_width; + pDstProfile->ch_params.center_freq_seg0 = + pSrcProfile->ch_params.center_freq_seg0; + pDstProfile->ch_params.center_freq_seg1 = + pSrcProfile->ch_params.center_freq_seg1; + pDstProfile->ch_params.sec_ch_offset = + pSrcProfile->ch_params.sec_ch_offset; + /*Save the WPS info */ + pDstProfile->bWPSAssociation = pSrcProfile->bWPSAssociation; + pDstProfile->bOSENAssociation = pSrcProfile->bOSENAssociation; + pDstProfile->uapsd_mask = pSrcProfile->uapsd_mask; + pDstProfile->beaconInterval = pSrcProfile->beaconInterval; + pDstProfile->privacy = pSrcProfile->privacy; + pDstProfile->fwdWPSPBCProbeReq = pSrcProfile->fwdWPSPBCProbeReq; + pDstProfile->csr80211AuthType = pSrcProfile->csr80211AuthType; + pDstProfile->dtimPeriod = pSrcProfile->dtimPeriod; + pDstProfile->ApUapsdEnable = pSrcProfile->ApUapsdEnable; + pDstProfile->SSIDs.SSIDList[0].ssidHidden = + pSrcProfile->SSIDs.SSIDList[0].ssidHidden; + pDstProfile->protEnabled = pSrcProfile->protEnabled; + pDstProfile->obssProtEnabled = pSrcProfile->obssProtEnabled; + pDstProfile->cfg_protection = pSrcProfile->cfg_protection; + pDstProfile->wps_state = pSrcProfile->wps_state; + pDstProfile->ieee80211d = pSrcProfile->ieee80211d; + pDstProfile->sap_dot11mc = pSrcProfile->sap_dot11mc; + pDstProfile->do_not_roam = pSrcProfile->do_not_roam; + qdf_mem_copy(&pDstProfile->Keys, &pSrcProfile->Keys, + sizeof(pDstProfile->Keys)); +#ifdef WLAN_FEATURE_11W + pDstProfile->MFPEnabled = pSrcProfile->MFPEnabled; + pDstProfile->MFPRequired = pSrcProfile->MFPRequired; + pDstProfile->MFPCapable = pSrcProfile->MFPCapable; +#endif + if (pSrcProfile->MDID.mdiePresent) { + pDstProfile->MDID.mdiePresent = 1; + pDstProfile->MDID.mobilityDomain = + pSrcProfile->MDID.mobilityDomain; + } + qdf_mem_copy(&pDstProfile->addIeParams, &pSrcProfile->addIeParams, + sizeof(tSirAddIeParams)); + if (pSrcProfile->supported_rates.numRates) { + qdf_mem_copy(pDstProfile->supported_rates.rate, + pSrcProfile->supported_rates.rate, + pSrcProfile->supported_rates.numRates); + pDstProfile->supported_rates.numRates = + pSrcProfile->supported_rates.numRates; + } + if (pSrcProfile->extended_rates.numRates) { + qdf_mem_copy(pDstProfile->extended_rates.rate, + pSrcProfile->extended_rates.rate, + pSrcProfile->extended_rates.numRates); + pDstProfile->extended_rates.numRates = + pSrcProfile->extended_rates.numRates; + } +end: + if (!QDF_IS_STATUS_SUCCESS(status)) { + csr_release_profile(pMac, pDstProfile); + pDstProfile = NULL; + } + + return status; +} + +QDF_STATUS csr_roam_copy_connected_profile(tpAniSirGlobal pMac, + uint32_t sessionId, tCsrRoamProfile *pDstProfile) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tCsrRoamConnectedProfile *pSrcProfile = + &pMac->roam.roamSession[sessionId].connectedProfile; + + qdf_mem_set(pDstProfile, sizeof(tCsrRoamProfile), 0); + + pDstProfile->BSSIDs.bssid = qdf_mem_malloc(sizeof(struct qdf_mac_addr)); + if (NULL == pDstProfile->BSSIDs.bssid) { + status = QDF_STATUS_E_NOMEM; + sms_log(pMac, LOGE, + FL("failed to allocate memory for BSSID " + MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(pSrcProfile->bssid.bytes)); + goto end; + } + pDstProfile->BSSIDs.numOfBSSIDs = 1; + qdf_copy_macaddr(pDstProfile->BSSIDs.bssid, &pSrcProfile->bssid); + + if (pSrcProfile->SSID.length > 0) { + pDstProfile->SSIDs.SSIDList = + qdf_mem_malloc(sizeof(tCsrSSIDInfo)); + if (NULL == pDstProfile->SSIDs.SSIDList) { + status = QDF_STATUS_E_NOMEM; + sms_log(pMac, LOGE, + FL("failed to allocate memory for SSID " + MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(pSrcProfile->bssid.bytes)); + goto end; + } + pDstProfile->SSIDs.numOfSSIDs = 1; + pDstProfile->SSIDs.SSIDList[0].handoffPermitted = + pSrcProfile->handoffPermitted; + pDstProfile->SSIDs.SSIDList[0].ssidHidden = + pSrcProfile->ssidHidden; + qdf_mem_copy(&pDstProfile->SSIDs.SSIDList[0].SSID, + &pSrcProfile->SSID, sizeof(tSirMacSSid)); + } + if (pSrcProfile->nAddIEAssocLength) { + pDstProfile->pAddIEAssoc = + qdf_mem_malloc(pSrcProfile->nAddIEAssocLength); + if (NULL == pDstProfile->pAddIEAssoc) { + status = QDF_STATUS_E_NOMEM; + sms_log(pMac, LOGE, + FL("failed to allocate mem for additional ie")); + goto end; + } + pDstProfile->nAddIEAssocLength = pSrcProfile->nAddIEAssocLength; + qdf_mem_copy(pDstProfile->pAddIEAssoc, pSrcProfile->pAddIEAssoc, + pSrcProfile->nAddIEAssocLength); + } + pDstProfile->ChannelInfo.ChannelList = qdf_mem_malloc(1); + if (NULL == pDstProfile->ChannelInfo.ChannelList) { + status = QDF_STATUS_E_NOMEM; + goto end; + } + pDstProfile->ChannelInfo.numOfChannels = 1; + pDstProfile->ChannelInfo.ChannelList[0] = pSrcProfile->operationChannel; + pDstProfile->AuthType.numEntries = 1; + pDstProfile->AuthType.authType[0] = pSrcProfile->AuthType; + pDstProfile->negotiatedAuthType = pSrcProfile->AuthType; + pDstProfile->EncryptionType.numEntries = 1; + pDstProfile->EncryptionType.encryptionType[0] = + pSrcProfile->EncryptionType; + pDstProfile->negotiatedUCEncryptionType = + pSrcProfile->EncryptionType; + pDstProfile->mcEncryptionType.numEntries = 1; + pDstProfile->mcEncryptionType.encryptionType[0] = + pSrcProfile->mcEncryptionType; + pDstProfile->negotiatedMCEncryptionType = + pSrcProfile->mcEncryptionType; + pDstProfile->BSSType = pSrcProfile->BSSType; + pDstProfile->CBMode = pSrcProfile->CBMode; + qdf_mem_copy(&pDstProfile->Keys, &pSrcProfile->Keys, + sizeof(pDstProfile->Keys)); + if (pSrcProfile->MDID.mdiePresent) { + pDstProfile->MDID.mdiePresent = 1; + pDstProfile->MDID.mobilityDomain = + pSrcProfile->MDID.mobilityDomain; + } +#ifdef WLAN_FEATURE_11W + pDstProfile->MFPEnabled = pSrcProfile->MFPEnabled; + pDstProfile->MFPRequired = pSrcProfile->MFPRequired; + pDstProfile->MFPCapable = pSrcProfile->MFPCapable; +#endif + +end: + if (!QDF_IS_STATUS_SUCCESS(status)) { + csr_release_profile(pMac, pDstProfile); + pDstProfile = NULL; + } + + return status; +} + +QDF_STATUS csr_roam_issue_connect(tpAniSirGlobal pMac, uint32_t sessionId, + tCsrRoamProfile *pProfile, + tScanResultHandle hBSSList, + eCsrRoamReason reason, uint32_t roamId, + bool fImediate, bool fClearScan) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tSmeCmd *pCommand; + + pCommand = csr_get_command_buffer(pMac); + if (NULL == pCommand) { + sms_log(pMac, LOGE, FL(" fail to get command buffer")); + status = QDF_STATUS_E_RESOURCES; + } else { + if (fClearScan) { + csr_scan_abort_mac_scan_not_for_connect(pMac, sessionId); + } + pCommand->u.roamCmd.fReleaseProfile = false; + if (NULL == pProfile) { + /* We can roam now */ + /* Since pProfile is NULL, we need to build our own profile, set everything to default */ + /* We can only support open and no encryption */ + pCommand->u.roamCmd.roamProfile.AuthType.numEntries = 1; + pCommand->u.roamCmd.roamProfile.AuthType.authType[0] = + eCSR_AUTH_TYPE_OPEN_SYSTEM; + pCommand->u.roamCmd.roamProfile.EncryptionType. + numEntries = 1; + pCommand->u.roamCmd.roamProfile.EncryptionType. + encryptionType[0] = eCSR_ENCRYPT_TYPE_NONE; + pCommand->u.roamCmd.roamProfile.csrPersona = + QDF_STA_MODE; + } else { + /* make a copy of the profile */ + status = + csr_roam_copy_profile(pMac, + &pCommand->u.roamCmd.roamProfile, + pProfile); + if (QDF_IS_STATUS_SUCCESS(status)) { + pCommand->u.roamCmd.fReleaseProfile = true; + } + } + + pCommand->command = eSmeCommandRoam; + pCommand->sessionId = (uint8_t) sessionId; + pCommand->u.roamCmd.hBSSList = hBSSList; + pCommand->u.roamCmd.roamId = roamId; + pCommand->u.roamCmd.roamReason = reason; + /* We need to free the BssList when the command is done */ + pCommand->u.roamCmd.fReleaseBssList = true; + pCommand->u.roamCmd.fUpdateCurRoamProfile = true; + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO, + FL("CSR PERSONA=%d"), + pCommand->u.roamCmd.roamProfile.csrPersona); + status = csr_queue_sme_command(pMac, pCommand, fImediate); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOGE, + FL(" fail to send message status = %d"), status); + csr_release_command_roam(pMac, pCommand); + } + } + + return status; +} + +QDF_STATUS csr_roam_issue_reassoc(tpAniSirGlobal pMac, uint32_t sessionId, + tCsrRoamProfile *pProfile, + tCsrRoamModifyProfileFields *pMmodProfileFields, + eCsrRoamReason reason, uint32_t roamId, + bool fImediate) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tSmeCmd *pCommand; + + pCommand = csr_get_command_buffer(pMac); + if (NULL == pCommand) { + sms_log(pMac, LOGE, FL(" fail to get command buffer")); + status = QDF_STATUS_E_RESOURCES; + } else { + csr_scan_abort_mac_scan_not_for_connect(pMac, sessionId); + if (pProfile) { + /* This is likely trying to reassoc to different profile */ + pCommand->u.roamCmd.fReleaseProfile = false; + /* make a copy of the profile */ + status = + csr_roam_copy_profile(pMac, + &pCommand->u.roamCmd.roamProfile, + pProfile); + pCommand->u.roamCmd.fUpdateCurRoamProfile = true; + } else { + status = + csr_roam_copy_connected_profile(pMac, sessionId, + &pCommand->u.roamCmd. + roamProfile); + /* how to update WPA/WPA2 info in roamProfile?? */ + pCommand->u.roamCmd.roamProfile.uapsd_mask = + pMmodProfileFields->uapsd_mask; + } + if (QDF_IS_STATUS_SUCCESS(status)) { + pCommand->u.roamCmd.fReleaseProfile = true; + } + pCommand->command = eSmeCommandRoam; + pCommand->sessionId = (uint8_t) sessionId; + pCommand->u.roamCmd.roamId = roamId; + pCommand->u.roamCmd.roamReason = reason; + /* We need to free the BssList when the command is done */ + /* For reassoc there is no BSS list, so the bool set to false */ + pCommand->u.roamCmd.hBSSList = CSR_INVALID_SCANRESULT_HANDLE; + pCommand->u.roamCmd.fReleaseBssList = false; + pCommand->u.roamCmd.fReassoc = true; + csr_roam_remove_duplicate_command(pMac, sessionId, pCommand, + reason); + status = csr_queue_sme_command(pMac, pCommand, fImediate); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOGE, + FL(" fail to send message status = %d"), status); + csr_roam_completion(pMac, sessionId, NULL, pCommand, + eCSR_ROAM_RESULT_FAILURE, false); + csr_release_command_roam(pMac, pCommand); + } + } + return status; +} + +QDF_STATUS csr_dequeue_roam_command(tpAniSirGlobal pMac, eCsrRoamReason reason) +{ + tListElem *pEntry; + tSmeCmd *pCommand; + pEntry = csr_ll_peek_head(&pMac->sme.smeCmdActiveList, LL_ACCESS_LOCK); + if (pEntry) { + pCommand = GET_BASE_ADDR(pEntry, tSmeCmd, Link); + if ((eSmeCommandRoam == pCommand->command) && + (eCsrPerformPreauth == reason)) { + sms_log(pMac, LOG1, FL("DQ-Command = %d, Reason = %d"), + pCommand->command, + pCommand->u.roamCmd.roamReason); + if (csr_ll_remove_entry + (&pMac->sme.smeCmdActiveList, pEntry, + LL_ACCESS_LOCK)) { + csr_release_command_preauth(pMac, pCommand); + } + } else if ((eSmeCommandRoam == pCommand->command) && + (eCsrSmeIssuedFTReassoc == reason)) { + sms_log(pMac, LOG1, FL("DQ-Command = %d, Reason = %d"), + pCommand->command, + pCommand->u.roamCmd.roamReason); + if (csr_ll_remove_entry + (&pMac->sme.smeCmdActiveList, pEntry, + LL_ACCESS_LOCK)) { + csr_release_command_roam(pMac, pCommand); + } + } else { + sms_log(pMac, LOGE, FL("Command = %d, Reason = %d "), + pCommand->command, + pCommand->u.roamCmd.roamReason); + } + } else { + sms_log(pMac, LOGE, + FL("pEntry NULL for eWNI_SME_FT_PRE_AUTH_RSP")); + } + sme_process_pending_queue(pMac); + return QDF_STATUS_SUCCESS; +} + +/** + * csr_roam_print_candidate_aps() - print all candidate AP in sorted + * score. + * @pMac: global mac context + * @hScanList: Handle for scan list + * + * Return : void + */ +static void csr_roam_print_candidate_aps(tpAniSirGlobal pMac, + tScanResultHandle hScanList) +{ + tListElem *pEntry; + tCsrScanResult *pBssDesc = NULL; + tScanResultList *bss_list = NULL; + + bss_list = (tScanResultList *)hScanList; + pEntry = csr_ll_peek_head(&bss_list->List, LL_ACCESS_NOLOCK); + while (pEntry) { + pBssDesc = GET_BASE_ADDR(pEntry, + tCsrScanResult, Link); + sms_log(pMac, LOG1, FL("BSSID "MAC_ADDRESS_STR" score is %d"), + MAC_ADDR_ARRAY(pBssDesc->Result.BssDescriptor.bssId), + pBssDesc->bss_score); + + pEntry = csr_ll_next(&bss_list->List, pEntry, + LL_ACCESS_NOLOCK); + } + return; + +} + +QDF_STATUS csr_roam_connect(tpAniSirGlobal pMac, uint32_t sessionId, + tCsrRoamProfile *pProfile, + uint32_t *pRoamId) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tScanResultHandle hBSSList; + tCsrScanResultFilter *pScanFilter; + uint32_t roamId = 0; + bool fCallCallback = false; + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + tSirBssDescription *first_ap_profile; + + if (NULL == pSession) { + sms_log(pMac, LOGE, + FL("session does not exist for given sessionId:%d"), + sessionId); + return QDF_STATUS_E_FAILURE; + } + + if (NULL == pProfile) { + sms_log(pMac, LOGP, FL("No profile specified")); + return QDF_STATUS_E_FAILURE; + } + + first_ap_profile = qdf_mem_malloc(sizeof(*first_ap_profile)); + if (NULL == first_ap_profile) { + sme_err("malloc fails for first_ap_profile"); + return QDF_STATUS_E_NOMEM; + } + + /* Initialize the count before proceeding with the Join requests */ + pSession->join_bssid_count = 0; + sms_log(pMac, LOG1, + FL("called BSSType = %s (%d) authtype = %d encryType = %d"), + sme_bss_type_to_string(pProfile->BSSType), + pProfile->BSSType, pProfile->AuthType.authType[0], + pProfile->EncryptionType.encryptionType[0]); + csr_roam_cancel_roaming(pMac, sessionId); + csr_scan_remove_fresh_scan_command(pMac, sessionId); + csr_scan_abort_all_scans(pMac, eCSR_SCAN_ABORT_DEFAULT); + csr_roam_remove_duplicate_command(pMac, sessionId, NULL, eCsrHddIssued); + /* Check whether ssid changes */ + if (csr_is_conn_state_connected(pMac, sessionId) && + pProfile->SSIDs.numOfSSIDs && !csr_is_ssid_in_list(pMac, + &pSession->connectedProfile.SSID, &pProfile->SSIDs)) + csr_roam_issue_disassociate_cmd(pMac, sessionId, + eCSR_DISCONNECT_REASON_UNSPECIFIED); + /* + * If roamSession.connectState is disconnecting that mean + * disconnect was received with scan for ssid in progress + * and dropped. This state will ensure that connect will + * not be issued from scan for ssid completion. Thus + * if this fresh connect also issue scan for ssid the connect + * command will be dropped assuming disconnect is in progress. + * Thus reset connectState here + */ + if (eCSR_ASSOC_STATE_TYPE_INFRA_DISCONNECTING == + pMac->roam.roamSession[sessionId].connectState) + pMac->roam.roamSession[sessionId].connectState = + eCSR_ASSOC_STATE_TYPE_NOT_CONNECTED; +#ifdef FEATURE_WLAN_BTAMP_UT_RF + pSession->maxRetryCount = CSR_JOIN_MAX_RETRY_COUNT; +#endif + pScanFilter = qdf_mem_malloc(sizeof(tCsrScanResultFilter)); + if (NULL == pScanFilter) { + status = QDF_STATUS_E_NOMEM; + goto end; + } + + /* Try to connect to any BSS */ + if (NULL == pProfile) { + /* No encryption */ + pScanFilter->EncryptionType.numEntries = 1; + pScanFilter->EncryptionType.encryptionType[0] = + eCSR_ENCRYPT_TYPE_NONE; + } else { + /* Here is the profile we need to connect to */ + status = csr_roam_prepare_filter_from_profile(pMac, + pProfile, pScanFilter); + } + roamId = GET_NEXT_ROAM_ID(&pMac->roam); + if (pRoamId) + *pRoamId = roamId; + if (!QDF_IS_STATUS_SUCCESS(status)) { + qdf_mem_free(pScanFilter); + goto end; + } + + /*Save the WPS info */ + if (NULL != pProfile) { + pScanFilter->bWPSAssociation = + pProfile->bWPSAssociation; + pScanFilter->bOSENAssociation = + pProfile->bOSENAssociation; + } else { + pScanFilter->bWPSAssociation = 0; + pScanFilter->bOSENAssociation = 0; + } + if (pProfile && CSR_IS_INFRA_AP(pProfile)) { + /* This can be started right away */ + status = csr_roam_issue_connect(pMac, sessionId, pProfile, NULL, + eCsrHddIssued, roamId, false, false); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOGE, + FL("CSR failed to issue start BSS cmd with status = 0x%08X"), + status); + fCallCallback = true; + } else { + sms_log(pMac, LOG1, + FL("Connect request to proceed for sap mode")); + } + + csr_free_scan_filter(pMac, pScanFilter); + qdf_mem_free(pScanFilter); + goto end; + } + status = csr_scan_get_result(pMac, pScanFilter, &hBSSList); + sms_log(pMac, LOG1, + FL("******* csr_scan_get_result Status ****** %d"), status); + csr_roam_print_candidate_aps(pMac, hBSSList); + if (QDF_IS_STATUS_SUCCESS(status)) { + /* check if set hw mode needs to be done */ + if ((pScanFilter->csrPersona == QDF_STA_MODE) || + (pScanFilter->csrPersona == QDF_P2P_CLIENT_MODE)) { + csr_get_bssdescr_from_scan_handle(hBSSList, + first_ap_profile); + status = cds_handle_conc_multiport(sessionId, + first_ap_profile->channelId); + if ((QDF_IS_STATUS_SUCCESS(status)) && + (!csr_wait_for_connection_update(pMac, true))) { + sms_log(pMac, LOG1, + FL("conn update error")); + csr_scan_result_purge(pMac, hBSSList); + fCallCallback = true; + status = QDF_STATUS_E_TIMEOUT; + goto error; + } else if (status == QDF_STATUS_E_FAILURE) { + sms_log(pMac, LOG1, FL("conn update error")); + csr_scan_result_purge(pMac, hBSSList); + fCallCallback = true; + goto error; + } + } + + status = csr_roam_issue_connect(pMac, sessionId, pProfile, + hBSSList, eCsrHddIssued, roamId, false, false); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOGE, + FL("CSR failed to issue connect cmd with status = 0x%08X"), + status); + csr_scan_result_purge(pMac, hBSSList); + fCallCallback = true; + } + } else if (NULL != pProfile) { + /* Check whether it is for start ibss */ + if (CSR_IS_START_IBSS(pProfile) || + CSR_IS_NDI(pProfile)) { + status = csr_roam_issue_connect(pMac, sessionId, + pProfile, NULL, eCsrHddIssued, + roamId, false, false); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOGE, + FL("Failed with status = 0x%08X"), + status); + fCallCallback = true; + } + } else { + /* scan for this SSID */ + status = csr_scan_for_ssid(pMac, sessionId, pProfile, + roamId, true); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOGE, + FL("CSR failed to issue SSID scan cmd with status = 0x%08X"), + status); + fCallCallback = true; + } else { + sms_log(pMac, LOG1, + FL("SSID scan requested")); + } + } + } else { + fCallCallback = true; + } + +error: + if (NULL != pProfile) + /* + * we need to free memory for filter + * if profile exists + */ + csr_free_scan_filter(pMac, pScanFilter); + + qdf_mem_free(pScanFilter); +end: + /* tell the caller if we fail to trigger a join request */ + if (fCallCallback) { + csr_roam_call_callback(pMac, sessionId, NULL, roamId, + eCSR_ROAM_FAILED, eCSR_ROAM_RESULT_FAILURE); + } + qdf_mem_free(first_ap_profile); + + return status; +} + +/** + * csr_roam_reassoc() - process reassoc command + * @mac_ctx: mac global context + * @session_id: session id + * @profile: roam profile + * @mod_fields: AC info being modified in reassoc + * @roam_id: roam id to be populated + * + * Return: status of operation + */ +QDF_STATUS +csr_roam_reassoc(tpAniSirGlobal mac_ctx, uint32_t session_id, + tCsrRoamProfile *profile, + tCsrRoamModifyProfileFields mod_fields, + uint32_t *roam_id) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + bool fCallCallback = true; + uint32_t roamId = 0; + + tCsrRoamSession *session = CSR_GET_SESSION(mac_ctx, session_id); + if (NULL == profile) { + sms_log(mac_ctx, LOGP, FL("No profile specified")); + return QDF_STATUS_E_FAILURE; + } + sms_log(mac_ctx, LOG1, + FL("called BSSType = %s (%d) authtype = %d encryType = %d"), + sme_bss_type_to_string(profile->BSSType), + profile->BSSType, profile->AuthType.authType[0], + profile->EncryptionType.encryptionType[0]); + csr_roam_cancel_roaming(mac_ctx, session_id); + csr_scan_remove_fresh_scan_command(mac_ctx, session_id); + csr_scan_abort_mac_scan_not_for_connect(mac_ctx, session_id); + csr_roam_remove_duplicate_command(mac_ctx, session_id, NULL, + eCsrHddIssuedReassocToSameAP); + if (csr_is_conn_state_connected(mac_ctx, session_id)) { + if (profile) { + if (profile->SSIDs.numOfSSIDs && + csr_is_ssid_in_list(mac_ctx, + &session->connectedProfile.SSID, + &profile->SSIDs)) { + fCallCallback = false; + } else { + /* + * Connected SSID did not match with what is + * asked in profile + */ + sms_log(mac_ctx, LOG1, FL("SSID mismatch")); + } + } else if (qdf_mem_cmp(&mod_fields, + &session->connectedProfile.modifyProfileFields, + sizeof(tCsrRoamModifyProfileFields))) { + fCallCallback = false; + } else { + sms_log(mac_ctx, LOG1, + /* + * Either the profile is NULL or none of the + * fields in tCsrRoamModifyProfileFields got + * modified + */ + FL("Profile NULL or nothing to modify.")); + } + } else { + sms_log(mac_ctx, LOG1, FL("Not connected! No need to reassoc")); + } + if (!fCallCallback) { + roamId = GET_NEXT_ROAM_ID(&mac_ctx->roam); + if (roam_id) + *roam_id = roamId; + status = csr_roam_issue_reassoc(mac_ctx, session_id, profile, + &mod_fields, eCsrHddIssuedReassocToSameAP, + roamId, false); + } else { + status = csr_roam_call_callback(mac_ctx, session_id, NULL, + roamId, eCSR_ROAM_FAILED, + eCSR_ROAM_RESULT_FAILURE); + } + return status; +} + +static QDF_STATUS csr_roam_join_last_profile(tpAniSirGlobal pMac, + uint32_t sessionId) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tScanResultHandle hBSSList = NULL; + tCsrScanResultFilter *pScanFilter = NULL; + uint32_t roamId; + tCsrRoamProfile *pProfile = NULL; + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!pSession) { + sms_log(pMac, LOGE, FL(" session %d not found "), sessionId); + return QDF_STATUS_E_FAILURE; + } + + if (pSession->pCurRoamProfile) { + csr_scan_abort_mac_scan_not_for_connect(pMac, sessionId); + /* We have to make a copy of pCurRoamProfile because it + * will be free inside csr_roam_issue_connect */ + pProfile = qdf_mem_malloc(sizeof(tCsrRoamProfile)); + if (NULL == pProfile) { + status = QDF_STATUS_E_NOMEM; + goto end; + } + status = csr_roam_copy_profile(pMac, pProfile, + pSession->pCurRoamProfile); + if (!QDF_IS_STATUS_SUCCESS(status)) + goto end; + pScanFilter = qdf_mem_malloc(sizeof(tCsrScanResultFilter)); + if (NULL == pScanFilter) { + status = QDF_STATUS_E_NOMEM; + goto end; + } + status = csr_roam_prepare_filter_from_profile(pMac, pProfile, + pScanFilter); + if (!QDF_IS_STATUS_SUCCESS(status)) + goto end; + roamId = GET_NEXT_ROAM_ID(&pMac->roam); + status = csr_scan_get_result(pMac, pScanFilter, &hBSSList); + if (QDF_IS_STATUS_SUCCESS(status)) { + /* we want to put the last connected BSS to the + * very beginning, if possible */ + csr_move_bss_to_head_from_bssid(pMac, + &pSession->connectedProfile.bssid, hBSSList); + status = csr_roam_issue_connect(pMac, sessionId, + pProfile, hBSSList, eCsrHddIssued, + roamId, false, false); + if (!QDF_IS_STATUS_SUCCESS(status)) { + csr_scan_result_purge(pMac, hBSSList); + goto end; + } + } else { + /* scan for this SSID only incase AP suppresses SSID */ + status = csr_scan_for_ssid(pMac, sessionId, pProfile, + roamId, true); + if (!QDF_IS_STATUS_SUCCESS(status)) + goto end; + } + } /* We have a profile */ + else { + sms_log(pMac, LOGW, FL("cannot find a roaming profile")); + goto end; + } +end: + if (pScanFilter) { + csr_free_scan_filter(pMac, pScanFilter); + qdf_mem_free(pScanFilter); + } + if (NULL != pProfile) { + csr_release_profile(pMac, pProfile); + qdf_mem_free(pProfile); + } + return status; +} + +QDF_STATUS csr_roam_reconnect(tpAniSirGlobal pMac, uint32_t sessionId) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + if (csr_is_conn_state_connected(pMac, sessionId)) { + status = + csr_roam_issue_disassociate_cmd(pMac, sessionId, + eCSR_DISCONNECT_REASON_UNSPECIFIED); + if (QDF_IS_STATUS_SUCCESS(status)) { + status = csr_roam_join_last_profile(pMac, sessionId); + } + } + return status; +} + +QDF_STATUS csr_roam_connect_to_last_profile(tpAniSirGlobal pMac, uint32_t sessionId) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + sms_log(pMac, LOGW, FL("is called")); + csr_roam_cancel_roaming(pMac, sessionId); + csr_roam_remove_duplicate_command(pMac, sessionId, NULL, eCsrHddIssued); + if (csr_is_conn_state_disconnected(pMac, sessionId)) { + status = csr_roam_join_last_profile(pMac, sessionId); + } + return status; +} + +QDF_STATUS csr_roam_process_disassoc_deauth(tpAniSirGlobal pMac, tSmeCmd *pCommand, + bool fDisassoc, bool fMICFailure) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + bool fComplete = false; + eCsrRoamSubState NewSubstate; + uint32_t sessionId = pCommand->sessionId; + + if (CSR_IS_WAIT_FOR_KEY(pMac, sessionId)) { + sms_log(pMac, LOG1, + FL(" Stop Wait for key timer and change substate to" + " eCSR_ROAM_SUBSTATE_NONE")); + csr_roam_stop_wait_for_key_timer(pMac); + csr_roam_substate_change(pMac, eCSR_ROAM_SUBSTATE_NONE, sessionId); + } + /* change state to 'Roaming'... */ + csr_roam_state_change(pMac, eCSR_ROAMING_STATE_JOINING, sessionId); + + if (csr_is_conn_state_ibss(pMac, sessionId)) { + /* If we are in an IBSS, then stop the IBSS... */ + status = + csr_roam_issue_stop_bss(pMac, sessionId, + eCSR_ROAM_SUBSTATE_STOP_BSS_REQ); + fComplete = (!QDF_IS_STATUS_SUCCESS(status)); + } else if (csr_is_conn_state_infra(pMac, sessionId)) { + /* + * in Infrastructure, we need to disassociate from the + * Infrastructure network... + */ + NewSubstate = eCSR_ROAM_SUBSTATE_DISASSOC_FORCED; + if (eCsrSmeIssuedDisassocForHandoff == + pCommand->u.roamCmd.roamReason) { + NewSubstate = eCSR_ROAM_SUBSTATE_DISASSOC_HANDOFF; + } else + if ((eCsrForcedDisassoc == pCommand->u.roamCmd.roamReason) + && (eSIR_MAC_DISASSOC_LEAVING_BSS_REASON == + pCommand->u.roamCmd.reason)) { + NewSubstate = eCSR_ROAM_SUBSTATE_DISASSOC_STA_HAS_LEFT; + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO, + FL + ("set to substate eCSR_ROAM_SUBSTATE_DISASSOC_STA_HAS_LEFT")); + } + if (eCsrSmeIssuedDisassocForHandoff != + pCommand->u.roamCmd.roamReason) { + /* + * If we are in neighbor preauth done state then + * on receiving disassoc or deauth we dont roam + * instead we just disassoc from current ap and + * then go to disconnected state. + * This happens for ESE and 11r FT connections ONLY. + */ + if (csr_roam_is11r_assoc(pMac, sessionId) && + (csr_neighbor_roam_state_preauth_done(pMac, + sessionId))) { + csr_neighbor_roam_tranistion_preauth_done_to_disconnected( + pMac, sessionId); + } +#ifdef FEATURE_WLAN_ESE + if (csr_roam_is_ese_assoc(pMac, sessionId) && + (csr_neighbor_roam_state_preauth_done(pMac, + sessionId))) { + csr_neighbor_roam_tranistion_preauth_done_to_disconnected( + pMac, sessionId); + } +#endif + if (csr_roam_is_fast_roam_enabled(pMac, sessionId) && + (csr_neighbor_roam_state_preauth_done(pMac, + sessionId))) { + csr_neighbor_roam_tranistion_preauth_done_to_disconnected( + pMac, sessionId); + } + } + if (fDisassoc) { + status = + csr_roam_issue_disassociate(pMac, sessionId, + NewSubstate, fMICFailure); + } else { + status = + csr_roam_issue_deauth(pMac, sessionId, + eCSR_ROAM_SUBSTATE_DEAUTH_REQ); + } + fComplete = (!QDF_IS_STATUS_SUCCESS(status)); + } else { + /* we got a dis-assoc request while not connected to any peer */ + /* just complete the command */ + fComplete = true; + status = QDF_STATUS_E_FAILURE; + } + if (fComplete) { + csr_roam_complete(pMac, eCsrNothingToJoin, NULL); + } + + if (QDF_IS_STATUS_SUCCESS(status)) { + if (csr_is_conn_state_infra(pMac, sessionId)) { + /* Set the state to disconnect here */ + pMac->roam.roamSession[sessionId].connectState = + eCSR_ASSOC_STATE_TYPE_NOT_CONNECTED; + } + } else { + sms_log(pMac, LOGW, FL(" failed with status %d"), status); + } + return status; +} + +/** + * csr_prepare_disconnect_command() - function to prepare disconnect command + * @mac: pointer to global mac structure + * @session_id: sme session index + * @sme_cmd: pointer to sme command being prepared + * + * Function to prepare internal sme disconnect command + * Return: QDF_STATUS_SUCCESS on success else QDF_STATUS_E_RESOURCES on failure + */ + +QDF_STATUS csr_prepare_disconnect_command(tpAniSirGlobal mac, + uint32_t session_id, tSmeCmd **sme_cmd) +{ + tSmeCmd *command; + + command = csr_get_command_buffer(mac); + if (!command) { + sms_log(mac, LOGE, FL("fail to get command buffer")); + return QDF_STATUS_E_RESOURCES; + } + + command->command = eSmeCommandRoam; + command->sessionId = (uint8_t)session_id; + command->u.roamCmd.roamReason = eCsrForcedDisassoc; + + *sme_cmd = command; + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS csr_roam_issue_disassociate_cmd(tpAniSirGlobal pMac, uint32_t sessionId, + eCsrRoamDisconnectReason reason) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tSmeCmd *pCommand; + do { + pCommand = csr_get_command_buffer(pMac); + if (!pCommand) { + sms_log(pMac, LOGE, FL(" fail to get command buffer")); + status = QDF_STATUS_E_RESOURCES; + break; + } + /* Change the substate in case it is wait-for-key */ + if (CSR_IS_WAIT_FOR_KEY(pMac, sessionId)) { + csr_roam_stop_wait_for_key_timer(pMac); + csr_roam_substate_change(pMac, eCSR_ROAM_SUBSTATE_NONE, + sessionId); + } + pCommand->command = eSmeCommandRoam; + pCommand->sessionId = (uint8_t) sessionId; + sms_log(pMac, LOG1, + FL("Disassociate reason: %d, sessionId: %d"), + reason, sessionId); + switch (reason) { + case eCSR_DISCONNECT_REASON_MIC_ERROR: + pCommand->u.roamCmd.roamReason = + eCsrForcedDisassocMICFailure; + break; + case eCSR_DISCONNECT_REASON_DEAUTH: + pCommand->u.roamCmd.roamReason = eCsrForcedDeauth; + break; + case eCSR_DISCONNECT_REASON_HANDOFF: + pCommand->u.roamCmd.roamReason = + eCsrSmeIssuedDisassocForHandoff; + break; + case eCSR_DISCONNECT_REASON_UNSPECIFIED: + case eCSR_DISCONNECT_REASON_DISASSOC: + pCommand->u.roamCmd.roamReason = eCsrForcedDisassoc; + break; + case eCSR_DISCONNECT_REASON_ROAM_HO_FAIL: + pCommand->u.roamCmd.roamReason = eCsrForcedDisassoc; + break; + case eCSR_DISCONNECT_REASON_IBSS_JOIN_FAILURE: + pCommand->u.roamCmd.roamReason = + eCsrSmeIssuedIbssJoinFailure; + break; + case eCSR_DISCONNECT_REASON_IBSS_LEAVE: + pCommand->u.roamCmd.roamReason = eCsrForcedIbssLeave; + break; + case eCSR_DISCONNECT_REASON_STA_HAS_LEFT: + pCommand->u.roamCmd.roamReason = eCsrForcedDisassoc; + pCommand->u.roamCmd.reason = + eSIR_MAC_DISASSOC_LEAVING_BSS_REASON; + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO, + FL("SME convert to internal reason code eCsrStaHasLeft")); + break; + case eCSR_DISCONNECT_REASON_NDI_DELETE: + pCommand->u.roamCmd.roamReason = eCsrStopBss; + pCommand->u.roamCmd.roamProfile.BSSType = + eCSR_BSS_TYPE_NDI; + default: + break; + } + pCommand->u.roamCmd.disconnect_reason = reason; + status = csr_queue_sme_command(pMac, pCommand, true); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOGE, + FL(" fail to send message status = %d"), status); + csr_release_command_roam(pMac, pCommand); + } + } while (0); + return status; +} + +QDF_STATUS csr_roam_issue_stop_bss_cmd(tpAniSirGlobal pMac, uint32_t sessionId, + bool fHighPriority) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tSmeCmd *pCommand; + pCommand = csr_get_command_buffer(pMac); + if (NULL != pCommand) { + /* Change the substate in case it is wait-for-key */ + if (CSR_IS_WAIT_FOR_KEY(pMac, sessionId)) { + csr_roam_stop_wait_for_key_timer(pMac); + csr_roam_substate_change(pMac, eCSR_ROAM_SUBSTATE_NONE, + sessionId); + } + pCommand->command = eSmeCommandRoam; + pCommand->sessionId = (uint8_t) sessionId; + pCommand->u.roamCmd.roamReason = eCsrStopBss; + status = csr_queue_sme_command(pMac, pCommand, fHighPriority); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOGE, + FL(" fail to send message status = %d"), status); + csr_release_command_roam(pMac, pCommand); + } + } else { + sms_log(pMac, LOGE, FL(" fail to get command buffer")); + status = QDF_STATUS_E_RESOURCES; + } + return status; +} + +QDF_STATUS csr_roam_disconnect_internal(tpAniSirGlobal pMac, uint32_t sessionId, + eCsrRoamDisconnectReason reason) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!pSession) { + sms_log(pMac, LOGE, FL(" session %d not found "), sessionId); + return QDF_STATUS_E_FAILURE; + } +#ifdef FEATURE_WLAN_BTAMP_UT_RF + /* Stop the retry */ + pSession->maxRetryCount = 0; + csr_roam_stop_join_retry_timer(pMac, sessionId); +#endif + /* Not to call cancel roaming here */ + /* Only issue disconnect when necessary */ + if (csr_is_conn_state_connected(pMac, sessionId) + || csr_is_bss_type_ibss(pSession->connectedProfile.BSSType) + || csr_is_roam_command_waiting_for_session(pMac, sessionId) + || CSR_IS_CONN_NDI(&pSession->connectedProfile)) { + sms_log(pMac, LOG2, FL("called")); + status = csr_roam_issue_disassociate_cmd(pMac, sessionId, + reason); + } else { + pMac->roam.roamSession[sessionId].connectState = + eCSR_ASSOC_STATE_TYPE_INFRA_DISCONNECTING; + csr_scan_abort_scan_for_ssid(pMac, sessionId); + status = QDF_STATUS_CMD_NOT_QUEUED; + sms_log(pMac, LOG1, + FL + (" Disconnect cmd not queued, Roam command is not present" + " return with status %d"), status); + } + return status; +} + +QDF_STATUS csr_roam_disconnect(tpAniSirGlobal pMac, uint32_t sessionId, + eCsrRoamDisconnectReason reason) +{ + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!pSession) { + sms_log(pMac, LOGE, FL(" session %d not found "), sessionId); + return QDF_STATUS_E_FAILURE; + } + + csr_roam_cancel_roaming(pMac, sessionId); + csr_roam_remove_duplicate_command(pMac, sessionId, NULL, + eCsrForcedDisassoc); + + return csr_roam_disconnect_internal(pMac, sessionId, reason); +} + +QDF_STATUS csr_roam_save_connected_infomation(tpAniSirGlobal pMac, + uint32_t sessionId, + tCsrRoamProfile *pProfile, + tSirBssDescription *pSirBssDesc, + tDot11fBeaconIEs *pIes) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tDot11fBeaconIEs *pIesTemp = pIes; + uint8_t index; + tCsrRoamSession *pSession = NULL; + tCsrRoamConnectedProfile *pConnectProfile = NULL; + + pSession = CSR_GET_SESSION(pMac, sessionId); + if (NULL == pSession) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("session %d not found"), sessionId); + return QDF_STATUS_E_FAILURE; + } + + sms_log(pMac, LOG1, FL("session id %d"), sessionId); + pConnectProfile = &pSession->connectedProfile; + if (pConnectProfile->pAddIEAssoc) { + qdf_mem_free(pConnectProfile->pAddIEAssoc); + pConnectProfile->pAddIEAssoc = NULL; + } + /* + * In case of LFR2.0, the connected profile is copied into a temporary + * profile and cleared and then is copied back. This is not needed for + * LFR3.0, since the profile is not cleared. + */ + if (!pSession->roam_synch_in_progress) { + qdf_mem_set(&pSession->connectedProfile, + sizeof(tCsrRoamConnectedProfile), 0); + pConnectProfile->AuthType = pProfile->negotiatedAuthType; + pConnectProfile->AuthInfo = pProfile->AuthType; + pConnectProfile->EncryptionType = + pProfile->negotiatedUCEncryptionType; + pConnectProfile->EncryptionInfo = pProfile->EncryptionType; + pConnectProfile->mcEncryptionType = + pProfile->negotiatedMCEncryptionType; + pConnectProfile->mcEncryptionInfo = pProfile->mcEncryptionType; + pConnectProfile->BSSType = pProfile->BSSType; + pConnectProfile->modifyProfileFields.uapsd_mask = + pProfile->uapsd_mask; + qdf_mem_copy(&pConnectProfile->Keys, &pProfile->Keys, + sizeof(tCsrKeys)); + if (pProfile->nAddIEAssocLength) { + pConnectProfile->pAddIEAssoc = + qdf_mem_malloc(pProfile->nAddIEAssocLength); + if (NULL == pConnectProfile->pAddIEAssoc) + status = QDF_STATUS_E_NOMEM; + else + status = QDF_STATUS_SUCCESS; + if (!QDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOGE, + FL("Failed to allocate memory for IE")); + return QDF_STATUS_E_FAILURE; + } + pConnectProfile->nAddIEAssocLength = + pProfile->nAddIEAssocLength; + qdf_mem_copy(pConnectProfile->pAddIEAssoc, + pProfile->pAddIEAssoc, + pProfile->nAddIEAssocLength); + } +#ifdef WLAN_FEATURE_11W + pConnectProfile->MFPEnabled = pProfile->MFPEnabled; + pConnectProfile->MFPRequired = pProfile->MFPRequired; + pConnectProfile->MFPCapable = pProfile->MFPCapable; +#endif + } + if (pIes) + pConnectProfile->CBMode = csr_get_cb_mode_from_ies(pMac, + pSirBssDesc->channelId, pIes); + else + sms_log(pMac, LOGE, FL("IE unavailable to derive CB mode")); + + /* Save bssid */ + pConnectProfile->operationChannel = pSirBssDesc->channelId; + pConnectProfile->beaconInterval = pSirBssDesc->beaconInterval; + if (!pConnectProfile->beaconInterval) { + sms_log(pMac, LOGW, FL("ERROR: Beacon interval is ZERO")); + } + csr_get_bss_id_bss_desc(pMac, pSirBssDesc, &pConnectProfile->bssid); + if (pSirBssDesc->mdiePresent) { + pConnectProfile->MDID.mdiePresent = 1; + pConnectProfile->MDID.mobilityDomain = + (pSirBssDesc->mdie[1] << 8) | (pSirBssDesc->mdie[0]); + } + if (NULL == pIesTemp) { + status = + csr_get_parsed_bss_description_ies(pMac, pSirBssDesc, + &pIesTemp); + } +#ifdef FEATURE_WLAN_ESE + if ((csr_is_profile_ese(pProfile) || + (QDF_IS_STATUS_SUCCESS(status) && (pIesTemp->ESEVersion.present) + && (pProfile->negotiatedAuthType == eCSR_AUTH_TYPE_OPEN_SYSTEM))) + && (pMac->roam.configParam.isEseIniFeatureEnabled)) { + pConnectProfile->isESEAssoc = 1; + } +#endif + /* save ssid */ + if (QDF_IS_STATUS_SUCCESS(status)) { + if (pIesTemp->SSID.present) { + pConnectProfile->SSID.length = pIesTemp->SSID.num_ssid; + qdf_mem_copy(pConnectProfile->SSID.ssId, + pIesTemp->SSID.ssid, + pIesTemp->SSID.num_ssid); + } + /* Save the bss desc */ + status = + csr_roam_save_connected_bss_desc(pMac, sessionId, pSirBssDesc); + + if (CSR_IS_QOS_BSS(pIesTemp) || pIesTemp->HTCaps.present) { + /* Some HT AP's dont send WMM IE so in that case we assume all HT Ap's are Qos Enabled AP's */ + pConnectProfile->qap = true; + } else { + pConnectProfile->qap = false; + } + + if (pIesTemp->ExtCap.present) { + struct s_ext_cap *p_ext_cap = (struct s_ext_cap *) + pIesTemp->ExtCap.bytes; + pConnectProfile->proxyARPService = p_ext_cap-> + proxy_arp_service; + } + + if (NULL == pIes) { + /* Free memory if it allocated locally */ + qdf_mem_free(pIesTemp); + } + } + /* Save Qos connection */ + pConnectProfile->qosConnection = + pMac->roam.roamSession[sessionId].fWMMConnection; + + if (!QDF_IS_STATUS_SUCCESS(status)) { + csr_free_connect_bss_desc(pMac, sessionId); + } + for (index = 0; index < pProfile->SSIDs.numOfSSIDs; index++) { + if ((pProfile->SSIDs.SSIDList[index].SSID.length == + pConnectProfile->SSID.length) + && (!qdf_mem_cmp(pProfile->SSIDs.SSIDList[index].SSID. + ssId, pConnectProfile->SSID.ssId, + pConnectProfile->SSID.length))) { + pConnectProfile->handoffPermitted = + pProfile->SSIDs.SSIDList[index].handoffPermitted; + break; + } + pConnectProfile->handoffPermitted = false; + } + + return status; +} + + +bool is_disconnect_pending(tpAniSirGlobal pmac, + uint8_t sessionid) +{ + tListElem *entry = NULL; + tListElem *next_entry = NULL; + tSmeCmd *command = NULL; + bool disconnect_cmd_exist = false; + + csr_ll_lock(&pmac->sme.smeCmdPendingList); + entry = csr_ll_peek_head(&pmac->sme.smeCmdPendingList, LL_ACCESS_NOLOCK); + while (entry) { + next_entry = csr_ll_next(&pmac->sme.smeCmdPendingList, + entry, LL_ACCESS_NOLOCK); + + command = GET_BASE_ADDR(entry, tSmeCmd, Link); + if (command && CSR_IS_DISCONNECT_COMMAND(command) && + command->sessionId == sessionid){ + disconnect_cmd_exist = true; + break; + } + entry = next_entry; + } + csr_ll_unlock(&pmac->sme.smeCmdPendingList); + return disconnect_cmd_exist; +} + +static void csr_roam_join_rsp_processor(tpAniSirGlobal pMac, + tSirSmeJoinRsp *pSmeJoinRsp) +{ + tListElem *pEntry = NULL; + tSmeCmd *pCommand = NULL; + tCsrRoamSession *session_ptr; + + if (pSmeJoinRsp) { + session_ptr = CSR_GET_SESSION(pMac, pSmeJoinRsp->sessionId); + } else { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Sme Join Response is NULL")); + return; + } + if (!session_ptr) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("session %d not found"), pSmeJoinRsp->sessionId); + return; + } + /* The head of the active list is the request we sent */ + pEntry = csr_ll_peek_head(&pMac->sme.smeCmdActiveList, LL_ACCESS_LOCK); + if (pEntry) { + pCommand = GET_BASE_ADDR(pEntry, tSmeCmd, Link); + } + if (eSIR_SME_SUCCESS == pSmeJoinRsp->statusCode) { + if (pCommand + && eCsrSmeIssuedAssocToSimilarAP == + pCommand->u.roamCmd.roamReason) { +#ifndef WLAN_MDM_CODE_REDUCTION_OPT + sme_qos_csr_event_ind(pMac, pSmeJoinRsp->sessionId, + SME_QOS_CSR_HANDOFF_COMPLETE, NULL); +#endif + } + + session_ptr->supported_nss_1x1 = + pSmeJoinRsp->supported_nss_1x1; + sms_log(pMac, LOG1, + FL("SME session supported nss: %d"), + session_ptr->supported_nss_1x1); + + /* * + * The join bssid count can be reset as soon as + * we are done with the join requests and returning + * the response to upper layers + * */ + session_ptr->join_bssid_count = 0; + csr_roam_complete(pMac, eCsrJoinSuccess, (void *)pSmeJoinRsp); + } else { + uint32_t roamId = 0; + bool is_dis_pending; + + /* The head of the active list is the request we sent */ + /* Try to get back the same profile and roam again */ + if (pCommand) { + roamId = pCommand->u.roamCmd.roamId; + } + session_ptr->joinFailStatusCode.statusCode = + pSmeJoinRsp->statusCode; + session_ptr->joinFailStatusCode.reasonCode = + pSmeJoinRsp->protStatusCode; + sms_log(pMac, LOGW, + "SmeJoinReq failed with statusCode= 0x%08X [%d]", + pSmeJoinRsp->statusCode, pSmeJoinRsp->statusCode); + /* If Join fails while Handoff is in progress, indicate disassociated event to supplicant to reconnect */ + if (csr_roam_is_handoff_in_progress(pMac, pSmeJoinRsp->sessionId)) { + csr_roam_call_callback(pMac, pSmeJoinRsp->sessionId, NULL, + roamId, eCSR_ROAM_DISASSOCIATED, + eCSR_ROAM_RESULT_FORCED); + /* Should indicate neighbor roam algorithm about the connect failure here */ + csr_neighbor_roam_indicate_connect(pMac, + pSmeJoinRsp->sessionId, + QDF_STATUS_E_FAILURE); + } + /* + * if userspace has issued disconnection, + * driver should not continue connecting + */ + is_dis_pending = is_disconnect_pending(pMac, session_ptr->sessionId); + if (pCommand && (session_ptr->join_bssid_count < + CSR_MAX_BSSID_COUNT) && !is_dis_pending) { + csr_roam(pMac, pCommand); + } else { + /* **************************************************** + * When the upper layers issue a connect command, there + * is a roam command with reason eCsrHddIssued that + * gets enqueued and an associated timer for the SME + * command timeout is started which is currently 120 + * seconds. This command would be dequeued only upon + * succesfull connections. In case of join failures, if + * there are too many BSS in the cache, and if we fail + * Join requests with all of them, there is a chance of + * timing out the above timer. + * ***************************************************/ + if (session_ptr->join_bssid_count >= + CSR_MAX_BSSID_COUNT) + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_ERROR, + FL("Excessive Join Req Failures")); + + if (is_dis_pending) + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_ERROR, + FL("disconnect is pending, complete roam")); + + if (session_ptr->bRefAssocStartCnt) + session_ptr->bRefAssocStartCnt--; + + session_ptr->join_bssid_count = 0; + csr_roam_call_callback(pMac, session_ptr->sessionId, + NULL, roamId, + eCSR_ROAM_ASSOCIATION_COMPLETION, + eCSR_ROAM_RESULT_NOT_ASSOCIATED); + csr_roam_complete(pMac, eCsrNothingToJoin, NULL); + } + } /*else: ( eSIR_SME_SUCCESS == pSmeJoinRsp->statusCode ) */ +} + +static QDF_STATUS csr_roam_issue_join(tpAniSirGlobal pMac, uint32_t sessionId, + tSirBssDescription *pSirBssDesc, + tDot11fBeaconIEs *pIes, + tCsrRoamProfile *pProfile, + uint32_t roamId) +{ + QDF_STATUS status; + sms_log(pMac, LOG1, "Attempting to Join Bssid= " MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(pSirBssDesc->bssId)); + + /* Set the roaming substate to 'join attempt'... */ + csr_roam_substate_change(pMac, eCSR_ROAM_SUBSTATE_JOIN_REQ, sessionId); + /* attempt to Join this BSS... */ + status = + csr_send_join_req_msg(pMac, sessionId, pSirBssDesc, pProfile, pIes, + eWNI_SME_JOIN_REQ); + return status; +} + +void csr_roam_reissue_roam_command(tpAniSirGlobal pMac) +{ + tListElem *pEntry; + tSmeCmd *pCommand; + tCsrRoamInfo roamInfo; + uint32_t sessionId; + tCsrRoamSession *pSession; + + pEntry = csr_ll_peek_head(&pMac->sme.smeCmdActiveList, LL_ACCESS_LOCK); + if (NULL == pEntry) { + sms_log(pMac, LOGE, + FL("Disassoc rsp can't continue, no active CMD")); + return; + } + pCommand = GET_BASE_ADDR(pEntry, tSmeCmd, Link); + if (eSmeCommandRoam != pCommand->command) { + sms_log(pMac, LOGW, FL("Active cmd, is not a roaming CMD")); + return; + } + sessionId = pCommand->sessionId; + pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!pSession) { + sms_log(pMac, LOGE, FL("session %d not found"), sessionId); + return; + } + + if (!pCommand->u.roamCmd.fStopWds) { + if (pSession->bRefAssocStartCnt > 0) { + /* + * bRefAssocStartCnt was incremented in + * csr_roam_join_next_bss when the roam command issued + * previously. As part of reissuing the roam command + * again csr_roam_join_next_bss is going increment + * RefAssocStartCnt. So make sure to decrement the + * bRefAssocStartCnt + */ + pSession->bRefAssocStartCnt--; + } + if (eCsrStopRoaming == csr_roam_join_next_bss(pMac, pCommand, + true)) { + sms_log(pMac, LOGW, + FL("Failed to reissue join command")); + csr_roam_complete(pMac, eCsrNothingToJoin, NULL); + } + return; + } + qdf_mem_set(&roamInfo, sizeof(tCsrRoamInfo), 0); + roamInfo.pBssDesc = pCommand->u.roamCmd.pLastRoamBss; + roamInfo.statusCode = pSession->joinFailStatusCode.statusCode; + roamInfo.reasonCode = pSession->joinFailStatusCode.reasonCode; + pSession->connectState = eCSR_ASSOC_STATE_TYPE_INFRA_DISCONNECTED; + csr_roam_call_callback(pMac, sessionId, &roamInfo, + pCommand->u.roamCmd.roamId, + eCSR_ROAM_INFRA_IND, + eCSR_ROAM_RESULT_INFRA_DISASSOCIATED); + + if (!QDF_IS_STATUS_SUCCESS(csr_roam_issue_stop_bss(pMac, sessionId, + eCSR_ROAM_SUBSTATE_STOP_BSS_REQ))) { + sms_log(pMac, LOGE, + FL("Failed to reissue stop_bss command for WDS")); + csr_roam_complete(pMac, eCsrNothingToJoin, NULL); + } +} + +bool csr_is_roam_command_waiting_for_session(tpAniSirGlobal pMac, uint32_t sessionId) +{ + bool fRet = false; + tListElem *pEntry; + tSmeCmd *pCommand = NULL; + /* alwasy lock active list before locking pending list */ + csr_ll_lock(&pMac->sme.smeCmdActiveList); + pEntry = csr_ll_peek_head(&pMac->sme.smeCmdActiveList, LL_ACCESS_NOLOCK); + if (pEntry) { + pCommand = GET_BASE_ADDR(pEntry, tSmeCmd, Link); + if ((eSmeCommandRoam == pCommand->command) + && (sessionId == pCommand->sessionId)) { + fRet = true; + } + } + if (false == fRet) { + csr_ll_lock(&pMac->sme.smeCmdPendingList); + pEntry = + csr_ll_peek_head(&pMac->sme.smeCmdPendingList, + LL_ACCESS_NOLOCK); + while (pEntry) { + pCommand = GET_BASE_ADDR(pEntry, tSmeCmd, Link); + if ((eSmeCommandRoam == pCommand->command) + && (sessionId == pCommand->sessionId)) { + fRet = true; + break; + } + pEntry = + csr_ll_next(&pMac->sme.smeCmdPendingList, pEntry, + LL_ACCESS_NOLOCK); + } + csr_ll_unlock(&pMac->sme.smeCmdPendingList); + } + if (false == fRet) { + csr_ll_lock(&pMac->roam.roamCmdPendingList); + pEntry = + csr_ll_peek_head(&pMac->roam.roamCmdPendingList, + LL_ACCESS_NOLOCK); + while (pEntry) { + pCommand = GET_BASE_ADDR(pEntry, tSmeCmd, Link); + if ((eSmeCommandRoam == pCommand->command) + && (sessionId == pCommand->sessionId)) { + fRet = true; + break; + } + pEntry = + csr_ll_next(&pMac->roam.roamCmdPendingList, pEntry, + LL_ACCESS_NOLOCK); + } + csr_ll_unlock(&pMac->roam.roamCmdPendingList); + } + csr_ll_unlock(&pMac->sme.smeCmdActiveList); + return fRet; +} + +bool csr_is_roam_command_waiting(tpAniSirGlobal pMac) +{ + bool fRet = false; + uint32_t i; + for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) { + fRet = csr_is_roam_command_waiting_for_session(pMac, i); + if (CSR_IS_SESSION_VALID(pMac, i) + && (fRet)) { + break; + } + } + return fRet; +} + +bool csr_is_scan_for_roam_command_active(tpAniSirGlobal pMac) +{ + bool fRet = false; + tListElem *pEntry; + tCsrCmd *pCommand; + /* alwasy lock active list before locking pending list */ + csr_ll_lock(&pMac->sme.smeCmdActiveList); + pEntry = csr_ll_peek_head(&pMac->sme.smeCmdActiveList, LL_ACCESS_NOLOCK); + if (pEntry) { + pCommand = GET_BASE_ADDR(pEntry, tCsrCmd, Link); + if ((eCsrRoamCommandScan == pCommand->command) && + ((eCsrScanForSsid == pCommand->u.scanCmd.reason) || + (eCsrScanP2PFindPeer == pCommand->u.scanCmd.reason))) { + fRet = true; + } + } + csr_ll_unlock(&pMac->sme.smeCmdActiveList); + return fRet; +} + +static void +csr_roaming_state_config_cnf_processor(tpAniSirGlobal mac_ctx, + uint32_t result) +{ + tListElem *entry = csr_ll_peek_head(&mac_ctx->sme.smeCmdActiveList, + LL_ACCESS_LOCK); + tCsrScanResult *scan_result = NULL; + tSirBssDescription *bss_desc = NULL; + tSmeCmd *cmd = NULL; + uint32_t session_id; + tCsrRoamSession *session; + tDot11fBeaconIEs *local_ies = NULL; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + + if (NULL == entry) { + sms_log(mac_ctx, LOGE, FL("CFG_CNF with active list empty")); + return; + } + cmd = GET_BASE_ADDR(entry, tSmeCmd, Link); + session_id = cmd->sessionId; + session = CSR_GET_SESSION(mac_ctx, session_id); + + if (!session) { + sms_log(mac_ctx, LOGE, FL("session %d not found"), session_id); + return; + } + + if (CSR_IS_ROAMING(session) && session->fCancelRoaming) { + /* the roaming is cancelled. Simply complete the command */ + sms_log(mac_ctx, LOGW, FL("Roam command canceled")); + csr_roam_complete(mac_ctx, eCsrNothingToJoin, NULL); + return; + } + + /* If the roaming has stopped, not to continue the roaming command */ + if (!CSR_IS_ROAMING(session) && CSR_IS_ROAMING_COMMAND(cmd)) { + /* No need to complete roaming here as it already completes */ + sms_log(mac_ctx, LOGW, + FL("Roam cmd (reason %d) aborted(roaming completed)"), + cmd->u.roamCmd.roamReason); + csr_set_abort_roaming_command(mac_ctx, cmd); + csr_roam_complete(mac_ctx, eCsrNothingToJoin, NULL); + return; + } + + if (!IS_SIR_STATUS_SUCCESS(result)) { + /* + * In the event the configuration failed, for infra let the roam + * processor attempt to join something else... + */ + if (cmd->u.roamCmd.pRoamBssEntry + && CSR_IS_INFRASTRUCTURE(&cmd->u.roamCmd.roamProfile)) { + csr_roam(mac_ctx, cmd); + } else { + /* We need to complete the command */ + if (csr_is_bss_type_ibss + (cmd->u.roamCmd.roamProfile.BSSType)) { + csr_roam_complete(mac_ctx, eCsrStartBssFailure, + NULL); + } else { + csr_roam_complete(mac_ctx, eCsrNothingToJoin, + NULL); + } + } + return; + } + + /* we have active entry */ + sms_log(mac_ctx, LOG2, "Cfg sequence complete"); + /* + * Successfully set the configuration parameters for the new Bss. + * Attempt to join the roaming Bss + */ + if (cmd->u.roamCmd.pRoamBssEntry) { + scan_result = GET_BASE_ADDR(cmd->u.roamCmd.pRoamBssEntry, + tCsrScanResult, + Link); + bss_desc = &scan_result->Result.BssDescriptor; + } + if (csr_is_bss_type_ibss(cmd->u.roamCmd.roamProfile.BSSType) + || CSR_IS_INFRA_AP(&cmd->u.roamCmd.roamProfile) + || CSR_IS_NDI(&cmd->u.roamCmd.roamProfile)) { + if (!QDF_IS_STATUS_SUCCESS(csr_roam_issue_start_bss(mac_ctx, + session_id, &session->bssParams, + &cmd->u.roamCmd.roamProfile, + bss_desc, + cmd->u.roamCmd.roamId))) { + sms_log(mac_ctx, LOGE, FL("CSR start BSS failed")); + /* We need to complete the command */ + csr_roam_complete(mac_ctx, eCsrStartBssFailure, NULL); + } + return; + } + + if (!cmd->u.roamCmd.pRoamBssEntry) { + sms_log(mac_ctx, LOGE, FL("pRoamBssEntry is NULL")); + /* We need to complete the command */ + csr_roam_complete(mac_ctx, eCsrJoinFailure, NULL); + return; + } + + if (NULL == scan_result) { + /* If we are roaming TO an Infrastructure BSS... */ + QDF_ASSERT(scan_result != NULL); + return; + } + + if (!csr_is_infra_bss_desc(bss_desc)) { + sms_log(mac_ctx, LOGW, + FL("found BSSType mismatching the one in BSS descp")); + return; + } + + local_ies = (tDot11fBeaconIEs *) scan_result->Result.pvIes; + if (!local_ies) { + status = csr_get_parsed_bss_description_ies(mac_ctx, bss_desc, + &local_ies); + if (!QDF_IS_STATUS_SUCCESS(status)) + return; + } + + if (csr_is_conn_state_connected_infra(mac_ctx, session_id)) { + if (csr_is_ssid_equal(mac_ctx, session->pConnectBssDesc, + bss_desc, local_ies)) { + cmd->u.roamCmd.fReassoc = true; + csr_roam_issue_reassociate(mac_ctx, session_id, + bss_desc, local_ies, + &cmd->u.roamCmd.roamProfile); + } else { + /* + * otherwise, we have to issue a new Join request to LIM + * because we disassociated from the previously + * associated AP. + */ + status = csr_roam_issue_join(mac_ctx, session_id, + bss_desc, local_ies, + &cmd->u.roamCmd.roamProfile, + cmd->u.roamCmd.roamId); + if (!QDF_IS_STATUS_SUCCESS(status)) { + /* try something else */ + csr_roam(mac_ctx, cmd); + } + } + } else { + status = QDF_STATUS_SUCCESS; + /* + * We need to come with other way to figure out that this is + * because of HO in BMP The below API will be only available for + * Android as it uses a different HO algorithm. Reassoc request + * will be used only for ESE and 11r handoff whereas other + * legacy roaming should use join request + */ + if (csr_roam_is_handoff_in_progress(mac_ctx, session_id) + && csr_roam_is11r_assoc(mac_ctx, session_id)) { + status = csr_roam_issue_reassociate(mac_ctx, + session_id, bss_desc, + (tDot11fBeaconIEs *) + (scan_result->Result.pvIes), + &cmd->u.roamCmd.roamProfile); + } else +#ifdef FEATURE_WLAN_ESE + if (csr_roam_is_handoff_in_progress(mac_ctx, session_id) + && csr_roam_is_ese_assoc(mac_ctx, session_id)) { + /* Now serialize the reassoc command. */ + status = csr_roam_issue_reassociate_cmd(mac_ctx, + session_id); + } else +#endif + if (csr_roam_is_handoff_in_progress(mac_ctx, session_id) + && csr_roam_is_fast_roam_enabled(mac_ctx, session_id)) { + /* Now serialize the reassoc command. */ + status = csr_roam_issue_reassociate_cmd(mac_ctx, + session_id); + } else { + /* + * else we are not connected and attempting to Join. + * Issue the Join request. + */ + status = csr_roam_issue_join(mac_ctx, session_id, + bss_desc, + (tDot11fBeaconIEs *) + (scan_result->Result.pvIes), + &cmd->u.roamCmd.roamProfile, + cmd->u.roamCmd.roamId); + } + if (!QDF_IS_STATUS_SUCCESS(status)) { + /* try something else */ + csr_roam(mac_ctx, cmd); + } + } + if (!scan_result->Result.pvIes) { + /* Locally allocated */ + qdf_mem_free(local_ies); + } +} + +static void csr_roam_roaming_state_reassoc_rsp_processor(tpAniSirGlobal pMac, + tpSirSmeJoinRsp pSmeJoinRsp) +{ + eCsrRoamCompleteResult result; + tpCsrNeighborRoamControlInfo pNeighborRoamInfo = + &pMac->roam.neighborRoamInfo[pSmeJoinRsp->sessionId]; + tCsrRoamInfo roamInfo; + uint32_t roamId = 0; + tCsrRoamSession *csr_session; + + if (eSIR_SME_SUCCESS == pSmeJoinRsp->statusCode) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + FL("CSR SmeReassocReq Successful")); + result = eCsrReassocSuccess; + csr_session = CSR_GET_SESSION(pMac, pSmeJoinRsp->sessionId); + if (NULL != csr_session) { + csr_session->supported_nss_1x1 = + pSmeJoinRsp->supported_nss_1x1; + sms_log(pMac, LOG1, FL("SME session supported nss: %d"), + csr_session->supported_nss_1x1); + } + /* + * Since the neighbor roam algorithm uses reassoc req for + * handoff instead of join, we need the response contents while + * processing the result in csr_roam_process_results() + */ + if (csr_roam_is_handoff_in_progress(pMac, pSmeJoinRsp->sessionId)) { + /* Need to dig more on indicating events to SME QoS module */ + sme_qos_csr_event_ind(pMac, pSmeJoinRsp->sessionId, + SME_QOS_CSR_HANDOFF_COMPLETE, NULL); + csr_roam_complete(pMac, result, pSmeJoinRsp); + } else { + csr_roam_complete(pMac, result, NULL); + } + } + /* Should we handle this similar to handling the join failure? Is it ok + * to call csr_roam_complete() with state as CsrJoinFailure */ + else { + sms_log(pMac, LOGW, + "CSR SmeReassocReq failed with statusCode= 0x%08X [%d]", + pSmeJoinRsp->statusCode, pSmeJoinRsp->statusCode); + result = eCsrReassocFailure; + cds_flush_logs(WLAN_LOG_TYPE_FATAL, + WLAN_LOG_INDICATOR_HOST_DRIVER, + WLAN_LOG_REASON_ROAM_FAIL, + true, false); + if ((eSIR_SME_FT_REASSOC_TIMEOUT_FAILURE == + pSmeJoinRsp->statusCode) + || (eSIR_SME_FT_REASSOC_FAILURE == + pSmeJoinRsp->statusCode) + || (eSIR_SME_INVALID_PARAMETERS == + pSmeJoinRsp->statusCode)) { + /* Inform HDD to turn off FT flag in HDD */ + if (pNeighborRoamInfo) { + qdf_mem_zero(&roamInfo, sizeof(tCsrRoamInfo)); + csr_roam_call_callback(pMac, + pSmeJoinRsp->sessionId, + &roamInfo, roamId, + eCSR_ROAM_FT_REASSOC_FAILED, + eSIR_SME_SUCCESS); + /* + * Since the above callback sends a disconnect + * to HDD, we should clean-up our state + * machine as well to be in sync with the upper + * layers. There is no need to send a disassoc + * since: 1) we will never reassoc to the current + * AP in LFR, and 2) there is no need to issue a + * disassoc to the AP with which we were trying + * to reassoc. + */ + csr_roam_complete(pMac, eCsrJoinFailure, NULL); + return; + } + } + /* In the event that the Reassociation fails, then we need to Disassociate the current association and keep */ + /* roaming. Note that we will attempt to Join the AP instead of a Reassoc since we may have attempted a */ + /* 'Reassoc to self', which AP's that don't support Reassoc will force a Disassoc. */ + /* The disassoc rsp message will remove the command from active list */ + if (!QDF_IS_STATUS_SUCCESS + (csr_roam_issue_disassociate + (pMac, pSmeJoinRsp->sessionId, + eCSR_ROAM_SUBSTATE_DISASSOC_REASSOC_FAILURE, false))) { + csr_roam_complete(pMac, eCsrJoinFailure, NULL); + } + } +} + +static void csr_roam_roaming_state_stop_bss_rsp_processor(tpAniSirGlobal pMac, + tSirSmeRsp *pSmeRsp) +{ + eCsrRoamCompleteResult result_code = eCsrNothingToJoin; + tCsrRoamProfile *profile; + +#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR + { + host_log_ibss_pkt_type *pIbssLog; + WLAN_HOST_DIAG_LOG_ALLOC(pIbssLog, host_log_ibss_pkt_type, + LOG_WLAN_IBSS_C); + if (pIbssLog) { + pIbssLog->eventId = WLAN_IBSS_EVENT_STOP_RSP; + if (eSIR_SME_SUCCESS != pSmeRsp->statusCode) { + pIbssLog->status = WLAN_IBSS_STATUS_FAILURE; + } + WLAN_HOST_DIAG_LOG_REPORT(pIbssLog); + } + } +#endif /* FEATURE_WLAN_DIAG_SUPPORT_CSR */ + pMac->roam.roamSession[pSmeRsp->sessionId].connectState = + eCSR_ASSOC_STATE_TYPE_NOT_CONNECTED; + if (CSR_IS_ROAM_SUBSTATE_STOP_BSS_REQ(pMac, pSmeRsp->sessionId)) { + profile = + pMac->roam.roamSession[pSmeRsp->sessionId].pCurRoamProfile; + if (profile && CSR_IS_CONN_NDI(profile)) { + result_code = eCsrStopBssSuccess; + if (pSmeRsp->statusCode != eSIR_SME_SUCCESS) + result_code = eCsrStopBssFailure; + } + csr_roam_complete(pMac, result_code, NULL); + } else if (CSR_IS_ROAM_SUBSTATE_DISCONNECT_CONTINUE(pMac, + pSmeRsp->sessionId)) { + csr_roam_reissue_roam_command(pMac); + } +} + +/** + * csr_dequeue_command() - removes a command from active cmd list + * @pMac: mac global context + * + * Return: void + */ +static void +csr_dequeue_command(tpAniSirGlobal mac_ctx) +{ + bool fRemoveCmd; + tSmeCmd *cmd = NULL; + tListElem *entry = csr_ll_peek_head(&mac_ctx->sme.smeCmdActiveList, + LL_ACCESS_LOCK); + if (!entry) { + sms_log(mac_ctx, LOGE, FL("NO commands are active")); + return; + } + + cmd = GET_BASE_ADDR(entry, tSmeCmd, Link); + /* + * If the head of the queue is Active and it is a given cmd type, remove + * and put this on the Free queue. + */ + if (eSmeCommandRoam != cmd->command) { + sms_log(mac_ctx, LOGE, FL("Roam command not active")); + return; + } + /* + * we need to process the result first before removing it from active + * list because state changes still happening insides + * roamQProcessRoamResults so no other roam command should be issued. + */ + fRemoveCmd = csr_ll_remove_entry(&mac_ctx->sme.smeCmdActiveList, entry, + LL_ACCESS_LOCK); + if (cmd->u.roamCmd.fReleaseProfile) { + csr_release_profile(mac_ctx, &cmd->u.roamCmd.roamProfile); + cmd->u.roamCmd.fReleaseProfile = false; + } + if (fRemoveCmd) + csr_release_command_roam(mac_ctx, cmd); + else + sms_log(mac_ctx, LOGE, FL("fail to remove cmd reason %d"), + cmd->u.roamCmd.roamReason); +} + +/** + * csr_post_roam_failure() - post roam failure back to csr and issues a disassoc + * @pMac: mac global context + * @session_id: session id + * @roam_info: roam info struct + * @scan_filter: scan filter to free + * @cur_roam_profile: current csr roam profile + * + * Return: void + */ +static void +csr_post_roam_failure(tpAniSirGlobal mac_ctx, + uint32_t session_id, + tCsrRoamInfo *roam_info, + tCsrScanResultFilter *scan_filter, + tCsrRoamProfile *cur_roam_profile) +{ + QDF_STATUS status; + + if (scan_filter) { + csr_free_scan_filter(mac_ctx, scan_filter); + qdf_mem_free(scan_filter); + } + if (cur_roam_profile) + qdf_mem_free(cur_roam_profile); + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + csr_roam_synch_clean_up(mac_ctx, session_id); +#endif + /* Inform the upper layers that the reassoc failed */ + qdf_mem_zero(roam_info, sizeof(tCsrRoamInfo)); + csr_roam_call_callback(mac_ctx, session_id, roam_info, 0, + eCSR_ROAM_FT_REASSOC_FAILED, eSIR_SME_SUCCESS); + /* + * Issue a disassoc request so that PE/LIM uses this to clean-up the FT + * session. Upon success, we would re-enter this routine after receiving + * the disassoc response and will fall into the reassoc fail sub-state. + * And, eventually call csr_roam_complete which would remove the roam + * command from SME active queue. + */ + status = csr_roam_issue_disassociate(mac_ctx, session_id, + eCSR_ROAM_SUBSTATE_DISASSOC_REASSOC_FAILURE, false); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sms_log(mac_ctx, LOGE, + FL("csr_roam_issue_disassociate failed, status %d"), + status); + csr_roam_complete(mac_ctx, eCsrJoinFailure, NULL); + } +} + +/** + * csr_check_profile_in_scan_cache() - finds if roam profile is present in scan + * cache or not + * @pMac: mac global context + * @scan_filter: out param, scan filter + * @neighbor_roam_info: roam info struct + * @hBSSList: scan result + * + * Return: true if found else false. + */ +static bool +csr_check_profile_in_scan_cache(tpAniSirGlobal mac_ctx, + tCsrScanResultFilter **scan_filter, + tpCsrNeighborRoamControlInfo neighbor_roam_info, + tScanResultHandle *hBSSList) +{ + QDF_STATUS status; + *scan_filter = qdf_mem_malloc(sizeof(tCsrScanResultFilter)); + if (NULL == *scan_filter) { + sms_log(mac_ctx, LOGE, FL("alloc for ScanFilter failed.")); + return false; + } + (*scan_filter)->scan_filter_for_roam = 1; + status = csr_roam_prepare_filter_from_profile(mac_ctx, + &neighbor_roam_info->csrNeighborRoamProfile, + *scan_filter); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sms_log(mac_ctx, LOGE, + FL("failed to prepare scan filter, status %d"), + status); + return false; + } + status = csr_scan_get_result(mac_ctx, *scan_filter, hBSSList); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sms_log(mac_ctx, LOGE, + FL("csr_scan_get_result failed, status %d"), + status); + return false; + } + return true; +} + +static +void csr_roam_roaming_state_disassoc_rsp_processor(tpAniSirGlobal pMac, + tSirSmeDisassocRsp *pSmeRsp) +{ + tScanResultHandle hBSSList; + tCsrRoamInfo roamInfo; + tCsrScanResultFilter *pScanFilter = NULL; + uint32_t roamId = 0; + tCsrRoamProfile *pCurRoamProfile = NULL; + QDF_STATUS status; + uint32_t sessionId; + tCsrRoamSession *pSession; + tpCsrNeighborRoamControlInfo pNeighborRoamInfo = NULL; + tSirSmeDisassocRsp SmeDisassocRsp; + + csr_ser_des_unpack_diassoc_rsp((uint8_t *) pSmeRsp, &SmeDisassocRsp); + sessionId = SmeDisassocRsp.sessionId; + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, FL("sessionId %d"), + sessionId); + + if (csr_is_conn_state_infra(pMac, sessionId)) { + pMac->roam.roamSession[sessionId].connectState = + eCSR_ASSOC_STATE_TYPE_NOT_CONNECTED; + } + + pSession = CSR_GET_SESSION(pMac, sessionId); + if (!pSession) { + sms_log(pMac, LOGE, FL("session %d not found"), sessionId); + return; + } + + if (CSR_IS_ROAM_SUBSTATE_DISASSOC_NO_JOIN(pMac, sessionId)) { + sms_log(pMac, LOG2, "***eCsrNothingToJoin***"); + csr_roam_complete(pMac, eCsrNothingToJoin, NULL); + } else if (CSR_IS_ROAM_SUBSTATE_DISASSOC_FORCED(pMac, sessionId) || + CSR_IS_ROAM_SUBSTATE_DISASSOC_REQ(pMac, sessionId)) { + if (eSIR_SME_SUCCESS == SmeDisassocRsp.statusCode) { + sms_log(pMac, LOG2, + FL("CSR force disassociated successful")); + /* + * A callback to HDD will be issued from + * csr_roam_complete so no need to do anything here + */ + } + csr_roam_complete(pMac, eCsrNothingToJoin, NULL); + } else if (CSR_IS_ROAM_SUBSTATE_DISASSOC_HO(pMac, sessionId)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + FL("CSR SmeDisassocReq due to HO on session %d"), + sessionId); + pNeighborRoamInfo = &pMac->roam.neighborRoamInfo[sessionId]; + /* + * First ensure if the roam profile is in the scan cache. + * If not, post a reassoc failure and disconnect. + */ + if (!csr_check_profile_in_scan_cache(pMac, &pScanFilter, + pNeighborRoamInfo, &hBSSList)) + goto POST_ROAM_FAILURE; + + /* + * After ensuring that the roam profile is in the scan result + * list, dequeue the command from the active list. + */ + csr_dequeue_command(pMac); + + /* notify HDD about handoff and provide the BSSID too */ + roamInfo.reasonCode = eCsrRoamReasonBetterAP; + + qdf_copy_macaddr(&roamInfo.bssid, + pNeighborRoamInfo->csrNeighborRoamProfile.BSSIDs.bssid); + + csr_roam_call_callback(pMac, sessionId, &roamInfo, 0, + eCSR_ROAM_ROAMING_START, + eCSR_ROAM_RESULT_NONE); + + /* + * Copy the connected profile to apply the same for this + * connection as well + */ + pCurRoamProfile = qdf_mem_malloc(sizeof(tCsrRoamProfile)); + if (pCurRoamProfile != NULL) { + /* + * notify sub-modules like QoS etc. that handoff + * happening + */ + sme_qos_csr_event_ind(pMac, sessionId, + SME_QOS_CSR_HANDOFF_ASSOC_REQ, + NULL); + csr_roam_copy_profile(pMac, pCurRoamProfile, + pSession->pCurRoamProfile); + /* make sure to put it at the head of the cmd queue */ + status = csr_roam_issue_connect(pMac, sessionId, + pCurRoamProfile, hBSSList, + eCsrSmeIssuedAssocToSimilarAP, + roamId, true, false); + if (!QDF_IS_STATUS_SUCCESS(status)) + sms_log(pMac, LOGE, + FL("issue_connect failed. status %d"), + status); + + csr_release_profile(pMac, pCurRoamProfile); + qdf_mem_free(pCurRoamProfile); + csr_free_scan_filter(pMac, pScanFilter); + qdf_mem_free(pScanFilter); + return; + } else { + csr_scan_result_purge(pMac, hBSSList); + } + +POST_ROAM_FAILURE: + csr_post_roam_failure(pMac, sessionId, &roamInfo, + pScanFilter, pCurRoamProfile); + } /* else if ( CSR_IS_ROAM_SUBSTATE_DISASSOC_HO( pMac ) ) */ + else if (CSR_IS_ROAM_SUBSTATE_REASSOC_FAIL(pMac, sessionId)) { + /* Disassoc due to Reassoc failure falls into this codepath */ + csr_roam_complete(pMac, eCsrJoinFailure, NULL); + } else { + if (eSIR_SME_SUCCESS == SmeDisassocRsp.statusCode) { + /* + * Successfully disassociated from the 'old' Bss. + * We get Disassociate response in three conditions. + * 1) The case where we are disasociating from an Infra + * Bss to start an IBSS. + * 2) When we are disassociating from an Infra Bss to + * join an IBSS or a new infra network. + * 3) Where we are doing an Infra to Infra roam between + * networks with different SSIDs. + * In all cases, we set the new Bss configuration here + * and attempt to join + */ + sms_log(pMac, LOG2, + FL("Disassociated successfully")); + } else { + sms_log(pMac, LOGE, + FL("DisassocReq failed, statusCode= 0x%08X"), + SmeDisassocRsp.statusCode); + } + /* We are not done yet. Get the data and continue roaming */ + csr_roam_reissue_roam_command(pMac); + } +} + +static void csr_roam_roaming_state_deauth_rsp_processor(tpAniSirGlobal pMac, + tSirSmeDeauthRsp *pSmeRsp) +{ + tSirResultCodes statusCode; + /* No one is sending eWNI_SME_DEAUTH_REQ to PE. */ + sms_log(pMac, LOGW, FL("is no-op")); + statusCode = csr_get_de_auth_rsp_status_code(pSmeRsp); + pMac->roam.deauthRspStatus = statusCode; + if (CSR_IS_ROAM_SUBSTATE_DEAUTH_REQ(pMac, pSmeRsp->sessionId)) { + csr_roam_complete(pMac, eCsrNothingToJoin, NULL); + } else { + if (eSIR_SME_SUCCESS == statusCode) { + /* Successfully deauth from the 'old' Bss... */ + /* */ + sms_log(pMac, LOG2, + "CSR SmeDeauthReq disassociated Successfully"); + } else { + sms_log(pMac, LOGW, + "SmeDeauthReq failed with statusCode= 0x%08X", + statusCode); + } + /* We are not done yet. Get the data and continue roaming */ + csr_roam_reissue_roam_command(pMac); + } +} + +static void csr_roam_roaming_state_start_bss_rsp_processor(tpAniSirGlobal pMac, + tSirSmeStartBssRsp * + pSmeStartBssRsp) +{ + eCsrRoamCompleteResult result; + + if (eSIR_SME_SUCCESS == pSmeStartBssRsp->statusCode) { + sms_log(pMac, LOGW, "SmeStartBssReq Successful"); + result = eCsrStartBssSuccess; + } else { + sms_log(pMac, LOGW, + "SmeStartBssReq failed with statusCode= 0x%08X", + pSmeStartBssRsp->statusCode); + /* Let csr_roam_complete decide what to do */ + result = eCsrStartBssFailure; + } + csr_roam_complete(pMac, result, pSmeStartBssRsp); +} + +/** + * csr_roaming_state_msg_processor() - process roaming messages + * @pMac: mac global context + * @pMsgBuf: message buffer + * + * We need to be careful on whether to cast pMsgBuf (pSmeRsp) to other type of + * strucutres. It depends on how the message is constructed. If the message is + * sent by lim_send_sme_rsp, the pMsgBuf is only a generic response and can only + * be used as pointer to tSirSmeRsp. For the messages where sender allocates + * memory for specific structures, then it can be cast accordingly. + * + * Return: status of operation + */ +void csr_roaming_state_msg_processor(tpAniSirGlobal pMac, void *pMsgBuf) +{ + tSirSmeRsp *pSmeRsp; + tSmeIbssPeerInd *pIbssPeerInd; + tCsrRoamInfo roamInfo; + pSmeRsp = (tSirSmeRsp *) pMsgBuf; + sms_log(pMac, LOG2, FL("Message %d[0x%04X] received in substate %s"), + pSmeRsp->messageType, pSmeRsp->messageType, + mac_trace_getcsr_roam_sub_state( + pMac->roam.curSubState[pSmeRsp->sessionId])); + + switch (pSmeRsp->messageType) { + + case eWNI_SME_JOIN_RSP: + /* in Roaming state, process the Join response message... */ + if (CSR_IS_ROAM_SUBSTATE_JOIN_REQ(pMac, pSmeRsp->sessionId)) + /* We sent a JOIN_REQ */ + csr_roam_join_rsp_processor(pMac, + (tSirSmeJoinRsp *) pSmeRsp); + break; + case eWNI_SME_REASSOC_RSP: + /* or the Reassociation response message... */ + if (CSR_IS_ROAM_SUBSTATE_REASSOC_REQ(pMac, pSmeRsp->sessionId)) + csr_roam_roaming_state_reassoc_rsp_processor(pMac, + (tpSirSmeJoinRsp) pSmeRsp); + break; + case eWNI_SME_STOP_BSS_RSP: + /* or the Stop Bss response message... */ + csr_roam_roaming_state_stop_bss_rsp_processor(pMac, pSmeRsp); + break; + case eWNI_SME_DISASSOC_RSP: + /* or the Disassociate response message... */ + if (CSR_IS_ROAM_SUBSTATE_DISASSOC_REQ(pMac, pSmeRsp->sessionId) + || CSR_IS_ROAM_SUBSTATE_DISASSOC_NO_JOIN(pMac, + pSmeRsp->sessionId) + || CSR_IS_ROAM_SUBSTATE_REASSOC_FAIL(pMac, + pSmeRsp->sessionId) + || CSR_IS_ROAM_SUBSTATE_DISASSOC_FORCED(pMac, + pSmeRsp->sessionId) + || CSR_IS_ROAM_SUBSTATE_DISCONNECT_CONTINUE(pMac, + pSmeRsp->sessionId) + || CSR_IS_ROAM_SUBSTATE_DISASSOC_HO(pMac, + pSmeRsp->sessionId)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + FL("eWNI_SME_DISASSOC_RSP subState = %s"), + mac_trace_getcsr_roam_sub_state( + pMac->roam.curSubState[pSmeRsp->sessionId])); + csr_roam_roaming_state_disassoc_rsp_processor(pMac, + (tSirSmeDisassocRsp *) pSmeRsp); + } + break; + case eWNI_SME_DEAUTH_RSP: + /* or the Deauthentication response message... */ + if (CSR_IS_ROAM_SUBSTATE_DEAUTH_REQ(pMac, pSmeRsp->sessionId)) { + csr_remove_cmd_from_pending_list(pMac, + pSmeRsp->sessionId, + INVALID_SCAN_ID, + &pMac->sme.smeCmdPendingList, + eSmeCommandWmStatusChange); + csr_remove_cmd_from_pending_list(pMac, + pSmeRsp->sessionId, + INVALID_SCAN_ID, + &pMac->roam.roamCmdPendingList, + eSmeCommandWmStatusChange); + csr_roam_roaming_state_deauth_rsp_processor(pMac, + (tSirSmeDeauthRsp *) pSmeRsp); + } + break; + case eWNI_SME_START_BSS_RSP: + /* or the Start BSS response message... */ + if (CSR_IS_ROAM_SUBSTATE_START_BSS_REQ(pMac, + pSmeRsp->sessionId)) + csr_roam_roaming_state_start_bss_rsp_processor(pMac, + (tSirSmeStartBssRsp *) pSmeRsp); + break; + /* In case CSR issues STOP_BSS, we need to tell HDD about peer departed + * becasue PE is removing them + */ + case eWNI_SME_IBSS_PEER_DEPARTED_IND: + pIbssPeerInd = (tSmeIbssPeerInd *) pSmeRsp; + sms_log(pMac, LOGE, + FL("Peer departed ntf from LIM in joining state")); + qdf_mem_set(&roamInfo, sizeof(tCsrRoamInfo), 0); + roamInfo.staId = (uint8_t) pIbssPeerInd->staId; + roamInfo.ucastSig = (uint8_t) pIbssPeerInd->ucastSig; + roamInfo.bcastSig = (uint8_t) pIbssPeerInd->bcastSig; + qdf_copy_macaddr(&roamInfo.peerMac, &pIbssPeerInd->peer_addr); + csr_roam_call_callback(pMac, pSmeRsp->sessionId, &roamInfo, 0, + eCSR_ROAM_CONNECT_STATUS_UPDATE, + eCSR_ROAM_RESULT_IBSS_PEER_DEPARTED); + break; + case eWNI_SME_GET_RSSI_REQ: + { + tAniGetRssiReq *pGetRssiReq = (tAniGetRssiReq *) pMsgBuf; + if (NULL != pGetRssiReq->rssiCallback) + ((tCsrRssiCallback) pGetRssiReq->rssiCallback) + (pGetRssiReq->lastRSSI, pGetRssiReq->staId, + pGetRssiReq->pDevContext); + else + sms_log(pMac, LOGE, + FL("pGetRssiReq->rssiCallback is NULL")); + } + break; + default: + sms_log(pMac, LOG1, + FL("Unexpected message type = %d[0x%X] received in substate %s"), + pSmeRsp->messageType, pSmeRsp->messageType, + mac_trace_getcsr_roam_sub_state( + pMac->roam.curSubState[pSmeRsp->sessionId])); + /* If we are connected, check the link status change */ + if (!csr_is_conn_state_disconnected(pMac, pSmeRsp->sessionId)) + csr_roam_check_for_link_status_change(pMac, pSmeRsp); + break; + } +} + +void csr_roam_joined_state_msg_processor(tpAniSirGlobal pMac, void *pMsgBuf) +{ + tSirSmeRsp *pSirMsg = (tSirSmeRsp *) pMsgBuf; + switch (pSirMsg->messageType) { + case eWNI_SME_GET_STATISTICS_RSP: + sms_log(pMac, LOG2, FL("Stats rsp from PE")); + csr_roam_stats_rsp_processor(pMac, pSirMsg); + break; + case eWNI_SME_UPPER_LAYER_ASSOC_CNF: + { + tCsrRoamSession *pSession; + tSirSmeAssocIndToUpperLayerCnf *pUpperLayerAssocCnf; + tCsrRoamInfo roamInfo; + tCsrRoamInfo *pRoamInfo = NULL; + uint32_t sessionId; + QDF_STATUS status; + sms_log(pMac, LOG1, + FL + ("ASSOCIATION confirmation can be given to upper layer ")); + qdf_mem_set(&roamInfo, sizeof(tCsrRoamInfo), 0); + pRoamInfo = &roamInfo; + pUpperLayerAssocCnf = + (tSirSmeAssocIndToUpperLayerCnf *) pMsgBuf; + status = + csr_roam_get_session_id_from_bssid(pMac, + (struct qdf_mac_addr *) + pUpperLayerAssocCnf-> + bssId, &sessionId); + pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!pSession) { + sms_log(pMac, LOGE, + FL(" session %d not found "), + sessionId); + return; + } + + pRoamInfo->statusCode = eSIR_SME_SUCCESS; /* send the status code as Success */ + pRoamInfo->u.pConnectedProfile = + &pSession->connectedProfile; + pRoamInfo->staId = (uint8_t) pUpperLayerAssocCnf->aid; + pRoamInfo->rsnIELen = + (uint8_t) pUpperLayerAssocCnf->rsnIE.length; + pRoamInfo->prsnIE = + pUpperLayerAssocCnf->rsnIE.rsnIEdata; +#ifdef FEATURE_WLAN_WAPI + pRoamInfo->wapiIELen = + (uint8_t) pUpperLayerAssocCnf->wapiIE.length; + pRoamInfo->pwapiIE = + pUpperLayerAssocCnf->wapiIE.wapiIEdata; +#endif + pRoamInfo->addIELen = + (uint8_t) pUpperLayerAssocCnf->addIE.length; + pRoamInfo->paddIE = + pUpperLayerAssocCnf->addIE.addIEdata; + qdf_mem_copy(pRoamInfo->peerMac.bytes, + pUpperLayerAssocCnf->peerMacAddr, + sizeof(tSirMacAddr)); + qdf_mem_copy(&pRoamInfo->bssid, + pUpperLayerAssocCnf->bssId, + sizeof(struct qdf_mac_addr)); + pRoamInfo->wmmEnabledSta = + pUpperLayerAssocCnf->wmmEnabledSta; + pRoamInfo->timingMeasCap = + pUpperLayerAssocCnf->timingMeasCap; + qdf_mem_copy(&pRoamInfo->chan_info, + &pUpperLayerAssocCnf->chan_info, + sizeof(tSirSmeChanInfo)); + if (CSR_IS_INFRA_AP(pRoamInfo->u.pConnectedProfile)) { + pMac->roam.roamSession[sessionId].connectState = + eCSR_ASSOC_STATE_TYPE_INFRA_CONNECTED; + pRoamInfo->fReassocReq = + pUpperLayerAssocCnf->reassocReq; + status = + csr_roam_call_callback(pMac, sessionId, + pRoamInfo, 0, + eCSR_ROAM_INFRA_IND, + eCSR_ROAM_RESULT_INFRA_ASSOCIATION_CNF); + } + } + break; + default: + csr_roam_check_for_link_status_change(pMac, pSirMsg); + break; + } +} + +QDF_STATUS csr_roam_issue_set_context_req(tpAniSirGlobal pMac, + uint32_t sessionId, + eCsrEncryptionType EncryptType, + tSirBssDescription *pBssDescription, + tSirMacAddr *bssId, bool addKey, + bool fUnicast, + tAniKeyDirection aniKeyDirection, + uint8_t keyId, uint16_t keyLength, + uint8_t *pKey, uint8_t paeRole) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tAniEdType edType; + + sms_log(pMac, LOG1, + FL("sessionId %d EncryptType %d"), sessionId, EncryptType); + + if (eCSR_ENCRYPT_TYPE_UNKNOWN == EncryptType) { + EncryptType = eCSR_ENCRYPT_TYPE_NONE; + } + + edType = csr_translate_encrypt_type_to_ed_type(EncryptType); + + /* + * Allow 0 keys to be set for the non-WPA encrypt types. For WPA encrypt + * types, the num keys must be non-zero or LIM will reject the set + * context (assumes the SET_CONTEXT does not occur until the keys are + * distrubuted). + */ + if (CSR_IS_ENC_TYPE_STATIC(EncryptType) || addKey) { + tCsrRoamSetKey setKey; + setKey.encType = EncryptType; + setKey.keyDirection = aniKeyDirection; + qdf_mem_copy(&setKey.peerMac, bssId, sizeof(struct qdf_mac_addr)); + /* 0 for supplicant */ + setKey.paeRole = paeRole; + /* Key index */ + setKey.keyId = keyId; + setKey.keyLength = keyLength; + if (keyLength) { + qdf_mem_copy(setKey.Key, pKey, keyLength); + } + status = csr_roam_issue_set_key_command(pMac, sessionId, + &setKey, 0); + } + return status; +} + +/** + * csr_update_key_cmd() - update key info in set key command + * @mac_ctx: mac global context + * @session: roam session + * @set_key: input set key command + * @set_key_cmd: set key command to update + * @enqueue_cmd: indicates if command need to be enqueued to sme + * + * This function will validate the key length, adjust if too long. Tt will + * update bool enqueue_cmd, to false if some error has occured key are local. + * + * Return: status of operation + */ +static QDF_STATUS +csr_update_key_cmd(tpAniSirGlobal mac_ctx, tCsrRoamSession *session, + tCsrRoamSetKey *set_key, tSmeCmd *set_key_cmd, + bool *enqueue_cmd) +{ + switch (set_key->encType) { + case eCSR_ENCRYPT_TYPE_WEP40: + case eCSR_ENCRYPT_TYPE_WEP40_STATICKEY: + /* KeyLength maybe 0 for static WEP */ + if (set_key->keyLength) { + if (set_key->keyLength < CSR_WEP40_KEY_LEN) { + sms_log(mac_ctx, LOGW, + FL("Invalid WEP40 keylength [= %d]"), + set_key->keyLength); + *enqueue_cmd = false; + return QDF_STATUS_E_INVAL; + } + + set_key_cmd->u.setKeyCmd.keyLength = CSR_WEP40_KEY_LEN; + qdf_mem_copy(set_key_cmd->u.setKeyCmd.Key, set_key->Key, + CSR_WEP40_KEY_LEN); + } + *enqueue_cmd = true; + break; + case eCSR_ENCRYPT_TYPE_WEP104: + case eCSR_ENCRYPT_TYPE_WEP104_STATICKEY: + /* KeyLength maybe 0 for static WEP */ + if (set_key->keyLength) { + if (set_key->keyLength < CSR_WEP104_KEY_LEN) { + sms_log(mac_ctx, LOGW, + FL("Invalid WEP104 keylength [= %d]"), + set_key->keyLength); + *enqueue_cmd = false; + return QDF_STATUS_E_INVAL; + } + + set_key_cmd->u.setKeyCmd.keyLength = CSR_WEP104_KEY_LEN; + qdf_mem_copy(set_key_cmd->u.setKeyCmd.Key, set_key->Key, + CSR_WEP104_KEY_LEN); + } + *enqueue_cmd = true; + break; + case eCSR_ENCRYPT_TYPE_TKIP: + if (set_key->keyLength < CSR_TKIP_KEY_LEN) { + sms_log(mac_ctx, LOGW, + FL("Invalid TKIP keylength [= %d]"), + set_key->keyLength); + *enqueue_cmd = false; + return QDF_STATUS_E_INVAL; + } + set_key_cmd->u.setKeyCmd.keyLength = CSR_TKIP_KEY_LEN; + qdf_mem_copy(set_key_cmd->u.setKeyCmd.Key, set_key->Key, + CSR_TKIP_KEY_LEN); + *enqueue_cmd = true; + break; + case eCSR_ENCRYPT_TYPE_AES: + if (set_key->keyLength < CSR_AES_KEY_LEN) { + sms_log(mac_ctx, LOGW, + FL("Invalid AES/CCMP keylength [= %d]"), + set_key->keyLength); + *enqueue_cmd = false; + return QDF_STATUS_E_INVAL; + } + set_key_cmd->u.setKeyCmd.keyLength = CSR_AES_KEY_LEN; + qdf_mem_copy(set_key_cmd->u.setKeyCmd.Key, set_key->Key, + CSR_AES_KEY_LEN); + *enqueue_cmd = true; + break; +#ifdef FEATURE_WLAN_WAPI + case eCSR_ENCRYPT_TYPE_WPI: + if (set_key->keyLength < CSR_WAPI_KEY_LEN) { + sms_log(mac_ctx, LOGW, + FL("Invalid WAPI keylength [= %d]"), + set_key->keyLength); + *enqueue_cmd = false; + return QDF_STATUS_E_INVAL; + } + set_key_cmd->u.setKeyCmd.keyLength = CSR_WAPI_KEY_LEN; + qdf_mem_copy(set_key_cmd->u.setKeyCmd.Key, set_key->Key, + CSR_WAPI_KEY_LEN); + if (session->pCurRoamProfile) { + session->pCurRoamProfile->negotiatedUCEncryptionType = + eCSR_ENCRYPT_TYPE_WPI; + } else { + sms_log(mac_ctx, LOGW, + FL("pCurRoamProfile is NULL.")); + *enqueue_cmd = false; + return QDF_STATUS_E_INVAL; + } + *enqueue_cmd = true; + break; +#endif /* FEATURE_WLAN_WAPI */ +#ifdef FEATURE_WLAN_ESE + case eCSR_ENCRYPT_TYPE_KRK: + /* no need to enqueue KRK key request, since they are local */ + *enqueue_cmd = false; + if (set_key->keyLength < CSR_KRK_KEY_LEN) { + sms_log(mac_ctx, LOGW, + FL("Invalid KRK keylength [= %d]"), + set_key->keyLength); + return QDF_STATUS_E_INVAL; + } + qdf_mem_copy(session->eseCckmInfo.krk, set_key->Key, + CSR_KRK_KEY_LEN); + session->eseCckmInfo.reassoc_req_num = 1; + session->eseCckmInfo.krk_plumbed = true; + break; +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + case eCSR_ENCRYPT_TYPE_BTK: + /* no need to enqueue KRK key request, since they are local */ + *enqueue_cmd = false; + if (set_key->keyLength < SIR_BTK_KEY_LEN) { + sms_log(mac_ctx, LOGW, + FL("LFR3:Invalid BTK keylength [= %d]"), + set_key->keyLength); + return QDF_STATUS_E_INVAL; + } + qdf_mem_copy(session->eseCckmInfo.btk, set_key->Key, + SIR_BTK_KEY_LEN); + break; +#endif +#endif /* FEATURE_WLAN_ESE */ +#ifdef WLAN_FEATURE_11W + /* Check for 11w BIP */ + case eCSR_ENCRYPT_TYPE_AES_CMAC: + if (set_key->keyLength < CSR_AES_KEY_LEN) { + sms_log(mac_ctx, LOGW, + FL("Invalid AES/CCMP keylength [= %d]"), + set_key->keyLength); + *enqueue_cmd = false; + return QDF_STATUS_E_INVAL; + } + set_key_cmd->u.setKeyCmd.keyLength = CSR_AES_KEY_LEN; + qdf_mem_copy(set_key_cmd->u.setKeyCmd.Key, set_key->Key, + CSR_AES_KEY_LEN); + *enqueue_cmd = true; + break; +#endif /* WLAN_FEATURE_11W */ + default: + /* for open security also we want to enqueue command */ + *enqueue_cmd = true; + return QDF_STATUS_SUCCESS; + } /* end of switch */ + return QDF_STATUS_SUCCESS; +} + + +static QDF_STATUS csr_roam_issue_set_key_command(tpAniSirGlobal pMac, + uint32_t sessionId, + tCsrRoamSetKey *pSetKey, + uint32_t roamId) +{ + QDF_STATUS status = QDF_STATUS_E_INVAL; + bool enqueue_cmd = true; + tSmeCmd *pCommand = NULL; +#if defined(FEATURE_WLAN_ESE) || defined (FEATURE_WLAN_WAPI) + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + if (NULL == pSession) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("session %d not found"), sessionId); + return QDF_STATUS_E_FAILURE; + } +#endif /* FEATURE_WLAN_ESE */ + + pCommand = csr_get_command_buffer(pMac); + if (NULL == pCommand) { + sms_log(pMac, LOGE, FL(" fail to get command buffer")); + return QDF_STATUS_E_RESOURCES; + } + qdf_mem_zero(pCommand, sizeof(tSmeCmd)); + pCommand->command = eSmeCommandSetKey; + pCommand->sessionId = (uint8_t) sessionId; + /* + * following function will validate the key length, Adjust if too long. + * for static WEP the keys are not set thru' SetContextReq + * + * it will update bool enqueue_cmd, to false if some error has occured + * key are local. enqueue sme command only if enqueue_cmd is true + * status is indication of success or failure and will be returned to + * called of current function if command is not enqueued due to key req + * being local + */ + status = csr_update_key_cmd(pMac, pSession, pSetKey, + pCommand, &enqueue_cmd); + if (enqueue_cmd) { + pCommand->u.setKeyCmd.roamId = roamId; + pCommand->u.setKeyCmd.encType = pSetKey->encType; + pCommand->u.setKeyCmd.keyDirection = pSetKey->keyDirection; + qdf_copy_macaddr(&pCommand->u.setKeyCmd.peermac, + &pSetKey->peerMac); + /* 0 for supplicant */ + pCommand->u.setKeyCmd.paeRole = pSetKey->paeRole; + pCommand->u.setKeyCmd.keyId = pSetKey->keyId; + qdf_mem_copy(pCommand->u.setKeyCmd.keyRsc, pSetKey->keyRsc, + CSR_MAX_RSC_LEN); + /* + * Always put set key to the head of the Q because it is the + * only thing to get executed in case of WT_KEY state + */ + + status = csr_queue_sme_command(pMac, pCommand, true); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOGE, + FL("fail to send message status = %d"), status); + /* update to false so that command can be freed */ + enqueue_cmd = false; + } + } + + /* + * Free the command if enqueue_cmd == false: + * this means that command was not enqueued because either there has + * been a failure, or it is a "local" operation like the set ESE CCKM + * KRK key. + */ + if (false == enqueue_cmd) + csr_release_command_set_key(pMac, pCommand); + + return status; +} + +QDF_STATUS csr_roam_process_set_key_command(tpAniSirGlobal pMac, tSmeCmd *pCommand) +{ + QDF_STATUS status; + uint8_t numKeys = (pCommand->u.setKeyCmd.keyLength) ? 1 : 0; + tAniEdType edType = + csr_translate_encrypt_type_to_ed_type(pCommand->u.setKeyCmd.encType); + bool fUnicast = + (pCommand->u.setKeyCmd.peermac.bytes[0] == 0xFF) ? false : true; + uint32_t sessionId = pCommand->sessionId; +#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + WLAN_HOST_DIAG_EVENT_DEF(setKeyEvent, + host_event_wlan_security_payload_type); + + if (NULL == pSession) { + sms_log(pMac, LOGE, FL(" session %d not found "), sessionId); + return QDF_STATUS_E_FAILURE; + } + + if (eSIR_ED_NONE != edType) { + qdf_mem_set(&setKeyEvent, + sizeof(host_event_wlan_security_payload_type), 0); + if (qdf_is_macaddr_group(&pCommand->u.setKeyCmd.peermac)) { + setKeyEvent.eventId = WLAN_SECURITY_EVENT_SET_BCAST_REQ; + setKeyEvent.encryptionModeMulticast = + (uint8_t) diag_enc_type_from_csr_type(pCommand->u. + setKeyCmd.encType); + setKeyEvent.encryptionModeUnicast = + (uint8_t) diag_enc_type_from_csr_type(pSession-> + connectedProfile. + EncryptionType); + } else { + setKeyEvent.eventId = + WLAN_SECURITY_EVENT_SET_UNICAST_REQ; + setKeyEvent.encryptionModeUnicast = + (uint8_t) diag_enc_type_from_csr_type(pCommand->u. + setKeyCmd.encType); + setKeyEvent.encryptionModeMulticast = + (uint8_t) diag_enc_type_from_csr_type(pSession-> + connectedProfile. + mcEncryptionType); + } + qdf_mem_copy(setKeyEvent.bssid, + pSession->connectedProfile.bssid.bytes, + QDF_MAC_ADDR_SIZE); + if (CSR_IS_ENC_TYPE_STATIC(pCommand->u.setKeyCmd.encType)) { + uint32_t defKeyId; + /* It has to be static WEP here */ + if (IS_SIR_STATUS_SUCCESS + (wlan_cfg_get_int + (pMac, WNI_CFG_WEP_DEFAULT_KEYID, &defKeyId))) { + setKeyEvent.keyId = (uint8_t) defKeyId; + } + } else { + setKeyEvent.keyId = pCommand->u.setKeyCmd.keyId; + } + setKeyEvent.authMode = + (uint8_t) diag_auth_type_from_csr_type(pSession-> + connectedProfile. + AuthType); + WLAN_HOST_DIAG_EVENT_REPORT(&setKeyEvent, EVENT_WLAN_SECURITY); + } +#endif /* FEATURE_WLAN_DIAG_SUPPORT_CSR */ + if (csr_is_set_key_allowed(pMac, sessionId)) { + status = csr_send_mb_set_context_req_msg(pMac, sessionId, + pCommand->u. + setKeyCmd.peermac, + numKeys, + edType, fUnicast, + pCommand->u.setKeyCmd. + keyDirection, + pCommand->u.setKeyCmd.keyId, + pCommand->u.setKeyCmd. + keyLength, + pCommand->u.setKeyCmd.Key, + pCommand->u.setKeyCmd. + paeRole, + pCommand->u.setKeyCmd. + keyRsc); + } else { + sms_log(pMac, LOGW, FL(" cannot process not connected")); + /* Set this status so the error handling take care of the case. */ + status = QDF_STATUS_CSR_WRONG_STATE; + } + if (!QDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOGE, FL(" error status %d"), status); + csr_roam_call_callback(pMac, sessionId, NULL, + pCommand->u.setKeyCmd.roamId, + eCSR_ROAM_SET_KEY_COMPLETE, + eCSR_ROAM_RESULT_FAILURE); +#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR + if (eSIR_ED_NONE != edType) { + if (qdf_is_macaddr_group( + &pCommand->u.setKeyCmd.peermac)) { + setKeyEvent.eventId = + WLAN_SECURITY_EVENT_SET_BCAST_RSP; + } else { + setKeyEvent.eventId = + WLAN_SECURITY_EVENT_SET_UNICAST_RSP; + } + setKeyEvent.status = WLAN_SECURITY_STATUS_FAILURE; + WLAN_HOST_DIAG_EVENT_REPORT(&setKeyEvent, + EVENT_WLAN_SECURITY); + } +#endif /* FEATURE_WLAN_DIAG_SUPPORT_CSR */ + } + return status; +} + +QDF_STATUS csr_roam_set_key(tpAniSirGlobal pMac, uint32_t sessionId, + tCsrRoamSetKey *pSetKey, uint32_t roamId) +{ + QDF_STATUS status; + + if (!csr_is_set_key_allowed(pMac, sessionId)) { + status = QDF_STATUS_CSR_WRONG_STATE; + } else { + status = + csr_roam_issue_set_key_command(pMac, sessionId, pSetKey, roamId); + } + return status; +} + +/* + Prepare a filter base on a profile for parsing the scan results. + Upon successful return, caller MUST call csr_free_scan_filter on + pScanFilter when it is done with the filter. + */ +QDF_STATUS +csr_roam_prepare_filter_from_profile(tpAniSirGlobal mac_ctx, + tCsrRoamProfile *profile, + tCsrScanResultFilter *scan_fltr) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + uint32_t size = 0; + uint8_t idx = 0; + tCsrChannelInfo *fltr_ch_info = &scan_fltr->ChannelInfo; + tCsrChannelInfo *profile_ch_info = &profile->ChannelInfo; + struct roam_ext_params *roam_params; + uint8_t i; + + roam_params = &mac_ctx->roam.configParam.roam_params; + + if (profile->BSSIDs.numOfBSSIDs) { + size = sizeof(struct qdf_mac_addr) * profile->BSSIDs.numOfBSSIDs; + scan_fltr->BSSIDs.bssid = qdf_mem_malloc(size); + if (NULL == scan_fltr->BSSIDs.bssid) { + status = QDF_STATUS_E_NOMEM; + goto free_filter; + } + scan_fltr->BSSIDs.numOfBSSIDs = profile->BSSIDs.numOfBSSIDs; + qdf_mem_copy(scan_fltr->BSSIDs.bssid, + profile->BSSIDs.bssid, size); + } + + if (profile->SSIDs.numOfSSIDs) { + scan_fltr->SSIDs.numOfSSIDs = profile->SSIDs.numOfSSIDs; + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + FL("No of Allowed List:%d"), + roam_params->num_ssid_allowed_list); + if (scan_fltr->scan_filter_for_roam + && roam_params->num_ssid_allowed_list) { + scan_fltr->SSIDs.numOfSSIDs = + roam_params->num_ssid_allowed_list; + size = sizeof(tCsrSSIDInfo) * + scan_fltr->SSIDs.numOfSSIDs; + scan_fltr->SSIDs.SSIDList = qdf_mem_malloc(size); + if (NULL == scan_fltr->SSIDs.SSIDList) + status = QDF_STATUS_E_FAILURE; + else + status = QDF_STATUS_SUCCESS; + if (!QDF_IS_STATUS_SUCCESS(status)) + goto free_filter; + for (i = 0; + i < roam_params->num_ssid_allowed_list; + i++) { + qdf_mem_copy((void *) + scan_fltr->SSIDs.SSIDList[i].SSID.ssId, + roam_params->ssid_allowed_list[i].ssId, + roam_params->ssid_allowed_list[i].length); + scan_fltr->SSIDs.SSIDList[i].SSID.length = + roam_params->ssid_allowed_list[i].length; + scan_fltr->SSIDs.SSIDList[i].handoffPermitted = + 1; + scan_fltr->SSIDs.SSIDList[i].ssidHidden = 0; + } + } else { + size = sizeof(tCsrSSIDInfo) * + profile->SSIDs.numOfSSIDs; + scan_fltr->SSIDs.SSIDList = qdf_mem_malloc(size); + if (NULL == scan_fltr->SSIDs.SSIDList) { + status = QDF_STATUS_E_NOMEM; + goto free_filter; + } + qdf_mem_copy(scan_fltr->SSIDs.SSIDList, + profile->SSIDs.SSIDList, size); + } + } + + if (!profile_ch_info->ChannelList + || (profile_ch_info->ChannelList[0] == 0)) { + fltr_ch_info->numOfChannels = 0; + fltr_ch_info->ChannelList = NULL; + } else if (profile_ch_info->numOfChannels) { + fltr_ch_info->numOfChannels = 0; + fltr_ch_info->ChannelList = + qdf_mem_malloc(sizeof(*(fltr_ch_info->ChannelList)) * + profile_ch_info->numOfChannels); + if (NULL == fltr_ch_info->ChannelList) { + status = QDF_STATUS_E_NOMEM; + goto free_filter; + } + + for (idx = 0; idx < profile_ch_info->numOfChannels; idx++) { + if (csr_roam_is_channel_valid(mac_ctx, + profile_ch_info->ChannelList[idx])) { + fltr_ch_info-> + ChannelList[fltr_ch_info->numOfChannels] + = profile_ch_info->ChannelList[idx]; + fltr_ch_info->numOfChannels++; + } else { + sms_log(mac_ctx, LOG1, + FL("Channel (%d) is invalid"), + profile_ch_info->ChannelList[idx]); + } + } + } else { + sms_log(mac_ctx, LOGE, FL("Channel list empty")); + status = QDF_STATUS_E_FAILURE; + goto free_filter; + } + scan_fltr->uapsd_mask = profile->uapsd_mask; + scan_fltr->authType = profile->AuthType; + scan_fltr->EncryptionType = profile->EncryptionType; + scan_fltr->mcEncryptionType = profile->mcEncryptionType; + scan_fltr->BSSType = profile->BSSType; + scan_fltr->phyMode = profile->phyMode; +#ifdef FEATURE_WLAN_WAPI + /* + * check if user asked for WAPI with 11n or auto mode, in that + * case modify the phymode to 11g + */ + if (csr_is_profile_wapi(profile)) { + if (scan_fltr->phyMode & eCSR_DOT11_MODE_11n) + scan_fltr->phyMode &= ~eCSR_DOT11_MODE_11n; + if (scan_fltr->phyMode & eCSR_DOT11_MODE_AUTO) + scan_fltr->phyMode &= ~eCSR_DOT11_MODE_AUTO; + if (!scan_fltr->phyMode) + scan_fltr->phyMode = eCSR_DOT11_MODE_11g; + } +#endif /* FEATURE_WLAN_WAPI */ + /*Save the WPS info */ + scan_fltr->bWPSAssociation = profile->bWPSAssociation; + scan_fltr->bOSENAssociation = profile->bOSENAssociation; + if (profile->countryCode[0]) { + /* + * This causes the matching function to use countryCode as one + * of the criteria. + */ + qdf_mem_copy(scan_fltr->countryCode, profile->countryCode, + WNI_CFG_COUNTRY_CODE_LEN); + } + if (profile->MDID.mdiePresent) { + scan_fltr->MDID.mdiePresent = 1; + scan_fltr->MDID.mobilityDomain = profile->MDID.mobilityDomain; + } + qdf_mem_copy(scan_fltr->bssid_hint.bytes, + profile->bssid_hint.bytes, QDF_MAC_ADDR_SIZE); + +#ifdef WLAN_FEATURE_11W + /* Management Frame Protection */ + scan_fltr->MFPEnabled = profile->MFPEnabled; + scan_fltr->MFPRequired = profile->MFPRequired; + scan_fltr->MFPCapable = profile->MFPCapable; +#endif + scan_fltr->csrPersona = profile->csrPersona; + +free_filter: + if (!QDF_IS_STATUS_SUCCESS(status)) + csr_free_scan_filter(mac_ctx, scan_fltr); + + return status; +} + +static +bool csr_roam_issue_wm_status_change(tpAniSirGlobal pMac, uint32_t sessionId, + eCsrRoamWmStatusChangeTypes Type, + tSirSmeRsp *pSmeRsp) +{ + bool fCommandQueued = false; + tSmeCmd *pCommand; + do { + /* Validate the type is ok... */ + if ((eCsrDisassociated != Type) + && (eCsrDeauthenticated != Type)) + break; + pCommand = csr_get_command_buffer(pMac); + if (!pCommand) { + sms_log(pMac, LOGE, FL(" fail to get command buffer")); + break; + } + /* Change the substate in case it is waiting for key */ + if (CSR_IS_WAIT_FOR_KEY(pMac, sessionId)) { + csr_roam_stop_wait_for_key_timer(pMac); + csr_roam_substate_change(pMac, eCSR_ROAM_SUBSTATE_NONE, + sessionId); + } + pCommand->command = eSmeCommandWmStatusChange; + pCommand->sessionId = (uint8_t) sessionId; + pCommand->u.wmStatusChangeCmd.Type = Type; + if (eCsrDisassociated == Type) { + qdf_mem_copy(&pCommand->u.wmStatusChangeCmd.u. + DisassocIndMsg, pSmeRsp, + sizeof(pCommand->u.wmStatusChangeCmd.u. + DisassocIndMsg)); + } else { + qdf_mem_copy(&pCommand->u.wmStatusChangeCmd.u. + DeauthIndMsg, pSmeRsp, + sizeof(pCommand->u.wmStatusChangeCmd.u. + DeauthIndMsg)); + } + if (QDF_IS_STATUS_SUCCESS + (csr_queue_sme_command(pMac, pCommand, true))) { + fCommandQueued = true; + } else { + sms_log(pMac, LOGE, FL(" fail to send message ")); + csr_release_command_wm_status_change(pMac, pCommand); + } + + /* AP has issued Dissac/Deauth, Set the operating mode value to configured value */ + csr_set_default_dot11_mode(pMac); + } while (0); + return fCommandQueued; +} + +static QDF_STATUS csr_send_snr_request(void *pGetRssiReq) +{ + void *wma_handle; + + wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma_handle) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "wma_handle is NULL"); + return QDF_STATUS_E_FAILURE; + } + + if (QDF_STATUS_SUCCESS != + wma_send_snr_request(wma_handle, pGetRssiReq)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "Failed to Trigger wma stats request"); + return QDF_STATUS_E_FAILURE; + } + + /* dont send success, otherwise call back + * will released with out values */ + return QDF_STATUS_E_BUSY; +} + +static void csr_update_rssi(tpAniSirGlobal pMac, void *pMsg) +{ + int8_t rssi = 0; + tAniGetRssiReq *pGetRssiReq = (tAniGetRssiReq *) pMsg; + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + if (pGetRssiReq) { + if (NULL != pGetRssiReq->p_cds_context) { + qdf_status = csr_send_snr_request(pGetRssiReq); + } else { + sms_log(pMac, LOGE, + FL("pGetRssiReq->p_cds_context is NULL")); + return; + } + + if (NULL != pGetRssiReq->rssiCallback) { + if (qdf_status != QDF_STATUS_E_BUSY) + ((tCsrRssiCallback) (pGetRssiReq->rssiCallback)) + (rssi, pGetRssiReq->staId, + pGetRssiReq->pDevContext); + else + sms_log(pMac, LOG1, + FL + ("rssi request is posted. waiting for reply")); + } else { + sms_log(pMac, LOGE, + FL("pGetRssiReq->rssiCallback is NULL")); + return; + } + } else { + sms_log(pMac, LOGE, FL("pGetRssiReq is NULL")); + } + return; + +} + +static void csr_update_snr(tpAniSirGlobal pMac, void *pMsg) +{ + tAniGetSnrReq *pGetSnrReq = (tAniGetSnrReq *) pMsg; + + if (pGetSnrReq) { + if (QDF_STATUS_SUCCESS != wma_get_snr(pGetSnrReq)) { + sms_log(pMac, LOGE, FL("Error in wma_get_snr")); + return; + } + + } else { + sms_log(pMac, LOGE, FL("pGetSnrReq is NULL")); + } + return; +} + +static QDF_STATUS csr_send_reset_ap_caps_changed(tpAniSirGlobal pMac, + struct qdf_mac_addr *bssId) +{ + tpSirResetAPCapsChange pMsg; + uint16_t len; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + /* Create the message and send to lim */ + len = sizeof(tSirResetAPCapsChange); + pMsg = qdf_mem_malloc(len); + if (NULL == pMsg) + status = QDF_STATUS_E_NOMEM; + else + status = QDF_STATUS_SUCCESS; + + if (QDF_IS_STATUS_SUCCESS(status)) { + pMsg->messageType = eWNI_SME_RESET_AP_CAPS_CHANGED; + pMsg->length = len; + qdf_copy_macaddr(&pMsg->bssId, bssId); + sms_log(pMac, LOG1, + FL("CSR reset caps change for Bssid= " MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(pMsg->bssId.bytes)); + status = cds_send_mb_message_to_mac(pMsg); + } else { + sms_log(pMac, LOGE, FL("Memory allocation failed")); + } + return status; +} + +static void +csr_roam_chk_lnk_assoc_ind(tpAniSirGlobal mac_ctx, tSirSmeRsp *msg_ptr) +{ + tCsrRoamSession *session; + uint32_t sessionId = CSR_SESSION_ID_INVALID; + QDF_STATUS status; + tCsrRoamInfo *roam_info_ptr = NULL; + tSirSmeAssocInd *pAssocInd; + tCsrRoamInfo roam_info; + qdf_mem_set(&roam_info, sizeof(roam_info), 0); + + sms_log(mac_ctx, LOG1, FL("Receive WNI_SME_ASSOC_IND from SME")); + pAssocInd = (tSirSmeAssocInd *) msg_ptr; + status = csr_roam_get_session_id_from_bssid(mac_ctx, + (struct qdf_mac_addr *) pAssocInd->bssId, &sessionId); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sms_log(mac_ctx, LOG1, + FL("Couldn't find session_id for given BSSID")); + return; + } + session = CSR_GET_SESSION(mac_ctx, sessionId); + if (!session) { + sms_log(mac_ctx, LOGE, FL("session %d not found"), sessionId); + return; + } + roam_info_ptr = &roam_info; + /* Required for indicating the frames to upper layer */ + roam_info_ptr->assocReqLength = pAssocInd->assocReqLength; + roam_info_ptr->assocReqPtr = pAssocInd->assocReqPtr; + roam_info_ptr->beaconPtr = pAssocInd->beaconPtr; + roam_info_ptr->beaconLength = pAssocInd->beaconLength; + roam_info_ptr->statusCode = eSIR_SME_SUCCESS; + roam_info_ptr->u.pConnectedProfile = &session->connectedProfile; + roam_info_ptr->staId = (uint8_t) pAssocInd->staId; + roam_info_ptr->rsnIELen = (uint8_t) pAssocInd->rsnIE.length; + roam_info_ptr->prsnIE = pAssocInd->rsnIE.rsnIEdata; +#ifdef FEATURE_WLAN_WAPI + roam_info_ptr->wapiIELen = (uint8_t) pAssocInd->wapiIE.length; + roam_info_ptr->pwapiIE = pAssocInd->wapiIE.wapiIEdata; +#endif + roam_info_ptr->addIELen = (uint8_t) pAssocInd->addIE.length; + roam_info_ptr->paddIE = pAssocInd->addIE.addIEdata; + qdf_mem_copy(roam_info_ptr->peerMac.bytes, + pAssocInd->peerMacAddr, + sizeof(tSirMacAddr)); + qdf_mem_copy(roam_info_ptr->bssid.bytes, + pAssocInd->bssId, + sizeof(struct qdf_mac_addr)); + roam_info_ptr->wmmEnabledSta = pAssocInd->wmmEnabledSta; + roam_info_ptr->timingMeasCap = pAssocInd->timingMeasCap; + qdf_mem_copy(&roam_info_ptr->chan_info, + &pAssocInd->chan_info, + sizeof(tSirSmeChanInfo)); + if (CSR_IS_INFRA_AP(roam_info_ptr->u.pConnectedProfile)) { + if (session->pCurRoamProfile && + CSR_IS_ENC_TYPE_STATIC( + session->pCurRoamProfile->negotiatedUCEncryptionType)) { + /* NO keys... these key parameters don't matter. */ + csr_roam_issue_set_context_req(mac_ctx, sessionId, + session->pCurRoamProfile->negotiatedUCEncryptionType, + session->pConnectBssDesc, + &(roam_info_ptr->peerMac.bytes), + false, true, eSIR_TX_RX, 0, 0, NULL, 0); + roam_info_ptr->fAuthRequired = false; + } else { + roam_info_ptr->fAuthRequired = true; + } + status = csr_roam_call_callback(mac_ctx, sessionId, + roam_info_ptr, 0, eCSR_ROAM_INFRA_IND, + eCSR_ROAM_RESULT_INFRA_ASSOCIATION_IND); + if (!QDF_IS_STATUS_SUCCESS(status)) + /* Refused due to Mac filtering */ + roam_info_ptr->statusCode = eSIR_SME_ASSOC_REFUSED; + } + + /* Send Association completion message to PE */ + status = csr_send_assoc_cnf_msg(mac_ctx, pAssocInd, status); + /* + * send a message to CSR itself just to avoid the EAPOL frames going + * OTA before association response + */ + if (CSR_IS_INFRA_AP(roam_info_ptr->u.pConnectedProfile) + && (roam_info_ptr->statusCode != eSIR_SME_ASSOC_REFUSED)) { + roam_info_ptr->fReassocReq = pAssocInd->reassocReq; + status = csr_send_assoc_ind_to_upper_layer_cnf_msg(mac_ctx, + pAssocInd, status, sessionId); + } +} + +static void +csr_roam_chk_lnk_disassoc_ind(tpAniSirGlobal mac_ctx, tSirSmeRsp *msg_ptr) +{ + tCsrRoamSession *session; + uint32_t sessionId = CSR_SESSION_ID_INVALID; + QDF_STATUS status; + tSirSmeDisassocInd *pDisassocInd; + tSmeCmd *cmd; + + cmd = qdf_mem_malloc(sizeof(*cmd)); + if (NULL == cmd) { + sms_log(mac_ctx, LOGE, + FL("memory allocation failed for size = %zu"), + sizeof(*cmd)); + return; + } + + /* + * Check if AP dis-associated us because of MIC failure. If so, + * then we need to take action immediately and not wait till the + * the WmStatusChange requests is pushed and processed + */ + pDisassocInd = (tSirSmeDisassocInd *) msg_ptr; + status = csr_roam_get_session_id_from_bssid(mac_ctx, + &pDisassocInd->bssid, &sessionId); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sms_log(mac_ctx, LOGE, FL("Session Id not found for BSSID " + MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(pDisassocInd->bssid.bytes)); + qdf_mem_free(cmd); + return; + } + + sms_log(mac_ctx, LOGE, + FL("DISASSOCIATION from peer =" MAC_ADDRESS_STR + " " " reason: %d status: %d session: %d"), + MAC_ADDR_ARRAY(pDisassocInd->peer_macaddr.bytes), + pDisassocInd->reasonCode, + pDisassocInd->statusCode, sessionId); + /* + * If we are in neighbor preauth done state then on receiving + * disassoc or deauth we dont roam instead we just disassoc + * from current ap and then go to disconnected state + * This happens for ESE and 11r FT connections ONLY. + */ + if (csr_roam_is11r_assoc(mac_ctx, sessionId) && + (csr_neighbor_roam_state_preauth_done(mac_ctx, sessionId))) + csr_neighbor_roam_tranistion_preauth_done_to_disconnected( + mac_ctx, sessionId); +#ifdef FEATURE_WLAN_ESE + if (csr_roam_is_ese_assoc(mac_ctx, sessionId) && + (csr_neighbor_roam_state_preauth_done(mac_ctx, sessionId))) + csr_neighbor_roam_tranistion_preauth_done_to_disconnected( + mac_ctx, sessionId); +#endif + if (csr_roam_is_fast_roam_enabled(mac_ctx, sessionId) && + (csr_neighbor_roam_state_preauth_done(mac_ctx, sessionId))) + csr_neighbor_roam_tranistion_preauth_done_to_disconnected( + mac_ctx, sessionId); + session = CSR_GET_SESSION(mac_ctx, sessionId); + if (!session) { + sms_log(mac_ctx, LOGE, FL("session %d not found"), sessionId); + qdf_mem_free(cmd); + return; + } + if (csr_is_conn_state_infra(mac_ctx, sessionId)) + session->connectState = eCSR_ASSOC_STATE_TYPE_NOT_CONNECTED; +#ifndef WLAN_MDM_CODE_REDUCTION_OPT + sme_qos_csr_event_ind(mac_ctx, (uint8_t) sessionId, + SME_QOS_CSR_DISCONNECT_IND, NULL); +#endif + csr_roam_link_down(mac_ctx, sessionId); + csr_roam_issue_wm_status_change(mac_ctx, sessionId, + eCsrDisassociated, msg_ptr); + if (CSR_IS_INFRA_AP(&session->connectedProfile)) { + /* + * STA/P2P client got disassociated so remove any pending + * deauth commands in sme pending list + */ + cmd->command = eSmeCommandRoam; + cmd->sessionId = (uint8_t) sessionId; + cmd->u.roamCmd.roamReason = eCsrForcedDeauthSta; + qdf_mem_copy(cmd->u.roamCmd.peerMac, + pDisassocInd->peer_macaddr.bytes, + QDF_MAC_ADDR_SIZE); + csr_roam_remove_duplicate_command(mac_ctx, sessionId, cmd, + eCsrForcedDeauthSta); + } + qdf_mem_free(cmd); +} + +/** + * csr_roam_send_disconnect_done_indication() - Send disconnect ind to HDD. + * + * @mac_ctx: mac global context + * @msg_ptr: incoming message + * + * This function gives final disconnect event to HDD after all cleanup in + * lower layers is done. + * + * Return: None + */ +static void +csr_roam_send_disconnect_done_indication(tpAniSirGlobal mac_ctx, tSirSmeRsp + *msg_ptr) +{ + struct sir_sme_discon_done_ind *discon_ind = + (struct sir_sme_discon_done_ind *)(msg_ptr); + tCsrRoamInfo roam_info; + tCsrRoamSession *session; + + sms_log(mac_ctx, LOG1, FL("eWNI_SME_DISCONNECT_DONE_IND RC:%d"), + discon_ind->reason_code); + + if (CSR_IS_SESSION_VALID(mac_ctx, discon_ind->session_id)) { + roam_info.reasonCode = discon_ind->reason_code; + roam_info.statusCode = eSIR_SME_STA_NOT_ASSOCIATED; + qdf_mem_copy(roam_info.peerMac.bytes, discon_ind->peer_mac, + ETH_ALEN); + csr_roam_call_callback(mac_ctx, discon_ind->session_id, + &roam_info, 0, eCSR_ROAM_LOSTLINK, + eCSR_ROAM_RESULT_DISASSOC_IND); + session = CSR_GET_SESSION(mac_ctx, discon_ind->session_id); + if (session && + !CSR_IS_INFRA_AP(&session->connectedProfile)) + csr_roam_state_change(mac_ctx, eCSR_ROAMING_STATE_IDLE, + discon_ind->session_id); + + } else + sms_log(mac_ctx, LOGE, FL("Inactive session %d"), + discon_ind->session_id); +} + +static void +csr_roam_chk_lnk_deauth_ind(tpAniSirGlobal mac_ctx, tSirSmeRsp *msg_ptr) +{ + tCsrRoamSession *session; + uint32_t sessionId = CSR_SESSION_ID_INVALID; + QDF_STATUS status; + tSirSmeDeauthInd *pDeauthInd; + tCsrRoamInfo roam_info; + + qdf_mem_set(&roam_info, sizeof(roam_info), 0); + sms_log(mac_ctx, LOG1, FL("DEAUTHENTICATION Indication from MAC")); + pDeauthInd = (tpSirSmeDeauthInd) msg_ptr; + status = csr_roam_get_session_id_from_bssid(mac_ctx, + &pDeauthInd->bssid, + &sessionId); + if (!QDF_IS_STATUS_SUCCESS(status)) + return; + /* If we are in neighbor preauth done state then on receiving + * disassoc or deauth we dont roam instead we just disassoc + * from current ap and then go to disconnected state + * This happens for ESE and 11r FT connections ONLY. + */ + if (csr_roam_is11r_assoc(mac_ctx, sessionId) && + (csr_neighbor_roam_state_preauth_done(mac_ctx, sessionId))) + csr_neighbor_roam_tranistion_preauth_done_to_disconnected( + mac_ctx, sessionId); +#ifdef FEATURE_WLAN_ESE + if (csr_roam_is_ese_assoc(mac_ctx, sessionId) && + (csr_neighbor_roam_state_preauth_done(mac_ctx, sessionId))) + csr_neighbor_roam_tranistion_preauth_done_to_disconnected( + mac_ctx, sessionId); +#endif + if (csr_roam_is_fast_roam_enabled(mac_ctx, sessionId) && + (csr_neighbor_roam_state_preauth_done(mac_ctx, sessionId))) + csr_neighbor_roam_tranistion_preauth_done_to_disconnected( + mac_ctx, sessionId); + session = CSR_GET_SESSION(mac_ctx, sessionId); + if (!session) { + sms_log(mac_ctx, LOGE, FL("session %d not found"), sessionId); + return; + } + + if (csr_is_conn_state_infra(mac_ctx, sessionId)) + session->connectState = eCSR_ASSOC_STATE_TYPE_NOT_CONNECTED; +#ifndef WLAN_MDM_CODE_REDUCTION_OPT + sme_qos_csr_event_ind(mac_ctx, (uint8_t) sessionId, + SME_QOS_CSR_DISCONNECT_IND, NULL); +#endif + csr_roam_link_down(mac_ctx, sessionId); + csr_roam_issue_wm_status_change(mac_ctx, sessionId, + eCsrDeauthenticated, + msg_ptr); +} + +static void +csr_roam_chk_lnk_swt_ch_ind(tpAniSirGlobal mac_ctx, tSirSmeRsp *msg_ptr) +{ + tCsrRoamSession *session; + uint32_t sessionId = CSR_SESSION_ID_INVALID; + QDF_STATUS status; + tpSirSmeSwitchChannelInd pSwitchChnInd; + tCsrRoamInfo roamInfo; + + /* in case of STA, the SWITCH_CHANNEL originates from its AP */ + sms_log(mac_ctx, LOGW, FL("eWNI_SME_SWITCH_CHL_IND from SME")); + pSwitchChnInd = (tpSirSmeSwitchChannelInd) msg_ptr; + /* Update with the new channel id. The channel id is hidden in the + * statusCode. + */ + status = csr_roam_get_session_id_from_bssid(mac_ctx, + &pSwitchChnInd->bssid, &sessionId); + if (QDF_IS_STATUS_SUCCESS(status)) { + session = CSR_GET_SESSION(mac_ctx, sessionId); + if (!session) { + sms_log(mac_ctx, LOGE, + FL("session %d not found"), sessionId); + return; + } + session->connectedProfile.operationChannel = + (uint8_t) pSwitchChnInd->newChannelId; + if (session->pConnectBssDesc) { + session->pConnectBssDesc->channelId = + (uint8_t) pSwitchChnInd->newChannelId; + } + + qdf_mem_set(&roamInfo, sizeof(tCsrRoamInfo), 0); + roamInfo.chan_info.chan_id = pSwitchChnInd->newChannelId; + roamInfo.chan_info.ch_width = + pSwitchChnInd->chan_params.ch_width; + roamInfo.chan_info.sec_ch_offset = + pSwitchChnInd->chan_params.sec_ch_offset; + roamInfo.chan_info.band_center_freq1 = + pSwitchChnInd->chan_params.center_freq_seg0; + roamInfo.chan_info.band_center_freq2 = + pSwitchChnInd->chan_params.center_freq_seg1; + status = csr_roam_call_callback(mac_ctx, sessionId, + &roamInfo, 0, eCSR_ROAM_STA_CHANNEL_SWITCH, + eCSR_ROAM_RESULT_NONE); + } +} + +static void +csr_roam_chk_lnk_deauth_rsp(tpAniSirGlobal mac_ctx, tSirSmeRsp *msg_ptr) +{ + tCsrRoamSession *session; + uint32_t sessionId = CSR_SESSION_ID_INVALID; + QDF_STATUS status; + tCsrRoamInfo *roam_info_ptr = NULL; + tSirSmeDeauthRsp *pDeauthRsp = (tSirSmeDeauthRsp *) msg_ptr; + tCsrRoamInfo roam_info; + + qdf_mem_set(&roam_info, sizeof(roam_info), 0); + sms_log(mac_ctx, LOGW, FL("eWNI_SME_DEAUTH_RSP from SME")); + sessionId = pDeauthRsp->sessionId; + if (!CSR_IS_SESSION_VALID(mac_ctx, sessionId)) + return; + session = CSR_GET_SESSION(mac_ctx, sessionId); + if (CSR_IS_INFRA_AP(&session->connectedProfile)) { + roam_info_ptr = &roam_info; + roam_info_ptr->u.pConnectedProfile = &session->connectedProfile; + qdf_copy_macaddr(&roam_info_ptr->peerMac, + &pDeauthRsp->peer_macaddr); + roam_info_ptr->reasonCode = eCSR_ROAM_RESULT_FORCED; + roam_info_ptr->statusCode = pDeauthRsp->statusCode; + status = csr_roam_call_callback(mac_ctx, sessionId, + roam_info_ptr, 0, + eCSR_ROAM_LOSTLINK, + eCSR_ROAM_RESULT_FORCED); + } +} + +static void +csr_roam_chk_lnk_disassoc_rsp(tpAniSirGlobal mac_ctx, tSirSmeRsp *msg_ptr) +{ + tCsrRoamSession *session; + uint32_t sessionId = CSR_SESSION_ID_INVALID; + QDF_STATUS status; + tCsrRoamInfo *roam_info_ptr = NULL; + tCsrRoamInfo roam_info; + /* + * session id is invalid here so cant use it to access the array + * curSubstate as index + */ + tSirSmeDisassocRsp *pDisassocRsp = (tSirSmeDisassocRsp *) msg_ptr; + + qdf_mem_set(&roam_info, sizeof(roam_info), 0); + sms_log(mac_ctx, LOGW, FL("eWNI_SME_DISASSOC_RSP from SME ")); + sessionId = pDisassocRsp->sessionId; + if (!CSR_IS_SESSION_VALID(mac_ctx, sessionId)) + return; + session = CSR_GET_SESSION(mac_ctx, sessionId); + if (CSR_IS_INFRA_AP(&session->connectedProfile)) { + roam_info_ptr = &roam_info; + roam_info_ptr->u.pConnectedProfile = &session->connectedProfile; + qdf_copy_macaddr(&roam_info_ptr->peerMac, + &pDisassocRsp->peer_macaddr); + roam_info_ptr->reasonCode = eCSR_ROAM_RESULT_FORCED; + roam_info_ptr->statusCode = pDisassocRsp->statusCode; + status = csr_roam_call_callback(mac_ctx, sessionId, + roam_info_ptr, 0, + eCSR_ROAM_LOSTLINK, + eCSR_ROAM_RESULT_FORCED); + } +} + +#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR +static void +csr_roam_diag_mic_fail(tpAniSirGlobal mac_ctx, uint32_t sessionId) +{ + WLAN_HOST_DIAG_EVENT_DEF(secEvent, + host_event_wlan_security_payload_type); + tCsrRoamSession *session = CSR_GET_SESSION(mac_ctx, sessionId); + if (!session) { + sms_log(mac_ctx, LOGE, FL("session %d not found"), sessionId); + return; + } + qdf_mem_set(&secEvent, sizeof(host_event_wlan_security_payload_type), + 0); + secEvent.eventId = WLAN_SECURITY_EVENT_MIC_ERROR; + secEvent.encryptionModeMulticast = + (uint8_t) diag_enc_type_from_csr_type( + session->connectedProfile.mcEncryptionType); + secEvent.encryptionModeUnicast = + (uint8_t) diag_enc_type_from_csr_type( + session->connectedProfile.EncryptionType); + secEvent.authMode = + (uint8_t) diag_auth_type_from_csr_type( + session->connectedProfile.AuthType); + qdf_mem_copy(secEvent.bssid, session->connectedProfile.bssid.bytes, + QDF_MAC_ADDR_SIZE); + WLAN_HOST_DIAG_EVENT_REPORT(&secEvent, EVENT_WLAN_SECURITY); +} +#endif /* FEATURE_WLAN_DIAG_SUPPORT_CSR */ + +static void +csr_roam_chk_lnk_mic_fail_ind(tpAniSirGlobal mac_ctx, tSirSmeRsp *msg_ptr) +{ + uint32_t sessionId = CSR_SESSION_ID_INVALID; + QDF_STATUS status; + tCsrRoamInfo *roam_info_ptr = NULL; + tCsrRoamInfo roam_info; + tpSirSmeMicFailureInd pMicInd = (tpSirSmeMicFailureInd) msg_ptr; + eCsrRoamResult result = eCSR_ROAM_RESULT_MIC_ERROR_UNICAST; + + qdf_mem_set(&roam_info, sizeof(roam_info), 0); + status = csr_roam_get_session_id_from_bssid(mac_ctx, + &pMicInd->bssId, &sessionId); + if (QDF_IS_STATUS_SUCCESS(status)) { + qdf_mem_set(&roam_info, sizeof(tCsrRoamInfo), 0); + roam_info.u.pMICFailureInfo = &pMicInd->info; + roam_info_ptr = &roam_info; + if (pMicInd->info.multicast) + result = eCSR_ROAM_RESULT_MIC_ERROR_GROUP; + else + result = eCSR_ROAM_RESULT_MIC_ERROR_UNICAST; + csr_roam_call_callback(mac_ctx, sessionId, roam_info_ptr, 0, + eCSR_ROAM_MIC_ERROR_IND, result); + } +#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR + csr_roam_diag_mic_fail(mac_ctx, sessionId); +#endif /* FEATURE_WLAN_DIAG_SUPPORT_CSR */ +} + +static void +csr_roam_chk_lnk_pbs_probe_req_ind(tpAniSirGlobal mac_ctx, tSirSmeRsp *msg_ptr) +{ + uint32_t sessionId = CSR_SESSION_ID_INVALID; + QDF_STATUS status; + tCsrRoamInfo roam_info; + tpSirSmeProbeReqInd pProbeReqInd = (tpSirSmeProbeReqInd) msg_ptr; + + qdf_mem_set(&roam_info, sizeof(roam_info), 0); + sms_log(mac_ctx, LOG1, FL("WPS PBC Probe request Indication from SME")); + + status = csr_roam_get_session_id_from_bssid(mac_ctx, + &pProbeReqInd->bssid, &sessionId); + if (QDF_IS_STATUS_SUCCESS(status)) { + qdf_mem_set(&roam_info, sizeof(tCsrRoamInfo), 0); + roam_info.u.pWPSPBCProbeReq = &pProbeReqInd->WPSPBCProbeReq; + csr_roam_call_callback(mac_ctx, sessionId, &roam_info, + 0, eCSR_ROAM_WPS_PBC_PROBE_REQ_IND, + eCSR_ROAM_RESULT_WPS_PBC_PROBE_REQ_IND); + } +} + +#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR +static void +csr_roam_diag_joined_new_bss(tpAniSirGlobal mac_ctx, + tSirSmeNewBssInfo *pNewBss) +{ + host_log_ibss_pkt_type *pIbssLog; + uint32_t bi; + WLAN_HOST_DIAG_LOG_ALLOC(pIbssLog, host_log_ibss_pkt_type, + LOG_WLAN_IBSS_C); + if (!pIbssLog) + return; + pIbssLog->eventId = WLAN_IBSS_EVENT_COALESCING; + if (pNewBss) { + qdf_copy_macaddr(&pIbssLog->bssid, &pNewBss->bssId); + if (pNewBss->ssId.length) + qdf_mem_copy(pIbssLog->ssid, pNewBss->ssId.ssId, + pNewBss->ssId.length); + pIbssLog->operatingChannel = pNewBss->channelNumber; + } + if (IS_SIR_STATUS_SUCCESS(wlan_cfg_get_int(mac_ctx, + WNI_CFG_BEACON_INTERVAL, + &bi))) + /* U8 is not enough for beacon interval */ + pIbssLog->beaconInterval = (uint8_t) bi; + WLAN_HOST_DIAG_LOG_REPORT(pIbssLog); +} +#endif /* FEATURE_WLAN_DIAG_SUPPORT_CSR */ + +static void +csr_roam_chk_lnk_wm_status_change_ntf(tpAniSirGlobal mac_ctx, + tSirSmeRsp *msg_ptr) +{ + tCsrRoamSession *session; + uint32_t sessionId = CSR_SESSION_ID_INVALID; + QDF_STATUS status; + tCsrRoamInfo *roam_info_ptr = NULL; + tSirSmeWmStatusChangeNtf *pStatusChangeMsg; + tCsrRoamInfo roam_info; + tSirSmeApNewCaps *pApNewCaps; + eCsrRoamResult result = eCSR_ROAM_RESULT_NONE; + tSirMacAddr Broadcastaddr = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; + tSirSmeNewBssInfo *pNewBss; + eRoamCmdStatus roamStatus = eCSR_ROAM_FAILED; + + qdf_mem_set(&roam_info, sizeof(roam_info), 0); + pStatusChangeMsg = (tSirSmeWmStatusChangeNtf *) msg_ptr; + switch (pStatusChangeMsg->statusChangeCode) { + case eSIR_SME_IBSS_ACTIVE: + sessionId = csr_find_ibss_session(mac_ctx); + if (CSR_SESSION_ID_INVALID == sessionId) + break; + session = CSR_GET_SESSION(mac_ctx, sessionId); + if (!session) { + sms_log(mac_ctx, LOGE, FL("session %d not found"), + sessionId); + return; + } + session->connectState = eCSR_ASSOC_STATE_TYPE_IBSS_CONNECTED; + if (session->pConnectBssDesc) { + qdf_mem_copy(&roam_info.bssid, + session->pConnectBssDesc->bssId, + sizeof(struct qdf_mac_addr)); + roam_info.u.pConnectedProfile = + &session->connectedProfile; + roam_info_ptr = &roam_info; + } else { + sms_log(mac_ctx, LOGE, + FL("CSR: connected BSS is empty")); + } + result = eCSR_ROAM_RESULT_IBSS_CONNECT; + roamStatus = eCSR_ROAM_CONNECT_STATUS_UPDATE; + break; + + case eSIR_SME_IBSS_INACTIVE: + sessionId = csr_find_ibss_session(mac_ctx); + if (CSR_SESSION_ID_INVALID != sessionId) { + session = CSR_GET_SESSION(mac_ctx, sessionId); + if (!session) { + sms_log(mac_ctx, LOGE, + FL("session %d not found"), sessionId); + return; + } + session->connectState = + eCSR_ASSOC_STATE_TYPE_IBSS_DISCONNECTED; + result = eCSR_ROAM_RESULT_IBSS_INACTIVE; + roamStatus = eCSR_ROAM_CONNECT_STATUS_UPDATE; + } + break; + + case eSIR_SME_JOINED_NEW_BSS: + /* IBSS coalescing. */ + sms_log(mac_ctx, LOGW, + FL("CSR: eSIR_SME_JOINED_NEW_BSS received from PE")); + sessionId = csr_find_ibss_session(mac_ctx); + if (CSR_SESSION_ID_INVALID == sessionId) + break; + session = CSR_GET_SESSION(mac_ctx, sessionId); + if (!session) { + sms_log(mac_ctx, LOGE, FL("session %d not found"), + sessionId); + return; + } + /* update the connection state information */ + pNewBss = &pStatusChangeMsg->statusChangeInfo.newBssInfo; +#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR + csr_roam_diag_joined_new_bss(mac_ctx, pNewBss); +#endif /* FEATURE_WLAN_DIAG_SUPPORT_CSR */ + csr_roam_update_connected_profile_from_new_bss(mac_ctx, + sessionId, + pNewBss); + + if ((eCSR_ENCRYPT_TYPE_NONE == + session->connectedProfile.EncryptionType)) { + csr_roam_issue_set_context_req(mac_ctx, + sessionId, + session->connectedProfile.EncryptionType, + session->pConnectBssDesc, + &Broadcastaddr, false, false, + eSIR_TX_RX, 0, 0, NULL, 0); + } + result = eCSR_ROAM_RESULT_IBSS_COALESCED; + roamStatus = eCSR_ROAM_IBSS_IND; + qdf_mem_copy(&roam_info.bssid, &pNewBss->bssId, + sizeof(struct qdf_mac_addr)); + roam_info_ptr = &roam_info; + /* This BSSID is the real BSSID, save it */ + if (session->pConnectBssDesc) + qdf_mem_copy(session->pConnectBssDesc->bssId, + &pNewBss->bssId, sizeof(struct qdf_mac_addr)); + break; + + /* + * detection by LIM that the capabilities of the associated + * AP have changed. + */ + case eSIR_SME_AP_CAPS_CHANGED: + pApNewCaps = &pStatusChangeMsg->statusChangeInfo.apNewCaps; + sms_log(mac_ctx, LOGW, + FL("CSR handling eSIR_SME_AP_CAPS_CHANGED")); + status = csr_roam_get_session_id_from_bssid(mac_ctx, + &pApNewCaps->bssId, &sessionId); + if (!QDF_IS_STATUS_SUCCESS(status)) + break; + if (eCSR_ROAMING_STATE_JOINED == + mac_ctx->roam.curState[sessionId] + && ((eCSR_ROAM_SUBSTATE_JOINED_REALTIME_TRAFFIC + == mac_ctx->roam.curSubState[sessionId]) + || (eCSR_ROAM_SUBSTATE_NONE == + mac_ctx->roam.curSubState[sessionId]) + || (eCSR_ROAM_SUBSTATE_JOINED_NON_REALTIME_TRAFFIC + == mac_ctx->roam.curSubState[sessionId]) + || (eCSR_ROAM_SUBSTATE_JOINED_NO_TRAFFIC == + mac_ctx->roam.curSubState[sessionId]))) { + sms_log(mac_ctx, LOGW, + FL("Calling csr_roam_disconnect_internal")); + csr_roam_disconnect_internal(mac_ctx, sessionId, + eCSR_DISCONNECT_REASON_UNSPECIFIED); + } else { + sms_log(mac_ctx, LOGW, + FL("Skipping the new scan as CSR is in state %s and sub-state %s"), + mac_trace_getcsr_roam_state( + mac_ctx->roam.curState[sessionId]), + mac_trace_getcsr_roam_sub_state( + mac_ctx->roam.curSubState[sessionId])); + /* We ignore the caps change event if CSR is not in full + * connected state. Send one event to PE to reset + * limSentCapsChangeNtf Once limSentCapsChangeNtf set + * 0, lim can send sub sequent CAPS change event + * otherwise lim cannot send any CAPS change events to + * SME + */ + csr_send_reset_ap_caps_changed(mac_ctx, + &pApNewCaps->bssId); + } + break; + + default: + roamStatus = eCSR_ROAM_FAILED; + result = eCSR_ROAM_RESULT_NONE; + break; + } /* end switch on statusChangeCode */ + if (eCSR_ROAM_RESULT_NONE != result) { + csr_roam_call_callback(mac_ctx, sessionId, roam_info_ptr, 0, + roamStatus, result); + } +} + +static void +csr_roam_chk_lnk_ibss_new_peer_ind(tpAniSirGlobal mac_ctx, tSirSmeRsp *msg_ptr) +{ + tCsrRoamSession *session; + uint32_t sessionId = CSR_SESSION_ID_INVALID; + QDF_STATUS status; + tCsrRoamInfo *roam_info_ptr = NULL; + tSmeIbssPeerInd *pIbssPeerInd = (tSmeIbssPeerInd *) msg_ptr; + tCsrRoamInfo roam_info; +#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR + host_log_ibss_pkt_type *pIbssLog; + WLAN_HOST_DIAG_LOG_ALLOC(pIbssLog, host_log_ibss_pkt_type, + LOG_WLAN_IBSS_C); + if (pIbssLog) { + pIbssLog->eventId = WLAN_IBSS_EVENT_PEER_JOIN; + qdf_copy_macaddr(&pIbssLog->peer_macaddr, + &pIbssPeerInd->peer_addr); + WLAN_HOST_DIAG_LOG_REPORT(pIbssLog); + } +#endif /* FEATURE_WLAN_DIAG_SUPPORT_CSR */ + + qdf_mem_set(&roam_info, sizeof(roam_info), 0); + sessionId = csr_find_ibss_session(mac_ctx); + if (CSR_SESSION_ID_INVALID == sessionId) + return; + session = CSR_GET_SESSION(mac_ctx, sessionId); + if (!session) { + sms_log(mac_ctx, LOGE, FL("session %d not found"), sessionId); + return; + } + /* + * Issue the set Context request to LIM to establish the Unicast STA + * context for the new peer... + */ + if (!session->pConnectBssDesc) { + sms_log(mac_ctx, LOGW, FL("CSR: connected BSS is empty")); + goto callback_and_free; + } + qdf_copy_macaddr(&roam_info.peerMac, &pIbssPeerInd->peer_addr); + qdf_mem_copy(&roam_info.bssid, session->pConnectBssDesc->bssId, + sizeof(struct qdf_mac_addr)); + if (pIbssPeerInd->mesgLen > sizeof(tSmeIbssPeerInd)) { + roam_info.pbFrames = qdf_mem_malloc((pIbssPeerInd->mesgLen - + sizeof(tSmeIbssPeerInd))); + if (NULL == roam_info.pbFrames) { + status = QDF_STATUS_E_NOMEM; + } else { + status = QDF_STATUS_SUCCESS; + roam_info.nBeaconLength = pIbssPeerInd->mesgLen - + sizeof(tSmeIbssPeerInd); + qdf_mem_copy(roam_info.pbFrames, + ((uint8_t *) pIbssPeerInd) + + sizeof(tSmeIbssPeerInd), + roam_info.nBeaconLength); + } + roam_info.staId = (uint8_t) pIbssPeerInd->staId; + roam_info.ucastSig = (uint8_t) pIbssPeerInd->ucastSig; + roam_info.bcastSig = (uint8_t) pIbssPeerInd->bcastSig; + roam_info.pBssDesc = qdf_mem_malloc( + session->pConnectBssDesc->length); + if (NULL == roam_info.pBssDesc) { + status = QDF_STATUS_E_NOMEM; + if (roam_info.pbFrames) + qdf_mem_free(roam_info.pbFrames); + if (roam_info.pBssDesc) + qdf_mem_free(roam_info.pBssDesc); + } else { + status = QDF_STATUS_SUCCESS; + qdf_mem_copy(roam_info.pBssDesc, + session->pConnectBssDesc, + session->pConnectBssDesc->length); + roam_info_ptr = &roam_info; + } + } else { + roam_info_ptr = &roam_info; + } + if ((eCSR_ENCRYPT_TYPE_NONE == + session->connectedProfile.EncryptionType)) { + /* NO keys. these key parameters don't matter */ + csr_roam_issue_set_context_req(mac_ctx, sessionId, + session->connectedProfile.EncryptionType, + session->pConnectBssDesc, + &pIbssPeerInd->peer_addr.bytes, + false, true, eSIR_TX_RX, 0, 0, NULL, 0); + } + +callback_and_free: + /* send up the sec type for the new peer */ + if (roam_info_ptr) + roam_info_ptr->u.pConnectedProfile = &session->connectedProfile; + csr_roam_call_callback(mac_ctx, sessionId, roam_info_ptr, 0, + eCSR_ROAM_CONNECT_STATUS_UPDATE, + eCSR_ROAM_RESULT_IBSS_NEW_PEER); + if (roam_info_ptr) { + if (roam_info.pbFrames) + qdf_mem_free(roam_info.pbFrames); + if (roam_info.pBssDesc) + qdf_mem_free(roam_info.pBssDesc); + } +} + +static void +csr_roam_chk_lnk_ibss_peer_departed_ind(tpAniSirGlobal mac_ctx, + tSirSmeRsp *msg_ptr) +{ + uint32_t sessionId = CSR_SESSION_ID_INVALID; + tCsrRoamInfo roam_info; + tSmeIbssPeerInd *pIbssPeerInd; + + if (NULL == msg_ptr) { + sms_log(mac_ctx, LOGE, FL("IBSS peer ind. message is NULL")); + return; + } + qdf_mem_set(&roam_info, sizeof(roam_info), 0); + pIbssPeerInd = (tSmeIbssPeerInd *) msg_ptr; + sessionId = csr_find_ibss_session(mac_ctx); + if (CSR_SESSION_ID_INVALID != sessionId) { +#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR + host_log_ibss_pkt_type *pIbssLog; + WLAN_HOST_DIAG_LOG_ALLOC(pIbssLog, host_log_ibss_pkt_type, + LOG_WLAN_IBSS_C); + if (pIbssLog) { + pIbssLog->eventId = WLAN_IBSS_EVENT_PEER_LEAVE; + if (pIbssPeerInd) { + qdf_copy_macaddr(&pIbssLog->peer_macaddr, + &pIbssPeerInd->peer_addr); + } + WLAN_HOST_DIAG_LOG_REPORT(pIbssLog); + } +#endif /* FEATURE_WLAN_DIAG_SUPPORT_CSR */ + sms_log(mac_ctx, LOGW, + FL("CSR: Peer departed notification from LIM")); + roam_info.staId = (uint8_t) pIbssPeerInd->staId; + roam_info.ucastSig = (uint8_t) pIbssPeerInd->ucastSig; + roam_info.bcastSig = (uint8_t) pIbssPeerInd->bcastSig; + qdf_copy_macaddr(&roam_info.peerMac, &pIbssPeerInd->peer_addr); + csr_roam_call_callback(mac_ctx, sessionId, &roam_info, 0, + eCSR_ROAM_CONNECT_STATUS_UPDATE, + eCSR_ROAM_RESULT_IBSS_PEER_DEPARTED); + } +} + +#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR +static void +csr_roam_diag_set_ctx_rsp(tpAniSirGlobal mac_ctx, + tCsrRoamSession *session, + tSirSmeSetContextRsp *pRsp) +{ + WLAN_HOST_DIAG_EVENT_DEF(setKeyEvent, + host_event_wlan_security_payload_type); + if (eCSR_ENCRYPT_TYPE_NONE == + session->connectedProfile.EncryptionType) + return; + qdf_mem_set(&setKeyEvent, + sizeof(host_event_wlan_security_payload_type), 0); + if (qdf_is_macaddr_group(&pRsp->peer_macaddr)) + setKeyEvent.eventId = + WLAN_SECURITY_EVENT_SET_BCAST_RSP; + else + setKeyEvent.eventId = + WLAN_SECURITY_EVENT_SET_UNICAST_RSP; + setKeyEvent.encryptionModeMulticast = + (uint8_t) diag_enc_type_from_csr_type( + session->connectedProfile.mcEncryptionType); + setKeyEvent.encryptionModeUnicast = + (uint8_t) diag_enc_type_from_csr_type( + session->connectedProfile.EncryptionType); + qdf_mem_copy(setKeyEvent.bssid, session->connectedProfile.bssid.bytes, + QDF_MAC_ADDR_SIZE); + setKeyEvent.authMode = + (uint8_t) diag_auth_type_from_csr_type( + session->connectedProfile.AuthType); + if (eSIR_SME_SUCCESS != pRsp->statusCode) + setKeyEvent.status = WLAN_SECURITY_STATUS_FAILURE; + WLAN_HOST_DIAG_EVENT_REPORT(&setKeyEvent, EVENT_WLAN_SECURITY); +} +#endif /* FEATURE_WLAN_DIAG_SUPPORT_CSR */ + +static void +csr_roam_chk_lnk_set_ctx_rsp(tpAniSirGlobal mac_ctx, tSirSmeRsp *msg_ptr) +{ + tCsrRoamSession *session; + uint32_t sessionId = CSR_SESSION_ID_INVALID; + QDF_STATUS status; + tCsrRoamInfo *roam_info_ptr = NULL; + tSmeCmd *cmd; + tCsrRoamInfo roam_info; + eCsrRoamResult result = eCSR_ROAM_RESULT_NONE; + tSirSmeSetContextRsp *pRsp = (tSirSmeSetContextRsp *) msg_ptr; + tListElem *entry; + + qdf_mem_set(&roam_info, sizeof(roam_info), 0); + entry = csr_ll_peek_head(&mac_ctx->sme.smeCmdActiveList, + LL_ACCESS_LOCK); + if (!entry) { + sms_log(mac_ctx, LOGE, FL("CSR: NO commands are ACTIVE ...")); + goto process_pending_n_exit; + } + + cmd = GET_BASE_ADDR(entry, tSmeCmd, Link); + if (eSmeCommandSetKey != cmd->command) { + sms_log(mac_ctx, LOGE, FL("CSR: setkey cmd is not ACTIVE ...")); + goto process_pending_n_exit; + } + sessionId = cmd->sessionId; + session = CSR_GET_SESSION(mac_ctx, sessionId); + if (!session) { + sms_log(mac_ctx, LOGE, FL("session %d not found"), sessionId); + return; + } +#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR + csr_roam_diag_set_ctx_rsp(mac_ctx, session, pRsp); +#endif /* FEATURE_WLAN_DIAG_SUPPORT_CSR */ + if (CSR_IS_WAIT_FOR_KEY(mac_ctx, sessionId)) { + csr_roam_stop_wait_for_key_timer(mac_ctx); + /* We are done with authentication, whethere succeed or not */ + csr_roam_substate_change(mac_ctx, eCSR_ROAM_SUBSTATE_NONE, + sessionId); + /* We do it here because this linkup function is not called + * after association when a key needs to be set. + */ + if (csr_is_conn_state_connected_infra(mac_ctx, sessionId)) + csr_roam_link_up(mac_ctx, + session->connectedProfile.bssid); + } + if (eSIR_SME_SUCCESS == pRsp->statusCode) { + qdf_copy_macaddr(&roam_info.peerMac, &pRsp->peer_macaddr); + /* Make sure we install the GTK before indicating to HDD as + * authenticated. This is to prevent broadcast packets go out + * after PTK and before GTK. + */ + if (qdf_is_macaddr_broadcast(&pRsp->peer_macaddr)) { + tpSirSetActiveModeSetBncFilterReq pMsg; + pMsg = qdf_mem_malloc( + sizeof(tSirSetActiveModeSetBncFilterReq)); + if (NULL == pMsg) { + sms_log(mac_ctx, LOGE, FL("Malloc failed")); + goto remove_entry_n_process_pending; + } + pMsg->messageType = eWNI_SME_SET_BCN_FILTER_REQ; + pMsg->length = sizeof(tSirSetActiveModeSetBncFilterReq); + pMsg->seesionId = sessionId; + qdf_copy_macaddr(&pMsg->bssid, + &session->connectedProfile.bssid); + + status = cds_send_mb_message_to_mac(pMsg); + /* + * OBSS SCAN Indication will be sent to Firmware + * to start OBSS Scan + */ + if (CSR_IS_CHANNEL_24GHZ( + session->connectedProfile.operationChannel) + && (session->connectState == + eCSR_ASSOC_STATE_TYPE_INFRA_ASSOCIATED) + && session->pCurRoamProfile + && ((QDF_P2P_CLIENT_MODE == + session->pCurRoamProfile->csrPersona) + || (QDF_STA_MODE == + session->pCurRoamProfile->csrPersona))) { + struct sme_obss_ht40_scanind_msg *msg; + msg = qdf_mem_malloc(sizeof( + struct sme_obss_ht40_scanind_msg)); + if (NULL == msg) { + sms_log(mac_ctx, LOGE, + FL("Malloc failed")); + goto remove_entry_n_process_pending; + } + msg->msg_type = eWNI_SME_HT40_OBSS_SCAN_IND; + msg->length = + sizeof(struct sme_obss_ht40_scanind_msg); + qdf_copy_macaddr(&msg->mac_addr, + &session->connectedProfile.bssid); + status = cds_send_mb_message_to_mac(msg); + } + result = eCSR_ROAM_RESULT_AUTHENTICATED; + } else { + result = eCSR_ROAM_RESULT_NONE; + } + roam_info_ptr = &roam_info; + } else { + result = eCSR_ROAM_RESULT_FAILURE; + sms_log(mac_ctx, LOGE, + FL("CSR: setkey command failed(err=%d) PeerMac " + MAC_ADDRESS_STR), + pRsp->statusCode, + MAC_ADDR_ARRAY(pRsp->peer_macaddr.bytes)); + } + csr_roam_call_callback(mac_ctx, sessionId, &roam_info, + cmd->u.setKeyCmd.roamId, + eCSR_ROAM_SET_KEY_COMPLETE, result); + /* Indicate SME_QOS that the SET_KEY is completed, so that SME_QOS + * can go ahead and initiate the TSPEC if any are pending + */ + sme_qos_csr_event_ind(mac_ctx, (uint8_t) sessionId, + SME_QOS_CSR_SET_KEY_SUCCESS_IND, NULL); +#ifdef FEATURE_WLAN_ESE + /* Send Adjacent AP repot to new AP. */ + if (result == eCSR_ROAM_RESULT_AUTHENTICATED + && session->isPrevApInfoValid + && session->connectedProfile.isESEAssoc) { + csr_send_ese_adjacent_ap_rep_ind(mac_ctx, session); + session->isPrevApInfoValid = false; + } +#endif +remove_entry_n_process_pending: + if (csr_ll_remove_entry(&mac_ctx->sme.smeCmdActiveList, entry, + LL_ACCESS_LOCK)) + csr_release_command_set_key(mac_ctx, cmd); + +process_pending_n_exit: + sme_process_pending_queue(mac_ctx); +} + + +static void +csr_roam_chk_lnk_max_assoc_exceeded(tpAniSirGlobal mac_ctx, tSirSmeRsp *msg_ptr) +{ + uint32_t sessionId = CSR_SESSION_ID_INVALID; + tSmeMaxAssocInd *pSmeMaxAssocInd; + tCsrRoamInfo roam_info; + + qdf_mem_set(&roam_info, sizeof(roam_info), 0); + pSmeMaxAssocInd = (tSmeMaxAssocInd *) msg_ptr; + sms_log(mac_ctx, LOG1, + FL("max assoc have been reached, new peer cannot be accepted")); + sessionId = pSmeMaxAssocInd->sessionId; + roam_info.sessionId = sessionId; + qdf_copy_macaddr(&roam_info.peerMac, &pSmeMaxAssocInd->peer_mac); + csr_roam_call_callback(mac_ctx, sessionId, &roam_info, 0, + eCSR_ROAM_INFRA_IND, + eCSR_ROAM_RESULT_MAX_ASSOC_EXCEEDED); +} + +void csr_roam_check_for_link_status_change(tpAniSirGlobal pMac, tSirSmeRsp *pSirMsg) +{ + if (NULL == pSirMsg) { + sms_log(pMac, LOGE, FL("pSirMsg is NULL")); + return; + } + switch (pSirMsg->messageType) { + case eWNI_SME_ASSOC_IND: + csr_roam_chk_lnk_assoc_ind(pMac, pSirMsg); + break; + case eWNI_SME_DISASSOC_IND: + csr_roam_chk_lnk_disassoc_ind(pMac, pSirMsg); + break; + case eWNI_SME_DISCONNECT_DONE_IND: + csr_roam_send_disconnect_done_indication(pMac, pSirMsg); + break; + case eWNI_SME_DEAUTH_IND: + csr_roam_chk_lnk_deauth_ind(pMac, pSirMsg); + break; + case eWNI_SME_SWITCH_CHL_IND: + csr_roam_chk_lnk_swt_ch_ind(pMac, pSirMsg); + break; + case eWNI_SME_DEAUTH_RSP: + csr_roam_chk_lnk_deauth_rsp(pMac, pSirMsg); + break; + case eWNI_SME_DISASSOC_RSP: + csr_roam_chk_lnk_disassoc_rsp(pMac, pSirMsg); + break; + case eWNI_SME_MIC_FAILURE_IND: + csr_roam_chk_lnk_mic_fail_ind(pMac, pSirMsg); + break; + case eWNI_SME_WPS_PBC_PROBE_REQ_IND: + csr_roam_chk_lnk_pbs_probe_req_ind(pMac, pSirMsg); + break; + case eWNI_SME_WM_STATUS_CHANGE_NTF: + csr_roam_chk_lnk_wm_status_change_ntf(pMac, pSirMsg); + break; + case eWNI_SME_IBSS_NEW_PEER_IND: + csr_roam_chk_lnk_ibss_new_peer_ind(pMac, pSirMsg); + break; + case eWNI_SME_IBSS_PEER_DEPARTED_IND: + csr_roam_chk_lnk_ibss_peer_departed_ind(pMac, pSirMsg); + break; + case eWNI_SME_SETCONTEXT_RSP: + csr_roam_chk_lnk_set_ctx_rsp(pMac, pSirMsg); + break; + case eWNI_SME_GET_STATISTICS_RSP: + sms_log(pMac, LOG2, FL("Stats rsp from PE")); + csr_roam_stats_rsp_processor(pMac, pSirMsg); + break; +#ifdef FEATURE_WLAN_ESE + case eWNI_SME_GET_TSM_STATS_RSP: + sms_log(pMac, LOG2, FL("TSM Stats rsp from PE")); + csr_tsm_stats_rsp_processor(pMac, pSirMsg); + break; +#endif /* FEATURE_WLAN_ESE */ + case eWNI_SME_GET_RSSI_REQ: + sms_log(pMac, LOG2, FL("GetRssiReq from self")); + csr_update_rssi(pMac, pSirMsg); + break; + case eWNI_SME_GET_SNR_REQ: + sms_log(pMac, LOG2, FL("GetSnrReq from self")); + csr_update_snr(pMac, pSirMsg); + break; + case eWNI_SME_FT_PRE_AUTH_RSP: + csr_roam_ft_pre_auth_rsp_processor(pMac, (tpSirFTPreAuthRsp) pSirMsg); + break; + case eWNI_SME_MAX_ASSOC_EXCEEDED: + csr_roam_chk_lnk_max_assoc_exceeded(pMac, pSirMsg); + break; + case eWNI_SME_CANDIDATE_FOUND_IND: + sms_log(pMac, LOG2, FL("Candidate found indication from PE")); + csr_neighbor_roam_candidate_found_ind_hdlr(pMac, pSirMsg); + break; + case eWNI_SME_HANDOFF_REQ: + sms_log(pMac, LOG2, FL("Handoff Req from self")); + csr_neighbor_roam_handoff_req_hdlr(pMac, pSirMsg); + break; + default: + break; + } /* end switch on message type */ +} + +void csr_call_roaming_completion_callback(tpAniSirGlobal pMac, + tCsrRoamSession *pSession, + tCsrRoamInfo *pRoamInfo, uint32_t roamId, + eCsrRoamResult roamResult) +{ + if (pSession) { + if (pSession->bRefAssocStartCnt) { + pSession->bRefAssocStartCnt--; + + if (0 != pSession->bRefAssocStartCnt) { + QDF_ASSERT(pSession->bRefAssocStartCnt == 0); + return; + } + /* Need to call association_completion because there is an assoc_start pending. */ + csr_roam_call_callback(pMac, pSession->sessionId, NULL, + roamId, + eCSR_ROAM_ASSOCIATION_COMPLETION, + eCSR_ROAM_RESULT_FAILURE); + } + csr_roam_call_callback(pMac, pSession->sessionId, pRoamInfo, + roamId, eCSR_ROAM_ROAMING_COMPLETION, + roamResult); + } else { + sms_log(pMac, LOGW, FL(" pSession is NULL")); + } +} + +QDF_STATUS csr_roam_start_roaming(tpAniSirGlobal pMac, uint32_t sessionId, + eCsrRoamingReason roamingReason) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + if (CSR_IS_LOSTLINK_ROAMING(roamingReason) && + (false == pMac->roam.roamSession[sessionId].fCancelRoaming)) { + status = csr_scan_request_lost_link1(pMac, sessionId); + } + return status; +} + +/* return a bool to indicate whether roaming completed or continue. */ +bool csr_roam_complete_roaming(tpAniSirGlobal pMac, uint32_t sessionId, + bool fForce, eCsrRoamResult roamResult) +{ + bool fCompleted = true; + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + if (!pSession) { + sms_log(pMac, LOGE, FL(" session %d not found "), sessionId); + return false; + } + /* Check whether time is up */ + if (pSession->fCancelRoaming || fForce || + eCsrReassocRoaming == pSession->roamingReason || + eCsrDynamicRoaming == pSession->roamingReason) { + sms_log(pMac, LOGW, FL(" indicates roaming completion")); + if (pSession->fCancelRoaming + && CSR_IS_LOSTLINK_ROAMING(pSession->roamingReason)) { + /* roaming is cancelled, tell HDD to indicate disconnect */ + /* Because LIM overload deauth_ind for both deauth frame and missed beacon */ + /* we need to use this logic to detinguish it. For missed beacon, LIM set reason */ + /* to be eSIR_BEACON_MISSED */ + if (eSIR_BEACON_MISSED == pSession->roamingStatusCode) { + roamResult = eCSR_ROAM_RESULT_LOSTLINK; + } else if (eCsrLostlinkRoamingDisassoc == + pSession->roamingReason) { + roamResult = eCSR_ROAM_RESULT_DISASSOC_IND; + } else if (eCsrLostlinkRoamingDeauth == + pSession->roamingReason) { + roamResult = eCSR_ROAM_RESULT_DEAUTH_IND; + } else { + roamResult = eCSR_ROAM_RESULT_LOSTLINK; + } + } + csr_call_roaming_completion_callback(pMac, pSession, NULL, 0, + roamResult); + pSession->roamingReason = eCsrNotRoaming; + } else { + pSession->roamResult = roamResult; + if (!QDF_IS_STATUS_SUCCESS + (csr_roam_start_roaming_timer + (pMac, sessionId, QDF_MC_TIMER_TO_SEC_UNIT))) { + csr_call_roaming_completion_callback(pMac, pSession, NULL, + 0, roamResult); + pSession->roamingReason = eCsrNotRoaming; + } else { + fCompleted = false; + } + } + return fCompleted; +} + +void csr_roam_cancel_roaming(tpAniSirGlobal pMac, uint32_t sessionId) +{ + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!pSession) { + sms_log(pMac, LOGE, FL(" session %d not found "), sessionId); + return; + } + + if (CSR_IS_ROAMING(pSession)) { + sms_log(pMac, LOGW, "Cancel roaming"); + pSession->fCancelRoaming = true; + if (CSR_IS_ROAM_JOINING(pMac, sessionId) + && CSR_IS_ROAM_SUBSTATE_CONFIG(pMac, sessionId)) { + /* No need to do anything in here because the handler takes care of it */ + } else { + eCsrRoamResult roamResult = + CSR_IS_LOSTLINK_ROAMING(pSession-> + roamingReason) ? + eCSR_ROAM_RESULT_LOSTLINK : eCSR_ROAM_RESULT_NONE; + /* Roaming is stopped after here */ + csr_roam_complete_roaming(pMac, sessionId, true, + roamResult); + /* Since CSR may be in lostlink roaming situation, abort all roaming related activities */ + csr_scan_abort_mac_scan(pMac, sessionId, + INVALID_SCAN_ID, eCSR_SCAN_ABORT_DEFAULT); + csr_roam_stop_roaming_timer(pMac, sessionId); + } + } +} + +void csr_roam_roaming_timer_handler(void *pv) +{ + tCsrTimerInfo *pInfo = (tCsrTimerInfo *) pv; + tpAniSirGlobal pMac = pInfo->pMac; + uint32_t sessionId = pInfo->sessionId; + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!pSession) { + sms_log(pMac, LOGE, FL(" session %d not found "), sessionId); + return; + } + + if (false == pSession->fCancelRoaming) { + if (!QDF_IS_STATUS_SUCCESS + (csr_roam_start_roaming + (pMac, sessionId, pSession->roamingReason))) { + csr_call_roaming_completion_callback(pMac, pSession, NULL, + 0, + pSession->roamResult); + pSession->roamingReason = eCsrNotRoaming; + } + } +} + +/** + * csr_roam_roaming_offload_timeout_handler() - Handler for roaming failure + * @timer_data: Carries the mac_ctx and session info + * + * This function would be invoked when the roaming_offload_timer expires. + * The timer is waiting in anticipation of a related roaming event from + * the firmware after receiving the ROAM_START event. + * + * Return: None + */ +void csr_roam_roaming_offload_timeout_handler(void *timer_data) +{ + tCsrTimerInfo *timer_info = (tCsrTimerInfo *) timer_data; + + if (timer_info) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + FL("LFR3:roaming offload timer expired, session: %d"), + timer_info->sessionId); + } else { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Invalid Session")); + return; + } + csr_roam_disconnect(timer_info->pMac, timer_info->sessionId, + eCSR_DISCONNECT_REASON_UNSPECIFIED); +} + +QDF_STATUS csr_roam_start_roaming_timer(tpAniSirGlobal pMac, uint32_t sessionId, + uint32_t interval) +{ + QDF_STATUS status; + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!pSession) { + sms_log(pMac, LOGE, FL(" session %d not found"), sessionId); + return QDF_STATUS_E_FAILURE; + } + + sms_log(pMac, LOG1, " csrScanStartRoamingTimer"); + pSession->roamingTimerInfo.sessionId = (uint8_t) sessionId; + status = qdf_mc_timer_start(&pSession->hTimerRoaming, + interval / QDF_MC_TIMER_TO_MS_UNIT); + + return status; +} + +QDF_STATUS csr_roam_stop_roaming_timer(tpAniSirGlobal pMac, uint32_t sessionId) +{ + return qdf_mc_timer_stop + (&pMac->roam.roamSession[sessionId].hTimerRoaming); +} + +void csr_roam_wait_for_key_time_out_handler(void *pv) +{ + tCsrTimerInfo *pInfo = (tCsrTimerInfo *) pv; + tpAniSirGlobal pMac = pInfo->pMac; + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, pInfo->sessionId); + QDF_STATUS status = QDF_STATUS_E_FAILURE; + + if (pSession == NULL) { + sms_log(pMac, LOGE, "%s: session not found", __func__); + return; + } + + sms_log(pMac, LOGW, + FL("WaitForKey timer expired in state=%s sub-state=%s"), + mac_trace_get_neighbour_roam_state(pMac->roam. + neighborRoamInfo[pInfo->sessionId]. + neighborRoamState), + mac_trace_getcsr_roam_sub_state(pMac->roam. + curSubState[pInfo->sessionId])); + + if (CSR_IS_WAIT_FOR_KEY(pMac, pInfo->sessionId)) { + if (csr_neighbor_roam_is_handoff_in_progress(pMac, pInfo->sessionId)) { + /* + * Enable heartbeat timer when hand-off is in progress + * and Key Wait timer expired. + */ + sms_log(pMac, LOG2, + "Enabling HB timer after WaitKey expiry" + " (nHBCount=%d)", + pMac->roam.configParam.HeartbeatThresh24); + cfg_set_int(pMac, WNI_CFG_HEART_BEAT_THRESHOLD, + pMac->roam.configParam.HeartbeatThresh24); + } + sms_log(pMac, LOGE, " SME pre-auth state timeout. "); + + /* Change the substate so command queue is unblocked. */ + if (CSR_ROAM_SESSION_MAX > pInfo->sessionId) { + csr_roam_substate_change(pMac, eCSR_ROAM_SUBSTATE_NONE, + pInfo->sessionId); + } + + if (csr_is_conn_state_connected_infra(pMac, pInfo->sessionId)) { + csr_roam_link_up(pMac, + pSession->connectedProfile.bssid); + sme_process_pending_queue(pMac); + status = sme_acquire_global_lock(&pMac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + csr_roam_disconnect(pMac, pInfo->sessionId, + eCSR_DISCONNECT_REASON_UNSPECIFIED); + sme_release_global_lock(&pMac->sme); + } + } else { + sms_log(pMac, LOGE, "%s: session not found", __func__); + } + } + +} + +/** + * csr_roam_roaming_offload_timer_action() - API to start/stop the timer + * @mac_ctx: MAC Context + * @interval: Value to be set for the timer + * @session_id: Session on which the timer should be operated + * @action: Start/Stop action for the timer + * + * API to start/stop the roaming offload timer + * + * Return: None + */ +void csr_roam_roaming_offload_timer_action(tpAniSirGlobal mac_ctx, + uint32_t interval, uint8_t session_id, + uint8_t action) +{ + tCsrRoamSession *csr_session = CSR_GET_SESSION(mac_ctx, session_id); + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + FL("LFR3: timer action %d, session %d, intvl %d"), + action, session_id, interval); + if (mac_ctx) { + csr_session = CSR_GET_SESSION(mac_ctx, session_id); + } else { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("LFR3: Invalid MAC Context")); + return; + } + if (!csr_session) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("LFR3: session %d not found"), session_id); + return; + } + csr_session->roamingTimerInfo.sessionId = (uint8_t) session_id; + if (action == ROAMING_OFFLOAD_TIMER_START) + qdf_mc_timer_start(&csr_session->roaming_offload_timer, + interval / QDF_MC_TIMER_TO_MS_UNIT); + if (action == ROAMING_OFFLOAD_TIMER_STOP) + qdf_mc_timer_stop(&csr_session->roaming_offload_timer); + + return; +} + +QDF_STATUS csr_roam_start_wait_for_key_timer(tpAniSirGlobal pMac, uint32_t interval) +{ + QDF_STATUS status; + tpCsrNeighborRoamControlInfo pNeighborRoamInfo = + &pMac->roam.neighborRoamInfo[pMac->roam.WaitForKeyTimerInfo. + sessionId]; + if (csr_neighbor_roam_is_handoff_in_progress(pMac, + pMac->roam.WaitForKeyTimerInfo. + sessionId)) { + /* Disable heartbeat timer when hand-off is in progress */ + sms_log(pMac, LOG2, + FL("disabling HB timer in state=%s sub-state=%s"), + mac_trace_get_neighbour_roam_state( + pNeighborRoamInfo->neighborRoamState), + mac_trace_getcsr_roam_sub_state( + pMac->roam.curSubState[pMac->roam. + WaitForKeyTimerInfo.sessionId])); + cfg_set_int(pMac, WNI_CFG_HEART_BEAT_THRESHOLD, 0); + } + sms_log(pMac, LOG1, " csrScanStartWaitForKeyTimer"); + status = qdf_mc_timer_start(&pMac->roam.hTimerWaitForKey, + interval / QDF_MC_TIMER_TO_MS_UNIT); + + return status; +} + +QDF_STATUS csr_roam_stop_wait_for_key_timer(tpAniSirGlobal pMac) +{ + tpCsrNeighborRoamControlInfo pNeighborRoamInfo = + &pMac->roam.neighborRoamInfo[pMac->roam.WaitForKeyTimerInfo. + sessionId]; + + sms_log(pMac, LOG2, + FL("WaitForKey timer stopped in state=%s sub-state=%s"), + mac_trace_get_neighbour_roam_state(pNeighborRoamInfo-> + neighborRoamState), + mac_trace_getcsr_roam_sub_state(pMac->roam. + curSubState[pMac->roam. + WaitForKeyTimerInfo. + sessionId])); + if (csr_neighbor_roam_is_handoff_in_progress(pMac, + pMac->roam.WaitForKeyTimerInfo. + sessionId)) { + /* + * Enable heartbeat timer when hand-off is in progress + * and Key Wait timer got stopped for some reason + */ + sms_log(pMac, LOG2, "Enabling HB timer after WaitKey stop" + " (nHBCount=%d)", + pMac->roam.configParam.HeartbeatThresh24); + cfg_set_int(pMac, WNI_CFG_HEART_BEAT_THRESHOLD, + pMac->roam.configParam.HeartbeatThresh24); + } + return qdf_mc_timer_stop(&pMac->roam.hTimerWaitForKey); +} + +void csr_roam_completion(tpAniSirGlobal pMac, uint32_t sessionId, + tCsrRoamInfo *pRoamInfo, tSmeCmd *pCommand, + eCsrRoamResult roamResult, bool fSuccess) +{ + eRoamCmdStatus roamStatus = csr_get_roam_complete_status(pMac, sessionId); + uint32_t roamId = 0; + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!pSession) { + sms_log(pMac, LOGE, FL(" session %d not found "), sessionId); + return; + } + + if (pCommand) { + roamId = pCommand->u.roamCmd.roamId; + if (sessionId != pCommand->sessionId) { + QDF_ASSERT(sessionId == pCommand->sessionId); + return; + } + } + if (eCSR_ROAM_ROAMING_COMPLETION == roamStatus) { + /* if success, force roaming completion */ + csr_roam_complete_roaming(pMac, sessionId, fSuccess, roamResult); + } else { + if (pSession->bRefAssocStartCnt != 0) { + QDF_ASSERT(pSession->bRefAssocStartCnt == 0); + return; + } + sms_log(pMac, LOGW, + FL + (" indicates association completion. roamResult = %d"), + roamResult); + csr_roam_call_callback(pMac, sessionId, pRoamInfo, roamId, + roamStatus, roamResult); + } +} + +static +QDF_STATUS csr_roam_lost_link(tpAniSirGlobal pMac, uint32_t sessionId, + uint32_t type, tSirSmeRsp *pSirMsg) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tSirSmeDeauthInd *pDeauthIndMsg = NULL; + tSirSmeDisassocInd *pDisassocIndMsg = NULL; + eCsrRoamResult result = eCSR_ROAM_RESULT_LOSTLINK; + tCsrRoamInfo roamInfo; + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!pSession) { + sms_log(pMac, LOGE, FL(" session %d not found "), sessionId); + return QDF_STATUS_E_FAILURE; + } + pSession->fCancelRoaming = false; + if (eWNI_SME_DISASSOC_IND == type) { + result = eCSR_ROAM_RESULT_DISASSOC_IND; + pDisassocIndMsg = (tSirSmeDisassocInd *) pSirMsg; + pSession->roamingStatusCode = pDisassocIndMsg->statusCode; + pSession->joinFailStatusCode.reasonCode = + pDisassocIndMsg->reasonCode; + } else if (eWNI_SME_DEAUTH_IND == type) { + result = eCSR_ROAM_RESULT_DEAUTH_IND; + pDeauthIndMsg = (tSirSmeDeauthInd *) pSirMsg; + pSession->roamingStatusCode = pDeauthIndMsg->statusCode; + pSession->joinFailStatusCode.reasonCode = + pDeauthIndMsg->reasonCode; + } else { + sms_log(pMac, LOGW, FL("gets an unknown type (%d)"), type); + result = eCSR_ROAM_RESULT_NONE; + pSession->joinFailStatusCode.reasonCode = 1; + } + + /* call profile lost link routine here */ + if (!CSR_IS_INFRA_AP(&pSession->connectedProfile)) { + csr_roam_call_callback(pMac, sessionId, NULL, 0, + eCSR_ROAM_LOSTLINK_DETECTED, result); + } + + if (eWNI_SME_DISASSOC_IND == type) { + status = csr_send_mb_disassoc_cnf_msg(pMac, pDisassocIndMsg); + } else if (eWNI_SME_DEAUTH_IND == type) { + status = csr_send_mb_deauth_cnf_msg(pMac, pDeauthIndMsg); + } + + /* prepare to tell HDD to disconnect */ + qdf_mem_set(&roamInfo, sizeof(tCsrRoamInfo), 0); + roamInfo.statusCode = (tSirResultCodes) pSession->roamingStatusCode; + roamInfo.reasonCode = pSession->joinFailStatusCode.reasonCode; + if (eWNI_SME_DISASSOC_IND == type) { + /* staMacAddr */ + qdf_copy_macaddr(&roamInfo.peerMac, + &pDisassocIndMsg->peer_macaddr); + roamInfo.staId = (uint8_t) pDisassocIndMsg->staId; + roamInfo.reasonCode = pDisassocIndMsg->reasonCode; + } else if (eWNI_SME_DEAUTH_IND == type) { + /* staMacAddr */ + qdf_copy_macaddr(&roamInfo.peerMac, + &pDeauthIndMsg->peer_macaddr); + roamInfo.staId = (uint8_t) pDeauthIndMsg->staId; + roamInfo.reasonCode = pDeauthIndMsg->reasonCode; + roamInfo.rxRssi = pDeauthIndMsg->rssi; + } + sms_log(pMac, LOGW, FL("roamInfo.staId: %d"), roamInfo.staId); + + return status; +} + + +static void csr_roam_wm_status_change_complete(tpAniSirGlobal pMac) +{ + tListElem *pEntry; + tSmeCmd *pCommand; + pEntry = csr_ll_peek_head(&pMac->sme.smeCmdActiveList, LL_ACCESS_LOCK); + if (pEntry) { + pCommand = GET_BASE_ADDR(pEntry, tSmeCmd, Link); + if (eSmeCommandWmStatusChange == pCommand->command) { + /* Nothing to process in a Lost Link completion.... It just kicks off a */ + /* roaming sequence. */ + if (csr_ll_remove_entry + (&pMac->sme.smeCmdActiveList, pEntry, + LL_ACCESS_LOCK)) { + csr_release_command_wm_status_change(pMac, pCommand); + } else { + sms_log(pMac, LOGE, + " ******csr_roam_wm_status_change_complete fail to release command"); + } + + } else { + sms_log(pMac, LOGW, + "CSR: WmStatusChange Completion called but LOST LINK command is not ACTIVE ..."); + } + } else { + sms_log(pMac, LOGW, + "CSR: WmStatusChange Completion called but NO commands are ACTIVE ..."); + } + sme_process_pending_queue(pMac); +} + +void csr_roam_process_wm_status_change_command(tpAniSirGlobal pMac, + tSmeCmd *pCommand) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tSirSmeRsp *pSirSmeMsg; + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, pCommand->sessionId); + + if (!pSession) { + sms_log(pMac, LOGE, FL(" session %d not found "), + pCommand->sessionId); + return; + } + sms_log(pMac, LOG1, FL("session:%d, CmdType : %d"), + pCommand->sessionId, pCommand->u.wmStatusChangeCmd.Type); + + switch (pCommand->u.wmStatusChangeCmd.Type) { + case eCsrDisassociated: + pSirSmeMsg = + (tSirSmeRsp *) &pCommand->u.wmStatusChangeCmd.u. + DisassocIndMsg; + status = + csr_roam_lost_link(pMac, pCommand->sessionId, + eWNI_SME_DISASSOC_IND, pSirSmeMsg); + break; + case eCsrDeauthenticated: + pSirSmeMsg = + (tSirSmeRsp *) &pCommand->u.wmStatusChangeCmd.u. + DeauthIndMsg; + status = + csr_roam_lost_link(pMac, pCommand->sessionId, + eWNI_SME_DEAUTH_IND, pSirSmeMsg); + break; + default: + sms_log(pMac, LOGW, FL("gets an unknown command %d"), + pCommand->u.wmStatusChangeCmd.Type); + break; + } + /* Lost Link just triggers a roaming sequence. We can complte the Lost Link */ + /* command here since there is nothing else to do. */ + csr_roam_wm_status_change_complete(pMac); +} + + +/** + * csr_compute_mode_and_band() - computes dot11mode + * @pMac: mac global context + * @dot11_mode: out param, do11 mode calculated + * @band: out param, band caclculated + * @opr_ch: operating channels + * + * This function finds dot11 mode based on current mode, operating channel and + * fw supported modes. + * + * Return: void + */ +static void +csr_compute_mode_and_band(tpAniSirGlobal mac_ctx, + eCsrCfgDot11Mode *dot11_mode, + eCsrBand *band, + uint8_t opr_ch) +{ + bool vht_24_ghz = mac_ctx->roam.configParam.enableVhtFor24GHz; + switch (mac_ctx->roam.configParam.uCfgDot11Mode) { + case eCSR_CFG_DOT11_MODE_11A: + *dot11_mode = eCSR_CFG_DOT11_MODE_11A; + *band = eCSR_BAND_5G; + break; + case eCSR_CFG_DOT11_MODE_11B: + *dot11_mode = eCSR_CFG_DOT11_MODE_11B; + *band = eCSR_BAND_24; + break; + case eCSR_CFG_DOT11_MODE_11G: + *dot11_mode = eCSR_CFG_DOT11_MODE_11G; + *band = eCSR_BAND_24; + break; + case eCSR_CFG_DOT11_MODE_11N: + *dot11_mode = eCSR_CFG_DOT11_MODE_11N; + *band = CSR_GET_BAND(opr_ch); + break; + case eCSR_CFG_DOT11_MODE_11AC: + if (IS_FEATURE_SUPPORTED_BY_FW(DOT11AC)) { + /* + * If the operating channel is in 2.4 GHz band, check + * for INI item to disable VHT operation in 2.4 GHz band + */ + if (CDS_IS_CHANNEL_24GHZ(opr_ch) && !vht_24_ghz) + /* Disable 11AC operation */ + *dot11_mode = eCSR_CFG_DOT11_MODE_11N; + else + *dot11_mode = eCSR_CFG_DOT11_MODE_11AC; + } else { + *dot11_mode = eCSR_CFG_DOT11_MODE_11N; + } + *band = CSR_GET_BAND(opr_ch); + break; + case eCSR_CFG_DOT11_MODE_11AC_ONLY: + if (IS_FEATURE_SUPPORTED_BY_FW(DOT11AC)) { + /* + * If the operating channel is in 2.4 GHz band, check + * for INI item to disable VHT operation in 2.4 GHz band + */ + if (CDS_IS_CHANNEL_24GHZ(opr_ch) && !vht_24_ghz) + /* Disable 11AC operation */ + *dot11_mode = eCSR_CFG_DOT11_MODE_11N; + else + *dot11_mode = eCSR_CFG_DOT11_MODE_11AC_ONLY; + } else { + *dot11_mode = eCSR_CFG_DOT11_MODE_11N; + } + *band = CSR_GET_BAND(opr_ch); + break; + case eCSR_CFG_DOT11_MODE_AUTO: + if (IS_FEATURE_SUPPORTED_BY_FW(DOT11AC)) { + /* + * If the operating channel is in 2.4 GHz band, + * check for INI item to disable VHT operation + * in 2.4 GHz band + */ + if (CDS_IS_CHANNEL_24GHZ(opr_ch) + && !vht_24_ghz) + /* Disable 11AC operation */ + *dot11_mode = eCSR_CFG_DOT11_MODE_11N; + else + *dot11_mode = eCSR_CFG_DOT11_MODE_11AC; + } else { + *dot11_mode = eCSR_CFG_DOT11_MODE_11N; + } + *band = CSR_GET_BAND(opr_ch); + break; + default: + /* + * Global dot11 Mode setting is 11a/b/g. use the channel number + * to determine the Mode setting. + */ + if (eCSR_OPERATING_CHANNEL_AUTO == opr_ch) { + *band = mac_ctx->roam.configParam.eBand; + if (eCSR_BAND_24 == *band) { + /* + * See reason in else if ( CDS_IS_CHANNEL_24GHZ + * (opr_ch) ) to pick 11B + */ + *dot11_mode = eCSR_CFG_DOT11_MODE_11B; + } else { + /* prefer 5GHz */ + *band = eCSR_BAND_5G; + *dot11_mode = eCSR_CFG_DOT11_MODE_11A; + } + } else if (CDS_IS_CHANNEL_24GHZ(opr_ch)) { + /* + * WiFi tests require IBSS networks to start in 11b mode + * without any change to the default parameter settings + * on the adapter. We use ACU to start an IBSS through + * creation of a startIBSS profile. This startIBSS + * profile has Auto MACProtocol and the adapter property + * setting for dot11Mode is also AUTO. So in this case, + * let's start the IBSS network in 11b mode instead of + * 11g mode. So this is for Auto=profile->MacProtocol && + * Auto=Global. dot11Mode && profile->channel is < 14, + * then start the IBSS in b mode. + * + * Note: we used to have this start as an 11g IBSS for + * best performance. now to specify that the user will + * have to set the do11Mode in the property page to 11g + * to force it. + */ + *dot11_mode = eCSR_CFG_DOT11_MODE_11B; + *band = eCSR_BAND_24; + } else { + /* else, it's a 5.0GHz channel. Set mode to 11a. */ + *dot11_mode = eCSR_CFG_DOT11_MODE_11A; + *band = eCSR_BAND_5G; + } + break; + } /* switch */ +} + +/** + * csr_roam_get_phy_mode_band_for_bss() - This function returns band and mode + * information. + * @mac_ctx: mac global context + * @profile: bss profile + * @band: out param, band caclculated + * @opr_ch: operating channels + * + * This function finds dot11 mode based on current mode, operating channel and + * fw supported modes. The only tricky part is that if phyMode is set to 11abg, + * this function may return eCSR_CFG_DOT11_MODE_11B instead of + * eCSR_CFG_DOT11_MODE_11G if everything is set to auto-pick. + * + * Return: dot11mode + */ +static eCsrCfgDot11Mode +csr_roam_get_phy_mode_band_for_bss(tpAniSirGlobal mac_ctx, + tCsrRoamProfile *profile, + uint8_t opr_chn, + eCsrBand *p_band) +{ + eCsrBand band; + eCsrCfgDot11Mode curr_mode = mac_ctx->roam.configParam.uCfgDot11Mode; + eCsrCfgDot11Mode cfg_dot11_mode = + csr_get_cfg_dot11_mode_from_csr_phy_mode(profile, + (eCsrPhyMode) profile->phyMode, + mac_ctx->roam.configParam.ProprietaryRatesEnabled); + + /* + * If the global setting for dot11Mode is set to auto/abg, we overwrite + * the setting in the profile. + */ + if ((!CSR_IS_INFRA_AP(profile) + && ((eCSR_CFG_DOT11_MODE_AUTO == curr_mode) + || (eCSR_CFG_DOT11_MODE_ABG == curr_mode))) + || (eCSR_CFG_DOT11_MODE_AUTO == cfg_dot11_mode) + || (eCSR_CFG_DOT11_MODE_ABG == cfg_dot11_mode)) { + csr_compute_mode_and_band(mac_ctx, &cfg_dot11_mode, + &band, opr_chn); + } /* if( eCSR_CFG_DOT11_MODE_ABG == cfg_dot11_mode ) */ + else { + /* dot11 mode is set, lets pick the band */ + if (eCSR_OPERATING_CHANNEL_AUTO == opr_chn) { + /* channel is Auto also. */ + band = mac_ctx->roam.configParam.eBand; + if (eCSR_BAND_ALL == band) { + /* prefer 5GHz */ + band = eCSR_BAND_5G; + } + } else{ + band = CSR_GET_BAND(opr_chn); + } + } + if (p_band) + *p_band = band; + + if (opr_chn == 14) { + sms_log(mac_ctx, LOGE, FL("Switching to Dot11B mode")); + cfg_dot11_mode = eCSR_CFG_DOT11_MODE_11B; + } + + if (IS_24G_CH(opr_chn) && + (false == mac_ctx->roam.configParam.enableVhtFor24GHz) && + (eCSR_CFG_DOT11_MODE_11AC == cfg_dot11_mode || + eCSR_CFG_DOT11_MODE_11AC_ONLY == cfg_dot11_mode)) + cfg_dot11_mode = eCSR_CFG_DOT11_MODE_11N; + /* + * Incase of WEP Security encryption type is coming as part of add key. + * So while STart BSS dont have information + */ + if ((!CSR_IS_11n_ALLOWED(profile->EncryptionType.encryptionType[0]) + || ((profile->privacy == 1) + && (profile->EncryptionType.encryptionType[0] == + eCSR_ENCRYPT_TYPE_NONE))) + && ((eCSR_CFG_DOT11_MODE_11N == cfg_dot11_mode) || + (eCSR_CFG_DOT11_MODE_11AC == cfg_dot11_mode))) { + /* We cannot do 11n here */ + if (CDS_IS_CHANNEL_24GHZ(opr_chn)) + cfg_dot11_mode = eCSR_CFG_DOT11_MODE_11G; + else + cfg_dot11_mode = eCSR_CFG_DOT11_MODE_11A; + } + return cfg_dot11_mode; +} + +QDF_STATUS csr_roam_issue_stop_bss(tpAniSirGlobal pMac, uint32_t sessionId, + eCsrRoamSubState NewSubstate) +{ + QDF_STATUS status; + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!pSession) { + sms_log(pMac, LOGE, FL(" session %d not found "), sessionId); + return QDF_STATUS_E_FAILURE; + } +#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR + { + host_log_ibss_pkt_type *pIbssLog; + WLAN_HOST_DIAG_LOG_ALLOC(pIbssLog, host_log_ibss_pkt_type, + LOG_WLAN_IBSS_C); + if (pIbssLog) { + pIbssLog->eventId = WLAN_IBSS_EVENT_STOP_REQ; + WLAN_HOST_DIAG_LOG_REPORT(pIbssLog); + } + } +#endif /* FEATURE_WLAN_DIAG_SUPPORT_CSR */ + /* Set the roaming substate to 'stop Bss request'... */ + csr_roam_substate_change(pMac, NewSubstate, sessionId); + + /* attempt to stop the Bss (reason code is ignored...) */ + status = csr_send_mb_stop_bss_req_msg(pMac, sessionId); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOGW, + FL("csr_send_mb_stop_bss_req_msg failed with status %d"), + status); + } + return status; +} + +/* pNumChan is a caller allocated space with the sizeof pChannels */ +QDF_STATUS csr_get_cfg_valid_channels(tpAniSirGlobal pMac, uint8_t *pChannels, + uint32_t *pNumChan) +{ + uint8_t num_chan_temp = 0; + int i; + + if (!IS_SIR_STATUS_SUCCESS(wlan_cfg_get_str(pMac, + WNI_CFG_VALID_CHANNEL_LIST, + (uint8_t *) pChannels, pNumChan))) + return QDF_STATUS_E_FAILURE; + + for (i = 0; i < *pNumChan; i++) { + if (!cds_is_dsrc_channel(cds_chan_to_freq(pChannels[i]))) { + pChannels[num_chan_temp] = pChannels[i]; + num_chan_temp++; + } + } + + *pNumChan = num_chan_temp; + return QDF_STATUS_SUCCESS; +} + +int8_t csr_get_cfg_max_tx_power(tpAniSirGlobal pMac, uint8_t channel) +{ + uint32_t cfgLength = 0; + uint16_t cfgId = 0; + int8_t maxTxPwr = 0; + uint8_t *pCountryInfo = NULL; + QDF_STATUS status; + uint8_t count = 0; + uint8_t firstChannel; + uint8_t maxChannels; + + if (CDS_IS_CHANNEL_5GHZ(channel)) { + cfgId = WNI_CFG_MAX_TX_POWER_5; + cfgLength = WNI_CFG_MAX_TX_POWER_5_LEN; + } else if (CDS_IS_CHANNEL_24GHZ(channel)) { + cfgId = WNI_CFG_MAX_TX_POWER_2_4; + cfgLength = WNI_CFG_MAX_TX_POWER_2_4_LEN; + } else + return maxTxPwr; + + pCountryInfo = qdf_mem_malloc(cfgLength); + if (NULL == pCountryInfo) + status = QDF_STATUS_E_NOMEM; + else + status = QDF_STATUS_SUCCESS; + if (status != QDF_STATUS_SUCCESS) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("%s: failed to allocate memory, status = %d"), + __FUNCTION__, status); + goto error; + } + if (wlan_cfg_get_str(pMac, cfgId, (uint8_t *)pCountryInfo, + &cfgLength) != eSIR_SUCCESS) { + goto error; + } + /* Identify the channel and maxtxpower */ + while (count <= (cfgLength - (sizeof(tSirMacChanInfo)))) { + firstChannel = pCountryInfo[count++]; + maxChannels = pCountryInfo[count++]; + maxTxPwr = pCountryInfo[count++]; + + if ((channel >= firstChannel) && + (channel < (firstChannel + maxChannels))) { + break; + } + } + +error: + if (NULL != pCountryInfo) + qdf_mem_free(pCountryInfo); + + return maxTxPwr; +} + +bool csr_roam_is_channel_valid(tpAniSirGlobal pMac, uint8_t channel) +{ + bool fValid = false; + uint32_t idxValidChannels; + uint32_t len = sizeof(pMac->roam.validChannelList); + + if (QDF_IS_STATUS_SUCCESS + (csr_get_cfg_valid_channels(pMac, pMac->roam.validChannelList, &len))) { + for (idxValidChannels = 0; (idxValidChannels < len); + idxValidChannels++) { + if (channel == + pMac->roam.validChannelList[idxValidChannels]) { + fValid = true; + break; + } + } + } + pMac->roam.numValidChannels = len; + return fValid; +} + +/* This function check and validate whether the NIC can do CB (40MHz) */ +static ePhyChanBondState csr_get_cb_mode_from_ies(tpAniSirGlobal pMac, + uint8_t primaryChn, + tDot11fBeaconIEs *pIes) +{ + ePhyChanBondState eRet = PHY_SINGLE_CHANNEL_CENTERED; + uint8_t centerChn; + uint32_t ChannelBondingMode; + if (CDS_IS_CHANNEL_24GHZ(primaryChn)) { + ChannelBondingMode = + pMac->roam.configParam.channelBondingMode24GHz; + } else { + ChannelBondingMode = + pMac->roam.configParam.channelBondingMode5GHz; + } + + if (WNI_CFG_CHANNEL_BONDING_MODE_DISABLE == ChannelBondingMode) + return PHY_SINGLE_CHANNEL_CENTERED; + + /* Figure what the other side's CB mode */ + if (!(pIes->HTCaps.present && (eHT_CHANNEL_WIDTH_40MHZ == + pIes->HTCaps.supportedChannelWidthSet))) { + return PHY_SINGLE_CHANNEL_CENTERED; + } + + /* In Case WPA2 and TKIP is the only one cipher suite in Pairwise */ + if ((pIes->RSN.present && (pIes->RSN.pwise_cipher_suite_count == 1) && + !memcmp(&(pIes->RSN.pwise_cipher_suites[0][0]), + "\x00\x0f\xac\x02", 4)) + /* In Case only WPA1 is supported and TKIP is + * the only one cipher suite in Unicast. + */ + || (!pIes->RSN.present && (pIes->WPA.present && + (pIes->WPA.unicast_cipher_count == 1) && + !memcmp(&(pIes->WPA.unicast_ciphers[0][0]), + "\x00\x50\xf2\x02", 4)))) { + sms_log(pMac, LOGW, + " No channel bonding in TKIP mode "); + return PHY_SINGLE_CHANNEL_CENTERED; + } + + if (!pIes->HTInfo.present) + return PHY_SINGLE_CHANNEL_CENTERED; + + /* + * This is called during INFRA STA/CLIENT and should use the merged + * value of supported channel width and recommended tx width as per + * standard + */ + sms_log(pMac, LOG1, "scws %u rtws %u sco %u", + pIes->HTCaps.supportedChannelWidthSet, + pIes->HTInfo.recommendedTxWidthSet, + pIes->HTInfo.secondaryChannelOffset); + + if (pIes->HTInfo.recommendedTxWidthSet == eHT_CHANNEL_WIDTH_40MHZ) + eRet = (ePhyChanBondState)pIes->HTInfo.secondaryChannelOffset; + else + eRet = PHY_SINGLE_CHANNEL_CENTERED; + + switch (eRet) { + case PHY_DOUBLE_CHANNEL_LOW_PRIMARY: + centerChn = primaryChn + CSR_CB_CENTER_CHANNEL_OFFSET; + break; + case PHY_DOUBLE_CHANNEL_HIGH_PRIMARY: + centerChn = primaryChn - CSR_CB_CENTER_CHANNEL_OFFSET; + break; + case PHY_SINGLE_CHANNEL_CENTERED: + default: + centerChn = primaryChn; + break; + } + + if ((PHY_SINGLE_CHANNEL_CENTERED != eRet) && + (QDF_STATUS_SUCCESS != sme_check_ch_in_band(pMac, + centerChn - 2, 2))) { + sms_log(pMac, LOGE, + "Invalid center channel (%d), disable 40MHz mode", + centerChn); + eRet = PHY_SINGLE_CHANNEL_CENTERED; + } + return eRet; +} + +static bool csr_is_encryption_in_list(tpAniSirGlobal pMac, + tCsrEncryptionList *pCipherList, + eCsrEncryptionType encryptionType) +{ + bool fFound = false; + uint32_t idx; + for (idx = 0; idx < pCipherList->numEntries; idx++) { + if (pCipherList->encryptionType[idx] == encryptionType) { + fFound = true; + break; + } + } + return fFound; +} + +static bool csr_is_auth_in_list(tpAniSirGlobal pMac, tCsrAuthList *pAuthList, + eCsrAuthType authType) +{ + bool fFound = false; + uint32_t idx; + for (idx = 0; idx < pAuthList->numEntries; idx++) { + if (pAuthList->authType[idx] == authType) { + fFound = true; + break; + } + } + return fFound; +} + +bool csr_is_same_profile(tpAniSirGlobal pMac, + tCsrRoamConnectedProfile *pProfile1, + tCsrRoamProfile *pProfile2) +{ + uint32_t i; + bool fCheck = false; + tCsrScanResultFilter *pScanFilter = NULL; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + if (!(pProfile1 && pProfile2)) + return fCheck; + pScanFilter = qdf_mem_malloc(sizeof(tCsrScanResultFilter)); + if (NULL == pScanFilter) + return fCheck; + + status = csr_roam_prepare_filter_from_profile(pMac, pProfile2, + pScanFilter); + if (!(QDF_IS_STATUS_SUCCESS(status))) + goto free_scan_filter; + + for (i = 0; i < pScanFilter->SSIDs.numOfSSIDs; i++) { + fCheck = csr_is_ssid_match(pMac, + pScanFilter->SSIDs.SSIDList[i].SSID.ssId, + pScanFilter->SSIDs.SSIDList[i].SSID.length, + pProfile1->SSID.ssId, + pProfile1->SSID.length, + false); + if (fCheck) + break; + } + if (!fCheck) + goto free_scan_filter; + + if (!csr_is_auth_in_list(pMac, &pProfile2->AuthType, + pProfile1->AuthType) + || (pProfile2->BSSType != pProfile1->BSSType) + || !csr_is_encryption_in_list(pMac, &pProfile2->EncryptionType, + pProfile1->EncryptionType)) { + fCheck = false; + goto free_scan_filter; + } + if (pProfile1->MDID.mdiePresent || pProfile2->MDID.mdiePresent) { + if (pProfile1->MDID.mobilityDomain + != pProfile2->MDID.mobilityDomain) { + fCheck = false; + goto free_scan_filter; + } + } + /* Match found */ + fCheck = true; +free_scan_filter: + csr_free_scan_filter(pMac, pScanFilter); + qdf_mem_free(pScanFilter); + return fCheck; +} + +bool csr_roam_is_same_profile_keys(tpAniSirGlobal pMac, + tCsrRoamConnectedProfile *pConnProfile, + tCsrRoamProfile *pProfile2) +{ + bool fCheck = false; + int i; + do { + /* Only check for static WEP */ + if (!csr_is_encryption_in_list + (pMac, &pProfile2->EncryptionType, + eCSR_ENCRYPT_TYPE_WEP40_STATICKEY) + && !csr_is_encryption_in_list(pMac, + &pProfile2->EncryptionType, + eCSR_ENCRYPT_TYPE_WEP104_STATICKEY)) { + fCheck = true; + break; + } + if (!csr_is_encryption_in_list + (pMac, &pProfile2->EncryptionType, + pConnProfile->EncryptionType)) + break; + if (pConnProfile->Keys.defaultIndex != + pProfile2->Keys.defaultIndex) + break; + for (i = 0; i < CSR_MAX_NUM_KEY; i++) { + if (pConnProfile->Keys.KeyLength[i] != + pProfile2->Keys.KeyLength[i]) + break; + if (qdf_mem_cmp(&pConnProfile->Keys.KeyMaterial[i], + &pProfile2->Keys.KeyMaterial[i], + pProfile2->Keys.KeyLength[i])) { + break; + } + } + if (i == CSR_MAX_NUM_KEY) { + fCheck = true; + } + } while (0); + return fCheck; +} + +/* IBSS */ + +static uint8_t csr_roam_get_ibss_start_channel_number50(tpAniSirGlobal pMac) +{ + uint8_t channel = 0; + uint32_t idx; + uint32_t idxValidChannels; + bool fFound = false; + uint32_t len = sizeof(pMac->roam.validChannelList); + + if (eCSR_OPERATING_CHANNEL_ANY != pMac->roam.configParam.AdHocChannel5G) { + channel = pMac->roam.configParam.AdHocChannel5G; + if (!csr_roam_is_channel_valid(pMac, channel)) { + channel = 0; + } + } + if (0 == channel + && + QDF_IS_STATUS_SUCCESS(csr_get_cfg_valid_channels + (pMac, + (uint8_t *) pMac->roam.validChannelList, + &len))) { + for (idx = 0; (idx < CSR_NUM_IBSS_START_CHANNELS_50) && !fFound; + idx++) { + for (idxValidChannels = 0; + (idxValidChannels < len) && !fFound; + idxValidChannels++) { + if (csr_start_ibss_channels50[idx] == + pMac->roam. + validChannelList[idxValidChannels]) { + fFound = true; + channel = csr_start_ibss_channels50[idx]; + } + } + } + /* + * this is rare, but if it does happen, + * we find anyone in 11a bandwidth and + * return the first 11a channel found! + */ + if (!fFound) { + for (idxValidChannels = 0; idxValidChannels < len; + idxValidChannels++) { + if (CDS_IS_CHANNEL_5GHZ(pMac->roam. + validChannelList[idxValidChannels])) { + /* the max channel# in 11g is 14 */ + if (idxValidChannels < + CSR_NUM_IBSS_START_CHANNELS_50) { + channel = + pMac->roam.validChannelList + [idxValidChannels]; + } + break; + } + } + } + } /* if */ + + return channel; +} + +static uint8_t csr_roam_get_ibss_start_channel_number24(tpAniSirGlobal pMac) +{ + uint8_t channel = 1; + uint32_t idx; + uint32_t idxValidChannels; + bool fFound = false; + uint32_t len = sizeof(pMac->roam.validChannelList); + + if (eCSR_OPERATING_CHANNEL_ANY != pMac->roam.configParam.AdHocChannel24) { + channel = pMac->roam.configParam.AdHocChannel24; + if (!csr_roam_is_channel_valid(pMac, channel)) { + channel = 0; + } + } + + if (0 == channel + && + QDF_IS_STATUS_SUCCESS(csr_get_cfg_valid_channels + (pMac, + (uint8_t *) pMac->roam.validChannelList, + &len))) { + for (idx = 0; (idx < CSR_NUM_IBSS_START_CHANNELS_24) && !fFound; + idx++) { + for (idxValidChannels = 0; + (idxValidChannels < len) && !fFound; + idxValidChannels++) { + if (csr_start_ibss_channels24[idx] == + pMac->roam. + validChannelList[idxValidChannels]) { + fFound = true; + channel = csr_start_ibss_channels24[idx]; + } + } + } + } + + return channel; +} +/** + * csr_populate_basic_rates() - populates OFDM or CCK rates + * @rates: rate struct to populate + * @is_ofdm_rates: true: ofdm rates, false: cck rates + * @is_basic_rates: indicates if rates are to be masked with + * CSR_DOT11_BASIC_RATE_MASK + * + * This function will populate OFDM or CCK rates + * + * Return: void + */ +static void +csr_populate_basic_rates(tSirMacRateSet *rate_set, bool is_ofdm_rates, + bool is_basic_rates) +{ + int i = 0; + uint8_t ofdm_rates[8] = { + SIR_MAC_RATE_6, + SIR_MAC_RATE_9, + SIR_MAC_RATE_12, + SIR_MAC_RATE_18, + SIR_MAC_RATE_24, + SIR_MAC_RATE_36, + SIR_MAC_RATE_48, + SIR_MAC_RATE_54 + }; + uint8_t cck_rates[4] = { + SIR_MAC_RATE_1, + SIR_MAC_RATE_2, + SIR_MAC_RATE_5_5, + SIR_MAC_RATE_11 + }; + + if (is_ofdm_rates == true) { + rate_set->numRates = 8; + qdf_mem_copy(rate_set->rate, ofdm_rates, sizeof(ofdm_rates)); + if (is_basic_rates) { + rate_set->rate[0] |= CSR_DOT11_BASIC_RATE_MASK; + rate_set->rate[2] |= CSR_DOT11_BASIC_RATE_MASK; + rate_set->rate[4] |= CSR_DOT11_BASIC_RATE_MASK; + } + for (i = 0; i < rate_set->numRates; i++) + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO, + FL("Default OFDM rate is %2x"), rate_set->rate[i]); + } else { + rate_set->numRates = 4; + qdf_mem_copy(rate_set->rate, cck_rates, sizeof(cck_rates)); + if (is_basic_rates) { + rate_set->rate[0] |= CSR_DOT11_BASIC_RATE_MASK; + rate_set->rate[1] |= CSR_DOT11_BASIC_RATE_MASK; + rate_set->rate[2] |= CSR_DOT11_BASIC_RATE_MASK; + rate_set->rate[3] |= CSR_DOT11_BASIC_RATE_MASK; + } + for (i = 0; i < rate_set->numRates; i++) + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO, + FL("Default CCK rate is %2x"), rate_set->rate[i]); + + } +} + +/** + * csr_convert_mode_to_nw_type() - convert mode into network type + * @dot11_mode: dot11_mode + * @band: 2.4 or 5 GHz + * + * Return: tSirNwType + */ +static tSirNwType +csr_convert_mode_to_nw_type(eCsrCfgDot11Mode dot11_mode, eCsrBand band) +{ + switch (dot11_mode) { + case eCSR_CFG_DOT11_MODE_11G: + return eSIR_11G_NW_TYPE; + case eCSR_CFG_DOT11_MODE_11B: + return eSIR_11B_NW_TYPE; + case eCSR_CFG_DOT11_MODE_11A: + return eSIR_11A_NW_TYPE; + case eCSR_CFG_DOT11_MODE_11N: + default: + /* + * Because LIM only verifies it against 11a, 11b or 11g, set + * only 11g or 11a here + */ + if (eCSR_BAND_24 == band) + return eSIR_11G_NW_TYPE; + else + return eSIR_11A_NW_TYPE; + } + return eSIR_DONOT_USE_NW_TYPE; +} + +/** + * csr_populate_supported_rates_from_hostapd() - populates operational + * and extended rates. + * from hostapd.conf file + * @opr_rates: rate struct to populate operational rates + * @ext_rates: rate struct to populate extended rates + * @profile: bss profile + * + * Return: void + */ +static void csr_populate_supported_rates_from_hostapd(tSirMacRateSet *opr_rates, + tSirMacRateSet *ext_rates, + tCsrRoamProfile *pProfile) +{ + int i = 0; + if (pProfile->supported_rates.numRates) { + opr_rates->numRates = pProfile->supported_rates.numRates; + qdf_mem_copy(opr_rates->rate, + pProfile->supported_rates.rate, + pProfile->supported_rates.numRates); + for (i = 0; i < opr_rates->numRates; i++) + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO, + FL("Supported Rate is %2x"), opr_rates->rate[i]); + } + if (pProfile->extended_rates.numRates) { + ext_rates->numRates = + pProfile->extended_rates.numRates; + qdf_mem_copy(ext_rates->rate, + pProfile->extended_rates.rate, + pProfile->extended_rates.numRates); + for (i = 0; i < ext_rates->numRates; i++) + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO, + FL("Extended Rate is %2x"), ext_rates->rate[i]); + } +} +/** + * csr_roam_get_bss_start_parms() - get bss start param from profile + * @pMac: mac global context + * @pProfile: roam profile + * @pParam: out param, start bss params + * @skip_hostapd_rate: to skip given hostapd's rate + * + * This function populates start bss param from roam profile + * + * Return: void + */ +static void +csr_roam_get_bss_start_parms(tpAniSirGlobal pMac, + tCsrRoamProfile *pProfile, + tCsrRoamStartBssParams *pParam, + bool skip_hostapd_rate) +{ + eCsrBand band; + uint8_t opr_ch = 0; + tSirNwType nw_type; + uint8_t tmp_opr_ch = 0; + tSirMacRateSet *opr_rates = &pParam->operationalRateSet; + tSirMacRateSet *ext_rates = &pParam->extendedRateSet; + + if (pProfile->ChannelInfo.numOfChannels + && pProfile->ChannelInfo.ChannelList) { + tmp_opr_ch = pProfile->ChannelInfo.ChannelList[0]; + } + + pParam->uCfgDot11Mode = csr_roam_get_phy_mode_band_for_bss(pMac, + pProfile, tmp_opr_ch, &band); + + if (((pProfile->csrPersona == QDF_P2P_CLIENT_MODE) + || (pProfile->csrPersona == QDF_P2P_GO_MODE)) + && (pParam->uCfgDot11Mode == eCSR_CFG_DOT11_MODE_11B)) { + /* This should never happen */ + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_FATAL, + FL("For P2P (persona %d) dot11_mode is 11B"), + pProfile->csrPersona); + QDF_ASSERT(0); + } + + nw_type = csr_convert_mode_to_nw_type(pParam->uCfgDot11Mode, band); + ext_rates->numRates = 0; + /* + * hostapd.conf will populate its basic and extended rates + * as per hw_mode but if acs in ini is enabled, driver should + * ignore basic and extended rates from hostapd.conf and should + * populate default rates. + */ + if (!cds_is_sub_20_mhz_enabled() && !skip_hostapd_rate && + (pProfile->supported_rates.numRates || + pProfile->extended_rates.numRates)) { + csr_populate_supported_rates_from_hostapd(opr_rates, + ext_rates, pProfile); + pParam->operationChn = tmp_opr_ch; + } else { + switch (nw_type) { + default: + sms_log(pMac, LOGE, + FL("sees an unknown pSirNwType (%d)"), + nw_type); + case eSIR_11A_NW_TYPE: + csr_populate_basic_rates(opr_rates, true, true); + if (eCSR_OPERATING_CHANNEL_ANY != tmp_opr_ch) { + opr_ch = tmp_opr_ch; + break; + } + opr_ch = csr_roam_get_ibss_start_channel_number50(pMac); + if (0 == opr_ch && + CSR_IS_PHY_MODE_DUAL_BAND(pProfile->phyMode) && + CSR_IS_PHY_MODE_DUAL_BAND( + pMac->roam.configParam.phyMode)) { + /* + * We could not find a 5G channel by auto pick, + * let's try 2.4G channels. We only do this here + * because csr_roam_get_phy_mode_band_for_bss + * always picks 11a for AUTO + */ + nw_type = eSIR_11B_NW_TYPE; + opr_ch = + csr_roam_get_ibss_start_channel_number24(pMac); + csr_populate_basic_rates(opr_rates, false, + true); + } + break; + case eSIR_11B_NW_TYPE: + csr_populate_basic_rates(opr_rates, false, true); + if (eCSR_OPERATING_CHANNEL_ANY == tmp_opr_ch) + opr_ch = + csr_roam_get_ibss_start_channel_number24(pMac); + else + opr_ch = tmp_opr_ch; + break; + case eSIR_11G_NW_TYPE: + /* For P2P Client and P2P GO, disable 11b rates */ + if ((pProfile->csrPersona == QDF_P2P_CLIENT_MODE) || + (pProfile->csrPersona == QDF_P2P_GO_MODE) || + (eCSR_CFG_DOT11_MODE_11G_ONLY == + pParam->uCfgDot11Mode)) { + csr_populate_basic_rates(opr_rates, true, true); + } else { + csr_populate_basic_rates(opr_rates, false, + true); + csr_populate_basic_rates(ext_rates, true, + false); + } + if (eCSR_OPERATING_CHANNEL_ANY == tmp_opr_ch) + opr_ch = + csr_roam_get_ibss_start_channel_number24(pMac); + else + opr_ch = tmp_opr_ch; + break; + } + pParam->operationChn = opr_ch; + } + pParam->sirNwType = nw_type; + pParam->ch_params.ch_width = pProfile->ch_params.ch_width; + pParam->ch_params.center_freq_seg0 = + pProfile->ch_params.center_freq_seg0; + pParam->ch_params.center_freq_seg1 = + pProfile->ch_params.center_freq_seg1; + pParam->ch_params.sec_ch_offset = + pProfile->ch_params.sec_ch_offset; +} + +static void +csr_roam_get_bss_start_parms_from_bss_desc(tpAniSirGlobal pMac, + tSirBssDescription *pBssDesc, + tDot11fBeaconIEs *pIes, + tCsrRoamStartBssParams *pParam) +{ + if (!pParam) { + sms_log(pMac, LOGE, FL("BSS param's pointer is NULL")); + return; + } + + pParam->sirNwType = pBssDesc->nwType; + pParam->cbMode = PHY_SINGLE_CHANNEL_CENTERED; + pParam->operationChn = pBssDesc->channelId; + qdf_mem_copy(&pParam->bssid, pBssDesc->bssId, sizeof(struct qdf_mac_addr)); + + if (!pIes) { + pParam->ssId.length = 0; + pParam->operationalRateSet.numRates = 0; + sms_log(pMac, LOGE, FL("IEs struct pointer is NULL")); + return; + } + + if (pIes->SuppRates.present) { + pParam->operationalRateSet.numRates = pIes->SuppRates.num_rates; + if (pIes->SuppRates.num_rates > SIR_MAC_RATESET_EID_MAX) { + sms_log(pMac, LOGE, + FL("num_rates: %d > max val, resetting"), + pIes->SuppRates.num_rates); + pIes->SuppRates.num_rates = SIR_MAC_RATESET_EID_MAX; + } + qdf_mem_copy(pParam->operationalRateSet.rate, + pIes->SuppRates.rates, + sizeof(*pIes->SuppRates.rates) * + pIes->SuppRates.num_rates); + } + if (pIes->ExtSuppRates.present) { + pParam->extendedRateSet.numRates = pIes->ExtSuppRates.num_rates; + if (pIes->ExtSuppRates.num_rates > SIR_MAC_RATESET_EID_MAX) { + sms_log(pMac, LOGE, + FL("num_rates: %d > max val, resetting"), + pIes->ExtSuppRates.num_rates); + pIes->ExtSuppRates.num_rates = SIR_MAC_RATESET_EID_MAX; + } + qdf_mem_copy(pParam->extendedRateSet.rate, + pIes->ExtSuppRates.rates, + sizeof(*pIes->ExtSuppRates.rates) * + pIes->ExtSuppRates.num_rates); + } + if (pIes->SSID.present) { + pParam->ssId.length = pIes->SSID.num_ssid; + qdf_mem_copy(pParam->ssId.ssId, pIes->SSID.ssid, + pParam->ssId.length); + } + pParam->cbMode = csr_get_cb_mode_from_ies(pMac, pParam->operationChn, + pIes); +} + +static void csr_roam_determine_max_rate_for_ad_hoc(tpAniSirGlobal pMac, + tSirMacRateSet *pSirRateSet) +{ + uint8_t MaxRate = 0; + uint32_t i; + uint8_t *pRate; + + pRate = pSirRateSet->rate; + for (i = 0; i < pSirRateSet->numRates; i++) { + MaxRate = + CSR_MAX(MaxRate, (pRate[i] & (~CSR_DOT11_BASIC_RATE_MASK))); + } + + /* Save the max rate in the connected state information... */ + + /* modify LastRates variable as well */ + + return; +} + +QDF_STATUS csr_roam_issue_start_bss(tpAniSirGlobal pMac, uint32_t sessionId, + tCsrRoamStartBssParams *pParam, + tCsrRoamProfile *pProfile, + tSirBssDescription *pBssDesc, uint32_t roamId) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + eCsrBand eBand; + /* Set the roaming substate to 'Start BSS attempt'... */ + csr_roam_substate_change(pMac, eCSR_ROAM_SUBSTATE_START_BSS_REQ, + sessionId); +#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR + /* Need to figure out whether we need to log WDS??? */ + if (CSR_IS_IBSS(pProfile)) { + host_log_ibss_pkt_type *pIbssLog; + WLAN_HOST_DIAG_LOG_ALLOC(pIbssLog, host_log_ibss_pkt_type, + LOG_WLAN_IBSS_C); + if (pIbssLog) { + if (pBssDesc) { + pIbssLog->eventId = + WLAN_IBSS_EVENT_JOIN_IBSS_REQ; + qdf_mem_copy(pIbssLog->bssid.bytes, + pBssDesc->bssId, QDF_MAC_ADDR_SIZE); + } else { + pIbssLog->eventId = + WLAN_IBSS_EVENT_START_IBSS_REQ; + } + qdf_mem_copy(pIbssLog->ssid, pParam->ssId.ssId, + pParam->ssId.length); + if (pProfile->ChannelInfo.numOfChannels == 0) { + pIbssLog->channelSetting = AUTO_PICK; + } else { + pIbssLog->channelSetting = SPECIFIED; + } + pIbssLog->operatingChannel = pParam->operationChn; + WLAN_HOST_DIAG_LOG_REPORT(pIbssLog); + } + } +#endif /* FEATURE_WLAN_DIAG_SUPPORT_CSR */ + /* Put RSN information in for Starting BSS */ + pParam->nRSNIELength = (uint16_t) pProfile->nRSNReqIELength; + pParam->pRSNIE = pProfile->pRSNReqIE; + + pParam->privacy = pProfile->privacy; + pParam->fwdWPSPBCProbeReq = pProfile->fwdWPSPBCProbeReq; + pParam->authType = pProfile->csr80211AuthType; + pParam->beaconInterval = pProfile->beaconInterval; + pParam->dtimPeriod = pProfile->dtimPeriod; + pParam->ApUapsdEnable = pProfile->ApUapsdEnable; + pParam->ssidHidden = pProfile->SSIDs.SSIDList[0].ssidHidden; + if (CSR_IS_INFRA_AP(pProfile) && (pParam->operationChn != 0)) { + if (csr_is_valid_channel(pMac, pParam->operationChn) != + QDF_STATUS_SUCCESS) { + pParam->operationChn = INFRA_AP_DEFAULT_CHANNEL; + } + } + pParam->protEnabled = pProfile->protEnabled; + pParam->obssProtEnabled = pProfile->obssProtEnabled; + pParam->ht_protection = pProfile->cfg_protection; + pParam->wps_state = pProfile->wps_state; + + pParam->uCfgDot11Mode = + csr_roam_get_phy_mode_band_for_bss(pMac, pProfile, + pParam-> + operationChn, + &eBand); + pParam->bssPersona = pProfile->csrPersona; + +#ifdef WLAN_FEATURE_11W + pParam->mfpCapable = (0 != pProfile->MFPCapable); + pParam->mfpRequired = (0 != pProfile->MFPRequired); +#endif + + pParam->addIeParams.probeRespDataLen = + pProfile->addIeParams.probeRespDataLen; + pParam->addIeParams.probeRespData_buff = + pProfile->addIeParams.probeRespData_buff; + + pParam->addIeParams.assocRespDataLen = + pProfile->addIeParams.assocRespDataLen; + pParam->addIeParams.assocRespData_buff = + pProfile->addIeParams.assocRespData_buff; + + if (CSR_IS_IBSS(pProfile)) { + pParam->addIeParams.probeRespBCNDataLen = + pProfile->nWPAReqIELength; + pParam->addIeParams.probeRespBCNData_buff = pProfile->pWPAReqIE; + } else { + pParam->addIeParams.probeRespBCNDataLen = + pProfile->addIeParams.probeRespBCNDataLen; + pParam->addIeParams.probeRespBCNData_buff = + pProfile->addIeParams.probeRespBCNData_buff; + } + pParam->sap_dot11mc = pProfile->sap_dot11mc; + + /* When starting an IBSS, start on the channel from the Profile. */ + status = + csr_send_mb_start_bss_req_msg(pMac, sessionId, pProfile->BSSType, pParam, + pBssDesc); + return status; +} + +void csr_roam_prepare_bss_params(tpAniSirGlobal pMac, uint32_t sessionId, + tCsrRoamProfile *pProfile, + tSirBssDescription *pBssDesc, + tBssConfigParam *pBssConfig, + tDot11fBeaconIEs *pIes) +{ + uint8_t Channel; + ePhyChanBondState cbMode = PHY_SINGLE_CHANNEL_CENTERED; + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!pSession) { + sms_log(pMac, LOGE, FL(" session %d not found "), sessionId); + return; + } + + if (pBssDesc) { + csr_roam_get_bss_start_parms_from_bss_desc(pMac, pBssDesc, pIes, + &pSession->bssParams); + if (CSR_IS_NDI(pProfile)) { + qdf_copy_macaddr(&pSession->bssParams.bssid, + &pSession->selfMacAddr); + } + } else { + csr_roam_get_bss_start_parms(pMac, pProfile, + &pSession->bssParams, false); + /* Use the first SSID */ + if (pProfile->SSIDs.numOfSSIDs) + qdf_mem_copy(&pSession->bssParams.ssId, + pProfile->SSIDs.SSIDList, + sizeof(tSirMacSSid)); + if (pProfile->BSSIDs.numOfBSSIDs) + /* Use the first BSSID */ + qdf_mem_copy(&pSession->bssParams.bssid, + pProfile->BSSIDs.bssid, + sizeof(struct qdf_mac_addr)); + else + qdf_mem_set(&pSession->bssParams.bssid, + sizeof(struct qdf_mac_addr), 0); + } + Channel = pSession->bssParams.operationChn; + /* Set operating channel in pProfile which will be used */ + /* in csr_roam_set_bss_config_cfg() to determine channel bonding */ + /* mode and will be configured in CFG later */ + pProfile->operationChannel = Channel; + + if (Channel == 0) { + sms_log(pMac, LOGE, + " CSR cannot find a channel to start IBSS"); + } else { + + csr_roam_determine_max_rate_for_ad_hoc(pMac, + &pSession->bssParams. + operationalRateSet); + if (CSR_IS_INFRA_AP(pProfile) || CSR_IS_START_IBSS(pProfile)) { + if (CDS_IS_CHANNEL_24GHZ(Channel)) { + cbMode = + pMac->roam.configParam. + channelBondingMode24GHz; + } else { + cbMode = + pMac->roam.configParam. + channelBondingMode5GHz; + } + sms_log(pMac, LOG1, "## cbMode %d", cbMode); + pBssConfig->cbMode = cbMode; + pSession->bssParams.cbMode = cbMode; + } + } +} + +static QDF_STATUS csr_roam_start_ibss(tpAniSirGlobal pMac, uint32_t sessionId, + tCsrRoamProfile *pProfile, + bool *pfSameIbss) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + bool fSameIbss = false; + + if (csr_is_conn_state_ibss(pMac, sessionId)) { + /* Check if any profile parameter has changed ? If any profile parameter */ + /* has changed then stop old BSS and start a new one with new parameters */ + if (csr_is_same_profile + (pMac, &pMac->roam.roamSession[sessionId].connectedProfile, + pProfile)) { + fSameIbss = true; + } else { + status = + csr_roam_issue_stop_bss(pMac, sessionId, + eCSR_ROAM_SUBSTATE_DISCONNECT_CONTINUE_ROAMING); + } + } else if (csr_is_conn_state_connected_infra(pMac, sessionId)) { + /* Disassociate from the connected Infrastructure network... */ + status = + csr_roam_issue_disassociate(pMac, sessionId, + eCSR_ROAM_SUBSTATE_DISCONNECT_CONTINUE_ROAMING, + false); + } else { + tBssConfigParam *pBssConfig; + + pBssConfig = qdf_mem_malloc(sizeof(tBssConfigParam)); + if (NULL == pBssConfig) + status = QDF_STATUS_E_NOMEM; + else + status = QDF_STATUS_SUCCESS; + if (QDF_IS_STATUS_SUCCESS(status)) { + /* there is no Bss description before we start an IBSS so we need to adopt */ + /* all Bss configuration parameters from the Profile. */ + status = + csr_roam_prepare_bss_config_from_profile(pMac, pProfile, + pBssConfig, + NULL); + if (QDF_IS_STATUS_SUCCESS(status)) { + /* save dotMode */ + pMac->roam.roamSession[sessionId].bssParams. + uCfgDot11Mode = pBssConfig->uCfgDot11Mode; + /* Prepare some more parameters for this IBSS */ + csr_roam_prepare_bss_params(pMac, sessionId, + pProfile, NULL, + pBssConfig, NULL); + status = + csr_roam_set_bss_config_cfg(pMac, sessionId, + pProfile, NULL, + pBssConfig, NULL, + false); + } + + qdf_mem_free(pBssConfig); + } /* Allocate memory */ + } + + if (pfSameIbss) { + *pfSameIbss = fSameIbss; + } + return status; +} + +static void csr_roam_update_connected_profile_from_new_bss(tpAniSirGlobal pMac, + uint32_t sessionId, + tSirSmeNewBssInfo *pNewBss) +{ + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!pSession) { + sms_log(pMac, LOGE, FL(" session %d not found "), sessionId); + return; + } + + if (pNewBss) { + /* Set the operating channel. */ + pSession->connectedProfile.operationChannel = + pNewBss->channelNumber; + /* move the BSSId from the BSS description into the connected state information. */ + qdf_mem_copy(&pSession->connectedProfile.bssid.bytes, + &(pNewBss->bssId), sizeof(struct qdf_mac_addr)); + } + return; +} + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +QDF_STATUS csr_roam_set_psk_pmk(tpAniSirGlobal pMac, uint32_t sessionId, + uint8_t *pPSK_PMK, size_t pmk_len) +{ + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + if (!pSession) { + sms_log(pMac, LOGE, FL("session %d not found"), sessionId); + return QDF_STATUS_E_FAILURE; + } + qdf_mem_copy(pSession->psk_pmk, pPSK_PMK, sizeof(pSession->psk_pmk)); + pSession->pmk_len = pmk_len; + csr_roam_offload_scan(pMac, sessionId, + ROAM_SCAN_OFFLOAD_UPDATE_CFG, + REASON_ROAM_PSK_PMK_CHANGED); + return QDF_STATUS_SUCCESS; +} +#endif /* WLAN_FEATURE_ROAM_OFFLOAD */ + +#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR +static void +csr_roam_diag_set_pmkid(tCsrRoamSession *pSession) +{ + WLAN_HOST_DIAG_EVENT_DEF(secEvent, + host_event_wlan_security_payload_type); + qdf_mem_set(&secEvent, + sizeof(host_event_wlan_security_payload_type), 0); + secEvent.eventId = WLAN_SECURITY_EVENT_PMKID_UPDATE; + secEvent.encryptionModeMulticast = + (uint8_t) diag_enc_type_from_csr_type( + pSession->connectedProfile.mcEncryptionType); + secEvent.encryptionModeUnicast = + (uint8_t) diag_enc_type_from_csr_type( + pSession->connectedProfile.EncryptionType); + qdf_mem_copy(secEvent.bssid, + pSession->connectedProfile.bssid.bytes, + QDF_MAC_ADDR_SIZE); + secEvent.authMode = (uint8_t) diag_auth_type_from_csr_type( + pSession->connectedProfile.AuthType); + WLAN_HOST_DIAG_EVENT_REPORT(&secEvent, EVENT_WLAN_SECURITY); +} +#endif /* FEATURE_WLAN_DIAG_SUPPORT_CSR */ + +QDF_STATUS +csr_roam_set_pmkid_cache(tpAniSirGlobal pMac, uint32_t sessionId, + tPmkidCacheInfo *pPMKIDCache, uint32_t numItems, + bool update_entire_cache) +{ + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + uint32_t i = 0; + tPmkidCacheInfo *pmksa; + + if (!pSession) { + sms_log(pMac, LOGE, FL("session %d not found"), sessionId); + return QDF_STATUS_E_FAILURE; + } + + sms_log(pMac, LOGW, FL("numItems = %d"), numItems); + + if (numItems > CSR_MAX_PMKID_ALLOWED) + return QDF_STATUS_E_INVAL; + +#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR + csr_roam_diag_set_pmkid(pSession); +#endif /* FEATURE_WLAN_DIAG_SUPPORT_CSR */ + + if (update_entire_cache) { + if (numItems && pPMKIDCache) { + pSession->NumPmkidCache = (uint16_t) numItems; + qdf_mem_copy(pSession->PmkidCacheInfo, pPMKIDCache, + sizeof(tPmkidCacheInfo) * numItems); + pSession->curr_cache_idx = (uint16_t)numItems; + } + return QDF_STATUS_SUCCESS; + } + + for (i = 0; i < numItems; i++) { + pmksa = &pPMKIDCache[i]; + + /* Delete the entry if present */ + csr_roam_del_pmkid_from_cache(pMac, sessionId, + pmksa->BSSID.bytes, false); + + /* Add entry to the cache */ + qdf_copy_macaddr( + &pSession->PmkidCacheInfo[pSession->curr_cache_idx].BSSID, + &pmksa->BSSID); + qdf_mem_copy( + pSession->PmkidCacheInfo[pSession->curr_cache_idx].PMKID, + pmksa->PMKID, CSR_RSN_PMKID_SIZE); + + /* Increment the CSR local cache index */ + if (pSession->curr_cache_idx < (CSR_MAX_PMKID_ALLOWED - 1)) + pSession->curr_cache_idx++; + else + pSession->curr_cache_idx = 0; + + pSession->NumPmkidCache++; + if (pSession->NumPmkidCache > CSR_MAX_PMKID_ALLOWED) + pSession->NumPmkidCache = CSR_MAX_PMKID_ALLOWED; + } + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS csr_roam_del_pmkid_from_cache(tpAniSirGlobal pMac, + uint32_t sessionId, + const uint8_t *pBSSId, + bool flush_cache) +{ + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + bool fMatchFound = false; + uint32_t Index; + uint32_t curr_idx; + uint32_t i; + + if (!pSession) { + sms_log(pMac, LOGE, FL(" session %d not found "), sessionId); + return QDF_STATUS_E_FAILURE; + } + + /* Check if there are no entries to delete */ + if (0 == pSession->NumPmkidCache) { + sms_log(pMac, LOG1, FL("No entries to delete/Flush")); + return QDF_STATUS_SUCCESS; + } + + if (flush_cache) { + /* Flush the entire cache */ + qdf_mem_zero(pSession->PmkidCacheInfo, + sizeof(tPmkidCacheInfo) * CSR_MAX_PMKID_ALLOWED); + pSession->NumPmkidCache = 0; + pSession->curr_cache_idx = 0; + return QDF_STATUS_SUCCESS; + } + + /* !flush_cache - so look up in the cache */ + for (Index = 0; Index < CSR_MAX_PMKID_ALLOWED; Index++) { + if (!qdf_mem_cmp(pSession->PmkidCacheInfo[Index].BSSID.bytes, + pBSSId, QDF_MAC_ADDR_SIZE)) { + fMatchFound = 1; + + /* Clear this - the matched entry */ + qdf_mem_zero(&pSession->PmkidCacheInfo[Index], + sizeof(tPmkidCacheInfo)); + break; + } + } + + if (Index == CSR_MAX_PMKID_ALLOWED && !fMatchFound) { + sms_log(pMac, LOG1, FL("No such PMKSA entry exists" + MAC_ADDRESS_STR), MAC_ADDR_ARRAY(pBSSId)); + return QDF_STATUS_SUCCESS; + } + + /* Match Found, Readjust the other entries */ + curr_idx = pSession->curr_cache_idx; + if (Index < curr_idx) { + for (i = Index; i < (curr_idx - 1); i++) { + qdf_mem_copy(&pSession->PmkidCacheInfo[i], + &pSession->PmkidCacheInfo[i + 1], + sizeof(tPmkidCacheInfo)); + } + + pSession->curr_cache_idx--; + qdf_mem_zero(&pSession->PmkidCacheInfo + [pSession->curr_cache_idx], + sizeof(tPmkidCacheInfo)); + } else if (Index > curr_idx) { + for (i = Index; i > (curr_idx); i--) { + qdf_mem_copy(&pSession->PmkidCacheInfo[i], + &pSession->PmkidCacheInfo[i - 1], + sizeof(tPmkidCacheInfo)); + } + + qdf_mem_zero(&pSession->PmkidCacheInfo + [pSession->curr_cache_idx], + sizeof(tPmkidCacheInfo)); + } + + /* Decrement the count since an entry has been deleted */ + pSession->NumPmkidCache--; + return QDF_STATUS_SUCCESS; +} + +uint32_t csr_roam_get_num_pmkid_cache(tpAniSirGlobal pMac, uint32_t sessionId) +{ + return pMac->roam.roamSession[sessionId].NumPmkidCache; +} + +QDF_STATUS csr_roam_get_pmkid_cache(tpAniSirGlobal pMac, uint32_t sessionId, + uint32_t *pNum, tPmkidCacheInfo *pPmkidCache) +{ + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + tPmkidCacheInfo *pmksa; + uint16_t i, j; + + if (!pSession) { + sms_log(pMac, LOGE, FL("session %d not found "), sessionId); + return QDF_STATUS_E_FAILURE; + } + + if (!pNum || !pPmkidCache) { + sms_log(pMac, LOGE, FL("Either pNum or pPmkidCache is NULL")); + return QDF_STATUS_E_FAILURE; + } + + if (pSession->NumPmkidCache == 0) { + *pNum = 0; + return QDF_STATUS_SUCCESS; + } + + if (*pNum < pSession->NumPmkidCache) { + return QDF_STATUS_E_FAILURE; + } + + if (pSession->NumPmkidCache > CSR_MAX_PMKID_ALLOWED) { + sms_log(pMac, LOGE, + FL( + "NumPmkidCache :%d is more than CSR_MAX_PMKID_ALLOWED, resetting to CSR_MAX_PMKID_ALLOWED"), + pSession->NumPmkidCache); + pSession->NumPmkidCache = CSR_MAX_PMKID_ALLOWED; + } + + for (i = 0, j = 0; ((j < pSession->NumPmkidCache) && + (i < CSR_MAX_PMKID_ALLOWED)); i++) { + /* Fill the valid entries */ + pmksa = &pSession->PmkidCacheInfo[i]; + if (!qdf_is_macaddr_zero(&pmksa->BSSID)) { + qdf_mem_copy(pPmkidCache, pmksa, + sizeof(tPmkidCacheInfo)); + pPmkidCache++; + j++; + } + } + + *pNum = pSession->NumPmkidCache; + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS csr_roam_get_wpa_rsn_req_ie(tpAniSirGlobal pMac, uint32_t sessionId, + uint32_t *pLen, uint8_t *pBuf) +{ + QDF_STATUS status = QDF_STATUS_E_INVAL; + uint32_t len; + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!pSession) { + sms_log(pMac, LOGE, FL(" session %d not found "), sessionId); + return QDF_STATUS_E_FAILURE; + } + + if (pLen) { + len = *pLen; + *pLen = pSession->nWpaRsnReqIeLength; + if (pBuf) { + if (len >= pSession->nWpaRsnReqIeLength) { + qdf_mem_copy(pBuf, pSession->pWpaRsnReqIE, + pSession->nWpaRsnReqIeLength); + status = QDF_STATUS_SUCCESS; + } + } + } + return status; +} + +QDF_STATUS csr_roam_get_wpa_rsn_rsp_ie(tpAniSirGlobal pMac, uint32_t sessionId, + uint32_t *pLen, uint8_t *pBuf) +{ + QDF_STATUS status = QDF_STATUS_E_INVAL; + uint32_t len; + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!pSession) { + sms_log(pMac, LOGE, FL(" session %d not found "), sessionId); + return QDF_STATUS_E_FAILURE; + } + + if (pLen) { + len = *pLen; + *pLen = pSession->nWpaRsnRspIeLength; + if (pBuf) { + if (len >= pSession->nWpaRsnRspIeLength) { + qdf_mem_copy(pBuf, pSession->pWpaRsnRspIE, + pSession->nWpaRsnRspIeLength); + status = QDF_STATUS_SUCCESS; + } + } + } + return status; +} + +#ifdef FEATURE_WLAN_WAPI +QDF_STATUS csr_roam_get_wapi_req_ie(tpAniSirGlobal pMac, uint32_t sessionId, + uint32_t *pLen, uint8_t *pBuf) +{ + QDF_STATUS status = QDF_STATUS_E_INVAL; + uint32_t len; + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!pSession) { + sms_log(pMac, LOGE, FL(" session %d not found "), sessionId); + return QDF_STATUS_E_FAILURE; + } + + if (pLen) { + len = *pLen; + *pLen = pSession->nWapiReqIeLength; + if (pBuf) { + if (len >= pSession->nWapiReqIeLength) { + qdf_mem_copy(pBuf, pSession->pWapiReqIE, + pSession->nWapiReqIeLength); + status = QDF_STATUS_SUCCESS; + } + } + } + return status; +} + +QDF_STATUS csr_roam_get_wapi_rsp_ie(tpAniSirGlobal pMac, uint32_t sessionId, + uint32_t *pLen, uint8_t *pBuf) +{ + QDF_STATUS status = QDF_STATUS_E_INVAL; + uint32_t len; + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!pSession) { + sms_log(pMac, LOGE, FL(" session %d not found "), sessionId); + return QDF_STATUS_E_FAILURE; + } + + if (pLen) { + len = *pLen; + *pLen = pSession->nWapiRspIeLength; + if (pBuf) { + if (len >= pSession->nWapiRspIeLength) { + qdf_mem_copy(pBuf, pSession->pWapiRspIE, + pSession->nWapiRspIeLength); + status = QDF_STATUS_SUCCESS; + } + } + } + return status; +} +#endif /* FEATURE_WLAN_WAPI */ +eRoamCmdStatus csr_get_roam_complete_status(tpAniSirGlobal pMac, uint32_t sessionId) +{ + eRoamCmdStatus retStatus = eCSR_ROAM_CONNECT_COMPLETION; + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!pSession) { + sms_log(pMac, LOGE, FL(" session %d not found "), sessionId); + return retStatus; + } + + if (CSR_IS_ROAMING(pSession)) { + retStatus = eCSR_ROAM_ROAMING_COMPLETION; + pSession->fRoaming = false; + } + return retStatus; +} + +/* This function remove the connected BSS from te cached scan result */ +QDF_STATUS +csr_roam_remove_connected_bss_from_scan_cache(tpAniSirGlobal pMac, + tCsrRoamConnectedProfile *pConnProfile) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tCsrScanResultFilter *pScanFilter = NULL; + tListElem *pEntry; + tCsrScanResult *pResult; + tDot11fBeaconIEs *pIes; + bool fMatch; + + if ((qdf_is_macaddr_zero(&pConnProfile->bssid) || + qdf_is_macaddr_broadcast(&pConnProfile->bssid))) + return status; + /* + * Prepare the filter. Only fill in the necessary fields. Not all fields + * are needed + */ + pScanFilter = qdf_mem_malloc(sizeof(tCsrScanResultFilter)); + if (NULL == pScanFilter) + return QDF_STATUS_E_NOMEM; + + pScanFilter->BSSIDs.bssid = qdf_mem_malloc(sizeof(struct qdf_mac_addr)); + if (NULL == pScanFilter->BSSIDs.bssid) { + qdf_mem_free(pScanFilter); + return QDF_STATUS_E_NOMEM; + } + qdf_mem_copy(pScanFilter->BSSIDs.bssid, + &pConnProfile->bssid, sizeof(struct qdf_mac_addr)); + pScanFilter->BSSIDs.numOfBSSIDs = 1; + if (!csr_is_nullssid(pConnProfile->SSID.ssId, + pConnProfile->SSID.length)) { + pScanFilter->SSIDs.SSIDList = qdf_mem_malloc( + sizeof(tCsrSSIDInfo)); + if (NULL == pScanFilter->SSIDs.SSIDList) { + csr_free_scan_filter(pMac, pScanFilter); + qdf_mem_free(pScanFilter); + return QDF_STATUS_E_NOMEM; + } + qdf_mem_copy(&pScanFilter->SSIDs.SSIDList[0].SSID, + &pConnProfile->SSID, sizeof(tSirMacSSid)); + } + pScanFilter->authType.numEntries = 1; + pScanFilter->authType.authType[0] = pConnProfile->AuthType; + pScanFilter->BSSType = pConnProfile->BSSType; + pScanFilter->EncryptionType.numEntries = 1; + pScanFilter->EncryptionType.encryptionType[0] = + pConnProfile->EncryptionType; + pScanFilter->mcEncryptionType.numEntries = 1; + pScanFilter->mcEncryptionType.encryptionType[0] = + pConnProfile->mcEncryptionType; + /* We ignore the channel for now, BSSID should be enough */ + pScanFilter->ChannelInfo.numOfChannels = 0; + /* Also ignore the following fields */ + pScanFilter->uapsd_mask = 0; + pScanFilter->bWPSAssociation = false; + pScanFilter->bOSENAssociation = false; + pScanFilter->countryCode[0] = 0; + pScanFilter->phyMode = eCSR_DOT11_MODE_AUTO; +#ifdef WLAN_FEATURE_11W + pScanFilter->MFPEnabled = pConnProfile->MFPEnabled; + pScanFilter->MFPRequired = pConnProfile->MFPRequired; + pScanFilter->MFPCapable = pConnProfile->MFPCapable; +#endif + csr_ll_lock(&pMac->scan.scanResultList); + pEntry = csr_ll_peek_head(&pMac->scan.scanResultList, LL_ACCESS_NOLOCK); + while (pEntry) { + pResult = GET_BASE_ADDR(pEntry, tCsrScanResult, Link); + pIes = (tDot11fBeaconIEs *) (pResult->Result.pvIes); + fMatch = csr_match_bss(pMac, &pResult->Result.BssDescriptor, + pScanFilter, NULL, NULL, NULL, &pIes); + /* Release the IEs allocated by csr_match_bss is needed */ + if (!pResult->Result.pvIes) { + /* + * need to free the IEs since it is allocated + * by csr_match_bss + */ + qdf_mem_free(pIes); + } + if (fMatch) { + /* We found the one */ + if (csr_ll_remove_entry(&pMac->scan.scanResultList, + pEntry, LL_ACCESS_NOLOCK)) + /* Free the memory */ + csr_free_scan_result_entry(pMac, pResult); + break; + } + pEntry = csr_ll_next(&pMac->scan.scanResultList, + pEntry, LL_ACCESS_NOLOCK); + } /* while */ + csr_ll_unlock(&pMac->scan.scanResultList); + csr_free_scan_filter(pMac, pScanFilter); + qdf_mem_free(pScanFilter); + return status; +} + +static QDF_STATUS csr_roam_start_wds(tpAniSirGlobal pMac, uint32_t sessionId, + tCsrRoamProfile *pProfile, + tSirBssDescription *pBssDesc) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + tBssConfigParam bssConfig; + + if (!pSession) { + sms_log(pMac, LOGE, FL(" session %d not found "), sessionId); + return QDF_STATUS_E_FAILURE; + } + + if (csr_is_conn_state_ibss(pMac, sessionId)) { + status = + csr_roam_issue_stop_bss(pMac, sessionId, + eCSR_ROAM_SUBSTATE_DISCONNECT_CONTINUE_ROAMING); + } else if (csr_is_conn_state_connected_infra(pMac, sessionId)) { + /* Disassociate from the connected Infrastructure network... */ + status = + csr_roam_issue_disassociate(pMac, sessionId, + eCSR_ROAM_SUBSTATE_DISCONNECT_CONTINUE_ROAMING, + false); + } else { + /* We don't expect Bt-AMP HDD not to disconnect the last connection first at this time. */ + /* Otherwise we need to add code to handle the */ + /* situation just like IBSS. Though for WDS station, we need to send disassoc to PE first then */ + /* send stop_bss to PE, before we can continue. */ + + if (csr_is_conn_state_wds(pMac, sessionId)) { + QDF_ASSERT(0); + return QDF_STATUS_E_FAILURE; + } + qdf_mem_set(&bssConfig, sizeof(tBssConfigParam), 0); + /* Assume HDD provide bssid in profile */ + qdf_copy_macaddr(&pSession->bssParams.bssid, + pProfile->BSSIDs.bssid); + /* there is no Bss description before we start an WDS so we need */ + /* to adopt all Bss configuration parameters from the Profile. */ + status = + csr_roam_prepare_bss_config_from_profile(pMac, pProfile, + &bssConfig, pBssDesc); + if (QDF_IS_STATUS_SUCCESS(status)) { + /* Save profile for late use */ + csr_free_roam_profile(pMac, sessionId); + pSession->pCurRoamProfile = + qdf_mem_malloc(sizeof(tCsrRoamProfile)); + if (pSession->pCurRoamProfile != NULL) { + csr_roam_copy_profile(pMac, + pSession->pCurRoamProfile, + pProfile); + } + /* Prepare some more parameters for this WDS */ + csr_roam_prepare_bss_params(pMac, sessionId, pProfile, NULL, + &bssConfig, NULL); + status = + csr_roam_set_bss_config_cfg(pMac, sessionId, pProfile, + NULL, &bssConfig, NULL, + false); + } + } + + return status; +} + +/** + * csr_add_supported_5Ghz_channels()- Add valid 5Ghz channels + * in Join req. + * @mac_ctx: pointer to global mac structure + * @chan_list: Pointer to channel list buffer to populate + * @num_chan: Pointer to number of channels value to update + * @supp_chan_ie: Boolean to check if we need to populate as IE + * + * This function is called to update valid 5Ghz channels + * in Join req. If @supp_chan_ie is true, supported channels IE + * format[chan num 1, num of channels 1, chan num 2, num of + * channels 2, ..] is populated. Else, @chan_list would be a list + * of supported channels[chan num 1, chan num 2..] + * + * Return: void + */ +static void csr_add_supported_5Ghz_channels(tpAniSirGlobal mac_ctx, + uint8_t *chan_list, + uint8_t *num_chnl, + bool supp_chan_ie) +{ + uint16_t i, j; + uint32_t size = 0; + + if (!chan_list) { + sms_log(mac_ctx, LOGE, FL("chan_list buffer NULL")); + return; + } + + size = sizeof(mac_ctx->roam.validChannelList); + if (QDF_IS_STATUS_SUCCESS + (csr_get_cfg_valid_channels(mac_ctx, + (uint8_t *) mac_ctx->roam.validChannelList, + &size))) { + for (i = 0, j = 0; i < size; i++) { + /* Only add 5ghz channels.*/ + if (CDS_IS_CHANNEL_5GHZ + (mac_ctx->roam.validChannelList[i])) { + chan_list[j] + = mac_ctx->roam.validChannelList[i]; + j++; + + if (supp_chan_ie) { + chan_list[j] = 1; + j++; + } + } + } + *num_chnl = (uint8_t)j; + } else { + sms_log(mac_ctx, LOGE, + FL("can not find any valid channel")); + *num_chnl = 0; + } +} + +/** + * csr_set_ldpc_exception() - to set allow any LDPC exception permitted + * @mac_ctx: Pointer to mac context + * @session: Pointer to SME/CSR session + * @channel: Given channel number where connection will go + * @usr_cfg_rx_ldpc: User provided RX LDPC setting + * + * This API will check if hardware allows LDPC to be enabled for provided + * channel and user has enabled the RX LDPC selection + * + * Return: QDF_STATUS + */ +static QDF_STATUS csr_set_ldpc_exception(tpAniSirGlobal mac_ctx, + tCsrRoamSession *session, uint8_t channel, + bool usr_cfg_rx_ldpc) +{ + if (!mac_ctx) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "mac_ctx is NULL"); + return QDF_STATUS_E_FAILURE; + } + if (!session) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "session is NULL"); + return QDF_STATUS_E_FAILURE; + } + if (usr_cfg_rx_ldpc && wma_is_rx_ldpc_supported_for_channel(channel)) { + session->htConfig.ht_rx_ldpc = 1; + session->vht_config.ldpc_coding = 1; + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO_HIGH, + "LDPC enable for chnl[%d]", channel); + } else { + session->htConfig.ht_rx_ldpc = 0; + session->vht_config.ldpc_coding = 0; + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO_HIGH, + "LDPC disable for chnl[%d]", channel); + } + return QDF_STATUS_SUCCESS; +} + +/** + * The communication between HDD and LIM is thru mailbox (MB). + * Both sides will access the data structure "tSirSmeJoinReq". + * The rule is, while the components of "tSirSmeJoinReq" can be accessed in the + * regular way like tSirSmeJoinReq.assocType, this guideline stops at component + * tSirRSNie; + * any acces to the components after tSirRSNie is forbidden because the space + * from tSirRSNie is squeezed with the component "tSirBssDescription" and since + * the size of actual 'tSirBssDescription' varies, the receiving side should + * keep in mind not to access the components DIRECTLY after tSirRSNie. + */ +QDF_STATUS csr_send_join_req_msg(tpAniSirGlobal pMac, uint32_t sessionId, + tSirBssDescription *pBssDescription, + tCsrRoamProfile *pProfile, + tDot11fBeaconIEs *pIes, uint16_t messageType) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + uint8_t acm_mask = 0, uapsd_mask; + uint16_t msgLen, ieLen; + tSirMacRateSet OpRateSet; + tSirMacRateSet ExRateSet; + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + uint32_t dwTmp, ucDot11Mode = 0; + uint8_t *wpaRsnIE = NULL; + uint8_t txBFCsnValue = 0; + tSirSmeJoinReq *csr_join_req; + tSirMacCapabilityInfo *pAP_capabilityInfo; + tAniBool fTmp; + int8_t pwrLimit = 0; + struct ps_global_info *ps_global_info = &pMac->sme.ps_global_info; + struct ps_params *ps_param = &ps_global_info->ps_params[sessionId]; + uint8_t ese_config = 0; + tpCsrNeighborRoamControlInfo neigh_roam_info; + uint32_t value = 0, value1 = 0; + QDF_STATUS packetdump_timer_status; + + if (!pSession) { + sms_log(pMac, LOGE, FL(" session %d not found "), sessionId); + return QDF_STATUS_E_FAILURE; + } + /* To satisfy klockworks */ + if (NULL == pBssDescription) { + sms_log(pMac, LOGE, FL(" pBssDescription is NULL")); + return QDF_STATUS_E_FAILURE; + } + neigh_roam_info = &pMac->roam.neighborRoamInfo[sessionId]; + if ((eWNI_SME_REASSOC_REQ == messageType) || + CDS_IS_CHANNEL_5GHZ(pBssDescription->channelId) || + (abs(pBssDescription->rssi) < + (neigh_roam_info->cfgParams.neighborLookupThreshold - + neigh_roam_info->cfgParams.hi_rssi_scan_rssi_delta))) { + pSession->disable_hi_rssi = true; + sms_log(pMac, LOG1, + FL("Disabling HI_RSSI feature, AP channel=%d, rssi=%d"), + pBssDescription->channelId, pBssDescription->rssi); + } else { + pSession->disable_hi_rssi = false; + } + + + do { + pSession->joinFailStatusCode.statusCode = eSIR_SME_SUCCESS; + pSession->joinFailStatusCode.reasonCode = 0; + qdf_mem_copy(&pSession->joinFailStatusCode.bssId, + &pBssDescription->bssId, sizeof(tSirMacAddr)); + /* + * the tSirSmeJoinReq which includes a single + * bssDescription. it includes a single uint32_t for the + * IE fields, but the length field in the bssDescription + * needs to be interpreted to determine length of IE fields + * So, take the size of the tSirSmeJoinReq, subtract size of + * bssDescription, add the number of bytes indicated by the + * length field of the bssDescription, add the size of length + * field because it not included in the lenghth field. + */ + msgLen = sizeof(tSirSmeJoinReq) - sizeof(*pBssDescription) + + pBssDescription->length + + sizeof(pBssDescription->length) + + /* + * add in the size of the WPA IE that + * we may build. + */ + sizeof(tCsrWpaIe) + sizeof(tCsrWpaAuthIe) + + sizeof(uint16_t); + csr_join_req = qdf_mem_malloc(msgLen); + if (NULL == csr_join_req) + status = QDF_STATUS_E_NOMEM; + else + status = QDF_STATUS_SUCCESS; + if (!QDF_IS_STATUS_SUCCESS(status)) + break; + + wpaRsnIE = qdf_mem_malloc(DOT11F_IE_RSN_MAX_LEN); + if (NULL == wpaRsnIE) { + status = QDF_STATUS_E_NOMEM; + } + if (!QDF_IS_STATUS_SUCCESS(status)) + break; + + csr_join_req->messageType = messageType; + csr_join_req->length = msgLen; + csr_join_req->sessionId = (uint8_t) sessionId; + csr_join_req->transactionId = 0; + if (pIes->SSID.present && pIes->SSID.num_ssid) { + csr_join_req->ssId.length = pIes->SSID.num_ssid; + qdf_mem_copy(&csr_join_req->ssId.ssId, pIes->SSID.ssid, + pIes->SSID.num_ssid); + } else + csr_join_req->ssId.length = 0; + qdf_mem_copy(&csr_join_req->selfMacAddr, &pSession->selfMacAddr, + sizeof(tSirMacAddr)); + sms_log(pMac, LOGE, + FL("Connecting to ssid:%.*s bssid: " + MAC_ADDRESS_STR" rssi: %d channel: %d country_code: %c%c"), + pIes->SSID.num_ssid, pIes->SSID.ssid, + MAC_ADDR_ARRAY(pBssDescription->bssId), + pBssDescription->rssi, pBssDescription->channelId, + pMac->scan.countryCodeCurrent[0], + pMac->scan.countryCodeCurrent[1]); + /* bsstype */ + dwTmp = csr_translate_bsstype_to_mac_type + (pProfile->BSSType); + csr_join_req->bsstype = dwTmp; + /* dot11mode */ + ucDot11Mode = + csr_translate_to_wni_cfg_dot11_mode(pMac, + pSession->bssParams. + uCfgDot11Mode); + if (pBssDescription->channelId <= 14 + && false == pMac->roam.configParam.enableVhtFor24GHz + && WNI_CFG_DOT11_MODE_11AC == ucDot11Mode) { + /* Need to disable VHT operation in 2.4 GHz band */ + ucDot11Mode = WNI_CFG_DOT11_MODE_11N; + } + csr_join_req->dot11mode = (uint8_t) ucDot11Mode; +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH + csr_join_req->cc_switch_mode = + pMac->roam.configParam.cc_switch_mode; +#endif + csr_join_req->staPersona = (uint8_t) pProfile->csrPersona; + csr_join_req->wps_registration = pProfile->bWPSAssociation; + csr_join_req->cbMode = (uint8_t) pSession->bssParams.cbMode; + sms_log(pMac, LOG2, + FL("CSR PERSONA=%d CSR CbMode %d"), + pProfile->csrPersona, pSession->bssParams.cbMode); + csr_join_req->uapsdPerAcBitmask = pProfile->uapsd_mask; + pSession->uapsd_mask = pProfile->uapsd_mask; + status = + csr_get_rate_set(pMac, pProfile, + (eCsrPhyMode) pProfile->phyMode, + pBssDescription, pIes, &OpRateSet, + &ExRateSet); + ps_param->uapsd_per_ac_bit_mask = + pProfile->uapsd_mask; + if (QDF_IS_STATUS_SUCCESS(status)) { + /* OperationalRateSet */ + if (OpRateSet.numRates) { + csr_join_req->operationalRateSet.numRates = + OpRateSet.numRates; + qdf_mem_copy(&csr_join_req->operationalRateSet. + rate, OpRateSet.rate, + OpRateSet.numRates); + } else + csr_join_req->operationalRateSet.numRates = 0; + + /* ExtendedRateSet */ + if (ExRateSet.numRates) { + csr_join_req->extendedRateSet.numRates = + ExRateSet.numRates; + qdf_mem_copy(&csr_join_req->extendedRateSet. + rate, ExRateSet.rate, + ExRateSet.numRates); + } else + csr_join_req->extendedRateSet.numRates = 0; + } else { + csr_join_req->operationalRateSet.numRates = 0; + csr_join_req->extendedRateSet.numRates = 0; + } + /* rsnIE */ + if (csr_is_profile_wpa(pProfile)) { + /* Insert the Wpa IE into the join request */ + ieLen = + csr_retrieve_wpa_ie(pMac, pProfile, + pBssDescription, pIes, + (tCsrWpaIe *) (wpaRsnIE)); + } else if (csr_is_profile_rsn(pProfile)) { + /* Insert the RSN IE into the join request */ + ieLen = + csr_retrieve_rsn_ie(pMac, sessionId, pProfile, + pBssDescription, pIes, + (tCsrRSNIe *) (wpaRsnIE)); + } +#ifdef FEATURE_WLAN_WAPI + else if (csr_is_profile_wapi(pProfile)) { + /* Insert the WAPI IE into the join request */ + ieLen = + csr_retrieve_wapi_ie(pMac, sessionId, pProfile, + pBssDescription, pIes, + (tCsrWapiIe *) (wpaRsnIE)); + } +#endif /* FEATURE_WLAN_WAPI */ + else { + ieLen = 0; + } + /* remember the IE for future use */ + if (ieLen) { + if (ieLen > DOT11F_IE_RSN_MAX_LEN) { + sms_log(pMac, LOGE, + FL + (" WPA RSN IE length :%d is more than DOT11F_IE_RSN_MAX_LEN, resetting to %d"), + ieLen, DOT11F_IE_RSN_MAX_LEN); + ieLen = DOT11F_IE_RSN_MAX_LEN; + } +#ifdef FEATURE_WLAN_WAPI + if (csr_is_profile_wapi(pProfile)) { + /* Check whether we need to allocate more mem */ + if (ieLen > pSession->nWapiReqIeLength) { + if (pSession->pWapiReqIE + && pSession->nWapiReqIeLength) { + qdf_mem_free(pSession-> + pWapiReqIE); + } + pSession->pWapiReqIE = + qdf_mem_malloc(ieLen); + if (NULL == pSession->pWapiReqIE) + status = QDF_STATUS_E_NOMEM; + else + status = QDF_STATUS_SUCCESS; + if (!QDF_IS_STATUS_SUCCESS(status)) + break; + } + pSession->nWapiReqIeLength = ieLen; + qdf_mem_copy(pSession->pWapiReqIE, wpaRsnIE, + ieLen); + csr_join_req->rsnIE.length = ieLen; + qdf_mem_copy(&csr_join_req->rsnIE.rsnIEdata, + wpaRsnIE, ieLen); + } else /* should be WPA/WPA2 otherwise */ +#endif /* FEATURE_WLAN_WAPI */ + { + /* Check whether we need to allocate more mem */ + if (ieLen > pSession->nWpaRsnReqIeLength) { + if (pSession->pWpaRsnReqIE + && pSession->nWpaRsnReqIeLength) { + qdf_mem_free(pSession-> + pWpaRsnReqIE); + } + pSession->pWpaRsnReqIE = + qdf_mem_malloc(ieLen); + if (NULL == pSession->pWpaRsnReqIE) + status = QDF_STATUS_E_NOMEM; + else + status = QDF_STATUS_SUCCESS; + if (!QDF_IS_STATUS_SUCCESS(status)) + break; + } + pSession->nWpaRsnReqIeLength = ieLen; + qdf_mem_copy(pSession->pWpaRsnReqIE, wpaRsnIE, + ieLen); + csr_join_req->rsnIE.length = ieLen; + qdf_mem_copy(&csr_join_req->rsnIE.rsnIEdata, + wpaRsnIE, ieLen); + } + } else { + /* free whatever old info */ + pSession->nWpaRsnReqIeLength = 0; + if (pSession->pWpaRsnReqIE) { + qdf_mem_free(pSession->pWpaRsnReqIE); + pSession->pWpaRsnReqIE = NULL; + } +#ifdef FEATURE_WLAN_WAPI + pSession->nWapiReqIeLength = 0; + if (pSession->pWapiReqIE) { + qdf_mem_free(pSession->pWapiReqIE); + pSession->pWapiReqIE = NULL; + } +#endif /* FEATURE_WLAN_WAPI */ + csr_join_req->rsnIE.length = 0; + } +#ifdef FEATURE_WLAN_ESE + if (eWNI_SME_JOIN_REQ == messageType) + csr_join_req->cckmIE.length = 0; + else if (eWNI_SME_REASSOC_REQ == messageType) { + /* cckmIE */ + if (csr_is_profile_ese(pProfile)) { + /* Insert the CCKM IE into the join request */ + ieLen = pSession->suppCckmIeInfo.cckmIeLen; + qdf_mem_copy((void *)(wpaRsnIE), + pSession->suppCckmIeInfo.cckmIe, + ieLen); + } else + ieLen = 0; + /* + * If present, copy the IE into the + * eWNI_SME_REASSOC_REQ message buffer + */ + if (ieLen) { + /* + * Copy the CCKM IE over from the temp + * buffer (wpaRsnIE) + */ + csr_join_req->cckmIE.length = ieLen; + qdf_mem_copy(&csr_join_req->cckmIE.cckmIEdata, + wpaRsnIE, ieLen); + } else + csr_join_req->cckmIE.length = 0; + } +#endif /* FEATURE_WLAN_ESE */ + /* addIEScan */ + if (pProfile->nAddIEScanLength && pProfile->pAddIEScan) { + ieLen = pProfile->nAddIEScanLength; + if (ieLen > pSession->nAddIEScanLength) { + if (pSession->pAddIEScan + && pSession->nAddIEScanLength) { + qdf_mem_free(pSession->pAddIEScan); + } + pSession->pAddIEScan = qdf_mem_malloc(ieLen); + if (NULL == pSession->pAddIEScan) + status = QDF_STATUS_E_NOMEM; + else + status = QDF_STATUS_SUCCESS; + if (!QDF_IS_STATUS_SUCCESS(status)) + break; + } + pSession->nAddIEScanLength = ieLen; + qdf_mem_copy(pSession->pAddIEScan, pProfile->pAddIEScan, + ieLen); + csr_join_req->addIEScan.length = ieLen; + qdf_mem_copy(&csr_join_req->addIEScan.addIEdata, + pProfile->pAddIEScan, ieLen); + } else { + pSession->nAddIEScanLength = 0; + if (pSession->pAddIEScan) { + qdf_mem_free(pSession->pAddIEScan); + pSession->pAddIEScan = NULL; + } + csr_join_req->addIEScan.length = 0; + } + /* addIEAssoc */ + if (pProfile->nAddIEAssocLength && pProfile->pAddIEAssoc) { + ieLen = pProfile->nAddIEAssocLength; + if (ieLen > pSession->nAddIEAssocLength) { + if (pSession->pAddIEAssoc + && pSession->nAddIEAssocLength) { + qdf_mem_free(pSession->pAddIEAssoc); + } + pSession->pAddIEAssoc = qdf_mem_malloc(ieLen); + if (NULL == pSession->pAddIEAssoc) + status = QDF_STATUS_E_NOMEM; + else + status = QDF_STATUS_SUCCESS; + if (!QDF_IS_STATUS_SUCCESS(status)) + break; + } + pSession->nAddIEAssocLength = ieLen; + qdf_mem_copy(pSession->pAddIEAssoc, + pProfile->pAddIEAssoc, ieLen); + csr_join_req->addIEAssoc.length = ieLen; + qdf_mem_copy(&csr_join_req->addIEAssoc.addIEdata, + pProfile->pAddIEAssoc, ieLen); + } else { + pSession->nAddIEAssocLength = 0; + if (pSession->pAddIEAssoc) { + qdf_mem_free(pSession->pAddIEAssoc); + pSession->pAddIEAssoc = NULL; + } + csr_join_req->addIEAssoc.length = 0; + } + + if (eWNI_SME_REASSOC_REQ == messageType) { + /* Unmask any AC in reassoc that is ACM-set */ + uapsd_mask = (uint8_t) pProfile->uapsd_mask; + if (uapsd_mask && (NULL != pBssDescription)) { + if (CSR_IS_QOS_BSS(pIes) + && CSR_IS_UAPSD_BSS(pIes)) +#ifndef WLAN_MDM_CODE_REDUCTION_OPT + acm_mask = + sme_qos_get_acm_mask(pMac, + pBssDescription, + pIes); +#endif /* WLAN_MDM_CODE_REDUCTION_OPT */ + else + uapsd_mask = 0; + } + } + + csr_join_req->UCEncryptionType = + csr_translate_encrypt_type_to_ed_type + (pProfile->negotiatedUCEncryptionType); + + csr_join_req->MCEncryptionType = + csr_translate_encrypt_type_to_ed_type + (pProfile->negotiatedMCEncryptionType); +#ifdef WLAN_FEATURE_11W + if (pProfile->MFPEnabled) + csr_join_req->MgmtEncryptionType = eSIR_ED_AES_128_CMAC; + else + csr_join_req->MgmtEncryptionType = eSIR_ED_NONE; +#endif + if (pProfile->MFPEnabled && + !(pProfile->MFPRequired) && + ((pIes->RSN.present) && + (!(pIes->RSN.RSN_Cap[0] >> 7) & 0x1))) + csr_join_req->MgmtEncryptionType = eSIR_ED_NONE; +#ifdef FEATURE_WLAN_ESE + ese_config = pMac->roam.configParam.isEseIniFeatureEnabled; +#endif + pProfile->MDID.mdiePresent = pBssDescription->mdiePresent; + if (csr_is_profile11r(pProfile) +#ifdef FEATURE_WLAN_ESE + && + !((pProfile->negotiatedAuthType == + eCSR_AUTH_TYPE_OPEN_SYSTEM) && (pIes->ESEVersion.present) + && (ese_config)) +#endif + ) + csr_join_req->is11Rconnection = true; + else + csr_join_req->is11Rconnection = false; +#ifdef FEATURE_WLAN_ESE + if (true == ese_config) + csr_join_req->isESEFeatureIniEnabled = true; + else + csr_join_req->isESEFeatureIniEnabled = false; + + /* A profile can not be both ESE and 11R. But an 802.11R AP + * may be advertising support for ESE as well. So if we are + * associating Open or explicitly ESE then we will get ESE. + * If we are associating explictly 11R only then we will get + * 11R. + */ + if ((csr_is_profile_ese(pProfile) || + ((pIes->ESEVersion.present) && + (pProfile->negotiatedAuthType == + eCSR_AUTH_TYPE_OPEN_SYSTEM))) + && (ese_config)) + csr_join_req->isESEconnection = true; + else + csr_join_req->isESEconnection = false; + + if (eWNI_SME_JOIN_REQ == messageType) { + tESETspecInfo eseTspec; + /* + * ESE-Tspec IEs in the ASSOC request is presently not + * supported. so nullify the TSPEC parameters + */ + qdf_mem_set(&eseTspec, sizeof(tESETspecInfo), 0); + qdf_mem_copy(&csr_join_req->eseTspecInfo, + &eseTspec, sizeof(tESETspecInfo)); + } else if (eWNI_SME_REASSOC_REQ == messageType) { + if ((csr_is_profile_ese(pProfile) || + ((pIes->ESEVersion.present) + && (pProfile->negotiatedAuthType == + eCSR_AUTH_TYPE_OPEN_SYSTEM))) && + (ese_config)) { + tESETspecInfo eseTspec; + qdf_mem_set(&eseTspec, sizeof(tESETspecInfo), + 0); + eseTspec.numTspecs = + sme_qos_ese_retrieve_tspec_info(pMac, + sessionId, + (tTspecInfo *) &eseTspec. + tspec[0]); + csr_join_req->eseTspecInfo.numTspecs = + eseTspec.numTspecs; + if (eseTspec.numTspecs) { + qdf_mem_copy(&csr_join_req->eseTspecInfo + .tspec[0], + &eseTspec.tspec[0], + (eseTspec.numTspecs * + sizeof(tTspecInfo))); + } + } else { + tESETspecInfo eseTspec; + /** + * ESE-Tspec IEs in the ASSOC request is + * presently not supported. so nullify the TSPEC + * parameters + */ + qdf_mem_set(&eseTspec, sizeof(tESETspecInfo), + 0); + qdf_mem_copy(&csr_join_req->eseTspecInfo, + &eseTspec, + sizeof(tESETspecInfo)); + } + } +#endif /* FEATURE_WLAN_ESE */ + if (ese_config + || csr_roam_is_fast_roam_enabled(pMac, sessionId)) { + csr_join_req->isFastTransitionEnabled = true; + } else { + csr_join_req->isFastTransitionEnabled = false; + } + if (csr_roam_is_fast_roam_enabled(pMac, sessionId)) + csr_join_req->isFastRoamIniFeatureEnabled = true; + else + csr_join_req->isFastRoamIniFeatureEnabled = false; + + csr_join_req->txLdpcIniFeatureEnabled = + (uint8_t) pMac->roam.configParam.txLdpcEnable; + + if ((csr_is11h_supported(pMac)) + && (CDS_IS_CHANNEL_5GHZ(pBssDescription->channelId)) + && (pIes->Country.present) + && (!pMac->roam.configParam. + fSupplicantCountryCodeHasPriority)) { + csr_save_to_channel_power2_g_5_g(pMac, + pIes->Country.num_triplets * + sizeof(tSirMacChanInfo), + (tSirMacChanInfo *) + (&pIes->Country.triplets[0])); + csr_apply_power2_current(pMac); + } + /* + * If RX LDPC has been disabled for 2.4GHz channels and enabled + * for 5Ghz for STA like persona then here is how to handle + * those cases (by now channel has been decided). + */ + if (eSIR_INFRASTRUCTURE_MODE == csr_join_req->bsstype || + !wma_is_dbs_enable()) + csr_set_ldpc_exception(pMac, pSession, + pBssDescription->channelId, + pMac->roam.configParam.rxLdpcEnable); + qdf_mem_copy(&csr_join_req->htConfig, + &pSession->htConfig, sizeof(tSirHTConfig)); + qdf_mem_copy(&csr_join_req->vht_config, &pSession->vht_config, + sizeof(pSession->vht_config)); + sms_log(pMac, LOG2, + FL("ht capability 0x%x VHT capability 0x%x"), + (unsigned int)(*(uint32_t *) &csr_join_req->htConfig), + (unsigned int)(*(uint32_t *) &csr_join_req->vht_config)); + if (wlan_cfg_get_int(pMac, WNI_CFG_VHT_SU_BEAMFORMEE_CAP, + &value) != eSIR_SUCCESS) + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + FL("Failed to get SU beamformee capability")); + if (wlan_cfg_get_int(pMac, + WNI_CFG_VHT_CSN_BEAMFORMEE_ANT_SUPPORTED, + &value1) != eSIR_SUCCESS) + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + FL("Failed to get CSN beamformee capability")); + + csr_join_req->vht_config.su_beam_formee = value; + + /* Set BF CSN value only if SU Bformee is enabled */ + if (csr_join_req->vht_config.su_beam_formee) { + txBFCsnValue = (uint8_t)value1; + if (IS_BSS_VHT_CAPABLE(pIes->VHTCaps) && + pIes->VHTCaps.csnofBeamformerAntSup) + txBFCsnValue = QDF_MIN(txBFCsnValue, + pIes->VHTCaps.csnofBeamformerAntSup); + else if (IS_BSS_VHT_CAPABLE( + pIes->vendor_vht_ie.VHTCaps) + && pIes->vendor_vht_ie.VHTCaps. + csnofBeamformerAntSup) + txBFCsnValue = QDF_MIN(txBFCsnValue, + pIes->vendor_vht_ie. + VHTCaps.csnofBeamformerAntSup); + } + csr_join_req->vht_config.csnof_beamformer_antSup = txBFCsnValue; + + if (wlan_cfg_get_int(pMac, + WNI_CFG_VHT_SU_BEAMFORMER_CAP, &value) + != eSIR_SUCCESS) + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + FL("Failed to get SU beamformer capability")); + + /* + * Set SU Bformer only if SU Bformer is enabled in INI + * and AP is SU Bformee capable + */ + if (value && !((IS_BSS_VHT_CAPABLE(pIes->VHTCaps) && + pIes->VHTCaps.suBeamformeeCap) || + (IS_BSS_VHT_CAPABLE( + pIes->vendor_vht_ie.VHTCaps) + && pIes->vendor_vht_ie.VHTCaps. + suBeamformeeCap))) + value = 0; + + csr_join_req->vht_config.su_beam_former = value; + + /* Set num soundingdim value to 0 if SU Bformer is disabled */ + if (!csr_join_req->vht_config.su_beam_former) + csr_join_req->vht_config.num_soundingdim = 0; + + if (wlan_cfg_get_int(pMac, + WNI_CFG_VHT_MU_BEAMFORMEE_CAP, &value) + != eSIR_SUCCESS) + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + FL("Failed to get CSN beamformee capability")); + /* + * Set MU Bformee only if SU Bformee is enabled and + * MU Bformee is enabled in INI + */ + if (value && csr_join_req->vht_config.su_beam_formee) + csr_join_req->vht_config.mu_beam_formee = 1; + else + csr_join_req->vht_config.mu_beam_formee = 0; + + csr_join_req->enableVhtpAid = + (uint8_t) pMac->roam.configParam.enableVhtpAid; + + csr_join_req->enableVhtGid = + (uint8_t) pMac->roam.configParam.enableVhtGid; + + csr_join_req->enableAmpduPs = + (uint8_t) pMac->roam.configParam.enableAmpduPs; + + csr_join_req->enableHtSmps = + (uint8_t) pMac->roam.configParam.enableHtSmps; + + csr_join_req->htSmps = (uint8_t) pMac->roam.configParam.htSmps; + csr_join_req->send_smps_action = + pMac->roam.configParam.send_smps_action; + + csr_join_req->max_amsdu_num = + (uint8_t) pMac->roam.configParam.max_amsdu_num; + + if (pMac->roam.roamSession[sessionId].fWMMConnection) + csr_join_req->isWMEenabled = true; + else + csr_join_req->isWMEenabled = false; + + if (pMac->roam.roamSession[sessionId].fQOSConnection) + csr_join_req->isQosEnabled = true; + else + csr_join_req->isQosEnabled = false; + + if (pProfile->bOSENAssociation) + csr_join_req->isOSENConnection = true; + else + csr_join_req->isOSENConnection = false; + + /* Fill rrm config parameters */ + qdf_mem_copy(&csr_join_req->rrm_config, + &pMac->rrm.rrmSmeContext.rrmConfig, + sizeof(struct rrm_config_param)); + + pAP_capabilityInfo = + (tSirMacCapabilityInfo *) + &pBssDescription->capabilityInfo; + /* + * tell the target AP my 11H capability only if both AP and STA + * support + * 11H and the channel being used is 11a + */ + if (csr_is11h_supported(pMac) && pAP_capabilityInfo->spectrumMgt + && eSIR_11A_NW_TYPE == pBssDescription->nwType) { + fTmp = (tAniBool) 1; + } else + fTmp = (tAniBool) 0; + + csr_join_req->spectrumMgtIndicator = fTmp; + csr_join_req->powerCap.minTxPower = MIN_TX_PWR_CAP; + /* + * This is required for 11k test VoWiFi Ent: Test 2. + * We need the power capabilities for Assoc Req. + * This macro is provided by the halPhyCfg.h. We pick our + * max and min capability by the halPhy provided macros + */ + pwrLimit = csr_get_cfg_max_tx_power(pMac, + pBssDescription->channelId); + if (0 != pwrLimit && pwrLimit < MAX_TX_PWR_CAP) + csr_join_req->powerCap.maxTxPower = pwrLimit; + else + csr_join_req->powerCap.maxTxPower = MAX_TX_PWR_CAP; + + csr_add_supported_5Ghz_channels(pMac, + csr_join_req->supportedChannels.channelList, + &csr_join_req->supportedChannels.numChnl, + false); + + csr_join_req->uapsdPerAcBitmask = (uint8_t)pProfile->uapsd_mask; + /* Move the entire BssDescription into the join request. */ + qdf_mem_copy(&csr_join_req->bssDescription, pBssDescription, + pBssDescription->length + + sizeof(pBssDescription->length)); + + /* + * conc_custom_rule1: + * If SAP comes up first and STA comes up later then SAP + * need to follow STA's channel in 2.4Ghz. In following if + * condition we are adding sanity check, just to make sure that + * if this rule is enabled then don't allow STA to connect on + * 5gz channel and also by this time SAP's channel should be the + * same as STA's channel. + */ + if (pMac->roam.configParam.conc_custom_rule1) { + if ((0 == + pMac-> + roam.configParam.is_sta_connection_in_5gz_enabled) + && CDS_IS_CHANNEL_5GHZ(pBssDescription-> + channelId)) { + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_ERROR, + FL("STA-conn on 5G isn't allowed")); + status = QDF_STATUS_E_FAILURE; + break; + } + if (!CDS_IS_CHANNEL_5GHZ(pBssDescription->channelId) && + (false == csr_is_conn_allow_2g_band(pMac, + pBssDescription->channelId))) { + status = QDF_STATUS_E_FAILURE; + break; + } + } + + /* + * conc_custom_rule2: + * If P2PGO comes up first and STA comes up later then P2PGO + * need to follow STA's channel in 5Ghz. In following if + * condition we are just adding sanity check to make sure that + * by this time P2PGO's channel is same as STA's channel. + */ + if (pMac->roam.configParam.conc_custom_rule2) { + if (!CDS_IS_CHANNEL_24GHZ(pBssDescription->channelId) && + (false == csr_is_conn_allow_5g_band(pMac, + pBssDescription->channelId))) { + status = QDF_STATUS_E_FAILURE; + break; + } + } + if (pSession->pCurRoamProfile->csrPersona == QDF_STA_MODE) + csr_join_req->enable_bcast_probe_rsp = + pMac->roam.configParam.enable_bcast_probe_rsp; + + csr_join_req->ignore_assoc_disallowed = + pSession->ignore_assoc_disallowed; + status = cds_send_mb_message_to_mac(csr_join_req); + if (!QDF_IS_STATUS_SUCCESS(status)) { + /* + * cds_send_mb_message_to_mac would've released the mem + * allocated by csr_join_req. Let's make it defensive by + * assigning NULL to the pointer. + */ + csr_join_req = NULL; + break; + } else { + if (pProfile->csrPersona == QDF_STA_MODE) { + sms_log(pMac, LOG1, + FL(" Invoking packetdump register API")); + wlan_register_txrx_packetdump(); + packetdump_timer_status = + qdf_mc_timer_start( + &pMac->roam.packetdump_timer, + (PKT_DUMP_TIMER_DURATION * + QDF_MC_TIMER_TO_SEC_UNIT)/ + QDF_MC_TIMER_TO_MS_UNIT); + if (!QDF_IS_STATUS_SUCCESS( + packetdump_timer_status)) { + sms_log(pMac, LOGE, + FL("cannot start packetdump timer")); + sms_log(pMac, LOGE, + FL("packetdump_timer_status: %d"), + packetdump_timer_status); + } + } +#ifndef WLAN_MDM_CODE_REDUCTION_OPT + if (eWNI_SME_JOIN_REQ == messageType) { + /* Notify QoS module that join happening */ + pSession->join_bssid_count++; + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_DEBUG, + "BSSID Count = %d", + pSession->join_bssid_count); + sme_qos_csr_event_ind(pMac, (uint8_t) sessionId, + SME_QOS_CSR_JOIN_REQ, NULL); + } else if (eWNI_SME_REASSOC_REQ == messageType) { + /* Notify QoS module that reassoc happening */ + sme_qos_csr_event_ind(pMac, (uint8_t) sessionId, + SME_QOS_CSR_REASSOC_REQ, + NULL); + } +#endif + } + } while (0); + + /* Clean up the memory in case of any failure */ + if (!QDF_IS_STATUS_SUCCESS(status) && (NULL != csr_join_req)) + qdf_mem_free(csr_join_req); + + if (wpaRsnIE) + qdf_mem_free(wpaRsnIE); + + return status; +} + +/* */ +QDF_STATUS csr_send_mb_disassoc_req_msg(tpAniSirGlobal pMac, uint32_t sessionId, + tSirMacAddr bssId, uint16_t reasonCode) +{ + tSirSmeDisassocReq *pMsg; + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!CSR_IS_SESSION_VALID(pMac, sessionId)) + return QDF_STATUS_E_FAILURE; + + pMsg = qdf_mem_malloc(sizeof(tSirSmeDisassocReq)); + if (NULL == pMsg) + return QDF_STATUS_E_NOMEM; + + pMsg->messageType = eWNI_SME_DISASSOC_REQ; + pMsg->length = sizeof(tSirSmeDisassocReq); + pMsg->sessionId = sessionId; + pMsg->transactionId = 0; + if ((pSession->pCurRoamProfile != NULL) + && (CSR_IS_INFRA_AP(pSession->pCurRoamProfile))) { + qdf_mem_copy(&pMsg->bssid.bytes, + &pSession->selfMacAddr, + QDF_MAC_ADDR_SIZE); + qdf_mem_copy(&pMsg->peer_macaddr.bytes, + bssId, + QDF_MAC_ADDR_SIZE); + } else { + qdf_mem_copy(&pMsg->bssid.bytes, + bssId, QDF_MAC_ADDR_SIZE); + qdf_mem_copy(&pMsg->peer_macaddr.bytes, + bssId, QDF_MAC_ADDR_SIZE); + } + pMsg->reasonCode = reasonCode; + pMsg->process_ho_fail = (pSession->disconnect_reason == + eCSR_DISCONNECT_REASON_ROAM_HO_FAIL) ? true : false; + /* + * The state will be DISASSOC_HANDOFF only when we are doing + * handoff. Here we should not send the disassoc over the air + * to the AP + */ + if ((CSR_IS_ROAM_SUBSTATE_DISASSOC_HO(pMac, sessionId) + && csr_roam_is11r_assoc(pMac, sessionId)) || + pMsg->process_ho_fail) { + /* Set DoNotSendOverTheAir flag to 1 only for handoff case */ + pMsg->doNotSendOverTheAir = CSR_DONT_SEND_DISASSOC_OVER_THE_AIR; + } + return cds_send_mb_message_to_mac(pMsg); +} + +QDF_STATUS +csr_send_mb_get_associated_stas_req_msg(tpAniSirGlobal pMac, uint32_t sessionId, + QDF_MODULE_ID modId, + struct qdf_mac_addr bssid, + void *pUsrContext, + void *pfnSapEventCallback, + uint8_t *pAssocStasBuf) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tSirSmeGetAssocSTAsReq *pMsg; + + pMsg = qdf_mem_malloc(sizeof(*pMsg)); + if (NULL == pMsg) + return QDF_STATUS_E_NOMEM; + + pMsg->messageType = eWNI_SME_GET_ASSOC_STAS_REQ; + qdf_copy_macaddr(&pMsg->bssid, &bssid); + pMsg->modId = modId; + qdf_mem_copy(pMsg->pUsrContext, pUsrContext, sizeof(void *)); + qdf_mem_copy(pMsg->pSapEventCallback, + pfnSapEventCallback, sizeof(void *)); + qdf_mem_copy(pMsg->pAssocStasArray, pAssocStasBuf, sizeof(void *)); + pMsg->length = sizeof(*pMsg); + status = cds_send_mb_message_to_mac(pMsg); + + return status; +} + +QDF_STATUS +csr_send_mb_get_wpspbc_sessions(tpAniSirGlobal pMac, uint32_t sessionId, + struct qdf_mac_addr bssid, void *pUsrContext, + void *pfnSapEventCallback, + struct qdf_mac_addr remove_mac) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tSirSmeGetWPSPBCSessionsReq *pMsg; + + do { + pMsg = qdf_mem_malloc(sizeof(tSirSmeGetWPSPBCSessionsReq)); + if (NULL == pMsg) + status = QDF_STATUS_E_NOMEM; + else + status = QDF_STATUS_SUCCESS; + if (!QDF_IS_STATUS_SUCCESS(status)) + break; + qdf_mem_set(pMsg, sizeof(tSirSmeGetWPSPBCSessionsReq), 0); + pMsg->messageType = eWNI_SME_GET_WPSPBC_SESSION_REQ; + qdf_mem_copy(pMsg->pUsrContext, pUsrContext, sizeof(void *)); + qdf_mem_copy(pMsg->pSapEventCallback, pfnSapEventCallback, + sizeof(void *)); + qdf_copy_macaddr(&pMsg->bssid, &bssid); + qdf_copy_macaddr(&pMsg->remove_mac, &remove_mac); + pMsg->length = sizeof(struct sSirSmeGetWPSPBCSessionsReq); + status = cds_send_mb_message_to_mac(pMsg); + } while (0); + return status; +} + +QDF_STATUS csr_send_chng_mcc_beacon_interval(tpAniSirGlobal pMac, uint32_t sessionId) +{ + tpSirChangeBIParams pMsg; + uint16_t len = 0; + QDF_STATUS status = QDF_STATUS_SUCCESS; + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!pSession) { + sms_log(pMac, LOGE, FL(" session %d not found "), sessionId); + return QDF_STATUS_E_FAILURE; + } + /* NO need to update the Beacon Params if update beacon parameter flag is not set */ + if (!pMac->roam.roamSession[sessionId].bssParams.updatebeaconInterval) + return QDF_STATUS_SUCCESS; + + pMac->roam.roamSession[sessionId].bssParams.updatebeaconInterval = + false; + + /* Create the message and send to lim */ + len = sizeof(tSirChangeBIParams); + pMsg = qdf_mem_malloc(len); + if (NULL == pMsg) + status = QDF_STATUS_E_NOMEM; + else + status = QDF_STATUS_SUCCESS; + if (QDF_IS_STATUS_SUCCESS(status)) { + pMsg->messageType = eWNI_SME_CHNG_MCC_BEACON_INTERVAL; + pMsg->length = len; + + qdf_copy_macaddr(&pMsg->bssid, &pSession->selfMacAddr); + sms_log(pMac, LOG1, + FL("CSR Attempting to change BI for Bssid= " + MAC_ADDRESS_STR), MAC_ADDR_ARRAY(pMsg->bssid.bytes)); + pMsg->sessionId = sessionId; + sms_log(pMac, LOG1, FL(" session %d BeaconInterval %d"), + sessionId, + pMac->roam.roamSession[sessionId].bssParams. + beaconInterval); + pMsg->beaconInterval = + pMac->roam.roamSession[sessionId].bssParams.beaconInterval; + status = cds_send_mb_message_to_mac(pMsg); + } + return status; +} + +#ifdef QCA_HT_2040_COEX +QDF_STATUS csr_set_ht2040_mode(tpAniSirGlobal pMac, uint32_t sessionId, + ePhyChanBondState cbMode, bool obssEnabled) +{ + tpSirSetHT2040Mode pMsg; + uint16_t len = 0; + QDF_STATUS status = QDF_STATUS_SUCCESS; + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!pSession) { + sms_log(pMac, LOGE, FL(" session %d not found "), sessionId); + return QDF_STATUS_E_FAILURE; + } + + /* Create the message and send to lim */ + len = sizeof(tSirSetHT2040Mode); + pMsg = qdf_mem_malloc(len); + if (NULL == pMsg) + status = QDF_STATUS_E_NOMEM; + else + status = QDF_STATUS_SUCCESS; + if (QDF_IS_STATUS_SUCCESS(status)) { + qdf_mem_set(pMsg, sizeof(tSirSetHT2040Mode), 0); + pMsg->messageType = eWNI_SME_SET_HT_2040_MODE; + pMsg->length = len; + + qdf_copy_macaddr(&pMsg->bssid, &pSession->selfMacAddr); + sms_log(pMac, LOG1, + FL("CSR Attempting to set HT20/40 mode for Bssid= " + MAC_ADDRESS_STR), MAC_ADDR_ARRAY(pMsg->bssid.bytes)); + pMsg->sessionId = sessionId; + sms_log(pMac, LOG1, FL(" session %d HT20/40 mode %d"), + sessionId, cbMode); + pMsg->cbMode = cbMode; + pMsg->obssEnabled = obssEnabled; + status = cds_send_mb_message_to_mac(pMsg); + } + return status; +} +#endif + +QDF_STATUS csr_send_mb_deauth_req_msg(tpAniSirGlobal pMac, uint32_t sessionId, + tSirMacAddr bssId, uint16_t reasonCode) +{ + tSirSmeDeauthReq *pMsg; + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!CSR_IS_SESSION_VALID(pMac, sessionId)) + return QDF_STATUS_E_FAILURE; + + pMsg = qdf_mem_malloc(sizeof(tSirSmeDeauthReq)); + if (NULL == pMsg) + return QDF_STATUS_E_NOMEM; + + qdf_mem_set(pMsg, sizeof(tSirSmeDeauthReq), 0); + pMsg->messageType = eWNI_SME_DEAUTH_REQ; + pMsg->length = sizeof(tSirSmeDeauthReq); + pMsg->sessionId = sessionId; + pMsg->transactionId = 0; + + if ((pSession->pCurRoamProfile != NULL) + && (CSR_IS_INFRA_AP(pSession->pCurRoamProfile))) { + qdf_mem_copy(&pMsg->bssid, + &pSession->selfMacAddr, + QDF_MAC_ADDR_SIZE); + } else { + qdf_mem_copy(&pMsg->bssid, + bssId, QDF_MAC_ADDR_SIZE); + } + + /* Set the peer MAC address before sending the message to LIM */ + qdf_mem_copy(&pMsg->peer_macaddr.bytes, bssId, QDF_MAC_ADDR_SIZE); + pMsg->reasonCode = reasonCode; + + return cds_send_mb_message_to_mac(pMsg); +} + +QDF_STATUS csr_send_mb_disassoc_cnf_msg(tpAniSirGlobal pMac, + tpSirSmeDisassocInd pDisassocInd) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tSirSmeDisassocCnf *pMsg; + do { + pMsg = qdf_mem_malloc(sizeof(tSirSmeDisassocCnf)); + if (NULL == pMsg) + status = QDF_STATUS_E_NOMEM; + else + status = QDF_STATUS_SUCCESS; + if (!QDF_IS_STATUS_SUCCESS(status)) + break; + pMsg->messageType = eWNI_SME_DISASSOC_CNF; + pMsg->statusCode = eSIR_SME_SUCCESS; + pMsg->length = sizeof(tSirSmeDisassocCnf); + qdf_copy_macaddr(&pMsg->peer_macaddr, + &pDisassocInd->peer_macaddr); + status = QDF_STATUS_SUCCESS; + if (!QDF_IS_STATUS_SUCCESS(status)) { + qdf_mem_free(pMsg); + break; + } + + qdf_copy_macaddr(&pMsg->bssid, &pDisassocInd->bssid); + status = QDF_STATUS_SUCCESS; + if (!QDF_IS_STATUS_SUCCESS(status)) { + qdf_mem_free(pMsg); + break; + } + + status = cds_send_mb_message_to_mac(pMsg); + } while (0); + return status; +} + +QDF_STATUS csr_send_mb_deauth_cnf_msg(tpAniSirGlobal pMac, + tpSirSmeDeauthInd pDeauthInd) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tSirSmeDeauthCnf *pMsg; + do { + pMsg = qdf_mem_malloc(sizeof(tSirSmeDeauthCnf)); + if (NULL == pMsg) + status = QDF_STATUS_E_NOMEM; + else + status = QDF_STATUS_SUCCESS; + if (!QDF_IS_STATUS_SUCCESS(status)) + break; + pMsg->messageType = eWNI_SME_DEAUTH_CNF; + pMsg->statusCode = eSIR_SME_SUCCESS; + pMsg->length = sizeof(tSirSmeDeauthCnf); + qdf_copy_macaddr(&pMsg->bssid, &pDeauthInd->bssid); + status = QDF_STATUS_SUCCESS; + if (!QDF_IS_STATUS_SUCCESS(status)) { + qdf_mem_free(pMsg); + break; + } + qdf_copy_macaddr(&pMsg->peer_macaddr, + &pDeauthInd->peer_macaddr); + status = QDF_STATUS_SUCCESS; + if (!QDF_IS_STATUS_SUCCESS(status)) { + qdf_mem_free(pMsg); + break; + } + status = cds_send_mb_message_to_mac(pMsg); + } while (0); + return status; +} + +QDF_STATUS csr_send_assoc_cnf_msg(tpAniSirGlobal pMac, tpSirSmeAssocInd pAssocInd, + QDF_STATUS Halstatus) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tSirSmeAssocCnf *pMsg; + cds_msg_t msg; + + sms_log(pMac, LOG1, + FL("Posting eWNI_SME_ASSOC_CNF to LIM.HalStatus :%d"), + Halstatus); + do { + pMsg = qdf_mem_malloc(sizeof(tSirSmeAssocCnf)); + if (NULL == pMsg) + return QDF_STATUS_E_NOMEM; + pMsg->messageType = eWNI_SME_ASSOC_CNF; + pMsg->length = sizeof(tSirSmeAssocCnf); + if (QDF_IS_STATUS_SUCCESS(Halstatus)) + pMsg->statusCode = eSIR_SME_SUCCESS; + else + pMsg->statusCode = eSIR_SME_ASSOC_REFUSED; + /* bssId */ + qdf_mem_copy(pMsg->bssid.bytes, pAssocInd->bssId, + QDF_MAC_ADDR_SIZE); + /* peerMacAddr */ + qdf_mem_copy(pMsg->peer_macaddr.bytes, pAssocInd->peerMacAddr, + QDF_MAC_ADDR_SIZE); + /* aid */ + pMsg->aid = pAssocInd->aid; + /* alternateBssId */ + qdf_mem_copy(pMsg->alternate_bssid.bytes, pAssocInd->bssId, + QDF_MAC_ADDR_SIZE); + /* alternateChannelId */ + pMsg->alternateChannelId = 11; + msg.type = pMsg->messageType; + msg.bodyval = 0; + msg.bodyptr = pMsg; + /* pMsg is freed by cds_send_mb_message_to_mac in anycase*/ + status = cds_mq_post_message_by_priority(CDS_MQ_ID_PE, + &msg, HIGH_PRIORITY); + } while (0); + return status; +} + +QDF_STATUS csr_send_assoc_ind_to_upper_layer_cnf_msg(tpAniSirGlobal pMac, + tpSirSmeAssocInd pAssocInd, + QDF_STATUS Halstatus, + uint8_t sessionId) +{ + tSirMsgQ msgQ; + tSirSmeAssocIndToUpperLayerCnf *pMsg; + uint8_t *pBuf; + tSirResultCodes statusCode; + uint16_t wTmp; + do { + pMsg = qdf_mem_malloc(sizeof(tSirSmeAssocIndToUpperLayerCnf)); + if (NULL == pMsg) + return QDF_STATUS_E_NOMEM; + + pMsg->messageType = eWNI_SME_UPPER_LAYER_ASSOC_CNF; + pMsg->length = sizeof(tSirSmeAssocIndToUpperLayerCnf); + + pMsg->sessionId = sessionId; + + pBuf = (uint8_t *) &pMsg->statusCode; + if (QDF_IS_STATUS_SUCCESS(Halstatus)) + statusCode = eSIR_SME_SUCCESS; + else + statusCode = eSIR_SME_ASSOC_REFUSED; + qdf_mem_copy(pBuf, &statusCode, sizeof(tSirResultCodes)); + pBuf += sizeof(tSirResultCodes); + /* bssId */ + qdf_mem_copy((tSirMacAddr *) pBuf, pAssocInd->bssId, + sizeof(tSirMacAddr)); + pBuf += sizeof(tSirMacAddr); + /* peerMacAddr */ + qdf_mem_copy((tSirMacAddr *) pBuf, pAssocInd->peerMacAddr, + sizeof(tSirMacAddr)); + pBuf += sizeof(tSirMacAddr); + /* StaId */ + wTmp = pAssocInd->staId; + qdf_mem_copy(pBuf, &wTmp, sizeof(uint16_t)); + pBuf += sizeof(uint16_t); + /* alternateBssId */ + qdf_mem_copy((tSirMacAddr *) pBuf, pAssocInd->bssId, + sizeof(tSirMacAddr)); + pBuf += sizeof(tSirMacAddr); + /* alternateChannelId */ + *pBuf = 11; + pBuf += sizeof(uint8_t); + /* Instead of copying roam Info, we just copy only WmmEnabled, RsnIE information */ + /* Wmm */ + *pBuf = pAssocInd->wmmEnabledSta; + pBuf += sizeof(uint8_t); + /* RSN IE */ + qdf_mem_copy((tSirRSNie *) pBuf, &pAssocInd->rsnIE, + sizeof(tSirRSNie)); + pBuf += sizeof(tSirRSNie); +#ifdef FEATURE_WLAN_WAPI + /* WAPI IE */ + qdf_mem_copy((tSirWAPIie *) pBuf, &pAssocInd->wapiIE, + sizeof(tSirWAPIie)); + pBuf += sizeof(tSirWAPIie); +#endif + /* Additional IE */ + qdf_mem_copy((void *)pBuf, &pAssocInd->addIE, + sizeof(tSirAddie)); + pBuf += sizeof(tSirAddie); + /* reassocReq */ + *pBuf = pAssocInd->reassocReq; + pBuf += sizeof(uint8_t); + /* timingMeasCap */ + *pBuf = pAssocInd->timingMeasCap; + pBuf += sizeof(uint8_t); + qdf_mem_copy((void *)pBuf, &pAssocInd->chan_info, + sizeof(tSirSmeChanInfo)); + msgQ.type = eWNI_SME_UPPER_LAYER_ASSOC_CNF; + msgQ.bodyptr = pMsg; + msgQ.bodyval = 0; + sys_process_mmh_msg(pMac, &msgQ); + } while (0); + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS csr_send_mb_set_context_req_msg(tpAniSirGlobal pMac, + uint32_t sessionId, + struct qdf_mac_addr peer_macaddr, + uint8_t numKeys, + tAniEdType edType, bool fUnicast, + tAniKeyDirection aniKeyDirection, + uint8_t keyId, uint8_t keyLength, + uint8_t *pKey, uint8_t paeRole, + uint8_t *pKeyRsc) +{ + tSirSmeSetContextReq *pMsg; + uint16_t msgLen; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + sms_log(pMac, LOG1, FL("keylength is %d, Encry type is : %d"), + keyLength, edType); + do { + if ((1 != numKeys) && (0 != numKeys)) + break; + /* + * All of these fields appear in every SET_CONTEXT message. + * Below we'll add in the size for each key set. Since we only support + * up to one key, we always allocate memory for 1 key. + */ + msgLen = sizeof(struct sSirSmeSetContextReq); + + pMsg = qdf_mem_malloc(msgLen); + if (NULL == pMsg) + return QDF_STATUS_E_NOMEM; + pMsg->messageType = eWNI_SME_SETCONTEXT_REQ; + pMsg->length = msgLen; + pMsg->sessionId = (uint8_t) sessionId; + pMsg->transactionId = 0; + qdf_copy_macaddr(&pMsg->peer_macaddr, &peer_macaddr); + qdf_copy_macaddr(&pMsg->bssid, + &pSession->connectedProfile.bssid); + + /** + * Set the pMsg->keyMaterial.length field + * (this length is defined as all data that follows the + * edType field in the tSirKeyMaterial keyMaterial; field). + * + * NOTE: This keyMaterial.length contains the length of a + * MAX size key, though the keyLength can be shorter than this + * max size. Is LIM interpreting this ok ? + */ + pMsg->keyMaterial.length = + sizeof(pMsg->keyMaterial.numKeys) + + (numKeys * sizeof(pMsg->keyMaterial.key)); + pMsg->keyMaterial.edType = edType; + pMsg->keyMaterial.numKeys = numKeys; + pMsg->keyMaterial.key[0].keyId = keyId; + pMsg->keyMaterial.key[0].unicast = fUnicast; + pMsg->keyMaterial.key[0].keyDirection = aniKeyDirection; + qdf_mem_copy(pMsg->keyMaterial.key[0].keyRsc, + pKeyRsc, CSR_MAX_RSC_LEN); + /* 0 is Supplicant */ + pMsg->keyMaterial.key[0].paeRole = paeRole; + pMsg->keyMaterial.key[0].keyLength = keyLength; + if (keyLength && pKey) + qdf_mem_copy(pMsg->keyMaterial.key[0].key, + pKey, keyLength); + status = cds_send_mb_message_to_mac(pMsg); + } while (0); + return status; +} + +QDF_STATUS csr_send_mb_start_bss_req_msg(tpAniSirGlobal pMac, uint32_t sessionId, + eCsrRoamBssType bssType, + tCsrRoamStartBssParams *pParam, + tSirBssDescription *pBssDesc) +{ + tSirSmeStartBssReq *pMsg; + uint16_t wTmp; + uint32_t value = 0; + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!pSession) { + sms_log(pMac, LOGE, FL(" session %d not found "), sessionId); + return QDF_STATUS_E_FAILURE; + } + + pSession->joinFailStatusCode.statusCode = eSIR_SME_SUCCESS; + pSession->joinFailStatusCode.reasonCode = 0; + pMsg = qdf_mem_malloc(sizeof(tSirSmeStartBssReq)); + if (NULL == pMsg) + return QDF_STATUS_E_NOMEM; + + pMsg->messageType = eWNI_SME_START_BSS_REQ; + pMsg->sessionId = sessionId; + pMsg->length = sizeof(tSirSmeStartBssReq); + pMsg->transactionId = 0; + qdf_copy_macaddr(&pMsg->bssid, &pParam->bssid); + /* selfMacAddr */ + qdf_copy_macaddr(&pMsg->self_macaddr, &pSession->selfMacAddr); + /* beaconInterval */ + if (pBssDesc && pBssDesc->beaconInterval) + wTmp = pBssDesc->beaconInterval; + else if (pParam->beaconInterval) + wTmp = pParam->beaconInterval; + else + wTmp = WNI_CFG_BEACON_INTERVAL_STADEF; + + csr_validate_mcc_beacon_interval(pMac, pParam->operationChn, + &wTmp, sessionId, pParam->bssPersona); + /* Update the beacon Interval */ + pParam->beaconInterval = wTmp; + pMsg->beaconInterval = wTmp; + pMsg->dot11mode = + csr_translate_to_wni_cfg_dot11_mode(pMac, + pParam->uCfgDot11Mode); +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH + pMsg->cc_switch_mode = pMac->roam.configParam.cc_switch_mode; +#endif + pMsg->bssType = csr_translate_bsstype_to_mac_type(bssType); + qdf_mem_copy(&pMsg->ssId, &pParam->ssId, sizeof(pParam->ssId)); + pMsg->channelId = pParam->operationChn; + /* What should we really do for the cbmode. */ + pMsg->cbMode = (ePhyChanBondState) pParam->cbMode; + pMsg->vht_channel_width = pParam->ch_params.ch_width; + pMsg->center_freq_seg0 = pParam->ch_params.center_freq_seg0; + pMsg->center_freq_seg1 = pParam->ch_params.center_freq_seg1; + pMsg->sec_ch_offset = pParam->ch_params.sec_ch_offset; + pMsg->privacy = pParam->privacy; + pMsg->apUapsdEnable = pParam->ApUapsdEnable; + pMsg->ssidHidden = pParam->ssidHidden; + pMsg->fwdWPSPBCProbeReq = (uint8_t) pParam->fwdWPSPBCProbeReq; + pMsg->protEnabled = (uint8_t) pParam->protEnabled; + pMsg->obssProtEnabled = (uint8_t) pParam->obssProtEnabled; + /* set cfg related to protection */ + pMsg->ht_capab = pParam->ht_protection; + pMsg->authType = pParam->authType; + pMsg->dtimPeriod = pParam->dtimPeriod; + pMsg->wps_state = pParam->wps_state; + pMsg->isCoalesingInIBSSAllowed = pMac->isCoalesingInIBSSAllowed; + pMsg->bssPersona = pParam->bssPersona; + pMsg->txLdpcIniFeatureEnabled = pMac->roam.configParam.txLdpcEnable; + + if (wlan_cfg_get_int(pMac, WNI_CFG_VHT_SU_BEAMFORMEE_CAP, &value) + != eSIR_SUCCESS) + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + FL("could not get SU beam formee capability")); + pMsg->vht_config.su_beam_formee = + (uint8_t)value && + (uint8_t)pMac->roam.configParam.enable_txbf_sap_mode; + if (wlan_cfg_get_int(pMac, + WNI_CFG_VHT_CSN_BEAMFORMEE_ANT_SUPPORTED, + &value) != eSIR_SUCCESS) + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + FL("Failed to get CSN beamformee capability")); + pMsg->vht_config.csnof_beamformer_antSup = (uint8_t)value; + +#ifdef WLAN_FEATURE_11W + pMsg->pmfCapable = pParam->mfpCapable; + pMsg->pmfRequired = pParam->mfpRequired; +#endif + + if (pParam->nRSNIELength > sizeof(pMsg->rsnIE.rsnIEdata)) { + qdf_mem_free(pMsg); + return QDF_STATUS_E_INVAL; + } + pMsg->rsnIE.length = pParam->nRSNIELength; + qdf_mem_copy(pMsg->rsnIE.rsnIEdata, + pParam->pRSNIE, + pParam->nRSNIELength); + pMsg->nwType = (tSirNwType)pParam->sirNwType; + qdf_mem_copy(&pMsg->operationalRateSet, + &pParam->operationalRateSet, + sizeof(tSirMacRateSet)); + qdf_mem_copy(&pMsg->extendedRateSet, + &pParam->extendedRateSet, + sizeof(tSirMacRateSet)); + /* + * If RX LDPC has been disabled for 2.4GHz channels and enabled + * for 5Ghz for STA like persona then here is how to handle + * those cases (by now channel has been decided). + */ + if (eSIR_IBSS_MODE == pMsg->bssType || !wma_is_dbs_enable()) + csr_set_ldpc_exception(pMac, pSession, + pMsg->channelId, + pMac->roam.configParam.rxLdpcEnable); + qdf_mem_copy(&pMsg->vht_config, + &pSession->vht_config, + sizeof(pSession->vht_config)); + qdf_mem_copy(&pMsg->htConfig, + &pSession->htConfig, + sizeof(tSirHTConfig)); + sms_log(pMac, LOG2, FL("ht capability 0x%x VHT capability 0x%x"), + (uint32_t)(*(uint32_t *) &pMsg->htConfig), + (uint32_t)(*(uint32_t *) &pMsg->vht_config)); + qdf_mem_copy(&pMsg->addIeParams, + &pParam->addIeParams, + sizeof(pParam->addIeParams)); + pMsg->obssEnabled = pMac->roam.configParam.obssEnabled; + pMsg->sap_dot11mc = pParam->sap_dot11mc; + pMsg->vendor_vht_sap = + pMac->roam.configParam.vendor_vht_sap; + + return cds_send_mb_message_to_mac(pMsg); +} + +QDF_STATUS csr_send_mb_stop_bss_req_msg(tpAniSirGlobal pMac, uint32_t sessionId) +{ + tSirSmeStopBssReq *pMsg; + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!pSession) { + sms_log(pMac, LOGE, FL(" session %d not found "), sessionId); + return QDF_STATUS_E_FAILURE; + } + + pMsg = qdf_mem_malloc(sizeof(tSirSmeStopBssReq)); + if (NULL == pMsg) + return QDF_STATUS_E_NOMEM; + pMsg->messageType = eWNI_SME_STOP_BSS_REQ; + pMsg->sessionId = sessionId; + pMsg->length = sizeof(tSirSmeStopBssReq); + pMsg->transactionId = 0; + pMsg->reasonCode = 0; + qdf_copy_macaddr(&pMsg->bssid, &pSession->connectedProfile.bssid); + return cds_send_mb_message_to_mac(pMsg); +} + +QDF_STATUS csr_reassoc(tpAniSirGlobal pMac, uint32_t sessionId, + tCsrRoamModifyProfileFields *pModProfileFields, + uint32_t *pRoamId, bool fForce) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + uint32_t roamId = 0; + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + if ((csr_is_conn_state_connected(pMac, sessionId)) && + (fForce || (qdf_mem_cmp(&pModProfileFields, + &pSession->connectedProfile. + modifyProfileFields, + sizeof(tCsrRoamModifyProfileFields))))) { + roamId = GET_NEXT_ROAM_ID(&pMac->roam); + if (pRoamId) { + *pRoamId = roamId; + } + + status = + csr_roam_issue_reassoc(pMac, sessionId, NULL, + pModProfileFields, + eCsrSmeIssuedReassocToSameAP, + roamId, false); + } + return status; +} + +static QDF_STATUS csr_roam_session_opened(tpAniSirGlobal pMac, + uint32_t sessionId) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tCsrRoamInfo roamInfo; + qdf_mem_set(&roamInfo, sizeof(tCsrRoamInfo), 0); + status = csr_roam_call_callback(pMac, sessionId, &roamInfo, 0, + eCSR_ROAM_SESSION_OPENED, + eCSR_ROAM_RESULT_NONE); + return status; +} + +QDF_STATUS csr_process_add_sta_session_rsp(tpAniSirGlobal pMac, uint8_t *pMsg) +{ + tListElem *pEntry = NULL; + tSmeCmd *pCommand = NULL; + struct add_sta_self_params *rsp; + struct send_extcap_ie *msg; + QDF_STATUS status; + + if (pMsg == NULL) { + sms_log(pMac, LOGE, "in %s msg ptr is NULL", __func__); + return QDF_STATUS_E_FAILURE; + } + pEntry = csr_ll_peek_head(&pMac->sme.smeCmdActiveList, LL_ACCESS_LOCK); + if (!pEntry) { + sms_log(pMac, LOGE, "in %s NO commands are ACTIVE ...", + __func__); + return QDF_STATUS_E_FAILURE; + } + pCommand = GET_BASE_ADDR(pEntry, tSmeCmd, Link); + if (eSmeCommandAddStaSession != pCommand->command) { + sms_log(pMac, LOGE, "in %s Cmd not in active list ...", + __func__); + return QDF_STATUS_E_FAILURE; + } + rsp = (struct add_sta_self_params *) pMsg; + sms_log(pMac, LOG1, "Add Sta self rsp status = %d", rsp->status); + + if (QDF_STATUS_SUCCESS == rsp->status && + (WMI_VDEV_TYPE_STA == rsp->type || + (WMI_VDEV_TYPE_AP == rsp->type && + WMI_UNIFIED_VDEV_SUBTYPE_P2P_DEVICE == rsp->sub_type))) { + sms_log(pMac, LOG1, FL("send SET IE msg to PE")); + msg = qdf_mem_malloc(sizeof(*msg)); + if (NULL == msg) { + sms_log(pMac, LOGE, FL("Memory allocation failed")); + return QDF_STATUS_E_NOMEM; + } + + msg->msg_type = eWNI_SME_SET_IE_REQ; + msg->session_id = rsp->session_id; + msg->length = sizeof(*msg); + status = cds_send_mb_message_to_mac(msg); + if (!QDF_IS_STATUS_SUCCESS(status)) + sms_log(pMac, LOGE, + FL("Failed to send down the set IE req ")); + } + + csr_roam_session_opened(pMac, pCommand->sessionId); + /* Remove this command out of the active list */ + if (csr_ll_remove_entry(&pMac->sme.smeCmdActiveList, pEntry, + LL_ACCESS_LOCK)) { + /* Now put this command back on the avilable command list */ + csr_release_command(pMac, pCommand); + } + sme_process_pending_queue(pMac); + return QDF_STATUS_SUCCESS; +} + +/** + * csr_get_vdev_type_nss() - gets the nss value based on vdev type + * @mac_ctx: Pointer to Global MAC structure + * @dev_mode: current device operating mode. + * @nss2g: Pointer to the 2G Nss parameter. + * @nss5g: Pointer to the 5G Nss parameter. + * + * Fills the 2G and 5G Nss values based on device mode. + * + * Return: None + */ +void csr_get_vdev_type_nss(tpAniSirGlobal mac_ctx, + enum tQDF_ADAPTER_MODE dev_mode, + uint8_t *nss_2g, uint8_t *nss_5g) +{ + switch (dev_mode) { + case QDF_STA_MODE: + *nss_2g = mac_ctx->vdev_type_nss_2g.sta; + *nss_5g = mac_ctx->vdev_type_nss_5g.sta; + break; + case QDF_SAP_MODE: + *nss_2g = mac_ctx->vdev_type_nss_2g.sap; + *nss_5g = mac_ctx->vdev_type_nss_5g.sap; + break; + case QDF_P2P_CLIENT_MODE: + *nss_2g = mac_ctx->vdev_type_nss_2g.p2p_cli; + *nss_5g = mac_ctx->vdev_type_nss_5g.p2p_cli; + break; + case QDF_P2P_GO_MODE: + *nss_2g = mac_ctx->vdev_type_nss_2g.p2p_go; + *nss_5g = mac_ctx->vdev_type_nss_5g.p2p_go; + break; + case QDF_P2P_DEVICE_MODE: + *nss_2g = mac_ctx->vdev_type_nss_2g.p2p_dev; + *nss_5g = mac_ctx->vdev_type_nss_5g.p2p_dev; + break; + case QDF_IBSS_MODE: + *nss_2g = mac_ctx->vdev_type_nss_2g.ibss; + *nss_5g = mac_ctx->vdev_type_nss_5g.ibss; + break; + case QDF_OCB_MODE: + *nss_2g = mac_ctx->vdev_type_nss_2g.ocb; + *nss_5g = mac_ctx->vdev_type_nss_5g.ocb; + break; + default: + *nss_2g = 1; + *nss_5g = 1; + sms_log(mac_ctx, LOGE, FL("Unknown device mode")); + break; + } + sms_log(mac_ctx, LOG1, FL("mode - %d: nss_2g - %d, 5g - %d"), + dev_mode, *nss_2g, *nss_5g); +} + +static +QDF_STATUS csr_issue_add_sta_for_session_req(tpAniSirGlobal pMac, + uint32_t sessionId, + tSirMacAddr sessionMacAddr, + uint32_t type, uint32_t subType) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tSmeCmd *pCommand; + pCommand = csr_get_command_buffer(pMac); + if (NULL == pCommand) { + status = QDF_STATUS_E_RESOURCES; + } else { + pCommand->command = eSmeCommandAddStaSession; + pCommand->sessionId = (uint8_t) sessionId; + qdf_mem_copy(pCommand->u.addStaSessionCmd.selfMacAddr, + sessionMacAddr, sizeof(tSirMacAddr)); + pCommand->u.addStaSessionCmd.currDeviceMode = + pMac->sme.currDeviceMode; + pCommand->u.addStaSessionCmd.type = type; + pCommand->u.addStaSessionCmd.subType = subType; + status = csr_queue_sme_command(pMac, pCommand, true); + if (!QDF_IS_STATUS_SUCCESS(status)) { + /* Should be panic?? */ + sms_log(pMac, LOGE, + FL(" fail to send message status = %d"), status); + } + } + return status; +} + +QDF_STATUS csr_process_add_sta_session_command(tpAniSirGlobal pMac, + tSmeCmd *pCommand) +{ + tAddStaForSessionCmd *pAddStaReq = + &pCommand->u.addStaSessionCmd; + uint8_t sessionId = pCommand->sessionId; + struct add_sta_self_params *add_sta_self_req; + uint8_t nss_2g; + uint8_t nss_5g; + QDF_STATUS status = QDF_STATUS_E_NOMEM; + tSirMsgQ msg; + + add_sta_self_req = qdf_mem_malloc(sizeof(struct add_sta_self_params)); + if (NULL == add_sta_self_req) { + sms_log(pMac, LOGP, + FL + ("Unable to allocate memory for tAddSelfStaParams")); + return status; + } + + csr_get_vdev_type_nss(pMac, pAddStaReq->currDeviceMode, + &nss_2g, &nss_5g); + qdf_mem_copy(add_sta_self_req->self_mac_addr, pAddStaReq->selfMacAddr, + sizeof(tSirMacAddr)); + add_sta_self_req->curr_device_mode = pAddStaReq->currDeviceMode; + add_sta_self_req->session_id = sessionId; + add_sta_self_req->type = pAddStaReq->type; + add_sta_self_req->sub_type = pAddStaReq->subType; + add_sta_self_req->nss_2g = nss_2g; + add_sta_self_req->nss_5g = nss_5g; + add_sta_self_req->tx_aggregation_size = + pMac->roam.configParam.tx_aggregation_size; + add_sta_self_req->rx_aggregation_size = + pMac->roam.configParam.rx_aggregation_size; + add_sta_self_req->enable_bcast_probe_rsp = + pMac->roam.configParam.enable_bcast_probe_rsp; + add_sta_self_req->fils_max_chan_guard_time = + pMac->roam.configParam.fils_max_chan_guard_time; + add_sta_self_req->pkt_err_disconn_th = + pMac->roam.configParam.pkt_err_disconn_th; + msg.type = WMA_ADD_STA_SELF_REQ; + msg.reserved = 0; + msg.bodyptr = add_sta_self_req; + msg.bodyval = 0; + + sms_log(pMac, LOG1, + FL + ("Send WMA_ADD_STA_SELF_REQ for selfMac=" MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(add_sta_self_req->self_mac_addr)); + status = wma_post_ctrl_msg(pMac, &msg); + + if (status != QDF_STATUS_SUCCESS) { + sms_log(pMac, LOGP, FL("wma_post_ctrl_msg failed")); + qdf_mem_free(add_sta_self_req); + add_sta_self_req = NULL; + } + return status; +} + +QDF_STATUS csr_roam_open_session(tpAniSirGlobal mac_ctx, + csr_roam_completeCallback callback, + void *pContext, + uint8_t *pSelfMacAddr, uint8_t *pbSessionId, + uint32_t type, uint32_t subType) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + uint32_t i, value = 0, session_id; + union { + uint16_t nCfgValue16; + tSirMacHTCapabilityInfo htCapInfo; + } uHTCapabilityInfo; + uint32_t nCfgValue = 0; + tCsrRoamSession *session; + *pbSessionId = CSR_SESSION_ID_INVALID; + + if (QDF_STATUS_SUCCESS == csr_roam_get_session_id_from_bssid(mac_ctx, + (struct qdf_mac_addr *)pSelfMacAddr, + &session_id)) { + sms_log(mac_ctx, LOGE, + FL("Session %d exists with mac address" + MAC_ADDRESS_STR), + session_id, MAC_ADDR_ARRAY(pSelfMacAddr)); + return QDF_STATUS_E_FAILURE; + } + + for (i = 0; i < mac_ctx->sme.max_intf_count; i++) { + sms_log(mac_ctx, LOG1, FL("session:%d active:%d"), i, + mac_ctx->roam.roamSession[i].sessionActive); + if (!CSR_IS_SESSION_VALID(mac_ctx, i)) { + session = CSR_GET_SESSION(mac_ctx, i); + if (!session) { + sms_log(mac_ctx, LOGE, + FL("Session does not exist for interface %d"), + i); + break; + } + status = QDF_STATUS_SUCCESS; + session->sessionActive = true; + session->sessionId = (uint8_t) i; + + /* Initialize FT related data structures only in STA mode */ + sme_ft_open(mac_ctx, session->sessionId); + + session->callback = callback; + session->pContext = pContext; + qdf_mem_copy(&session->selfMacAddr, pSelfMacAddr, + sizeof(struct qdf_mac_addr)); + *pbSessionId = (uint8_t) i; + status = + qdf_mc_timer_init(&session->hTimerRoaming, + QDF_TIMER_TYPE_SW, + csr_roam_roaming_timer_handler, + &session->roamingTimerInfo); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sms_log(mac_ctx, LOGE, + FL("cannot allocate memory for Roaming timer")); + break; + } + status = qdf_mc_timer_init( + &session->roaming_offload_timer, + QDF_TIMER_TYPE_SW, + csr_roam_roaming_offload_timeout_handler, + &session->roamingTimerInfo); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sms_log(mac_ctx, LOGE, + FL("mem fail for roaming timer")); + break; + } + /* get the HT capability info */ + if (wlan_cfg_get_int(mac_ctx, WNI_CFG_HT_CAP_INFO, &value) + != eSIR_SUCCESS) { + QDF_TRACE(QDF_MODULE_ID_QDF, + QDF_TRACE_LEVEL_ERROR, + "%s: could not get HT capability info", + __func__); + break; + } +#ifdef FEATURE_WLAN_BTAMP_UT_RF + status = qdf_mc_timer_init(&session->hTimerJoinRetry, + QDF_TIMER_TYPE_SW, + csr_roam_join_retry_timer_handler, + &session-> + joinRetryTimerInfo); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sms_log(mac_ctx, LOGE, + FL + ("cannot allocate memory for join retry timer")); + break; + } +#endif + uHTCapabilityInfo.nCfgValue16 = 0xFFFF & value; + session->htConfig.ht_rx_ldpc = + uHTCapabilityInfo.htCapInfo.advCodingCap; + session->htConfig.ht_tx_stbc = + uHTCapabilityInfo.htCapInfo.txSTBC; + session->htConfig.ht_rx_stbc = + uHTCapabilityInfo.htCapInfo.rxSTBC; + session->htConfig.ht_sgi20 = + uHTCapabilityInfo.htCapInfo.shortGI20MHz; + session->htConfig.ht_sgi40 = + uHTCapabilityInfo.htCapInfo.shortGI40MHz; + + wlan_cfg_get_int(mac_ctx, WNI_CFG_VHT_MAX_MPDU_LENGTH, + &nCfgValue); + session->vht_config.max_mpdu_len = nCfgValue; + + nCfgValue = 0; + wlan_cfg_get_int(mac_ctx, + WNI_CFG_VHT_SUPPORTED_CHAN_WIDTH_SET, + &nCfgValue); + session->vht_config.supported_channel_widthset = + nCfgValue; + + nCfgValue = 0; + wlan_cfg_get_int(mac_ctx, WNI_CFG_VHT_LDPC_CODING_CAP, + &nCfgValue); + session->vht_config.ldpc_coding = nCfgValue; + + nCfgValue = 0; + wlan_cfg_get_int(mac_ctx, WNI_CFG_VHT_SHORT_GI_80MHZ, + &nCfgValue); + session->vht_config.shortgi80 = nCfgValue; + + nCfgValue = 0; + wlan_cfg_get_int(mac_ctx, + WNI_CFG_VHT_SHORT_GI_160_AND_80_PLUS_80MHZ, + &nCfgValue); + session->vht_config.shortgi160and80plus80 = nCfgValue; + + nCfgValue = 0; + wlan_cfg_get_int(mac_ctx, WNI_CFG_VHT_TXSTBC, + &nCfgValue); + session->vht_config.tx_stbc = nCfgValue; + + nCfgValue = 0; + wlan_cfg_get_int(mac_ctx, WNI_CFG_VHT_RXSTBC, + &nCfgValue); + session->vht_config.rx_stbc = nCfgValue; + + nCfgValue = 0; + wlan_cfg_get_int(mac_ctx, WNI_CFG_VHT_SU_BEAMFORMER_CAP, + &nCfgValue); + session->vht_config.su_beam_former = nCfgValue; + + nCfgValue = 0; + wlan_cfg_get_int(mac_ctx, WNI_CFG_VHT_SU_BEAMFORMEE_CAP, + &nCfgValue); + session->vht_config.su_beam_formee = nCfgValue; + + nCfgValue = 0; + wlan_cfg_get_int(mac_ctx, + WNI_CFG_VHT_CSN_BEAMFORMEE_ANT_SUPPORTED, + &nCfgValue); + session->vht_config.csnof_beamformer_antSup = + nCfgValue; + + nCfgValue = 0; + wlan_cfg_get_int(mac_ctx, + WNI_CFG_VHT_NUM_SOUNDING_DIMENSIONS, + &nCfgValue); + session->vht_config.num_soundingdim = nCfgValue; + + nCfgValue = 0; + wlan_cfg_get_int(mac_ctx, WNI_CFG_VHT_MU_BEAMFORMER_CAP, + &nCfgValue); + session->vht_config.mu_beam_former = nCfgValue; + + nCfgValue = 0; + wlan_cfg_get_int(mac_ctx, WNI_CFG_VHT_MU_BEAMFORMEE_CAP, + &nCfgValue); + session->vht_config.mu_beam_formee = nCfgValue; + + nCfgValue = 0; + wlan_cfg_get_int(mac_ctx, WNI_CFG_VHT_TXOP_PS, + &nCfgValue); + session->vht_config.vht_txops = nCfgValue; + + nCfgValue = 0; + wlan_cfg_get_int(mac_ctx, WNI_CFG_VHT_HTC_VHTC_CAP, + &nCfgValue); + session->vht_config.htc_vhtcap = nCfgValue; + + nCfgValue = 0; + wlan_cfg_get_int(mac_ctx, WNI_CFG_VHT_RX_ANT_PATTERN, + &nCfgValue); + session->vht_config.rx_antpattern = nCfgValue; + + nCfgValue = 0; + wlan_cfg_get_int(mac_ctx, WNI_CFG_VHT_TX_ANT_PATTERN, + &nCfgValue); + session->vht_config.tx_antpattern = nCfgValue; + + nCfgValue = 0; + wlan_cfg_get_int(mac_ctx, + WNI_CFG_VHT_AMPDU_LEN_EXPONENT, + &nCfgValue); + session->vht_config.max_ampdu_lenexp = nCfgValue; + + status = csr_issue_add_sta_for_session_req(mac_ctx, i, + pSelfMacAddr, + type, subType); + break; + } + } + if (mac_ctx->sme.max_intf_count == i) { + /* No session is available */ + sms_log(mac_ctx, LOGE, + "%s: Reached max interfaces: %d! Session creation will fail", + __func__, mac_ctx->sme.max_intf_count); + status = QDF_STATUS_E_RESOURCES; + } + return status; +} + +QDF_STATUS csr_process_del_sta_session_rsp(tpAniSirGlobal pMac, uint8_t *pMsg) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tListElem *pEntry = NULL; + tSmeCmd *pCommand = NULL; + struct del_sta_self_params *rsp; + uint8_t sessionId; + + if (pMsg == NULL) { + sms_log(pMac, LOGE, FL("msg ptr is NULL")); + return status; + } + pEntry = csr_ll_peek_head(&pMac->sme.smeCmdActiveList, LL_ACCESS_LOCK); + if (!pEntry) { + sms_log(pMac, LOGE, FL("NO commands are ACTIVE ...")); + return status; + } + pCommand = GET_BASE_ADDR(pEntry, tSmeCmd, Link); + sessionId = pCommand->sessionId; + if (eSmeCommandDelStaSession != pCommand->command) { + sms_log(pMac, LOGE, FL("NO Del sta session command ACTIVE")); + return status; + } + rsp = (struct del_sta_self_params *) pMsg; + sms_log(pMac, LOG1, FL("Del Sta rsp status = %d"), rsp->status); + /* This session is done. */ + csr_cleanup_session(pMac, sessionId); + if (pCommand->u.delStaSessionCmd.callback) { + status = sme_release_global_lock(&pMac->sme); + if (!QDF_IS_STATUS_SUCCESS(status)) + sms_log(pMac, LOG1, FL("Failed to Release Lock")); + else { + pCommand->u.delStaSessionCmd. + callback(pCommand->u.delStaSessionCmd.pContext); + status = sme_acquire_global_lock(&pMac->sme); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOG1, FL("Failed to get Lock")); + return status; + } + } + } + /* Remove this command out of the active list */ + if (csr_ll_remove_entry(&pMac->sme.smeCmdActiveList, pEntry, + LL_ACCESS_LOCK)) { + /* Now put this command back on the avilable command list */ + csr_release_command(pMac, pCommand); + } + sme_process_pending_queue(pMac); + status = QDF_STATUS_SUCCESS; + return status; +} + + +static QDF_STATUS +csr_issue_del_sta_for_session_req(tpAniSirGlobal pMac, uint32_t sessionId, + tSirMacAddr sessionMacAddr, + csr_roamSessionCloseCallback callback, + void *pContext) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tSmeCmd *pCommand; + pCommand = csr_get_command_buffer(pMac); + if (NULL == pCommand) { + status = QDF_STATUS_E_RESOURCES; + } else { + pCommand->command = eSmeCommandDelStaSession; + pCommand->sessionId = (uint8_t) sessionId; + pCommand->u.delStaSessionCmd.callback = callback; + pCommand->u.delStaSessionCmd.pContext = pContext; + qdf_mem_copy(pCommand->u.delStaSessionCmd.selfMacAddr, + sessionMacAddr, sizeof(tSirMacAddr)); + status = csr_queue_sme_command(pMac, pCommand, true); + if (!QDF_IS_STATUS_SUCCESS(status)) { + /* Should be panic?? */ + sms_log(pMac, LOGE, + FL(" fail to send message status = %d"), status); + } + } + return status; +} + +QDF_STATUS csr_process_del_sta_session_command(tpAniSirGlobal pMac, + tSmeCmd *pCommand) +{ + struct del_sta_self_params *del_sta_self_req; + tSirMsgQ msg; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + del_sta_self_req = qdf_mem_malloc(sizeof(struct del_sta_self_params)); + if (NULL == del_sta_self_req) { + sms_log(pMac, LOGP, + FL(" mem alloc failed for tDelStaSelfParams")); + return QDF_STATUS_E_NOMEM; + } + + qdf_mem_copy(del_sta_self_req->self_mac_addr, + pCommand->u.delStaSessionCmd.selfMacAddr, + sizeof(tSirMacAddr)); + + del_sta_self_req->session_id = pCommand->sessionId; + msg.type = WMA_DEL_STA_SELF_REQ; + msg.reserved = 0; + msg.bodyptr = del_sta_self_req; + msg.bodyval = 0; + + sms_log(pMac, LOG1, + FL("sending WMA_DEL_STA_SELF_REQ")); + status = wma_post_ctrl_msg(pMac, &msg); + if (status != QDF_STATUS_SUCCESS) { + sms_log(pMac, LOGP, FL("wma_post_ctrl_msg failed")); + qdf_mem_free(del_sta_self_req); + } + return status; +} + +static void purge_csr_session_cmd_list(tpAniSirGlobal pMac, uint32_t sessionId) +{ + tDblLinkList *pList = &pMac->roam.roamCmdPendingList; + tListElem *pEntry, *pNext; + tSmeCmd *pCommand; + tDblLinkList localList; + + qdf_mem_zero(&localList, sizeof(tDblLinkList)); + if (!QDF_IS_STATUS_SUCCESS(csr_ll_open(pMac->hHdd, &localList))) { + sms_log(pMac, LOGE, FL(" failed to open list")); + return; + } + csr_ll_lock(pList); + pEntry = csr_ll_peek_head(pList, LL_ACCESS_NOLOCK); + while (pEntry != NULL) { + pNext = csr_ll_next(pList, pEntry, LL_ACCESS_NOLOCK); + pCommand = GET_BASE_ADDR(pEntry, tSmeCmd, Link); + if (pCommand->sessionId == sessionId) { + if (csr_ll_remove_entry(pList, pEntry, LL_ACCESS_NOLOCK)) { + csr_ll_insert_tail(&localList, pEntry, + LL_ACCESS_NOLOCK); + } + } + pEntry = pNext; + } + csr_ll_unlock(pList); + + while ((pEntry = csr_ll_remove_head(&localList, LL_ACCESS_NOLOCK))) { + pCommand = GET_BASE_ADDR(pEntry, tSmeCmd, Link); + csr_abort_command(pMac, pCommand, true); + } + csr_ll_close(&localList); +} + +void csr_cleanup_session(tpAniSirGlobal pMac, uint32_t sessionId) +{ + if (CSR_IS_SESSION_VALID(pMac, sessionId)) { + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + + csr_roam_stop(pMac, sessionId); + + /* Clean up FT related data structures */ + sme_ft_close(pMac, sessionId); + csr_free_connect_bss_desc(pMac, sessionId); + csr_roam_free_connect_profile(&pSession->connectedProfile); + csr_roam_free_connected_info(pMac, &pSession->connectedInfo); + qdf_mc_timer_destroy(&pSession->hTimerRoaming); + qdf_mc_timer_destroy(&pSession->roaming_offload_timer); +#ifdef FEATURE_WLAN_BTAMP_UT_RF + qdf_mc_timer_destroy(&pSession->hTimerJoinRetry); +#endif + purge_sme_session_cmd_list(pMac, sessionId, + &pMac->sme.smeCmdPendingList); + purge_sme_session_cmd_list(pMac, sessionId, + &pMac->sme. + smeScanCmdPendingList); + + purge_csr_session_cmd_list(pMac, sessionId); + csr_init_session(pMac, sessionId); + } +} + +QDF_STATUS csr_roam_close_session(tpAniSirGlobal pMac, uint32_t sessionId, + bool fSync, + csr_roamSessionCloseCallback callback, + void *pContext) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + if (CSR_IS_SESSION_VALID(pMac, sessionId)) { + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + /* Vdev going down stop roaming */ + pSession->fCancelRoaming = true; + if (fSync) { + csr_cleanup_session(pMac, sessionId); + } else { + purge_sme_session_cmd_list(pMac, sessionId, + &pMac->sme.smeCmdPendingList); + purge_sme_session_cmd_list(pMac, sessionId, + &pMac->sme.smeScanCmdPendingList); + + purge_sme_session_cmd_list(pMac, sessionId, + &pMac->sme.smeScanCmdActiveList); + + purge_csr_session_cmd_list(pMac, sessionId); + status = csr_issue_del_sta_for_session_req(pMac, + sessionId, + pSession->selfMacAddr.bytes, + callback, pContext); + } + } else { + status = QDF_STATUS_E_INVAL; + } + return status; +} + +static void csr_init_session(tpAniSirGlobal pMac, uint32_t sessionId) +{ + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!pSession) { + sms_log(pMac, LOGE, FL(" session %d not found "), sessionId); + return; + } + + pSession->sessionActive = false; + pSession->sessionId = CSR_SESSION_ID_INVALID; + pSession->callback = NULL; + pSession->pContext = NULL; + pSession->connectState = eCSR_ASSOC_STATE_TYPE_NOT_CONNECTED; + csr_free_roam_profile(pMac, sessionId); + csr_roam_free_connect_profile(&pSession->connectedProfile); + csr_roam_free_connected_info(pMac, &pSession->connectedInfo); + csr_free_connect_bss_desc(pMac, sessionId); + csr_scan_enable(pMac); + qdf_mem_set(&pSession->selfMacAddr, sizeof(struct qdf_mac_addr), 0); + if (pSession->pWpaRsnReqIE) { + qdf_mem_free(pSession->pWpaRsnReqIE); + pSession->pWpaRsnReqIE = NULL; + } + pSession->nWpaRsnReqIeLength = 0; + if (pSession->pWpaRsnRspIE) { + qdf_mem_free(pSession->pWpaRsnRspIE); + pSession->pWpaRsnRspIE = NULL; + } + pSession->nWpaRsnRspIeLength = 0; +#ifdef FEATURE_WLAN_WAPI + if (pSession->pWapiReqIE) { + qdf_mem_free(pSession->pWapiReqIE); + pSession->pWapiReqIE = NULL; + } + pSession->nWapiReqIeLength = 0; + if (pSession->pWapiRspIE) { + qdf_mem_free(pSession->pWapiRspIE); + pSession->pWapiRspIE = NULL; + } + pSession->nWapiRspIeLength = 0; +#endif /* FEATURE_WLAN_WAPI */ + if (pSession->pAddIEScan) { + qdf_mem_free(pSession->pAddIEScan); + pSession->pAddIEScan = NULL; + } + pSession->nAddIEScanLength = 0; + if (pSession->pAddIEAssoc) { + qdf_mem_free(pSession->pAddIEAssoc); + pSession->pAddIEAssoc = NULL; + } + pSession->nAddIEAssocLength = 0; +} + +QDF_STATUS csr_roam_get_session_id_from_bssid(tpAniSirGlobal pMac, + struct qdf_mac_addr *bssid, + uint32_t *pSessionId) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + uint32_t i; + for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) { + if (CSR_IS_SESSION_VALID(pMac, i)) { + if (qdf_is_macaddr_equal(bssid, + &pMac->roam.roamSession[i].connectedProfile. + bssid)) { + /* Found it */ + status = QDF_STATUS_SUCCESS; + *pSessionId = i; + break; + } + } + } + return status; +} + +/* This function assumes that we only support one IBSS session. We cannot use BSSID to identify */ +/* session because for IBSS, the bssid changes. */ +static uint32_t csr_find_ibss_session(tpAniSirGlobal pMac) +{ + uint32_t i, nRet = CSR_SESSION_ID_INVALID; + tCsrRoamSession *pSession; + for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) { + if (CSR_IS_SESSION_VALID(pMac, i)) { + pSession = CSR_GET_SESSION(pMac, i); + if (pSession->pCurRoamProfile + && + (csr_is_bss_type_ibss + (pSession->connectedProfile.BSSType))) { + /* Found it */ + nRet = i; + break; + } + } + } + return nRet; +} + +static void csr_roam_link_up(tpAniSirGlobal pMac, struct qdf_mac_addr bssid) +{ + uint32_t sessionId = 0; + + /* + * Update the current BSS info in ho control block based on connected + * profile info from pmac global structure + */ + + sms_log(pMac, LOGW, + " csr_roam_link_up: WLAN link UP with AP= " MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(bssid.bytes)); + /* Check for user misconfig of RSSI trigger threshold */ + pMac->roam.configParam.vccRssiThreshold = + (0 == pMac->roam.configParam.vccRssiThreshold) ? + CSR_VCC_RSSI_THRESHOLD : + pMac->roam.configParam.vccRssiThreshold; + pMac->roam.vccLinkQuality = eCSR_ROAM_LINK_QUAL_POOR_IND; + /* Check for user misconfig of UL MAC Loss trigger threshold */ + pMac->roam.configParam.vccUlMacLossThreshold = + (0 == pMac->roam.configParam.vccUlMacLossThreshold) ? + CSR_VCC_UL_MAC_LOSS_THRESHOLD : pMac->roam.configParam. + vccUlMacLossThreshold; + /* Indicate the neighbor roal algorithm about the connect indication */ + csr_roam_get_session_id_from_bssid(pMac, &bssid, + &sessionId); + csr_neighbor_roam_indicate_connect(pMac, sessionId, + QDF_STATUS_SUCCESS); +} + +static void csr_roam_link_down(tpAniSirGlobal pMac, uint32_t sessionId) +{ + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!pSession) { + sms_log(pMac, LOGE, FL(" session %d not found "), sessionId); + return; + } + /* Only to handle the case for Handover on infra link */ + if (eCSR_BSS_TYPE_INFRASTRUCTURE != pSession->connectedProfile.BSSType) { + return; + } + /* + * Incase of station mode, immediately stop data transmission whenever + * link down is detected. + */ + if (csr_roam_is_sta_mode(pMac, sessionId) + && !CSR_IS_ROAM_SUBSTATE_DISASSOC_HO(pMac, sessionId) + && !csr_roam_is11r_assoc(pMac, sessionId)) { + sms_log(pMac, LOG1, FL("Inform Link lost for session %d"), + sessionId); + csr_roam_call_callback(pMac, sessionId, NULL, 0, + eCSR_ROAM_LOSTLINK, + eCSR_ROAM_RESULT_LOSTLINK); + } + /* deregister the clients requesting stats from PE/TL & also stop the corresponding timers */ + csr_roam_dereg_statistics_req(pMac); + pMac->roam.vccLinkQuality = eCSR_ROAM_LINK_QUAL_POOR_IND; + /* Indicate the neighbor roal algorithm about the disconnect indication */ + csr_neighbor_roam_indicate_disconnect(pMac, sessionId); + + /* Remove this code once SLM_Sessionization is supported */ + /* BMPS_WORKAROUND_NOT_NEEDED */ + if (!IS_FEATURE_SUPPORTED_BY_FW(SLM_SESSIONIZATION) && + csr_is_infra_ap_started(pMac) && + pMac->roam.configParam.doBMPSWorkaround) { + pMac->roam.configParam.doBMPSWorkaround = 0; + } + +} + +void csr_roam_tl_stats_timer_handler(void *pv) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(pv); + QDF_STATUS status; + pMac->roam.tlStatsReqInfo.timerRunning = false; + + sms_log(pMac, LOG1, + FL + (" TL stat timer is no-op. It needs to support multiple stations")); + + if (!pMac->roam.tlStatsReqInfo.timerRunning) { + if (pMac->roam.tlStatsReqInfo.periodicity) { + /* start timer */ + status = + qdf_mc_timer_start(&pMac->roam.tlStatsReqInfo. + hTlStatsTimer, + pMac->roam.tlStatsReqInfo. + periodicity); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOGE, + FL + ("csr_roam_tl_stats_timer_handler:cannot start TlStatsTimer timer")); + return; + } + pMac->roam.tlStatsReqInfo.timerRunning = true; + } + } +} + +void csr_roam_pe_stats_timer_handler(void *pv) +{ + tCsrPeStatsReqInfo *pPeStatsReqListEntry = (tCsrPeStatsReqInfo *) pv; + QDF_STATUS status; + tpAniSirGlobal pMac = pPeStatsReqListEntry->pMac; + QDF_STATUS qdf_status; + pPeStatsReqListEntry->timerRunning = false; + if (pPeStatsReqListEntry->timerStopFailed == true) { + /* If we entered here, meaning the timer could not be successfully */ + /* stopped in csr_roam_remove_entry_from_pe_stats_req_list(). So do it here. */ + + /* Destroy the timer */ + qdf_status = + qdf_mc_timer_destroy(&pPeStatsReqListEntry->hPeStatsTimer); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + sms_log(pMac, LOGE, + FL + ("csr_roam_pe_stats_timer_handler:failed to destroy hPeStatsTimer timer")); + } + /* Free the entry */ + qdf_mem_free(pPeStatsReqListEntry); + pPeStatsReqListEntry = NULL; + } else { + if (!pPeStatsReqListEntry->rspPending) { + status = + csr_send_mb_stats_req_msg(pMac, + pPeStatsReqListEntry-> + statsMask & ~(1 << + eCsrGlobalClassDStats), + pPeStatsReqListEntry->staId, + pPeStatsReqListEntry-> + sessionId); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOGE, + FL + ("csr_roam_pe_stats_timer_handler:failed to send down stats req to PE")); + } else { + pPeStatsReqListEntry->rspPending = true; + } + } + /* send down a req */ + if (pPeStatsReqListEntry->periodicity && + (QDF_TIMER_STATE_STOPPED == + qdf_mc_timer_get_current_state(&pPeStatsReqListEntry-> + hPeStatsTimer))) { + if (pPeStatsReqListEntry->periodicity < + pMac->roam.configParam. + statsReqPeriodicityInPS) { + pPeStatsReqListEntry->periodicity = + pMac->roam.configParam. + statsReqPeriodicityInPS; + } + /* start timer */ + qdf_status = + qdf_mc_timer_start(&pPeStatsReqListEntry-> + hPeStatsTimer, + pPeStatsReqListEntry-> + periodicity); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + sms_log(pMac, LOGE, + FL + ("csr_roam_pe_stats_timer_handler:cannot start hPeStatsTimer timer")); + return; + } + pPeStatsReqListEntry->timerRunning = true; + + } + + } +} + +void csr_roam_stats_client_timer_handler(void *pv) +{ + tCsrStatsClientReqInfo *pStaEntry = (tCsrStatsClientReqInfo *) pv; + if (QDF_TIMER_STATE_STOPPED == + qdf_mc_timer_get_current_state(&pStaEntry->timer)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO, + FL("roam stats client timer is stopped")); + } +} + +QDF_STATUS csr_send_mb_stats_req_msg(tpAniSirGlobal pMac, uint32_t statsMask, + uint8_t staId, uint8_t sessionId) +{ + tAniGetPEStatsReq *pMsg; + QDF_STATUS status = QDF_STATUS_SUCCESS; + pMsg = qdf_mem_malloc(sizeof(tAniGetPEStatsReq)); + if (NULL == pMsg) { + sms_log(pMac, LOGE, FL("Failed to allocate mem for stats req ")); + return QDF_STATUS_E_NOMEM; + } + /* need to initiate a stats request to PE */ + pMsg->msgType = eWNI_SME_GET_STATISTICS_REQ; + pMsg->msgLen = (uint16_t) sizeof(tAniGetPEStatsReq); + pMsg->staId = staId; + pMsg->statsMask = statsMask; + pMsg->sessionId = sessionId; + status = cds_send_mb_message_to_mac(pMsg); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOG1, FL("Failed to send down the stats req ")); + } + return status; +} + +/** + * csr_update_stats() - updates correct stats struct in mac_ctx + * @mac: mac global context + * @stats_type: stats type + * @sme_stats_rsp: stats rsp msg packet + * @stats: input stats data buffer to fill in mac_ctx struct + * @length: out param - stats length + * + * This function fills corresponding stats struct in mac_cts based on stats type + * passed + * + * Return: void + */ +static void +csr_update_stats(tpAniSirGlobal mac, uint8_t stats_type, + tAniGetPEStatsRsp *sme_stats_rsp, + uint8_t **stats, uint32_t *length) +{ + switch (stats_type) { + case eCsrSummaryStats: + sms_log(mac, LOG2, FL("summary stats")); + qdf_mem_copy((uint8_t *) &mac->roam.summaryStatsInfo, *stats, + sizeof(tCsrSummaryStatsInfo)); + *stats += sizeof(tCsrSummaryStatsInfo); + *length -= sizeof(tCsrSummaryStatsInfo); + break; + case eCsrGlobalClassAStats: + sms_log(mac, LOG2, FL("ClassA stats")); + qdf_mem_copy((uint8_t *) &mac->roam.classAStatsInfo, *stats, + sizeof(tCsrGlobalClassAStatsInfo)); + *stats += sizeof(tCsrGlobalClassAStatsInfo); + *length -= sizeof(tCsrGlobalClassAStatsInfo); + break; + case eCsrGlobalClassBStats: + sms_log(mac, LOG2, FL("ClassB stats")); + qdf_mem_copy((uint8_t *) &mac->roam.classBStatsInfo, *stats, + sizeof(tCsrGlobalClassBStatsInfo)); + *stats += sizeof(tCsrGlobalClassBStatsInfo); + *length -= sizeof(tCsrGlobalClassBStatsInfo); + break; + case eCsrGlobalClassCStats: + sms_log(mac, LOG2, FL("ClassC stats")); + qdf_mem_copy((uint8_t *) &mac->roam.classCStatsInfo, *stats, + sizeof(tCsrGlobalClassCStatsInfo)); + *stats += sizeof(tCsrGlobalClassCStatsInfo); + *length -= sizeof(tCsrGlobalClassCStatsInfo); + break; + case eCsrPerStaStats: + sms_log(mac, LOG2, FL("PerSta stats")); + if (CSR_MAX_STA > sme_stats_rsp->staId) { + qdf_mem_copy( + &mac->roam.perStaStatsInfo[sme_stats_rsp->staId], + *stats, sizeof(tCsrPerStaStatsInfo)); + } else { + sms_log(mac, LOGE, FL("out bound staId:%d. failed to copy PerSta stats"), + sme_stats_rsp->staId); + QDF_ASSERT(0); + } + *stats += sizeof(tCsrPerStaStatsInfo); + *length -= sizeof(tCsrPerStaStatsInfo); + break; + case csr_per_chain_rssi_stats: + sms_log(mac, LOG2, + FL("csrRoamStatsRspProcessor:Per Chain RSSI stats")); + qdf_mem_copy((uint8_t *)&mac->roam.per_chain_rssi_stats, + *stats, sizeof(struct csr_per_chain_rssi_stats_info)); + *stats += sizeof(struct csr_per_chain_rssi_stats_info); + *length -= sizeof(struct csr_per_chain_rssi_stats_info); + break; + default: + sms_log(mac, LOGW, FL("unknown stats type")); + break; + } +} + +/** + * csr_roam_stats_rsp_processor() - processes stats rsp msg + * @pMac mac global context + * @pSirMsg: incoming message + * + * Return: void + */ +void csr_roam_stats_rsp_processor(tpAniSirGlobal pMac, tSirSmeRsp *pSirMsg) +{ + tAniGetPEStatsRsp *pSmeStatsRsp; + tListElem *pEntry = NULL; + tCsrStatsClientReqInfo *pTempStaEntry = NULL; + tCsrPeStatsReqInfo *pPeStaEntry = NULL; + uint32_t tempMask = 0; + uint8_t counter = 0; + uint8_t *pStats = NULL; + uint32_t length = 0; + void *p_cds_gctx; + int8_t rssi = 0, snr = 0; + uint32_t *pRssi = NULL, *pSnr = NULL; + uint32_t linkCapacity; + pSmeStatsRsp = (tAniGetPEStatsRsp *) pSirMsg; + + if (pSmeStatsRsp->rc) { + sms_log(pMac, LOGW, FL("stats rsp from PE shows failure")); + goto post_update; + } + tempMask = pSmeStatsRsp->statsMask; + pStats = ((uint8_t *) &pSmeStatsRsp->statsMask) + + sizeof(pSmeStatsRsp->statsMask); + /* + * subtract all statistics from this length, and after processing the + * entire 'stat' part of the message, if the length is not zero, then + * rssi is piggy packed in this 'stats' message. + */ + length = pSmeStatsRsp->msgLen - sizeof(tAniGetPEStatsRsp); + /* new stats info from PE, fill up the stats strucutres in PMAC */ + while (tempMask) { + if (tempMask & 1) { + csr_update_stats(pMac, counter, pSmeStatsRsp, + &pStats, &length); + } + tempMask >>= 1; + counter++; + } + p_cds_gctx = cds_get_global_context(); + if (length != 0) { + pRssi = (uint32_t *) pStats; + rssi = (int8_t) *pRssi; + pStats += sizeof(uint32_t); + length -= sizeof(uint32_t); + } else { + /* If riva is not sending rssi, continue to use the hack */ + rssi = RSSI_HACK_BMPS; + } + + if (length != 0) { + linkCapacity = *(uint32_t *) pStats; + pStats += sizeof(uint32_t); + length -= sizeof(uint32_t); + } else { + linkCapacity = 0; + } + + if (length != 0) { + pSnr = (uint32_t *) pStats; + snr = (int8_t) *pSnr; + } else { + snr = SNR_HACK_BMPS; + } + +post_update: + /* make sure to update the pe stats req list */ + pEntry = csr_roam_find_in_pe_stats_req_list(pMac, pSmeStatsRsp->statsMask); + if (pEntry) { + pPeStaEntry = GET_BASE_ADDR(pEntry, tCsrPeStatsReqInfo, link); + pPeStaEntry->rspPending = false; + + } + /* check the one timer cases */ + pEntry = csr_roam_check_client_req_list(pMac, pSmeStatsRsp->statsMask); + if (pEntry) { + pTempStaEntry = + GET_BASE_ADDR(pEntry, tCsrStatsClientReqInfo, link); + if (pTempStaEntry->timerExpired) { + /* send up the stats report */ + csr_roam_report_statistics(pMac, pTempStaEntry->statsMask, + pTempStaEntry->callback, + pTempStaEntry->staId, + pTempStaEntry->pContext); + /* also remove from the client list */ + csr_roam_remove_stat_list_entry(pMac, pEntry); + pTempStaEntry = NULL; + } + } +} + +tListElem *csr_roam_find_in_pe_stats_req_list(tpAniSirGlobal pMac, uint32_t statsMask) +{ + tListElem *pEntry = NULL; + tCsrPeStatsReqInfo *pTempStaEntry = NULL; + pEntry = csr_ll_peek_head(&pMac->roam.peStatsReqList, LL_ACCESS_LOCK); + if (!pEntry) { + /* list empty */ + sms_log(pMac, LOG2, + "csr_roam_find_in_pe_stats_req_list: List empty, no request to PE"); + return NULL; + } + while (pEntry) { + pTempStaEntry = GET_BASE_ADDR(pEntry, tCsrPeStatsReqInfo, link); + if (pTempStaEntry->statsMask == statsMask) { + sms_log(pMac, LOG3, + "csr_roam_find_in_pe_stats_req_list: match found"); + break; + } + pEntry = + csr_ll_next(&pMac->roam.peStatsReqList, pEntry, + LL_ACCESS_NOLOCK); + } + return pEntry; +} + +static +tListElem *csr_roam_checkn_update_client_req_list(tpAniSirGlobal pMac, + tCsrStatsClientReqInfo *pStaEntry, + bool update) +{ + tListElem *pEntry; + tCsrStatsClientReqInfo *pTempStaEntry; + pEntry = csr_ll_peek_head(&pMac->roam.statsClientReqList, LL_ACCESS_LOCK); + if (!pEntry) { + /* list empty */ + sms_log(pMac, LOG2, + "csr_roam_checkn_update_client_req_list: List empty, no request from " + "upper layer client(s)"); + return NULL; + } + while (pEntry) { + pTempStaEntry = + GET_BASE_ADDR(pEntry, tCsrStatsClientReqInfo, link); + if ((pTempStaEntry->requesterId == pStaEntry->requesterId) + && (pTempStaEntry->statsMask == pStaEntry->statsMask)) { + sms_log(pMac, LOG3, + "csr_roam_checkn_update_client_req_list: match found"); + if (update) { + pTempStaEntry->periodicity = + pStaEntry->periodicity; + pTempStaEntry->callback = pStaEntry->callback; + pTempStaEntry->pContext = pStaEntry->pContext; + } + break; + } + pEntry = + csr_ll_next(&pMac->roam.statsClientReqList, pEntry, + LL_ACCESS_NOLOCK); + } + return pEntry; +} + +tListElem *csr_roam_check_client_req_list(tpAniSirGlobal pMac, uint32_t statsMask) +{ + tListElem *pEntry; + tCsrStatsClientReqInfo *pTempStaEntry; + pEntry = csr_ll_peek_head(&pMac->roam.statsClientReqList, LL_ACCESS_LOCK); + if (!pEntry) { + /* list empty */ + sms_log(pMac, LOG2, + "csr_roam_check_client_req_list: List empty, no request from " + "upper layer client(s)"); + return NULL; + } + while (pEntry) { + pTempStaEntry = + GET_BASE_ADDR(pEntry, tCsrStatsClientReqInfo, link); + if ((pTempStaEntry-> + statsMask & ~(1 << eCsrGlobalClassDStats)) == statsMask) { + sms_log(pMac, LOG3, + "csr_roam_check_client_req_list: match found"); + break; + } + pEntry = + csr_ll_next(&pMac->roam.statsClientReqList, pEntry, + LL_ACCESS_NOLOCK); + } + return pEntry; +} + +void csr_roam_vcc_trigger(tpAniSirGlobal pMac) +{ + eCsrRoamLinkQualityInd newVccLinkQuality; + uint32_t ul_mac_loss = 0; + uint32_t ul_mac_loss_trigger_threshold; + /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + /*------------------------------------------------------------------------- + Link quality is currently binary based on OBIWAN recommended triggers + Check for a change in link quality and notify client if necessary + -------------------------------------------------------------------------*/ + ul_mac_loss_trigger_threshold = + pMac->roam.configParam.vccUlMacLossThreshold; + if (0 == ul_mac_loss_trigger_threshold) { + QDF_ASSERT(ul_mac_loss_trigger_threshold != 0); + return; + } + sms_log(pMac, LOGW, "csr_roam_vcc_trigger: UL_MAC_LOSS_THRESHOLD is %d", + ul_mac_loss_trigger_threshold); + if (ul_mac_loss_trigger_threshold < ul_mac_loss) { + sms_log(pMac, LOGW, "csr_roam_vcc_trigger: link quality is POOR "); + newVccLinkQuality = eCSR_ROAM_LINK_QUAL_POOR_IND; + } else { + sms_log(pMac, LOGW, "csr_roam_vcc_trigger: link quality is GOOD"); + newVccLinkQuality = eCSR_ROAM_LINK_QUAL_GOOD_IND; + } + sms_log(pMac, LOGW, + "csr_roam_vcc_trigger: link qual : *** UL_MAC_LOSS %d *** ", + ul_mac_loss); + if (newVccLinkQuality != pMac->roam.vccLinkQuality) { + sms_log(pMac, LOGW, + "csr_roam_vcc_trigger: link quality changed: trigger necessary"); + if (NULL != pMac->roam.linkQualityIndInfo.callback) { + sms_log(pMac, LOGW, + "csr_roam_vcc_trigger: link quality indication %d", + newVccLinkQuality); + + /* we now invoke the callback once to notify client of initial value */ + pMac->roam.linkQualityIndInfo. + callback(newVccLinkQuality, + pMac->roam.linkQualityIndInfo.context); + /* event: EVENT_WLAN_VCC */ + } + } + pMac->roam.vccLinkQuality = newVccLinkQuality; + +} + +tCsrStatsClientReqInfo *csr_roam_insert_entry_into_list(tpAniSirGlobal pMac, + tDblLinkList *pStaList, + tCsrStatsClientReqInfo * + pStaEntry) +{ + tCsrStatsClientReqInfo *pNewStaEntry = NULL; + /* if same entity requested for same set of stats with different periodicity & */ + /* callback update it */ + if (NULL == csr_roam_checkn_update_client_req_list(pMac, pStaEntry, true)) { + + pNewStaEntry = qdf_mem_malloc(sizeof(tCsrStatsClientReqInfo)); + if (NULL == pNewStaEntry) { + sms_log(pMac, LOGW, + "csr_roam_insert_entry_into_list: couldn't allocate memory for the " + "entry"); + return NULL; + } + + pNewStaEntry->callback = pStaEntry->callback; + pNewStaEntry->pContext = pStaEntry->pContext; + pNewStaEntry->periodicity = pStaEntry->periodicity; + pNewStaEntry->requesterId = pStaEntry->requesterId; + pNewStaEntry->statsMask = pStaEntry->statsMask; + pNewStaEntry->pPeStaEntry = pStaEntry->pPeStaEntry; + pNewStaEntry->pMac = pStaEntry->pMac; + pNewStaEntry->staId = pStaEntry->staId; + pNewStaEntry->timerExpired = pStaEntry->timerExpired; + + csr_ll_insert_tail(pStaList, &pNewStaEntry->link, LL_ACCESS_LOCK); + } + return pNewStaEntry; +} + +static +tCsrPeStatsReqInfo *csr_roam_insert_entry_into_pe_stats_req_list(tpAniSirGlobal pMac, + tDblLinkList * + pStaList, + tCsrPeStatsReqInfo * + pStaEntry) +{ + tCsrPeStatsReqInfo *pNewStaEntry = NULL; + pNewStaEntry = qdf_mem_malloc(sizeof(tCsrPeStatsReqInfo)); + if (NULL == pNewStaEntry) { + sms_log(pMac, LOGW, + "csr_roam_insert_entry_into_pe_stats_req_list: couldn't allocate memory for the " + "entry"); + return NULL; + } + + pNewStaEntry->hPeStatsTimer = pStaEntry->hPeStatsTimer; + pNewStaEntry->numClient = pStaEntry->numClient; + pNewStaEntry->periodicity = pStaEntry->periodicity; + pNewStaEntry->statsMask = pStaEntry->statsMask; + pNewStaEntry->pMac = pStaEntry->pMac; + pNewStaEntry->staId = pStaEntry->staId; + pNewStaEntry->timerRunning = pStaEntry->timerRunning; + pNewStaEntry->rspPending = pStaEntry->rspPending; + + csr_ll_insert_tail(pStaList, &pNewStaEntry->link, LL_ACCESS_LOCK); + return pNewStaEntry; +} + +QDF_STATUS csr_get_rssi(tpAniSirGlobal pMac, + tCsrRssiCallback callback, + uint8_t staId, + struct qdf_mac_addr bssId, + int8_t lastRSSI, void *pContext, void *p_cds_context) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + cds_msg_t msg; + uint32_t sessionId; + + tAniGetRssiReq *pMsg; + sms_log(pMac, LOG2, FL("called")); + + status = csr_roam_get_session_id_from_bssid(pMac, &bssId, &sessionId); + if (!QDF_IS_STATUS_SUCCESS(status)) { + callback(lastRSSI, staId, pContext); + sms_log(pMac, LOGE, FL("Failed to get SessionId")); + return QDF_STATUS_E_FAILURE; + } + + pMsg = qdf_mem_malloc(sizeof(tAniGetRssiReq)); + if (NULL == pMsg) { + sms_log(pMac, LOGE, + " csr_get_rssi: failed to allocate mem for req "); + return QDF_STATUS_E_NOMEM; + } + + pMsg->msgType = eWNI_SME_GET_RSSI_REQ; + pMsg->msgLen = (uint16_t) sizeof(tAniGetRssiReq); + pMsg->sessionId = sessionId; + pMsg->staId = staId; + pMsg->rssiCallback = callback; + pMsg->pDevContext = pContext; + pMsg->p_cds_context = p_cds_context; + /* + * store RSSI at time of calling, so that if RSSI request cannot + * be sent to firmware, this value can be used to return immediately + */ + pMsg->lastRSSI = lastRSSI; + msg.type = eWNI_SME_GET_RSSI_REQ; + msg.bodyptr = pMsg; + msg.reserved = 0; + if (QDF_STATUS_SUCCESS != cds_mq_post_message(CDS_MQ_ID_SME, &msg)) { + sms_log(pMac, LOGE, " csr_get_rssi failed to post msg to self "); + qdf_mem_free((void *)pMsg); + status = QDF_STATUS_E_FAILURE; + } + sms_log(pMac, LOG2, FL("returned")); + return status; +} + +QDF_STATUS csr_get_snr(tpAniSirGlobal pMac, + tCsrSnrCallback callback, + uint8_t staId, struct qdf_mac_addr bssId, void *pContext) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + cds_msg_t msg; + uint32_t sessionId; + + tAniGetSnrReq *pMsg; + + sms_log(pMac, LOG2, FL("called")); + + pMsg = (tAniGetSnrReq *) qdf_mem_malloc(sizeof(tAniGetSnrReq)); + if (NULL == pMsg) { + sms_log(pMac, LOGE, "%s: failed to allocate mem for req", + __func__); + return QDF_STATUS_E_NOMEM; + } + + status = csr_roam_get_session_id_from_bssid(pMac, &bssId, &sessionId); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sme_err("Failed to get SessionId"); + return QDF_STATUS_E_FAILURE; + } + + pMsg->msgType = eWNI_SME_GET_SNR_REQ; + pMsg->msgLen = (uint16_t) sizeof(tAniGetSnrReq); + pMsg->sessionId = sessionId; + pMsg->staId = staId; + pMsg->snrCallback = callback; + pMsg->pDevContext = pContext; + msg.type = eWNI_SME_GET_SNR_REQ; + msg.bodyptr = pMsg; + msg.reserved = 0; + + if (QDF_STATUS_SUCCESS != cds_mq_post_message(CDS_MQ_ID_SME, &msg)) { + sms_log(pMac, LOGE, "%s failed to post msg to self", __func__); + qdf_mem_free((void *)pMsg); + status = QDF_STATUS_E_FAILURE; + } + + sms_log(pMac, LOG2, FL("returned")); + return status; +} + +/** + * csr_deregister_client_request() - deregisters a get stats request + * @mac_ctx: mac global context + * @sta_entry: stats request entry + * + * Return: status of operation + */ +static QDF_STATUS +csr_deregister_client_request(tpAniSirGlobal mac_ctx, + tCsrStatsClientReqInfo *sta_entry) +{ + QDF_STATUS status; + tListElem *entry = NULL; + tCsrStatsClientReqInfo *ptr_sta_entry = NULL; + + entry = csr_roam_checkn_update_client_req_list(mac_ctx, sta_entry, + false); + if (!entry) { + sms_log(mac_ctx, LOGW, + FL("callback is empty in the request & couldn't find any existing request in statsClientReqList")); + return QDF_STATUS_E_FAILURE; + } + /* clean up & return */ + ptr_sta_entry = GET_BASE_ADDR(entry, tCsrStatsClientReqInfo, link); + if (NULL != ptr_sta_entry->pPeStaEntry) { + ptr_sta_entry->pPeStaEntry->numClient--; + /* check if we need to delete the entry from peStatsReqList */ + if (!ptr_sta_entry->pPeStaEntry->numClient) + csr_roam_remove_entry_from_pe_stats_req_list(mac_ctx, + ptr_sta_entry->pPeStaEntry); + } + /* check if we need to stop the tl stats timer too */ + mac_ctx->roam.tlStatsReqInfo.numClient--; + if (!mac_ctx->roam.tlStatsReqInfo.numClient) { + if (mac_ctx->roam.tlStatsReqInfo.timerRunning) { + status = qdf_mc_timer_stop( + &mac_ctx->roam.tlStatsReqInfo.hTlStatsTimer); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sms_log(mac_ctx, LOGE, + FL("cannot stop TlStatsTimer timer")); + return status; + } + } + mac_ctx->roam.tlStatsReqInfo.periodicity = 0; + mac_ctx->roam.tlStatsReqInfo.timerRunning = false; + } + qdf_mc_timer_stop(&ptr_sta_entry->timer); + /* Destroy the qdf timer... */ + status = qdf_mc_timer_destroy(&ptr_sta_entry->timer); + if (!QDF_IS_STATUS_SUCCESS(status)) + sms_log(mac_ctx, LOGE, + FL("failed to destroy Client req timer")); + + csr_roam_remove_stat_list_entry(mac_ctx, entry); + return QDF_STATUS_SUCCESS; +} + +/** + * csr_insert_stats_request_to_list() - inserts request to existing list + * @mac_ctx: mac global context + * @sta_entry: stats request entry + * @periodicity: periodicity of stats + * + * Return: status of operation + */ +static QDF_STATUS +csr_insert_stats_request_to_list(tpAniSirGlobal mac_ctx, + tCsrStatsClientReqInfo *sta_entry, + uint32_t periodicity) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tCsrStatsClientReqInfo *ptr_sta_entry = csr_roam_insert_entry_into_list( + mac_ctx, &mac_ctx->roam.statsClientReqList, + sta_entry); + if (!ptr_sta_entry) { + sms_log(mac_ctx, LOGW, + FL("Failed to insert req in statsClientReqList")); + return QDF_STATUS_E_FAILURE; + } + /* Init & start timer if needed */ + ptr_sta_entry->periodicity = periodicity; + if (ptr_sta_entry->periodicity) { + status = qdf_mc_timer_init(&ptr_sta_entry->timer, + QDF_TIMER_TYPE_SW, + csr_roam_stats_client_timer_handler, + ptr_sta_entry); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sms_log(mac_ctx, LOGE, + FL("cannot init StatsClient timer")); + return QDF_STATUS_E_FAILURE; + } + status = qdf_mc_timer_start(&ptr_sta_entry->timer, + ptr_sta_entry->periodicity); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sms_log(mac_ctx, LOGE, + FL("cannot start StatsClient timer")); + return QDF_STATUS_E_FAILURE; + } + } + return status; +} + +/** + * csr_get_statistics_from_tl() - fetch stats from tl layer + * @mac_ctx: mac global context + * @cache: indicate if cached stats are required + * @staId: station id + * @periodicity: periodicity of stats + * + * Return: status of operation + */ +static QDF_STATUS +csr_get_statistics_from_tl(tpAniSirGlobal mac_ctx, + bool cache, + uint8_t staId, + uint32_t periodicity) +{ + QDF_STATUS status; + + if (cache && mac_ctx->roam.tlStatsReqInfo.numClient) { + sms_log(mac_ctx, LOGE, FL("Looking for cached stats from TL")); + mac_ctx->roam.tlStatsReqInfo.numClient++; + return QDF_STATUS_SUCCESS; + } + + /* update periodicity */ + if (mac_ctx->roam.tlStatsReqInfo.periodicity) + mac_ctx->roam.tlStatsReqInfo.periodicity = + QDF_MIN(periodicity, + mac_ctx->roam.tlStatsReqInfo.periodicity); + else + mac_ctx->roam.tlStatsReqInfo.periodicity = periodicity; + + if (mac_ctx->roam.tlStatsReqInfo.periodicity + < CSR_MIN_TL_STAT_QUERY_PERIOD) { + mac_ctx->roam.tlStatsReqInfo.periodicity = + CSR_MIN_TL_STAT_QUERY_PERIOD; + } + + if (!mac_ctx->roam.tlStatsReqInfo.timerRunning) { + + if (mac_ctx->roam.tlStatsReqInfo.periodicity) { + /* start timer */ + status = qdf_mc_timer_start( + &mac_ctx->roam.tlStatsReqInfo.hTlStatsTimer, + mac_ctx->roam.tlStatsReqInfo.periodicity); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sms_log(mac_ctx, LOGE, + FL("cannot start TlStatsTimer timer")); + return QDF_STATUS_E_FAILURE; + } + mac_ctx->roam.tlStatsReqInfo.timerRunning = true; + } + } + mac_ctx->roam.tlStatsReqInfo.numClient++; + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS csr_get_statistics(tpAniSirGlobal pMac, + eCsrStatsRequesterType requesterId, + uint32_t statsMask, + tCsrStatsCallback callback, + uint32_t periodicity, + bool cache, + uint8_t staId, + void *pContext, + uint8_t sessionId) +{ + tCsrStatsClientReqInfo staEntry; + tCsrPeStatsReqInfo *pPeStaEntry = NULL; + bool found = false; + QDF_STATUS status = QDF_STATUS_SUCCESS; + bool insertInClientList = false; + uint32_t temp_mask = 0; + + if (csr_is_all_session_disconnected(pMac)) + return QDF_STATUS_E_FAILURE; + + if (csr_neighbor_middle_of_roaming(pMac, sessionId)) { + sms_log(pMac, LOG1, FL("in the middle of roaming states")); + return QDF_STATUS_E_FAILURE; + } + + if ((!statsMask) && (!callback)) { + sms_log(pMac, LOGW, + FL("statsMask & callback empty in the request")); + return QDF_STATUS_E_FAILURE; + } + /* for the search list method for deregister */ + staEntry.requesterId = requesterId; + staEntry.statsMask = statsMask; + /* requester wants to deregister or just an error */ + if ((statsMask) && (!callback)) + return csr_deregister_client_request(pMac, &staEntry); + + if (cache && !periodicity) { + /* return the cached stats */ + csr_roam_report_statistics(pMac, statsMask, callback, staId, + pContext); + return QDF_STATUS_SUCCESS; + } + /* add the request in the client req list */ + staEntry.callback = callback; + staEntry.pContext = pContext; + staEntry.periodicity = periodicity; + staEntry.pPeStaEntry = NULL; + staEntry.staId = staId; + staEntry.pMac = pMac; + staEntry.timerExpired = false; + staEntry.sessionId = sessionId; + + /* if periodic report requested with non cached result from PE/TL */ + if (periodicity) { + /* if looking for stats from PE */ + temp_mask = statsMask & ~(1 << eCsrGlobalClassDStats); + if (temp_mask) { + /* check if same req made already & waiting for rsp */ + pPeStaEntry = csr_roam_check_pe_stats_req_list(pMac, + temp_mask, periodicity, &found, + staId, sessionId); + if (!pPeStaEntry) + /* bail out, maxed out on num of req for PE */ + return QDF_STATUS_E_FAILURE; + else + staEntry.pPeStaEntry = pPeStaEntry; + } + /* + * request stats from TL rightaway if requested by client, + * update tlStatsReqInfo if needed + */ + temp_mask = statsMask & (1 << eCsrGlobalClassDStats); + if (temp_mask) { + status = csr_get_statistics_from_tl(pMac, cache, staId, + periodicity); + if (!QDF_IS_STATUS_SUCCESS(status)) + return status; + } + insertInClientList = true; + } + /* if one time report requested with non cached result from PE/TL */ + else if (!cache && !periodicity) { + temp_mask = statsMask & ~(1 << eCsrGlobalClassDStats); + if (temp_mask) { + /* send down a req */ + status = csr_send_mb_stats_req_msg(pMac, + temp_mask, staId, sessionId); + if (!QDF_IS_STATUS_SUCCESS(status)) + sms_log(pMac, LOGE, + FL("failed to send down stats req")); + /* + * so that when the stats rsp comes back from PE we + * respond to upper layer right away + */ + staEntry.timerExpired = true; + insertInClientList = true; + } + /* if looking for stats from TL only */ + if (!insertInClientList) { + /* return the stats */ + csr_roam_report_statistics(pMac, statsMask, callback, + staId, pContext); + return QDF_STATUS_SUCCESS; + } + } + if (insertInClientList) + return csr_insert_stats_request_to_list(pMac, &staEntry, + periodicity); + + return QDF_STATUS_SUCCESS; +} + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +/** + * csr_roam_set_key_mgmt_offload() - enable/disable key mgmt offload + * @mac_ctx: mac context. + * @session_id: Session Identifier + * @roam_key_mgmt_offload_enabled: key mgmt enable/disable flag + * @pmkid_modes: PMKID modes of PMKSA caching and OKC + * + * Return: QDF_STATUS_SUCCESS - CSR updated config successfully. + * Other status means CSR is failed to update. + */ + +QDF_STATUS csr_roam_set_key_mgmt_offload(tpAniSirGlobal mac_ctx, + uint32_t session_id, + bool roam_key_mgmt_offload_enabled, + struct pmkid_mode_bits *pmkid_modes) +{ + tCsrRoamSession *session = CSR_GET_SESSION(mac_ctx, session_id); + if (!session) { + sms_log(mac_ctx, LOGE, FL("session %d not found"), session_id); + return QDF_STATUS_E_FAILURE; + } + session->RoamKeyMgmtOffloadEnabled = roam_key_mgmt_offload_enabled; + session->pmkid_modes.fw_okc = pmkid_modes->fw_okc; + session->pmkid_modes.fw_pmksa_cache = pmkid_modes->fw_pmksa_cache; + return QDF_STATUS_SUCCESS; +} + +/** + * csr_update_roam_scan_offload_request() - updates req msg with roam offload + * paramters + * @pMac: mac global context + * @req_buf: out param, roam offload scan request packet + * @session: roam session + * + * Return: void + */ +static void +csr_update_roam_scan_offload_request(tpAniSirGlobal mac_ctx, + tSirRoamOffloadScanReq *req_buf, + tCsrRoamSession *session) +{ + qdf_mem_copy(req_buf->PSK_PMK, session->psk_pmk, + sizeof(req_buf->PSK_PMK)); + req_buf->pmk_len = session->pmk_len; + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "LFR3: PMK Length = %d", req_buf->pmk_len); + req_buf->R0KH_ID_Length = session->ftSmeContext.r0kh_id_len; + qdf_mem_copy(req_buf->R0KH_ID, + session->ftSmeContext.r0kh_id, + req_buf->R0KH_ID_Length); + req_buf->Prefer5GHz = mac_ctx->roam.configParam.nRoamPrefer5GHz; + req_buf->RoamRssiCatGap = mac_ctx->roam.configParam.bCatRssiOffset; + req_buf->Select5GHzMargin = mac_ctx->roam.configParam.nSelect5GHzMargin; + if (wlan_cfg_get_int(mac_ctx, WNI_CFG_REASSOCIATION_FAILURE_TIMEOUT, + (uint32_t *) &req_buf->ReassocFailureTimeout) + != eSIR_SUCCESS) { + sms_log(mac_ctx, LOGE, + FL("could not retrieve ReassocFailureTimeout value")); + req_buf->ReassocFailureTimeout = + DEFAULT_REASSOC_FAILURE_TIMEOUT; + } +#ifdef FEATURE_WLAN_ESE + if (csr_is_auth_type_ese(req_buf->ConnectedNetwork.authentication)) { + qdf_mem_copy(req_buf->KRK, session->eseCckmInfo.krk, + SIR_KRK_KEY_LEN); + qdf_mem_copy(req_buf->BTK, session->eseCckmInfo.btk, + SIR_BTK_KEY_LEN); + } +#endif + req_buf->AcUapsd.acbe_uapsd = SIR_UAPSD_GET(ACBE, session->uapsd_mask); + req_buf->AcUapsd.acbk_uapsd = SIR_UAPSD_GET(ACBK, session->uapsd_mask); + req_buf->AcUapsd.acvi_uapsd = SIR_UAPSD_GET(ACVI, session->uapsd_mask); + req_buf->AcUapsd.acvo_uapsd = SIR_UAPSD_GET(ACVO, session->uapsd_mask); +} +#endif /* WLAN_FEATURE_ROAM_OFFLOAD */ + +#if defined(WLAN_FEATURE_HOST_ROAM) || defined(WLAN_FEATURE_ROAM_OFFLOAD) +/** + * csr_check_band_channel_match() - check if passed band and channel match + * paramters + * @band: band to match with channel + * @channel: channel to match with band + * + * Return: bool if match else false + */ +static bool +csr_check_band_channel_match(eCsrBand band, uint8_t channel) +{ + if (eCSR_BAND_ALL == band) + return true; + + if (eCSR_BAND_24 == band && CDS_IS_CHANNEL_24GHZ(channel)) + return true; + + if (eCSR_BAND_5G == band && CDS_IS_CHANNEL_5GHZ(channel)) + return true; + + return false; +} + +/** + * csr_fetch_ch_lst_from_ini() - fetch channel list from ini and update req msg + * paramters + * @mac_ctx: global mac ctx + * @roam_info: roam info struct + * @req_buf: out param, roam offload scan request packet + * + * Return: result of operation + */ +static QDF_STATUS +csr_fetch_ch_lst_from_ini(tpAniSirGlobal mac_ctx, + tpCsrNeighborRoamControlInfo roam_info, + tSirRoamOffloadScanReq *req_buf) +{ + eCsrBand band; + uint8_t i = 0; + uint8_t num_channels = 0; + uint8_t *ch_lst = roam_info->cfgParams.channelInfo.ChannelList; + uint16_t unsafe_chan[NUM_CHANNELS]; + uint16_t unsafe_chan_cnt = 0; + uint16_t cnt = 0; + bool is_unsafe_chan; + qdf_device_t qdf_ctx = cds_get_context(QDF_MODULE_ID_QDF_DEVICE); + + if (!qdf_ctx) { + cds_err("qdf_ctx is NULL"); + return QDF_STATUS_E_FAILURE; + } + + pld_get_wlan_unsafe_channel(qdf_ctx->dev, unsafe_chan, + &unsafe_chan_cnt, + sizeof(unsafe_chan)); + + /* + * The INI channels need to be filtered with respect to the current band + * that is supported. + */ + band = mac_ctx->roam.configParam.bandCapability; + if ((eCSR_BAND_24 != band) && (eCSR_BAND_5G != band) + && (eCSR_BAND_ALL != band)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Invalid band(%d), roam scan offload req aborted"), + band); + return QDF_STATUS_E_FAILURE; + } + + for (i = 0; i < roam_info->cfgParams.channelInfo.numOfChannels; i++) { + if (!csr_check_band_channel_match(band, *ch_lst)) + continue; + /* Allow DFS channels only if the DFS roaming is enabled */ + if ((!mac_ctx->roam.configParam.allowDFSChannelRoam || + (mac_ctx->roam.configParam.sta_roam_policy.dfs_mode == + CSR_STA_ROAM_POLICY_DFS_DISABLED)) && + (CDS_IS_DFS_CH(*ch_lst))) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO, + FL("ignoring dfs channel %d"), *ch_lst); + ch_lst++; + continue; + } + + if (mac_ctx->roam.configParam.sta_roam_policy. + skip_unsafe_channels && + unsafe_chan_cnt) { + is_unsafe_chan = false; + for (cnt = 0; cnt < unsafe_chan_cnt; cnt++) { + if (unsafe_chan[cnt] == *ch_lst) { + is_unsafe_chan = true; + break; + } + } + if (is_unsafe_chan) { + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_INFO, + FL("ignoring unsafe channel %d"), + *ch_lst); + ch_lst++; + continue; + } + } + req_buf->ConnectedNetwork.ChannelCache[num_channels++] = + *ch_lst; + ch_lst++; + + } + req_buf->ConnectedNetwork.ChannelCount = num_channels; + req_buf->ChannelCacheType = CHANNEL_LIST_STATIC; + return QDF_STATUS_SUCCESS; +} + +/** + * csr_fetch_ch_lst_from_occupied_lst() - fetch channel list from occupied list + * and update req msg + * paramters + * @mac_ctx: global mac ctx + * @session_id: session id + * @reason: reason to roam + * @req_buf: out param, roam offload scan request packet + * @roam_info: roam info struct + * + * Return: void + */ +static void +csr_fetch_ch_lst_from_occupied_lst(tpAniSirGlobal mac_ctx, + uint8_t session_id, + uint8_t reason, + tSirRoamOffloadScanReq *req_buf, + tpCsrNeighborRoamControlInfo roam_info) +{ + uint8_t i = 0; + uint8_t num_channels = 0; + uint8_t *ch_lst = + mac_ctx->scan.occupiedChannels[session_id].channelList; + uint16_t unsafe_chan[NUM_CHANNELS]; + uint16_t unsafe_chan_cnt = 0; + uint16_t cnt = 0; + bool is_unsafe_chan; + qdf_device_t qdf_ctx = cds_get_context(QDF_MODULE_ID_QDF_DEVICE); + + if (!qdf_ctx) { + cds_err("qdf_ctx is NULL"); + return; + } + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "Num of channels before filtering=%d", + mac_ctx->scan.occupiedChannels[session_id].numChannels); + pld_get_wlan_unsafe_channel(qdf_ctx->dev, unsafe_chan, + &unsafe_chan_cnt, + sizeof(unsafe_chan)); + for (i = 0; i < mac_ctx->scan.occupiedChannels[session_id].numChannels; + i++) { + if ((!mac_ctx->roam.configParam.allowDFSChannelRoam || + (mac_ctx->roam.configParam.sta_roam_policy.dfs_mode == + CSR_STA_ROAM_POLICY_DFS_DISABLED)) && + (CDS_IS_DFS_CH(*ch_lst))) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO, + FL("ignoring dfs channel %d"), *ch_lst); + ch_lst++; + continue; + } + + if (mac_ctx->roam.configParam.sta_roam_policy. + skip_unsafe_channels && + unsafe_chan_cnt) { + is_unsafe_chan = false; + for (cnt = 0; cnt < unsafe_chan_cnt; cnt++) { + if (unsafe_chan[cnt] == *ch_lst) { + is_unsafe_chan = true; + break; + } + } + if (is_unsafe_chan) { + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_INFO, + FL("ignoring unsafe channel %d"), + *ch_lst); + ch_lst++; + continue; + } + } + req_buf->ConnectedNetwork.ChannelCache[num_channels++] = + *ch_lst; + if (*ch_lst) + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "DFSRoam=%d, ChnlState=%d, Chnl=%d, num_ch=%d", + mac_ctx->roam.configParam.allowDFSChannelRoam, + cds_get_channel_state(*ch_lst), *ch_lst, + num_channels); + ch_lst++; + } + req_buf->ConnectedNetwork.ChannelCount = num_channels; + /* + * If the profile changes as to what it was earlier, inform the FW + * through FLUSH as ChannelCacheType in which case, the FW will flush + * the occupied channels for the earlier profile and try to learn them + * afresh + */ + if (reason == REASON_FLUSH_CHANNEL_LIST) + req_buf->ChannelCacheType = CHANNEL_LIST_DYNAMIC_FLUSH; + else { + if (csr_neighbor_roam_is_new_connected_profile(mac_ctx, + session_id)) + req_buf->ChannelCacheType = CHANNEL_LIST_DYNAMIC_INIT; + else + req_buf->ChannelCacheType = CHANNEL_LIST_DYNAMIC_UPDATE; + } +} + +/** + * csr_fetch_valid_ch_lst() - fetch channel list from valid channel list and + * update req msg + * paramters + * @mac_ctx: global mac ctx + * @req_buf: out param, roam offload scan request packet + * + * Return: void + */ +static QDF_STATUS +csr_fetch_valid_ch_lst(tpAniSirGlobal mac_ctx, + tSirRoamOffloadScanReq *req_buf) +{ + QDF_STATUS status; + uint32_t host_channels = 0; + uint8_t *ch_lst = NULL; + uint8_t i = 0, num_channels = 0; + uint16_t unsafe_chan[NUM_CHANNELS]; + uint16_t unsafe_chan_cnt = 0; + uint16_t cnt = 0; + bool is_unsafe_chan; + qdf_device_t qdf_ctx = cds_get_context(QDF_MODULE_ID_QDF_DEVICE); + + if (!qdf_ctx) { + cds_err("qdf_ctx is NULL"); + return QDF_STATUS_E_FAILURE; + } + + pld_get_wlan_unsafe_channel(qdf_ctx->dev, unsafe_chan, + &unsafe_chan_cnt, + sizeof(unsafe_chan)); + + host_channels = sizeof(mac_ctx->roam.validChannelList); + status = csr_get_cfg_valid_channels(mac_ctx, + mac_ctx->roam.validChannelList, + &host_channels); + if (!QDF_IS_STATUS_SUCCESS(status)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Failed to get the valid channel list")); + return status; + } + ch_lst = mac_ctx->roam.validChannelList; + mac_ctx->roam.numValidChannels = host_channels; + for (i = 0; i < mac_ctx->roam.numValidChannels; i++) { + ch_lst++; + if ((!mac_ctx->roam.configParam.allowDFSChannelRoam || + (mac_ctx->roam.configParam.sta_roam_policy.dfs_mode == + CSR_STA_ROAM_POLICY_DFS_DISABLED)) && + (CDS_IS_DFS_CH(*ch_lst))) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO, + FL("ignoring dfs channel %d"), *ch_lst); + ch_lst++; + continue; + } + + if (mac_ctx->roam.configParam. + sta_roam_policy.skip_unsafe_channels && + unsafe_chan_cnt) { + is_unsafe_chan = false; + for (cnt = 0; cnt < unsafe_chan_cnt; cnt++) { + if (unsafe_chan[cnt] == *ch_lst) { + is_unsafe_chan = true; + break; + } + } + if (is_unsafe_chan) { + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_INFO, + FL("ignoring unsafe channel %d"), + *ch_lst); + ch_lst++; + continue; + } + } + req_buf->ConnectedNetwork.ChannelCache[num_channels++] = + *ch_lst; + ch_lst++; + } + req_buf->ValidChannelCount = num_channels; + return status; +} + +/** + * csr_create_roam_scan_offload_request() - init roam offload scan request + * + * paramters + * @mac_ctx: global mac ctx + * @command: roam scan offload command input + * @session_id: session id + * @reason: reason to roam + * @session: roam session + * @roam_info: roam info struct + * + * Return: roam offload scan request packet buffer + */ +static tSirRoamOffloadScanReq * +csr_create_roam_scan_offload_request(tpAniSirGlobal mac_ctx, + uint8_t command, + uint8_t session_id, + uint8_t reason, + tCsrRoamSession *session, + tpCsrNeighborRoamControlInfo roam_info) +{ + QDF_STATUS status; + uint8_t i, j, dot11_mode; + bool ese_neighbor_list_recvd = false; + uint8_t ch_cache_str[128] = { 0 }; + tSirRoamOffloadScanReq *req_buf = NULL; + tpCsrChannelInfo curr_ch_lst_info = + &roam_info->roamChannelInfo.currentChannelListInfo; +#ifdef FEATURE_WLAN_ESE + /* + * this flag will be true if connection is ESE and no neighbor + * list received or if the connection is not ESE + */ + ese_neighbor_list_recvd = ((roam_info->isESEAssoc) + && (roam_info->roamChannelInfo.IAPPNeighborListReceived + == false)) + || (roam_info->isESEAssoc == false); +#endif /* FEATURE_WLAN_ESE */ + + req_buf = qdf_mem_malloc(sizeof(tSirRoamOffloadScanReq)); + if (NULL == req_buf) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Mem alloc for roam scan offload req failed.")); + return NULL; + } + req_buf->Command = command; + /* + * If command is STOP, then pass down ScanOffloadEnabled as Zero. This + * will handle the case of host driver reloads, but Riva still up and + * running + */ + if (command == ROAM_SCAN_OFFLOAD_STOP) { + /* + * clear the roaming parameters that are per connection. + * For a new connection, they have to be programmed again. + */ + if (csr_neighbor_middle_of_roaming((tHalHandle)mac_ctx, + session_id)) + req_buf->middle_of_roaming = 1; + else + csr_roam_reset_roam_params(mac_ctx); + req_buf->RoamScanOffloadEnabled = 0; + } else { + req_buf->RoamScanOffloadEnabled = + mac_ctx->roam.configParam.isRoamOffloadScanEnabled; + } + qdf_mem_copy(req_buf->ConnectedNetwork.currAPbssid, + roam_info->currAPbssid.bytes, sizeof(struct qdf_mac_addr)); + req_buf->ConnectedNetwork.ssId.length = + mac_ctx->roam.roamSession[session_id]. + connectedProfile.SSID.length; + qdf_mem_copy(req_buf->ConnectedNetwork.ssId.ssId, + mac_ctx->roam.roamSession[session_id]. + connectedProfile.SSID.ssId, + req_buf->ConnectedNetwork.ssId.length); + req_buf->ConnectedNetwork.authentication = + mac_ctx->roam.roamSession[session_id].connectedProfile.AuthType; + req_buf->ConnectedNetwork.encryption = + mac_ctx->roam.roamSession[session_id]. + connectedProfile.EncryptionType; + req_buf->ConnectedNetwork.mcencryption = + mac_ctx->roam.roamSession[session_id]. + connectedProfile.mcEncryptionType; +#ifdef WLAN_FEATURE_11W + req_buf->ConnectedNetwork.mfp_enabled = + mac_ctx->roam.roamSession[session_id].connectedProfile.MFPEnabled; +#endif + req_buf->delay_before_vdev_stop = + roam_info->cfgParams.delay_before_vdev_stop; + req_buf->OpportunisticScanThresholdDiff = + roam_info->cfgParams.nOpportunisticThresholdDiff; + req_buf->RoamRescanRssiDiff = + roam_info->cfgParams.nRoamRescanRssiDiff; + req_buf->RoamRssiDiff = mac_ctx->roam.configParam.RoamRssiDiff; + req_buf->reason = reason; + req_buf->NeighborScanTimerPeriod = + roam_info->cfgParams.neighborScanPeriod; + req_buf->NeighborRoamScanRefreshPeriod = + roam_info->cfgParams.neighborResultsRefreshPeriod; + req_buf->NeighborScanChannelMinTime = + roam_info->cfgParams.minChannelScanTime; + req_buf->NeighborScanChannelMaxTime = + roam_info->cfgParams.maxChannelScanTime; + req_buf->EmptyRefreshScanPeriod = + roam_info->cfgParams.emptyScanRefreshPeriod; + req_buf->RoamBmissFirstBcnt = + roam_info->cfgParams.nRoamBmissFirstBcnt; + req_buf->RoamBmissFinalBcnt = + roam_info->cfgParams.nRoamBmissFinalBcnt; + req_buf->RoamBeaconRssiWeight = + roam_info->cfgParams.nRoamBeaconRssiWeight; + /* MAWC feature */ + req_buf->MAWCEnabled = mac_ctx->roam.configParam.MAWCEnabled; +#ifdef FEATURE_WLAN_ESE + req_buf->IsESEAssoc = + csr_roam_is_ese_assoc(mac_ctx, session_id) && + ((req_buf->ConnectedNetwork.authentication == + eCSR_AUTH_TYPE_OPEN_SYSTEM) || + (csr_is_auth_type_ese(req_buf-> + ConnectedNetwork.authentication))); + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + FL("IsEseAssoc=%d middle of roaming %d ese_neighbor_list_recvd %d cur no of chan %d"), + req_buf->IsESEAssoc, + req_buf->middle_of_roaming, + ese_neighbor_list_recvd, + curr_ch_lst_info->numOfChannels); +#endif + if (ese_neighbor_list_recvd || curr_ch_lst_info->numOfChannels == 0) { + /* + * Retrieve the Channel Cache either from ini or from the + * occupied channels list. Give Preference to INI Channels + */ + if (roam_info->cfgParams.channelInfo.numOfChannels) { + status = csr_fetch_ch_lst_from_ini(mac_ctx, roam_info, + req_buf); + if (!QDF_IS_STATUS_SUCCESS(status)) { + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_DEBUG, + FL("Fetch channel list from ini failed")); + qdf_mem_free(req_buf); + return NULL; + } + } else { + csr_fetch_ch_lst_from_occupied_lst(mac_ctx, session_id, + reason, req_buf, roam_info); + } + } +#ifdef FEATURE_WLAN_ESE + else { + /* + * If ESE is enabled, and a neighbor Report is received,then + * Ignore the INI Channels or the Occupied Channel List. + * Consider the channels in the neighbor list sent by the ESE AP + */ + csr_fetch_ch_lst_from_received_list(mac_ctx, roam_info, + curr_ch_lst_info, req_buf); + } +#endif + + if (req_buf->ConnectedNetwork.ChannelCount == 0) { + /* Maintain the Valid Channels List */ + status = csr_fetch_valid_ch_lst(mac_ctx, req_buf); + if (!QDF_IS_STATUS_SUCCESS(status)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "Fetch channel list fail"); + qdf_mem_free(req_buf); + return NULL; + } + } + + for (i = 0, j = 0; i < req_buf->ConnectedNetwork.ChannelCount; i++) { + if (j < sizeof(ch_cache_str)) { + j += snprintf(ch_cache_str + j, + sizeof(ch_cache_str) - j, " %d", + req_buf->ConnectedNetwork. + ChannelCache[i]); + } else + break; + } + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + FL("ChnlCacheType:%d, No of Chnls:%d,Channels: %s"), + req_buf->ChannelCacheType, + req_buf->ConnectedNetwork.ChannelCount, ch_cache_str); + + req_buf->MDID.mdiePresent = + mac_ctx->roam.roamSession[session_id]. + connectedProfile.MDID.mdiePresent; + req_buf->MDID.mobilityDomain = + mac_ctx->roam.roamSession[session_id]. + connectedProfile.MDID.mobilityDomain; + req_buf->sessionId = session_id; + req_buf->nProbes = mac_ctx->roam.configParam.nProbes; + req_buf->HomeAwayTime = mac_ctx->roam.configParam.nRoamScanHomeAwayTime; + + /* + * Home Away Time should be at least equal to (MaxDwell time + (2*RFS)), + * where RFS is the RF Switching time. It is twice RFS to consider the + * time to go off channel and return to the home channel. + */ + if (req_buf->HomeAwayTime < (req_buf->NeighborScanChannelMaxTime + + (2 * CSR_ROAM_SCAN_CHANNEL_SWITCH_TIME))) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_WARN, + FL("Invalid config, Home away time(%d) is less than (twice RF switching time + channel max time)(%d). Hence enforcing home away time to disable (0)"), + req_buf->HomeAwayTime, + (req_buf->NeighborScanChannelMaxTime + + (2 * CSR_ROAM_SCAN_CHANNEL_SWITCH_TIME))); + req_buf->HomeAwayTime = 0; + } + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + FL("HomeAwayTime:%d"), req_buf->HomeAwayTime); + + /*Prepare a probe request for 2.4GHz band and one for 5GHz band */ + dot11_mode = (uint8_t) csr_translate_to_wni_cfg_dot11_mode(mac_ctx, + csr_find_best_phy_mode(mac_ctx, + mac_ctx->roam.configParam.phyMode)); + req_buf->allowDFSChannelRoam = + mac_ctx->roam.configParam.allowDFSChannelRoam; + req_buf->early_stop_scan_enable = + mac_ctx->roam.configParam.early_stop_scan_enable; + req_buf->early_stop_scan_min_threshold = + mac_ctx->roam.configParam.early_stop_scan_min_threshold; + req_buf->early_stop_scan_max_threshold = + mac_ctx->roam.configParam.early_stop_scan_max_threshold; + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + FL("EarlyStopFeature Enable=%d, MinThresh=%d, MaxThresh=%d"), + req_buf->early_stop_scan_enable, + req_buf->early_stop_scan_min_threshold, + req_buf->early_stop_scan_max_threshold); + req_buf->roamscan_adaptive_dwell_mode = + mac_ctx->roam.configParam.roamscan_adaptive_dwell_mode; +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + req_buf->RoamOffloadEnabled = csr_roamIsRoamOffloadEnabled(mac_ctx); + req_buf->RoamKeyMgmtOffloadEnabled = session->RoamKeyMgmtOffloadEnabled; + req_buf->pmkid_modes = session->pmkid_modes; + /* Roam Offload piggybacks upon the Roam Scan offload command. */ + if (req_buf->RoamOffloadEnabled) + csr_update_roam_scan_offload_request(mac_ctx, req_buf, session); + qdf_mem_copy(&req_buf->roam_params, + &mac_ctx->roam.configParam.roam_params, + sizeof(req_buf->roam_params)); +#endif + return req_buf; +} +/** + * check_allowed_ssid_list() - Check the WhiteList + * @req_buffer: Buffer which contains the connected profile SSID. + * @roam_params: Buffer which contains the whitelist SSID's. + * + * Check if the connected profile SSID exists in the whitelist. + * It is assumed that the framework provides this also in the whitelist. + * If it exists there is no issue. Otherwise add it to the list. + * + * Return: None + */ +static void check_allowed_ssid_list(tSirRoamOffloadScanReq *req_buffer, + struct roam_ext_params *roam_params) +{ + int i = 0; + bool match = false; + for (i = 0; i < roam_params->num_ssid_allowed_list; i++) { + if ((roam_params->ssid_allowed_list[i].length == + req_buffer->ConnectedNetwork.ssId.length) && + (!qdf_mem_cmp(roam_params->ssid_allowed_list[i].ssId, + req_buffer->ConnectedNetwork.ssId.ssId, + roam_params->ssid_allowed_list[i].length))) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "Whitelist contains connected profile SSID"); + match = true; + break; + } + } + if (!match) { + if (roam_params->num_ssid_allowed_list >= + MAX_SSID_ALLOWED_LIST) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "Whitelist is FULL. Cannot Add another entry"); + return; + } + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "Adding Connected profile SSID to whitelist"); + /* i is the next available index to add the entry.*/ + i = roam_params->num_ssid_allowed_list; + qdf_mem_copy(roam_params->ssid_allowed_list[i].ssId, + req_buffer->ConnectedNetwork.ssId.ssId, + req_buffer->ConnectedNetwork.ssId.length); + roam_params->ssid_allowed_list[i].length = + req_buffer->ConnectedNetwork.ssId.length; + roam_params->num_ssid_allowed_list++; + } +} + +/* + * Below Table describe whether RSO command can be send down to fimrware or not. + * Host check it on the basis of previous RSO command sent down to firmware. + *||==========================================================================|| + *|| New cmd | LAST SENT COMMAND ---> || + *||====|=====================================================================|| + *|| V | START | STOP | RESTART | UPDATE_CFG| ABORT_SCAN || + *|| -------------------------------------------------------------------------|| + *|| RSO_START | NO | YES | NO | NO | NO || + *|| RSO_STOP | YES | YES | YES | YES | YES || + *|| RSO_RESTART | YES | YES | NO | YES | YES || + *|| RSO_UPDATE_CFG | YES | NO | YES | YES | YES || + *|| RSO_ABORT_SCAN | YES | NO | YES | YES | YES || + *||==========================================================================|| + **/ +#define RSO_START_BIT (1<roam.neighborRoamInfo[session_id]; + uint8_t desiredMask = 0; + bool ret_val; + + switch (command) { + case ROAM_SCAN_OFFLOAD_START: + desiredMask = RSO_START_ALLOW_MASK; + break; + case ROAM_SCAN_OFFLOAD_STOP: + desiredMask = RSO_STOP_ALLOW_MASK; + break; + case ROAM_SCAN_OFFLOAD_RESTART: + desiredMask = RSO_RESTART_ALLOW_MASK; + break; + case ROAM_SCAN_OFFLOAD_UPDATE_CFG: + desiredMask = RSO_UPDATE_CFG_ALLOW_MASK; + break; + case ROAM_SCAN_OFFLOAD_ABORT_SCAN: + desiredMask = RSO_ABORT_SCAN_ALLOW_MASK; + break; + default: + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Wrong RSO command %d, not allowed"), command); + return 0;/*Cmd Not allowed*/ + } + ret_val = desiredMask & (1 << neigh_roam_info->last_sent_cmd); + return ret_val; +} + +/* + * csr_roam_send_rso_cmd() - API to send RSO command to PE + * @mac_ctx: Pointer to global MAC structure + * @session_id: Session ID + * @request_buf: Pointer to tSirRoamOffloadScanReq + * + * Return: QDF_STATUS + */ +static QDF_STATUS csr_roam_send_rso_cmd(tpAniSirGlobal mac_ctx, + uint8_t session_id, + tSirRoamOffloadScanReq *request_buf) +{ + QDF_STATUS status; + request_buf->message_type = eWNI_SME_ROAM_SCAN_OFFLOAD_REQ; + request_buf->length = sizeof(*request_buf); + + status = cds_send_mb_message_to_mac(request_buf); + if (QDF_STATUS_SUCCESS != status) { + sms_log(mac_ctx, LOGE, FL("Send RSO from CSR failed")); + return status; + } + return QDF_STATUS_SUCCESS; +} + +/** + * csr_append_assoc_ies() - Append specific IE to assoc IE's buffer + * @mac_ctx: Pointer to global mac context + * @req_buf: Pointer to Roam offload scan request + * @ie_id: IE ID to be appended + * @ie_len: IE length to be appended + * @ie_data: IE data to be appended + * + * Return: None + */ +static void csr_append_assoc_ies(tpAniSirGlobal mac_ctx, + tSirRoamOffloadScanReq *req_buf, uint8_t ie_id, + uint8_t ie_len, uint8_t *ie_data) +{ + tSirAddie *assoc_ie = &req_buf->assoc_ie; + if ((SIR_MAC_MAX_ADD_IE_LENGTH - assoc_ie->length) < ie_len) { + sms_log(mac_ctx, LOGE, "Appending IE(id:%d) fails", ie_id); + return; + } + + sms_log(mac_ctx, LOG1, "Appended IE(Id:%d) to RSO", ie_id); + assoc_ie->addIEdata[assoc_ie->length] = ie_id; + assoc_ie->addIEdata[assoc_ie->length + 1] = ie_len; + qdf_mem_copy(&assoc_ie->addIEdata[assoc_ie->length + 2], + ie_data, ie_len); + assoc_ie->length += (ie_len + 2); +} + +#ifdef FEATURE_WLAN_ESE +/** + * ese_populate_addtional_ies() - add IEs to reassoc frame + * @mac_ctx: Pointer to global mac structure + * @session: pointer to CSR session + * @req_buf: Pointer to Roam offload scan request + * + * This function populates the TSPEC ie and appends the info + * to assoc buffer. + * + * Return: None + */ +static void ese_populate_addtional_ies(tpAniSirGlobal mac_ctx, + tCsrRoamSession *session, + tSirRoamOffloadScanReq *req_buf) { + + uint8_t tspec_ie_hdr[SIR_MAC_OUI_WME_HDR_MIN] + = { 0x00, 0x50, 0xf2, 0x02, 0x02, 0x01 }; + uint8_t tspec_ie_buf[DOT11F_IE_WMMTSPEC_MAX_LEN], j; + ese_wmm_tspec_ie *tspec_ie; + tESETspecInfo ese_tspec; + + tspec_ie = (ese_wmm_tspec_ie *)(tspec_ie_buf + SIR_MAC_OUI_WME_HDR_MIN); + if (csr_is_wmm_supported(mac_ctx) && + mac_ctx->roam.configParam.isEseIniFeatureEnabled && + csr_roam_is_ese_assoc(mac_ctx, session->sessionId)) { + ese_tspec.numTspecs = sme_qos_ese_retrieve_tspec_info(mac_ctx, + session->sessionId, + (tTspecInfo *) &ese_tspec.tspec[0]); + qdf_mem_copy(tspec_ie_buf, tspec_ie_hdr, + SIR_MAC_OUI_WME_HDR_MIN); + for (j = 0; j < ese_tspec.numTspecs; j++) { + /* Populate the tspec_ie */ + ese_populate_wmm_tspec(&ese_tspec.tspec[j].tspec, + tspec_ie); + csr_append_assoc_ies(mac_ctx, req_buf, + IEEE80211_ELEMID_VENDOR, + DOT11F_IE_WMMTSPEC_MAX_LEN, + tspec_ie_buf); + } + } + +} +#else +static inline void ese_populate_addtional_ies(tpAniSirGlobal mac_ctx, + tCsrRoamSession *session, tSirRoamOffloadScanReq *req_buf) { +} +#endif +/** + * csr_update_driver_assoc_ies() - Append driver built IE's to assoc IE's + * @mac_ctx: Pointer to global mac structure + * @session: pointer to CSR session + * @req_buf: Pointer to Roam offload scan request + * + * Return: None + */ +static void csr_update_driver_assoc_ies(tpAniSirGlobal mac_ctx, + tCsrRoamSession *session, + tSirRoamOffloadScanReq *req_buf) +{ + bool power_caps_populated = false; + uint32_t csr_11henable = WNI_CFG_11H_ENABLED_STADEF; + uint8_t *rrm_cap_ie_data + = (uint8_t *) &mac_ctx->rrm.rrmPEContext.rrmEnabledCaps; + uint8_t power_cap_ie_data[DOT11F_IE_POWERCAPS_MAX_LEN] + = {MIN_TX_PWR_CAP, MAX_TX_PWR_CAP}; + uint8_t max_tx_pwr_cap = 0; + uint8_t supp_chan_ie[DOT11F_IE_SUPPCHANNELS_MAX_LEN], supp_chan_ie_len; + +#ifdef FEATURE_WLAN_ESE + uint8_t ese_ie[DOT11F_IE_ESEVERSION_MAX_LEN] + = { 0x0, 0x40, 0x96, 0x3, ESE_VERSION_SUPPORTED}; +#endif + uint8_t qcn_ie[DOT11F_IE_QCN_IE_MAX_LEN] + = {0x8C, 0xFD, 0xF0, 0x1, QCN_IE_VERSION_SUBATTR_ID, + QCN_IE_VERSION_SUBATTR_DATA_LEN, + QCN_IE_VERSION_SUPPORTED, + QCN_IE_SUBVERSION_SUPPORTED}; + + if (session->pConnectBssDesc) + max_tx_pwr_cap = csr_get_cfg_max_tx_power(mac_ctx, + session->pConnectBssDesc->channelId); + if (max_tx_pwr_cap) + power_cap_ie_data[1] = max_tx_pwr_cap; + + wlan_cfg_get_int(mac_ctx, WNI_CFG_11H_ENABLED, &csr_11henable); + + if (csr_11henable && csr_is11h_supported(mac_ctx)) { + /* Append power cap IE */ + csr_append_assoc_ies(mac_ctx, req_buf, IEEE80211_ELEMID_PWRCAP, + DOT11F_IE_POWERCAPS_MAX_LEN, + power_cap_ie_data); + power_caps_populated = true; + + /* Append Supported channels IE */ + csr_add_supported_5Ghz_channels(mac_ctx, supp_chan_ie, + &supp_chan_ie_len, true); + + csr_append_assoc_ies(mac_ctx, req_buf, + IEEE80211_ELEMID_SUPPCHAN, + supp_chan_ie_len, supp_chan_ie); + } + +#ifdef FEATURE_WLAN_ESE + /* Append ESE version IE if isEseIniFeatureEnabled INI is enabled */ + if (mac_ctx->roam.configParam.isEseIniFeatureEnabled) + csr_append_assoc_ies(mac_ctx, req_buf, IEEE80211_ELEMID_VENDOR, + DOT11F_IE_ESEVERSION_MAX_LEN, + ese_ie); +#endif + + if (mac_ctx->rrm.rrmPEContext.rrmEnable) { + /* Append RRM IE */ + csr_append_assoc_ies(mac_ctx, req_buf, IEEE80211_ELEMID_RRM, + DOT11F_IE_RRMENABLEDCAP_MAX_LEN, + rrm_cap_ie_data); + if (!power_caps_populated) + /* Append Power cap IE if not appended already */ + csr_append_assoc_ies(mac_ctx, req_buf, + IEEE80211_ELEMID_PWRCAP, + DOT11F_IE_POWERCAPS_MAX_LEN, + power_cap_ie_data); + } + ese_populate_addtional_ies(mac_ctx, session, req_buf); + + /* Append QCN IE if g_support_qcn_ie INI is enabled */ + if (mac_ctx->roam.configParam.qcn_ie_support) + csr_append_assoc_ies(mac_ctx, req_buf, IEEE80211_ELEMID_VENDOR, + DOT11F_IE_QCN_IE_MAX_LEN, + qcn_ie); +} + +/** + * csr_create_per_roam_request() - create PER roam offload scan request + * + * parameters + * @mac_ctx: global mac ctx + * @session_id: session id + * + * Return: per roam config request packet buffer + */ +static struct wmi_per_roam_config_req * +csr_create_per_roam_request(tpAniSirGlobal mac_ctx, uint8_t session_id) +{ + struct wmi_per_roam_config_req *req_buf = NULL; + + req_buf = qdf_mem_malloc(sizeof(struct wmi_per_roam_config_req)); + if (!req_buf) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Mem alloc for per roam req failed.")); + return NULL; + } + req_buf->vdev_id = session_id; + req_buf->per_config.enable = + mac_ctx->roam.configParam.per_roam_config.enable; + req_buf->per_config.tx_high_rate_thresh = + mac_ctx->roam.configParam.per_roam_config.tx_high_rate_thresh; + req_buf->per_config.rx_high_rate_thresh = + mac_ctx->roam.configParam.per_roam_config.rx_high_rate_thresh; + req_buf->per_config.tx_low_rate_thresh = + mac_ctx->roam.configParam.per_roam_config.tx_low_rate_thresh; + req_buf->per_config.rx_low_rate_thresh = + mac_ctx->roam.configParam.per_roam_config.rx_low_rate_thresh; + req_buf->per_config.per_rest_time = + mac_ctx->roam.configParam.per_roam_config.per_rest_time; + req_buf->per_config.tx_per_mon_time = + mac_ctx->roam.configParam.per_roam_config.tx_per_mon_time; + req_buf->per_config.rx_per_mon_time = + mac_ctx->roam.configParam.per_roam_config.rx_per_mon_time; + req_buf->per_config.tx_rate_thresh_percnt = + mac_ctx->roam.configParam.per_roam_config.tx_rate_thresh_percnt; + req_buf->per_config.rx_rate_thresh_percnt = + mac_ctx->roam.configParam.per_roam_config.rx_rate_thresh_percnt; + req_buf->per_config.min_candidate_rssi = + mac_ctx->roam.configParam.per_roam_config.min_candidate_rssi; + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + FL("PER based roaming configuaration enable: %d vdev: %d high_rate_thresh: %d low_rate_thresh: %d rate_thresh_percnt: %d per_rest_time: %d monitor_time: %d min cand rssi: %d"), + req_buf->per_config.enable, session_id, + req_buf->per_config.tx_high_rate_thresh, + req_buf->per_config.tx_low_rate_thresh, + req_buf->per_config.tx_rate_thresh_percnt, + req_buf->per_config.per_rest_time, + req_buf->per_config.tx_per_mon_time, + req_buf->per_config.min_candidate_rssi); + return req_buf; +} + +/** + * csr_roam_offload_per_scan() - populates roam offload scan request and sends + * to WMA + * + * parameters + * @mac_ctx: global mac ctx + * @session_id: session id + * + * Return: result of operation + */ +static QDF_STATUS +csr_roam_offload_per_scan(tpAniSirGlobal mac_ctx, uint8_t session_id) +{ + tpCsrNeighborRoamControlInfo roam_info = + &mac_ctx->roam.neighborRoamInfo[session_id]; + struct wmi_per_roam_config_req *req_buf; + cds_msg_t msg; + + /* + * No need to update in case of stop command, FW takes care of stopping + * this internally + */ + if (roam_info->last_sent_cmd == ROAM_SCAN_OFFLOAD_STOP) + return QDF_STATUS_SUCCESS; + + if (!mac_ctx->roam.configParam.per_roam_config.enable) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO, + FL("PER based roaming is disabled in configuration")); + return QDF_STATUS_SUCCESS; + } + + req_buf = csr_create_per_roam_request(mac_ctx, session_id); + if (!req_buf) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Failed to create req packet")); + return QDF_STATUS_E_FAILURE; + } + msg.type = WMA_SET_PER_ROAM_CONFIG_CMD; + msg.reserved = 0; + msg.bodyptr = req_buf; + if (!QDF_IS_STATUS_SUCCESS(cds_mq_post_message(QDF_MODULE_ID_WMA, + &msg))) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "%s: Unable to post WMA_SET_PER_ROAM_CONFIG_CMD to WMA", + __func__); + qdf_mem_free(req_buf); + } + return QDF_STATUS_SUCCESS; +} + +/** + * csr_roam_offload_scan() - populates roam offload scan request and sends to + * WMA + * + * paramters + * @mac_ctx: global mac ctx + * @session_id: session id + * @command: roam scan offload command input + * @reason: reason to roam + * + * Return: result of operation + */ +QDF_STATUS +csr_roam_offload_scan(tpAniSirGlobal mac_ctx, uint8_t session_id, + uint8_t command, uint8_t reason) +{ + uint8_t *state = NULL; + tSirRoamOffloadScanReq *req_buf; + QDF_STATUS status = QDF_STATUS_SUCCESS; + tCsrRoamSession *session = CSR_GET_SESSION(mac_ctx, session_id); + tpCsrNeighborRoamControlInfo roam_info = + &mac_ctx->roam.neighborRoamInfo[session_id]; + struct roam_ext_params *roam_params_dst; + struct roam_ext_params *roam_params_src; + uint8_t i; + uint8_t op_channel; + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "RSO Command %d, Session id %d, Reason %d", + command, session_id, reason); + if (NULL == session) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("session is null")); + return QDF_STATUS_E_FAILURE; + } + + if ((ROAM_SCAN_OFFLOAD_START == command) && + (session->pCurRoamProfile && + session->pCurRoamProfile->do_not_roam)) { + sms_log(mac_ctx, LOGE, + FL("Supplicant disabled driver roaming")); + return QDF_STATUS_E_FAILURE; + } + if (0 == csr_roam_is_roam_offload_scan_enabled(mac_ctx)) { + sms_log(mac_ctx, LOGE, "isRoamOffloadScanEnabled not set"); + return QDF_STATUS_E_FAILURE; + } + if (!csr_is_RSO_cmd_allowed(mac_ctx, command, session_id) && + reason != REASON_ROAM_SET_BLACKLIST_BSSID) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("RSO out-of-sync command %d lastSentCmd %d"), + command, roam_info->last_sent_cmd); + return QDF_STATUS_E_FAILURE; + } + + if ((true == b_roam_scan_offload_started) + && (ROAM_SCAN_OFFLOAD_START == command)) { + sms_log(mac_ctx, LOGE, "Roam Scan Offload is already started"); + return QDF_STATUS_E_FAILURE; + } + /* + * The Dynamic Config Items Update may happen even if the state is in + * INIT. It is important to ensure that the command is passed down to + * the FW only if the Infra Station is in a connected state. A connected + * station could also be in a PREAUTH or REASSOC states. + * 1) Block all CMDs that are not STOP in INIT State. For STOP always + * inform firmware irrespective of state. + * 2) Block update cfg CMD if its for REASON_ROAM_SET_BLACKLIST_BSSID, + * because we need to inform firmware of blacklisted AP for PNO in + * all states. + */ + + if ((roam_info->neighborRoamState == + eCSR_NEIGHBOR_ROAM_STATE_INIT) && + (command != ROAM_SCAN_OFFLOAD_STOP) && + (reason != REASON_ROAM_SET_BLACKLIST_BSSID)) { + state = mac_trace_get_neighbour_roam_state( + roam_info->neighborRoamState); + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + FL("Scan Command not sent to FW state=%s and cmd=%d"), + state, command); + return QDF_STATUS_E_FAILURE; + } + + req_buf = csr_create_roam_scan_offload_request(mac_ctx, command, + session_id, reason, + session, roam_info); + if (!req_buf) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Failed to create req packet")); + return QDF_STATUS_E_FAILURE; + } + roam_params_dst = &req_buf->roam_params; + roam_params_src = &mac_ctx->roam.configParam.roam_params; + if (reason == REASON_ROAM_SET_SSID_ALLOWED) + check_allowed_ssid_list(req_buf, roam_params_src); + /* + * Configure the lookup threshold either from INI or from framework. + * If both are present, give higher priority to the one from framework. + */ + if (roam_params_src->alert_rssi_threshold) + req_buf->LookupThreshold = + roam_params_src->alert_rssi_threshold; + else + req_buf->LookupThreshold = + (int8_t)roam_info->cfgParams.neighborLookupThreshold * + (-1); + qdf_mem_copy(roam_params_dst, roam_params_src, + sizeof(struct roam_ext_params)); + /* + * rssi_diff which is updated via framework is equivalent to the + * INI RoamRssiDiff parameter and hence should be updated. + */ + if (roam_params_src->rssi_diff) + req_buf->RoamRssiDiff = roam_params_src->rssi_diff; + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "num_bssid_avoid_list: %d, num_ssid_allowed_list: %d, " + "num_bssid_favored: %d, raise_rssi_thresh_5g: %d, " + "drop_rssi_thresh_5g: %d, raise_rssi_type_5g: %d, " + "raise_factor_5g: %d, drop_rssi_type_5g: %d, " + "drop_factor_5g: %d, max_raise_rssi_5g: %d, " + "max_drop_rssi_5g: %d, rssi_diff: %d, alert_rssi_threshold:%d", + roam_params_dst->num_bssid_avoid_list, + roam_params_dst->num_ssid_allowed_list, + roam_params_dst->num_bssid_favored, + roam_params_dst->raise_rssi_thresh_5g, + roam_params_dst->drop_rssi_thresh_5g, + roam_params_dst->raise_rssi_type_5g, + roam_params_dst->raise_factor_5g, + roam_params_dst->drop_rssi_type_5g, + roam_params_dst->drop_factor_5g, + roam_params_dst->max_raise_rssi_5g, + roam_params_dst->max_drop_rssi_5g, + req_buf->RoamRssiDiff, roam_params_dst->alert_rssi_threshold); + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "dense_rssi_thresh_offset: %d, dense_min_aps_cnt:%d, traffic_threshold:%d", + roam_params_dst->dense_rssi_thresh_offset, + roam_params_dst->dense_min_aps_cnt, + roam_params_dst->traffic_threshold); + + /* Set initial dense roam status */ + if (mac_ctx->scan.roam_candidate_count[session_id] > + roam_params_dst->dense_min_aps_cnt) + roam_params_dst->initial_dense_status = true; + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "initial_dense_status:%d, candidate count:%d", + roam_params_dst->initial_dense_status, + mac_ctx->scan.roam_candidate_count[session_id]); + + for (i = 0; i < roam_params_dst->num_bssid_avoid_list; i++) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "Blacklist Bssid: ("MAC_ADDRESS_STR")", + MAC_ADDR_ARRAY(roam_params_dst->bssid_avoid_list[i].bytes)); + } + for (i = 0; i < roam_params_dst->num_ssid_allowed_list; i++) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "Whitelist: %.*s", + roam_params_dst->ssid_allowed_list[i].length, + roam_params_dst->ssid_allowed_list[i].ssId); + } + for (i = 0; i < roam_params_dst->num_bssid_favored; i++) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "Preferred Bssid: ("MAC_ADDRESS_STR") score: %d", + MAC_ADDR_ARRAY(roam_params_dst->bssid_favored[i].bytes), + roam_params_dst->bssid_favored_factor[i]); + } + + op_channel = session->connectedProfile.operationChannel; + req_buf->hi_rssi_scan_max_count = + roam_info->cfgParams.hi_rssi_scan_max_count; + req_buf->hi_rssi_scan_delay = + roam_info->cfgParams.hi_rssi_scan_delay; + req_buf->hi_rssi_scan_rssi_ub = + roam_info->cfgParams.hi_rssi_scan_rssi_ub; + /* + * If the current operation channel is 5G frequency band, then + * there is no need to enable the HI_RSSI feature. This feature + * is useful only if we are connected to a 2.4 GHz AP and we wish + * to connect to a better 5GHz AP is available. + */ + if (session->disable_hi_rssi) + req_buf->hi_rssi_scan_rssi_delta = 0; + else + req_buf->hi_rssi_scan_rssi_delta = + roam_info->cfgParams.hi_rssi_scan_rssi_delta; + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "hi_rssi:delta=%d, max_count=%d, delay=%d, ub=%d", + req_buf->hi_rssi_scan_rssi_delta, + req_buf->hi_rssi_scan_max_count, + req_buf->hi_rssi_scan_delay, + req_buf->hi_rssi_scan_rssi_ub); + + if (command != ROAM_SCAN_OFFLOAD_STOP) { + req_buf->assoc_ie.length = session->nAddIEAssocLength; + qdf_mem_copy(req_buf->assoc_ie.addIEdata, + session->pAddIEAssoc, + session->nAddIEAssocLength); + csr_update_driver_assoc_ies(mac_ctx, session, req_buf); + } + + if (!QDF_IS_STATUS_SUCCESS( + csr_roam_send_rso_cmd(mac_ctx, session_id, req_buf))) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Not able to post message to PE", + __func__); + return QDF_STATUS_E_FAILURE; + } else { + if (ROAM_SCAN_OFFLOAD_START == command) + b_roam_scan_offload_started = true; + else if (ROAM_SCAN_OFFLOAD_STOP == command) + b_roam_scan_offload_started = false; + } + /* update the last sent cmd */ + roam_info->last_sent_cmd = command; + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "Roam Scan Offload Command %d, Reason %d", command, reason); + /* Update PER config to FW after sending the command */ + csr_roam_offload_per_scan(mac_ctx, session_id); + return status; +} + +QDF_STATUS csr_roam_offload_scan_rsp_hdlr(tpAniSirGlobal pMac, + tpSirRoamOffloadScanRsp scanOffloadRsp) +{ + switch (scanOffloadRsp->reason) { + case 0: + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "Rsp for Roam Scan Offload with failure status"); + break; + case REASON_OS_REQUESTED_ROAMING_NOW: + csr_neighbor_roam_proceed_with_handoff_req(pMac, + scanOffloadRsp->sessionId); + break; + + default: + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO, + "Rsp for Roam Scan Offload with reason %d", + scanOffloadRsp->reason); + } + return QDF_STATUS_SUCCESS; +} +#endif + +tCsrPeStatsReqInfo *csr_roam_check_pe_stats_req_list(tpAniSirGlobal pMac, + uint32_t statsMask, + uint32_t periodicity, + bool *pFound, + uint8_t staId, uint8_t sessionId) +{ + bool found = false; + QDF_STATUS status = QDF_STATUS_SUCCESS; + tCsrPeStatsReqInfo staEntry; + tCsrPeStatsReqInfo *pTempStaEntry = NULL; + tListElem *pStaEntry = NULL; + QDF_STATUS qdf_status; + *pFound = false; + + pStaEntry = csr_roam_find_in_pe_stats_req_list(pMac, statsMask); + if (pStaEntry) { + pTempStaEntry = + GET_BASE_ADDR(pStaEntry, tCsrPeStatsReqInfo, link); + if (pTempStaEntry->periodicity) { + pTempStaEntry->periodicity = + QDF_MIN(periodicity, + pTempStaEntry->periodicity); + } else { + pTempStaEntry->periodicity = periodicity; + } + pTempStaEntry->numClient++; + found = true; + } else { + qdf_mem_set(&staEntry, sizeof(tCsrPeStatsReqInfo), 0); + staEntry.numClient = 1; + staEntry.periodicity = periodicity; + staEntry.pMac = pMac; + staEntry.rspPending = false; + staEntry.staId = staId; + staEntry.statsMask = statsMask; + staEntry.timerRunning = false; + staEntry.sessionId = sessionId; + pTempStaEntry = + csr_roam_insert_entry_into_pe_stats_req_list(pMac, + &pMac->roam. + peStatsReqList, + &staEntry); + if (!pTempStaEntry) { + /* msg */ + sms_log(pMac, LOGW, + "csr_roam_check_pe_stats_req_list: Failed to insert req in peStatsReqList"); + return NULL; + } + } + pTempStaEntry->periodicity = + pMac->roam.configParam.statsReqPeriodicityInPS; + + if (!pTempStaEntry->timerRunning) { + /* send down a req in case of one time req, for periodic ones wait for timer to expire */ + if (!pTempStaEntry->rspPending && !pTempStaEntry->periodicity) { + status = csr_send_mb_stats_req_msg(pMac, + statsMask & ~(1 << + eCsrGlobalClassDStats), + staId, sessionId); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOGE, + FL + ("csr_roam_check_pe_stats_req_list:failed to send down stats req to PE")); + } else { + pTempStaEntry->rspPending = true; + } + } + if (pTempStaEntry->periodicity) { + if (!found) { + + qdf_status = + qdf_mc_timer_init(&pTempStaEntry-> + hPeStatsTimer, + QDF_TIMER_TYPE_SW, + csr_roam_pe_stats_timer_handler, + pTempStaEntry); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + sms_log(pMac, LOGE, + FL + ("csr_roam_check_pe_stats_req_list:cannot init hPeStatsTimer timer")); + return NULL; + } + } + /* start timer */ + sms_log(pMac, LOG1, + "csr_roam_check_pe_stats_req_list:peStatsTimer period %d", + pTempStaEntry->periodicity); + qdf_status = + qdf_mc_timer_start(&pTempStaEntry->hPeStatsTimer, + pTempStaEntry->periodicity); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + sms_log(pMac, LOGE, + FL + ("csr_roam_check_pe_stats_req_list:cannot start hPeStatsTimer timer")); + return NULL; + } + pTempStaEntry->timerRunning = true; + } + } + *pFound = found; + return pTempStaEntry; +} + +/* + pStaEntry is no longer invalid upon the return of this function. + */ +static void csr_roam_remove_stat_list_entry(tpAniSirGlobal pMac, tListElem *pEntry) +{ + if (pEntry) { + if (csr_ll_remove_entry + (&pMac->roam.statsClientReqList, pEntry, LL_ACCESS_LOCK)) { + qdf_mem_free(GET_BASE_ADDR + (pEntry, tCsrStatsClientReqInfo, link)); + } + } +} + +void csr_roam_remove_entry_from_pe_stats_req_list(tpAniSirGlobal pMac, + tCsrPeStatsReqInfo *pPeStaEntry) +{ + tListElem *pEntry; + tCsrPeStatsReqInfo *pTempStaEntry; + QDF_STATUS qdf_status; + pEntry = csr_ll_peek_head(&pMac->roam.peStatsReqList, LL_ACCESS_LOCK); + if (!pEntry) { + sms_log(pMac, LOGE, FL(" List empty, no stats req for PE")); + return; + } + while (pEntry) { + pTempStaEntry = GET_BASE_ADDR(pEntry, tCsrPeStatsReqInfo, link); + if (NULL == pTempStaEntry + || (pTempStaEntry->statsMask != + pPeStaEntry->statsMask)) { + pEntry = csr_ll_next(&pMac->roam.peStatsReqList, pEntry, + LL_ACCESS_NOLOCK); + continue; + } + sms_log(pMac, LOGW, FL("Match found")); + if (pTempStaEntry->timerRunning) { + qdf_status = qdf_mc_timer_stop( + &pTempStaEntry->hPeStatsTimer); + /* + * If we are not able to stop the timer here, just + * remove the entry from the linked list. Destroy the + * timer object and free the memory in the timer CB + */ + if (qdf_status == QDF_STATUS_SUCCESS) { + /* the timer is successfully stopped */ + pTempStaEntry->timerRunning = false; + /* Destroy the timer */ + qdf_status = qdf_mc_timer_destroy( + &pTempStaEntry->hPeStatsTimer); + } else { + /* + * the timer could not be stopped. Hence destroy + * and free the memory for the PE stat entry in + * the timer CB. + */ + pTempStaEntry->timerStopFailed = true; + } + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + sms_log(pMac, LOGE, + FL("failed to stop/destroy timer")); + } + } + + if (csr_ll_remove_entry(&pMac->roam.peStatsReqList, pEntry, + LL_ACCESS_LOCK)) { + /* + * Only free the memory if we could stop the timer + * successfully + */ + if (!pTempStaEntry->timerStopFailed) { + qdf_mem_free(pTempStaEntry); + pTempStaEntry = NULL; + } + break; + } + pEntry = csr_ll_next(&pMac->roam.peStatsReqList, pEntry, + LL_ACCESS_NOLOCK); + } /* end of while loop */ + return; +} + +void csr_roam_report_statistics(tpAniSirGlobal pMac, uint32_t statsMask, + tCsrStatsCallback callback, uint8_t staId, + void *pContext) +{ + uint8_t stats[500]; + uint8_t *pStats = NULL; + uint32_t tempMask = 0; + uint8_t counter = 0; + if (!callback) { + sms_log(pMac, LOGE, FL("Cannot report callback NULL")); + return; + } + if (!statsMask) { + sms_log(pMac, LOGE, FL("Cannot report statsMask is 0")); + return; + } + pStats = stats; + tempMask = statsMask; + while (tempMask) { + if (tempMask & 1) { + /* new stats info from PE, fill up the stats strucutres in PMAC */ + switch (counter) { + case eCsrSummaryStats: + sms_log(pMac, LOG2, FL("Summary stats")); + qdf_mem_copy(pStats, + (uint8_t *) &pMac->roam. + summaryStatsInfo, + sizeof(tCsrSummaryStatsInfo)); + pStats += sizeof(tCsrSummaryStatsInfo); + break; + case eCsrGlobalClassAStats: + sms_log(pMac, LOG2, FL("ClassA stats")); + qdf_mem_copy(pStats, + (uint8_t *) &pMac->roam. + classAStatsInfo, + sizeof(tCsrGlobalClassAStatsInfo)); + pStats += sizeof(tCsrGlobalClassAStatsInfo); + break; + case eCsrGlobalClassBStats: + sms_log(pMac, LOG2, FL("ClassB stats")); + qdf_mem_copy(pStats, + (uint8_t *) &pMac->roam. + classBStatsInfo, + sizeof(tCsrGlobalClassBStatsInfo)); + pStats += sizeof(tCsrGlobalClassBStatsInfo); + break; + case eCsrGlobalClassCStats: + sms_log(pMac, LOG2, FL("ClassC stats")); + qdf_mem_copy(pStats, + (uint8_t *) &pMac->roam. + classCStatsInfo, + sizeof(tCsrGlobalClassCStatsInfo)); + pStats += sizeof(tCsrGlobalClassCStatsInfo); + break; + case eCsrGlobalClassDStats: + sms_log(pMac, LOG2, FL("ClassD stats")); + qdf_mem_copy(pStats, + (uint8_t *) &pMac->roam. + classDStatsInfo, + sizeof(tCsrGlobalClassDStatsInfo)); + pStats += sizeof(tCsrGlobalClassDStatsInfo); + break; + case eCsrPerStaStats: + sms_log(pMac, LOG2, FL("PerSta stats")); + qdf_mem_copy(pStats, + (uint8_t *) &pMac->roam. + perStaStatsInfo[staId], + sizeof(tCsrPerStaStatsInfo)); + pStats += sizeof(tCsrPerStaStatsInfo); + break; + case csr_per_chain_rssi_stats: + sms_log(pMac, LOG2, FL("Per Chain RSSI stats")); + qdf_mem_copy(pStats, + (uint8_t *)&pMac->roam.per_chain_rssi_stats, + sizeof(struct csr_per_chain_rssi_stats_info)); + pStats += sizeof( + struct csr_per_chain_rssi_stats_info); + break; + default: + sms_log(pMac, LOGE, + FL("Unknown stats type and counter %d"), + counter); + break; + } + } + tempMask >>= 1; + counter++; + } + callback(stats, pContext); +} + +QDF_STATUS csr_roam_dereg_statistics_req(tpAniSirGlobal pMac) +{ + tListElem *pEntry = NULL; + tListElem *pPrevEntry = NULL; + tCsrStatsClientReqInfo *pTempStaEntry = NULL; + QDF_STATUS status = QDF_STATUS_SUCCESS; + QDF_STATUS qdf_status; + pEntry = csr_ll_peek_head(&pMac->roam.statsClientReqList, LL_ACCESS_LOCK); + if (!pEntry) { + /* list empty */ + sms_log(pMac, LOGW, + "csr_roam_dereg_statistics_req: List empty, no request from " + "upper layer client(s)"); + return status; + } + while (pEntry) { + if (pPrevEntry) { + pTempStaEntry = + GET_BASE_ADDR(pPrevEntry, tCsrStatsClientReqInfo, + link); + /* send up the stats report */ + csr_roam_report_statistics(pMac, pTempStaEntry->statsMask, + pTempStaEntry->callback, + pTempStaEntry->staId, + pTempStaEntry->pContext); + csr_roam_remove_stat_list_entry(pMac, pPrevEntry); + } + pTempStaEntry = + GET_BASE_ADDR(pEntry, tCsrStatsClientReqInfo, link); + if (pTempStaEntry->pPeStaEntry) { + /* pPeStaEntry can be NULL */ + pTempStaEntry->pPeStaEntry->numClient--; + /* check if we need to delete the entry from peStatsReqList too */ + if (!pTempStaEntry->pPeStaEntry->numClient) { + csr_roam_remove_entry_from_pe_stats_req_list(pMac, + pTempStaEntry-> + pPeStaEntry); + } + } + /* check if we need to stop the tl stats timer too */ + pMac->roam.tlStatsReqInfo.numClient--; + if (!pMac->roam.tlStatsReqInfo.numClient) { + if (pMac->roam.tlStatsReqInfo.timerRunning) { + status = + qdf_mc_timer_stop(&pMac->roam. + tlStatsReqInfo. + hTlStatsTimer); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOGE, + FL + ("csr_roam_dereg_statistics_req:cannot stop TlStatsTimer timer")); + /* we will continue */ + } + } + pMac->roam.tlStatsReqInfo.periodicity = 0; + pMac->roam.tlStatsReqInfo.timerRunning = false; + } + if (pTempStaEntry->periodicity) { + /* While creating StaEntry in csr_get_statistics, */ + /* Initializing and starting timer only when periodicity is set. */ + /* So Stop and Destroy timer only when periodicity is set. */ + + qdf_mc_timer_stop(&pTempStaEntry->timer); + /* Destroy the qdf timer... */ + qdf_status = + qdf_mc_timer_destroy(&pTempStaEntry->timer); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + sms_log(pMac, LOGE, + FL + ("csr_roam_dereg_statistics_req:failed to destroy Client req timer")); + } + } + + pPrevEntry = pEntry; + pEntry = + csr_ll_next(&pMac->roam.statsClientReqList, pEntry, + LL_ACCESS_NOLOCK); + } + /* the last one */ + if (pPrevEntry) { + pTempStaEntry = + GET_BASE_ADDR(pPrevEntry, tCsrStatsClientReqInfo, link); + /* send up the stats report */ + csr_roam_report_statistics(pMac, pTempStaEntry->statsMask, + pTempStaEntry->callback, + pTempStaEntry->staId, + pTempStaEntry->pContext); + csr_roam_remove_stat_list_entry(pMac, pPrevEntry); + } + return status; + +} + +tSmeCmd *csr_get_command_buffer(tpAniSirGlobal pMac) +{ + tSmeCmd *pCmd = sme_get_command_buffer(pMac); + if (pCmd) { + pMac->roam.sPendingCommands++; + } + return pCmd; +} + +void csr_release_command(tpAniSirGlobal pMac, tSmeCmd *pCommand) +{ + if (pMac->roam.sPendingCommands > 0) { + /* All command allocated through csr_get_command_buffer need to */ + /* decrement the pending count when releasing. */ + pMac->roam.sPendingCommands--; + sme_release_command(pMac, pCommand); + } else { + sms_log(pMac, LOGE, FL("no pending commands")); + QDF_ASSERT(0); + } +} + +/* Return SUCCESS is the command is queued, failed */ +QDF_STATUS csr_queue_sme_command(tpAniSirGlobal pMac, tSmeCmd *pCommand, + bool fHighPriority) +{ + bool fNoCmdPending; + + if (!SME_IS_START(pMac)) { + sms_log(pMac, LOGE, FL("Sme in stop state")); + QDF_ASSERT(0); + return QDF_STATUS_E_PERM; + } + + if ((eSmeCommandScan == pCommand->command) && pMac->scan.fDropScanCmd) { + sms_log(pMac, LOGW, FL(" drop scan (scan reason %d) command"), + pCommand->u.scanCmd.reason); + return QDF_STATUS_CSR_WRONG_STATE; + } + + if ((pCommand->command == eSmeCommandScan) + || (pCommand->command == eSmeCommandRemainOnChannel)) { + if (csr_ll_count(&pMac->sme.smeScanCmdActiveList) >= + pMac->scan.max_scan_count) { + sms_log(pMac, LOGE, FL("scan pending list count %d"), + pMac->sme.smeScanCmdPendingList.Count); + csr_scan_call_callback(pMac, pCommand, eCSR_SCAN_ABORT); + return QDF_STATUS_E_FAILURE; + } + sms_log(pMac, LOGW, + FL("scan pending list count %d scan_id %d"), + pMac->sme.smeScanCmdPendingList.Count, + pCommand->u.scanCmd.scanID); + csr_ll_insert_tail(&pMac->sme.smeScanCmdPendingList, + &pCommand->Link, LL_ACCESS_LOCK); + /* process the command queue... */ + sme_process_pending_queue(pMac); + return QDF_STATUS_SUCCESS; + } + /* Make sure roamCmdPendingList is not empty first */ + fNoCmdPending = + csr_ll_is_list_empty(&pMac->roam.roamCmdPendingList, false); + if (fNoCmdPending) { + sme_push_command(pMac, pCommand, fHighPriority); + } else { + /* no list lock is needed since SME lock is held */ + if (!fHighPriority) { + csr_ll_insert_tail(&pMac->roam.roamCmdPendingList, + &pCommand->Link, false); + } else { + csr_ll_insert_head(&pMac->roam.roamCmdPendingList, + &pCommand->Link, false); + } + } + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS csr_roam_update_config(tpAniSirGlobal mac_ctx, uint8_t session_id, + uint16_t capab, uint32_t value) +{ + struct update_config *msg; + QDF_STATUS status = QDF_STATUS_SUCCESS; + tCsrRoamSession *session = CSR_GET_SESSION(mac_ctx, session_id); + + sms_log(mac_ctx, LOG1, FL("update HT config requested")); + if (NULL == session) { + sme_err("Session does not exist for session id %d", session_id); + return QDF_STATUS_E_FAILURE; + } + + msg = qdf_mem_malloc(sizeof(*msg)); + if (NULL == msg) { + sme_err("malloc failed"); + return QDF_STATUS_E_NOMEM; + } + + msg->messageType = eWNI_SME_UPDATE_CONFIG; + msg->sme_session_id = session_id; + msg->capab = capab; + msg->value = value; + msg->length = sizeof(*msg); + status = cds_send_mb_message_to_mac(msg); + + return status; +} + +QDF_STATUS csr_roam_update_apwpsie(tpAniSirGlobal pMac, uint32_t sessionId, + tSirAPWPSIEs *pAPWPSIES) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tSirUpdateAPWPSIEsReq *pMsg; + + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + if (NULL == pSession) { + sms_log(pMac, LOGE, + FL("Session does not exist for session id %d"), + sessionId); + return QDF_STATUS_E_FAILURE; + } + + pMsg = qdf_mem_malloc(sizeof(*pMsg)); + if (NULL == pMsg) + return QDF_STATUS_E_NOMEM; + + pMsg->messageType = eWNI_SME_UPDATE_APWPSIE_REQ; + pMsg->transactionId = 0; + qdf_copy_macaddr(&pMsg->bssid, &pSession->selfMacAddr); + pMsg->sessionId = sessionId; + qdf_mem_copy(&pMsg->APWPSIEs, pAPWPSIES, sizeof(tSirAPWPSIEs)); + pMsg->length = sizeof(*pMsg); + status = cds_send_mb_message_to_mac(pMsg); + + return status; +} + +QDF_STATUS csr_roam_update_wparsni_es(tpAniSirGlobal pMac, uint32_t sessionId, + tSirRSNie *pAPSirRSNie) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tSirUpdateAPWPARSNIEsReq *pMsg; + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + if (NULL == pSession) { + sms_log(pMac, LOGE, + FL(" Session does not exist for session id %d"), + sessionId); + return QDF_STATUS_E_FAILURE; + } + do { + pMsg = qdf_mem_malloc(sizeof(tSirUpdateAPWPARSNIEsReq)); + if (NULL == pMsg) + return QDF_STATUS_E_NOMEM; + pMsg->messageType = eWNI_SME_SET_APWPARSNIEs_REQ; + pMsg->transactionId = 0; + qdf_copy_macaddr(&pMsg->bssid, &pSession->selfMacAddr); + pMsg->sessionId = sessionId; + qdf_mem_copy(&pMsg->APWPARSNIEs, pAPSirRSNie, + sizeof(tSirRSNie)); + pMsg->length = sizeof(struct sSirUpdateAPWPARSNIEsReq); + status = cds_send_mb_message_to_mac(pMsg); + } while (0); + return status; +} + +/* + pBuf points to the beginning of the message + LIM packs disassoc rsp as below, + messageType - 2 bytes + messageLength - 2 bytes + sessionId - 1 byte + transactionId - 2 bytes (uint16_t) + reasonCode - 4 bytes (sizeof(tSirResultCodes)) + peerMacAddr - 6 bytes + The rest is conditionally defined of (WNI_POLARIS_FW_PRODUCT == AP) and not used + */ +static void csr_ser_des_unpack_diassoc_rsp(uint8_t *pBuf, tSirSmeDisassocRsp *pRsp) +{ + if (pBuf && pRsp) { + pBuf += 4; /* skip type and length */ + pRsp->sessionId = *pBuf++; + qdf_get_u16(pBuf, (uint16_t *) &pRsp->transactionId); + pBuf += 2; + qdf_get_u32(pBuf, (uint32_t *) &pRsp->statusCode); + pBuf += 4; + qdf_mem_copy(pRsp->peer_macaddr.bytes, pBuf, QDF_MAC_ADDR_SIZE); + } +} + +/* Returns whether a session is in QDF_STA_MODE...or not */ +bool csr_roam_is_sta_mode(tpAniSirGlobal pMac, uint32_t sessionId) +{ + tCsrRoamSession *pSession = NULL; + pSession = CSR_GET_SESSION(pMac, sessionId); + if (!pSession) { + sms_log(pMac, LOGE, FL(" %s: session %d not found "), __func__, + sessionId); + return false; + } + if (!CSR_IS_SESSION_VALID(pMac, sessionId)) { + sms_log(pMac, LOGE, FL(" %s: Inactive session"), __func__); + return false; + } + if (eCSR_BSS_TYPE_INFRASTRUCTURE != pSession->connectedProfile.BSSType) { + return false; + } + /* There is a possibility that the above check may fail,because + * P2P CLI also uses the same BSSType (eCSR_BSS_TYPE_INFRASTRUCTURE) + * when it is connected.So,we may sneak through the above check even + * if we are not a STA mode INFRA station. So, if we sneak through + * the above condition, we can use the following check if we are + * really in STA Mode.*/ + + if (NULL != pSession->pCurRoamProfile) { + if (pSession->pCurRoamProfile->csrPersona == QDF_STA_MODE) { + return true; + } else { + return false; + } + } + + return false; +} + +QDF_STATUS csr_handoff_request(tpAniSirGlobal pMac, + uint8_t sessionId, + tCsrHandoffRequest *pHandoffInfo) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + cds_msg_t msg; + + tAniHandoffReq *pMsg; + pMsg = qdf_mem_malloc(sizeof(tAniHandoffReq)); + if (NULL == pMsg) { + sms_log(pMac, LOGE, + " csr_handoff_request: failed to allocate mem for req "); + return QDF_STATUS_E_NOMEM; + } + pMsg->msgType = eWNI_SME_HANDOFF_REQ; + pMsg->msgLen = (uint16_t) sizeof(tAniHandoffReq); + pMsg->sessionId = sessionId; + pMsg->channel = pHandoffInfo->channel; + pMsg->handoff_src = pHandoffInfo->src; + qdf_mem_copy(pMsg->bssid, pHandoffInfo->bssid.bytes, QDF_MAC_ADDR_SIZE); + msg.type = eWNI_SME_HANDOFF_REQ; + msg.bodyptr = pMsg; + msg.reserved = 0; + if (QDF_STATUS_SUCCESS != cds_mq_post_message(CDS_MQ_ID_SME, &msg)) { + sms_log(pMac, LOGE, + " csr_handoff_request failed to post msg to self "); + qdf_mem_free((void *)pMsg); + status = QDF_STATUS_E_FAILURE; + } + return status; +} + +/** + * csr_roam_channel_change_req() - Post channel change request to LIM + * @pMac: mac context + * @bssid: SAP bssid + * @ch_params: channel information + * @profile: CSR profile + * + * This API is primarily used to post Channel Change Req for SAP + * + * Return: QDF_STATUS + */ +QDF_STATUS csr_roam_channel_change_req(tpAniSirGlobal pMac, + struct qdf_mac_addr bssid, + struct ch_params_s *ch_params, + tCsrRoamProfile *profile) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tSirChanChangeRequest *pMsg; + tCsrRoamStartBssParams param; + + /* + * while changing the channel, use basic rates given by driver + * and not by hostapd as there is a chance that hostapd might + * give us rates based on original channel which may not be + * suitable for new channel + */ + csr_roam_get_bss_start_parms(pMac, profile, ¶m, true); + pMsg = qdf_mem_malloc(sizeof(tSirChanChangeRequest)); + if (!pMsg) { + return QDF_STATUS_E_NOMEM; + } + + pMsg->messageType = eWNI_SME_CHANNEL_CHANGE_REQ; + pMsg->messageLen = sizeof(tSirChanChangeRequest); + pMsg->targetChannel = profile->ChannelInfo.ChannelList[0]; + pMsg->sec_ch_offset = ch_params->sec_ch_offset; + pMsg->ch_width = profile->ch_params.ch_width; + pMsg->dot11mode = csr_translate_to_wni_cfg_dot11_mode(pMac, + pMac->roam.configParam.uCfgDot11Mode); + if (IS_24G_CH(pMsg->targetChannel) && + (false == pMac->roam.configParam.enableVhtFor24GHz) && + (WNI_CFG_DOT11_MODE_11AC == pMsg->dot11mode || + WNI_CFG_DOT11_MODE_11AC_ONLY == pMsg->dot11mode)) + pMsg->dot11mode = WNI_CFG_DOT11_MODE_11N; + + pMsg->center_freq_seg_0 = ch_params->center_freq_seg0; + pMsg->center_freq_seg_1 = ch_params->center_freq_seg1; + qdf_mem_copy(pMsg->bssid, bssid.bytes, QDF_MAC_ADDR_SIZE); + qdf_mem_copy(&pMsg->operational_rateset, + ¶m.operationalRateSet, sizeof(pMsg->operational_rateset)); + qdf_mem_copy(&pMsg->extended_rateset, + ¶m.extendedRateSet, sizeof(pMsg->extended_rateset)); + status = cds_send_mb_message_to_mac(pMsg); + + return status; +} + +/* + * Post Beacon Tx Start request to LIM + * immediately after SAP CAC WAIT is + * completed without any RADAR indications. + */ +QDF_STATUS csr_roam_start_beacon_req(tpAniSirGlobal pMac, + struct qdf_mac_addr bssid, + uint8_t dfsCacWaitStatus) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tSirStartBeaconIndication *pMsg; + + pMsg = qdf_mem_malloc(sizeof(tSirStartBeaconIndication)); + + if (!pMsg) { + return QDF_STATUS_E_NOMEM; + } + + pMsg->messageType = eWNI_SME_START_BEACON_REQ; + pMsg->messageLen = sizeof(tSirStartBeaconIndication); + pMsg->beaconStartStatus = dfsCacWaitStatus; + qdf_mem_copy(pMsg->bssid, bssid.bytes, QDF_MAC_ADDR_SIZE); + + status = cds_send_mb_message_to_mac(pMsg); + + return status; +} + +/*---------------------------------------------------------------------------- + \fn csr_roam_modify_add_ies + \brief This function sends msg to modify the additional IE buffers in PE + \param pMac - pMac global structure + \param pModifyIE - pointer to tSirModifyIE structure + \param updateType - Type of buffer + \- return Success or failure + -----------------------------------------------------------------------------*/ +QDF_STATUS +csr_roam_modify_add_ies(tpAniSirGlobal pMac, + tSirModifyIE *pModifyIE, eUpdateIEsType updateType) +{ + tpSirModifyIEsInd pModifyAddIEInd = NULL; + uint8_t *pLocalBuffer = NULL; + QDF_STATUS status; + + /* following buffer will be freed by consumer (PE) */ + pLocalBuffer = qdf_mem_malloc(pModifyIE->ieBufferlength); + + if (NULL == pLocalBuffer) { + sms_log(pMac, LOGE, FL("Memory Allocation Failure!!!")); + return QDF_STATUS_E_NOMEM; + } + + pModifyAddIEInd = qdf_mem_malloc(sizeof(tSirModifyIEsInd)); + if (NULL == pModifyAddIEInd) { + sms_log(pMac, LOGE, FL("Memory Allocation Failure!!!")); + qdf_mem_free(pLocalBuffer); + return QDF_STATUS_E_NOMEM; + } + + /*copy the IE buffer */ + qdf_mem_copy(pLocalBuffer, pModifyIE->pIEBuffer, + pModifyIE->ieBufferlength); + qdf_mem_zero(pModifyAddIEInd, sizeof(tSirModifyIEsInd)); + + pModifyAddIEInd->msgType = eWNI_SME_MODIFY_ADDITIONAL_IES; + pModifyAddIEInd->msgLen = sizeof(tSirModifyIEsInd); + + qdf_copy_macaddr(&pModifyAddIEInd->modifyIE.bssid, &pModifyIE->bssid); + + pModifyAddIEInd->modifyIE.smeSessionId = pModifyIE->smeSessionId; + pModifyAddIEInd->modifyIE.notify = pModifyIE->notify; + pModifyAddIEInd->modifyIE.ieID = pModifyIE->ieID; + pModifyAddIEInd->modifyIE.ieIDLen = pModifyIE->ieIDLen; + pModifyAddIEInd->modifyIE.pIEBuffer = pLocalBuffer; + pModifyAddIEInd->modifyIE.ieBufferlength = pModifyIE->ieBufferlength; + pModifyAddIEInd->modifyIE.oui_length = pModifyIE->oui_length; + + pModifyAddIEInd->updateType = updateType; + + status = cds_send_mb_message_to_mac(pModifyAddIEInd); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOGE, + FL("Failed to send eWNI_SME_UPDATE_ADDTIONAL_IES msg" + "!!! status %d"), status); + qdf_mem_free(pLocalBuffer); + } + return status; +} + +/*---------------------------------------------------------------------------- + \fn csr_roam_update_add_ies + \brief This function sends msg to updates the additional IE buffers in PE + \param pMac - pMac global structure + \param sessionId - SME session id + \param bssid - BSSID + \param additionIEBuffer - buffer containing addition IE from hostapd + \param length - length of buffer + \param updateType - Type of buffer + \param append - append or replace completely + \- return Success or failure + -----------------------------------------------------------------------------*/ +QDF_STATUS +csr_roam_update_add_ies(tpAniSirGlobal pMac, + tSirUpdateIE *pUpdateIE, eUpdateIEsType updateType) +{ + tpSirUpdateIEsInd pUpdateAddIEs = NULL; + uint8_t *pLocalBuffer = NULL; + QDF_STATUS status; + + if (pUpdateIE->ieBufferlength != 0) { + /* Following buffer will be freed by consumer (PE) */ + pLocalBuffer = qdf_mem_malloc(pUpdateIE->ieBufferlength); + if (NULL == pLocalBuffer) { + sms_log(pMac, LOGE, FL("Memory Allocation Failure!!!")); + return QDF_STATUS_E_NOMEM; + } + qdf_mem_copy(pLocalBuffer, pUpdateIE->pAdditionIEBuffer, + pUpdateIE->ieBufferlength); + } + + pUpdateAddIEs = qdf_mem_malloc(sizeof(tSirUpdateIEsInd)); + if (NULL == pUpdateAddIEs) { + sms_log(pMac, LOGE, FL("Memory Allocation Failure!!!")); + if (pLocalBuffer != NULL) { + qdf_mem_free(pLocalBuffer); + } + return QDF_STATUS_E_NOMEM; + } + + pUpdateAddIEs->msgType = eWNI_SME_UPDATE_ADDITIONAL_IES; + pUpdateAddIEs->msgLen = sizeof(tSirUpdateIEsInd); + + qdf_copy_macaddr(&pUpdateAddIEs->updateIE.bssid, &pUpdateIE->bssid); + + pUpdateAddIEs->updateIE.smeSessionId = pUpdateIE->smeSessionId; + pUpdateAddIEs->updateIE.append = pUpdateIE->append; + pUpdateAddIEs->updateIE.notify = pUpdateIE->notify; + pUpdateAddIEs->updateIE.ieBufferlength = pUpdateIE->ieBufferlength; + pUpdateAddIEs->updateIE.pAdditionIEBuffer = pLocalBuffer; + + pUpdateAddIEs->updateType = updateType; + + status = cds_send_mb_message_to_mac(pUpdateAddIEs); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOGE, + FL("Failed to send eWNI_SME_UPDATE_ADDTIONAL_IES msg" + "!!! status %d"), status); + qdf_mem_free(pLocalBuffer); + } + return status; +} + +/** + * csr_send_ext_change_channel()- function to post send ECSA + * action frame to lim. + * @mac_ctx: pointer to global mac structure + * @channel: new channel to switch + * @session_id: senssion it should be sent on. + * + * This function is called to post ECSA frame to lim. + * + * Return: success if msg posted to LIM else return failure + */ +QDF_STATUS csr_send_ext_change_channel(tpAniSirGlobal mac_ctx, uint32_t channel, + uint8_t session_id) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct sir_sme_ext_cng_chan_req *msg; + + msg = qdf_mem_malloc(sizeof(*msg)); + if (NULL == msg) + return QDF_STATUS_E_NOMEM; + + msg->message_type = eWNI_SME_EXT_CHANGE_CHANNEL; + msg->length = sizeof(*msg); + msg->new_channel = channel; + msg->session_id = session_id; + status = cds_send_mb_message_to_mac(msg); + return status; +} + +/** + * csr_roam_send_chan_sw_ie_request() - Request to transmit CSA IE + * @mac_ctx: Global MAC context + * @bssid: BSSID + * @target_channel: Channel on which to send the IE + * @csa_ie_reqd: Include/Exclude CSA IE. + * @ch_params: operating Channel related information + * + * This function sends request to transmit channel switch announcement + * IE to lower layers + * + * Return: success or failure + **/ +QDF_STATUS csr_roam_send_chan_sw_ie_request(tpAniSirGlobal mac_ctx, + struct qdf_mac_addr bssid, + uint8_t target_channel, + uint8_t csa_ie_reqd, + struct ch_params_s *ch_params) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tSirDfsCsaIeRequest *msg; + + msg = qdf_mem_malloc(sizeof(tSirDfsCsaIeRequest)); + if (!msg) { + return QDF_STATUS_E_NOMEM; + } + + msg->msgType = eWNI_SME_DFS_BEACON_CHAN_SW_IE_REQ; + msg->msgLen = sizeof(tSirDfsCsaIeRequest); + + msg->targetChannel = target_channel; + msg->csaIeRequired = csa_ie_reqd; + qdf_mem_copy(msg->bssid, bssid.bytes, QDF_MAC_ADDR_SIZE); + qdf_mem_copy(&msg->ch_params, ch_params, sizeof(struct ch_params_s)); + + status = cds_send_mb_message_to_mac(msg); + + return status; +} +#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR +/** + * csr_roaming_report_diag_event() - Diag events for LFR3 + * @mac_ctx: MAC context + * @roam_synch_ind_ptr: Roam Synch Indication Pointer + * @reason: Reason for this event to happen + * + * The major events in the host for LFR3 roaming such as + * roam synch indication, roam synch completion and + * roam synch handoff fail will be indicated to the + * diag framework using this API. + * + * Return: None + */ +void csr_roaming_report_diag_event(tpAniSirGlobal mac_ctx, + roam_offload_synch_ind *roam_synch_ind_ptr, + eCsrDiagWlanStatusEventReason reason) +{ + WLAN_HOST_DIAG_EVENT_DEF(roam_connection, + host_event_wlan_status_payload_type); + qdf_mem_set(&roam_connection, + sizeof(host_event_wlan_status_payload_type), 0); + switch (reason) { + case eCSR_REASON_ROAM_SYNCH_IND: + roam_connection.eventId = eCSR_WLAN_STATUS_CONNECT; + if (roam_synch_ind_ptr) { + roam_connection.rssi = roam_synch_ind_ptr->rssi; + roam_connection.channel = + cds_freq_to_chan(roam_synch_ind_ptr->chan_freq); + } + break; + case eCSR_REASON_ROAM_SYNCH_CNF: + roam_connection.eventId = eCSR_WLAN_STATUS_CONNECT; + break; + case eCSR_REASON_ROAM_HO_FAIL: + roam_connection.eventId = eCSR_WLAN_STATUS_DISCONNECT; + break; + default: + sms_log(mac_ctx, LOGE, + FL("LFR3: Unsupported reason %d"), reason); + return; + } + roam_connection.reason = reason; + WLAN_HOST_DIAG_EVENT_REPORT(&roam_connection, EVENT_WLAN_STATUS_V2); +} +#endif + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +/*---------------------------------------------------------------------------- +* fn csr_process_ho_fail_ind +* brief This function will process the Hand Off Failure indication +* received from the firmware. It will trigger a disconnect on +* the session which the firmware reported a hand off failure +* param pMac global structure +* param pMsgBuf - Contains the session ID for which the handler should apply +* --------------------------------------------------------------------------*/ +void csr_process_ho_fail_ind(tpAniSirGlobal pMac, void *pMsgBuf) +{ + tSirSmeHOFailureInd *pSmeHOFailInd = (tSirSmeHOFailureInd *) pMsgBuf; + uint32_t sessionId; + + if (pSmeHOFailInd) + sessionId = pSmeHOFailInd->sessionId; + else { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "LFR3: Hand-Off Failure Ind is NULL"); + return; + } + /* Roaming is supported only on Infra STA Mode. */ + if (!csr_roam_is_sta_mode(pMac, sessionId)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "LFR3:HO Fail cannot be handled for session %d", + sessionId); + return; + } + cds_set_connection_in_progress(false); + csr_roam_roaming_offload_timer_action(pMac, 0, sessionId, + ROAMING_OFFLOAD_TIMER_STOP); + csr_roam_call_callback(pMac, sessionId, NULL, 0, + eCSR_ROAM_NAPI_OFF, eCSR_ROAM_RESULT_FAILURE); + csr_roam_synch_clean_up(pMac, sessionId); + csr_roaming_report_diag_event(pMac, NULL, + eCSR_REASON_ROAM_HO_FAIL); + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "LFR3:Issue Disconnect on session %d", sessionId); + csr_roam_disconnect(pMac, sessionId, + eCSR_DISCONNECT_REASON_ROAM_HO_FAIL); + if (pMac->roam.configParam.enable_fatal_event) + cds_flush_logs(WLAN_LOG_TYPE_FATAL, + WLAN_LOG_INDICATOR_HOST_DRIVER, + WLAN_LOG_REASON_ROAM_HO_FAILURE, + true, false); +} +#endif /* WLAN_FEATURE_ROAM_OFFLOAD */ + +/** + * csr_update_op_class_array() - update op class for each band + * @mac_ctx: mac global context + * @op_classes: out param, operating class array to update + * @channel_info: channel info + * @ch_name: channel band name to display in debug messages + * @i: out param, stores number of operating classes + * + * Return: void + */ +static void +csr_update_op_class_array(tpAniSirGlobal mac_ctx, + uint8_t *op_classes, + tCsrChannel *channel_info, + char *ch_name, + uint8_t *i) +{ + uint8_t j = 0, idx = 0, class = 0; + bool found = false; + uint8_t num_channels = channel_info->numChannels; + uint8_t ch_bandwidth; + + sms_log(mac_ctx, LOG1, + FL("Num of %s channels, %d"), + ch_name, num_channels); + + for (idx = 0; idx < num_channels + && *i < (CDS_MAX_SUPP_OPER_CLASSES - 1); idx++) { + for (ch_bandwidth = BW20; ch_bandwidth < BWALL; + ch_bandwidth++) { + class = cds_reg_dmn_get_opclass_from_channel( + mac_ctx->scan.countryCodeCurrent, + channel_info->channelList[idx], + ch_bandwidth); + sms_log(mac_ctx, LOG4, FL("for chan %d, op class: %d"), + channel_info->channelList[idx], class); + + found = false; + for (j = 0; j < CDS_MAX_SUPP_OPER_CLASSES - 1; + j++) { + if (op_classes[j] == class) { + found = true; + break; + } + } + + if (!found) { + op_classes[*i] = class; + *i = *i + 1; + } + } + } +} + +/** + * csr_update_op_class_array() - update op class for all bands + * @hHal: global hal context + * + * Return: void + */ +void csr_init_operating_classes(tHalHandle hHal) +{ + uint8_t i = 0; + uint8_t j = 0; + uint8_t swap = 0; + uint8_t numClasses = 0; + uint8_t opClasses[CDS_MAX_SUPP_OPER_CLASSES] = {0,}; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + sms_log(pMac, LOG1, FL("Current Country = %c%c"), + pMac->scan.countryCodeCurrent[0], + pMac->scan.countryCodeCurrent[1]); + + csr_update_op_class_array(pMac, opClasses, + &pMac->scan.base_channels, "20MHz", &i); + numClasses = i; + + /* As per spec the operating classes should be in ascending order. + * Bubble sort is fine since we don't have many classes + */ + for (i = 0; i < (numClasses - 1); i++) { + for (j = 0; j < (numClasses - i - 1); j++) { + /* For decreasing order use < */ + if (opClasses[j] > opClasses[j + 1]) { + swap = opClasses[j]; + opClasses[j] = opClasses[j + 1]; + opClasses[j + 1] = swap; + } + } + } + + sms_log(pMac, LOG1, FL("Number of unique supported op classes %d"), + numClasses); + for (i = 0; i < numClasses; i++) { + sms_log(pMac, LOG1, FL("supported opClasses[%d] = %d"), i, + opClasses[i]); + } + + /* Set the ordered list of op classes in regdomain + * for use by other modules + */ + cds_reg_dmn_set_curr_opclasses(numClasses, &opClasses[0]); +} + +/** + * csr_find_session_by_type() - This function will find given session type from + * all sessions. + * @mac_ctx: pointer to mac context. + * @type: session type + * + * Return: session id for give session type. + **/ +static uint32_t +csr_find_session_by_type(tpAniSirGlobal mac_ctx, enum tQDF_ADAPTER_MODE type) +{ + uint32_t i, session_id = CSR_SESSION_ID_INVALID; + tCsrRoamSession *session_ptr; + for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) { + if (!CSR_IS_SESSION_VALID(mac_ctx, i)) + continue; + + session_ptr = CSR_GET_SESSION(mac_ctx, i); + if (type == session_ptr->bssParams.bssPersona) { + session_id = i; + break; + } + } + return session_id; +} +/** + * csr_is_conn_allow_2g_band() - This function will check if station's conn + * is allowed in 2.4Ghz band. + * @mac_ctx: pointer to mac context. + * @chnl: station's channel. + * + * This function will check if station's connection is allowed in 5Ghz band + * after comparing it with SAP's operating channel. If SAP's operating + * channel and Station's channel is different than this function will return + * false else true. + * + * Return: true or false. + **/ +static bool csr_is_conn_allow_2g_band(tpAniSirGlobal mac_ctx, uint32_t chnl) +{ + uint32_t sap_session_id; + tCsrRoamSession *sap_session; + + if (0 == chnl) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("channel is zero, connection not allowed")); + + return false; + } + + sap_session_id = csr_find_session_by_type(mac_ctx, QDF_SAP_MODE); + if (CSR_SESSION_ID_INVALID != sap_session_id) { + sap_session = CSR_GET_SESSION(mac_ctx, sap_session_id); + if ((0 != sap_session->bssParams.operationChn) && + (sap_session->bssParams.operationChn != chnl)) { + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL + ("Can't allow STA to connect, chnls not same")); + return false; + } + } + return true; +} + +/** + * csr_is_conn_allow_5g_band() - This function will check if station's conn + * is allowed in 5Ghz band. + * @mac_ctx: pointer to mac context. + * @chnl: station's channel. + * + * This function will check if station's connection is allowed in 5Ghz band + * after comparing it with P2PGO's operating channel. If P2PGO's operating + * channel and Station's channel is different than this function will return + * false else true. + * + * Return: true or false. + **/ +static bool csr_is_conn_allow_5g_band(tpAniSirGlobal mac_ctx, uint32_t chnl) +{ + uint32_t p2pgo_session_id; + tCsrRoamSession *p2pgo_session; + + if (0 == chnl) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL + ("channel is zero, connection not allowed")); + return false; + } + + p2pgo_session_id = csr_find_session_by_type(mac_ctx, QDF_P2P_GO_MODE); + if (CSR_SESSION_ID_INVALID != p2pgo_session_id) { + p2pgo_session = CSR_GET_SESSION(mac_ctx, p2pgo_session_id); + if ((0 != p2pgo_session->bssParams.operationChn) && + (eCSR_ASSOC_STATE_TYPE_NOT_CONNECTED != + p2pgo_session->connectState) && + (p2pgo_session->bssParams.operationChn != + chnl)) { + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL + ("Can't allow STA to connect, chnls not same")); + return false; + } + } + return true; +} + +/** + * csr_clear_joinreq_param() - This function will clear station's params + * for stored join request to csr. + * @hal_handle: pointer to hal context. + * @session_id: station's session id. + * + * This function will clear station's allocated memory for cached join + * request. + * + * Return: true or false based on function's overall success. + **/ +bool csr_clear_joinreq_param(tpAniSirGlobal mac_ctx, + uint32_t session_id) +{ + tCsrRoamSession *sta_session; + tScanResultList *bss_list; + + if (NULL == mac_ctx) + return false; + + sta_session = CSR_GET_SESSION(mac_ctx, session_id); + if (NULL == sta_session) + return false; + + /* Release the memory allocated by previous join request */ + bss_list = + (tScanResultList *)&sta_session->stored_roam_profile. + bsslist_handle; + if (NULL != bss_list) { + csr_scan_result_purge(mac_ctx, + sta_session->stored_roam_profile.bsslist_handle); + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO, + FL("bss list is released for session %d"), session_id); + sta_session->stored_roam_profile.bsslist_handle = NULL; + } + sta_session->stored_roam_profile.bsslist_handle = NULL; + csr_release_profile(mac_ctx, &sta_session->stored_roam_profile.profile); + sta_session->stored_roam_profile.reason = 0; + sta_session->stored_roam_profile.roam_id = 0; + sta_session->stored_roam_profile.imediate_flag = false; + sta_session->stored_roam_profile.clear_flag = false; + return true; +} + +/** + * csr_store_joinreq_param() - This function will store station's join + * request to that station's session. + * @mac_ctx: pointer to mac context. + * @profile: pointer to station's roam profile. + * @scan_cache: pointer to station's scan cache. + * @roam_id: reference to roam_id variable being passed. + * @session_id: station's session id. + * + * This function will store station's join request to one of the + * csr structure and add it to station's session. + * + * Return: true or false based on function's overall success. + **/ +bool csr_store_joinreq_param(tpAniSirGlobal mac_ctx, + tCsrRoamProfile *profile, + tScanResultHandle scan_cache, + uint32_t *roam_id, + uint32_t session_id) +{ + tCsrRoamSession *sta_session; + + if (NULL == mac_ctx) + return false; + + sta_session = CSR_GET_SESSION(mac_ctx, session_id); + if (NULL == sta_session) + return false; + + sta_session->stored_roam_profile.session_id = session_id; + csr_roam_copy_profile(mac_ctx, + &sta_session->stored_roam_profile.profile, profile); + /* new bsslist_handle's memory will be relased later */ + sta_session->stored_roam_profile.bsslist_handle = scan_cache; + sta_session->stored_roam_profile.reason = eCsrHddIssued; + sta_session->stored_roam_profile.roam_id = *roam_id; + sta_session->stored_roam_profile.imediate_flag = false; + sta_session->stored_roam_profile.clear_flag = false; + + return true; +} + +/** + * csr_issue_stored_joinreq() - This function will issues station's stored + * the join request. + * @mac_ctx: pointer to mac context. + * @roam_id: reference to roam_id variable being passed. + * @session_id: station's session id. + * + * This function will issue station's stored join request, from this point + * onwards the flow will be just like normal connect request. + * + * Return: QDF_STATUS_SUCCESS or QDF_STATUS_E_FAILURE. + **/ +QDF_STATUS csr_issue_stored_joinreq(tpAniSirGlobal mac_ctx, + uint32_t *roam_id, + uint32_t session_id) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tCsrRoamSession *sta_session; + uint32_t new_roam_id; + + sta_session = CSR_GET_SESSION(mac_ctx, session_id); + if (NULL == sta_session) + return QDF_STATUS_E_FAILURE; + new_roam_id = GET_NEXT_ROAM_ID(&mac_ctx->roam); + *roam_id = new_roam_id; + status = csr_roam_issue_connect(mac_ctx, + sta_session->stored_roam_profile.session_id, + &sta_session->stored_roam_profile.profile, + sta_session->stored_roam_profile.bsslist_handle, + sta_session->stored_roam_profile.reason, + new_roam_id, + sta_session->stored_roam_profile.imediate_flag, + sta_session->stored_roam_profile.clear_flag); + if (QDF_STATUS_SUCCESS != status) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL + ("CSR failed issuing connect cmd with status = 0x%08X"), + status); + csr_clear_joinreq_param(mac_ctx, session_id); + } + return status; +} + +/** + * csr_process_set_hw_mode() - Set HW mode command to PE + * @mac: Globacl MAC pointer + * @command: Command received from SME + * + * Posts the set HW mode command to PE. This message passing + * through PE is required for PE's internal management + * + * Return: None + */ +void csr_process_set_hw_mode(tpAniSirGlobal mac, tSmeCmd *command) +{ + uint32_t len; + struct s_sir_set_hw_mode *cmd = NULL; + QDF_STATUS status; + tSirMsgQ msg; + struct sir_set_hw_mode_resp *param; + enum cds_hw_mode_change cds_hw_mode; + + /* Setting HW mode is for the entire system. + * So, no need to check session + */ + + if (!command) { + sms_log(mac, LOGE, FL("Set HW mode param is NULL")); + goto fail; + } + + len = sizeof(*cmd); + cmd = qdf_mem_malloc(len); + if (!cmd) { + sms_log(mac, LOGE, FL("Memory allocation failed")); + /* Probably the fail response will also fail during malloc. + * Still proceeding to send response! + */ + goto fail; + } + + /* For hidden SSID case, if there is any scan command pending + * it needs to be cleared before issuing set HW mode + */ + if (command->u.set_hw_mode_cmd.reason == SIR_UPDATE_REASON_HIDDEN_STA) { + sms_log(mac, LOGE, FL("clear any pending scan command")); + status = csr_scan_abort_mac_scan_not_for_connect(mac, + command->u.set_hw_mode_cmd.session_id); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sms_log(mac, LOGE, FL("Failed to clear scan cmd")); + goto fail; + } + } + + if ((SIR_UPDATE_REASON_OPPORTUNISTIC == + command->u.set_hw_mode_cmd.reason) && + (cds_is_connection_in_progress(NULL, NULL))) { + sms_log(mac, LOGE, + FL("Set HW mode refused: conn is in progress")); + cds_restart_opportunistic_timer(false); + goto fail; + } + + cds_hw_mode = wma_get_cds_hw_mode_change_from_hw_mode_index( + command->u.set_hw_mode_cmd.hw_mode_index); + + if (CDS_HW_MODE_NOT_IN_PROGRESS == cds_hw_mode) + goto fail; + + cds_set_hw_mode_change_in_progress(cds_hw_mode); + + cmd->messageType = eWNI_SME_SET_HW_MODE_REQ; + cmd->length = len; + cmd->set_hw.hw_mode_index = command->u.set_hw_mode_cmd.hw_mode_index; + cmd->set_hw.reason = command->u.set_hw_mode_cmd.reason; + /* + * Below callback and context info are not needed for PE as of now. + * Storing the passed value in the same s_sir_set_hw_mode format. + */ + cmd->set_hw.set_hw_mode_cb = command->u.set_hw_mode_cmd.set_hw_mode_cb; + + sms_log(mac, LOG1, + FL("Posting set hw mode req to PE session:%d reason:%d"), + command->u.set_hw_mode_cmd.session_id, + command->u.set_hw_mode_cmd.reason); + + status = cds_send_mb_message_to_mac(cmd); + if (QDF_STATUS_SUCCESS != status) { + cds_set_hw_mode_change_in_progress(CDS_HW_MODE_NOT_IN_PROGRESS); + sms_log(mac, LOGE, FL("Posting to PE failed")); + return; + } + return; +fail: + if (cmd) + qdf_mem_free(cmd); + param = qdf_mem_malloc(sizeof(*param)); + if (!param) { + sms_log(mac, LOGE, + FL("Malloc fail: Fail to send response to SME")); + return; + } + sms_log(mac, LOGE, FL("Sending set HW fail response to SME")); + param->status = SET_HW_MODE_STATUS_ECANCELED; + param->cfgd_hw_mode_index = 0; + param->num_vdev_mac_entries = 0; + msg.type = eWNI_SME_SET_HW_MODE_RESP; + msg.bodyptr = param; + msg.bodyval = 0; + sys_process_mmh_msg(mac, &msg); +} + +/** + * csr_process_set_dual_mac_config() - Set HW mode command to PE + * @mac: Global MAC pointer + * @command: Command received from SME + * + * Posts the set dual mac config command to PE. + * + * Return: None + */ +void csr_process_set_dual_mac_config(tpAniSirGlobal mac, tSmeCmd *command) +{ + uint32_t len; + struct sir_set_dual_mac_cfg *cmd; + QDF_STATUS status; + tSirMsgQ msg; + struct sir_dual_mac_config_resp *param; + + /* Setting MAC configuration is for the entire system. + * So, no need to check session + */ + + if (!command) { + sms_log(mac, LOGE, FL("Set HW mode param is NULL")); + goto fail; + } + + len = sizeof(*cmd); + cmd = qdf_mem_malloc(len); + if (!cmd) { + sms_log(mac, LOGE, FL("Memory allocation failed")); + /* Probably the fail response will also fail during malloc. + * Still proceeding to send response! + */ + goto fail; + } + + cmd->message_type = eWNI_SME_SET_DUAL_MAC_CFG_REQ; + cmd->length = len; + cmd->set_dual_mac.scan_config = command->u.set_dual_mac_cmd.scan_config; + cmd->set_dual_mac.fw_mode_config = + command->u.set_dual_mac_cmd.fw_mode_config; + /* + * Below callback and context info are not needed for PE as of now. + * Storing the passed value in the same sir_set_dual_mac_cfg format. + */ + cmd->set_dual_mac.set_dual_mac_cb = + command->u.set_dual_mac_cmd.set_dual_mac_cb; + + sms_log(mac, LOG1, + FL("Posting eWNI_SME_SET_DUAL_MAC_CFG_REQ to PE: %x %x"), + cmd->set_dual_mac.scan_config, + cmd->set_dual_mac.fw_mode_config); + + status = cds_send_mb_message_to_mac(cmd); + if (QDF_STATUS_SUCCESS != status) { + sms_log(mac, LOGE, FL("Posting to PE failed")); + return; + } + return; +fail: + param = qdf_mem_malloc(sizeof(*param)); + if (!param) { + sms_log(mac, LOGE, + FL("Malloc fail: Fail to send response to SME")); + return; + } + sms_log(mac, LOGE, FL("Sending set dual mac fail response to SME")); + param->status = SET_HW_MODE_STATUS_ECANCELED; + msg.type = eWNI_SME_SET_DUAL_MAC_CFG_RESP; + msg.bodyptr = param; + msg.bodyval = 0; + sys_process_mmh_msg(mac, &msg); +} + +/** + * csr_process_set_antenna_mode() - Set antenna mode command to + * PE + * @mac: Global MAC pointer + * @command: Command received from SME + * + * Posts the set dual mac config command to PE. + * + * Return: None + */ +void csr_process_set_antenna_mode(tpAniSirGlobal mac, tSmeCmd *command) +{ + uint32_t len; + struct sir_set_antenna_mode *cmd; + QDF_STATUS status; + tSirMsgQ msg; + struct sir_antenna_mode_resp *param; + + /* Setting MAC configuration is for the entire system. + * So, no need to check session + */ + + if (!command) { + sms_log(mac, LOGE, FL("Set antenna mode param is NULL")); + goto fail; + } + + len = sizeof(*cmd); + cmd = qdf_mem_malloc(len); + if (!cmd) { + sms_log(mac, LOGE, FL("Memory allocation failed")); + goto fail; + } + + cmd->message_type = eWNI_SME_SET_ANTENNA_MODE_REQ; + cmd->length = len; + cmd->set_antenna_mode = command->u.set_antenna_mode_cmd; + + sms_log(mac, LOG1, + FL("Posting eWNI_SME_SET_ANTENNA_MODE_REQ to PE: %d %d"), + cmd->set_antenna_mode.num_rx_chains, + cmd->set_antenna_mode.num_tx_chains); + + status = cds_send_mb_message_to_mac(cmd); + if (QDF_STATUS_SUCCESS != status) { + sms_log(mac, LOGE, FL("Posting to PE failed")); + /* + * cds_send_mb_message_to_mac would've released the mem + * allocated by cmd. + */ + goto fail; + } + + return; +fail: + param = qdf_mem_malloc(sizeof(*param)); + if (!param) { + sms_log(mac, LOGE, + FL("Malloc fail: Fail to send response to SME")); + return; + } + sms_log(mac, LOGE, FL("Sending set dual mac fail response to SME")); + param->status = SET_ANTENNA_MODE_STATUS_ECANCELED; + msg.type = eWNI_SME_SET_ANTENNA_MODE_RESP; + msg.bodyptr = param; + msg.bodyval = 0; + sys_process_mmh_msg(mac, &msg); +} + +/** + * csr_process_nss_update_req() - Update nss command to PE + * @mac: Globacl MAC pointer + * @command: Command received from SME + * + * Posts the nss update command to PE. This message passing + * through PE is required for PE's internal management + * + * Return: None + */ +void csr_process_nss_update_req(tpAniSirGlobal mac, tSmeCmd *command) +{ + uint32_t len; + struct sir_nss_update_request *msg; + QDF_STATUS status; + tSirMsgQ msg_return; + struct sir_beacon_tx_complete_rsp *param; + tCsrRoamSession *session; + + if (!command) { + sms_log(mac, LOGE, FL("nss update param is NULL")); + return; + } + + if (!CSR_IS_SESSION_VALID(mac, command->sessionId)) { + sms_log(mac, LOGE, FL("Invalid session id %d"), + command->sessionId); + return; + } + session = CSR_GET_SESSION(mac, command->sessionId); + + len = sizeof(*msg); + msg = qdf_mem_malloc(len); + if (!msg) { + sms_log(mac, LOGE, FL("Memory allocation failed")); + /* Probably the fail response is also fail during malloc. + * Still proceeding to send response! + */ + goto fail; + } + + msg->msgType = eWNI_SME_NSS_UPDATE_REQ; + msg->msgLen = sizeof(*msg); + + msg->new_nss = command->u.nss_update_cmd.new_nss; + msg->vdev_id = command->u.nss_update_cmd.session_id; + + sms_log(mac, LOG1, + FL("Posting eWNI_SME_NSS_UPDATE_REQ to PE")); + + status = cds_send_mb_message_to_mac(msg); + if (QDF_STATUS_SUCCESS != status) { + sms_log(mac, LOGE, FL("Posting to PE failed")); + return; + } + return; +fail: + param = qdf_mem_malloc(sizeof(*param)); + if (!param) { + sms_log(mac, LOGE, + FL("Malloc fail: Fail to send response to SME")); + return; + } + sms_log(mac, LOGE, FL("Sending nss update fail response to SME")); + param->tx_status = QDF_STATUS_E_FAILURE; + param->session_id = command->u.nss_update_cmd.session_id; + msg_return.type = eWNI_SME_NSS_UPDATE_RSP; + msg_return.bodyptr = param; + msg_return.bodyval = 0; + sys_process_mmh_msg(mac, &msg_return); +} +#ifdef FEATURE_WLAN_TDLS +/** + * csr_roam_fill_tdls_info() - Fill TDLS information + * @roam_info: Roaming information buffer + * @join_rsp: Join response which has TDLS info + * + * Return: None + */ +void csr_roam_fill_tdls_info(tpAniSirGlobal mac_ctx, tCsrRoamInfo *roam_info, + tpSirSmeJoinRsp join_rsp) +{ + roam_info->tdls_prohibited = join_rsp->tdls_prohibited; + roam_info->tdls_chan_swit_prohibited = + join_rsp->tdls_chan_swit_prohibited; + sms_log(mac_ctx, LOG1, + FL("tdls:prohibit: %d, chan_swit_prohibit: %d"), + roam_info->tdls_prohibited, + roam_info->tdls_chan_swit_prohibited); +} +#endif + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +static QDF_STATUS csr_process_roam_sync_callback(tpAniSirGlobal mac_ctx, + roam_offload_synch_ind *roam_synch_data, + tpSirBssDescription bss_desc, enum sir_roam_op_code reason) +{ + uint8_t session_id = roam_synch_data->roamedVdevId; + tCsrRoamSession *session = CSR_GET_SESSION(mac_ctx, session_id); + tDot11fBeaconIEs *ies_local = NULL; + struct ps_global_info *ps_global_info = &mac_ctx->sme.ps_global_info; + tCsrRoamInfo *roam_info; + tCsrRoamConnectedProfile *conn_profile = NULL; + sme_QosAssocInfo assoc_info; + tpAddBssParams add_bss_params; + QDF_STATUS status = QDF_STATUS_SUCCESS; + uint16_t len; +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH + tSirSmeHTProfile *src_profile = NULL; + tCsrRoamHTProfile *dst_profile = NULL; +#endif + + if (!session) { + sms_log(mac_ctx, LOGE, FL("LFR3: Session not found")); + return QDF_STATUS_E_FAILURE; + } + + sms_log(mac_ctx, LOG1, FL("LFR3: reason: %d"), reason); + switch (reason) { + case SIR_ROAMING_DEREGISTER_STA: + /* + * The following is the first thing done in CSR + * after receiving RSI. Hence stopping the timer here. + */ + csr_roam_roaming_offload_timer_action(mac_ctx, + 0, session_id, ROAMING_OFFLOAD_TIMER_STOP); + if (!CSR_IS_ROAM_JOINED(mac_ctx, session_id)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + FL("LFR3: Session not in connected state")); + return QDF_STATUS_E_FAILURE; + } + csr_roam_call_callback(mac_ctx, session_id, NULL, 0, + eCSR_ROAM_FT_START, eSIR_SME_SUCCESS); + return status; + case SIR_ROAMING_START: + csr_roam_roaming_offload_timer_action(mac_ctx, + CSR_ROAMING_OFFLOAD_TIMEOUT_PERIOD, session_id, + ROAMING_OFFLOAD_TIMER_START); + csr_roam_call_callback(mac_ctx, session_id, NULL, 0, + eCSR_ROAM_START, eSIR_SME_SUCCESS); + return status; + case SIR_ROAMING_ABORT: + csr_roam_roaming_offload_timer_action(mac_ctx, + 0, session_id, ROAMING_OFFLOAD_TIMER_STOP); + csr_roam_call_callback(mac_ctx, session_id, NULL, 0, + eCSR_ROAM_ABORT, eSIR_SME_SUCCESS); + return status; + case SIR_ROAM_SYNCH_NAPI_OFF: + csr_roam_call_callback(mac_ctx, session_id, NULL, 0, + eCSR_ROAM_NAPI_OFF, eSIR_SME_SUCCESS); + return status; + case SIR_ROAMING_INVOKE_FAIL: + csr_roam_call_callback(mac_ctx, session_id, NULL, 0, + eCSR_ROAM_ASSOCIATION_FAILURE, + eCSR_ROAM_RESULT_INVOKE_FAILED); + + /* Userspace roam request failed, disconnect with current AP */ + sms_log(mac_ctx, LOG1, + FL("LFR3: roam invoke from user-space fail, dis cur AP")); + csr_roam_disconnect(mac_ctx, session_id, + eCSR_DISCONNECT_REASON_DEAUTH); + return status; + case SIR_ROAM_SYNCH_PROPAGATION: + break; + case SIR_ROAM_SYNCH_COMPLETE: + /* + * Following operations need to be done once roam sync + * completion is sent to FW, hence called here: + * 1) Firmware has already updated DBS policy. Update connection + * table in the host driver. + * 2) Force SCC switch if needed + * 3) Set connection in progress = false + */ + /* first update connection info from wma interface */ + cds_update_connection_info(session_id); + /* then update remaining parameters from roam sync ctx */ + sms_log(mac_ctx, LOGE, FL("Update DBS hw mode")); + cds_hw_mode_transition_cb( + roam_synch_data->hw_mode_trans_ind.old_hw_mode_index, + roam_synch_data->hw_mode_trans_ind.new_hw_mode_index, + roam_synch_data->hw_mode_trans_ind.num_vdev_mac_entries, + roam_synch_data->hw_mode_trans_ind.vdev_mac_map); + cds_set_connection_in_progress(false); + session->roam_synch_in_progress = false; + cds_check_concurrent_intf_and_restart_sap(session->pContext); + return status; + default: + sms_log(mac_ctx, LOGE, FL("LFR3: callback reason %d"), reason); + return QDF_STATUS_E_FAILURE; + } + session->roam_synch_in_progress = true; + session->roam_synch_data = roam_synch_data; + status = csr_get_parsed_bss_description_ies( + mac_ctx, bss_desc, &ies_local); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sms_log(mac_ctx, LOGE, FL("LFR3: fail to parse IEs")); + session->roam_synch_in_progress = false; + return status; + } + conn_profile = &session->connectedProfile; + csr_roam_stop_network(mac_ctx, session_id, + session->pCurRoamProfile, + bss_desc, + ies_local); + ps_global_info->remain_in_power_active_till_dhcp = false; + session->connectState = eCSR_ASSOC_STATE_TYPE_INFRA_ASSOCIATED; + roam_info = qdf_mem_malloc(sizeof(tCsrRoamInfo)); + if (NULL == roam_info) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + FL("LFR3: Mem Alloc failed for roam info")); + session->roam_synch_in_progress = false; + qdf_mem_free(ies_local); + return QDF_STATUS_E_NOMEM; + } + csr_scan_save_roam_offload_ap_to_scan_cache(mac_ctx, roam_synch_data, + bss_desc); + roam_info->sessionId = session_id; + csr_roam_call_callback(mac_ctx, roam_synch_data->roamedVdevId, + roam_info, 0, eCSR_ROAM_TDLS_STATUS_UPDATE, + eCSR_ROAM_RESULT_DELETE_ALL_TDLS_PEER_IND); + qdf_mem_copy(&roam_info->bssid.bytes, &bss_desc->bssId, + sizeof(struct qdf_mac_addr)); + csr_roam_save_connected_infomation(mac_ctx, session_id, + session->pCurRoamProfile, + bss_desc, + ies_local); + csr_roam_save_security_rsp_ie(mac_ctx, session_id, + session->pCurRoamProfile->negotiatedAuthType, + bss_desc, ies_local); + +#ifdef FEATURE_WLAN_ESE + roam_info->isESEAssoc = conn_profile->isESEAssoc; +#endif + + /* + * Encryption keys for new connection are obtained as follows: + * authStatus = CSR_ROAM_AUTH_STATUS_AUTHENTICATED + * Open - No keys required. + * Static WEP - Firmware copies keys from old AP to new AP. + * Fast roaming authentications e.g. PSK, FT, CCKM - firmware + * supplicant obtains them through 4-way handshake. + * + * authStatus = CSR_ROAM_AUTH_STATUS_CONNECTED + * All other authentications - Host supplicant performs EAPOL + * with AP after this point and sends new keys to the driver. + * Driver starts wait_for_key timer for that purpose. + */ + if ((roam_synch_data->authStatus + == CSR_ROAM_AUTH_STATUS_AUTHENTICATED)) { + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_DEBUG, + FL("LFR3:Don't start waitforkey timer")); + csr_roam_substate_change(mac_ctx, + eCSR_ROAM_SUBSTATE_NONE, session_id); + } else { + roam_info->fAuthRequired = true; + csr_roam_substate_change(mac_ctx, + eCSR_ROAM_SUBSTATE_WAIT_FOR_KEY, + session_id); + + ps_global_info->remain_in_power_active_till_dhcp = true; + mac_ctx->roam.WaitForKeyTimerInfo.sessionId = session_id; + if (!QDF_IS_STATUS_SUCCESS(csr_roam_start_wait_for_key_timer( + mac_ctx, CSR_WAIT_FOR_KEY_TIMEOUT_PERIOD)) + ) { + sms_log(mac_ctx, LOGE, FL + ("Failed wait for key timer start")); + csr_roam_substate_change(mac_ctx, + eCSR_ROAM_SUBSTATE_NONE, + session_id); + } + } + roam_info->nBeaconLength = 0; + roam_info->nAssocReqLength = roam_synch_data->reassoc_req_length - + SIR_MAC_HDR_LEN_3A - SIR_MAC_REASSOC_SSID_OFFSET; + roam_info->nAssocRspLength = roam_synch_data->reassocRespLength - + SIR_MAC_HDR_LEN_3A; + roam_info->pbFrames = qdf_mem_malloc(roam_info->nBeaconLength + + roam_info->nAssocReqLength + roam_info->nAssocRspLength); + if (NULL == roam_info->pbFrames) { + sms_log(mac_ctx, LOGE, FL("no memory available")); + session->roam_synch_in_progress = false; + if (roam_info) + qdf_mem_free(roam_info); + qdf_mem_free(ies_local); + return QDF_STATUS_E_NOMEM; + } + qdf_mem_copy(roam_info->pbFrames, + (uint8_t *)roam_synch_data + + roam_synch_data->reassoc_req_offset + + SIR_MAC_HDR_LEN_3A + SIR_MAC_REASSOC_SSID_OFFSET, + roam_info->nAssocReqLength); + qdf_mem_copy(roam_info->pbFrames + roam_info->nAssocReqLength, + (uint8_t *)roam_synch_data + + roam_synch_data->reassocRespOffset + + SIR_MAC_HDR_LEN_3A, + roam_info->nAssocRspLength); + + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_DEBUG, + FL("LFR3:Clear Connected info")); + csr_roam_free_connected_info(mac_ctx, + &session->connectedInfo); + len = roam_synch_data->join_rsp->parsedRicRspLen; + +#ifdef FEATURE_WLAN_ESE + len += roam_synch_data->join_rsp->tspecIeLen; + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + FL("LFR3: tspecLen %d"), + roam_synch_data->join_rsp->tspecIeLen); +#endif + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + FL("LFR3: RIC length - %d"), + roam_synch_data->join_rsp->parsedRicRspLen); + if (len) { + session->connectedInfo.pbFrames = + qdf_mem_malloc(len); + if (session->connectedInfo.pbFrames != NULL) { + qdf_mem_copy(session->connectedInfo.pbFrames, + roam_synch_data->join_rsp->frames, len); + session->connectedInfo.nRICRspLength = + roam_synch_data->join_rsp->parsedRicRspLen; + +#ifdef FEATURE_WLAN_ESE + session->connectedInfo.nTspecIeLength = + roam_synch_data->join_rsp->tspecIeLen; +#endif + } + } + conn_profile->vht_channel_width = + roam_synch_data->join_rsp->vht_channel_width; + add_bss_params = (tpAddBssParams)roam_synch_data->add_bss_params; + session->connectedInfo.staId = add_bss_params->staContext.staIdx; + roam_info->staId = session->connectedInfo.staId; + roam_info->ucastSig = + (uint8_t) roam_synch_data->join_rsp->ucastSig; + roam_info->bcastSig = + (uint8_t) roam_synch_data->join_rsp->bcastSig; + roam_info->timingMeasCap = + roam_synch_data->join_rsp->timingMeasCap; + roam_info->chan_info.nss = roam_synch_data->join_rsp->nss; + roam_info->chan_info.rate_flags = + roam_synch_data->join_rsp->max_rate_flags; + csr_roam_fill_tdls_info(mac_ctx, roam_info, roam_synch_data->join_rsp); +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH + src_profile = &roam_synch_data->join_rsp->HTProfile; + dst_profile = &conn_profile->HTProfile; + if (mac_ctx->roam.configParam.cc_switch_mode + != QDF_MCC_TO_SCC_SWITCH_DISABLE) + csr_roam_copy_ht_profile(dst_profile, + src_profile); +#endif + assoc_info.pBssDesc = bss_desc; + roam_info->statusCode = eSIR_SME_SUCCESS; + roam_info->reasonCode = eSIR_SME_SUCCESS; + assoc_info.pProfile = session->pCurRoamProfile; + mac_ctx->roam.roamSession[session_id].connectState = + eCSR_ASSOC_STATE_TYPE_NOT_CONNECTED; + sme_qos_csr_event_ind(mac_ctx, session_id, + SME_QOS_CSR_HANDOFF_ASSOC_REQ, NULL); + sme_qos_csr_event_ind(mac_ctx, session_id, + SME_QOS_CSR_REASSOC_REQ, NULL); + sme_qos_csr_event_ind(mac_ctx, session_id, + SME_QOS_CSR_HANDOFF_COMPLETE, NULL); + mac_ctx->roam.roamSession[session_id].connectState = + eCSR_ASSOC_STATE_TYPE_INFRA_ASSOCIATED; + sme_qos_csr_event_ind(mac_ctx, session_id, + SME_QOS_CSR_REASSOC_COMPLETE, &assoc_info); + sme_qos_remove_addts_delts_cmd(mac_ctx, session_id); + roam_info->pBssDesc = bss_desc; + conn_profile->acm_mask = sme_qos_get_acm_mask(mac_ctx, + bss_desc, NULL); + if (conn_profile->modifyProfileFields.uapsd_mask) { + sms_log(mac_ctx, LOG1, + " uapsd_mask (0x%X) set, request UAPSD now", + conn_profile->modifyProfileFields.uapsd_mask); + sme_ps_start_uapsd(mac_ctx, session_id, + NULL, NULL); + } + conn_profile->dot11Mode = session->bssParams.uCfgDot11Mode; + roam_info->u.pConnectedProfile = conn_profile; + + sms_log(mac_ctx, LOG1, + FL("vht ch width %d staId %d nss %d rate_flag %d dot11Mode %d"), + conn_profile->vht_channel_width, + roam_info->staId, + roam_info->chan_info.nss, + roam_info->chan_info.rate_flags, + conn_profile->dot11Mode); + + if (!IS_FEATURE_SUPPORTED_BY_FW + (SLM_SESSIONIZATION) && + (csr_is_concurrent_session_running(mac_ctx))) { + mac_ctx->roam.configParam.doBMPSWorkaround = 1; + } + roam_info->roamSynchInProgress = true; + roam_info->synchAuthStatus = roam_synch_data->authStatus; + qdf_mem_copy(roam_info->kck, roam_synch_data->kck, SIR_KCK_KEY_LEN); + qdf_mem_copy(roam_info->kek, roam_synch_data->kek, SIR_KEK_KEY_LEN); + qdf_mem_copy(roam_info->replay_ctr, roam_synch_data->replay_ctr, + SIR_REPLAY_CTR_LEN); + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + FL("LFR3: Copy KCK, KEK and Replay Ctr")); + roam_info->subnet_change_status = + CSR_GET_SUBNET_STATUS(roam_synch_data->roamReason); + csr_roam_call_callback(mac_ctx, session_id, roam_info, 0, + eCSR_ROAM_ASSOCIATION_COMPLETION, eCSR_ROAM_RESULT_ASSOCIATED); + csr_reset_pmkid_candidate_list(mac_ctx, session_id); +#ifdef FEATURE_WLAN_WAPI + csr_reset_bkid_candidate_list(mac_ctx, session_id); +#endif + if (!CSR_IS_WAIT_FOR_KEY(mac_ctx, session_id)) { + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_DEBUG, + FL + ("NO CSR_IS_WAIT_FOR_KEY -> csr_roam_link_up")); + csr_roam_link_up(mac_ctx, conn_profile->bssid); + } + + session->fRoaming = false; + session->roam_synch_in_progress = false; + qdf_mem_free(roam_info->pbFrames); + qdf_mem_free(roam_info); + qdf_mem_free(ies_local); + + return status; +} + +/** + * csr_roam_synch_callback() - SME level callback for roam synch propagation + * @mac_ctx: MAC Context + * @roam_synch_data: Roam synch data buffer pointer + * @bss_desc: BSS descriptor pointer + * @reason: Reason for calling the callback + * + * This callback is registered with WMA and used after roaming happens in + * firmware and the call to this routine completes the roam synch + * propagation at both CSR and HDD levels. The HDD level propagation + * is achieved through the already defined callback for assoc completion + * handler. + * + * Return: Success or Failure. + */ +QDF_STATUS csr_roam_synch_callback(tpAniSirGlobal mac_ctx, + roam_offload_synch_ind *roam_synch_data, + tpSirBssDescription bss_desc, enum sir_roam_op_code reason) +{ + QDF_STATUS status; + + status = sme_acquire_global_lock(&mac_ctx->sme); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sms_log(mac_ctx, LOGE, FL("LFR3: Locking failed, bailing out")); + return status; + } + + status = csr_process_roam_sync_callback(mac_ctx, roam_synch_data, + bss_desc, reason); + + sme_release_global_lock(&mac_ctx->sme); + + return status; +} +#endif diff --git a/drivers/staging/qcacld-3.0/core/sme/src/csr/csr_api_scan.c b/drivers/staging/qcacld-3.0/core/sme/src/csr/csr_api_scan.c new file mode 100644 index 0000000000000000000000000000000000000000..ea7850fb3c9022b3001e7950a765909f1a9c5272 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/sme/src/csr/csr_api_scan.c @@ -0,0 +1,7743 @@ +/* + * Copyright (c) 2011-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** ------------------------------------------------------------------------- * + ------------------------------------------------------------------------- * + + \file csr_api_scan.c + + Implementation for the Common Scan interfaces. + ========================================================================== */ + +#include "ani_global.h" + +#include "cds_mq.h" +#include "csr_inside_api.h" +#include "sme_inside.h" +#include "sms_debug.h" + +#include "csr_support.h" + +#include "host_diag_core_log.h" +#include "host_diag_core_event.h" + +#include "cds_reg_service.h" +#include "wma_types.h" +#include "cds_utils.h" +#include "cfg_api.h" +#include "wma.h" + +#include "cds_concurrency.h" +#include "wlan_hdd_main.h" +#include "pld_common.h" +#include "csr_internal.h" + +#define MIN_CHN_TIME_TO_FIND_GO 100 +#define MAX_CHN_TIME_TO_FIND_GO 100 +#define DIRECT_SSID_LEN 7 + +/* Purpose of HIDDEN_TIMER +** When we remove hidden ssid from the profile i.e., forget the SSID via GUI that SSID shouldn't see in the profile +** For above requirement we used timer limit, logic is explained below +** Timer value is initialsed to current time when it receives corresponding probe response of hidden SSID (The probe request is +** received regularly till SSID in the profile. Once it is removed from profile probe request is not sent.) when we receive probe response +** for broadcast probe request, during update SSID with saved SSID we will diff current time with saved SSID time if it is greater than 1 min +** then we are not updating with old one +*/ + +#define HIDDEN_TIMER (1*60*1000) +#define CSR_SCAN_RESULT_RSSI_WEIGHT 80 /* must be less than 100, represent the persentage of new RSSI */ +#define CSR_PURGE_RSSI_THRESHOLD -70 + +#define MAX_ACTIVE_SCAN_FOR_ONE_CHANNEL 140 +#define MIN_ACTIVE_SCAN_FOR_ONE_CHANNEL 120 + +#define MAX_ACTIVE_SCAN_FOR_ONE_CHANNEL_FASTREASSOC 30 +#define MIN_ACTIVE_SCAN_FOR_ONE_CHANNEL_FASTREASSOC 20 + +#define PCL_ADVANTAGE 20 +#define PCL_RSSI_THRESHOLD -75 + +#define CSR_SCAN_IS_OVER_BSS_LIMIT(pMac) \ + ((pMac)->scan.nBssLimit <= (csr_ll_count(&(pMac)->scan.scanResultList))) + +void csr_scan_get_result_timer_handler(void *); +static void csr_set_default_scan_timing(tpAniSirGlobal pMac, tSirScanType scanType, + tCsrScanRequest *pScanRequest); +#ifdef WLAN_AP_STA_CONCURRENCY +static void csr_sta_ap_conc_timer_handler(void *); +#endif +bool csr_is_supported_channel(tpAniSirGlobal pMac, uint8_t channelId); +QDF_STATUS csr_scan_channels(tpAniSirGlobal pMac, tSmeCmd *pCommand); +void csr_set_cfg_valid_channel_list(tpAniSirGlobal pMac, uint8_t *pChannelList, + uint8_t NumChannels); +void csr_save_tx_power_to_cfg(tpAniSirGlobal pMac, tDblLinkList *pList, + uint32_t cfgId); +void csr_set_cfg_country_code(tpAniSirGlobal pMac, uint8_t *countryCode); +void csr_purge_channel_power(tpAniSirGlobal pMac, tDblLinkList *pChannelList); +void csr_release_scan_command(tpAniSirGlobal pMac, tSmeCmd *pCommand, + eCsrScanStatus scanStatus); +static bool csr_scan_validate_scan_result(tpAniSirGlobal pMac, uint8_t *pChannels, + uint8_t numChn, + tSirBssDescription *pBssDesc, + tDot11fBeaconIEs **ppIes); +bool csr_roam_is_valid_channel(tpAniSirGlobal pMac, uint8_t channel); +static void csr_purge_scan_result_by_age(void *pv); + +#define CSR_IS_SOCIAL_CHANNEL(channel) \ + (((channel) == 1) || ((channel) == 6) || ((channel) == 11)) + +static void csr_release_scan_cmd_pending_list(tpAniSirGlobal pMac) +{ + tListElem *pEntry; + tSmeCmd *pCommand; + + while ((pEntry = + csr_ll_remove_head(&pMac->scan.scanCmdPendingList, + LL_ACCESS_LOCK)) != NULL) { + pCommand = GET_BASE_ADDR(pEntry, tSmeCmd, Link); + if (eSmeCsrCommandMask & pCommand->command) { + csr_abort_command(pMac, pCommand, true); + } else { + sms_log(pMac, LOGE, FL("Error: Received command : %d"), + pCommand->command); + } + } +} + +/* pResult is invalid calling this function. */ +void csr_free_scan_result_entry(tpAniSirGlobal pMac, tCsrScanResult *pResult) +{ + if (NULL != pResult->Result.pvIes) { + qdf_mem_free(pResult->Result.pvIes); + } + qdf_mem_free(pResult); +} + +static QDF_STATUS csr_ll_scan_purge_result(tpAniSirGlobal pMac, + tDblLinkList *pList) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tListElem *pEntry; + tCsrScanResult *pBssDesc; + + csr_ll_lock(pList); + + while ((pEntry = csr_ll_remove_head(pList, LL_ACCESS_NOLOCK)) != NULL) { + pBssDesc = GET_BASE_ADDR(pEntry, tCsrScanResult, Link); + csr_free_scan_result_entry(pMac, pBssDesc); + } + + csr_ll_unlock(pList); + + return status; +} + +QDF_STATUS csr_scan_open(tpAniSirGlobal mac_ctx) +{ + QDF_STATUS status; + + csr_ll_open(mac_ctx->hHdd, &mac_ctx->scan.scanResultList); + csr_ll_open(mac_ctx->hHdd, &mac_ctx->scan.tempScanResults); + csr_ll_open(mac_ctx->hHdd, &mac_ctx->scan.channelPowerInfoList24); + csr_ll_open(mac_ctx->hHdd, &mac_ctx->scan.channelPowerInfoList5G); +#ifdef WLAN_AP_STA_CONCURRENCY + csr_ll_open(mac_ctx->hHdd, &mac_ctx->scan.scanCmdPendingList); +#endif + mac_ctx->scan.fFullScanIssued = false; + mac_ctx->scan.nBssLimit = CSR_MAX_BSS_SUPPORT; +#ifdef WLAN_AP_STA_CONCURRENCY + status = qdf_mc_timer_init(&mac_ctx->scan.hTimerStaApConcTimer, + QDF_TIMER_TYPE_SW, + csr_sta_ap_conc_timer_handler, + mac_ctx); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sms_log(mac_ctx, LOGE, + FL("Mem Alloc failed for hTimerStaApConcTimer timer")); + return status; + } +#endif + return status; +} + +QDF_STATUS csr_scan_close(tpAniSirGlobal pMac) +{ + csr_ll_scan_purge_result(pMac, &pMac->scan.tempScanResults); + csr_ll_scan_purge_result(pMac, &pMac->scan.scanResultList); +#ifdef WLAN_AP_STA_CONCURRENCY + csr_release_scan_cmd_pending_list(pMac); +#endif + csr_ll_close(&pMac->scan.scanResultList); + csr_ll_close(&pMac->scan.tempScanResults); +#ifdef WLAN_AP_STA_CONCURRENCY + csr_ll_close(&pMac->scan.scanCmdPendingList); +#endif + csr_purge_channel_power(pMac, &pMac->scan.channelPowerInfoList24); + csr_purge_channel_power(pMac, &pMac->scan.channelPowerInfoList5G); + csr_ll_close(&pMac->scan.channelPowerInfoList24); + csr_ll_close(&pMac->scan.channelPowerInfoList5G); + csr_scan_disable(pMac); +#ifdef WLAN_AP_STA_CONCURRENCY + qdf_mc_timer_destroy(&pMac->scan.hTimerStaApConcTimer); +#endif + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS csr_scan_enable(tpAniSirGlobal pMac) +{ + + pMac->scan.fScanEnable = true; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS csr_scan_disable(tpAniSirGlobal pMac) +{ + pMac->scan.fScanEnable = false; + + return QDF_STATUS_SUCCESS; +} + +/* Set scan timing parameters according to state of other driver sessions */ +/* No validation of the parameters is performed. */ +static void csr_set_default_scan_timing(tpAniSirGlobal pMac, tSirScanType scanType, + tCsrScanRequest *pScanRequest) +{ +#ifdef WLAN_AP_STA_CONCURRENCY + if (csr_is_any_session_connected(pMac)) { + /* Reset passive scan time as per ini parameter. */ + cfg_set_int(pMac, WNI_CFG_PASSIVE_MAXIMUM_CHANNEL_TIME, + pMac->roam.configParam.nPassiveMaxChnTimeConc); + /* If multi-session, use the appropriate default scan times */ + if (scanType == eSIR_ACTIVE_SCAN) { + pScanRequest->maxChnTime = + pMac->roam.configParam.nActiveMaxChnTimeConc; + pScanRequest->minChnTime = + pMac->roam.configParam.nActiveMinChnTimeConc; + } else { + pScanRequest->maxChnTime = + pMac->roam.configParam.nPassiveMaxChnTimeConc; + pScanRequest->minChnTime = + pMac->roam.configParam.nPassiveMinChnTimeConc; + } + pScanRequest->restTime = pMac->roam.configParam.nRestTimeConc; + + pScanRequest->min_rest_time = + pMac->roam.configParam.min_rest_time_conc; + pScanRequest->idle_time = + pMac->roam.configParam.idle_time_conc; + + /* Return so that fields set above will not be overwritten. */ + return; + } +#endif + + /* This portion of the code executed if multi-session not supported */ + /* (WLAN_AP_STA_CONCURRENCY not defined) or no multi-session. */ + /* Use the "regular" (non-concurrency) default scan timing. */ + cfg_set_int(pMac, WNI_CFG_PASSIVE_MAXIMUM_CHANNEL_TIME, + pMac->roam.configParam.nPassiveMaxChnTime); + if (pScanRequest->scanType == eSIR_ACTIVE_SCAN) { + pScanRequest->maxChnTime = + pMac->roam.configParam.nActiveMaxChnTime; + pScanRequest->minChnTime = + pMac->roam.configParam.nActiveMinChnTime; + } else { + pScanRequest->maxChnTime = + pMac->roam.configParam.nPassiveMaxChnTime; + pScanRequest->minChnTime = + pMac->roam.configParam.nPassiveMinChnTime; + } +#ifdef WLAN_AP_STA_CONCURRENCY + + /* No rest time/Idle time if no sessions are connected. */ + pScanRequest->restTime = 0; + pScanRequest->min_rest_time = 0; + pScanRequest->idle_time = 0; + +#endif +} + +/** + * csr_scan_2g_only_request() - This function will update the scan request with + * only 2.4GHz valid channel list. + * @mac_ctx: Pointer to Global MAC structure + * @scan_cmd scan cmd + * @scan_req scan req + * + * This function will update the scan request with only 2.4GHz valid channel + * list. + * + * @Return: status of operation + */ +static QDF_STATUS +csr_scan_2g_only_request(tpAniSirGlobal mac_ctx, + tSmeCmd *scan_cmd, + tCsrScanRequest *scan_req) +{ + uint8_t idx, lst_sz = 0; + + QDF_ASSERT(scan_cmd && scan_req); + /* To silence the KW tool null check is added */ + if ((scan_cmd == NULL) || (scan_req == NULL)) { + sms_log(mac_ctx, LOGE, + FL(" Scan Cmd or Scan Request is NULL ")); + return QDF_STATUS_E_INVAL; + } + + if (eCSR_SCAN_REQUEST_FULL_SCAN != scan_req->requestType) + return QDF_STATUS_SUCCESS; + + sms_log(mac_ctx, LOG1, + FL("Scanning only 2G Channels during first scan")); + + /* Contsruct valid Supported 2.4 GHz Channel List */ + if (NULL == scan_req->ChannelInfo.ChannelList) { + scan_req->ChannelInfo.ChannelList = + qdf_mem_malloc(NUM_24GHZ_CHANNELS); + if (NULL == scan_req->ChannelInfo.ChannelList) { + sms_log(mac_ctx, LOGE, FL("Memory allocation failed.")); + return QDF_STATUS_E_NOMEM; + } + for (idx = 1; idx <= NUM_24GHZ_CHANNELS; idx++) { + if (csr_is_supported_channel(mac_ctx, idx)) { + scan_req->ChannelInfo.ChannelList[lst_sz] = idx; + lst_sz++; + } + } + } else { + for (idx = 0; + idx < scan_req->ChannelInfo.numOfChannels; + idx++) { + if (scan_req->ChannelInfo.ChannelList[idx] <= + CDS_24_GHZ_CHANNEL_14 + && csr_is_supported_channel(mac_ctx, + scan_req->ChannelInfo.ChannelList[idx])) { + scan_req->ChannelInfo.ChannelList[lst_sz] = + scan_req->ChannelInfo.ChannelList[idx]; + lst_sz++; + } + } + } + scan_req->ChannelInfo.numOfChannels = lst_sz; + return QDF_STATUS_SUCCESS; +} + +static void +csr_set_scan_reason(tSmeCmd *scan_cmd, eCsrRequestType req_type) +{ + switch (req_type) { + case eCSR_SCAN_REQUEST_11D_SCAN: + scan_cmd->u.scanCmd.reason = eCsrScan11d1; + break; +#ifdef SOFTAP_CHANNEL_RANGE + case eCSR_SCAN_SOFTAP_CHANNEL_RANGE: +#endif + case eCSR_SCAN_REQUEST_FULL_SCAN: + case eCSR_SCAN_P2P_DISCOVERY: + scan_cmd->u.scanCmd.reason = eCsrScanUserRequest; + break; + case eCSR_SCAN_HO_PROBE_SCAN: + scan_cmd->u.scanCmd.reason = eCsrScanProbeBss; + break; + case eCSR_SCAN_P2P_FIND_PEER: + scan_cmd->u.scanCmd.reason = eCsrScanP2PFindPeer; + break; + default: + break; + } +} + +static QDF_STATUS +csr_issue_11d_scan(tpAniSirGlobal mac_ctx, tSmeCmd *scan_cmd, + tCsrScanRequest *scan_req, uint16_t session_id) +{ + QDF_STATUS status; + tSmeCmd *scan_11d_cmd = NULL; + tCsrScanRequest tmp_rq; + tCsrChannelInfo *chn_info = &tmp_rq.ChannelInfo; + uint32_t num_chn = mac_ctx->scan.base_channels.numChannels; + tCsrRoamSession *csr_session = CSR_GET_SESSION(mac_ctx, session_id); + + if (csr_session == NULL) { + sms_log(mac_ctx, LOGE, FL("session %d not found"), + session_id); + QDF_ASSERT(0); + return QDF_STATUS_E_FAILURE; + } + + if (num_chn > WNI_CFG_VALID_CHANNEL_LIST_LEN) { + sms_log(mac_ctx, LOGE, FL("invalid number of channels: %d"), + num_chn); + return QDF_STATUS_E_FAILURE; + } + + if (!(((false == mac_ctx->first_scan_done) + && (eCSR_SCAN_REQUEST_11D_SCAN != scan_req->requestType)) +#ifdef SOFTAP_CHANNEL_RANGE + && (eCSR_SCAN_SOFTAP_CHANNEL_RANGE != scan_req->requestType) +#endif + && (false == mac_ctx->scan.fEnableBypass11d))) + return QDF_STATUS_SUCCESS; + + qdf_mem_set(&tmp_rq, sizeof(tCsrScanRequest), 0); + scan_11d_cmd = csr_get_command_buffer(mac_ctx); + if (!scan_11d_cmd) { + sms_log(mac_ctx, LOGE, FL("scan_11d_cmd failed")); + return QDF_STATUS_E_FAILURE; + } + + qdf_mem_set(&scan_11d_cmd->u.scanCmd, sizeof(tScanCmd), 0); + chn_info->ChannelList = qdf_mem_malloc(num_chn); + if (NULL == chn_info->ChannelList) { + sms_log(mac_ctx, LOGE, FL("Failed to allocate memory")); + return QDF_STATUS_E_NOMEM; + } + qdf_mem_copy(chn_info->ChannelList, + mac_ctx->scan.base_channels.channelList, num_chn); + + chn_info->numOfChannels = (uint8_t) num_chn; + scan_11d_cmd->command = eSmeCommandScan; + scan_11d_cmd->u.scanCmd.callback = mac_ctx->scan.callback11dScanDone; + scan_11d_cmd->u.scanCmd.pContext = NULL; + wma_get_scan_id(&scan_11d_cmd->u.scanCmd.scanID); + tmp_rq.BSSType = eCSR_BSS_TYPE_ANY; + tmp_rq.scan_id = scan_11d_cmd->u.scanCmd.scanID; + + status = qdf_mc_timer_init(&scan_cmd->u.scanCmd.csr_scan_timer, + QDF_TIMER_TYPE_SW, + csr_scan_active_list_timeout_handle, scan_11d_cmd); + + if (csr_is11d_supported(mac_ctx)) { + tmp_rq.bcnRptReqScan = scan_req->bcnRptReqScan; + if (scan_req->bcnRptReqScan) + tmp_rq.scanType = scan_req->scanType ? + eSIR_PASSIVE_SCAN : scan_req->scanType; + else + tmp_rq.scanType = eSIR_PASSIVE_SCAN; + tmp_rq.requestType = eCSR_SCAN_REQUEST_11D_SCAN; + scan_11d_cmd->u.scanCmd.reason = eCsrScan11d1; + tmp_rq.maxChnTime = + mac_ctx->roam.configParam.nPassiveMaxChnTime; + tmp_rq.minChnTime = + mac_ctx->roam.configParam.nPassiveMinChnTime; + } else { + tmp_rq.bcnRptReqScan = scan_req->bcnRptReqScan; + if (scan_req->bcnRptReqScan) + tmp_rq.scanType = scan_req->scanType; + else + tmp_rq.scanType = eSIR_ACTIVE_SCAN; + tmp_rq.requestType = scan_req->requestType; + scan_11d_cmd->u.scanCmd.reason = scan_cmd->u.scanCmd.reason; + tmp_rq.maxChnTime = mac_ctx->roam.configParam.nActiveMaxChnTime; + tmp_rq.minChnTime = mac_ctx->roam.configParam.nActiveMinChnTime; + } + if (mac_ctx->roam.configParam.nInitialDwellTime) { + tmp_rq.maxChnTime = mac_ctx->roam.configParam.nInitialDwellTime; + sms_log(mac_ctx, LOG1, FL("11d scan, updating dwell time for first scan %u"), + tmp_rq.maxChnTime); + } + + status = csr_scan_copy_request(mac_ctx, + &scan_11d_cmd->u.scanCmd.u.scanRequest, &tmp_rq); + /* Free the channel list */ + qdf_mem_free(chn_info->ChannelList); + chn_info->ChannelList = NULL; + if (!QDF_IS_STATUS_SUCCESS(status)) { + sms_log(mac_ctx, LOGE, FL("csr_scan_copy_request failed")); + return QDF_STATUS_E_FAILURE; + } + + mac_ctx->scan.scanProfile.numOfChannels = + scan_11d_cmd->u.scanCmd.u.scanRequest.ChannelInfo.numOfChannels; + + + status = csr_queue_sme_command(mac_ctx, scan_11d_cmd, false); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sms_log(mac_ctx, LOGE, FL("Failed to send message status = %d"), + status); + return QDF_STATUS_E_FAILURE; + } + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS csr_scan_request(tpAniSirGlobal pMac, uint16_t sessionId, + tCsrScanRequest *scan_req, + csr_scan_completeCallback callback, void *pContext) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tSmeCmd *scan_cmd = NULL; + tCsrScanRequest *pTempScanReq = NULL; + tCsrConfig *cfg_prm = &pMac->roam.configParam; + + if (scan_req == NULL) { + sms_log(pMac, LOGE, FL("scan_req is NULL")); + QDF_ASSERT(0); + return status; + } + + /* + * During group formation, the P2P client scans for GO with the specific + * SSID. There will be chances of GO switching to other channels because + * of scan or to STA channel in case of STA+GO MCC scenario. So to + * increase the possibility of client to find the GO, the dwell time of + * scan is increased to 100ms. + * If the scan request is for specific SSId the length of SSID will be + * greater than 7 as SSID for p2p search contains "DIRECT-") + */ + if (scan_req->p2pSearch + && scan_req->SSIDs.numOfSSIDs + && (NULL != scan_req->SSIDs.SSIDList) + && (scan_req->SSIDs.SSIDList->SSID.length > DIRECT_SSID_LEN)) { + sms_log(pMac, LOG1, FL("P2P: Increasing the min and max Dwell time to %d for specific SSID scan %.*s"), + MAX_CHN_TIME_TO_FIND_GO, + scan_req->SSIDs.SSIDList->SSID.length, + scan_req->SSIDs.SSIDList->SSID.ssId); + scan_req->maxChnTime = MAX_CHN_TIME_TO_FIND_GO; + scan_req->minChnTime = MIN_CHN_TIME_TO_FIND_GO; + } + + if (!pMac->scan.fScanEnable) { + sms_log(pMac, LOGE, FL("SId: %d Scanning not enabled Scan type=%u, numOfSSIDs=%d P2P search=%d"), + sessionId, scan_req->requestType, + scan_req->SSIDs.numOfSSIDs, + scan_req->p2pSearch); + goto release_cmd; + } + + scan_cmd = csr_get_command_buffer(pMac); + if (!scan_cmd) { + sms_log(pMac, LOGE, FL("scan_cmd is NULL")); + goto release_cmd; + } + + qdf_mem_set(&scan_cmd->u.scanCmd, sizeof(tScanCmd), 0); + scan_cmd->command = eSmeCommandScan; + scan_cmd->sessionId = sessionId; + if (scan_cmd->sessionId >= CSR_ROAM_SESSION_MAX) + sms_log(pMac, LOGE, FL("Invalid Sme SessionID: %d"), sessionId); + scan_cmd->u.scanCmd.callback = callback; + scan_cmd->u.scanCmd.pContext = pContext; + csr_set_scan_reason(scan_cmd, scan_req->requestType); + if (scan_req->minChnTime == 0 && scan_req->maxChnTime == 0) { + /* The caller doesn't set the time correctly. Set it here */ + csr_set_default_scan_timing(pMac, scan_req->scanType, scan_req); + sms_log(pMac, LOG1, + FL("Setting default min %d and max %d ChnTime"), + scan_req->minChnTime, scan_req->maxChnTime); + } +#ifdef WLAN_AP_STA_CONCURRENCY + /* + * Need to set restTime/min_Ret_time/idle_time + * only if at least one session is connected + */ + if (scan_req->restTime == 0 && csr_is_any_session_connected(pMac)) { + scan_req->restTime = cfg_prm->nRestTimeConc; + scan_req->min_rest_time = cfg_prm->min_rest_time_conc; + scan_req->idle_time = cfg_prm->idle_time_conc; + if (scan_req->scanType == eSIR_ACTIVE_SCAN) { + scan_req->maxChnTime = cfg_prm->nActiveMaxChnTimeConc; + scan_req->minChnTime = cfg_prm->nActiveMinChnTimeConc; + } else { + scan_req->maxChnTime = cfg_prm->nPassiveMaxChnTimeConc; + scan_req->minChnTime = cfg_prm->nPassiveMinChnTimeConc; + } + } +#endif + /* Increase dwell time in case P2P Search and Miracast is not present */ + if (scan_req->p2pSearch && scan_req->ChannelInfo.numOfChannels + == P2P_SOCIAL_CHANNELS && (!(pMac->sme.miracast_value))) { + scan_req->maxChnTime += P2P_SEARCH_DWELL_TIME_INCREASE; + } + scan_cmd->u.scanCmd.scanID = scan_req->scan_id; + /* + * If it is the first scan request from HDD, CSR checks if it is for 11d + * If it is not, CSR will save the scan request in the pending cmd queue + * & issue an 11d scan request to PE. + */ + status = csr_issue_11d_scan(pMac, scan_cmd, scan_req, sessionId); + if (status != QDF_STATUS_SUCCESS) + goto release_cmd; + + /* + * Scan only 2G Channels if set in ini file. This is mainly to reduce + * the First Scan duration once we turn on Wifi + */ + if (pMac->scan.fFirstScanOnly2GChnl + && false == pMac->first_scan_done) { + csr_scan_2g_only_request(pMac, scan_cmd, scan_req); + pMac->first_scan_done = true; + } + + + if (cfg_prm->nInitialDwellTime) { + scan_req->maxChnTime = cfg_prm->nInitialDwellTime; + cfg_prm->nInitialDwellTime = 0; + sms_log(pMac, LOG1, FL("updating dwell time for first scan %u"), + scan_req->maxChnTime); + } + scan_req->scan_adaptive_dwell_mode = cfg_prm->scan_adaptive_dwell_mode; + + status = csr_scan_copy_request(pMac, &scan_cmd->u.scanCmd.u.scanRequest, + scan_req); + /* + * Reset the variable after the first scan is queued after loading the + * driver. The purpose of this parameter is that DFS channels are + * skipped during the first scan after loading the driver. The above API + * builds the target scan request in which this variable is used. + */ + cfg_prm->initial_scan_no_dfs_chnl = 0; + if (!QDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOGE, + FL("fail to copy request status = %d"), status); + goto release_cmd; + } + + pTempScanReq = &scan_cmd->u.scanCmd.u.scanRequest; + pMac->scan.scanProfile.numOfChannels = + pTempScanReq->ChannelInfo.numOfChannels; + status = qdf_mc_timer_init(&scan_cmd->u.scanCmd.csr_scan_timer, + QDF_TIMER_TYPE_SW, + csr_scan_active_list_timeout_handle, scan_cmd); + sms_log(pMac, LOG1, + FL("SId=%d scanId=%d Scan reason=%u numSSIDs=%d numChan=%d P2P search=%d minCT=%d maxCT=%d uIEFieldLen=%d BSSID: " MAC_ADDRESS_STR), + sessionId, scan_cmd->u.scanCmd.scanID, + scan_cmd->u.scanCmd.reason, pTempScanReq->SSIDs.numOfSSIDs, + pTempScanReq->ChannelInfo.numOfChannels, + pTempScanReq->p2pSearch, pTempScanReq->minChnTime, + pTempScanReq->maxChnTime, pTempScanReq->uIEFieldLen, + MAC_ADDR_ARRAY(scan_cmd->u.scanCmd.u.scanRequest.bssid.bytes)); + + status = csr_queue_sme_command(pMac, scan_cmd, false); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOGE, + FL("fail to send message status = %d"), status); + } + +release_cmd: + if (!QDF_IS_STATUS_SUCCESS(status) && scan_cmd) { + sms_log(pMac, LOGE, FL(" SId: %d Failed with status=%d" + " Scan reason=%u numOfSSIDs=%d" + " P2P search=%d scanId=%d"), + sessionId, status, scan_cmd->u.scanCmd.reason, + scan_req->SSIDs.numOfSSIDs, scan_req->p2pSearch, + scan_cmd->u.scanCmd.scanID); + csr_release_command_scan(pMac, scan_cmd); + } + + return status; +} + +static QDF_STATUS csr_issue_roam_after_lostlink_scan(tpAniSirGlobal pMac, + uint32_t sessionId, + eCsrRoamReason reason) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tScanResultHandle hBSSList = NULL; + tCsrScanResultFilter *pScanFilter = NULL; + uint32_t roamId = 0; + tCsrRoamProfile *pProfile = NULL; + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!pSession) { + sms_log(pMac, LOGE, FL("session %d not found"), sessionId); + return QDF_STATUS_E_FAILURE; + } + + sms_log(pMac, LOG1, FL("Entry")); + if (pSession->fCancelRoaming) { + sms_log(pMac, LOGW, FL("lost link roaming canceled")); + status = QDF_STATUS_SUCCESS; + goto free_filter; + } + /* Here is the profile we need to connect to */ + pScanFilter = qdf_mem_malloc(sizeof(tCsrScanResultFilter)); + if (NULL == pScanFilter) { + status = QDF_STATUS_E_NOMEM; + goto free_filter; + } + if (NULL == pSession->pCurRoamProfile) { + pScanFilter->EncryptionType.numEntries = 1; + pScanFilter->EncryptionType.encryptionType[0] = + eCSR_ENCRYPT_TYPE_NONE; + } else { + /* + * We have to make a copy of pCurRoamProfile because it will + * be free inside csr_roam_issue_connect + */ + pProfile = qdf_mem_malloc(sizeof(tCsrRoamProfile)); + if (NULL == pProfile) { + status = QDF_STATUS_E_NOMEM; + goto free_filter; + } + status = csr_roam_copy_profile(pMac, pProfile, + pSession->pCurRoamProfile); + if (!QDF_IS_STATUS_SUCCESS(status)) + goto free_filter; + status = csr_roam_prepare_filter_from_profile(pMac, pProfile, + pScanFilter); + } /* We have a profile */ + roamId = GET_NEXT_ROAM_ID(&pMac->roam); + if (!QDF_IS_STATUS_SUCCESS(status)) + goto free_filter; + + status = csr_scan_get_result(pMac, pScanFilter, &hBSSList); + if (!QDF_IS_STATUS_SUCCESS(status)) + goto free_filter; + + if (eCsrLostLink1 == reason) { + /* if possible put the last connected BSS in beginning */ + csr_move_bss_to_head_from_bssid(pMac, + &pSession->connectedProfile.bssid, hBSSList); + } + status = csr_roam_issue_connect(pMac, sessionId, pProfile, hBSSList, + reason, roamId, true, true); + if (!QDF_IS_STATUS_SUCCESS(status)) { + csr_scan_result_purge(pMac, hBSSList); + } + +free_filter: + if (pScanFilter) { + /* we need to free memory for filter if profile exists */ + csr_free_scan_filter(pMac, pScanFilter); + qdf_mem_free(pScanFilter); + } + if (NULL != pProfile) { + csr_release_profile(pMac, pProfile); + qdf_mem_free(pProfile); + } + return status; +} + +QDF_STATUS csr_scan_handle_failed_lostlink1(tpAniSirGlobal pMac, + uint32_t sessionId) +{ + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!pSession) { + sms_log(pMac, LOGE, FL("session %d not found"), sessionId); + return QDF_STATUS_E_FAILURE; + } + sms_log(pMac, LOGW, "Lost link scan 1 failed"); + if (pSession->fCancelRoaming) + return QDF_STATUS_E_FAILURE; + if (!pSession->pCurRoamProfile) + return csr_scan_request_lost_link3(pMac, sessionId); + /* + * We fail lostlink1 but there may be other BSS in the cached result + * fit the profile. Give it a try first + */ + if (pSession->pCurRoamProfile->SSIDs.numOfSSIDs == 0 || + pSession->pCurRoamProfile->SSIDs.numOfSSIDs > 1) + /* try lostlink scan2 */ + return csr_scan_request_lost_link2(pMac, sessionId); + if (!pSession->pCurRoamProfile->ChannelInfo.ChannelList + || pSession->pCurRoamProfile->ChannelInfo.ChannelList[0] == 0) { + /* go straight to lostlink scan3 */ + return csr_scan_request_lost_link3(pMac, sessionId); + } + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS csr_scan_handle_failed_lostlink2(tpAniSirGlobal pMac, + uint32_t sessionId) +{ + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!pSession) { + sms_log(pMac, LOGE, FL("session %d not found"), sessionId); + return QDF_STATUS_E_FAILURE; + } + + sms_log(pMac, LOGW, "Lost link scan 2 failed"); + if (pSession->fCancelRoaming) + return QDF_STATUS_E_FAILURE; + + if (!pSession->pCurRoamProfile + || !pSession->pCurRoamProfile->ChannelInfo.ChannelList + || pSession->pCurRoamProfile->ChannelInfo.ChannelList[0] == 0) { + /* try lostlink scan3 */ + return csr_scan_request_lost_link3(pMac, sessionId); + } + return QDF_STATUS_E_FAILURE; +} + +QDF_STATUS csr_scan_handle_failed_lostlink3(tpAniSirGlobal pMac, + uint32_t sessionId) +{ + sms_log(pMac, LOGW, "Lost link scan 3 failed"); + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS +csr_update_lost_link1_cmd(tpAniSirGlobal mac_ctx, tSmeCmd *cmd, + tCsrRoamSession *pSession, uint32_t session_id) +{ + uint8_t i, num_ch = 0; + tScanResultHandle bss_lst = NULL; + tCsrScanResultInfo *scan_result = NULL; + tCsrScanResultFilter *scan_filter = NULL; + QDF_STATUS status = QDF_STATUS_SUCCESS; + tCsrSSIDs *ssid_list = &cmd->u.scanCmd.u.scanRequest.SSIDs; + tCsrChannelInfo *ch_info = &cmd->u.scanCmd.u.scanRequest.ChannelInfo; + + cmd->command = eSmeCommandScan; + cmd->sessionId = (uint8_t) session_id; + cmd->u.scanCmd.reason = eCsrScanLostLink1; + cmd->u.scanCmd.callback = NULL; + cmd->u.scanCmd.pContext = NULL; + cmd->u.scanCmd.u.scanRequest.maxChnTime = + mac_ctx->roam.configParam.nActiveMaxChnTime; + cmd->u.scanCmd.u.scanRequest.minChnTime = + mac_ctx->roam.configParam.nActiveMinChnTime; + cmd->u.scanCmd.u.scanRequest.scanType = eSIR_ACTIVE_SCAN; + wma_get_scan_id(&cmd->u.scanCmd.scanID); + status = qdf_mc_timer_init(&cmd->u.scanCmd.csr_scan_timer, + QDF_TIMER_TYPE_SW, + csr_scan_active_list_timeout_handle, cmd); + cmd->u.scanCmd.u.scanRequest.scan_id = + cmd->u.scanCmd.scanID; + + if (pSession->connectedProfile.SSID.length) { + /* + * on error: following memory will be released by call to + * csr_release_command_scan in the end + */ + ssid_list->SSIDList = qdf_mem_malloc(sizeof(tCsrSSIDInfo)); + if (NULL == ssid_list->SSIDList) + return QDF_STATUS_E_NOMEM; + ssid_list->numOfSSIDs = 1; + qdf_mem_copy(&ssid_list->SSIDList[0].SSID, + &pSession->connectedProfile.SSID, + sizeof(tSirMacSSid)); + } else { + ssid_list->numOfSSIDs = 0; + } + + if (!pSession->pCurRoamProfile) + return QDF_STATUS_SUCCESS; + + scan_filter = qdf_mem_malloc(sizeof(tCsrScanResultFilter)); + if (NULL == scan_filter) + return QDF_STATUS_E_NOMEM; + + status = csr_roam_prepare_filter_from_profile(mac_ctx, + pSession->pCurRoamProfile, scan_filter); + if (!QDF_IS_STATUS_SUCCESS(status)) + goto free_lost_link1_local_mem; + + if (!(QDF_IS_STATUS_SUCCESS(csr_scan_get_result(mac_ctx, scan_filter, + &bss_lst)) && bss_lst)) { + if (csr_roam_is_channel_valid(mac_ctx, + pSession->connectedProfile.operationChannel)) { + ch_info->ChannelList = qdf_mem_malloc(1); + if (NULL == ch_info->ChannelList) { + status = QDF_STATUS_E_NOMEM; + goto free_lost_link1_local_mem; + } + ch_info->ChannelList[0] = + pSession->connectedProfile.operationChannel; + ch_info->numOfChannels = 1; + } + csr_free_scan_filter(mac_ctx, scan_filter); + qdf_mem_free(scan_filter); + return status; + } + + /* on error: this mem will be released by csr_release_command_scan */ + ch_info->ChannelList = qdf_mem_malloc(WNI_CFG_VALID_CHANNEL_LIST_LEN); + if (NULL == ch_info->ChannelList) { + status = QDF_STATUS_E_NOMEM; + goto free_lost_link1_local_mem; + } + + scan_result = csr_scan_result_get_next(mac_ctx, bss_lst); + while (scan_result != NULL && num_ch < WNI_CFG_VALID_CHANNEL_LIST_LEN) { + for (i = 0; i < num_ch; i++) { + if (ch_info->ChannelList[i] == + scan_result->BssDescriptor.channelId) + break; + } + if (i == num_ch) + ch_info->ChannelList[num_ch++] = + scan_result->BssDescriptor.channelId; + scan_result = csr_scan_result_get_next(mac_ctx, bss_lst); + } + /* Include the last connected BSS' channel */ + if (csr_roam_is_channel_valid(mac_ctx, + pSession->connectedProfile.operationChannel)) { + for (i = 0; i < num_ch; i++) { + if (ch_info->ChannelList[i] == + pSession->connectedProfile.operationChannel) + break; + } + if (i == num_ch) + ch_info->ChannelList[num_ch++] = + pSession->connectedProfile.operationChannel; + } + ch_info->numOfChannels = num_ch; +free_lost_link1_local_mem: + if (scan_filter) { + csr_free_scan_filter(mac_ctx, scan_filter); + qdf_mem_free(scan_filter); + } + if (bss_lst) + csr_scan_result_purge(mac_ctx, bss_lst); + return status; +} + +/** + * csr_scan_request_lost_link1() - start scan on link lost 1 + * @mac_ctx: mac global context + * @session_id: session id + * + * Lostlink1 scan is to actively scan the last connected profile's SSID on all + * matched BSS channels. If no roam profile (it should not), it is like + * lostlinkscan3 + * + * Return: status of operation + */ +QDF_STATUS +csr_scan_request_lost_link1(tpAniSirGlobal mac_ctx, uint32_t session_id) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tSmeCmd *cmd = NULL; + tCsrRoamSession *session = CSR_GET_SESSION(mac_ctx, session_id); + + if (!session) { + sms_log(mac_ctx, LOGE, FL("session %d not found"), session_id); + return QDF_STATUS_E_FAILURE; + } + + sms_log(mac_ctx, LOGW, FL("Entry")); + cmd = csr_get_command_buffer(mac_ctx); + if (!cmd) { + status = QDF_STATUS_E_RESOURCES; + goto release_lost_link1_cmd; + } + qdf_mem_set(&cmd->u.scanCmd, sizeof(tScanCmd), 0); + status = csr_update_lost_link1_cmd(mac_ctx, cmd, session, session_id); + if (!QDF_IS_STATUS_SUCCESS(status)) + goto release_lost_link1_cmd; + + qdf_mem_set(&cmd->u.scanCmd.u.scanRequest.bssid, + sizeof(struct qdf_mac_addr), 0xFF); + status = csr_queue_sme_command(mac_ctx, cmd, false); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sms_log(mac_ctx, LOGE, + FL("fail to send message status = %d"), status); + } + +release_lost_link1_cmd: + if (!QDF_IS_STATUS_SUCCESS(status)) { + sms_log(mac_ctx, LOGW, FL("failed with status %d"), status); + if (cmd) + csr_release_command_scan(mac_ctx, cmd); + status = csr_scan_handle_failed_lostlink1(mac_ctx, session_id); + } + return status; +} + +static QDF_STATUS +csr_update_lost_link2_cmd(tpAniSirGlobal mac_ctx, tSmeCmd *cmd, + uint32_t session_id, tCsrRoamSession *session) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + uint8_t i, num_ch = 0; + tScanResultHandle bss_lst = NULL; + tCsrScanResultInfo *scan_result = NULL; + tCsrScanResultFilter *scan_fltr = NULL; + tCsrChannelInfo *ch_info = &cmd->u.scanCmd.u.scanRequest.ChannelInfo; + + cmd->command = eSmeCommandScan; + cmd->sessionId = (uint8_t) session_id; + cmd->u.scanCmd.reason = eCsrScanLostLink2; + cmd->u.scanCmd.callback = NULL; + cmd->u.scanCmd.pContext = NULL; + cmd->u.scanCmd.u.scanRequest.maxChnTime = + mac_ctx->roam.configParam.nActiveMaxChnTime; + cmd->u.scanCmd.u.scanRequest.minChnTime = + mac_ctx->roam.configParam.nActiveMinChnTime; + cmd->u.scanCmd.u.scanRequest.scanType = eSIR_ACTIVE_SCAN; + wma_get_scan_id(&cmd->u.scanCmd.scanID); + cmd->u.scanCmd.u.scanRequest.scan_id = + cmd->u.scanCmd.scanID; + if (!session->pCurRoamProfile) + return QDF_STATUS_SUCCESS; + status = qdf_mc_timer_init(&cmd->u.scanCmd.csr_scan_timer, + QDF_TIMER_TYPE_SW, + csr_scan_active_list_timeout_handle, cmd); + scan_fltr = qdf_mem_malloc(sizeof(tCsrScanResultFilter)); + if (NULL == scan_fltr) + return QDF_STATUS_E_NOMEM; + + qdf_mem_set(scan_fltr, sizeof(tCsrScanResultFilter), 0); + status = csr_roam_prepare_filter_from_profile(mac_ctx, + session->pCurRoamProfile, scan_fltr); + if (!QDF_IS_STATUS_SUCCESS(status)) + goto free_lost_link2_local_mem; + + status = csr_scan_get_result(mac_ctx, scan_fltr, &bss_lst); + if (!QDF_IS_STATUS_SUCCESS(status)) + goto free_lost_link2_local_mem; + + if (!bss_lst) + goto free_lost_link2_local_mem; + + ch_info->ChannelList = qdf_mem_malloc(WNI_CFG_VALID_CHANNEL_LIST_LEN); + if (NULL == ch_info->ChannelList) { + status = QDF_STATUS_E_NOMEM; + goto free_lost_link2_local_mem; + } + scan_result = csr_scan_result_get_next(mac_ctx, bss_lst); + while (scan_result != NULL && num_ch < WNI_CFG_VALID_CHANNEL_LIST_LEN) { + for (i = 0; i < num_ch; i++) { + if (ch_info->ChannelList[i] == + scan_result->BssDescriptor.channelId) + break; + } + if (i == num_ch) + ch_info->ChannelList[num_ch++] = + scan_result->BssDescriptor.channelId; + scan_result = csr_scan_result_get_next(mac_ctx, bss_lst); + } + ch_info->numOfChannels = num_ch; + +free_lost_link2_local_mem: + if (scan_fltr) { + csr_free_scan_filter(mac_ctx, scan_fltr); + qdf_mem_free(scan_fltr); + } + if (bss_lst) + csr_scan_result_purge(mac_ctx, bss_lst); + return status; +} + +/** + * csr_scan_request_lost_link2() - start scan on link lost 2 + * @mac_ctx: mac global context + * @session_id: session id + * + * Lostlink2 scan is to actively scan the all SSIDs of the last roaming + * profile's on all matched BSS channels. Since MAC doesn't support multiple + * SSID, we scan all SSIDs and filter them afterwards + * + * Return: status of operation + */ +QDF_STATUS +csr_scan_request_lost_link2(tpAniSirGlobal mac_ctx, uint32_t session_id) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tSmeCmd *cmd = NULL; + tCsrRoamSession *session = CSR_GET_SESSION(mac_ctx, session_id); + + if (!session) { + sms_log(mac_ctx, LOGE, FL("session %d not found"), session_id); + return QDF_STATUS_E_FAILURE; + } + + sms_log(mac_ctx, LOGW, FL(" called")); + cmd = csr_get_command_buffer(mac_ctx); + if (!cmd) { + status = QDF_STATUS_E_RESOURCES; + goto release_lost_link2_cmd; + } + qdf_mem_set(&cmd->u.scanCmd, sizeof(tScanCmd), 0); + status = csr_update_lost_link2_cmd(mac_ctx, cmd, session_id, session); + if (!QDF_IS_STATUS_SUCCESS(status)) + goto release_lost_link2_cmd; + + qdf_mem_set(&cmd->u.scanCmd.u.scanRequest.bssid, + sizeof(struct qdf_mac_addr), 0xFF); + /* Put to the head in pending queue */ + status = csr_queue_sme_command(mac_ctx, cmd, true); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sms_log(mac_ctx, LOGE, + FL("fail to send message status = %d"), status); + goto release_lost_link2_cmd; + } + +release_lost_link2_cmd: + if (!QDF_IS_STATUS_SUCCESS(status)) { + sms_log(mac_ctx, LOGW, FL("failed with status %d"), status); + if (cmd) + csr_release_command_scan(mac_ctx, cmd); + status = csr_scan_handle_failed_lostlink2(mac_ctx, session_id); + } + return status; +} + +/** + * csr_scan_request_lost_link3() - To actively scan all valid channels + * @mac_ctx: mac global context + * @session_id: session id + * + * Return: status of operation + */ +QDF_STATUS +csr_scan_request_lost_link3(tpAniSirGlobal mac_ctx, uint32_t session_id) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tSmeCmd *cmd; + + sms_log(mac_ctx, LOGW, FL(" called")); + do { + cmd = csr_get_command_buffer(mac_ctx); + if (!cmd) { + status = QDF_STATUS_E_RESOURCES; + break; + } + qdf_mem_set(&cmd->u.scanCmd, sizeof(tScanCmd), 0); + cmd->command = eSmeCommandScan; + cmd->sessionId = (uint8_t) session_id; + cmd->u.scanCmd.reason = eCsrScanLostLink3; + cmd->u.scanCmd.callback = NULL; + cmd->u.scanCmd.pContext = NULL; + cmd->u.scanCmd.u.scanRequest.maxChnTime = + mac_ctx->roam.configParam.nActiveMaxChnTime; + cmd->u.scanCmd.u.scanRequest.minChnTime = + mac_ctx->roam.configParam.nActiveMinChnTime; + cmd->u.scanCmd.u.scanRequest.scanType = eSIR_ACTIVE_SCAN; + wma_get_scan_id(&cmd->u.scanCmd.scanID); + status = qdf_mc_timer_init(&cmd->u.scanCmd.csr_scan_timer, + QDF_TIMER_TYPE_SW, + csr_scan_active_list_timeout_handle, cmd); + cmd->u.scanCmd.u.scanRequest.scan_id = + cmd->u.scanCmd.scanID; + qdf_set_macaddr_broadcast(&cmd->u.scanCmd.u.scanRequest.bssid); + /* Put to the head of pending queue */ + status = csr_queue_sme_command(mac_ctx, cmd, true); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sms_log(mac_ctx, LOGE, + FL("fail to send message status = %d"), status); + break; + } + } while (0); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sms_log(mac_ctx, LOGW, FL("failed with status %d"), status); + if (cmd) + csr_release_command_scan(mac_ctx, cmd); + } + + return status; +} + +QDF_STATUS csr_scan_handle_search_for_ssid(tpAniSirGlobal pMac, + tSmeCmd *pCommand) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tScanResultHandle hBSSList = CSR_INVALID_SCANRESULT_HANDLE; + tCsrScanResultFilter *pScanFilter = NULL; + tCsrRoamProfile *pProfile = pCommand->u.scanCmd.pToRoamProfile; + uint32_t sessionId = pCommand->sessionId; + + do { + /* If this scan is for LFR */ + if (pMac->roam.neighborRoamInfo[sessionId].uOsRequestedHandoff) { + /* notify LFR state m/c */ + status = csr_neighbor_roam_sssid_scan_done(pMac, + sessionId, QDF_STATUS_SUCCESS); + if (QDF_STATUS_SUCCESS != status) + csr_neighbor_roam_start_lfr_scan(pMac, + sessionId); + status = QDF_STATUS_SUCCESS; + break; + } + /* + * If there is roam command waiting, ignore this roam because + * the newer roam command is the one to execute + */ + if (csr_is_roam_command_waiting_for_session(pMac, sessionId)) { + sms_log(pMac, LOGW, + FL("aborts because roam command waiting")); + break; + } + if (pProfile == NULL) + break; + pScanFilter = qdf_mem_malloc(sizeof(tCsrScanResultFilter)); + if (NULL == pScanFilter) { + status = QDF_STATUS_E_NOMEM; + break; + } + status = csr_roam_prepare_filter_from_profile(pMac, pProfile, + pScanFilter); + if (!QDF_IS_STATUS_SUCCESS(status)) + break; + status = csr_scan_get_result(pMac, pScanFilter, &hBSSList); + if (!QDF_IS_STATUS_SUCCESS(status)) + break; + if (pMac->roam.roamSession[sessionId].connectState == + eCSR_ASSOC_STATE_TYPE_INFRA_DISCONNECTING) { + sms_log(pMac, LOGE, + FL("upper layer issued disconnetion")); + status = QDF_STATUS_E_FAILURE; + break; + } + status = csr_roam_issue_connect(pMac, sessionId, pProfile, + hBSSList, eCsrHddIssued, + pCommand->u.scanCmd.roamId, + true, true); + } while (0); + + if (!QDF_IS_STATUS_SUCCESS(status)) { + if (CSR_INVALID_SCANRESULT_HANDLE != hBSSList) { + csr_scan_result_purge(pMac, hBSSList); + } + /* We haven't done anything to this profile */ + csr_roam_call_callback(pMac, sessionId, NULL, + pCommand->u.scanCmd.roamId, + eCSR_ROAM_ASSOCIATION_FAILURE, + eCSR_ROAM_RESULT_SCAN_FOR_SSID_FAILURE); + } + if (pScanFilter) { + csr_free_scan_filter(pMac, pScanFilter); + qdf_mem_free(pScanFilter); + } + return status; +} + +QDF_STATUS csr_scan_handle_search_for_ssid_failure(tpAniSirGlobal pMac, + tSmeCmd *pCommand) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + uint32_t sessionId = pCommand->sessionId; + tCsrRoamProfile *pProfile = pCommand->u.scanCmd.pToRoamProfile; + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + eCsrRoamResult roam_result; + + if (!pSession) { + sms_log(pMac, LOGE, FL("session %d not found"), sessionId); + return QDF_STATUS_E_FAILURE; + } + /* If this scan is for LFR */ + if (pMac->roam.neighborRoamInfo[sessionId].uOsRequestedHandoff) { + /* notify LFR state m/c */ + status = csr_neighbor_roam_sssid_scan_done(pMac, sessionId, + QDF_STATUS_E_FAILURE); + if (QDF_STATUS_SUCCESS != status) + csr_neighbor_roam_start_lfr_scan(pMac, sessionId); + return QDF_STATUS_SUCCESS; + } +#ifdef WLAN_DEBUG + if (pCommand->u.scanCmd.u.scanRequest.SSIDs.numOfSSIDs == 1) { + char str[36]; + tSirMacSSid *ptr_ssid = + &pCommand->u.scanCmd.u.scanRequest.SSIDs.SSIDList[0].SSID; + qdf_mem_copy(str, ptr_ssid->ssId, ptr_ssid->length); + str[ptr_ssid->length] = 0; + sms_log(pMac, LOGW, FL("SSID = %s"), str); + } +#endif + /* + * Check whether it is for start ibss. No need to do anything if it + * is a JOIN request + */ + if (pProfile && CSR_IS_START_IBSS(pProfile)) { + status = csr_roam_issue_connect(pMac, sessionId, pProfile, NULL, + eCsrHddIssued, pCommand->u.scanCmd.roamId, + true, true); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOGE, + FL("failed to issue startIBSS, status: 0x%08X"), + status); + csr_roam_call_callback(pMac, sessionId, NULL, + pCommand->u.scanCmd.roamId, eCSR_ROAM_FAILED, + eCSR_ROAM_RESULT_FAILURE); + } + return status; + } + roam_result = eCSR_ROAM_RESULT_FAILURE; + if (NULL != pProfile && csr_is_bss_type_ibss(pProfile->BSSType)) { + roam_result = eCSR_ROAM_RESULT_IBSS_START_FAILED; + goto roam_completion; + } + /* Only indicate assoc_completion if we indicate assoc_start. */ + if (pSession->bRefAssocStartCnt > 0) { + tCsrRoamInfo *pRoamInfo = NULL, roamInfo; + + qdf_mem_set(&roamInfo, sizeof(tCsrRoamInfo), 0); + pRoamInfo = &roamInfo; + if (pCommand->u.roamCmd.pRoamBssEntry) { + tCsrScanResult *pScanResult = GET_BASE_ADDR( + pCommand->u.roamCmd.pRoamBssEntry, + tCsrScanResult, Link); + roamInfo.pBssDesc = &pScanResult->Result.BssDescriptor; + } + roamInfo.statusCode = pSession->joinFailStatusCode.statusCode; + roamInfo.reasonCode = pSession->joinFailStatusCode.reasonCode; + pSession->bRefAssocStartCnt--; + csr_roam_call_callback(pMac, sessionId, pRoamInfo, + pCommand->u.scanCmd.roamId, + eCSR_ROAM_ASSOCIATION_COMPLETION, + eCSR_ROAM_RESULT_SCAN_FOR_SSID_FAILURE); + } else { + csr_roam_call_callback(pMac, sessionId, NULL, + pCommand->u.scanCmd.roamId, + eCSR_ROAM_ASSOCIATION_FAILURE, + eCSR_ROAM_RESULT_SCAN_FOR_SSID_FAILURE); + } +roam_completion: + csr_roam_completion(pMac, sessionId, NULL, pCommand, roam_result, + false); + return status; +} + +QDF_STATUS csr_scan_result_purge(tpAniSirGlobal pMac, + tScanResultHandle hScanList) +{ + QDF_STATUS status = QDF_STATUS_E_INVAL; + tScanResultList *pScanList = (tScanResultList *) hScanList; + + if (pScanList) { + status = csr_ll_scan_purge_result(pMac, &pScanList->List); + csr_ll_close(&pScanList->List); + qdf_mem_free(pScanList); + } + return status; +} + +/** + * csr_remove_bssid_from_scan_list() - remove the bssid from + * scan list + * @mac_tx: mac context. + * @bssid: bssid to be removed + * + * This function remove the given bssid from scan list. + * + * Return: void. + */ +void csr_remove_bssid_from_scan_list(tpAniSirGlobal mac_ctx, + tSirMacAddr bssid) +{ + tListElem *entry, *free_elem; + tCsrScanResult *bss_desc; + tDblLinkList *list = &mac_ctx->scan.scanResultList; + + csr_ll_lock(list); + entry = csr_ll_peek_head(list, LL_ACCESS_NOLOCK); + while (entry != NULL) { + bss_desc = GET_BASE_ADDR(entry, tCsrScanResult, Link); + if (!qdf_mem_cmp(bss_desc->Result.BssDescriptor.bssId, + bssid, sizeof(tSirMacAddr))) { + free_elem = entry; + entry = csr_ll_next(list, entry, LL_ACCESS_NOLOCK); + csr_ll_remove_entry(list, free_elem, LL_ACCESS_NOLOCK); + csr_free_scan_result_entry(mac_ctx, bss_desc); + sms_log(mac_ctx, LOGW, FL("Removed BSS entry:%pM"), + bssid); + continue; + } + + entry = csr_ll_next(list, entry, LL_ACCESS_NOLOCK); + } + + csr_ll_unlock(list); +} + +/** + * csr_derive_prefer_value_from_rssi() - to derive prefer value + * @mac_ctx: Global MAC Context + * @rssi: RSSI of the BSS + * + * This routine will derive preferred value from given rssi + * + * Return: value between 0 to 14 + */ +static int csr_derive_prefer_value_from_rssi(tpAniSirGlobal mac_ctx, int rssi) +{ + int i = CSR_NUM_RSSI_CAT - 1, pref_val = 0; + while (i >= 0) { + if (rssi >= mac_ctx->roam.configParam.RSSICat[i]) { + pref_val = mac_ctx->roam.configParam.BssPreferValue[i]; + break; + } + i--; + }; + return pref_val; +} + +/** + * csr_get_pcl_weight_of_channel() - Get PCL weight if channel is present in pcl + * @mac_ctx: Global MAC Context + * @channel_id: channel of bss + * @filter: pointer to filter created through profile + * @pcl_chan_weight: Get PCL weight for corresponding channel + * @weight_list: Weight list for all the pcl channels. + * + * Get pcl_chan_weight if provided channel is present in pcl list + * + * Return: true or false + */ +static bool csr_get_pcl_weight_of_channel(tpAniSirGlobal mac_ctx, + int channel_id, + tCsrScanResultFilter *filter, int *pcl_chan_weight, + uint8_t *weight_list) +{ + int i; + bool status = false; + + if (NULL == filter) + return status; + + for (i = 0; i < filter->pcl_channels.numChannels; i++) { + if (filter->pcl_channels.channelList[i] == channel_id) { + *pcl_chan_weight = weight_list[i]; + status = true; + break; + } + } + return status; +} +/** + * csr_get_altered_rssi() - Artificially increase/decrease RSSI + * @mac_ctx: Global MAC Context pointer. + * @rssi: Actual RSSI of the AP. + * @channel_id: Channel on which the AP is parked. + * @bssid: BSSID of the AP to connect to. + * + * This routine will apply the boost and penalty parameters + * if the channel_id is of 5G band and it will also apply + * the preferred bssid score if there is a match between + * the bssid and the global preferred bssid list. + * + * Return: The modified RSSI Value + */ +static int csr_get_altered_rssi(tpAniSirGlobal mac_ctx, int rssi, + uint8_t channel_id, struct qdf_mac_addr *bssid) +{ + int modified_rssi; + int boost_factor; + int penalty_factor; + int i; + struct roam_ext_params *roam_params; + struct qdf_mac_addr fav_bssid; + struct qdf_mac_addr local_bssid; + + modified_rssi = rssi; + qdf_mem_zero(&local_bssid.bytes, QDF_MAC_ADDR_SIZE); + if (bssid) + qdf_mem_copy(local_bssid.bytes, bssid->bytes, + QDF_MAC_ADDR_SIZE); + roam_params = &mac_ctx->roam.configParam.roam_params; + /* + * If the 5G pref feature is enabled, apply the roaming + * parameters to boost or penalize the rssi. + * Boost Factor = boost_factor * (Actual RSSI - boost Threshold) + * Penalty Factor = penalty factor * (penalty threshold - Actual RSSI) + */ + if (CSR_IS_SELECT_5G_PREFERRED(mac_ctx) && + CDS_IS_CHANNEL_5GHZ(channel_id)) { + if (rssi > roam_params->raise_rssi_thresh_5g) { + /* Check and boost the threshold*/ + boost_factor = roam_params->raise_factor_5g * + (rssi - roam_params->raise_rssi_thresh_5g); + /* Check and penalize the threshold */ + modified_rssi += CSR_MIN(roam_params->max_raise_rssi_5g, + boost_factor); + } else if (rssi < roam_params->drop_rssi_thresh_5g) { + penalty_factor = roam_params->drop_factor_5g * + (roam_params->drop_rssi_thresh_5g - rssi); + modified_rssi -= CSR_MAX(roam_params->max_drop_rssi_5g, + penalty_factor); + } + sms_log(mac_ctx, LOG2, + FL("5G BSSID"MAC_ADDRESS_STR" AR=%d, MR=%d, ch=%d"), + MAC_ADDR_ARRAY(local_bssid.bytes), + rssi, modified_rssi, channel_id); + } + /* + * Check if there are preferred bssid and then apply the + * preferred score + */ + qdf_mem_zero(&fav_bssid.bytes, QDF_MAC_ADDR_SIZE); + if (bssid && roam_params->num_bssid_favored) { + for (i = 0; i < roam_params->num_bssid_favored; i++) { + qdf_mem_copy(fav_bssid.bytes, + &roam_params->bssid_favored[i], + QDF_MAC_ADDR_SIZE); + if (!qdf_is_macaddr_equal(&fav_bssid, bssid)) + continue; + modified_rssi += roam_params->bssid_favored_factor[i]; + sms_log(mac_ctx, LOG2, + FL("Pref"MAC_ADDRESS_STR" AR=%d, MR=%d, ch=%d"), + MAC_ADDR_ARRAY(local_bssid.bytes), + rssi, modified_rssi, channel_id); + } + } + return modified_rssi; +} + +/** + * csr_get_bss_prefer_value() - Get the preference value for BSS + * @mac_ctx: Global MAC Context + * @rssi: RSSI of the BSS + * @bssid: BSSID to which the preference value is returned + * @channel_id: Channel on which the AP is parked + * + * Each BSS descriptor should be assigned a preference value ranging from + * 14-0, which will be used as an RSSI bucket score while sorting the + * scan results. + * + * Return: Preference value for the BSSID + */ +static uint32_t csr_get_bss_prefer_value(tpAniSirGlobal mac_ctx, int rssi, + struct qdf_mac_addr *bssid, int channel_id) +{ + uint32_t ret = 0; + int modified_rssi; + + /* + * The RSSI does not get modified in case the 5G + * preference or preferred BSSID is not applicable + */ + modified_rssi = csr_get_altered_rssi(mac_ctx, rssi, channel_id, bssid); + ret = csr_derive_prefer_value_from_rssi(mac_ctx, modified_rssi); + + return ret; +} + +/* Return a CapValue base on the capabilities of a BSS */ +static uint32_t csr_get_bss_cap_value(tpAniSirGlobal pMac, + tSirBssDescription *pBssDesc, + tDot11fBeaconIEs *pIes) +{ + uint32_t ret = CSR_BSS_CAP_VALUE_NONE; + if (CSR_IS_ROAM_PREFER_5GHZ(pMac) || CSR_IS_SELECT_5G_PREFERRED(pMac)) { + if ((pBssDesc) && CDS_IS_CHANNEL_5GHZ(pBssDesc->channelId)) { + ret += CSR_BSS_CAP_VALUE_5GHZ; + } + } + /* + * if strict select 5GHz is non-zero then ignore the capability checking + */ + if (pIes && !CSR_IS_SELECT_5GHZ_MARGIN(pMac)) { + /* We only care about 11N capability */ + if (pIes->VHTCaps.present) + ret += CSR_BSS_CAP_VALUE_VHT; + else if (pIes->HTCaps.present) + ret += CSR_BSS_CAP_VALUE_HT; + if (CSR_IS_QOS_BSS(pIes)) { + ret += CSR_BSS_CAP_VALUE_WMM; + /* Give advantage to UAPSD */ + if (CSR_IS_UAPSD_BSS(pIes)) { + ret += CSR_BSS_CAP_VALUE_UAPSD; + } + } + } + + return ret; +} +/** + * csr_is_better_bss() - Is bss1 better than bss2 + * @mac_ctx: Global MAC Context pointer. + * @bss1: Pointer to the first BSS. + * @bss2: Pointer to the second BSS. + * + * This function helps in determining the preference value + * of a particular BSS in the scan result which is further + * used in the sorting logic of the final candidate AP's. + * + * Return: true, if bss1 is better than bss2 + * false, if bss2 is better than bss1. + */ +static bool csr_is_better_bss(tpAniSirGlobal mac_ctx, + tCsrScanResult *bss1, tCsrScanResult *bss2) +{ + bool ret; + if (CSR_IS_BETTER_PREFER_VALUE(bss1->bss_score, + bss2->bss_score)) + ret = true; + else + ret = false; + return ret; +} + +/* Add the channel to the occupiedChannels array */ +static void csr_scan_add_to_occupied_channels(tpAniSirGlobal pMac, + tCsrScanResult *pResult, + uint8_t sessionId, + tCsrChannel *occupied_ch, + tDot11fBeaconIEs *pIes, + bool is_init_list) +{ + QDF_STATUS status; + uint8_t ch; + uint8_t num_occupied_ch = occupied_ch->numChannels; + uint8_t *occupied_ch_lst = occupied_ch->channelList; + + ch = pResult->Result.BssDescriptor.channelId; + if (!csr_neighbor_roam_connected_profile_match(pMac, + sessionId, pResult, pIes)) + return; + + if (is_init_list) + pMac->scan.roam_candidate_count[sessionId]++; + + if (csr_is_channel_present_in_list(occupied_ch_lst, + num_occupied_ch, ch)) + return; + + status = csr_add_to_channel_list_front(occupied_ch_lst, + num_occupied_ch, ch); + if (QDF_IS_STATUS_SUCCESS(status)) { + occupied_ch->numChannels++; + sms_log(pMac, LOG2, + FL("Added channel %d to the list (count=%d)"), + ch, occupied_ch->numChannels); + if (occupied_ch->numChannels > + CSR_BG_SCAN_OCCUPIED_CHANNEL_LIST_LEN) + occupied_ch->numChannels = + CSR_BG_SCAN_OCCUPIED_CHANNEL_LIST_LEN; + } +} + +/* Put the BSS into the scan result list */ +/* pIes can not be NULL */ +static void csr_scan_add_result(tpAniSirGlobal pMac, tCsrScanResult *pResult, + tDot11fBeaconIEs *pIes, uint32_t sessionId) +{ + tpCsrNeighborRoamControlInfo pNeighborRoamInfo = + &pMac->roam.neighborRoamInfo[sessionId]; + + struct qdf_mac_addr bssid; + uint8_t channel_id = pResult->Result.BssDescriptor.channelId; + qdf_mem_zero(&bssid.bytes, QDF_MAC_ADDR_SIZE); + qdf_mem_copy(bssid.bytes, &pResult->Result.BssDescriptor.bssId, + QDF_MAC_ADDR_SIZE); + pResult->preferValue = csr_get_bss_prefer_value(pMac, + (int)pResult->Result.BssDescriptor.rssi, + &bssid, channel_id); + pResult->capValue = csr_get_bss_cap_value(pMac, + &pResult->Result.BssDescriptor, pIes); + csr_ll_insert_tail(&pMac->scan.scanResultList, &pResult->Link, + LL_ACCESS_LOCK); + if (0 == pNeighborRoamInfo->cfgParams.channelInfo.numOfChannels) { + /* + * Build the occupied channel list, only if + * "gNeighborScanChannelList" is NOT set in the cfg.ini file + */ + csr_scan_add_to_occupied_channels(pMac, pResult, sessionId, + &pMac->scan.occupiedChannels[sessionId], pIes, + false); + } +} + +static QDF_STATUS +csr_save_ies(tpAniSirGlobal pMac, + tCsrScanResultFilter *pFilter, + tCsrScanResult *pBssDesc, + tDot11fBeaconIEs **pNewIes, + bool *fMatch, + eCsrEncryptionType *uc, + eCsrEncryptionType *mc, + eCsrAuthType *auth) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tDot11fBeaconIEs *pIes = NULL; + + if (!pFilter) + return status; + *fMatch = csr_match_bss(pMac, &pBssDesc->Result.BssDescriptor, + pFilter, auth, uc, mc, &pIes); +#ifdef WLAN_DEBUG_ROAM_OFFLOAD + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + FL("csr_match_bss fmatch %d"), *fMatch); +#endif + if (NULL == pIes) + return status; + /* Only save it when matching */ + if (!(*fMatch) && !pBssDesc->Result.pvIes) { + qdf_mem_free(pIes); + return status; + } + if (!pBssDesc->Result.pvIes) { + /* + * csr_match_bss allocates the memory. Simply pass it and it + * is freed later + */ + *pNewIes = pIes; + return status; + } + /* + * The pIes is allocated by someone else. make a copy + * Only to save parsed IEs if caller provides a filter. Most likely the + * caller is using to for association, hence save the parsed IEs + */ + *pNewIes = qdf_mem_malloc(sizeof(tDot11fBeaconIEs)); + if (NULL == *pNewIes) { + status = QDF_STATUS_E_NOMEM; + sms_log(pMac, LOGE, FL("fail to allocate memory for IEs")); + /* Need to free memory allocated by csr_match_bss */ + if (!pBssDesc->Result.pvIes) + qdf_mem_free(pIes); + return status; + } + qdf_mem_copy(*pNewIes, pIes, sizeof(tDot11fBeaconIEs)); + return status; +} + +/** + * csr_calc_other_rssi_count_weight() - Calculate channel weight based on other + * APs RSSI and count for candiate selection. + * @rssi: Best rssi on that channel + * @count: No. of APs on that channel + * + * Return : uint32_t + */ +static uint32_t csr_calc_other_rssi_count_weight(int32_t rssi, int32_t count) +{ + int32_t rssi_weight = 0; + int32_t count_weight = 0; + int32_t rssi_count_weight = 0; + + rssi_weight = BEST_CANDIDATE_RSSI_WEIGHT * (rssi - MIN_RSSI); + + do_div(rssi_weight, (MAX_RSSI - MIN_RSSI)); + + if (rssi_weight > BEST_CANDIDATE_RSSI_WEIGHT) + rssi_weight = BEST_CANDIDATE_RSSI_WEIGHT; + else if (rssi_weight < 0) + rssi_weight = 0; + + count_weight = BEST_CANDIDATE_AP_COUNT_WEIGHT * + (count + BEST_CANDIDATE_MIN_COUNT); + + do_div(count_weight, + (BEST_CANDIDATE_MAX_COUNT + BEST_CANDIDATE_MIN_COUNT)); + + if (count_weight > BEST_CANDIDATE_AP_COUNT_WEIGHT) + count_weight = BEST_CANDIDATE_AP_COUNT_WEIGHT; + + rssi_count_weight = ROAM_MAX_CHANNEL_WEIGHT - + (rssi_weight + count_weight); + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + FL("rssi_weight=%d, count_weight=%d, rssi_count_weight=%d rssi=%d count=%d"), + rssi_weight, count_weight, rssi_count_weight, rssi, count); + + return rssi_count_weight; +} + +/** + * _csr_calculate_bss_score () - Calculate BSS score based on AP capabilty + * and channel condition for best candidate + * selection + * @bss_info: bss information + * @best_rssi : Best rssi on BSS channel + * @ap_cnt: No of AP count on BSS channel + * @pcl_chan_weight: pcl weight of BSS channel + * + * Return : int32_t + */ +static int32_t _csr_calculate_bss_score(tSirBssDescription *bss_info, + int32_t best_rssi, int32_t ap_cnt, int pcl_chan_weight) +{ + int32_t score = 0; + int32_t ap_load = 0; + int32_t normalised_width = BEST_CANDIDATE_20MHZ; + int32_t normalised_rssi = 0; + int32_t channel_weight; + int32_t pcl_score = 0; + int32_t modified_rssi = 0; + int32_t temp_pcl_chan_weight = 0; + + /* + * Total weight of a BSSID is calculated on basis of 100 in which + * contribution of every factor is considered like this. + * RSSI: RSSI_WEIGHTAGE : 25 + * HT_CAPABILITY_WEIGHTAGE: 7 + * VHT_CAP_WEIGHTAGE: 5 + * BEAMFORMING_CAP_WEIGHTAGE: 2 + * CHAN_WIDTH_WEIGHTAGE:10 + * CHAN_BAND_WEIGHTAGE: 5 + * CCA_WEIGHTAGE: 8 + * OTHER_AP_WEIGHT: 28 + * PCL: 10 + * + * Rssi_weightage is again divided in another factors like if Rssi is + * very good, very less or medium. + * According to this FR, best rssi is being considered as -40. + * EXCELLENT_RSSI = -40 + * GOOD_RSSI = -55 + * POOR_RSSI = -65 + * BAD_RSSI = -80 + * + * And weightage to all the RSSI type is given like this. + * ROAM_EXCELLENT_RSSI_WEIGHT = 100 + * ROAM_GOOD_RSSI_WEIGHT = 80 + * ROAM_BAD_RSSI_WEIGHT = 60 + * + */ + + if (bss_info->rssi) { + /* + * if RSSI of AP is less then -80, driver should ignore that + * candidate. + */ + if (bss_info->rssi < BAD_RSSI) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + FL("Drop this BSS "MAC_ADDRESS_STR " due to low rssi %d"), + MAC_ADDR_ARRAY(bss_info->bssId), bss_info->rssi); + score = 0; + return score; + } + /* If BSS is in PCL list, give a boost of -20dbm */ + if (pcl_chan_weight) + modified_rssi = bss_info->rssi + PCL_ADVANTAGE; + else + modified_rssi = bss_info->rssi; + /* + * Calculate % of rssi we are getting + * max = 100 + * min = 0 + * less than -40 = 100% + * -40 - -55 = 80% + * -55 - -65 = 60% + * below that = 100 - value + **/ + if (modified_rssi >= BEST_CANDIDATE_EXCELLENT_RSSI) + normalised_rssi = BEST_CANDIDATE_EXCELLENT_RSSI_WEIGHT; + else if (modified_rssi >= BEST_CANDIDATE_GOOD_RSSI) + normalised_rssi = BEST_CANDIDATE_GOOD_RSSI_WEIGHT; + else if (modified_rssi >= BEST_CANDIDATE_POOR_RSSI) + normalised_rssi = BEST_CANDIDATE_BAD_RSSI_WEIGHT; + else + normalised_rssi = modified_rssi - MIN_RSSI; + + /* Calculate score part for rssi */ + score += (normalised_rssi * RSSI_WEIGHTAGE); + } + /* If BSS is in PCL list extra pcl Weight is added n % */ + if (pcl_chan_weight) { + temp_pcl_chan_weight = + (MAX_WEIGHT_OF_PCL_CHANNELS - pcl_chan_weight); + do_div(temp_pcl_chan_weight, + PCL_GROUPS_WEIGHT_DIFFERENCE); + pcl_score = PCL_WEIGHT - temp_pcl_chan_weight; + + if (pcl_score < 0) + pcl_score = 0; + + score += pcl_score * BEST_CANDIDATE_MAX_WEIGHT; + } + /* If AP supports HT caps, extra 10% score will be added */ + if (bss_info->ht_caps_present) + score += BEST_CANDIDATE_MAX_WEIGHT * HT_CAPABILITY_WEIGHTAGE; + + /* If AP supports VHT caps, Extra 6% score will be added to score */ + if (bss_info->vht_caps_present) + score += BEST_CANDIDATE_MAX_WEIGHT * VHT_CAP_WEIGHTAGE; + + /* If AP supports beam forming, extra 2% score will be added to score.*/ + if (bss_info->beacomforming_capable) + score += BEST_CANDIDATE_MAX_WEIGHT * BEAMFORMING_CAP_WEIGHTAGE; + + /* + * Channel width is again calculated on basis of 100. + * Where if AP is + * 80MHZ = 100 + * 40MHZ = 70 + * 20MHZ = 30 weightage is given out of 100. + * Channel width weightage is given as CHAN_WIDTH_WEIGHTAGE (10%). + */ + if (bss_info->chan_width == eHT_CHANNEL_WIDTH_80MHZ) + normalised_width = BEST_CANDIDATE_80MHZ; + else if (bss_info->chan_width == eHT_CHANNEL_WIDTH_40MHZ) + normalised_width = BEST_CANDIDATE_40MHZ; + else + normalised_width = BEST_CANDIDATE_20MHZ; + score += normalised_width * CHAN_WIDTH_WEIGHTAGE; + + /* If AP is on 5Ghz channel , extra score of 5% is added to BSS score.*/ + if (get_rf_band(bss_info->channelId) == SIR_BAND_5_GHZ && + bss_info->rssi > RSSI_THRESHOLD_5GHZ) + score += BEST_CANDIDATE_MAX_WEIGHT * CHAN_BAND_WEIGHTAGE; + + /* + * If QBSS load is present, extra CCA weightage is given on based of AP + * load as 10%. + */ + if (bss_info->QBSSLoad_present) { + /* calculate value in % */ + ap_load = (bss_info->qbss_chan_load * + BEST_CANDIDATE_MAX_WEIGHT); + do_div(ap_load, MAX_AP_LOAD); + } + /* + * If doesn't announce its ap load, driver will take it as 50% of + * CCA_WEIGHTAGE + */ + if (ap_load) + score += (MAX_CHANNEL_UTILIZATION - ap_load) * CCA_WEIGHTAGE; + else + score += DEFAULT_CHANNEL_UTILIZATION * CCA_WEIGHTAGE; + + if (ap_cnt == 0) + channel_weight = ROAM_MAX_CHANNEL_WEIGHT; + else + channel_weight = csr_calc_other_rssi_count_weight( + best_rssi, ap_cnt); + + score += channel_weight * OTHER_AP_WEIGHT; + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + FL("BSSID:"MAC_ADDRESS_STR" rssi=%d normalized_rssi=%d htcaps=%d vht=%d bw=%d channel=%d beamforming=%d ap_load=%d channel_weight=%d pcl_score %d Final Score %d "), + MAC_ADDR_ARRAY(bss_info->bssId), + bss_info->rssi, normalised_rssi, bss_info->ht_caps_present, + bss_info->vht_caps_present, bss_info->chan_width, + bss_info->channelId, + bss_info->beacomforming_capable, ap_load, channel_weight, + pcl_score, + score); + return score; +} +/** + * csr_calculate_bss_score() - Calculate candidate AP score for Best + * candidate selection for connection + * @mac_ctx: Pointer to mac context + * @bss: BSSID + * @pcl_chan_weight: pcl weight for bss channel + * + * Return: void + * + * Calculate candidate AP score for Best candidate selection for connection. + */ +static void csr_calculate_bss_score(tpAniSirGlobal pMac, + tCsrScanResult *pBss, + int pcl_chan_weight) +{ + int32_t score = 0; + int channel_id; + tSirBssDescription *bss_info = &(pBss->Result.BssDescriptor); + + channel_id = cds_get_channel_enum(pBss->Result.BssDescriptor.channelId); + + + if (channel_id < NUM_CHANNELS) + score = _csr_calculate_bss_score(bss_info, + pMac->candidate_channel_info[channel_id]. + max_rssi_on_channel, + pMac->candidate_channel_info[channel_id]. + other_ap_count, pcl_chan_weight); + + pBss->bss_score = score; + return; +} + +static QDF_STATUS +csr_save_scan_entry(tpAniSirGlobal pMac, + tCsrScanResultFilter *pFilter, + bool fMatch, + tCsrScanResult *pBssDesc, + tDot11fBeaconIEs *pNewIes, + tScanResultList *pRetList, + uint32_t *count, + eCsrEncryptionType uc, + eCsrEncryptionType mc, + eCsrAuthType *auth, + uint8_t *weight_list) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tCsrScanResult *pResult; + uint32_t bssLen, allocLen; + /* To sort the list */ + tListElem *pTmpEntry; + tCsrScanResult *pTmpResult; + int pcl_chan_weight = 0; + + if (!(NULL == pFilter || fMatch)) + return status; + + bssLen = pBssDesc->Result.BssDescriptor.length + + sizeof(pBssDesc->Result.BssDescriptor.length); + allocLen = sizeof(tCsrScanResult) + bssLen; + pResult = qdf_mem_malloc(allocLen); + if (NULL == pResult) { + status = QDF_STATUS_E_NOMEM; + sms_log(pMac, LOGE, + FL("fail to allocate memory for scan result, len=%d"), + allocLen); + if (pNewIes) + qdf_mem_free(pNewIes); + return status; + } + pResult->capValue = pBssDesc->capValue; + pResult->preferValue = pBssDesc->preferValue; + pResult->ucEncryptionType = uc; + pResult->mcEncryptionType = mc; + pResult->authType = *auth; + pResult->Result.ssId = pBssDesc->Result.ssId; + pResult->Result.timer = pBssDesc->Result.timer; + /* save the pIes for later use */ + pResult->Result.pvIes = pNewIes; + pResult->bss_score = 0; + /* save bss description */ + qdf_mem_copy(&pResult->Result.BssDescriptor, + &pBssDesc->Result.BssDescriptor, + bssLen); + /* + * calculate pcl_chan_weight from weight list to honor PCL list + */ + if (pFilter && pFilter->pcl_channels.numChannels > 0 && + (pBssDesc->Result.BssDescriptor.rssi > PCL_RSSI_THRESHOLD)) { + if (csr_get_pcl_weight_of_channel(pMac, + pBssDesc->Result.BssDescriptor.channelId, + pFilter, &pcl_chan_weight, weight_list)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + FL(" pcl channel %d pcl_chan_weight %d"), + pBssDesc->Result.BssDescriptor.channelId, + pcl_chan_weight); + } + } + if (pFilter) + csr_calculate_bss_score(pMac, pResult, pcl_chan_weight); + + /* + * No need to lock pRetList because it is locally allocated and no + * outside can access it at this time + */ + if (csr_ll_is_list_empty(&pRetList->List, LL_ACCESS_NOLOCK)) { + csr_ll_insert_tail(&pRetList->List, &pResult->Link, + LL_ACCESS_NOLOCK); + (*count)++; + return status; + } + if (pFilter && + !qdf_mem_cmp(pResult->Result.BssDescriptor.bssId, + pFilter->bssid_hint.bytes, QDF_MAC_ADDR_SIZE) && + pMac->roam.configParam.is_bssid_hint_priority) { + /* bssid hint AP should be on head */ + csr_ll_insert_head(&pRetList->List, + &pResult->Link, LL_ACCESS_NOLOCK); + (*count)++; + pResult->bss_score = BEST_CANDIDATE_MAX_BSS_SCORE; + return status; + } + pTmpEntry = csr_ll_peek_head(&pRetList->List, LL_ACCESS_NOLOCK); + while (pTmpEntry) { + pTmpResult = GET_BASE_ADDR(pTmpEntry, tCsrScanResult, Link); + + if (csr_is_better_bss(pMac, pResult, pTmpResult)) { + csr_ll_insert_entry(&pRetList->List, pTmpEntry, + &pResult->Link, LL_ACCESS_NOLOCK); + /* To indicate we are done */ + pResult = NULL; + break; + } + pTmpEntry = csr_ll_next(&pRetList->List, + pTmpEntry, LL_ACCESS_NOLOCK); + } + if (pResult != NULL) { + /* This one is not better than any one */ + csr_ll_insert_tail(&pRetList->List, &pResult->Link, + LL_ACCESS_NOLOCK); + } + (*count)++; + return status; +} +/** + * csr_calculate_other_ap_count_n_rssi() - calculate channel load on matching + * profile's channel + * @mac_ctx: Global MAC Context pointer. + * @pFilter: Filter to select candidate. + * + * This function processes scan list and match scan results + * with candidate profile. If some scan result doesn't match + * with candidate profile, this function calculates no of + * those AP and best RSSI on that candidate's channel. + * + * Return : void + */ +static void csr_calculate_other_ap_count_n_rssi(tpAniSirGlobal pMac, + tCsrScanResultFilter *pFilter) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tListElem *entry; + bool match = false; + tCsrScanResult *bss = NULL; + tDot11fBeaconIEs *ies, *new_ies = NULL; + int channel_id; + + csr_ll_lock(&pMac->scan.scanResultList); + entry = csr_ll_peek_head(&pMac->scan.scanResultList, LL_ACCESS_NOLOCK); + while (entry) { + bss = GET_BASE_ADDR(entry, tCsrScanResult, Link); + ies = (tDot11fBeaconIEs *) (bss->Result.pvIes); + match = false; + new_ies = NULL; + + status = csr_save_ies(pMac, pFilter, bss, &new_ies, + &match, NULL, NULL, NULL); + if (new_ies) + qdf_mem_free(new_ies); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOG1, FL("save ies fail")); + break; + } + /* + * Calculate Count of APs and Best Rssi on matching profile's + * channel. This information will be used to calculate + * total congestion on that channel. + */ + if (!match) { + channel_id = cds_get_channel_enum( + bss->Result.BssDescriptor.channelId); + if (channel_id >= NUM_CHANNELS) { + sms_log(pMac, LOGE, FL("Invalid channel")); + return; + } + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + FL("channel_id %d ssid %s rssi %d mac address "MAC_ADDRESS_STR), + bss->Result.BssDescriptor.channelId, + bss->Result.ssId.ssId, + bss->Result.BssDescriptor.rssi, + MAC_ADDR_ARRAY( + bss->Result.BssDescriptor.bssId)); + pMac->candidate_channel_info[channel_id]. + other_ap_count++; + if (pMac->candidate_channel_info[channel_id]. + max_rssi_on_channel >= 0) + pMac->candidate_channel_info[channel_id]. + max_rssi_on_channel = -127; + if ((bss->Result.BssDescriptor.rssi > + pMac->candidate_channel_info[channel_id]. + max_rssi_on_channel)) + pMac->candidate_channel_info[channel_id]. + max_rssi_on_channel = + bss->Result.BssDescriptor.rssi; + } + entry = csr_ll_next(&pMac->scan.scanResultList, entry, + LL_ACCESS_NOLOCK); + + } + csr_ll_unlock(&pMac->scan.scanResultList); + return; +} + + +static QDF_STATUS +csr_parse_scan_results(tpAniSirGlobal pMac, + tCsrScanResultFilter *pFilter, + tScanResultList *pRetList, + uint32_t *count) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tListElem *pEntry; + bool fMatch = false; + tCsrScanResult *pBssDesc = NULL; + tDot11fBeaconIEs *pIes, *pNewIes = NULL; + eCsrEncryptionType uc, mc; + eCsrAuthType auth = eCSR_AUTH_TYPE_OPEN_SYSTEM; + uint32_t len = 0; + enum cds_con_mode new_mode; + uint8_t weight_list[QDF_MAX_NUM_CHAN]; + + + csr_ll_lock(&pMac->scan.scanResultList); + + if (pFilter && (0 == pFilter->BSSIDs.numOfBSSIDs)) { + if (cds_map_concurrency_mode( + &pFilter->csrPersona, &new_mode)) { + status = cds_get_pcl(new_mode, + &pFilter->pcl_channels.channelList[0], &len, + weight_list, QDF_ARRAY_SIZE(weight_list)); + pFilter->pcl_channels.numChannels = (uint8_t)len; + } + } + + if (QDF_STATUS_E_FAILURE == status) + sms_log(pMac, QDF_TRACE_LEVEL_ERROR, + FL("Retrieving pcl failed from HDD")); + pEntry = csr_ll_peek_head(&pMac->scan.scanResultList, LL_ACCESS_NOLOCK); + while (pEntry) { + pBssDesc = GET_BASE_ADDR(pEntry, tCsrScanResult, Link); + pIes = (tDot11fBeaconIEs *) (pBssDesc->Result.pvIes); + /* + * if pBssDesc->Result.pvIes is NULL, we need to free any memory + * allocated by csr_match_bss for any error condition, + * otherwiase, it will be freed later + */ + fMatch = false; + pNewIes = NULL; + status = csr_save_ies(pMac, pFilter, pBssDesc, &pNewIes, + &fMatch, &uc, &mc, &auth); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOG1, FL("save ies fail %d"), + status); + break; + } + status = csr_save_scan_entry(pMac, pFilter, fMatch, pBssDesc, + pNewIes, pRetList, count, uc, mc, + &auth, weight_list); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOG1, FL("save entry fail %d"), + status); + break; + } + pEntry = csr_ll_next(&pMac->scan.scanResultList, pEntry, + LL_ACCESS_NOLOCK); + } /* while */ + csr_ll_unlock(&pMac->scan.scanResultList); + return status; +} + +QDF_STATUS csr_scan_get_result(tpAniSirGlobal pMac, + tCsrScanResultFilter *pFilter, + tScanResultHandle *phResult) +{ + QDF_STATUS status; + tScanResultList *pRetList; + uint32_t count = 0; + + if (phResult) + *phResult = CSR_INVALID_SCANRESULT_HANDLE; + + qdf_mem_set(&pMac->candidate_channel_info, + sizeof(struct candidate_chan_info), 0); + if (pFilter) + csr_calculate_other_ap_count_n_rssi(pMac, pFilter); + + pRetList = qdf_mem_malloc(sizeof(tScanResultList)); + if (NULL == pRetList) { + sms_log(pMac, LOGE, FL("pRetList is NULL")); + return QDF_STATUS_E_NOMEM; + } + + csr_ll_open(pMac->hHdd, &pRetList->List); + pRetList->pCurEntry = NULL; + status = csr_parse_scan_results(pMac, pFilter, pRetList, &count); + sms_log(pMac, LOG1, FL("return %d BSS %d"), + csr_ll_count(&pRetList->List), status); + if (!QDF_IS_STATUS_SUCCESS(status) || (phResult == NULL)) { + /* Fail or No one wants the result. */ + csr_scan_result_purge(pMac, (tScanResultHandle) pRetList); + } else { + if (0 == count) { + /* We are here meaning the there is no match */ + csr_ll_close(&pRetList->List); + qdf_mem_free(pRetList); + status = QDF_STATUS_E_NULL_VALUE; + } else if (phResult) { + *phResult = pRetList; + } + } + return status; +} + +/* + * NOTE: This routine is being added to make + * sure that scan results are not being flushed + * while roaming. If the scan results are flushed, + * we are unable to recover from + * csr_roam_roaming_state_disassoc_rsp_processor. + * If it is needed to remove this routine, + * first ensure that we recover gracefully from + * csr_roam_roaming_state_disassoc_rsp_processor if + * csr_scan_get_result returns with a failure because + * of not being able to find the roaming BSS. + */ +static bool csr_scan_flush_denied(tpAniSirGlobal pMac) +{ + uint8_t sessionId; + + for (sessionId = 0; sessionId < CSR_ROAM_SESSION_MAX; sessionId++) { + if (CSR_IS_SESSION_VALID(pMac, sessionId)) { + if (csr_neighbor_middle_of_roaming(pMac, sessionId)) + return 1; + } + } + return 0; +} + +QDF_STATUS csr_scan_flush_result(tpAniSirGlobal pMac) +{ + bool isFlushDenied = csr_scan_flush_denied(pMac); + + if (isFlushDenied) { + sms_log(pMac, LOGW, "%s: scan flush denied in roam state %d", + __func__, isFlushDenied); + return QDF_STATUS_E_FAILURE; + } + + sms_log(pMac, LOG1, "%s: Flushing all scan results", __func__); + csr_ll_scan_purge_result(pMac, &pMac->scan.tempScanResults); + csr_ll_scan_purge_result(pMac, &pMac->scan.scanResultList); + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS csr_scan_flush_selective_result(tpAniSirGlobal pMac, bool flushP2P) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tListElem *pEntry, *pFreeElem; + tCsrScanResult *pBssDesc; + tDblLinkList *pList = &pMac->scan.scanResultList; + + csr_ll_lock(pList); + + pEntry = csr_ll_peek_head(pList, LL_ACCESS_NOLOCK); + while (pEntry != NULL) { + pBssDesc = GET_BASE_ADDR(pEntry, tCsrScanResult, Link); + if (flushP2P && !qdf_mem_cmp(pBssDesc->Result.ssId.ssId, + "DIRECT-", 7)) { + pFreeElem = pEntry; + pEntry = csr_ll_next(pList, pEntry, LL_ACCESS_NOLOCK); + csr_ll_remove_entry(pList, pFreeElem, LL_ACCESS_NOLOCK); + csr_free_scan_result_entry(pMac, pBssDesc); + continue; + } + pEntry = csr_ll_next(pList, pEntry, LL_ACCESS_NOLOCK); + } + + csr_ll_unlock(pList); + + return status; +} + +void csr_scan_flush_bss_entry(tpAniSirGlobal pMac, + tpSmeCsaOffloadInd pCsaOffloadInd) +{ + tListElem *pEntry, *pFreeElem; + tCsrScanResult *pBssDesc; + tDblLinkList *pList = &pMac->scan.scanResultList; + + csr_ll_lock(pList); + + pEntry = csr_ll_peek_head(pList, LL_ACCESS_NOLOCK); + while (pEntry != NULL) { + pBssDesc = GET_BASE_ADDR(pEntry, tCsrScanResult, Link); + if (!qdf_mem_cmp(pBssDesc->Result.BssDescriptor.bssId, + pCsaOffloadInd->bssid.bytes, QDF_MAC_ADDR_SIZE)) { + pFreeElem = pEntry; + pEntry = csr_ll_next(pList, pEntry, LL_ACCESS_NOLOCK); + csr_ll_remove_entry(pList, pFreeElem, LL_ACCESS_NOLOCK); + csr_free_scan_result_entry(pMac, pBssDesc); + sms_log(pMac, LOG1, FL("Removed BSS entry:%pM"), + pCsaOffloadInd->bssid.bytes); + continue; + } + + pEntry = csr_ll_next(pList, pEntry, LL_ACCESS_NOLOCK); + } + + csr_ll_unlock(pList); +} + +/** + * csr_check11d_channel + * + ***FUNCTION: + * This function is called from csr_scan_filter_results function and + * compare channel number with given channel list. + * + ***LOGIC: + * Check Scan result channel number with CFG channel list + * + ***ASSUMPTIONS: + * + * + ***NOTE: + * + * @param channelId channel number + * @param pChannelList Pointer to channel list + * @param numChannels Number of channel in channel list + * + * @return Status + */ + +static QDF_STATUS csr_check11d_channel(uint8_t channelId, uint8_t *pChannelList, + uint32_t numChannels) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + uint8_t i = 0; + + for (i = 0; i < numChannels; i++) { + if (pChannelList[i] == channelId) { + status = QDF_STATUS_SUCCESS; + break; + } + } + return status; +} + +/** + * csr_scan_filter_results + * + ***FUNCTION: + * This function is called from csr_apply_country_information function and + * filter scan result based on valid channel list number. + * + ***LOGIC: + * Get scan result from scan list and Check Scan result channel number + * with 11d channel list if channel number is found in 11d channel list + * then do not remove scan result entry from scan list + * + ***ASSUMPTIONS: + * + * + ***NOTE: + * + * @param pMac Pointer to Global MAC structure + * + * @return Status + */ + +QDF_STATUS csr_scan_filter_results(tpAniSirGlobal pMac) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tListElem *pEntry, *pTempEntry; + tCsrScanResult *pBssDesc; + uint32_t len = sizeof(pMac->roam.validChannelList); + + /* Get valid channels list from CFG */ + if (!QDF_IS_STATUS_SUCCESS(csr_get_cfg_valid_channels(pMac, + pMac->roam. + validChannelList, + &len))) { + sms_log(pMac, LOGE, "Failed to get Channel list from CFG"); + } + + csr_ll_lock(&pMac->scan.scanResultList); + pEntry = csr_ll_peek_head(&pMac->scan.scanResultList, LL_ACCESS_NOLOCK); + while (pEntry) { + pBssDesc = GET_BASE_ADDR(pEntry, tCsrScanResult, Link); + pTempEntry = csr_ll_next(&pMac->scan.scanResultList, pEntry, + LL_ACCESS_NOLOCK); + if (csr_check11d_channel(pBssDesc->Result.BssDescriptor.channelId, + pMac->roam.validChannelList, len)) { + /* Remove Scan result which does not have 11d channel */ + if (csr_ll_remove_entry(&pMac->scan.scanResultList, + pEntry, LL_ACCESS_NOLOCK)) { + csr_free_scan_result_entry(pMac, pBssDesc); + } + } else { + sms_log(pMac, LOG1, FL("%d is a Valid channel"), + pBssDesc->Result.BssDescriptor.channelId); + } + pEntry = pTempEntry; + } + + csr_ll_unlock(&pMac->scan.scanResultList); + csr_ll_lock(&pMac->scan.tempScanResults); + + pEntry = csr_ll_peek_head(&pMac->scan.tempScanResults, + LL_ACCESS_NOLOCK); + while (pEntry) { + pBssDesc = GET_BASE_ADDR(pEntry, tCsrScanResult, Link); + pTempEntry = csr_ll_next(&pMac->scan.tempScanResults, pEntry, + LL_ACCESS_NOLOCK); + if (csr_check11d_channel(pBssDesc->Result.BssDescriptor.channelId, + pMac->roam.validChannelList, len)) { + /* Remove Scan result which does not have 11d channel */ + if (csr_ll_remove_entry + (&pMac->scan.tempScanResults, pEntry, + LL_ACCESS_NOLOCK)) { + csr_free_scan_result_entry(pMac, pBssDesc); + } + } else { + sms_log(pMac, LOG1, FL("%d is a Valid channel"), + pBssDesc->Result.BssDescriptor.channelId); + } + pEntry = pTempEntry; + } + + csr_ll_unlock(&pMac->scan.tempScanResults); + return status; +} + +QDF_STATUS csr_scan_copy_result_list(tpAniSirGlobal pMac, tScanResultHandle hIn, + tScanResultHandle *phResult) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tScanResultList *pRetList, *pInList = (tScanResultList *) hIn; + tCsrScanResult *pResult, *pScanResult; + uint32_t count = 0; + tListElem *pEntry; + uint32_t bssLen, allocLen; + + if (phResult) { + *phResult = CSR_INVALID_SCANRESULT_HANDLE; + } + pRetList = qdf_mem_malloc(sizeof(tScanResultList)); + if (NULL == pRetList) + status = QDF_STATUS_E_NOMEM; + else { + csr_ll_open(pMac->hHdd, &pRetList->List); + pRetList->pCurEntry = NULL; + csr_ll_lock(&pMac->scan.scanResultList); + csr_ll_lock(&pInList->List); + + pEntry = csr_ll_peek_head(&pInList->List, LL_ACCESS_NOLOCK); + while (pEntry) { + pScanResult = + GET_BASE_ADDR(pEntry, tCsrScanResult, Link); + bssLen = + pScanResult->Result.BssDescriptor.length + + sizeof(pScanResult->Result.BssDescriptor.length); + allocLen = sizeof(tCsrScanResult) + bssLen; + pResult = qdf_mem_malloc(allocLen); + if (NULL == pResult) + status = QDF_STATUS_E_NOMEM; + else + status = QDF_STATUS_SUCCESS; + if (!QDF_IS_STATUS_SUCCESS(status)) { + csr_scan_result_purge(pMac, + (tScanResultHandle *) + pRetList); + count = 0; + break; + } + qdf_mem_set(pResult, allocLen, 0); + qdf_mem_copy(&pResult->Result.BssDescriptor, + &pScanResult->Result.BssDescriptor, + bssLen); + if (pScanResult->Result.pvIes) { + pResult->Result.pvIes = + qdf_mem_malloc(sizeof(tDot11fBeaconIEs)); + if (NULL == pResult->Result.pvIes) + status = QDF_STATUS_E_NOMEM; + else + status = QDF_STATUS_SUCCESS; + if (!QDF_IS_STATUS_SUCCESS(status)) { + /* Free the memory we allocate above first */ + qdf_mem_free(pResult); + csr_scan_result_purge(pMac, + (tScanResultHandle *) + pRetList); + count = 0; + break; + } + qdf_mem_copy(pResult->Result.pvIes, + pScanResult->Result.pvIes, + sizeof(tDot11fBeaconIEs)); + } + csr_ll_insert_tail(&pRetList->List, &pResult->Link, + LL_ACCESS_LOCK); + count++; + pEntry = + csr_ll_next(&pInList->List, pEntry, LL_ACCESS_NOLOCK); + } /* while */ + csr_ll_unlock(&pInList->List); + csr_ll_unlock(&pMac->scan.scanResultList); + + if (QDF_IS_STATUS_SUCCESS(status)) { + if (0 == count) { + csr_ll_close(&pRetList->List); + qdf_mem_free(pRetList); + status = QDF_STATUS_E_NULL_VALUE; + } else if (phResult) { + *phResult = pRetList; + } + } + } /* Allocated pRetList */ + + return status; +} + +QDF_STATUS csr_scanning_state_msg_processor(tpAniSirGlobal pMac, + void *pMsgBuf) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tSirMbMsg *pMsg = (tSirMbMsg *) pMsgBuf; + tCsrRoamSession *pSession; + tSirSmeAssocIndToUpperLayerCnf *pUpperLayerAssocCnf; + tCsrRoamInfo roamInfo; + tCsrRoamInfo *pRoamInfo = NULL; + uint32_t sessionId; + + if (eWNI_SME_SCAN_RSP == pMsg->type) + return csr_scan_sme_scan_response(pMac, pMsgBuf); + + if (pMsg->type != eWNI_SME_UPPER_LAYER_ASSOC_CNF) { + if (csr_is_any_session_in_connect_state(pMac)) { + /* + * In case of we are connected, we need to check whether + * connect status changes because scan may also run + * while connected. + */ + csr_roam_check_for_link_status_change(pMac, + (tSirSmeRsp *) pMsgBuf); + } else { + sms_log(pMac, LOGW, + FL("Message [0x%04x] received in wrong state"), + pMsg->type); + } + return status; + } + + sms_log(pMac, LOG1, + FL("Scanning: ASSOC cnf can be given to upper layer")); + qdf_mem_set(&roamInfo, sizeof(tCsrRoamInfo), 0); + pRoamInfo = &roamInfo; + pUpperLayerAssocCnf = (tSirSmeAssocIndToUpperLayerCnf *) pMsgBuf; + status = csr_roam_get_session_id_from_bssid(pMac, + (struct qdf_mac_addr *)pUpperLayerAssocCnf->bssId, &sessionId); + pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!pSession) { + sms_log(pMac, LOGE, FL("session %d not found"), sessionId); + return QDF_STATUS_E_FAILURE; + } + + /* send the status code as Success */ + pRoamInfo->statusCode = eSIR_SME_SUCCESS; + pRoamInfo->u.pConnectedProfile = &pSession->connectedProfile; + pRoamInfo->staId = (uint8_t) pUpperLayerAssocCnf->aid; + pRoamInfo->rsnIELen = (uint8_t) pUpperLayerAssocCnf->rsnIE.length; + pRoamInfo->prsnIE = pUpperLayerAssocCnf->rsnIE.rsnIEdata; + pRoamInfo->addIELen = (uint8_t) pUpperLayerAssocCnf->addIE.length; + pRoamInfo->paddIE = pUpperLayerAssocCnf->addIE.addIEdata; + qdf_mem_copy(pRoamInfo->peerMac.bytes, + pUpperLayerAssocCnf->peerMacAddr, + QDF_MAC_ADDR_SIZE); + qdf_mem_copy(&pRoamInfo->bssid.bytes, pUpperLayerAssocCnf->bssId, + QDF_MAC_ADDR_SIZE); + pRoamInfo->wmmEnabledSta = pUpperLayerAssocCnf->wmmEnabledSta; + if (CSR_IS_INFRA_AP(pRoamInfo->u.pConnectedProfile)) { + pMac->roam.roamSession[sessionId].connectState = + eCSR_ASSOC_STATE_TYPE_INFRA_CONNECTED; + pRoamInfo->fReassocReq = pUpperLayerAssocCnf->reassocReq; + status = csr_roam_call_callback(pMac, sessionId, + pRoamInfo, 0, + eCSR_ROAM_INFRA_IND, + eCSR_ROAM_RESULT_INFRA_ASSOCIATION_CNF); + } + return status; +} + +static void csr_check_n_save_wsc_ie(tpAniSirGlobal pMac, + tSirBssDescription *pNewBssDescr, + tSirBssDescription *pOldBssDescr) +{ + int idx, len; + uint8_t *pbIe; + + /* If failed to remove, assuming someone else got it. */ + if ((pNewBssDescr->fProbeRsp != pOldBssDescr->fProbeRsp) && + (0 == pNewBssDescr->WscIeLen)) { + idx = 0; + len = GET_IE_LEN_IN_BSS(pOldBssDescr->length) - + DOT11F_IE_WSCPROBERES_MIN_LEN - 2; + pbIe = (uint8_t *) pOldBssDescr->ieFields; + /* Save WPS IE if it exists */ + pNewBssDescr->WscIeLen = 0; + while (idx < len) { + if ((DOT11F_EID_WSCPROBERES == pbIe[0]) && + (0x00 == pbIe[2]) && (0x50 == pbIe[3]) + && (0xf2 == pbIe[4]) && (0x04 == pbIe[5])) { + /* Founrd it */ + if ((DOT11F_IE_WSCPROBERES_MAX_LEN - 2) >= + pbIe[1]) { + qdf_mem_copy(pNewBssDescr-> + WscIeProbeRsp, pbIe, + pbIe[1] + 2); + pNewBssDescr->WscIeLen = pbIe[1] + 2; + } + break; + } + idx += pbIe[1] + 2; + pbIe += pbIe[1] + 2; + } + } +} + +/* pIes may be NULL */ +static bool csr_remove_dup_bss_description(tpAniSirGlobal pMac, + tSirBssDescription *bss_dscp, + tDot11fBeaconIEs *pIes, + tAniSSID *pSsid, + unsigned long *timer) +{ + tListElem *pEntry; + tCsrScanResult *scan_entry; + bool fRC = false; + + /* + * Walk through all the chained BssDescriptions. If we find a chained + * BssDescription that matches the BssID of the BssDescription passed + * in, then these must be duplicate scan results for this Bss. In that + * case, remove the 'old' Bss description from the linked list. + */ + csr_ll_lock(&pMac->scan.scanResultList); + pEntry = csr_ll_peek_head(&pMac->scan.scanResultList, LL_ACCESS_NOLOCK); + + while (pEntry) { + scan_entry = GET_BASE_ADDR(pEntry, tCsrScanResult, Link); + /* + * we have a duplicate scan results only when BSSID, SSID, + * Channel and NetworkType matches + */ + if (csr_is_duplicate_bss_description(pMac, + &scan_entry->Result.BssDescriptor, + bss_dscp, pIes)) { + if (bss_dscp->rx_channel == bss_dscp->channelId) { + /* + * Update rssi values only if beacon is + * received on the same channel that was + * sent on. + */ + int32_t rssi_new, rssi_old; + const int32_t weight = + CSR_SCAN_RESULT_RSSI_WEIGHT; + + rssi_new = (int32_t) bss_dscp->rssi; + rssi_old = (int32_t) scan_entry-> + Result.BssDescriptor.rssi; + rssi_new = ((rssi_new * weight) + + rssi_old * (100 - weight)) / 100; + bss_dscp->rssi = (int8_t) rssi_new; + + rssi_new = (int32_t) bss_dscp->rssi_raw; + rssi_old = (int32_t) scan_entry-> + Result.BssDescriptor.rssi_raw; + rssi_new = ((rssi_new * weight) + + rssi_old * (100 - weight)) / 100; + bss_dscp->rssi_raw = (int8_t) rssi_new; + } + + /* Remove the old entry from the list */ + if (csr_ll_remove_entry + (&pMac->scan.scanResultList, pEntry, + LL_ACCESS_NOLOCK)) { + /* + * we need to free the memory associated with + * this node. If failed to remove, assuming + * someone else got it. + */ + *pSsid = scan_entry->Result.ssId; + *timer = scan_entry->Result.timer; + csr_check_n_save_wsc_ie(pMac, bss_dscp, + &scan_entry->Result. + BssDescriptor); + csr_free_scan_result_entry(pMac, scan_entry); + } else { + sms_log(pMac, LOGW, FL("fail to remove entry")); + } + fRC = true; + /* + * If we found a match, we can stop looking through + * the list. + */ + break; + } + pEntry = csr_ll_next(&pMac->scan.scanResultList, pEntry, + LL_ACCESS_NOLOCK); + } + + csr_ll_unlock(&pMac->scan.scanResultList); + return fRC; +} + +static QDF_STATUS csr_add_pmkid_candidate_list(tpAniSirGlobal pMac, + uint32_t sessionId, + tSirBssDescription *pBssDesc, + tDot11fBeaconIEs *pIes) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + tPmkidCandidateInfo *pmkid_info = NULL; +#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR + WLAN_HOST_DIAG_EVENT_DEF(secEvent, + host_event_wlan_security_payload_type); +#endif /* FEATURE_WLAN_DIAG_SUPPORT_CSR */ + if (!pSession) { + sms_log(pMac, LOGE, FL(" session %d not found "), sessionId); + return QDF_STATUS_E_FAILURE; + } + + sms_log(pMac, LOGW, FL("NumPmkidCandidate = %d"), + pSession->NumPmkidCandidate); + if (!pIes) + return status; + /* check if this is a RSN BSS */ + if (!pIes->RSN.present) + return status; + + if (pSession->NumPmkidCandidate >= CSR_MAX_PMKID_ALLOWED) + return QDF_STATUS_E_FAILURE; + + /* BSS is capable of doing pre-authentication */ +#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR + qdf_mem_set(&secEvent, sizeof(host_event_wlan_security_payload_type), + 0); + secEvent.eventId = WLAN_SECURITY_EVENT_PMKID_CANDIDATE_FOUND; + secEvent.encryptionModeMulticast = (uint8_t)diag_enc_type_from_csr_type( + pSession->connectedProfile.mcEncryptionType); + secEvent.encryptionModeUnicast = (uint8_t)diag_enc_type_from_csr_type( + pSession->connectedProfile.EncryptionType); + qdf_mem_copy(secEvent.bssid, pSession->connectedProfile.bssid.bytes, + QDF_MAC_ADDR_SIZE); + secEvent.authMode = (uint8_t)diag_auth_type_from_csr_type( + pSession->connectedProfile.AuthType); + WLAN_HOST_DIAG_EVENT_REPORT(&secEvent, EVENT_WLAN_SECURITY); +#endif /* #ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR */ + + pmkid_info = &pSession->PmkidCandidateInfo[pSession->NumPmkidCandidate]; + /* if yes, then add to PMKIDCandidateList */ + qdf_mem_copy(pmkid_info->BSSID.bytes, pBssDesc->bssId, + QDF_MAC_ADDR_SIZE); + /* Bit 0 offirst byte - PreAuthentication Capability */ + if ((pIes->RSN.RSN_Cap[0] >> 0) & 0x1) + pmkid_info->preAuthSupported = true; + else + pmkid_info->preAuthSupported = false; + pSession->NumPmkidCandidate++; + return status; +} + +/* + * This function checks whether new AP is found for the current connected + * profile. If it is found, it return the sessionId, else it return invalid + * sessionID + */ +static QDF_STATUS csr_process_bss_desc_for_pmkid_list(tpAniSirGlobal pMac, + tSirBssDescription *pBssDesc, + tDot11fBeaconIEs *pIes, + uint8_t sessionId) +{ + tCsrRoamSession *pSession; + tDot11fBeaconIEs *pIesLocal = pIes; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + + if (!(pIesLocal || + QDF_IS_STATUS_SUCCESS( + csr_get_parsed_bss_description_ies(pMac, pBssDesc, + &pIesLocal)))) + return status; + + if (!CSR_IS_SESSION_VALID(pMac, sessionId)) { + if (!pIes) + qdf_mem_free(pIesLocal); + return status; + } + + pSession = CSR_GET_SESSION(pMac, sessionId); + if (csr_is_conn_state_connected_infra(pMac, sessionId) + && (eCSR_AUTH_TYPE_RSN == pSession->connectedProfile.AuthType) + && csr_match_bss_to_connect_profile(pMac, + &pSession->connectedProfile, + pBssDesc, pIesLocal)) { + /* This new BSS fits the current profile connected */ + status = csr_add_pmkid_candidate_list(pMac, sessionId, + pBssDesc, pIesLocal); + if (!QDF_IS_STATUS_SUCCESS(status)) + sms_log(pMac, LOGE, + FL("csr_add_pmkid_candidate_list failed")); + else + status = QDF_STATUS_SUCCESS; + } + + if (!pIes) + qdf_mem_free(pIesLocal); + + return status; +} + +#ifdef FEATURE_WLAN_WAPI +static QDF_STATUS csr_add_bkid_candidate_list(tpAniSirGlobal pMac, + uint32_t sessionId, + tSirBssDescription *pBssDesc, + tDot11fBeaconIEs *pIes) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!pSession) { + sms_log(pMac, LOGE, FL(" session %d not found "), sessionId); + return QDF_STATUS_E_FAILURE; + } + + sms_log(pMac, LOGW, + "csr_add_bkid_candidate_list called pMac->scan.NumBkidCandidate = %d", + pSession->NumBkidCandidate); + if (pIes) { + /* check if this is a WAPI BSS */ + if (pIes->WAPI.present) { + /* Check if the BSS is capable of doing pre-authentication */ + if (pSession->NumBkidCandidate < CSR_MAX_BKID_ALLOWED) { + + /* if yes, then add to BKIDCandidateList */ + qdf_mem_copy(pSession-> + BkidCandidateInfo[pSession-> + NumBkidCandidate]. + BSSID.bytes, pBssDesc->bssId, + QDF_MAC_ADDR_SIZE); + if (pIes->WAPI.preauth) { + pSession->BkidCandidateInfo[pSession-> + NumBkidCandidate]. + preAuthSupported = true; + } else { + pSession->BkidCandidateInfo[pSession-> + NumBkidCandidate]. + preAuthSupported = false; + } + pSession->NumBkidCandidate++; + } else { + status = QDF_STATUS_E_FAILURE; + } + } + } + + return status; +} + +/* + * This function checks whether new AP is found for the current connected + * profile, if so add to BKIDCandidateList + */ +static bool csr_process_bss_desc_for_bkid_list(tpAniSirGlobal pMac, + tSirBssDescription *pBssDesc, + tDot11fBeaconIEs *pIes) +{ + bool fRC = false; + tDot11fBeaconIEs *pIesLocal = pIes; + uint32_t sessionId; + tCsrRoamSession *pSession; + QDF_STATUS status; + + if (!(pIesLocal || + QDF_IS_STATUS_SUCCESS( + csr_get_parsed_bss_description_ies(pMac, pBssDesc, + &pIesLocal)))) + return fRC; + + for (sessionId = 0; sessionId < CSR_ROAM_SESSION_MAX; sessionId++) { + if (!CSR_IS_SESSION_VALID(pMac, sessionId)) + continue; + pSession = CSR_GET_SESSION(pMac, sessionId); + if (csr_is_conn_state_connected_infra(pMac, sessionId) + && (eCSR_AUTH_TYPE_WAPI_WAI_CERTIFICATE == + pSession->connectedProfile.AuthType) + && csr_match_bss_to_connect_profile(pMac, + &pSession->connectedProfile, + pBssDesc, pIesLocal)) { + /* this new BSS fits the current profile connected */ + status = csr_add_bkid_candidate_list(pMac, sessionId, + pBssDesc, pIesLocal); + if (QDF_IS_STATUS_SUCCESS(status)) + fRC = true; + } + } + if (!pIes) + qdf_mem_free(pIesLocal); + return fRC; +} + +#endif + +/** + * csr_purge_scan_results() - This function removes scan entry based + * on RSSI or AGE + * @mac_ctx: pointer to Global MAC structure + * + * This function removes scan entry based on RSSI or AGE. + * If an scan entry with RSSI less than CSR_PURGE_RSSI_THRESHOLD, + * the scan entry is removed else oldest entry is removed. + * + * Return: None + */ +static void csr_purge_scan_results(tpAniSirGlobal mac_ctx) +{ + tListElem *pentry, *tmp_entry; + tCsrScanResult *presult, *oldest_bss = NULL, *weakest_bss = NULL; + uint64_t oldest_entry = 0; + uint64_t curr_time = (uint64_t)qdf_mc_timer_get_system_time(); + int8_t weakest_rssi = 0; + + csr_ll_lock(&mac_ctx->scan.scanResultList); + pentry = csr_ll_peek_head(&mac_ctx->scan.scanResultList, + LL_ACCESS_NOLOCK); + while (pentry) { + tmp_entry = csr_ll_next(&mac_ctx->scan.scanResultList, pentry, + LL_ACCESS_NOLOCK); + presult = GET_BASE_ADDR(pentry, tCsrScanResult, Link); + if ((curr_time - presult->Result.BssDescriptor.received_time) > + oldest_entry) { + oldest_entry = curr_time - + presult->Result.BssDescriptor.received_time; + oldest_bss = presult; + } + if (presult->Result.BssDescriptor.rssi < weakest_rssi) { + weakest_rssi = presult->Result.BssDescriptor.rssi; + weakest_bss = presult; + } + pentry = tmp_entry; + } + if (oldest_bss) { + tCsrScanResult *bss_to_remove; + + if (weakest_rssi < CSR_PURGE_RSSI_THRESHOLD) + bss_to_remove = weakest_bss; + else + bss_to_remove = oldest_bss; + /* Free the old BSS Entries */ + if (csr_ll_remove_entry(&mac_ctx->scan.scanResultList, + &bss_to_remove->Link, LL_ACCESS_NOLOCK)) { + sms_log(mac_ctx, LOG1, + FL("BSSID: "MAC_ADDRESS_STR" Removed, time delta (%llu) RSSI %d"), + MAC_ADDR_ARRAY( + bss_to_remove->Result.BssDescriptor.bssId), + (curr_time - + bss_to_remove->Result.BssDescriptor.received_time), + bss_to_remove->Result.BssDescriptor.rssi); + csr_free_scan_result_entry(mac_ctx, bss_to_remove); + } + } + csr_ll_unlock(&mac_ctx->scan.scanResultList); +} + +static void +csr_remove_from_tmp_list(tpAniSirGlobal mac_ctx, + uint8_t reason, + uint8_t session_id) +{ + QDF_STATUS status; + tListElem *entry; + tCsrScanResult *bss_dscp; + tDot11fBeaconIEs *local_ie = NULL; + bool dup_bss; + tAniSSID tmpSsid; + unsigned long timer = 0; + + tmpSsid.length = 0; + while ((entry = csr_ll_remove_tail(&mac_ctx->scan.tempScanResults, + LL_ACCESS_LOCK)) != NULL) { + bss_dscp = GET_BASE_ADDR(entry, tCsrScanResult, Link); + sms_log(mac_ctx, LOG2, + FL("...Bssid= "MAC_ADDRESS_STR" chan= %d, rssi = -%d"), + MAC_ADDR_ARRAY(bss_dscp->Result.BssDescriptor. + bssId), + bss_dscp->Result.BssDescriptor.channelId, + bss_dscp->Result.BssDescriptor.rssi * (-1)); + + /* At this time, bss_dscp->Result.pvIes may be NULL */ + local_ie = (tDot11fBeaconIEs *)(bss_dscp->Result.pvIes); + if (local_ie == NULL) { + status = csr_get_parsed_bss_description_ies(mac_ctx, + &bss_dscp->Result.BssDescriptor, &local_ie); + if (!local_ie || !QDF_IS_STATUS_SUCCESS(status)) { + sms_log(mac_ctx, LOGE, FL("Cannot pared IEs")); + csr_free_scan_result_entry(mac_ctx, bss_dscp); + continue; + } + } + dup_bss = csr_remove_dup_bss_description(mac_ctx, + &bss_dscp->Result.BssDescriptor, + local_ie, &tmpSsid, &timer); + /* + * Check whether we have reach out limit, but don't lose the + * LFR candidates came from FW + */ + if (CSR_SCAN_IS_OVER_BSS_LIMIT(mac_ctx)) { + sms_log(mac_ctx, LOG1, FL("BSS Limit reached")); + csr_purge_scan_results(mac_ctx); + } + /* check for duplicate scan results */ + if (!dup_bss) { + status = csr_process_bss_desc_for_pmkid_list(mac_ctx, + &bss_dscp->Result.BssDescriptor, + local_ie, session_id); + if (QDF_IS_STATUS_SUCCESS(status)) { + /* Found a new BSS */ + csr_roam_call_callback(mac_ctx, session_id, + NULL, 0, eCSR_ROAM_SCAN_FOUND_NEW_BSS, + eCSR_ROAM_RESULT_NONE); + } + } else { + /* + * Check if the new one has SSID it it, if not, use + * the older SSID if it exists. + * + * New BSS has a hidden SSID and old one has the SSID. + * Keep the SSID only if diff of saved SSID time and + * current time is less than 1 min to avoid side effect + * of saving SSID with old one is that if AP changes + * its SSID while remain hidden, we may never see it + * and also to address the requirement of When we remove + * hidden ssid from the profile i.e., forget the SSID + * via GUI that SSID shouldn't see in the profile + */ + uint64_t time_gap = + (uint64_t)qdf_mc_timer_get_system_time() - + timer; + if ((0 == bss_dscp->Result.ssId.length) + && (time_gap <= HIDDEN_TIMER) + && tmpSsid.length) { + bss_dscp->Result.timer = timer; + bss_dscp->Result.ssId = tmpSsid; + } + } + + if (csr_is11d_supported(mac_ctx) + && local_ie->Country.present) { + csr_add_vote_for_country_info(mac_ctx, + local_ie->Country.country); + sms_log(mac_ctx, LOGW, + FL("11d AP Bssid "MAC_ADDRESS_STR + " chan= %d, rssi = -%d, countryCode %c%c"), + MAC_ADDR_ARRAY( + bss_dscp->Result.BssDescriptor.bssId), + bss_dscp->Result.BssDescriptor.channelId, + bss_dscp->Result.BssDescriptor.rssi * (-1), + local_ie->Country.country[0], + local_ie->Country.country[1]); + } + /* append to main list */ + csr_scan_add_result(mac_ctx, bss_dscp, local_ie, session_id); + if ((bss_dscp->Result.pvIes == NULL) && local_ie) + qdf_mem_free(local_ie); + } /* end of loop */ +} + +static void csr_move_temp_scan_results_to_main_list(tpAniSirGlobal pMac, + uint8_t reason, + uint8_t sessionId) +{ + tCsrRoamSession *pSession; + uint32_t i; + + /* remove the BSS descriptions from temporary list */ + csr_remove_from_tmp_list(pMac, reason, sessionId); + /* + * We don't need to update CC while connected to an AP which is + * advertising CC already + */ + if (!csr_is11d_supported(pMac)) + return; + + for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) { + if (!CSR_IS_SESSION_VALID(pMac, i)) + continue; + pSession = CSR_GET_SESSION(pMac, i); + if (csr_is_conn_state_connected(pMac, i)) { + sms_log(pMac, LOGW, + FL("No need to update CC in connected state")); + return; + } + } + if (csr_elected_country_info(pMac)) + csr_learn_11dcountry_information(pMac, NULL, NULL, true); +} + +static tCsrScanResult *csr_scan_save_bss_description(tpAniSirGlobal pMac, + tSirBssDescription * + pBSSDescription, + tDot11fBeaconIEs *pIes, + uint8_t sessionId) +{ + tCsrScanResult *pCsrBssDescription = NULL; + uint32_t cbBSSDesc; + uint32_t cbAllocated; + + /* figure out how big the BSS description is (the BSSDesc->length does NOT */ + /* include the size of the length field itself). */ + cbBSSDesc = pBSSDescription->length + sizeof(pBSSDescription->length); + + cbAllocated = sizeof(tCsrScanResult) + cbBSSDesc; + + pCsrBssDescription = qdf_mem_malloc(cbAllocated); + if (NULL != pCsrBssDescription) { + pCsrBssDescription->AgingCount = + (int32_t) pMac->roam.configParam.agingCount; + sms_log(pMac, LOGW, + FL(" Set Aging Count = %d for BSS " MAC_ADDRESS_STR " "), + pCsrBssDescription->AgingCount, + MAC_ADDR_ARRAY(pCsrBssDescription->Result.BssDescriptor. + bssId)); + qdf_mem_copy(&pCsrBssDescription->Result.BssDescriptor, + pBSSDescription, cbBSSDesc); +#if defined(QDF_ENSBALED) + if (NULL != pCsrBssDescription->Result.pvIes) { + QDF_ASSERT(pCsrBssDescription->Result.pvIes == NULL); + return NULL; + } +#endif + csr_scan_add_result(pMac, pCsrBssDescription, pIes, sessionId); + } + + return pCsrBssDescription; +} + +/* Append a Bss Description... */ +tCsrScanResult *csr_scan_append_bss_description(tpAniSirGlobal pMac, + tSirBssDescription * + pSirBssDescription, + tDot11fBeaconIEs *pIes, + uint8_t sessionId) +{ + tCsrScanResult *pCsrBssDescription = NULL; + tAniSSID tmpSsid; + unsigned long timer = 0; + int result; + + tmpSsid.length = 0; + result = csr_remove_dup_bss_description(pMac, pSirBssDescription, + pIes, &tmpSsid, &timer); + pCsrBssDescription = csr_scan_save_bss_description(pMac, + pSirBssDescription, pIes, sessionId); + if (result && (pCsrBssDescription != NULL)) { + /* + * Check if the new one has SSID it it, if not, use the older + * SSID if it exists. + */ + if ((0 == pCsrBssDescription->Result.ssId.length) + && tmpSsid.length) { + /* + * New BSS has a hidden SSID and old one has the SSID. + * Keep the SSID only if diff of saved SSID time and + * current time is less than 1 min to avoid side effect + * of saving SSID with old one is that if AP changes its + * SSID while remain hidden, we may never see it and + * also to address the requirement of. When we remove + * hidden ssid from the profile i.e., forget the SSID + * via GUI that SSID shouldn't see in the profile + */ + if (((uint64_t)qdf_mc_timer_get_system_time() - timer) <= + HIDDEN_TIMER) { + pCsrBssDescription->Result.ssId = tmpSsid; + pCsrBssDescription->Result.timer = timer; + } + } + } + + return pCsrBssDescription; +} + +void csr_purge_channel_power(tpAniSirGlobal pMac, tDblLinkList *pChannelList) +{ + tCsrChannelPowerInfo *pChannelSet; + tListElem *pEntry; + + csr_ll_lock(pChannelList); + /* + * Remove the channel sets from the learned list and put them + * in the free list + */ + while ((pEntry = csr_ll_remove_head(pChannelList, + LL_ACCESS_NOLOCK)) != NULL) { + pChannelSet = GET_BASE_ADDR(pEntry, tCsrChannelPowerInfo, link); + if (pChannelSet) + qdf_mem_free(pChannelSet); + } + csr_ll_unlock(pChannelList); + return; +} + +/* + * Save the channelList into the ultimate storage as the final stage of channel + * Input: pCountryInfo -- the country code (e.g. "USI"), channel list, and power + * limit are all stored inside this data structure + */ +QDF_STATUS csr_save_to_channel_power2_g_5_g(tpAniSirGlobal pMac, + uint32_t tableSize, + tSirMacChanInfo *channelTable) +{ + uint32_t i = tableSize / sizeof(tSirMacChanInfo); + tSirMacChanInfo *pChannelInfo; + tCsrChannelPowerInfo *pChannelSet; + bool f2GHzInfoFound = false; + bool f2GListPurged = false, f5GListPurged = false; + + pChannelInfo = channelTable; + /* atleast 3 bytes have to be remaining -- from "countryString" */ + while (i--) { + pChannelSet = qdf_mem_malloc(sizeof(tCsrChannelPowerInfo)); + if (NULL == pChannelSet) { + pChannelInfo++; + continue; + } + pChannelSet->firstChannel = pChannelInfo->firstChanNum; + pChannelSet->numChannels = pChannelInfo->numChannels; + /* + * Now set the inter-channel offset based on the frequency band + * the channel set lies in + */ + if ((CDS_IS_CHANNEL_24GHZ(pChannelSet->firstChannel)) && + ((pChannelSet->firstChannel + + (pChannelSet->numChannels - 1)) <= + CDS_MAX_24GHZ_CHANNEL_NUMBER)) { + pChannelSet->interChannelOffset = 1; + f2GHzInfoFound = true; + } else if ((CDS_IS_CHANNEL_5GHZ(pChannelSet->firstChannel)) + && ((pChannelSet->firstChannel + + ((pChannelSet->numChannels - 1) * 4)) <= + CDS_MAX_5GHZ_CHANNEL_NUMBER)) { + pChannelSet->interChannelOffset = 4; + f2GHzInfoFound = false; + } else { + sms_log(pMac, LOGW, + FL("Invalid Channel %d Present in Country IE"), + pChannelSet->firstChannel); + qdf_mem_free(pChannelSet); + return QDF_STATUS_E_FAILURE; + } + pChannelSet->txPower = QDF_MIN(pChannelInfo->maxTxPower, + pMac->roam.configParam.nTxPowerCap); + if (f2GHzInfoFound) { + if (!f2GListPurged) { + /* purge previous results if found new */ + csr_purge_channel_power(pMac, + &pMac->scan. + channelPowerInfoList24); + f2GListPurged = true; + } + if (CSR_IS_OPERATING_BG_BAND(pMac)) { + /* add to the list of 2.4 GHz channel sets */ + csr_ll_insert_tail(&pMac->scan. + channelPowerInfoList24, + &pChannelSet->link, + LL_ACCESS_LOCK); + } else { + sms_log(pMac, LOGW, + FL("Adding 11B/G ch in 11A. 1st ch %d"), + pChannelSet->firstChannel); + qdf_mem_free(pChannelSet); + } + } else { + /* 5GHz info found */ + if (!f5GListPurged) { + /* purge previous results if found new */ + csr_purge_channel_power(pMac, + &pMac->scan. + channelPowerInfoList5G); + f5GListPurged = true; + } + if (CSR_IS_OPERATING_A_BAND(pMac)) { + /* add to the list of 5GHz channel sets */ + csr_ll_insert_tail(&pMac->scan. + channelPowerInfoList5G, + &pChannelSet->link, + LL_ACCESS_LOCK); + } else { + sms_log(pMac, LOGW, + FL("Adding 11A ch in B/G. 1st ch %d"), + pChannelSet->firstChannel); + qdf_mem_free(pChannelSet); + } + } + pChannelInfo++; /* move to next entry */ + } + return QDF_STATUS_SUCCESS; +} + +static void csr_clear_dfs_channel_list(tpAniSirGlobal pMac) +{ + tSirMbMsg *pMsg; + uint16_t msgLen; + + msgLen = (uint16_t) (sizeof(tSirMbMsg)); + pMsg = qdf_mem_malloc(msgLen); + if (NULL != pMsg) { + pMsg->type = eWNI_SME_CLEAR_DFS_CHANNEL_LIST; + pMsg->msgLen = msgLen; + cds_send_mb_message_to_mac(pMsg); + } +} + +void csr_apply_power2_current(tpAniSirGlobal pMac) +{ + sms_log(pMac, LOG3, FL(" Updating Cfg with power settings")); + csr_save_tx_power_to_cfg(pMac, &pMac->scan.channelPowerInfoList24, + WNI_CFG_MAX_TX_POWER_2_4); + csr_save_tx_power_to_cfg(pMac, &pMac->scan.channelPowerInfoList5G, + WNI_CFG_MAX_TX_POWER_5); +} + +void csr_apply_channel_power_info_to_fw(tpAniSirGlobal mac_ctx, + tCsrChannel *ch_lst, + uint8_t *countryCode) +{ + int i; + uint8_t num_ch = 0; + uint8_t tempNumChannels = 0; + tCsrChannel tmp_ch_lst; + + if (ch_lst->numChannels) { + tempNumChannels = CSR_MIN(ch_lst->numChannels, + WNI_CFG_VALID_CHANNEL_LIST_LEN); + for (i = 0; i < tempNumChannels; i++) { + tmp_ch_lst.channelList[num_ch] = ch_lst->channelList[i]; + num_ch++; + } + tmp_ch_lst.numChannels = num_ch; + /* Store the channel+power info in the global place: Cfg */ + csr_apply_power2_current(mac_ctx); + csr_set_cfg_valid_channel_list(mac_ctx, tmp_ch_lst.channelList, + tmp_ch_lst.numChannels); + /* + * extend scan capability, build a scan list based on the + * channel list : channel# + active/passive scan + */ + csr_set_cfg_scan_control_list(mac_ctx, countryCode, + &tmp_ch_lst); + /* Send msg to Lim to clear DFS channel list */ + csr_clear_dfs_channel_list(mac_ctx); + } else { + sms_log(mac_ctx, LOGE, FL("11D channel list is empty")); + } + csr_set_cfg_country_code(mac_ctx, countryCode); +} + +#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR +static void csr_diag_reset_country_information(tpAniSirGlobal pMac) +{ + + host_log_802_11d_pkt_type *p11dLog; + int Index; + WLAN_HOST_DIAG_LOG_ALLOC(p11dLog, host_log_802_11d_pkt_type, + LOG_WLAN_80211D_C); + if (!p11dLog) + return; + + p11dLog->eventId = WLAN_80211D_EVENT_RESET; + qdf_mem_copy(p11dLog->countryCode, pMac->scan.countryCodeCurrent, 3); + p11dLog->numChannel = pMac->scan.base_channels.numChannels; + if (p11dLog->numChannel <= HOST_LOG_MAX_NUM_CHANNEL) { + qdf_mem_copy(p11dLog->Channels, + pMac->scan.base_channels.channelList, + p11dLog->numChannel); + for (Index = 0; + Index < pMac->scan.base_channels.numChannels; + Index++) { + p11dLog->TxPwr[Index] = QDF_MIN( + pMac->scan.defaultPowerTable[Index].power, + pMac->roam.configParam.nTxPowerCap); + } + } + if (!pMac->roam.configParam.Is11dSupportEnabled) + p11dLog->supportMultipleDomain = WLAN_80211D_DISABLED; + else + p11dLog->supportMultipleDomain = + WLAN_80211D_SUPPORT_MULTI_DOMAIN; + WLAN_HOST_DIAG_LOG_REPORT(p11dLog); +} +#endif /* FEATURE_WLAN_DIAG_SUPPORT_CSR */ + +/** + * csr_apply_channel_power_info_wrapper() - sends channel info to fw + * @pMac: main MAC data structure + * + * This function sends the channel power info to firmware + * + * Return: none + */ +void csr_apply_channel_power_info_wrapper(tpAniSirGlobal pMac) +{ + +#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR + csr_diag_reset_country_information(pMac); +#endif /* FEATURE_WLAN_DIAG_SUPPORT_CSR */ + csr_prune_channel_list_for_mode(pMac, &pMac->scan.base_channels); + csr_save_channel_power_for_band(pMac, false); + csr_save_channel_power_for_band(pMac, true); + /* apply the channel list, power settings, and the country code. */ + csr_apply_channel_power_info_to_fw(pMac, + &pMac->scan.base_channels, pMac->scan.countryCodeCurrent); + /* clear the 11d channel list */ + qdf_mem_set(&pMac->scan.channels11d, sizeof(pMac->scan.channels11d), 0); +} + +void csr_clear_votes_for_country_info(tpAniSirGlobal pMac) +{ + pMac->scan.countryCodeCount = 0; + qdf_mem_set(pMac->scan.votes11d, + sizeof(tCsrVotes11d) * CSR_MAX_NUM_COUNTRY_CODE, 0); +} + +void csr_add_vote_for_country_info(tpAniSirGlobal pMac, uint8_t *pCountryCode) +{ + bool match = false; + uint8_t i; + + /* convert to UPPER here so we are assured + * the strings are always in upper case. + */ + for (i = 0; i < 3; i++) { + pCountryCode[i] = (uint8_t) csr_to_upper(pCountryCode[i]); + } + + /* Some of the 'old' Cisco 350 series AP's advertise NA as the + * country code (for North America ??). NA is not a valid country code + * or domain so let's allow this by changing it to the proper + * country code (which is US). We've also seen some NETGEAR AP's + * that have "XX " as the country code with valid 2.4 GHz US channel + * information. If we cannot find the country code advertised in the + * 11d information element, let's default to US. + */ + + if (!QDF_IS_STATUS_SUCCESS(csr_get_regulatory_domain_for_country(pMac, + pCountryCode, NULL, + SOURCE_QUERY))) { + pCountryCode[0] = '0'; + pCountryCode[1] = '0'; + } + + /* We've seen some of the AP's improperly put a 0 for the + * third character of the country code. spec says valid charcters are + * 'O' (for outdoor), 'I' for Indoor, or ' ' (space; for either). + * if we see a 0 in this third character, let's change it to a ' '. + */ + if (0 == pCountryCode[2]) { + pCountryCode[2] = ' '; + } + + for (i = 0; i < pMac->scan.countryCodeCount; i++) { + match = (!qdf_mem_cmp(pMac->scan.votes11d[i].countryCode, + pCountryCode, 2)); + if (match) { + break; + } + } + + if (match) { + pMac->scan.votes11d[i].votes++; + } else { + qdf_mem_copy(pMac->scan.votes11d[pMac->scan.countryCodeCount]. + countryCode, pCountryCode, 3); + pMac->scan.votes11d[pMac->scan.countryCodeCount].votes = 1; + pMac->scan.countryCodeCount++; + } + + return; +} + +bool csr_elected_country_info(tpAniSirGlobal pMac) +{ + bool fRet = false; + uint8_t maxVotes = 0; + uint8_t i, j = 0; + + if (!pMac->scan.countryCodeCount) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_WARN, + "No AP with 11d Country code is present in scan list"); + return fRet; + } + maxVotes = pMac->scan.votes11d[0].votes; + fRet = true; + + for (i = 1; i < pMac->scan.countryCodeCount; i++) { + /* If we have a tie for max votes for 2 different country codes, + * pick random.we can put some more intelligence - TBD + */ + if (maxVotes < pMac->scan.votes11d[i].votes) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO, + " Votes for Country %c%c : %d\n", + pMac->scan.votes11d[i].countryCode[0], + pMac->scan.votes11d[i].countryCode[1], + pMac->scan.votes11d[i].votes); + + maxVotes = pMac->scan.votes11d[i].votes; + j = i; + fRet = true; + } + + } + if (fRet) { + qdf_mem_copy(pMac->scan.countryCodeElected, + pMac->scan.votes11d[j].countryCode, + WNI_CFG_COUNTRY_CODE_LEN); + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO, + "Selected Country is %c%c With count %d\n", + pMac->scan.votes11d[j].countryCode[0], + pMac->scan.votes11d[j].countryCode[1], + pMac->scan.votes11d[j].votes); + } + return fRet; +} + +/** + * csr_set_country_code() - Set country code + * @pMac: main MAC data structure + * @pCountry: ptr to Country Code + * + * This function sends the channel power info to firmware + * + * Return: none + */ +QDF_STATUS csr_set_country_code(tpAniSirGlobal pMac, uint8_t *pCountry) +{ + QDF_STATUS status = QDF_STATUS_E_INVAL; + v_REGDOMAIN_t domainId; + + if (pCountry) { + + status = csr_get_regulatory_domain_for_country(pMac, pCountry, + &domainId, + SOURCE_USERSPACE); + if (QDF_IS_STATUS_SUCCESS(status)) { + qdf_mem_copy(pMac->scan.countryCodeCurrent, + pCountry, + WNI_CFG_COUNTRY_CODE_LEN); + csr_set_cfg_country_code(pMac, pCountry); + } + } + return status; +} + +/* caller allocated memory for pNumChn and pChnPowerInfo */ +/* As input, *pNumChn has the size of the array of pChnPowerInfo */ +/* Upon return, *pNumChn has the number of channels assigned. */ +static void csr_get_channel_power_info(tpAniSirGlobal pMac, tDblLinkList *list, + uint32_t *num_ch, + struct channel_power *chn_pwr_info) +{ + tListElem *entry; + uint32_t chn_idx = 0, idx; + tCsrChannelPowerInfo *ch_set; + + /* Get 2.4Ghz first */ + entry = csr_ll_peek_head(list, LL_ACCESS_LOCK); + while (entry && (chn_idx < *num_ch)) { + ch_set = GET_BASE_ADDR(entry, tCsrChannelPowerInfo, link); + for (idx = 0; (idx < ch_set->numChannels) + && (chn_idx < *num_ch); idx++) { + chn_pwr_info[chn_idx].chan_num = + (uint8_t) (ch_set->firstChannel + + (idx * ch_set->interChannelOffset)); + chn_pwr_info[chn_idx++].power = ch_set->txPower; + } + entry = csr_ll_next(list, entry, LL_ACCESS_LOCK); + } + *num_ch = chn_idx; + + return; +} + +#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR +static void csr_diag_apply_country_info(tpAniSirGlobal mac_ctx) +{ + host_log_802_11d_pkt_type *p11dLog; + struct channel_power chnPwrInfo[WNI_CFG_VALID_CHANNEL_LIST_LEN]; + uint32_t nChnInfo = WNI_CFG_VALID_CHANNEL_LIST_LEN, nTmp; + + WLAN_HOST_DIAG_LOG_ALLOC(p11dLog, host_log_802_11d_pkt_type, + LOG_WLAN_80211D_C); + if (!p11dLog) + return; + + p11dLog->eventId = WLAN_80211D_EVENT_COUNTRY_SET; + qdf_mem_copy(p11dLog->countryCode, mac_ctx->scan.countryCode11d, 3); + p11dLog->numChannel = mac_ctx->scan.channels11d.numChannels; + if (p11dLog->numChannel > HOST_LOG_MAX_NUM_CHANNEL) + goto diag_end; + + qdf_mem_copy(p11dLog->Channels, + mac_ctx->scan.channels11d.channelList, + p11dLog->numChannel); + csr_get_channel_power_info(mac_ctx, + &mac_ctx->scan.channelPowerInfoList24, + &nChnInfo, chnPwrInfo); + nTmp = nChnInfo; + nChnInfo = WNI_CFG_VALID_CHANNEL_LIST_LEN - nTmp; + csr_get_channel_power_info(mac_ctx, + &mac_ctx->scan.channelPowerInfoList5G, + &nChnInfo, &chnPwrInfo[nTmp]); + for (nTmp = 0; nTmp < p11dLog->numChannel; nTmp++) { + for (nChnInfo = 0; + nChnInfo < WNI_CFG_VALID_CHANNEL_LIST_LEN; + nChnInfo++) { + if (p11dLog->Channels[nTmp] == + chnPwrInfo[nChnInfo].chan_num) { + p11dLog->TxPwr[nTmp] = + chnPwrInfo[nChnInfo].power; + break; + } + } + } +diag_end: + if (!mac_ctx->roam.configParam.Is11dSupportEnabled) + p11dLog->supportMultipleDomain = WLAN_80211D_DISABLED; + else + p11dLog->supportMultipleDomain = + WLAN_80211D_SUPPORT_MULTI_DOMAIN; + WLAN_HOST_DIAG_LOG_REPORT(p11dLog); +} +#endif /* #ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR */ + +/** + * csr_apply_country_information() - apply country code information + * @pMac: core MAC data structure + * + * This function programs the new country code + * + * Return: none + */ +void csr_apply_country_information(tpAniSirGlobal pMac) +{ + v_REGDOMAIN_t domainId; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + if (!csr_is11d_supported(pMac) + || 0 == pMac->scan.channelOf11dInfo) + return; + status = csr_get_regulatory_domain_for_country(pMac, + pMac->scan.countryCode11d, &domainId, SOURCE_QUERY); + if (!QDF_IS_STATUS_SUCCESS(status)) + return; + /* Check whether we need to enforce default domain */ +#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR + csr_diag_apply_country_info(pMac); +#endif /* #ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR */ + + if (pMac->scan.domainIdCurrent != domainId) + return; + if (pMac->scan.domainIdCurrent != domainId) { + sms_log(pMac, LOGW, FL("Domain Changed Old %d, new %d"), + pMac->scan.domainIdCurrent, domainId); + status = wma_set_reg_domain(pMac, domainId); + } + if (status != QDF_STATUS_SUCCESS) + sms_log(pMac, LOGE, FL("fail to set regId %d"), domainId); + pMac->scan.domainIdCurrent = domainId; + /* switch to active scans using this new channel list */ + pMac->scan.curScanType = eSIR_ACTIVE_SCAN; +} + +void csr_save_channel_power_for_band(tpAniSirGlobal pMac, bool fill_5f) +{ + uint32_t idx, count = 0; + tSirMacChanInfo *chan_info; + tSirMacChanInfo *ch_info_start; + int32_t max_ch_idx; + bool tmp_bool; + uint8_t ch = 0; + + max_ch_idx = + (pMac->scan.base_channels.numChannels < + WNI_CFG_VALID_CHANNEL_LIST_LEN) ? + pMac->scan.base_channels.numChannels : + WNI_CFG_VALID_CHANNEL_LIST_LEN; + + chan_info = qdf_mem_malloc(sizeof(tSirMacChanInfo) * + WNI_CFG_VALID_CHANNEL_LIST_LEN); + if (NULL == chan_info) + return; + + ch_info_start = chan_info; + for (idx = 0; idx < max_ch_idx; idx++) { + ch = pMac->scan.defaultPowerTable[idx].chan_num; + tmp_bool = (fill_5f && CDS_IS_CHANNEL_5GHZ(ch)) + || (!fill_5f && CDS_IS_CHANNEL_24GHZ(ch)); + if (!tmp_bool) + continue; + + if (count >= WNI_CFG_VALID_CHANNEL_LIST_LEN) { + sms_log(pMac, LOGW, FL("count(%d) exceeded"), count); + break; + } + + chan_info->firstChanNum = + pMac->scan.defaultPowerTable[idx].chan_num; + chan_info->numChannels = 1; + chan_info->maxTxPower = + QDF_MIN(pMac->scan.defaultPowerTable[idx].power, + pMac->roam.configParam.nTxPowerCap); + chan_info++; + count++; + } + if (count) { + csr_save_to_channel_power2_g_5_g(pMac, + count * sizeof(tSirMacChanInfo), ch_info_start); + } + qdf_mem_free(ch_info_start); +} + +bool csr_is_supported_channel(tpAniSirGlobal pMac, uint8_t channelId) +{ + bool fRet = false; + uint32_t i; + + for (i = 0; i < pMac->scan.base_channels.numChannels; i++) { + if (channelId == + pMac->scan.base_channels.channelList[i]) { + fRet = true; + break; + } + } + + return fRet; +} + +/* + * 802.11D only: Gather 11d IE via beacon or Probe response and store them in pAdapter->channels11d + */ +bool csr_learn_11dcountry_information(tpAniSirGlobal pMac, + tSirBssDescription *pSirBssDesc, + tDot11fBeaconIEs *pIes, bool fForce) +{ + QDF_STATUS status; + uint8_t *pCountryCodeSelected; + bool fRet = false; + v_REGDOMAIN_t domainId; + tDot11fBeaconIEs *pIesLocal = pIes; + bool useVoting = false; + + if ((NULL == pSirBssDesc) && (NULL == pIes)) + useVoting = true; + + /* check if .11d support is enabled */ + if (!csr_is11d_supported(pMac)) + goto free_ie; + + if (false == useVoting) { + if (!pIesLocal && + (!QDF_IS_STATUS_SUCCESS( + csr_get_parsed_bss_description_ies( + pMac, pSirBssDesc, &pIesLocal)))) + goto free_ie; + /* check if country information element is present */ + if (!pIesLocal->Country.present) + /* No country info */ + goto free_ie; + status = csr_get_regulatory_domain_for_country(pMac, + pIesLocal->Country.country, &domainId, + SOURCE_QUERY); + if (QDF_IS_STATUS_SUCCESS(status) + && (domainId == REGDOMAIN_WORLD)) + goto free_ie; + } /* useVoting == false */ + + if (false == useVoting) + pCountryCodeSelected = pIesLocal->Country.country; + else + pCountryCodeSelected = pMac->scan.countryCodeElected; + + if (qdf_mem_cmp(pCountryCodeSelected, pMac->scan.countryCodeCurrent, + CDS_COUNTRY_CODE_LEN) == 0) { + qdf_mem_copy(pMac->scan.countryCode11d, + pMac->scan.countryCodeCurrent, + CDS_COUNTRY_CODE_LEN); + goto free_ie; + } + + pMac->reg_hint_src = SOURCE_11D; + status = csr_get_regulatory_domain_for_country(pMac, + pCountryCodeSelected, &domainId, SOURCE_11D); + if (status != QDF_STATUS_SUCCESS) { + sms_log(pMac, LOGE, FL("fail to get regId %d"), domainId); + fRet = false; + goto free_ie; + } + + fRet = true; +free_ie: + if (!pIes && pIesLocal) { + /* locally allocated */ + qdf_mem_free(pIesLocal); + } + return fRet; +} + +void csr_save_scan_results(tpAniSirGlobal pMac, uint8_t reason, + uint8_t sessionId) +{ + sms_log(pMac, LOG4, "%s: Saving scan results", __func__); + + /* initialize this to false. profMoveInterimScanResultsToMainList() routine */ + /* will set this to the channel where an .11d beacon is seen */ + pMac->scan.channelOf11dInfo = 0; + /* move the scan results from interim list to the main scan list */ + csr_move_temp_scan_results_to_main_list(pMac, reason, sessionId); + + /* Now check if we gathered any domain/country specific information */ + /* If so, we should update channel list and apply Tx power settings */ + if (csr_is11d_supported(pMac)) { + csr_apply_country_information(pMac); + } +} + +void csr_reinit_scan_cmd(tpAniSirGlobal pMac, tSmeCmd *pCommand) +{ + switch (pCommand->u.scanCmd.reason) { + case eCsrScanAbortNormalScan: + default: + csr_scan_free_request(pMac, &pCommand->u.scanCmd.u.scanRequest); + break; + } + if (pCommand->u.scanCmd.pToRoamProfile) { + csr_release_profile(pMac, pCommand->u.scanCmd.pToRoamProfile); + qdf_mem_free(pCommand->u.scanCmd.pToRoamProfile); + } + qdf_mem_set(&pCommand->u.scanCmd, sizeof(tScanCmd), 0); +} + +static eCsrScanCompleteNextCommand csr_scan_get_next_command_state( + tpAniSirGlobal pMac, + tSmeCmd *pCommand, + bool fSuccess, + uint8_t *chan) +{ + eCsrScanCompleteNextCommand NextCommand = eCsrNextScanNothing; + int8_t channel; + + switch (pCommand->u.scanCmd.reason) { + case eCsrScan11d1: + NextCommand = + (fSuccess) ? eCsrNext11dScan1Success : + eCsrNext11dScan1Failure; + break; + case eCsrScan11d2: + NextCommand = + (fSuccess) ? eCsrNext11dScan2Success : + eCsrNext11dScan2Failure; + break; + case eCsrScan11dDone: + NextCommand = eCsrNext11dScanComplete; + break; + case eCsrScanLostLink1: + NextCommand = + (fSuccess) ? eCsrNextLostLinkScan1Success : + eCsrNextLostLinkScan1Failed; + break; + case eCsrScanLostLink2: + NextCommand = + (fSuccess) ? eCsrNextLostLinkScan2Success : + eCsrNextLostLinkScan2Failed; + break; + case eCsrScanLostLink3: + NextCommand = + (fSuccess) ? eCsrNextLostLinkScan3Success : + eCsrNextLostLinkScan3Failed; + break; + case eCsrScanForSsid: + /* success: + * set hw_mode success -> csr_scan_handle_search_for_ssid + * set hw_mode fail -> csr_scan_handle_search_for_ssid_failure + * failure: csr_scan_handle_search_for_ssid_failure + */ + sms_log(pMac, LOG1, FL("Resp for eCsrScanForSsid")); + channel = cds_search_and_check_for_session_conc( + pCommand->sessionId, + pCommand->u.scanCmd.pToRoamProfile); + if ((!channel) || !fSuccess) { + NextCommand = eCsrNexteScanForSsidFailure; + sms_log(pMac, LOG1, + FL("next ScanForSsidFailure %d %d"), + channel, fSuccess); + } else { + NextCommand = eCsrNextCheckAllowConc; + *chan = channel; + sms_log(pMac, LOG1, FL("next CheckAllowConc")); + } + break; + default: + NextCommand = eCsrNextScanNothing; + break; + } + return NextCommand; +} + +/* Return whether the pCommand is finished. */ +static bool csr_handle_scan11d1_failure(tpAniSirGlobal pMac, tSmeCmd *pCommand) +{ + bool fRet = true; + + /* Apply back the default setting and passively scan one more time. */ + csr_apply_channel_power_info_wrapper(pMac); + pCommand->u.scanCmd.reason = eCsrScan11d2; + if (QDF_IS_STATUS_SUCCESS(csr_scan_channels(pMac, pCommand))) { + fRet = false; + } + + return fRet; +} + +#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR +static void +csr_diag_scan_complete(tpAniSirGlobal pMac, + tSmeCmd *pCommand, + tSirSmeScanRsp *pScanRsp) +{ + host_log_scan_pkt_type *pScanLog = NULL; + tScanResultHandle hScanResult; + tCsrScanResultInfo *pScanResult; + tDot11fBeaconIEs *pIes; + int n = 0, c = 0; + QDF_STATUS status; + + WLAN_HOST_DIAG_LOG_ALLOC(pScanLog, + host_log_scan_pkt_type, + LOG_WLAN_SCAN_C); + if (!pScanLog) + return; + + if (eCsrScanProbeBss == pCommand->u.scanCmd.reason) { + pScanLog->eventId = WLAN_SCAN_EVENT_HO_SCAN_RSP; + } else { + if (eSIR_PASSIVE_SCAN != pMac->scan.curScanType) + pScanLog->eventId = WLAN_SCAN_EVENT_ACTIVE_SCAN_RSP; + else + pScanLog->eventId = WLAN_SCAN_EVENT_PASSIVE_SCAN_RSP; + } + if (eSIR_SME_SUCCESS != pScanRsp->statusCode) { + pScanLog->status = WLAN_SCAN_STATUS_FAILURE; + WLAN_HOST_DIAG_LOG_REPORT(pScanLog); + return; + } + + status = csr_scan_get_result(pMac, NULL, &hScanResult); + if (!QDF_IS_STATUS_SUCCESS(status)) { + WLAN_HOST_DIAG_LOG_REPORT(pScanLog); + return; + } + + pScanResult = csr_scan_result_get_next(pMac, hScanResult); + while (pScanResult != NULL) { + if (n < HOST_LOG_MAX_NUM_BSSID) { + status = csr_get_parsed_bss_description_ies(pMac, + &pScanResult->BssDescriptor, &pIes); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOGE, FL("fail to parse IEs")); + break; + } + qdf_mem_copy(pScanLog->bssid[n], + pScanResult->BssDescriptor.bssId, 6); + if (pIes && pIes->SSID.present && + HOST_LOG_MAX_SSID_SIZE >= pIes->SSID.num_ssid) { + qdf_mem_copy(pScanLog->ssid[n], + pIes->SSID.ssid, + pIes->SSID.num_ssid); + } + qdf_mem_free(pIes); + n++; + } + c++; + pScanResult = csr_scan_result_get_next(pMac, hScanResult); + } + pScanLog->numSsid = (uint8_t) n; + pScanLog->totalSsid = (uint8_t) c; + csr_scan_result_purge(pMac, hScanResult); + WLAN_HOST_DIAG_LOG_REPORT(pScanLog); + + csr_diag_event_report(pMac, eCSR_EVENT_SCAN_COMPLETE, eSIR_SUCCESS, + eSIR_SUCCESS); + if (c > 0) + csr_diag_event_report(pMac, eCSR_EVENT_SCAN_RES_FOUND, + eSIR_SUCCESS, eSIR_SUCCESS); +} +#endif /* #ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR */ + +/** + * csr_saved_scan_cmd_free_fields() - Free internal fields of scan command + * + * @mac_ctx: Global MAC context + * @saved_scan_cmd: Pointer to scan command + * + * Frees data structures allocated inside saved_scan_cmd and releases + * the profile. + * Return: None + */ + +static void csr_saved_scan_cmd_free_fields(tpAniSirGlobal mac_ctx, + tSmeCmd *saved_scan_cmd) +{ + if (saved_scan_cmd->u.scanCmd.pToRoamProfile) { + csr_release_profile(mac_ctx, + saved_scan_cmd->u.scanCmd.pToRoamProfile); + qdf_mem_free(saved_scan_cmd->u.scanCmd.pToRoamProfile); + saved_scan_cmd->u.scanCmd.pToRoamProfile = NULL; + } + if (saved_scan_cmd->u.scanCmd.u.scanRequest.SSIDs.SSIDList) { + qdf_mem_free(saved_scan_cmd->u.scanCmd.u. + scanRequest.SSIDs.SSIDList); + saved_scan_cmd->u.scanCmd.u.scanRequest.SSIDs.SSIDList = NULL; + } + if (saved_scan_cmd->u.roamCmd.pRoamBssEntry) { + qdf_mem_free(saved_scan_cmd->u.roamCmd.pRoamBssEntry); + saved_scan_cmd->u.roamCmd.pRoamBssEntry = NULL; + } +} + +/** + * csr_save_profile() - Save the profile info from sme command + * @mac_ctx: Global MAC context + * @save_cmd: Pointer where the command will be saved + * @command: Command from which the profile will be saved + * + * Saves the profile information from the SME's scan command + * + * Return: QDF_STATUS + */ +static QDF_STATUS csr_save_profile(tpAniSirGlobal mac_ctx, + tSmeCmd *save_cmd, tSmeCmd *command) +{ + tCsrScanResult *scan_result; + tCsrScanResult *temp; + uint32_t bss_len; + QDF_STATUS status; + + save_cmd->u.scanCmd.pToRoamProfile = + qdf_mem_malloc(sizeof(tCsrRoamProfile)); + if (!save_cmd->u.scanCmd.pToRoamProfile) { + sms_log(mac_ctx, LOGE, FL("pToRoamProfile mem fail")); + goto error; + } + + status = csr_roam_copy_profile(mac_ctx, + save_cmd->u.scanCmd.pToRoamProfile, + command->u.scanCmd.pToRoamProfile); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sms_log(mac_ctx, LOGE, FL("csr_roam_copy_profile fail")); + goto error; + } + + save_cmd->sessionId = command->sessionId; + save_cmd->u.scanCmd.roamId = command->u.scanCmd.roamId; + save_cmd->u.scanCmd.u.scanRequest.SSIDs.numOfSSIDs = + command->u.scanCmd.u.scanRequest.SSIDs.numOfSSIDs; + save_cmd->u.scanCmd.u.scanRequest.SSIDs.SSIDList = + qdf_mem_malloc( + save_cmd->u.scanCmd.u.scanRequest.SSIDs.numOfSSIDs * + sizeof(tCsrSSIDInfo)); + if (!save_cmd->u.scanCmd.u.scanRequest.SSIDs.SSIDList) { + sms_log(mac_ctx, LOGE, FL("SSIDList mem fail")); + goto error; + } + + qdf_mem_copy(save_cmd->u.scanCmd.u.scanRequest.SSIDs.SSIDList, + command->u.scanCmd.u.scanRequest.SSIDs.SSIDList, + save_cmd->u.scanCmd.u.scanRequest.SSIDs.numOfSSIDs * + sizeof(tCsrSSIDInfo)); + + if (!command->u.roamCmd.pRoamBssEntry) + return QDF_STATUS_SUCCESS; + + scan_result = GET_BASE_ADDR(command->u.roamCmd.pRoamBssEntry, + tCsrScanResult, Link); + + bss_len = scan_result->Result.BssDescriptor.length + + sizeof(scan_result->Result.BssDescriptor.length); + + temp = qdf_mem_malloc(sizeof(tCsrScanResult) + bss_len); + if (!temp) { + sms_log(mac_ctx, LOGE, FL("bss mem fail")); + goto error; + } + + temp->AgingCount = scan_result->AgingCount; + temp->preferValue = scan_result->preferValue; + temp->capValue = scan_result->capValue; + temp->ucEncryptionType = scan_result->ucEncryptionType; + temp->mcEncryptionType = scan_result->mcEncryptionType; + temp->authType = scan_result->authType; + /* pvIes is unsued in success/failure */ + temp->Result.pvIes = NULL; + + qdf_mem_copy(temp->Result.pvIes, + scan_result->Result.pvIes, + sizeof(*scan_result->Result.pvIes)); + temp->Result.ssId.length = scan_result->Result.ssId.length; + qdf_mem_copy(temp->Result.ssId.ssId, + scan_result->Result.ssId.ssId, + sizeof(scan_result->Result.ssId.ssId)); + temp->Result.timer = scan_result->Result.timer; + qdf_mem_copy(&temp->Result.BssDescriptor, + &scan_result->Result.BssDescriptor, + sizeof(temp->Result.BssDescriptor)); + temp->Link.last = temp->Link.next = NULL; + save_cmd->u.roamCmd.pRoamBssEntry = (tListElem *)temp; + + return QDF_STATUS_SUCCESS; +error: + csr_scan_handle_search_for_ssid_failure(mac_ctx, + command); + csr_saved_scan_cmd_free_fields(mac_ctx, save_cmd); + + return QDF_STATUS_E_FAILURE; +} + +static void +csr_handle_nxt_cmd(tpAniSirGlobal mac_ctx, tSmeCmd *pCommand, + eCsrScanCompleteNextCommand *nxt_cmd, + bool *remove_cmd, uint32_t session_id, + uint8_t chan) +{ + QDF_STATUS status, ret; + tSmeCmd *save_cmd = NULL; + tSmeCmd *saved_scan_cmd; + + switch (*nxt_cmd) { + case eCsrNext11dScan1Success: + case eCsrNext11dScan2Success: + sms_log(mac_ctx, LOG2, + FL("11dScan1/3 produced results. Reissue Active scan")); + /* + * if we found country information, no need to continue scanning + * further, bail out + */ + *remove_cmd = true; + *nxt_cmd = eCsrNext11dScanComplete; + break; + case eCsrNext11dScan1Failure: + /* + * We are not done yet. 11d scan fail once. We will try to reset + * anything and do it over again. The only meaningful thing for + * this retry is that we cannot find 11d information after a + * reset so we clear the "old" 11d info and give it once more + * chance + */ + *remove_cmd = csr_handle_scan11d1_failure(mac_ctx, pCommand); + if (*remove_cmd) + *nxt_cmd = eCsrNext11dScanComplete; + break; + case eCsrNextLostLinkScan1Success: + status = csr_issue_roam_after_lostlink_scan(mac_ctx, session_id, + eCsrLostLink1); + if (!QDF_IS_STATUS_SUCCESS(status)) + csr_scan_handle_failed_lostlink1(mac_ctx, session_id); + break; + case eCsrNextLostLinkScan2Success: + status = csr_issue_roam_after_lostlink_scan(mac_ctx, session_id, + eCsrLostLink2); + if (!QDF_IS_STATUS_SUCCESS(status)) + csr_scan_handle_failed_lostlink2(mac_ctx, session_id); + break; + case eCsrNextLostLinkScan3Success: + status = csr_issue_roam_after_lostlink_scan(mac_ctx, session_id, + eCsrLostLink3); + if (!QDF_IS_STATUS_SUCCESS(status)) + csr_scan_handle_failed_lostlink3(mac_ctx, session_id); + break; + case eCsrNextLostLinkScan1Failed: + csr_scan_handle_failed_lostlink1(mac_ctx, session_id); + break; + case eCsrNextLostLinkScan2Failed: + csr_scan_handle_failed_lostlink2(mac_ctx, session_id); + break; + case eCsrNextLostLinkScan3Failed: + csr_scan_handle_failed_lostlink3(mac_ctx, session_id); + break; + case eCsrNexteScanForSsidSuccess: + csr_scan_handle_search_for_ssid(mac_ctx, pCommand); + break; + case eCsrNexteScanForSsidFailure: + csr_scan_handle_search_for_ssid_failure(mac_ctx, pCommand); + break; + case eCsrNextCheckAllowConc: + ret = cds_current_connections_update(pCommand->sessionId, + chan, + SIR_UPDATE_REASON_HIDDEN_STA); + sms_log(mac_ctx, LOG1, FL("chan: %d session: %d status: %d"), + chan, pCommand->sessionId, ret); + saved_scan_cmd = (tSmeCmd *)mac_ctx->sme.saved_scan_cmd; + if (saved_scan_cmd) { + csr_saved_scan_cmd_free_fields(mac_ctx, + saved_scan_cmd); + qdf_mem_free(saved_scan_cmd); + saved_scan_cmd = NULL; + sms_log(mac_ctx, LOGE, + FL("memory should have been free. Check!")); + } + + save_cmd = (tSmeCmd *) qdf_mem_malloc(sizeof(*pCommand)); + if (!save_cmd) { + sms_log(mac_ctx, LOGE, FL("save_cmd mem fail")); + goto error; + } + + status = csr_save_profile(mac_ctx, save_cmd, pCommand); + if (!QDF_IS_STATUS_SUCCESS(status)) { + /* csr_save_profile should report error */ + sms_log(mac_ctx, LOGE, FL("profile save failed %d"), + status); + qdf_mem_free(save_cmd); + return; + } + + mac_ctx->sme.saved_scan_cmd = (void *)save_cmd; + + if (QDF_STATUS_E_FAILURE == ret) { +error: + sms_log(mac_ctx, LOGE, FL("conn update fail %d"), chan); + csr_scan_handle_search_for_ssid_failure(mac_ctx, + pCommand); + if (mac_ctx->sme.saved_scan_cmd) { + csr_saved_scan_cmd_free_fields(mac_ctx, + mac_ctx->sme.saved_scan_cmd); + qdf_mem_free(mac_ctx->sme.saved_scan_cmd); + mac_ctx->sme.saved_scan_cmd = NULL; + } + } else if ((QDF_STATUS_E_NOSUPPORT == ret) || + (QDF_STATUS_E_ALREADY == ret)) { + sms_log(mac_ctx, LOGE, FL("conn update ret %d"), ret); + csr_scan_handle_search_for_ssid(mac_ctx, pCommand); + if (mac_ctx->sme.saved_scan_cmd) { + csr_saved_scan_cmd_free_fields(mac_ctx, + mac_ctx->sme.saved_scan_cmd); + qdf_mem_free(mac_ctx->sme.saved_scan_cmd); + mac_ctx->sme.saved_scan_cmd = NULL; + } + } + /* Else: Set hw mode was issued and the saved connect would + * be issued after set hw mode response + */ + break; + default: + break; + } +} + +/** + * csr_get_active_scan_entry() - To get scan entry from active command list + * + * @mac_ctx - MAC context + * @scan_id - Scan identifier of the scan request + * @entry - scan entry returned. + * + * Scan entry in the active scan list mapping to the sent scan id + * is returned to the caller. + * + * Return: QDF_STATUS. + */ +QDF_STATUS csr_get_active_scan_entry(tpAniSirGlobal mac_ctx, + uint32_t scan_id, tListElem **entry) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tListElem *localentry; + tSmeCmd *cmd; + uint32_t cmd_scan_id = 0; + + csr_ll_lock(&mac_ctx->sme.smeScanCmdActiveList); + + if (csr_ll_is_list_empty(&mac_ctx->sme.smeScanCmdActiveList, + LL_ACCESS_NOLOCK)) { + sms_log(mac_ctx, LOGE, + FL(" Active list Empty scanId: %d"), scan_id); + csr_ll_unlock(&mac_ctx->sme.smeScanCmdActiveList); + return QDF_STATUS_SUCCESS; + } + localentry = csr_ll_peek_head(&mac_ctx->sme.smeScanCmdActiveList, + LL_ACCESS_NOLOCK); + while (localentry) { + cmd = GET_BASE_ADDR(localentry, tSmeCmd, Link); + if (cmd->command == eSmeCommandScan) + cmd_scan_id = cmd->u.scanCmd.u.scanRequest.scan_id; + else if (cmd->command == eSmeCommandRemainOnChannel) + cmd_scan_id = cmd->u.remainChlCmd.scan_id; + if (cmd_scan_id == scan_id) { + sms_log(mac_ctx, LOG1, FL(" scanId Matched %d"), + scan_id); + *entry = localentry; + csr_ll_unlock(&mac_ctx->sme.smeScanCmdActiveList); + return QDF_STATUS_SUCCESS; + } + localentry = csr_ll_next(&mac_ctx->sme.smeScanCmdActiveList, + localentry, LL_ACCESS_NOLOCK); + } + csr_ll_unlock(&mac_ctx->sme.smeScanCmdActiveList); + return status; +} + +/* Return whether the command should be removed */ +bool csr_scan_complete(tpAniSirGlobal pMac, tSirSmeScanRsp *pScanRsp) +{ + eCsrScanCompleteNextCommand NextCommand = eCsrNextScanNothing; + tListElem *pEntry = NULL; + tSmeCmd *pCommand; + bool fRemoveCommand = true; + bool fSuccess; + uint32_t sessionId = 0; + uint8_t chan; + + csr_get_active_scan_entry(pMac, pScanRsp->scan_id, &pEntry); + if (!pEntry) { + sms_log(pMac, LOGE, + FL("Scan Completion called but NO cmd ACTIVE ...")); + return false; + } + + pCommand = GET_BASE_ADDR(pEntry, tSmeCmd, Link); + /* + * If the head of the queue is Active and it is a SCAN command, remove + * and put this on the Free queue. + */ + if (eSmeCommandScan != pCommand->command) { + sms_log(pMac, LOGW, + FL("Scan Completion called, but active SCAN cmd")); + return false; + } + + sessionId = pCommand->sessionId; + if (eSIR_SME_SUCCESS != pScanRsp->statusCode) { + fSuccess = false; + } else { + /* + * pMac->scan.tempScanResults is not empty meaning the scan + * found something. This check only valid here because + * csrSaveScanresults is not yet called + */ + fSuccess = (!csr_ll_is_list_empty(&pMac->scan.tempScanResults, + LL_ACCESS_LOCK)); + } + if (pCommand->u.scanCmd.abort_scan_indication & + eCSR_SCAN_ABORT_DUE_TO_BAND_CHANGE) { + /* + * Scan aborted due to band change + * The scan results need to be flushed + */ + if (pCommand->u.scanCmd.callback + != pMac->scan.callback11dScanDone) { + sms_log(pMac, LOG1, FL("Filtering the scan results")); + csr_scan_filter_results(pMac); + } else { + sms_log(pMac, LOG1, + FL("11d_scan_done, flushing the scan results")); + } + } + csr_save_scan_results(pMac, pCommand->u.scanCmd.reason, sessionId); + +#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR + csr_diag_scan_complete(pMac, pCommand, pScanRsp); +#endif /* #ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR */ + NextCommand = csr_scan_get_next_command_state(pMac, pCommand, fSuccess, + &chan); + /* We reuse the command here instead reissue a new command */ + csr_handle_nxt_cmd(pMac, pCommand, &NextCommand, + &fRemoveCommand, sessionId, chan); + return fRemoveCommand; +} + +static void +csr_scan_remove_dup_bss_description_from_interim_list(tpAniSirGlobal mac_ctx, + tSirBssDescription *bss_dscp, + tDot11fBeaconIEs *pIes, uint32_t flags) +{ + tListElem *pEntry; + tCsrScanResult *scan_bss_dscp; + int8_t scan_entry_rssi = 0; + /* + * Walk through all the chained BssDescriptions. If we find a chained + * BssDescription that matches the BssID of the BssDescription passed + * in, then these must be duplicate scan results for this Bss. In that + * case, remove the 'old' Bss description from the linked list. + */ + sms_log(mac_ctx, LOG4, FL(" for BSS " MAC_ADDRESS_STR " "), + MAC_ADDR_ARRAY(bss_dscp->bssId)); + csr_ll_lock(&mac_ctx->scan.tempScanResults); + pEntry = csr_ll_peek_head(&mac_ctx->scan.tempScanResults, + LL_ACCESS_NOLOCK); + while (pEntry) { + scan_bss_dscp = GET_BASE_ADDR(pEntry, tCsrScanResult, Link); + /* + * we have a duplicate scan results only when BSSID, SSID, + * Channel and NetworkType matches + */ + scan_entry_rssi = scan_bss_dscp->Result.BssDescriptor.rssi; + if (csr_is_duplicate_bss_description(mac_ctx, + &scan_bss_dscp->Result.BssDescriptor, bss_dscp, pIes)) { + + /* Do not update RSSI id skip RSSI Update flag is set */ + if (flags & WLAN_SKIP_RSSI_UPDATE) { + bss_dscp->rssi = + scan_bss_dscp->Result.BssDescriptor.rssi; + bss_dscp->rssi_raw = + scan_bss_dscp->Result.BssDescriptor.rssi_raw; + } else { + /* + * Following is mathematically + * a = (aX + b(100-X))/100 where: + * a = bss_dscp->rssi, b = scan_entry_rssi + * and X = CSR_SCAN_RESULT_RSSI_WEIGHT + */ + bss_dscp->rssi = (int8_t) + ((((int32_t) bss_dscp->rssi * + CSR_SCAN_RESULT_RSSI_WEIGHT) + + ((int32_t) scan_entry_rssi * + (100 - CSR_SCAN_RESULT_RSSI_WEIGHT))) + / 100); + } + /* Remove the 'old' entry from the list */ + if (csr_ll_remove_entry(&mac_ctx->scan.tempScanResults, + pEntry, LL_ACCESS_NOLOCK)) { + csr_check_n_save_wsc_ie(mac_ctx, bss_dscp, + &scan_bss_dscp->Result. + BssDescriptor); + /* + * we need to free the memory associated with + * this node + */ + csr_free_scan_result_entry(mac_ctx, + scan_bss_dscp); + } + /* + * If we found a match, we can stop looking through + * the list. + */ + break; + } + pEntry = csr_ll_next(&mac_ctx->scan.tempScanResults, pEntry, + LL_ACCESS_NOLOCK); + } + + csr_ll_unlock(&mac_ctx->scan.tempScanResults); +} + +/* Caller allocated memory pfNewBssForConn to return whether new candidate for */ +/* current connection is found. Cannot be NULL */ +static tCsrScanResult *csr_scan_save_bss_description_to_interim_list( + tpAniSirGlobal pMac, + tSirBssDescription *pBSSDescription, + tDot11fBeaconIEs *pIes) +{ + tCsrScanResult *pCsrBssDescription = NULL; + uint32_t cbBSSDesc; + uint32_t cbAllocated; + + /* figure out how big the BSS description is (the BSSDesc->length does NOT */ + /* include the size of the length field itself). */ + cbBSSDesc = pBSSDescription->length + sizeof(pBSSDescription->length); + + cbAllocated = sizeof(tCsrScanResult) + cbBSSDesc; + + sms_log(pMac, LOG4, FL("new BSS description, length %d, cbBSSDesc %d"), + cbAllocated, cbBSSDesc); + pCsrBssDescription = qdf_mem_malloc(cbAllocated); + if (NULL != pCsrBssDescription) { + qdf_mem_copy(&pCsrBssDescription->Result.BssDescriptor, + pBSSDescription, cbBSSDesc); + pCsrBssDescription->AgingCount = + (int32_t) pMac->roam.configParam.agingCount; + sms_log(pMac, LOG4, + FL(" Set Aging Count = %d for BSS " MAC_ADDRESS_STR " "), + pCsrBssDescription->AgingCount, + MAC_ADDR_ARRAY(pCsrBssDescription->Result.BssDescriptor. + bssId)); + /* Save SSID separately for later use */ + if (pIes->SSID.present + && !csr_is_nullssid(pIes->SSID.ssid, pIes->SSID.num_ssid)) { + /* SSID not hidden */ + uint32_t len = pIes->SSID.num_ssid; + if (len > SIR_MAC_MAX_SSID_LENGTH) { + /* truncate to fit in our struct */ + len = SIR_MAC_MAX_SSID_LENGTH; + } + pCsrBssDescription->Result.ssId.length = len; + pCsrBssDescription->Result.timer = + qdf_mc_timer_get_system_time(); + qdf_mem_copy(pCsrBssDescription->Result.ssId.ssId, + pIes->SSID.ssid, len); + } + csr_ll_insert_tail(&pMac->scan.tempScanResults, + &pCsrBssDescription->Link, LL_ACCESS_LOCK); + } + + return pCsrBssDescription; +} + +bool csr_is_duplicate_bss_description(tpAniSirGlobal pMac, + tSirBssDescription *pSirBssDesc1, + tSirBssDescription *pSirBssDesc2, + tDot11fBeaconIEs *pIes2) +{ + bool fMatch = false; + tSirMacCapabilityInfo *pCap1, *pCap2; + tDot11fBeaconIEs *pIes1 = NULL; + tDot11fBeaconIEs *pIesTemp = pIes2; + QDF_STATUS status; + + pCap1 = (tSirMacCapabilityInfo *) &pSirBssDesc1->capabilityInfo; + pCap2 = (tSirMacCapabilityInfo *) &pSirBssDesc2->capabilityInfo; + + if (pCap1->ess != pCap2->ess) { + if (qdf_is_macaddr_equal( + (struct qdf_mac_addr *) pSirBssDesc1->bssId, + (struct qdf_mac_addr *) pSirBssDesc2->bssId)) + sms_log(pMac, LOGE, + FL("ess mismatch for same BSSID "MAC_ADDRESS_STR""), + MAC_ADDR_ARRAY(pSirBssDesc1->bssId)); + + goto free_ies; + } + + if (pCap1->ess && + qdf_is_macaddr_equal((struct qdf_mac_addr *) pSirBssDesc1->bssId, + (struct qdf_mac_addr *) pSirBssDesc2->bssId)) { + fMatch = true; + /* Check for SSID match, if exists */ + status = csr_get_parsed_bss_description_ies(pMac, pSirBssDesc1, + &pIes1); + if (!QDF_IS_STATUS_SUCCESS(status)) + goto free_ies; + + if (NULL == pIesTemp) { + status = csr_get_parsed_bss_description_ies(pMac, + pSirBssDesc2, &pIesTemp); + if (!QDF_IS_STATUS_SUCCESS(status)) + goto free_ies; + } + } else if (pCap1->ibss && (pSirBssDesc1->channelId == + pSirBssDesc2->channelId)) { + status = csr_get_parsed_bss_description_ies(pMac, pSirBssDesc1, + &pIes1); + if (!QDF_IS_STATUS_SUCCESS(status)) + goto free_ies; + + if (NULL == pIesTemp) { + status = csr_get_parsed_bss_description_ies(pMac, + pSirBssDesc2, &pIesTemp); + if (!QDF_IS_STATUS_SUCCESS(status)) + goto free_ies; + } + } + /* In case of P2P devices, ess and ibss will be set to zero */ + else if (!pCap1->ess && + qdf_is_macaddr_equal( + (struct qdf_mac_addr *) pSirBssDesc1->bssId, + (struct qdf_mac_addr *) pSirBssDesc2->bssId)) { + fMatch = true; + } + +free_ies: + if (pIes1) + qdf_mem_free(pIes1); + if ((NULL == pIes2) && pIesTemp) + /* locally allocated */ + qdf_mem_free(pIesTemp); + return fMatch; +} + +bool csr_is_network_type_equal(tSirBssDescription *pSirBssDesc1, + tSirBssDescription *pSirBssDesc2) +{ + return pSirBssDesc1->nwType == pSirBssDesc2->nwType; +} + +/* to check whether the BSS matches the dot11Mode */ +static bool csr_scan_is_bss_allowed(tpAniSirGlobal pMac, + tSirBssDescription *pBssDesc, + tDot11fBeaconIEs *pIes) +{ + bool fAllowed = false; + eCsrPhyMode phyMode; + + if (QDF_IS_STATUS_SUCCESS + (csr_get_phy_mode_from_bss(pMac, pBssDesc, &phyMode, pIes))) { + switch (pMac->roam.configParam.phyMode) { + case eCSR_DOT11_MODE_11b: + fAllowed = (bool) (eCSR_DOT11_MODE_11a != phyMode); + break; + case eCSR_DOT11_MODE_11g: + fAllowed = (bool) (eCSR_DOT11_MODE_11a != phyMode); + break; + case eCSR_DOT11_MODE_11g_ONLY: + fAllowed = (bool) (eCSR_DOT11_MODE_11g == phyMode); + break; + case eCSR_DOT11_MODE_11a: + fAllowed = (bool) ((eCSR_DOT11_MODE_11b != phyMode) + && (eCSR_DOT11_MODE_11g != phyMode)); + break; + case eCSR_DOT11_MODE_11n_ONLY: + fAllowed = (bool) ((eCSR_DOT11_MODE_11n == phyMode)); + break; + + case eCSR_DOT11_MODE_11ac_ONLY: + fAllowed = (bool) ((eCSR_DOT11_MODE_11ac == phyMode)); + break; + case eCSR_DOT11_MODE_11b_ONLY: + fAllowed = (bool) (eCSR_DOT11_MODE_11b == phyMode); + break; + case eCSR_DOT11_MODE_11n: + case eCSR_DOT11_MODE_11ac: + default: + fAllowed = true; + break; + } + } + + return fAllowed; +} + +/* Return pIes to caller for future use when returning true. */ +static bool csr_scan_validate_scan_result(tpAniSirGlobal pMac, + uint8_t *pChannels, + uint8_t numChn, + tSirBssDescription *pBssDesc, + tDot11fBeaconIEs **ppIes) +{ + bool valid = false; + tDot11fBeaconIEs *pIes = NULL; + uint8_t index; + QDF_STATUS status; + + for (index = 0; index < numChn; index++) { + /* + * This check relies on the fact that a single BSS description + * is returned in each ScanRsp call, which is the way LIM + * implemented the scan req/rsp funtions. We changed to this + * model when we ran with a large number of APs. If this were to + * change, then this check would have to mess with removing the + * bssDescription from somewhere in an arbitrary index in the + * bssDescription array. + */ + if (pChannels[index] == pBssDesc->channelId) { + valid = true; + break; + } + } + *ppIes = NULL; + if (valid) { + status = csr_get_parsed_bss_description_ies(pMac, pBssDesc, + &pIes); + if (!QDF_IS_STATUS_SUCCESS(status)) + return false; + + valid = csr_scan_is_bss_allowed(pMac, pBssDesc, pIes); + if (valid) + *ppIes = pIes; + else + qdf_mem_free(pIes); + } + return valid; +} + +static void csr_update_scantype(tpAniSirGlobal pMac, tDot11fBeaconIEs *pIes, + uint8_t channelId) +{ + if (eSIR_PASSIVE_SCAN != pMac->scan.curScanType) + return; + + if (csr_is11d_supported(pMac)) { + /* Check whether the BSS is acceptable based on + * 11d info and our config. + */ + if (!csr_match_country_code(pMac, NULL, pIes)) + return; + + /* check if channel is acceptable by config */ + if (csr_is_supported_channel(pMac, channelId)) + pMac->scan.curScanType = eSIR_ACTIVE_SCAN; + + } else + pMac->scan.curScanType = eSIR_ACTIVE_SCAN; + +} + +/* Return whether last scan result is received */ +static bool csr_scan_process_scan_results(tpAniSirGlobal pMac, tSmeCmd *pCommand, + tSirSmeScanRsp *pScanRsp, + bool *pfRemoveCommand) +{ + bool fRet = false, fRemoveCommand = false; + QDF_STATUS status; + + sms_log(pMac, LOG1, FL("scan reason = %d, response status code = %d"), + pCommand->u.scanCmd.reason, pScanRsp->statusCode); + fRemoveCommand = csr_scan_complete(pMac, pScanRsp); + fRet = true; + if (pfRemoveCommand) { + *pfRemoveCommand = fRemoveCommand; + } + + /* + * Currently SET_FCC_CHANNEL issues updated channel list to fw. + * At the time of driver load, if scan is issued followed with + * SET_FCC_CHANNEL, driver will send update channel list to fw. + * Fw will stop ongoing scan because of that GUI will have very less + * scan list. + * Update channel list should be sent to fw once scan is done + */ + if (pMac->scan.defer_update_channel_list) { + status = csr_update_channel_list(pMac); + if (!QDF_IS_STATUS_SUCCESS(status)) + sms_log(pMac, LOGE, + FL("failed to update the supported channel list")); + pMac->scan.defer_update_channel_list = false; + } + + return fRet; +} + +/** + * csr_scan_get_session_id() - Get session id + * @mac_ctx: Pointer to global mac + * + * This function returns a valid session id + * + * Return: session id + */ +static uint8_t csr_scan_get_session_id(tpAniSirGlobal mac_ctx) +{ + uint8_t i; + + for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) + if (CSR_IS_SESSION_VALID(mac_ctx, i)) + return i; + + return CSR_SESSION_ID_INVALID; +} + +/* csr_scan_process_single_bssdescr() - Add a bssdescriptor to scan table + * + * @mac_ctx - MAC context + * @bssdescr - Pointer to BSS description structure that contains + * everything from beacon/probe response frame and additional + * information. + * @scan_id - Scan identifier of the scan request that was running + * when this beacon was received. Reserved for future when + * firmware provides that information. + * @flags - Reserved for future use. + * + * Callback routine called by LIM when it receives a beacon or probe response + * from the device. 802.11 frame is already converted to internal + * tSirBssDescription data structure. + * + * Return: 0 or other error codes. + */ + +QDF_STATUS csr_scan_process_single_bssdescr(tpAniSirGlobal mac_ctx, + tSirBssDescription *bssdescr, + uint32_t scan_id, uint32_t flags) +{ + tDot11fBeaconIEs *ies = NULL; + uint8_t *chanlist = NULL; + uint8_t cnt_channels = 0; + uint32_t len = sizeof(mac_ctx->roam.validChannelList); + tCsrRoamInfo *roam_info; + uint8_t session_id; + + session_id = csr_scan_get_session_id(mac_ctx); + sms_log(mac_ctx, LOG4, "CSR: Processing single bssdescr"); + if (QDF_IS_STATUS_SUCCESS( + csr_get_cfg_valid_channels(mac_ctx, + (uint8_t *) mac_ctx->roam.validChannelList, + &len))) { + chanlist = mac_ctx->roam.validChannelList; + cnt_channels = (uint8_t) len; + } else { + /* Cannot continue */ + sms_log(mac_ctx, LOGW, + FL("Received results on invalid channel")); + return QDF_STATUS_E_INVAL; + } + + if (csr_scan_validate_scan_result(mac_ctx, chanlist, + cnt_channels, bssdescr, &ies)) { + + csr_scan_remove_dup_bss_description_from_interim_list + (mac_ctx, bssdescr, ies, flags); + csr_scan_save_bss_description_to_interim_list + (mac_ctx, bssdescr, ies); + roam_info = qdf_mem_malloc(sizeof(*roam_info)); + if (roam_info) { + qdf_mem_zero(roam_info, sizeof(*roam_info)); + roam_info->pBssDesc = bssdescr; + + if (session_id == CSR_SESSION_ID_INVALID) { + if (ies != NULL) + qdf_mem_free(ies); + qdf_mem_free(roam_info); + return QDF_STATUS_E_INVAL; + + } + csr_roam_call_callback(mac_ctx, session_id, roam_info, + 0, eCSR_ROAM_UPDATE_SCAN_RESULT, + eCSR_ROAM_RESULT_NONE); + qdf_mem_free(roam_info); + } else { + sms_log(mac_ctx, LOG1, "qdf_mem_malloc failed"); + } + /* + * If scan is not in progress and interim list + * reach threashold, move scan results from temp + * to main list and age out old results. + */ + if (csr_ll_is_list_empty(&mac_ctx->sme.smeScanCmdActiveList, + LL_ACCESS_LOCK) && + csr_ll_count(&mac_ctx->scan.tempScanResults) >= + CSR_MAX_BSS_SUPPORT/10) { + csr_remove_from_tmp_list(mac_ctx, eCsrScanOther, + session_id); + /* Purge the scan results based on Aging */ + if (mac_ctx->scan.scanResultCfgAgingTime) + csr_purge_scan_result_by_age(mac_ctx); + } + csr_update_scantype(mac_ctx, ies, bssdescr->channelId); + /* Free the resource */ + if (ies != NULL) + qdf_mem_free(ies); + } + return QDF_STATUS_SUCCESS; +} + + +static bool csr_scan_is_wild_card_scan(tpAniSirGlobal pMac, tSmeCmd *pCommand) +{ + uint8_t bssid[QDF_MAC_ADDR_SIZE] = {0}; + /* + * It is not a wild card scan if the bssid is not broadcast and + * the number of SSID is 1. + */ + return ((!qdf_mem_cmp(pCommand->u.scanCmd.u.scanRequest.bssid.bytes, + bssid, sizeof(struct qdf_mac_addr))) + || (0xff == pCommand->u.scanCmd.u.scanRequest.bssid.bytes[0])) + && (pCommand->u.scanCmd.u.scanRequest.SSIDs.numOfSSIDs != 1); +} + +QDF_STATUS csr_scan_sme_scan_response(tpAniSirGlobal pMac, + void *pMsgBuf) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tListElem *pEntry = NULL; + tSmeCmd *pCommand; + eCsrScanStatus scanStatus; + tSirSmeScanRsp *pScanRsp = (tSirSmeScanRsp *)pMsgBuf; + bool fRemoveCommand = true; + eCsrScanReason reason = eCsrScanOther; + + csr_get_active_scan_entry(pMac, pScanRsp->scan_id, &pEntry); + if (!pEntry) + goto error_handling; + + sms_log(pMac, LOG1, FL("Scan completion called:scan_id %d, entry = %p"), + pScanRsp->scan_id, pEntry); + + pCommand = GET_BASE_ADDR(pEntry, tSmeCmd, Link); + if (eSmeCommandScan != pCommand->command) + goto error_handling; + + /* Purge the scan results based on Aging */ + if (pEntry && pMac->scan.scanResultCfgAgingTime) + csr_purge_scan_result_by_age(pMac); + scanStatus = (eSIR_SME_SUCCESS == pScanRsp->statusCode) ? + eCSR_SCAN_SUCCESS : eCSR_SCAN_FAILURE; + reason = pCommand->u.scanCmd.reason; + switch (pCommand->u.scanCmd.reason) { + case eCsrScanAbortNormalScan: + break; + case eCsrScanP2PFindPeer: + scanStatus = (eSIR_SME_SUCCESS == pScanRsp->statusCode) ? + eCSR_SCAN_FOUND_PEER : eCSR_SCAN_FAILURE; + csr_scan_process_scan_results(pMac, pCommand, pScanRsp, NULL); + break; + default: + if (csr_scan_process_scan_results(pMac, pCommand, pScanRsp, + &fRemoveCommand) + && csr_scan_is_wild_card_scan(pMac, pCommand) + && !pCommand->u.scanCmd.u.scanRequest.p2pSearch) { + + /* Age out logic will be taken care by the age out timer */ + } + break; + } + if (fRemoveCommand) + csr_release_scan_command(pMac, pCommand, scanStatus); + sme_process_pending_queue(pMac); + return status; + +error_handling: +#ifdef FEATURE_WLAN_SCAN_PNO + if (pMac->pnoOffload && pScanRsp->statusCode == eSIR_PNO_SCAN_SUCCESS) { + sms_log(pMac, LOG1, FL("PNO Scan completion called")); + csr_save_scan_results(pMac, eCsrScanCandidateFound, + pScanRsp->sessionId); + return QDF_STATUS_SUCCESS; + } else { + /* + * Scan completion was called, PNO is active, but scan + * response was not PNO + */ + sms_log(pMac, LOGE, + FL("Scan completion called, scan rsp was not PNO.")); + return QDF_STATUS_E_FAILURE; + } +#endif + sms_log(pMac, LOGE, FL("Scan completion called, but no active SCAN command.")); + return QDF_STATUS_E_FAILURE; +} + +tCsrScanResultInfo *csr_scan_result_get_first(tpAniSirGlobal pMac, + tScanResultHandle hScanResult) +{ + tListElem *pEntry; + tCsrScanResult *pResult; + tCsrScanResultInfo *pRet = NULL; + tScanResultList *pResultList = (tScanResultList *) hScanResult; + + if (pResultList) { + csr_ll_lock(&pResultList->List); + pEntry = csr_ll_peek_head(&pResultList->List, LL_ACCESS_NOLOCK); + if (pEntry) { + pResult = GET_BASE_ADDR(pEntry, tCsrScanResult, Link); + pRet = &pResult->Result; + } + pResultList->pCurEntry = pEntry; + csr_ll_unlock(&pResultList->List); + } + + return pRet; +} + +tCsrScanResultInfo *csr_scan_result_get_next(tpAniSirGlobal pMac, + tScanResultHandle hScanResult) +{ + tListElem *pEntry = NULL; + tCsrScanResult *pResult = NULL; + tCsrScanResultInfo *pRet = NULL; + tScanResultList *pResultList = (tScanResultList *) hScanResult; + + if (!pResultList) + return NULL; + + csr_ll_lock(&pResultList->List); + if (NULL == pResultList->pCurEntry) { + pEntry = csr_ll_peek_head(&pResultList->List, LL_ACCESS_NOLOCK); + } else { + pEntry = csr_ll_next(&pResultList->List, pResultList->pCurEntry, + LL_ACCESS_NOLOCK); + } + if (pEntry) { + pResult = GET_BASE_ADDR(pEntry, tCsrScanResult, Link); + pRet = &pResult->Result; + } + pResultList->pCurEntry = pEntry; + csr_ll_unlock(&pResultList->List); + return pRet; +} + +/* + * This function moves the first BSS that matches the bssid to the + * head of the result + */ +QDF_STATUS csr_move_bss_to_head_from_bssid(tpAniSirGlobal pMac, + struct qdf_mac_addr *bssid, + tScanResultHandle hScanResult) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tScanResultList *pResultList = (tScanResultList *) hScanResult; + tCsrScanResult *pResult = NULL; + tListElem *pEntry = NULL; + + if (!(pResultList && bssid)) + return status; + + csr_ll_lock(&pResultList->List); + pEntry = csr_ll_peek_head(&pResultList->List, LL_ACCESS_NOLOCK); + while (pEntry) { + pResult = GET_BASE_ADDR(pEntry, tCsrScanResult, Link); + if (!qdf_mem_cmp(bssid, pResult->Result.BssDescriptor.bssId, + sizeof(struct qdf_mac_addr))) { + status = QDF_STATUS_SUCCESS; + csr_ll_remove_entry(&pResultList->List, pEntry, + LL_ACCESS_NOLOCK); + csr_ll_insert_head(&pResultList->List, pEntry, + LL_ACCESS_NOLOCK); + break; + } + pEntry = csr_ll_next(&pResultList->List, pResultList->pCurEntry, + LL_ACCESS_NOLOCK); + } + csr_ll_unlock(&pResultList->List); + return status; +} + +/* Remove the BSS if possible. */ +/* Return -- true == the BSS is remove. False == Fail to remove it */ +/* This function is called when list lock is held. Be caution what functions it can call. */ +static bool csr_scan_age_out_bss(tpAniSirGlobal pMac, tCsrScanResult *pResult) +{ + bool fRet = false; + uint32_t i; + tCsrRoamSession *pSession; + bool isConnBssfound = false; + + for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) { + if (!CSR_IS_SESSION_VALID(pMac, i)) + continue; + pSession = CSR_GET_SESSION(pMac, i); + /* Not to remove the BSS we are connected to. */ + if (csr_is_conn_state_connected_infra(pMac, i) + && (NULL != pSession->pConnectBssDesc) + && (csr_is_duplicate_bss_description(pMac, + &pResult->Result.BssDescriptor, + pSession->pConnectBssDesc, NULL))) { + isConnBssfound = true; + break; + } + } + if (isConnBssfound) { + /* + * Reset the counter so that aging out of connected BSS won't + * hapeen too soon + */ + pResult->AgingCount = + (int32_t) pMac->roam.configParam.agingCount; + sms_log(pMac, LOGW, + FL("Connected BSS, Set Aging Count=%d for BSS " + MAC_ADDRESS_STR), pResult->AgingCount, + MAC_ADDR_ARRAY(pResult->Result.BssDescriptor.bssId)); + pResult->Result.BssDescriptor.received_time = + (uint64_t)qdf_mc_timer_get_system_time(); + return fRet; + } + /* + * No need to hold the spin lock because caller should hold the lock for + * pMac->scan.scanResultList + */ + if (csr_ll_remove_entry(&pMac->scan.scanResultList, &pResult->Link, + LL_ACCESS_NOLOCK)) { + if (qdf_is_macaddr_equal( + (struct qdf_mac_addr *) &pResult->Result.BssDescriptor.bssId, + (struct qdf_mac_addr *) &pMac->scan.currentCountryBssid)) { + sms_log(pMac, LOGW, + FL("Aging out 11d BSS " MAC_ADDRESS_STR), + MAC_ADDR_ARRAY( + pResult->Result.BssDescriptor.bssId)); + pMac->scan.currentCountryRSSI = -128; + } + csr_free_scan_result_entry(pMac, pResult); + fRet = true; + } + return fRet; +} + +QDF_STATUS csr_scan_age_results(tpAniSirGlobal pMac, + tSmeGetScanChnRsp *pScanChnInfo) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tListElem *pEntry, *tmpEntry; + tCsrScanResult *pResult; + tLimScanChn *pChnInfo; + uint8_t i; + + csr_ll_lock(&pMac->scan.scanResultList); + for (i = 0; i < pScanChnInfo->numChn; i++) { + pChnInfo = &pScanChnInfo->scanChn[i]; + pEntry = + csr_ll_peek_head(&pMac->scan.scanResultList, LL_ACCESS_NOLOCK); + while (pEntry) { + tmpEntry = + csr_ll_next(&pMac->scan.scanResultList, pEntry, + LL_ACCESS_NOLOCK); + pResult = GET_BASE_ADDR(pEntry, tCsrScanResult, Link); + if (pResult->Result.BssDescriptor.channelId == + pChnInfo->channelId) { + if (pResult->AgingCount <= 0) { + sms_log(pMac, LOGW, + " age out due to ref count"); + csr_scan_age_out_bss(pMac, pResult); + } else { + pResult->AgingCount--; + sms_log(pMac, LOGW, + FL + ("Decremented AgingCount=%d for BSS " + MAC_ADDRESS_STR ""), + pResult->AgingCount, + MAC_ADDR_ARRAY(pResult->Result. + BssDescriptor. + bssId)); + } + } + pEntry = tmpEntry; + } + } + csr_ll_unlock(&pMac->scan.scanResultList); + + return status; +} + +static QDF_STATUS csr_send_mb_scan_req(tpAniSirGlobal pMac, uint16_t sessionId, + tCsrScanRequest *pScanReq, + tScanReqParam *pScanReqParam) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tSirSmeScanReq *pMsg; + uint16_t msgLen; + tSirScanType scanType = pScanReq->scanType; + uint32_t minChnTime; /* in units of milliseconds */ + uint32_t maxChnTime; /* in units of milliseconds */ + uint32_t i; + struct qdf_mac_addr selfmac; + + msgLen = (uint16_t) (sizeof(tSirSmeScanReq) - + sizeof(pMsg->channelList.channelNumber) + + (sizeof(pMsg->channelList.channelNumber) * + pScanReq->ChannelInfo.numOfChannels)) + + (pScanReq->uIEFieldLen); + + pMsg = qdf_mem_malloc(msgLen); + if (NULL == pMsg) { + sms_log(pMac, LOGE, FL("memory allocation failed")); + sms_log(pMac, LOG1, FL("Failed: SId: %d FirstMatch = %d" + " UniqueResult = %d freshScan = %d hiddenSsid = %d"), + sessionId, pScanReqParam->bReturnAfter1stMatch, + pScanReqParam->fUniqueResult, pScanReqParam->freshScan, + pScanReqParam->hiddenSsid); + sms_log(pMac, LOG1, + FL("scanType = %s (%u) BSSType = %s (%u) numOfSSIDs = %d" + " numOfChannels = %d requestType = %s (%d) p2pSearch = %d\n"), + sme_scan_type_to_string(pScanReq->scanType), + pScanReq->scanType, + sme_bss_type_to_string(pScanReq->BSSType), + pScanReq->BSSType, + pScanReq->SSIDs.numOfSSIDs, + pScanReq->ChannelInfo.numOfChannels, + sme_request_type_to_string(pScanReq->requestType), + pScanReq->requestType, pScanReq->p2pSearch); + return QDF_STATUS_E_NOMEM; + } + + pMsg->messageType = eWNI_SME_SCAN_REQ; + pMsg->length = msgLen; + /* ToDO: Fill in session info when we need to do scan base on session */ + if ((sessionId != CSR_SESSION_ID_INVALID)) { + pMsg->sessionId = sessionId; + } else { + /* if sessionId == CSR_SESSION_ID_INVALID, then send the scan + request on first available session */ + pMsg->sessionId = 0; + } + if (pMsg->sessionId >= CSR_ROAM_SESSION_MAX) + sms_log(pMac, LOGE, FL(" Invalid Sme Session ID = %d"), + pMsg->sessionId); + pMsg->transactionId = 0; + pMsg->dot11mode = (uint8_t) csr_translate_to_wni_cfg_dot11_mode(pMac, + csr_find_best_phy_mode(pMac, + pMac->roam.configParam.phyMode)); + pMsg->bssType = csr_translate_bsstype_to_mac_type(pScanReq->BSSType); + + if (CSR_IS_SESSION_VALID(pMac, sessionId)) { + qdf_copy_macaddr(&selfmac, + &pMac->roam.roamSession[sessionId].selfMacAddr); + } else { + /* + * Since we don't have session for the scanning, we find a valid + * session. In case we fail to do so, get the WNI_CFG_STA_ID + */ + for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) { + if (CSR_IS_SESSION_VALID(pMac, i)) { + qdf_copy_macaddr(&selfmac, + &pMac->roam.roamSession[i].selfMacAddr); + break; + } + } + if (CSR_ROAM_SESSION_MAX == i) { + uint32_t len = QDF_MAC_ADDR_SIZE; + status = wlan_cfg_get_str(pMac, WNI_CFG_STA_ID, + selfmac.bytes, &len); + if (!QDF_IS_STATUS_SUCCESS(status) + || (len < QDF_MAC_ADDR_SIZE)) { + sms_log(pMac, LOGE, + FL("Can't get self MAC address = %d"), + status); + /* Force failed status */ + status = QDF_STATUS_E_FAILURE; + goto send_scan_req; + } + } + } + qdf_copy_macaddr(&pMsg->selfMacAddr, &selfmac); + + qdf_copy_macaddr(&pMsg->bssId, &pScanReq->bssid); + if (qdf_is_macaddr_zero(&pScanReq->bssid)) + qdf_set_macaddr_broadcast(&pMsg->bssId); + else + qdf_copy_macaddr(&pMsg->bssId, &pScanReq->bssid); + minChnTime = pScanReq->minChnTime; + maxChnTime = pScanReq->maxChnTime; + + /* + * Verify the scan type first, if the scan is active scan, we need to + * make sure we are allowed to do so. if 11d is enabled & we don't see + * any beacon around, scan type falls back to passive. But in BT AMP STA + * mode we need to send out a directed probe + */ + if ((eSIR_PASSIVE_SCAN != scanType) + && (eCSR_SCAN_P2P_DISCOVERY != pScanReq->requestType) + && (false == pMac->scan.fEnableBypass11d)) { + scanType = pMac->scan.curScanType; + if (eSIR_PASSIVE_SCAN == pMac->scan.curScanType) { + if (minChnTime < + pMac->roam.configParam.nPassiveMinChnTime) { + minChnTime = + pMac->roam.configParam.nPassiveMinChnTime; + } + if (maxChnTime < + pMac->roam.configParam.nPassiveMaxChnTime) { + maxChnTime = + pMac->roam.configParam.nPassiveMaxChnTime; + } + } + } + pMsg->scanType = scanType; + pMsg->scan_adaptive_dwell_mode = pScanReq->scan_adaptive_dwell_mode; + + pMsg->numSsid = (pScanReq->SSIDs.numOfSSIDs < SIR_SCAN_MAX_NUM_SSID) ? + pScanReq->SSIDs.numOfSSIDs : SIR_SCAN_MAX_NUM_SSID; + if ((pScanReq->SSIDs.numOfSSIDs != 0) + && (eSIR_PASSIVE_SCAN != scanType)) { + for (i = 0; i < pMsg->numSsid; i++) { + qdf_mem_copy(&pMsg->ssId[i], + &pScanReq->SSIDs.SSIDList[i].SSID, + sizeof(tSirMacSSid)); + } + } else { + /* Otherwise we scan all SSID and let the result filter later */ + for (i = 0; i < SIR_SCAN_MAX_NUM_SSID; i++) + pMsg->ssId[i].length = 0; + } + + pMsg->minChannelTime = minChnTime; + pMsg->maxChannelTime = maxChnTime; + pMsg->scan_probe_repeat_time = + pMac->roam.configParam.scan_probe_repeat_time; + pMsg->scan_num_probes = pMac->roam.configParam.scan_num_probes; + /* hidden SSID option */ + pMsg->hiddenSsid = pScanReqParam->hiddenSsid; + /* maximum rest time */ + pMsg->restTime = pScanReq->restTime; + /* Minimum rest time */ + pMsg->min_rest_time = pScanReq->min_rest_time; + /* Idle time */ + pMsg->idle_time = pScanReq->idle_time; + pMsg->returnAfterFirstMatch = pScanReqParam->bReturnAfter1stMatch; + /* All the scan results caching will be done by Roaming */ + /* We do not want LIM to do any caching of scan results, */ + /* so delete the LIM cache on all scan requests */ + pMsg->returnFreshResults = pScanReqParam->freshScan; + /* Always ask for unique result */ + pMsg->returnUniqueResults = pScanReqParam->fUniqueResult; + pMsg->channelList.numChannels = + (uint8_t) pScanReq->ChannelInfo.numOfChannels; + if (pScanReq->ChannelInfo.numOfChannels) { + /* Assuming the channelNumber is uint8_t (1 byte) */ + qdf_mem_copy(pMsg->channelList.channelNumber, + pScanReq->ChannelInfo.ChannelList, + pScanReq->ChannelInfo.numOfChannels); + } + + pMsg->uIEFieldLen = (uint16_t) pScanReq->uIEFieldLen; + pMsg->uIEFieldOffset = (uint16_t) (sizeof(tSirSmeScanReq) - + sizeof(pMsg->channelList.channelNumber) + + (sizeof(pMsg->channelList.channelNumber) * + pScanReq->ChannelInfo.numOfChannels)); + if (pScanReq->uIEFieldLen != 0) { + qdf_mem_copy((uint8_t *) pMsg + pMsg->uIEFieldOffset, + pScanReq->pIEField, pScanReq->uIEFieldLen); + } + pMsg->p2pSearch = pScanReq->p2pSearch; + pMsg->scan_id = pScanReq->scan_id; + + pMsg->enable_scan_randomization = + pScanReq->enable_scan_randomization; + if (pMsg->enable_scan_randomization) { + qdf_mem_copy(pMsg->mac_addr, pScanReq->mac_addr, + QDF_MAC_ADDR_SIZE); + qdf_mem_copy(pMsg->mac_addr_mask, pScanReq->mac_addr_mask, + QDF_MAC_ADDR_SIZE); + } + +send_scan_req: + sms_log(pMac, LOG1, + FL("scanId %d domainIdCurrent %d scanType %s (%d) bssType %s (%d) requestType %s (%d) numChannels %d"), + pMsg->scan_id, pMac->scan.domainIdCurrent, + sme_scan_type_to_string(pMsg->scanType), pMsg->scanType, + sme_bss_type_to_string(pMsg->bssType), pMsg->bssType, + sme_request_type_to_string(pScanReq->requestType), + pScanReq->requestType, pMsg->channelList.numChannels); + + for (i = 0; i < pMsg->channelList.numChannels; i++) { + sms_log(pMac, LOG2, FL("channelNumber[%d]= %d"), i, + pMsg->channelList.channelNumber[i]); + } + + if (QDF_IS_STATUS_SUCCESS(status)) { + status = cds_send_mb_message_to_mac(pMsg); + } else { + sms_log(pMac, LOGE, + FL("failed to send down scan req with status = %d"), + status); + qdf_mem_free(pMsg); + } + return status; +} + +#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR +static void csr_diag_scan_channels(tpAniSirGlobal pMac, tSmeCmd *pCommand) +{ + host_log_scan_pkt_type *pScanLog = NULL; + + WLAN_HOST_DIAG_LOG_ALLOC(pScanLog, + host_log_scan_pkt_type, + LOG_WLAN_SCAN_C); + if (!pScanLog) + return; + + if (eCsrScanProbeBss == pCommand->u.scanCmd.reason) { + pScanLog->eventId = WLAN_SCAN_EVENT_HO_SCAN_REQ; + } else { + if ((eSIR_PASSIVE_SCAN != + pCommand->u.scanCmd.u.scanRequest.scanType) + && (eSIR_PASSIVE_SCAN != pMac->scan.curScanType)) { + pScanLog->eventId = WLAN_SCAN_EVENT_ACTIVE_SCAN_REQ; + } else { + pScanLog->eventId = WLAN_SCAN_EVENT_PASSIVE_SCAN_REQ; + } + } + pScanLog->minChnTime = + (uint8_t) pCommand->u.scanCmd.u.scanRequest.minChnTime; + pScanLog->maxChnTime = + (uint8_t) pCommand->u.scanCmd.u.scanRequest.maxChnTime; + pScanLog->numChannel = + (uint8_t) pCommand->u.scanCmd.u.scanRequest.ChannelInfo.numOfChannels; + if (pScanLog->numChannel && + (pScanLog->numChannel < HOST_LOG_MAX_NUM_CHANNEL)) { + qdf_mem_copy(pScanLog->channels, + pCommand->u.scanCmd.u.scanRequest.ChannelInfo.ChannelList, + pScanLog->numChannel); + } + WLAN_HOST_DIAG_LOG_REPORT(pScanLog); +} +#else +#define csr_diag_scan_channels(tpAniSirGlobal pMac, tSmeCmd *pCommand) (void)0; +#endif /* #ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR */ + +QDF_STATUS csr_scan_channels(tpAniSirGlobal pMac, tSmeCmd *pCommand) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tScanReqParam scanReq; + + /* + * Don't delete cached results. Rome rssi based scan candidates may land + * up in scan cache instead of LFR cache. They will be deleted upon + * query + */ + scanReq.freshScan = SIR_BG_SCAN_RETURN_FRESH_RESULTS; + scanReq.fUniqueResult = true; + scanReq.hiddenSsid = SIR_SCAN_NO_HIDDEN_SSID; + if (eCsrScanForSsid == pCommand->u.scanCmd.reason) { + scanReq.bReturnAfter1stMatch = + CSR_SCAN_RETURN_AFTER_FIRST_MATCH; + } else { + /* + * Basically do scan on all channels even for 11D 1st scan case + */ + scanReq.bReturnAfter1stMatch = + CSR_SCAN_RETURN_AFTER_ALL_CHANNELS; + } + if (eCsrScanProbeBss == pCommand->u.scanCmd.reason) + scanReq.hiddenSsid = SIR_SCAN_HIDDEN_SSID_PE_DECISION; + csr_diag_scan_channels(pMac, pCommand); + csr_clear_votes_for_country_info(pMac); + status = csr_send_mb_scan_req(pMac, pCommand->sessionId, + &pCommand->u.scanCmd.u.scanRequest, + &scanReq); + return status; +} + +static QDF_STATUS +csr_issue_user_scan(tpAniSirGlobal mac_ctx, tSmeCmd *cmd) +{ + int i, j; + QDF_STATUS status; + uint32_t len = 0; + uint8_t *ch_lst = NULL; + tCsrChannelInfo new_ch_info = { 0, NULL }; + + if (!mac_ctx->roam.configParam.fScanTwice) + return csr_scan_channels(mac_ctx, cmd); + + /* We scan 2.4 channel twice */ + if (cmd->u.scanCmd.u.scanRequest.ChannelInfo.numOfChannels + && (NULL != cmd->u.scanCmd.u.scanRequest.ChannelInfo.ChannelList)) { + len = cmd->u.scanCmd.u.scanRequest.ChannelInfo.numOfChannels; + /* allocate twice the channel */ + new_ch_info.ChannelList = (uint8_t *) qdf_mem_malloc(len * 2); + ch_lst = cmd->u.scanCmd.u.scanRequest.ChannelInfo.ChannelList; + } else { + /* get the valid channel list to scan all. */ + len = sizeof(mac_ctx->roam.validChannelList); + status = csr_get_cfg_valid_channels(mac_ctx, + (uint8_t *) mac_ctx->roam.validChannelList, &len); + if (QDF_IS_STATUS_SUCCESS(status)) { + /* allocate twice the channel */ + new_ch_info.ChannelList = + (uint8_t *) qdf_mem_malloc(len * 2); + ch_lst = mac_ctx->roam.validChannelList; + } + } + if (NULL == new_ch_info.ChannelList) { + new_ch_info.numOfChannels = 0; + } else { + j = 0; + for (i = 0; i < len; i++) { + new_ch_info.ChannelList[j++] = ch_lst[i]; + if (CDS_MAX_24GHZ_CHANNEL_NUMBER >= ch_lst[i]) + new_ch_info.ChannelList[j++] = ch_lst[i]; + } + if (NULL != + cmd->u.scanCmd.u.scanRequest.ChannelInfo.ChannelList) { + /* + * ch_lst points to the channellist from the command, + * free it. + */ + qdf_mem_free( + cmd->u.scanCmd.u.scanRequest.ChannelInfo.ChannelList); + cmd->u.scanCmd.u.scanRequest.ChannelInfo.ChannelList = + NULL; + } + cmd->u.scanCmd.u.scanRequest.ChannelInfo.numOfChannels = j; + cmd->u.scanCmd.u.scanRequest.ChannelInfo.ChannelList = + new_ch_info.ChannelList; + } + + return csr_scan_channels(mac_ctx, cmd); +} + +QDF_STATUS csr_process_scan_command(tpAniSirGlobal pMac, tSmeCmd *pCommand) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + + sms_log(pMac, LOG3, + FL("starting SCAN cmd in %d state. reason %d"), + pCommand->u.scanCmd.lastRoamState[pCommand->sessionId], + pCommand->u.scanCmd.reason); + + switch (pCommand->u.scanCmd.reason) { + case eCsrScanUserRequest: + status = csr_issue_user_scan(pMac, pCommand); + break; + default: + status = csr_scan_channels(pMac, pCommand); + break; + } + + if (!QDF_IS_STATUS_SUCCESS(status)) { + csr_release_scan_command(pMac, pCommand, eCSR_SCAN_FAILURE); + } + + return status; +} + +/** + * csr_scan_copy_request_valid_channels_only() - scan request of valid channels + * @mac_ctx : pointer to Global Mac Structure + * @dst_req: pointer to tCsrScanRequest + * @skip_dfs_chnl: 1 - skip dfs channel, 0 - don't skip dfs channel + * @src_req: pointer to tCsrScanRequest + * + * This function makes a copy of scan request with valid channels + * + * Return: none + */ +static void csr_scan_copy_request_valid_channels_only(tpAniSirGlobal mac_ctx, + tCsrScanRequest *dst_req, uint8_t skip_dfs_chnl, + tCsrScanRequest *src_req) +{ + uint32_t index = 0; + uint32_t new_index = 0; + uint16_t unsafe_chan[NUM_CHANNELS]; + uint16_t unsafe_chan_cnt = 0; + uint16_t cnt = 0; + bool is_unsafe_chan; + qdf_device_t qdf_ctx = cds_get_context(QDF_MODULE_ID_QDF_DEVICE); + + if (!qdf_ctx) { + cds_err("qdf_ctx is NULL"); + return; + } + pld_get_wlan_unsafe_channel(qdf_ctx->dev, unsafe_chan, + &unsafe_chan_cnt, + sizeof(unsafe_chan)); + + if (mac_ctx->roam.configParam.sta_roam_policy.dfs_mode == + CSR_STA_ROAM_POLICY_DFS_DISABLED) + skip_dfs_chnl = true; + + for (index = 0; index < src_req->ChannelInfo.numOfChannels; index++) { + /* Allow scan on valid channels only. + * If it is p2p scan and valid channel list doesnt contain + * social channels, enforce scan on social channels because + * that is the only way to find p2p peers. + * This can happen only if band is set to 5Ghz mode. + */ + if (src_req->ChannelInfo.ChannelList[index] < + CDS_MIN_11P_CHANNEL && + ((csr_roam_is_valid_channel(mac_ctx, + src_req->ChannelInfo.ChannelList[index])) || + ((eCSR_SCAN_P2P_DISCOVERY == src_req->requestType) && + CSR_IS_SOCIAL_CHANNEL( + src_req->ChannelInfo.ChannelList[index])))) { + if (((src_req->skipDfsChnlInP2pSearch || skip_dfs_chnl) + && (CHANNEL_STATE_DFS == + cds_get_channel_state(src_req-> + ChannelInfo. + ChannelList + [index]))) + ) { + sms_log(mac_ctx, LOG2, + FL(" reqType= %s (%d), numOfChannels=%d, ignoring DFS channel %d"), + sme_request_type_to_string( + src_req->requestType), + src_req->requestType, + src_req->ChannelInfo.numOfChannels, + src_req->ChannelInfo.ChannelList + [index]); + continue; + } + if (mac_ctx->roam.configParam. + sta_roam_policy.skip_unsafe_channels && + unsafe_chan_cnt) { + is_unsafe_chan = false; + for (cnt = 0; cnt < unsafe_chan_cnt; cnt++) { + if (unsafe_chan[cnt] == + src_req->ChannelInfo. + ChannelList[index]) { + is_unsafe_chan = true; + break; + } + } + if (is_unsafe_chan && + ((CSR_IS_CHANNEL_24GHZ( + src_req->ChannelInfo. + ChannelList[index]) && + mac_ctx->roam.configParam. + sta_roam_policy.sap_operating_band == + eCSR_BAND_24) || + (CDS_IS_CHANNEL_5GHZ( + src_req->ChannelInfo. + ChannelList[index]) && + mac_ctx->roam.configParam. + sta_roam_policy.sap_operating_band == + eCSR_BAND_5G))) { + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_INFO, + FL("ignoring unsafe channel %d"), + src_req->ChannelInfo. + ChannelList[index]); + continue; + } + } + + dst_req->ChannelInfo.ChannelList[new_index] = + src_req->ChannelInfo.ChannelList[index]; + new_index++; + } + } + dst_req->ChannelInfo.numOfChannels = new_index; +} + +/** + * csr_scan_filter_given_chnl_band() - filter all channels which matches given + * channel's band + * @mac_ctx: pointer to mac context + * @channel: Given channel + * @dst_req: destination scan request + * + * when ever particular connection already exist, STA should not scan the + * channels which fall under same band as given channel's band. + * this routine will filter out those channels + * + * Return: true if success otherwise false for any failure + */ +static bool csr_scan_filter_given_chnl_band(tpAniSirGlobal mac_ctx, + uint8_t channel, tCsrScanRequest *dst_req) { + uint8_t valid_chnl_list[WNI_CFG_VALID_CHANNEL_LIST_LEN] = {0}; + uint32_t filter_chnl_len = 0, i = 0; + uint32_t valid_chnl_len = WNI_CFG_VALID_CHANNEL_LIST_LEN; + + if (!channel) { + sms_log(mac_ctx, LOG1, + FL("Nothing to filter as no IBSS session")); + return true; + } + + if (!dst_req) { + sms_log(mac_ctx, LOGE, + FL("No valid scan requests")); + return false; + } + /* + * In case of concurrent IBSS session exist, scan only + * those channels which are not in IBSS channel's band. + * In case if no-concurrent IBSS session exist then scan + * full band + */ + if ((dst_req->ChannelInfo.numOfChannels == 0)) { + csr_get_cfg_valid_channels(mac_ctx, valid_chnl_list, + &valid_chnl_len); + } else { + valid_chnl_len = (WNI_CFG_VALID_CHANNEL_LIST_LEN > + dst_req->ChannelInfo.numOfChannels) ? + dst_req->ChannelInfo.numOfChannels : + WNI_CFG_VALID_CHANNEL_LIST_LEN; + qdf_mem_copy(valid_chnl_list, dst_req->ChannelInfo.ChannelList, + valid_chnl_len); + } + for (i = 0; i < valid_chnl_len; i++) { + /* + * Don't allow DSRC channel when IBSS or SAP DFS concurrent + * connection is up + */ + if (valid_chnl_list[i] >= CDS_MIN_11P_CHANNEL) + continue; + if (CDS_IS_CHANNEL_5GHZ(channel) && + CDS_IS_CHANNEL_24GHZ(valid_chnl_list[i])) { + valid_chnl_list[filter_chnl_len] = + valid_chnl_list[i]; + filter_chnl_len++; + } else if (CDS_IS_CHANNEL_24GHZ(channel) && + CDS_IS_CHANNEL_5GHZ(valid_chnl_list[i])) { + valid_chnl_list[filter_chnl_len] = + valid_chnl_list[i]; + filter_chnl_len++; + } + } + if (filter_chnl_len == 0) { + sms_log(mac_ctx, LOGE, + FL("there no channels to scan due to IBSS session")); + return false; + } + + if (dst_req->ChannelInfo.ChannelList) { + qdf_mem_free(dst_req->ChannelInfo.ChannelList); + dst_req->ChannelInfo.ChannelList = NULL; + dst_req->ChannelInfo.numOfChannels = 0; + } + + dst_req->ChannelInfo.ChannelList = + qdf_mem_malloc(filter_chnl_len * + sizeof(*dst_req->ChannelInfo.ChannelList)); + dst_req->ChannelInfo.numOfChannels = filter_chnl_len; + if (NULL == dst_req->ChannelInfo.ChannelList) { + sms_log(mac_ctx, LOGE, + FL("Memory allocation failed")); + return false; + } + qdf_mem_copy(dst_req->ChannelInfo.ChannelList, valid_chnl_list, + filter_chnl_len); + return true; +} + +/** + * csr_scan_copy_request() - Function to copy scan request + * @mac_ctx : pointer to Global Mac Structure + * @dst_req: pointer to tCsrScanRequest + * @src_req: pointer to tCsrScanRequest + * + * This function makes a copy of scan request + * + * Return: 0 - Success, Error number - Failure + */ +QDF_STATUS csr_scan_copy_request(tpAniSirGlobal mac_ctx, + tCsrScanRequest *dst_req, + tCsrScanRequest *src_req) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + uint32_t len = sizeof(mac_ctx->roam.validChannelList); + uint32_t index = 0; + uint32_t new_index = 0; + enum channel_state channel_state; + uint8_t channel = 0; + + bool skip_dfs_chnl = + mac_ctx->roam.configParam.initial_scan_no_dfs_chnl || + !mac_ctx->scan.fEnableDFSChnlScan; + + status = csr_scan_free_request(mac_ctx, dst_req); + if (!QDF_IS_STATUS_SUCCESS(status)) + goto complete; + qdf_mem_copy(dst_req, src_req, sizeof(tCsrScanRequest)); + /* Re-initialize the pointers to NULL since we did a copy */ + dst_req->pIEField = NULL; + dst_req->ChannelInfo.ChannelList = NULL; + dst_req->SSIDs.SSIDList = NULL; + + if (src_req->uIEFieldLen) { + dst_req->pIEField = + qdf_mem_malloc(src_req->uIEFieldLen); + if (NULL == dst_req->pIEField) { + status = QDF_STATUS_E_NOMEM; + sms_log(mac_ctx, LOGE, + FL("No memory for scanning IE fields")); + goto complete; + } else { + status = QDF_STATUS_SUCCESS; + qdf_mem_copy(dst_req->pIEField, src_req->pIEField, + src_req->uIEFieldLen); + dst_req->uIEFieldLen = src_req->uIEFieldLen; + } + } + + /* Allocate memory for IE field */ + if (src_req->ChannelInfo.numOfChannels == 0) { + dst_req->ChannelInfo.ChannelList = NULL; + dst_req->ChannelInfo.numOfChannels = 0; + } else { + dst_req->ChannelInfo.ChannelList = + qdf_mem_malloc(src_req->ChannelInfo.numOfChannels * + sizeof(*dst_req->ChannelInfo.ChannelList)); + if (NULL == dst_req->ChannelInfo.ChannelList) { + status = QDF_STATUS_E_NOMEM; + dst_req->ChannelInfo.numOfChannels = 0; + sms_log(mac_ctx, LOGE, + FL("No memory for scanning Channel List")); + goto complete; + } + + if ((src_req->scanType == eSIR_PASSIVE_SCAN) && + (src_req->requestType == eCSR_SCAN_REQUEST_11D_SCAN)) { + for (index = 0; index < src_req->ChannelInfo. + numOfChannels; index++) { + channel_state = + cds_get_channel_state(src_req-> + ChannelInfo. + ChannelList[index]); + if (src_req->ChannelInfo.ChannelList[index] < + CDS_MIN_11P_CHANNEL && + ((CHANNEL_STATE_ENABLE == + channel_state) || + ((CHANNEL_STATE_DFS == channel_state) && + !skip_dfs_chnl))) { + dst_req->ChannelInfo.ChannelList + [new_index] = + src_req-> + ChannelInfo. + ChannelList + [index]; + new_index++; + } + } + dst_req->ChannelInfo.numOfChannels = new_index; + } else if (QDF_IS_STATUS_SUCCESS( + csr_get_cfg_valid_channels(mac_ctx, + mac_ctx->roam.validChannelList, + &len))) { + new_index = 0; + mac_ctx->roam.numValidChannels = len; + csr_scan_copy_request_valid_channels_only(mac_ctx, + dst_req, skip_dfs_chnl, + src_req); + } else { + sms_log(mac_ctx, LOGE, + FL("Couldn't get the valid Channel List, keeping requester's list")); + new_index = 0; + for (index = 0; index < src_req->ChannelInfo. + numOfChannels; index++) { + if (src_req->ChannelInfo.ChannelList[index] < + CDS_MIN_11P_CHANNEL) { + dst_req->ChannelInfo. + ChannelList[new_index] = + src_req->ChannelInfo. + ChannelList[index]; + new_index++; + } + } + dst_req->ChannelInfo.numOfChannels = + new_index; + } + } /* Allocate memory for Channel List */ + + /* + * If IBSS concurrent connection exist, and if the scan + * request comes from STA adapter then we need to filter + * out IBSS channel's band otherwise it will cause issue + * in IBSS+STA concurrency + * + * If DFS SAP/GO concurrent connection exist, and if the scan + * request comes from STA adapter then we need to filter + * out SAP/GO channel's band otherwise it will cause issue in + * SAP+STA concurrency + */ + if (cds_is_ibss_conn_exist(&channel)) { + sms_log(mac_ctx, LOG1, + FL("Conc IBSS exist, channel list will be modified")); + } else if (cds_is_any_dfs_beaconing_session_present(&channel)) { + /* + * 1) if agile & DFS scans are supported + * 2) if hardware is DBS capable + * 3) if current hw mode is non-dbs + * if all above 3 conditions are true then don't skip any + * channel from scan list + */ + if (true != wma_is_current_hwmode_dbs() && + wma_get_dbs_plus_agile_scan_config() && + wma_get_single_mac_scan_with_dfs_config()) + channel = 0; + else + sms_log(mac_ctx, LOG1, + FL("Conc DFS SAP/GO exist, channel list will be modified")); + } + + if ((channel > 0) && + (!csr_scan_filter_given_chnl_band(mac_ctx, channel, dst_req))) { + sms_log(mac_ctx, LOGE, + FL("Can't filter channels due to IBSS/SAP DFS")); + goto complete; + } + + if (src_req->SSIDs.numOfSSIDs == 0) { + dst_req->SSIDs.numOfSSIDs = 0; + dst_req->SSIDs.SSIDList = NULL; + } else { + dst_req->SSIDs.SSIDList = + qdf_mem_malloc(src_req->SSIDs.numOfSSIDs * + sizeof(*dst_req->SSIDs.SSIDList)); + if (NULL == dst_req->SSIDs.SSIDList) + status = QDF_STATUS_E_NOMEM; + else + status = QDF_STATUS_SUCCESS; + if (QDF_IS_STATUS_SUCCESS(status)) { + dst_req->SSIDs.numOfSSIDs = + src_req->SSIDs.numOfSSIDs; + qdf_mem_copy(dst_req->SSIDs.SSIDList, + src_req->SSIDs.SSIDList, + src_req->SSIDs.numOfSSIDs * + sizeof(*dst_req->SSIDs.SSIDList)); + } else { + dst_req->SSIDs.numOfSSIDs = 0; + sms_log(mac_ctx, LOGE, + FL("No memory for scanning SSID List")); + goto complete; + } + } /* Allocate memory for SSID List */ + qdf_mem_copy(&dst_req->bssid, &src_req->bssid, + sizeof(struct qdf_mac_addr)); + dst_req->p2pSearch = src_req->p2pSearch; + dst_req->skipDfsChnlInP2pSearch = + src_req->skipDfsChnlInP2pSearch; + dst_req->scan_id = src_req->scan_id; + dst_req->timestamp = src_req->timestamp; + +complete: + if (!QDF_IS_STATUS_SUCCESS(status)) { + csr_scan_free_request(mac_ctx, dst_req); + } + + return status; +} + +QDF_STATUS csr_scan_free_request(tpAniSirGlobal pMac, tCsrScanRequest *pReq) +{ + + if (pReq->ChannelInfo.ChannelList) { + qdf_mem_free(pReq->ChannelInfo.ChannelList); + pReq->ChannelInfo.ChannelList = NULL; + } + pReq->ChannelInfo.numOfChannels = 0; + if (pReq->pIEField) { + qdf_mem_free(pReq->pIEField); + pReq->pIEField = NULL; + } + pReq->uIEFieldLen = 0; + if (pReq->SSIDs.SSIDList) { + qdf_mem_free(pReq->SSIDs.SSIDList); + pReq->SSIDs.SSIDList = NULL; + } + pReq->SSIDs.numOfSSIDs = 0; + + return QDF_STATUS_SUCCESS; +} + +void csr_scan_call_callback(tpAniSirGlobal pMac, tSmeCmd *pCommand, + eCsrScanStatus scanStatus) +{ + if (pCommand->u.scanCmd.callback) { + /* + * In case of eCsrScanForSsid scan, scan is aborted as host gets + * the desired AP, this doesn't necessaryly mean that scan is + * failed, send abort indication to upper layers only if scan + * status is not success + */ + if (pCommand->u.scanCmd.abort_scan_indication) { + if ((pCommand->u.scanCmd.reason != eCsrScanForSsid) || + (scanStatus != eCSR_SCAN_SUCCESS)) { + sms_log(pMac, LOG1, + FL("scanDone due to abort")); + scanStatus = eCSR_SCAN_ABORT; + } + } + pCommand->u.scanCmd.callback(pMac, pCommand->u.scanCmd.pContext, + pCommand->sessionId, + pCommand->u.scanCmd.scanID, + scanStatus); + } else { + sms_log(pMac, LOG2, "%s:%d - Callback NULL!!!", __func__, + __LINE__); + } +} + +#ifdef WLAN_AP_STA_CONCURRENCY +/** + * csr_sta_ap_conc_timer_handler - Function to handle STA,AP concurrency timer + * @pv: pointer variable + * + * Function handles STA,AP concurrency timer + * + * Return: none + */ +static void csr_sta_ap_conc_timer_handler(void *pv) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(pv); + tListElem *entry; + tSmeCmd *scan_cmd; + uint32_t session_id = CSR_SESSION_ID_INVALID; + tCsrScanRequest scan_req; + tSmeCmd *send_scancmd = NULL; + uint8_t num_chn = 0; + uint8_t numchan_combinedconc = 0; + uint8_t i, j; + tCsrChannelInfo *chn_info = NULL; + uint8_t channel_to_scan[WNI_CFG_VALID_CHANNEL_LIST_LEN]; + QDF_STATUS status; + + csr_ll_lock(&mac_ctx->scan.scanCmdPendingList); + + entry = csr_ll_peek_head(&mac_ctx->scan.scanCmdPendingList, + LL_ACCESS_NOLOCK); + + if (NULL == entry) { + csr_ll_unlock(&mac_ctx->scan.scanCmdPendingList); + return; + } + + + chn_info = &scan_req.ChannelInfo; + scan_cmd = GET_BASE_ADDR(entry, tSmeCmd, Link); + num_chn = + scan_cmd->u.scanCmd.u.scanRequest.ChannelInfo.numOfChannels; + session_id = scan_cmd->sessionId; + + /* + * if any session is connected and the number of channels to scan is + * greater than 1 then split the scan into multiple scan operations + * on each individual channel else continue to perform scan on all + * specified channels */ + + /* + * split scan if number of channels to scan is greater than 1 and + * any one of the following: + * - STA session is connected and the scan is not a P2P search + * - any P2P session is connected + * Do not split scans if no concurrent infra connections are + * active and if the scan is a BG scan triggered by LFR (OR) + * any scan if LFR is in the middle of a BG scan. Splitting + * the scan is delaying the time it takes for LFR to find + * candidates and resulting in disconnects. + */ + + if ((csr_is_sta_session_connected(mac_ctx) && + !csr_is_p2p_session_connected(mac_ctx))) + numchan_combinedconc = + mac_ctx->roam.configParam.nNumStaChanCombinedConc; + else if (csr_is_p2p_session_connected(mac_ctx)) + numchan_combinedconc = + mac_ctx->roam.configParam.nNumP2PChanCombinedConc; + + if ((num_chn > numchan_combinedconc) && + ((csr_is_sta_session_connected(mac_ctx) && + (csr_is_concurrent_infra_connected(mac_ctx)) && + (scan_cmd->u.scanCmd.u.scanRequest.p2pSearch != 1)) || + (csr_is_p2p_session_connected(mac_ctx)))) { + qdf_mem_set(&scan_req, sizeof(tCsrScanRequest), 0); + + /* optimize this to use 2 command buffer only */ + send_scancmd = csr_get_command_buffer(mac_ctx); + if (!send_scancmd) { + sms_log(mac_ctx, LOGE, + FL(" Failed to get Queue command buffer")); + csr_ll_unlock(&mac_ctx->scan.scanCmdPendingList); + return; + } + send_scancmd->command = scan_cmd->command; + send_scancmd->sessionId = scan_cmd->sessionId; + send_scancmd->u.scanCmd.callback = NULL; + send_scancmd->u.scanCmd.pContext = + scan_cmd->u.scanCmd.pContext; + send_scancmd->u.scanCmd.reason = + scan_cmd->u.scanCmd.reason; + /* let it wrap around */ + wma_get_scan_id(&send_scancmd->u.scanCmd.scanID); + + /* + * First copy all the parameters to local variable of scan + * request + */ + csr_scan_copy_request(mac_ctx, &scan_req, + &scan_cmd->u.scanCmd.u.scanRequest); + + /* + * Now modify the elements of local var scan request required + * to be modified for split scan + */ + if (scan_req.ChannelInfo.ChannelList != NULL) { + qdf_mem_free(scan_req.ChannelInfo.ChannelList); + scan_req.ChannelInfo.ChannelList = NULL; + } + + chn_info->numOfChannels = numchan_combinedconc; + qdf_mem_copy(&channel_to_scan[0], + &scan_cmd->u.scanCmd.u.scanRequest.ChannelInfo. + ChannelList[0], chn_info->numOfChannels + * sizeof(uint8_t)); + chn_info->ChannelList = &channel_to_scan[0]; + + for (i = 0, j = numchan_combinedconc; + i < (num_chn - numchan_combinedconc); + i++, j++) { + /* Move all the channels one step */ + scan_cmd->u.scanCmd.u.scanRequest.ChannelInfo. + ChannelList[i] = + scan_cmd->u.scanCmd.u.scanRequest. + ChannelInfo.ChannelList[j]; + } + + /* reduce outstanding # of channels to be scanned */ + scan_cmd->u.scanCmd.u.scanRequest.ChannelInfo.numOfChannels = + num_chn - numchan_combinedconc; + + scan_req.BSSType = eCSR_BSS_TYPE_ANY; + /* Modify callers parameters in case of concurrency */ + scan_req.scanType = eSIR_ACTIVE_SCAN; + /* Use concurrency values for min/maxChnTime. */ + csr_set_default_scan_timing(mac_ctx, scan_req.scanType, + &scan_req); + + status = csr_scan_copy_request(mac_ctx, + &send_scancmd->u.scanCmd.u. + scanRequest, &scan_req); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sms_log(mac_ctx, LOGE, + FL(" Failed to get copy csr_scan_request = %d"), + status); + csr_ll_unlock(&mac_ctx->scan.scanCmdPendingList); + return; + } + /* Clean the local scan variable */ + scan_req.ChannelInfo.ChannelList = NULL; + scan_req.ChannelInfo.numOfChannels = 0; + csr_scan_free_request(mac_ctx, &scan_req); + } else { + /* + * no active connected session present or numChn == 1 + * scan all remaining channels + */ + send_scancmd = scan_cmd; + /* remove this command from pending list */ + if (csr_ll_remove_head(&mac_ctx->scan.scanCmdPendingList, + /* + * In case between PeekHead and here, the entry + * got removed by another thread. + */ + LL_ACCESS_NOLOCK) == NULL) { + sms_log(mac_ctx, LOGE, + FL(" Failed to remove entry from scanCmdPendingList")); + } + + } + csr_queue_sme_command(mac_ctx, send_scancmd, false); + + + csr_ll_unlock(&mac_ctx->scan.scanCmdPendingList); + +} +#endif + +/** + * csr_purge_scan_result_by_age() - Purge scan results based on Age + * @pv: Global context + * + * This routine is to purge scan results based on aging. + * + * Return: None + */ +static void csr_purge_scan_result_by_age(void *pv) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(pv); + tListElem *entry, *tmp_entry; + tCsrScanResult *result; + uint64_t ageout_time = + mac_ctx->scan.scanResultCfgAgingTime * SYSTEM_TIME_SEC_TO_MSEC; + uint64_t cur_time = qdf_mc_timer_get_system_time(); + uint8_t *bssId; + + csr_ll_lock(&mac_ctx->scan.scanResultList); + entry = csr_ll_peek_head(&mac_ctx->scan.scanResultList, LL_ACCESS_NOLOCK); + sms_log(mac_ctx, LOG1, FL(" Ageout time=%llu"), ageout_time); + while (entry) { + tmp_entry = csr_ll_next(&mac_ctx->scan.scanResultList, entry, + LL_ACCESS_NOLOCK); + result = GET_BASE_ADDR(entry, tCsrScanResult, Link); + + if ((cur_time - result->Result.BssDescriptor.received_time) > + ageout_time) { + bssId = result->Result.BssDescriptor.bssId; + sms_log(mac_ctx, LOGW, + FL("age out for BSSID" MAC_ADDRESS_STR" Channel %d"), + MAC_ADDR_ARRAY(bssId), + result->Result.BssDescriptor.channelId); + csr_scan_age_out_bss(mac_ctx, result); + } + entry = tmp_entry; + } + csr_ll_unlock(&mac_ctx->scan.scanResultList); +} + +bool csr_scan_remove_fresh_scan_command(tpAniSirGlobal pMac, uint8_t sessionId) +{ + bool fRet = false; + tListElem *pEntry, *pEntryTmp; + tSmeCmd *pCommand; + tDblLinkList localList; + tDblLinkList *pCmdList; + + qdf_mem_zero(&localList, sizeof(tDblLinkList)); + if (!QDF_IS_STATUS_SUCCESS(csr_ll_open(pMac->hHdd, &localList))) { + sms_log(pMac, LOGE, FL(" failed to open list")); + return fRet; + } + + pCmdList = &pMac->sme.smeScanCmdPendingList; + + csr_ll_lock(pCmdList); + pEntry = csr_ll_peek_head(pCmdList, LL_ACCESS_NOLOCK); + while (pEntry) { + pEntryTmp = csr_ll_next(pCmdList, pEntry, LL_ACCESS_NOLOCK); + pCommand = GET_BASE_ADDR(pEntry, tSmeCmd, Link); + if (!((eSmeCommandScan == pCommand->command) + && (sessionId == pCommand->sessionId))) { + pEntry = pEntryTmp; + continue; + } + sms_log(pMac, LOGW, + FL("-------- abort scan command reason = %d"), + pCommand->u.scanCmd.reason); + /* The rest are fresh scan requests */ + if (csr_ll_remove_entry(pCmdList, pEntry, + LL_ACCESS_NOLOCK)) { + csr_ll_insert_tail(&localList, pEntry, + LL_ACCESS_NOLOCK); + } + fRet = true; + pEntry = pEntryTmp; + } + + csr_ll_unlock(pCmdList); + + while ((pEntry = csr_ll_remove_head(&localList, LL_ACCESS_NOLOCK))) { + pCommand = GET_BASE_ADDR(pEntry, tSmeCmd, Link); + if (pCommand->u.scanCmd.callback) { + /* + * User scan request is pending, send response with + * status eCSR_SCAN_ABORT + */ + pCommand->u.scanCmd.callback(pMac, + pCommand->u.scanCmd.pContext, sessionId, + pCommand->u.scanCmd.scanID, eCSR_SCAN_ABORT); + } + csr_release_command_scan(pMac, pCommand); + } + csr_ll_close(&localList); + + return fRet; +} + +void csr_release_scan_command(tpAniSirGlobal pMac, tSmeCmd *pCommand, + eCsrScanStatus scanStatus) +{ + eCsrScanReason reason = pCommand->u.scanCmd.reason; + bool status; + tDblLinkList *cmd_list = NULL; + + csr_scan_call_callback(pMac, pCommand, scanStatus); + sms_log(pMac, LOG1, FL("Remove Scan command reason = %d, scan_id %d"), + reason, pCommand->u.scanCmd.scanID); + cmd_list = &pMac->sme.smeScanCmdActiveList; + status = csr_ll_remove_entry(cmd_list, &pCommand->Link, LL_ACCESS_LOCK); + if (!status) { + sms_log(pMac, LOGE, + FL("cannot release command reason %d scan_id %d"), + pCommand->u.scanCmd.reason, + pCommand->u.scanCmd.scanID); + return; + } + csr_release_command_scan(pMac, pCommand); +} + +QDF_STATUS csr_scan_get_pmkid_candidate_list(tpAniSirGlobal pMac, + uint32_t sessionId, + tPmkidCandidateInfo *pPmkidList, + uint32_t *pNumItems) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + tCsrScanResultFilter *pScanFilter; + tCsrScanResultInfo *pScanResult; + tScanResultHandle hBSSList; + uint32_t nItems = *pNumItems; + + if (!pSession) { + sms_log(pMac, LOGE, FL(" session %d not found "), sessionId); + return QDF_STATUS_E_FAILURE; + } + + sms_log(pMac, LOGW, FL("pMac->scan.NumPmkidCandidate = %d"), + pSession->NumPmkidCandidate); + csr_reset_pmkid_candidate_list(pMac, sessionId); + if (!(csr_is_conn_state_connected(pMac, sessionId) + && pSession->pCurRoamProfile)) + return status; + + *pNumItems = 0; + pScanFilter = qdf_mem_malloc(sizeof(tCsrScanResultFilter)); + if (NULL == pScanFilter) + return QDF_STATUS_E_NOMEM; + + /* Here is the profile we need to connect to */ + status = csr_roam_prepare_filter_from_profile(pMac, + pSession->pCurRoamProfile, pScanFilter); + if (!QDF_IS_STATUS_SUCCESS(status)) { + qdf_mem_free(pScanFilter); + return status; + } + + status = csr_scan_get_result(pMac, pScanFilter, &hBSSList); + if (!QDF_IS_STATUS_SUCCESS(status)) { + csr_free_scan_filter(pMac, pScanFilter); + qdf_mem_free(pScanFilter); + return status; + } + + if (pSession->NumPmkidCandidate < nItems) { + pScanResult = csr_scan_result_get_next(pMac, hBSSList); + while (pScanResult != NULL) { + /* NumPmkidCandidate adds up here */ + csr_process_bss_desc_for_pmkid_list(pMac, + &pScanResult->BssDescriptor, + (tDot11fBeaconIEs *)(pScanResult->pvIes), + sessionId); + pScanResult = csr_scan_result_get_next(pMac, hBSSList); + } + } + + if (pSession->NumPmkidCandidate) { + *pNumItems = pSession->NumPmkidCandidate; + qdf_mem_copy(pPmkidList, pSession->PmkidCandidateInfo, + pSession->NumPmkidCandidate * + sizeof(tPmkidCandidateInfo)); + } + + csr_scan_result_purge(pMac, hBSSList); + csr_free_scan_filter(pMac, pScanFilter); + qdf_mem_free(pScanFilter); + return status; +} + +#ifdef FEATURE_WLAN_WAPI +QDF_STATUS csr_scan_get_bkid_candidate_list(tpAniSirGlobal pMac, + uint32_t sessionId, + tBkidCandidateInfo *pBkidList, + uint32_t *pNumItems) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + tCsrScanResultFilter *pScanFilter; + tCsrScanResultInfo *pScanResult; + tScanResultHandle hBSSList; + uint32_t nItems = *pNumItems; + + if (!pSession) { + sms_log(pMac, LOGE, FL(" session %d not found "), sessionId); + return QDF_STATUS_E_FAILURE; + } + + sms_log(pMac, LOGW, FL("pMac->scan.NumBkidCandidate = %d"), + pSession->NumBkidCandidate); + csr_reset_bkid_candidate_list(pMac, sessionId); + if (!(csr_is_conn_state_connected(pMac, sessionId) + && pSession->pCurRoamProfile)) + return status; + + *pNumItems = 0; + pScanFilter = qdf_mem_malloc(sizeof(tCsrScanResultFilter)); + if (NULL == pScanFilter) + return QDF_STATUS_E_NOMEM; + + /* Here is the profile we need to connect to */ + status = csr_roam_prepare_filter_from_profile(pMac, + pSession->pCurRoamProfile, pScanFilter); + if (!QDF_IS_STATUS_SUCCESS(status)) { + qdf_mem_free(pScanFilter); + return status; + } + + status = csr_scan_get_result(pMac, pScanFilter, &hBSSList); + if (!QDF_IS_STATUS_SUCCESS(status)) { + csr_free_scan_filter(pMac, pScanFilter); + qdf_mem_free(pScanFilter); + return status; + } + + if (pSession->NumBkidCandidate < nItems) { + pScanResult = csr_scan_result_get_next(pMac, hBSSList); + while (pScanResult != NULL) { + /* pMac->scan.NumBkidCandidate adds up here */ + csr_process_bss_desc_for_bkid_list(pMac, + &pScanResult->BssDescriptor, + (tDot11fBeaconIEs *)(pScanResult->pvIes)); + pScanResult = csr_scan_result_get_next(pMac, hBSSList); + } + } + + if (pSession->NumBkidCandidate) { + *pNumItems = pSession->NumBkidCandidate; + qdf_mem_copy(pBkidList, pSession->BkidCandidateInfo, + pSession->NumBkidCandidate * + sizeof(tBkidCandidateInfo)); + } + + csr_scan_result_purge(pMac, hBSSList); + csr_free_scan_filter(pMac, pScanFilter); + qdf_mem_free(pScanFilter); + return status; +} +#endif /* FEATURE_WLAN_WAPI */ + +/** + * csr_roam_copy_channellist() - Function to copy channel list + * @mac_ctx: pointer to Global Mac structure + * @profile: pointer to tCsrRoamProfile + * @scan_cmd: pointer to tSmeCmd + * @index: index for channellist + * + * Function copies channel list + * + * Return: none + */ +static void csr_roam_copy_channellist(tpAniSirGlobal mac_ctx, + tCsrRoamProfile *profile, + tSmeCmd *scan_cmd, uint8_t index) +{ + tCsrChannelInfo *channel_info = + &scan_cmd->u.scanCmd.u.scanRequest.ChannelInfo; + + for (index = 0; index < profile->ChannelInfo.numOfChannels; + index++) { + if (!csr_roam_is_valid_channel(mac_ctx, + profile->ChannelInfo.ChannelList[index])) { + sms_log(mac_ctx, LOGW, + FL("process a channel (%d) that is invalid"), + profile->ChannelInfo.ChannelList[index]); + continue; + } + channel_info->ChannelList[channel_info->numOfChannels] = + profile->ChannelInfo.ChannelList[index]; + scan_cmd->u.scanCmd.u.scanRequest.ChannelInfo.numOfChannels++; + } +} + +/** + * csr_ssid_scan_done_callback() - Callback to indicate + * scan is done for ssid scan + * @halHandle: handle to hal + * @context: SSID scan context + * @scanId: Scan id for the scheduled scan + * @status: scan done status + * + * Return - QDF_STATUS + */ +static QDF_STATUS csr_ssid_scan_done_callback(tHalHandle halHandle, + void *context, + uint8_t sessionId, + uint32_t scanId, + eCsrScanStatus status) +{ + struct csr_scan_for_ssid_context *scan_context = + (struct csr_scan_for_ssid_context *)context; + + if (NULL == scan_context) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("scan for ssid context not found")); + return QDF_STATUS_E_INVAL; + } + + if (eCSR_SCAN_ABORT == status) + csr_roam_call_callback(scan_context->mac_ctx, + scan_context->session_id, + NULL, scan_context->roam_id, + eCSR_ROAM_ASSOCIATION_FAILURE, + eCSR_ROAM_RESULT_SCAN_FOR_SSID_FAILURE); + qdf_mem_free(scan_context); + return QDF_STATUS_SUCCESS; +} + + +/** + * csr_scan_for_ssid() - Function usually used for BSSs that suppresses SSID + * @mac_ctx: Pointer to Global Mac structure + * @profile: pointer to tCsrRoamProfile + * @roam_id: variable representing roam id + * @notify: boolean variable + * + * Function is usually used for BSSs that suppresses SSID so the profile + * shall have one and only one SSID. + * + * Return: Success - QDF_STATUS_SUCCESS, Failure - error number + */ +QDF_STATUS csr_scan_for_ssid(tpAniSirGlobal mac_ctx, uint32_t session_id, + tCsrRoamProfile *profile, uint32_t roam_id, + bool notify) +{ + QDF_STATUS status = QDF_STATUS_E_INVAL; + tSmeCmd *scan_cmd = NULL; + tCsrScanRequest *scan_req = NULL; + uint8_t index = 0; + uint32_t num_ssid = profile->SSIDs.numOfSSIDs; + tpCsrNeighborRoamControlInfo neighbor_roaminfo = + &mac_ctx->roam.neighborRoamInfo[session_id]; + tCsrSSIDs *ssids = NULL; + struct csr_scan_for_ssid_context *context; + + sms_log(mac_ctx, LOG2, FL("called")); + + if (!(mac_ctx->scan.fScanEnable) && (num_ssid != 1)) { + sms_log(mac_ctx, LOGE, + FL("cannot scan because scanEnable (%d) or numSSID (%d) is invalid"), + mac_ctx->scan.fScanEnable, profile->SSIDs.numOfSSIDs); + return status; + } + + scan_cmd = csr_get_command_buffer(mac_ctx); + + if (!scan_cmd) { + sms_log(mac_ctx, LOGE, + FL("failed to allocate command buffer")); + goto error; + } + + qdf_mem_set(&scan_cmd->u.scanCmd, sizeof(tScanCmd), 0); + scan_cmd->u.scanCmd.pToRoamProfile = + qdf_mem_malloc(sizeof(tCsrRoamProfile)); + + if (NULL == scan_cmd->u.scanCmd.pToRoamProfile) + status = QDF_STATUS_E_NOMEM; + else + status = csr_roam_copy_profile(mac_ctx, + scan_cmd->u.scanCmd.pToRoamProfile, + profile); + + context = qdf_mem_malloc(sizeof(*context)); + if (NULL == context) { + sms_log(mac_ctx, LOGE, + "Failed to allocate memory for ssid scan context"); + goto error; + } + context->mac_ctx = mac_ctx; + context->session_id = session_id; + context->roam_id = roam_id; + + if (!QDF_IS_STATUS_SUCCESS(status)) + goto error; + + scan_cmd->u.scanCmd.roamId = roam_id; + scan_cmd->command = eSmeCommandScan; + scan_cmd->sessionId = (uint8_t) session_id; + scan_cmd->u.scanCmd.callback = csr_ssid_scan_done_callback; + scan_cmd->u.scanCmd.pContext = context; + scan_cmd->u.scanCmd.reason = eCsrScanForSsid; + + /* let it wrap around */ + wma_get_scan_id(&scan_cmd->u.scanCmd.scanID); + qdf_mem_set(&scan_cmd->u.scanCmd.u.scanRequest, + sizeof(tCsrScanRequest), 0); + status = qdf_mc_timer_init(&scan_cmd->u.scanCmd.csr_scan_timer, + QDF_TIMER_TYPE_SW, + csr_scan_active_list_timeout_handle, scan_cmd); + scan_req = &scan_cmd->u.scanCmd.u.scanRequest; + scan_req->scanType = eSIR_ACTIVE_SCAN; + scan_req->BSSType = profile->BSSType; + scan_req->scan_id = scan_cmd->u.scanCmd.scanID; + /* + * To avoid 11b rate in probe request Set p2pSearch + * flag as 1 for P2P Client Mode + */ + if (QDF_P2P_CLIENT_MODE == profile->csrPersona) + scan_req->p2pSearch = 1; + + /* Allocate memory for IE field */ + if (profile->pAddIEScan) { + scan_req->pIEField = + qdf_mem_malloc(profile->nAddIEScanLength); + + if (NULL == scan_req->pIEField) + status = QDF_STATUS_E_NOMEM; + else + status = QDF_STATUS_SUCCESS; + + if (QDF_IS_STATUS_SUCCESS(status)) { + qdf_mem_copy(scan_req->pIEField, + profile->pAddIEScan, + profile->nAddIEScanLength); + scan_req->uIEFieldLen = profile->nAddIEScanLength; + } else { + sms_log(mac_ctx, LOGE, + "No memory for scanning IE fields"); + } + } else + scan_req->uIEFieldLen = 0; + + /* + * For one channel be good enpugh time to receive beacon + * atleast + */ + if (1 == profile->ChannelInfo.numOfChannels) { + if (neighbor_roaminfo->handoffReqInfo.src == + FASTREASSOC) { + scan_req->maxChnTime = + MAX_ACTIVE_SCAN_FOR_ONE_CHANNEL_FASTREASSOC; + scan_req->minChnTime = + MIN_ACTIVE_SCAN_FOR_ONE_CHANNEL_FASTREASSOC; + /* Reset this value */ + neighbor_roaminfo->handoffReqInfo.src = 0; + } else { + scan_req->maxChnTime = + MAX_ACTIVE_SCAN_FOR_ONE_CHANNEL; + scan_req->minChnTime = + MIN_ACTIVE_SCAN_FOR_ONE_CHANNEL; + } + } else { + scan_req->maxChnTime = + mac_ctx->roam.configParam.nActiveMaxChnTime; + scan_req->minChnTime = + mac_ctx->roam.configParam.nActiveMinChnTime; + } + + if (profile->BSSIDs.numOfBSSIDs == 1) + qdf_copy_macaddr(&scan_req->bssid, + profile->BSSIDs.bssid); + else + qdf_set_macaddr_broadcast(&scan_req->bssid); + + if (profile->ChannelInfo.numOfChannels) { + scan_req->ChannelInfo.ChannelList = + qdf_mem_malloc(sizeof(*scan_req->ChannelInfo.ChannelList) * + profile->ChannelInfo.numOfChannels); + + if (NULL == scan_req->ChannelInfo.ChannelList) + status = QDF_STATUS_E_NOMEM; + else + status = QDF_STATUS_SUCCESS; + + scan_req->ChannelInfo.numOfChannels = 0; + + if (QDF_IS_STATUS_SUCCESS(status)) { + csr_roam_is_channel_valid(mac_ctx, + profile->ChannelInfo.ChannelList[0]); + csr_roam_copy_channellist(mac_ctx, + profile, scan_cmd, index); + } else { + goto error; + } + } else { + scan_req->ChannelInfo.numOfChannels = 0; + } + + if (profile->SSIDs.numOfSSIDs) { + scan_req->SSIDs.SSIDList = + qdf_mem_malloc(profile->SSIDs.numOfSSIDs * + sizeof(tCsrSSIDInfo)); + + if (NULL == scan_req->SSIDs.SSIDList) + status = QDF_STATUS_E_NOMEM; + else + status = QDF_STATUS_SUCCESS; + + if (!QDF_IS_STATUS_SUCCESS(status)) + goto error; + + ssids = &scan_req->SSIDs; + ssids->numOfSSIDs = 1; + + qdf_mem_copy(scan_req->SSIDs.SSIDList, + profile->SSIDs.SSIDList, + sizeof(tCsrSSIDInfo)); + } + + /* Start process the command */ + status = csr_queue_sme_command(mac_ctx, scan_cmd, false); +error: + if (!QDF_IS_STATUS_SUCCESS(status)) { + sms_log(mac_ctx, LOGE, + FL(" failed to iniate scan with status = %d"), status); + if (scan_cmd) + csr_release_command_scan(mac_ctx, scan_cmd); + if (notify) + csr_roam_call_callback(mac_ctx, session_id, NULL, + roam_id, eCSR_ROAM_FAILED, + eCSR_ROAM_RESULT_FAILURE); + } + return status; +} + +void csr_set_cfg_valid_channel_list(tpAniSirGlobal pMac, uint8_t *pChannelList, + uint8_t NumChannels) +{ + uint32_t dataLen = sizeof(uint8_t) * NumChannels; + QDF_STATUS status; + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO, + "%s: dump valid channel list(NumChannels(%d))", + __func__, NumChannels); + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO, + pChannelList, NumChannels); + cfg_set_str(pMac, WNI_CFG_VALID_CHANNEL_LIST, pChannelList, + dataLen); + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO, + "Scan offload is enabled, update default chan list"); + /* + * disable fcc constraint since new country code + * is being set + */ + pMac->scan.fcc_constraint = false; + status = csr_update_channel_list(pMac); + if (QDF_STATUS_SUCCESS != status) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "failed to update the supported channel list"); + } + return; +} + +/* + * The Tx power limits are saved in the cfg for future usage. + */ +void csr_save_tx_power_to_cfg(tpAniSirGlobal pMac, tDblLinkList *pList, + uint32_t cfgId) +{ + tListElem *pEntry; + uint32_t cbLen = 0, dataLen, tmp_len; + tCsrChannelPowerInfo *ch_set; + uint32_t idx; + tSirMacChanInfo *ch_pwr_set; + uint8_t *pBuf = NULL; + + /* allocate maximum space for all channels */ + dataLen = WNI_CFG_VALID_CHANNEL_LIST_LEN * sizeof(tSirMacChanInfo); + pBuf = qdf_mem_malloc(dataLen); + if (pBuf == NULL) + return; + + ch_pwr_set = (tSirMacChanInfo *) (pBuf); + pEntry = csr_ll_peek_head(pList, LL_ACCESS_LOCK); + /* + * write the tuples (startChan, numChan, txPower) for each channel found + * in the channel power list. + */ + while (pEntry) { + ch_set = GET_BASE_ADDR(pEntry, tCsrChannelPowerInfo, link); + if (1 != ch_set->interChannelOffset) { + /* + * we keep the 5G channel sets internally with an + * interchannel offset of 4. Expand these to the right + * format. (inter channel offset of 1 is the only option + * for the triplets that 11d advertises. + */ + tmp_len = cbLen + (ch_set->numChannels * + sizeof(tSirMacChanInfo)); + if (tmp_len >= dataLen) { + /* + * expanding this entry will overflow our + * allocation + */ + sms_log(pMac, LOGE, + FL("Buffer overflow, start %d, num %d, offset %d"), + ch_set->firstChannel, + ch_set->numChannels, + ch_set->interChannelOffset); + break; + } + + for (idx = 0; idx < ch_set->numChannels; idx++) { + ch_pwr_set->firstChanNum = (tSirMacChanNum) + (ch_set->firstChannel + (idx * + ch_set->interChannelOffset)); + sms_log(pMac, LOG3, + FL("Setting Channel Number %d"), + ch_pwr_set->firstChanNum); + ch_pwr_set->numChannels = 1; + ch_pwr_set->maxTxPower = + QDF_MIN(ch_set->txPower, + pMac->roam.configParam.nTxPowerCap); + sms_log(pMac, LOG3, + FL("Setting Max Transmit Power %d"), + ch_pwr_set->maxTxPower); + cbLen += sizeof(tSirMacChanInfo); + ch_pwr_set++; + } + } else { + if (cbLen >= dataLen) { + /* this entry will overflow our allocation */ + sms_log(pMac, LOGE, + FL("Buffer overflow, start %d, num %d, offset %d"), + ch_set->firstChannel, + ch_set->numChannels, + ch_set->interChannelOffset); + break; + } + ch_pwr_set->firstChanNum = ch_set->firstChannel; + sms_log(pMac, LOG3, FL("Setting Channel Number %d"), + ch_pwr_set->firstChanNum); + ch_pwr_set->numChannels = ch_set->numChannels; + ch_pwr_set->maxTxPower = QDF_MIN(ch_set->txPower, + pMac->roam.configParam.nTxPowerCap); + sms_log(pMac, LOG3, + FL("Setting Max Tx Power %d, nTxPower %d"), + ch_pwr_set->maxTxPower, + pMac->roam.configParam.nTxPowerCap); + cbLen += sizeof(tSirMacChanInfo); + ch_pwr_set++; + } + pEntry = csr_ll_next(pList, pEntry, LL_ACCESS_LOCK); + } + if (cbLen) + cfg_set_str(pMac, cfgId, (uint8_t *) pBuf, cbLen); + + qdf_mem_free(pBuf); +} + +void csr_set_cfg_country_code(tpAniSirGlobal pMac, uint8_t *countryCode) +{ + uint8_t cc[WNI_CFG_COUNTRY_CODE_LEN]; + /* v_REGDOMAIN_t DomainId */ + + sms_log(pMac, LOG3, FL("Setting Country Code in Cfg %s"), countryCode); + qdf_mem_copy(cc, countryCode, WNI_CFG_COUNTRY_CODE_LEN); + + /* + * don't program the bogus country codes that we created for Korea in the + * MAC. if we see the bogus country codes, program the MAC with the right + * country code. + */ + if (('K' == countryCode[0] && '1' == countryCode[1]) || + ('K' == countryCode[0] && '2' == countryCode[1]) || + ('K' == countryCode[0] && '3' == countryCode[1]) || + ('K' == countryCode[0] && '4' == countryCode[1])) { + /* + * replace the alternate Korea country codes, 'K1', 'K2', .. + * with 'KR' for Korea + */ + cc[1] = 'R'; + } + cfg_set_str(pMac, WNI_CFG_COUNTRY_CODE, cc, WNI_CFG_COUNTRY_CODE_LEN); + + /* + * Need to let HALPHY know about the current domain so it can apply some + * domain-specific settings (TX filter...) + */ + /* + if(QDF_IS_STATUS_SUCCESS(csr_get_regulatory_domain_for_country( + pMac, cc, &DomainId))) { + halPhySetRegDomain(pMac, DomainId); + } */ +} + +QDF_STATUS csr_get_country_code(tpAniSirGlobal pMac, uint8_t *pBuf, + uint8_t *pbLen) +{ + QDF_STATUS status = QDF_STATUS_E_INVAL; + uint32_t len; + + if (pBuf && pbLen && (*pbLen >= WNI_CFG_COUNTRY_CODE_LEN)) { + len = *pbLen; + status = wlan_cfg_get_str(pMac, WNI_CFG_COUNTRY_CODE, pBuf, &len); + if (QDF_IS_STATUS_SUCCESS(status)) { + *pbLen = (uint8_t) len; + } + } + + return status; +} + +void csr_set_cfg_scan_control_list(tpAniSirGlobal pMac, uint8_t *countryCode, + tCsrChannel *pChannelList) +{ + uint8_t i, j; + bool found = false; + uint8_t *pControlList = NULL; + uint32_t len = WNI_CFG_SCAN_CONTROL_LIST_LEN; + + pControlList = qdf_mem_malloc(WNI_CFG_SCAN_CONTROL_LIST_LEN); + if (pControlList != NULL) { + if (IS_SIR_STATUS_SUCCESS(wlan_cfg_get_str(pMac, + WNI_CFG_SCAN_CONTROL_LIST, + pControlList, &len))) { + for (i = 0; i < pChannelList->numChannels; i++) { + for (j = 0; j < len; j += 2) { + if (pControlList[j] == + pChannelList->channelList[i]) { + found = true; + break; + } + } + + if (found) { + /* insert a pair(channel#, flag) */ + pControlList[j + 1] = + csr_get_scan_type(pMac, + pControlList[j]); + found = false; /* reset the flag */ + } + + } + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO, + "%s: dump scan control list", __func__); + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_INFO, pControlList, + len); + + cfg_set_str(pMac, WNI_CFG_SCAN_CONTROL_LIST, + pControlList, len); + } /* Successfully getting scan control list */ + qdf_mem_free(pControlList); + } /* AllocateMemory */ +} + + +/** + * csr_scan_abort_all_scans() - Abort scan on all Sessions + * @mac_ctx: pointer to Global Mac structure + * @reason: reason for cancelling scan + * + * Abort scan on all Sessions + * + * Return: QDF_STATUS + */ +QDF_STATUS csr_scan_abort_all_scans(tpAniSirGlobal mac_ctx, + eCsrAbortReason reason) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + uint8_t session_id; + + mac_ctx->scan.fDropScanCmd = true; + for (session_id = 0; session_id < CSR_ROAM_SESSION_MAX; session_id++) { + if (CSR_IS_SESSION_VALID(mac_ctx, session_id)) { + csr_remove_cmd_from_pending_list( + mac_ctx, + session_id, INVALID_SCAN_ID, + &mac_ctx->sme.smeScanCmdPendingList, + eSmeCommandScan); + csr_abort_scan_from_active_list(mac_ctx, + &mac_ctx->sme.smeScanCmdActiveList, + session_id, INVALID_SCAN_ID, eSmeCommandScan, + reason); + } + } + mac_ctx->scan.fDropScanCmd = false; + + return status; +} + +QDF_STATUS csr_scan_abort_mac_scan(tpAniSirGlobal pMac, uint8_t sessionId, + uint32_t scan_id, eCsrAbortReason reason) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + QDF_STATUS ret; + + pMac->scan.fDropScanCmd = true; + ret = csr_remove_cmd_from_pending_list(pMac, + sessionId, scan_id, &pMac->sme.smeScanCmdPendingList, + eSmeCommandScan); + pMac->scan.fDropScanCmd = false; + + /* + * If we are not able to find command for scan id in + * pending list, check active list. Also if the session + * id is valid then we have to check below active list. + */ + if (ret != QDF_STATUS_SUCCESS || + sessionId != CSR_SESSION_ID_INVALID) { + status = csr_abort_scan_from_active_list(pMac, + &pMac->sme.smeScanCmdActiveList, sessionId, scan_id, + eSmeCommandScan, reason); + } + return status; +} + +QDF_STATUS csr_remove_cmd_from_pending_list(tpAniSirGlobal pMac, + uint8_t sessionId, + uint32_t scan_id, + tDblLinkList *pList, + eSmeCommandType commandType) +{ + tDblLinkList localList; + tListElem *pEntry; + tSmeCmd *pCommand; + tListElem *pEntryToRemove; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + + qdf_mem_zero(&localList, sizeof(tDblLinkList)); + if (!QDF_IS_STATUS_SUCCESS(csr_ll_open(pMac->hHdd, &localList))) { + sms_log(pMac, LOGE, FL("failed to open list")); + return status; + } + + csr_ll_lock(pList); + pEntry = csr_ll_peek_head(pList, LL_ACCESS_NOLOCK); + + /* + * Have to make sure we don't loop back to the head of the list, + * which will happen if the entry is NOT on the list + */ + while (pEntry) { + pEntryToRemove = pEntry; + pEntry = csr_ll_next(pList, pEntry, LL_ACCESS_NOLOCK); + pCommand = GET_BASE_ADDR(pEntryToRemove, tSmeCmd, Link); + + if ((pCommand->command == commandType) && + (((commandType == eSmeCommandScan) && + (pCommand->u.scanCmd.scanID == scan_id)) || + (pCommand->sessionId == sessionId))) { + /* Remove that entry only */ + if (csr_ll_remove_entry(pList, pEntryToRemove, + LL_ACCESS_NOLOCK)) { + csr_ll_insert_tail(&localList, pEntryToRemove, + LL_ACCESS_NOLOCK); + status = QDF_STATUS_SUCCESS; + } + } + } + csr_ll_unlock(pList); + + while ((pEntry = csr_ll_remove_head(&localList, LL_ACCESS_NOLOCK))) { + pCommand = GET_BASE_ADDR(pEntry, tSmeCmd, Link); + sms_log(pMac, LOG1, FL("Sending abort for command ID %d"), + (commandType == eSmeCommandScan) ? pCommand->u. + scanCmd.scanID : sessionId); + csr_abort_command(pMac, pCommand, false); + } + + csr_ll_close(&localList); + return status; +} + +QDF_STATUS csr_scan_abort_scan_for_ssid(tpAniSirGlobal pMac, uint32_t sessionId) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + + pMac->scan.fDropScanCmd = true; + csr_remove_scan_for_ssid_from_pending_list(pMac, + &pMac->sme.smeScanCmdPendingList, sessionId); + pMac->scan.fDropScanCmd = false; + csr_abort_scan_from_active_list(pMac, &pMac->sme.smeScanCmdActiveList, + sessionId, INVALID_SCAN_ID, eSmeCommandScan, + eCSR_SCAN_ABORT_SSID_ONLY); + return status; +} + +void csr_remove_scan_for_ssid_from_pending_list(tpAniSirGlobal pMac, + tDblLinkList *pList, + uint32_t sessionId) +{ + tDblLinkList localList; + tListElem *pEntry; + tSmeCmd *pCommand; + tListElem *pEntryToRemove; + + qdf_mem_zero(&localList, sizeof(tDblLinkList)); + if (!QDF_IS_STATUS_SUCCESS(csr_ll_open(pMac->hHdd, &localList))) { + sms_log(pMac, LOGE, FL(" failed to open list")); + return; + } + csr_ll_lock(pList); + if (!csr_ll_is_list_empty(pList, LL_ACCESS_NOLOCK)) { + pEntry = csr_ll_peek_head(pList, LL_ACCESS_NOLOCK); + /* + * Have to make sure we don't loop back to the head of the list, + * which will happen if the entry is NOT on the list... + */ + while (pEntry) { + pEntryToRemove = pEntry; + pEntry = csr_ll_next(pList, pEntry, LL_ACCESS_NOLOCK); + pCommand = GET_BASE_ADDR(pEntryToRemove, tSmeCmd, Link); + + if (!((eSmeCommandScan == pCommand->command) && + (sessionId == pCommand->sessionId))) + continue; + if (eCsrScanForSsid != pCommand->u.scanCmd.reason) + continue; + /* Remove that entry only */ + if (csr_ll_remove_entry(pList, pEntryToRemove, + LL_ACCESS_NOLOCK)) { + csr_ll_insert_tail(&localList, pEntryToRemove, + LL_ACCESS_NOLOCK); + } + } + } + csr_ll_unlock(pList); + while ((pEntry = csr_ll_remove_head(&localList, LL_ACCESS_NOLOCK))) { + pCommand = GET_BASE_ADDR(pEntry, tSmeCmd, Link); + csr_abort_command(pMac, pCommand, false); + } + csr_ll_close(&localList); +} + + +/** + * csr_send_scan_abort() - Sends scan abort command to firmware + * @mac_ctx: Pointer to Global Mac structure + * @session_id: CSR session identification + * @scan_id: scan identifier + * + * .Sends scan abort command to firmware + * + * Return: None + */ +static void csr_send_scan_abort(tpAniSirGlobal mac_ctx, + uint32_t session_id, uint32_t scan_id) +{ + tSirSmeScanAbortReq *msg; + uint16_t msg_len; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + msg_len = (uint16_t)(sizeof(tSirSmeScanAbortReq)); + msg = qdf_mem_malloc(msg_len); + if (NULL == msg) { + sms_log(mac_ctx, LOGE, + FL("Failed to alloc memory for SmeScanAbortReq")); + return; + } + msg->type = eWNI_SME_SCAN_ABORT_IND; + msg->msgLen = msg_len; + msg->sessionId = session_id; + msg->scan_id = scan_id; + sms_log(mac_ctx, LOG2, + FL("Abort scan sent to Firmware scan_id %d session %d"), + scan_id, session_id); + status = cds_send_mb_message_to_mac(msg); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sms_log(mac_ctx, LOGE, + FL("Failed to send abort scan.scan_id %d session %d"), + scan_id, session_id); + } + return; +} + +/** + * csr_abort_scan_from_active_list() - Remove Scan command from active list + * @mac_ctx: Pointer to Global Mac structure + * @list: pointer to scan active list + * @session_id: CSR session identification + * @scan_id: scan id + * @scan_cmd_type: scan command type + * @abort_reason: abort reason + * + * Remove Scan command from active scan list by matching either the scan id + * or session id. + * + * Return: Success - QDF_STATUS_SUCCESS, Failure - error number + */ +QDF_STATUS csr_abort_scan_from_active_list(tpAniSirGlobal mac_ctx, + tDblLinkList *list, uint32_t session_id, uint32_t scan_id, + eSmeCommandType scan_cmd_type, eCsrAbortReason abort_reason) +{ + tListElem *entry; + tSmeCmd *cmd; + tListElem *entry_remove; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + csr_ll_lock(list); + if (!csr_ll_is_list_empty(list, LL_ACCESS_NOLOCK)) { + entry = csr_ll_peek_head(list, LL_ACCESS_NOLOCK); + while (entry) { + entry_remove = entry; + entry = csr_ll_next(list, entry, LL_ACCESS_NOLOCK); + cmd = GET_BASE_ADDR(entry_remove, tSmeCmd, Link); + + /*skip if abort reason is for SSID*/ + if ((abort_reason == eCSR_SCAN_ABORT_SSID_ONLY) && + (eCsrScanForSsid != cmd->u.scanCmd.reason)) + continue; + /* + * Do not skip if command and either session id + * or scan id is matched + */ + if ((cmd->command == scan_cmd_type) && + ((cmd->u.scanCmd.scanID == scan_id) || + (cmd->sessionId == session_id))) { + if (abort_reason == + eCSR_SCAN_ABORT_DUE_TO_BAND_CHANGE) + cmd->u.scanCmd.abort_scan_indication = + eCSR_SCAN_ABORT_DUE_TO_BAND_CHANGE; + + csr_send_scan_abort(mac_ctx, cmd->sessionId, + cmd->u.scanCmd.scanID); + + } + } + } + csr_ll_unlock(list); + + return status; +} + + +QDF_STATUS csr_scan_abort_mac_scan_not_for_connect(tpAniSirGlobal pMac, + uint8_t sessionId) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + if (!csr_is_scan_for_roam_command_active(pMac)) { + /* + * Only abort the scan if it is not used for other roam/connect + * purpose + */ + status = csr_scan_abort_mac_scan(pMac, sessionId, + INVALID_SCAN_ID, eCSR_SCAN_ABORT_DEFAULT); + } + return status; +} +bool csr_roam_is_valid_channel(tpAniSirGlobal pMac, uint8_t channel) +{ + bool fValid = false; + uint32_t idx_valid_ch; + uint32_t len = pMac->roam.numValidChannels; + + for (idx_valid_ch = 0; (idx_valid_ch < len); idx_valid_ch++) { + if (channel == pMac->roam.validChannelList[idx_valid_ch]) { + fValid = true; + break; + } + } + return fValid; +} + +#ifdef FEATURE_WLAN_SCAN_PNO +QDF_STATUS csr_scan_save_preferred_network_found(tpAniSirGlobal pMac, + tSirPrefNetworkFoundInd * + pPrefNetworkFoundInd) +{ + uint32_t uLen = 0; + tpSirProbeRespBeacon parsed_frm; + tCsrScanResult *pScanResult = NULL; + tSirBssDescription *pBssDescr = NULL; + bool fDupBss; + tDot11fBeaconIEs *local_ie = NULL; + tAniSSID tmpSsid; + unsigned long timer = 0; + QDF_STATUS status; + + tpSirMacMgmtHdr macHeader = + (tpSirMacMgmtHdr) pPrefNetworkFoundInd->data; + parsed_frm = + (tpSirProbeRespBeacon) qdf_mem_malloc(sizeof(tSirProbeRespBeacon)); + + if (NULL == parsed_frm) { + sms_log(pMac, LOGE, FL("fail to allocate memory for frame")); + return QDF_STATUS_E_NOMEM; + } + if (pPrefNetworkFoundInd->frameLength <= SIR_MAC_HDR_LEN_3A) { + sms_log(pMac, LOGE, + FL("Incorrect len(%d)"), + pPrefNetworkFoundInd->frameLength); + qdf_mem_free(parsed_frm); + return QDF_STATUS_E_FAILURE; + } + if (sir_convert_probe_frame2_struct(pMac, + &pPrefNetworkFoundInd->data[SIR_MAC_HDR_LEN_3A], + pPrefNetworkFoundInd->frameLength - SIR_MAC_HDR_LEN_3A, + parsed_frm) != eSIR_SUCCESS + || !parsed_frm->ssidPresent) { + sms_log(pMac, LOGE, FL("Parse error ProbeResponse, length=%d"), + pPrefNetworkFoundInd->frameLength); + qdf_mem_free(parsed_frm); + return QDF_STATUS_E_FAILURE; + } + /* 24 byte MAC header and 12 byte to ssid IE */ + if (pPrefNetworkFoundInd->frameLength > + (SIR_MAC_HDR_LEN_3A + SIR_MAC_B_PR_SSID_OFFSET)) { + uLen = pPrefNetworkFoundInd->frameLength - + (SIR_MAC_HDR_LEN_3A + SIR_MAC_B_PR_SSID_OFFSET); + } + pScanResult = qdf_mem_malloc(sizeof(tCsrScanResult) + uLen); + if (NULL == pScanResult) { + sms_log(pMac, LOGE, FL("fail to allocate memory for frame")); + qdf_mem_free(parsed_frm); + return QDF_STATUS_E_NOMEM; + } + pBssDescr = &pScanResult->Result.BssDescriptor; + /* + * Length of BSS desription is without length of length itself and + * length of pointer that holds the next BSS description + */ + pBssDescr->length = (uint16_t)(offsetof(tSirBssDescription, ieFields[0]) + - sizeof(pBssDescr->length) + uLen); + if (parsed_frm->dsParamsPresent) + pBssDescr->channelId = parsed_frm->channelNumber; + else if (parsed_frm->HTInfo.present) + pBssDescr->channelId = parsed_frm->HTInfo.primaryChannel; + else { + /* + * If Probe Responce received in PNO indication does not + * contain DSParam IE or HT Info IE then add dummy channel + * to the received BSS info so that Scan result received as + * a part of PNO is updated to the supplicant. Specially + * applicable in case of AP configured in 11A only mode. + */ + if ((pMac->roam.configParam.bandCapability == eCSR_BAND_ALL) || + (pMac->roam.configParam.bandCapability == eCSR_BAND_24)) + pBssDescr->channelId = 1; + else if (pMac->roam.configParam.bandCapability == eCSR_BAND_5G) + pBssDescr->channelId = 36; + } + if ((pBssDescr->channelId > 0) && (pBssDescr->channelId < 15)) { + int i; + /* 11b or 11g packet */ + /* 11g iff extended Rate IE is present or */ + /* if there is an A rate in suppRate IE */ + for (i = 0; i < parsed_frm->supportedRates.numRates; i++) { + if (sirIsArate(parsed_frm->supportedRates.rate[i] + & 0x7f)) { + pBssDescr->nwType = eSIR_11G_NW_TYPE; + break; + } + } + if (parsed_frm->extendedRatesPresent) + pBssDescr->nwType = eSIR_11G_NW_TYPE; + } else { + /* 11a packet */ + pBssDescr->nwType = eSIR_11A_NW_TYPE; + } + pBssDescr->sinr = 0; + pBssDescr->rssi = -1 * pPrefNetworkFoundInd->rssi; + pBssDescr->beaconInterval = parsed_frm->beaconInterval; + if (!pBssDescr->beaconInterval) { + sms_log(pMac, LOGW, FL("Bcn Interval is Zero , default to 100" + MAC_ADDRESS_STR), MAC_ADDR_ARRAY(pBssDescr->bssId)); + pBssDescr->beaconInterval = 100; + } + pBssDescr->timeStamp[0] = parsed_frm->timeStamp[0]; + pBssDescr->timeStamp[1] = parsed_frm->timeStamp[1]; + pBssDescr->capabilityInfo = *((uint16_t *)&parsed_frm->capabilityInfo); + qdf_mem_copy((uint8_t *) &pBssDescr->bssId, + (uint8_t *) macHeader->bssId, sizeof(tSirMacAddr)); + pBssDescr->received_time = (uint64_t)qdf_mc_timer_get_system_time(); + + /* MobilityDomain */ + pBssDescr->mdie[0] = 0; + pBssDescr->mdie[1] = 0; + pBssDescr->mdie[2] = 0; + pBssDescr->mdiePresent = false; + /* + * If mdie is present in the probe rsp we fill it in the bss description + */ + if (parsed_frm->mdiePresent) { + pBssDescr->mdiePresent = true; + pBssDescr->mdie[0] = parsed_frm->mdie[0]; + pBssDescr->mdie[1] = parsed_frm->mdie[1]; + pBssDescr->mdie[2] = parsed_frm->mdie[2]; + } + sms_log(pMac, LOG1, FL("mdie=%02x%02x%02x"), + (unsigned int)pBssDescr->mdie[0], + (unsigned int)pBssDescr->mdie[1], + (unsigned int)pBssDescr->mdie[2]); + + sms_log(pMac, LOG2, FL("Bssid= "MAC_ADDRESS_STR" chan= %d, rssi = %d"), + MAC_ADDR_ARRAY(pBssDescr->bssId), pBssDescr->channelId, + pBssDescr->rssi); + /* IEs */ + if (uLen) { + qdf_mem_copy(&pBssDescr->ieFields, + pPrefNetworkFoundInd->data + (SIR_MAC_HDR_LEN_3A + + SIR_MAC_B_PR_SSID_OFFSET), uLen); + } + local_ie = (tDot11fBeaconIEs *) (pScanResult->Result.pvIes); + if (NULL == local_ie) { + status = csr_get_parsed_bss_description_ies(pMac, + &pScanResult->Result.BssDescriptor, &local_ie); + + if (!(local_ie || QDF_IS_STATUS_SUCCESS(status))) { + sms_log(pMac, LOGE, FL("Cannot parse IEs")); + csr_free_scan_result_entry(pMac, pScanResult); + qdf_mem_free(parsed_frm); + return QDF_STATUS_E_RESOURCES; + } + } + + fDupBss = csr_remove_dup_bss_description(pMac, + &pScanResult->Result.BssDescriptor, + local_ie, &tmpSsid, &timer); + /* Check whether we have reach out limit */ + if (CSR_SCAN_IS_OVER_BSS_LIMIT(pMac)) { + /* Limit reach */ + sms_log(pMac, LOGE, FL("BSS limit reached")); + /* Free the resources */ + if ((pScanResult->Result.pvIes == NULL) && local_ie) + qdf_mem_free(local_ie); + csr_free_scan_result_entry(pMac, pScanResult); + qdf_mem_free(parsed_frm); + return QDF_STATUS_E_RESOURCES; + } + + if ((SIR_MAC_MGMT_FRAME == macHeader->fc.type) && + (SIR_MAC_MGMT_PROBE_RSP == macHeader->fc.subType)) + pScanResult->Result.BssDescriptor.fProbeRsp = 1; + + /* Add to scan cache */ + csr_scan_add_result(pMac, pScanResult, local_ie, + pPrefNetworkFoundInd->sessionId); + + if ((pScanResult->Result.pvIes == NULL) && local_ie) + qdf_mem_free(local_ie); + qdf_mem_free(parsed_frm); + return QDF_STATUS_SUCCESS; +} +#endif /* FEATURE_WLAN_SCAN_PNO */ + +void csr_init_occupied_channels_list(tpAniSirGlobal pMac, uint8_t sessionId) +{ + tListElem *pEntry = NULL; + tCsrScanResult *pBssDesc = NULL; + tDot11fBeaconIEs *pIes = NULL; + tpCsrNeighborRoamControlInfo pNeighborRoamInfo = + &pMac->roam.neighborRoamInfo[sessionId]; + + if (0 != pNeighborRoamInfo->cfgParams.channelInfo.numOfChannels) { + /* + * Ini file contains neighbor scan channel list, hence NO need + * to build occupied channel list" + */ + sms_log(pMac, LOG1, FL("Ini contains neighbor scan ch list")); + return; + } + + if (!csr_neighbor_roam_is_new_connected_profile(pMac, sessionId)) { + /* + * Do not flush occupied list since current roam profile matches + * previous + */ + sms_log(pMac, LOG2, FL("Current roam profile matches prev")); + return; + } + + /* Empty occupied channels here */ + pMac->scan.occupiedChannels[sessionId].numChannels = 0; + pMac->scan.roam_candidate_count[sessionId] = 0; + + csr_ll_lock(&pMac->scan.scanResultList); + pEntry = csr_ll_peek_head(&pMac->scan.scanResultList, LL_ACCESS_NOLOCK); + while (pEntry) { + pBssDesc = GET_BASE_ADDR(pEntry, tCsrScanResult, Link); + pIes = (tDot11fBeaconIEs *) (pBssDesc->Result.pvIes); + /* At this time, pBssDescription->Result.pvIes may be NULL */ + if (!pIes && !QDF_IS_STATUS_SUCCESS( + csr_get_parsed_bss_description_ies(pMac, + &pBssDesc->Result.BssDescriptor, &pIes))) { + /* Pick next bss entry before continuing */ + pEntry = csr_ll_next(&pMac->scan.scanResultList, pEntry, + LL_ACCESS_NOLOCK); + continue; + } + csr_scan_add_to_occupied_channels(pMac, pBssDesc, sessionId, + &pMac->scan.occupiedChannels[sessionId], pIes, + true); + /* + * Free the memory allocated for pIes in + * csr_get_parsed_bss_description_ies + */ + if ((pBssDesc->Result.pvIes == NULL) && pIes) + qdf_mem_free(pIes); + pEntry = csr_ll_next(&pMac->scan.scanResultList, pEntry, + LL_ACCESS_NOLOCK); + } /* while */ + csr_ll_unlock(&pMac->scan.scanResultList); +} + +QDF_STATUS csr_scan_create_entry_in_scan_cache(tpAniSirGlobal pMac, + uint32_t sessionId, + struct qdf_mac_addr bssid, + uint8_t channel) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tDot11fBeaconIEs *pNewIes = NULL; + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + tSirBssDescription *pNewBssDescriptor = NULL; + uint32_t size = 0; + + if (NULL == pSession) { + status = QDF_STATUS_E_FAILURE; + return status; + } + sms_log(pMac, LOG2, FL("Current bssid::"MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(pSession->pConnectBssDesc->bssId)); + sms_log(pMac, LOG2, FL("My bssid::"MAC_ADDRESS_STR" channel %d"), + MAC_ADDR_ARRAY(bssid.bytes), channel); + + if (!QDF_IS_STATUS_SUCCESS(csr_get_parsed_bss_description_ies( + pMac, pSession->pConnectBssDesc, + &pNewIes))) { + sms_log(pMac, LOGE, FL("Failed to parse IEs")); + status = QDF_STATUS_E_FAILURE; + goto free_mem; + } + size = pSession->pConnectBssDesc->length + + sizeof(pSession->pConnectBssDesc->length); + if (!size) { + sms_log(pMac, LOGE, FL("length of bss descriptor is 0")); + status = QDF_STATUS_E_FAILURE; + goto free_mem; + } + pNewBssDescriptor = qdf_mem_malloc(size); + if (NULL == pNewBssDescriptor) { + sms_log(pMac, LOGE, FL("memory allocation failed")); + status = QDF_STATUS_E_FAILURE; + goto free_mem; + } + qdf_mem_copy(pNewBssDescriptor, pSession->pConnectBssDesc, size); + /* change the BSSID & channel as passed */ + qdf_mem_copy(pNewBssDescriptor->bssId, bssid.bytes, + sizeof(tSirMacAddr)); + pNewBssDescriptor->channelId = channel; + if (NULL == csr_scan_append_bss_description(pMac, pNewBssDescriptor, + pNewIes, sessionId)) { + sms_log(pMac, LOGE, + FL("csr_scan_append_bss_description failed")); + + status = QDF_STATUS_E_FAILURE; + goto free_mem; + } + sms_log(pMac, LOGE, FL("entry successfully added in scan cache")); + +free_mem: + if (pNewIes) { + qdf_mem_free(pNewIes); + } + if (pNewBssDescriptor) { + qdf_mem_free(pNewBssDescriptor); + } + return status; +} + +#ifdef FEATURE_WLAN_ESE +/* Update the TSF with the difference in system time */ +void update_cckmtsf(uint32_t *timeStamp0, uint32_t *timeStamp1, + uint64_t *incr) +{ + uint64_t timeStamp64 = ((uint64_t) *timeStamp1 << 32) | (*timeStamp0); + timeStamp64 = (uint64_t)(timeStamp64 + (*incr)); + *timeStamp0 = (uint32_t) (timeStamp64 & 0xffffffff); + *timeStamp1 = (uint32_t) ((timeStamp64 >> 32) & 0xffffffff); +} +#endif + +/** + * csr_scan_save_roam_offload_ap_to_scan_cache + * This function parses the received beacon/probe response + * from the firmware as part of the roam synch indication. + * The beacon or the probe response is parsed and is also + * saved into the scan cache + * + * @param pMac Pointer to Global Mac + * @param roam_sync_ind_ptr Roam Synch Indication from + * firmware which also contains the beacon/probe + * response + * @return Status + */ +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +QDF_STATUS csr_scan_save_roam_offload_ap_to_scan_cache(tpAniSirGlobal pMac, + roam_offload_synch_ind *roam_sync_ind_ptr, + tpSirBssDescription bss_desc_ptr) +{ + uint32_t length = 0; + bool dup_bss; + tDot11fBeaconIEs *ies_local_ptr = NULL; + tAniSSID tmpSsid; + unsigned long timer = 0; + tCsrScanResult *scan_res_ptr = NULL; + uint8_t session_id = roam_sync_ind_ptr->roamedVdevId; + + length = roam_sync_ind_ptr->beaconProbeRespLength - + (SIR_MAC_HDR_LEN_3A + SIR_MAC_B_PR_SSID_OFFSET); + scan_res_ptr = qdf_mem_malloc(sizeof(tCsrScanResult) + length); + if (scan_res_ptr == NULL) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + " fail to allocate memory for frame"); + return QDF_STATUS_E_NOMEM; + } + + qdf_mem_copy(&scan_res_ptr->Result.BssDescriptor, + bss_desc_ptr, + (sizeof(tSirBssDescription) + length)); + ies_local_ptr = (tDot11fBeaconIEs *)(scan_res_ptr->Result.pvIes); + if (!ies_local_ptr && + (!QDF_IS_STATUS_SUCCESS(csr_get_parsed_bss_description_ies( + pMac, &scan_res_ptr->Result. + BssDescriptor, + &ies_local_ptr)))) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s:Cannot Parse IEs", __func__); + csr_free_scan_result_entry(pMac, scan_res_ptr); + return QDF_STATUS_E_RESOURCES; + } + + dup_bss = csr_remove_dup_bss_description(pMac, + &scan_res_ptr->Result.BssDescriptor, + ies_local_ptr, &tmpSsid, &timer); + if (CSR_SCAN_IS_OVER_BSS_LIMIT(pMac)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s:BSS Limit Exceed", __func__); + if ((scan_res_ptr->Result.pvIes == NULL) && ies_local_ptr) + qdf_mem_free(ies_local_ptr); + + csr_free_scan_result_entry(pMac, scan_res_ptr); + return QDF_STATUS_E_RESOURCES; + } + + sms_log(pMac, LOG1, FL("LFR3:Add BSSID to scan cache" MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(scan_res_ptr->Result.BssDescriptor.bssId)); + csr_scan_add_result(pMac, scan_res_ptr, ies_local_ptr, session_id); + if ((scan_res_ptr->Result.pvIes == NULL) && ies_local_ptr) + qdf_mem_free(ies_local_ptr); + return QDF_STATUS_SUCCESS; +} +#endif + +/** + * csr_get_fst_bssdescr_ptr() - This function returns the pointer to first bss + * description from scan handle + * @result_handle: an object for the result. + * + * Return: first bss descriptor from the scan handle. + */ +tpSirBssDescription csr_get_fst_bssdescr_ptr(tScanResultHandle result_handle) +{ + tListElem *first_element = NULL; + tCsrScanResult *scan_result = NULL; + tScanResultList *bss_list = (tScanResultList *)result_handle; + + if (NULL == bss_list) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Empty bss_list")); + return NULL; + } + if (csr_ll_is_list_empty(&bss_list->List, LL_ACCESS_NOLOCK)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("bss_list->List is empty")); + return NULL; + } + first_element = csr_ll_peek_head(&bss_list->List, LL_ACCESS_NOLOCK); + if (NULL == first_element) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("peer head return NULL")); + return NULL; + } + + scan_result = GET_BASE_ADDR(first_element, tCsrScanResult, Link); + + return &scan_result->Result.BssDescriptor; +} + +/** + * csr_get_bssdescr_from_scan_handle() - This function to extract + * first bss description from scan handle + * @result_handle: an object for the result. + * + * This function is written to extract first bss from scan handle. + * + * Return: first bss descriptor from the scan handle. + */ +tSirBssDescription* +csr_get_bssdescr_from_scan_handle(tScanResultHandle result_handle, + tSirBssDescription *bss_descr) +{ + tListElem *first_element = NULL; + tCsrScanResult *scan_result = NULL; + tScanResultList *bss_list = (tScanResultList *)result_handle; + + if (NULL == bss_list) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Empty bss_list")); + return NULL; + } + if (csr_ll_is_list_empty(&bss_list->List, LL_ACCESS_NOLOCK)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("bss_list->List is empty")); + qdf_mem_free(bss_list); + return NULL; + } + first_element = csr_ll_peek_head(&bss_list->List, LL_ACCESS_NOLOCK); + if (first_element) { + scan_result = GET_BASE_ADDR(first_element, + tCsrScanResult, + Link); + qdf_mem_copy(bss_descr, + &scan_result->Result.BssDescriptor, + sizeof(tSirBssDescription)); + } + return bss_descr; +} + +/** + * scan_active_list_cmd_timeout_handle() - To handle scan active command timeout + * @userData: scan context + * + * This routine is to handle scan active command timeout + * + * Return: None + */ +void csr_scan_active_list_timeout_handle(void *userData) +{ + tSmeCmd *scan_cmd = (tSmeCmd *) userData; + tHalHandle *hal_ctx = cds_get_context(QDF_MODULE_ID_PE); + tpAniSirGlobal mac_ctx; + uint16_t scan_id; + tSirSmeScanAbortReq *msg; + uint16_t msg_len; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + if (scan_cmd == NULL) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Scan Timeout: Scan command is NULL")); + return; + } + if (hal_ctx == NULL) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("HAL Context is NULL")); + return; + } + mac_ctx = PMAC_STRUCT(hal_ctx); + scan_id = scan_cmd->u.scanCmd.scanID; + sms_log(mac_ctx, LOGE, + FL("Scan Timeout:Sending abort to Firmware ID %d session %d "), + scan_id, scan_cmd->sessionId); + msg_len = (uint16_t)(sizeof(tSirSmeScanAbortReq)); + msg = qdf_mem_malloc(msg_len); + if (NULL == msg) { + sms_log(mac_ctx, LOGE, + FL("Failed to alloc memory for SmeScanAbortReq")); + return; + } + msg->type = eWNI_SME_SCAN_ABORT_IND; + msg->msgLen = msg_len; + msg->sessionId = scan_cmd->sessionId; + msg->scan_id = scan_id; + status = cds_send_mb_message_to_mac(msg); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sms_log(mac_ctx, LOGE, + FL(" Failed to post message to LIM")); + } + csr_save_scan_results(mac_ctx, scan_cmd->u.scanCmd.reason, + scan_cmd->sessionId); + scan_cmd->u.scanCmd.abort_scan_indication = eCSR_SCAN_ABORT_DEFAULT; + csr_release_scan_command(mac_ctx, scan_cmd, eCSR_SCAN_FAILURE); + return; +} diff --git a/drivers/staging/qcacld-3.0/core/sme/src/csr/csr_cmd_process.c b/drivers/staging/qcacld-3.0/core/sme/src/csr/csr_cmd_process.c new file mode 100644 index 0000000000000000000000000000000000000000..9951648ac0dc4217cd8ff6b294e223d579cf2cee --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/sme/src/csr/csr_cmd_process.c @@ -0,0 +1,188 @@ +/* + * Copyright (c) 2011-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** ------------------------------------------------------------------------- * + ------------------------------------------------------------------------- * + \file csr_cmd_process.c + + Implementation for processing various commands. + ========================================================================== */ + +#include "ani_global.h" + +#include "csr_inside_api.h" +#include "sme_inside.h" +#include "sms_debug.h" +#include "mac_trace.h" + +/** + * csr_msg_processor() - To process all csr msg + * @mac_ctx: mac context + * @msg_buf: message buffer + * + * This routine will handle all the message for csr to process + * + * Return: QDF_STATUS + */ +QDF_STATUS csr_msg_processor(tpAniSirGlobal mac_ctx, void *msg_buf) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tSirSmeRsp *sme_rsp = (tSirSmeRsp *) msg_buf; +#ifdef FEATURE_WLAN_SCAN_PNO + tSirMbMsg *msg = (tSirMbMsg *) msg_buf; + tCsrRoamSession *session; +#endif + uint8_t session_id = sme_rsp->sessionId; + eCsrRoamState cur_state = mac_ctx->roam.curState[session_id]; + + sms_log(mac_ctx, LOG2, + FL("msg %d[0x%04X] recvd in curstate %s & substate %s id(%d)"), + sme_rsp->messageType, sme_rsp->messageType, + mac_trace_getcsr_roam_state(cur_state), + mac_trace_getcsr_roam_sub_state( + mac_ctx->roam.curSubState[session_id]), + session_id); + +#ifdef FEATURE_WLAN_SCAN_PNO + /* + * PNO scan responses have to be handled irrespective of CSR roam state. + * Check if PNO has been started & only then process the PNO scan result + * Also note that normal scan isn't allowed when PNO scan is in progress + * and so the scan responses reaching here when PNO is started must be + * PNO responses. For normal scan, the PNO started flag will be false + * and it'll be processed as usual based on the current CSR roam state. + */ + session = CSR_GET_SESSION(mac_ctx, session_id); + if (!session) { + sms_log(mac_ctx, LOGE, FL("session %d not found, msgType : %d"), + session_id, msg->type); + return QDF_STATUS_E_FAILURE; + } + + if (eWNI_SME_SCAN_RSP == msg->type) { + status = csr_scanning_state_msg_processor(mac_ctx, msg_buf); + if (QDF_STATUS_SUCCESS != status) + sms_log(mac_ctx, LOGE, + FL("handling PNO scan resp 0x%X CSR state %d"), + sme_rsp->messageType, cur_state); + return status; + } +#endif + + /* Process the message based on the state of the roaming states... */ +#if defined(ANI_RTT_DEBUG) + if (!pAdapter->fRttModeEnabled) { +#endif + switch (cur_state) { + case eCSR_ROAMING_STATE_JOINED: + /* are we in joined state */ + csr_roam_joined_state_msg_processor(mac_ctx, msg_buf); + break; + case eCSR_ROAMING_STATE_JOINING: + /* are we in roaming states */ +#if defined(ANI_EMUL_ASSOC) + emulRoamingStateMsgProcessor(pAdapter, pMBBufHdr); +#endif + csr_roaming_state_msg_processor(mac_ctx, msg_buf); + break; + + default: + /* + * For all other messages, we ignore it + * To work-around an issue where checking for set/remove + * key base on connection state is no longer workable + * due to failure or finding the condition meets both + * SAP and infra/IBSS requirement. + */ + if (eWNI_SME_SETCONTEXT_RSP == sme_rsp->messageType) { + sms_log(mac_ctx, LOGW, + FL("handling msg 0x%X CSR state is %d"), + sme_rsp->messageType, cur_state); + csr_roam_check_for_link_status_change(mac_ctx, + sme_rsp); + } else if (eWNI_SME_GET_RSSI_REQ == + sme_rsp->messageType) { + tAniGetRssiReq *pGetRssiReq = + (tAniGetRssiReq *) msg_buf; + if (NULL == pGetRssiReq->rssiCallback) { + sms_log(mac_ctx, LOGE, + FL("rssiCallback is NULL")); + return status; + } + sms_log(mac_ctx, LOGW, + FL("msg eWNI_SME_GET_RSSI_REQ is not handled by CSR in state %d. calling RSSI callback"), + cur_state); + ((tCsrRssiCallback)(pGetRssiReq->rssiCallback))( + pGetRssiReq->lastRSSI, + pGetRssiReq->staId, + pGetRssiReq->pDevContext); + } else { + sms_log(mac_ctx, LOGE, + FL("Message 0x%04X is not handled by CSR state is %d session Id %d"), + sme_rsp->messageType, cur_state, + session_id); + + if (eWNI_SME_FT_PRE_AUTH_RSP == + sme_rsp->messageType) { + sms_log(mac_ctx, LOGE, + FL("Dequeue eSmeCommandRoam command with reason eCsrPerformPreauth")); + csr_dequeue_roam_command(mac_ctx, + eCsrPerformPreauth); + } else if (eWNI_SME_REASSOC_RSP == + sme_rsp->messageType) { + sms_log(mac_ctx, LOGE, + FL("Dequeue eSmeCommandRoam command with reason eCsrSmeIssuedFTReassoc")); + csr_dequeue_roam_command(mac_ctx, + eCsrSmeIssuedFTReassoc); + } + } + break; + } /* switch */ +#if defined(ANI_RTT_DEBUG) + } +#endif + return status; +} + +bool csr_check_ps_ready(void *pv) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(pv); + + if (pMac->roam.sPendingCommands < 0) { + QDF_ASSERT(pMac->roam.sPendingCommands >= 0); + return 0; + } + return pMac->roam.sPendingCommands == 0; +} + +bool csr_check_ps_offload_ready(void *pv, uint32_t sessionId) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(pv); + + QDF_ASSERT(pMac->roam.sPendingCommands >= 0); + return pMac->roam.sPendingCommands == 0; +} diff --git a/drivers/staging/qcacld-3.0/core/sme/src/csr/csr_host_scan_roam.c b/drivers/staging/qcacld-3.0/core/sme/src/csr/csr_host_scan_roam.c new file mode 100644 index 0000000000000000000000000000000000000000..78c6e47852a9914fd26ba38697983013b6e47a99 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/sme/src/csr/csr_host_scan_roam.c @@ -0,0 +1,821 @@ +/* + * Copyright (c) 2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * 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. + */ + +/** + * DOC: csr_host_scan_roam.c + * + * Host based roaming processing scan results and initiating the roaming + */ + +#include "wma_types.h" +#include "cds_mq.h" +#include "csr_inside_api.h" +#include "sms_debug.h" +#include "sme_qos_internal.h" +#include "sme_inside.h" +#include "host_diag_core_event.h" +#include "host_diag_core_log.h" +#include "csr_api.h" +#include "sme_api.h" +#include "csr_neighbor_roam.h" +#include "mac_trace.h" +#include "cds_concurrency.h" + +/** + * csr_roam_issue_reassociate() - Issue Reassociate + * @pMac: Global MAC Context + * @sessionId: SME Session ID + * @pSirBssDesc: BSS Descriptor + * @pIes: Pointer to the IE's + * @pProfile: Roaming profile + * + * Return: Success or Failure + */ +QDF_STATUS csr_roam_issue_reassociate(tpAniSirGlobal pMac, + uint32_t sessionId, tSirBssDescription *pSirBssDesc, + tDot11fBeaconIEs *pIes, tCsrRoamProfile *pProfile) +{ + csr_roam_state_change(pMac, eCSR_ROAMING_STATE_JOINING, sessionId); + /* Set the roaming substate to 'join attempt'... */ + csr_roam_substate_change(pMac, eCSR_ROAM_SUBSTATE_REASSOC_REQ, + sessionId); + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO, + FL(" calling csr_send_join_req_msg (eWNI_SME_REASSOC_REQ)")); + /* attempt to Join this BSS... */ + return csr_send_join_req_msg(pMac, sessionId, pSirBssDesc, pProfile, + pIes, eWNI_SME_REASSOC_REQ); +} + +/** + * csr_roam_issue_reassociate_cmd() - Issue the reassociate command + * @pMac: Global MAC Context + * @sessionId: SME Session ID + * + * Return: Success or Failure status + */ +QDF_STATUS csr_roam_issue_reassociate_cmd(tpAniSirGlobal pMac, + uint32_t sessionId) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tSmeCmd *pCommand = NULL; + bool fHighPriority = true; + bool fRemoveCmd = false; + tListElem *pEntry; + pEntry = csr_ll_peek_head(&pMac->sme.smeCmdActiveList, LL_ACCESS_LOCK); + if (pEntry) { + pCommand = GET_BASE_ADDR(pEntry, tSmeCmd, Link); + if (!pCommand) { + sms_log(pMac, LOGE, FL(" fail to get command buffer")); + return QDF_STATUS_E_RESOURCES; + } + if (eSmeCommandRoam == pCommand->command) { + if (pCommand->u.roamCmd.roamReason == + eCsrSmeIssuedAssocToSimilarAP) + fRemoveCmd = + csr_ll_remove_entry(&pMac->sme. + smeCmdActiveList, + pEntry, + LL_ACCESS_LOCK); + else + sms_log(pMac, LOGE, + FL(" Unexpected roam cmd present")); + if (fRemoveCmd == false) + pCommand = NULL; + } + } + if (NULL == pCommand) { + sms_log(pMac, LOGE, + FL(" fail to get cmd buf based on prev roam command")); + return QDF_STATUS_E_RESOURCES; + } + do { + /* Change the substate in case it is wait-for-key */ + if (CSR_IS_WAIT_FOR_KEY(pMac, sessionId)) { + csr_roam_stop_wait_for_key_timer(pMac); + csr_roam_substate_change(pMac, eCSR_ROAM_SUBSTATE_NONE, + sessionId); + } + pCommand->command = eSmeCommandRoam; + pCommand->sessionId = (uint8_t) sessionId; + pCommand->u.roamCmd.roamReason = eCsrSmeIssuedFTReassoc; + status = csr_queue_sme_command(pMac, pCommand, fHighPriority); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOGE, + FL("fail to send message status=%d"), status); + csr_release_command_roam(pMac, pCommand); + } + } while (0); + + return status; +} + +/** + * csr_neighbor_roam_process_scan_results() - build roaming candidate list + * + * @mac_ctx: The handle returned by mac_open. + * @sessionid: Session information + * @scan_results_list: List obtained from csr_scan_get_result() + * + * This function applies various candidate checks like LFR, 11r, preauth, ESE + * and builds a roamable AP list. It applies age limit only if no suitable + * recent candidates are found. + * + * Output list is built in mac_ctx->roam.neighborRoamInfo[sessionid]. + * + * Return: void + */ + +void csr_neighbor_roam_process_scan_results(tpAniSirGlobal mac_ctx, + uint8_t sessionid, tScanResultHandle *scan_results_list) +{ + tCsrScanResultInfo *scan_result; + tpCsrNeighborRoamControlInfo n_roam_info = + &mac_ctx->roam.neighborRoamInfo[sessionid]; + tpCsrNeighborRoamBSSInfo bss_info; + uint64_t age = 0; + uint8_t num_candidates = 0; + uint8_t num_dropped = 0; + /* + * first iteration of scan list should consider + * age constraint for candidates + */ + bool age_constraint = true; +#ifdef FEATURE_WLAN_ESE + uint16_t qpresent; + uint16_t qavail; + bool voadmitted; +#endif + /* + * Expecting the scan result already to be in the sorted order based on + * RSSI. Based on the previous state we need to check whether the list + * should be sorted again taking neighbor score into consideration. If + * previous state is CFG_CHAN_LIST_SCAN, there should not be a neighbor + * score associated with any of the BSS. If the previous state is + * REPORT_QUERY, then there will be neighbor score for each of the APs. + * For now, let us take top of the list provided as it is by CSR Scan + * result API. Hence it is assumed that neighbor score and rssi score + * are in the same order. This will be taken care later. + */ + + do { + while (true) { + tSirBssDescription *descr; + + scan_result = csr_scan_result_get_next( + mac_ctx, *scan_results_list); + if (NULL == scan_result) + break; + descr = &scan_result->BssDescriptor; + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + FL("Scan result: BSSID " MAC_ADDRESS_STR + " (Rssi %d, Ch:%d)"), + MAC_ADDR_ARRAY(descr->bssId), + (int)abs(descr->rssi), descr->channelId); + + if (!qdf_mem_cmp(descr->bssId, + n_roam_info->currAPbssid.bytes, + sizeof(tSirMacAddr))) { + /* + * currently associated AP. Do not have this + * in the roamable AP list + */ + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_INFO, + "SKIP-currently associated AP"); + continue; + } + + /* + * Continue if MCC is disabled in INI and if AP + * will create MCC + */ + if (cds_concurrent_open_sessions_running() && + !mac_ctx->roam.configParam.fenableMCCMode) { + uint8_t conc_channel; + + conc_channel = + csr_get_concurrent_operation_channel(mac_ctx); + if (conc_channel && + (conc_channel != + scan_result->BssDescriptor.channelId)) { + sms_log(mac_ctx, LOG1, FL("MCC not supported so Ignore AP on channel %d"), + scan_result->BssDescriptor.channelId); + continue; + } + } + /* + * In case of reassoc requested by upper layer, look + * for exact match of bssid & channel. csr cache might + * have duplicates + */ + if ((n_roam_info->uOsRequestedHandoff) && + ((qdf_mem_cmp(descr->bssId, + n_roam_info->handoffReqInfo.bssid.bytes, + sizeof(tSirMacAddr))) + || (descr->channelId != + n_roam_info->handoffReqInfo.channel))) { + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_INFO, + "SKIP-not a candidate AP for OS requested roam"); + continue; + } + + if ((n_roam_info->is11rAssoc) && + (!csr_neighbor_roam_is_preauth_candidate(mac_ctx, + sessionid, descr->bssId))) { + sms_log(mac_ctx, LOGE, + FL("BSSID in preauth faillist.Ignore")); + continue; + } + +#ifdef FEATURE_WLAN_ESE + if (!csr_roam_is_roam_offload_scan_enabled(mac_ctx) && + (n_roam_info->isESEAssoc) && + !csr_neighbor_roam_is_preauth_candidate(mac_ctx, + sessionid, descr->bssId)) { + sms_log(mac_ctx, LOGE, + FL("BSSID in preauth faillist.Ignore")); + continue; + } + + qpresent = descr->QBSSLoad_present; + qavail = descr->QBSSLoad_avail; + voadmitted = n_roam_info->isVOAdmitted; + if (voadmitted) + sms_log(mac_ctx, LOG1, + FL("New QBSS=%s,BWavail=0x%x,req=0x%x"), + ((qpresent) ? "yes" : "no"), qavail, + n_roam_info->MinQBssLoadRequired); + if (voadmitted && qpresent && + (qavail < n_roam_info->MinQBssLoadRequired)) { + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_INFO, + "BSSID:" MAC_ADDRESS_STR "has no BW", + MAC_ADDR_ARRAY(descr->bssId)); + continue; + } + if (voadmitted && !qpresent) { + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_INFO, + "BSSID:" MAC_ADDRESS_STR "no LOAD IE", + MAC_ADDR_ARRAY(descr->bssId)); + continue; + } +#endif /* FEATURE_WLAN_ESE */ + + /* + * If we are supporting legacy roaming, and + * if the candidate is on the "pre-auth failed" list, + * ignore it. + */ + if (csr_roam_is_fast_roam_enabled(mac_ctx, sessionid) && + !csr_neighbor_roam_is_preauth_candidate(mac_ctx, + sessionid, descr->bssId)) { + sms_log(mac_ctx, LOGE, + FL("BSSID in preauth faillist Ignore")); + continue; + } + + /* check the age of the AP */ + age = (uint64_t) qdf_mc_timer_get_system_time() - + descr->received_time; + if (age_constraint == true && + age > ROAM_AP_AGE_LIMIT_MS) { + num_dropped++; + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_WARN, + FL("Old AP (probe rsp/beacon) skipped.") + ); + continue; + } + + /* Finished all checks, now add it to candidate list */ + bss_info = + qdf_mem_malloc(sizeof(tCsrNeighborRoamBSSInfo)); + if (NULL == bss_info) { + sms_log(mac_ctx, LOGE, + FL("Memory alloc fail. Ignored cnd.")); + continue; + } + bss_info->pBssDescription = + qdf_mem_malloc(descr->length + + sizeof(descr->length)); + if (bss_info->pBssDescription != NULL) { + qdf_mem_copy(bss_info->pBssDescription, descr, + descr->length + sizeof(descr->length)); + } else { + sms_log(mac_ctx, LOGE, + FL("Mem alloc failed. Ignore cand.")); + qdf_mem_free(bss_info); + continue; + } + /* + * Assign some preference value for now. Need to + * calculate theactual score based on RSSI and neighbor + * AP score + */ + bss_info->apPreferenceVal = 10; + num_candidates++; + csr_ll_insert_tail(&n_roam_info->roamableAPList, + &bss_info->List, LL_ACCESS_LOCK); + } /* end of while (csr_scan_result_get_next) */ + + /* if some candidates were found, then no need to repeat */ + if (num_candidates) + break; + /* + * if age_constraint is already false, we have done two + * iterations and no candidate were found + */ + if (age_constraint == false) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: No roam able candidates found", + __func__); + break; + } + /* + * if all candidates were dropped rescan the scan + * list but this time without age constraint. + */ + age_constraint = false; + /* if no candidates were dropped no need to repeat */ + } while (num_dropped); + + /* + * Now we have all the scan results in our local list. Good time to free + * up the the list we got as a part of csrGetScanResult + */ + csr_scan_result_purge(mac_ctx, *scan_results_list); +} + +/** + * csr_neighbor_roam_trigger_handoff() - Start roaming + * @mac_ctx: Global MAC Context + * @session_id: SME Session ID + * + * Return: None + */ +void csr_neighbor_roam_trigger_handoff(tpAniSirGlobal mac_ctx, + uint8_t session_id) +{ + if (csr_roam_is_fast_roam_enabled(mac_ctx, session_id)) + csr_neighbor_roam_issue_preauth_req(mac_ctx, session_id); + else + sms_log(mac_ctx, LOGE, FL("Roaming is disabled")); +} + +/** + * csr_neighbor_roam_process_scan_complete() - Post process the scan results + * @pMac: Global MAC Context + * @sessionId: SME Session ID + * + * Return: Success or Failure + */ +QDF_STATUS csr_neighbor_roam_process_scan_complete(tpAniSirGlobal pMac, + uint8_t sessionId) +{ + tpCsrNeighborRoamControlInfo pNeighborRoamInfo = + &pMac->roam.neighborRoamInfo[sessionId]; + tCsrScanResultFilter scanFilter; + tScanResultHandle scanResult; + uint32_t tempVal = 0; + QDF_STATUS hstatus; + + hstatus = csr_neighbor_roam_prepare_scan_profile_filter(pMac, + &scanFilter, + sessionId); + sms_log(pMac, LOGW, + FL("Prepare scan to find neighbor AP filter status = %d"), + hstatus); + if (QDF_STATUS_SUCCESS != hstatus) { + sms_log(pMac, LOGE, + FL("Scan Filter prep fail for Assoc %d Bail out"), + tempVal); + return QDF_STATUS_E_FAILURE; + } + hstatus = csr_scan_get_result(pMac, &scanFilter, &scanResult); + if (hstatus != QDF_STATUS_SUCCESS) { + sms_log(pMac, LOGE, + FL("Get Scan Result status code %d"), + hstatus); + } + /* Process the scan results and update roamable AP list */ + csr_neighbor_roam_process_scan_results(pMac, sessionId, &scanResult); + + /* Free the scan filter */ + csr_free_scan_filter(pMac, &scanFilter); + + tempVal = csr_ll_count(&pNeighborRoamInfo->roamableAPList); + + if (tempVal) { + csr_neighbor_roam_trigger_handoff(pMac, sessionId); + return QDF_STATUS_SUCCESS; + } + + if (csr_roam_is_roam_offload_scan_enabled(pMac)) { + if (pNeighborRoamInfo->uOsRequestedHandoff) { + csr_roam_offload_scan(pMac, sessionId, + ROAM_SCAN_OFFLOAD_START, + REASON_NO_CAND_FOUND_OR_NOT_ROAMING_NOW); + pNeighborRoamInfo->uOsRequestedHandoff = 0; + } else { + /* There is no candidate or We are not roaming Now. + * Inform the FW to restart Roam Offload Scan */ + csr_roam_offload_scan(pMac, sessionId, + ROAM_SCAN_OFFLOAD_RESTART, + REASON_NO_CAND_FOUND_OR_NOT_ROAMING_NOW); + } + csr_neighbor_roam_state_transition(pMac, + eCSR_NEIGHBOR_ROAM_STATE_CONNECTED, sessionId); + } + return QDF_STATUS_SUCCESS; + +} + +/** + * csr_neighbor_roam_candidate_found_ind_hdlr() + * + * @mac_ctx: Pointer to Global MAC structure + * @msg_buf: pointer to msg buff + * + * This function is called by CSR as soon as TL posts the candidate + * found indication to SME via MC thread + * + * Return: QDF_STATUS_SUCCESS on success, corresponding error code otherwise + */ +QDF_STATUS csr_neighbor_roam_candidate_found_ind_hdlr(tpAniSirGlobal pMac, + void *pMsg) +{ + tSirSmeCandidateFoundInd *pSirSmeCandidateFoundInd = + (tSirSmeCandidateFoundInd *) pMsg; + uint32_t sessionId = pSirSmeCandidateFoundInd->sessionId; + tpCsrNeighborRoamControlInfo pNeighborRoamInfo = + &pMac->roam.neighborRoamInfo[sessionId]; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + sms_log(pMac, LOG1, FL("Received indication from firmware")); + + /* we must be in connected state, if not ignore it */ + if ((eCSR_NEIGHBOR_ROAM_STATE_CONNECTED != + pNeighborRoamInfo->neighborRoamState) + || (pNeighborRoamInfo->uOsRequestedHandoff)) { + sms_log(pMac, LOGE, + FL("Recvd in NotCONNECTED or OsReqHandoff. Ignore")); + status = QDF_STATUS_E_FAILURE; + } else { + /* Firmware indicated that roaming candidate is found. Beacons + * are already in the SME scan results table. + * Process the results for choosing best roaming candidate. + */ + csr_save_scan_results(pMac, eCsrScanCandidateFound, + sessionId); + /* Future enhancements: + * If firmware tags candidate beacons, give them preference + * for roaming. + * Age out older entries so that new candidate beacons + * will get preference. + */ + status = csr_neighbor_roam_process_scan_complete(pMac, + sessionId); + if (QDF_STATUS_SUCCESS != status) { + sms_log(pMac, LOGE, + FL("scan process complete failed, status %d"), + status); + return QDF_STATUS_E_FAILURE; + } + } + + return status; +} + +/** + * csr_neighbor_roam_free_roamable_bss_list() - Frees roamable APs list + * @mac_ctx: The handle returned by mac_open. + * @llist: Neighbor Roam BSS List to be emptied + * + * Empties and frees all the nodes in the roamable AP list + * + * Return: none + */ +void csr_neighbor_roam_free_roamable_bss_list(tpAniSirGlobal mac_ctx, + tDblLinkList *llist) +{ + tpCsrNeighborRoamBSSInfo result = NULL; + + sms_log(mac_ctx, LOG2, + FL("Emptying the BSS list. Current count = %d"), + csr_ll_count(llist)); + + /* + * Pick up the head, remove and free the node till + * the list becomes empty + */ + while ((result = csr_neighbor_roam_next_roamable_ap(mac_ctx, llist, + NULL)) != NULL) { + csr_neighbor_roam_remove_roamable_ap_list_entry(mac_ctx, + llist, result); + csr_neighbor_roam_free_neighbor_roam_bss_node(mac_ctx, result); + } + return; +} + +/** + * csr_neighbor_roam_remove_roamable_ap_list_entry() + * + * @mac_ctx: Pointer to Global MAC structure + * @pList: The list from which the entry should be removed + * @pNeighborEntry: Neighbor Roam BSS Node to be removed + * + * This function removes a given entry from the given list + * + * Return: true if successfully removed, else false + */ +bool csr_neighbor_roam_remove_roamable_ap_list_entry(tpAniSirGlobal pMac, + tDblLinkList *pList, + tpCsrNeighborRoamBSSInfo + pNeighborEntry) +{ + if (pList) { + return csr_ll_remove_entry(pList, &pNeighborEntry->List, + LL_ACCESS_LOCK); + } + + sms_log(pMac, LOGE, + FL("Remove neigh BSS node from fail list. Current count = %d"), + csr_ll_count(pList)); + + return false; +} + +/** + * csr_neighbor_roam_next_roamable_ap() - Get next AP from roamable AP list + * @mac_ctx - The handle returned by mac_open. + * @plist - The list from which the entry should be returned + * @neighbor_entry - Neighbor Roam BSS Node whose next entry should be returned + * + * Gets the entry next to passed entry. If NULL is passed, return the entry + * in the head of the list + * + * Return: Neighbor Roam BSS Node to be returned + */ +tpCsrNeighborRoamBSSInfo csr_neighbor_roam_next_roamable_ap( + tpAniSirGlobal mac_ctx, tDblLinkList *llist, + tpCsrNeighborRoamBSSInfo neighbor_entry) +{ + tListElem *entry = NULL; + tpCsrNeighborRoamBSSInfo result = NULL; + + if (llist) { + if (NULL == neighbor_entry) + entry = csr_ll_peek_head(llist, LL_ACCESS_LOCK); + else + entry = csr_ll_next(llist, &neighbor_entry->List, + LL_ACCESS_LOCK); + if (entry) + result = GET_BASE_ADDR(entry, tCsrNeighborRoamBSSInfo, + List); + } + + return result; +} + + +/** + * csr_neighbor_roam_request_handoff() - Handoff to a different AP + * @mac_ctx: Pointer to Global MAC structure + * @session_id: Session ID + * + * This function triggers actual switching from one AP to the new AP. + * It issues disassociate with reason code as Handoff and CSR as a part of + * handling disassoc rsp, issues reassociate to the new AP + * + * Return: none + */ +void csr_neighbor_roam_request_handoff(tpAniSirGlobal mac_ctx, + uint8_t session_id) +{ + tCsrRoamInfo roam_info; + tpCsrNeighborRoamControlInfo neighbor_roam_info = + &mac_ctx->roam.neighborRoamInfo[session_id]; + tCsrNeighborRoamBSSInfo handoff_node; + uint32_t roamid = 0; + QDF_STATUS status; + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, "%s session_id=%d", + __func__, session_id); + + if (neighbor_roam_info->neighborRoamState != + eCSR_NEIGHBOR_ROAM_STATE_PREAUTH_DONE) { + sms_log(mac_ctx, LOGE, + FL("Roam requested when Neighbor roam is in %s state"), + mac_trace_get_neighbour_roam_state( + neighbor_roam_info->neighborRoamState)); + return; + } + + if (false == csr_neighbor_roam_get_handoff_ap_info(mac_ctx, + &handoff_node, session_id)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("failed to obtain handoff AP")); + return; + } + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + FL("HANDOFF CANDIDATE BSSID "MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(handoff_node.pBssDescription->bssId)); + + qdf_mem_zero(&roam_info, sizeof(tCsrRoamInfo)); + csr_roam_call_callback(mac_ctx, session_id, &roam_info, roamid, + eCSR_ROAM_FT_START, eSIR_SME_SUCCESS); + + qdf_mem_zero(&roam_info, sizeof(tCsrRoamInfo)); + csr_neighbor_roam_state_transition(mac_ctx, + eCSR_NEIGHBOR_ROAM_STATE_REASSOCIATING, session_id); + + csr_neighbor_roam_send_lfr_metric_event(mac_ctx, session_id, + handoff_node.pBssDescription->bssId, + eCSR_ROAM_HANDOVER_SUCCESS); + /* Free the profile.. Just to make sure we dont leak memory here */ + csr_release_profile(mac_ctx, + &neighbor_roam_info->csrNeighborRoamProfile); + /* + * Create the Handoff AP profile. Copy the currently connected profile + * and update only the BSSID and channel number. This should happen + * before issuing disconnect + */ + status = csr_roam_copy_connected_profile(mac_ctx, session_id, + &neighbor_roam_info->csrNeighborRoamProfile); + if (QDF_STATUS_SUCCESS != status) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("csr_roam_copy_connected_profile failed %d"), + status); + return; + } + qdf_mem_copy(neighbor_roam_info->csrNeighborRoamProfile.BSSIDs.bssid, + handoff_node.pBssDescription->bssId, sizeof(tSirMacAddr)); + neighbor_roam_info->csrNeighborRoamProfile.ChannelInfo.ChannelList[0] = + handoff_node.pBssDescription->channelId; + + sms_log(mac_ctx, LOGW, + " csr_roamHandoffRequested: disassociating with current AP"); + + if (!QDF_IS_STATUS_SUCCESS + (csr_roam_issue_disassociate_cmd + (mac_ctx, session_id, + eCSR_DISCONNECT_REASON_HANDOFF))) { + sms_log(mac_ctx, LOGW, + "csr_roamHandoffRequested: fail to issue disassoc"); + return; + } + /* notify HDD for handoff, providing the BSSID too */ + roam_info.reasonCode = eCsrRoamReasonBetterAP; + + qdf_mem_copy(roam_info.bssid.bytes, + handoff_node.pBssDescription->bssId, + sizeof(struct qdf_mac_addr)); + + csr_roam_call_callback(mac_ctx, session_id, &roam_info, 0, + eCSR_ROAM_ROAMING_START, eCSR_ROAM_RESULT_NONE); + + return; +} + + +/** + * csr_neighbor_roam_get_handoff_ap_info - Identifies the best AP for roaming + * + * @pMac: mac context + * @session_id: Session Id + * @hand_off_node: AP node that is the handoff candidate returned + * + * This function returns the best possible AP for handoff. For 11R case, it + * returns the 1st entry from pre-auth done list. For non-11r case, it returns + * the 1st entry from roamable AP list + * + * Return: true if able find handoff AP, false otherwise + */ + +bool csr_neighbor_roam_get_handoff_ap_info(tpAniSirGlobal pMac, + tpCsrNeighborRoamBSSInfo hand_off_node, + uint8_t session_id) +{ + tpCsrNeighborRoamControlInfo ngbr_roam_info = + &pMac->roam.neighborRoamInfo[session_id]; + tpCsrNeighborRoamBSSInfo bss_node = NULL; + + if (NULL == hand_off_node) { + QDF_ASSERT(NULL != hand_off_node); + return false; + } + if (ngbr_roam_info->is11rAssoc) { + /* Always the BSS info in the head is the handoff candidate */ + bss_node = csr_neighbor_roam_next_roamable_ap( + pMac, + &ngbr_roam_info->FTRoamInfo.preAuthDoneList, + NULL); + sms_log(pMac, LOG1, + FL("Number of Handoff candidates = %d"), + csr_ll_count(& + ngbr_roam_info->FTRoamInfo.preAuthDoneList)); + } else +#ifdef FEATURE_WLAN_ESE + if (ngbr_roam_info->isESEAssoc) { + /* Always the BSS info in the head is the handoff candidate */ + bss_node = + csr_neighbor_roam_next_roamable_ap(pMac, + &ngbr_roam_info->FTRoamInfo.preAuthDoneList, + NULL); + sms_log(pMac, LOG1, + FL("Number of Handoff candidates = %d"), + csr_ll_count(&ngbr_roam_info->FTRoamInfo. + preAuthDoneList)); + } else +#endif + if (csr_roam_is_fast_roam_enabled(pMac, session_id)) { + /* Always the BSS info in the head is the handoff candidate */ + bss_node = + csr_neighbor_roam_next_roamable_ap(pMac, + &ngbr_roam_info->FTRoamInfo.preAuthDoneList, + NULL); + sms_log(pMac, LOG1, + FL("Number of Handoff candidates = %d"), + csr_ll_count( + &ngbr_roam_info->FTRoamInfo.preAuthDoneList)); + } else { + bss_node = + csr_neighbor_roam_next_roamable_ap(pMac, + &ngbr_roam_info->roamableAPList, + NULL); + sms_log(pMac, LOG1, + FL("Number of Handoff candidates = %d"), + csr_ll_count(&ngbr_roam_info->roamableAPList)); + } + if (NULL == bss_node) + return false; + qdf_mem_copy(hand_off_node, bss_node, sizeof(tCsrNeighborRoamBSSInfo)); + return true; +} + +/** + * csr_neighbor_roam_is_handoff_in_progress() + * + * @mac_ctx: Pointer to Global MAC structure + * @session_id: Session ID + * + * This function returns whether handoff is in progress or not based on + * the current neighbor roam state + * + * Return: true if reassoc in progress, false otherwise + */ +bool csr_neighbor_roam_is_handoff_in_progress(tpAniSirGlobal pMac, + uint8_t sessionId) +{ + if (eCSR_NEIGHBOR_ROAM_STATE_REASSOCIATING == + pMac->roam.neighborRoamInfo[sessionId].neighborRoamState) + return true; + + return false; +} + +/** + * csr_neighbor_roam_free_neighbor_roam_bss_node() + * + * @mac_ctx: Pointer to Global MAC structure + * @neighborRoamBSSNode: Neighbor Roam BSS Node to be freed + * + * This function frees all the internal pointers CSR NeighborRoam BSS Info + * and also frees the node itself + * + * Return: None + */ +void csr_neighbor_roam_free_neighbor_roam_bss_node(tpAniSirGlobal pMac, + tpCsrNeighborRoamBSSInfo + neighborRoamBSSNode) +{ + if (neighborRoamBSSNode) { + if (neighborRoamBSSNode->pBssDescription) { + qdf_mem_free(neighborRoamBSSNode->pBssDescription); + neighborRoamBSSNode->pBssDescription = NULL; + } + qdf_mem_free(neighborRoamBSSNode); + neighborRoamBSSNode = NULL; + } + + return; +} diff --git a/drivers/staging/qcacld-3.0/core/sme/src/csr/csr_inside_api.h b/drivers/staging/qcacld-3.0/core/sme/src/csr/csr_inside_api.h new file mode 100644 index 0000000000000000000000000000000000000000..534cd31e6117d6639c3f6bfd5f8b2cc0c8cd4a6b --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/sme/src/csr/csr_inside_api.h @@ -0,0 +1,1129 @@ +/* + * Copyright (c) 2011-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** ------------------------------------------------------------------------- * + ------------------------------------------------------------------------- * + + \file csr_inside_api.h + + Define interface only used by CSR. + ========================================================================== */ +#ifndef CSR_INSIDE_API_H__ +#define CSR_INSIDE_API_H__ + +#include "csr_support.h" +#include "sme_inside.h" +#include "cds_reg_service.h" + +#define CSR_PASSIVE_MAX_CHANNEL_TIME 110 +#define CSR_PASSIVE_MIN_CHANNEL_TIME 60 + +#define CSR_ACTIVE_MAX_CHANNEL_TIME 40 +#define CSR_ACTIVE_MIN_CHANNEL_TIME 20 + +#ifdef WLAN_AP_STA_CONCURRENCY +#define CSR_PASSIVE_MAX_CHANNEL_TIME_CONC 110 +#define CSR_PASSIVE_MIN_CHANNEL_TIME_CONC 60 + +#define CSR_ACTIVE_MAX_CHANNEL_TIME_CONC 27 +#define CSR_ACTIVE_MIN_CHANNEL_TIME_CONC 20 + +#define CSR_REST_TIME_CONC 100 +#define CSR_MIN_REST_TIME_CONC 50 +#define CSR_IDLE_TIME_CONC 25 + +#define CSR_NUM_STA_CHAN_COMBINED_CONC 3 +#define CSR_NUM_P2P_CHAN_COMBINED_CONC 1 +#endif + +#define CSR_MAX_NUM_SUPPORTED_CHANNELS 55 + +#define CSR_MAX_2_4_GHZ_SUPPORTED_CHANNELS 14 + +#define CSR_MAX_BSS_SUPPORT 512 +#define SYSTEM_TIME_MSEC_TO_USEC 1000 +#define SYSTEM_TIME_SEC_TO_MSEC 1000 +#define SYSTEM_TIME_NSEC_TO_USEC 1000 + +/* This number minus 1 means the number of times a channel is scanned before a BSS is remvoed from */ +/* cache scan result */ +#define CSR_AGING_COUNT 3 +#define CSR_SCAN_GET_RESULT_INTERVAL (5 * QDF_MC_TIMER_TO_SEC_UNIT) /* 5 seconds */ +#define CSR_MIC_ERROR_TIMEOUT (60 * QDF_MC_TIMER_TO_SEC_UNIT) /* 60 seconds */ +#define CSR_TKIP_COUNTER_MEASURE_TIMEOUT (60 * QDF_MC_TIMER_TO_SEC_UNIT) /* 60 seconds */ + +/* the following defines are NOT used by palTimer */ +#define CSR_JOIN_FAILURE_TIMEOUT_DEFAULT (3000) +#define CSR_JOIN_FAILURE_TIMEOUT_MIN (1000) /* minimal value */ +/* These are going against the signed RSSI (int8_t) so it is between -+127 */ +#define CSR_BEST_RSSI_VALUE (-30) /* RSSI >= this is in CAT4 */ +#define CSR_DEFAULT_RSSI_DB_GAP 30 /* every 30 dbm for one category */ +#define CSR_BSS_CAP_VALUE_NONE 0 /* not much value */ +#define CSR_BSS_CAP_VALUE_HT 1 +#define CSR_BSS_CAP_VALUE_VHT 2 +#define CSR_BSS_CAP_VALUE_WMM 1 +#define CSR_BSS_CAP_VALUE_UAPSD 1 +#define CSR_BSS_CAP_VALUE_5GHZ 2 + +#define CSR_ROAMING_DFS_CHANNEL_DISABLED (0) +#define CSR_ROAMING_DFS_CHANNEL_ENABLED_NORMAL (1) +#define CSR_ROAMING_DFS_CHANNEL_ENABLED_ACTIVE (2) + +#define CSR_ACTIVE_SCAN_LIST_CMD_TIMEOUT (1000*30) + +/* *************************************************************************** + * The MAX BSSID Count should be lower than the command timeout value and it + * can be of a fraction of 3/4 of the total command timeout value. + * ***************************************************************************/ +#define CSR_MAX_BSSID_COUNT ((SME_ACTIVE_LIST_CMD_TIMEOUT_VALUE/4000) * 3) +#define CSR_CUSTOM_CONC_GO_BI 100 + +#define RSSI_THRESHOLD_5GHZ -70 +#define BEST_CANDIDATE_RSSI_WEIGHT 50 +#define MIN_RSSI (-100) +#define MAX_RSSI 0 +#define BEST_CANDIDATE_AP_COUNT_WEIGHT 50 +#define BEST_CANDIDATE_MAX_COUNT 30 +#define BEST_CANDIDATE_MIN_COUNT 0 +#define ROAM_MAX_CHANNEL_WEIGHT 100 +#define DEFAULT_CHANNEL_UTILIZATION 50 +#define MAX_CHANNEL_UTILIZATION 100 + +#define RSSI_WEIGHTAGE 25 +#define HT_CAPABILITY_WEIGHTAGE 7 +#define VHT_CAP_WEIGHTAGE 5 +#define BEAMFORMING_CAP_WEIGHTAGE 2 +#define CHAN_WIDTH_WEIGHTAGE 10 +#define CHAN_BAND_WEIGHTAGE 5 +#define WMM_WEIGHTAGE 0 +#define CCA_WEIGHTAGE 8 +#define OTHER_AP_WEIGHT 28 +#define PCL_WEIGHT 10 + +#define MAX_AP_LOAD 255 +#define BEST_CANDIDATE_EXCELLENT_RSSI -40 +#define BEST_CANDIDATE_GOOD_RSSI -55 +#define BEST_CANDIDATE_POOR_RSSI -65 +#define BAD_RSSI -80 +#define BEST_CANDIDATE_EXCELLENT_RSSI_WEIGHT 100 +#define BEST_CANDIDATE_GOOD_RSSI_WEIGHT 80 +#define BEST_CANDIDATE_BAD_RSSI_WEIGHT 60 +#define BEST_CANDIDATE_MAX_WEIGHT 100 +#define BEST_CANDIDATE_80MHZ 100 +#define BEST_CANDIDATE_40MHZ 70 +#define BEST_CANDIDATE_20MHZ 30 +#define BEST_CANDIDATE_PENALTY (3/10) +#define BEST_CANDIDATE_MAX_BSS_SCORE 10000 + + +typedef enum { + eCsrNextScanNothing, + eCsrNextLostLinkScan1Success, + eCsrNextLostLinkScan1Failed, + eCsrNextLostLinkScan2Success, + eCsrNextLostLinkScan2Failed, + eCsrNextLostLinkScan3Success, + eCsrNexteScanForSsidSuccess, + eCsrNextLostLinkScan3Failed, + eCsrNext11dScan1Failure, + eCsrNext11dScan1Success, + eCsrNext11dScan2Failure, + eCsrNext11dScan2Success, + eCsrNext11dScanComplete, + eCsrNexteScanForSsidFailure, + eCsrNextCheckAllowConc, + +} eCsrScanCompleteNextCommand; + +typedef enum { + eCsrJoinSuccess, + eCsrJoinFailure, + eCsrReassocSuccess, + eCsrReassocFailure, + eCsrNothingToJoin, + eCsrStartBssSuccess, + eCsrStartBssFailure, + eCsrSilentlyStopRoaming, + eCsrSilentlyStopRoamingSaveState, + eCsrJoinFailureDueToConcurrency, + eCsrStopBssSuccess, + eCsrStopBssFailure, +} eCsrRoamCompleteResult; + +typedef struct tagScanReqParam { + uint8_t bReturnAfter1stMatch; + uint8_t fUniqueResult; + uint8_t freshScan; + uint8_t hiddenSsid; + uint8_t reserved; +} tScanReqParam; + +typedef struct tagCsrScanResult { + tListElem Link; + int32_t AgingCount; /* This BSS is removed when it reaches 0 or less */ + uint32_t preferValue; /* The bigger the number, the better the BSS. This value override capValue */ + uint32_t capValue; /* The biggger the better. This value is in use only if we have equal preferValue */ + eCsrEncryptionType ucEncryptionType; /* Preferred Encryption type that matched with profile. */ + eCsrEncryptionType mcEncryptionType; + eCsrAuthType authType; /* Preferred auth type that matched with the profile. */ + int bss_score; + + tCsrScanResultInfo Result; + /* + * WARNING - Do not add any element here + * This member Result must be the last in the structure because the end + * of tSirBssDescription (inside) is an array with nonknown size at + * this time. + */ +} tCsrScanResult; + +typedef struct { + tDblLinkList List; + tListElem *pCurEntry; +} tScanResultList; + +/** + * csr_scan_for_ssid_context() - Callback context for SSID scan + * + * @mac_ctx: mac context + * @session_id: scan session id + * @roam_id: roam Id + */ +struct csr_scan_for_ssid_context { + tpAniSirGlobal mac_ctx; + uint32_t session_id; + uint32_t roam_id; +}; + +#define CSR_IS_ROAM_REASON(pCmd, reason) ((reason) == (pCmd)->roamCmd.roamReason) +#define CSR_IS_BETTER_PREFER_VALUE(v1, v2) ((v1) > (v2)) +#define CSR_IS_EQUAL_PREFER_VALUE(v1, v2) ((v1) == (v2)) +#define CSR_IS_BETTER_CAP_VALUE(v1, v2) ((v1) > (v2)) +#define CSR_IS_EQUAL_CAP_VALUE(v1, v2) ((v1) == (v2)) +#define CSR_IS_BETTER_RSSI(v1, v2) ((v1) > (v2)) +#define CSR_IS_ENC_TYPE_STATIC(encType) ((eCSR_ENCRYPT_TYPE_NONE == (encType)) || \ + (eCSR_ENCRYPT_TYPE_WEP40_STATICKEY == (encType)) || \ + (eCSR_ENCRYPT_TYPE_WEP104_STATICKEY == (encType))) +#define CSR_IS_WAIT_FOR_KEY(pMac, sessionId) \ + (CSR_IS_ROAM_JOINED(pMac, sessionId) && \ + CSR_IS_ROAM_SUBSTATE_WAITFORKEY(pMac, sessionId)) +/* WIFI has a test case for not using HT rates with TKIP as encryption */ +/* We may need to add WEP but for now, TKIP only. */ + +#define CSR_IS_11n_ALLOWED(encType) ((eCSR_ENCRYPT_TYPE_TKIP != (encType)) && \ + (eCSR_ENCRYPT_TYPE_WEP40_STATICKEY != (encType)) && \ + (eCSR_ENCRYPT_TYPE_WEP104_STATICKEY != (encType)) && \ + (eCSR_ENCRYPT_TYPE_WEP40 != (encType)) && \ + (eCSR_ENCRYPT_TYPE_WEP104 != (encType))) + +#define CSR_IS_DISCONNECT_COMMAND(pCommand) ((eSmeCommandRoam == (pCommand)->command) && \ + ((eCsrForcedDisassoc == (pCommand)->u.roamCmd.roamReason) || \ + (eCsrForcedDeauth == (pCommand)->u.roamCmd.roamReason) || \ + (eCsrSmeIssuedDisassocForHandoff == \ + (pCommand)->u.roamCmd.roamReason) || \ + (eCsrForcedDisassocMICFailure == \ + (pCommand)->u.roamCmd.roamReason))) + +eCsrRoamState csr_roam_state_change(tpAniSirGlobal pMac, + eCsrRoamState NewRoamState, uint8_t sessionId); +QDF_STATUS csr_scanning_state_msg_processor(tpAniSirGlobal pMac, void *pMsgBuf); +void csr_roaming_state_msg_processor(tpAniSirGlobal pMac, void *pMsgBuf); +void csr_roam_joined_state_msg_processor(tpAniSirGlobal pMac, void *pMsgBuf); +bool csr_scan_complete(tpAniSirGlobal pMac, tSirSmeScanRsp *pScanRsp); +void csr_release_command_roam(tpAniSirGlobal pMac, tSmeCmd *pCommand); +void csr_release_command_scan(tpAniSirGlobal pMac, tSmeCmd *pCommand); +void csr_release_command_wm_status_change(tpAniSirGlobal pMac, tSmeCmd *pCommand); +extern void csr_release_roc_req_cmd(tpAniSirGlobal mac_ctx); + +bool csr_is_duplicate_bss_description(tpAniSirGlobal pMac, + tSirBssDescription *pSirBssDesc1, + tSirBssDescription *pSirBssDesc2, + tDot11fBeaconIEs *pIes2); +QDF_STATUS csr_roam_save_connected_bss_desc(tpAniSirGlobal pMac, uint32_t sessionId, + tSirBssDescription *pBssDesc); +bool csr_is_network_type_equal(tSirBssDescription *pSirBssDesc1, + tSirBssDescription *pSirBssDesc2); +QDF_STATUS csr_scan_sme_scan_response(tpAniSirGlobal pMac, void *pMsgBuf); +/* + Prepare a filter base on a profile for parsing the scan results. + Upon successful return, caller MUST call csr_free_scan_filter on + pScanFilter when it is done with the filter. + */ +QDF_STATUS csr_roam_prepare_filter_from_profile(tpAniSirGlobal pMac, + tCsrRoamProfile *pProfile, + tCsrScanResultFilter *pScanFilter); +QDF_STATUS csr_roam_copy_profile(tpAniSirGlobal pMac, + tCsrRoamProfile *pDstProfile, + tCsrRoamProfile *pSrcProfile); +QDF_STATUS csr_roam_start(tpAniSirGlobal pMac); +void csr_roam_stop(tpAniSirGlobal pMac, uint32_t sessionId); +void csr_roam_startMICFailureTimer(tpAniSirGlobal pMac); +void csr_roam_stopMICFailureTimer(tpAniSirGlobal pMac); +void csr_roam_startTKIPCounterMeasureTimer(tpAniSirGlobal pMac); +void csr_roam_stopTKIPCounterMeasureTimer(tpAniSirGlobal pMac); + +QDF_STATUS csr_scan_open(tpAniSirGlobal pMac); +QDF_STATUS csr_scan_close(tpAniSirGlobal pMac); +QDF_STATUS csr_scan_request_lost_link1(tpAniSirGlobal pMac, uint32_t sessionId); +QDF_STATUS csr_scan_request_lost_link2(tpAniSirGlobal pMac, uint32_t sessionId); +QDF_STATUS csr_scan_request_lost_link3(tpAniSirGlobal pMac, uint32_t sessionId); +QDF_STATUS csr_scan_handle_failed_lostlink1(tpAniSirGlobal pMac, + uint32_t sessionId); +QDF_STATUS csr_scan_handle_failed_lostlink2(tpAniSirGlobal pMac, + uint32_t sessionId); +QDF_STATUS csr_scan_handle_failed_lostlink3(tpAniSirGlobal pMac, + uint32_t sessionId); +tCsrScanResult *csr_scan_append_bss_description(tpAniSirGlobal pMac, + tSirBssDescription * + pSirBssDescription, + tDot11fBeaconIEs *pIes, + uint8_t sessionId); +void csr_scan_call_callback(tpAniSirGlobal pMac, tSmeCmd *pCommand, + eCsrScanStatus scanStatus); +QDF_STATUS csr_scan_copy_request(tpAniSirGlobal pMac, tCsrScanRequest *pDstReq, + tCsrScanRequest *pSrcReq); +QDF_STATUS csr_scan_free_request(tpAniSirGlobal pMac, tCsrScanRequest *pReq); +QDF_STATUS csr_scan_copy_result_list(tpAniSirGlobal pMac, tScanResultHandle hIn, + tScanResultHandle *phResult); +QDF_STATUS csr_scan_for_ssid(tpAniSirGlobal pMac, uint32_t sessionId, + tCsrRoamProfile *pProfile, uint32_t roamId, + bool notify); +/* To remove fresh scan commands from the pending queue */ +bool csr_scan_remove_fresh_scan_command(tpAniSirGlobal pMac, uint8_t sessionId); +QDF_STATUS csr_scan_abort_mac_scan(tpAniSirGlobal pMac, uint8_t sessionId, + uint32_t scan_id, eCsrAbortReason reason); +QDF_STATUS csr_scan_abort_all_scans(tpAniSirGlobal mac_ctx, + eCsrAbortReason reason); +/** + * csr_remove_cmd_from_pending_list() - Remove command from + * pending list + * @pMac: Pointer to Global MAC structure + * @sessionId: session id + * @scan_id: scan id + * @pList: pointer to pending command list + * @commandType: sme command type + * + * Remove command from pending list by matching either + * scan id or session id. + * + * Return: QDF_STATUS_SUCCESS for success, QDF_STATUS_E_FAILURE + * for failure + */ +QDF_STATUS csr_remove_cmd_from_pending_list(tpAniSirGlobal pMac, + uint8_t sessionId, + uint32_t scan_id, + tDblLinkList *pList, + eSmeCommandType commandType); +QDF_STATUS csr_scan_abort_mac_scan_not_for_connect(tpAniSirGlobal pMac, + uint8_t sessionId); +QDF_STATUS csr_scan_abort_scan_for_ssid(tpAniSirGlobal pMac, uint32_t sessionId); +void csr_remove_scan_for_ssid_from_pending_list(tpAniSirGlobal pMac, + tDblLinkList *pList, + uint32_t sessionId); + +QDF_STATUS csr_abort_scan_from_active_list(tpAniSirGlobal pMac, + tDblLinkList *pList, uint32_t sessionId, uint32_t scan_id, + eSmeCommandType scan_cmd_type, eCsrAbortReason abort_reason); + +/* To age out scan results base. tSmeGetScanChnRsp is a pointer returned by LIM that */ +/* has the information regarding scanned channels. */ +/* The logic is that whenever CSR add a BSS to scan result, it set the age count to */ +/* a value. This function deduct the age count if channelId matches the BSS' channelId */ +/* The BSS is remove if the count reaches 0. */ +QDF_STATUS csr_scan_age_results(tpAniSirGlobal pMac, + tSmeGetScanChnRsp *pScanChnInfo); + +/* If fForce is true we will save the new String that is learn't. */ +/* Typically it will be true in case of Join or user initiated ioctl */ +bool csr_learn_11dcountry_information(tpAniSirGlobal pMac, + tSirBssDescription *pSirBssDesc, + tDot11fBeaconIEs *pIes, bool fForce); +void csr_apply_country_information(tpAniSirGlobal pMac); +void csr_set_cfg_scan_control_list(tpAniSirGlobal pMac, uint8_t *countryCode, + tCsrChannel *pChannelList); +void csr_reinit_scan_cmd(tpAniSirGlobal pMac, tSmeCmd *pCommand); +void csr_free_scan_result_entry(tpAniSirGlobal pMac, tCsrScanResult *pResult); + +QDF_STATUS csr_roam_call_callback(tpAniSirGlobal pMac, uint32_t sessionId, + tCsrRoamInfo *pRoamInfo, uint32_t roamId, + eRoamCmdStatus u1, eCsrRoamResult u2); +QDF_STATUS csr_roam_issue_connect(tpAniSirGlobal pMac, uint32_t sessionId, + tCsrRoamProfile *pProfile, + tScanResultHandle hBSSList, + eCsrRoamReason reason, uint32_t roamId, + bool fImediate, bool fClearScan); +QDF_STATUS csr_roam_issue_reassoc(tpAniSirGlobal pMac, uint32_t sessionId, + tCsrRoamProfile *pProfile, + tCsrRoamModifyProfileFields *pModProfileFields, + eCsrRoamReason reason, uint32_t roamId, + bool fImediate); +void csr_roam_complete(tpAniSirGlobal pMac, eCsrRoamCompleteResult Result, + void *Context); +QDF_STATUS csr_roam_issue_set_context_req(tpAniSirGlobal pMac, uint32_t sessionId, + eCsrEncryptionType EncryptType, + tSirBssDescription *pBssDescription, + tSirMacAddr *bssId, bool addKey, + bool fUnicast, + tAniKeyDirection aniKeyDirection, + uint8_t keyId, uint16_t keyLength, + uint8_t *pKey, uint8_t paeRole); +QDF_STATUS csr_roam_process_disassoc_deauth(tpAniSirGlobal pMac, tSmeCmd *pCommand, + bool fDisassoc, bool fMICFailure); +QDF_STATUS csr_roam_save_connected_infomation(tpAniSirGlobal pMac, + uint32_t sessionId, + tCsrRoamProfile *pProfile, + tSirBssDescription *pSirBssDesc, + tDot11fBeaconIEs *pIes); +void csr_roam_check_for_link_status_change(tpAniSirGlobal pMac, tSirSmeRsp *pSirMsg); +void csr_roam_stats_rsp_processor(tpAniSirGlobal pMac, tSirSmeRsp *pSirMsg); +QDF_STATUS csr_roam_issue_start_bss(tpAniSirGlobal pMac, uint32_t sessionId, + tCsrRoamStartBssParams *pParam, + tCsrRoamProfile *pProfile, + tSirBssDescription *pBssDesc, uint32_t roamId); +QDF_STATUS csr_roam_issue_stop_bss(tpAniSirGlobal pMac, uint32_t sessionId, + eCsrRoamSubState NewSubstate); +bool csr_is_same_profile(tpAniSirGlobal pMac, tCsrRoamConnectedProfile *pProfile1, + tCsrRoamProfile *pProfile2); +bool csr_is_roam_command_waiting(tpAniSirGlobal pMac); +bool csr_is_roam_command_waiting_for_session(tpAniSirGlobal pMac, uint32_t sessionId); +bool csr_is_scan_for_roam_command_active(tpAniSirGlobal pMac); +eRoamCmdStatus csr_get_roam_complete_status(tpAniSirGlobal pMac, + uint32_t sessionId); +/* pBand can be NULL if caller doesn't need to get it */ +QDF_STATUS csr_roam_issue_disassociate_cmd(tpAniSirGlobal pMac, uint32_t sessionId, + eCsrRoamDisconnectReason reason); +QDF_STATUS csr_roam_disconnect_internal(tpAniSirGlobal pMac, uint32_t sessionId, + eCsrRoamDisconnectReason reason); +/* pCommand may be NULL */ +void csr_roam_remove_duplicate_command(tpAniSirGlobal pMac, uint32_t sessionId, + tSmeCmd *pCommand, + eCsrRoamReason eRoamReason); + +QDF_STATUS csr_send_join_req_msg(tpAniSirGlobal pMac, uint32_t sessionId, + tSirBssDescription *pBssDescription, + tCsrRoamProfile *pProfile, + tDot11fBeaconIEs *pIes, uint16_t messageType); +QDF_STATUS csr_send_mb_disassoc_req_msg(tpAniSirGlobal pMac, uint32_t sessionId, + tSirMacAddr bssId, uint16_t reasonCode); +QDF_STATUS csr_send_mb_deauth_req_msg(tpAniSirGlobal pMac, uint32_t sessionId, + tSirMacAddr bssId, uint16_t reasonCode); +QDF_STATUS csr_send_mb_disassoc_cnf_msg(tpAniSirGlobal pMac, + tpSirSmeDisassocInd pDisassocInd); +QDF_STATUS csr_send_mb_deauth_cnf_msg(tpAniSirGlobal pMac, + tpSirSmeDeauthInd pDeauthInd); +QDF_STATUS csr_send_assoc_cnf_msg(tpAniSirGlobal pMac, tpSirSmeAssocInd pAssocInd, + QDF_STATUS status); +QDF_STATUS csr_send_assoc_ind_to_upper_layer_cnf_msg(tpAniSirGlobal pMac, + tpSirSmeAssocInd pAssocInd, + QDF_STATUS Halstatus, + uint8_t sessionId); +QDF_STATUS csr_send_mb_start_bss_req_msg(tpAniSirGlobal pMac, uint32_t sessionId, + eCsrRoamBssType bssType, + tCsrRoamStartBssParams *pParam, + tSirBssDescription *pBssDesc); +QDF_STATUS csr_send_mb_stop_bss_req_msg(tpAniSirGlobal pMac, uint32_t sessionId); + +/* Caller should put the BSS' ssid to fiedl bssSsid when comparing SSID for a BSS. */ +bool csr_is_ssid_match(tpAniSirGlobal pMac, uint8_t *ssid1, uint8_t ssid1Len, + uint8_t *bssSsid, uint8_t bssSsidLen, bool fSsidRequired); +bool csr_is_phy_mode_match(tpAniSirGlobal pMac, uint32_t phyMode, + tSirBssDescription *pSirBssDesc, + tCsrRoamProfile *pProfile, + eCsrCfgDot11Mode *pReturnCfgDot11Mode, + tDot11fBeaconIEs *pIes); +bool csr_roam_is_channel_valid(tpAniSirGlobal pMac, uint8_t channel); + +/* pNumChan is a caller allocated space with the sizeof pChannels */ +QDF_STATUS csr_get_cfg_valid_channels(tpAniSirGlobal pMac, uint8_t *pChannels, + uint32_t *pNumChan); +void csr_roam_ccm_cfg_set_callback(tpAniSirGlobal pMac, int32_t result); + +int8_t csr_get_cfg_max_tx_power(tpAniSirGlobal pMac, uint8_t channel); + +/* To free the last roaming profile */ +void csr_free_roam_profile(tpAniSirGlobal pMac, uint32_t sessionId); +void csr_free_connect_bss_desc(tpAniSirGlobal pMac, uint32_t sessionId); +QDF_STATUS csr_move_bss_to_head_from_bssid(tpAniSirGlobal pMac, + struct qdf_mac_addr *bssid, + tScanResultHandle hScanResult); +bool csr_check_ps_ready(void *pv); +bool csr_check_ps_offload_ready(void *pv, uint32_t sessionId); + +/* to free memory allocated inside the profile structure */ +void csr_release_profile(tpAniSirGlobal pMac, tCsrRoamProfile *pProfile); +/* To free memory allocated inside scanFilter */ +void csr_free_scan_filter(tpAniSirGlobal pMac, tCsrScanResultFilter *pScanFilter); +eCsrCfgDot11Mode csr_get_cfg_dot11_mode_from_csr_phy_mode(tCsrRoamProfile *pProfile, + eCsrPhyMode phyMode, + bool fProprietary); +uint32_t csr_translate_to_wni_cfg_dot11_mode(tpAniSirGlobal pMac, + eCsrCfgDot11Mode csrDot11Mode); +void csr_save_channel_power_for_band(tpAniSirGlobal pMac, bool fPopulate5GBand); +void csr_apply_channel_power_info_to_fw(tpAniSirGlobal pMac, + tCsrChannel *pChannelList, + uint8_t *countryCode); +void csr_apply_power2_current(tpAniSirGlobal pMac); +void csr_assign_rssi_for_category(tpAniSirGlobal pMac, int8_t bestApRssi, + uint8_t catOffset); +QDF_STATUS csr_roam_remove_connected_bss_from_scan_cache(tpAniSirGlobal pMac, + tCsrRoamConnectedProfile * + pConnProfile); +QDF_STATUS csr_roam_start_roaming(tpAniSirGlobal pMac, uint32_t sessionId, + eCsrRoamingReason roamingReason); +/* return a bool to indicate whether roaming completed or continue. */ +bool csr_roam_complete_roaming(tpAniSirGlobal pMac, uint32_t sessionId, + bool fForce, eCsrRoamResult roamResult); +void csr_roam_completion(tpAniSirGlobal pMac, uint32_t sessionId, + tCsrRoamInfo *pRoamInfo, tSmeCmd *pCommand, + eCsrRoamResult roamResult, bool fSuccess); +void csr_roam_cancel_roaming(tpAniSirGlobal pMac, uint32_t sessionId); +void csr_apply_channel_power_info_wrapper(tpAniSirGlobal pMac); +void csr_reset_pmkid_candidate_list(tpAniSirGlobal pMac, uint32_t sessionId); +#ifdef FEATURE_WLAN_WAPI +void csr_reset_bkid_candidate_list(tpAniSirGlobal pMac, uint32_t sessionId); +#endif /* FEATURE_WLAN_WAPI */ +QDF_STATUS csr_save_to_channel_power2_g_5_g(tpAniSirGlobal pMac, uint32_t tableSize, + tSirMacChanInfo *channelTable); + +/* To check whether a country code matches the one in the IE */ +/* Only check the first two characters, ignoring in/outdoor */ +/* pCountry -- caller allocated buffer contain the country code that is checking against */ +/* the one in pIes. It can be NULL. */ +/* caller must provide pIes, it cannot be NULL */ +/* This function always return true if 11d support is not turned on. */ +/* pIes cannot be NULL */ +bool csr_match_country_code(tpAniSirGlobal pMac, uint8_t *pCountry, + tDot11fBeaconIEs *pIes); +QDF_STATUS csr_roam_set_key(tpAniSirGlobal pMac, uint32_t sessionId, + tCsrRoamSetKey *pSetKey, uint32_t roamId); +QDF_STATUS csr_roam_open_session(tpAniSirGlobal pMac, + csr_roam_completeCallback callback, void *pContext, + uint8_t *pSelfMacAddr, uint8_t *pbSessionId, + uint32_t type, uint32_t subType); +/* fSync: true means cleanupneeds to handle synchronously. */ +QDF_STATUS csr_roam_close_session(tpAniSirGlobal pMac, uint32_t sessionId, + bool fSync, + csr_roamSessionCloseCallback callback, + void *pContext); +void csr_cleanup_session(tpAniSirGlobal pMac, uint32_t sessionId); +QDF_STATUS csr_roam_get_session_id_from_bssid(tpAniSirGlobal pMac, struct qdf_mac_addr *bssid, + uint32_t *pSessionId); +eCsrCfgDot11Mode csr_find_best_phy_mode(tpAniSirGlobal pMac, uint32_t phyMode); + +/* --------------------------------------------------------------------------- + \fn csr_scan_enable + \brief Enable the scanning feature of CSR. It must be called before any scan request can be performed. + \param tHalHandle - HAL context handle + \return QDF_STATUS + -------------------------------------------------------------------------------*/ +QDF_STATUS csr_scan_enable(tpAniSirGlobal); + +/* --------------------------------------------------------------------------- + \fn csr_scan_disable + \brief Disableing the scanning feature of CSR. After this function return success, no scan is performed until + a successfull to csr_scan_enable + \param tHalHandle - HAL context handle + \return QDF_STATUS + -------------------------------------------------------------------------------*/ +QDF_STATUS csr_scan_disable(tpAniSirGlobal); +/* --------------------------------------------------------------------------- + \fn csr_scan_request + \brief Request a 11d or full scan. + \param callback - a callback function that scan calls upon finish, will not be called if csr_scan_request returns error + \param pContext - a pointer passed in for the callback + \return QDF_STATUS + -------------------------------------------------------------------------------*/ +QDF_STATUS csr_scan_request(tpAniSirGlobal, uint16_t, tCsrScanRequest *, + csr_scan_completeCallback callback, void *pContext); + +/* --------------------------------------------------------------------------- + \fn csrScanAbort + \brief If a scan request is abort, the scan complete callback will be called first before csrScanAbort returns. + \param pScanRequestID - The request ID returned from csr_scan_request + \return QDF_STATUS + -------------------------------------------------------------------------------*/ +QDF_STATUS csrScanAbort(tpAniSirGlobal, uint32_t scanRequestID); + +/* --------------------------------------------------------------------------- + \fn csr_scan_get_result + \brief Return scan results. + \param pFilter - If pFilter is NULL, all cached results are returned + \param phResult - an object for the result. + \return QDF_STATUS + -------------------------------------------------------------------------------*/ +QDF_STATUS csr_scan_get_result(tpAniSirGlobal, tCsrScanResultFilter *pFilter, + tScanResultHandle *phResult); + +/* --------------------------------------------------------------------------- + \fn csr_scan_flush_result + \brief Clear scan results. + \param pMac - pMac global pointer + \param sessionId - Session Identifier + \return QDF_STATUS + -------------------------------------------------------------------------------*/ +QDF_STATUS csr_scan_flush_result(tpAniSirGlobal); +/* --------------------------------------------------------------------------- + * \fn csr_scan_filter_results + * \brief Filter scan results based on valid channel list. + * \param pMac - Pointer to Global MAC structure + * \return QDF_STATUS + ***------------------------------------------------------------------------------- + */ +QDF_STATUS csr_scan_filter_results(tpAniSirGlobal pMac); + +void csr_save_scan_results(tpAniSirGlobal pMac, uint8_t reason, + uint8_t sessionId); + +QDF_STATUS csr_scan_flush_selective_result(tpAniSirGlobal, bool flushP2P); + +/* --------------------------------------------------------------------------- + \fn csr_scan_result_get_first + \brief Returns the first element of scan result. + \param hScanResult - returned from csr_scan_get_result + \return tCsrScanResultInfo * - NULL if no result + -------------------------------------------------------------------------------*/ +tCsrScanResultInfo *csr_scan_result_get_first(tpAniSirGlobal, + tScanResultHandle hScanResult); +/* --------------------------------------------------------------------------- + \fn csr_scan_result_get_next + \brief Returns the next element of scan result. It can be called without calling csr_scan_result_get_first first + \param hScanResult - returned from csr_scan_get_result + \return Null if no result or reach the end + -------------------------------------------------------------------------------*/ +tCsrScanResultInfo *csr_scan_result_get_next(tpAniSirGlobal, + tScanResultHandle hScanResult); + +/* --------------------------------------------------------------------------- + \fn csr_get_country_code + \brief this function is to get the country code current being used + \param pBuf - Caller allocated buffer with at least 3 bytes, upon success return, this has the country code + \param pbLen - Caller allocated, as input, it indicates the length of pBuf. Upon success return, + this contains the length of the data in pBuf + \return QDF_STATUS + -------------------------------------------------------------------------------*/ +QDF_STATUS csr_get_country_code(tpAniSirGlobal pMac, uint8_t *pBuf, + uint8_t *pbLen); + +/* --------------------------------------------------------------------------- + \fn csr_set_country_code + \brief this function is to set the country code so channel/power setting matches the countrycode and + the domain it belongs to. + \param pCountry - Caller allocated buffer with at least 3 bytes specifying the country code + \return QDF_STATUS + -------------------------------------------------------------------------------*/ +QDF_STATUS csr_set_country_code(tpAniSirGlobal pMac, uint8_t *pCountry); + +/* --------------------------------------------------------------------------- + \fn csr_get_regulatory_domain_for_country + \brief this function is to get the regulatory domain for a country. + This function must be called after CFG is downloaded and all the band/mode setting already passed into + CSR. + \param pCountry - Caller allocated buffer with at least 3 bytes specifying the country code + \param pDomainId - Caller allocated buffer to get the return domain ID upon success return. Can be NULL. + \param source - the source of country information. + \return QDF_STATUS + -------------------------------------------------------------------------------*/ +QDF_STATUS csr_get_regulatory_domain_for_country(tpAniSirGlobal pMac, + uint8_t *pCountry, + v_REGDOMAIN_t *pDomainId, + enum country_src source); + +/* some support functions */ +bool csr_is11d_supported(tpAniSirGlobal pMac); +bool csr_is11h_supported(tpAniSirGlobal pMac); +bool csr_is11e_supported(tpAniSirGlobal pMac); +bool csr_is_wmm_supported(tpAniSirGlobal pMac); +bool csr_is_mcc_supported(tpAniSirGlobal pMac); + +/* Return SUCCESS is the command is queued, failed */ +QDF_STATUS csr_queue_sme_command(tpAniSirGlobal pMac, tSmeCmd *pCommand, + bool fHighPriority); +tSmeCmd *csr_get_command_buffer(tpAniSirGlobal pMac); +void csr_release_command(tpAniSirGlobal pMac, tSmeCmd *pCommand); +void csr_scan_flush_bss_entry(tpAniSirGlobal pMac, + tpSmeCsaOffloadInd pCsaOffloadInd); +QDF_STATUS csr_get_active_scan_entry(tpAniSirGlobal mac, uint32_t scan_id, + tListElem **entry); + +#ifdef FEATURE_WLAN_WAPI +bool csr_is_profile_wapi(tCsrRoamProfile *pProfile); +#endif /* FEATURE_WLAN_WAPI */ + +void csr_get_vdev_type_nss(tpAniSirGlobal mac_ctx, + enum tQDF_ADAPTER_MODE dev_mode, + uint8_t *nss_2g, uint8_t *nss_5g); + +#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR + +/* Security */ +#define WLAN_SECURITY_EVENT_REMOVE_KEY_REQ 5 +#define WLAN_SECURITY_EVENT_REMOVE_KEY_RSP 6 +#define WLAN_SECURITY_EVENT_PMKID_CANDIDATE_FOUND 7 +#define WLAN_SECURITY_EVENT_PMKID_UPDATE 8 +#define WLAN_SECURITY_EVENT_MIC_ERROR 9 +#define WLAN_SECURITY_EVENT_SET_UNICAST_REQ 10 +#define WLAN_SECURITY_EVENT_SET_UNICAST_RSP 11 +#define WLAN_SECURITY_EVENT_SET_BCAST_REQ 12 +#define WLAN_SECURITY_EVENT_SET_BCAST_RSP 13 + + +#define AUTH_OPEN 0 +#define AUTH_SHARED 1 +#define AUTH_WPA_EAP 2 +#define AUTH_WPA_PSK 3 +#define AUTH_WPA2_EAP 4 +#define AUTH_WPA2_PSK 5 +#ifdef FEATURE_WLAN_WAPI +#define AUTH_WAPI_CERT 6 +#define AUTH_WAPI_PSK 7 +#endif /* FEATURE_WLAN_WAPI */ + +#define ENC_MODE_OPEN 0 +#define ENC_MODE_WEP40 1 +#define ENC_MODE_WEP104 2 +#define ENC_MODE_TKIP 3 +#define ENC_MODE_AES 4 +#ifdef FEATURE_WLAN_WAPI +#define ENC_MODE_SMS4 5 /* WAPI */ +#endif /* FEATURE_WLAN_WAPI */ + +#define NO_MATCH 0 +#define MATCH 1 + +#define WLAN_SECURITY_STATUS_SUCCESS 0 +#define WLAN_SECURITY_STATUS_FAILURE 1 + +/* Scan */ +#define WLAN_SCAN_EVENT_ACTIVE_SCAN_REQ 1 +#define WLAN_SCAN_EVENT_ACTIVE_SCAN_RSP 2 +#define WLAN_SCAN_EVENT_PASSIVE_SCAN_REQ 3 +#define WLAN_SCAN_EVENT_PASSIVE_SCAN_RSP 4 +#define WLAN_SCAN_EVENT_HO_SCAN_REQ 5 +#define WLAN_SCAN_EVENT_HO_SCAN_RSP 6 + +#define WLAN_SCAN_STATUS_SUCCESS 0 +#define WLAN_SCAN_STATUS_FAILURE 1 +#define WLAN_SCAN_STATUS_ABORT 2 + +/* Ibss */ +#define WLAN_IBSS_EVENT_START_IBSS_REQ 0 +#define WLAN_IBSS_EVENT_START_IBSS_RSP 1 +#define WLAN_IBSS_EVENT_JOIN_IBSS_REQ 2 +#define WLAN_IBSS_EVENT_JOIN_IBSS_RSP 3 +#define WLAN_IBSS_EVENT_COALESCING 4 +#define WLAN_IBSS_EVENT_PEER_JOIN 5 +#define WLAN_IBSS_EVENT_PEER_LEAVE 6 +#define WLAN_IBSS_EVENT_STOP_REQ 7 +#define WLAN_IBSS_EVENT_STOP_RSP 8 + +#define AUTO_PICK 0 +#define SPECIFIED 1 + +#define WLAN_IBSS_STATUS_SUCCESS 0 +#define WLAN_IBSS_STATUS_FAILURE 1 + +/* 11d */ +#define WLAN_80211D_EVENT_COUNTRY_SET 0 +#define WLAN_80211D_EVENT_RESET 1 + +#define WLAN_80211D_DISABLED 0 +#define WLAN_80211D_SUPPORT_MULTI_DOMAIN 1 +#define WLAN_80211D_NOT_SUPPORT_MULTI_DOMAIN 2 + +int diag_auth_type_from_csr_type(eCsrAuthType authType); +int diag_enc_type_from_csr_type(eCsrEncryptionType encType); +#endif /* #ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR */ +/* --------------------------------------------------------------------------- + \fn csr_scan_result_purge + \brief remove all items(tCsrScanResult) in the list and free memory for each item + \param hScanResult - returned from csr_scan_get_result. hScanResult is considered gone by + calling this function and even before this function reutrns. + \return QDF_STATUS + -------------------------------------------------------------------------------*/ +QDF_STATUS csr_scan_result_purge(tpAniSirGlobal pMac, + tScanResultHandle hScanResult); + +/* /////////////////////////////////////////Common Scan ends */ + +/* --------------------------------------------------------------------------- + \fn csr_roam_connect + \brief To inititiate an association + \param pProfile - can be NULL to join to any open ones + \param pRoamId - to get back the request ID + \return QDF_STATUS + -------------------------------------------------------------------------------*/ +QDF_STATUS csr_roam_connect(tpAniSirGlobal pMac, uint32_t sessionId, + tCsrRoamProfile *pProfile, + uint32_t *pRoamId); + +/* --------------------------------------------------------------------------- + \fn csr_roam_reassoc + \brief To inititiate a re-association + \param pProfile - can be NULL to join the currently connected AP. In that + case modProfileFields should carry the modified field(s) which could trigger + reassoc + \param modProfileFields - fields which are part of tCsrRoamConnectedProfile + that might need modification dynamically once STA is up & running and this + could trigger a reassoc + \param pRoamId - to get back the request ID + \return QDF_STATUS + -------------------------------------------------------------------------------*/ +QDF_STATUS csr_roam_reassoc(tpAniSirGlobal pMac, uint32_t sessionId, + tCsrRoamProfile *pProfile, + tCsrRoamModifyProfileFields modProfileFields, + uint32_t *pRoamId); + +/* --------------------------------------------------------------------------- + \fn csr_roam_reconnect + \brief To disconnect and reconnect with the same profile + \return QDF_STATUS. It returns fail if currently not connected + -------------------------------------------------------------------------------*/ +QDF_STATUS csr_roam_reconnect(tpAniSirGlobal pMac, uint32_t sessionId); + +/* --------------------------------------------------------------------------- + \fn csr_roam_set_pmkid_cache + \brief return the PMKID candidate list + \param pPMKIDCache - caller allocated buffer point to an array of tPmkidCacheInfo + \param numItems - a variable that has the number of tPmkidCacheInfo allocated + when retruning, this is either the number needed or number of items put into pPMKIDCache + \return QDF_STATUS - when fail, it usually means the buffer allocated is not big enough and pNumItems + has the number of tPmkidCacheInfo. + \Note: pNumItems is a number of tPmkidCacheInfo, not sizeof(tPmkidCacheInfo) * something + -------------------------------------------------------------------------------*/ +QDF_STATUS csr_roam_set_pmkid_cache(tpAniSirGlobal pMac, uint32_t sessionId, + tPmkidCacheInfo *pPMKIDCache, + uint32_t numItems, bool update_entire_cache); + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +/* --------------------------------------------------------------------------- + *\fn csr_roam_set_psk_pmk + *\brief store PSK/PMK + *\param pMac - pointer to global structure for MAC + *\param sessionId - Sme session id + *\param pPSK_PMK - pointer to an array of Psk/Pmk + *\return QDF_STATUS - usually it succeed unless sessionId is not found + *\Note: + *-------------------------------------------------------------------------------*/ +QDF_STATUS csr_roam_set_psk_pmk(tpAniSirGlobal pMac, uint32_t sessionId, + uint8_t *pPSK_PMK, size_t pmk_len); + +QDF_STATUS csr_roam_set_key_mgmt_offload(tpAniSirGlobal mac_ctx, + uint32_t session_id, + bool roam_key_mgmt_offload_enabled, + struct pmkid_mode_bits *pmkid_modes); +#endif +/* --------------------------------------------------------------------------- + \fn csr_roam_get_wpa_rsn_req_ie + \brief return the WPA or RSN IE CSR passes to PE to JOIN request or START_BSS request + \param pLen - caller allocated memory that has the length of pBuf as input. Upon returned, *pLen has the + needed or IE length in pBuf. + \param pBuf - Caller allocated memory that contain the IE field, if any, upon return + \return QDF_STATUS - when fail, it usually means the buffer allocated is not big enough + -------------------------------------------------------------------------------*/ +QDF_STATUS csr_roam_get_wpa_rsn_req_ie(tpAniSirGlobal pMac, uint32_t sessionId, + uint32_t *pLen, uint8_t *pBuf); + +/* --------------------------------------------------------------------------- + \fn csr_roam_get_wpa_rsn_rsp_ie + \brief return the WPA or RSN IE from the beacon or probe rsp if connected + \param pLen - caller allocated memory that has the length of pBuf as input. Upon returned, *pLen has the + needed or IE length in pBuf. + \param pBuf - Caller allocated memory that contain the IE field, if any, upon return + \return QDF_STATUS - when fail, it usually means the buffer allocated is not big enough + -------------------------------------------------------------------------------*/ +QDF_STATUS csr_roam_get_wpa_rsn_rsp_ie(tpAniSirGlobal pMac, uint32_t sessionId, + uint32_t *pLen, uint8_t *pBuf); + +/* --------------------------------------------------------------------------- + \fn csr_roam_get_num_pmkid_cache + \brief return number of PMKID cache entries + \return uint32_t - the number of PMKID cache entries + -------------------------------------------------------------------------------*/ +uint32_t csr_roam_get_num_pmkid_cache(tpAniSirGlobal pMac, uint32_t sessionId); + +/* --------------------------------------------------------------------------- + \fn csr_roam_get_pmkid_cache + \brief return PMKID cache from CSR + \param pNum - caller allocated memory that has the space of the number of pBuf tPmkidCacheInfo as input. Upon returned, *pNum has the + needed or actually number in tPmkidCacheInfo. + \param pPmkidCache - Caller allocated memory that contains PMKID cache, if any, upon return + \return QDF_STATUS - when fail, it usually means the buffer allocated is not big enough + -------------------------------------------------------------------------------*/ +QDF_STATUS csr_roam_get_pmkid_cache(tpAniSirGlobal pMac, uint32_t sessionId, + uint32_t *pNum, tPmkidCacheInfo *pPmkidCache); + +/** + * csr_roam_get_connect_profile() - To return the current connect profile, + * caller must call csr_roam_free_connect_profile after it is done and before + * reuse for another csr_roam_get_connect_profile call. + * + * @pMac: pointer to global adapter context + * @sessionId: session ID + * @pProfile: pointer to a caller allocated structure + * tCsrRoamConnectedProfile + * + * Return: QDF_STATUS. Failure if not connected, success otherwise + */ +QDF_STATUS csr_roam_get_connect_profile(tpAniSirGlobal pMac, uint32_t sessionId, + tCsrRoamConnectedProfile *pProfile); + +/* --------------------------------------------------------------------------- + \fn csr_roam_get_connect_state + \brief To return the current connect state of Roaming + \return QDF_STATUS + -------------------------------------------------------------------------------*/ +QDF_STATUS csr_roam_get_connect_state(tpAniSirGlobal pMac, uint32_t sessionId, + eCsrConnectState *pState); + +void csr_roam_free_connect_profile(tCsrRoamConnectedProfile *profile); + +/* --------------------------------------------------------------------------- + \fn csr_apply_channel_and_power_list + \brief HDD calls this function to set the WNI_CFG_VALID_CHANNEL_LIST base on the band/mode settings. + This function must be called after CFG is downloaded and all the band/mode setting already passed into + CSR. + \return QDF_STATUS + -------------------------------------------------------------------------------*/ +QDF_STATUS csr_apply_channel_and_power_list(tpAniSirGlobal pMac); + +/* --------------------------------------------------------------------------- + \fn csr_roam_connect_to_last_profile + \brief To disconnect and reconnect with the same profile + \return QDF_STATUS. It returns fail if currently connected + -------------------------------------------------------------------------------*/ +QDF_STATUS csr_roam_connect_to_last_profile(tpAniSirGlobal pMac, uint32_t sessionId); + +/* --------------------------------------------------------------------------- + \fn csr_roam_disconnect + \brief To disconnect from a network + \param reason -- To indicate the reason for disconnecting. Currently, only eCSR_DISCONNECT_REASON_MIC_ERROR is meanful. + \return QDF_STATUS + -------------------------------------------------------------------------------*/ +QDF_STATUS csr_roam_disconnect(tpAniSirGlobal pMac, uint32_t sessionId, + eCsrRoamDisconnectReason reason); + +/* --------------------------------------------------------------------------- + \fn csr_scan_get_pmkid_candidate_list + \brief return the PMKID candidate list + \param pPmkidList - caller allocated buffer point to an array of tPmkidCandidateInfo + \param pNumItems - pointer to a variable that has the number of tPmkidCandidateInfo allocated + when retruning, this is either the number needed or number of items put into pPmkidList + \return QDF_STATUS - when fail, it usually means the buffer allocated is not big enough and pNumItems + has the number of tPmkidCandidateInfo. + \Note: pNumItems is a number of tPmkidCandidateInfo, not sizeof(tPmkidCandidateInfo) * something + -------------------------------------------------------------------------------*/ +QDF_STATUS csr_scan_get_pmkid_candidate_list(tpAniSirGlobal pMac, uint32_t sessionId, + tPmkidCandidateInfo *pPmkidList, + uint32_t *pNumItems); + +/* This function is used to stop a BSS. It is similar of csr_roamIssueDisconnect but this function */ +/* doesn't have any logic other than blindly trying to stop BSS */ +QDF_STATUS csr_roam_issue_stop_bss_cmd(tpAniSirGlobal pMac, uint32_t sessionId, + bool fHighPriority); + +void csr_call_roaming_completion_callback(tpAniSirGlobal pMac, + tCsrRoamSession *pSession, + tCsrRoamInfo *pRoamInfo, uint32_t roamId, + eCsrRoamResult roamResult); +/** + * csr_roam_issue_disassociate_sta_cmd() - disassociate a associated station + * @pMac: Pointer to global structure for MAC + * @sessionId: Session Id for Soft AP + * @p_del_sta_params: Pointer to parameters of the station to disassoc + * + * CSR function that HDD calls to issue a deauthenticate station command + * + * Return: QDF_STATUS_SUCCESS on success or another QDF_STATUS_* on error + */ +QDF_STATUS csr_roam_issue_disassociate_sta_cmd(tpAniSirGlobal pMac, + uint32_t sessionId, + struct tagCsrDelStaParams + *p_del_sta_params); +/** + * csr_roam_issue_deauth_sta_cmd() - issue deauthenticate station command + * @pMac: Pointer to global structure for MAC + * @sessionId: Session Id for Soft AP + * @pDelStaParams: Pointer to parameters of the station to deauthenticate + * + * CSR function that HDD calls to issue a deauthenticate station command + * + * Return: QDF_STATUS_SUCCESS on success or another QDF_STATUS_** on error + */ +QDF_STATUS csr_roam_issue_deauth_sta_cmd(tpAniSirGlobal pMac, + uint32_t sessionId, + struct tagCsrDelStaParams *pDelStaParams); + +/* --------------------------------------------------------------------------- + \fn csr_roam_issue_tkip_counter_measures + \brief csr function that HDD calls to start and stop tkip countermeasures + \param sessionId - session Id for Soft AP + \param bEnable - Flag to start/stop countermeasures + \return QDF_STATUS + ---------------------------------------------------------------------------*/ +QDF_STATUS csr_roam_issue_tkip_counter_measures(tpAniSirGlobal pMac, + uint32_t sessionId, bool bEnable); + +/* --------------------------------------------------------------------------- + \fn csr_roam_get_associated_stas + \brief csr function that HDD calls to get list of associated stations based on module ID + \param sessionId - session Id for Soft AP + \param modId - module ID - PE/HAL/TL + \param pUsrContext - Opaque HDD context + \param pfnSapEventCallback - Sap event callback in HDD + \param pAssocStasBuf - Caller allocated memory to be filled with associatd stations info + \return QDF_STATUS + ---------------------------------------------------------------------------*/ +QDF_STATUS csr_roam_get_associated_stas(tpAniSirGlobal pMac, uint32_t sessionId, + QDF_MODULE_ID modId, void *pUsrContext, + void *pfnSapEventCallback, + uint8_t *pAssocStasBuf); + +QDF_STATUS csr_send_mb_get_associated_stas_req_msg(tpAniSirGlobal pMac, + uint32_t sessionId, + QDF_MODULE_ID modId, + struct qdf_mac_addr bssId, + void *pUsrContext, + void *pfnSapEventCallback, + uint8_t *pAssocStasBuf); + +/* --------------------------------------------------------------------------- + \fn csr_roam_get_wps_session_overlap + \brief csr function that HDD calls to get WPS PBC session overlap information + \param sessionId - session Id for Soft AP + \param pUsrContext - Opaque HDD context + \param pfnSapEventCallback - Sap event callback in HDD + \param pRemoveMac - pointer to MAC address of session to be removed + \return QDF_STATUS + ---------------------------------------------------------------------------*/ +QDF_STATUS csr_roam_get_wps_session_overlap(tpAniSirGlobal pMac, uint32_t sessionId, + void *pUsrContext, + void *pfnSapEventCallback, + struct qdf_mac_addr pRemoveMac); + +QDF_STATUS csr_send_mb_get_wpspbc_sessions(tpAniSirGlobal pMac, + uint32_t sessionId, + struct qdf_mac_addr bssId, + void *pUsrContext, + void *pfnSapEventCallback, + struct qdf_mac_addr pRemoveMac); + +/* --------------------------------------------------------------------------- + \fn csr_send_chng_mcc_beacon_interval + \brief csr function that HDD calls to send Update beacon interval + \param sessionId - session Id for Soft AP + \return QDF_STATUS + ---------------------------------------------------------------------------*/ +QDF_STATUS +csr_send_chng_mcc_beacon_interval(tpAniSirGlobal pMac, uint32_t sessionId); + +#ifdef WLAN_FEATURE_HOST_ROAM +void csr_roam_ft_pre_auth_rsp_processor(tHalHandle hHal, + tpSirFTPreAuthRsp pFTPreAuthRsp); +void csr_release_command_preauth(tpAniSirGlobal mac_ctx, tSmeCmd *command); +#else +static inline void csr_roam_ft_pre_auth_rsp_processor(tHalHandle hHal, + tpSirFTPreAuthRsp pFTPreAuthRsp) +{} +static inline void csr_release_command_preauth(tpAniSirGlobal mac_ctx, + tSmeCmd *command) +{} +#endif + +#if defined(FEATURE_WLAN_ESE) +void update_cckmtsf(uint32_t *timeStamp0, uint32_t *timeStamp1, + uint64_t *incr); +#endif + +QDF_STATUS csr_roam_enqueue_preauth(tpAniSirGlobal pMac, uint32_t sessionId, + tpSirBssDescription pBssDescription, + eCsrRoamReason reason, bool fImmediate); +QDF_STATUS csr_dequeue_roam_command(tpAniSirGlobal pMac, eCsrRoamReason reason); +void csr_init_occupied_channels_list(tpAniSirGlobal pMac, uint8_t sessionId); +bool csr_neighbor_roam_is_new_connected_profile(tpAniSirGlobal pMac, + uint8_t sessionId); +bool csr_neighbor_roam_connected_profile_match(tpAniSirGlobal pMac, + uint8_t sessionId, + tCsrScanResult *pResult, + tDot11fBeaconIEs *pIes); + +QDF_STATUS csr_scan_create_entry_in_scan_cache(tpAniSirGlobal pMac, + uint32_t sessionId, + struct qdf_mac_addr bssid, + uint8_t channel); + +QDF_STATUS csr_update_channel_list(tpAniSirGlobal pMac); +QDF_STATUS csr_roam_del_pmkid_from_cache(tpAniSirGlobal pMac, + uint32_t sessionId, + const uint8_t *pBSSId, + bool flush_cache); + +bool csr_elected_country_info(tpAniSirGlobal pMac); +void csr_add_vote_for_country_info(tpAniSirGlobal pMac, uint8_t *pCountryCode); +void csr_clear_votes_for_country_info(tpAniSirGlobal pMac); + +#endif +QDF_STATUS csr_send_ext_change_channel(tpAniSirGlobal mac_ctx, + uint32_t channel, uint8_t session_id); + +#ifdef QCA_HT_2040_COEX +QDF_STATUS csr_set_ht2040_mode(tpAniSirGlobal pMac, uint32_t sessionId, + ePhyChanBondState cbMode, bool obssEnabled); +#endif +QDF_STATUS csr_scan_handle_search_for_ssid(tpAniSirGlobal mac, + tSmeCmd *command); +QDF_STATUS csr_scan_handle_search_for_ssid_failure(tpAniSirGlobal mac, + tSmeCmd *command); + +tpSirBssDescription csr_get_fst_bssdescr_ptr(tScanResultHandle result_handle); + +tSirBssDescription* +csr_get_bssdescr_from_scan_handle(tScanResultHandle result_handle, + tSirBssDescription *bss_descr); +void csr_release_scan_command(tpAniSirGlobal pMac, tSmeCmd *pCommand, + eCsrScanStatus scanStatus); +bool is_disconnect_pending(tpAniSirGlobal mac_ctx, + uint8_t sessionid); +void csr_scan_active_list_timeout_handle(void *userData); +QDF_STATUS csr_prepare_disconnect_command(tpAniSirGlobal mac, + uint32_t session_id, tSmeCmd **sme_cmd); +QDF_STATUS csr_roam_prepare_bss_config_from_profile(tpAniSirGlobal mac_ctx, + tCsrRoamProfile *profile, tBssConfigParam *bss_cfg, + tSirBssDescription *bss_desc); +void csr_roam_prepare_bss_params(tpAniSirGlobal mac_ctx, uint32_t session_id, + tCsrRoamProfile *profile, tSirBssDescription *bss_desc, + tBssConfigParam *bss_cfg, tDot11fBeaconIEs *ies); + +void csr_remove_bssid_from_scan_list(tpAniSirGlobal mac_ctx, + tSirMacAddr bssid); + +QDF_STATUS csr_roam_set_bss_config_cfg(tpAniSirGlobal mac_ctx, + uint32_t session_id, + tCsrRoamProfile *profile, tSirBssDescription *bss_desc, + tBssConfigParam *bss_cfg, tDot11fBeaconIEs *ies, + bool reset_country); +void csr_prune_channel_list_for_mode(tpAniSirGlobal pMac, + tCsrChannel *pChannelList); diff --git a/drivers/staging/qcacld-3.0/core/sme/src/csr/csr_link_list.c b/drivers/staging/qcacld-3.0/core/sme/src/csr/csr_link_list.c new file mode 100644 index 0000000000000000000000000000000000000000..6bac6d808ccffb8e69092d51bfadf6ad8e7fc585 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/sme/src/csr/csr_link_list.c @@ -0,0 +1,571 @@ +/* + * Copyright (c) 2011-2012, 2014-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** ------------------------------------------------------------------------- * + ------------------------------------------------------------------------- * + \file csr_link_list.c + + Implementation for the Common link list interfaces. + ========================================================================== */ + +#include "csr_link_list.h" +#include "qdf_lock.h" +#include "qdf_mem.h" +#include "qdf_trace.h" +#include "qdf_mc_timer.h" + +static inline void csr_list_init(tListElem *pList) +{ + pList->last = pList->next = pList; +} + +static inline void csr_list_remove_entry(tListElem *pEntry) +{ + tListElem *pLast; + tListElem *pNext; + + pLast = pEntry->last; + pNext = pEntry->next; + pLast->next = pNext; + pNext->last = pLast; +} + +static inline tListElem *csr_list_remove_head(tListElem *pHead) +{ + tListElem *pEntry; + tListElem *pNext; + + pEntry = pHead->next; + pNext = pEntry->next; + pHead->next = pNext; + pNext->last = pHead; + + return pEntry; +} + +static inline tListElem *csr_list_remove_tail(tListElem *pHead) +{ + tListElem *pEntry; + tListElem *pLast; + + pEntry = pHead->last; + pLast = pEntry->last; + pHead->last = pLast; + pLast->next = pHead; + + return pEntry; +} + +static inline void csr_list_insert_tail(tListElem *pHead, tListElem *pEntry) +{ + tListElem *pLast; + + pLast = pHead->last; + pEntry->last = pLast; + pEntry->next = pHead; + pLast->next = pEntry; + pHead->last = pEntry; +} + +static inline void csr_list_insert_head(tListElem *pHead, tListElem *pEntry) +{ + tListElem *pNext; + + pNext = pHead->next; + pEntry->next = pNext; + pEntry->last = pHead; + pNext->last = pEntry; + pHead->next = pEntry; +} + +/* Insert pNewEntry before pEntry */ +static void csr_list_insert_entry(tListElem *pEntry, tListElem *pNewEntry) +{ + tListElem *pLast; + if (!pEntry) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_FATAL, + "%s: Error!! pEntry is Null", __func__); + return; + } + + pLast = pEntry->last; + pLast->next = pNewEntry; + pEntry->last = pNewEntry; + pNewEntry->next = pEntry; + pNewEntry->last = pLast; +} + +uint32_t csr_ll_count(tDblLinkList *pList) +{ + uint32_t c = 0; + + if (!pList) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_FATAL, + "%s: Error!! pList is Null", __func__); + return c; + } + + if (pList && (LIST_FLAG_OPEN == pList->Flag)) { + c = pList->Count; + } + + return c; +} + +void csr_ll_lock(tDblLinkList *pList) +{ + + if (!pList) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_FATAL, + "%s: Error!! pList is Null", __func__); + return; + } + + if (LIST_FLAG_OPEN == pList->Flag) { + qdf_mutex_acquire(&pList->Lock); + } +} + +void csr_ll_unlock(tDblLinkList *pList) +{ + + if (!pList) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_FATAL, + "%s: Error!! pList is Null", __func__); + return; + } + + if (LIST_FLAG_OPEN == pList->Flag) { + qdf_mutex_release(&pList->Lock); + } +} + +bool csr_ll_is_list_empty(tDblLinkList *pList, bool fInterlocked) +{ + bool fEmpty = true; + + if (!pList) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_FATAL, + "%s: Error!! pList is Null", __func__); + return fEmpty; + } + + if (LIST_FLAG_OPEN == pList->Flag) { + if (fInterlocked) { + csr_ll_lock(pList); + } + + fEmpty = csrIsListEmpty(&pList->ListHead); + + if (fInterlocked) { + csr_ll_unlock(pList); + } + } + return fEmpty; +} + +bool csr_ll_find_entry(tDblLinkList *pList, tListElem *pEntryToFind) +{ + bool fFound = false; + tListElem *pEntry; + + if (!pList) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_FATAL, + "%s: Error!! pList is Null", __func__); + return fFound; + } + + if (LIST_FLAG_OPEN == pList->Flag) { + pEntry = csr_ll_peek_head(pList, LL_ACCESS_NOLOCK); + + /* Have to make sure we don't loop back to the head of the list, which will */ + /* happen if the entry is NOT on the list... */ + + while (pEntry && (pEntry != &pList->ListHead)) { + if (pEntry == pEntryToFind) { + fFound = true; + break; + } + pEntry = pEntry->next; + } + + } + return fFound; +} + +QDF_STATUS csr_ll_open(tHddHandle hHdd, tDblLinkList *pList) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + QDF_STATUS qdf_status; + + if (!pList) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_FATAL, + "%s: Error!! pList is Null", __func__); + return QDF_STATUS_E_FAILURE; + } + + if (LIST_FLAG_OPEN != pList->Flag) { + pList->Count = 0; + pList->cmdTimeoutTimer = NULL; + qdf_status = qdf_mutex_create(&pList->Lock); + + if (QDF_IS_STATUS_SUCCESS(qdf_status)) { + csr_list_init(&pList->ListHead); + pList->Flag = LIST_FLAG_OPEN; + pList->hHdd = hHdd; + } else { + status = QDF_STATUS_E_FAILURE; + } + } + return status; +} + +void csr_ll_close(tDblLinkList *pList) +{ + if (!pList) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_FATAL, + "%s: Error!! pList is Null", __func__); + return; + } + + if (LIST_FLAG_OPEN == pList->Flag) { + /* Make sure the list is empty... */ + csr_ll_purge(pList, LL_ACCESS_LOCK); + qdf_mutex_destroy(&pList->Lock); + pList->Flag = LIST_FLAG_CLOSE; + } +} + +void csr_ll_insert_tail(tDblLinkList *pList, tListElem *pEntry, + bool fInterlocked) +{ + if (!pList) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_FATAL, + "%s: Error!! pList is Null", __func__); + return; + } + + if (LIST_FLAG_OPEN == pList->Flag) { + if (fInterlocked) { + csr_ll_lock(pList); + } + csr_list_insert_tail(&pList->ListHead, pEntry); + pList->Count++; + if (fInterlocked) { + csr_ll_unlock(pList); + } + } +} + +void csr_ll_insert_head(tDblLinkList *pList, tListElem *pEntry, + bool fInterlocked) +{ + + if (!pList) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_FATAL, + "%s: Error!! pList is Null", __func__); + return; + } + + if (LIST_FLAG_OPEN == pList->Flag) { + if (fInterlocked) { + csr_ll_lock(pList); + } + csr_list_insert_head(&pList->ListHead, pEntry); + pList->Count++; + if (fInterlocked) { + csr_ll_unlock(pList); + } + if (pList->cmdTimeoutTimer && pList->cmdTimeoutDuration) { + /* timer to detect pending command in activelist */ + qdf_mc_timer_start(pList->cmdTimeoutTimer, + pList->cmdTimeoutDuration); + } + } +} + +void csr_ll_insert_entry(tDblLinkList *pList, tListElem *pEntry, + tListElem *pNewEntry, bool fInterlocked) +{ + if (!pList) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_FATAL, + "%s: Error!! pList is Null", __func__); + return; + } + + if (LIST_FLAG_OPEN == pList->Flag) { + if (fInterlocked) { + csr_ll_lock(pList); + } + csr_list_insert_entry(pEntry, pNewEntry); + pList->Count++; + if (fInterlocked) { + csr_ll_unlock(pList); + } + } +} + +tListElem *csr_ll_remove_tail(tDblLinkList *pList, bool fInterlocked) +{ + tListElem *pEntry = NULL; + + if (!pList) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_FATAL, + "%s: Error!! pList is Null", __func__); + return pEntry; + } + + if (LIST_FLAG_OPEN == pList->Flag) { + if (fInterlocked) { + csr_ll_lock(pList); + } + + if (!csrIsListEmpty(&pList->ListHead)) { + + pEntry = csr_list_remove_tail(&pList->ListHead); + pList->Count--; + } + if (fInterlocked) { + csr_ll_unlock(pList); + } + } + + return pEntry; +} + +tListElem *csr_ll_peek_tail(tDblLinkList *pList, bool fInterlocked) +{ + tListElem *pEntry = NULL; + + if (!pList) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_FATAL, + "%s: Error!! pList is Null", __func__); + return pEntry; + } + + if (LIST_FLAG_OPEN == pList->Flag) { + if (fInterlocked) { + csr_ll_lock(pList); + } + + if (!csrIsListEmpty(&pList->ListHead)) { + pEntry = pList->ListHead.last; + } + if (fInterlocked) { + csr_ll_unlock(pList); + } + } + + return pEntry; +} + +tListElem *csr_ll_remove_head(tDblLinkList *pList, bool fInterlocked) +{ + tListElem *pEntry = NULL; + + if (!pList) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_FATAL, + "%s: Error!! pList is Null", __func__); + return pEntry; + } + + if (LIST_FLAG_OPEN == pList->Flag) { + if (fInterlocked) { + csr_ll_lock(pList); + } + + if (!csrIsListEmpty(&pList->ListHead)) { + pEntry = csr_list_remove_head(&pList->ListHead); + pList->Count--; + } + + if (fInterlocked) { + csr_ll_unlock(pList); + } + } + + return pEntry; +} + +tListElem *csr_ll_peek_head(tDblLinkList *pList, bool fInterlocked) +{ + tListElem *pEntry = NULL; + + if (!pList) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_FATAL, + "%s: Error!! pList is Null", __func__); + return pEntry; + } + + if (LIST_FLAG_OPEN == pList->Flag) { + if (fInterlocked) { + csr_ll_lock(pList); + } + + if (!csrIsListEmpty(&pList->ListHead)) { + pEntry = pList->ListHead.next; + } + if (fInterlocked) { + csr_ll_unlock(pList); + } + } + + return pEntry; +} + +void csr_ll_purge(tDblLinkList *pList, bool fInterlocked) +{ + tListElem *pEntry; + + if (!pList) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_FATAL, + "%s: Error!! pList is Null", __func__); + return; + } + + if (LIST_FLAG_OPEN == pList->Flag) { + if (fInterlocked) { + csr_ll_lock(pList); + } + while ((pEntry = csr_ll_remove_head(pList, LL_ACCESS_NOLOCK))) { + /* just remove everything from the list until */ + /* nothing left on the list. */ + } + if (fInterlocked) { + csr_ll_unlock(pList); + } + } +} + +bool csr_ll_remove_entry(tDblLinkList *pList, tListElem *pEntryToRemove, + bool fInterlocked) +{ + bool fFound = false; + tListElem *pEntry; + + if (!pList) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_FATAL, + "%s: Error!! pList is Null", __func__); + return fFound; + } + + if (LIST_FLAG_OPEN == pList->Flag) { + if (fInterlocked) { + csr_ll_lock(pList); + } + + pEntry = csr_ll_peek_head(pList, LL_ACCESS_NOLOCK); + + /* Have to make sure we don't loop back to the head of the list, which will */ + /* happen if the entry is NOT on the list... */ + while (pEntry && (pEntry != &pList->ListHead)) { + if (pEntry == pEntryToRemove) { + csr_list_remove_entry(pEntry); + pList->Count--; + + fFound = true; + break; + } + + pEntry = pEntry->next; + } + if (fInterlocked) { + csr_ll_unlock(pList); + } + if (pList->cmdTimeoutTimer) { + qdf_mc_timer_stop(pList->cmdTimeoutTimer); + } + } + + return fFound; +} + +tListElem *csr_ll_next(tDblLinkList *pList, tListElem *pEntry, + bool fInterlocked) +{ + tListElem *pNextEntry = NULL; + + if (!pList) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_FATAL, + "%s: Error!! pList is Null", __func__); + return pNextEntry; + } + + if (LIST_FLAG_OPEN == pList->Flag) { + if (fInterlocked) { + csr_ll_lock(pList); + } + + if (!csrIsListEmpty(&pList->ListHead) + && csr_ll_find_entry(pList, pEntry)) { + pNextEntry = pEntry->next; + /* Make sure we don't walk past the head */ + if (pNextEntry == &pList->ListHead) { + pNextEntry = NULL; + } + } + + if (fInterlocked) { + csr_ll_unlock(pList); + } + } + + return pNextEntry; +} + +tListElem *csr_ll_previous(tDblLinkList *pList, tListElem *pEntry, + bool fInterlocked) +{ + tListElem *pNextEntry = NULL; + + if (!pList) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_FATAL, + "%s: Error!! pList is Null", __func__); + return pNextEntry; + } + + if (LIST_FLAG_OPEN == pList->Flag) { + if (fInterlocked) { + csr_ll_lock(pList); + } + + if (!csrIsListEmpty(&pList->ListHead) + && csr_ll_find_entry(pList, pEntry)) { + pNextEntry = pEntry->last; + /* Make sure we don't walk past the head */ + if (pNextEntry == &pList->ListHead) { + pNextEntry = NULL; + } + } + + if (fInterlocked) { + csr_ll_unlock(pList); + } + } + + return pNextEntry; +} diff --git a/drivers/staging/qcacld-3.0/core/sme/src/csr/csr_neighbor_roam.c b/drivers/staging/qcacld-3.0/core/sme/src/csr/csr_neighbor_roam.c new file mode 100644 index 0000000000000000000000000000000000000000..c1c88fc039ab38723f8b8e4bd631aa394c21a839 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/sme/src/csr/csr_neighbor_roam.c @@ -0,0 +1,1791 @@ +/* + * Copyright (c) 2011-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** ------------------------------------------------------------------------- * + ------------------------------------------------------------------------- * + + \file csr_neighbor_roam.c + + Implementation for the simple roaming algorithm for 802.11r Fast + transitions and Legacy roaming for Android platform. + ========================================================================== */ + +#include "wma_types.h" +#include "cds_mq.h" +#include "csr_inside_api.h" +#include "sms_debug.h" +#include "sme_qos_internal.h" +#include "sme_inside.h" +#include "host_diag_core_event.h" +#include "host_diag_core_log.h" +#include "csr_api.h" +#include "sme_api.h" +#include "csr_neighbor_roam.h" +#include "mac_trace.h" +#include "cds_concurrency.h" + +#define NEIGHBOR_ROAM_DEBUG sms_log +static const char *lfr_get_config_item_string(uint8_t reason) +{ + switch (reason) { + CASE_RETURN_STRING(REASON_LOOKUP_THRESH_CHANGED); + CASE_RETURN_STRING(REASON_OPPORTUNISTIC_THRESH_DIFF_CHANGED); + CASE_RETURN_STRING(REASON_ROAM_RESCAN_RSSI_DIFF_CHANGED); + CASE_RETURN_STRING(REASON_ROAM_BMISS_FIRST_BCNT_CHANGED); + CASE_RETURN_STRING(REASON_ROAM_BMISS_FINAL_BCNT_CHANGED); + CASE_RETURN_STRING(REASON_ROAM_BEACON_RSSI_WEIGHT_CHANGED); + default: + return "unknown"; + } +} + +static void csr_neighbor_roam_reset_channel_info(tpCsrNeighborRoamChannelInfo + rChInfo); + +QDF_STATUS csr_roam_copy_connected_profile(tpAniSirGlobal pMac, uint32_t sessionId, + tCsrRoamProfile *pDstProfile); + +void csr_neighbor_roam_state_transition(tpAniSirGlobal mac_ctx, + uint8_t newstate, uint8_t session) +{ + mac_ctx->roam.neighborRoamInfo[session].prevNeighborRoamState = + mac_ctx->roam.neighborRoamInfo[session].neighborRoamState; + mac_ctx->roam.neighborRoamInfo[session].neighborRoamState = newstate; + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + FL("Sessionid (%d) NeighborRoam transition from %s to %s"), + session, csr_neighbor_roam_state_to_string( + mac_ctx->roam.neighborRoamInfo[session].prevNeighborRoamState), + csr_neighbor_roam_state_to_string(newstate)); +} + +uint8_t *csr_neighbor_roam_state_to_string(uint8_t state) +{ + switch (state) { + CASE_RETURN_STRING(eCSR_NEIGHBOR_ROAM_STATE_CLOSED); + CASE_RETURN_STRING(eCSR_NEIGHBOR_ROAM_STATE_INIT); + CASE_RETURN_STRING(eCSR_NEIGHBOR_ROAM_STATE_CONNECTED); + CASE_RETURN_STRING(eCSR_NEIGHBOR_ROAM_STATE_REASSOCIATING); + CASE_RETURN_STRING(eCSR_NEIGHBOR_ROAM_STATE_PREAUTHENTICATING); + CASE_RETURN_STRING(eCSR_NEIGHBOR_ROAM_STATE_PREAUTH_DONE); + default: + return "eCSR_NEIGHBOR_ROAM_STATE_UNKNOWN"; + } + +} + +#ifdef FEATURE_WLAN_LFR_METRICS +/** + * csr_neighbor_roam_send_lfr_metric_event() - Send event of LFR metric + * @mac_ctx: Handle returned by mac_open. + * @session_id: Session information + * @bssid: BSSID of attempted AP + * @status: Result of LFR operation + * + * LFR metrics - pre-auth completion metric + * Send the event to supplicant indicating pre-auth result + * + * Return: void + */ + +void csr_neighbor_roam_send_lfr_metric_event( + tpAniSirGlobal mac_ctx, + uint8_t session_id, + tSirMacAddr bssid, + eRoamCmdStatus status) +{ + tCsrRoamInfo *roam_info; + + roam_info = qdf_mem_malloc(sizeof(tCsrRoamInfo)); + if (NULL == roam_info) { + sms_log(mac_ctx, LOG1, FL("Memory allocation failed!")); + } else { + qdf_mem_copy((void *)roam_info->bssid.bytes, + (void *)bssid, sizeof(struct qdf_mac_addr)); + csr_roam_call_callback(mac_ctx, session_id, roam_info, 0, + status, 0); + qdf_mem_free(roam_info); + } +} +#endif + +/** + * csr_neighbor_roam_update_fast_roaming_enabled() - update roaming capability + * + * @mac_ctx: Global MAC context + * @session_id: Session + * @fast_roam_enabled: Is fast roaming enabled on this device? + * This capability can be changed dynamically. + * + * Return: None + */ +QDF_STATUS csr_neighbor_roam_update_fast_roaming_enabled(tpAniSirGlobal mac_ctx, + uint8_t session_id, + const bool fast_roam_enabled) +{ + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + tpCsrNeighborRoamControlInfo neighbor_roam_info = + &mac_ctx->roam.neighborRoamInfo[session_id]; + + switch (neighbor_roam_info->neighborRoamState) { + case eCSR_NEIGHBOR_ROAM_STATE_CONNECTED: + if (fast_roam_enabled) { + csr_roam_offload_scan(mac_ctx, session_id, + ROAM_SCAN_OFFLOAD_START, + REASON_CONNECT); + } else { + csr_roam_offload_scan(mac_ctx, session_id, + ROAM_SCAN_OFFLOAD_STOP, + REASON_DISCONNECTED); + } + break; + case eCSR_NEIGHBOR_ROAM_STATE_INIT: + NEIGHBOR_ROAM_DEBUG(mac_ctx, LOG2, + FL + ("Currently in INIT state, Nothing to do")); + break; + default: + NEIGHBOR_ROAM_DEBUG(mac_ctx, LOGE, + FL + ("Unexpected state %s, returning failure"), + mac_trace_get_neighbour_roam_state + (neighbor_roam_info->neighborRoamState)); + qdf_status = QDF_STATUS_E_FAILURE; + break; + } + return qdf_status; +} +QDF_STATUS csr_neighbor_roam_update_config(tpAniSirGlobal mac_ctx, + uint8_t session_id, uint8_t value, uint8_t reason) +{ + tpCsrNeighborRoamControlInfo pNeighborRoamInfo = + &mac_ctx->roam.neighborRoamInfo[session_id]; + tpCsrNeighborRoamCfgParams cfg_params; + eCsrNeighborRoamState state; + uint8_t old_value; + + if (NULL == pNeighborRoamInfo) { + sms_log(mac_ctx, LOG1, FL("Invalid Session ID %d"), session_id); + return QDF_STATUS_E_FAILURE; + } + cfg_params = &pNeighborRoamInfo->cfgParams; + state = pNeighborRoamInfo->neighborRoamState; + if ((state == eCSR_NEIGHBOR_ROAM_STATE_CONNECTED) || + state == eCSR_NEIGHBOR_ROAM_STATE_INIT) { + switch (reason) { + case REASON_LOOKUP_THRESH_CHANGED: + old_value = cfg_params->neighborLookupThreshold; + cfg_params->neighborLookupThreshold = value; + pNeighborRoamInfo->currentNeighborLookupThreshold = + value; + break; + case REASON_OPPORTUNISTIC_THRESH_DIFF_CHANGED: + old_value = cfg_params->nOpportunisticThresholdDiff; + cfg_params->nOpportunisticThresholdDiff = value; + pNeighborRoamInfo->currentOpportunisticThresholdDiff = + value; + break; + case REASON_ROAM_RESCAN_RSSI_DIFF_CHANGED: + old_value = cfg_params->nRoamRescanRssiDiff; + cfg_params->nRoamRescanRssiDiff = value; + pNeighborRoamInfo->currentRoamRescanRssiDiff = value; + break; + case REASON_ROAM_BMISS_FIRST_BCNT_CHANGED: + old_value = cfg_params->nRoamBmissFirstBcnt; + cfg_params->nRoamBmissFirstBcnt = value; + pNeighborRoamInfo->currentRoamBmissFirstBcnt = value; + break; + case REASON_ROAM_BMISS_FINAL_BCNT_CHANGED: + old_value = cfg_params->nRoamBmissFinalBcnt; + cfg_params->nRoamBmissFinalBcnt = value; + pNeighborRoamInfo->currentRoamBmissFinalBcnt = value; + break; + case REASON_ROAM_BEACON_RSSI_WEIGHT_CHANGED: + old_value = cfg_params->nRoamBeaconRssiWeight; + cfg_params->nRoamBeaconRssiWeight = value; + pNeighborRoamInfo->currentRoamBeaconRssiWeight = value; + break; + default: + sms_log(mac_ctx, LOG2, FL("Unknown update cfg reason")); + return QDF_STATUS_E_FAILURE; + } + } else { + sms_log(mac_ctx, LOGE, FL("Unexpected state %s, return fail"), + mac_trace_get_neighbour_roam_state(state)); + return QDF_STATUS_E_FAILURE; + } + if (state == eCSR_NEIGHBOR_ROAM_STATE_CONNECTED) { + sms_log(mac_ctx, LOG2, FL("CONNECTED, send update cfg cmd")); + csr_roam_offload_scan(mac_ctx, session_id, + ROAM_SCAN_OFFLOAD_UPDATE_CFG, reason); + } + sms_log(mac_ctx, LOG2, FL("LFR config for %s changed from %d to %d"), + lfr_get_config_item_string(reason), old_value, value); + return QDF_STATUS_SUCCESS; +} + +/*CleanUP Routines*/ +static void csr_neighbor_roam_reset_channel_info(tpCsrNeighborRoamChannelInfo + rChInfo) +{ + if ((rChInfo->IAPPNeighborListReceived == false) && + (rChInfo->currentChannelListInfo.numOfChannels)) { + rChInfo->currentChanIndex = + CSR_NEIGHBOR_ROAM_INVALID_CHANNEL_INDEX; + rChInfo->currentChannelListInfo.numOfChannels = 0; + + if (rChInfo->currentChannelListInfo.ChannelList) + qdf_mem_free(rChInfo->currentChannelListInfo. + ChannelList); + + rChInfo->currentChannelListInfo.ChannelList = NULL; + } else { + rChInfo->currentChanIndex = 0; + } +} + +/** + * csr_neighbor_roam_reset_connected_state_control_info() + * + * @mac_ctx: Pointer to Global MAC structure + * @sessionId : session id + * + * This function will reset the neighbor roam control info data structures. + * This function should be invoked whenever we move to CONNECTED state from + * any state other than INIT state + * + * Return: None + */ +static void csr_neighbor_roam_reset_connected_state_control_info( + tpAniSirGlobal pMac, + uint8_t sessionId) +{ + tpCsrNeighborRoamControlInfo pNeighborRoamInfo = + &pMac->roam.neighborRoamInfo[sessionId]; + + csr_neighbor_roam_reset_channel_info(&pNeighborRoamInfo->roamChannelInfo); + csr_neighbor_roam_free_roamable_bss_list(pMac, + &pNeighborRoamInfo->roamableAPList); + + /* Do not free up the preauth done list here */ + pNeighborRoamInfo->FTRoamInfo.currentNeighborRptRetryNum = 0; + pNeighborRoamInfo->FTRoamInfo.neighborRptPending = false; + pNeighborRoamInfo->FTRoamInfo.numPreAuthRetries = 0; + pNeighborRoamInfo->FTRoamInfo.numBssFromNeighborReport = 0; + pNeighborRoamInfo->FTRoamInfo.preauthRspPending = 0; + qdf_mem_zero(pNeighborRoamInfo->FTRoamInfo.neighboReportBssInfo, + sizeof(tCsrNeighborReportBssInfo) * + MAX_BSS_IN_NEIGHBOR_RPT); + pNeighborRoamInfo->uOsRequestedHandoff = 0; + qdf_mem_zero(&pNeighborRoamInfo->handoffReqInfo, + sizeof(tCsrHandoffRequest)); +} + +static void csr_neighbor_roam_reset_report_scan_state_control_info( + tpAniSirGlobal pMac, + uint8_t sessionId) +{ + tpCsrNeighborRoamControlInfo pNeighborRoamInfo = + &pMac->roam.neighborRoamInfo[sessionId]; + + qdf_zero_macaddr(&pNeighborRoamInfo->currAPbssid); +#ifdef FEATURE_WLAN_ESE + pNeighborRoamInfo->isESEAssoc = false; + pNeighborRoamInfo->isVOAdmitted = false; + pNeighborRoamInfo->MinQBssLoadRequired = 0; +#endif + + /* Purge roamable AP list */ + csr_neighbor_roam_free_roamable_bss_list(pMac, + &pNeighborRoamInfo->roamableAPList); + return; +} + +/** + * csr_neighbor_roam_reset_init_state_control_info() + * + * @mac_ctx: Pointer to Global MAC structure + * @sessionId : session id + * + * This function will reset the neighbor roam control info data structures. + * This function should be invoked whenever we move to CONNECTED state from + * INIT state + * + * Return: None + */ +static void csr_neighbor_roam_reset_init_state_control_info(tpAniSirGlobal pMac, + uint8_t sessionId) +{ + csr_neighbor_roam_reset_connected_state_control_info(pMac, sessionId); + + /* In addition to the above resets, + we should clear off the curAPBssId/Session ID in the timers */ + csr_neighbor_roam_reset_report_scan_state_control_info(pMac, sessionId); +} + +/** + * csr_neighbor_roam_prepare_scan_profile_filter() + * + * @mac_ctx: Pointer to Global MAC structure + * @session_id: Session ID + * @scan_filter: Populated scan filter based on the connected profile + * + * This function creates a scan filter based on the currently + * connected profile. Based on this filter, scan results are obtained + * + * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_FAILURE otherwise + */ +QDF_STATUS +csr_neighbor_roam_prepare_scan_profile_filter(tpAniSirGlobal pMac, + tCsrScanResultFilter *pScanFilter, + uint8_t sessionId) +{ + tpCsrNeighborRoamControlInfo nbr_roam_info = + &pMac->roam.neighborRoamInfo[sessionId]; + tCsrRoamConnectedProfile *pCurProfile = + &pMac->roam.roamSession[sessionId].connectedProfile; + uint8_t i = 0; + struct roam_ext_params *roam_params; + uint8_t num_ch = 0; + + QDF_ASSERT(pScanFilter != NULL); + if (pScanFilter == NULL) + return QDF_STATUS_E_FAILURE; + + qdf_mem_zero(pScanFilter, sizeof(tCsrScanResultFilter)); + roam_params = &pMac->roam.configParam.roam_params; + /* We dont want to set BSSID based Filter */ + pScanFilter->BSSIDs.numOfBSSIDs = 0; + pScanFilter->scan_filter_for_roam = 1; + /* only for HDD requested handoff fill in the BSSID in the filter */ + if (nbr_roam_info->uOsRequestedHandoff) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + FL("OS Requested Handoff")); + pScanFilter->BSSIDs.numOfBSSIDs = 1; + pScanFilter->BSSIDs.bssid = + qdf_mem_malloc(sizeof(tSirMacAddr) * + pScanFilter->BSSIDs.numOfBSSIDs); + if (NULL == pScanFilter->BSSIDs.bssid) { + sms_log(pMac, LOGE, + FL("Scan Filter BSSID mem alloc failed")); + return QDF_STATUS_E_NOMEM; + } + + /* Populate the BSSID from handoff info received from HDD */ + for (i = 0; i < pScanFilter->BSSIDs.numOfBSSIDs; i++) { + qdf_copy_macaddr(&pScanFilter->BSSIDs.bssid[i], + &nbr_roam_info->handoffReqInfo.bssid); + } + } + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + FL("No of Allowed SSID List:%d"), + roam_params->num_ssid_allowed_list); + if (roam_params->num_ssid_allowed_list) { + pScanFilter->SSIDs.numOfSSIDs = + roam_params->num_ssid_allowed_list; + pScanFilter->SSIDs.SSIDList = + qdf_mem_malloc(sizeof(tCsrSSIDInfo) * + pScanFilter->SSIDs.numOfSSIDs); + if (NULL == pScanFilter->SSIDs.SSIDList) { + sms_log(pMac, LOGE, + FL("Scan Filter SSID mem alloc failed")); + return QDF_STATUS_E_NOMEM; + } + for (i = 0; i < roam_params->num_ssid_allowed_list; i++) { + pScanFilter->SSIDs.SSIDList[i].handoffPermitted = 1; + pScanFilter->SSIDs.SSIDList[i].ssidHidden = 0; + qdf_mem_copy((void *) + pScanFilter->SSIDs.SSIDList[i].SSID.ssId, + roam_params->ssid_allowed_list[i].ssId, + roam_params->ssid_allowed_list[i].length); + pScanFilter->SSIDs.SSIDList[i].SSID.length = + roam_params->ssid_allowed_list[i].length; + } + } else { + /* Populate all the information from the connected profile */ + pScanFilter->SSIDs.numOfSSIDs = 1; + pScanFilter->SSIDs.SSIDList = + qdf_mem_malloc(sizeof(tCsrSSIDInfo)); + if (NULL == pScanFilter->SSIDs.SSIDList) { + sms_log(pMac, LOGE, + FL("Scan Filter SSID mem alloc failed")); + return QDF_STATUS_E_NOMEM; + } + pScanFilter->SSIDs.SSIDList->handoffPermitted = 1; + pScanFilter->SSIDs.SSIDList->ssidHidden = 0; + pScanFilter->SSIDs.SSIDList->SSID.length = + pCurProfile->SSID.length; + qdf_mem_copy((void *)pScanFilter->SSIDs.SSIDList->SSID.ssId, + (void *)pCurProfile->SSID.ssId, + pCurProfile->SSID.length); + + NEIGHBOR_ROAM_DEBUG(pMac, LOG1, + FL("Filtering for SSID %.*s,length of SSID = %u"), + pScanFilter->SSIDs.SSIDList->SSID.length, + pScanFilter->SSIDs.SSIDList->SSID.ssId, + pScanFilter->SSIDs.SSIDList->SSID.length); + } + pScanFilter->authType.numEntries = 1; + pScanFilter->authType.authType[0] = pCurProfile->AuthType; + + pScanFilter->EncryptionType.numEntries = 1; /* This must be 1 */ + pScanFilter->EncryptionType.encryptionType[0] = + pCurProfile->EncryptionType; + + pScanFilter->mcEncryptionType.numEntries = 1; + pScanFilter->mcEncryptionType.encryptionType[0] = + pCurProfile->mcEncryptionType; + + pScanFilter->BSSType = pCurProfile->BSSType; + + num_ch = + nbr_roam_info->roamChannelInfo.currentChannelListInfo.numOfChannels; + if (num_ch) { + /* + * We are intrested only in the scan results on channels we + * scanned + */ + pScanFilter->ChannelInfo.numOfChannels = num_ch; + pScanFilter->ChannelInfo.ChannelList = + qdf_mem_malloc(num_ch * sizeof(uint8_t)); + if (NULL == pScanFilter->ChannelInfo.ChannelList) { + sms_log(pMac, LOGE, + FL("Scan Filter Ch list mem alloc failed")); + qdf_mem_free(pScanFilter->SSIDs.SSIDList); + pScanFilter->SSIDs.SSIDList = NULL; + return QDF_STATUS_E_NOMEM; + } + for (i = 0; i < pScanFilter->ChannelInfo.numOfChannels; i++) { + pScanFilter->ChannelInfo.ChannelList[i] = + nbr_roam_info->roamChannelInfo.currentChannelListInfo. + ChannelList[i]; + } + } else { + pScanFilter->ChannelInfo.numOfChannels = 0; + pScanFilter->ChannelInfo.ChannelList = NULL; + } + + if (nbr_roam_info->is11rAssoc) { + /* + * MDIE should be added as a part of profile. This should be + * added as a part of filter as well + */ + pScanFilter->MDID.mdiePresent = pCurProfile->MDID.mdiePresent; + pScanFilter->MDID.mobilityDomain = + pCurProfile->MDID.mobilityDomain; + } + +#ifdef WLAN_FEATURE_11W + pScanFilter->MFPEnabled = pCurProfile->MFPEnabled; + pScanFilter->MFPRequired = pCurProfile->MFPRequired; + pScanFilter->MFPCapable = pCurProfile->MFPCapable; +#endif + return QDF_STATUS_SUCCESS; +} + +/** + * csr_neighbor_roam_channels_filter_by_current_band() + * + * @mac_ctx: Pointer to Global MAC structure + * @session_id: Session ID + * @input_ch_list: The input channel list + * @input_num_of_ch: The number of channels in input channel list + * @output_ch_list: The output channel list + * @output_num_of_ch: The number of channels in output channel list + * @merged_output_num_of_ch: The final number of channels in the + * output channel list. + * + * This function is used to filter out the channels based on the + * currently associated AP channel + * + * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_FAILURE otherwise + */ +QDF_STATUS csr_neighbor_roam_channels_filter_by_current_band(tpAniSirGlobal pMac, + uint8_t sessionId, + uint8_t * + pInputChannelList, + uint8_t + inputNumOfChannels, + uint8_t * + pOutputChannelList, + uint8_t * + pMergedOutputNumOfChannels) +{ + uint8_t i = 0; + uint8_t numChannels = 0; + uint8_t currAPoperationChannel = + pMac->roam.neighborRoamInfo[sessionId].currAPoperationChannel; + /* Check for NULL pointer */ + if (!pInputChannelList) + return QDF_STATUS_E_INVAL; + + /* Check for NULL pointer */ + if (!pOutputChannelList) + return QDF_STATUS_E_INVAL; + + if (inputNumOfChannels > WNI_CFG_VALID_CHANNEL_LIST_LEN) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Wrong Number of Input Channels %d", + __func__, inputNumOfChannels); + return QDF_STATUS_E_INVAL; + } + for (i = 0; i < inputNumOfChannels; i++) { + if (get_rf_band(currAPoperationChannel) == + get_rf_band(pInputChannelList[i])) { + pOutputChannelList[numChannels] = pInputChannelList[i]; + numChannels++; + } + } + + /* Return final number of channels */ + *pMergedOutputNumOfChannels = numChannels; + + return QDF_STATUS_SUCCESS; +} + +/** + * csr_neighbor_roam_channels_filter_by_current_band() + * + * @mac_ctx: Pointer to Global MAC structure + * @session_id: Session ID + * @input_ch_list: The additional channels to merge in to the + * "merged" channels list. + * @input_num_of_ch: The number of additional channels. + * @output_ch_list: The place to put the "merged" channel list. + * @output_num_of_ch: The original number of channels in the + * "merged" channels list. + * @merged_output_num_of_ch: The final number of channels in the + * "merged" channel list. + * + * This function is used to merge two channel list. + * NB: If called with outputNumOfChannels == 0, this routines simply + * copies the input channel list to the output channel list. if number + * of merged channels are more than 100, num of channels set to 100 + * + * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_FAILURE otherwise + */ +QDF_STATUS csr_neighbor_roam_merge_channel_lists(tpAniSirGlobal pMac, + uint8_t *pInputChannelList, + uint8_t inputNumOfChannels, + uint8_t *pOutputChannelList, + uint8_t outputNumOfChannels, + uint8_t * + pMergedOutputNumOfChannels) +{ + uint8_t i = 0; + uint8_t j = 0; + uint8_t numChannels = outputNumOfChannels; + + /* Check for NULL pointer */ + if (!pInputChannelList) + return QDF_STATUS_E_INVAL; + + /* Check for NULL pointer */ + if (!pOutputChannelList) + return QDF_STATUS_E_INVAL; + + if (inputNumOfChannels > WNI_CFG_VALID_CHANNEL_LIST_LEN) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Wrong Number of Input Channels %d", + __func__, inputNumOfChannels); + return QDF_STATUS_E_INVAL; + } + if (outputNumOfChannels >= WNI_CFG_VALID_CHANNEL_LIST_LEN) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Wrong Number of Output Channels %d", + __func__, outputNumOfChannels); + return QDF_STATUS_E_INVAL; + } + /* Add the "new" channels in the input list to the end of the output list. */ + for (i = 0; i < inputNumOfChannels; i++) { + for (j = 0; j < outputNumOfChannels; j++) { + if (pInputChannelList[i] == pOutputChannelList[j]) + break; + } + if (j == outputNumOfChannels) { + if (pInputChannelList[i]) { + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_INFO, + "%s: [INFOLOG] Adding extra %d to Neighbor channel list", + __func__, pInputChannelList[i]); + pOutputChannelList[numChannels] = + pInputChannelList[i]; + numChannels++; + } + } + if (numChannels >= WNI_CFG_VALID_CHANNEL_LIST_LEN) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO, + "%s: Merge Neighbor channel list reached Max " + "limit %d", __func__, numChannels); + break; + } + } + + /* Return final number of channels */ + *pMergedOutputNumOfChannels = numChannels; + + return QDF_STATUS_SUCCESS; +} + +/** + * csr_neighbor_roam_is_ssid_and_security_match() - to match ssid/security + * @pMac: Pointer to mac context + * @pCurProfile: pointer to current roam profile + * @pBssDesc: pointer to bss description + * @pIes: pointer to local ies + * + * This routine will be called to see if SSID and security parameters + * are matching. + * + * Return: bool + */ +static bool csr_neighbor_roam_is_ssid_and_security_match(tpAniSirGlobal pMac, + tCsrRoamConnectedProfile *pCurProfile, + tSirBssDescription *pBssDesc, tDot11fBeaconIEs *pIes) +{ + tCsrAuthList authType; + tCsrEncryptionList uCEncryptionType; + tCsrEncryptionList mCEncryptionType; + bool fMatch = false; + + authType.numEntries = 1; + authType.authType[0] = pCurProfile->AuthType; + uCEncryptionType.numEntries = 1; + uCEncryptionType.encryptionType[0] = pCurProfile->EncryptionType; + mCEncryptionType.numEntries = 1; + mCEncryptionType.encryptionType[0] = pCurProfile->mcEncryptionType; + + /* Again, treat missing pIes as a non-match. */ + if (!pIes) + return false; + + /* Treat a missing SSID as a non-match. */ + if (!pIes->SSID.present) + return false; + + fMatch = csr_is_ssid_match(pMac, + (void *)pCurProfile->SSID.ssId, + pCurProfile->SSID.length, + pIes->SSID.ssid, + pIes->SSID.num_ssid, true); + if (true == fMatch) { +#ifdef WLAN_FEATURE_11W + /* + * We are sending current connected APs profile setting + * if other AP doesn't have the same PMF setting as currently + * connected AP then we will have some issues in roaming. + * + * Make sure all the APs have same PMF settings to avoid + * any corner cases. + */ + fMatch = csr_is_security_match(pMac, &authType, + &uCEncryptionType, &mCEncryptionType, + &pCurProfile->MFPEnabled, + &pCurProfile->MFPRequired, + &pCurProfile->MFPCapable, + pBssDesc, pIes, NULL, NULL, NULL); +#else + fMatch = csr_is_security_match(pMac, &authType, + &uCEncryptionType, + &mCEncryptionType, NULL, + NULL, NULL, pBssDesc, + pIes, NULL, NULL, NULL); +#endif + return fMatch; + } else { + return fMatch; + } + +} + +bool csr_neighbor_roam_is_new_connected_profile(tpAniSirGlobal pMac, + uint8_t sessionId) +{ + tpCsrNeighborRoamControlInfo pNeighborRoamInfo = + &pMac->roam.neighborRoamInfo[sessionId]; + tCsrRoamConnectedProfile *pCurrProfile = NULL; + tCsrRoamConnectedProfile *pPrevProfile = NULL; + tDot11fBeaconIEs *pIes = NULL; + tSirBssDescription *pBssDesc = NULL; + bool fNew = true; + + if (!(pMac->roam.roamSession && CSR_IS_SESSION_VALID(pMac, sessionId))) { + return fNew; + } + + pCurrProfile = &pMac->roam.roamSession[sessionId].connectedProfile; + if (!pCurrProfile) { + return fNew; + } + + pPrevProfile = &pNeighborRoamInfo->prevConnProfile; + if (!pPrevProfile) { + return fNew; + } + + pBssDesc = pPrevProfile->pBssDesc; + if (pBssDesc) { + if (QDF_IS_STATUS_SUCCESS( + csr_get_parsed_bss_description_ies(pMac, pBssDesc, &pIes)) + && csr_neighbor_roam_is_ssid_and_security_match(pMac, + pCurrProfile, pBssDesc, pIes)) { + fNew = false; + } + if (pIes) { + qdf_mem_free(pIes); + } + } + + if (fNew) { + sms_log(pMac, LOG1, + FL("Prev roam profile did not match current")); + } else { + sms_log(pMac, LOG1, FL("Prev roam profile matches current")); + } + + return fNew; +} + +bool csr_neighbor_roam_connected_profile_match(tpAniSirGlobal pMac, + uint8_t sessionId, + tCsrScanResult *pResult, + tDot11fBeaconIEs *pIes) +{ + tCsrRoamConnectedProfile *pCurProfile = NULL; + tSirBssDescription *pBssDesc = &pResult->Result.BssDescriptor; + + if (!(pMac->roam.roamSession && CSR_IS_SESSION_VALID(pMac, sessionId))) { + return false; + } + + pCurProfile = &pMac->roam.roamSession[sessionId].connectedProfile; + + if (!pCurProfile) { + return false; + } + + return csr_neighbor_roam_is_ssid_and_security_match(pMac, pCurProfile, + pBssDesc, pIes); +} + +/** + * csr_roam_reset_roam_params - API to reset the roaming parameters + * @mac_ctx: Pointer to the global MAC structure + * + * The BSSID blacklist should not be cleared since it has to + * be used across connections. These parameters will be cleared + * and sent to firmware with with the roaming STOP command. + * + * Return: VOID + */ +void csr_roam_reset_roam_params(tpAniSirGlobal mac_ctx) +{ + struct roam_ext_params *roam_params = NULL; + + /* + * clear all the whitelist parameters and remaining + * needs to be retained across connections. + */ + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + FL("Roaming parameters are reset")); + roam_params = &mac_ctx->roam.configParam.roam_params; + roam_params->num_ssid_allowed_list = 0; + qdf_mem_set(&roam_params->ssid_allowed_list, 0, + sizeof(tSirMacSSid) * MAX_SSID_ALLOWED_LIST); +} + +/** + * csr_neighbor_roam_indicate_disconnect() - To indicate disconnect + * @pMac: The handle returned by mac_open + * @sessionId: CSR session id that got disconnected + * + * This function is called by CSR as soon as the station disconnects + * from the AP. This function does the necessary cleanup of neighbor roam + * data structures. Neighbor roam state transitions to INIT state whenever + * this function is called except if the current state is REASSOCIATING + * + * Return: QDF_STATUS + */ +QDF_STATUS csr_neighbor_roam_indicate_disconnect(tpAniSirGlobal pMac, + uint8_t sessionId) +{ + tpCsrNeighborRoamControlInfo pNeighborRoamInfo = + &pMac->roam.neighborRoamInfo[sessionId]; + tCsrRoamConnectedProfile *pPrevProfile = + &pNeighborRoamInfo->prevConnProfile; + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + tCsrRoamSession *roam_session = NULL; + + if (NULL == pSession) { + sms_log(pMac, LOGE, FL("pSession is NULL")); + return QDF_STATUS_E_FAILURE; + } + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO, + FL("Disconn ind on session %d in state %d from bss :" + MAC_ADDRESS_STR), sessionId, + pNeighborRoamInfo->neighborRoamState, + MAC_ADDR_ARRAY(pSession->connectedProfile.bssid.bytes)); + /* + * Free the current previous profile and move + * the current profile to prev profile. + */ + csr_roam_free_connect_profile(pPrevProfile); + csr_roam_copy_connect_profile(pMac, sessionId, pPrevProfile); + /* + * clear the roaming parameters that are per connection. + * For a new connection, they have to be programmed again. + */ + if (!csr_neighbor_middle_of_roaming((tHalHandle)pMac, sessionId)) + csr_roam_reset_roam_params(pMac); + if (NULL != pSession) { + roam_session = &pMac->roam.roamSession[sessionId]; + if (NULL != pSession->pCurRoamProfile && (QDF_STA_MODE != + roam_session->pCurRoamProfile->csrPersona)) { + sms_log(pMac, LOGE, + FL("Ignore disconn ind rcvd from nonSTA persona" + "sessionId: %d, csrPersonna %d"), + sessionId, + (int)roam_session->pCurRoamProfile->csrPersona); + return QDF_STATUS_SUCCESS; + } +#ifdef FEATURE_WLAN_ESE + if (pSession->connectedProfile.isESEAssoc) { + qdf_mem_copy(&pSession->prevApSSID, + &pSession->connectedProfile.SSID, + sizeof(tSirMacSSid)); + qdf_copy_macaddr(&pSession->prevApBssid, + &pSession->connectedProfile.bssid); + pSession->prevOpChannel = + pSession->connectedProfile.operationChannel; + pSession->isPrevApInfoValid = true; + pSession->roamTS1 = qdf_mc_timer_get_system_time(); + } +#endif + } + + switch (pNeighborRoamInfo->neighborRoamState) { + case eCSR_NEIGHBOR_ROAM_STATE_REASSOCIATING: + /* + * Stop scan and neighbor refresh timers. + * These are indeed not required when we'r in reassoc state. + */ + if (!CSR_IS_ROAM_SUBSTATE_DISASSOC_HO(pMac, sessionId)) { + /* + * Disconnect indication during Disassoc Handoff + * sub-state is received when we are trying to + * disconnect with the old AP during roam. + * BUT, if receive a disconnect indication outside of + * Disassoc Handoff sub-state, then it means that + * this is a genuine disconnect and we need to clean up. + * Otherwise, we will be stuck in reassoc state which'll + * in-turn block scans. + */ + csr_neighbor_roam_state_transition(pMac, + eCSR_NEIGHBOR_ROAM_STATE_INIT, sessionId); + pNeighborRoamInfo->roamChannelInfo. + IAPPNeighborListReceived = false; + pNeighborRoamInfo->uOsRequestedHandoff = 0; + } + break; + + case eCSR_NEIGHBOR_ROAM_STATE_INIT: + csr_neighbor_roam_reset_init_state_control_info(pMac, + sessionId); + break; + + case eCSR_NEIGHBOR_ROAM_STATE_CONNECTED: + csr_neighbor_roam_state_transition(pMac, + eCSR_NEIGHBOR_ROAM_STATE_INIT, sessionId); + pNeighborRoamInfo->roamChannelInfo.IAPPNeighborListReceived = + false; + csr_neighbor_roam_reset_connected_state_control_info(pMac, + sessionId); + break; + + case eCSR_NEIGHBOR_ROAM_STATE_PREAUTH_DONE: + /* Stop pre-auth to reassoc interval timer */ + qdf_mc_timer_stop(&pSession->ftSmeContext. + preAuthReassocIntvlTimer); + case eCSR_NEIGHBOR_ROAM_STATE_PREAUTHENTICATING: + csr_neighbor_roam_state_transition(pMac, + eCSR_NEIGHBOR_ROAM_STATE_INIT, sessionId); + pNeighborRoamInfo->roamChannelInfo.IAPPNeighborListReceived = + false; + csr_neighbor_roam_reset_preauth_control_info(pMac, sessionId); + csr_neighbor_roam_reset_report_scan_state_control_info(pMac, + sessionId); + break; + default: + NEIGHBOR_ROAM_DEBUG(pMac, LOGW, FL("Received disconnect event" + "in state %s "), + mac_trace_get_neighbour_roam_state( + pNeighborRoamInfo->neighborRoamState)); + NEIGHBOR_ROAM_DEBUG(pMac, LOGW, FL("Transit to INIT state")); + csr_neighbor_roam_state_transition(pMac, + eCSR_NEIGHBOR_ROAM_STATE_INIT, sessionId); + pNeighborRoamInfo->roamChannelInfo. + IAPPNeighborListReceived = false; + pNeighborRoamInfo->uOsRequestedHandoff = 0; + break; + } + /*Inform the Firmware to STOP Scanning as the host has a disconnect. */ + if (csr_roam_is_sta_mode(pMac, sessionId)) { + csr_roam_offload_scan(pMac, sessionId, ROAM_SCAN_OFFLOAD_STOP, + REASON_DISCONNECTED); + } + + return QDF_STATUS_SUCCESS; +} + +/** + * csr_neighbor_roam_info_ctx_init() - Initialize neighbor roam struct + * @pMac: mac context + * @session_id: Session Id + * + * This initializes all the necessary data structures related to the + * associated AP. + * + * Return: QDF status + */ +static void csr_neighbor_roam_info_ctx_init( + tpAniSirGlobal pMac, + uint8_t session_id) +{ + tpCsrNeighborRoamControlInfo ngbr_roam_info = + &pMac->roam.neighborRoamInfo[session_id]; + tCsrRoamSession *session = &pMac->roam.roamSession[session_id]; + + int init_ft_flag = false; + + /* + * Initialize the occupied list ONLY if we are + * transitioning from INIT state to CONNECTED state. + */ + if (eCSR_NEIGHBOR_ROAM_STATE_INIT == + ngbr_roam_info->neighborRoamState) + csr_init_occupied_channels_list(pMac, session_id); + csr_neighbor_roam_state_transition(pMac, + eCSR_NEIGHBOR_ROAM_STATE_CONNECTED, session_id); + + qdf_copy_macaddr(&ngbr_roam_info->currAPbssid, + &session->connectedProfile.bssid); + ngbr_roam_info->currAPoperationChannel = + session->connectedProfile.operationChannel; + ngbr_roam_info->currentNeighborLookupThreshold = + ngbr_roam_info->cfgParams.neighborLookupThreshold; + ngbr_roam_info->currentOpportunisticThresholdDiff = + ngbr_roam_info->cfgParams.nOpportunisticThresholdDiff; + ngbr_roam_info->currentRoamRescanRssiDiff = + ngbr_roam_info->cfgParams.nRoamRescanRssiDiff; + ngbr_roam_info->currentRoamBmissFirstBcnt = + ngbr_roam_info->cfgParams.nRoamBmissFirstBcnt; + ngbr_roam_info->currentRoamBmissFinalBcnt = + ngbr_roam_info->cfgParams.nRoamBmissFinalBcnt; + ngbr_roam_info->currentRoamBeaconRssiWeight = + ngbr_roam_info->cfgParams.nRoamBeaconRssiWeight; + + /** + * Now we can clear the preauthDone that + * was saved as we are connected afresh */ + csr_neighbor_roam_free_roamable_bss_list(pMac, + &ngbr_roam_info->FTRoamInfo.preAuthDoneList); + + /* Based on the auth scheme tell if we are 11r */ + if (csr_is_auth_type11r + (session->connectedProfile.AuthType, + session->connectedProfile.MDID.mdiePresent)) { + if (pMac->roam.configParam.isFastTransitionEnabled) + init_ft_flag = true; + ngbr_roam_info->is11rAssoc = true; + } else + ngbr_roam_info->is11rAssoc = false; + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO_HIGH, + FL("11rAssoc is = %d"), ngbr_roam_info->is11rAssoc); + +#ifdef FEATURE_WLAN_ESE + /* Based on the auth scheme tell if we are 11r */ + if (session->connectedProfile.isESEAssoc) { + if (pMac->roam.configParam.isFastTransitionEnabled) + init_ft_flag = true; + ngbr_roam_info->isESEAssoc = true; + } else + ngbr_roam_info->isESEAssoc = false; + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO_HIGH, + FL("isESEAssoc is = %d ft = %d"), + ngbr_roam_info->isESEAssoc, init_ft_flag); +#endif + /* If "Legacy Fast Roaming" is enabled */ + if (csr_roam_is_fast_roam_enabled(pMac, session_id)) + init_ft_flag = true; + if (init_ft_flag == false) + return; + /* Initialize all the data structures needed for the 11r FT Preauth */ + ngbr_roam_info->FTRoamInfo.currentNeighborRptRetryNum = 0; + csr_neighbor_roam_purge_preauth_failed_list(pMac); + if (csr_roam_is_roam_offload_scan_enabled(pMac)) { + /* + * If this is not a INFRA type BSS, then do not send the command + * down to firmware.Do not send the START command for + * other session connections.*/ + if (!csr_roam_is_sta_mode(pMac, session_id)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "Wrong Mode %d", + session->connectedProfile.BSSType); + return; + } + ngbr_roam_info->uOsRequestedHandoff = 0; +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + if (session->roam_synch_in_progress) { + if (pMac->roam.pReassocResp != NULL) { + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_DEBUG, + "Free Reassoc Rsp"); + qdf_mem_free(pMac->roam.pReassocResp); + pMac->roam.pReassocResp = NULL; + } + } else +#endif + csr_roam_offload_scan(pMac, session_id, + ROAM_SCAN_OFFLOAD_START, + REASON_CONNECT); + } +} + +/** + * csr_neighbor_roam_indicate_connect() + * @pMac: mac context + * @session_id: Session Id + * @qdf_status: QDF status + * + * This function is called by CSR as soon as the station connects to an AP. + * This initializes all the necessary data structures related to the + * associated AP and transitions the state to CONNECTED state + * + * Return: QDF status + */ +QDF_STATUS csr_neighbor_roam_indicate_connect( + tpAniSirGlobal pMac, uint8_t session_id, + QDF_STATUS qdf_status) +{ + tpCsrNeighborRoamControlInfo ngbr_roam_info = + &pMac->roam.neighborRoamInfo[session_id]; + tCsrRoamSession *session = &pMac->roam.roamSession[session_id]; +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + tCsrRoamInfo roamInfo; + tpSirSetActiveModeSetBncFilterReq msg; +#endif + QDF_STATUS status = QDF_STATUS_SUCCESS; + + /* if session id invalid then we need return failure */ + if (NULL == ngbr_roam_info || !CSR_IS_SESSION_VALID(pMac, session_id) + || (NULL == pMac->roam.roamSession[session_id].pCurRoamProfile)) { + return QDF_STATUS_E_FAILURE; + } + + sms_log(pMac, LOG2, + FL("Connect ind. received with session id %d in state %s"), + session_id, mac_trace_get_neighbour_roam_state( + ngbr_roam_info->neighborRoamState)); + + /* Bail out if this is NOT a STA persona */ + if (pMac->roam.roamSession[session_id].pCurRoamProfile->csrPersona != + QDF_STA_MODE) { + sms_log(pMac, LOGE, + FL("Ignoring Connect ind received from a non STA." + "session_id: %d, csrPersonna %d"), session_id, + (int)session->pCurRoamProfile->csrPersona); + return QDF_STATUS_SUCCESS; + } + /* if a concurrent session is running */ + if ((false == + CSR_IS_FASTROAM_IN_CONCURRENCY_INI_FEATURE_ENABLED(pMac)) && + (csr_is_concurrent_session_running(pMac))) { + sms_log(pMac, LOGE, + FL("Ignoring Connect ind. received in multisession %d"), + csr_is_concurrent_session_running(pMac)); + return QDF_STATUS_SUCCESS; + } +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + if (session->roam_synch_in_progress && + (eSIR_ROAM_AUTH_STATUS_AUTHENTICATED == + session->roam_synch_data->authStatus)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "LFR3:csr_neighbor_roam_indicate_connect"); + msg = qdf_mem_malloc(sizeof(tSirSetActiveModeSetBncFilterReq)); + if (msg == NULL) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "LFR3:Mem Alloc failed for beacon Filter Req"); + return QDF_STATUS_E_NOMEM; + } + msg->messageType = eWNI_SME_SET_BCN_FILTER_REQ; + msg->length = sizeof(tSirSetActiveModeSetBncFilterReq); + msg->seesionId = session_id; + qdf_copy_macaddr(&msg->bssid, + &session->connectedProfile.bssid); + status = cds_send_mb_message_to_mac(msg); + qdf_copy_macaddr(&roamInfo.peerMac, + &session->connectedProfile.bssid); + roamInfo.roamSynchInProgress = + session->roam_synch_in_progress; + csr_roam_call_callback(pMac, session_id, &roamInfo, 0, + eCSR_ROAM_SET_KEY_COMPLETE, + eCSR_ROAM_RESULT_AUTHENTICATED); + csr_neighbor_roam_reset_init_state_control_info(pMac, + session_id); + csr_neighbor_roam_info_ctx_init(pMac, session_id); + + return status; + } +#endif + + switch (ngbr_roam_info->neighborRoamState) { + case eCSR_NEIGHBOR_ROAM_STATE_REASSOCIATING: + if (QDF_STATUS_SUCCESS != qdf_status) { + /** + * Just transition the state to INIT state.Rest of the + * clean up happens when we get next connect indication + */ + csr_neighbor_roam_state_transition(pMac, + eCSR_NEIGHBOR_ROAM_STATE_INIT, session_id); + ngbr_roam_info->roamChannelInfo.IAPPNeighborListReceived = + false; + ngbr_roam_info->uOsRequestedHandoff = 0; + break; + } + /* Fall through if the status is SUCCESS */ + case eCSR_NEIGHBOR_ROAM_STATE_INIT: + /* Reset all the data structures here */ + csr_neighbor_roam_reset_init_state_control_info(pMac, + session_id); + csr_neighbor_roam_info_ctx_init(pMac, session_id); + break; + default: + sms_log(pMac, LOGE, + FL("Connect evt received in invalid state %s Ignoring"), + mac_trace_get_neighbour_roam_state( + ngbr_roam_info->neighborRoamState)); + break; + } + return status; +} + +/* --------------------------------------------------------------------------- + + \fn csr_neighbor_roam_init11r_assoc_info + + \brief This function initializes 11r related neighbor roam data structures + + \param pMac - The handle returned by mac_open. + + \return QDF_STATUS_SUCCESS on success, corresponding error code otherwise + + ---------------------------------------------------------------------------*/ +static QDF_STATUS csr_neighbor_roam_init11r_assoc_info(tpAniSirGlobal pMac) +{ + QDF_STATUS status; + uint8_t i; + tpCsrNeighborRoamControlInfo pNeighborRoamInfo = NULL; + tpCsr11rAssocNeighborInfo pFTRoamInfo = NULL; + + for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) { + pNeighborRoamInfo = &pMac->roam.neighborRoamInfo[i]; + pFTRoamInfo = &pNeighborRoamInfo->FTRoamInfo; + + pNeighborRoamInfo->is11rAssoc = false; + pNeighborRoamInfo->cfgParams.maxNeighborRetries = + pMac->roam.configParam.neighborRoamConfig. + nMaxNeighborRetries; + + pFTRoamInfo->neighborReportTimeout = + CSR_NEIGHBOR_ROAM_REPORT_QUERY_TIMEOUT; + pFTRoamInfo->PEPreauthRespTimeout = + CSR_NEIGHBOR_ROAM_PREAUTH_RSP_WAIT_MULTIPLIER * + pNeighborRoamInfo->cfgParams.neighborScanPeriod; + pFTRoamInfo->neighborRptPending = false; + pFTRoamInfo->preauthRspPending = false; + + pFTRoamInfo->currentNeighborRptRetryNum = 0; + pFTRoamInfo->numBssFromNeighborReport = 0; + + qdf_mem_zero(pFTRoamInfo->neighboReportBssInfo, + sizeof(tCsrNeighborReportBssInfo) * + MAX_BSS_IN_NEIGHBOR_RPT); + + status = csr_ll_open(pMac->hHdd, &pFTRoamInfo->preAuthDoneList); + if (QDF_STATUS_SUCCESS != status) { + sms_log(pMac, LOGE, + FL("LL Open of preauth done AP List failed")); + return QDF_STATUS_E_RESOURCES; + } + } + return status; +} + +/* --------------------------------------------------------------------------- + + \fn csr_neighbor_roam_init + + \brief This function initializes neighbor roam data structures + + \param pMac - The handle returned by mac_open. + + \return QDF_STATUS_SUCCESS on success, corresponding error code otherwise + + ---------------------------------------------------------------------------*/ +QDF_STATUS csr_neighbor_roam_init(tpAniSirGlobal pMac, uint8_t sessionId) +{ + QDF_STATUS status; + tpCsrNeighborRoamControlInfo pNeighborRoamInfo = + &pMac->roam.neighborRoamInfo[sessionId]; + + pNeighborRoamInfo->neighborRoamState = eCSR_NEIGHBOR_ROAM_STATE_CLOSED; + pNeighborRoamInfo->prevNeighborRoamState = + eCSR_NEIGHBOR_ROAM_STATE_CLOSED; + pNeighborRoamInfo->cfgParams.maxChannelScanTime = + pMac->roam.configParam.neighborRoamConfig.nNeighborScanMaxChanTime; + pNeighborRoamInfo->cfgParams.minChannelScanTime = + pMac->roam.configParam.neighborRoamConfig.nNeighborScanMinChanTime; + pNeighborRoamInfo->cfgParams.maxNeighborRetries = 0; + pNeighborRoamInfo->cfgParams.neighborLookupThreshold = + pMac->roam.configParam.neighborRoamConfig. + nNeighborLookupRssiThreshold; + pNeighborRoamInfo->cfgParams.delay_before_vdev_stop = + pMac->roam.configParam.neighborRoamConfig. + delay_before_vdev_stop; + pNeighborRoamInfo->cfgParams.nOpportunisticThresholdDiff = + pMac->roam.configParam.neighborRoamConfig. + nOpportunisticThresholdDiff; + pNeighborRoamInfo->cfgParams.nRoamRescanRssiDiff = + pMac->roam.configParam.neighborRoamConfig.nRoamRescanRssiDiff; + pNeighborRoamInfo->cfgParams.nRoamBmissFirstBcnt = + pMac->roam.configParam.neighborRoamConfig.nRoamBmissFirstBcnt; + pNeighborRoamInfo->cfgParams.nRoamBmissFinalBcnt = + pMac->roam.configParam.neighborRoamConfig.nRoamBmissFinalBcnt; + pNeighborRoamInfo->cfgParams.nRoamBeaconRssiWeight = + pMac->roam.configParam.neighborRoamConfig.nRoamBeaconRssiWeight; + pNeighborRoamInfo->cfgParams.neighborScanPeriod = + pMac->roam.configParam.neighborRoamConfig.nNeighborScanTimerPeriod; + pNeighborRoamInfo->cfgParams.neighborResultsRefreshPeriod = + pMac->roam.configParam.neighborRoamConfig. + nNeighborResultsRefreshPeriod; + pNeighborRoamInfo->cfgParams.emptyScanRefreshPeriod = + pMac->roam.configParam.neighborRoamConfig.nEmptyScanRefreshPeriod; + + pNeighborRoamInfo->cfgParams.channelInfo.numOfChannels = + pMac->roam.configParam.neighborRoamConfig.neighborScanChanList. + numChannels; + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + FL("number of channels: %u"), + pNeighborRoamInfo->cfgParams.channelInfo.numOfChannels); + if (pNeighborRoamInfo->cfgParams.channelInfo.numOfChannels != 0) { + pNeighborRoamInfo->cfgParams.channelInfo.ChannelList = + qdf_mem_malloc(pMac->roam.configParam.neighborRoamConfig. + neighborScanChanList.numChannels); + if (NULL == + pNeighborRoamInfo->cfgParams.channelInfo.ChannelList) { + sms_log(pMac, LOGE, + FL("Memory Allocation for CFG Channel List failed")); + return QDF_STATUS_E_NOMEM; + } + } else { + pNeighborRoamInfo->cfgParams.channelInfo.ChannelList = NULL; + } + + /* Update the roam global structure from CFG */ + qdf_mem_copy(pNeighborRoamInfo->cfgParams.channelInfo.ChannelList, + pMac->roam.configParam.neighborRoamConfig. + neighborScanChanList.channelList, + pMac->roam.configParam.neighborRoamConfig. + neighborScanChanList.numChannels); + pNeighborRoamInfo->cfgParams.hi_rssi_scan_max_count = + pMac->roam.configParam.neighborRoamConfig. + nhi_rssi_scan_max_count; + pNeighborRoamInfo->cfgParams.hi_rssi_scan_rssi_delta = + pMac->roam.configParam.neighborRoamConfig. + nhi_rssi_scan_rssi_delta; + pNeighborRoamInfo->cfgParams.hi_rssi_scan_delay = + pMac->roam.configParam.neighborRoamConfig. + nhi_rssi_scan_delay; + pNeighborRoamInfo->cfgParams.hi_rssi_scan_rssi_ub = + pMac->roam.configParam.neighborRoamConfig. + nhi_rssi_scan_rssi_ub; + + qdf_zero_macaddr(&pNeighborRoamInfo->currAPbssid); + pNeighborRoamInfo->currentNeighborLookupThreshold = + pNeighborRoamInfo->cfgParams.neighborLookupThreshold; + pNeighborRoamInfo->currentOpportunisticThresholdDiff = + pNeighborRoamInfo->cfgParams.nOpportunisticThresholdDiff; + pNeighborRoamInfo->currentRoamRescanRssiDiff = + pNeighborRoamInfo->cfgParams.nRoamRescanRssiDiff; + pNeighborRoamInfo->currentRoamBmissFirstBcnt = + pNeighborRoamInfo->cfgParams.nRoamBmissFirstBcnt; + pNeighborRoamInfo->currentRoamBmissFinalBcnt = + pNeighborRoamInfo->cfgParams.nRoamBmissFinalBcnt; + pNeighborRoamInfo->currentRoamBeaconRssiWeight = + pNeighborRoamInfo->cfgParams.nRoamBeaconRssiWeight; + qdf_mem_set(&pNeighborRoamInfo->prevConnProfile, + sizeof(tCsrRoamConnectedProfile), 0); + + status = csr_ll_open(pMac->hHdd, &pNeighborRoamInfo->roamableAPList); + if (QDF_STATUS_SUCCESS != status) { + sms_log(pMac, LOGE, FL("LL Open of roam able AP List failed")); + qdf_mem_free(pNeighborRoamInfo->cfgParams.channelInfo. + ChannelList); + pNeighborRoamInfo->cfgParams.channelInfo.ChannelList = NULL; + return QDF_STATUS_E_RESOURCES; + } + + pNeighborRoamInfo->roamChannelInfo.currentChanIndex = + CSR_NEIGHBOR_ROAM_INVALID_CHANNEL_INDEX; + pNeighborRoamInfo->roamChannelInfo.currentChannelListInfo. + numOfChannels = 0; + pNeighborRoamInfo->roamChannelInfo.currentChannelListInfo.ChannelList = + NULL; + pNeighborRoamInfo->roamChannelInfo.IAPPNeighborListReceived = false; + + status = csr_neighbor_roam_init11r_assoc_info(pMac); + if (QDF_STATUS_SUCCESS != status) { + sms_log(pMac, LOGE, FL("LL Open of roam able AP List failed")); + qdf_mem_free(pNeighborRoamInfo->cfgParams.channelInfo. + ChannelList); + pNeighborRoamInfo->cfgParams.channelInfo.ChannelList = NULL; + csr_ll_close(&pNeighborRoamInfo->roamableAPList); + return QDF_STATUS_E_RESOURCES; + } + + csr_neighbor_roam_state_transition(pMac, + eCSR_NEIGHBOR_ROAM_STATE_INIT, sessionId); + pNeighborRoamInfo->roamChannelInfo.IAPPNeighborListReceived = false; + pNeighborRoamInfo->uOsRequestedHandoff = 0; + /* Set the Last Sent Cmd as RSO_STOP */ + pNeighborRoamInfo->last_sent_cmd = ROAM_SCAN_OFFLOAD_STOP; + return QDF_STATUS_SUCCESS; +} + +/* --------------------------------------------------------------------------- + + \fn csr_neighbor_roam_close + + \brief This function closes/frees all the neighbor roam data structures + + \param pMac - The handle returned by mac_open. + \param sessionId - Session identifier + \return VOID + + ---------------------------------------------------------------------------*/ +void csr_neighbor_roam_close(tpAniSirGlobal pMac, uint8_t sessionId) +{ + tpCsrNeighborRoamControlInfo pNeighborRoamInfo = + &pMac->roam.neighborRoamInfo[sessionId]; + + if (eCSR_NEIGHBOR_ROAM_STATE_CLOSED == + pNeighborRoamInfo->neighborRoamState) { + sms_log(pMac, LOGW, + FL("Neighbor Roam Algorithm Already Closed")); + return; + } + + if (pNeighborRoamInfo->cfgParams.channelInfo.ChannelList) + qdf_mem_free(pNeighborRoamInfo->cfgParams.channelInfo. + ChannelList); + + pNeighborRoamInfo->cfgParams.channelInfo.ChannelList = NULL; + + /* Should free up the nodes in the list before closing the double Linked list */ + csr_neighbor_roam_free_roamable_bss_list(pMac, + &pNeighborRoamInfo->roamableAPList); + csr_ll_close(&pNeighborRoamInfo->roamableAPList); + + if (pNeighborRoamInfo->roamChannelInfo.currentChannelListInfo. + ChannelList) { + qdf_mem_free(pNeighborRoamInfo->roamChannelInfo. + currentChannelListInfo.ChannelList); + } + + pNeighborRoamInfo->roamChannelInfo.currentChannelListInfo.ChannelList = + NULL; + pNeighborRoamInfo->roamChannelInfo.currentChanIndex = + CSR_NEIGHBOR_ROAM_INVALID_CHANNEL_INDEX; + pNeighborRoamInfo->roamChannelInfo.currentChannelListInfo. + numOfChannels = 0; + pNeighborRoamInfo->roamChannelInfo.IAPPNeighborListReceived = false; + + /* Free the profile.. */ + csr_release_profile(pMac, &pNeighborRoamInfo->csrNeighborRoamProfile); + csr_roam_free_connect_profile(&pNeighborRoamInfo->prevConnProfile); + pNeighborRoamInfo->FTRoamInfo.currentNeighborRptRetryNum = 0; + pNeighborRoamInfo->FTRoamInfo.numBssFromNeighborReport = 0; + qdf_mem_zero(pNeighborRoamInfo->FTRoamInfo.neighboReportBssInfo, + sizeof(tCsrNeighborReportBssInfo) * + MAX_BSS_IN_NEIGHBOR_RPT); + csr_neighbor_roam_free_roamable_bss_list(pMac, + &pNeighborRoamInfo->FTRoamInfo. + preAuthDoneList); + csr_ll_close(&pNeighborRoamInfo->FTRoamInfo.preAuthDoneList); + + csr_neighbor_roam_state_transition(pMac, + eCSR_NEIGHBOR_ROAM_STATE_CLOSED, sessionId); + + return; +} + +/** + * csr_neighbor_roam_is11r_assoc() - Check if association type is 11R + * @mac_ctx: MAC Global context + * @session_id: Session ID + * + * Return: true if 11r Association, false otherwise. + */ +bool csr_neighbor_roam_is11r_assoc(tpAniSirGlobal mac_ctx, uint8_t session_id) +{ + return mac_ctx->roam.neighborRoamInfo[session_id].is11rAssoc; +} + +/* --------------------------------------------------------------------------- + \brief This function returns true if STA is in the middle of roaming states + + \param halHandle - The handle from HDD context. + \param sessionId - Session identifier + + \return bool + + ---------------------------------------------------------------------------*/ +bool csr_neighbor_middle_of_roaming(tpAniSirGlobal pMac, uint8_t sessionId) +{ + tpCsrNeighborRoamControlInfo pNeighborRoamInfo = + &pMac->roam.neighborRoamInfo[sessionId]; + bool val = (eCSR_NEIGHBOR_ROAM_STATE_REASSOCIATING == + pNeighborRoamInfo->neighborRoamState) || + (eCSR_NEIGHBOR_ROAM_STATE_PREAUTHENTICATING == + pNeighborRoamInfo->neighborRoamState) || + (eCSR_NEIGHBOR_ROAM_STATE_PREAUTH_DONE == + pNeighborRoamInfo->neighborRoamState); + return val; +} + +/** + * csr_neighbor_roam_process_handoff_req - Processes handoff request + * + * @mac_ctx Pointer to mac context + * @session_id SME session id + * + * This function is called start with the handoff process. First do a + * SSID scan for the BSSID provided. + * + * Return: status + */ +static QDF_STATUS csr_neighbor_roam_process_handoff_req( + tpAniSirGlobal mac_ctx, + uint8_t session_id) +{ + tpCsrNeighborRoamControlInfo roam_ctrl_info = + &mac_ctx->roam.neighborRoamInfo[session_id]; + QDF_STATUS status = QDF_STATUS_SUCCESS; + uint32_t roam_id; + tCsrRoamProfile *profile = NULL; + tCsrRoamSession *session = CSR_GET_SESSION(mac_ctx, session_id); + uint8_t i = 0; + uint8_t roam_now = 0; + uint8_t roamable_ap_count = 0; + tCsrScanResultFilter scan_filter; + tScanResultHandle scan_result; + + if (NULL == session) { + sms_log(mac_ctx, LOGE, FL("session is NULL ")); + return QDF_STATUS_E_FAILURE; + } + + roam_id = GET_NEXT_ROAM_ID(&mac_ctx->roam); + profile = qdf_mem_malloc(sizeof(tCsrRoamProfile)); + if (NULL == profile) { + sms_log(mac_ctx, LOGE, FL("Memory alloc failed")); + return QDF_STATUS_E_NOMEM; + } + status = + csr_roam_copy_profile(mac_ctx, profile, + session->pCurRoamProfile); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sms_log(mac_ctx, LOGE, FL("Profile copy failed")); + goto end; + } + /* Add the BSSID & Channel */ + profile->BSSIDs.numOfBSSIDs = 1; + if (NULL == profile->BSSIDs.bssid) { + profile->BSSIDs.bssid = + qdf_mem_malloc(sizeof(tSirMacAddr) * + profile->BSSIDs.numOfBSSIDs); + if (NULL == profile->BSSIDs.bssid) { + sms_log(mac_ctx, LOGE, FL("mem alloc failed for BSSID")); + status = QDF_STATUS_E_NOMEM; + goto end; + } + } + + /* Populate the BSSID from handoff info received from HDD */ + for (i = 0; i < profile->BSSIDs.numOfBSSIDs; i++) { + qdf_copy_macaddr(&profile->BSSIDs.bssid[i], + &roam_ctrl_info->handoffReqInfo.bssid); + } + + profile->ChannelInfo.numOfChannels = 1; + if (NULL == profile->ChannelInfo.ChannelList) { + profile->ChannelInfo.ChannelList = + qdf_mem_malloc(sizeof(*profile-> + ChannelInfo.ChannelList) * + profile->ChannelInfo.numOfChannels); + if (NULL == profile->ChannelInfo.ChannelList) { + sms_log(mac_ctx, LOGE, + FL("mem alloc failed for ChannelList")); + status = QDF_STATUS_E_NOMEM; + goto end; + } + } + profile->ChannelInfo.ChannelList[0] = + roam_ctrl_info->handoffReqInfo.channel; + + /* + * For User space connect requests, the scan has already been done. + * So, check if the BSS descriptor exists in the scan cache and + * proceed with the handoff instead of a redundant scan again. + */ + if (roam_ctrl_info->handoffReqInfo.src == CONNECT_CMD_USERSPACE) { + sms_log(mac_ctx, LOG1, + FL("Connect cmd with bssid within same ESS")); + status = csr_neighbor_roam_prepare_scan_profile_filter(mac_ctx, + &scan_filter, + session_id); + sms_log(mac_ctx, LOG1, FL("Filter creation status = %d"), + status); + status = csr_scan_get_result(mac_ctx, &scan_filter, + &scan_result); + csr_neighbor_roam_process_scan_results(mac_ctx, session_id, + &scan_result); + roamable_ap_count = csr_ll_count( + &roam_ctrl_info->roamableAPList); + csr_free_scan_filter(mac_ctx, &scan_filter); + sms_log(mac_ctx, LOG1, FL("roam_now=%d, roamable_ap_count=%d"), + roam_now, roamable_ap_count); + } + if (roam_now && roamable_ap_count) { + csr_neighbor_roam_trigger_handoff(mac_ctx, session_id); + } else { + status = csr_scan_for_ssid(mac_ctx, session_id, profile, + roam_id, false); + if (status != QDF_STATUS_SUCCESS) + sms_log(mac_ctx, LOGE, FL("SSID scan failed")); + } + +end: + if (NULL != profile) { + csr_release_profile(mac_ctx, profile); + qdf_mem_free(profile); + } + + return status; +} + +/* --------------------------------------------------------------------------- + + \fn csr_neighbor_roam_sssid_scan_done + + \brief This function is called once SSID scan is done. If SSID scan failed + to find our candidate add an entry to csr scan cache ourself before starting + the handoff process + + \param pMac - The handle returned by mac_open. + + \return QDF_STATUS_SUCCESS on success, corresponding error code otherwise + + ---------------------------------------------------------------------------*/ +QDF_STATUS csr_neighbor_roam_sssid_scan_done(tpAniSirGlobal pMac, + uint8_t sessionId, QDF_STATUS status) +{ + tpCsrNeighborRoamControlInfo pNeighborRoamInfo = + &pMac->roam.neighborRoamInfo[sessionId]; + QDF_STATUS hstatus; + + sms_log(pMac, LOGE, FL("called ")); + + /* we must be in connected state, if not ignore it */ + if (eCSR_NEIGHBOR_ROAM_STATE_CONNECTED != + pNeighborRoamInfo->neighborRoamState) { + sms_log(pMac, LOGE, + FL("Received in not CONNECTED state. Ignore it")); + return QDF_STATUS_E_FAILURE; + } + /* if SSID scan failed to find our candidate add an entry to csr scan cache ourself */ + if (!QDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOGE, FL("Add an entry to csr scan cache")); + hstatus = csr_scan_create_entry_in_scan_cache(pMac, sessionId, + pNeighborRoamInfo-> + handoffReqInfo.bssid, + pNeighborRoamInfo-> + handoffReqInfo.channel); + if (QDF_STATUS_SUCCESS != hstatus) { + sms_log(pMac, LOGE, + FL + ("csr_scan_create_entry_in_scan_cache failed with status %d"), + hstatus); + return QDF_STATUS_E_FAILURE; + } + } + + /* Now we have completed scanning for the candidate provided by HDD. Let move on to HO */ + hstatus = csr_neighbor_roam_process_scan_complete(pMac, sessionId); + + if (QDF_STATUS_SUCCESS != hstatus) { + sms_log(pMac, LOGE, + FL + ("Neighbor scan process complete failed with status %d"), + hstatus); + return QDF_STATUS_E_FAILURE; + } + return QDF_STATUS_SUCCESS; +} + + +/** + * csr_neighbor_roam_handoff_req_hdlr - Processes handoff request + * @mac_ctx Pointer to mac context + * @msg message sent to HDD + * + * This function is called by CSR as soon as it gets a handoff request + * to SME via MC thread + * + * Return: status + */ +QDF_STATUS csr_neighbor_roam_handoff_req_hdlr( + tpAniSirGlobal mac_ctx, void *msg) +{ + tAniHandoffReq *handoff_req = (tAniHandoffReq *) msg; + uint32_t session_id = handoff_req->sessionId; + tpCsrNeighborRoamControlInfo roam_ctrl_info = + &mac_ctx->roam.neighborRoamInfo[session_id]; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + /* we must be in connected state, if not ignore it */ + if (eCSR_NEIGHBOR_ROAM_STATE_CONNECTED != + roam_ctrl_info->neighborRoamState) { + sms_log(mac_ctx, LOGE, + FL("Received in not CONNECTED state. Ignore it")); + return QDF_STATUS_E_FAILURE; + } + + /* save the handoff info came from HDD as part of the reassoc req */ + handoff_req = (tAniHandoffReq *) msg; + if (NULL == handoff_req) { + sms_log(mac_ctx, LOGE, FL("Received msg is NULL")); + return QDF_STATUS_E_FAILURE; + } + + /* sanity check */ + if (!qdf_mem_cmp(handoff_req->bssid, + roam_ctrl_info->currAPbssid.bytes, + sizeof(tSirMacAddr))) { + sms_log(mac_ctx, LOGE, + FL + ("Received req has same BSSID as current AP!!")); + return QDF_STATUS_E_FAILURE; + } + roam_ctrl_info->handoffReqInfo.channel = + handoff_req->channel; + roam_ctrl_info->handoffReqInfo.src = + handoff_req->handoff_src; + qdf_mem_copy(&roam_ctrl_info->handoffReqInfo.bssid.bytes, + &handoff_req->bssid, QDF_MAC_ADDR_SIZE); + roam_ctrl_info->uOsRequestedHandoff = 1; + status = csr_roam_offload_scan(mac_ctx, session_id, + ROAM_SCAN_OFFLOAD_STOP, + REASON_OS_REQUESTED_ROAMING_NOW); + if (QDF_STATUS_SUCCESS != status) { + sms_log(mac_ctx, LOGE, + FL("csr_roam_offload_scan failed")); + roam_ctrl_info->uOsRequestedHandoff = 0; + } + return status; +} + +/** + * csr_neighbor_roam_proceed_with_handoff_req() + * + * @mac_ctx: Pointer to Global MAC structure + * @session_id: Session ID + * + * This function is called by CSR as soon as it gets rsp back for + * ROAM_SCAN_OFFLOAD_STOP with reason REASON_OS_REQUESTED_ROAMING_NOW + * + * Return: QDF_STATUS_SUCCESS on success, corresponding error code otherwise + */ +QDF_STATUS csr_neighbor_roam_proceed_with_handoff_req(tpAniSirGlobal pMac, + uint8_t sessionId) +{ + tpCsrNeighborRoamControlInfo pNeighborRoamInfo = + &pMac->roam.neighborRoamInfo[sessionId]; + QDF_STATUS status = QDF_STATUS_SUCCESS; + /* we must be in connected state, if not ignore it */ + if ((eCSR_NEIGHBOR_ROAM_STATE_CONNECTED != + pNeighborRoamInfo->neighborRoamState) + || (!pNeighborRoamInfo->uOsRequestedHandoff)) { + sms_log(pMac, LOGE, + FL("Received in not CONNECTED state(%d) or uOsRequestedHandoff(%d) is not set. Ignore it"), + pNeighborRoamInfo->neighborRoamState, + pNeighborRoamInfo->uOsRequestedHandoff); + status = QDF_STATUS_E_FAILURE; + } else { + /* Let's go ahead with handoff */ + status = csr_neighbor_roam_process_handoff_req(pMac, sessionId); + } + if (!QDF_IS_STATUS_SUCCESS(status)) { + pNeighborRoamInfo->uOsRequestedHandoff = 0; + } + return status; +} + +/* --------------------------------------------------------------------------- + + \fn csr_neighbor_roam_start_lfr_scan + + \brief This function is called if HDD requested handoff failed for some + reason. start the LFR logic at that point.By the time, this function is + called, a STOP command has already been issued. + + \param pMac - The handle returned by mac_open. + + \return QDF_STATUS_SUCCESS on success, corresponding error code otherwise + + ---------------------------------------------------------------------------*/ +QDF_STATUS csr_neighbor_roam_start_lfr_scan(tpAniSirGlobal pMac, uint8_t sessionId) +{ + tpCsrNeighborRoamControlInfo pNeighborRoamInfo = + &pMac->roam.neighborRoamInfo[sessionId]; + pNeighborRoamInfo->uOsRequestedHandoff = 0; + /* There is no candidate or We are not roaming Now. + * Inform the FW to restart Roam Offload Scan */ + csr_roam_offload_scan(pMac, sessionId, ROAM_SCAN_OFFLOAD_START, + REASON_NO_CAND_FOUND_OR_NOT_ROAMING_NOW); + + return QDF_STATUS_SUCCESS; +} diff --git a/drivers/staging/qcacld-3.0/core/sme/src/csr/csr_roam_preauth.c b/drivers/staging/qcacld-3.0/core/sme/src/csr/csr_roam_preauth.c new file mode 100644 index 0000000000000000000000000000000000000000..5a372f0f99535634cfde1a028657ccd51989421e --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/sme/src/csr/csr_roam_preauth.c @@ -0,0 +1,769 @@ +/* + * Copyright (c) 2016-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * 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. + */ + +/** + * DOC: csr_roam_preauth.c + * + * Host based roaming preauthentication implementation + */ + +#include "wma_types.h" +#include "cds_mq.h" +#include "csr_inside_api.h" +#include "sms_debug.h" +#include "sme_qos_internal.h" +#include "sme_inside.h" +#include "host_diag_core_event.h" +#include "host_diag_core_log.h" +#include "csr_api.h" +#include "sme_api.h" +#include "csr_neighbor_roam.h" +#include "mac_trace.h" +#include "cds_concurrency.h" + +static void csr_reinit_preauth_cmd(tpAniSirGlobal pMac, tSmeCmd *pCommand); +static QDF_STATUS csr_neighbor_roam_add_preauth_fail(tpAniSirGlobal mac_ctx, + uint8_t session_id, tSirMacAddr bssid); +/** + * csr_neighbor_roam_state_preauth_done() - Check if state is preauth done + * @mac_ctx: Global MAC context + * @session_id: SME session ID + * + * Return: True if the state id preauth done, false otherwise + */ +bool csr_neighbor_roam_state_preauth_done(tpAniSirGlobal mac_ctx, + uint8_t session_id) +{ + return mac_ctx->roam.neighborRoamInfo[session_id].neighborRoamState == + eCSR_NEIGHBOR_ROAM_STATE_PREAUTH_DONE; +} + +/** + * csr_neighbor_roam_tranistion_preauth_done_to_disconnected() - Transition + * the state from preauth done to disconnected + * @mac_ctx: Global MAC Context + * @session_id: SME Session ID + * + * In the event that we are associated with AP1 and we have + * completed pre auth with AP2. Then we receive a deauth/disassoc from AP1. + * At this point neighbor roam is in pre auth done state, pre auth timer + * is running. We now handle this case by stopping timer and clearing + * the pre-auth state. We basically clear up and just go to disconnected + * state + * + * Return: None + */ +void csr_neighbor_roam_tranistion_preauth_done_to_disconnected( + tpAniSirGlobal mac_ctx, uint8_t session_id) +{ + tpCsrNeighborRoamControlInfo pNeighborRoamInfo = + &mac_ctx->roam.neighborRoamInfo[session_id]; + tCsrRoamSession *session = CSR_GET_SESSION(mac_ctx, session_id); + + if (!session) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + FL("session is NULL")); + return; + } + + if (pNeighborRoamInfo->neighborRoamState != + eCSR_NEIGHBOR_ROAM_STATE_PREAUTH_DONE) + return; + + qdf_mc_timer_stop(&session->ftSmeContext.preAuthReassocIntvlTimer); + csr_neighbor_roam_state_transition(mac_ctx, + eCSR_NEIGHBOR_ROAM_STATE_INIT, session_id); + pNeighborRoamInfo->roamChannelInfo.IAPPNeighborListReceived = false; + pNeighborRoamInfo->uOsRequestedHandoff = 0; +} + +/** + * csr_reinit_preauth_cmd() - Cleanup the preauth command + * @mac_ctx: Global MAC context + * @command: Command to be cleaned up + * + * Return: None + */ +static void csr_reinit_preauth_cmd(tpAniSirGlobal mac_ctx, tSmeCmd *command) +{ + command->u.roamCmd.pLastRoamBss = NULL; + command->u.roamCmd.pRoamBssEntry = NULL; + qdf_mem_set(&command->u.roamCmd, sizeof(tRoamCmd), 0); +} + +/** + * csr_release_command_preauth() - Release the preauth command + * @mac_ctx: Global MAC context + * @command: Command to be released + * + * Return: None + */ +void csr_release_command_preauth(tpAniSirGlobal mac_ctx, tSmeCmd *command) +{ + csr_reinit_preauth_cmd(mac_ctx, command); + csr_release_command(mac_ctx, command); +} + +/** + * csr_roam_enqueue_preauth() - Put the preauth command in the queue + * @mac_ctx: Global MAC Context + * @session_id: SME Session ID + * @bss_desc: BSS descriptor + * @reason: roaming reason + * @immediate: High priority in the queue or not + * + * Return: Success if queued properly, false otherwise. + */ +QDF_STATUS csr_roam_enqueue_preauth(tpAniSirGlobal mac_ctx, + uint32_t session_id, tpSirBssDescription bss_desc, + eCsrRoamReason reason, bool immediate) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tSmeCmd *command; + + command = csr_get_command_buffer(mac_ctx); + if (NULL == command) { + sms_log(mac_ctx, LOGE, FL(" fail to get command buffer")); + status = QDF_STATUS_E_RESOURCES; + } else { + if (bss_desc) { + command->command = eSmeCommandRoam; + command->sessionId = (uint8_t) session_id; + command->u.roamCmd.roamReason = reason; + command->u.roamCmd.pLastRoamBss = bss_desc; + status = csr_queue_sme_command(mac_ctx, command, + immediate); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sms_log(mac_ctx, LOGE, + FL("fail to queue preauth,status=%d"), + status); + csr_release_command_preauth(mac_ctx, command); + } + } else { + status = QDF_STATUS_E_RESOURCES; + } + } + return status; +} + +/** + * csr_neighbor_roam_purge_preauth_failed_list() - Purge the preauth fail list + * @mac_ctx: Global MAC Context + * + * Return: None + */ +void csr_neighbor_roam_purge_preauth_failed_list(tpAniSirGlobal mac_ctx) +{ + uint8_t i; + uint8_t j; + uint8_t num_mac_addr; + tpCsrNeighborRoamControlInfo neigh_roam_info = NULL; + tpCsrPreauthFailListInfo fail_list; + + for (j = 0; j < CSR_ROAM_SESSION_MAX; j++) { + neigh_roam_info = &mac_ctx->roam.neighborRoamInfo[j]; + fail_list = &neigh_roam_info->FTRoamInfo.preAuthFailList; + num_mac_addr = fail_list->numMACAddress; + for (i = 0; i < num_mac_addr; i++) + qdf_mem_zero(fail_list->macAddress[i], + sizeof(tSirMacAddr)); + fail_list->numMACAddress = 0; + } +} + +/** + * @csr_neighbor_roam_reset_preauth_control_info - Reset preauth info + * @mac_ctx: Global MAC Context + * @session_id: SME Session ID + * + * Return: None + */ +void csr_neighbor_roam_reset_preauth_control_info(tpAniSirGlobal mac_ctx, + uint8_t session_id) +{ + tpCsrNeighborRoamControlInfo neigh_roam_info = + &mac_ctx->roam.neighborRoamInfo[session_id]; + + neigh_roam_info->is11rAssoc = false; + csr_neighbor_roam_purge_preauth_failed_list(mac_ctx); + + neigh_roam_info->FTRoamInfo.preauthRspPending = false; + neigh_roam_info->FTRoamInfo.numPreAuthRetries = 0; + neigh_roam_info->FTRoamInfo.currentNeighborRptRetryNum = 0; + neigh_roam_info->FTRoamInfo.neighborRptPending = false; + neigh_roam_info->FTRoamInfo.numBssFromNeighborReport = 0; + qdf_mem_zero(neigh_roam_info->FTRoamInfo.neighboReportBssInfo, + sizeof(tCsrNeighborReportBssInfo) * + MAX_BSS_IN_NEIGHBOR_RPT); + neigh_roam_info->uOsRequestedHandoff = 0; + qdf_mem_zero(&neigh_roam_info->handoffReqInfo, + sizeof(tCsrHandoffRequest)); +} + +/** + * csr_neighbor_roam_preauth_rsp_handler() - handle preauth response + * @mac_ctx: The handle returned by mac_open. + * @session_id: SME session + * @lim_status: eSIR_SUCCESS/eSIR_FAILURE/eSIR_LIM_MAX_STA_REACHED_ERROR/ + * eSIT_LIM_AUTH_RSP_TIMEOUT status from PE + * + * This function handle the Preauth response from PE + * Every preauth is allowed max 3 tries if it fails. If a bssid failed + * for more than MAX_TRIES, we will remove it from the list and try + * with the next node in the roamable AP list and add the BSSID to + * pre-auth failed list. If no more entries present in roamable AP list, + * transition to REPORT_SCAN state. + * + * Return: QDF_STATUS_SUCCESS on success (i.e. pre-auth processed), + * QDF_STATUS_E_FAILURE otherwise + */ +QDF_STATUS csr_neighbor_roam_preauth_rsp_handler(tpAniSirGlobal mac_ctx, + uint8_t session_id, + tSirRetStatus lim_status) +{ + tpCsrNeighborRoamControlInfo neighbor_roam_info = + &mac_ctx->roam.neighborRoamInfo[session_id]; + QDF_STATUS status = QDF_STATUS_SUCCESS; + QDF_STATUS preauth_processed = QDF_STATUS_SUCCESS; + tpCsrNeighborRoamBSSInfo preauth_rsp_node = NULL; + + if (false == neighbor_roam_info->FTRoamInfo.preauthRspPending) { + /* + * This can happen when we disconnect immediately + * after sending a pre-auth request. During processing + * of the disconnect command, we would have reset + * preauthRspPending and transitioned to INIT state. + */ + sms_log(mac_ctx, LOGW, + FL("Unexpected pre-auth response in state %d"), + neighbor_roam_info->neighborRoamState); + preauth_processed = QDF_STATUS_E_FAILURE; + goto DEQ_PREAUTH; + } + /* We can receive it in these 2 states. */ + if ((neighbor_roam_info->neighborRoamState != + eCSR_NEIGHBOR_ROAM_STATE_PREAUTHENTICATING)) { + sms_log(mac_ctx, LOGW, + FL("Preauth response received in state %s"), + mac_trace_get_neighbour_roam_state + (neighbor_roam_info->neighborRoamState)); + preauth_processed = QDF_STATUS_E_FAILURE; + goto DEQ_PREAUTH; + } + + neighbor_roam_info->FTRoamInfo.preauthRspPending = false; + + if (eSIR_SUCCESS == lim_status) + preauth_rsp_node = + csr_neighbor_roam_next_roamable_ap( + mac_ctx, &neighbor_roam_info->roamableAPList, + NULL); + if ((eSIR_SUCCESS == lim_status) && (NULL != preauth_rsp_node)) { + sms_log(mac_ctx, LOG1, + FL("Preauth completed successfully after %d tries"), + neighbor_roam_info->FTRoamInfo.numPreAuthRetries); + sms_log(mac_ctx, LOG1, + FL("After Pre-Auth: BSSID " MAC_ADDRESS_STR ", Ch:%d"), + MAC_ADDR_ARRAY( + preauth_rsp_node->pBssDescription->bssId), + (int)preauth_rsp_node->pBssDescription->channelId); + + csr_neighbor_roam_send_lfr_metric_event(mac_ctx, session_id, + preauth_rsp_node->pBssDescription->bssId, + eCSR_ROAM_PREAUTH_STATUS_SUCCESS); + /* + * Preauth completed successfully. Insert the preauthenticated + * node to tail of preAuthDoneList. + */ + csr_neighbor_roam_remove_roamable_ap_list_entry(mac_ctx, + &neighbor_roam_info->roamableAPList, + preauth_rsp_node); + csr_ll_insert_tail( + &neighbor_roam_info->FTRoamInfo.preAuthDoneList, + &preauth_rsp_node->List, LL_ACCESS_LOCK); + + csr_neighbor_roam_state_transition(mac_ctx, + eCSR_NEIGHBOR_ROAM_STATE_PREAUTH_DONE, session_id); + neighbor_roam_info->FTRoamInfo.numPreAuthRetries = 0; + + /* + * The caller of this function would start a timer and by + * the time it expires, supplicant should have provided + * the updated FTIEs to SME. So, when it expires, handoff + * will be triggered then. + */ + } else { + tpCsrNeighborRoamBSSInfo neighbor_bss_node = NULL; + tListElem *entry; + bool is_dis_pending = false; + + sms_log(mac_ctx, LOGE, + FL("Preauth failed retry number %d, status = 0x%x"), + neighbor_roam_info->FTRoamInfo.numPreAuthRetries, + lim_status); + + /* + * Preauth failed. Add the bssId to the preAuth failed list + * of MAC Address. Also remove the AP from roamable AP list. + */ + if ((neighbor_roam_info->FTRoamInfo.numPreAuthRetries >= + CSR_NEIGHBOR_ROAM_MAX_NUM_PREAUTH_RETRIES) || + (eSIR_LIM_MAX_STA_REACHED_ERROR == lim_status)) { + /* + * We are going to remove the node as it fails for + * more than MAX tries. Reset this count to 0 + */ + neighbor_roam_info->FTRoamInfo.numPreAuthRetries = 0; + + /* + * The one in the head of the list should be one with + * which we issued pre-auth and failed + */ + entry = csr_ll_remove_head( + &neighbor_roam_info->roamableAPList, + LL_ACCESS_LOCK); + if (!entry) { + sms_log(mac_ctx, LOGE, + FL("Preauth list is empty")); + goto NEXT_PREAUTH; + } + neighbor_bss_node = GET_BASE_ADDR(entry, + tCsrNeighborRoamBSSInfo, + List); + /* + * Add the BSSID to pre-auth fail list if + * it is not requested by HDD + */ + if (!neighbor_roam_info->uOsRequestedHandoff) + status = + csr_neighbor_roam_add_preauth_fail( + mac_ctx, session_id, + neighbor_bss_node-> + pBssDescription->bssId); + csr_neighbor_roam_send_lfr_metric_event(mac_ctx, + session_id, + neighbor_bss_node->pBssDescription->bssId, + eCSR_ROAM_PREAUTH_STATUS_FAILURE); + /* Now we can free this node */ + csr_neighbor_roam_free_neighbor_roam_bss_node( + mac_ctx, neighbor_bss_node); + } +NEXT_PREAUTH: + is_dis_pending = is_disconnect_pending(mac_ctx, session_id); + if (is_dis_pending) { + sms_log(mac_ctx, LOGE, + FL("Disconnect in progress, Abort preauth")); + goto ABORT_PREAUTH; + } + /* Issue preauth request for the same/next entry */ + if (QDF_STATUS_SUCCESS == csr_neighbor_roam_issue_preauth_req( + mac_ctx, session_id)) + goto DEQ_PREAUTH; +ABORT_PREAUTH: + if (csr_roam_is_roam_offload_scan_enabled(mac_ctx)) { + if (neighbor_roam_info->uOsRequestedHandoff) { + neighbor_roam_info->uOsRequestedHandoff = 0; + csr_roam_offload_scan(mac_ctx, 0, + ROAM_SCAN_OFFLOAD_START, + REASON_PREAUTH_FAILED_FOR_ALL); + } else { + csr_roam_offload_scan(mac_ctx, 0, + ROAM_SCAN_OFFLOAD_RESTART, + REASON_PREAUTH_FAILED_FOR_ALL); + } + csr_neighbor_roam_state_transition(mac_ctx, + eCSR_NEIGHBOR_ROAM_STATE_CONNECTED, session_id); + } + } + +DEQ_PREAUTH: + csr_dequeue_roam_command(mac_ctx, eCsrPerformPreauth); + return preauth_processed; +} + +/** + * csr_neighbor_roam_add_preauth_fail() - add bssid to preauth failed list + * @mac_ctx: The handle returned by mac_open. + * @bssid: BSSID to be added to the preauth fail list + * + * This function adds the given BSSID to the Preauth fail list + * + * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_FAILURE otherwise + */ +static QDF_STATUS csr_neighbor_roam_add_preauth_fail(tpAniSirGlobal mac_ctx, + uint8_t session_id, tSirMacAddr bssid) +{ + uint8_t i = 0; + tpCsrNeighborRoamControlInfo neighbor_roam_info = + &mac_ctx->roam.neighborRoamInfo[session_id]; + uint8_t num_mac_addr = neighbor_roam_info->FTRoamInfo.preAuthFailList. + numMACAddress; + + sms_log(mac_ctx, LOGE, + FL(" Added BSSID " MAC_ADDRESS_STR " to Preauth failed list"), + MAC_ADDR_ARRAY(bssid)); + + for (i = 0; + i < neighbor_roam_info->FTRoamInfo.preAuthFailList.numMACAddress; + i++) { + if (!qdf_mem_cmp( + neighbor_roam_info->FTRoamInfo.preAuthFailList.macAddress[i], + bssid, sizeof(tSirMacAddr))) { + sms_log(mac_ctx, LOGW, + FL("BSSID "MAC_ADDRESS_STR" already fail list"), + MAC_ADDR_ARRAY(bssid)); + return QDF_STATUS_SUCCESS; + } + } + + if ((num_mac_addr + 1) > MAX_NUM_PREAUTH_FAIL_LIST_ADDRESS) { + sms_log(mac_ctx, LOGE, + FL("Cannot add, preauth fail list is full.")); + return QDF_STATUS_E_FAILURE; + } + qdf_mem_copy(neighbor_roam_info->FTRoamInfo.preAuthFailList. + macAddress[num_mac_addr], bssid, sizeof(tSirMacAddr)); + neighbor_roam_info->FTRoamInfo.preAuthFailList.numMACAddress++; + + return QDF_STATUS_SUCCESS; +} + +/** + * csr_neighbor_roam_is_preauth_candidate() + * + * @mac_ctx: Pointer to Global MAC structure + * @bssId : BSSID of the candidate + * + * This function checks whether the given MAC address is already present + * in the preauth fail list and returns true/false accordingly + * + * Return: true if preauth candidate, false otherwise + */ +bool csr_neighbor_roam_is_preauth_candidate(tpAniSirGlobal pMac, + uint8_t sessionId, tSirMacAddr bssId) +{ + uint8_t i = 0; + tpCsrNeighborRoamControlInfo pNeighborRoamInfo = + &pMac->roam.neighborRoamInfo[sessionId]; + + if (csr_roam_is_roam_offload_scan_enabled(pMac)) + return true; + if (0 == pNeighborRoamInfo->FTRoamInfo.preAuthFailList.numMACAddress) + return true; + + for (i = 0; + i < pNeighborRoamInfo->FTRoamInfo.preAuthFailList.numMACAddress; + i++) { + if (!qdf_mem_cmp(pNeighborRoamInfo->FTRoamInfo. + preAuthFailList.macAddress[i], bssId, + sizeof(tSirMacAddr))) { + sms_log(pMac, LOGE, + FL("BSSID exists in fail list" MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(bssId)); + return false; + } + } + + return true; +} + +/** + * csr_roam_issue_ft_preauth_req() - Initiate Preauthentication request + * @hal: Global Handle + * @session_id: SME Session ID + * @bss_desc: BSS descriptor + * + * Return: Success or Failure + */ +QDF_STATUS csr_roam_issue_ft_preauth_req(tHalHandle hal, uint32_t session_id, + tpSirBssDescription bss_desc) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + tpSirFTPreAuthReq preauth_req; + uint16_t auth_req_len = 0; + tCsrRoamSession *csr_session = CSR_GET_SESSION(mac_ctx, session_id); + + if (NULL == csr_session) { + sms_log(mac_ctx, LOGE, + FL("Session does not exist for session id(%d)"), + session_id); + return QDF_STATUS_E_FAILURE; + } + + auth_req_len = sizeof(tSirFTPreAuthReq); + preauth_req = (tpSirFTPreAuthReq) qdf_mem_malloc(auth_req_len); + if (NULL == preauth_req) { + sms_log(mac_ctx, LOGE, + FL("Memory allocation for FT Preauth request failed")); + return QDF_STATUS_E_NOMEM; + } + /* Save the SME Session ID. We need it while processing preauth resp */ + csr_session->ftSmeContext.smeSessionId = session_id; + + preauth_req->pbssDescription = + (tpSirBssDescription) qdf_mem_malloc(sizeof(bss_desc->length) + + bss_desc->length); + if (NULL == preauth_req->pbssDescription) { + sms_log(mac_ctx, LOGE, + FL("Memory allocation for FT Preauth request failed")); + return QDF_STATUS_E_NOMEM; + } + + preauth_req->messageType = eWNI_SME_FT_PRE_AUTH_REQ; + + preauth_req->preAuthchannelNum = bss_desc->channelId; + + qdf_mem_copy((void *)&preauth_req->currbssId, + (void *)csr_session->connectedProfile.bssid.bytes, + sizeof(tSirMacAddr)); + qdf_mem_copy((void *)&preauth_req->preAuthbssId, + (void *)bss_desc->bssId, sizeof(tSirMacAddr)); + qdf_mem_copy((void *)&preauth_req->self_mac_addr, + (void *)&csr_session->selfMacAddr.bytes, sizeof(tSirMacAddr)); + + if (csr_roam_is11r_assoc(mac_ctx, session_id) && + (mac_ctx->roam.roamSession[session_id].connectedProfile.AuthType != + eCSR_AUTH_TYPE_OPEN_SYSTEM)) { + preauth_req->ft_ies_length = + (uint16_t) csr_session->ftSmeContext.auth_ft_ies_length; + qdf_mem_copy(preauth_req->ft_ies, + csr_session->ftSmeContext.auth_ft_ies, + csr_session->ftSmeContext.auth_ft_ies_length); + } else { + preauth_req->ft_ies_length = 0; + } + qdf_mem_copy(preauth_req->pbssDescription, bss_desc, + sizeof(bss_desc->length) + bss_desc->length); + preauth_req->length = auth_req_len; + return cds_send_mb_message_to_mac(preauth_req); +} + +/** + * csr_roam_ft_pre_auth_rsp_processor() - Handle the preauth response + * @hal: Global Handle + * preauth_rsp: Received preauthentication response + * + * Return: None + */ +void csr_roam_ft_pre_auth_rsp_processor(tHalHandle hal, + tpSirFTPreAuthRsp preauth_rsp) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + QDF_STATUS status = QDF_STATUS_SUCCESS; + tCsrRoamInfo roam_info; + eCsrAuthType conn_Auth_type; + uint32_t session_id = preauth_rsp->smeSessionId; + tCsrRoamSession *csr_session = CSR_GET_SESSION(mac_ctx, session_id); + tDot11fAuthentication *p_auth = NULL; + + if (NULL == csr_session) { + sms_log(mac_ctx, LOGE, FL("CSR session is NULL")); + return; + } + status = csr_neighbor_roam_preauth_rsp_handler(mac_ctx, + preauth_rsp->smeSessionId, preauth_rsp->status); + if (status != QDF_STATUS_SUCCESS) { + sms_log(mac_ctx, LOGE, + FL("Preauth was not processed: %d SessionID: %d"), + status, session_id); + return; + } + + if (QDF_STATUS_SUCCESS != (QDF_STATUS) preauth_rsp->status) + return; + csr_session->ftSmeContext.FTState = eFT_AUTH_COMPLETE; + csr_session->ftSmeContext.psavedFTPreAuthRsp = preauth_rsp; + /* No need to notify qos module if this is a non 11r & ESE roam */ + if (csr_roam_is11r_assoc(mac_ctx, preauth_rsp->smeSessionId) +#ifdef FEATURE_WLAN_ESE + || csr_roam_is_ese_assoc(mac_ctx, preauth_rsp->smeSessionId) +#endif + ) { + sme_qos_csr_event_ind(mac_ctx, + csr_session->ftSmeContext.smeSessionId, + SME_QOS_CSR_PREAUTH_SUCCESS_IND, NULL); + } + status = + qdf_mc_timer_start( + &csr_session->ftSmeContext.preAuthReassocIntvlTimer, + 60); + if (QDF_STATUS_SUCCESS != status) { + sms_log(mac_ctx, LOGE, + FL("PreauthReassocInterval timer failed status %d"), + status); + return; + } + qdf_mem_copy((void *)&csr_session->ftSmeContext.preAuthbssId, + (void *)preauth_rsp->preAuthbssId, + sizeof(struct qdf_mac_addr)); + if (csr_roam_is11r_assoc(mac_ctx, preauth_rsp->smeSessionId)) + csr_roam_call_callback(mac_ctx, preauth_rsp->smeSessionId, + NULL, 0, eCSR_ROAM_FT_RESPONSE, eCSR_ROAM_RESULT_NONE); + +#ifdef FEATURE_WLAN_ESE + if (csr_roam_is_ese_assoc(mac_ctx, preauth_rsp->smeSessionId)) { + csr_roam_read_tsf(mac_ctx, (uint8_t *) roam_info.timestamp, + preauth_rsp->smeSessionId); + qdf_mem_copy((void *)&roam_info.bssid, + (void *)preauth_rsp->preAuthbssId, + sizeof(struct qdf_mac_addr)); + csr_roam_call_callback(mac_ctx, preauth_rsp->smeSessionId, + &roam_info, 0, eCSR_ROAM_CCKM_PREAUTH_NOTIFY, + 0); + } +#endif + + if (csr_roam_is_fast_roam_enabled(mac_ctx, preauth_rsp->smeSessionId)) { + /* Save the bssid from the received response */ + qdf_mem_copy((void *)&roam_info.bssid, + (void *)preauth_rsp->preAuthbssId, + sizeof(struct qdf_mac_addr)); + csr_roam_call_callback(mac_ctx, preauth_rsp->smeSessionId, + &roam_info, 0, eCSR_ROAM_PMK_NOTIFY, 0); + } + + /* If its an Open Auth, FT IEs are not provided by supplicant */ + /* Hence populate them here */ + conn_Auth_type = + mac_ctx->roam.roamSession[session_id].connectedProfile.AuthType; + + csr_session->ftSmeContext.addMDIE = false; + + /* Done with it, init it. */ + csr_session->ftSmeContext.psavedFTPreAuthRsp = NULL; + + if (csr_roam_is11r_assoc(mac_ctx, preauth_rsp->smeSessionId) && + (conn_Auth_type == eCSR_AUTH_TYPE_OPEN_SYSTEM)) { + uint16_t ft_ies_length; + ft_ies_length = preauth_rsp->ric_ies_length; + + if ((csr_session->ftSmeContext.reassoc_ft_ies) && + (csr_session->ftSmeContext.reassoc_ft_ies_length)) { + qdf_mem_free(csr_session->ftSmeContext.reassoc_ft_ies); + csr_session->ftSmeContext.reassoc_ft_ies_length = 0; + csr_session->ftSmeContext.reassoc_ft_ies = NULL; + } + p_auth = (tDot11fAuthentication *) qdf_mem_malloc( + sizeof(tDot11fAuthentication)); + + if (p_auth == NULL) + return; + + status = dot11f_unpack_authentication(mac_ctx, + preauth_rsp->ft_ies, + preauth_rsp->ft_ies_length, p_auth); + if (DOT11F_FAILED(status)) + sms_log(mac_ctx, LOGE, + FL("Failed to parse an Authentication frame")); + else if (p_auth->MobilityDomain.present) + csr_session->ftSmeContext.addMDIE = true; + + qdf_mem_free(p_auth); + + if (!ft_ies_length) + return; + + csr_session->ftSmeContext.reassoc_ft_ies = + qdf_mem_malloc(ft_ies_length); + if (NULL == csr_session->ftSmeContext.reassoc_ft_ies) { + sms_log(mac_ctx, LOGE, + FL("Memory allocation failed for ft_ies")); + return; + } else { + /* Copy the RIC IEs to reassoc IEs */ + qdf_mem_copy(((uint8_t *) csr_session->ftSmeContext. + reassoc_ft_ies), + (uint8_t *) preauth_rsp->ric_ies, + preauth_rsp->ric_ies_length); + csr_session->ftSmeContext.reassoc_ft_ies_length = + ft_ies_length; + csr_session->ftSmeContext.addMDIE = true; + } + } +} + +/** + * csr_neighbor_roam_issue_preauth_req() - Send preauth request to first AP + * @mac_ctx: The handle returned by mac_open. + * @session_id: Session information + * + * This function issues preauth request to PE with the 1st AP entry in the + * roamable AP list + * + * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_FAILURE otherwise + */ +QDF_STATUS csr_neighbor_roam_issue_preauth_req(tpAniSirGlobal mac_ctx, + uint8_t session_id) +{ + tpCsrNeighborRoamControlInfo neighbor_roam_info = + &mac_ctx->roam.neighborRoamInfo[session_id]; + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpCsrNeighborRoamBSSInfo neighbor_bss_node; + + + if (false != neighbor_roam_info->FTRoamInfo.preauthRspPending) { + /* This must not be true here */ + QDF_ASSERT(neighbor_roam_info->FTRoamInfo.preauthRspPending == + false); + return QDF_STATUS_E_FAILURE; + } + + /* + * Issue Preauth request to PE here. + * Need to issue the preauth request with the BSSID that is in the + * head of the roamable AP list. Parameters that should be passed are + * BSSID, Channel number and the neighborScanPeriod(probably). If + * roamableAPList gets empty, should transition to REPORT_SCAN state + */ + neighbor_bss_node = csr_neighbor_roam_next_roamable_ap(mac_ctx, + &neighbor_roam_info->roamableAPList, NULL); + + if (NULL == neighbor_bss_node) { + sms_log(mac_ctx, LOGW, FL("Roamable AP list is empty.. ")); + return QDF_STATUS_E_FAILURE; + } else { + csr_neighbor_roam_send_lfr_metric_event(mac_ctx, session_id, + neighbor_bss_node->pBssDescription->bssId, + eCSR_ROAM_PREAUTH_INIT_NOTIFY); + status = csr_roam_enqueue_preauth(mac_ctx, session_id, + neighbor_bss_node->pBssDescription, + eCsrPerformPreauth, true); + + sms_log(mac_ctx, LOG1, + FL("Before Pre-Auth: BSSID " MAC_ADDRESS_STR ", Ch:%d"), + MAC_ADDR_ARRAY( + neighbor_bss_node->pBssDescription->bssId), + (int)neighbor_bss_node->pBssDescription->channelId); + + if (QDF_STATUS_SUCCESS != status) { + sms_log(mac_ctx, LOGE, + FL("Return failed preauth request status %d"), + status); + return status; + } + } + + neighbor_roam_info->FTRoamInfo.preauthRspPending = true; + neighbor_roam_info->FTRoamInfo.numPreAuthRetries++; + csr_neighbor_roam_state_transition(mac_ctx, + eCSR_NEIGHBOR_ROAM_STATE_PREAUTHENTICATING, session_id); + + return status; +} diff --git a/drivers/staging/qcacld-3.0/core/sme/src/csr/csr_tdls_process.c b/drivers/staging/qcacld-3.0/core/sme/src/csr/csr_tdls_process.c new file mode 100644 index 0000000000000000000000000000000000000000..cae0f7e564daa6f14c4a6dfae99f1d6910a800fa --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/sme/src/csr/csr_tdls_process.c @@ -0,0 +1,854 @@ +/* + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** ------------------------------------------------------------------------- * + ------------------------------------------------------------------------- * + + \file csr_tdls_process.c + + Implementation for the TDLS interface to PE. + ========================================================================== */ + +#ifdef FEATURE_WLAN_TDLS + +#include "ani_global.h" /* for tpAniSirGlobal */ +#include "cds_mq.h" +#include "csr_inside_api.h" +#include "sme_inside.h" +#include "sms_debug.h" + +#include "csr_support.h" + +#include "host_diag_core_log.h" +#include "host_diag_core_event.h" +#include "csr_internal.h" + +/* + * common routine to remove TDLS cmd from SME command list.. + * commands are removed after getting reponse from PE. + */ +static QDF_STATUS csr_tdls_remove_sme_cmd(tpAniSirGlobal pMac, + eSmeCommandType cmdType) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tListElem *pEntry; + tSmeCmd *pCommand; + + pEntry = csr_ll_peek_head(&pMac->sme.smeCmdActiveList, LL_ACCESS_LOCK); + if (pEntry) { + pCommand = GET_BASE_ADDR(pEntry, tSmeCmd, Link); + if (cmdType == pCommand->command) { + if (csr_ll_remove_entry(&pMac->sme.smeCmdActiveList, + pEntry, LL_ACCESS_LOCK)) { + qdf_mem_zero(&pCommand->u.tdlsCmd, + sizeof(tTdlsCmd)); + csr_release_command(pMac, pCommand); + sme_process_pending_queue(pMac); + status = QDF_STATUS_SUCCESS; + } + } + } + return status; +} + +/** + * csr_tdls_send_mgmt_req() - to send a TDLS frame to PE through SME + * @hHal: HAL context + * @sessionId: SME session id + * @tdlsSendMgmt: tdls mgmt pointer + * + * TDLS request API, called from HDD to send a TDLS frame in SME/CSR and + * send message to PE to trigger TDLS discovery procedure. + */ +QDF_STATUS csr_tdls_send_mgmt_req(tHalHandle hHal, uint8_t sessionId, + tCsrTdlsSendMgmt *tdlsSendMgmt) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + tSmeCmd *tdlsSendMgmtCmd; + tTdlsSendMgmtCmdInfo *tdlsSendMgmtCmdInfo; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + + /* If connected and in Infra. Only then allow this */ + if (!CSR_IS_SESSION_VALID(pMac, sessionId) || + !csr_is_conn_state_connected_infra(pMac, sessionId) || + (NULL == tdlsSendMgmt)) + return status; + tdlsSendMgmtCmd = csr_get_command_buffer(pMac); + if (!tdlsSendMgmtCmd) + return status; + tdlsSendMgmtCmdInfo = &tdlsSendMgmtCmd->u.tdlsCmd.u.tdlsSendMgmtCmdInfo; + tdlsSendMgmtCmd->sessionId = sessionId; + tdlsSendMgmtCmdInfo->frameType = tdlsSendMgmt->frameType; + tdlsSendMgmtCmdInfo->dialog = tdlsSendMgmt->dialog; + tdlsSendMgmtCmdInfo->statusCode = tdlsSendMgmt->statusCode; + tdlsSendMgmtCmdInfo->responder = tdlsSendMgmt->responder; + tdlsSendMgmtCmdInfo->peerCapability = tdlsSendMgmt->peerCapability; + qdf_mem_copy(tdlsSendMgmtCmdInfo->peerMac, tdlsSendMgmt->peerMac, + sizeof(tSirMacAddr)); + + if ((0 != tdlsSendMgmt->len) && (NULL != tdlsSendMgmt->buf)) { + tdlsSendMgmtCmdInfo->buf = qdf_mem_malloc(tdlsSendMgmt->len); + if (NULL == tdlsSendMgmtCmdInfo->buf) { + status = QDF_STATUS_E_NOMEM; + sms_log(pMac, LOGE, FL("Alloc Failed")); + QDF_ASSERT(0); + return status; + } + qdf_mem_copy(tdlsSendMgmtCmdInfo->buf, tdlsSendMgmt->buf, + tdlsSendMgmt->len); + tdlsSendMgmtCmdInfo->len = tdlsSendMgmt->len; + } else { + tdlsSendMgmtCmdInfo->buf = NULL; + tdlsSendMgmtCmdInfo->len = 0; + } + + tdlsSendMgmtCmdInfo->ac = tdlsSendMgmt->ac; + + tdlsSendMgmtCmd->command = eSmeCommandTdlsSendMgmt; + tdlsSendMgmtCmd->u.tdlsCmd.size = sizeof(tTdlsSendMgmtCmdInfo); + sme_push_command(pMac, tdlsSendMgmtCmd, false); + status = QDF_STATUS_SUCCESS; + sms_log(pMac, LOG1, + FL("Successfully posted eSmeCommandTdlsSendMgmt to SME")); + return status; +} + +/* + * TDLS request API, called from HDD to add a TDLS peer + */ +QDF_STATUS csr_tdls_change_peer_sta(tHalHandle hHal, uint8_t sessionId, + const tSirMacAddr peerMac, + tCsrStaParams *pstaParams) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + tSmeCmd *tdlsAddStaCmd; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + + /* If connected and in Infra. Only then allow this */ + if (CSR_IS_SESSION_VALID(pMac, sessionId) && + csr_is_conn_state_connected_infra(pMac, sessionId) && + (NULL != peerMac) && (NULL != pstaParams)) { + + tdlsAddStaCmd = csr_get_command_buffer(pMac); + + if (tdlsAddStaCmd) { + tTdlsAddStaCmdInfo *tdlsAddStaCmdInfo = + &tdlsAddStaCmd->u.tdlsCmd.u.tdlsAddStaCmdInfo; + + tdlsAddStaCmdInfo->tdlsAddOper = TDLS_OPER_UPDATE; + + tdlsAddStaCmd->sessionId = sessionId; + + qdf_mem_copy(tdlsAddStaCmdInfo->peermac.bytes, + peerMac, QDF_MAC_ADDR_SIZE); + tdlsAddStaCmdInfo->capability = pstaParams->capability; + tdlsAddStaCmdInfo->uapsdQueues = + pstaParams->uapsd_queues; + tdlsAddStaCmdInfo->maxSp = pstaParams->max_sp; + qdf_mem_copy(tdlsAddStaCmdInfo->extnCapability, + pstaParams->extn_capability, + sizeof(pstaParams->extn_capability)); + + tdlsAddStaCmdInfo->htcap_present = + pstaParams->htcap_present; + if (pstaParams->htcap_present) + qdf_mem_copy(&tdlsAddStaCmdInfo->HTCap, + &pstaParams->HTCap, + sizeof(pstaParams->HTCap)); + else + qdf_mem_set(&tdlsAddStaCmdInfo->HTCap, + sizeof(pstaParams->HTCap), 0); + + tdlsAddStaCmdInfo->vhtcap_present = + pstaParams->vhtcap_present; + if (pstaParams->vhtcap_present) + qdf_mem_copy(&tdlsAddStaCmdInfo->VHTCap, + &pstaParams->VHTCap, + sizeof(pstaParams->VHTCap)); + else + qdf_mem_set(&tdlsAddStaCmdInfo->VHTCap, + sizeof(pstaParams->VHTCap), 0); + + tdlsAddStaCmdInfo->supportedRatesLen = + pstaParams->supported_rates_len; + + if (0 != pstaParams->supported_rates_len) + qdf_mem_copy(&tdlsAddStaCmdInfo->supportedRates, + pstaParams->supported_rates, + pstaParams->supported_rates_len); + + tdlsAddStaCmd->command = eSmeCommandTdlsAddPeer; + tdlsAddStaCmd->u.tdlsCmd.size = + sizeof(tTdlsAddStaCmdInfo); + sme_push_command(pMac, tdlsAddStaCmd, false); + status = QDF_STATUS_SUCCESS; + sms_log(pMac, LOG1, + FL("Successfully posted eSmeCommandTdlsAddPeer to SME to modify peer ")); + } + } + + return status; +} + +/* + * TDLS request API, called from HDD to Send Link Establishment Parameters + */ +QDF_STATUS csr_tdls_send_link_establish_params(tHalHandle hHal, + uint8_t sessionId, + const tSirMacAddr peerMac, + tCsrTdlsLinkEstablishParams * + tdlsLinkEstablishParams) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + tSmeCmd *tdlsLinkEstablishCmd; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + /* If connected and in Infra. Only then allow this */ + if (CSR_IS_SESSION_VALID(pMac, sessionId) && + csr_is_conn_state_connected_infra(pMac, sessionId) && + (NULL != peerMac)) { + tdlsLinkEstablishCmd = csr_get_command_buffer(pMac); + + if (tdlsLinkEstablishCmd) { + tTdlsLinkEstablishCmdInfo *tdlsLinkEstablishCmdInfo = + &tdlsLinkEstablishCmd->u.tdlsCmd.u. + tdlsLinkEstablishCmdInfo; + + tdlsLinkEstablishCmd->sessionId = sessionId; + + qdf_mem_copy(tdlsLinkEstablishCmdInfo->peermac.bytes, + peerMac, QDF_MAC_ADDR_SIZE); + tdlsLinkEstablishCmdInfo->isBufSta = + tdlsLinkEstablishParams->isBufSta; + tdlsLinkEstablishCmdInfo->isResponder = + tdlsLinkEstablishParams->isResponder; + tdlsLinkEstablishCmdInfo->maxSp = + tdlsLinkEstablishParams->maxSp; + tdlsLinkEstablishCmdInfo->uapsdQueues = + tdlsLinkEstablishParams->uapsdQueues; + tdlsLinkEstablishCmdInfo->isOffChannelSupported = + tdlsLinkEstablishParams->isOffChannelSupported; + qdf_mem_copy(tdlsLinkEstablishCmdInfo-> + supportedChannels, + tdlsLinkEstablishParams->supportedChannels, + tdlsLinkEstablishParams-> + supportedChannelsLen); + tdlsLinkEstablishCmdInfo->supportedChannelsLen = + tdlsLinkEstablishParams->supportedChannelsLen; + qdf_mem_copy(tdlsLinkEstablishCmdInfo-> + supportedOperClasses, + tdlsLinkEstablishParams-> + supportedOperClasses, + tdlsLinkEstablishParams-> + supportedOperClassesLen); + tdlsLinkEstablishCmdInfo->supportedOperClassesLen = + tdlsLinkEstablishParams->supportedOperClassesLen; + tdlsLinkEstablishCmdInfo->isResponder = + tdlsLinkEstablishParams->isResponder; + tdlsLinkEstablishCmdInfo->maxSp = + tdlsLinkEstablishParams->maxSp; + tdlsLinkEstablishCmdInfo->uapsdQueues = + tdlsLinkEstablishParams->uapsdQueues; + tdlsLinkEstablishCmd->command = + eSmeCommandTdlsLinkEstablish; + tdlsLinkEstablishCmd->u.tdlsCmd.size = + sizeof(tTdlsLinkEstablishCmdInfo); + sme_push_command(pMac, tdlsLinkEstablishCmd, false); + status = QDF_STATUS_SUCCESS; + sms_log(pMac, LOG1, + FL("Successfully posted eSmeCommandTdlsLinkEstablish to SME")); + } + } + + return status; +} + +/* + * TDLS request API, called from HDD to add a TDLS peer + */ +QDF_STATUS csr_tdls_add_peer_sta(tHalHandle hHal, uint8_t sessionId, + const tSirMacAddr peerMac) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + tSmeCmd *tdlsAddStaCmd; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + + /* If connected and in Infra. Only then allow this */ + if (CSR_IS_SESSION_VALID(pMac, sessionId) && + csr_is_conn_state_connected_infra(pMac, sessionId) && + (NULL != peerMac)) { + tdlsAddStaCmd = csr_get_command_buffer(pMac); + + if (tdlsAddStaCmd) { + tTdlsAddStaCmdInfo *tdlsAddStaCmdInfo = + &tdlsAddStaCmd->u.tdlsCmd.u.tdlsAddStaCmdInfo; + + tdlsAddStaCmd->sessionId = sessionId; + tdlsAddStaCmdInfo->tdlsAddOper = TDLS_OPER_ADD; + + qdf_mem_copy(tdlsAddStaCmdInfo->peermac.bytes, + peerMac, QDF_MAC_ADDR_SIZE); + + tdlsAddStaCmd->command = eSmeCommandTdlsAddPeer; + tdlsAddStaCmd->u.tdlsCmd.size = + sizeof(tTdlsAddStaCmdInfo); + sme_push_command(pMac, tdlsAddStaCmd, false); + status = QDF_STATUS_SUCCESS; + sms_log(pMac, LOG1, + FL("Successfully posted eSmeCommandTdlsAddPeer to SME")); + } + } + + return status; +} + +/* + * TDLS request API, called from HDD to delete a TDLS peer + */ +QDF_STATUS csr_tdls_del_peer_sta(tHalHandle hHal, uint8_t sessionId, + const tSirMacAddr peerMac) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + tSmeCmd *tdlsDelStaCmd; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + + /* If connected and in Infra. Only then allow this */ + if (CSR_IS_SESSION_VALID(pMac, sessionId) && + csr_is_conn_state_connected_infra(pMac, sessionId) && + (NULL != peerMac)) { + tdlsDelStaCmd = csr_get_command_buffer(pMac); + + if (tdlsDelStaCmd) { + tTdlsDelStaCmdInfo *tdlsDelStaCmdInfo = + &tdlsDelStaCmd->u.tdlsCmd.u.tdlsDelStaCmdInfo; + + tdlsDelStaCmd->sessionId = sessionId; + + qdf_mem_copy(tdlsDelStaCmdInfo->peermac.bytes, + peerMac, QDF_MAC_ADDR_SIZE); + + tdlsDelStaCmd->command = eSmeCommandTdlsDelPeer; + tdlsDelStaCmd->u.tdlsCmd.size = + sizeof(tTdlsDelStaCmdInfo); + sme_push_command(pMac, tdlsDelStaCmd, false); + status = QDF_STATUS_SUCCESS; + sms_log(pMac, LOG1, + FL("Successfully posted eSmeCommandTdlsDelPeer to SME")); + } + } + + return status; +} + +/* + * TDLS messages sent to PE . + */ +static QDF_STATUS tdls_send_message(tpAniSirGlobal pMac, uint16_t msg_type, + void *msg_data, uint32_t msg_size) +{ + + tSirMbMsg *pMsg = (tSirMbMsg *) msg_data; + pMsg->type = msg_type; + pMsg->msgLen = (uint16_t) (msg_size); + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO, + ("sending msg = %d"), pMsg->type); + /* Send message. */ + if (cds_send_mb_message_to_mac(pMsg) != QDF_STATUS_SUCCESS) { + sms_log(pMac, LOGE, FL("Cannot send message")); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS csr_tdls_process_send_mgmt(tpAniSirGlobal pMac, tSmeCmd *cmd) +{ + tTdlsSendMgmtCmdInfo *tdlsSendMgmtCmdInfo = + &cmd->u.tdlsCmd.u.tdlsSendMgmtCmdInfo; + tSirTdlsSendMgmtReq *tdlsSendMgmtReq = NULL; + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, cmd->sessionId); + QDF_STATUS status = QDF_STATUS_E_FAILURE; + + if (NULL == pSession) { + sms_log(pMac, LOGE, FL("pSession is NULL")); + return QDF_STATUS_E_FAILURE; + } + if (NULL == pSession->pConnectBssDesc) { + sms_log(pMac, LOGE, FL("BSS Description is not present")); + return QDF_STATUS_E_FAILURE; + } + + tdlsSendMgmtReq = + qdf_mem_malloc(sizeof(tSirTdlsSendMgmtReq) + + tdlsSendMgmtCmdInfo->len); + if (NULL == tdlsSendMgmtReq) + status = QDF_STATUS_E_NOMEM; + else + status = QDF_STATUS_SUCCESS; + + if (!QDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOGE, FL("alloc failed")); + QDF_ASSERT(0); + return status; + } + tdlsSendMgmtReq->sessionId = cmd->sessionId; + /* Using dialog as transactionId. This can be used to match response with request */ + tdlsSendMgmtReq->transactionId = tdlsSendMgmtCmdInfo->dialog; + tdlsSendMgmtReq->reqType = tdlsSendMgmtCmdInfo->frameType; + tdlsSendMgmtReq->dialog = tdlsSendMgmtCmdInfo->dialog; + tdlsSendMgmtReq->statusCode = tdlsSendMgmtCmdInfo->statusCode; + tdlsSendMgmtReq->responder = tdlsSendMgmtCmdInfo->responder; + tdlsSendMgmtReq->peerCapability = tdlsSendMgmtCmdInfo->peerCapability; + tdlsSendMgmtReq->ac = tdlsSendMgmtCmdInfo->ac; + + qdf_mem_copy(tdlsSendMgmtReq->bssid.bytes, + pSession->pConnectBssDesc->bssId, QDF_MAC_ADDR_SIZE); + + qdf_mem_copy(tdlsSendMgmtReq->peer_mac.bytes, + tdlsSendMgmtCmdInfo->peerMac, QDF_MAC_ADDR_SIZE); + + if (tdlsSendMgmtCmdInfo->len && tdlsSendMgmtCmdInfo->buf) { + qdf_mem_copy(tdlsSendMgmtReq->addIe, tdlsSendMgmtCmdInfo->buf, + tdlsSendMgmtCmdInfo->len); + + } + /* Send the request to PE. */ + sms_log(pMac, LOG1, FL("sending TDLS Mgmt Frame req to PE ")); + status = tdls_send_message(pMac, eWNI_SME_TDLS_SEND_MGMT_REQ, + (void *)tdlsSendMgmtReq, + sizeof(tSirTdlsSendMgmtReq) + + tdlsSendMgmtCmdInfo->len); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOGE, FL("Failed to send request to MAC")); + } + if (tdlsSendMgmtCmdInfo->len && tdlsSendMgmtCmdInfo->buf) { + /* Done with the buf. Free it. */ + qdf_mem_free(tdlsSendMgmtCmdInfo->buf); + tdlsSendMgmtCmdInfo->buf = NULL; + tdlsSendMgmtCmdInfo->len = 0; + } + + return status; +} + +static QDF_STATUS csr_tdls_process_add_sta(tpAniSirGlobal pMac, tSmeCmd *cmd) +{ + tTdlsAddStaCmdInfo *tdlsAddStaCmdInfo = + &cmd->u.tdlsCmd.u.tdlsAddStaCmdInfo; + tSirTdlsAddStaReq *tdlsAddStaReq = NULL; + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, cmd->sessionId); + QDF_STATUS status = QDF_STATUS_E_FAILURE; + + if (NULL == pSession) { + sms_log(pMac, LOGE, FL("pSession is NULL")); + return QDF_STATUS_E_FAILURE; + } + + if (NULL == pSession->pConnectBssDesc) { + sms_log(pMac, LOGE, FL("BSS description is not present")); + return QDF_STATUS_E_FAILURE; + } + + tdlsAddStaReq = qdf_mem_malloc(sizeof(tSirTdlsAddStaReq)); + if (NULL == tdlsAddStaReq) + status = QDF_STATUS_E_NOMEM; + else + status = QDF_STATUS_SUCCESS; + + if (!QDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOGE, FL("alloc failed")); + QDF_ASSERT(0); + return status; + } + tdlsAddStaReq->sessionId = cmd->sessionId; + tdlsAddStaReq->tdlsAddOper = tdlsAddStaCmdInfo->tdlsAddOper; + /* Using dialog as transactionId. This can be used to match response with request */ + tdlsAddStaReq->transactionId = 0; + + qdf_mem_copy(tdlsAddStaReq->bssid.bytes, + pSession->pConnectBssDesc->bssId, QDF_MAC_ADDR_SIZE); + + qdf_copy_macaddr(&tdlsAddStaReq->peermac, + &tdlsAddStaCmdInfo->peermac); + + tdlsAddStaReq->capability = tdlsAddStaCmdInfo->capability; + tdlsAddStaReq->uapsd_queues = tdlsAddStaCmdInfo->uapsdQueues; + tdlsAddStaReq->max_sp = tdlsAddStaCmdInfo->maxSp; + + qdf_mem_copy(tdlsAddStaReq->extn_capability, + tdlsAddStaCmdInfo->extnCapability, SIR_MAC_MAX_EXTN_CAP); + tdlsAddStaReq->htcap_present = tdlsAddStaCmdInfo->htcap_present; + qdf_mem_copy(&tdlsAddStaReq->htCap, + &tdlsAddStaCmdInfo->HTCap, + sizeof(tdlsAddStaCmdInfo->HTCap)); + tdlsAddStaReq->vhtcap_present = tdlsAddStaCmdInfo->vhtcap_present; + qdf_mem_copy(&tdlsAddStaReq->vhtCap, + &tdlsAddStaCmdInfo->VHTCap, + sizeof(tdlsAddStaCmdInfo->VHTCap)); + tdlsAddStaReq->supported_rates_length = + tdlsAddStaCmdInfo->supportedRatesLen; + qdf_mem_copy(&tdlsAddStaReq->supported_rates, + tdlsAddStaCmdInfo->supportedRates, + tdlsAddStaCmdInfo->supportedRatesLen); + + /* Send the request to PE. */ + sms_log(pMac, LOGE, "sending TDLS Add Sta req to PE "); + status = tdls_send_message(pMac, eWNI_SME_TDLS_ADD_STA_REQ, + (void *)tdlsAddStaReq, + sizeof(tSirTdlsAddStaReq)); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOGE, FL("Failed to send request to MAC")); + } + return status; +} + +static QDF_STATUS csr_tdls_process_del_sta(tpAniSirGlobal pMac, tSmeCmd *cmd) +{ + tTdlsDelStaCmdInfo *tdlsDelStaCmdInfo = + &cmd->u.tdlsCmd.u.tdlsDelStaCmdInfo; + tSirTdlsDelStaReq *tdlsDelStaReq = NULL; + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, cmd->sessionId); + QDF_STATUS status = QDF_STATUS_E_FAILURE; + + if (NULL == pSession) { + sms_log(pMac, LOGE, FL("pSession is NULL")); + return QDF_STATUS_E_FAILURE; + } + + if (NULL == pSession->pConnectBssDesc) { + sms_log(pMac, LOGE, FL("BSS description is not present")); + return QDF_STATUS_E_FAILURE; + } + + tdlsDelStaReq = qdf_mem_malloc(sizeof(tSirTdlsDelStaReq)); + if (NULL == tdlsDelStaReq) + status = QDF_STATUS_E_NOMEM; + else + status = QDF_STATUS_SUCCESS; + + if (!QDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOGE, FL("alloc failed")); + QDF_ASSERT(0); + return status; + } + tdlsDelStaReq->sessionId = cmd->sessionId; + /* Using dialog as transactionId. This can be used to match response with request */ + tdlsDelStaReq->transactionId = 0; + + qdf_mem_copy(tdlsDelStaReq->bssid.bytes, + pSession->pConnectBssDesc->bssId, QDF_MAC_ADDR_SIZE); + + qdf_copy_macaddr(&tdlsDelStaReq->peermac, + &tdlsDelStaCmdInfo->peermac); + + /* Send the request to PE. */ + sms_log(pMac, LOG1, + "sending TDLS Del Sta " MAC_ADDRESS_STR " req to PE", + MAC_ADDR_ARRAY(tdlsDelStaCmdInfo->peermac.bytes)); + status = tdls_send_message(pMac, eWNI_SME_TDLS_DEL_STA_REQ, + (void *)tdlsDelStaReq, + sizeof(tSirTdlsDelStaReq)); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOGE, FL("Failed to send request to MAC")); + } + return status; +} + +/* + * commands received from CSR + */ +QDF_STATUS csr_tdls_process_cmd(tpAniSirGlobal pMac, tSmeCmd *cmd) +{ + eSmeCommandType cmdType = cmd->command; + bool status = true; + switch (cmdType) { + case eSmeCommandTdlsSendMgmt: + { + status = csr_tdls_process_send_mgmt(pMac, cmd); + if (QDF_IS_STATUS_SUCCESS(status)) { + status = false; + } + } + break; + case eSmeCommandTdlsAddPeer: + { + status = csr_tdls_process_add_sta(pMac, cmd); + if (QDF_IS_STATUS_SUCCESS(status)) { + status = false; + } + } + break; + case eSmeCommandTdlsDelPeer: + { + status = csr_tdls_process_del_sta(pMac, cmd); + if (QDF_IS_STATUS_SUCCESS(status)) { + status = false; + } + } + break; + case eSmeCommandTdlsLinkEstablish: + { + status = csr_tdls_process_link_establish(pMac, cmd); + if (QDF_IS_STATUS_SUCCESS(status)) { + status = false; + } + } + break; + default: + { + /* TODO: Add defualt handling */ + break; + } + + } + return status; +} + +QDF_STATUS csr_tdls_process_link_establish(tpAniSirGlobal pMac, tSmeCmd *cmd) +{ + tTdlsLinkEstablishCmdInfo *tdlsLinkEstablishCmdInfo = + &cmd->u.tdlsCmd.u.tdlsLinkEstablishCmdInfo; + tSirTdlsLinkEstablishReq *tdlsLinkEstablishReq = NULL; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, cmd->sessionId); + + if (NULL == pSession) { + sms_log(pMac, LOGE, FL("pSession is NULL")); + return QDF_STATUS_E_FAILURE; + } + + tdlsLinkEstablishReq = qdf_mem_malloc(sizeof(tSirTdlsLinkEstablishReq)); + + if (tdlsLinkEstablishReq == NULL) { + sms_log(pMac, LOGE, FL("alloc failed")); + QDF_ASSERT(0); + return QDF_STATUS_E_NOMEM; + } + tdlsLinkEstablishReq->sessionId = cmd->sessionId; + /* Using dialog as transactionId. This can be used to match response with request */ + tdlsLinkEstablishReq->transactionId = 0; + qdf_copy_macaddr(&tdlsLinkEstablishReq->peermac, + &tdlsLinkEstablishCmdInfo->peermac); + qdf_mem_copy(tdlsLinkEstablishReq->bssid.bytes, + pSession->pConnectBssDesc->bssId, QDF_MAC_ADDR_SIZE); + qdf_mem_copy(tdlsLinkEstablishReq->supportedChannels, + tdlsLinkEstablishCmdInfo->supportedChannels, + tdlsLinkEstablishCmdInfo->supportedChannelsLen); + tdlsLinkEstablishReq->supportedChannelsLen = + tdlsLinkEstablishCmdInfo->supportedChannelsLen; + qdf_mem_copy(tdlsLinkEstablishReq->supportedOperClasses, + tdlsLinkEstablishCmdInfo->supportedOperClasses, + tdlsLinkEstablishCmdInfo->supportedOperClassesLen); + tdlsLinkEstablishReq->supportedOperClassesLen = + tdlsLinkEstablishCmdInfo->supportedOperClassesLen; + tdlsLinkEstablishReq->isBufSta = tdlsLinkEstablishCmdInfo->isBufSta; + tdlsLinkEstablishReq->isResponder = + tdlsLinkEstablishCmdInfo->isResponder; + tdlsLinkEstablishReq->uapsdQueues = + tdlsLinkEstablishCmdInfo->uapsdQueues; + tdlsLinkEstablishReq->maxSp = tdlsLinkEstablishCmdInfo->maxSp; + + /* Send the request to PE. */ + sms_log(pMac, LOGE, "sending TDLS Link Establish Request to PE \n"); + status = tdls_send_message(pMac, eWNI_SME_TDLS_LINK_ESTABLISH_REQ, + (void *)tdlsLinkEstablishReq, + sizeof(tSirTdlsLinkEstablishReq)); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOGE, FL("Failed to send request to MAC\n")); + } + return status; +} + +/* + * TDLS Message processor, will be called after TDLS message recieved from + * PE + */ +QDF_STATUS tdls_msg_processor(tpAniSirGlobal pMac, uint16_t msgType, + void *pMsgBuf) +{ + tCsrRoamInfo roamInfo = { 0 }; + eCsrRoamResult roamResult; + tSirTdlsAddStaRsp *addStaRsp = (tSirTdlsAddStaRsp *) pMsgBuf; + tSirTdlsDelStaRsp *delStaRsp = (tSirTdlsDelStaRsp *) pMsgBuf; + tpSirTdlsDelStaInd pSirTdlsDelStaInd = (tpSirTdlsDelStaInd) pMsgBuf; + tpSirTdlsDelAllPeerInd pSirTdlsDelAllPeerInd = + (tpSirTdlsDelAllPeerInd) pMsgBuf; + tpSirMgmtTxCompletionInd tdls_tx_comp_ind = + (tpSirMgmtTxCompletionInd) pMsgBuf; + tSirTdlsLinkEstablishReqRsp *linkEstablishReqRsp = + (tSirTdlsLinkEstablishReqRsp *) pMsgBuf; + tSirTdlsEventnotify *tevent = (tSirTdlsEventnotify *) pMsgBuf; + + switch (msgType) { + case eWNI_SME_TDLS_SEND_MGMT_RSP: + { + tSirSmeRsp *msg = (tSirSmeRsp *) pMsgBuf; + tCsrRoamInfo roam_info = {0}; + + /* remove pending eSmeCommandTdlsDiscovery command */ + csr_tdls_remove_sme_cmd(pMac, eSmeCommandTdlsSendMgmt); + if (eSIR_SME_SUCCESS != msg->statusCode) { + /* Tx failed, so there wont be any ack confirmation*/ + /* Indicate ack failure to upper layer */ + roamInfo.reasonCode = 0; + csr_roam_call_callback(pMac, msg->sessionId, + &roam_info, 0, + eCSR_ROAM_RESULT_MGMT_TX_COMPLETE_IND, + 0); + } + break; + } + case eWNI_SME_TDLS_ADD_STA_RSP: + qdf_copy_macaddr(&roamInfo.peerMac, &addStaRsp->peermac); + roamInfo.staId = addStaRsp->staId; + roamInfo.ucastSig = addStaRsp->ucastSig; + roamInfo.bcastSig = addStaRsp->bcastSig; + roamInfo.statusCode = addStaRsp->statusCode; + /* + * register peer with TL, we have to go through HDD as + * this is the only way to register any STA with TL. + */ + if (addStaRsp->tdlsAddOper == TDLS_OPER_ADD) + roamResult = eCSR_ROAM_RESULT_ADD_TDLS_PEER; + else /* addStaRsp->tdlsAddOper must be TDLS_OPER_UPDATE */ + roamResult = eCSR_ROAM_RESULT_UPDATE_TDLS_PEER; + csr_roam_call_callback(pMac, addStaRsp->sessionId, + &roamInfo, 0, eCSR_ROAM_TDLS_STATUS_UPDATE, + roamResult); + + /* remove pending eSmeCommandTdlsDiscovery command */ + csr_tdls_remove_sme_cmd(pMac, eSmeCommandTdlsAddPeer); + break; + case eWNI_SME_TDLS_DEL_STA_RSP: + qdf_copy_macaddr(&roamInfo.peerMac, &delStaRsp->peermac); + roamInfo.staId = delStaRsp->staId; + roamInfo.statusCode = delStaRsp->statusCode; + /* + * register peer with TL, we have to go through HDD as + * this is the only way to register any STA with TL. + */ + csr_roam_call_callback(pMac, delStaRsp->sessionId, + &roamInfo, 0, + eCSR_ROAM_TDLS_STATUS_UPDATE, + eCSR_ROAM_RESULT_DELETE_TDLS_PEER); + + csr_tdls_remove_sme_cmd(pMac, eSmeCommandTdlsDelPeer); + break; + case eWNI_SME_TDLS_DEL_STA_IND: + qdf_copy_macaddr(&roamInfo.peerMac, + &pSirTdlsDelStaInd->peermac); + roamInfo.staId = pSirTdlsDelStaInd->staId; + roamInfo.reasonCode = pSirTdlsDelStaInd->reasonCode; + + /* Sending the TEARDOWN indication to HDD. */ + csr_roam_call_callback(pMac, + pSirTdlsDelStaInd->sessionId, &roamInfo, + 0, eCSR_ROAM_TDLS_STATUS_UPDATE, + eCSR_ROAM_RESULT_TEARDOWN_TDLS_PEER_IND); + break; + case eWNI_SME_TDLS_DEL_ALL_PEER_IND: + /* Sending the TEARDOWN indication to HDD. */ + csr_roam_call_callback(pMac, + pSirTdlsDelAllPeerInd->sessionId, + &roamInfo, 0, + eCSR_ROAM_TDLS_STATUS_UPDATE, + eCSR_ROAM_RESULT_DELETE_ALL_TDLS_PEER_IND); + break; + case eWNI_SME_MGMT_FRM_TX_COMPLETION_IND: + roamInfo.reasonCode = + tdls_tx_comp_ind->txCompleteStatus; + + csr_roam_call_callback(pMac, + tdls_tx_comp_ind->sessionId, + &roamInfo, 0, + eCSR_ROAM_RESULT_MGMT_TX_COMPLETE_IND, + 0); + break; + case eWNI_SME_TDLS_LINK_ESTABLISH_RSP: + csr_roam_call_callback(pMac, + linkEstablishReqRsp->sessionId, + &roamInfo, 0, + eCSR_ROAM_TDLS_STATUS_UPDATE, + eCSR_ROAM_RESULT_LINK_ESTABLISH_REQ_RSP); + /* remove pending eSmeCommandTdlsLinkEstablish command */ + csr_tdls_remove_sme_cmd(pMac, eSmeCommandTdlsLinkEstablish); + break; + case eWNI_SME_TDLS_SHOULD_DISCOVER: + qdf_copy_macaddr(&roamInfo.peerMac, &tevent->peermac); + roamInfo.reasonCode = tevent->peer_reason; + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO, + "%s: eWNI_SME_TDLS_SHOULD_DISCOVER for peer mac: " + MAC_ADDRESS_STR " peer_reason: %d", + __func__, MAC_ADDR_ARRAY(tevent->peermac.bytes), + tevent->peer_reason); + csr_roam_call_callback(pMac, tevent->sessionId, &roamInfo, + 0, eCSR_ROAM_TDLS_STATUS_UPDATE, + eCSR_ROAM_RESULT_TDLS_SHOULD_DISCOVER); + break; + case eWNI_SME_TDLS_SHOULD_TEARDOWN: + qdf_copy_macaddr(&roamInfo.peerMac, &tevent->peermac); + roamInfo.reasonCode = tevent->peer_reason; + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO, + "%s: eWNI_SME_TDLS_SHOULD_TEARDOWN for peer mac: " + MAC_ADDRESS_STR " peer_reason: %d", + __func__, MAC_ADDR_ARRAY(tevent->peermac.bytes), + tevent->peer_reason); + csr_roam_call_callback(pMac, tevent->sessionId, &roamInfo, + 0, eCSR_ROAM_TDLS_STATUS_UPDATE, + eCSR_ROAM_RESULT_TDLS_SHOULD_TEARDOWN); + break; + case eWNI_SME_TDLS_PEER_DISCONNECTED: + qdf_copy_macaddr(&roamInfo.peerMac, &tevent->peermac); + roamInfo.reasonCode = tevent->peer_reason; + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO, + "%s: eWNI_SME_TDLS_PEER_DISCONNECTED for peer mac: " + MAC_ADDRESS_STR " peer_reason: %d", + __func__, MAC_ADDR_ARRAY(tevent->peermac.bytes), + tevent->peer_reason); + csr_roam_call_callback(pMac, tevent->sessionId, &roamInfo, + 0, eCSR_ROAM_TDLS_STATUS_UPDATE, + eCSR_ROAM_RESULT_TDLS_SHOULD_PEER_DISCONNECTED); + break; + case eWNI_SME_TDLS_CONNECTION_TRACKER_NOTIFICATION: + qdf_copy_macaddr(&roamInfo.peerMac, &tevent->peermac); + roamInfo.reasonCode = tevent->peer_reason; + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO, + "%s: eWNI_SME_TDLS_CONNECTION_TRACKER_NOTIFICATION for peer mac: " + MAC_ADDRESS_STR " peer_reason: %d", + __func__, MAC_ADDR_ARRAY(tevent->peermac.bytes), + tevent->peer_reason); + csr_roam_call_callback(pMac, tevent->sessionId, &roamInfo, + 0, eCSR_ROAM_TDLS_STATUS_UPDATE, + eCSR_ROAM_RESULT_TDLS_CONNECTION_TRACKER_NOTIFICATION); + break; + default: + break; + } + + return QDF_STATUS_SUCCESS; +} +#endif diff --git a/drivers/staging/qcacld-3.0/core/sme/src/csr/csr_util.c b/drivers/staging/qcacld-3.0/core/sme/src/csr/csr_util.c new file mode 100644 index 0000000000000000000000000000000000000000..d5b3dea78f963876c209b0b611295330a9ca139f --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/sme/src/csr/csr_util.c @@ -0,0 +1,5764 @@ +/* + * Copyright (c) 2011-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** ------------------------------------------------------------------------- * + ------------------------------------------------------------------------- * + + \file csr_util.c + + Implementation supporting routines for CSR. + ========================================================================== */ + +#include "ani_global.h" + +#include "csr_support.h" +#include "csr_inside_api.h" +#include "sms_debug.h" +#include "sme_qos_internal.h" +#include "wma_types.h" +#include "cds_utils.h" +#include "cds_concurrency.h" + + +uint8_t csr_wpa_oui[][CSR_WPA_OUI_SIZE] = { + {0x00, 0x50, 0xf2, 0x00} + , + {0x00, 0x50, 0xf2, 0x01} + , + {0x00, 0x50, 0xf2, 0x02} + , + {0x00, 0x50, 0xf2, 0x03} + , + {0x00, 0x50, 0xf2, 0x04} + , + {0x00, 0x50, 0xf2, 0x05} + , +#ifdef FEATURE_WLAN_ESE + {0x00, 0x40, 0x96, 0x00} + , /* CCKM */ +#endif /* FEATURE_WLAN_ESE */ +}; + +uint8_t csr_rsn_oui[][CSR_RSN_OUI_SIZE] = { + {0x00, 0x0F, 0xAC, 0x00} + , /* group cipher */ + {0x00, 0x0F, 0xAC, 0x01} + , /* WEP-40 or RSN */ + {0x00, 0x0F, 0xAC, 0x02} + , /* TKIP or RSN-PSK */ + {0x00, 0x0F, 0xAC, 0x03} + , /* Reserved */ + {0x00, 0x0F, 0xAC, 0x04} + , /* AES-CCMP */ + {0x00, 0x0F, 0xAC, 0x05} + , /* WEP-104 */ + {0x00, 0x40, 0x96, 0x00} + , /* CCKM */ + {0x00, 0x0F, 0xAC, 0x06} + , /* BIP (encryption type) or + RSN-PSK-SHA256 (authentication type) */ + /* RSN-8021X-SHA256 (authentication type) */ + {0x00, 0x0F, 0xAC, 0x05} +}; + +#ifdef FEATURE_WLAN_WAPI +uint8_t csr_wapi_oui[][CSR_WAPI_OUI_SIZE] = { + {0x00, 0x14, 0x72, 0x00} + , /* Reserved */ + {0x00, 0x14, 0x72, 0x01} + , /* WAI certificate or SMS4 */ + {0x00, 0x14, 0x72, 0x02} /* WAI PSK */ +}; +#endif /* FEATURE_WLAN_WAPI */ +uint8_t csr_wme_info_oui[CSR_WME_OUI_SIZE] = { 0x00, 0x50, 0xf2, 0x02 }; +uint8_t csr_wme_parm_oui[CSR_WME_OUI_SIZE] = { 0x00, 0x50, 0xf2, 0x02 }; + +/* ////////////////////////////////////////////////////////////////////// */ + +/** + * \var g_phy_rates_suppt + * + * \brief Rate support lookup table + * + * + * This is a lookup table indexing rates & configuration parameters to + * support. Given a rate (in unites of 0.5Mpbs) & three bools (MIMO + * Enabled, Channel Bonding Enabled, & Concatenation Enabled), one can + * determine whether the given rate is supported by computing two + * indices. The first maps the rate to table row as indicated below + * (i.e. eHddSuppRate_6Mbps maps to row zero, eHddSuppRate_9Mbps to row + * 1, and so on). Index two can be computed like so: + * + * \code + * idx2 = ( fEsf ? 0x4 : 0x0 ) | + * ( fCb ? 0x2 : 0x0 ) | + * ( fMimo ? 0x1 : 0x0 ); + * \endcode + * + * + * Given that: + * + * \code + * fSupported = g_phy_rates_suppt[idx1][idx2]; + * \endcode + * + * + * This table is based on the document "PHY Supported Rates.doc". This + * table is permissive in that a rate is reflected as being supported + * even when turning off an enabled feature would be required. For + * instance, "PHY Supported Rates" lists 42Mpbs as unsupported when CB, + * ESF, & MIMO are all on. However, if we turn off either of CB or + * MIMO, it then becomes supported. Therefore, we mark it as supported + * even in index 7 of this table. + * + * + */ + +static const bool g_phy_rates_suppt[24][8] = { + + /* SSF SSF SSF SSF ESF ESF ESF ESF */ + /* SIMO MIMO SIMO MIMO SIMO MIMO SIMO MIMO */ + /* No CB No CB CB CB No CB No CB CB CB */ + {true, true, true, true, true, true, true, true}, /* 6Mbps */ + {true, true, true, true, true, true, true, true}, /* 9Mbps */ + {true, true, true, true, true, true, true, true}, /* 12Mbps */ + {true, true, true, true, true, true, true, true}, /* 18Mbps */ + {false, false, true, true, false, false, true, true}, /* 20Mbps */ + {true, true, true, true, true, true, true, true}, /* 24Mbps */ + {true, true, true, true, true, true, true, true}, /* 36Mbps */ + {false, false, true, true, false, true, true, true}, /* 40Mbps */ + {false, false, true, true, false, true, true, true}, /* 42Mbps */ + {true, true, true, true, true, true, true, true}, /* 48Mbps */ + {true, true, true, true, true, true, true, true}, /* 54Mbps */ + {false, true, true, true, false, true, true, true}, /* 72Mbps */ + {false, false, true, true, false, true, true, true}, /* 80Mbps */ + {false, false, true, true, false, true, true, true}, /* 84Mbps */ + {false, true, true, true, false, true, true, true}, /* 96Mbps */ + {false, true, true, true, false, true, true, true}, /* 108Mbps */ + {false, false, true, true, false, true, true, true}, /* 120Mbps */ + {false, false, true, true, false, true, true, true}, /* 126Mbps */ + {false, false, false, true, false, false, false, true}, /* 144Mbps */ + {false, false, false, true, false, false, false, true}, /* 160Mbps */ + {false, false, false, true, false, false, false, true}, /* 168Mbps */ + {false, false, false, true, false, false, false, true}, /* 192Mbps */ + {false, false, false, true, false, false, false, true}, /* 216Mbps */ + {false, false, false, true, false, false, false, true}, /* 240Mbps */ + +}; + +#define CASE_RETURN_STR(n) {\ + case (n): return (# n);\ +} + +const char *get_e_roam_cmd_status_str(eRoamCmdStatus val) +{ + switch (val) { + CASE_RETURN_STR(eCSR_ROAM_CANCELLED); + CASE_RETURN_STR(eCSR_ROAM_FAILED); + CASE_RETURN_STR(eCSR_ROAM_ROAMING_START); + CASE_RETURN_STR(eCSR_ROAM_ROAMING_COMPLETION); + CASE_RETURN_STR(eCSR_ROAM_CONNECT_COMPLETION); + CASE_RETURN_STR(eCSR_ROAM_ASSOCIATION_START); + CASE_RETURN_STR(eCSR_ROAM_ASSOCIATION_COMPLETION); + CASE_RETURN_STR(eCSR_ROAM_DISASSOCIATED); + CASE_RETURN_STR(eCSR_ROAM_ASSOCIATION_FAILURE); + CASE_RETURN_STR(eCSR_ROAM_SHOULD_ROAM); + CASE_RETURN_STR(eCSR_ROAM_SCAN_FOUND_NEW_BSS); + CASE_RETURN_STR(eCSR_ROAM_LOSTLINK); + CASE_RETURN_STR(eCSR_ROAM_LOSTLINK_DETECTED); + CASE_RETURN_STR(eCSR_ROAM_MIC_ERROR_IND); + CASE_RETURN_STR(eCSR_ROAM_IBSS_IND); + CASE_RETURN_STR(eCSR_ROAM_CONNECT_STATUS_UPDATE); + CASE_RETURN_STR(eCSR_ROAM_GEN_INFO); + CASE_RETURN_STR(eCSR_ROAM_SET_KEY_COMPLETE); + CASE_RETURN_STR(eCSR_ROAM_IBSS_LEAVE); + CASE_RETURN_STR(eCSR_ROAM_INFRA_IND); + CASE_RETURN_STR(eCSR_ROAM_WPS_PBC_PROBE_REQ_IND); + CASE_RETURN_STR(eCSR_ROAM_FT_RESPONSE); + CASE_RETURN_STR(eCSR_ROAM_FT_START); + CASE_RETURN_STR(eCSR_ROAM_REMAIN_CHAN_READY); + CASE_RETURN_STR(eCSR_ROAM_SESSION_OPENED); + CASE_RETURN_STR(eCSR_ROAM_FT_REASSOC_FAILED); + CASE_RETURN_STR(eCSR_ROAM_PMK_NOTIFY); +#ifdef FEATURE_WLAN_LFR_METRICS + CASE_RETURN_STR(eCSR_ROAM_PREAUTH_INIT_NOTIFY); + CASE_RETURN_STR(eCSR_ROAM_PREAUTH_STATUS_SUCCESS); + CASE_RETURN_STR(eCSR_ROAM_PREAUTH_STATUS_FAILURE); + CASE_RETURN_STR(eCSR_ROAM_HANDOVER_SUCCESS); +#endif +#ifdef FEATURE_WLAN_TDLS + CASE_RETURN_STR(eCSR_ROAM_TDLS_STATUS_UPDATE); + CASE_RETURN_STR(eCSR_ROAM_RESULT_MGMT_TX_COMPLETE_IND); +#endif + CASE_RETURN_STR(eCSR_ROAM_DISCONNECT_ALL_P2P_CLIENTS); + CASE_RETURN_STR(eCSR_ROAM_SEND_P2P_STOP_BSS); +#ifdef WLAN_FEATURE_11W + CASE_RETURN_STR(eCSR_ROAM_UNPROT_MGMT_FRAME_IND); +#endif +#ifdef WLAN_FEATURE_RMC + CASE_RETURN_STR(eCSR_ROAM_IBSS_PEER_INFO_COMPLETE); +#endif +#ifdef FEATURE_WLAN_ESE + CASE_RETURN_STR(eCSR_ROAM_TSM_IE_IND); + CASE_RETURN_STR(eCSR_ROAM_CCKM_PREAUTH_NOTIFY); + CASE_RETURN_STR(eCSR_ROAM_ESE_ADJ_AP_REPORT_IND); + CASE_RETURN_STR(eCSR_ROAM_ESE_BCN_REPORT_IND); +#endif /* FEATURE_WLAN_ESE */ + CASE_RETURN_STR(eCSR_ROAM_DFS_RADAR_IND); + CASE_RETURN_STR(eCSR_ROAM_SET_CHANNEL_RSP); + CASE_RETURN_STR(eCSR_ROAM_DFS_CHAN_SW_NOTIFY); + CASE_RETURN_STR(eCSR_ROAM_EXT_CHG_CHNL_IND); + CASE_RETURN_STR(eCSR_ROAM_STA_CHANNEL_SWITCH); + CASE_RETURN_STR(eCSR_ROAM_NDP_STATUS_UPDATE); + CASE_RETURN_STR(eCSR_ROAM_UPDATE_SCAN_RESULT); + CASE_RETURN_STR(eCSR_ROAM_START); + CASE_RETURN_STR(eCSR_ROAM_ABORT); + CASE_RETURN_STR(eCSR_ROAM_NAPI_OFF); + default: + return "unknown"; + } +} + +const char *get_e_csr_roam_result_str(eCsrRoamResult val) +{ + switch (val) { + CASE_RETURN_STR(eCSR_ROAM_RESULT_NONE); + CASE_RETURN_STR(eCSR_ROAM_RESULT_FAILURE); + CASE_RETURN_STR(eCSR_ROAM_RESULT_ASSOCIATED); + CASE_RETURN_STR(eCSR_ROAM_RESULT_NOT_ASSOCIATED); + CASE_RETURN_STR(eCSR_ROAM_RESULT_MIC_FAILURE); + CASE_RETURN_STR(eCSR_ROAM_RESULT_FORCED); + CASE_RETURN_STR(eCSR_ROAM_RESULT_DISASSOC_IND); + CASE_RETURN_STR(eCSR_ROAM_RESULT_DEAUTH_IND); + CASE_RETURN_STR(eCSR_ROAM_RESULT_CAP_CHANGED); + CASE_RETURN_STR(eCSR_ROAM_RESULT_IBSS_STARTED); + CASE_RETURN_STR(eCSR_ROAM_RESULT_IBSS_START_FAILED); + CASE_RETURN_STR(eCSR_ROAM_RESULT_IBSS_JOIN_SUCCESS); + CASE_RETURN_STR(eCSR_ROAM_RESULT_IBSS_JOIN_FAILED); + CASE_RETURN_STR(eCSR_ROAM_RESULT_IBSS_CONNECT); + CASE_RETURN_STR(eCSR_ROAM_RESULT_IBSS_INACTIVE); + CASE_RETURN_STR(eCSR_ROAM_RESULT_IBSS_NEW_PEER); + CASE_RETURN_STR(eCSR_ROAM_RESULT_IBSS_PEER_DEPARTED); + CASE_RETURN_STR(eCSR_ROAM_RESULT_IBSS_COALESCED); + CASE_RETURN_STR(eCSR_ROAM_RESULT_IBSS_STOP); + CASE_RETURN_STR(eCSR_ROAM_RESULT_LOSTLINK); + CASE_RETURN_STR(eCSR_ROAM_RESULT_MIC_ERROR_UNICAST); + CASE_RETURN_STR(eCSR_ROAM_RESULT_MIC_ERROR_GROUP); + CASE_RETURN_STR(eCSR_ROAM_RESULT_AUTHENTICATED); + CASE_RETURN_STR(eCSR_ROAM_RESULT_NEW_RSN_BSS); + #ifdef FEATURE_WLAN_WAPI + CASE_RETURN_STR(eCSR_ROAM_RESULT_NEW_WAPI_BSS); + #endif /* FEATURE_WLAN_WAPI */ + CASE_RETURN_STR(eCSR_ROAM_RESULT_INFRA_STARTED); + CASE_RETURN_STR(eCSR_ROAM_RESULT_INFRA_START_FAILED); + CASE_RETURN_STR(eCSR_ROAM_RESULT_INFRA_STOPPED); + CASE_RETURN_STR(eCSR_ROAM_RESULT_INFRA_ASSOCIATION_IND); + CASE_RETURN_STR(eCSR_ROAM_RESULT_INFRA_ASSOCIATION_CNF); + CASE_RETURN_STR(eCSR_ROAM_RESULT_INFRA_DISASSOCIATED); + CASE_RETURN_STR(eCSR_ROAM_RESULT_WPS_PBC_PROBE_REQ_IND); + CASE_RETURN_STR(eCSR_ROAM_RESULT_SEND_ACTION_FAIL); + CASE_RETURN_STR(eCSR_ROAM_RESULT_MAX_ASSOC_EXCEEDED); + CASE_RETURN_STR(eCSR_ROAM_RESULT_ASSOC_FAIL_CON_CHANNEL); + CASE_RETURN_STR(eCSR_ROAM_RESULT_ADD_TDLS_PEER); + CASE_RETURN_STR(eCSR_ROAM_RESULT_UPDATE_TDLS_PEER); + CASE_RETURN_STR(eCSR_ROAM_RESULT_DELETE_TDLS_PEER); + CASE_RETURN_STR(eCSR_ROAM_RESULT_TEARDOWN_TDLS_PEER_IND); + CASE_RETURN_STR(eCSR_ROAM_RESULT_DELETE_ALL_TDLS_PEER_IND); + CASE_RETURN_STR(eCSR_ROAM_RESULT_LINK_ESTABLISH_REQ_RSP); + CASE_RETURN_STR(eCSR_ROAM_RESULT_TDLS_SHOULD_DISCOVER); + CASE_RETURN_STR(eCSR_ROAM_RESULT_TDLS_SHOULD_TEARDOWN); + CASE_RETURN_STR(eCSR_ROAM_RESULT_TDLS_SHOULD_PEER_DISCONNECTED); + CASE_RETURN_STR + (eCSR_ROAM_RESULT_TDLS_CONNECTION_TRACKER_NOTIFICATION); + CASE_RETURN_STR(eCSR_ROAM_RESULT_IBSS_PEER_INFO_SUCCESS); + CASE_RETURN_STR(eCSR_ROAM_RESULT_IBSS_PEER_INFO_FAILED); + CASE_RETURN_STR(eCSR_ROAM_RESULT_DFS_RADAR_FOUND_IND); + CASE_RETURN_STR(eCSR_ROAM_RESULT_CHANNEL_CHANGE_SUCCESS); + CASE_RETURN_STR(eCSR_ROAM_RESULT_CHANNEL_CHANGE_FAILURE); + CASE_RETURN_STR(eCSR_ROAM_RESULT_DFS_CHANSW_UPDATE_SUCCESS); + CASE_RETURN_STR(eCSR_ROAM_EXT_CHG_CHNL_UPDATE_IND); + CASE_RETURN_STR(eCSR_ROAM_RESULT_NDI_CREATE_RSP); + CASE_RETURN_STR(eCSR_ROAM_RESULT_NDI_DELETE_RSP); + CASE_RETURN_STR(eCSR_ROAM_RESULT_NDP_INITIATOR_RSP); + CASE_RETURN_STR(eCSR_ROAM_RESULT_NDP_NEW_PEER_IND); + CASE_RETURN_STR(eCSR_ROAM_RESULT_NDP_CONFIRM_IND); + CASE_RETURN_STR(eCSR_ROAM_RESULT_NDP_INDICATION); + CASE_RETURN_STR(eCSR_ROAM_RESULT_NDP_SCHED_UPDATE_RSP); + CASE_RETURN_STR(eCSR_ROAM_RESULT_NDP_RESPONDER_RSP); + CASE_RETURN_STR(eCSR_ROAM_RESULT_NDP_END_RSP); + CASE_RETURN_STR(eCSR_ROAM_RESULT_NDP_PEER_DEPARTED_IND); + CASE_RETURN_STR(eCSR_ROAM_RESULT_NDP_END_IND); + CASE_RETURN_STR(eCSR_ROAM_RESULT_SCAN_FOR_SSID_FAILURE); + default: + return "unknown"; + } +} + +bool csr_get_bss_id_bss_desc(tHalHandle hHal, tSirBssDescription *pSirBssDesc, + struct qdf_mac_addr *pBssId) +{ + qdf_mem_copy(pBssId, &pSirBssDesc->bssId[0], + sizeof(struct qdf_mac_addr)); + return true; +} + +bool csr_is_bss_id_equal(tHalHandle hHal, tSirBssDescription *pSirBssDesc1, + tSirBssDescription *pSirBssDesc2) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + bool fEqual = false; + struct qdf_mac_addr bssId1; + struct qdf_mac_addr bssId2; + + do { + if (!pSirBssDesc1) + break; + if (!pSirBssDesc2) + break; + + if (!csr_get_bss_id_bss_desc(pMac, pSirBssDesc1, &bssId1)) + break; + if (!csr_get_bss_id_bss_desc(pMac, pSirBssDesc2, &bssId2)) + break; + + fEqual = qdf_is_macaddr_equal(&bssId1, &bssId2); + } while (0); + + return fEqual; +} + +bool csr_is_conn_state_connected_ibss(tpAniSirGlobal pMac, uint32_t sessionId) +{ + return eCSR_ASSOC_STATE_TYPE_IBSS_CONNECTED == + pMac->roam.roamSession[sessionId].connectState; +} + +bool csr_is_conn_state_disconnected_ibss(tpAniSirGlobal pMac, + uint32_t sessionId) +{ + return eCSR_ASSOC_STATE_TYPE_IBSS_DISCONNECTED == + pMac->roam.roamSession[sessionId].connectState; +} + +bool csr_is_conn_state_connected_infra(tpAniSirGlobal pMac, uint32_t sessionId) +{ + return eCSR_ASSOC_STATE_TYPE_INFRA_ASSOCIATED == + pMac->roam.roamSession[sessionId].connectState; +} + +bool csr_is_conn_state_connected(tpAniSirGlobal pMac, uint32_t sessionId) +{ + if (csr_is_conn_state_connected_ibss(pMac, sessionId) + || csr_is_conn_state_connected_infra(pMac, sessionId) + || csr_is_conn_state_connected_wds(pMac, sessionId)) + return true; + else + return false; +} + +bool csr_is_conn_state_infra(tpAniSirGlobal pMac, uint32_t sessionId) +{ + return csr_is_conn_state_connected_infra(pMac, sessionId); +} + +bool csr_is_conn_state_ibss(tpAniSirGlobal pMac, uint32_t sessionId) +{ + return csr_is_conn_state_connected_ibss(pMac, sessionId) || + csr_is_conn_state_disconnected_ibss(pMac, sessionId); +} + +bool csr_is_conn_state_connected_wds(tpAniSirGlobal pMac, uint32_t sessionId) +{ + return eCSR_ASSOC_STATE_TYPE_WDS_CONNECTED == + pMac->roam.roamSession[sessionId].connectState; +} + +bool csr_is_conn_state_connected_infra_ap(tpAniSirGlobal pMac, + uint32_t sessionId) +{ + return (eCSR_ASSOC_STATE_TYPE_INFRA_CONNECTED == + pMac->roam.roamSession[sessionId].connectState) || + (eCSR_ASSOC_STATE_TYPE_INFRA_DISCONNECTED == + pMac->roam.roamSession[sessionId].connectState); +} + +bool csr_is_conn_state_disconnected_wds(tpAniSirGlobal pMac, uint32_t sessionId) +{ + return eCSR_ASSOC_STATE_TYPE_WDS_DISCONNECTED == + pMac->roam.roamSession[sessionId].connectState; +} + +bool csr_is_conn_state_wds(tpAniSirGlobal pMac, uint32_t sessionId) +{ + return csr_is_conn_state_connected_wds(pMac, sessionId) || + csr_is_conn_state_disconnected_wds(pMac, sessionId); +} + +static bool csr_is_conn_state_ap(tpAniSirGlobal pMac, uint32_t sessionId) +{ + tCsrRoamSession *pSession; + pSession = CSR_GET_SESSION(pMac, sessionId); + if (!pSession) + return false; + if (CSR_IS_INFRA_AP(&pSession->connectedProfile)) + return true; + return false; +} + +bool csr_is_any_session_in_connect_state(tpAniSirGlobal pMac) +{ + uint32_t i; + bool fRc = false; + + for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) { + if (CSR_IS_SESSION_VALID(pMac, i) && + (csr_is_conn_state_infra(pMac, i) + || csr_is_conn_state_ibss(pMac, i) + || csr_is_conn_state_ap(pMac, i))) { + fRc = true; + break; + } + } + + return fRc; +} + +int8_t csr_get_infra_session_id(tpAniSirGlobal pMac) +{ + uint8_t i; + int8_t sessionid = -1; + + for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) { + if (CSR_IS_SESSION_VALID(pMac, i) + && csr_is_conn_state_infra(pMac, i)) { + sessionid = i; + break; + } + } + + return sessionid; +} + +uint8_t csr_get_infra_operation_channel(tpAniSirGlobal pMac, uint8_t sessionId) +{ + uint8_t channel; + + if (CSR_IS_SESSION_VALID(pMac, sessionId)) { + channel = + pMac->roam.roamSession[sessionId].connectedProfile. + operationChannel; + } else { + channel = 0; + } + return channel; +} + +bool csr_is_session_client_and_connected(tpAniSirGlobal pMac, uint8_t sessionId) +{ + tCsrRoamSession *pSession = NULL; + if (CSR_IS_SESSION_VALID(pMac, sessionId) + && csr_is_conn_state_infra(pMac, sessionId)) { + pSession = CSR_GET_SESSION(pMac, sessionId); + if (NULL != pSession->pCurRoamProfile) { + if ((pSession->pCurRoamProfile->csrPersona == + QDF_STA_MODE) + || (pSession->pCurRoamProfile->csrPersona == + QDF_P2P_CLIENT_MODE)) + return true; + } + } + return false; +} + +/** + * csr_get_concurrent_operation_channel() - To get concurrent operating channel + * @mac_ctx: Pointer to mac context + * + * This routine will return operating channel on FIRST BSS that is + * active/operating to be used for concurrency mode. + * If other BSS is not up or not connected it will return 0 + * + * Return: uint8_t + */ +uint8_t csr_get_concurrent_operation_channel(tpAniSirGlobal mac_ctx) +{ + tCsrRoamSession *session = NULL; + uint8_t i = 0; + enum tQDF_ADAPTER_MODE persona; + + for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) { + if (!CSR_IS_SESSION_VALID(mac_ctx, i)) + continue; + session = CSR_GET_SESSION(mac_ctx, i); + if (NULL == session->pCurRoamProfile) + continue; + persona = session->pCurRoamProfile->csrPersona; + if ((((persona == QDF_STA_MODE) || + (persona == QDF_P2P_CLIENT_MODE)) && + (session->connectState == + eCSR_ASSOC_STATE_TYPE_INFRA_ASSOCIATED)) || + (((persona == QDF_P2P_GO_MODE) || + (persona == QDF_SAP_MODE)) + && (session->connectState != + eCSR_ASSOC_STATE_TYPE_NOT_CONNECTED))) + return session->connectedProfile.operationChannel; + + } + return 0; +} + +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH + +#define HALF_BW_OF(eCSR_bw_val) ((eCSR_bw_val)/2) + +/* calculation of center channel based on V/HT BW and WIFI channel bw=5MHz) */ + +#define CSR_GET_HT40_PLUS_CCH(och) ((och)+2) +#define CSR_GET_HT40_MINUS_CCH(och) ((och)-2) + +#define CSR_GET_HT80_PLUS_LL_CCH(och) ((och)+6) +#define CSR_GET_HT80_PLUS_HL_CCH(och) ((och)+2) +#define CSR_GET_HT80_MINUS_LH_CCH(och) ((och)-2) +#define CSR_GET_HT80_MINUS_HH_CCH(och) ((och)-6) + +/** + * csr_get_ch_from_ht_profile() - to get channel from HT profile + * @pMac: pointer to Mac context + * @htp: pointer to HT profile + * @och: operating channel + * @cfreq: channel frequency + * @hbw: half bandwidth + * + * This function will fill half bandwidth and channel frequency based + * on the HT profile + * + * Return: none + */ +static void csr_get_ch_from_ht_profile(tpAniSirGlobal pMac, + tCsrRoamHTProfile *htp, + uint16_t och, uint16_t *cfreq, + uint16_t *hbw) +{ + uint16_t cch, ch_bond; + + if (och > 14) + ch_bond = pMac->roam.configParam.channelBondingMode5GHz; + else + ch_bond = pMac->roam.configParam.channelBondingMode24GHz; + + cch = och; + *hbw = HALF_BW_OF(eCSR_BW_20MHz_VAL); + + if (!ch_bond) + goto ret; + + sms_log(pMac, LOG1, FL("##HTC: %d scbw: %d rcbw: %d sco: %d" + "VHTC: %d apc: %d apbw: %d" + ), + htp->htCapability, htp->htSupportedChannelWidthSet, + htp->htRecommendedTxWidthSet, + htp->htSecondaryChannelOffset, + htp->vhtCapability, htp->apCenterChan, htp->apChanWidth + ); + + if (htp->vhtCapability) { + cch = htp->apCenterChan; + if (htp->apChanWidth == WNI_CFG_VHT_CHANNEL_WIDTH_80MHZ) + *hbw = HALF_BW_OF(eCSR_BW_80MHz_VAL); + else if (htp->apChanWidth == WNI_CFG_VHT_CHANNEL_WIDTH_160MHZ) + *hbw = HALF_BW_OF(eCSR_BW_160MHz_VAL); + + if (!*hbw && htp->htCapability) { + if (htp->htSupportedChannelWidthSet == + eHT_CHANNEL_WIDTH_40MHZ) + *hbw = HALF_BW_OF(eCSR_BW_40MHz_VAL); + else + *hbw = HALF_BW_OF(eCSR_BW_20MHz_VAL); + } + } else if (htp->htCapability) { + if (htp->htSupportedChannelWidthSet == + eHT_CHANNEL_WIDTH_40MHZ) { + *hbw = HALF_BW_OF(eCSR_BW_40MHz_VAL); + if (htp->htSecondaryChannelOffset == + PHY_DOUBLE_CHANNEL_LOW_PRIMARY) + cch = CSR_GET_HT40_PLUS_CCH(och); + else if (htp->htSecondaryChannelOffset == + PHY_DOUBLE_CHANNEL_HIGH_PRIMARY) + cch = CSR_GET_HT40_MINUS_CCH(och); + } else { + cch = och; + *hbw = HALF_BW_OF(eCSR_BW_20MHz_VAL); + } + } + +ret: + *cfreq = cds_chan_to_freq(cch); + return; +} + +/** + * csr_calc_chb_for_sap_phymode() - to calc channel bandwidth for sap phymode + * @mac_ctx: pointer to mac context + * @sap_ch: SAP operating channel + * @sap_phymode: SAP physical mode + * @sap_cch: concurrency channel + * @sap_hbw: SAP half bw + * @chb: channel bandwidth + * + * This routine is called to calculate channel bandwidth + * + * Return: none + */ +static void csr_calc_chb_for_sap_phymode(tpAniSirGlobal mac_ctx, + uint16_t *sap_ch, eCsrPhyMode *sap_phymode, + uint16_t *sap_cch, uint16_t *sap_hbw, uint8_t *chb) +{ + if (*sap_phymode == eCSR_DOT11_MODE_11n || + *sap_phymode == eCSR_DOT11_MODE_11n_ONLY) { + + *sap_hbw = HALF_BW_OF(eCSR_BW_40MHz_VAL); + if (*chb == PHY_DOUBLE_CHANNEL_LOW_PRIMARY) + *sap_cch = CSR_GET_HT40_PLUS_CCH(*sap_ch); + else if (*chb == PHY_DOUBLE_CHANNEL_HIGH_PRIMARY) + *sap_cch = CSR_GET_HT40_MINUS_CCH(*sap_ch); + + } else if (*sap_phymode == eCSR_DOT11_MODE_11ac || + *sap_phymode == eCSR_DOT11_MODE_11ac_ONLY) { + /*11AC only 80/40/20 Mhz supported in Rome */ + if (mac_ctx->roam.configParam.nVhtChannelWidth == + (WNI_CFG_VHT_CHANNEL_WIDTH_80MHZ + 1)) { + *sap_hbw = HALF_BW_OF(eCSR_BW_80MHz_VAL); + if (*chb == + (PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_LOW - 1)) + *sap_cch = CSR_GET_HT80_PLUS_LL_CCH(*sap_ch); + else if (*chb == + (PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_LOW + - 1)) + *sap_cch = CSR_GET_HT80_PLUS_HL_CCH(*sap_ch); + else if (*chb == + (PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_HIGH + - 1)) + *sap_cch = CSR_GET_HT80_MINUS_LH_CCH(*sap_ch); + else if (*chb == + (PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_HIGH + - 1)) + *sap_cch = CSR_GET_HT80_MINUS_HH_CCH(*sap_ch); + } else { + *sap_hbw = HALF_BW_OF(eCSR_BW_40MHz_VAL); + if (*chb == (PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_LOW + - 1)) + *sap_cch = CSR_GET_HT40_PLUS_CCH(*sap_ch); + else if (*chb == + (PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_LOW + - 1)) + *sap_cch = CSR_GET_HT40_MINUS_CCH(*sap_ch); + else if (*chb == + (PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_HIGH + - 1)) + *sap_cch = CSR_GET_HT40_PLUS_CCH(*sap_ch); + else if (*chb == + (PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_HIGH + - 1)) + *sap_cch = CSR_GET_HT40_MINUS_CCH(*sap_ch); + } + } +} + +/** + * csr_handle_conc_chnl_overlap_for_sap_go - To handle overlap for AP+AP + * @mac_ctx: pointer to mac context + * @session: Current session + * @sap_ch: SAP/GO operating channel + * @sap_hbw: SAP/GO half bw + * @sap_cfreq: SAP/GO channel frequency + * @intf_ch: concurrent SAP/GO operating channel + * @intf_hbw: concurrent SAP/GO half bw + * @intf_cfreq: concurrent SAP/GO channel frequency + * + * This routine is called to check if one SAP/GO channel is overlapping with + * other SAP/GO channel + * + * Return: none + */ +static void csr_handle_conc_chnl_overlap_for_sap_go(tpAniSirGlobal mac_ctx, + tCsrRoamSession *session, + uint16_t *sap_ch, uint16_t *sap_hbw, uint16_t *sap_cfreq, + uint16_t *intf_ch, uint16_t *intf_hbw, uint16_t *intf_cfreq) +{ + /* + * if conc_custom_rule1 is defined then we don't + * want p2pgo to follow SAP's channel or SAP to + * follow P2PGO's channel. + */ + if (0 == mac_ctx->roam.configParam.conc_custom_rule1 && + 0 == mac_ctx->roam.configParam.conc_custom_rule2) { + if (*sap_ch == 0) { + *sap_ch = session->connectedProfile.operationChannel; + csr_get_ch_from_ht_profile(mac_ctx, + &session->connectedProfile.HTProfile, + *sap_ch, sap_cfreq, sap_hbw); + } else if (*sap_ch != + session->connectedProfile.operationChannel) { + *intf_ch = session->connectedProfile.operationChannel; + csr_get_ch_from_ht_profile(mac_ctx, + &session->connectedProfile.HTProfile, + *intf_ch, intf_cfreq, intf_hbw); + } + } else if (*sap_ch == 0 && + (session->pCurRoamProfile->csrPersona == + QDF_SAP_MODE)) { + *sap_ch = session->connectedProfile.operationChannel; + csr_get_ch_from_ht_profile(mac_ctx, + &session->connectedProfile.HTProfile, + *sap_ch, sap_cfreq, sap_hbw); + } +} + + +/** + * csr_check_concurrent_channel_overlap() - To check concurrent overlap chnls + * @mac_ctx: Pointer to mac context + * @sap_ch: SAP channel + * @sap_phymode: SAP phy mode + * @cc_switch_mode: concurrent switch mode + * + * This routine will be called to check concurrent overlap channels + * + * Return: uint16_t + */ +uint16_t csr_check_concurrent_channel_overlap(tpAniSirGlobal mac_ctx, + uint16_t sap_ch, eCsrPhyMode sap_phymode, + uint8_t cc_switch_mode) +{ + tCsrRoamSession *session = NULL; + uint8_t i = 0, chb = PHY_SINGLE_CHANNEL_CENTERED; + uint16_t intf_ch = 0, sap_hbw = 0, intf_hbw = 0, intf_cfreq = 0; + uint16_t sap_cfreq = 0; + uint16_t sap_lfreq, sap_hfreq, intf_lfreq, intf_hfreq, sap_cch = 0; + QDF_STATUS status; + + sms_log(mac_ctx, LOG1, FL("sap_ch:%d sap_phymode:%d"), + sap_ch, sap_phymode); + + if (mac_ctx->roam.configParam.cc_switch_mode == + QDF_MCC_TO_SCC_SWITCH_DISABLE) + return 0; + + if (sap_ch != 0) { + sap_cch = sap_ch; + sap_hbw = HALF_BW_OF(eCSR_BW_20MHz_VAL); + + if (sap_ch > 14) + chb = mac_ctx->roam.configParam.channelBondingMode5GHz; + else + chb = mac_ctx->roam.configParam.channelBondingMode24GHz; + + if (chb) + csr_calc_chb_for_sap_phymode(mac_ctx, &sap_ch, + &sap_phymode, &sap_cch, &sap_hbw, &chb); + sap_cfreq = cds_chan_to_freq(sap_cch); + } + + sms_log(mac_ctx, LOG1, + FL("sap_ch:%d sap_phymode:%d sap_cch:%d sap_hbw:%d chb:%d"), + sap_ch, sap_phymode, sap_cch, sap_hbw, chb); + + for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) { + if (!CSR_IS_SESSION_VALID(mac_ctx, i)) + continue; + + session = CSR_GET_SESSION(mac_ctx, i); + if (NULL == session->pCurRoamProfile) + continue; + if (((session->pCurRoamProfile->csrPersona == QDF_STA_MODE) || + (session->pCurRoamProfile->csrPersona == + QDF_P2P_CLIENT_MODE)) && + (session->connectState == + eCSR_ASSOC_STATE_TYPE_INFRA_ASSOCIATED)) { + intf_ch = session->connectedProfile.operationChannel; + csr_get_ch_from_ht_profile(mac_ctx, + &session->connectedProfile.HTProfile, + intf_ch, &intf_cfreq, &intf_hbw); + sms_log(mac_ctx, LOG1, + FL("%d: intf_ch:%d intf_cfreq:%d intf_hbw:%d"), + i, intf_ch, intf_cfreq, intf_hbw); + } else if (((session->pCurRoamProfile->csrPersona == + QDF_P2P_GO_MODE) || + (session->pCurRoamProfile->csrPersona == + QDF_SAP_MODE)) && + (session->connectState != + eCSR_ASSOC_STATE_TYPE_NOT_CONNECTED)) { + if (session->ch_switch_in_progress) + continue; + + csr_handle_conc_chnl_overlap_for_sap_go(mac_ctx, + session, &sap_ch, &sap_hbw, &sap_cfreq, + &intf_ch, &intf_hbw, &intf_cfreq); + + sms_log(mac_ctx, LOG1, + FL("%d: sap_ch:%d sap_hbw:%d sap_cfreq:%d intf_ch:%d intf_hbw:%d, intf_cfreq:%d"), + i, sap_ch, sap_hbw, sap_cfreq, + intf_ch, intf_hbw, intf_cfreq); + } + } + + sms_log(mac_ctx, LOG1, + FL("intf_ch:%d sap_ch:%d cc_switch_mode:%d"), + intf_ch, sap_ch, cc_switch_mode); + + if (intf_ch && sap_ch != intf_ch && + cc_switch_mode != QDF_MCC_TO_SCC_SWITCH_FORCE && + cc_switch_mode != + QDF_MCC_TO_SCC_SWITCH_FORCE_WITHOUT_DISCONNECTION && + cc_switch_mode != + QDF_MCC_TO_SCC_SWITCH_WITH_FAVORITE_CHANNEL) { + sap_lfreq = sap_cfreq - sap_hbw; + sap_hfreq = sap_cfreq + sap_hbw; + intf_lfreq = intf_cfreq - intf_hbw; + intf_hfreq = intf_cfreq + intf_hbw; + + sms_log(mac_ctx, LOGE, + FL("\nSAP: OCH: %03d OCF: %d CCH: %03d CF: %d BW: %d LF: %d HF: %d\n" + "INTF: OCH: %03d OCF: %d CCH: %03d CF: %d BW: %d LF: %d HF: %d"), + sap_ch, cds_chan_to_freq(sap_ch), + cds_freq_to_chan(sap_cfreq), sap_cfreq, sap_hbw * 2, + sap_lfreq, sap_hfreq, intf_ch, + cds_chan_to_freq(intf_ch), cds_freq_to_chan(intf_cfreq), + intf_cfreq, intf_hbw * 2, intf_lfreq, intf_hfreq); + + if (!(((sap_lfreq > intf_lfreq && sap_lfreq < intf_hfreq) || + (sap_hfreq > intf_lfreq && sap_hfreq < intf_hfreq)) || + ((intf_lfreq > sap_lfreq && intf_lfreq < sap_hfreq) || + (intf_hfreq > sap_lfreq && intf_hfreq < sap_hfreq)))) + intf_ch = 0; + } else if (intf_ch && sap_ch != intf_ch && + ((cc_switch_mode == QDF_MCC_TO_SCC_SWITCH_FORCE) || + (cc_switch_mode == + QDF_MCC_TO_SCC_SWITCH_FORCE_WITHOUT_DISCONNECTION) || + (cc_switch_mode == + QDF_MCC_TO_SCC_SWITCH_WITH_FAVORITE_CHANNEL))) { + if (!((intf_ch < 14 && sap_ch < 14) || + (intf_ch > 14 && sap_ch > 14))) + intf_ch = 0; + else if (cc_switch_mode == + QDF_MCC_TO_SCC_SWITCH_WITH_FAVORITE_CHANNEL) { + status = + cds_get_sap_mandatory_channel((uint32_t *)&intf_ch); + if (QDF_IS_STATUS_ERROR(status)) { + sms_log(mac_ctx, LOGE, + FL("no mandatory channel")); + intf_ch = sap_ch; + } + } + } else if ((intf_ch == sap_ch) && (cc_switch_mode == + QDF_MCC_TO_SCC_SWITCH_WITH_FAVORITE_CHANNEL)) { + if (cds_chan_to_band(intf_ch) == CDS_BAND_2GHZ) { + status = + cds_get_sap_mandatory_channel( + (uint32_t *)&intf_ch); + if (QDF_IS_STATUS_ERROR(status)) { + sms_log(mac_ctx, LOGE, + FL("no mandatory channel")); + intf_ch = sap_ch; + } + } + } + + if (intf_ch == sap_ch) + intf_ch = 0; + + sms_log(mac_ctx, LOGE, FL("##Concurrent Channels %s Interfering"), + intf_ch == 0 ? "Not" : "Are"); + return intf_ch; +} +#endif + +bool csr_is_all_session_disconnected(tpAniSirGlobal pMac) +{ + uint32_t i; + bool fRc = true; + + for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) { + if (CSR_IS_SESSION_VALID(pMac, i) + && !csr_is_conn_state_disconnected(pMac, i)) { + fRc = false; + break; + } + } + + return fRc; +} + +/** + * csr_is_sta_session_connected() - to find if concurrent sta is active + * @mac_ctx: pointer to mac context + * + * This function will iterate through each session and check if sta + * session exist and active + * + * Return: true or false + */ +bool csr_is_sta_session_connected(tpAniSirGlobal mac_ctx) +{ + uint32_t i; + tCsrRoamSession *pSession = NULL; + + for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) { + if (CSR_IS_SESSION_VALID(mac_ctx, i) && + !csr_is_conn_state_disconnected(mac_ctx, i)) { + pSession = CSR_GET_SESSION(mac_ctx, i); + + if ((NULL != pSession->pCurRoamProfile) && + (QDF_STA_MODE == + pSession->pCurRoamProfile->csrPersona)) + return true; + } + } + + return false; +} + +/** + * csr_is_p2p_session_connected() - to find if any p2p session is active + * @mac_ctx: pointer to mac context + * + * This function will iterate through each session and check if any p2p + * session exist and active + * + * Return: true or false + */ +bool csr_is_p2p_session_connected(tpAniSirGlobal pMac) +{ + uint32_t i; + tCsrRoamSession *pSession = NULL; + enum tQDF_ADAPTER_MODE persona; + + for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) { + if (!CSR_IS_SESSION_VALID(pMac, i)) + continue; + + if (csr_is_conn_state_disconnected(pMac, i)) + continue; + + pSession = CSR_GET_SESSION(pMac, i); + if (pSession->pCurRoamProfile == NULL) + continue; + + persona = pSession->pCurRoamProfile->csrPersona; + if (QDF_P2P_CLIENT_MODE == persona || + QDF_P2P_GO_MODE == persona) + return true; + } + + return false; +} + +bool csr_is_any_session_connected(tpAniSirGlobal pMac) +{ + uint32_t i, count; + bool fRc = false; + + count = 0; + for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) { + if (CSR_IS_SESSION_VALID(pMac, i) + && !csr_is_conn_state_disconnected(pMac, i)) + count++; + } + + if (count > 0) + fRc = true; + return fRc; +} + +bool csr_is_infra_connected(tpAniSirGlobal pMac) +{ + uint32_t i; + bool fRc = false; + + for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) { + if (CSR_IS_SESSION_VALID(pMac, i) + && csr_is_conn_state_connected_infra(pMac, i)) { + fRc = true; + break; + } + } + + return fRc; +} + +bool csr_is_concurrent_infra_connected(tpAniSirGlobal pMac) +{ + uint32_t i, noOfConnectedInfra = 0; + + bool fRc = false; + + for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) { + if (CSR_IS_SESSION_VALID(pMac, i) + && csr_is_conn_state_connected_infra(pMac, i)) { + ++noOfConnectedInfra; + } + } + + /* More than one Infra Sta Connected */ + if (noOfConnectedInfra > 1) + fRc = true; + return fRc; +} + +bool csr_is_ibss_started(tpAniSirGlobal pMac) +{ + uint32_t i; + bool fRc = false; + + for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) { + if (CSR_IS_SESSION_VALID(pMac, i) + && csr_is_conn_state_ibss(pMac, i)) { + fRc = true; + break; + } + } + + return fRc; +} + +bool csr_is_concurrent_session_running(tpAniSirGlobal pMac) +{ + uint32_t sessionId, noOfCocurrentSession = 0; + eCsrConnectState connectState; + + bool fRc = false; + + for (sessionId = 0; sessionId < CSR_ROAM_SESSION_MAX; sessionId++) { + if (CSR_IS_SESSION_VALID(pMac, sessionId)) { + connectState = + pMac->roam.roamSession[sessionId].connectState; + if ((eCSR_ASSOC_STATE_TYPE_INFRA_ASSOCIATED == + connectState) + || (eCSR_ASSOC_STATE_TYPE_INFRA_CONNECTED == + connectState) + || (eCSR_ASSOC_STATE_TYPE_INFRA_DISCONNECTED == + connectState)) { + ++noOfCocurrentSession; + } + } + } + + /* More than one session is Up and Running */ + if (noOfCocurrentSession > 1) + fRc = true; + return fRc; +} + +bool csr_is_infra_ap_started(tpAniSirGlobal pMac) +{ + uint32_t sessionId; + bool fRc = false; + + for (sessionId = 0; sessionId < CSR_ROAM_SESSION_MAX; sessionId++) { + if (CSR_IS_SESSION_VALID(pMac, sessionId) + && (csr_is_conn_state_connected_infra_ap(pMac, sessionId))) { + fRc = true; + break; + } + } + + return fRc; + +} + +bool csr_is_conn_state_disconnected(tpAniSirGlobal pMac, uint32_t sessionId) +{ + return eCSR_ASSOC_STATE_TYPE_NOT_CONNECTED == + pMac->roam.roamSession[sessionId].connectState; +} + +/** + * csr_is_valid_mc_concurrent_session() - To check concurren session is valid + * @mac_ctx: pointer to mac context + * @session_id: session id + * @bss_descr: bss description + * + * This function validates the concurrent session + * + * Return: true or false + */ +bool csr_is_valid_mc_concurrent_session(tpAniSirGlobal mac_ctx, + uint32_t session_id, + tSirBssDescription *bss_descr) +{ + tCsrRoamSession *pSession = NULL; + + /* Check for MCC support */ + if (!mac_ctx->roam.configParam.fenableMCCMode) + return false; + if (!CSR_IS_SESSION_VALID(mac_ctx, session_id)) + return false; + /* Validate BeaconInterval */ + pSession = CSR_GET_SESSION(mac_ctx, session_id); + if (NULL == pSession->pCurRoamProfile) + return false; + if (QDF_STATUS_SUCCESS == csr_validate_mcc_beacon_interval(mac_ctx, + bss_descr->channelId, + &bss_descr->beaconInterval, session_id, + pSession->pCurRoamProfile->csrPersona)) + return true; + return false; +} + +static tSirMacCapabilityInfo csr_get_bss_capabilities(tSirBssDescription * + pSirBssDesc) +{ + tSirMacCapabilityInfo dot11Caps; + + /* tSirMacCapabilityInfo is 16-bit */ + qdf_get_u16((uint8_t *) &pSirBssDesc->capabilityInfo, + (uint16_t *) &dot11Caps); + + return dot11Caps; +} + +bool csr_is_infra_bss_desc(tSirBssDescription *pSirBssDesc) +{ + tSirMacCapabilityInfo dot11Caps = csr_get_bss_capabilities(pSirBssDesc); + + return (bool) dot11Caps.ess; +} + +bool csr_is_ibss_bss_desc(tSirBssDescription *pSirBssDesc) +{ + tSirMacCapabilityInfo dot11Caps = csr_get_bss_capabilities(pSirBssDesc); + + return (bool) dot11Caps.ibss; +} + +static bool csr_is_qos_bss_desc(tSirBssDescription *pSirBssDesc) +{ + tSirMacCapabilityInfo dot11Caps = csr_get_bss_capabilities(pSirBssDesc); + + return (bool) dot11Caps.qos; +} + +bool csr_is_privacy(tSirBssDescription *pSirBssDesc) +{ + tSirMacCapabilityInfo dot11Caps = csr_get_bss_capabilities(pSirBssDesc); + + return (bool) dot11Caps.privacy; +} + +bool csr_is11d_supported(tpAniSirGlobal pMac) +{ + return pMac->roam.configParam.Is11dSupportEnabled; +} + +bool csr_is11h_supported(tpAniSirGlobal pMac) +{ + return pMac->roam.configParam.Is11hSupportEnabled; +} + +bool csr_is11e_supported(tpAniSirGlobal pMac) +{ + return pMac->roam.configParam.Is11eSupportEnabled; +} + +bool csr_is_mcc_supported(tpAniSirGlobal pMac) +{ + return pMac->roam.configParam.fenableMCCMode; + +} + +bool csr_is_wmm_supported(tpAniSirGlobal pMac) +{ + if (eCsrRoamWmmNoQos == pMac->roam.configParam.WMMSupportMode) + return false; + else + return true; +} + +/* pIes is the IEs for pSirBssDesc2 */ +bool csr_is_ssid_equal(tHalHandle hHal, tSirBssDescription *pSirBssDesc1, + tSirBssDescription *pSirBssDesc2, tDot11fBeaconIEs *pIes2) +{ + bool fEqual = false; + tSirMacSSid Ssid1, Ssid2; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + tDot11fBeaconIEs *pIes1 = NULL; + tDot11fBeaconIEs *pIesLocal = pIes2; + + do { + if ((NULL == pSirBssDesc1) || (NULL == pSirBssDesc2)) + break; + if (!pIesLocal + && + !QDF_IS_STATUS_SUCCESS(csr_get_parsed_bss_description_ies + (pMac, pSirBssDesc2, + &pIesLocal))) { + sms_log(pMac, LOGE, FL(" fail to parse IEs")); + break; + } + if (!QDF_IS_STATUS_SUCCESS + (csr_get_parsed_bss_description_ies(pMac, + pSirBssDesc1, &pIes1))) { + break; + } + if ((!pIes1->SSID.present) || (!pIesLocal->SSID.present)) + break; + if (pIes1->SSID.num_ssid != pIesLocal->SSID.num_ssid) + break; + qdf_mem_copy(Ssid1.ssId, pIes1->SSID.ssid, + pIes1->SSID.num_ssid); + qdf_mem_copy(Ssid2.ssId, pIesLocal->SSID.ssid, + pIesLocal->SSID.num_ssid); + + fEqual = (!qdf_mem_cmp(Ssid1.ssId, Ssid2.ssId, + pIesLocal->SSID.num_ssid)); + + } while (0); + if (pIes1) + qdf_mem_free(pIes1); + if (pIesLocal && !pIes2) + qdf_mem_free(pIesLocal); + + return fEqual; +} + +/* pIes can be passed in as NULL if the caller doesn't have one prepared */ +static bool csr_is_bss_description_wme(tHalHandle hHal, + tSirBssDescription *pSirBssDesc, + tDot11fBeaconIEs *pIes) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + /* Assume that WME is found... */ + bool fWme = true; + tDot11fBeaconIEs *pIesTemp = pIes; + + do { + if (pIesTemp == NULL) { + if (!QDF_IS_STATUS_SUCCESS + (csr_get_parsed_bss_description_ies + (pMac, pSirBssDesc, &pIesTemp))) { + fWme = false; + break; + } + } + /* if the Wme Info IE is found, then WME is supported... */ + if (CSR_IS_QOS_BSS(pIesTemp)) + break; + /* if none of these are found, then WME is NOT supported... */ + fWme = false; + } while (0); + if (!csr_is_wmm_supported(pMac) && fWme) { + if (!pIesTemp->HTCaps.present) { + fWme = false; + } + } + if ((pIes == NULL) && (NULL != pIesTemp)) { + /* we allocate memory here so free it before returning */ + qdf_mem_free(pIesTemp); + } + + return fWme; +} + +eCsrMediaAccessType csr_get_qo_s_from_bss_desc(tHalHandle hHal, + tSirBssDescription *pSirBssDesc, + tDot11fBeaconIEs *pIes) +{ + eCsrMediaAccessType qosType = eCSR_MEDIUM_ACCESS_DCF; + + if (NULL == pIes) { + QDF_ASSERT(pIes != NULL); + return qosType; + } + + do { + /* if we find WMM in the Bss Description, then we let this */ + /* override and use WMM. */ + if (csr_is_bss_description_wme(hHal, pSirBssDesc, pIes)) { + qosType = eCSR_MEDIUM_ACCESS_WMM_eDCF_DSCP; + } else { + /* if the QoS bit is on, then the AP is advertising 11E QoS... */ + if (csr_is_qos_bss_desc(pSirBssDesc)) { + qosType = eCSR_MEDIUM_ACCESS_11e_eDCF; + } else { + qosType = eCSR_MEDIUM_ACCESS_DCF; + } + /* scale back based on the types turned on for the adapter... */ + if (eCSR_MEDIUM_ACCESS_11e_eDCF == qosType + && !csr_is11e_supported(hHal)) { + qosType = eCSR_MEDIUM_ACCESS_DCF; + } + } + + } while (0); + + return qosType; +} + +/* Caller allocates memory for pIEStruct */ +QDF_STATUS csr_parse_bss_description_ies(tHalHandle hHal, + tSirBssDescription *pBssDesc, + tDot11fBeaconIEs *pIEStruct) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + int ieLen = + (int)(pBssDesc->length + sizeof(pBssDesc->length) - + GET_FIELD_OFFSET(tSirBssDescription, ieFields)); + + if (ieLen > 0 && pIEStruct) { + if (!DOT11F_FAILED + (dot11f_unpack_beacon_i_es + (pMac, (uint8_t *) pBssDesc->ieFields, ieLen, + pIEStruct))) { + status = QDF_STATUS_SUCCESS; + } + } + + return status; +} + +/* This function will allocate memory for the parsed IEs to the caller. Caller must free the memory */ +/* after it is done with the data only if this function succeeds */ +QDF_STATUS csr_get_parsed_bss_description_ies(tHalHandle hHal, + tSirBssDescription *pBssDesc, + tDot11fBeaconIEs **ppIEStruct) +{ + QDF_STATUS status = QDF_STATUS_E_INVAL; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + if (pBssDesc && ppIEStruct) { + *ppIEStruct = qdf_mem_malloc(sizeof(tDot11fBeaconIEs)); + if ((*ppIEStruct) != NULL) { + status = + csr_parse_bss_description_ies(hHal, pBssDesc, + *ppIEStruct); + if (!QDF_IS_STATUS_SUCCESS(status)) { + qdf_mem_free(*ppIEStruct); + *ppIEStruct = NULL; + } + } else { + sms_log(pMac, LOGE, FL(" failed to allocate memory")); + QDF_ASSERT(0); + return QDF_STATUS_E_NOMEM; + } + } + + return status; +} + +bool csr_is_nullssid(uint8_t *pBssSsid, uint8_t len) +{ + bool fNullSsid = false; + + uint32_t SsidLength; + uint8_t *pSsidStr; + + do { + if (0 == len) { + fNullSsid = true; + break; + } + /* Consider 0 or space for hidden SSID */ + if (0 == pBssSsid[0]) { + fNullSsid = true; + break; + } + + SsidLength = len; + pSsidStr = pBssSsid; + + while (SsidLength) { + if (*pSsidStr) + break; + + pSsidStr++; + SsidLength--; + } + + if (0 == SsidLength) { + fNullSsid = true; + break; + } + } while (0); + + return fNullSsid; +} + +uint32_t csr_get_frag_thresh(tHalHandle hHal) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + return pMac->roam.configParam.FragmentationThreshold; +} + +uint32_t csr_get_rts_thresh(tHalHandle hHal) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + return pMac->roam.configParam.RTSThreshold; +} + +static eCsrPhyMode csr_translate_to_phy_mode_from_bss_desc( + tSirBssDescription *pSirBssDesc) +{ + eCsrPhyMode phyMode; + + switch (pSirBssDesc->nwType) { + case eSIR_11A_NW_TYPE: + phyMode = eCSR_DOT11_MODE_11a; + break; + + case eSIR_11B_NW_TYPE: + phyMode = eCSR_DOT11_MODE_11b; + break; + + case eSIR_11G_NW_TYPE: + phyMode = eCSR_DOT11_MODE_11g; + break; + + case eSIR_11N_NW_TYPE: + phyMode = eCSR_DOT11_MODE_11n; + break; + case eSIR_11AC_NW_TYPE: + default: + phyMode = eCSR_DOT11_MODE_11ac; + break; + } + return phyMode; +} + +uint32_t csr_translate_to_wni_cfg_dot11_mode(tpAniSirGlobal pMac, + eCsrCfgDot11Mode csrDot11Mode) +{ + uint32_t ret; + + switch (csrDot11Mode) { + case eCSR_CFG_DOT11_MODE_AUTO: + sms_log(pMac, LOGW, + FL(" Warning: sees eCSR_CFG_DOT11_MODE_AUTO ")); + if (IS_FEATURE_SUPPORTED_BY_FW(DOT11AC)) + ret = WNI_CFG_DOT11_MODE_11AC; + else + ret = WNI_CFG_DOT11_MODE_11N; + break; + case eCSR_CFG_DOT11_MODE_11A: + ret = WNI_CFG_DOT11_MODE_11A; + break; + case eCSR_CFG_DOT11_MODE_11B: + ret = WNI_CFG_DOT11_MODE_11B; + break; + case eCSR_CFG_DOT11_MODE_11G: + ret = WNI_CFG_DOT11_MODE_11G; + break; + case eCSR_CFG_DOT11_MODE_11N: + ret = WNI_CFG_DOT11_MODE_11N; + break; + case eCSR_CFG_DOT11_MODE_11G_ONLY: + ret = WNI_CFG_DOT11_MODE_11G_ONLY; + break; + case eCSR_CFG_DOT11_MODE_11N_ONLY: + ret = WNI_CFG_DOT11_MODE_11N_ONLY; + break; + case eCSR_CFG_DOT11_MODE_11AC_ONLY: + if (IS_FEATURE_SUPPORTED_BY_FW(DOT11AC)) + ret = WNI_CFG_DOT11_MODE_11AC_ONLY; + else + ret = WNI_CFG_DOT11_MODE_11N; + break; + case eCSR_CFG_DOT11_MODE_11AC: + if (IS_FEATURE_SUPPORTED_BY_FW(DOT11AC)) + ret = WNI_CFG_DOT11_MODE_11AC; + else + ret = WNI_CFG_DOT11_MODE_11N; + break; + default: + sms_log(pMac, LOGW, FL("doesn't expect %d as csrDo11Mode"), + csrDot11Mode); + if (eCSR_BAND_24 == pMac->roam.configParam.eBand) { + ret = WNI_CFG_DOT11_MODE_11G; + } else { + ret = WNI_CFG_DOT11_MODE_11A; + } + break; + } + + return ret; +} + +/** + * csr_get_phy_mode_from_bss() - Get Phy Mode + * @pMac: Global MAC context + * @pBSSDescription: BSS Descriptor + * @pPhyMode: Physical Mode + * @pIes: Pointer to the IE fields + * + * This function should only return the super set of supported modes + * 11n implies 11b/g/a/n. + * + * Return: success + **/ +QDF_STATUS csr_get_phy_mode_from_bss(tpAniSirGlobal pMac, + tSirBssDescription *pBSSDescription, + eCsrPhyMode *pPhyMode, tDot11fBeaconIEs *pIes) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + eCsrPhyMode phyMode = + csr_translate_to_phy_mode_from_bss_desc(pBSSDescription); + + if (pIes) { + if (pIes->HTCaps.present) { + phyMode = eCSR_DOT11_MODE_11n; + if (IS_BSS_VHT_CAPABLE(pIes->VHTCaps) || + IS_BSS_VHT_CAPABLE(pIes->vendor_vht_ie.VHTCaps)) + phyMode = eCSR_DOT11_MODE_11ac; + } + *pPhyMode = phyMode; + } + + return status; +} + +/** + * csr_get_phy_mode_in_use() - to get phymode + * @phyModeIn: physical mode + * @bssPhyMode: physical mode in bss + * @f5GhzBand: 5Ghz band + * @pCfgDot11ModeToUse: dot11 mode in use + * + * This function returns the correct eCSR_CFG_DOT11_MODE is the two phyModes + * matches. bssPhyMode is the mode derived from the BSS description + * f5GhzBand is derived from the channel id of BSS description + * + * Return: true or false + */ +static bool csr_get_phy_mode_in_use(eCsrPhyMode phyModeIn, + eCsrPhyMode bssPhyMode, + bool f5GhzBand, + eCsrCfgDot11Mode *pCfgDot11ModeToUse) +{ + bool fMatch = false; + eCsrCfgDot11Mode cfgDot11Mode; + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11N; + + switch (phyModeIn) { + /* 11a or 11b or 11g */ + case eCSR_DOT11_MODE_abg: + fMatch = true; + if (f5GhzBand) + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11A; + else if (eCSR_DOT11_MODE_11b == bssPhyMode) + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11B; + else + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11G; + break; + + case eCSR_DOT11_MODE_11a: + if (f5GhzBand) { + fMatch = true; + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11A; + } + break; + + case eCSR_DOT11_MODE_11g: + if (!f5GhzBand) { + fMatch = true; + if (eCSR_DOT11_MODE_11b == bssPhyMode) + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11B; + else + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11G; + } + break; + + case eCSR_DOT11_MODE_11g_ONLY: + if (eCSR_DOT11_MODE_11g == bssPhyMode) { + fMatch = true; + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11G; + } + break; + + case eCSR_DOT11_MODE_11b: + if (!f5GhzBand) { + fMatch = true; + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11B; + } + break; + + case eCSR_DOT11_MODE_11b_ONLY: + if (eCSR_DOT11_MODE_11b == bssPhyMode) { + fMatch = true; + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11B; + } + break; + + case eCSR_DOT11_MODE_11n: + fMatch = true; + switch (bssPhyMode) { + case eCSR_DOT11_MODE_11g: + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11G; + break; + case eCSR_DOT11_MODE_11b: + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11B; + break; + case eCSR_DOT11_MODE_11a: + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11A; + break; + case eCSR_DOT11_MODE_11n: + case eCSR_DOT11_MODE_11ac: + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11N; + break; + + default: + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11AC; + break; + } + break; + + case eCSR_DOT11_MODE_11n_ONLY: + if ((eCSR_DOT11_MODE_11n == bssPhyMode)) { + fMatch = true; + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11N; + + } + + break; + case eCSR_DOT11_MODE_11ac: + fMatch = true; + switch (bssPhyMode) { + case eCSR_DOT11_MODE_11g: + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11G; + break; + case eCSR_DOT11_MODE_11b: + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11B; + break; + case eCSR_DOT11_MODE_11a: + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11A; + break; + case eCSR_DOT11_MODE_11n: + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11N; + break; + case eCSR_DOT11_MODE_11ac: + default: + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11AC; + break; + } + break; + + case eCSR_DOT11_MODE_11ac_ONLY: + if ((eCSR_DOT11_MODE_11ac == bssPhyMode)) { + fMatch = true; + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11AC; + } + break; + + default: + fMatch = true; + switch (bssPhyMode) { + case eCSR_DOT11_MODE_11g: + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11G; + break; + case eCSR_DOT11_MODE_11b: + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11B; + break; + case eCSR_DOT11_MODE_11a: + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11A; + break; + case eCSR_DOT11_MODE_11n: + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11N; + break; + case eCSR_DOT11_MODE_11ac: + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11AC; + break; + default: + cfgDot11Mode = eCSR_CFG_DOT11_MODE_AUTO; + break; + } + break; + } + + if (fMatch && pCfgDot11ModeToUse) { + if (cfgDot11Mode == eCSR_CFG_DOT11_MODE_11AC + && (!IS_FEATURE_SUPPORTED_BY_FW(DOT11AC))) + *pCfgDot11ModeToUse = eCSR_CFG_DOT11_MODE_11N; + else + *pCfgDot11ModeToUse = cfgDot11Mode; + } + return fMatch; +} + +/** + * csr_is_phy_mode_match() - to find if phy mode matches + * @pMac: pointer to mac context + * @phyMode: physical mode + * @pSirBssDesc: bss description + * @pProfile: pointer to roam profile + * @pReturnCfgDot11Mode: dot1 mode to return + * @pIes: pointer to IEs + * + * This function decides whether the one of the bit of phyMode is matching the + * mode in the BSS and allowed by the user setting + * + * Return: true or false based on mode that fits the criteria + */ +bool csr_is_phy_mode_match(tpAniSirGlobal pMac, uint32_t phyMode, + tSirBssDescription *pSirBssDesc, + tCsrRoamProfile *pProfile, + eCsrCfgDot11Mode *pReturnCfgDot11Mode, + tDot11fBeaconIEs *pIes) +{ + bool fMatch = false; + eCsrPhyMode phyModeInBssDesc = eCSR_DOT11_MODE_AUTO, phyMode2; + eCsrCfgDot11Mode cfgDot11ModeToUse = eCSR_CFG_DOT11_MODE_AUTO; + uint32_t bitMask, loopCount; + + if (!QDF_IS_STATUS_SUCCESS(csr_get_phy_mode_from_bss(pMac, pSirBssDesc, + &phyModeInBssDesc, pIes))) + return fMatch; + + if ((0 == phyMode) || (eCSR_DOT11_MODE_AUTO & phyMode)) { + if (eCSR_CFG_DOT11_MODE_ABG == + pMac->roam.configParam.uCfgDot11Mode) + phyMode = eCSR_DOT11_MODE_abg; + else if (eCSR_CFG_DOT11_MODE_AUTO == + pMac->roam.configParam.uCfgDot11Mode) + phyMode = eCSR_DOT11_MODE_11ac; + else + /* user's pick */ + phyMode = pMac->roam.configParam.phyMode; + } + + if ((0 == phyMode) || (eCSR_DOT11_MODE_AUTO & phyMode)) { + if (0 != phyMode) { + if (eCSR_DOT11_MODE_AUTO & phyMode) { + phyMode2 = + eCSR_DOT11_MODE_AUTO & phyMode; + } + } else { + phyMode2 = phyMode; + } + fMatch = csr_get_phy_mode_in_use(phyMode2, phyModeInBssDesc, + CDS_IS_CHANNEL_5GHZ(pSirBssDesc->channelId), + &cfgDot11ModeToUse); + } else { + bitMask = 1; + loopCount = 0; + while (loopCount < eCSR_NUM_PHY_MODE) { + phyMode2 = (phyMode & (bitMask << loopCount++)); + if (0 != phyMode2 && csr_get_phy_mode_in_use(phyMode2, + phyModeInBssDesc, + CDS_IS_CHANNEL_5GHZ + (pSirBssDesc->channelId), + &cfgDot11ModeToUse)) { + fMatch = true; + break; + } + } + } + if (fMatch && pReturnCfgDot11Mode) { + if (pProfile) { + /* + * IEEE 11n spec (8.4.3): HT STA shall + * eliminate TKIP as a choice for the pairwise + * cipher suite if CCMP is advertised by the AP + * or if the AP included an HT capabilities + * element in its Beacons and Probe Response. + */ + if ((!CSR_IS_11n_ALLOWED( + pProfile->negotiatedUCEncryptionType)) + && ((eCSR_CFG_DOT11_MODE_11N == + cfgDot11ModeToUse) || + (eCSR_CFG_DOT11_MODE_11AC == + cfgDot11ModeToUse))) { + /* We cannot do 11n here */ + if (!CDS_IS_CHANNEL_5GHZ + (pSirBssDesc->channelId)) { + cfgDot11ModeToUse = + eCSR_CFG_DOT11_MODE_11G; + } else { + cfgDot11ModeToUse = + eCSR_CFG_DOT11_MODE_11A; + } + } + } + *pReturnCfgDot11Mode = cfgDot11ModeToUse; + } + + return fMatch; +} + +eCsrCfgDot11Mode csr_find_best_phy_mode(tpAniSirGlobal pMac, uint32_t phyMode) +{ + eCsrCfgDot11Mode cfgDot11ModeToUse; + eCsrBand eBand = pMac->roam.configParam.eBand; + + if ((0 == phyMode) || + (eCSR_DOT11_MODE_11ac & phyMode) || + (eCSR_DOT11_MODE_AUTO & phyMode)) { + if (IS_FEATURE_SUPPORTED_BY_FW(DOT11AC)) { + cfgDot11ModeToUse = eCSR_CFG_DOT11_MODE_11AC; + } else { + /* Default to 11N mode if user has configured 11ac mode + * and FW doesn't supports 11ac mode . + */ + cfgDot11ModeToUse = eCSR_CFG_DOT11_MODE_11N; + } + } else { + if ((eCSR_DOT11_MODE_11n | eCSR_DOT11_MODE_11n_ONLY) & phyMode) { + cfgDot11ModeToUse = eCSR_CFG_DOT11_MODE_11N; + } else if (eCSR_DOT11_MODE_abg & phyMode) { + if (eCSR_BAND_24 != eBand) { + cfgDot11ModeToUse = eCSR_CFG_DOT11_MODE_11A; + } else { + cfgDot11ModeToUse = eCSR_CFG_DOT11_MODE_11G; + } + } else if (eCSR_DOT11_MODE_11a & phyMode) { + cfgDot11ModeToUse = eCSR_CFG_DOT11_MODE_11A; + } else if ((eCSR_DOT11_MODE_11g | eCSR_DOT11_MODE_11g_ONLY) & + phyMode) { + cfgDot11ModeToUse = eCSR_CFG_DOT11_MODE_11G; + } else { + cfgDot11ModeToUse = eCSR_CFG_DOT11_MODE_11B; + } + } + + return cfgDot11ModeToUse; +} + +uint32_t csr_get11h_power_constraint(tHalHandle hHal, + tDot11fIEPowerConstraints *pPowerConstraint) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + uint32_t localPowerConstraint = 0; + + /* check if .11h support is enabled, if not, the power constraint is 0. */ + if (pMac->roam.configParam.Is11hSupportEnabled + && pPowerConstraint->present) { + localPowerConstraint = pPowerConstraint->localPowerConstraints; + } + + return localPowerConstraint; +} + +bool csr_is_profile_wpa(tCsrRoamProfile *pProfile) +{ + bool fWpaProfile = false; + + switch (pProfile->negotiatedAuthType) { + case eCSR_AUTH_TYPE_WPA: + case eCSR_AUTH_TYPE_WPA_PSK: + case eCSR_AUTH_TYPE_WPA_NONE: +#ifdef FEATURE_WLAN_ESE + case eCSR_AUTH_TYPE_CCKM_WPA: +#endif + fWpaProfile = true; + break; + + default: + fWpaProfile = false; + break; + } + + if (fWpaProfile) { + switch (pProfile->negotiatedUCEncryptionType) { + case eCSR_ENCRYPT_TYPE_WEP40: + case eCSR_ENCRYPT_TYPE_WEP104: + case eCSR_ENCRYPT_TYPE_TKIP: + case eCSR_ENCRYPT_TYPE_AES: + fWpaProfile = true; + break; + + default: + fWpaProfile = false; + break; + } + } + return fWpaProfile; +} + +bool csr_is_profile_rsn(tCsrRoamProfile *pProfile) +{ + bool fRSNProfile = false; + + switch (pProfile->negotiatedAuthType) { + case eCSR_AUTH_TYPE_RSN: + case eCSR_AUTH_TYPE_RSN_PSK: + case eCSR_AUTH_TYPE_FT_RSN: + case eCSR_AUTH_TYPE_FT_RSN_PSK: +#ifdef FEATURE_WLAN_ESE + case eCSR_AUTH_TYPE_CCKM_RSN: +#endif +#ifdef WLAN_FEATURE_11W + case eCSR_AUTH_TYPE_RSN_PSK_SHA256: + case eCSR_AUTH_TYPE_RSN_8021X_SHA256: +#endif + fRSNProfile = true; + break; + + default: + fRSNProfile = false; + break; + } + + if (fRSNProfile) { + switch (pProfile->negotiatedUCEncryptionType) { + /* !!REVIEW - For WPA2, use of RSN IE mandates */ + /* use of AES as encryption. Here, we qualify */ + /* even if encryption type is WEP or TKIP */ + case eCSR_ENCRYPT_TYPE_WEP40: + case eCSR_ENCRYPT_TYPE_WEP104: + case eCSR_ENCRYPT_TYPE_TKIP: + case eCSR_ENCRYPT_TYPE_AES: + fRSNProfile = true; + break; + + default: + fRSNProfile = false; + break; + } + } + return fRSNProfile; +} + +/** + * csr_update_mcc_p2p_beacon_interval() - update p2p beacon interval + * @mac_ctx: pointer to mac context + * + * This function is to update the mcc p2p beacon interval + * + * Return: QDF_STATUS + */ +static QDF_STATUS csr_update_mcc_p2p_beacon_interval(tpAniSirGlobal mac_ctx) +{ + uint32_t session_id = 0; + tCsrRoamSession *roam_session; + + /* If MCC is not supported just break and return SUCCESS */ + if (!mac_ctx->roam.configParam.fenableMCCMode) + return QDF_STATUS_E_FAILURE; + + for (session_id = 0; session_id < CSR_ROAM_SESSION_MAX; session_id++) { + /* + * If GO in MCC support different beacon interval, + * change the BI of the P2P-GO + */ + roam_session = &mac_ctx->roam.roamSession[session_id]; + if (roam_session->bssParams.bssPersona != QDF_P2P_GO_MODE) + continue; + /* + * Handle different BI scneario based on the + * configuration set.If Config is set to 0x02 then + * Disconnect all the P2P clients associated. If config + * is set to 0x04 then update the BI without + * disconnecting all the clients + */ + if ((mac_ctx->roam.configParam.fAllowMCCGODiffBI == 0x04) + && (roam_session->bssParams. + updatebeaconInterval)) { + return csr_send_chng_mcc_beacon_interval(mac_ctx, + session_id); + } else if (roam_session->bssParams.updatebeaconInterval) { + /* + * If the configuration of fAllowMCCGODiffBI is set to + * other than 0x04 + */ + return csr_roam_call_callback(mac_ctx, + session_id, + NULL, 0, + eCSR_ROAM_DISCONNECT_ALL_P2P_CLIENTS, + eCSR_ROAM_RESULT_NONE); + } + } + return QDF_STATUS_E_FAILURE; +} + +static uint16_t csr_calculate_mcc_beacon_interval(tpAniSirGlobal pMac, + uint16_t sta_bi, + uint16_t go_gbi) +{ + uint8_t num_beacons = 0; + uint8_t is_multiple = 0; + uint16_t go_cbi = 0; + uint16_t go_fbi = 0; + uint16_t sta_cbi = 0; + + /* If GO's given beacon Interval is less than 100 */ + if (go_gbi < 100) + go_cbi = 100; + /* if GO's given beacon Interval is greater than or equal to 100 */ + else + go_cbi = 100 + (go_gbi % 100); + + if (sta_bi == 0) { + /* There is possibility to receive zero as value. + Which will cause divide by zero. Hence initialise with 100 + */ + sta_bi = 100; + sms_log(pMac, LOGW, + FL("sta_bi 2nd parameter is zero, initialize to %d"), + sta_bi); + } + /* check, if either one is multiple of another */ + if (sta_bi > go_cbi) { + is_multiple = !(sta_bi % go_cbi); + } else { + is_multiple = !(go_cbi % sta_bi); + } + /* if it is multiple, then accept GO's beacon interval range [100,199] as it is */ + if (is_multiple) { + return go_cbi; + } + /* else , if it is not multiple, then then check for number of beacons to be */ + /* inserted based on sta BI */ + num_beacons = sta_bi / 100; + if (num_beacons) { + /* GO's final beacon interval will be aligned to sta beacon interval, but */ + /* in the range of [100, 199]. */ + sta_cbi = sta_bi / num_beacons; + go_fbi = sta_cbi; + } else { + /* if STA beacon interval is less than 100, use GO's change bacon interval */ + /* instead of updating to STA's beacon interval. */ + go_fbi = go_cbi; + } + return go_fbi; +} + +/** + * csr_validate_p2pcli_bcn_intrvl() - to validate p2pcli beacon interval + * @mac_ctx: pointer to mac context + * @chnl_id: channel id variable + * @bcn_interval: pointer to given beacon interval + * @session_id: given session id + * @status: fill the status in terms of QDF_STATUS to inform caller + * + * This API can provide the validation the beacon interval and re-calculate + * in case concurrency + * + * Return: bool + */ +static bool csr_validate_p2pcli_bcn_intrvl(tpAniSirGlobal mac_ctx, + uint8_t chnl_id, uint16_t *bcn_interval, uint32_t session_id, + QDF_STATUS *status) +{ + tCsrRoamSession *roamsession; + + roamsession = &mac_ctx->roam.roamSession[session_id]; + if (roamsession->pCurRoamProfile && + (roamsession->pCurRoamProfile->csrPersona == + QDF_STA_MODE)) { + /* check for P2P client mode */ + sms_log(mac_ctx, LOG1, + FL(" Ignore Beacon Interval Validation...")); + } else if (roamsession->bssParams.bssPersona == QDF_P2P_GO_MODE) { + /* Check for P2P go scenario */ + if ((roamsession->bssParams.operationChn != chnl_id) + && (roamsession->bssParams.beaconInterval != + *bcn_interval)) { + sms_log(mac_ctx, LOGE, + FL("BcnIntrvl is diff can't connect to P2P_GO network ...")); + *status = QDF_STATUS_E_FAILURE; + return true; + } + } + return false; +} + +/** + * csr_validate_p2pgo_bcn_intrvl() - to validate p2pgo beacon interval + * @mac_ctx: pointer to mac context + * @chnl_id: channel id variable + * @bcn_interval: pointer to given beacon interval + * @session_id: given session id + * @status: fill the status in terms of QDF_STATUS to inform caller + * + * This API can provide the validation the beacon interval and re-calculate + * in case concurrency + * + * Return: bool + */ +static bool csr_validate_p2pgo_bcn_intrvl(tpAniSirGlobal mac_ctx, + uint8_t chnl_id, uint16_t *bcn_interval, + uint32_t session_id, QDF_STATUS *status) +{ + tCsrRoamSession *roamsession; + tCsrConfig *cfg_param; + tCsrRoamConnectedProfile *conn_profile; + uint16_t new_bcn_interval; + + roamsession = &mac_ctx->roam.roamSession[session_id]; + cfg_param = &mac_ctx->roam.configParam; + conn_profile = &roamsession->connectedProfile; + if (roamsession->pCurRoamProfile && + ((roamsession->pCurRoamProfile->csrPersona == + QDF_P2P_CLIENT_MODE) || + (roamsession->pCurRoamProfile->csrPersona == + QDF_STA_MODE))) { + /* check for P2P_client scenario */ + if ((conn_profile->operationChannel == 0) && + (conn_profile->beaconInterval == 0)) + return false; + + if (csr_is_conn_state_connected_infra(mac_ctx, session_id) && + (conn_profile->operationChannel != chnl_id) && + (conn_profile->beaconInterval != *bcn_interval)) { + /* + * Updated beaconInterval should be used only when + * we are starting a new BSS not incase of + * client or STA case + */ + + /* Calculate beacon Interval for P2P-GO incase of MCC */ + if (cfg_param->conc_custom_rule1 || + cfg_param->conc_custom_rule2) { + new_bcn_interval = CSR_CUSTOM_CONC_GO_BI; + } else { + new_bcn_interval = + csr_calculate_mcc_beacon_interval( + mac_ctx, + conn_profile->beaconInterval, + *bcn_interval); + } + if (*bcn_interval != new_bcn_interval) + *bcn_interval = new_bcn_interval; + *status = QDF_STATUS_SUCCESS; + return true; + } + } + return false; +} + +/** + * csr_validate_sta_bcn_intrvl() - to validate sta beacon interval + * @mac_ctx: pointer to mac context + * @chnl_id: channel id variable + * @bcn_interval: pointer to given beacon interval + * @session_id: given session id + * @status: fill the status in terms of QDF_STATUS to inform caller + * + * This API can provide the validation the beacon interval and re-calculate + * in case concurrency + * + * Return: bool + */ +static bool csr_validate_sta_bcn_intrvl(tpAniSirGlobal mac_ctx, + uint8_t chnl_id, uint16_t *bcn_interval, + uint32_t session_id, QDF_STATUS *status) +{ + tCsrRoamSession *roamsession; + tCsrConfig *cfg_param; + uint16_t new_bcn_interval; + + roamsession = &mac_ctx->roam.roamSession[session_id]; + cfg_param = &mac_ctx->roam.configParam; + + if (roamsession->pCurRoamProfile && + (roamsession->pCurRoamProfile->csrPersona == + QDF_P2P_CLIENT_MODE)) { + /* check for P2P client mode */ + sms_log(mac_ctx, LOG1, + FL("Bcn Intrvl validation not require for STA/CLIENT")); + return false; + } + if ((roamsession->bssParams.bssPersona == QDF_SAP_MODE) && + (roamsession->bssParams.operationChn != chnl_id)) { + /* + * IF SAP has started and STA wants to connect + * on different channel MCC should + * MCC should not be enabled so making it + * false to enforce on same channel + */ + sms_log(mac_ctx, LOGE, + FL("*** MCC with SAP+STA sessions ****")); + *status = QDF_STATUS_SUCCESS; + return true; + } + /* + * Check for P2P go scenario + * if GO in MCC support different + * beacon interval, + * change the BI of the P2P-GO + */ + if ((roamsession->bssParams.bssPersona == QDF_P2P_GO_MODE) && + (roamsession->bssParams.operationChn != chnl_id) && + (roamsession->bssParams.beaconInterval != *bcn_interval)) { + /* if GO in MCC support diff beacon interval, return success */ + if (cfg_param->fAllowMCCGODiffBI == 0x01) { + *status = QDF_STATUS_SUCCESS; + return true; + } + /* + * Send only Broadcast disassoc and update bcn_interval + * If configuration is set to 0x04 then dont + * disconnect all the station + */ + if ((cfg_param->fAllowMCCGODiffBI == 0x02) + || (cfg_param->fAllowMCCGODiffBI == 0x04)) { + /* Check to pass the right beacon Interval */ + if (cfg_param->conc_custom_rule1 || + cfg_param->conc_custom_rule2) { + new_bcn_interval = CSR_CUSTOM_CONC_GO_BI; + } else { + new_bcn_interval = + csr_calculate_mcc_beacon_interval( + mac_ctx, *bcn_interval, + roamsession->bssParams.beaconInterval); + } + sms_log(mac_ctx, LOG1, + FL(" Peer AP BI : %d, new Beacon Interval: %d"), + *bcn_interval, new_bcn_interval); + /* Update the becon Interval */ + if (new_bcn_interval != + roamsession->bssParams.beaconInterval) { + /* Update the bcn_interval now */ + sms_log(mac_ctx, LOGE, + FL(" Beacon Interval got changed config used: %d\n"), + cfg_param->fAllowMCCGODiffBI); + + roamsession->bssParams.beaconInterval = + new_bcn_interval; + roamsession->bssParams.updatebeaconInterval = + true; + *status = csr_update_mcc_p2p_beacon_interval( + mac_ctx); + return true; + } + *status = QDF_STATUS_SUCCESS; + return true; + } + if (cfg_param->fAllowMCCGODiffBI + == 0x03) { + /* Disconnect the P2P session */ + roamsession->bssParams.updatebeaconInterval = false; + *status = csr_roam_call_callback(mac_ctx, + session_id, NULL, 0, + eCSR_ROAM_SEND_P2P_STOP_BSS, + eCSR_ROAM_RESULT_NONE); + return true; + } + sms_log(mac_ctx, LOGE, + FL("BcnIntrvl is diff can't connect to preferred AP...")); + *status = QDF_STATUS_E_FAILURE; + return true; + } + return false; +} + +/** + * csr_validate_mcc_beacon_interval() - to validate the mcc beacon interval + * @mac_ctx: pointer to mac context + * @chnl_id: channel number + * @bcn_interval: provided beacon interval + * @cur_session_id: current session id + * @cur_bss_persona: Current BSS persona + * + * This API will validate the mcc beacon interval + * + * Return: QDF_STATUS + */ +QDF_STATUS csr_validate_mcc_beacon_interval(tpAniSirGlobal mac_ctx, + uint8_t chnl_id, + uint16_t *bcn_interval, + uint32_t cur_session_id, + enum tQDF_ADAPTER_MODE cur_bss_persona) +{ + uint32_t session_id = 0; + QDF_STATUS status; + bool is_done; + + /* If MCC is not supported just break */ + if (!mac_ctx->roam.configParam.fenableMCCMode) + return QDF_STATUS_E_FAILURE; + + for (session_id = 0; session_id < CSR_ROAM_SESSION_MAX; session_id++) { + if (cur_session_id == session_id) + continue; + + if (!CSR_IS_SESSION_VALID(mac_ctx, session_id)) + continue; + + switch (cur_bss_persona) { + case QDF_STA_MODE: + is_done = csr_validate_sta_bcn_intrvl(mac_ctx, chnl_id, + bcn_interval, session_id, &status); + if (true == is_done) + return status; + break; + + case QDF_P2P_CLIENT_MODE: + is_done = csr_validate_p2pcli_bcn_intrvl(mac_ctx, + chnl_id, bcn_interval, session_id, + &status); + if (true == is_done) + return status; + break; + + case QDF_SAP_MODE: + case QDF_IBSS_MODE: + break; + + case QDF_P2P_GO_MODE: + is_done = csr_validate_p2pgo_bcn_intrvl(mac_ctx, + chnl_id, bcn_interval, + session_id, &status); + if (true == is_done) + return status; + break; + + default: + sms_log(mac_ctx, LOGE, + FL("Persona not supported : %d"), + cur_bss_persona); + return QDF_STATUS_E_FAILURE; + } + } + return QDF_STATUS_SUCCESS; +} + +/** + * csr_is_auth_type11r() - Check if Authentication type is 11R + * @auth_type: The authentication type that is used to make the connection + * @mdie_present: Is MDIE IE present + * + * Return: true if is 11R auth type, false otherwise + */ +bool csr_is_auth_type11r(eCsrAuthType auth_type, uint8_t mdie_present) +{ + switch (auth_type) { + case eCSR_AUTH_TYPE_OPEN_SYSTEM: + if (mdie_present) + return true; + break; + case eCSR_AUTH_TYPE_FT_RSN_PSK: + case eCSR_AUTH_TYPE_FT_RSN: + return true; + break; + default: + break; + } + return false; +} + +/* Function to return true if the profile is 11r */ +bool csr_is_profile11r(tCsrRoamProfile *pProfile) +{ + return csr_is_auth_type11r(pProfile->negotiatedAuthType, + pProfile->MDID.mdiePresent); +} + + +#ifdef FEATURE_WLAN_ESE + +/* Function to return true if the authtype is ESE */ +bool csr_is_auth_type_ese(eCsrAuthType AuthType) +{ + switch (AuthType) { + case eCSR_AUTH_TYPE_CCKM_WPA: + case eCSR_AUTH_TYPE_CCKM_RSN: + return true; + break; + default: + break; + } + return false; +} + +/* Function to return true if the profile is ESE */ +bool csr_is_profile_ese(tCsrRoamProfile *pProfile) +{ + return csr_is_auth_type_ese(pProfile->negotiatedAuthType); +} + +#endif + +#ifdef FEATURE_WLAN_WAPI +bool csr_is_profile_wapi(tCsrRoamProfile *pProfile) +{ + bool fWapiProfile = false; + + switch (pProfile->negotiatedAuthType) { + case eCSR_AUTH_TYPE_WAPI_WAI_CERTIFICATE: + case eCSR_AUTH_TYPE_WAPI_WAI_PSK: + fWapiProfile = true; + break; + + default: + fWapiProfile = false; + break; + } + + if (fWapiProfile) { + switch (pProfile->negotiatedUCEncryptionType) { + case eCSR_ENCRYPT_TYPE_WPI: + fWapiProfile = true; + break; + + default: + fWapiProfile = false; + break; + } + } + return fWapiProfile; +} + +static bool csr_is_wapi_oui_equal(tpAniSirGlobal pMac, uint8_t *Oui1, + uint8_t *Oui2) +{ + return !qdf_mem_cmp(Oui1, Oui2, CSR_WAPI_OUI_SIZE); +} + +static bool csr_is_wapi_oui_match(tpAniSirGlobal pMac, + uint8_t AllCyphers[][CSR_WAPI_OUI_SIZE], + uint8_t cAllCyphers, uint8_t Cypher[], + uint8_t Oui[]) +{ + bool fYes = false; + uint8_t idx; + + for (idx = 0; idx < cAllCyphers; idx++) { + if (csr_is_wapi_oui_equal(pMac, AllCyphers[idx], Cypher)) { + fYes = true; + break; + } + } + + if (fYes && Oui) { + qdf_mem_copy(Oui, AllCyphers[idx], CSR_WAPI_OUI_SIZE); + } + + return fYes; +} +#endif /* FEATURE_WLAN_WAPI */ + +static bool csr_is_wpa_oui_equal(tpAniSirGlobal pMac, uint8_t *Oui1, + uint8_t *Oui2) +{ + return !qdf_mem_cmp(Oui1, Oui2, CSR_WPA_OUI_SIZE); +} + +static bool csr_is_oui_match(tpAniSirGlobal pMac, + uint8_t AllCyphers[][CSR_WPA_OUI_SIZE], + uint8_t cAllCyphers, uint8_t Cypher[], uint8_t Oui[]) +{ + bool fYes = false; + uint8_t idx; + + for (idx = 0; idx < cAllCyphers; idx++) { + if (csr_is_wpa_oui_equal(pMac, AllCyphers[idx], Cypher)) { + fYes = true; + break; + } + } + + if (fYes && Oui) { + qdf_mem_copy(Oui, AllCyphers[idx], CSR_WPA_OUI_SIZE); + } + + return fYes; +} + +static bool csr_match_rsnoui_index(tpAniSirGlobal pMac, + uint8_t AllCyphers[][CSR_RSN_OUI_SIZE], + uint8_t cAllCyphers, uint8_t ouiIndex, + uint8_t Oui[]) +{ + return csr_is_oui_match + (pMac, AllCyphers, cAllCyphers, csr_rsn_oui[ouiIndex], Oui); + +} + +#ifdef FEATURE_WLAN_WAPI +static bool csr_match_wapi_oui_index(tpAniSirGlobal pMac, + uint8_t AllCyphers[][CSR_WAPI_OUI_SIZE], + uint8_t cAllCyphers, uint8_t ouiIndex, + uint8_t Oui[]) +{ + return csr_is_wapi_oui_match + (pMac, AllCyphers, cAllCyphers, csr_wapi_oui[ouiIndex], Oui); + +} +#endif /* FEATURE_WLAN_WAPI */ + +static bool csr_match_wpaoui_index(tpAniSirGlobal pMac, + uint8_t AllCyphers[][CSR_RSN_OUI_SIZE], + uint8_t cAllCyphers, uint8_t ouiIndex, + uint8_t Oui[]) +{ + return csr_is_oui_match + (pMac, AllCyphers, cAllCyphers, csr_wpa_oui[ouiIndex], Oui); + +} + +#ifdef FEATURE_WLAN_WAPI +static bool csr_is_auth_wapi_cert(tpAniSirGlobal pMac, + uint8_t AllSuites[][CSR_WAPI_OUI_SIZE], + uint8_t cAllSuites, uint8_t Oui[]) +{ + return csr_is_wapi_oui_match + (pMac, AllSuites, cAllSuites, csr_wapi_oui[1], Oui); +} + +static bool csr_is_auth_wapi_psk(tpAniSirGlobal pMac, + uint8_t AllSuites[][CSR_WAPI_OUI_SIZE], + uint8_t cAllSuites, uint8_t Oui[]) +{ + return csr_is_wapi_oui_match + (pMac, AllSuites, cAllSuites, csr_wapi_oui[2], Oui); +} +#endif /* FEATURE_WLAN_WAPI */ + + +/* + * Function for 11R FT Authentication. We match the FT Authentication Cipher + * suite here. This matches for FT Auth with the 802.1X exchange. + */ +static bool csr_is_ft_auth_rsn(tpAniSirGlobal pMac, + uint8_t AllSuites[][CSR_RSN_OUI_SIZE], + uint8_t cAllSuites, uint8_t Oui[]) +{ + return csr_is_oui_match + (pMac, AllSuites, cAllSuites, csr_rsn_oui[03], Oui); +} + +/* + * Function for 11R FT Authentication. We match the FT Authentication Cipher + * suite here. This matches for FT Auth with the PSK. + */ +static bool csr_is_ft_auth_rsn_psk(tpAniSirGlobal pMac, + uint8_t AllSuites[][CSR_RSN_OUI_SIZE], + uint8_t cAllSuites, uint8_t Oui[]) +{ + return csr_is_oui_match + (pMac, AllSuites, cAllSuites, csr_rsn_oui[04], Oui); +} + + +#ifdef FEATURE_WLAN_ESE + +/* + * Function for ESE CCKM AKM Authentication. We match the CCKM AKM + * Authentication Key Management suite here. This matches for CCKM AKM Auth + * with the 802.1X exchange. + */ +static bool csr_is_ese_cckm_auth_rsn(tpAniSirGlobal pMac, + uint8_t AllSuites[][CSR_RSN_OUI_SIZE], + uint8_t cAllSuites, uint8_t Oui[]) +{ + return csr_is_oui_match + (pMac, AllSuites, cAllSuites, csr_rsn_oui[06], Oui); +} + +static bool csr_is_ese_cckm_auth_wpa(tpAniSirGlobal pMac, + uint8_t AllSuites[][CSR_WPA_OUI_SIZE], + uint8_t cAllSuites, uint8_t Oui[]) +{ + return csr_is_oui_match + (pMac, AllSuites, cAllSuites, csr_wpa_oui[06], Oui); +} + +#endif + +static bool csr_is_auth_rsn(tpAniSirGlobal pMac, + uint8_t AllSuites[][CSR_RSN_OUI_SIZE], + uint8_t cAllSuites, uint8_t Oui[]) +{ + return csr_is_oui_match + (pMac, AllSuites, cAllSuites, csr_rsn_oui[01], Oui); +} + +static bool csr_is_auth_rsn_psk(tpAniSirGlobal pMac, + uint8_t AllSuites[][CSR_RSN_OUI_SIZE], + uint8_t cAllSuites, uint8_t Oui[]) +{ + return csr_is_oui_match + (pMac, AllSuites, cAllSuites, csr_rsn_oui[02], Oui); +} + +#ifdef WLAN_FEATURE_11W +static bool csr_is_auth_rsn_psk_sha256(tpAniSirGlobal pMac, + uint8_t AllSuites[][CSR_RSN_OUI_SIZE], + uint8_t cAllSuites, uint8_t Oui[]) +{ + return csr_is_oui_match + (pMac, AllSuites, cAllSuites, csr_rsn_oui[07], Oui); +} +static bool csr_is_auth_rsn8021x_sha256(tpAniSirGlobal pMac, + uint8_t AllSuites[][CSR_RSN_OUI_SIZE], + uint8_t cAllSuites, uint8_t Oui[]) +{ + return csr_is_oui_match + (pMac, AllSuites, cAllSuites, csr_rsn_oui[8], Oui); +} +#endif + +static bool csr_is_auth_wpa(tpAniSirGlobal pMac, + uint8_t AllSuites[][CSR_WPA_OUI_SIZE], + uint8_t cAllSuites, uint8_t Oui[]) +{ + return csr_is_oui_match + (pMac, AllSuites, cAllSuites, csr_wpa_oui[01], Oui); +} + +static bool csr_is_auth_wpa_psk(tpAniSirGlobal pMac, + uint8_t AllSuites[][CSR_WPA_OUI_SIZE], + uint8_t cAllSuites, uint8_t Oui[]) +{ + return csr_is_oui_match + (pMac, AllSuites, cAllSuites, csr_wpa_oui[02], Oui); +} + +static uint8_t csr_get_oui_index_from_cipher(eCsrEncryptionType enType) +{ + uint8_t OUIIndex; + + switch (enType) { + case eCSR_ENCRYPT_TYPE_WEP40: + case eCSR_ENCRYPT_TYPE_WEP40_STATICKEY: + OUIIndex = CSR_OUI_WEP40_OR_1X_INDEX; + break; + case eCSR_ENCRYPT_TYPE_WEP104: + case eCSR_ENCRYPT_TYPE_WEP104_STATICKEY: + OUIIndex = CSR_OUI_WEP104_INDEX; + break; + case eCSR_ENCRYPT_TYPE_TKIP: + OUIIndex = CSR_OUI_TKIP_OR_PSK_INDEX; + break; + case eCSR_ENCRYPT_TYPE_AES: + OUIIndex = CSR_OUI_AES_INDEX; + break; + case eCSR_ENCRYPT_TYPE_NONE: + OUIIndex = CSR_OUI_USE_GROUP_CIPHER_INDEX; + break; +#ifdef FEATURE_WLAN_WAPI + case eCSR_ENCRYPT_TYPE_WPI: + OUIIndex = CSR_OUI_WAPI_WAI_CERT_OR_SMS4_INDEX; + break; +#endif /* FEATURE_WLAN_WAPI */ + default: /* HOWTO handle this? */ + OUIIndex = CSR_OUI_RESERVED_INDEX; + break; + } /* switch */ + + return OUIIndex; +} +/** + * csr_get_rsn_information() - to get RSN infomation + * @hal: pointer to HAL + * @auth_type: auth type + * @encr_type: encryption type + * @mc_encryption: multicast encryption type + * @rsn_ie: pointer to RSN IE + * @ucast_cipher: Unicast cipher + * @mcast_cipher: Multicast cipher + * @auth_suite: Authentication suite + * @capabilities: RSN capabilities + * @negotiated_authtype: Negotiated auth type + * @negotiated_mccipher: negotiated multicast cipher + * + * This routine will get all RSN information + * + * Return: bool + */ +static bool csr_get_rsn_information(tHalHandle hal, tCsrAuthList *auth_type, + eCsrEncryptionType encr_type, + tCsrEncryptionList *mc_encryption, + tDot11fIERSN *rsn_ie, uint8_t *ucast_cipher, + uint8_t *mcast_cipher, uint8_t *auth_suite, + tCsrRSNCapabilities *capabilities, + eCsrAuthType *negotiated_authtype, + eCsrEncryptionType *negotiated_mccipher) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + bool acceptable_cipher = false; + uint8_t c_ucast_cipher = 0; + uint8_t c_mcast_cipher = 0; + uint8_t c_auth_suites = 0, i; + uint8_t unicast[CSR_RSN_OUI_SIZE]; + uint8_t multicast[CSR_RSN_OUI_SIZE]; + uint8_t authsuites[CSR_RSN_MAX_AUTH_SUITES][CSR_RSN_OUI_SIZE]; + uint8_t authentication[CSR_RSN_OUI_SIZE]; + uint8_t mccipher_arr[CSR_RSN_MAX_MULTICAST_CYPHERS][CSR_RSN_OUI_SIZE]; + eCsrAuthType neg_authtype = eCSR_AUTH_TYPE_UNKNOWN; + + if (!rsn_ie->present) + goto end; + c_mcast_cipher++; + qdf_mem_copy(mccipher_arr, rsn_ie->gp_cipher_suite, + CSR_RSN_OUI_SIZE); + c_ucast_cipher = + (uint8_t) (rsn_ie->pwise_cipher_suite_count); + c_auth_suites = (uint8_t) (rsn_ie->akm_suite_count); + for (i = 0; i < c_auth_suites && i < CSR_RSN_MAX_AUTH_SUITES; i++) { + qdf_mem_copy((void *)&authsuites[i], + (void *)&rsn_ie->akm_suites[i], CSR_RSN_OUI_SIZE); + } + + /* Check - Is requested unicast Cipher supported by the BSS. */ + acceptable_cipher = csr_match_rsnoui_index(mac_ctx, + rsn_ie->pwise_cipher_suites, c_ucast_cipher, + csr_get_oui_index_from_cipher(encr_type), + unicast); + + if (!acceptable_cipher) + goto end; + + /* unicast is supported. Pick the first matching Group cipher, if any */ + for (i = 0; i < mc_encryption->numEntries; i++) { + acceptable_cipher = csr_match_rsnoui_index(mac_ctx, + mccipher_arr, c_mcast_cipher, + csr_get_oui_index_from_cipher( + mc_encryption->encryptionType[i]), + multicast); + if (acceptable_cipher) + break; + } + if (!acceptable_cipher) + goto end; + + if (negotiated_mccipher) + *negotiated_mccipher = mc_encryption->encryptionType[i]; + + /* Initializing with false as it has true value already */ + acceptable_cipher = false; + for (i = 0; i < auth_type->numEntries; i++) { + /* + * Ciphers are supported, Match authentication algorithm and + * pick first matching authtype. + */ + /* Changed the AKM suites according to order of preference */ + if (csr_is_ft_auth_rsn(mac_ctx, authsuites, + c_auth_suites, authentication)) { + if (eCSR_AUTH_TYPE_FT_RSN == auth_type->authType[i]) + neg_authtype = eCSR_AUTH_TYPE_FT_RSN; + } + if ((neg_authtype == eCSR_AUTH_TYPE_UNKNOWN) + && csr_is_ft_auth_rsn_psk(mac_ctx, authsuites, + c_auth_suites, authentication)) { + if (eCSR_AUTH_TYPE_FT_RSN_PSK == + auth_type->authType[i]) + neg_authtype = eCSR_AUTH_TYPE_FT_RSN_PSK; + } +#ifdef FEATURE_WLAN_ESE + /* ESE only supports 802.1X. No PSK. */ + if ((neg_authtype == eCSR_AUTH_TYPE_UNKNOWN) && + csr_is_ese_cckm_auth_rsn(mac_ctx, authsuites, + c_auth_suites, authentication)) { + if (eCSR_AUTH_TYPE_CCKM_RSN == auth_type->authType[i]) + neg_authtype = eCSR_AUTH_TYPE_CCKM_RSN; + } +#endif + if ((neg_authtype == eCSR_AUTH_TYPE_UNKNOWN) + && csr_is_auth_rsn(mac_ctx, authsuites, + c_auth_suites, authentication)) { + if (eCSR_AUTH_TYPE_RSN == auth_type->authType[i]) + neg_authtype = eCSR_AUTH_TYPE_RSN; + } + if ((neg_authtype == eCSR_AUTH_TYPE_UNKNOWN) + && csr_is_auth_rsn_psk(mac_ctx, authsuites, + c_auth_suites, authentication)) { + if (eCSR_AUTH_TYPE_RSN_PSK == auth_type->authType[i]) + neg_authtype = eCSR_AUTH_TYPE_RSN_PSK; + } +#ifdef WLAN_FEATURE_11W + if ((neg_authtype == eCSR_AUTH_TYPE_UNKNOWN) + && csr_is_auth_rsn_psk_sha256(mac_ctx, authsuites, + c_auth_suites, authentication)) { + if (eCSR_AUTH_TYPE_RSN_PSK_SHA256 == + auth_type->authType[i]) + neg_authtype = eCSR_AUTH_TYPE_RSN_PSK_SHA256; + } + if ((neg_authtype == eCSR_AUTH_TYPE_UNKNOWN) && + csr_is_auth_rsn8021x_sha256(mac_ctx, authsuites, + c_auth_suites, authentication)) { + if (eCSR_AUTH_TYPE_RSN_8021X_SHA256 == + auth_type->authType[i]) + neg_authtype = eCSR_AUTH_TYPE_RSN_8021X_SHA256; + } +#endif + + /* + * The 1st auth type in the APs RSN IE, to match stations + * connecting profiles auth type will cause us to exit this + * loop. This is added as some APs advertise multiple akms in + * the RSN IE + */ + if (eCSR_AUTH_TYPE_UNKNOWN != neg_authtype) { + acceptable_cipher = true; + break; + } + } /* for */ +end: + if (acceptable_cipher) { + if (mcast_cipher) + qdf_mem_copy(mcast_cipher, multicast, + CSR_RSN_OUI_SIZE); + + if (ucast_cipher) + qdf_mem_copy(ucast_cipher, unicast, CSR_RSN_OUI_SIZE); + + if (auth_suite) + qdf_mem_copy(auth_suite, authentication, + CSR_RSN_OUI_SIZE); + + if (negotiated_authtype) + *negotiated_authtype = neg_authtype; + + if (capabilities) { + /* Bit 0 Preauthentication */ + capabilities->PreAuthSupported = + (rsn_ie->RSN_Cap[0] >> 0) & 0x1; + /* Bit 1 No Pairwise */ + capabilities->NoPairwise = + (rsn_ie->RSN_Cap[0] >> 1) & 0x1; + /* Bit 2, 3 PTKSA Replay Counter */ + capabilities->PTKSAReplayCounter = + (rsn_ie->RSN_Cap[0] >> 2) & 0x3; + /* Bit 4, 5 GTKSA Replay Counter */ + capabilities->GTKSAReplayCounter = + (rsn_ie->RSN_Cap[0] >> 4) & 0x3; +#ifdef WLAN_FEATURE_11W + /* Bit 6 MFPR */ + capabilities->MFPRequired = + (rsn_ie->RSN_Cap[0] >> 6) & 0x1; + /* Bit 7 MFPC */ + capabilities->MFPCapable = + (rsn_ie->RSN_Cap[0] >> 7) & 0x1; +#else + /* Bit 6 MFPR */ + capabilities->MFPRequired = 0; + /* Bit 7 MFPC */ + capabilities->MFPCapable = 0; +#endif + /* remaining reserved */ + capabilities->Reserved = rsn_ie->RSN_Cap[1] & 0xff; + } + } + return acceptable_cipher; +} + +#ifdef WLAN_FEATURE_11W +/** + * csr_is_pmf_capabilities_in_rsn_match() - check for PMF capability + * @hHal: Global HAL handle + * @pFilterMFPEnabled: given by supplicant to us to specify what kind + * of connection supplicant is expecting to make + * if it is enabled then make PMF connection. + * if it is disabled then make normal connection. + * @pFilterMFPRequired: given by supplicant based on our configuration + * if it is 1 then we will require mandatory + * PMF connection and if it is 0 then we PMF + * connection is optional. + * @pFilterMFPCapable: given by supplicant based on our configuration + * if it 1 then we are PMF capable and if it 0 + * then we are not PMF capable. + * @pRSNIe: RSNIe from Beacon/probe response of + * neighbor AP against which we will compare + * our capabilities. + * + * This function is to match our current capabilities with the AP + * to which we are expecting make the connection. + * + * Return: if our PMF capabilities matches with AP then we + * will return true to indicate that we are good + * to make connection with it. Else we will return false + **/ +static bool +csr_is_pmf_capabilities_in_rsn_match(tHalHandle hHal, + bool *pFilterMFPEnabled, + uint8_t *pFilterMFPRequired, + uint8_t *pFilterMFPCapable, + tDot11fIERSN *pRSNIe) +{ + uint8_t apProfileMFPCapable = 0; + uint8_t apProfileMFPRequired = 0; + if (pRSNIe && pFilterMFPEnabled && pFilterMFPCapable + && pFilterMFPRequired) { + /* Extracting MFPCapable bit from RSN Ie */ + apProfileMFPCapable = (pRSNIe->RSN_Cap[0] >> 7) & 0x1; + apProfileMFPRequired = (pRSNIe->RSN_Cap[0] >> 6) & 0x1; + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO, + FL("pFilterMFPEnabled=%d pFilterMFPRequired=%d" + "pFilterMFPCapable=%d apProfileMFPCapable=%d" + "apProfileMFPRequired=%d"), + *pFilterMFPEnabled, *pFilterMFPRequired, + *pFilterMFPCapable, apProfileMFPCapable, + apProfileMFPRequired); + + if (*pFilterMFPEnabled && *pFilterMFPCapable + && *pFilterMFPRequired && (apProfileMFPCapable == 0)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO, + "AP is not capable to make PMF connection"); + return false; + } else if (!(*pFilterMFPCapable) && + apProfileMFPCapable && apProfileMFPRequired) { + + /* + * In this case, AP with whom we trying to connect + * requires mandatory PMF connections and we are not + * capable so this AP is not good choice to connect + */ + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO, + "AP needs PMF connection and we are not capable of pmf connection"); + return false; + } + } + return true; +} +#endif + +static bool csr_is_rsn_match(tHalHandle hHal, tCsrAuthList *pAuthType, + eCsrEncryptionType enType, + tCsrEncryptionList *pEnMcType, + bool *pMFPEnabled, uint8_t *pMFPRequired, + uint8_t *pMFPCapable, + tDot11fBeaconIEs *pIes, + eCsrAuthType *pNegotiatedAuthType, + eCsrEncryptionType *pNegotiatedMCCipher) +{ + bool fRSNMatch = false; + + /* See if the cyphers in the Bss description match with the settings in the profile. */ + fRSNMatch = + csr_get_rsn_information(hHal, pAuthType, enType, pEnMcType, &pIes->RSN, + NULL, NULL, NULL, NULL, pNegotiatedAuthType, + pNegotiatedMCCipher); +#ifdef WLAN_FEATURE_11W + /* If all the filter matches then finally checks for PMF capabilities */ + if (fRSNMatch) { + fRSNMatch = csr_is_pmf_capabilities_in_rsn_match(hHal, pMFPEnabled, + pMFPRequired, + pMFPCapable, + &pIes->RSN); + } +#endif + return fRSNMatch; +} + +static bool csr_lookup_pmkid(tpAniSirGlobal pMac, uint32_t sessionId, + uint8_t *pBSSId, uint8_t *pPMKId) +{ + bool fRC = false, fMatchFound = false; + uint32_t Index; + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!pSession) { + sms_log(pMac, LOGE, FL(" session %d not found "), sessionId); + return false; + } + + do { + for (Index = 0; Index < CSR_MAX_PMKID_ALLOWED; Index++) { + sms_log(pMac, LOG1, + "match PMKID " MAC_ADDRESS_STR " to ", + MAC_ADDR_ARRAY(pBSSId)); + if (!qdf_mem_cmp + (pBSSId, pSession->PmkidCacheInfo[Index].BSSID.bytes, + sizeof(struct qdf_mac_addr))) { + /* match found */ + fMatchFound = true; + break; + } + } + + if (!fMatchFound) + break; + + qdf_mem_copy(pPMKId, pSession->PmkidCacheInfo[Index].PMKID, + CSR_RSN_PMKID_SIZE); + + fRC = true; + } while (0); + sms_log(pMac, LOGW, + "csr_lookup_pmkid called return match = %d pMac->roam.NumPmkidCache = %d", + fRC, pSession->NumPmkidCache); + + return fRC; +} + +uint8_t csr_construct_rsn_ie(tHalHandle hHal, uint32_t sessionId, + tCsrRoamProfile *pProfile, + tSirBssDescription *pSirBssDesc, + tDot11fBeaconIEs *pIes, tCsrRSNIe *pRSNIe) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + bool fRSNMatch; + uint8_t cbRSNIe = 0; + uint8_t UnicastCypher[CSR_RSN_OUI_SIZE]; + uint8_t MulticastCypher[CSR_RSN_OUI_SIZE]; + uint8_t AuthSuite[CSR_RSN_OUI_SIZE]; + tCsrRSNAuthIe *pAuthSuite; + tCsrRSNCapabilities RSNCapabilities; + tCsrRSNPMKIe *pPMK; + uint8_t PMKId[CSR_RSN_PMKID_SIZE]; +#ifdef WLAN_FEATURE_11W + uint8_t *pGroupMgmtCipherSuite; +#endif + tDot11fBeaconIEs *pIesLocal = pIes; + eCsrAuthType negAuthType = eCSR_AUTH_TYPE_UNKNOWN; + + sms_log(pMac, LOGW, "%s called...", __func__); + + do { + if (!csr_is_profile_rsn(pProfile)) + break; + + if (!pIesLocal + && + (!QDF_IS_STATUS_SUCCESS + (csr_get_parsed_bss_description_ies + (pMac, pSirBssDesc, &pIesLocal)))) { + break; + } + /* See if the cyphers in the Bss description match with the settings in the profile. */ + fRSNMatch = + csr_get_rsn_information(hHal, &pProfile->AuthType, + pProfile->negotiatedUCEncryptionType, + &pProfile->mcEncryptionType, + &pIesLocal->RSN, UnicastCypher, + MulticastCypher, AuthSuite, + &RSNCapabilities, &negAuthType, NULL); + if (!fRSNMatch) + break; + + pRSNIe->IeHeader.ElementID = SIR_MAC_RSN_EID; + + pRSNIe->Version = CSR_RSN_VERSION_SUPPORTED; + + qdf_mem_copy(pRSNIe->MulticastOui, MulticastCypher, + sizeof(MulticastCypher)); + + pRSNIe->cUnicastCyphers = 1; + + qdf_mem_copy(&pRSNIe->UnicastOui[0], UnicastCypher, + sizeof(UnicastCypher)); + + pAuthSuite = + (tCsrRSNAuthIe *) (&pRSNIe-> + UnicastOui[pRSNIe->cUnicastCyphers]); + + pAuthSuite->cAuthenticationSuites = 1; + qdf_mem_copy(&pAuthSuite->AuthOui[0], AuthSuite, + sizeof(AuthSuite)); + + /* RSN capabilities follows the Auth Suite (two octects) */ + /* !!REVIEW - What should STA put in RSN capabilities, currently */ + /* just putting back APs capabilities */ + /* For one, we shouldn't EVER be sending out "pre-auth supported". It is an AP only capability */ + /* For another, we should use the Management Frame Protection values given by the supplicant */ + RSNCapabilities.PreAuthSupported = 0; +#ifdef WLAN_FEATURE_11W + if (RSNCapabilities.MFPCapable && pProfile->MFPCapable) { + RSNCapabilities.MFPCapable = pProfile->MFPCapable; + RSNCapabilities.MFPRequired = pProfile->MFPRequired; + } else { + RSNCapabilities.MFPCapable = 0; + RSNCapabilities.MFPRequired = 0; + } +#endif + *(uint16_t *) (&pAuthSuite->AuthOui[1]) = + *((uint16_t *) (&RSNCapabilities)); + + pPMK = + (tCsrRSNPMKIe *) (((uint8_t *) (&pAuthSuite->AuthOui[1])) + + sizeof(uint16_t)); + + /* Don't include the PMK SA IDs for CCKM associations. */ + if ( +#ifdef FEATURE_WLAN_ESE + (eCSR_AUTH_TYPE_CCKM_RSN != negAuthType) && +#endif + csr_lookup_pmkid(pMac, sessionId, pSirBssDesc->bssId, + &(PMKId[0]))) { + pPMK->cPMKIDs = 1; + + qdf_mem_copy(pPMK->PMKIDList[0].PMKID, PMKId, + CSR_RSN_PMKID_SIZE); + } else { + pPMK->cPMKIDs = 0; + } + +#ifdef WLAN_FEATURE_11W + /* Advertise BIP in group cipher key management only if PMF is + * enabled and AP is capable. + */ + if (pProfile->MFPEnabled && + (RSNCapabilities.MFPCapable && pProfile->MFPCapable)) { + pGroupMgmtCipherSuite = + (uint8_t *) pPMK + sizeof(uint16_t) + + (pPMK->cPMKIDs * CSR_RSN_PMKID_SIZE); + qdf_mem_copy(pGroupMgmtCipherSuite, csr_rsn_oui[07], + CSR_WPA_OUI_SIZE); + } +#endif + + /* Add in the fixed fields plus 1 Unicast cypher, less the IE Header length */ + /* Add in the size of the Auth suite (count plus a single OUI) */ + /* Add in the RSN caps field. */ + /* Add PMKID count and PMKID (if any) */ + /* Add group management cipher suite */ + pRSNIe->IeHeader.Length = + (uint8_t) (sizeof(*pRSNIe) - sizeof(pRSNIe->IeHeader) + + sizeof(*pAuthSuite) + + sizeof(tCsrRSNCapabilities)); + if (pPMK->cPMKIDs) { + pRSNIe->IeHeader.Length += (uint8_t) (sizeof(uint16_t) + + (pPMK->cPMKIDs * + CSR_RSN_PMKID_SIZE)); + } +#ifdef WLAN_FEATURE_11W + if (pProfile->MFPEnabled && + (RSNCapabilities.MFPCapable && pProfile->MFPCapable)) { + if (0 == pPMK->cPMKIDs) + pRSNIe->IeHeader.Length += sizeof(uint16_t); + pRSNIe->IeHeader.Length += CSR_WPA_OUI_SIZE; + } +#endif + + /* return the size of the IE header (total) constructed... */ + cbRSNIe = pRSNIe->IeHeader.Length + sizeof(pRSNIe->IeHeader); + + } while (0); + + if (!pIes && pIesLocal) { + /* locally allocated */ + qdf_mem_free(pIesLocal); + } + + return cbRSNIe; +} + +#ifdef FEATURE_WLAN_WAPI +/** + * csr_get_wapi_information() - to get WAPI infomation + * @hal: pointer to HAL + * @auth_type: auth type + * @encr_type: encryption type + * @mc_encryption: multicast encryption type + * @wapi_ie: pointer to WAPI IE + * @ucast_cipher: Unicast cipher + * @mcast_cipher: Multicast cipher + * @auth_suite: Authentication suite + * @negotiated_authtype: Negotiated auth type + * @negotiated_mccipher: negotiated multicast cipher + * + * This routine will get all WAPI information + * + * Return: bool + */ +static bool csr_get_wapi_information(tHalHandle hal, tCsrAuthList *auth_type, + eCsrEncryptionType encr_type, + tCsrEncryptionList *mc_encryption, + tDot11fIEWAPI *wapi_ie, + uint8_t *ucast_cipher, + uint8_t *mcast_cipher, uint8_t *auth_suite, + eCsrAuthType *negotiated_authtype, + eCsrEncryptionType *negotiated_mccipher) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + bool acceptable_cipher = false; + uint8_t c_ucast_cipher = 0; + uint8_t c_mcast_cipher = 0; + uint8_t c_auth_suites = 0, i; + uint8_t unicast[CSR_WAPI_OUI_SIZE]; + uint8_t multicast[CSR_WAPI_OUI_SIZE]; + uint8_t authsuites[CSR_WAPI_MAX_AUTH_SUITES][CSR_WAPI_OUI_SIZE]; + uint8_t authentication[CSR_WAPI_OUI_SIZE]; + uint8_t mccipher_arr[CSR_WAPI_MAX_MULTICAST_CYPHERS][CSR_WAPI_OUI_SIZE]; + eCsrAuthType neg_authtype = eCSR_AUTH_TYPE_UNKNOWN; + uint8_t wapioui_idx = 0; + + if (!wapi_ie->present) + goto end; + + c_mcast_cipher++; + qdf_mem_copy(mccipher_arr, wapi_ie->multicast_cipher_suite, + CSR_WAPI_OUI_SIZE); + c_ucast_cipher = (uint8_t) (wapi_ie->unicast_cipher_suite_count); + c_auth_suites = (uint8_t) (wapi_ie->akm_suite_count); + for (i = 0; i < c_auth_suites && i < CSR_WAPI_MAX_AUTH_SUITES; i++) + qdf_mem_copy((void *)&authsuites[i], + (void *)&wapi_ie->akm_suites[i], CSR_WAPI_OUI_SIZE); + + wapioui_idx = csr_get_oui_index_from_cipher(encr_type); + if (wapioui_idx >= CSR_OUI_WAPI_WAI_MAX_INDEX) { + sms_log(mac_ctx, LOGE, + FL("Wapi OUI index = %d out of limit"), + wapioui_idx); + acceptable_cipher = false; + goto end; + } + /* Check - Is requested unicast Cipher supported by the BSS. */ + acceptable_cipher = csr_match_wapi_oui_index(mac_ctx, + wapi_ie->unicast_cipher_suites, + c_ucast_cipher, wapioui_idx, unicast); + if (!acceptable_cipher) + goto end; + + /* unicast is supported. Pick the first matching Group cipher, if any */ + for (i = 0; i < mc_encryption->numEntries; i++) { + wapioui_idx = csr_get_oui_index_from_cipher( + mc_encryption->encryptionType[i]); + if (wapioui_idx >= CSR_OUI_WAPI_WAI_MAX_INDEX) { + sms_log(mac_ctx, LOGE, + FL("Wapi OUI index = %d out of limit"), + wapioui_idx); + acceptable_cipher = false; + break; + } + acceptable_cipher = csr_match_wapi_oui_index(mac_ctx, + mccipher_arr, c_mcast_cipher, + wapioui_idx, multicast); + if (acceptable_cipher) + break; + } + if (!acceptable_cipher) + goto end; + + if (negotiated_mccipher) + *negotiated_mccipher = + mc_encryption->encryptionType[i]; + + /* + * Ciphers are supported, Match authentication algorithm and + * pick first matching authtype + */ + if (csr_is_auth_wapi_cert + (mac_ctx, authsuites, c_auth_suites, authentication)) { + neg_authtype = + eCSR_AUTH_TYPE_WAPI_WAI_CERTIFICATE; + } else if (csr_is_auth_wapi_psk(mac_ctx, authsuites, + c_auth_suites, authentication)) { + neg_authtype = eCSR_AUTH_TYPE_WAPI_WAI_PSK; + } else { + acceptable_cipher = false; + neg_authtype = eCSR_AUTH_TYPE_UNKNOWN; + } + + /* Caller doesn't care about auth type, or BSS doesn't match */ + if ((0 == auth_type->numEntries) || (false == acceptable_cipher)) + goto end; + + acceptable_cipher = false; + for (i = 0; i < auth_type->numEntries; i++) { + if (auth_type->authType[i] == neg_authtype) { + acceptable_cipher = true; + break; + } + } + +end: + if (acceptable_cipher) { + if (mcast_cipher) + qdf_mem_copy(mcast_cipher, multicast, + CSR_WAPI_OUI_SIZE); + if (ucast_cipher) + qdf_mem_copy(ucast_cipher, unicast, CSR_WAPI_OUI_SIZE); + if (auth_suite) + qdf_mem_copy(auth_suite, authentication, + CSR_WAPI_OUI_SIZE); + if (negotiated_authtype) + *negotiated_authtype = neg_authtype; + } + return acceptable_cipher; +} + +static bool csr_is_wapi_match(tHalHandle hHal, tCsrAuthList *pAuthType, + eCsrEncryptionType enType, + tCsrEncryptionList *pEnMcType, + tDot11fBeaconIEs *pIes, + eCsrAuthType *pNegotiatedAuthType, + eCsrEncryptionType *pNegotiatedMCCipher) +{ + bool fWapiMatch = false; + + /* See if the cyphers in the Bss description match with the settings in the profile. */ + fWapiMatch = + csr_get_wapi_information(hHal, pAuthType, enType, pEnMcType, + &pIes->WAPI, NULL, NULL, NULL, + pNegotiatedAuthType, + pNegotiatedMCCipher); + + return fWapiMatch; +} + +static bool csr_lookup_bkid(tpAniSirGlobal pMac, uint32_t sessionId, + uint8_t *pBSSId, uint8_t *pBKId) +{ + bool fRC = false, fMatchFound = false; + uint32_t Index; + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + + if (!pSession) { + sms_log(pMac, LOGE, FL(" session %d not found "), sessionId); + return false; + } + + do { + for (Index = 0; Index < pSession->NumBkidCache; Index++) { + sms_log(pMac, LOGW, "match BKID " MAC_ADDRESS_STR " to ", + MAC_ADDR_ARRAY(pBSSId)); + if (!qdf_mem_cmp + (pBSSId, pSession->BkidCacheInfo[Index].BSSID.bytes, + sizeof(struct qdf_mac_addr))) { + /* match found */ + fMatchFound = true; + break; + } + } + + if (!fMatchFound) + break; + + qdf_mem_copy(pBKId, pSession->BkidCacheInfo[Index].BKID, + CSR_WAPI_BKID_SIZE); + + fRC = true; + } while (0); + sms_log(pMac, LOGW, + "csr_lookup_bkid called return match = %d pMac->roam.NumBkidCache = %d", + fRC, pSession->NumBkidCache); + + return fRC; +} + +uint8_t csr_construct_wapi_ie(tpAniSirGlobal pMac, uint32_t sessionId, + tCsrRoamProfile *pProfile, + tSirBssDescription *pSirBssDesc, + tDot11fBeaconIEs *pIes, tCsrWapiIe *pWapiIe) +{ + bool fWapiMatch = false; + uint8_t cbWapiIe = 0; + uint8_t UnicastCypher[CSR_WAPI_OUI_SIZE]; + uint8_t MulticastCypher[CSR_WAPI_OUI_SIZE]; + uint8_t AuthSuite[CSR_WAPI_OUI_SIZE]; + uint8_t BKId[CSR_WAPI_BKID_SIZE]; + uint8_t *pWapi = NULL; + bool fBKIDFound = false; + tDot11fBeaconIEs *pIesLocal = pIes; + + do { + if (!csr_is_profile_wapi(pProfile)) + break; + + if (!pIesLocal + && + (!QDF_IS_STATUS_SUCCESS + (csr_get_parsed_bss_description_ies + (pMac, pSirBssDesc, &pIesLocal)))) { + break; + } + /* See if the cyphers in the Bss description match with the settings in the profile. */ + fWapiMatch = + csr_get_wapi_information(pMac, &pProfile->AuthType, + pProfile->negotiatedUCEncryptionType, + &pProfile->mcEncryptionType, + &pIesLocal->WAPI, UnicastCypher, + MulticastCypher, AuthSuite, NULL, + NULL); + if (!fWapiMatch) + break; + + qdf_mem_set(pWapiIe, sizeof(tCsrWapiIe), 0); + + pWapiIe->IeHeader.ElementID = DOT11F_EID_WAPI; + + pWapiIe->Version = CSR_WAPI_VERSION_SUPPORTED; + + pWapiIe->cAuthenticationSuites = 1; + qdf_mem_copy(&pWapiIe->AuthOui[0], AuthSuite, + sizeof(AuthSuite)); + + pWapi = (uint8_t *) (&pWapiIe->AuthOui[1]); + + *pWapi = (uint16_t) 1; /* cUnicastCyphers */ + pWapi += 2; + qdf_mem_copy(pWapi, UnicastCypher, sizeof(UnicastCypher)); + pWapi += sizeof(UnicastCypher); + + qdf_mem_copy(pWapi, MulticastCypher, sizeof(MulticastCypher)); + pWapi += sizeof(MulticastCypher); + + /* WAPI capabilities follows the Auth Suite (two octects) */ + /* we shouldn't EVER be sending out "pre-auth supported". It is an AP only capability */ + /* & since we already did a memset pWapiIe to 0, skip these fields */ + pWapi += 2; + + fBKIDFound = + csr_lookup_bkid(pMac, sessionId, pSirBssDesc->bssId, + &(BKId[0])); + + if (fBKIDFound) { + /* Do we need to change the endianness here */ + *pWapi = (uint16_t) 1; /* cBKIDs */ + pWapi += 2; + qdf_mem_copy(pWapi, BKId, CSR_WAPI_BKID_SIZE); + } else { + *pWapi = 0; + pWapi += 1; + *pWapi = 0; + pWapi += 1; + } + + /* Add in the IE fields except the IE header */ + /* Add BKID count and BKID (if any) */ + pWapiIe->IeHeader.Length = + (uint8_t) (sizeof(*pWapiIe) - sizeof(pWapiIe->IeHeader)); + + /*2 bytes for BKID Count field */ + pWapiIe->IeHeader.Length += sizeof(uint16_t); + + if (fBKIDFound) { + pWapiIe->IeHeader.Length += CSR_WAPI_BKID_SIZE; + } + /* return the size of the IE header (total) constructed... */ + cbWapiIe = pWapiIe->IeHeader.Length + sizeof(pWapiIe->IeHeader); + + } while (0); + + if (!pIes && pIesLocal) { + /* locally allocated */ + qdf_mem_free(pIesLocal); + } + + return cbWapiIe; +} +#endif /* FEATURE_WLAN_WAPI */ + +/** + * csr_get_wpa_cyphers() - to get WPA cipher info + * @mac_ctx: pointer to mac context + * @auth_type: auth type + * @encr_type: encryption type + * @mc_encryption: multicast encryption type + * @wpa_ie: pointer to WPA IE + * @ucast_cipher: Unicast cipher + * @mcast_cipher: Multicast cipher + * @auth_suite: Authentication suite + * @negotiated_authtype: Negotiated auth type + * @negotiated_mccipher: negotiated multicast cipher + * + * This routine will get all WPA information + * + * Return: bool + */ +static bool csr_get_wpa_cyphers(tpAniSirGlobal mac_ctx, tCsrAuthList *auth_type, + eCsrEncryptionType encr_type, + tCsrEncryptionList *mc_encryption, + tDot11fIEWPA *wpa_ie, uint8_t *ucast_cipher, + uint8_t *mcast_cipher, uint8_t *auth_suite, + eCsrAuthType *negotiated_authtype, + eCsrEncryptionType *negotiated_mccipher) +{ + bool acceptable_cipher = false; + uint8_t c_ucast_cipher = 0; + uint8_t c_mcast_cipher = 0; + uint8_t c_auth_suites = 0; + uint8_t unicast[CSR_WPA_OUI_SIZE]; + uint8_t multicast[CSR_WPA_OUI_SIZE]; + uint8_t authentication[CSR_WPA_OUI_SIZE]; + uint8_t mccipher_arr[1][CSR_WPA_OUI_SIZE]; + uint8_t i; + eCsrAuthType neg_authtype = eCSR_AUTH_TYPE_UNKNOWN; + + if (!wpa_ie->present) + goto end; + c_mcast_cipher = 1; + qdf_mem_copy(mccipher_arr, wpa_ie->multicast_cipher, CSR_WPA_OUI_SIZE); + c_ucast_cipher = (uint8_t) (wpa_ie->unicast_cipher_count); + c_auth_suites = (uint8_t) (wpa_ie->auth_suite_count); + + /* Check - Is requested unicast Cipher supported by the BSS. */ + acceptable_cipher = csr_match_wpaoui_index(mac_ctx, + wpa_ie->unicast_ciphers, c_ucast_cipher, + csr_get_oui_index_from_cipher(encr_type), + unicast); + if (!acceptable_cipher) + goto end; + /* unicast is supported. Pick the first matching Group cipher, if any */ + for (i = 0; i < mc_encryption->numEntries; i++) { + acceptable_cipher = csr_match_wpaoui_index(mac_ctx, + mccipher_arr, c_mcast_cipher, + csr_get_oui_index_from_cipher( + mc_encryption->encryptionType[i]), + multicast); + if (acceptable_cipher) + break; + } + if (!acceptable_cipher) + goto end; + + if (negotiated_mccipher) + *negotiated_mccipher = mc_encryption->encryptionType[i]; + + /* Initializing with false as it has true value already */ + acceptable_cipher = false; + for (i = 0; i < auth_type->numEntries; i++) { + /* + * Ciphers are supported, Match authentication algorithm and + * pick first matching authtype + */ + if (csr_is_auth_wpa(mac_ctx, wpa_ie->auth_suites, c_auth_suites, + authentication)) { + if (eCSR_AUTH_TYPE_WPA == auth_type->authType[i]) + neg_authtype = eCSR_AUTH_TYPE_WPA; + } + if ((neg_authtype == eCSR_AUTH_TYPE_UNKNOWN) && + csr_is_auth_wpa_psk(mac_ctx, + wpa_ie->auth_suites, c_auth_suites, + authentication)) { + if (eCSR_AUTH_TYPE_WPA_PSK == auth_type->authType[i]) + neg_authtype = eCSR_AUTH_TYPE_WPA_PSK; + } +#ifdef FEATURE_WLAN_ESE + if ((neg_authtype == eCSR_AUTH_TYPE_UNKNOWN) + && csr_is_ese_cckm_auth_wpa(mac_ctx, + wpa_ie->auth_suites, c_auth_suites, + authentication)) { + if (eCSR_AUTH_TYPE_CCKM_WPA == auth_type->authType[i]) + neg_authtype = eCSR_AUTH_TYPE_CCKM_WPA; + } +#endif /* FEATURE_WLAN_ESE */ + + /* + * The 1st auth type in the APs WPA IE, to match stations + * connecting profiles auth type will cause us to exit this + * loop. This is added as some APs advertise multiple akms in + * the WPA IE + */ + if (eCSR_AUTH_TYPE_UNKNOWN != neg_authtype) { + acceptable_cipher = true; + break; + } + } + +end: + if (acceptable_cipher) { + if (mcast_cipher) + qdf_mem_copy((uint8_t **) mcast_cipher, multicast, + CSR_WPA_OUI_SIZE); + + if (ucast_cipher) + qdf_mem_copy((uint8_t **) ucast_cipher, unicast, + CSR_WPA_OUI_SIZE); + + if (auth_suite) + qdf_mem_copy((uint8_t **) auth_suite, authentication, + CSR_WPA_OUI_SIZE); + + if (negotiated_authtype) + *negotiated_authtype = neg_authtype; + } + + return acceptable_cipher; +} + +static bool csr_is_wpa_encryption_match(tpAniSirGlobal pMac, + tCsrAuthList *pAuthType, + eCsrEncryptionType enType, + tCsrEncryptionList *pEnMcType, + tDot11fBeaconIEs *pIes, + eCsrAuthType *pNegotiatedAuthtype, + eCsrEncryptionType *pNegotiatedMCCipher) +{ + bool fWpaMatch = false; + + /* See if the cyphers in the Bss description match with the settings in the profile. */ + fWpaMatch = + csr_get_wpa_cyphers(pMac, pAuthType, enType, pEnMcType, &pIes->WPA, + NULL, NULL, NULL, pNegotiatedAuthtype, + pNegotiatedMCCipher); + + return fWpaMatch; +} + +uint8_t csr_construct_wpa_ie(tHalHandle hHal, tCsrRoamProfile *pProfile, + tSirBssDescription *pSirBssDesc, + tDot11fBeaconIEs *pIes, tCsrWpaIe *pWpaIe) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + bool fWpaMatch; + uint8_t cbWpaIe = 0; + uint8_t UnicastCypher[CSR_WPA_OUI_SIZE]; + uint8_t MulticastCypher[CSR_WPA_OUI_SIZE]; + uint8_t AuthSuite[CSR_WPA_OUI_SIZE]; + tCsrWpaAuthIe *pAuthSuite; + tDot11fBeaconIEs *pIesLocal = pIes; + + do { + if (!csr_is_profile_wpa(pProfile)) + break; + + if (!pIesLocal + && + (!QDF_IS_STATUS_SUCCESS + (csr_get_parsed_bss_description_ies + (pMac, pSirBssDesc, &pIesLocal)))) { + break; + } + /* See if the cyphers in the Bss description match with the settings in the profile. */ + fWpaMatch = + csr_get_wpa_cyphers(hHal, &pProfile->AuthType, + pProfile->negotiatedUCEncryptionType, + &pProfile->mcEncryptionType, + &pIesLocal->WPA, UnicastCypher, + MulticastCypher, AuthSuite, NULL, NULL); + if (!fWpaMatch) + break; + + pWpaIe->IeHeader.ElementID = SIR_MAC_WPA_EID; + + qdf_mem_copy(pWpaIe->Oui, csr_wpa_oui[01], sizeof(pWpaIe->Oui)); + + pWpaIe->Version = CSR_WPA_VERSION_SUPPORTED; + + qdf_mem_copy(pWpaIe->MulticastOui, MulticastCypher, + sizeof(MulticastCypher)); + + pWpaIe->cUnicastCyphers = 1; + + qdf_mem_copy(&pWpaIe->UnicastOui[0], UnicastCypher, + sizeof(UnicastCypher)); + + pAuthSuite = + (tCsrWpaAuthIe *) (&pWpaIe-> + UnicastOui[pWpaIe->cUnicastCyphers]); + + pAuthSuite->cAuthenticationSuites = 1; + qdf_mem_copy(&pAuthSuite->AuthOui[0], AuthSuite, + sizeof(AuthSuite)); + + /* The WPA capabilities follows the Auth Suite (two octects)-- */ + /* this field is optional, and we always "send" zero, so just */ + /* remove it. This is consistent with our assumptions in the */ + /* frames compiler; c.f. bug 15234: */ + /* http://gold.woodsidenet.com/bugzilla/show_bug.cgi?id=15234 */ + + /* Add in the fixed fields plus 1 Unicast cypher, less the IE Header length */ + /* Add in the size of the Auth suite (count plus a single OUI) */ + pWpaIe->IeHeader.Length = + sizeof(*pWpaIe) - sizeof(pWpaIe->IeHeader) + + sizeof(*pAuthSuite); + + /* return the size of the IE header (total) constructed... */ + cbWpaIe = pWpaIe->IeHeader.Length + sizeof(pWpaIe->IeHeader); + + } while (0); + + if (!pIes && pIesLocal) { + /* locally allocated */ + qdf_mem_free(pIesLocal); + } + + return cbWpaIe; +} + +/* If a WPAIE exists in the profile, just use it. Or else construct one from the BSS */ +/* Caller allocated memory for pWpaIe and guarrantee it can contain a max length WPA IE */ +uint8_t csr_retrieve_wpa_ie(tHalHandle hHal, tCsrRoamProfile *pProfile, + tSirBssDescription *pSirBssDesc, + tDot11fBeaconIEs *pIes, tCsrWpaIe *pWpaIe) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + uint8_t cbWpaIe = 0; + + do { + if (!csr_is_profile_wpa(pProfile)) + break; + if (pProfile->nWPAReqIELength && pProfile->pWPAReqIE) { + if (pProfile->nWPAReqIELength <= + DOT11F_IE_RSN_MAX_LEN) { + cbWpaIe = (uint8_t) pProfile->nWPAReqIELength; + qdf_mem_copy(pWpaIe, pProfile->pWPAReqIE, + cbWpaIe); + } else { + sms_log(pMac, LOGW, + " csr_retrieve_wpa_ie detect invalid WPA IE length (%d) ", + pProfile->nWPAReqIELength); + } + } else { + cbWpaIe = + csr_construct_wpa_ie(pMac, pProfile, pSirBssDesc, pIes, + pWpaIe); + } + } while (0); + + return cbWpaIe; +} + +/* If a RSNIE exists in the profile, just use it. Or else construct one from the BSS */ +/* Caller allocated memory for pWpaIe and guarrantee it can contain a max length WPA IE */ +uint8_t csr_retrieve_rsn_ie(tHalHandle hHal, uint32_t sessionId, + tCsrRoamProfile *pProfile, + tSirBssDescription *pSirBssDesc, + tDot11fBeaconIEs *pIes, tCsrRSNIe *pRsnIe) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + uint8_t cbRsnIe = 0; + + do { + if (!csr_is_profile_rsn(pProfile)) + break; + if (csr_roam_is_fast_roam_enabled(pMac, sessionId)) { + /* If "Legacy Fast Roaming" is enabled ALWAYS rebuild the RSN IE from */ + /* scratch. So it contains the current PMK-IDs */ + cbRsnIe = + csr_construct_rsn_ie(pMac, sessionId, pProfile, + pSirBssDesc, pIes, pRsnIe); + } else if (pProfile->nRSNReqIELength && pProfile->pRSNReqIE) { + /* If you have one started away, re-use it. */ + if (pProfile->nRSNReqIELength <= + DOT11F_IE_RSN_MAX_LEN) { + cbRsnIe = (uint8_t) pProfile->nRSNReqIELength; + qdf_mem_copy(pRsnIe, pProfile->pRSNReqIE, + cbRsnIe); + } else { + sms_log(pMac, LOGW, + " csr_retrieve_rsn_ie detect invalid RSN IE length (%d) ", + pProfile->nRSNReqIELength); + } + } else { + cbRsnIe = + csr_construct_rsn_ie(pMac, sessionId, pProfile, + pSirBssDesc, pIes, pRsnIe); + } + } while (0); + + return cbRsnIe; +} + +#ifdef FEATURE_WLAN_WAPI +/* If a WAPI IE exists in the profile, just use it. Or else construct one from the BSS */ +/* Caller allocated memory for pWapiIe and guarrantee it can contain a max length WAPI IE */ +uint8_t csr_retrieve_wapi_ie(tHalHandle hHal, uint32_t sessionId, + tCsrRoamProfile *pProfile, + tSirBssDescription *pSirBssDesc, + tDot11fBeaconIEs *pIes, tCsrWapiIe *pWapiIe) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + uint8_t cbWapiIe = 0; + + do { + if (!csr_is_profile_wapi(pProfile)) + break; + if (pProfile->nWAPIReqIELength && pProfile->pWAPIReqIE) { + if (DOT11F_IE_WAPI_MAX_LEN >= + pProfile->nWAPIReqIELength) { + cbWapiIe = (uint8_t) pProfile->nWAPIReqIELength; + qdf_mem_copy(pWapiIe, pProfile->pWAPIReqIE, + cbWapiIe); + } else { + sms_log(pMac, LOGW, + " csr_retrieve_wapi_ie detect invalid WAPI IE length (%d) ", + pProfile->nWAPIReqIELength); + } + } else { + cbWapiIe = + csr_construct_wapi_ie(pMac, sessionId, pProfile, + pSirBssDesc, pIes, pWapiIe); + } + } while (0); + + return cbWapiIe; +} +#endif /* FEATURE_WLAN_WAPI */ + +bool csr_rates_is_dot11_rate11b_supported_rate(uint8_t dot11Rate) +{ + bool fSupported = false; + uint16_t nonBasicRate = + (uint16_t) (BITS_OFF(dot11Rate, CSR_DOT11_BASIC_RATE_MASK)); + + switch (nonBasicRate) { + case eCsrSuppRate_1Mbps: + case eCsrSuppRate_2Mbps: + case eCsrSuppRate_5_5Mbps: + case eCsrSuppRate_11Mbps: + fSupported = true; + break; + + default: + break; + } + + return fSupported; +} + +bool csr_rates_is_dot11_rate11a_supported_rate(uint8_t dot11Rate) +{ + bool fSupported = false; + uint16_t nonBasicRate = + (uint16_t) (BITS_OFF(dot11Rate, CSR_DOT11_BASIC_RATE_MASK)); + + switch (nonBasicRate) { + case eCsrSuppRate_6Mbps: + case eCsrSuppRate_9Mbps: + case eCsrSuppRate_12Mbps: + case eCsrSuppRate_18Mbps: + case eCsrSuppRate_24Mbps: + case eCsrSuppRate_36Mbps: + case eCsrSuppRate_48Mbps: + case eCsrSuppRate_54Mbps: + fSupported = true; + break; + + default: + break; + } + + return fSupported; +} + +tAniEdType csr_translate_encrypt_type_to_ed_type(eCsrEncryptionType EncryptType) +{ + tAniEdType edType; + + switch (EncryptType) { + default: + case eCSR_ENCRYPT_TYPE_NONE: + edType = eSIR_ED_NONE; + break; + + case eCSR_ENCRYPT_TYPE_WEP40_STATICKEY: + case eCSR_ENCRYPT_TYPE_WEP40: + edType = eSIR_ED_WEP40; + break; + + case eCSR_ENCRYPT_TYPE_WEP104_STATICKEY: + case eCSR_ENCRYPT_TYPE_WEP104: + edType = eSIR_ED_WEP104; + break; + + case eCSR_ENCRYPT_TYPE_TKIP: + edType = eSIR_ED_TKIP; + break; + + case eCSR_ENCRYPT_TYPE_AES: + edType = eSIR_ED_CCMP; + break; +#ifdef FEATURE_WLAN_WAPI + case eCSR_ENCRYPT_TYPE_WPI: + edType = eSIR_ED_WPI; + break; +#endif +#ifdef WLAN_FEATURE_11W + /* 11w BIP */ + case eCSR_ENCRYPT_TYPE_AES_CMAC: + edType = eSIR_ED_AES_128_CMAC; + break; +#endif + } + + return edType; +} + +/** + * csr_validate_wep() - to validate wep + * @uc_encry_type: unicast encryption type + * @auth_list: Auth list + * @mc_encryption_list: multicast encryption type + * @negotiated_authtype: negotiated auth type + * @negotiated_mc_encry: negotiated mc encry type + * @bss_descr: BSS description + * @ie_ptr: IE pointer + * + * This function just checks whether HDD is giving correct values for + * Multicast cipher and Auth + * + * Return: bool + */ +static bool csr_validate_wep(tpAniSirGlobal mac_ctx, + eCsrEncryptionType uc_encry_type, + tCsrAuthList *auth_list, + tCsrEncryptionList *mc_encryption_list, + eCsrAuthType *negotiated_authtype, + eCsrEncryptionType *negotiated_mc_encry, + tSirBssDescription *bss_descr, + tDot11fBeaconIEs *ie_ptr) +{ + uint32_t idx; + bool match = false; + eCsrAuthType negotiated_auth = eCSR_AUTH_TYPE_OPEN_SYSTEM; + eCsrEncryptionType negotiated_mccipher = eCSR_ENCRYPT_TYPE_UNKNOWN; + + /* If privacy bit is not set, consider no match */ + if (!csr_is_privacy(bss_descr)) + goto end; + + for (idx = 0; idx < mc_encryption_list->numEntries; idx++) { + switch (mc_encryption_list->encryptionType[idx]) { + case eCSR_ENCRYPT_TYPE_WEP40_STATICKEY: + case eCSR_ENCRYPT_TYPE_WEP104_STATICKEY: + case eCSR_ENCRYPT_TYPE_WEP40: + case eCSR_ENCRYPT_TYPE_WEP104: + /* + * Multicast list may contain WEP40/WEP104. + * Check whether it matches UC. + */ + if (uc_encry_type == + mc_encryption_list->encryptionType[idx]) { + match = true; + negotiated_mccipher = + mc_encryption_list->encryptionType[idx]; + } + break; + default: + match = false; + break; + } + if (match) + break; + } + + if (!match) + goto end; + + for (idx = 0; idx < auth_list->numEntries; idx++) { + switch (auth_list->authType[idx]) { + case eCSR_AUTH_TYPE_OPEN_SYSTEM: + case eCSR_AUTH_TYPE_SHARED_KEY: + case eCSR_AUTH_TYPE_AUTOSWITCH: + match = true; + negotiated_auth = auth_list->authType[idx]; + break; + default: + match = false; + } + if (match) + break; + } + + if (!match) + goto end; + + if (!ie_ptr) + goto end; + + /* + * In case of WPA / WPA2, check whether it supports WEP as well. + * Prepare the encryption type for WPA/WPA2 functions + */ + if (eCSR_ENCRYPT_TYPE_WEP40_STATICKEY == uc_encry_type) + uc_encry_type = eCSR_ENCRYPT_TYPE_WEP40; + else if (eCSR_ENCRYPT_TYPE_WEP104 == uc_encry_type) + uc_encry_type = eCSR_ENCRYPT_TYPE_WEP104; + + /* else we can use the encryption type directly */ + if (ie_ptr->WPA.present) { + match = (!qdf_mem_cmp(ie_ptr->WPA.multicast_cipher, + csr_wpa_oui[csr_get_oui_index_from_cipher( + uc_encry_type)], + CSR_WPA_OUI_SIZE)); + if (match) + goto end; + } + if (ie_ptr->RSN.present) { + match = (!qdf_mem_cmp(ie_ptr->RSN.gp_cipher_suite, + csr_rsn_oui[csr_get_oui_index_from_cipher( + uc_encry_type)], + CSR_RSN_OUI_SIZE)); + } + + +end: + if (match) { + if (negotiated_authtype) + *negotiated_authtype = negotiated_auth; + if (negotiated_mc_encry) + *negotiated_mc_encry = negotiated_mccipher; + } + return match; +} + +/** + * csr_validate_open_none() - Check if the security is matching + * @bss_desc: BSS Descriptor on which the check is done + * @mc_enc_type: Multicast encryption type + * @mc_cipher: Multicast Cipher + * @auth_type: Authentication type + * @neg_auth_type: Negotiated Auth type with the AP + * + * Return: Boolean value to tell if matched or not. + */ +static bool csr_validate_open_none(tSirBssDescription *bss_desc, + tCsrEncryptionList *mc_enc_type, eCsrEncryptionType *mc_cipher, + tCsrAuthList *auth_type, eCsrAuthType *neg_auth_type) +{ + bool match; + uint8_t idx; + + /* + * for NO encryption, if the Bss description has the + * Privacy bit turned on, then encryption is required + * so we have to reject this Bss. + */ + if (csr_is_privacy(bss_desc)) + match = false; + else + match = true; + if (match) { + match = false; + /* Check MC cipher and Auth type requested. */ + for (idx = 0; idx < mc_enc_type->numEntries; idx++) { + if (eCSR_ENCRYPT_TYPE_NONE == + mc_enc_type->encryptionType[idx]) { + match = true; + *mc_cipher = mc_enc_type->encryptionType[idx]; + break; + } + } + if (!match) + return match; + + match = false; + /* Check Auth list. It should contain AuthOpen. */ + for (idx = 0; idx < auth_type->numEntries; idx++) { + if ((eCSR_AUTH_TYPE_OPEN_SYSTEM == + auth_type->authType[idx]) || + (eCSR_AUTH_TYPE_AUTOSWITCH == + auth_type->authType[idx])) { + match = true; + *neg_auth_type = + eCSR_AUTH_TYPE_OPEN_SYSTEM; + break; + } + } + if (!match) + return match; + + } + return match; +} + +/** + * csr_validate_any_default() - Check if the security is matching + * @hal: Global HAL handle + * @auth_type: Authentication type + * @mc_enc_type: Multicast encryption type + * @mfp_enabled: Management frame protection feature + * @mfp_required: Mangement frame protection mandatory + * @mfp_capable: Device capable of MFP + * @ies_ptr: Pointer to the IE fields + * @neg_auth_type: Negotiated Auth type with the AP + * @bss_desc: BSS Descriptor + * @neg_uc_cipher: Negotiated unicast cipher suite + * @neg_mc_cipher: Negotiated multicast cipher + * + * Return: Boolean value to tell if matched or not. + */ +static bool csr_validate_any_default(tHalHandle hal, tCsrAuthList *auth_type, + tCsrEncryptionList *mc_enc_type, bool *mfp_enabled, + uint8_t *mfp_required, uint8_t *mfp_capable, + tDot11fBeaconIEs *ies_ptr, eCsrAuthType *neg_auth_type, + tSirBssDescription *bss_desc, eCsrEncryptionType *uc_cipher, + eCsrEncryptionType *mc_cipher) +{ + bool match_any = false; + bool match = true; + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + /* It is allowed to match anything. Try the more secured ones first. */ + if (ies_ptr) { + /* Check AES first */ + *uc_cipher = eCSR_ENCRYPT_TYPE_AES; + match_any = csr_is_rsn_match(hal, auth_type, + *uc_cipher, mc_enc_type, mfp_enabled, + mfp_required, mfp_capable, ies_ptr, + neg_auth_type, mc_cipher); + if (!match_any) { + /* Check TKIP */ + *uc_cipher = eCSR_ENCRYPT_TYPE_TKIP; + match_any = csr_is_rsn_match(hal, auth_type, *uc_cipher, + mc_enc_type, mfp_enabled, mfp_required, + mfp_capable, ies_ptr, neg_auth_type, + mc_cipher); + } +#ifdef FEATURE_WLAN_WAPI + if (!match_any) { + /* Check WAPI */ + *uc_cipher = eCSR_ENCRYPT_TYPE_WPI; + match_any = csr_is_wapi_match(hal, auth_type, + *uc_cipher, mc_enc_type, ies_ptr, + neg_auth_type, mc_cipher); + } +#endif + } + if (match_any) + return match; + *uc_cipher = eCSR_ENCRYPT_TYPE_WEP104; + if (csr_validate_wep(mac_ctx, *uc_cipher, auth_type, mc_enc_type, + neg_auth_type, mc_cipher, bss_desc, ies_ptr)) + return match; + *uc_cipher = eCSR_ENCRYPT_TYPE_WEP40; + if (csr_validate_wep(mac_ctx, *uc_cipher, auth_type, mc_enc_type, + neg_auth_type, mc_cipher, bss_desc, ies_ptr)) + return match; + *uc_cipher = eCSR_ENCRYPT_TYPE_WEP104_STATICKEY; + if (csr_validate_wep(mac_ctx, *uc_cipher, auth_type, mc_enc_type, + neg_auth_type, mc_cipher, bss_desc, ies_ptr)) + return match; + *uc_cipher = eCSR_ENCRYPT_TYPE_WEP40_STATICKEY; + if (csr_validate_wep(mac_ctx, *uc_cipher, auth_type, mc_enc_type, + neg_auth_type, mc_cipher, bss_desc, ies_ptr)) + return match; + /* It must be open and no enc */ + if (csr_is_privacy(bss_desc)) { + match = false; + return match; + } + + *neg_auth_type = eCSR_AUTH_TYPE_OPEN_SYSTEM; + *mc_cipher = eCSR_ENCRYPT_TYPE_NONE; + *uc_cipher = eCSR_ENCRYPT_TYPE_NONE; + return match; + +} + +/** + * csr_is_security_match() - Check if the security is matching + * @hal: Global HAL handle + * @auth_type: Authentication type + * @uc_enc_type: Unicast Encryption type + * @mc_enc_type: Multicast encryption type + * @mfp_enabled: Management frame protection feature + * @mfp_required: Mangement frame protection mandatory + * @mfp_capable: Device capable of MFP + * @bss_desc: BSS Descriptor + * @ies_ptr: Pointer to the IE fields + * @neg_auth_type: Negotiated Auth type with the AP + * @neg_uc_cipher: Negotiated unicast cipher suite + * @neg_mc_cipher: Negotiated multicast cipher + * + * Return: Boolean value to tell if matched or not. + */ +bool csr_is_security_match(tHalHandle hal, tCsrAuthList *auth_type, + tCsrEncryptionList *uc_enc_type, + tCsrEncryptionList *mc_enc_type, bool *mfp_enabled, + uint8_t *mfp_required, uint8_t *mfp_capable, + tSirBssDescription *bss_desc, tDot11fBeaconIEs *ies_ptr, + eCsrAuthType *neg_auth_type, + eCsrEncryptionType *neg_uc_cipher, + eCsrEncryptionType *neg_mc_cipher) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + bool match = false; + uint8_t i; + eCsrEncryptionType mc_cipher = eCSR_ENCRYPT_TYPE_UNKNOWN; + eCsrEncryptionType uc_cipher = eCSR_ENCRYPT_TYPE_UNKNOWN; + eCsrAuthType local_neg_auth_type = eCSR_AUTH_TYPE_UNKNOWN; + + for (i = 0; ((i < uc_enc_type->numEntries) && (!match)); i++) { + uc_cipher = uc_enc_type->encryptionType[i]; + /* + * If the Bss description shows the Privacy bit is on, then we + * must have some sort of encryption configured for the profile + * to work. Don't attempt to join networks with Privacy bit + * set when profiles say NONE for encryption type. + */ + switch (uc_cipher) { + case eCSR_ENCRYPT_TYPE_NONE: + match = csr_validate_open_none(bss_desc, mc_enc_type, + &mc_cipher, auth_type, + &local_neg_auth_type); + break; + + case eCSR_ENCRYPT_TYPE_WEP40_STATICKEY: + case eCSR_ENCRYPT_TYPE_WEP104_STATICKEY: + /* + * !! might want to check for WEP keys set in the + * Profile.... ? !! don't need to have the privacy bit + * in the Bss description. Many AP policies make + * legacy encryption 'optional' so we don't know if we + * can associate or not. The AP will reject if + * encryption is not allowed without the Privacy bit + * turned on. + */ + match = csr_validate_wep(mac_ctx, uc_cipher, auth_type, + mc_enc_type, &local_neg_auth_type, + &mc_cipher, bss_desc, ies_ptr); + + break; + /* these are all of the WPA encryption types... */ + case eCSR_ENCRYPT_TYPE_WEP40: + case eCSR_ENCRYPT_TYPE_WEP104: + match = csr_validate_wep(mac_ctx, uc_cipher, auth_type, + mc_enc_type, &local_neg_auth_type, + &mc_cipher, bss_desc, ies_ptr); + break; + + case eCSR_ENCRYPT_TYPE_TKIP: + case eCSR_ENCRYPT_TYPE_AES: + if (!ies_ptr) { + match = false; + break; + } + /* First check if there is a RSN match */ + match = csr_is_rsn_match(mac_ctx, auth_type, + uc_cipher, mc_enc_type, + mfp_enabled, mfp_required, + mfp_capable, ies_ptr, + &local_neg_auth_type, + &mc_cipher); + /* If not RSN, then check WPA match */ + if (!match) + match = csr_is_wpa_encryption_match( + mac_ctx, auth_type, + uc_cipher, mc_enc_type, + ies_ptr, + &local_neg_auth_type, + &mc_cipher); + break; +#ifdef FEATURE_WLAN_WAPI + case eCSR_ENCRYPT_TYPE_WPI: /* WAPI */ + if (ies_ptr) + match = csr_is_wapi_match(hal, auth_type, + uc_cipher, mc_enc_type, ies_ptr, + &local_neg_auth_type, + &mc_cipher); + else + match = false; + break; +#endif /* FEATURE_WLAN_WAPI */ + case eCSR_ENCRYPT_TYPE_ANY: + default: + match = csr_validate_any_default(hal, auth_type, + mc_enc_type, mfp_enabled, mfp_required, + mfp_capable, ies_ptr, + &local_neg_auth_type, bss_desc, + &uc_cipher, &mc_cipher); + break; + } + + } + + if (match) { + if (neg_uc_cipher) + *neg_uc_cipher = uc_cipher; + if (neg_mc_cipher) + *neg_mc_cipher = mc_cipher; + if (neg_auth_type) + *neg_auth_type = local_neg_auth_type; + } + return match; +} + +bool csr_is_ssid_match(tpAniSirGlobal pMac, uint8_t *ssid1, uint8_t ssid1Len, + uint8_t *bssSsid, uint8_t bssSsidLen, bool fSsidRequired) +{ + bool fMatch = false; + + do { + /* + * Check for the specification of the Broadcast SSID at the + * beginning of the list. If specified, then all SSIDs are + * matches (broadcast SSID means accept all SSIDs). + */ + if (ssid1Len == 0) { + fMatch = true; + break; + } + + /* There are a few special cases. If the Bss description has a Broadcast SSID, */ + /* then our Profile must have a single SSID without Wildcards so we can program */ + /* the SSID. */ + /* SSID could be suppressed in beacons. In that case SSID IE has valid length */ + /* but the SSID value is all NULL characters. That condition is trated same */ + /* as NULL SSID */ + if (csr_is_nullssid(bssSsid, bssSsidLen)) { + if (false == fSsidRequired) { + fMatch = true; + break; + } + } + + if (ssid1Len != bssSsidLen) + break; + if (!qdf_mem_cmp(bssSsid, ssid1, bssSsidLen)) { + fMatch = true; + break; + } + + } while (0); + + return fMatch; +} + +/* Null ssid means match */ +bool csr_is_ssid_in_list(tHalHandle hHal, tSirMacSSid *pSsid, + tCsrSSIDs *pSsidList) +{ + bool fMatch = false; + uint32_t i; + + if (pSsidList && pSsid) { + for (i = 0; i < pSsidList->numOfSSIDs; i++) { + if (csr_is_nullssid + (pSsidList->SSIDList[i].SSID.ssId, + pSsidList->SSIDList[i].SSID.length) + || + ((pSsidList->SSIDList[i].SSID.length == + pSsid->length) + && (!qdf_mem_cmp(pSsid->ssId, + pSsidList->SSIDList[i].SSID. + ssId, pSsid->length)))) { + fMatch = true; + break; + } + } + } + + return fMatch; +} + +bool csr_is_bssid_match(tHalHandle hHal, struct qdf_mac_addr *pProfBssid, + struct qdf_mac_addr *BssBssid) +{ + bool fMatch = false; + struct qdf_mac_addr ProfileBssid; + + /* for efficiency of the MAC_ADDRESS functions, move the */ + /* Bssid's into MAC_ADDRESS structs. */ + qdf_mem_copy(&ProfileBssid, pProfBssid, sizeof(struct qdf_mac_addr)); + + do { + + /* Give the profile the benefit of the doubt... accept either all 0 or */ + /* the real broadcast Bssid (all 0xff) as broadcast Bssids (meaning to */ + /* match any Bssids). */ + if (qdf_is_macaddr_zero(&ProfileBssid) || + qdf_is_macaddr_broadcast(&ProfileBssid)) { + fMatch = true; + break; + } + + if (qdf_is_macaddr_equal(BssBssid, &ProfileBssid)) { + fMatch = true; + break; + } + + } while (0); + + return fMatch; +} + +bool csr_is_bss_type_match(eCsrRoamBssType bssType1, eCsrRoamBssType bssType2) +{ + if ((eCSR_BSS_TYPE_ANY != bssType1 && eCSR_BSS_TYPE_ANY != bssType2) + && (bssType1 != bssType2)) + return false; + else + return true; +} + +bool csr_is_bss_type_ibss(eCsrRoamBssType bssType) +{ + return (bool) + (eCSR_BSS_TYPE_START_IBSS == bssType + || eCSR_BSS_TYPE_IBSS == bssType); +} + + +static bool csr_is_bss_type_caps_match(eCsrRoamBssType bssType, + tSirBssDescription *pSirBssDesc) +{ + bool fMatch = true; + + do { + switch (bssType) { + case eCSR_BSS_TYPE_ANY: + break; + + case eCSR_BSS_TYPE_INFRASTRUCTURE: + if (!csr_is_infra_bss_desc(pSirBssDesc)) + fMatch = false; + break; + + case eCSR_BSS_TYPE_IBSS: + case eCSR_BSS_TYPE_START_IBSS: + if (!csr_is_ibss_bss_desc(pSirBssDesc)) + fMatch = false; + + break; + default: + fMatch = false; + break; + } + } while (0); + + return fMatch; +} + +static bool csr_is_capabilities_match(tpAniSirGlobal pMac, eCsrRoamBssType bssType, + tSirBssDescription *pSirBssDesc) +{ + return csr_is_bss_type_caps_match(bssType, pSirBssDesc); +} + +static bool csr_is_specific_channel_match(tpAniSirGlobal pMac, + tSirBssDescription *pSirBssDesc, + uint8_t Channel) +{ + bool fMatch = true; + + do { + /* if the channel is ANY, then always match... */ + if (eCSR_OPERATING_CHANNEL_ANY == Channel) + break; + if (Channel == pSirBssDesc->channelId) + break; + + /* didn't match anything.. so return NO match */ + fMatch = false; + + } while (0); + + return fMatch; +} + +static bool csr_is_channel_band_match(tpAniSirGlobal pMac, uint8_t channelId, + tSirBssDescription *pSirBssDesc) +{ + bool fMatch = true; + + do { + /* if the profile says Any channel AND the global settings says ANY channel, then we */ + /* always match... */ + if (eCSR_OPERATING_CHANNEL_ANY == channelId) + break; + + if (eCSR_OPERATING_CHANNEL_ANY != channelId) { + fMatch = + csr_is_specific_channel_match(pMac, pSirBssDesc, + channelId); + } + + } while (0); + + return fMatch; +} + +/** + * csr_is_aggregate_rate_supported() - to check if aggregate rate is supported + * @mac_ctx: pointer to mac context + * @rate: A rate in units of 500kbps + * + * + * The rate encoding is just as in 802.11 Information Elements, except + * that the high bit is \em not interpreted as indicating a Basic Rate, + * and proprietary rates are allowed, too. + * + * Note that if the adapter's dot11Mode is g, we don't restrict the + * rates. According to hwReadEepromParameters, this will happen when: + * ... the card is configured for ALL bands through the property + * page. If this occurs, and the card is not an ABG card ,then this + * code is setting the dot11Mode to assume the mode that the + * hardware can support. For example, if the card is an 11BG card + * and we are configured to support ALL bands, then we change the + * dot11Mode to 11g because ALL in this case is only what the + * hardware can support. + * + * Return: true if the adapter is currently capable of supporting this rate + */ + +static bool csr_is_aggregate_rate_supported(tpAniSirGlobal mac_ctx, + uint16_t rate) +{ + bool supported = false; + uint16_t idx, new_rate; + + /* In case basic rate flag is set */ + new_rate = BITS_OFF(rate, CSR_DOT11_BASIC_RATE_MASK); + if (eCSR_CFG_DOT11_MODE_11A == + mac_ctx->roam.configParam.uCfgDot11Mode) { + switch (new_rate) { + case eCsrSuppRate_6Mbps: + case eCsrSuppRate_9Mbps: + case eCsrSuppRate_12Mbps: + case eCsrSuppRate_18Mbps: + case eCsrSuppRate_24Mbps: + case eCsrSuppRate_36Mbps: + case eCsrSuppRate_48Mbps: + case eCsrSuppRate_54Mbps: + supported = true; + break; + default: + supported = false; + break; + } + + } else if (eCSR_CFG_DOT11_MODE_11B == + mac_ctx->roam.configParam.uCfgDot11Mode) { + switch (new_rate) { + case eCsrSuppRate_1Mbps: + case eCsrSuppRate_2Mbps: + case eCsrSuppRate_5_5Mbps: + case eCsrSuppRate_11Mbps: + supported = true; + break; + default: + supported = false; + break; + } + } else if (!mac_ctx->roam.configParam.ProprietaryRatesEnabled) { + + switch (new_rate) { + case eCsrSuppRate_1Mbps: + case eCsrSuppRate_2Mbps: + case eCsrSuppRate_5_5Mbps: + case eCsrSuppRate_6Mbps: + case eCsrSuppRate_9Mbps: + case eCsrSuppRate_11Mbps: + case eCsrSuppRate_12Mbps: + case eCsrSuppRate_18Mbps: + case eCsrSuppRate_24Mbps: + case eCsrSuppRate_36Mbps: + case eCsrSuppRate_48Mbps: + case eCsrSuppRate_54Mbps: + supported = true; + break; + default: + supported = false; + break; + } + } else if (eCsrSuppRate_1Mbps == new_rate || + eCsrSuppRate_2Mbps == new_rate || + eCsrSuppRate_5_5Mbps == new_rate || + eCsrSuppRate_11Mbps == new_rate) { + supported = true; + } else { + idx = 0x1; + + switch (new_rate) { + case eCsrSuppRate_6Mbps: + supported = g_phy_rates_suppt[0][idx]; + break; + case eCsrSuppRate_9Mbps: + supported = g_phy_rates_suppt[1][idx]; + break; + case eCsrSuppRate_12Mbps: + supported = g_phy_rates_suppt[2][idx]; + break; + case eCsrSuppRate_18Mbps: + supported = g_phy_rates_suppt[3][idx]; + break; + case eCsrSuppRate_20Mbps: + supported = g_phy_rates_suppt[4][idx]; + break; + case eCsrSuppRate_24Mbps: + supported = g_phy_rates_suppt[5][idx]; + break; + case eCsrSuppRate_36Mbps: + supported = g_phy_rates_suppt[6][idx]; + break; + case eCsrSuppRate_40Mbps: + supported = g_phy_rates_suppt[7][idx]; + break; + case eCsrSuppRate_42Mbps: + supported = g_phy_rates_suppt[8][idx]; + break; + case eCsrSuppRate_48Mbps: + supported = g_phy_rates_suppt[9][idx]; + break; + case eCsrSuppRate_54Mbps: + supported = g_phy_rates_suppt[10][idx]; + break; + case eCsrSuppRate_72Mbps: + supported = g_phy_rates_suppt[11][idx]; + break; + case eCsrSuppRate_80Mbps: + supported = g_phy_rates_suppt[12][idx]; + break; + case eCsrSuppRate_84Mbps: + supported = g_phy_rates_suppt[13][idx]; + break; + case eCsrSuppRate_96Mbps: + supported = g_phy_rates_suppt[14][idx]; + break; + case eCsrSuppRate_108Mbps: + supported = g_phy_rates_suppt[15][idx]; + break; + case eCsrSuppRate_120Mbps: + supported = g_phy_rates_suppt[16][idx]; + break; + case eCsrSuppRate_126Mbps: + supported = g_phy_rates_suppt[17][idx]; + break; + case eCsrSuppRate_144Mbps: + supported = g_phy_rates_suppt[18][idx]; + break; + case eCsrSuppRate_160Mbps: + supported = g_phy_rates_suppt[19][idx]; + break; + case eCsrSuppRate_168Mbps: + supported = g_phy_rates_suppt[20][idx]; + break; + case eCsrSuppRate_192Mbps: + supported = g_phy_rates_suppt[21][idx]; + break; + case eCsrSuppRate_216Mbps: + supported = g_phy_rates_suppt[22][idx]; + break; + case eCsrSuppRate_240Mbps: + supported = g_phy_rates_suppt[23][idx]; + break; + default: + supported = false; + break; + } + } + return supported; +} + +/** + * csr_is_rate_set_match() - to check if rate set is matching + * @mac_ctx: pointer to mac context + * @bss_supported_rates: supported rates of BSS + * @bss_ext_supp_rates: extended rates of bss + * + * This routine is to checke if rate set is matched or no + * + * Return: bool + */ +static bool csr_is_rate_set_match(tpAniSirGlobal mac_ctx, + tDot11fIESuppRates *bss_supported_rates, + tDot11fIEExtSuppRates *bss_ext_supp_rates) +{ + bool match = true; + uint32_t i; + + /* + * Validate that all of the Basic rates advertised in the Bss + * description are supported + */ + if (bss_supported_rates) { + for (i = 0; i < bss_supported_rates->num_rates; i++) { + if (!CSR_IS_BASIC_RATE(bss_supported_rates->rates[i])) + continue; + if (!csr_is_aggregate_rate_supported(mac_ctx, + bss_supported_rates->rates[i])) { + match = false; + break; + } + } + } + if (match && bss_ext_supp_rates) { + for (i = 0; i < bss_ext_supp_rates->num_rates; i++) { + if (!CSR_IS_BASIC_RATE(bss_ext_supp_rates->rates[i])) + continue; + if (!csr_is_aggregate_rate_supported(mac_ctx, + bss_ext_supp_rates->rates[i])) { + match = false; + break; + } + } + } + return match; +} + +/** + * csr_match_bss() - to compare the bss + * @hal: pointer to hal context + * @bss_descr: pointer bss description + * @filter: scan filter + * @neg_auth: negotiated auth + * @neg_uc: negotiated for unicast + * @neg_mc: negotiated for multicast + * @ie_dblptr: double pointer to IE + * + * This routine will be called to match the bss + * If caller want to get the *ie_dblptr allocated by this function, + * pass in *ie_dblptr = NULL + * + * Return: bool + */ +bool csr_match_bss(tHalHandle hal, tSirBssDescription *bss_descr, + tCsrScanResultFilter *filter, eCsrAuthType *neg_auth, + eCsrEncryptionType *neg_uc, eCsrEncryptionType *neg_mc, + tDot11fBeaconIEs **ie_dblptr) +{ + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + bool rc = false, check, blacklist_check; + uint32_t i; + tDot11fBeaconIEs *ie_ptr = NULL; + uint8_t *pb; + struct roam_ext_params *roam_params; + uint8_t *p2p_macaddr = NULL; + + roam_params = &mac_ctx->roam.configParam.roam_params; + if ((NULL == ie_dblptr) || (*ie_dblptr) == NULL) { + /* If no IEs passed in, get our own. */ + if (!QDF_IS_STATUS_SUCCESS( + csr_get_parsed_bss_description_ies(mac_ctx, + bss_descr, &ie_ptr))) { + goto end; + } + } else { + /* Save the one pass in for local use */ + ie_ptr = *ie_dblptr; + } + + /* Check if caller wants P2P */ + check = (!filter->p2pResult || ie_ptr->P2PBeaconProbeRes.present); + if (!check) + goto end; + + /* Check for Blacklist BSSID's and avoid connections */ + blacklist_check = false; + for (i = 0; i < roam_params->num_bssid_avoid_list; i++) { + if (qdf_is_macaddr_equal((struct qdf_mac_addr *) + &roam_params->bssid_avoid_list[i], + (struct qdf_mac_addr *)bss_descr->bssId)) { + blacklist_check = true; + break; + } + } + if (blacklist_check) { + sms_log(mac_ctx, LOGE, + FL("Don't Attempt connect to blacklist bssid")); + goto end; + } + + if (ie_ptr->SSID.present) { + for (i = 0; i < filter->SSIDs.numOfSSIDs; i++) { + check = csr_is_ssid_match(mac_ctx, + filter->SSIDs.SSIDList[i].SSID.ssId, + filter->SSIDs.SSIDList[i].SSID.length, + ie_ptr->SSID.ssid, + ie_ptr->SSID.num_ssid, true); + if (check) + break; + } + if (!check) + goto end; + } + check = true; + p2p_macaddr = ie_ptr->P2PBeaconProbeRes.P2PDeviceInfo.P2PDeviceAddress; + for (i = 0; i < filter->BSSIDs.numOfBSSIDs; i++) { + check = csr_is_bssid_match(mac_ctx, + (struct qdf_mac_addr *)&filter->BSSIDs.bssid[i], + (struct qdf_mac_addr *)bss_descr->bssId); + if (check) + break; + + if (filter->p2pResult && ie_ptr->P2PBeaconProbeRes.present) { + check = csr_is_bssid_match(mac_ctx, + (struct qdf_mac_addr *) + &filter->BSSIDs.bssid[i], + (struct qdf_mac_addr *)p2p_macaddr); + if (check) + break; + } + } + if (!check) + goto end; + + check = true; + for (i = 0; i < filter->ChannelInfo.numOfChannels; i++) { + check = csr_is_channel_band_match(mac_ctx, + filter->ChannelInfo.ChannelList[i], bss_descr); + if (check) + break; + } + if (!check) + goto end; + /* If this is for measurement filtering */ + if (filter->fMeasurement) { + rc = true; + goto end; + } + if (!csr_is_phy_mode_match(mac_ctx, filter->phyMode, bss_descr, + NULL, NULL, ie_ptr)) + goto end; + +#ifdef WLAN_FEATURE_11W + if ((!filter->bWPSAssociation) && (!filter->bOSENAssociation) && + !csr_is_security_match(mac_ctx, &filter->authType, + &filter->EncryptionType, + &filter->mcEncryptionType, + &filter->MFPEnabled, + &filter->MFPRequired, + &filter->MFPCapable, + bss_descr, ie_ptr, neg_auth, + neg_uc, neg_mc)) +#else + if ((!filter->bWPSAssociation) && (!filter->bOSENAssociation) && + !csr_is_security_match(mac_ctx, &filter->authType, + &filter->EncryptionType, + &filter->mcEncryptionType, + NULL, NULL, NULL, + bss_descr, ie_ptr, neg_auth, + neg_uc, neg_mc)) +#endif + goto end; + if (!csr_is_capabilities_match(mac_ctx, filter->BSSType, bss_descr)) + goto end; + if (!csr_is_rate_set_match(mac_ctx, &ie_ptr->SuppRates, + &ie_ptr->ExtSuppRates)) + goto end; + if ((eCsrRoamWmmQbssOnly == mac_ctx->roam.configParam.WMMSupportMode) + && !CSR_IS_QOS_BSS(ie_ptr)) + goto end; + /* + * Check country. check even when pb is NULL because we may + * want to make sure + */ + pb = (filter->countryCode[0]) ? (filter->countryCode) : NULL; + check = csr_match_country_code(mac_ctx, pb, ie_ptr); + if (!check) + goto end; + + if (filter->MDID.mdiePresent && csr_roam_is11r_assoc(mac_ctx, + mac_ctx->roam.roamSession->sessionId)) { + if (bss_descr->mdiePresent) { + if (filter->MDID.mobilityDomain != + (bss_descr->mdie[1] << 8 | + bss_descr->mdie[0])) + goto end; + } else { + goto end; + } + } + rc = true; + +end: + if (ie_dblptr) + *ie_dblptr = ie_ptr; + else if (ie_ptr) + qdf_mem_free(ie_ptr); + return rc; +} + +static bool csr_match_connected_bss_security(tpAniSirGlobal pMac, + tCsrRoamConnectedProfile *pProfile, + tSirBssDescription *pBssDesc, + tDot11fBeaconIEs *pIes) +{ + tCsrEncryptionList ucEncryptionList, mcEncryptionList; + tCsrAuthList authList; + + ucEncryptionList.numEntries = 1; + ucEncryptionList.encryptionType[0] = pProfile->EncryptionType; + + mcEncryptionList.numEntries = 1; + mcEncryptionList.encryptionType[0] = pProfile->mcEncryptionType; + + authList.numEntries = 1; + authList.authType[0] = pProfile->AuthType; + +#ifdef WLAN_FEATURE_11W + return csr_is_security_match(pMac, &authList, &ucEncryptionList, + &mcEncryptionList, + &pProfile->MFPEnabled, + &pProfile->MFPRequired, + &pProfile->MFPCapable, + pBssDesc, pIes, NULL, NULL, NULL); +#else + return csr_is_security_match(pMac, &authList, &ucEncryptionList, + &mcEncryptionList, NULL, NULL, NULL, + pBssDesc, pIes, NULL, NULL, NULL); +#endif + +} + +bool csr_match_bss_to_connect_profile(tHalHandle hHal, + tCsrRoamConnectedProfile *pProfile, + tSirBssDescription *pBssDesc, + tDot11fBeaconIEs *pIes) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + bool fRC = false, fCheck; + tDot11fBeaconIEs *pIesLocal = pIes; + + do { + if (!pIes) { + if (!QDF_IS_STATUS_SUCCESS + (csr_get_parsed_bss_description_ies + (pMac, pBssDesc, &pIesLocal))) { + break; + } + } + fCheck = true; + if (pIesLocal->SSID.present) { + bool fCheckSsid = false; + if (pProfile->SSID.length) { + fCheckSsid = true; + } + fCheck = + csr_is_ssid_match(pMac, pProfile->SSID.ssId, + pProfile->SSID.length, + pIesLocal->SSID.ssid, + pIesLocal->SSID.num_ssid, + fCheckSsid); + if (!fCheck) + break; + } + if (!csr_match_connected_bss_security + (pMac, pProfile, pBssDesc, pIesLocal)) + break; + if (!csr_is_capabilities_match(pMac, pProfile->BSSType, pBssDesc)) + break; + if (!csr_is_rate_set_match + (pMac, &pIesLocal->SuppRates, &pIesLocal->ExtSuppRates)) + break; + fCheck = + csr_is_channel_band_match(pMac, pProfile->operationChannel, + pBssDesc); + if (!fCheck) + break; + + fRC = true; + + } while (0); + + if (!pIes && pIesLocal) { + /* locally allocated */ + qdf_mem_free(pIesLocal); + } + + return fRC; +} + +void csr_add_rate_bitmap(uint8_t rate, uint16_t *pRateBitmap) +{ + uint16_t rateBitmap; + uint16_t n = BITS_OFF(rate, CSR_DOT11_BASIC_RATE_MASK); + rateBitmap = *pRateBitmap; + switch (n) { + case SIR_MAC_RATE_1: + rateBitmap |= SIR_MAC_RATE_1_BITMAP; + break; + case SIR_MAC_RATE_2: + rateBitmap |= SIR_MAC_RATE_2_BITMAP; + break; + case SIR_MAC_RATE_5_5: + rateBitmap |= SIR_MAC_RATE_5_5_BITMAP; + break; + case SIR_MAC_RATE_11: + rateBitmap |= SIR_MAC_RATE_11_BITMAP; + break; + case SIR_MAC_RATE_6: + rateBitmap |= SIR_MAC_RATE_6_BITMAP; + break; + case SIR_MAC_RATE_9: + rateBitmap |= SIR_MAC_RATE_9_BITMAP; + break; + case SIR_MAC_RATE_12: + rateBitmap |= SIR_MAC_RATE_12_BITMAP; + break; + case SIR_MAC_RATE_18: + rateBitmap |= SIR_MAC_RATE_18_BITMAP; + break; + case SIR_MAC_RATE_24: + rateBitmap |= SIR_MAC_RATE_24_BITMAP; + break; + case SIR_MAC_RATE_36: + rateBitmap |= SIR_MAC_RATE_36_BITMAP; + break; + case SIR_MAC_RATE_48: + rateBitmap |= SIR_MAC_RATE_48_BITMAP; + break; + case SIR_MAC_RATE_54: + rateBitmap |= SIR_MAC_RATE_54_BITMAP; + break; + } + *pRateBitmap = rateBitmap; +} + +bool csr_check_rate_bitmap(uint8_t rate, uint16_t rateBitmap) +{ + uint16_t n = BITS_OFF(rate, CSR_DOT11_BASIC_RATE_MASK); + + switch (n) { + case SIR_MAC_RATE_1: + rateBitmap &= SIR_MAC_RATE_1_BITMAP; + break; + case SIR_MAC_RATE_2: + rateBitmap &= SIR_MAC_RATE_2_BITMAP; + break; + case SIR_MAC_RATE_5_5: + rateBitmap &= SIR_MAC_RATE_5_5_BITMAP; + break; + case SIR_MAC_RATE_11: + rateBitmap &= SIR_MAC_RATE_11_BITMAP; + break; + case SIR_MAC_RATE_6: + rateBitmap &= SIR_MAC_RATE_6_BITMAP; + break; + case SIR_MAC_RATE_9: + rateBitmap &= SIR_MAC_RATE_9_BITMAP; + break; + case SIR_MAC_RATE_12: + rateBitmap &= SIR_MAC_RATE_12_BITMAP; + break; + case SIR_MAC_RATE_18: + rateBitmap &= SIR_MAC_RATE_18_BITMAP; + break; + case SIR_MAC_RATE_24: + rateBitmap &= SIR_MAC_RATE_24_BITMAP; + break; + case SIR_MAC_RATE_36: + rateBitmap &= SIR_MAC_RATE_36_BITMAP; + break; + case SIR_MAC_RATE_48: + rateBitmap &= SIR_MAC_RATE_48_BITMAP; + break; + case SIR_MAC_RATE_54: + rateBitmap &= SIR_MAC_RATE_54_BITMAP; + break; + } + return !!rateBitmap; +} + +bool csr_rates_is_dot11_rate_supported(tHalHandle hHal, uint8_t rate) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + uint16_t n = BITS_OFF(rate, CSR_DOT11_BASIC_RATE_MASK); + + return csr_is_aggregate_rate_supported(pMac, n); +} + +static uint16_t csr_rates_mac_prop_to_dot11(uint16_t Rate) +{ + uint16_t ConvertedRate = Rate; + + switch (Rate) { + case SIR_MAC_RATE_1: + ConvertedRate = 2; + break; + case SIR_MAC_RATE_2: + ConvertedRate = 4; + break; + case SIR_MAC_RATE_5_5: + ConvertedRate = 11; + break; + case SIR_MAC_RATE_11: + ConvertedRate = 22; + break; + + case SIR_MAC_RATE_6: + ConvertedRate = 12; + break; + case SIR_MAC_RATE_9: + ConvertedRate = 18; + break; + case SIR_MAC_RATE_12: + ConvertedRate = 24; + break; + case SIR_MAC_RATE_18: + ConvertedRate = 36; + break; + case SIR_MAC_RATE_24: + ConvertedRate = 48; + break; + case SIR_MAC_RATE_36: + ConvertedRate = 72; + break; + case SIR_MAC_RATE_42: + ConvertedRate = 84; + break; + case SIR_MAC_RATE_48: + ConvertedRate = 96; + break; + case SIR_MAC_RATE_54: + ConvertedRate = 108; + break; + + case SIR_MAC_RATE_72: + ConvertedRate = 144; + break; + case SIR_MAC_RATE_84: + ConvertedRate = 168; + break; + case SIR_MAC_RATE_96: + ConvertedRate = 192; + break; + case SIR_MAC_RATE_108: + ConvertedRate = 216; + break; + case SIR_MAC_RATE_126: + ConvertedRate = 252; + break; + case SIR_MAC_RATE_144: + ConvertedRate = 288; + break; + case SIR_MAC_RATE_168: + ConvertedRate = 336; + break; + case SIR_MAC_RATE_192: + ConvertedRate = 384; + break; + case SIR_MAC_RATE_216: + ConvertedRate = 432; + break; + case SIR_MAC_RATE_240: + ConvertedRate = 480; + break; + + case 0xff: + ConvertedRate = 0; + break; + } + + return ConvertedRate; +} + +uint16_t csr_rates_find_best_rate(tSirMacRateSet *pSuppRates, + tSirMacRateSet *pExtRates, + tSirMacPropRateSet *pPropRates) +{ + uint8_t i; + uint16_t nBest; + + nBest = pSuppRates->rate[0] & (~CSR_DOT11_BASIC_RATE_MASK); + + if (pSuppRates->numRates > SIR_MAC_RATESET_EID_MAX) { + pSuppRates->numRates = SIR_MAC_RATESET_EID_MAX; + } + + for (i = 1U; i < pSuppRates->numRates; ++i) { + nBest = + (uint16_t) CSR_MAX(nBest, + pSuppRates-> + rate[i] & (~CSR_DOT11_BASIC_RATE_MASK)); + } + + if (NULL != pExtRates) { + for (i = 0U; i < pExtRates->numRates; ++i) { + nBest = + (uint16_t) CSR_MAX(nBest, + pExtRates-> + rate[i] & + (~CSR_DOT11_BASIC_RATE_MASK)); + } + } + + if (NULL != pPropRates) { + for (i = 0U; i < pPropRates->numPropRates; ++i) { + nBest = + (uint16_t) CSR_MAX(nBest, + csr_rates_mac_prop_to_dot11 + (pPropRates->propRate[i])); + } + } + + return nBest; +} + +void csr_release_profile(tpAniSirGlobal pMac, tCsrRoamProfile *pProfile) +{ + if (pProfile) { + if (pProfile->BSSIDs.bssid) { + qdf_mem_free(pProfile->BSSIDs.bssid); + pProfile->BSSIDs.bssid = NULL; + } + if (pProfile->SSIDs.SSIDList) { + qdf_mem_free(pProfile->SSIDs.SSIDList); + pProfile->SSIDs.SSIDList = NULL; + } + if (pProfile->pWPAReqIE) { + qdf_mem_free(pProfile->pWPAReqIE); + pProfile->pWPAReqIE = NULL; + } + if (pProfile->pRSNReqIE) { + qdf_mem_free(pProfile->pRSNReqIE); + pProfile->pRSNReqIE = NULL; + } +#ifdef FEATURE_WLAN_WAPI + if (pProfile->pWAPIReqIE) { + qdf_mem_free(pProfile->pWAPIReqIE); + pProfile->pWAPIReqIE = NULL; + } +#endif /* FEATURE_WLAN_WAPI */ + + if (pProfile->pAddIEScan) { + qdf_mem_free(pProfile->pAddIEScan); + pProfile->pAddIEScan = NULL; + } + + if (pProfile->pAddIEAssoc) { + qdf_mem_free(pProfile->pAddIEAssoc); + pProfile->pAddIEAssoc = NULL; + } + if (pProfile->ChannelInfo.ChannelList) { + qdf_mem_free(pProfile->ChannelInfo.ChannelList); + pProfile->ChannelInfo.ChannelList = NULL; + } + qdf_mem_set(pProfile, sizeof(tCsrRoamProfile), 0); + } +} + +void csr_free_scan_filter(tpAniSirGlobal pMac, tCsrScanResultFilter *pScanFilter) +{ + if (pScanFilter->BSSIDs.bssid) { + qdf_mem_free(pScanFilter->BSSIDs.bssid); + pScanFilter->BSSIDs.bssid = NULL; + } + if (pScanFilter->ChannelInfo.ChannelList) { + qdf_mem_free(pScanFilter->ChannelInfo.ChannelList); + pScanFilter->ChannelInfo.ChannelList = NULL; + } + if (pScanFilter->SSIDs.SSIDList) { + qdf_mem_free(pScanFilter->SSIDs.SSIDList); + pScanFilter->SSIDs.SSIDList = NULL; + } +} + +void csr_free_roam_profile(tpAniSirGlobal pMac, uint32_t sessionId) +{ + tCsrRoamSession *pSession = &pMac->roam.roamSession[sessionId]; + + if (pSession->pCurRoamProfile) { + csr_release_profile(pMac, pSession->pCurRoamProfile); + qdf_mem_free(pSession->pCurRoamProfile); + pSession->pCurRoamProfile = NULL; + } +} + +void csr_free_connect_bss_desc(tpAniSirGlobal pMac, uint32_t sessionId) +{ + tCsrRoamSession *pSession = &pMac->roam.roamSession[sessionId]; + + if (pSession->pConnectBssDesc) { + qdf_mem_free(pSession->pConnectBssDesc); + pSession->pConnectBssDesc = NULL; + } +} + +tSirResultCodes csr_get_disassoc_rsp_status_code(tSirSmeDisassocRsp * + pSmeDisassocRsp) +{ + uint8_t *pBuffer = (uint8_t *) pSmeDisassocRsp; + uint32_t ret; + + pBuffer += (sizeof(uint16_t) + sizeof(uint16_t) + sizeof(tSirMacAddr)); + /* tSirResultCodes is an enum, assuming is 32bit */ + /* If we cannot make this assumption, use copymemory */ + qdf_get_u32(pBuffer, &ret); + + return (tSirResultCodes) ret; +} + +tSirResultCodes csr_get_de_auth_rsp_status_code(tSirSmeDeauthRsp *pSmeRsp) +{ + uint8_t *pBuffer = (uint8_t *) pSmeRsp; + uint32_t ret; + + pBuffer += + (sizeof(uint16_t) + sizeof(uint16_t) + sizeof(uint8_t) + + sizeof(uint16_t)); + /* tSirResultCodes is an enum, assuming is 32bit */ + /* If we cannot make this assumption, use copymemory */ + qdf_get_u32(pBuffer, &ret); + + return (tSirResultCodes) ret; +} + +tSirScanType csr_get_scan_type(tpAniSirGlobal pMac, uint8_t chnId) +{ + tSirScanType scanType = eSIR_PASSIVE_SCAN; + enum channel_state channelEnabledType; + + channelEnabledType = cds_get_channel_state(chnId); + if (CHANNEL_STATE_ENABLE == channelEnabledType) { + scanType = eSIR_ACTIVE_SCAN; + } + return scanType; +} + +uint8_t csr_to_upper(uint8_t ch) +{ + uint8_t chOut; + + if (ch >= 'a' && ch <= 'z') { + chOut = ch - 'a' + 'A'; + } else { + chOut = ch; + } + return chOut; +} + +tSirBssType csr_translate_bsstype_to_mac_type(eCsrRoamBssType csrtype) +{ + tSirBssType ret; + + switch (csrtype) { + case eCSR_BSS_TYPE_INFRASTRUCTURE: + ret = eSIR_INFRASTRUCTURE_MODE; + break; + case eCSR_BSS_TYPE_IBSS: + case eCSR_BSS_TYPE_START_IBSS: + ret = eSIR_IBSS_MODE; + break; + case eCSR_BSS_TYPE_INFRA_AP: + ret = eSIR_INFRA_AP_MODE; + break; + case eCSR_BSS_TYPE_NDI: + ret = eSIR_NDI_MODE; + break; + case eCSR_BSS_TYPE_ANY: + default: + ret = eSIR_AUTO_MODE; + break; + } + + return ret; +} + +/* This function use the parameters to decide the CFG value. */ +/* CSR never sets WNI_CFG_DOT11_MODE_ALL to the CFG */ +/* So PE should not see WNI_CFG_DOT11_MODE_ALL when it gets the CFG value */ +eCsrCfgDot11Mode csr_get_cfg_dot11_mode_from_csr_phy_mode(tCsrRoamProfile *pProfile, + eCsrPhyMode phyMode, + bool fProprietary) +{ + uint32_t cfgDot11Mode = eCSR_CFG_DOT11_MODE_ABG; + + switch (phyMode) { + case eCSR_DOT11_MODE_11a: + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11A; + break; + case eCSR_DOT11_MODE_11b: + case eCSR_DOT11_MODE_11b_ONLY: + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11B; + break; + case eCSR_DOT11_MODE_11g: + case eCSR_DOT11_MODE_11g_ONLY: + if (pProfile && (CSR_IS_INFRA_AP(pProfile)) + && (phyMode == eCSR_DOT11_MODE_11g_ONLY)) + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11G_ONLY; + else + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11G; + break; + case eCSR_DOT11_MODE_11n: + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11N; + break; + case eCSR_DOT11_MODE_11n_ONLY: + if (pProfile && CSR_IS_INFRA_AP(pProfile)) + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11N_ONLY; + else + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11N; + break; + case eCSR_DOT11_MODE_abg: + cfgDot11Mode = eCSR_CFG_DOT11_MODE_ABG; + break; + case eCSR_DOT11_MODE_AUTO: + cfgDot11Mode = eCSR_CFG_DOT11_MODE_AUTO; + break; + + case eCSR_DOT11_MODE_11ac: + if (IS_FEATURE_SUPPORTED_BY_FW(DOT11AC)) { + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11AC; + } else { + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11N; + } + break; + case eCSR_DOT11_MODE_11ac_ONLY: + if (IS_FEATURE_SUPPORTED_BY_FW(DOT11AC)) { + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11AC_ONLY; + } else { + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11N; + } + break; + default: + /* No need to assign anything here */ + break; + } + + return cfgDot11Mode; +} + +QDF_STATUS csr_get_regulatory_domain_for_country(tpAniSirGlobal pMac, + uint8_t *pCountry, + v_REGDOMAIN_t *pDomainId, + enum country_src source) +{ + QDF_STATUS status = QDF_STATUS_E_INVAL; + QDF_STATUS qdf_status; + uint8_t countryCode[CDS_COUNTRY_CODE_LEN + 1]; + v_REGDOMAIN_t domainId; + + if (pCountry) { + countryCode[0] = pCountry[0]; + countryCode[1] = pCountry[1]; + qdf_status = cds_get_reg_domain_from_country_code(&domainId, + countryCode, + source); + + if (QDF_IS_STATUS_SUCCESS(qdf_status)) { + if (pDomainId) { + *pDomainId = domainId; + } + status = QDF_STATUS_SUCCESS; + } else { + sms_log(pMac, LOGW, + FL + (" Couldn't find domain for country code %c%c"), + pCountry[0], pCountry[1]); + status = QDF_STATUS_E_INVAL; + } + } + + return status; +} + +/* To check whether a country code matches the one in the IE */ +/* Only check the first two characters, ignoring in/outdoor */ +/* pCountry -- caller allocated buffer contain the country code that is checking against */ +/* the one in pIes. It can be NULL. */ +/* caller must provide pIes, it cannot be NULL */ +/* This function always return true if 11d support is not turned on. */ +bool csr_match_country_code(tpAniSirGlobal pMac, uint8_t *pCountry, + tDot11fBeaconIEs *pIes) +{ + bool fRet = true; + + do { + if (!csr_is11d_supported(pMac)) { + break; + } + if (!pIes) { + sms_log(pMac, LOGE, FL(" No IEs")); + break; + } + + if (pCountry) { + uint32_t i; + + if (!pIes->Country.present) { + fRet = false; + break; + } + /* Convert the CountryCode characters to upper */ + for (i = 0; i < WNI_CFG_COUNTRY_CODE_LEN - 1; i++) { + pCountry[i] = csr_to_upper(pCountry[i]); + } + if (qdf_mem_cmp(pIes->Country.country, pCountry, + WNI_CFG_COUNTRY_CODE_LEN - 1)) { + fRet = false; + break; + } + } + } while (0); + + return fRet; +} + +QDF_STATUS csr_get_modify_profile_fields(tpAniSirGlobal pMac, uint32_t sessionId, + tCsrRoamModifyProfileFields * + pModifyProfileFields) +{ + + if (!pModifyProfileFields) { + return QDF_STATUS_E_FAILURE; + } + + qdf_mem_copy(pModifyProfileFields, + &pMac->roam.roamSession[sessionId].connectedProfile. + modifyProfileFields, sizeof(tCsrRoamModifyProfileFields)); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS csr_set_modify_profile_fields(tpAniSirGlobal pMac, uint32_t sessionId, + tCsrRoamModifyProfileFields * + pModifyProfileFields) +{ + tCsrRoamSession *pSession = CSR_GET_SESSION(pMac, sessionId); + + qdf_mem_copy(&pSession->connectedProfile.modifyProfileFields, + pModifyProfileFields, sizeof(tCsrRoamModifyProfileFields)); + + return QDF_STATUS_SUCCESS; +} + + +bool csr_is_set_key_allowed(tpAniSirGlobal pMac, uint32_t sessionId) +{ + bool fRet = true; + tCsrRoamSession *pSession; + + pSession = CSR_GET_SESSION(pMac, sessionId); + + /* + * This condition is not working for infra state. When infra is in + * not-connected state the pSession->pCurRoamProfile is NULL, this + * function returns true, that is incorrect. + * Since SAP requires to set key without any BSS started, it needs + * this condition to be met. In other words, this function is useless. + * The current work-around is to process setcontext_rsp no matter + * what the state is. + */ + sms_log(pMac, LOG2, + FL(" is not what it intends to. Must be revisit or removed")); + if ((NULL == pSession) + || (csr_is_conn_state_disconnected(pMac, sessionId) + && (pSession->pCurRoamProfile != NULL) + && (!(CSR_IS_INFRA_AP(pSession->pCurRoamProfile)))) + ) { + fRet = false; + } + + return fRet; +} + +/* no need to acquire lock for this basic function */ +uint16_t sme_chn_to_freq(uint8_t chanNum) +{ + int i; + + for (i = 0; i < NUM_CHANNELS; i++) { + if (CDS_CHANNEL_NUM(i) == chanNum) + return CDS_CHANNEL_FREQ(i); + } + + return 0; +} + +/* Disconnect all active sessions by sending disassoc. This is mainly used to disconnect the remaining session when we + * transition from concurrent sessions to a single session. The use case is Infra STA and wifi direct multiple sessions are up and + * P2P session is removed. The Infra STA session remains and should resume BMPS if BMPS is enabled by default. However, there + * are some issues seen with BMPS resume during this transition and this is a workaround which will allow the Infra STA session to + * disconnect and auto connect back and enter BMPS this giving the same effect as resuming BMPS + */ + +/* Remove this code once SLM_Sessionization is supported */ +/* BMPS_WORKAROUND_NOT_NEEDED */ +void csr_disconnect_all_active_sessions(tpAniSirGlobal pMac) +{ + uint8_t i; + + /* Disconnect all the active sessions */ + for (i = 0; i < CSR_ROAM_SESSION_MAX; i++) { + if (CSR_IS_SESSION_VALID(pMac, i) + && !csr_is_conn_state_disconnected(pMac, i)) { + csr_roam_disconnect_internal(pMac, i, + eCSR_DISCONNECT_REASON_UNSPECIFIED); + } + } +} + +bool csr_is_channel_present_in_list(uint8_t *pChannelList, + int numChannels, uint8_t channel) +{ + int i = 0; + + /* Check for NULL pointer */ + if (!pChannelList || (numChannels == 0)) { + return false; + } + /* Look for the channel in the list */ + for (i = 0; (i < numChannels) && + (i < WNI_CFG_VALID_CHANNEL_LIST_LEN); i++) { + if (pChannelList[i] == channel) + return true; + } + + return false; +} + +/** + * sme_request_type_to_string(): converts scan request enum to string. + * @request_type: scan request type enum. + * + * Return: Printable string for request_type + */ +const char *sme_request_type_to_string(const uint8_t request_type) +{ + switch (request_type) { + CASE_RETURN_STRING(eCSR_SCAN_REQUEST_11D_SCAN); + CASE_RETURN_STRING(eCSR_SCAN_REQUEST_FULL_SCAN); + CASE_RETURN_STRING(eCSR_SCAN_IDLE_MODE_SCAN); + CASE_RETURN_STRING(eCSR_SCAN_HO_PROBE_SCAN); + CASE_RETURN_STRING(eCSR_SCAN_P2P_DISCOVERY); + CASE_RETURN_STRING(eCSR_SCAN_SOFTAP_CHANNEL_RANGE); + CASE_RETURN_STRING(eCSR_SCAN_P2P_FIND_PEER); + default: + return "Unknown Scan Request Type"; + } +} + +/** + * sme_bsstype_to_string() - converts bss type to string. + * @bss_type: bss type enum + * + * Return: printable string for bss type + */ +const char *sme_bss_type_to_string(const uint8_t bss_type) +{ + switch (bss_type) { + CASE_RETURN_STRING(eCSR_BSS_TYPE_INFRASTRUCTURE); + CASE_RETURN_STRING(eCSR_BSS_TYPE_INFRA_AP); + CASE_RETURN_STRING(eCSR_BSS_TYPE_IBSS); + CASE_RETURN_STRING(eCSR_BSS_TYPE_START_IBSS); + CASE_RETURN_STRING(eCSR_BSS_TYPE_ANY); + default: + return "unknown bss type"; + } +} + +/** + * sme_scantype_to_string() - converts scan type to string. + * @scan_type: scan type enum + * + * Return: printable string for scan type + */ +const char *sme_scan_type_to_string(const uint8_t scan_type) +{ + switch (scan_type) { + CASE_RETURN_STRING(eSIR_PASSIVE_SCAN); + CASE_RETURN_STRING(eSIR_ACTIVE_SCAN); + CASE_RETURN_STRING(eSIR_BEACON_TABLE); + default: + return "unknown scan type"; + } +} + +QDF_STATUS csr_add_to_channel_list_front(uint8_t *pChannelList, + int numChannels, uint8_t channel) +{ + int i = 0; + + /* Check for NULL pointer */ + if (!pChannelList) + return QDF_STATUS_E_NULL_VALUE; + + /* Make room for the addition. (Start moving from the back.) */ + for (i = numChannels; i > 0; i--) { + pChannelList[i] = pChannelList[i - 1]; + } + + /* Now add the NEW channel...at the front */ + pChannelList[0] = channel; + + return QDF_STATUS_SUCCESS; +} +#ifdef FEATURE_WLAN_DIAG_SUPPORT +/** + * csr_diag_event_report() - send PE diag event + * @pmac: pointer to global MAC context. + * @event_typev: sub event type for DIAG event. + * @status: status of the event + * @reasoncode: reasoncode for the given status + * + * This function is called to send diag event + * + * Return: NA + */ +void csr_diag_event_report(tpAniSirGlobal pmac, uint16_t event_type, + uint16_t status, uint16_t reasoncode) +{ + WLAN_HOST_DIAG_EVENT_DEF(diag_event, host_event_wlan_pe_payload_type); + + qdf_mem_zero(&diag_event, sizeof(host_event_wlan_pe_payload_type)); + + /* diag_event.bssid is already all zeroes */ + diag_event.sme_state = sme_get_lim_sme_state(pmac); + diag_event.mlm_state = sme_get_lim_mlm_state(pmac); + diag_event.event_type = event_type; + diag_event.status = status; + diag_event.reason_code = reasoncode; + + WLAN_HOST_DIAG_EVENT_REPORT(&diag_event, EVENT_WLAN_PE); + return; +} +#endif + +/** + * csr_wait_for_connection_update() - Wait for hw mode update + * @mac: Pointer to the MAC context + * @do_release_reacquire_lock: Indicates whether release and + * re-acquisition of SME global lock is required. + * + * Waits for CONNECTION_UPDATE_TIMEOUT time so that the + * hw mode update can get processed. + * + * Return: True if the wait was successful, false otherwise + */ +bool csr_wait_for_connection_update(tpAniSirGlobal mac, + bool do_release_reacquire_lock) +{ + QDF_STATUS status, ret; + + if (do_release_reacquire_lock == true) { + ret = sme_release_global_lock(&mac->sme); + if (!QDF_IS_STATUS_SUCCESS(ret)) { + cds_err("lock release fail %d", ret); + return false; + } + } + + status = qdf_wait_for_connection_update(); + + if (do_release_reacquire_lock == true) { + ret = sme_acquire_global_lock(&mac->sme); + if (!QDF_IS_STATUS_SUCCESS(ret)) { + cds_err("lock acquire fail %d", ret); + return false; + } + } + + if (!QDF_IS_STATUS_SUCCESS(status)) { + cds_err("wait for event failed"); + return false; + } + + return true; +} + +/** + * csr_get_session_persona() - get persona of a session + * @pmac: pointer to global MAC context + * @session_id: session id + * + * This function is to return the persona of a session + * + * Reture: enum tQDF_ADAPTER_MODE persona + */ +enum tQDF_ADAPTER_MODE csr_get_session_persona(tpAniSirGlobal pmac, + uint32_t session_id) +{ + tCsrRoamSession *session = NULL; + + session = CSR_GET_SESSION(pmac, session_id); + if (NULL == session || NULL == session->pCurRoamProfile) + return QDF_MAX_NO_OF_MODE; + + return session->pCurRoamProfile->csrPersona; +} + +/** + * csr_is_ndi_started() - function to check if NDI is started + * @mac_ctx: handle to mac context + * @session_id: session identifier + * + * returns: true if NDI is started, false otherwise + */ +bool csr_is_ndi_started(tpAniSirGlobal mac_ctx, uint32_t session_id) +{ + tCsrRoamSession *session = CSR_GET_SESSION(mac_ctx, session_id); + if (!session) + return false; + + return eCSR_CONNECT_STATE_TYPE_NDI_STARTED == session->connectState; +} diff --git a/drivers/staging/qcacld-3.0/core/sme/src/nan/nan_api.c b/drivers/staging/qcacld-3.0/core/sme/src/nan/nan_api.c new file mode 100644 index 0000000000000000000000000000000000000000..854975790758891505513f70b4a4993b35ea4384 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/sme/src/nan/nan_api.c @@ -0,0 +1,165 @@ +/* + * Copyright (c) 2014-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#include "sme_api.h" +#include "sms_debug.h" +#include "csr_inside_api.h" +#include "sme_inside.h" +#include "nan_api.h" +#include "cfg_api.h" +#include "wma_types.h" + +/****************************************************************************** + * Function: sme_nan_register_callback + * + * Description: + * This function gets called when HDD wants register nan rsp callback with + * sme layer. + * + * Args: + * hHal and callback which needs to be registered. + * + * Returns: + * void + *****************************************************************************/ +void sme_nan_register_callback(tHalHandle hHal, nan_callback callback) +{ + tpAniSirGlobal pMac = NULL; + + if (NULL == hHal) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("hHal is not valid")); + return; + } + pMac = PMAC_STRUCT(hHal); + pMac->sme.nanCallback = callback; +} + +/** + * sme_nan_deregister_callback() - NAN De-register cb function + * @h_hal: Hal handle + * + * De-register nan rsp callback with sme layer. + * + * Return: void + */ +void sme_nan_deregister_callback(tHalHandle h_hal) +{ + tpAniSirGlobal pmac; + + if (!h_hal) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("hHal is not valid")); + return; + } + pmac = PMAC_STRUCT(h_hal); + pmac->sme.nanCallback = NULL; +} + + +/****************************************************************************** + * Function: sme_nan_request + * + * Description: + * This function gets called when HDD receives NAN vendor command + * from userspace + * + * Args: + * Nan Request structure ptr + * + * Returns: + * QDF_STATUS + *****************************************************************************/ +QDF_STATUS sme_nan_request(tpNanRequestReq input) +{ + cds_msg_t msg; + tpNanRequest data; + size_t data_len; + + data_len = sizeof(tNanRequest) + input->request_data_len; + data = qdf_mem_malloc(data_len); + + if (data == NULL) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Memory allocation failure")); + return QDF_STATUS_E_NOMEM; + } + data->request_data_len = input->request_data_len; + if (input->request_data_len) { + qdf_mem_copy(data->request_data, + input->request_data, input->request_data_len); + } + + msg.type = WMA_NAN_REQUEST; + msg.reserved = 0; + msg.bodyptr = data; + + if (QDF_STATUS_SUCCESS != cds_mq_post_message(QDF_MODULE_ID_WMA, &msg)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL + ("Not able to post WMA_NAN_REQUEST message to WMA")); + qdf_mem_free(data); + return QDF_STATUS_SUCCESS; + } + + return QDF_STATUS_SUCCESS; +} + +/****************************************************************************** +* Function: sme_nan_event +* +* Description: +* This callback function will be called when SME received eWNI_SME_NAN_EVENT +* event from WMA +* +* Args: +* hHal - HAL handle for device +* pMsg - Message body passed from WMA; includes NAN header +* +* Returns: +* QDF_STATUS +******************************************************************************/ +QDF_STATUS sme_nan_event(tHalHandle hHal, void *pMsg) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + QDF_STATUS status = QDF_STATUS_SUCCESS; + + if (NULL == pMsg) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("msg ptr is NULL")); + status = QDF_STATUS_E_FAILURE; + } else { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO_MED, + FL("SME: Received sme_nan_event")); + if (pMac->sme.nanCallback) { + pMac->sme.nanCallback(pMac->hHdd, + (tSirNanEvent *) pMsg); + } + } + + return status; +} diff --git a/drivers/staging/qcacld-3.0/core/sme/src/nan/nan_datapath_api.c b/drivers/staging/qcacld-3.0/core/sme/src/nan/nan_datapath_api.c new file mode 100644 index 0000000000000000000000000000000000000000..9d09ab08c92c6293fa759d6087e5b83f85993840 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/sme/src/nan/nan_datapath_api.c @@ -0,0 +1,827 @@ +/* + * Copyright (c) 2016-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * 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. + */ + +/** + * DOC: nan_datapath_api.c + * + * SME NAN Data path API implementation + */ +#include "sms_debug.h" +#include "sme_api.h" +#include "sme_inside.h" +#include "csr_internal.h" +#include "sme_nan_datapath.h" + +/** + * csr_free_ndp_initiator_req() - free resouces from sme command for ndp + * initiator request + * @cmd: sme command msg + * + * Return: None + */ +static void csr_free_ndp_initiator_req(tSmeCmd *cmd) +{ + qdf_mem_free(cmd->u.initiator_req.ndp_config.ndp_cfg); + cmd->u.initiator_req.ndp_config.ndp_cfg = NULL; + cmd->u.initiator_req.ndp_config.ndp_cfg_len = 0; + qdf_mem_free(cmd->u.initiator_req.ndp_info.ndp_app_info); + cmd->u.initiator_req.ndp_info.ndp_app_info = NULL; + cmd->u.initiator_req.ndp_info.ndp_app_info_len = 0; + qdf_mem_free(cmd->u.initiator_req.pmk.pmk); + cmd->u.initiator_req.pmk.pmk = NULL; + cmd->u.initiator_req.pmk.pmk_len = 0; +} + +/** + * csr_free_ndp_responder_req() - free resouces from sme command for ndp + * responder request + * @cmd: sme command msg + * + * Return: None + */ +static void csr_free_ndp_responder_req(tSmeCmd *cmd) +{ + qdf_mem_free(cmd->u.responder_req.ndp_config.ndp_cfg); + cmd->u.responder_req.ndp_config.ndp_cfg = NULL; + cmd->u.responder_req.ndp_config.ndp_cfg_len = 0; + qdf_mem_free(cmd->u.responder_req.ndp_info.ndp_app_info); + cmd->u.responder_req.ndp_info.ndp_app_info = NULL; + cmd->u.responder_req.ndp_info.ndp_app_info_len = 0; + qdf_mem_free(cmd->u.responder_req.pmk.pmk); + cmd->u.responder_req.pmk.pmk = NULL; + cmd->u.responder_req.pmk.pmk_len = 0; +} + +/** + * sme_ndp_initiator_req_handler() - ndp initiator req handler + * @hal: hal handle + * @req_params: request parameters + * + * Return: QDF_STATUS_SUCCESS on success; error number otherwise + */ +QDF_STATUS sme_ndp_initiator_req_handler(tHalHandle hal, + struct ndp_initiator_req *req_params) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tSmeCmd *cmd; + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + + if (NULL == req_params) { + sms_log(mac_ctx, LOGE, FL("Invalid req_params")); + return QDF_STATUS_E_INVAL; + } + + status = sme_acquire_global_lock(&mac_ctx->sme); + if (QDF_STATUS_SUCCESS != status) { + sms_log(mac_ctx, LOGE, + FL("SME lock failed, status:%d"), status); + return status; + } + cmd = csr_get_command_buffer(mac_ctx); + if (NULL == cmd) { + sme_release_global_lock(&mac_ctx->sme); + return QDF_STATUS_E_RESOURCES; + } + + cmd->command = eSmeCommandNdpInitiatorRequest; + cmd->sessionId = (uint8_t)req_params->vdev_id; + qdf_mem_copy(&cmd->u.initiator_req, req_params, + sizeof(struct ndp_initiator_req)); + /* pointers copied as part of above operation are to be overwritten */ + cmd->u.initiator_req.ndp_info.ndp_app_info = NULL; + cmd->u.initiator_req.ndp_config.ndp_cfg = NULL; + cmd->u.initiator_req.pmk.pmk = NULL; + + if (req_params->ndp_info.ndp_app_info_len) { + cmd->u.initiator_req.ndp_info.ndp_app_info = + qdf_mem_malloc(req_params->ndp_info.ndp_app_info_len); + if (NULL == cmd->u.initiator_req.ndp_info.ndp_app_info) { + csr_release_ndp_initiator_req(mac_ctx, cmd); + sme_release_global_lock(&mac_ctx->sme); + return QDF_STATUS_E_NOMEM; + } + qdf_mem_copy(cmd->u.initiator_req.ndp_info.ndp_app_info, + req_params->ndp_info.ndp_app_info, + req_params->ndp_info.ndp_app_info_len); + } + + if (req_params->ndp_config.ndp_cfg_len) { + cmd->u.initiator_req.ndp_config.ndp_cfg = + qdf_mem_malloc(req_params->ndp_config.ndp_cfg_len); + if (NULL == cmd->u.initiator_req.ndp_config.ndp_cfg) { + csr_release_ndp_initiator_req(mac_ctx, cmd); + sme_release_global_lock(&mac_ctx->sme); + return QDF_STATUS_E_NOMEM; + } + qdf_mem_copy(cmd->u.initiator_req.ndp_config.ndp_cfg, + req_params->ndp_config.ndp_cfg, + req_params->ndp_config.ndp_cfg_len); + } + + if (req_params->pmk.pmk_len) { + cmd->u.initiator_req.pmk.pmk = + qdf_mem_malloc(req_params->pmk.pmk_len); + if (NULL == cmd->u.initiator_req.pmk.pmk) { + csr_release_ndp_initiator_req(mac_ctx, cmd); + sme_release_global_lock(&mac_ctx->sme); + return QDF_STATUS_E_NOMEM; + } + qdf_mem_copy(cmd->u.initiator_req.pmk.pmk, + req_params->pmk.pmk, req_params->pmk.pmk_len); + } + + status = csr_queue_sme_command(mac_ctx, cmd, true); + if (QDF_STATUS_SUCCESS != status) { + sms_log(mac_ctx, LOGE, FL("SME enqueue failed, status:%d"), + status); + csr_release_ndp_initiator_req(mac_ctx, cmd); + } + + sme_release_global_lock(&mac_ctx->sme); + return status; +} +/** + * sme_ndp_responder_req_handler() - ndp responder request handler + * @hal: hal handle + * @req_params: request parameters + * + * Return: QDF_STATUS_SUCCESS on success; error number otherwise + */ +QDF_STATUS sme_ndp_responder_req_handler(tHalHandle hal, + struct ndp_responder_req *req_params) +{ + QDF_STATUS status; + tSmeCmd *cmd; + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + + if (NULL == req_params) { + sms_log(mac_ctx, LOGE, FL("Invalid req_params")); + return QDF_STATUS_E_INVAL; + } + + status = sme_acquire_global_lock(&mac_ctx->sme); + if (QDF_STATUS_SUCCESS != status) { + sms_log(mac_ctx, LOGE, + FL("SME lock failed, status:%d"), status); + return status; + } + cmd = csr_get_command_buffer(mac_ctx); + if (NULL == cmd) { + sme_release_global_lock(&mac_ctx->sme); + return QDF_STATUS_E_RESOURCES; + } + + cmd->command = eSmeCommandNdpResponderRequest; + cmd->sessionId = (uint8_t)req_params->vdev_id; + qdf_mem_copy(&cmd->u.responder_req, req_params, + sizeof(*req_params)); + + /* + * Pointers copied as part of above operation are + * to be overwritten + */ + cmd->u.responder_req.ndp_info.ndp_app_info = NULL; + cmd->u.responder_req.ndp_config.ndp_cfg = NULL; + cmd->u.responder_req.pmk.pmk = NULL; + + if (req_params->ndp_info.ndp_app_info_len) { + cmd->u.responder_req.ndp_info.ndp_app_info = + qdf_mem_malloc(req_params->ndp_info.ndp_app_info_len); + if (NULL == cmd->u.responder_req.ndp_info.ndp_app_info) { + csr_release_ndp_responder_req(mac_ctx, cmd); + sme_release_global_lock(&mac_ctx->sme); + return QDF_STATUS_E_NOMEM; + } + qdf_mem_copy(cmd->u.responder_req.ndp_info.ndp_app_info, + req_params->ndp_info.ndp_app_info, + req_params->ndp_info.ndp_app_info_len); + } + + if (req_params->ndp_config.ndp_cfg_len) { + cmd->u.responder_req.ndp_config.ndp_cfg = + qdf_mem_malloc(req_params->ndp_config.ndp_cfg_len); + if (NULL == cmd->u.responder_req.ndp_config.ndp_cfg) { + csr_release_ndp_responder_req(mac_ctx, cmd); + sme_release_global_lock(&mac_ctx->sme); + return QDF_STATUS_E_NOMEM; + } + qdf_mem_copy(cmd->u.responder_req.ndp_config.ndp_cfg, + req_params->ndp_config.ndp_cfg, + req_params->ndp_config.ndp_cfg_len); + } + + if (req_params->pmk.pmk_len) { + cmd->u.responder_req.pmk.pmk = + qdf_mem_malloc(req_params->pmk.pmk_len); + if (NULL == cmd->u.responder_req.pmk.pmk) { + csr_release_ndp_responder_req(mac_ctx, cmd); + sme_release_global_lock(&mac_ctx->sme); + return QDF_STATUS_E_NOMEM; + } + qdf_mem_copy(cmd->u.responder_req.pmk.pmk, + req_params->pmk.pmk, req_params->pmk.pmk_len); + } + + status = csr_queue_sme_command(mac_ctx, cmd, true); + if (QDF_STATUS_SUCCESS != status) { + sms_log(mac_ctx, LOGE, + FL("SME enqueue failed, status:%d"), status); + csr_release_ndp_responder_req(mac_ctx, cmd); + } + + sme_release_global_lock(&mac_ctx->sme); + return status; +} + +/** + * sme_ndp_end_req_handler() - ndp end request handler + * @hal: hal handle + * @req: ndp end request parameters + * + * Return: QDF_STATUS_SUCCESS on success; error number otherwise + */ +QDF_STATUS sme_ndp_end_req_handler(tHalHandle hal, struct ndp_end_req *req) +{ + tSmeCmd *cmd; + QDF_STATUS ret = QDF_STATUS_SUCCESS; + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpAniSirGlobal mac_ctx = PMAC_STRUCT(hal); + + if (NULL == req) { + sms_log(mac_ctx, LOGE, FL("Invalid ndp end req")); + return QDF_STATUS_E_INVAL; + } + + status = sme_acquire_global_lock(&mac_ctx->sme); + if (QDF_STATUS_SUCCESS != status) { + sms_log(mac_ctx, LOGE, + FL("SME lock failed, status:%d"), status); + return QDF_STATUS_E_RESOURCES; + } + cmd = csr_get_command_buffer(mac_ctx); + if (NULL == cmd) { + sme_release_global_lock(&mac_ctx->sme); + return QDF_STATUS_E_RESOURCES; + } + + cmd->command = eSmeCommandNdpDataEndInitiatorRequest; + cmd->u.data_end_req = qdf_mem_malloc(sizeof(*req) + + (req->num_ndp_instances * sizeof(uint32_t))); + if (NULL == cmd->u.data_end_req) { + csr_release_command_roam(mac_ctx, cmd); + sme_release_global_lock(&mac_ctx->sme); + return QDF_STATUS_E_NOMEM; + } + + qdf_mem_copy(cmd->u.data_end_req, req, sizeof(*req)); + cmd->u.data_end_req->ndp_ids = + (uint32_t *)((uint8_t *)&cmd->u.data_end_req[1]); + qdf_mem_copy(cmd->u.data_end_req->ndp_ids, req->ndp_ids, + sizeof(uint32_t) * req->num_ndp_instances); + + status = csr_queue_sme_command(mac_ctx, cmd, true); + if (QDF_STATUS_SUCCESS != status) { + sms_log(mac_ctx, LOGE, FL("SME enqueue failed, status:%d"), + status); + ret = QDF_STATUS_E_FAILURE; + csr_release_ndp_data_end_req(mac_ctx, cmd); + } + + sme_release_global_lock(&mac_ctx->sme); + return ret; +} + +/** + * csr_roam_start_ndi() - Start connection for NAN datapath + * @mac_ctx: Global MAC context + * @session: SME session ID + * @profile: Configuration profile + * + * Return: Success or failure code + */ +QDF_STATUS csr_roam_start_ndi(tpAniSirGlobal mac_ctx, uint32_t session, + tCsrRoamProfile *profile) +{ + QDF_STATUS status; + tBssConfigParam bss_cfg = {0}; + + /* Build BSS configuration from profile */ + status = csr_roam_prepare_bss_config_from_profile(mac_ctx, profile, + &bss_cfg, NULL); + if (QDF_IS_STATUS_SUCCESS(status)) { + mac_ctx->roam.roamSession[session].bssParams.uCfgDot11Mode + = bss_cfg.uCfgDot11Mode; + /* Copy profile parameters to PE session */ + csr_roam_prepare_bss_params(mac_ctx, session, profile, NULL, + &bss_cfg, NULL); + /* + * Following routine will eventually call + * csrRoamIssueStartBss through csrRoamCcmCfgSetCallback + */ + status = csr_roam_set_bss_config_cfg(mac_ctx, session, profile, + NULL, &bss_cfg, NULL, false); + } + + if (QDF_IS_STATUS_SUCCESS(status)) + sms_log(mac_ctx, LOG1, FL("Profile config is valid")); + else + sms_log(mac_ctx, LOGE, + FL("Profile config is invalid. status = 0x%x"), status); + + return status; +} + +/** + * csr_roam_save_ndi_connected_info() - Save connected profile parameters + * @mac_ctx: Global MAC context + * @session_id: Session ID + * @roam_profile: Profile given for starting BSS + * @bssdesc: BSS description from tSirSmeStartBssRsp response + * + * Saves NDI profile parameters into session's connected profile. + * + * Return: None + */ +void csr_roam_save_ndi_connected_info(tpAniSirGlobal mac_ctx, + uint32_t session_id, + tCsrRoamProfile *roam_profile, + tSirBssDescription *bssdesc) +{ + tCsrRoamSession *roam_session = NULL; + tCsrRoamConnectedProfile *connect_profile = NULL; + + roam_session = CSR_GET_SESSION(mac_ctx, session_id); + if (NULL == roam_session) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("session %d not found"), session_id); + return; + } + + connect_profile = &roam_session->connectedProfile; + qdf_mem_set(&roam_session->connectedProfile, + sizeof(connect_profile), 0); + connect_profile->AuthType = roam_profile->negotiatedAuthType; + connect_profile->AuthInfo = roam_profile->AuthType; + connect_profile->CBMode = roam_profile->CBMode; + connect_profile->EncryptionType = + roam_profile->negotiatedUCEncryptionType; + connect_profile->EncryptionInfo = roam_profile->EncryptionType; + connect_profile->mcEncryptionType = + roam_profile->negotiatedMCEncryptionType; + connect_profile->mcEncryptionInfo = + roam_profile->mcEncryptionType; + connect_profile->BSSType = roam_profile->BSSType; + connect_profile->modifyProfileFields.uapsd_mask = + roam_profile->uapsd_mask; + connect_profile->operationChannel = bssdesc->channelId; + connect_profile->beaconInterval = 0; + qdf_mem_copy(&connect_profile->Keys, &roam_profile->Keys, + sizeof(roam_profile->Keys)); + csr_get_bss_id_bss_desc(mac_ctx, bssdesc, &connect_profile->bssid); + connect_profile->SSID.length = 0; + csr_free_connect_bss_desc(mac_ctx, session_id); + connect_profile->qap = false; + connect_profile->qosConnection = false; +} + +/** + * csr_roam_update_ndp_return_params() - updates ndp return parameters + * @mac_ctx: MAC context handle + * @result: result of the roaming command + * @roam_status: roam status returned to the roam command initiator + * @roam_result: roam result returned to the roam command initiator + * @roam_info: Roam info data structure to be updated + * + * Results: None + */ +void csr_roam_update_ndp_return_params(tpAniSirGlobal mac_ctx, + uint32_t result, + uint32_t *roam_status, + uint32_t *roam_result, + tCsrRoamInfo *roam_info) +{ + + switch (result) { + case eCsrStartBssSuccess: + roam_info->ndp.ndi_create_params.reason = 0; + roam_info->ndp.ndi_create_params.status = + NDP_RSP_STATUS_SUCCESS; + roam_info->ndp.ndi_create_params.sta_id = roam_info->staId; + *roam_status = eCSR_ROAM_NDP_STATUS_UPDATE; + *roam_result = eCSR_ROAM_RESULT_NDI_CREATE_RSP; + break; + case eCsrStartBssFailure: + roam_info->ndp.ndi_create_params.status = NDP_RSP_STATUS_ERROR; + roam_info->ndp.ndi_create_params.reason = + NDP_NAN_DATA_IFACE_CREATE_FAILED; + *roam_status = eCSR_ROAM_NDP_STATUS_UPDATE; + *roam_result = eCSR_ROAM_RESULT_NDI_CREATE_RSP; + break; + case eCsrStopBssSuccess: + roam_info->ndp.ndi_delete_params.reason = 0; + roam_info->ndp.ndi_delete_params.status = + NDP_RSP_STATUS_SUCCESS; + *roam_status = eCSR_ROAM_NDP_STATUS_UPDATE; + *roam_result = eCSR_ROAM_RESULT_NDI_DELETE_RSP; + break; + case eCsrStopBssFailure: + roam_info->ndp.ndi_delete_params.status = NDP_RSP_STATUS_ERROR; + roam_info->ndp.ndi_delete_params.reason = + NDP_NAN_DATA_IFACE_DELETE_FAILED; + *roam_status = eCSR_ROAM_NDP_STATUS_UPDATE; + *roam_result = eCSR_ROAM_RESULT_NDI_DELETE_RSP; + break; + default: + sms_log(mac_ctx, LOGE, + FL("Invalid CSR Roam result code: %d"), result); + break; + } +} + +/** + * csr_process_ndp_initiator_request() - process ndp initiator request + * @mac_ctx: Global MAC context + * @cmd: ndp initiator sme cmd + * + * Return: status of operation + */ +QDF_STATUS csr_process_ndp_initiator_request(tpAniSirGlobal mac_ctx, + tSmeCmd *cmd) +{ + QDF_STATUS status; + struct sir_sme_ndp_initiator_req *lim_msg; + uint16_t msg_len; + uint8_t *self_mac_addr = NULL; + struct ndp_initiator_req *req; + + if (NULL == cmd) { + sms_log(mac_ctx, LOGE, FL("Invalid req_params")); + return QDF_STATUS_E_INVAL; + } + req = &cmd->u.initiator_req; + + msg_len = sizeof(*lim_msg); + lim_msg = qdf_mem_malloc(msg_len); + if (NULL == lim_msg) { + status = QDF_STATUS_E_NOMEM; + goto sme_initiator_req_failed; + } + + lim_msg->msg_type = eWNI_SME_NDP_INITIATOR_REQ; + lim_msg->msg_len = msg_len; + /* + * following is being copied from p_cmd->u.initiator_req, + * no need to perform deep copy, as we are going to use memory + * allocated at SME in p_cmd->u.initiator_req and pass it all the way + * to WMA. + */ + qdf_mem_copy(&lim_msg->req, req, sizeof(struct ndp_initiator_req)); + + self_mac_addr = lim_msg->req.self_ndi_mac_addr.bytes; + sms_log(mac_ctx, LOG1, FL("selfMac = "MAC_ADDRESS_STR), + MAC_ADDR_ARRAY(self_mac_addr)); + + status = cds_send_mb_message_to_mac(lim_msg); + if (status != QDF_STATUS_SUCCESS) + csr_free_ndp_initiator_req(cmd); + +sme_initiator_req_failed: + /* If fail, free up resources allocated in sme. */ + if (status != QDF_STATUS_SUCCESS) + csr_free_ndp_initiator_req(cmd); + return status; +} + +/** + * csr_process_ndp_responder_request() - ndp responder req + * @mac_ctx: Global MAC context + * @cmd: Cmd sent to SME + * + * Return: Success or failure code + */ +QDF_STATUS csr_process_ndp_responder_request(tpAniSirGlobal mac_ctx, + tSmeCmd *cmd) +{ + struct sir_sme_ndp_responder_req *lim_msg; + uint16_t msg_len; + QDF_STATUS status; + + if (!cmd) { + sms_log(mac_ctx, LOGE, FL("Invalid req_params")); + return QDF_STATUS_E_INVAL; + } + + msg_len = sizeof(*lim_msg); + lim_msg = qdf_mem_malloc(msg_len); + + if (!lim_msg) { + sms_log(mac_ctx, LOGE, FL("Mem alloc fail")); + status = QDF_STATUS_E_NOMEM; + goto free_config; + } + + lim_msg->msg_type = eWNI_SME_NDP_RESPONDER_REQ; + lim_msg->msg_len = msg_len; + /* + * following is being copied from p_cmd->u.responder_req, + * no need to perform deep copy, as we are going to use memory + * allocated at SME in p_cmd->u.responder_req and pass it all the way + * to WMA. + */ + qdf_mem_copy(&lim_msg->req, &cmd->u.responder_req, + sizeof(struct ndp_responder_req)); + + sms_log(mac_ctx, LOG1, + FL("vdev_id %d ndp_rsp = %d Instance id %d"), + lim_msg->req.vdev_id, + lim_msg->req.ndp_rsp, + lim_msg->req.ndp_instance_id); + + status = cds_send_mb_message_to_mac(lim_msg); + +free_config: + /* If fail, free up the ndp_cfg and ndp_app_info allocated in sme. */ + if (status != QDF_STATUS_SUCCESS) + csr_free_ndp_responder_req(cmd); + return status; +} + +/* + * csr_process_ndp_data_end_request() - process ndp data end request + * @mac_ctx: Global MAC context + * @cmd: sme command containing ndp initiator request + * + * Return: status of operation + */ +QDF_STATUS csr_process_ndp_data_end_request(tpAniSirGlobal mac_ctx, + tSmeCmd *cmd) +{ + QDF_STATUS status; + struct sir_sme_ndp_end_req *lim_msg; + uint16_t msg_len; + + if (NULL == cmd) { + sms_log(mac_ctx, LOGE, FL("NULL sme cmd")); + return QDF_STATUS_E_INVAL; + } + + msg_len = sizeof(*lim_msg); + lim_msg = qdf_mem_malloc(msg_len); + if (NULL == lim_msg) { + sms_log(mac_ctx, LOGE, FL("Malloc failed")); + qdf_mem_free(cmd->u.data_end_req); + cmd->u.data_end_req = NULL; + return QDF_STATUS_E_NOMEM; + } + + lim_msg->msg_type = (uint16_t)eWNI_SME_NDP_END_REQ; + lim_msg->msg_len = msg_len; + lim_msg->req = cmd->u.data_end_req; + + status = cds_send_mb_message_to_mac(lim_msg); + if (status != QDF_STATUS_SUCCESS) { + qdf_mem_free(cmd->u.data_end_req); + cmd->u.data_end_req = NULL; + } + return status; +} + +/** + * sme_ndp_msg_processor() - message processor for ndp/ndi north-bound SME msg. + * @mac_ctx: Global MAC context + * @msg: ndp/ndi SME message + * + * This function will further call csrRoamCallCallback with appropriate + * roam_status and roam_result thus allowing hdd to correctly identify NDP/NDI + * response. + * + * Return: nothing + */ +void sme_ndp_msg_processor(tpAniSirGlobal mac_ctx, cds_msg_t *msg) +{ + tCsrRoamInfo roam_info = {0}; + eCsrRoamResult result; + uint32_t session_id; + tListElem *entry = NULL; + tSmeCmd *cmd = NULL; + bool release_active_cmd = false; + eSmeCommandType cmd_to_rel = eSmeNoCommand; + bool send_to_user = true; + + entry = csr_ll_peek_head(&mac_ctx->sme.smeCmdActiveList, + LL_ACCESS_LOCK); + if (entry != NULL) + cmd = GET_BASE_ADDR(entry, tSmeCmd, Link); + + switch (msg->type) { + case eWNI_SME_NDP_CONFIRM_IND: { + result = eCSR_ROAM_RESULT_NDP_CONFIRM_IND; + /* copy msg from msg body to roam info passed to callback */ + qdf_mem_copy(&roam_info.ndp.ndp_confirm_params, msg->bodyptr, + sizeof(roam_info.ndp.ndp_confirm_params)); + session_id = roam_info.ndp.ndp_confirm_params.vdev_id; + break; + } + case eWNI_SME_NDP_INITIATOR_RSP: { + if (true == msg->bodyval) { + /* rsp was locally generated, do not send to HDD */ + send_to_user = false; + } else { + result = eCSR_ROAM_RESULT_NDP_INITIATOR_RSP; + qdf_mem_copy(&roam_info.ndp.ndp_init_rsp_params, + msg->bodyptr, + sizeof(roam_info.ndp.ndp_init_rsp_params)); + session_id = roam_info.ndp.ndp_init_rsp_params.vdev_id; + } + release_active_cmd = true; + cmd_to_rel = eSmeCommandNdpInitiatorRequest; + break; + } + case eWNI_SME_NDP_NEW_PEER_IND: { + result = eCSR_ROAM_RESULT_NDP_NEW_PEER_IND; + /* copy msg from msg body to roam info passed to callback */ + qdf_mem_copy(&roam_info.ndp.ndp_peer_ind_params, + msg->bodyptr, + sizeof(roam_info.ndp.ndp_peer_ind_params)); + session_id = roam_info.ndp.ndp_peer_ind_params.session_id; + break; + } + case eWNI_SME_NDP_INDICATION: + result = eCSR_ROAM_RESULT_NDP_INDICATION; + /* copy msg from msg body to roam info passed to callback */ + qdf_mem_copy(&roam_info.ndp.ndp_indication_params, + msg->bodyptr, sizeof(struct ndp_indication_event)); + session_id = roam_info.ndp.ndp_indication_params.vdev_id; + break; + case eWNI_SME_NDP_RESPONDER_RSP: + if (true == msg->bodyval) { + /* rsp was locally generated, do not send to HDD */ + send_to_user = false; + } else { + result = eCSR_ROAM_RESULT_NDP_RESPONDER_RSP; + /* + * Copy msg from msg body to roam info passed to + * callback + */ + qdf_mem_copy(&roam_info.ndp.ndp_responder_rsp_params, + msg->bodyptr, + sizeof(struct ndp_responder_rsp_event)); + session_id = + roam_info.ndp.ndp_responder_rsp_params.vdev_id; + } + release_active_cmd = true; + cmd_to_rel = eSmeCommandNdpResponderRequest; + break; + case eWNI_SME_NDP_END_RSP: { + if (true == msg->bodyval) { + /* rsp was locally generated, do not send to HDD */ + send_to_user = false; + } else { + result = eCSR_ROAM_RESULT_NDP_END_RSP; + roam_info.ndp.ndp_end_rsp_params = msg->bodyptr; + /* + * NDP_END_IND is independent of session, but session_id + * is needed for csrRoamCallCallback(). Set it to 0 + * which is a valid session. + */ + session_id = 0; + } + release_active_cmd = true; + cmd_to_rel = eSmeCommandNdpDataEndInitiatorRequest; + break; + } + case eWNI_SME_NDP_END_IND: + result = eCSR_ROAM_RESULT_NDP_END_IND; + roam_info.ndp.ndp_end_ind_params = msg->bodyptr; + /* + * NDP_END_IND is independent of session, but session_id is + * needed for csr_roam_call_callback(). Set it to vdev_id of + * first entry which is a valid session. vdev_id is likely to + * be same for all. + */ + session_id = + roam_info.ndp.ndp_end_ind_params->ndp_map[0].vdev_id; + break; + case eWNI_SME_NDP_PEER_DEPARTED_IND: + result = eCSR_ROAM_RESULT_NDP_PEER_DEPARTED_IND; + /* copy msg from msg body to roam info passed to callback */ + qdf_mem_copy(&roam_info.ndp.ndp_peer_ind_params, + msg->bodyptr, + sizeof(roam_info.ndp.ndp_peer_ind_params)); + session_id = + ((struct sme_ndp_peer_ind *)msg->bodyptr)->session_id; + break; + default: + sms_log(mac_ctx, LOGE, FL("Unhandled NDP rsp")); + qdf_mem_free(msg->bodyptr); + return; + } + + if (true == send_to_user) + csr_roam_call_callback(mac_ctx, session_id, &roam_info, 0, + eCSR_ROAM_NDP_STATUS_UPDATE, result); + + /* + * free ndp_cfg and ndp_app_info if required + * For some commands this info may be needed in HDD + * so free them after roam callback. + */ + switch (msg->type) { + case eWNI_SME_NDP_INITIATOR_RSP: + if (cmd && eSmeCommandNdpInitiatorRequest == cmd->command) { + qdf_mem_free(cmd->u.initiator_req.ndp_config.ndp_cfg); + qdf_mem_free( + cmd->u.initiator_req.ndp_info.ndp_app_info); + } + break; + case eWNI_SME_NDP_INDICATION: + qdf_mem_free(roam_info.ndp.ndp_indication_params.scid.scid); + qdf_mem_free( + roam_info.ndp.ndp_indication_params.ndp_config.ndp_cfg); + qdf_mem_free( + roam_info.ndp.ndp_indication_params.ndp_info.ndp_app_info); + break; + case eWNI_SME_NDP_END_RSP: + if (cmd && + eSmeCommandNdpDataEndInitiatorRequest == cmd->command) { + qdf_mem_free(cmd->u.data_end_req); + cmd->u.data_end_req = NULL; + } + break; + case eWNI_SME_NDP_END_IND: + break; + default: + break; + } + qdf_mem_free(msg->bodyptr); + msg->bodyptr = NULL; + + if (release_active_cmd && cmd && cmd_to_rel == cmd->command) { + /* Now put this cmd back on the avilable command list */ + if (csr_ll_remove_entry(&mac_ctx->sme.smeCmdActiveList, + entry, LL_ACCESS_LOCK)) + sme_release_command(mac_ctx, cmd); + sme_process_pending_queue(mac_ctx); + } +} + +/** + * csr_release_ndp_initiator_req() - free resouces from sme command for ndp + * and release the cmd + * initiator request + * @mac_ctx: Global MAC context + * @cmd: sme command msg + * + * Return: None + */ +void csr_release_ndp_initiator_req(tpAniSirGlobal mac_ctx, tSmeCmd *cmd) +{ + csr_free_ndp_initiator_req(cmd); + sme_release_command(mac_ctx, cmd); +} + +/** + * csr_release_ndp_responder_req() - free resouces from sme command for ndp + * responder request and release the command + * @mac_ctx: Global MAC context + * @cmd: sme command msg + * + * Return: None + */ +void csr_release_ndp_responder_req(tpAniSirGlobal mac_ctx, tSmeCmd *cmd) +{ + csr_free_ndp_responder_req(cmd); + sme_release_command(mac_ctx, cmd); +} + +/** + * csr_release_ndp_data_end_req() - free resouces from sme command for ndp + * data end request + * @mac_ctx: Global MAC context + * @cmd: sme command msg + * + * Return: None + */ +void csr_release_ndp_data_end_req(tpAniSirGlobal mac_ctx, tSmeCmd *cmd) +{ + qdf_mem_free(cmd->u.data_end_req); + cmd->u.data_end_req = NULL; + sme_release_command(mac_ctx, cmd); +} diff --git a/drivers/staging/qcacld-3.0/core/sme/src/p2p/p2p_api.c b/drivers/staging/qcacld-3.0/core/sme/src/p2p/p2p_api.c new file mode 100644 index 0000000000000000000000000000000000000000..60a7aff3d4949d80d858bb61f582a8a23a9ea349 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/sme/src/p2p/p2p_api.c @@ -0,0 +1,358 @@ +/* + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#include "sme_api.h" +#include "sms_debug.h" +#include "csr_inside_api.h" +#include "sme_inside.h" +#include "p2p_api.h" +#include "cfg_api.h" +#include "wma.h" + +/*------------------------------------------------------------------ + * + * handle SME remain on channel request. + * + *------------------------------------------------------------------*/ + +QDF_STATUS p2p_process_remain_on_channel_cmd(tpAniSirGlobal pMac, + tSmeCmd *p2pRemainonChn) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tSirRemainOnChnReq *pMsg; + uint32_t len; + tCsrRoamSession *pSession = + CSR_GET_SESSION(pMac, p2pRemainonChn->sessionId); + + if (!pSession) { + sms_log(pMac, LOGE, FL(" session %d not found "), + p2pRemainonChn->sessionId); + goto error; + } + + if (!pSession->sessionActive) { + sms_log(pMac, LOGE, + FL(" session %d is invalid or listen is disabled "), + p2pRemainonChn->sessionId); + goto error; + } + len = sizeof(tSirRemainOnChnReq) + pMac->p2pContext.probeRspIeLength; + + if (len > 0xFFFF) { + /*In coming len for Msg is more then 16bit value */ + sms_log(pMac, LOGE, FL(" Message length is very large, %d"), + len); + goto error; + } + + pMsg = qdf_mem_malloc(len); + if (NULL == pMsg) + goto error; + else { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO, "%s call", + __func__); + pMsg->messageType = eWNI_SME_REMAIN_ON_CHANNEL_REQ; + pMsg->length = (uint16_t) len; + qdf_copy_macaddr(&pMsg->selfMacAddr, &pSession->selfMacAddr); + pMsg->chnNum = p2pRemainonChn->u.remainChlCmd.chn; + pMsg->phyMode = p2pRemainonChn->u.remainChlCmd.phyMode; + pMsg->duration = p2pRemainonChn->u.remainChlCmd.duration; + pMsg->sessionId = p2pRemainonChn->sessionId; + pMsg->isProbeRequestAllowed = + p2pRemainonChn->u.remainChlCmd.isP2PProbeReqAllowed; + pMsg->scan_id = p2pRemainonChn->u.remainChlCmd.scan_id; + if (pMac->p2pContext.probeRspIeLength) + qdf_mem_copy((void *)pMsg->probeRspIe, + (void *)pMac->p2pContext.probeRspIe, + pMac->p2pContext.probeRspIeLength); + status = cds_send_mb_message_to_mac(pMsg); + } +error: + if (QDF_STATUS_E_FAILURE == status) + csr_release_roc_req_cmd(pMac); + return status; +} + +/*------------------------------------------------------------------ + * + * handle LIM remain on channel rsp: Success/failure. + * + *------------------------------------------------------------------*/ + +QDF_STATUS sme_remain_on_chn_rsp(tpAniSirGlobal pMac, uint8_t *pMsg) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tListElem *pEntry = NULL; + tSmeCmd *pCommand = NULL; + bool fFound; + remainOnChanCallback callback = NULL; + struct sir_roc_rsp *rsp = (struct sir_roc_rsp *)pMsg; + + csr_get_active_scan_entry(pMac, rsp->scan_id, &pEntry); + if (!pEntry) { + sms_log(pMac, LOGE, FL("No cmd found in active list.")); + return status; + } + + pCommand = GET_BASE_ADDR(pEntry, tSmeCmd, Link); + if (eSmeCommandRemainOnChannel != pCommand->command) + return status; + + callback = pCommand->u.remainChlCmd.callback; + if (callback) + callback(pMac, pCommand->u.remainChlCmd.callbackCtx, + rsp->status, rsp->scan_id); + + fFound = csr_ll_remove_entry(&pMac->sme.smeScanCmdActiveList, pEntry, + LL_ACCESS_LOCK); + if (fFound) { + /* Now put this command back on the avilable command list */ + sme_release_command(pMac, pCommand); + } + sme_process_pending_queue(pMac); + return status; +} + +/*------------------------------------------------------------------ + * + * Handle the remain on channel ready indication from PE + * + *------------------------------------------------------------------*/ + +QDF_STATUS sme_remain_on_chn_ready(tHalHandle hHal, uint8_t *pMsg) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + QDF_STATUS status = QDF_STATUS_SUCCESS; + tListElem *pEntry = NULL; + tSmeCmd *pCommand = NULL; + tCsrRoamInfo RoamInfo; + struct sir_roc_rsp *rsp = (struct sir_roc_rsp *)pMsg; + + csr_get_active_scan_entry(pMac, rsp->scan_id, &pEntry); + if (!pEntry) { + sms_log(pMac, LOGE, FL("No cmd found in active list.")); + return status; + } + sms_log(pMac, LOG1, + FL("Ready Ind %d %d"), rsp->session_id, rsp->scan_id); + pCommand = GET_BASE_ADDR(pEntry, tSmeCmd, Link); + if (eSmeCommandRemainOnChannel == pCommand->command) { + RoamInfo.roc_scan_id = rsp->scan_id; + /* forward the indication to HDD */ + RoamInfo.pRemainCtx = pCommand->u.remainChlCmd.callbackCtx; + csr_roam_call_callback(pMac, rsp->session_id, + &RoamInfo, 0, + eCSR_ROAM_REMAIN_CHAN_READY, 0); + } + + return status; +} + +QDF_STATUS sme_p2p_open(tHalHandle hHal) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + QDF_STATUS status = QDF_STATUS_SUCCESS; + + /* If static structure is too big, Need to change this function to allocate memory dynamically */ + qdf_mem_zero(&pMac->p2pContext, sizeof(tp2pContext)); + + if (!QDF_IS_STATUS_SUCCESS(status)) { + sme_p2p_close(hHal); + } + + return status; +} + +QDF_STATUS p2p_stop(tHalHandle hHal) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + if (pMac->p2pContext.probeRspIe) { + qdf_mem_free(pMac->p2pContext.probeRspIe); + pMac->p2pContext.probeRspIe = NULL; + } + + pMac->p2pContext.probeRspIeLength = 0; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS sme_p2p_close(tHalHandle hHal) +{ + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + if (pMac->p2pContext.probeRspIe) { + qdf_mem_free(pMac->p2pContext.probeRspIe); + pMac->p2pContext.probeRspIe = NULL; + } + + pMac->p2pContext.probeRspIeLength = 0; + + return QDF_STATUS_SUCCESS; +} + +tSirRFBand get_rf_band(uint8_t channel) +{ + if ((channel >= SIR_11A_CHANNEL_BEGIN) && + (channel <= SIR_11A_CHANNEL_END)) + return SIR_BAND_5_GHZ; + + if ((channel >= SIR_11B_CHANNEL_BEGIN) && + (channel <= SIR_11B_CHANNEL_END)) + return SIR_BAND_2_4_GHZ; + + return SIR_BAND_UNKNOWN; +} + +/* --------------------------------------------------------------------------- + + \fn p2p_remain_on_channel + \brief API to post the remain on channel command. + \param hHal - The handle returned by mac_open. + \param sessinId - HDD session ID. + \param channel - Channel to remain on channel. + \param duration - Duration for which we should remain on channel + \param callback - callback function. + \param pContext - argument to the callback function + \return QDF_STATUS + + -------------------------------------------------------------------------------*/ +QDF_STATUS p2p_remain_on_channel(tHalHandle hHal, uint8_t sessionId, + uint8_t channel, uint32_t duration, + remainOnChanCallback callback, + void *pContext, uint8_t isP2PProbeReqAllowed, + uint32_t scan_id) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + tSmeCmd *pRemainChlCmd = NULL; + uint32_t phyMode; + + pRemainChlCmd = sme_get_command_buffer(pMac); + if (pRemainChlCmd == NULL) + return QDF_STATUS_E_FAILURE; + + if (SIR_BAND_5_GHZ == get_rf_band(channel)) { + phyMode = WNI_CFG_PHY_MODE_11A; + } else { + phyMode = WNI_CFG_PHY_MODE_11G; + } + + cfg_set_int(pMac, WNI_CFG_PHY_MODE, phyMode); + + do { + /* call set in context */ + pRemainChlCmd->command = eSmeCommandRemainOnChannel; + pRemainChlCmd->sessionId = sessionId; + pRemainChlCmd->u.remainChlCmd.chn = channel; + pRemainChlCmd->u.remainChlCmd.duration = duration; + pRemainChlCmd->u.remainChlCmd.isP2PProbeReqAllowed = + isP2PProbeReqAllowed; + pRemainChlCmd->u.remainChlCmd.callback = callback; + pRemainChlCmd->u.remainChlCmd.callbackCtx = pContext; + pRemainChlCmd->u.remainChlCmd.scan_id = scan_id; + + /* Put it at the head of the Q if we just finish finding the peer and ready to send a frame */ + status = csr_queue_sme_command(pMac, pRemainChlCmd, false); + } while (0); + + sms_log(pMac, LOGW, "exiting function %s", __func__); + + return status; +} + +QDF_STATUS p2p_send_action(tHalHandle hHal, uint8_t sessionId, + const uint8_t *pBuf, uint32_t len, uint16_t wait, + bool noack, uint16_t channel_freq) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tSirMbMsgP2p *pMsg; + uint16_t msgLen; + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO_MED, + " %s sends action frame", __func__); + msgLen = (uint16_t) ((sizeof(tSirMbMsgP2p)) + len); + pMsg = qdf_mem_malloc(msgLen); + if (NULL == pMsg) + status = QDF_STATUS_E_NOMEM; + else { + pMsg->type = eWNI_SME_SEND_ACTION_FRAME_IND; + pMsg->msgLen = msgLen; + pMsg->sessionId = sessionId; + pMsg->noack = noack; + pMsg->channel_freq = channel_freq; + pMsg->wait = (uint16_t) wait; + qdf_mem_copy(pMsg->data, pBuf, len); + status = cds_send_mb_message_to_mac(pMsg); + } + return status; +} + +QDF_STATUS p2p_cancel_remain_on_channel(tHalHandle hHal, + uint8_t sessionId, uint32_t scan_id) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tSirMbMsgP2p *pMsg; + uint16_t msgLen; + + /* Need to check session ID to support concurrency */ + + msgLen = (uint16_t) (sizeof(tSirMbMsgP2p)); + pMsg = qdf_mem_malloc(msgLen); + if (NULL == pMsg) + status = QDF_STATUS_E_NOMEM; + else { + qdf_mem_set((void *)pMsg, msgLen, 0); + pMsg->type = eWNI_SME_ABORT_REMAIN_ON_CHAN_IND; + pMsg->msgLen = msgLen; + pMsg->sessionId = sessionId; + pMsg->scan_id = scan_id; + status = cds_send_mb_message_to_mac(pMsg); + } + + return status; +} + +QDF_STATUS p2p_set_ps(tHalHandle hHal, tP2pPsConfig *pNoA) +{ + tpP2pPsConfig pNoAParam; + tSirMsgQ msg; + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + + pNoAParam = qdf_mem_malloc(sizeof(tP2pPsConfig)); + if (NULL == pNoAParam) + status = QDF_STATUS_E_NOMEM; + else { + qdf_mem_copy(pNoAParam, pNoA, sizeof(tP2pPsConfig)); + msg.type = eWNI_SME_UPDATE_NOA; + msg.bodyval = 0; + msg.bodyptr = pNoAParam; + lim_post_msg_api(pMac, &msg); + } + return status; +} diff --git a/drivers/staging/qcacld-3.0/core/sme/src/qos/sme_qos.c b/drivers/staging/qcacld-3.0/core/sme/src/qos/sme_qos.c new file mode 100644 index 0000000000000000000000000000000000000000..75cbc420f75f2db7cd5aea988294b086d7379245 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/sme/src/qos/sme_qos.c @@ -0,0 +1,7840 @@ +/* + * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/**========================================================================= + + \file sme_qos.c + + \brief implementation for SME QoS APIs + + ========================================================================*/ +/* $Header$ */ +/*-------------------------------------------------------------------------- + Include Files + ------------------------------------------------------------------------*/ + +#include "ani_global.h" + +#include "sme_inside.h" +#include "host_diag_core_event.h" +#include "host_diag_core_log.h" + +#include "sms_debug.h" +#include "utils_parser.h" +#include "sme_power_save_api.h" + +#ifndef WLAN_MDM_CODE_REDUCTION_OPT +/* TODO : 6Mbps as Cisco APs seem to like only this value; analysis req. */ +#define SME_QOS_MIN_PHY_RATE 0x5B8D80 +#define SME_QOS_SURPLUS_BW_ALLOWANCE 0x2000 /* Ratio of 1.0 */ +/*--------------------------------------------------------------------------- + Max values to bound tspec params against and avoid rollover + ---------------------------------------------------------------------------*/ +#define SME_QOS_32BIT_MAX 0xFFFFFFFF +#define SME_QOS_16BIT_MAX 0xFFFF +#define SME_QOS_16BIT_MSB 0x8000 +/*--------------------------------------------------------------------------- + Adds y to x, but saturates at 32-bit max to avoid rollover + ---------------------------------------------------------------------------*/ +#define SME_QOS_BOUNDED_U32_ADD_Y_TO_X(_x, _y) \ + do { \ + (_x) = ((SME_QOS_32BIT_MAX - (_x)) < (_y)) ? \ + (SME_QOS_32BIT_MAX) : (_x) + (_y); \ + } while (0) + +/*--------------------------------------------------------------------------- + As per WMM spec there could be max 2 TSPEC running on the same AC with + different direction. We will refer each TSPEC with an index + ---------------------------------------------------------------------------*/ +#define SME_QOS_TSPEC_INDEX_0 0 +#define SME_QOS_TSPEC_INDEX_1 1 +#define SME_QOS_TSPEC_INDEX_MAX 2 +#define SME_QOS_TSPEC_MASK_BIT_1_SET 1 +#define SME_QOS_TSPEC_MASK_BIT_2_SET 2 +#define SME_QOS_TSPEC_MASK_BIT_1_2_SET 3 +#define SME_QOS_TSPEC_MASK_CLEAR 0 + +/* which key to search on, in the flowlist (1 = flowID, 2 = AC, 4 = reason) */ +#define SME_QOS_SEARCH_KEY_INDEX_1 1 +#define SME_QOS_SEARCH_KEY_INDEX_2 2 +#define SME_QOS_SEARCH_KEY_INDEX_3 4 +#define SME_QOS_SEARCH_KEY_INDEX_4 8 /* ac + direction */ +#define SME_QOS_SEARCH_KEY_INDEX_5 0x10 /* ac + tspec_mask */ +/* special value for searching any Session Id */ +#define SME_QOS_SEARCH_SESSION_ID_ANY CSR_ROAM_SESSION_MAX +#define SME_QOS_ACCESS_POLICY_EDCA 1 +#define SME_QOS_MAX_TID 255 +#define SME_QOS_TSPEC_IE_LENGTH 61 +#define SME_QOS_TSPEC_IE_TYPE 2 +#define SME_QOS_MIN_FLOW_ID 1 +#define SME_QOS_MAX_FLOW_ID 0xFFFFFFFE +#define SME_QOS_INVALID_FLOW_ID 0xFFFFFFFF +/* per the WMM Specification v1.2 Section 2.2.10 */ +/* The Dialog Token field shall be set [...] to a non-zero value */ +#define SME_QOS_MIN_DIALOG_TOKEN 1 +#define SME_QOS_MAX_DIALOG_TOKEN 0xFF +/*-------------------------------------------------------------------------- + Type declarations + ------------------------------------------------------------------------*/ +/*--------------------------------------------------------------------------- + Enumeration of the various states in the QoS state m/c + ---------------------------------------------------------------------------*/ +typedef enum { + SME_QOS_CLOSED = 0, + SME_QOS_INIT, + SME_QOS_LINK_UP, + SME_QOS_REQUESTED, + SME_QOS_QOS_ON, + SME_QOS_HANDOFF, + +} sme_QosStates; +/*--------------------------------------------------------------------------- + Enumeration of the various Release QoS trigger + ---------------------------------------------------------------------------*/ +typedef enum { + SME_QOS_RELEASE_DEFAULT = 0, + SME_QOS_RELEASE_BY_AP, +} sme_QosRelTriggers; +/*--------------------------------------------------------------------------- + Enumeration of the various QoS cmds + ---------------------------------------------------------------------------*/ +typedef enum { + SME_QOS_SETUP_REQ = 0, + SME_QOS_RELEASE_REQ, + SME_QOS_MODIFY_REQ, + SME_QOS_RESEND_REQ, + SME_QOS_CMD_MAX +} sme_QosCmdType; +/*--------------------------------------------------------------------------- + Enumeration of the various QoS reason codes to be used in the Flow list + ---------------------------------------------------------------------------*/ +typedef enum { + SME_QOS_REASON_SETUP = 0, + SME_QOS_REASON_RELEASE, + SME_QOS_REASON_MODIFY, + SME_QOS_REASON_MODIFY_PENDING, + SME_QOS_REASON_REQ_SUCCESS, + SME_QOS_REASON_MAX +} sme_QosReasonType; + +/*--------------------------------------------------------------------------- + Table to map user priority passed in as an argument to appropriate Access + Category as specified in 802.11e/WMM + ---------------------------------------------------------------------------*/ +sme_QosEdcaAcType sme_qos_u_pto_ac_map[SME_QOS_WMM_UP_MAX] = { + SME_QOS_EDCA_AC_BE, /* User Priority 0 */ + SME_QOS_EDCA_AC_BK, /* User Priority 1 */ + SME_QOS_EDCA_AC_BK, /* User Priority 2 */ + SME_QOS_EDCA_AC_BE, /* User Priority 3 */ + SME_QOS_EDCA_AC_VI, /* User Priority 4 */ + SME_QOS_EDCA_AC_VI, /* User Priority 5 */ + SME_QOS_EDCA_AC_VO, /* User Priority 6 */ + SME_QOS_EDCA_AC_VO /* User Priority 7 */ +}; + +/*--------------------------------------------------------------------------- + Table to map access category (AC) to appropriate user priority as specified + in 802.11e/WMM + Note: there is a quantization loss here because 4 ACs are mapped to 8 UPs + Mapping is done for consistency + ---------------------------------------------------------------------------*/ +sme_QosWmmUpType sme_qos_a_cto_up_map[SME_QOS_EDCA_AC_MAX] = { + SME_QOS_WMM_UP_BE, /* AC BE */ + SME_QOS_WMM_UP_BK, /* AC BK */ + SME_QOS_WMM_UP_VI, /* AC VI */ + SME_QOS_WMM_UP_VO /* AC VO */ +}; + +/*--------------------------------------------------------------------------- + DESCRIPTION + SME QoS module's FLOW Link List structure. This list can hold information per + flow/request, like TSPEC params requested, which AC it is running on + ---------------------------------------------------------------------------*/ +typedef struct sme_QosFlowInfoEntry_s { + tListElem link; /* list links */ + uint8_t sessionId; + uint8_t tspec_mask; + sme_QosReasonType reason; + uint32_t QosFlowID; + sme_QosEdcaAcType ac_type; + sme_QosWmmTspecInfo QoSInfo; + void *HDDcontext; + sme_QosCallback QoSCallback; + bool hoRenewal; /* set to true while re-negotiating flows after */ + /* handoff, will set to false once done with */ + /* the process. Helps SME to decide if at all */ + /* to notify HDD/LIS for flow renewal after HO */ +} sme_QosFlowInfoEntry; +/*--------------------------------------------------------------------------- + DESCRIPTION + SME QoS module's setup request cmd related information structure. + ---------------------------------------------------------------------------*/ +typedef struct sme_qos_setupCmdInfo_s { + uint32_t QosFlowID; + sme_QosWmmTspecInfo QoSInfo; + void *HDDcontext; + sme_QosCallback QoSCallback; + sme_QosWmmUpType UPType; + bool hoRenewal; /* set to true while re-negotiating flows after */ + /* handoff, will set to false once done with */ + /* the process. Helps SME to decide if at all */ + /* to notify HDD/LIS for flow renewal after HO */ +} sme_qos_setupCmdInfo; +/*--------------------------------------------------------------------------- + DESCRIPTION + SME QoS module's modify cmd related information structure. + ---------------------------------------------------------------------------*/ +typedef struct sme_QosModifyCmdInfo_s { + uint32_t QosFlowID; + sme_QosEdcaAcType ac; + sme_QosWmmTspecInfo QoSInfo; +} sme_QosModifyCmdInfo; +/*--------------------------------------------------------------------------- + DESCRIPTION + SME QoS module's resend cmd related information structure. + ---------------------------------------------------------------------------*/ +typedef struct sme_QosResendCmdInfo_s { + uint8_t tspecMask; + sme_QosEdcaAcType ac; + sme_QosWmmTspecInfo QoSInfo; +} sme_QosResendCmdInfo; +/*--------------------------------------------------------------------------- + DESCRIPTION + SME QoS module's release cmd related information structure. + ---------------------------------------------------------------------------*/ +typedef struct sme_QosReleaseCmdInfo_s { + uint32_t QosFlowID; +} sme_QosReleaseCmdInfo; +/*--------------------------------------------------------------------------- + DESCRIPTION + SME QoS module's buffered cmd related information structure. + ---------------------------------------------------------------------------*/ +typedef struct sme_QosCmdInfo_s { + sme_QosCmdType command; + tpAniSirGlobal pMac; + uint8_t sessionId; + union { + sme_qos_setupCmdInfo setupCmdInfo; + sme_QosModifyCmdInfo modifyCmdInfo; + sme_QosResendCmdInfo resendCmdInfo; + sme_QosReleaseCmdInfo releaseCmdInfo; + } u; +} sme_QosCmdInfo; +/*--------------------------------------------------------------------------- + DESCRIPTION + SME QoS module's buffered cmd List structure. This list can hold information + related to any pending cmd from HDD + ---------------------------------------------------------------------------*/ +typedef struct sme_QosCmdInfoEntry_s { + tListElem link; /* list links */ + sme_QosCmdInfo cmdInfo; +} sme_QosCmdInfoEntry; +/*--------------------------------------------------------------------------- + DESCRIPTION + SME QoS module's Per AC information structure. This can hold information on + how many flows running on the AC, the current, previous states the AC is in + ---------------------------------------------------------------------------*/ +typedef struct sme_QosACInfo_s { + uint8_t num_flows[SME_QOS_TSPEC_INDEX_MAX]; + sme_QosStates curr_state; + sme_QosStates prev_state; + sme_QosWmmTspecInfo curr_QoSInfo[SME_QOS_TSPEC_INDEX_MAX]; + sme_QosWmmTspecInfo requested_QoSInfo[SME_QOS_TSPEC_INDEX_MAX]; + /* reassoc requested for APSD */ + bool reassoc_pending; + /* + * As per WMM spec there could be max 2 TSPEC running on the same + * AC with different direction. We will refer each TSPEC with an index + */ + /* status showing if both the indices are in use */ + uint8_t tspec_mask_status; + /* tspec negotiation going on for which index */ + uint8_t tspec_pending; + /* set to true while re-negotiating flows after */ + bool hoRenewal; + /* + * handoff, will set to false once done with the process. Helps SME to + * decide if at all to notify HDD/LIS for flow renewal after HO + */ + uint8_t ricIdentifier[SME_QOS_TSPEC_INDEX_MAX]; + /* + * stores the ADD TS response for each AC. The ADD TS response is + * formed by parsing the RIC received in the the reassoc response + */ + tSirAddtsRsp addTsRsp[SME_QOS_TSPEC_INDEX_MAX]; + sme_QosRelTriggers relTrig; + +} sme_QosACInfo; +/*--------------------------------------------------------------------------- + DESCRIPTION + SME QoS module's Per session information structure. This can hold information + on the state of the session + ---------------------------------------------------------------------------*/ +typedef struct sme_QosSessionInfo_s { + /* what is this entry's session id */ + uint8_t sessionId; + /* is the session currently active */ + bool sessionActive; + /* All AC info for this session */ + sme_QosACInfo ac_info[SME_QOS_EDCA_AC_MAX]; + /* Bitmask of the ACs with APSD on */ + /* Bit0:VO; Bit1:VI; Bit2:BK; Bit3:BE all other bits are ignored */ + uint8_t apsdMask; + /* association information for this session */ + sme_QosAssocInfo assocInfo; + /* ID assigned to our reassoc request */ + uint32_t roamID; + /* maintaining a powersave status in QoS module, to be fed back to PMC at */ + /* times through the sme_qos_pmc_check_routine */ + bool readyForPowerSave; + /* are we in the process of handing off to a different AP */ + bool handoffRequested; + /* following reassoc or AddTS has UAPSD already been requested from PMC */ + bool uapsdAlreadyRequested; + /* commands that are being buffered for this session */ + tDblLinkList bufferedCommandList; + + bool ftHandoffInProgress; + +} sme_QosSessionInfo; +/*--------------------------------------------------------------------------- + DESCRIPTION + Search key union. We can use the flowID, ac type, or reason to find an entry + in the flow list + ---------------------------------------------------------------------------*/ +typedef union sme_QosSearchKey_s { + uint32_t QosFlowID; + sme_QosEdcaAcType ac_type; + sme_QosReasonType reason; +} sme_QosSearchKey; +/*--------------------------------------------------------------------------- + DESCRIPTION + We can either use the flowID or the ac type to find an entry in the flow list. + The index is a bitmap telling us which key to use. Starting from LSB, + bit 0 - Flow ID + bit 1 - AC type + ---------------------------------------------------------------------------*/ +typedef struct sme_QosSearchInfo_s { + uint8_t sessionId; + uint8_t index; + sme_QosSearchKey key; + sme_QosWmmDirType direction; + uint8_t tspec_mask; +} sme_QosSearchInfo; +/*--------------------------------------------------------------------------- + DESCRIPTION + SME QoS module's internal control block. + ---------------------------------------------------------------------------*/ +struct sme_qos_cb_s { + /* global Mac pointer */ + tpAniSirGlobal pMac; + /* All Session Info */ + sme_QosSessionInfo sessionInfo[CSR_ROAM_SESSION_MAX]; + /* All FLOW info */ + tDblLinkList flow_list; + /* default TSPEC params */ + sme_QosWmmTspecInfo def_QoSInfo[SME_QOS_EDCA_AC_MAX]; + /* counter for assigning Flow IDs */ + uint32_t nextFlowId; + /* counter for assigning Dialog Tokens */ + uint8_t nextDialogToken; +} sme_qos_cb; +typedef QDF_STATUS (*sme_QosProcessSearchEntry)(tpAniSirGlobal pMac, + tListElem *pEntry); + +sme_QosStatusType sme_qos_internal_setup_req(tpAniSirGlobal pMac, + uint8_t sessionId, + sme_QosWmmTspecInfo *pQoSInfo, + sme_QosCallback QoSCallback, + void *HDDcontext, + sme_QosWmmUpType UPType, + uint32_t QosFlowID, + bool buffered_cmd, bool hoRenewal); +sme_QosStatusType sme_qos_internal_modify_req(tpAniSirGlobal pMac, + sme_QosWmmTspecInfo *pQoSInfo, + uint32_t QosFlowID, + bool buffered_cmd); +sme_QosStatusType sme_qos_internal_release_req(tpAniSirGlobal pMac, + uint8_t session_id, + uint32_t QosFlowID, + bool buffered_cmd); +sme_QosStatusType sme_qos_setup(tpAniSirGlobal pMac, + uint8_t sessionId, + sme_QosWmmTspecInfo *pTspec_Info, + sme_QosEdcaAcType ac); +QDF_STATUS sme_qos_add_ts_req(tpAniSirGlobal pMac, + uint8_t sessionId, + sme_QosWmmTspecInfo *pTspec_Info, + sme_QosEdcaAcType ac); +QDF_STATUS sme_qos_del_ts_req(tpAniSirGlobal pMac, + uint8_t sessionId, + sme_QosEdcaAcType ac, uint8_t tspec_mask); +QDF_STATUS sme_qos_process_add_ts_rsp(tpAniSirGlobal pMac, void *pMsgBuf); +QDF_STATUS sme_qos_process_del_ts_ind(tpAniSirGlobal pMac, void *pMsgBuf); +QDF_STATUS sme_qos_process_del_ts_rsp(tpAniSirGlobal pMac, void *pMsgBuf); +QDF_STATUS sme_qos_process_assoc_complete_ev(tpAniSirGlobal pMac, uint8_t sessionId, + void *pEvent_info); +QDF_STATUS sme_qos_process_reassoc_req_ev(tpAniSirGlobal pMac, uint8_t sessionId, + void *pEvent_info); +QDF_STATUS sme_qos_process_reassoc_success_ev(tpAniSirGlobal pMac, + uint8_t sessionId, void *pEvent_info); +QDF_STATUS sme_qos_process_reassoc_failure_ev(tpAniSirGlobal pMac, + uint8_t sessionId, void *pEvent_info); +QDF_STATUS sme_qos_process_disconnect_ev(tpAniSirGlobal pMac, uint8_t sessionId, + void *pEvent_info); +QDF_STATUS sme_qos_process_join_req_ev(tpAniSirGlobal pMac, uint8_t sessionId, + void *pEvent_info); +QDF_STATUS sme_qos_process_handoff_assoc_req_ev(tpAniSirGlobal pMac, + uint8_t sessionId, + void *pEvent_info); +QDF_STATUS sme_qos_process_handoff_success_ev(tpAniSirGlobal pMac, + uint8_t sessionId, void *pEvent_info); +QDF_STATUS sme_qos_process_handoff_failure_ev(tpAniSirGlobal pMac, + uint8_t sessionId, void *pEvent_info); +QDF_STATUS sme_qos_process_preauth_success_ind(tpAniSirGlobal pMac, + uint8_t sessionId, + void *pEvent_info); +QDF_STATUS sme_qos_process_set_key_success_ind(tpAniSirGlobal pMac, + uint8_t sessionId, void *pEvent_info); +QDF_STATUS sme_qos_process_aggr_qos_rsp(tpAniSirGlobal pMac, void *pMsgBuf); +QDF_STATUS sme_qos_ft_aggr_qos_req(tpAniSirGlobal pMac, uint8_t sessionId); +QDF_STATUS sme_qos_process_add_ts_success_rsp(tpAniSirGlobal pMac, + uint8_t sessionId, + tSirAddtsRspInfo *pRsp); +QDF_STATUS sme_qos_process_add_ts_failure_rsp(tpAniSirGlobal pMac, + uint8_t sessionId, + tSirAddtsRspInfo *pRsp); +QDF_STATUS sme_qos_aggregate_params(sme_QosWmmTspecInfo *pInput_Tspec_Info, + sme_QosWmmTspecInfo *pCurrent_Tspec_Info, + sme_QosWmmTspecInfo *pUpdated_Tspec_Info); +static QDF_STATUS sme_qos_update_params(uint8_t sessionId, + sme_QosEdcaAcType ac, + uint8_t tspec_mask, + sme_QosWmmTspecInfo *pTspec_Info); +sme_QosWmmUpType sme_qos_ac_to_up(sme_QosEdcaAcType ac); +sme_QosEdcaAcType sme_qos_up_to_ac(sme_QosWmmUpType up); +bool sme_qos_is_acm(tpAniSirGlobal pMac, tSirBssDescription *pSirBssDesc, + sme_QosEdcaAcType ac, tDot11fBeaconIEs *pIes); +tListElem *sme_qos_find_in_flow_list(sme_QosSearchInfo search_key); +QDF_STATUS sme_qos_find_all_in_flow_list(tpAniSirGlobal pMac, + sme_QosSearchInfo search_key, + sme_QosProcessSearchEntry fnp); +static void sme_qos_state_transition(uint8_t sessionId, + sme_QosEdcaAcType ac, + sme_QosStates new_state); +QDF_STATUS sme_qos_buffer_cmd(sme_QosCmdInfo *pcmd, bool insert_head); +static QDF_STATUS sme_qos_process_buffered_cmd(uint8_t sessionId); +QDF_STATUS sme_qos_save_assoc_info(sme_QosSessionInfo *pSession, + sme_QosAssocInfo *pAssoc_info); +QDF_STATUS sme_qos_setup_fnp(tpAniSirGlobal pMac, tListElem *pEntry); +QDF_STATUS sme_qos_modification_notify_fnp(tpAniSirGlobal pMac, + tListElem *pEntry); +QDF_STATUS sme_qos_modify_fnp(tpAniSirGlobal pMac, tListElem *pEntry); +QDF_STATUS sme_qos_del_ts_ind_fnp(tpAniSirGlobal pMac, tListElem *pEntry); +QDF_STATUS sme_qos_reassoc_success_ev_fnp(tpAniSirGlobal pMac, tListElem *pEntry); +QDF_STATUS sme_qos_add_ts_failure_fnp(tpAniSirGlobal pMac, tListElem *pEntry); +QDF_STATUS sme_qos_add_ts_success_fnp(tpAniSirGlobal pMac, tListElem *pEntry); +static bool sme_qos_is_rsp_pending(uint8_t sessionId, sme_QosEdcaAcType ac); +static bool sme_qos_is_uapsd_active(void); + +void sme_qos_pmc_offload_start_uapsd_callback(void *callbackContext, + uint32_t sessionId, QDF_STATUS status); +bool sme_qos_pmc_offload_check_routine(void *callbackContext, uint32_t sessionId); + +static QDF_STATUS sme_qos_buffer_existing_flows(tpAniSirGlobal pMac, + uint8_t sessionId); +static QDF_STATUS sme_qos_delete_existing_flows(tpAniSirGlobal pMac, + uint8_t sessionId); +static void sme_qos_cleanup_ctrl_blk_for_handoff(tpAniSirGlobal pMac, + uint8_t sessionId); +static QDF_STATUS sme_qos_delete_buffered_requests(tpAniSirGlobal pMac, + uint8_t sessionId); +bool sme_qos_validate_requested_params(tpAniSirGlobal pMac, + sme_QosWmmTspecInfo *pQoSInfo, + uint8_t sessionId); + +extern QDF_STATUS sme_acquire_global_lock(tSmeStruct *psSme); +extern QDF_STATUS sme_release_global_lock(tSmeStruct *psSme); +static QDF_STATUS qos_issue_command(tpAniSirGlobal pMac, uint8_t sessionId, + eSmeCommandType cmdType, + sme_QosWmmTspecInfo *pQoSInfo, + sme_QosEdcaAcType ac, uint8_t tspec_mask); +/* + sme_qos_re_request_add_ts to re-send AddTS for the combined QoS request + */ +static sme_QosStatusType sme_qos_re_request_add_ts(tpAniSirGlobal pMac, + uint8_t sessionId, + sme_QosWmmTspecInfo *pQoSInfo, + sme_QosEdcaAcType ac, + uint8_t tspecMask); +static void sme_qos_init_a_cs(tpAniSirGlobal pMac, uint8_t sessionId); +static QDF_STATUS sme_qos_request_reassoc(tpAniSirGlobal pMac, uint8_t sessionId, + tCsrRoamModifyProfileFields * + pModFields, bool fForce); +static uint32_t sme_qos_assign_flow_id(void); +static uint8_t sme_qos_assign_dialog_token(void); +static QDF_STATUS sme_qos_update_tspec_mask(uint8_t sessionId, + sme_QosSearchInfo search_key, + uint8_t new_tspec_mask); + +/* External APIs definitions */ + +/** + * sme_qos_open() - called to initialize SME QoS module. + * @pMac: global MAC context + * + * This function must be called before any API call to + * SME QoS module. + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_qos_open(tpAniSirGlobal pMac) +{ + sme_QosSessionInfo *pSession; + uint8_t sessionId; + QDF_STATUS status; + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: initializing SME-QoS module", __func__, __LINE__); + /* init the control block */ + /* (note that this will make all sessions invalid) */ + qdf_mem_zero(&sme_qos_cb, sizeof(sme_qos_cb)); + sme_qos_cb.pMac = pMac; + sme_qos_cb.nextFlowId = SME_QOS_MIN_FLOW_ID; + sme_qos_cb.nextDialogToken = SME_QOS_MIN_DIALOG_TOKEN; + /* init flow list */ + status = csr_ll_open(pMac->hHdd, &sme_qos_cb.flow_list); + if (!QDF_IS_STATUS_SUCCESS(status)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_FATAL, + "%s: %d: cannot initialize Flow List", + __func__, __LINE__); + return QDF_STATUS_E_FAILURE; + } + + for (sessionId = 0; sessionId < CSR_ROAM_SESSION_MAX; ++sessionId) { + pSession = &sme_qos_cb.sessionInfo[sessionId]; + pSession->sessionId = sessionId; + /* initialize the session's per-AC information */ + sme_qos_init_a_cs(pMac, sessionId); + /* initialize the session's buffered command list */ + status = csr_ll_open(pMac->hHdd, &pSession->bufferedCommandList); + if (!QDF_IS_STATUS_SUCCESS(status)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_FATAL, + "%s: %d: cannot initialize cmd list for session %d", + __func__, __LINE__, sessionId); + return QDF_STATUS_E_FAILURE; + } + pSession->readyForPowerSave = true; + } + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: done initializing SME-QoS module", + __func__, __LINE__); + return QDF_STATUS_SUCCESS; +} + +/* -------------------------------------------------------------------------- + \brief sme_qos_close() - To close down SME QoS module. There should not be + any API call into this module after calling this function until another + call of sme_qos_open. + \param pMac - Pointer to the global MAC parameter structure. + + \return QDF_STATUS + ----------------------------------------------------------------------------*/ +QDF_STATUS sme_qos_close(tpAniSirGlobal pMac) +{ + sme_QosSessionInfo *pSession; + sme_QosEdcaAcType ac; + uint8_t sessionId; + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: closing down SME-QoS", __func__, __LINE__); + + /* cleanup control block */ + /* close the flow list */ + csr_ll_close(&sme_qos_cb.flow_list); + /* shut down all of the sessions */ + for (sessionId = 0; sessionId < CSR_ROAM_SESSION_MAX; ++sessionId) { + pSession = &sme_qos_cb.sessionInfo[sessionId]; + if (pSession == NULL) + continue; + + sme_qos_init_a_cs(pMac, sessionId); + /* this session doesn't require UAPSD */ + pSession->apsdMask = 0; + + pSession->uapsdAlreadyRequested = false; + pSession->handoffRequested = false; + pSession->readyForPowerSave = true; + pSession->roamID = 0; + /* need to clean up buffered req */ + sme_qos_delete_buffered_requests(pMac, sessionId); + /* need to clean up flows */ + sme_qos_delete_existing_flows(pMac, sessionId); + + /* Clean up the assoc info if already allocated */ + if (pSession->assocInfo.pBssDesc) { + qdf_mem_free(pSession->assocInfo.pBssDesc); + pSession->assocInfo.pBssDesc = NULL; + } + /* close the session's buffered command list */ + csr_ll_close(&pSession->bufferedCommandList); + for (ac = SME_QOS_EDCA_AC_BE; ac < SME_QOS_EDCA_AC_MAX; ac++) { + sme_qos_state_transition(sessionId, ac, SME_QOS_CLOSED); + } + pSession->sessionActive = false; + pSession->readyForPowerSave = true; + } + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: closed down QoS", __func__, __LINE__); + return QDF_STATUS_SUCCESS; +} + +/** + * sme_qos_setup_req() - The SME QoS API exposed to HDD to request for QoS + * on a particular AC. + * @hHal: The handle returned by mac_open. + * @sessionId: sessionId returned by sme_open_session. + * @pQoSInfo: Pointer to sme_QosWmmTspecInfo which contains the WMM TSPEC + * related info as defined above, provided by HDD + * @QoSCallback: The callback which is registered per flow while + * requesting for QoS. Used for any notification for the + * flow (i.e. setup success/failure/release) which needs to + * be sent to HDD + * @HDDcontext: A cookie passed by HDD to be used by SME during any QoS + * notification (through the callabck) to HDD + * @UPType: Useful only if HDD or any other upper layer module (BAP etc.) + * looking for implicit QoS setup, in that + * case, the pQoSInfo will be NULL & SME will know about the AC + * (from the UP provided in this param) QoS is requested on + * @pQosFlowID: Identification per flow running on each AC generated by + * SME. It is only meaningful if the QoS setup for the flow is + * successful + * This function should be called after a link has been + * established, i.e. STA is associated with an AP etc. If the request involves + * admission control on the requested AC, HDD needs to provide the necessary + * Traffic Specification (TSPEC) parameters otherwise SME is going to use the + * default params. + * Return: QDF_STATUS_SUCCESS - Setup is successful. + * Other status means Setup request failed + */ +sme_QosStatusType sme_qos_setup_req(tHalHandle hHal, uint32_t sessionId, + sme_QosWmmTspecInfo *pQoSInfo, + sme_QosCallback QoSCallback, + void *HDDcontext, + sme_QosWmmUpType UPType, + uint32_t *pQosFlowID) +{ + sme_QosSessionInfo *pSession; + QDF_STATUS lock_status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + sme_QosStatusType status; + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: QoS Setup requested by client on session %d", + __func__, __LINE__, sessionId); + lock_status = sme_acquire_global_lock(&pMac->sme); + if (!QDF_IS_STATUS_SUCCESS(lock_status)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: Unable to obtain lock", __func__, __LINE__); + return SME_QOS_STATUS_SETUP_FAILURE_RSP; + } + /* Make sure the session is valid */ + if (!CSR_IS_SESSION_VALID(pMac, sessionId)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: Supplied Session ID %d is invalid", + __func__, __LINE__, sessionId); + status = SME_QOS_STATUS_SETUP_FAILURE_RSP; + } else { + /* Make sure the session is active */ + pSession = &sme_qos_cb.sessionInfo[sessionId]; + if (!pSession->sessionActive) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: Supplied Session ID %d is inactive", + __func__, __LINE__, sessionId); + status = SME_QOS_STATUS_SETUP_FAILURE_RSP; + } else { + /* Assign a Flow ID */ + *pQosFlowID = sme_qos_assign_flow_id(); + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: QoS request on session %d assigned Flow ID %d", + __func__, __LINE__, sessionId, *pQosFlowID); + /* Call the internal function for QoS setup, */ + /* adding a layer of abstraction */ + status = + sme_qos_internal_setup_req(pMac, (uint8_t) sessionId, + pQoSInfo, QoSCallback, + HDDcontext, UPType, + *pQosFlowID, false, + false); + } + } + sme_release_global_lock(&pMac->sme); + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: QoS setup return status on session %d is %d", + __func__, __LINE__, sessionId, status); + return status; +} + +/** + * sme_qos_modify_req() - The SME QoS API exposed to HDD to request for + * modification of certain QoS params on a flow running on a particular AC. + * @hHal: The handle returned by mac_open. + * @pQoSInfo: Pointer to sme_QosWmmTspecInfo which contains the WMM TSPEC + * related info as defined above, provided by HDD + * @QosFlowID: Identification per flow running on each AC generated by + * SME. It is only meaningful if the QoS setup for the flow has + * been successful already + * + * This function should be called after a link has been established, + * i.e. STA is associated with an AP etc. & a QoS setup has been succesful for + * that flow. If the request involves admission control on the requested AC, + * HDD needs to provide the necessary Traffic Specification (TSPEC) parameters & + * SME might start the renegotiation process through ADDTS. + * + * Return: SME_QOS_STATUS_SETUP_SUCCESS_RSP - Modification is successful. + * Other status means request failed + */ +sme_QosStatusType sme_qos_modify_req(tHalHandle hHal, + sme_QosWmmTspecInfo *pQoSInfo, + uint32_t QosFlowID) +{ + QDF_STATUS lock_status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + sme_QosStatusType status; + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: QoS Modify requested by client for Flow %d", + __func__, __LINE__, QosFlowID); + lock_status = sme_acquire_global_lock(&pMac->sme); + if (!QDF_IS_STATUS_SUCCESS(lock_status)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: Unable to obtain lock", __func__, __LINE__); + return SME_QOS_STATUS_MODIFY_SETUP_FAILURE_RSP; + } + /* Call the internal function for QoS modify, adding a layer of abstraction */ + status = sme_qos_internal_modify_req(pMac, pQoSInfo, QosFlowID, false); + sme_release_global_lock(&pMac->sme); + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: QoS Modify return status on Flow %d is %d", + __func__, __LINE__, QosFlowID, status); + return status; +} + +/** + * sme_qos_release_req() - The SME QoS API exposed to HDD to request for + * releasing a QoS flow running on a particular AC. + * + * @hHal: The handle returned by mac_open. + * @session_id: session_id returned by sme_open_session. + * @QosFlowID: Identification per flow running on each AC generated by SME + * It is only meaningful if the QoS setup for the flow is successful + * + * This function should be called only if a QoS is set up with a valid FlowID. + * HDD sould invoke this API only if an explicit request for QoS release has + * come from Application + * + * Return: QDF_STATUS_SUCCESS - Release is successful. + */ +sme_QosStatusType sme_qos_release_req(tHalHandle hHal, uint8_t session_id, + uint32_t QosFlowID) +{ + QDF_STATUS lock_status = QDF_STATUS_E_FAILURE; + tpAniSirGlobal pMac = PMAC_STRUCT(hHal); + sme_QosStatusType status; + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: QoS Release requested by client for Flow %d", + __func__, __LINE__, QosFlowID); + lock_status = sme_acquire_global_lock(&pMac->sme); + if (!QDF_IS_STATUS_SUCCESS(lock_status)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: Unable to obtain lock", __func__, __LINE__); + return SME_QOS_STATUS_RELEASE_FAILURE_RSP; + } + /* Call the internal function for QoS release, adding a layer of abstraction */ + status = sme_qos_internal_release_req(pMac, session_id, QosFlowID, + false); + sme_release_global_lock(&pMac->sme); + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: QoS Release return status on Flow %d is %d", + __func__, __LINE__, QosFlowID, status); + return status; +} + +void qos_release_command(tpAniSirGlobal pMac, tSmeCmd *pCommand) +{ + qdf_mem_zero(&pCommand->u.qosCmd, sizeof(tGenericQosCmd)); + sme_release_command(pMac, pCommand); +} + +/** + * sme_qos_msg_processor() - Processes QOS messages + * @mac_ctx: Pointer to the global MAC parameter structure. + * @msg_type: the type of msg passed by PE as defined in wni_api.h + * @msg: a pointer to a buffer that maps to various structures bases. + * + * sme_process_msg() calls this function for the messages that + * are handled by SME QoS module. + * + * Return: QDF_STATUS enumeration. + */ +QDF_STATUS sme_qos_msg_processor(tpAniSirGlobal mac_ctx, + uint16_t msg_type, void *msg) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tListElem *entry = NULL; + tSmeCmd *command; + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO_HIGH, + FL(" msg = %d for QoS"), msg_type); + /* switch on the msg type & make the state transition accordingly */ + switch (msg_type) { + case eWNI_SME_ADDTS_RSP: + entry = csr_ll_peek_head(&mac_ctx->sme.smeCmdActiveList, + LL_ACCESS_LOCK); + if (NULL == entry) + break; + command = GET_BASE_ADDR(entry, tSmeCmd, Link); + if (eSmeCommandAddTs == command->command) { + status = sme_qos_process_add_ts_rsp(mac_ctx, msg); + if (csr_ll_remove_entry + (&mac_ctx->sme.smeCmdActiveList, entry, + LL_ACCESS_LOCK)) { + qos_release_command(mac_ctx, command); + } + sme_process_pending_queue(mac_ctx); + } + break; + case eWNI_SME_DELTS_RSP: + entry = + csr_ll_peek_head(&mac_ctx->sme.smeCmdActiveList, + LL_ACCESS_LOCK); + if (NULL == entry) + break; + command = GET_BASE_ADDR(entry, tSmeCmd, Link); + if (eSmeCommandDelTs == command->command) { + status = sme_qos_process_del_ts_rsp(mac_ctx, msg); + if (csr_ll_remove_entry + (&mac_ctx->sme.smeCmdActiveList, entry, + LL_ACCESS_LOCK)) { + qos_release_command(mac_ctx, command); + } + sme_process_pending_queue(mac_ctx); + } + break; + case eWNI_SME_DELTS_IND: + status = sme_qos_process_del_ts_ind(mac_ctx, msg); + break; + case eWNI_SME_FT_AGGR_QOS_RSP: + status = sme_qos_process_aggr_qos_rsp(mac_ctx, msg); + break; + default: + /* err msg */ + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("unknown msg type = %d"), + msg_type); + break; + } + return status; +} + +/** + * sme_qos_validate_params() - validate SME QOS parameters. + * @pMac: Pointer to the global MAC parameter structure. + * @pBssDesc: Pointer to the BSS Descriptor information passed down by + * CSR to PE while issuing the Join request + * + * The SME QoS API exposed to CSR to validate AP + * capabilities regarding QoS support & any other QoS parameter validation. + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_qos_validate_params(tpAniSirGlobal pMac, + tSirBssDescription *pBssDesc) +{ + tDot11fBeaconIEs *pIes = NULL; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: validation for QAP & APSD", __func__, __LINE__); + do { + if (!QDF_IS_STATUS_SUCCESS( + csr_get_parsed_bss_description_ies( + pMac, pBssDesc, &pIes))) { + /* err msg */ + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: csr_get_parsed_bss_description_ies() failed", + __func__, __LINE__); + break; + } + /* check if the AP is QAP & it supports APSD */ + if (!CSR_IS_QOS_BSS(pIes)) { + /* err msg */ + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: AP doesn't support QoS", + __func__, __LINE__); + + break; + } + if (!(pIes->WMMParams.qosInfo & SME_QOS_AP_SUPPORTS_APSD) && + !(pIes->WMMInfoAp.uapsd)) { + /* err msg */ + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: AP doesn't support APSD", + __func__, __LINE__); + break; + } + status = QDF_STATUS_SUCCESS; + } while (0); + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: validated with status = %d", + __func__, __LINE__, status); + if (pIes) { + qdf_mem_free(pIes); + } + return status; +} + +void sme_qos_remove_addts_delts_cmd(tpAniSirGlobal mac_ctx, uint8_t session_id) +{ + tListElem *entry; + tSmeCmd *command; + + entry = csr_ll_peek_head(&mac_ctx->sme.smeCmdActiveList, + LL_ACCESS_LOCK); + if (NULL == entry) + return; + command = GET_BASE_ADDR(entry, tSmeCmd, Link); + if ((eSmeCommandAddTs == command->command || + eSmeCommandDelTs == command->command) && + command->sessionId == session_id) { + if (csr_ll_remove_entry(&mac_ctx->sme.smeCmdActiveList, entry, + LL_ACCESS_LOCK)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO, + "%s: removed addts/delts command", __func__); + qos_release_command(mac_ctx, command); + } + } +} + +/*-------------------------------------------------------------------------- + \brief sme_qos_csr_event_ind() - The QoS sub-module in SME expects notifications + from CSR when certain events occur as mentioned in sme_qos_csr_event_indType. + \param pMac - Pointer to the global MAC parameter structure. + \param ind - The event occurred of type sme_qos_csr_event_indType. + \param pEvent_info - Information related to the event + + \return QDF_STATUS + + \sa + + --------------------------------------------------------------------------*/ +QDF_STATUS sme_qos_csr_event_ind(tpAniSirGlobal pMac, + uint8_t sessionId, + sme_qos_csr_event_indType ind, void *pEvent_info) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: On Session %d Event %d received from CSR", + __func__, __LINE__, sessionId, ind); + switch (ind) { + case SME_QOS_CSR_ASSOC_COMPLETE: + /* expecting assoc info in pEvent_info */ + status = + sme_qos_process_assoc_complete_ev(pMac, sessionId, pEvent_info); + break; + case SME_QOS_CSR_REASSOC_REQ: + /* nothing expected in pEvent_info */ + status = + sme_qos_process_reassoc_req_ev(pMac, sessionId, pEvent_info); + break; + case SME_QOS_CSR_REASSOC_COMPLETE: + /* expecting assoc info in pEvent_info */ + status = + sme_qos_process_reassoc_success_ev(pMac, sessionId, + pEvent_info); + break; + case SME_QOS_CSR_REASSOC_FAILURE: + /* nothing expected in pEvent_info */ + status = + sme_qos_process_reassoc_failure_ev(pMac, sessionId, + pEvent_info); + break; + case SME_QOS_CSR_DISCONNECT_REQ: + case SME_QOS_CSR_DISCONNECT_IND: + /* nothing expected in pEvent_info */ + status = + sme_qos_process_disconnect_ev(pMac, sessionId, pEvent_info); + break; + case SME_QOS_CSR_JOIN_REQ: + /* nothing expected in pEvent_info */ + status = sme_qos_process_join_req_ev(pMac, sessionId, pEvent_info); + break; + case SME_QOS_CSR_HANDOFF_ASSOC_REQ: + /* nothing expected in pEvent_info */ + status = + sme_qos_process_handoff_assoc_req_ev(pMac, sessionId, + pEvent_info); + break; + case SME_QOS_CSR_HANDOFF_COMPLETE: + /* nothing expected in pEvent_info */ + status = + sme_qos_process_handoff_success_ev(pMac, sessionId, + pEvent_info); + break; + case SME_QOS_CSR_HANDOFF_FAILURE: + /* nothing expected in pEvent_info */ + status = + sme_qos_process_handoff_failure_ev(pMac, sessionId, + pEvent_info); + break; + case SME_QOS_CSR_PREAUTH_SUCCESS_IND: + status = + sme_qos_process_preauth_success_ind(pMac, sessionId, + pEvent_info); + break; + case SME_QOS_CSR_SET_KEY_SUCCESS_IND: + status = + sme_qos_process_set_key_success_ind(pMac, sessionId, + pEvent_info); + break; + default: + /* Err msg */ + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: On Session %d Unknown Event %d received from CSR", + __func__, __LINE__, sessionId, ind); + break; + } + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: On Session %d processed Event %d with status %d", + __func__, __LINE__, sessionId, ind, status); + return status; +} + +/*-------------------------------------------------------------------------- + \brief sme_qos_get_acm_mask() - The QoS sub-module API to find out on which ACs + AP mandates Admission Control (ACM = 1) + (Bit0:VO; Bit1:VI; Bit2:BK; Bit3:BE all other bits are ignored) + \param pMac - Pointer to the global MAC parameter structure. + \param pSirBssDesc - The event occurred of type sme_qos_csr_event_indType. + + \return a bit mask indicating for which ACs AP has ACM set to 1 + + \sa + + --------------------------------------------------------------------------*/ +uint8_t sme_qos_get_acm_mask(tpAniSirGlobal pMac, tSirBssDescription *pSirBssDesc, + tDot11fBeaconIEs *pIes) +{ + sme_QosEdcaAcType ac; + uint8_t acm_mask = 0; + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: invoked", __func__, __LINE__); + for (ac = SME_QOS_EDCA_AC_BE; ac < SME_QOS_EDCA_AC_MAX; ac++) { + if (sme_qos_is_acm(pMac, pSirBssDesc, ac, pIes)) { + acm_mask = acm_mask | (1 << (SME_QOS_EDCA_AC_VO - ac)); + } + + } + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: mask is %d", __func__, __LINE__, acm_mask); + return acm_mask; +} + +/* Internal function definitions */ + +/** + * sme_qos_internal_setup_req() - The SME QoS internal setup request handling + * function. + * + * @pMac: Pointer to the global MAC parameter structure. + * @pQoSInfo: Pointer to sme_QosWmmTspecInfo which contains the WMM TSPEC + * related info as defined above, provided by HDD + * @QoSCallback: The callback which is registered per flow while + * requesting for QoS. Used for any notification for the + * flow (i.e. setup success/failure/release) which needs to + * be sent to HDD + * @HDDcontext: A cookie passed by HDD to be used by SME during any QoS + * notification (through the callabck) to HDD + * @UPType: Useful only if HDD or any other upper layer module (BAP etc.) + * looking for implicit QoS setup, in that + * case, the pQoSInfo will be NULL & SME will know about the AC + * (from the UP provided in this param) QoS is requested on + * @QosFlowID: Identification per flow running on each AC generated by + * SME. It is only meaningful if the QoS setup for the flow is + * successful + * @buffered_cmd: tells us if the cmd was a buffered one or fresh from + * client + * + * If the request involves admission control on the requested AC, HDD needs to + * provide the necessary Traffic Specification (TSPEC) parameters otherwise SME + * is going to use the default params. + * + * Return: QDF_STATUS_SUCCESS - Setup is successful. + * Other status means Setup request failed + */ +sme_QosStatusType sme_qos_internal_setup_req(tpAniSirGlobal pMac, + uint8_t sessionId, + sme_QosWmmTspecInfo *pQoSInfo, + sme_QosCallback QoSCallback, + void *HDDcontext, + sme_QosWmmUpType UPType, + uint32_t QosFlowID, + bool buffered_cmd, bool hoRenewal) +{ + sme_QosSessionInfo *pSession; + sme_QosACInfo *pACInfo; + sme_QosEdcaAcType ac; + sme_QosWmmTspecInfo Tspec_Info; + sme_QosStates new_state = SME_QOS_CLOSED; + sme_QosFlowInfoEntry *pentry = NULL; + sme_QosCmdInfo cmd; + sme_QosStatusType status = SME_QOS_STATUS_SETUP_FAILURE_RSP; + uint8_t tmask = 0; + uint8_t new_tmask = 0; + sme_QosSearchInfo search_key; + QDF_STATUS hstatus; + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: invoked on session %d for flow %d", + __func__, __LINE__, sessionId, QosFlowID); + pSession = &sme_qos_cb.sessionInfo[sessionId]; + /* if caller sent an empty TSPEC, fill up with the default one */ + if (!pQoSInfo) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_WARN, + "%s: %d: caller sent an empty QoS param list, using defaults", + __func__, __LINE__); + /* find the AC with UPType passed in */ + ac = sme_qos_up_to_ac(UPType); + if (SME_QOS_EDCA_AC_MAX == ac) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: invalid AC %d from UP %d", + __func__, __LINE__, ac, UPType); + + return SME_QOS_STATUS_SETUP_INVALID_PARAMS_RSP; + } + Tspec_Info = sme_qos_cb.def_QoSInfo[ac]; + } else { + /* find the AC */ + ac = sme_qos_up_to_ac(pQoSInfo->ts_info.up); + if (SME_QOS_EDCA_AC_MAX == ac) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: invalid AC %d from UP %d", + __func__, __LINE__, ac, pQoSInfo->ts_info.up); + + return SME_QOS_STATUS_SETUP_INVALID_PARAMS_RSP; + } + /* validate QoS params */ + if (!sme_qos_validate_requested_params(pMac, pQoSInfo, sessionId)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: invalid params", __func__, __LINE__); + return SME_QOS_STATUS_SETUP_INVALID_PARAMS_RSP; + } + Tspec_Info = *pQoSInfo; + } + pACInfo = &pSession->ac_info[ac]; + /* need to vote off powersave for the duration of this request */ + pSession->readyForPowerSave = false; + /* check to consider the following flowing scenario. + * Addts request is pending on one AC, while APSD requested on another + * which needs a reassoc. Will buffer a request if Addts is pending + * on any AC, which will safegaurd the above scenario, & also won't + * confuse PE with back to back Addts or Addts followed by Reassoc + */ + if (sme_qos_is_rsp_pending(sessionId, ac)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO_MED, + "%s: %d: buffering the setup request for flow %d in state %d " + "since another request is pending", + __func__, __LINE__, QosFlowID, pACInfo->curr_state); + /* we need to buffer the command */ + cmd.command = SME_QOS_SETUP_REQ; + cmd.pMac = pMac; + cmd.sessionId = sessionId; + cmd.u.setupCmdInfo.HDDcontext = HDDcontext; + cmd.u.setupCmdInfo.QoSInfo = Tspec_Info; + cmd.u.setupCmdInfo.QoSCallback = QoSCallback; + cmd.u.setupCmdInfo.UPType = UPType; + cmd.u.setupCmdInfo.hoRenewal = hoRenewal; + cmd.u.setupCmdInfo.QosFlowID = QosFlowID; + hstatus = sme_qos_buffer_cmd(&cmd, buffered_cmd); + if (!QDF_IS_STATUS_SUCCESS(hstatus)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: couldn't buffer the setup request in state = %d", + __func__, __LINE__, pACInfo->curr_state); + /* unable to buffer the request */ + /* nothing is pending so vote powersave back on */ + pSession->readyForPowerSave = true; + return SME_QOS_STATUS_SETUP_FAILURE_RSP; + } + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: Buffered setup request for flow = %d", + __func__, __LINE__, QosFlowID); + return SME_QOS_STATUS_SETUP_REQ_PENDING_RSP; + } + /* get into the state m/c to see if the request can be granted */ + switch (pACInfo->curr_state) { + case SME_QOS_LINK_UP: + /* call the internal qos setup logic to decide on if the */ + /* request is NOP, or need reassoc for APSD and/or need to send out ADDTS */ + status = sme_qos_setup(pMac, sessionId, &Tspec_Info, ac); + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: On session %d with AC %d in state SME_QOS_LINK_UP " + "sme_qos_setup returned with status %d", + __func__, __LINE__, sessionId, ac, status); + if (SME_QOS_STATUS_SETUP_REQ_PENDING_RSP != status) { + /* we aren't waiting for a response from the AP */ + /* so vote powersave back on */ + pSession->readyForPowerSave = true; + } + if ((SME_QOS_STATUS_SETUP_REQ_PENDING_RSP == status) || + (SME_QOS_STATUS_SETUP_SUCCESS_NO_ACM_NO_APSD_RSP == status) + || (SME_QOS_STATUS_SETUP_SUCCESS_APSD_SET_ALREADY == + status)) { + /* we received an expected "good" status */ + /* create an entry in the flow list */ + pentry = qdf_mem_malloc(sizeof(*pentry)); + if (!pentry) { + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_ERROR, + "%s: %d: couldn't allocate memory for the new " + "entry in the Flow List", __func__, + __LINE__); + return SME_QOS_STATUS_SETUP_FAILURE_RSP; + } + pentry->ac_type = ac; + pentry->HDDcontext = HDDcontext; + pentry->QoSCallback = QoSCallback; + pentry->hoRenewal = hoRenewal; + pentry->QosFlowID = QosFlowID; + pentry->sessionId = sessionId; + /* since we are in state SME_QOS_LINK_UP this must be the */ + /* first TSPEC on this AC, so use index 0 (mask bit 1) */ + pACInfo->requested_QoSInfo[SME_QOS_TSPEC_INDEX_0] = + Tspec_Info; + if (SME_QOS_STATUS_SETUP_REQ_PENDING_RSP == status) { + if (pACInfo->tspec_mask_status && + !pACInfo->reassoc_pending) { + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_ERROR, + "%s: %d: On session %d with AC %d in state " + "SME_QOS_LINK_UP tspec_mask_status is %d " + "but should not be set yet", + __func__, __LINE__, sessionId, + ac, + pACInfo->tspec_mask_status); + QDF_ASSERT(0); + qdf_mem_free(pentry); + return SME_QOS_STATUS_SETUP_FAILURE_RSP; + } + pACInfo->tspec_mask_status = + SME_QOS_TSPEC_MASK_BIT_1_SET; + if (!pACInfo->reassoc_pending) { + /* we didn't request for reassoc, it must be a tspec negotiation */ + pACInfo->tspec_pending = 1; + } + + pentry->reason = SME_QOS_REASON_SETUP; + new_state = SME_QOS_REQUESTED; + } else { + /* SME_QOS_STATUS_SETUP_SUCCESS_NO_ACM_NO_APSD_RSP or */ + /* SME_QOS_STATUS_SETUP_SUCCESS_APSD_SET_ALREADY */ + pentry->reason = SME_QOS_REASON_REQ_SUCCESS; + new_state = SME_QOS_QOS_ON; + pACInfo->tspec_mask_status = + SME_QOS_TSPEC_MASK_BIT_1_SET; + pACInfo->curr_QoSInfo[SME_QOS_TSPEC_INDEX_0] = + Tspec_Info; + if (buffered_cmd && !pentry->hoRenewal) { + QoSCallback(pMac, HDDcontext, + &pACInfo-> + curr_QoSInfo + [SME_QOS_TSPEC_INDEX_0], + status, pentry->QosFlowID); + } + pentry->hoRenewal = false; + } + pACInfo->num_flows[SME_QOS_TSPEC_INDEX_0]++; + + /* indicate on which index the flow entry belongs to & add it to the */ + /* Flow List at the end */ + pentry->tspec_mask = pACInfo->tspec_mask_status; + pentry->QoSInfo = Tspec_Info; + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: Creating entry on session %d at %p with flowID %d", + __func__, __LINE__, + sessionId, pentry, QosFlowID); + csr_ll_insert_tail(&sme_qos_cb.flow_list, &pentry->link, + true); + } else { + /* unexpected status returned by sme_qos_setup() */ + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: On session %d unexpected status %d " + "returned by sme_qos_setup", + __func__, __LINE__, sessionId, status); + new_state = pACInfo->curr_state; + if (buffered_cmd && hoRenewal) { + QoSCallback(pMac, HDDcontext, + &pACInfo-> + curr_QoSInfo[SME_QOS_TSPEC_INDEX_0], + SME_QOS_STATUS_RELEASE_QOS_LOST_IND, + QosFlowID); + } + } + break; + case SME_QOS_HANDOFF: + case SME_QOS_REQUESTED: + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO_MED, + "%s: %d: Buffering setup request for flow %d in state = %d", + __func__, __LINE__, QosFlowID, pACInfo->curr_state); + /* buffer cmd */ + cmd.command = SME_QOS_SETUP_REQ; + cmd.pMac = pMac; + cmd.sessionId = sessionId; + cmd.u.setupCmdInfo.HDDcontext = HDDcontext; + cmd.u.setupCmdInfo.QoSInfo = Tspec_Info; + cmd.u.setupCmdInfo.QoSCallback = QoSCallback; + cmd.u.setupCmdInfo.UPType = UPType; + cmd.u.setupCmdInfo.hoRenewal = hoRenewal; + cmd.u.setupCmdInfo.QosFlowID = QosFlowID; + hstatus = sme_qos_buffer_cmd(&cmd, buffered_cmd); + if (!QDF_IS_STATUS_SUCCESS(hstatus)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: On session %d couldn't buffer the setup " + "request for flow %d in state = %d", + __func__, __LINE__, + sessionId, QosFlowID, pACInfo->curr_state); + /* unable to buffer the request */ + /* nothing is pending so vote powersave back on */ + pSession->readyForPowerSave = true; + return SME_QOS_STATUS_SETUP_FAILURE_RSP; + } + status = SME_QOS_STATUS_SETUP_REQ_PENDING_RSP; + new_state = pACInfo->curr_state; + break; + case SME_QOS_QOS_ON: + + /* check if multiple flows running on the ac */ + if ((pACInfo->num_flows[SME_QOS_TSPEC_INDEX_0] > 0) || + (pACInfo->num_flows[SME_QOS_TSPEC_INDEX_1] > 0)) { + /* do we need to care about the case where APSD needed on ACM = 0 below? */ + if (CSR_IS_ADDTS_WHEN_ACMOFF_SUPPORTED(pMac) || + sme_qos_is_acm(pMac, pSession->assocInfo.pBssDesc, ac, + NULL)) { + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_INFO_MED, + "%s: %d: tspec_mask_status = %d for AC = %d", + __func__, __LINE__, + pACInfo->tspec_mask_status, ac); + if (!pACInfo->tspec_mask_status) { + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_ERROR, + "%s: %d: tspec_mask_status can't be 0 for ac = %d in " + "state = %d", __func__, + __LINE__, ac, + pACInfo->curr_state); + QDF_ASSERT(0); + /* unable to service the request */ + /* nothing is pending so vote powersave back on */ + pSession->readyForPowerSave = true; + return status; + } + /* Flow aggregation */ + if (((pACInfo->tspec_mask_status > 0) && + (pACInfo->tspec_mask_status <= + SME_QOS_TSPEC_INDEX_MAX))) { + /* Either of upstream, downstream or bidirectional flows are present */ + /* If either of new stream or current stream is for bidirecional, aggregate + * the new stream with the current streams present and send out aggregated Tspec.*/ + if ((Tspec_Info.ts_info.direction == + SME_QOS_WMM_TS_DIR_BOTH) + || (pACInfo-> + curr_QoSInfo[pACInfo-> + tspec_mask_status - + 1].ts_info. + direction == + SME_QOS_WMM_TS_DIR_BOTH)) { + /* Aggregate the new stream with the current stream(s). */ + tmask = + pACInfo->tspec_mask_status; + } + /* None of new stream or current (aggregated) streams are for bidirectional. + * Check if the new stream direction matches the current stream direction. */ + else if (pACInfo-> + curr_QoSInfo[pACInfo-> + tspec_mask_status + - + 1].ts_info. + direction == + Tspec_Info.ts_info.direction) { + /* Aggregate the new stream with the current stream(s). */ + tmask = + pACInfo->tspec_mask_status; + } + /* New stream is in different direction. */ + else { + /* No Aggregation. Mark the 2nd tpsec index also as active. */ + tmask = + SME_QOS_TSPEC_MASK_CLEAR; + new_tmask = + SME_QOS_TSPEC_MASK_BIT_1_2_SET + & ~pACInfo-> + tspec_mask_status; + pACInfo->tspec_mask_status = + SME_QOS_TSPEC_MASK_BIT_1_2_SET; + } + } else if (SME_QOS_TSPEC_MASK_BIT_1_2_SET == + pACInfo->tspec_mask_status) { + /* Both uplink and downlink streams are present. */ + /* If new stream is bidirectional, aggregate new stream with all existing + * upstreams and downstreams. Send out new aggregated tpsec. */ + if (Tspec_Info.ts_info.direction == + SME_QOS_WMM_TS_DIR_BOTH) { + /* Only one tspec index (0) will be in use after this aggregation. */ + tmask = + SME_QOS_TSPEC_MASK_BIT_1_2_SET; + pACInfo->tspec_mask_status = + SME_QOS_TSPEC_MASK_BIT_1_SET; + } + /* New stream is also uni-directional + * Find out the tsepc index with which it needs to be aggregated */ + else if (pACInfo-> + curr_QoSInfo + [SME_QOS_TSPEC_INDEX_0]. + ts_info.direction != + Tspec_Info.ts_info.direction) { + /* Aggregate with 2nd tspec index */ + tmask = + SME_QOS_TSPEC_MASK_BIT_2_SET; + } else { + /* Aggregate with 1st tspec index */ + tmask = + SME_QOS_TSPEC_MASK_BIT_1_SET; + } + } else { + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_INFO_MED, + "%s: %d: wrong tmask = %d", + __func__, __LINE__, + pACInfo->tspec_mask_status); + } + } else { + /* ACM = 0 */ + /* We won't be sending a TSPEC to the AP but we still need */ + /* to aggregate to calculate trigger frame parameters */ + tmask = SME_QOS_TSPEC_MASK_BIT_1_SET; + } + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO_MED, + "%s: %d: tmask = %d, new_tmask = %d in state = %d", + __func__, __LINE__, + tmask, new_tmask, pACInfo->curr_state); + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO_MED, + "%s: %d: tspec_mask_status = %d for AC = %d", + __func__, __LINE__, + pACInfo->tspec_mask_status, ac); + if (tmask) { + /* create the aggregate TSPEC */ + if (tmask != SME_QOS_TSPEC_MASK_BIT_1_2_SET) { + hstatus = + sme_qos_aggregate_params(&Tspec_Info, + &pACInfo-> + curr_QoSInfo + [tmask - 1], + &pACInfo-> + requested_QoSInfo + [tmask - 1]); + } else { + /* Aggregate the new bidirectional stream with the existing upstreams and + * downstreams in tspec indices 0 and 1. */ + tmask = SME_QOS_TSPEC_MASK_BIT_1_SET; + + hstatus = sme_qos_aggregate_params( + &Tspec_Info, &pACInfo-> + curr_QoSInfo + [SME_QOS_TSPEC_INDEX_0], + &pACInfo-> + requested_QoSInfo + [tmask - 1]); + if (hstatus == QDF_STATUS_SUCCESS) { + hstatus = + sme_qos_aggregate_params + (&pACInfo-> + curr_QoSInfo + [SME_QOS_TSPEC_INDEX_1], + &pACInfo-> + requested_QoSInfo[tmask - + 1], + NULL); + } + } + + if (!QDF_IS_STATUS_SUCCESS(hstatus)) { + /* err msg */ + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_ERROR, + "%s: %d: failed to aggregate params", + __func__, __LINE__); + /* unable to service the request */ + /* nothing is pending so vote powersave back on */ + pSession->readyForPowerSave = true; + return SME_QOS_STATUS_SETUP_FAILURE_RSP; + } + } else { + if (! + (new_tmask > 0 + && new_tmask <= SME_QOS_TSPEC_INDEX_MAX)) { + return SME_QOS_STATUS_SETUP_FAILURE_RSP; + } + tmask = new_tmask; + pACInfo->requested_QoSInfo[tmask - 1] = + Tspec_Info; + } + } else { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: no flows running for ac = %d while in state = %d", + __func__, __LINE__, ac, pACInfo->curr_state); + QDF_ASSERT(0); + /* unable to service the request */ + /* nothing is pending so vote powersave back on */ + pSession->readyForPowerSave = true; + return status; + } + /* although aggregating, make sure to request on the correct UP,TID,PSB and direction */ + pACInfo->requested_QoSInfo[tmask - 1].ts_info.up = + Tspec_Info.ts_info.up; + pACInfo->requested_QoSInfo[tmask - 1].ts_info.tid = + Tspec_Info.ts_info.tid; + pACInfo->requested_QoSInfo[tmask - 1].ts_info.direction = + Tspec_Info.ts_info.direction; + pACInfo->requested_QoSInfo[tmask - 1].ts_info.psb = + Tspec_Info.ts_info.psb; + status = + sme_qos_setup(pMac, sessionId, + &pACInfo->requested_QoSInfo[tmask - 1], ac); + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: On session %d with AC %d in state SME_QOS_QOS_ON " + "sme_qos_setup returned with status %d", __func__, + __LINE__, sessionId, ac, status); + if (SME_QOS_STATUS_SETUP_REQ_PENDING_RSP != status) { + /* we aren't waiting for a response from the AP */ + /* so vote powersave back on */ + pSession->readyForPowerSave = true; + } + if ((SME_QOS_STATUS_SETUP_REQ_PENDING_RSP == status) || + (SME_QOS_STATUS_SETUP_SUCCESS_NO_ACM_NO_APSD_RSP == status) + || (SME_QOS_STATUS_SETUP_SUCCESS_APSD_SET_ALREADY == + status)) { + /* we received an expected "good" status */ + /* create an entry in the flow list */ + pentry = + (sme_QosFlowInfoEntry *) + qdf_mem_malloc(sizeof(*pentry)); + if (!pentry) { + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_ERROR, + "%s: %d: couldn't allocate memory for the new " + "entry in the Flow List", __func__, + __LINE__); + return SME_QOS_STATUS_SETUP_FAILURE_RSP; + } + pentry->ac_type = ac; + pentry->HDDcontext = HDDcontext; + pentry->QoSCallback = QoSCallback; + pentry->hoRenewal = hoRenewal; + pentry->QosFlowID = QosFlowID; + pentry->sessionId = sessionId; + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: Creating flow %d", + __func__, __LINE__, QosFlowID); + if ((SME_QOS_STATUS_SETUP_SUCCESS_NO_ACM_NO_APSD_RSP == + status) + || (SME_QOS_STATUS_SETUP_SUCCESS_APSD_SET_ALREADY == + status)) { + new_state = pACInfo->curr_state; + pentry->reason = SME_QOS_REASON_REQ_SUCCESS; + pACInfo->curr_QoSInfo[SME_QOS_TSPEC_INDEX_0] = + pACInfo-> + requested_QoSInfo[SME_QOS_TSPEC_INDEX_0]; + if (buffered_cmd && !pentry->hoRenewal) { + QoSCallback(pMac, HDDcontext, + &pACInfo-> + curr_QoSInfo + [SME_QOS_TSPEC_INDEX_0], + status, pentry->QosFlowID); + } + if (SME_QOS_STATUS_SETUP_SUCCESS_APSD_SET_ALREADY == status) { + /* if we are not in handoff, then notify all flows on */ + /* this AC that the aggregate TSPEC may have changed */ + if (!pentry->hoRenewal) { + qdf_mem_zero(&search_key, + sizeof + (sme_QosSearchInfo)); + search_key.key.ac_type = ac; + search_key.index = + SME_QOS_SEARCH_KEY_INDEX_2; + search_key.sessionId = + sessionId; + hstatus = + sme_qos_find_all_in_flow_list + (pMac, search_key, + sme_qos_setup_fnp); + if (!QDF_IS_STATUS_SUCCESS + (hstatus)) { + QDF_TRACE + (QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_ERROR, + "%s: %d: couldn't notify other " + "entries on this AC =%d", + __func__, __LINE__, + ac); + } + } + } + pentry->hoRenewal = false; + } else { + /* SME_QOS_STATUS_SETUP_REQ_PENDING_RSP */ + new_state = SME_QOS_REQUESTED; + pentry->reason = SME_QOS_REASON_SETUP; + /* Need this info when addts comes back from PE to know on */ + /* which index of the AC the request was from */ + pACInfo->tspec_pending = tmask; + } + pACInfo->num_flows[tmask - 1]++; + /* indicate on which index the flow entry belongs to & add it to the */ + /* Flow List at the end */ + pentry->tspec_mask = tmask; + pentry->QoSInfo = Tspec_Info; + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: On session %d creating entry at %p with flowID %d", + __func__, __LINE__, + sessionId, pentry, QosFlowID); + csr_ll_insert_tail(&sme_qos_cb.flow_list, &pentry->link, + true); + } else { + /* unexpected status returned by sme_qos_setup() */ + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: On session %d unexpected status %d " + "returned by sme_qos_setup", + __func__, __LINE__, sessionId, status); + new_state = pACInfo->curr_state; + } + break; + case SME_QOS_CLOSED: + case SME_QOS_INIT: + default: + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: setup requested in unexpected state = %d", + __func__, __LINE__, pACInfo->curr_state); + /* unable to service the request */ + /* nothing is pending so vote powersave back on */ + pSession->readyForPowerSave = true; + QDF_ASSERT(0); + new_state = pACInfo->curr_state; + } + /* if current state is same as previous no need for transistion, + if we are doing reassoc & we are already in handoff state, no need to move + to requested state. But make sure to set the previous state as requested + state + */ + if ((new_state != pACInfo->curr_state) && + (!(pACInfo->reassoc_pending && + (SME_QOS_HANDOFF == pACInfo->curr_state)))) { + sme_qos_state_transition(sessionId, ac, new_state); + } + + if (pACInfo->reassoc_pending && + (SME_QOS_HANDOFF == pACInfo->curr_state)) { + pACInfo->prev_state = SME_QOS_REQUESTED; + } + if ((SME_QOS_STATUS_SETUP_SUCCESS_NO_ACM_NO_APSD_RSP == status) || + (SME_QOS_STATUS_SETUP_SUCCESS_APSD_SET_ALREADY == status)) { + (void)sme_qos_process_buffered_cmd(sessionId); + } + return status; +} + +/** + * sme_qos_internal_modify_req() - The SME QoS internal function to request + * for modification of certain QoS params on a flow running on a particular AC. + * @pMac: Pointer to the global MAC parameter structure. + * @pQoSInfo: Pointer to sme_QosWmmTspecInfo which contains the WMM TSPEC + * related info as defined above, provided by HDD + * @QosFlowID: Identification per flow running on each AC generated by + * SME. It is only meaningful if the QoS setup for the flow has + * been successful already + * + * If the request involves admission control on the requested AC, HDD needs to + * provide the necessary Traffic Specification (TSPEC) parameters & SME might + * start the renegotiation process through ADDTS. + * + * Return: SME_QOS_STATUS_SETUP_SUCCESS_RSP - Modification is successful. + * Other status means request failed + */ +sme_QosStatusType sme_qos_internal_modify_req(tpAniSirGlobal pMac, + sme_QosWmmTspecInfo *pQoSInfo, + uint32_t QosFlowID, + bool buffered_cmd) +{ + tListElem *pEntry = NULL; + sme_QosSessionInfo *pSession; + sme_QosACInfo *pACInfo; + sme_QosFlowInfoEntry *pNewEntry = NULL; + sme_QosFlowInfoEntry *flow_info = NULL; + sme_QosEdcaAcType ac; + sme_QosStates new_state = SME_QOS_CLOSED; + sme_QosStatusType status = SME_QOS_STATUS_MODIFY_SETUP_FAILURE_RSP; + sme_QosWmmTspecInfo Aggr_Tspec_Info; + sme_QosSearchInfo search_key; + sme_QosCmdInfo cmd; + uint8_t sessionId; + QDF_STATUS hstatus; + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: invoked for flow %d", __func__, __LINE__, QosFlowID); + + qdf_mem_zero(&search_key, sizeof(sme_QosSearchInfo)); + /* set the key type & the key to be searched in the Flow List */ + search_key.key.QosFlowID = QosFlowID; + search_key.index = SME_QOS_SEARCH_KEY_INDEX_1; + search_key.sessionId = SME_QOS_SEARCH_SESSION_ID_ANY; + /* go through the link list to find out the details on the flow */ + pEntry = sme_qos_find_in_flow_list(search_key); + if (!pEntry) { + /* Err msg */ + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: no match found for flowID = %d", + __func__, __LINE__, QosFlowID); + return SME_QOS_STATUS_MODIFY_SETUP_INVALID_PARAMS_RSP; + } + /* find the AC */ + flow_info = GET_BASE_ADDR(pEntry, sme_QosFlowInfoEntry, link); + ac = flow_info->ac_type; + + sessionId = flow_info->sessionId; + pSession = &sme_qos_cb.sessionInfo[sessionId]; + pACInfo = &pSession->ac_info[ac]; + + /* validate QoS params */ + if (!sme_qos_validate_requested_params(pMac, pQoSInfo, sessionId)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: invalid params", __func__, __LINE__); + return SME_QOS_STATUS_MODIFY_SETUP_INVALID_PARAMS_RSP; + } + /* For modify, make sure that direction, TID and UP are not being altered */ + if ((pQoSInfo->ts_info.direction != + flow_info->QoSInfo.ts_info.direction) + || (pQoSInfo->ts_info.up != flow_info->QoSInfo.ts_info.up) + || (pQoSInfo->ts_info.tid != flow_info->QoSInfo.ts_info.tid)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: Modification of direction/tid/up is not allowed", + __func__, __LINE__); + + return SME_QOS_STATUS_MODIFY_SETUP_INVALID_PARAMS_RSP; + } + + /* should not be same as previous ioctl parameters */ + if ((pQoSInfo->nominal_msdu_size == + flow_info->QoSInfo.nominal_msdu_size) && + (pQoSInfo->maximum_msdu_size == + flow_info->QoSInfo.maximum_msdu_size) && + (pQoSInfo->min_data_rate == + flow_info->QoSInfo.min_data_rate) && + (pQoSInfo->mean_data_rate == + flow_info->QoSInfo.mean_data_rate) && + (pQoSInfo->peak_data_rate == + flow_info->QoSInfo.peak_data_rate) && + (pQoSInfo->min_service_interval == + flow_info->QoSInfo.min_service_interval) && + (pQoSInfo->max_service_interval == + flow_info->QoSInfo.max_service_interval) && + (pQoSInfo->inactivity_interval == + flow_info->QoSInfo.inactivity_interval) && + (pQoSInfo->suspension_interval == + flow_info->QoSInfo.suspension_interval) && + (pQoSInfo->surplus_bw_allowance == + flow_info->QoSInfo.surplus_bw_allowance)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: the addts parameters are same as last request," + "dropping the current request", __func__, __LINE__); + + return SME_QOS_STATUS_MODIFY_SETUP_FAILURE_RSP; + } + + /* need to vote off powersave for the duration of this request */ + pSession->readyForPowerSave = false; + /* check to consider the following flowing scenario. + * Addts request is pending on one AC, while APSD requested on another + * which needs a reassoc. Will buffer a request if Addts is pending on + * any AC, which will safegaurd the above scenario, & also won't + * confuse PE with back to back Addts or Addts followed by Reassoc + */ + if (sme_qos_is_rsp_pending(sessionId, ac)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO_MED, + "%s: %d: buffering the modify request for flow %d in state %d " + "since another request is pending", + __func__, __LINE__, QosFlowID, pACInfo->curr_state); + /* we need to buffer the command */ + cmd.command = SME_QOS_MODIFY_REQ; + cmd.pMac = pMac; + cmd.sessionId = sessionId; + cmd.u.modifyCmdInfo.QosFlowID = QosFlowID; + cmd.u.modifyCmdInfo.QoSInfo = *pQoSInfo; + hstatus = sme_qos_buffer_cmd(&cmd, buffered_cmd); + if (!QDF_IS_STATUS_SUCCESS(hstatus)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: couldn't buffer the modify request in state = %d", + __func__, __LINE__, pACInfo->curr_state); + /* unable to buffer the request */ + /* nothing is pending so vote powersave back on */ + pSession->readyForPowerSave = true; + return SME_QOS_STATUS_MODIFY_SETUP_FAILURE_RSP; + } + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: Buffered modify request for flow = %d", + __func__, __LINE__, QosFlowID); + return SME_QOS_STATUS_MODIFY_SETUP_PENDING_RSP; + } + /* get into the stat m/c to see if the request can be granted */ + switch (pACInfo->curr_state) { + case SME_QOS_QOS_ON: + /* save the new params adding a new (duplicate) entry in the Flow List */ + /* Once we have decided on OTA exchange needed or not we can delete the */ + /* original one from the List */ + pNewEntry = + (sme_QosFlowInfoEntry *) qdf_mem_malloc(sizeof(*pNewEntry)); + if (!pNewEntry) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: couldn't allocate memory for the new " + "entry in the Flow List", __func__, __LINE__); + /* unable to service the request */ + /* nothing is pending so vote powersave back on */ + pSession->readyForPowerSave = true; + return SME_QOS_STATUS_MODIFY_SETUP_FAILURE_RSP; + } + pNewEntry->ac_type = ac; + pNewEntry->sessionId = sessionId; + pNewEntry->HDDcontext = flow_info->HDDcontext; + pNewEntry->QoSCallback = flow_info->QoSCallback; + pNewEntry->QosFlowID = flow_info->QosFlowID; + pNewEntry->reason = SME_QOS_REASON_MODIFY_PENDING; + /* since it is a modify request, use the same index on which the flow */ + /* entry originally was running & add it to the Flow List at the end */ + pNewEntry->tspec_mask = flow_info->tspec_mask; + pNewEntry->QoSInfo = *pQoSInfo; + /* update the entry from Flow List which needed to be modified */ + flow_info->reason = SME_QOS_REASON_MODIFY; + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: On session %d creating modified " + "entry at %p with flowID %d", + __func__, __LINE__, + sessionId, pNewEntry, pNewEntry->QosFlowID); + /* add the new entry under construction to the Flow List */ + csr_ll_insert_tail(&sme_qos_cb.flow_list, &pNewEntry->link, + true); + /* update TSPEC with the new param set */ + hstatus = sme_qos_update_params(sessionId, + ac, pNewEntry->tspec_mask, + &Aggr_Tspec_Info); + if (QDF_IS_STATUS_SUCCESS(hstatus)) { + pACInfo->requested_QoSInfo[pNewEntry->tspec_mask - 1] = + Aggr_Tspec_Info; + /* if ACM, send out a new ADDTS */ + status = sme_qos_setup(pMac, sessionId, + &pACInfo-> + requested_QoSInfo[pNewEntry-> + tspec_mask - 1], + ac); + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: On session %d with AC %d in state SME_QOS_QOS_ON " + "sme_qos_setup returned with status %d", + __func__, __LINE__, sessionId, ac, status); + if (SME_QOS_STATUS_SETUP_REQ_PENDING_RSP != status) { + /* we aren't waiting for a response from the AP */ + /* so vote powersave back on */ + pSession->readyForPowerSave = true; + } + if (SME_QOS_STATUS_SETUP_REQ_PENDING_RSP == status) { + new_state = SME_QOS_REQUESTED; + status = + SME_QOS_STATUS_MODIFY_SETUP_PENDING_RSP; + pACInfo->tspec_pending = pNewEntry->tspec_mask; + } else + if ((SME_QOS_STATUS_SETUP_SUCCESS_NO_ACM_NO_APSD_RSP + == status) + || + (SME_QOS_STATUS_SETUP_SUCCESS_APSD_SET_ALREADY + == status)) { + new_state = SME_QOS_QOS_ON; + + qdf_mem_zero(&search_key, + sizeof(sme_QosSearchInfo)); + /* delete the original entry in FLOW list which got modified */ + search_key.key.ac_type = ac; + search_key.index = SME_QOS_SEARCH_KEY_INDEX_2; + search_key.sessionId = sessionId; + hstatus = + sme_qos_find_all_in_flow_list(pMac, search_key, + sme_qos_modify_fnp); + if (!QDF_IS_STATUS_SUCCESS(hstatus)) { + status = + SME_QOS_STATUS_MODIFY_SETUP_FAILURE_RSP; + } + if (SME_QOS_STATUS_MODIFY_SETUP_FAILURE_RSP != + status) { + pACInfo->curr_QoSInfo[pNewEntry-> + tspec_mask - 1] = + pACInfo-> + requested_QoSInfo[pNewEntry-> + tspec_mask - 1]; + if (SME_QOS_STATUS_SETUP_SUCCESS_APSD_SET_ALREADY == status) { + status = + SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_APSD_SET_ALREADY; + qdf_mem_zero(&search_key, + sizeof + (sme_QosSearchInfo)); + search_key.key.ac_type = ac; + search_key.index = + SME_QOS_SEARCH_KEY_INDEX_2; + search_key.sessionId = + sessionId; + hstatus = + sme_qos_find_all_in_flow_list + (pMac, search_key, + sme_qos_modification_notify_fnp); + if (!QDF_IS_STATUS_SUCCESS + (hstatus)) { + QDF_TRACE + (QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_ERROR, + "%s: %d: couldn't notify other " + "entries on this AC =%d", + __func__, __LINE__, + ac); + } + } else + if + (SME_QOS_STATUS_SETUP_SUCCESS_NO_ACM_NO_APSD_RSP + == status) { + status = + SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_NO_ACM_NO_APSD_RSP; + } + } + if (buffered_cmd) { + flow_info->QoSCallback(pMac, + flow_info-> + HDDcontext, + &pACInfo-> + curr_QoSInfo + [pNewEntry-> + tspec_mask - 1], + status, + flow_info-> + QosFlowID); + } + + } else { + /* unexpected status returned by sme_qos_setup() */ + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_ERROR, + "%s: %d: On session %d unexpected status %d " + "returned by sme_qos_setup", __func__, + __LINE__, sessionId, status); + new_state = SME_QOS_QOS_ON; + } + } else { + /* err msg */ + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: sme_qos_update_params() failed", + __func__, __LINE__); + /* unable to service the request */ + /* nothing is pending so vote powersave back on */ + pSession->readyForPowerSave = true; + new_state = SME_QOS_LINK_UP; + } + /* if we are doing reassoc & we are already in handoff state, no need + to move to requested state. But make sure to set the previous state + as requested state + */ + if (!(pACInfo->reassoc_pending && + (SME_QOS_HANDOFF == pACInfo->curr_state))) { + sme_qos_state_transition(sessionId, ac, new_state); + } else { + pACInfo->prev_state = SME_QOS_REQUESTED; + } + break; + case SME_QOS_HANDOFF: + case SME_QOS_REQUESTED: + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO_MED, + "%s: %d: Buffering modify request for flow %d in state = %d", + __func__, __LINE__, QosFlowID, pACInfo->curr_state); + /* buffer cmd */ + cmd.command = SME_QOS_MODIFY_REQ; + cmd.pMac = pMac; + cmd.sessionId = sessionId; + cmd.u.modifyCmdInfo.QosFlowID = QosFlowID; + cmd.u.modifyCmdInfo.QoSInfo = *pQoSInfo; + hstatus = sme_qos_buffer_cmd(&cmd, buffered_cmd); + if (!QDF_IS_STATUS_SUCCESS(hstatus)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: couldn't buffer the modify request in state = %d", + __func__, __LINE__, pACInfo->curr_state); + /* unable to buffer the request */ + /* nothing is pending so vote powersave back on */ + pSession->readyForPowerSave = true; + return SME_QOS_STATUS_MODIFY_SETUP_FAILURE_RSP; + } + status = SME_QOS_STATUS_MODIFY_SETUP_PENDING_RSP; + break; + case SME_QOS_CLOSED: + case SME_QOS_INIT: + case SME_QOS_LINK_UP: + default: + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: modify requested in unexpected state = %d", + __func__, __LINE__, pACInfo->curr_state); + /* unable to service the request */ + /* nothing is pending so vote powersave back on */ + pSession->readyForPowerSave = true; + break; + } + if ((SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_NO_ACM_NO_APSD_RSP == status) + || (SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_APSD_SET_ALREADY == + status)) { + (void)sme_qos_process_buffered_cmd(sessionId); + } + return status; +} + +/** + * sme_qos_internal_release_req() - release QOS flow on a particular AC + * @pMac: Pointer to the global MAC parameter structure. + * @sessionId: sessionId returned by sme_open_session. + * @QosFlowID: Identification per flow running on each AC generated by SME + * It is only meaningful if the QoS setup for the flow is successful + * + * The SME QoS internal function to request + * for releasing a QoS flow running on a particular AC. + + * Return: QDF_STATUS_SUCCESS - Release is successful. + */ +sme_QosStatusType sme_qos_internal_release_req(tpAniSirGlobal pMac, + uint8_t sessionId, + uint32_t QosFlowID, + bool buffered_cmd) +{ + tListElem *pEntry = NULL; + sme_QosSessionInfo *pSession; + sme_QosACInfo *pACInfo; + sme_QosFlowInfoEntry *flow_info = NULL; + sme_QosFlowInfoEntry *pDeletedFlow = NULL; + sme_QosEdcaAcType ac; + sme_QosStates new_state = SME_QOS_CLOSED; + sme_QosStatusType status = SME_QOS_STATUS_RELEASE_FAILURE_RSP; + sme_QosWmmTspecInfo Aggr_Tspec_Info; + sme_QosSearchInfo search_key; + sme_QosCmdInfo cmd; + tCsrRoamModifyProfileFields modifyProfileFields; + bool deltsIssued = false; + QDF_STATUS hstatus; + bool biDirectionalFlowsPresent = false; + bool uplinkFlowsPresent = false; + bool downlinkFlowsPresent = false; + tListElem *pResult = NULL; + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: invoked for flow %d", __func__, __LINE__, QosFlowID); + + qdf_mem_zero(&search_key, sizeof(sme_QosSearchInfo)); + /* set the key type & the key to be searched in the Flow List */ + search_key.key.QosFlowID = QosFlowID; + search_key.index = SME_QOS_SEARCH_KEY_INDEX_1; + search_key.sessionId = SME_QOS_SEARCH_SESSION_ID_ANY; + /* go through the link list to find out the details on the flow */ + pEntry = sme_qos_find_in_flow_list(search_key); + + if (!pEntry) { + /* Err msg */ + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: no match found for flowID = %d", + __func__, __LINE__, QosFlowID); + + pSession = &sme_qos_cb.sessionInfo[sessionId]; + if (!buffered_cmd && + !csr_ll_is_list_empty(&pSession->bufferedCommandList, + false)) { + cmd.command = SME_QOS_RELEASE_REQ; + cmd.pMac = pMac; + cmd.sessionId = sessionId; + cmd.u.releaseCmdInfo.QosFlowID = QosFlowID; + hstatus = sme_qos_buffer_cmd(&cmd, buffered_cmd); + if (QDF_IS_STATUS_SUCCESS(hstatus)) { + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_INFO_HIGH, + "%s:%d: Buffered release request for flow = %d", + __func__, __LINE__, QosFlowID); + } + } + return SME_QOS_STATUS_RELEASE_INVALID_PARAMS_RSP; + } + /* find the AC */ + flow_info = GET_BASE_ADDR(pEntry, sme_QosFlowInfoEntry, link); + ac = flow_info->ac_type; + sessionId = flow_info->sessionId; + + if (!CSR_IS_SESSION_VALID(pMac, sessionId)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: Session Id: %d is invalid", + __func__, __LINE__, sessionId); + return status; + } + + pSession = &sme_qos_cb.sessionInfo[sessionId]; + pACInfo = &pSession->ac_info[ac]; + /* need to vote off powersave for the duration of this request */ + pSession->readyForPowerSave = false; + /* check to consider the following flowing scenario. + * Addts request is pending on one AC, while APSD requested on another + * which needs a reassoc. Will buffer a request if Addts is pending on + * any AC, which will safegaurd the above scenario, & also won't + * confuse PE with back to back Addts or Addts followed by Reassoc + */ + if (sme_qos_is_rsp_pending(sessionId, ac)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO_MED, + "%s: %d: buffering the release request for flow %d in state %d " + "since another request is pending", + __func__, __LINE__, QosFlowID, pACInfo->curr_state); + /* we need to buffer the command */ + cmd.command = SME_QOS_RELEASE_REQ; + cmd.pMac = pMac; + cmd.sessionId = sessionId; + cmd.u.releaseCmdInfo.QosFlowID = QosFlowID; + hstatus = sme_qos_buffer_cmd(&cmd, buffered_cmd); + if (!QDF_IS_STATUS_SUCCESS(hstatus)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: couldn't buffer the release request in state = %d", + __func__, __LINE__, pACInfo->curr_state); + /* unable to buffer the request */ + /* nothing is pending so vote powersave back on */ + pSession->readyForPowerSave = true; + return SME_QOS_STATUS_RELEASE_FAILURE_RSP; + } + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: Buffered release request for flow = %d", + __func__, __LINE__, QosFlowID); + return SME_QOS_STATUS_RELEASE_REQ_PENDING_RSP; + } + /* get into the stat m/c to see if the request can be granted */ + switch (pACInfo->curr_state) { + case SME_QOS_QOS_ON: + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO_MED, + "%s: %d: tspec_mask_status = %d for AC = %d with " + "entry tspec_mask = %d", + __func__, __LINE__, + pACInfo->tspec_mask_status, ac, + flow_info->tspec_mask); + + /* check if multiple flows running on the ac */ + if (pACInfo->num_flows[flow_info->tspec_mask - 1] > 1) { + /* don't want to include the flow in the new TSPEC on which release */ + /* is requested */ + flow_info->reason = SME_QOS_REASON_RELEASE; + + /* Check if the flow being released is for bi-diretional. + * Following flows may present in the system. + * a) bi-directional flows + * b) uplink flows + * c) downlink flows. + * If the flow being released is for bidirectional, splitting of existing + * streams into two tspec indices is required in case ff (b), (c) are present + * and not (a). + * In case if split occurs, all upstreams are aggregated into tspec index 0, + * downstreams are aggregaed into tspec index 1 and two tspec requests for + * (aggregated) upstream(s) followed by (aggregated) downstream(s) is sent + * to AP. */ + if (flow_info->QoSInfo.ts_info.direction == + SME_QOS_WMM_TS_DIR_BOTH) { + qdf_mem_zero(&search_key, + sizeof(sme_QosSearchInfo)); + /* set the key type & the key to be searched in the Flow List */ + search_key.key.ac_type = ac; + search_key.index = SME_QOS_SEARCH_KEY_INDEX_4; + search_key.sessionId = sessionId; + search_key.direction = SME_QOS_WMM_TS_DIR_BOTH; + pResult = sme_qos_find_in_flow_list(search_key); + if (pResult) + biDirectionalFlowsPresent = true; + + if (!biDirectionalFlowsPresent) { + /* The only existing bidirectional flow is being released */ + + /* Check if uplink flows exist */ + search_key.direction = + SME_QOS_WMM_TS_DIR_UPLINK; + pResult = + sme_qos_find_in_flow_list(search_key); + if (pResult) + uplinkFlowsPresent = true; + + /* Check if downlink flows exist */ + search_key.direction = + SME_QOS_WMM_TS_DIR_DOWNLINK; + pResult = + sme_qos_find_in_flow_list(search_key); + if (pResult) + downlinkFlowsPresent = true; + + if (uplinkFlowsPresent + && downlinkFlowsPresent) { + /* Need to split the uni-directional flows into SME_QOS_TSPEC_INDEX_0 and SME_QOS_TSPEC_INDEX_1 */ + + qdf_mem_zero(&search_key, + sizeof + (sme_QosSearchInfo)); + /* Mark all downstream flows as using tspec index 1 */ + search_key.key.ac_type = ac; + search_key.index = + SME_QOS_SEARCH_KEY_INDEX_4; + search_key.sessionId = + sessionId; + search_key.direction = + SME_QOS_WMM_TS_DIR_DOWNLINK; + sme_qos_update_tspec_mask + (sessionId, search_key, + SME_QOS_TSPEC_MASK_BIT_2_SET); + + /* Aggregate all downstream flows */ + hstatus = + sme_qos_update_params + (sessionId, ac, + SME_QOS_TSPEC_MASK_BIT_2_SET, + &Aggr_Tspec_Info); + + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_ERROR, + "%s: %d: On session %d buffering the AddTS request " + "for AC %d in state %d as Addts is pending " + "on other Tspec index of this AC", + __func__, __LINE__, + sessionId, ac, + pACInfo->curr_state); + + /* Buffer the (aggregated) tspec request for downstream flows. */ + /* Please note that the (aggregated) tspec for upstream flows is sent */ + /* out by the susequent logic. */ + cmd.command = + SME_QOS_RESEND_REQ; + cmd.pMac = pMac; + cmd.sessionId = sessionId; + cmd.u.resendCmdInfo.ac = ac; + cmd.u.resendCmdInfo.tspecMask = + SME_QOS_TSPEC_MASK_BIT_2_SET; + cmd.u.resendCmdInfo.QoSInfo = + Aggr_Tspec_Info; + pACInfo-> + requested_QoSInfo + [SME_QOS_TSPEC_MASK_BIT_2_SET + - 1] = Aggr_Tspec_Info; + if (!QDF_IS_STATUS_SUCCESS + (sme_qos_buffer_cmd + (&cmd, false))) { + QDF_TRACE + (QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_ERROR, + "%s: %d: On session %d unable to buffer the AddTS " + "request for AC %d TSPEC %d in state %d", + __func__, __LINE__, + sessionId, ac, + SME_QOS_TSPEC_MASK_BIT_2_SET, + pACInfo-> + curr_state); + + /* unable to buffer the request */ + /* nothing is pending so vote powersave back on */ + pSession-> + readyForPowerSave = + true; + + return + SME_QOS_STATUS_MODIFY_SETUP_FAILURE_RSP; + } + pACInfo->tspec_mask_status = + SME_QOS_TSPEC_MASK_BIT_1_2_SET; + + } + } + } + + /* In case of splitting of existing streams, + * tspec_mask will be pointing to tspec index 0 and + * aggregated tspec for upstream(s) is sent out here. */ + hstatus = sme_qos_update_params(sessionId, + ac, flow_info->tspec_mask, + &Aggr_Tspec_Info); + if (QDF_IS_STATUS_SUCCESS(hstatus)) { + pACInfo->requested_QoSInfo[flow_info-> + tspec_mask - 1] = + Aggr_Tspec_Info; + /* if ACM, send out a new ADDTS */ + status = sme_qos_setup(pMac, sessionId, + &pACInfo-> + requested_QoSInfo + [flow_info->tspec_mask - + 1], ac); + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: On session %d with AC %d in state SME_QOS_QOS_ON " + "sme_qos_setup returned with status %d", + __func__, __LINE__, sessionId, ac, + status); + if (SME_QOS_STATUS_SETUP_REQ_PENDING_RSP != + status) { + /* we aren't waiting for a response from the AP */ + /* so vote powersave back on */ + pSession->readyForPowerSave = true; + } + if (SME_QOS_STATUS_SETUP_REQ_PENDING_RSP == + status) { + new_state = SME_QOS_REQUESTED; + status = + SME_QOS_STATUS_RELEASE_REQ_PENDING_RSP; + pACInfo->tspec_pending = + flow_info->tspec_mask; + } else + if ((SME_QOS_STATUS_SETUP_SUCCESS_NO_ACM_NO_APSD_RSP == status) || (SME_QOS_STATUS_SETUP_SUCCESS_APSD_SET_ALREADY == status)) { + new_state = SME_QOS_QOS_ON; + pACInfo->num_flows[flow_info-> + tspec_mask - 1]--; + pACInfo->curr_QoSInfo[flow_info-> + tspec_mask - 1] = + pACInfo-> + requested_QoSInfo[flow_info-> + tspec_mask - 1]; + /* delete the entry from Flow List */ + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: Deleting entry at %p with flowID %d", + __func__, __LINE__, flow_info, + QosFlowID); + csr_ll_remove_entry(&sme_qos_cb.flow_list, + pEntry, true); + pDeletedFlow = flow_info; + if (SME_QOS_STATUS_SETUP_SUCCESS_APSD_SET_ALREADY == status) { + qdf_mem_zero(&search_key, + sizeof + (sme_QosSearchInfo)); + search_key.key.ac_type = ac; + search_key.index = + SME_QOS_SEARCH_KEY_INDEX_2; + search_key.sessionId = + sessionId; + hstatus = + sme_qos_find_all_in_flow_list + (pMac, search_key, + sme_qos_setup_fnp); + if (!QDF_IS_STATUS_SUCCESS + (hstatus)) { + QDF_TRACE + (QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_ERROR, + "%s: %d: couldn't notify other " + "entries on this AC =%d", + __func__, __LINE__, + ac); + } + } + status = + SME_QOS_STATUS_RELEASE_SUCCESS_RSP; + if (buffered_cmd) { + flow_info->QoSCallback(pMac, + flow_info-> + HDDcontext, + &pACInfo-> + curr_QoSInfo + [flow_info-> + tspec_mask + - 1], + status, + flow_info-> + QosFlowID); + } + } else { + /* unexpected status returned by sme_qos_setup() */ + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_ERROR, + "%s: %d: On session %d unexpected status %d " + "returned by sme_qos_setup", + __func__, __LINE__, sessionId, + status); + new_state = SME_QOS_LINK_UP; + pACInfo->num_flows[flow_info-> + tspec_mask - 1]--; + pACInfo->curr_QoSInfo[flow_info-> + tspec_mask - 1] = + pACInfo-> + requested_QoSInfo[flow_info-> + tspec_mask - 1]; + /* delete the entry from Flow List */ + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: On session %d deleting entry at " + "%p with flowID %d", __func__, + __LINE__, sessionId, + flow_info, QosFlowID); + csr_ll_remove_entry(&sme_qos_cb.flow_list, + pEntry, true); + pDeletedFlow = flow_info; + if (buffered_cmd) { + flow_info->QoSCallback(pMac, + flow_info-> + HDDcontext, + &pACInfo-> + curr_QoSInfo + [flow_info-> + tspec_mask + - 1], + status, + flow_info-> + QosFlowID); + } + } + } else { + /* err msg */ + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_ERROR, + "%s: %d: sme_qos_update_params() failed", + __func__, __LINE__); + /* unable to service the request */ + /* nothing is pending so vote powersave back on */ + pSession->readyForPowerSave = true; + new_state = SME_QOS_LINK_UP; + if (buffered_cmd) { + flow_info->QoSCallback(pMac, + flow_info-> + HDDcontext, + &pACInfo-> + curr_QoSInfo + [flow_info-> + tspec_mask - 1], + status, + flow_info-> + QosFlowID); + } + } + } else { + /* this is the only flow aggregated in this TSPEC */ + status = SME_QOS_STATUS_RELEASE_SUCCESS_RSP; + /* check if delts needs to be sent */ + if (CSR_IS_ADDTS_WHEN_ACMOFF_SUPPORTED(pMac) || + sme_qos_is_acm(pMac, pSession->assocInfo.pBssDesc, ac, + NULL)) { + /* check if other TSPEC for this AC is also in use */ + if (SME_QOS_TSPEC_MASK_BIT_1_2_SET != + pACInfo->tspec_mask_status) { + /* this is the only TSPEC active on this AC */ + /* so indicate that we no longer require APSD */ + pSession->apsdMask &= + ~(1 << (SME_QOS_EDCA_AC_VO - ac)); + /* Also update modifyProfileFields.uapsd_mask in CSR for consistency */ + csr_get_modify_profile_fields(pMac, + flow_info-> + sessionId, + &modifyProfileFields); + modifyProfileFields.uapsd_mask = + pSession->apsdMask; + csr_set_modify_profile_fields(pMac, + flow_info-> + sessionId, + &modifyProfileFields); + if (!pSession->apsdMask) { + /* this session no longer needs UAPSD */ + /* do any sessions still require UAPSD? */ + if (!sme_qos_is_uapsd_active()) { + /* No sessions require UAPSD so turn it off */ + /* (really don't care when PMC stops it) */ + sme_ps_uapsd_disable( + pMac, sessionId); + } + } + } + if (SME_QOS_RELEASE_DEFAULT == pACInfo->relTrig) { + /* send delts */ + hstatus = + qos_issue_command(pMac, sessionId, + eSmeCommandDelTs, + NULL, ac, + flow_info-> + tspec_mask); + if (!QDF_IS_STATUS_SUCCESS(hstatus)) { + /* err msg */ + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_ERROR, + "%s: %d: sme_qos_del_ts_req() failed", + __func__, __LINE__); + status = + SME_QOS_STATUS_RELEASE_FAILURE_RSP; + /* we won't be waiting for a response from the AP */ + /* so vote powersave back on */ + pSession->readyForPowerSave = + true; + } else { + pACInfo->tspec_mask_status &= + SME_QOS_TSPEC_MASK_BIT_1_2_SET + & (~flow_info->tspec_mask); + deltsIssued = true; + } + } else { + pSession->readyForPowerSave = true; + pACInfo->tspec_mask_status &= + SME_QOS_TSPEC_MASK_BIT_1_2_SET & + (~flow_info->tspec_mask); + deltsIssued = true; + } + } else if (pSession->apsdMask & + (1 << (SME_QOS_EDCA_AC_VO - ac))) { + /* reassoc logic */ + csr_get_modify_profile_fields(pMac, sessionId, + &modifyProfileFields); + modifyProfileFields.uapsd_mask |= + pSession->apsdMask; + modifyProfileFields.uapsd_mask &= + ~(1 << (SME_QOS_EDCA_AC_VO - ac)); + pSession->apsdMask &= + ~(1 << (SME_QOS_EDCA_AC_VO - ac)); + if (!pSession->apsdMask) { + /* this session no longer needs UAPSD */ + /* do any sessions still require UAPSD? */ + if (!sme_qos_is_uapsd_active()) { + /* No sessions require UAPSD so turn it off */ + /* (really don't care when PMC stops it) */ + sme_ps_uapsd_disable( + pMac, sessionId); + } + } + hstatus = sme_qos_request_reassoc(pMac, sessionId, + &modifyProfileFields, + false); + if (!QDF_IS_STATUS_SUCCESS(hstatus)) { + /* err msg */ + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_ERROR, + "%s: %d: Reassoc failed", + __func__, __LINE__); + status = + SME_QOS_STATUS_RELEASE_FAILURE_RSP; + /* we won't be waiting for a response from the AP */ + /* so vote powersave back on */ + pSession->readyForPowerSave = true; + } else { + pACInfo->reassoc_pending = false; /* no need to wait */ + pACInfo->prev_state = SME_QOS_LINK_UP; + pACInfo->tspec_pending = 0; + } + } else { + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: nothing to do for AC = %d", + __func__, __LINE__, ac); + /* we won't be waiting for a response from the AP */ + /* so vote powersave back on */ + pSession->readyForPowerSave = true; + } + + if (SME_QOS_RELEASE_BY_AP == pACInfo->relTrig) { + flow_info->QoSCallback(pMac, + flow_info->HDDcontext, + &pACInfo-> + curr_QoSInfo[flow_info-> + tspec_mask - + 1], + SME_QOS_STATUS_RELEASE_QOS_LOST_IND, + flow_info->QosFlowID); + + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: Deleting entry at %p with flowID %d", + __func__, __LINE__, flow_info, + flow_info->QosFlowID); + } else if (buffered_cmd) { + flow_info->QoSCallback(pMac, + flow_info->HDDcontext, + NULL, status, + flow_info->QosFlowID); + } + + if (SME_QOS_STATUS_RELEASE_FAILURE_RSP == status) { + break; + } + + if (((SME_QOS_TSPEC_MASK_BIT_1_2_SET & ~flow_info-> + tspec_mask) > 0) + && + ((SME_QOS_TSPEC_MASK_BIT_1_2_SET & ~flow_info-> + tspec_mask) <= SME_QOS_TSPEC_INDEX_MAX)) { + if (pACInfo-> + num_flows[(SME_QOS_TSPEC_MASK_BIT_1_2_SET & + ~flow_info->tspec_mask) - 1] > + 0) { + new_state = SME_QOS_QOS_ON; + } else { + new_state = SME_QOS_LINK_UP; + } + } else { + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: Exceeded the array bounds of pACInfo->num_flows", + __func__, __LINE__); + QDF_ASSERT(0); + return + SME_QOS_STATUS_RELEASE_INVALID_PARAMS_RSP; + } + + if (false == deltsIssued) { + qdf_mem_zero(&pACInfo-> + curr_QoSInfo[flow_info-> + tspec_mask - 1], + sizeof(sme_QosWmmTspecInfo)); + } + qdf_mem_zero(&pACInfo-> + requested_QoSInfo[flow_info->tspec_mask - + 1], + sizeof(sme_QosWmmTspecInfo)); + pACInfo->num_flows[flow_info->tspec_mask - 1]--; + /* delete the entry from Flow List */ + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: On session %d deleting entry at %p with flowID %d", + __func__, __LINE__, + sessionId, flow_info, QosFlowID); + csr_ll_remove_entry(&sme_qos_cb.flow_list, pEntry, + true); + pDeletedFlow = flow_info; + pACInfo->relTrig = SME_QOS_RELEASE_DEFAULT; + } + /* if we are doing reassoc & we are already in handoff state, no need + to move to requested state. But make sure to set the previous state + as requested state + */ + if (SME_QOS_HANDOFF != pACInfo->curr_state) { + sme_qos_state_transition(sessionId, ac, new_state); + } + if (pACInfo->reassoc_pending) { + pACInfo->prev_state = SME_QOS_REQUESTED; + } + break; + case SME_QOS_HANDOFF: + case SME_QOS_REQUESTED: + /* buffer cmd */ + cmd.command = SME_QOS_RELEASE_REQ; + cmd.pMac = pMac; + cmd.sessionId = sessionId; + cmd.u.releaseCmdInfo.QosFlowID = QosFlowID; + hstatus = sme_qos_buffer_cmd(&cmd, buffered_cmd); + if (!QDF_IS_STATUS_SUCCESS(hstatus)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: couldn't buffer the release request in state = %d", + __func__, __LINE__, pACInfo->curr_state); + /* unable to service the request */ + /* nothing is pending so vote powersave back on */ + pSession->readyForPowerSave = true; + return SME_QOS_STATUS_RELEASE_FAILURE_RSP; + } + status = SME_QOS_STATUS_RELEASE_REQ_PENDING_RSP; + break; + case SME_QOS_CLOSED: + case SME_QOS_INIT: + case SME_QOS_LINK_UP: + default: + /* print error msg */ + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: release request in unexpected state = %d", + __func__, __LINE__, pACInfo->curr_state); + QDF_ASSERT(0); + /* unable to service the request */ + /* nothing is pending so vote powersave back on */ + pSession->readyForPowerSave = true; + break; + } + /* if we deleted a flow, reclaim the memory */ + if (pDeletedFlow) { + qdf_mem_free(pDeletedFlow); + } + if ((SME_QOS_STATUS_RELEASE_SUCCESS_RSP == status)) { + (void)sme_qos_process_buffered_cmd(sessionId); + } + return status; +} + +/** + * sme_qos_setup() - internal SME QOS setup function. + * @pMac: Pointer to the global MAC parameter structure. + * @sessionId: Session upon which setup is being performed + * @pTspec_Info: Pointer to sme_QosWmmTspecInfo which contains the WMM + * TSPEC related info as defined above + * @ac: Enumeration of the various EDCA Access Categories. + * + * The internal qos setup function which has the intelligence + * if the request is NOP, or for APSD and/or need to send out ADDTS. + * It also does the sanity check for QAP, AP supports APSD etc. + * The logic used in the code might be confusing. + * + * Trying to cover all the cases here. + * AP supports App wants ACM = 1 Already set APSD Result + * | 0 | 0 | 0 | 0 | NO ACM NO APSD + * | 0 | 0 | 0 | 1 | NO ACM NO APSD/INVALID + * | 0 | 0 | 1 | 0 | ADDTS + * | 0 | 0 | 1 | 1 | ADDTS + * | 0 | 1 | 0 | 0 | FAILURE + * | 0 | 1 | 0 | 1 | INVALID + * | 0 | 1 | 1 | 0 | ADDTS + * | 0 | 1 | 1 | 1 | ADDTS + * | 1 | 0 | 0 | 0 | NO ACM NO APSD + * | 1 | 0 | 0 | 1 | NO ACM NO APSD + * | 1 | 0 | 1 | 0 | ADDTS + * | 1 | 0 | 1 | 1 | ADDTS + * | 1 | 1 | 0 | 0 | REASSOC + * | 1 | 1 | 0 | 1 | NOP: APSD SET ALREADY + * | 1 | 1 | 1 | 0 | ADDTS + * | 1 | 1 | 1 | 1 | ADDTS + * + * Return: SME_QOS_STATUS_SETUP_SUCCESS_RSP if the setup is successful' + */ +sme_QosStatusType sme_qos_setup(tpAniSirGlobal pMac, + uint8_t sessionId, + sme_QosWmmTspecInfo *pTspec_Info, + sme_QosEdcaAcType ac) +{ + sme_QosSessionInfo *pSession; + sme_QosACInfo *pACInfo; + sme_QosStatusType status = SME_QOS_STATUS_SETUP_FAILURE_RSP; + tDot11fBeaconIEs *pIes = NULL; + tCsrRoamModifyProfileFields modifyProfileFields; + QDF_STATUS hstatus; + if (!CSR_IS_SESSION_VALID(pMac, sessionId)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: Session Id %d is invalid", + __func__, __LINE__, sessionId); + return status; + } + pSession = &sme_qos_cb.sessionInfo[sessionId]; + if (!pSession->sessionActive) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: Session %d is inactive", + __func__, __LINE__, sessionId); + return status; + } + if (!pSession->assocInfo.pBssDesc) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: Session %d has an Invalid BSS Descriptor", + __func__, __LINE__, sessionId); + return status; + } + hstatus = csr_get_parsed_bss_description_ies(pMac, + pSession->assocInfo.pBssDesc, + &pIes); + if (!QDF_IS_STATUS_SUCCESS(hstatus)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: On session %d unable to parse BSS IEs", + __func__, __LINE__, sessionId); + return status; + } + + /* success so pIes was allocated */ + + if (!CSR_IS_QOS_BSS(pIes)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: On session %d AP doesn't support QoS", + __func__, __LINE__, sessionId); + qdf_mem_free(pIes); + /* notify HDD through the synchronous status msg */ + return SME_QOS_STATUS_SETUP_NOT_QOS_AP_RSP; + } + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + "%s: %d: UAPSD/PSB set %d: ", __func__, __LINE__, + pTspec_Info->ts_info.psb); + + pACInfo = &pSession->ac_info[ac]; + do { + /* is ACM enabled for this AC? */ + if (CSR_IS_ADDTS_WHEN_ACMOFF_SUPPORTED(pMac) || + sme_qos_is_acm(pMac, pSession->assocInfo.pBssDesc, + ac, NULL)) { + /* ACM is enabled for this AC so we must send an AddTS */ + if (pTspec_Info->ts_info.psb && + !(pIes->WMMParams. + qosInfo & SME_QOS_AP_SUPPORTS_APSD) + && !(pIes->WMMInfoAp.uapsd)) { + /* application is looking for APSD but AP doesn't support it */ + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_ERROR, + "%s: %d: On session %d AP doesn't support APSD", + __func__, __LINE__, sessionId); + break; + } + + if (SME_QOS_MAX_TID == pTspec_Info->ts_info.tid) { + /* App didn't set TID, generate one */ + pTspec_Info->ts_info.tid = + (uint8_t) (SME_QOS_WMM_UP_NC - + pTspec_Info->ts_info.up); + } + /* addts logic */ + hstatus = + qos_issue_command(pMac, sessionId, eSmeCommandAddTs, + pTspec_Info, ac, 0); + if (!QDF_IS_STATUS_SUCCESS(hstatus)) { + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_ERROR, + "%s: %d: sme_qos_add_ts_req() failed", + __func__, __LINE__); + break; + } + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: On session %d AddTS on AC %d is pending", + __func__, __LINE__, sessionId, ac); + status = SME_QOS_STATUS_SETUP_REQ_PENDING_RSP; + break; + } + /* ACM is not enabled for this AC */ + /* Is the application looking for APSD? */ + if (0 == pTspec_Info->ts_info.psb) { + /* no, we don't need APSD */ + /* but check the case, if the setup is called as a result of a release */ + /* or modify which boils down to the fact that APSD was set on this AC */ + /* but no longer needed - so we need a reassoc for the above case to */ + /* let the AP know */ + if (pSession-> + apsdMask & (1 << (SME_QOS_EDCA_AC_VO - ac))) { + /* APSD was formerly enabled on this AC but is no longer required */ + /* so we must reassociate */ + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: On session %d reassoc needed " + "to disable APSD on AC %d", __func__, + __LINE__, sessionId, ac); + csr_get_modify_profile_fields(pMac, sessionId, + &modifyProfileFields); + modifyProfileFields.uapsd_mask |= + pSession->apsdMask; + modifyProfileFields.uapsd_mask &= + ~(1 << (SME_QOS_EDCA_AC_VO - ac)); + hstatus = + sme_qos_request_reassoc(pMac, sessionId, + &modifyProfileFields, + false); + if (!QDF_IS_STATUS_SUCCESS(hstatus)) { + /* err msg */ + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_ERROR, + "%s: %d: Unable to request reassociation", + __func__, __LINE__); + break; + } else { + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: On session %d reassociation to enable " + "APSD on AC %d is pending", + __func__, __LINE__, sessionId, + ac); + status = + SME_QOS_STATUS_SETUP_REQ_PENDING_RSP; + pACInfo->reassoc_pending = true; + } + } else { + /* we don't need APSD on this AC */ + /* and we don't currently have APSD on this AC */ + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: Request is not looking for APSD & Admission " + "Control isn't mandatory for the AC", + __func__, __LINE__); + /* return success right away */ + status = + SME_QOS_STATUS_SETUP_SUCCESS_NO_ACM_NO_APSD_RSP; + } + break; + } else if (!(pIes->WMMParams.qosInfo & SME_QOS_AP_SUPPORTS_APSD) + && !(pIes->WMMInfoAp.uapsd)) { + /* application is looking for APSD but AP doesn't support it */ + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: On session %d AP doesn't support APSD", + __func__, __LINE__, sessionId); + break; + } else if (pSession-> + apsdMask & (1 << (SME_QOS_EDCA_AC_VO - ac))) { + /* application is looking for APSD */ + /* and it is already enabled on this AC */ + status = SME_QOS_STATUS_SETUP_SUCCESS_APSD_SET_ALREADY; + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: Request is looking for APSD and it is already " + "set for the AC", __func__, __LINE__); + break; + } else { + /* application is looking for APSD */ + /* but it is not enabled on this AC */ + /* so we need to reassociate */ + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_INFO_HIGH, + FL("On session %d reassoc needed to enable APSD on AC %d"), + sessionId, ac); + /* reassoc logic */ + /* update the UAPSD mask to include the new */ + /* AC on which APSD is requested */ + csr_get_modify_profile_fields(pMac, sessionId, + &modifyProfileFields); + modifyProfileFields.uapsd_mask |= + pSession->apsdMask; + modifyProfileFields.uapsd_mask |= + 1 << (SME_QOS_EDCA_AC_VO - ac); + hstatus = + sme_qos_request_reassoc(pMac, sessionId, + &modifyProfileFields, + false); + if (!QDF_IS_STATUS_SUCCESS(hstatus)) { + /* err msg */ + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_ERROR, + "%s: %d: Unable to request reassociation", + __func__, __LINE__); + break; + } else { + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_INFO_HIGH, + FL("On session %d reassociation to enable APSD on AC %d is pending"), + sessionId, ac); + status = + SME_QOS_STATUS_SETUP_REQ_PENDING_RSP; + pACInfo->reassoc_pending = true; + } + } + } while (0); + + qdf_mem_free(pIes); + return status; +} + +/* This is a dummy function now. But the purpose of me adding this was to + * delay the TSPEC processing till SET_KEY completes. This function can be + * used to do any SME_QOS processing after the SET_KEY. As of now, it is + * not required as we are ok with tspec getting programmed before set_key + * as the roam timings are measured without tspec in reassoc! + */ +QDF_STATUS sme_qos_process_set_key_success_ind(tpAniSirGlobal pMac, + uint8_t sessionId, void *pEvent_info) +{ + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_WARN, + "########### Set Key Complete #############"); + (void)sme_qos_process_buffered_cmd(sessionId); + return QDF_STATUS_SUCCESS; +} + +#ifdef FEATURE_WLAN_ESE +/** + * sme_qos_ese_save_tspec_response() - save TSPEC parameters. + * @pMac: Pointer to the global MAC parameter structure. + * @sessionId: SME session ID + * @pTspec: Pointer to the TSPEC IE from the reassoc rsp + * @ac: Access Category for which this TSPEC rsp is received + * @tspecIndex: flow/direction + * + * This function saves the TSPEC parameters that came along in the TSPEC IE + * in the reassoc response + * + * Return: QDF_STATUS_SUCCESS - Release is successful. + */ +static QDF_STATUS +sme_qos_ese_save_tspec_response(tpAniSirGlobal pMac, uint8_t sessionId, + tDot11fIEWMMTSPEC *pTspec, uint8_t ac, + uint8_t tspecIndex) +{ + tpSirAddtsRsp pAddtsRsp = + &sme_qos_cb.sessionInfo[sessionId].ac_info[ac].addTsRsp[tspecIndex]; + + ac = sme_qos_u_pto_ac_map[pTspec->user_priority]; + + qdf_mem_zero(pAddtsRsp, sizeof(tSirAddtsRsp)); + + pAddtsRsp->messageType = eWNI_SME_ADDTS_RSP; + pAddtsRsp->length = sizeof(tSirAddtsRsp); + pAddtsRsp->rc = eSIR_SUCCESS; + pAddtsRsp->sessionId = sessionId; + pAddtsRsp->rsp.dialogToken = 0; + pAddtsRsp->rsp.status = eSIR_SUCCESS; + pAddtsRsp->rsp.wmeTspecPresent = pTspec->present; + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO, + "%s: Copy Tspec to local data structure ac=%d, tspecIdx=%d", + __func__, ac, tspecIndex); + + if (pAddtsRsp->rsp.wmeTspecPresent) { + /* Copy TSPEC params received in assoc response to addts response */ + convert_wmmtspec(pMac, &pAddtsRsp->rsp.tspec, pTspec); + } + + return QDF_STATUS_SUCCESS; +} + +/** + * sme_qos_ese_process_reassoc_tspec_rsp() - process ese reassoc tspec response + * @pMac: Pointer to the global MAC parameter structure. + * @sessionId: SME session ID + * @pEven_info: Pointer to the smeJoinRsp structure + * + * This function processes the WMM TSPEC IE in the reassoc response. + * Reassoc triggered as part of ESE roaming to another ESE capable AP. + * If the TSPEC was added before reassoc, as part of Call Admission Control, + * the reasso req from the STA would carry the TSPEC parameters which were + * already negotiated with the older AP. + * + * Return: QDF_STATUS_SUCCESS - Release is successful. + */ +static +QDF_STATUS sme_qos_ese_process_reassoc_tspec_rsp(tpAniSirGlobal pMac, + uint8_t sessionId, + void *pEvent_info) +{ + sme_QosSessionInfo *pSession; + sme_QosACInfo *pACInfo; + tDot11fIEWMMTSPEC *pTspecIE = NULL; + tCsrRoamSession *pCsrSession = NULL; + tCsrRoamConnectedInfo *pCsrConnectedInfo = NULL; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + uint8_t ac, numTspec, cnt; + uint8_t tspec_flow_index, tspec_mask_status; + uint32_t tspecIeLen; + + pCsrSession = CSR_GET_SESSION(pMac, sessionId); + if (NULL == pCsrSession) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("session %d not found"), sessionId); + return QDF_STATUS_E_FAILURE; + } + pCsrConnectedInfo = &pCsrSession->connectedInfo; + pSession = &sme_qos_cb.sessionInfo[sessionId]; + + /* Get the TSPEC IEs which came along with the reassoc response */ + /* from the pbFrames pointer */ + pTspecIE = + (tDot11fIEWMMTSPEC *) (pCsrConnectedInfo->pbFrames + + pCsrConnectedInfo->nBeaconLength + + pCsrConnectedInfo->nAssocReqLength + + pCsrConnectedInfo->nAssocRspLength + + pCsrConnectedInfo->nRICRspLength); + + /* Get the number of tspecs Ies in the frame, the min length */ + /* should be atleast equal to the one TSPEC IE */ + tspecIeLen = pCsrConnectedInfo->nTspecIeLength; + if (tspecIeLen < sizeof(tDot11fIEWMMTSPEC)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("ESE Tspec IE len %d less than min %zu"), + tspecIeLen, sizeof(tDot11fIEWMMTSPEC)); + return QDF_STATUS_E_FAILURE; + } + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_WARN, + "TspecLen = %d, pbFrames = %p, pTspecIE = %p", + tspecIeLen, pCsrConnectedInfo->pbFrames, pTspecIE); + + numTspec = (tspecIeLen) / sizeof(tDot11fIEWMMTSPEC); + for (cnt = 0; cnt < numTspec; cnt++) { + ac = sme_qos_up_to_ac(pTspecIE->user_priority); + if (ac >= SME_QOS_EDCA_AC_MAX) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("ac %d more than it`s max value"), ac); + return QDF_STATUS_E_FAILURE; + } + pACInfo = &pSession->ac_info[ac]; + tspec_mask_status = pACInfo->tspec_mask_status; + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_WARN, + FL("UP=%d, ac=%d, tspec_mask_status=%x"), + pTspecIE->user_priority, ac, tspec_mask_status); + + for (tspec_flow_index = 0; + tspec_flow_index < SME_QOS_TSPEC_INDEX_MAX; + tspec_flow_index++) { + if (tspec_mask_status & (1 << tspec_flow_index)) { + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_WARN, + FL + ("Found Tspec entry flow = %d AC = %d"), + tspec_flow_index, ac); + sme_qos_ese_save_tspec_response(pMac, sessionId, + pTspecIE, ac, + tspec_flow_index); + } else { + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_WARN, + FL + ("Not found Tspec entry flow = %d AC = %d"), + tspec_flow_index, ac); + } + } + /* Increment the pointer to point it to the next TSPEC IE */ + pTspecIE++; + } + + /* Send the Aggregated QoS request to HAL */ + status = sme_qos_ft_aggr_qos_req(pMac, sessionId); + + return status; +} + +/** + * sme_qos_copy_tspec_info() - copy tspec info. + * @pMac: Pointer to the global MAC parameter structure. + * @pTspec_Info: source structure + * @pTspec: destination structure + * + * This function copies the existing TSPEC parameters from the source structure + * to the destination structure. + * + * Return: None + */ +static void sme_qos_copy_tspec_info(tpAniSirGlobal pMac, + sme_QosWmmTspecInfo *pTspec_Info, + tSirMacTspecIE *pTspec) +{ + /* As per WMM_AC_testplan_v0.39 Minimum Service Interval, Maximum Service + * Interval, Service Start Time, Suspension Interval and Delay Bound are + * all intended for HCCA operation and therefore must be set to zero*/ + pTspec->delayBound = pTspec_Info->delay_bound; + pTspec->inactInterval = pTspec_Info->inactivity_interval; + pTspec->length = SME_QOS_TSPEC_IE_LENGTH; + pTspec->maxBurstSz = pTspec_Info->max_burst_size; + pTspec->maxMsduSz = pTspec_Info->maximum_msdu_size; + pTspec->maxSvcInterval = pTspec_Info->max_service_interval; + pTspec->meanDataRate = pTspec_Info->mean_data_rate; + pTspec->mediumTime = pTspec_Info->medium_time; + pTspec->minDataRate = pTspec_Info->min_data_rate; + pTspec->minPhyRate = pTspec_Info->min_phy_rate; + pTspec->minSvcInterval = pTspec_Info->min_service_interval; + pTspec->nomMsduSz = pTspec_Info->nominal_msdu_size; + pTspec->peakDataRate = pTspec_Info->peak_data_rate; + pTspec->surplusBw = pTspec_Info->surplus_bw_allowance; + pTspec->suspendInterval = pTspec_Info->suspension_interval; + pTspec->svcStartTime = pTspec_Info->svc_start_time; + pTspec->tsinfo.traffic.direction = pTspec_Info->ts_info.direction; + + /* Make sure UAPSD is allowed */ + if (pTspec_Info->ts_info.psb) { + pTspec->tsinfo.traffic.psb = pTspec_Info->ts_info.psb; + } else { + pTspec->tsinfo.traffic.psb = 0; + pTspec_Info->ts_info.psb = 0; + } + pTspec->tsinfo.traffic.tsid = pTspec_Info->ts_info.tid; + pTspec->tsinfo.traffic.userPrio = pTspec_Info->ts_info.up; + pTspec->tsinfo.traffic.accessPolicy = SME_QOS_ACCESS_POLICY_EDCA; + pTspec->tsinfo.traffic.burstSizeDefn = + pTspec_Info->ts_info.burst_size_defn; + pTspec->tsinfo.traffic.ackPolicy = pTspec_Info->ts_info.ack_policy; + pTspec->type = SME_QOS_TSPEC_IE_TYPE; + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: up = %d, tid = %d", + __func__, __LINE__, + pTspec_Info->ts_info.up, pTspec_Info->ts_info.tid); +} + +/** + * sme_qos_ese_retrieve_tspec_info() - retrieve tspec info. + * @pMac: Pointer to the global MAC parameter structure. + * @sessionId: SME session ID + * @pTspecInfo: Pointer to the structure to carry back the TSPEC parameters + * + * This function is called by CSR when try to create reassoc request message to + * PE - csrSendSmeReassocReqMsg. This functions get the existing tspec + * parameters to be included in the reassoc request. + * + * Return: uint8_t - number of existing negotiated TSPECs + */ +uint8_t sme_qos_ese_retrieve_tspec_info(tpAniSirGlobal mac_ctx, + uint8_t session_id, tTspecInfo *tspec_info) +{ + sme_QosSessionInfo *session; + sme_QosACInfo *ac_info; + uint8_t ac, num_tspec = 0; + tTspecInfo *dst_tspec = tspec_info; + uint8_t tspec_mask; + uint8_t tspec_pending; + + /* + * TODO: Check if TSPEC has already been established + * if not return + */ + session = &sme_qos_cb.sessionInfo[session_id]; + for (ac = SME_QOS_EDCA_AC_BE; ac < SME_QOS_EDCA_AC_MAX; ac++) { + volatile uint8_t index = 0; + ac_info = &session->ac_info[ac]; + tspec_pending = ac_info->tspec_pending; + tspec_mask = ac_info->tspec_mask_status; + do { + /* + * If a tspec status is pending, take + * requested_QoSInfo for RIC request, + * else use curr_QoSInfo for the + * RIC request + */ + if ((tspec_mask & SME_QOS_TSPEC_MASK_BIT_1_SET) + && (tspec_pending & + SME_QOS_TSPEC_MASK_BIT_1_SET)){ + sme_qos_copy_tspec_info(mac_ctx, + &ac_info->requested_QoSInfo[index], + &dst_tspec->tspec); + dst_tspec->valid = true; + num_tspec++; + dst_tspec++; + } else if ((tspec_mask & SME_QOS_TSPEC_MASK_BIT_1_SET) + && !(tspec_pending & + SME_QOS_TSPEC_MASK_BIT_1_SET)){ + sme_qos_copy_tspec_info(mac_ctx, + &ac_info->curr_QoSInfo[index], + &dst_tspec->tspec); + dst_tspec->valid = true; + num_tspec++; + dst_tspec++; + } + tspec_mask >>= 1; + tspec_pending >>= 1; + index++; + } while (tspec_mask); + } + return num_tspec; +} + +#endif + +static +QDF_STATUS sme_qos_create_tspec_ricie(tpAniSirGlobal pMac, + sme_QosWmmTspecInfo *pTspec_Info, + uint8_t *pRICBuffer, uint32_t *pRICLength, + uint8_t *pRICIdentifier) +{ + tDot11fIERICDataDesc ricIE; + uint32_t nStatus; + + if (pRICBuffer == NULL || pRICIdentifier == NULL || pRICLength == NULL) { + QDF_ASSERT(0); + return QDF_STATUS_E_FAILURE; + } + + qdf_mem_zero(&ricIE, sizeof(tDot11fIERICDataDesc)); + + ricIE.present = 1; + ricIE.RICData.present = 1; + ricIE.RICData.resourceDescCount = 1; + ricIE.RICData.statusCode = 0; + ricIE.RICData.Identifier = sme_qos_assign_dialog_token(); +#ifndef USE_80211_WMMTSPEC_FOR_RIC + ricIE.TSPEC.present = 1; + ricIE.TSPEC.delay_bound = pTspec_Info->delay_bound; + ricIE.TSPEC.inactivity_int = pTspec_Info->inactivity_interval; + ricIE.TSPEC.burst_size = pTspec_Info->max_burst_size; + ricIE.TSPEC.max_msdu_size = pTspec_Info->maximum_msdu_size; + ricIE.TSPEC.max_service_int = pTspec_Info->max_service_interval; + ricIE.TSPEC.mean_data_rate = pTspec_Info->mean_data_rate; + ricIE.TSPEC.medium_time = 0; + ricIE.TSPEC.min_data_rate = pTspec_Info->min_data_rate; + ricIE.TSPEC.min_phy_rate = pTspec_Info->min_phy_rate; + ricIE.TSPEC.min_service_int = pTspec_Info->min_service_interval; + ricIE.TSPEC.size = pTspec_Info->nominal_msdu_size; + ricIE.TSPEC.peak_data_rate = pTspec_Info->peak_data_rate; + ricIE.TSPEC.surplus_bw_allowance = pTspec_Info->surplus_bw_allowance; + ricIE.TSPEC.suspension_int = pTspec_Info->suspension_interval; + ricIE.TSPEC.service_start_time = pTspec_Info->svc_start_time; + ricIE.TSPEC.direction = pTspec_Info->ts_info.direction; + /* Make sure UAPSD is allowed */ + if (pTspec_Info->ts_info.psb) { + ricIE.TSPEC.psb = pTspec_Info->ts_info.psb; + } else { + ricIE.TSPEC.psb = 0; + } + ricIE.TSPEC.tsid = pTspec_Info->ts_info.tid; + ricIE.TSPEC.user_priority = pTspec_Info->ts_info.up; + ricIE.TSPEC.access_policy = SME_QOS_ACCESS_POLICY_EDCA; + + *pRICIdentifier = ricIE.RICData.Identifier; + + nStatus = + dot11f_pack_ie_ric_data_desc(pMac, &ricIE, pRICBuffer, sizeof(ricIE), + pRICLength); + if (DOT11F_FAILED(nStatus)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL + ("Packing of RIC Data of length %d failed with status %d"), + *pRICLength, nStatus); + } +#else /* WMM TSPEC */ + /*As per WMM_AC_testplan_v0.39 Minimum Service Interval, Maximum Service + Interval, Service Start Time, Suspension Interval and Delay Bound are + all intended for HCCA operation and therefore must be set to zero */ + ricIE.WMMTSPEC.present = 1; + ricIE.WMMTSPEC.version = 1; + ricIE.WMMTSPEC.delay_bound = pTspec_Info->delay_bound; + ricIE.WMMTSPEC.inactivity_int = pTspec_Info->inactivity_interval; + ricIE.WMMTSPEC.burst_size = pTspec_Info->max_burst_size; + ricIE.WMMTSPEC.max_msdu_size = pTspec_Info->maximum_msdu_size; + ricIE.WMMTSPEC.max_service_int = pTspec_Info->max_service_interval; + ricIE.WMMTSPEC.mean_data_rate = pTspec_Info->mean_data_rate; + ricIE.WMMTSPEC.medium_time = 0; + ricIE.WMMTSPEC.min_data_rate = pTspec_Info->min_data_rate; + ricIE.WMMTSPEC.min_phy_rate = pTspec_Info->min_phy_rate; + ricIE.WMMTSPEC.min_service_int = pTspec_Info->min_service_interval; + ricIE.WMMTSPEC.size = pTspec_Info->nominal_msdu_size; + ricIE.WMMTSPEC.peak_data_rate = pTspec_Info->peak_data_rate; + ricIE.WMMTSPEC.surplus_bw_allowance = pTspec_Info->surplus_bw_allowance; + ricIE.WMMTSPEC.suspension_int = pTspec_Info->suspension_interval; + ricIE.WMMTSPEC.service_start_time = pTspec_Info->svc_start_time; + ricIE.WMMTSPEC.direction = pTspec_Info->ts_info.direction; + /* Make sure UAPSD is allowed */ + if (pTspec_Info->ts_info.psb) { + ricIE.WMMTSPEC.psb = pTspec_Info->ts_info.psb; + } else { + ricIE.WMMTSPEC.psb = 0; + } + ricIE.WMMTSPEC.tsid = pTspec_Info->ts_info.tid; + ricIE.WMMTSPEC.user_priority = pTspec_Info->ts_info.up; + ricIE.WMMTSPEC.access_policy = SME_QOS_ACCESS_POLICY_EDCA; + + nStatus = + dot11f_pack_ie_ric_data_desc(pMac, &ricIE, pRICBuffer, sizeof(ricIE), + pRICLength); + if (DOT11F_FAILED(nStatus)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL + ("Packing of RIC Data of length %d failed with status %d"), + *pRICLength, nStatus); + } +#endif /* 80211_TSPEC */ + *pRICIdentifier = ricIE.RICData.Identifier; + return nStatus; +} +/** + * sme_qos_process_ft_reassoc_req_ev()- processes reassoc request + * + * @session_id: SME Session Id + * + * This function Process reassoc request related to QOS + * + * Return: QDF_STATUS enumeration value. + */ +static QDF_STATUS sme_qos_process_ft_reassoc_req_ev( + uint8_t sessionId) +{ + sme_QosSessionInfo *session; + sme_QosACInfo *ac_info; + uint8_t ac, qos_requested = false; + uint8_t tspec_index; + sme_QosFlowInfoEntry *flow_info = NULL; + tListElem *entry = NULL; + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO_HIGH, + FL("Invoked on session %d"), sessionId); + + session = &sme_qos_cb.sessionInfo[sessionId]; + + for (ac = SME_QOS_EDCA_AC_BE; ac < SME_QOS_EDCA_AC_MAX; ac++) { + ac_info = &session->ac_info[ac]; + qos_requested = false; + + for (tspec_index = 0; + tspec_index < SME_QOS_TSPEC_INDEX_MAX; + tspec_index++) { + /* + * Only in the below case, copy the AC's curr + * QoS Info to requested QoS info + */ + if ((ac_info->ricIdentifier[tspec_index] + && !ac_info->tspec_pending) + || (ac_info-> + tspec_mask_status & (1 << tspec_index))) { + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_INFO, + FL("Copying the currentQos to " + "requestedQos for AC=%d, flow=%d"), + ac, tspec_index); + + ac_info->requested_QoSInfo[tspec_index] = + ac_info->curr_QoSInfo[tspec_index]; + qdf_mem_zero( + &ac_info->curr_QoSInfo[tspec_index], + sizeof(sme_QosWmmTspecInfo)); + qos_requested = true; + } + } + + /* + * Only if the tspec is required, transition the state to + * SME_QOS_REQUESTED for this AC + */ + if (qos_requested) { + switch (ac_info->curr_state) { + case SME_QOS_HANDOFF: + sme_qos_state_transition(sessionId, ac, + SME_QOS_REQUESTED); + break; + default: + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_ERROR, + FL("FT Reassoc req event in" + " unexpected state %d"), + ac_info->curr_state); + QDF_ASSERT(0); + } + } + } + + /* + * At this point of time, we are + * disconnected from the old AP, so it is safe + * to reset all these session variables + */ + session->apsdMask = 0; + session->uapsdAlreadyRequested = 0; + session->readyForPowerSave = 0; + + /* + * Now change reason and HO renewal of + * all the flow in this session only + */ + entry = csr_ll_peek_head(&sme_qos_cb.flow_list, false); + if (!entry) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_WARN, + FL("Flow List empty, nothing to update")); + return QDF_STATUS_E_FAILURE; + } + + do { + flow_info = GET_BASE_ADDR(entry, sme_QosFlowInfoEntry, link); + if (sessionId == flow_info->sessionId) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO_HIGH, + FL("Changing FlowID %d reason to SETUP" + "and HO renewal to false"), + flow_info->QosFlowID); + flow_info->reason = SME_QOS_REASON_SETUP; + flow_info->hoRenewal = true; + } + entry = csr_ll_next(&sme_qos_cb.flow_list, entry, false); + } while (entry); + + return QDF_STATUS_SUCCESS; +} + +/** + * sme_qos_fill_aggr_info - fill QOS Aggregation info + * + * @ac_id - index to the AC + * @ts_id - index to TS for a given AC + * @direction - traffic direction + * @msg - QOS message + * @session - sme session information + * + * this is a helper function to populate aggregation information + * for QOS message. + * + * Return: None + */ +static void sme_qos_fill_aggr_info(int ac_id, int ts_id, + sme_QosWmmDirType direction, + tSirAggrQosReq *msg, + sme_QosSessionInfo *session) +{ + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_WARN, + FL("Found tspec entry AC=%d, flow=%d, direction = %d"), + ac_id, ts_id, direction); + + msg->aggrInfo.aggrAddTsInfo[ac_id].dialogToken = + sme_qos_assign_dialog_token(); + msg->aggrInfo.aggrAddTsInfo[ac_id].lleTspecPresent = + session->ac_info[ac_id].addTsRsp[ts_id].rsp.lleTspecPresent; + msg->aggrInfo.aggrAddTsInfo[ac_id].numTclas = + session->ac_info[ac_id].addTsRsp[ts_id].rsp.numTclas; + qdf_mem_copy(msg->aggrInfo.aggrAddTsInfo[ac_id].tclasInfo, + session->ac_info[ac_id].addTsRsp[ts_id].rsp.tclasInfo, + SIR_MAC_TCLASIE_MAXNUM); + msg->aggrInfo.aggrAddTsInfo[ac_id].tclasProc = + session->ac_info[ac_id].addTsRsp[ts_id].rsp.tclasProc; + msg->aggrInfo.aggrAddTsInfo[ac_id].tclasProcPresent = + session->ac_info[ac_id].addTsRsp[ts_id].rsp.tclasProcPresent; + msg->aggrInfo.aggrAddTsInfo[ac_id].tspec = + session->ac_info[ac_id].addTsRsp[ts_id].rsp.tspec; + msg->aggrInfo.aggrAddTsInfo[ac_id].wmeTspecPresent = + session->ac_info[ac_id].addTsRsp[ts_id].rsp.wmeTspecPresent; + msg->aggrInfo.aggrAddTsInfo[ac_id].wsmTspecPresent = + session->ac_info[ac_id].addTsRsp[ts_id].rsp.wsmTspecPresent; + msg->aggrInfo.tspecIdx |= (1 << ac_id); + + /* Mark the index for this AC as pending for response, which would be */ + /* used to validate the AddTS response from HAL->PE->SME */ + session->ac_info[ac_id].tspec_pending = (1 << ts_id); + + return; +} + +/** + * sme_qos_ft_aggr_qos_req - send aggregated QOS request + * + * @mac_ctx - global MAC context + * @session_id - sme session Id + * + * This function is used to send aggregated QOS request to HAL. + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_qos_ft_aggr_qos_req(tpAniSirGlobal mac_ctx, uint8_t session_id) +{ + tSirAggrQosReq *aggr_req = NULL; + sme_QosSessionInfo *session; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + int i, j = 0; + uint8_t direction; + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO_HIGH, + FL("invoked on session %d"), session_id); + + session = &sme_qos_cb.sessionInfo[session_id]; + + aggr_req = (tSirAggrQosReq *) qdf_mem_malloc(sizeof(tSirAggrQosReq)); + + if (!aggr_req) { + /* err msg */ + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("couldn't allocate memory for the msg buffer")); + return QDF_STATUS_E_NOMEM; + } + + aggr_req->messageType = eWNI_SME_FT_AGGR_QOS_REQ; + aggr_req->length = sizeof(tSirAggrQosReq); + aggr_req->sessionId = session_id; + aggr_req->timeout = 0; + aggr_req->rspReqd = true; + qdf_mem_copy(&aggr_req->bssid.bytes[0], + &session->assocInfo.pBssDesc->bssId[0], + sizeof(struct qdf_mac_addr)); + + for (i = 0; i < SME_QOS_EDCA_AC_MAX; i++) { + for (j = 0; j < SME_QOS_TSPEC_INDEX_MAX; j++) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO, + FL("ac=%d, tspec_mask_staus=%x, tspec_index=%d"), + i, session->ac_info[i].tspec_mask_status, j); + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO, + FL("direction = %d"), + session->ac_info[i].addTsRsp[j].rsp.tspec. + tsinfo.traffic.direction); + /* Check if any flow is active on this AC */ + if (!((session->ac_info[i].tspec_mask_status) & + (1 << j))) + continue; + + direction = session->ac_info[i].addTsRsp[j].rsp.tspec. + tsinfo.traffic.direction; + + if ((direction == SME_QOS_WMM_TS_DIR_UPLINK) || + (direction == SME_QOS_WMM_TS_DIR_BOTH)) { + sme_qos_fill_aggr_info(i, j, direction, + aggr_req, session); + } + } + } + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO, + FL("Sending aggregated message to HAL 0x%x"), + aggr_req->aggrInfo.tspecIdx); + + if (QDF_IS_STATUS_SUCCESS(cds_send_mb_message_to_mac(aggr_req))) { + status = QDF_STATUS_SUCCESS; + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO_HIGH, + FL("sent down a AGGR QoS req to PE")); + } + + return status; +} + +static +QDF_STATUS sme_qos_process_ftric_response(tpAniSirGlobal pMac, + uint8_t sessionId, + tDot11fIERICDataDesc *pRicDataDesc, + uint8_t ac, uint8_t tspecIndex) +{ + uint8_t i = 0; + tpSirAddtsRsp pAddtsRsp + = + &sme_qos_cb.sessionInfo[sessionId].ac_info[ac].addTsRsp[tspecIndex]; + + qdf_mem_zero(pAddtsRsp, sizeof(tSirAddtsRsp)); + + pAddtsRsp->messageType = eWNI_SME_ADDTS_RSP; + pAddtsRsp->length = sizeof(tSirAddtsRsp); + pAddtsRsp->rc = pRicDataDesc->RICData.statusCode; + pAddtsRsp->sessionId = sessionId; + pAddtsRsp->rsp.dialogToken = pRicDataDesc->RICData.Identifier; + pAddtsRsp->rsp.status = pRicDataDesc->RICData.statusCode; + pAddtsRsp->rsp.wmeTspecPresent = pRicDataDesc->TSPEC.present; + if (pAddtsRsp->rsp.wmeTspecPresent) { + /* Copy TSPEC params received in RIC response to addts response */ + convert_tspec(pMac, &pAddtsRsp->rsp.tspec, &pRicDataDesc->TSPEC); + } + + pAddtsRsp->rsp.numTclas = pRicDataDesc->num_TCLAS; + if (pAddtsRsp->rsp.numTclas) { + for (i = 0; i < pAddtsRsp->rsp.numTclas; i++) { + /* Copy TCLAS info per index to the addts response */ + convert_tclas(pMac, &pAddtsRsp->rsp.tclasInfo[i], + &pRicDataDesc->TCLAS[i]); + } + } + + pAddtsRsp->rsp.tclasProcPresent = pRicDataDesc->TCLASSPROC.present; + if (pAddtsRsp->rsp.tclasProcPresent) + pAddtsRsp->rsp.tclasProc = pRicDataDesc->TCLASSPROC.processing; + + pAddtsRsp->rsp.schedulePresent = pRicDataDesc->Schedule.present; + if (pAddtsRsp->rsp.schedulePresent) { + /* Copy Schedule IE params to addts response */ + convert_schedule(pMac, &pAddtsRsp->rsp.schedule, + &pRicDataDesc->Schedule); + } + /* Need to check the below portion is a part of WMM TSPEC */ + /* Process Delay element */ + if (pRicDataDesc->TSDelay.present) + convert_ts_delay(pMac, &pAddtsRsp->rsp.delay, + &pRicDataDesc->TSDelay); + + /* Need to call for WMMTSPEC */ + if (pRicDataDesc->WMMTSPEC.present) { + convert_wmmtspec(pMac, &pAddtsRsp->rsp.tspec, + &pRicDataDesc->WMMTSPEC); + } + /* return sme_qos_process_add_ts_rsp(pMac, &addtsRsp); */ + return QDF_STATUS_SUCCESS; +} + +/** + * sme_qos_process_aggr_qos_rsp - process qos aggregation response + * + * @mac_ctx - global mac context + * @msgbuf - SME message buffer + * + * this function process the QOS aggregation response received. + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_qos_process_aggr_qos_rsp(tpAniSirGlobal mac_ctx, void *msgbuf) +{ + tpSirAggrQosRsp rsp = (tpSirAggrQosRsp) msgbuf; + tSirAddtsRsp addtsrsp; + QDF_STATUS status = QDF_STATUS_SUCCESS; + int i, j = 0; + uint8_t sessionid = rsp->sessionId; + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO, + FL("Received AGGR_QOS resp from LIM")); + + /* Copy the updated response information for TSPEC of all the ACs */ + for (i = 0; i < SIR_QOS_NUM_AC_MAX; i++) { + uint8_t tspec_mask_status = + sme_qos_cb.sessionInfo[sessionid].ac_info[i]. + tspec_mask_status; + for (j = 0; j < SME_QOS_TSPEC_INDEX_MAX; j++) { + uint8_t direction = + sme_qos_cb.sessionInfo[sessionid]. + ac_info[i].addTsRsp[j].rsp.tspec.tsinfo.traffic. + direction; + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO, + FL("Addts rsp from LIM AC=%d, flow=%d dir=%d, tspecIdx=%x"), + i, j, direction, rsp->aggrInfo.tspecIdx); + + /* Check if the direction is Uplink or bi-directional */ + if (!(((1 << i) & rsp->aggrInfo.tspecIdx) && + ((tspec_mask_status) & (1 << j)) && + ((direction == SME_QOS_WMM_TS_DIR_UPLINK) || + (direction == SME_QOS_WMM_TS_DIR_BOTH)))) { + continue; + } + addtsrsp = + sme_qos_cb.sessionInfo[sessionid].ac_info[i]. + addTsRsp[j]; + addtsrsp.rc = rsp->aggrInfo.aggrRsp[i].status; + addtsrsp.rsp.status = rsp->aggrInfo.aggrRsp[i].status; + addtsrsp.rsp.tspec = rsp->aggrInfo.aggrRsp[i].tspec; + + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_INFO, + FL("Processing Addts rsp from LIM AC=%d, flow=%d"), + i, j); + /* post ADD TS response for each */ + if (sme_qos_process_add_ts_rsp(mac_ctx, &addtsrsp) != + QDF_STATUS_SUCCESS) + status = QDF_STATUS_E_FAILURE; + } + } + return status; +} + +/** + * sme_qos_find_matching_tspec() - utility function to find matching tspec + * @mac_ctx: global MAC context + * @sessionid: session ID + * @ac: AC index + * @ac_info: Current AC info + * @ric_data_desc: pointer to ric data + * @ric_rsplen: pointer to ric response length + * + * This utility function is called by sme_qos_process_ft_reassoc_rsp_ev + * to find the matching tspec + * + * Return: QDF_STATUS + */ +static QDF_STATUS sme_qos_find_matching_tspec(tpAniSirGlobal mac_ctx, + uint8_t sessionid, uint8_t ac, sme_QosACInfo *ac_info, + tDot11fIERICDataDesc *ric_data_desc, uint32_t *ric_rsplen) +{ + uint8_t tspec_flow_index; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO, + FL("invoked on session %d"), sessionid); + + for (tspec_flow_index = 0; + tspec_flow_index < SME_QOS_TSPEC_INDEX_MAX; tspec_flow_index++) { + /* + * Only in the below case, copy the AC's curr QoS Info + * to requested QoS info + */ + if (!ac_info->ricIdentifier[tspec_flow_index]) + continue; + + if (!*ric_rsplen) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("RIC Response not received for AC %d on " + "TSPEC Index %d, RIC Req Identifier = %d"), + ac, tspec_flow_index, + ac_info->ricIdentifier[tspec_flow_index]); + QDF_ASSERT(0); + continue; + } + /* Now we got response for this identifier. Process it. */ + if (!ric_data_desc->present) + continue; + if (!ric_data_desc->RICData.present) + continue; + + if (ric_data_desc->RICData.Identifier != + ac_info->ricIdentifier[tspec_flow_index]) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("RIC response order not same as request sent. " + "Request ID = %d, Response ID = %d"), + ac_info->ricIdentifier[tspec_flow_index], + ric_data_desc->RICData.Identifier); + QDF_ASSERT(0); + } else { + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_INFO, + FL("Processing RIC Response for AC %d, " + "TSPEC Flow index %d with RIC ID %d "), + ac, tspec_flow_index, + ric_data_desc->RICData.Identifier); + status = sme_qos_process_ftric_response(mac_ctx, + sessionid, ric_data_desc, ac, + tspec_flow_index); + if (QDF_STATUS_SUCCESS != status) { + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_ERROR, + FL("Failed with status %d for AC %d in " + "TSPEC Flow index = %d"), + status, ac, tspec_flow_index); + } + } + ric_data_desc++; + *ric_rsplen -= sizeof(tDot11fIERICDataDesc); + } + return status; +} + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +/** + * sme_qos_find_matching_tspec_lfr3() - utility function to find matching tspec + * @mac_ctx: global MAC context + * @sessionid: session ID + * @ac: AC index + * @qos_session: QOS session + * @ric_data_desc: pointer to ric data + * @ric_rsplen: ric response length + * + * This utility function is called by sme_qos_process_ft_reassoc_rsp_ev + * to find the matching tspec while LFR3 is enabled. + * + * Return: QDF_STATUS + */ +static QDF_STATUS sme_qos_find_matching_tspec_lfr3(tpAniSirGlobal mac_ctx, + uint8_t sessionid, uint8_t ac, sme_QosSessionInfo *qos_session, + tDot11fIERICDataDesc *ric_data_desc, uint32_t ric_rsplen) +{ + sme_QosACInfo *ac_info; + uint8_t tspec_flow_idx; + bool found = false; + sme_QosWmmDirType direction, qos_dir; + uint8_t ac1; + tDot11fIERICDataDesc *ric_data = NULL; + uint32_t ric_len; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO, + FL("invoked on session %d"), sessionid); + + ric_data = ric_data_desc; + ric_len = ric_rsplen; + ac_info = &qos_session->ac_info[ac]; + for (tspec_flow_idx = 0; tspec_flow_idx < SME_QOS_TSPEC_INDEX_MAX; + tspec_flow_idx++) { + if (!((qos_session->ac_info[ac].tspec_mask_status) & + (1 << tspec_flow_idx))) + goto sme_qos_next_ric; + qos_dir = + ac_info->requested_QoSInfo[tspec_flow_idx].ts_info.direction; + do { + ac1 = sme_qos_up_to_ac( + ric_data->WMMTSPEC.user_priority); + if (ac == SME_QOS_EDCA_AC_MAX) { + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_ERROR, + FL("Invalid AC %d UP %d"), ac, + ric_data->WMMTSPEC.user_priority); + break; + } + direction = ric_data->WMMTSPEC.direction; + if (ac == ac1 && direction == qos_dir) { + found = true; + status = sme_qos_process_ftric_response(mac_ctx, + sessionid, ric_data, ac, + tspec_flow_idx); + if (QDF_STATUS_SUCCESS != status) { + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_ERROR, + FL("Failed with status %d for AC %d " + "in TSPEC Flow index = %d"), + status, ac, tspec_flow_idx); + } + break; + } + ric_data++; + ric_len -= sizeof(tDot11fIERICDataDesc); + } while (ric_len); +sme_qos_next_ric: + ric_data = ric_data_desc; + ric_len = ric_rsplen; + found = false; + } + + return status; +} +#endif /* WLAN_FEATURE_ROAM_OFFLOAD */ + +static +QDF_STATUS sme_qos_process_ft_reassoc_rsp_ev(tpAniSirGlobal mac_ctx, + uint8_t sessionid, void *event_info) +{ + sme_QosSessionInfo *qos_session; + sme_QosACInfo *ac_info; + uint8_t ac; + tDot11fIERICDataDesc *ric_data_desc = NULL; + QDF_STATUS status = QDF_STATUS_SUCCESS; + tCsrRoamSession *csr_session = CSR_GET_SESSION(mac_ctx, sessionid); + tCsrRoamConnectedInfo *csr_conn_info = NULL; + uint32_t ric_rsplen; +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + tDot11fIERICDataDesc *ric_data = NULL; + uint32_t ric_len; +#endif + + if (NULL == csr_session) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("The Session pointer is NULL")); + return QDF_STATUS_E_FAILURE; + } + csr_conn_info = &csr_session->connectedInfo; + ric_rsplen = csr_conn_info->nRICRspLength; + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO_HIGH, + FL("invoked on session %d"), sessionid); + + qos_session = &sme_qos_cb.sessionInfo[sessionid]; + + ric_data_desc = (tDot11fIERICDataDesc *) ((csr_conn_info->pbFrames) + + (csr_conn_info->nBeaconLength + + csr_conn_info->nAssocReqLength + + csr_conn_info->nAssocRspLength)); + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + if (!csr_session->roam_synch_in_progress) { +#endif + for (ac = SME_QOS_EDCA_AC_BE; ac < SME_QOS_EDCA_AC_MAX; ac++) { + ac_info = &qos_session->ac_info[ac]; + sme_qos_find_matching_tspec(mac_ctx, sessionid, ac, + ac_info, ric_data_desc, &ric_rsplen); + } + + if (ric_rsplen) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("RIC Resp still follows . Rem len = %d"), + ric_rsplen); + QDF_ASSERT(0); + } +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + } else { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO, + FL("LFR3-11r Compare RIC in Reassoc Resp to find" + " matching tspec in host.")); + ric_data = ric_data_desc; + ric_len = ric_rsplen; + if (ric_rsplen && ric_data_desc->present && + ric_data_desc->WMMTSPEC.present) { + for (ac = SME_QOS_EDCA_AC_BE; ac < SME_QOS_EDCA_AC_MAX; + ac++) { + sme_qos_find_matching_tspec_lfr3(mac_ctx, + sessionid, ac, qos_session, ric_data, + ric_len); + } + } else { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO, + FL("LFR3-11r ric_rsplen is zero or ric_data_desc is" + " not present or wmmtspec is not present")); + } + } +#endif + + /* Send the Aggregated QoS request to HAL */ + status = sme_qos_ft_aggr_qos_req(mac_ctx, sessionid); + + return status; +} + +/** + * sme_qos_add_ts_req() - send ADDTS request. + * @pMac: Pointer to the global MAC parameter structure. + * @sessionId: Session upon which the TSPEC should be added + * @pTspec_Info: Pointer to sme_QosWmmTspecInfo which contains the WMM + * TSPEC related info as defined above + * @ac: Enumeration of the various EDCA Access Categories. + * + * This function is used to send down the ADDTS request with TSPEC params to PE + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_qos_add_ts_req(tpAniSirGlobal pMac, + uint8_t sessionId, + sme_QosWmmTspecInfo *pTspec_Info, + sme_QosEdcaAcType ac) +{ + tSirAddtsReq *pMsg = NULL; + sme_QosSessionInfo *pSession; + QDF_STATUS status = QDF_STATUS_E_FAILURE; +#ifdef FEATURE_WLAN_ESE + tCsrRoamSession *pCsrSession = CSR_GET_SESSION(pMac, sessionId); +#endif +#ifdef FEATURE_WLAN_DIAG_SUPPORT + WLAN_HOST_DIAG_EVENT_DEF(qos, host_event_wlan_qos_payload_type); +#endif + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: invoked on session %d for AC %d", + __func__, __LINE__, sessionId, ac); + if (sessionId >= CSR_ROAM_SESSION_MAX) { + /* err msg */ + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: sessionId(%d) is invalid", + __func__, __LINE__, sessionId); + return QDF_STATUS_E_FAILURE; + } + + pSession = &sme_qos_cb.sessionInfo[sessionId]; + pMsg = (tSirAddtsReq *) qdf_mem_malloc(sizeof(tSirAddtsReq)); + if (!pMsg) { + /* err msg */ + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: couldn't allocate memory for the msg buffer", + __func__, __LINE__); + return QDF_STATUS_E_NOMEM; + } + pMsg->messageType = eWNI_SME_ADDTS_REQ; + pMsg->length = sizeof(tSirAddtsReq); + pMsg->sessionId = sessionId; + pMsg->timeout = 0; + pMsg->rspReqd = true; + pMsg->req.dialogToken = sme_qos_assign_dialog_token(); + /*As per WMM_AC_testplan_v0.39 Minimum Service Interval, Maximum Service + Interval, Service Start Time, Suspension Interval and Delay Bound are + all intended for HCCA operation and therefore must be set to zero */ + pMsg->req.tspec.delayBound = 0; + pMsg->req.tspec.inactInterval = pTspec_Info->inactivity_interval; + pMsg->req.tspec.length = SME_QOS_TSPEC_IE_LENGTH; + pMsg->req.tspec.maxBurstSz = pTspec_Info->max_burst_size; + pMsg->req.tspec.maxMsduSz = pTspec_Info->maximum_msdu_size; + pMsg->req.tspec.maxSvcInterval = pTspec_Info->max_service_interval; + pMsg->req.tspec.meanDataRate = pTspec_Info->mean_data_rate; + pMsg->req.tspec.mediumTime = pTspec_Info->medium_time; + pMsg->req.tspec.minDataRate = pTspec_Info->min_data_rate; + pMsg->req.tspec.minPhyRate = pTspec_Info->min_phy_rate; + pMsg->req.tspec.minSvcInterval = pTspec_Info->min_service_interval; + pMsg->req.tspec.nomMsduSz = pTspec_Info->nominal_msdu_size; + pMsg->req.tspec.peakDataRate = pTspec_Info->peak_data_rate; + pMsg->req.tspec.surplusBw = pTspec_Info->surplus_bw_allowance; + pMsg->req.tspec.suspendInterval = pTspec_Info->suspension_interval; + pMsg->req.tspec.svcStartTime = 0; + pMsg->req.tspec.tsinfo.traffic.direction = + pTspec_Info->ts_info.direction; + /* Make sure UAPSD is allowed */ + if (pTspec_Info->ts_info.psb) { + pMsg->req.tspec.tsinfo.traffic.psb = pTspec_Info->ts_info.psb; + } else { + pMsg->req.tspec.tsinfo.traffic.psb = 0; + pTspec_Info->ts_info.psb = 0; + } + pMsg->req.tspec.tsinfo.traffic.tsid = pTspec_Info->ts_info.tid; + pMsg->req.tspec.tsinfo.traffic.userPrio = pTspec_Info->ts_info.up; + pMsg->req.tspec.tsinfo.traffic.accessPolicy = + SME_QOS_ACCESS_POLICY_EDCA; + pMsg->req.tspec.tsinfo.traffic.burstSizeDefn = + pTspec_Info->ts_info.burst_size_defn; + pMsg->req.tspec.tsinfo.traffic.ackPolicy = + pTspec_Info->ts_info.ack_policy; + pMsg->req.tspec.type = SME_QOS_TSPEC_IE_TYPE; + /*Fill the BSSID pMsg->req.bssId */ + if (NULL == pSession->assocInfo.pBssDesc) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: BSS descriptor is NULL so we don't send request to PE", + __func__, __LINE__); + qdf_mem_free(pMsg); + return QDF_STATUS_E_FAILURE; + } + qdf_mem_copy(&pMsg->bssid.bytes[0], + &pSession->assocInfo.pBssDesc->bssId[0], + sizeof(struct qdf_mac_addr)); + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: up = %d, tid = %d", + __func__, __LINE__, + pTspec_Info->ts_info.up, pTspec_Info->ts_info.tid); +#ifdef FEATURE_WLAN_ESE + if (pCsrSession->connectedProfile.isESEAssoc) { + pMsg->req.tsrsIE.tsid = pTspec_Info->ts_info.up; + pMsg->req.tsrsPresent = 1; + } +#endif + if (QDF_IS_STATUS_SUCCESS(cds_send_mb_message_to_mac(pMsg))) { + status = QDF_STATUS_SUCCESS; + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: sent down a ADDTS req to PE", + __func__, __LINE__); + /* event: EVENT_WLAN_QOS */ +#ifdef FEATURE_WLAN_DIAG_SUPPORT + qos.eventId = SME_QOS_DIAG_ADDTS_REQ; + qos.reasonCode = SME_QOS_DIAG_USER_REQUESTED; + WLAN_HOST_DIAG_EVENT_REPORT(&qos, EVENT_WLAN_QOS); +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + } + return status; +} + +/*-------------------------------------------------------------------------- + \brief sme_qos_del_ts_req() - To send down the DELTS request with TSPEC params + to PE + + \param pMac - Pointer to the global MAC parameter structure. + \param sessionId - Session from which the TSPEC should be deleted + \param ac - Enumeration of the various EDCA Access Categories. + \param tspec_mask - on which tspec per AC, the delts is requested + + \return QDF_STATUS + + \sa + + --------------------------------------------------------------------------*/ +QDF_STATUS sme_qos_del_ts_req(tpAniSirGlobal pMac, + uint8_t sessionId, + sme_QosEdcaAcType ac, uint8_t tspec_mask) +{ + sme_QosSessionInfo *pSession; + sme_QosACInfo *pACInfo; + tSirDeltsReq *pMsg; + sme_QosWmmTspecInfo *pTspecInfo; + QDF_STATUS status = QDF_STATUS_E_FAILURE; +#ifdef FEATURE_WLAN_DIAG_SUPPORT + WLAN_HOST_DIAG_EVENT_DEF(qos, host_event_wlan_qos_payload_type); +#endif + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: invoked on session %d for AC %d", + __func__, __LINE__, sessionId, ac); + pMsg = (tSirDeltsReq *) qdf_mem_malloc(sizeof(tSirDeltsReq)); + if (!pMsg) { + /* err msg */ + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: couldn't allocate memory for the msg buffer", + __func__, __LINE__); + return QDF_STATUS_E_NOMEM; + } + /* get pointer to the TSPEC being deleted */ + pSession = &sme_qos_cb.sessionInfo[sessionId]; + pACInfo = &pSession->ac_info[ac]; + pTspecInfo = &pACInfo->curr_QoSInfo[tspec_mask - 1]; + pMsg->messageType = eWNI_SME_DELTS_REQ; + pMsg->length = sizeof(tSirDeltsReq); + pMsg->sessionId = sessionId; + pMsg->rspReqd = true; + pMsg->req.tspec.delayBound = pTspecInfo->delay_bound; + pMsg->req.tspec.inactInterval = pTspecInfo->inactivity_interval; + pMsg->req.tspec.length = SME_QOS_TSPEC_IE_LENGTH; + pMsg->req.tspec.maxBurstSz = pTspecInfo->max_burst_size; + pMsg->req.tspec.maxMsduSz = pTspecInfo->maximum_msdu_size; + pMsg->req.tspec.maxSvcInterval = pTspecInfo->max_service_interval; + pMsg->req.tspec.meanDataRate = pTspecInfo->mean_data_rate; + pMsg->req.tspec.mediumTime = pTspecInfo->medium_time; + pMsg->req.tspec.minDataRate = pTspecInfo->min_data_rate; + pMsg->req.tspec.minPhyRate = pTspecInfo->min_phy_rate; + pMsg->req.tspec.minSvcInterval = pTspecInfo->min_service_interval; + pMsg->req.tspec.nomMsduSz = pTspecInfo->nominal_msdu_size; + pMsg->req.tspec.peakDataRate = pTspecInfo->peak_data_rate; + pMsg->req.tspec.surplusBw = pTspecInfo->surplus_bw_allowance; + pMsg->req.tspec.suspendInterval = pTspecInfo->suspension_interval; + pMsg->req.tspec.svcStartTime = pTspecInfo->svc_start_time; + pMsg->req.tspec.tsinfo.traffic.direction = + pTspecInfo->ts_info.direction; + pMsg->req.tspec.tsinfo.traffic.psb = pTspecInfo->ts_info.psb; + pMsg->req.tspec.tsinfo.traffic.tsid = pTspecInfo->ts_info.tid; + pMsg->req.tspec.tsinfo.traffic.userPrio = pTspecInfo->ts_info.up; + pMsg->req.tspec.tsinfo.traffic.accessPolicy = + SME_QOS_ACCESS_POLICY_EDCA; + pMsg->req.tspec.tsinfo.traffic.burstSizeDefn = + pTspecInfo->ts_info.burst_size_defn; + pMsg->req.tspec.tsinfo.traffic.ackPolicy = + pTspecInfo->ts_info.ack_policy; + pMsg->req.tspec.type = SME_QOS_TSPEC_IE_TYPE; + /*Fill the BSSID pMsg->req.bssId */ + if (NULL == pSession->assocInfo.pBssDesc) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: BSS descriptor is NULL so we don't send request to PE", + __func__, __LINE__); + qdf_mem_free(pMsg); + return QDF_STATUS_E_FAILURE; + } + qdf_mem_copy(&pMsg->bssid.bytes[0], + &pSession->assocInfo.pBssDesc->bssId[0], + sizeof(struct qdf_mac_addr)); + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: up = %d, tid = %d", + __func__, __LINE__, + pTspecInfo->ts_info.up, pTspecInfo->ts_info.tid); + qdf_mem_zero(&pACInfo->curr_QoSInfo[tspec_mask - 1], + sizeof(sme_QosWmmTspecInfo)); + if (QDF_IS_STATUS_SUCCESS(cds_send_mb_message_to_mac(pMsg))) { + status = QDF_STATUS_SUCCESS; + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: sme_qos_del_ts_req:Test: sent down a DELTS req to PE", + __func__, __LINE__); + /* event: EVENT_WLAN_QOS */ +#ifdef FEATURE_WLAN_DIAG_SUPPORT + qos.eventId = SME_QOS_DIAG_DELTS; + qos.reasonCode = SME_QOS_DIAG_USER_REQUESTED; + WLAN_HOST_DIAG_EVENT_REPORT(&qos, EVENT_WLAN_QOS); +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + } + sme_set_tspec_uapsd_mask_per_session(pMac, + &pMsg->req.tspec.tsinfo, + sessionId); + + return status; +} + +/*-------------------------------------------------------------------------- + \brief sme_qos_process_add_ts_rsp() - Function to process the + eWNI_SME_ADDTS_RSP came from PE + + \param pMac - Pointer to the global MAC parameter structure. + \param pMsgBuf - Pointer to the msg buffer came from PE. + + \return QDF_STATUS + + \sa + + --------------------------------------------------------------------------*/ +QDF_STATUS sme_qos_process_add_ts_rsp(tpAniSirGlobal pMac, void *pMsgBuf) +{ + tpSirAddtsRsp paddts_rsp = (tpSirAddtsRsp) pMsgBuf; + sme_QosSessionInfo *pSession; + uint8_t sessionId = paddts_rsp->sessionId; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + sme_QosWmmUpType up = + (sme_QosWmmUpType) paddts_rsp->rsp.tspec.tsinfo.traffic.userPrio; + sme_QosACInfo *pACInfo; + sme_QosEdcaAcType ac; +#ifdef FEATURE_WLAN_DIAG_SUPPORT + WLAN_HOST_DIAG_EVENT_DEF(qos, host_event_wlan_qos_payload_type); +#endif + + pSession = &sme_qos_cb.sessionInfo[sessionId]; + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: invoked on session %d for UP %d", + __func__, __LINE__, sessionId, up); + + ac = sme_qos_up_to_ac(up); + if (SME_QOS_EDCA_AC_MAX == ac) { + /* err msg */ + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: invalid AC %d from UP %d", + __func__, __LINE__, ac, up); + + return QDF_STATUS_E_FAILURE; + } + pACInfo = &pSession->ac_info[ac]; + if (SME_QOS_HANDOFF == pACInfo->curr_state) { + sms_log(pMac, LOG1, + FL + ("ADDTS Response received for AC %d in HANDOFF State.. Dropping"), + ac); + pSession->readyForPowerSave = true; + return QDF_STATUS_SUCCESS; + } + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: Invoked on session %d with return code %d", + __func__, __LINE__, sessionId, paddts_rsp->rc); + /* our outstanding request has been serviced */ + /* we can go into powersave */ + pSession->readyForPowerSave = true; + if (paddts_rsp->rc) { + /* event: EVENT_WLAN_QOS */ +#ifdef FEATURE_WLAN_DIAG_SUPPORT + qos.eventId = SME_QOS_DIAG_ADDTS_RSP; + qos.reasonCode = SME_QOS_DIAG_ADDTS_REFUSED; + WLAN_HOST_DIAG_EVENT_REPORT(&qos, EVENT_WLAN_QOS); +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + status = + sme_qos_process_add_ts_failure_rsp(pMac, sessionId, + &paddts_rsp->rsp); + } else { + status = + sme_qos_process_add_ts_success_rsp(pMac, sessionId, + &paddts_rsp->rsp); + } + return status; +} + +/*-------------------------------------------------------------------------- + \brief sme_qos_process_del_ts_rsp() - Function to process the + eWNI_SME_DELTS_RSP came from PE + + \param pMac - Pointer to the global MAC parameter structure. + \param pMsgBuf - Pointer to the msg buffer came from PE. + + \return QDF_STATUS + + \sa + + --------------------------------------------------------------------------*/ +QDF_STATUS sme_qos_process_del_ts_rsp(tpAniSirGlobal pMac, void *pMsgBuf) +{ + tpSirDeltsRsp pDeltsRsp = (tpSirDeltsRsp) pMsgBuf; + sme_QosSessionInfo *pSession; + uint8_t sessionId = pDeltsRsp->sessionId; + /* msg */ + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: Invoked on session %d with return code %d", + __func__, __LINE__, sessionId, pDeltsRsp->rc); + pSession = &sme_qos_cb.sessionInfo[sessionId]; + /* our outstanding request has been serviced */ + /* we can go into powersave */ + pSession->readyForPowerSave = true; + (void)sme_qos_process_buffered_cmd(sessionId); + return QDF_STATUS_SUCCESS; +} + +/*-------------------------------------------------------------------------- + \brief sme_qos_process_del_ts_ind() - Function to process the + eWNI_SME_DELTS_IND came from PE + + Since it's a DELTS indication from AP, will notify all the flows running on + this AC about QoS release + \param pMac - Pointer to the global MAC parameter structure. + \param pMsgBuf - Pointer to the msg buffer came from PE. + + \return QDF_STATUS + + \sa + + --------------------------------------------------------------------------*/ +QDF_STATUS sme_qos_process_del_ts_ind(tpAniSirGlobal pMac, void *pMsgBuf) +{ + tpSirDeltsRsp pdeltsind = (tpSirDeltsRsp) pMsgBuf; + sme_QosSessionInfo *pSession; + sme_QosACInfo *pACInfo; + uint8_t sessionId = pdeltsind->sessionId; + sme_QosEdcaAcType ac; + sme_QosSearchInfo search_key; + tSirMacTSInfo *tsinfo; + sme_QosWmmUpType up = + (sme_QosWmmUpType) pdeltsind->rsp.tspec.tsinfo.traffic.userPrio; +#ifdef FEATURE_WLAN_DIAG_SUPPORT + WLAN_HOST_DIAG_EVENT_DEF(qos, host_event_wlan_qos_payload_type); +#endif + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: Invoked on session %d for UP %d", + __func__, __LINE__, sessionId, up); + tsinfo = &pdeltsind->rsp.tspec.tsinfo; + ac = sme_qos_up_to_ac(up); + if (SME_QOS_EDCA_AC_MAX == ac) { + /* err msg */ + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: invalid AC %d from UP %d", + __func__, __LINE__, ac, up); + return QDF_STATUS_E_FAILURE; + } + pSession = &sme_qos_cb.sessionInfo[sessionId]; + pACInfo = &pSession->ac_info[ac]; + + qdf_mem_zero(&search_key, sizeof(sme_QosSearchInfo)); + /* set the key type & the key to be searched in the Flow List */ + search_key.key.ac_type = ac; + search_key.index = SME_QOS_SEARCH_KEY_INDEX_2; + search_key.sessionId = sessionId; + /* find all Flows on the perticular AC & delete them, also send HDD indication */ + /* through the callback it registered per request */ + if (!QDF_IS_STATUS_SUCCESS + (sme_qos_find_all_in_flow_list(pMac, search_key, sme_qos_del_ts_ind_fnp))) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: no match found for ac = %d", __func__, + __LINE__, search_key.key.ac_type); + QDF_ASSERT(0); + return QDF_STATUS_E_FAILURE; + } + sme_set_tspec_uapsd_mask_per_session(pMac, tsinfo, sessionId); +/* event: EVENT_WLAN_QOS */ +#ifdef FEATURE_WLAN_DIAG_SUPPORT + qos.eventId = SME_QOS_DIAG_DELTS; + qos.reasonCode = SME_QOS_DIAG_DELTS_IND_FROM_AP; + WLAN_HOST_DIAG_EVENT_REPORT(&qos, EVENT_WLAN_QOS); +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + + return QDF_STATUS_SUCCESS; +} + +/*-------------------------------------------------------------------------- + \brief sme_qos_process_assoc_complete_ev() - Function to process the + SME_QOS_CSR_ASSOC_COMPLETE event indication from CSR + \param pEvent_info - Pointer to relevant info from CSR. + + \return QDF_STATUS + + \sa + + --------------------------------------------------------------------------*/ +QDF_STATUS sme_qos_process_assoc_complete_ev(tpAniSirGlobal pMac, uint8_t sessionId, + void *pEvent_info) +{ + sme_QosSessionInfo *pSession; + sme_QosACInfo *pACInfo; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + sme_QosEdcaAcType ac = SME_QOS_EDCA_AC_BE; + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: invoked on session %d", + __func__, __LINE__, sessionId); + pSession = &sme_qos_cb.sessionInfo[sessionId]; + if (((SME_QOS_INIT == pSession->ac_info[SME_QOS_EDCA_AC_BE].curr_state) + && (SME_QOS_INIT == + pSession->ac_info[SME_QOS_EDCA_AC_BK].curr_state) + && (SME_QOS_INIT == + pSession->ac_info[SME_QOS_EDCA_AC_VI].curr_state) + && (SME_QOS_INIT == + pSession->ac_info[SME_QOS_EDCA_AC_VO].curr_state)) + || (pSession->handoffRequested)) { + /* get the association info */ + if (!pEvent_info) { + /* err msg */ + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: pEvent_info is NULL", + __func__, __LINE__); + return status; + } + if (!((sme_QosAssocInfo *) pEvent_info)->pBssDesc) { + /* err msg */ + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: pBssDesc is NULL", + __func__, __LINE__); + return status; + } + if ((pSession->assocInfo.pBssDesc) && + (csr_is_bssid_match + (pMac, (struct qdf_mac_addr *) &pSession->assocInfo.pBssDesc->bssId, + (struct qdf_mac_addr *) &(((sme_QosAssocInfo *) pEvent_info)-> + pBssDesc->bssId)))) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: assoc with the same BSS, no update needed", + __func__, __LINE__); + } else { + status = sme_qos_save_assoc_info(pSession, pEvent_info); + } + } else { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: wrong state: BE %d, BK %d, VI %d, VO %d", + __func__, __LINE__, + pSession->ac_info[SME_QOS_EDCA_AC_BE].curr_state, + pSession->ac_info[SME_QOS_EDCA_AC_BK].curr_state, + pSession->ac_info[SME_QOS_EDCA_AC_VI].curr_state, + pSession->ac_info[SME_QOS_EDCA_AC_VO].curr_state); + QDF_ASSERT(0); + return status; + } + /* the session is active */ + pSession->sessionActive = true; + if (pSession->handoffRequested) { + pSession->handoffRequested = false; + /* renew all flows */ + (void)sme_qos_process_buffered_cmd(sessionId); + status = QDF_STATUS_SUCCESS; + } else { + for (ac = SME_QOS_EDCA_AC_BE; ac < SME_QOS_EDCA_AC_MAX; ac++) { + pACInfo = &pSession->ac_info[ac]; + switch (pACInfo->curr_state) { + case SME_QOS_INIT: + sme_qos_state_transition(sessionId, ac, + SME_QOS_LINK_UP); + break; + case SME_QOS_LINK_UP: + case SME_QOS_REQUESTED: + case SME_QOS_QOS_ON: + case SME_QOS_HANDOFF: + case SME_QOS_CLOSED: + default: + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_ERROR, + "%s: %d: On session %d AC %d is in wrong state %d", + __func__, __LINE__, sessionId, ac, + pACInfo->curr_state); + break; + } + } + } + return status; +} + +/*-------------------------------------------------------------------------- + \brief sme_qos_process_reassoc_req_ev() - Function to process the + SME_QOS_CSR_REASSOC_REQ event indication from CSR + \param pEvent_info - Pointer to relevant info from CSR. + + \return QDF_STATUS + + \sa + + --------------------------------------------------------------------------*/ +QDF_STATUS sme_qos_process_reassoc_req_ev(tpAniSirGlobal pMac, uint8_t sessionId, + void *pEvent_info) +{ + sme_QosSessionInfo *pSession; + sme_QosACInfo *pACInfo; + sme_QosEdcaAcType ac; + sme_QosFlowInfoEntry *flow_info = NULL; + tListElem *entry = NULL; + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: invoked on session %d", + __func__, __LINE__, sessionId); + pSession = &sme_qos_cb.sessionInfo[sessionId]; + + if (pSession->ftHandoffInProgress) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: no need for state transition, should " + "already be in handoff state", __func__, __LINE__); + if ((pSession->ac_info[0].curr_state != SME_QOS_HANDOFF) || + (pSession->ac_info[1].curr_state != SME_QOS_HANDOFF) || + (pSession->ac_info[2].curr_state != SME_QOS_HANDOFF) || + (pSession->ac_info[3].curr_state != SME_QOS_HANDOFF)) { + return QDF_STATUS_E_FAILURE; + } + sme_qos_process_ft_reassoc_req_ev(sessionId); + return QDF_STATUS_SUCCESS; + } + + if (pSession->handoffRequested) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: no need for state transition, should " + "already be in handoff state", __func__, __LINE__); + + if ((pSession->ac_info[0].curr_state != SME_QOS_HANDOFF) || + (pSession->ac_info[1].curr_state != SME_QOS_HANDOFF) || + (pSession->ac_info[2].curr_state != SME_QOS_HANDOFF) || + (pSession->ac_info[3].curr_state != SME_QOS_HANDOFF)) { + QDF_ASSERT(0); + return QDF_STATUS_E_FAILURE; + } + + /* + * Now change reason and HO renewal of + * all the flow in this session only + */ + entry = csr_ll_peek_head(&sme_qos_cb.flow_list, false); + if (!entry) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_WARN, + FL("Flow List empty, nothing to update")); + return QDF_STATUS_E_FAILURE; + } + + do { + flow_info = GET_BASE_ADDR(entry, sme_QosFlowInfoEntry, + link); + if (sessionId == flow_info->sessionId) { + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_INFO_HIGH, + FL("Changing FlowID %d reason to" + " SETUP and HO renewal to true"), + flow_info->QosFlowID); + flow_info->reason = SME_QOS_REASON_SETUP; + flow_info->hoRenewal = true; + } + entry = csr_ll_next(&sme_qos_cb.flow_list, entry, + false); + } while (entry); + + /* buffer the existing flows to be renewed after handoff is done */ + sme_qos_buffer_existing_flows(pMac, sessionId); + /* clean up the control block partially for handoff */ + sme_qos_cleanup_ctrl_blk_for_handoff(pMac, sessionId); + return QDF_STATUS_SUCCESS; + } +/* TBH: Assuming both handoff algo & 11r willn't be enabled at the same time */ + if (pSession->ftHandoffInProgress) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: no need for state transition, should " + "already be in handoff state", __func__, __LINE__); + + if ((pSession->ac_info[0].curr_state != SME_QOS_HANDOFF) || + (pSession->ac_info[1].curr_state != SME_QOS_HANDOFF) || + (pSession->ac_info[2].curr_state != SME_QOS_HANDOFF) || + (pSession->ac_info[3].curr_state != SME_QOS_HANDOFF)) { + QDF_ASSERT(0); + return QDF_STATUS_E_FAILURE; + } + + sme_qos_process_ft_reassoc_req_ev(sessionId); + return QDF_STATUS_SUCCESS; + } + + for (ac = SME_QOS_EDCA_AC_BE; ac < SME_QOS_EDCA_AC_MAX; ac++) { + pACInfo = &pSession->ac_info[ac]; + switch (pACInfo->curr_state) { + case SME_QOS_LINK_UP: + case SME_QOS_REQUESTED: + case SME_QOS_QOS_ON: + sme_qos_state_transition(sessionId, ac, SME_QOS_HANDOFF); + break; + case SME_QOS_HANDOFF: + /* This is normal because sme_qos_request_reassoc may already change the state */ + break; + case SME_QOS_CLOSED: + case SME_QOS_INIT: + default: + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: On session %d AC %d is in wrong state %d", + __func__, __LINE__, + sessionId, ac, pACInfo->curr_state); + break; + } + } + return QDF_STATUS_SUCCESS; +} + +/** + * sme_qos_handle_handoff_state() - utility function called by + * sme_qos_process_reassoc_success_ev + * @mac_ctx: global MAC context + * @qos_session: QOS session + * @ac_info: AC information + * @ac: current AC index + * @sessionid: session id + * + * This function is called by sme_qos_process_reassoc_success_ev + * to update the state machine on the reception of reassoc success + * notificaiton + * + * Return: QDF_STATUS + */ +static +QDF_STATUS sme_qos_handle_handoff_state(tpAniSirGlobal mac_ctx, + sme_QosSessionInfo *qos_session, sme_QosACInfo *ac_info, + sme_QosEdcaAcType ac, uint8_t sessionid) + +{ + sme_QosSearchInfo search_key; + sme_QosSearchInfo search_key1; + sme_QosEdcaAcType ac_index; + tListElem *list_elt = NULL; + sme_QosFlowInfoEntry *flow_info = NULL; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + + /* return to our previous state */ + sme_qos_state_transition(sessionid, ac, ac_info->prev_state); + /* for which ac APSD (hence the reassoc) is requested */ + if (!ac_info->reassoc_pending) + return QDF_STATUS_SUCCESS; + + /* + * update the apsd mask in CB - make sure to take care of the + * case where we are resetting the bit in apsd_mask + */ + if (ac_info->requested_QoSInfo[SME_QOS_TSPEC_INDEX_0].ts_info.psb) + qos_session->apsdMask |= 1 << (SME_QOS_EDCA_AC_VO - ac); + else + qos_session->apsdMask &= ~(1 << (SME_QOS_EDCA_AC_VO - ac)); + + ac_info->reassoc_pending = false; + /* + * during setup it gets set as addts & reassoc both gets a + * pending flag ac_info->tspec_pending = 0; + */ + sme_qos_state_transition(sessionid, ac, SME_QOS_QOS_ON); + /* notify HDD with new Service Interval */ + ac_info->curr_QoSInfo[SME_QOS_TSPEC_INDEX_0] = + ac_info->requested_QoSInfo[SME_QOS_TSPEC_INDEX_0]; + qdf_mem_zero(&search_key, sizeof(sme_QosSearchInfo)); + /* set the key type & the key to be searched in the Flow List */ + search_key.key.ac_type = ac; + search_key.index = SME_QOS_SEARCH_KEY_INDEX_2; + search_key.sessionId = sessionid; + /* notify PMC that reassoc is done for APSD on certain AC?? */ + + qdf_mem_zero(&search_key1, sizeof(sme_QosSearchInfo)); + /* set the hoRenewal field in control block if needed */ + search_key1.index = SME_QOS_SEARCH_KEY_INDEX_3; + search_key1.key.reason = SME_QOS_REASON_SETUP; + search_key1.sessionId = sessionid; + for (ac_index = SME_QOS_EDCA_AC_BE; ac_index < SME_QOS_EDCA_AC_MAX; + ac_index++) { + list_elt = sme_qos_find_in_flow_list(search_key1); + if (list_elt) { + flow_info = GET_BASE_ADDR(list_elt, + sme_QosFlowInfoEntry, link); + if (flow_info->ac_type == ac) { + ac_info->hoRenewal = flow_info->hoRenewal; + break; + } + } + } + /* + * notify HDD the success for the requested flow notify all the + * other flows running on the AC that QoS got modified + */ + status = sme_qos_find_all_in_flow_list(mac_ctx, search_key, + sme_qos_reassoc_success_ev_fnp); + if (!QDF_IS_STATUS_SUCCESS(status)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("no match found for ac = %d"), + search_key.key.ac_type); + QDF_ASSERT(0); + return QDF_STATUS_E_FAILURE; + } + ac_info->hoRenewal = false; + qdf_mem_zero(&ac_info->requested_QoSInfo[SME_QOS_TSPEC_INDEX_0], + sizeof(sme_QosWmmTspecInfo)); + + return status; +} + +/** + * sme_qos_process_reassoc_success_ev() - process SME_QOS_CSR_REASSOC_COMPLETE + * + * @mac_ctx: global MAC context + * @sessionid: session ID + * @event_info: event buffer from CSR + * + * Function to process the SME_QOS_CSR_REASSOC_COMPLETE event indication + * from CSR + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_qos_process_reassoc_success_ev(tpAniSirGlobal mac_ctx, + uint8_t sessionid, void *event_info) +{ + + tCsrRoamSession *csr_roam_session = NULL; + sme_QosSessionInfo *qos_session; + sme_QosACInfo *ac_info; + sme_QosEdcaAcType ac; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO_HIGH, + FL("invoked on session %d"), sessionid); + + if (CSR_ROAM_SESSION_MAX <= sessionid) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("invoked on session %d"), sessionid); + return status; + } + + csr_roam_session = CSR_GET_SESSION(mac_ctx, sessionid); + + qos_session = &sme_qos_cb.sessionInfo[sessionid]; + /* + * our pending reassociation has completed + * we can allow powersave + */ + qos_session->readyForPowerSave = true; + + /* get the association info */ + if (!event_info) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("event_info is NULL")); + return status; + } + + if (!((sme_QosAssocInfo *) event_info)->pBssDesc) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("pBssDesc is NULL")); + return status; + } + status = sme_qos_save_assoc_info(qos_session, event_info); + if (status) + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("sme_qos_save_assoc_info() failed")); + + /* + * Assuming both handoff algo & 11r willn't be enabled + * at the same time + */ + if (qos_session->handoffRequested) { + qos_session->handoffRequested = false; + /* renew all flows */ + (void)sme_qos_process_buffered_cmd(sessionid); + return QDF_STATUS_SUCCESS; + } + if (qos_session->ftHandoffInProgress) { + if (csr_roam_is11r_assoc(mac_ctx, sessionid)) { + if (csr_roam_session && + csr_roam_session->connectedInfo.nRICRspLength) { + status = sme_qos_process_ft_reassoc_rsp_ev( + mac_ctx, sessionid, + event_info); + } else { + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_ERROR, FL( + "session or RIC data is not present")); + } + } +#ifdef FEATURE_WLAN_ESE + /* + * If ESE association check for TSPEC IEs in the + * reassoc rsp frame + */ + if (csr_roam_is_ese_assoc(mac_ctx, sessionid)) { + if (csr_roam_session && + csr_roam_session->connectedInfo.nTspecIeLength) { + status = sme_qos_ese_process_reassoc_tspec_rsp( + mac_ctx, sessionid, event_info); + } + } +#endif + qos_session->ftHandoffInProgress = false; + qos_session->handoffRequested = false; + return status; + } + + qos_session->sessionActive = true; + for (ac = SME_QOS_EDCA_AC_BE; ac < SME_QOS_EDCA_AC_MAX; ac++) { + ac_info = &qos_session->ac_info[ac]; + switch (ac_info->curr_state) { + case SME_QOS_HANDOFF: + status = sme_qos_handle_handoff_state(mac_ctx, + qos_session, ac_info, ac, sessionid); + break; + case SME_QOS_INIT: + case SME_QOS_CLOSED: + /* NOP */ + status = QDF_STATUS_SUCCESS; + break; + case SME_QOS_LINK_UP: + case SME_QOS_REQUESTED: + case SME_QOS_QOS_ON: + default: + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("session %d AC %d is in wrong state %d"), + sessionid, ac, ac_info->curr_state); + break; + } + } + (void)sme_qos_process_buffered_cmd(sessionid); + return status; +} + +/*-------------------------------------------------------------------------- + \brief sme_qos_process_reassoc_failure_ev() - Function to process the + SME_QOS_CSR_REASSOC_FAILURE event indication from CSR + \param pEvent_info - Pointer to relevant info from CSR. + + \return QDF_STATUS + + \sa + + --------------------------------------------------------------------------*/ +QDF_STATUS sme_qos_process_reassoc_failure_ev(tpAniSirGlobal pMac, + uint8_t sessionId, void *pEvent_info) +{ + sme_QosSessionInfo *pSession; + sme_QosACInfo *pACInfo; + sme_QosEdcaAcType ac; + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: invoked on session %d", + __func__, __LINE__, sessionId); + pSession = &sme_qos_cb.sessionInfo[sessionId]; + /* our pending reassociation has completed */ + /* we can allow powersave */ + pSession->readyForPowerSave = true; + for (ac = SME_QOS_EDCA_AC_BE; ac < SME_QOS_EDCA_AC_MAX; ac++) { + pACInfo = &pSession->ac_info[ac]; + switch (pACInfo->curr_state) { + case SME_QOS_HANDOFF: + sme_qos_state_transition(sessionId, ac, SME_QOS_INIT); + if (pACInfo->reassoc_pending) { + pACInfo->reassoc_pending = false; + } + qdf_mem_zero(&pACInfo-> + curr_QoSInfo[SME_QOS_TSPEC_INDEX_0], + sizeof(sme_QosWmmTspecInfo)); + qdf_mem_zero(&pACInfo-> + requested_QoSInfo[SME_QOS_TSPEC_INDEX_0], + sizeof(sme_QosWmmTspecInfo)); + qdf_mem_zero(&pACInfo-> + curr_QoSInfo[SME_QOS_TSPEC_INDEX_1], + sizeof(sme_QosWmmTspecInfo)); + qdf_mem_zero(&pACInfo-> + requested_QoSInfo[SME_QOS_TSPEC_INDEX_1], + sizeof(sme_QosWmmTspecInfo)); + pACInfo->tspec_mask_status = SME_QOS_TSPEC_MASK_CLEAR; + pACInfo->tspec_pending = 0; + pACInfo->num_flows[SME_QOS_TSPEC_INDEX_0] = 0; + pACInfo->num_flows[SME_QOS_TSPEC_INDEX_1] = 0; + break; + case SME_QOS_INIT: + case SME_QOS_CLOSED: + /* NOP */ + break; + case SME_QOS_LINK_UP: + case SME_QOS_REQUESTED: + case SME_QOS_QOS_ON: + default: + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: On session %d AC %d is in wrong state %d", + __func__, __LINE__, + sessionId, ac, pACInfo->curr_state); + break; + } + } + /* need to clean up flows */ + sme_qos_delete_existing_flows(pMac, sessionId); + return QDF_STATUS_SUCCESS; +} + +/*-------------------------------------------------------------------------- + \brief sme_qos_process_handoff_assoc_req_ev() - Function to process the + SME_QOS_CSR_HANDOFF_ASSOC_REQ event indication from CSR + \param pEvent_info - Pointer to relevant info from CSR. + + \return QDF_STATUS + + \sa + + --------------------------------------------------------------------------*/ +QDF_STATUS sme_qos_process_handoff_assoc_req_ev(tpAniSirGlobal pMac, + uint8_t sessionId, void *pEvent_info) +{ + sme_QosSessionInfo *pSession; + sme_QosACInfo *pACInfo; + uint8_t ac; + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: invoked on session %d", + __func__, __LINE__, sessionId); + pSession = &sme_qos_cb.sessionInfo[sessionId]; + for (ac = SME_QOS_EDCA_AC_BE; ac < SME_QOS_EDCA_AC_MAX; ac++) { + pACInfo = &pSession->ac_info[ac]; + switch (pACInfo->curr_state) { + case SME_QOS_LINK_UP: + case SME_QOS_REQUESTED: + case SME_QOS_QOS_ON: + sme_qos_state_transition(sessionId, ac, SME_QOS_HANDOFF); + break; + case SME_QOS_HANDOFF: + /* print error msg */ + if (pSession->ftHandoffInProgress) { + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_INFO, + "%s: %d: SME_QOS_CSR_HANDOFF_ASSOC_REQ received in " + "SME_QOS_HANDOFF state with FT in progress", + __func__, __LINE__); + break; + } + + case SME_QOS_CLOSED: + case SME_QOS_INIT: + default: + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: On session %d AC %d is in wrong state %d", + __func__, __LINE__, + sessionId, ac, pACInfo->curr_state); + break; + } + } +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + if (csr_roam_is11r_assoc(pMac, sessionId)) { + pSession->ftHandoffInProgress = true; + } +#endif + /* If FT handoff is in progress, legacy handoff need not be enabled */ + if (!pSession->ftHandoffInProgress) { + pSession->handoffRequested = true; + } + /* this session no longer needs UAPSD */ + pSession->apsdMask = 0; + /* do any sessions still require UAPSD? */ + sme_ps_uapsd_disable(pMac, sessionId); + pSession->uapsdAlreadyRequested = false; + return QDF_STATUS_SUCCESS; +} + +/*-------------------------------------------------------------------------- + \brief sme_qos_process_handoff_success_ev() - Function to process the + SME_QOS_CSR_HANDOFF_COMPLETE event indication from CSR + \param pEvent_info - Pointer to relevant info from CSR. + + \return QDF_STATUS + + \sa + + --------------------------------------------------------------------------*/ +QDF_STATUS sme_qos_process_handoff_success_ev(tpAniSirGlobal pMac, + uint8_t sessionId, void *pEvent_info) +{ + sme_QosSessionInfo *pSession; + sme_QosACInfo *pACInfo; + uint8_t ac; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: invoked on session %d", + __func__, __LINE__, sessionId); + pSession = &sme_qos_cb.sessionInfo[sessionId]; + /* go back to original state before handoff */ + for (ac = SME_QOS_EDCA_AC_BE; ac < SME_QOS_EDCA_AC_MAX; ac++) { + pACInfo = &pSession->ac_info[ac]; + switch (pACInfo->curr_state) { + case SME_QOS_HANDOFF: + sme_qos_state_transition(sessionId, ac, + pACInfo->prev_state); + /* we will retry for the requested flow(s) with the new AP */ + if (SME_QOS_REQUESTED == pACInfo->curr_state) { + pACInfo->curr_state = SME_QOS_LINK_UP; + } + status = QDF_STATUS_SUCCESS; + break; + /* FT logic, has already moved it to QOS_REQUESTED state during the */ + /* reassoc request event, which would include the Qos (TSPEC) params */ + /* in the reassoc req frame */ + case SME_QOS_REQUESTED: + break; + case SME_QOS_INIT: + case SME_QOS_CLOSED: + case SME_QOS_LINK_UP: + case SME_QOS_QOS_ON: + default: +/* In case of 11r - RIC, we request QoS and Hand-off at the same time hence the + state may be SME_QOS_REQUESTED */ + if (pSession->ftHandoffInProgress) + break; + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: On session %d AC %d is in wrong state %d", + __func__, __LINE__, + sessionId, ac, pACInfo->curr_state); + break; + } + } + return status; +} + +/*-------------------------------------------------------------------------- + \brief sme_qos_process_handoff_failure_ev() - Function to process the + SME_QOS_CSR_HANDOFF_FAILURE event indication from CSR + \param pEvent_info - Pointer to relevant info from CSR. + + \return QDF_STATUS + + \sa + + --------------------------------------------------------------------------*/ +QDF_STATUS sme_qos_process_handoff_failure_ev(tpAniSirGlobal pMac, + uint8_t sessionId, void *pEvent_info) +{ + sme_QosSessionInfo *pSession; + sme_QosACInfo *pACInfo; + uint8_t ac; + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: invoked on session %d", + __func__, __LINE__, sessionId); + pSession = &sme_qos_cb.sessionInfo[sessionId]; + for (ac = SME_QOS_EDCA_AC_BE; ac < SME_QOS_EDCA_AC_MAX; ac++) { + pACInfo = &pSession->ac_info[ac]; + switch (pACInfo->curr_state) { + case SME_QOS_HANDOFF: + sme_qos_state_transition(sessionId, ac, SME_QOS_INIT); + /* need to clean up flows: TODO */ + qdf_mem_zero(&pACInfo-> + curr_QoSInfo[SME_QOS_TSPEC_INDEX_0], + sizeof(sme_QosWmmTspecInfo)); + qdf_mem_zero(&pACInfo-> + requested_QoSInfo[SME_QOS_TSPEC_INDEX_0], + sizeof(sme_QosWmmTspecInfo)); + qdf_mem_zero(&pACInfo-> + curr_QoSInfo[SME_QOS_TSPEC_INDEX_1], + sizeof(sme_QosWmmTspecInfo)); + qdf_mem_zero(&pACInfo-> + requested_QoSInfo[SME_QOS_TSPEC_INDEX_1], + sizeof(sme_QosWmmTspecInfo)); + pACInfo->tspec_mask_status = SME_QOS_TSPEC_MASK_CLEAR; + pACInfo->tspec_pending = 0; + pACInfo->num_flows[SME_QOS_TSPEC_INDEX_0] = 0; + pACInfo->num_flows[SME_QOS_TSPEC_INDEX_1] = 0; + break; + case SME_QOS_INIT: + case SME_QOS_CLOSED: + case SME_QOS_LINK_UP: + case SME_QOS_REQUESTED: + case SME_QOS_QOS_ON: + default: + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: On session %d AC %d is in wrong state %d", + __func__, __LINE__, + sessionId, ac, pACInfo->curr_state); + break; + } + } + /* no longer in handoff */ + pSession->handoffRequested = false; + /* clean up the assoc info */ + if (pSession->assocInfo.pBssDesc) { + qdf_mem_free(pSession->assocInfo.pBssDesc); + pSession->assocInfo.pBssDesc = NULL; + } + return QDF_STATUS_SUCCESS; +} + +/*-------------------------------------------------------------------------- + \brief sme_qos_process_disconnect_ev() - Function to process the + SME_QOS_CSR_DISCONNECT_REQ or SME_QOS_CSR_DISCONNECT_IND event indication + from CSR + \param pEvent_info - Pointer to relevant info from CSR. + + \return QDF_STATUS + + \sa + + --------------------------------------------------------------------------*/ +QDF_STATUS sme_qos_process_disconnect_ev(tpAniSirGlobal pMac, uint8_t sessionId, + void *pEvent_info) +{ + sme_QosSessionInfo *pSession; + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: invoked on session %d", + __func__, __LINE__, sessionId); + pSession = &sme_qos_cb.sessionInfo[sessionId]; + /* + * In case of 11r - RIC, we request QoS and Hand-off at the + * same time hence the state may be SME_QOS_REQUESTED + */ + if ((pSession->handoffRequested) + && !pSession->ftHandoffInProgress) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: no need for state transition, should " + "already be in handoff state", __func__, __LINE__); + if ((pSession->ac_info[0].curr_state != SME_QOS_HANDOFF) || + (pSession->ac_info[1].curr_state != SME_QOS_HANDOFF) || + (pSession->ac_info[2].curr_state != SME_QOS_HANDOFF) || + (pSession->ac_info[3].curr_state != SME_QOS_HANDOFF)) { + QDF_ASSERT(0); + return QDF_STATUS_SUCCESS; + } + + return QDF_STATUS_SUCCESS; + } + sme_qos_init_a_cs(pMac, sessionId); + /* this session doesn't require UAPSD */ + pSession->apsdMask = 0; + + sme_ps_uapsd_disable(pMac, sessionId); + + pSession->uapsdAlreadyRequested = false; + pSession->handoffRequested = false; + pSession->readyForPowerSave = true; + pSession->roamID = 0; + /* need to clean up buffered req */ + sme_qos_delete_buffered_requests(pMac, sessionId); + /* need to clean up flows */ + sme_qos_delete_existing_flows(pMac, sessionId); + /* clean up the assoc info */ + if (pSession->assocInfo.pBssDesc) { + qdf_mem_free(pSession->assocInfo.pBssDesc); + pSession->assocInfo.pBssDesc = NULL; + } + sme_qos_cb.sessionInfo[sessionId].sessionActive = false; + return QDF_STATUS_SUCCESS; +} + +/*-------------------------------------------------------------------------- + \brief sme_qos_process_join_req_ev() - Function to process the + SME_QOS_CSR_JOIN_REQ event indication from CSR + \param pEvent_info - Pointer to relevant info from CSR. + + \return QDF_STATUS + + \sa + + --------------------------------------------------------------------------*/ +QDF_STATUS sme_qos_process_join_req_ev(tpAniSirGlobal pMac, uint8_t sessionId, + void *pEvent_info) +{ + sme_QosSessionInfo *pSession; + sme_QosEdcaAcType ac; + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: invoked on session %d", + __func__, __LINE__, sessionId); + pSession = &sme_qos_cb.sessionInfo[sessionId]; + if (pSession->handoffRequested) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: no need for state transition, should " + "already be in handoff state", __func__, __LINE__); + if ((pSession->ac_info[0].curr_state != SME_QOS_HANDOFF) || + (pSession->ac_info[1].curr_state != SME_QOS_HANDOFF) || + (pSession->ac_info[2].curr_state != SME_QOS_HANDOFF) || + (pSession->ac_info[3].curr_state != SME_QOS_HANDOFF)) { + /* just print */ + QDF_ASSERT(0); + } + /* buffer the existing flows to be renewed after handoff is done */ + sme_qos_buffer_existing_flows(pMac, sessionId); + /* clean up the control block partially for handoff */ + sme_qos_cleanup_ctrl_blk_for_handoff(pMac, sessionId); + return QDF_STATUS_SUCCESS; + } + + for (ac = SME_QOS_EDCA_AC_BE; ac < SME_QOS_EDCA_AC_MAX; ac++) { + sme_qos_state_transition(sessionId, ac, SME_QOS_INIT); + } + /* clean up the assoc info if already set */ + if (pSession->assocInfo.pBssDesc) { + qdf_mem_free(pSession->assocInfo.pBssDesc); + pSession->assocInfo.pBssDesc = NULL; + } + return QDF_STATUS_SUCCESS; +} + +/** + * sme_qos_process_preauth_success_ind() - process preauth success indication + * @mac_ctx: global MAC context + * @sessionid: session ID + * @event_info: event buffer + * + * Function to process the SME_QOS_CSR_PREAUTH_SUCCESS_IND event indication + * from CSR + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_qos_process_preauth_success_ind(tpAniSirGlobal mac_ctx, + uint8_t sessionid, void *event_info) +{ + sme_QosSessionInfo *qos_session; + tCsrRoamSession *sme_session = CSR_GET_SESSION(mac_ctx, sessionid); + sme_QosACInfo *ac_info; + uint8_t ac; + QDF_STATUS status = QDF_STATUS_SUCCESS; + uint16_t ric_offset = 0; + uint32_t ric_ielen = 0; + uint8_t *ric_ie; + uint8_t tspec_mask_status = 0; + uint8_t tspec_pending_status = 0; + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO_HIGH, + FL("invoked on SME session %d"), sessionid); + + if (NULL == sme_session) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("sme_session is NULL")); + return QDF_STATUS_E_INVAL; + } + + qos_session = &sme_qos_cb.sessionInfo[sessionid]; + + for (ac = SME_QOS_EDCA_AC_BE; ac < SME_QOS_EDCA_AC_MAX; ac++) { + ac_info = &qos_session->ac_info[ac]; + + switch (ac_info->curr_state) { + case SME_QOS_LINK_UP: + case SME_QOS_REQUESTED: + case SME_QOS_QOS_ON: + sme_qos_state_transition(sessionid, ac, SME_QOS_HANDOFF); + break; + case SME_QOS_HANDOFF: + /* print error msg */ + case SME_QOS_CLOSED: + case SME_QOS_INIT: + default: + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Session %d AC %d is in wrong state %d"), + sessionid, ac, ac_info->curr_state); + break; + } + } + + qos_session->ftHandoffInProgress = true; + + /* Check if its a 11R roaming before preparing the RIC IEs */ + if (!csr_roam_is11r_assoc(mac_ctx, sessionid)) + return status; + + /* Data is accessed from saved PreAuth Rsp */ + if (NULL == sme_session->ftSmeContext.psavedFTPreAuthRsp) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("psavedFTPreAuthRsp is NULL")); + return QDF_STATUS_E_INVAL; + } + + /* + * Any Block Ack info there, should have been already filled by PE and + * present in this buffer and the ric_ies_length should contain the + * length of the whole RIC IEs. Filling of TSPEC info should start + * from this length + */ + ric_ie = sme_session->ftSmeContext.psavedFTPreAuthRsp->ric_ies; + ric_offset = + sme_session->ftSmeContext.psavedFTPreAuthRsp->ric_ies_length; + + /* + * Now we have to process the currentTspeInfo inside this session and + * create the RIC IEs + */ + for (ac = SME_QOS_EDCA_AC_BE; ac < SME_QOS_EDCA_AC_MAX; ac++) { + volatile uint8_t tspec_idx = 0; + ric_ielen = 0; + ac_info = &qos_session->ac_info[ac]; + tspec_pending_status = ac_info->tspec_pending; + tspec_mask_status = ac_info->tspec_mask_status; + qdf_mem_zero(ac_info->ricIdentifier, SME_QOS_TSPEC_INDEX_MAX); + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO, + FL("AC %d ==> TSPEC status = %d, tspec pending = %d"), + ac, tspec_mask_status, tspec_pending_status); + + do { + if (!(tspec_mask_status & 0x1)) + goto add_next_ric; + + /* + * If a tspec status is pending, take requested_QoSInfo + * for RIC request, else use curr_QoSInfo for the + * RIC request + */ + if (tspec_pending_status & 0x1) { + status = sme_qos_create_tspec_ricie(mac_ctx, + &ac_info->requested_QoSInfo[tspec_idx], + ric_ie + ric_offset, &ric_ielen, + &ac_info->ricIdentifier[tspec_idx]); + } else { + status = sme_qos_create_tspec_ricie(mac_ctx, + &ac_info->curr_QoSInfo[tspec_idx], + ric_ie + ric_offset, &ric_ielen, + &ac_info->ricIdentifier[tspec_idx]); + } +add_next_ric: + ric_offset += ric_ielen; + sme_session->ftSmeContext.psavedFTPreAuthRsp-> + ric_ies_length += ric_ielen; + tspec_mask_status >>= 1; + tspec_pending_status >>= 1; + tspec_idx++; + } while (tspec_mask_status); + } + return status; +} + +/*-------------------------------------------------------------------------- + \brief sme_qos_process_add_ts_failure_rsp() - Function to process the + Addts request failure response came from PE + + We will notify HDD only for the requested Flow, other Flows running on the AC + stay intact + + \param pMac - Pointer to the global MAC parameter structure. + \param pRsp - Pointer to the addts response structure came from PE. + + \return QDF_STATUS + + \sa + + --------------------------------------------------------------------------*/ +QDF_STATUS sme_qos_process_add_ts_failure_rsp(tpAniSirGlobal pMac, + uint8_t sessionId, + tSirAddtsRspInfo *pRsp) +{ + sme_QosSessionInfo *pSession; + sme_QosACInfo *pACInfo; + sme_QosEdcaAcType ac; + sme_QosSearchInfo search_key; + uint8_t tspec_pending; + sme_QosWmmUpType up = + (sme_QosWmmUpType) pRsp->tspec.tsinfo.traffic.userPrio; + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: invoked on session %d for UP %d", __func__, __LINE__, + sessionId, up); + ac = sme_qos_up_to_ac(up); + if (SME_QOS_EDCA_AC_MAX == ac) { + /* err msg */ + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: invalid AC %d from UP %d", + __func__, __LINE__, ac, up); + return QDF_STATUS_E_FAILURE; + } + pSession = &sme_qos_cb.sessionInfo[sessionId]; + pACInfo = &pSession->ac_info[ac]; + /* is there a TSPEC request pending on this AC? */ + tspec_pending = pACInfo->tspec_pending; + if (!tspec_pending) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: On session %d an AddTS is not pending on AC %d", + __func__, __LINE__, sessionId, ac); + QDF_ASSERT(0); + return QDF_STATUS_E_FAILURE; + } + + qdf_mem_zero(&search_key, sizeof(sme_QosSearchInfo)); + /* set the key type & the key to be searched in the Flow List */ + search_key.key.ac_type = ac; + search_key.index = SME_QOS_SEARCH_KEY_INDEX_2; + search_key.sessionId = sessionId; + if (!QDF_IS_STATUS_SUCCESS + (sme_qos_find_all_in_flow_list + (pMac, search_key, sme_qos_add_ts_failure_fnp))) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: On session %d no match found for ac = %d", + __func__, __LINE__, sessionId, + search_key.key.ac_type); + QDF_ASSERT(0); + return QDF_STATUS_E_FAILURE; + } + qdf_mem_zero(&pACInfo->requested_QoSInfo[tspec_pending - 1], + sizeof(sme_QosWmmTspecInfo)); + + if ((!pACInfo->num_flows[0]) && (!pACInfo->num_flows[1])) { + pACInfo->tspec_mask_status &= SME_QOS_TSPEC_MASK_BIT_1_2_SET & + (~pACInfo->tspec_pending); + sme_qos_state_transition(sessionId, ac, SME_QOS_LINK_UP); + } else { + sme_qos_state_transition(sessionId, ac, SME_QOS_QOS_ON); + } + pACInfo->tspec_pending = 0; + + (void)sme_qos_process_buffered_cmd(sessionId); + + return QDF_STATUS_SUCCESS; +} + +/** + * sme_qos_update_tspec_mask() - Utiltity function to update the tspec. + * @sessionid: Session upon which the TSPEC is being updated + * @search_key: search key + * @new_tspec_mask: tspec to be set for this AC + * + * Typical usage while aggregating unidirectional flows into a bi-directional + * flow on AC which is running multiple flows + * + * Return: QDF_STATUS + */ +static QDF_STATUS sme_qos_update_tspec_mask(uint8_t sessionid, + sme_QosSearchInfo search_key, + uint8_t new_tspec_mask) +{ + tListElem *list_elt = NULL, *list_next_elt = NULL; + sme_QosFlowInfoEntry *flow_info = NULL; + sme_QosSessionInfo *qos_session; + sme_QosACInfo *ac_info; + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO_HIGH, + FL("invoked on session %d for AC %d TSPEC %d"), + sessionid, search_key.key.ac_type, new_tspec_mask); + + qos_session = &sme_qos_cb.sessionInfo[sessionid]; + + if (search_key.key.ac_type < SME_QOS_EDCA_AC_MAX) { + ac_info = &qos_session->ac_info[search_key.key.ac_type]; + } else { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO_HIGH, + FL("Exceeded the array bounds")); + QDF_ASSERT(0); + return QDF_STATUS_E_FAILURE; + } + + list_elt = csr_ll_peek_head(&sme_qos_cb.flow_list, false); + if (!list_elt) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Flow List empty, nothing to update")); + return QDF_STATUS_E_FAILURE; + } + + while (list_elt) { + list_next_elt = csr_ll_next(&sme_qos_cb.flow_list, list_elt, + false); + flow_info = GET_BASE_ADDR(list_elt, sme_QosFlowInfoEntry, link); + + if (search_key.sessionId != flow_info->sessionId) { + list_elt = list_next_elt; + continue; + } + + if (search_key.index & SME_QOS_SEARCH_KEY_INDEX_4) { + if ((search_key.key.ac_type == flow_info->ac_type) && + (search_key.direction == + flow_info->QoSInfo.ts_info.direction)) { + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_INFO_HIGH, + FL("Flow %d matches"), flow_info->QosFlowID); + ac_info->num_flows[flow_info->tspec_mask - 1]--; + ac_info->num_flows[new_tspec_mask - 1]++; + flow_info->tspec_mask = new_tspec_mask; + } + } else if (search_key.index & SME_QOS_SEARCH_KEY_INDEX_5) { + if ((search_key.key.ac_type == flow_info->ac_type) && + (search_key.tspec_mask == flow_info->tspec_mask)) { + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_INFO_HIGH, + FL("Flow %d matches"), flow_info->QosFlowID); + ac_info->num_flows[flow_info->tspec_mask - 1]--; + ac_info->num_flows[new_tspec_mask - 1]++; + flow_info->tspec_mask = new_tspec_mask; + } + } + list_elt = list_next_elt; + } + + return QDF_STATUS_SUCCESS; +} + +/*-------------------------------------------------------------------------- + \brief sme_qos_process_add_ts_success_rsp() - Function to process the + Addts request success response came from PE + + We will notify HDD with addts success for the requested Flow, & for other + Flows running on the AC we will send an addts modify status + + \param pMac - Pointer to the global MAC parameter structure. + \param pRsp - Pointer to the addts response structure came from PE. + + \return QDF_STATUS + + \sa + + --------------------------------------------------------------------------*/ +QDF_STATUS sme_qos_process_add_ts_success_rsp(tpAniSirGlobal pMac, + uint8_t sessionId, + tSirAddtsRspInfo *pRsp) +{ + sme_QosSessionInfo *pSession; + sme_QosACInfo *pACInfo; + sme_QosEdcaAcType ac, ac_index; + sme_QosSearchInfo search_key; + sme_QosSearchInfo search_key1; + tCsrRoamSession *csr_session; + uint8_t tspec_pending; + tListElem *pEntry = NULL; + sme_QosFlowInfoEntry *flow_info = NULL; + sme_QosWmmUpType up = + (sme_QosWmmUpType) pRsp->tspec.tsinfo.traffic.userPrio; +#ifdef FEATURE_WLAN_DIAG_SUPPORT + WLAN_HOST_DIAG_EVENT_DEF(qos, host_event_wlan_qos_payload_type); + host_log_qos_tspec_pkt_type *log_ptr = NULL; +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: invoked on session %d for UP %d", + __func__, __LINE__, sessionId, up); + pSession = &sme_qos_cb.sessionInfo[sessionId]; + ac = sme_qos_up_to_ac(up); + if (SME_QOS_EDCA_AC_MAX == ac) { + /* err msg */ + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: invalid AC %d from UP %d", + __func__, __LINE__, ac, up); + return QDF_STATUS_E_FAILURE; + } + pACInfo = &pSession->ac_info[ac]; + /* is there a TSPEC request pending on this AC? */ + tspec_pending = pACInfo->tspec_pending; + if (!tspec_pending) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: On session %d an AddTS is not pending on AC %d", + __func__, __LINE__, sessionId, ac); + return QDF_STATUS_E_FAILURE; + } + /* App is looking for APSD or the App which was looking for APSD has been */ + /* released, so STA re-negotiated with AP */ + if (pACInfo->requested_QoSInfo[tspec_pending - 1].ts_info.psb) { + /* update the session's apsd mask */ + pSession->apsdMask |= 1 << (SME_QOS_EDCA_AC_VO - ac); + } else { + if (((SME_QOS_TSPEC_MASK_BIT_1_2_SET & ~tspec_pending) > 0) && + ((SME_QOS_TSPEC_MASK_BIT_1_2_SET & ~tspec_pending) <= + SME_QOS_TSPEC_INDEX_MAX)) { + if (!pACInfo->requested_QoSInfo + [(SME_QOS_TSPEC_MASK_BIT_1_2_SET & ~tspec_pending) - + 1].ts_info.psb) { + /* update the session's apsd mask */ + pSession->apsdMask &= + ~(1 << (SME_QOS_EDCA_AC_VO - ac)); + } + } else { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: Exceeded the array bounds of pACInfo->requested_QosInfo", + __func__, __LINE__); + QDF_ASSERT(0); + return QDF_STATUS_E_FAILURE; + } + } + + pACInfo->curr_QoSInfo[tspec_pending - 1].ts_info.burst_size_defn = + pRsp->tspec.tsinfo.traffic.burstSizeDefn; + pACInfo->curr_QoSInfo[tspec_pending - 1].ts_info.ack_policy = + pRsp->tspec.tsinfo.traffic.ackPolicy; + pACInfo->curr_QoSInfo[tspec_pending - 1].ts_info.up = + pRsp->tspec.tsinfo.traffic.userPrio; + pACInfo->curr_QoSInfo[tspec_pending - 1].ts_info.psb = + pRsp->tspec.tsinfo.traffic.psb; + pACInfo->curr_QoSInfo[tspec_pending - 1].ts_info.direction = + pRsp->tspec.tsinfo.traffic.direction; + pACInfo->curr_QoSInfo[tspec_pending - 1].ts_info.tid = + pRsp->tspec.tsinfo.traffic.tsid; + pACInfo->curr_QoSInfo[tspec_pending - 1].nominal_msdu_size = + pRsp->tspec.nomMsduSz; + pACInfo->curr_QoSInfo[tspec_pending - 1].maximum_msdu_size = + pRsp->tspec.maxMsduSz; + pACInfo->curr_QoSInfo[tspec_pending - 1].min_service_interval = + pRsp->tspec.minSvcInterval; + pACInfo->curr_QoSInfo[tspec_pending - 1].max_service_interval = + pRsp->tspec.maxSvcInterval; + pACInfo->curr_QoSInfo[tspec_pending - 1].inactivity_interval = + pRsp->tspec.inactInterval; + pACInfo->curr_QoSInfo[tspec_pending - 1].suspension_interval = + pRsp->tspec.suspendInterval; + pACInfo->curr_QoSInfo[tspec_pending - 1].svc_start_time = + pRsp->tspec.svcStartTime; + pACInfo->curr_QoSInfo[tspec_pending - 1].min_data_rate = + pRsp->tspec.minDataRate; + pACInfo->curr_QoSInfo[tspec_pending - 1].mean_data_rate = + pRsp->tspec.meanDataRate; + pACInfo->curr_QoSInfo[tspec_pending - 1].peak_data_rate = + pRsp->tspec.peakDataRate; + pACInfo->curr_QoSInfo[tspec_pending - 1].max_burst_size = + pRsp->tspec.maxBurstSz; + pACInfo->curr_QoSInfo[tspec_pending - 1].delay_bound = + pRsp->tspec.delayBound; + + pACInfo->curr_QoSInfo[tspec_pending - 1].min_phy_rate = + pRsp->tspec.minPhyRate; + pACInfo->curr_QoSInfo[tspec_pending - 1].surplus_bw_allowance = + pRsp->tspec.surplusBw; + pACInfo->curr_QoSInfo[tspec_pending - 1].medium_time = + pRsp->tspec.mediumTime; + + sme_set_tspec_uapsd_mask_per_session(pMac, + &pRsp->tspec.tsinfo, sessionId); + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: On session %d AddTspec Medium Time %d", + __func__, __LINE__, sessionId, pRsp->tspec.mediumTime); + + /* Check if the current flow is for bi-directional. If so, update the number of flows + * to reflect that all flows are aggregated into tspec index 0. */ + if ((pACInfo->curr_QoSInfo[pACInfo->tspec_pending - 1].ts_info. + direction == SME_QOS_WMM_TS_DIR_BOTH) + && (pACInfo->num_flows[SME_QOS_TSPEC_INDEX_1] > 0)) { + qdf_mem_zero(&search_key, sizeof(sme_QosSearchInfo)); + /* update tspec_mask for all the flows having SME_QOS_TSPEC_MASK_BIT_2_SET to SME_QOS_TSPEC_MASK_BIT_1_SET */ + search_key.key.ac_type = ac; + search_key.index = SME_QOS_SEARCH_KEY_INDEX_5; + search_key.sessionId = sessionId; + search_key.tspec_mask = SME_QOS_TSPEC_MASK_BIT_2_SET; + sme_qos_update_tspec_mask(sessionId, search_key, + SME_QOS_TSPEC_MASK_BIT_1_SET); + } + + qdf_mem_zero(&search_key1, sizeof(sme_QosSearchInfo)); + /* set the horenewal field in control block if needed */ + search_key1.index = SME_QOS_SEARCH_KEY_INDEX_3; + search_key1.key.reason = SME_QOS_REASON_SETUP; + search_key1.sessionId = sessionId; + for (ac_index = SME_QOS_EDCA_AC_BE; ac_index < SME_QOS_EDCA_AC_MAX; + ac_index++) { + pEntry = sme_qos_find_in_flow_list(search_key1); + if (pEntry) { + flow_info = + GET_BASE_ADDR(pEntry, sme_QosFlowInfoEntry, link); + if (flow_info->ac_type == ac) { + pACInfo->hoRenewal = flow_info->hoRenewal; + break; + } + } + } + qdf_mem_zero(&search_key, sizeof(sme_QosSearchInfo)); + /* set the key type & the key to be searched in the Flow List */ + search_key.key.ac_type = ac; + search_key.index = SME_QOS_SEARCH_KEY_INDEX_2; + search_key.sessionId = sessionId; + /* notify HDD the success for the requested flow */ + /* notify all the other flows running on the AC that QoS got modified */ + if (!QDF_IS_STATUS_SUCCESS + (sme_qos_find_all_in_flow_list + (pMac, search_key, sme_qos_add_ts_success_fnp))) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: On session %d no match found for ac %d", + __func__, __LINE__, sessionId, + search_key.key.ac_type); + QDF_ASSERT(0); + return QDF_STATUS_E_FAILURE; + } + pACInfo->hoRenewal = false; + qdf_mem_zero(&pACInfo->requested_QoSInfo[tspec_pending - 1], + sizeof(sme_QosWmmTspecInfo)); + /* event: EVENT_WLAN_QOS */ +#ifdef FEATURE_WLAN_DIAG_SUPPORT + qos.eventId = SME_QOS_DIAG_ADDTS_RSP; + qos.reasonCode = SME_QOS_DIAG_ADDTS_ADMISSION_ACCEPTED; + WLAN_HOST_DIAG_EVENT_REPORT(&qos, EVENT_WLAN_QOS); + WLAN_HOST_DIAG_LOG_ALLOC(log_ptr, host_log_qos_tspec_pkt_type, + LOG_WLAN_QOS_TSPEC_C); + if (log_ptr) { + log_ptr->delay_bound = + pACInfo->curr_QoSInfo[tspec_pending - 1].delay_bound; + log_ptr->inactivity_interval = + pACInfo->curr_QoSInfo[tspec_pending - + 1].inactivity_interval; + log_ptr->max_burst_size = + pACInfo->curr_QoSInfo[tspec_pending - 1].max_burst_size; + log_ptr->max_service_interval = + pACInfo->curr_QoSInfo[tspec_pending - + 1].max_service_interval; + log_ptr->maximum_msdu_size = + pACInfo->curr_QoSInfo[tspec_pending - 1].maximum_msdu_size; + log_ptr->mean_data_rate = + pACInfo->curr_QoSInfo[tspec_pending - 1].mean_data_rate; + log_ptr->medium_time = + pACInfo->curr_QoSInfo[tspec_pending - 1].medium_time; + log_ptr->min_data_rate = + pACInfo->curr_QoSInfo[tspec_pending - 1].min_data_rate; + log_ptr->min_phy_rate = + pACInfo->curr_QoSInfo[tspec_pending - 1].min_phy_rate; + log_ptr->min_service_interval = + pACInfo->curr_QoSInfo[tspec_pending - + 1].min_service_interval; + log_ptr->nominal_msdu_size = + pACInfo->curr_QoSInfo[tspec_pending - 1].nominal_msdu_size; + log_ptr->peak_data_rate = + pACInfo->curr_QoSInfo[tspec_pending - 1].peak_data_rate; + log_ptr->surplus_bw_allowance = + pACInfo->curr_QoSInfo[tspec_pending - + 1].surplus_bw_allowance; + log_ptr->suspension_interval = + pACInfo->curr_QoSInfo[tspec_pending - + 1].surplus_bw_allowance; + log_ptr->suspension_interval = + pACInfo->curr_QoSInfo[tspec_pending - + 1].suspension_interval; + log_ptr->svc_start_time = + pACInfo->curr_QoSInfo[tspec_pending - 1].svc_start_time; + log_ptr->tsinfo[0] = + pACInfo->curr_QoSInfo[tspec_pending - + 1].ts_info.direction << 5 | pACInfo-> + curr_QoSInfo[tspec_pending - 1].ts_info.tid << 1; + log_ptr->tsinfo[1] = + pACInfo->curr_QoSInfo[tspec_pending - + 1].ts_info.up << 11 | pACInfo-> + curr_QoSInfo[tspec_pending - 1].ts_info.psb << 10; + log_ptr->tsinfo[2] = 0; + } + WLAN_HOST_DIAG_LOG_REPORT(log_ptr); +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + pACInfo->tspec_pending = 0; + + sme_qos_state_transition(sessionId, ac, SME_QOS_QOS_ON); + + /* Inform this TSPEC IE change to FW */ + csr_session = CSR_GET_SESSION(pMac, sessionId); + if (csr_session != NULL && + csr_session->pCurRoamProfile->csrPersona == QDF_STA_MODE) { + csr_roam_offload_scan(pMac, sessionId, + ROAM_SCAN_OFFLOAD_UPDATE_CFG, + REASON_CONNECT_IES_CHANGED); + } + + (void)sme_qos_process_buffered_cmd(sessionId); + return QDF_STATUS_SUCCESS; +} + +/*-------------------------------------------------------------------------- + \brief sme_qos_aggregate_params() - Utiltity function to increament the TSPEC + params per AC. Typical usage while using flow aggregation or deletion of flows + + \param pInput_Tspec_Info - Pointer to sme_QosWmmTspecInfo which contains the + WMM TSPEC related info with which pCurrent_Tspec_Info will be updated + \param pCurrent_Tspec_Info - Pointer to sme_QosWmmTspecInfo which contains + current the WMM TSPEC related info + + \return QDF_STATUS + + \sa + + --------------------------------------------------------------------------*/ +QDF_STATUS sme_qos_aggregate_params(sme_QosWmmTspecInfo *pInput_Tspec_Info, + sme_QosWmmTspecInfo *pCurrent_Tspec_Info, + sme_QosWmmTspecInfo *pUpdated_Tspec_Info) +{ + sme_QosWmmTspecInfo TspecInfo; + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: invoked", __func__, __LINE__); + if (!pInput_Tspec_Info) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: input is NULL, nothing to aggregate", + __func__, __LINE__); + return QDF_STATUS_E_FAILURE; + } + if (!pCurrent_Tspec_Info) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: Current is NULL, can't aggregate", + __func__, __LINE__); + return QDF_STATUS_E_FAILURE; + } + qdf_mem_copy(&TspecInfo, pCurrent_Tspec_Info, + sizeof(sme_QosWmmTspecInfo)); + TspecInfo.ts_info.psb = pInput_Tspec_Info->ts_info.psb; + /*------------------------------------------------------------------------- + APSD preference is only meaningful if service interval was set by app + -------------------------------------------------------------------------*/ + if (pCurrent_Tspec_Info->min_service_interval && + pInput_Tspec_Info->min_service_interval && + (pCurrent_Tspec_Info->ts_info.direction != + pInput_Tspec_Info->ts_info.direction)) { + TspecInfo.min_service_interval = + QDF_MIN(pCurrent_Tspec_Info->min_service_interval, + pInput_Tspec_Info->min_service_interval); + } else if (pInput_Tspec_Info->min_service_interval) { + TspecInfo.min_service_interval = + pInput_Tspec_Info->min_service_interval; + } + if (pCurrent_Tspec_Info->max_service_interval && + pInput_Tspec_Info->max_service_interval && + (pCurrent_Tspec_Info->ts_info.direction != + pInput_Tspec_Info->ts_info.direction)) { + TspecInfo.max_service_interval = + QDF_MIN(pCurrent_Tspec_Info->max_service_interval, + pInput_Tspec_Info->max_service_interval); + } else { + TspecInfo.max_service_interval = + pInput_Tspec_Info->max_service_interval; + } + /*------------------------------------------------------------------------- + If directions don't match, it must necessarily be both uplink and + downlink + -------------------------------------------------------------------------*/ + if (pCurrent_Tspec_Info->ts_info.direction != + pInput_Tspec_Info->ts_info.direction) { + TspecInfo.ts_info.direction = + pInput_Tspec_Info->ts_info.direction; + } + /*------------------------------------------------------------------------- + Max MSDU size : these sizes are `maxed' + -------------------------------------------------------------------------*/ + TspecInfo.maximum_msdu_size = + QDF_MAX(pCurrent_Tspec_Info->maximum_msdu_size, + pInput_Tspec_Info->maximum_msdu_size); + + /*------------------------------------------------------------------------- + Inactivity interval : these sizes are `maxed' + -------------------------------------------------------------------------*/ + TspecInfo.inactivity_interval = + QDF_MAX(pCurrent_Tspec_Info->inactivity_interval, + pInput_Tspec_Info->inactivity_interval); + + /*------------------------------------------------------------------------- + Delay bounds: min of all values + Check on 0: if 0, it means initial value since delay can never be 0!! + -------------------------------------------------------------------------*/ + if (pCurrent_Tspec_Info->delay_bound) { + TspecInfo.delay_bound = + QDF_MIN(pCurrent_Tspec_Info->delay_bound, + pInput_Tspec_Info->delay_bound); + } else { + TspecInfo.delay_bound = pInput_Tspec_Info->delay_bound; + } + TspecInfo.max_burst_size = QDF_MAX(pCurrent_Tspec_Info->max_burst_size, + pInput_Tspec_Info->max_burst_size); + + /*------------------------------------------------------------------------- + Nominal MSDU size also has a fixed bit that needs to be `handled' before + aggregation + This can be handled only if previous size is the same as new or both have + the fixed bit set + These sizes are not added: but `maxed' + -------------------------------------------------------------------------*/ + TspecInfo.nominal_msdu_size = + QDF_MAX(pCurrent_Tspec_Info->nominal_msdu_size & ~SME_QOS_16BIT_MSB, + pInput_Tspec_Info->nominal_msdu_size & ~SME_QOS_16BIT_MSB); + + if (((pCurrent_Tspec_Info->nominal_msdu_size == 0) || + (pCurrent_Tspec_Info->nominal_msdu_size & SME_QOS_16BIT_MSB)) && + ((pInput_Tspec_Info->nominal_msdu_size == 0) || + (pInput_Tspec_Info->nominal_msdu_size & SME_QOS_16BIT_MSB))) { + TspecInfo.nominal_msdu_size |= SME_QOS_16BIT_MSB; + } + + /*------------------------------------------------------------------------- + Data rates: + Add up the rates for aggregation + -------------------------------------------------------------------------*/ + SME_QOS_BOUNDED_U32_ADD_Y_TO_X(TspecInfo.peak_data_rate, + pInput_Tspec_Info->peak_data_rate); + SME_QOS_BOUNDED_U32_ADD_Y_TO_X(TspecInfo.min_data_rate, + pInput_Tspec_Info->min_data_rate); + /* mean data rate = peak data rate: aggregate to be flexible on apps */ + SME_QOS_BOUNDED_U32_ADD_Y_TO_X(TspecInfo.mean_data_rate, + pInput_Tspec_Info->mean_data_rate); + + /*------------------------------------------------------------------------- + Suspension interval : this is set to the inactivity interval since per + spec it is less than or equal to inactivity interval + This is not provided by app since we currently don't support the HCCA + mode of operation + Currently set it to 0 to avoid confusion: Cisco ESE needs ~0; spec + requires inactivity interval to be > suspension interval: this could + be tricky! + -------------------------------------------------------------------------*/ + TspecInfo.suspension_interval = pInput_Tspec_Info->suspension_interval; + /*------------------------------------------------------------------------- + Remaining parameters do not come from app as they are very WLAN + air interface specific + Set meaningful values here + -------------------------------------------------------------------------*/ + TspecInfo.medium_time = 0; /* per WMM spec */ + TspecInfo.min_phy_rate = SME_QOS_MIN_PHY_RATE; + TspecInfo.svc_start_time = 0; /* arbitrary */ + TspecInfo.surplus_bw_allowance += + pInput_Tspec_Info->surplus_bw_allowance; + if (TspecInfo.surplus_bw_allowance > SME_QOS_SURPLUS_BW_ALLOWANCE) { + TspecInfo.surplus_bw_allowance = SME_QOS_SURPLUS_BW_ALLOWANCE; + } + /* Set ack_policy to block ack even if one stream requests block ack policy */ + if ((pInput_Tspec_Info->ts_info.ack_policy == + SME_QOS_WMM_TS_ACK_POLICY_HT_IMMEDIATE_BLOCK_ACK) + || (pCurrent_Tspec_Info->ts_info.ack_policy == + SME_QOS_WMM_TS_ACK_POLICY_HT_IMMEDIATE_BLOCK_ACK)) { + TspecInfo.ts_info.ack_policy = + SME_QOS_WMM_TS_ACK_POLICY_HT_IMMEDIATE_BLOCK_ACK; + } + + if (pInput_Tspec_Info->ts_info.burst_size_defn + || pCurrent_Tspec_Info->ts_info.burst_size_defn) { + TspecInfo.ts_info.burst_size_defn = 1; + } + if (pUpdated_Tspec_Info) { + qdf_mem_copy(pUpdated_Tspec_Info, &TspecInfo, + sizeof(sme_QosWmmTspecInfo)); + } else { + qdf_mem_copy(pCurrent_Tspec_Info, &TspecInfo, + sizeof(sme_QosWmmTspecInfo)); + } + return QDF_STATUS_SUCCESS; +} + +/*-------------------------------------------------------------------------- + \brief sme_qos_update_params() - Utiltity function to update the TSPEC + params per AC. Typical usage while deleting flows on AC which is running + multiple flows + + \param sessionId - Session upon which the TSPEC is being updated + \param ac - Enumeration of the various EDCA Access Categories. + \param tspec_mask - on which tspec per AC, the update is requested + + \return QDF_STATUS + + \sa + + --------------------------------------------------------------------------*/ +static QDF_STATUS sme_qos_update_params(uint8_t sessionId, + sme_QosEdcaAcType ac, + uint8_t tspec_mask, + sme_QosWmmTspecInfo *pTspec_Info) +{ + tListElem *pEntry = NULL, *pNextEntry = NULL; + sme_QosSessionInfo *pSession; + sme_QosACInfo *pACInfo; + sme_QosFlowInfoEntry *flow_info = NULL; + sme_QosWmmTspecInfo Tspec_Info; + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: invoked on session %d for AC %d TSPEC %d", + __func__, __LINE__, sessionId, ac, tspec_mask); + if (!pTspec_Info) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: output is NULL, can't aggregate", + __func__, __LINE__); + return QDF_STATUS_E_FAILURE; + } + qdf_mem_zero(&Tspec_Info, sizeof(sme_QosWmmTspecInfo)); + pEntry = csr_ll_peek_head(&sme_qos_cb.flow_list, false); + if (!pEntry) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: Flow List empty, nothing to update", + __func__, __LINE__); + return QDF_STATUS_E_FAILURE; + } + pSession = &sme_qos_cb.sessionInfo[sessionId]; + pACInfo = &pSession->ac_info[ac]; + /* init the TS info field */ + Tspec_Info.ts_info.up = + pACInfo->curr_QoSInfo[tspec_mask - 1].ts_info.up; + Tspec_Info.ts_info.psb = + pACInfo->curr_QoSInfo[tspec_mask - 1].ts_info.psb; + Tspec_Info.ts_info.tid = + pACInfo->curr_QoSInfo[tspec_mask - 1].ts_info.tid; + while (pEntry) { + pNextEntry = csr_ll_next(&sme_qos_cb.flow_list, pEntry, false); + flow_info = GET_BASE_ADDR(pEntry, sme_QosFlowInfoEntry, link); + if ((sessionId == flow_info->sessionId) && + (ac == flow_info->ac_type) && + (tspec_mask == flow_info->tspec_mask)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: Flow %d matches", + __func__, __LINE__, flow_info->QosFlowID); + + if ((SME_QOS_REASON_RELEASE == flow_info->reason) || + (SME_QOS_REASON_MODIFY == flow_info->reason)) { + /* msg */ + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: Skipping Flow %d as it is marked " + "for release/modify", __func__, + __LINE__, flow_info->QosFlowID); + } else + if (!QDF_IS_STATUS_SUCCESS + (sme_qos_aggregate_params + (&flow_info->QoSInfo, &Tspec_Info, NULL))) { + /* err msg */ + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_ERROR, + "%s: %d: sme_qos_aggregate_params() failed", + __func__, __LINE__); + } + } + pEntry = pNextEntry; + } + /* return the aggregate */ + *pTspec_Info = Tspec_Info; + return QDF_STATUS_SUCCESS; +} + +/*-------------------------------------------------------------------------- + \brief sme_qos_ac_to_up() - Utiltity function to map an AC to UP + Note: there is a quantization loss here because 4 ACs are mapped to 8 UPs + Mapping is done for consistency + \param ac - Enumeration of the various EDCA Access Categories. + \return an User Priority + + \sa + + --------------------------------------------------------------------------*/ +sme_QosWmmUpType sme_qos_ac_to_up(sme_QosEdcaAcType ac) +{ + sme_QosWmmUpType up = SME_QOS_WMM_UP_MAX; + if (ac >= 0 && ac < SME_QOS_EDCA_AC_MAX) { + up = sme_qos_a_cto_up_map[ac]; + } + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO_MED, + "%s: %d: ac = %d up = %d returned", + __func__, __LINE__, ac, up); + return up; +} + +/*-------------------------------------------------------------------------- + \brief sme_qos_up_to_ac() - Utiltity function to map an UP to AC + \param up - Enumeration of the various User priorities (UP). + \return an Access Category + + \sa + + --------------------------------------------------------------------------*/ +sme_QosEdcaAcType sme_qos_up_to_ac(sme_QosWmmUpType up) +{ + sme_QosEdcaAcType ac = SME_QOS_EDCA_AC_MAX; + if (up >= 0 && up < SME_QOS_WMM_UP_MAX) { + ac = sme_qos_u_pto_ac_map[up]; + } + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO_MED, + "%s: %d: up = %d ac = %d returned", + __func__, __LINE__, up, ac); + return ac; +} + +/*-------------------------------------------------------------------------- + \brief sme_qos_state_transition() - The state transition function per AC. We + save the previous state also. + \param sessionId - Session upon which the state machine is running + \param ac - Enumeration of the various EDCA Access Categories. + \param new_state - The state FSM is moving to. + + \return None + + \sa + + --------------------------------------------------------------------------*/ +static void sme_qos_state_transition(uint8_t sessionId, + sme_QosEdcaAcType ac, + sme_QosStates new_state) +{ + sme_QosSessionInfo *pSession; + sme_QosACInfo *pACInfo; + pSession = &sme_qos_cb.sessionInfo[sessionId]; + pACInfo = &pSession->ac_info[ac]; + pACInfo->prev_state = pACInfo->curr_state; + pACInfo->curr_state = new_state; + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: On session %d new state=%d, old state=%d, for AC=%d", + __func__, __LINE__, + sessionId, pACInfo->curr_state, pACInfo->prev_state, ac); +} + +/** + * sme_qos_find_in_flow_list() - find a flow entry from the flow list + * @search_key: We can either use the flowID or the ac type to find the + * entry in the flow list. + * A bitmap in sme_QosSearchInfo tells which key to use. + * Starting from LSB, + * bit 0 - Flow ID + * bit 1 - AC type + * + * Utility function to find an flow entry from the flow_list. + * + * Return: pointer to the list element + */ +tListElem *sme_qos_find_in_flow_list(sme_QosSearchInfo search_key) +{ + tListElem *list_elt = NULL, *list_next_elt = NULL; + sme_QosFlowInfoEntry *flow_info = NULL; + + list_elt = csr_ll_peek_head(&sme_qos_cb.flow_list, false); + if (!list_elt) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Flow List empty, can't search")); + return NULL; + } + + while (list_elt) { + list_next_elt = csr_ll_next(&sme_qos_cb.flow_list, list_elt, + false); + flow_info = GET_BASE_ADDR(list_elt, sme_QosFlowInfoEntry, link); + + if ((search_key.sessionId != flow_info->sessionId) && + (search_key.sessionId != SME_QOS_SEARCH_SESSION_ID_ANY)) { + list_elt = list_next_elt; + continue; + } + + if (search_key.index & SME_QOS_SEARCH_KEY_INDEX_1) { + if (search_key.key.QosFlowID == flow_info->QosFlowID) { + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_INFO_HIGH, + FL("match found on flowID, ending search")); + break; + } + } else if (search_key.index & SME_QOS_SEARCH_KEY_INDEX_2) { + if (search_key.key.ac_type == flow_info->ac_type) { + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_INFO_HIGH, + FL("match found on ac, ending search")); + break; + } + } else if (search_key.index & SME_QOS_SEARCH_KEY_INDEX_3) { + if (search_key.key.reason == flow_info->reason) { + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_INFO_HIGH, + FL("match found on reason, ending search")); + break; + } + } else if (search_key.index & SME_QOS_SEARCH_KEY_INDEX_4) { + if ((search_key.key.ac_type == flow_info->ac_type) && + (search_key.direction == + flow_info->QoSInfo.ts_info.direction)) { + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_INFO_HIGH, + FL("match found on reason, ending search")); + break; + } + } + list_elt = list_next_elt; + } + return list_elt; +} + +/** + * sme_qos_find_all_in_flow_list() - find a flow entry in the flow list + * @mac_ctx: global MAC context + * @search_key: search key + * @fnp: function pointer specifying the action type for the entry found + * + * Utility function to find an flow entry from the flow_list & act on it. + * search_key - We can either use the flowID or the ac type to find the + * entry in the flow list. + * A bitmap in sme_QosSearchInfo tells which key to use. Starting from LSB, + * bit 0 - Flow ID + * bit 1 - AC type + * + * Return: None + */ +QDF_STATUS sme_qos_find_all_in_flow_list(tpAniSirGlobal mac_ctx, + sme_QosSearchInfo search_key, + sme_QosProcessSearchEntry fnp) +{ + tListElem *list_elt = NULL, *list_next_elt = NULL; + sme_QosSessionInfo *qos_session; + sme_QosFlowInfoEntry *flow_info = NULL; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + sme_QosEdcaAcType ac_type; + + list_elt = csr_ll_peek_head(&sme_qos_cb.flow_list, false); + if (!list_elt) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Flow List empty, can't search")); + return QDF_STATUS_E_FAILURE; + } + + while (list_elt) { + list_next_elt = csr_ll_next(&sme_qos_cb.flow_list, list_elt, + false); + flow_info = GET_BASE_ADDR(list_elt, sme_QosFlowInfoEntry, link); + qos_session = &sme_qos_cb.sessionInfo[flow_info->sessionId]; + if ((search_key.sessionId != flow_info->sessionId) && + (search_key.sessionId != SME_QOS_SEARCH_SESSION_ID_ANY)) { + list_elt = list_next_elt; + continue; + } + + if ((search_key.index & SME_QOS_SEARCH_KEY_INDEX_1) && + (search_key.key.QosFlowID == flow_info->QosFlowID)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO_HIGH, + FL("match found on flowID, ending search")); + status = fnp(mac_ctx, list_elt); + if (QDF_STATUS_E_FAILURE == status) { + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_ERROR, + FL("Failed to process entry")); + break; + } + } else if ((search_key.index & SME_QOS_SEARCH_KEY_INDEX_2) && + (search_key.key.ac_type == flow_info->ac_type)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO_HIGH, + FL("match found on ac, ending search")); + ac_type = flow_info->ac_type; + flow_info->hoRenewal = + qos_session->ac_info[ac_type].hoRenewal; + status = fnp(mac_ctx, list_elt); + if (QDF_STATUS_E_FAILURE == status) { + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_ERROR, + FL("Failed to process entry")); + break; + } + } + list_elt = list_next_elt; + } + return status; +} + +/*-------------------------------------------------------------------------- + \brief sme_qos_is_acm() - Utility function to check if a particular AC + mandates Admission Control. + \param ac - Enumeration of the various EDCA Access Categories. + + \return true if the AC mandates Admission Control + + \sa + + --------------------------------------------------------------------------*/ +bool sme_qos_is_acm(tpAniSirGlobal pMac, tSirBssDescription *pSirBssDesc, + sme_QosEdcaAcType ac, tDot11fBeaconIEs *pIes) +{ + bool ret_val = false; + tDot11fBeaconIEs *pIesLocal; + if (!pSirBssDesc) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: pSirBssDesc is NULL", __func__, __LINE__); + return false; + } + + if (NULL != pIes) { + /* IEs were provided so use them locally */ + pIesLocal = pIes; + } else { + /* IEs were not provided so parse them ourselves */ + if (!QDF_IS_STATUS_SUCCESS + (csr_get_parsed_bss_description_ies + (pMac, pSirBssDesc, &pIesLocal))) { + /* err msg */ + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: csr_get_parsed_bss_description_ies() failed", + __func__, __LINE__); + return false; + } + + /* if success then pIesLocal was allocated */ + } + + if (CSR_IS_QOS_BSS(pIesLocal)) { + switch (ac) { + case SME_QOS_EDCA_AC_BE: + if (pIesLocal->WMMParams.acbe_acm) + ret_val = true; + break; + case SME_QOS_EDCA_AC_BK: + if (pIesLocal->WMMParams.acbk_acm) + ret_val = true; + break; + case SME_QOS_EDCA_AC_VI: + if (pIesLocal->WMMParams.acvi_acm) + ret_val = true; + break; + case SME_QOS_EDCA_AC_VO: + if (pIesLocal->WMMParams.acvo_acm) + ret_val = true; + break; + default: + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: unknown AC = %d", + __func__, __LINE__, ac); + /* Assert */ + QDF_ASSERT(0); + break; + } + } /* IS_QOS_BSS */ + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: ACM = %d for AC = %d", + __func__, __LINE__, ret_val, ac); + if (NULL == pIes) { + /* IEs were allocated locally so free them */ + qdf_mem_free(pIesLocal); + } + return ret_val; +} + +/** + * sme_qos_buffer_existing_flows() - buffer existing flows in flow_list + * @mac_ctx: global MAC context + * @sessionid: session ID + * + * Utility function to buffer the existing flows in flow_list, + * so that we can renew them after handoff is done. + * + * Return: QDF_STATUS + */ +static QDF_STATUS sme_qos_buffer_existing_flows(tpAniSirGlobal mac_ctx, + uint8_t sessionid) +{ + tListElem *list_entry = NULL, *list_nextentry = NULL; + sme_QosSessionInfo *qos_session; + sme_QosFlowInfoEntry *flow_info = NULL; + sme_QosCmdInfo cmd; + sme_qos_setupCmdInfo *setupinfo; + + list_entry = csr_ll_peek_head(&sme_qos_cb.flow_list, false); + if (!list_entry) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO_HIGH, + FL("Flow List empty, nothing to buffer")); + return QDF_STATUS_E_FAILURE; + } + + while (list_entry) { + list_nextentry = csr_ll_next(&sme_qos_cb.flow_list, list_entry, + false); + flow_info = GET_BASE_ADDR(list_entry, sme_QosFlowInfoEntry, + link); + if (flow_info->sessionId != sessionid) { + list_entry = list_nextentry; + continue; + } + + if ((SME_QOS_REASON_REQ_SUCCESS == flow_info->reason) || + (SME_QOS_REASON_SETUP == flow_info->reason)) { + cmd.command = SME_QOS_SETUP_REQ; + cmd.pMac = mac_ctx; + cmd.sessionId = sessionid; + setupinfo = &cmd.u.setupCmdInfo; + + setupinfo->HDDcontext = flow_info->HDDcontext; + setupinfo->QoSInfo = flow_info->QoSInfo; + setupinfo->QoSCallback = flow_info->QoSCallback; + /* shouldn't be needed */ + setupinfo->UPType = SME_QOS_WMM_UP_MAX; + setupinfo->QosFlowID = flow_info->QosFlowID; + if (SME_QOS_REASON_SETUP == flow_info->reason) + setupinfo->hoRenewal = false; + else + setupinfo->hoRenewal = true; + + if (!QDF_IS_STATUS_SUCCESS + (sme_qos_buffer_cmd(&cmd, true))) + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_ERROR, + FL("couldn't buffer the setup request" + " for flow %d in handoff state"), + flow_info->QosFlowID); + else + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_INFO_HIGH, + FL("buffered a setup request for " + "flow %d in handoff state"), + flow_info->QosFlowID); + } else if (SME_QOS_REASON_RELEASE == flow_info->reason) { + cmd.command = SME_QOS_RELEASE_REQ; + cmd.pMac = mac_ctx; + cmd.sessionId = sessionid; + cmd.u.releaseCmdInfo.QosFlowID = flow_info->QosFlowID; + if (!QDF_IS_STATUS_SUCCESS + (sme_qos_buffer_cmd(&cmd, true))) + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_ERROR, + FL("couldn't buffer the release req" + " for flow %d in handoff state"), + flow_info->QosFlowID); + else + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_INFO_HIGH, + FL("buffered a release request for " + "flow %d in handoff state"), + flow_info->QosFlowID); + } else if (SME_QOS_REASON_MODIFY_PENDING == + flow_info->reason) { + cmd.command = SME_QOS_MODIFY_REQ; + cmd.pMac = mac_ctx; + cmd.sessionId = sessionid; + cmd.u.modifyCmdInfo.QosFlowID = flow_info->QosFlowID; + cmd.u.modifyCmdInfo.QoSInfo = flow_info->QoSInfo; + if (!QDF_IS_STATUS_SUCCESS + (sme_qos_buffer_cmd(&cmd, true))) + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_ERROR, + FL("couldn't buffer the modify req" + " for flow %d in handoff state"), + flow_info->QosFlowID); + else + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_INFO_HIGH, + FL("buffered a modify request for " + "flow %d in handoff state"), + flow_info->QosFlowID); + } + /* delete the entry from Flow List */ + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO_HIGH, + FL("Deleting original entry at %p with flowID %d"), + flow_info, flow_info->QosFlowID); + csr_ll_remove_entry(&sme_qos_cb.flow_list, list_entry, true); + qdf_mem_free(flow_info); + + list_entry = list_nextentry; + } + qos_session = &sme_qos_cb.sessionInfo[sessionid]; + qos_session->uapsdAlreadyRequested = false; + return QDF_STATUS_SUCCESS; +} + +/*-------------------------------------------------------------------------- + \brief sme_qos_delete_existing_flows() - Utility function to Delete the existing + flows in flow_list, if we lost connectivity. + + \return QDF_STATUS + + \sa + + --------------------------------------------------------------------------*/ +static QDF_STATUS sme_qos_delete_existing_flows(tpAniSirGlobal pMac, + uint8_t sessionId) +{ + tListElem *pEntry = NULL, *pNextEntry = NULL; + sme_QosFlowInfoEntry *flow_info = NULL; + pEntry = csr_ll_peek_head(&sme_qos_cb.flow_list, true); + if (!pEntry) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_WARN, + "%s: %d: Flow List empty, nothing to delete", + __func__, __LINE__); + return QDF_STATUS_E_FAILURE; + } + while (pEntry) { + pNextEntry = csr_ll_next(&sme_qos_cb.flow_list, pEntry, true); + flow_info = GET_BASE_ADDR(pEntry, sme_QosFlowInfoEntry, link); + if (flow_info->sessionId == sessionId) { + if ((SME_QOS_REASON_REQ_SUCCESS == flow_info->reason) || + (SME_QOS_REASON_SETUP == flow_info->reason) || + (SME_QOS_REASON_RELEASE == flow_info->reason) || + (SME_QOS_REASON_MODIFY == flow_info->reason)) { + flow_info->QoSCallback(pMac, + flow_info->HDDcontext, + NULL, + SME_QOS_STATUS_RELEASE_QOS_LOST_IND, + flow_info->QosFlowID); + } + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: Deleting entry at %p with flowID %d", + __func__, __LINE__, + flow_info, flow_info->QosFlowID); + /* delete the entry from Flow List */ + csr_ll_remove_entry(&sme_qos_cb.flow_list, pEntry, + true); + qdf_mem_free(flow_info); + } + pEntry = pNextEntry; + } + return QDF_STATUS_SUCCESS; +} + +/** + * sme_qos_buffer_cmd() - buffer a request. + * @pcmd: a pointer to the cmd structure to be saved inside the buffered + * cmd link list + * @insert_head: flag indicate if cmd should be added to the list head. + * + * Utility function to buffer a request (setup/modify/release) from client + * while processing another one on the same AC. + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_qos_buffer_cmd(sme_QosCmdInfo *pcmd, bool insert_head) +{ + sme_QosSessionInfo *pSession; + sme_QosCmdInfoEntry *pentry = NULL; + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: Invoked", __func__, __LINE__); + pentry = + (sme_QosCmdInfoEntry *) qdf_mem_malloc(sizeof(sme_QosCmdInfoEntry)); + if (!pentry) { + /* err msg */ + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: Memory allocation failure", + __func__, __LINE__); + return QDF_STATUS_E_NOMEM; + } + /* copy the entire CmdInfo */ + pentry->cmdInfo = *pcmd; + + pSession = &sme_qos_cb.sessionInfo[pcmd->sessionId]; + if (insert_head) { + csr_ll_insert_head(&pSession->bufferedCommandList, &pentry->link, + true); + } else { + csr_ll_insert_tail(&pSession->bufferedCommandList, &pentry->link, + true); + } + return QDF_STATUS_SUCCESS; +} + +/** + * sme_qos_process_buffered_cmd() - process qos buffered request + * @session_id: Session ID + * + * Utility function to process a buffered request (setup/modify/release) + * initially came from the client. + * + * Return:QDF_STATUS + */ +static QDF_STATUS sme_qos_process_buffered_cmd(uint8_t session_id) +{ + sme_QosSessionInfo *qos_session; + sme_QosCmdInfoEntry *pcmd = NULL; + tListElem *list_elt = NULL; + sme_QosStatusType hdd_status = SME_QOS_STATUS_SETUP_FAILURE_RSP; + QDF_STATUS qdf_ret_status = QDF_STATUS_SUCCESS; + sme_QosCmdInfo *qos_cmd = NULL; + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO, + FL("Invoked on session %d"), session_id); + qos_session = &sme_qos_cb.sessionInfo[session_id]; + if (!csr_ll_is_list_empty(&qos_session->bufferedCommandList, false)) { + list_elt = csr_ll_remove_head(&qos_session->bufferedCommandList, + true); + if (!list_elt) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("no more buffered commands on session %d"), + session_id); + qos_session->readyForPowerSave = true; + return QDF_STATUS_E_FAILURE; + } + pcmd = GET_BASE_ADDR(list_elt, sme_QosCmdInfoEntry, link); + qos_cmd = &pcmd->cmdInfo; + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO_HIGH, + FL("Qos cmd %d"), qos_cmd->command); + switch (qos_cmd->command) { + case SME_QOS_SETUP_REQ: + hdd_status = sme_qos_internal_setup_req( + qos_cmd->pMac, qos_cmd->sessionId, + &qos_cmd->u.setupCmdInfo.QoSInfo, + qos_cmd->u.setupCmdInfo.QoSCallback, + qos_cmd->u.setupCmdInfo.HDDcontext, + qos_cmd->u.setupCmdInfo.UPType, + qos_cmd->u.setupCmdInfo.QosFlowID, + true, qos_cmd->u.setupCmdInfo.hoRenewal); + if (SME_QOS_STATUS_SETUP_FAILURE_RSP == hdd_status) { + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_ERROR, + FL("sme_qos_internal_setup_req failed on session %d"), + session_id); + qdf_ret_status = QDF_STATUS_E_FAILURE; + } + break; + case SME_QOS_RELEASE_REQ: + hdd_status = sme_qos_internal_release_req(qos_cmd->pMac, + qos_cmd->sessionId, + qos_cmd->u.releaseCmdInfo.QosFlowID, + true); + if (SME_QOS_STATUS_RELEASE_FAILURE_RSP == hdd_status) { + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_ERROR, + FL("sme_qos_internal_release_req failed on session %d"), + session_id); + qdf_ret_status = QDF_STATUS_E_FAILURE; + } + break; + case SME_QOS_MODIFY_REQ: + hdd_status = sme_qos_internal_modify_req(qos_cmd->pMac, + &qos_cmd->u.modifyCmdInfo.QoSInfo, + qos_cmd->u.modifyCmdInfo.QosFlowID, + true); + if (SME_QOS_STATUS_MODIFY_SETUP_FAILURE_RSP == + hdd_status) { + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_ERROR, + FL("sme_qos_internal_modify_req failed on session %d"), + session_id); + qdf_ret_status = QDF_STATUS_E_FAILURE; + } + break; + case SME_QOS_RESEND_REQ: + hdd_status = sme_qos_re_request_add_ts(qos_cmd->pMac, + qos_cmd->sessionId, + &qos_cmd->u.resendCmdInfo.QoSInfo, + qos_cmd->u.resendCmdInfo.ac, + qos_cmd->u.resendCmdInfo.tspecMask); + if (SME_QOS_STATUS_MODIFY_SETUP_FAILURE_RSP == + hdd_status) { + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_ERROR, + FL("sme_qos_re_request_add_ts failed on session %d"), + session_id); + qdf_ret_status = QDF_STATUS_E_FAILURE; + } + break; + default: + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("On session %d unknown cmd = %d"), + session_id, qos_cmd->command); + QDF_ASSERT(0); + break; + } + /* buffered command has been processed, reclaim the memory */ + qdf_mem_free(pcmd); + } else { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO_HIGH, + FL("cmd buffer empty")); + qos_session->readyForPowerSave = true; + } + return qdf_ret_status; +} + +/*-------------------------------------------------------------------------- + \brief sme_qos_delete_buffered_requests() - Utility function to Delete the buffered + requests in the buffered_cmd_list, if we lost connectivity. + + \return QDF_STATUS + + \sa + + --------------------------------------------------------------------------*/ +static QDF_STATUS sme_qos_delete_buffered_requests(tpAniSirGlobal pMac, + uint8_t sessionId) +{ + sme_QosSessionInfo *pSession; + sme_QosCmdInfoEntry *pcmd = NULL; + tListElem *pEntry = NULL, *pNextEntry = NULL; + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: Invoked on session %d", + __func__, __LINE__, sessionId); + pSession = &sme_qos_cb.sessionInfo[sessionId]; + pEntry = csr_ll_peek_head(&pSession->bufferedCommandList, true); + if (!pEntry) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_WARN, + "%s: %d: Buffered List empty, nothing to delete on session %d", + __func__, __LINE__, sessionId); + return QDF_STATUS_E_FAILURE; + } + while (pEntry) { + pNextEntry = + csr_ll_next(&pSession->bufferedCommandList, pEntry, true); + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO, + "%s: %d: deleting entry from buffered List", __func__, + __LINE__); + /* delete the entry from Flow List */ + csr_ll_remove_entry(&pSession->bufferedCommandList, pEntry, + true); + /* reclaim the memory */ + pcmd = GET_BASE_ADDR(pEntry, sme_QosCmdInfoEntry, link); + qdf_mem_free(pcmd); + pEntry = pNextEntry; + } + return QDF_STATUS_SUCCESS; +} + +/** + * sme_qos_save_assoc_info() - save assoc info. + * @pSession: pointer to QOS session + * @pAssoc_info: pointer to the assoc structure to store the BSS descriptor + * of the AP, the profile that HDD sent down with the + * connect request + * + * Utility function to save the assoc info in the CB like BSS descriptor + * of the AP, the profile that HDD sent down with the connect request, + * while CSR notifies for assoc/reassoc success. + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_qos_save_assoc_info(sme_QosSessionInfo *pSession, + sme_QosAssocInfo *pAssoc_info) +{ + tSirBssDescription *pBssDesc = NULL; + uint32_t bssLen = 0; + if (NULL == pAssoc_info) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: pAssoc_info is NULL", __func__, __LINE__); + return QDF_STATUS_E_FAILURE; + } + /* clean up the assoc info if already set */ + if (pSession->assocInfo.pBssDesc) { + qdf_mem_free(pSession->assocInfo.pBssDesc); + pSession->assocInfo.pBssDesc = NULL; + } + bssLen = pAssoc_info->pBssDesc->length + + sizeof(pAssoc_info->pBssDesc->length); + /* save the bss Descriptor */ + pBssDesc = (tSirBssDescription *) qdf_mem_malloc(bssLen); + if (!pBssDesc) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: couldn't allocate memory for the bss Descriptor", + __func__, __LINE__); + return QDF_STATUS_E_NOMEM; + } + qdf_mem_copy(pBssDesc, pAssoc_info->pBssDesc, bssLen); + pSession->assocInfo.pBssDesc = pBssDesc; + /* save the apsd info from assoc */ + if (pAssoc_info->pProfile) { + pSession->apsdMask |= pAssoc_info->pProfile->uapsd_mask; + } + /* [TODO] Do we need to update the global APSD bitmap? */ + return QDF_STATUS_SUCCESS; +} + +/*-------------------------------------------------------------------------- + \brief sme_qos_setup_fnp() - Utility function (pointer) to notify other entries + in FLOW list on the same AC that qos params got modified + \param pMac - Pointer to the global MAC parameter structure. + \param pEntry - Pointer to an entry in the flow_list(i.e. tListElem structure) + + \return QDF_STATUS + + \sa + + --------------------------------------------------------------------------*/ +QDF_STATUS sme_qos_setup_fnp(tpAniSirGlobal pMac, tListElem *pEntry) +{ + sme_QosSessionInfo *pSession; + sme_QosACInfo *pACInfo; + sme_QosFlowInfoEntry *flow_info = NULL; + sme_QosStatusType hdd_status = SME_QOS_STATUS_SETUP_MODIFIED_IND; + sme_QosEdcaAcType ac; + if (!pEntry) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: Entry is NULL", __func__, __LINE__); + QDF_ASSERT(0); + return QDF_STATUS_E_FAILURE; + } + flow_info = GET_BASE_ADDR(pEntry, sme_QosFlowInfoEntry, link); + ac = flow_info->ac_type; + pSession = &sme_qos_cb.sessionInfo[flow_info->sessionId]; + pACInfo = &pSession->ac_info[ac]; + if (SME_QOS_REASON_REQ_SUCCESS == flow_info->reason) { + /* notify HDD, only the other Flows running on the AC */ + flow_info->QoSCallback(pMac, flow_info->HDDcontext, + &pACInfo->curr_QoSInfo[flow_info-> + tspec_mask - 1], + hdd_status, flow_info->QosFlowID); + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: Entry with flowID = %d getting notified", + __func__, __LINE__, flow_info->QosFlowID); + } + return QDF_STATUS_SUCCESS; +} + +/*-------------------------------------------------------------------------- + \brief sme_qos_modification_notify_fnp() - Utility function (pointer) to notify + other entries in FLOW list on the same AC that qos params got modified + \param pMac - Pointer to the global MAC parameter structure. + \param pEntry - Pointer to an entry in the flow_list(i.e. tListElem structure) + + \return QDF_STATUS + + \sa + + --------------------------------------------------------------------------*/ +QDF_STATUS sme_qos_modification_notify_fnp(tpAniSirGlobal pMac, tListElem *pEntry) +{ + sme_QosSessionInfo *pSession; + sme_QosACInfo *pACInfo; + sme_QosFlowInfoEntry *flow_info = NULL; + sme_QosStatusType hdd_status = SME_QOS_STATUS_SETUP_MODIFIED_IND; + sme_QosEdcaAcType ac; + if (!pEntry) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: Entry is NULL", __func__, __LINE__); + QDF_ASSERT(0); + return QDF_STATUS_E_FAILURE; + } + flow_info = GET_BASE_ADDR(pEntry, sme_QosFlowInfoEntry, link); + ac = flow_info->ac_type; + pSession = &sme_qos_cb.sessionInfo[flow_info->sessionId]; + pACInfo = &pSession->ac_info[ac]; + if (SME_QOS_REASON_REQ_SUCCESS == flow_info->reason) { + /* notify HDD, only the other Flows running on the AC */ + flow_info->QoSCallback(pMac, flow_info->HDDcontext, + &pACInfo->curr_QoSInfo[flow_info-> + tspec_mask - 1], + hdd_status, flow_info->QosFlowID); + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: Entry with flowID = %d getting notified", + __func__, __LINE__, flow_info->QosFlowID); + } + return QDF_STATUS_SUCCESS; +} + +/*-------------------------------------------------------------------------- + \brief sme_qos_modify_fnp() - Utility function (pointer) to delete the origianl + entry in FLOW list & add the modified one + \param pMac - Pointer to the global MAC parameter structure. + \param pEntry - Pointer to an entry in the flow_list(i.e. tListElem structure) + + \return QDF_STATUS + + \sa + + --------------------------------------------------------------------------*/ +QDF_STATUS sme_qos_modify_fnp(tpAniSirGlobal pMac, tListElem *pEntry) +{ + sme_QosFlowInfoEntry *flow_info = NULL; + if (!pEntry) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: Entry is NULL", __func__, __LINE__); + QDF_ASSERT(0); + return QDF_STATUS_E_FAILURE; + } + flow_info = GET_BASE_ADDR(pEntry, sme_QosFlowInfoEntry, link); + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO, + FL("reason %d"), flow_info->reason); + switch (flow_info->reason) { + case SME_QOS_REASON_MODIFY_PENDING: + /* set the proper reason code for the new (with modified params) entry */ + flow_info->reason = SME_QOS_REASON_REQ_SUCCESS; + break; + case SME_QOS_REASON_MODIFY: + /* delete the original entry from Flow List */ + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: Deleting original entry at %p with flowID %d", + __func__, __LINE__, flow_info, flow_info->QosFlowID); + csr_ll_remove_entry(&sme_qos_cb.flow_list, pEntry, true); + /* reclaim the memory */ + qdf_mem_free(flow_info); + break; + default: + break; + } + return QDF_STATUS_SUCCESS; +} + +/*-------------------------------------------------------------------------- + \brief sme_qos_del_ts_ind_fnp() - Utility function (pointer) to find all Flows on + the perticular AC & delete them, also send HDD indication through the callback + it registered per request + \param pMac - Pointer to the global MAC parameter structure. + \param pEntry - Pointer to an entry in the flow_list(i.e. tListElem structure) + + \return QDF_STATUS + + \sa + + --------------------------------------------------------------------------*/ +QDF_STATUS sme_qos_del_ts_ind_fnp(tpAniSirGlobal pMac, tListElem *pEntry) +{ + sme_QosSessionInfo *pSession; + sme_QosACInfo *pACInfo; + sme_QosFlowInfoEntry *flow_info = NULL; + sme_QosEdcaAcType ac; + QDF_STATUS lock_status = QDF_STATUS_E_FAILURE; + sme_QosStatusType status; + + if (!pEntry) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: Entry is NULL", __func__, __LINE__); + QDF_ASSERT(0); + return QDF_STATUS_E_FAILURE; + } + /* delete the entry from Flow List */ + flow_info = GET_BASE_ADDR(pEntry, sme_QosFlowInfoEntry, link); + ac = flow_info->ac_type; + pSession = &sme_qos_cb.sessionInfo[flow_info->sessionId]; + pACInfo = &pSession->ac_info[ac]; + pACInfo->relTrig = SME_QOS_RELEASE_BY_AP; + + lock_status = sme_acquire_global_lock(&pMac->sme); + if (!QDF_IS_STATUS_SUCCESS(lock_status)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: Unable to obtain lock", __func__, __LINE__); + return SME_QOS_STATUS_RELEASE_FAILURE_RSP; + } + /* Call the internal function for QoS release, adding a layer of abstraction */ + status = + sme_qos_internal_release_req(pMac, flow_info->sessionId, + flow_info->QosFlowID, false); + sme_release_global_lock(&pMac->sme); + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: QoS Release return status on Flow %d is %d", + __func__, __LINE__, flow_info->QosFlowID, status); + + return QDF_STATUS_SUCCESS; +} + +/** + * sme_qos_reassoc_success_ev_fnp Notification function to HDD + * + * @mac_ctx: Mac context + * @entry: Pointer to an entry in the flow_list + * + * Utility function (pointer) to notify HDD + * the success for the requested flow & notify all the other flows + * running on the same AC that QoS params got modified + * + * Return: QDF_STATUS enumaration + */ +QDF_STATUS +sme_qos_reassoc_success_ev_fnp(tpAniSirGlobal mac_ctx, + tListElem *entry) +{ + sme_QosSessionInfo *qos_session; + sme_QosACInfo *ac_info; + sme_QosFlowInfoEntry *flow_info = NULL; + bool delete_entry = false; + sme_QosStatusType hdd_status = SME_QOS_STATUS_SETUP_FAILURE_RSP; + sme_QosEdcaAcType ac; + QDF_STATUS pmc_status = QDF_STATUS_E_FAILURE; + if (!entry) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: Entry is NULL", __func__, __LINE__); + QDF_ASSERT(0); + return QDF_STATUS_E_FAILURE; + } + flow_info = GET_BASE_ADDR(entry, sme_QosFlowInfoEntry, link); + ac = flow_info->ac_type; + qos_session = &sme_qos_cb.sessionInfo[flow_info->sessionId]; + ac_info = &qos_session->ac_info[ac]; + switch (flow_info->reason) { + case SME_QOS_REASON_SETUP: + hdd_status = SME_QOS_STATUS_SETUP_SUCCESS_IND; + delete_entry = false; + flow_info->reason = SME_QOS_REASON_REQ_SUCCESS; + /* -Check for the case where we had to do reassoc to + * reset the apsd bit for the ac - release or modify + * scenario.Notify PMC as App is looking for APSD + * If we already requested then we don't need to + * do anything.*/ + if (ac_info->requested_QoSInfo[SME_QOS_TSPEC_INDEX_0].ts_info.psb && + !qos_session->uapsdAlreadyRequested) { + /* this is the first flow to detect we need + * PMC in UAPSD mode */ + pmc_status = sme_ps_start_uapsd(mac_ctx, + flow_info->sessionId, + sme_qos_pmc_offload_start_uapsd_callback, + qos_session); + /* if PMC doesn't return success right away means + * it is yet to put the module in BMPS state & later + * to UAPSD state */ + if (QDF_STATUS_E_FAILURE == pmc_status) { + hdd_status = + SME_QOS_STATUS_SETUP_SUCCESS_IND_APSD_SET_FAILED; + /* we need to always notify this case */ + flow_info->hoRenewal = false; + } else if (QDF_STATUS_PMC_PENDING == pmc_status) { + /* let other flows know PMC has been notified */ + qos_session->uapsdAlreadyRequested = + true; + + } + } + /* for any other pmc status we declare success */ + break; + case SME_QOS_REASON_RELEASE: + ac_info->num_flows[SME_QOS_TSPEC_INDEX_0]--; + /* fall through */ + case SME_QOS_REASON_MODIFY: + delete_entry = true; + break; + case SME_QOS_REASON_MODIFY_PENDING: + hdd_status = SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_IND; + delete_entry = false; + flow_info->reason = SME_QOS_REASON_REQ_SUCCESS; + if (ac_info->requested_QoSInfo[SME_QOS_TSPEC_INDEX_0].ts_info.psb && + !qos_session->uapsdAlreadyRequested) { + /* this is the first flow to detect we need + * PMC in UAPSD mode */ + pmc_status = sme_ps_start_uapsd(mac_ctx, + flow_info->sessionId, + sme_qos_pmc_offload_start_uapsd_callback, + qos_session); + /* if PMC doesn't return success right away means + * it is yet to put the module in BMPS state & + * later to UAPSD state */ + if (QDF_STATUS_E_FAILURE == pmc_status) { + hdd_status = + SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_IND_APSD_SET_FAILED; + /* we need to always notify this case */ + flow_info->hoRenewal = false; + } else if (QDF_STATUS_PMC_PENDING == pmc_status) { + qos_session->uapsdAlreadyRequested = + true; + } + } + /* for any other pmc status we declare success */ + break; + case SME_QOS_REASON_REQ_SUCCESS: + hdd_status = SME_QOS_STATUS_SETUP_MODIFIED_IND; + /* fall through */ + default: + delete_entry = false; + break; + } + if (!delete_entry) { + if (!flow_info->hoRenewal) { + flow_info->QoSCallback(mac_ctx, flow_info->HDDcontext, + &ac_info->curr_QoSInfo[SME_QOS_TSPEC_INDEX_0], + hdd_status, flow_info->QosFlowID); + } else { + flow_info->hoRenewal = false; + } + } else { + /* delete the entry from Flow List */ + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO_HIGH, + FL("Deleting entry at %p with flowID %d"), + flow_info, flow_info->QosFlowID); + csr_ll_remove_entry(&sme_qos_cb.flow_list, entry, true); + /* reclaim the memory */ + qdf_mem_free(flow_info); + } + return QDF_STATUS_SUCCESS; +} + +/*-------------------------------------------------------------------------- + \brief sme_qos_add_ts_failure_fnp() - Utility function (pointer), + if the Addts request was for for an flow setup request, delete the entry from + Flow list & notify HDD + if the Addts request was for downgrading of QoS params because of an flow + release requested on the AC, delete the entry from Flow list & notify HDD + if the Addts request was for change of QoS params because of an flow + modification requested on the AC, delete the new entry from Flow list & notify + HDD + + \param pMac - Pointer to the global MAC parameter structure. + \param pEntry - Pointer to an entry in the flow_list(i.e. tListElem structure) + + \return QDF_STATUS + + \sa + + --------------------------------------------------------------------------*/ +QDF_STATUS sme_qos_add_ts_failure_fnp(tpAniSirGlobal pMac, tListElem *pEntry) +{ + sme_QosSessionInfo *pSession; + sme_QosACInfo *pACInfo; + sme_QosFlowInfoEntry *flow_info = NULL; + bool inform_hdd = false; + sme_QosStatusType hdd_status = SME_QOS_STATUS_SETUP_FAILURE_RSP; + sme_QosEdcaAcType ac; + if (!pEntry) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: Entry is NULL", __func__, __LINE__); + QDF_ASSERT(0); + return QDF_STATUS_E_FAILURE; + } + flow_info = GET_BASE_ADDR(pEntry, sme_QosFlowInfoEntry, link); + ac = flow_info->ac_type; + pSession = &sme_qos_cb.sessionInfo[flow_info->sessionId]; + pACInfo = &pSession->ac_info[ac]; + switch (flow_info->reason) { + case SME_QOS_REASON_SETUP: + hdd_status = SME_QOS_STATUS_SETUP_FAILURE_RSP; + pACInfo->num_flows[pACInfo->tspec_pending - 1]--; + inform_hdd = true; + break; + case SME_QOS_REASON_RELEASE: + hdd_status = SME_QOS_STATUS_RELEASE_FAILURE_RSP; + pACInfo->num_flows[pACInfo->tspec_pending - 1]--; + inform_hdd = true; + break; + case SME_QOS_REASON_MODIFY_PENDING: + hdd_status = SME_QOS_STATUS_MODIFY_SETUP_FAILURE_RSP; + inform_hdd = true; + break; + case SME_QOS_REASON_MODIFY: + flow_info->reason = SME_QOS_REASON_REQ_SUCCESS; + case SME_QOS_REASON_REQ_SUCCESS: + default: + inform_hdd = false; + break; + } + if (inform_hdd) { + /* notify HDD, only the requested Flow, other Flows running on the AC stay */ + /* intact */ + if (!flow_info->hoRenewal) { + flow_info->QoSCallback(pMac, flow_info->HDDcontext, + &pACInfo->curr_QoSInfo[pACInfo-> + tspec_pending + - 1], + hdd_status, + flow_info->QosFlowID); + } else { + flow_info->QoSCallback(pMac, flow_info->HDDcontext, + &pACInfo->curr_QoSInfo[pACInfo-> + tspec_pending + - 1], + SME_QOS_STATUS_RELEASE_QOS_LOST_IND, + flow_info->QosFlowID); + } + /* delete the entry from Flow List */ + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: Deleting entry at %p with flowID %d", + __func__, __LINE__, flow_info, flow_info->QosFlowID); + csr_ll_remove_entry(&sme_qos_cb.flow_list, pEntry, true); + /* reclaim the memory */ + qdf_mem_free(flow_info); + } + return QDF_STATUS_SUCCESS; +} + +/** + * sme_qos_add_ts_success_fnp() - Utility function (pointer) to notify HDD + * + * @mac_ctx: Mac context + * @entry: Pointer to an entry in the flow_list(i.e. tListElem structure). + * + * Description : Utility function (pointer), + * If the Addts request was for for an flow setup request, notify + * HDD for success for the flow & notify all the other flows running + * on the same AC that QoS params got modified + * if the Addts request was for downgrading of QoS params + * because of an flow release requested on the AC, delete + * the entry from Flow list & notify HDD if the Addts request + * was for change of QoS params because of an flow modification + * requested on the AC, delete the old entry from Flow list & notify + * HDD for success for the flow & notify all the other flows running + * on the same AC that QoS params got modified + * + * Return: Status + */ + +QDF_STATUS sme_qos_add_ts_success_fnp(tpAniSirGlobal mac_ctx, + tListElem *entry) +{ + sme_QosSessionInfo *qos_session; + sme_QosACInfo *ac_info; + sme_QosFlowInfoEntry *flow_info = NULL; + bool inform_hdd = false; + bool delete_entry = false; + sme_QosStatusType hdd_status = SME_QOS_STATUS_SETUP_FAILURE_RSP; + sme_QosEdcaAcType ac; + QDF_STATUS pmc_status = QDF_STATUS_E_FAILURE; + tCsrRoamModifyProfileFields profile_fields; + uint8_t psb; + uint8_t tspec_index; + + if (!entry) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Entry is NULL")); + QDF_ASSERT(0); + return QDF_STATUS_E_FAILURE; + } + flow_info = GET_BASE_ADDR(entry, sme_QosFlowInfoEntry, link); + ac = flow_info->ac_type; + qos_session = &sme_qos_cb.sessionInfo[flow_info->sessionId]; + ac_info = &qos_session->ac_info[ac]; + tspec_index = ac_info->tspec_pending - 1; + if (flow_info->tspec_mask != ac_info->tspec_pending) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO_HIGH, + FL(" No need to notify the HDD, the ADDTS " + "success is not for index = %d of the AC = %d"), + flow_info->tspec_mask, ac); + return QDF_STATUS_SUCCESS; + } + switch (flow_info->reason) { + case SME_QOS_REASON_SETUP: + hdd_status = SME_QOS_STATUS_SETUP_SUCCESS_IND; + flow_info->reason = SME_QOS_REASON_REQ_SUCCESS; + delete_entry = false; + inform_hdd = true; + /* check if App is looking for APSD + * notify PMC as App is looking for APSD. If we already + * requested then we don't need to do anything */ + if (ac_info->requested_QoSInfo[tspec_index].ts_info.psb && + !qos_session->uapsdAlreadyRequested) { + /* this is the first flow to detect we need + * PMC in UAPSD mode */ + pmc_status = sme_ps_start_uapsd(mac_ctx, + flow_info->sessionId, + sme_qos_pmc_offload_start_uapsd_callback, + qos_session); + /* if PMC doesn't return success right away means + * it is yet to put the module in BMPS state & later + * to UAPSD state */ + if (QDF_STATUS_E_FAILURE == pmc_status) { + hdd_status = + SME_QOS_STATUS_SETUP_SUCCESS_IND_APSD_SET_FAILED; + /* we need to always notify this case */ + flow_info->hoRenewal = false; + } else if (QDF_STATUS_PMC_PENDING == pmc_status) { + /* let other flows know PMC has been notified */ + qos_session->uapsdAlreadyRequested = + true; + } + /* for any other pmc status we declare success */ + } + break; + case SME_QOS_REASON_RELEASE: + ac_info->num_flows[tspec_index]--; + hdd_status = SME_QOS_STATUS_RELEASE_SUCCESS_RSP; + inform_hdd = true; + delete_entry = true; + break; + case SME_QOS_REASON_MODIFY: + delete_entry = true; + inform_hdd = false; + break; + case SME_QOS_REASON_MODIFY_PENDING: + hdd_status = SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_IND; + delete_entry = false; + flow_info->reason = SME_QOS_REASON_REQ_SUCCESS; + inform_hdd = true; + psb = ac_info->requested_QoSInfo[tspec_index].ts_info.psb; + /* notify PMC if App is looking for APSD + * notify PMC as App is looking for APSD. If we already + * requested then we don't need to do anything. */ + if (psb && !qos_session->uapsdAlreadyRequested) { + /* this is the first flow to detect + * we need PMC in UAPSD mode */ + pmc_status = + sme_ps_start_uapsd(mac_ctx, + flow_info->sessionId, + sme_qos_pmc_offload_start_uapsd_callback, + qos_session); + /* if PMC doesn't return success right + * away means it is yet to put + * the module in BMPS state & later to UAPSD state */ + if (QDF_STATUS_E_FAILURE == pmc_status) { + hdd_status = + SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_IND_APSD_SET_FAILED; + /* we need to always notify this case */ + flow_info->hoRenewal = false; + } else if (QDF_STATUS_PMC_PENDING == pmc_status) { + /* let other flows know PMC has been notified */ + qos_session->uapsdAlreadyRequested = + true; + } + /* for any other pmc status we declare success */ + } else if (!psb && + ((ac_info->num_flows[flow_info->tspec_mask - 1] == 1) + && (SME_QOS_TSPEC_MASK_BIT_1_2_SET != + ac_info->tspec_mask_status))) { + /* this is the only TSPEC active on this AC */ + /* so indicate that we no longer require APSD */ + qos_session->apsdMask &= + ~(1 << (SME_QOS_EDCA_AC_VO - ac)); + /* Also update modifyProfileFields.uapsd_mask + * in CSR for consistency */ + csr_get_modify_profile_fields(mac_ctx, + flow_info->sessionId, + &profile_fields); + profile_fields.uapsd_mask = + qos_session->apsdMask; + csr_set_modify_profile_fields(mac_ctx, + flow_info->sessionId, + &profile_fields); + if (!qos_session->apsdMask) { + sme_ps_uapsd_disable(mac_ctx, + flow_info->sessionId); + } + } + break; + case SME_QOS_REASON_REQ_SUCCESS: + hdd_status = SME_QOS_STATUS_SETUP_MODIFIED_IND; + inform_hdd = true; + default: + delete_entry = false; + break; + } + if (inform_hdd) { + if (!flow_info->hoRenewal) { + flow_info->QoSCallback(mac_ctx, flow_info->HDDcontext, + &ac_info->curr_QoSInfo[tspec_index], + hdd_status, + flow_info->QosFlowID); + } else { + flow_info->hoRenewal = false; + } + } + if (delete_entry) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO_HIGH, + FL("Deleting entry at %p with flowID %d"), + flow_info, flow_info->QosFlowID); + /* delete the entry from Flow List */ + csr_ll_remove_entry(&sme_qos_cb.flow_list, entry, true); + /* reclaim the memory */ + qdf_mem_free(flow_info); + } + return QDF_STATUS_SUCCESS; +} + +/*-------------------------------------------------------------------------- + \brief sme_qos_is_rsp_pending() - Utility function to check if we are waiting + for an AddTS or reassoc response on some AC other than the given AC + + \param sessionId - Session we are interted in + \param ac - Enumeration of the various EDCA Access Categories. + + \return bool + true - Response is pending on an AC + + \sa + + --------------------------------------------------------------------------*/ +static bool sme_qos_is_rsp_pending(uint8_t sessionId, sme_QosEdcaAcType ac) +{ + sme_QosSessionInfo *pSession; + sme_QosACInfo *pACInfo; + sme_QosEdcaAcType acIndex; + bool status = false; + pSession = &sme_qos_cb.sessionInfo[sessionId]; + for (acIndex = SME_QOS_EDCA_AC_BE; acIndex < SME_QOS_EDCA_AC_MAX; + acIndex++) { + if (acIndex == ac) { + continue; + } + pACInfo = &pSession->ac_info[acIndex]; + if ((pACInfo->tspec_pending) || (pACInfo->reassoc_pending)) { + status = true; + break; + } + } + return status; +} + +/*-------------------------------------------------------------------------- + \brief sme_qos_update_hand_off() - Function which can be called to update + Hand-off state of SME QoS Session + \param sessionId - session id + \param updateHandOff - value True/False to update the handoff flag + + \sa + + -------------------------------------------------------------------------*/ +void sme_qos_update_hand_off(uint8_t sessionId, bool updateHandOff) +{ + sme_QosSessionInfo *pSession; + pSession = &sme_qos_cb.sessionInfo[sessionId]; + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO_MED, + "%s: %d: handoffRequested %d updateHandOff %d", + __func__, __LINE__, pSession->handoffRequested, + updateHandOff); + + pSession->handoffRequested = updateHandOff; + +} + +/*-------------------------------------------------------------------------- + \brief sme_qos_is_uapsd_active() - Function which can be called to determine + if any sessions require PMC to be in U-APSD mode. + \return bool + + Returns true if at least one session required PMC to be in U-APSD mode + Returns false if no sessions require PMC to be in U-APSD mode + + \sa + + --------------------------------------------------------------------------*/ +static bool sme_qos_is_uapsd_active(void) +{ + sme_QosSessionInfo *pSession; + uint8_t sessionId; + for (sessionId = 0; sessionId < CSR_ROAM_SESSION_MAX; ++sessionId) { + pSession = &sme_qos_cb.sessionInfo[sessionId]; + if ((pSession->sessionActive) && (pSession->apsdMask)) { + return true; + } + } + /* no active sessions have U-APSD active */ + return false; +} + +/*-------------------------------------------------------------------------- + \brief sme_QosPmcStartUAPSDCallback() - Callback function registered with PMC + to notify SME-QoS when it puts the chip into UAPSD mode + + \param callbackContext - The context passed to PMC during pmc_start_uapsd call. + \param status - QDF_STATUS returned by PMC. + + \return None + + \sa + + --------------------------------------------------------------------------*/ +void sme_qos_pmc_offload_start_uapsd_callback(void *callbackContext, + uint32_t sessionId, QDF_STATUS status) +{ + sme_QosSessionInfo *pSession = callbackContext; + pSession->uapsdAlreadyRequested = false; +} + +bool sme_qos_pmc_offload_check_routine(void *callbackContext, uint32_t sessionId) +{ + sme_QosSessionInfo *pSession = &sme_qos_cb.sessionInfo[sessionId]; + + if ((pSession->sessionActive) && (!pSession->readyForPowerSave)) { + return false; + } + return true; + +} + + +QDF_STATUS sme_offload_qos_process_out_of_uapsd_mode(tpAniSirGlobal pMac, + uint32_t sessionId) +{ + sme_QosSessionInfo *pSession; + tListElem *pEntry = NULL, *pNextEntry = NULL; + sme_QosFlowInfoEntry *flow_info = NULL; + + pEntry = csr_ll_peek_head(&sme_qos_cb.flow_list, false); + if (!pEntry) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: Flow List empty, can't search", + __func__, __LINE__); + return QDF_STATUS_E_FAILURE; + } + while (pEntry) { + pNextEntry = csr_ll_next(&sme_qos_cb.flow_list, pEntry, false); + flow_info = GET_BASE_ADDR(pEntry, sme_QosFlowInfoEntry, link); + pSession = &sme_qos_cb.sessionInfo[flow_info->sessionId]; + /* only notify the flows which already successfully setup UAPSD */ + if ((sessionId == flow_info->sessionId) && + (flow_info->QoSInfo.max_service_interval || + flow_info->QoSInfo.min_service_interval) && + (SME_QOS_REASON_REQ_SUCCESS == flow_info->reason)) { + flow_info->QoSCallback(pMac, flow_info->HDDcontext, + &pSession->ac_info[flow_info-> + ac_type].curr_QoSInfo + [flow_info->tspec_mask - 1], + SME_QOS_STATUS_OUT_OF_APSD_POWER_MODE_IND, + flow_info->QosFlowID); + } + pEntry = pNextEntry; + } + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS sme_offload_qos_process_into_uapsd_mode(tpAniSirGlobal pMac, + uint32_t sessionId) +{ + sme_QosSessionInfo *pSession; + tListElem *pEntry = NULL, *pNextEntry = NULL; + sme_QosFlowInfoEntry *flow_info = NULL; + + pEntry = csr_ll_peek_head(&sme_qos_cb.flow_list, false); + if (!pEntry) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: Flow List empty, can't search", + __func__, __LINE__); + return QDF_STATUS_E_FAILURE; + } + while (pEntry) { + pNextEntry = csr_ll_next(&sme_qos_cb.flow_list, pEntry, false); + flow_info = GET_BASE_ADDR(pEntry, sme_QosFlowInfoEntry, link); + pSession = &sme_qos_cb.sessionInfo[flow_info->sessionId]; + /* only notify the flows which already successfully setup UAPSD */ + if ((sessionId == flow_info->sessionId) && + (flow_info->QoSInfo.max_service_interval || + flow_info->QoSInfo.min_service_interval) && + (SME_QOS_REASON_REQ_SUCCESS == flow_info->reason)) { + flow_info->QoSCallback(pMac, flow_info->HDDcontext, + &pSession->ac_info[flow_info-> + ac_type].curr_QoSInfo + [flow_info->tspec_mask - 1], + SME_QOS_STATUS_INTO_APSD_POWER_MODE_IND, + flow_info->QosFlowID); + } + pEntry = pNextEntry; + } + return QDF_STATUS_SUCCESS; +} + +void sme_qos_cleanup_ctrl_blk_for_handoff(tpAniSirGlobal pMac, uint8_t sessionId) +{ + sme_QosSessionInfo *pSession; + sme_QosACInfo *pACInfo; + sme_QosEdcaAcType ac; + pSession = &sme_qos_cb.sessionInfo[sessionId]; + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO, + FL("invoked on session %d"), sessionId); + + for (ac = SME_QOS_EDCA_AC_BE; ac < SME_QOS_EDCA_AC_MAX; ac++) { + pACInfo = &pSession->ac_info[ac]; + qdf_mem_zero(pACInfo->curr_QoSInfo, + sizeof(sme_QosWmmTspecInfo) * + SME_QOS_TSPEC_INDEX_MAX); + qdf_mem_zero(pACInfo->requested_QoSInfo, + sizeof(sme_QosWmmTspecInfo) * + SME_QOS_TSPEC_INDEX_MAX); + pACInfo->num_flows[0] = 0; + pACInfo->num_flows[1] = 0; + pACInfo->reassoc_pending = false; + pACInfo->tspec_mask_status = 0; + pACInfo->tspec_pending = false; + pACInfo->hoRenewal = false; + pACInfo->prev_state = SME_QOS_LINK_UP; + } +} + +/** + * sme_qos_is_ts_info_ack_policy_valid() - check if ACK policy is allowed. + * @pMac: The handle returned by mac_open. + * @pQoSInfo: Pointer to sme_QosWmmTspecInfo which contains the WMM TSPEC + * @ related info, provided by HDD + * @sessionId: sessionId returned by sme_open_session. + * + * The SME QoS API exposed to HDD to check if TS info ack policy field can be + * set to "HT-immediate block acknowledgement" + * + * Return: true - Current Association is HT association and so TS info ack + * policy can be set to "HT-immediate block acknowledgement" + */ +bool sme_qos_is_ts_info_ack_policy_valid(tpAniSirGlobal pMac, + sme_QosWmmTspecInfo *pQoSInfo, + uint8_t sessionId) +{ + tDot11fBeaconIEs *pIes = NULL; + sme_QosSessionInfo *pSession; + QDF_STATUS hstatus; + if (!CSR_IS_SESSION_VALID(pMac, sessionId)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: Session Id %d is invalid", + __func__, __LINE__, sessionId); + return false; + } + + pSession = &sme_qos_cb.sessionInfo[sessionId]; + + if (!pSession->sessionActive) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: Session %d is inactive", + __func__, __LINE__, sessionId); + return false; + } + + if (!pSession->assocInfo.pBssDesc) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: Session %d has an Invalid BSS Descriptor", + __func__, __LINE__, sessionId); + return false; + } + + hstatus = csr_get_parsed_bss_description_ies(pMac, + pSession->assocInfo.pBssDesc, + &pIes); + if (!QDF_IS_STATUS_SUCCESS(hstatus)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: On session %d unable to parse BSS IEs", + __func__, __LINE__, sessionId); + return false; + } + + /* success means pIes was allocated */ + + if (!pIes->HTCaps.present && + pQoSInfo->ts_info.ack_policy == + SME_QOS_WMM_TS_ACK_POLICY_HT_IMMEDIATE_BLOCK_ACK) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: On session %d HT Caps aren't present but application set ack policy to HT ", + __func__, __LINE__, sessionId); + + qdf_mem_free(pIes); + return false; + } + + qdf_mem_free(pIes); + return true; +} + +bool sme_qos_validate_requested_params(tpAniSirGlobal pMac, + sme_QosWmmTspecInfo *pQoSInfo, + uint8_t sessionId) +{ + bool rc = false; + + do { + if (SME_QOS_WMM_TS_DIR_RESV == pQoSInfo->ts_info.direction) + break; + if (!sme_qos_is_ts_info_ack_policy_valid(pMac, pQoSInfo, sessionId)) + break; + + rc = true; + } while (0); + return rc; +} + +static QDF_STATUS qos_issue_command(tpAniSirGlobal pMac, uint8_t sessionId, + eSmeCommandType cmdType, + sme_QosWmmTspecInfo *pQoSInfo, + sme_QosEdcaAcType ac, uint8_t tspec_mask) +{ + QDF_STATUS status = QDF_STATUS_E_RESOURCES; + tSmeCmd *pCommand = NULL; + do { + pCommand = sme_get_command_buffer(pMac); + if (!pCommand) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: fail to get command buffer for command %d", + __func__, __LINE__, cmdType); + break; + } + pCommand->command = cmdType; + pCommand->sessionId = sessionId; + switch (cmdType) { + case eSmeCommandAddTs: + if (pQoSInfo) { + status = QDF_STATUS_SUCCESS; + pCommand->u.qosCmd.tspecInfo = *pQoSInfo; + pCommand->u.qosCmd.ac = ac; + } else { + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_ERROR, + "%s: %d: NULL pointer passed", + __func__, __LINE__); + status = QDF_STATUS_E_INVAL; + } + break; + case eSmeCommandDelTs: + status = QDF_STATUS_SUCCESS; + pCommand->u.qosCmd.ac = ac; + pCommand->u.qosCmd.tspec_mask = tspec_mask; + break; + default: + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: invalid command type %d", + __func__, __LINE__, cmdType); + status = QDF_STATUS_E_INVAL; + break; + } + } while (0); + if (QDF_IS_STATUS_SUCCESS(status) && pCommand) { + sme_push_command(pMac, pCommand, false); + } else if (pCommand) { + qos_release_command(pMac, pCommand); + } + return status; +} + +bool qos_process_command(tpAniSirGlobal pMac, tSmeCmd *pCommand) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + bool fRemoveCmd = true; + do { + switch (pCommand->command) { + case eSmeCommandAddTs: + status = + sme_qos_add_ts_req(pMac, (uint8_t) pCommand->sessionId, + &pCommand->u.qosCmd.tspecInfo, + pCommand->u.qosCmd.ac); + if (QDF_IS_STATUS_SUCCESS(status)) { + fRemoveCmd = false; + status = SME_QOS_STATUS_SETUP_REQ_PENDING_RSP; + } + break; + case eSmeCommandDelTs: + status = + sme_qos_del_ts_req(pMac, (uint8_t) pCommand->sessionId, + pCommand->u.qosCmd.ac, + pCommand->u.qosCmd.tspec_mask); + if (QDF_IS_STATUS_SUCCESS(status)) { + fRemoveCmd = false; + } + break; + default: + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: %d: invalid command type %d", + __func__, __LINE__, pCommand->command); + break; + } /* switch */ + } while (0); + return fRemoveCmd; +} + +/** + * sme_qos_re_request_add_ts - Re-send AddTS for the combined QoS request + * + * @mac_ctx Pointer to mac context + * @session_id SME session id + * @qos_info - Tspec information + * @ac - Access category + * @tspec_mask - Tspec Mask + * + * This function is called to re-send AddTS for the combined QoS request + * + * Return: status + */ +static +sme_QosStatusType sme_qos_re_request_add_ts(tpAniSirGlobal mac_ctx, + uint8_t session_id, sme_QosWmmTspecInfo *qos_info, + sme_QosEdcaAcType ac, uint8_t tspec_mask) +{ + sme_QosSessionInfo *session; + sme_QosACInfo *ac_info; + sme_QosStatusType status = SME_QOS_STATUS_MODIFY_SETUP_FAILURE_RSP; + sme_QosCmdInfo cmd; + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO_HIGH, + FL(" Invoked on session %d for AC %d TSPEC %d"), + session_id, ac, tspec_mask); + session = &sme_qos_cb.sessionInfo[session_id]; + ac_info = &session->ac_info[ac]; + /* need to vote off powersave for the duration of this request */ + session->readyForPowerSave = false; + /* + * call PMC's request for power function + * AND another check is added considering the flowing scenario + * Addts reqest is pending on one AC, while APSD requested on + * another which needs a reassoc. Will buffer a request if Addts + * is pending on any AC, which will safegaurd the above scenario, + * 2& also won't confuse PE with back to back Addts or Addts + * followed by Reassoc. + */ + if (sme_qos_is_rsp_pending(session_id, ac)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL(" On session %d buffering the AddTS request " + "for AC %d in state %d as Addts is pending " + "on other AC or waiting for full power"), + session_id, ac, + ac_info->curr_state); + /* buffer cmd */ + cmd.command = SME_QOS_RESEND_REQ; + cmd.pMac = mac_ctx; + cmd.sessionId = session_id; + cmd.u.resendCmdInfo.ac = ac; + cmd.u.resendCmdInfo.tspecMask = tspec_mask; + cmd.u.resendCmdInfo.QoSInfo = *qos_info; + if (!QDF_IS_STATUS_SUCCESS(sme_qos_buffer_cmd(&cmd, false))) { + QDF_TRACE(QDF_MODULE_ID_SME, + QDF_TRACE_LEVEL_ERROR, + FL("On session %d unable to buffer the AddTS " + "request for AC %d TSPEC %d in state %d"), + session_id, ac, tspec_mask, + ac_info->curr_state); + /* unable to buffer the request + * nothing is pending so vote powersave back on */ + session->readyForPowerSave = true; + return SME_QOS_STATUS_MODIFY_SETUP_FAILURE_RSP; + } + return SME_QOS_STATUS_MODIFY_SETUP_PENDING_RSP; + } + + /* get into the stat m/c to see if the request can be granted */ + switch (ac_info->curr_state) { + case SME_QOS_QOS_ON: + { + /* if ACM, send out a new ADDTS */ + ac_info->hoRenewal = true; + status = sme_qos_setup(mac_ctx, session_id, qos_info, ac); + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO_HIGH, + FL("sme_qos_setup returned in SME_QOS_QOS_ON state")); + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO_HIGH, + FL("sme_qos_setup AC %d with status =%d"), ac, status); + if (SME_QOS_STATUS_SETUP_REQ_PENDING_RSP != status) { + /* we aren't waiting for a response from the AP */ + /* so vote powersave back on */ + session->readyForPowerSave = true; + } + if (SME_QOS_STATUS_SETUP_REQ_PENDING_RSP == status) { + status = SME_QOS_STATUS_MODIFY_SETUP_PENDING_RSP; + ac_info->tspec_pending = tspec_mask; + } else if ((SME_QOS_STATUS_SETUP_SUCCESS_NO_ACM_NO_APSD_RSP == + status) || + (SME_QOS_STATUS_SETUP_SUCCESS_APSD_SET_ALREADY == + status) || + (SME_QOS_STATUS_SETUP_SUCCESS_IND_APSD_PENDING == + status)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("UAPSD is setup already status = %d "), + status); + } else { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("sme_qos_setup return status = %d "), + status); + } + } + break; + case SME_QOS_HANDOFF: + case SME_QOS_REQUESTED: + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Re-Add request in state = %d buffer the request"), + ac_info->curr_state); + cmd.command = SME_QOS_RESEND_REQ; + cmd.pMac = mac_ctx; + cmd.sessionId = session_id; + cmd.u.resendCmdInfo.ac = ac; + cmd.u.resendCmdInfo.tspecMask = tspec_mask; + cmd.u.resendCmdInfo.QoSInfo = *qos_info; + if (!QDF_IS_STATUS_SUCCESS(sme_qos_buffer_cmd(&cmd, false))) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL(" couldn't buf the read request state = %d"), + ac_info->curr_state); + /* unable to buffer the request + * nothing is pending so vote powersave back on */ + session->readyForPowerSave = true; + return SME_QOS_STATUS_MODIFY_SETUP_FAILURE_RSP; + } + status = SME_QOS_STATUS_MODIFY_SETUP_PENDING_RSP; + break; + case SME_QOS_CLOSED: + case SME_QOS_INIT: + case SME_QOS_LINK_UP: + default: + /* print error msg, */ + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("ReAdd request in unexpected state = %d"), + ac_info->curr_state); + /* unable to service the request + * nothing is pending so vote powersave back on */ + session->readyForPowerSave = true; + break; + } + if ((SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_NO_ACM_NO_APSD_RSP == + status) || + (SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_APSD_SET_ALREADY == + status)) { + (void)sme_qos_process_buffered_cmd(session_id); + } + return status; +} + +static void sme_qos_init_a_cs(tpAniSirGlobal pMac, uint8_t sessionId) +{ + sme_QosSessionInfo *pSession; + sme_QosEdcaAcType ac; + pSession = &sme_qos_cb.sessionInfo[sessionId]; + for (ac = SME_QOS_EDCA_AC_BE; ac < SME_QOS_EDCA_AC_MAX; ac++) { + qdf_mem_zero(&pSession->ac_info[ac], sizeof(sme_QosACInfo)); + sme_qos_state_transition(sessionId, ac, SME_QOS_INIT); + } +} + +static QDF_STATUS sme_qos_request_reassoc(tpAniSirGlobal pMac, uint8_t sessionId, + tCsrRoamModifyProfileFields * + pModFields, bool fForce) +{ + sme_QosSessionInfo *pSession; + sme_QosACInfo *pACInfo; + QDF_STATUS status; + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: %d: Invoked on session %d with UAPSD mask 0x%X", + __func__, __LINE__, sessionId, pModFields->uapsd_mask); + pSession = &sme_qos_cb.sessionInfo[sessionId]; + status = + csr_reassoc(pMac, sessionId, pModFields, &pSession->roamID, fForce); + if (QDF_IS_STATUS_SUCCESS(status)) { + /* Update the state to Handoff so subsequent requests are queued until */ + /* this one is finished */ + sme_QosEdcaAcType ac; + for (ac = SME_QOS_EDCA_AC_BE; ac < SME_QOS_EDCA_AC_MAX; ac++) { + pACInfo = &pSession->ac_info[ac]; + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO, + "%s: %d: AC[%d] is in state [%d]", + __func__, __LINE__, ac, pACInfo->curr_state); + /* If it is already in HANDOFF state, don't do anything since we */ + /* MUST preserve the previous state and sme_qos_state_transition */ + /* will change the previous state */ + if (SME_QOS_HANDOFF != pACInfo->curr_state) { + sme_qos_state_transition(sessionId, ac, + SME_QOS_HANDOFF); + } + } + } + return status; +} + +static uint32_t sme_qos_assign_flow_id(void) +{ + uint32_t flowId; + flowId = sme_qos_cb.nextFlowId; + if (SME_QOS_MAX_FLOW_ID == flowId) { + /* The Flow ID wrapped. This is obviously not a real life scenario */ + /* but handle it to keep the software test folks happy */ + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_FATAL, + "%s: %d: Software Test made the flow counter wrap, " + "QoS may no longer be functional", + __func__, __LINE__); + sme_qos_cb.nextFlowId = SME_QOS_MIN_FLOW_ID; + } else { + sme_qos_cb.nextFlowId++; + } + return flowId; +} + +static uint8_t sme_qos_assign_dialog_token(void) +{ + uint8_t token; + token = sme_qos_cb.nextDialogToken; + if (SME_QOS_MAX_DIALOG_TOKEN == token) { + /* wrap is ok */ + sme_qos_cb.nextDialogToken = SME_QOS_MIN_DIALOG_TOKEN; + } else { + sme_qos_cb.nextDialogToken++; + } + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO, + FL("token %d"), token); + return token; +} +#endif /* WLAN_MDM_CODE_REDUCTION_OPT */ diff --git a/drivers/staging/qcacld-3.0/core/sme/src/rrm/sme_rrm.c b/drivers/staging/qcacld-3.0/core/sme/src/rrm/sme_rrm.c new file mode 100644 index 0000000000000000000000000000000000000000..7389ac5f60df35081af1e4dc7819d875cf2e6ff1 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/sme/src/rrm/sme_rrm.c @@ -0,0 +1,1478 @@ +/* + * Copyright (c) 2011-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/**========================================================================= + + \file sme_Rrm.c + + \brief implementation for SME RRM APIs + + ========================================================================*/ + +/* $Header$ */ + +/*-------------------------------------------------------------------------- + Include Files + ------------------------------------------------------------------------*/ +#include "ani_global.h" +#include "sme_inside.h" +#include "sme_api.h" +#include "sms_debug.h" +#include "cfg_api.h" + +#ifdef FEATURE_WLAN_DIAG_SUPPORT +#include "host_diag_core_event.h" +#include "host_diag_core_log.h" +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + +#include "csr_inside_api.h" + +#include "rrm_global.h" + + +/* Roam score for a neighbor AP will be calculated based on the below definitions. + The calculated roam score will be used to select the roamable candidate from neighbor AP list */ +#define RRM_ROAM_SCORE_NEIGHBOR_REPORT_REACHABILITY 0 /* When we support 11r over the DS, this should have a non-zero value */ +#define RRM_ROAM_SCORE_NEIGHBOR_REPORT_SECURITY 10 +#define RRM_ROAM_SCORE_NEIGHBOR_REPORT_KEY_SCOPE 20 +#define RRM_ROAM_SCORE_NEIGHBOR_REPORT_CAPABILITY_SPECTRUM_MGMT 0 /* Not used */ +#define RRM_ROAM_SCORE_NEIGHBOR_REPORT_CAPABILITY_QOS 5 +#define RRM_ROAM_SCORE_NEIGHBOR_REPORT_CAPABILITY_APSD 3 +#define RRM_ROAM_SCORE_NEIGHBOR_REPORT_CAPABILITY_RRM 8 +#define RRM_ROAM_SCORE_NEIGHBOR_REPORT_CAPABILITY_DELAYED_BA 0 /* We dont support delayed BA */ +#define RRM_ROAM_SCORE_NEIGHBOR_REPORT_CAPABILITY_IMMEDIATE_BA 3 +#define RRM_ROAM_SCORE_NEIGHBOR_REPORT_MOBILITY_DOMAIN 30 + +#ifdef FEATURE_WLAN_ESE +#define RRM_ROAM_SCORE_NEIGHBOR_IAPP_LIST 30 +#endif + +uint64_t rrm_scan_timer; + +/** + * rrm_ll_purge_neighbor_cache() -Purges all the entries in the neighbor cache + * + * @pMac: Pointer to the Hal Handle. + * @pList: Pointer the List that should be purged. + * + * This function purges all the entries in the neighbor cache and frees up all + * the internal nodes + * + * Return: void + */ +static void rrm_ll_purge_neighbor_cache(tpAniSirGlobal pMac, + tDblLinkList *pList) +{ + tListElem *pEntry; + tRrmNeighborReportDesc *pNeighborReportDesc; + csr_ll_lock(pList); + while ((pEntry = csr_ll_remove_head(pList, LL_ACCESS_NOLOCK)) != NULL) { + pNeighborReportDesc = + GET_BASE_ADDR(pEntry, tRrmNeighborReportDesc, List); + qdf_mem_free(pNeighborReportDesc->pNeighborBssDescription); + qdf_mem_free(pNeighborReportDesc); + } + csr_ll_unlock(pList); + return; +} + +/** + * rrm_indicate_neighbor_report_result() -calls the callback registered for + * neighbor report + * @pMac: Pointer to the Hal Handle. + * @qdf_status - QDF_STATUS_SUCCESS/QDF_STATUS_FAILURE based on whether a valid + * report is received or neighbor timer expired + * + * This function calls the callback register by the caller while requesting for + * neighbor report. This function gets invoked if a neighbor report is received + * from an AP or neighbor response wait timer expires. + * + * Return: void + */ +static void rrm_indicate_neighbor_report_result(tpAniSirGlobal pMac, + QDF_STATUS qdf_status) +{ + NeighborReportRspCallback callback; + void *callbackContext; + + /* Reset the neighbor response pending status */ + pMac->rrm.rrmSmeContext.neighborReqControlInfo.isNeighborRspPending = + false; + + /* Stop the timer if it is already running. The timer should be running only in the SUCCESS case. */ + if (QDF_TIMER_STATE_RUNNING == + qdf_mc_timer_get_current_state(&pMac->rrm.rrmSmeContext. + neighborReqControlInfo. + neighborRspWaitTimer)) { + sms_log(pMac, LOG1, FL("No entry in neighbor report cache")); + qdf_mc_timer_stop(&pMac->rrm.rrmSmeContext. + neighborReqControlInfo.neighborRspWaitTimer); + } + callback = + pMac->rrm.rrmSmeContext.neighborReqControlInfo. + neighborRspCallbackInfo.neighborRspCallback; + callbackContext = + pMac->rrm.rrmSmeContext.neighborReqControlInfo. + neighborRspCallbackInfo.neighborRspCallbackContext; + + /* Reset the callback and the callback context before calling the callback. It is very likely that there may be a registration in + callback itself. */ + pMac->rrm.rrmSmeContext.neighborReqControlInfo.neighborRspCallbackInfo. + neighborRspCallback = NULL; + pMac->rrm.rrmSmeContext.neighborReqControlInfo.neighborRspCallbackInfo. + neighborRspCallbackContext = NULL; + + /* Call the callback with the status received from caller */ + if (callback) + callback(callbackContext, qdf_status); + + return; + +} + +/** + * sme_RrmBeaconReportXmitInd () - Send beacon report + * @mac_ctx Pointer to mac context + * @result_arr scan results + * @msrmnt_status flag to indicate that the measurement is done. + * @bss_count bss count + * + * Create and send the beacon report Xmit ind message to PE. + * + * Return: status + */ + +static QDF_STATUS +sme_rrm_send_beacon_report_xmit_ind(tpAniSirGlobal mac_ctx, + tCsrScanResultInfo **result_arr, uint8_t msrmnt_status, + uint8_t bss_count) +{ + tpSirBssDescription bss_desc = NULL; + tpSirBeaconReportXmitInd beacon_rep; + uint16_t length, ie_len, tot_len; + uint8_t i = 0, j = 0; + tCsrScanResultInfo *cur_result = NULL; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpRrmSMEContext rrm_ctx = &mac_ctx->rrm.rrmSmeContext; + + if (NULL == result_arr && !msrmnt_status) { + sms_log(mac_ctx, LOGE, "Beacon report xmit Ind to PE Failed"); + return QDF_STATUS_E_FAILURE; + } + + if (result_arr) + cur_result = result_arr[j]; + + do { + length = sizeof(tSirBeaconReportXmitInd); + beacon_rep = qdf_mem_malloc(length); + if (NULL == beacon_rep) { + sms_log(mac_ctx, LOGP, + "Unable to allocate memory for beacon report"); + return QDF_STATUS_E_NOMEM; + } + beacon_rep->messageType = eWNI_SME_BEACON_REPORT_RESP_XMIT_IND; + beacon_rep->length = length; + beacon_rep->uDialogToken = rrm_ctx->token; + beacon_rep->duration = rrm_ctx->duration[0]; + beacon_rep->regClass = rrm_ctx->regClass; + qdf_mem_copy(beacon_rep->bssId, rrm_ctx->sessionBssId.bytes, + QDF_MAC_ADDR_SIZE); + + i = 0; + while (cur_result) { + bss_desc = &cur_result->BssDescriptor; + if (bss_desc == NULL) + break; + ie_len = GET_IE_LEN_IN_BSS(bss_desc->length); + tot_len = ie_len + sizeof(*bss_desc); + beacon_rep->pBssDescription[i] = + qdf_mem_malloc(tot_len); + if (NULL == + beacon_rep->pBssDescription[i]) + break; + qdf_mem_copy(beacon_rep->pBssDescription[i], + bss_desc, sizeof(tSirBssDescription)); + qdf_mem_copy( + &beacon_rep->pBssDescription[i]->ieFields[0], + bss_desc->ieFields, ie_len); + sms_log(mac_ctx, LOG1, + ".RRM Result Bssid = " MAC_ADDRESS_STR + " chan= %d, rssi = -%d", + MAC_ADDR_ARRAY( + beacon_rep->pBssDescription[i]->bssId), + beacon_rep->pBssDescription[i]->channelId, + beacon_rep->pBssDescription[i]->rssi * (-1)); + beacon_rep->numBssDesc++; + if (++i >= SIR_BCN_REPORT_MAX_BSS_DESC) + break; + cur_result = + result_arr[j + i]; + } + + j += i; + if (!result_arr || (cur_result == NULL) + || (j >= bss_count)) { + cur_result = NULL; + sms_log(mac_ctx, LOG1, + "Reached to max/last BSS in cur_result list"); + } else { + cur_result = result_arr[j]; + sms_log(mac_ctx, LOG1, + "Move to the next BSS set in cur_result list"); + } + beacon_rep->fMeasureDone = + (cur_result) ? false : msrmnt_status; + sms_log(mac_ctx, LOG1, + "SME Sending BcnRepXmit to PE numBss %d i %d j %d", + beacon_rep->numBssDesc, i, j); + status = cds_send_mb_message_to_mac(beacon_rep); + } while (cur_result); + + return status; +} + +#ifdef FEATURE_WLAN_ESE +/** + * sme_ese_send_beacon_req_scan_results () - Send beacon report + * @mac_ctx Pointer to mac context + * @session_id - session id + * @result_arr scan results + * @msrmnt_status flag to indicate that the measurement is done. + * @bss_count number of bss found + * + * This function sends up the scan results received as a part of + * beacon request scanning. + * This function is called after receiving the scan results per channel + * Due to the limitation on the size of the IWEVCUSTOM buffer, we send + * 3 BSSIDs of beacon report information in one custom event; + * + * Return: status + */ +static QDF_STATUS sme_ese_send_beacon_req_scan_results( + tpAniSirGlobal mac_ctx, uint32_t session_id, + uint8_t channel, tCsrScanResultInfo **result_arr, + uint8_t msrmnt_status, uint8_t bss_count) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tSirRetStatus fill_ie_status; + tpSirBssDescription bss_desc = NULL; + uint32_t ie_len = 0; + uint32_t out_ie_len = 0; + uint8_t bss_counter = 0; + tCsrScanResultInfo *cur_result = NULL; + tpRrmSMEContext rrm_ctx = &mac_ctx->rrm.rrmSmeContext; + tCsrRoamInfo roam_info; + tSirEseBcnReportRsp bcn_rpt_rsp; + tpSirEseBcnReportRsp bcn_report = &bcn_rpt_rsp; + tpCsrEseBeaconReqParams cur_meas_req = NULL; + uint8_t i = 0, j = 0; + tBcnReportFields *bcn_rpt_fields; + + if (NULL == rrm_ctx) { + sms_log(mac_ctx, LOGE, "rrm_ctx is NULL"); + return QDF_STATUS_E_FAILURE; + } + + if (NULL == result_arr && !msrmnt_status) { + sms_log(mac_ctx, LOGE, "Beacon report xmit Ind to HDD Failed"); + return QDF_STATUS_E_FAILURE; + } + + if (result_arr) + cur_result = result_arr[bss_counter]; + + qdf_mem_zero(&bcn_rpt_rsp, sizeof(tSirEseBcnReportRsp)); + do { + cur_meas_req = NULL; + for (i = 0; i < rrm_ctx->eseBcnReqInfo.numBcnReqIe; i++) { + if (rrm_ctx->eseBcnReqInfo.bcnReq[i].channel == + channel) { + cur_meas_req = + &rrm_ctx->eseBcnReqInfo.bcnReq[i]; + break; + } + } + if (NULL != cur_meas_req) + bcn_report->measurementToken = + cur_meas_req->measurementToken; + sms_log(mac_ctx, LOG1, "Channel(%d) MeasToken(%d)", channel, + bcn_report->measurementToken); + + j = 0; + while (cur_result) { + bss_desc = &cur_result->BssDescriptor; + if (NULL == bss_desc) { + cur_result = NULL; + break; + } + ie_len = GET_IE_LEN_IN_BSS(bss_desc->length); + bcn_rpt_fields = + &bcn_report->bcnRepBssInfo[j].bcnReportFields; + bcn_rpt_fields->ChanNum = + bss_desc->channelId; + bcn_report->bcnRepBssInfo[j].bcnReportFields.Spare = 0; + if (NULL != cur_meas_req) + bcn_rpt_fields->MeasDuration = + cur_meas_req->measurementDuration; + bcn_rpt_fields->PhyType = bss_desc->nwType; + bcn_rpt_fields->RecvSigPower = bss_desc->rssi; + bcn_rpt_fields->ParentTsf = bss_desc->parentTSF; + bcn_rpt_fields->TargetTsf[0] = bss_desc->timeStamp[0]; + bcn_rpt_fields->TargetTsf[1] = bss_desc->timeStamp[1]; + bcn_rpt_fields->BcnInterval = bss_desc->beaconInterval; + bcn_rpt_fields->CapabilityInfo = + bss_desc->capabilityInfo; + + qdf_mem_copy(bcn_rpt_fields->Bssid, + bss_desc->bssId, sizeof(tSirMacAddr)); + fill_ie_status = + sir_beacon_ie_ese_bcn_report(mac_ctx, + (uint8_t *) bss_desc->ieFields, + ie_len, + &(bcn_report->bcnRepBssInfo[j].pBuf), + &out_ie_len); + if (eSIR_FAILURE == fill_ie_status) + continue; + bcn_report->bcnRepBssInfo[j].ieLen = out_ie_len; + + sms_log(mac_ctx, LOG1, "Bssid(" MAC_ADDRESS_STR")" + "Channel=%d Rssi=%d", + MAC_ADDR_ARRAY(bss_desc->bssId), + bss_desc->channelId, (-1) * bss_desc->rssi); + bcn_report->numBss++; + if (++j >= SIR_BCN_REPORT_MAX_BSS_DESC) + break; + cur_result = result_arr[j]; + } + + bss_counter += j; + if (!result_arr || !cur_result + || (bss_counter >= SIR_BCN_REPORT_MAX_BSS_DESC)) { + cur_result = NULL; + sms_log(mac_ctx, LOGE, + "Reached to the max/last BSS in cur_result list"); + } else { + cur_result = result_arr[bss_counter]; + sms_log(mac_ctx, LOGE, + "Move to the next BSS set in cur_result list"); + } + + bcn_report->flag = + (msrmnt_status << 1) | ((cur_result) ? true : false); + + sms_log(mac_ctx, LOG1, "SME Sending BcnRep to HDD numBss(%d)" + " j(%d) bss_counter(%d) flag(%d)", + bcn_report->numBss, j, bss_counter, + bcn_report->flag); + + roam_info.pEseBcnReportRsp = bcn_report; + status = csr_roam_call_callback(mac_ctx, session_id, &roam_info, + 0, eCSR_ROAM_ESE_BCN_REPORT_IND, 0); + + /* Free the memory allocated to IE */ + for (i = 0; i < j; i++) + if (bcn_report->bcnRepBssInfo[i].pBuf) + qdf_mem_free(bcn_report->bcnRepBssInfo[i].pBuf); + } while (cur_result); + return status; +} + +#endif /* FEATURE_WLAN_ESE */ + +/** + * sme_rrm_send_scan_result() - to get scan result and send the beacon report + * @mac_ctx: pointer to mac context + * @num_chan: number of channels + * @chan_list: list of channels to fetch the result from + * @measurementdone: Flag to indicate measurement done or no + * + * This function is called to get the scan result from CSR and send the beacon + * report xmit ind message to PE + * + * Return: QDF_STATUS + */ +static QDF_STATUS sme_rrm_send_scan_result(tpAniSirGlobal mac_ctx, + uint8_t num_chan, + uint8_t *chan_list, + uint8_t measurementdone) +{ + tCsrScanResultFilter filter; + tScanResultHandle result_handle; + tCsrScanResultInfo *scan_results, *next_result; + tCsrScanResultInfo *scanresults_arr[SIR_BCN_REPORT_MAX_BSS_DESC]; + QDF_STATUS status; + uint8_t counter = 0; + tpRrmSMEContext rrm_ctx = &mac_ctx->rrm.rrmSmeContext; + uint32_t session_id; + tCsrRoamInfo *roam_info; + + qdf_mem_zero(&filter, sizeof(filter)); + qdf_mem_zero(scanresults_arr, + sizeof(next_result) * SIR_BCN_REPORT_MAX_BSS_DESC); + filter.BSSIDs.numOfBSSIDs = 1; + filter.BSSIDs.bssid = (struct qdf_mac_addr *)&rrm_ctx->bssId; + + if (rrm_ctx->ssId.length) { + filter.SSIDs.SSIDList = + (tCsrSSIDInfo *) qdf_mem_malloc(sizeof(tCsrSSIDInfo)); + if (filter.SSIDs.SSIDList == NULL) { + sms_log(mac_ctx, LOGP, FL("qdf_mem_malloc failed")); + return QDF_STATUS_E_NOMEM; + } + + filter.SSIDs.SSIDList->SSID.length = + rrm_ctx->ssId.length; + qdf_mem_copy(filter.SSIDs.SSIDList->SSID.ssId, + rrm_ctx->ssId.ssId, rrm_ctx->ssId.length); + filter.SSIDs.numOfSSIDs = 1; + } else { + filter.SSIDs.numOfSSIDs = 0; + } + + filter.ChannelInfo.numOfChannels = num_chan; + filter.ChannelInfo.ChannelList = chan_list; + filter.fMeasurement = true; + + /* + * In case this is beacon report request from last AP (before roaming) + * following call to csr_roam_get_session_id_from_bssid will fail, + * hence use current session ID instead of one stored in SME rrm context + */ + if (QDF_STATUS_E_FAILURE == csr_roam_get_session_id_from_bssid(mac_ctx, + &rrm_ctx->sessionBssId, &session_id)) { + sms_log(mac_ctx, LOG1, + FL("BSSID mismatch, using current session_id")); + session_id = mac_ctx->roam.roamSession->sessionId; + } + status = sme_scan_get_result(mac_ctx, (uint8_t) session_id, + &filter, &result_handle); + + if (filter.SSIDs.SSIDList) + qdf_mem_free(filter.SSIDs.SSIDList); + + sms_log(mac_ctx, LOG1, FL("RRM Measurement Done %d"), measurementdone); + if (NULL == result_handle) { + /* + * no scan results + * Spec. doesnt say anything about such condition + * Since section 7.4.6.2 (IEEE802.11k-2008) says-rrm report + * frame should contain one or more report IEs. It probably + * means dont send any respose if no matching BSS found. + * Moreover, there is no flag or field in measurement report + * IE(7.3.2.22) OR beacon report IE(7.3.2.22.6) that can be set + * to indicate no BSS found on a given channel. If we finished + * measurement on all the channels, we still need to send a + * xmit indication with moreToFollow set to MEASURMENT_DONE so + * that PE can clean any context allocated. + */ + if (!measurementdone) + return status; +#ifdef FEATURE_WLAN_ESE + if (eRRM_MSG_SOURCE_ESE_UPLOAD == rrm_ctx->msgSource) + status = sme_ese_send_beacon_req_scan_results(mac_ctx, + session_id, chan_list[0], + NULL, measurementdone, 0); + else +#endif /* FEATURE_WLAN_ESE */ + status = sme_rrm_send_beacon_report_xmit_ind(mac_ctx, + NULL, measurementdone, 0); + return status; + } + scan_results = sme_scan_result_get_first(mac_ctx, result_handle); + if (NULL == scan_results && measurementdone) { +#ifdef FEATURE_WLAN_ESE + if (eRRM_MSG_SOURCE_ESE_UPLOAD == rrm_ctx->msgSource) { + status = sme_ese_send_beacon_req_scan_results(mac_ctx, + session_id, + chan_list[0], + NULL, + measurementdone, + 0); + } else +#endif /* FEATURE_WLAN_ESE */ + status = sme_rrm_send_beacon_report_xmit_ind(mac_ctx, + NULL, measurementdone, 0); + } + counter = 0; + + roam_info = qdf_mem_malloc(sizeof(*roam_info)); + if (NULL == roam_info) { + sms_log(mac_ctx, LOGP, FL("vos_mem_malloc failed")); + status = QDF_STATUS_E_NOMEM; + goto rrm_send_scan_results_done; + } + + while (scan_results) { + next_result = sme_scan_result_get_next(mac_ctx, result_handle); + sms_log(mac_ctx, LOG1, "Scan res timer:%lu, rrm scan timer:%llu", + scan_results->timer, rrm_scan_timer); + if (scan_results->timer >= rrm_scan_timer) { + roam_info->pBssDesc = &scan_results->BssDescriptor; + csr_roam_call_callback(mac_ctx, session_id, roam_info, + 0, eCSR_ROAM_UPDATE_SCAN_RESULT, + eCSR_ROAM_RESULT_NONE); + scanresults_arr[counter++] = scan_results; + } + scan_results = next_result; + if (counter >= SIR_BCN_REPORT_MAX_BSS_DESC) + break; + } + qdf_mem_free(roam_info); + /* + * The beacon report should be sent whether the counter is zero or + * non-zero. There might be a few scan results in the cache but not + * actually are a result of this scan. During that scenario, the + * counter will be zero. The report should be sent and LIM will further + * cleanup the RRM to accept the further incoming requests + * In case the counter is Zero, the pScanResultsArr will be NULL. + * The next level routine does a check for the measurementDone to + * determine whether to send a report or not. + */ + sms_log(mac_ctx, LOG1, FL(" Number of BSS Desc with RRM Scan %d "), + counter); + if (counter || measurementdone) { +#ifdef FEATURE_WLAN_ESE + if (eRRM_MSG_SOURCE_ESE_UPLOAD == rrm_ctx->msgSource) + status = sme_ese_send_beacon_req_scan_results(mac_ctx, + session_id, chan_list[0], + scanresults_arr, measurementdone, + counter); + else +#endif /* FEATURE_WLAN_ESE */ + status = sme_rrm_send_beacon_report_xmit_ind(mac_ctx, + scanresults_arr, measurementdone, + counter); + } + +rrm_send_scan_results_done: + sme_scan_result_purge(mac_ctx, result_handle); + return status; +} + +/** + * sme_rrm_scan_request_callback() -Sends the beacon report xmit to PE + * @halHandle - Pointer to the Hal Handle. + * @pContext - Pointer to the data context. + * @scanId - Scan ID. + * @status - CSR Status. + * + * The sme module calls this callback function once it finish the scan request + * and this function send the beacon report xmit to PE and starts a timer of + * random interval to issue next request. + * + * Return : 0 for success, non zero for failure + */ + +static QDF_STATUS sme_rrm_scan_request_callback(tHalHandle halHandle, + void *pContext, + uint8_t sessionId, + uint32_t scanId, + eCsrScanStatus status) +{ + + uint16_t interval; + tpAniSirGlobal pMac = (tpAniSirGlobal) halHandle; + tpRrmSMEContext pSmeRrmContext = &pMac->rrm.rrmSmeContext; + uint32_t time_tick; + + /* if any more channels are pending, start a timer of a random value within randomization interval. */ + /* */ + /* */ + if ((pSmeRrmContext->currentIndex + 1) < + pSmeRrmContext->channelList.numOfChannels) { + sme_rrm_send_scan_result(pMac, 1, + &pSmeRrmContext->channelList. + ChannelList[pSmeRrmContext->currentIndex], + false); + + pSmeRrmContext->currentIndex++; /* Advance the current index. */ + /* start the timer to issue next request. */ + /* From timer tick get a random number within 10ms and max randmization interval. */ + time_tick = qdf_mc_timer_get_system_ticks(); + interval = + time_tick % (pSmeRrmContext->randnIntvl - 10 + 1) + 10; + + sms_log(pMac, LOG1, "Set timer for interval %d ", interval); + qdf_mc_timer_start(&pSmeRrmContext->IterMeasTimer, interval); + + } else { + /* Done with the measurement. Clean up all context and send a message to PE with measurement done flag set. */ + sme_rrm_send_scan_result(pMac, 1, + &pSmeRrmContext->channelList. + ChannelList[pSmeRrmContext->currentIndex], + true); + qdf_mem_free(pSmeRrmContext->channelList.ChannelList); +#ifdef FEATURE_WLAN_ESE + pSmeRrmContext->eseBcnReqInProgress = false; +#endif + } + + return QDF_STATUS_SUCCESS; +} + +/** + * sme_rrm_issue_scan_req() - To issue rrm scan request + * @mac_ctx: pointer to mac context + * + * This routine is called to issue rrm scan request + * + * Return: QDF_STATUS + */ +static QDF_STATUS sme_rrm_issue_scan_req(tpAniSirGlobal mac_ctx) +{ + /* Issue scan request. */ + tCsrScanRequest scan_req; + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpRrmSMEContext sme_rrm_ctx = &mac_ctx->rrm.rrmSmeContext; + uint32_t session_id; + uint32_t max_chan_time; + tSirScanType scan_type; + uint64_t current_time; + + status = csr_roam_get_session_id_from_bssid(mac_ctx, + &sme_rrm_ctx->sessionBssId, &session_id); + if (status != QDF_STATUS_SUCCESS) { + sms_log(mac_ctx, LOGE, FL("Invalid sme Session ID")); + return QDF_STATUS_E_FAILURE; + } + + if ((sme_rrm_ctx->currentIndex) >= + sme_rrm_ctx->channelList.numOfChannels) + return status; + + if (eRRM_MSG_SOURCE_ESE_UPLOAD == sme_rrm_ctx->msgSource || + eRRM_MSG_SOURCE_LEGACY_ESE == sme_rrm_ctx->msgSource) + scan_type = sme_rrm_ctx->measMode[sme_rrm_ctx->currentIndex]; + else + scan_type = sme_rrm_ctx->measMode[0]; + + if ((eSIR_ACTIVE_SCAN == scan_type) || + (eSIR_PASSIVE_SCAN == scan_type)) { + qdf_mem_zero(&scan_req, sizeof(scan_req)); + /* set scan_type, active or passive */ + scan_req.bcnRptReqScan = true; + scan_req.scanType = scan_type; + qdf_mem_copy(&scan_req.bssid.bytes, sme_rrm_ctx->bssId, + QDF_MAC_ADDR_SIZE); + if (sme_rrm_ctx->ssId.length) { + scan_req.SSIDs.numOfSSIDs = 1; + scan_req.SSIDs.SSIDList = + (tCsrSSIDInfo *)qdf_mem_malloc( + sizeof(tCsrSSIDInfo)); + if (NULL == scan_req.SSIDs.SSIDList) { + sms_log(mac_ctx, LOGP, + FL("qdf_mem_malloc failed")); + return QDF_STATUS_E_NOMEM; + } + scan_req.SSIDs.SSIDList->SSID.length = + sme_rrm_ctx->ssId.length; + qdf_mem_copy(scan_req.SSIDs.SSIDList->SSID.ssId, + sme_rrm_ctx->ssId.ssId, + sme_rrm_ctx->ssId.length); + } + + /* + * set min and max channel time + * sme_rrm_ctx->duration; Dont use min timeout. + */ + scan_req.minChnTime = 0; + if (eRRM_MSG_SOURCE_ESE_UPLOAD == sme_rrm_ctx->msgSource || + eRRM_MSG_SOURCE_LEGACY_ESE == sme_rrm_ctx->msgSource) + scan_req.maxChnTime = sme_rrm_ctx->duration[ + sme_rrm_ctx->currentIndex]; + else + scan_req.maxChnTime = sme_rrm_ctx->duration[0]; + + sms_log(mac_ctx, LOG1, FL("Scan Type(%d) Max Dwell Time(%d)"), + scan_req.scanType, scan_req.maxChnTime); + /* + * Use gPassive/gActiveMaxChannelTime if maxChanTime is less + * than default. + */ + if (eSIR_ACTIVE_SCAN == scan_type) + max_chan_time = + mac_ctx->roam.configParam.nActiveMaxChnTime; + else + max_chan_time = + mac_ctx->roam.configParam.nPassiveMaxChnTime; + + if (scan_req.maxChnTime < max_chan_time) { + scan_req.maxChnTime = max_chan_time; + sms_log(mac_ctx, LOG1, + FL("Setting default max %d ChanTime"), + max_chan_time); + } + + /* + * For RRM scans timing is very important especially when the + * request is for limited channels. There is no need for + * firmware to rest for about 100-200 ms on the home channel. + * Instead, it can start the scan right away which will make the + * host to respond with the beacon report as quickly as + * possible. Ensure that the scan requests are not back to back + * and hence there is a check to see if the requests are atleast + * 1 second apart. + */ + current_time = (uint64_t)qdf_mc_timer_get_system_time(); + sms_log(mac_ctx, LOG1, "prev scan triggered before %llu ms, totalchannels %d", + current_time - rrm_scan_timer, + sme_rrm_ctx->channelList.numOfChannels); + if ((abs(current_time - rrm_scan_timer) > 1000) && + (sme_rrm_ctx->channelList.numOfChannels == 1)) { + scan_req.restTime = 1; + scan_req.min_rest_time = 1; + scan_req.idle_time = 1; + } + + rrm_scan_timer = (uint64_t)qdf_mc_timer_get_system_time(); + + /* set BSSType to default type */ + scan_req.BSSType = eCSR_BSS_TYPE_ANY; + /*Scan all the channels */ + scan_req.ChannelInfo.numOfChannels = 1; + scan_req.ChannelInfo.ChannelList = + &sme_rrm_ctx->channelList.ChannelList[ + sme_rrm_ctx->currentIndex]; + sms_log(mac_ctx, LOG1, FL("Duration %d On channel %d "), + scan_req.maxChnTime, + sme_rrm_ctx->channelList.ChannelList[ + sme_rrm_ctx->currentIndex]); + /* set requestType to full scan */ + scan_req.requestType = eCSR_SCAN_REQUEST_FULL_SCAN; + status = sme_scan_request(mac_ctx, (uint8_t) session_id, + &scan_req, + &sme_rrm_scan_request_callback, NULL); + + if (sme_rrm_ctx->ssId.length) + qdf_mem_free(scan_req.SSIDs.SSIDList); + } else if (eSIR_BEACON_TABLE == scan_type) { + /* + * In beacon table mode, scan results are taken directly from + * scan cache without issuing any scan request. So, it is not + * proper to update rrm_scan_timer with latest time and hence + * made it to zero to satisfy + * pScanResult->timer >= rrm_scan_timer + */ + rrm_scan_timer = 0; + if ((sme_rrm_ctx->currentIndex + 1) < + sme_rrm_ctx->channelList.numOfChannels) { + sme_rrm_send_scan_result(mac_ctx, 1, + &sme_rrm_ctx->channelList.ChannelList[ + sme_rrm_ctx->currentIndex], false); + /* Advance the current index. */ + sme_rrm_ctx->currentIndex++; + sme_rrm_issue_scan_req(mac_ctx); +#ifdef FEATURE_WLAN_ESE + sme_rrm_ctx->eseBcnReqInProgress = false; +#endif + } else { + /* + * Done with the measurement. Clean up all context and + * send a message to PE with measurement done flag set. + */ + sme_rrm_send_scan_result(mac_ctx, 1, + &sme_rrm_ctx->channelList.ChannelList[ + sme_rrm_ctx->currentIndex], true); + qdf_mem_free(sme_rrm_ctx->channelList.ChannelList); + } + } else { + sms_log(mac_ctx, LOGE, FL("Unknown beacon report req mode(%d)"), + scan_type); + /* + * Indicate measurement completion to PE + * If this is not done, pCurrentReq pointer will not be freed + * and PE will not handle subsequent Beacon requests + */ + sme_rrm_send_beacon_report_xmit_ind(mac_ctx, NULL, true, 0); + } + return status; +} + +/** + * sme_rrm_process_beacon_report_req_ind() -Process beacon report request + * @pMac:- Global Mac structure + * @pMsgBuf:- a pointer to a buffer that maps to various structures base + * on the message type.The beginning of the buffer can always + * map to tSirSmeRsp. + * + * This is called to process the Beacon + * report request from peer AP forwarded through PE . + * + * Return : QDF_STATUS_SUCCESS - Validation is successful. + */ +QDF_STATUS sme_rrm_process_beacon_report_req_ind(tpAniSirGlobal pMac, void *pMsgBuf) +{ + tpSirBeaconReportReqInd pBeaconReq = (tpSirBeaconReportReqInd) pMsgBuf; + tpRrmSMEContext pSmeRrmContext = &pMac->rrm.rrmSmeContext; + uint32_t len = 0, i = 0; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + sms_log(pMac, LOG1, "Received Beacon report request ind Channel = %d", + pBeaconReq->channelInfo.channelNum); + /* section 11.10.8.1 (IEEE Std 802.11k-2008) */ + /* channel 0 and 255 has special meaning. */ + if ((pBeaconReq->channelInfo.channelNum == 0) || + ((pBeaconReq->channelInfo.channelNum == 255) + && (pBeaconReq->channelList.numChannels == 0))) { + /* Add all the channel in the regulatory domain. */ + wlan_cfg_get_str_len(pMac, WNI_CFG_VALID_CHANNEL_LIST, &len); + pSmeRrmContext->channelList.ChannelList = qdf_mem_malloc(len); + if (pSmeRrmContext->channelList.ChannelList == NULL) { + sms_log(pMac, LOGP, FL("qdf_mem_malloc failed")); + return QDF_STATUS_E_NOMEM; + } + csr_get_cfg_valid_channels(pMac, + pSmeRrmContext->channelList.ChannelList, + &len); + pSmeRrmContext->channelList.numOfChannels = (uint8_t) len; + } else { + len = 0; + pSmeRrmContext->channelList.numOfChannels = 0; + + /* If valid channel is present. We first Measure on the given channel. and */ + /* if there are additional channels present in APchannelreport, measure on these also. */ + if (pBeaconReq->channelInfo.channelNum != 255) + len = 1; + + len += pBeaconReq->channelList.numChannels; + + pSmeRrmContext->channelList.ChannelList = qdf_mem_malloc(len); + if (pSmeRrmContext->channelList.ChannelList == NULL) { + sms_log(pMac, LOGP, FL("qdf_mem_malloc failed")); + return QDF_STATUS_E_NOMEM; + } + + if (pBeaconReq->channelInfo.channelNum != 255) { + if (csr_roam_is_channel_valid + (pMac, pBeaconReq->channelInfo.channelNum)) + pSmeRrmContext->channelList. + ChannelList[pSmeRrmContext->channelList. + numOfChannels++] = + pBeaconReq->channelInfo.channelNum; + else + sms_log(pMac, LOGE, "Invalid channel"); + } + + for (i = 0; i < pBeaconReq->channelList.numChannels; i++) { + if (csr_roam_is_channel_valid + (pMac, pBeaconReq->channelList.channelNumber[i])) { + pSmeRrmContext->channelList. + ChannelList[pSmeRrmContext->channelList. + numOfChannels] = + pBeaconReq->channelList.channelNumber[i]; + pSmeRrmContext->channelList.numOfChannels++; + } + } + } + + /* Copy session bssid */ + qdf_mem_copy(pSmeRrmContext->sessionBssId.bytes, pBeaconReq->bssId, + sizeof(tSirMacAddr)); + + /* copy measurement bssid */ + qdf_mem_copy(pSmeRrmContext->bssId, pBeaconReq->macaddrBssid, + sizeof(tSirMacAddr)); + + /* Copy ssid */ + qdf_mem_copy(&pSmeRrmContext->ssId, &pBeaconReq->ssId, + sizeof(tAniSSID)); + + pSmeRrmContext->token = pBeaconReq->uDialogToken; + pSmeRrmContext->regClass = pBeaconReq->channelInfo.regulatoryClass; + pSmeRrmContext->randnIntvl = + QDF_MAX(pBeaconReq->randomizationInterval, + pSmeRrmContext->rrmConfig.max_randn_interval); + pSmeRrmContext->currentIndex = 0; + pSmeRrmContext->msgSource = pBeaconReq->msgSource; + qdf_mem_copy((uint8_t *) &pSmeRrmContext->measMode, + (uint8_t *) &pBeaconReq->fMeasurementtype, + SIR_ESE_MAX_MEAS_IE_REQS); + qdf_mem_copy((uint8_t *) &pSmeRrmContext->duration, + (uint8_t *) &pBeaconReq->measurementDuration, + SIR_ESE_MAX_MEAS_IE_REQS); + + sms_log(pMac, LOG1, + FL("token %d regClass %d randnIntvl %d msgSource %d"), + pSmeRrmContext->token, pSmeRrmContext->regClass, + pSmeRrmContext->randnIntvl, pSmeRrmContext->msgSource); + + status = sme_rrm_issue_scan_req(pMac); + + return status; +} + +/** + * sme_rrm_neighbor_report_request() - This is API can be used to trigger a + * Neighbor report from the peer. + * @sessionId: session identifier on which the request should be made. + * @pNeighborReq: a pointer to a neighbor report request. + * + * This is API can be used to trigger a Neighbor report from the peer. + * + * Return: QDF_STATUS_SUCCESS - Validation is successful. + */ +QDF_STATUS sme_rrm_neighbor_report_request(tpAniSirGlobal pMac, uint8_t sessionId, + tpRrmNeighborReq pNeighborReq, + tpRrmNeighborRspCallbackInfo + callbackInfo) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpSirNeighborReportReqInd pMsg; + tCsrRoamSession *pSession; + + sms_log(pMac, LOG1, + FL("Request to send Neighbor report request received ")); + if (!CSR_IS_SESSION_VALID(pMac, sessionId)) { + sms_log(pMac, LOGE, FL("Invalid session %d"), sessionId); + return QDF_STATUS_E_INVAL; + } + pSession = CSR_GET_SESSION(pMac, sessionId); + + /* If already a report is pending, return failure */ + if (true == + pMac->rrm.rrmSmeContext.neighborReqControlInfo. + isNeighborRspPending) { + sms_log(pMac, LOGE, + FL("Neighbor request already pending.. Not allowed")); + return QDF_STATUS_E_AGAIN; + } + + pMsg = qdf_mem_malloc(sizeof(tSirNeighborReportReqInd)); + if (NULL == pMsg) { + sms_log(pMac, LOGE, + "Unable to allocate memory for Neighbor request"); + return QDF_STATUS_E_NOMEM; + } + + rrm_ll_purge_neighbor_cache(pMac, + &pMac->rrm.rrmSmeContext.neighborReportCache); + + pMsg->messageType = eWNI_SME_NEIGHBOR_REPORT_REQ_IND; + pMsg->length = sizeof(tSirNeighborReportReqInd); + qdf_mem_copy(&pMsg->bssId, &pSession->connectedProfile.bssid, + sizeof(tSirMacAddr)); + pMsg->noSSID = pNeighborReq->no_ssid; + qdf_mem_copy(&pMsg->ucSSID, &pNeighborReq->ssid, sizeof(tSirMacSSid)); + + status = cds_send_mb_message_to_mac(pMsg); + if (status != QDF_STATUS_SUCCESS) + return QDF_STATUS_E_FAILURE; + + /* Neighbor report request message sent successfully to PE. Now register the callbacks */ + pMac->rrm.rrmSmeContext.neighborReqControlInfo.neighborRspCallbackInfo. + neighborRspCallback = callbackInfo->neighborRspCallback; + pMac->rrm.rrmSmeContext.neighborReqControlInfo.neighborRspCallbackInfo. + neighborRspCallbackContext = + callbackInfo->neighborRspCallbackContext; + pMac->rrm.rrmSmeContext.neighborReqControlInfo.isNeighborRspPending = + true; + + /* Start neighbor response wait timer now */ + qdf_mc_timer_start(&pMac->rrm.rrmSmeContext.neighborReqControlInfo. + neighborRspWaitTimer, callbackInfo->timeout); + + return QDF_STATUS_SUCCESS; +} + +/** + * rrm_calculate_neighbor_ap_roam_score() - caclulates roam score + * @mac_ctx: mac global context + * @pNeighborReportDesc: Neighbor BSS Descriptor node for which roam score + * should be calculated + * + * This API is called while handling individual neighbor reports from the APs + * neighbor AP report to calculate the cumulative roam score before storing it + * in neighbor cache. + * + * Return: void + */ +static void +rrm_calculate_neighbor_ap_roam_score(tpAniSirGlobal mac_ctx, + tpRrmNeighborReportDesc nbr_report_desc) +{ + tpSirNeighborBssDescripton nbr_bss_desc; + uint32_t roam_score = 0; +#ifdef FEATURE_WLAN_ESE + uint8_t session_id; +#endif + if (NULL == nbr_report_desc) { + QDF_ASSERT(0); + return; + } + + if (NULL == nbr_report_desc->pNeighborBssDescription) { + QDF_ASSERT(0); + return; + } + + nbr_bss_desc = nbr_report_desc->pNeighborBssDescription; + if (!nbr_bss_desc->bssidInfo.rrmInfo.fMobilityDomain) + goto check_11r_assoc; + + roam_score += RRM_ROAM_SCORE_NEIGHBOR_REPORT_MOBILITY_DOMAIN; + if (!nbr_bss_desc->bssidInfo.rrmInfo.fSameSecurityMode) + goto check_11r_assoc; + + roam_score += RRM_ROAM_SCORE_NEIGHBOR_REPORT_SECURITY; + if (!nbr_bss_desc->bssidInfo.rrmInfo.fSameAuthenticator) + goto check_11r_assoc; + + roam_score += RRM_ROAM_SCORE_NEIGHBOR_REPORT_KEY_SCOPE; + if (!nbr_bss_desc->bssidInfo.rrmInfo.fCapRadioMeasurement) + goto check_11r_assoc; + + roam_score += RRM_ROAM_SCORE_NEIGHBOR_REPORT_CAPABILITY_RRM; + if (nbr_bss_desc->bssidInfo.rrmInfo.fCapSpectrumMeasurement) + roam_score += + RRM_ROAM_SCORE_NEIGHBOR_REPORT_CAPABILITY_SPECTRUM_MGMT; + + if (nbr_bss_desc->bssidInfo.rrmInfo.fCapQos) + roam_score += RRM_ROAM_SCORE_NEIGHBOR_REPORT_CAPABILITY_QOS; + + if (nbr_bss_desc->bssidInfo.rrmInfo.fCapApsd) + roam_score += RRM_ROAM_SCORE_NEIGHBOR_REPORT_CAPABILITY_APSD; + + if (nbr_bss_desc->bssidInfo.rrmInfo.fCapDelayedBlockAck) + roam_score += + RRM_ROAM_SCORE_NEIGHBOR_REPORT_CAPABILITY_DELAYED_BA; + + if (nbr_bss_desc->bssidInfo.rrmInfo.fCapImmediateBlockAck) + roam_score += + RRM_ROAM_SCORE_NEIGHBOR_REPORT_CAPABILITY_IMMEDIATE_BA; + + if (nbr_bss_desc->bssidInfo.rrmInfo.fApPreauthReachable) + roam_score += RRM_ROAM_SCORE_NEIGHBOR_REPORT_REACHABILITY; + +check_11r_assoc: +#ifdef FEATURE_WLAN_ESE + session_id = nbr_report_desc->sessionId; + /* It has come in the report so its the best score */ + if (csr_neighbor_roam_is11r_assoc(mac_ctx, session_id) == false) { + /* IAPP Route so lets make use of this info save all AP, as the + * list does not come all the time. Save and reuse till the next + * AP List comes to us. Even save our own MAC address. Will be + * useful next time around. + */ + roam_score += RRM_ROAM_SCORE_NEIGHBOR_IAPP_LIST; + } +#endif + nbr_report_desc->roamScore = roam_score; +} + +/** + * rrm_store_neighbor_rpt_by_roam_score()-store Neighbor BSS descriptor + * @pNeighborReportDesc - Neighbor BSS Descriptor node to be stored in cache + * + * This API is called to store a given + * Neighbor BSS descriptor to the neighbor cache. This function + * stores the neighbor BSS descriptors in such a way that descriptors + * are sorted by roamScore in descending order + * + * Return: void. + */ +static void rrm_store_neighbor_rpt_by_roam_score(tpAniSirGlobal pMac, + tpRrmNeighborReportDesc pNeighborReportDesc) +{ + tpRrmSMEContext pSmeRrmContext = &pMac->rrm.rrmSmeContext; + tListElem *pEntry; + tRrmNeighborReportDesc *pTempNeighborReportDesc; + + if (NULL == pNeighborReportDesc) { + QDF_ASSERT(0); + return; + } + if (NULL == pNeighborReportDesc->pNeighborBssDescription) { + QDF_ASSERT(0); + return; + } + + if (csr_ll_is_list_empty + (&pSmeRrmContext->neighborReportCache, LL_ACCESS_LOCK)) { + sms_log(pMac, LOGE, + FL + ("Neighbor report cache is empty.. Adding a entry now")); + /* Neighbor list cache is empty. Insert this entry in the tail */ + csr_ll_insert_tail(&pSmeRrmContext->neighborReportCache, + &pNeighborReportDesc->List, LL_ACCESS_LOCK); + return; + } else { + /* Should store the neighbor BSS description in the order sorted by roamScore in descending + order. APs with highest roamScore should be the 1st entry in the list */ + pEntry = + csr_ll_peek_head(&pSmeRrmContext->neighborReportCache, + LL_ACCESS_LOCK); + while (pEntry != NULL) { + pTempNeighborReportDesc = + GET_BASE_ADDR(pEntry, tRrmNeighborReportDesc, List); + if (pTempNeighborReportDesc->roamScore < + pNeighborReportDesc->roamScore) + break; + pEntry = + csr_ll_next(&pSmeRrmContext->neighborReportCache, + pEntry, LL_ACCESS_LOCK); + } + + if (pEntry) + /* This BSS roamscore is better than something in the list. Insert this before that one */ + csr_ll_insert_entry(&pSmeRrmContext->neighborReportCache, + pEntry, &pNeighborReportDesc->List, + LL_ACCESS_LOCK); + else + /* All the entries in the list has a better roam Score than this one. Insert this at the last */ + csr_ll_insert_tail(&pSmeRrmContext->neighborReportCache, + &pNeighborReportDesc->List, + LL_ACCESS_LOCK); + } + return; +} + +/** + * sme_rrm_process_neighbor_report() -Process the Neighbor report received + * from PE + * @pMac - Global MAC structure + * @pMsgBuf - a pointer to a buffer that maps to various structures base + * on the message type. + * The beginning of the buffer can always map to tSirSmeRsp. + * This is called to process the Neighbor report received from PE. + * + * Return: QDF_STATUS_SUCCESS - Validation is successful + */ +static QDF_STATUS sme_rrm_process_neighbor_report(tpAniSirGlobal pMac, + void *pMsgBuf) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpSirNeighborReportInd pNeighborRpt = (tpSirNeighborReportInd) pMsgBuf; + tpRrmNeighborReportDesc pNeighborReportDesc; + uint8_t i = 0; + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + uint32_t sessionId; + + /* Get the session id */ + status = + csr_roam_get_session_id_from_bssid(pMac, + (struct qdf_mac_addr *) pNeighborRpt->bssId, + &sessionId); + if (QDF_IS_STATUS_SUCCESS(status)) { +#ifdef FEATURE_WLAN_ESE + /* Clear the cache for ESE. */ + if (csr_roam_is_ese_assoc(pMac, sessionId)) { + rrm_ll_purge_neighbor_cache(pMac, + &pMac->rrm.rrmSmeContext. + neighborReportCache); + } +#endif + } + + for (i = 0; i < pNeighborRpt->numNeighborReports; i++) { + pNeighborReportDesc = + qdf_mem_malloc(sizeof(tRrmNeighborReportDesc)); + if (NULL == pNeighborReportDesc) { + sms_log(pMac, LOGE, + "Failed to alloc memory for RRM report desc"); + status = QDF_STATUS_E_NOMEM; + goto end; + + } + + pNeighborReportDesc->pNeighborBssDescription = + qdf_mem_malloc(sizeof(tSirNeighborBssDescription)); + if (NULL == pNeighborReportDesc->pNeighborBssDescription) { + sms_log(pMac, LOGE, + "Failed to alloc mem for RRM BSS Description"); + qdf_mem_free(pNeighborReportDesc); + status = QDF_STATUS_E_NOMEM; + goto end; + } + qdf_mem_copy(pNeighborReportDesc->pNeighborBssDescription, + &pNeighborRpt->sNeighborBssDescription[i], + sizeof(tSirNeighborBssDescription)); + + sms_log(pMac, LOG1, + "Received neighbor report with Neighbor BSSID: " + MAC_ADDRESS_STR, + MAC_ADDR_ARRAY( + pNeighborRpt->sNeighborBssDescription[i].bssId)); + + rrm_calculate_neighbor_ap_roam_score(pMac, pNeighborReportDesc); + + if (pNeighborReportDesc->roamScore > 0) { + rrm_store_neighbor_rpt_by_roam_score(pMac, + pNeighborReportDesc); + } else { + sms_log(pMac, LOGE, + FL("Roam score of BSSID " MAC_ADDRESS_STR + " is 0, Ignoring.."), + MAC_ADDR_ARRAY(pNeighborRpt-> + sNeighborBssDescription[i]. + bssId)); + + qdf_mem_free( + pNeighborReportDesc->pNeighborBssDescription); + qdf_mem_free(pNeighborReportDesc); + } + } +end: + + if (!csr_ll_count(&pMac->rrm.rrmSmeContext.neighborReportCache)) + qdf_status = QDF_STATUS_E_FAILURE; + + rrm_indicate_neighbor_report_result(pMac, qdf_status); + return status; +} + +/** + * sme_rrm_msg_processor()-Process RRM message + * @pMac - Pointer to the global MAC parameter structure. + * @msg_type - the type of msg passed by PE as defined in wni_api.h + * @pMsgBuf - a pointer to a buffer that maps to various structures base + * on the message type. + * The beginning of the buffer can always map to tSirSmeRsp. + * sme_process_msg() calls this function for the + * messages that are handled by SME RRM module. + * + * Return: QDF_STATUS_SUCCESS - Validation is successful. + */ +QDF_STATUS sme_rrm_msg_processor(tpAniSirGlobal pMac, uint16_t msg_type, + void *pMsgBuf) +{ + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO_HIGH, + FL(" Msg = %d for RRM measurement"), msg_type); + + /* switch on the msg type & make the state transition accordingly */ + switch (msg_type) { + case eWNI_SME_NEIGHBOR_REPORT_IND: + sme_rrm_process_neighbor_report(pMac, pMsgBuf); + break; + + case eWNI_SME_BEACON_REPORT_REQ_IND: + sme_rrm_process_beacon_report_req_ind(pMac, pMsgBuf); + break; + + default: + /* err msg */ + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("sme_rrm_msg_processor:unknown msg type = %d"), + msg_type); + + break; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * rrm_iter_meas_timer_handle() - Timer handler to handlet the timeout + * @ pMac - The handle returned by mac_open. + * + * Timer handler to handlet the timeout condition when a specific BT + * stop event does not come back, in which case to restore back the + * heartbeat timer. + * + * Return: NULL + */ +static void rrm_iter_meas_timer_handle(void *userData) +{ + tpAniSirGlobal pMac = (tpAniSirGlobal) userData; + sms_log(pMac, LOGE, + "Randomization timer expired...send on next channel "); + /* Issue a scan req for next channel. */ + sme_rrm_issue_scan_req(pMac); +} +/** + * rrm_neighbor_rsp_timeout_handler() - Timer handler to handlet the timeout + * @pMac - The handle returned by mac_open. + * + * Timer handler to handle the timeout condition when a neighbor request is sent + * and no neighbor response is received from the AP + * + * Return: NULL + */ +static void rrm_neighbor_rsp_timeout_handler(void *userData) +{ + tpAniSirGlobal pMac = (tpAniSirGlobal) userData; + sms_log(pMac, LOGE, "Neighbor Response timed out "); + rrm_indicate_neighbor_report_result(pMac, QDF_STATUS_E_FAILURE); + return; +} + +/** + * rrm_open() - Initialze all RRM module + * @ pMac: The handle returned by mac_open. + * + * Initialze all RRM module. + * + * Return: QDF_STATUS + */ +QDF_STATUS rrm_open(tpAniSirGlobal pMac) +{ + + QDF_STATUS qdf_status; + tpRrmSMEContext pSmeRrmContext = &pMac->rrm.rrmSmeContext; + QDF_STATUS qdf_ret_status = QDF_STATUS_SUCCESS; + + pSmeRrmContext->rrmConfig.max_randn_interval = 50; /* ms */ + + qdf_status = qdf_mc_timer_init(&pSmeRrmContext->IterMeasTimer, + QDF_TIMER_TYPE_SW, + rrm_iter_meas_timer_handle, (void *)pMac); + + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "rrm_open: Fail to init timer"); + + return QDF_STATUS_E_FAILURE; + } + + qdf_status = + qdf_mc_timer_init(&pSmeRrmContext->neighborReqControlInfo. + neighborRspWaitTimer, QDF_TIMER_TYPE_SW, + rrm_neighbor_rsp_timeout_handler, (void *)pMac); + + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "rrm_open: Fail to init timer"); + + return QDF_STATUS_E_FAILURE; + } + + pSmeRrmContext->neighborReqControlInfo.isNeighborRspPending = false; + + qdf_ret_status = + csr_ll_open(pMac->hHdd, &pSmeRrmContext->neighborReportCache); + if (QDF_STATUS_SUCCESS != qdf_ret_status) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "rrm_open: Fail to open neighbor cache result"); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * rrm_close() - Release all RRM modules and their resources. + * @pMac - The handle returned by mac_open. + * + * Release all RRM modules and their resources. + * + * Return: QDF_STATUS + * QDF_STATUS_E_FAILURE success + * QDF_STATUS_SUCCESS failure + */ + +QDF_STATUS rrm_close(tpAniSirGlobal pMac) +{ + + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + tpRrmSMEContext pSmeRrmContext = &pMac->rrm.rrmSmeContext; + + if (QDF_TIMER_STATE_RUNNING == + qdf_mc_timer_get_current_state(&pSmeRrmContext->IterMeasTimer)) { + qdf_status = qdf_mc_timer_stop(&pSmeRrmContext->IterMeasTimer); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Timer stop fail")); + } + } + + qdf_status = qdf_mc_timer_destroy(&pSmeRrmContext->IterMeasTimer); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("Fail to destroy timer")); + + } + + if (QDF_TIMER_STATE_RUNNING == + qdf_mc_timer_get_current_state(&pSmeRrmContext-> + neighborReqControlInfo. + neighborRspWaitTimer)) { + qdf_status = + qdf_mc_timer_stop(&pSmeRrmContext->neighborReqControlInfo. + neighborRspWaitTimer); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_FATAL, + FL("Timer stop fail")); + } + } + + qdf_status = + qdf_mc_timer_destroy(&pSmeRrmContext->neighborReqControlInfo. + neighborRspWaitTimer); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_FATAL, + FL("Fail to destroy timer")); + + } + + rrm_ll_purge_neighbor_cache(pMac, &pSmeRrmContext->neighborReportCache); + + csr_ll_close(&pSmeRrmContext->neighborReportCache); + + return qdf_status; + +} + +/* --------------------------------------------------------------------------- + + \fn rrm_ready + + \brief fn + + \param pMac - The handle returned by mac_open. + + \return QDF_STATUS + + ---------------------------------------------------------------------------*/ + +QDF_STATUS rrm_ready(tpAniSirGlobal pMac) +{ + + return QDF_STATUS_SUCCESS; +} + +/* --------------------------------------------------------------------------- + + \fn rrm_change_default_config_param + \brief fn + + \param pMac - The handle returned by mac_open. + \param pRrmConfig - pointer to new rrm configs. + + \return QDF_STATUS + + ---------------------------------------------------------------------------*/ +QDF_STATUS rrm_change_default_config_param(tpAniSirGlobal pMac, + struct rrm_config_param *rrm_config) +{ + qdf_mem_copy(&pMac->rrm.rrmSmeContext.rrmConfig, rrm_config, + sizeof(struct rrm_config_param)); + + return QDF_STATUS_SUCCESS; +} diff --git a/drivers/staging/qcacld-3.0/core/utils/epping/inc/epping_internal.h b/drivers/staging/qcacld-3.0/core/utils/epping/inc/epping_internal.h new file mode 100644 index 0000000000000000000000000000000000000000..fdd71c4174927cf934c0d0b1faa5f02f86681ebe --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/utils/epping/inc/epping_internal.h @@ -0,0 +1,199 @@ +/* + * Copyright (c) 2014-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef EPPING_INTERNAL_H +#define EPPING_INTERNAL_H +/**=========================================================================== + + \file epping_internal.h + + \brief Linux epping internal head file + + ==========================================================================*/ + +/*--------------------------------------------------------------------------- + Include files + -------------------------------------------------------------------------*/ + +#include +#include +#include +#include +#include +#if defined(WLAN_OPEN_SOURCE) && defined(CONFIG_HAS_WAKELOCK) +#include +#endif +#include "htc_api.h" +#include "htc_packet.h" +#include "epping_test.h" +#include +#include +#include + +#define EPPING_LOG_MASK (1< +#include + +/* epping_main signatures */ +int epping_open(void); +void epping_close(void); +void epping_disable(void); +int epping_enable(struct device *parent_dev); +#endif /* end #ifndef EPPING_MAIN_H */ diff --git a/drivers/staging/qcacld-3.0/core/utils/epping/src/epping_helper.c b/drivers/staging/qcacld-3.0/core/utils/epping/src/epping_helper.c new file mode 100644 index 0000000000000000000000000000000000000000..4e6b6257b1265398956fd4acee3a140e461e50bf --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/utils/epping/src/epping_helper.c @@ -0,0 +1,210 @@ +/* + * Copyright (c) 2014-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/*======================================================================== + + \file epping_main.c + + \brief WLAN End Point Ping test tool implementation + + ========================================================================*/ + +/*-------------------------------------------------------------------------- + Include Files + ------------------------------------------------------------------------*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "epping_main.h" +#include "epping_internal.h" + +int epping_cookie_init(epping_context_t *pEpping_ctx) +{ + A_UINT32 i, j; + + pEpping_ctx->cookie_list = NULL; + pEpping_ctx->cookie_count = 0; + for (i = 0; i < MAX_COOKIE_SLOTS_NUM; i++) { + pEpping_ctx->s_cookie_mem[i] = + qdf_mem_malloc(sizeof(struct epping_cookie) * + MAX_COOKIE_SLOT_SIZE); + if (pEpping_ctx->s_cookie_mem[i] == NULL) { + EPPING_LOG(QDF_TRACE_LEVEL_FATAL, + "%s: no mem for cookie (idx = %d)", __func__, + i); + goto error; + } + } + qdf_spinlock_create(&pEpping_ctx->cookie_lock); + + for (i = 0; i < MAX_COOKIE_SLOTS_NUM; i++) { + struct epping_cookie *cookie_mem = pEpping_ctx->s_cookie_mem[i]; + for (j = 0; j < MAX_COOKIE_SLOT_SIZE; j++) { + epping_free_cookie(pEpping_ctx, &cookie_mem[j]); + } + } + return 0; +error: + for (i = 0; i < MAX_COOKIE_SLOTS_NUM; i++) { + if (pEpping_ctx->s_cookie_mem[i]) { + qdf_mem_free(pEpping_ctx->s_cookie_mem[i]); + pEpping_ctx->s_cookie_mem[i] = NULL; + } + } + return -ENOMEM; +} + +/* cleanup cookie queue */ +void epping_cookie_cleanup(epping_context_t *pEpping_ctx) +{ + int i; + qdf_spin_lock_bh(&pEpping_ctx->cookie_lock); + pEpping_ctx->cookie_list = NULL; + pEpping_ctx->cookie_count = 0; + qdf_spin_unlock_bh(&pEpping_ctx->cookie_lock); + for (i = 0; i < MAX_COOKIE_SLOTS_NUM; i++) { + if (pEpping_ctx->s_cookie_mem[i]) { + qdf_mem_free(pEpping_ctx->s_cookie_mem[i]); + pEpping_ctx->s_cookie_mem[i] = NULL; + } + } +} + +void epping_free_cookie(epping_context_t *pEpping_ctx, + struct epping_cookie *cookie) +{ + qdf_spin_lock_bh(&pEpping_ctx->cookie_lock); + cookie->next = pEpping_ctx->cookie_list; + pEpping_ctx->cookie_list = cookie; + pEpping_ctx->cookie_count++; + qdf_spin_unlock_bh(&pEpping_ctx->cookie_lock); +} + +struct epping_cookie *epping_alloc_cookie(epping_context_t *pEpping_ctx) +{ + struct epping_cookie *cookie; + + qdf_spin_lock_bh(&pEpping_ctx->cookie_lock); + cookie = pEpping_ctx->cookie_list; + if (cookie != NULL) { + pEpping_ctx->cookie_list = cookie->next; + pEpping_ctx->cookie_count--; + } + qdf_spin_unlock_bh(&pEpping_ctx->cookie_lock); + return cookie; +} + +void epping_get_dummy_mac_addr(tSirMacAddr macAddr) +{ + macAddr[0] = 69; /* E */ + macAddr[1] = 80; /* P */ + macAddr[2] = 80; /* P */ + macAddr[3] = 73; /* I */ + macAddr[4] = 78; /* N */ + macAddr[5] = 71; /* G */ +} + +void epping_hex_dump(void *data, int buf_len, const char *str) +{ + char *buf = (char *)data; + int i; + + printk("%s: E, %s\n", __func__, str); + for (i = 0; (i + 7) < buf_len; i += 8) { + printk("%02x %02x %02x %02x %02x %02x %02x %02x\n", + buf[i], + buf[i + 1], + buf[i + 2], + buf[i + 3], + buf[i + 4], buf[i + 5], buf[i + 6], buf[i + 7]); + } + + /* Dump the bytes in the last line */ + for (; i < buf_len; i++) { + printk("%02x ", buf[i]); + } + printk("\n%s: X %s\n", __func__, str); +} + +void *epping_get_qdf_ctx(void) +{ + qdf_device_t *qdf_ctx; + + qdf_ctx = cds_get_context(QDF_MODULE_ID_QDF_DEVICE); + return qdf_ctx; +} + +void epping_log_packet(epping_adapter_t *pAdapter, + EPPING_HEADER *eppingHdr, int ret, const char *str) +{ + if (eppingHdr->Cmd_h & EPPING_LOG_MASK) { + EPPING_LOG(QDF_TRACE_LEVEL_FATAL, + "%s: cmd = %d, seqNo = %u, flag = 0x%x, ret = %d, " + "txCount = %lu, txDrop = %lu, txBytes = %lu," + "rxCount = %lu, rxDrop = %lu, rxBytes = %lu\n", + str, eppingHdr->Cmd_h, eppingHdr->SeqNo, + eppingHdr->CmdFlags_h, ret, + pAdapter->stats.tx_packets, + pAdapter->stats.tx_dropped, + pAdapter->stats.tx_bytes, + pAdapter->stats.rx_packets, + pAdapter->stats.rx_dropped, + pAdapter->stats.rx_bytes); + } +} + +void epping_log_stats(epping_adapter_t *pAdapter, const char *str) +{ + EPPING_LOG(QDF_TRACE_LEVEL_FATAL, + "%s: txCount = %lu, txDrop = %lu, tx_bytes = %lu, " + "rxCount = %lu, rxDrop = %lu, rx_bytes = %lu, tx_acks = %u\n", + str, + pAdapter->stats.tx_packets, + pAdapter->stats.tx_dropped, + pAdapter->stats.tx_bytes, + pAdapter->stats.rx_packets, + pAdapter->stats.rx_dropped, + pAdapter->stats.rx_bytes, + pAdapter->pEpping_ctx->total_tx_acks); +} + +void epping_set_kperf_flag(epping_adapter_t *pAdapter, + HTC_ENDPOINT_ID eid, A_UINT8 kperf_flag) +{ + pAdapter->pEpping_ctx->kperf_num_rx_recv[eid] = 0; + pAdapter->pEpping_ctx->kperf_num_tx_acks[eid] = 0; +} diff --git a/drivers/staging/qcacld-3.0/core/utils/epping/src/epping_main.c b/drivers/staging/qcacld-3.0/core/utils/epping/src/epping_main.c new file mode 100644 index 0000000000000000000000000000000000000000..a248966af6f46d61a5ff35a3a3820794e73b8c4d --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/utils/epping/src/epping_main.c @@ -0,0 +1,354 @@ +/* + * Copyright (c) 2014-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/*======================================================================== + + \file epping_main.c + + \brief WLAN End Point Ping test tool implementation + + ========================================================================*/ + +/*-------------------------------------------------------------------------- + Include Files + ------------------------------------------------------------------------*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "bmi.h" +#include "ol_fw.h" +#include "ol_if_athvar.h" +#include "hif.h" +#include "epping_main.h" +#include "epping_internal.h" +#include "cds_concurrency.h" + +#ifdef TIMER_MANAGER +#define TIMER_MANAGER_STR " +TIMER_MANAGER" +#else +#define TIMER_MANAGER_STR "" +#endif + +#ifdef MEMORY_DEBUG +#define MEMORY_DEBUG_STR " +MEMORY_DEBUG" +#else +#define MEMORY_DEBUG_STR "" +#endif + +#ifdef HIF_SDIO +#define WLAN_WAIT_TIME_WLANSTART 10000 +#else +#define WLAN_WAIT_TIME_WLANSTART 2000 +#endif + +static struct epping_context *g_epping_ctx; + +/** + * epping_open(): End point ping driver open Function + * + * This function is called by HDD to open epping module + * + * + * return - 0 for success, negative for failure + */ +int epping_open(void) +{ + EPPING_LOG(QDF_TRACE_LEVEL_INFO_HIGH, "%s: Enter", __func__); + + g_epping_ctx = qdf_mem_malloc(sizeof(*g_epping_ctx)); + + if (g_epping_ctx == NULL) { + EPPING_LOG(QDF_TRACE_LEVEL_ERROR, + "%s: cannot alloc epping context", __func__); + return -ENOMEM; + } + + g_epping_ctx->con_mode = cds_get_conparam(); + return 0; +} + +/** + * epping_disable(): End point ping driver disable Function + * + * This is the driver disable function - called by HDD to + * disable epping module + * + * return: none + */ +void epping_disable(void) +{ + epping_context_t *pEpping_ctx; + struct hif_opaque_softc *hif_ctx; + HTC_HANDLE htc_handle; + + pEpping_ctx = g_epping_ctx; + if (pEpping_ctx == NULL) { + EPPING_LOG(QDF_TRACE_LEVEL_FATAL, + "%s: error: pEpping_ctx = NULL", __func__); + return; + } + + if (pEpping_ctx->epping_adapter) { + epping_destroy_adapter(pEpping_ctx->epping_adapter); + pEpping_ctx->epping_adapter = NULL; + } + + hif_ctx = cds_get_context(QDF_MODULE_ID_HIF); + if (hif_ctx == NULL) { + EPPING_LOG(QDF_TRACE_LEVEL_FATAL, + "%s: error: hif_ctx = NULL", __func__); + return; + } + hif_disable_isr(hif_ctx); + hif_reset_soc(hif_ctx); + + htc_handle = cds_get_context(QDF_MODULE_ID_HTC); + if (htc_handle == NULL) { + EPPING_LOG(QDF_TRACE_LEVEL_FATAL, + "%s: error: htc_handle = NULL", __func__); + return; + } + htc_stop(htc_handle); + epping_cookie_cleanup(pEpping_ctx); + htc_destroy(htc_handle); +} + +/** + * epping_close(): End point ping driver close Function + * + * This is the driver close function - called by HDD to close epping module + * + * return: none + */ +void epping_close(void) +{ + epping_context_t *to_free; + + + if (g_epping_ctx == NULL) { + EPPING_LOG(QDF_TRACE_LEVEL_FATAL, + "%s: error: g_epping_ctx = NULL", __func__); + return; + } + + to_free = g_epping_ctx; + g_epping_ctx = NULL; + qdf_mem_free(to_free); +} + +/** + * epping_target_suspend_acknowledge() - process wow ack/nack from fw + * @context: HTC_INIT_INFO->context + * @wow_nack: true when wow is rejected + */ +static void epping_target_suspend_acknowledge(void *context, bool wow_nack) +{ + if (NULL == g_epping_ctx) { + EPPING_LOG(QDF_TRACE_LEVEL_FATAL, + "%s: epping_ctx is NULL", __func__); + return; + } + /* EPPING_TODO: do we need wow_nack? */ + g_epping_ctx->wow_nack = wow_nack; +} + +/** + * epping_update_ol_config - API to update ol configuration parameters + * + * Return: void + */ +static void epping_update_ol_config(void) +{ + struct ol_config_info cfg; + struct ol_context *ol_ctx = cds_get_context(QDF_MODULE_ID_BMI); + + if (!ol_ctx) + return; + + cfg.enable_self_recovery = 0; + cfg.enable_uart_print = 0; + cfg.enable_fw_log = 0; + cfg.enable_ramdump_collection = 0; + cfg.enable_lpass_support = 0; + + ol_init_ini_config(ol_ctx, &cfg); +} +/** + * epping_enable(): End point ping driver enable Function + * + * This is the driver enable function - called by HDD to enable + * epping module + * + * return - 0 : success, negative: error + */ +int epping_enable(struct device *parent_dev) +{ + int ret = 0; + epping_context_t *pEpping_ctx = NULL; + cds_context_type *p_cds_context = NULL; + qdf_device_t qdf_ctx; + HTC_INIT_INFO htcInfo; + struct hif_opaque_softc *scn; + tSirMacAddr adapter_macAddr; + struct hif_target_info *tgt_info; + struct ol_context *ol_ctx; + + EPPING_LOG(QDF_TRACE_LEVEL_INFO_HIGH, "%s: Enter", __func__); + + p_cds_context = cds_get_global_context(); + + if (p_cds_context == NULL) { + EPPING_LOG(QDF_TRACE_LEVEL_FATAL, + "%s: Failed cds_get_global_context", __func__); + ret = -1; + return ret; + } + + pEpping_ctx = g_epping_ctx; + if (pEpping_ctx == NULL) { + EPPING_LOG(QDF_TRACE_LEVEL_FATAL, + "%s: Failed to get pEpping_ctx", __func__); + ret = -1; + return ret; + } + pEpping_ctx->parent_dev = (void *)parent_dev; + epping_get_dummy_mac_addr(adapter_macAddr); + + /* Initialize the timer module */ + qdf_timer_module_init(); + + scn = cds_get_context(QDF_MODULE_ID_HIF); + if (!scn) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_FATAL, + "%s: scn is null!", __func__); + return -1; + } + + tgt_info = hif_get_target_info_handle(scn); + + /* store target type and target version info in hdd ctx */ + pEpping_ctx->target_type = tgt_info->target_type; + + ol_ctx = cds_get_context(QDF_MODULE_ID_BMI); + if (!ol_ctx) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_FATAL, + "%s: ol_ctx is NULL", __func__); + return A_ERROR; + } + + epping_update_ol_config(); +#ifndef FEATURE_BMI_2 + /* Initialize BMI and Download firmware */ + if (bmi_download_firmware(ol_ctx)) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_FATAL, + "%s: BMI failed to download target", __func__); + bmi_cleanup(ol_ctx); + return -1; + } +#endif + EPPING_LOG(QDF_TRACE_LEVEL_INFO_HIGH, + "%s: bmi_download_firmware done", __func__); + + htcInfo.pContext = ol_ctx; + htcInfo.TargetFailure = ol_target_failure; + htcInfo.TargetSendSuspendComplete = epping_target_suspend_acknowledge; + qdf_ctx = cds_get_context(QDF_MODULE_ID_QDF_DEVICE); + + /* Create HTC */ + p_cds_context->htc_ctx = htc_create(scn, &htcInfo, qdf_ctx, + cds_get_conparam()); + if (!p_cds_context->htc_ctx) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_FATAL, + "%s: Failed to Create HTC", __func__); + bmi_cleanup(ol_ctx); + return -1; + } + pEpping_ctx->HTCHandle = + cds_get_context(QDF_MODULE_ID_HTC); + if (pEpping_ctx->HTCHandle == NULL) { + EPPING_LOG(QDF_TRACE_LEVEL_FATAL, + "%s: HTCHandle is NULL", __func__); + return -1; + } + + if (bmi_done(ol_ctx)) { + EPPING_LOG(QDF_TRACE_LEVEL_FATAL, + "%s: Failed to complete BMI phase", __func__); + goto error_end; + } + + /* start HIF */ + if (htc_wait_target(pEpping_ctx->HTCHandle) != A_OK) { + EPPING_LOG(QDF_TRACE_LEVEL_FATAL, + "%s: htc_wait_target error", __func__); + goto error_end; + } + EPPING_LOG(QDF_TRACE_LEVEL_INFO_HIGH, "%s: HTC ready", __func__); + + ret = epping_connect_service(pEpping_ctx); + if (ret != 0) { + EPPING_LOG(QDF_TRACE_LEVEL_FATAL, + "%s: htc_wait_targetdone", __func__); + goto error_end; + } + if (htc_start(pEpping_ctx->HTCHandle) != A_OK) { + goto error_end; + } + EPPING_LOG(QDF_TRACE_LEVEL_INFO_HIGH, "%s: HTC started", __func__); + + /* init the tx cookie resource */ + ret = epping_cookie_init(pEpping_ctx); + if (ret == 0) { + pEpping_ctx->epping_adapter = epping_add_adapter(pEpping_ctx, + adapter_macAddr, + QDF_STA_MODE); + } + if (ret < 0 || pEpping_ctx->epping_adapter == NULL) { + EPPING_LOG(QDF_TRACE_LEVEL_FATAL, + "%s: epping_add_adaptererror error", __func__); + htc_stop(pEpping_ctx->HTCHandle); + epping_cookie_cleanup(pEpping_ctx); + goto error_end; + } + + EPPING_LOG(QDF_TRACE_LEVEL_INFO_HIGH, "%s: Exit", __func__); + return ret; + +error_end: + htc_destroy(p_cds_context->htc_ctx); + p_cds_context->htc_ctx = NULL; + bmi_cleanup(ol_ctx); + return -1; +} diff --git a/drivers/staging/qcacld-3.0/core/utils/epping/src/epping_rx.c b/drivers/staging/qcacld-3.0/core/utils/epping/src/epping_rx.c new file mode 100644 index 0000000000000000000000000000000000000000..81e74d3daba1e042bbd7970f2e6e1a0be79bf5d6 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/utils/epping/src/epping_rx.c @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2014-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/*======================================================================== + + \file epping_main.c + + \brief WLAN End Point Ping test tool implementation + + ========================================================================*/ + +/*-------------------------------------------------------------------------- + Include Files + ------------------------------------------------------------------------*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "epping_main.h" +#include "epping_internal.h" +#include "epping_test.h" +#include + +#define AR6000_MAX_RX_BUFFERS 16 +#define AR6000_BUFFER_SIZE 1664 +#define AR6000_MIN_HEAD_ROOM 64 + +static bool enb_rx_dump; + +#ifdef HIF_SDIO +void epping_refill(void *ctx, HTC_ENDPOINT_ID Endpoint) +{ + epping_context_t *pEpping_ctx = (epping_context_t *) ctx; + void *osBuf; + int RxBuffers; + int buffersToRefill; + HTC_PACKET *pPacket; + HTC_PACKET_QUEUE queue; + + buffersToRefill = (int)AR6000_MAX_RX_BUFFERS - + htc_get_num_recv_buffers(pEpping_ctx->HTCHandle, Endpoint); + + if (buffersToRefill <= 0) { + /* fast return, nothing to fill */ + return; + } + + INIT_HTC_PACKET_QUEUE(&queue); + + EPPING_LOG(QDF_TRACE_LEVEL_INFO, + "%s: providing htc with %d buffers at eid=%d\n", + __func__, buffersToRefill, Endpoint); + + for (RxBuffers = 0; RxBuffers < buffersToRefill; RxBuffers++) { + osBuf = qdf_nbuf_alloc(NULL, AR6000_BUFFER_SIZE, + AR6000_MIN_HEAD_ROOM, 4, false); + if (NULL == osBuf) { + break; + } + /* the HTC packet wrapper is at the head of the reserved area + * in the skb */ + pPacket = (HTC_PACKET *) (A_NETBUF_HEAD(osBuf)); + /* set re-fill info */ + SET_HTC_PACKET_INFO_RX_REFILL(pPacket, osBuf, + qdf_nbuf_data(osBuf), + AR6000_BUFFER_SIZE, Endpoint); + SET_HTC_PACKET_NET_BUF_CONTEXT(pPacket, osBuf); + /* add to queue */ + HTC_PACKET_ENQUEUE(&queue, pPacket); + } + + if (!HTC_QUEUE_EMPTY(&queue)) { + /* add packets */ + htc_add_receive_pkt_multiple(pEpping_ctx->HTCHandle, &queue); + } +} +#endif /* HIF_SDIO */ + +void epping_rx(void *ctx, HTC_PACKET *pPacket) +{ + epping_context_t *pEpping_ctx = (epping_context_t *) ctx; + epping_adapter_t *pAdapter = pEpping_ctx->epping_adapter; + struct net_device *dev = pAdapter->dev; + A_STATUS status = pPacket->Status; + HTC_ENDPOINT_ID eid = pPacket->Endpoint; + struct sk_buff *pktSkb = (struct sk_buff *)pPacket->pPktContext; + + EPPING_LOG(QDF_TRACE_LEVEL_INFO, + "%s: pAdapter = 0x%p eid=%d, skb=0x%p, data=0x%p, len=0x%x status:%d", + __func__, pAdapter, eid, pktSkb, pPacket->pBuffer, + pPacket->ActualLength, status); + + if (status != A_OK) { + if (status != A_ECANCELED) { + printk("%s: RX ERR (%d)\n", __func__, status); + } + qdf_nbuf_free(pktSkb); + return; + } + + /* deliver to up layer */ + if (pktSkb) { + if (EPPING_ALIGNMENT_PAD > 0) { + A_NETBUF_PULL(pktSkb, EPPING_ALIGNMENT_PAD); + } + if (enb_rx_dump) + epping_hex_dump((void *)qdf_nbuf_data(pktSkb), + pktSkb->len, __func__); + pktSkb->dev = dev; + if ((pktSkb->dev->flags & IFF_UP) == IFF_UP) { + pktSkb->protocol = eth_type_trans(pktSkb, pktSkb->dev); + ++pAdapter->stats.rx_packets; + pAdapter->stats.rx_bytes += pktSkb->len; + qdf_net_buf_debug_release_skb(pktSkb); + if (hdd_napi_enabled(HDD_NAPI_ANY)) + netif_receive_skb(pktSkb); + else + netif_rx_ni(pktSkb); + if ((pAdapter->stats.rx_packets % + EPPING_STATS_LOG_COUNT) == 0) { + EPPING_LOG(QDF_TRACE_LEVEL_FATAL, + "%s: total_rx_pkts = %lu", + __func__, + pAdapter->stats.rx_packets); + } + } else { + ++pAdapter->stats.rx_dropped; + qdf_nbuf_free(pktSkb); + } + } +} diff --git a/drivers/staging/qcacld-3.0/core/utils/epping/src/epping_tx.c b/drivers/staging/qcacld-3.0/core/utils/epping/src/epping_tx.c new file mode 100644 index 0000000000000000000000000000000000000000..5cfe3d1a57deb4cfbde775e814ed083db06408f6 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/utils/epping/src/epping_tx.c @@ -0,0 +1,405 @@ +/* + * Copyright (c) 2014-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/*======================================================================== + + \file epping_main.c + + \brief WLAN End Point Ping test tool implementation + + ========================================================================*/ + +/*-------------------------------------------------------------------------- + Include Files + ------------------------------------------------------------------------*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "epping_main.h" +#include "epping_internal.h" +#include "epping_test.h" + +#define TX_RETRY_TIMEOUT_IN_MS 1 + +static bool enb_tx_dump; + +void epping_tx_dup_pkt(epping_adapter_t *pAdapter, + HTC_ENDPOINT_ID eid, qdf_nbuf_t skb) +{ + struct epping_cookie *cookie = NULL; + int skb_len, ret; + qdf_nbuf_t new_skb; + + cookie = epping_alloc_cookie(pAdapter->pEpping_ctx); + if (cookie == NULL) { + EPPING_LOG(QDF_TRACE_LEVEL_FATAL, + "%s: epping_alloc_cookie returns no resource\n", + __func__); + return; + } + new_skb = qdf_nbuf_copy(skb); + if (!new_skb) { + EPPING_LOG(QDF_TRACE_LEVEL_FATAL, + "%s: qdf_nbuf_copy returns no resource\n", __func__); + epping_free_cookie(pAdapter->pEpping_ctx, cookie); + return; + } + SET_HTC_PACKET_INFO_TX(&cookie->HtcPkt, + cookie, qdf_nbuf_data(skb), + qdf_nbuf_len(new_skb), eid, 0); + SET_HTC_PACKET_NET_BUF_CONTEXT(&cookie->HtcPkt, new_skb); + skb_len = (int)qdf_nbuf_len(new_skb); + /* send the packet */ + ret = htc_send_pkt(pAdapter->pEpping_ctx->HTCHandle, &cookie->HtcPkt); + if (ret != A_OK) { + EPPING_LOG(QDF_TRACE_LEVEL_FATAL, + "%s: htc_send_pkt failed, ret = %d\n", __func__, ret); + epping_free_cookie(pAdapter->pEpping_ctx, cookie); + qdf_nbuf_free(new_skb); + return; + } + pAdapter->stats.tx_bytes += skb_len; + ++pAdapter->stats.tx_packets; + if (((pAdapter->stats.tx_packets + + pAdapter->stats.tx_dropped) % EPPING_STATS_LOG_COUNT) == 0 && + (pAdapter->stats.tx_packets || pAdapter->stats.tx_dropped)) { + epping_log_stats(pAdapter, __func__); + } +} + +static int epping_tx_send_int(qdf_nbuf_t skb, epping_adapter_t *pAdapter) +{ + EPPING_HEADER *eppingHdr = (EPPING_HEADER *) qdf_nbuf_data(skb); + HTC_ENDPOINT_ID eid = ENDPOINT_UNUSED; + struct epping_cookie *cookie = NULL; + A_UINT8 ac = 0; + A_STATUS ret = A_OK; + int skb_len; + EPPING_HEADER tmpHdr = *eppingHdr; + + /* allocate resource for this packet */ + cookie = epping_alloc_cookie(pAdapter->pEpping_ctx); + /* no resource */ + if (cookie == NULL) { + EPPING_LOG(QDF_TRACE_LEVEL_FATAL, + "%s: epping_alloc_cookie returns no resource\n", + __func__); + return -1; + } + + if (enb_tx_dump) + epping_hex_dump((void *)eppingHdr, skb->len, __func__); + /* + * a quirk of linux, the payload of the frame is 32-bit aligned and thus + * the addition of the HTC header will mis-align the start of the HTC + * frame, so we add some padding which will be stripped off in the target + */ + if (EPPING_ALIGNMENT_PAD > 0) { + A_NETBUF_PUSH(skb, EPPING_ALIGNMENT_PAD); + } + /* prepare ep/HTC information */ + ac = eppingHdr->StreamNo_h; + eid = pAdapter->pEpping_ctx->EppingEndpoint[ac]; + if (eid < 0 || eid >= EPPING_MAX_NUM_EPIDS) { + EPPING_LOG(QDF_TRACE_LEVEL_FATAL, + "%s: invalid eid = %d, ac = %d\n", __func__, eid, + ac); + return -1; + } + if (tmpHdr.Cmd_h == EPPING_CMD_RESET_RECV_CNT || + tmpHdr.Cmd_h == EPPING_CMD_CONT_RX_START) { + epping_set_kperf_flag(pAdapter, eid, tmpHdr.CmdBuffer_t[0]); + } + SET_HTC_PACKET_INFO_TX(&cookie->HtcPkt, + cookie, qdf_nbuf_data(skb), qdf_nbuf_len(skb), + eid, 0); + SET_HTC_PACKET_NET_BUF_CONTEXT(&cookie->HtcPkt, skb); + skb_len = skb->len; + /* send the packet */ + ret = htc_send_pkt(pAdapter->pEpping_ctx->HTCHandle, &cookie->HtcPkt); + epping_log_packet(pAdapter, &tmpHdr, ret, __func__); + if (ret != A_OK) { + EPPING_LOG(QDF_TRACE_LEVEL_FATAL, + "%s: htc_send_pkt failed, status = %d\n", __func__, + ret); + epping_free_cookie(pAdapter->pEpping_ctx, cookie); + return -1; + } + pAdapter->stats.tx_bytes += skb_len; + ++pAdapter->stats.tx_packets; + if (((pAdapter->stats.tx_packets + + pAdapter->stats.tx_dropped) % EPPING_STATS_LOG_COUNT) == 0 && + (pAdapter->stats.tx_packets || pAdapter->stats.tx_dropped)) { + epping_log_stats(pAdapter, __func__); + } + + return 0; +} + +void epping_tx_timer_expire(epping_adapter_t *pAdapter) +{ + qdf_nbuf_t nodrop_skb; + + EPPING_LOG(QDF_TRACE_LEVEL_INFO, "%s: queue len: %d\n", __func__, + qdf_nbuf_queue_len(&pAdapter->nodrop_queue)); + + if (!qdf_nbuf_queue_len(&pAdapter->nodrop_queue)) { + /* nodrop queue is empty so no need to arm timer */ + pAdapter->epping_timer_state = EPPING_TX_TIMER_STOPPED; + return; + } + + /* try to flush nodrop queue */ + while ((nodrop_skb = qdf_nbuf_queue_remove(&pAdapter->nodrop_queue))) { + htc_set_nodrop_pkt(pAdapter->pEpping_ctx->HTCHandle, true); + if (epping_tx_send_int(nodrop_skb, pAdapter)) { + EPPING_LOG(QDF_TRACE_LEVEL_FATAL, + "%s: nodrop: %p xmit fail in timer\n", + __func__, nodrop_skb); + /* fail to xmit so put the nodrop packet to the nodrop queue */ + qdf_nbuf_queue_insert_head(&pAdapter->nodrop_queue, + nodrop_skb); + break; + } else { + htc_set_nodrop_pkt(pAdapter->pEpping_ctx->HTCHandle, false); + EPPING_LOG(QDF_TRACE_LEVEL_INFO, + "%s: nodrop: %p xmit ok in timer\n", + __func__, nodrop_skb); + } + } + + /* if nodrop queue is not empty, continue to arm timer */ + if (nodrop_skb) { + qdf_spin_lock_bh(&pAdapter->data_lock); + /* if nodrop queue is not empty, continue to arm timer */ + if (pAdapter->epping_timer_state != EPPING_TX_TIMER_RUNNING) { + pAdapter->epping_timer_state = EPPING_TX_TIMER_RUNNING; + qdf_timer_mod(&pAdapter->epping_timer, + TX_RETRY_TIMEOUT_IN_MS); + } + qdf_spin_unlock_bh(&pAdapter->data_lock); + } else { + pAdapter->epping_timer_state = EPPING_TX_TIMER_STOPPED; + } +} + +int epping_tx_send(qdf_nbuf_t skb, epping_adapter_t *pAdapter) +{ + qdf_nbuf_t nodrop_skb; + EPPING_HEADER *eppingHdr; + A_UINT8 ac = 0; + + eppingHdr = (EPPING_HEADER *) qdf_nbuf_data(skb); + + if (!IS_EPPING_PACKET(eppingHdr)) { + EPPING_LOG(QDF_TRACE_LEVEL_FATAL, + "%s: Recived non endpoint ping packets\n", __func__); + /* no packet to send, cleanup */ + qdf_nbuf_free(skb); + return -ENOMEM; + } + + /* the stream ID is mapped to an access class */ + ac = eppingHdr->StreamNo_h; + /* hard coded two ep ids */ + if (ac != 0 && ac != 1) { + EPPING_LOG(QDF_TRACE_LEVEL_FATAL, + "%s: ac %d is not mapped to mboxping service\n", + __func__, ac); + qdf_nbuf_free(skb); + return -ENOMEM; + } + + /* + * some EPPING packets cannot be dropped no matter what access class + * it was sent on. A special care has been taken: + * 1. when there is no TX resource, queue the control packets to + * a special queue + * 2. when there is TX resource, send the queued control packets first + * and then other packets + * 3. a timer launches to check if there is queued control packets and + * flush them + */ + + /* check the nodrop queue first */ + while ((nodrop_skb = qdf_nbuf_queue_remove(&pAdapter->nodrop_queue))) { + htc_set_nodrop_pkt(pAdapter->pEpping_ctx->HTCHandle, true); + if (epping_tx_send_int(nodrop_skb, pAdapter)) { + EPPING_LOG(QDF_TRACE_LEVEL_FATAL, + "%s: nodrop: %p xmit fail\n", __func__, + nodrop_skb); + /* fail to xmit so put the nodrop packet to the nodrop queue */ + qdf_nbuf_queue_insert_head(&pAdapter->nodrop_queue, + nodrop_skb); + /* no cookie so free the current skb */ + goto tx_fail; + } else { + htc_set_nodrop_pkt(pAdapter->pEpping_ctx->HTCHandle, false); + EPPING_LOG(QDF_TRACE_LEVEL_INFO, + "%s: nodrop: %p xmit ok\n", __func__, + nodrop_skb); + } + } + + /* send the original packet */ + if (epping_tx_send_int(skb, pAdapter)) + goto tx_fail; + + return 0; + +tx_fail: + if (!IS_EPING_PACKET_NO_DROP(eppingHdr)) { + /* allow to drop the skb so drop it */ + qdf_nbuf_free(skb); + ++pAdapter->stats.tx_dropped; + EPPING_LOG(QDF_TRACE_LEVEL_FATAL, + "%s: Tx skb %p dropped, stats.tx_dropped = %ld\n", + __func__, skb, pAdapter->stats.tx_dropped); + return -ENOMEM; + } else { + EPPING_LOG(QDF_TRACE_LEVEL_FATAL, + "%s: nodrop: %p queued\n", __func__, skb); + qdf_nbuf_queue_add(&pAdapter->nodrop_queue, skb); + qdf_spin_lock_bh(&pAdapter->data_lock); + if (pAdapter->epping_timer_state != EPPING_TX_TIMER_RUNNING) { + pAdapter->epping_timer_state = EPPING_TX_TIMER_RUNNING; + qdf_timer_mod(&pAdapter->epping_timer, + TX_RETRY_TIMEOUT_IN_MS); + } + qdf_spin_unlock_bh(&pAdapter->data_lock); + } + + return 0; +} + +#ifdef HIF_SDIO +HTC_SEND_FULL_ACTION epping_tx_queue_full(void *Context, HTC_PACKET *pPacket) +{ + /* + * Call netif_stop_queue frequently will impact the mboxping tx t-put. + * Return HTC_SEND_FULL_KEEP directly in epping_tx_queue_full to avoid. + */ + return HTC_SEND_FULL_KEEP; +} +#endif /* HIF_SDIO */ +void epping_tx_complete_multiple(void *ctx, HTC_PACKET_QUEUE *pPacketQueue) +{ + epping_context_t *pEpping_ctx = (epping_context_t *) ctx; + epping_adapter_t *pAdapter = pEpping_ctx->epping_adapter; + struct net_device *dev = pAdapter->dev; + A_STATUS status; + HTC_ENDPOINT_ID eid; + qdf_nbuf_t pktSkb; + struct epping_cookie *cookie; + A_BOOL flushing = false; + qdf_nbuf_queue_t skb_queue; + HTC_PACKET *htc_pkt; + + qdf_nbuf_queue_init(&skb_queue); + + qdf_spin_lock_bh(&pAdapter->data_lock); + + while (!HTC_QUEUE_EMPTY(pPacketQueue)) { + htc_pkt = htc_packet_dequeue(pPacketQueue); + if (htc_pkt == NULL) + break; + status = htc_pkt->Status; + eid = htc_pkt->Endpoint; + pktSkb = GET_HTC_PACKET_NET_BUF_CONTEXT(htc_pkt); + cookie = htc_pkt->pPktContext; + + if (!pktSkb) { + EPPING_LOG(QDF_TRACE_LEVEL_ERROR, + "%s: NULL skb from hc packet", __func__); + QDF_BUG(0); + } else { + if (htc_pkt->pBuffer != qdf_nbuf_data(pktSkb)) { + EPPING_LOG(QDF_TRACE_LEVEL_ERROR, + "%s: htc_pkt buffer not equal to skb->data", + __func__); + QDF_BUG(0); + } + /* add this to the list, use faster non-lock API */ + qdf_nbuf_queue_add(&skb_queue, pktSkb); + + if (A_SUCCESS(status)) { + if (htc_pkt->ActualLength != + qdf_nbuf_len(pktSkb)) { + EPPING_LOG(QDF_TRACE_LEVEL_ERROR, + "%s: htc_pkt length not equal to skb->len", + __func__); + QDF_BUG(0); + } + } + } + + EPPING_LOG(QDF_TRACE_LEVEL_INFO, + "%s skb=%p data=%p len=0x%x eid=%d ", + __func__, pktSkb, htc_pkt->pBuffer, + htc_pkt->ActualLength, eid); + + if (A_FAILED(status)) { + if (status == A_ECANCELED) { + /* a packet was flushed */ + flushing = true; + } + if (status != A_NO_RESOURCE) { + printk("%s() -TX ERROR, status: 0x%x\n", + __func__, status); + } + } else { + EPPING_LOG(QDF_TRACE_LEVEL_INFO, "%s: OK\n", __func__); + flushing = false; + } + + epping_free_cookie(pAdapter->pEpping_ctx, cookie); + } + + qdf_spin_unlock_bh(&pAdapter->data_lock); + + /* free all skbs in our local list */ + while (qdf_nbuf_queue_len(&skb_queue)) { + /* use non-lock version */ + pktSkb = qdf_nbuf_queue_remove(&skb_queue); + if (pktSkb == NULL) + break; + qdf_nbuf_tx_free(pktSkb, QDF_NBUF_PKT_ERROR); + pEpping_ctx->total_tx_acks++; + } + + if (!flushing) { + netif_wake_queue(dev); + } +} diff --git a/drivers/staging/qcacld-3.0/core/utils/epping/src/epping_txrx.c b/drivers/staging/qcacld-3.0/core/utils/epping/src/epping_txrx.c new file mode 100644 index 0000000000000000000000000000000000000000..43cd77713df8e7e2e17dfebfeae4befaa9e0a22d --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/utils/epping/src/epping_txrx.c @@ -0,0 +1,470 @@ +/* + * Copyright (c) 2014-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/*======================================================================== + + \file epping_main.c + + \brief WLAN End Point Ping test tool implementation + + ========================================================================*/ + +/*-------------------------------------------------------------------------- + Include Files + ------------------------------------------------------------------------*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "epping_main.h" +#include "epping_internal.h" + +static int epping_start_adapter(epping_adapter_t *pAdapter); +static void epping_stop_adapter(epping_adapter_t *pAdapter); + +static void epping_timer_expire(void *data) +{ + struct net_device *dev = (struct net_device *)data; + epping_adapter_t *pAdapter; + + if (dev == NULL) { + EPPING_LOG(QDF_TRACE_LEVEL_FATAL, + "%s: netdev = NULL", __func__); + return; + } + + pAdapter = netdev_priv(dev); + if (pAdapter == NULL) { + EPPING_LOG(QDF_TRACE_LEVEL_FATAL, + "%s: adapter = NULL", __func__); + return; + } + pAdapter->epping_timer_state = EPPING_TX_TIMER_STOPPED; + epping_tx_timer_expire(pAdapter); +} + +static int epping_ndev_open(struct net_device *dev) +{ + epping_adapter_t *pAdapter; + int ret = 0; + + pAdapter = netdev_priv(dev); + epping_start_adapter(pAdapter); + return ret; +} + +static int epping_ndev_stop(struct net_device *dev) +{ + epping_adapter_t *pAdapter; + int ret = 0; + + pAdapter = netdev_priv(dev); + if (NULL == pAdapter) { + EPPING_LOG(QDF_TRACE_LEVEL_FATAL, + "%s: EPPING adapter context is Null", __func__); + ret = -ENODEV; + goto end; + } + epping_stop_adapter(pAdapter); +end: + return ret; +} + +static void epping_ndev_uninit(struct net_device *dev) +{ + epping_adapter_t *pAdapter; + + pAdapter = netdev_priv(dev); + if (NULL == pAdapter) { + EPPING_LOG(QDF_TRACE_LEVEL_FATAL, + "%s: EPPING adapter context is Null", __func__); + goto end; + } + epping_stop_adapter(pAdapter); +end: + return; +} + +static void epping_tx_queue_timeout(struct net_device *dev) +{ + epping_adapter_t *pAdapter; + + pAdapter = netdev_priv(dev); + if (NULL == pAdapter) { + EPPING_LOG(QDF_TRACE_LEVEL_FATAL, + "%s: EPPING adapter context is Null", __func__); + goto end; + } + + EPPING_LOG(QDF_TRACE_LEVEL_ERROR, + "%s: Transmission timeout occurred, pAdapter->started= %d", + __func__, pAdapter->started); + + /* Getting here implies we disabled the TX queues + * for too long. Since this is epping + * (not because of disassociation or low resource scenarios), + * try to restart the queue + */ + if (pAdapter->started) + netif_wake_queue(dev); +end: + return; + +} + +static int epping_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + epping_adapter_t *pAdapter; + int ret = 0; + + pAdapter = netdev_priv(dev); + if (NULL == pAdapter) { + EPPING_LOG(QDF_TRACE_LEVEL_FATAL, + "%s: EPPING adapter context is Null", __func__); + ret = -ENODEV; + goto end; + } + ret = epping_tx_send(skb, pAdapter); +end: + return ret; +} + +static struct net_device_stats *epping_get_stats(struct net_device *dev) +{ + epping_adapter_t *pAdapter = netdev_priv(dev); + + if (NULL == pAdapter) { + EPPING_LOG(QDF_TRACE_LEVEL_ERROR, "%s: pAdapter = NULL", + __func__); + return NULL; + } + + return &pAdapter->stats; +} + +static int epping_ndev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) +{ + epping_adapter_t *pAdapter; + int ret = 0; + + pAdapter = netdev_priv(dev); + if (NULL == pAdapter) { + EPPING_LOG(QDF_TRACE_LEVEL_FATAL, + "%s: EPPING adapter context is Null", __func__); + ret = -ENODEV; + goto end; + } + if (dev != pAdapter->dev) { + EPPING_LOG(QDF_TRACE_LEVEL_FATAL, + "%s: HDD adapter/dev inconsistency", __func__); + ret = -ENODEV; + goto end; + } + + if ((!ifr) || (!ifr->ifr_data)) { + ret = -EINVAL; + goto end; + } + + switch (cmd) { + case (SIOCDEVPRIVATE + 1): + EPPING_LOG(QDF_TRACE_LEVEL_ERROR, + "%s: do not support ioctl %d (SIOCDEVPRIVATE + 1)", + __func__, cmd); + break; + default: + EPPING_LOG(QDF_TRACE_LEVEL_ERROR, "%s: unknown ioctl %d", + __func__, cmd); + ret = -EINVAL; + break; + } + +end: + return ret; +} + +static int epping_set_mac_address(struct net_device *dev, void *addr) +{ + epping_adapter_t *pAdapter = netdev_priv(dev); + struct sockaddr *psta_mac_addr = addr; + qdf_mem_copy(&pAdapter->macAddressCurrent, + psta_mac_addr->sa_data, ETH_ALEN); + qdf_mem_copy(dev->dev_addr, psta_mac_addr->sa_data, ETH_ALEN); + return 0; +} + +static void epping_stop_adapter(epping_adapter_t *pAdapter) +{ + qdf_device_t qdf_ctx = cds_get_context(QDF_MODULE_ID_QDF_DEVICE); + + if (!qdf_ctx) { + EPPING_LOG(QDF_TRACE_LEVEL_FATAL, + "%s: qdf_ctx is NULL\n", __func__); + return; + } + + if (pAdapter && pAdapter->started) { + EPPING_LOG(LOG1, FL("Disabling queues")); + netif_tx_disable(pAdapter->dev); + netif_carrier_off(pAdapter->dev); + pAdapter->started = false; + pld_request_bus_bandwidth(qdf_ctx->dev, + PLD_BUS_WIDTH_LOW); + } +} + +static int epping_start_adapter(epping_adapter_t *pAdapter) +{ + qdf_device_t qdf_ctx = cds_get_context(QDF_MODULE_ID_QDF_DEVICE); + + if (!qdf_ctx) { + EPPING_LOG(QDF_TRACE_LEVEL_FATAL, + "%s: qdf_ctx is NULL", __func__); + return -EINVAL; + } + + if (!pAdapter) { + EPPING_LOG(QDF_TRACE_LEVEL_FATAL, + "%s: pAdapter= NULL\n", __func__); + return -EINVAL; + } + if (!pAdapter->started) { + pld_request_bus_bandwidth(qdf_ctx->dev, + PLD_BUS_WIDTH_HIGH); + netif_carrier_on(pAdapter->dev); + EPPING_LOG(LOG1, FL("Enabling queues")); + netif_tx_start_all_queues(pAdapter->dev); + pAdapter->started = true; + } else { + EPPING_LOG(QDF_TRACE_LEVEL_WARN, + "%s: pAdapter %p already started\n", __func__, + pAdapter); + } + return 0; +} + +static int epping_register_adapter(epping_adapter_t *pAdapter) +{ + int ret = 0; + + ret = register_netdev(pAdapter->dev); + if (ret != 0) { + EPPING_LOG(QDF_TRACE_LEVEL_FATAL, + "%s: unable to register device\n", + pAdapter->dev->name); + } else { + pAdapter->registered = true; + } + return ret; +} + +static void epping_unregister_adapter(epping_adapter_t *pAdapter) +{ + if (pAdapter) { + epping_stop_adapter(pAdapter); + if (pAdapter->registered) { + unregister_netdev(pAdapter->dev); + pAdapter->registered = false; + } + } else { + EPPING_LOG(QDF_TRACE_LEVEL_FATAL, + "%s: pAdapter = NULL, unable to unregister device\n", + __func__); + } +} + +void epping_destroy_adapter(epping_adapter_t *pAdapter) +{ + struct net_device *dev = NULL; + epping_context_t *pEpping_ctx; + + if (!pAdapter || !pAdapter->pEpping_ctx) { + EPPING_LOG(QDF_TRACE_LEVEL_FATAL, + "%s: pAdapter = NULL\n", __func__); + return; + } + + dev = pAdapter->dev; + pEpping_ctx = pAdapter->pEpping_ctx; + epping_unregister_adapter(pAdapter); + + qdf_spinlock_destroy(&pAdapter->data_lock); + qdf_timer_free(&pAdapter->epping_timer); + pAdapter->epping_timer_state = EPPING_TX_TIMER_STOPPED; + + while (qdf_nbuf_queue_len(&pAdapter->nodrop_queue)) { + qdf_nbuf_t tmp_nbuf = NULL; + tmp_nbuf = qdf_nbuf_queue_remove(&pAdapter->nodrop_queue); + if (tmp_nbuf) + qdf_nbuf_free(tmp_nbuf); + } + + free_netdev(dev); + if (!pEpping_ctx) + EPPING_LOG(QDF_TRACE_LEVEL_FATAL, + "%s: pEpping_ctx = NULL\n", __func__); + else + pEpping_ctx->epping_adapter = NULL; +} + +static struct net_device_ops epping_drv_ops = { + .ndo_open = epping_ndev_open, + .ndo_stop = epping_ndev_stop, + .ndo_uninit = epping_ndev_uninit, + .ndo_start_xmit = epping_hard_start_xmit, + .ndo_tx_timeout = epping_tx_queue_timeout, + .ndo_get_stats = epping_get_stats, + .ndo_do_ioctl = epping_ndev_ioctl, + .ndo_set_mac_address = epping_set_mac_address, + .ndo_select_queue = NULL, +}; + +#define EPPING_TX_QUEUE_MAX_LEN 128 /* need to be power of 2 */ + +epping_adapter_t *epping_add_adapter(epping_context_t *pEpping_ctx, + tSirMacAddr macAddr, + enum tQDF_ADAPTER_MODE device_mode) +{ + struct net_device *dev; + epping_adapter_t *pAdapter; + + dev = alloc_netdev(sizeof(epping_adapter_t), "wifi%d", +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 17, 0)) + NET_NAME_UNKNOWN, +#endif + ether_setup); + if (dev == NULL) { + EPPING_LOG(QDF_TRACE_LEVEL_FATAL, + "%s: Cannot allocate epping_adapter_t\n", __func__); + return NULL; + } + + pAdapter = netdev_priv(dev); + qdf_mem_zero(pAdapter, sizeof(*pAdapter)); + pAdapter->dev = dev; + pAdapter->pEpping_ctx = pEpping_ctx; + pAdapter->device_mode = device_mode; /* station, SAP, etc */ + qdf_mem_copy(dev->dev_addr, (void *)macAddr, sizeof(tSirMacAddr)); + qdf_mem_copy(pAdapter->macAddressCurrent.bytes, + macAddr, sizeof(tSirMacAddr)); + qdf_spinlock_create(&pAdapter->data_lock); + qdf_nbuf_queue_init(&pAdapter->nodrop_queue); + pAdapter->epping_timer_state = EPPING_TX_TIMER_STOPPED; + qdf_timer_init(epping_get_qdf_ctx(), &pAdapter->epping_timer, + epping_timer_expire, dev, QDF_TIMER_TYPE_SW); + dev->type = ARPHRD_IEEE80211; + dev->netdev_ops = &epping_drv_ops; + dev->watchdog_timeo = 5 * HZ; /* XXX */ + dev->tx_queue_len = EPPING_TXBUF - 1; /* 1 for mgmt frame */ + if (epping_register_adapter(pAdapter) == 0) { + EPPING_LOG(LOG1, FL("Disabling queues")); + netif_tx_disable(dev); + netif_carrier_off(dev); + return pAdapter; + } else { + epping_destroy_adapter(pAdapter); + return NULL; + } +} + +int epping_connect_service(epping_context_t *pEpping_ctx) +{ + int status, i; + HTC_SERVICE_CONNECT_REQ connect; + HTC_SERVICE_CONNECT_RESP response; + + qdf_mem_zero(&connect, sizeof(connect)); + qdf_mem_zero(&response, sizeof(response)); + + /* these fields are the same for all service endpoints */ + connect.EpCallbacks.pContext = pEpping_ctx; + connect.EpCallbacks.EpTxCompleteMultiple = epping_tx_complete_multiple; + connect.EpCallbacks.EpRecv = epping_rx; + /* epping_tx_complete use Multiple version */ + connect.EpCallbacks.EpTxComplete = NULL; + connect.MaxSendQueueDepth = 64; + +#ifdef HIF_SDIO + connect.EpCallbacks.EpRecvRefill = epping_refill; + connect.EpCallbacks.EpSendFull = + epping_tx_queue_full /* ar6000_tx_queue_full */; +#elif defined(HIF_USB) || defined(HIF_PCI) + connect.EpCallbacks.EpRecvRefill = NULL /* provided by HIF */; + connect.EpCallbacks.EpSendFull = NULL /* provided by HIF */; + /* disable flow control for hw flow control */ + connect.ConnectionFlags |= HTC_CONNECT_FLAGS_DISABLE_CREDIT_FLOW_CTRL; +#endif + + /* connect to service */ + connect.service_id = WMI_DATA_BE_SVC; + status = htc_connect_service(pEpping_ctx->HTCHandle, &connect, &response); + if (status != EOK) { + EPPING_LOG(QDF_TRACE_LEVEL_FATAL, + "Failed to connect to Endpoint Ping BE service status:%d\n", + status); + return status; + } else { + EPPING_LOG(QDF_TRACE_LEVEL_FATAL, + "eppingtest BE endpoint:%d\n", response.Endpoint); + } + pEpping_ctx->EppingEndpoint[0] = response.Endpoint; + +#if defined(HIF_PCI) || defined(HIF_USB) + connect.service_id = WMI_DATA_BK_SVC; + status = htc_connect_service(pEpping_ctx->HTCHandle, &connect, &response); + if (status != EOK) { + EPPING_LOG(QDF_TRACE_LEVEL_FATAL, + "Failed to connect to Endpoint Ping BK service status:%d\n", + status); + return status; + } else { + EPPING_LOG(QDF_TRACE_LEVEL_FATAL, + "eppingtest BK endpoint:%d\n", response.Endpoint); + } + pEpping_ctx->EppingEndpoint[1] = response.Endpoint; + /* Since we do not create other two SVC use BK endpoint + * for rest ACs (2, 3) */ + for (i = 2; i < EPPING_MAX_NUM_EPIDS; i++) { + pEpping_ctx->EppingEndpoint[i] = response.Endpoint; + } +#else + /* we only use one endpoint for high latenance bus. + * Map all AC's EPIDs to the same endpoint ID returned by HTC */ + for (i = 0; i < EPPING_MAX_NUM_EPIDS; i++) { + pEpping_ctx->EppingEndpoint[i] = response.Endpoint; + } +#endif + return 0; +} diff --git a/drivers/staging/qcacld-3.0/core/utils/fwlog/dbglog_host.c b/drivers/staging/qcacld-3.0/core/utils/fwlog/dbglog_host.c new file mode 100644 index 0000000000000000000000000000000000000000..11be14cb7faa04d7ce35006abc64a8d7fe5422ec --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/utils/fwlog/dbglog_host.c @@ -0,0 +1,4399 @@ +/* + * Copyright (c) 2013-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* Host Debug log implementation */ + +#include "athdefs.h" +#include "a_types.h" +#include "dbglog_host.h" +#include "wmi.h" +#include "wmi_unified_api.h" +#include "wma.h" +#include "ol_defines.h" +#include +#include "host_diag_core_event.h" +#include "qwlan_version.h" +#include +#include +#include + +#ifdef WLAN_OPEN_SOURCE +#include +#endif /* WLAN_OPEN_SOURCE */ +#include "wmi_unified_priv.h" + +#ifdef MULTI_IF_NAME +#define CLD_DEBUGFS_DIR "cld" MULTI_IF_NAME +#else + +#define CLD_DEBUGFS_DIR "cld" +#endif +#define DEBUGFS_BLOCK_NAME "dbglog_block" + +#define ATH_MODULE_NAME fwlog +#include +#define FWLOG_DEBUG ATH_DEBUG_MAKE_MODULE_MASK(0) + +#ifdef WLAN_DEBUG + +static int get_version; +static int gprint_limiter; +static bool tgt_assert_enable; +static ATH_DEBUG_MASK_DESCRIPTION g_fwlog_debug_description[] = { + {FWLOG_DEBUG, "fwlog"}, +}; + +ATH_DEBUG_INSTANTIATE_MODULE_VAR(fwlog, + "fwlog", + "Firmware Debug Log", + ATH_DEBUG_MASK_DEFAULTS | ATH_DEBUG_INFO | + ATH_DEBUG_ERR, + ATH_DEBUG_DESCRIPTION_COUNT + (g_fwlog_debug_description), + g_fwlog_debug_description); +#endif + +module_dbg_print mod_print[WLAN_MODULE_ID_MAX]; + +A_UINT32 dbglog_process_type = DBGLOG_PROCESS_NET_RAW; + +static const char *dbglog_get_module_str(A_UINT32 module_id) +{ + switch (module_id) { + case WLAN_MODULE_INF: + return "INF"; + case WLAN_MODULE_WMI: + return "WMI"; + case WLAN_MODULE_STA_PWRSAVE: + return "STA PS"; + case WLAN_MODULE_WHAL: + return "WHAL"; + case WLAN_MODULE_COEX: + return "COEX"; + case WLAN_MODULE_ROAM: + return "ROAM"; + case WLAN_MODULE_RESMGR_CHAN_MANAGER: + return "CHANMGR"; + case WLAN_MODULE_RESMGR: + return "RESMGR"; + case WLAN_MODULE_VDEV_MGR: + return "VDEV"; + case WLAN_MODULE_SCAN: + return "SCAN"; + case WLAN_MODULE_RATECTRL: + return "RC"; + case WLAN_MODULE_AP_PWRSAVE: + return "AP PS"; + case WLAN_MODULE_BLOCKACK: + return "BA"; + case WLAN_MODULE_MGMT_TXRX: + return "MGMT"; + case WLAN_MODULE_DATA_TXRX: + return "DATA"; + case WLAN_MODULE_HTT: + return "HTT"; + case WLAN_MODULE_HOST: + return "HOST"; + case WLAN_MODULE_BEACON: + return "BEACON"; + case WLAN_MODULE_OFFLOAD: + return "OFFLOAD"; + case WLAN_MODULE_WAL: + return "WAL"; + case WAL_MODULE_DE: + return "DE"; + case WLAN_MODULE_PCIELP: + return "PCIELP"; + case WLAN_MODULE_RTT: + return "RTT"; + case WLAN_MODULE_DCS: + return "DCS"; + case WLAN_MODULE_CACHEMGR: + return "CACHEMGR"; + case WLAN_MODULE_ANI: + return "ANI"; + case WLAN_MODULE_TEST: + return "TESTPOINT"; + case WLAN_MODULE_STA_SMPS: + return "STA_SMPS"; + case WLAN_MODULE_TDLS: + return "TDLS"; + case WLAN_MODULE_P2P: + return "P2P"; + case WLAN_MODULE_WOW: + return "WoW"; + case WLAN_MODULE_IBSS_PWRSAVE: + return "IBSS PS"; + case WLAN_MODULE_EXTSCAN: + return "ExtScan"; + case WLAN_MODULE_UNIT_TEST: + return "UNIT_TEST"; + case WLAN_MODULE_MLME: + return "MLME"; + case WLAN_MODULE_SUPPL: + return "SUPPLICANT"; + default: + return "UNKNOWN"; + } +} + +char *DBG_MSG_ARR[WLAN_MODULE_ID_MAX][MAX_DBG_MSGS] = { + { + "INF_MSG_START", + "INF_ASSERTION_FAILED", + "INF_TARGET_ID", + "INF_MSG_END" + }, + { + "WMI_DBGID_DEFINITION_START", + "WMI_CMD_RX_XTND_PKT_TOO_SHORT", + "WMI_EXTENDED_CMD_NOT_HANDLED", + "WMI_CMD_RX_PKT_TOO_SHORT", + "WMI_CALLING_WMI_EXTENSION_FN", + "WMI_CMD_NOT_HANDLED", + "WMI_IN_SYNC", + "WMI_TARGET_WMI_SYNC_CMD", + "WMI_SET_SNR_THRESHOLD_PARAMS", + "WMI_SET_RSSI_THRESHOLD_PARAMS", + "WMI_SET_LQ_TRESHOLD_PARAMS", + "WMI_TARGET_CREATE_PSTREAM_CMD", + "WMI_WI_DTM_INUSE", + "WMI_TARGET_DELETE_PSTREAM_CMD", + "WMI_TARGET_IMPLICIT_DELETE_PSTREAM_CMD", + "WMI_TARGET_GET_BIT_RATE_CMD", + "WMI_GET_RATE_MASK_CMD_FIX_RATE_MASK_IS", + "WMI_TARGET_GET_AVAILABLE_CHANNELS_CMD", + "WMI_TARGET_GET_TX_PWR_CMD", + "WMI_FREE_EVBUF_WMIBUF", + "WMI_FREE_EVBUF_DATABUF", + "WMI_FREE_EVBUF_BADFLAG", + "WMI_HTC_RX_ERROR_DATA_PACKET", + "WMI_HTC_RX_SYNC_PAUSING_FOR_MBOX", + "WMI_INCORRECT_WMI_DATA_HDR_DROPPING_PKT", + "WMI_SENDING_READY_EVENT", + "WMI_SETPOWER_MDOE_TO_MAXPERF", + "WMI_SETPOWER_MDOE_TO_REC", + "WMI_BSSINFO_EVENT_FROM", + "WMI_TARGET_GET_STATS_CMD", + "WMI_SENDING_SCAN_COMPLETE_EVENT", + "WMI_SENDING_RSSI_INDB_THRESHOLD_EVENT ", + "WMI_SENDING_RSSI_INDBM_THRESHOLD_EVENT", + "WMI_SENDING_LINK_QUALITY_THRESHOLD_EVENT", + "WMI_SENDING_ERROR_REPORT_EVENT", + "WMI_SENDING_CAC_EVENT", + "WMI_TARGET_GET_ROAM_TABLE_CMD", + "WMI_TARGET_GET_ROAM_DATA_CMD", + "WMI_SENDING_GPIO_INTR_EVENT", + "WMI_SENDING_GPIO_ACK_EVENT", + "WMI_SENDING_GPIO_DATA_EVENT", + "WMI_CMD_RX", + "WMI_CMD_RX_XTND", + "WMI_EVENT_SEND", + "WMI_EVENT_SEND_XTND", + "WMI_CMD_PARAMS_DUMP_START", + "WMI_CMD_PARAMS_DUMP_END", + "WMI_CMD_PARAMS", + "WMI_EVENT_ALLOC_FAILURE", + "WMI_DBGID_DCS_PARAM_CMD", + "WMI_SEND_EVENT_WRONG_TLV", + "WMI_SEND_EVENT_NO_TLV_DEF", + "WMI_DBGID_DEFNITION_END", + }, + { + "PS_STA_DEFINITION_START", + "PS_STA_PM_ARB_REQUEST", + "PS_STA_DELIVER_EVENT", + "PS_STA_PSPOLL_SEQ_DONE", + "PS_STA_COEX_MODE", + "PS_STA_PSPOLL_ALLOW", + "PS_STA_SET_PARAM", + "PS_STA_SPECPOLL_TIMER_STARTED", + "PS_STA_SPECPOLL_TIMER_STOPPED", + }, + { + "WHAL_DBGID_DEFINITION_START", + "WHAL_ERROR_ANI_CONTROL", + "WHAL_ERROR_CHIP_TEST1", + "WHAL_ERROR_CHIP_TEST2", + "WHAL_ERROR_EEPROM_CHECKSUM", + "WHAL_ERROR_EEPROM_MACADDR", + "WHAL_ERROR_INTERRUPT_HIU", + "WHAL_ERROR_KEYCACHE_RESET", + "WHAL_ERROR_KEYCACHE_SET", + "WHAL_ERROR_KEYCACHE_TYPE", + "WHAL_ERROR_KEYCACHE_TKIPENTRY", + "WHAL_ERROR_KEYCACHE_WEPLENGTH", + "WHAL_ERROR_PHY_INVALID_CHANNEL", + "WHAL_ERROR_POWER_AWAKE", + "WHAL_ERROR_POWER_SET", + "WHAL_ERROR_RECV_STOPDMA", + "WHAL_ERROR_RECV_STOPPCU", + "WHAL_ERROR_RESET_CHANNF1", + "WHAL_ERROR_RESET_CHANNF2", + "WHAL_ERROR_RESET_PM", + "WHAL_ERROR_RESET_OFFSETCAL", + "WHAL_ERROR_RESET_RFGRANT", + "WHAL_ERROR_RESET_RXFRAME", + "WHAL_ERROR_RESET_STOPDMA", + "WHAL_ERROR_RESET_ERRID", + "WHAL_ERROR_RESET_ADCDCCAL1", + "WHAL_ERROR_RESET_ADCDCCAL2", + "WHAL_ERROR_RESET_TXIQCAL", + "WHAL_ERROR_RESET_RXIQCAL", + "WHAL_ERROR_RESET_CARRIERLEAK", + "WHAL_ERROR_XMIT_COMPUTE", + "WHAL_ERROR_XMIT_NOQUEUE", + "WHAL_ERROR_XMIT_ACTIVEQUEUE", + "WHAL_ERROR_XMIT_BADTYPE", + "WHAL_ERROR_XMIT_STOPDMA", + "WHAL_ERROR_INTERRUPT_BB_PANIC", + "WHAL_ERROR_PAPRD_MAXGAIN_ABOVE_WINDOW", + "WHAL_ERROR_QCU_HW_PAUSE_MISMATCH", + "WHAL_DBGID_DEFINITION_END", + }, + { + "COEX_DEBUGID_START", + "BTCOEX_DBG_MCI_1", + "BTCOEX_DBG_MCI_2", + "BTCOEX_DBG_MCI_3", + "BTCOEX_DBG_MCI_4", + "BTCOEX_DBG_MCI_5", + "BTCOEX_DBG_MCI_6", + "BTCOEX_DBG_MCI_7", + "BTCOEX_DBG_MCI_8", + "BTCOEX_DBG_MCI_9", + "BTCOEX_DBG_MCI_10", + "COEX_WAL_BTCOEX_INIT", + "COEX_WAL_PAUSE", + "COEX_WAL_RESUME", + "COEX_UPDATE_AFH", + "COEX_HWQ_EMPTY_CB", + "COEX_MCI_TIMER_HANDLER", + "COEX_MCI_RECOVER", + "ERROR_COEX_MCI_ISR", + "ERROR_COEX_MCI_GPM", + "COEX_ProfileType", + "COEX_LinkID", + "COEX_LinkState", + "COEX_LinkRole", + "COEX_LinkRate", + "COEX_VoiceType", + "COEX_TInterval", + "COEX_WRetrx", + "COEX_Attempts", + "COEX_PerformanceState", + "COEX_LinkType", + "COEX_RX_MCI_GPM_VERSION_QUERY", + "COEX_RX_MCI_GPM_VERSION_RESPONSE", + "COEX_RX_MCI_GPM_STATUS_QUERY", + "COEX_STATE_WLAN_VDEV_DOWN", + "COEX_STATE_WLAN_VDEV_START", + "COEX_STATE_WLAN_VDEV_CONNECTED", + "COEX_STATE_WLAN_VDEV_SCAN_STARTED", + "COEX_STATE_WLAN_VDEV_SCAN_END", + "COEX_STATE_WLAN_DEFAULT", + "COEX_CHANNEL_CHANGE", + "COEX_POWER_CHANGE", + "COEX_CONFIG_MGR", + "COEX_TX_MCI_GPM_BT_CAL_REQ", + "COEX_TX_MCI_GPM_BT_CAL_GRANT", + "COEX_TX_MCI_GPM_BT_CAL_DONE", + "COEX_TX_MCI_GPM_WLAN_CAL_REQ", + "COEX_TX_MCI_GPM_WLAN_CAL_GRANT", + "COEX_TX_MCI_GPM_WLAN_CAL_DONE", + "COEX_TX_MCI_GPM_BT_DEBUG", + "COEX_TX_MCI_GPM_VERSION_QUERY", + "COEX_TX_MCI_GPM_VERSION_RESPONSE", + "COEX_TX_MCI_GPM_STATUS_QUERY", + "COEX_TX_MCI_GPM_HALT_BT_GPM", + "COEX_TX_MCI_GPM_WLAN_CHANNELS", + "COEX_TX_MCI_GPM_BT_PROFILE_INFO", + "COEX_TX_MCI_GPM_BT_STATUS_UPDATE", + "COEX_TX_MCI_GPM_BT_UPDATE_FLAGS", + "COEX_TX_MCI_GPM_UNKNOWN", + "COEX_TX_MCI_SYS_WAKING", + "COEX_TX_MCI_LNA_TAKE", + "COEX_TX_MCI_LNA_TRANS", + "COEX_TX_MCI_SYS_SLEEPING", + "COEX_TX_MCI_REQ_WAKE", + "COEX_TX_MCI_REMOTE_RESET", + "COEX_TX_MCI_TYPE_UNKNOWN", + "COEX_WHAL_MCI_RESET", + "COEX_POLL_BT_CAL_DONE_TIMEOUT", + "COEX_WHAL_PAUSE", + "COEX_RX_MCI_GPM_BT_CAL_REQ", + "COEX_RX_MCI_GPM_BT_CAL_DONE", + "COEX_RX_MCI_GPM_BT_CAL_GRANT", + "COEX_WLAN_CAL_START", + "COEX_WLAN_CAL_RESULT", + "COEX_BtMciState", + "COEX_BtCalState", + "COEX_WlanCalState", + "COEX_RxReqWakeCount", + "COEX_RxRemoteResetCount", + "COEX_RESTART_CAL", + "COEX_SENDMSG_QUEUE", + "COEX_RESETSEQ_LNAINFO_TIMEOUT", + "COEX_MCI_ISR_IntRaw", + "COEX_MCI_ISR_Int1Raw", + "COEX_MCI_ISR_RxMsgRaw", + "COEX_WHAL_COEX_RESET", + "COEX_WAL_COEX_INIT", + "COEX_TXRX_CNT_LIMIT_ISR", + "COEX_CH_BUSY", + "COEX_REASSESS_WLAN_STATE", + "COEX_BTCOEX_WLAN_STATE_UPDATE", + "COEX_BT_NUM_OF_PROFILES", + "COEX_BT_NUM_OF_HID_PROFILES", + "COEX_BT_NUM_OF_ACL_PROFILES", + "COEX_BT_NUM_OF_HI_ACL_PROFILES", + "COEX_BT_NUM_OF_VOICE_PROFILES", + "COEX_WLAN_AGGR_LIMIT", + "COEX_BT_LOW_PRIO_BUDGET", + "COEX_BT_HI_PRIO_BUDGET", + "COEX_BT_IDLE_TIME", + "COEX_SET_COEX_WEIGHT", + "COEX_WLAN_WEIGHT_GROUP", + "COEX_BT_WEIGHT_GROUP", + "COEX_BT_INTERVAL_ALLOC", + "COEX_BT_SCHEME", + "COEX_BT_MGR", + "COEX_BT_SM_ERROR", + "COEX_SYSTEM_UPDATE", + "COEX_LOW_PRIO_LIMIT", + "COEX_HI_PRIO_LIMIT", + "COEX_BT_INTERVAL_START", + "COEX_WLAN_INTERVAL_START", + "COEX_NON_LINK_BUDGET", + "COEX_CONTENTION_MSG", + "COEX_SET_NSS", + "COEX_SELF_GEN_MASK", + "COEX_PROFILE_ERROR", + "COEX_WLAN_INIT", + "COEX_BEACON_MISS", + "COEX_BEACON_OK", + "COEX_BTCOEX_SCAN_ACTIVITY", + "COEX_SCAN_ACTIVITY", + "COEX_FORCE_QUIETTIME", + "COEX_BT_MGR_QUIETTIME", + "COEX_BT_INACTIVITY_TRIGGER", + "COEX_BT_INACTIVITY_REPORTED", + "COEX_TX_MCI_GPM_WLAN_PRIO", + "COEX_TX_MCI_GPM_BT_PAUSE_PROFILE", + "COEX_TX_MCI_GPM_WLAN_SET_ACL_INACTIVITY", + "COEX_RX_MCI_GPM_BT_ACL_INACTIVITY_REPORT", + "COEX_GENERIC_ERROR", + "COEX_RX_RATE_THRESHOLD", + "COEX_RSSI", + "COEX_WLAN_VDEV_NOTIF_START", /* 133 */ + "COEX_WLAN_VDEV_NOTIF_UP", /* 134 */ + "COEX_WLAN_VDEV_NOTIF_DOWN", /* 135 */ + "COEX_WLAN_VDEV_NOTIF_STOP", /* 136 */ + "COEX_WLAN_VDEV_NOTIF_ADD_PEER", /* 137 */ + "COEX_WLAN_VDEV_NOTIF_DELETE_PEER", /* 138 */ + "COEX_WLAN_VDEV_NOTIF_CONNECTED_PEER", /* 139 */ + "COEX_WLAN_VDEV_NOTIF_PAUSE", /* 140 */ + "COEX_WLAN_VDEV_NOTIF_UNPAUSED", /* 141 */ + "COEX_STATE_WLAN_VDEV_PEER_ADD", /* 142 */ + "COEX_STATE_WLAN_VDEV_CONNECTED_PEER", /* 143 */ + "COEX_STATE_WLAN_VDEV_DELETE_PEER", /* 144 */ + "COEX_STATE_WLAN_VDEV_PAUSE", /* 145 */ + "COEX_STATE_WLAN_VDEV_UNPAUSED", /* 146 */ + "COEX_SCAN_CALLBACK", /* 147 */ + "COEX_RC_SET_CHAINMASK", /* 148 */ + "COEX_TX_MCI_GPM_WLAN_SET_BT_RXSS_THRES", /* 149 */ + "COEX_TX_MCI_GPM_BT_RXSS_THRES_QUERY", /* 150 */ + "COEX_BT_RXSS_THRES", /* 151 */ + "COEX_BT_PROFILE_ADD_RMV", /* 152 */ + "COEX_BT_SCHED_INFO", /* 153 */ + "COEX_TRF_MGMT", /* 154 */ + "COEX_SCHED_START", /* 155 */ + "COEX_SCHED_RESULT", /* 156 */ + "COEX_SCHED_ERROR", /* 157 */ + "COEX_SCHED_PRE_OP", /* 158 */ + "COEX_SCHED_POST_OP", /* 159 */ + "COEX_RX_RATE", /* 160 */ + "COEX_ACK_PRIORITY", /* 161 */ + "COEX_STATE_WLAN_VDEV_UP", /* 162 */ + "COEX_STATE_WLAN_VDEV_PEER_UPDATE", /* 163 */ + "COEX_STATE_WLAN_VDEV_STOP", /* 164 */ + "COEX_WLAN_PAUSE_PEER", /* 165 */ + "COEX_WLAN_UNPAUSE_PEER", /* 166 */ + "COEX_WLAN_PAUSE_INTERVAL_START", /* 167 */ + "COEX_WLAN_POSTPAUSE_INTERVAL_START", /* 168 */ + "COEX_TRF_FREERUN", /* 169 */ + "COEX_TRF_SHAPE_PM", /* 170 */ + "COEX_TRF_SHAPE_PSP", /* 171 */ + "COEX_TRF_SHAPE_S_CTS", /* 172 */ + "COEX_CHAIN_CONFIG", /* 173 */ + "COEX_SYSTEM_MONITOR", /* 174 */ + "COEX_SINGLECHAIN_INIT", /* 175 */ + "COEX_MULTICHAIN_INIT", /* 176 */ + "COEX_SINGLECHAIN_DBG_1", /* 177 */ + "COEX_SINGLECHAIN_DBG_2", /* 178 */ + "COEX_SINGLECHAIN_DBG_3", /* 179 */ + "COEX_MULTICHAIN_DBG_1", /* 180 */ + "COEX_MULTICHAIN_DBG_2", /* 181 */ + "COEX_MULTICHAIN_DBG_3", /* 182 */ + "COEX_PSP_TX_CB", /* 183 */ + "COEX_PSP_RX_CB", /* 184 */ + "COEX_PSP_STAT_1", /* 185 */ + "COEX_PSP_SPEC_POLL", /* 186 */ + "COEX_PSP_READY_STATE", /* 187 */ + "COEX_PSP_TX_STATUS_STATE", /* 188 */ + "COEX_PSP_RX_STATUS_STATE_1", /* 189 */ + "COEX_PSP_NOT_READY_STATE", /* 190 */ + "COEX_PSP_DISABLED_STATE", /* 191 */ + "COEX_PSP_ENABLED_STATE", /* 192 */ + "COEX_PSP_SEND_PSPOLL", /* 193 */ + "COEX_PSP_MGR_ENTER", /* 194 */ + "COEX_PSP_MGR_RESULT", /* 195 */ + "COEX_PSP_NONWLAN_INTERVAL", /* 196 */ + "COEX_PSP_STAT_2", /* 197 */ + "COEX_PSP_RX_STATUS_STATE_2", /* 198 */ + "COEX_PSP_ERROR", /* 199 */ + "COEX_T2BT", /* 200 */ + "COEX_BT_DURATION", /* 201 */ + "COEX_TX_MCI_GPM_WLAN_SCHED_INFO_TRIG", /* 202 */ + "COEX_TX_MCI_GPM_WLAN_SCHED_INFO_TRIG_RSP", /* 203 */ + "COEX_TX_MCI_GPM_SCAN_OP", /* 204 */ + "COEX_TX_MCI_GPM_BT_PAUSE_GPM_TX", /* 205 */ + "COEX_CTS2S_SEND", /* 206 */ + "COEX_CTS2S_RESULT", /* 207 */ + "COEX_ENTER_OCS", /* 208 */ + "COEX_EXIT_OCS", /* 209 */ + "COEX_UPDATE_OCS", /* 210 */ + "COEX_STATUS_OCS", /* 211 */ + "COEX_STATS_BT", /* 212 */ + "COEX_MWS_WLAN_INIT", + "COEX_MWS_WBTMR_SYNC", + "COEX_MWS_TYPE2_RX", + "COEX_MWS_TYPE2_TX", + "COEX_MWS_WLAN_CHAVD", + "COEX_MWS_WLAN_CHAVD_INSERT", + "COEX_MWS_WLAN_CHAVD_MERGE", + "COEX_MWS_WLAN_CHAVD_RPT", + "COEX_MWS_CP_MSG_SEND", + "COEX_MWS_CP_ESCAPE", + "COEX_MWS_CP_UNFRAME", + "COEX_MWS_CP_SYNC_UPDATE", + "COEX_MWS_CP_SYNC", + "COEX_MWS_CP_WLAN_STATE_IND", + "COEX_MWS_CP_SYNCRESP_TIMEOUT", + "COEX_MWS_SCHEME_UPDATE", + "COEX_MWS_WLAN_EVENT", + "COEX_MWS_UART_UNESCAPE", + "COEX_MWS_UART_ENCODE_SEND", + "COEX_MWS_UART_RECV_DECODE", + "COEX_MWS_UL_HDL", + "COEX_MWS_REMOTE_EVENT", + "COEX_MWS_OTHER", + "COEX_MWS_ERROR", + "COEX_MWS_ANT_DIVERSITY", /* 237 */ + "COEX_P2P_GO", + "COEX_P2P_CLIENT", + "COEX_SCC_1", + "COEX_SCC_2", + "COEX_MCC_1", + "COEX_MCC_2", + "COEX_TRF_SHAPE_NOA", + "COEX_NOA_ONESHOT", + "COEX_NOA_PERIODIC", + "COEX_LE_1", + "COEX_LE_2", + "COEX_ANT_1", + "COEX_ANT_2", + "COEX_ENTER_NOA", + "COEX_EXIT_NOA", + "COEX_BT_SCAN_PROTECT", /* 253 */ + "COEX_DEBUG_ID_END" /* 254 */ + }, + { + "ROAM_DBGID_DEFINITION_START", + "ROAM_MODULE_INIT", + "ROAM_DEV_START", + "ROAM_CONFIG_RSSI_THRESH", + "ROAM_CONFIG_SCAN_PERIOD", + "ROAM_CONFIG_AP_PROFILE", + "ROAM_CONFIG_CHAN_LIST", + "ROAM_CONFIG_SCAN_PARAMS", + "ROAM_CONFIG_RSSI_CHANGE", + "ROAM_SCAN_TIMER_START", + "ROAM_SCAN_TIMER_EXPIRE", + "ROAM_SCAN_TIMER_STOP", + "ROAM_SCAN_STARTED", + "ROAM_SCAN_COMPLETE", + "ROAM_SCAN_CANCELLED", + "ROAM_CANDIDATE_FOUND", + "ROAM_RSSI_ACTIVE_SCAN", + "ROAM_RSSI_ACTIVE_ROAM", + "ROAM_RSSI_GOOD", + "ROAM_BMISS_FIRST_RECV", + "ROAM_DEV_STOP", + "ROAM_FW_OFFLOAD_ENABLE", + "ROAM_CANDIDATE_SSID_MATCH", + "ROAM_CANDIDATE_SECURITY_MATCH", + "ROAM_LOW_RSSI_INTERRUPT", + "ROAM_HIGH_RSSI_INTERRUPT", + "ROAM_SCAN_REQUESTED", + "ROAM_BETTER_CANDIDATE_FOUND", + "ROAM_BETTER_AP_EVENT", + "ROAM_CANCEL_LOW_PRIO_SCAN", + "ROAM_FINAL_BMISS_RECVD", + "ROAM_CONFIG_SCAN_MODE", + "ROAM_BMISS_FINAL_SCAN_ENABLE", + "ROAM_SUITABLE_AP_EVENT", + "ROAM_RSN_IE_PARSE_ERROR", + "ROAM_WPA_IE_PARSE_ERROR", + "ROAM_SCAN_CMD_FROM_HOST", + "ROAM_HO_SORT_CANDIDATE", + "ROAM_HO_SAVE_CANDIDATE", + "ROAM_HO_GET_CANDIDATE", + "ROAM_HO_OFFLOAD_SET_PARAM", + "ROAM_HO_SM", + "ROAM_HO_HTT_SAVED", + "ROAM_HO_SYNC_START", + "ROAM_HO_START", + "ROAM_HO_COMPLETE", + "ROAM_HO_STOP", + "ROAM_HO_HTT_FORWARD", + "ROAM_DBGID_DEFINITION_END" + }, + { + "RESMGR_CHMGR_DEFINITION_START", + "RESMGR_CHMGR_PAUSE_COMPLETE", + "RESMGR_CHMGR_CHANNEL_CHANGE", + "RESMGR_CHMGR_RESUME_COMPLETE", + "RESMGR_CHMGR_VDEV_PAUSE", + "RESMGR_CHMGR_VDEV_UNPAUSE", + "RESMGR_CHMGR_CTS2S_TX_COMP", + "RESMGR_CHMGR_CFEND_TX_COMP", + "RESMGR_CHMGR_DEFINITION_END" + }, + { + "RESMGR_DEFINITION_START", + "RESMGR_OCS_ALLOCRAM_SIZE", + "RESMGR_OCS_RESOURCES", + "RESMGR_LINK_CREATE", + "RESMGR_LINK_DELETE", + "RESMGR_OCS_CHREQ_CREATE", + "RESMGR_OCS_CHREQ_DELETE", + "RESMGR_OCS_CHREQ_START", + "RESMGR_OCS_CHREQ_STOP", + "RESMGR_OCS_SCHEDULER_INVOKED", + "RESMGR_OCS_CHREQ_GRANT", + "RESMGR_OCS_CHREQ_COMPLETE", + "RESMGR_OCS_NEXT_TSFTIME", + "RESMGR_OCS_TSF_TIMEOUT_US", + "RESMGR_OCS_CURR_CAT_WINDOW", + "RESMGR_OCS_CURR_CAT_WINDOW_REQ", + "RESMGR_OCS_CURR_CAT_WINDOW_TIMESLOT", + "RESMGR_OCS_CHREQ_RESTART", + "RESMGR_OCS_CLEANUP_CH_ALLOCATORS", + "RESMGR_OCS_PURGE_CHREQ", + "RESMGR_OCS_CH_ALLOCATOR_FREE", + "RESMGR_OCS_RECOMPUTE_SCHEDULE", + "RESMGR_OCS_NEW_CAT_WINDOW_REQ", + "RESMGR_OCS_NEW_CAT_WINDOW_TIMESLOT", + "RESMGR_OCS_CUR_CH_ALLOC", + "RESMGR_OCS_WIN_CH_ALLOC", + "RESMGR_OCS_SCHED_CH_CHANGE", + "RESMGR_OCS_CONSTRUCT_CAT_WIN", + "RESMGR_OCS_CHREQ_PREEMPTED", + "RESMGR_OCS_CH_SWITCH_REQ", + "RESMGR_OCS_CHANNEL_SWITCHED", + "RESMGR_OCS_CLEANUP_STALE_REQS", + "RESMGR_OCS_CHREQ_UPDATE", + "RESMGR_OCS_REG_NOA_NOTIF", + "RESMGR_OCS_DEREG_NOA_NOTIF", + "RESMGR_OCS_GEN_PERIODIC_NOA", + "RESMGR_OCS_RECAL_QUOTAS", + "RESMGR_OCS_GRANTED_QUOTA_STATS", + "RESMGR_OCS_ALLOCATED_QUOTA_STATS", + "RESMGR_OCS_REQ_QUOTA_STATS", + "RESMGR_OCS_TRACKING_TIME_FIRED", + "RESMGR_VC_ARBITRATE_ATTRIBUTES", + "RESMGR_OCS_LATENCY_STRICT_TIME_SLOT", + "RESMGR_OCS_CURR_TSF", + "RESMGR_OCS_QUOTA_REM", + "RESMGR_OCS_LATENCY_CASE_NO", + "RESMGR_OCS_WIN_CAT_DUR", + "RESMGR_VC_UPDATE_CUR_VC", + "RESMGR_VC_REG_UNREG_LINK", + "RESMGR_VC_PRINT_LINK", + "RESMGR_OCS_MISS_TOLERANCE", + "RESMGR_DYN_SCH_ALLOCRAM_SIZE", + "RESMGR_DYN_SCH_ENABLE", + "RESMGR_DYN_SCH_ACTIVE", + "RESMGR_DYN_SCH_CH_STATS_START", + "RESMGR_DYN_SCH_CH_SX_STATS", + "RESMGR_DYN_SCH_TOT_UTIL_PER", + "RESMGR_DYN_SCH_HOME_CH_QUOTA", + "RESMGR_OCS_REG_RECAL_QUOTA_NOTIF", + "RESMGR_OCS_DEREG_RECAL_QUOTA_NOTIF", + "RESMGR_DEFINITION_END" + }, + { + "VDEV_MGR_DEBID_DEFINITION_START", /* vdev Mgr */ + "VDEV_MGR_FIRST_BEACON_MISS_DETECTED", + "VDEV_MGR_FINAL_BEACON_MISS_DETECTED", + "VDEV_MGR_BEACON_IN_SYNC", + "VDEV_MGR_AP_KEEPALIVE_IDLE", + "VDEV_MGR_AP_KEEPALIVE_INACTIVE", + "VDEV_MGR_AP_KEEPALIVE_UNRESPONSIVE", + "VDEV_MGR_AP_TBTT_CONFIG", + "VDEV_MGR_FIRST_BCN_RECEIVED", + "VDEV_MGR_VDEV_START", + "VDEV_MGR_VDEV_UP", + "VDEV_MGR_PEER_AUTHORIZED", + "VDEV_MGR_OCS_HP_LP_REQ_POSTED", + "VDEV_MGR_VDEV_START_OCS_HP_REQ_COMPLETE", + "VDEV_MGR_VDEV_START_OCS_HP_REQ_STOP", + "VDEV_MGR_HP_START_TIME", + "VDEV_MGR_VDEV_PAUSE_DELAY_UPDATE", + "VDEV_MGR_VDEV_PAUSE_FAIL", + "VDEV_MGR_GEN_PERIODIC_NOA", + "VDEV_MGR_OFF_CHAN_GO_CH_REQ_SETUP", + "VDEV_MGR_DEFINITION_END", + }, + { + "SCAN_START_COMMAND_FAILED", /* scan */ + "SCAN_STOP_COMMAND_FAILED", + "SCAN_EVENT_SEND_FAILED", + "SCAN_ENGINE_START", + "SCAN_ENGINE_CANCEL_COMMAND", + "SCAN_ENGINE_STOP_DUE_TO_TIMEOUT", + "SCAN_EVENT_SEND_TO_HOST", + "SCAN_FWLOG_EVENT_ADD", + "SCAN_FWLOG_EVENT_REM", + "SCAN_FWLOG_EVENT_PREEMPTED", + "SCAN_FWLOG_EVENT_RESTARTED", + "SCAN_FWLOG_EVENT_COMPLETED", + }, + { + "RATECTRL_DBGID_DEFINITION_START", /* Rate ctrl */ + "RATECTRL_DBGID_ASSOC", + "RATECTRL_DBGID_NSS_CHANGE", + "RATECTRL_DBGID_CHAINMASK_ERR", + "RATECTRL_DBGID_UNEXPECTED_FRAME", + "RATECTRL_DBGID_WAL_RCQUERY", + "RATECTRL_DBGID_WAL_RCUPDATE", + "RATECTRL_DBGID_GTX_UPDATE", + "RATECTRL_DBGID_DEFINITION_END" + }, + { + "AP_PS_DBGID_DEFINITION_START", + "AP_PS_DBGID_UPDATE_TIM", + "AP_PS_DBGID_PEER_STATE_CHANGE", + "AP_PS_DBGID_PSPOLL", + "AP_PS_DBGID_PEER_CREATE", + "AP_PS_DBGID_PEER_DELETE", + "AP_PS_DBGID_VDEV_CREATE", + "AP_PS_DBGID_VDEV_DELETE", + "AP_PS_DBGID_SYNC_TIM", + "AP_PS_DBGID_NEXT_RESPONSE", + "AP_PS_DBGID_START_SP", + "AP_PS_DBGID_COMPLETED_EOSP", + "AP_PS_DBGID_TRIGGER", + "AP_PS_DBGID_DUPLICATE_TRIGGER", + "AP_PS_DBGID_UAPSD_RESPONSE", + "AP_PS_DBGID_SEND_COMPLETE", + "AP_PS_DBGID_SEND_N_COMPLETE", + "AP_PS_DBGID_DETECT_OUT_OF_SYNC_STA", + "AP_PS_DBGID_DELIVER_CAB", + }, + { + "" /* Block Ack */ + }, + /* Mgmt TxRx */ + { + "MGMT_TXRX_DBGID_DEFINITION_START", + "MGMT_TXRX_FORWARD_TO_HOST", + "MGMT_TXRX_DBGID_DEFINITION_END", + }, + { /* Data TxRx */ + "DATA_TXRX_DBGID_DEFINITION_START", + "DATA_TXRX_DBGID_RX_DATA_SEQ_LEN_INFO", + "DATA_TXRX_DBGID_DEFINITION_END", + }, + {"" /* HTT */ + }, + {"" /* HOST */ + }, + {"" /* BEACON */ + "BEACON_EVENT_SWBA_SEND_FAILED", + "BEACON_EVENT_EARLY_RX_BMISS_STATUS", + "BEACON_EVENT_EARLY_RX_SLEEP_SLOP", + "BEACON_EVENT_EARLY_RX_CONT_BMISS_TIMEOUT", + "BEACON_EVENT_EARLY_RX_PAUSE_SKIP_BCN_NUM", + "BEACON_EVENT_EARLY_RX_CLK_DRIFT", + "BEACON_EVENT_EARLY_RX_AP_DRIFT", + "BEACON_EVENT_EARLY_RX_BCN_TYPE",}, + { /* Offload Mgr */ + "OFFLOAD_MGR_DBGID_DEFINITION_START", + "OFFLOADMGR_REGISTER_OFFLOAD", + "OFFLOADMGR_DEREGISTER_OFFLOAD", + "OFFLOADMGR_NO_REG_DATA_HANDLERS", + "OFFLOADMGR_NO_REG_EVENT_HANDLERS", + "OFFLOADMGR_REG_OFFLOAD_FAILED", + "OFFLOADMGR_DBGID_DEFINITION_END", + }, + { + "WAL_DBGID_DEFINITION_START", + "WAL_DBGID_FAST_WAKE_REQUEST", + "WAL_DBGID_FAST_WAKE_RELEASE", + "WAL_DBGID_SET_POWER_STATE", + "WAL_DBGID_MISSING", + "WAL_DBGID_CHANNEL_CHANGE_FORCE_RESET", + "WAL_DBGID_CHANNEL_CHANGE", + "WAL_DBGID_VDEV_START", + "WAL_DBGID_VDEV_STOP", + "WAL_DBGID_VDEV_UP", + "WAL_DBGID_VDEV_DOWN", + "WAL_DBGID_SW_WDOG_RESET", + "WAL_DBGID_TX_SCH_REGISTER_TIDQ", + "WAL_DBGID_TX_SCH_UNREGISTER_TIDQ", + "WAL_DBGID_TX_SCH_TICKLE_TIDQ", + "WAL_DBGID_XCESS_FAILURES", + "WAL_DBGID_AST_ADD_WDS_ENTRY", + "WAL_DBGID_AST_DEL_WDS_ENTRY", + "WAL_DBGID_AST_WDS_ENTRY_PEER_CHG", + "WAL_DBGID_AST_WDS_SRC_LEARN_FAIL", + "WAL_DBGID_STA_KICKOUT", + "WAL_DBGID_BAR_TX_FAIL", + "WAL_DBGID_BAR_ALLOC_FAIL", + "WAL_DBGID_LOCAL_DATA_TX_FAIL", + "WAL_DBGID_SECURITY_PM4_QUEUED", + "WAL_DBGID_SECURITY_GM1_QUEUED", + "WAL_DBGID_SECURITY_PM4_SENT", + "WAL_DBGID_SECURITY_ALLOW_DATA", + "WAL_DBGID_SECURITY_UCAST_KEY_SET", + "WAL_DBGID_SECURITY_MCAST_KEY_SET", + "WAL_DBGID_SECURITY_ENCR_EN", + "WAL_DBGID_BB_WDOG_TRIGGERED", + "WAL_DBGID_RX_LOCAL_BUFS_LWM", + "WAL_DBGID_RX_LOCAL_DROP_LARGE_MGMT", + "WAL_DBGID_VHT_ILLEGAL_RATE_PHY_ERR_DETECTED", + "WAL_DBGID_DEV_RESET", + "WAL_DBGID_TX_BA_SETUP", + "WAL_DBGID_RX_BA_SETUP", + "WAL_DBGID_DEV_TX_TIMEOUT", + "WAL_DBGID_DEV_RX_TIMEOUT", + "WAL_DBGID_STA_VDEV_XRETRY", + "WAL_DBGID_DCS", + "WAL_DBGID_MGMT_TX_FAIL", + "WAL_DBGID_SET_M4_SENT_MANUALLY", + "WAL_DBGID_PROCESS_4_WAY_HANDSHAKE", + "WAL_DBGID_WAL_CHANNEL_CHANGE_START", + "WAL_DBGID_WAL_CHANNEL_CHANGE_COMPLETE", + "WAL_DBGID_WHAL_CHANNEL_CHANGE_START", + "WAL_DBGID_WHAL_CHANNEL_CHANGE_COMPLETE", + "WAL_DBGID_TX_MGMT_DESCID_SEQ_TYPE_LEN", + "WAL_DBGID_TX_DATA_MSDUID_SEQ_TYPE_LEN", + "WAL_DBGID_TX_DISCARD", + "WAL_DBGID_TX_MGMT_COMP_DESCID_STATUS", + "WAL_DBGID_TX_DATA_COMP_MSDUID_STATUS", + "WAL_DBGID_RESET_PCU_CYCLE_CNT", + "WAL_DBGID_SETUP_RSSI_INTERRUPTS", + "WAL_DBGID_BRSSI_CONFIG", + "WAL_DBGID_CURRENT_BRSSI_AVE", + "WAL_DBGID_BCN_TX_COMP", + "WAL_DBGID_SET_HW_CHAINMASK", + "WAL_DBGID_SET_HW_CHAINMASK_TXRX_STOP_FAIL", + "WAL_DBGID_GET_HW_CHAINMASK", + "WAL_DBGID_SMPS_DISABLE", + "WAL_DBGID_SMPS_ENABLE_HW_CNTRL", + "WAL_DBGID_SMPS_SWSEL_CHAINMASK", + "WAL_DBGID_DEFINITION_END", + }, + { + "" /* DE */ + }, + { + "" /* pcie lp */ + }, + { + /* RTT */ + "RTT_CALL_FLOW", + "RTT_REQ_SUB_TYPE", + "RTT_MEAS_REQ_HEAD", + "RTT_MEAS_REQ_BODY", + "", + "", + "RTT_INIT_GLOBAL_STATE", + "", + "RTT_REPORT", + "", + "RTT_ERROR_REPORT", + "RTT_TIMER_STOP", + "RTT_SEND_TM_FRAME", + "RTT_V3_RESP_CNT", + "RTT_V3_RESP_FINISH", + "RTT_CHANNEL_SWITCH_REQ", + "RTT_CHANNEL_SWITCH_GRANT", + "RTT_CHANNEL_SWITCH_COMPLETE", + "RTT_CHANNEL_SWITCH_PREEMPT", + "RTT_CHANNEL_SWITCH_STOP", + "RTT_TIMER_START", + }, + { /* RESOURCE */ + "RESOURCE_DBGID_DEFINITION_START", + "RESOURCE_PEER_ALLOC", + "RESOURCE_PEER_FREE", + "RESOURCE_PEER_ALLOC_WAL_PEER", + "RESOURCE_PEER_NBRHOOD_MGMT_ALLOC", + "RESOURCE_PEER_NBRHOOD_MGMT_INFO," "RESOURCE_DBGID_DEFINITION_END", + }, + { /* DCS */ + "WLAN_DCS_DBGID_INIT", + "WLAN_DCS_DBGID_WMI_CWINT", + "WLAN_DCS_DBGID_TIMER", + "WLAN_DCS_DBGID_CMDG", + "WLAN_DCS_DBGID_CMDS", + "WLAN_DCS_DBGID_DINIT" + }, + { /* CACHEMGR */ + "" + }, + { /* ANI */ + "ANI_DBGID_POLL", + "ANI_DBGID_CONTROL", + "ANI_DBGID_OFDM_PARAMS", + "ANI_DBGID_CCK_PARAMS", + "ANI_DBGID_RESET", + "ANI_DBGID_RESTART", + "ANI_DBGID_OFDM_LEVEL", + "ANI_DBGID_CCK_LEVEL", + "ANI_DBGID_FIRSTEP", + "ANI_DBGID_CYCPWR", + "ANI_DBGID_MRC_CCK", + "ANI_DBGID_SELF_CORR_LOW", + "ANI_DBGID_ENABLE", + "ANI_DBGID_CURRENT_LEVEL", + "ANI_DBGID_POLL_PERIOD", + "ANI_DBGID_LISTEN_PERIOD", + "ANI_DBGID_OFDM_LEVEL_CFG", + "ANI_DBGID_CCK_LEVEL_CFG" + }, + { + "P2P_DBGID_DEFINITION_START", + "P2P_DEV_REGISTER", + "P2P_HANDLE_NOA", + "P2P_UPDATE_SCHEDULE_OPPS", + "P2P_UPDATE_SCHEDULE", + "P2P_UPDATE_START_TIME", + "P2P_UPDATE_START_TIME_DIFF_TSF32", + "P2P_UPDATE_START_TIME_FINAL", + "P2P_SETUP_SCHEDULE_TIMER", + "P2P_PROCESS_SCHEDULE_AFTER_CALC", + "P2P_PROCESS_SCHEDULE_STARTED_TIMER", + "P2P_CALC_SCHEDULES_FIRST_CALL_ALL_NEXT_EVENT", + "P2P_CALC_SCHEDULES_FIRST_VALUE", + "P2P_CALC_SCHEDULES_EARLIEST_NEXT_EVENT", + "P2P_CALC_SCHEDULES_SANITY_COUNT", + "P2P_CALC_SCHEDULES_CALL_ALL_NEXT_EVENT_FROM_WHILE_LOOP", + "P2P_CALC_SCHEDULES_TIMEOUT_1", + "P2P_CALC_SCHEDULES_TIMEOUT_2", + "P2P_FIND_ALL_NEXT_EVENTS_REQ_EXPIRED", + "P2P_FIND_ALL_NEXT_EVENTS_REQ_ACTIVE", + "P2P_FIND_NEXT_EVENT_REQ_NOT_STARTED", + "P2P_FIND_NEXT_EVENT_REQ_COMPLETE_NON_PERIODIC", + "P2P_FIND_NEXT_EVENT_IN_MID_OF_NOA", + "P2P_FIND_NEXT_EVENT_REQ_COMPLETE", + "P2P_SCHEDULE_TIMEOUT", + "P2P_CALC_SCHEDULES_ENTER", + "P2P_PROCESS_SCHEDULE_ENTER", + "P2P_FIND_ALL_NEXT_EVENTS_INDIVIDUAL_REQ_AFTER_CHANGE", + "P2P_FIND_ALL_NEXT_EVENTS_INDIVIDUAL_REQ_BEFORE_CHANGE", + "P2P_FIND_ALL_NEXT_EVENTS_ENTER", + "P2P_FIND_NEXT_EVENT_ENTER", + "P2P_NOA_GO_PRESENT", + "P2P_NOA_GO_ABSENT", + "P2P_GO_NOA_NOTIF", + "P2P_GO_TBTT_OFFSET", + "P2P_GO_GET_NOA_INFO", + "P2P_GO_ADD_ONE_SHOT_NOA", + "P2P_GO_GET_NOA_IE", + "P2P_GO_BCN_TX_COMP", + "P2P_DBGID_DEFINITION_END", + }, + { + "CSA_DBGID_DEFINITION_START", + "CSA_OFFLOAD_POOL_INIT", + "CSA_OFFLOAD_REGISTER_VDEV", + "CSA_OFFLOAD_DEREGISTER_VDEV", + "CSA_DEREGISTER_VDEV_ERROR", + "CSA_OFFLOAD_BEACON_RECEIVED", + "CSA_OFFLOAD_BEACON_CSA_RECV", + "CSA_OFFLOAD_CSA_RECV_ERROR_IE", + "CSA_OFFLOAD_CSA_TIMER_ERROR", + "CSA_OFFLOAD_CSA_TIMER_EXP", + "CSA_OFFLOAD_WMI_EVENT_ERROR", + "CSA_OFFLOAD_WMI_EVENT_SENT", + "CSA_OFFLOAD_WMI_CHANSWITCH_RECV", + "CSA_DBGID_DEFINITION_END", + }, + { /* NLO offload */ + "" + }, + { + "WLAN_CHATTER_DBGID_DEFINITION_START", + "WLAN_CHATTER_ENTER", + "WLAN_CHATTER_EXIT", + "WLAN_CHATTER_FILTER_HIT", + "WLAN_CHATTER_FILTER_MISS", + "WLAN_CHATTER_FILTER_FULL", + "WLAN_CHATTER_FILTER_TM_ADJ", + "WLAN_CHATTER_BUFFER_FULL", + "WLAN_CHATTER_TIMEOUT", + "WLAN_CHATTER_DBGID_DEFINITION_END", + }, + { + "WOW_DBGID_DEFINITION_START", + "WOW_ENABLE_CMDID", + "WOW_RECV_DATA_PKT", + "WOW_WAKE_HOST_DATA", + "WOW_RECV_MGMT", + "WOW_WAKE_HOST_MGMT", + "WOW_RECV_EVENT", + "WOW_WAKE_HOST_EVENT", + "WOW_INIT", + "WOW_RECV_MAGIC_PKT", + "WOW_RECV_BITMAP_PATTERN", + "WOW_AP_VDEV_DISALLOW", + "WOW_STA_VDEV_DISALLOW", + "WOW_P2PGO_VDEV_DISALLOW", + "WOW_NS_OFLD_ENABLE", + "WOW_ARP_OFLD_ENABLE", + "WOW_NS_ARP_OFLD_DISABLE", + "WOW_NS_RECEIVED", + "WOW_NS_REPLIED", + "WOW_ARP_RECEIVED", + "WOW_ARP_REPLIED", + "WOW_DBGID_DEFINITION_END", + }, + { /* WAL VDEV */ + "" + }, + { /* WAL PDEV */ + "" + }, + { /* TEST */ + "TP_CHANGE_CHANNEL", + "TP_LOCAL_SEND", + }, + { /* STA SMPS */ + "STA_SMPS_DBGID_DEFINITION_START", + "STA_SMPS_DBGID_CREATE_PDEV_INSTANCE", + "STA_SMPS_DBGID_CREATE_VIRTUAL_CHAN_INSTANCE", + "STA_SMPS_DBGID_DELETE_VIRTUAL_CHAN_INSTANCE", + "STA_SMPS_DBGID_CREATE_STA_INSTANCE", + "STA_SMPS_DBGID_DELETE_STA_INSTANCE", + "STA_SMPS_DBGID_VIRTUAL_CHAN_SMPS_START", + "STA_SMPS_DBGID_VIRTUAL_CHAN_SMPS_STOP", + "STA_SMPS_DBGID_SEND_SMPS_ACTION_FRAME", + "STA_SMPS_DBGID_HOST_FORCED_MODE", + "STA_SMPS_DBGID_FW_FORCED_MODE", + "STA_SMPS_DBGID_RSSI_THRESHOLD_CROSSED", + "STA_SMPS_DBGID_SMPS_ACTION_FRAME_COMPLETION", + "STA_SMPS_DBGID_DTIM_EBT_EVENT_CHMASK_UPDATE", + "STA_SMPS_DBGID_DTIM_CHMASK_UPDATE", + "STA_SMPS_DBGID_DTIM_BEACON_EVENT_CHMASK_UPDATE", + "STA_SMPS_DBGID_DTIM_POWER_STATE_CHANGE", + "STA_SMPS_DBGID_DTIM_CHMASK_UPDATE_SLEEP", + "STA_SMPS_DBGID_DTIM_CHMASK_UPDATE_AWAKE", + "SMPS_DBGID_DEFINITION_END", + }, + { /* SWBMISS */ + "SWBMISS_DBGID_DEFINITION_START", + "SWBMISS_ENABLED", + "SWBMISS_DISABLED", + "SWBMISS_DBGID_DEFINITION_END", + }, + { /* WMMAC */ + "" + }, + { /* TDLS */ + "TDLS_DBGID_DEFINITION_START", + "TDLS_DBGID_VDEV_CREATE", + "TDLS_DBGID_VDEV_DELETE", + "TDLS_DBGID_ENABLED_PASSIVE", + "TDLS_DBGID_ENABLED_ACTIVE", + "TDLS_DBGID_DISABLED", + "TDLS_DBGID_CONNTRACK_TIMER", + "TDLS_DBGID_WAL_SET", + "TDLS_DBGID_WAL_GET", + "TDLS_DBGID_WAL_PEER_UPDATE_SET", + "TDLS_DBGID_WAL_PEER_UPDATE_EVT", + "TDLS_DBGID_WAL_VDEV_CREATE", + "TDLS_DBGID_WAL_VDEV_DELETE", + "TDLS_DBGID_WLAN_EVENT", + "TDLS_DBGID_WLAN_PEER_UPDATE_SET", + "TDLS_DBGID_PEER_EVT_DRP_THRESH", + "TDLS_DBGID_PEER_EVT_DRP_RATE", + "TDLS_DBGID_PEER_EVT_DRP_RSSI", + "TDLS_DBGID_PEER_EVT_DISCOVER", + "TDLS_DBGID_PEER_EVT_DELETE", + "TDLS_DBGID_PEER_CAP_UPDATE", + "TDLS_DBGID_UAPSD_SEND_PTI_FRAME", + "TDLS_DBGID_UAPSD_SEND_PTI_FRAME2PEER", + "TDLS_DBGID_UAPSD_START_PTR_TIMER", + "TDLS_DBGID_UAPSD_CANCEL_PTR_TIMER", + "TDLS_DBGID_UAPSD_PTR_TIMER_TIMEOUT", + "TDLS_DBGID_UAPSD_STA_PS_EVENT_HANDLER", + "TDLS_DBGID_UAPSD_PEER_EVENT_HANDLER", + "TDLS_DBGID_UAPSD_PS_DEFAULT_SETTINGS", + "TDLS_DBGID_UAPSD_GENERIC", + }, + { /* HB */ + "WLAN_HB_DBGID_DEFINITION_START", + "WLAN_HB_DBGID_INIT", + "WLAN_HB_DBGID_TCP_GET_TXBUF_FAIL", + "WLAN_HB_DBGID_TCP_SEND_FAIL", + "WLAN_HB_DBGID_BSS_PEER_NULL", + "WLAN_HB_DBGID_UDP_GET_TXBUF_FAIL", + "WLAN_HB_DBGID_UDP_SEND_FAIL", + "WLAN_HB_DBGID_WMI_CMD_INVALID_PARAM", + "WLAN_HB_DBGID_WMI_CMD_INVALID_OP", + "WLAN_HB_DBGID_WOW_NOT_ENTERED", + "WLAN_HB_DBGID_ALLOC_SESS_FAIL", + "WLAN_HB_DBGID_CTX_NULL", + "WLAN_HB_DBGID_CHKSUM_ERR", + "WLAN_HB_DBGID_UDP_TX", + "WLAN_HB_DBGID_TCP_TX", + "WLAN_HB_DBGID_DEFINITION_END", + }, + { /* TXBF */ + "TXBFEE_DBGID_START", + "TXBFEE_DBGID_NDPA_RECEIVED", + "TXBFEE_DBGID_HOST_CONFIG_TXBFEE_TYPE", + "TXBFER_DBGID_SEND_NDPA", + "TXBFER_DBGID_GET_NDPA_BUF_FAIL", + "TXBFER_DBGID_SEND_NDPA_FAIL", + "TXBFER_DBGID_GET_NDP_BUF_FAIL", + "TXBFER_DBGID_SEND_NDP_FAIL", + "TXBFER_DBGID_GET_BRPOLL_BUF_FAIL", + "TXBFER_DBGID_SEND_BRPOLL_FAIL", + "TXBFER_DBGID_HOST_CONFIG_CMDID", + "TXBFEE_DBGID_HOST_CONFIG_CMDID", + "TXBFEE_DBGID_ENABLED_ENABLED_UPLOAD_H", + "TXBFEE_DBGID_UPLOADH_CV_TAG", + "TXBFEE_DBGID_UPLOADH_H_TAG", + "TXBFEE_DBGID_CAPTUREH_RECEIVED", + "TXBFEE_DBGID_PACKET_IS_STEERED", + "TXBFEE_UPLOADH_EVENT_ALLOC_MEM_FAIL", + "TXBFEE_DBGID_END", + }, + { /*BATCH SCAN */ + }, + { /*THERMAL MGR */ + "THERMAL_MGR_DBGID_DEFINITION_START", + "THERMAL_MGR_NEW_THRESH", + "THERMAL_MGR_THRESH_CROSSED", + "THERMAL_MGR_DBGID_DEFINITION END", + }, + { /* WLAN_MODULE_PHYERR_DFS */ + "" + }, + { + /* WLAN_MODULE_RMC */ + "RMC_DBGID_DEFINITION_START", + "RMC_CREATE_INSTANCE", + "RMC_DELETE_INSTANCE", + "RMC_LDR_SEL", + "RMC_NO_LDR", + "RMC_LDR_NOT_SEL", + "RMC_LDR_INF_SENT", + "RMC_PEER_ADD", + "RMC_PEER_DELETE", + "RMC_PEER_UNKNOWN", + "RMC_SET_MODE", + "RMC_SET_ACTION_PERIOD", + "RMC_ACRION_FRAME_RX", + "RMC_DBGID_DEFINITION_END", + }, + { + /* WLAN_MODULE_STATS */ + "WLAN_STATS_DBGID_DEFINITION_START", + "WLAN_STATS_DBGID_EST_LINKSPEED_VDEV_EN_DIS", + "WLAN_STATS_DBGID_EST_LINKSPEED_CHAN_TIME_START", + "WLAN_STATS_DBGID_EST_LINKSPEED_CHAN_TIME_END", + "WLAN_STATS_DBGID_EST_LINKSPEED_CALC", + "WLAN_STATS_DBGID_EST_LINKSPEED_UPDATE_HOME_CHAN", + "WLAN_STATS_DBGID_DEFINITION_END", + }, + { + /* WLAN_MODULE_NAN */ + }, + { + /* WLAN_MODULE_IBSS_PWRSAVE */ + "IBSS_PS_DBGID_DEFINITION_START", + "IBSS_PS_DBGID_PEER_CREATE", + "IBSS_PS_DBGID_PEER_DELETE", + "IBSS_PS_DBGID_VDEV_CREATE", + "IBSS_PS_DBGID_VDEV_DELETE", + "IBSS_PS_DBGID_VDEV_EVENT", + "IBSS_PS_DBGID_PEER_EVENT", + "IBSS_PS_DBGID_DELIVER_CAB", + "IBSS_PS_DBGID_DELIVER_UC_DATA", + "IBSS_PS_DBGID_DELIVER_UC_DATA_ERROR", + "IBSS_PS_DBGID_UC_INACTIVITY_TMR_RESTART", + "IBSS_PS_DBGID_MC_INACTIVITY_TMR_RESTART", + "IBSS_PS_DBGID_NULL_TX_COMPLETION", + "IBSS_PS_DBGID_ATIM_TIMER_START", + "IBSS_PS_DBGID_UC_ATIM_SEND", + "IBSS_PS_DBGID_BC_ATIM_SEND", + "IBSS_PS_DBGID_UC_TIMEOUT", + "IBSS_PS_DBGID_PWR_COLLAPSE_ALLOWED", + "IBSS_PS_DBGID_PWR_COLLAPSE_NOT_ALLOWED", + "IBSS_PS_DBGID_SET_PARAM", + "IBSS_PS_DBGID_HOST_TX_PAUSE", + "IBSS_PS_DBGID_HOST_TX_UNPAUSE", + "IBSS_PS_DBGID_PS_DESC_BIN_HWM", + "IBSS_PS_DBGID_PS_DESC_BIN_LWM", + "IBSS_PS_DBGID_PS_KICKOUT_PEER", + "IBSS_PS_DBGID_SET_PEER_PARAM", + "IBSS_PS_DBGID_BCN_ATIM_WIN_MISMATCH", + "IBSS_PS_DBGID_RX_CHAINMASK_CHANGE", + }, + { + /* HIF UART Interface DBGIDs */ + "HIF_UART_DBGID_START", + "HIF_UART_DBGID_POWER_STATE", + "HIF_UART_DBGID_TXRX_FLOW", + "HIF_UART_DBGID_TXRX_CTRL_CHAR", + "HIF_UART_DBGID_TXRX_BUF_DUMP", + }, + { + /* LPI */ + "" + }, + { + /* EXTSCAN DBGIDs */ + "EXTSCAN_START", + "EXTSCAN_STOP", + "EXTSCAN_CLEAR_ENTRY_CONTENT", + "EXTSCAN_GET_FREE_ENTRY_SUCCESS", + "EXTSCAN_GET_FREE_ENTRY_INCONSISTENT", + "EXTSCAN_GET_FREE_ENTRY_NO_MORE_ENTRIES", + "EXTSCAN_CREATE_ENTRY_SUCCESS", + "EXTSCAN_CREATE_ENTRY_ERROR", + "EXTSCAN_SEARCH_SCAN_ENTRY_QUEUE", + "EXTSCAN_SEARCH_SCAN_ENTRY_KEY_FOUND", + "EXTSCAN_SEARCH_SCAN_ENTRY_KEY_NOT_FOUND", + "EXTSCAN_ADD_ENTRY", + "EXTSCAN_BUCKET_SEND_OPERATION_EVENT", + "EXTSCAN_BUCKET_SEND_OPERATION_EVENT_FAILED", + "EXTSCAN_BUCKET_START_SCAN_CYCLE", + "EXTSCAN_BUCKET_PERIODIC_TIMER", + "EXTSCAN_SEND_START_STOP_EVENT", + "EXTSCAN_NOTIFY_WLAN_CHANGE", + "EXTSCAN_NOTIFY_WLAN_HOTLIST_MATCH", + "EXTSCAN_MAIN_RECEIVED_FRAME", + "EXTSCAN_MAIN_NO_SSID_IE", + "EXTSCAN_MAIN_MALFORMED_FRAME", + "EXTSCAN_FIND_BSSID_BY_REFERENCE", + "EXTSCAN_FIND_BSSID_BY_REFERENCE_ERROR", + "EXTSCAN_NOTIFY_TABLE_USAGE", + "EXTSCAN_FOUND_RSSI_ENTRY", + "EXTSCAN_BSSID_FOUND_RSSI_SAMPLE", + "EXTSCAN_BSSID_ADDED_RSSI_SAMPLE", + "EXTSCAN_BSSID_REPLACED_RSSI_SAMPLE", + "EXTSCAN_BSSID_TRANSFER_CURRENT_SAMPLES", + "EXTSCAN_BUCKET_PROCESS_SCAN_EVENT", + "EXTSCAN_BUCKET_CANNOT_FIND_BUCKET", + "EXTSCAN_START_SCAN_REQUEST_FAILED", + "EXTSCAN_BUCKET_STOP_CURRENT_SCANS", + "EXTSCAN_BUCKET_SCAN_STOP_REQUEST", + "EXTSCAN_BUCKET_PERIODIC_TIMER_ERROR", + "EXTSCAN_BUCKET_START_OPERATION", + "EXTSCAN_START_INTERNAL_ERROR", + "EXTSCAN_NOTIFY_HOTLIST_MATCH", + "EXTSCAN_CONFIG_HOTLIST_TABLE", + "EXTSCAN_CONFIG_WLAN_CHANGE_TABLE", + }, + { /* UNIT_TEST */ + "UNIT_TEST_GEN", + }, + { /* MLME */ + "MLME_DEBUG_CMN", + "MLME_IF", + "MLME_AUTH", + "MLME_REASSOC", + "MLME_DEAUTH", + "MLME_DISASSOC", + "MLME_ROAM", + "MLME_RETRY", + "MLME_TIMER", + "MLME_FRMPARSE", + }, + { /*SUPPLICANT */ + "SUPPL_INIT", + "SUPPL_RECV_EAPOL", + "SUPPL_RECV_EAPOL_TIMEOUT", + "SUPPL_SEND_EAPOL", + "SUPPL_MIC_MISMATCH", + "SUPPL_FINISH", + }, +}; + +int dbglog_module_log_enable(wmi_unified_t wmi_handle, A_UINT32 mod_id, + bool isenable) +{ + A_UINT32 val = 0; + + if (mod_id > WLAN_MODULE_ID_MAX) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + ("dbglog_module_log_enable: Invalid module id %d\n", + mod_id)); + return -EINVAL; + } + + WMI_DBGLOG_SET_MODULE_ID(val, mod_id); + if (isenable) { + /* set it to global module level */ + WMI_DBGLOG_SET_LOG_LEVEL(val, DBGLOG_INFO); + } else { + /* set it to ERROR level */ + WMI_DBGLOG_SET_LOG_LEVEL(val, DBGLOG_ERR); + } + wma_config_debug_module_cmd(wmi_handle, WMI_DEBUG_LOG_PARAM_LOG_LEVEL, + val, NULL, 0); + + return 0; +} + +int dbglog_vap_log_enable(wmi_unified_t wmi_handle, A_UINT16 vap_id, + bool isenable) +{ + if (vap_id > DBGLOG_MAX_VDEVID) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + ("dbglog_vap_log_enable:Invalid vap_id %d\n", + vap_id)); + return -EINVAL; + } + + wma_config_debug_module_cmd(wmi_handle, + isenable ? WMI_DEBUG_LOG_PARAM_VDEV_ENABLE : + WMI_DEBUG_LOG_PARAM_VDEV_DISABLE, vap_id, + NULL, 0); + + return 0; +} + +int dbglog_set_log_lvl(wmi_unified_t wmi_handle, enum DBGLOG_LOG_LVL log_lvl) +{ + A_UINT32 val = 0; + + if (log_lvl > DBGLOG_LVL_MAX) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + ("dbglog_set_log_lvl:Invalid log level %d\n", + log_lvl)); + return -EINVAL; + } + + WMI_DBGLOG_SET_MODULE_ID(val, WMI_DEBUG_LOG_MODULE_ALL); + WMI_DBGLOG_SET_LOG_LEVEL(val, log_lvl); + wma_config_debug_module_cmd(wmi_handle, WMI_DEBUG_LOG_PARAM_LOG_LEVEL, + val, NULL, 0); + + return 0; +} + +int dbglog_set_mod_log_lvl(wmi_unified_t wmi_handle, A_UINT32 mod_log_lvl) +{ + /* set the global module level to log_lvl */ + wma_config_debug_module_cmd(wmi_handle, WMI_DEBUG_LOG_PARAM_LOG_LEVEL, + mod_log_lvl, NULL, 0); + + return 0; +} + +void +dbglog_set_vap_enable_bitmap(wmi_unified_t wmi_handle, + A_UINT32 vap_enable_bitmap) +{ + wma_config_debug_module_cmd(wmi_handle, + WMI_DEBUG_LOG_PARAM_VDEV_ENABLE_BITMAP, + vap_enable_bitmap, NULL, 0); +} + +void +dbglog_set_mod_enable_bitmap(wmi_unified_t wmi_handle, A_UINT32 log_level, + A_UINT32 *mod_enable_bitmap, A_UINT32 bitmap_len) +{ + wma_config_debug_module_cmd(wmi_handle, + WMI_DEBUG_LOG_PARAM_MOD_ENABLE_BITMAP, + log_level, mod_enable_bitmap, bitmap_len); +} + +int dbglog_report_enable(wmi_unified_t wmi_handle, bool isenable) +{ + int bitmap[2] = { 0 }; + + if (isenable > true) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + ("dbglog_report_enable:Invalid value %d\n", + isenable)); + return -EINVAL; + } + + if (isenable) { + /* set the vap enable bitmap */ + dbglog_set_vap_enable_bitmap(wmi_handle, 0xFFFF); + bitmap[0] = 0xFFFFFFFF; + bitmap[1] = 0x1F; + /* set the module level bitmap */ + dbglog_set_mod_enable_bitmap(wmi_handle, 0x0, bitmap, 2); + } else { + dbglog_set_vap_enable_bitmap(wmi_handle, bitmap[0]); + dbglog_set_mod_enable_bitmap(wmi_handle, DBGLOG_LVL_MAX, bitmap, + 2); + } + return 0; +} + +static char *dbglog_get_msg(A_UINT32 moduleid, A_UINT32 debugid) +{ + static char unknown_str[64]; + + if (moduleid < WLAN_MODULE_ID_MAX && debugid < MAX_DBG_MSGS) { + char *str = DBG_MSG_ARR[moduleid][debugid]; + if (str && str[0] != '\0') { + return str; + } + } + + snprintf(unknown_str, sizeof(unknown_str), + "UNKNOWN %u:%u", moduleid, debugid); + + return unknown_str; +} + +static +void dbglog_printf(A_UINT32 timestamp, A_UINT16 vap_id, const char *fmt, ...) +{ + char buf[128]; + va_list ap; + + if (vap_id < DBGLOG_MAX_VDEVID) { + AR_DEBUG_PRINTF(ATH_DEBUG_INFO, + (DBGLOG_PRINT_PREFIX "[%u] vap-%u ", timestamp, + vap_id)); + } else { + AR_DEBUG_PRINTF(ATH_DEBUG_INFO, + (DBGLOG_PRINT_PREFIX "[%u] ", timestamp)); + } + + va_start(ap, fmt); + vsnprintf(buf, sizeof(buf), fmt, ap); + va_end(ap); + + AR_DEBUG_PRINTF(ATH_DEBUG_INFO, ("%s\n", buf)); +} + +static void +dbglog_printf_no_line_break(A_UINT32 timestamp, + A_UINT16 vap_id, const char *fmt, ...) +{ + char buf[128]; + va_list ap; + + if (vap_id < DBGLOG_MAX_VDEVID) { + AR_DEBUG_PRINTF(ATH_DEBUG_INFO, + (DBGLOG_PRINT_PREFIX "[%u] vap-%u ", timestamp, + vap_id)); + } else { + AR_DEBUG_PRINTF(ATH_DEBUG_INFO, + (DBGLOG_PRINT_PREFIX "[%u] ", timestamp)); + } + + va_start(ap, fmt); + vsnprintf(buf, sizeof(buf), fmt, ap); + va_end(ap); + + AR_DEBUG_PRINTF(ATH_DEBUG_INFO, ("%s", buf)); +} + +#define USE_NUMERIC 0 + +static A_BOOL +dbglog_default_print_handler(A_UINT32 mod_id, A_UINT16 vap_id, A_UINT32 dbg_id, + A_UINT32 timestamp, A_UINT16 numargs, + A_UINT32 *args) +{ + int i; + + if (vap_id < DBGLOG_MAX_VDEVID) { + AR_DEBUG_PRINTF(ATH_DEBUG_INFO, + (DBGLOG_PRINT_PREFIX "[%u] vap-%u %s ( ", + timestamp, vap_id, dbglog_get_msg(mod_id, + dbg_id))); + } else { + AR_DEBUG_PRINTF(ATH_DEBUG_INFO, + (DBGLOG_PRINT_PREFIX "[%u] %s ( ", timestamp, + dbglog_get_msg(mod_id, dbg_id))); + } + + for (i = 0; i < numargs; i++) { +#if USE_NUMERIC + AR_DEBUG_PRINTF(ATH_DEBUG_INFO, ("%u", args[i])); +#else + AR_DEBUG_PRINTF(ATH_DEBUG_INFO, ("%#x", args[i])); +#endif + if ((i + 1) < numargs) { + AR_DEBUG_PRINTF(ATH_DEBUG_INFO, (", ")); + } + } + AR_DEBUG_PRINTF(ATH_DEBUG_INFO, (" )\n")); + + return true; +} + +#define DBGLOG_PARSE_ARGS_STRING_LENGTH (DBGLOG_NUM_ARGS_MAX * 11 + 10) +static int dbglog_print_raw_data(A_UINT32 *buffer, A_UINT32 length) +{ + A_UINT32 timestamp; + A_UINT32 debugid; + A_UINT32 moduleid; + A_UINT16 numargs, curArgs; + A_UINT32 count = 0, totalWriteLen, writeLen; + char parseArgsString[DBGLOG_PARSE_ARGS_STRING_LENGTH]; + char *dbgidString; + + while (count < length) { + + debugid = DBGLOG_GET_DBGID(buffer[count + 1]); + moduleid = DBGLOG_GET_MODULEID(buffer[count + 1]); + numargs = DBGLOG_GET_NUMARGS(buffer[count + 1]); + timestamp = DBGLOG_GET_TIME_STAMP(buffer[count]); + + if (moduleid < WLAN_MODULE_ID_MAX && debugid < MAX_DBG_MSGS + && numargs <= DBGLOG_NUM_ARGS_MAX) { + + OS_MEMZERO(parseArgsString, sizeof(parseArgsString)); + totalWriteLen = 0; + + 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; + } + + if (debugid < MAX_DBG_MSGS) { + dbgidString = DBG_MSG_ARR[moduleid][debugid]; + if (dbgidString != NULL) { + AR_DEBUG_PRINTF(ATH_DEBUG_INFO, + ("fw:%s(%x %x):%s\n", + dbgidString, timestamp, + buffer[count + 1], + parseArgsString)); + } else { + /* host need sync with FW id */ + AR_DEBUG_PRINTF(ATH_DEBUG_INFO, + ("fw:%s:m:%x,id:%x(%x %x):%s\n", + "UNKNOWN", moduleid, + debugid, timestamp, + buffer[count + 1], + parseArgsString)); + } + } else if (debugid == + DBGLOG_DBGID_SM_FRAMEWORK_PROXY_DBGLOG_MSG) { + /* specific debugid */ + AR_DEBUG_PRINTF(ATH_DEBUG_INFO, + ("fw:%s:m:%x,id:%x(%x %x):%s\n", + "DBGLOG_SM_MSG", moduleid, + debugid, timestamp, + buffer[count + 1], + parseArgsString)); + } else { + AR_DEBUG_PRINTF(ATH_DEBUG_INFO, + ("fw:%s:m:%x,id:%x(%x %x):%s\n", + "UNKNOWN", moduleid, debugid, + timestamp, buffer[count + 1], + parseArgsString)); + } + } + + count += numargs + 2; /* 32 bit Time stamp + 32 bit Dbg header */ + } + + return 0; + +} + +#ifdef WLAN_OPEN_SOURCE +static int +dbglog_debugfs_raw_data(wmi_unified_t wmi_handle, const uint8_t *buf, + A_UINT32 length, A_UINT32 dropped) +{ + struct fwdebug *fwlog = (struct fwdebug *)&wmi_handle->dbglog; + struct dbglog_slot *slot; + struct sk_buff *skb; + size_t slot_len; + + if (WARN_ON(length > ATH6KL_FWLOG_PAYLOAD_SIZE)) + return -ENODEV; + + slot_len = sizeof(*slot) + ATH6KL_FWLOG_PAYLOAD_SIZE; + + skb = alloc_skb(slot_len, GFP_KERNEL); + if (!skb) + return -ENOMEM; + + slot = (struct dbglog_slot *)skb_put(skb, slot_len); + slot->diag_type = (A_UINT32) DIAG_TYPE_FW_DEBUG_MSG; + slot->timestamp = cpu_to_le32(jiffies); + slot->length = cpu_to_le32(length); + slot->dropped = cpu_to_le32(dropped); + memcpy(slot->payload, buf, length); + + /* Need to pad each record to fixed length ATH6KL_FWLOG_PAYLOAD_SIZE */ + memset(slot->payload + length, 0, ATH6KL_FWLOG_PAYLOAD_SIZE - length); + + spin_lock(&fwlog->fwlog_queue.lock); + + __skb_queue_tail(&fwlog->fwlog_queue, skb); + + complete(&fwlog->fwlog_completion); + + /* drop oldest entries */ + while (skb_queue_len(&fwlog->fwlog_queue) > ATH6KL_FWLOG_MAX_ENTRIES) { + skb = __skb_dequeue(&fwlog->fwlog_queue); + kfree_skb(skb); + } + + spin_unlock(&fwlog->fwlog_queue.lock); + + return true; +} +#endif /* WLAN_OPEN_SOURCE */ + +/** + * send_fw_diag_nl_data - pack the data from fw diag event handler + * @buffer: buffer of diag event + * @len: length of the diag event + * @event: the even type + * + * return: 0 if sent successfully, otherwise error code + */ +static int send_fw_diag_nl_data(const uint8_t *buffer, A_UINT32 len, + A_UINT32 event_type) +{ + struct sk_buff *skb_out; + struct nlmsghdr *nlh; + int res = 0; + tAniNlHdr *wnl; + int radio; + int msg_len; + + if (WARN_ON(len > ATH6KL_FWLOG_PAYLOAD_SIZE)) + return -ENODEV; + + if (nl_srv_is_initialized() != 0) + return -EIO; + + radio = cds_get_radio_index(); + if (radio == -EINVAL) + return -EIO; + + if (cds_is_multicast_logging()) { + msg_len = len + sizeof(radio); + skb_out = nlmsg_new(msg_len, GFP_KERNEL); + if (!skb_out) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + ("Failed to allocate new skb\n")); + return -ENOMEM; + } + nlh = nlmsg_put(skb_out, 0, 0, WLAN_NL_MSG_CNSS_DIAG, msg_len, + 0); + if (!nlh) { + kfree_skb(skb_out); + return -EMSGSIZE; + } + wnl = (tAniNlHdr *)nlh; + wnl->radio = radio; + + /* data buffer offset from nlmsg_hdr + sizeof(int) radio */ + memcpy(nlmsg_data(nlh) + sizeof(radio), buffer, len); + + res = nl_srv_bcast(skb_out); + if ((res < 0) && (res != -ESRCH)) { + AR_DEBUG_PRINTF(ATH_DEBUG_RSVD1, + ("%s: nl_srv_bcast failed 0x%x\n", + __func__, res)); + return res; + } + } + return res; +} + +/** + * process_fw_diag_event_data() - process diag events and fw messages + * @datap: data to be processed + * @num_data: number of data chunks + * + * return: success + */ +static int +process_fw_diag_event_data(uint8_t *datap, uint32_t num_data) +{ + uint32_t i; + uint32_t diag_type; + uint32_t nl_data_len; /* diag hdr + payload */ + uint32_t diag_data_len; /* each fw diag payload */ + struct wlan_diag_data *diag_data; + + for (i = 0; i < num_data; i++) { + diag_data = (struct wlan_diag_data *)datap; + diag_type = WLAN_DIAG_0_TYPE_GET(diag_data->word0); + diag_data_len = WLAN_DIAG_0_LEN_GET(diag_data->word0); + /* Length of diag struct and len of payload */ + nl_data_len = sizeof(struct wlan_diag_data) + diag_data_len; + + switch (diag_type) { + case DIAG_TYPE_FW_EVENT: + return send_fw_diag_nl_data(datap, nl_data_len, + diag_type); + break; + case DIAG_TYPE_FW_LOG: + return send_fw_diag_nl_data(datap, nl_data_len, + diag_type); + break; + } + /* Move to the next event and send to cnss-diag */ + datap += nl_data_len; + } + + return 0; +} + +static int +send_diag_netlink_data(const uint8_t *buffer, A_UINT32 len, A_UINT32 cmd) +{ + struct sk_buff *skb_out; + struct nlmsghdr *nlh; + int res = 0; + struct dbglog_slot *slot; + size_t slot_len; + tAniNlHdr *wnl; + int radio; + + if (WARN_ON(len > ATH6KL_FWLOG_PAYLOAD_SIZE)) + return -ENODEV; + + if (nl_srv_is_initialized() != 0) + return -EIO; + + radio = cds_get_radio_index(); + if (radio == -EINVAL) + return -EIO; + + if (cds_is_multicast_logging()) { + slot_len = sizeof(*slot) + ATH6KL_FWLOG_PAYLOAD_SIZE + + sizeof(radio); + + skb_out = nlmsg_new(slot_len, GFP_KERNEL); + if (!skb_out) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + ("Failed to allocate new skb\n")); + return -1; + } + + nlh = nlmsg_put(skb_out, 0, 0, WLAN_NL_MSG_CNSS_DIAG, + slot_len, 0); + if (!nlh) { + kfree_skb(skb_out); + return -EMSGSIZE; + } + wnl = (tAniNlHdr *)nlh; + wnl->radio = radio; + /* data buffer offset from: nlmsg_hdr + sizeof(int) radio */ + slot = (struct dbglog_slot *) (nlmsg_data(nlh) + sizeof(radio)); + slot->diag_type = cmd; + slot->timestamp = cpu_to_le32(jiffies); + slot->length = cpu_to_le32(len); + /* Version mapped to get_version here */ + slot->dropped = get_version; + memcpy(slot->payload, buffer, len); + + res = nl_srv_bcast(skb_out); + if ((res < 0) && (res != -ESRCH)) { + AR_DEBUG_PRINTF(ATH_DEBUG_RSVD1, + ("%s: nl_srv_bcast failed 0x%x\n", + __func__, res)); + return res; + } + } + return res; +} + +static int +dbglog_process_netlink_data(wmi_unified_t wmi_handle, const uint8_t *buffer, + A_UINT32 len, A_UINT32 dropped) +{ + struct sk_buff *skb_out; + struct nlmsghdr *nlh; + int res = 0; + struct dbglog_slot *slot; + size_t slot_len; + tAniNlHdr *wnl; + int radio; + + if (WARN_ON(len > ATH6KL_FWLOG_PAYLOAD_SIZE)) + return -ENODEV; + + if (nl_srv_is_initialized() != 0) + return -EIO; + + radio = cds_get_radio_index(); + if (radio == -EINVAL) + return -EIO; + + if (cds_is_multicast_logging()) { + slot_len = sizeof(*slot) + ATH6KL_FWLOG_PAYLOAD_SIZE + + sizeof(radio); + + skb_out = nlmsg_new(slot_len, GFP_KERNEL); + if (!skb_out) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + ("Failed to allocate new skb\n")); + return -1; + } + + nlh = nlmsg_put(skb_out, 0, 0, WLAN_NL_MSG_CNSS_DIAG, + slot_len, 0); + if (!nlh) { + kfree_skb(skb_out); + return -EMSGSIZE; + } + wnl = (tAniNlHdr *)nlh; + wnl->radio = radio; + /* data buffer offset from: nlmsg_hdr + sizeof(int) radio */ + slot = (struct dbglog_slot *) (nlmsg_data(nlh) + sizeof(radio)); + slot->diag_type = (A_UINT32) DIAG_TYPE_FW_DEBUG_MSG; + slot->timestamp = cpu_to_le32(jiffies); + slot->length = cpu_to_le32(len); + slot->dropped = cpu_to_le32(dropped); + memcpy(slot->payload, buffer, len); + + res = nl_srv_bcast(skb_out); + if ((res < 0) && (res != -ESRCH)) { + AR_DEBUG_PRINTF(ATH_DEBUG_RSVD1, + ("%s: nl_srv_ucast failed 0x%x\n", + __func__, res)); + return res; + } + } + return res; +} + +/* + * WMI diag data event handler, this function invoked as a CB + * when there DIAG_EVENT, DIAG_MSG, DIAG_DBG to be + * forwarded from the FW. This is the new implementation for + * replacement of fw_dbg and dbg messages + */ + +static int diag_fw_handler(ol_scn_t scn, uint8_t *data, uint32_t datalen) +{ + + tp_wma_handle wma = (tp_wma_handle) scn; + wmitlv_cmd_param_info *param_buf; + uint8_t *datap; + uint32_t len = 0; + uint32_t *buffer; + + if (!wma) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("NULL Pointer assigned\n")); + return -1; + } + /* when fw asser occurs,host can't use TLV format. */ + if (wma->is_fw_assert) { + datap = data; + len = datalen; + wma->is_fw_assert = 0; + } else { + param_buf = (wmitlv_cmd_param_info *) data; + if (!param_buf) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + ("Get NULL point message from FW\n")); + return -1; + } + + param_buf = (wmitlv_cmd_param_info *) data; + datap = param_buf->tlv_ptr; + len = param_buf->num_elements; + if (!get_version) { + buffer = (uint32_t *) datap; + buffer++; /* skip offset */ + if (WLAN_DIAG_TYPE_CONFIG == DIAG_GET_TYPE(*buffer)) { + buffer++; /* skip */ + if (DIAG_VERSION_INFO == DIAG_GET_ID(*buffer)) { + buffer++; /* skip */ + /* get payload */ + get_version = *buffer; + } + } + } + } + if (dbglog_process_type == DBGLOG_PROCESS_PRINT_RAW) { + if (!gprint_limiter) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("NOT Supported" + " only supports net link socket\n")); + gprint_limiter = true; + } + return 0; + } + + if (dbglog_process_type == DBGLOG_PROCESS_NET_RAW) { + return send_diag_netlink_data((A_UINT8 *) datap, + len, DIAG_TYPE_FW_MSG); + } +#ifdef WLAN_OPEN_SOURCE + if (dbglog_process_type == DBGLOG_PROCESS_POOL_RAW) { + if (!gprint_limiter) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("NOT Supported" + " only supports net link socket\n")); + gprint_limiter = true; + } + return 0; + } +#endif /* WLAN_OPEN_SOURCE */ + if (!gprint_limiter) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("NOT Supported" + " only supports net link socket\n")); + gprint_limiter = true; + } + /* Always returns zero */ + return 0; +} + +/* + * WMI diag data event handler, this function invoked as a CB + * when there DIAG_DATA to be forwarded from the FW. + */ +static int +fw_diag_data_event_handler(ol_scn_t scn, uint8_t *data, uint32_t datalen) +{ + + WMI_DIAG_DATA_CONTAINER_EVENTID_param_tlvs *param_buf; + uint8_t *datap; + uint32_t num_data; /* Total events */ + + param_buf = (WMI_DIAG_DATA_CONTAINER_EVENTID_param_tlvs *) data; + if (!param_buf) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + ("Got NULL point message from FW\n")); + return -1; + } + + num_data = param_buf->num_bufp; + + datap = (uint8_t *) param_buf->bufp; + + return process_fw_diag_event_data(datap, num_data); +} + +int dbglog_parse_debug_logs(ol_scn_t scn, uint8_t *data, uint32_t datalen) +{ + tp_wma_handle wma = (tp_wma_handle) scn; + A_UINT32 count; + A_UINT32 *buffer; + A_UINT32 timestamp; + A_UINT32 debugid; + A_UINT32 moduleid; + A_UINT16 vapid; + A_UINT16 numargs; + qdf_size_t length; + A_UINT32 dropped; + WMI_DEBUG_MESG_EVENTID_param_tlvs *param_buf; + uint8_t *datap; + uint32_t len; + + if (!wma) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, ("NULL Pointer assigned\n")); + return -1; + } + /*when fw asser occurs,host can't use TLV format. */ + if (wma->is_fw_assert) { + datap = data; + len = datalen; + wma->is_fw_assert = 0; + } else { + param_buf = (WMI_DEBUG_MESG_EVENTID_param_tlvs *) data; + if (!param_buf) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + ("Get NULL point message from FW\n")); + return -1; + } + + datap = param_buf->bufp; + len = param_buf->num_bufp; + } + + dropped = *((A_UINT32 *) datap); + if (dropped > 0) { + AR_DEBUG_PRINTF(ATH_DEBUG_TRC, + ("%d log buffers are dropped \n", dropped)); + } + datap += sizeof(dropped); + len -= sizeof(dropped); + + count = 0; + buffer = (A_UINT32 *) datap; + length = (len >> 2); + + if (dbglog_process_type == DBGLOG_PROCESS_PRINT_RAW) { + return dbglog_print_raw_data(buffer, length); + } + + if (dbglog_process_type == DBGLOG_PROCESS_NET_RAW) { + return dbglog_process_netlink_data((wmi_unified_t) wma-> + wmi_handle, + (A_UINT8 *) buffer, + len, dropped); + } +#ifdef WLAN_OPEN_SOURCE + if (dbglog_process_type == DBGLOG_PROCESS_POOL_RAW) { + return dbglog_debugfs_raw_data((wmi_unified_t) wma->wmi_handle, + (A_UINT8 *) buffer, len, + dropped); + } +#endif /* WLAN_OPEN_SOURCE */ + + while ((count + 2) < length) { + timestamp = DBGLOG_GET_TIME_STAMP(buffer[count]); + debugid = DBGLOG_GET_DBGID(buffer[count + 1]); + moduleid = DBGLOG_GET_MODULEID(buffer[count + 1]); + vapid = DBGLOG_GET_VDEVID(buffer[count + 1]); + numargs = DBGLOG_GET_NUMARGS(buffer[count + 1]); + + if ((count + 2 + numargs) > length) + return 0; + + if (moduleid >= WLAN_MODULE_ID_MAX) + return 0; + + if (mod_print[moduleid] == NULL) { + /* No module specific log registered use the default handler */ + dbglog_default_print_handler(moduleid, vapid, debugid, + timestamp, numargs, + (((A_UINT32 *) buffer) + + 2 + count)); + } else { + if (! + (mod_print[moduleid] + (moduleid, vapid, debugid, timestamp, numargs, + (((A_UINT32 *) buffer) + 2 + count)))) { + /* The message is not handled by the module specific handler */ + dbglog_default_print_handler(moduleid, vapid, + debugid, timestamp, + numargs, + (((A_UINT32 *) + buffer) + 2 + + count)); + + } + } + + count += numargs + 2; /* 32 bit Time stamp + 32 bit Dbg header */ + } + /* Always returns zero */ + return 0; +} + +void dbglog_reg_modprint(A_UINT32 mod_id, module_dbg_print printfn) +{ + if (!mod_print[mod_id]) { + mod_print[mod_id] = printfn; + } else { + AR_DEBUG_PRINTF(ATH_DEBUG_INFO, + ("module print is already registered for this module %d\n", + mod_id)); + } +} + +static void +dbglog_sm_print(A_UINT32 timestamp, + A_UINT16 vap_id, + A_UINT16 numargs, + A_UINT32 *args, + const char *module_prefix, + const char *states[], A_UINT32 num_states, + const char *events[], A_UINT32 num_events) +{ + A_UINT8 type, arg1, arg2, arg3; + A_UINT32 extra, extra2, extra3; + + if (numargs != 4) { + return; + } + + type = (args[0] >> 24) & 0xff; + arg1 = (args[0] >> 16) & 0xff; + arg2 = (args[0] >> 8) & 0xff; + arg3 = (args[0] >> 0) & 0xff; + + extra = args[1]; + extra2 = args[2]; + extra3 = args[3]; + + switch (type) { + case 0: /* state transition */ + if (arg1 < num_states && arg2 < num_states) { + dbglog_printf(timestamp, vap_id, + "%s: %s => %s (%#x, %#x, %#x)", + module_prefix, states[arg1], states[arg2], + extra, extra2, extra3); + } else { + dbglog_printf(timestamp, vap_id, + "%s: %u => %u (%#x, %#x, %#x)", + module_prefix, arg1, arg2, extra, extra2, + extra3); + } + break; + case 1: /* dispatch event */ + if (arg1 < num_states && arg2 < num_events) { + dbglog_printf(timestamp, vap_id, + "%s: %s < %s (%#x, %#x, %#x)", + module_prefix, states[arg1], events[arg2], + extra, extra2, extra3); + } else { + dbglog_printf(timestamp, vap_id, + "%s: %u < %u (%#x, %#x, %#x)", + module_prefix, arg1, arg2, extra, extra2, + extra3); + } + break; + case 2: /* warning */ + switch (arg1) { + case 0: /* unhandled event */ + if (arg2 < num_states && arg3 < num_events) { + dbglog_printf(timestamp, vap_id, + "%s: unhandled event %s in state %s (%#x, %#x, %#x)", + module_prefix, events[arg3], + states[arg2], extra, extra2, + extra3); + } else { + dbglog_printf(timestamp, vap_id, + "%s: unhandled event %u in state %u (%#x, %#x, %#x)", + module_prefix, arg3, arg2, extra, + extra2, extra3); + } + break; + default: + break; + + } + break; + } +} + +static A_BOOL +dbglog_sta_powersave_print_handler(A_UINT32 mod_id, + A_UINT16 vap_id, + A_UINT32 dbg_id, + A_UINT32 timestamp, + A_UINT16 numargs, A_UINT32 *args) +{ + static const char *states[] = { + "IDLE", + "ACTIVE", + "SLEEP_TXQ_FLUSH", + "SLEEP_TX_SENT", + "PAUSE", + "SLEEP_DOZE", + "SLEEP_AWAKE", + "ACTIVE_TXQ_FLUSH", + "ACTIVE_TX_SENT", + "PAUSE_TXQ_FLUSH", + "PAUSE_TX_SENT", + "IDLE_TXQ_FLUSH", + "IDLE_TX_SENT", + }; + + static const char *events[] = { + "START", + "STOP", + "PAUSE", + "UNPAUSE", + "TIM", + "DTIM", + "SEND_COMPLETE", + "PRE_SEND", + "RX", + "HWQ_EMPTY", + "PAUSE_TIMEOUT", + "TXRX_INACTIVITY_TIMEOUT", + "PSPOLL_TIMEOUT", + "UAPSD_TIMEOUT", + "DELAYED_SLEEP_TIMEOUT", + "SEND_N_COMPLETE", + "TIDQ_PAUSE_COMPLETE", + "SEND_PSPOLL", + "SEND_SPEC_PSPOLL", + }; + + switch (dbg_id) { + case DBGLOG_DBGID_SM_FRAMEWORK_PROXY_DBGLOG_MSG: + dbglog_sm_print(timestamp, vap_id, numargs, args, "STA PS", + states, QDF_ARRAY_SIZE(states), events, + QDF_ARRAY_SIZE(events)); + break; + case PS_STA_PM_ARB_REQUEST: + if (numargs == 4) { + dbglog_printf(timestamp, vap_id, + "PM ARB request flags=%x, last_time=%x %s: %s", + args[1], args[2], + dbglog_get_module_str(args[0]), + args[3] ? "SLEEP" : "WAKE"); + } + break; + case PS_STA_DELIVER_EVENT: + if (numargs == 2) { + dbglog_printf(timestamp, vap_id, "STA PS: %s %s", + (args[0] == 0 ? "PAUSE_COMPLETE" : + (args[0] == 1 ? "UNPAUSE_COMPLETE" : + (args[0] == 2 ? "SLEEP" : + (args[0] == + 3 ? "AWAKE" : "UNKNOWN")))), + (args[1] == + 0 ? "SUCCESS" : (args[1] == + 1 ? "TXQ_FLUSH_TIMEOUT" + : (args[1] == + 2 ? "NO_ACK" + : (args[1] == + 3 ? + "RX_LEAK_TIMEOUT" + : (args[1] == + 4 ? + "PSPOLL_UAPSD_BUSY_TIMEOUT" + : + "UNKNOWN")))))); + } + break; + case PS_STA_PSPOLL_SEQ_DONE: + if (numargs == 5) { + dbglog_printf(timestamp, vap_id, + "STA PS poll: queue=%u comp=%u rsp=%u rsp_dur=%u fc=%x qos=%x %s", + args[0], args[1], args[2], args[3], + (args[4] >> 16) & 0xffff, + (args[4] >> 8) & 0xff, + (args[4] & 0xff) == + 0 ? "SUCCESS" : (args[4] & 0xff) == + 1 ? "NO_ACK" : (args[4] & 0xff) == + 2 ? "DROPPED" : (args[4] & 0xff) == + 3 ? "FILTERED" : (args[4] & 0xff) == + 4 ? "RSP_TIMEOUT" : "UNKNOWN"); + } + break; + case PS_STA_COEX_MODE: + if (numargs == 1) { + dbglog_printf(timestamp, vap_id, "STA PS COEX MODE %s", + args[0] ? "ENABLED" : "DISABLED"); + } + break; + case PS_STA_PSPOLL_ALLOW: + if (numargs == 3) { + dbglog_printf(timestamp, vap_id, + "STA PS-Poll %s flags=%x time=%u", + args[0] ? "ALLOW" : "DISALLOW", args[1], + args[2]); + } + break; + case PS_STA_SET_PARAM: + if (numargs == 2) { + struct { + char *name; + int is_time_param; + } params[] = { + { + "MAX_SLEEP_ATTEMPTS", 0 + }, { + "DELAYED_SLEEP", 1 + }, { + "TXRX_INACTIVITY", 1 + }, { + "MAX_TX_BEFORE_WAKE", 0 + }, { + "UAPSD_TIMEOUT", 1 + }, { + "UAPSD_CONFIG", 0 + }, { + "PSPOLL_RESPONSE_TIMEOUT", 1 + }, { + "MAX_PSPOLL_BEFORE_WAKE", 0 + }, { + "RX_WAKE_POLICY", 0 + }, { + "DELAYED_PAUSE_RX_LEAK", 1 + }, { + "TXRX_INACTIVITY_BLOCKED_RETRY", 1 + }, { + "SPEC_WAKE_INTERVAL", 1 + }, { + "MAX_SPEC_NODATA_PSPOLL", 0 + }, { + "ESTIMATED_PSPOLL_RESP_TIME", 1 + }, { + "QPOWER_MAX_PSPOLL_BEFORE_WAKE", 0 + }, { + "QPOWER_ENABLE", 0 + }, + }; + A_UINT32 param = args[0]; + A_UINT32 value = args[1]; + + if (param < QDF_ARRAY_SIZE(params)) { + if (params[param].is_time_param) { + dbglog_printf(timestamp, vap_id, + "STA PS SET_PARAM %s => %u (us)", + params[param].name, + value); + } else { + dbglog_printf(timestamp, vap_id, + "STA PS SET_PARAM %s => %#x", + params[param].name, + value); + } + } else { + dbglog_printf(timestamp, vap_id, + "STA PS SET_PARAM %x => %#x", + param, value); + } + } + break; + case PS_STA_SPECPOLL_TIMER_STARTED: + dbglog_printf(timestamp, vap_id, + "SPEC Poll Timer Started: Beacon time Remaining:%d wakeup interval:%d", + args[0], args[1]); + break; + case PS_STA_SPECPOLL_TIMER_STOPPED: + dbglog_printf(timestamp, vap_id, "SPEC Poll Timer Stopped"); + break; + default: + return false; + } + + return true; +} + +/* IBSS PS sub modules */ +enum wlan_ibss_ps_sub_module { + WLAN_IBSS_PS_SUB_MODULE_IBSS_NW_SM = 0, + WLAN_IBSS_PS_SUB_MODULE_IBSS_SELF_PS = 1, + WLAN_IBSS_PS_SUB_MODULE_IBSS_PEER_PS = 2, + WLAN_IBSS_PS_SUB_MODULE_MAX = 3, +}; + +#define WLAN_IBSS_PS_SUB_MODULE_OFFSET 0x1E + +static A_BOOL +dbglog_ibss_powersave_print_handler(A_UINT32 mod_id, + A_UINT16 vap_id, + A_UINT32 dbg_id, + A_UINT32 timestamp, + A_UINT16 numargs, A_UINT32 *args) +{ + static const char *nw_states[] = { + "WAIT_FOR_TBTT", + "ATIM_WINDOW_PRE_BCN", + "ATIM_WINDOW_POST_BCN", + "OUT_OF_ATIM_WINDOW", + "PAUSE_PENDING", + "PAUSED", + }; + + static const char *ps_states[] = { + "ACTIVE", + "SLEEP_TX_SEND", + "SLEEP_DOZE_PAUSE_PENDING", + "SLEEP_DOZE", + "SLEEP_AWAKE", + "ACTIVE_TX_SEND", + "PAUSE_TX_SEND", + "PAUSED", + }; + + static const char *peer_ps_states[] = { + "ACTIVE", + "SLEEP_AWAKE", + "SLEEP_DOZE", + "PS_UNKNOWN", + }; + + static const char *events[] = { + "START", + "STOP", + "SWBA", + "TBTT", + "TX_BCN_CMP", + "SEND_COMPLETE", + "SEND_N_COMPLETE", + "PRE_SEND", + "RX", + "UC_INACTIVITY_TIMEOUT", + "BC_INACTIVITY_TIMEOUT", + "ATIM_WINDOW_BEGIN", + "ATIM_WINDOW_END", + "HWQ_EMPTY", + "UC_ATIM_RCVD", + "TRAFFIC_EXCHANGE_DONE", + "POWER_SAVE_STATE_CHANGE", + "NEW_PEER_JOIN", + "IBSS_VDEV_PAUSE_REQUEST", + "IBSS_VDEV_PAUSE_RESPONSE", + "IBSS_VDEV_PAUSE_TIMEOUT", + "IBSS_VDEV_UNPAUSE_REQUEST", + "PS_STATE_CHANGE", + }; + + enum wlan_ibss_ps_sub_module sub_module; + + switch (dbg_id) { + case DBGLOG_DBGID_SM_FRAMEWORK_PROXY_DBGLOG_MSG: + sub_module = (args[1] >> WLAN_IBSS_PS_SUB_MODULE_OFFSET) & 0x3; + switch (sub_module) { + case WLAN_IBSS_PS_SUB_MODULE_IBSS_NW_SM: + dbglog_sm_print(timestamp, vap_id, numargs, args, + "IBSS PS NW", nw_states, + QDF_ARRAY_SIZE(nw_states), events, + QDF_ARRAY_SIZE(events)); + break; + case WLAN_IBSS_PS_SUB_MODULE_IBSS_SELF_PS: + dbglog_sm_print(timestamp, vap_id, numargs, args, + "IBSS PS Self", ps_states, + QDF_ARRAY_SIZE(ps_states), events, + QDF_ARRAY_SIZE(events)); + break; + case WLAN_IBSS_PS_SUB_MODULE_IBSS_PEER_PS: + dbglog_sm_print(timestamp, vap_id, numargs, args, + "IBSS PS Peer", peer_ps_states, + QDF_ARRAY_SIZE(peer_ps_states), events, + QDF_ARRAY_SIZE(events)); + break; + default: + break; + } + break; + case IBSS_PS_DBGID_PEER_CREATE: + if (numargs == 2) { + dbglog_printf(timestamp, vap_id, + "IBSS PS: peer alloc failed for peer ID:%u", + args[0]); + } else if (numargs == 1) { + dbglog_printf(timestamp, vap_id, + "IBSS PS: create peer ID=%u", args[0]); + } + break; + case IBSS_PS_DBGID_PEER_DELETE: + if (numargs == 4) { + dbglog_printf(timestamp, vap_id, + "IBSS PS: delete peer ID=%u num_peers:%d num_sleeping_peers:%d ps_enabled_for_this_peer:%d", + args[0], args[1], args[2], args[3]); + } + break; + case IBSS_PS_DBGID_VDEV_CREATE: + if (numargs == 1) { + dbglog_printf(timestamp, vap_id, + "IBSS PS: vdev alloc failed", args[0]); + } else if (numargs == 0) { + dbglog_printf(timestamp, vap_id, + "IBSS PS: vdev created"); + } + break; + case IBSS_PS_DBGID_VDEV_DELETE: + dbglog_printf(timestamp, vap_id, "IBSS PS: vdev deleted"); + break; + + case IBSS_PS_DBGID_VDEV_EVENT: + if (numargs == 1) { + if (args[0] == 5) { + dbglog_printf(timestamp, vap_id, + "IBSS PS: vdev event for peer add"); + } else if (args[0] == 7) { + dbglog_printf(timestamp, vap_id, + "IBSS PS: vdev event for peer delete"); + } else { + dbglog_printf(timestamp, vap_id, + "IBSS PS: vdev event %u", + args[0]); + } + } + break; + + case IBSS_PS_DBGID_PEER_EVENT: + if (numargs == 4) { + if (args[0] == 0xFFFF) { + dbglog_printf(timestamp, vap_id, + "IBSS PS: pre_send for peer:%u peer_type:%u sm_event_mask:%0x", + args[1], args[3], args[2]); + } else if (args[0] == 0x20000) { + dbglog_printf(timestamp, vap_id, + "IBSS PS: send_complete for peer:%u peer_type:%u sm_event_mask:%0x", + args[1], args[3], args[2]); + } else if (args[0] == 0x10) { + dbglog_printf(timestamp, vap_id, + "IBSS PS: send_n_complete for peer:%u peer_type:%u sm_event_mask:%0x", + args[1], args[3], args[2]); + } else if (args[0] == 0x40) { + dbglog_printf(timestamp, vap_id, + "IBSS PS: rx event for peer:%u peer_type:%u sm_event_mask:%0x", + args[1], args[3], args[2]); + } else if (args[0] == 0x4) { + dbglog_printf(timestamp, vap_id, + "IBSS PS: hw_q_empty for peer:%u peer_type:%u sm_event_mask:%0x", + args[1], args[3], args[2]); + } + } + break; + + case IBSS_PS_DBGID_DELIVER_CAB: + if (numargs == 4) { + dbglog_printf(timestamp, vap_id, + "IBSS PS: Deliver CAB n_mpdu:%d send_flags:%0x tid_cur:%d q_depth_for_other_tid:%d", + args[0], args[1], args[2], args[3]); + } + break; + + case IBSS_PS_DBGID_DELIVER_UC_DATA: + if (numargs == 4) { + dbglog_printf(timestamp, vap_id, + "IBSS PS: Deliver UC data peer:%d tid:%d n_mpdu:%d send_flags:%0x", + args[0], args[1], args[2], args[3]); + } + break; + + case IBSS_PS_DBGID_DELIVER_UC_DATA_ERROR: + if (numargs == 4) { + dbglog_printf(timestamp, vap_id, + "IBSS PS: Deliver UC data error peer:%d tid:%d allowed_tidmask:%0x, pending_tidmap:%0x", + args[0], args[1], args[2], args[3]); + } + break; + + case IBSS_PS_DBGID_UC_INACTIVITY_TMR_RESTART: + if (numargs == 2) { + dbglog_printf(timestamp, vap_id, + "IBSS PS: UC timer restart peer:%d timer_val:%0x", + args[0], args[1]); + } + break; + + case IBSS_PS_DBGID_MC_INACTIVITY_TMR_RESTART: + if (numargs == 1) { + dbglog_printf(timestamp, vap_id, + "IBSS PS: MC timer restart timer_val:%0x", + args[0]); + } + break; + + case IBSS_PS_DBGID_NULL_TX_COMPLETION: + if (numargs == 3) { + dbglog_printf(timestamp, vap_id, + "IBSS PS: null tx completion peer:%d tx_completion_status:%d flags:%0x", + args[0], args[1], args[2]); + } + break; + + case IBSS_PS_DBGID_ATIM_TIMER_START: + if (numargs == 4) { + dbglog_printf(timestamp, vap_id, + "IBSS PS: ATIM timer start tsf:%0x %0x tbtt:%0x %0x", + args[0], args[1], args[2], args[3]); + } + break; + + case IBSS_PS_DBGID_UC_ATIM_SEND: + if (numargs == 2) { + dbglog_printf(timestamp, vap_id, + "IBSS PS: Send ATIM to peer:%d", args[1]); + } else if (numargs == 1) { + dbglog_printf(timestamp, vap_id, + "IBSS PS: no peers to send UC ATIM", + args[1]); + } + break; + + case IBSS_PS_DBGID_BC_ATIM_SEND: + if (numargs == 2) { + dbglog_printf(timestamp, vap_id, + "IBSS PS: MC Data, num_of_peers:%d bc_atim_sent:%d", + args[1], args[0]); + } + break; + + case IBSS_PS_DBGID_UC_TIMEOUT: + if (numargs == 2) { + dbglog_printf(timestamp, vap_id, + "IBSS PS: UC timeout for peer:%d send_null:%d", + args[0], args[1]); + } + break; + + case IBSS_PS_DBGID_PWR_COLLAPSE_ALLOWED: + dbglog_printf(timestamp, vap_id, + "IBSS PS: allow power collapse"); + break; + + case IBSS_PS_DBGID_PWR_COLLAPSE_NOT_ALLOWED: + if (numargs == 0) { + dbglog_printf(timestamp, vap_id, + "IBSS PS: power collapse not allowed by INI"); + } else if (numargs == 1) { + dbglog_printf(timestamp, vap_id, + "IBSS PS: power collapse not allowed since peer id:%d is not PS capable", + args[0]); + } else if (numargs == 2) { + dbglog_printf(timestamp, vap_id, + "IBSS PS: power collapse not allowed - no peers in NW"); + } else if (numargs == 3) { + if (args[0] == 2) { + dbglog_printf(timestamp, vap_id, + "IBSS PS: power collapse not allowed, non-zero qdepth %d %d", + args[1], args[2]); + } else if (args[0] == 3) { + dbglog_printf(timestamp, vap_id, + "IBSS PS: power collapse not allowed by peer:%d peer_flags:%0x", + args[1], args[2]); + } + } else if (numargs == 5) { + dbglog_printf(timestamp, vap_id, + "IBSS PS: power collapse not allowed by state m/c nw_cur_state:%d nw_next_state:%d ps_cur_state:%d flags:%0x", + args[1], args[2], args[3], args[4]); + } + break; + + case IBSS_PS_DBGID_SET_PARAM: + if (numargs == 2) { + dbglog_printf(timestamp, vap_id, + "IBSS PS: Set Param ID:%0x Value:%0x", + args[0], args[1]); + } + break; + + case IBSS_PS_DBGID_HOST_TX_PAUSE: + if (numargs == 1) { + dbglog_printf(timestamp, vap_id, + "IBSS PS: Pausing host, vdev_map:%0x", + args[0]); + } + break; + + case IBSS_PS_DBGID_HOST_TX_UNPAUSE: + if (numargs == 1) { + dbglog_printf(timestamp, vap_id, + "IBSS PS: Unpausing host, vdev_map:%0x", + args[0]); + } + break; + case IBSS_PS_DBGID_PS_DESC_BIN_LWM: + if (numargs == 1) { + dbglog_printf(timestamp, vap_id, + "IBSS PS: LWM, vdev_map:%0x", args[0]); + } + break; + + case IBSS_PS_DBGID_PS_DESC_BIN_HWM: + if (numargs == 1) { + dbglog_printf(timestamp, vap_id, + "IBSS PS: HWM, vdev_map:%0x", args[0]); + } + break; + + case IBSS_PS_DBGID_PS_KICKOUT_PEER: + if (numargs == 3) { + dbglog_printf(timestamp, vap_id, + "IBSS PS: Kickout peer id:%d atim_fail_cnt:%d status:%d", + args[0], args[1], args[2]); + } + break; + + case IBSS_PS_DBGID_SET_PEER_PARAM: + if (numargs == 3) { + dbglog_printf(timestamp, vap_id, + "IBSS PS: Set Peer Id:%d Param ID:%0x Value:%0x", + args[0], args[1], args[2]); + } + break; + + case IBSS_PS_DBGID_BCN_ATIM_WIN_MISMATCH: + if (numargs == 4) { + if (args[0] == 0xDEAD) { + dbglog_printf(timestamp, vap_id, + "IBSS PS: ATIM window length mismatch, our's:%d, peer id:%d, peer's:%d", + args[1], args[2], args[3]); + } else if (args[0] == 0xBEEF) { + dbglog_printf(timestamp, vap_id, + "IBSS PS: Peer ATIM window length changed, peer id:%d, peer recorded atim window:%d new atim window:%d", + args[1], args[2], args[3]); + } + } + break; + + case IBSS_PS_DBGID_RX_CHAINMASK_CHANGE: + if (numargs == 2) { + if (args[1] == 0x1) { + dbglog_printf(timestamp, vap_id, + "IBSS PS: Voting for low power chainmask from :%d", + args[0]); + } else { + dbglog_printf(timestamp, vap_id, + "IBSS PS: Voting for high power chainmask from :%d", + args[0]); + } + } + break; + + default: + return false; + } + + return true; +} + +static +A_BOOL dbglog_ratectrl_print_handler(A_UINT32 mod_id, + A_UINT16 vap_id, + A_UINT32 dbg_id, + A_UINT32 timestamp, + A_UINT16 numargs, A_UINT32 *args) +{ + switch (dbg_id) { + case RATECTRL_DBGID_ASSOC: + dbglog_printf(timestamp, vap_id, + "RATE: ChainMask %d, phymode %d, ni_flags 0x%08x, vht_mcs_set 0x%04x, ht_mcs_set 0x%04x", + args[0], args[1], args[2], args[3], args[4]); + break; + case RATECTRL_DBGID_NSS_CHANGE: + dbglog_printf(timestamp, vap_id, "RATE: NEW NSS %d\n", args[0]); + break; + case RATECTRL_DBGID_CHAINMASK_ERR: + dbglog_printf(timestamp, vap_id, + "RATE: Chainmask ERR %d %d %d\n", args[0], + args[1], args[2]); + break; + case RATECTRL_DBGID_UNEXPECTED_FRAME: + dbglog_printf(timestamp, vap_id, + "RATE: WARN1: rate %d flags 0x%08x\n", args[0], + args[1]); + break; + case RATECTRL_DBGID_WAL_RCQUERY: + dbglog_printf(timestamp, vap_id, + "ratectrl_dbgid_wal_rcquery [rix1 %d rix2 %d rix3 %d proberix %d ppduflag 0x%x] ", + args[0], args[1], args[2], args[3], args[4]); + break; + case RATECTRL_DBGID_WAL_RCUPDATE: + dbglog_printf(timestamp, vap_id, + "ratectrl_dbgid_wal_rcupdate [numelems %d ppduflag 0x%x] ", + args[0], args[1]); + break; + case RATECTRL_DBGID_GTX_UPDATE: + { + switch (args[0]) { + case 255: + dbglog_printf(timestamp, vap_id, + "GtxInitPwrCfg [bw[last %d|cur %d] rtcode 0x%x tpc %d tpc_init_pwr_cfg %d] ", + args[1] >> 8, args[1] & 0xff, + args[2], args[3], args[4]); + break; + case 254: + dbglog_printf(timestamp, vap_id, + "gtx_cfg_addr [RTMask0@0x%x PERThreshold@0x%x gtxTPCMin@0x%x userGtxMask@0x%x] ", + args[1], args[2], args[3], + args[4]); + break; + default: + dbglog_printf(timestamp, vap_id, + "gtx_update [act %d bw %d rix 0x%x tpc %d per %d lastrssi %d] ", + args[0], args[1], args[2], + args[3], args[4], args[5]); + } + } + break; + } + return true; +} + +static +A_BOOL dbglog_ani_print_handler(A_UINT32 mod_id, + A_UINT16 vap_id, + A_UINT32 dbg_id, + A_UINT32 timestamp, + A_UINT16 numargs, A_UINT32 *args) +{ + switch (dbg_id) { + case ANI_DBGID_ENABLE: + dbglog_printf(timestamp, vap_id, "ANI Enable: %d", args[0]); + break; + case ANI_DBGID_POLL: + dbglog_printf(timestamp, vap_id, + "ANI POLLING: AccumListenTime %d ListenTime %d ofdmphyerr %d cckphyerr %d", + args[0], args[1], args[2], args[3]); + break; + case ANI_DBGID_RESTART: + dbglog_printf(timestamp, vap_id, "ANI Restart"); + break; + case ANI_DBGID_CURRENT_LEVEL: + dbglog_printf(timestamp, vap_id, + "ANI CURRENT LEVEL ofdm level %d cck level %d", + args[0], args[1]); + break; + case ANI_DBGID_OFDM_LEVEL: + dbglog_printf(timestamp, vap_id, + "ANI UPDATE ofdm level %d firstep %d firstep_low %d cycpwr_thr %d self_corr_low %d", + args[0], args[1], args[2], args[3], args[4]); + break; + case ANI_DBGID_CCK_LEVEL: + dbglog_printf(timestamp, vap_id, + "ANI UPDATE cck level %d firstep %d firstep_low %d mrc_cck %d", + args[0], args[1], args[2], args[3]); + break; + case ANI_DBGID_CONTROL: + dbglog_printf(timestamp, vap_id, + "ANI CONTROL ofdmlevel %d ccklevel %d\n", + args[0]); + + break; + case ANI_DBGID_OFDM_PARAMS: + dbglog_printf(timestamp, vap_id, + "ANI ofdm_control firstep %d cycpwr %d\n", + args[0], args[1]); + break; + case ANI_DBGID_CCK_PARAMS: + dbglog_printf(timestamp, vap_id, + "ANI cck_control mrc_cck %d barker_threshold %d\n", + args[0], args[1]); + break; + case ANI_DBGID_RESET: + dbglog_printf(timestamp, vap_id, + "ANI resetting resetflag %d resetCause %8x channel index %d", + args[0], args[1], args[2]); + break; + case ANI_DBGID_SELF_CORR_LOW: + dbglog_printf(timestamp, vap_id, "ANI self_corr_low %d", + args[0]); + break; + case ANI_DBGID_FIRSTEP: + dbglog_printf(timestamp, vap_id, + "ANI firstep %d firstep_low %d", args[0], + args[1]); + break; + case ANI_DBGID_MRC_CCK: + dbglog_printf(timestamp, vap_id, "ANI mrc_cck %d", args[0]); + break; + case ANI_DBGID_CYCPWR: + dbglog_printf(timestamp, vap_id, "ANI cypwr_thresh %d", + args[0]); + break; + case ANI_DBGID_POLL_PERIOD: + dbglog_printf(timestamp, vap_id, + "ANI Configure poll period to %d", args[0]); + break; + case ANI_DBGID_LISTEN_PERIOD: + dbglog_printf(timestamp, vap_id, + "ANI Configure listen period to %d", args[0]); + break; + case ANI_DBGID_OFDM_LEVEL_CFG: + dbglog_printf(timestamp, vap_id, + "ANI Configure ofdm level to %d", args[0]); + break; + case ANI_DBGID_CCK_LEVEL_CFG: + dbglog_printf(timestamp, vap_id, + "ANI Configure cck level to %d", args[0]); + break; + default: + dbglog_printf(timestamp, vap_id, "ANI arg1 %d arg2 %d arg3 %d", + args[0], args[1], args[2]); + break; + } + return true; +} + +static A_BOOL +dbglog_ap_powersave_print_handler(A_UINT32 mod_id, + A_UINT16 vap_id, + A_UINT32 dbg_id, + A_UINT32 timestamp, + A_UINT16 numargs, A_UINT32 *args) +{ + switch (dbg_id) { + case AP_PS_DBGID_UPDATE_TIM: + if (numargs == 2) { + dbglog_printf(timestamp, vap_id, + "AP PS: TIM update AID=%u %s", + args[0], args[1] ? "set" : "clear"); + } + break; + case AP_PS_DBGID_PEER_STATE_CHANGE: + if (numargs == 2) { + dbglog_printf(timestamp, vap_id, + "AP PS: AID=%u power save %s", + args[0], + args[1] ? "enabled" : "disabled"); + } + break; + case AP_PS_DBGID_PSPOLL: + if (numargs == 3) { + dbglog_printf(timestamp, vap_id, + "AP PS: AID=%u pspoll response tid=%u flags=%x", + args[0], args[1], args[2]); + } + break; + case AP_PS_DBGID_PEER_CREATE: + if (numargs == 1) { + dbglog_printf(timestamp, vap_id, + "AP PS: create peer AID=%u", args[0]); + } + break; + case AP_PS_DBGID_PEER_DELETE: + if (numargs == 1) { + dbglog_printf(timestamp, vap_id, + "AP PS: delete peer AID=%u", args[0]); + } + break; + case AP_PS_DBGID_VDEV_CREATE: + dbglog_printf(timestamp, vap_id, "AP PS: vdev create"); + break; + case AP_PS_DBGID_VDEV_DELETE: + dbglog_printf(timestamp, vap_id, "AP PS: vdev delete"); + break; + case AP_PS_DBGID_SYNC_TIM: + if (numargs == 3) { + dbglog_printf(timestamp, vap_id, + "AP PS: AID=%u advertised=%#x buffered=%#x", + args[0], args[1], args[2]); + } + break; + case AP_PS_DBGID_NEXT_RESPONSE: + if (numargs == 4) { + dbglog_printf(timestamp, vap_id, + "AP PS: AID=%u select next response %s%s%s", + args[0], args[1] ? "(usp active) " : "", + args[2] ? "(pending usp) " : "", + args[3] ? "(pending poll response)" : ""); + } + break; + case AP_PS_DBGID_START_SP: + if (numargs == 3) { + dbglog_printf(timestamp, vap_id, + "AP PS: AID=%u START SP tsf=%#x (%u)", + args[0], args[1], args[2]); + } + break; + case AP_PS_DBGID_COMPLETED_EOSP: + if (numargs == 3) { + dbglog_printf(timestamp, vap_id, + "AP PS: AID=%u EOSP eosp_tsf=%#x trigger_tsf=%#x", + args[0], args[1], args[2]); + } + break; + case AP_PS_DBGID_TRIGGER: + if (numargs == 4) { + dbglog_printf(timestamp, vap_id, + "AP PS: AID=%u TRIGGER tsf=%#x %s%s", + args[0], args[1], + args[2] ? "(usp active) " : "", + args[3] ? "(send_n in progress)" : ""); + } + break; + case AP_PS_DBGID_DUPLICATE_TRIGGER: + if (numargs == 4) { + dbglog_printf(timestamp, vap_id, + "AP PS: AID=%u DUP TRIGGER tsf=%#x seq=%u ac=%u", + args[0], args[1], args[2], args[3]); + } + break; + case AP_PS_DBGID_UAPSD_RESPONSE: + if (numargs == 5) { + dbglog_printf(timestamp, vap_id, + "AP PS: AID=%u UAPSD response tid=%u, n_mpdu=%u flags=%#x max_sp=%u current_sp=%u", + args[0], args[1], args[2], args[3], + (args[4] >> 16) & 0xffff, + args[4] & 0xffff); + } + break; + case AP_PS_DBGID_SEND_COMPLETE: + if (numargs == 5) { + dbglog_printf(timestamp, vap_id, + "AP PS: AID=%u SEND_COMPLETE fc=%#x qos=%#x %s%s", + args[0], args[1], args[2], + args[3] ? "(usp active) " : "", + args[4] ? "(pending poll response)" : ""); + } + break; + case AP_PS_DBGID_SEND_N_COMPLETE: + if (numargs == 3) { + dbglog_printf(timestamp, vap_id, + "AP PS: AID=%u SEND_N_COMPLETE %s%s", + args[0], + args[1] ? "(usp active) " : "", + args[2] ? "(pending poll response)" : ""); + } + break; + case AP_PS_DBGID_DETECT_OUT_OF_SYNC_STA: + if (numargs == 4) { + dbglog_printf(timestamp, vap_id, + "AP PS: AID=%u detected out-of-sync now=%u tx_waiting=%u txq_depth=%u", + args[0], args[1], args[2], args[3]); + } + break; + case AP_PS_DBGID_DELIVER_CAB: + if (numargs == 4) { + dbglog_printf(timestamp, vap_id, + "AP PS: CAB %s n_mpdus=%u, flags=%x, extra=%u", + (args[0] == 17) ? "MGMT" : "DATA", + args[1], args[2], args[3]); + } + break; + default: + return false; + } + + return true; +} + +static A_BOOL +dbglog_wal_print_handler(A_UINT32 mod_id, + A_UINT16 vap_id, + A_UINT32 dbg_id, + A_UINT32 timestamp, A_UINT16 numargs, A_UINT32 *args) +{ + static const char *states[] = { + "ACTIVE", + "WAIT", + "WAIT_FILTER", + "PAUSE", + "PAUSE_SEND_N", + "BLOCK", + }; + + static const char *events[] = { + "PAUSE", + "PAUSE_FILTER", + "UNPAUSE", + + "BLOCK", + "BLOCK_FILTER", + "UNBLOCK", + + "HWQ_EMPTY", + "ALLOW_N", + }; + +#define WAL_VDEV_TYPE(type) \ + (type == 0 ? "AP" : \ + (type == 1 ? "STA" : \ + (type == 2 ? "IBSS" : \ + (type == 2 ? "MONITOR" : \ + "UNKNOWN")))) + +#define WAL_SLEEP_STATE(state) \ + (state == 1 ? "NETWORK SLEEP" : \ + (state == 2 ? "AWAKE" : \ + (state == 3 ? "SYSTEM SLEEP" : \ + "UNKNOWN"))) + + switch (dbg_id) { + case DBGLOG_DBGID_SM_FRAMEWORK_PROXY_DBGLOG_MSG: + dbglog_sm_print(timestamp, vap_id, numargs, args, "TID PAUSE", + states, QDF_ARRAY_SIZE(states), events, + QDF_ARRAY_SIZE(events)); + break; + case WAL_DBGID_SET_POWER_STATE: + if (numargs == 3) { + dbglog_printf(timestamp, vap_id, + "WAL %s => %s, req_count=%u", + WAL_SLEEP_STATE(args[0]), + WAL_SLEEP_STATE(args[1]), args[2]); + } + break; + case WAL_DBGID_CHANNEL_CHANGE_FORCE_RESET: + if (numargs == 4) { + dbglog_printf(timestamp, vap_id, + "WAL channel change (force reset) freq=%u, flags=%u mode=%u rx_ok=%u tx_ok=%u", + args[0] & 0x0000ffff, + (args[0] & 0xffff0000) >> 16, args[1], + args[2], args[3]); + } + break; + case WAL_DBGID_CHANNEL_CHANGE: + if (numargs == 2) { + dbglog_printf(timestamp, vap_id, + "WAL channel change freq=%u, mode=%u flags=%u rx_ok=1 tx_ok=1", + args[0] & 0x0000ffff, + (args[0] & 0xffff0000) >> 16, args[1]); + } + break; + case WAL_DBGID_VDEV_START: + if (numargs == 1) { + dbglog_printf(timestamp, vap_id, "WAL %s vdev started", + WAL_VDEV_TYPE(args[0])); + } + break; + case WAL_DBGID_VDEV_STOP: + dbglog_printf(timestamp, vap_id, "WAL %s vdev stopped", + WAL_VDEV_TYPE(args[0])); + break; + case WAL_DBGID_VDEV_UP: + dbglog_printf(timestamp, vap_id, "WAL %s vdev up, count=%u", + WAL_VDEV_TYPE(args[0]), args[1]); + break; + case WAL_DBGID_VDEV_DOWN: + dbglog_printf(timestamp, vap_id, "WAL %s vdev down, count=%u", + WAL_VDEV_TYPE(args[0]), args[1]); + break; + case WAL_DBGID_TX_MGMT_DESCID_SEQ_TYPE_LEN: + dbglog_printf(timestamp, vap_id, + "WAL Tx Mgmt frame desc_id=0x%x, seq=0x%x, type=0x%x, len=0x%x islocal=0x%x", + args[0], args[1], args[2], + (args[3] & 0xffff0000) >> 16, + args[3] & 0x0000ffff); + break; + case WAL_DBGID_TX_MGMT_COMP_DESCID_STATUS: + dbglog_printf(timestamp, vap_id, + "WAL Tx Mgmt frame completion desc_id=0x%x, status=0x%x, islocal=0x%x", + args[0], args[1], args[2]); + break; + case WAL_DBGID_TX_DATA_MSDUID_SEQ_TYPE_LEN: + dbglog_printf(timestamp, vap_id, + "WAL Tx Data frame msdu_id=0x%x, seq=0x%x, type=0x%x, len=0x%x", + args[0], args[1], args[2], args[3]); + break; + case WAL_DBGID_TX_DATA_COMP_MSDUID_STATUS: + dbglog_printf(timestamp, vap_id, + "WAL Tx Data frame completion desc_id=0x%x, status=0x%x, seq=0x%x", + args[0], args[1], args[2]); + break; + case WAL_DBGID_RESET_PCU_CYCLE_CNT: + dbglog_printf(timestamp, vap_id, + "WAL PCU cycle counter value at reset:%x", + args[0]); + break; + case WAL_DBGID_TX_DISCARD: + dbglog_printf(timestamp, vap_id, + "WAL Tx enqueue discard msdu_id=0x%x", args[0]); + break; + case WAL_DBGID_SET_HW_CHAINMASK: + dbglog_printf(timestamp, vap_id, "WAL_DBGID_SET_HW_CHAINMASK " + "pdev=%d, txchain=0x%x, rxchain=0x%x", + args[0], args[1], args[2]); + break; + case WAL_DBGID_SET_HW_CHAINMASK_TXRX_STOP_FAIL: + dbglog_printf(timestamp, vap_id, + "WAL_DBGID_SET_HW_CHAINMASK_TXRX_STOP_FAIL rxstop=%d, txstop=%d", + args[0], args[1]); + break; + case WAL_DBGID_GET_HW_CHAINMASK: + dbglog_printf(timestamp, vap_id, "WAL_DBGID_GET_HW_CHAINMASK " + "txchain=0x%x, rxchain=0x%x", args[0], args[1]); + break; + case WAL_DBGID_SMPS_DISABLE: + dbglog_printf(timestamp, vap_id, "WAL_DBGID_SMPS_DISABLE"); + break; + case WAL_DBGID_SMPS_ENABLE_HW_CNTRL: + dbglog_printf(timestamp, vap_id, + "WAL_DBGID_SMPS_ENABLE_HW_CNTRL low_pwr_mask=0x%x, high_pwr_mask=0x%x", + args[0], args[1]); + break; + case WAL_DBGID_SMPS_SWSEL_CHAINMASK: + dbglog_printf(timestamp, vap_id, + "WAL_DBGID_SMPS_SWSEL_CHAINMASK low_pwr=0x%x, chain_mask=0x%x", + args[0], args[1]); + break; + default: + return false; + } + + return true; +} + +static A_BOOL +dbglog_scan_print_handler(A_UINT32 mod_id, + A_UINT16 vap_id, + A_UINT32 dbg_id, + A_UINT32 timestamp, A_UINT16 numargs, A_UINT32 *args) +{ + static const char *states[] = { + "IDLE", + "BSSCHAN", + "WAIT_FOREIGN_CHAN", + "FOREIGN_CHANNEL", + "TERMINATING" + }; + + static const char *events[] = { + "REQ", + "STOP", + "BSSCHAN", + "FOREIGN_CHAN", + "CHECK_ACTIVITY", + "REST_TIME_EXPIRE", + "DWELL_TIME_EXPIRE", + "PROBE_TIME_EXPIRE", + }; + + switch (dbg_id) { + case DBGLOG_DBGID_SM_FRAMEWORK_PROXY_DBGLOG_MSG: + dbglog_sm_print(timestamp, vap_id, numargs, args, "SCAN", + states, QDF_ARRAY_SIZE(states), events, + QDF_ARRAY_SIZE(events)); + break; + default: + return false; + } + + return true; +} + +static +A_BOOL dbglog_coex_print_handler(A_UINT32 mod_id, + A_UINT16 vap_id, + A_UINT32 dbg_id, + A_UINT32 timestamp, + A_UINT16 numargs, A_UINT32 *args) +{ + A_UINT8 i; + char *dbg_id_str; + + static const char *wlan_rx_xput_status[] = { + "WLAN_XPUT_NORMAL", + "WLAN_XPUT_UNDER_THRESH", + "WLAN_XPUT_CRITICAL", + "WLAN_XPUT_RECOVERY_TIMEOUT", + }; + + static const char *coex_sched_req[] = { + "SCHED_REQ_NEXT", + "SCHED_REQ_BT", + "SCHED_REQ_WLAN", + "SCHED_REQ_POSTPAUSE", + "SCHED_REQ_UNPAUSE", + }; + + static const char *coex_sched_type[] = { + "SCHED_NONE", + "SCHED_WLAN", + "SCHED_BT", + "SCHED_WLAN_PAUSE", + "SCHED_WLAN_POSTPAUSE", + "SCHED_WLAN_UNPAUSE", + "COEX_SCHED_MWS", + }; + + static const char *coex_trf_mgmt_type[] = { + "TRF_MGMT_FREERUN", + "TRF_MGMT_SHAPE_PM", + "TRF_MGMT_SHAPE_PSP", + "TRF_MGMT_SHAPE_S_CTS", + "TRF_MGMT_SHAPE_OCS", + "TRF_MGMT_SHAPE_FIXED_TIME", + "TRF_MGMT_SHAPE_NOA", + "TRF_MGMT_SHAPE_OCS_CRITICAL", + "TRF_MGMT_NONE", + }; + + static const char *coex_system_status[] = { + "ALL_OFF", + "BTCOEX_NOT_REQD", + "WLAN_IS_IDLE", + "EXECUTE_SCHEME", + "BT_FULL_CONCURRENCY", + "WLAN_SLEEPING", + "WLAN_IS_PAUSED", + "WAIT_FOR_NEXT_ACTION", + "SOC_WAKE", + }; + + static const char *wlan_rssi_type[] = { + "LOW_RSSI", + "MID_RSSI", + "HI_RSSI", + "INVALID_RSSI", + }; + + static const char *coex_bt_scheme[] = { + "IDLE_CTRL", + "ACTIVE_ASYNC_CTRL", + "PASSIVE_SYNC_CTRL", + "ACTIVE_SYNC_CTRL", + "DEFAULT_CTRL", + "CONCURRENCY_CTRL", + }; + + static const char *wal_peer_rx_rate_stats_event_sent[] = { + "PR_RX_EVT_SENT_NONE", + "PR_RX_EVT_SENT_LOWER", + "PR_RX_EVT_SENT_UPPER", + }; + + static const char *wlan_psp_stimulus[] = { + "ENTRY", + "EXIT", + "PS_READY", + "PS_NOT_READY", + "RX_MORE_DATA_RCVD", + "RX_NO_MORE_DATA_RCVD", + "TX_DATA_COMPLT", + "TX_COMPLT", + "TIM_SET", + "REQ", + "DONE_SUCCESS", + "DONE_NO_PS_POLL_ACK", + "DONE_RESPONSE_TMO", + "DONE_DROPPED", + "DONE_FILTERED", + "WLAN_START", + "NONWLAN_START", + "NONWLAN_INTVL_UPDATE", + "NULL_TX", + "NULL_TX_COMPLT", + "BMISS_FIRST", + "NULL_TX_FAIL", + "RX_NO_MORE_DATA_DATAFRM", + }; + + static const char *coex_pspoll_state[] = { + "STATE_DISABLED", + "STATE_NOT_READY", + "STATE_ENABLED", + "STATE_READY", + "STATE_TX_STATUS", + "STATE_RX_STATUS", + }; + + static const char *coex_scheduler_interval[] = { + "COEX_SCHED_NONWLAN_INT", + "COEX_SCHED_WLAN_INT", + }; + + static const char *wlan_weight[] = { + "BT_COEX_BASE", + "BT_COEX_LOW", + "BT_COEX_MID", + "BT_COEX_MID_NONSYNC", + "BT_COEX_HI_NONVOICE", + "BT_COEX_HI", + "BT_COEX_CRITICAL", + }; + + static const char *wlan_power_state[] = { + "SLEEP", + "AWAKE", + "FULL_SLEEP", + }; + + static const char *coex_psp_error_type[] = { + "DISABLED_STATE", + "VDEV_NULL", + "COEX_PSP_ENTRY", + "ZERO_INTERVAL", + "COEX_PSP_EXIT", + "READY_DISABLED", + "READY_NOT_DISABLED", + "POLL_PKT_DROPPED", + "SET_TIMER_PARAM", + }; + + static const char *wlan_phymode[] = { + "A", + "G", + "B", + "G_ONLY", + "NA_HT20", + "NG_HT20", + "NA_HT40", + "NG_HT40", + "AC_VHT20", + "AC_VHT40", + "AC_VHT80", + "AC_VHT20_2G", + "AC_VHT40_2G", + "AC_VHT80_2G", + "UNKNOWN", + }; + + static const char *wlan_curr_band[] = { + "2G", + "5G", + }; + + dbg_id_str = dbglog_get_msg(mod_id, dbg_id); + + switch (dbg_id) { + case COEX_SYSTEM_UPDATE: + if (numargs == 1 && args[0] < 9) { + dbglog_printf(timestamp, vap_id, "%s: %s", dbg_id_str, + coex_system_status[args[0]]); + } else if (numargs >= 5 && args[0] < 9 && args[2] < 9) { + dbglog_printf(timestamp, vap_id, + "%s: %s, WlanSysState(0x%x), %s, NumChains(%u), AggrLimit(%u)", + dbg_id_str, coex_system_status[args[0]], + args[1], coex_trf_mgmt_type[args[2]], + args[3], args[4]); + } else { + return false; + } + break; + case COEX_SCHED_START: + if (numargs >= 5 && args[0] < 5 && args[2] < 9 && args[3] < 4 + && args[4] < 4) { + if (args[1] == 0xffffffff) { + dbglog_printf(timestamp, vap_id, + "%s: %s, DETERMINE_DURATION, %s, %s, %s", + dbg_id_str, + coex_sched_req[args[0]], + coex_trf_mgmt_type[args[2]], + wlan_rx_xput_status[args[3]], + wlan_rssi_type[args[4]]); + } else { + dbglog_printf(timestamp, vap_id, + "%s: %s, IntvlDur(%u), %s, %s, %s", + dbg_id_str, + coex_sched_req[args[0]], args[1], + coex_trf_mgmt_type[args[2]], + wlan_rx_xput_status[args[3]], + wlan_rssi_type[args[4]]); + } + } else { + return false; + } + break; + case COEX_SCHED_RESULT: + if (numargs >= 5 && args[0] < 5 && args[1] < 9 && args[2] < 9) { + dbglog_printf(timestamp, vap_id, + "%s: %s, %s, %s, CoexMgrPolicy(%u), IdleOverride(%u)", + dbg_id_str, coex_sched_req[args[0]], + coex_trf_mgmt_type[args[1]], + coex_trf_mgmt_type[args[2]], args[3], + args[4]); + } else { + return false; + } + break; + case COEX_BT_SCHEME: + if (numargs >= 1 && args[0] < 6) { + dbglog_printf(timestamp, vap_id, "%s: %s", dbg_id_str, + coex_bt_scheme[args[0]]); + } else { + return false; + } + break; + case COEX_TRF_FREERUN: + if (numargs >= 5 && args[0] < 7) { + dbglog_printf(timestamp, vap_id, + "%s: %s, AllocatedBtIntvls(%u), BtIntvlCnt(%u), AllocatedWlanIntvls(%u), WlanIntvlCnt(%u)", + dbg_id_str, coex_sched_type[args[0]], + args[1], args[2], args[3], args[4]); + } else { + return false; + } + break; + case COEX_TRF_SHAPE_PM: /* used by ocs now */ + if (numargs >= 3) { + dbglog_printf(timestamp, vap_id, + "%s: IntvlLength(%u), BtDuration(%u), WlanDuration(%u)", + dbg_id_str, args[0], args[1], args[2]); + } else { + return false; + } + break; + case COEX_SYSTEM_MONITOR: + if (numargs >= 5 && args[1] < 4 && args[4] < 4) { + dbglog_printf(timestamp, vap_id, + "%s: WlanRxCritical(%u), %s, MinDirectRxRate(%u), MonitorActiveNum(%u), %s", + dbg_id_str, args[0], + wlan_rx_xput_status[args[1]], args[2], + args[3], wlan_rssi_type[args[4]]); + } else { + return false; + } + break; + case COEX_RX_RATE: + if (numargs >= 5 && args[4] < 3) { + dbglog_printf(timestamp, vap_id, + "%s: NumUnderThreshPeers(%u), MinDirectRate(%u), LastRateSample(%u), DeltaT(%u), %s", + dbg_id_str, args[0], args[1], args[2], + args[3], + wal_peer_rx_rate_stats_event_sent[args + [4]]); + } else { + return false; + } + break; + case COEX_WLAN_INTERVAL_START: + if (numargs >= 5) { + dbglog_printf(timestamp, vap_id, + "%s: WlanIntvlCnt(%u), Duration(%u), Weight(%u), BaseIdleOverride(%u), WeightMat[0](0x%x)", + dbg_id_str, args[0], args[1], args[2], + args[3], args[4]); + } else { + return false; + } + break; + case COEX_WLAN_POSTPAUSE_INTERVAL_START: + if (numargs >= 4) { + dbglog_printf(timestamp, vap_id, + "%s: WlanPostPauseIntvlCnt(%u), XputMonitorActiveNum(%u), Duration(%u), Weight(%u)", + dbg_id_str, args[0], args[1], args[2], + args[3]); + } else { + return false; + } + break; + case COEX_BT_INTERVAL_START: + if (numargs >= 5) { + dbglog_printf(timestamp, vap_id, + "%s: BtIntvlCnt(%u), Duration(%u), Weight(%u), BaseIdleOverride(%u), WeightMat[0](0x%x), ", + dbg_id_str, args[0], args[1], args[2], + args[3], args[4]); + } else { + return false; + } + break; + case COEX_POWER_CHANGE: + if (numargs >= 3 && args[1] < 3 && args[2] < 3) { + dbglog_printf(timestamp, vap_id, + "%s: Event(0x%x) %s->%s", dbg_id_str, + args[0], wlan_power_state[args[1]], + wlan_power_state[args[2]]); + } else { + return false; + } + break; + case COEX_CHANNEL_CHANGE: + if (numargs >= 5 && args[3] < 2 && args[4] < 15) { + dbglog_printf(timestamp, vap_id, + "%s: %uMhz->%uMhz, WlanSysState(0x%x), CurrBand(%s), PhyMode(%s)", + dbg_id_str, args[0], args[1], args[2], + wlan_curr_band[args[3]], + wlan_phymode[args[4]]); + } else { + return false; + } + break; + case COEX_PSP_MGR_ENTER: + if (numargs >= 5 && args[0] < 23 && args[1] < 6 && args[3] < 2) { + dbglog_printf(timestamp, vap_id, + "%s: %s, %s, PsPollAvg(%u), %s, CurrT(%u)", + dbg_id_str, wlan_psp_stimulus[args[0]], + coex_pspoll_state[args[1]], args[2], + coex_scheduler_interval[args[3]], + args[4]); + } else { + return false; + } + break; + /* Translate following into decimal */ + case COEX_SINGLECHAIN_DBG_1: + case COEX_SINGLECHAIN_DBG_2: + case COEX_SINGLECHAIN_DBG_3: + case COEX_MULTICHAIN_DBG_1: + case COEX_MULTICHAIN_DBG_2: + case COEX_MULTICHAIN_DBG_3: + case BTCOEX_DBG_MCI_1: + case BTCOEX_DBG_MCI_2: + case BTCOEX_DBG_MCI_3: + case BTCOEX_DBG_MCI_4: + case BTCOEX_DBG_MCI_5: + case BTCOEX_DBG_MCI_6: + case BTCOEX_DBG_MCI_7: + case BTCOEX_DBG_MCI_8: + case BTCOEX_DBG_MCI_9: + case BTCOEX_DBG_MCI_10: + + if (numargs > 0) { + dbglog_printf_no_line_break(timestamp, vap_id, "%s: %u", + dbg_id_str, args[0]); + for (i = 1; i < numargs; i++) { + printk(", %u", args[i]); + } + printk("\n"); + } else { + return false; + } + break; + case COEX_LinkID: + if (numargs >= 4) { + if (args[0]) { /* Add profile */ + dbglog_printf(timestamp, vap_id, + "%s Alloc: LocalID(%u), RemoteID(%u), MinFreeLocalID(%u)", + dbg_id_str, args[1], args[2], + args[3]); + } else { /* Remove profile */ + dbglog_printf(timestamp, vap_id, + "%s Dealloc: LocalID(%u), RemoteID(%u), MinFreeLocalID(%u)", + dbg_id_str, args[1], args[2], + args[3]); + } + } else { + return false; + } + break; + case COEX_PSP_MGR_RESULT: + if (numargs >= 5 && args[0] < 6) { + dbglog_printf(timestamp, vap_id, + "%s: %s, PsPollAvg(%u), EstimationOverrun(%u), EstimationUnderun(%u), NotReadyErr(%u)", + dbg_id_str, coex_pspoll_state[args[0]], + args[1], args[2], args[3], args[4]); + } else { + return false; + } + break; + case COEX_TRF_SHAPE_PSP: + if (numargs >= 5 && args[0] < 7 && args[1] < 7) { + dbglog_printf(timestamp, vap_id, + "%s: %s, %s, Dur(%u), BtTriggerRecvd(%u), PspWlanCritical(%u)", + dbg_id_str, coex_sched_type[args[0]], + wlan_weight[args[1]], args[2], args[3], + args[4]); + } else { + return false; + } + break; + case COEX_PSP_SPEC_POLL: + if (numargs >= 5) { + dbglog_printf(timestamp, vap_id, + "%s: PsPollSpecEna(%u), Count(%u), NextTS(%u), AllowSpecPsPollTx(%u), Intvl(%u)", + dbg_id_str, args[0], args[1], args[2], + args[3], args[4]); + } else { + return false; + } + break; + case COEX_PSP_READY_STATE: + if (numargs >= 5) { + dbglog_printf(timestamp, vap_id, + "%s: T2NonWlan(%u), CoexSchedulerEndTS(%u), MoreData(%u), PSPRespExpectedTS(%u), NonWlanIdleT(%u)", + dbg_id_str, args[0], args[1], args[2], + args[3], args[4]); + } else { + return false; + } + break; + case COEX_PSP_NONWLAN_INTERVAL: + if (numargs >= 4) { + dbglog_printf(timestamp, vap_id, + "%s: NonWlanBaseIntvl(%u), NonWlanIdleT(%u), PSPSpecIntvl(%u), ApRespTimeout(%u)", + dbg_id_str, args[0], args[1], args[2], + args[3]); + } else { + return false; + } + break; + case COEX_PSP_ERROR: + if (numargs >= 1 && args[0] < 9) { + dbglog_printf_no_line_break(timestamp, vap_id, "%s: %s", + dbg_id_str, + coex_psp_error_type[args + [0]]); + for (i = 1; i < numargs; i++) { + AR_DEBUG_PRINTF(ATH_DEBUG_INFO, + (", %u", args[i])); + } + AR_DEBUG_PRINTF(ATH_DEBUG_INFO, ("\n")); + } else { + return false; + } + break; + case COEX_PSP_STAT_1: + if (numargs >= 5) { + dbglog_printf(timestamp, vap_id, + "%s: ApResp0(%u), ApResp1(%u), ApResp2(%u), ApResp3(%u), ApResp4(%u)", + dbg_id_str, args[0], args[1], args[2], + args[3], args[4]); + } else { + return false; + } + break; + case COEX_PSP_STAT_2: + if (numargs >= 5) { + dbglog_printf(timestamp, vap_id, + "%s: DataPt(%u), Max(%u), NextApRespIndex(%u), NumOfValidDataPts(%u), PsPollAvg(%u)", + dbg_id_str, args[0], args[1], args[2], + args[3], args[4]); + } else { + return false; + } + break; + case COEX_PSP_RX_STATUS_STATE_1: + if (numargs >= 5) { + if (args[2]) { + dbglog_printf(timestamp, vap_id, + "%s: RsExpectedTS(%u), RespActualTS(%u), Overrun, RsOverrunT(%u), RsRxDur(%u)", + dbg_id_str, args[0], args[1], + args[3], args[4]); + } else { + dbglog_printf(timestamp, vap_id, + "%s: RsExpectedTS(%u), RespActualTS(%u), Underrun, RsUnderrunT(%u), RsRxDur(%u)", + dbg_id_str, args[0], args[1], + args[3], args[4]); + } + } else { + return false; + } + break; + default: + return false; + } + + return true; +} + +static A_BOOL +dbglog_beacon_print_handler(A_UINT32 mod_id, + A_UINT16 vap_id, + A_UINT32 dbg_id, + A_UINT32 timestamp, + A_UINT16 numargs, A_UINT32 *args) +{ + static const char *states[] = { + "INIT", + "ADJUST_START", + "ADJUSTING", + "ADJUST_HOLD", + }; + + static const char *events[] = { + "ADJUST_START", + "ADJUST_RESTART", + "ADJUST_STOP", + "ADJUST_PAUSE", + "ADJUST_UNPAUSE", + "ADJUST_INC_SLOP_STEP", + "ADJUST_HOLD", + "ADJUST_HOLD_TIME_OUT", + }; + + switch (dbg_id) { + case DBGLOG_DBGID_SM_FRAMEWORK_PROXY_DBGLOG_MSG: + dbglog_sm_print(timestamp, vap_id, numargs, args, "EARLY_RX", + states, QDF_ARRAY_SIZE(states), events, + QDF_ARRAY_SIZE(events)); + break; + case BEACON_EVENT_EARLY_RX_BMISS_STATUS: + if (numargs == 3) { + dbglog_printf(timestamp, vap_id, + "early_rx bmiss status:rcv=%d total=%d miss=%d", + args[0], args[1], args[2]); + } + break; + case BEACON_EVENT_EARLY_RX_SLEEP_SLOP: + if (numargs == 1) { + dbglog_printf(timestamp, vap_id, + "early_rx update sleep_slop:%d", args[0]); + } + break; + case BEACON_EVENT_EARLY_RX_CONT_BMISS_TIMEOUT: + if (numargs == 1) { + dbglog_printf(timestamp, vap_id, + "early_rx cont bmiss timeout,update sleep_slop:%d", + args[0]); + } + break; + case BEACON_EVENT_EARLY_RX_PAUSE_SKIP_BCN_NUM: + if (numargs == 1) { + dbglog_printf(timestamp, vap_id, + "early_rx skip bcn num:%d", args[0]); + } + break; + case BEACON_EVENT_EARLY_RX_CLK_DRIFT: + if (numargs == 1) { + dbglog_printf(timestamp, vap_id, + "early_rx clk drift:%d", args[0]); + } + break; + case BEACON_EVENT_EARLY_RX_AP_DRIFT: + if (numargs == 1) { + dbglog_printf(timestamp, vap_id, + "early_rx ap drift:%d", args[0]); + } + break; + case BEACON_EVENT_EARLY_RX_BCN_TYPE: + if (numargs == 1) { + dbglog_printf(timestamp, vap_id, + "early_rx bcn type:%d", args[0]); + } + break; + default: + return false; + } + + return true; +} + +static A_BOOL +dbglog_data_txrx_print_handler(A_UINT32 mod_id, + A_UINT16 vap_id, + A_UINT32 dbg_id, + A_UINT32 timestamp, + A_UINT16 numargs, A_UINT32 *args) +{ + switch (dbg_id) { + case DATA_TXRX_DBGID_RX_DATA_SEQ_LEN_INFO: + dbglog_printf(timestamp, vap_id, + "DATA RX seq=0x%x, len=0x%x, stored=0x%x, duperr=0x%x", + args[0], args[1], (args[2] & 0xffff0000) >> 16, + args[2] & 0x0000ffff); + break; + default: + return false; + } + + return true; +} + +static +A_BOOL dbglog_smps_print_handler(A_UINT32 mod_id, + A_UINT16 vap_id, + A_UINT32 dbg_id, + A_UINT32 timestamp, + A_UINT16 numargs, A_UINT32 *args) +{ + static const char *states[] = { + "S_INACTIVE", + "S_STATIC", + "S_DYNAMIC", + "S_STALLED", + "S_INACTIVE_WAIT", + "S_STATIC_WAIT", + "S_DYNAMIC_WAIT", + }; + + static const char *events[] = { + "E_STOP", + "E_STOP_COMPL", + "E_START", + "E_STATIC", + "E_STATIC_COMPL", + "E_DYNAMIC", + "E_DYNAMIC_COMPL", + "E_STALL", + "E_RSSI_ABOVE_THRESH", + "E_RSSI_BELOW_THRESH", + "E_FORCED_NONE", + }; + switch (dbg_id) { + case DBGLOG_DBGID_SM_FRAMEWORK_PROXY_DBGLOG_MSG: + dbglog_sm_print(timestamp, vap_id, numargs, args, "STA_SMPS SM", + states, QDF_ARRAY_SIZE(states), events, + QDF_ARRAY_SIZE(events)); + break; + case STA_SMPS_DBGID_CREATE_PDEV_INSTANCE: + dbglog_printf(timestamp, vap_id, "STA_SMPS Create PDEV ctx %#x", + args[0]); + break; + case STA_SMPS_DBGID_CREATE_VIRTUAL_CHAN_INSTANCE: + dbglog_printf(timestamp, vap_id, + "STA_SMPS Create Virtual Chan ctx %#x", args[0]); + break; + case STA_SMPS_DBGID_DELETE_VIRTUAL_CHAN_INSTANCE: + dbglog_printf(timestamp, vap_id, + "STA_SMPS Delete Virtual Chan ctx %#x", args[0]); + break; + case STA_SMPS_DBGID_CREATE_STA_INSTANCE: + dbglog_printf(timestamp, vap_id, "STA_SMPS Create STA ctx %#x", + args[0]); + break; + case STA_SMPS_DBGID_DELETE_STA_INSTANCE: + dbglog_printf(timestamp, vap_id, "STA_SMPS Delete STA ctx %#x", + args[0]); + break; + case STA_SMPS_DBGID_VIRTUAL_CHAN_SMPS_START: + break; + case STA_SMPS_DBGID_VIRTUAL_CHAN_SMPS_STOP: + break; + case STA_SMPS_DBGID_SEND_SMPS_ACTION_FRAME: + dbglog_printf(timestamp, vap_id, + "STA_SMPS STA %#x Signal SMPS mode as %s; cb_flags %#x", + args[0], + (args[1] == + 0 ? "DISABLED" : (args[1] == + 0x1 ? "STATIC" : (args[1] == + 0x3 ? + "DYNAMIC" : + "UNKNOWN"))), + args[2]); + break; + case STA_SMPS_DBGID_DTIM_EBT_EVENT_CHMASK_UPDATE: + dbglog_printf(timestamp, vap_id, + "STA_SMPS_DBGID_DTIM_EBT_EVENT_CHMASK_UPDATE"); + break; + case STA_SMPS_DBGID_DTIM_CHMASK_UPDATE: + dbglog_printf(timestamp, vap_id, + "STA_SMPS_DBGID_DTIM_CHMASK_UPDATE " + "tx_mask %#x rx_mask %#x arb_dtim_mask %#x", + args[0], args[1], args[2]); + break; + case STA_SMPS_DBGID_DTIM_BEACON_EVENT_CHMASK_UPDATE: + dbglog_printf(timestamp, vap_id, + "STA_SMPS_DBGID_DTIM_BEACON_EVENT_CHMASK_UPDATE"); + break; + case STA_SMPS_DBGID_DTIM_POWER_STATE_CHANGE: + dbglog_printf(timestamp, vap_id, + "STA_SMPS_DBGID_DTIM_POWER_STATE_CHANGE cur_pwr_state %s new_pwr_state %s", + (args[0] == + 0x1 ? "SLEEP" : (args[0] == + 0x2 ? "AWAKE" : (args[0] == + 0x3 ? + "FULL_SLEEP" : + "UNKNOWN"))), + (args[1] == + 0x1 ? "SLEEP" : (args[1] == + 0x2 ? "AWAKE" : (args[1] == + 0x3 ? + "FULL_SLEEP" : + "UNKNOWN")))); + break; + case STA_SMPS_DBGID_DTIM_CHMASK_UPDATE_SLEEP: + dbglog_printf(timestamp, vap_id, + "STA_SMPS_DBGID_DTIM_CHMASK_UPDATE_SLEEP " + "tx_mask %#x rx_mask %#x orig_rx %#x dtim_rx %#x", + args[0], args[1], args[2], args[3]); + break; + case STA_SMPS_DBGID_DTIM_CHMASK_UPDATE_AWAKE: + dbglog_printf(timestamp, vap_id, + "STA_SMPS_DBGID_DTIM_CHMASK_UPDATE_AWAKE " + "tx_mask %#x rx_mask %#x orig_rx %#x", args[0], + args[1], args[2]); + break; + default: + dbglog_printf(timestamp, vap_id, "STA_SMPS: UNKNOWN DBGID!"); + return false; + } + + return true; +} + +static A_BOOL +dbglog_p2p_print_handler(A_UINT32 mod_id, + A_UINT16 vap_id, + A_UINT32 dbg_id, + A_UINT32 timestamp, A_UINT16 numargs, A_UINT32 *args) +{ + static const char *states[] = { + "ACTIVE", + "DOZE", + "TX_BCN", + "CTWIN", + "OPPPS", + }; + + static const char *events[] = { + "ONESHOT_NOA", + "CTWINDOW", + "PERIODIC_NOA", + "IDLE", + "NOA_CHANGED", + "TBTT", + "TX_BCN_CMP", + "OPPPS_OK", + "OPPPS_CHANGED", + }; + + switch (dbg_id) { + case DBGLOG_DBGID_SM_FRAMEWORK_PROXY_DBGLOG_MSG: + dbglog_sm_print(timestamp, vap_id, numargs, args, "P2P GO PS", + states, QDF_ARRAY_SIZE(states), events, + QDF_ARRAY_SIZE(events)); + break; + default: + return false; + } + + return true; +} + +static A_BOOL +dbglog_pcielp_print_handler(A_UINT32 mod_id, + A_UINT16 vap_id, + A_UINT32 dbg_id, + A_UINT32 timestamp, + A_UINT16 numargs, A_UINT32 *args) +{ + static const char *states[] = { + "STOP", + "TX", + "RX", + "SLEEP", + "SUSPEND", + }; + + static const char *events[] = { + "VDEV_UP", + "ALL_VDEV_DOWN", + "AWAKE", + "SLEEP", + "TX_ACTIVITY", + "TX_INACTIVITY", + "TX_AC_CHANGE", + "SUSPEND", + "RESUME", + }; + + switch (dbg_id) { + case DBGLOG_DBGID_SM_FRAMEWORK_PROXY_DBGLOG_MSG: + dbglog_sm_print(timestamp, vap_id, numargs, args, "PCIELP", + states, QDF_ARRAY_SIZE(states), events, + QDF_ARRAY_SIZE(events)); + break; + default: + return false; + } + + return true; +} + +#ifdef WLAN_OPEN_SOURCE +static int dbglog_block_open(struct inode *inode, struct file *file) +{ + struct fwdebug *fwlog = inode->i_private; + + if (fwlog->fwlog_open) + return -EBUSY; + + fwlog->fwlog_open = true; + + file->private_data = inode->i_private; + return 0; +} + +static int dbglog_block_release(struct inode *inode, struct file *file) +{ + struct fwdebug *fwlog = inode->i_private; + + fwlog->fwlog_open = false; + + return 0; +} + +static ssize_t dbglog_block_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct fwdebug *fwlog = file->private_data; + struct sk_buff *skb; + ssize_t ret_cnt; + size_t len = 0, not_copied; + char *buf; + int ret; + + buf = vmalloc(count); + if (!buf) + return -ENOMEM; + + spin_lock_bh(&fwlog->fwlog_queue.lock); + + if (skb_queue_len(&fwlog->fwlog_queue) == 0) { + /* we must init under queue lock */ + init_completion(&fwlog->fwlog_completion); + + spin_unlock_bh(&fwlog->fwlog_queue.lock); + + ret = + wait_for_completion_interruptible(&fwlog->fwlog_completion); + if (ret == -ERESTARTSYS) { + vfree(buf); + return ret; + } + + spin_lock_bh(&fwlog->fwlog_queue.lock); + } + + while ((skb = __skb_dequeue(&fwlog->fwlog_queue))) { + if (skb->len > count - len) { + /* not enough space, put skb back and leave */ + __skb_queue_head(&fwlog->fwlog_queue, skb); + break; + } + + memcpy(buf + len, skb->data, skb->len); + len += skb->len; + + kfree_skb(skb); + } + + spin_unlock_bh(&fwlog->fwlog_queue.lock); + + /* FIXME: what to do if len == 0? */ + not_copied = copy_to_user(user_buf, buf, len); + if (not_copied != 0) { + ret_cnt = -EFAULT; + goto out; + } + + *ppos = *ppos + len; + + ret_cnt = len; + +out: + vfree(buf); + + return ret_cnt; +} + +static const struct file_operations fops_dbglog_block = { + .open = dbglog_block_open, + .release = dbglog_block_release, + .read = dbglog_block_read, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + +static int dbglog_debugfs_init(wmi_unified_t wmi_handle) +{ + + wmi_handle->debugfs_phy = debugfs_create_dir(CLD_DEBUGFS_DIR, NULL); + if (!wmi_handle->debugfs_phy) + return -ENOMEM; + + debugfs_create_file(DEBUGFS_BLOCK_NAME, S_IRUSR, + wmi_handle->debugfs_phy, &wmi_handle->dbglog, + &fops_dbglog_block); + + return true; +} + +static int dbglog_debugfs_remove(wmi_unified_t wmi_handle) +{ + debugfs_remove_recursive(wmi_handle->debugfs_phy); + return true; +} +#endif /* WLAN_OPEN_SOURCE */ + +/**--------------------------------------------------------------------------- + \brief cnss_diag_msg_callback() - Call back invoked by netlink service + + This function gets invoked by netlink service when a message is recevied + from the cnss-diag application in user-space. + + \param - + - skb - skb with netlink message + + \return - 0 for success, non zero for failure + --------------------------------------------------------------------------*/ +static int cnss_diag_msg_callback(struct sk_buff *skb) +{ + struct nlmsghdr *nlh; + struct dbglog_slot *slot; + A_UINT8 *msg; + + nlh = (struct nlmsghdr *)skb->data; + if (!nlh) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + ("%s: Netlink header null \n", __func__)); + return -1; + } + + msg = NLMSG_DATA(nlh); + + slot = (struct dbglog_slot *)msg; + switch (slot->diag_type) { + case DIAG_TYPE_CRASH_INJECT: + if (slot->length == 2) { + AR_DEBUG_PRINTF(ATH_DEBUG_INFO, + ("%s : DIAG_TYPE_CRASH_INJECT: %d %d\n", + __func__, slot->payload[0], slot->payload[1])); + if (!tgt_assert_enable) { + AR_DEBUG_PRINTF(ATH_DEBUG_INFO, + ("%s: tgt Assert Disabled\n", + __func__)); + return 0; + } + wma_cli_set2_command(0, GEN_PARAM_CRASH_INJECT, + slot->payload[0], slot->payload[1], + GEN_CMD); + } else { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + ("crash_inject cmd error\n")); + } + break; + default: + break; + } + return 0; + +} + +/**--------------------------------------------------------------------------- + \brief cnss_diag_activate_service() - Activate cnss_diag message handler + + This function registers a handler to receive netlink message from + an cnss-diag application process. + + \param - + - None + + \return - 0 for success, non zero for failure + --------------------------------------------------------------------------*/ +int cnss_diag_activate_service(void) +{ + int ret = 0; + + /* Register the msg handler for msgs addressed to WLAN_NL_MSG_OEM */ + ret = nl_srv_register(WLAN_NL_MSG_CNSS_DIAG, cnss_diag_msg_callback); + if (ret) { + AR_DEBUG_PRINTF(ATH_DEBUG_ERR, + ("CNSS-DIAG Registration failed")); + return ret; + } + return 0; +} + +static A_BOOL +dbglog_wow_print_handler(A_UINT32 mod_id, + A_UINT16 vap_id, + A_UINT32 dbg_id, + A_UINT32 timestamp, A_UINT16 numargs, A_UINT32 *args) +{ + + switch (dbg_id) { + case WOW_NS_OFLD_ENABLE: + if (4 == numargs) { + dbglog_printf(timestamp, vap_id, + "Enable NS offload, for sender %02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x", + *(A_UINT8 *) &args[0], + *((A_UINT8 *) &args[0] + 1), + *((A_UINT8 *) &args[0] + 2), + *((A_UINT8 *) &args[0] + 3), + *(A_UINT8 *) &args[1], + *((A_UINT8 *) &args[1] + 1), + *((A_UINT8 *) &args[1] + 2), + *((A_UINT8 *) &args[1] + 3), + *(A_UINT8 *) &args[2], + *((A_UINT8 *) &args[2] + 1), + *((A_UINT8 *) &args[2] + 2), + *((A_UINT8 *) &args[2] + 3), + *(A_UINT8 *) &args[3], + *((A_UINT8 *) &args[3] + 1), + *((A_UINT8 *) &args[3] + 2), + *((A_UINT8 *) &args[3] + 3)); + } else { + return false; + } + break; + case WOW_ARP_OFLD_ENABLE: + if (1 == numargs) { + dbglog_printf(timestamp, vap_id, + "Enable ARP offload, for sender %d.%d.%d.%d", + *(A_UINT8 *) args, + *((A_UINT8 *) args + 1), + *((A_UINT8 *) args + 2), + *((A_UINT8 *) args + 3)); + } else { + return false; + } + break; + case WOW_NS_ARP_OFLD_DISABLE: + if (0 == numargs) { + dbglog_printf(timestamp, vap_id, + "disable NS/ARP offload"); + } else { + return false; + } + break; + case WOW_NS_RECEIVED: + if (4 == numargs) { + dbglog_printf(timestamp, vap_id, + "NS requested from %02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x", + *(A_UINT8 *) &args[0], + *((A_UINT8 *) &args[0] + 1), + *((A_UINT8 *) &args[0] + 2), + *((A_UINT8 *) &args[0] + 3), + *(A_UINT8 *) &args[1], + *((A_UINT8 *) &args[1] + 1), + *((A_UINT8 *) &args[1] + 2), + *((A_UINT8 *) &args[1] + 3), + *(A_UINT8 *) &args[2], + *((A_UINT8 *) &args[2] + 1), + *((A_UINT8 *) &args[2] + 2), + *((A_UINT8 *) &args[2] + 3), + *(A_UINT8 *) &args[3], + *((A_UINT8 *) &args[3] + 1), + *((A_UINT8 *) &args[3] + 2), + *((A_UINT8 *) &args[3] + 3)); + } else { + return false; + } + break; + case WOW_NS_REPLIED: + if (4 == numargs) { + dbglog_printf(timestamp, vap_id, + "NS replied to %02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x", + *(A_UINT8 *) &args[0], + *((A_UINT8 *) &args[0] + 1), + *((A_UINT8 *) &args[0] + 2), + *((A_UINT8 *) &args[0] + 3), + *(A_UINT8 *) &args[1], + *((A_UINT8 *) &args[1] + 1), + *((A_UINT8 *) &args[1] + 2), + *((A_UINT8 *) &args[1] + 3), + *(A_UINT8 *) &args[2], + *((A_UINT8 *) &args[2] + 1), + *((A_UINT8 *) &args[2] + 2), + *((A_UINT8 *) &args[2] + 3), + *(A_UINT8 *) &args[3], + *((A_UINT8 *) &args[3] + 1), + *((A_UINT8 *) &args[3] + 2), + *((A_UINT8 *) &args[3] + 3)); + } else { + return false; + } + break; + case WOW_ARP_RECEIVED: + if (1 == numargs) { + dbglog_printf(timestamp, vap_id, + "ARP requested from %d.%d.%d.%d", + *(A_UINT8 *) args, + *((A_UINT8 *) args + 1), + *((A_UINT8 *) args + 2), + *((A_UINT8 *) args + 3)); + } else { + return false; + } + break; + break; + case WOW_ARP_REPLIED: + if (1 == numargs) { + dbglog_printf(timestamp, vap_id, + "ARP replied to %d.%d.%d.%d", + *(A_UINT8 *) args, + *((A_UINT8 *) args + 1), + *((A_UINT8 *) args + 2), + *((A_UINT8 *) args + 3)); + } else { + return false; + } + break; + default: + return false; + } + + return true; +} + +int dbglog_parser_type_init(wmi_unified_t wmi_handle, int type) +{ + if (type >= DBGLOG_PROCESS_MAX) { + return A_ERROR; + } + + dbglog_process_type = type; + gprint_limiter = false; + + return A_OK; +} + +int dbglog_init(wmi_unified_t wmi_handle) +{ + int res = 0; + OS_MEMSET(mod_print, 0, sizeof(mod_print)); + + dbglog_reg_modprint(WLAN_MODULE_STA_PWRSAVE, + dbglog_sta_powersave_print_handler); + dbglog_reg_modprint(WLAN_MODULE_AP_PWRSAVE, + dbglog_ap_powersave_print_handler); + dbglog_reg_modprint(WLAN_MODULE_WAL, dbglog_wal_print_handler); + dbglog_reg_modprint(WLAN_MODULE_SCAN, dbglog_scan_print_handler); + dbglog_reg_modprint(WLAN_MODULE_RATECTRL, + dbglog_ratectrl_print_handler); + dbglog_reg_modprint(WLAN_MODULE_ANI, dbglog_ani_print_handler); + dbglog_reg_modprint(WLAN_MODULE_COEX, dbglog_coex_print_handler); + dbglog_reg_modprint(WLAN_MODULE_BEACON, dbglog_beacon_print_handler); + dbglog_reg_modprint(WLAN_MODULE_WOW, dbglog_wow_print_handler); + dbglog_reg_modprint(WLAN_MODULE_DATA_TXRX, + dbglog_data_txrx_print_handler); + dbglog_reg_modprint(WLAN_MODULE_STA_SMPS, dbglog_smps_print_handler); + dbglog_reg_modprint(WLAN_MODULE_P2P, dbglog_p2p_print_handler); + dbglog_reg_modprint(WLAN_MODULE_PCIELP, dbglog_pcielp_print_handler); + dbglog_reg_modprint(WLAN_MODULE_IBSS_PWRSAVE, + dbglog_ibss_powersave_print_handler); + tgt_assert_enable = wmi_handle->tgt_force_assert_enable; + + /* Register handler for F3 or debug messages */ + res = + wmi_unified_register_event_handler(wmi_handle, + WMI_DEBUG_MESG_EVENTID, + dbglog_parse_debug_logs, + WMA_RX_WORK_CTX); + if (res != 0) + return res; + + /* Register handler for FW diag events */ + res = wmi_unified_register_event_handler(wmi_handle, + WMI_DIAG_DATA_CONTAINER_EVENTID, + fw_diag_data_event_handler, + WMA_RX_WORK_CTX); + if (res != 0) + return res; + + /* Register handler for new FW diag Event, LOG, MSG combined */ + res = wmi_unified_register_event_handler(wmi_handle, WMI_DIAG_EVENTID, + diag_fw_handler, + WMA_RX_WORK_CTX); + if (res != 0) + return res; + +#ifdef WLAN_OPEN_SOURCE + /* Initialize the fw debug log queue */ + skb_queue_head_init(&wmi_handle->dbglog.fwlog_queue); + init_completion(&wmi_handle->dbglog.fwlog_completion); + + /* Initialize debugfs */ + dbglog_debugfs_init(wmi_handle); +#endif /* WLAN_OPEN_SOURCE */ + + return res; +} + +int dbglog_deinit(wmi_unified_t wmi_handle) +{ + int res = 0; + +#ifdef WLAN_OPEN_SOURCE + /* DeInitialize the fw debug log queue */ + skb_queue_purge(&wmi_handle->dbglog.fwlog_queue); + complete(&wmi_handle->dbglog.fwlog_completion); + + /* Deinitialize the debugfs */ + dbglog_debugfs_remove(wmi_handle); +#endif /* WLAN_OPEN_SOURCE */ + tgt_assert_enable = 0; + + res = + wmi_unified_unregister_event_handler(wmi_handle, + WMI_DEBUG_MESG_EVENTID); + if (res != 0) + return res; + + return res; +} diff --git a/drivers/staging/qcacld-3.0/core/utils/fwlog/dbglog_host.h b/drivers/staging/qcacld-3.0/core/utils/fwlog/dbglog_host.h new file mode 100644 index 0000000000000000000000000000000000000000..3d7fd2827a85b0de3ead8edf9213eefb115beaa7 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/utils/fwlog/dbglog_host.h @@ -0,0 +1,174 @@ +/* + * Copyright (c) 2011, 2014-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef _DBGLOG_HOST_H_ +#define _DBGLOG_HOST_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "dbglog_common.h" +#include "ol_defines.h" + +#define DIAG_FWID_OFFSET 24 +#define DIAG_FWID_MASK 0xFF000000 /* Bit 24-31 */ + +#define DIAG_TIMESTAMP_OFFSET 0 +#define DIAG_TIMESTAMP_MASK 0x00FFFFFF /* Bit 0-23 */ + +#define DIAG_ID_OFFSET 16 +#define DIAG_ID_MASK 0xFFFF0000 /* Bit 16-31 */ + +#define DIAG_VDEVID_OFFSET 11 +#define DIAG_VDEVID_MASK 0x0000F800 /* Bit 11-15 */ +#define DIAG_VDEVID_NUM_MAX 16 + +#define DIAG_VDEVLEVEL_OFFSET 8 +#define DIAG_VDEVLEVEL_MASK 0x00000700 /* Bit 8-10 */ + +#define DIAG_PAYLEN_OFFSET 0 +#define DIAG_PAYLEN_MASK 0x000000FF /* Bit 0-7 */ + +#define DIAG_PAYLEN_OFFSET16 0 +#define DIAG_PAYLEN_MASK16 0x0000FFFF /* Bit 0-16 */ + +#define DIAG_GET_TYPE(arg) \ + ((arg & DIAG_FWID_MASK) >> DIAG_FWID_OFFSET) + +#define DIAG_GET_TIME_STAMP(arg) \ + ((arg & DIAG_TIMESTAMP_MASK) >> DIAG_TIMESTAMP_OFFSET) + +#define DIAG_GET_ID(arg) \ + ((arg & DIAG_ID_MASK) >> DIAG_ID_OFFSET) + +#define DIAG_GET_VDEVID(arg) \ + ((arg & DIAG_VDEVID_MASK) >> DIAG_VDEVID_OFFSET) + +#define DIAG_GET_VDEVLEVEL(arg) \ + ((arg & DIAG_VDEVLEVEL_MASK) >> DIAG_VDEVLEVEL_OFFSET) + +#define DIAG_GET_PAYLEN(arg) \ + ((arg & DIAG_PAYLEN_MASK) >> DIAG_PAYLEN_OFFSET) + +#define DIAG_GET_PAYLEN16(arg) \ + ((arg & DIAG_PAYLEN_MASK16) >> DIAG_PAYLEN_OFFSET16) + +/* + * set the dbglog parser type + */int +dbglog_parser_type_init(wmi_unified_t wmi_handle, int type); + +/** dbglog_int - Registers a WMI event handle for WMI_DBGMSG_EVENT + * @brief wmi_handle - handle to wmi module + */ +int +dbglog_init(wmi_unified_t wmi_handle); + +/** dbglog_deinit - UnRegisters a WMI event handle for WMI_DBGMSG_EVENT + * @brief wmi_handle - handle to wmi module + */ +int +dbglog_deinit(wmi_unified_t wmi_handle); + +/** set the size of the report size + * @brief wmi_handle - handle to Wmi module + * @brief size - Report size + */ +int +dbglog_set_report_size(wmi_unified_t wmi_handle, A_UINT16 size); + +/** Set the resolution for time stamp + * @brief wmi_handle - handle to Wmi module + * @ brief tsr - time stamp resolution + */ +int +dbglog_set_timestamp_resolution(wmi_unified_t wmi_handle, + A_UINT16 tsr); + +/** Enable reporting. If it is set to false then Traget wont deliver + * any debug information + */ +int +dbglog_report_enable(wmi_unified_t wmi_handle, A_BOOL isenable); + +/** Set the log level + * @brief DBGLOG_INFO - Information lowest log level + * @brief DBGLOG_WARNING + * @brief DBGLOG_ERROR - default log level + */ +int +dbglog_set_log_lvl(wmi_unified_t wmi_handle, enum DBGLOG_LOG_LVL log_lvl); + +/* + * set the debug log level for a given module + * mod_id_lvl : the format is more user friendly. + * module_id = mod_id_lvl/10; + * log_level = mod_id_lvl%10; + * example : mod_id_lvl is 153. then module id is 15 and log level is 3. this format allows + * user to pass a sinlge value (which is the most convenient way for most of the OSs) + * to be passed from user to the driver. + */ +int +dbglog_set_mod_log_lvl(wmi_unified_t wmi_handle, A_UINT32 mod_id_lvl); + +/** Enable/Disable the logging for VAP */ +int +dbglog_vap_log_enable(wmi_unified_t wmi_handle, A_UINT16 vap_id, + A_BOOL isenable); +/** Enable/Disable logging for Module */ +int +dbglog_module_log_enable(wmi_unified_t wmi_handle, A_UINT32 mod_id, + A_BOOL isenable); + +/** set vap enablie bitmap */ +void +dbglog_set_vap_enable_bitmap(wmi_unified_t wmi_handle, + A_UINT32 vap_enable_bitmap); + +/** set log level for all the modules specified in the bitmap. for all other modules + * with 0 in the bitmap (or) outside the bitmap , the log level be reset to DBGLOG_ERR. + */ +void +dbglog_set_mod_enable_bitmap(wmi_unified_t wmi_handle, + A_UINT32 log_level, + A_UINT32 *mod_enable_bitmap, + A_UINT32 bitmap_len); + +int +dbglog_parse_debug_logs(ol_scn_t scn, u_int8_t *datap, + u_int32_t len); + + +/** Register the cnss_diag activate with the wlan driver */ +int cnss_diag_activate_service(void); + +#ifdef __cplusplus +} +#endif + +#endif /* _DBGLOG_HOST_H_ */ diff --git a/drivers/staging/qcacld-3.0/core/utils/host_diag_log/inc/host_diag_core_event.h b/drivers/staging/qcacld-3.0/core/utils/host_diag_log/inc/host_diag_core_event.h new file mode 100644 index 0000000000000000000000000000000000000000..085e2dcf8baf93b4dcefcdeb221f3b59cc79b1c2 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/utils/host_diag_log/inc/host_diag_core_event.h @@ -0,0 +1,636 @@ +/* + * Copyright (c) 2014-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#if !defined(__HOST_DIAG_CORE_EVENT_H) +#define __HOST_DIAG_CORE_EVENT_H + +/**========================================================================= + + \file host_diag_core_event.h + + \brief WLAN UTIL host DIAG Events + + Definitions for DIAG Events + + ========================================================================*/ + +/* $Header$ */ + +/*-------------------------------------------------------------------------- + Include Files + ------------------------------------------------------------------------*/ +#include "qdf_types.h" +#include "cds_pack_align.h" +#include "i_host_diag_core_event.h" + +/*-------------------------------------------------------------------------- + Preprocessor definitions and constants + ------------------------------------------------------------------------*/ +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#define WAKE_LOCK_NAME_LEN 80 + +/*------------------------------------------------------------------------- + Event ID: EVENT_WLAN_SECURITY + ------------------------------------------------------------------------*/ +typedef struct { + uint8_t eventId; + uint8_t authMode; + uint8_t encryptionModeUnicast; + uint8_t encryptionModeMulticast; + uint8_t pmkIDMatch; + uint8_t bssid[6]; + uint8_t keyId; + uint8_t status; +} host_event_wlan_security_payload_type; + +/*------------------------------------------------------------------------- + Event ID: EVENT_WLAN_STATUS_V2 + ------------------------------------------------------------------------*/ +typedef struct { + uint8_t eventId; + uint8_t ssid[32]; + uint8_t bssType; + uint8_t rssi; + uint8_t channel; + uint8_t qosCapability; + uint8_t authType; + uint8_t encryptionType; + uint8_t reason; + uint8_t reasonDisconnect; +} host_event_wlan_status_payload_type; + +/*------------------------------------------------------------------------- + Event ID: EVENT_WLAN_HANDOFF + ------------------------------------------------------------------------*/ +typedef struct { + uint8_t eventId; + uint8_t currentApBssid[6]; + uint8_t currentApRssi; + uint8_t candidateApBssid[6]; + uint8_t candidateApRssi; +} host_event_wlan_handoff_payload_type; + +/*------------------------------------------------------------------------- + Event ID: EVENT_WLAN_VCC + ------------------------------------------------------------------------*/ +typedef struct { + uint8_t eventId; + uint8_t rssi; + uint8_t txPer; + uint8_t rxPer; + int linkQuality; +} host_event_wlan_vcc_payload_type; + +/*------------------------------------------------------------------------- + Event ID: EVENT_WLAN_QOS + ------------------------------------------------------------------------*/ +typedef struct { + uint8_t eventId; + uint8_t reasonCode; +} host_event_wlan_qos_payload_type; + +/*------------------------------------------------------------------------- + Event ID: EVENT_WLAN_PE + ------------------------------------------------------------------------*/ +typedef struct { + char bssid[6]; + uint16_t event_type; + uint16_t sme_state; + uint16_t mlm_state; + uint16_t status; + uint16_t reason_code; +} host_event_wlan_pe_payload_type; + +/*------------------------------------------------------------------------- + Event ID: EVENT_WLAN_ADD_BLOCK_ACK_SUCCESS + ------------------------------------------------------------------------*/ +typedef struct { + char ucBaPeerMac[6]; + uint8_t ucBaTid; + uint8_t ucBaBufferSize; + uint16_t usBaSSN; + uint8_t fInitiator; +} host_event_wlan_add_block_ack_success_payload_type; + +/*------------------------------------------------------------------------- + Event ID: EVENT_WLAN_ADD_BLOCK_ACK_FAILED + ------------------------------------------------------------------------*/ +typedef struct { + char ucBaPeerMac[6]; + uint8_t ucBaTid; + uint8_t ucReasonCode; + uint8_t fInitiator; +} host_event_wlan_add_block_ack_failed_payload_type; + +/*------------------------------------------------------------------------- + Event ID: EVENT_WLAN_DELETE_BLOCK_ACK_SUCCESS + ------------------------------------------------------------------------*/ +typedef struct { + char ucBaPeerMac[6]; + uint8_t ucBaTid; + uint8_t ucDeleteReasonCode; +} host_event_wlan_add_block_ack_deleted_payload_type; + +/*------------------------------------------------------------------------- + Event ID: EVENT_WLAN_DELETE_BLOCK_ACK_FAILED + ------------------------------------------------------------------------*/ +typedef struct { + char ucBaPeerMac[6]; + uint8_t ucBaTid; + uint8_t ucDeleteReasonCode; + uint8_t ucFailReasonCode; +} host_event_wlan_add_block_ack_delete_failed_payload_type; + +/*------------------------------------------------------------------------- + Event ID: EVENT_WLAN_BSS_PROTECTION + ------------------------------------------------------------------------*/ +typedef struct { + uint8_t event_type; + uint8_t prot_type; +} host_event_wlan_bss_prot_payload_type; + +/*------------------------------------------------------------------------- + Event ID: EVENT_WLAN_BRINGUP_STATUS + ------------------------------------------------------------------------*/ +typedef struct { + uint16_t wlanStatus; + char driverVersion[10]; +} host_event_wlan_bringup_status_payload_type; + +CDS_PACK_START +/*------------------------------------------------------------------------- + Event ID: EVENT_WLAN_POWERSAVE_GENERIC + ------------------------------------------------------------------------*/ +typedef CDS_PACK_PRE struct { + uint8_t event_subtype; + uint8_t full_power_request_reason; + uint8_t pmc_current_state; + uint8_t enable_disable_powersave_mode; + uint8_t winmob_d_power_state; + uint8_t dtim_period; + uint16_t final_listen_intv; + uint16_t bmps_auto_timer_duration; + uint16_t bmps_period; +} CDS_PACK_POST host_event_wlan_powersave_payload_type; + +CDS_PACK_END +/*------------------------------------------------------------------------- + Event ID: EVENT_WLAN_POWERSAVE_WOW + ------------------------------------------------------------------------*/ +typedef struct { + uint8_t event_subtype; + uint8_t wow_type; + uint8_t wow_magic_pattern[6]; + uint8_t wow_del_ptrn_id; + uint8_t wow_wakeup_cause; + uint8_t wow_wakeup_cause_pbm_ptrn_id; +} host_event_wlan_powersave_wow_payload_type; + +/*------------------------------------------------------------------------- + Event ID: EVENT_WLAN_POWERSAVE_WOW_STATS + ------------------------------------------------------------------------*/ +/** + * host_event_wlan_powersave_wow_stats - Structure holding wow stats information + * @wow_ucast_wake_up_count: wow unicast packet wakeup count + * @wow_bcast_wake_up_count: wow broadcast packet wakeup count + * @wow_ipv4_mcast_wake_up_count: wow ipv4 multicast packet wakeup count + * @wow_ipv6_mcast_wake_up_count: wow ipv6 multicast packet wakeup count + * @wow_ipv6_mcast_ra_stats: wow ipv6 multicast router advertisement + * packet wakeup count + * @wow_ipv6_mcast_ns_stats: wow ipv6 multicast Neighbor Solicitation + * packet wakeup count + * @wow_ipv6_mcast_na_stats: wow ipv6 multicast address space + * packet wakeup count + * @wow_pno_match_wake_up_count: wow preferred network offload match + * packet wakeup count + * @wow_pno_complete_wake_up_count: wow preferred network offload complete + * packet wakeup count + * @wow_gscan_wake_up_count: wow external scan packet wakeup count + * @wow_low_rssi_wake_up_count: wow low rssi packet wakeup count + * @wow_rssi_breach_wake_up_count: wow rssi breach packet wakeup count + * @wow_icmpv4_count: wow icmpv4 packet count + * @wow_icmpv6_count: wow icmpv6 packet count + * @wow_oem_response_wake_up_count: wow oem response packet wakeup count + * + * This structure contains the wow stats information related to diag event + */ +struct host_event_wlan_powersave_wow_stats { + uint32_t wow_ucast_wake_up_count; + uint32_t wow_bcast_wake_up_count; + uint32_t wow_ipv4_mcast_wake_up_count; + uint32_t wow_ipv6_mcast_wake_up_count; + uint32_t wow_ipv6_mcast_ra_stats; + uint32_t wow_ipv6_mcast_ns_stats; + uint32_t wow_ipv6_mcast_na_stats; + uint32_t wow_pno_match_wake_up_count; + uint32_t wow_pno_complete_wake_up_count; + uint32_t wow_gscan_wake_up_count; + uint32_t wow_low_rssi_wake_up_count; + uint32_t wow_rssi_breach_wake_up_count; + uint32_t wow_icmpv4_count; + uint32_t wow_icmpv6_count; + uint32_t wow_oem_response_wake_up_count; + uint32_t Reserved_1; + uint32_t Reserved_2; + uint32_t Reserved_3; + uint32_t Reserved_4; +}; + +/*------------------------------------------------------------------------- + Event ID: EVENT_WLAN_BTC + ------------------------------------------------------------------------*/ +typedef struct { + uint8_t eventId; + uint8_t btAddr[6]; + uint16_t connHandle; + uint8_t connStatus; + uint8_t linkType; + uint8_t scoInterval; + uint8_t scoWindow; + uint8_t retransWindow; + uint8_t mode; +} host_event_wlan_btc_type; + +/*------------------------------------------------------------------------- + Event ID: EVENT_WLAN_EAPOL + ------------------------------------------------------------------------*/ +/** + * struct host_event_wlan_eapol - Structure holding the eapol information + * @event_sub_type: 0-Transmitted, 1-Received + * @eapol_packet_type: 0 - EAP Start, 1 - EAPOL Start, 2 - EAPOL Logoff + 3 - EAPOL Key, 4 - EAPOL Encapsulated Alert + * @eapol_key_info: This field from the driver is in big endian format. + * So, the masks .0x8013. can be used to extract the + * message type. After masking, the values corresponding + * to messages 1/2/3/4 are given below: + * Msg. 1 0x8000 + * Msg. 2 0x0001 + * Msg. 3 0x8013 + * Msg. 4 0x0003 + * @eapol_rate: Rate at which the frame is received + * @dest_addr: Destination address + * @src_addr: Source address + * + * This structure contains the EAPOL information related to logging + */ +struct host_event_wlan_eapol { + uint8_t event_sub_type; + uint8_t eapol_packet_type; + uint16_t eapol_key_info; + uint16_t eapol_rate; + uint8_t dest_addr[6]; + uint8_t src_addr[6]; +}; + +/*------------------------------------------------------------------------- + Event ID: EVENT_WLAN_LOW_RESOURCE_FAILURE + ------------------------------------------------------------------------*/ +/** + * struct host_event_wlan_low_resource_failure - Structure holding the + * low resource failure information + * @event_sub_type: Gives further information about reason for + * low resource condition + * + * This structure will hold the low resource failure information + */ +struct host_event_wlan_low_resource_failure { + uint8_t event_sub_type; +}; + +/** + * enum resource_failure_type - Reason for low resource failure condition + * @WIFI_EVENT_MEMORY_FAILURE: Memory failure + * + * This enum has the reason codes why the low resource situation is observed + */ +enum resource_failure_type { + WIFI_EVENT_MEMORY_FAILURE, +}; + +/*------------------------------------------------------------------------- + Event ID: EVENT_WLAN_WAKE_LOCK + ------------------------------------------------------------------------*/ +/** + * struct host_event_wlan_wake_lock - Structure holding the wakelock information + * @status: Whether the wakelock is taken/released + * @reason: Reason for taking this wakelock + * @timeout: Timeout value in case of timed wakelocks + * @name_len: Length of the name of the wakelock that will follow + * @name: Name of the wakelock + * + * This structure will hold the wakelock information + */ +struct host_event_wlan_wake_lock { + uint32_t status; + uint32_t reason; + uint32_t timeout; + uint32_t name_len; + char name[WAKE_LOCK_NAME_LEN]; +}; + +/*------------------------------------------------------------------------- + Event ID: EVENT_WLAN_LOG_COMPLETE + ------------------------------------------------------------------------*/ +/** + * struct host_event_wlan_log_complete - Holds log completion details + * @is_fatal: Indicates if the event is fatal or not + * @indicator: Source of the bug report - Framework/Host/Firmware + * @reason_code: Reason for triggering bug report + * @reserved: Reserved field + * + * This structure holds the log completion related information + */ +struct host_event_wlan_log_complete { + uint32_t is_fatal; + uint32_t indicator; + uint32_t reason_code; + uint32_t reserved; +}; + +/*------------------------------------------------------------------------- + Event ID: EVENT_WLAN_STA_KICKOUT + ------------------------------------------------------------------------*/ +/** + * struct host_event_wlan_kickout - Holds diag event details + * @reasoncode: Indicates the reasoncode of event + * @peer_macaddr: Indicates the peer macaddr + * @vdev_id: Indicate unique id for identifying the VDEV + * + * This structure holds the diag event related information + */ + +struct host_event_wlan_kickout { + uint32_t reasoncode; + uint8_t peer_mac[QDF_MAC_ADDR_SIZE]; + uint8_t vdev_id; +}; + +/*------------------------------------------------------------------------- + Event ID: EVENT_WLAN_SOFTAP_DATASTALL/EVENT_WLAN_STA_DATASTALL + ------------------------------------------------------------------------*/ +/** + * struct host_event_wlan_softap_datastall - Holds diag event details + * @reason: Indicates the reason of event + * + *This structure holds the host diag event related information + */ + +struct host_event_wlan_datastall { + uint32_t reason; +}; + +/*------------------------------------------------------------------------- + Event ID: EVENT_WLAN_SSR_REINIT_SUBSYSTEM + ------------------------------------------------------------------------*/ +/** + * struct host_event_wlan_ssr_reinit - Holds diag event details + * @status: Indicates the status of event + * + *This structure holds the host diag event related information + */ + +struct host_event_wlan_ssr_reinit { + uint32_t status; +}; + +/*------------------------------------------------------------------------- + Event ID: EVENT_WLAN_SSR_SHUTDOWN_SUBSYSTEM + ------------------------------------------------------------------------*/ +/** + * struct host_event_wlan_ssr_shutdown - Holds diag event details + * @status: Indicates the status of event + * + *This structure holds the host diag event related information + */ + +struct host_event_wlan_ssr_shutdown { + uint32_t status; +}; + + +/*------------------------------------------------------------------------- + Function declarations and documenation + ------------------------------------------------------------------------*/ +/** + * enum host_sta_kickout_events - Enum containing sta kickout subtype + * @HOST_STA_KICKOUT_REASON_BMISS: Indicate sta got disconnected reason + * beacon miss + * @HOST_STA_KICKOUT_REASON_XRETRY: Indicate sta got disconnected reason xretry + * @HOST_STA_KICKOUT_REASON_UNSPECIFIED: Indicate sta disconnection + * reason unspecified + * @HOST_STA_KICKOUT_REASON_KEEP_ALIVE: Indicate sta is disconnected + * because of keep alive + * + * This enum contains the event subtype + */ +enum host_sta_kickout_events { + HOST_STA_KICKOUT_REASON_BMISS, + HOST_STA_KICKOUT_REASON_XRETRY, + HOST_STA_KICKOUT_REASON_UNSPECIFIED, + HOST_STA_KICKOUT_REASON_KEEP_ALIVE, +}; + +/*------------------------------------------------------------------------- + Function declarations and documenation + ------------------------------------------------------------------------*/ +/** + * enum host_datastall_events - Enum containing datastall subtype + * @STA_TX_TIMEOUT: Indicate sta tx timeout + * @SOFTAP_TX_TIMEOUT:Indicate softap tx timeout + * + * This enum contains the event subtype + */ +enum host_datastall_events { + STA_TX_TIMEOUT, + SOFTAP_TX_TIMEOUT, +}; + +/*------------------------------------------------------------------------- + Function declarations and documenation + ------------------------------------------------------------------------*/ +/** + * enum host_ssr_events - Enum containing ssr subtype + * @SSR_SUB_SYSTEM_REINIT: Indicate ssr reinit state + * @SSR_SUB_SYSTEM_SHUTDOWN: Indicate ssr shutdown state + * + * This enum contains the event subtype + */ +enum host_ssr_events { + SSR_SUB_SYSTEM_REINIT, + SSR_SUB_SYSTEM_SHUTDOWN, +}; + +/** + * struct host_event_tdls_teardown - tdls teardown diag event + * @reason: reason for tear down + * @peer_mac: peer mac + * + * This structure contains tdls teardown diag event info + */ +struct host_event_tdls_teardown { + uint32_t reason; + uint8_t peer_mac[QDF_MAC_ADDR_SIZE]; +}; + +/** + * struct host_event_tdls_enable_link - tdls enable link event + * @peer_mac: peer mac + * @is_off_chan_supported: if off channel supported + * @is_off_chan_configured: if off channel configured + * @is_off_chan_established: if off channel established + * + * This structure contain tdls enable link diag event info + */ +struct host_event_tdls_enable_link { + uint8_t peer_mac[QDF_MAC_ADDR_SIZE]; + uint8_t is_off_chan_supported; + uint8_t is_off_chan_configured; + uint8_t is_off_chan_established; +}; + +/** + * struct host_event_suspend - suspend/resume state + * @state: suspend/resume state + * + * This structure contains suspend resume diag event info + */ +struct host_event_suspend { + uint8_t state; +}; + +/** + * struct host_event_offload_req - offload state + * @offload_type: offload type + * @state: enabled or disabled state + * + * This structure contains offload diag event info + */ +struct host_event_offload_req { + uint8_t offload_type; + uint8_t state; +}; + +/** + * struct host_event_tdls_scan_rejected - scan + * rejected due to tdls + * @status: rejected status + * + * This structure contains scan rejected due to + * tdls event info + */ +struct host_event_tdls_scan_rejected { + uint8_t status; +}; + +/** + * struct host_event_tdls_tx_rx_mgmt - for TX RX management frame + * @event_id: event ID + * @tx_rx: tx or rx + * @type: type of frame + * @action_sub_type: action frame type + * @peer_mac: peer mac + * + * This structure contains tdls TX RX management frame info + */ +struct host_event_tdls_tx_rx_mgmt { + uint8_t event_id; + uint8_t tx_rx; + uint8_t type; + uint8_t action_sub_type; + uint8_t peer_mac[QDF_MAC_ADDR_SIZE]; +}; + +/*------------------------------------------------------------------------- + Function declarations and documenation + ------------------------------------------------------------------------*/ +/** + * enum wifi_connectivity_events - Enum containing EAPOL sub type + * @WIFI_EVENT_DRIVER_EAPOL_FRAME_TRANSMIT_REQUESTED: EAPOL transmitted + * @WIFI_EVENT_DRIVER_EAPOL_FRAME_RECEIVED: EAPOL received + * + * This enum contains the EAPOL subtype + */ +enum wifi_connectivity_events { + WIFI_EVENT_DRIVER_EAPOL_FRAME_TRANSMIT_REQUESTED, + WIFI_EVENT_DRIVER_EAPOL_FRAME_RECEIVED, +}; + +/** + * enum wake_lock_reason - Reason for taking/releasing wakelock + * @WIFI_POWER_EVENT_WAKELOCK_DRIVER_INIT: Driver initialization + * @WIFI_POWER_EVENT_WAKELOCK_DRIVER_REINIT: Driver re-initialization + * @WIFI_POWER_EVENT_WAKELOCK_DRIVER_EXIT: Driver shutdown + * @WIFI_POWER_EVENT_WAKELOCK_SCAN: Scan request/response handling + * @WIFI_POWER_EVENT_WAKELOCK_EXT_SCAN: Extended scan request/response handling + * @WIFI_POWER_EVENT_WAKELOCK_RESUME_WLAN: Driver resume + * @WIFI_POWER_EVENT_WAKELOCK_ROC: Remain on channel request/response handling + * @WIFI_POWER_EVENT_WAKELOCK_AUTO_SUSPEND: Auto suspend related handling + * @WIFI_POWER_EVENT_WAKELOCK_IPA: IPA related handling + * @WIFI_POWER_EVENT_WAKELOCK_ADD_STA: Addition of STA + * @WIFI_POWER_EVENT_WAKELOCK_HOLD_RX: Wakelocks taken for receive + * @WIFI_POWER_EVENT_WAKELOCK_SAP: SoftAP related wakelocks + * @WIFI_POWER_EVENT_WAKELOCK_WOW: WoW feature related + * @WIFI_POWER_EVENT_WAKELOCK_PNO: PNO feature related + * @WIFI_POWER_EVENT_WAKELOCK_DEL_STA: Deletion of a station + * @WIFI_POWER_EVENT_WAKELOCK_DFS: DFS related wakelocks + * @WIFI_POWER_EVENT_WAKELOCK_WMI_CMD_RSP: Firmware response + * @WIFI_POWER_EVENT_WAKELOCK_MISC: Miscellaneous wakelocks + * @WIFI_POWER_EVENT_WAKELOCK_DHCP: DHCP negotiation under way + * @WIFI_POWER_EVENT_WAKELOCK_MGMT_TX: MGMT Tx wake lock + * + * Indicates the reason for which the wakelock was taken/released + */ +enum wake_lock_reason { + WIFI_POWER_EVENT_WAKELOCK_DRIVER_INIT, + WIFI_POWER_EVENT_WAKELOCK_DRIVER_REINIT, + WIFI_POWER_EVENT_WAKELOCK_DRIVER_EXIT, + WIFI_POWER_EVENT_WAKELOCK_SCAN, + WIFI_POWER_EVENT_WAKELOCK_EXT_SCAN, + WIFI_POWER_EVENT_WAKELOCK_RESUME_WLAN, + WIFI_POWER_EVENT_WAKELOCK_ROC, + WIFI_POWER_EVENT_WAKELOCK_AUTO_SUSPEND, + WIFI_POWER_EVENT_WAKELOCK_IPA, + WIFI_POWER_EVENT_WAKELOCK_ADD_STA, + WIFI_POWER_EVENT_WAKELOCK_HOLD_RX, + WIFI_POWER_EVENT_WAKELOCK_SAP, + WIFI_POWER_EVENT_WAKELOCK_WOW, + WIFI_POWER_EVENT_WAKELOCK_PNO, + WIFI_POWER_EVENT_WAKELOCK_DEL_STA, + WIFI_POWER_EVENT_WAKELOCK_DFS, + WIFI_POWER_EVENT_WAKELOCK_WMI_CMD_RSP, + WIFI_POWER_EVENT_WAKELOCK_MISC, + WIFI_POWER_EVENT_WAKELOCK_DHCP, + WIFI_POWER_EVENT_WAKELOCK_MGMT_TX, +}; + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* __HOST_DIAG_CORE_EVENT_H */ diff --git a/drivers/staging/qcacld-3.0/core/utils/host_diag_log/inc/host_diag_core_log.h b/drivers/staging/qcacld-3.0/core/utils/host_diag_log/inc/host_diag_core_log.h new file mode 100644 index 0000000000000000000000000000000000000000..8aad69f3426428ea1d1a48b864f893ac88f340d6 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/utils/host_diag_log/inc/host_diag_core_log.h @@ -0,0 +1,278 @@ +/* + * Copyright (c) 2014-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#if !defined(__HOST_DIAG_CORE_LOG_H) +#define __HOST_DIAG_CORE_LOG_H + +/**========================================================================= + + \file host_diag_core_log.h + + \brief WLAN UTIL host DIAG logs + + Definitions for WLAN UTIL host diag events + + ========================================================================*/ + +/* $Header$ */ + +/*-------------------------------------------------------------------------- + Include Files + ------------------------------------------------------------------------*/ +#include "qdf_types.h" +#include "i_host_diag_core_log.h" + +/*-------------------------------------------------------------------------- + Preprocessor definitions and constants + ------------------------------------------------------------------------*/ +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/*-------------------------------------------------------------------------- + Preprocessor definitions and constants + ------------------------------------------------------------------------*/ +#define HOST_LOG_MAX_NUM_SSID (21) +#define HOST_LOG_MAX_NUM_BSSID (21) +#define HOST_LOG_MAX_SSID_SIZE (32) +#define HOST_LOG_MAX_BSSID_SIZE (6) +#define HOST_LOG_MAX_NUM_CHANNEL (64) +#define HOST_LOG_MAX_NUM_HO_CANDIDATE_APS (20) +#define HOST_LOG_MAX_WOW_PTRN_SIZE (128) +#define HOST_LOG_MAX_WOW_PTRN_MASK_SIZE (16) +#define VOS_LOG_PKT_LOG_SIZE (2048) +#define HOST_LOG_PKT_LOG_THRESHOLD 40960 + +/* Version to be updated whenever format of vos_log_pktlog_info changes */ +#define VERSION_LOG_WLAN_PKT_LOG_INFO_C 1 + +/*--------------------------------------------------------------------------- + This packet contains the scan results of the recent scan operation + LOG_WLAN_SCAN_C 0x1496 + ---------------------------------------------------------------------------*/ +typedef struct { + log_hdr_type hdr; + uint8_t eventId; + uint8_t numSsid; + uint8_t ssid[HOST_LOG_MAX_NUM_SSID][HOST_LOG_MAX_SSID_SIZE]; + uint8_t bssid[HOST_LOG_MAX_NUM_BSSID][HOST_LOG_MAX_BSSID_SIZE]; + uint8_t totalSsid; + uint8_t minChnTime; + uint8_t maxChnTime; + uint16_t timeBetweenBgScan; + uint8_t BSSMode; + uint8_t numChannel; + uint8_t channels[HOST_LOG_MAX_NUM_CHANNEL]; + uint16_t status; +} host_log_scan_pkt_type; + +/*--------------------------------------------------------------------------- + This packet contains the information related to IBSS connection setup + LOG_WLAN_IBSS_C 0x1497 + ---------------------------------------------------------------------------*/ +typedef struct { + log_hdr_type hdr; + uint8_t eventId; + uint8_t channelSetting; + struct qdf_mac_addr bssid; + struct qdf_mac_addr peer_macaddr; + uint8_t ssid[HOST_LOG_MAX_SSID_SIZE]; + uint8_t operatingChannel; + uint8_t beaconInterval; + uint8_t status; +} host_log_ibss_pkt_type; + +/*--------------------------------------------------------------------------- + This packet contains the information related to 802.11D + LOG_WLAN_80211D_C 0x1498 + ---------------------------------------------------------------------------*/ +typedef struct { + log_hdr_type hdr; + uint8_t eventId; + uint8_t numChannel; + uint8_t Channels[HOST_LOG_MAX_NUM_CHANNEL]; + uint8_t TxPwr[HOST_LOG_MAX_NUM_CHANNEL]; + uint8_t countryCode[3]; + uint8_t supportMultipleDomain; +} host_log_802_11d_pkt_type; + +/*--------------------------------------------------------------------------- + This is a log packet which contains below handoff information: + - Current AP + RSSI (if already associated) + - Candidate AP + RSSI (before association and when the list is updated) + - For each BSSID in candidate list, provide RSSI, QoS and security compatibility + LOG_WLAN_HANDOFF_C 0x1499 + ---------------------------------------------------------------------------*/ +typedef struct { + uint8_t ssid[9]; + uint8_t bssid[HOST_LOG_MAX_BSSID_SIZE]; + uint8_t channel_id; + uint32_t qos_score; + uint32_t sec_score; + uint32_t rssi_score; + uint32_t overall_score; + uint32_t tx_per; /* represented as a % */ + uint32_t rx_per; /* represented as a % */ + +} host_log_ho_ap_info; + +typedef struct { + log_hdr_type hdr; + uint32_t num_aps; + host_log_ho_ap_info current_ap_info; + host_log_ho_ap_info + candidate_ap_info[HOST_LOG_MAX_NUM_HO_CANDIDATE_APS]; +} host_log_ho_pkt_type; + +/*--------------------------------------------------------------------------- + This packet contains the information related to the EDCA parameters + advertised by the AP + LOG_WLAN_QOS_EDCA_C 0x149A + ---------------------------------------------------------------------------*/ +typedef struct { + log_hdr_type hdr; + uint8_t aci_be; + uint8_t cw_be; + uint16_t txoplimit_be; + uint8_t aci_bk; + uint8_t cw_bk; + uint16_t txoplimit_bk; + uint8_t aci_vi; + uint8_t cw_vi; + uint16_t txoplimit_vi; + uint8_t aci_vo; + uint8_t cw_vo; + uint16_t txoplimit_vo; +} host_log_qos_edca_pkt_type; + +/*--------------------------------------------------------------------------- + This packet contains the total number of beacon received value + LOG_WLAN_BEACON_UPDATE_C 0x149B + ---------------------------------------------------------------------------*/ +typedef struct { + log_hdr_type hdr; + uint32_t bcn_rx_cnt; +} host_log_beacon_update_pkt_type; + +/*--------------------------------------------------------------------------- + This packet contains the information related to a WoW patern value when set + LOG_WLAN_POWERSAVE_WOW_ADD_PTRN_C 0x149C + ---------------------------------------------------------------------------*/ +typedef struct { + log_hdr_type hdr; + uint8_t pattern_id; + uint8_t pattern_byte_offset; + uint8_t pattern_size; + uint8_t pattern[HOST_LOG_MAX_WOW_PTRN_SIZE]; + uint8_t pattern_mask_size; + uint8_t pattern_mask[HOST_LOG_MAX_WOW_PTRN_MASK_SIZE]; +} host_log_powersave_wow_add_ptrn_pkt_type; + +/*--------------------------------------------------------------------------- + This packet contains the Tspec info negotiated with the AP for the + specific AC + LOG_WLAN_QOS_TSPEC_C 0x14A2 + ---------------------------------------------------------------------------*/ +typedef struct { + log_hdr_type hdr; + uint8_t tsinfo[3]; + uint16_t nominal_msdu_size; + uint16_t maximum_msdu_size; + uint32_t min_service_interval; + uint32_t max_service_interval; + uint32_t inactivity_interval; + uint32_t suspension_interval; + uint32_t svc_start_time; + uint32_t min_data_rate; + uint32_t mean_data_rate; + uint32_t peak_data_rate; + uint32_t max_burst_size; + uint32_t delay_bound; + uint32_t min_phy_rate; + uint16_t surplus_bw_allowance; + uint16_t medium_time; +} host_log_qos_tspec_pkt_type; + +/*--------------------------------------------------------------------------- + This packet contains data information when stall detected + LOG_TRSP_DATA_STALL_C 0x1801 + ---------------------------------------------------------------------------*/ + +typedef struct { + char channelName[4]; + uint32_t numDesc; + uint32_t numFreeDesc; + uint32_t numRsvdDesc; + uint32_t headDescOrder; + uint32_t tailDescOrder; + uint32_t ctrlRegVal; + uint32_t statRegVal; + uint32_t numValDesc; + uint32_t numInvalDesc; +} host_log_data_stall_channel_type; + +typedef struct { + log_hdr_type hdr; + uint32_t PowerState; + uint32_t numFreeBd; + host_log_data_stall_channel_type dxeChannelInfo[4]; +} host_log_data_stall_type; + +/*--------------------------------------------------------------------------- + This packet contains the rssi value from BSS descriptor + LOG_WLAN_RSSI_UPDATE_C 0x1354 + ---------------------------------------------------------------------------*/ +typedef struct { + log_hdr_type hdr; + int8_t rssi; +} host_log_rssi_pkt_type; + +/** + * struct host_log_pktlog_info - Packet log info + * @log_hdr: Log header + * @buf_len: Length of the buffer that follows + * @buf: Buffer containing the packet log info + * + * Structure containing the packet log information + * LOG_WLAN_PKT_LOG_INFO_C 0x18E0 + */ +struct host_log_pktlog_info { + log_hdr_type log_hdr; + uint32_t version; + uint32_t seq_no; + uint32_t buf_len; + uint8_t buf[]; +}; + +/*------------------------------------------------------------------------- + Function declarations and documenation + ------------------------------------------------------------------------*/ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* __HOST_DIAG_CORE_LOG_H */ diff --git a/drivers/staging/qcacld-3.0/core/utils/host_diag_log/inc/host_diag_event_defs.h b/drivers/staging/qcacld-3.0/core/utils/host_diag_log/inc/host_diag_event_defs.h new file mode 100644 index 0000000000000000000000000000000000000000..c29f36b0981a6cbe87c88563ba9b59a6219cd0af --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/utils/host_diag_log/inc/host_diag_event_defs.h @@ -0,0 +1,903 @@ +/* + * Copyright (c) 2014-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef EVENT_DEFS_H +#define EVENT_DEFS_H + +typedef enum { + EVENT_DROP_ID = 0, + + /* Events between 0x1 to 0x674 are not used */ + + /* + * + * EVENT_WLAN_SECURITY + * @ eventId: Event id + * @ authMode: Shows the auth mode + * @ encryptionModeUnicast: Encryption Mode Unicast + * @ encryptionModeMulticast: Encryption Mode Multicast + * @ pmkIDMatch: PMK ID Match + * @ bssid: BSSID < 0 to 5 > + * @ keyId: Key ID + * @ status: Shows the status 0 is Success and 1 is failure + * + * This event is used in SECURITY to send various wlan security modes + * Values for parameters are defined below: + * Event ID: offset: 0 length: 1 + * 5 - Remove Key Req + * 6 - Remove Key Rsp + * 7 - PMKID Candidate Found + * 8 - PMKID Update + * 9 - Mic Error + * 10 - Set UniCast Key Req + * 11 - Set UniCast Key Rsp + * 12 - Set BCast Key Req + * 13 - Set BCast Key Rsp + * + * Auth Mode: offset: 1 length: 1 + * 0 - Open + * 1 - Shared + * 2 - WPA EAP + * 3 - WPA PSK + * 4 - WPA2 EAP + * 5 - WPA2 PSK + * + * Encryption Mode Unicast: offset: 2 length: 1 + * 0 - Open + * 1 - WEP40 + * 2 - WEP104 + * 3 - TKIP + * 4 - AES + * + * Encryption Mode Multicast: offset: 3 length: 1 + * 0 - Open + * 1 - WEP40 + * 2 - WEP104 + * 3 - TKIP + * 4 - AES + * + * ENC_MODE_SMS4: offset: 4 length:1 + * + * PMK ID Match: offset: 5 length: 1 + * 0 - No Match + * 1 - Match + * + * BSSID[0]: offset: 6 length: 1 + * BSSID[1]: offset: 7 length: 1 + * BSSID[2]: offset: 8 length: 1 + * BSSID[3]: offset: 9 length: 1 + * BSSID[4]: offset: 10 length: 1 + * BSSID[5]: offset: 11 length: 1 + * + * Key ID: offset: 12 length: 1 + * Status: offset: 13 length: 1 + * 0 - Success + * 1 - Failure + * + * Supported Feature: wlan security + * + * + */ + + EVENT_WLAN_SECURITY = 0x675, /* 13 byte payload */ + + /* + * + * EVENT_WLAN_STATUS + * @ eventId: Event id + * @ ssid: SSID + * @ bssType: BSS Type + * @ rssi: RSSI + * @ channel: Channel + * @ qosCapability: QoS Capability + * @ authmode: Auth Mode + * @ encryptionType: Encryption Type + * @ reason: Reason + * @ reasonDisconnect: Reason Disconnect + * + * This event is used to send wlan status + * Values for parameters are defined below: + * Event ID: offset: 0 length: 1 + * 0 - Connect + * 1 - Disconnect + * + * SSID: offset: 1 length: 32 + * BSS Type: offset: 33 + SSID length, length: 1 + * 0 - None + * 1 - BSS_TYPE_INFRASTRUCTURE + * 2 - BSS_TYPE_INFRA_AP + * 3 - BSS_TYPE_IBSS + * 4 - BSS_TYPE_START_IBSS + * 5 - BSS_TYPE_NDI + * 6 - BSS_TYPE_ANY + * + * RSSI: offset: 34 length: 1 + * Channel: offset: 35 length: 1 + * QoS Capability: offset: 36 length: 1 + * Auth Mode: offset: 37 length: 1 + * 0 - Open + * 1 - Shared + * 2 - WPA EAP + * 3 - WPA PSK + * 4 - WPA2 EAP + * 5 - WPA2 PSK + * 6 - WAPI CERT + * 7 - WAPI PSK + * + * Encryption Type: offset: 38 length: 1 + * 0 - Open + * 1 - WEP40 + * 2 - WEP104 + * 3 - TKIP + * 4 - AES + * + * ENC_MODE_SMS4: offset: 39 length: 1 + * + * Reason: offset: 40 length: 1 + * 0 - Unspecified + * 1 - User Requested + * 2 - Mic Error + * 3 - Diassoc + * 4 - Deauth + * 5 - Handoff + * + * Reason Disconnect: offset: 41 length: 1 + * + * Supported Feature: wlan status + * + * + */ + + EVENT_WLAN_STATUS, /* 15 byte payload */ + + /* Events 0x677 and 0x678 are not used */ + + /* + * + * EVENT_WLAN_QOS + * @ eventId: event id + * @ reasonCode: Reason for event + * + * This event is used to send quality set services + * Values for parameters are defined below: + * Event ID: offset: 0 length: 1 + * 0 - Add TS Req + * 1 - Add TS Rsp + * 2 - Delts + * + * Reason Code: offset: 1 length: 1 + * 0 - Admission Accepted + * 1 - Invalid Params + * 2 - Reserved + * 3 - Refused + * 4 - User Requested + * 5 - Ind From AP + * + * Supported Feature: Qos wlan + * + * + */ + + EVENT_WLAN_QOS = 0x679, /* 2 byte payload */ + + /* + * + * EVENT_WLAN_PE + * @bssid: BSSID + * @ event_type: Event type + * @ sme_state: SME state + * @ mlm_state: MLM state + * @ status: 0 - Success, 1 - Failure < majority 0 is success > + * @reason_code: reason for event report + * + * This event is used in PE to send different diag events. + * Values for parameters are defined below: + * + * bssid[0]: offset: 0 length: 1 + * bssid[1]: offset: 1 length: 1 + * bssid[2]: offset: 2 length: 1 + * bssid[3]: offset: 3 length: 1 + * bssid[4]: offset: 4 length: 1 + * bssid[5]: offset: 5 length: 1 + * + * Event Type: offset: 6 length: 2 + * 0 - SCAN REQ EVENT + * 1 - SCAN ABORT IND EVENT + * 2 - SCAN_RSP_EVENT + * 3 - JOIN_REQ_EVENT + * 4 - JOIN_RSP_EVENT + * 5 - SETCONTEXT_REQ_EVENT + * 6 - SETCONTEXT_RSP_EVENT + * 7 - REASSOC_REQ_EVENT + * 8 - REASSOC_RSP_EVENT + * 9 - AUTH_REQ_EVENT + * 10 - AUTH_RSP_EVENT + * 11 - DISASSOC_REQ_EVENT + * 12 - DISASSOC_RSP_EVENT + * 13 - DISASSOC_IND_EVENT + * 14 - DISASSOC_CNF_EVENT + * 15 - DEAUTH_REQ_EVENT + * 16 - DEAUTH_RSP_EVENT + * 17 - DEAUTH_IND_EVENT + * 18 - START_BSS_REQ_EVENT + * 19 - START_BSS_RSP_EVENT + * 20 - AUTH_IND_EVENT + * 21 - ASSOC_IND_EVENT + * 22 - ASSOC_CNF_EVENT + * 23 - REASSOC_IND_EVENT + * 24 - SWITCH_CHL_IND_EVENT + * 25 - SWITCH_CHL_RSP_EVENT + * 26 - STOP_BSS_REQ_EVENT + * 27 - STOP_BSS_RSP_EVENT + * 28 - DEAUTH_CNF_EVENT + * 29 - ADDTS_REQ_EVENT + * 30 - ADDTS_RSP_EVENT + * 31 - DELTS_REQ_EVENT + * 32 - DELTS_RSP_EVENT + * 33 - DELTS_IND_EVENT + * 34 - ENTER_BMPS_REQ_EVENT + * 35 - ENTER_BMPS_RSP_EVENT + * 36 - EXIT_BMPS_REQ_EVENT + * 37 - BMPS_RSP_EVENT + * 38 - EXIT_BMPS_IND_EVENT + * 39 - ENTER_IMPS_REQ_EVENT + * 40 - ENTER_IMPS_RSP_EVENT + * 41 - EXIT_IMPS_REQ_EVENT + * 42 - EXIT_IMPS_RSP_EVENT + * 43 - ENTER_UAPSD_REQ_EVENT + * 44 - ENTER_UAPSD_RSP_EVENT + * 45 - EXIT_UAPSD_REQ_EVENT + * 46 - EXIT_UAPSD_RSP_EVENT + * 47 - WOWL_ADD_BCAST_PTRN_EVENT + * 48 - WOWL_DEL_BCAST_PTRN_EVENT + * 49 - ENTER_WOWL_REQ_EVENT + * 50 - ENTER_WOWL_RSP_EVENT + * 51 - EXIT_WOWL_REQ_EVENT + * 52 - EXIT_WOWL_RSP_EVENT + * 53 - HAL_ADDBA_REQ_EVENT + * 54 - HAL_ADDBA_RSP_EVENT + * 55 - HAL_DELBA_IND_EVENT + * 56 - HB_FAILURE_TIMEOUT + * 57 - PRE_AUTH_REQ_EVENT + * 58 - PRE_AUTH_RSP_EVENT + * 59 - PREAUTH_DONE + * 60 - REASSOCIATING + * 61 - CONNECTED + * 62 - ASSOC_REQ_EVENT + * 63 - AUTH_COMP_EVENT + * 64 - ASSOC_COMP_EVENT + * 65 - AUTH_START_EVENT + * 66 - ASSOC_START_EVENT + * 67 - REASSOC_START_EVENT + * 68 - ROAM_AUTH_START_EVENT + * 69 - ROAM_AUTH_COMP_EVENT + * 70 - ROAM_ASSOC_START_EVENT + * 71 - ROAM_ASSOC_COMP_EVENT + * 72 - SCAN_COMPLETE_EVENT + * 73 - SCAN_RESULT_FOUND_EVENT + * 74 - ASSOC_TIMEOUT + * 75 - AUTH_TIMEOUT + * 76 - DEAUTH_FRAME_EVENT + * 77 - DISASSOC_FRAME_EVENT + * + * SME State: offset: 8 length: 2 + * 0 - OFFLINE + * 1 - IDLE + * 2 - SUSPEND + * 3 - WT SCAN + * 4 - WT JOIN + * 5 - WT AUTH + * 6 - WT ASSOC + * 7 - WT REASSOC + * 8 - WT REASSOC LINK FAIL + * 9 - JOIN FAILURE + * 10 - ASSOCIATED + * 11 - REASSOCIATED + * 12 - LINK EST + * 13 - LINK EST WT SCAN + * 14 - WT PRE AUTH + * 15 - WT DISASSOC + * 16 - WT DEAUTH + * 17 - WT START BSS + * 18 - WT STOP BSS + * 19 - NORMAL + * 20 - CHANNEL SCAN + * 21 - NORMAL CHANNEL SCAN + * + * MLM State: offset: 10 legth: 2 + * 0 - MLM OFFLINE + * 1 - MLM IDLE + * 2 - MLM WT PROBE RESP + * 3 - MLM PASSIVE SCAN + * 4 - MLM WT JOIN BEACON + * 5 - MLM JOINED + * 6 - MLM BSS STARTED + * 7 - MLM WT AUTH FRAME + * 8 - MLM WT AUTH FRAME + * 9 - MLM WT AUTH FRAME + * 10 - MLM AUTH RSP TIMEOUT + * 11 - MLM AUTHENTICATED + * 12 - MLM WT ASSOC RSP + * 13 - MLM WT REASSOC RSP + * 14 - MLM ASSOCIATED + * 15 - MLM REASSOCIATED + * 16 - MLM LINK ESTABLISHED + * 17 - MLM WT ASSOC CNF + * 18 - MLM LEARN + * 19 - MLM WT ADD BSS RSP + * 20 - MLM WT DEL BSS RSP + * 21 - MLM WT ADD BSS RSP ASSOC + * 22 - MLM WT ADD BSS RSP REASSOC + * 23 - MLM WT ADD BSS RSP PREASSOC + * 24 - MLM WT ADD STA RSP + * 25 - MLM WT DEL STA RSP + * 26 - MLM WT ASSOC DEL STA RSP + * 27 - MLM WT SET BSS KEY + * 28 - MLM WT SET STA KEY + * 29 - MLM WT SET STA BCASTKEY + * 30 - MLM WT ADDBA RSP + * 31 - MLM WT REMOVE BSS KEY + * 32 - MLM WT REMOVE STA KEY + * 33 - MLM WT SET MIMOPS + * + * Status: offset: 12 length: 2 + * Reason Code: offset: 14 length: 2 + * + * Supported Feature: STA + * + * + */ + + EVENT_WLAN_PE, /* 16 byte payload */ + + /* Events between 0x67b to 0x67f are not used */ + + /* + * + * EVENT_WLAN_BRINGUP_STATUS + * @ wlanStatus: Describe wlan status + * @ driverVersion: Driver version between 0 to 9 + * + * This event is used in BRINGUP to send wlan status + * Values for parameters are defined below: + * WLAN Status: offset: 0 length: 2 + * 0 - WLAN Disabled + * 1 - WLAN Enabled + * 2 - Reset Fail + * 3 - Reset Success + * 4 - Device Removed + * 5 - Devide Inserted + * 6 - Driver Unloaded + * 7 - Driver Loaded + * + * driverVersion: offset: 2 length: 10 + * + * Supported Feature: Bringup + * + * + */ + + EVENT_WLAN_BRINGUP_STATUS = 0x680, /* 12 byte payload */ + + /* + * + * EVENT_WLAN_POWERSAVE_GENERIC + * @ event_subtype: Event subtype + * @ full_power_request_reason: Full power request reason + * @ pmc_current_state: Pmc current state + * @ enable_disable_powersave_mode: Enable disable powersave mode + * @ winmob_d_power_state: winmob d power state + * @ dtim_period: DTIM period + * @ final_listen_intv: Final listen int + * @ bmps_auto_timer_duration: BMPS auto timer duration + * @ bmps_period: BMPS period + * + * This event is used in POWERSAVE to send wlan status + * Values for parameters are defined below: + * Event Sub Type: offset: 0 length: 1 + * Full Power Req Reason: offset: 1 length: 1 + * PMC Current State: offset: 2 length: 1 + * Enable disable powersave mode: 3 length: 1 + * Winmob D Power State: offset: 4 length: 1 + * DTIM Period: offset:5 length: 1 + * Final Listen INTV: offset:6 length: 2 + * BMPS Auto Timer Duration: 8 length: 2 + * BMPS Period: offset: 10 length:2 + * + * Supported Feature: POWERSAVE GENERIC + * + * + */ + + EVENT_WLAN_POWERSAVE_GENERIC, /* 16 byte payload */ + + /* + * + * EVENT_WLAN_POWERSAVE_WOW + * @ event_subtype: Event subtype + * @ wow_type: Wow type + * @ wow_magic_pattern: It will use pattern from 0 to 5 + * @ wow_del_ptrn_id: Wow delete pattern id + * @ wow_wakeup_cause: Wow wakeup cause + * @ wow_wakeup_cause_pbm_ptrn_id: Wow wakeup cause pbm pattern id + * + * This event is used in POWERSAVE WOW to send the wow wakeup pattern, + * cause etc + * Values for parameters are defined below: + * Event Sub Type: offset: 0 length: 1 + * 0 - Enter + * 1 - Exit + * 2 - Del Pattern + * 3 - Wakup + * + * WOW Type: offset: 1 length: 1 + * 0 - None + * 1 - Magic Pkt Only + * 2 - Byte Match Only + * 3 - Magic Pkt Byte Match + * + * WOW Magic Pattern: offset:2 length: 6 + * WOW Del Pattern ID: offset:8 length: 1 + * WOW Wakeup Cause: offset: 9 length: 1 + * 0 - Magic Pkt Match + * 1 - Ptrn Byte Match + * WOW Wakeup Cause PBM Ptrn ID: offset: 10 length: 1 + * + * Supported Feature: Powersave wow + * + * + */ + + EVENT_WLAN_POWERSAVE_WOW, /* 11 byte payload */ + + /* Events between 0x683 to 0x690 are not used */ + + /* + * + * EVENT_WLAN_BTC + * @ eventId: Event id + * @ btAddr: BT address + * @ connHandle: Connection handle + * @ connStatus: Connection status + * @ linkType: Link Type + * @ scoInterval: Synchronous Connection Oriented interval + * @ scoWindow: Synchronous Connection Oriented window + * @ retransWindow: Retransmisson window + * @ mode: Mode + * + * This event is used in Bluetooth to send the btc status + * Values for parameters are defined below: + * Event ID: offset: 0 length: 1 + * 0 - DEVICE SWITCHED ON + * 1 - DEVICE SWITCHED OFF + * 2 - INQUIRY STARTED + * 3 - INQUIRY STOPPED + * 4 - PAGE STARTED + * 5 - PAGE STOPPED + * 6 - CREATE ACL CONNECTION + * 7 - ACL CONNECTION COMPLETE + * 8 - CREATE SYNC CONNECTION + * 9 - SYNC CONNECTION COMPLETE + * 10 - SYNC CONNECTION UPDATED + * 11 - DISCONNECTION COMPLETE + * 12 - MODE CHANGED + * 13 - A2DP STREAM START + * 14 - A2DP STREAM STOP + * + * BT Addr[0]: offset: 1 length: 1 + * BT Addr[1]: offset: 2 length: 1 + * BT Addr[2]: offset: 3 length: 1 + * BT Addr[3]: offset: 4 length: 1 + * BT Addr[4]: offset: 5 length: 1 + * BT Addr[5]: offset: 6 length: 1 + * + * Conn Handle: offset: 7 length: 2 + * 65535 - Invalid + * + * Conn Status: offset:9 length: 1 + * 0 - Fail + * 1 - success + * + * Link Type: offset: 10 length: 1 + * 0 - SCO + * 1 - ACL + * 2 - ESCO + * + * Sco Interval: offset: 11 length: 1 + * Sco Window: offset: 12 length: 1 + * Retrans Window: offset: 13 length: 1 + * + * Mode: offset: 14 length: 1 + * 0 - Active + * 1 - Hold + * 2 - Sniff + * 3 - Park + * + * Supported Feature: Bluetooth + * + * + */ + + EVENT_WLAN_BTC = 0x691, /* 15 byte payload */ + + /* + * + * EVENT_WLAN_EAPOL + * @ event_sub_type: 0-Transmitted, 1-Received + * @ eapol_packet_type: 0 - EAP Start, 1 - EAPOL Start, 2 - EAPOL + * Logoff, 3 - EAPOL Key, 4 - EAPOL Encapsulated Alert + * @ eapol_key_info: This field from the driver is in big endian format + * @ eapol_rate: Rate at which the frame is received + * @ dest_addr: Destination address + * * @ src_addr: Source address + * + * This event is used to send Extensible Authentication Protocol + * information + * Values for parameters are defined below: + * event_sub_type: offset: 0 length: 1 + * eapol_packet_type: offset: 1 length: 1 + * eapol_key_info: offset:2 length: 2 + * eapol_rate: offset: 4 length: 2 + * dest_addr[0]: offset: 6 length: 1 + * dest_addr[1]: offset: 7 length: 1 + * dest_addr[2]: offset: 8 length: 1 + * dest_addr[3]: offset: 9 length: 1 + * dest_addr[4]: offset: 10 length: 1 + * dest_addr[5]: offset: 11 length: 1 + * src_addr[0]: offset: 12 length: 1 + * src_addr[1]: offset: 13 length: 1 + * src_addr[2]: offset: 14 length: 1 + * src_addr[3]: offset: 15 length: 1 + * src_addr[4]: offset: 16 length: 1 + * src_addr[5]: offset: 17 length: 1 + * + * Supported Feature: Extensible Authentication Protocol + * + * + */ + + EVENT_WLAN_EAPOL = 0xA8D,/* 18 bytes payload */ + + /* + * + * EVENT_WLAN_WAKE_LOCK + * @ status: Whether the wakelock is taken/released + * @ reason: Reason for taking this wakelock + * @ timeout: Timeout value in case of timed wakelocks + * @ name_len: Length of the name of the wakelock that will follow + * @ name: Name of the wakelock + * + * This event is used to send wakelock information + * Values for parameters are defined below: + * status: offset: 0 length: 4 + * reason: offset: 4 length: 4 + * timeout: offset: 8 length: 4 + * name_len: offset: 12 length: 4 + * + * Supported Feature: wlan wakelock + * + * + */ + + EVENT_WLAN_WAKE_LOCK = 0xAA2, /* 96 bytes payload */ + EVENT_WLAN_BEACON_RECEIVED = 0xAA6, /* FW event: 2726 */ + + /* + * + * EVENT_WLAN_LOG_COMPLETE + * @ is_fatal: Indicates if the event is fatal or not + * @ indicator: Source of the bug report - Framework/Host/Firmware + * @ reason_code: Reason for triggering bug report + * @ reserved: Reserved field + * + * This event is used to send log completion related information + * Values for parameters are defined below: + * is_fatal: offset: 0 length: 4 + * indicator: offset: 4 length: 4 + * reason_code: offset: 8 length: 4 + * reserved: offset: 12 length: 4 + * + * Supported Feature: Logging + * + * + */ + + EVENT_WLAN_LOG_COMPLETE = 0xAA7, /* 16 bytes payload */ + + /* + * + * EVENT_WLAN_STATUS_V2 + * @ event_id: Event id + * @ ssid: Network SSID + * @ bssType: BSS Type + * @ rssi: RSSI + * @ channel: Channel Numbers + * @ qosCapability: quality of service capability + * @ authType: Authentication type + * @ encryptionType: Encryption type + * @ reason: Reason for triggering status + * @ reasonDisconnect:Reason for disconnection + * + * This event is used to send varius wlan status + * Values for parameters are defined below: + * eventId: offset: 0 length: 1 + * ssid[0] - ssid[31]: offset: 1 to 32, length: 1 + * bssType: offset: 33 length: 1 + * rssi: offset: 34 length: 1 + * channel: offset: 35 length: 1 + * qosCapability: offset: 36 length: 1 + * authType: offset: 37 length: 1 + * encryptionType: offset: 38 length: 1 + * reason: offset: 39 length: 1 + * reasonDisconnect: offset: 40 length: 1 + * + * Supported Feature: Wlan status + * + * + */ + + EVENT_WLAN_STATUS_V2 = 0xAB3, + + /* + * + * EVENT_WLAN_TDLS_TEARDOWN + * @ reason: reason for tear down. + * @peer_mac: Peer mac address + * + * + * This event is sent when TDLS tear down happens. + * + * Supported Feature: TDLS + * + * + */ + EVENT_WLAN_TDLS_TEARDOWN = 0xAB5, + + /* + * + * EVENT_WLAN_TDLS_ENABLE_LINK + * @peer_mac: peer mac + * @is_off_chan_supported: If peer supports off channel + * @is_off_chan_configured: If off channel is configured + * @is_off_chan_established: If off channel is established + * + * + * This event is sent when TDLS enable link happens. + * + * Supported Feature: TDLS + * + * + */ + EVENT_WLAN_TDLS_ENABLE_LINK = 0XAB6, + + /* + * + * EVENT_WLAN_SUSPEND_RESUME + * @ state: suspend/resume state + * + * This event is used to send suspend resume info + * Values for parameters are defined below: + * suspend: offset: 0 length: 1 + * 0 - HDD_WLAN_EARLY_SUSPEND + * 1 - HDD_WLAN_SUSPEND + * 2 - HDD_WLAN_EARLY_RESUME + * 3 - HDD_WLAN_RESUME + * + * Supported Feature: suspend/resume + * + * + */ + + EVENT_WLAN_SUSPEND_RESUME = 0xAB7, + + /* + * + * EVENT_WLAN_OFFLOAD_REQ + * @ offload_type: offload type + * @ state: enabled or disabled state + * + * This event is used to send offload info + * Values for parameters are defined below: + * offloadType: offset: 0 length: 1 + * 0 - SIR_IPV4_ARP_REPLY_OFFLOAD + * 1 - SIR_IPV6_NEIGHBOR_DISCOVERY_OFFLOAD + * 2 - SIR_IPV6_NS_OFFLOAD + * + * enableOrDisable: offset: 1 length: 1 + * 0 - SIR_OFFLOAD_DISABLE + * 1 - SIR_OFFLOAD_ENABLE + * + * Supported Feature: offload + * + * + */ + + EVENT_WLAN_OFFLOAD_REQ = 0xAB8, + + /* + * + * EVENT_TDLS_SCAN_BLOCK + * @status: rejected status + * + * + * This event is sent when scan is rejected due to TDLS. + * + * Supported Feature: TDLS + * + * + */ + EVENT_TDLS_SCAN_BLOCK = 0xAB9, + + /* + * + * EVENT_WLAN_TDLS_TX_RX_MGMT + * @event_id: event id + * @tx_rx: tx or rx + * @type: type of frame + * @action_sub_type: action frame type + * @peer_mac: peer mac + * + * + * This event is sent when TDLS mgmt rx tx happens. + * + * Supported Feature: TDLS + * + * + */ + EVENT_WLAN_TDLS_TX_RX_MGMT = 0xABA, + + /* + * + * EVENT_WLAN_LOW_RESOURCE_FAILURE + * @ WIFI_EVENT_MEMORY_FAILURE: Memory failure + * + * This event is used to send reason why low resource situation + * is observed + * + * Supported Feature: Memory + * + * + */ + + EVENT_WLAN_LOW_RESOURCE_FAILURE = 0xABB, + + /* + * + * EVENT_WLAN_POWERSAVE_WOW_STATS + * @ wow_ucast_wake_up_count: send unicast packet count + * @ wow_bcast_wake_up_count: send broadcast packet count + * @ wow_ipv4_mcast_wake_up_coun: send ipv4 multicast packet count + * @ wow_ipv6_mcast_wake_up_count: send ipv6 multicast packet count + * @ wow_ipv6_mcast_ra_stats: send ipv6 multicast ra packet count + * @ wow_ipv6_mcast_ns_stats: send ipv6 multicast ns packet count + * @ wow_ipv6_mcast_na_stats: send ipv6 multicast na packet count + * @ wow_pno_match_wake_up_count: preferred network offload match count + * @ wow_pno_complete_wake_up_count: preferred network offload complete + * @ wow_gscan_wake_up_count:Reason: send external scan packet count + * @ wow_low_rssi_wake_up_count: send low rssi packet count + * @ wow_rssi_breach_wake_up_count: send rssi breach packet count + * @ wow_icmpv4_count: Send icmpv4 packet count + * @ wow_icmpv6_count: send icmpv6 packet count + * @ wow_oem_response_wake_up_count: Send oem response packet count + * + * This event is used to send wow wakeup stats information + * + * Supported Feature: Wlan powersave wow + * + * + */ + + EVENT_WLAN_POWERSAVE_WOW_STATS = 0xB33, + + /* + * + * EVENT_WLAN_STA_KICKOUT + * @reasoncode: Indicates the reasoncode of event + * @peer_macaddr: Indicates the peer macaddr + * @vdev_id: Indicate unique id for identifying the VDEV + * + * This event is used to send sta kickout information + * Values for parameters are defined below: + * Reasoncode: offset: 0 length: 4 + * Peer macaddr: offset: 4 length: 6 + * VDEV ID: offset: 10 length 1 + * + * Supported Feature: STA + * + * + */ + + EVENT_WLAN_STA_KICKOUT = 0xB39, + + /* + * + * EVENT_WLAN_STA_DATASTALL + * @reason: Indicates the reason of event + * + * This event is used to send sta datastall information + * Values for parameters are defined below: + * Reason: offset:0 length: 4 + * + * Supported Feature: STA + * + * + */ + + EVENT_WLAN_STA_DATASTALL = 0xB3A, + + /* + * + * EVENT_WLAN_SOFTAP_DATASTALL + * @reason: Indicates the reason of event + * + * This event is used to send SAP datastall information + * Values for parameters are defined below: + * Reason: offset:0 length: 4 + * + * Supported Feature: SAP + * + * + */ + + EVENT_WLAN_SOFTAP_DATASTALL = 0xB3B, + + /* + * + * EVENT_WLAN_SSR_REINIT_SUBSYSTEM + * @status: Indicates the status of event + * + * This event is used to send ssr reinit status + * Values for parameters are defined below: + * Status: offset: 0 length: 4 + * + * Supported Feature: SSR + * + * + */ + + EVENT_WLAN_SSR_REINIT_SUBSYSTEM = 0xB3C, + + /* + * + * EVENT_WLAN_SSR_SHUTDOWN_SUBSYSTEM + * @status: Indicates the status of event + * + * This event is used to send ssr shutdown status + * Values for parameters are defined below: + * Status: offset: 0 length: 4 + * + * Supported Feature: SSR + * + * + */ + + EVENT_WLAN_SSR_SHUTDOWN_SUBSYSTEM = 0xB3D, + + EVENT_MAX_ID = 0x0FFF +} event_id_enum_type; + +#endif /* EVENT_DEFS_H */ diff --git a/drivers/staging/qcacld-3.0/core/utils/host_diag_log/inc/log_codes.h b/drivers/staging/qcacld-3.0/core/utils/host_diag_log/inc/log_codes.h new file mode 100644 index 0000000000000000000000000000000000000000..98fe903e20dee0b09f79ebf6505d0e175cbcf7d1 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/utils/host_diag_log/inc/log_codes.h @@ -0,0 +1,2075 @@ +/* + * Copyright (c) 2014-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef LOG_CODES_H +#define LOG_CODES_H + +/*=========================================================================== + + Log Code Definitions + + General Description + This file contains log code definitions and is shared with the tools. + + ===========================================================================*/ + +/* DO NOT MODIFY THIS FILE WITHOUT PRIOR APPROVAL +** +** Log codes, by design, are a tightly controlled set of values. +** Developers may not create log codes at will. +** +** Request new logs using the following process: +** +** 1. Send email to asw.diag.request requesting log codassignments. +** 2. Identify the log needed by name. +** 3. Provide a brief description for the log. +** +*/ + +/*=========================================================================== + + Edit History + + $Header: //source/qcom/qct/core/services/diag/api/inc/main/latest/log_codes.h#9 $ + + when who what, where, why + -------- --- ---------------------------------------------------------- + 07/30/09 dhao Consolidate log_codes_apps.h + 07/30/09 dhao Add Last log code definition for Equip ID 11 + 06/26/09 dhao Update format the macro + 06/24/09 sar Reverted last change. + 06/24/09 sar Added log code for LOG_MC_STM_C. + 11/02/01 sfh Featurize common NAS log codes for UMTS. + 10/30/01 sfh Added log code for LOG_GPS_FATPATH_INFO_C. + 10/24/01 sfh Added updates for UMTS equipment ID and log codes. + 06/27/01 lad Added multiple equipment ID support. + 05/22/01 sfh Reserved log codes 158 - 168. + 05/21/01 sfh Keep confusing XXX_BASE_C names for backwards compatibility. + 05/16/01 sfh Reserved log code 155. + 05/08/01 sfh Reserved log codes 150 - 154. + 04/06/01 lad Added definitions of base IDs (such as LOG_WCDMA_BASE_C). + This is currently using temporary ID values in the 0x1000 + range. + 02/23/01 lad Created file from DMSS log.h. Log codes only + + ===========================================================================*/ +#include + +/* ------------------------------------------------------------------------- + * Data Declarations + * ------------------------------------------------------------------------- */ + +/* ------------------------------------------------------------------------- + * Log equipment IDs. + * The most significant 4 bits of the 16 bit log code is the equipment ID. + * Orignally, the mobile was to have an ID, and base stations and other + * IDs. As QCT technology diversifies, new equipment IDs are assigned to new + * technology areas. 0x2000 and 0x3000 are reserved for legacy reasons, so + * the first + * addition starts at 0x4000. + * ------------------------------------------------------------------------- */ + +#define LOG_1X_BASE_C ((uint16_t) 0x1000) +#define LOG_WCDMA_BASE_C ((uint16_t) 0x4000) +#define LOG_GSM_BASE_C ((uint16_t) 0x5000) +#define LOG_LBS_BASE_C ((uint16_t) 0x6000) +#define LOG_UMTS_BASE_C ((uint16_t) 0x7000) +#define LOG_TDMA_BASE_C ((uint16_t) 0x8000) +#define LOG_DTV_BASE_C ((uint16_t) 0xA000) +#define LOG_APPS_BASE_C ((uint16_t) 0xB000) +#define LOG_LTE_BASE_C ((uint16_t) (0xB000 + 0x0010)) +#define LOG_LTE_LAST_C ((uint16_t) 0xB1FF) +#define LOG_WIMAX_BASE_C ((uint16_t) 0xB400) +#define LOG_DSP_BASE_C ((uint16_t) 0xC000) + +#define LOG_TOOLS_BASE_C ((uint16_t) 0xF000) + +/* LOG_BASE_C is what was used before expanding the use of the equipment ID. + * TODO: Once all targets are using the "core" diag system, this should be + * ommitted. */ +#define LOG_BASE_C LOG_1X_BASE_C + +/* ------------------------------------------------------------------------- + * Log Codes + * These codes identify the kind of information contained in a log entry. + * They are used in conjunction with the 'code' field of the log entry + * header. The data types associated with each code are defined below. + * ------------------------------------------------------------------------- */ + +/* The upper 4 bits of the 16 bit log entry code specify which type + * of equipment created the log entry. */ + +/* 0 Mobile Station temporal analyzer entry */ +#define LOG_TA_C (0x0 + LOG_1X_BASE_C) + +/* 1 AGC values and closed loop power control entry */ +#define LOG_AGC_PCTL_C (0x1 + LOG_1X_BASE_C) + +/* 2 Forward link frame rates and types entry */ +#define LOG_F_MUX1_C (0x2 + LOG_1X_BASE_C) + +/* 3 Reverse link frame rates and types entry */ +#define LOG_R_MUX1_C (0x3 + LOG_1X_BASE_C) + +/* 4 Access channel message entry */ +#define LOG_AC_MSG_C (0x4 + LOG_1X_BASE_C) + +/* 5 Reverse link traffic channel message entry */ +#define LOG_R_TC_MSG_C (0x5 + LOG_1X_BASE_C) + +/* 6 Sync channel message entry */ +#define LOG_SC_MSG_C (0x6 + LOG_1X_BASE_C) + +/* 7 Paging channel message entry */ +#define LOG_PC_MSG_C (0x7 + LOG_1X_BASE_C) + +/* 8 Forward link traffic channel message entry */ +#define LOG_F_TC_MSG_C (0x8 + LOG_1X_BASE_C) + +/* 9 Forward link vocoder packet entry */ +#define LOG_VOC_FOR_C (0x9 + LOG_1X_BASE_C) + +/* 10 Reverse link vocoder packet entry */ +#define LOG_VOC_REV_C (0xA + LOG_1X_BASE_C) + +/* 11 Temporal analyzer finger info only */ +#define LOG_FING_C (0xB + LOG_1X_BASE_C) + +/* 12 Searcher pathlog info (Reused old SRCH logtype) */ +#define LOG_SRCH_C (0xC + LOG_1X_BASE_C) + +/* 13 Position and speed information read from ETAK */ +#define LOG_ETAK_C (0xD + LOG_1X_BASE_C) + +/* 14 Markov frame statistics */ +#define LOG_MAR_C (0xE + LOG_1X_BASE_C) + +/* 15 New and improved temporal analyzer searcher info */ +#define LOG_SRCH2_C (0xF + LOG_1X_BASE_C) + +/* 16 The Fujitsu handset information */ +#define LOG_HANDSET_C (0x10 + LOG_1X_BASE_C) + +/* 17 Vocoder bit error rate mask */ +#define LOG_ERRMASK_C (0x11 + LOG_1X_BASE_C) + +/* 18 Analog voice channel information */ +#define LOG_ANALOG_INFO_C (0x12 + LOG_1X_BASE_C) + +/* 19 Access probe information */ +#define LOG_ACC_INFO_C (0x13 + LOG_1X_BASE_C) + +/* 20 Position & speed info read from GPS receiver */ +#define LOG_GPS_C (0x14 + LOG_1X_BASE_C) + +/* 21 Test Command information */ +#define LOG_TEST_CMD_C (0x15 + LOG_1X_BASE_C) + +/* 22 Sparse (20ms) AGC / closed loop power control entry */ +#define LOG_S_AGC_PCTL_C (0x16 + LOG_1X_BASE_C) + +/* 23 Notification of a band class change */ +#define LOG_BAND_CHANGE_C (0x17 + LOG_1X_BASE_C) + +/* 24 DM debug messages, if being logged via log services */ +#define LOG_DBG_MSG_C (0x18 + LOG_1X_BASE_C) + +/* 25 General temporal analyzer entry */ +#define LOG_GENRL_TA_C (0x19 + LOG_1X_BASE_C) + +/* 26 General temporal analyzer w/supplemental channels */ +#define LOG_GENRL_TA_SUP_CH_C (0x1A + LOG_1X_BASE_C) + +/* Featurization Removal requested by CMI + #ifdef FEATURE_PLT + */ + +/* 27 Decoder raw bits logging */ +#define LOG_PLT_C (0x1B + LOG_1X_BASE_C) + +/* Featurization Removal requested by CMI + #else + 27 EFS Usage Info - No implementation as yet + #define LOG_EFS_INFO_C (0x1B + LOG_1X_BASE_C) + #endif + */ + +/* 28 Analog Forward Channel */ +#define LOG_ANALOG_FORW_C (0x1C + LOG_1X_BASE_C) + +/* 29 Analog Reverse Channel */ +#define LOG_ANALOG_REVS_C (0x1D + LOG_1X_BASE_C) + +/* 30 Analog Handoff Entry */ +#define LOG_ANALOG_HANDOFF_C (0x1E + LOG_1X_BASE_C) + +/* 31 FM Slot Statistis entry */ +#define LOG_ANALOG_FMSLOT_C (0x1F + LOG_1X_BASE_C) + +/* 32 FOCC Word Sync Count entry */ +#define LOG_ANALOG_WS_COUNT_C (0x20 + LOG_1X_BASE_C) + +/* 33 */ +#define LOG_RLP_PACKET_C (0x21 + LOG_1X_BASE_C) + +/* 34 */ +#define LOG_ASYNC_TCP_SEG_C (0x22 + LOG_1X_BASE_C) + +/* 35 */ +#define LOG_PACKET_DATA_IP_PACKETS_C (0x23 + LOG_1X_BASE_C) + +/* 36 */ +#define LOG_FNBDT_MESSAGE_LOG_C (0x24 + LOG_1X_BASE_C) + +/* Begin IS-2000 LOG features */ + +/* 37 RLP RX Frames logging */ +#define LOG_RLP_RX_FRAMES_C (0x25 + LOG_1X_BASE_C) + +/* 38 RLP TX Frames logging */ +#define LOG_RLP_TX_FRAMES_C (0x26 + LOG_1X_BASE_C) + +/* 39 Reserved for additions to RLP frames */ +#define LOG_RLP_RSVD1_C (0x27 + LOG_1X_BASE_C) + +/* 40 Reserved for additions to RLP frames */ +#define LOG_RLP_RSVD2_C (0x28 + LOG_1X_BASE_C) + +/* 41 Forward Link Frame Types logging */ +#define LOG_FWD_FRAME_TYPES_C (0x29 + LOG_1X_BASE_C) + +/* 42 Reverse Link Frame Types logging */ +#define LOG_REV_FRAME_TYPES_C (0x2A + LOG_1X_BASE_C) + +/* 43 Fast Forward Power Control Parameters logging */ +#define LOG_FFWD_PCTRL_C (0x2B + LOG_1X_BASE_C) + +/* 44 Reverse Power Control Parameters logging */ +#define LOG_REV_PCTRL_C (0x2C + LOG_1X_BASE_C) + +/* 45 Searcher and Finger Information logging */ +#define LOG_SRCH_FING_INFO_C (0x2D + LOG_1X_BASE_C) + +/* 46 Service Configuration logging */ +#define LOG_SVC_CONFIG_C (0x2E + LOG_1X_BASE_C) + +/* 47 Active Set Configuration logging */ +#define LOG_ASET_CONFIG_C (0x2F + LOG_1X_BASE_C) + +/* 48 Quick Paging Channel logging */ +#define LOG_QPCH_C (0x30 + LOG_1X_BASE_C) + +/* 49 RLP Statistics logging */ +#define LOG_RLP_STAT_C (0x31 + LOG_1X_BASE_C) + +/* 50 Simple Test Data Service Option logging */ +#define LOG_STDSO_C (0x32 + LOG_1X_BASE_C) + +/* 51 Pilot Phase Measurement results logging */ +#define LOG_SRCH_PPM_RES_C (0x33 + LOG_1X_BASE_C) + +/* 52 Pilot Phase Measurement Data Base logging */ +#define LOG_SRCH_PPM_DB_C (0x34 + LOG_1X_BASE_C) + +/* 53 Pilot Phase Measurement search results logging */ +#define LOG_SRCH_PPM_C (0x35 + LOG_1X_BASE_C) + +/* 54 IS-801 forward link message */ +#define LOG_GPS_FWD_MSG_C (0x36 + LOG_1X_BASE_C) + +/* 55 IS-801 reverse link message */ +#define LOG_GPS_REV_MSG_C (0x37 + LOG_1X_BASE_C) + +/* 56 GPS search session statistics */ +#define LOG_GPS_STATS_MSG_C (0x38 + LOG_1X_BASE_C) + +/* 57 GPS search results */ +#define LOG_GPS_SRCH_PEAKS_MSG_C (0x39 + LOG_1X_BASE_C) + +/* 58 Factory Testmode logging */ +#define LOG_FTM_C (0x3A + LOG_1X_BASE_C) + +/* 59 Multiple Peak Logging */ +#define LOG_SRCH_GPS_MULTI_PEAKS_INFO_C (0x3B + LOG_1X_BASE_C) + +/* 60 Post processed search results logs */ +#define LOG_SRCH_GPS_POST_PROC_C (0x3C + LOG_1X_BASE_C) + +/* 61 FULL Test Data Service Option logging */ +#define LOG_FTDSO_C (0x3D + LOG_1X_BASE_C) + +/* 62 Bluetooth logging */ +#define LOG_BT_RESERVED_CODES_BASE_C (0x3E + LOG_1X_BASE_C) +/* Keep confusing name for backwards compatibility. */ +#define LOG_BT_BASE_C LOG_BT_RESERVED_CODES_BASE_C + +/* 92 Bluetooth's last log code */ +#define LOG_BT_LAST_C (30 + LOG_BT_RESERVED_CODES_BASE_C) + +/* 93 HDR log codes */ +#define LOG_HDR_RESERVED_CODES_BASE_C (0x5D + LOG_1X_BASE_C) +/* Keep confusing name for backwards compatibility. */ +#define LOG_HDR_BASE_C LOG_HDR_RESERVED_CODES_BASE_C + +/* 143 is HDR's last log code */ +#define LOG_HDR_LAST_C (50 + LOG_HDR_RESERVED_CODES_BASE_C) + +/* 144 IS2000 DCCH Forward link channel */ +#define LOG_FOR_DCCH_MSG_C (0x90 + LOG_1X_BASE_C) +#define LOG_DCCH_FWD_C LOG_FOR_DCCH_MSG_C + +/* 145 IS2000 DCCH Forward link channel */ +#define LOG_REV_DCCH_MSG_C (0x91 + LOG_1X_BASE_C) +#define LOG_DCCH_REV_C LOG_REV_DCCH_MSG_C + +/* 146 IS2000 DCCH Forward link channel */ +#define LOG_ZREX_C (0x92 + LOG_1X_BASE_C) + +/* 147 Active set info logging, similar to ASET_CONFIG, but simpler. */ +#define LOG_ASET_INFO_C (0x93 + LOG_1X_BASE_C) + +/* 148 Pilot Phase Measurement four-shoulder-search resutlts logging */ +#define LOG_SRCH_PPM_4SHOULDER_RES_C (0x94 + LOG_1X_BASE_C) + +/* 149 Extended Pilot Phase Measurement Data Base logging */ +#define LOG_SRCH_EXT_PPM_DB_C (0x95 + LOG_1X_BASE_C) + +/* 150 GPS Visit Parameters */ +#define LOG_GPS_VISIT_PARAMETERS_C (0x96 + LOG_1X_BASE_C) + +/* 151 GPS Measurement */ +#define LOG_GPS_MEASUREMENT_C (0x97 + LOG_1X_BASE_C) + +/* 152 UIM Data */ +#define LOG_UIM_DATA_C (0x98 + LOG_1X_BASE_C) + +/* 153 STDSO plus P2 */ +#define LOG_STDSO_P2_C (0x99 + LOG_1X_BASE_C) + +/* 154 FTDSO plus P2 */ +#define LOG_FTDSO_P2_C (0x9A + LOG_1X_BASE_C) + +/* 155 Search PPM Statistics */ +#define LOG_SRCH_PPM_STATS_C (0x9B + LOG_1X_BASE_C) + +/* 156 PPP Tx Frames */ +#define LOG_PPP_TX_FRAMES_C (0x9C + LOG_1X_BASE_C) + +/* 157 PPP Rx Frames */ +#define LOG_PPP_RX_FRAMES_C (0x9D + LOG_1X_BASE_C) + +/* 158-187 SSL reserved log codes */ +#define LOG_SSL_RESERVED_CODES_BASE_C (0x9E + LOG_1X_BASE_C) +#define LOG_SSL_LAST_C (29 + LOG_SSL_RESERVED_CODES_BASE_C) + +/* 188-199 Puma reserved log codes */ +/* 188 QPCH, version 2 */ +#define LOG_QPCH_VER_2_C (0xBC + LOG_1X_BASE_C) + +/* 189 Enhanced Access Probe */ +#define LOG_EA_PROBE_C (0xBD + LOG_1X_BASE_C) + +/* 190 BCCH Frame Information */ +#define LOG_BCCH_FRAME_INFO_C (0xBE + LOG_1X_BASE_C) + +/* 191 FCCCH Frame Information */ +#define LOG_FCCCH_FRAME_INFO_C (0xBF + LOG_1X_BASE_C) + +/* 192 FDCH Frame Information */ +#define LOG_FDCH_FRAME_INFO_C (0xC0 + LOG_1X_BASE_C) + +/* 193 RDCH Frame Information */ +#define LOG_RDCH_FRAME_INFO_C (0xC1 + LOG_1X_BASE_C) + +/* 194 FFPC Information */ +#define LOG_FFPC_INFO_C (0xC2 + LOG_1X_BASE_C) + +/* 195 RPC Information */ +#define LOG_RPC_INFO_C (0xC3 + LOG_1X_BASE_C) + +/* 196 Searcher and Finger Information */ +#define LOG_SRCH_FING_INFO_VER_2_C (0xC4 + LOG_1X_BASE_C) + +/* 197 Service Configuration, version 2 */ +#define LOG_SRV_CONFIG_VER_2_C (0xC5 + LOG_1X_BASE_C) + +/* 198 Active Set Information, version 2 */ +#define LOG_ASET_INFO_VER_2_C (0xC6 + LOG_1X_BASE_C) + +/* 199 Reduced Active Set */ +#define LOG_REDUCED_ASET_INFO_C (0xC7 + LOG_1X_BASE_C) + +/* 200 Search Triage Info */ +#define LOG_SRCH_TRIAGE_INFO_C (0xC8 + LOG_1X_BASE_C) + +/* 201 RDA Frame Information */ +#define LOG_RDA_FRAME_INFO_C (0xC9 + LOG_1X_BASE_C) + +/* 202 gpsOne fatpath information */ +#define LOG_GPS_FATPATH_INFO_C (0xCA + LOG_1X_BASE_C) + +/* 203 Extended AGC */ +#define LOG_EXTENDED_AGC_C (0xCB + LOG_1X_BASE_C) + +/* 204 Transmit AGC */ +#define LOG_TRANSMIT_AGC_C (0xCC + LOG_1X_BASE_C) + +/* 205 I/Q Offset registers */ +#define LOG_IQ_OFFSET_REGISTERS_C (0xCD + LOG_1X_BASE_C) + +/* 206 DACC I/Q Accumulator registers */ +#define LOG_DACC_IQ_ACCUMULATOR_C (0xCE + LOG_1X_BASE_C) + +/* 207 Register polling results */ +#define LOG_REGISTER_POLLING_RESULTS_C (0xCF + LOG_1X_BASE_C) + +/* 208 System arbitration module */ +#define LOG_AT_SAM_C (0xD0 + LOG_1X_BASE_C) + +/* 209 Diablo searcher finger log */ +#define LOG_DIABLO_SRCH_FING_INFO_C (0xD1 + LOG_1X_BASE_C) + +/* 210 log reserved for dandrus */ +#define LOG_SD20_LAST_ACTION_C (0xD2 + LOG_1X_BASE_C) + +/* 211 log reserved for dandrus */ +#define LOG_SD20_LAST_ACTION_HYBRID_C (0xD3 + LOG_1X_BASE_C) + +/* 212 log reserved for dandrus */ +#define LOG_SD20_SS_OBJECT_C (0xD4 + LOG_1X_BASE_C) + +/* 213 log reserved for dandrus */ +#define LOG_SD20_SS_OBJECT_HYBRID_C (0xD5 + LOG_1X_BASE_C) + +/* 214 log reserved for jpinos */ +#define LOG_BCCH_SIGNALING_C (0xD6 + LOG_1X_BASE_C) + +/* 215 log reserved for jpinos */ +#define LOG_REACH_SIGNALING_C (0xD7 + LOG_1X_BASE_C) + +/* 216 log reserved for jpinos */ +#define LOG_FCCCH_SIGNALING_C (0xD8 + LOG_1X_BASE_C) + +/* 217 RDA Frame Information 2 */ +#define LOG_RDA_FRAME_INFO_2_C (0xD9 + LOG_1X_BASE_C) + +/* 218 */ +#define LOG_GPS_BIT_EDGE_RESULTS_C (0xDA + LOG_1X_BASE_C) + +/* 219 */ +#define LOG_PE_DATA_C (0xDB + LOG_1X_BASE_C) + +/* 220 */ +#define LOG_PE_PARTIAL_DATA_C (0xDC + LOG_1X_BASE_C) + +/* 221 */ +#define LOG_GPS_SINGLE_PEAK_SRCH_RESULTS_C (0xDD + LOG_1X_BASE_C) + +/* 222 */ +#define LOG_SRCH4_SAMPRAM_C (0xDE + LOG_1X_BASE_C) + +/* 223 */ +#define HDR_AN_PPP_TX_FRAMES (0xDF + LOG_1X_BASE_C) + +/* 224 */ +#define HDR_AN_PPP_RX_FRAMES (0xE0 + LOG_1X_BASE_C) + +/* 225 */ +#define LOG_GPS_SCHEDULER_TRACE_C (0xE1 + LOG_1X_BASE_C) + +/* 226 */ +#define LOG_MPEG4_YUV_FRAME_C (0xE2 + LOG_1X_BASE_C) + +/* 227 */ +#define LOG_MPEG4_CLIP_STATS_C (0xE3 + LOG_1X_BASE_C) + +/* 228 */ +#define LOG_MPEG4_CLIP_STATS_VER2_C (0xE4 + LOG_1X_BASE_C) + +/* 226-241 MMEG reserved. */ +#define LOG_MPEG_RESERVED_CODES_BASE_C (0xF1 + LOG_1X_BASE_C) + +/* 242-274 BREW reserved log range */ +#define LOG_BREW_RESERVED_CODES_BASE_C (0xF2 + LOG_1X_BASE_C) +#define LOG_BREW_LAST_C (32 + LOG_BREW_RESERVED_CODES_BASE_C) + +/* 275-339 PPP Extended Frames */ +#define LOG_PPP_FRAMES_RESERVED_CODES_BASE_C (0x113 + LOG_1X_BASE_C) +#define LOG_PPP_FRAMES_LAST_C (64 + LOG_PPP_FRAMES_RESERVED_CODES_BASE_C) + +#define LOG_PPP_EXT_FRAMED_RX_UM_C (0x113 + LOG_1X_BASE_C) +#define LOG_PPP_EXT_FRAMED_RX_RM_C (0x114 + LOG_1X_BASE_C) +#define LOG_PPP_EXT_FRAMED_RX_AN_C (0x115 + LOG_1X_BASE_C) + +#define LOG_PPP_EXT_FRAMED_TX_UM_C (0x123 + LOG_1X_BASE_C) +#define LOG_PPP_EXT_FRAMED_TX_RM_C (0x124 + LOG_1X_BASE_C) +#define LOG_PPP_EXT_FRAMED_TX_AN_C (0x125 + LOG_1X_BASE_C) + +#define LOG_PPP_EXT_UNFRAMED_RX_UM_C (0x133 + LOG_1X_BASE_C) +#define LOG_PPP_EXT_UNFRAMED_RX_RM_C (0x134 + LOG_1X_BASE_C) +#define LOG_PPP_EXT_UNFRAMED_RX_AN_C (0x135 + LOG_1X_BASE_C) + +#define LOG_PPP_EXT_UNFRAMED_TX_UM_C (0x143 + LOG_1X_BASE_C) +#define LOG_PPP_EXT_UNFRAMED_TX_RM_C (0x144 + LOG_1X_BASE_C) +#define LOG_PPP_EXT_UNFRAMED_TX_AN_C (0x145 + LOG_1X_BASE_C) + +/* 340 LOG_PE_DATA_EXT_C */ +#define LOG_PE_DATA_EXT_C (0x154 + LOG_1X_BASE_C) + +/* REX Subsystem logs */ +#define LOG_MEMDEBUG_C (0x155 + LOG_1X_BASE_C) +#define LOG_SYSPROFILE_C (0x156 + LOG_1X_BASE_C) +#define LOG_TASKPROFILE_C (0x157 + LOG_1X_BASE_C) +#define LOG_COREDUMP_C (0x158 + LOG_1X_BASE_C) + +/* 341-349 REX subsystem logs */ +#define LOG_REX_RESERVED_CODES_BASE_C (0x155 + LOG_1X_BASE_C) +#define LOG_REX_LAST_C (8 + LOG_REX_RESERVED_CODES_BASE_C) + +/* 350 LOG_PE_PARTIAL_DATA_EXT_C */ +#define LOG_PE_PARTIAL_DATA_EXT_C (0x15E + LOG_1X_BASE_C) + +/* 351 LOG_DIAG_STRESS_TEST_C */ +#define LOG_DIAG_STRESS_TEST_C (0x15F + LOG_1X_BASE_C) + +/* 352 LOG_WMS_READ_C */ +#define LOG_WMS_READ_C (0x160 + LOG_1X_BASE_C) + +/* 353 Search Triage Info Version 2 */ +#define LOG_SRCH_TRIAGE_INFO2_C (0x161 + LOG_1X_BASE_C) + +/* 354 RLP Rx FDCH Frames */ +#define LOG_RLP_RX_FDCH_FRAMES_C (0x162 + LOG_1X_BASE_C) + +/* 355 RLP Tx FDCH Frames */ +#define LOG_RLP_TX_FDCH_FRAMES_C (0x163 + LOG_1X_BASE_C) + +/* 356-371 QTV subsystem logs */ +#define LOG_QTV_RESERVED_CODES_BASE_C (0x164 + LOG_1X_BASE_C) +#define LOG_QTV_LAST_C (15 + LOG_QTV_RESERVED_CODES_BASE_C) + +/* 372 Searcher 4 1X */ +#define LOG_SRCH4_1X_C (0x174 + LOG_1X_BASE_C) + +/* 373 Searcher sleep statistics */ +#define LOG_SRCH_SLEEP_STATS_C (0x175 + LOG_1X_BASE_C) + +/* 374 Service Configuration, version 3 */ +#define LOG_SRV_CONFIG_VER_3_C (0x176 + LOG_1X_BASE_C) + +/* 375 Searcher 4 HDR */ +#define LOG_SRCH4_HDR_C (0x177 + LOG_1X_BASE_C) + +/* 376 Searcher 4 AFLT */ +#define LOG_SRCH4_AFLT_C (0x178 + LOG_1X_BASE_C) + +/* 377 Enhanced Finger Information */ +#define LOG_ENH_FING_INFO_C (0x179 + LOG_1X_BASE_C) + +/* 378 DV Information */ +#define LOG_DV_INFO_C (0x17A + LOG_1X_BASE_C) + +/* 379 WMS set routes information */ +#define LOG_WMS_SET_ROUTES_C (0x17B + LOG_1X_BASE_C) + +/* 380 FTM Version 2 Logs */ +#define LOG_FTM_VER_2_C (0x17C + LOG_1X_BASE_C) + +/* 381 GPS Multipeak logging */ +#define LOG_SRCH_GPS_MULTI_PEAKS_SIMPLIFIED_INFO_C (0x17D + LOG_1X_BASE_C) + +/* 382 GPS Multipeak logging */ +#define LOG_SRCH_GPS_MULTI_PEAKS_VERBOSE_INFO_C (0x17E + LOG_1X_BASE_C) + +/* 383-403 HDR reserved logs */ +#define LOG_HDR_RESERVED_CODES_BASE_2_C (0x17F + LOG_1X_BASE_C) +#define LOG_HDR_LAST_2_C (20 + LOG_HDR_RESERVED_CODES_BASE_2_C) + +/* RLP Rx - PDCH partial MuxPDU5 frames */ +#define LOG_RLP_RX_PDCH_PARTIAL_MUXPDU5_FRAMES_C (0x194 + LOG_1X_BASE_C) + +/* RLP Tx - PDCH partial MuxPDU5 frames */ +#define LOG_RLP_TX_PDCH_PARTIAL_MUXPDU5_FRAMES_C (0x195 + LOG_1X_BASE_C) + +/* RLP Rx internal details */ +#define LOG_RLP_RX_INTERNAL_DETAILS_C (0x196 + LOG_1X_BASE_C) + +/* RLP Tx internal details */ +#define LOG_RLP_TX_INTERNAL_DETAILS_C (0x197 + LOG_1X_BASE_C) + +/* MPEG4 Clip Statistics version 3 */ +#define LOG_MPEG4_CLIP_STATS_VER3_C (0x198 + LOG_1X_BASE_C) + +/* Mobile IP Performance */ +#define LOG_MOBILE_IP_PERFORMANCE_C (0x199 + LOG_1X_BASE_C) + +/* 410-430 Searcher reserved logs */ +#define LOG_SEARCHER_RESERVED_CODES_BASE_C (0x19A + LOG_1X_BASE_C) +#define LOG_SEARCHER_LAST_2_C (21 + LOG_SEARCHER_RESERVED_CODES_BASE_C) + +/* 432-480 QTV reserved logs */ +#define LOG_QTV2_RESERVED_CODES_BASE_C (0x1B0 + LOG_1X_BASE_C) +#define LOG_QTV2_LAST_C (48 + LOG_QTV2_RESERVED_CODES_BASE_C) + +#define LOG_QTV_PDS2_STATS (0x1B6 + LOG_1X_BASE_C) +#define LOG_QTV_PDS2_GET_REQUEST (0x1B7 + LOG_1X_BASE_C) +#define LOG_QTV_PDS2_GET_RESP_HEADER (0x1B8 + LOG_1X_BASE_C) +#define LOG_QTV_PDS2_GET_RESP_PCKT (0x1B9 + LOG_1X_BASE_C) +#define LOG_QTV_CMX_AUDIO_INPUT_DATA_C (0x1BA + LOG_1X_BASE_C) +#define LOG_QTV_RTSP_OPTIONS_C (0x1BB + LOG_1X_BASE_C) +#define LOG_QTV_RTSP_GET_PARAMETER_C (0x1BC + LOG_1X_BASE_C) +#define LOG_QTV_RTSP_SET_PARAMETER_C (0x1BD + LOG_1X_BASE_C) +#define LOG_QTV_VIDEO_BITSTREAM (0x1BE + LOG_1X_BASE_C) +#define LOG_ARM_VIDEO_DECODE_STATS (0x1BF + LOG_1X_BASE_C) +#define LOG_QTV_DSP_SLICE_BUFFER_C (0x1C0 + LOG_1X_BASE_C) +#define LOG_QTV_CMD_LOGGING_C (0x1C1 + LOG_1X_BASE_C) +#define LOG_QTV_AUDIO_FRAME_PTS_INFO_C (0x1C2 + LOG_1X_BASE_C) +#define LOG_QTV_VIDEO_FRAME_DECODE_INFO_C (0x1C3 + LOG_1X_BASE_C) +#define LOG_QTV_RTCP_COMPOUND_RR_C (0x1C4 + LOG_1X_BASE_C) +#define LOG_QTV_FRAME_BUFFER_RELEASE_REASON_C (0x1C5 + LOG_1X_BASE_C) +#define LOG_QTV_AUDIO_CHANNEL_SWITCH_FRAME_C (0x1C6 + LOG_1X_BASE_C) +#define LOG_QTV_RTP_DECRYPTED_PKT_C (0x1C7 + LOG_1X_BASE_C) +#define LOG_QTV_PCR_DRIFT_RATE_C (0x1C8 + LOG_1X_BASE_C) + +/* GPS PDSM logs */ +#define LOG_PDSM_POSITION_REPORT_CALLBACK_C (0x1E1 + LOG_1X_BASE_C) +#define LOG_PDSM_PD_EVENT_CALLBACK_C (0x1E2 + LOG_1X_BASE_C) +#define LOG_PDSM_PA_EVENT_CALLBACK_C (0x1E3 + LOG_1X_BASE_C) +#define LOG_PDSM_NOTIFY_VERIFY_REQUEST_C (0x1E4 + LOG_1X_BASE_C) +#define LOG_PDSM_RESERVED1_C (0x1E5 + LOG_1X_BASE_C) +#define LOG_PDSM_RESERVED2_C (0x1E6 + LOG_1X_BASE_C) + +/* Searcher Demodulation Status log */ +#define LOG_SRCH_DEMOD_STATUS_C (0x1E7 + LOG_1X_BASE_C) + +/* Searcher Call Statistics log */ +#define LOG_SRCH_CALL_STATISTICS_C (0x1E8 + LOG_1X_BASE_C) + +/* GPS MS-MPC Forward link */ +#define LOG_MS_MPC_FWD_LINK_C (0x1E9 + LOG_1X_BASE_C) + +/* GPS MS-MPC Reverse link */ +#define LOG_MS_MPC_REV_LINK_C (0x1EA + LOG_1X_BASE_C) + +/* Protocol Services Data */ +#define LOG_DATA_PROTOCOL_LOGGING_C (0x1EB + LOG_1X_BASE_C) + +/* MediaFLO reserved log codes */ +#define LOG_MFLO_RESERVED_CODES_BASE_C (0x1EC + LOG_1X_BASE_C) +#define LOG_MFLO_LAST_C (99 + LOG_MFLO_RESERVED_CODES_BASE_C) + +/* GPS demodulation tracking header info */ +#define LOG_GPS_DEMOD_TRACKING_HEADER_C (0x250 + LOG_1X_BASE_C) + +/* GPS demodulation tracking results */ +#define LOG_GPS_DEMOD_TRACKING_C (0x251 + LOG_1X_BASE_C) + +/* GPS bit edge logs from demod tracking */ +#define LOG_GPS_DEMOD_BIT_EDGE_C (0x252 + LOG_1X_BASE_C) + +/* GPS demodulation soft decisions */ +#define LOG_GPS_DEMOD_SOFT_DECISIONS_C (0x253 + LOG_1X_BASE_C) + +/* GPS post-processed demod tracking results */ +#define LOG_GPS_DEMOD_TRACKING_POST_PROC_C (0x254 + LOG_1X_BASE_C) + +/* GPS subframe log */ +#define LOG_GPS_DEMOD_SUBFRAME_C (0x255 + LOG_1X_BASE_C) + +/* F-CPCCH Quality Information */ +#define LOG_F_CPCCH_QUALITY_INFO_C (0x256 + LOG_1X_BASE_C) + +/* Reverse PDCCH/PDCH Frame Information */ +#define LOG_R_PDCCH_R_PDCH_FRAME_INFO_C (0x257 + LOG_1X_BASE_C) + +/* Forward G Channel Information */ +#define LOG_F_GCH_INFO_C (0x258 + LOG_1X_BASE_C) + +/* Forward G Channel Frame Information */ +#define LOG_F_GCH_FRAME_INFO_C (0x259 + LOG_1X_BASE_C) + +/* Forward RC Channel Information */ +#define LOG_F_RCCH_INFO_C (0x25A + LOG_1X_BASE_C) + +/* Forward ACK Channel Information */ +#define LOG_F_ACKCH_INFO_C (0x25B + LOG_1X_BASE_C) + +/* Forward ACK Channel ACKDA Information */ +#define LOG_F_ACKCH_ACKDA_C (0x25C + LOG_1X_BASE_C) + +/* Reverse REQ Channel Information */ +#define LOG_R_REQCH_INFO_C (0x25D + LOG_1X_BASE_C) + +/* Sleep Task Statistics */ +#define LOG_SLEEP_STATS_C (0x25E + LOG_1X_BASE_C) + +/* Sleep controller statistics 1X */ +#define LOG_1X_SLEEP_CONTROLLER_STATS_C (0x25F + LOG_1X_BASE_C) + +/* Sleep controller statistics HDR */ +#define LOG_HDR_SLEEP_CONTROLLER_STATS_C (0x260 + LOG_1X_BASE_C) + +/* Sleep controller statistics GSM */ +#define LOG_GSM_SLEEP_CONTROLLER_STATS_C (0x261 + LOG_1X_BASE_C) + +/* Sleep controller statistics WCDMA */ +#define LOG_WCDMA_SLEEP_CONTROLLER_STATS_C (0x262 + LOG_1X_BASE_C) + +/* Sleep task and controller reserved logs */ +#define LOG_SLEEP_APPS_STATS_C (0x263 + LOG_1X_BASE_C) +#define LOG_SLEEP_STATS_RESERVED2_C (0x264 + LOG_1X_BASE_C) +#define LOG_SLEEP_STATS_RESERVED3_C (0x265 + LOG_1X_BASE_C) + +/* DV Information placeholder channel logs */ +#define LOG_PDCCH_LO_SELECTED_C (0x266 + LOG_1X_BASE_C) +#define LOG_PDCCH_HI_SELECTED_C (0x267 + LOG_1X_BASE_C) +#define LOG_WALSH_SELECTED_C (0x268 + LOG_1X_BASE_C) +#define LOG_PDCH_BE_SELECTED_C (0x269 + LOG_1X_BASE_C) +#define LOG_PDCCH_LLR_SELECTED_C (0x26A + LOG_1X_BASE_C) +#define LOG_CQI_ACK_LO_SELECTED_C (0x26B + LOG_1X_BASE_C) +#define LOG_CQI_ACK_HI_SELECTED_C (0x26C + LOG_1X_BASE_C) +#define LOG_RL_GAIN_SELECTED_C (0x26D + LOG_1X_BASE_C) +#define LOG_PDCCH0_SNDA_SELECTED_C (0x26E + LOG_1X_BASE_C) +#define LOG_PDCCH1_SNDA_SELECTED_C (0x26F + LOG_1X_BASE_C) + +/* 624 WMS Message List */ +#define LOG_WMS_MESSAGE_LIST_C (0x270 + LOG_1X_BASE_C) + +/* 625 Multimode Generic SIM Driver Interface */ +#define LOG_MM_GENERIC_SIM_DRIVER_C (0x271 + LOG_1X_BASE_C) + +/* 626 Generic SIM Toolkit Task */ +#define LOG_GENERIC_SIM_TOOLKIT_TASK_C (0x272 + LOG_1X_BASE_C) + +/* 627 Call Manager Phone events log */ +#define LOG_CM_PH_EVENT_C (0x273 + LOG_1X_BASE_C) + +/* 628 WMS Set Message List */ +#define LOG_WMS_SET_MESSAGE_LIST_C (0x274 + LOG_1X_BASE_C) + +/* 629-704 HDR reserved logs */ +#define LOG_HDR_RESERVED_CODES_BASE_3_C (0x275 + LOG_1X_BASE_C) +#define LOG_HDR_LAST_3_C (75 + LOG_HDR_RESERVED_CODES_BASE_3_C) + +/* 705 Call Manager call event log */ +#define LOG_CM_CALL_EVENT_C (0x2C1 + LOG_1X_BASE_C) + +/* 706-738 QVP reserved logs */ +#define LOG_QVP_RESERVED_CODES_BASE_C (0x2C2 + LOG_1X_BASE_C) +#define LOG_QVP_LAST_C (32 + LOG_QVP_RESERVED_CODES_BASE_C) + +/* 739 GPS PE Position Report log */ +#define LOG_GPS_PE_POSITION_REPORT_C (0x2E3 + LOG_1X_BASE_C) + +/* 740 GPS PE Position Report Extended log */ +#define LOG_GPS_PE_POSITION_REPORT_EXT_C (0x2E4 + LOG_1X_BASE_C) + +/* 741 log */ +#define LOG_MDDI_HOST_STATS_C (0x2E5 + LOG_1X_BASE_C) + +/* GPS Decoded Ephemeris */ +#define LOG_GPS_DECODED_EPHEMERIS_C (0x2E6 + LOG_1X_BASE_C) + +/* GPS Decoded Almanac */ +#define LOG_GPS_DECODED_ALMANAC_C (0x2E7 + LOG_1X_BASE_C) + +/* Transceiver Resource Manager */ +#define LOG_TRANSCEIVER_RESOURCE_MGR_C (0x2E8 + LOG_1X_BASE_C) + +/* GPS Position Engine Info */ +#define LOG_GPS_POSITION_ENGINE_INFO_C (0x2E9 + LOG_1X_BASE_C) + +/* 746-810 RAPTOR reserved log range */ +#define LOG_RAPTOR_RESERVED_CODES_BASE_C (0x2EA + LOG_1X_BASE_C) +#define LOG_RAPTOR_LAST_C (64 + LOG_RAPTOR_RESERVED_CODES_BASE_C) + +/* QOS Specification Logging */ + +/* QOS Requested Log */ +#define LOG_QOS_REQUESTED_C (0x32B + LOG_1X_BASE_C) + +/* QOS Granted Log */ +#define LOG_QOS_GRANTED_C (0x32C + LOG_1X_BASE_C) + +/* QOS State Log */ +#define LOG_QOS_STATE_C (0x32D + LOG_1X_BASE_C) + +#define LOG_QOS_MODIFIED_C (0x32E + LOG_1X_BASE_C) + +#define LOG_QDJ_ENQUEUE_C (0x32F + LOG_1X_BASE_C) +#define LOG_QDJ_DEQUEUE_C (0x330 + LOG_1X_BASE_C) +#define LOG_QDJ_UPDATE_C (0x331 + LOG_1X_BASE_C) +#define LOG_QDTX_ENCODER_C (0x332 + LOG_1X_BASE_C) +#define LOG_QDTX_DECODER_C (0x333 + LOG_1X_BASE_C) + +#define LOG_PORT_ASSIGNMENT_STATUS_C (0x334 + LOG_1X_BASE_C) + +/* Protocol Services reserved log codes */ +#define LOG_PS_RESERVED_CODES_BASE_C (0x335 + LOG_1X_BASE_C) +#define LOG_PS_LAST_C (25 + LOG_PS_RESERVED_C) + +#define LOG_PS_STAT_IP_C (0x335 + LOG_1X_BASE_C) +#define LOG_PS_STAT_GLOBAL_IPV4_C (0x335 + LOG_1X_BASE_C) +#define LOG_PS_STAT_GLOBAL_IPV6_C (0x336 + LOG_1X_BASE_C) +#define LOG_PS_STAT_GLOBAL_ICMPV4_C (0x337 + LOG_1X_BASE_C) +#define LOG_PS_STAT_GLOBAL_ICMPV6_C (0x338 + LOG_1X_BASE_C) +#define LOG_PS_STAT_GLOBAL_TCP_C (0x339 + LOG_1X_BASE_C) +#define LOG_PS_STAT_GLOBAL_UDP_C (0x33A + LOG_1X_BASE_C) + +/* Protocol Services describe all TCP instances */ +#define LOG_PS_STAT_DESC_ALL_TCP_INST_C (0x33B + LOG_1X_BASE_C) + +/* Protocol Services describe all memory pool instances */ +#define LOG_PS_STAT_DESC_ALL_MEM_POOL_INST_C (0x33C + LOG_1X_BASE_C) + +/* Protocol Services describe all IFACE instances */ +#define LOG_PS_STAT_DESC_ALL_IFACE_INST_C (0x33D + LOG_1X_BASE_C) + +/* Protocol Services describe all PPP instances */ +#define LOG_PS_STAT_DESC_ALL_PPP_INST_C (0x33E + LOG_1X_BASE_C) + +/* Protocol Services describe all ARP instances */ +#define LOG_PS_STAT_DESC_ALL_ARP_INST_C (0x33F + LOG_1X_BASE_C) + +/* Protocol Services describe delta instance */ +#define LOG_PS_STAT_DESC_DELTA_INST_C (0x340 + LOG_1X_BASE_C) + +/* Protocol Services instance TCP statistics */ +#define LOG_PS_STAT_TCP_INST_C (0x341 + LOG_1X_BASE_C) + +/* Protocol Services instance UDP statistics */ +#define LOG_PS_STAT_UDP_INST_C (0x342 + LOG_1X_BASE_C) + +/* Protocol Services instance PPP statistics */ +#define LOG_PS_STAT_PPP_INST_C (0x343 + LOG_1X_BASE_C) + +/* Protocol Services instance IFACE statistics */ +#define LOG_PS_STAT_IFACE_INST_C (0x344 + LOG_1X_BASE_C) + +/* Protocol Services instance memory statistics */ +#define LOG_PS_STAT_MEM_INST_C (0x345 + LOG_1X_BASE_C) + +/* Protocol Services instance flow statistics */ +#define LOG_PS_STAT_FLOW_INST_C (0x346 + LOG_1X_BASE_C) + +/* Protocol Services instance physical link statistics */ +#define LOG_PS_STAT_PHYS_LINK_INST_C (0x347 + LOG_1X_BASE_C) + +/* Protocol Services instance ARP statistics */ +#define LOG_PS_STAT_ARP_INST_C (0x348 + LOG_1X_BASE_C) + +/* Protocol Services instance LLC statistics */ +#define LOG_PS_STAT_LLC_INST_C (0x349 + LOG_1X_BASE_C) + +/* Protocol Services instance IPHC statistics */ +#define LOG_PS_STAT_IPHC_INST_C (0x34A + LOG_1X_BASE_C) + +/* Protocol Services instance ROHC statistics */ +#define LOG_PS_STAT_ROHC_INST_C (0x34B + LOG_1X_BASE_C) + +/* Protocol Services instance RSVP statistics */ +#define LOG_PS_STAT_RSVP_INST_C (0x34C + LOG_1X_BASE_C) + +/* Protocol Services describe all LLC instances */ +#define LOG_PS_STAT_DESC_ALL_LLC_INST_C (0x34D + LOG_1X_BASE_C) + +/* Protocol Services describe all RSVP instances */ +#define LOG_PS_STAT_DESC_ALL_RSVP_INST_C (0x34E + LOG_1X_BASE_C) + +/* Call Manager Serving System event log */ +#define LOG_CM_SS_EVENT_C (0x34F + LOG_1X_BASE_C) + +/* VcTcxo manager’s automatic frequency control log */ +#define LOG_TCXOMGR_AFC_DATA_C (0x350 + LOG_1X_BASE_C) + +/* Clock transactions and general clocks status log */ +#define LOG_CLOCK_C (0x351 + LOG_1X_BASE_C) + +/* GPS search processed peak results and their associated search parameters */ +#define LOG_GPS_PROCESSED_PEAK_C (0x352 + LOG_1X_BASE_C) + +#define LOG_MDSP_LOG_CHUNKS_C (0x353 + LOG_1X_BASE_C) + +/* Periodic RSSI update log */ +#define LOG_WLAN_RSSI_UPDATE_C (0x354 + LOG_1X_BASE_C) + +/* Periodic Link Layer statistics log */ +#define LOG_WLAN_LL_STAT_C (0x355 + LOG_1X_BASE_C) + +/* QOS Extended State Log */ +#define LOG_QOS_STATE_EX_C (0x356 + LOG_1X_BASE_C) + +/* Bluetooth host HCI transmitted data */ +#define LOG_BT_HOST_HCI_TX_C (0x357 + LOG_1X_BASE_C) + +/* Bluetooth host HCI received data */ +#define LOG_BT_HOST_HCI_RX_C (0x358 + LOG_1X_BASE_C) + +/* Internal - GPS PE Position Report Part 3 */ +#define LOG_GPS_PE_POSITION_REPORT_PART3_C (0x359 + LOG_1X_BASE_C) + +/* Extended log code which logs requested QoS */ +#define LOG_QOS_REQUESTED_EX_C (0x35A + LOG_1X_BASE_C) + +/* Extended log code which logs granted QoS */ +#define LOG_QOS_GRANTED_EX_C (0x35B + LOG_1X_BASE_C) + +/* Extended log code which logs modified QoS */ +#define LOG_QOS_MODIFIED_EX_C (0x35C + LOG_1X_BASE_C) + +/* Bus Monitor Profiling Info */ +#define LOG_BUS_MON_PROF_INFO_C (0x35D + LOG_1X_BASE_C) + +/* Pilot Phase Measurement Search results */ +#define LOG_SRCH_PPM_RES_VER_2_C (0x35E + LOG_1X_BASE_C) + +/* Pilot Phase Measurement Data Base */ +#define LOG_SRCH_PPM_DB_VER_2_C (0x35F + LOG_1X_BASE_C) + +/* Pilot Phase Measurement state machine */ +#define LOG_PPM_SM_C (0x360 + LOG_1X_BASE_C) + +/* Robust Header Compression - Compressor */ +#define LOG_ROHC_COMPRESSOR_C (0x361 + LOG_1X_BASE_C) + +/* Robust Header Compression - Decompressor */ +#define LOG_ROHC_DECOMPRESSOR_C (0x362 + LOG_1X_BASE_C) + +/* Robust Header Compression - Feedback Compressor */ +#define LOG_ROHC_FEEDBACK_COMPRESSOR_C (0x363 + LOG_1X_BASE_C) + +/* Robust Header Compression - Feedback Decompressor */ +#define LOG_ROHC_FEEDBACK_DECOMPRESSOR_C (0x364 + LOG_1X_BASE_C) + +/* Bluetooth HCI commands */ +#define LOG_BT_HCI_CMD_C (0x365 + LOG_1X_BASE_C) + +/* Bluetooth HCI events */ +#define LOG_BT_HCI_EV_C (0x366 + LOG_1X_BASE_C) + +/* Bluetooth HCI Transmitted ACL data */ +#define LOG_BT_HCI_TX_ACL_C (0x367 + LOG_1X_BASE_C) + +/* Bluetooth HCI Received ACL data */ +#define LOG_BT_HCI_RX_ACL_C (0x368 + LOG_1X_BASE_C) + +/* Bluetooth SOC H4 Deep Sleep */ +#define LOG_BT_SOC_H4DS_C (0x369 + LOG_1X_BASE_C) + +/* UMTS to CDMA Handover Message */ +#define LOG_UMTS_TO_CDMA_HANDOVER_MSG_C (0x36A + LOG_1X_BASE_C) + +/* Graphic Event Data */ +#define LOG_PROFILER_GRAPHIC_DATA_C (0x36B + LOG_1X_BASE_C) + +/* Audio Event Data */ +#define LOG_PROFILER_AUDIO_DATA_C (0x36C + LOG_1X_BASE_C) + +/* GPS Spectral Information */ +#define LOG_GPS_SPECTRAL_INFO_C (0x36D + LOG_1X_BASE_C) + +/* AHB Performance Monitor LOG data */ +#define LOG_APM_C (0x36E + LOG_1X_BASE_C) + +/* GPS Clock Report */ +#define LOG_CONVERGED_GPS_CLOCK_REPORT_C (0x36F + LOG_1X_BASE_C) + +/* GPS Position Report */ +#define LOG_CONVERGED_GPS_POSITION_REPORT_C (0x370 + LOG_1X_BASE_C) + +/* GPS Measurement Report */ +#define LOG_CONVERGED_GPS_MEASUREMENT_REPORT_C (0x371 + LOG_1X_BASE_C) + +/* GPS RF Status Report */ +#define LOG_CONVERGED_GPS_RF_STATUS_REPORT_C (0x372 + LOG_1X_BASE_C) + +/* VOIP To CDMA Handover Message - Obsoleted by 0x138B - 0x138D */ +#define LOG_VOIP_TO_CDMA_HANDOVER_MSG_C (0x373 + LOG_1X_BASE_C) + +/* GPS Prescribed Dwell Result */ +#define LOG_GPS_PRESCRIBED_DWELL_RESULT_C (0x374 + LOG_1X_BASE_C) + +/* CGPS IPC Data */ +#define LOG_CGPS_IPC_DATA_C (0x375 + LOG_1X_BASE_C) + +/* CGPS Non IPC Data */ +#define LOG_CGPS_NON_IPC_DATA_C (0x376 + LOG_1X_BASE_C) + +/* CGPS Session Report */ +#define LOG_CGPS_REP_EVT_LOG_PACKET_C (0x377 + LOG_1X_BASE_C) + +/* CGPS PDSM Get Position */ +#define LOG_CGPS_PDSM_GET_POSITION_C (0x378 + LOG_1X_BASE_C) + +/* CGPS PDSM Set Parameters */ +#define LOG_CGPS_PDSM_SET_PARAMETERS_C (0x379 + LOG_1X_BASE_C) + +/* CGPS PDSM End Session */ +#define LOG_CGPS_PDSM_END_SESSION_C (0x37A + LOG_1X_BASE_C) + +/* CGPS PDSM notify Verify Response */ +#define LOG_CGPS_PDSM_NOTIFY_VERIFY_RESP_C (0x37B + LOG_1X_BASE_C) + +/* CGPS PDSM Position Report Callback */ +#define LOG_CGPS_PDSM_POSITION_REPORT_CALLBACK_C (0x37C + LOG_1X_BASE_C) + +/* CGPS PDSM PD Event Callback */ +#define LOG_CGPS_PDSM_PD_EVENT_CALLBACK_C (0x37D + LOG_1X_BASE_C) + +/* CGPS PDSM PA Event Callback */ +#define LOG_CGPS_PDSM_PA_EVENT_CALLBACK_C (0x37E + LOG_1X_BASE_C) + +/* CGPS PDSM notify Verify Request Callback */ +#define LOG_CGPS_PDSM_NOTIFY_VERIFY_REQUEST_C (0x37F + LOG_1X_BASE_C) + +/* CGPS PDSM PD Command Error Callback */ +#define LOG_CGPS_PDSM_PD_CMD_ERR_CALLBACK_C (0x380 + LOG_1X_BASE_C) + +/* CGPS PDSM PA Command Error Callback */ +#define LOG_CGPS_PDSM_PA_CMD_ERR_CALLBACK_C (0x381 + LOG_1X_BASE_C) + +/* CGPS PDSM Position Error */ +#define LOG_CGPS_PDSM_POS_ERROR_C (0x382 + LOG_1X_BASE_C) + +/* CGPS PDSM Extended Status Position Report */ +#define LOG_CGPS_PDSM_EXT_STATUS_POS_REPORT_C (0x383 + LOG_1X_BASE_C) + +/* CGPS PDSM Extended Status NMEA Report */ +#define LOG_CGPS_PDSM_EXT_STATUS_NMEA_REPORT_C (0x384 + LOG_1X_BASE_C) + +/* CGPS PDSM Extended Status Measurement Report */ +#define LOG_CGPS_PDSM_EXT_STATUS_MEAS_REPORT_C (0x385 + LOG_1X_BASE_C) + +/* CGPS Report Server TX Packet */ +#define LOG_CGPS_REP_SVR_TX_LOG_PACKET_C (0x386 + LOG_1X_BASE_C) + +/* CGPS Report Server RX Packet */ +#define LOG_CGPS_REP_SVR_RX_LOG_PACKET_C (0x387 + LOG_1X_BASE_C) + +/* UMTS To CDMA Handover Paging Channel Message */ +#define LOG_UMTS_TO_CDMA_HANDOVER_PCH_MSG_C (0x388 + LOG_1X_BASE_C) + +/* UMTS To CDMA Handover Traffic Channel Message */ +#define LOG_UMTS_TO_CDMA_HANDOVER_TCH_MSG_C (0x389 + LOG_1X_BASE_C) + +/* Converged GPS IQ Report */ +#define LOG_CONVERGED_GPS_IQ_REPORT_C (0x38A + LOG_1X_BASE_C) + +/* VOIP To CDMA Paging Channel Handover Message */ +#define LOG_VOIP_TO_CDMA_PCH_HANDOVER_MSG_C (0x38B + LOG_1X_BASE_C) + +/* VOIP To CDMA Access Channel Handover Message */ +#define LOG_VOIP_TO_CDMA_ACH_HANDOVER_MSG_C (0x38C + LOG_1X_BASE_C) + +/* VOIP To CDMA Forward Traffic Channel Handover Message */ +#define LOG_VOIP_TO_CDMA_FTC_HANDOVER_MSG_C (0x38D + LOG_1X_BASE_C) + +/* QMI reserved logs */ +#define LOG_QMI_RESERVED_CODES_BASE_C (0x38E + LOG_1X_BASE_C) +#define LOG_QMI_LAST_C (32 + LOG_QMI_RESERVED_CODES_BASE_C) + +/* QOS Info Code Update Log */ +#define LOG_QOS_INFO_CODE_UPDATE_C (0x3AF + LOG_1X_BASE_C) + +/* Transmit(Uplink) Vocoder PCM Packet Log */ +#define LOG_TX_PCM_PACKET_C (0x3B0 + LOG_1X_BASE_C) + +/* Audio Vocoder Data Paths */ +#define LOG_AUDVOC_DATA_PATHS_PACKET_C (0x3B0 + LOG_1X_BASE_C) + +/* Receive(Downlink) Vocoder PCM Packet Log */ +#define LOG_RX_PCM_PACKET_C (0x3B1 + LOG_1X_BASE_C) + +/* CRC of YUV frame log */ +#define LOG_DEC_CRC_FRAME_C (0x3B2 + LOG_1X_BASE_C) + +/* FLUTE Session Information */ +#define LOG_FLUTE_SESSION_INFO_C (0x3B3 + LOG_1X_BASE_C) + +/* FLUTE ADP File Information */ +#define LOG_FLUTE_ADP_FILE_INFO_C (0x3B4 + LOG_1X_BASE_C) + +/* FLUTE File Request Information */ +#define LOG_FLUTE_FILE_REQ_INFO_C (0x3B5 + LOG_1X_BASE_C) + +/* FLUTE FDT Instance Information */ +#define LOG_FLUTE_FDT_INST_C (0x3B6 + LOG_1X_BASE_C) + +/* FLUTE FDT Information */ +#define LOG_FLUTE_FDT_INFO_C (0x3B7 + LOG_1X_BASE_C) + +/* FLUTE File Log Packet Information */ +#define LOG_FLUTE_FILE_INFO_C (0x3B8 + LOG_1X_BASE_C) + +/* 3G 1X Parameter Overhead Information */ +#define LOG_VOIP_TO_CDMA_3G1X_PARAMETERS_C (0x3B9 + LOG_1X_BASE_C) + +/* CGPS ME Job Info */ +#define LOG_CGPS_ME_JOB_INFO_C (0x3BA + LOG_1X_BASE_C) + +/* CGPS ME SV Lists */ +#define LOG_CPGS_ME_SV_LISTS_C (0x3BB + LOG_1X_BASE_C) + +/* Flexible Profiling Status */ +#define LOG_PROFDIAG_GEN_STATUS_C (0x3BC + LOG_1X_BASE_C) + +/* Flexible Profiling Results */ +#define LOG_PROFDIAG_GEN_PROF_C (0x3BD + LOG_1X_BASE_C) + +/* FLUTE ADP File Content Log Packet Information */ +#define LOG_FLUTE_ADP_FILE_C (0x3BE + LOG_1X_BASE_C) + +/* FLUTE FDT Instance File Content Log Packet Information */ +#define LOG_FLUTE_FDT_INST_FILE_C (0x3BF + LOG_1X_BASE_C) + +/* FLUTE FDT Entries Information */ +#define LOG_FLUTE_FDT_ENTRIES_INFO_C (0x3C0 + LOG_1X_BASE_C) + +/* FLUTE File Contents Log Packet Information */ +#define LOG_FLUTE_FILE_C (0x3C1 + LOG_1X_BASE_C) + +/* CGPS ME Time-Transfer Info */ +#define LOG_CGPS_ME_TIME_TRANSFER_INFO_C (0x3C2 + LOG_1X_BASE_C) + +/* CGPS ME UMTS Time-Tagging Info */ +#define LOG_CGPS_ME_UMTS_TIME_TAGGING_INFO_C (0x3C3 + LOG_1X_BASE_C) + +/* CGPS ME Generic Time Estimate Put lnfo */ +#define LOG_CGPS_ME_TIME_EST_PUT_INFO_C (0x3C4 + LOG_1X_BASE_C) + +/* CGPS ME Generic Freq Estimate Put lnfo */ +#define LOG_CGPS_ME_FREQ_EST_PUT_INFO_C (0x3C5 + LOG_1X_BASE_C) + +/* CGPS Slow Clock Report */ +#define LOG_CGPS_SLOW_CLOCK_REPORT_C (0x3C6 + LOG_1X_BASE_C) + +/* Converged GPS Medium Grid */ +#define LOG_CONVERGED_GPS_MEDIUM_GRID_C (0x3C7 + LOG_1X_BASE_C) + +/* Static information about the driver or device */ +#define LOG_SNSD_INFO_C (0x3C8 + LOG_1X_BASE_C) + +/* Dynamic state information about the device or driver */ +#define LOG_SNSD_STATE_C (0x3C9 + LOG_1X_BASE_C) + +/* Data from a driver */ +#define LOG_SNSD_DATA (0x3CA + LOG_1X_BASE_C) +#define LOG_SNSD_DATA_C (0x3CA + LOG_1X_BASE_C) + +/* CGPS Cell DB Cell Change Info */ +#define LOG_CGPS_CELLDB_CELL_CHANGE_INFO_C (0x3CB + LOG_1X_BASE_C) + +/* xScalar YUV frame log */ +#define LOG_DEC_XSCALE_YUV_FRAME_C (0x3CC + LOG_1X_BASE_C) + +/* CRC of xScaled YUV frame log */ +#define LOG_DEC_XSCALE_CRC_FRAME_C (0x3CD + LOG_1X_BASE_C) + +/* CGPS Frequency Estimate Report */ +#define LOG_CGPS_FREQ_EST_REPORT_C (0x3CE + LOG_1X_BASE_C) + +/* GPS DCME Srch Job Completed */ +#define LOG_GPS_DCME_SRCH_JOB_COMPLETED_C (0x3CF + LOG_1X_BASE_C) + +/* CGPS ME Fastscan results */ +#define LOG_CGPS_ME_FASTSCAN_RESULTS_C (0x3D0 + LOG_1X_BASE_C) + +/* XO frequency Estimation log */ +#define LOG_XO_FREQ_EST_C (0x3D1 + LOG_1X_BASE_C) + +/* Tcxomgr field calibration data */ +#define LOG_TCXOMGR_FIELD_CAL_C (0x3D2 + LOG_1X_BASE_C) + +/* UMB Call Processing Connection Attempt */ +#define LOG_UMBCP_CONNECTION_ATTEMPT_C (0x3D3 + LOG_1X_BASE_C) + +/* UMB Call Processing Connection Release */ +#define LOG_UMBCP_CONNECTION_RELEASE_C (0x3D4 + LOG_1X_BASE_C) + +/* UMB Call Processing Page Message */ +#define LOG_UMBCP_PAGE_MESSAGE_C (0x3D5 + LOG_1X_BASE_C) + +/* UMB Call Processing OVHD Information */ +#define LOG_UMBCP_OVHD_INFO_C (0x3D6 + LOG_1X_BASE_C) + +/* UMB Call Processing Session Attempt */ +#define LOG_UMBCP_SESSION_ATTEMPT_C (0x3D7 + LOG_1X_BASE_C) + +/* UMB Call Processing Route Information */ +#define LOG_UMBCP_ROUTE_INFO_C (0x3D8 + LOG_1X_BASE_C) + +/* UMB Call Processing State Information */ +#define LOG_UMBCP_STATE_INFO_C (0x3D9 + LOG_1X_BASE_C) + +/* UMB Call Processing SNP */ +#define LOG_UMBCP_SNP_C (0x3DA + LOG_1X_BASE_C) + +/* CGPS Session Early Exit Decision */ +#define LOG_CGPS_SESSION_EARLY_EXIT_DECISION_C (0x3DB + LOG_1X_BASE_C) + +/* GPS RF Linearity Status */ +#define LOG_CGPS_ME_RF_LINEARITY_INFO_C (0x3DC + LOG_1X_BASE_C) + +/* CGPS ME 5ms IQ Sums */ +#define LOG_CGPS_ME_5MS_IQ_SUMS_C (0x3DD + LOG_1X_BASE_C) + +/* CGPS ME 20ms IQ Sums */ +#define LOG_CPGS_ME_20MS_IQ_SUMS_C (0x3DE + LOG_1X_BASE_C) + +/* ROHC Compressor Statistics */ +#define LOG_ROHC_COMPRESSOR_STATS_C (0x3DF + LOG_1X_BASE_C) + +/* ROHC Decompressor Statistics */ +#define LOG_ROHC_DECOMPRESSOR_STATS_C (0x3E0 + LOG_1X_BASE_C) + +/* Sensors - Kalman filter information */ +#define LOG_SENSOR_KF_INFO_C (0x3E1 + LOG_1X_BASE_C) + +/* Sensors - Integrated measurements */ +#define LOG_SENSOR_INT_MEAS_C (0x3E2 + LOG_1X_BASE_C) + +/* Sensors - Bias calibration values */ +#define LOG_SENSOR_BIAS_CALIBRATION_C (0x3E3 + LOG_1X_BASE_C) + +/* Log codes 0x13E4-0x13E7 are not following standard log naming convention */ + +/* DTV ISDB-T Transport Stream Packets */ +#define LOG_DTV_ISDB_TS_PACKETS (0x3E4 + LOG_1X_BASE_C) + +/* DTV ISDB-T PES Packets */ +#define LOG_DTV_ISDB_PES_PACKETS (0x3E5 + LOG_1X_BASE_C) + +/* DTV ISDB-T Sections */ +#define LOG_DTV_ISDB_SECTIONS (0x3E6 + LOG_1X_BASE_C) + +/* DTV ISDB-T Buffering */ +#define LOG_DTV_ISDB_BUFFERING (0x3E7 + LOG_1X_BASE_C) + +/* WLAN System Acquisition and Handoff */ +#define LOG_WLAN_SYS_ACQ_HO_C (0x3E8 + LOG_1X_BASE_C) + +/* WLAN General Configurable Parameters */ +#define LOG_WLAN_GEN_CONFIG_PARAMS_C (0x3E9 + LOG_1X_BASE_C) + +/* UMB Physical Layer Channel and Interference Estimation */ +#define LOG_UMB_PHY_RX_DPICH_CIE_C (0x3EA + LOG_1X_BASE_C) + +/* UMB Physical Layer MMSE/MRC Demodulated Data Symbols (Low) */ +#define LOG_UMB_PHY_RX_DATA_DEMOD_LOW_C (0x3EB + LOG_1X_BASE_C) + +/* UMB Physical Layer MMSE/MRC Demodulated Data Symbols (High) */ +#define LOG_UMB_PHY_RX_DATA_DEMOD_HIGH_C (0x3EC + LOG_1X_BASE_C) + +/* UMB Physical Layer DCH Decoder */ +#define LOG_UMB_PHY_RX_DCH_DECODER_C (0x3ED + LOG_1X_BASE_C) + +/* UMB Physical Layer DCH Statistics */ +#define LOG_UMB_PHY_DCH_STATISTICS_C (0x3EE + LOG_1X_BASE_C) + +/* UMB Physical Layer CqiPich Processing */ +#define LOG_UMB_PHY_RX_CQIPICH_C (0x3EF + LOG_1X_BASE_C) + +/* UMB Physical Layer MIMO/SIMO in CqiPich (High) */ +#define LOG_UMB_PHY_RX_CQIPICH_CHANTAPS_HIGH_C (0x3F0 + LOG_1X_BASE_C) + +/* UMB Physical Layer MIMO/SIMO in CquiPich (Low) */ +#define LOG_UMB_PHY_RX_CQIPICH_CHANTAPS_LOW_C (0x3F1 + LOG_1X_BASE_C) + +/* UMB Physical Layer Time-Domain Channel Taps (High) */ +#define LOG_UMB_PHY_RX_PPICH_CHAN_EST_HIGH_C (0x3F2 + LOG_1X_BASE_C) + +/* UMB Physical Layer Time-Domain Channel Taps (Low) */ +#define LOG_UMB_PHY_RX_PPICH_CHAN_EST_LOW_C (0x3F3 + LOG_1X_BASE_C) + +/* UMB Physical Layer AT Modulator */ +#define LOG_UMB_PHY_TX_PICH_CONFIG_C (0x3F4 + LOG_1X_BASE_C) + +/* UMB Physical Layer AT Modulator for R-ACK (High) */ +#define LOG_UMB_PHY_TX_ACK_HIGH_C (0x3F5 + LOG_1X_BASE_C) + +/* UMB Physical Layer AT Modulator for R-ACK (Low) */ +#define LOG_UMB_PHY_TX_ACK_LOW_C (0x3F6 + LOG_1X_BASE_C) + +/* UMB Physical Layer AT Modulator for R-PICH */ +#define LOG_UMB_PHY_TX_PICH_C (0x3F7 + LOG_1X_BASE_C) + +/* UMB Physical Layer AT Modulator for R-ACH (Access) */ +#define LOG_UMB_PHY_TX_ACH_C (0x3F8 + LOG_1X_BASE_C) + +/* UMB Physical Layer AT Modulator for R-ODDCCH (High) */ +#define LOG_UMB_PHY_TX_ODCCH_HIGH_C (0x3F9 + LOG_1X_BASE_C) + +/* UMB Physical Layer AT Modulator for R-ODDCCH (Low) */ +#define LOG_UMB_PHY_TX_ODCCH_LOW_C (0x3FA + LOG_1X_BASE_C) + +/* UMB Physical Layer AT Modulator for R-CDCCH */ +#define LOG_UMB_PHY_TX_RCDCCH_CONFIG_C (0x3FB + LOG_1X_BASE_C) + +/* UMB Physical Layer AT Modulator for CQI sent on RCDCCH */ +#define LOG_UMB_PHY_TX_NONFLSS_CQICH_C (0x3FC + LOG_1X_BASE_C) + +/* UMB Physical Layer AT Modulator for CQI sent on RCDCCH */ +#define LOG_UMB_PHY_TX_FLSS_CQICH_C (0x3FD + LOG_1X_BASE_C) + +/* UMB Physical Layer AT Modulator for PACH sent on RCDCCH */ +#define LOG_UMB_PHY_TX_PAHCH_C (0x3FE + LOG_1X_BASE_C) + +/* UMB Physical Layer AT Modulator for REQ sent on RCDCCH */ +#define LOG_UMB_PHY_TX_REQCH_C (0x3FF + LOG_1X_BASE_C) + +/* UMB Physical Layer AT Modulator for PSD sent on RCDCCH */ +#define LOG_UMB_PHY_TX_PSDCH_C (0x400 + LOG_1X_BASE_C) + +/* UMB Physical Layer AT Modulator for R-DCH */ +#define LOG_UMB_PHY_TX_DCH_C (0x401 + LOG_1X_BASE_C) + +/* UMB Physical Layer Time/Frequency/RxPower Estimate */ +#define LOG_UMB_PHY_RX_TIME_FREQ_POWER_ESTIMATE_C (0x402 + LOG_1X_BASE_C) + +/* UMB Physical Layer FLCS Processing */ +#define LOG_UMB_PHY_RX_FLCS_PROCESSING_C (0x403 + LOG_1X_BASE_C) + +/* UMB Physical Layer PBCCH Processing */ +#define LOG_UMB_PHY_RX_PBCCH_PROCESSING_C (0x404 + LOG_1X_BASE_C) + +/* UMB Physical Layer SBCCH Processing */ +#define LOG_UMB_PHY_RX_SBCCH_PROCESSING_C (0x405 + LOG_1X_BASE_C) + +/* UMB Physical Layer QPCH Processing */ +#define LOG_UMB_PHY_RX_QPCH_PROCESSING_C (0x406 + LOG_1X_BASE_C) + +/* UMB Physical Layer MRC Demodulated Data Symbols (Preamble SBCCH/QPCH) */ +#define LOG_UMB_PHY_RX_SBCCH_DEMOD_C (0x407 + LOG_1X_BASE_C) + +/* UMB Physical Layer MRC Demodulated Data Symbols (Preamble PBCCH) */ +#define LOG_UMB_PHY_RX_PBCCH_DEMOD_C (0x408 + LOG_1X_BASE_C) + +/* UMB Physical Layer VCQI */ +#define LOG_UMB_PHY_RX_VCQI_C (0x409 + LOG_1X_BASE_C) + +/* UMB Physical Layer Acquisition Algorithm */ +#define LOG_UMB_PHY_RX_INITIAL_ACQUISITION_C (0x40A + LOG_1X_BASE_C) + +/* UMB Physical Layer Handoff Search Algorithm */ +#define LOG_UMB_PHY_RX_HANDOFF_SEARCH_C (0x40B + LOG_1X_BASE_C) + +/* UMB RF RFFE Configuration Info */ +#define LOG_UMB_AT_RFFE_CONFG_C (0x40C + LOG_1X_BASE_C) + +/* UMB RF Calibrated Values After Powerup */ +#define LOG_UMB_AT_RFFE_RX_CALIB_C (0x40D + LOG_1X_BASE_C) + +/* UMB RF AGC Block in Acquisition Mode */ +#define LOG_UMB_AT_RFFE_RX_ACQ_C (0x40E + LOG_1X_BASE_C) + +/* UMB RF AGC Block in Idle Mode */ +#define LOG_UMB_AT_RFFE_RX_IDLE_C (0x40F + LOG_1X_BASE_C) + +/* UMB RF AGC Block in Connected Mode */ +#define LOG_UMB_AT_RFFE_RX_CONNECTED_C (0x410 + LOG_1X_BASE_C) + +/* UMB RF AGC Block in Connected Mode (FTM) */ +#define LOG_UMB_AT_RFFE_RX_CONNECTED_FTM_C (0x411 + LOG_1X_BASE_C) + +/* UMB RF Jammer Detector Functionality */ +#define LOG_UMB_AT_RFFE_RX_JAMMER_DETECTOR_FUNCTIONALITY_C (0x412 + LOG_1X_BASE_C) + +/* UMB RF Jammer Detector Response */ +#define LOG_UMB_AT_RFFE_RX_JAMMER_DETECTOR_RESPONSE_C (0x413 + LOG_1X_BASE_C) + +/* UMB RF RFFE TX Power Control */ +#define LOG_UMB_AT_RFFE_TX_BETA_SCALING_C (0x414 + LOG_1X_BASE_C) + +/* UMB Searcher Dump */ +#define LOG_UMB_SEARCHER_DUMP_C (0x415 + LOG_1X_BASE_C) + +/* UMB System Acquire */ +#define LOG_UMB_SYSTEM_ACQUIRE_C (0x416 + LOG_1X_BASE_C) + +/* UMB Set Maintenance */ +#define LOG_UMB_SET_MAINTENANCE_C (0x417 + LOG_1X_BASE_C) + +/* UMB QPCH */ +#define LOG_UMB_QPCH_C (0x418 + LOG_1X_BASE_C) + +/* UMB RLL Forward Partial RP Packet */ +#define LOG_UMB_RLL_FORWARD_PARTIAL_RP_C (0x419 + LOG_1X_BASE_C) + +/* UMB RLL Reverse Partial RP Packet */ +#define LOG_UMB_RLL_REVERSE_PARTIAL_RP_C (0x41A + LOG_1X_BASE_C) + +/* UMB RLL Forward Signal Packet */ +#define LOG_UMB_RLL_FORWARD_SIGNAL_C (0x41B + LOG_1X_BASE_C) + +/* UMB RLL Reverse Signal Packet */ +#define LOG_UMB_RLL_REVERSE_SIGNAL_C (0x41C + LOG_1X_BASE_C) + +/* UMB RLL Forward Statistics */ +#define LOG_UMB_RLL_FORWARD_STATS_C (0x41D + LOG_1X_BASE_C) + +/* UMB RLL Reverse Statistics */ +#define LOG_UMB_RLL_REVERSE_STATS_C (0x41E + LOG_1X_BASE_C) + +/* UMB RLL IRTP */ +#define LOG_UMB_RLL_IRTP_C (0x41F + LOG_1X_BASE_C) + +/* UMB AP Forward Link MAC Packets */ +#define LOG_UMB_AP_FL_MAC_PACKET_C (0x420 + LOG_1X_BASE_C) + +/* UMB AP Reverse Link MAC Packets */ +#define LOG_UMB_AP_RL_MAC_PACKET_C (0x421 + LOG_1X_BASE_C) + +/* GPS Performance Statistics log */ +#define LOG_CGPS_PERFORMANCE_STATS_C (0x422 + LOG_1X_BASE_C) + +/* UMB Searcher General Status */ +#define LOG_UMB_SRCH_GENERAL_STATUS_C (0x423 + LOG_1X_BASE_C) + +/* UMB Superframe Scheduler */ +#define LOG_UMB_SUPERFRAME_SCHEDULER_C (0x424 + LOG_1X_BASE_C) + +/* UMB Sector List */ +#define LOG_UMB_SECTOR_LIST_C (0x425 + LOG_1X_BASE_C) + +/* UMB MAC Access Attempt Command */ +#define LOG_UMB_MAC_ACCESS_ATTEMPT_CMD_C (0x426 + LOG_1X_BASE_C) + +/* UMB MAC Access Probe Information */ +#define LOG_UMB_MAC_ACCESS_PROBE_INFO_C (0x427 + LOG_1X_BASE_C) + +/* UMB MAC RTCMAC Package Information */ +#define LOG_UMB_MAC_RTCMAC_PKG_INFO_C (0x428 + LOG_1X_BASE_C) + +/* UMB MAC Super Frame Information */ +#define LOG_UMB_MAC_SI_INFO_C (0x429 + LOG_1X_BASE_C) + +/* UMB MAC Quick Channel Information */ +#define LOG_UMB_MAC_QCI_INFO_C (0x42A + LOG_1X_BASE_C) + +/* UMB MAC Paging Id List */ +#define LOG_UMB_MAC_PAGING_ID_LIST_C (0x42B + LOG_1X_BASE_C) + +/* UMB MAC Quick Paging Channel Information */ +#define LOG_UMB_MAC_QPCH_INFO_C (0x42C + LOG_1X_BASE_C) + +/* UMB MAC FTCMAC Information */ +#define LOG_UMB_MAC_FTCMAC_PKG_INFO_C (0x42D + LOG_1X_BASE_C) + +/* UMB MAC Access Grant Receiving */ +#define LOG_UMB_MAC_ACCESS_GRANT_C (0x42E + LOG_1X_BASE_C) + +/* UMB MAC Generic Debug Log */ +#define LOG_UMB_MAC_GEN_DEBUG_LOG_PKG_C (0x42F + LOG_1X_BASE_C) + +/* CGPS Frequency Bias Estimate */ +#define LOG_CGPS_MC_FREQ_BIAS_EST_C (0x430 + LOG_1X_BASE_C) + +/* UMB MAC Request Report Information Log */ +#define LOG_UMB_MAC_REQCH_REPORT_INFO_C (0x431 + LOG_1X_BASE_C) + +/* UMB MAC Reverse Link QoS Token Bucket Information Log */ +#define LOG_UMB_MAC_RLQOS_TOKEN_BUCKET_INFO_C (0x432 + LOG_1X_BASE_C) + +/* UMB MAC Reverse Link QoS Stream Information Log */ +#define LOG_UMB_MAC_RLQOS_STREAM_INFO_C (0x433 + LOG_1X_BASE_C) + +/* UMB MAC Reverse Link QoS Allotment Information Log */ +#define LOG_UMB_MAC_RLQOS_ALLOTMENT_INFO_C (0x434 + LOG_1X_BASE_C) + +/* UMB Searcher Recent State Machine Transactions */ +#define LOG_UMB_SRCH_STM_ACTIVITY_C (0x435 + LOG_1X_BASE_C) + +/* Performance Counters on ARM11 Profiling Information */ +#define LOG_ARM11_PERF_CNT_INFO_C (0x436 + LOG_1X_BASE_C) + +/* Protocol Services describe all flow instances */ +#define LOG_PS_STAT_DESC_ALL_FLOW_INST_C (0x437 + LOG_1X_BASE_C) + +/* Protocol Services describe all physical link instances */ +#define LOG_PS_STAT_DESC_ALL_PHYS_LINK_INST_C (0x438 + LOG_1X_BASE_C) + +/* Protocol Services describe all UDP instances */ +#define LOG_PS_STAT_DESC_ALL_UDP_INST_C (0x439 + LOG_1X_BASE_C) + +/* Searcher 4 Multi-Carrier HDR */ +#define LOG_SRCH4_MC_HDR_C (0x43A + LOG_1X_BASE_C) + +/* Protocol Services describe all IPHC instances */ +#define LOG_PS_STAT_DESC_ALL_IPHC_INST_C (0x43B + LOG_1X_BASE_C) + +/* Protocol Services describe all ROHC instances */ +#define LOG_PS_STAT_DESC_ALL_ROHC_INST_C (0x43C + LOG_1X_BASE_C) + +/* BCast security add program information */ +#define LOG_BCAST_SEC_ADD_PROGRAM_INFO_C (0x43D + LOG_1X_BASE_C) + +/* BCast security add program complete */ +#define LOG_BCAST_SEC_ADD_PROGRAM_COMPLETE_C (0x43E + LOG_1X_BASE_C) + +/* BCast security SDP parse */ +#define LOG_BCAST_SEC_SDP_PARSE_C (0x43F + LOG_1X_BASE_C) + +/* CGPS ME dynamic power optimization status */ +#define LOG_CGPS_ME_DPO_STATUS_C (0x440 + LOG_1X_BASE_C) + +/* CGPS PDSM on demand session start */ +#define LOG_CGPS_PDSM_ON_DEMAND_SESSION_START_C (0x441 + LOG_1X_BASE_C) + +/* CGPS PDSM on demand session stop */ +#define LOG_CGPS_PDSM_ON_DEMAND_SESSION_STOP_C (0x442 + LOG_1X_BASE_C) + +/* CGPS PDSM on demand session not started */ +#define LOG_CGPS_PDSM_ON_DEMAND_SESSION_NOT_STARTED_C (0x443 + LOG_1X_BASE_C) + +/* CGPS PDSM extern coarse position inject start */ +#define LOG_CGPS_PDSM_EXTERN_COARSE_POS_INJ_START_C (0x444 + LOG_1X_BASE_C) + +/* DTV ISDB-T TMCC information */ +#define LOG_DTV_ISDB_TMCC_C (0x445 + LOG_1X_BASE_C) + +/* RF development */ +#define LOG_RF_DEV_C (0x446 + LOG_1X_BASE_C) + +/* RF RFM API */ +#define LOG_RF_RFM_API_C (0x447 + LOG_1X_BASE_C) + +/* RF RFM state */ +#define LOG_RF_RFM_STATE_C (0x448 + LOG_1X_BASE_C) + +/* 1X RF Warmup */ +#define LOG_1X_RF_WARMUP_C (0x449 + LOG_1X_BASE_C) + +/* 1X RF power limiting */ +#define LOG_1X_RF_PWR_LMT_C (0x44A + LOG_1X_BASE_C) + +/* 1X RF state */ +#define LOG_1X_RF_STATE_C (0x44B + LOG_1X_BASE_C) + +/* 1X RF sleep */ +#define LOG_1X_RF_SLEEP_C (0x44C + LOG_1X_BASE_C) + +/* 1X RF TX state */ +#define LOG_1X_RF_TX_STATE_C (0x44D + LOG_1X_BASE_C) + +/* 1X RF IntelliCeiver state */ +#define LOG_1X_RF_INT_STATE_C (0x44E + LOG_1X_BASE_C) + +/* 1X RF RX ADC clock */ +#define LOG_1X_RF_RX_ADC_CLK_C (0x44F + LOG_1X_BASE_C) + +/* 1X RF LNA switch point */ +#define LOG_1X_RF_LNA_SWITCHP_C (0x450 + LOG_1X_BASE_C) + +/* 1X RF RX calibration */ +#define LOG_1X_RF_RX_CAL_C (0x451 + LOG_1X_BASE_C) + +/* 1X RF API */ +#define LOG_1X_RF_API_C (0x452 + LOG_1X_BASE_C) + +/* 1X RF RX PLL locking status */ +#define LOG_1X_RF_RX_PLL_LOCK_C (0x453 + LOG_1X_BASE_C) + +/* 1X RF voltage regulator */ +#define LOG_1X_RF_VREG_C (0x454 + LOG_1X_BASE_C) + +/* CGPS DIAG successful fix count */ +#define LOG_CGPS_DIAG_SUCCESSFUL_FIX_COUNT_C (0x455 + LOG_1X_BASE_C) + +/* CGPS MC track dynamic power optimization status */ +#define LOG_CGPS_MC_TRACK_DPO_STATUS_C (0x456 + LOG_1X_BASE_C) + +/* CGPS MC SBAS demodulated bits */ +#define LOG_CGPS_MC_SBAS_DEMOD_BITS_C (0x457 + LOG_1X_BASE_C) + +/* CGPS MC SBAS demodulated soft symbols */ +#define LOG_CGPS_MC_SBAS_DEMOD_SOFT_SYMBOLS_C (0x458 + LOG_1X_BASE_C) + +/* Data Services PPP configuration */ +#define LOG_DS_PPP_CONFIG_PARAMS_C (0x459 + LOG_1X_BASE_C) + +/* Data Services physical link configuration */ +#define LOG_DS_PHYS_LINK_CONFIG_PARAMS_C (0x45A + LOG_1X_BASE_C) + +/* Data Services PPP device configuration */ +#define LOG_PS_PPP_DEV_CONFIG_PARAMS_C (0x45B + LOG_1X_BASE_C) + +/* CGPS PDSM GPS state information */ +#define LOG_CGPS_PDSM_GPS_STATE_INFO_C (0x45C + LOG_1X_BASE_C) + +/* CGPS PDSM EXT status GPS state information */ +#define LOG_CGPS_PDSM_EXT_STATUS_GPS_STATE_INFO_C (0x45D + LOG_1X_BASE_C) + +/* CGPS ME Rapid Search Report */ +#define LOG_CGPS_ME_RAPID_SEARCH_REPORT_C (0x45E + LOG_1X_BASE_C) + +/* CGPS PDSM XTRA-T session */ +#define LOG_CGPS_PDSM_XTRA_T_SESSION_C (0x45F + LOG_1X_BASE_C) + +/* CGPS PDSM XTRA-T upload */ +#define LOG_CGPS_PDSM_XTRA_T_UPLOAD_C (0x460 + LOG_1X_BASE_C) + +/* CGPS Wiper Position Report */ +#define LOG_CGPS_WIPER_POSITION_REPORT_C (0x461 + LOG_1X_BASE_C) + +/* DTV DVBH Security SmartCard HTTP Digest Request Info */ +#define LOG_DTV_DVBH_SEC_SC_HTTP_DIGEST_REQ_C (0x462 + LOG_1X_BASE_C) + +/* DTV DVBH Security SmartCard HTTP Digest Response Info */ +#define LOG_DTV_DVBH_SEC_SC_HTTP_DIGEST_RSP_C (0x463 + LOG_1X_BASE_C) + +/* DTV DVBH Security SmartCard Services Registration Request Info */ +#define LOG_DTV_DVBH_SEC_SC_SVC_REG_REQ_C (0x464 + LOG_1X_BASE_C) + +/* DTV DVBH Security SmartCard Services Registration Complete Info */ +#define LOG_DTV_DVBH_SEC_SC_SVC_REG_COMPLETE_C (0x465 + LOG_1X_BASE_C) + +/* DTV DVBH Security SmartCard Services Deregistration Request Info */ +#define LOG_DTV_DVBH_SEC_SC_SVC_DEREG_REQ_C (0x466 + LOG_1X_BASE_C) + +/* DTV DVBH Security SmartCard Services Deregistration Complete Info */ +#define LOG_DTV_DVBH_SEC_SC_SVC_DEREG_COMPLETE_C (0x467 + LOG_1X_BASE_C) + +/* DTV DVBH Security SmartCard LTKM Request Info */ +#define LOG_DTV_DVBH_SEC_SC_LTKM_REQ_C (0x468 + LOG_1X_BASE_C) + +/* DTV DVBH Security SmartCard LTKM Request Complete Info */ +#define LOG_DTV_DVBH_SEC_SC_LTKM_REQ_COMPLETE_C (0x469 + LOG_1X_BASE_C) + +/* DTV DVBH Security SmartCard Program Selection Info */ +#define LOG_DTV_DVBH_SEC_SC_PROG_SEL_C (0x46A + LOG_1X_BASE_C) + +/* DTV DVBH Security SmartCard Program Selection Complete Info */ +#define LOG_DTV_DVBH_SEC_SC_PROG_SEL_COMPLETE_C (0x46B + LOG_1X_BASE_C) + +/* DTV DVBH Security SmartCard LTKM */ +#define LOG_DTV_DVBH_SEC_SC_LTKM_C (0x46C + LOG_1X_BASE_C) + +/* DTV DVBH Security SmartCard LTKM Verification Message */ +#define LOG_DTV_DVBH_SEC_SC_LTKM_VERIFICATION_C (0x46D + LOG_1X_BASE_C) + +/* DTV DVBH Security SmartCard Parental Control Message */ +#define LOG_DTV_DVBH_SEC_SC_PARENTAL_CTRL_C (0x46E + LOG_1X_BASE_C) + +/* DTV DVBH Security SmartCard STKM */ +#define LOG_DTV_DVBH_SEC_SC_STKM_C (0x46F + LOG_1X_BASE_C) + +/* Protocol Services Statistics Global Socket */ +#define LOG_PS_STAT_GLOBAL_SOCK_C (0x470 + LOG_1X_BASE_C) + +/* MCS Application Manager */ +#define LOG_MCS_APPMGR_C (0x471 + LOG_1X_BASE_C) + +/* MCS MSGR */ +#define LOG_MCS_MSGR_C (0x472 + LOG_1X_BASE_C) + +/* MCS QTF */ +#define LOG_MCS_QTF_C (0x473 + LOG_1X_BASE_C) + +/* Sensors Stationary Detector Output */ +#define LOG_STATIONARY_DETECTOR_OUTPUT_C (0x474 + LOG_1X_BASE_C) + +/* Print out the ppm data portion */ +#define LOG_CGPS_PDSM_EXT_STATUS_MEAS_REPORT_PPM_C (0x475 + LOG_1X_BASE_C) + +/* GNSS Position Report */ +#define LOG_GNSS_POSITION_REPORT_C (0x476 + LOG_1X_BASE_C) + +/* GNSS GPS Measurement Report */ +#define LOG_GNSS_GPS_MEASUREMENT_REPORT_C (0x477 + LOG_1X_BASE_C) + +/* GNSS Clock Report */ +#define LOG_GNSS_CLOCK_REPORT_C (0x478 + LOG_1X_BASE_C) + +/* GNSS Demod Soft Decision */ +#define LOG_GNSS_DEMOD_SOFT_DECISIONS_C (0x479 + LOG_1X_BASE_C) + +/* GNSS ME 5MS IQ sum */ +#define LOG_GNSS_ME_5MS_IQ_SUMS_C (0x47A + LOG_1X_BASE_C) + +/* GNSS CD DB report */ +#define LOG_GNSS_CD_DB_REPORT_C (0x47B + LOG_1X_BASE_C) + +/* GNSS PE WLS position report */ +#define LOG_GNSS_PE_WLS_POSITION_REPORT_C (0x47C + LOG_1X_BASE_C) + +/* GNSS PE KF position report */ +#define LOG_GNSS_PE_KF_POSITION_REPORT_C (0x47D + LOG_1X_BASE_C) + +/* GNSS PRX RF HW status report */ +#define LOG_GNSS_PRX_RF_HW_STATUS_REPORT_C (0x47E + LOG_1X_BASE_C) + +/* GNSS DRX RF HW status report */ +#define LOG_GNSS_DRX_RF_HW_STATUS_REPORT_C (0x47F + LOG_1X_BASE_C) + +/* GNSS Glonass Measurement report */ +#define LOG_GNSS_GLONASS_MEASUREMENT_REPORT_C (0x480 + LOG_1X_BASE_C) + +/* GNSS GPS HBW RXD measurement */ +#define LOG_GNSS_GPS_HBW_RXD_MEASUREMENT_C (0x481 + LOG_1X_BASE_C) + +/* GNSS PDSM position report callback */ +#define LOG_GNSS_PDSM_POSITION_REPORT_CALLBACK_C (0x482 + LOG_1X_BASE_C) + +/* ISense Request String */ +#define LOG_ISENSE_REQUEST_STR_C (0x483 + LOG_1X_BASE_C) + +/* ISense Response String */ +#define LOG_ISENSE_RESPONSE_STR_C (0x484 + LOG_1X_BASE_C) + +/* Bluetooth SOC General Log Packet*/ +#define LOG_BT_SOC_GENERAL_C (0x485 + LOG_1X_BASE_C) + +/* QCRil Call Flow */ +#define LOG_QCRIL_CALL_FLOW_C (0x486 + LOG_1X_BASE_C) + +/* CGPS Wideband FFT stats */ +#define LOG_CGPS_WB_FFT_STATS_C (0x487 + LOG_1X_BASE_C) + +/* CGPS Slow Clock Calibration Report*/ +#define LOG_CGPS_SLOW_CLOCK_CALIB_REPORT_C (0x488 + LOG_1X_BASE_C) + +/* SNS GPS TIMESTAMP */ +#define LOG_SNS_GPS_TIMESTAMP_C (0x489 + LOG_1X_BASE_C) + +/* GNSS Search Strategy Task Allocation */ +#define LOG_GNSS_SEARCH_STRATEGY_TASK_ALLOCATION_C (0x48A + LOG_1X_BASE_C) + +/* RF MC STM state */ +#define LOG_1XHDR_MC_STATE_C (0x48B + LOG_1X_BASE_C) + +/* Record in the Sparse Network DB */ +#define LOG_CGPS_SNDB_RECORD_C (0x48C + LOG_1X_BASE_C) + +/* Record removed from the DB */ +#define LOG_CGPS_SNDB_REMOVE_C (0x48D + LOG_1X_BASE_C) + +/* CGPS Reserved */ +#define LOG_GNSS_CC_PERFORMANCE_STATS_C (0x48E + LOG_1X_BASE_C) + +/* GNSS PDSM Set Paramerters */ +#define LOG_GNSS_PDSM_SET_PARAMETERS_C (0x48F + LOG_1X_BASE_C) + +/* GNSS PDSM PD Event Callback */ +#define LOG_GNSS_PDSM_PD_EVENT_CALLBACK_C (0x490 + LOG_1X_BASE_C) + +/* GNSS PDSM PA Event Callback */ +#define LOG_GNSS_PDSM_PA_EVENT_CALLBACK_C (0x491 + LOG_1X_BASE_C) + +/* CGPS Reserved */ +#define LOG_CGPS_RESERVED2_C (0x492 + LOG_1X_BASE_C) + +/* CGPS Reserved */ +#define LOG_CGPS_RESERVED3_C (0x493 + LOG_1X_BASE_C) + +/* GNSS PDSM EXT Status MEAS Report */ +#define LOG_GNSS_PDSM_EXT_STATUS_MEAS_REPORT_C (0x494 + LOG_1X_BASE_C) + +/* GNSS SM Error */ +#define LOG_GNSS_SM_ERROR_C (0x495 + LOG_1X_BASE_C) + +/* WLAN Scan */ +#define LOG_WLAN_SCAN_C (0x496 + LOG_1X_BASE_C) + +/* WLAN IBSS */ +#define LOG_WLAN_IBSS_C (0x497 + LOG_1X_BASE_C) + +/* WLAN 802.11d*/ +#define LOG_WLAN_80211D_C (0x498 + LOG_1X_BASE_C) + +/* WLAN Handoff */ +#define LOG_WLAN_HANDOFF_C (0x499 + LOG_1X_BASE_C) + +/* WLAN QoS EDCA */ +#define LOG_WLAN_QOS_EDCA_C (0x49A + LOG_1X_BASE_C) + +/* WLAN Beacon Update */ +#define LOG_WLAN_BEACON_UPDATE_C (0x49B + LOG_1X_BASE_C) + +/* WLAN Power save wow add pattern */ +#define LOG_WLAN_POWERSAVE_WOW_ADD_PTRN_C (0x49C + LOG_1X_BASE_C) + +/* WLAN WCM link metrics */ +#define LOG_WLAN_WCM_LINKMETRICS_C (0x49D + LOG_1X_BASE_C) + +/* WLAN wps scan complete*/ +#define LOG_WLAN_WPS_SCAN_COMPLETE_C (0x49E + LOG_1X_BASE_C) + +/* WLAN WPS WSC Message */ +#define LOG_WLAN_WPS_WSC_MESSAGE_C (0x49F + LOG_1X_BASE_C) + +/* WLAN WPS credentials */ +#define LOG_WLAN_WPS_CREDENTIALS_C (0x4A0 + LOG_1X_BASE_C) + +/* WLAN Qos TSpec*/ +#define LOG_WLAN_QOS_TSPEC_C (0x4A2 + LOG_1X_BASE_C) + +/* PMIC Vreg Control */ +#define LOG_PM_VREG_CONTROL_C (0x4A3 + LOG_1X_BASE_C) + +/* PMIC Vreg Level */ +#define LOG_PM_VREG_LEVEL_C (0x4A4 + LOG_1X_BASE_C) + +/* PMIC Vreg State */ +#define LOG_PM_VREG_STATE_C (0x4A5 + LOG_1X_BASE_C) + +/* CGPS SM EPH Randomization info */ +#define LOG_CGPS_SM_EPH_RANDOMIZATION_INFO_C (0x4A6 + LOG_1X_BASE_C) + +/* Audio calibration data */ +#define LOG_QACT_DATA_C (0x4A7 + LOG_1X_BASE_C) + +/* Compass 2D Tracked Calibration Set */ +#define LOG_SNS_VCPS_2D_TRACKED_CAL_SET (0x4A8 + LOG_1X_BASE_C) + +/* Compass 3D Tracked Calibration Set */ +#define LOG_SNS_VCPS_3D_TRACKED_CAL_SET (0x4A9 + LOG_1X_BASE_C) + +/* Calibration metric */ +#define LOG_SNS_VCPS_CAL_METRIC (0x4AA + LOG_1X_BASE_C) + +/* Accelerometer distance */ +#define LOG_SNS_VCPS_ACCEL_DIST (0x4AB + LOG_1X_BASE_C) + +/* Plane update */ +#define LOG_SNS_VCPS_PLANE_UPDATE (0x4AC + LOG_1X_BASE_C) + +/* Location report */ +#define LOG_SNS_VCPS_LOC_REPORT (0x4AD + LOG_1X_BASE_C) + +/* CM Active subscription */ +#define LOG_CM_PH_EVENT_SUBSCRIPTION_PREF_INFO_C (0x4AE + LOG_1X_BASE_C) + +/* DSDS version of CM call event */ +#define LOG_CM_DS_CALL_EVENT_C (0x4AF + LOG_1X_BASE_C) + +/* Sensors ?MobiSens Output */ +#define LOG_MOBISENS_OUTPUT_C (0x4B0 + LOG_1X_BASE_C) + +/* Accelerometer Data */ +#define LOG_ACCEL_DATA_C (0x4B1 + LOG_1X_BASE_C) + +/* Accelerometer Compensated Data */ +#define LOG_ACCEL_COMP_DATA_C (0x4B2 + LOG_1X_BASE_C) + +/* Motion State Data */ +#define LOG_MOTION_STATE_DATA_C (0x4B3 + LOG_1X_BASE_C) + +/* Stationary Position Indicator */ +#define LOG_STAT_POS_IND_C (0x4B4 + LOG_1X_BASE_C) + +/* Motion State Features */ +#define LOG_MOTION_STATE_FEATURES_C (0x4B5 + LOG_1X_BASE_C) + +/* Motion State Hard Decision */ +#define LOG_MOTION_STATE_HARD_DECISION_C (0x4B6 + LOG_1X_BASE_C) + +/* Motion State Soft Decision */ +#define LOG_MOTION_STATE_SOFT_DECISION_C (0x4B7 + LOG_1X_BASE_C) + +/* Sensors Software Version */ +#define LOG_SENSORS_SOFTWARE_VERSION_C (0x4B8 + LOG_1X_BASE_C) + +/* MobiSens Stationary Position Indicator Log Packet */ +#define LOG_MOBISENS_SPI_C (0x4B9 + LOG_1X_BASE_C) + +/* XO calibration raw IQ data */ +#define LOG_XO_IQ_DATA_C (0x4BA + LOG_1X_BASE_C) + +/*DTV CMMB Control Tabl Updated*/ +#define LOG_DTV_CMMB_CONTROL_TABLE_UPDATE ((0x4BB) + LOG_1X_BASE_C) + +/*DTV CMMB Media API Buffering Status*/ +#define LOG_DTV_CMMB_MEDIA_BUFFERING_STATUS ((0x4BC) + LOG_1X_BASE_C) + +/*DTV CMMB *Emergency Broadcast Data*/ +#define LOG_DTV_CMMB_CONTROL_EMERGENCY_BCAST ((0x4BD) + LOG_1X_BASE_C) + +/*DTV CMMB EMM/ECM Data*/ +#define LOG_DTV_CMMB_CAS_EMM_ECM ((0x4BE) + LOG_1X_BASE_C) + +/*DTV CMMB HW Status*/ +#define LOG_DTV_CMMB_HW_PERFORMANCE ((0x4BF) + LOG_1X_BASE_C) + +/*DTV CMMB ESSG Program Indication Information*/ +#define LOG_DTV_CMMB_ESG_PROGRAM_INDICATION_INFORMATION ((0x4C0) + LOG_1X_BASE_C) + +/* Sensors ¨C binary output of converted sensor data */ +#define LOG_CONVERTED_SENSOR_DATA_C ((0x4C1) + LOG_1X_BASE_C) + +/* CM Subscription event */ +#define LOG_CM_SUBSCRIPTION_EVENT_C ((0x4C2) + LOG_1X_BASE_C) + +/* Sensor Ambient Light Data */ +#define LOG_SNS_ALS_DATA_C ((0x4C3) + LOG_1X_BASE_C) + +/*Sensor Ambient Light Adaptive Data */ +#define LOG_SNS_ALS_DATA_ADAPTIVE_C ((0x4C4) + LOG_1X_BASE_C) + +/*Sensor Proximity Distance Data */ +#define LOG_SNS_PRX_DIST_DATA_C ((0x4C5) + LOG_1X_BASE_C) + +/*Sensor Proximity Data */ +#define LOG_SNS_PRX_DATA_C ((0x4C6) + LOG_1X_BASE_C) + +#define LOG_GNSS_SBAS_REPORT_C ((0x4C7) + LOG_1X_BASE_C) + +#define LOG_CPU_MONITOR_MODEM_C ((0x4C8) + LOG_1X_BASE_C) + +#define LOG_CPU_MONITOR_APPS_C ((0x4C9) + LOG_1X_BASE_C) + +#define LOG_BLAST_TASKPROFILE_C ((0x4CA) + LOG_1X_BASE_C) + +#define LOG_BLAST_SYSPROFILE_C ((0x4CB) + LOG_1X_BASE_C) + +#define LOG_FM_RADIO_FTM_C ((0x4CC) + LOG_1X_BASE_C) + +#define LOG_FM_RADIO_C ((0x4CD) + LOG_1X_BASE_C) + +#define LOG_UIM_DS_DATA_C ((0x4CE) + LOG_1X_BASE_C) + +#define LOG_QMI_CALL_FLOW_C ((0x4CF) + LOG_1X_BASE_C) + +#define LOG_APR_MODEM_C ((0x4D0) + LOG_1X_BASE_C) + +#define LOG_APR_APPS_C ((0x4D1) + LOG_1X_BASE_C) + +#define LOG_APR_ADSP_C ((0x4D2) + LOG_1X_BASE_C) + +#define LOG_DATA_MUX_RX_RAW_PACKET_C ((0x4D3) + LOG_1X_BASE_C) + +#define LOG_DATA_MUX_TX_RAW_PACKET_C ((0x4D4) + LOG_1X_BASE_C) + +#define LOG_DATA_MUX_RX_FRAME_PACKET_C ((0x4D5) + LOG_1X_BASE_C) + +#define LOG_DATA_MUX_TX_FRAME_PACKET_C ((0x4D6) + LOG_1X_BASE_C) + +#define LOG_CGPS_PDSM_EXT_STATUS_POS_INJ_REQ_INFO_C ((0x4D7) + LOG_1X_BASE_C) + +#define LOG_TEMPERATURE_MONITOR_C ((0x4D8) + LOG_1X_BASE_C) + +#define LOG_SNS_GESTURES_REST_DETECT_C ((0x4D9) + LOG_1X_BASE_C) + +#define LOG_SNS_GESTURES_ORIENTATION_C ((0x4DA) + LOG_1X_BASE_C) + +#define LOG_SNS_GESTURES_FACING_C ((0x4DB) + LOG_1X_BASE_C) + +#define LOG_SNS_GESTURES_BASIC_C ((0x4DC) + LOG_1X_BASE_C) + +#define LOG_SNS_GESTURES_HINBYE_C ((0x4DD) + LOG_1X_BASE_C) + +#define LOG_GNSS_OEMDRE_MEASUREMENT_REPORT_C ((0x4DE) + LOG_1X_BASE_C) + +#define LOG_GNSS_OEMDRE_POSITION_REPORT_C ((0x4E0) + LOG_1X_BASE_C) + +#define LOG_GNSS_OEMDRE_SVPOLY_REPORT_C ((0x4E1) + LOG_1X_BASE_C) + +#define LOG_GNSS_OEMDRSYNC_C ((0x4E2) + LOG_1X_BASE_C) + +#define LOG_SNS_MGR_EVENT_NOTIFY_C ((0x4E3) + LOG_1X_BASE_C) + +#define LOG_SNS_MGR_EVENT_REGISTER_C ((0x4E4) + LOG_1X_BASE_C) + +#define LOG_GNSS_PDSM_PPM_SESSION_BEGIN_C ((0x4E5) + LOG_1X_BASE_C) + +#define LOG_GNSS_PDSM_PPM_SESSION_PPM_SUSPEND_C ((0x4E6) + LOG_1X_BASE_C) + +#define LOG_GNSS_PDSM_PPM_REPORT_THROTTLED_C ((0x4E7) + LOG_1X_BASE_C) + +#define LOG_GNSS_PDSM_PPM_REPORT_FIRED_C ((0x4E8) + LOG_1X_BASE_C) + +#define LOG_GNSS_PDSM_PPM_SESSION_END_C ((0x4E9) + LOG_1X_BASE_C) + +#define LOG_TRSP_DATA_STALL_C ((0x801) + LOG_1X_BASE_C) + +#define LOG_WLAN_PKT_LOG_INFO_C ((0x8E0) + LOG_1X_BASE_C) + +/* The last defined DMSS log code */ +#define LOG_1X_LAST_C ((0x8E0) + LOG_1X_BASE_C) + +/* This is only here for old (pre equipment ID update) logging code */ +#define LOG_LAST_C (LOG_1X_LAST_C & 0xFFF) + +/* ------------------------------------------------------------------------- + * APPS LOG definition: + * The max number of 16 log codes is assigned for Apps. + * The last apps log code could be 0xB00F. + * Below definition is consolidated from log_codes_apps.h + * ------------------------------------------------------------------------- */ + +/* ======================== APPS Profiling ======================== */ +#define LOG_APPS_SYSPROFILE_C (0x01 + LOG_APPS_BASE_C) +#define LOG_APPS_TASKPROFILE_C (0x02 + LOG_APPS_BASE_C) + +/* The last defined APPS log code */ +/* Change it to (0x02 + LOG_LTE_LAST_C) to allow LTE log codes */ +#define LOG_APPS_LAST_C (0x02 + LOG_LTE_LAST_C) + +/* ------------------------------------------------------------------------- + * Log Equipment IDs. + * The number is represented by 4 bits. + * ------------------------------------------------------------------------- */ +typedef enum { + LOG_EQUIP_ID_OEM = 0, /* 3rd party OEM (licensee) use */ + LOG_EQUIP_ID_1X = 1, /* Traditional 1X line of products */ + LOG_EQUIP_ID_RSVD2 = 2, + LOG_EQUIP_ID_RSVD3 = 3, + LOG_EQUIP_ID_WCDMA = 4, + LOG_EQUIP_ID_GSM = 5, + LOG_EQUIP_ID_LBS = 6, + LOG_EQUIP_ID_UMTS = 7, + LOG_EQUIP_ID_TDMA = 8, + LOG_EQUIP_ID_BOA = 9, + LOG_EQUIP_ID_DTV = 10, + LOG_EQUIP_ID_APPS = 11, + LOG_EQUIP_ID_DSP = 12, + + LOG_EQUIP_ID_LAST_DEFAULT = LOG_EQUIP_ID_DSP +} log_equip_id_enum_type; + +#define LOG_EQUIP_ID_MAX 0xF /* The equipment ID is 4 bits */ + +/* Note that these are the official values and are used by default in + diagtune.h. + */ +#define LOG_EQUIP_ID_0_LAST_CODE_DEFAULT 0 +#define LOG_EQUIP_ID_1_LAST_CODE_DEFAULT LOG_1X_LAST_C +#define LOG_EQUIP_ID_2_LAST_CODE_DEFAULT 0 +#define LOG_EQUIP_ID_3_LAST_CODE_DEFAULT 0 +#define LOG_EQUIP_ID_4_LAST_CODE_DEFAULT 0 +#define LOG_EQUIP_ID_5_LAST_CODE_DEFAULT 0 +#define LOG_EQUIP_ID_6_LAST_CODE_DEFAULT 0 +#define LOG_EQUIP_ID_7_LAST_CODE_DEFAULT 0 +#define LOG_EQUIP_ID_8_LAST_CODE_DEFAULT 0 +#define LOG_EQUIP_ID_9_LAST_CODE_DEFAULT 0 +#define LOG_EQUIP_ID_10_LAST_CODE_DEFAULT 0 +#define LOG_EQUIP_ID_11_LAST_CODE_DEFAULT LOG_LTE_LAST_C +#define LOG_EQUIP_ID_12_LAST_CODE_DEFAULT 0 +#define LOG_EQUIP_ID_13_LAST_CODE_DEFAULT 0 +#define LOG_EQUIP_ID_14_LAST_CODE_DEFAULT 0 +#define LOG_EQUIP_ID_15_LAST_CODE_DEFAULT 0 + +#endif /* LOG_CODES_H */ diff --git a/drivers/staging/qcacld-3.0/core/utils/host_diag_log/src/host_diag_log.c b/drivers/staging/qcacld-3.0/core/utils/host_diag_log/src/host_diag_log.c new file mode 100644 index 0000000000000000000000000000000000000000..45d56715265f117667995613cd5e3ebb02952b79 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/utils/host_diag_log/src/host_diag_log.c @@ -0,0 +1,306 @@ +/* + * Copyright (c) 2014-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/*============================================================================ + FILE: host_diag_log.c + + OVERVIEW: This source file contains definitions for WLAN UTIL diag APIs + + DEPENDENCIES: + ============================================================================*/ + +#include "qdf_types.h" +#include "i_host_diag_core_log.h" +#include "host_diag_core_event.h" +#include "wlan_nlink_common.h" +#include "cds_sched.h" +#include "wlan_ptt_sock_svc.h" +#include "wlan_nlink_srv.h" +#include "cds_api.h" +#include "wlan_ps_wow_diag.h" + +#define PTT_MSG_DIAG_CMDS_TYPE (0x5050) + +#define DIAG_TYPE_LOGS (1) +#define DIAG_TYPE_EVENTS (2) + +#define DIAG_SWAP16(A) ((((uint16_t)(A) & 0xff00) >> 8) | (((uint16_t)(A) & 0x00ff) << 8)) + +typedef struct event_report_s { + uint32_t diag_type; + uint16_t event_id; + uint16_t length; +} event_report_t; + +/**--------------------------------------------------------------------------- + + \brief host_diag_log_set_code() - + + This function sets the logging code in the given log record. + + \param - ptr - Pointer to the log header type. + - code - log code. + \return - None + + --------------------------------------------------------------------------*/ + +void host_diag_log_set_code(void *ptr, uint16_t code) +{ + if (ptr) { + /* All log packets are required to start with 'log_header_type' */ + ((log_hdr_type *) ptr)->code = code; + } +} + +/**--------------------------------------------------------------------------- + + \brief host_diag_log_set_length() - + + This function sets the length field in the given log record. + + \param - ptr - Pointer to the log header type. + - length - log length. + + \return - None + + --------------------------------------------------------------------------*/ + +void host_diag_log_set_length(void *ptr, uint16_t length) +{ + if (ptr) { + /* All log packets are required to start with 'log_header_type' */ + ((log_hdr_type *) ptr)->len = (uint16_t) length; + } +} + +/**--------------------------------------------------------------------------- + + \brief host_diag_log_submit() - + + This function sends the log data to the ptt socket app only if it is registered with the driver. + + \param - ptr - Pointer to the log header type. + + \return - None + + --------------------------------------------------------------------------*/ + +void host_diag_log_submit(void *plog_hdr_ptr) +{ + log_hdr_type *pHdr = (log_hdr_type *) plog_hdr_ptr; + tAniHdr *wmsg = NULL; + uint8_t *pBuf; + uint16_t data_len; + uint16_t total_len; + + if (cds_is_load_or_unload_in_progress()) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO, + "%s: Unloading/Loading in Progress. Ignore!!!", + __func__); + return; + } + + if (nl_srv_is_initialized() != 0) + return; + + if (cds_is_multicast_logging()) { + data_len = pHdr->len; + + total_len = sizeof(tAniHdr) + sizeof(uint32_t) + data_len; + + pBuf = (uint8_t *) qdf_mem_malloc(total_len); + + if (!pBuf) { + QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR, + "qdf_mem_malloc failed"); + return; + } + + wmsg = (tAniHdr *) pBuf; + wmsg->type = PTT_MSG_DIAG_CMDS_TYPE; + wmsg->length = total_len; + wmsg->length = DIAG_SWAP16(wmsg->length); + pBuf += sizeof(tAniHdr); + + /* Diag Type events or log */ + *(uint32_t *) pBuf = DIAG_TYPE_LOGS; + pBuf += sizeof(uint32_t); + + memcpy(pBuf, pHdr, data_len); + ptt_sock_send_msg_to_app (wmsg, 0, ANI_NL_MSG_PUMAC, + INVALID_PID); + qdf_mem_free((void *)wmsg); + } + return; +} + +/** + * host_diag_log_wlock() - This function is used to send wake lock diag events + * @reason: Reason why the wakelock was taken or released + * @wake_lock_name: Function in which the wakelock was taken or released + * @timeout: Timeout value in case of timed wakelocks + * @status: Status field indicating whether the wake lock was taken/released + * + * This function is used to send wake lock diag events to user space + * + * Return: None + * + */ +void host_diag_log_wlock(uint32_t reason, const char *wake_lock_name, + uint32_t timeout, uint32_t status) +{ + WLAN_HOST_DIAG_EVENT_DEF(wlan_diag_event, + struct host_event_wlan_wake_lock); + + if ((nl_srv_is_initialized() != 0) || + (cds_is_wakelock_enabled() == false)) + return; + + wlan_diag_event.status = status; + wlan_diag_event.reason = reason; + wlan_diag_event.timeout = timeout; + wlan_diag_event.name_len = strlen(wake_lock_name); + strlcpy(&wlan_diag_event.name[0], + wake_lock_name, + wlan_diag_event.name_len+1); + + WLAN_HOST_DIAG_EVENT_REPORT(&wlan_diag_event, EVENT_WLAN_WAKE_LOCK); +} + +/**--------------------------------------------------------------------------- + + \brief host_diag_event_report_payload() - + + This function sends the event data to the ptt socket app only if it is + registered with the driver. + + \param - ptr - Pointer to the log header type. + + \return - None + + --------------------------------------------------------------------------*/ + +void host_diag_event_report_payload(uint16_t event_Id, uint16_t length, + void *pPayload) +{ + tAniHdr *wmsg = NULL; + uint8_t *pBuf; + event_report_t *pEvent_report; + uint16_t total_len; + + if (cds_is_load_or_unload_in_progress()) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO, + "%s: Unloading/Loading in Progress. Ignore!!!", + __func__); + return; + } + + if (nl_srv_is_initialized() != 0) + return; + + if (cds_is_multicast_logging()) { + total_len = sizeof(tAniHdr) + sizeof(event_report_t) + length; + + pBuf = (uint8_t *) qdf_mem_malloc(total_len); + + if (!pBuf) { + QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR, + "qdf_mem_malloc failed"); + return; + } + wmsg = (tAniHdr *) pBuf; + wmsg->type = PTT_MSG_DIAG_CMDS_TYPE; + wmsg->length = total_len; + wmsg->length = DIAG_SWAP16(wmsg->length); + pBuf += sizeof(tAniHdr); + + pEvent_report = (event_report_t *) pBuf; + pEvent_report->diag_type = DIAG_TYPE_EVENTS; + pEvent_report->event_id = event_Id; + pEvent_report->length = length; + + pBuf += sizeof(event_report_t); + + memcpy(pBuf, pPayload, length); + + if (ptt_sock_send_msg_to_app + (wmsg, 0, ANI_NL_MSG_PUMAC, INVALID_PID) < 0) { + QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_WARN, + "Ptt Socket error sending message to the app!!"); + qdf_mem_free((void *)wmsg); + return; + } + + qdf_mem_free((void *)wmsg); + } + + return; + +} + +/** + * host_log_low_resource_failure() - This function is used to send low + * resource failure event + * @event_sub_type: Reason why the failure was observed + * + * This function is used to send low resource failure events to user space + * + * Return: None + * + */ +void host_log_low_resource_failure(uint8_t event_sub_type) +{ + WLAN_HOST_DIAG_EVENT_DEF(wlan_diag_event, + struct host_event_wlan_low_resource_failure); + + wlan_diag_event.event_sub_type = event_sub_type; + + WLAN_HOST_DIAG_EVENT_REPORT(&wlan_diag_event, + EVENT_WLAN_LOW_RESOURCE_FAILURE); +} + +#ifdef FEATURE_WLAN_DIAG_SUPPORT +/** + * qdf_wow_wakeup_host_event()- send wow wakeup event + * @wow_wakeup_cause: WOW wakeup reason code + * + * This function sends wow wakeup reason code diag event + * + * Return: void. + */ +void qdf_wow_wakeup_host_event(uint8_t wow_wakeup_cause) +{ + WLAN_HOST_DIAG_EVENT_DEF(wowRequest, + host_event_wlan_powersave_wow_payload_type); + qdf_mem_zero(&wowRequest, sizeof(wowRequest)); + + wowRequest.event_subtype = WLAN_WOW_WAKEUP; + wowRequest.wow_wakeup_cause = wow_wakeup_cause; + WLAN_HOST_DIAG_EVENT_REPORT(&wowRequest, + EVENT_WLAN_POWERSAVE_WOW); +} +#endif diff --git a/drivers/staging/qcacld-3.0/core/utils/host_diag_log/src/i_host_diag_core_event.h b/drivers/staging/qcacld-3.0/core/utils/host_diag_log/src/i_host_diag_core_event.h new file mode 100644 index 0000000000000000000000000000000000000000..b90bae7fd21720bd689a05367d988e927de7b7ac --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/utils/host_diag_log/src/i_host_diag_core_event.h @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2014-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#if !defined(__I_HOST_DIAG_CORE_EVENT_H) +#define __I_HOST_DIAG_CORE_EVENT_H + +/**========================================================================= + + \file i_host_diag_core_event.h + + \brief Android specific definitions for WLAN UTIL DIAG events + + ========================================================================*/ + +/* $Header$ */ + +/*-------------------------------------------------------------------------- + Include Files + ------------------------------------------------------------------------*/ +#include +#ifdef FEATURE_WLAN_DIAG_SUPPORT +#include +#endif + +/*-------------------------------------------------------------------------- + Preprocessor definitions and constants + ------------------------------------------------------------------------*/ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#ifdef FEATURE_WLAN_DIAG_SUPPORT + +void host_diag_event_report_payload(uint16_t event_Id, uint16_t length, + void *pPayload); +/*--------------------------------------------------------------------------- + Allocate an event payload holder + ---------------------------------------------------------------------------*/ +#define WLAN_HOST_DIAG_EVENT_DEF(payload_name, payload_type) \ + payload_type(payload_name) + +/*--------------------------------------------------------------------------- + Report the event + ---------------------------------------------------------------------------*/ +#define WLAN_HOST_DIAG_EVENT_REPORT(payload_ptr, ev_id) \ + do { \ + host_diag_event_report_payload(ev_id, \ + sizeof(*(payload_ptr)), \ + (void *)(payload_ptr)); \ + } while (0) + +#else /* FEATURE_WLAN_DIAG_SUPPORT */ + +#define WLAN_HOST_DIAG_EVENT_DEF(payload_name, payload_type) +#define WLAN_HOST_DIAG_EVENT_REPORT(payload_ptr, ev_id) + +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + +/** + * enum auth_timeout_type - authentication timeout type + * @AUTH_FAILURE_TIMEOUT: auth failure timeout + * @AUTH_RESPONSE_TIMEOUT: auth response timeout + */ +enum auth_timeout_type { + AUTH_FAILURE_TIMEOUT, + AUTH_RESPONSE_TIMEOUT, +}; + +/*------------------------------------------------------------------------- + Function declarations and documenation + ------------------------------------------------------------------------*/ +#ifdef FEATURE_WLAN_DIAG_SUPPORT +void host_diag_log_wlock(uint32_t reason, const char *wake_lock_name, + uint32_t timeout, uint32_t status); +#else +static inline void host_diag_log_wlock(uint32_t reason, + const char *wake_lock_name, + uint32_t timeout, uint32_t status) +{ + +} +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + +#ifdef FEATURE_WLAN_DIAG_SUPPORT +void host_log_low_resource_failure(uint8_t event_sub_type); +#else +static inline void host_log_low_resource_failure(uint8_t event_sub_type) +{ + +} +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + +#ifdef FEATURE_WLAN_DIAG_SUPPORT +void qdf_wow_wakeup_host_event(uint8_t wow_wakeup_cause); +#else +static inline void qdf_wow_wakeup_host_event(uint8_t wow_wakeup_cause) +{ + return; +} +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* __I_HOST_DIAG_CORE_EVENT_H */ diff --git a/drivers/staging/qcacld-3.0/core/utils/host_diag_log/src/i_host_diag_core_log.h b/drivers/staging/qcacld-3.0/core/utils/host_diag_log/src/i_host_diag_core_log.h new file mode 100644 index 0000000000000000000000000000000000000000..9417837b8a34e75bf8caa70a2d0d9f609ae3d9b1 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/utils/host_diag_log/src/i_host_diag_core_log.h @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2014-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#if !defined(__I_HOST_DIAG_CORE_LOG_H) +#define __I_HOST_DIAG_CORE_LOG_H + +#ifdef FEATURE_WLAN_DIAG_SUPPORT +#include +#endif + +/**========================================================================= + + \file i_host_diag_core_event.h + + \brief android-specific definitions for WLAN UTIL DIAG logs + + ========================================================================*/ + +/* $Header$ */ + +/*-------------------------------------------------------------------------- + Include Files + ------------------------------------------------------------------------*/ +#include +#include + +/*-------------------------------------------------------------------------- + Preprocessor definitions and constants + ------------------------------------------------------------------------*/ +/* FIXME To be removed when DIAG support is added. This definiton should be */ +/* picked from log.h file above. */ +typedef struct { + /* Specifies the length, in bytes of the entry, including this header. */ + uint16_t len; + + /* Specifies the log code for the entry */ + uint16_t code; + + /*Time Stamp lo */ + uint32_t ts_lo; + + /*Time Stamp hi */ + uint32_t ts_hi; +} __packed log_hdr_type; + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#ifdef FEATURE_WLAN_DIAG_SUPPORT +void host_diag_log_set_code(void *ptr, uint16_t code); +void host_diag_log_set_length(void *ptr, uint16_t length); +void host_diag_log_set_timestamp(void *plog_hdr_ptr); +void host_diag_log_submit(void *plog_hdr_ptr); + +/*--------------------------------------------------------------------------- + Allocate an event payload holder + ---------------------------------------------------------------------------*/ + +#define WLAN_HOST_DIAG_LOG_ALLOC(payload_ptr, payload_type, log_code) \ + do { \ + payload_ptr = (payload_type *)qdf_mem_malloc(sizeof(payload_type)); \ + if (payload_ptr) { \ + host_diag_log_set_code(payload_ptr, log_code); \ + host_diag_log_set_length(payload_ptr, sizeof(payload_type)); \ + } \ + } while (0) + +/*--------------------------------------------------------------------------- + Report the event + ---------------------------------------------------------------------------*/ +#define WLAN_HOST_DIAG_LOG_REPORT(payload_ptr) \ + do { \ + if (payload_ptr) { \ + host_diag_log_submit(payload_ptr); \ + qdf_mem_free(payload_ptr); \ + } \ + } while (0) + +/*--------------------------------------------------------------------------- + Free the payload + ---------------------------------------------------------------------------*/ +#define WLAN_HOST_DIAG_LOG_FREE(payload_ptr) \ + do { \ + if (payload_ptr) { \ + qdf_mem_free(payload_ptr); \ + } \ + } while (0) + +#else /* FEATURE_WLAN_DIAG_SUPPORT */ + +#define WLAN_HOST_DIAG_LOG_ALLOC(payload_ptr, payload_type, log_code) +#define WLAN_HOST_DIAG_LOG_REPORT(payload_ptr) +#define WLAN_HOST_DIAG_LOG_FREE(payload_ptr) + +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + +/*------------------------------------------------------------------------- + Function declarations and documenation + ------------------------------------------------------------------------*/ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* __I_HOST_DIAG_CORE_LOG_H */ diff --git a/drivers/staging/qcacld-3.0/core/utils/logging/inc/wlan_logging_sock_svc.h b/drivers/staging/qcacld-3.0/core/utils/logging/inc/wlan_logging_sock_svc.h new file mode 100644 index 0000000000000000000000000000000000000000..06d0b6fe0f0ed5cd5d3fd550cd8faa5a7c7ca897 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/utils/logging/inc/wlan_logging_sock_svc.h @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2014-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/****************************************************************************** +* wlan_logging_sock_svc.h +* +******************************************************************************/ + +#ifndef WLAN_LOGGING_SOCK_SVC_H +#define WLAN_LOGGING_SOCK_SVC_H + +#include +#include +#include +#include + +int wlan_logging_sock_init_svc(void); +int wlan_logging_sock_deinit_svc(void); +int wlan_logging_sock_activate_svc(int log_fe_to_console, int num_buf); +int wlan_logging_sock_deactivate_svc(void); +int wlan_log_to_user(QDF_TRACE_LEVEL log_level, char *to_be_sent, int length); + +#ifdef WLAN_LOGGING_SOCK_SVC_ENABLE +void wlan_logging_set_per_pkt_stats(void); +void wlan_logging_set_log_level(void); +void wlan_logging_set_fw_flush_complete(void); +void wlan_flush_host_logs_for_fatal(void); +#else +static inline void wlan_flush_host_logs_for_fatal(void) +{ +} +static inline void wlan_logging_set_log_level(void) +{ +} +static inline void wlan_logging_set_per_pkt_stats(void) +{ +} +static inline void wlan_logging_set_fw_flush_complete(void) +{ +} +#endif /* WLAN_LOGGING_SOCK_SVC_ENABLE */ + +#ifdef FEATURE_WLAN_DIAG_SUPPORT +void wlan_report_log_completion(uint32_t is_fatal, + uint32_t indicator, + uint32_t reason_code, + uint8_t ring_id); +#else +static inline void wlan_report_log_completion(uint32_t is_fatal, + uint32_t indicator, + uint32_t reason_code, + unit8_t ring_id) +{ + return; +} + +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + +void wlan_pkt_stats_to_logger_thread(void *pl_hdr, void *pkt_dump, void *data); + +void wlan_deregister_txrx_packetdump(void); +void wlan_register_txrx_packetdump(void); + +#endif /* WLAN_LOGGING_SOCK_SVC_H */ diff --git a/drivers/staging/qcacld-3.0/core/utils/logging/src/wlan_logging_sock_svc.c b/drivers/staging/qcacld-3.0/core/utils/logging/src/wlan_logging_sock_svc.c new file mode 100644 index 0000000000000000000000000000000000000000..eba7db36a6122c4e2a7d8ea555083138af7643ae --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/utils/logging/src/wlan_logging_sock_svc.c @@ -0,0 +1,1549 @@ +/* + * Copyright (c) 2014-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/****************************************************************************** +* wlan_logging_sock_svc.c +* +******************************************************************************/ + +#ifdef WLAN_LOGGING_SOCK_SVC_ENABLE +#include +#include +#include +#include +#include +#include +#include +#include "cds_utils.h" +#include "host_diag_core_log.h" +#include "wma.h" +#include "ol_txrx_api.h" +#include "csr_api.h" +#include "wlan_hdd_main.h" +#include "pktlog_ac.h" + +#define MAX_NUM_PKT_LOG 32 + +/** + * struct tx_status - tx status + * @tx_status_ok: successfully sent + acked + * @tx_status_discard: discard - not sent (congestion control) + * @tx_status_no_ack: no_ack - sent, but no ack + * @tx_status_download_fail: download_fail - + * the host could not deliver the tx frame to the target + * @tx_status_peer_del: peer_del - tx completion for + * alreay deleted peer used for HL case + * + * This enum has tx status types + */ +enum tx_status { + tx_status_ok, + tx_status_discard, + tx_status_no_ack, + tx_status_download_fail, + tx_status_peer_del, +}; + +static uint8_t gtx_count; +static uint8_t grx_count; + +#define LOGGING_TRACE(level, args ...) \ + QDF_TRACE(QDF_MODULE_ID_HDD, level, ## args) + +/* Global variables */ + +#define ANI_NL_MSG_LOG_TYPE 89 +#define ANI_NL_MSG_READY_IND_TYPE 90 +#define MAX_LOGMSG_LENGTH 4096 +#define MAX_PKTSTATS_LENGTH 2048 +#define MAX_PKTSTATS_BUFF 16 + +#define HOST_LOG_DRIVER_MSG 0x001 +#define HOST_LOG_PER_PKT_STATS 0x002 +#define HOST_LOG_FW_FLUSH_COMPLETE 0x003 +#define DIAG_TYPE_LOGS 1 +#define PTT_MSG_DIAG_CMDS_TYPE 0x5050 + +struct log_msg { + struct list_head node; + unsigned int radio; + unsigned int index; + /* indicates the current filled log length in logbuf */ + unsigned int filled_length; + /* + * Buf to hold the log msg + * tAniHdr + log + */ + char logbuf[MAX_LOGMSG_LENGTH]; +}; + +/** + * struct packet_dump - This data structure contains the + * Tx/Rx packet stats + * @status: Status + * @type: Type + * @driver_ts: driver timestamp + * @fw_ts: fw timestamp + */ +struct packet_dump { + unsigned char status; + unsigned char type; + uint32_t driver_ts; + uint16_t fw_ts; +} __attribute__((__packed__)); + +/** + * struct pkt_stats_msg - This data structure contains the + * pkt stats node for link list + * @node: LinkList node + * @node: Pointer to skb + */ +struct pkt_stats_msg { + struct list_head node; + struct sk_buff *skb; +}; + +struct wlan_logging { + /* Log Fatal and ERROR to console */ + bool log_fe_to_console; + /* Number of buffers to be used for logging */ + int num_buf; + /* Lock to synchronize access to shared logging resource */ + spinlock_t spin_lock; + /* Holds the free node which can be used for filling logs */ + struct list_head free_list; + /* Holds the filled nodes which needs to be indicated to APP */ + struct list_head filled_list; + /* Wait queue for Logger thread */ + wait_queue_head_t wait_queue; + /* Logger thread */ + struct task_struct *thread; + /* Logging thread sets this variable on exit */ + struct completion shutdown_comp; + /* Indicates to logger thread to exit */ + bool exit; + /* Holds number of dropped logs */ + unsigned int drop_count; + /* current logbuf to which the log will be filled to */ + struct log_msg *pcur_node; + /* Event flag used for wakeup and post indication*/ + unsigned long eventFlag; + /* Indicates logger thread is activated */ + bool is_active; + /* Flush completion check */ + bool is_flush_complete; + /* paramaters for pkt stats */ + struct list_head pkt_stat_free_list; + struct list_head pkt_stat_filled_list; + struct pkt_stats_msg *pkt_stats_pcur_node; + unsigned int pkt_stat_drop_cnt; + spinlock_t pkt_stats_lock; + unsigned int pkt_stats_msg_idx; +}; + +static struct wlan_logging gwlan_logging; +static struct log_msg *gplog_msg; +static struct pkt_stats_msg *gpkt_stats_buffers; + +/* PID of the APP to log the message */ +static int gapp_pid = INVALID_PID; + +/* Utility function to send a netlink message to an application + * in user space + */ +static int wlan_send_sock_msg_to_app(tAniHdr *wmsg, int radio, + int src_mod, int pid) +{ + int err = -1; + int payload_len; + int tot_msg_len; + tAniNlHdr *wnl = NULL; + struct sk_buff *skb; + struct nlmsghdr *nlh; + int wmsg_length = ntohs(wmsg->length); + static int nlmsg_seq; + + if (radio < 0 || radio > ANI_MAX_RADIOS) { + LOGGING_TRACE(QDF_TRACE_LEVEL_ERROR, + "%s: invalid radio id [%d]", __func__, radio); + return -EINVAL; + } + + payload_len = wmsg_length + sizeof(wnl->radio) + sizeof(*wmsg); + tot_msg_len = NLMSG_SPACE(payload_len); + skb = dev_alloc_skb(tot_msg_len); + if (skb == NULL) { + LOGGING_TRACE(QDF_TRACE_LEVEL_ERROR, + "%s: dev_alloc_skb() failed for msg size[%d]", + __func__, tot_msg_len); + return -ENOMEM; + } + nlh = nlmsg_put(skb, pid, nlmsg_seq++, src_mod, payload_len, + NLM_F_REQUEST); + if (NULL == nlh) { + LOGGING_TRACE(QDF_TRACE_LEVEL_ERROR, + "%s: nlmsg_put() failed for msg size[%d]", + __func__, tot_msg_len); + kfree_skb(skb); + return -ENOMEM; + } + + wnl = (tAniNlHdr *) nlh; + wnl->radio = radio; + memcpy(&wnl->wmsg, wmsg, wmsg_length); + + err = nl_srv_ucast(skb, pid, MSG_DONTWAIT); + if (err) + LOGGING_TRACE(QDF_TRACE_LEVEL_INFO, + "%s: Failed sending Msg Type [0x%X] to pid[%d]\n", + __func__, wmsg->type, pid); + return err; +} + +/** + * is_data_path_module() - To check for a Datapath module + * @mod_id: Module id + * + * Checks if the input module id belongs to data path. + * + * Return: True if the module belongs to data path, false otherwise + */ +static bool is_data_path_module(QDF_MODULE_ID mod_id) +{ + switch (mod_id) { + case QDF_MODULE_ID_HDD_DATA: + case QDF_MODULE_ID_HDD_SAP_DATA: + case QDF_MODULE_ID_HTC: + case QDF_MODULE_ID_TXRX: + case QDF_MODULE_ID_HIF: + return true; + default: + return false; + } +} + +static void set_default_logtoapp_log_level(void) +{ + int i; + + /* module id 0 is reserved */ + for (i = 1; i < QDF_MODULE_ID_MAX; i++) { + if (is_data_path_module(i)) + qdf_trace_set_module_trace_level(i, + QDF_DATA_PATH_TRACE_LEVEL); + else + qdf_trace_set_value(i, QDF_TRACE_LEVEL_ALL, true); + } +} + +static void clear_default_logtoapp_log_level(void) +{ + int module; + + for (module = 0; module < QDF_MODULE_ID_MAX; module++) { + qdf_trace_set_value(module, QDF_TRACE_LEVEL_NONE, false); + qdf_trace_set_value(module, QDF_TRACE_LEVEL_FATAL, true); + qdf_trace_set_value(module, QDF_TRACE_LEVEL_ERROR, true); + } + + qdf_trace_set_value(QDF_MODULE_ID_RSV4, QDF_TRACE_LEVEL_NONE, + false); +} + +/* Need to call this with spin_lock acquired */ +static int wlan_queue_logmsg_for_app(void) +{ + char *ptr; + int ret = 0; + ptr = &gwlan_logging.pcur_node->logbuf[sizeof(tAniHdr)]; + ptr[gwlan_logging.pcur_node->filled_length] = '\0'; + + *(unsigned short *)(gwlan_logging.pcur_node->logbuf) = + ANI_NL_MSG_LOG_TYPE; + *(unsigned short *)(gwlan_logging.pcur_node->logbuf + 2) = + gwlan_logging.pcur_node->filled_length; + list_add_tail(&gwlan_logging.pcur_node->node, + &gwlan_logging.filled_list); + + if (!list_empty(&gwlan_logging.free_list)) { + /* Get buffer from free list */ + gwlan_logging.pcur_node = + (struct log_msg *)(gwlan_logging.free_list.next); + list_del_init(gwlan_logging.free_list.next); + } else if (!list_empty(&gwlan_logging.filled_list)) { + /* Get buffer from filled list */ + /* This condition will drop the packet from being + * indicated to app + */ + gwlan_logging.pcur_node = + (struct log_msg *)(gwlan_logging.filled_list.next); + ++gwlan_logging.drop_count; + list_del_init(gwlan_logging.filled_list.next); + ret = 1; + } + + /* Reset the current node values */ + gwlan_logging.pcur_node->filled_length = 0; + return ret; +} + +#ifdef QCA_WIFI_3_0_ADRASTEA +/** + * wlan_add_user_log_radio_time_stamp() - add radio, firmware timestamp and + * time stamp in log buffer + * @tbuf: Pointer to time stamp buffer + * @tbuf_sz: Time buffer size + * @ts: Time stamp value + * @radoi: the radio index + * + * For adrastea time stamp is QTIMER raw tick which will be used by cnss_diag + * to convert it into user visible time stamp. In adrstea FW also uses QTIMER + * raw ticks which is needed to synchronize host and fw log time stamps + * + * Also add logcat timestamp so that driver logs and + * logcat logs can be co-related + * + * For discrete solution e.g rome use system tick and convert it into + * seconds.milli seconds + * + * Return: number of characters written in target buffer not including + * trailing '/0' + */ +static int wlan_add_user_log_radio_time_stamp(char *tbuf, size_t tbuf_sz, + uint64_t ts, int radio) +{ + int tlen; + char time_buf[20]; + + qdf_get_time_of_the_day_in_hr_min_sec_usec(time_buf, sizeof(time_buf)); + + tlen = scnprintf(tbuf, tbuf_sz, "R%d: [%.16s][%llu] %s ", radio, + ((in_irq() ? "irq" : in_softirq() ? "soft_irq" : + current->comm)), + ts, time_buf); + return tlen; +} +#else +/** + * wlan_add_user_log_radio_time_stamp() - add radio, firmware timestamp and + * logcat timestamp in log buffer + * @tbuf: Pointer to time stamp buffer + * @tbuf_sz: Time buffer size + * @ts: Time stamp value + * @radio: the radio index + * + * For adrastea time stamp QTIMER raw tick which will be used by cnss_diag + * to convert it into user visible time stamp + * + * Also add logcat timestamp so that driver logs and + * logcat logs can be co-related + * + * For discrete solution e.g rome use system tick and convert it into + * seconds.milli seconds + * + * Return: number of characters written in target buffer not including + * trailing '/0' + */ +static int wlan_add_user_log_radio_time_stamp(char *tbuf, size_t tbuf_sz, + uint64_t ts, int radio) +{ + int tlen; + uint32_t rem; + char time_buf[20]; + + qdf_get_time_of_the_day_in_hr_min_sec_usec(time_buf, sizeof(time_buf)); + + rem = do_div(ts, QDF_MC_TIMER_TO_SEC_UNIT); + tlen = scnprintf(tbuf, tbuf_sz, "R%d: [%.16s][%lu.%06lu] %s ", radio, + ((in_irq() ? "irq" : in_softirq() ? "soft_irq" : + current->comm)), + (unsigned long) ts, + (unsigned long)rem, time_buf); + return tlen; +} +#endif + +int wlan_log_to_user(QDF_TRACE_LEVEL log_level, char *to_be_sent, int length) +{ + /* Add the current time stamp */ + char *ptr; + char tbuf[60]; + int tlen; + int total_log_len; + unsigned int *pfilled_length; + bool wake_up_thread = false; + unsigned long flags; + uint64_t ts; + int radio; + bool log_overflow = false; + + radio = cds_get_radio_index(); + + if (!cds_is_multicast_logging() || (radio == -EINVAL) || + (!gwlan_logging.is_active)) { + /* + * This is to make sure that we print the logs to kmsg console + * when no logger app is running. This is also needed to + * log the initial messages during loading of driver where even + * if app is running it will not be able to + * register with driver immediately and start logging all the + * messages. + */ + /* + * R%d: if the radio index is invalid, just post the message + * to console. + * Also the radio index shouldn't happen to be EINVAL, but if + * that happen just print it, so that the logging would be + * aware the cnss_logger is somehow failed. + */ + pr_info("R%d: %s\n", radio, to_be_sent); + return 0; + } + + ts = qdf_get_log_timestamp(); + tlen = wlan_add_user_log_radio_time_stamp(tbuf, sizeof(tbuf), ts, + radio); + + /* 1+1 indicate '\n'+'\0' */ + total_log_len = length + tlen + 1 + 1; + + spin_lock_irqsave(&gwlan_logging.spin_lock, flags); + /* wlan logging svc resources are not yet initialized */ + if (!gwlan_logging.pcur_node) { + spin_unlock_irqrestore(&gwlan_logging.spin_lock, flags); + return -EIO; + } + + pfilled_length = &gwlan_logging.pcur_node->filled_length; + + /* Check if we can accomodate more log into current node/buffer */ + if ((MAX_LOGMSG_LENGTH <= (*pfilled_length + + sizeof(tAniNlHdr))) || + ((MAX_LOGMSG_LENGTH - (*pfilled_length + + sizeof(tAniNlHdr))) < total_log_len)) { + wake_up_thread = true; + wlan_queue_logmsg_for_app(); + pfilled_length = &gwlan_logging.pcur_node->filled_length; + } + + ptr = &gwlan_logging.pcur_node->logbuf[sizeof(tAniHdr)]; + + /* Assumption here is that we receive logs which is always less than + * MAX_LOGMSG_LENGTH, where we can accomodate the + * tAniNlHdr + [context][timestamp] + log + * + * Continue and copy logs to the available length and discard the rest. + */ + if (MAX_LOGMSG_LENGTH < (sizeof(tAniNlHdr) + total_log_len)) { + log_overflow = true; + total_log_len = MAX_LOGMSG_LENGTH - sizeof(tAniNlHdr) - 2; + } + + memcpy(&ptr[*pfilled_length], tbuf, tlen); + memcpy(&ptr[*pfilled_length + tlen], to_be_sent, + min(length, (total_log_len - tlen))); + *pfilled_length += tlen + min(length, total_log_len - tlen); + ptr[*pfilled_length] = '\n'; + *pfilled_length += 1; + + spin_unlock_irqrestore(&gwlan_logging.spin_lock, flags); + /* + * QDF_ASSERT if complete log was not accomodated into + * the available buffer. + */ + QDF_ASSERT(!log_overflow); + + /* Wakeup logger thread */ + if ((true == wake_up_thread)) { + set_bit(HOST_LOG_DRIVER_MSG, &gwlan_logging.eventFlag); + wake_up_interruptible(&gwlan_logging.wait_queue); + } + + if (gwlan_logging.log_fe_to_console + && ((QDF_TRACE_LEVEL_FATAL == log_level) + || (QDF_TRACE_LEVEL_ERROR == log_level))) { + pr_info("%s %s\n", tbuf, to_be_sent); + } + + return 0; +} + +/** + * pkt_stats_fill_headers() - This function adds headers to skb + * @skb: skb to which headers need to be added + * + * Return: 0 on success or Errno on failure + */ +static int pkt_stats_fill_headers(struct sk_buff *skb) +{ + struct host_log_pktlog_info cds_pktlog; + int cds_pkt_size = sizeof(struct host_log_pktlog_info); + tAniNlHdr msg_header; + int extra_header_len, nl_payload_len; + static int nlmsg_seq; + int diag_type; + + qdf_mem_zero(&cds_pktlog, cds_pkt_size); + cds_pktlog.version = VERSION_LOG_WLAN_PKT_LOG_INFO_C; + cds_pktlog.buf_len = skb->len; + cds_pktlog.seq_no = gwlan_logging.pkt_stats_msg_idx++; + host_diag_log_set_code(&cds_pktlog, LOG_WLAN_PKT_LOG_INFO_C); + host_diag_log_set_length(&cds_pktlog.log_hdr, skb->len + + cds_pkt_size); + + if (unlikely(skb_headroom(skb) < cds_pkt_size)) { + pr_err("VPKT [%d]: Insufficient headroom, head[%p], data[%p], req[%zu]", + __LINE__, skb->head, skb->data, sizeof(msg_header)); + return -EIO; + } + + qdf_mem_copy(skb_push(skb, cds_pkt_size), + &cds_pktlog, cds_pkt_size); + + if (unlikely(skb_headroom(skb) < sizeof(int))) { + pr_err("VPKT [%d]: Insufficient headroom, head[%p], data[%p], req[%zu]", + __LINE__, skb->head, skb->data, sizeof(int)); + return -EIO; + } + + diag_type = DIAG_TYPE_LOGS; + qdf_mem_copy(skb_push(skb, sizeof(int)), &diag_type, sizeof(int)); + + extra_header_len = sizeof(msg_header.radio) + sizeof(tAniHdr) + + sizeof(struct nlmsghdr); + nl_payload_len = extra_header_len + skb->len; + + msg_header.nlh.nlmsg_type = ANI_NL_MSG_PUMAC; + msg_header.nlh.nlmsg_len = nl_payload_len; + msg_header.nlh.nlmsg_flags = NLM_F_REQUEST; + msg_header.nlh.nlmsg_pid = 0; + msg_header.nlh.nlmsg_seq = nlmsg_seq++; + msg_header.radio = 0; + msg_header.wmsg.type = PTT_MSG_DIAG_CMDS_TYPE; + msg_header.wmsg.length = cpu_to_be16(skb->len); + + if (unlikely(skb_headroom(skb) < sizeof(msg_header))) { + pr_err("VPKT [%d]: Insufficient headroom, head[%p], data[%p], req[%zu]", + __LINE__, skb->head, skb->data, sizeof(msg_header)); + return -EIO; + } + + qdf_mem_copy(skb_push(skb, sizeof(msg_header)), &msg_header, + sizeof(msg_header)); + + return 0; +} + +/** + * pktlog_send_per_pkt_stats_to_user() - This function is used to send the per + * packet statistics to the user + * + * This function is used to send the per packet statistics to the user + * + * Return: Success if the message is posted to user + */ +int pktlog_send_per_pkt_stats_to_user(void) +{ + int ret = -1; + struct pkt_stats_msg *pstats_msg; + unsigned long flags; + struct sk_buff *skb_new = NULL; + static int rate_limit; + bool free_old_skb = false; + + while (!list_empty(&gwlan_logging.pkt_stat_filled_list) + && !gwlan_logging.exit) { + skb_new = dev_alloc_skb(MAX_PKTSTATS_LENGTH); + if (skb_new == NULL) { + if (!rate_limit) { + pr_err("%s: dev_alloc_skb() failed for msg size[%d] drop count = %u\n", + __func__, MAX_LOGMSG_LENGTH, + gwlan_logging.drop_count); + } + rate_limit = 1; + ret = -ENOMEM; + break; + } + + spin_lock_irqsave(&gwlan_logging.pkt_stats_lock, flags); + + pstats_msg = (struct pkt_stats_msg *) + (gwlan_logging.pkt_stat_filled_list.next); + list_del_init(gwlan_logging.pkt_stat_filled_list.next); + spin_unlock_irqrestore(&gwlan_logging.pkt_stats_lock, flags); + + ret = pkt_stats_fill_headers(pstats_msg->skb); + if (ret < 0) { + pr_err("%s failed to fill headers %d\n", __func__, ret); + free_old_skb = true; + goto err; + } + ret = nl_srv_bcast(pstats_msg->skb); + if (ret < 0) { + pr_info("%s: Send Failed %d drop_count = %u\n", + __func__, ret, + ++gwlan_logging.pkt_stat_drop_cnt); + } else { + ret = 0; + } +err: + /* + * Free old skb in case or error before assigning new skb + * to the free list. + */ + if (free_old_skb) + dev_kfree_skb(pstats_msg->skb); + + spin_lock_irqsave(&gwlan_logging.pkt_stats_lock, flags); + pstats_msg->skb = skb_new; + list_add_tail(&pstats_msg->node, + &gwlan_logging.pkt_stat_free_list); + spin_unlock_irqrestore(&gwlan_logging.pkt_stats_lock, flags); + ret = 0; + } + + return ret; + +} + +static int send_filled_buffers_to_user(void) +{ + int ret = -1; + struct log_msg *plog_msg; + int payload_len; + int tot_msg_len; + tAniNlHdr *wnl; + struct sk_buff *skb = NULL; + struct nlmsghdr *nlh; + static int nlmsg_seq; + unsigned long flags; + static int rate_limit; + + while (!list_empty(&gwlan_logging.filled_list) + && !gwlan_logging.exit) { + + skb = dev_alloc_skb(MAX_LOGMSG_LENGTH); + if (skb == NULL) { + if (!rate_limit) { + pr_err + ("%s: dev_alloc_skb() failed for msg size[%d] drop count = %u\n", + __func__, MAX_LOGMSG_LENGTH, + gwlan_logging.drop_count); + } + rate_limit = 1; + ret = -ENOMEM; + break; + } + rate_limit = 0; + + spin_lock_irqsave(&gwlan_logging.spin_lock, flags); + + plog_msg = (struct log_msg *) + (gwlan_logging.filled_list.next); + list_del_init(gwlan_logging.filled_list.next); + spin_unlock_irqrestore(&gwlan_logging.spin_lock, flags); + /* 4 extra bytes for the radio idx */ + payload_len = plog_msg->filled_length + + sizeof(wnl->radio) + sizeof(tAniHdr); + + tot_msg_len = NLMSG_SPACE(payload_len); + nlh = nlmsg_put(skb, 0, nlmsg_seq++, + ANI_NL_MSG_LOG, payload_len, NLM_F_REQUEST); + if (NULL == nlh) { + spin_lock_irqsave(&gwlan_logging.spin_lock, flags); + list_add_tail(&plog_msg->node, + &gwlan_logging.free_list); + spin_unlock_irqrestore(&gwlan_logging.spin_lock, flags); + pr_err("%s: drop_count = %u\n", __func__, + ++gwlan_logging.drop_count); + pr_err("%s: nlmsg_put() failed for msg size[%d]\n", + __func__, tot_msg_len); + dev_kfree_skb(skb); + skb = NULL; + ret = -EINVAL; + continue; + } + + wnl = (tAniNlHdr *) nlh; + wnl->radio = plog_msg->radio; + memcpy(&wnl->wmsg, plog_msg->logbuf, + plog_msg->filled_length + sizeof(tAniHdr)); + + spin_lock_irqsave(&gwlan_logging.spin_lock, flags); + list_add_tail(&plog_msg->node, &gwlan_logging.free_list); + spin_unlock_irqrestore(&gwlan_logging.spin_lock, flags); + + ret = nl_srv_bcast(skb); + /* print every 64th drop count */ + if (ret < 0 && (!(gwlan_logging.drop_count % 0x40))) { + pr_err("%s: Send Failed %d drop_count = %u\n", + __func__, ret, ++gwlan_logging.drop_count); + } + } + + return ret; +} + +#ifdef FEATURE_WLAN_DIAG_SUPPORT +/** + * wlan_report_log_completion() - Report bug report completion to userspace + * @is_fatal: Type of event, fatal or not + * @indicator: Source of bug report, framework/host/firmware + * @reason_code: Reason for triggering bug report + * @ring_id: Ring id of logging entities + * + * This function is used to report the bug report completion to userspace + * + * Return: None + */ +void wlan_report_log_completion(uint32_t is_fatal, + uint32_t indicator, + uint32_t reason_code, + uint8_t ring_id) +{ + WLAN_HOST_DIAG_EVENT_DEF(wlan_diag_event, + struct host_event_wlan_log_complete); + + wlan_diag_event.is_fatal = is_fatal; + wlan_diag_event.indicator = indicator; + wlan_diag_event.reason_code = reason_code; + wlan_diag_event.reserved = ring_id; + + WLAN_HOST_DIAG_EVENT_REPORT(&wlan_diag_event, EVENT_WLAN_LOG_COMPLETE); +} +#endif + +/** + * send_flush_completion_to_user() - Indicate flush completion to the user + * @ring_id: Ring id of logging entities + * + * This function is used to send the flush completion message to user space + * + * Return: None + */ +static void send_flush_completion_to_user(uint8_t ring_id) +{ + uint32_t is_fatal, indicator, reason_code; + bool recovery_needed = false; + + cds_get_and_reset_log_completion(&is_fatal, &indicator, &reason_code, + &recovery_needed); + + /* Error on purpose, so that it will get logged in the kmsg */ + LOGGING_TRACE(QDF_TRACE_LEVEL_DEBUG, + "%s: Sending flush done to userspace, recovery: %d", + __func__, recovery_needed); + + wlan_report_log_completion(is_fatal, indicator, reason_code, ring_id); + + if (!recovery_needed) + return; + + if (cds_is_self_recovery_enabled()) + cds_trigger_recovery(false); + else + QDF_BUG(0); +} + +/** + * wlan_logging_thread() - The WLAN Logger thread + * @Arg - pointer to the HDD context + * + * This thread logs log message to App registered for the logs. + */ +static int wlan_logging_thread(void *Arg) +{ + int ret_wait_status = 0; + int ret = 0; + unsigned long flags; + + while (!gwlan_logging.exit) { + ret_wait_status = + wait_event_interruptible(gwlan_logging.wait_queue, + (!list_empty + (&gwlan_logging.filled_list) + || test_bit( + HOST_LOG_DRIVER_MSG, + &gwlan_logging.eventFlag) + || test_bit( + HOST_LOG_PER_PKT_STATS, + &gwlan_logging.eventFlag) + || test_bit( + HOST_LOG_FW_FLUSH_COMPLETE, + &gwlan_logging.eventFlag) + || gwlan_logging.exit)); + + if (ret_wait_status == -ERESTARTSYS) { + pr_err + ("%s: wait_event_interruptible returned -ERESTARTSYS", + __func__); + break; + } + + if (gwlan_logging.exit) + break; + + + if (test_and_clear_bit(HOST_LOG_DRIVER_MSG, + &gwlan_logging.eventFlag)) { + ret = send_filled_buffers_to_user(); + if (-ENOMEM == ret) + msleep(200); + if (WLAN_LOG_INDICATOR_HOST_ONLY == + cds_get_log_indicator()) { + send_flush_completion_to_user( + RING_ID_DRIVER_DEBUG); + } + } + + if (test_and_clear_bit(HOST_LOG_PER_PKT_STATS, + &gwlan_logging.eventFlag)) { + ret = pktlog_send_per_pkt_stats_to_user(); + if (-ENOMEM == ret) + msleep(200); + } + + if (test_and_clear_bit(HOST_LOG_FW_FLUSH_COMPLETE, + &gwlan_logging.eventFlag)) { + /* Flush bit could have been set while we were mid + * way in the logging thread. So, need to check other + * buffers like log messages, per packet stats again + * to flush any residual data in them + */ + if (gwlan_logging.is_flush_complete == true) { + gwlan_logging.is_flush_complete = false; + send_flush_completion_to_user( + RING_ID_DRIVER_DEBUG); + } else { + gwlan_logging.is_flush_complete = true; + /* Flush all current host logs*/ + spin_lock_irqsave(&gwlan_logging.spin_lock, + flags); + wlan_queue_logmsg_for_app(); + spin_unlock_irqrestore(&gwlan_logging.spin_lock, + flags); + set_bit(HOST_LOG_DRIVER_MSG, + &gwlan_logging.eventFlag); + set_bit(HOST_LOG_PER_PKT_STATS, + &gwlan_logging.eventFlag); + set_bit(HOST_LOG_FW_FLUSH_COMPLETE, + &gwlan_logging.eventFlag); + wake_up_interruptible( + &gwlan_logging.wait_queue); + } + } + } + + complete_and_exit(&gwlan_logging.shutdown_comp, 0); + + return 0; +} + +/* + * Process all the Netlink messages from Logger Socket app in user space + */ +static int wlan_logging_proc_sock_rx_msg(struct sk_buff *skb) +{ + tAniNlHdr *wnl; + int radio; + int type; + int ret, len; + + wnl = (tAniNlHdr *) skb->data; + radio = wnl->radio; + type = wnl->nlh.nlmsg_type; + + if (radio < 0 || radio > ANI_MAX_RADIOS) { + LOGGING_TRACE(QDF_TRACE_LEVEL_ERROR, + "%s: invalid radio id [%d]\n", __func__, radio); + return -EINVAL; + } + + len = ntohs(wnl->wmsg.length) + sizeof(tAniNlHdr); + if (len > skb_headlen(skb)) { + LOGGING_TRACE(QDF_TRACE_LEVEL_ERROR, + "%s: invalid length, msgLen:%x skb len:%x headLen: %d data_len: %d", + __func__, len, skb->len, skb_headlen(skb), + skb->data_len); + return -EINVAL; + } + + if (wnl->wmsg.length > skb->data_len) { + LOGGING_TRACE(QDF_TRACE_LEVEL_ERROR, + "%s: invalid length msgLen:%x skb data_len:%x\n", + __func__, wnl->wmsg.length, skb->data_len); + return -EINVAL; + } + + if (gapp_pid != INVALID_PID) { + if (wnl->nlh.nlmsg_pid > gapp_pid) { + gapp_pid = wnl->nlh.nlmsg_pid; + } + + spin_lock_bh(&gwlan_logging.spin_lock); + if (gwlan_logging.pcur_node->filled_length) { + wlan_queue_logmsg_for_app(); + } + spin_unlock_bh(&gwlan_logging.spin_lock); + set_bit(HOST_LOG_DRIVER_MSG, &gwlan_logging.eventFlag); + wake_up_interruptible(&gwlan_logging.wait_queue); + } else { + /* This is to set the default levels (WLAN logging + * default values not the QDF trace default) when + * logger app is registered for the first time. + */ + gapp_pid = wnl->nlh.nlmsg_pid; + } + + ret = wlan_send_sock_msg_to_app(&wnl->wmsg, 0, + ANI_NL_MSG_LOG, wnl->nlh.nlmsg_pid); + if (ret < 0) { + LOGGING_TRACE(QDF_TRACE_LEVEL_ERROR, + "wlan_send_sock_msg_to_app: failed"); + } + + return ret; +} + +int wlan_logging_sock_activate_svc(int log_fe_to_console, int num_buf) +{ + int i = 0, j, pkt_stats_size; + unsigned long irq_flag; + + gapp_pid = INVALID_PID; + + gplog_msg = (struct log_msg *)vmalloc(num_buf * sizeof(struct log_msg)); + if (!gplog_msg) { + pr_err("%s: Could not allocate memory\n", __func__); + return -ENOMEM; + } + + qdf_mem_zero(gplog_msg, (num_buf * sizeof(struct log_msg))); + + gwlan_logging.log_fe_to_console = !!log_fe_to_console; + gwlan_logging.num_buf = num_buf; + + spin_lock_irqsave(&gwlan_logging.spin_lock, irq_flag); + INIT_LIST_HEAD(&gwlan_logging.free_list); + INIT_LIST_HEAD(&gwlan_logging.filled_list); + + for (i = 0; i < num_buf; i++) { + list_add(&gplog_msg[i].node, &gwlan_logging.free_list); + gplog_msg[i].index = i; + } + gwlan_logging.pcur_node = (struct log_msg *) + (gwlan_logging.free_list.next); + list_del_init(gwlan_logging.free_list.next); + spin_unlock_irqrestore(&gwlan_logging.spin_lock, irq_flag); + + /* Initialize the pktStats data structure here */ + pkt_stats_size = sizeof(struct pkt_stats_msg); + gpkt_stats_buffers = vmalloc(MAX_PKTSTATS_BUFF * pkt_stats_size); + if (!gpkt_stats_buffers) { + pr_err("%s: Could not allocate memory for Pkt stats\n", + __func__); + goto err1; + } + qdf_mem_zero(gpkt_stats_buffers, + MAX_PKTSTATS_BUFF * pkt_stats_size); + + spin_lock_irqsave(&gwlan_logging.pkt_stats_lock, irq_flag); + gwlan_logging.pkt_stats_msg_idx = 0; + INIT_LIST_HEAD(&gwlan_logging.pkt_stat_free_list); + INIT_LIST_HEAD(&gwlan_logging.pkt_stat_filled_list); + spin_unlock_irqrestore(&gwlan_logging.pkt_stats_lock, irq_flag); + + + for (i = 0; i < MAX_PKTSTATS_BUFF; i++) { + gpkt_stats_buffers[i].skb = dev_alloc_skb(MAX_PKTSTATS_LENGTH); + if (gpkt_stats_buffers[i].skb == NULL) { + pr_err("%s: Memory alloc failed for skb", __func__); + /* free previously allocated skb and return */ + for (j = 0; j < i ; j++) + dev_kfree_skb(gpkt_stats_buffers[j].skb); + goto err2; + } + spin_lock_irqsave(&gwlan_logging.pkt_stats_lock, irq_flag); + list_add(&gpkt_stats_buffers[i].node, + &gwlan_logging.pkt_stat_free_list); + spin_unlock_irqrestore(&gwlan_logging.pkt_stats_lock, irq_flag); + } + spin_lock_irqsave(&gwlan_logging.pkt_stats_lock, irq_flag); + gwlan_logging.pkt_stats_pcur_node = (struct pkt_stats_msg *) + (gwlan_logging.pkt_stat_free_list.next); + list_del_init(gwlan_logging.pkt_stat_free_list.next); + spin_unlock_irqrestore(&gwlan_logging.pkt_stats_lock, irq_flag); + /* Pkt Stats intialization done */ + + init_waitqueue_head(&gwlan_logging.wait_queue); + gwlan_logging.exit = false; + clear_bit(HOST_LOG_DRIVER_MSG, &gwlan_logging.eventFlag); + clear_bit(HOST_LOG_PER_PKT_STATS, &gwlan_logging.eventFlag); + clear_bit(HOST_LOG_FW_FLUSH_COMPLETE, &gwlan_logging.eventFlag); + init_completion(&gwlan_logging.shutdown_comp); + gwlan_logging.thread = kthread_create(wlan_logging_thread, NULL, + "wlan_logging_thread"); + if (IS_ERR(gwlan_logging.thread)) { + pr_err("%s: Could not Create LogMsg Thread Controller", + __func__); + goto err3; + } + wake_up_process(gwlan_logging.thread); + gwlan_logging.is_active = true; + gwlan_logging.is_flush_complete = false; + + nl_srv_register(ANI_NL_MSG_LOG, wlan_logging_proc_sock_rx_msg); + + return 0; + +err3: + for (i = 0; i < MAX_PKTSTATS_BUFF; i++) { + if (gpkt_stats_buffers[i].skb) + dev_kfree_skb(gpkt_stats_buffers[i].skb); + } +err2: + spin_lock_irqsave(&gwlan_logging.pkt_stats_lock, irq_flag); + gwlan_logging.pkt_stats_pcur_node = NULL; + spin_unlock_irqrestore(&gwlan_logging.pkt_stats_lock, irq_flag); + vfree(gpkt_stats_buffers); + gpkt_stats_buffers = NULL; +err1: + spin_lock_irqsave(&gwlan_logging.spin_lock, irq_flag); + gwlan_logging.pcur_node = NULL; + spin_unlock_irqrestore(&gwlan_logging.spin_lock, irq_flag); + vfree(gplog_msg); + gplog_msg = NULL; + return -ENOMEM; +} + +int wlan_logging_sock_deactivate_svc(void) +{ + unsigned long irq_flag; + int i = 0; + + if (!gplog_msg) + return 0; + + nl_srv_unregister(ANI_NL_MSG_LOG, wlan_logging_proc_sock_rx_msg); + clear_default_logtoapp_log_level(); + gapp_pid = INVALID_PID; + + INIT_COMPLETION(gwlan_logging.shutdown_comp); + gwlan_logging.exit = true; + gwlan_logging.is_active = false; + cds_set_multicast_logging(0); + gwlan_logging.is_flush_complete = false; + clear_bit(HOST_LOG_DRIVER_MSG, &gwlan_logging.eventFlag); + clear_bit(HOST_LOG_PER_PKT_STATS, &gwlan_logging.eventFlag); + clear_bit(HOST_LOG_FW_FLUSH_COMPLETE, &gwlan_logging.eventFlag); + wake_up_interruptible(&gwlan_logging.wait_queue); + wait_for_completion(&gwlan_logging.shutdown_comp); + + spin_lock_irqsave(&gwlan_logging.spin_lock, irq_flag); + gwlan_logging.pcur_node = NULL; + spin_unlock_irqrestore(&gwlan_logging.spin_lock, irq_flag); + vfree(gplog_msg); + gplog_msg = NULL; + + spin_lock_irqsave(&gwlan_logging.pkt_stats_lock, irq_flag); + gwlan_logging.pkt_stats_pcur_node = NULL; + gwlan_logging.pkt_stats_msg_idx = 0; + gwlan_logging.pkt_stat_drop_cnt = 0; + for (i = 0; i < MAX_PKTSTATS_BUFF; i++) { + if (gpkt_stats_buffers[i].skb) + dev_kfree_skb(gpkt_stats_buffers[i].skb); + } + spin_unlock_irqrestore(&gwlan_logging.pkt_stats_lock, irq_flag); + + vfree(gpkt_stats_buffers); + gpkt_stats_buffers = NULL; + + return 0; +} + +int wlan_logging_sock_init_svc(void) +{ + spin_lock_init(&gwlan_logging.spin_lock); + spin_lock_init(&gwlan_logging.pkt_stats_lock); + gapp_pid = INVALID_PID; + gwlan_logging.pcur_node = NULL; + gwlan_logging.pkt_stats_pcur_node = NULL; + + return 0; +} + +int wlan_logging_sock_deinit_svc(void) +{ + gwlan_logging.pcur_node = NULL; + gwlan_logging.pkt_stats_pcur_node = NULL; + gapp_pid = INVALID_PID; + + return 0; +} + +/** + * wlan_logging_set_per_pkt_stats() - This function triggers per packet logging + * + * This function is used to send signal to the logger thread for logging per + * packet stats + * + * Return: None + * + */ +void wlan_logging_set_per_pkt_stats(void) +{ + if (gwlan_logging.is_active == false) + return; + + set_bit(HOST_LOG_PER_PKT_STATS, &gwlan_logging.eventFlag); + wake_up_interruptible(&gwlan_logging.wait_queue); +} + +/** + * wlan_logging_set_log_level() - Set the logging level + * + * This function is used to set the logging level of host debug messages + * + * Return: None + */ +void wlan_logging_set_log_level(void) +{ + set_default_logtoapp_log_level(); +} + +/* + * wlan_logging_set_fw_flush_complete() - FW log flush completion + * + * This function is used to send signal to the logger thread to indicate + * that the flushing of FW logs is complete by the FW + * + * Return: None + * + */ +void wlan_logging_set_fw_flush_complete(void) +{ + if (gwlan_logging.is_active == false || + !cds_is_fatal_event_enabled()) + return; + + set_bit(HOST_LOG_FW_FLUSH_COMPLETE, &gwlan_logging.eventFlag); + wake_up_interruptible(&gwlan_logging.wait_queue); +} + +/** + * wlan_flush_host_logs_for_fatal() - Flush host logs + * + * This function is used to send signal to the logger thread to + * Flush the host logs + * + * Return: None + */ +void wlan_flush_host_logs_for_fatal(void) +{ + unsigned long flags; + + if (cds_is_log_report_in_progress()) { + pr_info("%s:flush all host logs Setting HOST_LOG_POST_MASK\n", + __func__); + spin_lock_irqsave(&gwlan_logging.spin_lock, flags); + wlan_queue_logmsg_for_app(); + spin_unlock_irqrestore(&gwlan_logging.spin_lock, flags); + set_bit(HOST_LOG_DRIVER_MSG, &gwlan_logging.eventFlag); + wake_up_interruptible(&gwlan_logging.wait_queue); + } +} + +/** + * wlan_get_pkt_stats_free_node() - Get the free node for pkt stats + * + * This function is used to get the free node for pkt stats from + * free list/filles list + * + * Return: int + * + */ +static int wlan_get_pkt_stats_free_node(void) +{ + int ret = 0; + + list_add_tail(&gwlan_logging.pkt_stats_pcur_node->node, + &gwlan_logging.pkt_stat_filled_list); + + if (!list_empty(&gwlan_logging.pkt_stat_free_list)) { + /* Get buffer from free list */ + gwlan_logging.pkt_stats_pcur_node = + (struct pkt_stats_msg *)(gwlan_logging.pkt_stat_free_list.next); + list_del_init(gwlan_logging.pkt_stat_free_list.next); + } else if (!list_empty(&gwlan_logging.pkt_stat_filled_list)) { + /* Get buffer from filled list. This condition will drop the + * packet from being indicated to app + */ + gwlan_logging.pkt_stats_pcur_node = + (struct pkt_stats_msg *) + (gwlan_logging.pkt_stat_filled_list.next); + ++gwlan_logging.pkt_stat_drop_cnt; + /* print every 64th drop count */ + if (cds_is_multicast_logging() && + (!(gwlan_logging.pkt_stat_drop_cnt % 0x40))) { + pr_err("%s: drop_count = %u\n", + __func__, gwlan_logging.pkt_stat_drop_cnt); + } + list_del_init(gwlan_logging.pkt_stat_filled_list.next); + ret = 1; + } + + /* Reset the skb values, essential if dequeued from filled list */ + skb_trim(gwlan_logging.pkt_stats_pcur_node->skb, 0); + return ret; +} + +/** + * wlan_pkt_stats_to_logger_thread() - Add the pkt stats to SKB + * @pl_hdr: Pointer to pl_hdr + * @pkt_dump: Pointer to pkt_dump + * @data: Pointer to data + * + * This function adds the pktstats hdr and data to current + * skb node of free list. + * + * Return: None + */ +void wlan_pkt_stats_to_logger_thread(void *pl_hdr, void *pkt_dump, void *data) +{ + struct ath_pktlog_hdr *pktlog_hdr; + struct packet_dump *pkt_stats_dump; + int total_stats_len = 0; + bool wake_up_thread = false; + unsigned long flags; + struct sk_buff *ptr; + int hdr_size; + + pktlog_hdr = (struct ath_pktlog_hdr *)pl_hdr; + + if (pktlog_hdr == NULL) { + pr_err("%s : Invalid pkt_stats_header\n", __func__); + return; + } + + pkt_stats_dump = (struct packet_dump *)pkt_dump; + total_stats_len = sizeof(struct ath_pktlog_hdr) + + pktlog_hdr->size; + + spin_lock_irqsave(&gwlan_logging.pkt_stats_lock, flags); + + if (!gwlan_logging.pkt_stats_pcur_node || (NULL == pkt_stats_dump)) { + spin_unlock_irqrestore(&gwlan_logging.pkt_stats_lock, flags); + return; + } + + /* Check if we can accommodate more log into current node/buffer */ + hdr_size = sizeof(struct host_log_pktlog_info) + + sizeof(tAniNlHdr); + if ((total_stats_len + hdr_size) >= + skb_tailroom(gwlan_logging.pkt_stats_pcur_node->skb)) { + wake_up_thread = true; + wlan_get_pkt_stats_free_node(); + } + + ptr = gwlan_logging.pkt_stats_pcur_node->skb; + qdf_mem_copy(skb_put(ptr, + sizeof(struct ath_pktlog_hdr)), + pktlog_hdr, + sizeof(struct ath_pktlog_hdr)); + + if (pkt_stats_dump) { + qdf_mem_copy(skb_put(ptr, + sizeof(struct packet_dump)), + pkt_stats_dump, + sizeof(struct packet_dump)); + pktlog_hdr->size -= sizeof(struct packet_dump); + } + + if (data) + qdf_mem_copy(skb_put(ptr, + pktlog_hdr->size), + data, pktlog_hdr->size); + + if (pkt_stats_dump->type == STOP_MONITOR) { + wake_up_thread = true; + wlan_get_pkt_stats_free_node(); + } + + spin_unlock_irqrestore(&gwlan_logging.pkt_stats_lock, flags); + + /* Wakeup logger thread */ + if (true == wake_up_thread) { + set_bit(HOST_LOG_PER_PKT_STATS, &gwlan_logging.eventFlag); + wake_up_interruptible(&gwlan_logging.wait_queue); + } +} + +/** + * driver_hal_status_map() - maps driver to hal + * status + * @status: status to be mapped + * + * This function is used to map driver to hal status + * + * Return: None + * + */ +static void driver_hal_status_map(uint8_t *status) +{ + switch (*status) { + case tx_status_ok: + *status = TX_PKT_FATE_ACKED; + break; + case tx_status_discard: + *status = TX_PKT_FATE_DRV_DROP_OTHER; + break; + case tx_status_no_ack: + *status = TX_PKT_FATE_SENT; + break; + case tx_status_download_fail: + *status = TX_PKT_FATE_FW_QUEUED; + break; + default: + *status = TX_PKT_FATE_DRV_DROP_OTHER; + break; + } +} + + +/* + * send_packetdump() - send packet dump + * @netbuf: netbuf + * @status: status of tx packet + * @vdev_id: virtual device id + * @type: type of packet + * + * This function is used to send packet dump to HAL layer + * using wlan_pkt_stats_to_logger_thread + * + * Return: None + * + */ +static void send_packetdump(qdf_nbuf_t netbuf, uint8_t status, + uint8_t vdev_id, uint8_t type) +{ + struct ath_pktlog_hdr pktlog_hdr = {0}; + struct packet_dump pd_hdr = {0}; + hdd_context_t *hdd_ctx; + hdd_adapter_t *adapter; + v_CONTEXT_t vos_ctx; + + vos_ctx = cds_get_global_context(); + if (!vos_ctx) + return; + + hdd_ctx = (hdd_context_t *)cds_get_context(QDF_MODULE_ID_HDD); + if (!hdd_ctx) + return; + + adapter = hdd_get_adapter_by_vdev(hdd_ctx, vdev_id); + if (!adapter) + return; + + /* Send packet dump only for STA interface */ + if (adapter->device_mode != QDF_STA_MODE) + return; + +#if defined(HELIUMPLUS) + pktlog_hdr.flags |= PKTLOG_HDR_SIZE_16; +#endif + + pktlog_hdr.log_type = PKTLOG_TYPE_PKT_DUMP; + pktlog_hdr.size = sizeof(pd_hdr) + netbuf->len; + + pd_hdr.status = status; + pd_hdr.type = type; + pd_hdr.driver_ts = qdf_get_monotonic_boottime(); + + if ((type == TX_MGMT_PKT) || (type == TX_DATA_PKT)) + gtx_count++; + else if ((type == RX_MGMT_PKT) || (type == RX_DATA_PKT)) + grx_count++; + + wlan_pkt_stats_to_logger_thread(&pktlog_hdr, &pd_hdr, netbuf->data); +} + + +/* + * send_packetdump_monitor() - sends start/stop packet dump indication + * @type: type of packet + * + * This function is used to indicate HAL layer to start/stop monitoring + * of packets + * + * Return: None + * + */ +static void send_packetdump_monitor(uint8_t type) +{ + struct ath_pktlog_hdr pktlog_hdr = {0}; + struct packet_dump pd_hdr = {0}; + +#if defined(HELIUMPLUS) + pktlog_hdr.flags |= PKTLOG_HDR_SIZE_16; +#endif + + pktlog_hdr.log_type = PKTLOG_TYPE_PKT_DUMP; + pktlog_hdr.size = sizeof(pd_hdr); + + pd_hdr.type = type; + + LOGGING_TRACE(QDF_TRACE_LEVEL_INFO, + "fate Tx-Rx %s: type: %d", __func__, type); + + wlan_pkt_stats_to_logger_thread(&pktlog_hdr, &pd_hdr, NULL); +} + +/** + * wlan_deregister_txrx_packetdump() - tx/rx packet dump + * deregistration + * + * This function is used to deregister tx/rx packet dump callbacks + * with ol, pe and htt layers + * + * Return: None + * + */ +void wlan_deregister_txrx_packetdump(void) +{ + if (gtx_count || grx_count) { + ol_deregister_packetdump_callback(); + wma_deregister_packetdump_callback(); + send_packetdump_monitor(STOP_MONITOR); + csr_packetdump_timer_stop(); + + gtx_count = 0; + grx_count = 0; + } else + LOGGING_TRACE(QDF_TRACE_LEVEL_INFO, + "%s: deregistered packetdump already", __func__); +} + +/* + * check_txrx_packetdump_count() - function to check + * tx/rx packet dump global counts + * + * This function is used to check global counts of tx/rx + * packet dump functionality. + * + * Return: 1 if either gtx_count or grx_count reached 32 + * 0 otherwise + * + */ +static bool check_txrx_packetdump_count(void) +{ + if (gtx_count == MAX_NUM_PKT_LOG || + grx_count == MAX_NUM_PKT_LOG) { + LOGGING_TRACE(QDF_TRACE_LEVEL_INFO, + "%s gtx_count: %d grx_count: %d deregister packetdump", + __func__, gtx_count, grx_count); + wlan_deregister_txrx_packetdump(); + return 1; + } + return 0; +} + +/* + * tx_packetdump_cb() - tx packet dump callback + * @netbuf: netbuf + * @status: status of tx packet + * @vdev_id: virtual device id + * @type: packet type + * + * This function is used to send tx packet dump to HAL layer + * and deregister packet dump callbacks + * + * Return: None + * + */ +static void tx_packetdump_cb(qdf_nbuf_t netbuf, uint8_t status, + uint8_t vdev_id, uint8_t type) +{ + bool temp; + + temp = check_txrx_packetdump_count(); + if (temp) + return; + + driver_hal_status_map(&status); + send_packetdump(netbuf, status, vdev_id, type); +} + + +/* + * rx_packetdump_cb() - rx packet dump callback + * @netbuf: netbuf + * @status: status of rx packet + * @vdev_id: virtual device id + * @type: packet type + * + * This function is used to send rx packet dump to HAL layer + * and deregister packet dump callbacks + * + * Return: None + * + */ +static void rx_packetdump_cb(qdf_nbuf_t netbuf, uint8_t status, + uint8_t vdev_id, uint8_t type) +{ + bool temp; + + temp = check_txrx_packetdump_count(); + if (temp) + return; + + send_packetdump(netbuf, status, vdev_id, type); +} + + +/** + * wlan_register_txrx_packetdump() - tx/rx packet dump + * registration + * + * This function is used to register tx/rx packet dump callbacks + * with ol, pe and htt layers + * + * Return: None + * + */ +void wlan_register_txrx_packetdump(void) +{ + ol_register_packetdump_callback(tx_packetdump_cb, + rx_packetdump_cb); + wma_register_packetdump_callback(tx_packetdump_cb, + rx_packetdump_cb); + send_packetdump_monitor(START_MONITOR); + + gtx_count = 0; + grx_count = 0; +} + +#endif /* WLAN_LOGGING_SOCK_SVC_ENABLE */ diff --git a/drivers/staging/qcacld-3.0/core/utils/nlink/inc/wlan_nlink_common.h b/drivers/staging/qcacld-3.0/core/utils/nlink/inc/wlan_nlink_common.h new file mode 100644 index 0000000000000000000000000000000000000000..ad531e1e96f54318565149e6a07ab67867287196 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/utils/nlink/inc/wlan_nlink_common.h @@ -0,0 +1,245 @@ +/* + * Copyright (c) 2014-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/*=========================================================================== + \file wlan_nlink_common.h + + Exports and types for the Netlink Service interface. This header file contains + message types and definitions that is shared between the user space service + (e.g. logging service) and WLAN kernel module. + + ===========================================================================*/ + +#ifndef WLAN_NLINK_COMMON_H__ +#define WLAN_NLINK_COMMON_H__ + +#include + +#ifdef __KERNEL__ +#include +#else +#include +#endif + +/*--------------------------------------------------------------------------- + * External Functions + *-------------------------------------------------------------------------*/ + +/*--------------------------------------------------------------------------- + * Preprocessor Definitions and Constants + *-------------------------------------------------------------------------*/ +#define WLAN_NL_MAX_PAYLOAD 256 /* maximum size for netlink message */ +#define WLAN_NLINK_PROTO_FAMILY NETLINK_USERSOCK +#define WLAN_NLINK_MCAST_GRP_ID 0x01 + +/*--------------------------------------------------------------------------- + * Type Declarations + *-------------------------------------------------------------------------*/ + +/* + * The following enum defines the target service within WLAN driver for which the + * message is intended for. Each service along with its counterpart + * in the user space, define a set of messages they recognize. + * Each of this message will have an header of type tAniMsgHdr defined below. + * Each Netlink message to/from a kernel module will contain only one + * message which is preceded by a tAniMsgHdr. The maximun size (in bytes) of + * a netlink message is assumed to be MAX_PAYLOAD bytes. + * + * +------------+-------+----------+----------+ + * |Netlink hdr | Align |tAniMsgHdr| msg body | + * +------------+-------+----------|----------+ + */ + +/* Message Types */ +#define WLAN_SVC_FW_CRASHED_IND 0x100 +#define WLAN_SVC_LTE_COEX_IND 0x101 +#define WLAN_SVC_WLAN_AUTO_SHUTDOWN_IND 0x102 +#define WLAN_SVC_DFS_CAC_START_IND 0x103 +#define WLAN_SVC_DFS_CAC_END_IND 0x104 +#define WLAN_SVC_DFS_RADAR_DETECT_IND 0x105 +#define WLAN_SVC_WLAN_STATUS_IND 0x106 +#define WLAN_SVC_WLAN_VERSION_IND 0x107 +#define WLAN_SVC_DFS_ALL_CHANNEL_UNAVAIL_IND 0x108 +#define WLAN_SVC_WLAN_TP_IND 0x109 +#define WLAN_SVC_RPS_ENABLE_IND 0x10A +#define WLAN_SVC_WLAN_TP_TX_IND 0x10B +#define WLAN_SVC_WLAN_AUTO_SHUTDOWN_CANCEL_IND 0x10C +#define WLAN_SVC_WLAN_RADIO_INDEX 0x10D +#define WLAN_SVC_FW_SHUTDOWN_IND 0x10E +#define WLAN_SVC_CORE_MINFREQ 0x10F +#define WLAN_SVC_MAX_SSID_LEN 32 +#define WLAN_SVC_MAX_BSSID_LEN 6 +#define WLAN_SVC_MAX_STR_LEN 16 +#define WLAN_SVC_MAX_NUM_CHAN 128 +#define WLAN_SVC_COUNTRY_CODE_LEN 3 + +#define ANI_NL_MSG_BASE 0x10 /* Some arbitrary base */ + +typedef enum eAniNlModuleTypes { + ANI_NL_MSG_PUMAC = ANI_NL_MSG_BASE + 0x01, /* PTT Socket App */ + ANI_NL_MSG_PTT = ANI_NL_MSG_BASE + 0x07, /* Quarky GUI */ + WLAN_NL_MSG_OEM = ANI_NL_MSG_BASE + 0x09, + WLAN_NL_MSG_SVC, + WLAN_NL_MSG_CNSS_DIAG = ANI_NL_MSG_BASE + 0x0B, /* Value needs to be 27 */ + ANI_NL_MSG_LOG, + ANI_NL_MSG_MAX +} tAniNlModTypes, tWlanNlModTypes; + +#define WLAN_NL_MSG_BASE ANI_NL_MSG_BASE +#define WLAN_NL_MSG_MAX ANI_NL_MSG_MAX + +/* All Netlink messages must contain this header */ +typedef struct sAniHdr { + unsigned short type; + unsigned short length; +} tAniHdr, tAniMsgHdr; + +typedef struct sAniNlMsg { + struct nlmsghdr nlh; /* Netlink Header */ + int radio; /* unit number of the radio */ + tAniHdr wmsg; /* Airgo Message Header */ +} tAniNlHdr; + +struct radio_index_tlv { + unsigned short type; + unsigned short length; + int radio; +}; + +struct wlan_status_data { + uint8_t lpss_support; + uint8_t is_on; + uint8_t vdev_id; + uint8_t is_connected; + int8_t rssi; + uint8_t ssid_len; + uint8_t country_code[WLAN_SVC_COUNTRY_CODE_LEN]; + uint32_t vdev_mode; + uint32_t freq; + uint32_t numChannels; + uint8_t channel_list[WLAN_SVC_MAX_NUM_CHAN]; + uint8_t ssid[WLAN_SVC_MAX_SSID_LEN]; + uint8_t bssid[WLAN_SVC_MAX_BSSID_LEN]; +}; + +struct wlan_version_data { + uint32_t chip_id; + char chip_name[WLAN_SVC_MAX_STR_LEN]; + char chip_from[WLAN_SVC_MAX_STR_LEN]; + char host_version[WLAN_SVC_MAX_STR_LEN]; + char fw_version[WLAN_SVC_MAX_STR_LEN]; +}; + +struct wlan_dfs_info { + uint16_t channel; + uint8_t country_code[WLAN_SVC_COUNTRY_CODE_LEN]; +}; + +/* + * Maximim number of queues supported by WLAN driver. Setting an upper + * limit. Actual number of queues may be smaller than this value. + */ +#define WLAN_SVC_IFACE_NUM_QUEUES 6 + +/** + * struct wlan_rps_data - structure to send RPS info to cnss-daemon + * @ifname: interface name for which the RPS data belongs to + * @num_queues: number of rx queues for which RPS data is being sent + * @cpu_map_list: array of cpu maps for different rx queues supported by + * the wlan driver + * + * The structure specifies the format of data exchanged between wlan + * driver and cnss-daemon. On receipt of the data, cnss-daemon is expected + * to apply the 'cpu_map' for each rx queue belonging to the interface 'ifname' + */ +struct wlan_rps_data { + char ifname[IFNAMSIZ]; + uint16_t num_queues; + uint16_t cpu_map_list[WLAN_SVC_IFACE_NUM_QUEUES]; +}; + +/** + * enum wlan_tp_level - indicates wlan throughput level + * @WLAN_SVC_TP_NONE: used for initialization + * @WLAN_SVC_TP_LOW: used to identify low throughput level + * @WLAN_SVC_TP_MEDIUM: used to identify medium throughput level + * @WLAN_SVC_TP_HIGH: used to identify high throughput level + * + * The different throughput levels are determined on the basis of # of tx and + * rx packets and other threshold values. For example, if the # of total + * packets sent or received by the driver is greater than 500 in the last 100ms + * , the driver has a high throughput requirement. The driver may tweak certain + * system parameters based on the throughput level. + */ +enum wlan_tp_level { + WLAN_SVC_TP_NONE, + WLAN_SVC_TP_LOW, + WLAN_SVC_TP_MEDIUM, + WLAN_SVC_TP_HIGH, +}; + +/** + * struct wlan_core_minfreq - msg to [re]set the min freq of a set of cores + * @magic: signature token: 0xBABA + * @reserved: unused for now + * @coremask: bitmap of cores (16 bits) bit0=CORE0, bit1=CORE1, ... + * coremask is ONLY valid for set command + * valid values: 0xf0, or 0x0f + * @freq: frequency in KH + * > 0: "set to the given frequency" + * == 0: "free; remove the lock" + * + * Msg structure passed by the driver to cnss-daemon. + * + * Semantical Alert: + * There can be only one outstanding lock, even for different masks. + */ +#define WLAN_CORE_MINFREQ_MAGIC 0xBABA +struct wlan_core_minfreq { + uint16_t magic; + uint16_t reserved; + uint16_t coremask; + uint16_t freq; +}; + +/* Indication to enable TCP delayed ack in TPUT indication */ +#define TCP_DEL_ACK_IND (1 << 0) +/* Indication to enable TCP advance window scaling in TPUT indication */ +#define TCP_ADV_WIN_SCL (1 << 1) + +/** + * struct wlan_rx_tp_data - msg to TCP delayed ack and advance window scaling + * @level: Throughput level. + * @rx_tp_flags: Bit map of flags, for which this indcation will take + * effect, bit map for TCP_ADV_WIN_SCL and TCP_DEL_ACK_IND. + */ +struct wlan_rx_tp_data { + enum wlan_tp_level level; + uint16_t rx_tp_flags; +}; + +#endif /* WLAN_NLINK_COMMON_H__ */ diff --git a/drivers/staging/qcacld-3.0/core/utils/nlink/inc/wlan_nlink_srv.h b/drivers/staging/qcacld-3.0/core/utils/nlink/inc/wlan_nlink_srv.h new file mode 100644 index 0000000000000000000000000000000000000000..b455b64d583f062a5954a889f6bba2635887f1fa --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/utils/nlink/inc/wlan_nlink_srv.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/****************************************************************************** +* wlan_nlink_srv.h +* +* wlan_nlink_srv is used to RX/TX Netlink messages from user space to kernel +* modules and vice versa. Kernel modules must register a message handler for a +* message type so that the wlan_nlink_srv can invoke the corresponding msg handler +* whenever a Netlink message of a particular type has been received from an +* application. In the opposite direction, wlan_nlink_srv provides a mechanism +* which kernel modules can use to send Netlink messages to applications. +* +******************************************************************************/ + +#ifndef WLAN_NLINK_SRV_H +#define WLAN_NLINK_SRV_H + +#include +#include +#include + +#define INVALID_PID -1 +#define NLINK_MAX_CALLBACKS (WLAN_NL_MSG_MAX - WLAN_NL_MSG_BASE) + +typedef int (*nl_srv_msg_callback)(struct sk_buff *skb); + +int nl_srv_init(void *wiphy); +void nl_srv_exit(void); +int nl_srv_register(tWlanNlModTypes msg_type, nl_srv_msg_callback msg_handler); +int nl_srv_unregister(tWlanNlModTypes msg_type, + nl_srv_msg_callback msg_handler); +int nl_srv_ucast(struct sk_buff *skb, int dst_pid, int flag); +int nl_srv_bcast(struct sk_buff *skb); +int nl_srv_is_initialized(void); +#endif diff --git a/drivers/staging/qcacld-3.0/core/utils/nlink/src/wlan_nlink_srv.c b/drivers/staging/qcacld-3.0/core/utils/nlink/src/wlan_nlink_srv.c new file mode 100644 index 0000000000000000000000000000000000000000..192f5a95927231b1d247cde538e62111094dbdc0 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/utils/nlink/src/wlan_nlink_srv.c @@ -0,0 +1,553 @@ +/* + * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/****************************************************************************** +* wlan_nlink_srv.c +* +* This file contains the definitions specific to the wlan_nlink_srv +* +******************************************************************************/ +/* + * If MULTI_IF_NAME is not defined, then this is the primary instance of the + * driver and the diagnostics netlink socket will be available. If + * MULTI_IF_NAME is defined then this is not the primary instance of the driver + * and the diagnotics netlink socket will not be available since this + * diagnostics netlink socket can only be exposed by one instance of the driver. + */ +#ifndef MULTI_IF_NAME + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(CONFIG_CNSS_LOGGER) + +#include + +static int radio_idx = -EINVAL; +static void *wiphy_ptr; +static bool logger_initialized; + +/** + * nl_srv_init() - wrapper function to register to cnss_logger + * @wiphy: the pointer to the wiphy structure + * + * The netlink socket is no longer initialized in the driver itself, instead + * will be initialized in the cnss_logger module, the driver should register + * itself to cnss_logger module to get the radio_index for all the netlink + * operation. (cfg80211 vendor command is using different netlink socket). + * + * The cnss_logger_device_register() use to register the driver with the + * wiphy structure and the module name (debug purpose) and then return the + * radio_index depending on the availibility. + * + * Return: radio index for success and -EINVAL for failure + */ +int nl_srv_init(void *wiphy) +{ + if (logger_initialized) + goto initialized; + + wiphy_ptr = wiphy; + radio_idx = cnss_logger_device_register(wiphy, THIS_MODULE->name); + QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR, + "%s: radio_index: %d, wiphy_ptr: %p", + __func__, radio_idx, wiphy_ptr); + + if (radio_idx >= 0) + logger_initialized = true; + +initialized: + return radio_idx; +} + +/** + * nl_srv_exit() - wrapper function to unregister from cnss_logger + * + * The cnss_logger_device_unregister() use to unregister the driver with + * the radio_index assigned and wiphy structure from cnss_logger. + * + * Return: None + */ +void nl_srv_exit(void) +{ + if (logger_initialized) { + cnss_logger_device_unregister(radio_idx, wiphy_ptr); + radio_idx = -EINVAL; + wiphy_ptr = NULL; + logger_initialized = false; + } +} + +/** + * nl_srv_ucast() - wrapper function to do unicast tx through cnss_logger + * @skb: the socket buffer to send + * @dst_pid: the port id + * @flag: the blocking or nonblocking flag + * + * The nl_srv_is_initialized() is used to do sanity check if the netlink + * service is ready, e.g if the radio_index is assigned properly, if not + * the driver should take the responsibility to free the skb. + * + * The cnss_logger_nl_ucast() use the same parameters to send the socket + * buffers. + * + * Return: the error of the transmission status + */ +int nl_srv_ucast(struct sk_buff *skb, int dst_pid, int flag) +{ + int err = -EINVAL; + + /* sender's pid */ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 7, 0)) + NETLINK_CB(skb).pid = 0; +#else + NETLINK_CB(skb).portid = 0; +#endif + /* not multicast */ + NETLINK_CB(skb).dst_group = 0; + + if (nl_srv_is_initialized() == 0) { + err = cnss_logger_nl_ucast(skb, dst_pid, flag); + if (err < 0) + QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_WARN, + "NLINK: netlink_unicast to pid[%d] failed, ret[%d]", + dst_pid, err); + } else + dev_kfree_skb(skb); + return err; +} + +/** + * nl_srv_bcast() - wrapper function to do broadcast tx through cnss_logger + * @skb: the socket buffer to send + * + * The cnss_logger_nl_bcast() is used to transmit the socket buffer. + * + * Return: status of transmission + */ +int nl_srv_bcast(struct sk_buff *skb) +{ + int err = -EINVAL; + int flags = GFP_KERNEL; + + if (in_interrupt() || irqs_disabled() || in_atomic()) + flags = GFP_ATOMIC; + + /* sender's pid */ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 7, 0)) + NETLINK_CB(skb).pid = 0; +#else + NETLINK_CB(skb).portid = 0; +#endif + /* destination group */ + NETLINK_CB(skb).dst_group = WLAN_NLINK_MCAST_GRP_ID; + + if (nl_srv_is_initialized() == 0) { + err = cnss_logger_nl_bcast(skb, WLAN_NLINK_MCAST_GRP_ID, flags); + if ((err < 0) && (err != -ESRCH)) { + QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_WARN, + "NLINK: netlink_broadcast failed err = %d", + err); + dev_kfree_skb(skb); + } + } else + dev_kfree_skb(skb); + return err; +} + +/** + * nl_srv_unregister() - wrapper function to unregister event to cnss_logger + * @msg_type: the message to unregister + * @msg_handler: the message handler + * + * The cnss_logger_event_unregister() is used to unregister the message and + * message handler. + * + * Return: 0 if successfully unregister, otherwise proper error code + */ +int nl_srv_unregister(tWlanNlModTypes msg_type, nl_srv_msg_callback msg_handler) +{ + int ret = -EINVAL; + + if (nl_srv_is_initialized() != 0) + return ret; + + if ((msg_type >= WLAN_NL_MSG_BASE) && (msg_type < WLAN_NL_MSG_MAX) && + msg_handler != NULL) { + ret = cnss_logger_event_unregister(radio_idx, msg_type, + msg_handler); + } else { + QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR, + "NLINK: nl_srv_unregister failed for msg_type %d", + msg_type); + ret = -EINVAL; + } + + return ret; +} + +/** + * nl_srv_register() - wrapper function to register event to cnss_logger + * @msg_type: the message to register + * @msg_handler: the message handler + * + * The cnss_logger_event_register() is used to register the message and + * message handler. + * + * Return: 0 if successfully register, otherwise proper error code + */ +int nl_srv_register(tWlanNlModTypes msg_type, nl_srv_msg_callback msg_handler) +{ + int ret = -EINVAL; + + if (nl_srv_is_initialized() != 0) + return ret; + + if ((msg_type >= WLAN_NL_MSG_BASE) && (msg_type < WLAN_NL_MSG_MAX) && + msg_handler != NULL) { + ret = cnss_logger_event_register(radio_idx, msg_type, + msg_handler); + } else { + QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR, + "NLINK: nl_srv_register failed for msg_type %d", + msg_type); + ret = -EINVAL; + } + + return ret; +} + +/** + * nl_srv_is_initialized() - check if netlink service is initialized + * + * Return: 0 if it is initialized, otherwise error code + */ +inline int nl_srv_is_initialized(void) +{ + if (logger_initialized) + return 0; + else + return -EPERM; +} + +#else + + +/* Global variables */ +static DEFINE_MUTEX(nl_srv_sem); +static struct sock *nl_srv_sock; +static nl_srv_msg_callback nl_srv_msg_handler[NLINK_MAX_CALLBACKS]; + +/* Forward declaration */ +static void nl_srv_rcv(struct sk_buff *sk); +static void nl_srv_rcv_skb(struct sk_buff *skb); +static void nl_srv_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh); + +/* + * Initialize the netlink service. + * Netlink service is usable after this. + */ +int nl_srv_init(void *wiphy) +{ + int retcode = 0; + struct netlink_kernel_cfg cfg = { + .groups = WLAN_NLINK_MCAST_GRP_ID, + .input = nl_srv_rcv + }; + + nl_srv_sock = netlink_kernel_create(&init_net, WLAN_NLINK_PROTO_FAMILY, + &cfg); + + if (nl_srv_sock != NULL) { + memset(nl_srv_msg_handler, 0, sizeof(nl_srv_msg_handler)); + } else { + QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR, + "NLINK: netlink_kernel_create failed"); + retcode = -ECONNREFUSED; + } + return retcode; +} + +/* + * Deinit the netlink service. + * Netlink service is unusable after this. + */ +void nl_srv_exit(void) +{ + if (nl_srv_is_initialized() == 0) + netlink_kernel_release(nl_srv_sock); + + nl_srv_sock = NULL; +} + +/* + * Register a message handler for a specified module. + * Each module (e.g. WLAN_NL_MSG_BTC )will register a + * handler to handle messages addressed to it. + */ +int nl_srv_register(tWlanNlModTypes msg_type, nl_srv_msg_callback msg_handler) +{ + int retcode = 0; + + if ((msg_type >= WLAN_NL_MSG_BASE) && (msg_type < WLAN_NL_MSG_MAX) && + msg_handler != NULL) { + nl_srv_msg_handler[msg_type - WLAN_NL_MSG_BASE] = msg_handler; + } else { + QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_WARN, + "NLINK: nl_srv_register failed for msg_type %d", + msg_type); + retcode = -EINVAL; + } + + return retcode; +} + +/* + * Unregister the message handler for a specified module. + */ +int nl_srv_unregister(tWlanNlModTypes msg_type, nl_srv_msg_callback msg_handler) +{ + int retcode = 0; + + if ((msg_type >= WLAN_NL_MSG_BASE) && (msg_type < WLAN_NL_MSG_MAX) && + (nl_srv_msg_handler[msg_type - WLAN_NL_MSG_BASE] == msg_handler)) { + nl_srv_msg_handler[msg_type - WLAN_NL_MSG_BASE] = NULL; + } else { + QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_WARN, + "NLINK: nl_srv_unregister failed for msg_type %d", + msg_type); + retcode = -EINVAL; + } + + return retcode; +} + +/* + * Unicast the message to the process in user space identfied + * by the dst-pid + */ +int nl_srv_ucast(struct sk_buff *skb, int dst_pid, int flag) +{ + int err = -EINVAL; + + NETLINK_CB(skb).portid = 0; /* sender's pid */ + NETLINK_CB(skb).dst_group = 0; /* not multicast */ + + if (nl_srv_sock) { + err = netlink_unicast(nl_srv_sock, skb, dst_pid, flag); + if (err < 0) { + QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_WARN, + "NLINK: netlink_unicast to pid[%d] failed, ret[%d]", + dst_pid, err); + } + } else + dev_kfree_skb(skb); + return err; +} + +/* + * Broadcast the message. Broadcast will return an error if + * there are no listeners + */ +int nl_srv_bcast(struct sk_buff *skb) +{ + int err = -EINVAL; + int flags = GFP_KERNEL; + + if (in_interrupt() || irqs_disabled() || in_atomic()) + flags = GFP_ATOMIC; + + NETLINK_CB(skb).portid = 0; /* sender's pid */ + NETLINK_CB(skb).dst_group = WLAN_NLINK_MCAST_GRP_ID; /* destination group */ + + if (nl_srv_sock) { + err = netlink_broadcast(nl_srv_sock, skb, 0, + WLAN_NLINK_MCAST_GRP_ID, flags); + if ((err < 0) && (err != -ESRCH)) { + QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_WARN, + "NLINK: netlink_broadcast failed err = %d", + err); + dev_kfree_skb(skb); + } + } else + dev_kfree_skb(skb); + return err; +} + +/* + * Processes the Netlink socket input queue. + * Dequeue skb's from the socket input queue and process + * all the netlink messages in that skb, before moving + * to the next skb. + */ +static void nl_srv_rcv(struct sk_buff *sk) +{ + mutex_lock(&nl_srv_sem); + nl_srv_rcv_skb(sk); + mutex_unlock(&nl_srv_sem); +} + +/* + * Each skb could contain multiple Netlink messages. Process all the + * messages in one skb and discard malformed skb's silently. + */ +static void nl_srv_rcv_skb(struct sk_buff *skb) +{ + struct nlmsghdr *nlh; + + while (skb->len >= NLMSG_SPACE(0)) { + u32 rlen; + + nlh = (struct nlmsghdr *)skb->data; + + if (nlh->nlmsg_len < sizeof(*nlh) || skb->len < nlh->nlmsg_len) { + QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_WARN, + "NLINK: Invalid " + "Netlink message: skb[%p], len[%d], nlhdr[%p], nlmsg_len[%d]", + skb, skb->len, nlh, nlh->nlmsg_len); + return; + } + + rlen = NLMSG_ALIGN(nlh->nlmsg_len); + if (rlen > skb->len) + rlen = skb->len; + nl_srv_rcv_msg(skb, nlh); + skb_pull(skb, rlen); + } +} + +/* + * Process a netlink message. + * Each netlink message will have a message of type tAniMsgHdr inside. + */ +static void nl_srv_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) +{ + int type; + + /* Only requests are handled by kernel now */ + if (!(nlh->nlmsg_flags & NLM_F_REQUEST)) { + QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_WARN, + "NLINK: Received Invalid NL Req type [%x]", + nlh->nlmsg_flags); + return; + } + + type = nlh->nlmsg_type; + + /* Unknown message */ + if (type < WLAN_NL_MSG_BASE || type >= WLAN_NL_MSG_MAX) { + QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_WARN, + "NLINK: Received Invalid NL Msg type [%x]", type); + return; + } + + /* + * All the messages must at least carry the tAniMsgHdr + * Drop any message with invalid length + */ + if (nlh->nlmsg_len < NLMSG_LENGTH(sizeof(tAniMsgHdr))) { + QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_WARN, + "NLINK: Received NL Msg with invalid len[%x]", + nlh->nlmsg_len); + return; + } + + /* turn type into dispatch table offset */ + type -= WLAN_NL_MSG_BASE; + + /* dispatch to handler */ + if (nl_srv_msg_handler[type] != NULL) { + (nl_srv_msg_handler[type])(skb); + } else { + QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO, + "NLINK: No handler for Netlink Msg [0x%X]", type); + } +} + +/** + * nl_srv_is_initialized() - This function is used check if the netlink + * service is initialized + * + * This function is used check if the netlink service is initialized + * + * Return: Return -EPERM if the service is not initialized + * + */ +int nl_srv_is_initialized(void) +{ + if (nl_srv_sock) + return 0; + + return -EPERM; +} +#endif +#else /* ifndef MULTI_IF_NAME */ + +#include + +int nl_srv_init(void *wiphy) +{ + return 0; +} + +void nl_srv_exit(void) +{ +} + +int nl_srv_register(tWlanNlModTypes msg_type, nl_srv_msg_callback msg_handler) +{ + return 0; +} + +int nl_srv_unregister(tWlanNlModTypes msg_type, nl_srv_msg_callback msg_handler) +{ + return 0; +} + +int nl_srv_ucast(struct sk_buff *skb, int dst_pid, int flag) +{ + return 0; +} + +int nl_srv_bcast(struct sk_buff *skb) +{ + return 0; +} + +int nl_srv_is_initialized(void) +{ + return 0; +} +#endif diff --git a/drivers/staging/qcacld-3.0/core/utils/pktlog/include/pktlog.h b/drivers/staging/qcacld-3.0/core/utils/pktlog/include/pktlog.h new file mode 100644 index 0000000000000000000000000000000000000000..cfbf221847a2c110c64aa56ae9b8656767ceb690 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/utils/pktlog/include/pktlog.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2013-2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef _PKTLOG_ +#define _PKTLOG_ +#ifndef REMOVE_PKT_LOG + +/** + * @typedef ol_pktlog_dev_handle + * @brief opaque handle for pktlog device object + */ +struct ol_pktlog_dev_t; +typedef struct ol_pktlog_dev_t *ol_pktlog_dev_handle; +#endif /* #ifndef REMOVE_PKT_LOG */ +#endif /* _PKTLOG_ */ diff --git a/drivers/staging/qcacld-3.0/core/utils/pktlog/include/pktlog_ac.h b/drivers/staging/qcacld-3.0/core/utils/pktlog/include/pktlog_ac.h new file mode 100644 index 0000000000000000000000000000000000000000..d4a074fd49f50bf0477ed41d9cea2cfdacec5548 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/utils/pktlog/include/pktlog_ac.h @@ -0,0 +1,190 @@ +/* + * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef _PKTLOG_AC_H_ +#define _PKTLOG_AC_H_ +#ifndef REMOVE_PKT_LOG + +#include "ol_if_athvar.h" +#include +#include +#include "osdep.h" +#include +#include +#include +#include "hif.h" + +#define NO_REG_FUNCS 4 + +/* Locking interface for pktlog */ +#define PKTLOG_LOCK_INIT(_pl_info) spin_lock_init(&(_pl_info)->log_lock) +#define PKTLOG_LOCK_DESTROY(_pl_info) +#define PKTLOG_LOCK(_pl_info) spin_lock(&(_pl_info)->log_lock) +#define PKTLOG_UNLOCK(_pl_info) spin_unlock(&(_pl_info)->log_lock) + +#define PKTLOG_MODE_SYSTEM 1 +#define PKTLOG_MODE_ADAPTER 2 + +/* + * The proc entry starts with magic number and version field which will be + * used by post processing scripts. These fields are not needed by applications + * that do not use these scripts. This is skipped using the offset value. + */ +#define PKTLOG_READ_OFFSET 8 + +/* Opaque softc */ +struct ol_ath_generic_softc_t; +typedef struct ol_ath_generic_softc_t *ol_ath_generic_softc_handle; +extern void pktlog_disable_adapter_logging(struct hif_opaque_softc *scn); +extern int pktlog_alloc_buf(struct hif_opaque_softc *scn); +extern void pktlog_release_buf(struct hif_opaque_softc *scn); + +ssize_t pktlog_read_proc_entry(char *buf, size_t nbytes, loff_t *ppos, + struct ath_pktlog_info *pl_info, bool *read_complete); +int pktlog_send_per_pkt_stats_to_user(void); +A_STATUS +wdi_pktlog_unsubscribe(struct ol_txrx_pdev_t *txrx_pdev, uint32_t log_state); + +struct ol_pl_arch_dep_funcs { + void (*pktlog_init)(struct hif_opaque_softc *scn); + int (*pktlog_enable)(struct hif_opaque_softc *scn, int32_t log_state, + bool ini, uint8_t user, + uint32_t is_iwpriv_command); + int (*pktlog_setsize)(struct hif_opaque_softc *scn, int32_t log_state); + int (*pktlog_disable)(struct hif_opaque_softc *scn); +}; + +struct ol_pl_os_dep_funcs { + int (*pktlog_attach)(struct hif_opaque_softc *scn); + void (*pktlog_detach)(struct hif_opaque_softc *scn); +}; + +struct ath_pktlog_wmi_params { + WMI_PKTLOG_EVENT pktlog_event; + WMI_CMD_ID cmd_id; + bool ini_triggered; + uint8_t user_triggered; +}; + +extern struct ol_pl_arch_dep_funcs ol_pl_funcs; +extern struct ol_pl_os_dep_funcs *g_ol_pl_os_dep_funcs; + +/* Pktlog handler to save the state of the pktlogs */ +struct ol_pktlog_dev_t { + struct ol_pl_arch_dep_funcs *pl_funcs; + struct ath_pktlog_info *pl_info; + ol_ath_generic_softc_handle scn; + char *name; + bool tgt_pktlog_alloced; + bool is_pktlog_cb_subscribed; + bool mt_pktlog_enabled; + uint32_t htc_err_cnt; + uint8_t htc_endpoint; + void *htc_pdev; + bool vendor_cmd_send; +}; + +#define PKTLOG_SYSCTL_SIZE 14 +#define PKTLOG_MAX_SEND_QUEUE_DEPTH 64 + +/* + * Linux specific pktlog state information + */ +struct ath_pktlog_info_lnx { + struct ath_pktlog_info info; + struct ctl_table sysctls[PKTLOG_SYSCTL_SIZE]; + struct proc_dir_entry *proc_entry; + struct ctl_table_header *sysctl_header; +}; + +#define PL_INFO_LNX(_pl_info) ((struct ath_pktlog_info_lnx *)(_pl_info)) + +extern struct ol_pktlog_dev_t ol_pl_dev; + +/* + * WDI related data and functions + * Callback function to the WDI events + */ +void pktlog_callback(void *pdev, enum WDI_EVENT event, void *log_data); + +void pktlog_init(struct hif_opaque_softc *scn); +int pktlog_enable(struct hif_opaque_softc *scn, int32_t log_state, + bool, uint8_t, uint32_t); +int pktlog_setsize(struct hif_opaque_softc *scn, int32_t log_state); +int pktlog_clearbuff(struct hif_opaque_softc *scn, bool clear_buff); +int pktlog_disable(struct hif_opaque_softc *scn); +int pktlogmod_init(void *context); +void pktlogmod_exit(void *context); +int pktlog_htc_attach(void); +void pktlog_process_fw_msg(uint32_t *msg_word); + +#define ol_pktlog_attach(_scn) \ + do { \ + if (g_ol_pl_os_dep_funcs) { \ + g_ol_pl_os_dep_funcs->pktlog_attach(_scn); \ + } \ + } while (0) + +#define ol_pktlog_detach(_scn) \ + do { \ + if (g_ol_pl_os_dep_funcs) { \ + g_ol_pl_os_dep_funcs->pktlog_detach(_scn); \ + } \ + } while (0) + +#else /* REMOVE_PKT_LOG */ +#define ol_pktlog_attach(_scn) ({ (void)_scn; }) +#define ol_pktlog_detach(_scn) ({ (void)_scn; }) +static inline void pktlog_init(struct hif_opaque_softc *scn) +{ + return; +} +static int pktlog_enable(struct hif_opaque_softc *scn, int32_t log_state, + bool ini, uint8_t user, uint32_t is_iwpriv_command) +{ + return 0; +} +static int pktlog_setsize(struct hif_opaque_softc *scn, int32_t log_state) +{ + return 0; +} +static int pktlog_clearbuff(struct hif_opaque_softc *scn, bool clear_buff) +{ + return 0; +} +static int pktlog_disable(struct hif_opaque_softc *scn) +{ + return 0; +} +static inline int pktlog_htc_attach(void) +{ + return 0; +} +static inline void pktlog_process_fw_msg(uint32_t *msg_word) +{ } +#endif /* REMOVE_PKT_LOG */ +#endif /* _PKTLOG_AC_H_ */ diff --git a/drivers/staging/qcacld-3.0/core/utils/pktlog/include/pktlog_ac_api.h b/drivers/staging/qcacld-3.0/core/utils/pktlog/include/pktlog_ac_api.h new file mode 100644 index 0000000000000000000000000000000000000000..4674c5fe4689597003d11b2c6a300df9104ffb3a --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/utils/pktlog/include/pktlog_ac_api.h @@ -0,0 +1,145 @@ +/* + * Copyright (c) 2012-2014, 2016-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * The file is used to define structures that are shared between + * kernel space and user space pktlog application. + */ + +#ifndef _PKTLOG_AC_API_ +#define _PKTLOG_AC_API_ +#ifndef REMOVE_PKT_LOG + +/** + * @typedef ol_pktlog_dev_handle + * @brief opaque handle for pktlog device object + */ +struct ol_pktlog_dev_t; +typedef struct ol_pktlog_dev_t *ol_pktlog_dev_handle; + +/** + * @typedef hif_opaque_softc_handle + * @brief opaque handle for hif_opaque_softc + */ +struct hif_opaque_softc; +typedef struct hif_opaque_softc *hif_opaque_softc_handle; + +/** + * @typedef net_device_handle + * @brief opaque handle linux phy device object + */ +struct net_device; +typedef struct net_device *net_device_handle; + +void ol_pl_set_name(hif_opaque_softc_handle scn, net_device_handle dev); + +void ol_pl_sethandle(ol_pktlog_dev_handle *pl_handle, + hif_opaque_softc_handle scn); + +/* Packet log state information */ +#ifndef _PKTLOG_INFO +#define _PKTLOG_INFO + +/** + * enum ath_pktlog_state - pktlog status + * @PKTLOG_OPR_IN_PROGRESS : pktlog command in progress + * @PKTLOG_OPR_IN_PROGRESS_READ_START: pktlog read is issued + * @PKTLOG_OPR_IN_PROGRESS_READ_START_PKTLOG_DISABLED: + * as part of pktlog read, pktlog is disabled + * @PKTLOG_OPR_IN_PROGRESS_READ_COMPLETE: + * as part of read, till pktlog read is complete + * @PKTLOG_OPR_IN_PROGRESS_CLEARBUFF_COMPLETE: + * as part of read, pktlog clear buffer is done + * @PKTLOG_OPR_NOT_IN_PROGRESS: no pktlog command in progress + */ +enum ath_pktlog_state { + PKTLOG_OPR_IN_PROGRESS = 0, + PKTLOG_OPR_IN_PROGRESS_READ_START, + PKTLOG_OPR_IN_PROGRESS_READ_START_PKTLOG_DISABLED, + PKTLOG_OPR_IN_PROGRESS_READ_COMPLETE, + PKTLOG_OPR_IN_PROGRESS_CLEARBUFF_COMPLETE, + PKTLOG_OPR_NOT_IN_PROGRESS +}; + +struct ath_pktlog_info { + struct ath_pktlog_buf *buf; + uint32_t log_state; + uint32_t saved_state; + uint32_t options; + /* Initial saved state: It will save the log state in pktlog + * open and used in pktlog release after + * pktlog read is complete. + */ + uint32_t init_saved_state; + enum ath_pktlog_state curr_pkt_state; + + /* Size of buffer in bytes */ + int32_t buf_size; + spinlock_t log_lock; + struct mutex pktlog_mutex; + + /* Threshold of TCP SACK packets for triggered stop */ + int sack_thr; + + /* # of tail packets to log after triggered stop */ + int tail_length; + + /* throuput threshold in bytes for triggered stop */ + uint32_t thruput_thresh; + + /* (aggregated or single) packet size in bytes */ + uint32_t pktlen; + + /* a temporary variable for counting TX throughput only */ + /* PER threshold for triggered stop, 10 for 10%, range [1, 99] */ + uint32_t per_thresh; + + /* Phyerr threshold for triggered stop */ + uint32_t phyerr_thresh; + + /* time period for counting trigger parameters, in milisecond */ + uint32_t trigger_interval; + uint32_t start_time_thruput; + uint32_t start_time_per; +}; +#endif /* _PKTLOG_INFO */ +#else /* REMOVE_PKT_LOG */ +typedef void *ol_pktlog_dev_handle; +#define ol_pl_sethandle(pl_handle, scn) \ + do { \ + (void)pl_handle; \ + (void)scn; \ + } while (0) + +#define ol_pl_set_name(scn, dev) \ + do { \ + (void)scn; \ + (void)dev; \ + } while (0) + +#endif /* REMOVE_PKT_LOG */ +#endif /* _PKTLOG_AC_API_ */ diff --git a/drivers/staging/qcacld-3.0/core/utils/pktlog/include/pktlog_ac_i.h b/drivers/staging/qcacld-3.0/core/utils/pktlog/include/pktlog_ac_i.h new file mode 100644 index 0000000000000000000000000000000000000000..15b83d35ce8ba9a5b71fc589aa4695de9385540b --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/utils/pktlog/include/pktlog_ac_i.h @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef _PKTLOG_AC_I_ +#define _PKTLOG_AC_I_ +#ifndef REMOVE_PKT_LOG + +#include +#include + +#ifdef FEATURE_PKTLOG +#define PKTLOG_DEFAULT_BUFSIZE (10 * 1024 * 1024) /* 10MB */ +#else +#define PKTLOG_DEFAULT_BUFSIZE (1 * 1024 * 1024) /* 1MB */ +#endif +#define PKTLOG_DEFAULT_SACK_THR 3 +#define PKTLOG_DEFAULT_TAIL_LENGTH 100 +#define PKTLOG_DEFAULT_THRUPUT_THRESH (64 * 1024) +#define PKTLOG_DEFAULT_PER_THRESH 30 +#define PKTLOG_DEFAULT_PHYERR_THRESH 300 +#define PKTLOG_DEFAULT_TRIGGER_INTERVAL 500 +struct ath_pktlog_arg { + struct ath_pktlog_info *pl_info; + uint32_t flags; + uint16_t missed_cnt; +#ifdef HELIUMPLUS + uint8_t log_type; + uint8_t macId; +#else + uint16_t log_type; +#endif + size_t log_size; + uint16_t timestamp; +#ifdef HELIUMPLUS + uint32_t type_specific_data; +#endif + char *buf; +}; + +void pktlog_getbuf_intsafe(struct ath_pktlog_arg *plarg); +char *pktlog_getbuf(struct ol_pktlog_dev_t *pl_dev, + struct ath_pktlog_info *pl_info, + size_t log_size, struct ath_pktlog_hdr *pl_hdr); + +A_STATUS process_tx_info(struct ol_txrx_pdev_t *pdev, void *data); +A_STATUS process_rx_info(void *pdev, void *data); +A_STATUS process_rx_info_remote(void *pdev, void *data); +A_STATUS process_rate_find(void *pdev, void *data); +A_STATUS process_rate_update(void *pdev, void *data); +A_STATUS process_sw_event(void *pdev, void *data); + + +#endif /* REMOVE_PKT_LOG */ +#endif diff --git a/drivers/staging/qcacld-3.0/core/utils/pktlog/linux_ac.c b/drivers/staging/qcacld-3.0/core/utils/pktlog/linux_ac.c new file mode 100644 index 0000000000000000000000000000000000000000..e707932dc27d575d05f360d92313648c351a339c --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/utils/pktlog/linux_ac.c @@ -0,0 +1,1063 @@ +/* + * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef REMOVE_PKT_LOG +#ifndef EXPORT_SYMTAB +#define EXPORT_SYMTAB +#endif +#ifndef __KERNEL__ +#define __KERNEL__ +#endif +/* + * Linux specific implementation of Pktlogs for 802.11ac + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include "i_host_diag_core_log.h" +#include "host_diag_core_log.h" +#include "ani_global.h" + +#define PKTLOG_TAG "ATH_PKTLOG" +#define PKTLOG_DEVNAME_SIZE 32 +#define MAX_WLANDEV 1 + +#ifdef MULTI_IF_NAME +#define PKTLOG_PROC_DIR "ath_pktlog" MULTI_IF_NAME +#else +#define PKTLOG_PROC_DIR "ath_pktlog" +#endif + +/* Permissions for creating proc entries */ +#define PKTLOG_PROC_PERM 0444 +#define PKTLOG_PROCSYS_DIR_PERM 0555 +#define PKTLOG_PROCSYS_PERM 0644 + +#ifndef __MOD_INC_USE_COUNT +#define PKTLOG_MOD_INC_USE_COUNT \ + if (!try_module_get(THIS_MODULE)) { \ + printk(KERN_WARNING "try_module_get failed\n"); \ + } + +#define PKTLOG_MOD_DEC_USE_COUNT module_put(THIS_MODULE) +#else +#define PKTLOG_MOD_INC_USE_COUNT MOD_INC_USE_COUNT +#define PKTLOG_MOD_DEC_USE_COUNT MOD_DEC_USE_COUNT +#endif + +static struct ath_pktlog_info *g_pktlog_info; + +static struct proc_dir_entry *g_pktlog_pde; + +static int pktlog_attach(struct hif_opaque_softc *sc); +static void pktlog_detach(struct hif_opaque_softc *sc); +static int pktlog_open(struct inode *i, struct file *f); +static int pktlog_release(struct inode *i, struct file *f); +static ssize_t pktlog_read(struct file *file, char *buf, size_t nbytes, + loff_t *ppos); + +static struct file_operations pktlog_fops = { + open: pktlog_open, + release:pktlog_release, + read : pktlog_read, +}; + +/* + * Linux implementation of helper functions + */ + +static struct ol_pktlog_dev_t *get_pl_handle(struct hif_opaque_softc *scn) +{ + ol_txrx_pdev_handle pdev_txrx_handle; + pdev_txrx_handle = cds_get_context(QDF_MODULE_ID_TXRX); + if (!pdev_txrx_handle) + return NULL; + return pdev_txrx_handle->pl_dev; +} + +void ol_pl_set_name(hif_opaque_softc_handle scn, net_device_handle dev) +{ + ol_txrx_pdev_handle pdev_txrx_handle; + pdev_txrx_handle = cds_get_context(QDF_MODULE_ID_TXRX); + if (pdev_txrx_handle && pdev_txrx_handle->pl_dev && dev) + pdev_txrx_handle->pl_dev->name = dev->name; +} + +void pktlog_disable_adapter_logging(struct hif_opaque_softc *scn) +{ + struct ol_pktlog_dev_t *pl_dev = get_pl_handle(scn); + if (pl_dev) + pl_dev->pl_info->log_state = 0; +} + +int pktlog_alloc_buf(struct hif_opaque_softc *scn) +{ + uint32_t page_cnt; + unsigned long vaddr; + struct page *vpg; + struct ath_pktlog_info *pl_info; + struct ath_pktlog_buf *buffer; + ol_txrx_pdev_handle pdev_txrx_handle; + pdev_txrx_handle = cds_get_context(QDF_MODULE_ID_TXRX); + + if (!pdev_txrx_handle || !pdev_txrx_handle->pl_dev) { + printk(PKTLOG_TAG + "%s: Unable to allocate buffer " + "scn or scn->pdev_txrx_handle->pl_dev is null\n", + __func__); + return -EINVAL; + } + + pl_info = pdev_txrx_handle->pl_dev->pl_info; + + page_cnt = (sizeof(*(pl_info->buf)) + pl_info->buf_size) / PAGE_SIZE; + + spin_lock_bh(&pl_info->log_lock); + if (pl_info->buf != NULL) { + printk(PKTLOG_TAG "Buffer is already in use\n"); + spin_unlock_bh(&pl_info->log_lock); + return -EINVAL; + } + spin_unlock_bh(&pl_info->log_lock); + + buffer = vmalloc((page_cnt + 2) * PAGE_SIZE); + if (buffer == NULL) { + printk(PKTLOG_TAG + "%s: Unable to allocate buffer " + "(%d pages)\n", __func__, page_cnt); + return -ENOMEM; + } + + buffer = (struct ath_pktlog_buf *) + (((unsigned long)(buffer) + PAGE_SIZE - 1) + & PAGE_MASK); + + for (vaddr = (unsigned long)(buffer); + vaddr < ((unsigned long)(buffer) + (page_cnt * PAGE_SIZE)); + vaddr += PAGE_SIZE) { + vpg = vmalloc_to_page((const void *)vaddr); + SetPageReserved(vpg); + } + + spin_lock_bh(&pl_info->log_lock); + if (pl_info->buf != NULL) + pktlog_release_buf(scn); + + pl_info->buf = buffer; + spin_unlock_bh(&pl_info->log_lock); + return 0; +} + +void pktlog_release_buf(struct hif_opaque_softc *scn) +{ + unsigned long page_cnt; + unsigned long vaddr; + struct page *vpg; + struct ath_pktlog_info *pl_info; + ol_txrx_pdev_handle pdev_txrx_handle; + pdev_txrx_handle = cds_get_context(QDF_MODULE_ID_TXRX); + + if (!pdev_txrx_handle || !pdev_txrx_handle->pl_dev) { + printk(PKTLOG_TAG + "%s: Unable to allocate buffer" + "scn or scn->pdev_txrx_handle->pl_dev is null\n", + __func__); + return; + } + + pl_info = pdev_txrx_handle->pl_dev->pl_info; + + page_cnt = ((sizeof(*(pl_info->buf)) + pl_info->buf_size) / + PAGE_SIZE) + 1; + + for (vaddr = (unsigned long)(pl_info->buf); + vaddr < (unsigned long)(pl_info->buf) + (page_cnt * PAGE_SIZE); + vaddr += PAGE_SIZE) { + vpg = vmalloc_to_page((const void *)vaddr); + ClearPageReserved(vpg); + } + + vfree(pl_info->buf); + pl_info->buf = NULL; +} + +static void pktlog_cleanup(struct ath_pktlog_info *pl_info) +{ + pl_info->log_state = 0; + PKTLOG_LOCK_DESTROY(pl_info); + mutex_destroy(&pl_info->pktlog_mutex); +} + +/* sysctl procfs handler to enable pktlog */ +static int +qdf_sysctl_decl(ath_sysctl_pktlog_enable, ctl, write, filp, buffer, lenp, ppos) +{ + int ret, enable; + ol_ath_generic_softc_handle scn; + struct ol_pktlog_dev_t *pl_dev; + + scn = (ol_ath_generic_softc_handle) ctl->extra1; + + if (!scn) { + printk("%s: Invalid scn context\n", __func__); + ASSERT(0); + return -EINVAL; + } + + pl_dev = get_pl_handle((struct hif_opaque_softc *)scn); + + if (!pl_dev) { + printk("%s: Invalid pktlog context\n", __func__); + ASSERT(0); + return -ENODEV; + } + + ctl->data = &enable; + ctl->maxlen = sizeof(enable); + + if (write) { + ret = QDF_SYSCTL_PROC_DOINTVEC(ctl, write, filp, buffer, + lenp, ppos); + if (ret == 0) + ret = pl_dev->pl_funcs->pktlog_enable( + (struct hif_opaque_softc *)scn, enable, + cds_is_packet_log_enabled(), 0, 1); + else + QDF_TRACE(QDF_MODULE_ID_SYS, QDF_TRACE_LEVEL_DEBUG, + "Line:%d %s:proc_dointvec failed reason %d", + __LINE__, __func__, ret); + } else { + ret = QDF_SYSCTL_PROC_DOINTVEC(ctl, write, filp, buffer, + lenp, ppos); + if (ret) + QDF_TRACE(QDF_MODULE_ID_SYS, QDF_TRACE_LEVEL_DEBUG, + "Line:%d %s:proc_dointvec failed reason %d", + __LINE__, __func__, ret); + } + + ctl->data = NULL; + ctl->maxlen = 0; + + return ret; +} + +static int get_pktlog_bufsize(struct ol_pktlog_dev_t *pl_dev) +{ + return pl_dev->pl_info->buf_size; +} + +/* sysctl procfs handler to set/get pktlog size */ +static int +qdf_sysctl_decl(ath_sysctl_pktlog_size, ctl, write, filp, buffer, lenp, ppos) +{ + int ret, size; + ol_ath_generic_softc_handle scn; + struct ol_pktlog_dev_t *pl_dev; + + scn = (ol_ath_generic_softc_handle) ctl->extra1; + + if (!scn) { + printk("%s: Invalid scn context\n", __func__); + ASSERT(0); + return -EINVAL; + } + + pl_dev = get_pl_handle((struct hif_opaque_softc *)scn); + + if (!pl_dev) { + printk("%s: Invalid pktlog handle\n", __func__); + ASSERT(0); + return -ENODEV; + } + + ctl->data = &size; + ctl->maxlen = sizeof(size); + + if (write) { + ret = QDF_SYSCTL_PROC_DOINTVEC(ctl, write, filp, buffer, + lenp, ppos); + if (ret == 0) + ret = pl_dev->pl_funcs->pktlog_setsize( + (struct hif_opaque_softc *)scn, size); + } else { + size = get_pktlog_bufsize(pl_dev); + ret = QDF_SYSCTL_PROC_DOINTVEC(ctl, write, filp, buffer, + lenp, ppos); + } + + ctl->data = NULL; + ctl->maxlen = 0; + + return ret; +} + +/* Register sysctl table */ +static int pktlog_sysctl_register(struct hif_opaque_softc *scn) +{ + struct ol_pktlog_dev_t *pl_dev = get_pl_handle(scn); + struct ath_pktlog_info_lnx *pl_info_lnx; + char *proc_name; + + if (pl_dev) { + pl_info_lnx = PL_INFO_LNX(pl_dev->pl_info); + proc_name = pl_dev->name; + } else { + pl_info_lnx = PL_INFO_LNX(g_pktlog_info); + proc_name = PKTLOG_PROC_SYSTEM; + } + + /* + * Setup the sysctl table for creating the following sysctl entries: + * /proc/sys/PKTLOG_PROC_DIR//enable for enabling/disabling + * pktlog + * /proc/sys/PKTLOG_PROC_DIR//size for changing the buffer size + */ + memset(pl_info_lnx->sysctls, 0, sizeof(pl_info_lnx->sysctls)); + pl_info_lnx->sysctls[0].procname = PKTLOG_PROC_DIR; + pl_info_lnx->sysctls[0].mode = PKTLOG_PROCSYS_DIR_PERM; + pl_info_lnx->sysctls[0].child = &pl_info_lnx->sysctls[2]; + + /* [1] is NULL terminator */ + pl_info_lnx->sysctls[2].procname = proc_name; + pl_info_lnx->sysctls[2].mode = PKTLOG_PROCSYS_DIR_PERM; + pl_info_lnx->sysctls[2].child = &pl_info_lnx->sysctls[4]; + + /* [3] is NULL terminator */ + pl_info_lnx->sysctls[4].procname = "enable"; + pl_info_lnx->sysctls[4].mode = PKTLOG_PROCSYS_PERM; + pl_info_lnx->sysctls[4].proc_handler = ath_sysctl_pktlog_enable; + pl_info_lnx->sysctls[4].extra1 = scn; + + pl_info_lnx->sysctls[5].procname = "size"; + pl_info_lnx->sysctls[5].mode = PKTLOG_PROCSYS_PERM; + pl_info_lnx->sysctls[5].proc_handler = ath_sysctl_pktlog_size; + pl_info_lnx->sysctls[5].extra1 = scn; + + pl_info_lnx->sysctls[6].procname = "options"; + pl_info_lnx->sysctls[6].mode = PKTLOG_PROCSYS_PERM; + pl_info_lnx->sysctls[6].proc_handler = proc_dointvec; + pl_info_lnx->sysctls[6].data = &pl_info_lnx->info.options; + pl_info_lnx->sysctls[6].maxlen = sizeof(pl_info_lnx->info.options); + + pl_info_lnx->sysctls[7].procname = "sack_thr"; + pl_info_lnx->sysctls[7].mode = PKTLOG_PROCSYS_PERM; + pl_info_lnx->sysctls[7].proc_handler = proc_dointvec; + pl_info_lnx->sysctls[7].data = &pl_info_lnx->info.sack_thr; + pl_info_lnx->sysctls[7].maxlen = sizeof(pl_info_lnx->info.sack_thr); + + pl_info_lnx->sysctls[8].procname = "tail_length"; + pl_info_lnx->sysctls[8].mode = PKTLOG_PROCSYS_PERM; + pl_info_lnx->sysctls[8].proc_handler = proc_dointvec; + pl_info_lnx->sysctls[8].data = &pl_info_lnx->info.tail_length; + pl_info_lnx->sysctls[8].maxlen = sizeof(pl_info_lnx->info.tail_length); + + pl_info_lnx->sysctls[9].procname = "thruput_thresh"; + pl_info_lnx->sysctls[9].mode = PKTLOG_PROCSYS_PERM; + pl_info_lnx->sysctls[9].proc_handler = proc_dointvec; + pl_info_lnx->sysctls[9].data = &pl_info_lnx->info.thruput_thresh; + pl_info_lnx->sysctls[9].maxlen = + sizeof(pl_info_lnx->info.thruput_thresh); + + pl_info_lnx->sysctls[10].procname = "phyerr_thresh"; + pl_info_lnx->sysctls[10].mode = PKTLOG_PROCSYS_PERM; + pl_info_lnx->sysctls[10].proc_handler = proc_dointvec; + pl_info_lnx->sysctls[10].data = &pl_info_lnx->info.phyerr_thresh; + pl_info_lnx->sysctls[10].maxlen = + sizeof(pl_info_lnx->info.phyerr_thresh); + + pl_info_lnx->sysctls[11].procname = "per_thresh"; + pl_info_lnx->sysctls[11].mode = PKTLOG_PROCSYS_PERM; + pl_info_lnx->sysctls[11].proc_handler = proc_dointvec; + pl_info_lnx->sysctls[11].data = &pl_info_lnx->info.per_thresh; + pl_info_lnx->sysctls[11].maxlen = sizeof(pl_info_lnx->info.per_thresh); + + pl_info_lnx->sysctls[12].procname = "trigger_interval"; + pl_info_lnx->sysctls[12].mode = PKTLOG_PROCSYS_PERM; + pl_info_lnx->sysctls[12].proc_handler = proc_dointvec; + pl_info_lnx->sysctls[12].data = &pl_info_lnx->info.trigger_interval; + pl_info_lnx->sysctls[12].maxlen = + sizeof(pl_info_lnx->info.trigger_interval); + /* [13] is NULL terminator */ + + /* and register everything */ + /* register_sysctl_table changed from 2.6.21 onwards */ + pl_info_lnx->sysctl_header = + register_sysctl_table(pl_info_lnx->sysctls); + + if (!pl_info_lnx->sysctl_header) { + printk("%s: failed to register sysctls!\n", proc_name); + return -1; + } + + return 0; +} + +/* + * Initialize logging for system or adapter + * Parameter scn should be NULL for system wide logging + */ +static int pktlog_attach(struct hif_opaque_softc *scn) +{ + struct ol_pktlog_dev_t *pl_dev; + struct ath_pktlog_info_lnx *pl_info_lnx; + char *proc_name; + struct proc_dir_entry *proc_entry; + + pl_dev = get_pl_handle(scn); + + if (pl_dev != NULL) { + pl_info_lnx = kmalloc(sizeof(*pl_info_lnx), GFP_KERNEL); + if (pl_info_lnx == NULL) { + printk(PKTLOG_TAG "%s:allocation failed for pl_info\n", + __func__); + return -ENOMEM; + } + pl_dev->pl_info = &pl_info_lnx->info; + pl_dev->name = WLANDEV_BASENAME; + proc_name = pl_dev->name; + if (!pl_dev->pl_funcs) + pl_dev->pl_funcs = &ol_pl_funcs; + + /* + * Valid for both direct attach and offload architecture + */ + pl_dev->pl_funcs->pktlog_init(scn); + } else { + return -1; + } + + /* + * initialize log info + * might be good to move to pktlog_init + */ + /* pl_dev->tgt_pktlog_alloced = false; */ + pl_dev->vendor_cmd_send = false; + pl_info_lnx->proc_entry = NULL; + pl_info_lnx->sysctl_header = NULL; + + proc_entry = proc_create_data(proc_name, PKTLOG_PROC_PERM, + g_pktlog_pde, &pktlog_fops, + &pl_info_lnx->info); + + if (proc_entry == NULL) { + printk(PKTLOG_TAG "%s: create_proc_entry failed for %s\n", + __func__, proc_name); + goto attach_fail1; + } + + pl_info_lnx->proc_entry = proc_entry; + + if (pktlog_sysctl_register(scn)) { + printk(PKTLOG_TAG "%s: sysctl register failed for %s\n", + __func__, proc_name); + goto attach_fail2; + } + return 0; + +attach_fail2: + remove_proc_entry(proc_name, g_pktlog_pde); + +attach_fail1: + if (pl_dev) + kfree(pl_dev->pl_info); + return -1; +} + +static void pktlog_sysctl_unregister(struct ol_pktlog_dev_t *pl_dev) +{ + struct ath_pktlog_info_lnx *pl_info_lnx; + + if (!pl_dev) { + printk("%s: Invalid pktlog context\n", __func__); + ASSERT(0); + return; + } + + pl_info_lnx = (pl_dev) ? PL_INFO_LNX(pl_dev->pl_info) : + PL_INFO_LNX(g_pktlog_info); + + if (pl_info_lnx->sysctl_header) { + unregister_sysctl_table(pl_info_lnx->sysctl_header); + pl_info_lnx->sysctl_header = NULL; + } +} + +static void pktlog_detach(struct hif_opaque_softc *scn) +{ + struct ol_txrx_pdev_t *txrx_pdev; + struct ol_pktlog_dev_t *pl_dev; + struct ath_pktlog_info *pl_info; + + txrx_pdev = cds_get_context(QDF_MODULE_ID_TXRX); + if (!txrx_pdev) { + printk("%s: Invalid txrx_pdev context\n", __func__); + ASSERT(0); + return; + } + + pl_dev = txrx_pdev->pl_dev; + if (!pl_dev) { + printk("%s: Invalid pktlog context\n", __func__); + ASSERT(0); + return; + } + + pl_info = pl_dev->pl_info; + remove_proc_entry(WLANDEV_BASENAME, g_pktlog_pde); + pktlog_sysctl_unregister(pl_dev); + + spin_lock_bh(&pl_info->log_lock); + + if (pl_info->buf) { + pktlog_release_buf(scn); + pl_dev->tgt_pktlog_alloced = false; + } + spin_unlock_bh(&pl_info->log_lock); + pktlog_cleanup(pl_info); + + if (pl_dev) { + kfree(pl_info); + pl_dev->pl_info = NULL; + } +} + +static int __pktlog_open(struct inode *i, struct file *f) +{ + struct hif_opaque_softc *scn; + struct ol_pktlog_dev_t *pl_dev; + struct ath_pktlog_info *pl_info; + int ret = 0; + + PKTLOG_MOD_INC_USE_COUNT; + pl_info = (struct ath_pktlog_info *) + PDE_DATA(f->f_path.dentry->d_inode); + + if (!pl_info) { + pr_err("%s: pl_info NULL", __func__); + return -EINVAL; + } + + if (pl_info->curr_pkt_state != PKTLOG_OPR_NOT_IN_PROGRESS) { + pr_info("%s: plinfo state (%d) != PKTLOG_OPR_NOT_IN_PROGRESS", + __func__, pl_info->curr_pkt_state); + return -EBUSY; + } + + if (cds_is_load_or_unload_in_progress() || cds_is_driver_recovering()) { + pr_info("%s: Load/Unload or recovery is in progress", __func__); + return -EAGAIN; + } + + pl_info->curr_pkt_state = PKTLOG_OPR_IN_PROGRESS_READ_START; + scn = cds_get_context(QDF_MODULE_ID_HIF); + if (!scn) { + pl_info->curr_pkt_state = PKTLOG_OPR_NOT_IN_PROGRESS; + qdf_print("%s: Invalid scn context\n", __func__); + ASSERT(0); + return -EINVAL; + } + + pl_dev = get_pl_handle((struct hif_opaque_softc *)scn); + + if (!pl_dev) { + pl_info->curr_pkt_state = PKTLOG_OPR_NOT_IN_PROGRESS; + qdf_print("%s: Invalid pktlog handle\n", __func__); + ASSERT(0); + return -ENODEV; + } + + pl_info->init_saved_state = pl_info->log_state; + if (!pl_info->log_state) { + /* Pktlog is already disabled. + * Proceed to read directly. + */ + pl_info->curr_pkt_state = + PKTLOG_OPR_IN_PROGRESS_READ_START_PKTLOG_DISABLED; + return ret; + } + /* Disbable the pktlog internally. */ + ret = pl_dev->pl_funcs->pktlog_disable(scn); + pl_info->log_state = 0; + pl_info->curr_pkt_state = + PKTLOG_OPR_IN_PROGRESS_READ_START_PKTLOG_DISABLED; + return ret; +} + +static int pktlog_open(struct inode *i, struct file *f) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __pktlog_open(i, f); + cds_ssr_unprotect(__func__); + + return ret; +} + +static int __pktlog_release(struct inode *i, struct file *f) +{ + struct hif_opaque_softc *scn; + struct ol_pktlog_dev_t *pl_dev; + struct ath_pktlog_info *pl_info; + int ret = 0; + + PKTLOG_MOD_DEC_USE_COUNT; + + pl_info = (struct ath_pktlog_info *) + PDE_DATA(f->f_path.dentry->d_inode); + + if (!pl_info) + return -EINVAL; + + if (cds_is_load_or_unload_in_progress() || cds_is_driver_recovering()) { + pr_info("%s: Load/Unload or recovery is in progress", __func__); + return -EAGAIN; + } + + scn = cds_get_context(QDF_MODULE_ID_HIF); + if (!scn) { + pl_info->curr_pkt_state = PKTLOG_OPR_NOT_IN_PROGRESS; + qdf_print("%s: Invalid scn context\n", __func__); + ASSERT(0); + return -EINVAL; + } + + pl_dev = get_pl_handle((struct hif_opaque_softc *)scn); + + if (!pl_dev) { + pl_info->curr_pkt_state = PKTLOG_OPR_NOT_IN_PROGRESS; + qdf_print("%s: Invalid pktlog handle\n", __func__); + ASSERT(0); + return -ENODEV; + } + + pl_info->curr_pkt_state = PKTLOG_OPR_IN_PROGRESS_READ_COMPLETE; + /*clear pktlog buffer.*/ + pktlog_clearbuff(scn, true); + pl_info->log_state = pl_info->init_saved_state; + pl_info->init_saved_state = 0; + + /*Enable pktlog again*/ + ret = pl_dev->pl_funcs->pktlog_enable( + (struct hif_opaque_softc *)scn, pl_info->log_state, + cds_is_packet_log_enabled(), 0, 1); + if (ret != 0) + pr_warn("%s: pktlog cannot be enabled. ret value %d\n", + __func__, ret); + + pl_info->curr_pkt_state = PKTLOG_OPR_NOT_IN_PROGRESS; + return ret; +} + +static int pktlog_release(struct inode *i, struct file *f) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __pktlog_release(i, f); + cds_ssr_unprotect(__func__); + + return ret; +} + +#ifndef MIN +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) +#endif + +/** + * pktlog_read_proc_entry() - This function is used to read data from the + * proc entry into the readers buffer + * @buf: Readers buffer + * @nbytes: Number of bytes to read + * @ppos: Offset within the drivers buffer + * @pl_info: Packet log information pointer + * @read_complete: Boolean value indication whether read is complete + * + * This function is used to read data from the proc entry into the readers + * buffer. Its functionality is similar to 'pktlog_read' which does + * copy to user to the user space buffer + * + * Return: Number of bytes read from the buffer + * + */ + ssize_t +pktlog_read_proc_entry(char *buf, size_t nbytes, loff_t *ppos, + struct ath_pktlog_info *pl_info, bool *read_complete) +{ + size_t bufhdr_size; + size_t count = 0, ret_val = 0; + int rem_len; + int start_offset, end_offset; + int fold_offset, ppos_data, cur_rd_offset, cur_wr_offset; + struct ath_pktlog_buf *log_buf; + + spin_lock_bh(&pl_info->log_lock); + log_buf = pl_info->buf; + + *read_complete = false; + + if (log_buf == NULL) { + *read_complete = true; + spin_unlock_bh(&pl_info->log_lock); + return 0; + } + + if (*ppos == 0 && pl_info->log_state) { + pl_info->saved_state = pl_info->log_state; + pl_info->log_state = 0; + } + + bufhdr_size = sizeof(log_buf->bufhdr); + + /* copy valid log entries from circular buffer into user space */ + rem_len = nbytes; + count = 0; + + if (*ppos < bufhdr_size) { + count = MIN((bufhdr_size - *ppos), rem_len); + qdf_mem_copy(buf, ((char *)&log_buf->bufhdr) + *ppos, + count); + rem_len -= count; + ret_val += count; + } + + start_offset = log_buf->rd_offset; + cur_wr_offset = log_buf->wr_offset; + + if ((rem_len == 0) || (start_offset < 0)) + goto rd_done; + + fold_offset = -1; + cur_rd_offset = start_offset; + + /* Find the last offset and fold-offset if the buffer is folded */ + do { + struct ath_pktlog_hdr *log_hdr; + int log_data_offset; + + log_hdr = (struct ath_pktlog_hdr *) (log_buf->log_data + + cur_rd_offset); + + log_data_offset = cur_rd_offset + sizeof(struct ath_pktlog_hdr); + + if ((fold_offset == -1) + && ((pl_info->buf_size - log_data_offset) + <= log_hdr->size)) + fold_offset = log_data_offset - 1; + + PKTLOG_MOV_RD_IDX(cur_rd_offset, log_buf, pl_info->buf_size); + + if ((fold_offset == -1) && (cur_rd_offset == 0) + && (cur_rd_offset != cur_wr_offset)) + fold_offset = log_data_offset + log_hdr->size - 1; + + end_offset = log_data_offset + log_hdr->size - 1; + } while (cur_rd_offset != cur_wr_offset); + + ppos_data = *ppos + ret_val - bufhdr_size + start_offset; + + if (fold_offset == -1) { + if (ppos_data > end_offset) + goto rd_done; + + count = MIN(rem_len, (end_offset - ppos_data + 1)); + qdf_mem_copy(buf + ret_val, + log_buf->log_data + ppos_data, + count); + ret_val += count; + rem_len -= count; + } else { + if (ppos_data <= fold_offset) { + count = MIN(rem_len, (fold_offset - ppos_data + 1)); + qdf_mem_copy(buf + ret_val, + log_buf->log_data + ppos_data, + count); + ret_val += count; + rem_len -= count; + } + + if (rem_len == 0) + goto rd_done; + + ppos_data = + *ppos + ret_val - (bufhdr_size + + (fold_offset - start_offset + 1)); + + if (ppos_data <= end_offset) { + count = MIN(rem_len, (end_offset - ppos_data + 1)); + qdf_mem_copy(buf + ret_val, + log_buf->log_data + ppos_data, + count); + ret_val += count; + rem_len -= count; + } + } + +rd_done: + if ((ret_val < nbytes) && pl_info->saved_state) { + pl_info->log_state = pl_info->saved_state; + pl_info->saved_state = 0; + } + *ppos += ret_val; + + if (ret_val == 0) { + /* Write pointer might have been updated during the read. + * So, if some data is written into, lets not reset the pointers + * We can continue to read from the offset position + */ + if (cur_wr_offset != log_buf->wr_offset) { + *read_complete = false; + } else { + pl_info->buf->rd_offset = -1; + pl_info->buf->wr_offset = 0; + pl_info->buf->bytes_written = 0; + pl_info->buf->offset = PKTLOG_READ_OFFSET; + *read_complete = true; + } + } + spin_unlock_bh(&pl_info->log_lock); + return ret_val; +} + +static ssize_t +__pktlog_read(struct file *file, char *buf, size_t nbytes, loff_t *ppos) +{ + size_t bufhdr_size; + size_t count = 0, ret_val = 0; + int rem_len; + int start_offset, end_offset; + int fold_offset, ppos_data, cur_rd_offset; + struct ath_pktlog_info *pl_info; + struct ath_pktlog_buf *log_buf; + + if (cds_is_load_or_unload_in_progress() || cds_is_driver_recovering()) { + pr_info("%s: Load/Unload or recovery is in progress", __func__); + return -EAGAIN; + } + + pl_info = (struct ath_pktlog_info *) + PDE_DATA(file->f_path.dentry->d_inode); + if (!pl_info) + return 0; + + spin_lock_bh(&pl_info->log_lock); + log_buf = pl_info->buf; + + if (log_buf == NULL) { + spin_unlock_bh(&pl_info->log_lock); + return 0; + } + + if (pl_info->log_state) { + /* Read is not allowed when write is going on + * When issuing cat command, ensure to send + * pktlog disable command first. + */ + spin_unlock_bh(&pl_info->log_lock); + return -EINVAL; + } + + if (*ppos == 0 && pl_info->log_state) { + pl_info->saved_state = pl_info->log_state; + pl_info->log_state = 0; + } + + bufhdr_size = sizeof(log_buf->bufhdr); + + /* copy valid log entries from circular buffer into user space */ + rem_len = nbytes; + count = 0; + + if (*ppos < bufhdr_size) { + count = QDF_MIN((bufhdr_size - *ppos), rem_len); + spin_unlock_bh(&pl_info->log_lock); + if (copy_to_user(buf, ((char *)&log_buf->bufhdr) + *ppos, + count)) + return -EFAULT; + rem_len -= count; + ret_val += count; + spin_lock_bh(&pl_info->log_lock); + } + + start_offset = log_buf->rd_offset; + + if ((rem_len == 0) || (start_offset < 0)) + goto rd_done; + + fold_offset = -1; + cur_rd_offset = start_offset; + + /* Find the last offset and fold-offset if the buffer is folded */ + do { + struct ath_pktlog_hdr *log_hdr; + int log_data_offset; + + log_hdr = (struct ath_pktlog_hdr *)(log_buf->log_data + + cur_rd_offset); + + log_data_offset = cur_rd_offset + sizeof(struct ath_pktlog_hdr); + + if ((fold_offset == -1) + && ((pl_info->buf_size - log_data_offset) + <= log_hdr->size)) + fold_offset = log_data_offset - 1; + + PKTLOG_MOV_RD_IDX(cur_rd_offset, log_buf, pl_info->buf_size); + + if ((fold_offset == -1) && (cur_rd_offset == 0) + && (cur_rd_offset != log_buf->wr_offset)) + fold_offset = log_data_offset + log_hdr->size - 1; + + end_offset = log_data_offset + log_hdr->size - 1; + } while (cur_rd_offset != log_buf->wr_offset); + + ppos_data = *ppos + ret_val - bufhdr_size + start_offset; + + if (fold_offset == -1) { + if (ppos_data > end_offset) + goto rd_done; + + count = QDF_MIN(rem_len, (end_offset - ppos_data + 1)); + spin_unlock_bh(&pl_info->log_lock); + if (copy_to_user(buf + ret_val, + log_buf->log_data + ppos_data, count)) + return -EFAULT; + ret_val += count; + rem_len -= count; + spin_lock_bh(&pl_info->log_lock); + } else { + if (ppos_data <= fold_offset) { + count = QDF_MIN(rem_len, (fold_offset - ppos_data + 1)); + spin_unlock_bh(&pl_info->log_lock); + if (copy_to_user(buf + ret_val, + log_buf->log_data + ppos_data, count)) + return -EFAULT; + ret_val += count; + rem_len -= count; + spin_lock_bh(&pl_info->log_lock); + } + + if (rem_len == 0) + goto rd_done; + + ppos_data = + *ppos + ret_val - (bufhdr_size + + (fold_offset - start_offset + 1)); + + if (ppos_data <= end_offset) { + count = QDF_MIN(rem_len, (end_offset - ppos_data + 1)); + spin_unlock_bh(&pl_info->log_lock); + if (copy_to_user(buf + ret_val, + log_buf->log_data + ppos_data, count)) + return -EFAULT; + ret_val += count; + rem_len -= count; + spin_lock_bh(&pl_info->log_lock); + } + } + +rd_done: + if ((ret_val < nbytes) && pl_info->saved_state) { + pl_info->log_state = pl_info->saved_state; + pl_info->saved_state = 0; + } + *ppos += ret_val; + + spin_unlock_bh(&pl_info->log_lock); + return ret_val; +} + +static ssize_t +pktlog_read(struct file *file, char *buf, size_t nbytes, loff_t *ppos) +{ + int ret; + struct ath_pktlog_info *pl_info; + + pl_info = (struct ath_pktlog_info *) + PDE_DATA(file->f_path.dentry->d_inode); + if (!pl_info) + return 0; + + cds_ssr_protect(__func__); + mutex_lock(&pl_info->pktlog_mutex); + ret = __pktlog_read(file, buf, nbytes, ppos); + mutex_unlock(&pl_info->pktlog_mutex); + cds_ssr_unprotect(__func__); + return ret; +} + +int pktlogmod_init(void *context) +{ + int ret; + + /* create the proc directory entry */ + g_pktlog_pde = proc_mkdir(PKTLOG_PROC_DIR, NULL); + + if (g_pktlog_pde == NULL) { + printk(PKTLOG_TAG "%s: proc_mkdir failed\n", __func__); + return -1; + } + + /* Attach packet log */ + ret = pktlog_attach((struct hif_opaque_softc *)context); + + if (ret) + goto attach_fail; + + return ret; + +attach_fail: + remove_proc_entry(PKTLOG_PROC_DIR, NULL); + g_pktlog_pde = NULL; + return ret; +} + +void pktlogmod_exit(void *context) +{ + struct hif_opaque_softc *scn = (struct hif_opaque_softc *)context; + struct ol_pktlog_dev_t *pl_dev; + + if (!scn) + return; + + pl_dev = get_pl_handle(scn); + + if (!pl_dev || g_pktlog_pde == NULL) + return; + + pktlog_detach(scn); + /* + * pdev kill needs to be implemented + */ + remove_proc_entry(PKTLOG_PROC_DIR, NULL); +} +#endif diff --git a/drivers/staging/qcacld-3.0/core/utils/pktlog/pktlog_ac.c b/drivers/staging/qcacld-3.0/core/utils/pktlog/pktlog_ac.c new file mode 100644 index 0000000000000000000000000000000000000000..a3688a5efca7f21480b4dc3df8ad2b92895e1e2f --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/utils/pktlog/pktlog_ac.c @@ -0,0 +1,902 @@ +/* + * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * + * 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 REMOVE_PKT_LOG +#include "qdf_mem.h" +#include "athdefs.h" +#include "pktlog_ac_i.h" +#include "cds_api.h" +#include "wma_types.h" +#include "htc.h" + +wdi_event_subscribe PKTLOG_TX_SUBSCRIBER; +wdi_event_subscribe PKTLOG_RX_SUBSCRIBER; +wdi_event_subscribe PKTLOG_RX_REMOTE_SUBSCRIBER; +wdi_event_subscribe PKTLOG_RCFIND_SUBSCRIBER; +wdi_event_subscribe PKTLOG_RCUPDATE_SUBSCRIBER; +wdi_event_subscribe PKTLOG_SW_EVENT_SUBSCRIBER; + +struct ol_pl_arch_dep_funcs ol_pl_funcs = { + .pktlog_init = pktlog_init, + .pktlog_enable = pktlog_enable, + .pktlog_setsize = pktlog_setsize, + .pktlog_disable = pktlog_disable, /* valid for f/w disable */ +}; + +struct ol_pktlog_dev_t ol_pl_dev = { + .pl_funcs = &ol_pl_funcs, +}; + +void ol_pl_sethandle(ol_pktlog_dev_handle *pl_handle, + struct hif_opaque_softc *scn) +{ + ol_pl_dev.scn = (ol_ath_generic_softc_handle) scn; + *pl_handle = &ol_pl_dev; +} + +static A_STATUS pktlog_wma_post_msg(WMI_PKTLOG_EVENT event_types, + WMI_CMD_ID cmd_id, bool ini_triggered, + uint8_t user_triggered) +{ + cds_msg_t msg = { 0 }; + QDF_STATUS status; + struct ath_pktlog_wmi_params *param; + + param = qdf_mem_malloc(sizeof(struct ath_pktlog_wmi_params)); + + if (!param) + return A_NO_MEMORY; + + param->cmd_id = cmd_id; + param->pktlog_event = event_types; + param->ini_triggered = ini_triggered; + param->user_triggered = user_triggered; + + msg.type = WMA_PKTLOG_ENABLE_REQ; + msg.bodyptr = param; + msg.bodyval = 0; + + status = cds_mq_post_message(CDS_MQ_ID_WMA, &msg); + + if (status != QDF_STATUS_SUCCESS) { + qdf_mem_free(param); + return A_ERROR; + } + + return A_OK; +} + +static inline A_STATUS +pktlog_enable_tgt(struct hif_opaque_softc *_scn, uint32_t log_state, + bool ini_triggered, uint8_t user_triggered) +{ + uint32_t types = 0; + + if (log_state & ATH_PKTLOG_TX) + types |= WMI_PKTLOG_EVENT_TX; + + if (log_state & ATH_PKTLOG_RX) + types |= WMI_PKTLOG_EVENT_RX; + + if (log_state & ATH_PKTLOG_RCFIND) + types |= WMI_PKTLOG_EVENT_RCF; + + if (log_state & ATH_PKTLOG_RCUPDATE) + types |= WMI_PKTLOG_EVENT_RCU; + + if (log_state & ATH_PKTLOG_SW_EVENT) + types |= WMI_PKTLOG_EVENT_SW; + + return pktlog_wma_post_msg(types, WMI_PDEV_PKTLOG_ENABLE_CMDID, + ini_triggered, user_triggered); +} + +static inline A_STATUS +wdi_pktlog_subscribe(struct ol_txrx_pdev_t *txrx_pdev, int32_t log_state) +{ + if (!txrx_pdev) { + printk("Invalid pdev in %s\n", __func__); + return A_ERROR; + } + if (log_state & ATH_PKTLOG_TX) { + if (wdi_event_sub(txrx_pdev, + &PKTLOG_TX_SUBSCRIBER, WDI_EVENT_TX_STATUS)) { + return A_ERROR; + } + } + if (log_state & ATH_PKTLOG_RX) { + if (wdi_event_sub(txrx_pdev, + &PKTLOG_RX_SUBSCRIBER, WDI_EVENT_RX_DESC)) { + return A_ERROR; + } + if (wdi_event_sub(txrx_pdev, + &PKTLOG_RX_REMOTE_SUBSCRIBER, + WDI_EVENT_RX_DESC_REMOTE)) { + return A_ERROR; + } + } + if (log_state & ATH_PKTLOG_RCFIND) { + if (wdi_event_sub(txrx_pdev, + &PKTLOG_RCFIND_SUBSCRIBER, + WDI_EVENT_RATE_FIND)) { + return A_ERROR; + } + } + if (log_state & ATH_PKTLOG_RCUPDATE) { + if (wdi_event_sub(txrx_pdev, + &PKTLOG_RCUPDATE_SUBSCRIBER, + WDI_EVENT_RATE_UPDATE)) { + return A_ERROR; + } + } + if (log_state & ATH_PKTLOG_SW_EVENT) { + if (wdi_event_sub(txrx_pdev, + &PKTLOG_SW_EVENT_SUBSCRIBER, + WDI_EVENT_SW_EVENT)) { + return A_ERROR; + } + } + + return A_OK; +} + +void pktlog_callback(void *pdev, enum WDI_EVENT event, void *log_data) +{ + switch (event) { + case WDI_EVENT_TX_STATUS: + { + /* + * process TX message + */ + if (process_tx_info(pdev, log_data)) { + printk("Unable to process TX info\n"); + return; + } + break; + } + case WDI_EVENT_RX_DESC: + { + /* + * process RX message for local frames + */ + if (process_rx_info(pdev, log_data)) { + printk("Unable to process RX info\n"); + return; + } + break; + } + case WDI_EVENT_RX_DESC_REMOTE: + { + /* + * process RX message for remote frames + */ + if (process_rx_info_remote(pdev, log_data)) { + printk("Unable to process RX info\n"); + return; + } + break; + } + case WDI_EVENT_RATE_FIND: + { + /* + * process RATE_FIND message + */ + if (process_rate_find(pdev, log_data)) { + printk("Unable to process RC_FIND info\n"); + return; + } + break; + } + case WDI_EVENT_RATE_UPDATE: + { + /* + * process RATE_UPDATE message + */ + if (process_rate_update(pdev, log_data)) { + printk("Unable to process RC_UPDATE\n"); + return; + } + break; + } + case WDI_EVENT_SW_EVENT: + { + /* + * process SW EVENT message + */ + if (process_sw_event(pdev, log_data)) { + printk("Unable to process SW_EVENT\n"); + return; + } + break; + } + default: + break; + } +} + +A_STATUS +wdi_pktlog_unsubscribe(struct ol_txrx_pdev_t *txrx_pdev, uint32_t log_state) +{ + if (log_state & ATH_PKTLOG_TX) { + if (wdi_event_unsub(txrx_pdev, + &PKTLOG_TX_SUBSCRIBER, + WDI_EVENT_TX_STATUS)) { + return A_ERROR; + } + } + if (log_state & ATH_PKTLOG_RX) { + if (wdi_event_unsub(txrx_pdev, + &PKTLOG_RX_SUBSCRIBER, WDI_EVENT_RX_DESC)) { + return A_ERROR; + } + if (wdi_event_unsub(txrx_pdev, + &PKTLOG_RX_REMOTE_SUBSCRIBER, + WDI_EVENT_RX_DESC_REMOTE)) { + return A_ERROR; + } + } + if (log_state & ATH_PKTLOG_RCFIND) { + if (wdi_event_unsub(txrx_pdev, + &PKTLOG_RCFIND_SUBSCRIBER, + WDI_EVENT_RATE_FIND)) { + return A_ERROR; + } + } + if (log_state & ATH_PKTLOG_RCUPDATE) { + if (wdi_event_unsub(txrx_pdev, + &PKTLOG_RCUPDATE_SUBSCRIBER, + WDI_EVENT_RATE_UPDATE)) { + return A_ERROR; + } + } + if (log_state & ATH_PKTLOG_RCUPDATE) { + if (wdi_event_unsub(txrx_pdev, + &PKTLOG_SW_EVENT_SUBSCRIBER, + WDI_EVENT_SW_EVENT)) { + return A_ERROR; + } + } + return A_OK; +} + +int pktlog_disable(struct hif_opaque_softc *scn) +{ + struct ol_txrx_pdev_t *txrx_pdev = + cds_get_context(QDF_MODULE_ID_TXRX); + struct ol_pktlog_dev_t *pl_dev; + struct ath_pktlog_info *pl_info; + uint8_t save_pktlog_state; + + if (txrx_pdev == NULL || + txrx_pdev->pl_dev == NULL || + txrx_pdev->pl_dev->pl_info == NULL) + return -EFAULT; + + pl_dev = txrx_pdev->pl_dev; + pl_info = pl_dev->pl_info; + + if (pl_info->curr_pkt_state == PKTLOG_OPR_IN_PROGRESS || + pl_info->curr_pkt_state == + PKTLOG_OPR_IN_PROGRESS_READ_START_PKTLOG_DISABLED || + pl_info->curr_pkt_state == PKTLOG_OPR_IN_PROGRESS_READ_COMPLETE || + pl_info->curr_pkt_state == + PKTLOG_OPR_IN_PROGRESS_CLEARBUFF_COMPLETE) + return -EBUSY; + + save_pktlog_state = pl_info->curr_pkt_state; + pl_info->curr_pkt_state = PKTLOG_OPR_IN_PROGRESS; + + if (pktlog_wma_post_msg(0, WMI_PDEV_PKTLOG_DISABLE_CMDID, 0, 0)) { + pl_info->curr_pkt_state = PKTLOG_OPR_NOT_IN_PROGRESS; + printk("Failed to disable pktlog in target\n"); + return -1; + } + + if (pl_dev->is_pktlog_cb_subscribed && + wdi_pktlog_unsubscribe(txrx_pdev, pl_info->log_state)) { + pl_info->curr_pkt_state = PKTLOG_OPR_NOT_IN_PROGRESS; + printk("Cannot unsubscribe pktlog from the WDI\n"); + return -1; + } + pl_dev->is_pktlog_cb_subscribed = false; + pl_dev->is_pktlog_cb_subscribed = false; + if (save_pktlog_state == PKTLOG_OPR_IN_PROGRESS_READ_START) + pl_info->curr_pkt_state = + PKTLOG_OPR_IN_PROGRESS_READ_START_PKTLOG_DISABLED; + else + pl_info->curr_pkt_state = PKTLOG_OPR_NOT_IN_PROGRESS; + return 0; +} + +void pktlog_init(struct hif_opaque_softc *scn) +{ + struct ath_pktlog_info *pl_info; + ol_txrx_pdev_handle pdev_txrx_handle; + pdev_txrx_handle = cds_get_context(QDF_MODULE_ID_TXRX); + + if (pdev_txrx_handle == NULL || + pdev_txrx_handle->pl_dev == NULL || + pdev_txrx_handle->pl_dev->pl_info == NULL) + return; + + pl_info = pdev_txrx_handle->pl_dev->pl_info; + + OS_MEMZERO(pl_info, sizeof(*pl_info)); + PKTLOG_LOCK_INIT(pl_info); + mutex_init(&pl_info->pktlog_mutex); + + pl_info->buf_size = PKTLOG_DEFAULT_BUFSIZE; + pl_info->buf = NULL; + pl_info->log_state = 0; + pl_info->init_saved_state = 0; + pl_info->curr_pkt_state = PKTLOG_OPR_NOT_IN_PROGRESS; + pl_info->sack_thr = PKTLOG_DEFAULT_SACK_THR; + pl_info->tail_length = PKTLOG_DEFAULT_TAIL_LENGTH; + pl_info->thruput_thresh = PKTLOG_DEFAULT_THRUPUT_THRESH; + pl_info->per_thresh = PKTLOG_DEFAULT_PER_THRESH; + pl_info->phyerr_thresh = PKTLOG_DEFAULT_PHYERR_THRESH; + pl_info->trigger_interval = PKTLOG_DEFAULT_TRIGGER_INTERVAL; + pl_info->pktlen = 0; + pl_info->start_time_thruput = 0; + pl_info->start_time_per = 0; + pdev_txrx_handle->pl_dev->vendor_cmd_send = false; + + PKTLOG_TX_SUBSCRIBER.callback = pktlog_callback; + PKTLOG_RX_SUBSCRIBER.callback = pktlog_callback; + PKTLOG_RX_REMOTE_SUBSCRIBER.callback = pktlog_callback; + PKTLOG_RCFIND_SUBSCRIBER.callback = pktlog_callback; + PKTLOG_RCUPDATE_SUBSCRIBER.callback = pktlog_callback; + PKTLOG_SW_EVENT_SUBSCRIBER.callback = pktlog_callback; +} + +static int __pktlog_enable(struct hif_opaque_softc *scn, int32_t log_state, + bool ini_triggered, uint8_t user_triggered, + uint32_t is_iwpriv_command) +{ + struct ol_pktlog_dev_t *pl_dev; + struct ath_pktlog_info *pl_info; + struct ol_txrx_pdev_t *txrx_pdev; + int error; + + if (!scn) { + printk("%s: Invalid scn context\n", __func__); + ASSERT(0); + return -1; + } + + txrx_pdev = cds_get_context(QDF_MODULE_ID_TXRX); + if (!txrx_pdev) { + printk("%s: Invalid txrx_pdev context\n", __func__); + ASSERT(0); + return -1; + } + + pl_dev = txrx_pdev->pl_dev; + if (!pl_dev) { + printk("%s: Invalid pktlog context\n", __func__); + ASSERT(0); + return -1; + } + + pl_info = pl_dev->pl_info; + + if (!pl_info) + return 0; + + if (pl_info->curr_pkt_state < PKTLOG_OPR_IN_PROGRESS_CLEARBUFF_COMPLETE) + return -EBUSY; + + pl_info->curr_pkt_state = PKTLOG_OPR_IN_PROGRESS; + /* is_iwpriv_command : 0 indicates its a vendor command + * log_state: 0 indicates pktlog disable command + * vendor_cmd_send flag; false means no vendor pktlog enable + * command was sent previously + */ + if (is_iwpriv_command == 0 && log_state == 0 && + pl_dev->vendor_cmd_send == false) { + pl_info->curr_pkt_state = PKTLOG_OPR_NOT_IN_PROGRESS; + return 0; + } + + if (!pl_dev->tgt_pktlog_alloced) { + if (pl_info->buf == NULL) { + error = pktlog_alloc_buf(scn); + + if (error != 0) { + pl_info->curr_pkt_state = + PKTLOG_OPR_NOT_IN_PROGRESS; + return error; + } + + if (!pl_info->buf) { + pl_info->curr_pkt_state = + PKTLOG_OPR_NOT_IN_PROGRESS; + printk("%s: pktlog buf alloc failed\n", + __func__); + ASSERT(0); + return -1; + } + + } + + spin_lock_bh(&pl_info->log_lock); + pl_info->buf->bufhdr.version = CUR_PKTLOG_VER; + pl_info->buf->bufhdr.magic_num = PKTLOG_MAGIC_NUM; + pl_info->buf->wr_offset = 0; + pl_info->buf->rd_offset = -1; + /* These below variables are used by per packet stats*/ + pl_info->buf->bytes_written = 0; + pl_info->buf->msg_index = 1; + pl_info->buf->offset = PKTLOG_READ_OFFSET; + spin_unlock_bh(&pl_info->log_lock); + + pl_info->start_time_thruput = os_get_timestamp(); + pl_info->start_time_per = pl_info->start_time_thruput; + + pl_dev->tgt_pktlog_alloced = true; + } + + if (log_state != 0) { + /* WDI subscribe */ + if ((!pl_dev->is_pktlog_cb_subscribed) && + wdi_pktlog_subscribe(txrx_pdev, log_state)) { + pl_info->curr_pkt_state = PKTLOG_OPR_NOT_IN_PROGRESS; + printk("Unable to subscribe to the WDI %s\n", __func__); + return -1; + } + pl_dev->is_pktlog_cb_subscribed = true; + /* WMI command to enable pktlog on the firmware */ + if (pktlog_enable_tgt(scn, log_state, ini_triggered, + user_triggered)) { + pl_info->curr_pkt_state = PKTLOG_OPR_NOT_IN_PROGRESS; + printk("Device cannot be enabled, %s\n", __func__); + return -1; + } + + if (is_iwpriv_command == 0) + pl_dev->vendor_cmd_send = true; + } else { + pl_info->curr_pkt_state = PKTLOG_OPR_NOT_IN_PROGRESS; + pl_dev->pl_funcs->pktlog_disable(scn); + if (is_iwpriv_command == 0) + pl_dev->vendor_cmd_send = false; + } + + pl_info->log_state = log_state; + pl_info->curr_pkt_state = PKTLOG_OPR_NOT_IN_PROGRESS; + return 0; +} + +int pktlog_enable(struct hif_opaque_softc *scn, int32_t log_state, + bool ini_triggered, uint8_t user_triggered, + uint32_t is_iwpriv_command) +{ + struct ol_pktlog_dev_t *pl_dev; + struct ath_pktlog_info *pl_info; + struct ol_txrx_pdev_t *txrx_pdev; + int error; + + if (!scn) { + pr_err("%s: Invalid scn context\n", __func__); + ASSERT(0); + return -EINVAL; + } + + txrx_pdev = cds_get_context(QDF_MODULE_ID_TXRX); + if (!txrx_pdev) { + pr_err("%s: Invalid txrx_pdev context\n", __func__); + ASSERT(0); + return -EINVAL; + } + + pl_dev = txrx_pdev->pl_dev; + if (!pl_dev) { + pr_err("%s: Invalid pktlog context\n", __func__); + ASSERT(0); + return -EINVAL; + } + + pl_info = pl_dev->pl_info; + + if (!pl_info) + return 0; + + + mutex_lock(&pl_info->pktlog_mutex); + error = __pktlog_enable(scn, log_state, ini_triggered, + user_triggered, is_iwpriv_command); + mutex_unlock(&pl_info->pktlog_mutex); + return error; +} + +#define ONE_MEGABYTE (1024 * 1024) +#define MAX_ALLOWED_PKTLOG_SIZE (16 * ONE_MEGABYTE) + +static int __pktlog_setsize(struct hif_opaque_softc *scn, int32_t size) +{ + ol_txrx_pdev_handle pdev_txrx_handle = + cds_get_context(QDF_MODULE_ID_TXRX); + struct ol_pktlog_dev_t *pl_dev; + struct ath_pktlog_info *pl_info; + + if (pdev_txrx_handle == NULL || + pdev_txrx_handle->pl_dev == NULL || + pdev_txrx_handle->pl_dev->pl_info == NULL) + return -EFAULT; + + pl_dev = pdev_txrx_handle->pl_dev; + pl_info = pl_dev->pl_info; + + if (pl_info->curr_pkt_state < PKTLOG_OPR_NOT_IN_PROGRESS) + return -EBUSY; + + pl_info->curr_pkt_state = PKTLOG_OPR_IN_PROGRESS; + + if (size < ONE_MEGABYTE || size > MAX_ALLOWED_PKTLOG_SIZE) { + qdf_print("%s: Cannot Set Pktlog Buffer size of %d bytes." + "Min required is %d MB and Max allowed is %d MB.\n", + __func__, size, (ONE_MEGABYTE/ONE_MEGABYTE), + (MAX_ALLOWED_PKTLOG_SIZE/ONE_MEGABYTE)); + pl_info->curr_pkt_state = PKTLOG_OPR_NOT_IN_PROGRESS; + return -EINVAL; + } + + if (size == pl_info->buf_size) { + pl_info->curr_pkt_state = PKTLOG_OPR_NOT_IN_PROGRESS; + qdf_print("%s: Pktlog Buff Size is already of same size.", + __func__); + return 0; + } + + if (pl_info->log_state) { + pl_info->curr_pkt_state = PKTLOG_OPR_NOT_IN_PROGRESS; + qdf_print("%s: Logging should be disabled before changing" + "buffer size.", __func__); + return -EINVAL; + } + + spin_lock_bh(&pl_info->log_lock); + if (pl_info->buf != NULL) { + if (pl_dev->is_pktlog_cb_subscribed && + wdi_pktlog_unsubscribe(pdev_txrx_handle, + pl_info->log_state)) { + pl_info->curr_pkt_state = PKTLOG_OPR_NOT_IN_PROGRESS; + printk("Cannot unsubscribe pktlog from the WDI\n"); + spin_unlock_bh(&pl_info->log_lock); + return -EFAULT; + } + pktlog_release_buf(scn); + pl_dev->is_pktlog_cb_subscribed = false; + pl_dev->tgt_pktlog_alloced = false; + } + + if (size != 0) { + qdf_print("%s: New Pktlog Buff Size is %d\n", __func__, size); + pl_info->buf_size = size; + } + pl_info->curr_pkt_state = PKTLOG_OPR_NOT_IN_PROGRESS; + spin_unlock_bh(&pl_info->log_lock); + return 0; +} + +int pktlog_setsize(struct hif_opaque_softc *scn, int32_t size) +{ + int status; + ol_txrx_pdev_handle pdev_txrx_handle = + cds_get_context(QDF_MODULE_ID_TXRX); + struct ol_pktlog_dev_t *pl_dev; + struct ath_pktlog_info *pl_info; + + if (pdev_txrx_handle == NULL || + pdev_txrx_handle->pl_dev == NULL || + pdev_txrx_handle->pl_dev->pl_info == NULL) + return -EFAULT; + + pl_dev = pdev_txrx_handle->pl_dev; + pl_info = pl_dev->pl_info; + + mutex_lock(&pl_info->pktlog_mutex); + status = __pktlog_setsize(scn, size); + mutex_unlock(&pl_info->pktlog_mutex); + + return status; +} + +int pktlog_clearbuff(struct hif_opaque_softc *scn, bool clear_buff) +{ + ol_txrx_pdev_handle pdev_txrx_handle = + cds_get_context(QDF_MODULE_ID_TXRX); + struct ol_pktlog_dev_t *pl_dev; + struct ath_pktlog_info *pl_info; + uint8_t save_pktlog_state; + + if (pdev_txrx_handle == NULL || + pdev_txrx_handle->pl_dev == NULL || + pdev_txrx_handle->pl_dev->pl_info == NULL) + return -EFAULT; + + pl_dev = pdev_txrx_handle->pl_dev; + pl_info = pl_dev->pl_info; + + if (!clear_buff) + return -EINVAL; + + if (pl_info->curr_pkt_state < PKTLOG_OPR_IN_PROGRESS_READ_COMPLETE || + pl_info->curr_pkt_state == + PKTLOG_OPR_IN_PROGRESS_CLEARBUFF_COMPLETE) + return -EBUSY; + + save_pktlog_state = pl_info->curr_pkt_state; + pl_info->curr_pkt_state = PKTLOG_OPR_IN_PROGRESS; + + if (pl_info->log_state) { + pl_info->curr_pkt_state = PKTLOG_OPR_NOT_IN_PROGRESS; + qdf_print("%s: Logging should be disabled before clearing " + "pktlog buffer.", __func__); + return -EINVAL; + } + + if (pl_info->buf != NULL) { + if (pl_info->buf_size > 0) { + qdf_print("%s: pktlog buffer is cleared.", __func__); + memset(pl_info->buf, 0, pl_info->buf_size); + pl_dev->is_pktlog_cb_subscribed = false; + pl_dev->tgt_pktlog_alloced = false; + pl_info->buf->rd_offset = -1; + } else { + pl_info->curr_pkt_state = PKTLOG_OPR_NOT_IN_PROGRESS; + qdf_print("%s: pktlog buffer size is not proper. " + "Existing Buf size %d", __func__, pl_info->buf_size); + return -EFAULT; + } + } else { + pl_info->curr_pkt_state = PKTLOG_OPR_NOT_IN_PROGRESS; + qdf_print("%s: pktlog buff is NULL", __func__); + return -EFAULT; + } + + if (save_pktlog_state == PKTLOG_OPR_IN_PROGRESS_READ_COMPLETE) + pl_info->curr_pkt_state = + PKTLOG_OPR_IN_PROGRESS_CLEARBUFF_COMPLETE; + else + pl_info->curr_pkt_state = PKTLOG_OPR_NOT_IN_PROGRESS; + + return 0; +} + +/** + * pktlog_process_fw_msg() - process packetlog message + * @buff: buffer + * + * Return: None + */ +void pktlog_process_fw_msg(uint32_t *buff) +{ + uint32_t *pl_hdr; + uint32_t log_type; + struct ol_txrx_pdev_t *txrx_pdev = cds_get_context(QDF_MODULE_ID_TXRX); + + if (!txrx_pdev) { + qdf_print("%s: txrx_pdev is NULL", __func__); + return; + } + + pl_hdr = buff; + log_type = + (*(pl_hdr + 1) & ATH_PKTLOG_HDR_LOG_TYPE_MASK) >> + ATH_PKTLOG_HDR_LOG_TYPE_SHIFT; + if ((log_type == PKTLOG_TYPE_TX_CTRL) + || (log_type == PKTLOG_TYPE_TX_STAT) + || (log_type == PKTLOG_TYPE_TX_MSDU_ID) + || (log_type == PKTLOG_TYPE_TX_FRM_HDR) + || (log_type == PKTLOG_TYPE_TX_VIRT_ADDR)) + wdi_event_handler(WDI_EVENT_TX_STATUS, + txrx_pdev, pl_hdr); + else if (log_type == PKTLOG_TYPE_RC_FIND) + wdi_event_handler(WDI_EVENT_RATE_FIND, + txrx_pdev, pl_hdr); + else if (log_type == PKTLOG_TYPE_RC_UPDATE) + wdi_event_handler(WDI_EVENT_RATE_UPDATE, + txrx_pdev, pl_hdr); + else if (log_type == PKTLOG_TYPE_RX_STAT) + wdi_event_handler(WDI_EVENT_RX_DESC, + txrx_pdev, pl_hdr); + else if (log_type == PKTLOG_TYPE_SW_EVENT) + wdi_event_handler(WDI_EVENT_SW_EVENT, + txrx_pdev, pl_hdr); + +} + +#if defined(QCA_WIFI_3_0_ADRASTEA) +/** + * pktlog_t2h_msg_handler() - Target to host message handler + * @context: pdev context + * @pkt: HTC packet + * + * Return: None + */ +static void pktlog_t2h_msg_handler(void *context, HTC_PACKET *pkt) +{ + struct ol_pktlog_dev_t *pdev = (struct ol_pktlog_dev_t *)context; + qdf_nbuf_t pktlog_t2h_msg = (qdf_nbuf_t) pkt->pPktContext; + uint32_t *msg_word; + + /* check for successful message reception */ + if (pkt->Status != A_OK) { + if (pkt->Status != A_ECANCELED) + pdev->htc_err_cnt++; + qdf_nbuf_free(pktlog_t2h_msg); + return; + } + + /* confirm alignment */ + qdf_assert((((unsigned long)qdf_nbuf_data(pktlog_t2h_msg)) & 0x3) == 0); + + msg_word = (uint32_t *) qdf_nbuf_data(pktlog_t2h_msg); + pktlog_process_fw_msg(msg_word); + + qdf_nbuf_free(pktlog_t2h_msg); +} + +/** + * pktlog_tx_resume_handler() - resume callback + * @context: pdev context + * + * Return: None + */ +static void pktlog_tx_resume_handler(void *context) +{ + qdf_print("%s: Not expected", __func__); + qdf_assert(0); +} + +/** + * pktlog_h2t_send_complete() - send complete indication + * @context: pdev context + * @htc_pkt: HTC packet + * + * Return: None + */ +static void pktlog_h2t_send_complete(void *context, HTC_PACKET *htc_pkt) +{ + qdf_print("%s: Not expected", __func__); + qdf_assert(0); +} + +/** + * pktlog_h2t_full() - queue full indication + * @context: pdev context + * @pkt: HTC packet + * + * Return: HTC action + */ +static HTC_SEND_FULL_ACTION pktlog_h2t_full(void *context, HTC_PACKET *pkt) +{ + return HTC_SEND_FULL_KEEP; +} + +/** + * pktlog_htc_connect_service() - create new endpoint for packetlog + * @pdev - pktlog pdev + * + * Return: 0 for success/failure + */ +static int pktlog_htc_connect_service(struct ol_pktlog_dev_t *pdev) +{ + HTC_SERVICE_CONNECT_REQ connect; + HTC_SERVICE_CONNECT_RESP response; + A_STATUS status; + + qdf_mem_set(&connect, sizeof(connect), 0); + qdf_mem_set(&response, sizeof(response), 0); + + connect.pMetaData = NULL; + connect.MetaDataLength = 0; + connect.EpCallbacks.pContext = pdev; + connect.EpCallbacks.EpTxComplete = pktlog_h2t_send_complete; + connect.EpCallbacks.EpTxCompleteMultiple = NULL; + connect.EpCallbacks.EpRecv = pktlog_t2h_msg_handler; + connect.EpCallbacks.ep_resume_tx_queue = pktlog_tx_resume_handler; + + /* rx buffers currently are provided by HIF, not by EpRecvRefill */ + connect.EpCallbacks.EpRecvRefill = NULL; + connect.EpCallbacks.RecvRefillWaterMark = 1; + /* N/A, fill is done by HIF */ + + connect.EpCallbacks.EpSendFull = pktlog_h2t_full; + /* + * Specify how deep to let a queue get before htc_send_pkt will + * call the EpSendFull function due to excessive send queue depth. + */ + connect.MaxSendQueueDepth = PKTLOG_MAX_SEND_QUEUE_DEPTH; + + /* disable flow control for HTT data message service */ + connect.ConnectionFlags |= HTC_CONNECT_FLAGS_DISABLE_CREDIT_FLOW_CTRL; + + /* connect to control service */ + connect.service_id = PACKET_LOG_SVC; + + status = htc_connect_service(pdev->htc_pdev, &connect, &response); + + if (status != A_OK) { + pdev->mt_pktlog_enabled = false; + return -EIO; /* failure */ + } + + pdev->htc_endpoint = response.Endpoint; + pdev->mt_pktlog_enabled = true; + + return 0; /* success */ +} + +/** + * pktlog_htc_attach() - attach pktlog HTC service + * + * Return: 0 for success/failure + */ +int pktlog_htc_attach(void) +{ + struct ol_txrx_pdev_t *txrx_pdev = cds_get_context(QDF_MODULE_ID_TXRX); + struct ol_pktlog_dev_t *pdev = NULL; + void *htc_pdev = cds_get_context(QDF_MODULE_ID_HTC); + + if ((!txrx_pdev) || (!txrx_pdev->pl_dev) || (!htc_pdev)) + return -EINVAL; + + pdev = txrx_pdev->pl_dev; + pdev->htc_pdev = htc_pdev; + return pktlog_htc_connect_service(pdev); +} +#else +int pktlog_htc_attach(void) +{ + struct ol_txrx_pdev_t *txrx_pdev = cds_get_context(QDF_MODULE_ID_TXRX); + struct ol_pktlog_dev_t *pdev = NULL; + + if (!txrx_pdev) + return -EINVAL; + pdev = txrx_pdev->pl_dev; + pdev->mt_pktlog_enabled = false; + return 0; +} +#endif +#endif /* REMOVE_PKT_LOG */ diff --git a/drivers/staging/qcacld-3.0/core/utils/pktlog/pktlog_internal.c b/drivers/staging/qcacld-3.0/core/utils/pktlog/pktlog_internal.c new file mode 100644 index 0000000000000000000000000000000000000000..3299102963bb8fea97076cacd3940ed9873e46d2 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/utils/pktlog/pktlog_internal.c @@ -0,0 +1,883 @@ +/* + * Copyright (c) 2013-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* + * + * 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 REMOVE_PKT_LOG +#include "ol_txrx_types.h" +#include "ol_htt_tx_api.h" +#include "ol_tx_desc.h" +#include "qdf_mem.h" +#include "htt.h" +#include "htt_internal.h" +#include "pktlog_ac_i.h" +#include "wma_api.h" +#include "wlan_logging_sock_svc.h" + +#define TX_DESC_ID_LOW_MASK 0xffff +#define TX_DESC_ID_LOW_SHIFT 0 +#define TX_DESC_ID_HIGH_MASK 0xffff0000 +#define TX_DESC_ID_HIGH_SHIFT 16 + +void pktlog_getbuf_intsafe(struct ath_pktlog_arg *plarg) +{ + struct ath_pktlog_buf *log_buf; + int32_t buf_size; + struct ath_pktlog_hdr *log_hdr; + int32_t cur_wr_offset; + char *log_ptr; + struct ath_pktlog_info *pl_info; + uint16_t log_type; + size_t log_size; + uint32_t flags; +#ifdef HELIUMPLUS + uint8_t mac_id; +#endif + + if (!plarg) { + printk("Invalid parg in %s\n", __func__); + return; + } + + pl_info = plarg->pl_info; +#ifdef HELIUMPLUS + mac_id = plarg->macId; + log_type = plarg->log_type; +#else + log_type = plarg->log_type; +#endif + log_size = plarg->log_size; + log_buf = pl_info->buf; + flags = plarg->flags; + + if (!log_buf) { + printk("Invalid log_buf in %s\n", __func__); + return; + } + buf_size = pl_info->buf_size; + cur_wr_offset = log_buf->wr_offset; + /* Move read offset to the next entry if there is a buffer overlap */ + if (log_buf->rd_offset >= 0) { + if ((cur_wr_offset <= log_buf->rd_offset) + && (cur_wr_offset + sizeof(struct ath_pktlog_hdr)) > + log_buf->rd_offset) { + PKTLOG_MOV_RD_IDX(log_buf->rd_offset, log_buf, + buf_size); + } + } else { + log_buf->rd_offset = cur_wr_offset; + } + + log_hdr = (struct ath_pktlog_hdr *)(log_buf->log_data + cur_wr_offset); + + log_hdr->flags = flags; +#ifdef HELIUMPLUS + log_hdr->macId = mac_id; + log_hdr->log_type = log_type; +#else + log_hdr->log_type = log_type; +#endif + log_hdr->size = (uint16_t) log_size; + log_hdr->missed_cnt = plarg->missed_cnt; + log_hdr->timestamp = plarg->timestamp; +#ifdef HELIUMPLUS + log_hdr->type_specific_data = plarg->type_specific_data; +#endif + cur_wr_offset += sizeof(*log_hdr); + + if ((buf_size - cur_wr_offset) < log_size) { + while ((cur_wr_offset <= log_buf->rd_offset) + && (log_buf->rd_offset < buf_size)) { + PKTLOG_MOV_RD_IDX(log_buf->rd_offset, log_buf, + buf_size); + } + cur_wr_offset = 0; + } + + while ((cur_wr_offset <= log_buf->rd_offset) + && (cur_wr_offset + log_size) > log_buf->rd_offset) { + PKTLOG_MOV_RD_IDX(log_buf->rd_offset, log_buf, buf_size); + } + + log_ptr = &(log_buf->log_data[cur_wr_offset]); + cur_wr_offset += log_hdr->size; + + log_buf->wr_offset = ((buf_size - cur_wr_offset) >= + sizeof(struct ath_pktlog_hdr)) ? cur_wr_offset : + 0; + + plarg->buf = log_ptr; +} + +char *pktlog_getbuf(struct ol_pktlog_dev_t *pl_dev, + struct ath_pktlog_info *pl_info, + size_t log_size, struct ath_pktlog_hdr *pl_hdr) +{ + struct ath_pktlog_arg plarg = { 0, }; + uint8_t flags = 0; + + plarg.pl_info = pl_info; +#ifdef HELIUMPLUS + plarg.macId = pl_hdr->macId; + plarg.log_type = pl_hdr->log_type; +#else + plarg.log_type = pl_hdr->log_type; +#endif + plarg.log_size = log_size; + plarg.flags = pl_hdr->flags; + plarg.missed_cnt = pl_hdr->missed_cnt; + plarg.timestamp = pl_hdr->timestamp; +#ifdef HELIUMPLUS + plarg.type_specific_data = pl_hdr->type_specific_data; +#endif + if (flags & PHFLAGS_INTERRUPT_CONTEXT) { + /* + * We are already in interupt context, no need to make it + * intsafe. call the function directly. + */ + pktlog_getbuf_intsafe(&plarg); + } else { + PKTLOG_LOCK(pl_info); + pktlog_getbuf_intsafe(&plarg); + PKTLOG_UNLOCK(pl_info); + } + + return plarg.buf; +} + +static struct txctl_frm_hdr frm_hdr; + +#ifndef HELIUMPLUS +static void process_ieee_hdr(void *data) +{ + uint8_t dir; + struct ieee80211_frame *wh = (struct ieee80211_frame *)(data); + + frm_hdr.framectrl = *(uint16_t *) (wh->i_fc); + frm_hdr.seqctrl = *(uint16_t *) (wh->i_seq); + dir = (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK); + + if (dir == IEEE80211_FC1_DIR_TODS) { + frm_hdr.bssid_tail = + (wh->i_addr1[IEEE80211_ADDR_LEN - 2] << 8) | (wh-> + i_addr1 + [IEEE80211_ADDR_LEN + - 1]); + frm_hdr.sa_tail = + (wh->i_addr2[IEEE80211_ADDR_LEN - 2] << 8) | (wh-> + i_addr2 + [IEEE80211_ADDR_LEN + - 1]); + frm_hdr.da_tail = + (wh->i_addr3[IEEE80211_ADDR_LEN - 2] << 8) | (wh-> + i_addr3 + [IEEE80211_ADDR_LEN + - 1]); + } else if (dir == IEEE80211_FC1_DIR_FROMDS) { + frm_hdr.bssid_tail = + (wh->i_addr2[IEEE80211_ADDR_LEN - 2] << 8) | (wh-> + i_addr2 + [IEEE80211_ADDR_LEN + - 1]); + frm_hdr.sa_tail = + (wh->i_addr3[IEEE80211_ADDR_LEN - 2] << 8) | (wh-> + i_addr3 + [IEEE80211_ADDR_LEN + - 1]); + frm_hdr.da_tail = + (wh->i_addr1[IEEE80211_ADDR_LEN - 2] << 8) | (wh-> + i_addr1 + [IEEE80211_ADDR_LEN + - 1]); + } else { + frm_hdr.bssid_tail = + (wh->i_addr3[IEEE80211_ADDR_LEN - 2] << 8) | (wh-> + i_addr3 + [IEEE80211_ADDR_LEN + - 1]); + frm_hdr.sa_tail = + (wh->i_addr2[IEEE80211_ADDR_LEN - 2] << 8) | (wh-> + i_addr2 + [IEEE80211_ADDR_LEN + - 1]); + frm_hdr.da_tail = + (wh->i_addr1[IEEE80211_ADDR_LEN - 2] << 8) | (wh-> + i_addr1 + [IEEE80211_ADDR_LEN + - 1]); + } +} + +/** + * fill_ieee80211_hdr_data() - fill ieee802.11 data header + * @txrx_pdev: txrx pdev + * @pl_msdu_info: msdu info + * @data: data received from event + * + * Return: none + */ +static void +fill_ieee80211_hdr_data(struct ol_txrx_pdev_t *txrx_pdev, + struct ath_pktlog_msdu_info *pl_msdu_info, void *data) +{ + uint32_t i; + uint32_t *htt_tx_desc; + struct ol_tx_desc_t *tx_desc; + uint8_t msdu_id_offset = MSDU_ID_INFO_ID_OFFSET; + uint16_t tx_desc_id; + uint32_t *msdu_id_info = (uint32_t *) + ((void *)data + sizeof(struct ath_pktlog_hdr)); + uint32_t *msdu_id = (uint32_t *) ((char *)msdu_id_info + + msdu_id_offset); + uint8_t *addr, *vap_addr; + uint8_t vdev_id; + qdf_nbuf_t netbuf; + uint32_t len; + + + pl_msdu_info->num_msdu = *msdu_id_info; + pl_msdu_info->priv_size = sizeof(uint32_t) * + pl_msdu_info->num_msdu + sizeof(uint32_t); + + for (i = 0; i < pl_msdu_info->num_msdu; i++) { + /* + * Handle big endianness + * Increment msdu_id once after retrieving + * lower 16 bits and uppper 16 bits + */ + if (!(i % 2)) { + tx_desc_id = ((*msdu_id & TX_DESC_ID_LOW_MASK) + >> TX_DESC_ID_LOW_SHIFT); + } else { + tx_desc_id = ((*msdu_id & TX_DESC_ID_HIGH_MASK) + >> TX_DESC_ID_HIGH_SHIFT); + msdu_id += 1; + } + tx_desc = ol_tx_desc_find(txrx_pdev, tx_desc_id); + qdf_assert(tx_desc); + netbuf = tx_desc->netbuf; + htt_tx_desc = (uint32_t *) tx_desc->htt_tx_desc; + qdf_assert(htt_tx_desc); + + qdf_nbuf_peek_header(netbuf, &addr, &len); + + if (len < (2 * IEEE80211_ADDR_LEN)) { + qdf_print("TX frame does not have a valid address\n"); + return; + } + /* Adding header information for the TX data frames */ + vdev_id = (uint8_t) (*(htt_tx_desc + + HTT_TX_VDEV_ID_WORD) >> + HTT_TX_VDEV_ID_SHIFT) & + HTT_TX_VDEV_ID_MASK; + + vap_addr = wma_get_vdev_address_by_vdev_id(vdev_id); + + frm_hdr.da_tail = (addr[IEEE80211_ADDR_LEN - 2] << 8) | + (addr[IEEE80211_ADDR_LEN - 1]); + frm_hdr.sa_tail = + (addr[2 * IEEE80211_ADDR_LEN - 2] << 8) | + (addr[2 * IEEE80211_ADDR_LEN - 1]); + if (vap_addr) { + frm_hdr.bssid_tail = + (vap_addr[IEEE80211_ADDR_LEN - 2] << 8) | + (vap_addr[IEEE80211_ADDR_LEN - 1]); + } else { + frm_hdr.bssid_tail = 0x0000; + } + pl_msdu_info->priv.msdu_len[i] = *(htt_tx_desc + + HTT_TX_MSDU_LEN_DWORD) + & HTT_TX_MSDU_LEN_MASK; + /* + * Add more information per MSDU + * e.g., protocol information + */ + } + +} +#endif + +#ifdef HELIUMPLUS +A_STATUS process_tx_info(struct ol_txrx_pdev_t *txrx_pdev, void *data) +{ + /* + * Must include to process different types + * TX_CTL, TX_STATUS, TX_MSDU_ID, TX_FRM_HDR + */ + struct ol_pktlog_dev_t *pl_dev; + struct ath_pktlog_hdr pl_hdr; + struct ath_pktlog_info *pl_info; + uint32_t *pl_tgt_hdr; + + if (!txrx_pdev) { + printk("Invalid pdev in %s\n", __func__); + return A_ERROR; + } + qdf_assert(txrx_pdev->pl_dev); + qdf_assert(data); + pl_dev = txrx_pdev->pl_dev; + + pl_tgt_hdr = (uint32_t *) data; + /* + * Makes the short words (16 bits) portable b/w little endian + * and big endian + */ + pl_hdr.flags = (*(pl_tgt_hdr + ATH_PKTLOG_HDR_FLAGS_OFFSET) & + ATH_PKTLOG_HDR_FLAGS_MASK) >> + ATH_PKTLOG_HDR_FLAGS_SHIFT; + pl_hdr.flags |= PKTLOG_HDR_SIZE_16; + pl_hdr.missed_cnt = (*(pl_tgt_hdr + ATH_PKTLOG_HDR_MISSED_CNT_OFFSET) & + ATH_PKTLOG_HDR_MISSED_CNT_MASK) >> + ATH_PKTLOG_HDR_MISSED_CNT_SHIFT; + pl_hdr.log_type = (*(pl_tgt_hdr + ATH_PKTLOG_HDR_LOG_TYPE_OFFSET) & + ATH_PKTLOG_HDR_LOG_TYPE_MASK) >> + ATH_PKTLOG_HDR_LOG_TYPE_SHIFT; + pl_hdr.macId = (*(pl_tgt_hdr + ATH_PKTLOG_HDR_MAC_ID_OFFSET) & + ATH_PKTLOG_HDR_MAC_ID_MASK) >> + ATH_PKTLOG_HDR_MAC_ID_SHIFT; + pl_hdr.size = (*(pl_tgt_hdr + ATH_PKTLOG_HDR_SIZE_OFFSET) & + ATH_PKTLOG_HDR_SIZE_MASK) >> ATH_PKTLOG_HDR_SIZE_SHIFT; + pl_hdr.timestamp = *(pl_tgt_hdr + ATH_PKTLOG_HDR_TIMESTAMP_OFFSET); + pl_hdr.type_specific_data = + *(pl_tgt_hdr + ATH_PKTLOG_HDR_TYPE_SPECIFIC_DATA_OFFSET); + pl_info = pl_dev->pl_info; + + if (pl_hdr.log_type == PKTLOG_TYPE_TX_CTRL) { + size_t log_size = sizeof(frm_hdr) + pl_hdr.size; + void *txdesc_hdr_ctl = (void *) + pktlog_getbuf(pl_dev, pl_info, log_size, &pl_hdr); + qdf_assert(txdesc_hdr_ctl); + qdf_assert(pl_hdr.size < (370 * sizeof(u_int32_t))); + + qdf_mem_copy(txdesc_hdr_ctl, &frm_hdr, sizeof(frm_hdr)); + qdf_mem_copy((char *)txdesc_hdr_ctl + sizeof(frm_hdr), + ((void *)data + + sizeof(struct ath_pktlog_hdr)), + pl_hdr.size); + pl_hdr.size = log_size; + cds_pkt_stats_to_logger_thread(&pl_hdr, NULL, + txdesc_hdr_ctl); + } + + if (pl_hdr.log_type == PKTLOG_TYPE_TX_STAT) { + struct ath_pktlog_tx_status txstat_log; + size_t log_size = pl_hdr.size; + + txstat_log.ds_status = (void *) + pktlog_getbuf(pl_dev, pl_info, + log_size, &pl_hdr); + qdf_assert(txstat_log.ds_status); + qdf_mem_copy(txstat_log.ds_status, + ((void *)data + sizeof(struct ath_pktlog_hdr)), + pl_hdr.size); + cds_pkt_stats_to_logger_thread(&pl_hdr, NULL, + txstat_log.ds_status); + } + return A_OK; +} + +#else +A_STATUS process_tx_info(struct ol_txrx_pdev_t *txrx_pdev, void *data) +{ + /* + * Must include to process different types + * TX_CTL, TX_STATUS, TX_MSDU_ID, TX_FRM_HDR + */ + struct ol_pktlog_dev_t *pl_dev; + struct ath_pktlog_hdr pl_hdr; + struct ath_pktlog_info *pl_info; + uint32_t *pl_tgt_hdr; + + if (!txrx_pdev) { + qdf_print("Invalid pdev in %s\n", __func__); + return A_ERROR; + } + qdf_assert(txrx_pdev->pl_dev); + qdf_assert(data); + pl_dev = txrx_pdev->pl_dev; + + pl_tgt_hdr = (uint32_t *) data; + /* + * Makes the short words (16 bits) portable b/w little endian + * and big endian + */ + pl_hdr.flags = (*(pl_tgt_hdr + ATH_PKTLOG_HDR_FLAGS_OFFSET) & + ATH_PKTLOG_HDR_FLAGS_MASK) >> + ATH_PKTLOG_HDR_FLAGS_SHIFT; + pl_hdr.missed_cnt = (*(pl_tgt_hdr + ATH_PKTLOG_HDR_MISSED_CNT_OFFSET) & + ATH_PKTLOG_HDR_MISSED_CNT_MASK) >> + ATH_PKTLOG_HDR_MISSED_CNT_SHIFT; + pl_hdr.log_type = (*(pl_tgt_hdr + ATH_PKTLOG_HDR_LOG_TYPE_OFFSET) & + ATH_PKTLOG_HDR_LOG_TYPE_MASK) >> + ATH_PKTLOG_HDR_LOG_TYPE_SHIFT; + pl_hdr.size = (*(pl_tgt_hdr + ATH_PKTLOG_HDR_SIZE_OFFSET) & + ATH_PKTLOG_HDR_SIZE_MASK) >> ATH_PKTLOG_HDR_SIZE_SHIFT; + pl_hdr.timestamp = *(pl_tgt_hdr + ATH_PKTLOG_HDR_TIMESTAMP_OFFSET); + + pl_info = pl_dev->pl_info; + + if (pl_hdr.log_type == PKTLOG_TYPE_TX_FRM_HDR) { + /* Valid only for the TX CTL */ + process_ieee_hdr(data + sizeof(pl_hdr)); + } + + if (pl_hdr.log_type == PKTLOG_TYPE_TX_VIRT_ADDR) { + A_UINT32 desc_id = (A_UINT32) + *((A_UINT32 *) (data + sizeof(pl_hdr))); + A_UINT32 vdev_id = desc_id; + + /* if the pkt log msg is for the bcn frame the vdev id + * is piggybacked in desc_id and the MSB of the desc ID + * would be set to FF + */ +#define BCN_DESC_ID 0xFF + if ((desc_id >> 24) == BCN_DESC_ID) { + void *data; + A_UINT32 buf_size; + + vdev_id &= 0x00FFFFFF; + data = wma_get_beacon_buffer_by_vdev_id(vdev_id, + &buf_size); + if (data) { + process_ieee_hdr(data); + qdf_mem_free(data); + } + } else { + /* + * TODO: get the hdr content for mgmt frames from + * Tx mgmt desc pool + */ + } + } + + if (pl_hdr.log_type == PKTLOG_TYPE_TX_CTRL) { + struct ath_pktlog_txctl txctl_log; + size_t log_size = sizeof(txctl_log.priv); + + txctl_log.txdesc_hdr_ctl = (void *)pktlog_getbuf(pl_dev, + pl_info, + log_size, + &pl_hdr); + + if (!txctl_log.txdesc_hdr_ctl) { + printk + ("failed to get buf for txctl_log.txdesc_hdr_ctl\n"); + return A_ERROR; + } + + /* + * frm hdr is currently Valid only for local frames + * Add capability to include the fmr hdr for remote frames + */ + txctl_log.priv.frm_hdr = frm_hdr; + qdf_assert(txctl_log.priv.txdesc_ctl); + qdf_mem_copy((void *)&txctl_log.priv.txdesc_ctl, + ((void *)data + sizeof(struct ath_pktlog_hdr)), + pl_hdr.size); + qdf_assert(txctl_log.txdesc_hdr_ctl); + qdf_mem_copy(txctl_log.txdesc_hdr_ctl, &txctl_log.priv, + sizeof(txctl_log.priv)); + pl_hdr.size = log_size; + cds_pkt_stats_to_logger_thread(&pl_hdr, NULL, + txctl_log.txdesc_hdr_ctl); + /* Add Protocol information and HT specific information */ + } + + if (pl_hdr.log_type == PKTLOG_TYPE_TX_STAT) { + struct ath_pktlog_tx_status txstat_log; + size_t log_size = pl_hdr.size; + + txstat_log.ds_status = (void *) + pktlog_getbuf(pl_dev, pl_info, log_size, &pl_hdr); + qdf_assert(txstat_log.ds_status); + qdf_mem_copy(txstat_log.ds_status, + ((void *)data + sizeof(struct ath_pktlog_hdr)), + pl_hdr.size); + cds_pkt_stats_to_logger_thread(&pl_hdr, NULL, + txstat_log.ds_status); + } + + if (pl_hdr.log_type == PKTLOG_TYPE_TX_MSDU_ID) { + struct ath_pktlog_msdu_info pl_msdu_info; + size_t log_size; + + qdf_mem_set(&pl_msdu_info, sizeof(pl_msdu_info), 0); + log_size = sizeof(pl_msdu_info.priv); + + if (pl_dev->mt_pktlog_enabled == false) + fill_ieee80211_hdr_data(txrx_pdev, &pl_msdu_info, data); + + pl_msdu_info.ath_msdu_info = pktlog_getbuf(pl_dev, pl_info, + log_size, &pl_hdr); + qdf_mem_copy((void *)&pl_msdu_info.priv.msdu_id_info, + ((void *)data + sizeof(struct ath_pktlog_hdr)), + sizeof(pl_msdu_info.priv.msdu_id_info)); + qdf_mem_copy(pl_msdu_info.ath_msdu_info, &pl_msdu_info.priv, + sizeof(pl_msdu_info.priv)); + cds_pkt_stats_to_logger_thread(&pl_hdr, NULL, + pl_msdu_info.ath_msdu_info); + } + return A_OK; +} +#endif + +A_STATUS process_rx_info_remote(void *pdev, void *data) +{ + struct ol_pktlog_dev_t *pl_dev; + struct ath_pktlog_info *pl_info; + struct htt_host_rx_desc_base *rx_desc; + struct ath_pktlog_hdr pl_hdr; + struct ath_pktlog_rx_info rxstat_log; + size_t log_size; + struct ol_rx_remote_data *r_data = (struct ol_rx_remote_data *)data; + qdf_nbuf_t msdu; + + if (!pdev) { + printk("Invalid pdev in %s\n", __func__); + return A_ERROR; + } + if (!r_data) { + printk("Invalid data in %s\n", __func__); + return A_ERROR; + } + pl_dev = ((struct ol_txrx_pdev_t *)pdev)->pl_dev; + pl_info = pl_dev->pl_info; + msdu = r_data->msdu; + + while (msdu) { + rx_desc = + (struct htt_host_rx_desc_base *)(qdf_nbuf_data(msdu)) - 1; + log_size = + sizeof(*rx_desc) - sizeof(struct htt_host_fw_desc_base); + + /* + * Construct the pktlog header pl_hdr + * Because desc is DMA'd to the host memory + */ + pl_hdr.flags = (1 << PKTLOG_FLG_FRM_TYPE_REMOTE_S); + pl_hdr.missed_cnt = 0; +#if defined(HELIUMPLUS) + pl_hdr.macId = r_data->mac_id; + pl_hdr.log_type = PKTLOG_TYPE_RX_STAT; + pl_hdr.flags |= PKTLOG_HDR_SIZE_16; +#else + pl_hdr.log_type = PKTLOG_TYPE_RX_STAT; +#endif + pl_hdr.size = sizeof(*rx_desc) - + sizeof(struct htt_host_fw_desc_base); +#if defined(HELIUMPLUS) + pl_hdr.timestamp = + rx_desc->ppdu_end.rx_pkt_end.phy_timestamp_1_lower_32; + pl_hdr.type_specific_data = 0xDEADAA; +#else + pl_hdr.timestamp = rx_desc->ppdu_end.tsf_timestamp; +#endif /* !defined(HELIUMPLUS) */ + rxstat_log.rx_desc = (void *)pktlog_getbuf(pl_dev, pl_info, + log_size, &pl_hdr); + qdf_mem_copy(rxstat_log.rx_desc, (void *)rx_desc + + sizeof(struct htt_host_fw_desc_base), pl_hdr.size); + cds_pkt_stats_to_logger_thread(&pl_hdr, NULL, + rxstat_log.rx_desc); + msdu = qdf_nbuf_next(msdu); + } + return A_OK; +} + +A_STATUS process_rx_info(void *pdev, void *data) +{ + struct ol_pktlog_dev_t *pl_dev; + struct ath_pktlog_info *pl_info; + struct ath_pktlog_rx_info rxstat_log; + struct ath_pktlog_hdr pl_hdr; + size_t log_size; + uint32_t *pl_tgt_hdr; + + if (!pdev) { + printk("Invalid pdev in %s", __func__); + return A_ERROR; + } + pl_dev = ((struct ol_txrx_pdev_t *)pdev)->pl_dev; + pl_info = pl_dev->pl_info; + pl_tgt_hdr = (uint32_t *) data; + pl_hdr.flags = (*(pl_tgt_hdr + ATH_PKTLOG_HDR_FLAGS_OFFSET) & + ATH_PKTLOG_HDR_FLAGS_MASK) >> + ATH_PKTLOG_HDR_FLAGS_SHIFT; + pl_hdr.missed_cnt = (*(pl_tgt_hdr + ATH_PKTLOG_HDR_MISSED_CNT_OFFSET) & + ATH_PKTLOG_HDR_MISSED_CNT_MASK) >> + ATH_PKTLOG_HDR_MISSED_CNT_SHIFT; +#ifdef HELIUMPLUS + pl_hdr.log_type = (*(pl_tgt_hdr + ATH_PKTLOG_HDR_LOG_TYPE_OFFSET) & + ATH_PKTLOG_HDR_LOG_TYPE_MASK) >> + ATH_PKTLOG_HDR_LOG_TYPE_SHIFT; + pl_hdr.macId = (*(pl_tgt_hdr + ATH_PKTLOG_HDR_MAC_ID_OFFSET) & + ATH_PKTLOG_HDR_MAC_ID_MASK) >> + ATH_PKTLOG_HDR_MAC_ID_SHIFT; + pl_hdr.flags |= PKTLOG_HDR_SIZE_16; +#else + pl_hdr.log_type = (*(pl_tgt_hdr + ATH_PKTLOG_HDR_LOG_TYPE_OFFSET) & + ATH_PKTLOG_HDR_LOG_TYPE_MASK) >> + ATH_PKTLOG_HDR_LOG_TYPE_SHIFT; +#endif + + pl_hdr.size = (*(pl_tgt_hdr + ATH_PKTLOG_HDR_SIZE_OFFSET) & + ATH_PKTLOG_HDR_SIZE_MASK) >> ATH_PKTLOG_HDR_SIZE_SHIFT; + pl_hdr.timestamp = *(pl_tgt_hdr + ATH_PKTLOG_HDR_TIMESTAMP_OFFSET); +#ifdef HELIUMPLUS + pl_hdr.type_specific_data = + *(pl_tgt_hdr + ATH_PKTLOG_HDR_TYPE_SPECIFIC_DATA_OFFSET); +#endif + log_size = pl_hdr.size; + rxstat_log.rx_desc = (void *)pktlog_getbuf(pl_dev, pl_info, + log_size, &pl_hdr); + + qdf_mem_copy(rxstat_log.rx_desc, + (void *)data + sizeof(struct ath_pktlog_hdr), pl_hdr.size); + cds_pkt_stats_to_logger_thread(&pl_hdr, NULL, rxstat_log.rx_desc); + + return A_OK; +} + +A_STATUS process_rate_find(void *pdev, void *data) +{ + struct ol_pktlog_dev_t *pl_dev; + struct ath_pktlog_hdr pl_hdr; + struct ath_pktlog_info *pl_info; + size_t log_size; + + /* + * Will be uncommented when the rate control find + * for pktlog is implemented in the firmware. + * Currently derived from the TX PPDU status + */ + struct ath_pktlog_rc_find rcf_log; + uint32_t *pl_tgt_hdr; + + if (!pdev) { + qdf_print("Invalid pdev in %s\n", __func__); + return A_ERROR; + } + if (!data) { + qdf_print("Invalid data in %s\n", __func__); + return A_ERROR; + } + + pl_tgt_hdr = (uint32_t *) data; + /* + * Makes the short words (16 bits) portable b/w little endian + * and big endian + */ + pl_hdr.flags = (*(pl_tgt_hdr + ATH_PKTLOG_HDR_FLAGS_OFFSET) & + ATH_PKTLOG_HDR_FLAGS_MASK) >> + ATH_PKTLOG_HDR_FLAGS_SHIFT; + pl_hdr.missed_cnt = (*(pl_tgt_hdr + ATH_PKTLOG_HDR_MISSED_CNT_OFFSET) & + ATH_PKTLOG_HDR_MISSED_CNT_MASK) >> + ATH_PKTLOG_HDR_MISSED_CNT_SHIFT; +#ifdef HELIUMPLUS + pl_hdr.log_type = (*(pl_tgt_hdr + ATH_PKTLOG_HDR_LOG_TYPE_OFFSET) & + ATH_PKTLOG_HDR_LOG_TYPE_MASK) >> + ATH_PKTLOG_HDR_LOG_TYPE_SHIFT; + pl_hdr.macId = (*(pl_tgt_hdr + ATH_PKTLOG_HDR_MAC_ID_OFFSET) & + ATH_PKTLOG_HDR_MAC_ID_MASK) >> + ATH_PKTLOG_HDR_MAC_ID_SHIFT; + pl_hdr.flags |= PKTLOG_HDR_SIZE_16; +#else + pl_hdr.log_type = (*(pl_tgt_hdr + ATH_PKTLOG_HDR_LOG_TYPE_OFFSET) & + ATH_PKTLOG_HDR_LOG_TYPE_MASK) >> + ATH_PKTLOG_HDR_LOG_TYPE_SHIFT; +#endif + + pl_hdr.size = (*(pl_tgt_hdr + ATH_PKTLOG_HDR_SIZE_OFFSET) & + ATH_PKTLOG_HDR_SIZE_MASK) >> ATH_PKTLOG_HDR_SIZE_SHIFT; + pl_hdr.timestamp = *(pl_tgt_hdr + ATH_PKTLOG_HDR_TIMESTAMP_OFFSET); +#ifdef HELIUMPLUS + pl_hdr.type_specific_data = + *(pl_tgt_hdr + ATH_PKTLOG_HDR_TYPE_SPECIFIC_DATA_OFFSET); +#endif + pl_dev = ((struct ol_txrx_pdev_t *)pdev)->pl_dev; + pl_info = pl_dev->pl_info; + log_size = pl_hdr.size; + rcf_log.rcFind = (void *)pktlog_getbuf(pl_dev, pl_info, + log_size, &pl_hdr); + + qdf_mem_copy(rcf_log.rcFind, + ((char *)data + sizeof(struct ath_pktlog_hdr)), + pl_hdr.size); + cds_pkt_stats_to_logger_thread(&pl_hdr, NULL, rcf_log.rcFind); + + return A_OK; +} + +A_STATUS process_sw_event(void *pdev, void *data) +{ + struct ol_pktlog_dev_t *pl_dev; + struct ath_pktlog_hdr pl_hdr; + struct ath_pktlog_info *pl_info; + size_t log_size; + + /* + * Will be uncommented when the rate control find + * for pktlog is implemented in the firmware. + * Currently derived from the TX PPDU status + */ + struct ath_pktlog_sw_event sw_event; + uint32_t *pl_tgt_hdr; + + if (!pdev) { + qdf_print("Invalid pdev in %s\n", __func__); + return A_ERROR; + } + if (!data) { + qdf_print("Invalid data in %s\n", __func__); + return A_ERROR; + } + + pl_tgt_hdr = (uint32_t *) data; + /* + * Makes the short words (16 bits) portable b/w little endian + * and big endian + */ + pl_hdr.flags = (*(pl_tgt_hdr + ATH_PKTLOG_HDR_FLAGS_OFFSET) & + ATH_PKTLOG_HDR_FLAGS_MASK) >> + ATH_PKTLOG_HDR_FLAGS_SHIFT; + pl_hdr.missed_cnt = (*(pl_tgt_hdr + ATH_PKTLOG_HDR_MISSED_CNT_OFFSET) & + ATH_PKTLOG_HDR_MISSED_CNT_MASK) >> + ATH_PKTLOG_HDR_MISSED_CNT_SHIFT; +#ifdef HELIUMPLUS + pl_hdr.log_type = (*(pl_tgt_hdr + ATH_PKTLOG_HDR_LOG_TYPE_OFFSET) & + ATH_PKTLOG_HDR_LOG_TYPE_MASK) >> + ATH_PKTLOG_HDR_LOG_TYPE_SHIFT; + pl_hdr.macId = (*(pl_tgt_hdr + ATH_PKTLOG_HDR_MAC_ID_OFFSET) & + ATH_PKTLOG_HDR_MAC_ID_MASK) >> + ATH_PKTLOG_HDR_MAC_ID_SHIFT; +#else + pl_hdr.log_type = (*(pl_tgt_hdr + ATH_PKTLOG_HDR_LOG_TYPE_OFFSET) & + ATH_PKTLOG_HDR_LOG_TYPE_MASK) >> + ATH_PKTLOG_HDR_LOG_TYPE_SHIFT; +#endif + + pl_hdr.size = (*(pl_tgt_hdr + ATH_PKTLOG_HDR_SIZE_OFFSET) & + ATH_PKTLOG_HDR_SIZE_MASK) >> ATH_PKTLOG_HDR_SIZE_SHIFT; + pl_hdr.timestamp = *(pl_tgt_hdr + ATH_PKTLOG_HDR_TIMESTAMP_OFFSET); + +#ifdef HELIUMPLUS + pl_hdr.type_specific_data = + *(pl_tgt_hdr + ATH_PKTLOG_HDR_TYPE_SPECIFIC_DATA_OFFSET); +#endif + + pl_dev = ((struct ol_txrx_pdev_t *)pdev)->pl_dev; + pl_info = pl_dev->pl_info; + log_size = pl_hdr.size; + sw_event.sw_event = (void *)pktlog_getbuf(pl_dev, pl_info, + log_size, &pl_hdr); + + qdf_mem_copy(sw_event.sw_event, + ((char *)data + sizeof(struct ath_pktlog_hdr)), + pl_hdr.size); + + return A_OK; +} + +A_STATUS process_rate_update(void *pdev, void *data) +{ + struct ol_pktlog_dev_t *pl_dev; + struct ath_pktlog_hdr pl_hdr; + size_t log_size; + struct ath_pktlog_info *pl_info; + struct ath_pktlog_rc_update rcu_log; + uint32_t *pl_tgt_hdr; + + if (!pdev) { + printk("Invalid pdev in %s\n", __func__); + return A_ERROR; + } + if (!data) { + printk("Invalid data in %s\n", __func__); + return A_ERROR; + } + pl_tgt_hdr = (uint32_t *) data; + /* + * Makes the short words (16 bits) portable b/w little endian + * and big endian + */ + pl_hdr.flags = (*(pl_tgt_hdr + ATH_PKTLOG_HDR_FLAGS_OFFSET) & + ATH_PKTLOG_HDR_FLAGS_MASK) >> + ATH_PKTLOG_HDR_FLAGS_SHIFT; + pl_hdr.missed_cnt = (*(pl_tgt_hdr + ATH_PKTLOG_HDR_MISSED_CNT_OFFSET) & + ATH_PKTLOG_HDR_MISSED_CNT_MASK) >> + ATH_PKTLOG_HDR_MISSED_CNT_SHIFT; +#ifdef HELIUMPLUS + pl_hdr.log_type = (*(pl_tgt_hdr + ATH_PKTLOG_HDR_LOG_TYPE_OFFSET) & + ATH_PKTLOG_HDR_LOG_TYPE_MASK) >> + ATH_PKTLOG_HDR_LOG_TYPE_SHIFT; + pl_hdr.macId = (*(pl_tgt_hdr + ATH_PKTLOG_HDR_MAC_ID_OFFSET) & + ATH_PKTLOG_HDR_MAC_ID_MASK) >> + ATH_PKTLOG_HDR_MAC_ID_SHIFT; + pl_hdr.flags |= PKTLOG_HDR_SIZE_16; +#else + pl_hdr.log_type = (*(pl_tgt_hdr + ATH_PKTLOG_HDR_LOG_TYPE_OFFSET) & + ATH_PKTLOG_HDR_LOG_TYPE_MASK) >> + ATH_PKTLOG_HDR_LOG_TYPE_SHIFT; +#endif + + pl_hdr.size = (*(pl_tgt_hdr + ATH_PKTLOG_HDR_SIZE_OFFSET) & + ATH_PKTLOG_HDR_SIZE_MASK) >> ATH_PKTLOG_HDR_SIZE_SHIFT; + pl_hdr.timestamp = *(pl_tgt_hdr + ATH_PKTLOG_HDR_TIMESTAMP_OFFSET); +#ifdef HELIUMPLUS + pl_hdr.type_specific_data = + *(pl_tgt_hdr + ATH_PKTLOG_HDR_TYPE_SPECIFIC_DATA_OFFSET); +#endif + pl_dev = ((struct ol_txrx_pdev_t *)pdev)->pl_dev; + log_size = pl_hdr.size; + pl_info = pl_dev->pl_info; + + /* + * Will be uncommented when the rate control update + * for pktlog is implemented in the firmware. + * Currently derived from the TX PPDU status + */ + rcu_log.txRateCtrl = (void *)pktlog_getbuf(pl_dev, pl_info, + log_size, &pl_hdr); + qdf_mem_copy(rcu_log.txRateCtrl, + ((char *)data + sizeof(struct ath_pktlog_hdr)), + pl_hdr.size); + cds_pkt_stats_to_logger_thread(&pl_hdr, NULL, rcu_log.txRateCtrl); + return A_OK; +} +#endif /*REMOVE_PKT_LOG */ diff --git a/drivers/staging/qcacld-3.0/core/utils/ptt/inc/wlan_ptt_sock_svc.h b/drivers/staging/qcacld-3.0/core/utils/ptt/inc/wlan_ptt_sock_svc.h new file mode 100644 index 0000000000000000000000000000000000000000..44587480e7ace7cfc84b4c2975344ca32777bd8d --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/utils/ptt/inc/wlan_ptt_sock_svc.h @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/****************************************************************************** +* wlan_ptt_sock_svc.c +* +******************************************************************************/ +#ifndef PTT_SOCK_SVC_H +#define PTT_SOCK_SVC_H +#include +#include +#include +#include +#include +/* + * Quarky Message Format: + * The following is the messaging protocol between Quarky and PTT Socket App. + * The totalMsgLen is the length from Radio till msgBody. The value of Radio + * is always defaulted to 0. The MsgLen is the length from msgId till msgBody. + * The length of the msgBody varies with respect to the MsgId. Buffer space + * for MsgBody is already allocated in the received buffer. So in case of READ + * we just need to populate the values in the received message and send it + * back + * +------------+-------+-------+--------+-------+---------+ + * |TotalMsgLen | Radio | MsgId | MsgLen |Status |MsgBody | + * +------------+-------+-------|--------+-------+---------+ + * <------4----><--4---><---2--><---2---><---4--><---------> + */ +/* PTT Socket App Message Ids */ +#define PTT_MSG_READ_REGISTER 0x3040 +#define PTT_MSG_WRITE_REGISTER 0x3041 +#define PTT_MSG_READ_MEMORY 0x3044 +#define PTT_MSG_WRITE_MEMORY 0x3045 +#define PTT_MSG_LOG_DUMP_DBG 0x32A1 +#define PTT_MSG_FTM_CMDS_TYPE 0x4040 +#define ANI_DRIVER_MSG_START 0x0001 +#define ANI_MSG_APP_REG_REQ (ANI_DRIVER_MSG_START + 0) +#define ANI_MSG_APP_REG_RSP (ANI_DRIVER_MSG_START + 1) +#define ANI_MSG_OEM_DATA_REQ (ANI_DRIVER_MSG_START + 2) +#define ANI_MSG_OEM_DATA_RSP (ANI_DRIVER_MSG_START + 3) +#define ANI_MSG_CHANNEL_INFO_REQ (ANI_DRIVER_MSG_START + 4) +#define ANI_MSG_CHANNEL_INFO_RSP (ANI_DRIVER_MSG_START + 5) +#define ANI_MSG_OEM_ERROR (ANI_DRIVER_MSG_START + 6) +#define ANI_MSG_PEER_STATUS_IND (ANI_DRIVER_MSG_START + 7) +#define ANI_MSG_SET_OEM_CAP_REQ (ANI_DRIVER_MSG_START + 8) +#define ANI_MSG_SET_OEM_CAP_RSP (ANI_DRIVER_MSG_START + 9) +#define ANI_MSG_GET_OEM_CAP_REQ (ANI_DRIVER_MSG_START + 10) +#define ANI_MSG_GET_OEM_CAP_RSP (ANI_DRIVER_MSG_START + 11) + +#define ANI_MAX_RADIOS 3 +#define ANI_NL_MSG_OK 0 +#define ANI_NL_MSG_ERROR -1 +#define ANI_NL_MSG_OVERHEAD (NLMSG_SPACE(tAniHdr + 4)) +/* + * Packet Format for READ_REGISTER & WRITE_REGISTER: + * TotalMsgLen : 4 bytes [value=20 bytes] + * Radio : 4 bytes + * MsgId : 2 bytes + * MsgLen : 2 bytes + * Status : 4 bytes + * Address : 4 bytes + * Payload : 4 bytes + */ +/* + * Packet Format for READ_MEMORY & WRITE_MEMORY : + * TotalMsgLen : 4 bytes [value= 20+LEN_PAYLOAD bytes] + * Radio : 4 bytes + * MsgId : 2 bytes + * MsgLen : 2 bytes + * Status : 4 bytes + * Address : 4 bytes + * Length : 4 bytes [LEN_PAYLOAD] + * Payload : LEN_PAYLOAD bytes + */ +#ifdef PTT_SOCK_SVC_ENABLE +int ptt_sock_activate_svc(void); +void ptt_sock_deactivate_svc(void); +int ptt_sock_send_msg_to_app(tAniHdr *wmsg, int radio, int src_mod, int pid); +#else +static inline int ptt_sock_activate_svc(void) { return 0; } +static inline void ptt_sock_deactivate_svc(void) { return; } +static inline int ptt_sock_send_msg_to_app(tAniHdr *wmsg, int radio, + int src_mod, int pid) +{ + return 0; +} +#endif + +/* + * Format of message exchanged between the PTT Socket App in userspace and the + * WLAN Driver, in either direction. Each msg will begin with this header and + * will followed by the Quarky message + */ +typedef struct sAniAppRegReq { + tAniNlModTypes type; /* module id */ + int pid; /* process id */ +} tAniNlAppRegReq; +typedef struct sAniNlAppRegRsp { + tAniHdr wniHdr; /* Generic WNI msg header */ + tAniNlAppRegReq regReq; /* The original request msg */ + int ret; /* Return code */ +} tAniNlAppRegRsp; +#endif diff --git a/drivers/staging/qcacld-3.0/core/utils/ptt/src/wlan_ptt_sock_svc.c b/drivers/staging/qcacld-3.0/core/utils/ptt/src/wlan_ptt_sock_svc.c new file mode 100644 index 0000000000000000000000000000000000000000..4efb50ffbc47ded343339ebecb326915fd3cfa16 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/utils/ptt/src/wlan_ptt_sock_svc.c @@ -0,0 +1,231 @@ +/* + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/****************************************************************************** +* wlan_ptt_sock_svc.c +* +******************************************************************************/ +#ifdef PTT_SOCK_SVC_ENABLE +#include +#include +#include +#include +#include +#include +#include +#include + +#define PTT_SOCK_DEBUG +#ifdef PTT_SOCK_DEBUG +#define PTT_TRACE(level, args ...) QDF_TRACE(QDF_MODULE_ID_QDF, level, ## args) +#else +#define PTT_TRACE(level, args ...) +#endif + +/** ptt Process ID */ +static int32_t ptt_pid = INVALID_PID; + +#ifdef PTT_SOCK_DEBUG_VERBOSE +/* Utility function to perform a hex dump */ +static void ptt_sock_dump_buf(const unsigned char *pbuf, int cnt) +{ + int i; + for (i = 0; i < cnt; i++) { + if ((i % 16) == 0) + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO, + "\n%p:", pbuf); + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO, " %02X", + *pbuf); + pbuf++; + } + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_INFO, "\n"); +} +#endif + +/** + * ptt_sock_send_msg_to_app() - Send nl message to user space + * wmsg: Message header + * radio: Unit number of the radio + * src_mod: Message type + * pid: Process ID to which message will be unicast. Message + * will be broadcast when PID is INVALID_PID + * + * Utility function to send a netlink message to an application in user space + * + * Return: 0 on success and negative value on failure + */ +int ptt_sock_send_msg_to_app(tAniHdr *wmsg, int radio, int src_mod, int pid) +{ + int err = -1; + int payload_len; + int tot_msg_len; + tAniNlHdr *wnl; + struct sk_buff *skb; + struct nlmsghdr *nlh; + int wmsg_length = be16_to_cpu(wmsg->length); + static int nlmsg_seq; + + if (radio < 0 || radio > ANI_MAX_RADIOS) { + PTT_TRACE(QDF_TRACE_LEVEL_ERROR, "%s: invalid radio id [%d]\n", + __func__, radio); + return -EINVAL; + } + payload_len = wmsg_length + sizeof(wnl->radio) + sizeof(*wmsg); + tot_msg_len = NLMSG_SPACE(payload_len); + skb = dev_alloc_skb(tot_msg_len); + if (skb == NULL) { + PTT_TRACE(QDF_TRACE_LEVEL_ERROR, + "%s: dev_alloc_skb() failed for msg size[%d]\n", + __func__, tot_msg_len); + return -ENOMEM; + } + nlh = + nlmsg_put(skb, pid, nlmsg_seq++, src_mod, payload_len, + NLM_F_REQUEST); + if (NULL == nlh) { + PTT_TRACE(QDF_TRACE_LEVEL_ERROR, + "%s: nlmsg_put() failed for msg size[%d]\n", __func__, + tot_msg_len); + kfree_skb(skb); + return -ENOMEM; + } + wnl = (tAniNlHdr *) nlh; + wnl->radio = radio; + memcpy(&wnl->wmsg, wmsg, wmsg_length); +#ifdef PTT_SOCK_DEBUG_VERBOSE + ptt_sock_dump_buf((const unsigned char *)skb->data, skb->len); +#endif + + if (pid != INVALID_PID) + err = nl_srv_ucast(skb, pid, MSG_DONTWAIT); + else + err = nl_srv_bcast(skb); + + if (err) + PTT_TRACE(QDF_TRACE_LEVEL_INFO, + "%s:Failed sending Msg Type [0x%X] to pid[%d]\n", + __func__, be16_to_cpu(wmsg->type), pid); + return err; +} + +/* + * Process tregisteration request and send registration response messages + * to the PTT Socket App in user space + */ +static void ptt_sock_proc_reg_req(tAniHdr *wmsg, int radio) +{ + tAniNlAppRegReq *reg_req; + tAniNlAppRegRsp rspmsg; + reg_req = (tAniNlAppRegReq *) (wmsg + 1); + memset((char *)&rspmsg, 0, sizeof(rspmsg)); + /* send reg response message to the application */ + rspmsg.ret = ANI_NL_MSG_OK; + rspmsg.regReq.type = reg_req->type; + /*Save the pid */ + ptt_pid = reg_req->pid; + rspmsg.regReq.pid = reg_req->pid; + rspmsg.wniHdr.type = cpu_to_be16(ANI_MSG_APP_REG_RSP); + rspmsg.wniHdr.length = cpu_to_be16(sizeof(rspmsg)); + if (ptt_sock_send_msg_to_app((tAniHdr *) &rspmsg.wniHdr, radio, + ANI_NL_MSG_PUMAC, ptt_pid) < 0) { + PTT_TRACE(QDF_TRACE_LEVEL_INFO, + "%s: Error sending ANI_MSG_APP_REG_RSP to pid[%d]\n", + __func__, ptt_pid); + } +} + +/* + * Process all the messages from the PTT Socket App in user space + */ +static void ptt_proc_pumac_msg(struct sk_buff *skb, tAniHdr *wmsg, int radio) +{ + u16 ani_msg_type = be16_to_cpu(wmsg->type); + switch (ani_msg_type) { + case ANI_MSG_APP_REG_REQ: + PTT_TRACE(QDF_TRACE_LEVEL_INFO, + "%s: Received ANI_MSG_APP_REG_REQ [0x%X]\n", __func__, + ani_msg_type); + ptt_sock_proc_reg_req(wmsg, radio); + break; + default: + PTT_TRACE(QDF_TRACE_LEVEL_ERROR, + "%s: Received Unknown Msg Type[0x%X]\n", __func__, + ani_msg_type); + break; + } +} + +/* + * Process all the Netlink messages from PTT Socket app in user space + */ +static int ptt_sock_rx_nlink_msg(struct sk_buff *skb) +{ + tAniNlHdr *wnl; + int radio; + int type; + wnl = (tAniNlHdr *) skb->data; + radio = wnl->radio; + type = wnl->nlh.nlmsg_type; + switch (type) { + case ANI_NL_MSG_PUMAC: /* Message from the PTT socket APP */ + PTT_TRACE(QDF_TRACE_LEVEL_INFO, + "%s: Received ANI_NL_MSG_PUMAC Msg [0x%X]\n", + __func__, type); + ptt_proc_pumac_msg(skb, &wnl->wmsg, radio); + break; + default: + PTT_TRACE(QDF_TRACE_LEVEL_ERROR, "%s: Unknown NL Msg [0x%X]\n", + __func__, type); + break; + } + return 0; +} + +/** + * ptt_sock_activate_svc() - activate PTT service + * + * Return: 0 + */ +int ptt_sock_activate_svc(void) +{ + ptt_pid = INVALID_PID; + nl_srv_register(ANI_NL_MSG_PUMAC, ptt_sock_rx_nlink_msg); + nl_srv_register(ANI_NL_MSG_PTT, ptt_sock_rx_nlink_msg); + return 0; +} + +/** + * ptt_sock_deactivate_svc() - deactivate PTT service + * + * Return: Void + */ +void ptt_sock_deactivate_svc(void) +{ + ptt_pid = INVALID_PID; +} + +#endif /* PTT_SOCK_SVC_ENABLE */ diff --git a/drivers/staging/qcacld-3.0/core/wma/inc/wma.h b/drivers/staging/qcacld-3.0/core/wma/inc/wma.h new file mode 100644 index 0000000000000000000000000000000000000000..22ca27231774ff163f84892594f509fa925556c1 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/wma/inc/wma.h @@ -0,0 +1,2493 @@ +/* + * Copyright (c) 2013-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef WMA_H +#define WMA_H + +#include "a_types.h" +#include "qdf_types.h" +#include "osapi_linux.h" +#include "htc_packet.h" +#include "i_qdf_event.h" +#include "wmi_services.h" +#include "wmi_unified.h" +#include "wmi_version.h" +#include "qdf_types.h" +#include "cfg_api.h" +#include "qdf_status.h" +#include "cds_sched.h" +#include "sir_mac_prot_def.h" +#include "wma_types.h" +#include "ol_txrx_types.h" +#include +#include "utils_api.h" +#include "lim_types.h" +#include "wmi_unified_api.h" +#include "cdp_txrx_cmn.h" +#include "ol_defines.h" +#include "dbglog.h" + +/* Platform specific configuration for max. no. of fragments */ +#define QCA_OL_11AC_TX_MAX_FRAGS 2 + +/* Private */ + +#define WMA_READY_EVENTID_TIMEOUT 6000 +#define WMA_SERVICE_READY_EXT_TIMEOUT 6000 +#define WMA_TGT_SUSPEND_COMPLETE_TIMEOUT 6000 +#define WMA_WAKE_LOCK_TIMEOUT 1000 +#define WMA_RESUME_TIMEOUT 6000 +#define MAX_MEM_CHUNKS 32 + +#define WMA_CRASH_INJECT_TIMEOUT 5000 + +/* MAC ID to PDEV ID mapping is as given below + * MAC_ID PDEV_ID + * 0 1 + * 1 2 + * SOC Level WMI_PDEV_ID_SOC + */ +#define WMA_MAC_TO_PDEV_MAP(x) ((x) + (1)) +#define WMA_PDEV_TO_MAC_MAP(x) ((x) - (1)) + +/* In prima 12 HW stations are supported including BCAST STA(staId 0) + * and SELF STA(staId 1) so total ASSOC stations which can connect to Prima + * SoftAP = 12 - 1(Self STa) - 1(Bcast Sta) = 10 Stations. + */ + +#ifdef WLAN_SOFTAP_VSTA_FEATURE +#define WMA_MAX_SUPPORTED_STAS 38 +#else +#define WMA_MAX_SUPPORTED_STAS 12 +#endif +#define WMA_MAX_SUPPORTED_BSS 5 + +#define FRAGMENT_SIZE 3072 + +#define MAX_PRINT_FAILURE_CNT 50 + +#define WMA_INVALID_VDEV_ID 0xFF +#define MAX_MEM_CHUNKS 32 +#define WMA_MAX_VDEV_SIZE 20 +#define WMA_VDEV_TBL_ENTRY_ADD 1 +#define WMA_VDEV_TBL_ENTRY_DEL 0 + +/* 11A/G channel boundary */ +#define WMA_11A_CHANNEL_BEGIN 34 +#define WMA_11A_CHANNEL_END 165 +#define WMA_11G_CHANNEL_BEGIN 1 +#define WMA_11G_CHANNEL_END 14 + +#define WMA_11P_CHANNEL_BEGIN (170) +#define WMA_11P_CHANNEL_END (184) + +#define WMA_LOGD(args ...) \ + QDF_TRACE(QDF_MODULE_ID_WMA, QDF_TRACE_LEVEL_DEBUG, ## args) +#define WMA_LOGI(args ...) \ + QDF_TRACE(QDF_MODULE_ID_WMA, QDF_TRACE_LEVEL_INFO, ## args) +#define WMA_LOGW(args ...) \ + QDF_TRACE(QDF_MODULE_ID_WMA, QDF_TRACE_LEVEL_WARN, ## args) +#define WMA_LOGE(args ...) \ + QDF_TRACE(QDF_MODULE_ID_WMA, QDF_TRACE_LEVEL_ERROR, ## args) +#define WMA_LOGP(args ...) \ + QDF_TRACE(QDF_MODULE_ID_WMA, QDF_TRACE_LEVEL_FATAL, ## args) + +#define WMA_DEBUG_ALWAYS + +#ifdef WMA_DEBUG_ALWAYS +#define WMA_LOGA(args ...) \ + QDF_TRACE(QDF_MODULE_ID_WMA, QDF_TRACE_LEVEL_FATAL, ## args) +#else +#define WMA_LOGA(args ...) +#endif + +#define ALIGNED_WORD_SIZE 4 +#define WLAN_HAL_MSG_TYPE_MAX_ENUM_SIZE 0x7FFF +#define WMA_WILDCARD_PDEV_ID 0x0 + +/* Prefix used by scan req ids generated on the host */ +#define WMA_HOST_SCAN_REQID_PREFIX 0xA000 +/* Prefix used by roam scan req ids generated on the host */ +#define WMA_HOST_ROAM_SCAN_REQID_PREFIX 0xA800 +/* Prefix used by scan requestor id on host */ +#define WMA_HOST_SCAN_REQUESTOR_ID_PREFIX 0xA000 + +#define WMA_HW_DEF_SCAN_MAX_DURATION 30000 /* 30 secs */ + +/* Max offchannel duration */ +#define WMA_BURST_SCAN_MAX_NUM_OFFCHANNELS (3) +#define WMA_SCAN_NPROBES_DEFAULT (2) +#define WMA_SCAN_IDLE_TIME_DEFAULT (25) +#define WMA_P2P_SCAN_MAX_BURST_DURATION (180) +#define WMA_CTS_DURATION_MS_MAX (32) +#define WMA_GO_MIN_ACTIVE_SCAN_BURST_DURATION (40) +#define WMA_GO_MAX_ACTIVE_SCAN_BURST_DURATION (120) +#define WMA_DWELL_TIME_PASSIVE_DEFAULT (110) +#define WMA_DWELL_TIME_PROBE_TIME_MAP_SIZE (11) +#define WMA_3PORT_CONC_SCAN_MAX_BURST_DURATION (25) + +#define WMA_SEC_TO_USEC (1000000) + +#define BEACON_TX_BUFFER_SIZE (512) + +/* WMA_ETHER_TYPE_OFFSET = sa(6) + da(6) */ +#define WMA_ETHER_TYPE_OFFSET (6 + 6) +/* WMA_ICMP_V6_HEADER_OFFSET = sa(6) + da(6) + eth_type(2) + icmp_v6_hdr(6)*/ +#define WMA_ICMP_V6_HEADER_OFFSET (6 + 6 + 2 + 6) +/* WMA_ICMP_V6_TYPE_OFFSET = sa(6) + da(6) + eth_type(2) + 40 */ +#define WMA_ICMP_V6_TYPE_OFFSET (6 + 6 + 2 + 40) +/* WMA_IPV4_PROTOCOL = sa(6) + da(6) + eth_type(2) + 9 */ +#define WMA_IPV4_PROTOCOL (6 + 6 + 2 + 9) +#define WMA_ICMP_V6_HEADER_TYPE (0x3A) +#define WMA_ICMP_V6_RA_TYPE (0x86) +#define WMA_ICMP_V6_NS_TYPE (0x87) +#define WMA_ICMP_V6_NA_TYPE (0x88) +#define WMA_BCAST_MAC_ADDR (0xFF) +#define WMA_MCAST_IPV4_MAC_ADDR (0x01) +#define WMA_MCAST_IPV6_MAC_ADDR (0x33) +#define WMA_ICMP_PROTOCOL (0x01) + +#define WMA_IS_EAPOL_GET_MIN_LEN 14 +#define WMA_EAPOL_SUBTYPE_GET_MIN_LEN 21 +#define WMA_EAPOL_INFO_GET_MIN_LEN 23 +#define WMA_IS_DHCP_GET_MIN_LEN 38 +#define WMA_DHCP_SUBTYPE_GET_MIN_LEN 0x11D +#define WMA_DHCP_INFO_GET_MIN_LEN 50 +#define WMA_IS_ARP_GET_MIN_LEN 14 +#define WMA_ARP_SUBTYPE_GET_MIN_LEN 22 +#define WMA_IPV4_PROTO_GET_MIN_LEN 24 +#define WMA_IPV4_PKT_INFO_GET_MIN_LEN 42 +#define WMA_ICMP_SUBTYPE_GET_MIN_LEN 35 +#define WMA_IPV6_PROTO_GET_MIN_LEN 21 +#define WMA_IPV6_PKT_INFO_GET_MIN_LEN 62 +#define WMA_ICMPV6_SUBTYPE_GET_MIN_LEN 55 +/** + * ds_mode: distribution system mode + * @IEEE80211_NO_DS: NO DS at either side + * @IEEE80211_TO_DS: DS at receiver side + * @IEEE80211_FROM_DS: DS at sender side + * @IEEE80211_DS_TO_DS: DS at both sender and revceiver side + */ +enum ds_mode { + IEEE80211_NO_DS, + IEEE80211_TO_DS, + IEEE80211_FROM_DS, + IEEE80211_DS_TO_DS +}; + +/* Roaming default values + * All time and period values are in milliseconds. + * All rssi values are in dB except for WMA_NOISE_FLOOR_DBM_DEFAULT. + */ + +#define WMA_ROAM_SCAN_CHANNEL_SWITCH_TIME (4) +#define WMA_NOISE_FLOOR_DBM_DEFAULT (-96) +#define WMA_ROAM_RSSI_DIFF_DEFAULT (5) +#define WMA_ROAM_DWELL_TIME_ACTIVE_DEFAULT (100) +#define WMA_ROAM_DWELL_TIME_PASSIVE_DEFAULT (110) +#define WMA_ROAM_MIN_REST_TIME_DEFAULT (50) +#define WMA_ROAM_MAX_REST_TIME_DEFAULT (500) +#define WMA_ROAM_LOW_RSSI_TRIGGER_DEFAULT (20) +#define WMA_ROAM_LOW_RSSI_TRIGGER_VERYLOW (10) +#define WMA_ROAM_BEACON_WEIGHT_DEFAULT (14) +#define WMA_ROAM_OPP_SCAN_PERIOD_DEFAULT (120000) +#define WMA_ROAM_OPP_SCAN_AGING_PERIOD_DEFAULT (WMA_ROAM_OPP_SCAN_PERIOD_DEFAULT * 5) +#define WMA_ROAM_BMISS_FIRST_BCNT_DEFAULT (10) +#define WMA_ROAM_BMISS_FINAL_BCNT_DEFAULT (10) +#define WMA_ROAM_BMISS_FIRST_BCNT_DEFAULT_P2P (15) +#define WMA_ROAM_BMISS_FINAL_BCNT_DEFAULT_P2P (45) + +#define WMA_INVALID_KEY_IDX 0xff +#define WMA_DFS_RADAR_FOUND 1 + +#define WMA_MAX_RF_CHAINS(x) ((1 << x) - 1) +#define WMA_MIN_RF_CHAINS (1) +#define WMA_MAX_NSS (2) + + +#ifdef FEATURE_WLAN_EXTSCAN +#define WMA_MAX_EXTSCAN_MSG_SIZE 1536 +#define WMA_EXTSCAN_REST_TIME 100 +#define WMA_EXTSCAN_MAX_SCAN_TIME 50000 +#define WMA_EXTSCAN_BURST_DURATION 150 +#endif + +#define WMA_BCN_BUF_MAX_SIZE 2500 +#define WMA_NOA_IE_SIZE(num_desc) (2 + (13 * (num_desc))) +#define WMA_MAX_NOA_DESCRIPTORS 4 + +#define WMA_TIM_SUPPORTED_PVB_LENGTH ((HAL_NUM_STA / 8) + 1) + +#define WMA_WOW_PTRN_MASK_VALID 0xFF +#define WMA_NUM_BITS_IN_BYTE 8 + +#define WMA_AP_WOW_DEFAULT_PTRN_MAX 4 +#define WMA_STA_WOW_DEFAULT_PTRN_MAX 5 + +#define WMA_BSS_STATUS_STARTED 0x1 +#define WMA_BSS_STATUS_STOPPED 0x2 + +#define WMA_TARGET_REQ_TYPE_VDEV_START 0x1 +#define WMA_TARGET_REQ_TYPE_VDEV_STOP 0x2 +#define WMA_TARGET_REQ_TYPE_VDEV_DEL 0x3 + +#define WMA_PEER_ASSOC_CNF_START 0x01 +#define WMA_PEER_ASSOC_TIMEOUT (6000) /* 6 seconds */ + +#define WMA_DELETE_STA_RSP_START 0x02 +#define WMA_DELETE_STA_TIMEOUT (6000) /* 6 seconds */ + +#define WMA_DEL_P2P_SELF_STA_RSP_START 0x03 +#define WMA_SET_LINK_PEER_RSP 0x04 +#define WMA_DELETE_PEER_RSP 0x05 +#define WMA_VDEV_START_REQUEST_TIMEOUT (6000) /* 6 seconds */ +#define WMA_VDEV_STOP_REQUEST_TIMEOUT (6000) /* 6 seconds */ + +#define WMA_TGT_INVALID_SNR (0) + +#define WMA_TGT_IS_VALID_SNR(x) ((x) >= 0 && (x) < WMA_TGT_MAX_SNR) +#define WMA_TGT_IS_INVALID_SNR(x) (!WMA_TGT_IS_VALID_SNR(x)) + +#define WMA_TX_Q_RECHECK_TIMER_WAIT 2 /* 2 ms */ +#define WMA_TX_Q_RECHECK_TIMER_MAX_WAIT 20 /* 20 ms */ +#define WMA_MAX_NUM_ARGS 8 + +#define WMA_SMPS_MASK_LOWER_16BITS 0xFF +#define WMA_SMPS_MASK_UPPER_3BITS 0x7 +#define WMA_SMPS_PARAM_VALUE_S 29 + +#define WMA_MAX_SCAN_ID 0x00FF + +/* + * Setting the Tx Comp Timeout to 1 secs. + * TODO: Need to Revist the Timing + */ +#define WMA_TX_FRAME_COMPLETE_TIMEOUT 1000 +#define WMA_TX_FRAME_BUFFER_NO_FREE 0 +#define WMA_TX_FRAME_BUFFER_FREE 1 + +/* Default InActivity Time is 200 ms */ +#define POWERSAVE_DEFAULT_INACTIVITY_TIME 200 + +/* Default WOW InActivity Time is 50 ms */ +#define WOW_POWERSAVE_DEFAULT_INACTIVITY_TIME 50 + +/* Default Listen Interval */ +#define POWERSAVE_DEFAULT_LISTEN_INTERVAL 1 + +/* + * TODO: Add WMI_CMD_ID_MAX as part of WMI_CMD_ID + * instead of assigning it to the last valid wmi + * cmd+1 to avoid updating this when a command is + * added/deleted. + */ +#define WMI_CMDID_MAX (WMI_TXBF_CMDID + 1) + +#define WMA_NLO_FREQ_THRESH 1000 /* in MHz */ +#define WMA_SEC_TO_MSEC(sec) (sec * 1000) /* sec to msec */ +#define WMA_MSEC_TO_USEC(msec) (msec * 1000) /* msec to usec */ + +/* Default rssi threshold defined in CFG80211 */ +#define WMA_RSSI_THOLD_DEFAULT -300 + +#ifdef FEATURE_WLAN_SCAN_PNO +#define WMA_PNO_MATCH_WAKE_LOCK_TIMEOUT (5 * 1000) /* in msec */ +#ifdef CONFIG_SLUB_DEBUG_ON +#define WMA_PNO_SCAN_COMPLETE_WAKE_LOCK_TIMEOUT (2 * 1000) /* in msec */ +#else +#define WMA_PNO_SCAN_COMPLETE_WAKE_LOCK_TIMEOUT (1 * 1000) /* in msec */ +#endif /* CONFIG_SLUB_DEBUG_ON */ +#endif /* FEATURE_WLAN_SCAN_PNO */ + +#define WMA_AUTH_REQ_RECV_WAKE_LOCK_TIMEOUT (5 * 1000) /* in msec */ +#define WMA_ASSOC_REQ_RECV_WAKE_LOCK_DURATION (5 * 1000) /* in msec */ +#define WMA_DEAUTH_RECV_WAKE_LOCK_DURATION (5 * 1000) /* in msec */ +#define WMA_DISASSOC_RECV_WAKE_LOCK_DURATION (5 * 1000) /* in msec */ +#define WMA_ROAM_HO_WAKE_LOCK_DURATION (500) /* in msec */ +#ifdef FEATURE_WLAN_AUTO_SHUTDOWN +#define WMA_AUTO_SHUTDOWN_WAKE_LOCK_DURATION (5 * 1000) /* in msec */ +#endif +#define WMA_BMISS_EVENT_WAKE_LOCK_DURATION (4 * 1000) /* in msec */ +#define WMA_FW_RSP_EVENT_WAKE_LOCK_DURATION (3 * 1000) /* in msec */ + +#define WMA_TXMIC_LEN 8 +#define WMA_RXMIC_LEN 8 + +/* + * Length = (2 octets for Index and CTWin/Opp PS) and + * (13 octets for each NOA Descriptors) + */ + +#define WMA_P2P_NOA_IE_OPP_PS_SET (0x80) +#define WMA_P2P_NOA_IE_CTWIN_MASK (0x7F) + +#define WMA_P2P_IE_ID 0xdd +#define WMA_P2P_WFA_OUI { 0x50, 0x6f, 0x9a } +#define WMA_P2P_WFA_VER 0x09 /* ver 1.0 */ +#define WMA_WSC_OUI { 0x00, 0x50, 0xF2 } /* Microsoft WSC OUI byte */ + +/* P2P Sub element defintions (according to table 5 of Wifi's P2P spec) */ +#define WMA_P2P_SUB_ELEMENT_STATUS 0 +#define WMA_P2P_SUB_ELEMENT_MINOR_REASON 1 +#define WMA_P2P_SUB_ELEMENT_CAPABILITY 2 +#define WMA_P2P_SUB_ELEMENT_DEVICE_ID 3 +#define WMA_P2P_SUB_ELEMENT_GO_INTENT 4 +#define WMA_P2P_SUB_ELEMENT_CONFIGURATION_TIMEOUT 5 +#define WMA_P2P_SUB_ELEMENT_LISTEN_CHANNEL 6 +#define WMA_P2P_SUB_ELEMENT_GROUP_BSSID 7 +#define WMA_P2P_SUB_ELEMENT_EXTENDED_LISTEN_TIMING 8 +#define WMA_P2P_SUB_ELEMENT_INTENDED_INTERFACE_ADDR 9 +#define WMA_P2P_SUB_ELEMENT_MANAGEABILITY 10 +#define WMA_P2P_SUB_ELEMENT_CHANNEL_LIST 11 +#define WMA_P2P_SUB_ELEMENT_NOA 12 +#define WMA_P2P_SUB_ELEMENT_DEVICE_INFO 13 +#define WMA_P2P_SUB_ELEMENT_GROUP_INFO 14 +#define WMA_P2P_SUB_ELEMENT_GROUP_ID 15 +#define WMA_P2P_SUB_ELEMENT_INTERFACE 16 +#define WMA_P2P_SUB_ELEMENT_OP_CHANNEL 17 +#define WMA_P2P_SUB_ELEMENT_INVITATION_FLAGS 18 +#define WMA_P2P_SUB_ELEMENT_VENDOR 221 + +/* Macros for handling unaligned memory accesses */ +#define P2PIE_PUT_LE16(a, val) \ + do { \ + (a)[1] = ((u16) (val)) >> 8; \ + (a)[0] = ((u16) (val)) & 0xff; \ + } while (0) + +#define P2PIE_PUT_LE32(a, val) \ + do { \ + (a)[3] = (u8) ((((u32) (val)) >> 24) & 0xff); \ + (a)[2] = (u8) ((((u32) (val)) >> 16) & 0xff); \ + (a)[1] = (u8) ((((u32) (val)) >> 8) & 0xff); \ + (a)[0] = (u8) (((u32) (val)) & 0xff); \ + } while (0) + + +#define WMA_DEFAULT_MAX_PSPOLL_BEFORE_WAKE 1 + +#define WMA_DEFAULT_QPOWER_MAX_PSPOLL_BEFORE_WAKE 1 +#define WMA_DEFAULT_QPOWER_TX_WAKE_THRESHOLD 2 +#define WMA_DEFAULT_SIFS_BURST_DURATION 8160 + +#define WMA_VHT_PPS_PAID_MATCH 1 +#define WMA_VHT_PPS_GID_MATCH 2 +#define WMA_VHT_PPS_DELIM_CRC_FAIL 3 + +#define WMA_DFS_MAX_20M_SUB_CH 8 +#define WMA_80MHZ_START_CENTER_CH_DIFF 6 +#define WMA_160MHZ_START_CENTER_CH_DIFF 14 +#define WMA_NEXT_20MHZ_START_CH_DIFF 4 + +#define WMA_DEFAULT_HW_MODE_INDEX 0xFFFF +#define TWO_THIRD (2/3) + +/** + * WMA hardware mode list bit-mask definitions. + * Bits 4:0, 31:29 are unused. + * + * The below definitions are added corresponding to WMI DBS HW mode + * list to make it independent of firmware changes for WMI definitions. + * Currently these definitions have dependency with BIT positions of + * the existing WMI macros. Thus, if the BIT positions are changed for + * WMI macros, then these macros' BIT definitions are also need to be + * changed. + */ +#define WMA_HW_MODE_MAC0_TX_STREAMS_BITPOS (28) +#define WMA_HW_MODE_MAC0_RX_STREAMS_BITPOS (24) +#define WMA_HW_MODE_MAC1_TX_STREAMS_BITPOS (20) +#define WMA_HW_MODE_MAC1_RX_STREAMS_BITPOS (16) +#define WMA_HW_MODE_MAC0_BANDWIDTH_BITPOS (12) +#define WMA_HW_MODE_MAC1_BANDWIDTH_BITPOS (8) +#define WMA_HW_MODE_DBS_MODE_BITPOS (7) +#define WMA_HW_MODE_AGILE_DFS_MODE_BITPOS (6) +#define WMA_HW_MODE_SBS_MODE_BITPOS (5) + +#define WMA_HW_MODE_MAC0_TX_STREAMS_MASK \ + (0xf << WMA_HW_MODE_MAC0_TX_STREAMS_BITPOS) +#define WMA_HW_MODE_MAC0_RX_STREAMS_MASK \ + (0xf << WMA_HW_MODE_MAC0_RX_STREAMS_BITPOS) +#define WMA_HW_MODE_MAC1_TX_STREAMS_MASK \ + (0xf << WMA_HW_MODE_MAC1_TX_STREAMS_BITPOS) +#define WMA_HW_MODE_MAC1_RX_STREAMS_MASK \ + (0xf << WMA_HW_MODE_MAC1_RX_STREAMS_BITPOS) +#define WMA_HW_MODE_MAC0_BANDWIDTH_MASK \ + (0xf << WMA_HW_MODE_MAC0_BANDWIDTH_BITPOS) +#define WMA_HW_MODE_MAC1_BANDWIDTH_MASK \ + (0xf << WMA_HW_MODE_MAC1_BANDWIDTH_BITPOS) +#define WMA_HW_MODE_DBS_MODE_MASK \ + (0x1 << WMA_HW_MODE_DBS_MODE_BITPOS) +#define WMA_HW_MODE_AGILE_DFS_MODE_MASK \ + (0x1 << WMA_HW_MODE_AGILE_DFS_MODE_BITPOS) +#define WMA_HW_MODE_SBS_MODE_MASK \ + (0x1 << WMA_HW_MODE_SBS_MODE_BITPOS) + +#define WMA_HW_MODE_MAC0_TX_STREAMS_SET(hw_mode, value) \ + WMI_SET_BITS(hw_mode, WMA_HW_MODE_MAC0_TX_STREAMS_BITPOS, 4, value) +#define WMA_HW_MODE_MAC0_RX_STREAMS_SET(hw_mode, value) \ + WMI_SET_BITS(hw_mode, WMA_HW_MODE_MAC0_RX_STREAMS_BITPOS, 4, value) +#define WMA_HW_MODE_MAC1_TX_STREAMS_SET(hw_mode, value) \ + WMI_SET_BITS(hw_mode, WMA_HW_MODE_MAC1_TX_STREAMS_BITPOS, 4, value) +#define WMA_HW_MODE_MAC1_RX_STREAMS_SET(hw_mode, value) \ + WMI_SET_BITS(hw_mode, WMA_HW_MODE_MAC1_RX_STREAMS_BITPOS, 4, value) +#define WMA_HW_MODE_MAC0_BANDWIDTH_SET(hw_mode, value) \ + WMI_SET_BITS(hw_mode, WMA_HW_MODE_MAC0_BANDWIDTH_BITPOS, 4, value) +#define WMA_HW_MODE_MAC1_BANDWIDTH_SET(hw_mode, value) \ + WMI_SET_BITS(hw_mode, WMA_HW_MODE_MAC1_BANDWIDTH_BITPOS, 4, value) +#define WMA_HW_MODE_DBS_MODE_SET(hw_mode, value) \ + WMI_SET_BITS(hw_mode, WMA_HW_MODE_DBS_MODE_BITPOS, 1, value) +#define WMA_HW_MODE_AGILE_DFS_SET(hw_mode, value) \ + WMI_SET_BITS(hw_mode, WMA_HW_MODE_AGILE_DFS_MODE_BITPOS, 1, value) +#define WMA_HW_MODE_SBS_MODE_SET(hw_mode, value) \ + WMI_SET_BITS(hw_mode, WMA_HW_MODE_SBS_MODE_BITPOS, 1, value) + +#define WMA_HW_MODE_MAC0_TX_STREAMS_GET(hw_mode) \ + ((hw_mode & WMA_HW_MODE_MAC0_TX_STREAMS_MASK) >> \ + WMA_HW_MODE_MAC0_TX_STREAMS_BITPOS) +#define WMA_HW_MODE_MAC0_RX_STREAMS_GET(hw_mode) \ + ((hw_mode & WMA_HW_MODE_MAC0_RX_STREAMS_MASK) >> \ + WMA_HW_MODE_MAC0_RX_STREAMS_BITPOS) +#define WMA_HW_MODE_MAC1_TX_STREAMS_GET(hw_mode) \ + ((hw_mode & WMA_HW_MODE_MAC1_TX_STREAMS_MASK) >> \ + WMA_HW_MODE_MAC1_TX_STREAMS_BITPOS) +#define WMA_HW_MODE_MAC1_RX_STREAMS_GET(hw_mode) \ + ((hw_mode & WMA_HW_MODE_MAC1_RX_STREAMS_MASK) >> \ + WMA_HW_MODE_MAC1_RX_STREAMS_BITPOS) +#define WMA_HW_MODE_MAC0_BANDWIDTH_GET(hw_mode) \ + ((hw_mode & WMA_HW_MODE_MAC0_BANDWIDTH_MASK) >> \ + WMA_HW_MODE_MAC0_BANDWIDTH_BITPOS) +#define WMA_HW_MODE_MAC1_BANDWIDTH_GET(hw_mode) \ + ((hw_mode & WMA_HW_MODE_MAC1_BANDWIDTH_MASK) >> \ + WMA_HW_MODE_MAC1_BANDWIDTH_BITPOS) +#define WMA_HW_MODE_DBS_MODE_GET(hw_mode) \ + ((hw_mode & WMA_HW_MODE_DBS_MODE_MASK) >> \ + WMA_HW_MODE_DBS_MODE_BITPOS) +#define WMA_HW_MODE_AGILE_DFS_GET(hw_mode) \ + ((hw_mode & WMA_HW_MODE_AGILE_DFS_MODE_MASK) >> \ + WMA_HW_MODE_AGILE_DFS_MODE_BITPOS) +#define WMA_HW_MODE_SBS_MODE_GET(hw_mode) \ + ((hw_mode & WMA_HW_MODE_SBS_MODE_MASK) >> \ + WMA_HW_MODE_SBS_MODE_BITPOS) + + +#define WMA_SCAN_END_EVENT (WMI_SCAN_EVENT_COMPLETED | \ + WMI_SCAN_EVENT_DEQUEUED | \ + WMI_SCAN_EVENT_START_FAILED) + +/** + * struct probeTime_dwellTime - probe time, dwell time map + * @dwell_time: dwell time + * @probe_time: repeat probe time + */ +typedef struct probeTime_dwellTime { + uint8_t dwell_time; + uint8_t probe_time; +} t_probeTime_dwellTime; + +static const t_probeTime_dwellTime + probe_time_dwell_time_map[WMA_DWELL_TIME_PROBE_TIME_MAP_SIZE] = { + {28, 11}, /* 0 SSID */ + {28, 20}, /* 1 SSID */ + {28, 20}, /* 2 SSID */ + {28, 20}, /* 3 SSID */ + {28, 20}, /* 4 SSID */ + {28, 20}, /* 5 SSID */ + {28, 20}, /* 6 SSID */ + {28, 11}, /* 7 SSID */ + {28, 11}, /* 8 SSID */ + {28, 11}, /* 9 SSID */ + {28, 8} /* 10 SSID */ +}; + +typedef void (*txFailIndCallback)(uint8_t *peer_mac, uint8_t seqNo); +typedef void (*encrypt_decrypt_cb)(struct sir_encrypt_decrypt_rsp_params + *encrypt_decrypt_rsp_params); + + +typedef void (*tp_wma_packetdump_cb)(qdf_nbuf_t netbuf, + uint8_t status, uint8_t vdev_id, uint8_t type); + +/** + * enum t_wma_drv_type - wma driver type + * @WMA_DRIVER_TYPE_PRODUCTION: production driver type + * @WMA_DRIVER_TYPE_MFG: manufacture driver type + * @WMA_DRIVER_TYPE_INVALID: invalid driver type + */ +typedef enum { + WMA_DRIVER_TYPE_PRODUCTION = 0, + WMA_DRIVER_TYPE_MFG = 1, + WMA_DRIVER_TYPE_INVALID = 0x7FFFFFFF +} t_wma_drv_type; + +#ifdef FEATURE_WLAN_TDLS +/** + * enum t_wma_tdls_mode - TDLS mode + * @WMA_TDLS_SUPPORT_NOT_ENABLED: tdls is disable + * @WMA_TDLS_SUPPORT_DISABLED: suppress implicit trigger and not respond to peer + * @WMA_TDLS_SUPPORT_EXPLICIT_TRIGGER_ONLY: suppress implicit trigger, + * but respond to the peer + * @WMA_TDLS_SUPPORT_ENABLED: implicit trigger + * @WMA_TDLS_SUPPORT_ACTIVE_EXTERNAL_CONTROL: External control means + * implicit trigger but only to a peer mac configured by user space. + */ +typedef enum { + WMA_TDLS_SUPPORT_NOT_ENABLED = 0, + WMA_TDLS_SUPPORT_DISABLED, + WMA_TDLS_SUPPORT_EXPLICIT_TRIGGER_ONLY, + WMA_TDLS_SUPPORT_ENABLED, + WMA_TDLS_SUPPORT_ACTIVE_EXTERNAL_CONTROL, +} t_wma_tdls_mode; + +/** + * enum wma_tdls_peer_notification - TDLS events + * @WMA_TDLS_SHOULD_DISCOVER: tdls discovery recommended for peer (always based + * on tx bytes per second > tx_discover threshold + * NB: notification will be re-sent after + * discovery_request_interval_ms + * @WMA_TDLS_SHOULD_TEARDOWN: tdls link tear down recommended for peer + * due to tx bytes per second below + * tx_teardown_threshold + * NB: this notification sent once + * @WMA_TDLS_PEER_DISCONNECTED: tx peer TDLS link tear down complete + */ +enum wma_tdls_peer_notification { + WMA_TDLS_SHOULD_DISCOVER, + WMA_TDLS_SHOULD_TEARDOWN, + WMA_TDLS_PEER_DISCONNECTED, +}; + +/** + * enum wma_tdls_peer_reason - TDLS peer reason + * @WMA_TDLS_TEARDOWN_REASON_TX: tdls teardown recommended due to low transmits + * @WMA_TDLS_TEARDOWN_REASON_RATE: tdls tear down recommended due to + * packet rates < AP rates + * @WMA_TDLS_TEARDOWN_REASON_RSSI: tdls link tear down recommended + * due to poor RSSI + * @WMA_TDLS_TEARDOWN_REASON_SCAN: tdls link tear down recommended + * due to offchannel scan + * @WMA_TDLS_DISCONNECTED_REASON_PEER_DELETE: tdls peer disconnected + * due to peer deletion + */ +enum wma_tdls_peer_reason { + WMA_TDLS_TEARDOWN_REASON_TX, + WMA_TDLS_TEARDOWN_REASON_RATE, + WMA_TDLS_TEARDOWN_REASON_RSSI, + WMA_TDLS_TEARDOWN_REASON_SCAN, + WMA_TDLS_DISCONNECTED_REASON_PEER_DELETE, +}; +#endif /* FEATURE_WLAN_TDLS */ + +/** + * enum wma_rx_exec_ctx - wma rx execution context + * @WMA_RX_WORK_CTX: work queue context execution + * @WMA_RX_TASKLET_CTX: tasklet context execution + * @WMA_RX_SERIALIZER_CTX: MC thread context execution + * + */ +enum wma_rx_exec_ctx { + WMA_RX_WORK_CTX, + WMA_RX_TASKLET_CTX, + WMA_RX_SERIALIZER_CTX +}; + +/** + * enum wma_phy_idx + * @PHY1: to notify caller that PHY1 specific param needed + * @PHY2: to notify caller that PHY2 specific param needed + * @PHY1_PHY2: to notify caller that both PHY's param needed + * Note: Firmware sends phy map in terms of bitmask, so enum + * also needs to be defined that way. + * + * For example, 0x3 = 0011 = BIT0 corresponds to one phy and + * BIT1 coresponds to another phy. There is no direct relation between + * each bit to particular PHY (ex. PHYA or PHYB). + * + * In simple terms, 3 means referring both PHYs & 1 or 2 means + * referring to either PHYA or PHYB. + */ +enum wma_phy_idx { + PHY1 = 0x1, /* 0x1 */ + PHY2, /* 0x2 */ + PHY1_PHY2, /* 0x3 */ +}; + +/** + * struct wma_mem_chunk - memory chunks + * @vaddr: virtual address + * @paddr: physical address + * @memctx: dma mapped memory + * @len: length of data + * @req_id: request id + * + * memory chunck allocated by Host to be managed by FW + * used only for low latency interfaces like pcie + */ +struct wma_mem_chunk { + uint32_t *vaddr; + uint32_t paddr; + qdf_dma_mem_context(memctx); + uint32_t len; + uint32_t req_id; +}; + +/** + * struct p2p_scan_param - p2p scan listen parameters + * @scan_id: scan id + * @p2p_scan_type: p2p scan type + */ +struct p2p_scan_param { + uint32_t scan_id; + tSirP2pScanType p2p_scan_type; +}; + +/** + * struct scan_param - scan parameters + * @scan_id: scan id + * @scan_requestor_id: scan requestor id + * @p2p_scan_type: p2p scan type + */ +struct scan_param { + uint32_t scan_id; + uint32_t scan_requestor_id; + tSirP2pScanType p2p_scan_type; + uint32_t chan_freq; +}; + +/** + * struct beacon_info - structure to store beacon template + * @buf: skb ptr + * @len: length + * @dma_mapped: is it dma mapped or not + * @tim_ie_offset: TIM IE offset + * @dtim_count: DTIM count + * @seq_no: sequence no + * @noa_sub_ie: NOA sub IE + * @noa_sub_ie_len: NOA sub IE length + * @noa_ie: NOA IE + * @p2p_ie_offset: p2p IE offset + * @lock: lock + */ +struct beacon_info { + qdf_nbuf_t buf; + uint32_t len; + uint8_t dma_mapped; + uint32_t tim_ie_offset; + uint8_t dtim_count; + uint16_t seq_no; + uint8_t noa_sub_ie[2 + WMA_NOA_IE_SIZE(WMA_MAX_NOA_DESCRIPTORS)]; + uint16_t noa_sub_ie_len; + uint8_t *noa_ie; + uint16_t p2p_ie_offset; + qdf_spinlock_t lock; +}; + +/** + * struct beacon_tim_ie - structure to store TIM IE of beacon + * @tim_ie: tim ie + * @tim_len: tim ie length + * @dtim_count: dtim count + * @dtim_period: dtim period + * @tim_bitctl: tim bit control + * @tim_bitmap: tim bitmap + */ +struct beacon_tim_ie { + uint8_t tim_ie; + uint8_t tim_len; + uint8_t dtim_count; + uint8_t dtim_period; + uint8_t tim_bitctl; + uint8_t tim_bitmap[1]; +} __ATTRIB_PACK; + +/** + * struct pps - packet power save parameter + * @paid_match_enable: paid match enable + * @gid_match_enable: gid match enable + * @tim_clear: time clear + * @dtim_clear: dtim clear + * @eof_delim: eof delim + * @mac_match: mac match + * @delim_fail: delim fail + * @nsts_zero: nsts zero + * @rssi_chk: RSSI check + * @ebt_5g: ebt 5GHz + */ +struct pps { + bool paid_match_enable; + bool gid_match_enable; + bool tim_clear; + bool dtim_clear; + bool eof_delim; + bool mac_match; + bool delim_fail; + bool nsts_zero; + bool rssi_chk; + bool ebt_5g; +}; + +/** + * struct qpower_params - qpower related parameters + * @max_ps_poll_cnt: max ps poll count + * @max_tx_before_wake: max tx before wake + * @spec_ps_poll_wake_interval: ps poll wake interval + * @max_spec_nodata_ps_poll: no data ps poll + */ +struct qpower_params { + uint32_t max_ps_poll_cnt; + uint32_t max_tx_before_wake; + uint32_t spec_ps_poll_wake_interval; + uint32_t max_spec_nodata_ps_poll; +}; + + +/** + * struct gtx_config_t - GTX config + * @gtxRTMask: for HT and VHT rate masks + * @gtxUsrcfg: host request for GTX mask + * @gtxPERThreshold: PER Threshold (default: 10%) + * @gtxPERMargin: PER margin (default: 2%) + * @gtxTPCstep: TCP step (default: 1) + * @gtxTPCMin: TCP min (default: 5) + * @gtxBWMask: BW mask (20/40/80/160 Mhz) + */ +typedef struct { + uint32_t gtxRTMask[2]; + uint32_t gtxUsrcfg; + uint32_t gtxPERThreshold; + uint32_t gtxPERMargin; + uint32_t gtxTPCstep; + uint32_t gtxTPCMin; + uint32_t gtxBWMask; +} gtx_config_t; + +/** + * struct pdev_cli_config_t - store pdev parameters + * @ani_enable: ANI is enabled/disable on target + * @ani_poll_len: store ANI polling period + * @ani_listen_len: store ANI listening period + * @ani_ofdm_level: store ANI OFDM immunity level + * @ani_cck_level: store ANI CCK immunity level + * @cwmenable: Dynamic bw is enable/disable in fw + * @txchainmask: tx chain mask + * @rxchainmask: rx chain mask + * @txpow2g: tx power limit for 2GHz + * @txpow5g: tx power limit for 5GHz + * @burst_enable: is burst enable/disable + * @burst_dur: burst duration + * + * This structure stores pdev parameters. + * Some of these parameters are set in fw and some + * parameters are only maintained in host. + */ +typedef struct { + uint32_t ani_enable; + uint32_t ani_poll_len; + uint32_t ani_listen_len; + uint32_t ani_ofdm_level; + uint32_t ani_cck_level; + uint32_t cwmenable; + uint32_t cts_cbw; + uint32_t txchainmask; + uint32_t rxchainmask; + uint32_t txpow2g; + uint32_t txpow5g; + uint32_t burst_enable; + uint32_t burst_dur; +} pdev_cli_config_t; + +/** + * struct vdev_cli_config_t - store vdev parameters + * @nss: nss width + * @ldpc: is ldpc is enable/disable + * @tx_stbc: TX STBC is enable/disable + * @rx_stbc: RX STBC is enable/disable + * @shortgi: short gi is enable/disable + * @rtscts_en: RTS/CTS is enable/disable + * @chwidth: channel width + * @tx_rate: tx rate + * @ampdu: ampdu size + * @amsdu: amsdu size + * @erx_adjust: enable/disable early rx enable + * @erx_bmiss_num: target bmiss number per sample + * @erx_bmiss_cycle: sample cycle + * @erx_slop_step: slop_step value + * @erx_init_slop: init slop + * @erx_adj_pause: pause adjust enable/disable + * @erx_dri_sample: enable/disable drift sample + * @pps_params: packet power save parameters + * @qpower_params: qpower parameters + * @gtx_info: GTX offload info + * + * This structure stores vdev parameters. + * Some of these parameters are set in fw and some + * parameters are only maintained in host. + */ +typedef struct { + uint32_t nss; + uint32_t ldpc; + uint32_t tx_stbc; + uint32_t rx_stbc; + uint32_t shortgi; + uint32_t rtscts_en; + uint32_t chwidth; + uint32_t tx_rate; + uint32_t ampdu; + uint32_t amsdu; + uint32_t erx_adjust; + uint32_t erx_bmiss_num; + uint32_t erx_bmiss_cycle; + uint32_t erx_slop_step; + uint32_t erx_init_slop; + uint32_t erx_adj_pause; + uint32_t erx_dri_sample; + struct pps pps_params; + struct qpower_params qpower_params; + gtx_config_t gtx_info; +} vdev_cli_config_t; + +/** + * struct wma_version_info - Store wmi version info + * @major: wmi major version + * @minor: wmi minor version + * @revision: wmi revision number + */ +struct wma_version_info { + u_int32_t major; + u_int32_t minor; + u_int32_t revision; +}; + +/** + * struct wma_wow - store wow patterns + * @magic_ptrn_enable: magic pattern enable/disable + * @wow_enable: wow enable/disable + * @wow_enable_cmd_sent: is wow enable command sent to fw + * @deauth_enable: is deauth wakeup enable/disable + * @disassoc_enable: is disassoc wakeup enable/disable + * @bmiss_enable: is bmiss wakeup enable/disable + * @gtk_pdev_enable: is GTK based wakeup enable/disable + * @gtk_err_enable: is GTK error wakeup enable/disable + * @lphb_cache: lphb cache + * + * This structure stores wow patterns and + * wow related parameters in host. + */ +struct wma_wow { + bool magic_ptrn_enable; + bool wow_enable; + bool wow_enable_cmd_sent; + bool deauth_enable; + bool disassoc_enable; + bool bmiss_enable; + bool gtk_err_enable[WMA_MAX_SUPPORTED_BSS]; +#ifdef FEATURE_WLAN_LPHB + /* currently supports only vdev 0. + * cache has two entries: one for TCP and one for UDP. + */ + tSirLPHBReq lphb_cache[2]; +#endif +}; + +#ifdef WLAN_FEATURE_11W +#define CMAC_IPN_LEN (6) +#define WMA_IGTK_KEY_INDEX_4 (4) +#define WMA_IGTK_KEY_INDEX_5 (5) + +/** + * struct wma_igtk_ipn_t - GTK IPN info + * @ipn: IPN info + */ +typedef struct { + uint8_t ipn[CMAC_IPN_LEN]; +} wma_igtk_ipn_t; + +/** + * struct wma_igtk_key_t - GTK key + * @key_length: key length + * @key: key + * @key_id: key id + */ +typedef struct { + uint16_t key_length; + uint8_t key[CSR_AES_KEY_LEN]; + + /* IPN is maintained per iGTK keyID + * 0th index for iGTK keyID = 4; + * 1st index for iGTK KeyID = 5 + */ + wma_igtk_ipn_t key_id[2]; +} wma_igtk_key_t; +#endif + +/** + * struct vdev_restart_params_t - vdev restart parameters + * @vdev_id: vdev id + * @ssid: ssid + * @flags: flags + * @requestor_id: requestor id + * @chan: channel + * @hidden_ssid_restart_in_progress: hidden ssid restart flag + * @ssidHidden: is ssid hidden or not + */ +typedef struct { + A_UINT32 vdev_id; + wmi_ssid ssid; + A_UINT32 flags; + A_UINT32 requestor_id; + A_UINT32 disable_hw_ack; + wmi_channel chan; + qdf_atomic_t hidden_ssid_restart_in_progress; + uint8_t ssidHidden; +} vdev_restart_params_t; + +/** + * struct wma_txrx_node - txrx node + * @addr: mac address + * @bssid: bssid + * @handle: wma handle + * @beacon: beacon info + * @vdev_restart_params: vdev restart parameters + * @config: per vdev config parameters + * @scan_info: scan info + * @type: type + * @sub_type: sub type + * @nlo_match_evt_received: is nlo match event received or not + * @pno_in_progress: is pno in progress or not + * @plm_in_progress: is plm in progress or not + * @ptrn_match_enable: is pattern match is enable or not + * @num_wow_default_patterns: number of default wow patterns configured for vdev + * @num_wow_user_patterns: number of user wow patterns configured for vdev + * @conn_state: connection state + * @beaconInterval: beacon interval + * @llbCoexist: 11b coexist + * @shortSlotTimeSupported: is short slot time supported or not + * @dtimPeriod: DTIM period + * @chanmode: channel mode + * @vht_capable: VHT capablity flag + * @ht_capable: HT capablity flag + * @mhz: channel frequency in KHz + * @chan_width: channel bandwidth + * @vdev_up: is vdev up or not + * @tsfadjust: TSF adjust + * @addBssStaContext: add bss context + * @aid: association id + * @rmfEnabled: Robust Management Frame (RMF) enabled/disabled + * @key: GTK key + * @uapsd_cached_val: uapsd cached value + * @stats_rsp: stats response + * @fw_stats_set: fw stats value + * @del_staself_req: delete sta self request + * @bss_status: bss status + * @rate_flags: rate flags + * @nss: nss value + * @is_channel_switch: is channel switch + * @pause_bitmap: pause bitmap + * @tx_power: tx power in dbm + * @max_tx_power: max tx power in dbm + * @nwType: network type (802.11a/b/g/n/ac) + * @staKeyParams: sta key parameters + * @ps_enabled: is powersave enable/disable + * @restore_dtim_setting: DTIM settings restore flag + * @peer_count: peer count + * @roam_synch_in_progress: flag is in progress or not + * @plink_status_req: link status request + * @psnr_req: snr request + * @delay_before_vdev_stop: delay + * @tx_streams: number of tx streams can be used by the vdev + * @rx_streams: number of rx streams can be used by the vdev + * @chain_mask: chain mask can be used by the vdev + * @mac_id: the mac on which vdev is on + * @wep_default_key_idx: wep default index for group key + * @arp_offload_req: cached arp offload request + * @ns_offload_req: cached ns offload request + * @wow_stats: stat counters for WoW related events + * @rcpi_req: rcpi request + * It stores parameters per vdev in wma. + * @in_bmps : Whether bmps for this interface has been enabled + */ +struct wma_txrx_node { + uint8_t addr[IEEE80211_ADDR_LEN]; + uint8_t bssid[IEEE80211_ADDR_LEN]; + void *handle; + struct beacon_info *beacon; + vdev_restart_params_t vdev_restart_params; + vdev_cli_config_t config; + struct scan_param scan_info; + uint32_t type; + uint32_t sub_type; +#ifdef FEATURE_WLAN_SCAN_PNO + bool nlo_match_evt_received; + bool pno_in_progress; +#endif +#ifdef FEATURE_WLAN_ESE + bool plm_in_progress; +#endif + bool ptrn_match_enable; + uint8_t num_wow_default_patterns; + uint8_t num_wow_user_patterns; + bool conn_state; + tSirMacBeaconInterval beaconInterval; + uint8_t llbCoexist; + uint8_t shortSlotTimeSupported; + uint8_t dtimPeriod; + WLAN_PHY_MODE chanmode; + uint8_t vht_capable; + uint8_t ht_capable; + A_UINT32 mhz; + enum phy_ch_width chan_width; + bool vdev_active; + bool vdev_up; + uint64_t tsfadjust; + void *addBssStaContext; + uint8_t aid; + uint8_t rmfEnabled; +#ifdef WLAN_FEATURE_11W + wma_igtk_key_t key; +#endif /* WLAN_FEATURE_11W */ + uint32_t uapsd_cached_val; + tAniGetPEStatsRsp *stats_rsp; + uint8_t fw_stats_set; + void *del_staself_req; + qdf_atomic_t bss_status; + uint8_t rate_flags; + uint8_t nss; + bool is_channel_switch; + uint16_t pause_bitmap; + int8_t tx_power; + int8_t max_tx_power; + uint32_t nwType; + void *staKeyParams; + bool restore_dtim_setting; + uint32_t peer_count; + bool roam_synch_in_progress; + void *plink_status_req; + void *psnr_req; + uint8_t delay_before_vdev_stop; +#ifdef FEATURE_WLAN_EXTSCAN + bool extscan_in_progress; +#endif + uint32_t alt_modulated_dtim; + bool alt_modulated_dtim_enabled; + uint32_t tx_streams; + uint32_t rx_streams; + uint32_t chain_mask; + uint32_t mac_id; + bool roaming_in_progress; + int32_t roam_synch_delay; + uint8_t nss_2g; + uint8_t nss_5g; + bool p2p_lo_in_progress; + uint8_t wep_default_key_idx; + tSirHostOffloadReq arp_offload_req; + tSirHostOffloadReq ns_offload_req; + bool is_vdev_valid; + struct sir_vdev_wow_stats wow_stats; + struct sme_rcpi_req *rcpi_req; + bool in_bmps; + struct beacon_filter_param beacon_filter; + bool beacon_filter_enabled; +}; + +#if defined(QCA_WIFI_FTM) +#define MAX_UTF_EVENT_LENGTH 2048 +#define MAX_WMI_UTF_LEN 252 + +/** + * struct SEG_HDR_INFO_STRUCT - header info + * @len: length + * @msgref: message refrence + * @segmentInfo: segment info + * @pad: padding + */ +typedef struct { + A_UINT32 len; + A_UINT32 msgref; + A_UINT32 segmentInfo; + A_UINT32 pad; +} SEG_HDR_INFO_STRUCT; + +/** + * struct utf_event_info - UTF event info + * @data: data ptr + * @length: length + * @offset: offset + * @currentSeq: curent squence + * @expectedSeq: expected sequence + */ +struct utf_event_info { + uint8_t *data; + uint32_t length; + qdf_size_t offset; + uint8_t currentSeq; + uint8_t expectedSeq; +}; +#endif + +/** + * struct scan_timer_info - scan timer info + * @vdev_id: vdev id + * @scan_id: scan id + */ +typedef struct { + uint8_t vdev_id; + uint32_t scan_id; +} scan_timer_info; + +/** + * struct ibss_power_save_params - IBSS power save parameters + * @atimWindowLength: ATIM window length + * @isPowerSaveAllowed: is power save allowed + * @isPowerCollapseAllowed: is power collapsed allowed + * @isAwakeonTxRxEnabled: is awake on tx/rx enabled + * @inactivityCount: inactivity count + * @txSPEndInactivityTime: tx SP end inactivity time + * @ibssPsWarmupTime: IBSS power save warm up time + * @ibssPs1RxChainInAtimEnable: IBSS power save rx chain in ATIM enable + */ +typedef struct { + uint32_t atimWindowLength; + uint32_t isPowerSaveAllowed; + uint32_t isPowerCollapseAllowed; + uint32_t isAwakeonTxRxEnabled; + uint32_t inactivityCount; + uint32_t txSPEndInactivityTime; + uint32_t ibssPsWarmupTime; + uint32_t ibssPs1RxChainInAtimEnable; +} ibss_power_save_params; + +/** + * struct dbs_hw_mode_info - WLAN_DBS_HW_MODES_TLV Format + * @tlv_header: TLV header, TLV tag and len; tag equals WMITLV_TAG_ARRAY_UINT32 + * @hw_mode_list: WLAN_DBS_HW_MODE_LIST entries + */ +struct dbs_hw_mode_info { + uint32_t tlv_header; + uint32_t *hw_mode_list; +}; + +/** + * struct mac_ss_bw_info - hw_mode_list PHY/MAC params for each MAC + * @mac_tx_stream: Max TX stream + * @mac_rx_stream: Max RX stream + * @mac_bw: Max bandwidth + */ +struct mac_ss_bw_info { + uint32_t mac_tx_stream; + uint32_t mac_rx_stream; + uint32_t mac_bw; +}; + +/* Current HTC credit is 2, pool size of 50 is sufficient */ +#define WMI_DESC_POOL_MAX 50 + +/** + * struct wmi_desc_t - wmi management Tx descriptor. + * @tx_cmpl_cb_func: completion callback function, when DL completion and + * OTA done. + * @ota_post_proc_func: Post process callback function registered. + * @nbuf: Network buffer to be freed. + * @desc_id: WMI descriptor. + */ + +struct wmi_desc_t { + pWMATxRxCompFunc tx_cmpl_cb; + pWMAAckFnTxComp ota_post_proc_cb; + qdf_nbuf_t nbuf; + uint32_t desc_id; + uint8_t vdev_id; +}; + +/** + * union wmi_desc_elem_t - linked list wmi desc pool. + * @next: Pointer next descritor in the pool. + * @wmi_desc: wmi descriptor element. + */ +union wmi_desc_elem_t { + union wmi_desc_elem_t *next; + struct wmi_desc_t wmi_desc; +}; + +/** + * struct dual_mac_config - Dual MAC configurations + * @prev_scan_config: Previous scan configuration + * @prev_fw_mode_config: Previous FW mode configuration + * @cur_scan_config: Current scan configuration + * @cur_fw_mode_config: Current FW mode configuration + * @req_scan_config: Requested scan configuration + * @req_fw_mode_config: Requested FW mode configuration + */ +struct dual_mac_config { + uint32_t prev_scan_config; + uint32_t prev_fw_mode_config; + uint32_t cur_scan_config; + uint32_t cur_fw_mode_config; + uint32_t req_scan_config; + uint32_t req_fw_mode_config; + +}; + + +/** + * struct wma_ini_config - Structure to hold wma ini configuration + * @max_no_of_peers: Max Number of supported + * + * Placeholder for WMA ini parameters. + */ +struct wma_ini_config { + uint8_t max_no_of_peers; +}; + +/** + * struct wmi_valid_channels - Channel details part of WMI_SCAN_CHAN_LIST_CMDID + * @num_channels: Number of channels + * @channel_list: Channel list + */ +struct wma_valid_channels { + uint8_t num_channels; + uint8_t channel_list[MAX_NUM_CHAN]; +}; + +/** + * struct hw_mode_idx_to_mac_cap_idx - map between hw_mode to capabilities + * @num_of_macs: number of macs/PHYs for given hw_mode through hw_mode_id + * @mac_cap_idx: index of the mac/PHY for given hw_mode through hw_mode_id + * @hw_mode_id: given hw_mode id + */ +struct hw_mode_idx_to_mac_cap_idx { + uint8_t num_of_macs; + uint8_t mac_cap_idx; + uint8_t hw_mode_id; +}; + +/** + * struct extended_caps - new extended caps given by firmware + * @num_hw_modes: number of hardware modes for current SOC + * @each_hw_mode_cap: hw mode id to phy id mapping + * @each_phy_cap_per_hwmode: PHY's caps for each hw mode + * @num_phy_for_hal_reg_cap: number of phy for hal reg cap + * @hw_mode_to_mac_cap_map: map between hw_mode to capabilities + */ +struct extended_caps { + WMI_SOC_MAC_PHY_HW_MODE_CAPS num_hw_modes; + WMI_HW_MODE_CAPABILITIES *each_hw_mode_cap; + WMI_MAC_PHY_CAPABILITIES *each_phy_cap_per_hwmode; + WMI_SOC_HAL_REG_CAPABILITIES num_phy_for_hal_reg_cap; + WMI_HAL_REG_CAPABILITIES_EXT *each_phy_hal_reg_cap; + struct hw_mode_idx_to_mac_cap_idx *hw_mode_to_mac_cap_map; +}; + +/** + * struct peer_debug_rec - peer debug information record definition + * @time: timestamp when record was added + * @operation: identifier for operation, command, event, etc. + * @vdev_id: vdev identifier + * @peer_id: peer_id. Range 0 - 255, 0xffff is invalid peer_id. + * @mac_addr: mac address of peer + * @peer_obj: pointer to peer object + * @arg1: Optional argument #1 + * @arg2: Opttional argument #2 + */ +struct peer_debug_rec { + uint64_t time; + uint8_t operation; + uint8_t vdev_id; + uint16_t peer_id; + struct qdf_mac_addr mac_addr; + void *peer_obj; + uint32_t arg1; + uint32_t arg2; +}; + +#define WMA_PEER_DEBUG_MAX_REC 256 +/** + * struct peer_debug_info - Buffer to store the peer debug records + * @index: index of the most recent entry in the circular buffer + * @num_max_rec: maximum records stored in the records array + * @rec: array to store peer debug records, used in circular fashion + */ +struct peer_debug_info { + qdf_atomic_t index; + uint32_t num_max_rec; + struct peer_debug_rec rec[WMA_PEER_DEBUG_MAX_REC]; +}; + +/** + * struct t_wma_handle - wma context + * @wmi_handle: wmi handle + * @htc_handle: htc handle + * @cds_context: cds handle + * @mac_context: mac context + * @wma_ready_event: wma rx ready event + * @wma_resume_event: wma resume event + * @target_suspend: target suspend event + * @recovery_event: wma FW recovery event + * @max_station: max stations + * @max_bssid: max bssid + * @driver_type: driver type + * @myaddr: current mac address + * @hwaddr: mac address from EEPROM + * @target_abi_vers: target firmware version + * @final_abi_vers: The final ABI version to be used for communicating + * @target_fw_version: Target f/w build version + * @target_fw_vers_ext: Target f/w build version sub id + * @lpss_support: LPSS feature is supported in target or not + * @egap_support: Enhanced Green AP support flag + * @wmi_ready: wmi status flag + * @wlan_init_status: wlan init status + * @qdf_dev: qdf device + * @phy_capability: PHY Capability from Target + * @max_frag_entry: Max number of Fragment entry + * @wmi_service_bitmap: wmi services bitmap received from Target + * @wlan_resource_config: resource config + * @frameTransRequired: frame transmission required + * @wmaGlobalSystemRole: global system role + * @tx_frm_download_comp_cb: Tx Frame Compl Cb registered by umac + * @tx_frm_download_comp_event: Event to wait for tx download completion + * @tx_queue_empty_event: wait for tx queue to get flushed + * @umac_ota_ack_cb: Ack Complete Callback registered by umac + * @umac_data_ota_ack_cb: ack complete callback + * @last_umac_data_ota_timestamp: timestamp when OTA of last umac data was done + * @last_umac_data_nbuf: cache nbuf ptr for the last umac data buf + * @needShutdown: is shutdown needed or not + * @num_mem_chunks: number of memory chunk + * @mem_chunks: memory chunks + * @tgt_cfg_update_cb: configuration update callback + * @dfs_radar_indication_cb: Callback to indicate radar to HDD + * @reg_cap: regulatory capablities + * @scan_id: scan id + * @interfaces: txrx nodes(per vdev) + * @pdevconfig: pdev related configrations + * @vdev_resp_queue: vdev response queue + * @vdev_respq_lock: vdev response queue lock + * @ht_cap_info: HT capablity info + * @vht_cap_info: VHT capablity info + * @vht_supp_mcs: VHT supported MCS + * @num_rf_chains: number of RF chains + * @utf_event_info: UTF event information + * @is_fw_assert: is fw asserted + * @wow: wow related patterns & parameters + * @no_of_suspend_ind: number of suspend indications + * @no_of_resume_ind: number of resume indications + * @mArpInfo: arp info + * @powersave_mode: power save mode + * @ptrn_match_enable_all_vdev: is pattern match is enable/disable + * @pGetRssiReq: get RSSI request + * @thermal_mgmt_info: Thermal mitigation related info + * @roam_offload_enabled: is roam offload enable/disable + * @ol_ini_info: store ini status of arp offload, ns offload + * @ssdp: ssdp flag + * @enable_mc_list : To Check if Multicast list filtering is enabled in FW + * @ibss_started: is IBSS started or not + * @ibsskey_info: IBSS key info + * @dfs_ic: DFS umac interface information + * @hddTxFailCb: tx fail indication callback + * @pno_wake_lock: PNO wake lock + * @extscan_wake_lock: extscan wake lock + * @wow_wake_lock: wow wake lock + * @wow_nack: wow negative ack flag + * @ap_client_cnt: ap client count + * @is_wow_bus_suspended: is wow bus suspended flag + * @wma_scan_comp_timer: scan completion timer + * @dfs_phyerr_filter_offload: dfs phy error filter is offloaded or not + * @suitable_ap_hb_failure: better ap found + * @suitable_ap_hb_failure_rssi: record the RSSI when suitable_ap_hb_failure + * for later usage to report RSSI at beacon miss scenario + * @wma_ibss_power_save_params: IBSS Power Save config Parameters + * @IsRArateLimitEnabled: RA rate limiti s enabled or not + * @RArateLimitInterval: RA rate limit interval + * @is_lpass_enabled: Flag to indicate if LPASS feature is enabled or not + * @is_nan_enabled: Flag to indicate if NaN feature is enabled or not + * @staMaxLIModDtim: station max listen interval + * @staModDtim: station mode DTIM + * @staDynamicDtim: station dynamic DTIM + * @enable_mhf_offload: is MHF offload enable/disable + * @last_mhf_entries_timestamp: timestamp when last entries where set + * @dfs_pri_multiplier: DFS multiplier + * @hw_bd_id: hardware board id + * @hw_bd_info: hardware board info + * @in_d0wow: D0WOW is enable/disable + * @miracast_value: miracast value + * @log_completion_timer: log completion timer + * @mgmt_rx: management rx callback + * @num_dbs_hw_modes: Number of HW modes supported by the FW + * @dbs_mode: DBS HW mode list + * @old_hw_mode_index: Previous configured HW mode index + * @new_hw_mode_index: Current configured HW mode index + * @extended_caps phy_caps: extended caps per hw mode + * @peer_authorized_cb: peer authorized hdd callback + * @ocb_callback: callback to OCB commands + * @ocb_resp: response to OCB commands + * @wow_pno_match_wake_up_count: PNO match wake up count + * @wow_pno_complete_wake_up_count: PNO complete wake up count + * @wow_gscan_wake_up_count: Gscan wake up count + * @wow_low_rssi_wake_up_count: Low rssi wake up count + * @wow_rssi_breach_wake_up_count: RSSI breach wake up count + * @wow_ucast_wake_up_count: WoW unicast packet wake up count + * @wow_bcast_wake_up_count: WoW brodcast packet wake up count + * @wow_ipv4_mcast_wake_up_count: WoW IPV4 mcast packet wake up count + * @wow_ipv6_mcast_wake_up_count: WoW IPV6 mcast packet wake up count + * @wow_ipv6_mcast_ra_stats: WoW IPV6 mcast RA packet wake up count + * @wow_ipv6_mcast_ns_stats: WoW IPV6 mcast NS packet wake up count + * @wow_ipv6_mcast_na_stats: WoW IPV6 mcast NA packet wake up count + * @wow_icmpv4_count: WoW ipv4 icmp packet wake up count + * @wow_icmpv6_count: WoW ipv6 icmp packet wake up count + * @dual_mac_cfg: Dual mac configuration params for scan and fw mode + * + * @max_scan: maximum scan requests than can be queued + * This structure is global wma context + * It contains global wma module parameters and + * handle of other modules. + * @saved_wmi_init_cmd: Saved WMI INIT command + * @bpf_packet_filter_enable: BPF filter enabled or not + * @active_bpf_mode: Setting that determines how BPF is applied in active mode + * @service_ready_ext_evt: Wait event for service ready ext + * @wmi_cmd_rsp_wake_lock: wmi command response wake lock + * @wmi_cmd_rsp_runtime_lock: wmi command response bus lock + * @saved_chan: saved channel list sent as part of WMI_SCAN_CHAN_LIST_CMDID + * @fw_mem_dump_enabled: Fw memory dump support + * @ito_repeat_count: Indicates ito repeated count + */ +typedef struct { + void *wmi_handle; + void *htc_handle; + void *cds_context; + void *mac_context; + qdf_event_t wma_ready_event; + qdf_event_t wma_resume_event; + qdf_event_t target_suspend; + qdf_event_t runtime_suspend; + qdf_event_t recovery_event; + uint16_t max_station; + uint16_t max_bssid; + t_wma_drv_type driver_type; + uint8_t myaddr[IEEE80211_ADDR_LEN]; + uint8_t hwaddr[IEEE80211_ADDR_LEN]; + wmi_abi_version target_abi_vers; + wmi_abi_version final_abi_vers; + uint32_t target_fw_version; + uint32_t target_fw_vers_ext; +#ifdef WLAN_FEATURE_LPSS + uint8_t lpss_support; +#endif + uint8_t ap_arpns_support; +#ifdef FEATURE_GREEN_AP + bool egap_support; +#endif + bool wmi_ready; + uint32_t wlan_init_status; + qdf_device_t qdf_dev; + uint32_t phy_capability; + uint32_t max_frag_entry; + uint32_t wmi_service_bitmap[WMI_SERVICE_BM_SIZE]; + wmi_resource_config wlan_resource_config; + uint32_t frameTransRequired; + tBssSystemRole wmaGlobalSystemRole; + pWMATxRxCompFunc tx_frm_download_comp_cb; + qdf_event_t tx_frm_download_comp_event; + /* + * Dummy event to wait for draining MSDUs left in hardware tx + * queue and before requesting VDEV_STOP. Nobody will set this + * and wait will timeout, and code will poll the pending tx + * descriptors number to be zero. + */ + qdf_event_t tx_queue_empty_event; + pWMAAckFnTxComp umac_ota_ack_cb[SIR_MAC_MGMT_RESERVED15]; + pWMAAckFnTxComp umac_data_ota_ack_cb; + unsigned long last_umac_data_ota_timestamp; + qdf_nbuf_t last_umac_data_nbuf; + bool needShutdown; + uint32_t num_mem_chunks; + struct wmi_host_mem_chunk mem_chunks[MAX_MEM_CHUNKS]; + wma_tgt_cfg_cb tgt_cfg_update_cb; + wma_dfs_radar_indication_cb dfs_radar_indication_cb; + HAL_REG_CAPABILITIES reg_cap; + uint32_t scan_id; + struct wma_txrx_node *interfaces; + pdev_cli_config_t pdevconfig; + qdf_list_t vdev_resp_queue; + qdf_spinlock_t vdev_respq_lock; + qdf_list_t wma_hold_req_queue; + qdf_spinlock_t wma_hold_req_q_lock; + uint32_t ht_cap_info; + uint32_t vht_cap_info; + uint32_t vht_supp_mcs; + uint32_t num_rf_chains; +#if defined(QCA_WIFI_FTM) + struct utf_event_info utf_event_info; +#endif + uint8_t is_fw_assert; + struct wma_wow wow; + uint8_t no_of_suspend_ind; + uint8_t no_of_resume_ind; + /* Have a back up of arp info to send along + * with ns info suppose if ns also enabled + */ + tSirHostOffloadReq mArpInfo; + struct wma_tx_ack_work_ctx *ack_work_ctx; + uint8_t powersave_mode; + bool ptrn_match_enable_all_vdev; + void *pGetRssiReq; + t_thermal_mgmt thermal_mgmt_info; + bool roam_offload_enabled; + /* Here ol_ini_info is used to store ini + * status of arp offload, ns offload + * and others. Currently 1st bit is used + * for arp off load and 2nd bit for ns + * offload currently, rest bits are unused + */ + uint8_t ol_ini_info; + bool ssdp; + bool enable_mc_list; + uint8_t ibss_started; + tSetBssKeyParams ibsskey_info; + struct ieee80211com *dfs_ic; + txFailIndCallback hddTxFailCb; +#ifdef FEATURE_WLAN_SCAN_PNO + qdf_wake_lock_t pno_wake_lock; +#endif +#ifdef FEATURE_WLAN_EXTSCAN + qdf_wake_lock_t extscan_wake_lock; +#endif + qdf_wake_lock_t wow_wake_lock; + int wow_nack; + bool wow_initial_wake_up; + qdf_atomic_t is_wow_bus_suspended; + qdf_mc_timer_t wma_scan_comp_timer; + uint8_t dfs_phyerr_filter_offload; + bool suitable_ap_hb_failure; + uint32_t suitable_ap_hb_failure_rssi; + ibss_power_save_params wma_ibss_power_save_params; +#ifdef FEATURE_WLAN_RA_FILTERING + bool IsRArateLimitEnabled; + uint16_t RArateLimitInterval; +#endif +#ifdef WLAN_FEATURE_LPSS + bool is_lpass_enabled; +#endif +#ifdef WLAN_FEATURE_NAN + bool is_nan_enabled; +#endif + uint8_t staMaxLIModDtim; + uint8_t staModDtim; + uint8_t staDynamicDtim; + uint8_t enable_mhf_offload; + unsigned long last_mhf_entries_timestamp; + int32_t dfs_pri_multiplier; + uint32_t hw_bd_id; + uint32_t hw_bd_info[HW_BD_INFO_SIZE]; + uint32_t miracast_value; + qdf_mc_timer_t log_completion_timer; + wma_mgmt_frame_rx_callback mgmt_rx; + uint32_t num_dbs_hw_modes; + struct dbs_hw_mode_info hw_mode; + uint32_t old_hw_mode_index; + uint32_t new_hw_mode_index; + struct extended_caps phy_caps; + qdf_atomic_t scan_id_counter; + wma_peer_authorized_fp peer_authorized_cb; + uint32_t wow_unspecified_wake_count; + + /* OCB request contexts */ + struct sir_ocb_config *ocb_config_req; + struct dual_mac_config dual_mac_cfg; + struct { + uint16_t pool_size; + uint16_t num_free; + union wmi_desc_elem_t *array; + union wmi_desc_elem_t *freelist; + qdf_spinlock_t wmi_desc_pool_lock; + } wmi_desc_pool; + uint8_t max_scan; + uint16_t self_gen_frm_pwr; + bool tx_chain_mask_cck; + /* Going with a timer instead of wait event because on receiving the + * service ready event, we will be waiting on the MC thread for the + * service extended ready event which is also processed in MC thread. + * This leads to MC thread being stuck. Alternative was to process + * these events in tasklet/workqueue context. But, this leads to + * race conditions when the events are processed in two different + * context. So, processing ready event and extended ready event in + * the serialized MC thread context with a timer. + */ + qdf_mc_timer_t service_ready_ext_timer; + QDF_STATUS (*csr_roam_synch_cb)(tpAniSirGlobal mac, + roam_offload_synch_ind *roam_synch_data, + tpSirBssDescription bss_desc_ptr, + enum sir_roam_op_code reason); + QDF_STATUS (*pe_roam_synch_cb)(tpAniSirGlobal mac, + roam_offload_synch_ind *roam_synch_data, + tpSirBssDescription bss_desc_ptr); + qdf_wake_lock_t wmi_cmd_rsp_wake_lock; + qdf_runtime_lock_t wmi_cmd_rsp_runtime_lock; + qdf_runtime_lock_t wma_runtime_resume_lock; + uint32_t fine_time_measurement_cap; + bool bpf_enabled; + bool bpf_packet_filter_enable; + enum active_bpf_mode active_bpf_mode; + struct wma_ini_config ini_config; + struct wma_valid_channels saved_chan; + /* NAN datapath support enabled in firmware */ + bool nan_datapath_enabled; + QDF_STATUS (*pe_ndp_event_handler)(tpAniSirGlobal mac_ctx, + cds_msg_t *msg); + bool fw_timeout_crash; + bool sub_20_support; + tp_wma_packetdump_cb wma_mgmt_tx_packetdump_cb; + tp_wma_packetdump_cb wma_mgmt_rx_packetdump_cb; + bool rcpi_enabled; + tSirLLStatsResults *link_stats_results; + bool fw_mem_dump_enabled; + bool tx_bfee_8ss_enabled; + tSirAddonPsReq ps_setting; + struct peer_debug_info *peer_dbg; + bool auto_power_save_enabled; + uint8_t in_imps; + uint64_t tx_fail_cnt; + uint64_t wmi_desc_fail_count; + uint8_t ito_repeat_count; +} t_wma_handle, *tp_wma_handle; + +/** + * struct wma_target_cap - target capabality + * @wmi_service_bitmap: wmi services bitmap + * @wlan_resource_config: resource config + */ +struct wma_target_cap { + /* wmi services bitmap received from Target */ + uint32_t wmi_service_bitmap[WMI_SERVICE_BM_SIZE]; + /* default resource config,the os shim can overwrite it */ + wmi_resource_config wlan_resource_config; +}; + +/** + * struct t_wma_start_req - wma start request parameters + * @pConfigBuffer: config buffer + * @usConfigBufferLen: Length of the config buffer above + * @driver_type: Production or FTM driver + * @pUserData: user data + * @pIndUserData: indication function pointer to send to UMAC + * + * The shared memory between WDI and HAL is 4K so maximum data can be + * transferred from WDI to HAL is 4K + */ +typedef struct { + void *pConfigBuffer; + uint16_t usConfigBufferLen; + t_wma_drv_type driver_type; + void *pUserData; + void *pIndUserData; +} t_wma_start_req; + +/* Enumeration for Version */ +typedef enum { + WLAN_HAL_MSG_VERSION0 = 0, + WLAN_HAL_MSG_VERSION1 = 1, + WLAN_HAL_MSG_WCNSS_CTRL_VERSION = 0x7FFF, /*define as 2 bytes data */ + WLAN_HAL_MSG_VERSION_MAX_FIELD = WLAN_HAL_MSG_WCNSS_CTRL_VERSION +} tHalHostMsgVersion; + +/** + * struct sHalMacStartParameter - mac start request parameters + * @driverType: driver type (production/FTM) + * @uConfigBufferLen: length of config buffer + */ +typedef struct qdf_packed sHalMacStartParameter { + tDriverType driverType; + uint32_t uConfigBufferLen; + + /* Following this there is a TLV formatted buffer of length + * "uConfigBufferLen" bytes containing all config values. + * The TLV is expected to be formatted like this: + * 0 15 31 31+CFG_LEN-1 length-1 + * | CFG_ID | CFG_LEN | CFG_BODY | CFG_ID |......| + */ +} tHalMacStartParameter, *tpHalMacStartParameter; + +extern void cds_wma_complete_cback(void *p_cds_context); +extern void wma_send_regdomain_info_to_fw(uint32_t reg_dmn, uint16_t regdmn2G, + uint16_t regdmn5G, int8_t ctl2G, + int8_t ctl5G); +/** + * enum frame_index - Frame index + * @GENERIC_NODOWNLD_NOACK_COMP_INDEX: Frame index for no download comp no ack + * @GENERIC_DOWNLD_COMP_NOACK_COMP_INDEX: Frame index for download comp no ack + * @GENERIC_DOWNLD_COMP_ACK_COMP_INDEX: Frame index for download comp and ack + * @GENERIC_NODOWLOAD_ACK_COMP_INDEX: Frame index for no download comp and ack + * @FRAME_INDEX_MAX: maximum frame index + */ +enum frame_index { + GENERIC_NODOWNLD_NOACK_COMP_INDEX, + GENERIC_DOWNLD_COMP_NOACK_COMP_INDEX, + GENERIC_DOWNLD_COMP_ACK_COMP_INDEX, + GENERIC_NODOWLOAD_ACK_COMP_INDEX, + FRAME_INDEX_MAX +}; + +/** + * struct wma_tx_ack_work_ctx - tx ack work context + * @wma_handle: wma handle + * @sub_type: sub type + * @status: status + * @ack_cmp_work: work structure + */ +struct wma_tx_ack_work_ctx { + tp_wma_handle wma_handle; + uint16_t sub_type; + int32_t status; + qdf_work_t ack_cmp_work; +}; + +/** + * struct wma_target_req - target request parameters + * @event_timeout: event timeout + * @node: list + * @user_data: user data + * @msg_type: message type + * @vdev_id: vdev id + * @type: type + */ +struct wma_target_req { + qdf_mc_timer_t event_timeout; + qdf_list_node_t node; + void *user_data; + uint32_t msg_type; + uint8_t vdev_id; + uint8_t type; +}; + +/** + * struct wma_vdev_start_req - vdev start request parameters + * @beacon_intval: beacon interval + * @dtim_period: dtim period + * @max_txpow: max tx power + * @chan_offset: channel offset + * @is_dfs: is dfs supported or not + * @vdev_id: vdev id + * @chan: channel + * @oper_mode: operating mode + * @ssid: ssid + * @hidden_ssid: hidden ssid + * @pmf_enabled: is pmf enabled or not + * @vht_capable: VHT capabality + * @ht_capable: HT capabality + * @dfs_pri_multiplier: DFS multiplier + * @dot11_mode: 802.11 mode + * @is_half_rate: is the channel operating at 10MHz + * @is_quarter_rate: is the channel operating at 5MHz + * @preferred_tx_streams: policy manager indicates the preferred + * number of transmit streams + * @preferred_rx_streams: policy manager indicates the preferred + * number of receive streams + */ +struct wma_vdev_start_req { + uint32_t beacon_intval; + uint32_t dtim_period; + int32_t max_txpow; + enum phy_ch_width chan_width; + bool is_dfs; + uint8_t vdev_id; + uint8_t chan; + uint8_t oper_mode; + tSirMacSSid ssid; + uint8_t hidden_ssid; + uint8_t pmf_enabled; + uint8_t vht_capable; + uint8_t ch_center_freq_seg0; + uint8_t ch_center_freq_seg1; + uint8_t ht_capable; + int32_t dfs_pri_multiplier; + uint8_t dot11_mode; + bool is_half_rate; + bool is_quarter_rate; + uint32_t preferred_tx_streams; + uint32_t preferred_rx_streams; + uint8_t beacon_tx_rate; +}; + +/** + * struct wma_set_key_params - set key parameters + * @vdev_id: vdev id + * @def_key_idx: used to see if we have to read the key from cfg + * @key_len: key length + * @peer_mac: peer mac address + * @singl_tid_rc: 1=Single TID based Replay Count, 0=Per TID based RC + * @key_type: key type + * @key_idx: key index + * @unicast: unicast flag + * @key_data: key data + */ +struct wma_set_key_params { + uint8_t vdev_id; + /* def_key_idx can be used to see if we have to read the key from cfg */ + uint32_t def_key_idx; + uint16_t key_len; + uint8_t peer_mac[IEEE80211_ADDR_LEN]; + uint8_t singl_tid_rc; + enum eAniEdType key_type; + uint32_t key_idx; + bool unicast; + uint8_t key_data[SIR_MAC_MAX_KEY_LENGTH]; +}; + +/** + * struct t_thermal_cmd_params - thermal command parameters + * @minTemp: minimum temprature + * @maxTemp: maximum temprature + * @thermalEnable: thermal enable + */ +typedef struct { + uint16_t minTemp; + uint16_t maxTemp; + uint8_t thermalEnable; +} t_thermal_cmd_params, *tp_thermal_cmd_params; + +/** + * enum wma_cfg_cmd_id - wma cmd ids + * @WMA_VDEV_TXRX_FWSTATS_ENABLE_CMDID: txrx firmware stats enable command + * @WMA_VDEV_TXRX_FWSTATS_RESET_CMDID: txrx firmware stats reset command + * @WMA_VDEV_MCC_SET_TIME_LATENCY: set MCC latency time + * @WMA_VDEV_MCC_SET_TIME_QUOTA: set MCC time quota + * @WMA_VDEV_IBSS_SET_ATIM_WINDOW_SIZE: set IBSS ATIM window size + * @WMA_VDEV_IBSS_SET_POWER_SAVE_ALLOWED: set IBSS enable power save + * @WMA_VDEV_IBSS_SET_POWER_COLLAPSE_ALLOWED: set IBSS power collapse enable + * @WMA_VDEV_IBSS_SET_AWAKE_ON_TX_RX: awake IBSS on TX/RX + * @WMA_VDEV_IBSS_SET_INACTIVITY_TIME: set IBSS inactivity time + * @WMA_VDEV_IBSS_SET_TXSP_END_INACTIVITY_TIME: set IBSS TXSP + * @WMA_VDEV_IBSS_PS_SET_WARMUP_TIME_SECS: set IBSS power save warmup time + * @WMA_VDEV_IBSS_PS_SET_1RX_CHAIN_IN_ATIM_WINDOW: set IBSS power save ATIM + * @WMA_VDEV_DFS_CONTROL_CMDID: DFS control command + * @WMA_VDEV_TXRX_GET_IPA_UC_FW_STATS_CMDID: get IPA microcontroller fw stats + * @WMA_VDEV_TXRX_GET_IPA_UC_SHARING_STATS_CMDID: get IPA uC wifi-sharing stats + * @WMA_VDEV_TXRX_SET_IPA_UC_QUOTA_CMDID: set IPA uC quota limit + * + * wma command ids for configuration request which + * does not involve sending a wmi command. + */ +enum wma_cfg_cmd_id { + WMA_VDEV_TXRX_FWSTATS_ENABLE_CMDID = WMI_CMDID_MAX, + WMA_VDEV_TXRX_FWSTATS_RESET_CMDID, + WMA_VDEV_MCC_SET_TIME_LATENCY, + WMA_VDEV_MCC_SET_TIME_QUOTA, + WMA_VDEV_IBSS_SET_ATIM_WINDOW_SIZE, + WMA_VDEV_IBSS_SET_POWER_SAVE_ALLOWED, + WMA_VDEV_IBSS_SET_POWER_COLLAPSE_ALLOWED, + WMA_VDEV_IBSS_SET_AWAKE_ON_TX_RX, + WMA_VDEV_IBSS_SET_INACTIVITY_TIME, + WMA_VDEV_IBSS_SET_TXSP_END_INACTIVITY_TIME, + WMA_VDEV_IBSS_PS_SET_WARMUP_TIME_SECS, + WMA_VDEV_IBSS_PS_SET_1RX_CHAIN_IN_ATIM_WINDOW, + WMA_VDEV_DFS_CONTROL_CMDID, + WMA_VDEV_TXRX_GET_IPA_UC_FW_STATS_CMDID, + WMA_VDEV_TXRX_GET_IPA_UC_SHARING_STATS_CMDID, + WMA_VDEV_TXRX_SET_IPA_UC_QUOTA_CMDID, + WMA_CMD_ID_MAX +}; + +/** + * struct wma_trigger_uapsd_params - trigger uapsd parameters + * @wmm_ac: wmm access catagory + * @user_priority: user priority + * @service_interval: service interval + * @suspend_interval: suspend interval + * @delay_interval: delay interval + */ +typedef struct wma_trigger_uapsd_params { + uint32_t wmm_ac; + uint32_t user_priority; + uint32_t service_interval; + uint32_t suspend_interval; + uint32_t delay_interval; +} t_wma_trigger_uapsd_params, *tp_wma_trigger_uapsd_params; + +/** + * enum uapsd_peer_param_max_sp - U-APSD maximum service period of peer station + * @UAPSD_MAX_SP_LEN_UNLIMITED: unlimited max service period + * @UAPSD_MAX_SP_LEN_2: max service period = 2 + * @UAPSD_MAX_SP_LEN_4: max service period = 4 + * @UAPSD_MAX_SP_LEN_6: max service period = 6 + */ +enum uapsd_peer_param_max_sp { + UAPSD_MAX_SP_LEN_UNLIMITED = 0, + UAPSD_MAX_SP_LEN_2 = 2, + UAPSD_MAX_SP_LEN_4 = 4, + UAPSD_MAX_SP_LEN_6 = 6 +}; + +/** + * enum uapsd_peer_param_enabled_ac - U-APSD Enabled AC's of peer station + * @UAPSD_VO_ENABLED: enable uapsd for voice + * @UAPSD_VI_ENABLED: enable uapsd for video + * @UAPSD_BK_ENABLED: enable uapsd for background + * @UAPSD_BE_ENABLED: enable uapsd for best effort + */ +enum uapsd_peer_param_enabled_ac { + UAPSD_VO_ENABLED = 0x01, + UAPSD_VI_ENABLED = 0x02, + UAPSD_BK_ENABLED = 0x04, + UAPSD_BE_ENABLED = 0x08 +}; + +/** + * enum profile_id_t - Firmware profiling index + * @PROF_CPU_IDLE: cpu idle profile + * @PROF_PPDU_PROC: ppdu processing profile + * @PROF_PPDU_POST: ppdu post profile + * @PROF_HTT_TX_INPUT: htt tx input profile + * @PROF_MSDU_ENQ: msdu enqueue profile + * @PROF_PPDU_POST_HAL: ppdu post profile + * @PROF_COMPUTE_TX_TIME: tx time profile + * @PROF_MAX_ID: max profile index + */ +enum profile_id_t { + PROF_CPU_IDLE, + PROF_PPDU_PROC, + PROF_PPDU_POST, + PROF_HTT_TX_INPUT, + PROF_MSDU_ENQ, + PROF_PPDU_POST_HAL, + PROF_COMPUTE_TX_TIME, + PROF_MAX_ID, +}; + +/** + * struct p2p_ie - P2P IE structural definition. + * @p2p_id: p2p id + * @p2p_len: p2p length + * @p2p_oui: p2p OUI + * @p2p_oui_type: p2p OUI type + */ +struct p2p_ie { + uint8_t p2p_id; + uint8_t p2p_len; + uint8_t p2p_oui[3]; + uint8_t p2p_oui_type; +} __packed; + +/** + * struct p2p_noa_descriptor - noa descriptor + * @type_count: 255: continuous schedule, 0: reserved + * @duration: Absent period duration in micro seconds + * @interval: Absent period interval in micro seconds + * @start_time: 32 bit tsf time when in starts + */ +struct p2p_noa_descriptor { + uint8_t type_count; + uint32_t duration; + uint32_t interval; + uint32_t start_time; +} __packed; + +/** + * struct p2p_sub_element_noa - p2p noa element + * @p2p_sub_id: p2p sub id + * @p2p_sub_len: p2p sub length + * @index: identifies instance of NOA su element + * @oppPS: oppPS state of the AP + * @ctwindow: ctwindow in TUs + * @num_descriptors: number of NOA descriptors + * @noa_descriptors: noa descriptors + */ +struct p2p_sub_element_noa { + uint8_t p2p_sub_id; + uint8_t p2p_sub_len; + uint8_t index; /* identifies instance of NOA su element */ + uint8_t oppPS:1, /* oppPS state of the AP */ + ctwindow:7; /* ctwindow in TUs */ + uint8_t num_descriptors; /* number of NOA descriptors */ + struct p2p_noa_descriptor noa_descriptors[WMA_MAX_NOA_DESCRIPTORS]; +}; + +/** + * struct wma_decap_info_t - decapsulation info + * @hdr: header + * @hdr_len: header length + */ +struct wma_decap_info_t { + uint8_t hdr[sizeof(struct ieee80211_qosframe_addr4)]; + int32_t hdr_len; +}; + +/** + * enum packet_power_save - packet power save params + * @WMI_VDEV_PPS_PAID_MATCH: paid match param + * @WMI_VDEV_PPS_GID_MATCH: gid match param + * @WMI_VDEV_PPS_EARLY_TIM_CLEAR: early tim clear param + * @WMI_VDEV_PPS_EARLY_DTIM_CLEAR: early dtim clear param + * @WMI_VDEV_PPS_EOF_PAD_DELIM: eof pad delim param + * @WMI_VDEV_PPS_MACADDR_MISMATCH: macaddr mismatch param + * @WMI_VDEV_PPS_DELIM_CRC_FAIL: delim CRC fail param + * @WMI_VDEV_PPS_GID_NSTS_ZERO: gid nsts zero param + * @WMI_VDEV_PPS_RSSI_CHECK: RSSI check param + * @WMI_VDEV_PPS_5G_EBT: 5G ebt param + */ +typedef enum { + WMI_VDEV_PPS_PAID_MATCH = 0, + WMI_VDEV_PPS_GID_MATCH = 1, + WMI_VDEV_PPS_EARLY_TIM_CLEAR = 2, + WMI_VDEV_PPS_EARLY_DTIM_CLEAR = 3, + WMI_VDEV_PPS_EOF_PAD_DELIM = 4, + WMI_VDEV_PPS_MACADDR_MISMATCH = 5, + WMI_VDEV_PPS_DELIM_CRC_FAIL = 6, + WMI_VDEV_PPS_GID_NSTS_ZERO = 7, + WMI_VDEV_PPS_RSSI_CHECK = 8, + WMI_VDEV_VHT_SET_GID_MGMT = 9, + WMI_VDEV_PPS_5G_EBT = 10 +} packet_power_save; + +/** + * enum green_tx_param - green tx parameters + * @WMI_VDEV_PARAM_GTX_HT_MCS: ht mcs param + * @WMI_VDEV_PARAM_GTX_VHT_MCS: vht mcs param + * @WMI_VDEV_PARAM_GTX_USR_CFG: user cfg param + * @WMI_VDEV_PARAM_GTX_THRE: thre param + * @WMI_VDEV_PARAM_GTX_MARGIN: green tx margin param + * @WMI_VDEV_PARAM_GTX_STEP: green tx step param + * @WMI_VDEV_PARAM_GTX_MINTPC: mintpc param + * @WMI_VDEV_PARAM_GTX_BW_MASK: bandwidth mask + */ +typedef enum { + WMI_VDEV_PARAM_GTX_HT_MCS, + WMI_VDEV_PARAM_GTX_VHT_MCS, + WMI_VDEV_PARAM_GTX_USR_CFG, + WMI_VDEV_PARAM_GTX_THRE, + WMI_VDEV_PARAM_GTX_MARGIN, + WMI_VDEV_PARAM_GTX_STEP, + WMI_VDEV_PARAM_GTX_MINTPC, + WMI_VDEV_PARAM_GTX_BW_MASK, +} green_tx_param; + +#ifdef FEATURE_WLAN_TDLS +/** + * struct wma_tdls_params - TDLS parameters + * @vdev_id: vdev id + * @tdls_state: TDLS state + * @notification_interval_ms: notification inerval + * @tx_discovery_threshold: tx discovery threshold + * @tx_teardown_threshold: tx teardown threashold + * @rssi_teardown_threshold: RSSI teardown threshold + * @rssi_delta: RSSI delta + * @tdls_options: TDLS options + * @peer_traffic_ind_window: raffic indication window + * @peer_traffic_response_timeout: traffic response timeout + * @puapsd_mask: uapsd mask + * @puapsd_inactivity_time: uapsd inactivity time + * @puapsd_rx_frame_threshold: uapsd rx frame threshold + * @teardown_notification_ms: tdls teardown notification interval + * @tdls_peer_kickout_threshold: tdls packet threshold for + * peer kickout operation + */ +typedef struct wma_tdls_params { + uint32_t vdev_id; + uint32_t tdls_state; + uint32_t notification_interval_ms; + uint32_t tx_discovery_threshold; + uint32_t tx_teardown_threshold; + int32_t rssi_teardown_threshold; + int32_t rssi_delta; + uint32_t tdls_options; + uint32_t peer_traffic_ind_window; + uint32_t peer_traffic_response_timeout; + uint32_t puapsd_mask; + uint32_t puapsd_inactivity_time; + uint32_t puapsd_rx_frame_threshold; + uint32_t teardown_notification_ms; + uint32_t tdls_peer_kickout_threshold; +} t_wma_tdls_params; + +/** + * struct wma_tdls_peer_event - TDLS peer event + * @vdev_id: vdev id + * @peer_macaddr: peer MAC address + * @peer_status: TDLS peer status + * @peer_reason: TDLS peer reason + */ +typedef struct { + A_UINT32 vdev_id; + wmi_mac_addr peer_macaddr; + A_UINT32 peer_status; + A_UINT32 peer_reason; +} wma_tdls_peer_event; + +#endif /* FEATURE_WLAN_TDLS */ + +/** + * struct wma_dfs_radar_channel_list - dfs radar channel list + * @nchannels: nuber of channels + * @channels: Channel number including bonded channels on which + * radar is present + */ +struct wma_dfs_radar_channel_list { + A_UINT32 nchannels; + uint8_t channels[WMA_DFS_MAX_20M_SUB_CH]; +}; + +/** + * struct wma_dfs_radar_indication - Structure to indicate RADAR + * @vdev_id: vdev id + * @chan_list: Channel list on which RADAR is detected + * @dfs_radar_status: Flag to Indicate RADAR presence on the current channel + * @use_nol: Flag to indicate use NOL + */ +struct wma_dfs_radar_indication { + A_UINT32 vdev_id; + struct wma_dfs_radar_channel_list chan_list; + uint32_t dfs_radar_status; + int use_nol; +}; + +/** + * enum uapsd_ac - U-APSD Access Categories + * @UAPSD_BE: best effort + * @UAPSD_BK: back ground + * @UAPSD_VI: video + * @UAPSD_VO: voice + */ +enum uapsd_ac { + UAPSD_BE, + UAPSD_BK, + UAPSD_VI, + UAPSD_VO +}; + +QDF_STATUS wma_disable_uapsd_per_ac(tp_wma_handle wma_handle, + uint32_t vdev_id, enum uapsd_ac ac); + +/** + * enum uapsd_up - U-APSD User Priorities + * @UAPSD_UP_BE: best effort + * @UAPSD_UP_BK: back ground + * @UAPSD_UP_RESV: reserve + * @UAPSD_UP_EE: Excellent Effort + * @UAPSD_UP_CL: Critical Applications + * @UAPSD_UP_VI: video + * @UAPSD_UP_VO: voice + * @UAPSD_UP_NC: Network Control + */ +enum uapsd_up { + UAPSD_UP_BE, + UAPSD_UP_BK, + UAPSD_UP_RESV, + UAPSD_UP_EE, + UAPSD_UP_CL, + UAPSD_UP_VI, + UAPSD_UP_VO, + UAPSD_UP_NC, + UAPSD_UP_MAX +}; + +/** + * struct wma_unit_test_cmd - unit test command parameters + * @vdev_id: vdev id + * @module_id: module id + * @num_args: number of arguments + * @args: arguments + */ +typedef struct wma_unit_test_cmd { + uint32_t vdev_id; + WLAN_MODULE_ID module_id; + uint32_t num_args; + uint32_t args[WMA_MAX_NUM_ARGS]; +} t_wma_unit_test_cmd; + +/** + * struct wma_roam_invoke_cmd - roam invoke command + * @vdev_id: vdev id + * @bssid: mac address + * @channel: channel + * @frame_len: frame length, includs mac header, fixed params and ies + * @frame_buf: buffer contaning probe response or beacon + */ +struct wma_roam_invoke_cmd { + uint32_t vdev_id; + uint8_t bssid[IEEE80211_ADDR_LEN]; + uint32_t channel; + uint32_t frame_len; + uint8_t *frame_buf; +}; + +/** + * struct wma_process_fw_event_params - fw event parameters + * @wmi_handle: wmi handle + * @evt_buf: event buffer + */ +typedef struct { + void *wmi_handle; + void *evt_buf; +} wma_process_fw_event_params; + +int wma_process_fw_event_handler(void *ctx, void *ev, uint8_t rx_ctx); + +A_UINT32 e_csr_auth_type_to_rsn_authmode(eCsrAuthType authtype, + eCsrEncryptionType encr); +A_UINT32 e_csr_encryption_type_to_rsn_cipherset(eCsrEncryptionType encr); + +/* + * WMA-DFS Hooks + */ +int ol_if_dfs_attach(struct ieee80211com *ic, void *ptr, void *radar_info); +uint64_t ol_if_get_tsf64(struct ieee80211com *ic); +int ol_if_dfs_disable(struct ieee80211com *ic); +struct dfs_ieee80211_channel *ieee80211_find_channel(struct ieee80211com *ic, + int freq, uint32_t flags); +int ol_if_dfs_enable(struct ieee80211com *ic, int *is_fastclk, void *pe); +uint32_t ieee80211_ieee2mhz(uint32_t chan, uint32_t flags); +int ol_if_dfs_get_ext_busy(struct ieee80211com *ic); +int ol_if_dfs_get_mib_cycle_counts_pct(struct ieee80211com *ic, + uint32_t *rxc_pcnt, uint32_t *rxf_pcnt, + uint32_t *txf_pcnt); +uint16_t ol_if_dfs_usenol(struct ieee80211com *ic); +void ieee80211_mark_dfs(struct ieee80211com *ic, + struct dfs_ieee80211_channel *ichan); +int wma_dfs_indicate_radar(struct ieee80211com *ic, + struct dfs_ieee80211_channel *ichan); + +QDF_STATUS wma_trigger_uapsd_params(tp_wma_handle wma_handle, uint32_t vdev_id, + tp_wma_trigger_uapsd_params + trigger_uapsd_params); + +/* added to get average snr for both data and beacon */ +QDF_STATUS wma_send_snr_request(tp_wma_handle wma_handle, void *pGetRssiReq); + + +QDF_STATUS wma_update_vdev_tbl(tp_wma_handle wma_handle, uint8_t vdev_id, + ol_txrx_vdev_handle tx_rx_vdev_handle, + uint8_t *mac, uint32_t vdev_type, bool add_del); + +void wma_send_flush_logs_to_fw(tp_wma_handle wma_handle); +void wma_log_completion_timeout(void *data); + +QDF_STATUS wma_set_rssi_monitoring(tp_wma_handle wma, + struct rssi_monitor_req *req); + +QDF_STATUS wma_send_pdev_set_pcl_cmd(tp_wma_handle wma_handle, + struct wmi_pcl_chan_weights *msg); + +QDF_STATUS wma_send_pdev_set_hw_mode_cmd(tp_wma_handle wma_handle, + struct sir_hw_mode *msg); +QDF_STATUS wma_get_scan_id(uint32_t *scan_id); + +QDF_STATUS wma_send_pdev_set_dual_mac_config(tp_wma_handle wma_handle, + struct sir_dual_mac_config *msg); +QDF_STATUS wma_send_pdev_set_antenna_mode(tp_wma_handle wma_handle, + struct sir_antenna_mode_param *msg); +QDF_STATUS wma_crash_inject(tp_wma_handle wma_handle, uint32_t type, + uint32_t delay_time_ms); + +struct wma_target_req *wma_fill_vdev_req(tp_wma_handle wma, + uint8_t vdev_id, + uint32_t msg_type, uint8_t type, + void *params, uint32_t timeout); +struct wma_target_req *wma_fill_hold_req(tp_wma_handle wma, + uint8_t vdev_id, uint32_t msg_type, + uint8_t type, void *params, + uint32_t timeout); + +QDF_STATUS wma_vdev_start(tp_wma_handle wma, + struct wma_vdev_start_req *req, bool isRestart); + +void wma_remove_vdev_req(tp_wma_handle wma, uint8_t vdev_id, + uint8_t type); + +int wmi_desc_pool_init(tp_wma_handle wma_handle, uint32_t pool_size); +void wmi_desc_pool_deinit(tp_wma_handle wma_handle); +struct wmi_desc_t *wmi_desc_get(tp_wma_handle wma_handle); +void wmi_desc_put(tp_wma_handle wma_handle, struct wmi_desc_t *wmi_desc); +int wma_mgmt_tx_completion_handler(void *handle, uint8_t *cmpl_event_params, + uint32_t len); +int wma_mgmt_tx_bundle_completion_handler(void *handle, + uint8_t *cmpl_event_params, uint32_t len); +void wma_set_dfs_region(tp_wma_handle wma, enum dfs_region dfs_region); +uint32_t wma_get_vht_ch_width(void); +QDF_STATUS +wma_config_debug_module_cmd(wmi_unified_t wmi_handle, A_UINT32 param, + A_UINT32 val, A_UINT32 *module_id_bitmap, + A_UINT32 bitmap_len); +#ifdef FEATURE_LFR_SUBNET_DETECTION +QDF_STATUS wma_set_gateway_params(tp_wma_handle wma, + struct gateway_param_update_req *req); +#else +static inline QDF_STATUS wma_set_gateway_params(tp_wma_handle wma, + struct gateway_param_update_req *req) +{ + return QDF_STATUS_SUCCESS; +} +#endif /* FEATURE_LFR_SUBNET_DETECTION */ + +#if defined(FEATURE_LRO) +QDF_STATUS wma_lro_config_cmd(tp_wma_handle wma_handle, + struct wma_lro_config_cmd_t *wma_lro_cmd); +#else +static inline QDF_STATUS wma_lro_config_cmd(tp_wma_handle wma_handle, + struct wma_lro_config_cmd_t *wma_lro_cmd) +{ + return QDF_STATUS_SUCCESS; +} +#endif +bool wma_is_current_hwmode_dbs(void); +void +wma_indicate_err(enum ol_rx_err_type err_type, + struct ol_error_info *err_info); + +QDF_STATUS wma_ht40_stop_obss_scan(tp_wma_handle wma_handle, + int32_t vdev_id); + +void wma_process_fw_test_cmd(WMA_HANDLE handle, + struct set_fwtest_params *wma_fwtest); + +QDF_STATUS wma_send_ht40_obss_scanind(tp_wma_handle wma, + struct obss_ht40_scanind *req); + +int wma_get_bpf_caps_event_handler(void *handle, + u_int8_t *cmd_param_info, + u_int32_t len); +uint32_t wma_get_num_of_setbits_from_bitmask(uint32_t mask); +QDF_STATUS wma_get_bpf_capabilities(tp_wma_handle wma); +QDF_STATUS wma_set_bpf_instructions(tp_wma_handle wma, + struct sir_bpf_set_offload *bpf_set_offload); +void wma_process_set_pdev_ie_req(tp_wma_handle wma, + struct set_ie_param *ie_params); +void wma_process_set_pdev_ht_ie_req(tp_wma_handle wma, + struct set_ie_param *ie_params); +void wma_process_set_pdev_vht_ie_req(tp_wma_handle wma, + struct set_ie_param *ie_params); +void wma_remove_peer(tp_wma_handle wma, u_int8_t *bssid, + u_int8_t vdev_id, ol_txrx_peer_handle peer, + bool roam_synch_in_progress); + +QDF_STATUS wma_add_wow_wakeup_event(tp_wma_handle wma, + uint32_t vdev_id, + uint32_t *bitmap, + bool enable); +QDF_STATUS wma_create_peer(tp_wma_handle wma, ol_txrx_pdev_handle pdev, + ol_txrx_vdev_handle vdev, u8 peer_addr[6], + u_int32_t peer_type, u_int8_t vdev_id, + bool roam_synch_in_progress); + +/** + * wma_get_cca_stats() - send request to fw to get CCA + * @wmi_hdl: wma handle + * @vdev_id: vdev id + * + * Return: QDF status + */ +QDF_STATUS wma_get_cca_stats(tp_wma_handle wma_handle, + uint8_t vdev_id); + +struct wma_ini_config *wma_get_ini_handle(tp_wma_handle wma_handle); +WLAN_PHY_MODE wma_chan_phy_mode(u8 chan, enum phy_ch_width chan_width, + u8 dot11_mode); + +#ifdef FEATURE_OEM_DATA_SUPPORT +QDF_STATUS wma_start_oem_data_req(tp_wma_handle wma_handle, + struct oem_data_req *oem_req); +#endif + +QDF_STATUS wma_enable_disable_caevent_ind(tp_wma_handle wma_handle, + uint8_t val); +void wma_register_packetdump_callback( + tp_wma_packetdump_cb wma_mgmt_tx_packetdump_cb, + tp_wma_packetdump_cb wma_mgmt_rx_packetdump_cb); +void wma_deregister_packetdump_callback(void); +void wma_update_sta_inactivity_timeout(tp_wma_handle wma, + struct sme_sta_inactivity_timeout *sta_inactivity_timer); + +QDF_STATUS wma_send_udp_resp_offload_cmd(tp_wma_handle wma_handle, + struct udp_resp_offload *udp_response); + +/** + * wma_chip_power_save_failure_detected_handler() - chip pwr save fail detected + * event handler + * @handle: wma handle + * @cmd_param_info: event handler data + * @len: length of @cmd_param_info + * + * Return: QDF_STATUS_SUCCESS on success; error code otherwise + */ +int wma_chip_power_save_failure_detected_handler(void *handle, + uint8_t *cmd_param_info, + uint32_t len); + +/** + * wma_set_event_wow_bitmap() - set wow bitmask given WOW event + * @event: wow event + * @wow_bitmap_size: WOW bitmap size + * @bitmask: pointer to actual bitmask + * + * Return: none + */ +void wma_set_wow_event_bitmap(WOW_WAKE_EVENT_TYPE event, + uint32_t wow_bitmap_size, + uint32_t *bitmask); + +/** + * wma_set_sta_wow_bitmask() - set predefined bitmask for STA WOW events + * @bitmask: pointer to actual bitmask + * @wow_bitmap_size: WOW bitmap size + * + * Return: none + */ +void wma_set_sta_wow_bitmask(uint32_t *bitmask, uint32_t wow_bitmask_size); + +/** + * wma_set_sap_wow_bitmask() - set predefined bitmask for SAP WOW events + * @bitmask: pointer to actual bitmask + * @wow_bitmap_size: WOW bitmap size + * + * Return: none + */ +void wma_set_sap_wow_bitmask(uint32_t *bitmask, uint32_t wow_bitmask_size); + +/** + * wma_is_wow_bitmask_zero() - check if given wow bitmask is zero + * @bitmask: pointer to actual bitmask + * @wow_bitmap_size: WOW bitmap size + * + * Return: true if zero, false otherwise + */ +bool wma_is_wow_bitmask_zero(uint32_t *bitmask, + uint32_t wow_bitmask_size); +/** + * wma_process_roaming_config() - process roam request + * @wma_handle: wma handle + * @roam_req: roam request parameters + * + * Main routine to handle ROAM commands coming from CSR module. + * + * Return: QDF status + */ +QDF_STATUS wma_process_roaming_config(tp_wma_handle wma_handle, + tSirRoamOffloadScanReq *roam_req); + +/** + * wma_ipa_uc_stat_request() - set ipa config parameters + * @privcmd: private command + * + * Return: None + */ +void wma_ipa_uc_stat_request(wma_cli_set_cmd_t *privcmd); + +#endif diff --git a/drivers/staging/qcacld-3.0/core/wma/inc/wma_api.h b/drivers/staging/qcacld-3.0/core/wma/inc/wma_api.h new file mode 100644 index 0000000000000000000000000000000000000000..4eee2bd4d28a8e78b8f11bc63d642a8f1d094fcf --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/wma/inc/wma_api.h @@ -0,0 +1,402 @@ +/* + * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef WMA_API_H +#define WMA_API_H + +#include "osdep.h" +#include "cds_mq.h" +#include "ani_global.h" +#include "a_types.h" +#include "osapi_linux.h" +#include "wmi_unified.h" +#ifdef NOT_YET +#include "htc_api.h" +#endif +#include "lim_global.h" +#include "cds_concurrency.h" +#include "cds_utils.h" + +typedef void *WMA_HANDLE; + +/** + * enum GEN_PARAM - general parameters + * @GEN_VDEV_PARAM_AMPDU: Set ampdu size + * @GEN_VDEV_PARAM_AMSDU: Set amsdu size + * @GEN_PARAM_CRASH_INJECT: inject crash + * @GEN_PARAM_MODULATED_DTIM: moduled dtim + * @GEN_PARAM_CAPTURE_TSF: read tsf + * @GEN_PARAM_RESET_TSF_GPIO: reset tsf gpio + * @GEN_VDEV_ROAM_SYNCH_DELAY: roam sync delay + */ +typedef enum { + GEN_VDEV_PARAM_AMPDU = 0x1, + GEN_VDEV_PARAM_AMSDU, + GEN_PARAM_CRASH_INJECT, + GEN_PARAM_MODULATED_DTIM, + GEN_PARAM_CAPTURE_TSF, + GEN_PARAM_RESET_TSF_GPIO, + GEN_VDEV_ROAM_SYNCH_DELAY, +} GEN_PARAM; + +/** + * struct wma_caps_per_phy - various caps per phy + * @ht_2g: entire HT cap for 2G band in terms of 32 bit flag + * @ht_5g: entire HT cap for 5G band in terms of 32 bit flag + * @vht_2g: entire VHT cap for 2G band in terms of 32 bit flag + * @vht_5g: entire VHT cap for 5G band in terms of 32 bit flag + * @he_2g: entire HE cap for 2G band in terms of 32 bit flag + * @he_5g: entire HE cap for 5G band in terms of 32 bit flag + */ +struct wma_caps_per_phy { + uint32_t ht_2g; + uint32_t ht_5g; + uint32_t vht_2g; + uint32_t vht_5g; + uint32_t he_2g; + uint32_t he_5g; +}; + + +#define VDEV_CMD 1 +#define PDEV_CMD 2 +#define GEN_CMD 3 +#define DBG_CMD 4 +#define PPS_CMD 5 +#define QPOWER_CMD 6 +#define GTX_CMD 7 + +/** + * @DEBUG_PEER_CREATE_SEND: sent peer_create command to firmware + * @DEBUG_PEER_CREATE_RESP: received peer create response + * @DEBUG_PEER_DELETE_SEND: sent peer delete command to firmware + * @DEBUG_PEER_DELETE_RESP: received peer delete response + * @DEBUG_PEER_MAP_EVENT: received peer map event + * @DEBUG_PEER_UNMAP_EVENT: received peer unmap event + * @DEBUG_PEER_UNREF_DELETE: peer reference is decremented + * @DEBUG_DELETING_PEER_OBJ: peer object is deleted + * @DEBUG_ROAM_SYNCH_IND: received roam offload sync indication + * @DEBUG_ROAM_SYNCH_CNF: sent roam offload sync confirmation + * @DEBUG_ROAM_SYNCH_FAIL: received roam sync failure indication + * @DEBUG_ROAM_EVENT: received roam event + * @DEBUG_BUS_SUSPEND: host going into suspend mode + * @DEBUG_BUS_RESUME: host operation resumed + */ + +enum peer_debug_op { + DEBUG_PEER_CREATE_SEND = 0, + DEBUG_PEER_CREATE_RESP, + DEBUG_PEER_DELETE_SEND, + DEBUG_PEER_DELETE_RESP, + DEBUG_PEER_MAP_EVENT, + DEBUG_PEER_UNMAP_EVENT, + DEBUG_PEER_UNREF_DELETE, + DEBUG_DELETING_PEER_OBJ, + DEBUG_ROAM_SYNCH_IND, + DEBUG_ROAM_SYNCH_CNF, + DEBUG_ROAM_SYNCH_FAIL, + DEBUG_ROAM_EVENT, + DEBUG_WOW_ROAM_EVENT, + DEBUG_BUS_SUSPEND, + DEBUG_BUS_RESUME, + DEBUG_WOW_REASON, +}; + +#define DEBUG_INVALID_PEER_ID 0xffff +#define DEBUG_INVALID_VDEV_ID 0xff + +typedef void (*wma_peer_authorized_fp) (uint32_t vdev_id); + + +QDF_STATUS wma_pre_start(void *cds_context); + +void wma_mc_discard_msg(cds_msg_t *msg); + +QDF_STATUS wma_mc_process_msg(void *cds_context, cds_msg_t *msg); + +QDF_STATUS wma_start(void *cds_context); + +QDF_STATUS wma_stop(void *cds_context, uint8_t reason); + +QDF_STATUS wma_close(void *cds_context); + +QDF_STATUS wma_wmi_service_close(void *cds_context); + +QDF_STATUS wma_wmi_work_close(void *cds_context); + +int wma_rx_ready_event(void *handle, uint8_t *ev, uint32_t len); + +int wma_rx_service_ready_event(void *handle, uint8_t *ev, uint32_t len); + +int wma_rx_service_ready_ext_event(void *handle, uint8_t *ev, uint32_t len); + +void wma_setneedshutdown(void *cds_context); + +bool wma_needshutdown(void *cds_context); + +QDF_STATUS wma_wait_for_ready_event(WMA_HANDLE handle); + +uint8_t wma_map_channel(uint8_t mapChannel); + +int wma_cli_get_command(int vdev_id, int param_id, int vpdev); +int wma_cli_set_command(int vdev_id, int param_id, int sval, int vpdev); +int wma_cli_set2_command(int vdev_id, int param_id, int sval1, + int sval2, int vpdev); + +QDF_STATUS wma_set_htconfig(uint8_t vdev_id, uint16_t ht_capab, int value); +QDF_STATUS wma_set_reg_domain(void *clientCtxt, v_REGDOMAIN_t regId); + +QDF_STATUS wma_get_wcnss_software_version(void *p_cds_gctx, + uint8_t *pVersion, + uint32_t versionBufferSize); +int wma_runtime_suspend(uint32_t wow_flags); +int wma_runtime_resume(void); +int wma_bus_suspend(uint32_t wow_flags); +int wma_is_target_wake_up_received(void); +int wma_clear_target_wake_up(void); +QDF_STATUS wma_suspend_target(WMA_HANDLE handle, int disable_target_intr); +void wma_target_suspend_acknowledge(void *context, bool wow_nack); +void wma_handle_initial_wake_up(void); +int wma_bus_resume(void); +QDF_STATUS wma_resume_target(WMA_HANDLE handle); +QDF_STATUS wma_disable_wow_in_fw(WMA_HANDLE handle); +QDF_STATUS wma_disable_d0wow_in_fw(WMA_HANDLE handle); +bool wma_is_wow_mode_selected(WMA_HANDLE handle); +QDF_STATUS wma_enable_wow_in_fw(WMA_HANDLE handle, uint32_t wow_flags); +QDF_STATUS wma_enable_d0wow_in_fw(WMA_HANDLE handle, uint32_t wow_flags); +void wma_set_peer_authorized_cb(void *wma_ctx, wma_peer_authorized_fp auth_cb); +QDF_STATUS wma_set_peer_param(void *wma_ctx, uint8_t *peer_addr, + uint32_t param_id, + uint32_t param_value, uint32_t vdev_id); +QDF_STATUS wma_get_link_speed(WMA_HANDLE handle, tSirLinkSpeedInfo *pLinkSpeed); +#ifdef NOT_YET +QDF_STATUS wma_update_channel_list(WMA_HANDLE handle, void *scan_chan_info); +#endif + +uint8_t *wma_get_vdev_address_by_vdev_id(uint8_t vdev_id); +struct wma_txrx_node *wma_get_interface_by_vdev_id(uint8_t vdev_id); +bool wma_is_vdev_up(uint8_t vdev_id); + +void *wma_get_beacon_buffer_by_vdev_id(uint8_t vdev_id, uint32_t *buffer_size); + +uint8_t wma_get_fw_wlan_feat_caps(uint8_t featEnumValue); +tSirRetStatus wma_post_ctrl_msg(tpAniSirGlobal pMac, tSirMsgQ *pMsg); + +void wma_enable_disable_wakeup_event(WMA_HANDLE handle, + uint32_t vdev_id, + uint32_t *bitmap, + bool enable); +void wma_register_wow_wakeup_events(WMA_HANDLE handle, uint8_t vdev_id, + uint8_t vdev_type, uint8_t sub_type); +void wma_register_wow_default_patterns(WMA_HANDLE handle, uint8_t vdev_id); +QDF_STATUS wma_register_action_frame_patterns(WMA_HANDLE handle, + uint8_t vdev_id); + +int8_t wma_get_hw_mode_idx_from_dbs_hw_list(enum hw_mode_ss_config mac0_ss, + enum hw_mode_bandwidth mac0_bw, + enum hw_mode_ss_config mac1_ss, + enum hw_mode_bandwidth mac1_bw, + enum hw_mode_dbs_capab dbs, + enum hw_mode_agile_dfs_capab dfs, + enum hw_mode_sbs_capab sbs); +QDF_STATUS wma_get_hw_mode_from_idx(uint32_t idx, + struct sir_hw_mode_params *hw_mode); +int8_t wma_get_num_dbs_hw_modes(void); +bool wma_is_hw_dbs_capable(void); +int8_t wma_get_mac_id_of_vdev(uint32_t vdev_id); +void wma_update_intf_hw_mode_params(uint32_t vdev_id, uint32_t mac_id, + uint32_t cfgd_hw_mode_index); +QDF_STATUS wma_get_old_and_new_hw_index(uint32_t *old_hw_mode_index, + uint32_t *new_hw_mode_index); +void wma_set_dbs_capability_ut(uint32_t dbs); +QDF_STATUS wma_get_dbs_hw_modes(bool *one_by_one_dbs, bool *two_by_two_dbs); +QDF_STATUS wma_get_current_hw_mode(struct sir_hw_mode_params *hw_mode); +bool wma_is_dbs_enable(void); +enum cds_hw_mode_change +wma_get_cds_hw_mode_change_from_hw_mode_index(uint32_t hw_mode_index); + +QDF_STATUS wma_get_updated_scan_config(uint32_t *scan_config, + bool dbs_scan, + bool dbs_plus_agile_scan, + bool single_mac_scan_with_dfs); +QDF_STATUS wma_get_updated_fw_mode_config(uint32_t *fw_mode_config, + bool dbs, + bool agile_dfs); +bool wma_get_dbs_scan_config(void); +bool wma_get_dbs_plus_agile_scan_config(void); +bool wma_get_single_mac_scan_with_dfs_config(void); +bool wma_get_dbs_config(void); +bool wma_get_agile_dfs_config(void); +bool wma_is_dual_mac_disabled_in_ini(void); +bool wma_get_prev_dbs_config(void); +bool wma_get_prev_agile_dfs_config(void); +bool wma_get_prev_dbs_scan_config(void); +bool wma_get_prev_dbs_plus_agile_scan_config(void); +bool wma_get_prev_single_mac_scan_with_dfs_config(void); +QDF_STATUS wma_get_caps_for_phyidx_hwmode(struct wma_caps_per_phy *caps_per_phy, + enum hw_mode_dbs_capab hw_mode, enum cds_band_type band); +bool wma_is_rx_ldpc_supported_for_channel(uint32_t channel); + +#define LRO_IPV4_SEED_ARR_SZ 5 +#define LRO_IPV6_SEED_ARR_SZ 11 + +/** + * struct wma_lro_init_cmd_t - set LRO init parameters + * @lro_enable: indicates whether lro is enabled + * @tcp_flag: If the TCP flags from the packet do not match + * the values in this field after masking with TCP flags mask + * below, packet is not LRO eligible + * @tcp_flag_mask: field for comparing the TCP values provided + * above with the TCP flags field in the received packet + * @toeplitz_hash_ipv4: contains seed needed to compute the flow id + * 5-tuple toeplitz hash for ipv4 packets + * @toeplitz_hash_ipv6: contains seed needed to compute the flow id + * 5-tuple toeplitz hash for ipv6 packets + */ +struct wma_lro_config_cmd_t { + uint32_t lro_enable; + uint32_t tcp_flag:9, + tcp_flag_mask:9; + uint32_t toeplitz_hash_ipv4[LRO_IPV4_SEED_ARR_SZ]; + uint32_t toeplitz_hash_ipv6[LRO_IPV6_SEED_ARR_SZ]; +}; + +#if defined(FEATURE_LRO) +int wma_lro_init(struct wma_lro_config_cmd_t *lro_config); +#endif +bool wma_is_scan_simultaneous_capable(void); + +QDF_STATUS wma_remove_beacon_filter(WMA_HANDLE wma, + struct beacon_filter_param *filter_params); + +QDF_STATUS wma_add_beacon_filter(WMA_HANDLE wma, + struct beacon_filter_param *filter_params); +QDF_STATUS wma_send_adapt_dwelltime_params(WMA_HANDLE handle, + struct adaptive_dwelltime_params *dwelltime_params); +#ifdef FEATURE_GREEN_AP +void wma_setup_egap_support(struct wma_tgt_cfg *tgt_cfg, WMA_HANDLE handle); +void wma_register_egap_event_handle(WMA_HANDLE handle); +QDF_STATUS wma_send_egap_conf_params(WMA_HANDLE handle, + struct egap_conf_params *egap_params); +#else +static inline void wma_setup_egap_support(struct wma_tgt_cfg *tgt_cfg, + WMA_HANDLE handle) {} +static inline void wma_register_egap_event_handle(WMA_HANDLE handle) {} +static inline QDF_STATUS wma_send_egap_conf_params(WMA_HANDLE handle, + struct egap_conf_params *egap_params) +{ + return QDF_STATUS_E_NOSUPPORT; +} +#endif +QDF_STATUS wma_set_tx_power_scale(uint8_t vdev_id, int value); +QDF_STATUS wma_set_tx_power_scale_decr_db(uint8_t vdev_id, int value); + +#ifdef WLAN_FEATURE_NAN_DATAPATH +QDF_STATUS wma_register_ndp_cb(QDF_STATUS (*pe_ndp_event_handler) + (tpAniSirGlobal mac_ctx, + cds_msg_t *msg)); +#else +static inline QDF_STATUS wma_register_ndp_cb(QDF_STATUS (*pe_ndp_event_handler) + (tpAniSirGlobal mac_ctx, + cds_msg_t *msg)) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +bool wma_is_p2p_lo_capable(void); +QDF_STATUS wma_p2p_lo_start(struct sir_p2p_lo_start *params); +QDF_STATUS wma_p2p_lo_stop(u_int32_t vdev_id); +QDF_STATUS wma_get_wakelock_stats(struct sir_wake_lock_stats *wake_lock_stats); +void wma_process_pdev_hw_mode_trans_ind(void *wma, + wmi_pdev_hw_mode_transition_event_fixed_param *fixed_param, + wmi_pdev_set_hw_mode_response_vdev_mac_entry *vdev_mac_entry, + struct sir_hw_mode_trans_ind *hw_mode_trans_ind); + +#ifdef WLAN_FEATURE_DISA +QDF_STATUS wma_encrypt_decrypt_msg(WMA_HANDLE wma, + struct encrypt_decrypt_req_params *encrypt_decrypt_params); +#else +static inline QDF_STATUS wma_encrypt_decrypt_msg(WMA_HANDLE wma, + struct encrypt_decrypt_req_params *encrypt_decrypt_params) +{ + return 0; +} +#endif + +/** + * wma_set_cts2self_for_p2p_go() - set CTS2SELF command for P2P GO. + * @wma_handle: pointer to wma handle. + * @cts2self_for_p2p_go: value needs to set to firmware. + * + * At the time of driver startup, inform about ini parma to FW that + * if legacy client connects to P2P GO, stop using NOA for P2P GO. + * + * Return: QDF_STATUS. + */ +QDF_STATUS wma_set_cts2self_for_p2p_go(void *wma_handle, + uint32_t cts2self_for_p2p_go); +QDF_STATUS wma_set_tx_rx_aggregation_size + (struct sir_set_tx_rx_aggregation_size *tx_rx_aggregation_size); +/** + * wma_set_sar_limit() - set sar limits in the target + * @handle: wma handle + * @sar_limit_cmd_params: sar limit cmd params + * + * This function sends WMI command to set SAR limits. + * + * Return: QDF_STATUS enumeration + */ +QDF_STATUS wma_set_sar_limit(WMA_HANDLE handle, + struct sar_limit_cmd_params *sar_limit_params); +/** + * wma_set_qpower_config() - update qpower config in wma + * @vdev_id: the Id of the vdev to configure + * @qpower: new qpower value + * + * Return: QDF_STATUS_SUCCESS on success, error number otherwise + */ +QDF_STATUS wma_set_qpower_config(uint8_t vdev_id, uint8_t qpower); + +/** + * wma_peer_debug_log() - Add a debug log entry into peer debug records + * @vdev_id: vdev identifier + * @op: operation identifier + * @peer_id: peer id + * @mac_addr: mac address of peer, can be NULL + * @peer_obj: peer object address, can be NULL + * @arg1: extra argument #1 + * @arg2: extra argument #2 + * + * Return: none + */ +void wma_peer_debug_log(uint8_t vdev_id, uint8_t op, + uint16_t peer_id, void *mac_addr, + void *peer_obj, uint32_t val1, uint32_t val2); +void wma_peer_debug_dump(void); + +#endif diff --git a/drivers/staging/qcacld-3.0/core/wma/inc/wma_dfs_interface.h b/drivers/staging/qcacld-3.0/core/wma/inc/wma_dfs_interface.h new file mode 100644 index 0000000000000000000000000000000000000000..f30f7b3a291fbe66c0cb52c14acb64a06001f328 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/wma/inc/wma_dfs_interface.h @@ -0,0 +1,288 @@ +/* + * Copyright (c) 2014-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#include "ath_dfs_structs.h" +#include +#include "cds_reg_service.h" +#include "cds_regdomain.h" +#include "cds_ieee80211_common.h" + +#define IEEE80211_CHAN_MAX 255 + +/* channel attributes */ + +/* Turbo channel */ +#define IEEE80211_CHAN_TURBO 0x00000010 +/* CCK channel */ +#define IEEE80211_CHAN_CCK 0x00000020 +/* OFDM channel */ +#define IEEE80211_CHAN_OFDM 0x00000040 +/* 2 GHz spectrum channel. */ +#define IEEE80211_CHAN_2GHZ 0x00000080 +/* 5 GHz spectrum channel */ +#define IEEE80211_CHAN_5GHZ 0x00000100 +/* Only passive scan allowed */ +#define IEEE80211_CHAN_PASSIVE 0x00000200 +/* Dynamic CCK-OFDM channel */ +#define IEEE80211_CHAN_DYN 0x00000400 +/* GFSK channel (FHSS PHY) */ +#define IEEE80211_CHAN_GFSK 0x00000800 +/* 11a static turbo channel only */ +#define IEEE80211_CHAN_STURBO 0x00002000 +/* Half rate channel */ +#define IEEE80211_CHAN_HALF 0x00004000 +/* Quarter rate channel */ +#define IEEE80211_CHAN_QUARTER 0x00008000 +/* HT 20 channel */ +#define IEEE80211_CHAN_HT20 0x00010000 +/* HT 40 with extension channel above */ +#define IEEE80211_CHAN_HT40PLUS 0x00020000 +/* HT 40 with extension channel below */ +#define IEEE80211_CHAN_HT40MINUS 0x00040000 +/* HT 40 Intolerant */ +#define IEEE80211_CHAN_HT40INTOL 0x00080000 +/* VHT 20 channel */ +#define IEEE80211_CHAN_VHT20 0x00100000 +/* VHT 40 with extension channel above */ +#define IEEE80211_CHAN_VHT40PLUS 0x00200000 +/* VHT 40 with extension channel below */ +#define IEEE80211_CHAN_VHT40MINUS 0x00400000 +/* VHT 80 channel */ +#define IEEE80211_CHAN_VHT80 0x00800000 +/* VHT 80+80 Channel */ +#define IEEE80211_CHAN_VHT80P80 0x01000000 +/* VHT 160 Channel */ +#define IEEE80211_CHAN_VHT160 0x02000000 + +/* token for ``any channel'' */ +#define DFS_IEEE80211_CHAN_ANY (-1) +#define DFS_IEEE80211_CHAN_ANYC \ + ((struct dfs_ieee80211_channel *) DFS_IEEE80211_CHAN_ANY) + +#define IEEE80211_IS_CHAN_11N_HT40MINUS(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_HT40MINUS) != 0) +#define IEEE80211_IS_CHAN_11N_HT40PLUS(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_HT40PLUS) != 0) +#define IEEE80211_CHAN_11AC_VHT80 \ + (IEEE80211_CHAN_5GHZ | IEEE80211_CHAN_VHT80) + +#define IEEE80211_IS_CHAN_11AC_VHT80(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_11AC_VHT80) == \ + IEEE80211_CHAN_11AC_VHT80) +#define IEEE80211_IS_CHAN_11AC_VHT80P80(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_VHT80P80) == \ + IEEE80211_CHAN_VHT80P80) +#define IEEE80211_IS_CHAN_11AC_VHT160(_c) \ + (((_c)->ic_flags & IEEE80211_CHAN_VHT160) == \ + IEEE80211_CHAN_VHT160) +#define CHANNEL_108G \ + (IEEE80211_CHAN_2GHZ|IEEE80211_CHAN_OFDM|IEEE80211_CHAN_TURBO) + +/* + * Software use: channel interference + * used for as AR as well as RADAR + * interference detection + */ +#define CHANNEL_INTERFERENCE 0x01 +/* In case of VHT160, we can have 8 20Mhz channels */ +#define IEE80211_MAX_20M_SUB_CH 8 + +#define WMA_DFS2_PHYERROR_CODE 0x5 +#define WMA_DFS2_FALSE_RADAR_EXT 0x24 + +/** + * struct dfs_ieee80211_channel - channel info + * @ic_freq: frequency in MHz + * @ic_flags: channel flags + * @ic_flagext: flags extension + * @ic_ieee: IEEE channel number + * @ic_maxregpower: max regulatory power in dbm + * @ic_maxpower: max tx power in dbm + * @ic_minpower: min tx power in dbm + * @ic_regClassId: reg class id of this channel + * @ic_antennamax: max antenna gain from regulatory + * @ic_vhtop_ch_freq_seg1: channel center frequency + * @ic_vhtop_ch_freq_seg2: Channel Center frequency applicable + * @ic_pri_freq_center_freq_mhz_separation: separation b/w pri and center freq + * @ic_80p80_both_dfs: Flag indicating if both 80p80 segments are dfs + * @ic_radar_found_segid: Indicates seg ID on which radar is found in 80p80 mode + */ +struct dfs_ieee80211_channel { + uint32_t ic_freq; + uint32_t ic_freq_ext; + uint32_t ic_flags; + uint8_t ic_flagext; + uint8_t ic_ieee; + uint8_t ic_ieee_ext; + int8_t ic_maxregpower; + int8_t ic_maxpower; + int8_t ic_minpower; + uint8_t ic_regClassId; + uint8_t ic_antennamax; + uint32_t ic_vhtop_ch_freq_seg1; + uint32_t ic_vhtop_ch_freq_seg2; + int ic_pri_freq_center_freq_mhz_separation; + bool ic_80p80_both_dfs; + int ic_radar_found_segid; +}; + +/** + * struct ieee80211_channel_list - channel list + * @cl_nchans: number of channels + * @cl_channels: channel info + */ +struct ieee80211_channel_list { + int cl_nchans; + struct dfs_ieee80211_channel *cl_channels[IEE80211_MAX_20M_SUB_CH]; +}; + +/** + * struct ieee80211_dfs_state - dfs state + * @nol_event: nol event list + * @nol_timer: nol list processing + * @cac_timer: cac timer + * @cureps: current events/second + * @lastchan: chan w/ last radar event + * @newchan: chan selected next + * @cac_timeout_override: overridden cac timeout + * @flags: dfs flags + */ +struct ieee80211_dfs_state { + int nol_event[IEEE80211_CHAN_MAX]; + os_timer_t nol_timer; + os_timer_t cac_timer; + int cureps; + const struct dfs_ieee80211_channel *lastchan; + struct dfs_ieee80211_channel *newchan; + int cac_timeout_override; + uint8_t enable:1, cac_timer_running:1, ignore_dfs:1, ignore_cac:1; +}; + +/** + * enum DFS_HWBD_ID - Board ID to differentiate between DFS-2 and DFS-3 + * @DFS_HWBD_NONE: No hw board information/currently used for adreastea FPGA + * @DFS_HWBD_QCA6174: Rome(AR6320) + * @DFS_HWBD_QCA2582: Killer 1525 + */ +typedef enum { + DFS_HWBD_NONE = 0, + DFS_HWBD_QCA6174 = 1, + DFS_HWBD_QCA2582 = 2, +} DFS_HWBD_ID; + + +/** + * struct ieee80211com - per device structure + * @ic_opmode: operation mode + * @ic_channels: ieee80211 channel list + * @ic_nchans: number of channels + * @ic_curchan: current channel + * @ic_isdfsregdomain: is opearting in dfs region + * @current_dfs_regdomain: current dfs regulatory domain + * @vdev_id: vdev id + * @last_radar_found_chan: last radar found channel + * @dfs_pri_multiplier: dfs multiplier + */ +typedef struct ieee80211com { + void (*ic_start_csa)(struct ieee80211com *ic, uint8_t ieeeChan); + void (*ic_get_ext_chan_info)(struct ieee80211com *ic, + struct ieee80211_channel_list *chan); + enum ieee80211_opmode ic_opmode; + struct dfs_ieee80211_channel *(*ic_find_channel) + (struct ieee80211com *ic, int freq, uint32_t flags); + uint64_t (*ic_get_TSF64)(struct ieee80211com *ic); + unsigned int (*ic_ieee2mhz)(u_int chan, u_int flags); + struct dfs_ieee80211_channel ic_channels[IEEE80211_CHAN_MAX + 1]; + int ic_nchans; + struct dfs_ieee80211_channel *ic_curchan; + uint8_t ic_isdfsregdomain; + int (*ic_get_dfsdomain)(struct ieee80211com *); + uint16_t (*ic_dfs_usenol)(struct ieee80211com *ic); + uint16_t (*ic_dfs_isdfsregdomain)(struct ieee80211com *ic); + int (*ic_dfs_attached)(struct ieee80211com *ic); + void *ic_dfs; + struct ieee80211_dfs_state ic_dfs_state; + int (*ic_dfs_attach)(struct ieee80211com *ic, + void *pCap, void *radar_info); + int (*ic_dfs_detach)(struct ieee80211com *ic); + int (*ic_dfs_enable)(struct ieee80211com *ic, int *is_fastclk, + void *); + int (*ic_dfs_disable)(struct ieee80211com *ic); + int (*ic_get_ext_busy)(struct ieee80211com *ic); + int (*ic_get_mib_cycle_counts_pct)(struct ieee80211com *ic, + uint32_t *rxc_pcnt, + uint32_t *rxf_pcnt, + uint32_t *txf_pcnt); + int (*ic_dfs_get_thresholds)(struct ieee80211com *ic, void *pe); + + int (*ic_dfs_debug)(struct ieee80211com *ic, int type, void *data); + /* + * Update the channel list with the current set of DFS + * NOL entries. + * + * + 'cmd' indicates what to do; for now it should just + * be DFS_NOL_CLIST_CMD_UPDATE which will update all + * channels, given the _entire_ NOL. (Rather than + * the earlier behaviour with clist_update, which + * was to either add or remove a set of channel + * entries.) + */ + void (*ic_dfs_clist_update)(struct ieee80211com *ic, int cmd, + struct dfs_nol_chan_entry *, int nentries); + void (*ic_dfs_notify_radar)(struct ieee80211com *ic, + struct dfs_ieee80211_channel *chan); + void (*ic_dfs_unmark_radar)(struct ieee80211com *ic, + struct dfs_ieee80211_channel *chan); + int (*ic_dfs_control)(struct ieee80211com *ic, + u_int id, void *indata, uint32_t insize, + void *outdata, uint32_t *outsize); + enum dfs_region current_dfs_regdomain; + uint8_t vdev_id; + uint8_t last_radar_found_chan; + int32_t dfs_pri_multiplier; + qdf_spinlock_t chan_lock; + bool disable_phy_err_processing; + DFS_HWBD_ID dfs_hw_bd_id; +} IEEE80211COM, *PIEEE80211COM; + +/** + * ieee80211_chan2freq() - Convert channel to frequency value. + * @ic: ieee80211com ptr + * @c: ieee80211 channel + * + * Return: freqency in MHz + */ +static inline u_int +ieee80211_chan2freq(struct ieee80211com *ic, + const struct dfs_ieee80211_channel *c) +{ + if (c == NULL) { + return 0; + } + return (c == DFS_IEEE80211_CHAN_ANYC) ? + DFS_IEEE80211_CHAN_ANY : c->ic_freq; +} diff --git a/drivers/staging/qcacld-3.0/core/wma/inc/wma_if.h b/drivers/staging/qcacld-3.0/core/wma/inc/wma_if.h new file mode 100644 index 0000000000000000000000000000000000000000..6052cecc5a06e219afce3c791df83cf932be46e7 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/wma/inc/wma_if.h @@ -0,0 +1,1455 @@ +/* + * Copyright (c) 2011-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef _HALMSGAPI_H_ +#define _HALMSGAPI_H_ + +#include "qdf_types.h" +#include "sir_api.h" +#include "sir_params.h" + + +/* + * Validate the OS Type being built + */ + +#if defined(ANI_OS_TYPE_ANDROID) /* ANDROID */ + +#if defined(ANI_OS_TYPE_QNX) +#error "more than one ANI_OS_TYPE_xxx is defined for this build" +#endif + +#elif defined (ANI_OS_TYPE_QNX) /* QNX */ + +#if defined(ANI_OS_TYPE_ANDROID) +#error "more than one ANI_OS_TYPE_xxx is defined for this build" +#endif + +#elif !defined(ANI_OS_TYPE_ANDROID) && !defined(ANI_OS_TYPE_QNX) /* NONE */ +#error "NONE of the ANI_OS_TYPE_xxx are defined for this build" +#endif + +/* + * Validate the compiler + */ +#if (defined (ANI_COMPILER_TYPE_MSVC) && defined (ANI_COMPILER_TYPE_GCC) && defined (ANI_COMPILER_TYPE_RVCT)) +#error "more than one ANI_COMPILER_TYPE_xxx is defined for this build" + +#elif !(defined (ANI_COMPILER_TYPE_MSVC) || defined (ANI_COMPILER_TYPE_GCC) || defined (ANI_COMPILER_TYPE_RVCT)) +#error "NONE of the ANI_COMPILER_TYPE_xxx are defined for this build" + +#endif + + +#define WMA_CONFIG_PARAM_UPDATE_REQ SIR_CFG_PARAM_UPDATE_IND + +#define HAL_NUM_BSSID 2 +/* operMode in ADD BSS message */ +#define BSS_OPERATIONAL_MODE_AP 0 +#define BSS_OPERATIONAL_MODE_STA 1 +#define BSS_OPERATIONAL_MODE_IBSS 2 +#define BSS_OPERATIONAL_MODE_NDI 3 + +/* STA entry type in add sta message */ +#define STA_ENTRY_SELF 0 +#define STA_ENTRY_OTHER 1 +#define STA_ENTRY_BSSID 2 +/* Special station id for transmitting broadcast frames. */ +#define STA_ENTRY_BCAST 3 +#define STA_ENTRY_PEER STA_ENTRY_OTHER +#ifdef FEATURE_WLAN_TDLS +#define STA_ENTRY_TDLS_PEER 4 +#endif /* FEATURE_WLAN_TDLS */ +#define STA_ENTRY_NDI_PEER 5 + +#define STA_INVALID_IDX 0xFF + +/* invalid channel id. */ +#define INVALID_CHANNEL_ID 0 + +/* + * From NOVA Mac Arch document + * Encryp. mode The encryption mode + * 000: Encryption functionality is not enabled + * 001: Encryption is set to WEP + * 010: Encryption is set to WEP 104 + * 011: Encryption is set to TKIP + * 100: Encryption is set to AES + * 101 - 111: Reserved for future + */ +#define ENC_POLICY_NULL 0 +#define ENC_POLICY_WEP40 1 +#define ENC_POLICY_WEP104 2 +#define ENC_POLICY_TKIP 3 +#define ENC_POLICY_AES_CCM 4 + +/* Max number of bytes required for stations bitmap aligned at 4 bytes boundary + */ +#define HALMSG_NUMBYTES_STATION_BITMAP(x) (((x / 32) + ((x % 32) ? 1 : 0)) * 4) + + +#define HAL_MAX_SUPP_CHANNELS 128 +#define HAL_MAX_SUPP_OPER_CLASSES 32 + +/** + * enum eFrameType - frame types + * @TXRX_FRM_RAW: raw frame + * @TXRX_FRM_ETH2: ethernet frame + * @TXRX_FRM_802_3: 802.3 frame + * @TXRX_FRM_802_11_MGMT: 802.11 mgmt frame + * @TXRX_FRM_802_11_CTRL: 802.11 control frame + * @TXRX_FRM_802_11_DATA: 802.11 data frame + */ +typedef enum { + TXRX_FRM_RAW, + TXRX_FRM_ETH2, + TXRX_FRM_802_3, + TXRX_FRM_802_11_MGMT, + TXRX_FRM_802_11_CTRL, + TXRX_FRM_802_11_DATA, + TXRX_FRM_IGNORED, /* This frame will be dropped */ + TXRX_FRM_MAX +} eFrameType; + +/** + * enum eFrameTxDir - frame tx direction + * @ANI_TXDIR_IBSS: IBSS frame + * @ANI_TXDIR_TODS: frame to DS + * @ANI_TXDIR_FROMDS: Frame from DS + * @ANI_TXDIR_WDS: WDS frame + */ +typedef enum { + ANI_TXDIR_IBSS = 0, + ANI_TXDIR_TODS, + ANI_TXDIR_FROMDS, + ANI_TXDIR_WDS +} eFrameTxDir; + +/** + *struct sAniBeaconStruct - Beacon structure + * @beaconLength: beacon length + * @macHdr: mac header for beacon + */ +typedef struct sAniBeaconStruct { + uint32_t beaconLength; + tSirMacMgmtHdr macHdr; +} qdf_packed tAniBeaconStruct, *tpAniBeaconStruct; + +/** + * struct sAniProbeRspStruct - probeRsp template structure + * @macHdr: mac header for probe response + */ +typedef struct sAniProbeRspStruct { + tSirMacMgmtHdr macHdr; + /* probeRsp body follows here */ +} qdf_packed tAniProbeRspStruct, *tpAniProbeRspStruct; + +/** + * struct tAddStaParams - add sta related parameters + * @bssId: bssid of sta + * @assocId: associd + * @staType: 0 - Self, 1 other/remote, 2 - bssid + * @staMac: MAC Address of STA + * @shortPreambleSupported: is short preamble supported or not + * @listenInterval: Listen interval + * @wmmEnabled: Support for 11e/WMM + * @uAPSD: U-APSD Flags: 1b per AC + * @maxSPLen: Max SP Length + * @htCapable: 11n HT capable STA + * @greenFieldCapable: 11n Green Field preamble support + * @txChannelWidthSet: TX Width Set: 0 - 20 MHz only, 1 - 20/40 MHz + * @mimoPS: MIMO Power Save + * @rifsMode: RIFS mode: 0 - NA, 1 - Allowed + * @lsigTxopProtection: L-SIG TXOP Protection mechanism + * @us32MaxAmpduDuration: in units of 32 us + * @maxAmpduSize: 0 : 8k , 1 : 16k, 2 : 32k, 3 : 64k + * @maxAmpduDensity: 3 : 0~7 : 2^(11nAMPDUdensity -4) + * @maxAmsduSize: 1 : 3839 bytes, 0 : 7935 bytes + * @fDsssCckMode40Mhz: DSSS CCK supported 40MHz + * @fShortGI40Mhz: short GI support for 40Mhz packets + * @fShortGI20Mhz: short GI support for 20Mhz packets + * @supportedRates: legacy supported rates + * @status: QDF status + * @staIdx: station index + * @bssIdx: BSSID of BSS to which the station is associated + * @updateSta: pdate the existing STA entry, if this flag is set + * @respReqd: A flag to indicate to HAL if the response message is required + * @rmfEnabled: Robust Management Frame (RMF) enabled/disabled + * @encryptType: The unicast encryption type in the association + * @ucUcastSig: Unicast DPU index + * @ucBcastSig: Broadcast DPU index + * @sessionId: PE session id + * @p2pCapableSta: if this is a P2P Capable Sta + * @csaOffloadEnable: CSA offload enable flag + * @vhtCapable: is VHT capabale or not + * @vhtTxChannelWidthSet: VHT channel width + * @vhtSupportedRxNss: VHT supported RX NSS + * @vhtTxBFCapable: txbf capable or not + * @vhtTxMUBformeeCapable: Bformee capable or not + * @enableVhtpAid: enable VHT AID + * @enableVhtGid: enable VHT GID + * @enableAmpduPs: AMPDU power save + * @enableHtSmps: enable HT SMPS + * @htSmpsconfig: HT SMPS config + * @htLdpcCapable: HT LDPC capable + * @vhtLdpcCapable: VHT LDPC capable + * @smesessionId: sme session id + * @wpa_rsn: RSN capable + * @capab_info: capabality info + * @ht_caps: HT capabalities + * @vht_caps: VHT vapabalities + * @nwType: NW Type + * @maxTxPower: max tx power + * @atimIePresent: Peer Atim Info + * @peerAtimWindowLength: peer ATIM Window length + * @nss: Return the number of spatial streams supported + * @max_amsdu_num: Maximum number of MSDUs in a tx aggregate frame + * + * This structure contains parameter required for + * add sta request of upper layer. + */ +typedef struct { + tSirMacAddr bssId; + uint16_t assocId; + /* Field to indicate if this is sta entry for itself STA adding entry + * for itself or remote (AP adding STA after successful association. + * This may or may not be required in production driver. + */ + uint8_t staType; + uint8_t shortPreambleSupported; + tSirMacAddr staMac; + uint16_t listenInterval; + uint8_t wmmEnabled; + uint8_t uAPSD; + uint8_t maxSPLen; + uint8_t htCapable; + /* 11n Green Field preamble support + * 0 - Not supported, 1 - Supported + * Add it to RA related fields of sta entry in HAL + */ + uint8_t greenFieldCapable; + uint8_t ch_width; + + tSirMacHTMIMOPowerSaveState mimoPS; + uint8_t rifsMode; + /* L-SIG TXOP Protection mechanism + * 0 - No Support, 1 - Supported + * SG - there is global field. + */ + uint8_t lsigTxopProtection; + uint8_t us32MaxAmpduDuration; + uint8_t maxAmpduSize; + uint8_t maxAmpduDensity; + uint8_t maxAmsduSize; + + /* 11n Parameters */ + /* HT STA should set it to 1 if it is enabled in BSS + * HT STA should set it to 0 if AP does not support it. + * This indication is sent to HAL and HAL uses this flag + * to pickup up appropriate 40Mhz rates. + */ + uint8_t fDsssCckMode40Mhz; + uint8_t fShortGI40Mhz; + uint8_t fShortGI20Mhz; + tSirSupportedRates supportedRates; + /* + * Following parameters are for returning status and station index from + * HAL to PE via response message. HAL does not read them. + */ + /* The return status of SIR_HAL_ADD_STA_REQ is reported here */ + QDF_STATUS status; + /* Station index; valid only when 'status' field value is + * QDF_STATUS_SUCCESS + */ + uint8_t staIdx; + /* BSSID of BSS to which the station is associated. + * This should be filled back in by HAL, and sent back to LIM as part of + * the response message, so LIM can cache it in the station entry of + * hash table. When station is deleted, LIM will make use of this bssIdx + * to delete BSS from hal tables and from softmac. + */ + uint8_t bssIdx; + uint8_t updateSta; + uint8_t respReqd; + uint8_t rmfEnabled; + uint32_t encryptType; + uint8_t ucUcastSig; + uint8_t ucBcastSig; + uint8_t sessionId; + uint8_t p2pCapableSta; + uint8_t csaOffloadEnable; + uint8_t vhtCapable; + uint8_t vhtSupportedRxNss; + uint8_t vhtTxBFCapable; + uint8_t enable_su_tx_bformer; + uint8_t vhtTxMUBformeeCapable; + uint8_t enableVhtpAid; + uint8_t enableVhtGid; + uint8_t enableAmpduPs; + uint8_t enableHtSmps; + uint8_t htSmpsconfig; + bool send_smps_action; + uint8_t htLdpcCapable; + uint8_t vhtLdpcCapable; + uint8_t smesessionId; + uint8_t wpa_rsn; + uint16_t capab_info; + uint16_t ht_caps; + uint32_t vht_caps; + tSirNwType nwType; + int8_t maxTxPower; + uint8_t atimIePresent; + uint32_t peerAtimWindowLength; + uint8_t nonRoamReassoc; + uint32_t nss; + uint8_t max_amsdu_num; +} tAddStaParams, *tpAddStaParams; + +/** + * struct tDeleteStaParams - parameters required for del sta request + * @staIdx: station index + * @assocId: association index + * @status: status + * @respReqd: is response required + * @sessionId: PE session id + * @smesessionId: SME session id + * @staType: station type + * @staMac: station mac + */ +typedef struct { + uint16_t staIdx; + uint16_t assocId; + QDF_STATUS status; + uint8_t respReqd; + uint8_t sessionId; + uint8_t smesessionId; + uint8_t staType; + tSirMacAddr staMac; +} tDeleteStaParams, *tpDeleteStaParams; + +/** + * struct tSetStaKeyParams - set key params + * @staIdx: station id + * @encType: encryption type + * @wepType: WEP type + * @defWEPIdx: Default WEP key, valid only for static WEP, must between 0 and 3 + * @key: valid only for non-static WEP encyrptions + * @singleTidRc: 1=Single TID based Replay Count, 0=Per TID based RC + * @smesessionId: sme session id + * @peerMacAddr: peer mac address + * @status: status + * @sessionId: session id + * @sendRsp: send response + * + * This is used by PE to configure the key information on a given station. + * When the secType is WEP40 or WEP104, the defWEPIdx is used to locate + * a preconfigured key from a BSS the station assoicated with; otherwise + * a new key descriptor is created based on the key field. + */ +typedef struct { + uint16_t staIdx; + tAniEdType encType; + tAniWepType wepType; + uint8_t defWEPIdx; + tSirKeys key[SIR_MAC_MAX_NUM_OF_DEFAULT_KEYS]; + uint8_t singleTidRc; + uint8_t smesessionId; + struct qdf_mac_addr peer_macaddr; + QDF_STATUS status; + uint8_t sessionId; + uint8_t sendRsp; +} tSetStaKeyParams, *tpSetStaKeyParams; + +/** + * struct sLimMlmSetKeysReq - set key request parameters + * @peerMacAddr: peer mac address + * @sessionId: PE session id + * @smesessionId: SME session id + * @aid: association id + * @edType: Encryption/Decryption type + * @numKeys: number of keys + * @key: key data + */ +typedef struct sLimMlmSetKeysReq { + struct qdf_mac_addr peer_macaddr; + uint8_t sessionId; /* Added For BT-AMP Support */ + uint8_t smesessionId; /* Added for drivers based on wmi interface */ + uint16_t aid; + tAniEdType edType; /* Encryption/Decryption type */ + uint8_t numKeys; + tSirKeys key[SIR_MAC_MAX_NUM_OF_DEFAULT_KEYS]; +} tLimMlmSetKeysReq, *tpLimMlmSetKeysReq; + +/** + * struct tAddBssParams - parameters required for add bss params + * @bssId: MAC Address/BSSID + * @selfMacAddr: Self Mac Address + * @bssType: BSS type + * @operMode: AP - 0; STA - 1; + * @nwType: network type + * @shortSlotTimeSupported: is short slot time supported or not + * @llaCoexist: is 11a coexist or not + * @llbCoexist: 11b coexist supported or not + * @llgCoexist: 11g coexist supported or not + * @ht20Coexist: HT20 coexist supported or not + * @fLsigTXOPProtectionFullSupport: TXOP protection supported or not + * @fRIFSMode: RIFS is supported or not + * @beaconInterval: beacon interval + * @dtimPeriod: DTIM period + * @cfParamSet: CF Param Set + * @rateSet: MAC Rate Set + * @htCapable: Enable/Disable HT capabilities + * @obssProtEnabled: Enable/Disable OBSS protection + * @rmfEnabled: RMF enabled/disabled + * @htOperMode: HT Operating Mode + * @HT Operating Mode: Dual CTS Protection: 0 - Unused, 1 - Used + * @txChannelWidthSet: TX Width Set: 0 - 20 MHz only, 1 - 20/40 MHz + * @currentOperChannel: Current Operating Channel + * @currentExtChannel: Current Extension Channel, if applicable + * @staContext: sta context + * @status: status + * @bssIdx: BSS index allocated by HAL + * @updateBss: update the existing BSS entry, if this flag is set + * @ssId: Add BSSID info for rxp filter + * @respReqd: send the response message to LIM only when this flag is set + * @sessionId: PE session id + * @txMgmtPower: tx power used for mgmt frames + * @maxTxPower: max power to be used after applying the power constraint + * @extSetStaKeyParamValid: Ext Bss Config Msg if set + * @extSetStaKeyParam: SetStaKeyParams for ext bss msg + * @ucMaxProbeRespRetryLimit: probe Response Max retries + * @bHiddenSSIDEn: To Enable Hidden ssid. + * @bProxyProbeRespEn: To Enable Disable FW Proxy Probe Resp + * @halPersona: Persona for the BSS can be STA,AP,GO,CLIENT value + * @bSpectrumMgtEnabled: Spectrum Management Capability, 1:Enabled, 0:Disabled. + * @vhtCapable: VHT capablity + * @vhtTxChannelWidthSet: VHT tx channel width + * @reassocReq: Set only during roaming reassociation + * @chainMask: chain mask + * @smpsMode: SMPS mode + * @dot11_mode: 802.11 mode + */ +typedef struct { + tSirMacAddr bssId; +#ifdef HAL_SELF_STA_PER_BSS + tSirMacAddr selfMacAddr; +#endif /* HAL_SELF_STA_PER_BSS */ + tSirBssType bssType; + uint8_t operMode; + tSirNwType nwType; + uint8_t shortSlotTimeSupported; + uint8_t llaCoexist; + uint8_t llbCoexist; + uint8_t llgCoexist; + uint8_t ht20Coexist; + uint8_t llnNonGFCoexist; + uint8_t fLsigTXOPProtectionFullSupport; + uint8_t fRIFSMode; + tSirMacBeaconInterval beaconInterval; + uint8_t dtimPeriod; + tSirMacCfParamSet cfParamSet; + tSirMacRateSet rateSet; + uint8_t htCapable; + uint8_t obssProtEnabled; + uint8_t rmfEnabled; + tSirMacHTOperatingMode htOperMode; + uint8_t dualCTSProtection; + uint8_t txChannelWidthSet; + uint8_t currentOperChannel; + tAddStaParams staContext; + QDF_STATUS status; + uint16_t bssIdx; + /* HAL should update the existing BSS entry, if this flag is set. + * PE will set this flag in case of reassoc, where we want to resue the + * the old bssID and still return success. + */ + uint8_t updateBss; + tSirMacSSid ssId; + uint8_t respReqd; + uint8_t sessionId; + int8_t txMgmtPower; + int8_t maxTxPower; + + uint8_t extSetStaKeyParamValid; + tSetStaKeyParams extSetStaKeyParam; + + uint8_t ucMaxProbeRespRetryLimit; + uint8_t bHiddenSSIDEn; + uint8_t bProxyProbeRespEn; + uint8_t halPersona; + uint8_t bSpectrumMgtEnabled; + uint8_t vhtCapable; + enum phy_ch_width ch_width; + uint8_t ch_center_freq_seg0; + uint8_t ch_center_freq_seg1; + uint8_t reassocReq; /* Set only during roaming reassociation */ + uint16_t chainMask; + uint16_t smpsMode; + uint8_t dot11_mode; + uint8_t nonRoamReassoc; + uint8_t wps_state; + uint8_t nss; + uint8_t nss_2g; + uint8_t nss_5g; + uint8_t beacon_tx_rate; + uint32_t tx_aggregation_size; + uint32_t rx_aggregation_size; +} tAddBssParams, *tpAddBssParams; + +/** + * struct tDeleteBssParams - params required for del bss request + * @bssIdx: BSSID + * @status: QDF status + * @respReqd: response message to LIM only when this flag is set + * @sessionId: PE session id + * @bssid: BSSID mac address + * @smesessionId: sme session id + */ +typedef struct { + uint8_t bssIdx; + QDF_STATUS status; + uint8_t respReqd; + uint8_t sessionId; + tSirMacAddr bssid; + uint8_t smesessionId; +} tDeleteBssParams, *tpDeleteBssParams; + +/** + * struct sSirScanEntry - scan entry + * @bssIdx: BSSID + * @activeBSScnt: active BSS count + */ +typedef struct sSirScanEntry { + uint8_t bssIdx[HAL_NUM_BSSID]; + uint8_t activeBSScnt; +} tSirScanEntry, *ptSirScanEntry; + +/** + * struct tInitScanParams - params required for init scan request + * @bssid: BSSID + * @notifyBss: notify BSS + * @useNoA: use NOA + * @notifyHost: notify UMAC if set + * @frameLength: frame length + * @frameType: frame type + * @scanDuration: Indicates the scan duration (in ms) + * @macMgmtHdr: For creation of CTS-to-Self and Data-NULL MAC packets + * @scanEntry: scan entry + * @checkLinkTraffic: when this flag is set, HAL should check for + * link traffic prior to scan + * @status: status + */ +typedef struct { + tSirMacAddr bssid; + uint8_t notifyBss; + uint8_t useNoA; + uint8_t notifyHost; + uint8_t frameLength; + uint8_t frameType; + uint16_t scanDuration; + tSirMacMgmtHdr macMgmtHdr; + tSirScanEntry scanEntry; + tSirLinkTrafficCheck checkLinkTraffic; + QDF_STATUS status; +} tInitScanParams, *tpInitScanParams; + +typedef enum eDelStaReasonCode { + HAL_DEL_STA_REASON_CODE_KEEP_ALIVE = 0x1, + HAL_DEL_STA_REASON_CODE_TIM_BASED = 0x2, + HAL_DEL_STA_REASON_CODE_RA_BASED = 0x3, + HAL_DEL_STA_REASON_CODE_UNKNOWN_A2 = 0x4 +} tDelStaReasonCode; + +typedef enum eSmpsModeValue { + STATIC_SMPS_MODE = 0x0, + DYNAMIC_SMPS_MODE = 0x1, + SMPS_MODE_RESERVED = 0x2, + SMPS_MODE_DISABLED = 0x3 +} tSmpsModeValue; + +/** + * struct tDeleteStaContext - params required for delete sta request + * @assocId: association id + * @staId: station id + * @bssId: mac address + * @addr2: mac address + * @reasonCode: reason code + * @rssi: rssi value during disconnection + */ +typedef struct { + bool is_tdls; + uint8_t vdev_id; + uint16_t assocId; + uint16_t staId; + tSirMacAddr bssId; + tSirMacAddr addr2; + uint16_t reasonCode; + int8_t rssi; +} tDeleteStaContext, *tpDeleteStaContext; + +/** + * struct tStartScanParams - params required for start scan request + * @scanChannel: Indicates the current scan channel + * @status: return status + * @startTSF: TSF value + * @txMgmtPower: TX mgmt power + */ +typedef struct { + uint8_t scanChannel; + QDF_STATUS status; + uint32_t startTSF[2]; + int8_t txMgmtPower; +} tStartScanParams, *tpStartScanParams; + +/** + * struct tEndScanParams - params required for end scan request + * @scanChannel: Indicates the current scan channel + * @status: return status + */ +typedef struct { + uint8_t scanChannel; + QDF_STATUS status; +} tEndScanParams, *tpEndScanParams; + +/** + * struct tFinishScanParams - params required for finish scan request + * @bssid: BSSID + * @currentOperChannel: Current operating channel + * @cbState: channel bond state + * @notifyBss: notify BSS flag + * @notifyHost: notify host flag + * @frameLength: frame length + * @frameType: frame type + * @macMgmtHdr: For creation of CTS-to-Self and Data-NULL MAC packets + * @scanEntry: scan entry + * @status: return status + * Request Type = SIR_HAL_FINISH_SCAN_REQ + */ +typedef struct { + tSirMacAddr bssid; + uint8_t currentOperChannel; + /* If 20/40 MHz is operational, this will indicate the 40 MHz extension + * channel in combination with the control channel + */ + ePhyChanBondState cbState; + /* For an STA, indicates if a Data NULL frame needs to be sent + * to the AP with FrameControl.PwrMgmt bit set to 0 + */ + uint8_t notifyBss; + uint8_t notifyHost; + uint8_t frameLength; + uint8_t frameType; + tSirMacMgmtHdr macMgmtHdr; + tSirScanEntry scanEntry; + QDF_STATUS status; +} tFinishScanParams, *tpFinishScanParams; + +#ifdef FEATURE_OEM_DATA_SUPPORT + +#ifndef OEM_DATA_RSP_SIZE +#define OEM_DATA_RSP_SIZE 1724 +#endif + +/** + * struct tStartOemDataRsp - start OEM Data response + * @target_rsp: Indicates if the rsp is from Target or WMA generated. + * @rsp_len: oem data response length + * @oem_data_rsp: pointer to OEM Data response + */ +typedef struct { + bool target_rsp; + uint32_t rsp_len; + uint8_t *oem_data_rsp; +} tStartOemDataRsp, *tpStartOemDataRsp; +#endif /* FEATURE_OEM_DATA_SUPPORT */ + +/** + * struct tBeaconGenParams - params required for beacon gen request + * @bssIdx: Identifies the BSSID for which it is time to generate a beacon + * @bssId: BSSID + * @numOfSta: Number of stations in power save, who have data pending + * @numOfStaWithoutData: Number of stations in power save, + * who don't have any data pending + * @fBroadcastTrafficPending: broadcast traffic pending flag + * @dtimCount: DTIM count + * @rsvd: reserved(padding) + */ +typedef struct sBeaconGenParams { + uint8_t bssIdx; + tSirMacAddr bssId; +#ifdef FIXME_VOLANS + uint8_t numOfSta; + uint8_t numOfStaWithoutData; + uint8_t fBroadcastTrafficPending; + uint8_t dtimCount; +#endif /* FIXME_VOLANS */ + uint8_t rsvd[3]; +} tBeaconGenParams, *tpBeaconGenParams; + +/** + * struct tSendbeaconParams - send beacon parameters + * @bssId: BSSID mac address + * @beacon: beacon data + * @beaconLength: beacon length of template + * @timIeOffset: TIM IE offset + * @p2pIeOffset: P2P IE offset + */ +typedef struct { + tSirMacAddr bssId; + uint8_t *beacon; + uint32_t beaconLength; + uint32_t timIeOffset; + uint16_t p2pIeOffset; +} tSendbeaconParams, *tpSendbeaconParams; + +/** + * struct tSendProbeRespParams - send probe response parameters + * @bssId: BSSID + * @pProbeRespTemplate: probe response template + * @probeRespTemplateLen: probe response template length + * @ucProxyProbeReqValidIEBmap: valid IE bitmap + */ +typedef struct sSendProbeRespParams { + tSirMacAddr bssId; + uint8_t *pProbeRespTemplate; + uint32_t probeRespTemplateLen; + uint32_t ucProxyProbeReqValidIEBmap[8]; +} tSendProbeRespParams, *tpSendProbeRespParams; + +/** + * struct tSetBssKeyParams - BSS key parameters + * @bssIdx: BSSID index + * @encType: encryption Type + * @numKeys: number of keys + * @key: key data + * @singleTidRc: 1=Single TID based Replay Count, 0=Per TID based RC + * @smesessionId: sme session id + * @status: return status of command + * @sessionId: PE session id + */ +typedef struct { + uint8_t bssIdx; + tAniEdType encType; + uint8_t numKeys; + tSirKeys key[SIR_MAC_MAX_NUM_OF_DEFAULT_KEYS]; + uint8_t singleTidRc; + uint8_t smesessionId; + QDF_STATUS status; + uint8_t sessionId; +} tSetBssKeyParams, *tpSetBssKeyParams; + +/** + * struct tUpdateBeaconParams - update beacon request parameters + * @bssIdx: BSSID index + * @fShortPreamble: shortPreamble mode + * @fShortSlotTime: short Slot time + * @beaconInterval: Beacon Interval + * @llaCoexist: 11a coexist + * @llbCoexist: 11b coexist + * @llgCoexist: 11g coexist + * @ht20MhzCoexist: HT 20MHz coexist + * @fLsigTXOPProtectionFullSupport: TXOP protection supported or not + * @fRIFSMode: RIFS mode + * @paramChangeBitmap: change bitmap + * @smeSessionId: SME session id + */ +typedef struct { + uint8_t bssIdx; + uint8_t fShortPreamble; + uint8_t fShortSlotTime; + uint16_t beaconInterval; + uint8_t llaCoexist; + uint8_t llbCoexist; + uint8_t llgCoexist; + uint8_t ht20MhzCoexist; + uint8_t llnNonGFCoexist; + uint8_t fLsigTXOPProtectionFullSupport; + uint8_t fRIFSMode; + uint16_t paramChangeBitmap; + uint8_t smeSessionId; +} tUpdateBeaconParams, *tpUpdateBeaconParams; + +/** + * struct tUpdateVHTOpMode - VHT operating mode + * @opMode: VHT operating mode + * @staId: station id + * @smesessionId: SME session id + * @peer_mac: peer mac address + */ +typedef struct { + uint16_t opMode; + uint16_t dot11_mode; + uint16_t staId; + uint16_t smesessionId; + tSirMacAddr peer_mac; +} tUpdateVHTOpMode, *tpUpdateVHTOpMode; + +/** + * struct tUpdateRxNss - update rx nss parameters + * @rxNss: rx nss value + * @staId: station id + * @smesessionId: sme session id + * @peer_mac: peer mac address + */ +typedef struct { + uint16_t rxNss; + uint16_t staId; + uint16_t smesessionId; + tSirMacAddr peer_mac; +} tUpdateRxNss, *tpUpdateRxNss; + +/** + * struct tUpdateMembership - update membership parmaters + * @membership: membership value + * @staId: station id + * @smesessionId: SME session id + * @peer_mac: peer mac address + */ +typedef struct { + uint32_t membership; + uint16_t staId; + uint16_t smesessionId; + tSirMacAddr peer_mac; +} tUpdateMembership, *tpUpdateMembership; + +/** + * struct tUpdateUserPos - update user position parmeters + * @userPos: user position + * @staId: station id + * @smesessionId: sme session id + * @peer_mac: peer mac address + */ +typedef struct { + uint32_t userPos; + uint16_t staId; + uint16_t smesessionId; + tSirMacAddr peer_mac; +} tUpdateUserPos, *tpUpdateUserPos; + +/** + * struct tUpdateCFParams -CF parameters + * @bssIdx: BSSID index + * @cfpCount: CFP count + * @cfpPeriod: the number of DTIM intervals between the start of CFPs + */ +typedef struct { + uint8_t bssIdx; + /* + * cfpCount indicates how many DTIMs (including the current frame) + * appear before the next CFP start. A CFPCount of 0 indicates that + * the current DTIM marks the start of the CFP. + */ + uint8_t cfpCount; + uint8_t cfpPeriod; +} tUpdateCFParams, *tpUpdateCFParams; + +/** + * struct tSwitchChannelParams - switch channel request parameter + * @channelNumber: channel number + * @localPowerConstraint: local power constraint + * @secondaryChannelOffset: scondary channel offset + * @peSessionId: PE session id + * @txMgmtPower: TX mgmt power + * @maxTxPower: max tx power + * @selfStaMacAddr: self mac address + * @bssId: bssid + * @status: QDF status + * @chainMask: chanin mask + * @smpsMode: SMPS mode + * @isDfsChannel: is DFS channel + * @vhtCapable: VHT capable + * @dot11_mode: 802.11 mode + */ +typedef struct { + uint8_t channelNumber; + uint8_t peSessionId; + int8_t txMgmtPower; + int8_t maxTxPower; + tSirMacAddr selfStaMacAddr; + /* the request has power constraints, this should be applied only to + * that session + * VO Wifi comment: BSSID is needed to identify which session issued + * this request. As the request has power constraints, this should be + * applied only to that session + * V IMP: Keep bssId field at the end of this msg. + * It is used to mantain backward compatbility by way of ignoring if + * using new host/old FW or old host/new FW since it is at the end of + * this struct + */ + tSirMacAddr bssId; + QDF_STATUS status; + uint16_t chainMask; + uint16_t smpsMode; + uint8_t isDfsChannel; + uint8_t vhtCapable; + enum phy_ch_width ch_width; + uint8_t ch_center_freq_seg0; + uint8_t ch_center_freq_seg1; + uint8_t dot11_mode; + + uint8_t restart_on_chan_switch; + uint8_t nss; +} tSwitchChannelParams, *tpSwitchChannelParams; + +typedef void (*tpSetLinkStateCallback)(tpAniSirGlobal pMac, void *msgParam, + bool status); + +/** + * struct tLinkStateParams - link state parameters + * @bssid: BSSID + * @selfMacAddr: self mac address + * @state: link state + * @callback: callback function pointer + * @callbackArg: callback argument + * @session: session context + */ +typedef struct sLinkStateParams { + /* SIR_HAL_SET_LINK_STATE */ + tSirMacAddr bssid; + tSirMacAddr selfMacAddr; + tSirLinkState state; + tpSetLinkStateCallback callback; + void *callbackArg; + int ft; + void *session; + bool status; +} tLinkStateParams, *tpLinkStateParams; + +/** + * struct tAddTsParams - ADDTS related parameters + * @staIdx: station index + * @tspecIdx: TSPEC handler uniquely identifying a TSPEC for a STA in a BSS + * @tspec: tspec value + * @status: QDF status + * @sessionId: session id + * @tsm_interval: TSM interval period passed from lim to WMA + * @setRICparams: RIC parameters + * @sme_session_id: sme session id + */ +typedef struct { + uint16_t staIdx; + uint16_t tspecIdx; + tSirMacTspecIE tspec; + QDF_STATUS status; + uint8_t sessionId; +#ifdef FEATURE_WLAN_ESE + uint16_t tsm_interval; +#endif /* FEATURE_WLAN_ESE */ +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + uint8_t setRICparams; +#endif /* WLAN_FEATURE_ROAM_OFFLOAD */ + uint8_t sme_session_id; +} tAddTsParams, *tpAddTsParams; + +/** + * struct tDelTsParams - DELTS related parameters + * @staIdx: station index + * @tspecIdx: TSPEC identifier uniquely identifying a TSPEC for a STA in a BSS + * @bssId: BSSID + * @sessionId: session id + * @userPrio: user priority + * @delTsInfo: DELTS info + * @setRICparams: RIC parameters + */ +typedef struct { + uint16_t staIdx; + uint16_t tspecIdx; + tSirMacAddr bssId; + uint8_t sessionId; + uint8_t userPrio; +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + tSirDeltsReqInfo delTsInfo; + uint8_t setRICparams; +#endif /* WLAN_FEATURE_ROAM_OFFLOAD */ +} tDelTsParams, *tpDelTsParams; + + +#define HAL_QOS_NUM_TSPEC_MAX 2 +#define HAL_QOS_NUM_AC_MAX 4 + +/** + * struct tAggrAddTsParams - ADDTS parameters + * @staIdx: station index + * @tspecIdx: TSPEC handler uniquely identifying a TSPEC for a STA in a BSS + * @tspec: tspec value + * @status: QDF status + * @sessionId: session id + */ +typedef struct { + uint16_t staIdx; + uint16_t tspecIdx; + tSirMacTspecIE tspec[HAL_QOS_NUM_AC_MAX]; + QDF_STATUS status[HAL_QOS_NUM_AC_MAX]; + uint8_t sessionId; +} tAggrAddTsParams, *tpAggrAddTsParams; + + +typedef tSirRetStatus (*tHalMsgCallback)(tpAniSirGlobal pMac, uint32_t mesgId, + void *mesgParam); + +/** + * struct tEdcaParams - EDCA parameters + * @bssIdx: BSSID index + * @acbe: best effort access catagory + * @acbk: Background access catagory + * @acvi: video access catagory + * @acvo: voice access catagory + */ +typedef struct { + uint16_t bssIdx; + tSirMacEdcaParamRecord acbe; + tSirMacEdcaParamRecord acbk; + tSirMacEdcaParamRecord acvi; + tSirMacEdcaParamRecord acvo; +} tEdcaParams, *tpEdcaParams; + +/** + * struct tSetMIMOPS - MIMO power save related parameters + * @staIdx: station index + * @htMIMOPSState: MIMO Power Save State + * @status: response status + * @fsendRsp: send response flag + * @peerMac: peer mac address + * @sessionId: session id + */ +typedef struct sSet_MIMOPS { + uint16_t staIdx; + tSirMacHTMIMOPowerSaveState htMIMOPSState; + QDF_STATUS status; + uint8_t fsendRsp; + tSirMacAddr peerMac; + uint8_t sessionId; +} tSetMIMOPS, *tpSetMIMOPS; + +/** + * struct tUapsdParams - Uapsd related parameters + * @bkDeliveryEnabled: BK delivery enable flag + * @beDeliveryEnabled: BE delivery enable flag + * @viDeliveryEnabled: VI delivery enable flag + * @voDeliveryEnabled: VO delivery enable flag + * @bkTriggerEnabled: BK trigger enable flag + * @beTriggerEnabled: BE trigger enable flag + * @viTriggerEnabled: VI trigger enable flag + * @voTriggerEnabled: VO trigger enable flag + * @status: response status + * @bssIdx: BSSID index + * Request Type = SIR_HAL_ENTER_UAPSD_REQ + */ +typedef struct sUapsdParams { + uint8_t bkDeliveryEnabled:1; + uint8_t beDeliveryEnabled:1; + uint8_t viDeliveryEnabled:1; + uint8_t voDeliveryEnabled:1; + uint8_t bkTriggerEnabled:1; + uint8_t beTriggerEnabled:1; + uint8_t viTriggerEnabled:1; + uint8_t voTriggerEnabled:1; + QDF_STATUS status; + uint8_t bssIdx; +} tUapsdParams, *tpUapsdParams; + +/** + * struct tHalIndCB - hal message indication callback + * @pHalIndCB: hal message indication callabck + */ +typedef struct tHalIndCB { + tHalMsgCallback pHalIndCB; +} tHalIndCB, *tpHalIndCB; + +/** + * struct sControlTxParams - control tx parameters + * @stopTx: stop transmission + * @fCtrlGlobal: Master flag to stop or resume all transmission + * @ctrlSta: If this flag is set, staBitmap + * @ctrlBss: If this flag is set, bssBitmap and beaconBitmap is valid + * @bssBitmap: bitmap of BSS indices to be stopped for resumed + * @beaconBitmap: this bitmap contains bitmap of BSS indices to be + * stopped for resumed for beacon transmission + */ +typedef struct sControlTxParams { + bool stopTx; + uint8_t fCtrlGlobal; + uint8_t ctrlSta; + uint8_t ctrlBss; + /* When ctrlBss is set, this bitmap contains bitmap of BSS indices to be + * stopped for resumed for transmission. + * This is 32 bit bitmap, not array of bytes. + */ + uint32_t bssBitmap; + /* When ctrlBss is set, this bitmap contains bitmap of BSS indices to be + * stopped for resumed for beacon transmission. + */ + uint32_t beaconBitmap; +} tTxControlParams, *tpTxControlParams; + +/** + * struct tMaxTxPowerParams - Max Tx Power parameters + * @bssId: BSSID is needed to identify which session issued this request + * @selfStaMacAddr: self mac address + * @power: tx power in dbm + * @dev_mode: device mode + * Request Type = SIR_HAL_SET_MAX_TX_POWER_REQ + */ +typedef struct sMaxTxPowerParams { + struct qdf_mac_addr bssId; + struct qdf_mac_addr selfStaMacAddr; + /* In request, + * power == MaxTx power to be used. + * In response, + * power == tx power used for management frames. + */ + int8_t power; + enum tQDF_ADAPTER_MODE dev_mode; +} tMaxTxPowerParams, *tpMaxTxPowerParams; + +/** + * struct tMaxTxPowerPerBandParams - max tx power per band info + * @bandInfo: band info + * @power: power in dbm + */ +typedef struct sMaxTxPowerPerBandParams { + eCsrBand bandInfo; + int8_t power; +} tMaxTxPowerPerBandParams, *tpMaxTxPowerPerBandParams; + +/** + * struct add_sta_self_params - Add Sta Self params + * @self_mac_addr: self MAC Address + * @curr_device_mode: operating device mode + * @type: Vdev Type + * @sub_type: Vdev Sub Type + * @session_id: SME Session ID + * @nss_2g: vdev nss in 2.4G + * @nss_5g: vdev nss in 5G + * @status: response status code + * @tx_aggregation_size: Tx aggregation size + * @rx_aggregation_size: Rx aggregation size + * @enable_bcast_probe_rsp: enable broadcast probe response + * @fils_max_chan_guard_time: FILS max channel guard time + * @pkt_err_disconn_th: packet drop threshold + */ +struct add_sta_self_params { + tSirMacAddr self_mac_addr; + enum tQDF_ADAPTER_MODE curr_device_mode; + uint32_t type; + uint32_t sub_type; + uint8_t session_id; + uint8_t nss_2g; + uint8_t nss_5g; + uint32_t status; + uint32_t tx_aggregation_size; + uint32_t rx_aggregation_size; + bool enable_bcast_probe_rsp; + uint8_t fils_max_chan_guard_time; + uint16_t pkt_err_disconn_th; +}; + +/** + * struct set_ie_param - set IE params structure + * @pdev_id: pdev id + * @ie_type: IE type + * @nss: Nss value + * @ie_len: IE length + * @ie_ptr: Pointer to IE data + * + * Holds the set pdev IE req data. + */ +struct set_ie_param { + uint8_t pdev_id; + uint8_t ie_type; + uint8_t nss; + uint8_t ie_len; + uint8_t *ie_ptr; +}; + +/** + * struct set_dtim_params - dtim params + * @session_id: SME Session ID + * @dtim_period: dtim period + */ +struct set_dtim_params { + uint8_t session_id; + uint8_t dtim_period; +}; + +#define DOT11_HT_IE 1 +#define DOT11_VHT_IE 2 + +#ifdef FEATURE_WLAN_TDLS + +#define HAL_TDLS_MAX_SUPP_CHANNELS 128 +#define HAL_TDLS_MAX_SUPP_OPER_CLASSES 32 + +/** + * struct tTdlsPeerCapParams - TDLS peer capablities parameters + * @isPeerResponder: is peer responder or not + * @peerUapsdQueue: peer uapsd queue + * @peerMaxSp: peer max SP value + * @peerBuffStaSupport: peer buffer sta supported or not + * @peerOffChanSupport: peer offchannel support + * @peerCurrOperClass: peer current operating class + * @selfCurrOperClass: self current operating class + * @peerChanLen: peer channel length + * @peerChan: peer channel list + * @peerOperClassLen: peer operating class length + * @peerOperClass: peer operating class + * @prefOffChanNum: peer offchannel number + * @prefOffChanBandwidth: peer offchannel bandwidth + * @opClassForPrefOffChan: operating class for offchannel + */ +typedef struct { + uint8_t isPeerResponder; + uint8_t peerUapsdQueue; + uint8_t peerMaxSp; + uint8_t peerBuffStaSupport; + uint8_t peerOffChanSupport; + uint8_t peerCurrOperClass; + uint8_t selfCurrOperClass; + uint8_t peerChanLen; + tSirUpdateChanParam peerChan[HAL_TDLS_MAX_SUPP_CHANNELS]; + uint8_t peerOperClassLen; + uint8_t peerOperClass[HAL_TDLS_MAX_SUPP_OPER_CLASSES]; + uint8_t prefOffChanNum; + uint8_t prefOffChanBandwidth; + uint8_t opClassForPrefOffChan; +} tTdlsPeerCapParams; + +/** + * struct tTdlsPeerStateParams - TDLS peer state parameters + * @vdevId: vdev id + * @peerMacAddr: peer mac address + * @peerCap: peer capabality + */ +typedef struct sTdlsPeerStateParams { + uint32_t vdevId; + tSirMacAddr peerMacAddr; + uint32_t peerState; + tTdlsPeerCapParams peerCap; + bool resp_reqd; +} tTdlsPeerStateParams; + +/** + * struct tdls_chan_switch_params - channel switch parameter structure + * @vdev_id: vdev ID + * @peer_mac_addr: Peer mac address + * @tdls_off_ch_bw_offset: Target off-channel bandwitdh offset + * @tdls_off_ch: Target Off Channel + * @oper_class: Operating class for target channel + * @is_responder: Responder or initiator + */ +typedef struct tdls_chan_switch_params_struct { + uint32_t vdev_id; + tSirMacAddr peer_mac_addr; + uint16_t tdls_off_ch_bw_offset; + uint8_t tdls_off_ch; + uint8_t tdls_sw_mode; + uint8_t oper_class; + uint8_t is_responder; +} tdls_chan_switch_params; + +#endif /* FEATURE_WLAN_TDLS */ + +/** + * struct tAbortScanParams - Abort scan parameters + * @SessionId: PE session id + * @scan_id: Scan ID used for original scan request + * @scan_requestor_id: Scan requesting entity + */ +typedef struct sAbortScanParams { + uint8_t SessionId; + uint32_t scan_id; + uint32_t scan_requestor_id; +} tAbortScanParams, *tpAbortScanParams; + +/** + * struct del_sta_self_params - Del Sta Self params + * @session_id: SME Session ID + * @status: response status code + */ +struct del_sta_self_params { + tSirMacAddr self_mac_addr; + uint8_t session_id; + uint32_t status; +}; + +/** + * struct del_sta_self_rsp_params - Del Sta Self response params + * @self_sta_param: sta params + * @generate_rsp: generate response to upper layers + */ +struct del_sta_self_rsp_params { + struct del_sta_self_params *self_sta_param; + uint8_t generate_rsp; +}; + +/** + * struct tP2pPsParams - P2P powersave related params + * @opp_ps: opportunistic power save + * @ctWindow: CT window + * @count: count + * @duration: duration + * @interval: interval + * @single_noa_duration: single shot noa duration + * @psSelection: power save selection + * @sessionId: session id + */ +typedef struct sP2pPsParams { + uint8_t opp_ps; + uint32_t ctWindow; + uint8_t count; + uint32_t duration; + uint32_t interval; + uint32_t single_noa_duration; + uint8_t psSelection; + uint8_t sessionId; +} tP2pPsParams, *tpP2pPsParams; + +/** + * struct tTdlsLinkEstablishParams - TDLS Link establish parameters + * @staIdx: station index + * @isResponder: responder flag + * @uapsdQueues: uapsd queue + * @maxSp: max SP period + * @isBufsta: is station flag + * @isOffChannelSupported: offchannel supported or not + * @peerCurrOperClass: peer current operating class + * @selfCurrOperClass: self current operating class + * @validChannelsLen: valid channel length + * @validChannels: valid channels + * @validOperClassesLen: valid operating class length + * @validOperClasses: valid operating class + * @status: return status of command + */ +typedef struct sTdlsLinkEstablishParams { + uint16_t staIdx; + uint8_t isResponder; + uint8_t uapsdQueues; + uint8_t maxSp; + uint8_t isBufsta; + uint8_t isOffChannelSupported; + uint8_t peerCurrOperClass; + uint8_t selfCurrOperClass; + uint8_t validChannelsLen; + uint8_t validChannels[HAL_MAX_SUPP_CHANNELS]; + uint8_t validOperClassesLen; + uint8_t validOperClasses[HAL_MAX_SUPP_OPER_CLASSES]; + uint32_t status; +} tTdlsLinkEstablishParams, *tpTdlsLinkEstablishParams; + +/** + * struct tHalHiddenSsidVdevRestart - hidden ssid vdev restart params + * @ssidHidden: is hidden ssid or not + * @sessionId: session id + */ +typedef struct tHalHiddenSsidVdevRestart { + uint8_t ssidHidden; + uint8_t sessionId; +} tHalHiddenSsidVdevRestart, *tpHalHiddenSsidVdevRestart; + + +extern void sys_process_mmh_msg(tpAniSirGlobal pMac, tSirMsgQ *pMsg); + +/** + * struct tBeaconFilterMsg - Beacon Filtering data structure + * @capabilityInfo: capability info + * @capabilityMask: capabality mask + * @beaconInterval: beacon interval + * @ieNum: IE number + * @reserved: reserved + */ +typedef struct sBeaconFilterMsg { + uint16_t capabilityInfo; + uint16_t capabilityMask; + uint16_t beaconInterval; + uint16_t ieNum; + uint8_t bssIdx; + uint8_t reserved; +} qdf_packed tBeaconFilterMsg, *tpBeaconFilterMsg; + +/** + * struct tEidByteInfo - Eid byte info + * @offset: offset + * @value: value + * @bitMask: BIT mask + * @ref: refrence + */ +typedef struct sEidByteInfo { + uint8_t offset; + uint8_t value; + uint8_t bitMask; + uint8_t ref; +} qdf_packed tEidByteInfo, *tpEidByteInfo; + +/** + * struct tBeaconFilterIe - beacon filter IE + * @elementId: element IE + * @checkIePresence: check IE presence + * @byte: Eid byte info + */ +typedef struct sBeaconFilterIe { + uint8_t elementId; + uint8_t checkIePresence; + tEidByteInfo byte; +} qdf_packed tBeaconFilterIe, *tpBeaconFilterIe; + +/** + * struct tDisableIntraBssFwd - intra bss forward parameters + * @sessionId: session id + * @disableintrabssfwd: disable intra bss forward flag + */ +typedef struct sDisableIntraBssFwd { + uint16_t sessionId; + bool disableintrabssfwd; +} qdf_packed tDisableIntraBssFwd, *tpDisableIntraBssFwd; + +#ifdef WLAN_FEATURE_STATS_EXT +/** + * struct tStatsExtRequest - ext stats request + * @vdev_id: vdev id + * @request_data_len: request data length + * @request_data: request data + */ +typedef struct sStatsExtRequest { + uint32_t vdev_id; + uint32_t request_data_len; + uint8_t request_data[]; +} tStatsExtRequest, *tpStatsExtRequest; +#endif /* WLAN_FEATURE_STATS_EXT */ + +#ifdef WLAN_FEATURE_NAN +/** + * struct tNanRequest - NAN request params + * @request_data_len: request data length + * @request_data: request data + */ +typedef struct sNanRequest { + uint16_t request_data_len; + uint8_t request_data[]; +} tNanRequest, *tpNanRequest; +#endif /* WLAN_FEATURE_NAN */ + +#endif /* _HALMSGAPI_H_ */ diff --git a/drivers/staging/qcacld-3.0/core/wma/inc/wma_internal.h b/drivers/staging/qcacld-3.0/core/wma/inc/wma_internal.h new file mode 100644 index 0000000000000000000000000000000000000000..b18253f90f10d5733fe96096c996d496d93a766d --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/wma/inc/wma_internal.h @@ -0,0 +1,1359 @@ +/* + * Copyright (c) 2013-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef WMA_INTERNAL_H +#define WMA_INTERNAL_H + +#if !defined(REMOVE_PKT_LOG) +#include "pktlog_ac.h" +#endif + +/* ################### defines ################### */ +/* + * TODO: Following constant should be shared by firwmare in + * wmi_unified.h. This will be done once wmi_unified.h is updated. + */ +#define WMI_PEER_STATE_AUTHORIZED 0x2 + +#define WMA_2_4_GHZ_MAX_FREQ 3000 +#define WOW_CSA_EVENT_OFFSET 12 + +#define WMA_DEFAULT_SCAN_REQUESTER_ID 1 +#define WMI_SCAN_FINISH_EVENTS (WMI_SCAN_EVENT_START_FAILED | \ + WMI_SCAN_EVENT_COMPLETED | \ + WMI_SCAN_EVENT_DEQUEUED) +/* default value */ +#define DEFAULT_INFRA_STA_KEEP_ALIVE_PERIOD 20 +#define DEFAULT_STA_SA_QUERY_MAX_RETRIES_COUNT (5) +#define DEFAULT_STA_SA_QUERY_RETRY_INTERVAL (200) + +/* pdev vdev and peer stats*/ +#define FW_PDEV_STATS_SET 0x1 +#define FW_VDEV_STATS_SET 0x2 +#define FW_PEER_STATS_SET 0x4 +#define FW_RSSI_PER_CHAIN_STATS_SET 0x8 +#define FW_STATS_SET 0xf + +/*AR9888/AR6320 noise floor approx value + * similar to the mentioned the WMA + */ +#define WMA_TGT_NOISE_FLOOR_DBM (-96) +#define WMA_TGT_MAX_SNR (WMA_TGT_NOISE_FLOOR_DBM * (-1)) + +/* + * Make sure that link monitor and keep alive + * default values should be in sync with CFG. + */ +#define WMA_LINK_MONITOR_DEFAULT_TIME_SECS 10 +#define WMA_KEEP_ALIVE_DEFAULT_TIME_SECS 5 + +#define AGC_DUMP 1 +#define CHAN_DUMP 2 +#define WD_DUMP 3 +#ifdef CONFIG_ATH_PCIE_ACCESS_DEBUG +#define PCIE_DUMP 4 +#endif + +/* conformance test limits */ +#define FCC 0x10 +#define MKK 0x40 +#define ETSI 0x30 + +/* Maximum Buffer length allowed for DFS-2 phyerrors */ +#define DFS_MAX_BUF_LENGTH 4096 + +/* + * Maximum Buffer length allowed for DFS-3 phyerrors + * When 160MHz is supported the Max length of phyerrors + * is larger than the legacy phyerrors. + */ +#define DFS3_MAX_BUF_LENGTH 4436 + +#define WMI_DEFAULT_NOISE_FLOOR_DBM (-96) + +#define WMI_MCC_MIN_CHANNEL_QUOTA 20 +#define WMI_MCC_MAX_CHANNEL_QUOTA 80 +#define WMI_MCC_MIN_NON_ZERO_CHANNEL_LATENCY 30 + +/* The maximum number of patterns that can be transmitted by the firmware + * and maximum patterns size. + */ +#define WMA_MAXNUM_PERIODIC_TX_PTRNS 6 + +#define WMI_MAX_HOST_CREDITS 2 +#define WMI_WOW_REQUIRED_CREDITS 1 + +#define WMI_MAX_MHF_ENTRIES 32 + + +#define MAX_HT_MCS_IDX 8 +#define MAX_VHT_MCS_IDX 10 +#define INVALID_MCS_IDX 255 + +#define LINK_STATUS_LEGACY 0 +#define LINK_STATUS_VHT 0x1 +#define LINK_STATUS_MIMO 0x2 +#define LINK_SUPPORT_VHT 0x4 +#define LINK_SUPPORT_MIMO 0x8 + +#define LINK_RATE_VHT 0x3 + +#define MAX_ENTRY_HOLD_REQ_QUEUE 2 +#define MAX_ENTRY_VDEV_RESP_QUEUE 10 + +/* Time(in ms) to detect DOS attack */ +#define WMA_MGMT_FRAME_DETECT_DOS_TIMER 1000 + +/** + * struct index_data_rate_type - non vht data rate type + * @mcs_index: mcs rate index + * @ht20_rate: HT20 supported rate table + * @ht40_rate: HT40 supported rate table + */ +struct index_data_rate_type { + uint8_t mcs_index; + uint16_t ht20_rate[2]; + uint16_t ht40_rate[2]; +}; + +/** + * struct index_vht_data_rate_type - vht data rate type + * @mcs_index: mcs rate index + * @ht20_rate: VHT20 supported rate table + * @ht40_rate: VHT40 supported rate table + * @ht80_rate: VHT80 supported rate table + */ +struct index_vht_data_rate_type { + uint8_t mcs_index; + uint16_t ht20_rate[2]; + uint16_t ht40_rate[2]; + uint16_t ht80_rate[2]; +}; + +/* + * wma_main.c functions declarations + */ + +int +wmi_unified_pdev_set_param(wmi_unified_t wmi_handle, WMI_PDEV_PARAM param_id, + uint32_t param_value); + +void wma_send_msg(tp_wma_handle wma_handle, uint16_t msg_type, + void *body_ptr, uint32_t body_val); + +void wma_data_tx_ack_comp_hdlr(void *wma_context, + qdf_nbuf_t netbuf, int32_t status); + +QDF_STATUS wma_set_ppsconfig(uint8_t vdev_id, uint16_t pps_param, + int value); + +/* + * wma_scan_roam.c functions declarations + */ + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +void wma_process_roam_invoke(WMA_HANDLE handle, + struct wma_roam_invoke_cmd *roaminvoke); + +void wma_process_roam_synch_fail(WMA_HANDLE handle, + struct roam_offload_synch_fail *synch_fail); + +int wma_roam_synch_event_handler(void *handle, uint8_t *event, + uint32_t len); +#endif + +/** + * wma_update_per_roam_config() -per roam config parameter updation to FW + * @handle: wma handle + * @req_buf: per roam config parameters + * + * Return: none + */ +void wma_update_per_roam_config(WMA_HANDLE handle, + struct wmi_per_roam_config_req *req_buf); + +QDF_STATUS wma_get_buf_start_scan_cmd(tp_wma_handle wma_handle, + tSirScanOffloadReq *scan_req, + struct scan_start_params *cmd); + +QDF_STATUS wma_get_buf_stop_scan_cmd(tp_wma_handle wma_handle, + wmi_buf_t *buf, + int *buf_len, + tAbortScanParams *abort_scan_req); + +QDF_STATUS wma_start_scan(tp_wma_handle wma_handle, + tSirScanOffloadReq *scan_req, uint16_t msg_type); + +QDF_STATUS wma_stop_scan(tp_wma_handle wma_handle, + tAbortScanParams *abort_scan_req); + +QDF_STATUS wma_update_channel_list(WMA_HANDLE handle, + tSirUpdateChanList *chan_list); + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +QDF_STATUS wma_roam_scan_fill_self_caps(tp_wma_handle wma_handle, + roam_offload_param * + roam_offload_params, + tSirRoamOffloadScanReq *roam_req); +#endif + +QDF_STATUS wma_roam_scan_offload_mode(tp_wma_handle wma_handle, + wmi_start_scan_cmd_fixed_param * + scan_cmd_fp, + tSirRoamOffloadScanReq *roam_req, + uint32_t mode, uint32_t vdev_id); + +QDF_STATUS wma_roam_scan_offload_rssi_thresh(tp_wma_handle wma_handle, + tSirRoamOffloadScanReq *roam_req); + +QDF_STATUS wma_roam_scan_offload_scan_period(tp_wma_handle wma_handle, + uint32_t scan_period, + uint32_t scan_age, + uint32_t vdev_id); + +QDF_STATUS wma_roam_scan_offload_rssi_change(tp_wma_handle wma_handle, + uint32_t vdev_id, + int32_t rssi_change_thresh, + uint32_t bcn_rssi_weight, + uint32_t hirssi_delay_btw_scans); + +QDF_STATUS wma_roam_scan_offload_chan_list(tp_wma_handle wma_handle, + uint8_t chan_count, + uint8_t *chan_list, + uint8_t list_type, uint32_t vdev_id); + +A_UINT32 e_csr_auth_type_to_rsn_authmode(eCsrAuthType authtype, + eCsrEncryptionType encr); + +A_UINT32 e_csr_encryption_type_to_rsn_cipherset(eCsrEncryptionType encr); + +void wma_roam_scan_fill_ap_profile(tp_wma_handle wma_handle, + tpAniSirGlobal pMac, + tSirRoamOffloadScanReq *roam_req, + wmi_ap_profile *ap_profile_p); + +void wma_roam_scan_fill_scan_params(tp_wma_handle wma_handle, + tpAniSirGlobal pMac, + tSirRoamOffloadScanReq *roam_req, + wmi_start_scan_cmd_fixed_param * + scan_params); + +QDF_STATUS wma_roam_scan_offload_ap_profile(tp_wma_handle wma_handle, + wmi_ap_profile *ap_profile_p, + uint32_t vdev_id); + +QDF_STATUS wma_roam_scan_bmiss_cnt(tp_wma_handle wma_handle, + A_INT32 first_bcnt, + A_UINT32 final_bcnt, uint32_t vdev_id); + +QDF_STATUS wma_roam_scan_offload_command(tp_wma_handle wma_handle, + uint32_t command, uint32_t vdev_id); + +QDF_STATUS wma_roam_preauth_chan_set(tp_wma_handle wma_handle, + tpSwitchChannelParams params, + uint8_t vdev_id); + +QDF_STATUS wma_roam_preauth_chan_cancel(tp_wma_handle wma_handle, + tpSwitchChannelParams params, + uint8_t vdev_id); + +void wma_roam_preauth_scan_event_handler(tp_wma_handle wma_handle, + uint8_t vdev_id, + wmi_scan_event_fixed_param * + wmi_event); + +void wma_set_channel(tp_wma_handle wma, tpSwitchChannelParams params); + +#ifdef FEATURE_WLAN_SCAN_PNO +QDF_STATUS wma_pno_start(tp_wma_handle wma, tpSirPNOScanReq pno); + +QDF_STATUS wma_pno_stop(tp_wma_handle wma, uint8_t vdev_id); + +void wma_config_pno(tp_wma_handle wma, tpSirPNOScanReq pno); +void wma_set_pno_channel_prediction(uint8_t *buf_ptr, + tpSirPNOScanReq pno); +void wma_scan_cache_updated_ind(tp_wma_handle wma, uint8_t sessionId); +#else +static inline void wma_set_pno_channel_prediction(uint8_t *buf_ptr, + void *pno) +{ + WMA_LOGD("PNO Channel Prediction feature not supported"); + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_FIXED_STRUC, 0); +} +#endif + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +void wma_set_ric_req(tp_wma_handle wma, void *msg, uint8_t is_add_ts); +#endif + +#ifdef FEATURE_WLAN_EXTSCAN + +int wma_extscan_start_stop_event_handler(void *handle, + uint8_t *cmd_param_info, + uint32_t len); + +int wma_extscan_operations_event_handler(void *handle, + uint8_t *cmd_param_info, + uint32_t len); + +int wma_extscan_table_usage_event_handler(void *handle, + uint8_t *cmd_param_info, + uint32_t len); + +int wma_extscan_capabilities_event_handler(void *handle, + uint8_t *cmd_param_info, + uint32_t len); + +int wma_extscan_hotlist_match_event_handler(void *handle, + uint8_t *cmd_param_info, + uint32_t len); + +int wma_extscan_cached_results_event_handler(void *handle, + uint8_t *cmd_param_info, + uint32_t len); + +int wma_extscan_change_results_event_handler(void *handle, + uint8_t *cmd_param_info, + uint32_t len); + +int wma_passpoint_match_event_handler(void *handle, + uint8_t *cmd_param_info, + uint32_t len); + +#endif + +void wma_register_extscan_event_handler(tp_wma_handle wma_handle); + +#ifdef FEATURE_WLAN_EXTSCAN +QDF_STATUS wma_get_buf_extscan_start_cmd(tp_wma_handle wma_handle, + tSirWifiScanCmdReqParams *pstart, + wmi_buf_t *buf, int *buf_len); + +QDF_STATUS wma_start_extscan(tp_wma_handle wma, + tSirWifiScanCmdReqParams *pstart); + +QDF_STATUS wma_stop_extscan(tp_wma_handle wma, + tSirExtScanStopReqParams *pstopcmd); + +QDF_STATUS wma_get_buf_extscan_hotlist_cmd(tp_wma_handle wma_handle, + tSirExtScanSetBssidHotListReqParams * + photlist, int *buf_len); + +QDF_STATUS wma_extscan_start_hotlist_monitor(tp_wma_handle wma, + tSirExtScanSetBssidHotListReqParams + *photlist); + +QDF_STATUS wma_extscan_stop_hotlist_monitor(tp_wma_handle wma, + tSirExtScanResetBssidHotlistReqParams + *photlist_reset); + +QDF_STATUS wma_get_buf_extscan_change_monitor_cmd(tp_wma_handle wma_handle, + tSirExtScanSetSigChangeReqParams + *psigchange, wmi_buf_t *buf, + int *buf_len); + +QDF_STATUS wma_extscan_start_change_monitor(tp_wma_handle wma, + tSirExtScanSetSigChangeReqParams * + psigchange); + +QDF_STATUS wma_extscan_stop_change_monitor(tp_wma_handle wma, + tSirExtScanResetSignificantChangeReqParams + *pResetReq); + +QDF_STATUS wma_extscan_get_cached_results(tp_wma_handle wma, + tSirExtScanGetCachedResultsReqParams * + pcached_results); + +QDF_STATUS wma_extscan_get_capabilities(tp_wma_handle wma, + tSirGetExtScanCapabilitiesReqParams * + pgetcapab); +QDF_STATUS wma_set_epno_network_list(tp_wma_handle wma, + struct wifi_epno_params *req); + +QDF_STATUS wma_set_passpoint_network_list(tp_wma_handle wma, + struct wifi_passpoint_req *req); + +QDF_STATUS wma_reset_passpoint_network_list(tp_wma_handle wma, + struct wifi_passpoint_req *req); +#endif + +QDF_STATUS wma_ipa_offload_enable_disable(tp_wma_handle wma, + struct sir_ipa_offload_enable_disable *ipa_offload); + +void wma_process_unit_test_cmd(WMA_HANDLE handle, + t_wma_unit_test_cmd * wma_utest); + +QDF_STATUS wma_scan_probe_setoui(tp_wma_handle wma, tSirScanMacOui *psetoui); + +int wma_scan_event_callback(WMA_HANDLE handle, uint8_t *data, uint32_t len); + +void wma_roam_better_ap_handler(tp_wma_handle wma, uint32_t vdev_id); + +int wma_roam_event_callback(WMA_HANDLE handle, uint8_t *event_buf, + uint32_t len); + +#ifdef FEATURE_WLAN_SCAN_PNO +int wma_nlo_match_evt_handler(void *handle, uint8_t *event, uint32_t len); + +int wma_nlo_scan_cmp_evt_handler(void *handle, uint8_t *event, uint32_t len); +#endif + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +void wma_process_roam_synch_complete(WMA_HANDLE handle, uint8_t vdev_id); +static inline bool wma_is_roam_synch_in_progress(tp_wma_handle wma, + uint8_t vdev_id) +{ + return wma->interfaces[vdev_id].roam_synch_in_progress; +} +#else +static inline bool wma_is_roam_synch_in_progress(tp_wma_handle wma, + uint8_t vdev_id) +{ + return false; +} +static inline uint32_t wma_roam_scan_get_cckm_mode( + struct sSirRoamOffloadScanReq *roam_req, uint32_t auth_mode) +{ + return WMI_AUTH_CCKM; +} +#endif + +/* + * wma_dev_if.c functions declarations + */ + +void *wma_find_vdev_by_addr(tp_wma_handle wma, uint8_t *addr, + uint8_t *vdev_id); + +/** + * wma_find_vdev_by_id() - Returns vdev handle for given vdev id. + * @wma - wma handle + * @vdev_id - vdev ID + * + * Return: Returns vdev handle if given vdev id is valid. + * Otherwise returns NULL. + */ +static inline void *wma_find_vdev_by_id(tp_wma_handle wma, uint8_t vdev_id) +{ + if (vdev_id > wma->max_bssid) + return NULL; + + return wma->interfaces[vdev_id].handle; +} + +/** + * wma_get_vdev_count() - Returns number of active vdev. + * @wma - wma handle + * + * Return: Returns valid vdev count. + */ +static inline uint8_t wma_get_vdev_count(tp_wma_handle wma) +{ + uint8_t vdev_count = 0, i; + + for (i = 0; i < wma->max_bssid; i++) { + if (wma->interfaces[i].handle) + vdev_count++; + } + return vdev_count; +} + +bool wma_is_vdev_in_ap_mode(tp_wma_handle wma, uint8_t vdev_id); + +#ifdef QCA_IBSS_SUPPORT +bool wma_is_vdev_in_ibss_mode(tp_wma_handle wma, uint8_t vdev_id); +#else +/** + * wma_is_vdev_in_ibss_mode(): dummy function + * @wma: wma handle + * @vdev_id: vdev id + * + * Return false since no vdev can be in ibss mode without ibss support + */ +static inline +bool wma_is_vdev_in_ibss_mode(tp_wma_handle wma, uint8_t vdev_id) +{ + return false; +} +#endif + +/** + * wma_is_vdev_in_beaconning_mode() - check if vdev is in a beaconning mode + * @wma: wma handle + * @vdev_id: vdev id + * + * Helper function to know whether given vdev id + * is in a beaconning mode or not. + * + * Return: True if vdev needs to beacon. + */ +static inline +bool wma_is_vdev_in_beaconning_mode(tp_wma_handle wma, uint8_t vdev_id) +{ + return wma_is_vdev_in_ap_mode(wma, vdev_id) || + wma_is_vdev_in_ibss_mode(wma, vdev_id); +} + +/** + * wma_find_bssid_by_vdev_id() - Get the BSS ID corresponding to the vdev ID + * @wma - wma handle + * @vdev_id - vdev ID + * + * Return: Returns pointer to bssid on success, + * otherwise returns NULL. + */ +static inline uint8_t *wma_find_bssid_by_vdev_id(tp_wma_handle wma, + uint8_t vdev_id) +{ + if (vdev_id >= wma->max_bssid) + return NULL; + + return wma->interfaces[vdev_id].bssid; +} + +void *wma_find_vdev_by_bssid(tp_wma_handle wma, uint8_t *bssid, + uint8_t *vdev_id); + +QDF_STATUS wma_vdev_detach(tp_wma_handle wma_handle, + struct del_sta_self_params *pdel_sta_self_req_param, + uint8_t generateRsp); + +int wma_vdev_start_resp_handler(void *handle, uint8_t *cmd_param_info, + uint32_t len); + +QDF_STATUS wma_vdev_set_param(wmi_unified_t wmi_handle, uint32_t if_id, + uint32_t param_id, uint32_t param_value); + +void wma_remove_peer(tp_wma_handle wma, uint8_t *bssid, + uint8_t vdev_id, ol_txrx_peer_handle peer, + bool roam_synch_in_progress); + +QDF_STATUS wma_create_peer(tp_wma_handle wma, ol_txrx_pdev_handle pdev, + ol_txrx_vdev_handle vdev, + u8 peer_addr[IEEE80211_ADDR_LEN], + uint32_t peer_type, uint8_t vdev_id, + bool roam_synch_in_progress); + +int wma_vdev_stop_resp_handler(void *handle, uint8_t *cmd_param_info, + u32 len); + +ol_txrx_vdev_handle wma_vdev_attach(tp_wma_handle wma_handle, + struct add_sta_self_params *self_sta_req, + uint8_t generateRsp); + +QDF_STATUS wma_vdev_start(tp_wma_handle wma, + struct wma_vdev_start_req *req, bool isRestart); + +void wma_vdev_resp_timer(void *data); + +struct wma_target_req *wma_fill_vdev_req(tp_wma_handle wma, + uint8_t vdev_id, + uint32_t msg_type, uint8_t type, + void *params, uint32_t timeout); + +void wma_hold_req_timer(void *data); +struct wma_target_req *wma_fill_hold_req(tp_wma_handle wma, + uint8_t vdev_id, uint32_t msg_type, + uint8_t type, void *params, + uint32_t timeout); + +void wma_remove_vdev_req(tp_wma_handle wma, uint8_t vdev_id, + uint8_t type); + +void wma_add_bss(tp_wma_handle wma, tpAddBssParams params); + +void wma_add_sta(tp_wma_handle wma, tpAddStaParams add_sta); + +void wma_delete_sta(tp_wma_handle wma, tpDeleteStaParams del_sta); + +void wma_delete_bss(tp_wma_handle wma, tpDeleteBssParams params); + +int32_t wma_find_vdev_by_type(tp_wma_handle wma, int32_t type); + +void wma_set_vdev_intrabss_fwd(tp_wma_handle wma_handle, + tpDisableIntraBssFwd pdis_intra_fwd); + +void wma_delete_bss_ho_fail(tp_wma_handle wma, tpDeleteBssParams params); + +/* + * wma_mgmt.c functions declarations + */ + +int wma_beacon_swba_handler(void *handle, uint8_t *event, uint32_t len); + +int wma_peer_sta_kickout_event_handler(void *handle, u8 *event, u32 len); + +void wma_extscan_wow_event_callback(void *handle, void *event, uint32_t len); + +int wma_unified_bcntx_status_event_handler(void *handle, + uint8_t *cmd_param_info, + uint32_t len); + +void wma_set_sta_sa_query_param(tp_wma_handle wma, + uint8_t vdev_id); + +void wma_set_sta_keep_alive(tp_wma_handle wma, uint8_t vdev_id, + uint32_t method, uint32_t timeperiod, + uint8_t *hostv4addr, uint8_t *destv4addr, + uint8_t *destmac); + +int wma_vdev_install_key_complete_event_handler(void *handle, + uint8_t *event, + uint32_t len); + +QDF_STATUS wma_send_peer_assoc(tp_wma_handle wma, + tSirNwType nw_type, + tpAddStaParams params); + +QDF_STATUS wmi_unified_vdev_set_gtx_cfg_send(wmi_unified_t wmi_handle, + uint32_t if_id, + gtx_config_t *gtx_info); + +void wma_update_protection_mode(tp_wma_handle wma, uint8_t vdev_id, + uint8_t llbcoexist); + +void wma_process_update_beacon_params(tp_wma_handle wma, + tUpdateBeaconParams *bcn_params); + +void wma_update_cfg_params(tp_wma_handle wma, tSirMsgQ *cfgParam); + +void wma_set_bsskey(tp_wma_handle wma_handle, tpSetBssKeyParams key_info); + +void wma_adjust_ibss_heart_beat_timer(tp_wma_handle wma, + uint8_t vdev_id, + int8_t peer_num_delta); + +void wma_set_stakey(tp_wma_handle wma_handle, tpSetStaKeyParams key_info); + +QDF_STATUS wma_process_update_edca_param_req(WMA_HANDLE handle, + tEdcaParams *edca_params); + +int wma_tbttoffset_update_event_handler(void *handle, uint8_t *event, + uint32_t len); + +void wma_send_probe_rsp_tmpl(tp_wma_handle wma, + tpSendProbeRespParams probe_rsp_info); + +void wma_send_beacon(tp_wma_handle wma, tpSendbeaconParams bcn_info); + +void wma_set_keepalive_req(tp_wma_handle wma, + tSirKeepAliveReq *keepalive); + +void wma_beacon_miss_handler(tp_wma_handle wma, uint32_t vdev_id, + int32_t rssi); + +void wma_process_update_opmode(tp_wma_handle wma_handle, + tUpdateVHTOpMode *update_vht_opmode); + +void wma_process_update_rx_nss(tp_wma_handle wma_handle, + tUpdateRxNss *update_rx_nss); + +void wma_process_update_membership(tp_wma_handle wma_handle, + tUpdateMembership *membership); + +void wma_process_update_userpos(tp_wma_handle wma_handle, + tUpdateUserPos *userpos); + +void wma_hidden_ssid_vdev_restart(tp_wma_handle wma_handle, + tHalHiddenSsidVdevRestart *pReq); + +/* + * wma_power.c functions declarations + */ + +void wma_enable_sta_ps_mode(tp_wma_handle wma, tpEnablePsParams ps_req); + +QDF_STATUS wma_unified_set_sta_ps_param(wmi_unified_t wmi_handle, + uint32_t vdev_id, uint32_t param, + uint32_t value); + +QDF_STATUS +wma_set_ibss_pwrsave_params(tp_wma_handle wma, uint8_t vdev_id); + +QDF_STATUS wma_set_ap_peer_uapsd(tp_wma_handle wma, uint32_t vdev_id, + uint8_t *peer_addr, uint8_t uapsd_value, + uint8_t max_sp); + +void wma_update_edca_params_for_ac(tSirMacEdcaParamRecord *edca_param, + wmi_wmm_vparams *wmm_param, int ac); + +void wma_set_tx_power(WMA_HANDLE handle, + tMaxTxPowerParams *tx_pwr_params); + +void wma_set_max_tx_power(WMA_HANDLE handle, + tMaxTxPowerParams *tx_pwr_params); + +void wma_disable_sta_ps_mode(tp_wma_handle wma, tpDisablePsParams ps_req); + +void wma_enable_uapsd_mode(tp_wma_handle wma, tpEnableUapsdParams ps_req); + +void wma_disable_uapsd_mode(tp_wma_handle wma, + tpDisableUapsdParams ps_req); + +QDF_STATUS wma_get_temperature(tp_wma_handle wma_handle); + +int wma_pdev_temperature_evt_handler(void *handle, uint8_t *event, + uint32_t len); + +QDF_STATUS wma_process_tx_power_limits(WMA_HANDLE handle, + tSirTxPowerLimit *ptxlim); + +void wma_update_noa(struct beacon_info *beacon, + struct p2p_sub_element_noa *noa_ie); + +void wma_update_probe_resp_noa(tp_wma_handle wma_handle, + struct p2p_sub_element_noa *noa_ie); + +int wma_p2p_noa_event_handler(void *handle, uint8_t *event, + uint32_t len); + +void wma_process_set_p2pgo_noa_req(tp_wma_handle wma, + tP2pPsParams *ps_params); + +void wma_process_set_mimops_req(tp_wma_handle wma_handle, + tSetMIMOPS *mimops); + +QDF_STATUS wma_set_mimops(tp_wma_handle wma, uint8_t vdev_id, int value); + +QDF_STATUS wma_notify_modem_power_state(void *wma_ptr, + tSirModemPowerStateInd *pReq); + +QDF_STATUS wma_set_smps_params(tp_wma_handle wma, uint8_t vdev_id, + int value); + +void wma_set_suspend_dtim(tp_wma_handle wma); + +void wma_set_resume_dtim(tp_wma_handle wma); + +/* + * wma_data.c functions declarations + */ + + +void wma_set_bss_rate_flags(struct wma_txrx_node *iface, + tpAddBssParams add_bss); + +int32_t wmi_unified_send_txbf(tp_wma_handle wma, tpAddStaParams params); + +void wma_update_txrx_chainmask(int num_rf_chains, int *cmd_value); + +int wma_peer_state_change_event_handler(void *handle, + uint8_t *event_buff, + uint32_t len); + +QDF_STATUS wma_set_enable_disable_mcc_adaptive_scheduler(uint32_t + mcc_adaptive_scheduler); + +QDF_STATUS wma_set_mcc_channel_time_latency + (tp_wma_handle wma, + uint32_t mcc_channel, uint32_t mcc_channel_time_latency); + +QDF_STATUS wma_set_mcc_channel_time_quota + (tp_wma_handle wma, + uint32_t adapter_1_chan_number, + uint32_t adapter_1_quota, uint32_t adapter_2_chan_number); + +void wma_set_linkstate(tp_wma_handle wma, tpLinkStateParams params); + +void wma_unpause_vdev(tp_wma_handle wma); + +QDF_STATUS wma_process_rate_update_indicate(tp_wma_handle wma, + tSirRateUpdateInd * + pRateUpdateParams); + +QDF_STATUS wma_tx_attach(tp_wma_handle wma_handle); + +QDF_STATUS wma_tx_detach(tp_wma_handle wma_handle); + +#if defined(QCA_LL_LEGACY_TX_FLOW_CONTROL) || \ + defined(QCA_LL_TX_FLOW_CONTROL_V2) || defined(CONFIG_HL_SUPPORT) + +int wma_mcc_vdev_tx_pause_evt_handler(void *handle, uint8_t *event, + uint32_t len); +#endif + +#if defined(CONFIG_HL_SUPPORT) && defined(QCA_BAD_PEER_TX_FLOW_CL) +QDF_STATUS wma_process_init_bad_peer_tx_ctl_info(tp_wma_handle wma, + struct t_bad_peer_txtcl_config *config); +#else +static inline QDF_STATUS +wma_process_init_bad_peer_tx_ctl_info(tp_wma_handle wma, + struct t_bad_peer_txtcl_config *config) +{ + return QDF_STATUS_E_FAILURE; +} +#endif + +QDF_STATUS wma_process_init_thermal_info(tp_wma_handle wma, + t_thermal_mgmt *pThermalParams); + +QDF_STATUS wma_process_set_thermal_level(tp_wma_handle wma, + uint8_t thermal_level); + +QDF_STATUS wma_set_thermal_mgmt(tp_wma_handle wma_handle, + t_thermal_cmd_params thermal_info); + +int wma_thermal_mgmt_evt_handler(void *handle, uint8_t *event, + uint32_t len); + +int wma_ibss_peer_info_event_handler(void *handle, uint8_t *data, + uint32_t len); + +int wma_fast_tx_fail_event_handler(void *handle, uint8_t *data, + uint32_t len); + +/* + * wma_utils.c functions declarations + */ + +#ifdef WLAN_FEATURE_STATS_EXT +int wma_stats_ext_event_handler(void *handle, uint8_t *event_buf, + uint32_t len); +#endif + +tSmpsModeValue host_map_smps_mode(A_UINT32 fw_smps_mode); +int wma_smps_mode_to_force_mode_param(uint8_t smps_mode); + +#ifdef WLAN_FEATURE_LINK_LAYER_STATS +void wma_register_ll_stats_event_handler(tp_wma_handle wma_handle); + +QDF_STATUS wma_process_ll_stats_clear_req + (tp_wma_handle wma, const tpSirLLStatsClearReq clearReq); + +QDF_STATUS wma_process_ll_stats_set_req + (tp_wma_handle wma, const tpSirLLStatsSetReq setReq); + +QDF_STATUS wma_process_ll_stats_get_req + (tp_wma_handle wma, const tpSirLLStatsGetReq getReq) ; + +int wma_unified_link_iface_stats_event_handler(void *handle, + uint8_t *cmd_param_info, + uint32_t len); +#endif + +void wma_post_link_status(tAniGetLinkStatus *pGetLinkStatus, + uint8_t link_status); + +int wma_link_status_event_handler(void *handle, uint8_t *cmd_param_info, + uint32_t len); +/** + * wma_rso_cmd_status_event_handler() - RSO Command status event handler + * @wmi_event: WMI event + * + * This function is used to send RSO command status to upper layer + * + * Return: 0 for success + */ +int wma_rso_cmd_status_event_handler(wmi_roam_event_fixed_param *wmi_event); +int wma_stats_event_handler(void *handle, uint8_t *cmd_param_info, + uint32_t len); + +QDF_STATUS wma_send_link_speed(uint32_t link_speed); + +int wma_link_speed_event_handler(void *handle, uint8_t *cmd_param_info, + uint32_t len); + +QDF_STATUS wma_wni_cfg_dnld(tp_wma_handle wma_handle); + +int wma_unified_debug_print_event_handler(void *handle, uint8_t *datap, + uint32_t len); + +bool wma_is_sap_active(tp_wma_handle wma_handle); + +bool wma_is_p2p_go_active(tp_wma_handle wma_handle); + +bool wma_is_p2p_cli_active(tp_wma_handle wma_handle); + +bool wma_is_sta_active(tp_wma_handle wma_handle); + +WLAN_PHY_MODE wma_peer_phymode(tSirNwType nw_type, uint8_t sta_type, + uint8_t is_ht, uint8_t ch_width, + uint8_t is_vht); + +int32_t wma_txrx_fw_stats_reset(tp_wma_handle wma_handle, + uint8_t vdev_id, uint32_t value); + +int32_t wma_set_txrx_fw_stats_level(tp_wma_handle wma_handle, + uint8_t vdev_id, uint32_t value); + +void wma_get_stats_req(WMA_HANDLE handle, + tAniGetPEStatsReq *get_stats_param); + +#if defined(QCA_WIFI_FTM) +void wma_utf_detach(tp_wma_handle wma_handle); + +void wma_utf_attach(tp_wma_handle wma_handle); + +QDF_STATUS +wma_process_ftm_command(tp_wma_handle wma_handle, + struct ar6k_testmode_cmd_data *msg_buffer); +#endif + +/* + * wma_features.c functions declarations + */ + +void wma_process_link_status_req(tp_wma_handle wma, + tAniGetLinkStatus *pGetLinkStatus); + +#ifdef FEATURE_WLAN_LPHB +QDF_STATUS wma_process_lphb_conf_req(tp_wma_handle wma_handle, + tSirLPHBReq *lphb_conf_req); + +#endif + +QDF_STATUS wma_process_dhcp_ind(tp_wma_handle wma_handle, + tAniDHCPInd *ta_dhcp_ind); + +int wma_profile_data_report_event_handler(void *handle, uint8_t *event_buf, + uint32_t len); + +QDF_STATUS wma_unified_fw_profiling_cmd(wmi_unified_t wmi_handle, + uint32_t cmd, uint32_t value1, uint32_t value2); + +void wma_wow_tx_complete(void *wma); + +int wmi_unified_nat_keepalive_enable(tp_wma_handle wma, uint8_t vdev_id); + +int wma_unified_csa_offload_enable(tp_wma_handle wma, uint8_t vdev_id); + +#ifdef WLAN_FEATURE_NAN +int wma_nan_rsp_event_handler(void *handle, uint8_t *event_buf, uint32_t len); +#endif + +#ifdef FEATURE_WLAN_TDLS +int wma_tdls_event_handler(void *handle, uint8_t *event, uint32_t len); +#endif + +int wma_csa_offload_handler(void *handle, uint8_t *event, uint32_t len); + +#ifdef WLAN_FEATURE_GTK_OFFLOAD +int wma_gtk_offload_status_event(void *handle, uint8_t *event, uint32_t len); +#endif + +#ifdef FEATURE_OEM_DATA_SUPPORT +int wma_oem_data_response_handler(void *handle, uint8_t *datap, + uint32_t len); +#endif + +void wma_register_dfs_event_handler(tp_wma_handle wma_handle); + +int +wma_unified_dfs_phyerr_filter_offload_enable(tp_wma_handle wma_handle); + +#if !defined(REMOVE_PKT_LOG) +QDF_STATUS wma_pktlog_wmi_send_cmd(WMA_HANDLE handle, + struct ath_pktlog_wmi_params *params); +#endif + +int wma_wow_wakeup_host_event(void *handle, uint8_t *event, + uint32_t len); +int wma_pdev_resume_event_handler(void *handle, uint8_t *event, uint32_t len); + +/** + * wma_get_wow_bus_suspend() - check is wow bus suspended or not + * @wma: wma handle + * + * Return: true/false + */ +static inline int wma_get_wow_bus_suspend(tp_wma_handle wma) +{ + + return qdf_atomic_read(&wma->is_wow_bus_suspended); +} + +QDF_STATUS wma_resume_req(tp_wma_handle wma, enum qdf_suspend_type type); + +QDF_STATUS wma_wow_add_pattern(tp_wma_handle wma, + struct wow_add_pattern *ptrn); + +QDF_STATUS wma_wow_delete_user_pattern(tp_wma_handle wma, + struct wow_delete_pattern *pattern); + +QDF_STATUS wma_wow_enter(tp_wma_handle wma, tpSirHalWowlEnterParams info); + +QDF_STATUS wma_wow_exit(tp_wma_handle wma, tpSirHalWowlExitParams info); + +QDF_STATUS wma_suspend_req(tp_wma_handle wma, enum qdf_suspend_type type); +void wma_calculate_and_update_conn_state(tp_wma_handle wma); +void wma_update_conn_state(tp_wma_handle wma, uint32_t conn_mask); +void wma_update_conn_state(tp_wma_handle wma, uint32_t conn_mask); + +void wma_del_ts_req(tp_wma_handle wma, tDelTsParams *msg); + +void wma_aggr_qos_req(tp_wma_handle wma, + tAggrAddTsParams *pAggrQosRspMsg); + +void wma_add_ts_req(tp_wma_handle wma, tAddTsParams *msg); + +int wma_process_receive_filter_set_filter_req(tp_wma_handle wma_handle, + tSirRcvPktFilterCfgType * + rcv_filter_param); + +int wma_process_receive_filter_clear_filter_req(tp_wma_handle wma_handle, + tSirRcvFltPktClearParam * + rcv_clear_param); + +#ifdef FEATURE_WLAN_ESE +QDF_STATUS wma_process_tsm_stats_req(tp_wma_handle wma_handler, + void *pTsmStatsMsg); +QDF_STATUS wma_plm_start(tp_wma_handle wma, const tpSirPlmReq plm); +QDF_STATUS wma_plm_stop(tp_wma_handle wma, const tpSirPlmReq plm); +void wma_config_plm(tp_wma_handle wma, tpSirPlmReq plm); +#endif + +QDF_STATUS wma_process_mcbc_set_filter_req(tp_wma_handle wma_handle, + tSirRcvFltMcAddrList * mcbc_param); +#ifdef WLAN_FEATURE_GTK_OFFLOAD +QDF_STATUS wma_process_gtk_offload_req(tp_wma_handle wma, + tpSirGtkOffloadParams params); + +QDF_STATUS wma_process_gtk_offload_getinfo_req(tp_wma_handle wma, + tpSirGtkOffloadGetInfoRspParams + params); +#endif + +QDF_STATUS wma_enable_arp_ns_offload(tp_wma_handle wma, + tpSirHostOffloadReq pHostOffloadParams, + bool bArpOnly); + +/** + * wma_conf_hw_filter_mode() - configure hw filter to the given mode + * @wma: wma handle + * @req: hardware filter request + * + * Return: QDF_STATUS + */ +QDF_STATUS wma_conf_hw_filter_mode(tp_wma_handle wma, + struct hw_filter_request *req); + +QDF_STATUS wma_process_cesium_enable_ind(tp_wma_handle wma); + +QDF_STATUS wma_process_get_peer_info_req + (tp_wma_handle wma, tSirIbssGetPeerInfoReqParams *pReq); + +QDF_STATUS wma_process_tx_fail_monitor_ind + (tp_wma_handle wma, tAniTXFailMonitorInd *pReq); + +QDF_STATUS wma_process_rmc_enable_ind(tp_wma_handle wma); + +QDF_STATUS wma_process_rmc_disable_ind(tp_wma_handle wma); + +QDF_STATUS wma_process_rmc_action_period_ind(tp_wma_handle wma); + +QDF_STATUS wma_process_add_periodic_tx_ptrn_ind(WMA_HANDLE handle, + tSirAddPeriodicTxPtrn * + pAddPeriodicTxPtrnParams); + +QDF_STATUS wma_process_del_periodic_tx_ptrn_ind(WMA_HANDLE handle, + tSirDelPeriodicTxPtrn * + pDelPeriodicTxPtrnParams); + +#ifdef WLAN_FEATURE_STATS_EXT +QDF_STATUS wma_stats_ext_req(void *wma_ptr, tpStatsExtRequest preq); +#endif + +QDF_STATUS wma_process_ibss_route_table_update_ind(void *wma_handle, + tAniIbssRouteTable * pData); + +#ifdef WLAN_FEATURE_EXTWOW_SUPPORT +QDF_STATUS wma_enable_ext_wow(tp_wma_handle wma, tpSirExtWoWParams params); + +int wma_set_app_type1_params_in_fw(tp_wma_handle wma, + tpSirAppType1Params appType1Params); + +QDF_STATUS wma_set_app_type2_params_in_fw(tp_wma_handle wma, + tpSirAppType2Params appType2Params); +#endif + +#ifdef FEATURE_WLAN_AUTO_SHUTDOWN +int wma_auto_shutdown_event_handler(void *handle, uint8_t *event, + uint32_t len); + +QDF_STATUS wma_set_auto_shutdown_timer_req(tp_wma_handle wma_handle, + tSirAutoShutdownCmdParams * + auto_sh_cmd); +#endif + +#ifdef WLAN_FEATURE_TSF +int wma_vdev_tsf_handler(void *handle, uint8_t *data, uint32_t data_len); +QDF_STATUS wma_capture_tsf(tp_wma_handle wma_handle, uint32_t vdev_id); +QDF_STATUS wma_reset_tsf_gpio(tp_wma_handle wma_handle, uint32_t vdev_id); +QDF_STATUS wma_set_tsf_gpio_pin(WMA_HANDLE handle, uint32_t pin); +#else +static inline QDF_STATUS wma_capture_tsf(tp_wma_handle wma_handle, + uint32_t vdev_id) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS wma_reset_tsf_gpio(tp_wma_handle wma_handle, + uint32_t vdev_id) +{ + return QDF_STATUS_SUCCESS; +} + +static inline int wma_vdev_tsf_handler(void *handle, uint8_t *data, + uint32_t data_len) +{ + return 0; +} + +static inline QDF_STATUS wma_set_tsf_gpio_pin(WMA_HANDLE handle, uint32_t pin) +{ + return QDF_STATUS_E_INVAL; +} +#endif +QDF_STATUS wma_set_wisa_params(tp_wma_handle wma, struct sir_wisa_params *wisa); + +#ifdef WLAN_FEATURE_NAN +QDF_STATUS wma_nan_req(void *wma_ptr, tpNanRequest nan_req); +#endif + +#ifdef DHCP_SERVER_OFFLOAD +int wma_process_dhcpserver_offload(tp_wma_handle wma_handle, + tSirDhcpSrvOffloadInfo * + pDhcpSrvOffloadInfo); +#endif + +#ifdef WLAN_FEATURE_GPIO_LED_FLASHING +QDF_STATUS wma_set_led_flashing(tp_wma_handle wma_handle, + tSirLedFlashingReq *flashing); +#endif + +#ifdef FEATURE_WLAN_CH_AVOID +int wma_channel_avoid_evt_handler(void *handle, uint8_t *event, + uint32_t len); + +QDF_STATUS wma_process_ch_avoid_update_req(tp_wma_handle wma_handle, + tSirChAvoidUpdateReq * + ch_avoid_update_req); +#endif + +QDF_STATUS wma_suspend_target(WMA_HANDLE handle, int disable_target_intr); + +#ifdef FEATURE_WLAN_TDLS + +QDF_STATUS wma_update_fw_tdls_state(WMA_HANDLE handle, void *pwmaTdlsparams); +int wma_update_tdls_peer_state(WMA_HANDLE handle, + tTdlsPeerStateParams *peerStateParams); +/** + * wma_set_tdls_offchan_mode() - set tdls off channel mode + * @handle: wma handle + * @chan_switch_params: Pointer to tdls channel switch parameter structure + * + * This function sets tdls off channel mode + * + * Return: 0 on success; negative errno otherwise + */ +QDF_STATUS wma_set_tdls_offchan_mode(WMA_HANDLE wma_handle, + tdls_chan_switch_params *chan_switch_params); +#endif + +struct ieee80211com *wma_dfs_attach(struct ieee80211com *dfs_ic); + +void wma_dfs_detach(struct ieee80211com *dfs_ic); + +void wma_dfs_configure(struct ieee80211com *ic); + +/** + * wma_dfs_configure_channel() - configure DFS channel + * @dfs_ic: ieee80211com ptr + * @band_center_freq1: center frequency 1 + * @band_center_freq2: center frequency 2 + * (valid only for 11ac vht 80plus80 mode) + * @req: vdev start request + * + * Set the Channel parameters in to DFS module + * Also,configure the DFS radar filters for + * matching the DFS phyerrors. + * + * Return: None + */ +void wma_dfs_configure_channel(struct ieee80211com *dfs_ic, + uint32_t band_center_freq1, + uint32_t band_center_freq2, + struct wma_vdev_start_req *req); + +void wma_set_vdev_mgmt_rate(tp_wma_handle wma, uint8_t vdev_id); +void wma_set_sap_keepalive(tp_wma_handle wma, uint8_t vdev_id); + +int wma_rssi_breached_event_handler(void *handle, + u_int8_t *cmd_param_info, u_int32_t len); +#ifdef WLAN_FEATURE_MEMDUMP +int wma_fw_mem_dump_event_handler(void *handle, u_int8_t *cmd_param_info, + u_int32_t len); +QDF_STATUS wma_process_fw_mem_dump_req(tp_wma_handle wma, + struct fw_dump_req *mem_dump_req); +#else +static inline int wma_fw_mem_dump_event_handler(void *handle, + u_int8_t *cmd_param_info, u_int32_t len) +{ + return 0; +} + +static inline QDF_STATUS wma_process_fw_mem_dump_req(tp_wma_handle wma, + void *mem_dump_req) +{ + return QDF_STATUS_SUCCESS; +} +#endif +QDF_STATUS wma_process_set_ie_info(tp_wma_handle wma, + struct vdev_ie_info *ie_info); +int wma_peer_assoc_conf_handler(void *handle, uint8_t *cmd_param_info, + uint32_t len); +int wma_vdev_delete_handler(void *handle, uint8_t *cmd_param_info, + uint32_t len); + +int wma_peer_delete_handler(void *handle, uint8_t *cmd_param_info, + uint32_t len); +void wma_remove_req(tp_wma_handle wma, uint8_t vdev_id, + uint8_t type); +int wma_p2p_lo_event_handler(void *handle, uint8_t *event_buf, + uint32_t len); + +QDF_STATUS wma_process_hal_pwr_dbg_cmd(WMA_HANDLE handle, + struct sir_mac_pwr_dbg_cmd * + sir_pwr_dbg_params); + +#ifdef WLAN_FEATURE_DISA +int wma_encrypt_decrypt_msg_handler(void *handle, uint8_t *data, + uint32_t data_len); +#else +static inline int wma_encrypt_decrypt_msg_handler(void *handle, uint8_t *data, + uint32_t data_len) +{ + return 0; +} +#endif + +/** + * wma_lost_link_info_handler() - collect lost link information and inform SME + * @wma: WMA handle + * @vdev_id: vdev ID + * @rssi: rssi at disconnection time + * + * Return: none + */ +void wma_lost_link_info_handler(tp_wma_handle wma, uint32_t vdev_id, + int32_t rssi); +int wma_unified_power_debug_stats_event_handler(void *handle, + uint8_t *cmd_param_info, uint32_t len); + +/** + * wma_get_rcpi_req() - get rcpi request + * @handle: wma handle + * @rcpi_request: rcpi params + * + * Return: none + */ +QDF_STATUS wma_get_rcpi_req(WMA_HANDLE handle, + struct sme_rcpi_req *rcpi_request); + +/** + * wma_rcpi_event_handler() - rcpi event handler + * @handle: wma handle + * @cmd_param_info: data from event + * @len: length + * + * Return: 0 for success or error code + */ +int wma_rcpi_event_handler(void *handle, uint8_t *cmd_param_info, + uint32_t len); + +#ifdef FEATURE_WLAN_DIAG_SUPPORT +/** + * wma_sta_kickout_event()- send sta kickout event + * @kickout_reason - reasoncode for kickout + * @macaddr[IEEE80211_ADDR_LEN]: Peer mac address + * @vdev_id: Unique id for identifying the VDEV + * + * This function sends sta kickout diag event + * + * Return: void. + */ +void wma_sta_kickout_event(uint32_t kickout_reason, uint8_t vdev_id, + uint8_t *macaddr); +#else +static inline void wma_sta_kickout_event(uint32_t kickout_reason, + uint8_t vdev_id, uint8_t *macaddr) +{ + +}; +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + +/** + * wma_acquire_wmi_resp_wakelock() - acquire the WMI response wakelock + * @wma: the WMA handle containing the wakelock to acquire + * @msec: the wakelock duration in milliseconds + * + * Return: void + */ +void wma_acquire_wmi_resp_wakelock(t_wma_handle *wma, uint32_t msec); + +/** + * wma_release_wmi_resp_wakelock() - release the WMI response wakelock + * @wma: the WMA handle containing the wakelock to release + * + * Return: void + */ +void wma_release_wmi_resp_wakelock(t_wma_handle *wma); + +/** + * wma_send_vdev_start_to_fw() - send the vdev start command to firmware + * @wma: the WMA handle containing a reference to the wmi_handle to use + * @params: the VDEV_START params to send to firmware + * + * This is a helper function that acquires the WMI response wakelock before + * sending down the VDEV_START command to firmware. This wakelock is + * automatically released on failure. Consumers should call + * wma_release_wmi_resp_wakelock() upon receipt of the VDEV_START response from + * firmware, to avoid power penalties. + * + * Return: QDF_STATUS + */ +QDF_STATUS +wma_send_vdev_start_to_fw(t_wma_handle *wma, struct vdev_start_params *params); + +/** + * wma_send_vdev_stop_to_fw() - send the vdev stop command to firmware + * @wma: the WMA handle containing a reference to the wmi_handle to use + * @vdev_id: the VDEV Id of the VDEV to stop + * + * This is a helper function that acquires the WMI response wakelock before + * sending down the VDEV_STOP command to firmware. This wakelock is + * automatically released on failure. Consumers should call + * wma_release_wmi_resp_wakelock() upon receipt of the VDEV_STOP response from + * firmware, to avoid power penalties. + * + * Return: QDF_STATUS + */ +QDF_STATUS wma_send_vdev_stop_to_fw(t_wma_handle *wma, uint8_t vdev_id); + +int wma_get_arp_stats_handler(void *handle, uint8_t *data, + uint32_t data_len); +#endif diff --git a/drivers/staging/qcacld-3.0/core/wma/inc/wma_tgt_cfg.h b/drivers/staging/qcacld-3.0/core/wma/inc/wma_tgt_cfg.h new file mode 100644 index 0000000000000000000000000000000000000000..fbd682a86eb804adf228d18774607e02cb3dbe05 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/wma/inc/wma_tgt_cfg.h @@ -0,0 +1,188 @@ +/* + * Copyright (c) 2013-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef WMA_TGT_CFG_H +#define WMA_TGT_CFG_H + +/** + * struct wma_tgt_services - target services + * @sta_power_save: sta power save + * @uapsd: uapsd + * @ap_dfs: ap dfs + * @en_11ac: enable 11ac + * @arp_offload: arp offload + * @early_rx: early rx + * @pno_offload: pno offload + * @beacon_offload: beacon offload + * @lte_coex_ant_share: LTE coex ant share + * @en_tdls: enable tdls + * @en_tdls_offchan: enable tdls offchan + * @en_tdls_uapsd_buf_sta: enable sta tdls uapsd buf + * @en_tdls_uapsd_sleep_sta: enable sta tdls uapsd sleep + * @en_roam_offload: enable roam offload + */ +struct wma_tgt_services { + uint32_t sta_power_save; + uint32_t uapsd; + uint32_t ap_dfs; + uint32_t en_11ac; + uint32_t arp_offload; + uint32_t early_rx; +#ifdef FEATURE_WLAN_SCAN_PNO + bool pno_offload; +#endif /* FEATURE_WLAN_SCAN_PNO */ + bool beacon_offload; + bool pmf_offload; + uint32_t lte_coex_ant_share; +#ifdef FEATURE_WLAN_TDLS + bool en_tdls; + bool en_tdls_offchan; + bool en_tdls_uapsd_buf_sta; + bool en_tdls_uapsd_sleep_sta; +#endif /* FEATURE_WLAN_TDLS */ +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + bool en_roam_offload; +#endif /* WLAN_FEATURE_ROAM_OFFLOAD */ +}; + +/** + * struct wma_tgt_ht_cap - ht capabalitiy + * @mpdu_density: mpdu density + * @ht_rx_stbc: ht rx stbc + * @ht_tx_stbc: ht tx stbc + * @ht_rx_ldpc: ht rx ldpc + * @ht_sgi_20: ht sgi 20 + * @ht_sgi_40: ht sgi 40 + * @num_rf_chains: num of rf chains + */ +struct wma_tgt_ht_cap { + uint32_t mpdu_density; + bool ht_rx_stbc; + bool ht_tx_stbc; + bool ht_rx_ldpc; + bool ht_sgi_20; + bool ht_sgi_40; + uint32_t num_rf_chains; +}; + +/** + * struct wma_tgt_vht_cap - vht capabalities + * @vht_max_mpdu: vht max mpdu + * @supp_chan_width: supported channel width + * @vht_rx_ldpc: vht rx ldpc + * @vht_short_gi_80: vht short gi 80 + * @vht_short_gi_160: vht short gi 160 + * @vht_tx_stbc: vht tx stbc + * @vht_rx_stbc: vht rx stbc + * @vht_su_bformer: vht su bformer + * @vht_su_bformee: vht su bformee + * @vht_mu_bformer: vht mu bformer + * @vht_mu_bformee: vht mu bformee + * @vht_max_ampdu_len_exp: vht max ampdu len exp + * @vht_txop_ps: vht txop ps + */ +struct wma_tgt_vht_cap { + uint32_t vht_max_mpdu; + uint32_t supp_chan_width; + uint32_t vht_rx_ldpc; + uint32_t vht_short_gi_80; + uint32_t vht_short_gi_160; + uint32_t vht_tx_stbc; + uint32_t vht_rx_stbc; + uint32_t vht_su_bformer; + uint32_t vht_su_bformee; + uint32_t vht_mu_bformer; + uint32_t vht_mu_bformee; + uint32_t vht_max_ampdu_len_exp; + uint32_t vht_txop_ps; +}; + +/** + * struct wma_dfs_radar_ind - dfs radar indication + * @ieee_chan_number: ieee channel number + * @chan_freq: channel freq + * @dfs_radar_status: dfs radar status + */ +struct wma_dfs_radar_ind { + uint8_t ieee_chan_number; + uint32_t chan_freq; + uint32_t dfs_radar_status; +}; + +/** + * struct wma_tgt_cfg - target config + * @target_fw_version: target fw version + * @target_fw_vers_ext: target fw extended sub version + * @band_cap: band capability + * @reg_domain: reg domain + * @eeprom_rd_ext: eeprom rd ext + * @hw_macaddr: hw mcast addr + * @services: struct wma_tgt_services + * @ht_cap: struct wma_tgt_ht_cap + * @vht_cap: struct wma_tgt_vht_cap + * @max_intf_count: max interface count + * @lpss_support: lpass support + * @egap_support: enhanced green ap support + * @nan_datapath_enabled: nan data path support + * @bool is_ra_rate_limit_enabled: RA filter support + * @fw_mem_dump_enabled: Fw memory dump support + * @tx_bfee_8ss_enabled: Tx Beamformee support for 8x8 + * @rcpi_enabled: for checking rcpi support + */ +struct wma_tgt_cfg { + uint32_t target_fw_version; + uint32_t target_fw_vers_ext; + uint8_t band_cap; + uint32_t reg_domain; + uint32_t eeprom_rd_ext; + struct qdf_mac_addr hw_macaddr; + struct wma_tgt_services services; + struct wma_tgt_ht_cap ht_cap; + struct wma_tgt_vht_cap vht_cap; + uint8_t max_intf_count; +#ifdef WLAN_FEATURE_LPSS + uint8_t lpss_support; +#endif + uint8_t ap_arpns_support; +#ifdef FEATURE_GREEN_AP + bool egap_support; +#endif + uint32_t fine_time_measurement_cap; + bool bpf_enabled; +#ifdef FEATURE_WLAN_RA_FILTERING + bool is_ra_rate_limit_enabled; +#endif +#ifdef WLAN_FEATURE_NAN_DATAPATH + bool nan_datapath_enabled; +#endif + bool sub_20_support; + uint16_t wmi_max_len; + bool fw_mem_dump_enabled; + bool tx_bfee_8ss_enabled; + bool rcpi_enabled; +}; +#endif /* WMA_TGT_CFG_H */ diff --git a/drivers/staging/qcacld-3.0/core/wma/inc/wma_types.h b/drivers/staging/qcacld-3.0/core/wma/inc/wma_types.h new file mode 100644 index 0000000000000000000000000000000000000000..121e7f718fe04eb3f049fbfb3c7b9c509ed5e0fa --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/wma/inc/wma_types.h @@ -0,0 +1,752 @@ +/* + * Copyright (c) 2012-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef WLAN_QCT_WMA_H +#define WLAN_QCT_WMA_H + +#include "ani_global.h" + +#include "wma_api.h" +#include "wma_tgt_cfg.h" +#include "i_cds_packet.h" + +#define IS_MCC_SUPPORTED 1 +#define IS_FEATURE_SUPPORTED_BY_FW(feat_enum_value) wma_get_fw_wlan_feat_caps(feat_enum_value) + +#define IS_ROAM_SCAN_OFFLOAD_FEATURE_ENABLE 1 + +#define IS_IBSS_HEARTBEAT_OFFLOAD_FEATURE_ENABLE 1 + +#ifdef FEATURE_WLAN_TDLS +#define IS_ADVANCE_TDLS_ENABLE 0 +#endif + +#ifdef WLAN_SOFTAP_VSTA_FEATURE +#define WMA_MAX_STA (41) +#else +#define WMA_MAX_STA (16) +#endif + +#define WMA_NVDownload_Start(x) ({ QDF_STATUS_SUCCESS; }) + +#define DPU_FEEDBACK_UNPROTECTED_ERROR 0x0F + +#define WMA_GET_RX_MAC_HEADER(pRxMeta) \ + (tpSirMacMgmtHdr)(((t_packetmeta *)pRxMeta)->mpdu_hdr_ptr) + +#define WMA_GET_RX_MPDUHEADER3A(pRxMeta) \ + (tpSirMacDataHdr3a)(((t_packetmeta *)pRxMeta)->mpdu_hdr_ptr) + +#define WMA_GET_RX_MPDU_HEADER_LEN(pRxMeta) \ + (((t_packetmeta *)pRxMeta)->mpdu_hdr_len) + +#define WMA_GET_RX_MPDU_LEN(pRxMeta) \ + (((t_packetmeta *)pRxMeta)->mpdu_len) + +#define WMA_GET_RX_PAYLOAD_LEN(pRxMeta) \ + (((t_packetmeta *)pRxMeta)->mpdu_data_len) + +#define WMA_GET_RX_TSF_DELTA(pRxMeta) \ + (((t_packetmeta *)pRxMeta)->tsf_delta) + +#define WMA_GET_RX_MAC_RATE_IDX(pRxMeta) 0 + +#define WMA_GET_RX_MPDU_DATA(pRxMeta) \ + (((t_packetmeta *)pRxMeta)->mpdu_data_ptr) + +#define WMA_GET_RX_MPDU_HEADER_OFFSET(pRxMeta) 0 + +#define WMA_GET_RX_UNKNOWN_UCAST(pRxMeta) 0 + +#define WMA_GET_RX_CH(pRxMeta) \ + (((t_packetmeta *)pRxMeta)->channel) + +#define WMA_IS_RX_BCAST(pRxMeta) 0 + +#define WMA_GET_RX_FT_DONE(pRxMeta) 0 + +#define WMA_GET_RX_DPU_FEEDBACK(pRxMeta) \ + (((t_packetmeta *)pRxMeta)->dpuFeedback) + +#define WMA_GET_RX_BEACON_SENT(pRxMeta) 0 + +#define WMA_GET_RX_TSF_LATER(pRxMeta) 0 + +#define WMA_GET_RX_TIMESTAMP(pRxMeta) \ + (((t_packetmeta *)pRxMeta)->timestamp) + +#define WMA_IS_RX_IN_SCAN(pRxMeta) \ + (((t_packetmeta *)pRxMeta)->scan) + +#define WMA_GET_OFFLOADSCANLEARN(pRxMeta) \ + (((t_packetmeta *)pRxMeta)->offloadScanLearn) +#define WMA_GET_ROAMCANDIDATEIND(pRxMeta) \ + (((t_packetmeta *)pRxMeta)->roamCandidateInd) +#define WMA_GET_SESSIONID(pRxMeta) \ + (((t_packetmeta *)pRxMeta)->sessionId) +#define WMA_GET_SCAN_SRC(pRxMeta) \ + (((t_packetmeta *)pRxMeta)->scan_src) + +#ifdef FEATURE_WLAN_EXTSCAN +#define WMA_IS_EXTSCAN_SCAN_SRC(pRxMeta) \ + ((((t_packetmeta *)pRxMeta)->scan_src) == WMI_MGMT_RX_HDR_EXTSCAN) +#define WMA_IS_EPNO_SCAN_SRC(pRxMeta) \ + ((((t_packetmeta *)pRxMeta)->scan_src) & WMI_MGMT_RX_HDR_ENLO) +#endif /* FEATURE_WLAN_EXTSCAN */ + +#define WMA_GET_RX_SNR(pRxMeta) \ + (((t_packetmeta *)pRxMeta)->snr) + +#define WMA_GET_RX_RFBAND(pRxMeta) 0 + +#define WMA_MAX_TXPOWER_INVALID 127 +/* rssi value normalized to noise floor of -96 dBm */ +#define WMA_GET_RX_RSSI_NORMALIZED(pRxMeta) \ + (((t_packetmeta *)pRxMeta)->rssi) + +/* raw rssi based on actual noise floor in hardware */ +#define WMA_GET_RX_RSSI_RAW(pRxMeta) \ + (((t_packetmeta *)pRxMeta)->rssi_raw) + +/* + * the repeat_cnt is reserved by FW team, the current value + * is always 0xffffffff + */ +#define WMI_WOW_PULSE_REPEAT_CNT 0xffffffff + + +/* WMA Messages */ +#define WMA_MSG_TYPES_BEGIN SIR_HAL_MSG_TYPES_BEGIN +#define WMA_ITC_MSG_TYPES_BEGIN SIR_HAL_ITC_MSG_TYPES_BEGIN +#define WMA_RADAR_DETECTED_IND SIR_HAL_RADAR_DETECTED_IND + +#define WMA_ADD_STA_REQ SIR_HAL_ADD_STA_REQ +#define WMA_ADD_STA_RSP SIR_HAL_ADD_STA_RSP +#define WMA_ADD_STA_SELF_RSP SIR_HAL_ADD_STA_SELF_RSP +#define WMA_DELETE_STA_REQ SIR_HAL_DELETE_STA_REQ +#define WMA_DELETE_STA_RSP SIR_HAL_DELETE_STA_RSP +#define WMA_ADD_BSS_REQ SIR_HAL_ADD_BSS_REQ +#define WMA_ADD_BSS_RSP SIR_HAL_ADD_BSS_RSP +#define WMA_DELETE_BSS_REQ SIR_HAL_DELETE_BSS_REQ +#define WMA_DELETE_BSS_HO_FAIL_REQ SIR_HAL_DELETE_BSS_HO_FAIL_REQ +#define WMA_DELETE_BSS_RSP SIR_HAL_DELETE_BSS_RSP +#define WMA_DELETE_BSS_HO_FAIL_RSP SIR_HAL_DELETE_BSS_HO_FAIL_RSP +#define WMA_SEND_BEACON_REQ SIR_HAL_SEND_BEACON_REQ +#define WMA_SEND_PROBE_RSP_TMPL SIR_HAL_SEND_PROBE_RSP_TMPL + +#define WMA_SET_BSSKEY_REQ SIR_HAL_SET_BSSKEY_REQ +#define WMA_SET_BSSKEY_RSP SIR_HAL_SET_BSSKEY_RSP +#define WMA_SET_STAKEY_REQ SIR_HAL_SET_STAKEY_REQ +#define WMA_SET_STAKEY_RSP SIR_HAL_SET_STAKEY_RSP +#define WMA_UPDATE_EDCA_PROFILE_IND SIR_HAL_UPDATE_EDCA_PROFILE_IND + +#define WMA_UPDATE_BEACON_IND SIR_HAL_UPDATE_BEACON_IND +#define WMA_UPDATE_CF_IND SIR_HAL_UPDATE_CF_IND +#define WMA_CHNL_SWITCH_REQ SIR_HAL_CHNL_SWITCH_REQ +#define WMA_ADD_TS_REQ SIR_HAL_ADD_TS_REQ +#define WMA_DEL_TS_REQ SIR_HAL_DEL_TS_REQ + +#define WMA_MISSED_BEACON_IND SIR_HAL_MISSED_BEACON_IND + +#define WMA_ENTER_PS_REQ SIR_HAL_ENTER_PS_REQ +#define WMA_EXIT_PS_REQ SIR_HAL_EXIT_PS_REQ + +#define WMA_SWITCH_CHANNEL_RSP SIR_HAL_SWITCH_CHANNEL_RSP +#define WMA_P2P_NOA_ATTR_IND SIR_HAL_P2P_NOA_ATTR_IND +#define WMA_P2P_NOA_START_IND SIR_HAL_P2P_NOA_START_IND +#define WMA_PWR_SAVE_CFG SIR_HAL_PWR_SAVE_CFG +#define WMA_REGISTER_PE_CALLBACK SIR_HAL_REGISTER_PE_CALLBACK + +#define WMA_IBSS_STA_ADD SIR_HAL_IBSS_STA_ADD +#define WMA_TIMER_ADJUST_ADAPTIVE_THRESHOLD_IND SIR_HAL_TIMER_ADJUST_ADAPTIVE_THRESHOLD_IND +#define WMA_SET_LINK_STATE SIR_HAL_SET_LINK_STATE +#define WMA_SET_LINK_STATE_RSP SIR_HAL_SET_LINK_STATE_RSP +#define WMA_SET_STA_BCASTKEY_REQ SIR_HAL_SET_STA_BCASTKEY_REQ +#define WMA_SET_STA_BCASTKEY_RSP SIR_HAL_SET_STA_BCASTKEY_RSP +#define WMA_ADD_TS_RSP SIR_HAL_ADD_TS_RSP +#define WMA_DPU_MIC_ERROR SIR_HAL_DPU_MIC_ERROR +#define WMA_TIMER_CHIP_MONITOR_TIMEOUT SIR_HAL_TIMER_CHIP_MONITOR_TIMEOUT +#define WMA_TIMER_TRAFFIC_ACTIVITY_REQ SIR_HAL_TIMER_TRAFFIC_ACTIVITY_REQ +#define WMA_TIMER_ADC_RSSI_STATS SIR_HAL_TIMER_ADC_RSSI_STATS +#define WMA_TIMER_TRAFFIC_STATS_IND SIR_HAL_TRAFFIC_STATS_IND + +#ifdef WLAN_FEATURE_11W +#define WMA_EXCLUDE_UNENCRYPTED_IND SIR_HAL_EXCLUDE_UNENCRYPTED_IND +#endif + +#ifdef FEATURE_WLAN_ESE +#define WMA_TSM_STATS_REQ SIR_HAL_TSM_STATS_REQ +#define WMA_TSM_STATS_RSP SIR_HAL_TSM_STATS_RSP +#endif + +#define WMA_HT40_OBSS_SCAN_IND SIR_HAL_HT40_OBSS_SCAN_IND + +#define WMA_SET_MIMOPS_REQ SIR_HAL_SET_MIMOPS_REQ +#define WMA_SET_MIMOPS_RSP SIR_HAL_SET_MIMOPS_RSP +#define WMA_SYS_READY_IND SIR_HAL_SYS_READY_IND +#define WMA_SET_TX_POWER_REQ SIR_HAL_SET_TX_POWER_REQ +#define WMA_SET_TX_POWER_RSP SIR_HAL_SET_TX_POWER_RSP +#define WMA_GET_TX_POWER_REQ SIR_HAL_GET_TX_POWER_REQ + +/* Messages to support transmit_halt and transmit_resume */ +#define WMA_TRANSMISSION_CONTROL_IND SIR_HAL_TRANSMISSION_CONTROL_IND +#define WMA_BEACON_FILTER_IND SIR_HAL_BEACON_FILTER_IND + +#define WMA_ENABLE_UAPSD_REQ SIR_HAL_ENABLE_UAPSD_REQ +#define WMA_DISABLE_UAPSD_REQ SIR_HAL_DISABLE_UAPSD_REQ + +/* / PE <-> HAL WOWL messages */ +#define WMA_WOW_ADD_PTRN SIR_HAL_WOW_ADD_PTRN +#define WMA_WOW_DEL_PTRN SIR_HAL_WOW_DEL_PTRN +#define WMA_WOWL_ENTER_REQ SIR_HAL_WOWL_ENTER_REQ +#define WMA_WOWL_ENTER_RSP SIR_HAL_WOWL_ENTER_RSP +#define WMA_WOWL_EXIT_REQ SIR_HAL_WOWL_EXIT_REQ +#define WMA_WOWL_EXIT_RSP SIR_HAL_WOWL_EXIT_RSP +/* / PE <-> HAL statistics messages */ +#define WMA_GET_STATISTICS_REQ SIR_HAL_GET_STATISTICS_REQ +#define WMA_GET_STATISTICS_RSP SIR_HAL_GET_STATISTICS_RSP +#define WMA_SET_KEY_DONE SIR_HAL_SET_KEY_DONE + +/* / PE <-> HAL BTC messages */ +#define WMA_BTC_SET_CFG SIR_HAL_BTC_SET_CFG +#define WMA_HANDLE_FW_MBOX_RSP SIR_HAL_HANDLE_FW_MBOX_RSP + +#define WMA_SET_MAX_TX_POWER_REQ SIR_HAL_SET_MAX_TX_POWER_REQ +#define WMA_SET_MAX_TX_POWER_RSP SIR_HAL_SET_MAX_TX_POWER_RSP +#define WMA_SET_DTIM_PERIOD SIR_HAL_SET_DTIM_PERIOD + +#define WMA_SET_MAX_TX_POWER_PER_BAND_REQ \ + SIR_HAL_SET_MAX_TX_POWER_PER_BAND_REQ + +/* / PE <-> HAL Host Offload message */ +#define WMA_SET_HOST_OFFLOAD SIR_HAL_SET_HOST_OFFLOAD + +/* / PE <-> HAL Keep Alive message */ +#define WMA_SET_KEEP_ALIVE SIR_HAL_SET_KEEP_ALIVE + +#ifdef WLAN_NS_OFFLOAD +#define WMA_SET_NS_OFFLOAD SIR_HAL_SET_NS_OFFLOAD +#endif /* WLAN_NS_OFFLOAD */ + +#define WMA_CONF_HW_FILTER SIR_HAL_CONF_HW_FILTER + +#define WMA_ADD_STA_SELF_REQ SIR_HAL_ADD_STA_SELF_REQ +#define WMA_DEL_STA_SELF_REQ SIR_HAL_DEL_STA_SELF_REQ + +#define WMA_SET_P2P_GO_NOA_REQ SIR_HAL_SET_P2P_GO_NOA_REQ + +#ifdef FEATURE_WLAN_TDLS +#define WMA_SET_TDLS_LINK_ESTABLISH_REQ SIR_HAL_TDLS_LINK_ESTABLISH_REQ +#define WMA_SET_TDLS_LINK_ESTABLISH_REQ_RSP SIR_HAL_TDLS_LINK_ESTABLISH_REQ_RSP +#endif + +#define WMA_WLAN_SUSPEND_IND SIR_HAL_WLAN_SUSPEND_IND +#define WMA_WLAN_RESUME_REQ SIR_HAL_WLAN_RESUME_REQ +#define WMA_MSG_TYPES_END SIR_HAL_MSG_TYPES_END + +#define WMA_RUNTIME_PM_SUSPEND_IND SIR_HAL_RUNTIME_PM_SUSPEND_IND +#define WMA_RUNTIME_PM_RESUME_IND SIR_HAL_RUNTIME_PM_RESUME_IND + +#define WMA_AGGR_QOS_REQ SIR_HAL_AGGR_QOS_REQ +#define WMA_AGGR_QOS_RSP SIR_HAL_AGGR_QOS_RSP + +/* FTM CMD MSG */ +#define WMA_FTM_CMD_REQ SIR_PTT_MSG_TYPES_BEGIN +#define WMA_FTM_CMD_RSP SIR_PTT_MSG_TYPES_END +#define WMA_CSA_OFFLOAD_EVENT SIR_CSA_OFFLOAD_EVENT + +#ifdef FEATURE_WLAN_SCAN_PNO +/*Requests sent to lower driver*/ +#define WMA_SET_PNO_REQ SIR_HAL_SET_PNO_REQ + +#endif /* FEATURE_WLAN_SCAN_PNO */ + +#ifdef FEATURE_WLAN_ESE +#define WMA_SET_PLM_REQ SIR_HAL_SET_PLM_REQ +#endif + +#define WMA_ROAM_SCAN_OFFLOAD_REQ SIR_HAL_ROAM_SCAN_OFFLOAD_REQ + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +#define WMA_ROAM_OFFLOAD_SYNCH_IND SIR_HAL_ROAM_OFFLOAD_SYNCH_IND +#define WMA_ROAM_OFFLOAD_SYNCH_FAIL SIR_HAL_ROAM_OFFLOAD_SYNCH_FAIL +#endif + +#ifdef WLAN_FEATURE_PACKET_FILTERING +#define WMA_8023_MULTICAST_LIST_REQ SIR_HAL_8023_MULTICAST_LIST_REQ +#define WMA_RECEIVE_FILTER_SET_FILTER_REQ SIR_HAL_RECEIVE_FILTER_SET_FILTER_REQ +#define WMA_PACKET_COALESCING_FILTER_MATCH_COUNT_REQ SIR_HAL_PACKET_COALESCING_FILTER_MATCH_COUNT_REQ +#define WMA_PACKET_COALESCING_FILTER_MATCH_COUNT_RSP SIR_HAL_PACKET_COALESCING_FILTER_MATCH_COUNT_RSP +#define WMA_RECEIVE_FILTER_CLEAR_FILTER_REQ SIR_HAL_RECEIVE_FILTER_CLEAR_FILTER_REQ +#endif /* WLAN_FEATURE_PACKET_FILTERING */ + +#define WMA_DHCP_START_IND SIR_HAL_DHCP_START_IND +#define WMA_DHCP_STOP_IND SIR_HAL_DHCP_STOP_IND + +#define WMA_TX_FAIL_MONITOR_IND SIR_HAL_TX_FAIL_MONITOR_IND + +#define WMA_HIDDEN_SSID_VDEV_RESTART SIR_HAL_HIDE_SSID_VDEV_RESTART + +#ifdef WLAN_FEATURE_GTK_OFFLOAD +#define WMA_GTK_OFFLOAD_REQ SIR_HAL_GTK_OFFLOAD_REQ +#define WMA_GTK_OFFLOAD_GETINFO_REQ SIR_HAL_GTK_OFFLOAD_GETINFO_REQ +#define WMA_GTK_OFFLOAD_GETINFO_RSP SIR_HAL_GTK_OFFLOAD_GETINFO_RSP +#endif /* WLAN_FEATURE_GTK_OFFLOAD */ + +#define WMA_SET_TM_LEVEL_REQ SIR_HAL_SET_TM_LEVEL_REQ + +#define WMA_UPDATE_OP_MODE SIR_HAL_UPDATE_OP_MODE +#define WMA_UPDATE_RX_NSS SIR_HAL_UPDATE_RX_NSS +#define WMA_UPDATE_MEMBERSHIP SIR_HAL_UPDATE_MEMBERSHIP +#define WMA_UPDATE_USERPOS SIR_HAL_UPDATE_USERPOS + +#ifdef WLAN_FEATURE_NAN +#define WMA_NAN_REQUEST SIR_HAL_NAN_REQUEST +#endif + +#define WMA_START_SCAN_OFFLOAD_REQ SIR_HAL_START_SCAN_OFFLOAD_REQ +#define WMA_STOP_SCAN_OFFLOAD_REQ SIR_HAL_STOP_SCAN_OFFLOAD_REQ +#define WMA_UPDATE_CHAN_LIST_REQ SIR_HAL_UPDATE_CHAN_LIST_REQ +#define WMA_RX_SCAN_EVENT SIR_HAL_RX_SCAN_EVENT +#define WMA_IBSS_PEER_INACTIVITY_IND SIR_HAL_IBSS_PEER_INACTIVITY_IND + +#define WMA_CLI_SET_CMD SIR_HAL_CLI_SET_CMD +#ifdef FEATURE_WLAN_SCAN_PNO +#define WMA_SME_SCAN_CACHE_UPDATED SIR_HAL_SME_SCAN_CACHE_UPDATED +#endif + +#ifndef REMOVE_PKT_LOG +#define WMA_PKTLOG_ENABLE_REQ SIR_HAL_PKTLOG_ENABLE_REQ +#endif + +#ifdef FEATURE_WLAN_LPHB +#define WMA_LPHB_CONF_REQ SIR_HAL_LPHB_CONF_IND +#endif /* FEATURE_WLAN_LPHB */ + +#ifdef FEATURE_WLAN_CH_AVOID +#define WMA_CH_AVOID_UPDATE_REQ SIR_HAL_CH_AVOID_UPDATE_REQ +#endif /* FEATURE_WLAN_CH_AVOID */ + +#ifdef FEATURE_WLAN_AUTO_SHUTDOWN +#define WMA_SET_AUTO_SHUTDOWN_TIMER_REQ SIR_HAL_SET_AUTO_SHUTDOWN_TIMER_REQ +#endif + +#define WMA_ADD_PERIODIC_TX_PTRN_IND SIR_HAL_ADD_PERIODIC_TX_PTRN_IND +#define WMA_DEL_PERIODIC_TX_PTRN_IND SIR_HAL_DEL_PERIODIC_TX_PTRN_IND + +#define WMA_TX_POWER_LIMIT SIR_HAL_SET_TX_POWER_LIMIT + +#define WMA_RATE_UPDATE_IND SIR_HAL_RATE_UPDATE_IND + +#define WMA_INIT_THERMAL_INFO_CMD SIR_HAL_INIT_THERMAL_INFO_CMD +#define WMA_SET_THERMAL_LEVEL SIR_HAL_SET_THERMAL_LEVEL +#define WMA_RMC_ENABLE_IND SIR_HAL_RMC_ENABLE_IND +#define WMA_RMC_DISABLE_IND SIR_HAL_RMC_DISABLE_IND +#define WMA_RMC_ACTION_PERIOD_IND SIR_HAL_RMC_ACTION_PERIOD_IND + +/* IBSS peer info related message */ +#define WMA_GET_IBSS_PEER_INFO_REQ SIR_HAL_IBSS_PEER_INFO_REQ + +#define WMA_IBSS_CESIUM_ENABLE_IND SIR_HAL_IBSS_CESIUM_ENABLE_IND + +#define WMA_INIT_BAD_PEER_TX_CTL_INFO_CMD SIR_HAL_BAD_PEER_TX_CTL_INI_CMD + +#ifdef FEATURE_WLAN_TDLS +#define WMA_UPDATE_FW_TDLS_STATE SIR_HAL_UPDATE_FW_TDLS_STATE +#define WMA_UPDATE_TDLS_PEER_STATE SIR_HAL_UPDATE_TDLS_PEER_STATE +#define WMA_TDLS_SHOULD_DISCOVER_CMD SIR_HAL_TDLS_SHOULD_DISCOVER +#define WMA_TDLS_SHOULD_TEARDOWN_CMD SIR_HAL_TDLS_SHOULD_TEARDOWN +#define WMA_TDLS_PEER_DISCONNECTED_CMD SIR_HAL_TDLS_PEER_DISCONNECTED +#define WMA_TDLS_SET_OFFCHAN_MODE SIR_HAL_TDLS_SET_OFFCHAN_MODE +#define WMA_TDLS_CONNECTION_TRACKER_NOTIFICATION_CMD SIR_HAL_TDLS_CONNECTION_TRACKER_NOTIFICATION +#endif +#define WMA_SET_SAP_INTRABSS_DIS SIR_HAL_SET_SAP_INTRABSS_DIS + +/* Message to Indicate Radar Presence on SAP Channel */ +#define WMA_DFS_RADAR_IND SIR_HAL_DFS_RADAR_IND + +/* Message to indicate beacon tx completion after beacon template update + * beacon offload case + */ +#define WMA_DFS_BEACON_TX_SUCCESS_IND SIR_HAL_BEACON_TX_SUCCESS_IND +#define WMA_DISASSOC_TX_COMP SIR_HAL_DISASSOC_TX_COMP +#define WMA_DEAUTH_TX_COMP SIR_HAL_DEAUTH_TX_COMP + +#define WMA_MODEM_POWER_STATE_IND SIR_HAL_MODEM_POWER_STATE_IND + +#ifdef WLAN_FEATURE_STATS_EXT +#define WMA_STATS_EXT_REQUEST SIR_HAL_STATS_EXT_REQUEST +#endif + +#define WMA_IPA_OFFLOAD_ENABLE_DISABLE SIR_HAL_IPA_OFFLOAD_ENABLE_DISABLE + +#define WMA_GET_TEMPERATURE_REQ SIR_HAL_GET_TEMPERATURE_REQ +#define WMA_SET_WISA_PARAMS SIR_HAL_SET_WISA_PARAMS + +#ifdef FEATURE_WLAN_EXTSCAN +#define WMA_EXTSCAN_GET_CAPABILITIES_REQ SIR_HAL_EXTSCAN_GET_CAPABILITIES_REQ +#define WMA_EXTSCAN_START_REQ SIR_HAL_EXTSCAN_START_REQ +#define WMA_EXTSCAN_STOP_REQ SIR_HAL_EXTSCAN_STOP_REQ +#define WMA_EXTSCAN_SET_BSSID_HOTLIST_REQ SIR_HAL_EXTSCAN_SET_BSS_HOTLIST_REQ +#define WMA_EXTSCAN_RESET_BSSID_HOTLIST_REQ SIR_HAL_EXTSCAN_RESET_BSS_HOTLIST_REQ +#define WMA_EXTSCAN_SET_SIGNF_CHANGE_REQ SIR_HAL_EXTSCAN_SET_SIGNF_CHANGE_REQ +#define WMA_EXTSCAN_RESET_SIGNF_CHANGE_REQ SIR_HAL_EXTSCAN_RESET_SIGNF_CHANGE_REQ +#define WMA_EXTSCAN_GET_CACHED_RESULTS_REQ SIR_HAL_EXTSCAN_GET_CACHED_RESULTS_REQ +#define WMA_SET_EPNO_LIST_REQ SIR_HAL_SET_EPNO_LIST_REQ +#define WMA_SET_PASSPOINT_LIST_REQ SIR_HAL_SET_PASSPOINT_LIST_REQ +#define WMA_RESET_PASSPOINT_LIST_REQ SIR_HAL_RESET_PASSPOINT_LIST_REQ + +#endif /* FEATURE_WLAN_EXTSCAN */ + +#ifdef WLAN_FEATURE_LINK_LAYER_STATS +#define WMA_LINK_LAYER_STATS_CLEAR_REQ SIR_HAL_LL_STATS_CLEAR_REQ +#define WMA_LINK_LAYER_STATS_SET_REQ SIR_HAL_LL_STATS_SET_REQ +#define WMA_LINK_LAYER_STATS_GET_REQ SIR_HAL_LL_STATS_GET_REQ +#define WMA_LINK_LAYER_STATS_RESULTS_RSP SIR_HAL_LL_STATS_RESULTS_RSP +#endif /* WLAN_FEATURE_LINK_LAYER_STATS */ + +#define WMA_LINK_STATUS_GET_REQ SIR_HAL_LINK_STATUS_GET_REQ + +#ifdef WLAN_FEATURE_EXTWOW_SUPPORT +#define WMA_WLAN_EXT_WOW SIR_HAL_CONFIG_EXT_WOW +#define WMA_WLAN_SET_APP_TYPE1_PARAMS SIR_HAL_CONFIG_APP_TYPE1_PARAMS +#define WMA_WLAN_SET_APP_TYPE2_PARAMS SIR_HAL_CONFIG_APP_TYPE2_PARAMS +#endif + +#define WMA_SET_SCAN_MAC_OUI_REQ SIR_HAL_SET_SCAN_MAC_OUI_REQ +#define WMA_TSF_GPIO_PIN SIR_HAL_TSF_GPIO_PIN_REQ + +#ifdef DHCP_SERVER_OFFLOAD +#define WMA_SET_DHCP_SERVER_OFFLOAD_CMD SIR_HAL_SET_DHCP_SERVER_OFFLOAD +#endif /* DHCP_SERVER_OFFLOAD */ + +#ifdef WLAN_FEATURE_GPIO_LED_FLASHING +#define WMA_LED_FLASHING_REQ SIR_HAL_LED_FLASHING_REQ +#endif + +/* Message posted by wmi when wmi event is received from FW */ +#define WMA_PROCESS_FW_EVENT SIR_HAL_PROCESS_FW_EVENT + +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE +#define WMA_UPDATE_Q2Q_IE_IND SIR_HAL_UPDATE_Q2Q_IE_IND +#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ +#define WMA_SET_RSSI_MONITOR_REQ SIR_HAL_SET_RSSI_MONITOR_REQ + +#define WMA_FW_MEM_DUMP_REQ SIR_HAL_FW_MEM_DUMP_REQ + +#define WMA_OCB_SET_CONFIG_CMD SIR_HAL_OCB_SET_CONFIG_CMD +#define WMA_OCB_SET_UTC_TIME_CMD SIR_HAL_OCB_SET_UTC_TIME_CMD +#define WMA_OCB_START_TIMING_ADVERT_CMD SIR_HAL_OCB_START_TIMING_ADVERT_CMD +#define WMA_OCB_STOP_TIMING_ADVERT_CMD SIR_HAL_OCB_STOP_TIMING_ADVERT_CMD +#define WMA_OCB_GET_TSF_TIMER_CMD SIR_HAL_OCB_GET_TSF_TIMER_CMD +#define WMA_DCC_GET_STATS_CMD SIR_HAL_DCC_GET_STATS_CMD +#define WMA_DCC_CLEAR_STATS_CMD SIR_HAL_DCC_CLEAR_STATS_CMD +#define WMA_DCC_UPDATE_NDL_CMD SIR_HAL_DCC_UPDATE_NDL_CMD +#define WMA_SET_IE_INFO SIR_HAL_SET_IE_INFO + +#define WMA_LRO_CONFIG_CMD SIR_HAL_LRO_CONFIG_CMD +#define WMA_GW_PARAM_UPDATE_REQ SIR_HAL_GATEWAY_PARAM_UPDATE_REQ +#define WMA_SET_EGAP_CONF_PARAMS SIR_HAL_SET_EGAP_CONF_PARAMS +#define WMA_ADD_BCN_FILTER_CMDID SIR_HAL_ADD_BCN_FILTER_CMDID +#define WMA_REMOVE_BCN_FILTER_CMDID SIR_HAL_REMOVE_BCN_FILTER_CMDID +#define WMA_SET_ADAPT_DWELLTIME_CONF_PARAMS SIR_HAL_SET_ADAPT_DWELLTIME_PARAMS + +#define WDA_BPF_GET_CAPABILITIES_REQ SIR_HAL_BPF_GET_CAPABILITIES_REQ +#define WDA_BPF_SET_INSTRUCTIONS_REQ SIR_HAL_BPF_SET_INSTRUCTIONS_REQ + +#define WMA_SET_PDEV_IE_REQ SIR_HAL_SET_PDEV_IE_REQ +#define WMA_UPDATE_WEP_DEFAULT_KEY SIR_HAL_UPDATE_WEP_DEFAULT_KEY +#define WMA_SEND_FREQ_RANGE_CONTROL_IND SIR_HAL_SEND_FREQ_RANGE_CONTROL_IND +#define WMA_ENCRYPT_DECRYPT_MSG SIR_HAL_ENCRYPT_DECRYPT_MSG +#define WMA_POWER_DEBUG_STATS_REQ SIR_HAL_POWER_DEBUG_STATS_REQ +#define WMA_GET_RCPI_REQ SIR_HAL_GET_RCPI_REQ + +#define WMA_SET_WOW_PULSE_CMD SIR_HAL_SET_WOW_PULSE_CMD + +#define WDA_SET_UDP_RESP_OFFLOAD SIR_HAL_SET_UDP_RESP_OFFLOAD + +#define WMA_SET_PER_ROAM_CONFIG_CMD SIR_HAL_SET_PER_ROAM_CONFIG_CMD +#define WMA_SET_ARP_STATS_REQ SIR_HAL_SET_ARP_STATS_REQ +#define WMA_GET_ARP_STATS_REQ SIR_HAL_GET_ARP_STATS_REQ + +/* Bit 6 will be used to control BD rate for Management frames */ +#define HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME 0x40 + +#define wma_tx_frame(hHal, pFrmBuf, frmLen, frmType, txDir, tid, pCompFunc, \ + pData, txFlag, sessionid, channel_freq) \ + (QDF_STATUS)( wma_tx_packet( \ + cds_get_context(QDF_MODULE_ID_WMA), \ + (pFrmBuf), \ + (frmLen), \ + (frmType), \ + (txDir), \ + (tid), \ + (pCompFunc), \ + (pData), \ + (NULL), \ + (txFlag), \ + (sessionid), \ + (false), \ + (channel_freq))) + +#define wma_tx_frameWithTxComplete(hHal, pFrmBuf, frmLen, frmType, txDir, tid, \ + pCompFunc, pData, pCBackFnTxComp, txFlag, sessionid, tdlsflag, \ + channel_freq) \ + (QDF_STATUS)( wma_tx_packet( \ + cds_get_context(QDF_MODULE_ID_WMA), \ + (pFrmBuf), \ + (frmLen), \ + (frmType), \ + (txDir), \ + (tid), \ + (pCompFunc), \ + (pData), \ + (pCBackFnTxComp), \ + (txFlag), \ + (sessionid), \ + (tdlsflag), \ + (channel_freq))) + + +#define WMA_SetEnableSSR(enable_ssr) ((void)enable_ssr) + +/** + * struct sUapsd_Params - Powersave Offload Changes + * @bkDeliveryEnabled: BK delivery enabled flag + * @beDeliveryEnabled: BE delivery enabled flag + * @viDeliveryEnabled: VI delivery enabled flag + * @voDeliveryEnabled: VO delivery enabled flag + * @bkTriggerEnabled: BK trigger enabled flag + * @beTriggerEnabled: BE trigger enabled flag + * @viTriggerEnabled: VI trigger enabled flag + * @voTriggerEnabled: VO trigger enabled flag + */ +typedef struct sUapsd_Params { + uint8_t bkDeliveryEnabled:1; + uint8_t beDeliveryEnabled:1; + uint8_t viDeliveryEnabled:1; + uint8_t voDeliveryEnabled:1; + uint8_t bkTriggerEnabled:1; + uint8_t beTriggerEnabled:1; + uint8_t viTriggerEnabled:1; + uint8_t voTriggerEnabled:1; + bool enable_ps; +} tUapsd_Params, *tpUapsd_Params; + +/** + * struct sEnablePsParams - Enable PowerSave Params + * @psSetting: power save setting + * @uapsdParams: UAPSD Parameters + * @bssid: mac address + * @sessionid: sme session id / vdev id + * @bcnDtimPeriod: beacon DTIM Period + * @status: success/failure + */ +typedef struct sEnablePsParams { + tSirAddonPsReq psSetting; + tUapsd_Params uapsdParams; + tSirMacAddr bssid; + uint32_t sessionid; + uint8_t bcnDtimPeriod; + uint32_t status; +} tEnablePsParams, *tpEnablePsParams; + +/** + * struct sDisablePsParams - Disable PowerSave Params + * @psSetting: power save setting + * @bssid: mac address + * @sessionid: sme session id / vdev id + * @status: success/failure + */ +typedef struct sDisablePsParams { + tSirAddonPsReq psSetting; + tSirMacAddr bssid; + uint32_t sessionid; + uint32_t status; +} tDisablePsParams, *tpDisablePsParams; + +/** + * struct sEnableUapsdParams - Enable Uapsd Params + * @uapsdParams: UAPSD parameters + * @bssid: mac address + * @sessionid: sme session id/ vdev id + * @status: success/failure + */ +typedef struct sEnableUapsdParams { + tUapsd_Params uapsdParams; + tSirMacAddr bssid; + uint32_t sessionid; + uint32_t status; +} tEnableUapsdParams, *tpEnableUapsdParams; + +/** + * struct sDisableUapsdParams - Disable Uapsd Params + * @bssid: mac address + * @sessionid: sme session id/ vdev id + * @status: success/failure + */ +typedef struct sDisableUapsdParams { + tSirMacAddr bssid; + uint32_t sessionid; + uint32_t status; +} tDisableUapsdParams, *tpDisableUapsdParams; + +typedef void (*pWMATxRxCompFunc)(void *pContext, void *pData, + bool bFreeData); + +/* callback function for TX complete */ +/* parameter 1 - global pMac pointer */ +/* parameter 2 - txComplete status : 1- success, 0 - failure. */ +typedef QDF_STATUS (*pWMAAckFnTxComp)(tpAniSirGlobal, uint32_t); + +typedef void (*wma_txFailIndCallback)(uint8_t *, uint8_t); + +/* generic callback for updating parameters from target to UMAC */ +typedef void (*wma_tgt_cfg_cb)(void *context, void *param); + +/* + * callback for Indicating Radar to HDD and disable Tx Queues + * to stop accepting data Tx packets from netif as radar is + * found on the current operating channel + */ +typedef bool (*wma_dfs_radar_indication_cb)(void *context, void *param); + +/** + * struct wma_cli_set_cmd_t - set command parameters + * @param_id: parameter id + * @param_value: parameter value + * @param_sec_value: parameter sec value + * @param_vdev_id: parameter vdev id + * @param_vp_dev: is it per vdev/pdev + */ +typedef struct { + uint32_t param_id; + uint32_t param_value; + uint32_t param_sec_value; + uint32_t param_vdev_id; + uint32_t param_vp_dev; +} wma_cli_set_cmd_t; + +#if defined(QCA_WIFI_FTM) +#define AR6K_TM_DATA_MAX_LEN 5000 +struct ar6k_testmode_cmd_data { + void *data; + int len; +}; +#endif + +#ifdef FEATURE_WLAN_TDLS +/** + * enum WMA_TdlsPeerState - TDLS PEER state + * @WMA_TDLS_PEER_STATE_PEERING: peer is making connection + * @WMA_TDLS_PEER_STATE_CONNECTED: peer is connected + * @WMA_TDLS_PEER_STATE_TEARDOWN: peer is teardown + * @WMA_TDLS_PEER_ADD_MAC_ADDR: add peer into connection table + * @WMA_TDLS_PEER_REMOVE_MAC_ADDR: remove peer from connection table + */ +typedef enum { + WMA_TDLS_PEER_STATE_PEERING, + WMA_TDLS_PEER_STATE_CONNECTED, + WMA_TDLS_PEER_STATE_TEARDOWN, + WMA_TDLS_PEER_ADD_MAC_ADDR, + WMA_TDLS_PEER_REMOVE_MAC_ADDR, +} WMA_TdlsPeerState; + +/** + * enum wma_tdls_off_chan_mode - modes for WMI_TDLS_SET_OFFCHAN_MODE_CMDID + * @WMA_TDLS_ENABLE_OFFCHANNEL: enable off channel + * @WMA_TDLS_DISABLE_OFFCHANNEL: disable off channel + */ +typedef enum { + WMA_TDLS_ENABLE_OFFCHANNEL, + WMA_TDLS_DISABLE_OFFCHANNEL +} wma_tdls_off_chan_mode; + +#endif /* FEATURE_WLAN_TDLS */ + +tSirRetStatus wma_post_ctrl_msg(tpAniSirGlobal pMac, tSirMsgQ *pMsg); + +tSirRetStatus u_mac_post_ctrl_msg(void *pSirGlobal, tSirMbMsg *pMb); + +QDF_STATUS wma_set_idle_ps_config(void *wma_ptr, uint32_t idle_ps); +QDF_STATUS wma_get_snr(tAniGetSnrReq *psnr_req); + +QDF_STATUS +wma_ds_peek_rx_packet_info + (cds_pkt_t *vosDataBuff, void **ppRxHeader, bool bSwap); + + +void wma_tx_abort(uint8_t vdev_id); + +QDF_STATUS wma_tx_packet(void *pWMA, + void *pFrmBuf, + uint16_t frmLen, + eFrameType frmType, + eFrameTxDir txDir, + uint8_t tid, + pWMATxRxCompFunc pCompFunc, + void *pData, + pWMAAckFnTxComp pAckTxComp, + uint8_t txFlag, uint8_t sessionId, bool tdlsflag, + uint16_t channel_freq); + +QDF_STATUS wma_open(void *p_cds_context, + wma_tgt_cfg_cb pTgtUpdCB, + wma_dfs_radar_indication_cb radar_ind_cb, + struct cds_config_info *cds_cfg); + +typedef QDF_STATUS (*wma_mgmt_frame_rx_callback)(void *p_cds_gctx, + void *cds_buff); + +QDF_STATUS wma_register_mgmt_frm_client(void *p_cds_gctx, + wma_mgmt_frame_rx_callback mgmt_rx_cb); + +QDF_STATUS wma_de_register_mgmt_frm_client(void *p_cds_gctx); +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +QDF_STATUS wma_register_roaming_callbacks(void *cds_ctx, + QDF_STATUS (*csr_roam_synch_cb)(tpAniSirGlobal mac, + roam_offload_synch_ind *roam_synch_data, + tpSirBssDescription bss_desc_ptr, + enum sir_roam_op_code reason), + QDF_STATUS (*pe_roam_synch_cb)(tpAniSirGlobal mac, + roam_offload_synch_ind *roam_synch_data, + tpSirBssDescription bss_desc_ptr)); +#else +static inline QDF_STATUS wma_register_roaming_callbacks(void *cds_ctx, + QDF_STATUS (*csr_roam_synch_cb)(tpAniSirGlobal mac, + roam_offload_synch_ind *roam_synch_data, + tpSirBssDescription bss_desc_ptr, + enum sir_roam_op_code reason), + QDF_STATUS (*pe_roam_synch_cb)(tpAniSirGlobal mac, + roam_offload_synch_ind *roam_synch_data, + tpSirBssDescription bss_desc_ptr)) +{ + return QDF_STATUS_E_NOSUPPORT; +} +#endif + +#endif diff --git a/drivers/staging/qcacld-3.0/core/wma/src/wlan_qct_wma_legacy.c b/drivers/staging/qcacld-3.0/core/wma/src/wlan_qct_wma_legacy.c new file mode 100644 index 0000000000000000000000000000000000000000..6e6fcf8f0fcfb842a05b9228da58b7e5a7dcbe82 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/wma/src/wlan_qct_wma_legacy.c @@ -0,0 +1,150 @@ +/* + * Copyright (c) 2013-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: wlan_qct_wma_legacy.c + * + * This software unit holds the implementation of the WLAN Device Adaptation + * Layer for the legacy functionalities that were part of the old HAL. + * + * The functions externalized by this module are to be called ONLY by other + * WLAN modules that properly register with the Transport Layer initially. + * + */ + +/* Standard include files */ +/* Application Specific include files */ +#include "lim_api.h" +#include "cfg_api.h" +#include "wma.h" +#include "sme_power_save_api.h" +/* Locally used Defines */ + +#define HAL_MMH_MB_MSG_TYPE_MASK 0xFF00 + +/** + * wma_post_ctrl_msg() - Posts WMA messages to MC thread + * @pMac: MAC parameters structure + * @pMsg: pointer with message + * + * Return: Success or Failure + */ + +tSirRetStatus wma_post_ctrl_msg(tpAniSirGlobal pMac, tSirMsgQ *pMsg) +{ + if (QDF_STATUS_SUCCESS != + cds_mq_post_message(CDS_MQ_ID_WMA, (cds_msg_t *) pMsg)) + return eSIR_FAILURE; + else + return eSIR_SUCCESS; +} + +/** + * wma_post_cfg_msg() - Posts MNT messages to gSirMntMsgQ + * @pMac: MAC parameters structure + * @pMsg: A pointer to the msg + * + * Return: Success or Failure + */ + +static tSirRetStatus wma_post_cfg_msg(tpAniSirGlobal pMac, tSirMsgQ *pMsg) +{ + tSirRetStatus rc = eSIR_SUCCESS; + + do { + /* + *For Windows based MAC, instead of posting message to different + * queues we will call the handler routines directly + */ + + cfg_process_mb_msg(pMac, (tSirMbMsg *) pMsg->bodyptr); + rc = eSIR_SUCCESS; + } while (0); + + return rc; +} + +/** + * u_mac_post_ctrl_msg() - post ctrl msg + * @pMb: A pointer to the maibox message + * + * Forwards the completely received message to the respective + * modules for further processing. + * + * NOTE: + * This function has been moved to the API file because for MAC running + * on Windows host, the host module will call this routine directly to + * send any mailbox messages. Making this function an API makes sure that + * outside world (any module outside MMH) only calls APIs to use MMH + * services and not an internal function. + * + * Return: success/error code + */ + +tSirRetStatus u_mac_post_ctrl_msg(void *pSirGlobal, tSirMbMsg *pMb) +{ + tSirMsgQ msg; + tSirRetStatus status = eSIR_SUCCESS; + tpAniSirGlobal pMac = (tpAniSirGlobal) pSirGlobal; + + msg.type = pMb->type; + msg.bodyval = 0; + msg.bodyptr = pMb; + + switch (msg.type & HAL_MMH_MB_MSG_TYPE_MASK) { + case WMA_MSG_TYPES_BEGIN: /* Posts a message to the HAL MsgQ */ + status = wma_post_ctrl_msg(pMac, &msg); + break; + + case SIR_LIM_MSG_TYPES_BEGIN: /* Posts a message to the LIM MsgQ */ + status = lim_post_msg_api(pMac, &msg); + break; + + case SIR_CFG_MSG_TYPES_BEGIN: /* Posts a message to the CFG MsgQ */ + status = wma_post_cfg_msg(pMac, &msg); + break; + + case SIR_PMM_MSG_TYPES_BEGIN: /* Posts a message to the LIM MsgQ */ + status = sme_post_pe_message(pMac, &msg); + break; + + case SIR_PTT_MSG_TYPES_BEGIN: + qdf_mem_free(msg.bodyptr); + break; + + default: + WMA_LOGD("Unknown message type = 0x%X\n", msg.type); + qdf_mem_free(msg.bodyptr); + return eSIR_FAILURE; + } + + if (status != eSIR_SUCCESS) + qdf_mem_free(msg.bodyptr); + + return status; + +} /* u_mac_post_ctrl_msg() */ diff --git a/drivers/staging/qcacld-3.0/core/wma/src/wma_data.c b/drivers/staging/qcacld-3.0/core/wma/src/wma_data.c new file mode 100644 index 0000000000000000000000000000000000000000..daee5591821b717b8c356ba93eb0a58915be5dd0 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/wma/src/wma_data.c @@ -0,0 +1,3245 @@ +/* + * Copyright (c) 2013-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: wma_data.c + * This file contains tx/rx and data path related functions. + */ + +/* Header files */ + +#include "wma.h" +#include "wma_api.h" +#include "cds_api.h" +#include "wmi_unified_api.h" +#include "wlan_qct_sys.h" +#include "wni_api.h" +#include "ani_global.h" +#include "wmi_unified.h" +#include "wni_cfg.h" +#include "cfg_api.h" +#include "ol_txrx_ctrl_api.h" +#include +#if defined(CONFIG_HL_SUPPORT) +#include "wlan_tgt_def_config_hl.h" +#else +#include "wlan_tgt_def_config.h" +#endif +#include "ol_txrx.h" +#include "qdf_nbuf.h" +#include "qdf_types.h" +#include "qdf_mem.h" +#include "ol_txrx_peer_find.h" + +#include "wma_types.h" +#include "lim_api.h" +#include "lim_session_utils.h" + +#include "cds_utils.h" + +#if !defined(REMOVE_PKT_LOG) +#include "pktlog_ac.h" +#endif /* REMOVE_PKT_LOG */ + +#include "dbglog_host.h" +#include "csr_api.h" +#include "ol_fw.h" + +#include "dfs.h" +#include "wma_internal.h" +#include "cdp_txrx_flow_ctrl_legacy.h" +#include "cdp_txrx_cmn.h" +#include "cdp_txrx_misc.h" +#include +#include +#include "cdp_txrx_stats.h" +#include "ol_ctrl_txrx_api.h" + +typedef struct { + int32_t rate; + uint8_t flag; +} wma_search_rate_t; + +#define WMA_MAX_OFDM_CCK_RATE_TBL_SIZE 12 +/* In ofdm_cck_rate_tbl->flag, if bit 7 is 1 it's CCK, otherwise it ofdm. + * Lower bit carries the ofdm/cck index for encoding the rate + */ +static wma_search_rate_t ofdm_cck_rate_tbl[WMA_MAX_OFDM_CCK_RATE_TBL_SIZE] = { + {540, 4}, /* 4: OFDM 54 Mbps */ + {480, 0}, /* 0: OFDM 48 Mbps */ + {360, 5}, /* 5: OFDM 36 Mbps */ + {240, 1}, /* 1: OFDM 24 Mbps */ + {180, 6}, /* 6: OFDM 18 Mbps */ + {120, 2}, /* 2: OFDM 12 Mbps */ + {110, (1 << 7)}, /* 0: CCK 11 Mbps Long */ + {90, 7}, /* 7: OFDM 9 Mbps */ + {60, 3}, /* 3: OFDM 6 Mbps */ + {55, ((1 << 7) | 1)}, /* 1: CCK 5.5 Mbps Long */ + {20, ((1 << 7) | 2)}, /* 2: CCK 2 Mbps Long */ + {10, ((1 << 7) | 3)} /* 3: CCK 1 Mbps Long */ +}; + +#define WMA_MAX_VHT20_RATE_TBL_SIZE 9 +/* In vht20_400ns_rate_tbl flag carries the mcs index for encoding the rate */ +static wma_search_rate_t vht20_400ns_rate_tbl[WMA_MAX_VHT20_RATE_TBL_SIZE] = { + {867, 8}, /* MCS8 1SS short GI */ + {722, 7}, /* MCS7 1SS short GI */ + {650, 6}, /* MCS6 1SS short GI */ + {578, 5}, /* MCS5 1SS short GI */ + {433, 4}, /* MCS4 1SS short GI */ + {289, 3}, /* MCS3 1SS short GI */ + {217, 2}, /* MCS2 1SS short GI */ + {144, 1}, /* MCS1 1SS short GI */ + {72, 0} /* MCS0 1SS short GI */ +}; + +/* In vht20_800ns_rate_tbl flag carries the mcs index for encoding the rate */ +static wma_search_rate_t vht20_800ns_rate_tbl[WMA_MAX_VHT20_RATE_TBL_SIZE] = { + {780, 8}, /* MCS8 1SS long GI */ + {650, 7}, /* MCS7 1SS long GI */ + {585, 6}, /* MCS6 1SS long GI */ + {520, 5}, /* MCS5 1SS long GI */ + {390, 4}, /* MCS4 1SS long GI */ + {260, 3}, /* MCS3 1SS long GI */ + {195, 2}, /* MCS2 1SS long GI */ + {130, 1}, /* MCS1 1SS long GI */ + {65, 0} /* MCS0 1SS long GI */ +}; + +#define WMA_MAX_VHT40_RATE_TBL_SIZE 10 +/* In vht40_400ns_rate_tbl flag carries the mcs index for encoding the rate */ +static wma_search_rate_t vht40_400ns_rate_tbl[WMA_MAX_VHT40_RATE_TBL_SIZE] = { + {2000, 9}, /* MCS9 1SS short GI */ + {1800, 8}, /* MCS8 1SS short GI */ + {1500, 7}, /* MCS7 1SS short GI */ + {1350, 6}, /* MCS6 1SS short GI */ + {1200, 5}, /* MCS5 1SS short GI */ + {900, 4}, /* MCS4 1SS short GI */ + {600, 3}, /* MCS3 1SS short GI */ + {450, 2}, /* MCS2 1SS short GI */ + {300, 1}, /* MCS1 1SS short GI */ + {150, 0}, /* MCS0 1SS short GI */ +}; + +static wma_search_rate_t vht40_800ns_rate_tbl[WMA_MAX_VHT40_RATE_TBL_SIZE] = { + {1800, 9}, /* MCS9 1SS long GI */ + {1620, 8}, /* MCS8 1SS long GI */ + {1350, 7}, /* MCS7 1SS long GI */ + {1215, 6}, /* MCS6 1SS long GI */ + {1080, 5}, /* MCS5 1SS long GI */ + {810, 4}, /* MCS4 1SS long GI */ + {540, 3}, /* MCS3 1SS long GI */ + {405, 2}, /* MCS2 1SS long GI */ + {270, 1}, /* MCS1 1SS long GI */ + {135, 0} /* MCS0 1SS long GI */ +}; + +#define WMA_MAX_VHT80_RATE_TBL_SIZE 10 +static wma_search_rate_t vht80_400ns_rate_tbl[WMA_MAX_VHT80_RATE_TBL_SIZE] = { + {4333, 9}, /* MCS9 1SS short GI */ + {3900, 8}, /* MCS8 1SS short GI */ + {3250, 7}, /* MCS7 1SS short GI */ + {2925, 6}, /* MCS6 1SS short GI */ + {2600, 5}, /* MCS5 1SS short GI */ + {1950, 4}, /* MCS4 1SS short GI */ + {1300, 3}, /* MCS3 1SS short GI */ + {975, 2}, /* MCS2 1SS short GI */ + {650, 1}, /* MCS1 1SS short GI */ + {325, 0} /* MCS0 1SS short GI */ +}; + +static wma_search_rate_t vht80_800ns_rate_tbl[WMA_MAX_VHT80_RATE_TBL_SIZE] = { + {3900, 9}, /* MCS9 1SS long GI */ + {3510, 8}, /* MCS8 1SS long GI */ + {2925, 7}, /* MCS7 1SS long GI */ + {2633, 6}, /* MCS6 1SS long GI */ + {2340, 5}, /* MCS5 1SS long GI */ + {1755, 4}, /* MCS4 1SS long GI */ + {1170, 3}, /* MCS3 1SS long GI */ + {878, 2}, /* MCS2 1SS long GI */ + {585, 1}, /* MCS1 1SS long GI */ + {293, 0} /* MCS0 1SS long GI */ +}; + +#define WMA_MAX_HT20_RATE_TBL_SIZE 8 +static wma_search_rate_t ht20_400ns_rate_tbl[WMA_MAX_HT20_RATE_TBL_SIZE] = { + {722, 7}, /* MCS7 1SS short GI */ + {650, 6}, /* MCS6 1SS short GI */ + {578, 5}, /* MCS5 1SS short GI */ + {433, 4}, /* MCS4 1SS short GI */ + {289, 3}, /* MCS3 1SS short GI */ + {217, 2}, /* MCS2 1SS short GI */ + {144, 1}, /* MCS1 1SS short GI */ + {72, 0} /* MCS0 1SS short GI */ +}; + +static wma_search_rate_t ht20_800ns_rate_tbl[WMA_MAX_HT20_RATE_TBL_SIZE] = { + {650, 7}, /* MCS7 1SS long GI */ + {585, 6}, /* MCS6 1SS long GI */ + {520, 5}, /* MCS5 1SS long GI */ + {390, 4}, /* MCS4 1SS long GI */ + {260, 3}, /* MCS3 1SS long GI */ + {195, 2}, /* MCS2 1SS long GI */ + {130, 1}, /* MCS1 1SS long GI */ + {65, 0} /* MCS0 1SS long GI */ +}; + +#define WMA_MAX_HT40_RATE_TBL_SIZE 8 +static wma_search_rate_t ht40_400ns_rate_tbl[WMA_MAX_HT40_RATE_TBL_SIZE] = { + {1500, 7}, /* MCS7 1SS short GI */ + {1350, 6}, /* MCS6 1SS short GI */ + {1200, 5}, /* MCS5 1SS short GI */ + {900, 4}, /* MCS4 1SS short GI */ + {600, 3}, /* MCS3 1SS short GI */ + {450, 2}, /* MCS2 1SS short GI */ + {300, 1}, /* MCS1 1SS short GI */ + {150, 0} /* MCS0 1SS short GI */ +}; + +static wma_search_rate_t ht40_800ns_rate_tbl[WMA_MAX_HT40_RATE_TBL_SIZE] = { + {1350, 7}, /* MCS7 1SS long GI */ + {1215, 6}, /* MCS6 1SS long GI */ + {1080, 5}, /* MCS5 1SS long GI */ + {810, 4}, /* MCS4 1SS long GI */ + {540, 3}, /* MCS3 1SS long GI */ + {405, 2}, /* MCS2 1SS long GI */ + {270, 1}, /* MCS1 1SS long GI */ + {135, 0} /* MCS0 1SS long GI */ +}; + +/** + * wma_bin_search_rate() - binary search function to find rate + * @tbl: rate table + * @tbl_size: table size + * @mbpsx10_rate: return mbps rate + * @ret_flag: return flag + * + * Return: none + */ +static void wma_bin_search_rate(wma_search_rate_t *tbl, int32_t tbl_size, + int32_t *mbpsx10_rate, uint8_t *ret_flag) +{ + int32_t upper, lower, mid; + + /* the table is descenting. index holds the largest value and the + * bottom index holds the smallest value */ + + upper = 0; /* index 0 */ + lower = tbl_size - 1; /* last index */ + + if (*mbpsx10_rate >= tbl[upper].rate) { + /* use the largest rate */ + *mbpsx10_rate = tbl[upper].rate; + *ret_flag = tbl[upper].flag; + return; + } else if (*mbpsx10_rate <= tbl[lower].rate) { + /* use the smallest rate */ + *mbpsx10_rate = tbl[lower].rate; + *ret_flag = tbl[lower].flag; + return; + } + /* now we do binery search to get the floor value */ + while (lower - upper > 1) { + mid = (upper + lower) >> 1; + if (*mbpsx10_rate == tbl[mid].rate) { + /* found the exact match */ + *mbpsx10_rate = tbl[mid].rate; + *ret_flag = tbl[mid].flag; + return; + } else { + /* not found. if mid's rate is larger than input move + * upper to mid. If mid's rate is larger than input + * move lower to mid. + */ + if (*mbpsx10_rate > tbl[mid].rate) + lower = mid; + else + upper = mid; + } + } + /* after the bin search the index is the ceiling of rate */ + *mbpsx10_rate = tbl[upper].rate; + *ret_flag = tbl[upper].flag; + return; +} + +/** + * wma_fill_ofdm_cck_mcast_rate() - fill ofdm cck mcast rate + * @mbpsx10_rate: mbps rates + * @nss: nss + * @rate: rate + * + * Return: QDF status + */ +static QDF_STATUS wma_fill_ofdm_cck_mcast_rate(int32_t mbpsx10_rate, + uint8_t nss, uint8_t *rate) +{ + uint8_t idx = 0; + wma_bin_search_rate(ofdm_cck_rate_tbl, WMA_MAX_OFDM_CCK_RATE_TBL_SIZE, + &mbpsx10_rate, &idx); + + /* if bit 7 is set it uses CCK */ + if (idx & 0x80) + *rate |= (1 << 6) | (idx & 0xF); /* set bit 6 to 1 for CCK */ + else + *rate |= (idx & 0xF); + return QDF_STATUS_SUCCESS; +} + +/** + * wma_set_ht_vht_mcast_rate() - set ht/vht mcast rate + * @shortgi: short gaurd interval + * @mbpsx10_rate: mbps rates + * @sgi_idx: shortgi index + * @sgi_rate: shortgi rate + * @lgi_idx: longgi index + * @lgi_rate: longgi rate + * @premable: preamble + * @rate: rate + * @streaming_rate: streaming rate + * + * Return: none + */ +static void wma_set_ht_vht_mcast_rate(uint32_t shortgi, int32_t mbpsx10_rate, + uint8_t sgi_idx, int32_t sgi_rate, + uint8_t lgi_idx, int32_t lgi_rate, + uint8_t premable, uint8_t *rate, + int32_t *streaming_rate) +{ + if (shortgi == 0) { + *rate |= (premable << 6) | (lgi_idx & 0xF); + *streaming_rate = lgi_rate; + } else { + *rate |= (premable << 6) | (sgi_idx & 0xF); + *streaming_rate = sgi_rate; + } +} + +/** + * wma_fill_ht20_mcast_rate() - fill ht20 mcast rate + * @shortgi: short gaurd interval + * @mbpsx10_rate: mbps rates + * @nss: nss + * @rate: rate + * @streaming_rate: streaming rate + * + * Return: QDF status + */ +static QDF_STATUS wma_fill_ht20_mcast_rate(uint32_t shortgi, + int32_t mbpsx10_rate, uint8_t nss, + uint8_t *rate, + int32_t *streaming_rate) +{ + uint8_t sgi_idx = 0, lgi_idx = 0; + int32_t sgi_rate, lgi_rate; + if (nss == 1) + mbpsx10_rate = mbpsx10_rate >> 1; + + sgi_rate = mbpsx10_rate; + lgi_rate = mbpsx10_rate; + if (shortgi) + wma_bin_search_rate(ht20_400ns_rate_tbl, + WMA_MAX_HT20_RATE_TBL_SIZE, &sgi_rate, + &sgi_idx); + else + wma_bin_search_rate(ht20_800ns_rate_tbl, + WMA_MAX_HT20_RATE_TBL_SIZE, &lgi_rate, + &lgi_idx); + + wma_set_ht_vht_mcast_rate(shortgi, mbpsx10_rate, sgi_idx, sgi_rate, + lgi_idx, lgi_rate, 2, rate, streaming_rate); + if (nss == 1) + *streaming_rate = *streaming_rate << 1; + return QDF_STATUS_SUCCESS; +} + +/** + * wma_fill_ht40_mcast_rate() - fill ht40 mcast rate + * @shortgi: short gaurd interval + * @mbpsx10_rate: mbps rates + * @nss: nss + * @rate: rate + * @streaming_rate: streaming rate + * + * Return: QDF status + */ +static QDF_STATUS wma_fill_ht40_mcast_rate(uint32_t shortgi, + int32_t mbpsx10_rate, uint8_t nss, + uint8_t *rate, + int32_t *streaming_rate) +{ + uint8_t sgi_idx = 0, lgi_idx = 0; + int32_t sgi_rate, lgi_rate; + + /* for 2x2 divide the rate by 2 */ + if (nss == 1) + mbpsx10_rate = mbpsx10_rate >> 1; + + sgi_rate = mbpsx10_rate; + lgi_rate = mbpsx10_rate; + if (shortgi) + wma_bin_search_rate(ht40_400ns_rate_tbl, + WMA_MAX_HT40_RATE_TBL_SIZE, &sgi_rate, + &sgi_idx); + else + wma_bin_search_rate(ht40_800ns_rate_tbl, + WMA_MAX_HT40_RATE_TBL_SIZE, &lgi_rate, + &lgi_idx); + + wma_set_ht_vht_mcast_rate(shortgi, mbpsx10_rate, sgi_idx, sgi_rate, + lgi_idx, lgi_rate, 2, rate, streaming_rate); + + return QDF_STATUS_SUCCESS; +} + +/** + * wma_fill_vht20_mcast_rate() - fill vht20 mcast rate + * @shortgi: short gaurd interval + * @mbpsx10_rate: mbps rates + * @nss: nss + * @rate: rate + * @streaming_rate: streaming rate + * + * Return: QDF status + */ +static QDF_STATUS wma_fill_vht20_mcast_rate(uint32_t shortgi, + int32_t mbpsx10_rate, uint8_t nss, + uint8_t *rate, + int32_t *streaming_rate) +{ + uint8_t sgi_idx = 0, lgi_idx = 0; + int32_t sgi_rate, lgi_rate; + + /* for 2x2 divide the rate by 2 */ + if (nss == 1) + mbpsx10_rate = mbpsx10_rate >> 1; + + sgi_rate = mbpsx10_rate; + lgi_rate = mbpsx10_rate; + if (shortgi) + wma_bin_search_rate(vht20_400ns_rate_tbl, + WMA_MAX_VHT20_RATE_TBL_SIZE, &sgi_rate, + &sgi_idx); + else + wma_bin_search_rate(vht20_800ns_rate_tbl, + WMA_MAX_VHT20_RATE_TBL_SIZE, &lgi_rate, + &lgi_idx); + + wma_set_ht_vht_mcast_rate(shortgi, mbpsx10_rate, sgi_idx, sgi_rate, + lgi_idx, lgi_rate, 3, rate, streaming_rate); + if (nss == 1) + *streaming_rate = *streaming_rate << 1; + return QDF_STATUS_SUCCESS; +} + +/** + * wma_fill_vht40_mcast_rate() - fill vht40 mcast rate + * @shortgi: short gaurd interval + * @mbpsx10_rate: mbps rates + * @nss: nss + * @rate: rate + * @streaming_rate: streaming rate + * + * Return: QDF status + */ +static QDF_STATUS wma_fill_vht40_mcast_rate(uint32_t shortgi, + int32_t mbpsx10_rate, uint8_t nss, + uint8_t *rate, + int32_t *streaming_rate) +{ + uint8_t sgi_idx = 0, lgi_idx = 0; + int32_t sgi_rate, lgi_rate; + + /* for 2x2 divide the rate by 2 */ + if (nss == 1) + mbpsx10_rate = mbpsx10_rate >> 1; + + sgi_rate = mbpsx10_rate; + lgi_rate = mbpsx10_rate; + if (shortgi) + wma_bin_search_rate(vht40_400ns_rate_tbl, + WMA_MAX_VHT40_RATE_TBL_SIZE, &sgi_rate, + &sgi_idx); + else + wma_bin_search_rate(vht40_800ns_rate_tbl, + WMA_MAX_VHT40_RATE_TBL_SIZE, &lgi_rate, + &lgi_idx); + + wma_set_ht_vht_mcast_rate(shortgi, mbpsx10_rate, + sgi_idx, sgi_rate, lgi_idx, lgi_rate, + 3, rate, streaming_rate); + if (nss == 1) + *streaming_rate = *streaming_rate << 1; + return QDF_STATUS_SUCCESS; +} + +/** + * wma_fill_vht80_mcast_rate() - fill vht80 mcast rate + * @shortgi: short gaurd interval + * @mbpsx10_rate: mbps rates + * @nss: nss + * @rate: rate + * @streaming_rate: streaming rate + * + * Return: QDF status + */ +static QDF_STATUS wma_fill_vht80_mcast_rate(uint32_t shortgi, + int32_t mbpsx10_rate, uint8_t nss, + uint8_t *rate, + int32_t *streaming_rate) +{ + uint8_t sgi_idx = 0, lgi_idx = 0; + int32_t sgi_rate, lgi_rate; + + /* for 2x2 divide the rate by 2 */ + if (nss == 1) + mbpsx10_rate = mbpsx10_rate >> 1; + + sgi_rate = mbpsx10_rate; + lgi_rate = mbpsx10_rate; + if (shortgi) + wma_bin_search_rate(vht80_400ns_rate_tbl, + WMA_MAX_VHT80_RATE_TBL_SIZE, &sgi_rate, + &sgi_idx); + else + wma_bin_search_rate(vht80_800ns_rate_tbl, + WMA_MAX_VHT80_RATE_TBL_SIZE, &lgi_rate, + &lgi_idx); + + wma_set_ht_vht_mcast_rate(shortgi, mbpsx10_rate, sgi_idx, sgi_rate, + lgi_idx, lgi_rate, 3, rate, streaming_rate); + if (nss == 1) + *streaming_rate = *streaming_rate << 1; + return QDF_STATUS_SUCCESS; +} + +/** + * wma_fill_ht_mcast_rate() - fill ht mcast rate + * @shortgi: short gaurd interval + * @chwidth: channel width + * @chanmode: channel mode + * @mhz: frequency + * @mbpsx10_rate: mbps rates + * @nss: nss + * @rate: rate + * @streaming_rate: streaming rate + * + * Return: QDF status + */ +static QDF_STATUS wma_fill_ht_mcast_rate(uint32_t shortgi, + uint32_t chwidth, int32_t mbpsx10_rate, + uint8_t nss, WLAN_PHY_MODE chanmode, + uint8_t *rate, + int32_t *streaming_rate) +{ + int32_t ret = 0; + + *streaming_rate = 0; + if (chwidth == 0) + ret = wma_fill_ht20_mcast_rate(shortgi, mbpsx10_rate, + nss, rate, streaming_rate); + else if (chwidth == 1) + ret = wma_fill_ht40_mcast_rate(shortgi, mbpsx10_rate, + nss, rate, streaming_rate); + else + WMA_LOGE("%s: Error, Invalid chwidth enum %d", __func__, + chwidth); + return (*streaming_rate != 0) ? QDF_STATUS_SUCCESS : QDF_STATUS_E_INVAL; +} + +/** + * wma_fill_vht_mcast_rate() - fill vht mcast rate + * @shortgi: short gaurd interval + * @chwidth: channel width + * @chanmode: channel mode + * @mhz: frequency + * @mbpsx10_rate: mbps rates + * @nss: nss + * @rate: rate + * @streaming_rate: streaming rate + * + * Return: QDF status + */ +static QDF_STATUS wma_fill_vht_mcast_rate(uint32_t shortgi, + uint32_t chwidth, + int32_t mbpsx10_rate, uint8_t nss, + WLAN_PHY_MODE chanmode, + uint8_t *rate, + int32_t *streaming_rate) +{ + int32_t ret = 0; + + *streaming_rate = 0; + if (chwidth == 0) + ret = wma_fill_vht20_mcast_rate(shortgi, mbpsx10_rate, nss, + rate, streaming_rate); + else if (chwidth == 1) + ret = wma_fill_vht40_mcast_rate(shortgi, mbpsx10_rate, nss, + rate, streaming_rate); + else if (chwidth == 2) + ret = wma_fill_vht80_mcast_rate(shortgi, mbpsx10_rate, nss, + rate, streaming_rate); + else + WMA_LOGE("%s: chwidth enum %d not supported", + __func__, chwidth); + return (*streaming_rate != 0) ? QDF_STATUS_SUCCESS : QDF_STATUS_E_INVAL; +} + +#define WMA_MCAST_1X1_CUT_OFF_RATE 2000 +/** + * wma_encode_mc_rate() - fill mc rates + * @shortgi: short gaurd interval + * @chwidth: channel width + * @chanmode: channel mode + * @mhz: frequency + * @mbpsx10_rate: mbps rates + * @nss: nss + * @rate: rate + * + * Return: QDF status + */ +static QDF_STATUS wma_encode_mc_rate(uint32_t shortgi, uint32_t chwidth, + WLAN_PHY_MODE chanmode, A_UINT32 mhz, + int32_t mbpsx10_rate, uint8_t nss, + uint8_t *rate) +{ + int32_t ret = 0; + + /* nss input value: 0 - 1x1; 1 - 2x2; 2 - 3x3 + * the phymode selection is based on following assumption: + * (1) if the app specifically requested 1x1 or 2x2 we hornor it + * (2) if mbpsx10_rate <= 540: always use BG + * (3) 540 < mbpsx10_rate <= 2000: use 1x1 HT/VHT + * (4) 2000 < mbpsx10_rate: use 2x2 HT/VHT + */ + WMA_LOGE("%s: Input: nss = %d, chanmode = %d, " + "mbpsx10 = 0x%x, chwidth = %d, shortgi = %d", + __func__, nss, chanmode, mbpsx10_rate, chwidth, shortgi); + if ((mbpsx10_rate & 0x40000000) && nss > 0) { + /* bit 30 indicates user inputed nss, + * bit 28 and 29 used to encode nss + */ + uint8_t user_nss = (mbpsx10_rate & 0x30000000) >> 28; + + nss = (user_nss < nss) ? user_nss : nss; + /* zero out bits 19 - 21 to recover the actual rate */ + mbpsx10_rate &= ~0x70000000; + } else if (mbpsx10_rate <= WMA_MCAST_1X1_CUT_OFF_RATE) { + /* if the input rate is less or equal to the + * 1x1 cutoff rate we use 1x1 only + */ + nss = 0; + } + /* encode NSS bits (bit 4, bit 5) */ + *rate = (nss & 0x3) << 4; + /* if mcast input rate exceeds the ofdm/cck max rate 54mpbs + * we try to choose best ht/vht mcs rate + */ + if (540 < mbpsx10_rate) { + /* cannot use ofdm/cck, choose closest ht/vht mcs rate */ + uint8_t rate_ht = *rate; + uint8_t rate_vht = *rate; + int32_t stream_rate_ht = 0; + int32_t stream_rate_vht = 0; + int32_t stream_rate = 0; + + ret = wma_fill_ht_mcast_rate(shortgi, chwidth, mbpsx10_rate, + nss, chanmode, &rate_ht, + &stream_rate_ht); + if (ret != QDF_STATUS_SUCCESS) { + stream_rate_ht = 0; + } + if (mhz < WMA_2_4_GHZ_MAX_FREQ) { + /* not in 5 GHZ frequency */ + *rate = rate_ht; + stream_rate = stream_rate_ht; + goto ht_vht_done; + } + /* capable doing 11AC mcast so that search vht tables */ + ret = wma_fill_vht_mcast_rate(shortgi, chwidth, mbpsx10_rate, + nss, chanmode, &rate_vht, + &stream_rate_vht); + if (ret != QDF_STATUS_SUCCESS) { + if (stream_rate_ht != 0) + ret = QDF_STATUS_SUCCESS; + *rate = rate_ht; + stream_rate = stream_rate_ht; + goto ht_vht_done; + } + if (stream_rate_ht == 0) { + /* only vht rate available */ + *rate = rate_vht; + stream_rate = stream_rate_vht; + } else { + /* set ht as default first */ + *rate = rate_ht; + stream_rate = stream_rate_ht; + if (stream_rate < mbpsx10_rate) { + if (mbpsx10_rate <= stream_rate_vht || + stream_rate < stream_rate_vht) { + *rate = rate_vht; + stream_rate = stream_rate_vht; + } + } else { + if (stream_rate_vht >= mbpsx10_rate && + stream_rate_vht < stream_rate) { + *rate = rate_vht; + stream_rate = stream_rate_vht; + } + } + } +ht_vht_done: + WMA_LOGE("%s: NSS = %d, ucast_chanmode = %d, " + "freq = %d, input_rate = %d, chwidth = %d " + "rate = 0x%x, streaming_rate = %d", + __func__, nss, chanmode, mhz, + mbpsx10_rate, chwidth, *rate, stream_rate); + } else { + if (mbpsx10_rate > 0) + ret = wma_fill_ofdm_cck_mcast_rate(mbpsx10_rate, + nss, rate); + else + *rate = 0xFF; + + WMA_LOGE("%s: NSS = %d, ucast_chanmode = %d, " + "input_rate = %d, rate = 0x%x", + __func__, nss, chanmode, mbpsx10_rate, *rate); + } + return ret; +} + +/** + * wma_set_bss_rate_flags() - set rate flags based on BSS capability + * @iface: txrx_node ctx + * @add_bss: add_bss params + * + * Return: none + */ +void wma_set_bss_rate_flags(struct wma_txrx_node *iface, + tpAddBssParams add_bss) +{ + iface->rate_flags = 0; + + if (add_bss->vhtCapable) { + if (add_bss->ch_width == CH_WIDTH_80P80MHZ) + iface->rate_flags |= eHAL_TX_RATE_VHT80; + if (add_bss->ch_width == CH_WIDTH_160MHZ) + iface->rate_flags |= eHAL_TX_RATE_VHT80; + if (add_bss->ch_width == CH_WIDTH_80MHZ) + iface->rate_flags |= eHAL_TX_RATE_VHT80; + else if (add_bss->ch_width) + iface->rate_flags |= eHAL_TX_RATE_VHT40; + else + iface->rate_flags |= eHAL_TX_RATE_VHT20; + } + /* avoid to conflict with htCapable flag */ + else if (add_bss->htCapable) { + if (add_bss->ch_width) + iface->rate_flags |= eHAL_TX_RATE_HT40; + else + iface->rate_flags |= eHAL_TX_RATE_HT20; + } + + if (add_bss->staContext.fShortGI20Mhz || + add_bss->staContext.fShortGI40Mhz) + iface->rate_flags |= eHAL_TX_RATE_SGI; + + if (!add_bss->htCapable && !add_bss->vhtCapable) + iface->rate_flags = eHAL_TX_RATE_LEGACY; +} + +/** + * wmi_unified_send_txbf() - set txbf parameter to fw + * @wma: wma handle + * @params: txbf parameters + * + * Return: 0 for success or error code + */ +int32_t wmi_unified_send_txbf(tp_wma_handle wma, tpAddStaParams params) +{ + wmi_vdev_txbf_en txbf_en = {0}; + + /* This is set when Other partner is Bformer + * and we are capable bformee(enabled both in ini and fw) + */ + txbf_en.sutxbfee = params->vhtTxBFCapable; + txbf_en.mutxbfee = params->vhtTxMUBformeeCapable; + txbf_en.sutxbfer = params->enable_su_tx_bformer; + + /* When MU TxBfee is set, SU TxBfee must be set by default */ + if (txbf_en.mutxbfee) + txbf_en.sutxbfee = txbf_en.mutxbfee; + + WMA_LOGD("txbf_en.sutxbfee %d txbf_en.mutxbfee %d, sutxbfer %d", + txbf_en.sutxbfee, txbf_en.mutxbfee, txbf_en.sutxbfer); + + return wma_vdev_set_param(wma->wmi_handle, + params->smesessionId, + WMI_VDEV_PARAM_TXBF, + *((A_UINT8 *) &txbf_en)); +} + +/** + * wma_data_tx_ack_work_handler() - process data tx ack + * @ack_work: work structure + * + * Return: none + */ +static void wma_data_tx_ack_work_handler(void *ack_work) +{ + struct wma_tx_ack_work_ctx *work; + tp_wma_handle wma_handle; + pWMAAckFnTxComp ack_cb; + + if (cds_is_load_or_unload_in_progress()) { + WMA_LOGE("%s: Driver load/unload in progress", __func__); + return; + } + + work = (struct wma_tx_ack_work_ctx *)ack_work; + + wma_handle = work->wma_handle; + ack_cb = wma_handle->umac_data_ota_ack_cb; + + if (work->status) + WMA_LOGE("Data Tx Ack Cb Status %d", work->status); + else + WMA_LOGD("Data Tx Ack Cb Status %d", work->status); + + /* Call the Ack Cb registered by UMAC */ + if (ack_cb) + ack_cb((tpAniSirGlobal) (wma_handle->mac_context), + work->status ? 0 : 1); + else + WMA_LOGE("Data Tx Ack Cb is NULL"); + + wma_handle->umac_data_ota_ack_cb = NULL; + wma_handle->last_umac_data_nbuf = NULL; + qdf_mem_free(work); + wma_handle->ack_work_ctx = NULL; +} + +/** + * wma_data_tx_ack_comp_hdlr() - handles tx data ack completion + * @context: context with which the handler is registered + * @netbuf: tx data nbuf + * @err: status of tx completion + * + * This is the cb registered with TxRx for + * Ack Complete + * + * Return: none + */ +void +wma_data_tx_ack_comp_hdlr(void *wma_context, qdf_nbuf_t netbuf, int32_t status) +{ + ol_txrx_pdev_handle pdev; + tp_wma_handle wma_handle = (tp_wma_handle) wma_context; + + if (NULL == wma_handle) { + WMA_LOGE("%s: Invalid WMA Handle", __func__); + return; + } + + pdev = cds_get_context(QDF_MODULE_ID_TXRX); + + if (NULL == pdev) { + WMA_LOGE("%s: Failed to get pdev", __func__); + return; + } + + /* + * if netBuf does not match with pending nbuf then just free the + * netbuf and do not call ack cb + */ + if (wma_handle->last_umac_data_nbuf != netbuf) { + if (wma_handle->umac_data_ota_ack_cb) { + WMA_LOGE("%s: nbuf does not match but umac_data_ota_ack_cb is not null", + __func__); + } else { + WMA_LOGE("%s: nbuf does not match and umac_data_ota_ack_cb is also null", + __func__); + } + goto free_nbuf; + } + + if (wma_handle && wma_handle->umac_data_ota_ack_cb) { + struct wma_tx_ack_work_ctx *ack_work; + + ack_work = qdf_mem_malloc(sizeof(struct wma_tx_ack_work_ctx)); + wma_handle->ack_work_ctx = ack_work; + if (ack_work) { + ack_work->wma_handle = wma_handle; + ack_work->sub_type = 0; + ack_work->status = status; + + qdf_create_work(0, &ack_work->ack_cmp_work, + wma_data_tx_ack_work_handler, + ack_work); + qdf_sched_work(0, &ack_work->ack_cmp_work); + } + } + +free_nbuf: + /* unmap and freeing the tx buf as txrx is not taking care */ + qdf_nbuf_unmap_single(pdev->osdev, netbuf, QDF_DMA_TO_DEVICE); + qdf_nbuf_free(netbuf); +} + +/** + * wma_update_txrx_chainmask() - update txrx chainmask + * @num_rf_chains: number rf chains + * @cmd_value: command value + * + * Return: none + */ +void wma_update_txrx_chainmask(int num_rf_chains, int *cmd_value) +{ + if (*cmd_value > WMA_MAX_RF_CHAINS(num_rf_chains)) { + WMA_LOGE("%s: Chainmask value exceeds the maximum" + " supported range setting it to" + " maximum value. Requested value %d" + " Updated value %d", __func__, *cmd_value, + WMA_MAX_RF_CHAINS(num_rf_chains)); + *cmd_value = WMA_MAX_RF_CHAINS(num_rf_chains); + } else if (*cmd_value < WMA_MIN_RF_CHAINS) { + WMA_LOGE("%s: Chainmask value is less than the minimum" + " supported range setting it to" + " minimum value. Requested value %d" + " Updated value %d", __func__, *cmd_value, + WMA_MIN_RF_CHAINS); + *cmd_value = WMA_MIN_RF_CHAINS; + } +} + +/** + * wma_peer_state_change_event_handler() - peer state change event handler + * @handle: wma handle + * @event_buff: event buffer + * @len: length of buffer + * + * This event handler unpauses vdev if peer state change to AUTHORIZED STATE + * + * Return: 0 for success or error code + */ +int wma_peer_state_change_event_handler(void *handle, + uint8_t *event_buff, + uint32_t len) +{ + WMI_PEER_STATE_EVENTID_param_tlvs *param_buf; + wmi_peer_state_event_fixed_param *event; + ol_txrx_vdev_handle vdev; + tp_wma_handle wma_handle = (tp_wma_handle) handle; + + if (!event_buff) { + WMA_LOGE("%s: Received NULL event ptr from FW", __func__); + return -EINVAL; + } + param_buf = (WMI_PEER_STATE_EVENTID_param_tlvs *) event_buff; + if (!param_buf) { + WMA_LOGE("%s: Received NULL buf ptr from FW", __func__); + return -ENOMEM; + } + + event = param_buf->fixed_param; + vdev = wma_find_vdev_by_id(wma_handle, event->vdev_id); + if (NULL == vdev) { + WMA_LOGP("%s: Couldn't find vdev for vdev_id: %d", + __func__, event->vdev_id); + return -EINVAL; + } + + if (ol_txrx_get_opmode(vdev) == wlan_op_mode_sta + && event->state == WMI_PEER_STATE_AUTHORIZED) { + /* + * set event so that hdd + * can procced and unpause tx queue + */ +#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL + if (!wma_handle->peer_authorized_cb) { + WMA_LOGE("%s: peer authorized cb not registered", + __func__); + return -EINVAL; + } + wma_handle->peer_authorized_cb(event->vdev_id); +#endif + } + + return 0; +} + +/** + * wma_set_enable_disable_mcc_adaptive_scheduler() -enable/disable mcc scheduler + * @mcc_adaptive_scheduler: enable/disable + * + * This function enable/disable mcc adaptive scheduler in fw. + * + * Return: QDF_STATUS_SUCCESS for sucess or error code + */ +QDF_STATUS wma_set_enable_disable_mcc_adaptive_scheduler(uint32_t + mcc_adaptive_scheduler) +{ + tp_wma_handle wma = NULL; + uint32_t pdev_id; + + wma = cds_get_context(QDF_MODULE_ID_WMA); + if (NULL == wma) { + WMA_LOGE("%s : Failed to get wma", __func__); + return QDF_STATUS_E_FAULT; + } + + /* + * Since there could be up to two instances of OCS in FW (one per MAC), + * FW provides the option of enabling and disabling MAS on a per MAC + * basis. But, Host does not have enable/disable option for individual + * MACs. So, FW agreed for the Host to send down a 'pdev id' of 0. + * When 'pdev id' of 0 is used, FW treats this as a SOC level command + * and applies the same value to both MACs. Irrespective of the value + * of 'WMI_SERVICE_DEPRECATED_REPLACE', the pdev id needs to be '0' + * (SOC level) for WMI_RESMGR_ADAPTIVE_OCS_ENABLE_DISABLE_CMDID + */ + pdev_id = WMI_PDEV_ID_SOC; + + return wmi_unified_set_enable_disable_mcc_adaptive_scheduler_cmd( + wma->wmi_handle, mcc_adaptive_scheduler, pdev_id); +} + +/** + * wma_set_mcc_channel_time_latency() -set MCC channel time latency + * @wma: wma handle + * @mcc_channel: mcc channel + * @mcc_channel_time_latency: MCC channel time latency. + * + * Currently used to set time latency for an MCC vdev/adapter using operating + * channel of it and channel number. The info is provided run time using + * iwpriv command: iwpriv setMccLatency . + * + * Return: QDF status + */ +QDF_STATUS wma_set_mcc_channel_time_latency + (tp_wma_handle wma, + uint32_t mcc_channel, uint32_t mcc_channel_time_latency) +{ + uint32_t cfg_val = 0; + struct sAniSirGlobal *pMac = NULL; + uint32_t channel1 = mcc_channel; + uint32_t chan1_freq = cds_chan_to_freq(channel1); + + if (!wma) { + WMA_LOGE("%s:NULL wma ptr. Exiting", __func__); + QDF_ASSERT(0); + return QDF_STATUS_E_FAILURE; + } + pMac = cds_get_context(QDF_MODULE_ID_PE); + if (!pMac) { + WMA_LOGE("%s:NULL pMac ptr. Exiting", __func__); + QDF_ASSERT(0); + return QDF_STATUS_E_FAILURE; + } + + /* First step is to confirm if MCC is active */ + if (!lim_is_in_mcc(pMac)) { + WMA_LOGE("%s: MCC is not active. Exiting", __func__); + QDF_ASSERT(0); + return QDF_STATUS_E_FAILURE; + } + /* Confirm MCC adaptive scheduler feature is disabled */ + if (wlan_cfg_get_int(pMac, WNI_CFG_ENABLE_MCC_ADAPTIVE_SCHED, + &cfg_val) == eSIR_SUCCESS) { + if (cfg_val == WNI_CFG_ENABLE_MCC_ADAPTIVE_SCHED_STAMAX) { + WMA_LOGD("%s: Can't set channel latency while MCC " + "ADAPTIVE SCHED is enabled. Exit", __func__); + return QDF_STATUS_SUCCESS; + } + } else { + WMA_LOGE("%s: Failed to get value for MCC_ADAPTIVE_SCHED, " + "Exit w/o setting latency", __func__); + QDF_ASSERT(0); + return QDF_STATUS_E_FAILURE; + } + + return wmi_unified_set_mcc_channel_time_latency_cmd(wma->wmi_handle, + chan1_freq, + mcc_channel_time_latency); +} + +/** + * wma_set_mcc_channel_time_quota() -set MCC channel time quota + * @wma: wma handle + * @adapter_1_chan_number: adapter 1 channel number + * @adapter_1_quota: adapter 1 quota + * @adapter_2_chan_number: adapter 2 channel number + * + * Currently used to set time quota for 2 MCC vdevs/adapters using (operating + * channel, quota) for each mode . The info is provided run time using + * iwpriv command: iwpriv setMccQuota . + * Note: the quota provided in command is for the same mode in cmd. HDD + * checks if MCC mode is active, gets the second mode and its operating chan. + * Quota for the 2nd role is calculated as 100 - quota of first mode. + * + * Return: QDF status + */ +QDF_STATUS wma_set_mcc_channel_time_quota + (tp_wma_handle wma, + uint32_t adapter_1_chan_number, + uint32_t adapter_1_quota, uint32_t adapter_2_chan_number) +{ + uint32_t cfg_val = 0; + struct sAniSirGlobal *pMac = NULL; + uint32_t chan1_freq = cds_chan_to_freq(adapter_1_chan_number); + uint32_t chan2_freq = cds_chan_to_freq(adapter_2_chan_number); + + if (!wma) { + WMA_LOGE("%s:NULL wma ptr. Exiting", __func__); + QDF_ASSERT(0); + return QDF_STATUS_E_FAILURE; + } + pMac = cds_get_context(QDF_MODULE_ID_PE); + if (!pMac) { + WMA_LOGE("%s:NULL pMac ptr. Exiting", __func__); + QDF_ASSERT(0); + return QDF_STATUS_E_FAILURE; + } + + /* First step is to confirm if MCC is active */ + if (!lim_is_in_mcc(pMac)) { + WMA_LOGD("%s: MCC is not active. Exiting", __func__); + QDF_ASSERT(0); + return QDF_STATUS_E_FAILURE; + } + + /* Confirm MCC adaptive scheduler feature is disabled */ + if (wlan_cfg_get_int(pMac, WNI_CFG_ENABLE_MCC_ADAPTIVE_SCHED, + &cfg_val) == eSIR_SUCCESS) { + if (cfg_val == WNI_CFG_ENABLE_MCC_ADAPTIVE_SCHED_STAMAX) { + WMA_LOGD("%s: Can't set channel quota while " + "MCC_ADAPTIVE_SCHED is enabled. Exit", + __func__); + return QDF_STATUS_SUCCESS; + } + } else { + WMA_LOGE("%s: Failed to retrieve " + "WNI_CFG_ENABLE_MCC_ADAPTIVE_SCHED. Exit", __func__); + QDF_ASSERT(0); + return QDF_STATUS_E_FAILURE; + } + + return wmi_unified_set_mcc_channel_time_quota_cmd(wma->wmi_handle, + chan1_freq, + adapter_1_quota, + chan2_freq); +} + +/** + * wma_set_linkstate() - set wma linkstate + * @wma: wma handle + * @params: link state params + * + * Return: none + */ +void wma_set_linkstate(tp_wma_handle wma, tpLinkStateParams params) +{ + ol_txrx_pdev_handle pdev; + ol_txrx_vdev_handle vdev; + uint8_t vdev_id; + bool roam_synch_in_progress = false; + QDF_STATUS status; + struct wma_target_req *msg; + + params->status = true; + WMA_LOGD("%s: state %d selfmac %pM", __func__, + params->state, params->selfMacAddr); + if ((params->state != eSIR_LINK_PREASSOC_STATE) && + (params->state != eSIR_LINK_DOWN_STATE)) { + WMA_LOGD("%s: unsupported link state %d", + __func__, params->state); + params->status = false; + goto out; + } + + pdev = cds_get_context(QDF_MODULE_ID_TXRX); + + if (NULL == pdev) { + WMA_LOGE("%s: Unable to get TXRX context", __func__); + params->status = false; + goto out; + } + + vdev = wma_find_vdev_by_addr(wma, params->selfMacAddr, &vdev_id); + if (!vdev) { + WMA_LOGP("%s: vdev not found for addr: %pM", + __func__, params->selfMacAddr); + params->status = false; + goto out; + } + + if (wma_is_vdev_in_ap_mode(wma, vdev_id)) { + WMA_LOGD("%s: Ignoring set link req in ap mode", __func__); + params->status = false; + goto out; + } + + if (params->state == eSIR_LINK_PREASSOC_STATE) { + if (wma_is_roam_synch_in_progress(wma, vdev_id)) + roam_synch_in_progress = true; + status = wma_create_peer(wma, pdev, vdev, params->bssid, + WMI_PEER_TYPE_DEFAULT, vdev_id, + roam_synch_in_progress); + if (status != QDF_STATUS_SUCCESS) { + WMA_LOGE("%s: Unable to create peer", __func__); + params->status = false; + } + if (roam_synch_in_progress) + return; + } else { + WMA_LOGD("%s, vdev_id: %d, pausing tx_ll_queue for VDEV_STOP", + __func__, vdev_id); + ol_txrx_vdev_pause(wma->interfaces[vdev_id].handle, + OL_TXQ_PAUSE_REASON_VDEV_STOP); + wma->interfaces[vdev_id].pause_bitmap |= (1 << PAUSE_TYPE_HOST); + + msg = wma_fill_vdev_req(wma, vdev_id, + WMA_SET_LINK_STATE, + WMA_TARGET_REQ_TYPE_VDEV_STOP, params, + WMA_VDEV_STOP_REQUEST_TIMEOUT); + if (!msg) { + WMA_LOGP(FL("Failed to fill vdev request for vdev_id %d"), + vdev_id); + params->status = false; + status = QDF_STATUS_E_NOMEM; + } + if (wma_send_vdev_stop_to_fw(wma, vdev_id)) { + WMA_LOGP("%s: %d Failed to send vdev stop vdev %d", + __func__, __LINE__, vdev_id); + params->status = false; + } else { + WMA_LOGP("%s: %d vdev stop sent vdev %d", + __func__, __LINE__, vdev_id); + /* + * Remove peer, Vdev down and sending set link + * response will be handled in vdev stop response + * handler + */ + return; + } + } +out: + wma_send_msg(wma, WMA_SET_LINK_STATE_RSP, (void *)params, 0); +} + +/** + * wma_unpause_vdev - unpause all vdev + * @wma: wma handle + * + * unpause all vdev aftter resume/coming out of wow mode + * + * Return: none + */ +void wma_unpause_vdev(tp_wma_handle wma) +{ + int8_t vdev_id; + struct wma_txrx_node *iface; + + for (vdev_id = 0; vdev_id < wma->max_bssid; vdev_id++) { + if (!wma->interfaces[vdev_id].handle) + continue; + +#if defined(QCA_LL_LEGACY_TX_FLOW_CONTROL) || defined(QCA_LL_TX_FLOW_CONTROL_V2) + /* When host resume, by default, unpause all active vdev */ + if (wma->interfaces[vdev_id].pause_bitmap) { + ol_txrx_vdev_unpause(wma->interfaces[vdev_id].handle, + 0xffffffff); + wma->interfaces[vdev_id].pause_bitmap = 0; + } +#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */ + + iface = &wma->interfaces[vdev_id]; + iface->conn_state = false; + } +} + +/** + * wma_process_rate_update_indate() - rate update indication + * @wma: wma handle + * @pRateUpdateParams: Rate update params + * + * This function update rate & short GI interval to fw based on params + * send by SME. + * + * Return: QDF status + */ +QDF_STATUS wma_process_rate_update_indicate(tp_wma_handle wma, + tSirRateUpdateInd * + pRateUpdateParams) +{ + int32_t ret = 0; + uint8_t vdev_id = 0; + void *pdev; + int32_t mbpsx10_rate = -1; + uint32_t paramId; + uint8_t rate = 0; + uint32_t short_gi; + struct wma_txrx_node *intr = wma->interfaces; + QDF_STATUS status; + + /* Get the vdev id */ + pdev = wma_find_vdev_by_addr(wma, pRateUpdateParams->bssid.bytes, + &vdev_id); + if (!pdev) { + WMA_LOGE("vdev handle is invalid for %pM", + pRateUpdateParams->bssid.bytes); + qdf_mem_free(pRateUpdateParams); + return QDF_STATUS_E_INVAL; + } + short_gi = intr[vdev_id].config.shortgi; + if (short_gi == 0) + short_gi = (intr[vdev_id].rate_flags & eHAL_TX_RATE_SGI) ? + true : false; + /* first check if reliable TX mcast rate is used. If not check the bcast. + * Then is mcast. Mcast rate is saved in mcastDataRate24GHz + */ + if (pRateUpdateParams->reliableMcastDataRateTxFlag > 0) { + mbpsx10_rate = pRateUpdateParams->reliableMcastDataRate; + paramId = WMI_VDEV_PARAM_MCAST_DATA_RATE; + if (pRateUpdateParams-> + reliableMcastDataRateTxFlag & eHAL_TX_RATE_SGI) + short_gi = 1; /* upper layer specified short GI */ + } else if (pRateUpdateParams->bcastDataRate > -1) { + mbpsx10_rate = pRateUpdateParams->bcastDataRate; + paramId = WMI_VDEV_PARAM_BCAST_DATA_RATE; + } else { + mbpsx10_rate = pRateUpdateParams->mcastDataRate24GHz; + paramId = WMI_VDEV_PARAM_MCAST_DATA_RATE; + if (pRateUpdateParams-> + mcastDataRate24GHzTxFlag & eHAL_TX_RATE_SGI) + short_gi = 1; /* upper layer specified short GI */ + } + WMA_LOGE("%s: dev_id = %d, dev_type = %d, dev_mode = %d, " + "mac = %pM, config.shortgi = %d, rate_flags = 0x%x", + __func__, vdev_id, intr[vdev_id].type, + pRateUpdateParams->dev_mode, pRateUpdateParams->bssid.bytes, + intr[vdev_id].config.shortgi, intr[vdev_id].rate_flags); + ret = wma_encode_mc_rate(short_gi, intr[vdev_id].config.chwidth, + intr[vdev_id].chanmode, intr[vdev_id].mhz, + mbpsx10_rate, pRateUpdateParams->nss, &rate); + if (ret != QDF_STATUS_SUCCESS) { + WMA_LOGE("%s: Error, Invalid input rate value", __func__); + qdf_mem_free(pRateUpdateParams); + return ret; + } + status = wma_vdev_set_param(wma->wmi_handle, vdev_id, + WMI_VDEV_PARAM_SGI, short_gi); + if (QDF_IS_STATUS_ERROR(status)) { + WMA_LOGE("%s: Failed to Set WMI_VDEV_PARAM_SGI (%d), status = %d", + __func__, short_gi, status); + qdf_mem_free(pRateUpdateParams); + return status; + } + status = wma_vdev_set_param(wma->wmi_handle, + vdev_id, paramId, rate); + qdf_mem_free(pRateUpdateParams); + if (QDF_IS_STATUS_ERROR(status)) { + WMA_LOGE("%s: Failed to Set rate, status = %d", __func__, status); + return status; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * wma_mgmt_tx_ack_work_handler() - mgmt tx ack work queue + * @ack_work: work structure + * + * Return: none + */ +static void wma_mgmt_tx_ack_work_handler(void *ack_work) +{ + struct wma_tx_ack_work_ctx *work; + tp_wma_handle wma_handle; + pWMAAckFnTxComp ack_cb; + + if (cds_is_load_or_unload_in_progress()) { + WMA_LOGE("%s: Driver load/unload in progress", __func__); + return; + } + + work = (struct wma_tx_ack_work_ctx *)ack_work; + + wma_handle = work->wma_handle; + ack_cb = wma_handle->umac_ota_ack_cb[work->sub_type]; + + WMA_LOGD("Tx Ack Cb SubType %d Status %d", + work->sub_type, work->status); + + /* Call the Ack Cb registered by UMAC */ + ack_cb((tpAniSirGlobal) (wma_handle->mac_context), + work->status ? 0 : 1); + + qdf_mem_free(work); + wma_handle->ack_work_ctx = NULL; +} + +/** + * wma_mgmt_tx_comp_conf_ind() - Post mgmt tx complete indication to PE. + * @wma_handle: Pointer to WMA handle + * @sub_type: Tx mgmt frame sub type + * @status: Mgmt frame tx status + * + * This function sends mgmt complition confirmation to PE for deauth + * and deassoc frames. + * + * Return: none + */ +static void +wma_mgmt_tx_comp_conf_ind(tp_wma_handle wma_handle, uint8_t sub_type, + int32_t status) +{ + int32_t tx_comp_status; + + tx_comp_status = status ? 0 : 1; + if (sub_type == SIR_MAC_MGMT_DISASSOC) { + wma_send_msg(wma_handle, WMA_DISASSOC_TX_COMP, NULL, + tx_comp_status); + } else if (sub_type == SIR_MAC_MGMT_DEAUTH) { + wma_send_msg(wma_handle, WMA_DEAUTH_TX_COMP, NULL, + tx_comp_status); + } +} + +/** + * wma_mgmt_tx_ack_comp_hdlr() - handles tx ack mgmt completion + * @context: context with which the handler is registered + * @netbuf: tx mgmt nbuf + * @status: status of tx completion + * + * This is callback registered with TxRx for + * Ack Complete. + * + * Return: none + */ +static void +wma_mgmt_tx_ack_comp_hdlr(void *wma_context, qdf_nbuf_t netbuf, int32_t status) +{ + tpSirMacFrameCtl pFc = (tpSirMacFrameCtl) (qdf_nbuf_data(netbuf)); + tp_wma_handle wma_handle = (tp_wma_handle) wma_context; + + if (wma_handle && wma_handle->umac_ota_ack_cb[pFc->subType]) { + if ((pFc->subType == SIR_MAC_MGMT_DISASSOC) || + (pFc->subType == SIR_MAC_MGMT_DEAUTH)) { + wma_mgmt_tx_comp_conf_ind(wma_handle, + (uint8_t) pFc->subType, + status); + } else { + struct wma_tx_ack_work_ctx *ack_work; + + ack_work = + qdf_mem_malloc(sizeof(struct wma_tx_ack_work_ctx)); + + if (ack_work) { + ack_work->wma_handle = wma_handle; + ack_work->sub_type = pFc->subType; + ack_work->status = status; + + qdf_create_work(0, &ack_work->ack_cmp_work, + wma_mgmt_tx_ack_work_handler, + ack_work); + + qdf_sched_work(0, &ack_work->ack_cmp_work); + } + } + } +} + +/** + * wma_mgmt_tx_dload_comp_hldr() - handles tx mgmt completion + * @context: context with which the handler is registered + * @netbuf: tx mgmt nbuf + * @status: status of tx completion + * + * This function calls registered download callback while sending mgmt packet. + * + * Return: none + */ +static void +wma_mgmt_tx_dload_comp_hldr(void *wma_context, qdf_nbuf_t netbuf, + int32_t status) +{ + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + + tp_wma_handle wma_handle = (tp_wma_handle) wma_context; + void *mac_context = wma_handle->mac_context; + + WMA_LOGD("Tx Complete Status %d", status); + + if (!wma_handle->tx_frm_download_comp_cb) { + WMA_LOGE("Tx Complete Cb not registered by umac"); + return; + } + + /* Call Tx Mgmt Complete Callback registered by umac */ + wma_handle->tx_frm_download_comp_cb(mac_context, netbuf, 0); + + /* Reset Callback */ + wma_handle->tx_frm_download_comp_cb = NULL; + + /* Set the Tx Mgmt Complete Event */ + qdf_status = qdf_event_set(&wma_handle->tx_frm_download_comp_event); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) + WMA_LOGP("%s: Event Set failed - tx_frm_comp_event", __func__); +} + +/** + * wma_tx_attach() - attach tx related callbacks + * @pwmaCtx: wma context + * + * attaches tx fn with underlying layer. + * + * Return: QDF status + */ +QDF_STATUS wma_tx_attach(tp_wma_handle wma_handle) +{ + /* Get the Vos Context */ + p_cds_contextType cds_handle = + (p_cds_contextType) (wma_handle->cds_context); + + /* Get the txRx Pdev handle */ + ol_txrx_pdev_handle txrx_pdev = + (ol_txrx_pdev_handle) (cds_handle->pdev_txrx_ctx); + + /* Register for Tx Management Frames */ + ol_txrx_mgmt_tx_cb_set(txrx_pdev, GENERIC_NODOWLOAD_ACK_COMP_INDEX, + NULL, wma_mgmt_tx_ack_comp_hdlr, wma_handle); + + ol_txrx_mgmt_tx_cb_set(txrx_pdev, GENERIC_DOWNLD_COMP_NOACK_COMP_INDEX, + wma_mgmt_tx_dload_comp_hldr, NULL, wma_handle); + + ol_txrx_mgmt_tx_cb_set(txrx_pdev, GENERIC_DOWNLD_COMP_ACK_COMP_INDEX, + wma_mgmt_tx_dload_comp_hldr, + wma_mgmt_tx_ack_comp_hdlr, wma_handle); + + /* Store the Mac Context */ + wma_handle->mac_context = cds_handle->pMACContext; + + return QDF_STATUS_SUCCESS; +} + +/** + * wma_tx_detach() - detach tx related callbacks + * @tp_wma_handle: wma context + * + * Deregister with TxRx for Tx Mgmt Download and Ack completion. + * + * Return: QDF status + */ +QDF_STATUS wma_tx_detach(tp_wma_handle wma_handle) +{ + uint32_t frame_index = 0; + + /* Get the Vos Context */ + p_cds_contextType cds_handle = + (p_cds_contextType) (wma_handle->cds_context); + + /* Get the txRx Pdev handle */ + ol_txrx_pdev_handle txrx_pdev = + (ol_txrx_pdev_handle) (cds_handle->pdev_txrx_ctx); + + if (txrx_pdev) { + /* Deregister with TxRx for Tx Mgmt completion call back */ + for (frame_index = 0; frame_index < FRAME_INDEX_MAX; + frame_index++) { + ol_txrx_mgmt_tx_cb_set(txrx_pdev, frame_index, NULL, + NULL, txrx_pdev); + } + } + + /* Reset Tx Frm Callbacks */ + wma_handle->tx_frm_download_comp_cb = NULL; + + /* Reset Tx Data Frame Ack Cb */ + wma_handle->umac_data_ota_ack_cb = NULL; + + /* Reset last Tx Data Frame nbuf ptr */ + wma_handle->last_umac_data_nbuf = NULL; + + return QDF_STATUS_SUCCESS; +} + +#if defined(QCA_LL_LEGACY_TX_FLOW_CONTROL) || \ + defined(QCA_LL_TX_FLOW_CONTROL_V2) || defined(CONFIG_HL_SUPPORT) + +/** + * wma_mcc_vdev_tx_pause_evt_handler() - pause event handler + * @handle: wma handle + * @event: event buffer + * @len: data length + * + * This function handle pause event from fw and pause/unpause + * vdev. + * + * Return: 0 for success or error code. + */ +int wma_mcc_vdev_tx_pause_evt_handler(void *handle, uint8_t *event, + uint32_t len) +{ + tp_wma_handle wma = (tp_wma_handle) handle; + WMI_TX_PAUSE_EVENTID_param_tlvs *param_buf; + wmi_tx_pause_event_fixed_param *wmi_event; + uint8_t vdev_id; + A_UINT32 vdev_map; + + param_buf = (WMI_TX_PAUSE_EVENTID_param_tlvs *) event; + if (!param_buf) { + WMA_LOGE("Invalid roam event buffer"); + return -EINVAL; + } + + if (wma_get_wow_bus_suspend(wma)) { + WMA_LOGD(" Suspend is in progress: Pause/Unpause Tx is NoOp"); + return 0; + } + + wmi_event = param_buf->fixed_param; + vdev_map = wmi_event->vdev_map; + /* FW mapped vdev from ID + * vdev_map = (1 << vdev_id) + * So, host should unmap to ID */ + for (vdev_id = 0; vdev_map != 0; vdev_id++) { + if (!(vdev_map & 0x1)) { + /* No Vdev */ + } else { + if (!wma->interfaces[vdev_id].handle) { + WMA_LOGE("%s: invalid vdev ID %d", __func__, + vdev_id); + /* Test Next VDEV */ + vdev_map >>= 1; + continue; + } + + /* PAUSE action, add bitmap */ + if (ACTION_PAUSE == wmi_event->action) { + /* + * Now only support per-dev pause so it is not + * necessary to pause a paused queue again. + */ + if (!wma->interfaces[vdev_id].pause_bitmap) + ol_txrx_vdev_pause( + wma->interfaces[vdev_id]. + handle, + OL_TXQ_PAUSE_REASON_FW); + wma->interfaces[vdev_id].pause_bitmap |= + (1 << wmi_event->pause_type); + } + /* UNPAUSE action, clean bitmap */ + else if (ACTION_UNPAUSE == wmi_event->action) { + /* Handle unpause only if already paused */ + if (wma->interfaces[vdev_id].pause_bitmap) { + wma->interfaces[vdev_id].pause_bitmap &= + ~(1 << wmi_event->pause_type); + + if (!wma->interfaces[vdev_id]. + pause_bitmap) { + /* PAUSE BIT MAP is cleared + * UNPAUSE VDEV */ + ol_txrx_vdev_unpause( + wma->interfaces[vdev_id] + .handle, + OL_TXQ_PAUSE_REASON_FW); + } + } + } else { + WMA_LOGE("Not Valid Action Type %d", + wmi_event->action); + } + + WMA_LOGD + ("vdev_id %d, pause_map 0x%x, pause type %d, action %d", + vdev_id, wma->interfaces[vdev_id].pause_bitmap, + wmi_event->pause_type, wmi_event->action); + } + /* Test Next VDEV */ + vdev_map >>= 1; + } + + return 0; +} + +#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */ + +#if defined(CONFIG_HL_SUPPORT) && defined(QCA_BAD_PEER_TX_FLOW_CL) + +/** + * wma_set_peer_rate_report_condition - + * this function set peer rate report + * condition info to firmware. + * @handle: Handle of WMA + * @config: Bad peer configuration from SIR module + * + * It is a wrapper function to sent WMI_PEER_SET_RATE_REPORT_CONDITION_CMDID + * to the firmare\target.If the command sent to firmware failed, free the + * buffer that allocated. + * + * Return: QDF_STATUS based on values sent to firmware + */ +static +QDF_STATUS wma_set_peer_rate_report_condition(WMA_HANDLE handle, + struct t_bad_peer_txtcl_config *config) +{ + tp_wma_handle wma_handle = (tp_wma_handle)handle; + struct wmi_peer_rate_report_params rate_report_params = {0}; + u_int32_t i, j; + + rate_report_params.rate_report_enable = config->enable; + rate_report_params.backoff_time = config->tgt_backoff; + rate_report_params.timer_period = config->tgt_report_prd; + for (i = 0; i < WMI_PEER_RATE_REPORT_COND_MAX_NUM; i++) { + rate_report_params.report_per_phy[i].cond_flags = + config->threshold[i].cond; + rate_report_params.report_per_phy[i].delta.delta_min = + config->threshold[i].delta; + rate_report_params.report_per_phy[i].delta.percent = + config->threshold[i].percentage; + for (j = 0; j < WMI_MAX_NUM_OF_RATE_THRESH; j++) { + rate_report_params.report_per_phy[i]. + report_rate_threshold[j] = + config->threshold[i].thresh[j]; + } + } + + return wmi_unified_peer_rate_report_cmd(wma_handle->wmi_handle, + &rate_report_params); +} + +/** + * wma_process_init_bad_peer_tx_ctl_info - + * this function to initialize peer rate report config info. + * @handle: Handle of WMA + * @config: Bad peer configuration from SIR module + * + * This function initializes the bad peer tx control data structure in WMA, + * sends down the initial configuration to the firmware and configures + * the peer status update seeting in the tx_rx module. + * + * Return: QDF_STATUS based on procedure status + */ + +QDF_STATUS wma_process_init_bad_peer_tx_ctl_info(tp_wma_handle wma, + struct t_bad_peer_txtcl_config *config) +{ + /* Parameter sanity check */ + ol_txrx_pdev_handle curr_pdev; + + if (NULL == wma || NULL == config) { + WMA_LOGE("%s Invalid input\n", __func__); + return QDF_STATUS_E_FAILURE; + } + + curr_pdev = cds_get_context(QDF_MODULE_ID_TXRX); + if (NULL == curr_pdev) { + WMA_LOGE("%s: Failed to get pdev\n", __func__); + return QDF_STATUS_E_FAILURE; + } + + WMA_LOGE("%s enable %d period %d txq limit %d\n", __func__, + config->enable, + config->period, + config->txq_limit); + + /* Only need to initialize the setting + when the feature is enabled */ + if (config->enable) { + int i = 0; + + ol_txrx_bad_peer_txctl_set_setting(curr_pdev, + config->enable, + config->period, + config->txq_limit); + + for (i = 0; i < WLAN_WMA_IEEE80211_MAX_LEVEL; i++) { + u_int32_t threshold, limit; + threshold = + config->threshold[i].thresh[0]; + limit = config->threshold[i].txlimit; + ol_txrx_bad_peer_txctl_update_threshold(curr_pdev, i, + threshold, + limit); + } + } + + return wma_set_peer_rate_report_condition(wma, config); +} +#endif /* defined(CONFIG_HL_SUPPORT) && defined(QCA_BAD_PEER_TX_FLOW_CL) */ + + +/** + * wma_process_init_thermal_info() - initialize thermal info + * @wma: Pointer to WMA handle + * @pThermalParams: Pointer to thermal mitigation parameters + * + * This function initializes the thermal management table in WMA, + * sends down the initial temperature thresholds to the firmware + * and configures the throttle period in the tx rx module + * + * Returns: QDF_STATUS_SUCCESS for success otherwise failure + */ +QDF_STATUS wma_process_init_thermal_info(tp_wma_handle wma, + t_thermal_mgmt *pThermalParams) +{ + t_thermal_cmd_params thermal_params; + ol_txrx_pdev_handle curr_pdev; + + if (NULL == wma || NULL == pThermalParams) { + WMA_LOGE("TM Invalid input"); + return QDF_STATUS_E_FAILURE; + } + + curr_pdev = cds_get_context(QDF_MODULE_ID_TXRX); + if (NULL == curr_pdev) { + WMA_LOGE("%s: Failed to get pdev", __func__); + return QDF_STATUS_E_FAILURE; + } + + WMA_LOGD("TM enable %d period %d", pThermalParams->thermalMgmtEnabled, + pThermalParams->throttlePeriod); + + WMA_LOGD("Throttle Duty Cycle Level in percentage:\n" + "0 %d\n" + "1 %d\n" + "2 %d\n" + "3 %d", + pThermalParams->throttle_duty_cycle_tbl[0], + pThermalParams->throttle_duty_cycle_tbl[1], + pThermalParams->throttle_duty_cycle_tbl[2], + pThermalParams->throttle_duty_cycle_tbl[3]); + + wma->thermal_mgmt_info.thermalMgmtEnabled = + pThermalParams->thermalMgmtEnabled; + wma->thermal_mgmt_info.thermalLevels[0].minTempThreshold = + pThermalParams->thermalLevels[0].minTempThreshold; + wma->thermal_mgmt_info.thermalLevels[0].maxTempThreshold = + pThermalParams->thermalLevels[0].maxTempThreshold; + wma->thermal_mgmt_info.thermalLevels[1].minTempThreshold = + pThermalParams->thermalLevels[1].minTempThreshold; + wma->thermal_mgmt_info.thermalLevels[1].maxTempThreshold = + pThermalParams->thermalLevels[1].maxTempThreshold; + wma->thermal_mgmt_info.thermalLevels[2].minTempThreshold = + pThermalParams->thermalLevels[2].minTempThreshold; + wma->thermal_mgmt_info.thermalLevels[2].maxTempThreshold = + pThermalParams->thermalLevels[2].maxTempThreshold; + wma->thermal_mgmt_info.thermalLevels[3].minTempThreshold = + pThermalParams->thermalLevels[3].minTempThreshold; + wma->thermal_mgmt_info.thermalLevels[3].maxTempThreshold = + pThermalParams->thermalLevels[3].maxTempThreshold; + wma->thermal_mgmt_info.thermalCurrLevel = WLAN_WMA_THERMAL_LEVEL_0; + + WMA_LOGD("TM level min max:\n" + "0 %d %d\n" + "1 %d %d\n" + "2 %d %d\n" + "3 %d %d", + wma->thermal_mgmt_info.thermalLevels[0].minTempThreshold, + wma->thermal_mgmt_info.thermalLevels[0].maxTempThreshold, + wma->thermal_mgmt_info.thermalLevels[1].minTempThreshold, + wma->thermal_mgmt_info.thermalLevels[1].maxTempThreshold, + wma->thermal_mgmt_info.thermalLevels[2].minTempThreshold, + wma->thermal_mgmt_info.thermalLevels[2].maxTempThreshold, + wma->thermal_mgmt_info.thermalLevels[3].minTempThreshold, + wma->thermal_mgmt_info.thermalLevels[3].maxTempThreshold); + + if (wma->thermal_mgmt_info.thermalMgmtEnabled) { + ol_tx_throttle_init_period(curr_pdev, + pThermalParams->throttlePeriod, + &pThermalParams->throttle_duty_cycle_tbl[0]); + + /* Get the temperature thresholds to set in firmware */ + thermal_params.minTemp = + wma->thermal_mgmt_info.thermalLevels[WLAN_WMA_THERMAL_LEVEL_0].minTempThreshold; + thermal_params.maxTemp = + wma->thermal_mgmt_info.thermalLevels[WLAN_WMA_THERMAL_LEVEL_0].maxTempThreshold; + thermal_params.thermalEnable = + wma->thermal_mgmt_info.thermalMgmtEnabled; + + WMA_LOGE("TM sending the following to firmware: min %d max %d enable %d", + thermal_params.minTemp, thermal_params.maxTemp, + thermal_params.thermalEnable); + + if (QDF_STATUS_SUCCESS != + wma_set_thermal_mgmt(wma, thermal_params)) { + WMA_LOGE("Could not send thermal mgmt command to the firmware!"); + } + } + return QDF_STATUS_SUCCESS; +} + +/** + * wma_set_thermal_level_ind() - send SME set thermal level indication message + * @level: thermal level + * + * Send SME SET_THERMAL_LEVEL_IND message + * + * Returns: none + */ +static void wma_set_thermal_level_ind(u_int8_t level) +{ + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + cds_msg_t sme_msg = {0}; + + WMA_LOGI(FL("Thermal level: %d"), level); + + sme_msg.type = eWNI_SME_SET_THERMAL_LEVEL_IND; + sme_msg.bodyptr = NULL; + sme_msg.bodyval = level; + + qdf_status = cds_mq_post_message(QDF_MODULE_ID_SME, &sme_msg); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) + WMA_LOGE(FL( + "Fail to post set thermal level ind msg")); +} + +/** + * wma_process_set_thermal_level() - sets thermal level + * @wma: Pointer to WMA handle + * @thermal_level : Thermal level + * + * This function sets the new thermal throttle level in the + * txrx module and sends down the corresponding temperature + * thresholds to the firmware + * + * Returns: QDF_STATUS_SUCCESS for success otherwise failure + */ +QDF_STATUS wma_process_set_thermal_level(tp_wma_handle wma, + uint8_t thermal_level) +{ + ol_txrx_pdev_handle curr_pdev; + + if (NULL == wma) { + WMA_LOGE("TM Invalid input"); + return QDF_STATUS_E_FAILURE; + } + + curr_pdev = cds_get_context(QDF_MODULE_ID_TXRX); + if (NULL == curr_pdev) { + WMA_LOGE("%s: Failed to get pdev", __func__); + return QDF_STATUS_E_FAILURE; + } + + WMA_LOGE("TM set level %d", thermal_level); + + /* Check if thermal mitigation is enabled */ + if (!wma->thermal_mgmt_info.thermalMgmtEnabled) { + WMA_LOGE("Thermal mgmt is not enabled, ignoring set level command"); + return QDF_STATUS_E_FAILURE; + } + + if (thermal_level >= WLAN_WMA_MAX_THERMAL_LEVELS) { + WMA_LOGE("Invalid thermal level set %d", thermal_level); + return QDF_STATUS_E_FAILURE; + } + + if (thermal_level == wma->thermal_mgmt_info.thermalCurrLevel) { + WMA_LOGD("Current level %d is same as the set level, ignoring", + wma->thermal_mgmt_info.thermalCurrLevel); + return QDF_STATUS_SUCCESS; + } + + wma->thermal_mgmt_info.thermalCurrLevel = thermal_level; + + ol_tx_throttle_set_level(curr_pdev, thermal_level); + + /* Send SME SET_THERMAL_LEVEL_IND message */ + wma_set_thermal_level_ind(thermal_level); + + return QDF_STATUS_SUCCESS; +} + + +/** + * wma_set_thermal_mgmt() - set thermal mgmt command to fw + * @wma_handle: Pointer to WMA handle + * @thermal_info: Thermal command information + * + * This function sends the thermal management command + * to the firmware + * + * Return: QDF_STATUS_SUCCESS for success otherwise failure + */ +QDF_STATUS wma_set_thermal_mgmt(tp_wma_handle wma_handle, + t_thermal_cmd_params thermal_info) +{ + struct thermal_cmd_params mgmt_thermal_info = {0}; + + if (!wma_handle) { + WMA_LOGE("%s:'wma_set_thermal_mgmt':invalid input", __func__); + QDF_ASSERT(0); + return QDF_STATUS_E_FAILURE; + } + + mgmt_thermal_info.min_temp = thermal_info.minTemp; + mgmt_thermal_info.max_temp = thermal_info.maxTemp; + mgmt_thermal_info.thermal_enable = thermal_info.thermalEnable; + + return wmi_unified_set_thermal_mgmt_cmd(wma_handle->wmi_handle, + &mgmt_thermal_info); +} + +/** + * wma_thermal_mgmt_get_level() - returns throttle level + * @handle: Pointer to WMA handle + * @temp: temperature + * + * This function returns the thermal(throttle) level + * given the temperature + * + * Return: thermal (throttle) level + */ +static uint8_t wma_thermal_mgmt_get_level(void *handle, uint32_t temp) +{ + tp_wma_handle wma = (tp_wma_handle) handle; + int i; + uint8_t level; + + level = i = wma->thermal_mgmt_info.thermalCurrLevel; + while (temp < wma->thermal_mgmt_info.thermalLevels[i].minTempThreshold + && i > 0) { + i--; + level = i; + } + + i = wma->thermal_mgmt_info.thermalCurrLevel; + while (temp > wma->thermal_mgmt_info.thermalLevels[i].maxTempThreshold + && i < (WLAN_WMA_MAX_THERMAL_LEVELS - 1)) { + i++; + level = i; + } + + WMA_LOGW("Change thermal level from %d -> %d\n", + wma->thermal_mgmt_info.thermalCurrLevel, level); + + return level; +} + +/** + * wma_thermal_mgmt_evt_handler() - thermal mgmt event handler + * @wma_handle: Pointer to WMA handle + * @event: Thermal event information + * + * This function handles the thermal mgmt event from the firmware len + * + * Return: 0 for success otherwise failure + */ +int wma_thermal_mgmt_evt_handler(void *handle, uint8_t *event, + uint32_t len) +{ + tp_wma_handle wma; + wmi_thermal_mgmt_event_fixed_param *tm_event; + uint8_t thermal_level; + t_thermal_cmd_params thermal_params; + WMI_THERMAL_MGMT_EVENTID_param_tlvs *param_buf; + ol_txrx_pdev_handle curr_pdev; + + if (NULL == event || NULL == handle) { + WMA_LOGE("Invalid thermal mitigation event buffer"); + return -EINVAL; + } + + wma = (tp_wma_handle) handle; + + if (NULL == wma) { + WMA_LOGE("%s: Failed to get wma handle", __func__); + return -EINVAL; + } + + param_buf = (WMI_THERMAL_MGMT_EVENTID_param_tlvs *) event; + + curr_pdev = cds_get_context(QDF_MODULE_ID_TXRX); + if (NULL == curr_pdev) { + WMA_LOGE("%s: Failed to get pdev", __func__); + return -EINVAL; + } + + /* Check if thermal mitigation is enabled */ + if (!wma->thermal_mgmt_info.thermalMgmtEnabled) { + WMA_LOGE("Thermal mgmt is not enabled, ignoring event"); + return -EINVAL; + } + + tm_event = param_buf->fixed_param; + WMA_LOGD("Thermal mgmt event received with temperature %d", + tm_event->temperature_degreeC); + + /* Get the thermal mitigation level for the reported temperature */ + thermal_level = + wma_thermal_mgmt_get_level(handle, tm_event->temperature_degreeC); + WMA_LOGD("Thermal mgmt level %d", thermal_level); + + if (thermal_level == wma->thermal_mgmt_info.thermalCurrLevel) { + WMA_LOGD("Current level %d is same as the set level, ignoring", + wma->thermal_mgmt_info.thermalCurrLevel); + return 0; + } + + wma->thermal_mgmt_info.thermalCurrLevel = thermal_level; + + /* Inform txrx */ + ol_tx_throttle_set_level(curr_pdev, thermal_level); + + /* Send SME SET_THERMAL_LEVEL_IND message */ + wma_set_thermal_level_ind(thermal_level); + + /* Get the temperature thresholds to set in firmware */ + thermal_params.minTemp = + wma->thermal_mgmt_info.thermalLevels[thermal_level]. + minTempThreshold; + thermal_params.maxTemp = + wma->thermal_mgmt_info.thermalLevels[thermal_level]. + maxTempThreshold; + thermal_params.thermalEnable = + wma->thermal_mgmt_info.thermalMgmtEnabled; + + if (QDF_STATUS_SUCCESS != wma_set_thermal_mgmt(wma, thermal_params)) { + WMA_LOGE("Could not send thermal mgmt command to the firmware!"); + return -EINVAL; + } + + return 0; +} + +/** + * wma_ibss_peer_info_event_handler() - IBSS peer info event handler + * @handle: wma handle + * @data: event data + * @len: length of data + * + * This function handles IBSS peer info event from FW. + * + * Return: 0 for success or error code + */ +int wma_ibss_peer_info_event_handler(void *handle, uint8_t *data, + uint32_t len) +{ + cds_msg_t cds_msg; + wmi_peer_info *peer_info; + ol_txrx_pdev_handle pdev; + tSirIbssPeerInfoParams *pSmeRsp; + uint32_t count, num_peers, status; + tSirIbssGetPeerInfoRspParams *pRsp; + WMI_PEER_INFO_EVENTID_param_tlvs *param_tlvs; + wmi_peer_info_event_fixed_param *fix_param; + uint8_t peer_mac[IEEE80211_ADDR_LEN]; + + pdev = cds_get_context(QDF_MODULE_ID_TXRX); + if (NULL == pdev) { + WMA_LOGE("%s: could not get pdev context", __func__); + return 0; + } + + param_tlvs = (WMI_PEER_INFO_EVENTID_param_tlvs *) data; + fix_param = param_tlvs->fixed_param; + peer_info = param_tlvs->peer_info; + num_peers = fix_param->num_peers; + status = 0; + + WMA_LOGE("%s: num_peers %d", __func__, num_peers); + + pRsp = qdf_mem_malloc(sizeof(tSirIbssGetPeerInfoRspParams)); + if (NULL == pRsp) { + WMA_LOGE("%s: could not allocate memory for ibss peer info rsp len %zu", + __func__, sizeof(tSirIbssGetPeerInfoRspParams)); + return 0; + } + + /*sanity check */ + if ((num_peers > 32) || (NULL == peer_info)) { + WMA_LOGE("%s: Invalid event data from target num_peers %d peer_info %p", + __func__, num_peers, peer_info); + status = 1; + goto send_response; + } + + /* + *For displaying only connected IBSS peer info, iterate till + *last but one entry only as last entry is used for IBSS creator + */ + for (count = 0; count < num_peers-1; count++) { + pSmeRsp = &pRsp->ibssPeerInfoRspParams.peerInfoParams[count]; + + WMI_MAC_ADDR_TO_CHAR_ARRAY(&peer_info->peer_mac_address, + peer_mac); + qdf_mem_copy(pSmeRsp->mac_addr, peer_mac, + sizeof(pSmeRsp->mac_addr)); + pSmeRsp->mcsIndex = 0; + pSmeRsp->rssi = peer_info->rssi + WMA_TGT_NOISE_FLOOR_DBM; + pSmeRsp->txRate = peer_info->data_rate; + pSmeRsp->txRateFlags = 0; + + WMA_LOGE("peer " MAC_ADDRESS_STR "rssi %d txRate %d", + MAC_ADDR_ARRAY(peer_mac), + pSmeRsp->rssi, pSmeRsp->txRate); + + peer_info++; + } + +send_response: + /* message header */ + pRsp->mesgType = eWNI_SME_IBSS_PEER_INFO_RSP; + pRsp->mesgLen = sizeof(tSirIbssGetPeerInfoRspParams); + pRsp->ibssPeerInfoRspParams.status = status; + pRsp->ibssPeerInfoRspParams.numPeers = num_peers; + + /* cds message wrapper */ + cds_msg.type = eWNI_SME_IBSS_PEER_INFO_RSP; + cds_msg.bodyptr = (void *)pRsp; + cds_msg.bodyval = 0; + + if (QDF_STATUS_SUCCESS != + cds_mq_post_message(CDS_MQ_ID_SME, (cds_msg_t *) &cds_msg)) { + WMA_LOGE("%s: could not post peer info rsp msg to SME", + __func__); + /* free the mem and return */ + qdf_mem_free((void *)pRsp); + } + + return 0; +} + +/** + * wma_fast_tx_fail_event_handler() -tx failure event handler + * @handle: wma handle + * @data: event data + * @len: data length + * + * Handle fast tx failure indication event from FW + * + * Return: 0 for success or error code. + */ +int wma_fast_tx_fail_event_handler(void *handle, uint8_t *data, + uint32_t len) +{ + uint8_t tx_fail_cnt; + uint8_t peer_mac[IEEE80211_ADDR_LEN]; + tp_wma_handle wma = (tp_wma_handle) handle; + WMI_PEER_TX_FAIL_CNT_THR_EVENTID_param_tlvs *param_tlvs; + wmi_peer_tx_fail_cnt_thr_event_fixed_param *fix_param; + + param_tlvs = (WMI_PEER_TX_FAIL_CNT_THR_EVENTID_param_tlvs *) data; + fix_param = param_tlvs->fixed_param; + + WMI_MAC_ADDR_TO_CHAR_ARRAY(&fix_param->peer_mac_address, peer_mac); + WMA_LOGE("%s: received fast tx failure event for peer" + " 0x:%2x:0x%2x:0x%2x:0x%2x:0x%2x:0x%2x seq No %d", __func__, + peer_mac[0], peer_mac[1], peer_mac[2], peer_mac[3], + peer_mac[4], peer_mac[5], fix_param->seq_no); + + tx_fail_cnt = fix_param->seq_no; + + /*call HDD callback */ + if (NULL != wma->hddTxFailCb) { + wma->hddTxFailCb(peer_mac, tx_fail_cnt); + } else { + WMA_LOGE("%s: HDD callback is %p", __func__, wma->hddTxFailCb); + } + + return 0; +} + +/** + * wma_decap_to_8023() - Decapsulate to 802.3 format + * @msdu: skb buffer + * @info: decapsulate info + * + * Return: none + */ +static void wma_decap_to_8023(qdf_nbuf_t msdu, struct wma_decap_info_t *info) +{ + struct llc_snap_hdr_t *llc_hdr; + uint16_t ether_type; + uint16_t l2_hdr_space; + struct ieee80211_qosframe_addr4 *wh; + uint8_t local_buf[ETHERNET_HDR_LEN]; + uint8_t *buf; + struct ethernet_hdr_t *ethr_hdr; + + buf = (uint8_t *) qdf_nbuf_data(msdu); + llc_hdr = (struct llc_snap_hdr_t *)buf; + ether_type = (llc_hdr->ethertype[0] << 8) | llc_hdr->ethertype[1]; + /* do llc remove if needed */ + l2_hdr_space = 0; + if (IS_SNAP(llc_hdr)) { + if (IS_BTEP(llc_hdr)) { + /* remove llc */ + l2_hdr_space += sizeof(struct llc_snap_hdr_t); + llc_hdr = NULL; + } else if (IS_RFC1042(llc_hdr)) { + if (!(ether_type == ETHERTYPE_AARP || + ether_type == ETHERTYPE_IPX)) { + /* remove llc */ + l2_hdr_space += sizeof(struct llc_snap_hdr_t); + llc_hdr = NULL; + } + } + } + if (l2_hdr_space > ETHERNET_HDR_LEN) { + buf = qdf_nbuf_pull_head(msdu, l2_hdr_space - ETHERNET_HDR_LEN); + } else if (l2_hdr_space < ETHERNET_HDR_LEN) { + buf = qdf_nbuf_push_head(msdu, ETHERNET_HDR_LEN - l2_hdr_space); + } + + /* mpdu hdr should be present in info,re-create ethr_hdr based on mpdu hdr */ + wh = (struct ieee80211_qosframe_addr4 *)info->hdr; + ethr_hdr = (struct ethernet_hdr_t *)local_buf; + switch (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) { + case IEEE80211_FC1_DIR_NODS: + qdf_mem_copy(ethr_hdr->dest_addr, wh->i_addr1, + ETHERNET_ADDR_LEN); + qdf_mem_copy(ethr_hdr->src_addr, wh->i_addr2, + ETHERNET_ADDR_LEN); + break; + case IEEE80211_FC1_DIR_TODS: + qdf_mem_copy(ethr_hdr->dest_addr, wh->i_addr3, + ETHERNET_ADDR_LEN); + qdf_mem_copy(ethr_hdr->src_addr, wh->i_addr2, + ETHERNET_ADDR_LEN); + break; + case IEEE80211_FC1_DIR_FROMDS: + qdf_mem_copy(ethr_hdr->dest_addr, wh->i_addr1, + ETHERNET_ADDR_LEN); + qdf_mem_copy(ethr_hdr->src_addr, wh->i_addr3, + ETHERNET_ADDR_LEN); + break; + case IEEE80211_FC1_DIR_DSTODS: + qdf_mem_copy(ethr_hdr->dest_addr, wh->i_addr3, + ETHERNET_ADDR_LEN); + qdf_mem_copy(ethr_hdr->src_addr, wh->i_addr4, + ETHERNET_ADDR_LEN); + break; + } + + if (llc_hdr == NULL) { + ethr_hdr->ethertype[0] = (ether_type >> 8) & 0xff; + ethr_hdr->ethertype[1] = (ether_type) & 0xff; + } else { + uint32_t pktlen = + qdf_nbuf_len(msdu) - sizeof(ethr_hdr->ethertype); + ether_type = (uint16_t) pktlen; + ether_type = qdf_nbuf_len(msdu) - sizeof(struct ethernet_hdr_t); + ethr_hdr->ethertype[0] = (ether_type >> 8) & 0xff; + ethr_hdr->ethertype[1] = (ether_type) & 0xff; + } + qdf_mem_copy(buf, ethr_hdr, ETHERNET_HDR_LEN); +} + +/** + * wma_ieee80211_hdrsize() - get 802.11 header size + * @data: 80211 frame + * + * Return: size of header + */ +static int32_t wma_ieee80211_hdrsize(const void *data) +{ + const struct ieee80211_frame *wh = (const struct ieee80211_frame *)data; + int32_t size = sizeof(struct ieee80211_frame); + + if ((wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) == IEEE80211_FC1_DIR_DSTODS) + size += IEEE80211_ADDR_LEN; + if (IEEE80211_QOS_HAS_SEQ(wh)) + size += sizeof(uint16_t); + return size; +} + +/** + * wmi_desc_pool_init() - Initialize the WMI descriptor pool + * @wma_handle: handle to wma + * @pool_size: Size of wma pool + * + * Return: 0 for success, error code on failure. + */ +int wmi_desc_pool_init(tp_wma_handle wma_handle, uint32_t pool_size) +{ + int i; + + if (!pool_size) { + WMA_LOGE("%s: failed to allocate desc pool", __func__); + qdf_assert_always(pool_size); + return -EINVAL; + } + WMA_LOGE("%s: initialize desc pool of size %d", __func__, pool_size); + wma_handle->wmi_desc_pool.pool_size = pool_size; + wma_handle->wmi_desc_pool.num_free = pool_size; + wma_handle->wmi_desc_pool.array = qdf_mem_malloc(pool_size * + sizeof(union wmi_desc_elem_t)); + if (!wma_handle->wmi_desc_pool.array) { + WMA_LOGE("%s: failed to allocate desc pool", __func__); + return -ENOMEM; + } + wma_handle->wmi_desc_pool.freelist = &wma_handle-> + wmi_desc_pool.array[0]; + + for (i = 0; i < (pool_size - 1); i++) { + wma_handle->wmi_desc_pool.array[i].wmi_desc.desc_id = i; + wma_handle->wmi_desc_pool.array[i].next = + &wma_handle->wmi_desc_pool.array[i + 1]; + } + + wma_handle->wmi_desc_pool.array[i].next = NULL; + wma_handle->wmi_desc_pool.array[i].wmi_desc.desc_id = i; + + qdf_spinlock_create(&wma_handle->wmi_desc_pool.wmi_desc_pool_lock); + return 0; +} + +/** + * wmi_desc_pool_deinit() - Deinitialize the WMI descriptor pool + * @wma_handle: handle to wma + * + * Return: None + */ +void wmi_desc_pool_deinit(tp_wma_handle wma_handle) +{ + struct wmi_desc_t *wmi_desc; + uint8_t i; + + qdf_spin_lock_bh(&wma_handle->wmi_desc_pool.wmi_desc_pool_lock); + if (wma_handle->wmi_desc_pool.array) { + for (i = 0; i < wma_handle->wmi_desc_pool.pool_size; i++) { + wmi_desc = (struct wmi_desc_t *) + (&wma_handle->wmi_desc_pool.array[i]); + if (wmi_desc && wmi_desc->nbuf) + cds_packet_free(wmi_desc->nbuf); + } + qdf_mem_free(wma_handle->wmi_desc_pool.array); + wma_handle->wmi_desc_pool.array = NULL; + } else { + WMA_LOGE("%s: Empty WMI descriptor pool", __func__); + } + + wma_handle->wmi_desc_pool.freelist = NULL; + wma_handle->wmi_desc_pool.pool_size = 0; + wma_handle->wmi_desc_pool.num_free = 0; + qdf_spin_unlock_bh(&wma_handle->wmi_desc_pool.wmi_desc_pool_lock); + qdf_spinlock_destroy(&wma_handle->wmi_desc_pool.wmi_desc_pool_lock); +} + +/* WMI MGMT TX wake lock timeout in milli seconds */ +#define WMI_MGMT_TX_WAKE_LOCK_DURATION 300 + +/** + * wmi_desc_get() - Get wmi descriptor from wmi free descriptor pool + * @wma_handle: handle to wma + * + * Return: pointer to wmi descriptor, NULL on failure + */ +struct wmi_desc_t *wmi_desc_get(tp_wma_handle wma_handle) +{ + struct wmi_desc_t *wmi_desc = NULL; + uint16_t num_free; + + qdf_spin_lock_bh(&wma_handle->wmi_desc_pool.wmi_desc_pool_lock); + if (wma_handle->wmi_desc_pool.freelist) { + wma_handle->wmi_desc_pool.num_free--; + wmi_desc = &wma_handle->wmi_desc_pool.freelist->wmi_desc; + wma_handle->wmi_desc_pool.freelist = + wma_handle->wmi_desc_pool.freelist->next; + + qdf_wake_lock_timeout_acquire(&wma_handle->wow_wake_lock, + WMI_MGMT_TX_WAKE_LOCK_DURATION); + + num_free = wma_handle->wmi_desc_pool.num_free; + } + qdf_spin_unlock_bh(&wma_handle->wmi_desc_pool.wmi_desc_pool_lock); + + if (wmi_desc) + WMA_LOGD("%s: num_free %d desc_id %d", + __func__, num_free, wmi_desc->desc_id); + else + WMA_LOGE("%s: WMI descriptors are exhausted", __func__); + + return wmi_desc; +} + +/** + * wmi_desc_put() - Put wmi descriptor to wmi free descriptor pool + * @wma_handle: handle to wma + * @wmi_desc: wmi descriptor + * + * Return: None + */ +void wmi_desc_put(tp_wma_handle wma_handle, struct wmi_desc_t *wmi_desc) +{ + uint16_t num_free; + + qdf_spin_lock_bh(&wma_handle->wmi_desc_pool.wmi_desc_pool_lock); + ((union wmi_desc_elem_t *)wmi_desc)->next = + wma_handle->wmi_desc_pool.freelist; + wma_handle->wmi_desc_pool.freelist = (union wmi_desc_elem_t *)wmi_desc; + wma_handle->wmi_desc_pool.num_free++; + + if (wma_handle->wmi_desc_pool.num_free == + wma_handle->wmi_desc_pool.pool_size) + qdf_wake_lock_release(&wma_handle->wow_wake_lock, + WIFI_POWER_EVENT_WAKELOCK_MGMT_TX); + + num_free = wma_handle->wmi_desc_pool.num_free; + + qdf_spin_unlock_bh(&wma_handle->wmi_desc_pool.wmi_desc_pool_lock); + + WMA_LOGD("%s: num_free %d desc_id %d", + __func__, num_free, wmi_desc->desc_id); +} + +/** + * wma_tx_packet() - Sends Tx Frame to TxRx + * @wma_context: wma context + * @tx_frame: frame buffer + * @frmLen: frame length + * @frmType: frame type + * @txDir: tx diection + * @tid: TID + * @tx_frm_download_comp_cb: tx download callback handler + * @tx_frm_ota_comp_cb: OTA complition handler + * @tx_flag: tx flag + * @vdev_id: vdev id + * @tdlsFlag: tdls flag + * + * This function sends the frame corresponding to the + * given vdev id. + * This is blocking call till the downloading of frame is complete. + * + * Return: QDF status + */ +QDF_STATUS wma_tx_packet(void *wma_context, void *tx_frame, uint16_t frmLen, + eFrameType frmType, eFrameTxDir txDir, uint8_t tid, + pWMATxRxCompFunc tx_frm_download_comp_cb, void *pData, + pWMAAckFnTxComp tx_frm_ota_comp_cb, uint8_t tx_flag, + uint8_t vdev_id, bool tdlsFlag, uint16_t channel_freq) +{ + tp_wma_handle wma_handle = (tp_wma_handle) (wma_context); + int32_t status; + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + int32_t is_high_latency; + ol_txrx_vdev_handle txrx_vdev; + enum frame_index tx_frm_index = GENERIC_NODOWNLD_NOACK_COMP_INDEX; + tpSirMacFrameCtl pFc = (tpSirMacFrameCtl) (qdf_nbuf_data(tx_frame)); + uint8_t use_6mbps = 0; + uint8_t downld_comp_required = 0; + uint16_t chanfreq; +#ifdef WLAN_FEATURE_11W + uint8_t *pFrame = NULL; + void *pPacket = NULL; + uint16_t newFrmLen = 0; +#endif /* WLAN_FEATURE_11W */ + struct wma_txrx_node *iface; + tpAniSirGlobal pMac; + tpSirMacMgmtHdr mHdr; + struct wmi_mgmt_params mgmt_param = {0}; + struct wmi_desc_t *wmi_desc = NULL; + ol_pdev_handle ctrl_pdev; + + if (NULL == wma_handle) { + WMA_LOGE("wma_handle is NULL"); + cds_packet_free((void *)tx_frame); + return QDF_STATUS_E_FAILURE; + } + iface = &wma_handle->interfaces[vdev_id]; + /* Get the vdev handle from vdev id */ + txrx_vdev = wma_handle->interfaces[vdev_id].handle; + + if (!txrx_vdev) { + WMA_LOGE("TxRx Vdev Handle is NULL"); + cds_packet_free((void *)tx_frame); + return QDF_STATUS_E_FAILURE; + } + + ol_txrx_hl_tdls_flag_reset(txrx_vdev, false); + + if (frmType >= TXRX_FRM_MAX) { + WMA_LOGE("Invalid Frame Type Fail to send Frame"); + cds_packet_free((void *)tx_frame); + return QDF_STATUS_E_FAILURE; + } + + pMac = cds_get_context(QDF_MODULE_ID_PE); + if (!pMac) { + WMA_LOGE("pMac Handle is NULL"); + cds_packet_free((void *)tx_frame); + return QDF_STATUS_E_FAILURE; + } + /* + * Currently only support to + * send 80211 Mgmt and 80211 Data are added. + */ + if (!((frmType == TXRX_FRM_802_11_MGMT) || + (frmType == TXRX_FRM_802_11_DATA))) { + WMA_LOGE("No Support to send other frames except 802.11 Mgmt/Data"); + cds_packet_free((void *)tx_frame); + return QDF_STATUS_E_FAILURE; + } +#ifdef WLAN_FEATURE_11W + if ((iface && iface->rmfEnabled) && + (frmType == TXRX_FRM_802_11_MGMT) && + (pFc->subType == SIR_MAC_MGMT_DISASSOC || + pFc->subType == SIR_MAC_MGMT_DEAUTH || + pFc->subType == SIR_MAC_MGMT_ACTION)) { + struct ieee80211_frame *wh = + (struct ieee80211_frame *)qdf_nbuf_data(tx_frame); + if (!IEEE80211_IS_BROADCAST(wh->i_addr1) && + !IEEE80211_IS_MULTICAST(wh->i_addr1)) { + if (pFc->wep) { + /* Allocate extra bytes for privacy header and trailer */ + newFrmLen = frmLen + IEEE80211_CCMP_HEADERLEN + + IEEE80211_CCMP_MICLEN; + qdf_status = + cds_packet_alloc((uint16_t) newFrmLen, + (void **)&pFrame, + (void **)&pPacket); + + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + WMA_LOGP("%s: Failed to allocate %d bytes for RMF status " + "code (%x)", __func__, newFrmLen, + qdf_status); + /* Free the original packet memory */ + cds_packet_free((void *)tx_frame); + goto error; + } + + /* + * Initialize the frame with 0's and only fill + * MAC header and data, Keep the CCMP header and + * trailer as 0's, firmware shall fill this + */ + qdf_mem_set(pFrame, newFrmLen, 0); + qdf_mem_copy(pFrame, wh, sizeof(*wh)); + qdf_mem_copy(pFrame + sizeof(*wh) + + IEEE80211_CCMP_HEADERLEN, + pData + sizeof(*wh), + frmLen - sizeof(*wh)); + + cds_packet_free((void *)tx_frame); + tx_frame = pPacket; + pData = pFrame; + frmLen = newFrmLen; + pFc = (tpSirMacFrameCtl) + (qdf_nbuf_data(tx_frame)); + } + } else { + /* Allocate extra bytes for MMIE */ + newFrmLen = frmLen + IEEE80211_MMIE_LEN; + qdf_status = cds_packet_alloc((uint16_t) newFrmLen, + (void **)&pFrame, + (void **)&pPacket); + + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + WMA_LOGP("%s: Failed to allocate %d bytes for RMF status " + "code (%x)", __func__, newFrmLen, + qdf_status); + /* Free the original packet memory */ + cds_packet_free((void *)tx_frame); + goto error; + } + /* + * Initialize the frame with 0's and only fill + * MAC header and data. MMIE field will be + * filled by cds_attach_mmie API + */ + qdf_mem_set(pFrame, newFrmLen, 0); + qdf_mem_copy(pFrame, wh, sizeof(*wh)); + qdf_mem_copy(pFrame + sizeof(*wh), + pData + sizeof(*wh), frmLen - sizeof(*wh)); + if (!cds_attach_mmie(iface->key.key, + iface->key.key_id[0].ipn, + WMA_IGTK_KEY_INDEX_4, + pFrame, + pFrame + newFrmLen, newFrmLen)) { + WMA_LOGP("%s: Failed to attach MMIE at the end of " + "frame", __func__); + /* Free the original packet memory */ + cds_packet_free((void *)tx_frame); + goto error; + } + cds_packet_free((void *)tx_frame); + tx_frame = pPacket; + pData = pFrame; + frmLen = newFrmLen; + pFc = (tpSirMacFrameCtl) (qdf_nbuf_data(tx_frame)); + } + } +#endif /* WLAN_FEATURE_11W */ + mHdr = (tpSirMacMgmtHdr)qdf_nbuf_data(tx_frame); + if ((frmType == TXRX_FRM_802_11_MGMT) && + (pFc->subType == SIR_MAC_MGMT_PROBE_RSP)) { + uint64_t adjusted_tsf_le; + struct ieee80211_frame *wh = + (struct ieee80211_frame *)qdf_nbuf_data(tx_frame); + + /* Make the TSF offset negative to match TSF in beacons */ + adjusted_tsf_le = cpu_to_le64(0ULL - + wma_handle->interfaces[vdev_id]. + tsfadjust); + A_MEMCPY(&wh[1], &adjusted_tsf_le, sizeof(adjusted_tsf_le)); + } + if (frmType == TXRX_FRM_802_11_DATA) { + qdf_nbuf_t ret; + qdf_nbuf_t skb = (qdf_nbuf_t) tx_frame; + ol_txrx_pdev_handle pdev = + cds_get_context(QDF_MODULE_ID_TXRX); + + struct wma_decap_info_t decap_info; + struct ieee80211_frame *wh = + (struct ieee80211_frame *)qdf_nbuf_data(skb); + unsigned long curr_timestamp = qdf_mc_timer_get_system_ticks(); + + if (pdev == NULL) { + WMA_LOGE("%s: pdev pointer is not available", __func__); + cds_packet_free((void *)tx_frame); + return QDF_STATUS_E_FAULT; + } + + /* + * 1) TxRx Module expects data input to be 802.3 format + * So Decapsulation has to be done. + * 2) Only one Outstanding Data pending for Ack is allowed + */ + if (tx_frm_ota_comp_cb) { + if (wma_handle->umac_data_ota_ack_cb) { + /* + * If last data frame was sent more than 5 seconds + * ago and still we did not receive ack/nack from + * fw then allow Tx of this data frame + */ + if (curr_timestamp >= + wma_handle->last_umac_data_ota_timestamp + + 500) { + WMA_LOGE("%s: No Tx Ack for last data frame for more than 5 secs, allow Tx of current data frame", + __func__); + } else { + WMA_LOGE("%s: Already one Data pending for Ack, reject Tx of data frame", + __func__); + cds_packet_free((void *)tx_frame); + return QDF_STATUS_E_FAILURE; + } + } + } else { + /* + * Data Frames are sent through TxRx Non Standard Data Path + * so Ack Complete Cb is must + */ + WMA_LOGE("No Ack Complete Cb. Don't Allow"); + cds_packet_free((void *)tx_frame); + return QDF_STATUS_E_FAILURE; + } + + /* Take out 802.11 header from skb */ + decap_info.hdr_len = wma_ieee80211_hdrsize(wh); + qdf_mem_copy(decap_info.hdr, wh, decap_info.hdr_len); + qdf_nbuf_pull_head(skb, decap_info.hdr_len); + + /* Decapsulate to 802.3 format */ + wma_decap_to_8023(skb, &decap_info); + + /* Zero out skb's context buffer for the driver to use */ + qdf_mem_set(skb->cb, sizeof(skb->cb), 0); + + /* Terminate the (single-element) list of tx frames */ + skb->next = NULL; + + /* Store the Ack Complete Cb */ + wma_handle->umac_data_ota_ack_cb = tx_frm_ota_comp_cb; + + /* Store the timestamp and nbuf for this data Tx */ + wma_handle->last_umac_data_ota_timestamp = curr_timestamp; + wma_handle->last_umac_data_nbuf = skb; + + /* Send the Data frame to TxRx in Non Standard Path */ + ol_txrx_hl_tdls_flag_reset(txrx_vdev, tdlsFlag); + + ret = ol_tx_non_std(txrx_vdev, OL_TX_SPEC_NO_FREE, skb); + + ol_txrx_hl_tdls_flag_reset(txrx_vdev, false); + + if (ret) { + WMA_LOGE("TxRx Rejected. Fail to do Tx"); + /* Call Download Cb so that umac can free the buffer */ + if (tx_frm_download_comp_cb) + tx_frm_download_comp_cb(wma_handle->mac_context, + tx_frame, + WMA_TX_FRAME_BUFFER_FREE); + wma_handle->umac_data_ota_ack_cb = NULL; + wma_handle->last_umac_data_nbuf = NULL; + return QDF_STATUS_E_FAILURE; + } + + /* Call Download Callback if passed */ + if (tx_frm_download_comp_cb) + tx_frm_download_comp_cb(wma_handle->mac_context, + tx_frame, + WMA_TX_FRAME_BUFFER_NO_FREE); + + return QDF_STATUS_SUCCESS; + } + + ctrl_pdev = ol_txrx_get_ctrl_pdev_from_vdev(txrx_vdev); + if (ctrl_pdev == NULL) { + WMA_LOGE("ol_pdev_handle is NULL\n"); + cds_packet_free((void *)tx_frame); + return QDF_STATUS_E_FAILURE; + } + is_high_latency = ol_cfg_is_high_latency(ctrl_pdev); + + downld_comp_required = tx_frm_download_comp_cb && is_high_latency && + tx_frm_ota_comp_cb; + + /* Fill the frame index to send */ + if (pFc->type == SIR_MAC_MGMT_FRAME) { + if (tx_frm_ota_comp_cb) { + if (downld_comp_required) + tx_frm_index = + GENERIC_DOWNLD_COMP_ACK_COMP_INDEX; + else + tx_frm_index = GENERIC_NODOWLOAD_ACK_COMP_INDEX; + + /* Store the Ack Cb sent by UMAC */ + if (pFc->subType < SIR_MAC_MGMT_RESERVED15) { + wma_handle->umac_ota_ack_cb[pFc->subType] = + tx_frm_ota_comp_cb; + } + } else { + if (downld_comp_required) + tx_frm_index = + GENERIC_DOWNLD_COMP_NOACK_COMP_INDEX; + else + tx_frm_index = + GENERIC_NODOWNLD_NOACK_COMP_INDEX; + } + } + + /* + * If Dowload Complete is required + * Wait for download complete + */ + if (downld_comp_required) { + /* Store Tx Comp Cb */ + wma_handle->tx_frm_download_comp_cb = tx_frm_download_comp_cb; + + /* Reset the Tx Frame Complete Event */ + qdf_status = + qdf_event_reset(&wma_handle->tx_frm_download_comp_event); + + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + WMA_LOGP("%s: Event Reset failed tx comp event %x", + __func__, qdf_status); + goto error; + } + } + + /* If the frame has to be sent at BD Rate2 inform TxRx */ + if (tx_flag & HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME) + use_6mbps = 1; + + if (wma_handle->interfaces[vdev_id].scan_info.chan_freq != 0) { + chanfreq = wma_handle->interfaces[vdev_id].scan_info.chan_freq; + WMA_LOGI("%s: Preauth frame on channel %d", __func__, chanfreq); + } else if (pFc->subType == SIR_MAC_MGMT_PROBE_RSP) { + if ((wma_is_vdev_in_ap_mode(wma_handle, vdev_id)) && + (0 != wma_handle->interfaces[vdev_id].mhz)) + chanfreq = wma_handle->interfaces[vdev_id].mhz; + else + chanfreq = channel_freq; + WMA_LOGI("%s: Probe response frame on channel %d vdev:%d", + __func__, chanfreq, vdev_id); + if (wma_is_vdev_in_ap_mode(wma_handle, vdev_id) && !chanfreq) + WMA_LOGE("%s: AP oper chan is zero", __func__); + } else if (pFc->subType == SIR_MAC_MGMT_ACTION) { + chanfreq = channel_freq; + } else { + chanfreq = 0; + } + if (pMac->fEnableDebugLog & 0x1) { + if ((pFc->type == SIR_MAC_MGMT_FRAME) && + (pFc->subType != SIR_MAC_MGMT_PROBE_REQ) && + (pFc->subType != SIR_MAC_MGMT_PROBE_RSP)) { + WMA_LOGE("TX MGMT - Type %hu, SubType %hu seq_num[%d]", + pFc->type, pFc->subType, + ((mHdr->seqControl.seqNumHi << 4) | + mHdr->seqControl.seqNumLo)); + } + } + + if (WMI_SERVICE_IS_ENABLED(wma_handle->wmi_service_bitmap, + WMI_SERVICE_MGMT_TX_WMI)) { + mgmt_param.tx_frame = tx_frame; + mgmt_param.frm_len = frmLen; + mgmt_param.vdev_id = vdev_id; + mgmt_param.pdata = pData; + mgmt_param.chanfreq = chanfreq; + mgmt_param.qdf_ctx = cds_get_context(QDF_MODULE_ID_QDF_DEVICE); + wmi_desc = wmi_desc_get(wma_handle); + if (!wmi_desc) { + /* Countinous failure can cause flooding of logs */ + if (!qdf_do_mod(wma_handle->wmi_desc_fail_count, + MAX_PRINT_FAILURE_CNT)) + WMA_LOGE("%s: Failed to get wmi_desc", + __func__); + else + WMA_LOGD("%s: Failed to get wmi_desc", + __func__); + + wma_handle->wmi_desc_fail_count++; + status = QDF_STATUS_E_FAILURE; + } else { + mgmt_param.desc_id = wmi_desc->desc_id; + wmi_desc->vdev_id = vdev_id; + status = wmi_mgmt_unified_cmd_send( + wma_handle->wmi_handle, + &mgmt_param); + if (status) { + wmi_desc_put(wma_handle, wmi_desc); + } else { + wmi_desc->nbuf = tx_frame; + wmi_desc->tx_cmpl_cb = tx_frm_download_comp_cb; + wmi_desc->ota_post_proc_cb = tx_frm_ota_comp_cb; + } + } + } else { + /* Hand over the Tx Mgmt frame to TxRx */ + status = ol_txrx_mgmt_send_ext(txrx_vdev, tx_frame, + tx_frm_index, use_6mbps, chanfreq); + } + + /* + * Failed to send Tx Mgmt Frame + */ + if (status) { + /* Call Download Cb so that umac can free the buffer */ + if (tx_frm_download_comp_cb) + tx_frm_download_comp_cb(wma_handle->mac_context, + tx_frame, + WMA_TX_FRAME_BUFFER_FREE); + if (!qdf_do_mod(wma_handle->tx_fail_cnt, MAX_PRINT_FAILURE_CNT)) + WMA_LOGE("%s: Failed to send Mgmt Frame", __func__); + else + WMA_LOGD("%s: Failed to send Mgmt Frame", __func__); + wma_handle->tx_fail_cnt++; + goto error; + } + + if (!tx_frm_download_comp_cb) + return QDF_STATUS_SUCCESS; + + /* + * Wait for Download Complete + * if required + */ + if (downld_comp_required) { + /* + * Wait for Download Complete + * @ Integrated : Dxe Complete + * @ Discrete : Target Download Complete + */ + qdf_status = + qdf_wait_single_event(&wma_handle-> + tx_frm_download_comp_event, + WMA_TX_FRAME_COMPLETE_TIMEOUT); + + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + WMA_LOGP("Wait Event failed txfrm_comp_event"); + /* + * @Integrated: Something Wrong with Dxe + * TODO: Some Debug Code + * Here We need to trigger SSR since + * since system went into a bad state where + * we didn't get Download Complete for almost + * WMA_TX_FRAME_COMPLETE_TIMEOUT (1 sec) + */ + + /* display scheduler stats */ + ol_txrx_display_stats(WLAN_SCHEDULER_STATS); + } + } + + return QDF_STATUS_SUCCESS; + +error: + wma_handle->tx_frm_download_comp_cb = NULL; + return QDF_STATUS_E_FAILURE; +} + +/** + * wma_ds_peek_rx_packet_info() - peek rx packet info + * @pkt: packet + * @pkt_meta: packet meta + * @bSwap: byte swap + * + * Function fills the rx packet meta info from the the cds packet + * + * Return: QDF status + */ +QDF_STATUS wma_ds_peek_rx_packet_info(cds_pkt_t *pkt, void **pkt_meta, + bool bSwap) +{ + /* Sanity Check */ + if (pkt == NULL) { + WMA_LOGE("wma:Invalid parameter sent on wma_peek_rx_pkt_info"); + return QDF_STATUS_E_FAULT; + } + + *pkt_meta = &(pkt->pkt_meta); + + return QDF_STATUS_SUCCESS; +} + +/** + * ol_rx_err() - ol rx err handler + * @pdev: ol pdev + * @vdev_id: vdev id + * @peer_mac_addr: peer mac address + * @tid: TID + * @tsf32: TSF + * @err_type: error type + * @rx_frame: rx frame + * @pn: PN Number + * @key_id: key id + * + * This function handles rx error and send MIC error failure to LIM + * + * Return: none + */ +void ol_rx_err(ol_pdev_handle pdev, uint8_t vdev_id, + uint8_t *peer_mac_addr, int tid, uint32_t tsf32, + enum ol_rx_err_type err_type, qdf_nbuf_t rx_frame, + uint64_t *pn, uint8_t key_id) +{ + tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA); + tpSirSmeMicFailureInd mic_err_ind; + struct ether_header *eth_hdr; + cds_msg_t cds_msg; + + if (NULL == wma) { + WMA_LOGE("%s: Failed to get wma", __func__); + return; + } + + if (err_type != OL_RX_ERR_TKIP_MIC) + return; + + if (qdf_nbuf_len(rx_frame) < sizeof(*eth_hdr)) + return; + eth_hdr = (struct ether_header *)qdf_nbuf_data(rx_frame); + mic_err_ind = qdf_mem_malloc(sizeof(*mic_err_ind)); + if (!mic_err_ind) { + WMA_LOGE("%s: Failed to allocate memory for MIC indication message", + __func__); + return; + } + + mic_err_ind->messageType = eWNI_SME_MIC_FAILURE_IND; + mic_err_ind->length = sizeof(*mic_err_ind); + mic_err_ind->sessionId = vdev_id; + qdf_copy_macaddr(&mic_err_ind->bssId, + (struct qdf_mac_addr *) &wma->interfaces[vdev_id].bssid); + qdf_mem_copy(mic_err_ind->info.taMacAddr, + (struct qdf_mac_addr *) peer_mac_addr, + sizeof(tSirMacAddr)); + qdf_mem_copy(mic_err_ind->info.srcMacAddr, + (struct qdf_mac_addr *) eth_hdr->ether_shost, + sizeof(tSirMacAddr)); + qdf_mem_copy(mic_err_ind->info.dstMacAddr, + (struct qdf_mac_addr *) eth_hdr->ether_dhost, + sizeof(tSirMacAddr)); + mic_err_ind->info.keyId = key_id; + mic_err_ind->info.multicast = + IEEE80211_IS_MULTICAST(eth_hdr->ether_dhost); + qdf_mem_copy(mic_err_ind->info.TSC, pn, SIR_CIPHER_SEQ_CTR_SIZE); + + qdf_mem_set(&cds_msg, sizeof(cds_msg_t), 0); + cds_msg.type = eWNI_SME_MIC_FAILURE_IND; + cds_msg.bodyptr = (void *) mic_err_ind; + + if (QDF_STATUS_SUCCESS != + cds_mq_post_message(CDS_MQ_ID_SME, (cds_msg_t *) &cds_msg)) { + WMA_LOGE("%s: could not post mic failure indication to SME", + __func__); + qdf_mem_free((void *)mic_err_ind); + } +} + +/** + * wma_tx_abort() - abort tx + * @vdev_id: vdev id + * + * In case of deauth host abort transmitting packet. + * + * Return: none + */ +void wma_tx_abort(uint8_t vdev_id) +{ +#define PEER_ALL_TID_BITMASK 0xffffffff + tp_wma_handle wma; + uint32_t peer_tid_bitmap = PEER_ALL_TID_BITMASK; + struct wma_txrx_node *iface; + struct peer_flush_params param = {0}; + + wma = cds_get_context(QDF_MODULE_ID_WMA); + if (NULL == wma) { + WMA_LOGE("%s: wma is NULL", __func__); + return; + } + + iface = &wma->interfaces[vdev_id]; + if (!iface->handle) { + WMA_LOGE("%s: Failed to get iface handle: %p", + __func__, iface->handle); + return; + } + WMA_LOGI("%s: vdevid %d bssid %pM", __func__, vdev_id, iface->bssid); + iface->pause_bitmap |= (1 << PAUSE_TYPE_HOST); + ol_txrx_vdev_pause(iface->handle, OL_TXQ_PAUSE_REASON_TX_ABORT); + + /* Flush all TIDs except MGMT TID for this peer in Target */ + peer_tid_bitmap &= ~(0x1 << WMI_MGMT_TID); + param.peer_tid_bitmap = peer_tid_bitmap; + param.vdev_id = vdev_id; + wmi_unified_peer_flush_tids_send(wma->wmi_handle, iface->bssid, + ¶m); +} + +#if defined(FEATURE_LRO) +/** + * wma_lro_config_cmd() - process the LRO config command + * @wma: Pointer to WMA handle + * @wma_lro_cmd: Pointer to LRO configuration parameters + * + * This function sends down the LRO configuration parameters to + * the firmware to enable LRO, sets the TCP flags and sets the + * seed values for the toeplitz hash generation + * + * Return: QDF_STATUS_SUCCESS for success otherwise failure + */ +QDF_STATUS wma_lro_config_cmd(tp_wma_handle wma_handle, + struct wma_lro_config_cmd_t *wma_lro_cmd) +{ + struct wmi_lro_config_cmd_t wmi_lro_cmd = {0}; + + if (NULL == wma_handle || NULL == wma_lro_cmd) { + WMA_LOGE("wma_lro_config_cmd': invalid input!"); + return QDF_STATUS_E_FAILURE; + } + + wmi_lro_cmd.lro_enable = wma_lro_cmd->lro_enable; + wmi_lro_cmd.tcp_flag = wma_lro_cmd->tcp_flag; + wmi_lro_cmd.tcp_flag_mask = wma_lro_cmd->tcp_flag_mask; + qdf_mem_copy(wmi_lro_cmd.toeplitz_hash_ipv4, + wma_lro_cmd->toeplitz_hash_ipv4, + LRO_IPV4_SEED_ARR_SZ * sizeof(uint32_t)); + qdf_mem_copy(wmi_lro_cmd.toeplitz_hash_ipv6, + wma_lro_cmd->toeplitz_hash_ipv6, + LRO_IPV6_SEED_ARR_SZ * sizeof(uint32_t)); + + return wmi_unified_lro_config_cmd(wma_handle->wmi_handle, + &wmi_lro_cmd); +} +#endif + +/** + * wma_indicate_err() - indicate an error to the protocol stack + * @err_type: error type + * @err_info: information associated with the error + * + * This function indicates an error encountered in the data path + * to the protocol stack + * + * Return: none + */ +void +wma_indicate_err( + enum ol_rx_err_type err_type, + struct ol_error_info *err_info) +{ + switch (err_type) { + case OL_RX_ERR_TKIP_MIC: + { + tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA); + tpSirSmeMicFailureInd mic_err_ind; + cds_msg_t cds_msg; + uint8_t vdev_id; + + if (NULL == wma) { + WMA_LOGE("%s: Failed to get wma context", + __func__); + return; + } + + mic_err_ind = qdf_mem_malloc(sizeof(*mic_err_ind)); + if (!mic_err_ind) { + WMA_LOGE("%s: MIC indication mem alloc failed", + __func__); + return; + } + + qdf_mem_set((void *) mic_err_ind, 0, + sizeof(*mic_err_ind)); + mic_err_ind->messageType = eWNI_SME_MIC_FAILURE_IND; + mic_err_ind->length = sizeof(*mic_err_ind); + vdev_id = err_info->u.mic_err.vdev_id; + qdf_copy_macaddr(&mic_err_ind->bssId, + (struct qdf_mac_addr *) &wma->interfaces[vdev_id].bssid); + WMA_LOGE("MIC error: BSSID:%02x:%02x:%02x:%02x:%02x:%02x\n", + mic_err_ind->bssId.bytes[0], mic_err_ind->bssId.bytes[1], + mic_err_ind->bssId.bytes[2], mic_err_ind->bssId.bytes[3], + mic_err_ind->bssId.bytes[4], mic_err_ind->bssId.bytes[5]); + qdf_mem_copy(mic_err_ind->info.taMacAddr, + (struct qdf_mac_addr *) err_info->u.mic_err.ta, + sizeof(tSirMacAddr)); + qdf_mem_copy(mic_err_ind->info.srcMacAddr, + (struct qdf_mac_addr *) err_info->u.mic_err.sa, + sizeof(tSirMacAddr)); + qdf_mem_copy(mic_err_ind->info.dstMacAddr, + (struct qdf_mac_addr *) err_info->u.mic_err.da, + sizeof(tSirMacAddr)); + mic_err_ind->info.keyId = err_info->u.mic_err.key_id; + mic_err_ind->info.multicast = + IEEE80211_IS_MULTICAST(err_info->u.mic_err.da); + qdf_mem_copy(mic_err_ind->info.TSC, + (void *)&err_info-> + u.mic_err.pn, SIR_CIPHER_SEQ_CTR_SIZE); + + qdf_mem_set(&cds_msg, sizeof(cds_msg_t), 0); + cds_msg.type = eWNI_SME_MIC_FAILURE_IND; + cds_msg.bodyptr = (void *) mic_err_ind; + if (QDF_STATUS_SUCCESS != + cds_mq_post_message(CDS_MQ_ID_SME, + (cds_msg_t *) &cds_msg)) { + WMA_LOGE("%s: mic failure ind post to SME failed", + __func__); + qdf_mem_free((void *)mic_err_ind); + } + break; + } + default: + { + WMA_LOGE("%s: unhandled ol error type %d", __func__, err_type); + break; + } + } +} diff --git a/drivers/staging/qcacld-3.0/core/wma/src/wma_dev_if.c b/drivers/staging/qcacld-3.0/core/wma/src/wma_dev_if.c new file mode 100644 index 0000000000000000000000000000000000000000..a9dc6ccd74fda16beb99e1f5335fb9af1dea5552 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/wma/src/wma_dev_if.c @@ -0,0 +1,5073 @@ +/* + * Copyright (c) 2013-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: wma_dev_if.c + * This file contains vdev & peer related operations. + */ + +/* Header files */ + +#include "wma.h" +#include "wma_api.h" +#include "cds_api.h" +#include "wmi_unified_api.h" +#include "wlan_qct_sys.h" +#include "wni_api.h" +#include "ani_global.h" +#include "wmi_unified.h" +#include "wni_cfg.h" +#include "cfg_api.h" + +#include "qdf_nbuf.h" +#include "qdf_types.h" +#include "qdf_mem.h" +#include "ol_txrx_peer_find.h" + +#include "wma_types.h" +#include "lim_api.h" +#include "lim_session_utils.h" + +#include "cds_utils.h" +#include "cds_concurrency.h" + +#if !defined(REMOVE_PKT_LOG) +#include "pktlog_ac.h" +#endif /* REMOVE_PKT_LOG */ + +#include "dbglog_host.h" +#include "csr_api.h" + +#include "dfs.h" +#include "wma_internal.h" + +#include "wma_ocb.h" +#include "cdp_txrx_cfg.h" +#include "cdp_txrx_flow_ctrl_legacy.h" +#include +#include +#include +#include "ol_txrx.h" + + +#include "cds_concurrency.h" +#include "wma_nan_datapath.h" + +/** + * wma_find_vdev_by_addr() - find vdev_id from mac address + * @wma: wma handle + * @addr: mac address + * @vdev_id: return vdev_id + * + * Return: Returns vdev handle or NULL if mac address don't match + */ +void *wma_find_vdev_by_addr(tp_wma_handle wma, uint8_t *addr, + uint8_t *vdev_id) +{ + uint8_t i; + + for (i = 0; i < wma->max_bssid; i++) { + if (qdf_is_macaddr_equal( + (struct qdf_mac_addr *) wma->interfaces[i].addr, + (struct qdf_mac_addr *) addr) == true) { + *vdev_id = i; + return wma->interfaces[i].handle; + } + } + return NULL; +} + + +/** + * wma_is_vdev_in_ap_mode() - check that vdev is in ap mode or not + * @wma: wma handle + * @vdev_id: vdev id + * + * Helper function to know whether given vdev id + * is in AP mode or not. + * + * Return: True/False + */ +bool wma_is_vdev_in_ap_mode(tp_wma_handle wma, uint8_t vdev_id) +{ + struct wma_txrx_node *intf = wma->interfaces; + + if (vdev_id > wma->max_bssid) { + WMA_LOGP("%s: Invalid vdev_id %hu", __func__, vdev_id); + QDF_ASSERT(0); + return false; + } + + if ((intf[vdev_id].type == WMI_VDEV_TYPE_AP) && + ((intf[vdev_id].sub_type == WMI_UNIFIED_VDEV_SUBTYPE_P2P_GO) || + (intf[vdev_id].sub_type == 0))) + return true; + + return false; +} + +#ifdef QCA_IBSS_SUPPORT +/** + * wma_is_vdev_in_ibss_mode() - check that vdev is in ibss mode or not + * @wma: wma handle + * @vdev_id: vdev id + * + * Helper function to know whether given vdev id + * is in IBSS mode or not. + * + * Return: True/False + */ +bool wma_is_vdev_in_ibss_mode(tp_wma_handle wma, uint8_t vdev_id) +{ + struct wma_txrx_node *intf = wma->interfaces; + + if (vdev_id > wma->max_bssid) { + WMA_LOGP("%s: Invalid vdev_id %hu", __func__, vdev_id); + QDF_ASSERT(0); + return false; + } + + if (intf[vdev_id].type == WMI_VDEV_TYPE_IBSS) + return true; + + return false; +} +#endif /* QCA_IBSS_SUPPORT */ + +/** + * wma_find_vdev_by_bssid() - Get the corresponding vdev_id from BSSID + * @wma - wma handle + * @vdev_id - vdev ID + * + * Return: fill vdev_id with appropriate vdev id and return vdev + * handle or NULL if not found. + */ +void *wma_find_vdev_by_bssid(tp_wma_handle wma, uint8_t *bssid, + uint8_t *vdev_id) +{ + int i; + + for (i = 0; i < wma->max_bssid; i++) { + if (qdf_is_macaddr_equal( + (struct qdf_mac_addr *) wma->interfaces[i].bssid, + (struct qdf_mac_addr *) bssid) == true) { + *vdev_id = i; + return wma->interfaces[i].handle; + } + } + + return NULL; +} + +/** + * wma_get_txrx_vdev_type() - return operating mode of vdev + * @type: vdev_type + * + * Return: return operating mode as enum wlan_op_mode type + */ +static enum wlan_op_mode wma_get_txrx_vdev_type(uint32_t type) +{ + enum wlan_op_mode vdev_type = wlan_op_mode_unknown; + switch (type) { + case WMI_VDEV_TYPE_AP: + vdev_type = wlan_op_mode_ap; + break; + case WMI_VDEV_TYPE_STA: + vdev_type = wlan_op_mode_sta; + break; +#ifdef QCA_IBSS_SUPPORT + case WMI_VDEV_TYPE_IBSS: + vdev_type = wlan_op_mode_ibss; + break; +#endif /* QCA_IBSS_SUPPORT */ + case WMI_VDEV_TYPE_OCB: + vdev_type = wlan_op_mode_ocb; + break; + case WMI_VDEV_TYPE_MONITOR: + vdev_type = wlan_op_mode_monitor; + break; + case WMI_VDEV_TYPE_NDI: + vdev_type = wlan_op_mode_ndi; + break; + default: + WMA_LOGE("Invalid vdev type %u", type); + vdev_type = wlan_op_mode_unknown; + } + + return vdev_type; +} + +/** + * wma_find_req() - find target request for vdev id + * @wma: wma handle + * @vdev_id: vdev id + * @type: request type + * + * Find target request for given vdev id & type of request. + * Remove that request from active list. + * + * Return: return target request if found or NULL. + */ +static struct wma_target_req *wma_find_req(tp_wma_handle wma, + uint8_t vdev_id, uint8_t type) +{ + struct wma_target_req *req_msg = NULL; + bool found = false; + qdf_list_node_t *node1 = NULL, *node2 = NULL; + QDF_STATUS status; + + qdf_spin_lock_bh(&wma->wma_hold_req_q_lock); + if (QDF_STATUS_SUCCESS != qdf_list_peek_front(&wma->wma_hold_req_queue, + &node2)) { + qdf_spin_unlock_bh(&wma->wma_hold_req_q_lock); + WMA_LOGE(FL("unable to get msg node from request queue")); + return NULL; + } + + do { + node1 = node2; + req_msg = qdf_container_of(node1, struct wma_target_req, node); + if (req_msg->vdev_id != vdev_id) + continue; + if (req_msg->type != type) + continue; + + found = true; + status = qdf_list_remove_node(&wma->wma_hold_req_queue, node1); + if (QDF_STATUS_SUCCESS != status) { + qdf_spin_unlock_bh(&wma->wma_hold_req_q_lock); + WMA_LOGD(FL("Failed to remove request for vdev_id %d type %d"), + vdev_id, type); + return NULL; + } + break; + } while (QDF_STATUS_SUCCESS == + qdf_list_peek_next(&wma->wma_hold_req_queue, node1, + &node2)); + + qdf_spin_unlock_bh(&wma->wma_hold_req_q_lock); + if (!found) { + WMA_LOGE(FL("target request not found for vdev_id %d type %d"), + vdev_id, type); + return NULL; + } + + WMA_LOGD(FL("target request found for vdev id: %d type %d"), + vdev_id, type); + + return req_msg; +} + +/** + * wma_find_remove_req_msgtype() - find and remove request for vdev id + * @wma: wma handle + * @vdev_id: vdev id + * @msg_type: message request type + * + * Find target request for given vdev id & sub type of request. + * Remove the same from active list. + * + * Return: Success if request found, failure other wise + */ +static struct wma_target_req *wma_find_remove_req_msgtype(tp_wma_handle wma, + uint8_t vdev_id, uint32_t msg_type) +{ + struct wma_target_req *req_msg = NULL; + bool found = false; + qdf_list_node_t *node1 = NULL, *node2 = NULL; + QDF_STATUS status; + + qdf_spin_lock_bh(&wma->wma_hold_req_q_lock); + if (QDF_STATUS_SUCCESS != qdf_list_peek_front(&wma->wma_hold_req_queue, + &node2)) { + qdf_spin_unlock_bh(&wma->wma_hold_req_q_lock); + WMA_LOGE(FL("unable to get msg node from request queue")); + return NULL; + } + + do { + node1 = node2; + req_msg = qdf_container_of(node1, struct wma_target_req, node); + if (req_msg->vdev_id != vdev_id) + continue; + if (req_msg->msg_type != msg_type) + continue; + + found = true; + status = qdf_list_remove_node(&wma->wma_hold_req_queue, node1); + if (QDF_STATUS_SUCCESS != status) { + qdf_spin_unlock_bh(&wma->wma_hold_req_q_lock); + WMA_LOGD(FL("Failed to remove request. vdev_id %d type %d"), + vdev_id, msg_type); + return NULL; + } + break; + } while (QDF_STATUS_SUCCESS == + qdf_list_peek_next(&wma->wma_hold_req_queue, node1, + &node2)); + + qdf_spin_unlock_bh(&wma->wma_hold_req_q_lock); + if (!found) { + WMA_LOGE(FL("target request not found for vdev_id %d type %d"), + vdev_id, msg_type); + return NULL; + } + + WMA_LOGD(FL("target request found for vdev id: %d type %d"), + vdev_id, msg_type); + + return req_msg; +} + + +/** + * wma_find_vdev_req() - find target request for vdev id + * @wma: wma handle + * @vdev_id: vdev id + * @type: request type + * + * Return: return target request if found or NULL. + */ +static struct wma_target_req *wma_find_vdev_req(tp_wma_handle wma, + uint8_t vdev_id, uint8_t type) +{ + struct wma_target_req *req_msg = NULL; + bool found = false; + qdf_list_node_t *node1 = NULL, *node2 = NULL; + QDF_STATUS status; + + qdf_spin_lock_bh(&wma->vdev_respq_lock); + if (QDF_STATUS_SUCCESS != qdf_list_peek_front(&wma->vdev_resp_queue, + &node2)) { + qdf_spin_unlock_bh(&wma->vdev_respq_lock); + WMA_LOGE(FL("unable to get target req from vdev resp queue")); + return NULL; + } + + do { + node1 = node2; + req_msg = qdf_container_of(node1, struct wma_target_req, node); + if (req_msg->vdev_id != vdev_id) + continue; + if (req_msg->type != type) + continue; + + found = true; + status = qdf_list_remove_node(&wma->vdev_resp_queue, node1); + if (QDF_STATUS_SUCCESS != status) { + qdf_spin_unlock_bh(&wma->vdev_respq_lock); + WMA_LOGD(FL("Failed to target req for vdev_id %d type %d"), + vdev_id, type); + return NULL; + } + break; + } while (QDF_STATUS_SUCCESS == + qdf_list_peek_next(&wma->vdev_resp_queue, + node1, &node2)); + + qdf_spin_unlock_bh(&wma->vdev_respq_lock); + if (!found) { + WMA_LOGP(FL("target request not found for vdev_id %d type %d"), + vdev_id, type); + return NULL; + } + WMA_LOGD(FL("target request found for vdev id: %d type %d msg %d"), + vdev_id, type, req_msg->msg_type); + return req_msg; +} + +/** + * wma_send_del_sta_self_resp() - send del sta self resp to Upper layer + * @param: params of del sta resp + * + * Return: none + */ +static inline void wma_send_del_sta_self_resp(struct del_sta_self_params *param) +{ + cds_msg_t sme_msg = {0}; + QDF_STATUS status; + + sme_msg.type = eWNI_SME_DEL_STA_SELF_RSP; + sme_msg.bodyptr = param; + + status = cds_mq_post_message(QDF_MODULE_ID_SME, &sme_msg); + if (!QDF_IS_STATUS_SUCCESS(status)) { + WMA_LOGE("Failed to post eWNI_SME_DEL_STA_SELF_RSP"); + qdf_mem_free(param); + } +} + +/** + * wma_vdev_detach_callback() - send vdev detach response to upper layer + * @ctx: txrx node ptr + * + * Return: none + */ +static void wma_vdev_detach_callback(void *ctx) +{ + tp_wma_handle wma; + struct wma_txrx_node *iface = (struct wma_txrx_node *)ctx; + struct del_sta_self_params *param; + struct wma_target_req *req_msg; + + wma = cds_get_context(QDF_MODULE_ID_WMA); + + if (!wma || !iface->del_staself_req) { + WMA_LOGP("%s: wma %p iface %p", __func__, wma, + iface->del_staself_req); + return; + } + param = (struct del_sta_self_params *) iface->del_staself_req; + iface->del_staself_req = NULL; + WMA_LOGE("%s: sending eWNI_SME_DEL_STA_SELF_RSP for vdev %d", + __func__, param->session_id); + if (!WMI_SERVICE_IS_ENABLED(wma->wmi_service_bitmap, + WMI_SERVICE_SYNC_DELETE_CMDS)) { + req_msg = wma_find_vdev_req(wma, param->session_id, + WMA_TARGET_REQ_TYPE_VDEV_DEL); + if (req_msg) { + WMA_LOGD("%s: Found vdev request for vdev id %d", + __func__, param->session_id); + qdf_mc_timer_stop(&req_msg->event_timeout); + qdf_mc_timer_destroy(&req_msg->event_timeout); + qdf_mem_free(req_msg); + } + } + if (iface->addBssStaContext) + qdf_mem_free(iface->addBssStaContext); + + + if (iface->staKeyParams) + qdf_mem_free(iface->staKeyParams); + + if (iface->stats_rsp) + qdf_mem_free(iface->stats_rsp); + + qdf_mem_zero(iface, sizeof(*iface)); + param->status = QDF_STATUS_SUCCESS; + wma_send_del_sta_self_resp(param); +} + + +/** + * wma_self_peer_remove() - Self peer remove handler + * @wma: wma handle + * @del_sta_self_req_param: vdev id + * @generate_vdev_rsp: request type + * + * Return: success if peer delete command sent to firmware, else failure. + */ + +static QDF_STATUS wma_self_peer_remove(tp_wma_handle wma_handle, + struct del_sta_self_params *del_sta_self_req_param, + uint8_t generate_vdev_rsp) +{ + ol_txrx_peer_handle peer; + ol_txrx_pdev_handle pdev; + uint8_t peer_id; + uint8_t vdev_id = del_sta_self_req_param->session_id; + struct wma_target_req *msg = NULL; + struct del_sta_self_rsp_params *sta_self_wmi_rsp; + + WMA_LOGE("P2P Device: removing self peer %pM", + del_sta_self_req_param->self_mac_addr); + + pdev = cds_get_context(QDF_MODULE_ID_TXRX); + if (NULL == pdev) { + WMA_LOGE("%s: Failed to get pdev", __func__); + return QDF_STATUS_E_FAULT; + } + + peer = ol_txrx_find_peer_by_addr(pdev, + del_sta_self_req_param->self_mac_addr, + &peer_id); + if (!peer) { + WMA_LOGE("%s Failed to find peer %pM", __func__, + del_sta_self_req_param->self_mac_addr); + return QDF_STATUS_SUCCESS; + } + wma_remove_peer(wma_handle, + del_sta_self_req_param->self_mac_addr, + vdev_id, peer, false); + + if (WMI_SERVICE_IS_ENABLED(wma_handle->wmi_service_bitmap, + WMI_SERVICE_SYNC_DELETE_CMDS)) { + sta_self_wmi_rsp = + qdf_mem_malloc(sizeof(struct del_sta_self_rsp_params)); + if (sta_self_wmi_rsp == NULL) { + WMA_LOGP(FL("Failed to allocate memory")); + return QDF_STATUS_E_NOMEM; + } + sta_self_wmi_rsp->self_sta_param = del_sta_self_req_param; + sta_self_wmi_rsp->generate_rsp = generate_vdev_rsp; + msg = wma_fill_hold_req(wma_handle, vdev_id, + WMA_DELETE_STA_REQ, + WMA_DEL_P2P_SELF_STA_RSP_START, + sta_self_wmi_rsp, + WMA_DELETE_STA_TIMEOUT); + if (!msg) { + WMA_LOGP(FL("Failed to allocate request for vdev_id %d"), + vdev_id); + wma_remove_req(wma_handle, vdev_id, + WMA_DEL_P2P_SELF_STA_RSP_START); + return QDF_STATUS_E_FAILURE; + } + } + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS wma_handle_vdev_detach(tp_wma_handle wma_handle, + struct del_sta_self_params *del_sta_self_req_param, + uint8_t generate_rsp) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + uint8_t vdev_id = del_sta_self_req_param->session_id; + struct wma_txrx_node *iface = &wma_handle->interfaces[vdev_id]; + struct wma_target_req *msg = NULL; + + status = wmi_unified_vdev_delete_send(wma_handle->wmi_handle, vdev_id); + if (QDF_IS_STATUS_ERROR(status)) { + WMA_LOGE("Unable to remove an interface"); + goto out; + } + + WMA_LOGE("vdev_id:%hu vdev_hdl:%p", vdev_id, iface->handle); + if (!generate_rsp) { + WMA_LOGE("Call txrx detach w/o callback for vdev %d", vdev_id); + ol_txrx_vdev_detach(iface->handle, NULL, NULL); + iface->handle = NULL; + wma_handle->interfaces[vdev_id].is_vdev_valid = false; + goto out; + } + + iface->del_staself_req = del_sta_self_req_param; + msg = wma_fill_vdev_req(wma_handle, vdev_id, WMA_DEL_STA_SELF_REQ, + WMA_TARGET_REQ_TYPE_VDEV_DEL, iface, 6000); + if (!msg) { + WMA_LOGE("%s: Failed to fill vdev request for vdev_id %d", + __func__, vdev_id); + status = QDF_STATUS_E_NOMEM; + goto out; + } + + /* Acquire wake lock only when you expect a response from firmware */ + if (WMI_SERVICE_IS_ENABLED(wma_handle->wmi_service_bitmap, + WMI_SERVICE_SYNC_DELETE_CMDS)) { + cds_host_diag_log_work(&wma_handle->wmi_cmd_rsp_wake_lock, + WMA_FW_RSP_EVENT_WAKE_LOCK_DURATION, + WIFI_POWER_EVENT_WAKELOCK_WMI_CMD_RSP); + qdf_wake_lock_timeout_acquire( + &wma_handle->wmi_cmd_rsp_wake_lock, + WMA_FW_RSP_EVENT_WAKE_LOCK_DURATION); + qdf_runtime_pm_prevent_suspend( + &wma_handle->wmi_cmd_rsp_runtime_lock); + } + WMA_LOGD("Call txrx detach with callback for vdev %d", vdev_id); + ol_txrx_vdev_detach(iface->handle, NULL, NULL); + iface->handle = NULL; + wma_handle->interfaces[vdev_id].is_vdev_valid = false; + + /* + * send the response immediately if WMI_SERVICE_SYNC_DELETE_CMDS + * service is not supported by firmware + */ + if (!WMI_SERVICE_IS_ENABLED(wma_handle->wmi_service_bitmap, + WMI_SERVICE_SYNC_DELETE_CMDS)) + wma_vdev_detach_callback(iface); + return status; +out: + if (iface->addBssStaContext) + qdf_mem_free(iface->addBssStaContext); + if (iface->staKeyParams) + qdf_mem_free(iface->staKeyParams); + qdf_mem_zero(iface, sizeof(*iface)); + del_sta_self_req_param->status = status; + if (generate_rsp) + wma_send_del_sta_self_resp(del_sta_self_req_param); + return status; +} +/** + * wma_vdev_detach() - send vdev delete command to fw + * @wma_handle: wma handle + * @pdel_sta_self_req_param: del sta params + * @generateRsp: generate Response flag + * + * Return: QDF status + */ +QDF_STATUS wma_vdev_detach(tp_wma_handle wma_handle, + struct del_sta_self_params *pdel_sta_self_req_param, + uint8_t generateRsp) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + uint8_t vdev_id = pdel_sta_self_req_param->session_id; + struct wma_txrx_node *iface = &wma_handle->interfaces[vdev_id]; + + if (qdf_atomic_read(&iface->bss_status) == WMA_BSS_STATUS_STARTED) { + WMA_LOGA("BSS is not yet stopped. Defering vdev(vdev id %x) deletion", + vdev_id); + iface->del_staself_req = pdel_sta_self_req_param; + return status; + } + + if (!iface->handle) { + WMA_LOGE("handle of vdev_id %d is NULL vdev is already freed", + vdev_id); + pdel_sta_self_req_param->status = status; + if (generateRsp) { + wma_send_del_sta_self_resp(pdel_sta_self_req_param); + } else { + qdf_mem_free(pdel_sta_self_req_param); + pdel_sta_self_req_param = NULL; + } + return status; + } + + iface->vdev_active = false; + /* P2P Device */ + if ((iface->type == WMI_VDEV_TYPE_AP) && + (iface->sub_type == WMI_UNIFIED_VDEV_SUBTYPE_P2P_DEVICE)) { + wma_self_peer_remove(wma_handle, pdel_sta_self_req_param, + generateRsp); + if (!WMI_SERVICE_IS_ENABLED(wma_handle->wmi_service_bitmap, + WMI_SERVICE_SYNC_DELETE_CMDS)) + status = wma_handle_vdev_detach(wma_handle, + pdel_sta_self_req_param, generateRsp); + } else { /* other than P2P */ + status = wma_handle_vdev_detach(wma_handle, + pdel_sta_self_req_param, generateRsp); + } + + return status; +} + +/** + * wma_vdev_start_rsp() - send vdev start response to upper layer + * @wma: wma handle + * @add_bss: add bss params + * @resp_event: response params + * + * Return: none + */ +static void wma_vdev_start_rsp(tp_wma_handle wma, + tpAddBssParams add_bss, + wmi_vdev_start_response_event_fixed_param * + resp_event) +{ + struct beacon_info *bcn; + ol_txrx_pdev_handle pdev; + ol_txrx_peer_handle peer = NULL; + uint8_t peer_id; + +#ifdef QCA_IBSS_SUPPORT + WMA_LOGD("%s: vdev start response received for %s mode", __func__, + add_bss->operMode == + BSS_OPERATIONAL_MODE_IBSS ? "IBSS" : "non-IBSS"); +#endif /* QCA_IBSS_SUPPORT */ + + if (resp_event->status) { + add_bss->status = QDF_STATUS_E_FAILURE; + goto send_fail_resp; + } + + if ((add_bss->operMode == BSS_OPERATIONAL_MODE_AP) +#ifdef QCA_IBSS_SUPPORT + || (add_bss->operMode == BSS_OPERATIONAL_MODE_IBSS) +#endif /* QCA_IBSS_SUPPORT */ + ) { + wma->interfaces[resp_event->vdev_id].beacon = + qdf_mem_malloc(sizeof(struct beacon_info)); + + bcn = wma->interfaces[resp_event->vdev_id].beacon; + if (!bcn) { + WMA_LOGE("%s: Failed alloc memory for beacon struct", + __func__); + add_bss->status = QDF_STATUS_E_NOMEM; + goto send_fail_resp; + } + bcn->buf = qdf_nbuf_alloc(NULL, WMA_BCN_BUF_MAX_SIZE, 0, + sizeof(uint32_t), 0); + if (!bcn->buf) { + WMA_LOGE("%s: No memory allocated for beacon buffer", + __func__); + qdf_mem_free(bcn); + add_bss->status = QDF_STATUS_E_FAILURE; + goto send_fail_resp; + } + bcn->seq_no = MIN_SW_SEQ; + qdf_spinlock_create(&bcn->lock); + qdf_atomic_set(&wma->interfaces[resp_event->vdev_id].bss_status, + WMA_BSS_STATUS_STARTED); + WMA_LOGD("%s: AP mode (type %d subtype %d) BSS is started", + __func__, wma->interfaces[resp_event->vdev_id].type, + wma->interfaces[resp_event->vdev_id].sub_type); + + WMA_LOGD("%s: Allocated beacon struct %p, template memory %p", + __func__, bcn, bcn->buf); + } + add_bss->status = QDF_STATUS_SUCCESS; + add_bss->bssIdx = resp_event->vdev_id; + add_bss->chainMask = resp_event->chain_mask; + if ((2 != resp_event->cfgd_rx_streams) || + (2 != resp_event->cfgd_tx_streams)) { + add_bss->nss = 1; + } + add_bss->smpsMode = host_map_smps_mode(resp_event->smps_mode); +send_fail_resp: + if (add_bss->status != QDF_STATUS_SUCCESS) { + WMA_LOGE("%s: ADD BSS failure %d", __func__, add_bss->status); + + /* Send vdev stop if vdev start was success*/ + if (!resp_event->status) + if (wma_send_vdev_stop_to_fw(wma, resp_event->vdev_id)) + WMA_LOGE("%s: %d Failed to send vdev stop", __func__, __LINE__); + + pdev = cds_get_context(QDF_MODULE_ID_TXRX); + if (NULL == pdev) + WMA_LOGE("%s: Failed to get pdev", __func__); + + if (pdev) + peer = ol_txrx_find_peer_by_addr(pdev, + add_bss->bssId, &peer_id); + if (!peer) + WMA_LOGE("%s Failed to find peer %pM", __func__, + add_bss->bssId); + + if (peer) + wma_remove_peer(wma, add_bss->bssId, + resp_event->vdev_id, peer, false); + } + + WMA_LOGD("%s: Sending add bss rsp to umac(vdev %d status %d)", + __func__, resp_event->vdev_id, add_bss->status); + wma_send_msg(wma, WMA_ADD_BSS_RSP, (void *)add_bss, 0); +} + +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE +/** + * wma_find_mcc_ap() - finds if device is operating AP in MCC mode or not + * @wma: wma handle. + * @vdev_id: vdev ID of device for which MCC has to be checked + * @add: flag indicating if current device is added or deleted + * + * This function parses through all the interfaces in wma and finds if + * any of those devces are in MCC mode with AP. If such a vdev is found + * involved AP vdevs are sent WDA_UPDATE_Q2Q_IE_IND msg to update their + * beacon template to include Q2Q IE. + * + * Return: none + */ +static void wma_find_mcc_ap(tp_wma_handle wma, uint8_t vdev_id, bool add) +{ + uint8_t i; + uint16_t prev_ch_freq = 0; + bool is_ap = false; + bool result = false; + uint8_t *ap_vdev_ids = NULL; + uint8_t num_ch = 0; + + ap_vdev_ids = qdf_mem_malloc(wma->max_bssid); + if (!ap_vdev_ids) + return; + + for (i = 0; i < wma->max_bssid; i++) { + ap_vdev_ids[i] = -1; + if (add == false && i == vdev_id) + continue; + + if (wma->interfaces[i].vdev_up || (i == vdev_id && add)) { + if (wma->interfaces[i].type == WMI_VDEV_TYPE_AP) { + is_ap = true; + ap_vdev_ids[i] = i; + } + + if (wma->interfaces[i].mhz != prev_ch_freq) { + num_ch++; + prev_ch_freq = wma->interfaces[i].mhz; + } + } + } + + if (is_ap && (num_ch > 1)) + result = true; + else + result = false; + + wma_send_msg(wma, WMA_UPDATE_Q2Q_IE_IND, (void *)ap_vdev_ids, result); +} +#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ + +static const wmi_channel_width mode_to_width[MODE_MAX] = { + [MODE_11A] = WMI_CHAN_WIDTH_20, + [MODE_11G] = WMI_CHAN_WIDTH_20, + [MODE_11B] = WMI_CHAN_WIDTH_20, + [MODE_11GONLY] = WMI_CHAN_WIDTH_20, + [MODE_11NA_HT20] = WMI_CHAN_WIDTH_20, + [MODE_11NG_HT20] = WMI_CHAN_WIDTH_20, + [MODE_11AC_VHT20] = WMI_CHAN_WIDTH_20, + [MODE_11AC_VHT20_2G] = WMI_CHAN_WIDTH_20, + [MODE_11NA_HT40] = WMI_CHAN_WIDTH_40, + [MODE_11NG_HT40] = WMI_CHAN_WIDTH_40, + [MODE_11AC_VHT40] = WMI_CHAN_WIDTH_40, + [MODE_11AC_VHT40_2G] = WMI_CHAN_WIDTH_40, + [MODE_11AC_VHT80] = WMI_CHAN_WIDTH_80, + [MODE_11AC_VHT80_2G] = WMI_CHAN_WIDTH_80, +#if CONFIG_160MHZ_SUPPORT + [MODE_11AC_VHT80_80] = WMI_CHAN_WIDTH_80P80, + [MODE_11AC_VHT160] = WMI_CHAN_WIDTH_160, +#endif + +#if SUPPORT_11AX + [MODE_11AX_HE20] = WMI_CHAN_WIDTH_20, + [MODE_11AX_HE40] = WMI_CHAN_WIDTH_40, + [MODE_11AX_HE80] = WMI_CHAN_WIDTH_80, + [MODE_11AX_HE80_80] = WMI_CHAN_WIDTH_80P80, + [MODE_11AX_HE160] = WMI_CHAN_WIDTH_160, + [MODE_11AX_HE20_2G] = WMI_CHAN_WIDTH_20, + [MODE_11AX_HE40_2G] = WMI_CHAN_WIDTH_40, + [MODE_11AX_HE80_2G] = WMI_CHAN_WIDTH_80, +#endif +}; + +/** + * chanmode_to_chanwidth() - get channel width through channel mode + * @chanmode: channel phy mode + * + * Return: channel width + */ +static wmi_channel_width chanmode_to_chanwidth(WLAN_PHY_MODE chanmode) +{ + wmi_channel_width chan_width; + + if (chanmode >= MODE_11A && chanmode < MODE_MAX) + chan_width = mode_to_width[chanmode]; + else + chan_width = WMI_CHAN_WIDTH_20; + + return chan_width; +} + +/** + * wma_vdev_start_resp_handler() - vdev start response handler + * @handle: wma handle + * @cmd_param_info: event buffer + * @len: buffer length + * + * Return: 0 for success or error code + */ +int wma_vdev_start_resp_handler(void *handle, uint8_t *cmd_param_info, + uint32_t len) +{ + tp_wma_handle wma = (tp_wma_handle) handle; + WMI_VDEV_START_RESP_EVENTID_param_tlvs *param_buf; + wmi_vdev_start_response_event_fixed_param *resp_event; + struct wma_target_req *req_msg; + struct wma_txrx_node *iface; + struct vdev_up_params param = {0}; + QDF_STATUS status; + int err; + wmi_channel_width chanwidth; + + wma_release_wmi_resp_wakelock(wma); + +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE + tpAniSirGlobal mac_ctx = cds_get_context(QDF_MODULE_ID_PE); + if (NULL == mac_ctx) { + WMA_LOGE("%s: Failed to get mac_ctx", __func__); + cds_set_do_hw_mode_change_flag(false); + return -EINVAL; + } +#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ + + WMA_LOGD("%s: Enter", __func__); + param_buf = (WMI_VDEV_START_RESP_EVENTID_param_tlvs *) cmd_param_info; + if (!param_buf) { + WMA_LOGE("Invalid start response event buffer"); + cds_set_do_hw_mode_change_flag(false); + return -EINVAL; + } + + resp_event = param_buf->fixed_param; + if (!resp_event) { + WMA_LOGE("Invalid start response event buffer"); + cds_set_do_hw_mode_change_flag(false); + return -EINVAL; + } + + if (wma_is_vdev_in_ap_mode(wma, resp_event->vdev_id)) { + qdf_spin_lock_bh(&wma->dfs_ic->chan_lock); + wma->dfs_ic->disable_phy_err_processing = false; + qdf_spin_unlock_bh(&wma->dfs_ic->chan_lock); + } + + if (resp_event->status == QDF_STATUS_SUCCESS) { + wma->interfaces[resp_event->vdev_id].tx_streams = + resp_event->cfgd_tx_streams; + wma->interfaces[resp_event->vdev_id].rx_streams = + resp_event->cfgd_rx_streams; + wma->interfaces[resp_event->vdev_id].chain_mask = + resp_event->chain_mask; + if (wma->wlan_resource_config.use_pdev_id) { + if (resp_event->pdev_id == WMI_PDEV_ID_SOC) { + WMA_LOGE("%s: soc level id received for mac id", + __func__); + QDF_BUG(0); + return -EINVAL; + } + wma->interfaces[resp_event->vdev_id].mac_id = + WMA_PDEV_TO_MAC_MAP(resp_event->pdev_id); + } else { + wma->interfaces[resp_event->vdev_id].mac_id = + resp_event->mac_id; + } + + WMA_LOGI("%s: vdev:%d tx ss=%d rx ss=%d chain mask=%d mac=%d", + __func__, + resp_event->vdev_id, + wma->interfaces[resp_event->vdev_id].tx_streams, + wma->interfaces[resp_event->vdev_id].rx_streams, + wma->interfaces[resp_event->vdev_id].chain_mask, + wma->interfaces[resp_event->vdev_id].mac_id); + } + + iface = &wma->interfaces[resp_event->vdev_id]; + + if ((resp_event->vdev_id <= wma->max_bssid) && + (qdf_atomic_read + (&wma->interfaces[resp_event->vdev_id].vdev_restart_params.hidden_ssid_restart_in_progress)) + && (wma_is_vdev_in_ap_mode(wma, resp_event->vdev_id) == true)) { + WMA_LOGE("%s: vdev restart event recevied for hidden ssid set using IOCTL", + __func__); + + param.vdev_id = resp_event->vdev_id; + param.assoc_id = 0; + if (wmi_unified_vdev_up_send + (wma->wmi_handle, + wma->interfaces[resp_event->vdev_id].bssid, + ¶m) != QDF_STATUS_SUCCESS) { + WMA_LOGE("%s : failed to send vdev up", __func__); + cds_set_do_hw_mode_change_flag(false); + return -EEXIST; + } + qdf_atomic_set(&wma->interfaces[resp_event->vdev_id]. + vdev_restart_params. + hidden_ssid_restart_in_progress, 0); + wma->interfaces[resp_event->vdev_id].vdev_up = true; + /* + * Unpause TX queue in SAP case while configuring hidden ssid + * enable or disable, else the data path is paused forever + * causing data packets(starting from DHCP offer) to get stuck + */ + ol_txrx_vdev_unpause(iface->handle, + OL_TXQ_PAUSE_REASON_VDEV_STOP); + iface->pause_bitmap &= ~(1 << PAUSE_TYPE_HOST); + + } + + req_msg = wma_find_vdev_req(wma, resp_event->vdev_id, + WMA_TARGET_REQ_TYPE_VDEV_START); + + if (!req_msg) { + WMA_LOGE("%s: Failed to lookup request message for vdev %d", + __func__, resp_event->vdev_id); + cds_set_do_hw_mode_change_flag(false); + return -EINVAL; + } + + qdf_mc_timer_stop(&req_msg->event_timeout); + +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE + if (resp_event->status == QDF_STATUS_SUCCESS + && mac_ctx->sap.sap_channel_avoidance) + wma_find_mcc_ap(wma, resp_event->vdev_id, true); +#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ + + if (req_msg->msg_type == WMA_CHNL_SWITCH_REQ) { + tpSwitchChannelParams params = + (tpSwitchChannelParams) req_msg->user_data; + if (!params) { + WMA_LOGE("%s: channel switch params is NULL for vdev %d", + __func__, resp_event->vdev_id); + cds_set_do_hw_mode_change_flag(false); + return -EINVAL; + } + + WMA_LOGD("%s: Send channel switch resp vdev %d status %d", + __func__, resp_event->vdev_id, resp_event->status); + params->chainMask = resp_event->chain_mask; + if ((2 != resp_event->cfgd_rx_streams) || + (2 != resp_event->cfgd_tx_streams)) { + params->nss = 1; + } + params->smpsMode = host_map_smps_mode(resp_event->smps_mode); + params->status = resp_event->status; + if (wma->interfaces[resp_event->vdev_id].is_channel_switch) { + wma->interfaces[resp_event->vdev_id].is_channel_switch = + false; + } + if (((resp_event->resp_type == WMI_VDEV_RESTART_RESP_EVENT) && + (iface->type == WMI_VDEV_TYPE_STA)) || + ((resp_event->resp_type == WMI_VDEV_START_RESP_EVENT) && + (iface->type == WMI_VDEV_TYPE_MONITOR))) { + err = wma_set_peer_param(wma, iface->bssid, + WMI_PEER_PHYMODE, iface->chanmode, + resp_event->vdev_id); + + WMA_LOGD("%s:vdev_id %d chanmode %d status %d", + __func__, resp_event->vdev_id, + iface->chanmode, err); + + chanwidth = chanmode_to_chanwidth(iface->chanmode); + err = wma_set_peer_param(wma, iface->bssid, + WMI_PEER_CHWIDTH, chanwidth, + resp_event->vdev_id); + + WMA_LOGD("%s:vdev_id %d chanwidth %d status %d", + __func__, resp_event->vdev_id, + chanwidth, err); + + param.vdev_id = resp_event->vdev_id; + param.assoc_id = iface->aid; + status = wmi_unified_vdev_up_send(wma->wmi_handle, + iface->bssid, + ¶m); + if (QDF_IS_STATUS_ERROR(status)) { + WMA_LOGE("%s:vdev_up failed vdev_id %d", + __func__, resp_event->vdev_id); + wma->interfaces[resp_event->vdev_id].vdev_up = + false; + cds_set_do_hw_mode_change_flag(false); + } else { + wma->interfaces[resp_event->vdev_id].vdev_up = + true; + if (iface->beacon_filter_enabled) + wma_add_beacon_filter(wma, + &iface->beacon_filter); + } + } + + wma_send_msg(wma, WMA_SWITCH_CHANNEL_RSP, (void *)params, 0); + } else if (req_msg->msg_type == WMA_ADD_BSS_REQ) { + tpAddBssParams bssParams = (tpAddBssParams) req_msg->user_data; + qdf_mem_copy(iface->bssid, bssParams->bssId, + IEEE80211_ADDR_LEN); + wma_vdev_start_rsp(wma, bssParams, resp_event); + } else if (req_msg->msg_type == WMA_OCB_SET_CONFIG_CMD) { + param.vdev_id = resp_event->vdev_id; + param.assoc_id = iface->aid; + if (wmi_unified_vdev_up_send(wma->wmi_handle, + iface->bssid, + ¶m) != QDF_STATUS_SUCCESS) { + WMA_LOGE(FL("failed to send vdev up")); + cds_set_do_hw_mode_change_flag(false); + return -EEXIST; + } + iface->vdev_up = true; + + wma_ocb_start_resp_ind_cont(wma); + } + + if ((wma->interfaces[resp_event->vdev_id].type == WMI_VDEV_TYPE_AP) && + wma->interfaces[resp_event->vdev_id].vdev_up) + wma_set_sap_keepalive(wma, resp_event->vdev_id); + + qdf_mc_timer_destroy(&req_msg->event_timeout); + qdf_mem_free(req_msg); + + return 0; +} + +/** + * wma_vdev_set_param() - set per vdev params in fw + * @wmi_handle: wmi handle + * @if_if: vdev id + * @param_id: parameter id + * @param_value: parameter value + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +QDF_STATUS +wma_vdev_set_param(wmi_unified_t wmi_handle, uint32_t if_id, + uint32_t param_id, uint32_t param_value) +{ + struct vdev_set_params param = {0}; + param.if_id = if_id; + param.param_id = param_id; + param.param_value = param_value; + + return wmi_unified_vdev_set_param_send(wmi_handle, ¶m); +} + +/** + * wma_set_peer_authorized_cb() - set peer authorized callback function + * @wma_Ctx: wma handle + * @auth_cb: peer authorized callback + * + * Return: none + */ +void wma_set_peer_authorized_cb(void *wma_ctx, wma_peer_authorized_fp auth_cb) +{ + tp_wma_handle wma_handle = (tp_wma_handle) wma_ctx; + wma_handle->peer_authorized_cb = auth_cb; +} + +/** + * wma_set_peer_param() - set peer parameter in fw + * @wma_ctx: wma handle + * @peer_addr: peer mac address + * @param_id: parameter id + * @param_value: parameter value + * @vdev_id: vdev id + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +QDF_STATUS wma_set_peer_param(void *wma_ctx, uint8_t *peer_addr, + uint32_t param_id, uint32_t param_value, + uint32_t vdev_id) +{ + tp_wma_handle wma_handle = (tp_wma_handle) wma_ctx; + struct peer_set_params param = {0}; + int err; + + param.vdev_id = vdev_id; + param.param_value = param_value; + param.param_id = param_id; + + err = wmi_set_peer_param_send(wma_handle->wmi_handle, peer_addr, + ¶m); + + return err; +} + +/** + * wma_remove_peer() - remove peer information from host driver and fw + * @wma: wma handle + * @bssid: mac address + * @vdev_id: vdev id + * @peer: peer ptr + * @roam_synch_in_progress: roam in progress flag + * + * Return: none + */ +void wma_remove_peer(tp_wma_handle wma, uint8_t *bssid, + uint8_t vdev_id, ol_txrx_peer_handle peer, + bool roam_synch_in_progress) +{ +#define PEER_ALL_TID_BITMASK 0xffffffff + uint32_t peer_tid_bitmap = PEER_ALL_TID_BITMASK; + uint8_t *peer_addr = bssid; + struct peer_flush_params param = {0}; + uint8_t *peer_mac_addr; + + peer_mac_addr = ol_txrx_peer_get_peer_mac_addr(peer); + if (peer_mac_addr == NULL) { + WMA_LOGE("%s: peer mac addr is NULL, Can't remove peer, vdevid %d peer_count %d", + __func__, vdev_id, + wma->interfaces[vdev_id].peer_count); + return; + } + + if (!wma->interfaces[vdev_id].peer_count) { + WMA_LOGE("%s: Can't remove peer with peer_addr %pM vdevid %d peer_count %d", + __func__, bssid, vdev_id, + wma->interfaces[vdev_id].peer_count); + return; + } + + if (roam_synch_in_progress) + goto peer_detach; + /* Flush all TIDs except MGMT TID for this peer in Target */ + peer_tid_bitmap &= ~(0x1 << WMI_MGMT_TID); + param.peer_tid_bitmap = peer_tid_bitmap; + param.vdev_id = vdev_id; + wmi_unified_peer_flush_tids_send(wma->wmi_handle, bssid, + ¶m); + + if (wma_is_vdev_in_ibss_mode(wma, vdev_id)) { + WMA_LOGD("%s: bssid %pM peer->mac_addr %pM", __func__, + bssid, peer_mac_addr); + peer_addr = peer_mac_addr; + } + + wma_peer_debug_log(vdev_id, DEBUG_PEER_DELETE_SEND, + DEBUG_INVALID_PEER_ID, peer_addr, peer, + 0, + qdf_atomic_read(&peer->ref_cnt)); + wmi_unified_peer_delete_send(wma->wmi_handle, peer_addr, + vdev_id); + +peer_detach: + WMA_LOGI("%s: Remove peer %p with peer_addr %pM vdevid %d peer_count %d", + __func__, peer, bssid, vdev_id, + wma->interfaces[vdev_id].peer_count); + + if (peer) { + if (roam_synch_in_progress) + ol_txrx_peer_detach_force_delete(peer); + else + ol_txrx_peer_detach(peer); + } + + wma->interfaces[vdev_id].peer_count--; +#undef PEER_ALL_TID_BITMASK +} + +/** + * wma_find_duplicate_peer_on_other_vdev() - Find if same peer exist + * on other vdevs + * @wma: wma handle + * @pdev: txrx pdev ptr + * @vdev_id: vdev id of vdev on which the peer + * needs to be added + * @peer_mac: peer mac addr which needs to be added + * + * Check if peer with same MAC is present on vdev other then + * the provided vdev_id + * + * Return: true if same peer is present on vdev other then vdev_id + * else return false + */ +static bool wma_find_duplicate_peer_on_other_vdev(tp_wma_handle wma, + ol_txrx_pdev_handle pdev, uint8_t vdev_id, uint8_t *peer_mac) +{ + int i; + uint8_t peer_id; + + for (i = 0; i < wma->max_bssid; i++) { + /* Need to check vdevs other than the vdev_id */ + if (vdev_id == i || + !wma->interfaces[i].handle) + continue; + if (ol_txrx_find_peer_by_addr_and_vdev(pdev, + wma->interfaces[i].handle, peer_mac, &peer_id)) { + WMA_LOGE("%s :Duplicate peer %pM (peer id %d) already exist on vdev %d", + __func__, peer_mac, peer_id, i); + return true; + } + } + return false; +} + +/** + * wma_create_peer() - send peer create command to fw + * @wma: wma handle + * @pdev: txrx pdev ptr + * @vdev: txrx vdev ptr + * @peer_addr: peer mac addr + * @peer_type: peer type + * @vdev_id: vdev id + * @roam_synch_in_progress: roam in progress + * + * Return: QDF status + */ +QDF_STATUS wma_create_peer(tp_wma_handle wma, ol_txrx_pdev_handle pdev, + ol_txrx_vdev_handle vdev, + u8 peer_addr[IEEE80211_ADDR_LEN], + uint32_t peer_type, uint8_t vdev_id, + bool roam_synch_in_progress) +{ + ol_txrx_peer_handle peer; + struct peer_create_params param = {0}; + uint8_t *mac_addr_raw; + + + if (++wma->interfaces[vdev_id].peer_count > + wma->wlan_resource_config.num_peers) { + WMA_LOGP("%s, the peer count exceeds the limit %d", __func__, + wma->interfaces[vdev_id].peer_count - 1); + goto err; + } + + /* + * Check if peer with same MAC exist on other Vdev, If so avoid + * adding this peer, as it will cause FW to crash. + */ + if (wma_find_duplicate_peer_on_other_vdev(wma, pdev, + vdev_id, peer_addr)) + goto err; + + peer = ol_txrx_peer_attach(vdev, peer_addr); + if (!peer) { + WMA_LOGE("%s : Unable to attach peer %pM", __func__, peer_addr); + goto err; + } + + if (roam_synch_in_progress) { + WMA_LOGE("%s: LFR3: Created peer %p with peer_addr %pM vdev_id %d," + "peer_count - %d", + __func__, peer, peer_addr, vdev_id, + wma->interfaces[vdev_id].peer_count); + return QDF_STATUS_SUCCESS; + } + param.peer_addr = peer_addr; + param.peer_type = peer_type; + param.vdev_id = vdev_id; + if (wmi_unified_peer_create_send(wma->wmi_handle, + ¶m) != QDF_STATUS_SUCCESS) { + WMA_LOGP("%s : Unable to create peer in Target", __func__); + ol_txrx_peer_detach(peer); + goto err; + } + WMA_LOGI("%s: Created peer %p ref_cnt %d with peer_addr %pM vdev_id %d, peer_count - %d", + __func__, peer, qdf_atomic_read(&peer->ref_cnt), + peer_addr, vdev_id, + wma->interfaces[vdev_id].peer_count); + wma_peer_debug_log(vdev_id, DEBUG_PEER_CREATE_SEND, + DEBUG_INVALID_PEER_ID, peer_addr, peer, 0, + qdf_atomic_read(&peer->ref_cnt)); + + mac_addr_raw = ol_txrx_get_vdev_mac_addr(vdev); + if (mac_addr_raw == NULL) { + WMA_LOGE("%s: peer mac addr is NULL", __func__); + return QDF_STATUS_E_FAULT; + } + + /* for each remote ibss peer, clear its keys */ + if (wma_is_vdev_in_ibss_mode(wma, vdev_id) && + qdf_mem_cmp(peer_addr, mac_addr_raw, IEEE80211_ADDR_LEN)) { + + tSetStaKeyParams key_info; + WMA_LOGD("%s: remote ibss peer %pM key clearing\n", __func__, + peer_addr); + qdf_mem_set(&key_info, sizeof(key_info), 0); + key_info.smesessionId = vdev_id; + qdf_mem_copy(key_info.peer_macaddr.bytes, peer_addr, + IEEE80211_ADDR_LEN); + key_info.sendRsp = false; + + wma_set_stakey(wma, &key_info); + } + + return QDF_STATUS_SUCCESS; +err: + wma->interfaces[vdev_id].peer_count--; + return QDF_STATUS_E_FAILURE; +} + +#ifdef QCA_IBSS_SUPPORT + +/** + * wma_delete_all_ibss_peers() - delete all ibss peer for vdev_id + * @wma: wma handle + * @vdev_id: vdev id + * + * This function send peer delete command to fw for all + * peers in peer_list and remove ref count for peer id + * peer will actually remove from list after receving + * unmap event from firmware. + * + * Return: none + */ +static void wma_delete_all_ibss_peers(tp_wma_handle wma, A_UINT32 vdev_id) +{ + ol_txrx_vdev_handle vdev; + + if (!wma || vdev_id > wma->max_bssid) + return; + + vdev = wma->interfaces[vdev_id].handle; + if (!vdev) + return; + + /* remove all remote peers of IBSS */ + ol_txrx_remove_peers_for_vdev(vdev, + (ol_txrx_vdev_peer_remove_cb)wma_remove_peer, wma, + true); +} +#else +/** + * wma_delete_all_ibss_peers(): dummy function for when ibss is not supported + * @wma: wma handle + * @vdev_id: vdev id + * + * This function send peer delete command to fw for all + * peers in peer_list and remove ref count for peer id + * peer will actually remove from list after receving + * unmap event from firmware. + * + * Return: none + */ +static void wma_delete_all_ibss_peers(tp_wma_handle wma, A_UINT32 vdev_id) +{ +} +#endif /* QCA_IBSS_SUPPORT */ + +/** + * wma_delete_all_ap_remote_peers() - delete all ap peer for vdev_id + * @wma: wma handle + * @vdev_id: vdev id + * + * This function send peer delete command to fw for all + * peers in peer_list and remove ref count for peer id + * peer will actually remove from list after receving + * unmap event from firmware. + * + * Return: none + */ +static void wma_delete_all_ap_remote_peers(tp_wma_handle wma, A_UINT32 vdev_id) +{ + ol_txrx_vdev_handle vdev; + + if (!wma || vdev_id > wma->max_bssid) + return; + + vdev = wma->interfaces[vdev_id].handle; + if (!vdev) + return; + + WMA_LOGE("%s: vdev_id - %d", __func__, vdev_id); + /* remove all remote peers of SAP */ + ol_txrx_remove_peers_for_vdev(vdev, + (ol_txrx_vdev_peer_remove_cb)wma_remove_peer, wma, false); +} + +/** + * wma_hidden_ssid_vdev_restart_on_vdev_stop() - restart vdev to set hidden ssid + * @wma_handle: wma handle + * @sessionId: session id + * + * Return: none + */ +static void wma_hidden_ssid_vdev_restart_on_vdev_stop(tp_wma_handle wma_handle, + uint8_t sessionId) +{ + struct wma_txrx_node *intr = wma_handle->interfaces; + struct hidden_ssid_vdev_restart_params params; + QDF_STATUS status; + + params.session_id = sessionId; + params.ssid_len = intr[sessionId].vdev_restart_params.ssid.ssid_len; + qdf_mem_copy(params.ssid, + intr[sessionId].vdev_restart_params.ssid.ssid, + params.ssid_len); + params.flags = intr[sessionId].vdev_restart_params.flags; + if (intr[sessionId].vdev_restart_params.ssidHidden) + params.flags |= WMI_UNIFIED_VDEV_START_HIDDEN_SSID; + else + params.flags &= (0xFFFFFFFE); + params.requestor_id = intr[sessionId].vdev_restart_params.requestor_id; + params.disable_hw_ack = + intr[sessionId].vdev_restart_params.disable_hw_ack; + + params.mhz = intr[sessionId].vdev_restart_params.chan.mhz; + params.band_center_freq1 = + intr[sessionId].vdev_restart_params.chan.band_center_freq1; + params.band_center_freq2 = + intr[sessionId].vdev_restart_params.chan.band_center_freq2; + params.info = intr[sessionId].vdev_restart_params.chan.info; + params.reg_info_1 = intr[sessionId].vdev_restart_params.chan.reg_info_1; + params.reg_info_2 = intr[sessionId].vdev_restart_params.chan.reg_info_2; + + status = wmi_unified_hidden_ssid_vdev_restart_send( + wma_handle->wmi_handle, ¶ms); + if (status == QDF_STATUS_E_FAILURE) { + WMA_LOGE("%s: Failed to send vdev restart command", __func__); + qdf_atomic_set(&intr[sessionId].vdev_restart_params. + hidden_ssid_restart_in_progress, 0); + } +} + +/** + * wma_cleanup_target_req_param() - free param memory of target request + * @tgt_req: target request params + * + * Return: none + */ +static void wma_cleanup_target_req_param(struct wma_target_req *tgt_req) +{ + if (tgt_req->msg_type == WMA_CHNL_SWITCH_REQ || + tgt_req->msg_type == WMA_DELETE_BSS_REQ || + tgt_req->msg_type == WMA_ADD_BSS_REQ) { + qdf_mem_free(tgt_req->user_data); + tgt_req->user_data = NULL; + } + + if (tgt_req->msg_type == WMA_SET_LINK_STATE && tgt_req->user_data) { + tpLinkStateParams params = + (tpLinkStateParams) tgt_req->user_data; + qdf_mem_free(params->callbackArg); + qdf_mem_free(tgt_req->user_data); + tgt_req->user_data = NULL; + } +} + +/** + * wma_config_active_bpf_mode() - Config active BPF mode in FW + * @wma: the WMA handle + * @vdev_id: the Id of the vdev for which the configuration should be applied + * + * Return: QDF status + */ +static QDF_STATUS wma_config_active_bpf_mode(t_wma_handle *wma, uint8_t vdev_id) +{ + const FW_ACTIVE_BPF_MODE mcbc_mode = FW_ACTIVE_BPF_MODE_FORCE_ENABLE; + FW_ACTIVE_BPF_MODE uc_mode; + + WMA_LOGI("Configuring Active BPF Mode %d for vdev %u", + wma->active_bpf_mode, vdev_id); + + switch (wma->active_bpf_mode) { + case ACTIVE_BPF_DISABLED: + uc_mode = FW_ACTIVE_BPF_MODE_DISABLE; + break; + case ACTIVE_BPF_ENABLED: + uc_mode = FW_ACTIVE_BPF_MODE_FORCE_ENABLE; + break; + case ACTIVE_BPF_ADAPTIVE: + uc_mode = FW_ACTIVE_BPF_MODE_ADAPTIVE_ENABLE; + break; + default: + WMA_LOGE("Invalid Active BPF Mode %d; Using 'disabled'", + wma->active_bpf_mode); + uc_mode = FW_ACTIVE_BPF_MODE_DISABLE; + break; + } + + return wmi_unified_set_active_bpf_mode_cmd(wma->wmi_handle, vdev_id, + uc_mode, mcbc_mode); +} + +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE +/** + * wma_check_and_find_mcc_ap() - finds if device is operating AP + * in MCC mode or not + * @wma: wma handle. + * @vdev_id: vdev ID of device for which MCC has to be checked + * + * This function internally calls wma_find_mcc_ap finds if + * device is operating AP in MCC mode or not + * + * Return: none + */ +static void +wma_check_and_find_mcc_ap(tp_wma_handle wma, uint8_t vdev_id) +{ + tpAniSirGlobal mac_ctx = cds_get_context(QDF_MODULE_ID_PE); + + if (NULL == mac_ctx) { + WMA_LOGE("%s: Failed to get mac_ctx", __func__); + return; + } + if (mac_ctx->sap.sap_channel_avoidance) + wma_find_mcc_ap(wma, vdev_id, false); +} +#else +static inline void +wma_check_and_find_mcc_ap(tp_wma_handle wma, uint8_t vdev_id) +{} +#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ + +/** + * wma_send_del_bss_response() - send del bss resp to upper layer + * @wma: wma handle. + * @vdev_id: vdev ID of device for which MCC has to be checked + * + * This function sends del bss resp to upper layer + * + * Return: none + */ +static void +wma_send_del_bss_response(tp_wma_handle wma, struct wma_target_req *req, + uint8_t vdev_id) +{ + struct wma_txrx_node *iface; + struct beacon_info *bcn; + tpDeleteBssParams params; + + if (!req) { + WMA_LOGE("%s req is NULL", __func__); + return; + } + + iface = &wma->interfaces[vdev_id]; + if (!iface->handle) { + WMA_LOGE("%s vdev id %d is already deleted", + __func__, vdev_id); + if (req->user_data) + qdf_mem_free(req->user_data); + req->user_data = NULL; + return; + } + + params = (tpDeleteBssParams) req->user_data; + if (wmi_unified_vdev_down_send(wma->wmi_handle, + vdev_id) != + QDF_STATUS_SUCCESS) { + WMA_LOGE("Failed to send vdev down cmd: vdev %d", + vdev_id); + } else { + wma->interfaces[vdev_id].vdev_up = false; + wma_check_and_find_mcc_ap(wma, vdev_id); + } + ol_txrx_vdev_flush(iface->handle); + WMA_LOGD("%s, vdev_id: %d, un-pausing tx_ll_queue for VDEV_STOP rsp", + __func__, vdev_id); + ol_txrx_vdev_unpause(iface->handle, + OL_TXQ_PAUSE_REASON_VDEV_STOP); + iface->pause_bitmap &= ~(1 << PAUSE_TYPE_HOST); + qdf_atomic_set(&iface->bss_status, WMA_BSS_STATUS_STOPPED); + WMA_LOGD("%s: (type %d subtype %d) BSS is stopped", + __func__, iface->type, iface->sub_type); + + bcn = wma->interfaces[vdev_id].beacon; + if (bcn) { + struct ol_txrx_pdev_t *pdev; + + pdev = cds_get_context(QDF_MODULE_ID_TXRX); + WMA_LOGD("%s: Freeing beacon struct %p, template memory %p", + __func__, bcn, bcn->buf); + if (bcn->dma_mapped && pdev) + qdf_nbuf_unmap_single(pdev->osdev, bcn->buf, + QDF_DMA_TO_DEVICE); + qdf_nbuf_free(bcn->buf); + qdf_mem_free(bcn); + wma->interfaces[vdev_id].beacon = NULL; + } + + /* + * Timeout status means its WMA generated DEL BSS REQ when ADD + * BSS REQ was timed out to stop the VDEV in this case no need + * to send response to UMAC + */ + if (params->status == QDF_STATUS_FW_MSG_TIMEDOUT) { + qdf_mem_free(req->user_data); + req->user_data = NULL; + WMA_LOGE("%s: DEL BSS from ADD BSS timeout do not send resp to UMAC (vdev id %x)", + __func__, vdev_id); + } else { + params->status = QDF_STATUS_SUCCESS; + wma_send_msg(wma, WMA_DELETE_BSS_RSP, (void *)params, + 0); + } + + if (iface->del_staself_req != NULL) { + WMA_LOGA("scheduling defered deletion (vdev id %x)", + vdev_id); + wma_vdev_detach(wma, iface->del_staself_req, 1); + } +} + + +/** + * wma_vdev_stop_resp_handler() - vdev stop response handler + * @handle: wma handle + * @cmd_param_info: event buffer + * @len: buffer length + * + * Return: 0 for success or error code + */ +int wma_vdev_stop_resp_handler(void *handle, uint8_t *cmd_param_info, + u32 len) +{ + tp_wma_handle wma = (tp_wma_handle) handle; + WMI_VDEV_STOPPED_EVENTID_param_tlvs *param_buf; + wmi_vdev_stopped_event_fixed_param *resp_event; + struct wma_target_req *req_msg, *del_req; + ol_txrx_peer_handle peer; + ol_txrx_pdev_handle pdev; + uint8_t peer_id; + struct wma_txrx_node *iface; + int32_t status = 0; + + wma_release_wmi_resp_wakelock(wma); + +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE + tpAniSirGlobal mac_ctx = cds_get_context(QDF_MODULE_ID_PE); + if (NULL == mac_ctx) { + WMA_LOGE("%s: Failed to get mac_ctx", __func__); + return -EINVAL; + } +#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ + + WMA_LOGI("%s: Enter", __func__); + param_buf = (WMI_VDEV_STOPPED_EVENTID_param_tlvs *) cmd_param_info; + if (!param_buf) { + WMA_LOGE("Invalid event buffer"); + return -EINVAL; + } + resp_event = param_buf->fixed_param; + + if ((resp_event->vdev_id <= wma->max_bssid) && + (qdf_atomic_read + (&wma->interfaces[resp_event->vdev_id].vdev_restart_params. + hidden_ssid_restart_in_progress)) + && ((wma->interfaces[resp_event->vdev_id].type == WMI_VDEV_TYPE_AP) + && (wma->interfaces[resp_event->vdev_id].sub_type == 0))) { + WMA_LOGE("%s: vdev stop event recevied for hidden ssid set using IOCTL ", + __func__); + + req_msg = wma_fill_vdev_req(wma, resp_event->vdev_id, + WMA_HIDDEN_SSID_VDEV_RESTART, + WMA_TARGET_REQ_TYPE_VDEV_START, resp_event, + WMA_VDEV_START_REQUEST_TIMEOUT); + if (!req_msg) { + WMA_LOGE("%s: Failed to fill vdev request, vdev_id %d", + __func__, resp_event->vdev_id); + return -EINVAL; + } + + wma_hidden_ssid_vdev_restart_on_vdev_stop(wma, + resp_event->vdev_id); + } + + req_msg = wma_find_vdev_req(wma, resp_event->vdev_id, + WMA_TARGET_REQ_TYPE_VDEV_STOP); + if (!req_msg) { + WMA_LOGP("%s: Failed to lookup vdev request for vdev id %d", + __func__, resp_event->vdev_id); + return -EINVAL; + } + pdev = cds_get_context(QDF_MODULE_ID_TXRX); + if (!pdev) { + WMA_LOGE("%s: pdev is NULL", __func__); + status = -EINVAL; + wma_cleanup_target_req_param(req_msg); + qdf_mc_timer_stop(&req_msg->event_timeout); + goto free_req_msg; + } + + qdf_mc_timer_stop(&req_msg->event_timeout); + if (req_msg->msg_type == WMA_DELETE_BSS_REQ) { + tpDeleteBssParams params = + (tpDeleteBssParams) req_msg->user_data; + + if (resp_event->vdev_id > wma->max_bssid) { + WMA_LOGE("%s: Invalid vdev_id %d", __func__, + resp_event->vdev_id); + wma_cleanup_target_req_param(req_msg); + status = -EINVAL; + goto free_req_msg; + } + + iface = &wma->interfaces[resp_event->vdev_id]; + if (iface->handle == NULL) { + WMA_LOGE("%s vdev id %d is already deleted", + __func__, resp_event->vdev_id); + wma_cleanup_target_req_param(req_msg); + status = -EINVAL; + goto free_req_msg; + } + + /* CCA is required only for sta interface */ + if (iface->type == WMI_VDEV_TYPE_STA) + wma_get_cca_stats(wma, resp_event->vdev_id); + + /* Clear arp and ns offload cache */ + qdf_mem_zero(&iface->ns_offload_req, + sizeof(iface->ns_offload_req)); + qdf_mem_zero(&iface->arp_offload_req, + sizeof(iface->arp_offload_req)); + + if (wma_is_vdev_in_ibss_mode(wma, resp_event->vdev_id)) + wma_delete_all_ibss_peers(wma, resp_event->vdev_id); + else if (WMA_IS_VDEV_IN_NDI_MODE(wma->interfaces, + resp_event->vdev_id)) { + wma_delete_all_nan_remote_peers(wma, + resp_event->vdev_id); + } else { + if (wma_is_vdev_in_ap_mode(wma, resp_event->vdev_id)) { + wma_delete_all_ap_remote_peers(wma, + resp_event->vdev_id); + } + peer = ol_txrx_find_peer_by_addr(pdev, params->bssid, + &peer_id); + if (!peer) + WMA_LOGD("%s Failed to find peer %pM", + __func__, params->bssid); + wma_remove_peer(wma, params->bssid, resp_event->vdev_id, + peer, false); + if (peer && WMI_SERVICE_IS_ENABLED( + wma->wmi_service_bitmap, + WMI_SERVICE_SYNC_DELETE_CMDS)) { + WMA_LOGD(FL("Wait for the peer delete. vdev_id %d"), + req_msg->vdev_id); + del_req = wma_fill_hold_req(wma, + req_msg->vdev_id, + WMA_DELETE_STA_REQ, + WMA_DELETE_PEER_RSP, + params, + WMA_DELETE_STA_TIMEOUT); + if (!del_req) { + WMA_LOGE(FL("Failed to allocate request. vdev_id %d"), + req_msg->vdev_id); + params->status = QDF_STATUS_E_NOMEM; + } else { + goto free_req_msg; + } + } + } + wma_send_del_bss_response(wma, req_msg, resp_event->vdev_id); + + } else if (req_msg->msg_type == WMA_SET_LINK_STATE) { + tpLinkStateParams params = + (tpLinkStateParams) req_msg->user_data; + + peer = ol_txrx_find_peer_by_addr(pdev, params->bssid, &peer_id); + if (peer) { + WMA_LOGP(FL("Deleting peer %pM vdev id %d"), + params->bssid, req_msg->vdev_id); + wma_remove_peer(wma, params->bssid, req_msg->vdev_id, + peer, false); + if (WMI_SERVICE_IS_ENABLED(wma->wmi_service_bitmap, + WMI_SERVICE_SYNC_DELETE_CMDS)) { + WMA_LOGI(FL("Wait for the peer delete. vdev_id %d"), + req_msg->vdev_id); + del_req = wma_fill_hold_req(wma, + req_msg->vdev_id, + WMA_DELETE_STA_REQ, + WMA_SET_LINK_PEER_RSP, + params, + WMA_DELETE_STA_TIMEOUT); + if (!del_req) { + WMA_LOGE(FL("Failed to allocate request. vdev_id %d"), + req_msg->vdev_id); + params->status = QDF_STATUS_E_NOMEM; + } else { + goto free_req_msg; + } + } + } + if (wmi_unified_vdev_down_send(wma->wmi_handle, + req_msg->vdev_id) != + QDF_STATUS_SUCCESS) { + WMA_LOGE("Failed to send vdev down cmd: vdev %d", + req_msg->vdev_id); + } + wma_send_msg(wma, WMA_SET_LINK_STATE_RSP, (void *)params, 0); + } +free_req_msg: + qdf_mc_timer_destroy(&req_msg->event_timeout); + qdf_mem_free(req_msg); + return status; +} + +/** + * wma_vdev_attach() - create vdev in fw + * @wma_handle: wma handle + * @self_sta_req: self sta request + * @generateRsp: generate response + * + * This function creates vdev in target and + * attach this vdev to txrx module. It also set + * vdev related params to fw. + * + * Return: txrx vdev handle + */ +ol_txrx_vdev_handle wma_vdev_attach(tp_wma_handle wma_handle, + struct add_sta_self_params *self_sta_req, + uint8_t generateRsp) +{ + ol_txrx_vdev_handle txrx_vdev_handle = NULL; + ol_txrx_pdev_handle txrx_pdev = cds_get_context(QDF_MODULE_ID_TXRX); + enum wlan_op_mode txrx_vdev_type; + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct sAniSirGlobal *mac = cds_get_context(QDF_MODULE_ID_PE); + uint32_t cfg_val; + uint16_t val16; + QDF_STATUS ret; + tSirMacHTCapabilityInfo *phtCapInfo; + cds_msg_t sme_msg = { 0 }; + struct vdev_create_params params = { 0 }; + u_int8_t vdev_id; + struct sir_set_tx_rx_aggregation_size tx_rx_aggregation_size; + + if (NULL == mac) { + WMA_LOGE("%s: Failed to get mac", __func__); + goto end; + } + + params.if_id = self_sta_req->session_id; + params.type = self_sta_req->type; + params.subtype = self_sta_req->sub_type; + params.nss_2g = self_sta_req->nss_2g; + params.nss_5g = self_sta_req->nss_5g; + + /* Create a vdev in target */ + status = wmi_unified_vdev_create_send(wma_handle->wmi_handle, + self_sta_req->self_mac_addr, + ¶ms); + if (QDF_IS_STATUS_ERROR(status)) { + WMA_LOGP("%s: Unable to add an interface for ath_dev", + __func__); + goto end; + } + + vdev_id = self_sta_req->session_id; + + txrx_vdev_type = wma_get_txrx_vdev_type(self_sta_req->type); + + if (wlan_op_mode_unknown == txrx_vdev_type) { + WMA_LOGE("Failed to get txrx vdev type"); + wmi_unified_vdev_delete_send(wma_handle->wmi_handle, + self_sta_req->session_id); + goto end; + } + + txrx_vdev_handle = ol_txrx_vdev_attach(txrx_pdev, + self_sta_req->self_mac_addr, + self_sta_req->session_id, + txrx_vdev_type); + wma_handle->interfaces[self_sta_req->session_id].pause_bitmap = 0; + + WMA_LOGD("vdev_id %hu, txrx_vdev_handle = %p", self_sta_req->session_id, + txrx_vdev_handle); + + if (NULL == txrx_vdev_handle) { + WMA_LOGP("%s: ol_txrx_vdev_attach failed", __func__); + status = QDF_STATUS_E_FAILURE; + wmi_unified_vdev_delete_send(wma_handle->wmi_handle, + self_sta_req->session_id); + goto end; + } + wma_handle->interfaces[self_sta_req->session_id].vdev_active = true; + + wma_handle->interfaces[self_sta_req->session_id].handle = + txrx_vdev_handle; + + wma_handle->interfaces[self_sta_req->session_id].ptrn_match_enable = + wma_handle->ptrn_match_enable_all_vdev ? true : false; + + if (wlan_cfg_get_int(mac, WNI_CFG_WOWLAN_DEAUTH_ENABLE, &cfg_val) + != eSIR_SUCCESS) + wma_handle->wow.deauth_enable = true; + else + wma_handle->wow.deauth_enable = cfg_val ? true : false; + + if (wlan_cfg_get_int(mac, WNI_CFG_WOWLAN_DISASSOC_ENABLE, &cfg_val) + != eSIR_SUCCESS) + wma_handle->wow.disassoc_enable = true; + else + wma_handle->wow.disassoc_enable = cfg_val ? true : false; + + if (wlan_cfg_get_int(mac, WNI_CFG_WOWLAN_MAX_MISSED_BEACON, &cfg_val) + != eSIR_SUCCESS) + wma_handle->wow.bmiss_enable = true; + else + wma_handle->wow.bmiss_enable = cfg_val ? true : false; + + qdf_mem_copy(wma_handle->interfaces[self_sta_req->session_id].addr, + self_sta_req->self_mac_addr, + sizeof(wma_handle->interfaces[self_sta_req->session_id]. + addr)); + + tx_rx_aggregation_size.tx_aggregation_size = + self_sta_req->tx_aggregation_size; + tx_rx_aggregation_size.rx_aggregation_size = + self_sta_req->rx_aggregation_size; + tx_rx_aggregation_size.vdev_id = self_sta_req->session_id; + + status = wma_set_tx_rx_aggregation_size(&tx_rx_aggregation_size); + if (status != QDF_STATUS_SUCCESS) + WMA_LOGE("failed to set aggregation sizes(err=%d)", status); + + switch (self_sta_req->type) { + case WMI_VDEV_TYPE_STA: + if (wlan_cfg_get_int(mac, WNI_CFG_INFRA_STA_KEEP_ALIVE_PERIOD, + &cfg_val) != eSIR_SUCCESS) { + WMA_LOGE("Failed to get value for " + "WNI_CFG_INFRA_STA_KEEP_ALIVE_PERIOD"); + cfg_val = DEFAULT_INFRA_STA_KEEP_ALIVE_PERIOD; + } + + wma_set_sta_keep_alive(wma_handle, + self_sta_req->session_id, + SIR_KEEP_ALIVE_NULL_PKT, + cfg_val, NULL, NULL, NULL); + + /* offload STA SA query related params to fwr */ + if (WMI_SERVICE_IS_ENABLED(wma_handle->wmi_service_bitmap, + WMI_SERVICE_STA_PMF_OFFLOAD)) { + wma_set_sta_sa_query_param(wma_handle, + self_sta_req->session_id); + } + break; + } + + wma_handle->interfaces[self_sta_req->session_id].type = + self_sta_req->type; + wma_handle->interfaces[self_sta_req->session_id].sub_type = + self_sta_req->sub_type; + qdf_atomic_init(&wma_handle->interfaces + [self_sta_req->session_id].bss_status); + + if (((self_sta_req->type == WMI_VDEV_TYPE_AP) && + (self_sta_req->sub_type == WMI_UNIFIED_VDEV_SUBTYPE_P2P_DEVICE)) || + (self_sta_req->type == WMI_VDEV_TYPE_OCB) || + (self_sta_req->type == WMI_VDEV_TYPE_MONITOR) || + (self_sta_req->type == WMI_VDEV_TYPE_NDI)) { + WMA_LOGD("Creating self peer %pM, vdev_id %hu", + self_sta_req->self_mac_addr, self_sta_req->session_id); + status = wma_create_peer(wma_handle, txrx_pdev, + txrx_vdev_handle, + self_sta_req->self_mac_addr, + WMI_PEER_TYPE_DEFAULT, + self_sta_req->session_id, false); + if (status != QDF_STATUS_SUCCESS) { + WMA_LOGE("%s: Failed to create peer", __func__); + status = QDF_STATUS_E_FAILURE; + wmi_unified_vdev_delete_send(wma_handle->wmi_handle, + self_sta_req->session_id); + } + } + + WMA_LOGD("Setting WMI_VDEV_PARAM_DISCONNECT_TH: %d", + self_sta_req->pkt_err_disconn_th); + ret = wma_vdev_set_param(wma_handle->wmi_handle, + self_sta_req->session_id, + WMI_VDEV_PARAM_DISCONNECT_TH, + self_sta_req->pkt_err_disconn_th); + if (ret) + WMA_LOGE("Failed to set WMI_VDEV_PARAM_DISCONNECT_TH"); + + wma_handle->interfaces[vdev_id].is_vdev_valid = true; + ret = wma_vdev_set_param(wma_handle->wmi_handle, + self_sta_req->session_id, + WMI_VDEV_PARAM_MCC_RTSCTS_PROTECTION_ENABLE, + mac->roam.configParam.mcc_rts_cts_prot_enable); + if (QDF_IS_STATUS_ERROR(ret)) + WMA_LOGE("Failed to set WMI VDEV MCC_RTSCTS_PROTECTION_ENABLE"); + + ret = wma_vdev_set_param(wma_handle->wmi_handle, + self_sta_req->session_id, + WMI_VDEV_PARAM_MCC_BROADCAST_PROBE_ENABLE, + mac->roam.configParam.mcc_bcast_prob_resp_enable); + if (QDF_IS_STATUS_ERROR(ret)) + WMA_LOGE("Failed to set WMI VDEV MCC_BROADCAST_PROBE_ENABLE"); + + if (wlan_cfg_get_int(mac, WNI_CFG_RTS_THRESHOLD, + &cfg_val) == eSIR_SUCCESS) { + ret = wma_vdev_set_param(wma_handle->wmi_handle, + self_sta_req->session_id, + WMI_VDEV_PARAM_RTS_THRESHOLD, + cfg_val); + if (QDF_IS_STATUS_ERROR(ret)) + WMA_LOGE("Failed to set WMI_VDEV_PARAM_RTS_THRESHOLD"); + } else { + WMA_LOGE("Failed to get value for WNI_CFG_RTS_THRESHOLD, leaving unchanged"); + } + + if (wlan_cfg_get_int(mac, WNI_CFG_FRAGMENTATION_THRESHOLD, + &cfg_val) == eSIR_SUCCESS) { + ret = wma_vdev_set_param(wma_handle->wmi_handle, + self_sta_req->session_id, + WMI_VDEV_PARAM_FRAGMENTATION_THRESHOLD, + cfg_val); + if (QDF_IS_STATUS_ERROR(ret)) + WMA_LOGE("Failed to set WMI_VDEV_PARAM_FRAGMENTATION_THRESHOLD"); + } else { + WMA_LOGE("Failed to get value for WNI_CFG_FRAGMENTATION_THRESHOLD, leaving unchanged"); + } + + if (wlan_cfg_get_int(mac, WNI_CFG_HT_CAP_INFO, &cfg_val) == eSIR_SUCCESS) { + val16 = (uint16_t) cfg_val; + phtCapInfo = (tSirMacHTCapabilityInfo *) &cfg_val; + ret = wma_vdev_set_param(wma_handle->wmi_handle, + self_sta_req->session_id, + WMI_VDEV_PARAM_TX_STBC, + phtCapInfo->txSTBC); + if (QDF_IS_STATUS_ERROR(ret)) + WMA_LOGE("Failed to set WMI_VDEV_PARAM_TX_STBC"); + } else { + WMA_LOGE("Failed to get value of HT_CAP, TX STBC unchanged"); + } + + wma_set_vdev_mgmt_rate(wma_handle, self_sta_req->session_id); + + /* Initialize roaming offload state */ + if ((self_sta_req->type == WMI_VDEV_TYPE_STA) && + (self_sta_req->sub_type == 0)) { + wma_handle->roam_offload_enabled = true; + ret = wma_vdev_set_param(wma_handle->wmi_handle, + self_sta_req->session_id, + WMI_VDEV_PARAM_ROAM_FW_OFFLOAD, + (WMI_ROAM_FW_OFFLOAD_ENABLE_FLAG | + WMI_ROAM_BMISS_FINAL_SCAN_ENABLE_FLAG)); + if (QDF_IS_STATUS_ERROR(ret)) + WMA_LOGE("Failed to set WMI_VDEV_PARAM_ROAM_FW_OFFLOAD"); + + /* Pass down enable/disable bcast probe rsp to FW */ + ret = wma_vdev_set_param( + wma_handle->wmi_handle, + self_sta_req->session_id, + WMI_VDEV_PARAM_ENABLE_BCAST_PROBE_RESPONSE, + self_sta_req->enable_bcast_probe_rsp); + if (QDF_IS_STATUS_ERROR(ret)) + WMA_LOGE("Failed to set WMI_VDEV_PARAM_ENABLE_BCAST_PROBE_RESPONSE"); + + /* Pass down the FILS max channel guard time to FW */ + ret = wma_vdev_set_param( + wma_handle->wmi_handle, + self_sta_req->session_id, + WMI_VDEV_PARAM_FILS_MAX_CHANNEL_GUARD_TIME, + self_sta_req->fils_max_chan_guard_time); + if (QDF_IS_STATUS_ERROR(ret)) + WMA_LOGE("Failed to set WMI_VDEV_PARAM_FILS_MAX_CHANNEL_GUARD_TIME"); + } + + /* Initialize BMISS parameters */ + if ((self_sta_req->type == WMI_VDEV_TYPE_STA) && + (self_sta_req->sub_type == 0)) + wma_roam_scan_bmiss_cnt(wma_handle, + mac->roam.configParam.neighborRoamConfig.nRoamBmissFirstBcnt, + mac->roam.configParam.neighborRoamConfig.nRoamBmissFinalBcnt, + self_sta_req->session_id); + + if (wlan_cfg_get_int(mac, WNI_CFG_ENABLE_MCC_ADAPTIVE_SCHED, + &cfg_val) == eSIR_SUCCESS) { + WMA_LOGD("%s: setting ini value for WNI_CFG_ENABLE_MCC_ADAPTIVE_SCHED: %d", + __func__, cfg_val); + ret = wma_set_enable_disable_mcc_adaptive_scheduler(cfg_val); + if (ret != QDF_STATUS_SUCCESS) { + WMA_LOGE("Failed to set WNI_CFG_ENABLE_MCC_ADAPTIVE_SCHED"); + } + } else { + WMA_LOGE("Failed to get value for WNI_CFG_ENABLE_MCC_ADAPTIVE_SCHED, leaving unchanged"); + } + + wma_register_wow_wakeup_events(wma_handle, self_sta_req->session_id, + self_sta_req->type, + self_sta_req->sub_type); + + wma_register_action_frame_patterns(wma_handle, + self_sta_req->session_id); + wma_register_wow_default_patterns(wma_handle, self_sta_req->session_id); + + if (self_sta_req->type == WMI_VDEV_TYPE_STA) { + status = wma_config_active_bpf_mode(wma_handle, + self_sta_req->session_id); + if (QDF_IS_STATUS_ERROR(status)) + WMA_LOGE("Failed to configure active BPF mode"); + } + +end: + self_sta_req->status = status; + +#ifdef QCA_IBSS_SUPPORT + if (generateRsp) +#endif + { + sme_msg.type = eWNI_SME_ADD_STA_SELF_RSP; + sme_msg.bodyptr = self_sta_req; + sme_msg.bodyval = 0; + + status = cds_mq_post_message(QDF_MODULE_ID_SME, &sme_msg); + if (!QDF_IS_STATUS_SUCCESS(status)) { + WMA_LOGE("Failed to post eWNI_SME_ADD_STA_SELF_RSP"); + qdf_mem_free(self_sta_req); + } + } + return txrx_vdev_handle; +} + +/** + * wma_vdev_start() - send vdev start request to fw + * @wma: wma handle + * @req: vdev start params + * @isRestart: isRestart flag + * + * Return: QDF status + */ +QDF_STATUS wma_vdev_start(tp_wma_handle wma, + struct wma_vdev_start_req *req, bool isRestart) +{ + struct vdev_start_params params = { 0 }; + wmi_vdev_start_request_cmd_fixed_param *cmd; + struct wma_txrx_node *intr = wma->interfaces; + tpAniSirGlobal mac_ctx = NULL; + struct ath_dfs *dfs; + uint32_t temp_ssid_len = 0; + uint32_t temp_flags = 0; + uint32_t temp_chan_info = 0; + uint32_t temp_reg_info_1 = 0; + uint32_t temp_reg_info_2 = 0; + uint16_t bw_val; + + mac_ctx = cds_get_context(QDF_MODULE_ID_PE); + if (mac_ctx == NULL) { + WMA_LOGE("%s: vdev start failed as mac_ctx is NULL", __func__); + return QDF_STATUS_E_FAILURE; + } + + dfs = (struct ath_dfs *)wma->dfs_ic->ic_dfs; + + WMA_LOGD("%s: Enter isRestart=%d vdev=%d", __func__, isRestart, + req->vdev_id); + params.vdev_id = req->vdev_id; + + /* Fill channel info */ + params.chan_freq = cds_chan_to_freq(req->chan); + params.chan_mode = wma_chan_phy_mode(req->chan, req->chan_width, + req->dot11_mode); + intr[params.vdev_id].chanmode = params.chan_mode; + intr[params.vdev_id].ht_capable = req->ht_capable; + intr[params.vdev_id].vht_capable = req->vht_capable; + intr[params.vdev_id].config.gtx_info.gtxRTMask[0] = + CFG_TGT_DEFAULT_GTX_HT_MASK; + intr[params.vdev_id].config.gtx_info.gtxRTMask[1] = + CFG_TGT_DEFAULT_GTX_VHT_MASK; + + if (wlan_cfg_get_int(mac_ctx, WNI_CFG_TGT_GTX_USR_CFG, + &intr[params.vdev_id].config.gtx_info.gtxUsrcfg) != eSIR_SUCCESS) { + intr[params.vdev_id].config.gtx_info.gtxUsrcfg = + WNI_CFG_TGT_GTX_USR_CFG_STADEF; + QDF_TRACE(QDF_MODULE_ID_WMA, QDF_TRACE_LEVEL_WARN, + "Failed to get WNI_CFG_TGT_GTX_USR_CFG"); + } + + intr[params.vdev_id].config.gtx_info.gtxPERThreshold = + CFG_TGT_DEFAULT_GTX_PER_THRESHOLD; + intr[params.vdev_id].config.gtx_info.gtxPERMargin = + CFG_TGT_DEFAULT_GTX_PER_MARGIN; + intr[params.vdev_id].config.gtx_info.gtxTPCstep = + CFG_TGT_DEFAULT_GTX_TPC_STEP; + intr[params.vdev_id].config.gtx_info.gtxTPCMin = + CFG_TGT_DEFAULT_GTX_TPC_MIN; + intr[params.vdev_id].config.gtx_info.gtxBWMask = + CFG_TGT_DEFAULT_GTX_BW_MASK; + intr[params.vdev_id].mhz = params.chan_freq; + intr[params.vdev_id].chan_width = req->chan_width; + + temp_chan_info &= 0xffffffc0; + temp_chan_info |= params.chan_mode; + + params.band_center_freq1 = params.chan_freq; + + bw_val = cds_bw_value(req->chan_width); + if (20 < bw_val) + params.band_center_freq1 = + cds_chan_to_freq(req->ch_center_freq_seg0); + if (80 < bw_val) + params.band_center_freq2 = + cds_chan_to_freq(req->ch_center_freq_seg1); + else + params.band_center_freq2 = 0; + + /* Set half or quarter rate WMI flags */ + params.is_half_rate = req->is_half_rate; + params.is_quarter_rate = req->is_quarter_rate; + + if (req->is_half_rate) + temp_chan_info |= (1 << WMI_CHAN_FLAG_HALF_RATE); + else if (req->is_quarter_rate) + temp_chan_info |= (1 << WMI_CHAN_FLAG_QUARTER_RATE); + + params.is_dfs = req->is_dfs; + params.is_restart = isRestart; + if ((QDF_GLOBAL_MONITOR_MODE != cds_get_conparam()) && req->is_dfs) { + temp_chan_info |= (1 << WMI_CHAN_FLAG_DFS); + params.dis_hw_ack = true; + req->dfs_pri_multiplier = wma->dfs_pri_multiplier; + + /* + * Configure the current operating channel + * to DFS module only if the device operating + * mode is AP. + * Enable/Disable Phyerr filtering offload + * depending on dfs_phyerr_filter_offload + * flag status as set in ini for SAP mode. + * Currently, only AP supports DFS master + * mode operation on DFS channels, P2P-GO + * does not support operation on DFS Channels. + */ + if (wma_is_vdev_in_ap_mode(wma, params.vdev_id) == true) { + /* + * If the Channel is DFS, + * set the WMI_CHAN_FLAG_DFS flag + */ + params.flag_dfs = WMI_CHAN_FLAG_DFS; + /* + * If DFS regulatory domain is invalid, + * then, DFS radar filters intialization + * will fail. So, do not configure the + * channel in to DFS modlue, do not + * indicate if phyerror filtering offload + * is enabled or not to the firmware, simply + * fail the VDEV start on the DFS channel + * early on, to protect the DFS module from + * processing phyerrors without being intialized. + */ + if (DFS_UNINIT_REGION == + wma->dfs_ic->current_dfs_regdomain) { + WMA_LOGE("%s[%d]:DFS Configured with Invalid regdomain" + " Failed to send VDEV START command", + __func__, __LINE__); + + return QDF_STATUS_E_FAILURE; + } + + if (isRestart) + wma->dfs_ic->disable_phy_err_processing = true; + + /* provide the current channel to DFS */ + wma_dfs_configure_channel(wma->dfs_ic, + params.band_center_freq1, + params.band_center_freq2, req); + + wma_unified_dfs_phyerr_filter_offload_enable(wma); + dfs->disable_dfs_ch_switch = + mac_ctx->sap.SapDfsInfo.disable_dfs_ch_switch; + } + } + + params.beacon_intval = req->beacon_intval; + params.dtim_period = req->dtim_period; + /* FIXME: Find out min, max and regulatory power levels */ + params.max_txpow = req->max_txpow; + temp_reg_info_1 &= 0xff00ffff; + temp_reg_info_1 |= ((req->max_txpow&0xff) << 16); + + temp_reg_info_2 &= 0xffff00ff; + temp_reg_info_2 |= ((req->max_txpow&0xff)<<8); + + /* TODO: Handle regulatory class, max antenna */ + if (!isRestart) { + params.beacon_intval = req->beacon_intval; + params.dtim_period = req->dtim_period; + + /* Copy the SSID */ + if (req->ssid.length) { + params.ssid.length = req->ssid.length; + if (req->ssid.length < sizeof(cmd->ssid.ssid)) + temp_ssid_len = req->ssid.length; + else + temp_ssid_len = sizeof(cmd->ssid.ssid); + qdf_mem_copy(params.ssid.mac_ssid, req->ssid.ssId, + temp_ssid_len); + } + + params.hidden_ssid = req->hidden_ssid; + params.pmf_enabled = req->pmf_enabled; + if (req->hidden_ssid) + temp_flags |= WMI_UNIFIED_VDEV_START_HIDDEN_SSID; + + if (req->pmf_enabled) + temp_flags |= WMI_UNIFIED_VDEV_START_PMF_ENABLED; + } + + params.num_noa_descriptors = 0; + params.preferred_rx_streams = req->preferred_rx_streams; + params.preferred_tx_streams = req->preferred_tx_streams; + + /* Store vdev params in SAP mode which can be used in vdev restart */ + if (intr[req->vdev_id].type == WMI_VDEV_TYPE_AP && + intr[req->vdev_id].sub_type == 0) { + intr[req->vdev_id].vdev_restart_params.vdev_id = req->vdev_id; + intr[req->vdev_id].vdev_restart_params.ssid.ssid_len = + temp_ssid_len; + qdf_mem_copy(intr[req->vdev_id].vdev_restart_params.ssid.ssid, + params.ssid.mac_ssid, temp_ssid_len); + intr[req->vdev_id].vdev_restart_params.flags = temp_flags; + intr[req->vdev_id].vdev_restart_params.requestor_id = 0; + intr[req->vdev_id].vdev_restart_params.disable_hw_ack = + params.dis_hw_ack; + intr[req->vdev_id].vdev_restart_params.chan.mhz = + params.chan_freq; + intr[req->vdev_id].vdev_restart_params.chan.band_center_freq1 = + params.band_center_freq1; + intr[req->vdev_id].vdev_restart_params.chan.band_center_freq2 = + params.band_center_freq2; + intr[req->vdev_id].vdev_restart_params.chan.info = + temp_chan_info; + intr[req->vdev_id].vdev_restart_params.chan.reg_info_1 = + temp_reg_info_1; + intr[req->vdev_id].vdev_restart_params.chan.reg_info_2 = + temp_reg_info_2; + } + + if (isRestart) { + /* + * Marking the VDEV UP STATUS to false + * since, VDEV RESTART will do a VDEV DOWN + * in the firmware. + */ + intr[params.vdev_id].vdev_up = false; + } else { + WMA_LOGD("%s, vdev_id: %d, unpausing tx_ll_queue at VDEV_START", + __func__, params.vdev_id); + ol_txrx_vdev_unpause(wma->interfaces[params.vdev_id].handle, + 0xffffffff); + wma->interfaces[params.vdev_id].pause_bitmap = 0; + } + + return wma_send_vdev_start_to_fw(wma, ¶ms); +} + +/** + * wma_peer_assoc_conf_handler() - peer assoc conf handler + * @handle: wma handle + * @cmd_param_info: event buffer + * @len: buffer length + * + * Return: 0 for success or error code + */ +int wma_peer_assoc_conf_handler(void *handle, uint8_t *cmd_param_info, + uint32_t len) +{ + tp_wma_handle wma = (tp_wma_handle) handle; + WMI_PEER_ASSOC_CONF_EVENTID_param_tlvs *param_buf; + wmi_peer_assoc_conf_event_fixed_param *event; + struct wma_target_req *req_msg; + uint8_t macaddr[IEEE80211_ADDR_LEN]; + int status = 0; + + WMA_LOGD(FL("Enter")); + param_buf = (WMI_PEER_ASSOC_CONF_EVENTID_param_tlvs *) cmd_param_info; + if (!param_buf) { + WMA_LOGE("Invalid peer assoc conf event buffer"); + return -EINVAL; + } + + event = param_buf->fixed_param; + if (!event) { + WMA_LOGE("Invalid peer assoc conf event buffer"); + return -EINVAL; + } + + WMI_MAC_ADDR_TO_CHAR_ARRAY(&event->peer_macaddr, macaddr); + WMA_LOGD(FL("peer assoc conf for vdev:%d mac=%pM"), + event->vdev_id, macaddr); + + req_msg = wma_find_req(wma, event->vdev_id, + WMA_PEER_ASSOC_CNF_START); + + if (!req_msg) { + WMA_LOGE(FL("Failed to lookup request message for vdev %d"), + event->vdev_id); + return -EINVAL; + } + + qdf_mc_timer_stop(&req_msg->event_timeout); + + if (req_msg->msg_type == WMA_ADD_STA_REQ) { + tpAddStaParams params = (tpAddStaParams)req_msg->user_data; + if (!params) { + WMA_LOGE(FL("add STA params is NULL for vdev %d"), + event->vdev_id); + status = -EINVAL; + goto free_req_msg; + } + + /* peer assoc conf event means the cmd succeeds */ + params->status = QDF_STATUS_SUCCESS; + WMA_LOGE(FL("Send ADD_STA_RSP: statype %d vdev_id %d aid %d bssid %pM staIdx %d status %d"), + params->staType, params->smesessionId, + params->assocId, params->bssId, params->staIdx, + params->status); + wma_send_msg(wma, WMA_ADD_STA_RSP, (void *)params, 0); + } else if (req_msg->msg_type == WMA_ADD_BSS_REQ) { + tpAddBssParams params = (tpAddBssParams) req_msg->user_data; + if (!params) { + WMA_LOGE(FL("add BSS params is NULL for vdev %d"), + event->vdev_id); + status = -EINVAL; + goto free_req_msg; + } + + /* peer assoc conf event means the cmd succeeds */ + params->status = QDF_STATUS_SUCCESS; + WMA_LOGE(FL("Send ADD BSS RSP: opermode %d update_bss %d nw_type %d bssid %pM" + " staIdx %d status %d"), params->operMode, + params->updateBss, params->nwType, params->bssId, + params->staContext.staIdx, params->status); + wma_send_msg(wma, WMA_ADD_BSS_RSP, (void *)params, 0); + } else { + WMA_LOGE(FL("Unhandled request message type: %d"), + req_msg->msg_type); + } + +free_req_msg: + qdf_mc_timer_destroy(&req_msg->event_timeout); + qdf_mem_free(req_msg); + + return status; +} + +/** + * wma_vdev_delete_handler() - vdev delete response handler + * @handle: wma handle + * @cmd_param_info: event buffer + * @len: buffer length + * + * Return: 0 for success or error code + */ +int wma_vdev_delete_handler(void *handle, uint8_t *cmd_param_info, + uint32_t len) +{ + tp_wma_handle wma = (tp_wma_handle) handle; + WMI_VDEV_DELETE_RESP_EVENTID_param_tlvs *param_buf; + wmi_vdev_delete_cmd_fixed_param *event; + struct wma_target_req *req_msg; + int status = 0; + + param_buf = (WMI_VDEV_DELETE_RESP_EVENTID_param_tlvs *)cmd_param_info; + if (!param_buf) { + WMA_LOGE("Invalid vdev delete event buffer"); + return -EINVAL; + } + + event = (wmi_vdev_delete_cmd_fixed_param *)param_buf->fixed_param; + if (!event) { + WMA_LOGE("Invalid vdev delete event buffer"); + return -EINVAL; + } + + WMA_LOGE("%s Vdev delete resp vdev id %d", __func__, event->vdev_id); + req_msg = wma_find_vdev_req(wma, event->vdev_id, + WMA_TARGET_REQ_TYPE_VDEV_DEL); + if (!req_msg) { + WMA_LOGD(FL("Vdev delete resp is not handled! vdev id %d"), + event->vdev_id); + return -EINVAL; + } + qdf_wake_lock_release(&wma->wmi_cmd_rsp_wake_lock, + WIFI_POWER_EVENT_WAKELOCK_WMI_CMD_RSP); + qdf_runtime_pm_allow_suspend(&wma->wmi_cmd_rsp_runtime_lock); + /* Send response to upper layers */ + wma_vdev_detach_callback(req_msg->user_data); + qdf_mc_timer_stop(&req_msg->event_timeout); + qdf_mc_timer_destroy(&req_msg->event_timeout); + qdf_mem_free(req_msg); + + return status; +} + +/** + * wma_peer_delete_handler() - peer delete response handler + * @handle: wma handle + * @cmd_param_info: event buffer + * @len: buffer length + * + * Return: 0 for success or error code + */ +int wma_peer_delete_handler(void *handle, uint8_t *cmd_param_info, + uint32_t len) +{ + tp_wma_handle wma = (tp_wma_handle) handle; + WMI_PEER_DELETE_RESP_EVENTID_param_tlvs *param_buf; + wmi_peer_delete_cmd_fixed_param *event; + struct wma_target_req *req_msg; + tDeleteStaParams *del_sta; + uint8_t macaddr[IEEE80211_ADDR_LEN]; + int status = 0; + + param_buf = (WMI_PEER_DELETE_RESP_EVENTID_param_tlvs *)cmd_param_info; + if (!param_buf) { + WMA_LOGE("Invalid vdev delete event buffer"); + return -EINVAL; + } + + event = (wmi_peer_delete_cmd_fixed_param *)param_buf->fixed_param; + if (!event) { + WMA_LOGE("Invalid vdev delete event buffer"); + return -EINVAL; + } + + WMI_MAC_ADDR_TO_CHAR_ARRAY(&event->peer_macaddr, macaddr); + WMA_LOGE(FL("Peer Delete Response, vdev %d Peer %pM"), + event->vdev_id, macaddr); + wma_peer_debug_log(event->vdev_id, DEBUG_PEER_DELETE_RESP, + DEBUG_INVALID_PEER_ID, macaddr, NULL, + 0, + 0); + req_msg = wma_find_remove_req_msgtype(wma, event->vdev_id, + WMA_DELETE_STA_REQ); + if (!req_msg) { + WMA_LOGD("Peer Delete response is not handled"); + return -EINVAL; + } + + qdf_wake_lock_release(&wma->wmi_cmd_rsp_wake_lock, + WIFI_POWER_EVENT_WAKELOCK_WMI_CMD_RSP); + qdf_runtime_pm_allow_suspend(&wma->wmi_cmd_rsp_runtime_lock); + /* Cleanup timeout handler */ + qdf_mc_timer_stop(&req_msg->event_timeout); + qdf_mc_timer_destroy(&req_msg->event_timeout); + + if (req_msg->type == WMA_DELETE_STA_RSP_START) { + del_sta = req_msg->user_data; + if (del_sta->respReqd) { + WMA_LOGD(FL("Sending peer del rsp to umac")); + wma_send_msg(wma, WMA_DELETE_STA_RSP, + (void *)del_sta, QDF_STATUS_SUCCESS); + } else { + qdf_mem_free(del_sta); + } + } else if (req_msg->type == WMA_DEL_P2P_SELF_STA_RSP_START) { + struct del_sta_self_rsp_params *data; + data = (struct del_sta_self_rsp_params *)req_msg->user_data; + WMA_LOGD(FL("Calling vdev detach handler")); + wma_handle_vdev_detach(wma, data->self_sta_param, + data->generate_rsp); + qdf_mem_free(data); + } else if (req_msg->type == WMA_SET_LINK_PEER_RSP) { + tpLinkStateParams params = + (tpLinkStateParams) req_msg->user_data; + if (wmi_unified_vdev_down_send(wma->wmi_handle, + req_msg->vdev_id) != + QDF_STATUS_SUCCESS) { + WMA_LOGE("Failed to send vdev down cmd: vdev %d", + req_msg->vdev_id); + } + wma_send_msg(wma, WMA_SET_LINK_STATE_RSP, (void *)params, 0); + + } else if (req_msg->type == WMA_DELETE_PEER_RSP) { + wma_send_del_bss_response(wma, req_msg, req_msg->vdev_id); + } + qdf_mem_free(req_msg); + return status; +} + +static inline bool wma_crash_on_fw_timeout(bool crash_enabled) +{ + /* Discard FW timeouts and dont crash during SSR */ + if (cds_is_driver_recovering()) + return false; + + if (cds_is_driver_unloading()) + return false; + + return crash_enabled; +} + +/** + * wma_hold_req_timer() - wma hold request timeout function + * @data: target request params + * + * Return: none + */ +void wma_hold_req_timer(void *data) +{ + tp_wma_handle wma; + struct wma_target_req *tgt_req = (struct wma_target_req *)data; + struct wma_target_req *msg; + + wma = cds_get_context(QDF_MODULE_ID_WMA); + if (NULL == wma) { + WMA_LOGE(FL("Failed to get wma")); + return; + } + + WMA_LOGA(FL("request %d is timed out for vdev_id - %d"), + tgt_req->msg_type, tgt_req->vdev_id); + msg = wma_find_req(wma, tgt_req->vdev_id, tgt_req->type); + + if (!msg) { + WMA_LOGE(FL("Failed to lookup request message - %d"), + tgt_req->msg_type); + /* + * if find request failed, then firmware rsp should have + * consumed the buffer. Do not free. + */ + return; + } + + if (tgt_req->msg_type == WMA_ADD_STA_REQ) { + tpAddStaParams params = (tpAddStaParams) tgt_req->user_data; + params->status = QDF_STATUS_E_TIMEOUT; + WMA_LOGA(FL("WMA_ADD_STA_REQ timed out")); + WMA_LOGD(FL("Sending add sta rsp to umac (mac:%pM, status:%d)"), + params->staMac, params->status); + if (wma_crash_on_fw_timeout(wma->fw_timeout_crash) == true) + QDF_BUG(0); + else + wma_send_msg(wma, WMA_ADD_STA_RSP, (void *)params, 0); + } else if (tgt_req->msg_type == WMA_ADD_BSS_REQ) { + tpAddBssParams params = (tpAddBssParams) tgt_req->user_data; + params->status = QDF_STATUS_E_TIMEOUT; + WMA_LOGA(FL("WMA_ADD_BSS_REQ timed out")); + WMA_LOGD(FL("Sending add bss rsp to umac (mac:%pM, status:%d)"), + params->selfMacAddr, params->status); + if (wma_crash_on_fw_timeout(wma->fw_timeout_crash) == true) + QDF_BUG(0); + else + wma_send_msg(wma, WMA_ADD_BSS_RSP, (void *)params, 0); + } else if ((tgt_req->msg_type == WMA_DELETE_STA_REQ) && + (tgt_req->type == WMA_DELETE_STA_RSP_START)) { + tpDeleteStaParams params = + (tpDeleteStaParams) tgt_req->user_data; + params->status = QDF_STATUS_E_TIMEOUT; + WMA_LOGE(FL("WMA_DEL_STA_REQ timed out")); + WMA_LOGP(FL("Sending del sta rsp to umac (mac:%pM, status:%d)"), + params->staMac, params->status); + + if (wma_crash_on_fw_timeout(wma->fw_timeout_crash) == true) { + QDF_BUG(0); + } else { + /* + * Assert in development build only. + * Send response in production builds. + */ + QDF_ASSERT(0); + wma_send_msg(wma, WMA_DELETE_STA_RSP, + (void *)params, 0); + } + } else if ((tgt_req->msg_type == WMA_DELETE_STA_REQ) && + (tgt_req->type == WMA_DEL_P2P_SELF_STA_RSP_START)) { + struct del_sta_self_rsp_params *del_sta; + del_sta = (struct del_sta_self_rsp_params *)tgt_req->user_data; + del_sta->self_sta_param->status = QDF_STATUS_E_TIMEOUT; + WMA_LOGA(FL("wma delete sta p2p request timed out")); + + if (wma_crash_on_fw_timeout(wma->fw_timeout_crash)) { + QDF_BUG(0); + } else { + if (del_sta->generate_rsp) + wma_send_del_sta_self_resp( + del_sta->self_sta_param); + } + qdf_mem_free(tgt_req->user_data); + } else if ((tgt_req->msg_type == WMA_DELETE_STA_REQ) && + (tgt_req->type == WMA_SET_LINK_PEER_RSP)) { + tpLinkStateParams params = + (tpLinkStateParams) tgt_req->user_data; + + params->status = false; + WMA_LOGA(FL("wma delete peer for set link timed out")); + if (wma_crash_on_fw_timeout(wma->fw_timeout_crash) == true) + QDF_BUG(0); + else + wma_send_msg(wma, WMA_SET_LINK_STATE_RSP, + params, 0); + } else if ((tgt_req->msg_type == WMA_DELETE_STA_REQ) && + (tgt_req->type == WMA_DELETE_PEER_RSP)) { + tpDeleteBssParams params = + (tpDeleteBssParams) tgt_req->user_data; + + params->status = QDF_STATUS_E_TIMEOUT; + WMA_LOGE(FL("wma delete peer for del bss req timed out")); + if (wma_crash_on_fw_timeout(wma->fw_timeout_crash) == true) + QDF_BUG(0); + else + wma_send_msg(wma, WMA_DELETE_BSS_RSP, params, 0); + } else { + WMA_LOGE(FL("Unhandled timeout for msg_type:%d and type:%d"), + tgt_req->msg_type, tgt_req->type); + QDF_BUG(0); + } + qdf_mem_free(tgt_req); +} + +/** + * wma_fill_hold_req() - fill wma request + * @wma: wma handle + * @msg_type: message type + * @type: request type + * @params: request params + * @timeout: timeout value + * + * Return: wma_target_req ptr + */ +struct wma_target_req *wma_fill_hold_req(tp_wma_handle wma, + uint8_t vdev_id, + uint32_t msg_type, uint8_t type, + void *params, uint32_t timeout) +{ + struct wma_target_req *req; + QDF_STATUS status; + + req = qdf_mem_malloc(sizeof(*req)); + if (!req) { + WMA_LOGP(FL("Failed to allocate memory for msg %d vdev %d"), + msg_type, vdev_id); + return NULL; + } + + WMA_LOGD(FL("vdev_id %d msg %d type %d"), vdev_id, msg_type, type); + qdf_spin_lock_bh(&wma->wma_hold_req_q_lock); + req->vdev_id = vdev_id; + req->msg_type = msg_type; + req->type = type; + req->user_data = params; + status = qdf_list_insert_back(&wma->wma_hold_req_queue, &req->node); + if (QDF_STATUS_SUCCESS != status) { + qdf_spin_unlock_bh(&wma->wma_hold_req_q_lock); + WMA_LOGE(FL("Failed add request in queue")); + qdf_mem_free(req); + return NULL; + } + qdf_spin_unlock_bh(&wma->wma_hold_req_q_lock); + qdf_mc_timer_init(&req->event_timeout, QDF_TIMER_TYPE_SW, + wma_hold_req_timer, req); + qdf_mc_timer_start(&req->event_timeout, timeout); + return req; +} + +/** + * wma_remove_req() - remove request + * @wma: wma handle + * @vdev_id: vdev id + * @type: type + * + * Return: none + */ +void wma_remove_req(tp_wma_handle wma, uint8_t vdev_id, + uint8_t type) +{ + struct wma_target_req *req_msg; + + WMA_LOGE(FL("Remove req for vdev: %d type: %d"), vdev_id, type); + req_msg = wma_find_req(wma, vdev_id, type); + if (!req_msg) { + WMA_LOGE(FL("target req not found for vdev: %d type: %d"), + vdev_id, type); + return; + } + + qdf_mc_timer_stop(&req_msg->event_timeout); + qdf_mc_timer_destroy(&req_msg->event_timeout); + qdf_mem_free(req_msg); +} + +/** + * wma_vdev_resp_timer() - wma response timeout function + * @data: target request params + * + * Return: none + */ +void wma_vdev_resp_timer(void *data) +{ + tp_wma_handle wma; + struct wma_target_req *tgt_req = (struct wma_target_req *)data; + ol_txrx_peer_handle peer; + ol_txrx_pdev_handle pdev; + uint8_t peer_id; + struct wma_target_req *msg; +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE + tpAniSirGlobal mac_ctx = cds_get_context(QDF_MODULE_ID_PE); + if (NULL == mac_ctx) { + WMA_LOGE("%s: Failed to get mac_ctx", __func__); + wma_cleanup_target_req_param(tgt_req); + goto free_tgt_req; + } +#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ + + wma = cds_get_context(QDF_MODULE_ID_WMA); + + if (NULL == wma) { + WMA_LOGE("%s: Failed to get wma", __func__); + wma_cleanup_target_req_param(tgt_req); + goto free_tgt_req; + } + + pdev = cds_get_context(QDF_MODULE_ID_TXRX); + + if (NULL == pdev) { + WMA_LOGE("%s: Failed to get pdev", __func__); + wma_cleanup_target_req_param(tgt_req); + qdf_mc_timer_stop(&tgt_req->event_timeout); + goto free_tgt_req; + } + + WMA_LOGA("%s: request %d is timed out for vdev_id - %d", __func__, + tgt_req->msg_type, tgt_req->vdev_id); + msg = wma_find_vdev_req(wma, tgt_req->vdev_id, tgt_req->type); + + if (!msg) { + WMA_LOGE("%s: Failed to lookup request message - %d", + __func__, tgt_req->msg_type); + wma_cleanup_target_req_param(tgt_req); + goto free_tgt_req; + } + + if (tgt_req->msg_type == WMA_CHNL_SWITCH_REQ) { + tpSwitchChannelParams params = + (tpSwitchChannelParams) tgt_req->user_data; + params->status = QDF_STATUS_E_TIMEOUT; + WMA_LOGA("%s: WMA_SWITCH_CHANNEL_REQ timedout", __func__); + + /* Trigger host crash if the flag is set */ + if (wma_crash_on_fw_timeout(wma->fw_timeout_crash) == true) + QDF_BUG(0); + else + wma_send_msg(wma, WMA_SWITCH_CHANNEL_RSP, + (void *)params, 0); + if (wma->interfaces[tgt_req->vdev_id].is_channel_switch) { + wma->interfaces[tgt_req->vdev_id].is_channel_switch = + false; + } + } else if (tgt_req->msg_type == WMA_DELETE_BSS_REQ) { + tpDeleteBssParams params = + (tpDeleteBssParams) tgt_req->user_data; + struct beacon_info *bcn; + struct wma_txrx_node *iface; + + if (tgt_req->vdev_id > wma->max_bssid) { + WMA_LOGE("%s: Invalid vdev_id %d", __func__, + tgt_req->vdev_id); + wma_cleanup_target_req_param(tgt_req); + qdf_mc_timer_stop(&tgt_req->event_timeout); + goto free_tgt_req; + } + + iface = &wma->interfaces[tgt_req->vdev_id]; + if (iface->handle == NULL) { + WMA_LOGE("%s vdev id %d is already deleted", + __func__, tgt_req->vdev_id); + wma_cleanup_target_req_param(tgt_req); + qdf_mc_timer_stop(&tgt_req->event_timeout); + goto free_tgt_req; + } + /* Trigger host crash when vdev response timesout */ + if (wma_crash_on_fw_timeout(wma->fw_timeout_crash) == true) { + QDF_BUG(0); + return; + } + + if (wma_is_vdev_in_ibss_mode(wma, tgt_req->vdev_id)) + wma_delete_all_ibss_peers(wma, tgt_req->vdev_id); + else { + if (wma_is_vdev_in_ap_mode(wma, tgt_req->vdev_id)) { + wma_delete_all_ap_remote_peers(wma, + tgt_req-> + vdev_id); + } + peer = ol_txrx_find_peer_by_addr(pdev, params->bssid, + &peer_id); + wma_remove_peer(wma, params->bssid, tgt_req->vdev_id, + peer, false); + } + + if (wmi_unified_vdev_down_send(wma->wmi_handle, + tgt_req->vdev_id) != QDF_STATUS_SUCCESS) { + WMA_LOGE("Failed to send vdev down cmd: vdev %d", + tgt_req->vdev_id); + } else { + wma->interfaces[tgt_req->vdev_id].vdev_up = false; +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE + if (mac_ctx->sap.sap_channel_avoidance) + wma_find_mcc_ap(wma, tgt_req->vdev_id, false); +#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ + } + ol_txrx_vdev_flush(iface->handle); + WMA_LOGD("%s, vdev_id: %d, un-pausing tx_ll_queue for WDA_DELETE_BSS_REQ timeout", + __func__, tgt_req->vdev_id); + ol_txrx_vdev_unpause(iface->handle, + OL_TXQ_PAUSE_REASON_VDEV_STOP); + iface->pause_bitmap &= ~(1 << PAUSE_TYPE_HOST); + qdf_atomic_set(&iface->bss_status, WMA_BSS_STATUS_STOPPED); + WMA_LOGD("%s: (type %d subtype %d) BSS is stopped", + __func__, iface->type, iface->sub_type); + + bcn = wma->interfaces[tgt_req->vdev_id].beacon; + + if (bcn) { + WMA_LOGD("%s: Freeing beacon struct %p, " + "template memory %p", __func__, bcn, bcn->buf); + if (bcn->dma_mapped) + qdf_nbuf_unmap_single(pdev->osdev, bcn->buf, + QDF_DMA_TO_DEVICE); + qdf_nbuf_free(bcn->buf); + qdf_mem_free(bcn); + wma->interfaces[tgt_req->vdev_id].beacon = NULL; + } + params->status = QDF_STATUS_E_TIMEOUT; + WMA_LOGA("%s: WMA_DELETE_BSS_REQ timedout", __func__); + wma_send_msg(wma, WMA_DELETE_BSS_RSP, + (void *)params, 0); + if (iface->del_staself_req) { + WMA_LOGA("scheduling defered deletion(vdev id %x)", + tgt_req->vdev_id); + wma_vdev_detach(wma, iface->del_staself_req, 1); + } + } else if (tgt_req->msg_type == WMA_DEL_STA_SELF_REQ) { + struct wma_txrx_node *iface = + (struct wma_txrx_node *)tgt_req->user_data; + struct del_sta_self_params *params = + (struct del_sta_self_params *) iface->del_staself_req; + + if (WMI_SERVICE_IS_ENABLED(wma->wmi_service_bitmap, + WMI_SERVICE_SYNC_DELETE_CMDS)) { + qdf_wake_lock_release(&wma->wmi_cmd_rsp_wake_lock, + WIFI_POWER_EVENT_WAKELOCK_WMI_CMD_RSP); + qdf_runtime_pm_allow_suspend( + &wma->wmi_cmd_rsp_runtime_lock); + } + params->status = QDF_STATUS_E_TIMEOUT; + + WMA_LOGA("%s: WMA_DEL_STA_SELF_REQ timedout", __func__); + if (wma_crash_on_fw_timeout(wma->fw_timeout_crash) == true) + QDF_BUG(0); + else + wma_send_del_sta_self_resp(iface->del_staself_req); + + if (iface->addBssStaContext) + qdf_mem_free(iface->addBssStaContext); + if (iface->staKeyParams) + qdf_mem_free(iface->staKeyParams); + qdf_mem_zero(iface, sizeof(*iface)); + } else if (tgt_req->msg_type == WMA_ADD_BSS_REQ) { + tpAddBssParams params = (tpAddBssParams) tgt_req->user_data; + + WMA_LOGA("%s: WMA_ADD_BSS_REQ timedout", __func__); + WMA_LOGI("%s: bssid %pM vdev_id %d", __func__, params->bssId, + tgt_req->vdev_id); + if (wma_crash_on_fw_timeout(wma->fw_timeout_crash) == true) { + QDF_BUG(0); + } else { + wma_send_msg(wma, WMA_ADD_BSS_RSP, (void *)params, 0); + QDF_ASSERT(0); + } + goto free_tgt_req; + + } else if (tgt_req->msg_type == WMA_OCB_SET_CONFIG_CMD) { + struct wma_txrx_node *iface; + + WMA_LOGE(FL("Failed to send OCB set config cmd")); + iface = &wma->interfaces[tgt_req->vdev_id]; + iface->vdev_up = false; + wma_ocb_set_config_resp(wma, QDF_STATUS_E_TIMEOUT); + } else if (tgt_req->msg_type == WMA_HIDDEN_SSID_VDEV_RESTART) { + WMA_LOGE("Hidden ssid vdev restart Timed Out; vdev_id: %d, type = %d", + tgt_req->vdev_id, tgt_req->type); + } else if (tgt_req->msg_type == WMA_SET_LINK_STATE) { + tpLinkStateParams params = + (tpLinkStateParams) tgt_req->user_data; + + peer = ol_txrx_find_peer_by_addr(pdev, params->bssid, &peer_id); + if (peer) { + WMA_LOGP(FL("Deleting peer %pM vdev id %d"), + params->bssid, tgt_req->vdev_id); + wma_remove_peer(wma, params->bssid, tgt_req->vdev_id, + peer, false); + } + if (wmi_unified_vdev_down_send(wma->wmi_handle, + tgt_req->vdev_id) != + QDF_STATUS_SUCCESS) { + WMA_LOGE("Failed to send vdev down cmd: vdev %d", + tgt_req->vdev_id); + } + params->status = QDF_STATUS_E_TIMEOUT; + WMA_LOGA("%s: WMA_SET_LINK_STATE timedout vdev %d", __func__, + tgt_req->vdev_id); + wma_send_msg(wma, WMA_SET_LINK_STATE_RSP, (void *)params, 0); + } +free_tgt_req: + qdf_mc_timer_destroy(&tgt_req->event_timeout); + qdf_mem_free(tgt_req); +} + +/** + * wma_fill_vdev_req() - fill vdev request + * @wma: wma handle + * @msg_type: message type + * @type: request type + * @params: request params + * @timeout: timeout value + * + * Return: wma_target_req ptr + */ +struct wma_target_req *wma_fill_vdev_req(tp_wma_handle wma, + uint8_t vdev_id, + uint32_t msg_type, uint8_t type, + void *params, uint32_t timeout) +{ + struct wma_target_req *req; + QDF_STATUS status; + + req = qdf_mem_malloc(sizeof(*req)); + if (!req) { + WMA_LOGP("%s: Failed to allocate memory for msg %d vdev %d", + __func__, msg_type, vdev_id); + return NULL; + } + + WMA_LOGD("%s: vdev_id %d msg %d", __func__, vdev_id, msg_type); + qdf_spin_lock_bh(&wma->vdev_respq_lock); + req->vdev_id = vdev_id; + req->msg_type = msg_type; + req->type = type; + req->user_data = params; + status = qdf_list_insert_back(&wma->vdev_resp_queue, &req->node); + if (QDF_STATUS_SUCCESS != status) { + qdf_spin_unlock_bh(&wma->vdev_respq_lock); + WMA_LOGE(FL("Failed add request in queue for vdev_id %d type %d"), + vdev_id, type); + qdf_mem_free(req); + return NULL; + } + qdf_spin_unlock_bh(&wma->vdev_respq_lock); + qdf_mc_timer_init(&req->event_timeout, QDF_TIMER_TYPE_SW, + wma_vdev_resp_timer, req); + qdf_mc_timer_start(&req->event_timeout, timeout); + return req; +} + +/** + * wma_remove_vdev_req() - remove vdev request + * @wma: wma handle + * @vdev_id: vdev id + * @type: type + * + * Return: none + */ +void wma_remove_vdev_req(tp_wma_handle wma, uint8_t vdev_id, + uint8_t type) +{ + struct wma_target_req *req_msg; + + req_msg = wma_find_vdev_req(wma, vdev_id, type); + if (!req_msg) + return; + + qdf_mc_timer_stop(&req_msg->event_timeout); + qdf_mc_timer_destroy(&req_msg->event_timeout); + qdf_mem_free(req_msg); +} + +/** + * wma_vdev_set_bss_params() - BSS set params functions + * @wma: wma handle + * @vdev_id: vdev id + * @beaconInterval: beacon interval + * @dtimPeriod: DTIM period + * @shortSlotTimeSupported: short slot time + * @llbCoexist: llbCoexist + * @maxTxPower: max tx power + * + * Return: none + */ +static void +wma_vdev_set_bss_params(tp_wma_handle wma, int vdev_id, + tSirMacBeaconInterval beaconInterval, + uint8_t dtimPeriod, uint8_t shortSlotTimeSupported, + uint8_t llbCoexist, int8_t maxTxPower) +{ + QDF_STATUS ret; + uint32_t slot_time; + struct wma_txrx_node *intr = wma->interfaces; + + /* Beacon Interval setting */ + ret = wma_vdev_set_param(wma->wmi_handle, vdev_id, + WMI_VDEV_PARAM_BEACON_INTERVAL, + beaconInterval); + + if (QDF_IS_STATUS_ERROR(ret)) + WMA_LOGE("failed to set WMI_VDEV_PARAM_BEACON_INTERVAL"); + + ret = wmi_unified_vdev_set_gtx_cfg_send(wma->wmi_handle, vdev_id, + &intr[vdev_id].config.gtx_info); + if (QDF_IS_STATUS_ERROR(ret)) + WMA_LOGE("failed to set WMI_VDEV_PARAM_DTIM_PERIOD"); + + ret = wma_vdev_set_param(wma->wmi_handle, vdev_id, + WMI_VDEV_PARAM_DTIM_PERIOD, + dtimPeriod); + if (QDF_IS_STATUS_ERROR(ret)) + WMA_LOGE("failed to set WMI_VDEV_PARAM_DTIM_PERIOD"); + + if (!maxTxPower) { + WMA_LOGW("Setting Tx power limit to 0"); + } + + WMA_LOGI("Set maxTx pwr [WMI_VDEV_PARAM_TX_PWRLIMIT] to %d", + maxTxPower); + + ret = wma_vdev_set_param(wma->wmi_handle, vdev_id, + WMI_VDEV_PARAM_TX_PWRLIMIT, + maxTxPower); + if (QDF_IS_STATUS_ERROR(ret)) + WMA_LOGE("failed to set WMI_VDEV_PARAM_TX_PWRLIMIT"); + else + intr[vdev_id].max_tx_power = maxTxPower; + + /* Slot time */ + if (shortSlotTimeSupported) + slot_time = WMI_VDEV_SLOT_TIME_SHORT; + else + slot_time = WMI_VDEV_SLOT_TIME_LONG; + + ret = wma_vdev_set_param(wma->wmi_handle, vdev_id, + WMI_VDEV_PARAM_SLOT_TIME, + slot_time); + if (QDF_IS_STATUS_ERROR(ret)) + WMA_LOGE("failed to set WMI_VDEV_PARAM_SLOT_TIME"); + + /* Initialize protection mode in case of coexistence */ + wma_update_protection_mode(wma, vdev_id, llbCoexist); +} + +/** + * wma_add_bss_ap_mode() - process add bss request in ap mode + * @wma: wma handle + * @add_bss: add bss parameters + * + * Return: none + */ +static void wma_add_bss_ap_mode(tp_wma_handle wma, tpAddBssParams add_bss) +{ + ol_txrx_pdev_handle pdev; + ol_txrx_vdev_handle vdev; + struct wma_vdev_start_req req; + ol_txrx_peer_handle peer; + struct wma_target_req *msg; + uint8_t vdev_id, peer_id; + QDF_STATUS status; + int8_t maxTxPower; + struct pdev_params param = {0}; +#ifdef WLAN_FEATURE_11W + QDF_STATUS ret; +#endif /* WLAN_FEATURE_11W */ + struct sir_hw_mode_params hw_mode = {0}; + uint32_t wow_mask[WMI_WOW_MAX_EVENT_BM_LEN] = {0}; + + pdev = cds_get_context(QDF_MODULE_ID_TXRX); + + if (NULL == pdev) { + WMA_LOGE("%s: Failed to get pdev", __func__); + goto send_fail_resp; + } + + vdev = wma_find_vdev_by_addr(wma, add_bss->bssId, &vdev_id); + if (!vdev) { + WMA_LOGE("%s: Failed to get vdev handle:"MAC_ADDRESS_STR, + __func__, MAC_ADDR_ARRAY(add_bss->bssId)); + + goto send_fail_resp; + } + if (SAP_WPS_DISABLED == add_bss->wps_state) { + wma_set_wow_event_bitmap(WOW_PROBE_REQ_WPS_IE_EVENT, + WMI_WOW_MAX_EVENT_BM_LEN, + wow_mask); + + wma_enable_disable_wakeup_event(wma, vdev_id, + wow_mask, false); + } + wma_set_bss_rate_flags(&wma->interfaces[vdev_id], add_bss); + status = wma_create_peer(wma, pdev, vdev, add_bss->bssId, + WMI_PEER_TYPE_DEFAULT, vdev_id, false); + if (status != QDF_STATUS_SUCCESS) { + WMA_LOGE("%s: Failed to create peer", __func__); + goto send_fail_resp; + } + + peer = ol_txrx_find_peer_by_addr(pdev, add_bss->bssId, &peer_id); + if (!peer) { + WMA_LOGE("%s Failed to find peer %pM", __func__, + add_bss->bssId); + goto send_fail_resp; + } + msg = wma_fill_vdev_req(wma, vdev_id, WMA_ADD_BSS_REQ, + WMA_TARGET_REQ_TYPE_VDEV_START, add_bss, + WMA_VDEV_START_REQUEST_TIMEOUT); + if (!msg) { + WMA_LOGP("%s Failed to allocate vdev request vdev_id %d", + __func__, vdev_id); + goto peer_cleanup; + } + + add_bss->staContext.staIdx = ol_txrx_local_peer_id(peer); + + qdf_mem_zero(&req, sizeof(req)); + req.vdev_id = vdev_id; + req.chan = add_bss->currentOperChannel; + req.chan_width = add_bss->ch_width; + + if (add_bss->ch_width == CH_WIDTH_10MHZ) + req.is_half_rate = 1; + else if (add_bss->ch_width == CH_WIDTH_5MHZ) + req.is_quarter_rate = 1; + + req.ch_center_freq_seg0 = add_bss->ch_center_freq_seg0; + req.ch_center_freq_seg1 = add_bss->ch_center_freq_seg1; + req.vht_capable = add_bss->vhtCapable; + req.max_txpow = add_bss->maxTxPower; + maxTxPower = add_bss->maxTxPower; +#ifdef WLAN_FEATURE_11W + if (add_bss->rmfEnabled) { + /* + * when 802.11w PMF is enabled for hw encr/decr + * use hw MFP Qos bits 0x10 + */ + param.param_id = WMI_PDEV_PARAM_PMF_QOS; + param.param_value = true; + ret = wmi_unified_pdev_param_send(wma->wmi_handle, + ¶m, WMA_WILDCARD_PDEV_ID); + if (QDF_IS_STATUS_ERROR(ret)) { + WMA_LOGE("%s: Failed to set QOS MFP/PMF (%d)", + __func__, ret); + } else { + WMA_LOGI("%s: QOS MFP/PMF set to %d", __func__, true); + } + } +#endif /* WLAN_FEATURE_11W */ + + req.beacon_intval = add_bss->beaconInterval; + req.dtim_period = add_bss->dtimPeriod; + req.hidden_ssid = add_bss->bHiddenSSIDEn; + req.is_dfs = add_bss->bSpectrumMgtEnabled; + req.oper_mode = BSS_OPERATIONAL_MODE_AP; + req.ssid.length = add_bss->ssId.length; + if (req.ssid.length > 0) + qdf_mem_copy(req.ssid.ssId, add_bss->ssId.ssId, + add_bss->ssId.length); + status = wma_get_current_hw_mode(&hw_mode); + if (!QDF_IS_STATUS_SUCCESS(status)) + WMA_LOGE("wma_get_current_hw_mode failed"); + + if (add_bss->nss == 2) { + req.preferred_rx_streams = 2; + req.preferred_tx_streams = 2; + } else { + req.preferred_rx_streams = 1; + req.preferred_tx_streams = 1; + } + + status = wma_vdev_start(wma, &req, false); + if (status != QDF_STATUS_SUCCESS) { + wma_remove_vdev_req(wma, vdev_id, + WMA_TARGET_REQ_TYPE_VDEV_START); + goto peer_cleanup; + } + + wma_vdev_set_bss_params(wma, vdev_id, + add_bss->beaconInterval, add_bss->dtimPeriod, + add_bss->shortSlotTimeSupported, + add_bss->llbCoexist, maxTxPower); + + return; + +peer_cleanup: + wma_remove_peer(wma, add_bss->bssId, vdev_id, peer, false); +send_fail_resp: + add_bss->status = QDF_STATUS_E_FAILURE; + wma_send_msg(wma, WMA_ADD_BSS_RSP, (void *)add_bss, 0); +} + +#ifdef QCA_IBSS_SUPPORT +/** + * wma_add_bss_ibss_mode() - process add bss request in IBSS mode + * @wma: wma handle + * @add_bss: add bss parameters + * + * Return: none + */ +static void wma_add_bss_ibss_mode(tp_wma_handle wma, tpAddBssParams add_bss) +{ + ol_txrx_pdev_handle pdev; + ol_txrx_vdev_handle vdev; + struct wma_vdev_start_req req; + ol_txrx_peer_handle peer = NULL; + struct wma_target_req *msg; + uint8_t vdev_id, peer_id; + QDF_STATUS status; + tSetBssKeyParams key_info; + struct sir_hw_mode_params hw_mode = {0}; + + vdev = wma_find_vdev_by_addr(wma, add_bss->selfMacAddr, &vdev_id); + if (!vdev) { + WMA_LOGE("%s: vdev not found for vdev id %d.", + __func__, vdev_id); + goto send_fail_resp; + } + WMA_LOGD("%s: add_bss->sessionId = %d", __func__, vdev_id); + pdev = cds_get_context(QDF_MODULE_ID_TXRX); + + if (NULL == pdev) { + WMA_LOGE("%s: Failed to get pdev", __func__); + goto send_fail_resp; + } + wma_set_bss_rate_flags(&wma->interfaces[vdev_id], add_bss); + + /* create ibss bss peer */ + status = wma_create_peer(wma, pdev, vdev, add_bss->selfMacAddr, + WMI_PEER_TYPE_DEFAULT, vdev_id, + false); + if (status != QDF_STATUS_SUCCESS) { + WMA_LOGE("%s: Failed to create peer", __func__); + goto send_fail_resp; + } + WMA_LOGA("IBSS BSS peer created with mac %pM", + add_bss->selfMacAddr); + + peer = ol_txrx_find_peer_by_addr(pdev, add_bss->selfMacAddr, &peer_id); + if (!peer) { + WMA_LOGE("%s Failed to find peer %pM", __func__, + add_bss->selfMacAddr); + goto send_fail_resp; + } + + /* clear leftover ibss keys on bss peer */ + + WMA_LOGD("%s: ibss bss key clearing", __func__); + qdf_mem_set(&key_info, sizeof(key_info), 0); + key_info.smesessionId = vdev_id; + key_info.numKeys = SIR_MAC_MAX_NUM_OF_DEFAULT_KEYS; + qdf_mem_copy(&wma->ibsskey_info, &key_info, sizeof(tSetBssKeyParams)); + + /* start ibss vdev */ + + add_bss->operMode = BSS_OPERATIONAL_MODE_IBSS; + + msg = wma_fill_vdev_req(wma, vdev_id, WMA_ADD_BSS_REQ, + WMA_TARGET_REQ_TYPE_VDEV_START, add_bss, + WMA_VDEV_START_REQUEST_TIMEOUT); + if (!msg) { + WMA_LOGP("%s Failed to allocate vdev request vdev_id %d", + __func__, vdev_id); + goto peer_cleanup; + } + WMA_LOGD("%s: vdev start request for IBSS enqueued", __func__); + + add_bss->staContext.staIdx = ol_txrx_local_peer_id(peer); + + /* + * If IBSS Power Save is supported by firmware + * set the IBSS power save params to firmware. + */ + if (WMI_SERVICE_IS_ENABLED(wma->wmi_service_bitmap, + WMI_SERVICE_IBSS_PWRSAVE)) { + status = wma_set_ibss_pwrsave_params(wma, vdev_id); + if (status != QDF_STATUS_SUCCESS) { + WMA_LOGE("%s: Failed to Set IBSS Power Save Params to firmware", + __func__); + goto peer_cleanup; + } + } + + qdf_mem_zero(&req, sizeof(req)); + req.vdev_id = vdev_id; + req.chan = add_bss->currentOperChannel; + req.chan_width = add_bss->ch_width; + req.ch_center_freq_seg0 = add_bss->ch_center_freq_seg0; + req.ch_center_freq_seg1 = add_bss->ch_center_freq_seg1; + req.vht_capable = add_bss->vhtCapable; +#if defined WLAN_FEATURE_VOWIF + req.max_txpow = add_bss->maxTxPower; +#else + req.max_txpow = 0; +#endif /* WLAN_FEATURE_VOWIF */ + req.beacon_intval = add_bss->beaconInterval; + req.dtim_period = add_bss->dtimPeriod; + req.hidden_ssid = add_bss->bHiddenSSIDEn; + req.is_dfs = add_bss->bSpectrumMgtEnabled; + req.oper_mode = BSS_OPERATIONAL_MODE_IBSS; + req.ssid.length = add_bss->ssId.length; + if (req.ssid.length > 0) + qdf_mem_copy(req.ssid.ssId, add_bss->ssId.ssId, + add_bss->ssId.length); + status = wma_get_current_hw_mode(&hw_mode); + if (!QDF_IS_STATUS_SUCCESS(status)) + WMA_LOGE("wma_get_current_hw_mode failed"); + + if (add_bss->nss == 2) { + req.preferred_rx_streams = 2; + req.preferred_tx_streams = 2; + } else { + req.preferred_rx_streams = 1; + req.preferred_tx_streams = 1; + } + + WMA_LOGD("%s: chan %d chan_width %d", __func__, req.chan, + req.chan_width); + WMA_LOGD("%s: ssid = %s", __func__, req.ssid.ssId); + + status = wma_vdev_start(wma, &req, false); + if (status != QDF_STATUS_SUCCESS) { + wma_remove_vdev_req(wma, vdev_id, + WMA_TARGET_REQ_TYPE_VDEV_START); + goto peer_cleanup; + } + WMA_LOGD("%s: vdev start request for IBSS sent to target", __func__); + + /* Initialize protection mode to no protection */ + status = wma_vdev_set_param(wma->wmi_handle, vdev_id, + WMI_VDEV_PARAM_PROTECTION_MODE, + IEEE80211_PROT_NONE); + if (QDF_IS_STATUS_ERROR(status)) + WMA_LOGE("Failed to initialize protection mode"); + + return; + +peer_cleanup: + if (peer) { + wma_remove_peer(wma, add_bss->bssId, vdev_id, peer, false); + } +send_fail_resp: + add_bss->status = QDF_STATUS_E_FAILURE; + wma_send_msg(wma, WMA_ADD_BSS_RSP, (void *)add_bss, 0); +} +#endif /* QCA_IBSS_SUPPORT */ + +/** + * wma_add_bss_sta_mode() - process add bss request in sta mode + * @wma: wma handle + * @add_bss: add bss parameters + * + * Return: none + */ +static void wma_add_bss_sta_mode(tp_wma_handle wma, tpAddBssParams add_bss) +{ + ol_txrx_pdev_handle pdev; + struct wma_vdev_start_req req; + struct wma_target_req *msg; + uint8_t peer_id; + ol_txrx_peer_handle peer = NULL; + QDF_STATUS status; + struct wma_txrx_node *iface; + int pps_val = 0; + bool roam_synch_in_progress = false; + tpAniSirGlobal pMac = cds_get_context(QDF_MODULE_ID_PE); + struct sir_hw_mode_params hw_mode = {0}; + bool peer_assoc_sent = false; + struct pdev_params param = {0}; + uint8_t vdev_id = add_bss->staContext.smesessionId; + + if (NULL == pMac) { + WMA_LOGE("%s: Unable to get PE context", __func__); + goto send_fail_resp; + } + + pdev = cds_get_context(QDF_MODULE_ID_TXRX); + + if (NULL == pdev) { + WMA_LOGE("%s Failed to get pdev", __func__); + goto send_fail_resp; + } + + iface = &wma->interfaces[vdev_id]; + + wma_set_bss_rate_flags(iface, add_bss); + if (add_bss->operMode) { + /* Save parameters later needed by WMA_ADD_STA_REQ */ + if (iface->addBssStaContext) { + qdf_mem_free(iface->addBssStaContext); + } + iface->addBssStaContext = qdf_mem_malloc(sizeof(tAddStaParams)); + if (!iface->addBssStaContext) { + WMA_LOGE("%s Failed to allocat memory", __func__); + goto send_fail_resp; + } + qdf_mem_copy(iface->addBssStaContext, &add_bss->staContext, + sizeof(tAddStaParams)); + + if (iface->staKeyParams) { + qdf_mem_free(iface->staKeyParams); + iface->staKeyParams = NULL; + } + if (add_bss->extSetStaKeyParamValid) { + iface->staKeyParams = + qdf_mem_malloc(sizeof(tSetStaKeyParams)); + if (!iface->staKeyParams) { + WMA_LOGE("%s Failed to allocat memory", + __func__); + goto send_fail_resp; + } + qdf_mem_copy(iface->staKeyParams, + &add_bss->extSetStaKeyParam, + sizeof(tSetStaKeyParams)); + } + /* Save parameters later needed by WMA_ADD_STA_REQ */ + iface->rmfEnabled = add_bss->rmfEnabled; + iface->beaconInterval = add_bss->beaconInterval; + iface->llbCoexist = add_bss->llbCoexist; + iface->shortSlotTimeSupported = add_bss->shortSlotTimeSupported; + iface->nwType = add_bss->nwType; + if (add_bss->nonRoamReassoc) { + peer = ol_txrx_find_peer_by_addr(pdev, add_bss->bssId, + &peer_id); + if (peer) { + add_bss->staContext.staIdx = + ol_txrx_local_peer_id(peer); + goto send_bss_resp; + } + } + if (add_bss->reassocReq) { +#if defined(QCA_LL_LEGACY_TX_FLOW_CONTROL) || defined(QCA_LL_TX_FLOW_CONTROL_V2) + ol_txrx_vdev_handle vdev; +#endif + /* Called in preassoc state. BSSID peer is already added by set_linkstate */ + peer = ol_txrx_find_peer_by_addr(pdev, add_bss->bssId, + &peer_id); + if (!peer) { + WMA_LOGE("%s Failed to find peer %pM", __func__, + add_bss->bssId); + goto send_fail_resp; + } + if (wma_is_roam_synch_in_progress(wma, vdev_id)) { + add_bss->staContext.staIdx = + ol_txrx_local_peer_id(peer); + WMA_LOGD("LFR3:%s: bssid %pM staIdx %d", + __func__, add_bss->bssId, + add_bss->staContext.staIdx); + return; + } + msg = wma_fill_vdev_req(wma, vdev_id, WMA_ADD_BSS_REQ, + WMA_TARGET_REQ_TYPE_VDEV_START, + add_bss, + WMA_VDEV_START_REQUEST_TIMEOUT); + if (!msg) { + WMA_LOGP("%s Failed to allocate vdev request vdev_id %d", + __func__, vdev_id); + goto peer_cleanup; + } + + add_bss->staContext.staIdx = + ol_txrx_local_peer_id(peer); + + qdf_mem_zero(&req, sizeof(req)); + req.vdev_id = vdev_id; + req.chan = add_bss->currentOperChannel; + req.chan_width = add_bss->ch_width; + + if (add_bss->ch_width == CH_WIDTH_10MHZ) + req.is_half_rate = 1; + else if (add_bss->ch_width == CH_WIDTH_5MHZ) + req.is_quarter_rate = 1; + + req.ch_center_freq_seg0 = add_bss->ch_center_freq_seg0; + req.ch_center_freq_seg1 = add_bss->ch_center_freq_seg1; + req.max_txpow = add_bss->maxTxPower; + req.beacon_intval = add_bss->beaconInterval; + req.dtim_period = add_bss->dtimPeriod; + req.hidden_ssid = add_bss->bHiddenSSIDEn; + req.is_dfs = add_bss->bSpectrumMgtEnabled; + req.ssid.length = add_bss->ssId.length; + req.oper_mode = BSS_OPERATIONAL_MODE_STA; + if (req.ssid.length > 0) + qdf_mem_copy(req.ssid.ssId, add_bss->ssId.ssId, + add_bss->ssId.length); + status = wma_get_current_hw_mode(&hw_mode); + if (!QDF_IS_STATUS_SUCCESS(status)) + WMA_LOGE("wma_get_current_hw_mode failed"); + + if (add_bss->nss == 2) { + req.preferred_rx_streams = 2; + req.preferred_tx_streams = 2; + } else { + req.preferred_rx_streams = 1; + req.preferred_tx_streams = 1; + } + + status = wma_vdev_start(wma, &req, false); + if (status != QDF_STATUS_SUCCESS) { + wma_remove_vdev_req(wma, vdev_id, + WMA_TARGET_REQ_TYPE_VDEV_START); + goto peer_cleanup; + } +#if defined(QCA_LL_LEGACY_TX_FLOW_CONTROL) || defined(QCA_LL_TX_FLOW_CONTROL_V2) + vdev = wma_find_vdev_by_id(wma, vdev_id); + if (!vdev) { + WMA_LOGE("%s Invalid txrx vdev", __func__); + goto peer_cleanup; + } + ol_txrx_vdev_pause(vdev, + OL_TXQ_PAUSE_REASON_PEER_UNAUTHORIZED); +#endif + /* ADD_BSS_RESP will be deferred to completion of VDEV_START */ + + return; + } + if (!add_bss->updateBss) { + goto send_bss_resp; + + } + /* Update peer state */ + if (add_bss->staContext.encryptType == eSIR_ED_NONE) { + WMA_LOGD("%s: Update peer(%pM) state into auth", + __func__, add_bss->bssId); + ol_txrx_peer_state_update(pdev, add_bss->bssId, + OL_TXRX_PEER_STATE_AUTH); + } else { +#if defined(QCA_LL_LEGACY_TX_FLOW_CONTROL) || defined(QCA_LL_TX_FLOW_CONTROL_V2) + ol_txrx_vdev_handle vdev; +#endif + WMA_LOGD("%s: Update peer(%pM) state into conn", + __func__, add_bss->bssId); + ol_txrx_peer_state_update(pdev, add_bss->bssId, + OL_TXRX_PEER_STATE_CONN); +#if defined(QCA_LL_LEGACY_TX_FLOW_CONTROL) || defined(QCA_LL_TX_FLOW_CONTROL_V2) + peer = ol_txrx_find_peer_by_addr(pdev, add_bss->bssId, + &peer_id); + if (!peer) { + WMA_LOGE("%s:%d Failed to find peer %pM", + __func__, __LINE__, add_bss->bssId); + goto send_fail_resp; + } + + vdev = wma_find_vdev_by_id(wma, vdev_id); + if (!vdev) { + WMA_LOGE("%s Invalid txrx vdev", __func__); + goto peer_cleanup; + } + ol_txrx_vdev_pause(vdev, + OL_TXQ_PAUSE_REASON_PEER_UNAUTHORIZED); +#endif + } + + wmi_unified_send_txbf(wma, &add_bss->staContext); + + pps_val = + ((pMac-> + enable5gEBT << 31) & 0xffff0000) | (PKT_PWR_SAVE_5G_EBT & + 0xffff); + status = wma_vdev_set_param(wma->wmi_handle, vdev_id, + WMI_VDEV_PARAM_PACKET_POWERSAVE, + pps_val); + if (QDF_IS_STATUS_ERROR(status)) + WMA_LOGE("Failed to send wmi packet power save cmd"); + else + WMA_LOGD("Sent PKT_PWR_SAVE_5G_EBT cmd to target, val = %x, status = %d", + pps_val, status); + wma_send_peer_assoc(wma, add_bss->nwType, + &add_bss->staContext); + peer_assoc_sent = true; +#ifdef WLAN_FEATURE_11W + if (add_bss->rmfEnabled) { + /* when 802.11w PMF is enabled for hw encr/decr + use hw MFP Qos bits 0x10 */ + param.param_id = WMI_PDEV_PARAM_PMF_QOS; + param.param_value = true; + status = wmi_unified_pdev_param_send(wma->wmi_handle, + ¶m, + WMA_WILDCARD_PDEV_ID); + if (QDF_IS_STATUS_ERROR(status)) { + WMA_LOGE("%s: Failed to set QOS MFP/PMF (%d)", + __func__, status); + } else { + WMA_LOGI("%s: QOS MFP/PMF set to %d", + __func__, true); + } + } +#endif /* WLAN_FEATURE_11W */ + + wma_vdev_set_bss_params(wma, add_bss->staContext.smesessionId, + add_bss->beaconInterval, + add_bss->dtimPeriod, + add_bss->shortSlotTimeSupported, + add_bss->llbCoexist, + add_bss->maxTxPower); + + /* + * Store the bssid in interface table, bssid will + * be used during group key setting sta mode. + */ + qdf_mem_copy(iface->bssid, add_bss->bssId, IEEE80211_ADDR_LEN); + + } +send_bss_resp: + ol_txrx_find_peer_by_addr(pdev, add_bss->bssId, + &add_bss->staContext.staIdx); + add_bss->status = (add_bss->staContext.staIdx < 0) ? + QDF_STATUS_E_FAILURE : QDF_STATUS_SUCCESS; + add_bss->bssIdx = add_bss->staContext.smesessionId; + qdf_mem_copy(add_bss->staContext.staMac, add_bss->bssId, + sizeof(add_bss->staContext.staMac)); + + if (!WMI_SERVICE_IS_ENABLED(wma->wmi_service_bitmap, + WMI_SERVICE_PEER_ASSOC_CONF)) { + WMA_LOGE(FL("WMI_SERVICE_PEER_ASSOC_CONF not enabled")); + goto send_final_rsp; + } + + /* In case of reassoc, peer assoc cmd will not be sent */ + if (!peer_assoc_sent) + goto send_final_rsp; + + msg = wma_fill_hold_req(wma, vdev_id, WMA_ADD_BSS_REQ, + WMA_PEER_ASSOC_CNF_START, add_bss, + WMA_PEER_ASSOC_TIMEOUT); + if (!msg) { + WMA_LOGP(FL("Failed to allocate request for vdev_id %d"), + vdev_id); + wma_remove_req(wma, vdev_id, WMA_PEER_ASSOC_CNF_START); + goto peer_cleanup; + } + return; + +send_final_rsp: + WMA_LOGD("%s: opermode %d update_bss %d nw_type %d bssid %pM" + " staIdx %d status %d", __func__, add_bss->operMode, + add_bss->updateBss, add_bss->nwType, add_bss->bssId, + add_bss->staContext.staIdx, add_bss->status); + wma_send_msg(wma, WMA_ADD_BSS_RSP, (void *)add_bss, 0); + return; + +peer_cleanup: + wma_remove_peer(wma, add_bss->bssId, vdev_id, peer, + roam_synch_in_progress); +send_fail_resp: + add_bss->status = QDF_STATUS_E_FAILURE; + if (!wma_is_roam_synch_in_progress(wma, vdev_id)) + wma_send_msg(wma, WMA_ADD_BSS_RSP, (void *)add_bss, 0); +} + +/** + * wma_add_bss() - Add BSS request to fw as per opmode + * @wma: wma handle + * @params: add bss params + * + * Return: none + */ +void wma_add_bss(tp_wma_handle wma, tpAddBssParams params) +{ + WMA_LOGD("%s: add_bss_param.halPersona = %d", + __func__, params->halPersona); + + switch (params->halPersona) { + + case QDF_SAP_MODE: + case QDF_P2P_GO_MODE: + /*If current bring up SAP/P2P channel matches the previous + *radar found channel then reset the last_radar_found_chan + *variable to avoid race conditions. + */ + if (params->currentOperChannel == + wma->dfs_ic->last_radar_found_chan) + wma->dfs_ic->last_radar_found_chan = 0; + + wma_add_bss_ap_mode(wma, params); + break; + +#ifdef QCA_IBSS_SUPPORT + case QDF_IBSS_MODE: + wma_add_bss_ibss_mode(wma, params); + break; +#endif + + case QDF_NDI_MODE: + wma_add_bss_ndi_mode(wma, params); + break; + + default: + wma_add_bss_sta_mode(wma, params); + break; + } +} + +/** + * wma_add_sta_req_ap_mode() - process add sta request in ap mode + * @wma: wma handle + * @add_sta: add sta params + * + * Return: none + */ +static void wma_add_sta_req_ap_mode(tp_wma_handle wma, tpAddStaParams add_sta) +{ + enum ol_txrx_peer_state state = OL_TXRX_PEER_STATE_CONN; + ol_txrx_pdev_handle pdev; + ol_txrx_vdev_handle vdev; + ol_txrx_peer_handle peer; + uint8_t peer_id; + QDF_STATUS status; + int32_t ret; + struct wma_txrx_node *iface = NULL; + struct wma_target_req *msg; + bool peer_assoc_cnf = false; + struct pdev_params param; + + pdev = cds_get_context(QDF_MODULE_ID_TXRX); + + if (NULL == pdev) { + WMA_LOGE("%s: Failed to find pdev", __func__); + add_sta->status = QDF_STATUS_E_FAILURE; + goto send_rsp; + } + /* UMAC sends WMA_ADD_STA_REQ msg twice to WMA when the station + * associates. First WMA_ADD_STA_REQ will have staType as + * STA_ENTRY_PEER and second posting will have STA_ENTRY_SELF. + * Peer creation is done in first WMA_ADD_STA_REQ and second + * WMA_ADD_STA_REQ which has STA_ENTRY_SELF is ignored and + * send fake response with success to UMAC. Otherwise UMAC + * will get blocked. + */ + if (add_sta->staType != STA_ENTRY_PEER) { + add_sta->status = QDF_STATUS_SUCCESS; + goto send_rsp; + } + + vdev = wma_find_vdev_by_id(wma, add_sta->smesessionId); + if (!vdev) { + WMA_LOGE("%s: Failed to find vdev", __func__); + add_sta->status = QDF_STATUS_E_FAILURE; + goto send_rsp; + } + + iface = &wma->interfaces[add_sta->smesessionId]; + peer = ol_txrx_find_peer_by_addr_and_vdev(pdev, + vdev, + add_sta->staMac, &peer_id); + if (peer) { + wma_remove_peer(wma, add_sta->staMac, add_sta->smesessionId, + peer, false); + WMA_LOGE("%s: Peer already exists, Deleted peer with peer_addr %pM", + __func__, add_sta->staMac); + } + /* The code above only checks the peer existence on its own vdev. + * Need to check whether the peer exists on other vDevs because firmware + * can't create the peer if the peer with same MAC address already + * exists on the pDev. As this peer belongs to other vDevs, just return + * here. + */ + peer = ol_txrx_find_peer_by_addr(pdev, add_sta->staMac, &peer_id); + if (peer) { + WMA_LOGE("%s: My vdev:%d, but Peer exists on other vdev with " + "peer_addr %pM and peer_id %d", + __func__, vdev->vdev_id, add_sta->staMac, peer_id); + add_sta->status = QDF_STATUS_E_FAILURE; + goto send_rsp; + } + + status = wma_create_peer(wma, pdev, vdev, add_sta->staMac, + WMI_PEER_TYPE_DEFAULT, add_sta->smesessionId, + false); + if (status != QDF_STATUS_SUCCESS) { + WMA_LOGE("%s: Failed to create peer for %pM", + __func__, add_sta->staMac); + add_sta->status = status; + goto send_rsp; + } + + peer = ol_txrx_find_peer_by_addr_and_vdev(pdev, + vdev, + add_sta->staMac, &peer_id); + if (!peer) { + WMA_LOGE("%s: Failed to find peer handle using peer mac %pM", + __func__, add_sta->staMac); + add_sta->status = QDF_STATUS_E_FAILURE; + wma_remove_peer(wma, add_sta->staMac, add_sta->smesessionId, + peer, false); + goto send_rsp; + } + + wmi_unified_send_txbf(wma, add_sta); + + if (WMI_SERVICE_IS_ENABLED(wma->wmi_service_bitmap, + WMI_SERVICE_PEER_ASSOC_CONF)) { + peer_assoc_cnf = true; + msg = wma_fill_hold_req(wma, add_sta->smesessionId, + WMA_ADD_STA_REQ, WMA_PEER_ASSOC_CNF_START, + add_sta, WMA_PEER_ASSOC_TIMEOUT); + if (!msg) { + WMA_LOGP(FL("Failed to alloc request for vdev_id %d"), + add_sta->smesessionId); + add_sta->status = QDF_STATUS_E_FAILURE; + wma_remove_req(wma, add_sta->smesessionId, + WMA_PEER_ASSOC_CNF_START); + wma_remove_peer(wma, add_sta->staMac, + add_sta->smesessionId, peer, false); + peer_assoc_cnf = false; + goto send_rsp; + } + } else { + WMA_LOGE(FL("WMI_SERVICE_PEER_ASSOC_CONF not enabled")); + } + + ret = wma_send_peer_assoc(wma, add_sta->nwType, add_sta); + if (ret) { + add_sta->status = QDF_STATUS_E_FAILURE; + wma_remove_peer(wma, add_sta->staMac, add_sta->smesessionId, + peer, false); + goto send_rsp; + } +#ifdef QCA_IBSS_SUPPORT + /* + * In IBSS mode send the peer + * Atim Window length if IBSS + * power save is enabled by the + * firmware. + */ + if (wma_is_vdev_in_ibss_mode(wma, add_sta->smesessionId) && + WMI_SERVICE_IS_ENABLED(wma->wmi_service_bitmap, + WMI_SERVICE_IBSS_PWRSAVE)) { + /* + * If ATIM Window is present in the peer + * beacon then send it to firmware else + * configure Zero ATIM Window length to + * firmware. + */ + if (add_sta->atimIePresent) { + wma_set_peer_param(wma, add_sta->staMac, + WMI_PEER_IBSS_ATIM_WINDOW_LENGTH, + add_sta->peerAtimWindowLength, + add_sta->smesessionId); + } else { + wma_set_peer_param(wma, add_sta->staMac, + WMI_PEER_IBSS_ATIM_WINDOW_LENGTH, + 0, add_sta->smesessionId); + } + } +#endif + +#ifdef WLAN_FEATURE_11W + if (add_sta->rmfEnabled) { + /* + * We have to store the state of PMF connection + * per STA for SAP case + * We will isolate the ifaces based on vdevid + */ + iface->rmfEnabled = add_sta->rmfEnabled; + /* + * when 802.11w PMF is enabled for hw encr/decr + * use hw MFP Qos bits 0x10 + */ + param.param_id = WMI_PDEV_PARAM_PMF_QOS; + param.param_value = true; + status = wmi_unified_pdev_param_send(wma->wmi_handle, + ¶m, WMA_WILDCARD_PDEV_ID); + if (QDF_IS_STATUS_ERROR(status)) { + WMA_LOGE("%s: Failed to set QOS MFP/PMF (%d)", + __func__, status); + } else { + WMA_LOGI("%s: QOS MFP/PMF set to %d", __func__, true); + } + } +#endif /* WLAN_FEATURE_11W */ + + if (add_sta->uAPSD) { + status = wma_set_ap_peer_uapsd(wma, add_sta->smesessionId, + add_sta->staMac, + add_sta->uAPSD, add_sta->maxSPLen); + if (QDF_IS_STATUS_ERROR(status)) { + WMA_LOGE("Failed to set peer uapsd param for %pM", + add_sta->staMac); + add_sta->status = QDF_STATUS_E_FAILURE; + wma_remove_peer(wma, add_sta->staMac, + add_sta->smesessionId, peer, false); + goto send_rsp; + } + } + + WMA_LOGD("%s: Moving peer %pM to state %d", + __func__, add_sta->staMac, state); + ol_txrx_peer_state_update(pdev, add_sta->staMac, state); + + add_sta->staIdx = ol_txrx_local_peer_id(peer); + add_sta->nss = iface->nss; + add_sta->status = QDF_STATUS_SUCCESS; +send_rsp: + /* Do not send add stat resp when peer assoc cnf is enabled */ + if (peer_assoc_cnf) { + WMA_LOGI(FL("WMI_SERVICE_PEER_ASSOC_CONF is enabled")); + return; + } + + WMA_LOGE(FL("statype %d vdev_id %d aid %d bssid %pM staIdx %d status %d"), + add_sta->staType, add_sta->smesessionId, + add_sta->assocId, add_sta->bssId, add_sta->staIdx, + add_sta->status); + wma_send_msg(wma, WMA_ADD_STA_RSP, (void *)add_sta, 0); +} + +#ifdef FEATURE_WLAN_TDLS + +/** + * wma_add_tdls_sta() - process add sta request in TDLS mode + * @wma: wma handle + * @add_sta: add sta params + * + * Return: none + */ +static void wma_add_tdls_sta(tp_wma_handle wma, tpAddStaParams add_sta) +{ + ol_txrx_pdev_handle pdev; + ol_txrx_vdev_handle vdev; + ol_txrx_peer_handle peer; + uint8_t peer_id; + QDF_STATUS status; + int32_t ret; + tTdlsPeerStateParams *peerStateParams; + struct wma_target_req *msg; + bool peer_assoc_cnf = false; + + WMA_LOGD("%s: staType: %d, staIdx: %d, updateSta: %d, " + "bssId: %pM, staMac: %pM", + __func__, add_sta->staType, add_sta->staIdx, + add_sta->updateSta, add_sta->bssId, add_sta->staMac); + + pdev = cds_get_context(QDF_MODULE_ID_TXRX); + + if (NULL == pdev) { + WMA_LOGE("%s: Failed to find pdev", __func__); + add_sta->status = QDF_STATUS_E_FAILURE; + goto send_rsp; + } + + vdev = wma_find_vdev_by_id(wma, add_sta->smesessionId); + if (!vdev) { + WMA_LOGE("%s: Failed to find vdev", __func__); + add_sta->status = QDF_STATUS_E_FAILURE; + goto send_rsp; + } + + if (0 == add_sta->updateSta) { + /* its a add sta request * */ + + ol_txrx_copy_mac_addr_raw(vdev, add_sta->bssId); + + WMA_LOGD("%s: addSta, calling wma_create_peer for %pM, vdev_id %hu", + __func__, add_sta->staMac, add_sta->smesessionId); + + status = wma_create_peer(wma, pdev, vdev, add_sta->staMac, + WMI_PEER_TYPE_TDLS, + add_sta->smesessionId, false); + if (status != QDF_STATUS_SUCCESS) { + WMA_LOGE("%s: Failed to create peer for %pM", + __func__, add_sta->staMac); + add_sta->status = status; + goto send_rsp; + } + + peer = ol_txrx_find_peer_by_addr(pdev, add_sta->staMac, &peer_id); + if (!peer) { + WMA_LOGE("%s: addSta, failed to find peer handle for mac %pM", + __func__, add_sta->staMac); + add_sta->status = QDF_STATUS_E_FAILURE; + wma_remove_peer(wma, add_sta->staMac, + add_sta->smesessionId, peer, false); + + ol_txrx_add_last_real_peer(pdev, vdev, &peer_id); + + goto send_rsp; + } + + add_sta->staIdx = ol_txrx_local_peer_id(peer); + WMA_LOGD("%s: addSta, after calling ol_txrx_local_peer_id, " + "staIdx: %d, staMac: %pM", + __func__, add_sta->staIdx, add_sta->staMac); + + peerStateParams = qdf_mem_malloc(sizeof(tTdlsPeerStateParams)); + if (!peerStateParams) { + WMA_LOGE + ("%s: Failed to allocate memory for peerStateParams for %pM", + __func__, add_sta->staMac); + add_sta->status = QDF_STATUS_E_NOMEM; + goto send_rsp; + } + + peerStateParams->peerState = WMI_TDLS_PEER_STATE_PEERING; + peerStateParams->vdevId = add_sta->smesessionId; + qdf_mem_copy(&peerStateParams->peerMacAddr, + &add_sta->staMac, sizeof(tSirMacAddr)); + wma_update_tdls_peer_state(wma, peerStateParams); + } else { + /* its a change sta request * */ + peer = + ol_txrx_find_peer_by_addr(pdev, add_sta->staMac, &peer_id); + if (!peer) { + WMA_LOGE("%s: changeSta,failed to find peer handle for mac %pM", + __func__, add_sta->staMac); + add_sta->status = QDF_STATUS_E_FAILURE; + wma_remove_peer(wma, add_sta->staMac, + add_sta->smesessionId, peer, false); + + ol_txrx_add_last_real_peer(pdev, vdev, &peer_id); + + goto send_rsp; + } + + if (WMI_SERVICE_IS_ENABLED(wma->wmi_service_bitmap, + WMI_SERVICE_PEER_ASSOC_CONF)) { + WMA_LOGE(FL("WMI_SERVICE_PEER_ASSOC_CONF is enabled")); + peer_assoc_cnf = true; + msg = wma_fill_hold_req(wma, add_sta->smesessionId, + WMA_ADD_STA_REQ, WMA_PEER_ASSOC_CNF_START, + add_sta, WMA_PEER_ASSOC_TIMEOUT); + if (!msg) { + WMA_LOGP(FL("Failed to alloc request for vdev_id %d"), + add_sta->smesessionId); + add_sta->status = QDF_STATUS_E_FAILURE; + wma_remove_req(wma, add_sta->smesessionId, + WMA_PEER_ASSOC_CNF_START); + wma_remove_peer(wma, add_sta->staMac, + add_sta->smesessionId, peer, false); + peer_assoc_cnf = false; + goto send_rsp; + } + } else { + WMA_LOGE(FL("WMI_SERVICE_PEER_ASSOC_CONF not enabled")); + } + + WMA_LOGD("%s: changeSta, calling wma_send_peer_assoc", + __func__); + + ret = + wma_send_peer_assoc(wma, add_sta->nwType, add_sta); + if (ret) { + add_sta->status = QDF_STATUS_E_FAILURE; + wma_remove_peer(wma, add_sta->staMac, + add_sta->smesessionId, peer, false); + ol_txrx_add_last_real_peer(pdev, vdev, &peer_id); + + goto send_rsp; + } + } + +send_rsp: + /* Do not send add stat resp when peer assoc cnf is enabled */ + if (peer_assoc_cnf) + return; + + WMA_LOGE(FL("statype %d vdev_id %d aid %d bssid %pM staIdx %d status %d"), + add_sta->staType, add_sta->smesessionId, + add_sta->assocId, add_sta->bssId, add_sta->staIdx, + add_sta->status); + wma_send_msg(wma, WMA_ADD_STA_RSP, (void *)add_sta, 0); +} +#endif + +/** + * wma_add_sta_req_sta_mode() - process add sta request in sta mode + * @wma: wma handle + * @add_sta: add sta params + * + * Return: none + */ +static void wma_add_sta_req_sta_mode(tp_wma_handle wma, tpAddStaParams params) +{ + ol_txrx_pdev_handle pdev; + QDF_STATUS status = QDF_STATUS_SUCCESS; + ol_txrx_peer_handle peer; + struct wma_txrx_node *iface; + int8_t maxTxPower; + int ret = 0; + struct wma_target_req *msg; + bool peer_assoc_cnf = false; + struct vdev_up_params param = {0}; + struct pdev_params pdev_param = {0}; + int smps_param; + +#ifdef FEATURE_WLAN_TDLS + if (STA_ENTRY_TDLS_PEER == params->staType) { + wma_add_tdls_sta(wma, params); + return; + } +#endif + + pdev = cds_get_context(QDF_MODULE_ID_TXRX); + + if (NULL == pdev) { + WMA_LOGE("%s: Unable to get pdev", __func__); + goto out; + } + + iface = &wma->interfaces[params->smesessionId]; + if (params->staType != STA_ENTRY_SELF) { + WMA_LOGP("%s: unsupported station type %d", + __func__, params->staType); + goto out; + } + peer = ol_txrx_find_peer_by_addr(pdev, params->bssId, ¶ms->staIdx); + if (peer == NULL) { + WMA_LOGE("%s: Peer is not present vdev id %d for %pM", __func__, + params->smesessionId, params->bssId); + status = QDF_STATUS_E_FAILURE; + goto out; + } + if (params->nonRoamReassoc) { + ol_txrx_peer_state_update(pdev, params->bssId, + OL_TXRX_PEER_STATE_AUTH); + qdf_atomic_set(&iface->bss_status, WMA_BSS_STATUS_STARTED); + iface->aid = params->assocId; + goto out; + } + + if (wma->interfaces[params->smesessionId].vdev_up == true) { + WMA_LOGE("%s: vdev id %d is already UP for %pM", __func__, + params->smesessionId, params->bssId); + status = QDF_STATUS_E_FAILURE; + goto out; + } + + if (peer != NULL && + (ol_txrx_get_peer_state(peer) == OL_TXRX_PEER_STATE_DISC)) { + /* + * This is the case for reassociation. + * peer state update and peer_assoc is required since it + * was not done by WMA_ADD_BSS_REQ. + */ + + /* Update peer state */ + if (params->encryptType == eSIR_ED_NONE) { + WMA_LOGD("%s: Update peer(%pM) state into auth", + __func__, params->bssId); + ol_txrx_peer_state_update(pdev, params->bssId, + OL_TXRX_PEER_STATE_AUTH); + } else { + WMA_LOGD("%s: Update peer(%pM) state into conn", + __func__, params->bssId); + ol_txrx_peer_state_update(pdev, params->bssId, + OL_TXRX_PEER_STATE_CONN); + } + + if (wma_is_roam_synch_in_progress(wma, params->smesessionId)) { + /* iface->nss = params->nss; */ + /*In LFR2.0, the following operations are performed as + * part of wma_send_peer_assoc. As we are + * skipping this operation, we are just executing the + * following which are useful for LFR3.0.*/ + ol_txrx_peer_state_update(pdev, params->bssId, + OL_TXRX_PEER_STATE_AUTH); + qdf_atomic_set(&iface->bss_status, + WMA_BSS_STATUS_STARTED); + iface->aid = params->assocId; + WMA_LOGE("LFR3:statype %d vdev %d aid %d bssid %pM", + params->staType, params->smesessionId, + params->assocId, params->bssId); + return; + } + wmi_unified_send_txbf(wma, params); + + if (WMI_SERVICE_IS_ENABLED(wma->wmi_service_bitmap, + WMI_SERVICE_PEER_ASSOC_CONF)) { + WMA_LOGE(FL("WMI_SERVICE_PEER_ASSOC_CONF is enabled")); + peer_assoc_cnf = true; + msg = wma_fill_hold_req(wma, params->smesessionId, + WMA_ADD_STA_REQ, WMA_PEER_ASSOC_CNF_START, + params, WMA_PEER_ASSOC_TIMEOUT); + if (!msg) { + WMA_LOGP(FL("Failed to alloc request for vdev_id %d"), + params->smesessionId); + params->status = QDF_STATUS_E_FAILURE; + wma_remove_req(wma, params->smesessionId, + WMA_PEER_ASSOC_CNF_START); + wma_remove_peer(wma, params->staMac, + params->smesessionId, peer, false); + peer_assoc_cnf = false; + goto out; + } + } else { + WMA_LOGE(FL("WMI_SERVICE_PEER_ASSOC_CONF not enabled")); + } + + ret = wma_send_peer_assoc(wma, + iface->nwType, + (tAddStaParams *) iface->addBssStaContext); + if (ret) { + status = QDF_STATUS_E_FAILURE; + wma_remove_peer(wma, params->bssId, + params->smesessionId, peer, false); + goto out; + } +#ifdef WLAN_FEATURE_11W + if (params->rmfEnabled) { + /* when 802.11w PMF is enabled for hw encr/decr + use hw MFP Qos bits 0x10 */ + pdev_param.param_id = WMI_PDEV_PARAM_PMF_QOS; + pdev_param.param_value = true; + status = wmi_unified_pdev_param_send(wma->wmi_handle, + &pdev_param, + WMA_WILDCARD_PDEV_ID); + if (QDF_IS_STATUS_ERROR(status)) { + WMA_LOGE("%s: Failed to set QOS MFP/PMF (%d)", + __func__, status); + } else { + WMA_LOGI("%s: QOS MFP/PMF set to %d", + __func__, true); + } + } +#endif /* WLAN_FEATURE_11W */ + /* + * Set the PTK in 11r mode because we already have it. + */ + if (iface->staKeyParams) { + wma_set_stakey(wma, + (tpSetStaKeyParams) iface->staKeyParams); + } + } + maxTxPower = params->maxTxPower; + wma_vdev_set_bss_params(wma, params->smesessionId, + iface->beaconInterval, iface->dtimPeriod, + iface->shortSlotTimeSupported, + iface->llbCoexist, maxTxPower); + + params->csaOffloadEnable = 0; + if (WMI_SERVICE_IS_ENABLED(wma->wmi_service_bitmap, + WMI_SERVICE_CSA_OFFLOAD)) { + params->csaOffloadEnable = 1; + if (wma_unified_csa_offload_enable(wma, params->smesessionId) < + 0) { + WMA_LOGE("Unable to enable CSA offload for vdev_id:%d", + params->smesessionId); + } + } + + if (WMI_SERVICE_IS_ENABLED(wma->wmi_service_bitmap, + WMI_SERVICE_FILTER_IPSEC_NATKEEPALIVE)) { + if (wmi_unified_nat_keepalive_enable(wma, params->smesessionId) + < 0) { + WMA_LOGE("Unable to enable NAT keepalive for vdev_id:%d", + params->smesessionId); + } + } + + param.vdev_id = params->smesessionId; + param.assoc_id = params->assocId; + if (wmi_unified_vdev_up_send(wma->wmi_handle, params->bssId, + ¶m) != QDF_STATUS_SUCCESS) { + WMA_LOGP("%s: Failed to send vdev up cmd: vdev %d bssid %pM", + __func__, params->smesessionId, params->bssId); + cds_set_do_hw_mode_change_flag(false); + status = QDF_STATUS_E_FAILURE; + } else { + wma->interfaces[params->smesessionId].vdev_up = true; + wma_set_vdev_mgmt_rate(wma, params->smesessionId); + } + + qdf_atomic_set(&iface->bss_status, WMA_BSS_STATUS_STARTED); + WMA_LOGD("%s: STA mode (type %d subtype %d) BSS is started", + __func__, iface->type, iface->sub_type); + /* Sta is now associated, configure various params */ + + /* Send SMPS force command to FW to send the required + * action frame only when SM power save is enbaled in + * from INI. In case dynamic antenna selection, the + * action frames are sent by the chain mask manager + * In addition to the action frames, The SM power save is + * published in the assoc request HT SMPS IE for both cases. + */ + if ((params->enableHtSmps) && (params->send_smps_action)) { + smps_param = wma_smps_mode_to_force_mode_param( + params->htSmpsconfig); + if (smps_param >= 0) { + WMA_LOGD("%s: Send SMPS force mode: %d", + __func__, params->htSmpsconfig); + wma_set_mimops(wma, params->smesessionId, + smps_param); + } + } + + /* Partial AID match power save, enable when SU bformee */ + if (params->enableVhtpAid && params->vhtTxBFCapable) + wma_set_ppsconfig(params->smesessionId, + WMA_VHT_PPS_PAID_MATCH, 1); + + /* Enable AMPDU power save, if htCapable/vhtCapable */ + if (params->enableAmpduPs && (params->htCapable || params->vhtCapable)) + wma_set_ppsconfig(params->smesessionId, + WMA_VHT_PPS_DELIM_CRC_FAIL, 1); + iface->aid = params->assocId; + params->nss = iface->nss; +out: + /* Do not send add stat resp when peer assoc cnf is enabled */ + if (peer_assoc_cnf) + return; + + params->status = status; + WMA_LOGE(FL("statype %d vdev_id %d aid %d bssid %pM staIdx %d status %d"), + params->staType, params->smesessionId, + params->assocId, params->bssId, params->staIdx, + params->status); + /* Don't send a response during roam sync operation */ + if (!wma_is_roam_synch_in_progress(wma, params->smesessionId)) + wma_send_msg(wma, WMA_ADD_STA_RSP, (void *)params, 0); +} + +/** + * wma_delete_sta_req_ap_mode() - proces delete sta request from UMAC in AP mode + * @wma: wma handle + * @del_sta: delete sta params + * + * Return: none + */ +static void wma_delete_sta_req_ap_mode(tp_wma_handle wma, + tpDeleteStaParams del_sta) +{ + ol_txrx_pdev_handle pdev; + ol_txrx_peer_handle peer; + struct wma_target_req *msg; + uint8_t *peer_mac_addr; + + pdev = cds_get_context(QDF_MODULE_ID_TXRX); + + if (NULL == pdev) { + WMA_LOGE("%s: Failed to get pdev", __func__); + del_sta->status = QDF_STATUS_E_FAILURE; + goto send_del_rsp; + } + + peer = ol_txrx_peer_find_by_local_id(pdev, del_sta->staIdx); + if (!peer) { + WMA_LOGE("%s: Failed to get peer handle using peer id %d", + __func__, del_sta->staIdx); + del_sta->status = QDF_STATUS_E_FAILURE; + goto send_del_rsp; + } + peer_mac_addr = ol_txrx_peer_get_peer_mac_addr(peer); + + wma_remove_peer(wma, peer_mac_addr, del_sta->smesessionId, peer, + false); + del_sta->status = QDF_STATUS_SUCCESS; + + if (WMI_SERVICE_IS_ENABLED(wma->wmi_service_bitmap, + WMI_SERVICE_SYNC_DELETE_CMDS)) { + msg = wma_fill_hold_req(wma, del_sta->smesessionId, + WMA_DELETE_STA_REQ, + WMA_DELETE_STA_RSP_START, del_sta, + WMA_DELETE_STA_TIMEOUT); + if (!msg) { + WMA_LOGP(FL("Failed to allocate request. vdev_id %d"), + del_sta->smesessionId); + wma_remove_req(wma, del_sta->smesessionId, + WMA_DELETE_STA_RSP_START); + del_sta->status = QDF_STATUS_E_NOMEM; + goto send_del_rsp; + } + /* + * Acquire wake lock and bus lock till + * firmware sends the response + */ + cds_host_diag_log_work(&wma->wmi_cmd_rsp_wake_lock, + WMA_FW_RSP_EVENT_WAKE_LOCK_DURATION, + WIFI_POWER_EVENT_WAKELOCK_WMI_CMD_RSP); + qdf_wake_lock_timeout_acquire(&wma->wmi_cmd_rsp_wake_lock, + WMA_FW_RSP_EVENT_WAKE_LOCK_DURATION); + qdf_runtime_pm_prevent_suspend(&wma->wmi_cmd_rsp_runtime_lock); + return; + } + +send_del_rsp: + if (del_sta->respReqd) { + WMA_LOGD("%s: Sending del rsp to umac (status: %d)", + __func__, del_sta->status); + wma_send_msg(wma, WMA_DELETE_STA_RSP, (void *)del_sta, 0); + } +} + +#ifdef FEATURE_WLAN_TDLS +/** + * wma_del_tdls_sta() - proces delete sta request from UMAC in TDLS + * @wma: wma handle + * @del_sta: delete sta params + * + * Return: none + */ +static void wma_del_tdls_sta(tp_wma_handle wma, tpDeleteStaParams del_sta) +{ + tTdlsPeerStateParams *peerStateParams; + struct wma_target_req *msg; + int status; + + peerStateParams = qdf_mem_malloc(sizeof(tTdlsPeerStateParams)); + if (!peerStateParams) { + WMA_LOGE("%s: Failed to allocate memory for peerStateParams for: %pM", + __func__, del_sta->staMac); + del_sta->status = QDF_STATUS_E_NOMEM; + goto send_del_rsp; + } + + peerStateParams->peerState = WMA_TDLS_PEER_STATE_TEARDOWN; + peerStateParams->vdevId = del_sta->smesessionId; + peerStateParams->resp_reqd = del_sta->respReqd; + qdf_mem_copy(&peerStateParams->peerMacAddr, + &del_sta->staMac, sizeof(tSirMacAddr)); + + WMA_LOGD("%s: sending tdls_peer_state for peer mac: %pM, " + " peerState: %d", + __func__, peerStateParams->peerMacAddr, + peerStateParams->peerState); + + status = wma_update_tdls_peer_state(wma, peerStateParams); + + if (status < 0) { + WMA_LOGE("%s: wma_update_tdls_peer_state returned failure", + __func__); + goto send_del_rsp; + } + + if (del_sta->respReqd && + WMI_SERVICE_IS_ENABLED(wma->wmi_service_bitmap, + WMI_SERVICE_SYNC_DELETE_CMDS)) { + del_sta->status = QDF_STATUS_SUCCESS; + msg = wma_fill_hold_req(wma, + del_sta->smesessionId, + WMA_DELETE_STA_REQ, + WMA_DELETE_STA_RSP_START, del_sta, + WMA_DELETE_STA_TIMEOUT); + if (!msg) { + WMA_LOGP(FL("Failed to allocate vdev_id %d"), + peerStateParams->vdevId); + wma_remove_req(wma, + peerStateParams->vdevId, + WMA_DELETE_STA_RSP_START); + del_sta->status = QDF_STATUS_E_NOMEM; + goto send_del_rsp; + } + /* + * Acquire wake lock and bus lock till + * firmware sends the response + */ + cds_host_diag_log_work(&wma-> + wmi_cmd_rsp_wake_lock, + WMA_FW_RSP_EVENT_WAKE_LOCK_DURATION, + WIFI_POWER_EVENT_WAKELOCK_WMI_CMD_RSP); + qdf_wake_lock_timeout_acquire(&wma-> + wmi_cmd_rsp_wake_lock, + WMA_FW_RSP_EVENT_WAKE_LOCK_DURATION); + qdf_runtime_pm_prevent_suspend(&wma-> + wmi_cmd_rsp_runtime_lock); + } + + return; + +send_del_rsp: + if (del_sta->respReqd) { + WMA_LOGD("%s: Sending del rsp to umac (status: %d)", + __func__, del_sta->status); + wma_send_msg(wma, WMA_DELETE_STA_RSP, (void *)del_sta, 0); + } +} +#endif + +/** + * wma_delete_sta_req_sta_mode() - proces delete sta request from UMAC + * @wma: wma handle + * @params: delete sta params + * + * Return: none + */ +static void wma_delete_sta_req_sta_mode(tp_wma_handle wma, + tpDeleteStaParams params) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct wma_txrx_node *iface; + iface = &wma->interfaces[params->smesessionId]; + iface->uapsd_cached_val = 0; + + if (wma_is_roam_synch_in_progress(wma, params->smesessionId)) + return; +#ifdef FEATURE_WLAN_TDLS + if (STA_ENTRY_TDLS_PEER == params->staType) { + wma_del_tdls_sta(wma, params); + return; + } +#endif + params->status = status; + if (params->respReqd) { + WMA_LOGD("%s: vdev_id %d status %d", __func__, + params->smesessionId, status); + wma_send_msg(wma, WMA_DELETE_STA_RSP, (void *)params, 0); + } +} + +/** + * wma_add_sta() - process add sta request as per opmode + * @wma: wma handle + * @add_Sta: add sta params + * + * Return: none + */ +void wma_add_sta(tp_wma_handle wma, tpAddStaParams add_sta) +{ + uint8_t oper_mode = BSS_OPERATIONAL_MODE_STA; + + WMA_LOGD("%s: add_sta->sessionId = %d.", __func__, + add_sta->smesessionId); + WMA_LOGD("%s: add_sta->bssId = %x:%x:%x:%x:%x:%x", __func__, + add_sta->bssId[0], add_sta->bssId[1], add_sta->bssId[2], + add_sta->bssId[3], add_sta->bssId[4], add_sta->bssId[5]); + + if (wma_is_vdev_in_ap_mode(wma, add_sta->smesessionId)) + oper_mode = BSS_OPERATIONAL_MODE_AP; + else if (wma_is_vdev_in_ibss_mode(wma, add_sta->smesessionId)) + oper_mode = BSS_OPERATIONAL_MODE_IBSS; + + if (WMA_IS_VDEV_IN_NDI_MODE(wma->interfaces, add_sta->smesessionId)) + oper_mode = BSS_OPERATIONAL_MODE_NDI; + switch (oper_mode) { + case BSS_OPERATIONAL_MODE_STA: + wma_add_sta_req_sta_mode(wma, add_sta); + break; + + /* IBSS should share the same code as AP mode */ + case BSS_OPERATIONAL_MODE_IBSS: + case BSS_OPERATIONAL_MODE_AP: + htc_vote_link_up(wma->htc_handle); + wma_add_sta_req_ap_mode(wma, add_sta); + break; + case BSS_OPERATIONAL_MODE_NDI: + wma_add_sta_ndi_mode(wma, add_sta); + break; + } + +#ifdef QCA_IBSS_SUPPORT + /* adjust heart beat thresold timer value for detecting ibss peer departure */ + if (oper_mode == BSS_OPERATIONAL_MODE_IBSS) + wma_adjust_ibss_heart_beat_timer(wma, add_sta->smesessionId, 1); +#endif + +} + +/** + * wma_delete_sta() - process del sta request as per opmode + * @wma: wma handle + * @del_sta: delete sta params + * + * Return: none + */ +void wma_delete_sta(tp_wma_handle wma, tpDeleteStaParams del_sta) +{ + uint8_t oper_mode = BSS_OPERATIONAL_MODE_STA; + uint8_t smesession_id = del_sta->smesessionId; + bool rsp_requested = del_sta->respReqd; + + if (wma_is_vdev_in_ap_mode(wma, smesession_id)) + oper_mode = BSS_OPERATIONAL_MODE_AP; + if (wma_is_vdev_in_ibss_mode(wma, smesession_id)) { + oper_mode = BSS_OPERATIONAL_MODE_IBSS; + WMA_LOGD("%s: to delete sta for IBSS mode", __func__); + } + if (del_sta->staType == STA_ENTRY_NDI_PEER) + oper_mode = BSS_OPERATIONAL_MODE_NDI; + + WMA_LOGD(FL("oper_mode %d"), oper_mode); + + switch (oper_mode) { + case BSS_OPERATIONAL_MODE_STA: + wma_delete_sta_req_sta_mode(wma, del_sta); + if (wma_is_roam_synch_in_progress(wma, smesession_id)) + return; + if (!rsp_requested) { + WMA_LOGD(FL("vdev_id %d status %d"), + del_sta->smesessionId, del_sta->status); + qdf_mem_free(del_sta); + } + break; + + case BSS_OPERATIONAL_MODE_IBSS: /* IBSS shares AP code */ + case BSS_OPERATIONAL_MODE_AP: + htc_vote_link_down(wma->htc_handle); + wma_delete_sta_req_ap_mode(wma, del_sta); + /* free the memory here only if sync feature is not enabled */ + if (!rsp_requested && + !WMI_SERVICE_IS_ENABLED(wma->wmi_service_bitmap, + WMI_SERVICE_SYNC_DELETE_CMDS)) { + WMA_LOGD(FL("vdev_id %d status %d"), + del_sta->smesessionId, del_sta->status); + qdf_mem_free(del_sta); + } + break; + case BSS_OPERATIONAL_MODE_NDI: + wma_delete_sta_req_ndi_mode(wma, del_sta); + break; + } + +#ifdef QCA_IBSS_SUPPORT + /* adjust heart beat thresold timer value for + * detecting ibss peer departure + */ + if (oper_mode == BSS_OPERATIONAL_MODE_IBSS) + wma_adjust_ibss_heart_beat_timer(wma, smesession_id, -1); +#endif +} + +/** + * wma_delete_bss_ho_fail() - process delete bss request for handoff failure + * @wma: wma handle + * @params: del bss parameters + * + * Delete BSS in case of ROAM_HO_FAIL processing is handled separately in + * this routine. It needs to be done without sending any commands to firmware + * because firmware has already stopped and deleted peer and vdev is down. + * Relevent logic is aggregated from other routines. It changes the host + * data structures without sending VDEV_STOP, PEER_FLUSH_TIDS, PEER_DELETE + * and VDEV_DOWN commands to firmware. + * + * Return: none + */ +void wma_delete_bss_ho_fail(tp_wma_handle wma, tpDeleteBssParams params) +{ + ol_txrx_pdev_handle pdev; + ol_txrx_peer_handle peer = NULL; + QDF_STATUS status = QDF_STATUS_SUCCESS; + uint8_t peer_id; + ol_txrx_vdev_handle txrx_vdev = NULL; + struct wma_txrx_node *iface; + + pdev = cds_get_context(QDF_MODULE_ID_TXRX); + + if (NULL == pdev) { + WMA_LOGE("%s:Unable to get TXRX context", __func__); + goto fail_del_bss_ho_fail; + } + peer = ol_txrx_find_peer_by_addr(pdev, params->bssid, &peer_id); + + if (!peer) { + WMA_LOGP("%s: Failed to find peer %pM", __func__, + params->bssid); + status = QDF_STATUS_E_FAILURE; + goto fail_del_bss_ho_fail; + } + + iface = &wma->interfaces[params->smesessionId]; + if (!iface || !iface->handle) { + WMA_LOGE("%s vdev id %d is already deleted", + __func__, params->smesessionId); + goto fail_del_bss_ho_fail; + } + qdf_mem_zero(iface->bssid, IEEE80211_ADDR_LEN); + + txrx_vdev = wma_find_vdev_by_id(wma, params->smesessionId); + if (!txrx_vdev) { + WMA_LOGE("%s:Invalid vdev handle", __func__); + status = QDF_STATUS_E_FAILURE; + goto fail_del_bss_ho_fail; + } + + /* Free the allocated stats response buffer for the the session */ + if (iface->stats_rsp) { + qdf_mem_free(iface->stats_rsp); + iface->stats_rsp = NULL; + } + + if (iface->psnr_req) { + qdf_mem_free(iface->psnr_req); + iface->psnr_req = NULL; + } + + if (iface->rcpi_req) { + struct sme_rcpi_req *rcpi_req = iface->rcpi_req; + + iface->rcpi_req = NULL; + qdf_mem_free(rcpi_req); + } + + qdf_mem_zero(&iface->ns_offload_req, + sizeof(iface->ns_offload_req)); + qdf_mem_zero(&iface->arp_offload_req, + sizeof(iface->arp_offload_req)); + + WMA_LOGD("%s, vdev_id: %d, pausing tx_ll_queue for VDEV_STOP (del_bss)", + __func__, params->smesessionId); + ol_txrx_vdev_pause(iface->handle, + OL_TXQ_PAUSE_REASON_VDEV_STOP); + iface->pause_bitmap |= (1 << PAUSE_TYPE_HOST); + + ol_txrx_vdev_flush(iface->handle); + WMA_LOGD("%s, vdev_id: %d, un-pausing tx_ll_queue for VDEV_STOP rsp", + __func__, params->smesessionId); + ol_txrx_vdev_unpause(iface->handle, + OL_TXQ_PAUSE_REASON_VDEV_STOP); + iface->pause_bitmap &= ~(1 << PAUSE_TYPE_HOST); + qdf_atomic_set(&iface->bss_status, WMA_BSS_STATUS_STOPPED); + WMA_LOGD("%s: (type %d subtype %d) BSS is stopped", + __func__, iface->type, iface->sub_type); + iface->vdev_up = false; + params->status = QDF_STATUS_SUCCESS; + if (!iface->peer_count) { + WMA_LOGE("%s: Can't remove peer with peer_addr %pM vdevid %d peer_count %d", + __func__, params->bssid, params->smesessionId, + iface->peer_count); + goto fail_del_bss_ho_fail; + } + + if (peer) + ol_txrx_peer_detach(peer); + iface->peer_count--; + WMA_LOGE("%s: Removed peer %p with peer_addr %pM vdevid %d peer_count %d", + __func__, peer, params->bssid, params->smesessionId, + iface->peer_count); +fail_del_bss_ho_fail: + params->status = status; + wma_send_msg(wma, WMA_DELETE_BSS_HO_FAIL_RSP, (void *)params, 0); +} + +/** + * wma_delete_bss() - process delete bss request from upper layer + * @wma: wma handle + * @params: del bss parameters + * + * Return: none + */ +void wma_delete_bss(tp_wma_handle wma, tpDeleteBssParams params) +{ + ol_txrx_pdev_handle pdev; + ol_txrx_peer_handle peer = NULL; + struct wma_target_req *msg; + QDF_STATUS status = QDF_STATUS_SUCCESS; + uint8_t peer_id; + uint8_t max_wait_iterations = 0; + ol_txrx_vdev_handle txrx_vdev = NULL; + bool roam_synch_in_progress = false; + struct wma_txrx_node *iface; + + pdev = cds_get_context(QDF_MODULE_ID_TXRX); + + if (NULL == pdev) { + WMA_LOGE("%s:Unable to get TXRX context", __func__); + goto out; + } + if (wma_is_vdev_in_ibss_mode(wma, params->smesessionId)) + /* in rome ibss case, self mac is used to create the bss peer */ + peer = ol_txrx_find_peer_by_addr(pdev, + wma->interfaces[params->smesessionId].addr, + &peer_id); + else if (WMA_IS_VDEV_IN_NDI_MODE(wma->interfaces, + params->smesessionId)) + /* In ndi case, self mac is used to create the self peer */ + peer = ol_txrx_find_peer_by_addr(pdev, + wma->interfaces[params->smesessionId].addr, + &peer_id); + else + peer = ol_txrx_find_peer_by_addr(pdev, params->bssid, &peer_id); + + if (!peer) { + WMA_LOGP("%s: Failed to find peer %pM", __func__, + params->bssid); + status = QDF_STATUS_E_FAILURE; + goto out; + } + + qdf_mem_zero(wma->interfaces[params->smesessionId].bssid, + IEEE80211_ADDR_LEN); + + txrx_vdev = wma_find_vdev_by_id(wma, params->smesessionId); + if (!txrx_vdev) { + WMA_LOGE("%s:Invalid vdev handle", __func__); + status = QDF_STATUS_E_FAILURE; + goto out; + } + + iface = &wma->interfaces[params->smesessionId]; + if (!iface || !iface->handle) { + WMA_LOGE("%s vdev id %d is already deleted", + __func__, params->smesessionId); + goto out; + } + /*Free the allocated stats response buffer for the the session */ + if (iface->stats_rsp) { + qdf_mem_free(iface->stats_rsp); + iface->stats_rsp = NULL; + } + + if (iface->psnr_req) { + qdf_mem_free(iface->psnr_req); + iface->psnr_req = NULL; + } + + if (iface->rcpi_req) { + struct sme_rcpi_req *rcpi_req = iface->rcpi_req; + + iface->rcpi_req = NULL; + qdf_mem_free(rcpi_req); + } + + if (wlan_op_mode_ibss == ol_txrx_get_opmode(txrx_vdev)) + wma->ibss_started = 0; + + if (wma_is_roam_synch_in_progress(wma, params->smesessionId)) { + roam_synch_in_progress = true; + WMA_LOGD("LFR3:%s: Setting vdev_up to FALSE for session %d", + __func__, params->smesessionId); + iface->vdev_up = false; + goto detach_peer; + } + msg = wma_fill_vdev_req(wma, params->smesessionId, WMA_DELETE_BSS_REQ, + WMA_TARGET_REQ_TYPE_VDEV_STOP, params, + WMA_VDEV_STOP_REQUEST_TIMEOUT); + if (!msg) { + WMA_LOGP("%s: Failed to fill vdev request for vdev_id %d", + __func__, params->smesessionId); + status = QDF_STATUS_E_NOMEM; + goto detach_peer; + } + + WMA_LOGW(FL("Outstanding msdu packets: %d"), + ol_txrx_get_tx_pending(pdev)); + + max_wait_iterations = + wma->interfaces[params->smesessionId].delay_before_vdev_stop / + WMA_TX_Q_RECHECK_TIMER_WAIT; + + while (ol_txrx_get_tx_pending(pdev) && max_wait_iterations) { + WMA_LOGW(FL("Waiting for outstanding packet to drain.")); + qdf_wait_single_event(&wma->tx_queue_empty_event, + WMA_TX_Q_RECHECK_TIMER_MAX_WAIT); + max_wait_iterations--; + } + + if (ol_txrx_get_tx_pending(pdev)) { + WMA_LOGW(FL("Outstanding msdu packets before VDEV_STOP : %d"), + ol_txrx_get_tx_pending(pdev)); + } + + WMA_LOGD("%s, vdev_id: %d, pausing tx_ll_queue for VDEV_STOP (del_bss)", + __func__, params->smesessionId); + ol_txrx_vdev_pause(iface->handle, + OL_TXQ_PAUSE_REASON_VDEV_STOP); + iface->pause_bitmap |= (1 << PAUSE_TYPE_HOST); + + if (wma_send_vdev_stop_to_fw(wma, params->smesessionId)) { + WMA_LOGP("%s: %d Failed to send vdev stop", __func__, __LINE__); + wma_remove_vdev_req(wma, params->smesessionId, + WMA_TARGET_REQ_TYPE_VDEV_STOP); + status = QDF_STATUS_E_FAILURE; + goto detach_peer; + } + WMA_LOGD("%s: bssid %pM vdev_id %d", + __func__, params->bssid, params->smesessionId); + return; +detach_peer: + wma_remove_peer(wma, params->bssid, params->smesessionId, peer, + roam_synch_in_progress); + if (wma_is_roam_synch_in_progress(wma, params->smesessionId)) + return; + +out: + params->status = status; + wma_send_msg(wma, WMA_DELETE_BSS_RSP, (void *)params, 0); +} + +/** + * wma_find_ibss_vdev() - This function finds vdev_id based on input type + * @wma: wma handle + * @type: vdev type + * + * Return: vdev id + */ +int32_t wma_find_vdev_by_type(tp_wma_handle wma, int32_t type) +{ + int32_t vdev_id = 0; + struct wma_txrx_node *intf = wma->interfaces; + + for (vdev_id = 0; vdev_id < wma->max_bssid; vdev_id++) { + if (NULL != intf) { + if (intf[vdev_id].type == type) + return vdev_id; + } + } + + return -EFAULT; +} + +/** + * wma_set_vdev_intrabss_fwd() - set intra_fwd value to wni_in. + * @wma_handle: wma handle + * @pdis_intra_fwd: Pointer to DisableIntraBssFwd struct + * + * Return: none + */ +void wma_set_vdev_intrabss_fwd(tp_wma_handle wma_handle, + tpDisableIntraBssFwd pdis_intra_fwd) +{ + ol_txrx_vdev_handle txrx_vdev; + WMA_LOGD("%s:intra_fwd:vdev(%d) intrabss_dis=%s", + __func__, pdis_intra_fwd->sessionId, + (pdis_intra_fwd->disableintrabssfwd ? "true" : "false")); + + txrx_vdev = wma_handle->interfaces[pdis_intra_fwd->sessionId].handle; + ol_vdev_rx_set_intrabss_fwd(txrx_vdev, + pdis_intra_fwd->disableintrabssfwd); +} diff --git a/drivers/staging/qcacld-3.0/core/wma/src/wma_dfs_interface.c b/drivers/staging/qcacld-3.0/core/wma/src/wma_dfs_interface.c new file mode 100644 index 0000000000000000000000000000000000000000..4af86ba6e233f3b91c48d72f1b109f8c67f7bfdc --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/wma/src/wma_dfs_interface.c @@ -0,0 +1,246 @@ +/* + * Copyright (c) 2013-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: wma_dfs_interface.c + * + * Source code borrowed from QCA_MAIN DFS module + */ + +#include "wma.h" +#include "ath_dfs_structs.h" +#include "wma_dfs_interface.h" +#include "dfs_interface.h" + +#ifndef ATH_SUPPORT_DFS +#define ATH_SUPPORT_DFS 1 +#endif + +/** + * ol_if_dfs_attach() - dfs attach + * @ic: ieee80211com ptr + * @ptr: ath_dfs_caps ptr + * @radar_info: radar info + * + * Return: 0 for success or error code + */ +int ol_if_dfs_attach(struct ieee80211com *ic, void *ptr, void *radar_info) +{ + struct ath_dfs_caps *pCap = (struct ath_dfs_caps *)ptr; + + qdf_print("%s: called; ptr=%p, radar_info=%p\n", + __func__, ptr, radar_info); + + pCap->ath_chip_is_bb_tlv = 1; + pCap->ath_dfs_combined_rssi_ok = 0; + pCap->ath_dfs_ext_chan_ok = 0; + pCap->ath_dfs_use_enhancement = 0; + pCap->ath_strong_signal_diversiry = 0; + pCap->ath_fastdiv_val = 0; + + return 0; +} + +/** + * ol_if_get_tsf64() - Place Holder API + * @ic: ieee80211com ptr + * + * We get the tsf from Firmware. + * + * Return: always return success(0) + */ +uint64_t ol_if_get_tsf64(struct ieee80211com *ic) +{ + return 0; +} + +/** + * ol_if_dfs_disable() - Place Holder API + * @ic: ieee80211com ptr + * + * ic_dfs_disable is just a place holder + * function since firmware takes care of + * disabling the dfs phyerrors disabling. + * + * Return: always return success(0) + */ +int ol_if_dfs_disable(struct ieee80211com *ic) +{ + return 0; +} + +/** + * ieee80211_find_channel() - find ieee80211 channel + * @ic: ieee80211com ptr + * @freq: frequency + * @flags: flags + * + * Locate a channel given a frequency+flags. We cache + * the previous lookup to optimize swithing between + * two channels--as happens with dynamic turbo. + * This verifies that found channels have not been + * excluded because of 11d. + * + * Return: returns dfs_ieee80211_channel or NULL for error + */ +struct dfs_ieee80211_channel *ieee80211_find_channel(struct ieee80211com *ic, + int freq, uint32_t flags) +{ + struct dfs_ieee80211_channel *c; + int i; + + flags &= IEEE80211_CHAN_ALLTURBO; + /* brute force search */ + for (i = 0; i < ic->ic_nchans; i++) { + c = &ic->ic_channels[i]; + + if ((!IEEE80211_IS_CHAN_11D_EXCLUDED(c)) && + (c->ic_freq == freq) && + ((c->ic_flags & IEEE80211_CHAN_ALLTURBO) == flags)) { + return c; + } + } + + return NULL; +} + +/** + * ic_dfs_enable() - enable DFS + * @ic: ieee80211com ptr + * @is_fastclk: is fastclock + * + * For offload solutions, radar PHY errors will be enabled + * by the target firmware when DFS is requested for the + * current channel. + * + * Return: Always returns success + */ +int ol_if_dfs_enable(struct ieee80211com *ic, int *is_fastclk, void *pe) +{ + /* + * For peregrine, treat fastclk as the "oversampling" mode. + * It's on by default. This may change at some point, so + * we should really query the firmware to find out what + * the current configuration is. + */ + (*is_fastclk) = 1; + + return 0; +} + +/** + * ieee80211_ieee2mhz() - Convert IEEE channel number to MHz frequency. + * @chan: channel number + * @flags: flags + * + * Return: frequency in MHz + */ +uint32_t ieee80211_ieee2mhz(uint32_t chan, uint32_t flags) +{ + if (flags & IEEE80211_CHAN_2GHZ) { + /* 2GHz band */ + if (chan == 14) + return 2484; + if (chan < 14) + return 2407 + chan * 5; + else + return 2512 + ((chan - 15) * 20); + } else if (flags & IEEE80211_CHAN_5GHZ) { + /* 5Ghz band */ + return 5000 + (chan * 5); + } else { + /* either, guess */ + if (chan == 14) + return 2484; + if (chan < 14) /* 0-13 */ + return 2407 + chan * 5; + if (chan < 27) /* 15-26 */ + return 2512 + ((chan - 15) * 20); + return 5000 + (chan * 5); + } +} + +/** + * ol_if_dfs_get_ext_busy() - Place holder function ic_get_ext_busy + * @ic: ieee80211com ptr + * + * Return: Always return success (0) + */ +int ol_if_dfs_get_ext_busy(struct ieee80211com *ic) +{ + return 0; +} + +/** + * ol_if_dfs_get_mib_cycle_counts_pct() - Place holder function + * @ic: ieee80211com ptr + * + * Return: Always return success (0) + */ +int +ol_if_dfs_get_mib_cycle_counts_pct(struct ieee80211com *ic, + uint32_t *rxc_pcnt, uint32_t *rxf_pcnt, + uint32_t *txf_pcnt) +{ + return 0; +} + +/** + * ol_if_dfs_usenol() - dfs usenol call + * @ic: ieee80211com ptr + * + * Return: 0 fo success or error code + */ +uint16_t ol_if_dfs_usenol(struct ieee80211com *ic) +{ +#if ATH_SUPPORT_DFS + return dfs_usenol(ic); +#else + return 0; +#endif /* ATH_SUPPORT_DFS */ + return 0; +} + +/** + * ieee80211_mark_dfs() - indicate radar on current operating freq + * @ic: ieee80211com ptr + * @ichan: channel + * + * Function to indicate Radar on the current + * SAP operating channel.This indication will + * be posted to SAP to select a new channel + * randomly and issue a vdev restart to + * operate on the new channel. + * + * Return: none + */ +void +ieee80211_mark_dfs(struct ieee80211com *ic, struct dfs_ieee80211_channel *ichan) +{ + int status; + status = wma_dfs_indicate_radar(ic, ichan); +} diff --git a/drivers/staging/qcacld-3.0/core/wma/src/wma_features.c b/drivers/staging/qcacld-3.0/core/wma/src/wma_features.c new file mode 100644 index 0000000000000000000000000000000000000000..b3ee42ffffe9aafb8cd53bc60fcb546cd00b4231 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/wma/src/wma_features.c @@ -0,0 +1,8968 @@ +/* + * Copyright (c) 2013-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: wma_features.c + * This file contains different features related functions like WoW, + * Offloads, TDLS etc. + */ + +/* Header files */ + +#include "cds_ieee80211_common.h" /* ieee80211_frame */ +#include "wma.h" +#include "wma_api.h" +#include "cds_api.h" +#include "wmi_unified_api.h" +#include "wlan_qct_sys.h" +#include "wni_api.h" +#include "ani_global.h" +#include "wmi_unified.h" +#include "wni_cfg.h" +#include "cfg_api.h" +#include "ol_txrx_ctrl_api.h" +#include +#include + +#include "qdf_nbuf.h" +#include "qdf_types.h" +#include "qdf_mem.h" +#include "ol_txrx_peer_find.h" + +#include "wma_types.h" +#include "lim_api.h" +#include "lim_session_utils.h" + +#include "cds_utils.h" + +#if !defined(REMOVE_PKT_LOG) +#include "pktlog_ac.h" +#endif /* REMOVE_PKT_LOG */ + +#include "dbglog_host.h" +#include "csr_api.h" +#include "ol_fw.h" + +#include "dfs.h" +#include "radar_filters.h" +#include "wma_internal.h" +#include "ol_txrx.h" +#include "wma_nan_datapath.h" + +#ifndef ARRAY_LENGTH +#define ARRAY_LENGTH(a) (sizeof(a) / sizeof((a)[0])) +#endif + +/** + * WMA_SET_VDEV_IE_SOURCE_HOST - Flag to identify the source of VDEV SET IE + * command. The value is 0x0 for the VDEV SET IE WMI commands from mobile + * MCL platform. + */ +#define WMA_SET_VDEV_IE_SOURCE_HOST 0x0 + +static const uint8_t arp_ptrn[] = {0x08, 0x06}; +static const uint8_t arp_mask[] = {0xff, 0xff}; +static const uint8_t ns_ptrn[] = {0x86, 0xDD}; +static const uint8_t discvr_ptrn[] = {0xe0, 0x00, 0x00, 0xf8}; +static const uint8_t discvr_mask[] = {0xf0, 0x00, 0x00, 0xf8}; + +#ifdef FEATURE_WLAN_DIAG_SUPPORT +/** + * qdf_wma_wow_wakeup_stats_event()- send wow wakeup stats + * + * This function sends wow wakeup stats diag event + * + * Return: void. + */ +static void qdf_wma_wow_wakeup_stats_event(void) +{ + QDF_STATUS status; + struct sir_wake_lock_stats stats; + WLAN_HOST_DIAG_EVENT_DEF(WowStats, + struct host_event_wlan_powersave_wow_stats); + + status = wma_get_wakelock_stats(&stats); + if (QDF_IS_STATUS_ERROR(status)) + return; + + qdf_mem_zero(&WowStats, sizeof(WowStats)); + WowStats.wow_bcast_wake_up_count = + stats.wow_bcast_wake_up_count; + WowStats.wow_ipv4_mcast_wake_up_count = + stats.wow_ipv4_mcast_wake_up_count; + WowStats.wow_ipv6_mcast_wake_up_count = + stats.wow_ipv6_mcast_wake_up_count; + WowStats.wow_ipv6_mcast_ra_stats = + stats.wow_ipv6_mcast_ra_stats; + WowStats.wow_ipv6_mcast_ns_stats = + stats.wow_ipv6_mcast_ns_stats; + WowStats.wow_ipv6_mcast_na_stats = + stats.wow_ipv6_mcast_na_stats; + WowStats.wow_pno_match_wake_up_count = + stats.wow_pno_match_wake_up_count; + WowStats.wow_pno_complete_wake_up_count = + stats.wow_pno_complete_wake_up_count; + WowStats.wow_gscan_wake_up_count = + stats.wow_gscan_wake_up_count; + WowStats.wow_low_rssi_wake_up_count = + stats.wow_low_rssi_wake_up_count; + WowStats.wow_rssi_breach_wake_up_count = + stats.wow_rssi_breach_wake_up_count; + WowStats.wow_icmpv4_count = + stats.wow_icmpv4_count; + WowStats.wow_icmpv6_count = + stats.wow_icmpv6_count; + WowStats.wow_oem_response_wake_up_count = + stats.wow_oem_response_wake_up_count; + + WLAN_HOST_DIAG_EVENT_REPORT(&WowStats, EVENT_WLAN_POWERSAVE_WOW_STATS); +} +#else +static void qdf_wma_wow_wakeup_stats_event(void) +{ + return; +} +#endif + +#ifdef FEATURE_WLAN_AUTO_SHUTDOWN +/** + * wma_post_auto_shutdown_msg() - to post auto shutdown event to sme + * + * Return: 0 for success or error code + */ +static int wma_post_auto_shutdown_msg(void) +{ + tSirAutoShutdownEvtParams *auto_sh_evt; + QDF_STATUS qdf_status; + cds_msg_t sme_msg = { 0 }; + + auto_sh_evt = (tSirAutoShutdownEvtParams *) + qdf_mem_malloc(sizeof(tSirAutoShutdownEvtParams)); + if (!auto_sh_evt) { + WMA_LOGE(FL("No Mem")); + return -ENOMEM; + } + + auto_sh_evt->shutdown_reason = + WMI_HOST_AUTO_SHUTDOWN_REASON_TIMER_EXPIRY; + sme_msg.type = eWNI_SME_AUTO_SHUTDOWN_IND; + sme_msg.bodyptr = auto_sh_evt; + sme_msg.bodyval = 0; + + qdf_status = cds_mq_post_message(QDF_MODULE_ID_SME, &sme_msg); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + WMA_LOGE("Fail to post eWNI_SME_AUTO_SHUTDOWN_IND msg to SME"); + qdf_mem_free(auto_sh_evt); + return -EINVAL; + } + + return 0; +} +#endif +/** + * wma_send_snr_request() - send request to fw to get RSSI stats + * @wma_handle: wma handle + * @pGetRssiReq: get RSSI request + * + * Return: QDF status + */ +QDF_STATUS wma_send_snr_request(tp_wma_handle wma_handle, + void *pGetRssiReq) +{ + tAniGetRssiReq *pRssiBkUp = NULL; + + /* command is in progess */ + if (NULL != wma_handle->pGetRssiReq) + return QDF_STATUS_SUCCESS; + + /* create a copy of csrRssiCallback to send rssi value + * after wmi event + */ + if (pGetRssiReq) { + pRssiBkUp = qdf_mem_malloc(sizeof(tAniGetRssiReq)); + if (!pRssiBkUp) { + WMA_LOGE("Failed to allocate memory for tAniGetRssiReq"); + wma_handle->pGetRssiReq = NULL; + return QDF_STATUS_E_NOMEM; + } + pRssiBkUp->sessionId = + ((tAniGetRssiReq *) pGetRssiReq)->sessionId; + pRssiBkUp->rssiCallback = + ((tAniGetRssiReq *) pGetRssiReq)->rssiCallback; + pRssiBkUp->pDevContext = + ((tAniGetRssiReq *) pGetRssiReq)->pDevContext; + wma_handle->pGetRssiReq = (void *)pRssiBkUp; + } + + if (wmi_unified_snr_request_cmd(wma_handle->wmi_handle)) { + WMA_LOGE("Failed to send host stats request to fw"); + qdf_mem_free(pRssiBkUp); + wma_handle->pGetRssiReq = NULL; + return QDF_STATUS_E_FAILURE; + } + return QDF_STATUS_SUCCESS; +} + +/** + * wma_get_snr() - get RSSI from fw + * @psnr_req: request params + * + * Return: QDF status + */ +QDF_STATUS wma_get_snr(tAniGetSnrReq *psnr_req) +{ + tAniGetSnrReq *psnr_req_bkp; + tp_wma_handle wma_handle = NULL; + struct wma_txrx_node *intr; + + wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + + if (NULL == wma_handle) { + WMA_LOGE("%s : Failed to get wma_handle", __func__); + return QDF_STATUS_E_FAULT; + } + + intr = &wma_handle->interfaces[psnr_req->sessionId]; + /* command is in progess */ + if (NULL != intr->psnr_req) { + WMA_LOGE("%s : previous snr request is pending", __func__); + return QDF_STATUS_SUCCESS; + } + + psnr_req_bkp = qdf_mem_malloc(sizeof(tAniGetSnrReq)); + if (!psnr_req_bkp) { + WMA_LOGE("Failed to allocate memory for tAniGetSnrReq"); + return QDF_STATUS_E_NOMEM; + } + + qdf_mem_set(psnr_req_bkp, sizeof(tAniGetSnrReq), 0); + psnr_req_bkp->staId = psnr_req->staId; + psnr_req_bkp->pDevContext = psnr_req->pDevContext; + psnr_req_bkp->snrCallback = psnr_req->snrCallback; + intr->psnr_req = (void *)psnr_req_bkp; + + if (wmi_unified_snr_cmd(wma_handle->wmi_handle, + psnr_req->sessionId)) { + WMA_LOGE("Failed to send host stats request to fw"); + qdf_mem_free(psnr_req_bkp); + intr->psnr_req = NULL; + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * wma_process_link_status_req() - process link status request from UMAC + * @wma: wma handle + * @pGetLinkStatus: get link params + * + * Return: none + */ +void wma_process_link_status_req(tp_wma_handle wma, + tAniGetLinkStatus *pGetLinkStatus) +{ + struct link_status_params cmd = {0}; + struct wma_txrx_node *iface = + &wma->interfaces[pGetLinkStatus->sessionId]; + + if (iface->plink_status_req) { + WMA_LOGE("%s:previous link status request is pending,deleting the new request", + __func__); + qdf_mem_free(pGetLinkStatus); + return; + } + + iface->plink_status_req = pGetLinkStatus; + cmd.session_id = pGetLinkStatus->sessionId; + if (wmi_unified_link_status_req_cmd(wma->wmi_handle, &cmd)) { + WMA_LOGE("Failed to send WMI link status request to fw"); + iface->plink_status_req = NULL; + goto end; + } + + return; + +end: + wma_post_link_status(pGetLinkStatus, LINK_STATUS_LEGACY); +} + +#ifdef WLAN_FEATURE_TSF +/** + * wma_vdev_tsf_handler() - handle tsf event indicated by FW + * @handle: wma context + * @data: event buffer + * @data len: length of event buffer + * + * Return: 0 on success + */ +int wma_vdev_tsf_handler(void *handle, uint8_t *data, uint32_t data_len) +{ + cds_msg_t tsf_msg = {0}; + WMI_VDEV_TSF_REPORT_EVENTID_param_tlvs *param_buf; + wmi_vdev_tsf_report_event_fixed_param *tsf_event; + struct stsf *ptsf; + + if (data == NULL) { + WMA_LOGE("%s: invalid pointer", __func__); + return -EINVAL; + } + ptsf = qdf_mem_malloc(sizeof(*ptsf)); + if (NULL == ptsf) { + WMA_LOGE("%s: failed to allocate tsf data structure", __func__); + return -ENOMEM; + } + + param_buf = (WMI_VDEV_TSF_REPORT_EVENTID_param_tlvs *)data; + tsf_event = param_buf->fixed_param; + + ptsf->vdev_id = tsf_event->vdev_id; + ptsf->tsf_low = tsf_event->tsf_low; + ptsf->tsf_high = tsf_event->tsf_high; + ptsf->soc_timer_low = tsf_event->qtimer_low; + ptsf->soc_timer_high = tsf_event->qtimer_high; + + WMA_LOGD("%s: receive WMI_VDEV_TSF_REPORT_EVENTID ", __func__); + WMA_LOGD("%s: vdev_id = %u,tsf_low =%u, tsf_high = %u", __func__, + ptsf->vdev_id, ptsf->tsf_low, ptsf->tsf_high); + + tsf_msg.type = eWNI_SME_TSF_EVENT; + tsf_msg.bodyptr = ptsf; + tsf_msg.bodyval = 0; + + if (QDF_STATUS_SUCCESS != + cds_mq_post_message(CDS_MQ_ID_SME, &tsf_msg)) { + + WMA_LOGP("%s: Failed to post eWNI_SME_TSF_EVENT", __func__); + qdf_mem_free(ptsf); + return -EINVAL; + } + return 0; +} + +#ifdef QCA_WIFI_3_0 +#define TSF_FW_ACTION_CMD TSF_TSTAMP_QTIMER_CAPTURE_REQ +#else +#define TSF_FW_ACTION_CMD TSF_TSTAMP_CAPTURE_REQ +#endif +/** + * wma_capture_tsf() - send wmi to fw to capture tsf + * @wma_handle: wma handler + * @vdev_id: vdev id + * + * Return: wmi send state + */ +QDF_STATUS wma_capture_tsf(tp_wma_handle wma_handle, uint32_t vdev_id) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + wmi_buf_t buf; + wmi_vdev_tsf_tstamp_action_cmd_fixed_param *cmd; + int ret; + int len = sizeof(*cmd); + + buf = wmi_buf_alloc(wma_handle->wmi_handle, len); + if (!buf) { + WMA_LOGP("%s: failed to allocate memory for cap tsf cmd", + __func__); + return QDF_STATUS_E_NOMEM; + } + + cmd = (wmi_vdev_tsf_tstamp_action_cmd_fixed_param *) wmi_buf_data(buf); + cmd->vdev_id = vdev_id; + cmd->tsf_action = TSF_FW_ACTION_CMD; + WMA_LOGD("%s :vdev_id %u, tsf_cmd: %d", __func__, cmd->vdev_id, + cmd->tsf_action); + + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_vdev_tsf_tstamp_action_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN( + wmi_vdev_tsf_tstamp_action_cmd_fixed_param)); + + ret = wmi_unified_cmd_send(wma_handle->wmi_handle, buf, len, + WMI_VDEV_TSF_TSTAMP_ACTION_CMDID); + if (ret != EOK) { + WMA_LOGE("wmi_unified_cmd_send returned Error %d", status); + status = QDF_STATUS_E_FAILURE; + goto error; + } + + return QDF_STATUS_SUCCESS; + +error: + if (buf) + wmi_buf_free(buf); + return status; +} + +/** + * wma_reset_tsf_gpio() - send wmi to fw to reset GPIO + * @wma_handle: wma handler + * @vdev_id: vdev id + * + * Return: wmi send state + */ +QDF_STATUS wma_reset_tsf_gpio(tp_wma_handle wma_handle, uint32_t vdev_id) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + wmi_buf_t buf; + wmi_vdev_tsf_tstamp_action_cmd_fixed_param *cmd; + int ret; + int len = sizeof(*cmd); + uint8_t *buf_ptr; + + buf = wmi_buf_alloc(wma_handle->wmi_handle, len); + if (!buf) { + WMA_LOGP("%s: failed to allocate memory for reset tsf gpio", + __func__); + return QDF_STATUS_E_NOMEM; + } + + buf_ptr = (uint8_t *) wmi_buf_data(buf); + cmd = (wmi_vdev_tsf_tstamp_action_cmd_fixed_param *) buf_ptr; + cmd->vdev_id = vdev_id; + cmd->tsf_action = TSF_TSTAMP_CAPTURE_RESET; + + WMA_LOGD("%s :vdev_id %u, TSF_TSTAMP_CAPTURE_RESET", __func__, + cmd->vdev_id); + + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_vdev_tsf_tstamp_action_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN( + wmi_vdev_tsf_tstamp_action_cmd_fixed_param)); + + ret = wmi_unified_cmd_send(wma_handle->wmi_handle, buf, len, + WMI_VDEV_TSF_TSTAMP_ACTION_CMDID); + + if (ret != EOK) { + WMA_LOGE("wmi_unified_cmd_send returned Error %d", status); + status = QDF_STATUS_E_FAILURE; + goto error; + } + return QDF_STATUS_SUCCESS; + +error: + if (buf) + wmi_buf_free(buf); + return status; +} + +/** + * wma_set_tsf_gpio_pin() - send wmi cmd to configure gpio pin + * @handle: wma handler + * @pin: GPIO pin id + * + * Return: QDF_STATUS + */ +QDF_STATUS wma_set_tsf_gpio_pin(WMA_HANDLE handle, uint32_t pin) +{ + tp_wma_handle wma = (tp_wma_handle)handle; + struct pdev_params pdev_param = {0}; + int32_t ret; + + if (!wma || !wma->wmi_handle) { + WMA_LOGE("%s: WMA is closed, can not set gpio", __func__); + return QDF_STATUS_E_INVAL; + } + + WMA_LOGD("%s: set tsf gpio pin: %d", __func__, pin); + + pdev_param.param_id = WMI_PDEV_PARAM_WNTS_CONFIG; + pdev_param.param_value = pin; + ret = wmi_unified_pdev_param_send(wma->wmi_handle, + &pdev_param, + WMA_WILDCARD_PDEV_ID); + if (ret) { + WMA_LOGE("%s: Failed to set tsf gpio pin (%d)", __func__, ret); + return QDF_STATUS_E_FAILURE; + } + return QDF_STATUS_SUCCESS; +} +#endif + +/** + * wma_set_wisa_params(): Set WISA features related params in FW + * @wma_handle: WMA handle + * @wisa: Pointer to WISA param struct + * + * Return: CDF status + */ +QDF_STATUS wma_set_wisa_params(tp_wma_handle wma_handle, + struct sir_wisa_params *wisa) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + wmi_buf_t buf; + wmi_vdev_wisa_cmd_fixed_param *cmd; + int ret, len = sizeof(*cmd); + + buf = wmi_buf_alloc(wma_handle->wmi_handle, len); + if (!buf) { + WMA_LOGP("%s: failed to allocate memory for WISA params", + __func__); + return QDF_STATUS_E_NOMEM; + } + + cmd = (wmi_vdev_wisa_cmd_fixed_param *) wmi_buf_data(buf); + cmd->wisa_mode = wisa->mode; + cmd->vdev_id = wisa->vdev_id; + + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_vdev_wisa_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN( + wmi_vdev_wisa_cmd_fixed_param)); + + ret = wmi_unified_cmd_send(wma_handle->wmi_handle, buf, len, + WMI_VDEV_WISA_CMDID); + if (ret != EOK) { + WMA_LOGE("wmi_unified_cmd_send returned Error %d", status); + status = QDF_STATUS_E_FAILURE; + goto error; + } + return QDF_STATUS_SUCCESS; + +error: + wmi_buf_free(buf); + return status; +} + +#ifdef FEATURE_WLAN_LPHB +/** + * wma_lphb_conf_hbenable() - enable command of LPHB configuration requests + * @wma_handle: WMA handle + * @lphb_conf_req: configuration info + * @by_user: whether this call is from user or cached resent + * + * Return: QDF status + */ +static QDF_STATUS wma_lphb_conf_hbenable(tp_wma_handle wma_handle, + tSirLPHBReq *lphb_conf_req, + bool by_user) +{ + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + int status = 0; + tSirLPHBEnableStruct *ts_lphb_enable; + wmi_hb_set_enable_cmd_fixed_param hb_enable_fp; + int i; + + if (lphb_conf_req == NULL) { + WMA_LOGE("%s : LPHB configuration is NULL", __func__); + return QDF_STATUS_E_FAILURE; + } + + ts_lphb_enable = &(lphb_conf_req->params.lphbEnableReq); + WMA_LOGI("%s: WMA --> WMI_HB_SET_ENABLE enable=%d, item=%d, session=%d", + __func__, + ts_lphb_enable->enable, + ts_lphb_enable->item, ts_lphb_enable->session); + + if ((ts_lphb_enable->item != 1) && (ts_lphb_enable->item != 2)) { + WMA_LOGE("%s : LPHB configuration wrong item %d", + __func__, ts_lphb_enable->item); + return QDF_STATUS_E_FAILURE; + } + + + /* fill in values */ + hb_enable_fp.vdev_id = ts_lphb_enable->session; + hb_enable_fp.enable = ts_lphb_enable->enable; + hb_enable_fp.item = ts_lphb_enable->item; + hb_enable_fp.session = ts_lphb_enable->session; + + status = wmi_unified_lphb_config_hbenable_cmd(wma_handle->wmi_handle, + &hb_enable_fp); + if (status != EOK) { + qdf_status = QDF_STATUS_E_FAILURE; + goto error; + } + + if (by_user) { + /* target already configured, now cache command status */ + if (ts_lphb_enable->enable) { + i = ts_lphb_enable->item - 1; + wma_handle->wow.lphb_cache[i].cmd + = LPHB_SET_EN_PARAMS_INDID; + wma_handle->wow.lphb_cache[i].params.lphbEnableReq. + enable = ts_lphb_enable->enable; + wma_handle->wow.lphb_cache[i].params.lphbEnableReq. + item = ts_lphb_enable->item; + wma_handle->wow.lphb_cache[i].params.lphbEnableReq. + session = ts_lphb_enable->session; + + WMA_LOGI("%s: cached LPHB status in WMA context for item %d", + __func__, i); + } else { + qdf_mem_zero((void *)&wma_handle->wow.lphb_cache, + sizeof(wma_handle->wow.lphb_cache)); + WMA_LOGI("%s: cleared all cached LPHB status in WMA context", + __func__); + } + } + + return QDF_STATUS_SUCCESS; +error: + return qdf_status; +} + +/** + * wma_lphb_conf_tcp_params() - set tcp params of LPHB configuration requests + * @wma_handle: wma handle + * @lphb_conf_req: lphb config request + * + * Return: QDF status + */ +static QDF_STATUS wma_lphb_conf_tcp_params(tp_wma_handle wma_handle, + tSirLPHBReq *lphb_conf_req) +{ + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + int status = 0; + tSirLPHBTcpParamStruct *ts_lphb_tcp_param; + wmi_hb_set_tcp_params_cmd_fixed_param hb_tcp_params_fp = {0}; + + + if (lphb_conf_req == NULL) { + WMA_LOGE("%s : LPHB configuration is NULL", __func__); + return QDF_STATUS_E_FAILURE; + } + + ts_lphb_tcp_param = &(lphb_conf_req->params.lphbTcpParamReq); + WMA_LOGI("%s: WMA --> WMI_HB_SET_TCP_PARAMS srv_ip=%08x, " + "dev_ip=%08x, src_port=%d, dst_port=%d, timeout=%d, " + "session=%d, gateway_mac="MAC_ADDRESS_STR", timePeriodSec=%d, " + "tcpSn=%d", __func__, ts_lphb_tcp_param->srv_ip, + ts_lphb_tcp_param->dev_ip, ts_lphb_tcp_param->src_port, + ts_lphb_tcp_param->dst_port, ts_lphb_tcp_param->timeout, + ts_lphb_tcp_param->session, + MAC_ADDR_ARRAY(ts_lphb_tcp_param->gateway_mac.bytes), + ts_lphb_tcp_param->timePeriodSec, ts_lphb_tcp_param->tcpSn); + + /* fill in values */ + hb_tcp_params_fp.vdev_id = ts_lphb_tcp_param->session; + hb_tcp_params_fp.srv_ip = ts_lphb_tcp_param->srv_ip; + hb_tcp_params_fp.dev_ip = ts_lphb_tcp_param->dev_ip; + hb_tcp_params_fp.seq = ts_lphb_tcp_param->tcpSn; + hb_tcp_params_fp.src_port = ts_lphb_tcp_param->src_port; + hb_tcp_params_fp.dst_port = ts_lphb_tcp_param->dst_port; + hb_tcp_params_fp.interval = ts_lphb_tcp_param->timePeriodSec; + hb_tcp_params_fp.timeout = ts_lphb_tcp_param->timeout; + hb_tcp_params_fp.session = ts_lphb_tcp_param->session; + WMI_CHAR_ARRAY_TO_MAC_ADDR(ts_lphb_tcp_param->gateway_mac.bytes, + &hb_tcp_params_fp.gateway_mac); + + status = wmi_unified_lphb_config_tcp_params_cmd(wma_handle->wmi_handle, + &hb_tcp_params_fp); + if (status != EOK) { + qdf_status = QDF_STATUS_E_FAILURE; + goto error; + } + + return QDF_STATUS_SUCCESS; +error: + return qdf_status; +} + +/** + * wma_lphb_conf_tcp_pkt_filter() - configure tcp packet filter command of LPHB + * @wma_handle: wma handle + * @lphb_conf_req: lphb config request + * + * Return: QDF status + */ +static QDF_STATUS wma_lphb_conf_tcp_pkt_filter(tp_wma_handle wma_handle, + tSirLPHBReq *lphb_conf_req) +{ + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + int status = 0; + tSirLPHBTcpFilterStruct *ts_lphb_tcp_filter; + wmi_hb_set_tcp_pkt_filter_cmd_fixed_param hb_tcp_filter_fp = {0}; + + if (lphb_conf_req == NULL) { + WMA_LOGE("%s : LPHB configuration is NULL", __func__); + return QDF_STATUS_E_FAILURE; + } + + ts_lphb_tcp_filter = &(lphb_conf_req->params.lphbTcpFilterReq); + WMA_LOGI("%s: WMA --> WMI_HB_SET_TCP_PKT_FILTER length=%d, offset=%d, session=%d, " + "filter=%2x:%2x:%2x:%2x:%2x:%2x ...", __func__, + ts_lphb_tcp_filter->length, ts_lphb_tcp_filter->offset, + ts_lphb_tcp_filter->session, ts_lphb_tcp_filter->filter[0], + ts_lphb_tcp_filter->filter[1], ts_lphb_tcp_filter->filter[2], + ts_lphb_tcp_filter->filter[3], ts_lphb_tcp_filter->filter[4], + ts_lphb_tcp_filter->filter[5]); + + /* fill in values */ + hb_tcp_filter_fp.vdev_id = ts_lphb_tcp_filter->session; + hb_tcp_filter_fp.length = ts_lphb_tcp_filter->length; + hb_tcp_filter_fp.offset = ts_lphb_tcp_filter->offset; + hb_tcp_filter_fp.session = ts_lphb_tcp_filter->session; + memcpy((void *)&hb_tcp_filter_fp.filter, + (void *)&ts_lphb_tcp_filter->filter, + WMI_WLAN_HB_MAX_FILTER_SIZE); + + status = wmi_unified_lphb_config_tcp_pkt_filter_cmd(wma_handle->wmi_handle, + &hb_tcp_filter_fp); + if (status != EOK) { + qdf_status = QDF_STATUS_E_FAILURE; + goto error; + } + + return QDF_STATUS_SUCCESS; +error: + return qdf_status; +} + +/** + * wma_lphb_conf_udp_params() - configure udp param command of LPHB + * @wma_handle: wma handle + * @lphb_conf_req: lphb config request + * + * Return: QDF status + */ +static QDF_STATUS wma_lphb_conf_udp_params(tp_wma_handle wma_handle, + tSirLPHBReq *lphb_conf_req) +{ + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + int status = 0; + tSirLPHBUdpParamStruct *ts_lphb_udp_param; + wmi_hb_set_udp_params_cmd_fixed_param hb_udp_params_fp = {0}; + + + if (lphb_conf_req == NULL) { + WMA_LOGE("%s : LPHB configuration is NULL", __func__); + return QDF_STATUS_E_FAILURE; + } + + ts_lphb_udp_param = &(lphb_conf_req->params.lphbUdpParamReq); + WMA_LOGI("%s: WMA --> WMI_HB_SET_UDP_PARAMS srv_ip=%d, dev_ip=%d, src_port=%d, " + "dst_port=%d, interval=%d, timeout=%d, session=%d, " + "gateway_mac="MAC_ADDRESS_STR, __func__, + ts_lphb_udp_param->srv_ip, ts_lphb_udp_param->dev_ip, + ts_lphb_udp_param->src_port, ts_lphb_udp_param->dst_port, + ts_lphb_udp_param->interval, ts_lphb_udp_param->timeout, + ts_lphb_udp_param->session, + MAC_ADDR_ARRAY(ts_lphb_udp_param->gateway_mac.bytes)); + + + /* fill in values */ + hb_udp_params_fp.vdev_id = ts_lphb_udp_param->session; + hb_udp_params_fp.srv_ip = ts_lphb_udp_param->srv_ip; + hb_udp_params_fp.dev_ip = ts_lphb_udp_param->dev_ip; + hb_udp_params_fp.src_port = ts_lphb_udp_param->src_port; + hb_udp_params_fp.dst_port = ts_lphb_udp_param->dst_port; + hb_udp_params_fp.interval = ts_lphb_udp_param->interval; + hb_udp_params_fp.timeout = ts_lphb_udp_param->timeout; + hb_udp_params_fp.session = ts_lphb_udp_param->session; + WMI_CHAR_ARRAY_TO_MAC_ADDR(ts_lphb_udp_param->gateway_mac.bytes, + &hb_udp_params_fp.gateway_mac); + + status = wmi_unified_lphb_config_udp_params_cmd(wma_handle->wmi_handle, + &hb_udp_params_fp); + if (status != EOK) { + qdf_status = QDF_STATUS_E_FAILURE; + goto error; + } + + return QDF_STATUS_SUCCESS; +error: + return qdf_status; +} + +/** + * wma_lphb_conf_udp_pkt_filter() - configure udp pkt filter command of LPHB + * @wma_handle: wma handle + * @lphb_conf_req: lphb config request + * + * Return: QDF status + */ +static QDF_STATUS wma_lphb_conf_udp_pkt_filter(tp_wma_handle wma_handle, + tSirLPHBReq *lphb_conf_req) +{ + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + int status = 0; + tSirLPHBUdpFilterStruct *ts_lphb_udp_filter; + wmi_hb_set_udp_pkt_filter_cmd_fixed_param hb_udp_filter_fp = {0}; + + if (lphb_conf_req == NULL) { + WMA_LOGE("%s : LPHB configuration is NULL", __func__); + return QDF_STATUS_E_FAILURE; + } + + ts_lphb_udp_filter = &(lphb_conf_req->params.lphbUdpFilterReq); + WMA_LOGI("%s: WMA --> WMI_HB_SET_UDP_PKT_FILTER length=%d, offset=%d, session=%d, " + "filter=%2x:%2x:%2x:%2x:%2x:%2x ...", __func__, + ts_lphb_udp_filter->length, ts_lphb_udp_filter->offset, + ts_lphb_udp_filter->session, ts_lphb_udp_filter->filter[0], + ts_lphb_udp_filter->filter[1], ts_lphb_udp_filter->filter[2], + ts_lphb_udp_filter->filter[3], ts_lphb_udp_filter->filter[4], + ts_lphb_udp_filter->filter[5]); + + + /* fill in values */ + hb_udp_filter_fp.vdev_id = ts_lphb_udp_filter->session; + hb_udp_filter_fp.length = ts_lphb_udp_filter->length; + hb_udp_filter_fp.offset = ts_lphb_udp_filter->offset; + hb_udp_filter_fp.session = ts_lphb_udp_filter->session; + memcpy((void *)&hb_udp_filter_fp.filter, + (void *)&ts_lphb_udp_filter->filter, + WMI_WLAN_HB_MAX_FILTER_SIZE); + + status = wmi_unified_lphb_config_udp_pkt_filter_cmd(wma_handle->wmi_handle, + &hb_udp_filter_fp); + if (status != EOK) { + qdf_status = QDF_STATUS_E_FAILURE; + goto error; + } + + return QDF_STATUS_SUCCESS; +error: + return qdf_status; +} + +/** + * wma_process_lphb_conf_req() - handle LPHB configuration requests + * @wma_handle: wma handle + * @lphb_conf_req: lphb config request + * + * Return: QDF status + */ +QDF_STATUS wma_process_lphb_conf_req(tp_wma_handle wma_handle, + tSirLPHBReq *lphb_conf_req) +{ + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + + if (lphb_conf_req == NULL) { + WMA_LOGE("%s : LPHB configuration is NULL", __func__); + return QDF_STATUS_E_FAILURE; + } + + WMA_LOGI("%s : LPHB configuration cmd id is %d", __func__, + lphb_conf_req->cmd); + switch (lphb_conf_req->cmd) { + case LPHB_SET_EN_PARAMS_INDID: + qdf_status = wma_lphb_conf_hbenable(wma_handle, + lphb_conf_req, true); + break; + + case LPHB_SET_TCP_PARAMS_INDID: + qdf_status = wma_lphb_conf_tcp_params(wma_handle, + lphb_conf_req); + break; + + case LPHB_SET_TCP_PKT_FILTER_INDID: + qdf_status = wma_lphb_conf_tcp_pkt_filter(wma_handle, + lphb_conf_req); + break; + + case LPHB_SET_UDP_PARAMS_INDID: + qdf_status = wma_lphb_conf_udp_params(wma_handle, + lphb_conf_req); + break; + + case LPHB_SET_UDP_PKT_FILTER_INDID: + qdf_status = wma_lphb_conf_udp_pkt_filter(wma_handle, + lphb_conf_req); + break; + + case LPHB_SET_NETWORK_INFO_INDID: + default: + break; + } + + qdf_mem_free(lphb_conf_req); + return qdf_status; +} +#endif /* FEATURE_WLAN_LPHB */ + +/** + * wma_process_dhcp_ind() - process dhcp indication from SME + * @wma_handle: wma handle + * @ta_dhcp_ind: DHCP indication + * + * Return: QDF Status + */ +QDF_STATUS wma_process_dhcp_ind(tp_wma_handle wma_handle, + tAniDHCPInd *ta_dhcp_ind) +{ + uint8_t vdev_id; + int status = 0; + wmi_peer_set_param_cmd_fixed_param peer_set_param_fp = {0}; + + if (!ta_dhcp_ind) { + WMA_LOGE("%s : DHCP indication is NULL", __func__); + return QDF_STATUS_E_FAILURE; + } + + if (!wma_find_vdev_by_addr(wma_handle, + ta_dhcp_ind->adapterMacAddr.bytes, + &vdev_id)) { + WMA_LOGE("%s: Failed to find vdev id for DHCP indication", + __func__); + return QDF_STATUS_E_FAILURE; + } + + WMA_LOGI("%s: WMA --> WMI_PEER_SET_PARAM triggered by DHCP, " + "msgType=%s," + "device_mode=%d, macAddr=" MAC_ADDRESS_STR, + __func__, + ta_dhcp_ind->msgType == WMA_DHCP_START_IND ? + "WMA_DHCP_START_IND" : "WMA_DHCP_STOP_IND", + ta_dhcp_ind->device_mode, + MAC_ADDR_ARRAY(ta_dhcp_ind->peerMacAddr.bytes)); + + /* fill in values */ + peer_set_param_fp.vdev_id = vdev_id; + peer_set_param_fp.param_id = WMI_PEER_CRIT_PROTO_HINT_ENABLED; + if (WMA_DHCP_START_IND == ta_dhcp_ind->msgType) + peer_set_param_fp.param_value = 1; + else + peer_set_param_fp.param_value = 0; + WMI_CHAR_ARRAY_TO_MAC_ADDR(ta_dhcp_ind->peerMacAddr.bytes, + &peer_set_param_fp.peer_macaddr); + + status = wmi_unified_process_dhcp_ind(wma_handle->wmi_handle, + &peer_set_param_fp); + if (status != EOK) { + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * wma_chan_phy__mode() - get WLAN_PHY_MODE for channel + * @chan: channel number + * @chan_width: maximum channel width possible + * @dot11_mode: maximum phy_mode possible + * + * Return: return WLAN_PHY_MODE + */ +WLAN_PHY_MODE wma_chan_phy_mode(u8 chan, enum phy_ch_width chan_width, + u8 dot11_mode) +{ + WLAN_PHY_MODE phymode = MODE_UNKNOWN; + uint16_t bw_val = cds_bw_value(chan_width); + + if (CDS_IS_CHANNEL_24GHZ(chan)) { + if (((CH_WIDTH_5MHZ == chan_width) || + (CH_WIDTH_10MHZ == chan_width)) && + ((WNI_CFG_DOT11_MODE_11B == dot11_mode) || + (WNI_CFG_DOT11_MODE_11G == dot11_mode) || + (WNI_CFG_DOT11_MODE_11N == dot11_mode) || + (WNI_CFG_DOT11_MODE_ALL == dot11_mode) || + (WNI_CFG_DOT11_MODE_11AC == dot11_mode))) + phymode = MODE_11G; + else { + switch (dot11_mode) { + case WNI_CFG_DOT11_MODE_11B: + if ((20 == bw_val) || + (40 == bw_val)) + phymode = MODE_11B; + break; + case WNI_CFG_DOT11_MODE_11G: + if ((20 == bw_val) || + (40 == bw_val)) + phymode = MODE_11G; + break; + case WNI_CFG_DOT11_MODE_11G_ONLY: + if ((20 == bw_val) || + (40 == bw_val)) + phymode = MODE_11GONLY; + break; + case WNI_CFG_DOT11_MODE_11N: + case WNI_CFG_DOT11_MODE_11N_ONLY: + if (20 == bw_val) + phymode = MODE_11NG_HT20; + else if (40 == bw_val) + phymode = MODE_11NG_HT40; + break; + case WNI_CFG_DOT11_MODE_ALL: + case WNI_CFG_DOT11_MODE_11AC: + case WNI_CFG_DOT11_MODE_11AC_ONLY: + if (20 == bw_val) + phymode = MODE_11AC_VHT20_2G; + else if (40 == bw_val) + phymode = MODE_11AC_VHT40_2G; + break; + default: + break; + } + } + } else if (CDS_IS_CHANNEL_DSRC(chan)) + phymode = MODE_11A; + else { + if (((CH_WIDTH_5MHZ == chan_width) || + (CH_WIDTH_10MHZ == chan_width)) && + ((WNI_CFG_DOT11_MODE_11A == dot11_mode) || + (WNI_CFG_DOT11_MODE_11N == dot11_mode) || + (WNI_CFG_DOT11_MODE_ALL == dot11_mode) || + (WNI_CFG_DOT11_MODE_11AC == dot11_mode))) + phymode = MODE_11A; + else { + switch (dot11_mode) { + case WNI_CFG_DOT11_MODE_11A: + if (0 < bw_val) + phymode = MODE_11A; + break; + case WNI_CFG_DOT11_MODE_11N: + case WNI_CFG_DOT11_MODE_11N_ONLY: + if (20 == bw_val) + phymode = MODE_11NA_HT20; + else if (40 <= bw_val) + phymode = MODE_11NA_HT40; + break; + case WNI_CFG_DOT11_MODE_ALL: + case WNI_CFG_DOT11_MODE_11AC: + case WNI_CFG_DOT11_MODE_11AC_ONLY: + if (20 == bw_val) + phymode = MODE_11AC_VHT20; + else if (40 == bw_val) + phymode = MODE_11AC_VHT40; + else if (80 == bw_val) + phymode = MODE_11AC_VHT80; + else if (CH_WIDTH_160MHZ == chan_width) + phymode = MODE_11AC_VHT160; + else if (CH_WIDTH_80P80MHZ == chan_width) + phymode = MODE_11AC_VHT80_80; + break; + default: + break; + } + } + } + + WMA_LOGD("%s: phymode %d channel %d ch_width %d" + "dot11_mode %d", __func__, phymode, chan, + chan_width, dot11_mode); + + QDF_ASSERT(MODE_UNKNOWN != phymode); + return phymode; +} + +/** + * wma_get_link_speed() -send command to get linkspeed + * @handle: wma handle + * @pLinkSpeed: link speed info + * + * Return: QDF status + */ +QDF_STATUS wma_get_link_speed(WMA_HANDLE handle, tSirLinkSpeedInfo *pLinkSpeed) +{ + tp_wma_handle wma_handle = (tp_wma_handle) handle; + wmi_mac_addr peer_macaddr; + + if (!wma_handle || !wma_handle->wmi_handle) { + WMA_LOGE("%s: WMA is closed, can not issue get link speed cmd", + __func__); + return QDF_STATUS_E_INVAL; + } + if (!WMI_SERVICE_IS_ENABLED(wma_handle->wmi_service_bitmap, + WMI_SERVICE_ESTIMATE_LINKSPEED)) { + WMA_LOGE("%s: Linkspeed feature bit not enabled" + " Sending value 0 as link speed.", __func__); + wma_send_link_speed(0); + return QDF_STATUS_E_FAILURE; + } + + /* Copy the peer macaddress to the wma buffer */ + WMI_CHAR_ARRAY_TO_MAC_ADDR(pLinkSpeed->peer_macaddr.bytes, + &peer_macaddr); + + WMA_LOGD("%s: pLinkSpeed->peerMacAddr: %pM, " + "peer_macaddr.mac_addr31to0: 0x%x, peer_macaddr.mac_addr47to32: 0x%x", + __func__, pLinkSpeed->peer_macaddr.bytes, + peer_macaddr.mac_addr31to0, + peer_macaddr.mac_addr47to32); + + if (wmi_unified_get_link_speed_cmd(wma_handle->wmi_handle, + peer_macaddr)) { + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/** +* wma_add_beacon_filter() - Issue WMI command to set beacon filter +* @wma: wma handler +* @filter_params: beacon_filter_param to set +* +* Return: Return QDF_STATUS +*/ +QDF_STATUS wma_add_beacon_filter(WMA_HANDLE handle, + struct beacon_filter_param *filter_params) +{ + int i; + wmi_buf_t wmi_buf; + u_int8_t *buf; + A_UINT32 *ie_map; + int ret; + struct wma_txrx_node *iface; + tp_wma_handle wma = (tp_wma_handle) handle; + + wmi_add_bcn_filter_cmd_fixed_param *cmd; + int len = sizeof(wmi_add_bcn_filter_cmd_fixed_param); + + len += WMI_TLV_HDR_SIZE; + len += BCN_FLT_MAX_ELEMS_IE_LIST*sizeof(A_UINT32); + + if (!wma || !wma->wmi_handle) { + WMA_LOGE("%s: WMA is closed, can not issue set beacon filter", + __func__); + return QDF_STATUS_E_INVAL; + } + + iface = &wma->interfaces[filter_params->vdev_id]; + qdf_mem_copy(&iface->beacon_filter, filter_params, + sizeof(struct beacon_filter_param)); + iface->beacon_filter_enabled = true; + + wmi_buf = wmi_buf_alloc(wma->wmi_handle, len); + if (!wmi_buf) { + WMA_LOGE("%s: wmi_buf_alloc failed", __func__); + return QDF_STATUS_E_NOMEM; + } + + buf = (u_int8_t *) wmi_buf_data(wmi_buf); + + cmd = (wmi_add_bcn_filter_cmd_fixed_param *)wmi_buf_data(wmi_buf); + cmd->vdev_id = filter_params->vdev_id; + + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_add_bcn_filter_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN( + wmi_add_bcn_filter_cmd_fixed_param)); + + buf += sizeof(wmi_add_bcn_filter_cmd_fixed_param); + + WMITLV_SET_HDR(buf, WMITLV_TAG_ARRAY_UINT32, + (BCN_FLT_MAX_ELEMS_IE_LIST * sizeof(u_int32_t))); + + ie_map = (A_UINT32 *)(buf + WMI_TLV_HDR_SIZE); + for (i = 0; i < BCN_FLT_MAX_ELEMS_IE_LIST; i++) { + ie_map[i] = filter_params->ie_map[i]; + WMA_LOGD("beacon filter ie map = %u", ie_map[i]); + } + + ret = wmi_unified_cmd_send(wma->wmi_handle, wmi_buf, len, + WMI_ADD_BCN_FILTER_CMDID); + if (ret) { + WMA_LOGE("Failed to send wmi add beacon filter = %d", + ret); + wmi_buf_free(wmi_buf); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/** +* wma_remove_beacon_filter() - Issue WMI command to remove beacon filter +* @wma: wma handler +* @filter_params: beacon_filter_params +* +* Return: Return QDF_STATUS +*/ +QDF_STATUS wma_remove_beacon_filter(WMA_HANDLE handle, + struct beacon_filter_param *filter_params) +{ + wmi_buf_t buf; + tp_wma_handle wma = (tp_wma_handle) handle; + wmi_rmv_bcn_filter_cmd_fixed_param *cmd; + int len = sizeof(wmi_rmv_bcn_filter_cmd_fixed_param); + int ret; + + if (!wma || !wma->wmi_handle) { + WMA_LOGE("%s: WMA is closed, cannot issue remove beacon filter", + __func__); + return QDF_STATUS_E_INVAL; + } + + buf = wmi_buf_alloc(wma->wmi_handle, len); + if (!buf) { + WMA_LOGE("%s: wmi_buf_alloc failed", __func__); + return QDF_STATUS_E_NOMEM; + } + cmd = (wmi_rmv_bcn_filter_cmd_fixed_param *)wmi_buf_data(buf); + cmd->vdev_id = filter_params->vdev_id; + + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_rmv_bcn_filter_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN( + wmi_rmv_bcn_filter_cmd_fixed_param)); + + ret = wmi_unified_cmd_send(wma->wmi_handle, buf, len, + WMI_RMV_BCN_FILTER_CMDID); + if (ret) { + WMA_LOGE("Failed to send wmi remove beacon filter = %d", + ret); + wmi_buf_free(buf); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * wma_send_adapt_dwelltime_params() - send adaptive dwelltime configuration + * params to firmware + * @wma_handle: wma handler + * @dwelltime_params: pointer to dwelltime_params + * + * Return: QDF_STATUS_SUCCESS on success and QDF failure reason code for failure + */ +QDF_STATUS wma_send_adapt_dwelltime_params(WMA_HANDLE handle, + struct adaptive_dwelltime_params *dwelltime_params) +{ + tp_wma_handle wma_handle = (tp_wma_handle) handle; + struct wmi_adaptive_dwelltime_params wmi_param = {0}; + int32_t err; + + wmi_param.is_enabled = dwelltime_params->is_enabled; + wmi_param.dwelltime_mode = dwelltime_params->dwelltime_mode; + wmi_param.lpf_weight = dwelltime_params->lpf_weight; + wmi_param.passive_mon_intval = dwelltime_params->passive_mon_intval; + wmi_param.wifi_act_threshold = dwelltime_params->wifi_act_threshold; + err = wmi_unified_send_adapt_dwelltime_params_cmd(wma_handle-> + wmi_handle, &wmi_param); + if (err) + return QDF_STATUS_E_FAILURE; + + return QDF_STATUS_SUCCESS; +} + +#ifdef FEATURE_GREEN_AP + +/** + * wma_egap_info_status_event() - egap info status event + * @handle: pointer to wma handler + * @event: pointer to event + * @len: len of the event + * + * Return: 0 for success, otherwise appropriate error code + */ +static int wma_egap_info_status_event(void *handle, u_int8_t *event, + uint32_t len) +{ + WMI_TX_PAUSE_EVENTID_param_tlvs *param_buf; + wmi_ap_ps_egap_info_event_fixed_param *egap_info_event; + wmi_ap_ps_egap_info_chainmask_list *chainmask_event; + u_int8_t *buf_ptr; + + param_buf = (WMI_TX_PAUSE_EVENTID_param_tlvs *)event; + if (!param_buf) { + WMA_LOGE("Invalid EGAP Info status event buffer"); + return -EINVAL; + } + + egap_info_event = (wmi_ap_ps_egap_info_event_fixed_param *) + param_buf->fixed_param; + buf_ptr = (uint8_t *)egap_info_event; + buf_ptr += sizeof(wmi_ap_ps_egap_info_event_fixed_param); + chainmask_event = (wmi_ap_ps_egap_info_chainmask_list *)buf_ptr; + + WMA_LOGI("mac_id: %d, status: %d, tx_mask: %x, rx_mask: %d", + chainmask_event->mac_id, + egap_info_event->status, + chainmask_event->tx_chainmask, + chainmask_event->rx_chainmask); + return 0; +} + +/** + * wma_send_egap_conf_params() - send wmi cmd of egap configuration params + * @wma_handle: wma handler + * @egap_params: pointer to egap_params + * + * Return: 0 for success, otherwise appropriate error code + */ +QDF_STATUS wma_send_egap_conf_params(WMA_HANDLE handle, + struct egap_conf_params *egap_params) +{ + tp_wma_handle wma_handle = (tp_wma_handle) handle; + wmi_ap_ps_egap_param_cmd_fixed_param cmd = {0}; + int32_t err; + + cmd.enable = egap_params->enable; + cmd.inactivity_time = egap_params->inactivity_time; + cmd.wait_time = egap_params->wait_time; + cmd.flags = egap_params->flags; + err = wmi_unified_egap_conf_params_cmd(wma_handle->wmi_handle, &cmd); + if (err) { + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * wma_setup_egap_support() - setup the EGAP support flag + * @tgt_cfg: pointer to hdd target configuration + * @egap_support: EGAP support flag + * + * Return: None + */ +void wma_setup_egap_support(struct wma_tgt_cfg *tgt_cfg, WMA_HANDLE handle) +{ + tp_wma_handle wma_handle = (tp_wma_handle) handle; + + if (tgt_cfg && wma_handle) + tgt_cfg->egap_support = wma_handle->egap_support; +} + +/** + * wma_register_egap_event_handle() - register the EGAP event handle + * @wma_handle: wma handler + * + * Return: None + */ +void wma_register_egap_event_handle(WMA_HANDLE handle) +{ + tp_wma_handle wma_handle = (tp_wma_handle) handle; + QDF_STATUS status; + + if (WMI_SERVICE_IS_ENABLED(wma_handle->wmi_service_bitmap, + WMI_SERVICE_EGAP)) { + status = wmi_unified_register_event_handler( + wma_handle->wmi_handle, + WMI_AP_PS_EGAP_INFO_EVENTID, + wma_egap_info_status_event, + WMA_RX_SERIALIZER_CTX); + if (QDF_IS_STATUS_ERROR(status)) { + WMA_LOGE("Failed to register Enhance Green AP event"); + wma_handle->egap_support = false; + } else { + WMA_LOGI("Set the Enhance Green AP event handler"); + wma_handle->egap_support = true; + } + } else + wma_handle->egap_support = false; +} +#endif /* FEATURE_GREEN_AP */ + +/** + * wma_unified_fw_profiling_cmd() - send FW profiling cmd to WLAN FW + * @wma: wma handle + * @cmd: Profiling command index + * @value1: parameter1 value + * @value2: parameter2 value + * + * Return: 0 for success else error code + */ +QDF_STATUS wma_unified_fw_profiling_cmd(wmi_unified_t wmi_handle, + uint32_t cmd, uint32_t value1, uint32_t value2) +{ + int ret; + + ret = wmi_unified_fw_profiling_data_cmd(wmi_handle, cmd, + value1, value2); + if (ret) { + WMA_LOGE("enable cmd Failed for id %d value %d", + value1, value2); + return ret; + } + + return QDF_STATUS_SUCCESS; +} + +#ifdef FEATURE_WLAN_LPHB +/** + * wma_lphb_handler() - send LPHB indication to SME + * @wma: wma handle + * @event: event handler + * + * Return: 0 for success or error code + */ +static int wma_lphb_handler(tp_wma_handle wma, uint8_t *event) +{ + wmi_hb_ind_event_fixed_param *hb_fp; + tSirLPHBInd *slphb_indication; + QDF_STATUS qdf_status; + cds_msg_t sme_msg = { 0 }; + + hb_fp = (wmi_hb_ind_event_fixed_param *) event; + if (!hb_fp) { + WMA_LOGE("Invalid wmi_hb_ind_event_fixed_param buffer"); + return -EINVAL; + } + + WMA_LOGD("lphb indication received with vdev_id=%d, session=%d, reason=%d", + hb_fp->vdev_id, hb_fp->session, hb_fp->reason); + + slphb_indication = (tSirLPHBInd *) qdf_mem_malloc(sizeof(tSirLPHBInd)); + + if (!slphb_indication) { + WMA_LOGE("Invalid LPHB indication buffer"); + return -ENOMEM; + } + + slphb_indication->sessionIdx = hb_fp->session; + slphb_indication->protocolType = hb_fp->reason; + slphb_indication->eventReason = hb_fp->reason; + + sme_msg.type = eWNI_SME_LPHB_IND; + sme_msg.bodyptr = slphb_indication; + sme_msg.bodyval = 0; + + qdf_status = cds_mq_post_message(QDF_MODULE_ID_SME, &sme_msg); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + WMA_LOGE("Fail to post eWNI_SME_LPHB_IND msg to SME"); + qdf_mem_free(slphb_indication); + return -EINVAL; + } + + return 0; +} +#endif /* FEATURE_WLAN_LPHB */ + +#ifdef FEATURE_WLAN_RA_FILTERING +/** + * wma_wow_sta_ra_filter() - set RA filter pattern in fw + * @wma: wma handle + * @vdev_id: vdev id + * + * Return: QDF status + */ +static QDF_STATUS wma_wow_sta_ra_filter(tp_wma_handle wma, uint8_t vdev_id) +{ + + struct wma_txrx_node *iface; + int ret; + uint8_t default_pattern; + + iface = &wma->interfaces[vdev_id]; + + default_pattern = iface->num_wow_default_patterns++; + + WMA_LOGD("%s: send RA rate limit [%d] to fw vdev = %d", __func__, + wma->RArateLimitInterval, vdev_id); + + ret = wmi_unified_wow_sta_ra_filter_cmd(wma->wmi_handle, vdev_id, + default_pattern, wma->RArateLimitInterval); + if (ret) { + WMA_LOGE("%s: Failed to send RA rate limit to fw", __func__); + iface->num_wow_default_patterns--; + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; + +} +#endif /* FEATURE_WLAN_RA_FILTERING */ + +/** + * wmi_unified_nat_keepalive_enable() - enable NAT keepalive filter + * @wma: wma handle + * @vdev_id: vdev id + * + * Return: 0 for success or error code + */ +int wmi_unified_nat_keepalive_enable(tp_wma_handle wma, uint8_t vdev_id) +{ + + if (wmi_unified_nat_keepalive_en_cmd(wma->wmi_handle, vdev_id)) + return QDF_STATUS_E_FAILURE; + + return QDF_STATUS_SUCCESS; +} + +/** + * wma_unified_csa_offload_enable() - sen CSA offload enable command + * @wma: wma handle + * @vdev_id: vdev id + * + * Return: 0 for success or error code + */ +int wma_unified_csa_offload_enable(tp_wma_handle wma, uint8_t vdev_id) +{ + if (wmi_unified_csa_offload_enable(wma->wmi_handle, + vdev_id)) { + WMA_LOGP("%s: Failed to send CSA offload enable command", + __func__); + return -EIO; + } + + return 0; +} + +#ifdef WLAN_FEATURE_NAN +/** + * wma_nan_rsp_event_handler() - Function is used to handle nan response + * @handle: wma handle + * @event_buf: event buffer + * @len: length of buffer + * + * Return: 0 for success or error code + */ +int wma_nan_rsp_event_handler(void *handle, uint8_t *event_buf, + uint32_t len) +{ + WMI_NAN_EVENTID_param_tlvs *param_buf; + tSirNanEvent *nan_rsp_event; + wmi_nan_event_hdr *nan_rsp_event_hdr; + QDF_STATUS status; + cds_msg_t cds_msg; + uint8_t *buf_ptr; + uint32_t alloc_len; + + /* + * This is how received event_buf looks like + * + * <-------------------- event_buf -----------------------------------> + * + * <--wmi_nan_event_hdr--><---WMI_TLV_HDR_SIZE---><----- data --------> + * + * +-----------+---------+-----------------------+--------------------+ + * | tlv_header| data_len| WMITLV_TAG_ARRAY_BYTE | nan_rsp_event_data | + * +-----------+---------+-----------------------+--------------------+ + */ + + WMA_LOGD("%s: Posting NaN response event to SME", __func__); + param_buf = (WMI_NAN_EVENTID_param_tlvs *) event_buf; + if (!param_buf) { + WMA_LOGE("%s: Invalid nan response event buf", __func__); + return -EINVAL; + } + nan_rsp_event_hdr = param_buf->fixed_param; + buf_ptr = (uint8_t *) nan_rsp_event_hdr; + alloc_len = sizeof(tSirNanEvent); + alloc_len += nan_rsp_event_hdr->data_len; + nan_rsp_event = (tSirNanEvent *) qdf_mem_malloc(alloc_len); + if (NULL == nan_rsp_event) { + WMA_LOGE("%s: Memory allocation failure", __func__); + return -ENOMEM; + } + + nan_rsp_event->event_data_len = nan_rsp_event_hdr->data_len; + qdf_mem_copy(nan_rsp_event->event_data, buf_ptr + + sizeof(wmi_nan_event_hdr) + WMI_TLV_HDR_SIZE, + nan_rsp_event->event_data_len); + cds_msg.type = eWNI_SME_NAN_EVENT; + cds_msg.bodyptr = (void *)nan_rsp_event; + cds_msg.bodyval = 0; + + status = cds_mq_post_message(CDS_MQ_ID_SME, &cds_msg); + if (status != QDF_STATUS_SUCCESS) { + WMA_LOGE("%s: Failed to post NaN response event to SME", + __func__); + qdf_mem_free(nan_rsp_event); + return -EFAULT; + } + WMA_LOGD("%s: NaN response event Posted to SME", __func__); + return 0; +} +#else +static int wma_nan_rsp_event_handler(void *handle, uint8_t *event_buf, + uint32_t len) +{ + return 0; +} +#endif /* WLAN_FEATURE_NAN */ + +/** + * wma_csa_offload_handler() - CSA event handler + * @handle: wma handle + * @event: event buffer + * @len: buffer length + * + * This event is sent by firmware when it receives CSA IE. + * + * Return: 0 for success or error code + */ +int wma_csa_offload_handler(void *handle, uint8_t *event, uint32_t len) +{ + tp_wma_handle wma = (tp_wma_handle) handle; + WMI_CSA_HANDLING_EVENTID_param_tlvs *param_buf; + wmi_csa_event_fixed_param *csa_event; + uint8_t bssid[IEEE80211_ADDR_LEN]; + uint8_t vdev_id = 0; + uint8_t cur_chan = 0; + struct ieee80211_channelswitch_ie *csa_ie; + struct csa_offload_params *csa_offload_event; + struct ieee80211_extendedchannelswitch_ie *xcsa_ie; + struct ieee80211_ie_wide_bw_switch *wb_ie; + struct wma_txrx_node *intr = wma->interfaces; + + param_buf = (WMI_CSA_HANDLING_EVENTID_param_tlvs *) event; + + WMA_LOGD("%s: Enter", __func__); + if (!param_buf) { + WMA_LOGE("Invalid csa event buffer"); + return -EINVAL; + } + csa_event = param_buf->fixed_param; + WMI_MAC_ADDR_TO_CHAR_ARRAY(&csa_event->i_addr2, &bssid[0]); + + if (wma_find_vdev_by_bssid(wma, bssid, &vdev_id) == NULL) { + WMA_LOGE("Invalid bssid received %s:%d", __func__, __LINE__); + return -EINVAL; + } + + csa_offload_event = qdf_mem_malloc(sizeof(*csa_offload_event)); + if (!csa_offload_event) { + WMA_LOGE("QDF MEM Alloc Failed for csa_offload_event"); + return -EINVAL; + } + + qdf_mem_zero(csa_offload_event, sizeof(*csa_offload_event)); + qdf_mem_copy(csa_offload_event->bssId, &bssid, IEEE80211_ADDR_LEN); + + if (csa_event->ies_present_flag & WMI_CSA_IE_PRESENT) { + csa_ie = (struct ieee80211_channelswitch_ie *) + (&csa_event->csa_ie[0]); + csa_offload_event->channel = csa_ie->newchannel; + csa_offload_event->switch_mode = csa_ie->switchmode; + } else if (csa_event->ies_present_flag & WMI_XCSA_IE_PRESENT) { + xcsa_ie = (struct ieee80211_extendedchannelswitch_ie *) + (&csa_event->xcsa_ie[0]); + csa_offload_event->channel = xcsa_ie->newchannel; + csa_offload_event->switch_mode = xcsa_ie->switchmode; + csa_offload_event->new_op_class = xcsa_ie->newClass; + } else { + WMA_LOGE("CSA Event error: No CSA IE present"); + qdf_mem_free(csa_offload_event); + return -EINVAL; + } + + if (csa_event->ies_present_flag & WMI_WBW_IE_PRESENT) { + wb_ie = (struct ieee80211_ie_wide_bw_switch *) + (&csa_event->wb_ie[0]); + csa_offload_event->new_ch_width = wb_ie->new_ch_width; + csa_offload_event->new_ch_freq_seg1 = wb_ie->new_ch_freq_seg1; + csa_offload_event->new_ch_freq_seg2 = wb_ie->new_ch_freq_seg2; + } + + csa_offload_event->ies_present_flag = csa_event->ies_present_flag; + + WMA_LOGD("CSA: New Channel = %d BSSID:%pM", + csa_offload_event->channel, csa_offload_event->bssId); + + cur_chan = cds_freq_to_chan(intr[vdev_id].mhz); + /* + * basic sanity check: requested channel should not be 0 + * and equal to home channel + */ + if (0 == csa_offload_event->channel) { + WMA_LOGE("CSA Event with channel %d. Ignore !!", + csa_offload_event->channel); + qdf_mem_free(csa_offload_event); + return -EINVAL; + } + wma->interfaces[vdev_id].is_channel_switch = true; + wma_send_msg(wma, WMA_CSA_OFFLOAD_EVENT, (void *)csa_offload_event, 0); + return 0; +} + +#ifdef FEATURE_OEM_DATA_SUPPORT +/** + * wma_oem_data_response_handler() - OEM data response event handler + * @handle: wma handle + * @datap: data ptr + * @len: data length + * + * Return: 0 for success or error code + */ +int wma_oem_data_response_handler(void *handle, + uint8_t *datap, uint32_t len) +{ + WMI_OEM_RESPONSE_EVENTID_param_tlvs *param_buf; + uint8_t *data; + uint32_t datalen; + struct oem_data_rsp *oem_rsp; + tpAniSirGlobal pmac = cds_get_context(QDF_MODULE_ID_PE); + + if (!pmac) { + WMA_LOGE(FL("Invalid pmac")); + return -EINVAL; + } + + if (!pmac->sme.oem_data_rsp_callback) { + WMA_LOGE(FL("Callback not registered")); + return -EINVAL; + } + + param_buf = (WMI_OEM_RESPONSE_EVENTID_param_tlvs *) datap; + if (!param_buf) { + WMA_LOGE(FL("Received NULL buf ptr from FW")); + return -ENOMEM; + } + + data = param_buf->data; + datalen = param_buf->num_data; + + if (!data) { + WMA_LOGE(FL("Received NULL data from FW")); + return -EINVAL; + } + + if (datalen > OEM_DATA_RSP_SIZE) { + WMA_LOGE(FL("Received data len %d exceeds max value %d"), + datalen, OEM_DATA_RSP_SIZE); + return -EINVAL; + } + + oem_rsp = qdf_mem_malloc(sizeof(*oem_rsp)); + if (!oem_rsp) { + WMA_LOGE(FL("Failed to alloc oem_data_rsp")); + return -ENOMEM; + } + oem_rsp->rsp_len = datalen; + if (oem_rsp->rsp_len) { + oem_rsp->data = qdf_mem_malloc(oem_rsp->rsp_len); + if (!oem_rsp->data) { + WMA_LOGE(FL("malloc failed for data")); + qdf_mem_free(oem_rsp); + return -ENOMEM; + } + } else { + WMA_LOGE(FL("Invalid rsp length: %d"), + oem_rsp->rsp_len); + qdf_mem_free(oem_rsp); + return -EINVAL; + } + + qdf_mem_copy(oem_rsp->data, data, datalen); + + WMA_LOGI(FL("Sending OEM_DATA_RSP(len: %d) to upper layer"), datalen); + + pmac->sme.oem_data_rsp_callback(oem_rsp); + + if (oem_rsp->data) + qdf_mem_free(oem_rsp->data); + qdf_mem_free(oem_rsp); + + return 0; +} + +/** + * wma_start_oem_data_req() - start OEM data request to target + * @wma_handle: wma handle + * @oem_data_req: start request params + * + * Return: QDF_STATUS + */ +QDF_STATUS wma_start_oem_data_req(tp_wma_handle wma_handle, + struct oem_data_req *oem_data_req) +{ + int ret = 0; + + WMA_LOGD(FL("Send OEM Data Request to target")); + + if (!oem_data_req || !oem_data_req->data) { + WMA_LOGE(FL("oem_data_req is null")); + return QDF_STATUS_E_INVAL; + } + + if (!wma_handle || !wma_handle->wmi_handle) { + WMA_LOGE(FL("WMA - closed, can not send Oem data request cmd")); + qdf_mem_free(oem_data_req->data); + return QDF_STATUS_E_INVAL; + } + + ret = wmi_unified_start_oem_data_cmd(wma_handle->wmi_handle, + oem_data_req->data_len, + oem_data_req->data); + + if (!QDF_IS_STATUS_SUCCESS(ret)) + WMA_LOGE(FL("wmi cmd send failed")); + + return ret; +} +#endif /* FEATURE_OEM_DATA_SUPPORT */ + + +/** + * wma_unified_dfs_radar_rx_event_handler() - dfs radar rx event handler + * @handle: wma handle + * @data: data buffer + * @datalen: data length + * + * WMI handler for WMI_DFS_RADAR_EVENTID + * This handler is registered for handling + * filtered DFS Phyerror. This handler is + * will be invoked only when DFS Phyerr + * filtering offload is enabled. + * + * Return: 1 for Success and 0 for error + */ +static int wma_unified_dfs_radar_rx_event_handler(void *handle, + uint8_t *data, + uint32_t datalen) +{ + tp_wma_handle wma = (tp_wma_handle) handle; + struct ieee80211com *ic; + struct ath_dfs *dfs; + struct dfs_event *event; + struct dfs_ieee80211_channel *chan; + int empty; + int do_check_chirp = 0; + int is_hw_chirp = 0; + int is_sw_chirp = 0; + int is_pri = 0; + bool is_ch_dfs = false; + + WMI_DFS_RADAR_EVENTID_param_tlvs *param_tlvs; + wmi_dfs_radar_event_fixed_param *radar_event; + + ic = wma->dfs_ic; + if (NULL == ic) { + WMA_LOGE("%s: dfs_ic is NULL ", __func__); + return 0; + } + + dfs = (struct ath_dfs *)ic->ic_dfs; + param_tlvs = (WMI_DFS_RADAR_EVENTID_param_tlvs *) data; + + if (NULL == dfs) { + WMA_LOGE("%s: dfs is NULL ", __func__); + return 0; + } + /* + * This parameter holds the number + * of phyerror interrupts to the host + * after the phyerrors have passed through + * false detect filters in the firmware. + */ + dfs->dfs_phyerr_count++; + + if (!param_tlvs) { + WMA_LOGE("%s: Received NULL data from FW", __func__); + return 0; + } + + radar_event = param_tlvs->fixed_param; + + qdf_spin_lock_bh(&ic->chan_lock); + chan = ic->ic_curchan; + if (ic->disable_phy_err_processing) { + WMA_LOGD("%s: radar indication done,drop phyerror event", + __func__); + qdf_spin_unlock_bh(&ic->chan_lock); + return 0; + } + + if (IEEE80211_IS_CHAN_11AC_VHT160(chan)) { + is_ch_dfs = true; + } else if (IEEE80211_IS_CHAN_11AC_VHT80P80(chan)) { + if (cds_get_channel_state(chan->ic_ieee) == CHANNEL_STATE_DFS || + cds_get_channel_state(chan->ic_ieee_ext - + WMA_80MHZ_START_CENTER_CH_DIFF) == + CHANNEL_STATE_DFS) + is_ch_dfs = true; + } else { + if (cds_get_channel_state(chan->ic_ieee) == CHANNEL_STATE_DFS) + is_ch_dfs = true; + } + if (!is_ch_dfs) { + WMA_LOGE + ("%s: Invalid DFS Phyerror event. Channel=%d is Non-DFS", + __func__, chan->ic_ieee); + qdf_spin_unlock_bh(&ic->chan_lock); + return 0; + } + + qdf_spin_unlock_bh(&ic->chan_lock); + dfs->ath_dfs_stats.total_phy_errors++; + + if (dfs->dfs_caps.ath_chip_is_bb_tlv) { + do_check_chirp = 1; + is_pri = 1; + is_hw_chirp = radar_event->pulse_is_chirp; + + if ((uint32_t) dfs->dfs_phyerr_freq_min > + radar_event->pulse_center_freq) { + dfs->dfs_phyerr_freq_min = + (int)radar_event->pulse_center_freq; + } + + if (dfs->dfs_phyerr_freq_max < + (int)radar_event->pulse_center_freq) { + dfs->dfs_phyerr_freq_max = + (int)radar_event->pulse_center_freq; + } + } + + /* + * Now, add the parsed, checked and filtered + * radar phyerror event radar pulse event list. + * This event will then be processed by + * dfs_radar_processevent() to see if the pattern + * of pulses in radar pulse list match any radar + * singnature in the current regulatory domain. + */ + + ATH_DFSEVENTQ_LOCK(dfs); + empty = STAILQ_EMPTY(&(dfs->dfs_eventq)); + ATH_DFSEVENTQ_UNLOCK(dfs); + if (empty) { + return 0; + } + /* + * Add the event to the list, if there's space. + */ + ATH_DFSEVENTQ_LOCK(dfs); + event = STAILQ_FIRST(&(dfs->dfs_eventq)); + if (event == NULL) { + ATH_DFSEVENTQ_UNLOCK(dfs); + WMA_LOGE("%s: No more space left for queuing DFS Phyerror events", + __func__); + return 0; + } + STAILQ_REMOVE_HEAD(&(dfs->dfs_eventq), re_list); + ATH_DFSEVENTQ_UNLOCK(dfs); + dfs->dfs_phyerr_queued_count++; + dfs->dfs_phyerr_w53_counter++; + event->re_dur = (uint8_t) radar_event->pulse_duration; + event->re_rssi = radar_event->rssi; + event->re_ts = radar_event->pulse_detect_ts & DFS_TSMASK; + event->re_full_ts = (((uint64_t) radar_event->upload_fullts_high) << 32) + | radar_event->upload_fullts_low; + + /* + * Index of peak magnitude + */ + event->sidx = radar_event->peak_sidx; + event->re_flags = 0; + + /* + * Handle chirp flags. + */ + if (do_check_chirp) { + event->re_flags |= DFS_EVENT_CHECKCHIRP; + if (is_hw_chirp) { + event->re_flags |= DFS_EVENT_HW_CHIRP; + } + if (is_sw_chirp) { + event->re_flags |= DFS_EVENT_SW_CHIRP; + } + } + /* + * Correctly set which channel is being reported on + */ + if (is_pri) { + event->re_chanindex = (uint8_t) dfs->dfs_curchan_radindex; + } else { + if (dfs->dfs_extchan_radindex == -1) { + WMA_LOGI("%s phyerr on ext channel", __func__); + } + event->re_chanindex = (uint8_t) dfs->dfs_extchan_radindex; + WMA_LOGI("%s:New extension channel event is added to queue", + __func__); + } + + ATH_DFSQ_LOCK(dfs); + + STAILQ_INSERT_TAIL(&(dfs->dfs_radarq), event, re_list); + + empty = STAILQ_EMPTY(&dfs->dfs_radarq); + + ATH_DFSQ_UNLOCK(dfs); + + if (!empty && !dfs->ath_radar_tasksched) { + dfs->ath_radar_tasksched = 1; + OS_SET_TIMER(&dfs->ath_dfs_task_timer, 0); + } + + return 1; + +} + +/** + * wma_unified_phyerr_rx_event_handler() - phyerr event handler + * @handle: wma handle + * @data: data buffer + * @datalen: buffer length + * + * WMI Handler for WMI_PHYERR_EVENTID event from firmware. + * This handler is currently handling only DFS phy errors. + * This handler will be invoked only when the DFS phyerror + * filtering offload is disabled. + * + * Return: 1:Success, 0:Failure + */ +static int wma_unified_phyerr_rx_event_handler(void *handle, + uint8_t *data, uint32_t datalen) +{ + tp_wma_handle wma = (tp_wma_handle) handle; + WMI_PHYERR_EVENTID_param_tlvs *param_tlvs; + wmi_comb_phyerr_rx_hdr *pe_hdr; + uint8_t *bufp; + wmi_single_phyerr_rx_event *ev; + struct ieee80211com *ic = wma->dfs_ic; + qdf_size_t n; + A_UINT64 tsf64 = 0; + int phy_err_code = 0; + A_UINT32 phy_err_mask = 0; + int error = 0; + tpAniSirGlobal mac_ctx = + (tpAniSirGlobal)cds_get_context(QDF_MODULE_ID_PE); + bool enable_log = false; + int max_dfs_buf_length = 0; + + if (NULL == mac_ctx) { + WMA_LOGE("%s: mac_ctx is NULL", __func__); + return 0; + } + enable_log = mac_ctx->sap.enable_dfs_phy_error_logs; + + param_tlvs = (WMI_PHYERR_EVENTID_param_tlvs *) data; + + if (!param_tlvs) { + WMA_LOGE("%s: Received NULL data from FW", __func__); + return 0; + } + + pe_hdr = param_tlvs->hdr; + if (pe_hdr == NULL) { + WMA_LOGE("%s: Received Data PE Header is NULL", __func__); + return 0; + } + + /* Ensure it's at least the size of the header */ + if (datalen < sizeof(*pe_hdr)) { + WMA_LOGE("%s: Expected minimum size %zu, received %d", + __func__, sizeof(*pe_hdr), datalen); + return 0; + } + /* + * The max buffer lenght is larger for DFS-3 than DFS-2. + * So, accordingly use the correct max buffer size. + */ + if (wma->hw_bd_id != WMI_HWBD_QCA6174) + max_dfs_buf_length = DFS3_MAX_BUF_LENGTH; + else + max_dfs_buf_length = DFS_MAX_BUF_LENGTH; + + if (pe_hdr->buf_len > max_dfs_buf_length) { + WMA_LOGE("%s: Received Invalid Phyerror event buffer length = %d" + "Maximum allowed buf length = %d", __func__, + pe_hdr->buf_len, max_dfs_buf_length); + + return 0; + } + + /* + * Reconstruct the 64 bit event TSF. This isn't from the MAC, it's + * at the time the event was sent to us, the TSF value will be + * in the future. + */ + tsf64 = pe_hdr->tsf_l32; + tsf64 |= (((uint64_t) pe_hdr->tsf_u32) << 32); + + /* + * Check the HW board ID to figure out + * if DFS-3 is supported. In DFS-3 + * phyerror mask indicates the type of + * phyerror, whereas in DFS-2 phyerrorcode + * indicates the type of phyerror. If the + * board is NOT WMI_HWBD_QCA6174, for now + * assume that it supports DFS-3. + */ + if (wma->hw_bd_id != WMI_HWBD_QCA6174) { + phy_err_mask = pe_hdr->rsPhyErrMask0; + WMA_LOGD("%s: DFS-3 phyerror mask = 0x%x", + __func__, phy_err_mask); + } + + /* + * Loop over the bufp, extracting out phyerrors + * wmi_unified_comb_phyerr_rx_event.bufp is a char pointer, + * which isn't correct here - what we have received here + * is an array of TLV-style PHY errors. + */ + n = 0; /* Start just after the header */ + bufp = param_tlvs->bufp; + while (n < pe_hdr->buf_len) { + /* ensure there's at least space for the header */ + if ((pe_hdr->buf_len - n) < sizeof(ev->hdr)) { + WMA_LOGE("%s: Not enough space.(datalen=%d, n=%zu, hdr=%zu bytes", + __func__, pe_hdr->buf_len, n, sizeof(ev->hdr)); + error = 1; + break; + } + /* + * Obtain a pointer to the beginning of the current event. + * data[0] is the beginning of the WMI payload. + */ + ev = (wmi_single_phyerr_rx_event *) &bufp[n]; + + /* + * Sanity check the buffer length of the event against + * what we currently have. + * Since buf_len is 32 bits, we check if it overflows + * a large 32 bit value. It's not 0x7fffffff because + * we increase n by (buf_len + sizeof(hdr)), which would + * in itself cause n to overflow. + * If "int" is 64 bits then this becomes a moot point. + */ + if (ev->hdr.buf_len > 0x7f000000) { + WMA_LOGE("%s:buf_len is garbage (0x%x)", __func__, + ev->hdr.buf_len); + error = 1; + break; + } + if (n + ev->hdr.buf_len > pe_hdr->buf_len) { + WMA_LOGE("%s: buf_len exceeds available space n=%zu," + "buf_len=%d, datalen=%d", + __func__, n, ev->hdr.buf_len, pe_hdr->buf_len); + error = 1; + break; + } + /* + * If the board id is WMI_HWBD_QCA6174 + * then it supports only DFS-2. So, fetch + * phyerror code in order to know the type + * of phyerror. + */ + if (wma->hw_bd_id == WMI_HWBD_QCA6174) { + phy_err_code = WMI_UNIFIED_PHYERRCODE_GET(&ev->hdr); + WMA_LOGD("%s: DFS-2 phyerror code = 0x%x", + __func__, phy_err_code); + } + + /* + * phy_err_code is set for DFS-2 and phy_err_mask + * is set for DFS-3. Checking both to support + * compatability for older platforms. + * If the phyerror or phyerrmask category matches, + * pass radar events to the dfs pattern matching code. + * Don't pass radar events with no buffer payload. + */ + if (((phy_err_mask & WMI_PHY_ERROR_MASK0_RADAR) || + (phy_err_mask & WMI_PHY_ERROR_MASK0_FALSE_RADAR_EXT)) || + (phy_err_code == WMA_DFS2_PHYERROR_CODE || + phy_err_code == WMA_DFS2_FALSE_RADAR_EXT)) { + if (ev->hdr.buf_len > 0) { + /* Calling in to the DFS module to process the phyerr */ + dfs_process_phyerr(ic, &ev->bufp[0], + ev->hdr.buf_len, + WMI_UNIFIED_RSSI_COMB_GET + (&ev->hdr) & 0xff, + /* Extension RSSI */ + WMI_UNIFIED_RSSI_COMB_GET + (&ev->hdr) & 0xff, + ev->hdr.tsf_timestamp, + tsf64, enable_log); + } + } + + /* + * Advance the buffer pointer to the next PHY error. + * buflen is the length of this payload, so we need to + * advance past the current header _AND_ the payload. + */ + n += sizeof(*ev) + ev->hdr.buf_len; + + } /*end while() */ + if (error) + return 0; + else + return 1; +} + +/** + * wma_register_dfs_event_handler() - register dfs event handler + * @wma_handle: wma handle + * + * Register appropriate dfs phyerror event handler + * based on phyerror filtering offload is enabled + * or disabled. + * + * Return: none + */ +void wma_register_dfs_event_handler(tp_wma_handle wma_handle) +{ + if (NULL == wma_handle) { + WMA_LOGE("%s:wma_handle is NULL", __func__); + return; + } + + if (false == wma_handle->dfs_phyerr_filter_offload) { + /* + * Register the wma_unified_phyerr_rx_event_handler + * for filtering offload disabled case to handle + * the DFS phyerrors. + */ + WMA_LOGD("%s:Phyerror Filtering offload is Disabled in ini", + __func__); + wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_PHYERR_EVENTID, + wma_unified_phyerr_rx_event_handler, + WMA_RX_WORK_CTX); + WMA_LOGD("%s: WMI_PHYERR_EVENTID event handler registered", + __func__); + } else { + WMA_LOGD("%s:Phyerror Filtering offload is Enabled in ini", + __func__); + wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_DFS_RADAR_EVENTID, + wma_unified_dfs_radar_rx_event_handler, + WMA_RX_WORK_CTX); + WMA_LOGD("%s:WMI_DFS_RADAR_EVENTID event handler registered", + __func__); + } + + return; +} + +/** + * wma_unified_dfs_phyerr_filter_offload_enable() - enable dfs phyerr filter + * @wma_handle: wma handle + * + * Send WMI_DFS_PHYERR_FILTER_ENA_CMDID or + * WMI_DFS_PHYERR_FILTER_DIS_CMDID command + * to firmware based on phyerr filtering + * offload status. + * + * Return: 1 success, 0 failure + */ +int +wma_unified_dfs_phyerr_filter_offload_enable(tp_wma_handle wma_handle) +{ + int ret; + + if (NULL == wma_handle) { + WMA_LOGE("%s:wma_handle is NULL", __func__); + return 0; + } + + ret = wmi_unified_dfs_phyerr_filter_offload_en_cmd(wma_handle->wmi_handle, + wma_handle->dfs_phyerr_filter_offload); + if (ret) + return QDF_STATUS_E_FAILURE; + + + return QDF_STATUS_SUCCESS; +} + +#if !defined(REMOVE_PKT_LOG) +/** + * wma_pktlog_wmi_send_cmd() - send pktlog enable/disable command to target + * @handle: wma handle + * @params: pktlog params + * + * Return: QDF status + */ +QDF_STATUS wma_pktlog_wmi_send_cmd(WMA_HANDLE handle, + struct ath_pktlog_wmi_params *params) +{ + tp_wma_handle wma_handle = (tp_wma_handle) handle; + int ret; + + ret = wmi_unified_pktlog_wmi_send_cmd(wma_handle->wmi_handle, + params->pktlog_event, + params->cmd_id, params->user_triggered); + if (ret) + return QDF_STATUS_E_FAILURE; + + return QDF_STATUS_SUCCESS; +} +#endif /* REMOVE_PKT_LOG */ + +static void wma_send_status_to_suspend_ind(tp_wma_handle wma, bool suspended) +{ + tSirReadyToSuspendInd *ready_to_suspend; + QDF_STATUS status; + cds_msg_t cds_msg; + uint8_t len; + + WMA_LOGD("Posting ready to suspend indication to umac"); + + len = sizeof(tSirReadyToSuspendInd); + ready_to_suspend = (tSirReadyToSuspendInd *) qdf_mem_malloc(len); + + if (NULL == ready_to_suspend) { + WMA_LOGE("%s: Memory allocation failure", __func__); + return; + } + + ready_to_suspend->mesgType = eWNI_SME_READY_TO_SUSPEND_IND; + ready_to_suspend->mesgLen = len; + ready_to_suspend->suspended = suspended; + + cds_msg.type = eWNI_SME_READY_TO_SUSPEND_IND; + cds_msg.bodyptr = (void *)ready_to_suspend; + cds_msg.bodyval = 0; + + status = cds_mq_post_message(CDS_MQ_ID_SME, &cds_msg); + if (status != QDF_STATUS_SUCCESS) { + WMA_LOGE("Failed to post ready to suspend"); + qdf_mem_free(ready_to_suspend); + } +} + +/** + * wma_wow_wake_reason_str() - Converts wow wakeup reason code to text format + * @wake_reason - WOW wake reason + * + * Return: reason code in string format + */ +static const u8 *wma_wow_wake_reason_str(A_INT32 wake_reason) +{ + switch (wake_reason) { + case WOW_REASON_UNSPECIFIED: + return "UNSPECIFIED"; + case WOW_REASON_NLOD: + return "NLOD"; + case WOW_REASON_AP_ASSOC_LOST: + return "AP_ASSOC_LOST"; + case WOW_REASON_LOW_RSSI: + return "LOW_RSSI"; + case WOW_REASON_DEAUTH_RECVD: + return "DEAUTH_RECVD"; + case WOW_REASON_DISASSOC_RECVD: + return "DISASSOC_RECVD"; + case WOW_REASON_GTK_HS_ERR: + return "GTK_HS_ERR"; + case WOW_REASON_EAP_REQ: + return "EAP_REQ"; + case WOW_REASON_FOURWAY_HS_RECV: + return "FOURWAY_HS_RECV"; + case WOW_REASON_TIMER_INTR_RECV: + return "TIMER_INTR_RECV"; + case WOW_REASON_PATTERN_MATCH_FOUND: + return "PATTERN_MATCH_FOUND"; + case WOW_REASON_RECV_MAGIC_PATTERN: + return "RECV_MAGIC_PATTERN"; + case WOW_REASON_P2P_DISC: + return "P2P_DISC"; + case WOW_REASON_WLAN_HB: + return "WLAN_HB"; + case WOW_REASON_CSA_EVENT: + return "CSA_EVENT"; + case WOW_REASON_PROBE_REQ_WPS_IE_RECV: + return "PROBE_REQ_WPS_IE_RECV"; + case WOW_REASON_AUTH_REQ_RECV: + return "AUTH_REQ_RECV"; + case WOW_REASON_ASSOC_REQ_RECV: + return "ASSOC_REQ_RECV"; + case WOW_REASON_HTT_EVENT: + return "HTT_EVENT"; + case WOW_REASON_RA_MATCH: + return "RA_MATCH"; + case WOW_REASON_HOST_AUTO_SHUTDOWN: + return "HOST_AUTO_SHUTDOWN"; + case WOW_REASON_IOAC_MAGIC_EVENT: + return "IOAC_MAGIC_EVENT"; + case WOW_REASON_IOAC_SHORT_EVENT: + return "IOAC_SHORT_EVENT"; + case WOW_REASON_IOAC_EXTEND_EVENT: + return "IOAC_EXTEND_EVENT"; + case WOW_REASON_IOAC_TIMER_EVENT: + return "IOAC_TIMER_EVENT"; + case WOW_REASON_ROAM_HO: + return "ROAM_HO"; + case WOW_REASON_DFS_PHYERR_RADADR_EVENT: + return "DFS_PHYERR_RADADR_EVENT"; + case WOW_REASON_BEACON_RECV: + return "BEACON_RECV"; + case WOW_REASON_CLIENT_KICKOUT_EVENT: + return "CLIENT_KICKOUT_EVENT"; + case WOW_REASON_NAN_EVENT: + return "NAN_EVENT"; + case WOW_REASON_EXTSCAN: + return "EXTSCAN"; + case WOW_REASON_RSSI_BREACH_EVENT: + return "RSSI_BREACH_EVENT"; + case WOW_REASON_IOAC_REV_KA_FAIL_EVENT: + return "IOAC_REV_KA_FAIL_EVENT"; + case WOW_REASON_IOAC_SOCK_EVENT: + return "IOAC_SOCK_EVENT"; + case WOW_REASON_NLO_SCAN_COMPLETE: + return "NLO_SCAN_COMPLETE"; + case WOW_REASON_PACKET_FILTER_MATCH: + return "PACKET_FILTER_MATCH"; + case WOW_REASON_ASSOC_RES_RECV: + return "ASSOC_RES_RECV"; + case WOW_REASON_REASSOC_REQ_RECV: + return "REASSOC_REQ_RECV"; + case WOW_REASON_REASSOC_RES_RECV: + return "REASSOC_RES_RECV"; + case WOW_REASON_ACTION_FRAME_RECV: + return "ACTION_FRAME_RECV"; + case WOW_REASON_BPF_ALLOW: + return "BPF_ALLOW"; + case WOW_REASON_NAN_DATA: + return "NAN_DATA"; + case WOW_REASON_OEM_RESPONSE_EVENT: + return "OEM_RESPONSE_EVENT"; + case WOW_REASON_TDLS_CONN_TRACKER_EVENT: + return "TDLS_CONN_TRACKER_EVENT"; + case WOW_REASON_CRITICAL_LOG: + return "CRITICAL_LOG"; + case WOW_REASON_P2P_LISTEN_OFFLOAD: + return "P2P_LISTEN_OFFLOAD"; + case WOW_REASON_NAN_EVENT_WAKE_HOST: + return "NAN_EVENT_WAKE_HOST"; + case WOW_REASON_DEBUG_TEST: + return "DEBUG_TEST"; + case WOW_REASON_CHIP_POWER_FAILURE_DETECT: + return "CHIP_POWER_FAILURE_DETECT"; + default: + return "unknown"; + } +} + +/** + * wma_wow_stats_display() - display wow wake up stats + * @stats: per vdev stats counters + * + * Return: none + */ +static void wma_wow_stats_display(struct sir_vdev_wow_stats *stats) +{ + WMA_LOGA("uc %d bc %d v4_mc %d v6_mc %d ra %d ns %d na %d pno_match %d pno_complete %d gscan %d low_rssi %d rssi_breach %d icmp %d icmpv6 %d oem %d", + stats->ucast, + stats->bcast, + stats->ipv4_mcast, + stats->ipv6_mcast, + stats->ipv6_mcast_ra, + stats->ipv6_mcast_ns, + stats->ipv6_mcast_na, + stats->pno_match, + stats->pno_complete, + stats->gscan, + stats->low_rssi, + stats->rssi_breach, + stats->icmpv4, + stats->icmpv6, + stats->oem_response); +} + +/** + * wma_wow_ipv6_mcast_stats() - ipv6 mcast wake up stats + * @stats: per vdev stats counters + * @data: Pointer to pattern match data + * + * Return: none + */ +static void wma_wow_ipv6_mcast_stats(struct sir_vdev_wow_stats *stats, + uint8_t *data) +{ + static const uint8_t ipv6_ether_type[] = {0x86, 0xDD}; + + if (!memcmp(ipv6_ether_type, (data + WMA_ETHER_TYPE_OFFSET), + sizeof(ipv6_ether_type))) { + if (WMA_ICMP_V6_HEADER_TYPE == + *(data + WMA_ICMP_V6_HEADER_OFFSET)) { + stats->icmpv6++; + if (WMA_ICMP_V6_RA_TYPE == + *(data + WMA_ICMP_V6_TYPE_OFFSET)) + stats->ipv6_mcast_ra++; + else if (WMA_ICMP_V6_NS_TYPE == + *(data + WMA_ICMP_V6_TYPE_OFFSET)) + stats->ipv6_mcast_ns++; + else if (WMA_ICMP_V6_NA_TYPE == + *(data + WMA_ICMP_V6_TYPE_OFFSET)) + stats->ipv6_mcast_na++; + else + WMA_LOGA("ICMP V6 type : 0x%x", + *(data + WMA_ICMP_V6_TYPE_OFFSET)); + } else { + WMA_LOGA("ICMP_V6 header 0x%x", + *(data + WMA_ICMP_V6_HEADER_OFFSET)); + } + } else { + WMA_LOGA("Ethertype x%x:0x%x", + *(data + WMA_ETHER_TYPE_OFFSET), + *(data + WMA_ETHER_TYPE_OFFSET + 1)); + } + + return; +} + +/** + * wma_inc_wow_stats() - maintain wow pattern match wake up stats + * @stats: per vdev stats counters + * @data: Pointer to pattern match data + * @len: Pattern match data length + * @reason: Wake up reason + * + * Return: none + */ +static void wma_inc_wow_stats(struct sir_vdev_wow_stats *stats, uint8_t *data, + int32_t len, WOW_WAKE_REASON_TYPE reason) +{ + switch (reason) { + case WOW_REASON_BPF_ALLOW: + case WOW_REASON_PATTERN_MATCH_FOUND: + if (!data || len == 0) { + WMA_LOGE("Null data packet for wow reason %s", + wma_wow_wake_reason_str(reason)); + break; + } + + if (WMA_BCAST_MAC_ADDR == *data) { + stats->bcast++; + if (len >= WMA_IPV4_PROTO_GET_MIN_LEN && + qdf_nbuf_data_is_icmp_pkt(data)) + stats->icmpv4++; + else if ((len > WMA_ICMP_V6_TYPE_OFFSET) && + qdf_nbuf_data_is_icmpv6_pkt(data)) + stats->icmpv6++; + } else if (WMA_MCAST_IPV4_MAC_ADDR == *data) { + stats->ipv4_mcast++; + if (len >= WMA_IPV4_PROTO_GET_MIN_LEN && + WMA_ICMP_PROTOCOL == *(data + WMA_IPV4_PROTOCOL)) + stats->icmpv4++; + } else if (WMA_MCAST_IPV6_MAC_ADDR == *data) { + stats->ipv6_mcast++; + if (len > WMA_ICMP_V6_TYPE_OFFSET) + wma_wow_ipv6_mcast_stats(stats, data); + else + WMA_LOGA("ICMP_V6 data len %d", len); + } else { + stats->ucast++; + if (qdf_nbuf_data_is_ipv4_mcast_pkt(data)) + stats->ipv4_mcast++; + else if (qdf_nbuf_data_is_ipv6_mcast_pkt(data)) + stats->ipv6_mcast++; + + if (len >= WMA_IPV4_PROTO_GET_MIN_LEN && + qdf_nbuf_data_is_icmp_pkt(data)) + stats->icmpv4++; + else if (len > WMA_ICMP_V6_TYPE_OFFSET && + qdf_nbuf_data_is_icmpv6_pkt(data)) + stats->icmpv6++; + } + break; + + case WOW_REASON_RA_MATCH: + stats->ipv6_mcast++; + stats->ipv6_mcast_ra++; + stats->icmpv6++; + break; + + case WOW_REASON_NLOD: + stats->pno_match++; + break; + + case WOW_REASON_NLO_SCAN_COMPLETE: + stats->pno_complete++; + break; + + case WOW_REASON_LOW_RSSI: + stats->low_rssi++; + break; + + case WOW_REASON_EXTSCAN: + stats->gscan++; + break; + + case WOW_REASON_RSSI_BREACH_EVENT: + stats->rssi_breach++; + break; + case WOW_REASON_OEM_RESPONSE_EVENT: + stats->oem_response++; + break; + + case WOW_REASON_CHIP_POWER_FAILURE_DETECT: + stats->pwr_save_fail_detected++; + break; + + default: + WMA_LOGI("Stats for WoW reason %s are not tracked", + wma_wow_wake_reason_str(reason)); + + /* don't bother displaying stats that haven't changed */ + return; + } + + wma_wow_stats_display(stats); +} + +#ifdef FEATURE_WLAN_EXTSCAN +/** + * wma_extscan_get_eventid_from_tlvtag() - map tlv tag to corresponding event id + * @tag: WMI TLV tag + * + * Return: + * 0 if TLV tag is invalid + * else return corresponding WMI event id + */ +static int wma_extscan_get_eventid_from_tlvtag(uint32_t tag) +{ + uint32_t event_id; + + switch (tag) { + case WMITLV_TAG_STRUC_wmi_extscan_start_stop_event_fixed_param: + event_id = WMI_EXTSCAN_START_STOP_EVENTID; + break; + + case WMITLV_TAG_STRUC_wmi_extscan_operation_event_fixed_param: + event_id = WMI_EXTSCAN_OPERATION_EVENTID; + break; + + case WMITLV_TAG_STRUC_wmi_extscan_table_usage_event_fixed_param: + event_id = WMI_EXTSCAN_TABLE_USAGE_EVENTID; + break; + + case WMITLV_TAG_STRUC_wmi_extscan_cached_results_event_fixed_param: + event_id = WMI_EXTSCAN_CACHED_RESULTS_EVENTID; + break; + + case WMITLV_TAG_STRUC_wmi_extscan_wlan_change_results_event_fixed_param: + event_id = WMI_EXTSCAN_WLAN_CHANGE_RESULTS_EVENTID; + break; + + case WMITLV_TAG_STRUC_wmi_extscan_hotlist_match_event_fixed_param: + event_id = WMI_EXTSCAN_HOTLIST_MATCH_EVENTID; + break; + + case WMITLV_TAG_STRUC_wmi_extscan_capabilities_event_fixed_param: + event_id = WMI_EXTSCAN_CAPABILITIES_EVENTID; + break; + + default: + event_id = 0; + WMA_LOGE("%s: Unknown tag: %d", __func__, tag); + break; + } + + WMA_LOGI("%s: For tag %d WMI event 0x%x", __func__, tag, event_id); + return event_id; +} +#else +static int wma_extscan_get_eventid_from_tlvtag(uint32_t tag) +{ + return 0; +} +#endif + +/** + * wow_get_wmi_eventid() - map reason or tlv tag to corresponding event id + * @tag: WMI TLV tag + * @reason: WOW reason + * + * WOW reason type is primarily used to find the ID. If there could be + * multiple events that can be sent as a WOW event with same reason + * then tlv tag is used to identify the corresponding event. + * + * Return: + * 0 if TLV tag/reason is invalid + * else return corresponding WMI event id + */ +static int wow_get_wmi_eventid(int32_t reason, uint32_t tag) +{ + uint32_t event_id; + + switch (reason) { + case WOW_REASON_NLO_SCAN_COMPLETE: + event_id = WMI_NLO_SCAN_COMPLETE_EVENTID; + break; + case WOW_REASON_CSA_EVENT: + event_id = WMI_CSA_HANDLING_EVENTID; + break; + case WOW_REASON_LOW_RSSI: + event_id = WMI_ROAM_EVENTID; + break; + case WOW_REASON_CLIENT_KICKOUT_EVENT: + event_id = WMI_PEER_STA_KICKOUT_EVENTID; + break; + case WOW_REASON_EXTSCAN: + event_id = wma_extscan_get_eventid_from_tlvtag(tag); + break; + case WOW_REASON_RSSI_BREACH_EVENT: + event_id = WMI_RSSI_BREACH_EVENTID; + break; + case WOW_REASON_NAN_EVENT: + event_id = WMI_NAN_EVENTID; + break; + case WOW_REASON_NAN_DATA: + event_id = wma_ndp_get_eventid_from_tlvtag(tag); + break; + case WOW_REASON_TDLS_CONN_TRACKER_EVENT: + event_id = WOW_TDLS_CONN_TRACKER_EVENT; + break; + case WOW_REASON_ROAM_HO: + event_id = WMI_ROAM_EVENTID; + break; + default: + WMA_LOGD(FL("Unexpected WOW reason : %s(%d)"), + wma_wow_wake_reason_str(reason), reason); + event_id = 0; + break; + } + wma_peer_debug_log(WMA_INVALID_VDEV_ID, DEBUG_WOW_REASON, + DEBUG_INVALID_PEER_ID, NULL, NULL, + reason, event_id); + + return event_id; +} + +/** + * tlv_check_required() - tells whether to check the wow packet buffer + * for proper TLV structure. + * @reason: WOW reason + * + * In most cases, wow wake up event carries the actual event buffer in + * wow_packet_buffer with some exceptions. This function is used to + * determine when to check for the TLVs in wow_packet_buffer. + * + * Return: true if check is required and false otherwise. + */ +static bool tlv_check_required(int32_t reason) +{ + switch (reason) { + case WOW_REASON_NLO_SCAN_COMPLETE: + case WOW_REASON_CSA_EVENT: + case WOW_REASON_LOW_RSSI: + case WOW_REASON_CLIENT_KICKOUT_EVENT: + case WOW_REASON_EXTSCAN: + case WOW_REASON_RSSI_BREACH_EVENT: + case WOW_REASON_NAN_EVENT: + case WOW_REASON_NAN_DATA: + case WOW_REASON_ROAM_HO: + return true; + default: + return false; + } +} + +/** + * wma_pkt_proto_subtype_to_string() - to convert proto subtype + * of data packet to string. + * @proto_subtype: proto subtype for data packet + * + * This function returns the string for the proto subtype of + * data packet. + * + * Return: string for proto subtype for data packet + */ +static const char * +wma_pkt_proto_subtype_to_string(enum qdf_proto_subtype proto_subtype) +{ + switch (proto_subtype) { + case QDF_PROTO_EAPOL_M1: + return "EAPOL M1"; + case QDF_PROTO_EAPOL_M2: + return "EAPOL M2"; + case QDF_PROTO_EAPOL_M3: + return "EAPOL M3"; + case QDF_PROTO_EAPOL_M4: + return "EAPOL M4"; + case QDF_PROTO_DHCP_DISCOVER: + return "DHCP DISCOVER"; + case QDF_PROTO_DHCP_REQUEST: + return "DHCP REQUEST"; + case QDF_PROTO_DHCP_OFFER: + return "DHCP OFFER"; + case QDF_PROTO_DHCP_ACK: + return "DHCP ACK"; + case QDF_PROTO_DHCP_NACK: + return "DHCP NACK"; + case QDF_PROTO_DHCP_RELEASE: + return "DHCP RELEASE"; + case QDF_PROTO_DHCP_INFORM: + return "DHCP INFORM"; + case QDF_PROTO_DHCP_DECLINE: + return "DHCP DECLINE"; + case QDF_PROTO_ARP_REQ: + return "ARP REQUEST"; + case QDF_PROTO_ARP_RES: + return "ARP RESPONSE"; + case QDF_PROTO_ICMP_REQ: + return "ICMP REQUEST"; + case QDF_PROTO_ICMP_RES: + return "ICMP RESPONSE"; + case QDF_PROTO_ICMPV6_REQ: + return "ICMPV6 REQUEST"; + case QDF_PROTO_ICMPV6_RES: + return "ICMPV6 RESPONSE"; + case QDF_PROTO_ICMPV6_RS: + return "ICMPV6 RS"; + case QDF_PROTO_ICMPV6_RA: + return "ICMPV6 RA"; + case QDF_PROTO_ICMPV6_NS: + return "ICMPV6 NS"; + case QDF_PROTO_ICMPV6_NA: + return "ICMPV6 NA"; + case QDF_PROTO_IPV4_UDP: + return "IPV4 UDP Packet"; + case QDF_PROTO_IPV4_TCP: + return "IPV4 TCP Packet"; + case QDF_PROTO_IPV6_UDP: + return "IPV6 UDP Packet"; + case QDF_PROTO_IPV6_TCP: + return "IPV6 TCP Packet"; + default: + return "Invalid Packet"; + } +} + +/** + * wma_wow_get_pkt_proto_subtype() - get the proto subtype + * of the packet. + * @data: Pointer to data buffer + * @len: length of the data buffer + * + * This function gives the proto subtype of the packet. + * + * Return: proto subtype of the packet. + */ +static enum qdf_proto_subtype +wma_wow_get_pkt_proto_subtype(uint8_t *data, + uint32_t len) +{ + uint16_t ether_type = (uint16_t)(*(uint16_t *)(data + + QDF_NBUF_TRAC_ETH_TYPE_OFFSET)); + + WMA_LOGD("Ether Type: 0x%04x", + ani_cpu_to_be16(ether_type)); + + if (QDF_NBUF_TRAC_EAPOL_ETH_TYPE == + ani_cpu_to_be16(ether_type)) { + if (len >= WMA_EAPOL_SUBTYPE_GET_MIN_LEN) + return qdf_nbuf_data_get_eapol_subtype(data); + WMA_LOGD("EAPOL Packet"); + return QDF_PROTO_INVALID; + } else if (QDF_NBUF_TRAC_ARP_ETH_TYPE == + ani_cpu_to_be16(ether_type)) { + if (len >= WMA_ARP_SUBTYPE_GET_MIN_LEN) + return qdf_nbuf_data_get_arp_subtype(data); + WMA_LOGD("ARP Packet"); + return QDF_PROTO_INVALID; + } else if (QDF_NBUF_TRAC_IPV4_ETH_TYPE == + ani_cpu_to_be16(ether_type)) { + if (len >= WMA_IPV4_PROTO_GET_MIN_LEN) { + uint8_t proto_type; + + proto_type = qdf_nbuf_data_get_ipv4_proto(data); + WMA_LOGD("IPV4_proto_type: %u", proto_type); + if (proto_type == QDF_NBUF_TRAC_ICMP_TYPE) { + if (len >= WMA_ICMP_SUBTYPE_GET_MIN_LEN) + return qdf_nbuf_data_get_icmp_subtype( + data); + WMA_LOGD("ICMP Packet"); + return QDF_PROTO_INVALID; + } else if (proto_type == QDF_NBUF_TRAC_UDP_TYPE) { + if (len >= WMA_IS_DHCP_GET_MIN_LEN) { + if (qdf_nbuf_data_is_ipv4_dhcp_pkt(data)) { + if (len >= + WMA_DHCP_SUBTYPE_GET_MIN_LEN) + return qdf_nbuf_data_get_dhcp_subtype(data); + WMA_LOGD("DHCP Packet"); + return QDF_PROTO_INVALID; + } + } + return QDF_PROTO_IPV4_UDP; + } else if (proto_type == QDF_NBUF_TRAC_TCP_TYPE) { + return QDF_PROTO_IPV4_TCP; + } + } + WMA_LOGD("IPV4 Packet"); + return QDF_PROTO_INVALID; + } else if (QDF_NBUF_TRAC_IPV6_ETH_TYPE == + ani_cpu_to_be16(ether_type)) { + if (len >= WMA_IPV6_PROTO_GET_MIN_LEN) { + uint8_t proto_type; + + proto_type = qdf_nbuf_data_get_ipv6_proto(data); + WMA_LOGD("IPV6_proto_type: %u", proto_type); + if (proto_type == QDF_NBUF_TRAC_ICMPV6_TYPE) { + if (len >= WMA_ICMPV6_SUBTYPE_GET_MIN_LEN) + return qdf_nbuf_data_get_icmpv6_subtype( + data); + WMA_LOGD("ICMPV6 Packet"); + return QDF_PROTO_INVALID; + } else if (proto_type == QDF_NBUF_TRAC_UDP_TYPE) { + return QDF_PROTO_IPV6_UDP; + } else if (proto_type == QDF_NBUF_TRAC_TCP_TYPE) { + return QDF_PROTO_IPV6_TCP; + } + } + WMA_LOGD("IPV6 Packet"); + return QDF_PROTO_INVALID; + } + + return QDF_PROTO_INVALID; +} + +/** + * wma_wow_parse_data_pkt_buffer() - API to parse data buffer for data + * packet that resulted in WOW wakeup. + * @data: Pointer to data buffer + * @buf_len: data buffer length + * + * This function parses the data buffer received (first few bytes of + * skb->data) to get informaton like src mac addr, dst mac addr, packet + * len, seq_num, etc. + * + * Return: void + */ +static void wma_wow_parse_data_pkt_buffer(uint8_t *data, + uint32_t buf_len) +{ + enum qdf_proto_subtype proto_subtype; + uint16_t pkt_len, key_len, seq_num; + uint16_t src_port, dst_port; + uint32_t transaction_id, tcp_seq_num; + char *ip_addr; + + WMA_LOGD("wow_buf_pkt_len: %u", buf_len); + if (buf_len >= QDF_NBUF_TRAC_IPV4_OFFSET) + WMA_LOGD("Src_mac: " MAC_ADDRESS_STR " Dst_mac: " MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(data + QDF_NBUF_SRC_MAC_OFFSET), + MAC_ADDR_ARRAY(data + QDF_NBUF_DEST_MAC_OFFSET)); + else + goto end; + + proto_subtype = wma_wow_get_pkt_proto_subtype(data, buf_len); + switch (proto_subtype) { + case QDF_PROTO_EAPOL_M1: + case QDF_PROTO_EAPOL_M2: + case QDF_PROTO_EAPOL_M3: + case QDF_PROTO_EAPOL_M4: + WMA_LOGD("WOW Wakeup: %s rcvd", + wma_pkt_proto_subtype_to_string(proto_subtype)); + if (buf_len >= WMA_EAPOL_INFO_GET_MIN_LEN) { + pkt_len = (uint16_t)(*(uint16_t *)(data + + EAPOL_PKT_LEN_OFFSET)); + key_len = (uint16_t)(*(uint16_t *)(data + + EAPOL_KEY_LEN_OFFSET)); + WMA_LOGD("Pkt_len: %u, Key_len: %u", + ani_cpu_to_be16(pkt_len), + ani_cpu_to_be16(key_len)); + } + break; + + case QDF_PROTO_DHCP_DISCOVER: + case QDF_PROTO_DHCP_REQUEST: + case QDF_PROTO_DHCP_OFFER: + case QDF_PROTO_DHCP_ACK: + case QDF_PROTO_DHCP_NACK: + case QDF_PROTO_DHCP_RELEASE: + case QDF_PROTO_DHCP_INFORM: + case QDF_PROTO_DHCP_DECLINE: + WMA_LOGD("WOW Wakeup: %s rcvd", + wma_pkt_proto_subtype_to_string(proto_subtype)); + if (buf_len >= WMA_DHCP_INFO_GET_MIN_LEN) { + pkt_len = (uint16_t)(*(uint16_t *)(data + + DHCP_PKT_LEN_OFFSET)); + transaction_id = (uint32_t)(*(uint32_t *)(data + + DHCP_TRANSACTION_ID_OFFSET)); + WMA_LOGD("Pkt_len: %u, Transaction_id: %u", + ani_cpu_to_be16(pkt_len), + ani_cpu_to_be16(transaction_id)); + } + break; + + case QDF_PROTO_ARP_REQ: + case QDF_PROTO_ARP_RES: + WMA_LOGD("WOW Wakeup: %s rcvd", + wma_pkt_proto_subtype_to_string(proto_subtype)); + break; + + case QDF_PROTO_ICMP_REQ: + case QDF_PROTO_ICMP_RES: + WMA_LOGD("WOW Wakeup: %s rcvd", + wma_pkt_proto_subtype_to_string(proto_subtype)); + if (buf_len >= WMA_IPV4_PKT_INFO_GET_MIN_LEN) { + pkt_len = (uint16_t)(*(uint16_t *)(data + + IPV4_PKT_LEN_OFFSET)); + seq_num = (uint16_t)(*(uint16_t *)(data + + ICMP_SEQ_NUM_OFFSET)); + WMA_LOGD("Pkt_len: %u, Seq_num: %u", + ani_cpu_to_be16(pkt_len), + ani_cpu_to_be16(seq_num)); + } + break; + + case QDF_PROTO_ICMPV6_REQ: + case QDF_PROTO_ICMPV6_RES: + case QDF_PROTO_ICMPV6_RS: + case QDF_PROTO_ICMPV6_RA: + case QDF_PROTO_ICMPV6_NS: + case QDF_PROTO_ICMPV6_NA: + WMA_LOGD("WOW Wakeup: %s rcvd", + wma_pkt_proto_subtype_to_string(proto_subtype)); + if (buf_len >= WMA_IPV6_PKT_INFO_GET_MIN_LEN) { + pkt_len = (uint16_t)(*(uint16_t *)(data + + IPV6_PKT_LEN_OFFSET)); + seq_num = (uint16_t)(*(uint16_t *)(data + + ICMPV6_SEQ_NUM_OFFSET)); + WMA_LOGD("Pkt_len: %u, Seq_num: %u", + ani_cpu_to_be16(pkt_len), + ani_cpu_to_be16(seq_num)); + } + break; + + case QDF_PROTO_IPV4_UDP: + case QDF_PROTO_IPV4_TCP: + WMA_LOGD("WOW Wakeup: %s rcvd", + wma_pkt_proto_subtype_to_string(proto_subtype)); + if (buf_len >= WMA_IPV4_PKT_INFO_GET_MIN_LEN) { + pkt_len = (uint16_t)(*(uint16_t *)(data + + IPV4_PKT_LEN_OFFSET)); + ip_addr = (char *)(data + IPV4_SRC_ADDR_OFFSET); + WMA_LOGD("src addr %d:%d:%d:%d", ip_addr[0], ip_addr[1], + ip_addr[2], ip_addr[3]); + ip_addr = (char *)(data + IPV4_DST_ADDR_OFFSET); + WMA_LOGD("dst addr %d:%d:%d:%d", ip_addr[0], ip_addr[1], + ip_addr[2], ip_addr[3]); + src_port = (uint16_t)(*(uint16_t *)(data + + IPV4_SRC_PORT_OFFSET)); + dst_port = (uint16_t)(*(uint16_t *)(data + + IPV4_DST_PORT_OFFSET)); + WMA_LOGD("Pkt_len: %u", + ani_cpu_to_be16(pkt_len)); + WMA_LOGD("src_port: %u, dst_port: %u", + ani_cpu_to_be16(src_port), + ani_cpu_to_be16(dst_port)); + if (proto_subtype == QDF_PROTO_IPV4_TCP) { + tcp_seq_num = (uint32_t)(*(uint32_t *)(data + + IPV4_TCP_SEQ_NUM_OFFSET)); + WMA_LOGD("TCP_seq_num: %u", + ani_cpu_to_be16(tcp_seq_num)); + } + } + break; + + case QDF_PROTO_IPV6_UDP: + case QDF_PROTO_IPV6_TCP: + WMA_LOGD("WOW Wakeup: %s rcvd", + wma_pkt_proto_subtype_to_string(proto_subtype)); + if (buf_len >= WMA_IPV6_PKT_INFO_GET_MIN_LEN) { + pkt_len = (uint16_t)(*(uint16_t *)(data + + IPV6_PKT_LEN_OFFSET)); + ip_addr = (char *)(data + IPV6_SRC_ADDR_OFFSET); + WMA_LOGD("src addr "IPV6_ADDR_STR, ip_addr[0], + ip_addr[1], ip_addr[2], ip_addr[3], ip_addr[4], + ip_addr[5], ip_addr[6], ip_addr[7], ip_addr[8], + ip_addr[9], ip_addr[10], ip_addr[11], + ip_addr[12], ip_addr[13], ip_addr[14], + ip_addr[15]); + ip_addr = (char *)(data + IPV6_DST_ADDR_OFFSET); + WMA_LOGD("dst addr "IPV6_ADDR_STR, ip_addr[0], + ip_addr[1], ip_addr[2], ip_addr[3], ip_addr[4], + ip_addr[5], ip_addr[6], ip_addr[7], ip_addr[8], + ip_addr[9], ip_addr[10], ip_addr[11], + ip_addr[12], ip_addr[13], ip_addr[14], + ip_addr[15]); + src_port = (uint16_t)(*(uint16_t *)(data + + IPV6_SRC_PORT_OFFSET)); + dst_port = (uint16_t)(*(uint16_t *)(data + + IPV6_DST_PORT_OFFSET)); + WMA_LOGD("Pkt_len: %u", + ani_cpu_to_be16(pkt_len)); + WMA_LOGD("src_port: %u, dst_port: %u", + ani_cpu_to_be16(src_port), + ani_cpu_to_be16(dst_port)); + if (proto_subtype == QDF_PROTO_IPV6_TCP) { + tcp_seq_num = (uint32_t)(*(uint32_t *)(data + + IPV6_TCP_SEQ_NUM_OFFSET)); + WMA_LOGD("TCP_seq_num: %u", + ani_cpu_to_be16(tcp_seq_num)); + } + } + break; + + default: +end: + WMA_LOGD("wow_buf_pkt_len: %u", buf_len); + break; + } +} + +/** + * wma_wow_dump_mgmt_buffer() - API to parse data buffer for mgmt. + * packet that resulted in WOW wakeup. + * @wow_packet_buffer: Pointer to data buffer + * @buf_len: length of data buffer + * + * This function parses the data buffer received (802.11 header) + * to get informaton like src mac addr, dst mac addr, seq_num, + * frag_num, etc. + * + * Return: void + */ +static void wma_wow_dump_mgmt_buffer(uint8_t *wow_packet_buffer, + uint32_t buf_len) +{ + struct ieee80211_frame_addr4 *wh; + + WMA_LOGD("wow_buf_pkt_len: %u", buf_len); + wh = (struct ieee80211_frame_addr4 *) + (wow_packet_buffer + 4); + if (buf_len >= sizeof(struct ieee80211_frame)) { + uint8_t to_from_ds, frag_num; + uint32_t seq_num; + + WMA_LOGE("RA: " MAC_ADDRESS_STR " TA: " MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(wh->i_addr1), + MAC_ADDR_ARRAY(wh->i_addr2)); + + WMA_LOGE("TO_DS: %u, FROM_DS: %u", + wh->i_fc[1] & IEEE80211_FC1_DIR_TODS, + wh->i_fc[1] & IEEE80211_FC1_DIR_FROMDS); + + to_from_ds = wh->i_fc[1] & IEEE80211_FC1_DIR_DSTODS; + + switch (to_from_ds) { + case IEEE80211_NO_DS: + WMA_LOGE("BSSID: " MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(wh->i_addr3)); + break; + case IEEE80211_TO_DS: + WMA_LOGE("DA: " MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(wh->i_addr3)); + break; + case IEEE80211_FROM_DS: + WMA_LOGE("SA: " MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(wh->i_addr3)); + break; + case IEEE80211_DS_TO_DS: + if (buf_len >= sizeof(struct ieee80211_frame_addr4)) + WMA_LOGE("DA: " MAC_ADDRESS_STR " SA: " + MAC_ADDRESS_STR, + MAC_ADDR_ARRAY(wh->i_addr3), + MAC_ADDR_ARRAY(wh->i_addr4)); + break; + } + + seq_num = (((*(uint16_t *)wh->i_seq) & + IEEE80211_SEQ_SEQ_MASK) >> + IEEE80211_SEQ_SEQ_SHIFT); + frag_num = (((*(uint16_t *)wh->i_seq) & + IEEE80211_SEQ_FRAG_MASK) >> + IEEE80211_SEQ_FRAG_SHIFT); + + WMA_LOGE("SEQ_NUM: %u, FRAG_NUM: %u", + seq_num, frag_num); + } else { + WMA_LOGE("Insufficient buffer length for mgmt. packet"); + } +} + +/** + * wma_wow_get_wakelock_ms() - return the wakelock duration + * for some mgmt packets received. + * @wake_reason: wow wakeup reason + * + * This function returns the wakelock duration for some mgmt packets + * received while in wow suspend. + * + * Return: wakelock duration in ms + */ +static uint32_t wma_wow_get_wakelock_ms(int wake_reason) +{ + switch (wake_reason) { + case WOW_REASON_AUTH_REQ_RECV: + return WMA_AUTH_REQ_RECV_WAKE_LOCK_TIMEOUT; + case WOW_REASON_ASSOC_REQ_RECV: + return WMA_ASSOC_REQ_RECV_WAKE_LOCK_DURATION; + case WOW_REASON_DEAUTH_RECVD: + return WMA_DEAUTH_RECV_WAKE_LOCK_DURATION; + case WOW_REASON_DISASSOC_RECVD: + return WMA_DISASSOC_RECV_WAKE_LOCK_DURATION; + case WOW_REASON_AP_ASSOC_LOST: + return WMA_BMISS_EVENT_WAKE_LOCK_DURATION; +#ifdef FEATURE_WLAN_AUTO_SHUTDOWN + case WOW_REASON_HOST_AUTO_SHUTDOWN: + return WMA_AUTO_SHUTDOWN_WAKE_LOCK_DURATION; +#endif + case WOW_REASON_ROAM_HO: + return WMA_ROAM_HO_WAKE_LOCK_DURATION; + } + + return 0; +} + +/** + * wma_wow_ap_lost_helper() - helper function to handle WOW_REASON_AP_ASSOC_LOST + * reason code and retrieve RSSI from the event. + * @wma: Pointer to wma handle + * @param: WMI_WOW_WAKEUP_HOST_EVENTID_param_tlvs buffer pointer + * + * Return: none + */ +static void wma_wow_ap_lost_helper(tp_wma_handle wma, void *param) +{ + WMI_WOW_WAKEUP_HOST_EVENTID_param_tlvs *param_buf; + WOW_EVENT_INFO_fixed_param *wake_info; + WMI_ROAM_EVENTID_param_tlvs event_param; + wmi_roam_event_fixed_param *roam_event; + u_int32_t wow_buf_pkt_len = 0; + + param_buf = (WMI_WOW_WAKEUP_HOST_EVENTID_param_tlvs *) param; + wake_info = param_buf->fixed_param; + WMA_LOGA("%s: Beacon miss indication on vdev %d", + __func__, wake_info->vdev_id); + + if (NULL == param_buf->wow_packet_buffer) { + WMA_LOGE("%s: invalid wow packet buffer", __func__); + goto exit_handler; + } + + qdf_mem_copy((u_int8_t *) &wow_buf_pkt_len, + param_buf->wow_packet_buffer, 4); + WMA_LOGD("wow_packet_buffer dump"); + qdf_trace_hex_dump(QDF_MODULE_ID_WMA, QDF_TRACE_LEVEL_DEBUG, + param_buf->wow_packet_buffer, wow_buf_pkt_len); + if (wow_buf_pkt_len >= sizeof(event_param)) { + roam_event = (wmi_roam_event_fixed_param *) + (param_buf->wow_packet_buffer + 4); + wma_beacon_miss_handler(wma, wake_info->vdev_id, + roam_event->rssi); + return; + } + +exit_handler: + /* in the case that no RSSI is available from the event */ + WMA_LOGE("%s: rssi is not available from wow_packet_buffer", __func__); + wma_beacon_miss_handler(wma, wake_info->vdev_id, 0); +} + +static const char *wma_vdev_type_str(uint32_t vdev_type) +{ + switch (vdev_type) { + case WMI_VDEV_TYPE_AP: + return "AP"; + case WMI_VDEV_TYPE_STA: + return "STA"; + case WMI_VDEV_TYPE_IBSS: + return "IBSS"; + case WMI_VDEV_TYPE_MONITOR: + return "MONITOR"; + case WMI_VDEV_TYPE_NAN: + return "NAN"; + case WMI_VDEV_TYPE_OCB: + return "OCB"; + case WMI_VDEV_TYPE_NDI: + return "NDI"; + default: + return "unknown"; + } +} + +/** + * wma_wow_wakeup_host_event() - wakeup host event handler + * @handle: wma handle + * @event: event data + * @len: buffer length + * + * Handler to catch wow wakeup host event. This event will have + * reason why the firmware has woken the host. + * + * Return: 0 for success or error + */ +int wma_wow_wakeup_host_event(void *handle, uint8_t *event, + uint32_t len) +{ + tp_wma_handle wma = (tp_wma_handle) handle; + struct wma_txrx_node *wma_vdev; + WMI_WOW_WAKEUP_HOST_EVENTID_param_tlvs *param_buf; + WOW_EVENT_INFO_fixed_param *wake_info; + uint32_t wakelock_duration; + void *wmi_cmd_struct_ptr = NULL; + uint32_t tlv_hdr, tag, wow_buf_pkt_len = 0, event_id = 0; + uint8_t *wow_buf_data = NULL; + int tlv_ok_status; + + param_buf = (WMI_WOW_WAKEUP_HOST_EVENTID_param_tlvs *) event; + if (!param_buf) { + WMA_LOGE("Invalid wow wakeup host event buf"); + return -EINVAL; + } + + wake_info = param_buf->fixed_param; + wma_vdev = &wma->interfaces[wake_info->vdev_id]; + + if ((wake_info->wake_reason != WOW_REASON_UNSPECIFIED) || + (wake_info->wake_reason == WOW_REASON_UNSPECIFIED && + !wmi_get_runtime_pm_inprogress(wma->wmi_handle))) { + WMA_LOGA("WOW wakeup host event received; reason: %s(%d), vdev_id: %d, vdev_type: %s", + wma_wow_wake_reason_str(wake_info->wake_reason), + wake_info->wake_reason, + wake_info->vdev_id, + wma_vdev ? wma_vdev_type_str(wma_vdev->type) : "null"); + qdf_wow_wakeup_host_event(wake_info->wake_reason); + qdf_wma_wow_wakeup_stats_event(); + } + + qdf_event_set(&wma->wma_resume_event); + + if (param_buf->wow_packet_buffer && + tlv_check_required(wake_info->wake_reason)) { + /* + * In case of wow_packet_buffer, first 4 bytes is the length. + * Following the length is the actual buffer. + */ + wow_buf_pkt_len = *(uint32_t *)param_buf->wow_packet_buffer; + tlv_hdr = WMITLV_GET_HDR( + (uint8_t *)param_buf->wow_packet_buffer + 4); + + tag = WMITLV_GET_TLVTAG(tlv_hdr); + event_id = wow_get_wmi_eventid(wake_info->wake_reason, tag); + if (!event_id) { + WMA_LOGE(FL("Unable to find matching ID")); + return -EINVAL; + } + + tlv_ok_status = wmitlv_check_and_pad_event_tlvs( + handle, param_buf->wow_packet_buffer + 4, + wow_buf_pkt_len, event_id, + &wmi_cmd_struct_ptr); + + if (tlv_ok_status != 0) { + WMA_LOGE(FL("Invalid TLVs, Length:%d event_id:%d status: %d"), + wow_buf_pkt_len, event_id, tlv_ok_status); + return -EINVAL; + } + } + + switch (wake_info->wake_reason) { + case WOW_REASON_AUTH_REQ_RECV: + case WOW_REASON_ASSOC_REQ_RECV: + case WOW_REASON_DEAUTH_RECVD: + case WOW_REASON_DISASSOC_RECVD: + case WOW_REASON_ASSOC_RES_RECV: + case WOW_REASON_REASSOC_REQ_RECV: + case WOW_REASON_REASSOC_RES_RECV: + case WOW_REASON_BEACON_RECV: + case WOW_REASON_ACTION_FRAME_RECV: + if (param_buf->wow_packet_buffer) { + /* First 4-bytes of wow_packet_buffer is the length */ + qdf_mem_copy((uint8_t *) &wow_buf_pkt_len, + param_buf->wow_packet_buffer, 4); + if (wow_buf_pkt_len) + wma_wow_dump_mgmt_buffer( + param_buf->wow_packet_buffer, + wow_buf_pkt_len); + else + WMA_LOGE("wow packet buffer is empty"); + } else { + WMA_LOGE("No wow packet buffer present"); + } + break; + + case WOW_REASON_AP_ASSOC_LOST: + wma_wow_ap_lost_helper(wma, param_buf); + break; +#ifdef FEATURE_WLAN_AUTO_SHUTDOWN + case WOW_REASON_HOST_AUTO_SHUTDOWN: + WMA_LOGA("Received WOW Auto Shutdown trigger in suspend"); + if (wma_post_auto_shutdown_msg()) + return -EINVAL; + break; +#endif /* FEATURE_WLAN_AUTO_SHUTDOWN */ +#ifdef FEATURE_WLAN_SCAN_PNO + case WOW_REASON_NLOD: + if (wma_vdev) { + WMA_LOGD("NLO match happened"); + wma_vdev->nlo_match_evt_received = true; + cds_host_diag_log_work(&wma->pno_wake_lock, + WMA_PNO_MATCH_WAKE_LOCK_TIMEOUT, + WIFI_POWER_EVENT_WAKELOCK_PNO); + qdf_wake_lock_timeout_acquire(&wma->pno_wake_lock, + WMA_PNO_MATCH_WAKE_LOCK_TIMEOUT); + } + break; + + case WOW_REASON_NLO_SCAN_COMPLETE: + WMA_LOGD("Host woken up due to pno scan complete reason"); + if (param_buf->wow_packet_buffer) + wma_nlo_scan_cmp_evt_handler(handle, + wmi_cmd_struct_ptr, wow_buf_pkt_len); + else + WMA_LOGD("No wow_packet_buffer present"); + break; +#endif /* FEATURE_WLAN_SCAN_PNO */ + + case WOW_REASON_CSA_EVENT: + WMA_LOGD("Host woken up because of CSA IE"); + wma_csa_offload_handler(handle, wmi_cmd_struct_ptr, + wow_buf_pkt_len); + break; + +#ifdef FEATURE_WLAN_LPHB + case WOW_REASON_WLAN_HB: + wma_lphb_handler(wma, (uint8_t *) param_buf->hb_indevt); + break; +#endif /* FEATURE_WLAN_LPHB */ + + case WOW_REASON_HTT_EVENT: + break; + + case WOW_REASON_BPF_ALLOW: + case WOW_REASON_PATTERN_MATCH_FOUND: +#ifdef FEATURE_WLAN_RA_FILTERING + case WOW_REASON_RA_MATCH: +#endif /* FEATURE_WLAN_RA_FILTERING */ + case WOW_REASON_RECV_MAGIC_PATTERN: + if (wma_vdev) + wma_wow_stats_display(&wma_vdev->wow_stats); + + WMA_LOGD("Wake up for Rx packet, dump starting from ethernet hdr"); + if (!param_buf->wow_packet_buffer) { + WMA_LOGE("No wow packet buffer present"); + break; + } + + /* First 4-bytes of wow_packet_buffer is the length */ + qdf_mem_copy((uint8_t *)&wow_buf_pkt_len, + param_buf->wow_packet_buffer, 4); + if (wow_buf_pkt_len == 0) { + WMA_LOGE("wow packet buffer is empty"); + break; + } + + wow_buf_data = (uint8_t *)(param_buf->wow_packet_buffer + 4); + qdf_trace_hex_dump(QDF_MODULE_ID_WMA, QDF_TRACE_LEVEL_DEBUG, + wow_buf_data, wow_buf_pkt_len); + wma_wow_parse_data_pkt_buffer(wow_buf_data, wow_buf_pkt_len); + + break; + + case WOW_REASON_LOW_RSSI: + case WOW_REASON_ROAM_HO: + /* + * WOW_REASON_LOW_RSSI is used for following roaming events - + * WMI_ROAM_REASON_BETTER_AP, WMI_ROAM_REASON_BMISS, + * WMI_ROAM_REASON_SUITABLE_AP will be handled by + * wma_roam_event_callback(). + * WOW_REASON_ROAM_HO is associated with + * WMI_ROAM_REASON_HO_FAILED event and it will be handled by + * wma_roam_event_callback(). + */ + wma_peer_debug_log(wake_info->vdev_id, + DEBUG_WOW_ROAM_EVENT, DEBUG_INVALID_PEER_ID, + NULL, NULL, + wake_info->wake_reason, wow_buf_pkt_len); + WMA_LOGD("Host woken up because of roam event"); + if (param_buf->wow_packet_buffer) { + /* Roam event is embedded in wow_packet_buffer */ + WMA_LOGD("wow_packet_buffer dump"); + qdf_trace_hex_dump(QDF_MODULE_ID_WMA, + QDF_TRACE_LEVEL_DEBUG, + param_buf->wow_packet_buffer, + wow_buf_pkt_len); + wma_roam_event_callback(handle, wmi_cmd_struct_ptr, + wow_buf_pkt_len); + } else { + /* + * No wow_packet_buffer means a better AP beacon + * will follow in a later event. + */ + WMA_LOGD("Host woken up because of better AP beacon"); + } + break; + case WOW_REASON_CLIENT_KICKOUT_EVENT: + WMA_LOGD("Host woken up because of sta_kickout event"); + if (param_buf->wow_packet_buffer) { + WMA_LOGD("wow_packet_buffer dump"); + qdf_trace_hex_dump(QDF_MODULE_ID_WMA, + QDF_TRACE_LEVEL_DEBUG, + param_buf->wow_packet_buffer, wow_buf_pkt_len); + wma_peer_sta_kickout_event_handler(handle, + wmi_cmd_struct_ptr, wow_buf_pkt_len); + } else { + WMA_LOGD("No wow_packet_buffer present"); + } + break; +#ifdef FEATURE_WLAN_EXTSCAN + case WOW_REASON_EXTSCAN: + WMA_LOGD("Host woken up because of extscan reason"); + if (param_buf->wow_packet_buffer) + wma_extscan_wow_event_callback(handle, + wmi_cmd_struct_ptr, wow_buf_pkt_len); + else + WMA_LOGE("wow_packet_buffer is empty"); + break; +#endif + case WOW_REASON_RSSI_BREACH_EVENT: + WMA_LOGD("Host woken up because of rssi breach reason"); + /* rssi breach event is embedded in wow_packet_buffer */ + if (param_buf->wow_packet_buffer) + wma_rssi_breached_event_handler(handle, + wmi_cmd_struct_ptr, wow_buf_pkt_len); + else + WMA_LOGD("No wow_packet_buffer present"); + break; + case WOW_REASON_NAN_EVENT: + WMA_LOGA("Host woken up due to NAN event reason"); + wma_nan_rsp_event_handler(handle, + wmi_cmd_struct_ptr, wow_buf_pkt_len); + break; + case WOW_REASON_NAN_DATA: + WMA_LOGD(FL("Host woken up for NAN data path event from FW")); + if (param_buf->wow_packet_buffer) { + wma_ndp_wow_event_callback(handle, wmi_cmd_struct_ptr, + wow_buf_pkt_len, event_id); + } else { + WMA_LOGE(FL("wow_packet_buffer is empty")); + } + break; + case WOW_REASON_OEM_RESPONSE_EVENT: + /* + * Actual OEM Response event will follow after this + * WOW Wakeup event + */ + WMA_LOGD(FL("Host woken up for OEM Response event")); + break; +#ifdef FEATURE_WLAN_TDLS + case WOW_REASON_TDLS_CONN_TRACKER_EVENT: + WMA_LOGD("Host woken up because of TDLS event"); + if (param_buf->wow_packet_buffer) + wma_tdls_event_handler(handle, + wmi_cmd_struct_ptr, wow_buf_pkt_len); + else + WMA_LOGD("No wow_packet_buffer present"); + break; +#endif + case WOW_REASON_CHIP_POWER_FAILURE_DETECT: + /* Just update stats and exit */ + WMA_LOGD("Host woken up because of chip power save failure"); + break; + default: + break; + } + + /* Log wake reason at appropriate (global/vdev) level */ + if (wake_info->wake_reason == WOW_REASON_UNSPECIFIED) + wma->wow_unspecified_wake_count++; + else if (wma_vdev) + wma_inc_wow_stats(&wma_vdev->wow_stats, + wow_buf_data, + wow_buf_data ? wow_buf_pkt_len : 0, + wake_info->wake_reason); + else + WMA_LOGE("Vdev is NULL, but wake reason is vdev related"); + + wakelock_duration = wma_wow_get_wakelock_ms(wake_info->wake_reason); + if (wakelock_duration) { + cds_host_diag_log_work(&wma->wow_wake_lock, + wakelock_duration, + WIFI_POWER_EVENT_WAKELOCK_WOW); + qdf_wake_lock_timeout_acquire(&wma->wow_wake_lock, + wakelock_duration); + WMA_LOGA("Holding %d msec wake_lock", wakelock_duration); + } + + if (wmi_cmd_struct_ptr) + wmitlv_free_allocated_event_tlvs(event_id, &wmi_cmd_struct_ptr); + + return 0; +} + +/** + * wma_pdev_resume_event_handler() - PDEV resume event handler + * @handle: wma handle + * @event: event data + * @len: buffer length + * + * Return: 0 for success or error + */ +int wma_pdev_resume_event_handler(void *handle, uint8_t *event, uint32_t len) +{ + tp_wma_handle wma = (tp_wma_handle) handle; + + WMA_LOGA("Received PDEV resume event"); + + qdf_event_set(&wma->wma_resume_event); + + return 0; +} +/** + * wma_set_wow_bus_suspend() - set suspend flag + * @wma: wma handle + * @val: value + * + * Return: none + */ +static inline void wma_set_wow_bus_suspend(tp_wma_handle wma, int val) +{ + qdf_atomic_set(&wma->is_wow_bus_suspended, val); + wmi_set_is_wow_bus_suspended(wma->wmi_handle, val); +} + +/** + * wma_add_wow_wakeup_event() - Configures wow wakeup events. + * @wma: wma handle + * @vdev_id: vdev id + * @bitmap: Event bitmap + * @enable: enable/disable + * + * Return: QDF status + */ +QDF_STATUS wma_add_wow_wakeup_event(tp_wma_handle wma, + uint32_t vdev_id, + uint32_t *bitmap, + bool enable) +{ + int ret; + + ret = wmi_unified_add_wow_wakeup_event_cmd(wma->wmi_handle, vdev_id, + bitmap, enable); + if (ret) { + WMA_LOGE("Failed to config wow wakeup event"); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * wma_send_wow_patterns_to_fw() - Sends WOW patterns to FW. + * @wma: wma handle + * @vdev_id: vdev id + * @ptrn_id: pattern id + * @ptrn: pattern + * @ptrn_len: pattern length + * @ptrn_offset: pattern offset + * @mask: mask + * @mask_len: mask length + * @user: true for user configured pattern and false for default pattern + * + * Return: QDF status + */ +static QDF_STATUS wma_send_wow_patterns_to_fw(tp_wma_handle wma, + uint8_t vdev_id, uint8_t ptrn_id, + const uint8_t *ptrn, uint8_t ptrn_len, + uint8_t ptrn_offset, const uint8_t *mask, + uint8_t mask_len, bool user) +{ + struct wma_txrx_node *iface; + int ret; + + iface = &wma->interfaces[vdev_id]; + ret = wmi_unified_wow_patterns_to_fw_cmd(wma->wmi_handle, + vdev_id, ptrn_id, ptrn, + ptrn_len, ptrn_offset, mask, + mask_len, user, 0); + if (ret) { + if (!user) + iface->num_wow_default_patterns--; + return QDF_STATUS_E_FAILURE; + } + + if (user) + iface->num_wow_user_patterns++; + + return QDF_STATUS_SUCCESS; +} + +/** + * wma_wow_ap() - set WOW patterns in ap mode + * @wma: wma handle + * @vdev_id: vdev id + * + * Configures default WOW pattern for the given vdev_id which is in AP mode. + * + * Return: QDF status + */ +static QDF_STATUS wma_wow_ap(tp_wma_handle wma, uint8_t vdev_id) +{ + QDF_STATUS ret; + uint8_t arp_offset = 20; + uint8_t mac_mask[IEEE80211_ADDR_LEN]; + struct wma_txrx_node *iface = &wma->interfaces[vdev_id]; + + /* + * Setup unicast pkt pattern + * WoW pattern id should be unique for each vdev + * WoW pattern id can be same on 2 different VDEVs + */ + qdf_mem_set(&mac_mask, IEEE80211_ADDR_LEN, 0xFF); + ret = wma_send_wow_patterns_to_fw(wma, vdev_id, + iface->num_wow_default_patterns++, + wma->interfaces[vdev_id].addr, + IEEE80211_ADDR_LEN, 0, mac_mask, + IEEE80211_ADDR_LEN, false); + if (ret != QDF_STATUS_SUCCESS) { + WMA_LOGE("Failed to add WOW unicast pattern ret %d", ret); + return ret; + } + + /* + * Setup all ARP pkt pattern. This is dummy pattern hence the length + * is zero. Pattern ID should be unique per vdev. + */ + ret = wma_send_wow_patterns_to_fw(wma, vdev_id, + iface->num_wow_default_patterns++, + arp_ptrn, 0, arp_offset, arp_mask, 0, false); + if (ret != QDF_STATUS_SUCCESS) { + WMA_LOGE("Failed to add WOW ARP pattern ret %d", ret); + return ret; + } + + return ret; +} + +/** + * wma_configure_wow_ssdp() - API to configure WoW SSDP + * @wma: WMA Handle + * @vdev_id: Vdev Id + * + * API to configure SSDP pattern as WoW pattern + * + * Return: Success/Failure + */ +static QDF_STATUS wma_configure_wow_ssdp(tp_wma_handle wma, uint8_t vdev_id) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + uint8_t discvr_offset = 30; + struct wma_txrx_node *iface = &wma->interfaces[vdev_id]; + + /* + * WoW pattern ID should be unique for each vdev + * Different WoW patterns can use same pattern ID + */ + status = wma_send_wow_patterns_to_fw(wma, vdev_id, + iface->num_wow_default_patterns++, + discvr_ptrn, sizeof(discvr_ptrn), discvr_offset, + discvr_mask, sizeof(discvr_ptrn), false); + + if (status != QDF_STATUS_SUCCESS) + WMA_LOGE("Failed to add WOW mDNS/SSDP/LLMNR pattern"); + + return status; +} + +/** + * wma_configure_mc_ssdp() - API to configure SSDP address as MC list + * @wma: WMA Handle + * @vdev_id: Vdev Id + * + * SSDP address 239.255.255.250 is converted to Multicast Mac address + * and configure it to FW. Firmware will apply this pattern on the incoming + * packets to filter them out during chatter/wow mode. + * + * Return: Success/Failure + */ +static QDF_STATUS wma_configure_mc_ssdp(tp_wma_handle wma, uint8_t vdev_id) +{ + WMI_SET_MCASTBCAST_FILTER_CMD_fixed_param *cmd; + wmi_buf_t buf; + const tSirMacAddr ssdp_addr = {0x01, 0x00, 0x5e, 0x7f, 0xff, 0xfa}; + int ret; + WMI_SET_MCASTBCAST_FILTER_CMD_fixed_param fixed_param; + uint32_t tag = + WMITLV_TAG_STRUC_WMI_SET_MCASTBCAST_FILTER_CMD_fixed_param; + + buf = wmi_buf_alloc(wma->wmi_handle, sizeof(*cmd)); + if (!buf) { + WMA_LOGE("%s No Memory for MC address", __func__); + return QDF_STATUS_E_NOMEM; + } + + cmd = (WMI_SET_MCASTBCAST_FILTER_CMD_fixed_param *) wmi_buf_data(buf); + + WMITLV_SET_HDR(&cmd->tlv_header, tag, + WMITLV_GET_STRUCT_TLVLEN(fixed_param)); + + cmd->action = WMI_MCAST_FILTER_SET; + cmd->vdev_id = vdev_id; + WMI_CHAR_ARRAY_TO_MAC_ADDR(ssdp_addr, &cmd->mcastbdcastaddr); + ret = wmi_unified_cmd_send(wma->wmi_handle, buf, sizeof(*cmd), + WMI_SET_MCASTBCAST_FILTER_CMDID); + if (ret != QDF_STATUS_SUCCESS) { + WMA_LOGE("%s Failed to configure FW with SSDP MC address", + __func__); + wmi_buf_free(buf); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * wma_configure_ssdp() - API to Configure SSDP pattern to FW + * @wma: WMA Handle + * @vdev_id: VDEV ID + * + * Setup multicast pattern for mDNS 224.0.0.251, SSDP 239.255.255.250 and LLMNR + * 224.0.0.252 + * + * Return: Success/Failure. + */ +static QDF_STATUS wma_configure_ssdp(tp_wma_handle wma, uint8_t vdev_id) +{ + if (!wma->ssdp) { + WMA_LOGD("mDNS, SSDP, LLMNR patterns are disabled from ini"); + return QDF_STATUS_SUCCESS; + } + + WMA_LOGD("%s, enable_mc_list:%d", __func__, wma->enable_mc_list); + + if (wma->enable_mc_list) + return wma_configure_mc_ssdp(wma, vdev_id); + + return wma_configure_wow_ssdp(wma, vdev_id); +} + +/** + * wma_register_action_frame_patterns() - register action frame map to fw + * @handle: Pointer to wma handle + * @vdev_id: VDEV ID + * + * This is called to push action frames wow patterns from local + * cache to firmware. + * + * Return: QDF_STATUS + */ +QDF_STATUS wma_register_action_frame_patterns(WMA_HANDLE handle, + uint8_t vdev_id) +{ + tp_wma_handle wma = handle; + struct action_wakeup_set_param cmd = {0}; + int32_t err; + int i = 0; + + cmd.vdev_id = vdev_id; + cmd.operation = WOW_ACTION_WAKEUP_OPERATION_SET; + + cmd.action_category_map[i++] = ALLOWED_ACTION_FRAMES_BITMAP0; + cmd.action_category_map[i++] = ALLOWED_ACTION_FRAMES_BITMAP1; + cmd.action_category_map[i++] = ALLOWED_ACTION_FRAMES_BITMAP2; + cmd.action_category_map[i++] = ALLOWED_ACTION_FRAMES_BITMAP3; + cmd.action_category_map[i++] = ALLOWED_ACTION_FRAMES_BITMAP4; + cmd.action_category_map[i++] = ALLOWED_ACTION_FRAMES_BITMAP5; + cmd.action_category_map[i++] = ALLOWED_ACTION_FRAMES_BITMAP6; + cmd.action_category_map[i++] = ALLOWED_ACTION_FRAMES_BITMAP7; + + for (i = 0; i < WMI_SUPPORTED_ACTION_CATEGORY_ELE_LIST; i++) { + if (i < ALLOWED_ACTION_FRAME_MAP_WORDS) + WMA_LOGD("%s: %d action Wakeup pattern 0x%x in fw", + __func__, i, cmd.action_category_map[i]); + else + cmd.action_category_map[i] = 0; + } + + err = wmi_unified_action_frame_patterns_cmd(wma->wmi_handle, &cmd); + if (err) { + WMA_LOGE("Failed to config wow action frame map, ret %d", err); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * wma_wow_sta() - set WOW patterns in sta mode + * @wma: wma handle + * @vdev_id: vdev id + * + * Configures default WOW pattern for the given vdev_id which is in sta mode. + * + * Return: QDF status + */ +static QDF_STATUS wma_wow_sta(tp_wma_handle wma, uint8_t vdev_id) +{ + uint8_t arp_offset = 12; + uint8_t mac_mask[IEEE80211_ADDR_LEN]; + QDF_STATUS ret = QDF_STATUS_SUCCESS; + struct wma_txrx_node *iface = &wma->interfaces[vdev_id]; + + qdf_mem_set(&mac_mask, IEEE80211_ADDR_LEN, 0xFF); + /* + * Set up unicast wow pattern + * WoW pattern ID should be unique for each vdev + * Different WoW patterns can use same pattern ID + */ + ret = wma_send_wow_patterns_to_fw(wma, vdev_id, + iface->num_wow_default_patterns++, + wma->interfaces[vdev_id].addr, + IEEE80211_ADDR_LEN, 0, mac_mask, + IEEE80211_ADDR_LEN, false); + if (ret != QDF_STATUS_SUCCESS) { + WMA_LOGE("Failed to add WOW unicast pattern ret %d", ret); + return ret; + } + + ret = wma_configure_ssdp(wma, vdev_id); + if (ret != QDF_STATUS_SUCCESS) + WMA_LOGE("Failed to configure SSDP patterns to FW"); + + /* when arp offload or ns offloaded is disabled + * from ini file, configure broad cast arp pattern + * to fw, so that host can wake up + */ + if (!(wma->ol_ini_info & 0x1)) { + /* Setup all ARP pkt pattern */ + WMA_LOGI("ARP offload is disabled in INI enable WoW for ARP"); + ret = wma_send_wow_patterns_to_fw(wma, vdev_id, + iface->num_wow_default_patterns++, + arp_ptrn, sizeof(arp_ptrn), arp_offset, + arp_mask, sizeof(arp_mask), false); + if (ret != QDF_STATUS_SUCCESS) { + WMA_LOGE("Failed to add WOW ARP pattern"); + return ret; + } + } + + /* for NS or NDP offload packets */ + if (!(wma->ol_ini_info & 0x2)) { + /* Setup all NS pkt pattern */ + WMA_LOGI("NS offload is disabled in INI enable WoW for NS"); + ret = wma_send_wow_patterns_to_fw(wma, vdev_id, + iface->num_wow_default_patterns++, + ns_ptrn, sizeof(arp_ptrn), arp_offset, + arp_mask, sizeof(arp_mask), false); + if (ret != QDF_STATUS_SUCCESS) { + WMA_LOGE("Failed to add WOW NS pattern"); + return ret; + } + } + + return ret; +} + +/** + * wma_register_wow_default_patterns() - register default wow patterns with fw + * @handle: Pointer to wma handle + * @vdev_id: vdev id + * + * WoW default wake up pattern rule is: + * - For STA & P2P CLI mode register for same STA specific wow patterns + * - For SAP/P2P GO & IBSS mode register for same SAP specific wow patterns + * + * Return: none + */ +void wma_register_wow_default_patterns(WMA_HANDLE handle, uint8_t vdev_id) +{ + tp_wma_handle wma = handle; + struct wma_txrx_node *iface; + + if (vdev_id > wma->max_bssid) { + WMA_LOGE("Invalid vdev id %d", vdev_id); + return; + } + iface = &wma->interfaces[vdev_id]; + + if (iface->ptrn_match_enable) { + if (wma_is_vdev_in_beaconning_mode(wma, vdev_id)) { + /* Configure SAP/GO/IBSS mode default wow patterns */ + WMA_LOGI("Config SAP specific default wow patterns vdev_id %d", + vdev_id); + wma_wow_ap(wma, vdev_id); + } else { + /* Configure STA/P2P CLI mode default wow patterns */ + WMA_LOGI("Config STA specific default wow patterns vdev_id %d", + vdev_id); + wma_wow_sta(wma, vdev_id); + if (wma->IsRArateLimitEnabled) { + WMA_LOGI("Config STA RA limit wow patterns vdev_id %d", + vdev_id); + wma_wow_sta_ra_filter(wma, vdev_id); + } + } + } + + return; +} + + +/** + * wma_register_wow_wakeup_events() - register vdev specific wake events with fw + * @handle: Pointer to wma handle + * @vdev_id: vdev Id + * @vdev_type: vdev type + * @vdev_subtype: vdev sub type + * + * WoW wake up event rule is following: + * 1) STA mode and P2P CLI mode wake up events are same + * 2) SAP mode and P2P GO mode wake up events are same + * 3) IBSS mode wake events are same as STA mode plus WOW_BEACON_EVENT + * + * Return: none + */ +void wma_register_wow_wakeup_events(WMA_HANDLE handle, + uint8_t vdev_id, + uint8_t vdev_type, + uint8_t vdev_subtype) +{ + tp_wma_handle wma = handle; + uint32_t event_bitmap[WMI_WOW_MAX_EVENT_BM_LEN] = {0}; + + WMA_LOGI("vdev_type %d vdev_subtype %d vdev_id %d", vdev_type, + vdev_subtype, vdev_id); + + if ((WMI_VDEV_TYPE_STA == vdev_type) || + ((WMI_VDEV_TYPE_AP == vdev_type) && + (WMI_UNIFIED_VDEV_SUBTYPE_P2P_DEVICE == vdev_subtype))) { + /* Configure STA/P2P CLI mode specific default wake up events */ + wma_set_sta_wow_bitmask(event_bitmap, + WMI_WOW_MAX_EVENT_BM_LEN); + + if ((wma->interfaces[vdev_id].in_bmps == true || + wma->in_imps == true) && + wma->auto_power_save_enabled) + wma_set_wow_event_bitmap( + WOW_CHIP_POWER_FAILURE_DETECT_EVENT, + WMI_WOW_MAX_EVENT_BM_LEN, + event_bitmap); + + } else if (WMI_VDEV_TYPE_IBSS == vdev_type) { + /* Configure IBSS mode specific default wake up events */ + wma_set_sta_wow_bitmask(event_bitmap, + WMI_WOW_MAX_EVENT_BM_LEN); + wma_set_wow_event_bitmap(WOW_BEACON_EVENT, + WMI_WOW_MAX_EVENT_BM_LEN, + event_bitmap); + } else if (WMI_VDEV_TYPE_AP == vdev_type) { + /* Configure SAP/GO mode specific default wake up events */ + wma_set_sap_wow_bitmask(event_bitmap, + WMI_WOW_MAX_EVENT_BM_LEN); + } else if (WMI_VDEV_TYPE_NDI == vdev_type) { + /* + * Configure NAN data path specific default wake up events. + * Following routine sends the command to firmware. + */ + wma_ndp_add_wow_wakeup_event(wma, vdev_id); + return; + } else { + WMA_LOGE("unknown type %d subtype %d", vdev_type, vdev_subtype); + return; + } + + wma_add_wow_wakeup_event(wma, vdev_id, event_bitmap, true); + + return; +} + +/** + * wma_enable_disable_wakeup_event() - Configures wow wakeup events + * @wma: wma handle + * @vdev_id: vdev id + * @bitmap: Event bitmap + * @enable: enable/disable + * + * Return: none + */ +void wma_enable_disable_wakeup_event(WMA_HANDLE handle, + uint32_t vdev_id, + uint32_t *bitmap, + bool enable) +{ + tp_wma_handle wma = handle; + uint32_t event_bitmap[WMI_WOW_MAX_EVENT_BM_LEN] = {0}; + + qdf_mem_copy(event_bitmap, bitmap, sizeof(uint32_t) * + WMI_WOW_MAX_EVENT_BM_LEN); + + WMA_LOGI("vdev_id %d wake up event 0x%x%x%x%x enable %d", + vdev_id, bitmap[0], bitmap[1], bitmap[2], bitmap[3], enable); + wma_add_wow_wakeup_event(wma, vdev_id, event_bitmap, enable); +} + +/** + * wma_enable_wow_in_fw() - wnable wow in fw + * @wma: wma handle + * @wow_flags: bitmap of WMI WOW flags to pass to FW + * + * Return: QDF status + */ +QDF_STATUS wma_enable_wow_in_fw(WMA_HANDLE handle, uint32_t wow_flags) +{ + tp_wma_handle wma = handle; + int ret; + struct hif_opaque_softc *scn; + int host_credits; + int wmi_pending_cmds; + struct wow_cmd_params param = {0}; + + tpAniSirGlobal pMac = cds_get_context(QDF_MODULE_ID_PE); + + if (NULL == pMac) { + WMA_LOGE("%s: Unable to get PE context", __func__); + return QDF_STATUS_E_FAILURE; + } + + qdf_event_reset(&wma->target_suspend); + wma->wow_nack = false; + + host_credits = wmi_get_host_credits(wma->wmi_handle); + wmi_pending_cmds = wmi_get_pending_cmds(wma->wmi_handle); + + WMA_LOGD("Credits:%d; Pending_Cmds: %d", + host_credits, wmi_pending_cmds); + + param.enable = true; + param.can_suspend_link = htc_can_suspend_link(wma->htc_handle); + param.flags = wow_flags; + ret = wmi_unified_wow_enable_send(wma->wmi_handle, ¶m, + WMA_WILDCARD_PDEV_ID); + if (ret) { + WMA_LOGE("Failed to enable wow in fw"); + goto error; + } + + wmi_set_target_suspend(wma->wmi_handle, true); + + if (qdf_wait_single_event(&wma->target_suspend, + WMA_TGT_SUSPEND_COMPLETE_TIMEOUT) + != QDF_STATUS_SUCCESS) { + WMA_LOGE("Failed to receive WoW Enable Ack from FW"); + WMA_LOGE("Credits:%d; Pending_Cmds: %d", + wmi_get_host_credits(wma->wmi_handle), + wmi_get_pending_cmds(wma->wmi_handle)); + wmi_set_target_suspend(wma->wmi_handle, false); + if (!cds_is_driver_recovering()) { + cds_trigger_recovery(false); + } else { + WMA_LOGE("%s: LOGP is in progress, ignore!", __func__); + } + + return QDF_STATUS_E_FAILURE; + } + + if (wma->wow_nack) { + WMA_LOGE("FW not ready to WOW"); + wmi_set_target_suspend(wma->wmi_handle, false); + return QDF_STATUS_E_AGAIN; + } + + host_credits = wmi_get_host_credits(wma->wmi_handle); + wmi_pending_cmds = wmi_get_pending_cmds(wma->wmi_handle); + + if (host_credits < WMI_WOW_REQUIRED_CREDITS) { + WMA_LOGE("%s: No Credits after HTC ACK:%d, pending_cmds:%d, " + "cannot resume back", __func__, host_credits, + wmi_pending_cmds); + htc_dump_counter_info(wma->htc_handle); + if (!cds_is_driver_recovering()) + cds_trigger_recovery(false); + else + WMA_LOGE("%s: SSR in progress, ignore no credit issue", + __func__); + } + + WMA_LOGD("WOW enabled successfully in fw: credits:%d" + "pending_cmds: %d", host_credits, wmi_pending_cmds); + + scn = cds_get_context(QDF_MODULE_ID_HIF); + + if (scn == NULL) { + WMA_LOGE("%s: Failed to get HIF context", __func__); + wmi_set_target_suspend(wma->wmi_handle, false); + QDF_ASSERT(0); + return QDF_STATUS_E_FAULT; + } + + wma->wow.wow_enable_cmd_sent = true; + + return QDF_STATUS_SUCCESS; + +error: + return QDF_STATUS_E_FAILURE; +} + +/** + * wma_resume_req() - clear configured wow patterns in fw + * @wma: wma handle + * @type: type of suspend + * + * Return: QDF status + */ +QDF_STATUS wma_resume_req(tp_wma_handle wma, enum qdf_suspend_type type) +{ + if (type == QDF_SYSTEM_SUSPEND) { + wma->no_of_resume_ind++; + + if (wma->no_of_resume_ind < wma_get_vdev_count(wma)) + return QDF_STATUS_SUCCESS; + + wma->no_of_resume_ind = 0; + } + + /* Reset the DTIM Parameters */ + wma_set_resume_dtim(wma); + /* need to reset if hif_pci_suspend_fails */ + wma_set_wow_bus_suspend(wma, 0); + /* unpause the vdev if left paused and hif_pci_suspend fails */ + wma_unpause_vdev(wma); + + wmi_set_runtime_pm_inprogress(wma->wmi_handle, false); + + if (type == QDF_RUNTIME_SUSPEND) + qdf_runtime_pm_allow_suspend(&wma->wma_runtime_resume_lock); + + return QDF_STATUS_SUCCESS; +} + +/** + * wma_wow_delete_pattern() - delete wow pattern in target + * @wma: wma handle + * @ptrn_id: pattern id + * @vdev_id: vdev id + * @user: true for user pattern and false for default pattern + * + * Return: QDF status + */ +static QDF_STATUS wma_wow_delete_pattern(tp_wma_handle wma, uint8_t ptrn_id, + uint8_t vdev_id, bool user) +{ + + struct wma_txrx_node *iface; + int ret; + + iface = &wma->interfaces[vdev_id]; + ret = wmi_unified_wow_delete_pattern_cmd(wma->wmi_handle, ptrn_id, + vdev_id); + if (ret) { + return QDF_STATUS_E_FAILURE; + } + + if (user) + iface->num_wow_user_patterns--; + + return QDF_STATUS_SUCCESS; +} + +/** + * wma_wow_add_pattern() - add wow pattern in target + * @wma: wma handle + * @ptrn: wow pattern + * + * This function does following: + * 1) Delete all default patterns of the vdev + * 2) Add received wow patterns for given vdev in target. + * + * Target is responsible for caching wow patterns accross multiple + * suspend/resumes until the pattern is deleted by user + * + * Return: QDF status + */ +QDF_STATUS wma_wow_add_pattern(tp_wma_handle wma, struct wow_add_pattern *ptrn) +{ + uint8_t id; + uint8_t bit_to_check, pos; + struct wma_txrx_node *iface; + QDF_STATUS ret = QDF_STATUS_SUCCESS; + uint8_t new_mask[SIR_WOWL_BCAST_PATTERN_MAX_SIZE]; + + if (ptrn->session_id > wma->max_bssid) { + WMA_LOGE("Invalid vdev id (%d)", ptrn->session_id); + return QDF_STATUS_E_INVAL; + } + + iface = &wma->interfaces[ptrn->session_id]; + + /* clear all default patterns cofigured by wma */ + for (id = 0; id < iface->num_wow_default_patterns; id++) + wma_wow_delete_pattern(wma, id, ptrn->session_id, false); + + iface->num_wow_default_patterns = 0; + + WMA_LOGI("Add user passed wow pattern id %d vdev id %d", + ptrn->pattern_id, ptrn->session_id); + /* + * Convert received pattern mask value from bit representation + * to byte representation. + * + * For example, received value from umac, + * + * Mask value : A1 (equivalent binary is "1010 0001") + * Pattern value : 12:00:13:00:00:00:00:44 + * + * The value which goes to FW after the conversion from this + * function (1 in mask value will become FF and 0 will + * become 00), + * + * Mask value : FF:00:FF:00:0:00:00:FF + * Pattern value : 12:00:13:00:00:00:00:44 + */ + qdf_mem_zero(new_mask, sizeof(new_mask)); + for (pos = 0; pos < ptrn->pattern_size; pos++) { + bit_to_check = (WMA_NUM_BITS_IN_BYTE - 1) - + (pos % WMA_NUM_BITS_IN_BYTE); + bit_to_check = 0x1 << bit_to_check; + if (ptrn->pattern_mask[pos / WMA_NUM_BITS_IN_BYTE] & + bit_to_check) + new_mask[pos] = WMA_WOW_PTRN_MASK_VALID; + } + + ret = wma_send_wow_patterns_to_fw(wma, ptrn->session_id, + ptrn->pattern_id, + ptrn->pattern, ptrn->pattern_size, + ptrn->pattern_byte_offset, new_mask, + ptrn->pattern_size, true); + if (ret != QDF_STATUS_SUCCESS) + WMA_LOGE("Failed to add wow pattern %d", ptrn->pattern_id); + + return ret; +} + +/** + * wma_wow_delete_user_pattern() - delete user configured wow pattern in target + * @wma: wma handle + * @ptrn: wow pattern + * + * This function does following: + * 1) Deletes a particular user configured wow pattern in target + * 2) After deleting all user wow patterns add default wow patterns + * specific to that vdev. + * + * Return: QDF status + */ +QDF_STATUS wma_wow_delete_user_pattern(tp_wma_handle wma, + struct wow_delete_pattern *pattern) +{ + struct wma_txrx_node *iface; + + if (pattern->session_id > wma->max_bssid) { + WMA_LOGE("Invalid vdev id %d", pattern->session_id); + return QDF_STATUS_E_INVAL; + } + + iface = &wma->interfaces[pattern->session_id]; + if (iface->num_wow_user_patterns <= 0) { + WMA_LOGE("No valid user pattern. Num user pattern %u vdev %d", + iface->num_wow_user_patterns, pattern->session_id); + return QDF_STATUS_E_INVAL; + } + + WMA_LOGI("Delete user passed wow pattern id %d total user pattern %d", + pattern->pattern_id, iface->num_wow_user_patterns); + + wma_wow_delete_pattern(wma, pattern->pattern_id, + pattern->session_id, true); + + /* configure default patterns once all user patterns are deleted */ + if (!iface->num_wow_user_patterns) + wma_register_wow_default_patterns(wma, pattern->session_id); + + return QDF_STATUS_SUCCESS; +} + +/** + * wma_wow_enter() - store enable/disable status for pattern + * @wma: wma handle + * @info: wow parameters + * + * Records pattern enable/disable status locally. This choice will + * take effect when the driver enter into suspend state. + * + * Return: QDF status + */ +QDF_STATUS wma_wow_enter(tp_wma_handle wma, tpSirHalWowlEnterParams info) +{ + struct wma_txrx_node *iface; + + WMA_LOGD("wow enable req received for vdev id: %d", info->sessionId); + + if (info->sessionId > wma->max_bssid) { + WMA_LOGE("Invalid vdev id (%d)", info->sessionId); + qdf_mem_free(info); + return QDF_STATUS_E_INVAL; + } + + iface = &wma->interfaces[info->sessionId]; + iface->ptrn_match_enable = info->ucPatternFilteringEnable ? + true : false; + wma->wow.magic_ptrn_enable = info->ucMagicPktEnable ? true : false; + wma->wow.deauth_enable = info->ucWowDeauthRcv ? true : false; + wma->wow.disassoc_enable = info->ucWowDeauthRcv ? true : false; + wma->wow.bmiss_enable = info->ucWowMaxMissedBeacons ? true : false; + + qdf_mem_free(info); + + return QDF_STATUS_SUCCESS; +} + +/** + * wma_wow_exit() - clear all wma states + * @wma: wma handle + * @info: wow params + * + * Return: QDF status + */ +QDF_STATUS wma_wow_exit(tp_wma_handle wma, tpSirHalWowlExitParams info) +{ + struct wma_txrx_node *iface; + + WMA_LOGD("wow disable req received for vdev id: %d", info->sessionId); + + if (info->sessionId > wma->max_bssid) { + WMA_LOGE("Invalid vdev id (%d)", info->sessionId); + qdf_mem_free(info); + return QDF_STATUS_E_INVAL; + } + + iface = &wma->interfaces[info->sessionId]; + iface->ptrn_match_enable = false; + wma->wow.magic_ptrn_enable = false; + qdf_mem_free(info); + + return QDF_STATUS_SUCCESS; +} + +/** + * wma_calculate_and_update_conn_state(): calculate each interfaces conn state + * @wma: validated wma handle + * + * Identifies any vdev that is up and not in ap mode as connected. + * stores this in the interfaces conn_state varible. + */ +void wma_calculate_and_update_conn_state(tp_wma_handle wma) +{ + int i; + for (i = 0; i < wma->max_bssid; i++) { + wma->interfaces[i].conn_state = + !!(wma->interfaces[i].vdev_up && + !wma_is_vdev_in_ap_mode(wma, i)); + } +} + +/** + * wma_update_conn_state(): synchronize wma & hdd + * @wma: wma handle + * @conn_state: boolean array to populate + * @len: validation parameter + * + * populate interfaces conn_state with true if the interface + * is a connected client and wow will configure a pattern. + */ +void wma_update_conn_state(tp_wma_handle wma, uint32_t conn_mask) +{ + int i; + for (i = 0; i < wma->max_bssid; i++) { + if (conn_mask & (1 << i)) + wma->interfaces[i].conn_state = true; + else + wma->interfaces[i].conn_state = false; + } + + if (wma->wow.magic_ptrn_enable) + return; + + for (i = 0; i < wma->max_bssid; i++) { + if (!wma->interfaces[i].ptrn_match_enable) + wma->interfaces[i].conn_state = false; + } +} + +/** + * wma_is_beaconning_vdev_up(): check if a beaconning vdev is up + * @wma: wma handle + * + * Return TRUE if beaconning vdev is up + */ +static inline +bool wma_is_beaconning_vdev_up(tp_wma_handle wma) +{ + int i; + for (i = 0; i < wma->max_bssid; i++) { + if (wma_is_vdev_in_beaconning_mode(wma, i) + && wma->interfaces[i].vdev_up) + return true; + } + return false; +} + +/** + * wma_support_wow_for_beaconing: wow query for beaconning + * @wma: wma handle + * + * Need to configure wow to enable beaconning offload when + * a beaconing vdev is up and beaonning offload is configured. + * + * Return: true if we need to enable wow for beaconning offload + */ +static inline +bool wma_support_wow_for_beaconing(tp_wma_handle wma) +{ + if (WMI_SERVICE_IS_ENABLED(wma->wmi_service_bitmap, + WMI_SERVICE_BEACON_OFFLOAD)) { + if (wma_is_beaconning_vdev_up(wma)) + return true; + } + return false; +} + +#ifdef FEATURE_WLAN_SCAN_PNO +/** + * wma_is_pnoscan_in_progress(): check if a pnoscan is in progress + * @wma: wma handle + * @vdev_id: vdev_id + * + * Return: TRUE/FALSE + */ +static inline +bool wma_is_pnoscan_in_progress(tp_wma_handle wma, int vdev_id) +{ + return wma->interfaces[vdev_id].pno_in_progress; +} + +/** + * wma_is_pnoscan_match_found(): check if a scan match was found + * @wma: wma handle + * @vdev_id: vdev_id + * + * Return: TRUE/FALSE + */ +static inline +bool wma_is_pnoscan_match_found(tp_wma_handle wma, int vdev_id) +{ + return wma->interfaces[vdev_id].nlo_match_evt_received; +} +#else +/** + * wma_is_pnoscan_in_progress(): dummy + * + * Return: False since no pnoscan cannot be in progress + * when feature flag is not defined. + */ +bool wma_is_pnoscan_in_progress(tp_wma_handle wma, int vdev_id) +{ + return FALSE; +} + +/** + * wma_is_pnoscan_match_found(): dummy + * @wma: wma handle + * @vdev_id: vdev_id + * + * Return: False since no pnoscan cannot occur + * when feature flag is not defined. + */ +static inline +bool wma_is_pnoscan_match_found(tp_wma_handle wma, int vdev_id) +{ + return FALSE; +} +#endif + +#ifdef FEATURE_WLAN_EXTSCAN +static inline +/** + * wma_is_extscan_in_progress(): check if an extscan is in progress + * @wma: wma handle + * @vdev_id: vdev_id + * + * Return: TRUE/FALSvE + */ +bool wma_is_extscan_in_progress(tp_wma_handle wma, int vdev_id) +{ + return wma->interfaces[vdev_id].extscan_in_progress; +} +#else +/** + * wma_is_extscan_in_progress(): dummy + * + * Return: False since no extscan can be in progress + * when feature flag is not defined. + */ +bool wma_is_extscan_in_progress(tp_wma_handle wma, int vdev_id) +{ + return false; +} +#endif + +/** + * wma_is_p2plo_in_progress(): check if P2P listen offload is in progress + * @wma: wma handle + * @vdev_id: vdev_id + * + * This function is to check if p2p listen offload is in progress, + * true: p2p listen offload in progress + * false: otherwise + * + * Return: TRUE/FALSE + */ +static inline +bool wma_is_p2plo_in_progress(tp_wma_handle wma, int vdev_id) +{ + return wma->interfaces[vdev_id].p2p_lo_in_progress; +} + +#ifdef WLAN_FEATURE_LPSS +/** + * wma_is_lpass_enabled() - check if lpass is enabled + * @handle: Pointer to wma handle + * + * WoW is needed if LPASS or NaN feature is enabled in INI because + * target can't wake up itself if its put in PDEV suspend when LPASS + * or NaN features are supported + * + * Return: true if lpass is enabled else false + */ +bool static wma_is_lpass_enabled(tp_wma_handle wma) +{ + if (wma->is_lpass_enabled) + return true; + else + return false; +} +#else +bool static wma_is_lpass_enabled(tp_wma_handle wma) +{ + return false; +} +#endif + +#ifdef WLAN_FEATURE_NAN +/** + * wma_is_nan_enabled() - check if NaN is enabled + * @handle: Pointer to wma handle + * + * WoW is needed if LPASS or NaN feature is enabled in INI because + * target can't wake up itself if its put in PDEV suspend when LPASS + * or NaN features are supported + * + * Return: true if NaN is enabled else false + */ +bool static wma_is_nan_enabled(tp_wma_handle wma) +{ + if (wma->is_nan_enabled) + return true; + else + return false; +} +#else +bool static wma_is_nan_enabled(tp_wma_handle wma) +{ + return false; +} +#endif + +/** + * wma_is_wow_applicable(): should enable wow + * @wma: wma handle + * + * Enable WOW if any one of the condition meets, + * 1) Is any one of vdev in beaconning mode (in AP mode) ? + * 2) Is any one of vdev in connected state (in STA mode) ? + * 3) Is PNO in progress in any one of vdev ? + * 4) Is Extscan in progress in any one of vdev ? + * 5) Is P2P listen offload in any one of vdev? + * 6) Is any vdev in NAN data mode? BSS is already started at the + * the time of device creation. It is ready to accept data + * requests. + * 7) If LPASS feature is enabled + * 8) If NaN feature is enabled + * If none of above conditions is true then return false + * + * Return: true if wma needs to configure wow false otherwise. + */ +static bool wma_is_wow_applicable(tp_wma_handle wma) +{ + int vdev_id; + if (wma_support_wow_for_beaconing(wma)) { + WMA_LOGD("vdev is in beaconning mode, enabling wow"); + return true; + } + + for (vdev_id = 0; vdev_id < wma->max_bssid; vdev_id++) { + if (wma->interfaces[vdev_id].conn_state) { + WMA_LOGD("STA is connected, enabling wow"); + return true; + } else if (wma_is_pnoscan_in_progress(wma, vdev_id)) { + WMA_LOGD("PNO is in progress, enabling wow"); + return true; + } else if (wma_is_extscan_in_progress(wma, vdev_id)) { + WMA_LOGD("EXT is in progress, enabling wow"); + return true; + } else if (wma_is_p2plo_in_progress(wma, vdev_id)) { + WMA_LOGD("P2P LO is in progress, enabling wow"); + return true; + } else if (wma_is_lpass_enabled(wma)) { + WMA_LOGD("LPASS is enabled, enabling WoW"); + return true; + } else if (wma_is_nan_enabled(wma)) { + WMA_LOGD("NAN is enabled, enabling WoW"); + return true; + } else if (WMA_IS_VDEV_IN_NDI_MODE(wma->interfaces, vdev_id)) { + WMA_LOGD("vdev %d is in NAN data mode, enabling wow", + vdev_id); + return true; + } + } + + WMA_LOGD("All vdev are in disconnected state and pno/extscan is not in progress, skipping wow"); + return false; +} + +/* Define for conciseness */ +#define BM_LEN WMI_WOW_MAX_EVENT_BM_LEN +#define EV_NLO WOW_NLO_SCAN_COMPLETE_EVENT +#define EV_PWR WOW_CHIP_POWER_FAILURE_DETECT_EVENT +/** + * wma_configure_dynamic_wake_events(): configure dyanmic wake events + * @wma: wma handle + * + * Some wake events need to be enabled dynamically. Controll those here. + * + * Return: none + */ +static void wma_configure_dynamic_wake_events(tp_wma_handle wma) +{ + + int vdev_id; + uint32_t enable_mask[BM_LEN] = {0}; + uint32_t disable_mask[BM_LEN] = {0}; + bool enable_configured = false; + bool disable_configured = false; + ol_txrx_vdev_handle vdev; + + for (vdev_id = 0; vdev_id < wma->max_bssid; vdev_id++) { + + qdf_mem_set(enable_mask, sizeof(uint32_t) * BM_LEN, 0); + qdf_mem_set(disable_mask, sizeof(uint32_t) * BM_LEN, 0); + vdev = wma_find_vdev_by_id(wma, vdev_id); + if (NULL == vdev) { + WMA_LOGP("%s: Couldn't find vdev for vdev_id: %d", + __func__, vdev_id); + continue; + } + + if (wma_is_pnoscan_in_progress(wma, vdev_id)) { + if (wma_is_pnoscan_match_found(wma, vdev_id)) { + wma_set_wow_event_bitmap(EV_NLO, + BM_LEN, + enable_mask); + enable_configured = true; + } else + wma_set_wow_event_bitmap(EV_NLO, + BM_LEN, + disable_mask); + disable_configured = true; + } + if ((wma->interfaces[vdev_id].in_bmps == true || + wma->in_imps == true) && + (wma->interfaces[vdev_id].type == WMI_VDEV_TYPE_STA || + (wma->interfaces[vdev_id].type == WMI_VDEV_TYPE_AP && + (wma->interfaces[vdev_id].sub_type == + WMI_UNIFIED_VDEV_SUBTYPE_P2P_DEVICE || + wma->interfaces[vdev_id].sub_type == + WMI_UNIFIED_VDEV_SUBTYPE_P2P_CLIENT))) && + wma->auto_power_save_enabled) { + wma_set_wow_event_bitmap(EV_PWR, + BM_LEN, + enable_mask); + enable_configured = true; + } + if (enable_configured) { + wma_enable_disable_wakeup_event(wma, vdev_id, + enable_mask, true); + } + + if (disable_configured) { + wma_enable_disable_wakeup_event(wma, vdev_id, + disable_mask, false); + } + + enable_configured = false; + disable_configured = false; + } +} +#undef BM_LEN +#undef EV_NLO +#undef EV_PWR + +#ifdef FEATURE_WLAN_LPHB +/** + * wma_apply_lphb(): apply cached LPHB settings + * @wma: wma handle + * + * LPHB cache, if any item was enabled, should be + * applied. + */ +static inline +void wma_apply_lphb(tp_wma_handle wma) +{ + int i; + WMA_LOGD("%s: checking LPHB cache", __func__); + for (i = 0; i < 2; i++) { + if (wma->wow.lphb_cache[i].params.lphbEnableReq.enable) { + WMA_LOGD("%s: LPHB cache for item %d is marked as enable", + __func__, i + 1); + wma_lphb_conf_hbenable(wma, &(wma->wow.lphb_cache[i]), + false); + } + } +} +#else +void wma_apply_lphb(tp_wma_handle wma) {} +#endif /* FEATURE_WLAN_LPHB */ + +static void wma_notify_suspend_req_procesed(tp_wma_handle wma, + enum qdf_suspend_type type) +{ + if (type == QDF_SYSTEM_SUSPEND) + wma_send_status_to_suspend_ind(wma, true); + else if (type == QDF_RUNTIME_SUSPEND) + qdf_event_set(&wma->runtime_suspend); +} + +/** + * wma_suspend_req() - Handles suspend indication request received from umac. + * @wma: wma handle + * @type: type of suspend + * + * The type controlls how we notify the indicator that the indication has + * been processed + * + * Return: QDF status + */ +QDF_STATUS wma_suspend_req(tp_wma_handle wma, enum qdf_suspend_type type) +{ + if (type == QDF_RUNTIME_SUSPEND) + wmi_set_runtime_pm_inprogress(wma->wmi_handle, true); + + if (wma_is_wow_applicable(wma)) { + WMA_LOGI("WOW Suspend"); + wma_apply_lphb(wma); + + wma_configure_dynamic_wake_events(wma); + + wma->wow.wow_enable = true; + wma->wow.wow_enable_cmd_sent = false; + } + + /* Set the Suspend DTIM Parameters */ + wma_set_suspend_dtim(wma); + + wma_notify_suspend_req_procesed(wma, type); + + /* to handle race between hif_pci_suspend and + * unpause/pause tx handler + */ + wma_set_wow_bus_suspend(wma, 1); + + return QDF_STATUS_SUCCESS; +} + +/** + * wma_send_host_wakeup_ind_to_fw() - send wakeup ind to fw + * @wma: wma handle + * + * Sends host wakeup indication to FW. On receiving this indication, + * FW will come out of WOW. + * + * Return: QDF status + */ +static QDF_STATUS wma_send_host_wakeup_ind_to_fw(tp_wma_handle wma) +{ + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + int ret; + tpAniSirGlobal pMac = cds_get_context(QDF_MODULE_ID_PE); + if (NULL == pMac) { + WMA_LOGE("%s: Unable to get PE context", __func__); + return QDF_STATUS_E_FAILURE; + } + + qdf_event_reset(&wma->wma_resume_event); + + ret = wmi_unified_host_wakeup_ind_to_fw_cmd(wma->wmi_handle); + if (ret) { + return QDF_STATUS_E_FAILURE; + } + + WMA_LOGD("Host wakeup indication sent to fw"); + + qdf_status = qdf_wait_single_event(&(wma->wma_resume_event), + WMA_RESUME_TIMEOUT); + if (QDF_STATUS_SUCCESS != qdf_status) { + WMA_LOGP("%s: Timeout waiting for resume event from FW", + __func__); + WMA_LOGP("%s: Pending commands %d credits %d", __func__, + wmi_get_pending_cmds(wma->wmi_handle), + wmi_get_host_credits(wma->wmi_handle)); + if (!cds_is_driver_recovering()) { + wmi_tag_crash_inject(wma->wmi_handle, true); + cds_trigger_recovery(false); + } else { + WMA_LOGE("%s: SSR in progress, ignore resume timeout", + __func__); + } + } else { + WMA_LOGD("Host wakeup received"); + } + + if (QDF_STATUS_SUCCESS == qdf_status) + wmi_set_target_suspend(wma->wmi_handle, false); + + return qdf_status; +} + +/** + * wma_disable_wow_in_fw() - Disable wow in PCIe resume context. + * @handle: wma handle + * + * Return: 0 for success or error code + */ +QDF_STATUS wma_disable_wow_in_fw(WMA_HANDLE handle) +{ + tp_wma_handle wma = handle; + QDF_STATUS ret; + + ret = wma_send_host_wakeup_ind_to_fw(wma); + + if (ret != QDF_STATUS_SUCCESS) + return ret; + + wma->wow.wow_enable = false; + wma->wow.wow_enable_cmd_sent = false; + + /* To allow the tx pause/unpause events */ + wma_set_wow_bus_suspend(wma, 0); + /* Unpause the vdev as we are resuming */ + wma_unpause_vdev(wma); + + return ret; +} + + +/** + * wma_is_wow_mode_selected() - check if wow needs to be enabled in fw + * @handle: Pointer to wma handle + * + * If lpass is enabled then always do wow else check wow_enable config + * + * Return: true is wow mode is needed else false + */ +bool wma_is_wow_mode_selected(WMA_HANDLE handle) +{ + tp_wma_handle wma = (tp_wma_handle) handle; + WMA_LOGD("WoW enable %d", wma->wow.wow_enable); + return wma->wow.wow_enable; +} + +/** + * wma_del_ts_req() - send DELTS request to fw + * @wma: wma handle + * @msg: delts params + * + * Return: none + */ +void wma_del_ts_req(tp_wma_handle wma, tDelTsParams *msg) +{ + if (wmi_unified_del_ts_cmd(wma->wmi_handle, + msg->sessionId, + TID_TO_WME_AC(msg->userPrio))) { + WMA_LOGP("%s: Failed to send vdev DELTS command", __func__); + } + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + if (msg->setRICparams == true) + wma_set_ric_req(wma, msg, false); +#endif /* WLAN_FEATURE_ROAM_OFFLOAD */ + + qdf_mem_free(msg); +} + +/** + * wma_aggr_qos_req() - send aggr qos request to fw + * @wma: handle to wma + * @pAggrQosRspMsg - combined struct for all ADD_TS requests. + * + * A function to handle WMA_AGGR_QOS_REQ. This will send out + * ADD_TS requestes to firmware in loop for all the ACs with + * active flow. + * + * Return: none + */ +void wma_aggr_qos_req(tp_wma_handle wma, + tAggrAddTsParams *pAggrQosRspMsg) +{ + wmi_unified_aggr_qos_cmd(wma->wmi_handle, + (struct aggr_add_ts_param *)pAggrQosRspMsg); + /* send reponse to upper layers from here only. */ + wma_send_msg(wma, WMA_AGGR_QOS_RSP, pAggrQosRspMsg, 0); +} + +#ifdef FEATURE_WLAN_ESE +/** + * wma_set_tsm_interval() - Set TSM interval + * @req: pointer to ADDTS request + * + * Return: QDF_STATUS_E_FAILURE or QDF_STATUS_SUCCESS + */ +static QDF_STATUS wma_set_tsm_interval(tAddTsParams *req) +{ + /* + * msmt_interval is in unit called TU (1 TU = 1024 us) + * max value of msmt_interval cannot make resulting + * interval_milliseconds overflow 32 bit + * + */ + uint32_t interval_milliseconds; + ol_txrx_pdev_handle pdev = cds_get_context(QDF_MODULE_ID_TXRX); + if (NULL == pdev) { + WMA_LOGE("%s: Failed to get pdev", __func__); + return QDF_STATUS_E_FAILURE; + } + + interval_milliseconds = (req->tsm_interval * 1024) / 1000; + + ol_tx_set_compute_interval(pdev, interval_milliseconds); + return QDF_STATUS_SUCCESS; +} +#else +static inline QDF_STATUS wma_set_tsm_interval(tAddTsParams *req) +{ + return QDF_STATUS_SUCCESS; +} +#endif /* FEATURE_WLAN_ESE */ + +/** + * wma_add_ts_req() - send ADDTS request to fw + * @wma: wma handle + * @msg: ADDTS params + * + * Return: none + */ +void wma_add_ts_req(tp_wma_handle wma, tAddTsParams *msg) +{ + struct add_ts_param cmd = {0}; + msg->status = QDF_STATUS_SUCCESS; + + if (wma_set_tsm_interval(msg) == QDF_STATUS_SUCCESS) { + + cmd.sme_session_id = msg->sme_session_id; + cmd.tspec.tsinfo.traffic.userPrio = + TID_TO_WME_AC(msg->tspec.tsinfo.traffic.userPrio); + cmd.tspec.mediumTime = msg->tspec.mediumTime; + if (wmi_unified_add_ts_cmd(wma->wmi_handle, &cmd)) + msg->status = QDF_STATUS_E_FAILURE; + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + if (msg->setRICparams == true) + wma_set_ric_req(wma, msg, true); +#endif /* WLAN_FEATURE_ROAM_OFFLOAD */ + + } + wma_send_msg(wma, WMA_ADD_TS_RSP, msg, 0); +} + +/** + * wma_enable_disable_packet_filter() - enable/disable packet filter in target + * @wma: Pointer to wma handle + * @vdev_id: vdev id + * @enable: Flag to enable/disable packet filter + * + * Return: 0 for success or error code + */ +static int wma_enable_disable_packet_filter(tp_wma_handle wma, + uint8_t vdev_id, bool enable) +{ + int ret; + + ret = wmi_unified_enable_disable_packet_filter_cmd(wma->wmi_handle, + vdev_id, enable); + if (ret) + WMA_LOGE("Failed to send packet filter wmi cmd to fw"); + + return ret; +} + +/** + * wma_config_packet_filter() - configure packet filter in target + * @wma: Pointer to wma handle + * @vdev_id: vdev id + * @rcv_filter_param: Packet filter parameters + * @filter_id: Filter id + * @enable: Flag to add/delete packet filter configuration + * + * Return: 0 for success or error code + */ +static int wma_config_packet_filter(tp_wma_handle wma, + uint8_t vdev_id, tSirRcvPktFilterCfgType *rcv_filter_param, + uint8_t filter_id, bool enable) +{ + int err; + + /* send the command along with data */ + err = wmi_unified_config_packet_filter_cmd(wma->wmi_handle, + vdev_id, (struct rcv_pkt_filter_config *)rcv_filter_param, + filter_id, enable); + if (err) { + WMA_LOGE("Failed to send pkt_filter cmd"); + return -EIO; + } + + /* Enable packet filter */ + if (enable) + wma_enable_disable_packet_filter(wma, vdev_id, true); + + return 0; +} + +/** + * wma_process_receive_filter_set_filter_req() - enable packet filter + * @wma_handle: wma handle + * @rcv_filter_param: filter params + * + * Return: 0 for success or error code + */ +int wma_process_receive_filter_set_filter_req(tp_wma_handle wma, + tSirRcvPktFilterCfgType *rcv_filter_param) +{ + int ret = 0; + uint8_t vdev_id; + + /* Get the vdev id */ + if (!wma_find_vdev_by_bssid(wma, + rcv_filter_param->bssid.bytes, &vdev_id)) { + WMA_LOGE("vdev handle is invalid for %pM", + rcv_filter_param->bssid.bytes); + return -EINVAL; + } + + ret = wma_config_packet_filter(wma, vdev_id, rcv_filter_param, + rcv_filter_param->filterId, true); + + return ret; +} + +/** + * wma_process_receive_filter_clear_filter_req() - disable packet filter + * @wma_handle: wma handle + * @rcv_clear_param: filter params + * + * Return: 0 for success or error code + */ +int wma_process_receive_filter_clear_filter_req(tp_wma_handle wma, + tSirRcvFltPktClearParam *rcv_clear_param) +{ + int ret = 0; + uint8_t vdev_id; + + /* Get the vdev id */ + if (!wma_find_vdev_by_addr(wma, + rcv_clear_param->self_macaddr.bytes, + &vdev_id)) { + WMA_LOGE("vdev handle is invalid for %pM", + rcv_clear_param->bssid.bytes); + return -EINVAL; + } + + ret = wma_config_packet_filter(wma, vdev_id, NULL, + rcv_clear_param->filterId, false); + + return ret; +} + +#ifdef FEATURE_WLAN_ESE + +#define TSM_DELAY_HISTROGRAM_BINS 4 +/** + * wma_process_tsm_stats_req() - process tsm stats request + * @wma_handler - handle to wma + * @pTsmStatsMsg - TSM stats struct that needs to be populated and + * passed in message. + * + * A parallel function to WMA_ProcessTsmStatsReq for pronto. This + * function fetches stats from data path APIs and post + * WMA_TSM_STATS_RSP msg back to LIM. + * + * Return: QDF status + */ +QDF_STATUS wma_process_tsm_stats_req(tp_wma_handle wma_handler, + void *pTsmStatsMsg) +{ + uint8_t counter; + uint32_t queue_delay_microsec = 0; + uint32_t tx_delay_microsec = 0; + uint16_t packet_count = 0; + uint16_t packet_loss_count = 0; + tpAniTrafStrmMetrics pTsmMetric = NULL; + tpAniGetTsmStatsReq pStats = (tpAniGetTsmStatsReq) pTsmStatsMsg; + tpAniGetTsmStatsRsp pTsmRspParams = NULL; + int tid = pStats->tid; + /* + * The number of histrogram bin report by data path api are different + * than required by TSM, hence different (6) size array used + */ + uint16_t bin_values[QCA_TX_DELAY_HIST_REPORT_BINS] = { 0, }; + + ol_txrx_pdev_handle pdev = cds_get_context(QDF_MODULE_ID_TXRX); + + if (NULL == pdev) { + WMA_LOGE("%s: Failed to get pdev", __func__); + qdf_mem_free(pTsmStatsMsg); + return QDF_STATUS_E_INVAL; + } + + /* get required values from data path APIs */ + ol_tx_delay(pdev, &queue_delay_microsec, &tx_delay_microsec, tid); + ol_tx_delay_hist(pdev, bin_values, tid); + ol_tx_packet_count(pdev, &packet_count, &packet_loss_count, tid); + + pTsmRspParams = qdf_mem_malloc(sizeof(*pTsmRspParams)); + if (NULL == pTsmRspParams) { + QDF_TRACE(QDF_MODULE_ID_WMA, QDF_TRACE_LEVEL_ERROR, + "%s: QDF MEM Alloc Failure", __func__); + QDF_ASSERT(0); + qdf_mem_free(pTsmStatsMsg); + return QDF_STATUS_E_NOMEM; + } + pTsmRspParams->staId = pStats->staId; + pTsmRspParams->rc = eSIR_FAILURE; + pTsmRspParams->tsmStatsReq = pStats; + pTsmMetric = &pTsmRspParams->tsmMetrics; + /* populate pTsmMetric */ + pTsmMetric->UplinkPktQueueDly = queue_delay_microsec; + /* store only required number of bin values */ + for (counter = 0; counter < TSM_DELAY_HISTROGRAM_BINS; counter++) { + pTsmMetric->UplinkPktQueueDlyHist[counter] = + bin_values[counter]; + } + pTsmMetric->UplinkPktTxDly = tx_delay_microsec; + pTsmMetric->UplinkPktLoss = packet_loss_count; + pTsmMetric->UplinkPktCount = packet_count; + + /* + * No need to populate roaming delay and roaming count as they are + * being populated just before sending IAPP frame out + */ + /* post this message to LIM/PE */ + wma_send_msg(wma_handler, WMA_TSM_STATS_RSP, (void *)pTsmRspParams, 0); + return QDF_STATUS_SUCCESS; +} + +#endif /* FEATURE_WLAN_ESE */ + +/** + * wma_add_clear_mcbc_filter() - set mcast filter command to fw + * @wma_handle: wma handle + * @vdev_id: vdev id + * @multicastAddr: mcast address + * @clearList: clear list flag + * + * Return: 0 for success or error code + */ +static QDF_STATUS wma_add_clear_mcbc_filter(tp_wma_handle wma_handle, + uint8_t vdev_id, + struct qdf_mac_addr multicast_addr, + bool clearList) +{ + return wmi_unified_add_clear_mcbc_filter_cmd(wma_handle->wmi_handle, + vdev_id, multicast_addr, clearList); +} + +/** + * wma_config_enhance_multicast_offload() - config enhance multicast offload + * @wma_handle: wma handle + * @vdev_id: vdev id + * @action: enable or disable enhance multicast offload + * + * Return: none + */ +static void wma_config_enhance_multicast_offload(tp_wma_handle wma_handle, + uint8_t vdev_id, + uint8_t action) +{ + int status; + wmi_buf_t buf; + wmi_config_enhanced_mcast_filter_cmd_fixed_param *cmd; + + buf = wmi_buf_alloc(wma_handle->wmi_handle, sizeof(*cmd)); + if (!buf) { + WMA_LOGE("Failed to allocate buffer to send set key cmd"); + return; + } + + cmd = (wmi_config_enhanced_mcast_filter_cmd_fixed_param *) + wmi_buf_data(buf); + + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_config_enhanced_mcast_filter_fixed_param, + WMITLV_GET_STRUCT_TLVLEN(wmi_config_enhanced_mcast_filter_cmd_fixed_param)); + + cmd->vdev_id = vdev_id; + cmd->enable = ((0 == action) ? ENHANCED_MCAST_FILTER_DISABLED : + ENHANCED_MCAST_FILTER_ENABLED); + + WMA_LOGD("%s: config enhance multicast offload action %d for vdev %d", + __func__, action, vdev_id); + + status = wmi_unified_cmd_send(wma_handle->wmi_handle, buf, + sizeof(*cmd), WMI_CONFIG_ENHANCED_MCAST_FILTER_CMDID); + if (status) { + qdf_nbuf_free(buf); + WMA_LOGE("%s:Failed to send WMI_CONFIG_ENHANCED_MCAST_FILTER_CMDID", + __func__); + } + + return; +} + +/** + * wma_process_mcbc_set_filter_req() - process mcbc set filter request + * @wma_handle: wma handle + * @mcbc_param: mcbc params + * + * Return: QDF status + */ +QDF_STATUS wma_process_mcbc_set_filter_req(tp_wma_handle wma_handle, + tSirRcvFltMcAddrList *mcbc_param) +{ + uint8_t vdev_id = 0; + int i; + + if (mcbc_param->ulMulticastAddrCnt <= 0) { + WMA_LOGW("Number of multicast addresses is 0"); + return QDF_STATUS_E_FAILURE; + } else if (mcbc_param->ulMulticastAddrCnt > + CFG_TGT_MAX_MULTICAST_FILTER_ENTRIES) { + WMA_LOGW("Number of multicast addresses %u is more than max %u", + mcbc_param->ulMulticastAddrCnt, + CFG_TGT_MAX_MULTICAST_FILTER_ENTRIES); + return QDF_STATUS_E_FAILURE; + } + + if (!wma_find_vdev_by_addr(wma_handle, + mcbc_param->self_macaddr.bytes, &vdev_id)) { + WMA_LOGE("%s: Failed to find vdev id for %pM", __func__, + mcbc_param->bssid.bytes); + return QDF_STATUS_E_FAILURE; + } + + /* + * Configure enhance multicast offload feature for filtering out + * multicast IP data packets transmitted using unicast MAC address + */ + if (WMI_SERVICE_IS_ENABLED(wma_handle->wmi_service_bitmap, + WMI_SERVICE_ENHANCED_MCAST_FILTER)) { + WMA_LOGD("%s: FW supports enhance multicast offload", __func__); + wma_config_enhance_multicast_offload(wma_handle, vdev_id, + mcbc_param->action); + } else { + WMA_LOGD("%s: FW does not support enhance multicast offload", + __func__); + } + + /* set mcbc_param->action to clear MCList and reset + * to configure the MCList in FW + */ + + for (i = 0; i < mcbc_param->ulMulticastAddrCnt; i++) { + wma_add_clear_mcbc_filter(wma_handle, vdev_id, + mcbc_param->multicastAddr[i], + (mcbc_param->action == 0)); + } + return QDF_STATUS_SUCCESS; +} + +#ifdef WLAN_FEATURE_GTK_OFFLOAD +#define GTK_OFFLOAD_ENABLE 0 +#define GTK_OFFLOAD_DISABLE 1 + +/** + * wma_gtk_offload_status_event() - GTK offload status event handler + * @handle: wma handle + * @event: event buffer + * @len: buffer length + * + * Return: 0 for success or error code + */ +int wma_gtk_offload_status_event(void *handle, uint8_t *event, + uint32_t len) +{ + tp_wma_handle wma = (tp_wma_handle) handle; + WMI_GTK_OFFLOAD_STATUS_EVENT_fixed_param *status; + WMI_GTK_OFFLOAD_STATUS_EVENTID_param_tlvs *param_buf; + tpSirGtkOffloadGetInfoRspParams resp; + cds_msg_t cds_msg; + uint8_t *bssid; + + WMA_LOGD("%s Enter", __func__); + + param_buf = (WMI_GTK_OFFLOAD_STATUS_EVENTID_param_tlvs *) event; + if (!param_buf) { + WMA_LOGE("param_buf is NULL"); + return -EINVAL; + } + + status = (WMI_GTK_OFFLOAD_STATUS_EVENT_fixed_param *) param_buf->fixed_param; + + if (len < sizeof(WMI_GTK_OFFLOAD_STATUS_EVENT_fixed_param)) { + WMA_LOGE("Invalid length for GTK status"); + return -EINVAL; + } + bssid = wma_find_bssid_by_vdev_id(wma, status->vdev_id); + if (!bssid) { + WMA_LOGE("invalid bssid for vdev id %d", status->vdev_id); + return -ENOENT; + } + + resp = qdf_mem_malloc(sizeof(*resp)); + if (!resp) { + WMA_LOGE("%s: Failed to alloc response", __func__); + return -ENOMEM; + } + qdf_mem_zero(resp, sizeof(*resp)); + resp->mesgType = eWNI_PMC_GTK_OFFLOAD_GETINFO_RSP; + resp->mesgLen = sizeof(*resp); + resp->ulStatus = QDF_STATUS_SUCCESS; + resp->ulTotalRekeyCount = status->refresh_cnt; + /* TODO: Is the total rekey count and GTK rekey count same? */ + resp->ulGTKRekeyCount = status->refresh_cnt; + + qdf_mem_copy(&resp->ullKeyReplayCounter, &status->replay_counter, + GTK_REPLAY_COUNTER_BYTES); + + qdf_mem_copy(resp->bssid.bytes, bssid, IEEE80211_ADDR_LEN); + +#ifdef IGTK_OFFLOAD + /* TODO: Is the refresh count same for GTK and IGTK? */ + resp->ulIGTKRekeyCount = status->refresh_cnt; +#endif /* IGTK_OFFLOAD */ + + cds_msg.type = eWNI_PMC_GTK_OFFLOAD_GETINFO_RSP; + cds_msg.bodyptr = (void *)resp; + cds_msg.bodyval = 0; + + if (cds_mq_post_message(CDS_MQ_ID_SME, (cds_msg_t *) &cds_msg) + != QDF_STATUS_SUCCESS) { + WMA_LOGE("Failed to post GTK response to SME"); + qdf_mem_free(resp); + return -EINVAL; + } + + WMA_LOGD("GTK: got target status with replay counter " + "%02x%02x%02x%02x%02x%02x%02x%02x. vdev %d " + "Refresh GTK %d times exchanges since last set operation", + status->replay_counter[0], + status->replay_counter[1], + status->replay_counter[2], + status->replay_counter[3], + status->replay_counter[4], + status->replay_counter[5], + status->replay_counter[6], + status->replay_counter[7], + status->vdev_id, status->refresh_cnt); + + WMA_LOGD("%s Exit", __func__); + + return 0; +} + +/** + * wma_send_gtk_offload_req() - send GTK offload command to fw + * @wma: wma handle + * @vdev_id: vdev id + * @params: GTK offload parameters + * + * Return: QDF status + */ +static QDF_STATUS wma_send_gtk_offload_req(tp_wma_handle wma, uint8_t vdev_id, + tpSirGtkOffloadParams params) +{ + struct gtk_offload_params offload_params = {0}; + QDF_STATUS status = QDF_STATUS_SUCCESS; + bool enable_offload; + uint32_t gtk_offload_opcode; + + WMA_LOGD("%s Enter", __func__); + + /* Request target to enable GTK offload */ + if (params->ulFlags == GTK_OFFLOAD_ENABLE) { + gtk_offload_opcode = GTK_OFFLOAD_ENABLE_OPCODE; + wma->wow.gtk_err_enable[vdev_id] = true; + + /* Copy the keys and replay counter */ + qdf_mem_copy(offload_params.aKCK, params->aKCK, + GTK_OFFLOAD_KCK_BYTES); + qdf_mem_copy(offload_params.aKEK, params->aKEK, + GTK_OFFLOAD_KEK_BYTES); + qdf_mem_copy(&offload_params.ullKeyReplayCounter, + ¶ms->ullKeyReplayCounter, GTK_REPLAY_COUNTER_BYTES); + } else { + wma->wow.gtk_err_enable[vdev_id] = false; + gtk_offload_opcode = GTK_OFFLOAD_DISABLE_OPCODE; + } + + enable_offload = params->ulFlags; + + /* send the wmi command */ + status = wmi_unified_send_gtk_offload_cmd(wma->wmi_handle, + vdev_id, &offload_params, + enable_offload, + gtk_offload_opcode); + if (QDF_IS_STATUS_ERROR(status)) + goto out; + + WMA_LOGD("VDEVID: %d, GTK_FLAGS: x%x", vdev_id, gtk_offload_opcode); +out: + WMA_LOGD("%s Exit", __func__); + return status; +} + +/** + * wma_process_gtk_offload_req() - process GTK offload req from umac + * @handle: wma handle + * @params: GTK offload params + * + * Return: QDF status + */ +QDF_STATUS wma_process_gtk_offload_req(tp_wma_handle wma, + tpSirGtkOffloadParams params) +{ + uint8_t vdev_id; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + WMA_LOGD("%s Enter", __func__); + + WMA_LOGD("%s replay_ctr 0x%llx", __func__, + params->ullKeyReplayCounter); + + /* Get the vdev id */ + if (!wma_find_vdev_by_bssid(wma, params->bssid.bytes, &vdev_id)) { + WMA_LOGE("vdev handle is invalid for %pM", params->bssid.bytes); + status = QDF_STATUS_E_INVAL; + goto out; + } + + /* Validate vdev id */ + if (vdev_id >= WMA_MAX_SUPPORTED_BSS) { + WMA_LOGE("invalid vdev_id %d for %pM", vdev_id, + params->bssid.bytes); + status = QDF_STATUS_E_INVAL; + goto out; + } + + if ((params->ulFlags == GTK_OFFLOAD_ENABLE) && + (wma->wow.gtk_err_enable[vdev_id] == true)) { + WMA_LOGE("%s GTK Offload already enabled. Disable it first " + "vdev_id %d", __func__, vdev_id); + params->ulFlags = GTK_OFFLOAD_DISABLE; + status = wma_send_gtk_offload_req(wma, vdev_id, params); + if (status != QDF_STATUS_SUCCESS) { + WMA_LOGE("%s Failed to disable GTK Offload", __func__); + goto out; + } + WMA_LOGD("%s Enable GTK Offload again with updated inputs", + __func__); + params->ulFlags = GTK_OFFLOAD_ENABLE; + } + status = wma_send_gtk_offload_req(wma, vdev_id, params); +out: + qdf_mem_free(params); + WMA_LOGD("%s Exit", __func__); + return status; +} + +/** + * wma_process_gtk_offload_getinfo_req() - send GTK offload cmd to fw + * @wma: wma handle + * @params: GTK offload params + * + * Return: QDF status + */ +QDF_STATUS wma_process_gtk_offload_getinfo_req(tp_wma_handle wma, + tpSirGtkOffloadGetInfoRspParams params) +{ + uint8_t vdev_id; + uint64_t offload_req_opcode; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + WMA_LOGD("%s Enter", __func__); + + /* Get the vdev id */ + if (!wma_find_vdev_by_bssid(wma, params->bssid.bytes, &vdev_id)) { + WMA_LOGE("vdev handle is invalid for %pM", params->bssid.bytes); + status = QDF_STATUS_E_INVAL; + goto out; + } + + /* Request for GTK offload status */ + offload_req_opcode = GTK_OFFLOAD_REQUEST_STATUS_OPCODE; + + /* send the wmi command */ + status = wmi_unified_process_gtk_offload_getinfo_cmd(wma->wmi_handle, + vdev_id, offload_req_opcode); + +out: + qdf_mem_free(params); + WMA_LOGD("%s Exit", __func__); + return status; +} +#endif /* WLAN_FEATURE_GTK_OFFLOAD */ + +/** + * wma_enable_arp_ns_offload() - enable ARP NS offload + * @wma: wma handle + * @tpSirHostOffloadReq: offload request + * @config_arp: config arp flag + * + * To configure ARP NS off load data to firmware + * when target goes to wow mode. + * + * Return: QDF Status + */ +QDF_STATUS wma_enable_arp_ns_offload(tp_wma_handle wma, + tpSirHostOffloadReq + offload_req, bool config_arp) +{ + int32_t res; + uint8_t vdev_id; + tpSirHostOffloadReq ns_offload_req; + tpSirHostOffloadReq arp_offload_req; + + /* Get the vdev id */ + if (!wma_find_vdev_by_bssid(wma, offload_req->bssid.bytes, + &vdev_id)) { + WMA_LOGE("vdev handle is invalid for %pM", + offload_req->bssid.bytes); + qdf_mem_free(offload_req); + return QDF_STATUS_E_INVAL; + } + + if (!wma->interfaces[vdev_id].vdev_up) { + WMA_LOGE("vdev %d is not up skipping arp/ns offload", vdev_id); + qdf_mem_free(offload_req); + return QDF_STATUS_E_FAILURE; + } + + /* + * config_arp is true means arp request comes from upper layer + * Hence ns request need to used from wma cached request. + */ + if (config_arp) { + arp_offload_req = offload_req; + ns_offload_req = &wma->interfaces[vdev_id].ns_offload_req; + WMA_LOGD(" %s: ARP Offload vdev_id: %d enable: %d", + __func__, vdev_id, + offload_req->enableOrDisable); + } else { + ns_offload_req = offload_req; + arp_offload_req = &wma->interfaces[vdev_id].arp_offload_req; + WMA_LOGD(" %s: NS Offload vdev_id: %d enable: %d ns_count: %u", + __func__, vdev_id, + offload_req->enableOrDisable, + offload_req->num_ns_offload_count); + } + + res = wmi_unified_enable_arp_ns_offload_cmd(wma->wmi_handle, + (struct host_offload_req_param *)arp_offload_req, + (struct host_offload_req_param *)ns_offload_req, + config_arp, + vdev_id); + if (res) { + WMA_LOGE("Failed to enable ARP NDP/NSffload"); + qdf_mem_free(offload_req); + return QDF_STATUS_E_FAILURE; + } + + if (config_arp) { + qdf_mem_copy(&wma->interfaces[vdev_id].arp_offload_req, + offload_req, + sizeof(wma->interfaces[vdev_id].arp_offload_req)); + } else { + qdf_mem_copy(&wma->interfaces[vdev_id].ns_offload_req, + offload_req, + sizeof(wma->interfaces[vdev_id].ns_offload_req)); + } + + qdf_mem_free(offload_req); + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wma_conf_hw_filter_mode(tp_wma_handle wma, + struct hw_filter_request *req) +{ + QDF_STATUS status; + uint8_t vdev_id; + + /* Get the vdev id */ + if (!wma_find_vdev_by_bssid(wma, req->bssid.bytes, &vdev_id)) { + WMA_LOGE("vdev handle is invalid for %pM", + req->bssid.bytes); + qdf_mem_free(req); + return QDF_STATUS_E_INVAL; + } + + if (!wma->interfaces[vdev_id].vdev_up) { + WMA_LOGE("vdev %d is not up skipping enable Broadcast Filter", + vdev_id); + qdf_mem_free(req); + return QDF_STATUS_E_FAILURE; + } + + status = wmi_unified_conf_hw_filter_mode_cmd(wma->wmi_handle, vdev_id, + req->mode_bitmap); + if (QDF_IS_STATUS_ERROR(status)) + WMA_LOGE("Failed to enable/disable Broadcast Filter"); + + qdf_mem_free(req); + + return status; +} + +/** + * wma_process_cesium_enable_ind() - enables cesium functionality in target + * @wma: wma handle + * + * Return: QDF status + */ +QDF_STATUS wma_process_cesium_enable_ind(tp_wma_handle wma) +{ + QDF_STATUS ret; + int32_t vdev_id; + + vdev_id = wma_find_vdev_by_type(wma, WMI_VDEV_TYPE_IBSS); + if (vdev_id < 0) { + WMA_LOGE("%s: IBSS vdev does not exist could not enable cesium", + __func__); + return QDF_STATUS_E_FAILURE; + } + + /* Send enable cesium command to target */ + WMA_LOGE("Enable cesium in target for vdevId %d ", vdev_id); + ret = wma_vdev_set_param(wma->wmi_handle, vdev_id, + WMI_VDEV_PARAM_ENABLE_RMC, 1); + if (ret) { + WMA_LOGE("Enable cesium failed for vdevId %d", vdev_id); + return QDF_STATUS_E_FAILURE; + } + return QDF_STATUS_SUCCESS; +} + +/** + * wma_process_get_peer_info_req() - sends get peer info cmd to target + * @wma: wma handle + * @preq: get peer info request + * + * Return: QDF status + */ +QDF_STATUS wma_process_get_peer_info_req + (tp_wma_handle wma, tSirIbssGetPeerInfoReqParams *pReq) +{ + int32_t ret; + uint8_t *p; + uint16_t len; + wmi_buf_t buf; + int32_t vdev_id; + ol_txrx_pdev_handle pdev; + struct ol_txrx_peer_t *peer; + uint8_t peer_mac[IEEE80211_ADDR_LEN]; + wmi_peer_info_req_cmd_fixed_param *p_get_peer_info_cmd; + uint8_t bcast_mac[IEEE80211_ADDR_LEN] = { 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff }; + + vdev_id = wma_find_vdev_by_type(wma, WMI_VDEV_TYPE_IBSS); + if (vdev_id < 0) { + WMA_LOGE("%s: IBSS vdev does not exist could not get peer info", + __func__); + return QDF_STATUS_E_FAILURE; + } + + pdev = cds_get_context(QDF_MODULE_ID_TXRX); + if (NULL == pdev) { + WMA_LOGE("%s: Failed to get pdev context", __func__); + return QDF_STATUS_E_FAILURE; + } + + if (0xFF == pReq->staIdx) { + /*get info for all peers */ + qdf_mem_copy(peer_mac, bcast_mac, IEEE80211_ADDR_LEN); + } else { + /*get info for a single peer */ + peer = ol_txrx_peer_find_by_local_id(pdev, pReq->staIdx); + if (!peer) { + WMA_LOGE("%s: Failed to get peer handle using peer id %d", + __func__, pReq->staIdx); + return QDF_STATUS_E_FAILURE; + } + WMA_LOGE("%s: staIdx %d peer mac: 0x%2x:0x%2x:0x%2x:0x%2x:0x%2x:0x%2x", + __func__, pReq->staIdx, peer->mac_addr.raw[0], + peer->mac_addr.raw[1], peer->mac_addr.raw[2], + peer->mac_addr.raw[3], peer->mac_addr.raw[4], + peer->mac_addr.raw[5]); + qdf_mem_copy(peer_mac, peer->mac_addr.raw, IEEE80211_ADDR_LEN); + } + + len = sizeof(wmi_peer_info_req_cmd_fixed_param); + buf = wmi_buf_alloc(wma->wmi_handle, len); + if (!buf) { + WMA_LOGE("%s %d: No WMI resource!", __func__, __LINE__); + return QDF_STATUS_E_FAILURE; + } + + p = (uint8_t *) wmi_buf_data(buf); + qdf_mem_zero(p, len); + p_get_peer_info_cmd = (wmi_peer_info_req_cmd_fixed_param *) p; + + WMITLV_SET_HDR(&p_get_peer_info_cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_peer_info_req_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_peer_info_req_cmd_fixed_param)); + + p_get_peer_info_cmd->vdev_id = vdev_id; + WMI_CHAR_ARRAY_TO_MAC_ADDR(peer_mac, + &p_get_peer_info_cmd->peer_mac_address); + + ret = wmi_unified_cmd_send(wma->wmi_handle, buf, len, + WMI_PEER_INFO_REQ_CMDID); + if (ret != QDF_STATUS_SUCCESS) + wmi_buf_free(buf); + + WMA_LOGE("IBSS get peer info cmd sent len: %d, vdev %d" + " command id: %d, status: %d", len, + vdev_id, WMI_PEER_INFO_REQ_CMDID, ret); + + return QDF_STATUS_SUCCESS; +} + +/** + * wma_process_tx_fail_monitor_ind() - sends tx fail monitor cmd to target + * @wma: wma handle + * @pReq: tx fail monitor command params + * + * Return: QDF status + */ +QDF_STATUS wma_process_tx_fail_monitor_ind + (tp_wma_handle wma, tAniTXFailMonitorInd *pReq) +{ + QDF_STATUS ret; + int32_t vdev_id; + + vdev_id = wma_find_vdev_by_type(wma, WMI_VDEV_TYPE_IBSS); + if (vdev_id < 0) { + WMA_LOGE("%s: IBSS vdev does not exist could not send fast tx fail" + " monitor indication message to target", __func__); + return QDF_STATUS_E_FAILURE; + } + + /* Send enable cesium command to target */ + WMA_LOGE("send fast tx fail monitor ind cmd target for vdevId %d val %d", + vdev_id, pReq->tx_fail_count); + + if (0 == pReq->tx_fail_count) { + wma->hddTxFailCb = NULL; + } else { + wma->hddTxFailCb = pReq->txFailIndCallback; + } + ret = wma_vdev_set_param(wma->wmi_handle, vdev_id, + WMI_VDEV_PARAM_SET_IBSS_TX_FAIL_CNT_THR, + pReq->tx_fail_count); + if (ret) { + WMA_LOGE("tx fail monitor failed for vdevId %d", vdev_id); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * wma_process_rmc_enable_ind() - enables RMC functionality in target + * @wma: wma handle + * + * Return: QDF status + */ +QDF_STATUS wma_process_rmc_enable_ind(tp_wma_handle wma) +{ + int ret; + uint8_t *p; + uint16_t len; + wmi_buf_t buf; + int32_t vdev_id; + wmi_rmc_set_mode_cmd_fixed_param *p_rmc_enable_cmd; + + vdev_id = wma_find_vdev_by_type(wma, WMI_VDEV_TYPE_IBSS); + if (vdev_id < 0) { + WMA_LOGE("%s: IBSS vdev does not exist could not enable RMC", + __func__); + return QDF_STATUS_E_FAILURE; + } + + len = sizeof(wmi_rmc_set_mode_cmd_fixed_param); + buf = wmi_buf_alloc(wma->wmi_handle, len); + if (!buf) { + WMA_LOGE("%s %d: No WMI resource!", __func__, __LINE__); + return QDF_STATUS_E_FAILURE; + } + + p = (uint8_t *) wmi_buf_data(buf); + qdf_mem_zero(p, len); + p_rmc_enable_cmd = (wmi_rmc_set_mode_cmd_fixed_param *) p; + + WMITLV_SET_HDR(&p_rmc_enable_cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_rmc_set_mode_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_rmc_set_mode_cmd_fixed_param)); + + p_rmc_enable_cmd->vdev_id = vdev_id; + p_rmc_enable_cmd->enable_rmc = WMI_RMC_MODE_ENABLED; + + ret = wmi_unified_cmd_send(wma->wmi_handle, buf, len, + WMI_RMC_SET_MODE_CMDID); + if (ret != QDF_STATUS_SUCCESS) + wmi_buf_free(buf); + + WMA_LOGE("Enable RMC cmd sent len: %d, vdev %d" " command id: %d," + " status: %d", len, vdev_id, WMI_RMC_SET_MODE_CMDID, ret); + + return QDF_STATUS_SUCCESS; +} + +/** + * wma_process_rmc_disable_ind() - disables rmc functionality in target + * @wma: wma handle + * + * Return: QDF status + */ +QDF_STATUS wma_process_rmc_disable_ind(tp_wma_handle wma) +{ + int ret; + uint8_t *p; + uint16_t len; + wmi_buf_t buf; + int32_t vdev_id; + wmi_rmc_set_mode_cmd_fixed_param *p_rmc_disable_cmd; + + vdev_id = wma_find_vdev_by_type(wma, WMI_VDEV_TYPE_IBSS); + if (vdev_id < 0) { + WMA_LOGE("%s: IBSS vdev does not exist could not disable RMC", + __func__); + return QDF_STATUS_E_FAILURE; + } + + len = sizeof(wmi_rmc_set_mode_cmd_fixed_param); + buf = wmi_buf_alloc(wma->wmi_handle, len); + if (!buf) { + WMA_LOGE("%s %d: No WMI resource!", __func__, __LINE__); + return QDF_STATUS_E_FAILURE; + } + + p = (uint8_t *) wmi_buf_data(buf); + qdf_mem_zero(p, len); + p_rmc_disable_cmd = (wmi_rmc_set_mode_cmd_fixed_param *) p; + + WMITLV_SET_HDR(&p_rmc_disable_cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_rmc_set_mode_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_rmc_set_mode_cmd_fixed_param)); + + p_rmc_disable_cmd->vdev_id = vdev_id; + p_rmc_disable_cmd->enable_rmc = WMI_RMC_MODE_DISABLED; + + ret = wmi_unified_cmd_send(wma->wmi_handle, buf, len, + WMI_RMC_SET_MODE_CMDID); + if (ret != QDF_STATUS_SUCCESS) + wmi_buf_free(buf); + + WMA_LOGE("Disable RMC cmd sent len: %d, vdev %d" " command id: %d," + " status: %d", len, vdev_id, WMI_RMC_SET_MODE_CMDID, ret); + + return QDF_STATUS_SUCCESS; +} + +/** + * wma_process_rmc_action_period_ind() - sends RMC action period to target + * @wma: wma handle + * + * Return: QDF status + */ +QDF_STATUS wma_process_rmc_action_period_ind(tp_wma_handle wma) +{ + int ret; + uint8_t *p; + uint16_t len; + uint32_t periodicity_msec; + wmi_buf_t buf; + int32_t vdev_id; + wmi_rmc_set_action_period_cmd_fixed_param *p_rmc_cmd; + struct sAniSirGlobal *mac = cds_get_context(QDF_MODULE_ID_PE); + + if (NULL == mac) { + WMA_LOGE("%s: MAC mac does not exist", __func__); + return QDF_STATUS_E_FAILURE; + } + + vdev_id = wma_find_vdev_by_type(wma, WMI_VDEV_TYPE_IBSS); + if (vdev_id < 0) { + WMA_LOGE("%s: IBSS vdev does not exist could not send" + " RMC action period to target", __func__); + return QDF_STATUS_E_FAILURE; + } + + len = sizeof(wmi_rmc_set_action_period_cmd_fixed_param); + buf = wmi_buf_alloc(wma->wmi_handle, len); + if (!buf) { + WMA_LOGE("%s %d: No WMI resource!", __func__, __LINE__); + return QDF_STATUS_E_FAILURE; + } + + p = (uint8_t *) wmi_buf_data(buf); + qdf_mem_zero(p, len); + p_rmc_cmd = (wmi_rmc_set_action_period_cmd_fixed_param *) p; + + WMITLV_SET_HDR(&p_rmc_cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_rmc_set_action_period_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_rmc_set_action_period_cmd_fixed_param)); + + if (wlan_cfg_get_int(mac, WNI_CFG_RMC_ACTION_PERIOD_FREQUENCY, + &periodicity_msec) != eSIR_SUCCESS) { + WMA_LOGE("Failed to get value for RMC action period using default"); + periodicity_msec = WNI_CFG_RMC_ACTION_PERIOD_FREQUENCY_STADEF; + } + + p_rmc_cmd->vdev_id = vdev_id; + p_rmc_cmd->periodicity_msec = periodicity_msec; + + ret = wmi_unified_cmd_send(wma->wmi_handle, buf, len, + WMI_RMC_SET_ACTION_PERIOD_CMDID); + if (ret != QDF_STATUS_SUCCESS) + wmi_buf_free(buf); + + WMA_LOGE("RMC action period %d cmd sent len: %d, vdev %d" + " command id: %d, status: %d", periodicity_msec, + len, vdev_id, WMI_RMC_SET_ACTION_PERIOD_CMDID, ret); + + return QDF_STATUS_SUCCESS; +} + +/** + * wma_process_add_periodic_tx_ptrn_ind - add periodic tx ptrn + * @handle: wma handle + * @pAddPeriodicTxPtrnParams: tx ptrn params + * + * Retrun: QDF status + */ +QDF_STATUS wma_process_add_periodic_tx_ptrn_ind(WMA_HANDLE handle, + tSirAddPeriodicTxPtrn * + pAddPeriodicTxPtrnParams) +{ + tp_wma_handle wma_handle = (tp_wma_handle) handle; + struct periodic_tx_pattern *params_ptr; + uint8_t vdev_id; + QDF_STATUS status; + + if (!wma_handle || !wma_handle->wmi_handle) { + WMA_LOGE("%s: WMA is closed, can not issue fw add pattern cmd", + __func__); + return QDF_STATUS_E_INVAL; + } + + params_ptr = qdf_mem_malloc(sizeof(*params_ptr)); + + if (!params_ptr) { + WMA_LOGE( + "%s: unable to allocate memory for periodic_tx_pattern", + __func__); + return QDF_STATUS_E_NOMEM; + } + + if (!wma_find_vdev_by_addr(wma_handle, + pAddPeriodicTxPtrnParams->mac_address.bytes, + &vdev_id)) { + WMA_LOGE("%s: Failed to find vdev id for %pM", __func__, + pAddPeriodicTxPtrnParams->mac_address.bytes); + return QDF_STATUS_E_INVAL; + } + + params_ptr->ucPtrnId = pAddPeriodicTxPtrnParams->ucPtrnId; + params_ptr->ucPtrnSize = pAddPeriodicTxPtrnParams->ucPtrnSize; + params_ptr->usPtrnIntervalMs = + pAddPeriodicTxPtrnParams->usPtrnIntervalMs; + qdf_mem_copy(¶ms_ptr->mac_address, + &pAddPeriodicTxPtrnParams->mac_address, + sizeof(struct qdf_mac_addr)); + qdf_mem_copy(params_ptr->ucPattern, + pAddPeriodicTxPtrnParams->ucPattern, + params_ptr->ucPtrnSize); + + status = wmi_unified_process_add_periodic_tx_ptrn_cmd( + wma_handle->wmi_handle, params_ptr, vdev_id); + + qdf_mem_free(params_ptr); + return status; +} + +/** + * wma_process_del_periodic_tx_ptrn_ind - del periodic tx ptrn + * @handle: wma handle + * @pDelPeriodicTxPtrnParams: tx ptrn params + * + * Retrun: QDF status + */ +QDF_STATUS wma_process_del_periodic_tx_ptrn_ind(WMA_HANDLE handle, + tSirDelPeriodicTxPtrn * + pDelPeriodicTxPtrnParams) +{ + tp_wma_handle wma_handle = (tp_wma_handle) handle; + uint8_t vdev_id; + + if (!wma_handle || !wma_handle->wmi_handle) { + WMA_LOGE("%s: WMA is closed, can not issue Del Pattern cmd", + __func__); + return QDF_STATUS_E_INVAL; + } + + if (!wma_find_vdev_by_addr(wma_handle, + pDelPeriodicTxPtrnParams->mac_address.bytes, + &vdev_id)) { + WMA_LOGE("%s: Failed to find vdev id for %pM", __func__, + pDelPeriodicTxPtrnParams->mac_address.bytes); + return QDF_STATUS_E_INVAL; + } + + return wmi_unified_process_del_periodic_tx_ptrn_cmd( + wma_handle->wmi_handle, vdev_id, + pDelPeriodicTxPtrnParams->ucPtrnId); +} + +#ifdef WLAN_FEATURE_STATS_EXT +/** + * wma_stats_ext_req() - request ext stats from fw + * @wma_ptr: wma handle + * @preq: stats ext params + * + * Return: QDF status + */ +QDF_STATUS wma_stats_ext_req(void *wma_ptr, tpStatsExtRequest preq) +{ + tp_wma_handle wma = (tp_wma_handle) wma_ptr; + struct stats_ext_params *params; + size_t params_len; + QDF_STATUS status; + + if (!wma) { + WMA_LOGE("%s: wma handle is NULL", __func__); + return QDF_STATUS_E_FAILURE; + } + + params_len = sizeof(*params) + preq->request_data_len; + params = qdf_mem_malloc(params_len); + + if (params == NULL) { + WMA_LOGE(FL("memory allocation failed")); + return QDF_STATUS_E_NOMEM; + } + + params->vdev_id = preq->vdev_id; + params->request_data_len = preq->request_data_len; + if (preq->request_data_len > 0) + qdf_mem_copy(params->request_data, preq->request_data, + params->request_data_len); + + status = wmi_unified_stats_ext_req_cmd(wma->wmi_handle, params); + qdf_mem_free(params); + + return status; +} + +#endif /* WLAN_FEATURE_STATS_EXT */ + +#ifdef WLAN_FEATURE_EXTWOW_SUPPORT +/** + * wma_send_status_of_ext_wow() - send ext wow status to SME + * @wma: wma handle + * @status: status + * + * Return: none + */ +static void wma_send_status_of_ext_wow(tp_wma_handle wma, bool status) +{ + tSirReadyToExtWoWInd *ready_to_extwow; + QDF_STATUS vstatus; + cds_msg_t cds_msg; + uint8_t len; + + WMA_LOGD("Posting ready to suspend indication to umac"); + + len = sizeof(tSirReadyToExtWoWInd); + ready_to_extwow = (tSirReadyToExtWoWInd *) qdf_mem_malloc(len); + + if (NULL == ready_to_extwow) { + WMA_LOGE("%s: Memory allocation failure", __func__); + return; + } + + ready_to_extwow->mesgType = eWNI_SME_READY_TO_EXTWOW_IND; + ready_to_extwow->mesgLen = len; + ready_to_extwow->status = status; + + cds_msg.type = eWNI_SME_READY_TO_EXTWOW_IND; + cds_msg.bodyptr = (void *)ready_to_extwow; + cds_msg.bodyval = 0; + + vstatus = cds_mq_post_message(CDS_MQ_ID_SME, &cds_msg); + if (vstatus != QDF_STATUS_SUCCESS) { + WMA_LOGE("Failed to post ready to suspend"); + qdf_mem_free(ready_to_extwow); + } +} + +/** + * wma_enable_ext_wow() - enable ext wow in fw + * @wma: wma handle + * @params: ext wow params + * + * Return:0 for success or error code + */ +QDF_STATUS wma_enable_ext_wow(tp_wma_handle wma, tpSirExtWoWParams params) +{ + struct ext_wow_params wow_params = {0}; + QDF_STATUS status; + + if (!wma) { + WMA_LOGE("%s: wma handle is NULL", __func__); + return QDF_STATUS_E_FAILURE; + } + + wow_params.vdev_id = params->vdev_id; + wow_params.type = (enum wmi_ext_wow_type) params->type; + wow_params.wakeup_pin_num = params->wakeup_pin_num; + + status = wmi_unified_enable_ext_wow_cmd(wma->wmi_handle, + &wow_params); + if (QDF_IS_STATUS_ERROR(status)) + return status; + + wma_send_status_of_ext_wow(wma, true); + return status; + +} + +/** + * wma_set_app_type1_params_in_fw() - set app type1 params in fw + * @wma: wma handle + * @appType1Params: app type1 params + * + * Return: QDF status + */ +int wma_set_app_type1_params_in_fw(tp_wma_handle wma, + tpSirAppType1Params appType1Params) +{ + int ret; + + ret = wmi_unified_app_type1_params_in_fw_cmd(wma->wmi_handle, + (struct app_type1_params *)appType1Params); + if (ret) { + WMA_LOGE("%s: Failed to set APP TYPE1 PARAMS", __func__); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * wma_set_app_type2_params_in_fw() - set app type2 params in fw + * @wma: wma handle + * @appType2Params: app type2 params + * + * Return: QDF status + */ +QDF_STATUS wma_set_app_type2_params_in_fw(tp_wma_handle wma, + tpSirAppType2Params appType2Params) +{ + struct app_type2_params params = {0}; + + if (!wma) { + WMA_LOGE("%s: wma handle is NULL", __func__); + return QDF_STATUS_E_FAILURE; + } + + params.vdev_id = appType2Params->vdev_id; + params.rc4_key_len = appType2Params->rc4_key_len; + qdf_mem_copy(params.rc4_key, appType2Params->rc4_key, 16); + params.ip_id = appType2Params->ip_id; + params.ip_device_ip = appType2Params->ip_device_ip; + params.ip_server_ip = appType2Params->ip_server_ip; + params.tcp_src_port = appType2Params->tcp_src_port; + params.tcp_dst_port = appType2Params->tcp_dst_port; + params.tcp_seq = appType2Params->tcp_seq; + params.tcp_ack_seq = appType2Params->tcp_ack_seq; + params.keepalive_init = appType2Params->keepalive_init; + params.keepalive_min = appType2Params->keepalive_min; + params.keepalive_max = appType2Params->keepalive_max; + params.keepalive_inc = appType2Params->keepalive_inc; + params.tcp_tx_timeout_val = appType2Params->tcp_tx_timeout_val; + params.tcp_rx_timeout_val = appType2Params->tcp_rx_timeout_val; + qdf_mem_copy(¶ms.gateway_mac, &appType2Params->gateway_mac, + sizeof(struct qdf_mac_addr)); + + return wmi_unified_set_app_type2_params_in_fw_cmd(wma->wmi_handle, + ¶ms); + +} +#endif /* WLAN_FEATURE_EXTWOW_SUPPORT */ + +#ifdef FEATURE_WLAN_AUTO_SHUTDOWN +/** + * wma_auto_shutdown_event_handler() - process auto shutdown timer trigger + * @handle: wma handle + * @event: event buffer + * @len: buffer length + * + * Return: 0 for success or error code + */ +int wma_auto_shutdown_event_handler(void *handle, uint8_t *event, + uint32_t len) +{ + wmi_host_auto_shutdown_event_fixed_param *wmi_auto_sh_evt; + WMI_HOST_AUTO_SHUTDOWN_EVENTID_param_tlvs *param_buf = + (WMI_HOST_AUTO_SHUTDOWN_EVENTID_param_tlvs *) + event; + + if (!param_buf || !param_buf->fixed_param) { + WMA_LOGE("%s:%d: Invalid Auto shutdown timer evt", __func__, + __LINE__); + return -EINVAL; + } + + wmi_auto_sh_evt = param_buf->fixed_param; + + if (wmi_auto_sh_evt->shutdown_reason + != WMI_HOST_AUTO_SHUTDOWN_REASON_TIMER_EXPIRY) { + WMA_LOGE("%s:%d: Invalid Auto shutdown timer evt", __func__, + __LINE__); + return -EINVAL; + } + + WMA_LOGD("%s:%d: Auto Shutdown Evt: %d", __func__, __LINE__, + wmi_auto_sh_evt->shutdown_reason); + return wma_post_auto_shutdown_msg(); +} + +/** + * wma_set_auto_shutdown_timer_req() - sets auto shutdown timer in firmware + * @wma: wma handle + * @auto_sh_cmd: auto shutdown timer value + * + * Return: QDF status + */ +QDF_STATUS wma_set_auto_shutdown_timer_req(tp_wma_handle wma_handle, + tSirAutoShutdownCmdParams * + auto_sh_cmd) +{ + if (auto_sh_cmd == NULL) { + WMA_LOGE("%s : Invalid Autoshutdown cfg cmd", __func__); + return QDF_STATUS_E_FAILURE; + } + + return wmi_unified_set_auto_shutdown_timer_cmd(wma_handle->wmi_handle, + auto_sh_cmd->timer_val); +} +#endif /* FEATURE_WLAN_AUTO_SHUTDOWN */ + +#ifdef WLAN_FEATURE_NAN +/** + * wma_nan_req() - to send nan request to target + * @wma: wma_handle + * @nan_req: request data which will be non-null + * + * Return: QDF status + */ +QDF_STATUS wma_nan_req(void *wma_ptr, tpNanRequest nan_req) +{ + tp_wma_handle wma_handle = (tp_wma_handle) wma_ptr; + struct nan_req_params *params; + size_t params_len; + QDF_STATUS status; + + if (!wma_handle) { + WMA_LOGE("%s: wma handle is NULL", __func__); + return QDF_STATUS_E_FAILURE; + } + + params_len = sizeof(*params) + nan_req->request_data_len; + params = qdf_mem_malloc(params_len); + + if (params == NULL) { + WMA_LOGE(FL("memory allocation failed")); + return QDF_STATUS_E_NOMEM; + } + + params->request_data_len = nan_req->request_data_len; + if (params->request_data_len > 0) + qdf_mem_copy(params->request_data, nan_req->request_data, + params->request_data_len); + + status = wmi_unified_nan_req_cmd(wma_handle->wmi_handle, params); + qdf_mem_free(params); + + return status; +} +#endif /* WLAN_FEATURE_NAN */ + +#ifdef DHCP_SERVER_OFFLOAD +/** + * wma_process_dhcpserver_offload() - enable DHCP server offload + * @wma_handle: wma handle + * @pDhcpSrvOffloadInfo: DHCP server offload info + * + * Return: 0 for success or error code + */ +QDF_STATUS wma_process_dhcpserver_offload(tp_wma_handle wma_handle, + tSirDhcpSrvOffloadInfo * + pDhcpSrvOffloadInfo) +{ + struct dhcp_offload_info_params params = {0}; + QDF_STATUS status; + + if (!wma_handle) { + WMA_LOGE("%s: wma handle is NULL", __func__); + return -EIO; + } + + params.vdev_id = pDhcpSrvOffloadInfo->vdev_id; + params.dhcpSrvOffloadEnabled = + pDhcpSrvOffloadInfo->dhcpSrvOffloadEnabled; + params.dhcpClientNum = pDhcpSrvOffloadInfo->dhcpClientNum; + params.dhcpSrvIP = pDhcpSrvOffloadInfo->; + + status = wmi_unified_process_dhcpserver_offload_cmd( + wma_handle->wmi_handle, ¶ms); + if (QDF_IS_STATUS_ERROR(status)) + return status; + + WMA_LOGD("Set dhcp server offload to vdevId %d", + pDhcpSrvOffloadInfo->vdev_id); + return status; +} +#endif /* DHCP_SERVER_OFFLOAD */ + +#ifdef WLAN_FEATURE_GPIO_LED_FLASHING +/** + * wma_set_led_flashing() - set led flashing in fw + * @wma_handle: wma handle + * @flashing: flashing request + * + * Return: QDF status + */ +QDF_STATUS wma_set_led_flashing(tp_wma_handle wma_handle, + tSirLedFlashingReq *flashing) +{ + struct flashing_req_params cmd = {0}; + + if (!wma_handle || !wma_handle->wmi_handle) { + WMA_LOGE(FL("WMA is closed, can not issue cmd")); + return QDF_STATUS_E_INVAL; + } + if (!flashing) { + WMA_LOGE(FL("invalid parameter: flashing")); + return QDF_STATUS_E_INVAL; + } + cmd.req_id = flashing->reqId; + cmd.pattern_id = flashing->pattern_id; + cmd.led_x0 = flashing->led_x0; + cmd.led_x1 = flashing->led_x1; + status = wmi_unified_set_led_flashing_cmd(wma_handle->wmi_handle, + &cmd); + if (status != EOK) { + return QDF_STATUS_E_FAILURE; + } + return QDF_STATUS_SUCCESS; +} +#endif /* WLAN_FEATURE_GPIO_LED_FLASHING */ + +#ifdef FEATURE_WLAN_CH_AVOID +/** + * wma_channel_avoid_evt_handler() - process channel to avoid event from FW. + * @handle: wma handle + * @event: event buffer + * @len: buffer length + * + * Return: 0 for success or error code + */ +int wma_channel_avoid_evt_handler(void *handle, uint8_t *event, + uint32_t len) +{ + wmi_avoid_freq_ranges_event_fixed_param *afr_fixed_param; + wmi_avoid_freq_range_desc *afr_desc; + uint32_t num_freq_ranges, freq_range_idx; + tSirChAvoidIndType *sca_indication; + QDF_STATUS qdf_status; + cds_msg_t sme_msg = { 0 }; + WMI_WLAN_FREQ_AVOID_EVENTID_param_tlvs *param_buf = + (WMI_WLAN_FREQ_AVOID_EVENTID_param_tlvs *) event; + + if (!param_buf) { + WMA_LOGE("Invalid channel avoid event buffer"); + return -EINVAL; + } + + afr_fixed_param = param_buf->fixed_param; + if (!afr_fixed_param) { + WMA_LOGE("Invalid channel avoid event fixed param buffer"); + return -EINVAL; + } + + num_freq_ranges = + (afr_fixed_param->num_freq_ranges > + SIR_CH_AVOID_MAX_RANGE) ? SIR_CH_AVOID_MAX_RANGE : + afr_fixed_param->num_freq_ranges; + + WMA_LOGD("Channel avoid event received with %d ranges", + num_freq_ranges); + for (freq_range_idx = 0; freq_range_idx < num_freq_ranges; + freq_range_idx++) { + afr_desc = (wmi_avoid_freq_range_desc *) + ((void *)param_buf->avd_freq_range + + freq_range_idx * sizeof(wmi_avoid_freq_range_desc)); + + WMA_LOGD("range %d: tlv id = %u, start freq = %u, end freq = %u", + freq_range_idx, afr_desc->tlv_header, afr_desc->start_freq, + afr_desc->end_freq); + } + + sca_indication = (tSirChAvoidIndType *) + qdf_mem_malloc(sizeof(tSirChAvoidIndType)); + if (!sca_indication) { + WMA_LOGE("Invalid channel avoid indication buffer"); + return -EINVAL; + } + + sca_indication->avoid_range_count = num_freq_ranges; + for (freq_range_idx = 0; freq_range_idx < num_freq_ranges; + freq_range_idx++) { + afr_desc = (wmi_avoid_freq_range_desc *) + ((void *)param_buf->avd_freq_range + + freq_range_idx * sizeof(wmi_avoid_freq_range_desc)); + sca_indication->avoid_freq_range[freq_range_idx].start_freq = + afr_desc->start_freq; + sca_indication->avoid_freq_range[freq_range_idx].end_freq = + afr_desc->end_freq; + } + + sme_msg.type = eWNI_SME_CH_AVOID_IND; + sme_msg.bodyptr = sca_indication; + sme_msg.bodyval = 0; + + qdf_status = cds_mq_post_message(QDF_MODULE_ID_SME, &sme_msg); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + WMA_LOGE("Fail to post eWNI_SME_CH_AVOID_IND msg to SME"); + qdf_mem_free(sca_indication); + return -EINVAL; + } + + return 0; +} + +/** + * wma_process_ch_avoid_update_req() - handles channel avoid update request + * @wma_handle: wma handle + * @ch_avoid_update_req: channel avoid update params + * + * Return: QDF status + */ +QDF_STATUS wma_process_ch_avoid_update_req(tp_wma_handle wma_handle, + tSirChAvoidUpdateReq * + ch_avoid_update_req) +{ + QDF_STATUS status; + if (!wma_handle) { + WMA_LOGE("%s: wma handle is NULL", __func__); + return QDF_STATUS_E_FAILURE; + } + if (ch_avoid_update_req == NULL) { + WMA_LOGE("%s : ch_avoid_update_req is NULL", __func__); + return QDF_STATUS_E_FAILURE; + } + + WMA_LOGI("%s: WMA --> WMI_CHAN_AVOID_UPDATE", __func__); + + status = wmi_unified_process_ch_avoid_update_cmd( + wma_handle->wmi_handle); + if (QDF_IS_STATUS_ERROR(status)) + return status; + + WMA_LOGI("%s: WMA --> WMI_CHAN_AVOID_UPDATE sent through WMI", + __func__); + return status; +} +#endif /* FEATURE_WLAN_CH_AVOID */ + +/** + * wma_set_reg_domain() - set reg domain + * @clientCtxt: client context + * @regId: reg id + * + * Return: QDF status + */ +QDF_STATUS wma_set_reg_domain(void *clientCtxt, v_REGDOMAIN_t regId) +{ + if (QDF_STATUS_SUCCESS != + cds_set_reg_domain(clientCtxt, regId)) + return QDF_STATUS_E_INVAL; + + return QDF_STATUS_SUCCESS; +} + +/** + * wma_send_regdomain_info_to_fw() - send regdomain info to fw + * @reg_dmn: reg domain + * @regdmn2G: 2G reg domain + * @regdmn5G: 5G reg domain + * @ctl2G: 2G test limit + * @ctl5G: 5G test limit + * + * Return: none + */ +void wma_send_regdomain_info_to_fw(uint32_t reg_dmn, uint16_t regdmn2G, + uint16_t regdmn5G, int8_t ctl2G, + int8_t ctl5G) +{ + tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA); + int32_t cck_mask_val = 0; + struct pdev_params pdev_param = {0}; + QDF_STATUS ret = QDF_STATUS_SUCCESS; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + if (NULL == wma) { + WMA_LOGE("%s: wma context is NULL", __func__); + return; + } + + status = wmi_unified_send_regdomain_info_to_fw_cmd(wma->wmi_handle, + reg_dmn, regdmn2G, regdmn5G, ctl2G, ctl5G); + if (status == QDF_STATUS_E_NOMEM) + return; + + if ((((reg_dmn & ~CTRY_FLAG) == CTRY_JAPAN14) || + ((reg_dmn & ~CTRY_FLAG) == CTRY_KOREA_ROC)) && + (true == wma->tx_chain_mask_cck)) + cck_mask_val = 1; + + cck_mask_val |= (wma->self_gen_frm_pwr << 16); + pdev_param.param_id = WMI_PDEV_PARAM_TX_CHAIN_MASK_CCK; + pdev_param.param_value = cck_mask_val; + ret = wmi_unified_pdev_param_send(wma->wmi_handle, + &pdev_param, + WMA_WILDCARD_PDEV_ID); + + if (QDF_IS_STATUS_ERROR(ret)) + WMA_LOGE("failed to set PDEV tx_chain_mask_cck %d", + ret); + + return; +} + +/** + * wma_post_runtime_resume_msg() - post the resume request + * @handle: validated wma handle + * + * request the MC thread unpaus the vdev and set resume dtim + * + * Return: qdf status of the mq post + */ +static QDF_STATUS wma_post_runtime_resume_msg(WMA_HANDLE handle) +{ + cds_msg_t resume_msg; + QDF_STATUS status; + tp_wma_handle wma = (tp_wma_handle) handle; + + qdf_runtime_pm_prevent_suspend(&wma->wma_runtime_resume_lock); + + resume_msg.bodyptr = NULL; + resume_msg.type = WMA_RUNTIME_PM_RESUME_IND; + + status = cds_mq_post_message(QDF_MODULE_ID_WMA, &resume_msg); + + if (!QDF_IS_STATUS_SUCCESS(status)) { + WMA_LOGE("Failed to post Runtime PM Resume IND to VOS"); + qdf_runtime_pm_allow_suspend(&wma->wma_runtime_resume_lock); + } + + return status; +} + +/** + * wma_post_runtime_suspend_msg() - post the suspend request + * @handle: validated wma handle + * + * Requests for offloads to be configured for runtime suspend + * on the MC thread + * + * Return QDF_STATUS_E_AGAIN in case of timeout or QDF_STATUS_SUCCESS + */ +static QDF_STATUS wma_post_runtime_suspend_msg(WMA_HANDLE handle) +{ + cds_msg_t cds_msg; + QDF_STATUS qdf_status; + tp_wma_handle wma = (tp_wma_handle) handle; + + qdf_event_reset(&wma->runtime_suspend); + + cds_msg.bodyptr = NULL; + cds_msg.type = WMA_RUNTIME_PM_SUSPEND_IND; + qdf_status = cds_mq_post_message(QDF_MODULE_ID_WMA, &cds_msg); + + if (qdf_status != QDF_STATUS_SUCCESS) + goto failure; + + if (qdf_wait_single_event(&wma->runtime_suspend, + WMA_TGT_SUSPEND_COMPLETE_TIMEOUT) != + QDF_STATUS_SUCCESS) { + WMA_LOGE("Failed to get runtime suspend event"); + goto msg_timed_out; + } + + return QDF_STATUS_SUCCESS; + +msg_timed_out: + wma_post_runtime_resume_msg(wma); +failure: + return QDF_STATUS_E_AGAIN; +} + +/** + * __wma_bus_suspend(): handles bus suspend for wma + * @type: is this suspend part of runtime suspend or system suspend? + * @wow_flags: bitmap of WMI WOW flags to pass to FW + * + * Bails if a scan is in progress. + * Calls the appropriate handlers based on configuration and event. + * + * Return: 0 for success or error code + */ +static int __wma_bus_suspend(enum qdf_suspend_type type, uint32_t wow_flags) +{ + WMA_HANDLE handle = cds_get_context(QDF_MODULE_ID_WMA); + if (NULL == handle) { + WMA_LOGE("%s: wma context is NULL", __func__); + return -EFAULT; + } + + wma_peer_debug_log(DEBUG_INVALID_VDEV_ID, DEBUG_BUS_SUSPEND, + DEBUG_INVALID_PEER_ID, NULL, NULL, + type, wow_flags); + + if (type == QDF_RUNTIME_SUSPEND) { + QDF_STATUS status = wma_post_runtime_suspend_msg(handle); + if (status) + return qdf_status_to_os_return(status); + } + + if (type == QDF_SYSTEM_SUSPEND) + WMA_LOGI("%s: wow mode selected %d", __func__, + wma_is_wow_mode_selected(handle)); + + if (wma_is_wow_mode_selected(handle)) { + QDF_STATUS status = wma_enable_wow_in_fw(handle, wow_flags); + return qdf_status_to_os_return(status); + } + + return wma_suspend_target(handle, 0); +} + +/** + * wma_runtime_suspend() - handles runtime suspend request from hdd + * @wow_flags: bitmap of WMI WOW flags to pass to FW + * + * Calls the appropriate handler based on configuration and event. + * Last busy marking should prevent race conditions between processing + * of asyncronous fw events and the running of runtime suspend. + * (eg. last busy marking should guarantee that any auth requests have + * been processed) + * Events comming from the host are not protected, but aren't expected + * to be an issue. + * + * Return: 0 for success or error code + */ +int wma_runtime_suspend(uint32_t wow_flags) +{ + return __wma_bus_suspend(QDF_RUNTIME_SUSPEND, wow_flags); +} + +/** + * wma_bus_suspend() - handles bus suspend request from hdd + * @wow_flags: bitmap of WMI WOW flags to pass to FW + * + * Calls the appropriate handler based on configuration and event + * + * Return: 0 for success or error code + */ +int wma_bus_suspend(uint32_t wow_flags) +{ + + return __wma_bus_suspend(QDF_SYSTEM_SUSPEND, wow_flags); +} + +/** + * __wma_bus_resume() - bus resume for wma + * + * does the part of the bus resume common to bus and system suspend + * + * Return: os error code. + */ +static int __wma_bus_resume(WMA_HANDLE handle) +{ + bool wow_mode = wma_is_wow_mode_selected(handle); + tp_wma_handle wma = handle; + QDF_STATUS status; + + WMA_LOGI("%s: wow mode %d", __func__, wow_mode); + + wma_peer_debug_log(DEBUG_INVALID_VDEV_ID, DEBUG_BUS_RESUME, + DEBUG_INVALID_PEER_ID, NULL, NULL, + 0, 0); + + wma->wow_initial_wake_up = false; + + if (!wow_mode) + return qdf_status_to_os_return(wma_resume_target(handle)); + + status = wma_disable_wow_in_fw(handle); + return qdf_status_to_os_return(status); +} + +/** + * wma_runtime_resume() - do the runtime resume operation for wma + * + * Return: os error code. + */ +int wma_runtime_resume(void) +{ + int ret; + QDF_STATUS status; + WMA_HANDLE handle = cds_get_context(QDF_MODULE_ID_WMA); + if (NULL == handle) { + WMA_LOGE("%s: wma context is NULL", __func__); + return -EFAULT; + } + + ret = __wma_bus_resume(handle); + if (ret) + return ret; + + status = wma_post_runtime_resume_msg(handle); + return qdf_status_to_os_return(status); +} + +/** + * wma_bus_resume() - handles bus resume request from hdd + * @handle: valid wma handle + * + * Calls the appropriate handler based on configuration + * + * Return: 0 for success or error code + */ +int wma_bus_resume(void) +{ + WMA_HANDLE handle = cds_get_context(QDF_MODULE_ID_WMA); + if (NULL == handle) { + WMA_LOGE("%s: wma context is NULL", __func__); + return -EFAULT; + } + + return __wma_bus_resume(handle); +} + +/** + * wma_suspend_target_timeout() - Handles the target suspend timeout + * @is_self_recovery_enabled: Is self recovery enabled or not + * + * Return: NONE + */ +static inline void wma_suspend_target_timeout(bool is_self_recovery_enabled) +{ + if (cds_is_load_or_unload_in_progress()) + WMA_LOGE("%s: Module (un)loading; Ignoring suspend timeout", + __func__); + else if (cds_is_driver_recovering()) + WMA_LOGE("%s: Module recovering; Ignoring suspend timeout", + __func__); + else + cds_trigger_recovery(false); +} + +/** + * wma_suspend_target() - suspend target + * @handle: wma handle + * @disable_target_intr: disable target interrupt + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +QDF_STATUS wma_suspend_target(WMA_HANDLE handle, int disable_target_intr) +{ + tp_wma_handle wma_handle = (tp_wma_handle) handle; + QDF_STATUS status; + struct suspend_params param = {0}; + + tpAniSirGlobal pmac = cds_get_context(QDF_MODULE_ID_PE); + + if (!wma_handle || !wma_handle->wmi_handle) { + WMA_LOGE("WMA is closed. can not issue suspend cmd"); + return QDF_STATUS_E_INVAL; + } + + if (NULL == pmac) { + WMA_LOGE("%s: Unable to get PE context", __func__); + return QDF_STATUS_E_INVAL; + } + + qdf_event_reset(&wma_handle->target_suspend); + param.disable_target_intr = disable_target_intr; + status = wmi_unified_suspend_send(wma_handle->wmi_handle, + ¶m, + WMA_WILDCARD_PDEV_ID); + if (QDF_IS_STATUS_ERROR(status)) + return status; + + wmi_set_target_suspend(wma_handle->wmi_handle, true); + + if (qdf_wait_single_event(&wma_handle->target_suspend, + WMA_TGT_SUSPEND_COMPLETE_TIMEOUT) + != QDF_STATUS_SUCCESS) { + WMA_LOGE("Failed to get ACK from firmware for pdev suspend"); + wmi_set_target_suspend(wma_handle->wmi_handle, false); + wma_suspend_target_timeout(pmac->sme.enableSelfRecovery); + return QDF_STATUS_E_FAULT; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * wma_target_suspend_acknowledge() - update target susspend status + * @context: HTC_INIT_INFO->context + * @wow_nack: true when wow is rejected + * + * Return: none + */ +void wma_target_suspend_acknowledge(void *context, bool wow_nack) +{ + tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA); + + if (NULL == wma) { + WMA_LOGE("%s: wma is NULL", __func__); + return; + } + + wma->wow_nack = wow_nack; + qdf_event_set(&wma->target_suspend); + if (wow_nack && !wmi_get_runtime_pm_inprogress(wma->wmi_handle)) { + cds_host_diag_log_work(&wma->wow_wake_lock, + WMA_WAKE_LOCK_TIMEOUT, + WIFI_POWER_EVENT_WAKELOCK_WOW); + qdf_wake_lock_timeout_acquire(&wma->wow_wake_lock, + WMA_WAKE_LOCK_TIMEOUT); + } +} + +/** + * wma_handle_initial_wake_up() - handle inital wake up + * + * Return: none + */ +void wma_handle_initial_wake_up(void) +{ + tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA); + + if (NULL == wma) { + WMA_LOGE("%s: wma is NULL", __func__); + return; + } + + wma->wow_initial_wake_up = true; +} + +/** + * wma_is_target_wake_up_received() - check for initial wake up + * + * Check if target initial wake up is received and fail PM suspend gracefully + * + * Return: -EAGAIN if initial wake up is received else 0 + */ +int wma_is_target_wake_up_received(void) +{ + tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA); + + if (NULL == wma) { + WMA_LOGE("%s: wma is NULL", __func__); + return -EAGAIN; + } + + if (wma->wow_initial_wake_up) { + WMA_LOGE("Target initial wake up received try again"); + return -EAGAIN; + } + + return 0; +} + +/** + * wma_clear_target_wake_up() - clear initial wake up + * + * Clear target initial wake up reason + * + * Return: 0 for success and negative error code for failure + */ +int wma_clear_target_wake_up(void) +{ + tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA); + + if (NULL == wma) { + WMA_LOGE("%s: wma is NULL", __func__); + return -EFAULT; + } + + wma->wow_initial_wake_up = false; + + return 0; +} + +/** + * wma_resume_target() - resume target + * @handle: wma handle + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +QDF_STATUS wma_resume_target(WMA_HANDLE handle) +{ + tp_wma_handle wma = (tp_wma_handle) handle; + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = cds_get_context(QDF_MODULE_ID_PE); + if (NULL == pMac) { + WMA_LOGE("%s: Unable to get PE context", __func__); + return QDF_STATUS_E_INVAL; + } + + qdf_event_reset(&wma->wma_resume_event); + qdf_status = wmi_unified_resume_send(wma->wmi_handle, + WMA_WILDCARD_PDEV_ID); + if (QDF_IS_STATUS_ERROR(qdf_status)) + WMA_LOGE("Failed to send WMI_PDEV_RESUME_CMDID command"); + + qdf_status = qdf_wait_single_event(&(wma->wma_resume_event), + WMA_RESUME_TIMEOUT); + if (QDF_STATUS_SUCCESS != qdf_status) { + WMA_LOGP("%s: Timeout waiting for resume event from FW", + __func__); + WMA_LOGP("%s: Pending commands %d credits %d", __func__, + wmi_get_pending_cmds(wma->wmi_handle), + wmi_get_host_credits(wma->wmi_handle)); + if (!cds_is_driver_recovering()) { + cds_trigger_recovery(false); + } else { + WMA_LOGE("%s: SSR in progress, ignore resume timeout", + __func__); + } + } else { + WMA_LOGD("Host wakeup received"); + } + + if (QDF_STATUS_SUCCESS == qdf_status) + wmi_set_target_suspend(wma->wmi_handle, false); + + return qdf_status; +} + +#ifdef FEATURE_WLAN_TDLS +/** + * wma_tdls_event_handler() - handle TDLS event + * @handle: wma handle + * @event: event buffer + * @len: buffer length + * + * Return: 0 for success or error code + */ +int wma_tdls_event_handler(void *handle, uint8_t *event, uint32_t len) +{ + tp_wma_handle wma = (tp_wma_handle) handle; + WMI_TDLS_PEER_EVENTID_param_tlvs *param_buf = NULL; + wmi_tdls_peer_event_fixed_param *peer_event = NULL; + tSirTdlsEventnotify *tdls_event; + + if (!event) { + WMA_LOGE("%s: event param null", __func__); + return -EINVAL; + } + + param_buf = (WMI_TDLS_PEER_EVENTID_param_tlvs *) event; + if (!param_buf) { + WMA_LOGE("%s: received null buf from target", __func__); + return -EINVAL; + } + + peer_event = param_buf->fixed_param; + if (!peer_event) { + WMA_LOGE("%s: received null event data from target", __func__); + return -EINVAL; + } + + tdls_event = (tSirTdlsEventnotify *) + qdf_mem_malloc(sizeof(*tdls_event)); + if (!tdls_event) { + WMA_LOGE("%s: failed to allocate memory for tdls_event", + __func__); + return -ENOMEM; + } + + tdls_event->sessionId = peer_event->vdev_id; + WMI_MAC_ADDR_TO_CHAR_ARRAY(&peer_event->peer_macaddr, + tdls_event->peermac.bytes); + + switch (peer_event->peer_status) { + case WMI_TDLS_SHOULD_DISCOVER: + tdls_event->messageType = WMA_TDLS_SHOULD_DISCOVER_CMD; + break; + case WMI_TDLS_SHOULD_TEARDOWN: + tdls_event->messageType = WMA_TDLS_SHOULD_TEARDOWN_CMD; + break; + case WMI_TDLS_PEER_DISCONNECTED: + tdls_event->messageType = WMA_TDLS_PEER_DISCONNECTED_CMD; + break; + case WMI_TDLS_CONNECTION_TRACKER_NOTIFICATION: + tdls_event->messageType = + WMA_TDLS_CONNECTION_TRACKER_NOTIFICATION_CMD; + break; + default: + qdf_mem_free(tdls_event); + WMA_LOGE("%s: Discarding unknown tdls event(%d) from target", + __func__, peer_event->peer_status); + return -EINVAL; + } + + switch (peer_event->peer_reason) { + case WMI_TDLS_TEARDOWN_REASON_TX: + tdls_event->peer_reason = eWNI_TDLS_TEARDOWN_REASON_TX; + break; + case WMI_TDLS_TEARDOWN_REASON_RSSI: + tdls_event->peer_reason = eWNI_TDLS_TEARDOWN_REASON_RSSI; + break; + case WMI_TDLS_TEARDOWN_REASON_SCAN: + tdls_event->peer_reason = eWNI_TDLS_TEARDOWN_REASON_SCAN; + break; + case WMI_TDLS_DISCONNECTED_REASON_PEER_DELETE: + tdls_event->peer_reason = + eWNI_TDLS_DISCONNECTED_REASON_PEER_DELETE; + break; + case WMI_TDLS_TEARDOWN_REASON_PTR_TIMEOUT: + tdls_event->peer_reason = eWNI_TDLS_TEARDOWN_REASON_PTR_TIMEOUT; + break; + case WMI_TDLS_TEARDOWN_REASON_BAD_PTR: + tdls_event->peer_reason = eWNI_TDLS_TEARDOWN_REASON_BAD_PTR; + break; + case WMI_TDLS_TEARDOWN_REASON_NO_RESPONSE: + tdls_event->peer_reason = eWNI_TDLS_TEARDOWN_REASON_NO_RESPONSE; + break; + case WMI_TDLS_ENTER_BUF_STA: + tdls_event->peer_reason = eWNI_TDLS_PEER_ENTER_BUF_STA; + break; + case WMI_TDLS_EXIT_BUF_STA: + tdls_event->peer_reason = eWNI_TDLS_PEER_EXIT_BUF_STA; + break; + case WMI_TDLS_ENTER_BT_BUSY_MODE: + tdls_event->peer_reason = eWNI_TDLS_ENTER_BT_BUSY_MODE; + break; + case WMI_TDLS_EXIT_BT_BUSY_MODE: + tdls_event->peer_reason = eWNI_TDLS_EXIT_BT_BUSY_MODE; + break; + case WMI_TDLS_SCAN_STARTED_EVENT: + tdls_event->peer_reason = eWMI_TDLS_SCAN_STARTED_EVENT; + break; + case WMI_TDLS_SCAN_COMPLETED_EVENT: + tdls_event->peer_reason = eWMI_TDLS_SCAN_COMPLETED_EVENT; + break; + + default: + qdf_mem_free(tdls_event); + WMA_LOGE("%s: unknown reason(%d) in tdls event(%d) from target", + __func__, peer_event->peer_reason, + peer_event->peer_status); + return -EINVAL; + } + + WMA_LOGD("%s: sending msg to umac, messageType: 0x%x, " + "for peer: %pM, reason: %d, smesessionId: %d", + __func__, tdls_event->messageType, tdls_event->peermac.bytes, + tdls_event->peer_reason, tdls_event->sessionId); + + wma_send_msg(wma, tdls_event->messageType, (void *)tdls_event, 0); + return 0; +} + +/** + * wma_set_tdls_offchan_mode() - set tdls off channel mode + * @handle: wma handle + * @chan_switch_params: Pointer to tdls channel switch parameter structure + * + * This function sets tdls off channel mode + * + * Return: 0 on success; Negative errno otherwise + */ +QDF_STATUS wma_set_tdls_offchan_mode(WMA_HANDLE handle, + tdls_chan_switch_params *chan_switch_params) +{ + tp_wma_handle wma_handle = (tp_wma_handle) handle; + struct tdls_channel_switch_params params = {0}; + QDF_STATUS ret = QDF_STATUS_SUCCESS; + + if (!wma_handle || !wma_handle->wmi_handle) { + WMA_LOGE(FL( + "WMA is closed, can not issue tdls off channel cmd" + )); + ret = -EINVAL; + goto end; + } + + params.vdev_id = chan_switch_params->vdev_id; + params.tdls_off_ch_bw_offset = + chan_switch_params->tdls_off_ch_bw_offset; + params.tdls_off_ch = chan_switch_params->tdls_off_ch; + params.tdls_sw_mode = chan_switch_params->tdls_sw_mode; + params.oper_class = chan_switch_params->oper_class; + params.is_responder = chan_switch_params->is_responder; + qdf_mem_copy(params.peer_mac_addr, chan_switch_params->peer_mac_addr, + IEEE80211_ADDR_LEN); + + ret = wmi_unified_set_tdls_offchan_mode_cmd(wma_handle->wmi_handle, + ¶ms); + +end: + if (chan_switch_params) + qdf_mem_free(chan_switch_params); + return ret; +} + +/** + * wma_update_fw_tdls_state() - send enable/disable tdls for a vdev + * @wma: wma handle + * @pwmaTdlsparams: TDLS params + * + * Return: 0 for sucess or error code + */ +QDF_STATUS wma_update_fw_tdls_state(WMA_HANDLE handle, void *pwmaTdlsparams) +{ + tp_wma_handle wma_handle = (tp_wma_handle) handle; + t_wma_tdls_mode tdls_mode; + t_wma_tdls_params *wma_tdls = (t_wma_tdls_params *) pwmaTdlsparams; + struct wmi_tdls_params params = {0}; + QDF_STATUS ret = QDF_STATUS_SUCCESS; + uint8_t tdls_state; + + if (!wma_handle || !wma_handle->wmi_handle) { + WMA_LOGE("%s: WMA is closed, can not issue fw tdls state cmd", + __func__); + ret = -EINVAL; + goto end_fw_tdls_state; + } + + params.tdls_state = wma_tdls->tdls_state; + tdls_mode = wma_tdls->tdls_state; + + if (WMA_TDLS_SUPPORT_EXPLICIT_TRIGGER_ONLY == tdls_mode) { + tdls_state = WMI_TDLS_ENABLE_PASSIVE; + } else if (WMA_TDLS_SUPPORT_ENABLED == tdls_mode) { + tdls_state = WMI_TDLS_ENABLE_CONNECTION_TRACKER_IN_HOST; + } else if (WMA_TDLS_SUPPORT_ACTIVE_EXTERNAL_CONTROL == tdls_mode) { + tdls_state = WMI_TDLS_ENABLE_CONNECTION_TRACKER_IN_HOST; + } else { + tdls_state = WMI_TDLS_DISABLE; + } + + params.vdev_id = wma_tdls->vdev_id; + params.notification_interval_ms = wma_tdls->notification_interval_ms; + params.tx_discovery_threshold = wma_tdls->tx_discovery_threshold; + params.tx_teardown_threshold = wma_tdls->tx_teardown_threshold; + params.rssi_teardown_threshold = wma_tdls->rssi_teardown_threshold; + params.rssi_delta = wma_tdls->rssi_delta; + params.tdls_options = wma_tdls->tdls_options; + params.peer_traffic_ind_window = wma_tdls->peer_traffic_ind_window; + params.peer_traffic_response_timeout = + wma_tdls->peer_traffic_response_timeout; + params.puapsd_mask = wma_tdls->puapsd_mask; + params.puapsd_inactivity_time = wma_tdls->puapsd_inactivity_time; + params.puapsd_rx_frame_threshold = + wma_tdls->puapsd_rx_frame_threshold; + params.teardown_notification_ms = + wma_tdls->teardown_notification_ms; + params.tdls_peer_kickout_threshold = + wma_tdls->tdls_peer_kickout_threshold; + + ret = wmi_unified_update_fw_tdls_state_cmd(wma_handle->wmi_handle, + ¶ms, tdls_state); + if (QDF_IS_STATUS_ERROR(ret)) + goto end_fw_tdls_state; + + WMA_LOGD("%s: vdev_id %d", __func__, wma_tdls->vdev_id); + +end_fw_tdls_state: + if (pwmaTdlsparams) + qdf_mem_free(pwmaTdlsparams); + return ret; +} + +/** + * wma_update_tdls_peer_state() - update TDLS peer state + * @handle: wma handle + * @peerStateParams: TDLS peer state params + * + * Return: 0 for success or error code + */ +int wma_update_tdls_peer_state(WMA_HANDLE handle, + tTdlsPeerStateParams *peerStateParams) +{ + tp_wma_handle wma_handle = (tp_wma_handle) handle; + uint32_t i; + ol_txrx_pdev_handle pdev; + uint8_t peer_id; + ol_txrx_peer_handle peer; + uint8_t *peer_mac_addr; + int ret = 0; + uint32_t *ch_mhz = NULL; + bool restore_last_peer = false; + + if (!wma_handle || !wma_handle->wmi_handle) { + WMA_LOGE("%s: WMA is closed, can not issue cmd", __func__); + ret = -EINVAL; + goto end_tdls_peer_state; + } + + /* peer capability info is valid only when peer state is connected */ + if (WMA_TDLS_PEER_STATE_CONNECTED != peerStateParams->peerState) { + qdf_mem_zero(&peerStateParams->peerCap, + sizeof(tTdlsPeerCapParams)); + } + + if (peerStateParams->peerCap.peerChanLen) { + ch_mhz = qdf_mem_malloc(sizeof(uint32_t) * + peerStateParams->peerCap.peerChanLen); + if (ch_mhz == NULL) { + WMA_LOGE("%s: memory allocation failed", __func__); + ret = -ENOMEM; + goto end_tdls_peer_state; + } + } + + for (i = 0; i < peerStateParams->peerCap.peerChanLen; ++i) { + ch_mhz[i] = + cds_chan_to_freq(peerStateParams->peerCap.peerChan[i]. + chanId); + } + + /* Make sure that peer exists before sending peer state cmd*/ + pdev = cds_get_context(QDF_MODULE_ID_TXRX); + if (!pdev) { + WMA_LOGE("%s: Failed to find pdev", __func__); + ret = -EIO; + goto end_tdls_peer_state; + } + + peer = ol_txrx_find_peer_by_addr(pdev, + peerStateParams->peerMacAddr, + &peer_id); + if (!peer) { + WMA_LOGE("%s: peer not exists %pM", + __func__, peerStateParams->peerMacAddr); + ret = -EIO; + goto end_tdls_peer_state; + } + + if (wmi_unified_update_tdls_peer_state_cmd(wma_handle->wmi_handle, + (struct tdls_peer_state_params *)peerStateParams, + ch_mhz)) { + WMA_LOGE("%s: failed to send tdls peer update state command", + __func__); + ret = -EIO; + goto end_tdls_peer_state; + } + + /* in case of teardown, remove peer from fw */ + if (WMA_TDLS_PEER_STATE_TEARDOWN == peerStateParams->peerState) { + peer_mac_addr = ol_txrx_peer_get_peer_mac_addr(peer); + restore_last_peer = is_vdev_restore_last_peer(peer); + + WMA_LOGD("%s: calling wma_remove_peer for peer " MAC_ADDRESS_STR + " vdevId: %d", __func__, + MAC_ADDR_ARRAY(peer_mac_addr), + peerStateParams->vdevId); + wma_remove_peer(wma_handle, peer_mac_addr, + peerStateParams->vdevId, peer, false); + ol_txrx_update_last_real_peer(pdev, peer, &peer_id, + restore_last_peer); + } + +end_tdls_peer_state: + if (ch_mhz) + qdf_mem_free(ch_mhz); + if (peerStateParams) + qdf_mem_free(peerStateParams); + return ret; +} +#endif /* FEATURE_WLAN_TDLS */ + +/** + * wma_dfs_attach() - Attach DFS methods to the umac state. + * @dfs_ic: ieee80211com ptr + * + * Return: Return ieee80211com ptr with updated info + */ +struct ieee80211com *wma_dfs_attach(struct ieee80211com *dfs_ic) +{ + /*Allocate memory for dfs_ic before passing it up to dfs_attach() */ + dfs_ic = (struct ieee80211com *) + os_malloc(NULL, sizeof(struct ieee80211com), GFP_ATOMIC); + if (dfs_ic == NULL) { + WMA_LOGE("%s:Allocation of dfs_ic failed %zu", + __func__, sizeof(struct ieee80211com)); + return NULL; + } + OS_MEMZERO(dfs_ic, sizeof(struct ieee80211com)); + /* DFS pattern matching hooks */ + dfs_ic->ic_dfs_attach = ol_if_dfs_attach; + dfs_ic->ic_dfs_disable = ol_if_dfs_disable; + dfs_ic->ic_find_channel = ieee80211_find_channel; + dfs_ic->ic_dfs_enable = ol_if_dfs_enable; + dfs_ic->ic_ieee2mhz = ieee80211_ieee2mhz; + + /* Hardware facing hooks */ + dfs_ic->ic_get_ext_busy = ol_if_dfs_get_ext_busy; + dfs_ic->ic_get_mib_cycle_counts_pct = + ol_if_dfs_get_mib_cycle_counts_pct; + dfs_ic->ic_get_TSF64 = ol_if_get_tsf64; + + /* NOL related hooks */ + dfs_ic->ic_dfs_usenol = ol_if_dfs_usenol; + /* + * Hooks from wma/dfs/ back + * into the PE/SME + * and shared DFS code + */ + dfs_ic->ic_dfs_notify_radar = ieee80211_mark_dfs; + qdf_spinlock_create(&dfs_ic->chan_lock); + /* Initializes DFS Data Structures and queues */ + dfs_attach(dfs_ic); + + return dfs_ic; +} + +/** + * wma_dfs_detach() - Detach DFS methods + * @dfs_ic: ieee80211com ptr + * + * Return: none + */ +void wma_dfs_detach(struct ieee80211com *dfs_ic) +{ + dfs_detach(dfs_ic); + + qdf_spinlock_destroy(&dfs_ic->chan_lock); + if (NULL != dfs_ic->ic_curchan) { + OS_FREE(dfs_ic->ic_curchan); + dfs_ic->ic_curchan = NULL; + } + + OS_FREE(dfs_ic); +} + +/** + * wma_dfs_configure() - configure dfs + * @ic: ieee80211com ptr + * + * Configures Radar Filters during + * vdev start/channel change/regulatory domain + * change.This Configuration enables to program + * the DFS pattern matching module. + * + * Return: none + */ +void wma_dfs_configure(struct ieee80211com *ic) +{ + struct ath_dfs_radar_tab_info rinfo; + int dfsdomain; + int radar_enabled_status = 0; + if (ic == NULL) { + WMA_LOGE("%s: DFS ic is Invalid", __func__); + return; + } + + dfsdomain = ic->current_dfs_regdomain; + + /* Fetch current radar patterns from the lmac */ + OS_MEMZERO(&rinfo, sizeof(rinfo)); + + /* + * Look up the current DFS + * regulatory domain and decide + * which radar pulses to use. + */ + switch (dfsdomain) { + case DFS_FCC_REGION: + WMA_LOGI("%s: DFS-FCC domain", __func__); + rinfo.dfsdomain = DFS_FCC_REGION; + rinfo.dfs_radars = dfs_fcc_radars; + rinfo.numradars = QDF_ARRAY_SIZE(dfs_fcc_radars); + rinfo.b5pulses = dfs_fcc_bin5pulses; + rinfo.numb5radars = QDF_ARRAY_SIZE(dfs_fcc_bin5pulses); + break; + case DFS_ETSI_REGION: + WMA_LOGI("%s: DFS-ETSI domain", __func__); + rinfo.dfsdomain = DFS_ETSI_REGION; + rinfo.dfs_radars = dfs_etsi_radars; + rinfo.numradars = QDF_ARRAY_SIZE(dfs_etsi_radars); + rinfo.b5pulses = NULL; + rinfo.numb5radars = 0; + break; + case DFS_MKK_REGION: + WMA_LOGI("%s: DFS-MKK domain", __func__); + rinfo.dfsdomain = DFS_MKK_REGION; + rinfo.dfs_radars = dfs_mkk4_radars; + rinfo.numradars = QDF_ARRAY_SIZE(dfs_mkk4_radars); + rinfo.b5pulses = dfs_jpn_bin5pulses; + rinfo.numb5radars = QDF_ARRAY_SIZE(dfs_jpn_bin5pulses); + break; + case DFS_CN_REGION: + WMA_LOGI("%s: DFS-CN domain", __func__); + rinfo.dfsdomain = DFS_CN_REGION; + rinfo.dfs_radars = dfs_china_radars; + rinfo.numradars = QDF_ARRAY_SIZE(dfs_china_radars); + rinfo.b5pulses = NULL; + rinfo.numb5radars = 0; + break; + case DFS_KR_REGION: + WMA_LOGI("%s: DFS-KR domain", __func__); + rinfo.dfsdomain = DFS_KR_REGION; + rinfo.dfs_radars = dfs_korea_radars; + rinfo.numradars = QDF_ARRAY_SIZE(dfs_korea_radars); + rinfo.b5pulses = NULL; + rinfo.numb5radars = 0; + break; + default: + WMA_LOGI("%s: DFS-UNINT domain", __func__); + rinfo.dfsdomain = DFS_UNINIT_REGION; + rinfo.dfs_radars = NULL; + rinfo.numradars = 0; + rinfo.b5pulses = NULL; + rinfo.numb5radars = 0; + break; + } + + rinfo.dfs_pri_multiplier = ic->dfs_pri_multiplier; + + /* + * Set the regulatory domain, + * radar pulse table and enable + * radar events if required. + * dfs_radar_enable() returns + * 0 on success and non-zero + * failure. + */ + radar_enabled_status = dfs_radar_enable(ic, &rinfo); + if (radar_enabled_status != DFS_STATUS_SUCCESS) { + WMA_LOGE("%s[%d]: DFS- Radar Detection Enabling Failed", + __func__, __LINE__); + } +} + +/** + * wma_dfs_configure_channel() - configure DFS channel + * @dfs_ic: ieee80211com ptr + * @band_center_freq1: center frequency 1 + * @band_center_freq2: center frequency 2 + * (valid only for 11ac vht 80plus80 mode) + * @req: vdev start request + * + * Set the Channel parameters in to DFS module + * Also,configure the DFS radar filters for + * matching the DFS phyerrors. + * + * Return: None + */ +void wma_dfs_configure_channel(struct ieee80211com *dfs_ic, + uint32_t band_center_freq1, + uint32_t band_center_freq2, + struct wma_vdev_start_req *req) +{ + uint8_t ext_channel; + + if (dfs_ic == NULL) { + WMA_LOGE("%s: DFS ic is Invalid", __func__); + return; + } + + qdf_spin_lock_bh(&dfs_ic->chan_lock); + if (!dfs_ic->ic_curchan) { + dfs_ic->ic_curchan = (struct dfs_ieee80211_channel *)os_malloc( + NULL, + sizeof(struct dfs_ieee80211_channel), + GFP_ATOMIC); + if (dfs_ic->ic_curchan == NULL) { + qdf_spin_unlock_bh(&dfs_ic->chan_lock); + WMA_LOGE( + "%s: allocation of dfs_ic->ic_curchan failed %zu", + __func__, sizeof(struct dfs_ieee80211_channel)); + return; + } + } + + OS_MEMZERO(dfs_ic->ic_curchan, sizeof(struct dfs_ieee80211_channel)); + + dfs_ic->ic_curchan->ic_ieee = req->chan; + dfs_ic->ic_curchan->ic_freq = cds_chan_to_freq(req->chan); + dfs_ic->ic_curchan->ic_vhtop_ch_freq_seg1 = band_center_freq1; + dfs_ic->ic_curchan->ic_vhtop_ch_freq_seg2 = band_center_freq2; + dfs_ic->ic_curchan->ic_pri_freq_center_freq_mhz_separation = + dfs_ic->ic_curchan->ic_freq - + dfs_ic->ic_curchan->ic_vhtop_ch_freq_seg1; + + if ((dfs_ic->ic_curchan->ic_ieee >= WMA_11A_CHANNEL_BEGIN) && + (dfs_ic->ic_curchan->ic_ieee <= WMA_11A_CHANNEL_END)) { + dfs_ic->ic_curchan->ic_flags |= IEEE80211_CHAN_5GHZ; + } + + switch (req->chan_width) { + case CH_WIDTH_20MHZ: + dfs_ic->ic_curchan->ic_flags |= + (req->vht_capable ? IEEE80211_CHAN_VHT20 : + IEEE80211_CHAN_HT20); + break; + case CH_WIDTH_40MHZ: + if (req->chan < req->ch_center_freq_seg0) + dfs_ic->ic_curchan->ic_flags |= + (req->vht_capable ? + IEEE80211_CHAN_VHT40PLUS : + IEEE80211_CHAN_HT40PLUS); + else + dfs_ic->ic_curchan->ic_flags |= + (req->vht_capable ? + IEEE80211_CHAN_VHT40MINUS : + IEEE80211_CHAN_HT40MINUS); + break; + case CH_WIDTH_80MHZ: + dfs_ic->ic_curchan->ic_flags |= IEEE80211_CHAN_VHT80; + break; + case CH_WIDTH_80P80MHZ: + ext_channel = cds_freq_to_chan(band_center_freq2); + dfs_ic->ic_curchan->ic_flags |= + IEEE80211_CHAN_VHT80P80; + dfs_ic->ic_curchan->ic_freq_ext = + band_center_freq2; + dfs_ic->ic_curchan->ic_ieee_ext = ext_channel; + + /* verify both the 80MHz are DFS bands or not */ + if ((CHANNEL_STATE_DFS == + cds_get_5g_bonded_channel_state(req->chan , + CH_WIDTH_80MHZ)) && + (CHANNEL_STATE_DFS == cds_get_5g_bonded_channel_state( + ext_channel - WMA_80MHZ_START_CENTER_CH_DIFF, + CH_WIDTH_80MHZ))) + dfs_ic->ic_curchan->ic_80p80_both_dfs = true; + break; + case CH_WIDTH_160MHZ: + dfs_ic->ic_curchan->ic_flags |= + IEEE80211_CHAN_VHT160; + break; + default: + WMA_LOGD( + "%s: Recieved a wrong channel width %d", + __func__, req->chan_width); + break; + } + + dfs_ic->ic_curchan->ic_flagext |= IEEE80211_CHAN_DFS; + + if (req->oper_mode == BSS_OPERATIONAL_MODE_AP) { + dfs_ic->ic_opmode = IEEE80211_M_HOSTAP; + dfs_ic->vdev_id = req->vdev_id; + } + + dfs_ic->dfs_pri_multiplier = req->dfs_pri_multiplier; + qdf_spin_unlock_bh(&dfs_ic->chan_lock); + + /* + * Configuring the DFS with current channel and the radar filters + */ + wma_dfs_configure(dfs_ic); + WMA_LOGD("%s: DFS- CHANNEL CONFIGURED", __func__); + return; +} + + +/** + * wma_set_dfs_region() - set DFS region + * @wma: wma handle + * + * Configure the DFS region for DFS radar filter initialization + * + * Return: none + */ +void wma_set_dfs_region(tp_wma_handle wma, enum dfs_region dfs_region) +{ + if (dfs_region >= DFS_UNDEF_REGION || + dfs_region == DFS_UNINIT_REGION) + + /* assign DFS_FCC_REGION as default region*/ + wma->dfs_ic->current_dfs_regdomain = DFS_FCC_REGION; + else + wma->dfs_ic->current_dfs_regdomain = dfs_region; + + WMA_LOGI("%s: DFS Region Domain: %d", __func__, + wma->dfs_ic->current_dfs_regdomain); +} + +/** + * wma_get_channels() - prepare dfs radar channel list + * @ichan: channel + * @chan_list: return channel list + * + * Return: return number of channels + */ +static int wma_get_channels(struct dfs_ieee80211_channel *ichan, + struct wma_dfs_radar_channel_list *chan_list) +{ + uint8_t center_chan = cds_freq_to_chan(ichan->ic_vhtop_ch_freq_seg1); + int count = 0; + int start_channel = 0; + int loop; + + chan_list->nchannels = 0; + + if (IEEE80211_IS_CHAN_11AC_VHT160(ichan)) { + + /* + * as per the latest draft for BSS bandwidth 160MHz, + * channel frequency segment 2 represents the center + * channel frequency. + */ + if (ichan->ic_vhtop_ch_freq_seg2) + center_chan = + cds_freq_to_chan(ichan->ic_vhtop_ch_freq_seg2); + /* + * In 160MHz channel width, need to + * check if each of the 8 20MHz channel + * is DFS before adding to the NOL list. + * As it is possible that part of the + * 160MHz can be Non-DFS channels. + */ + start_channel = center_chan - WMA_160MHZ_START_CENTER_CH_DIFF; + for (loop = 0; loop < WMA_DFS_MAX_20M_SUB_CH; loop++) { + if (cds_get_channel_state(start_channel + + (loop * WMA_NEXT_20MHZ_START_CH_DIFF)) == + CHANNEL_STATE_DFS) { + chan_list->channels[count] = start_channel + + (loop * WMA_NEXT_20MHZ_START_CH_DIFF); + count++; + } + } + chan_list->nchannels = count; + } else if (IEEE80211_IS_CHAN_11AC_VHT80P80(ichan)) { + chan_list->nchannels = 4; + /* + * If SAP is operating in 80p80 mode, either + * one of the two 80 segments or both the 80 + * segments can be DFS channels, so need to + * identify on which 80 segment radar has + * been detected and only add those channels + * to the NOL list. center frequency should be + * based on the segment id passed as part of + * channel information in radar indication. + */ + if (ichan->ic_radar_found_segid == DFS_80P80_SEG1) + center_chan = + cds_freq_to_chan(ichan->ic_vhtop_ch_freq_seg2); + chan_list->channels[0] = center_chan - 6; + chan_list->channels[1] = center_chan - 2; + chan_list->channels[2] = center_chan + 2; + chan_list->channels[3] = center_chan + 6; + } else if (IEEE80211_IS_CHAN_11AC_VHT80(ichan)) { + chan_list->nchannels = 4; + chan_list->channels[0] = center_chan - 6; + chan_list->channels[1] = center_chan - 2; + chan_list->channels[2] = center_chan + 2; + chan_list->channels[3] = center_chan + 6; + } else if (IEEE80211_IS_CHAN_11N_HT40(ichan) || + IEEE80211_IS_CHAN_11AC_VHT40(ichan)) { + chan_list->nchannels = 2; + chan_list->channels[0] = center_chan - 2; + chan_list->channels[1] = center_chan + 2; + } else { + chan_list->nchannels = 1; + chan_list->channels[0] = center_chan; + } + + return chan_list->nchannels; +} + + +/** + * wma_dfs_indicate_radar() - Indicate Radar to SAP/HDD + * @ic: ieee80211com ptr + * @ichan: ieee 80211 channel + * + * Return: 0 for success or error code + */ +int wma_dfs_indicate_radar(struct ieee80211com *ic, + struct dfs_ieee80211_channel *ichan) +{ + tp_wma_handle wma; + void *hdd_ctx; + struct wma_dfs_radar_indication *radar_event; + struct wma_dfs_radar_ind wma_radar_event; + tpAniSirGlobal pmac = NULL; + bool indication_status; + + wma = cds_get_context(QDF_MODULE_ID_WMA); + if (wma == NULL) { + WMA_LOGE("%s: DFS- Invalid wma", __func__); + return -ENOENT; + } + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + pmac = (tpAniSirGlobal) + cds_get_context(QDF_MODULE_ID_PE); + + if (!pmac) { + WMA_LOGE("%s: Invalid MAC handle", __func__); + return -ENOENT; + } + + if (wma->dfs_ic != ic) { + WMA_LOGE("%s:DFS- Invalid WMA handle", __func__); + return -ENOENT; + } + + /* + * Do not post multiple Radar events on the same channel. + * But, when DFS test mode is enabled, allow multiple dfs + * radar events to be posted on the same channel. + */ + qdf_spin_lock_bh(&ic->chan_lock); + if (!pmac->sap.SapDfsInfo.disable_dfs_ch_switch) + wma->dfs_ic->disable_phy_err_processing = true; + + if ((ichan->ic_ieee != (wma->dfs_ic->last_radar_found_chan)) || + (pmac->sap.SapDfsInfo.disable_dfs_ch_switch == true)) { + radar_event = (struct wma_dfs_radar_indication *) + qdf_mem_malloc(sizeof(struct wma_dfs_radar_indication)); + if (radar_event == NULL) { + WMA_LOGE(FL("Failed to allocate memory for radar_event")); + qdf_spin_unlock_bh(&ic->chan_lock); + return -ENOMEM; + } + wma->dfs_ic->last_radar_found_chan = ichan->ic_ieee; + /* Indicate the radar event to HDD to stop the netif Tx queues */ + wma_radar_event.chan_freq = ichan->ic_freq; + wma_radar_event.dfs_radar_status = WMA_DFS_RADAR_FOUND; + indication_status = + wma->dfs_radar_indication_cb(hdd_ctx, &wma_radar_event); + if (indication_status == false) { + WMA_LOGE("%s:Application triggered channel switch in progress!.. drop radar event indiaction to SAP", + __func__); + qdf_mem_free(radar_event); + qdf_spin_unlock_bh(&ic->chan_lock); + return 0; + } + + WMA_LOGE("%s:DFS- RADAR INDICATED TO HDD", __func__); + + wma_radar_event.ieee_chan_number = ichan->ic_ieee; + /* + * Indicate to the radar event to SAP to + * select a new channel and set CSA IE + */ + radar_event->vdev_id = ic->vdev_id; + wma_get_channels(ichan, &radar_event->chan_list); + radar_event->dfs_radar_status = WMA_DFS_RADAR_FOUND; + radar_event->use_nol = ic->ic_dfs_usenol(ic); + wma_send_msg(wma, WMA_DFS_RADAR_IND, (void *)radar_event, 0); + WMA_LOGE("%s:DFS- WMA_DFS_RADAR_IND Message Posted", __func__); + } + qdf_spin_unlock_bh(&ic->chan_lock); + + return 0; +} + +#ifdef WLAN_FEATURE_MEMDUMP +/* + * wma_process_fw_mem_dump_req() - Function to request fw memory dump from + * firmware + * @wma: Pointer to WMA handle + * @mem_dump_req: Pointer for mem_dump_req + * + * This function sends memory dump request to firmware + * + * Return: QDF_STATUS_SUCCESS for success otherwise failure + * + */ +QDF_STATUS wma_process_fw_mem_dump_req(tp_wma_handle wma, + struct fw_dump_req *mem_dump_req) +{ + int ret; + + if (!mem_dump_req || !wma) { + WMA_LOGE(FL("input pointer is NULL")); + return QDF_STATUS_E_FAILURE; + } + + ret = wmi_unified_process_fw_mem_dump_cmd(wma->wmi_handle, + (struct fw_dump_req_param *) mem_dump_req); + if (ret) + return QDF_STATUS_E_FAILURE; + + return QDF_STATUS_SUCCESS; +} + +/** + * wma_fw_mem_dump_rsp() - send fw mem dump response to SME + * + * @req_id - request id. + * @status - copy status from the firmware. + * + * This function is called by the memory dump response handler to + * indicate SME that firmware dump copy is complete + * + * Return: QDF_STATUS + */ +static QDF_STATUS wma_fw_mem_dump_rsp(uint32_t req_id, uint32_t status) +{ + struct fw_dump_rsp *dump_rsp; + cds_msg_t sme_msg = {0}; + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + + dump_rsp = qdf_mem_malloc(sizeof(*dump_rsp)); + + if (!dump_rsp) { + WMA_LOGE(FL("Memory allocation failed.")); + qdf_status = QDF_STATUS_E_NOMEM; + return qdf_status; + } + + WMA_LOGI(FL("FW memory dump copy complete status: %d for request: %d"), + status, req_id); + + dump_rsp->request_id = req_id; + dump_rsp->dump_complete = status; + + sme_msg.type = eWNI_SME_FW_DUMP_IND; + sme_msg.bodyptr = dump_rsp; + sme_msg.bodyval = 0; + + qdf_status = cds_mq_post_message(QDF_MODULE_ID_SME, &sme_msg); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + WMA_LOGE(FL("Fail to post fw mem dump ind msg")); + qdf_mem_free(dump_rsp); + } + + return qdf_status; +} + +/** + * wma_fw_mem_dump_event_handler() - handles fw memory dump event + * + * @handle: pointer to wma handle. + * @cmd_param_info: pointer to TLV info received in the event. + * @len: length of data in @cmd_param_info + * + * This function is a handler for firmware memory dump event. + * + * Return: integer (0 for success and error code otherwise) + */ +int wma_fw_mem_dump_event_handler(void *handle, u_int8_t *cmd_param_info, + u_int32_t len) +{ + WMI_UPDATE_FW_MEM_DUMP_EVENTID_param_tlvs *param_buf; + wmi_update_fw_mem_dump_fixed_param *event; + QDF_STATUS status; + + param_buf = + (WMI_UPDATE_FW_MEM_DUMP_EVENTID_param_tlvs *) cmd_param_info; + if (!param_buf) { + WMA_LOGA("%s: Invalid stats event", __func__); + return -EINVAL; + } + + event = param_buf->fixed_param; + + status = wma_fw_mem_dump_rsp(event->request_id, + event->fw_mem_dump_complete); + if (QDF_STATUS_SUCCESS != status) { + WMA_LOGE("Error posting FW MEM DUMP RSP."); + return -EINVAL; + } + + WMA_LOGI("FW MEM DUMP RSP posted successfully"); + return 0; +} +#endif /* WLAN_FEATURE_MEMDUMP */ + +/* + * wma_process_set_ie_info() - Function to send IE info to firmware + * @wma: Pointer to WMA handle + * @ie_data: Pointer for ie data + * + * This function sends IE information to firmware + * + * Return: QDF_STATUS_SUCCESS for success otherwise failure + * + */ +QDF_STATUS wma_process_set_ie_info(tp_wma_handle wma, + struct vdev_ie_info *ie_info) +{ + struct wma_txrx_node *interface; + struct vdev_ie_info_param cmd = {0}; + int ret; + + if (!ie_info || !wma) { + WMA_LOGE(FL("input pointer is NULL")); + return QDF_STATUS_E_FAILURE; + } + + /* Validate the input */ + if (ie_info->length <= 0) { + WMA_LOGE(FL("Invalid IE length")); + return QDF_STATUS_E_INVAL; + } + + if (ie_info->vdev_id >= wma->max_bssid) { + WMA_LOGE(FL("Invalid vdev_id: %d"), ie_info->vdev_id); + return QDF_STATUS_E_INVAL; + } + + interface = &wma->interfaces[ie_info->vdev_id]; + if (!interface->is_vdev_valid) { + WMA_LOGE(FL("vdev_id: %d is not active"), ie_info->vdev_id); + return QDF_STATUS_E_INVAL; + } + + cmd.vdev_id = ie_info->vdev_id; + cmd.ie_id = ie_info->ie_id; + cmd.length = ie_info->length; + cmd.band = ie_info->band; + cmd.data = ie_info->data; + cmd.ie_source = WMA_SET_VDEV_IE_SOURCE_HOST; + + WMA_LOGD(FL("ie_id: %d, band: %d, len: %d"), + ie_info->ie_id, ie_info->band, ie_info->length); + + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_WMA, QDF_TRACE_LEVEL_DEBUG, + ie_info->data, ie_info->length); + + ret = wmi_unified_process_set_ie_info_cmd(wma->wmi_handle, + &cmd); + return ret; +} + +/** + * wma_get_bpf_caps_event_handler() - Event handler for get bpf capability + * @handle: WMA global handle + * @cmd_param_info: command event data + * @len: Length of @cmd_param_info + * + * Return: 0 on Success or Errno on failure + */ +int wma_get_bpf_caps_event_handler(void *handle, + u_int8_t *cmd_param_info, + u_int32_t len) +{ + WMI_BPF_CAPABILIY_INFO_EVENTID_param_tlvs *param_buf; + wmi_bpf_capability_info_evt_fixed_param *event; + struct sir_bpf_get_offload *bpf_get_offload; + tpAniSirGlobal pmac = (tpAniSirGlobal)cds_get_context( + QDF_MODULE_ID_PE); + + if (!pmac) { + WMA_LOGE("%s: Invalid pmac", __func__); + return -EINVAL; + } + if (!pmac->sme.pbpf_get_offload_cb) { + WMA_LOGE("%s: Callback not registered", __func__); + return -EINVAL; + } + + param_buf = (WMI_BPF_CAPABILIY_INFO_EVENTID_param_tlvs *)cmd_param_info; + event = param_buf->fixed_param; + bpf_get_offload = qdf_mem_malloc(sizeof(*bpf_get_offload)); + + if (!bpf_get_offload) { + WMA_LOGP("%s: Memory allocation failed.", __func__); + return -ENOMEM; + } + + bpf_get_offload->bpf_version = event->bpf_version; + bpf_get_offload->max_bpf_filters = event->max_bpf_filters; + bpf_get_offload->max_bytes_for_bpf_inst = + event->max_bytes_for_bpf_inst; + WMA_LOGD("%s: BPF capabilities version: %d max bpf filter size: %d", + __func__, bpf_get_offload->bpf_version, + bpf_get_offload->max_bytes_for_bpf_inst); + + WMA_LOGD("%s: sending bpf capabilities event to hdd", __func__); + pmac->sme.pbpf_get_offload_cb(pmac->hHdd, bpf_get_offload); + qdf_mem_free(bpf_get_offload); + return 0; +} + +/** + * wma_get_bpf_capabilities - Send get bpf capability to firmware + * @wma_handle: wma handle + * + * Return: QDF_STATUS enumeration. + */ +QDF_STATUS wma_get_bpf_capabilities(tp_wma_handle wma) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + wmi_bpf_get_capability_cmd_fixed_param *cmd; + wmi_buf_t wmi_buf; + uint32_t len; + u_int8_t *buf_ptr; + + if (!wma || !wma->wmi_handle) { + WMA_LOGE(FL("WMA is closed, can not issue get BPF capab")); + return QDF_STATUS_E_INVAL; + } + + if (!WMI_SERVICE_IS_ENABLED(wma->wmi_service_bitmap, + WMI_SERVICE_BPF_OFFLOAD)) { + WMA_LOGE(FL("BPF cababilities feature bit not enabled")); + return QDF_STATUS_E_FAILURE; + } + + len = sizeof(*cmd); + wmi_buf = wmi_buf_alloc(wma->wmi_handle, len); + if (!wmi_buf) { + WMA_LOGE("%s: wmi_buf_alloc failed", __func__); + return QDF_STATUS_E_NOMEM; + } + + buf_ptr = (u_int8_t *) wmi_buf_data(wmi_buf); + cmd = (wmi_bpf_get_capability_cmd_fixed_param *) buf_ptr; + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_bpf_get_capability_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN( + wmi_bpf_get_capability_cmd_fixed_param)); + + if (wmi_unified_cmd_send(wma->wmi_handle, wmi_buf, len, + WMI_BPF_GET_CAPABILITY_CMDID)) { + WMA_LOGE(FL("Failed to send BPF capability command")); + wmi_buf_free(wmi_buf); + return QDF_STATUS_E_FAILURE; + } + return status; +} + +/** + * wma_set_bpf_instructions - Set bpf instructions to firmware + * @wma: wma handle + * @bpf_set_offload: Bpf offload information to set to firmware + * + * Return: QDF_STATUS enumeration + */ +QDF_STATUS wma_set_bpf_instructions(tp_wma_handle wma, + struct sir_bpf_set_offload *bpf_set_offload) +{ + wmi_bpf_set_vdev_instructions_cmd_fixed_param *cmd; + wmi_buf_t wmi_buf; + uint32_t len = 0, len_aligned = 0; + u_int8_t *buf_ptr; + + if (!wma || !wma->wmi_handle) { + WMA_LOGE("%s: WMA is closed, can not issue set BPF capability", + __func__); + return QDF_STATUS_E_INVAL; + } + + if (!WMI_SERVICE_IS_ENABLED(wma->wmi_service_bitmap, + WMI_SERVICE_BPF_OFFLOAD)) { + WMA_LOGE(FL("BPF offload feature Disabled")); + return QDF_STATUS_E_NOSUPPORT; + } + + if (bpf_set_offload->total_length) { + len_aligned = roundup(bpf_set_offload->current_length, + sizeof(A_UINT32)); + len = len_aligned + WMI_TLV_HDR_SIZE; + } + + len += sizeof(*cmd); + wmi_buf = wmi_buf_alloc(wma->wmi_handle, len); + if (!wmi_buf) { + WMA_LOGE("%s: wmi_buf_alloc failed", __func__); + return QDF_STATUS_E_NOMEM; + } + + buf_ptr = (u_int8_t *) wmi_buf_data(wmi_buf); + cmd = (wmi_bpf_set_vdev_instructions_cmd_fixed_param *) buf_ptr; + + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_bpf_set_vdev_instructions_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN( + wmi_bpf_set_vdev_instructions_cmd_fixed_param)); + cmd->vdev_id = bpf_set_offload->session_id; + cmd->filter_id = bpf_set_offload->filter_id; + cmd->total_length = bpf_set_offload->total_length; + cmd->current_offset = bpf_set_offload->current_offset; + cmd->current_length = bpf_set_offload->current_length; + + if (bpf_set_offload->total_length) { + buf_ptr += + sizeof(wmi_bpf_set_vdev_instructions_cmd_fixed_param); + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE, len_aligned); + buf_ptr += WMI_TLV_HDR_SIZE; + qdf_mem_copy(buf_ptr, bpf_set_offload->program, + bpf_set_offload->current_length); + } + + if (wmi_unified_cmd_send(wma->wmi_handle, wmi_buf, len, + WMI_BPF_SET_VDEV_INSTRUCTIONS_CMDID)) { + WMA_LOGE(FL("Failed to send config bpf instructions command")); + wmi_buf_free(wmi_buf); + return QDF_STATUS_E_FAILURE; + } + return QDF_STATUS_SUCCESS; +} + +/** + * wma_set_tx_rx_aggregation_size() - sets tx rx aggregation sizes + * @tx_rx_aggregation_size: aggregation size parameters + * + * This function sets tx rx aggregation sizes + * + * Return: VOS_STATUS_SUCCESS on success, error number otherwise + */ +QDF_STATUS wma_set_tx_rx_aggregation_size( + struct sir_set_tx_rx_aggregation_size *tx_rx_aggregation_size) +{ + tp_wma_handle wma_handle; + wmi_vdev_set_custom_aggr_size_cmd_fixed_param *cmd; + int32_t len; + wmi_buf_t buf; + u_int8_t *buf_ptr; + int ret; + + wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + + if (!tx_rx_aggregation_size) { + WMA_LOGE("%s: invalid pointer", __func__); + return QDF_STATUS_E_INVAL; + } + + if (!wma_handle) { + WMA_LOGE("%s: WMA context is invald!", __func__); + return QDF_STATUS_E_INVAL; + } + + len = sizeof(*cmd); + buf = wmi_buf_alloc(wma_handle->wmi_handle, len); + + if (!buf) { + WMA_LOGE("%s: Failed allocate wmi buffer", __func__); + return QDF_STATUS_E_NOMEM; + } + + buf_ptr = (u_int8_t *) wmi_buf_data(buf); + cmd = (wmi_vdev_set_custom_aggr_size_cmd_fixed_param *) buf_ptr; + + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_vdev_set_custom_aggr_size_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN( + wmi_vdev_set_custom_aggr_size_cmd_fixed_param)); + + cmd->vdev_id = tx_rx_aggregation_size->vdev_id; + cmd->tx_aggr_size = tx_rx_aggregation_size->tx_aggregation_size; + cmd->rx_aggr_size = tx_rx_aggregation_size->rx_aggregation_size; + + WMA_LOGI("tx aggr: %d rx aggr: %d vdev: %d", + cmd->tx_aggr_size, cmd->rx_aggr_size, cmd->vdev_id); + + ret = wmi_unified_cmd_send(wma_handle->wmi_handle, buf, len, + WMI_VDEV_SET_CUSTOM_AGGR_SIZE_CMDID); + if (ret) { + WMA_LOGE("%s: Failed to send aggregation size command", + __func__); + wmi_buf_free(buf); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * wma_p2p_lo_start() - P2P listen offload start + * @params: p2p listen offload parameters + * + * This function sends WMI command to start P2P listen offload. + * + * Return: QDF_STATUS enumeration + */ +QDF_STATUS wma_p2p_lo_start(struct sir_p2p_lo_start *params) +{ + wmi_buf_t buf; + wmi_p2p_lo_start_cmd_fixed_param *cmd; + int32_t len = sizeof(*cmd); + tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA); + uint8_t *buf_ptr; + int ret; + int device_types_len_aligned, probe_resp_len_aligned; + + if (NULL == wma) { + WMA_LOGE("%s: wma context is NULL", __func__); + return QDF_STATUS_E_INVAL; + } + + device_types_len_aligned = qdf_roundup(params->dev_types_len, + sizeof(A_UINT32)); + probe_resp_len_aligned = qdf_roundup(params->probe_resp_len, + sizeof(A_UINT32)); + + len += 2 * WMI_TLV_HDR_SIZE + device_types_len_aligned + + probe_resp_len_aligned; + + buf = wmi_buf_alloc(wma->wmi_handle, len); + if (!buf) { + WMA_LOGP("%s: failed to allocate memory for p2p lo start", + __func__); + return QDF_STATUS_E_NOMEM; + } + + cmd = (wmi_p2p_lo_start_cmd_fixed_param *)wmi_buf_data(buf); + buf_ptr = (uint8_t *) wmi_buf_data(buf); + + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_p2p_lo_start_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN( + wmi_p2p_lo_start_cmd_fixed_param)); + + cmd->vdev_id = params->vdev_id; + cmd->ctl_flags = params->ctl_flags; + cmd->channel = params->freq; + cmd->period = params->period; + cmd->interval = params->interval; + cmd->count = params->count; + cmd->device_types_len = params->dev_types_len; + cmd->prob_resp_len = params->probe_resp_len; + + buf_ptr += sizeof(wmi_p2p_lo_start_cmd_fixed_param); + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE, + device_types_len_aligned); + buf_ptr += WMI_TLV_HDR_SIZE; + qdf_mem_copy(buf_ptr, params->device_types, params->dev_types_len); + + buf_ptr += device_types_len_aligned; + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE, probe_resp_len_aligned); + buf_ptr += WMI_TLV_HDR_SIZE; + qdf_mem_copy(buf_ptr, params->probe_resp_tmplt, params->probe_resp_len); + + WMA_LOGI("%s: Sending WMI_P2P_LO_START command, channel=%d, period=%d, interval=%d, count=%d", + __func__, cmd->channel, cmd->period, + cmd->interval, cmd->count); + + ret = wmi_unified_cmd_send(wma->wmi_handle, + buf, len, + WMI_P2P_LISTEN_OFFLOAD_START_CMDID); + if (ret) { + WMA_LOGE("Failed to send p2p lo start: %d", ret); + wmi_buf_free(buf); + } + + WMA_LOGI("%s: Successfully sent WMI_P2P_LO_START", __func__); + wma->interfaces[params->vdev_id].p2p_lo_in_progress = true; + + return ret; +} + +/** + * wma_p2p_lo_stop() - P2P listen offload stop + * @vdev_id: vdev identifier + * + * This function sends WMI command to stop P2P listen offload. + * + * Return: QDF_STATUS enumeration + */ +QDF_STATUS wma_p2p_lo_stop(u_int32_t vdev_id) +{ + wmi_buf_t buf; + wmi_p2p_lo_stop_cmd_fixed_param *cmd; + int32_t len; + tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA); + int ret; + + if (NULL == wma) { + WMA_LOGE("%s: wma context is NULL", __func__); + return QDF_STATUS_E_INVAL; + } + + len = sizeof(*cmd); + buf = wmi_buf_alloc(wma->wmi_handle, len); + if (!buf) { + WMA_LOGP("%s: failed to allocate memory for p2p lo stop", + __func__); + return QDF_STATUS_E_NOMEM; + } + cmd = (wmi_p2p_lo_stop_cmd_fixed_param *)wmi_buf_data(buf); + + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_p2p_lo_stop_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN( + wmi_p2p_lo_stop_cmd_fixed_param)); + + cmd->vdev_id = vdev_id; + + WMA_LOGI("%s: Sending WMI_P2P_LO_STOP command", __func__); + + ret = wmi_unified_cmd_send(wma->wmi_handle, + buf, len, + WMI_P2P_LISTEN_OFFLOAD_STOP_CMDID); + if (ret) { + WMA_LOGE("Failed to send p2p lo stop: %d", ret); + wmi_buf_free(buf); + } + + WMA_LOGI("%s: Successfully sent WMI_P2P_LO_STOP", __func__); + wma->interfaces[vdev_id].p2p_lo_in_progress = false; + + return ret; +} + +/** + * wma_p2p_lo_event_handler() - p2p lo event + * @handle: the WMA handle + * @event_buf: buffer with the event parameters + * @len: length of the buffer + * + * This function receives P2P listen offload stop event from FW and + * pass the event information to upper layer. + * + * Return: 0 on success + */ +int wma_p2p_lo_event_handler(void *handle, uint8_t *event_buf, + uint32_t len) +{ + tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA); + struct sir_p2p_lo_event *event; + WMI_P2P_LISTEN_OFFLOAD_STOPPED_EVENTID_param_tlvs *param_tlvs; + wmi_p2p_lo_stopped_event_fixed_param *fix_param; + tpAniSirGlobal p_mac = cds_get_context(QDF_MODULE_ID_PE); + + if (!wma) { + WMA_LOGE("%s: Invalid WMA Context", __func__); + return -EINVAL; + } + + if (!p_mac) { + WMA_LOGE("%s: Invalid p_mac", __func__); + return -EINVAL; + } + + if (!p_mac->sme.p2p_lo_event_callback) { + WMA_LOGE("%s: Callback not registered", __func__); + return -EINVAL; + } + + param_tlvs = (WMI_P2P_LISTEN_OFFLOAD_STOPPED_EVENTID_param_tlvs *) + event_buf; + fix_param = param_tlvs->fixed_param; + event = qdf_mem_malloc(sizeof(*event)); + if (event == NULL) { + WMA_LOGE("Event allocation failed"); + return -ENOMEM; + } + event->vdev_id = fix_param->vdev_id; + event->reason_code = fix_param->reason; + + p_mac->sme.p2p_lo_event_callback(p_mac->hHdd, event); + + wma->interfaces[event->vdev_id].p2p_lo_in_progress = false; + + return 0; +} + +/** + * wma_get_wakelock_stats() - Populates wake lock stats + * @stats: non-null wakelock structure to populate + * + * This function collects wake lock stats + * + * Return: QDF_STATUS_SUCCESS on success, error value otherwise + */ +QDF_STATUS wma_get_wakelock_stats(struct sir_wake_lock_stats *stats) +{ + t_wma_handle *wma; + struct sir_vdev_wow_stats *vstats; + int i; + + if (!stats) { + WMA_LOGE("%s: invalid stats pointer", __func__); + return QDF_STATUS_E_INVAL; + } + + wma = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma) { + WMA_LOGE("%s: invalid WMA context", __func__); + return QDF_STATUS_E_INVAL; + } + + /* ensure counters are zeroed */ + qdf_mem_zero(stats, sizeof(*stats)); + + /* populate global level stats */ + stats->wow_unspecified_wake_up_count = wma->wow_unspecified_wake_count; + + /* populate vdev level stats */ + for (i = 0; i < wma->max_bssid; ++i) { + if (!wma->interfaces[i].handle) + continue; + + vstats = &wma->interfaces[i].wow_stats; + + stats->wow_ucast_wake_up_count += vstats->ucast; + stats->wow_bcast_wake_up_count += vstats->bcast; + stats->wow_ipv4_mcast_wake_up_count += vstats->ipv4_mcast; + stats->wow_ipv6_mcast_wake_up_count += vstats->ipv6_mcast; + stats->wow_ipv6_mcast_ra_stats += vstats->ipv6_mcast_ra; + stats->wow_ipv6_mcast_ns_stats += vstats->ipv6_mcast_ns; + stats->wow_ipv6_mcast_na_stats += vstats->ipv6_mcast_na; + stats->wow_icmpv4_count += vstats->icmpv4; + stats->wow_icmpv6_count += vstats->icmpv6; + stats->wow_rssi_breach_wake_up_count += vstats->rssi_breach; + stats->wow_low_rssi_wake_up_count += vstats->low_rssi; + stats->wow_gscan_wake_up_count += vstats->gscan; + stats->wow_pno_complete_wake_up_count += vstats->pno_complete; + stats->wow_pno_match_wake_up_count += vstats->pno_match; + stats->wow_oem_response_wake_up_count += vstats->oem_response; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * wma_process_fw_test_cmd() - send unit test command to fw. + * @handle: wma handle + * @wma_fwtest: fw test command + * + * This function send fw test command to fw. + * + * Return: none + */ +void wma_process_fw_test_cmd(WMA_HANDLE handle, + struct set_fwtest_params *wma_fwtest) +{ + tp_wma_handle wma_handle = (tp_wma_handle) handle; + + if (!wma_handle || !wma_handle->wmi_handle) { + WMA_LOGE("%s: WMA is closed, can not issue fw test cmd", + __func__); + return; + } + + if (wmi_unified_fw_test_cmd(wma_handle->wmi_handle, + (struct set_fwtest_params *)wma_fwtest)) { + WMA_LOGE("%s: Failed to issue fw test cmd", + __func__); + return; + } +} + +/** + * wma_enable_disable_caevent_ind() - Issue WMI command to enable or + * disable ca event indication + * @wma: wma handler + * @val: boolean value true or false + * + * Return: QDF_STATUS + */ +QDF_STATUS wma_enable_disable_caevent_ind(tp_wma_handle wma, uint8_t val) +{ + WMI_CHAN_AVOID_RPT_ALLOW_CMD_fixed_param *cmd; + wmi_buf_t wmi_buf; + uint8_t *buf_ptr; + uint32_t len; + + if (!wma || !wma->wmi_handle) { + WMA_LOGE(FL("WMA is closed, can not issue set/clear CA")); + return QDF_STATUS_E_INVAL; + } + + len = sizeof(*cmd); + wmi_buf = wmi_buf_alloc(wma->wmi_handle, len); + if (!wmi_buf) { + WMA_LOGE(FL("wmi_buf_alloc failed")); + return QDF_STATUS_E_NOMEM; + } + buf_ptr = (uint8_t *) wmi_buf_data(wmi_buf); + cmd = (WMI_CHAN_AVOID_RPT_ALLOW_CMD_fixed_param *) buf_ptr; + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_WMI_CHAN_AVOID_RPT_ALLOW_CMD_fixed_param, + WMITLV_GET_STRUCT_TLVLEN( + WMI_CHAN_AVOID_RPT_ALLOW_CMD_fixed_param)); + cmd->rpt_allow = val; + if (wmi_unified_cmd_send(wma->wmi_handle, wmi_buf, len, + WMI_CHAN_AVOID_RPT_ALLOW_CMDID)) { + WMA_LOGE(FL("Failed to send enable/disable CA event command")); + wmi_buf_free(wmi_buf); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wma_set_sar_limit(WMA_HANDLE handle, + struct sar_limit_cmd_params *sar_limit_params) +{ + int ret; + tp_wma_handle wma = (tp_wma_handle) handle; + + if (!wma || !wma->wmi_handle) { + WMA_LOGE("%s: WMA is closed, can not issue set sar limit msg", + __func__); + return QDF_STATUS_E_INVAL; + } + + if (sar_limit_params == NULL) { + WMA_LOGE("%s: set sar limit ptr NULL", + __func__); + return QDF_STATUS_E_INVAL; + } + + ret = wmi_unified_send_sar_limit_cmd(wma->wmi_handle, + sar_limit_params); + + return ret; +} + +#ifdef WLAN_FEATURE_DISA +/** + * wma_encrypt_decrypt_msg() - + * @encrypt_decrypt_params: encryption/decryption params + * @data_len: data length + * @encrypt_decrypt_cb: encrypt/decrypt callback + * + * This function sends WMI command to check encryption/decryption engine. + * + * Return: QDF_STATUS enumeration + */ +QDF_STATUS wma_encrypt_decrypt_msg(WMA_HANDLE handle, + struct encrypt_decrypt_req_params *encrypt_decrypt_params) +{ + int ret; + tp_wma_handle wma = (tp_wma_handle) handle; + + if (!wma || !wma->wmi_handle) { + WMA_LOGE("%s: WMA is closed, can not issue encrypt/decrypt msg", + __func__); + return QDF_STATUS_E_INVAL; + } + + if (encrypt_decrypt_params == NULL) { + WMA_LOGE("%s: encrypt/decrypt ptr NULL", + __func__); + return QDF_STATUS_E_INVAL; + } + + ret = wmi_unified_encrypt_decrypt_send_cmd(wma->wmi_handle, + encrypt_decrypt_params); + + return ret; +} + +/** + * wma_encrypt_decrypt_msg_handler() - handle encrypt/decrypt data + * indicated by FW + * @handle: wma context + * @data: event buffer + * @data len: length of event buffer + * + * Return: 0 on success + */ +int wma_encrypt_decrypt_msg_handler(void *handle, uint8_t *data, + uint32_t data_len) +{ + WMI_VDEV_ENCRYPT_DECRYPT_DATA_RESP_EVENTID_param_tlvs *param_buf; + wmi_vdev_encrypt_decrypt_data_resp_event_fixed_param *data_event; + struct sir_encrypt_decrypt_rsp_params encrypt_decrypt_rsp_params; + tp_wma_handle wma = handle; + u_int8_t *buf_ptr; + tpAniSirGlobal pmac; + + if (data == NULL) { + WMA_LOGE("%s: invalid pointer", __func__); + return -EINVAL; + } + + if (wma == NULL) { + WMA_LOGE("%s: wma context is NULL", __func__); + return -EINVAL; + } + + WMA_LOGE("%s: received WMI_VDEV_ENCRYPT_DECRYPT_DATA_RESP_EVENTID ", + __func__); + + pmac = (tpAniSirGlobal)cds_get_context(QDF_MODULE_ID_PE); + + if (!pmac) { + WMA_LOGE("%s: Invalid pmac", __func__); + return -EINVAL; + } + if (!pmac->sme.encrypt_decrypt_cb) { + WMA_LOGE("%s: Callback not registered", __func__); + return -EINVAL; + } + + param_buf = + (WMI_VDEV_ENCRYPT_DECRYPT_DATA_RESP_EVENTID_param_tlvs *)data; + if (!param_buf) { + WMA_LOGE("%s: Invalid response data buf", __func__); + return -EINVAL; + } + + data_event = param_buf->fixed_param; + + encrypt_decrypt_rsp_params.vdev_id = data_event->vdev_id; + encrypt_decrypt_rsp_params.status = data_event->status; + encrypt_decrypt_rsp_params.data_length = data_event->data_length; + + if (encrypt_decrypt_rsp_params.data_length) { + buf_ptr = + (uint8_t *)data_event + + sizeof( + wmi_vdev_encrypt_decrypt_data_resp_event_fixed_param) + + WMI_TLV_HDR_SIZE; + + encrypt_decrypt_rsp_params.data = buf_ptr; + } + + pmac->sme.encrypt_decrypt_cb(pmac->hHdd, &encrypt_decrypt_rsp_params); + + return 0; +} +#endif + +/** + * wma_get_arp_stats_handler() - handle arp stats data + * indicated by FW + * @handle: wma context + * @data: event buffer + * @data len: length of event buffer + * + * Return: 0 on success + */ +int wma_get_arp_stats_handler(void *handle, uint8_t *data, + uint32_t data_len) +{ + WMI_VDEV_GET_ARP_STAT_EVENTID_param_tlvs *param_buf; + wmi_vdev_get_arp_stats_event_fixed_param *data_event; + struct rsp_stats rsp; + tpAniSirGlobal mac = cds_get_context(QDF_MODULE_ID_PE); + + ENTER(); + + if (!mac) { + WMA_LOGE("%s: Invalid mac context", __func__); + return -EINVAL; + } + + if (!mac->sme.get_arp_stats_cb) { + WMA_LOGE("%s: Callback not registered", __func__); + return -EINVAL; + } + + if (data == NULL) { + WMA_LOGE("%s: invalid pointer", __func__); + return -EINVAL; + } + param_buf = (WMI_VDEV_GET_ARP_STAT_EVENTID_param_tlvs *)data; + if (!param_buf) { + WMA_LOGE("%s: Invalid get arp stats event", __func__); + return -EINVAL; + } + data_event = param_buf->fixed_param; + if (!data_event) { + WMA_LOGE("%s: Invalid get arp stats data event", __func__); + return -EINVAL; + } + rsp.arp_req_enqueue = data_event->arp_req_enqueue; + rsp.vdev_id = data_event->vdev_id; + rsp.arp_req_tx_success = data_event->arp_req_tx_success; + rsp.arp_req_tx_failure = data_event->arp_req_tx_failure; + rsp.arp_rsp_recvd = data_event->arp_rsp_recvd; + rsp.out_of_order_arp_rsp_drop_cnt = + data_event->out_of_order_arp_rsp_drop_cnt; + rsp.dad_detected = data_event->dad_detected; + rsp.connect_status = data_event->connect_status; + rsp.ba_session_establishment_status = + data_event->ba_session_establishment_status; + + mac->sme.get_arp_stats_cb(mac->hHdd, &rsp); + + EXIT(); + + return 0; +} + +/** + * wma_unified_power_debug_stats_event_handler() - WMA handler function to + * handle Power stats event from firmware + * @handle: Pointer to wma handle + * @cmd_param_info: Pointer to Power stats event TLV + * @len: Length of the cmd_param_info + * + * Return: 0 on success, error number otherwise + */ +#ifdef WLAN_POWER_DEBUGFS +int wma_unified_power_debug_stats_event_handler(void *handle, + uint8_t *cmd_param_info, uint32_t len) +{ + WMI_PDEV_CHIP_POWER_STATS_EVENTID_param_tlvs *param_tlvs; + struct power_stats_response *power_stats_results; + wmi_pdev_chip_power_stats_event_fixed_param *param_buf; + uint32_t power_stats_len, stats_registers_len, *debug_registers; + + tpAniSirGlobal mac = (tpAniSirGlobal)cds_get_context(QDF_MODULE_ID_PE); + param_tlvs = + (WMI_PDEV_CHIP_POWER_STATS_EVENTID_param_tlvs *) cmd_param_info; + + param_buf = (wmi_pdev_chip_power_stats_event_fixed_param *) + param_tlvs->fixed_param; + if (!mac || !mac->sme.power_stats_resp_callback) { + WMA_LOGD("%s: NULL mac ptr or HDD callback is null", __func__); + return -EINVAL; + } + + if (!param_buf) { + WMA_LOGD("%s: NULL power stats event fixed param", __func__); + return -EINVAL; + } + + debug_registers = param_tlvs->debug_registers; + stats_registers_len = + (sizeof(uint32_t) * param_buf->num_debug_register); + power_stats_len = stats_registers_len + sizeof(*power_stats_results); + power_stats_results = qdf_mem_malloc(power_stats_len); + if (!power_stats_results) { + WMA_LOGD("%s: could not allocate mem for power stats results", + __func__); + return -ENOMEM; + } + WMA_LOGD("Cumulative sleep time %d cumulative total on time %d deep sleep enter counter %d last deep sleep enter tstamp ts %d debug registers fmt %d num debug register %d", + param_buf->cumulative_sleep_time_ms, + param_buf->cumulative_total_on_time_ms, + param_buf->deep_sleep_enter_counter, + param_buf->last_deep_sleep_enter_tstamp_ms, + param_buf->debug_register_fmt, + param_buf->num_debug_register); + + power_stats_results->cumulative_sleep_time_ms + = param_buf->cumulative_sleep_time_ms; + power_stats_results->cumulative_total_on_time_ms + = param_buf->cumulative_total_on_time_ms; + power_stats_results->deep_sleep_enter_counter + = param_buf->deep_sleep_enter_counter; + power_stats_results->last_deep_sleep_enter_tstamp_ms + = param_buf->last_deep_sleep_enter_tstamp_ms; + power_stats_results->debug_register_fmt + = param_buf->debug_register_fmt; + power_stats_results->num_debug_register + = param_buf->num_debug_register; + + power_stats_results->debug_registers + = (uint32_t *)(power_stats_results + 1); + + qdf_mem_copy(power_stats_results->debug_registers, + debug_registers, stats_registers_len); + + mac->sme.power_stats_resp_callback(power_stats_results, + mac->sme.power_debug_stats_context); + qdf_mem_free(power_stats_results); + return 0; +} +#else +int wma_unified_power_debug_stats_event_handler(void *handle, + uint8_t *cmd_param_info, uint32_t len) +{ + return 0; +} +#endif + +#ifdef WLAN_FEATURE_UDP_RESPONSE_OFFLOAD +/** +* wma_send_udp_resp_offload_cmd() - send wmi cmd of udp response offload +* infomation to fw. +* @wma_handle: wma handler +* @udp_response: udp_resp_offload struct pointer +* +* Return: QDF_STATUS +*/ +QDF_STATUS wma_send_udp_resp_offload_cmd(tp_wma_handle wma_handle, + struct udp_resp_offload *udp_response) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + wmi_buf_t buf; + WMI_WOW_UDP_SVC_OFLD_CMD_fixed_param *cmd; + uint16_t len; + uint16_t pattern_len = 0; + uint16_t response_len = 0; + uint16_t udp_len = 0; + uint16_t resp_len = 0; + + WMA_LOGD("%s: Enter", __func__); + if (1 == udp_response->enable) { + pattern_len = strlen(udp_response->udp_payload_filter); + response_len = strlen(udp_response->udp_response_payload); + } + + udp_len = (pattern_len % 4) ? + (4 * ((pattern_len / 4) + 1)) : (pattern_len); + + resp_len = (response_len % 4) ? + (4 * ((response_len / 4) + 1)) : (response_len); + + + len = sizeof(*cmd) + udp_len + resp_len + 2 * WMI_TLV_HDR_SIZE; + buf = wmi_buf_alloc(wma_handle->wmi_handle, len); + if (!buf) { + WMA_LOGE("wmi_buf_alloc failed"); + return QDF_STATUS_E_NOMEM; + } + + cmd = (WMI_WOW_UDP_SVC_OFLD_CMD_fixed_param *)wmi_buf_data(buf); + + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_WMI_WOW_UDP_SVC_OFLD_CMD_fixed_param, + WMITLV_GET_STRUCT_TLVLEN( + WMI_WOW_UDP_SVC_OFLD_CMD_fixed_param)); + + cmd->vdev_id = udp_response->vdev_id; + cmd->enable = udp_response->enable; + cmd->dest_port = udp_response->dest_port; + cmd->pattern_len = pattern_len; + cmd->response_len = response_len; + + + WMITLV_SET_HDR((A_UINT32 *)(cmd + 1), + WMITLV_TAG_ARRAY_BYTE, + udp_len); + + qdf_mem_copy((void *)(cmd + 1) + WMI_TLV_HDR_SIZE, + (void *)udp_response->udp_payload_filter, + cmd->pattern_len); + WMITLV_SET_HDR((A_UINT32 *)((void *)(cmd + 1) + + WMI_TLV_HDR_SIZE + udp_len), + WMITLV_TAG_ARRAY_BYTE, + resp_len); + + qdf_mem_copy((void *)(cmd + 1) + WMI_TLV_HDR_SIZE + + udp_len + WMI_TLV_HDR_SIZE, + (void *)udp_response->udp_response_payload, + cmd->response_len); + + WMA_LOGD("wma_set_udp_resp_cmd: enable:%d vdev_id:%d dest_port:%u", + cmd->enable, cmd->vdev_id, cmd->dest_port); + + if (wmi_unified_cmd_send(wma_handle->wmi_handle, buf, len, + WMI_WOW_UDP_SVC_OFLD_CMDID)) { + WMA_LOGE("Failed to send set udp resp offload"); + wmi_buf_free(buf); + status = QDF_STATUS_E_FAILURE; + } + + WMA_LOGD("%s: Exit", __func__); + return status; +} +#else +inline QDF_STATUS wma_send_udp_resp_offload_cmd(tp_wma_handle wma_handle, + struct udp_resp_offload *udp_response) +{ + return QDF_STATUS_E_FAILURE; +} +#endif diff --git a/drivers/staging/qcacld-3.0/core/wma/src/wma_main.c b/drivers/staging/qcacld-3.0/core/wma/src/wma_main.c new file mode 100644 index 0000000000000000000000000000000000000000..ce314c1d556843a7ff297e5fefac22a3b2a8ae7a --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/wma/src/wma_main.c @@ -0,0 +1,7594 @@ +/* + * Copyright (c) 2013-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: wma_main.c + * + * This file contains wma initialization and FW exchange + * related functions. + */ + +/* Header files */ + +#include "wma.h" +#include "wma_api.h" +#include "cds_api.h" +#include "wmi_unified_api.h" +#include "wlan_qct_sys.h" +#include "wni_api.h" +#include "ani_global.h" +#include "wmi_unified.h" +#include "wni_cfg.h" +#include "cfg_api.h" +#if defined(CONFIG_HL_SUPPORT) +#include "wlan_tgt_def_config_hl.h" +#else +#include "wlan_tgt_def_config.h" +#endif +#include "qdf_nbuf.h" +#include "qdf_types.h" +#include "qdf_mem.h" +#include "ol_txrx_peer_find.h" + +#include "wma_types.h" +#include "lim_api.h" +#include "lim_session_utils.h" + +#include "cds_utils.h" + +#if !defined(REMOVE_PKT_LOG) +#include "pktlog_ac.h" +#endif /* REMOVE_PKT_LOG */ + +#include "dbglog_host.h" +#include "wmi_version_whitelist.h" +#include "csr_api.h" +#include "ol_fw.h" + +#include "dfs.h" +#include "wma_internal.h" + +#include "wma_ocb.h" +#include "cds_concurrency.h" +#include "cdp_txrx_cfg.h" +#include "cdp_txrx_flow_ctrl_legacy.h" +#include "cdp_txrx_flow_ctrl_v2.h" +#include "cdp_txrx_ipa.h" +#include "wma_nan_datapath.h" + +#define WMA_LOG_COMPLETION_TIMER 10000 /* 10 seconds */ + +#define WMI_TLV_HEADROOM 128 + +static uint32_t g_fw_wlan_feat_caps; + +/** + * wma_get_fw_wlan_feat_caps() - get fw feature capablity + * @featEnumValue: feature enum value + * + * Return: true/false + */ +uint8_t wma_get_fw_wlan_feat_caps(uint8_t featEnumValue) +{ + return (g_fw_wlan_feat_caps & (1 << featEnumValue)) ? true : false; +} + +/** + * wma_service_ready_ext_evt_timeout() - Service ready extended event timeout + * @data: Timeout handler data + * + * This function is called when the FW fails to send WMI_SERVICE_READY_EXT_EVENT + * message + * + * Return: None + */ +static void wma_service_ready_ext_evt_timeout(void *data) +{ + tp_wma_handle wma_handle; + + WMA_LOGA("%s: Timeout waiting for WMI_SERVICE_READY_EXT_EVENT", + __func__); + + wma_handle = (tp_wma_handle) data; + + if (!wma_handle) { + WMA_LOGE("%s: Invalid WMA handle", __func__); + goto end; + } + +end: + /* Assert here. Panic is being called in insmod thread */ + QDF_ASSERT(0); +} + +/** + * wma_get_ini_handle() - API to get WMA ini info handle + * @wma: WMA Handle + * + * Returns the pointer to WMA ini structure. + * Return: struct wma_ini_config + */ +struct wma_ini_config *wma_get_ini_handle(tp_wma_handle wma) +{ + if (!wma) { + WMA_LOGE("%s: Invalid WMA context\n", __func__); + return NULL; + } + + return &wma->ini_config; +} + +#define MAX_SUPPORTED_PEERS_REV1_1 14 +#define MAX_SUPPORTED_PEERS_REV1_3 32 +#define MIN_NO_OF_PEERS 1 + +/** + * wma_get_number_of_peers_supported - API to query for number of peers + * supported + * @wma: WMA Handle + * + * Return: Max Number of Peers Supported + */ +static uint8_t wma_get_number_of_peers_supported(tp_wma_handle wma) +{ + struct hif_target_info *tgt_info; + struct wma_ini_config *cfg = wma_get_ini_handle(wma); + uint8_t max_no_of_peers = cfg ? cfg->max_no_of_peers : MIN_NO_OF_PEERS; + struct hif_opaque_softc *scn = cds_get_context(QDF_MODULE_ID_HIF); + + if (!scn) { + WMA_LOGE("%s: Invalid wma handle", __func__); + return 0; + } + + tgt_info = hif_get_target_info_handle(scn); + + switch (tgt_info->target_version) { + case AR6320_REV1_1_VERSION: + if (max_no_of_peers > MAX_SUPPORTED_PEERS_REV1_1) + max_no_of_peers = MAX_SUPPORTED_PEERS_REV1_1; + break; + default: + if (max_no_of_peers > MAX_SUPPORTED_PEERS_REV1_3) + max_no_of_peers = MAX_SUPPORTED_PEERS_REV1_3; + break; + } + + return max_no_of_peers; +} + +/** + * wma_set_default_tgt_config() - set default tgt config + * @wma_handle: wma handle + * + * Return: none + */ +static void wma_set_default_tgt_config(tp_wma_handle wma_handle) +{ + uint8_t no_of_peers_supported; + wmi_resource_config tgt_cfg = { + 0, /* Filling zero for TLV Tag and Length fields */ + CFG_TGT_NUM_VDEV, + CFG_TGT_NUM_PEERS + CFG_TGT_NUM_VDEV + 2, + CFG_TGT_NUM_OFFLOAD_PEERS, + CFG_TGT_NUM_OFFLOAD_REORDER_BUFFS, + CFG_TGT_NUM_PEER_KEYS, + CFG_TGT_NUM_TIDS, + CFG_TGT_AST_SKID_LIMIT, + CFG_TGT_DEFAULT_TX_CHAIN_MASK, + CFG_TGT_DEFAULT_RX_CHAIN_MASK, + {CFG_TGT_RX_TIMEOUT_LO_PRI, CFG_TGT_RX_TIMEOUT_LO_PRI, + CFG_TGT_RX_TIMEOUT_LO_PRI, CFG_TGT_RX_TIMEOUT_HI_PRI}, + CFG_TGT_RX_DECAP_MODE, + CFG_TGT_DEFAULT_SCAN_MAX_REQS, + CFG_TGT_DEFAULT_BMISS_OFFLOAD_MAX_VDEV, + CFG_TGT_DEFAULT_ROAM_OFFLOAD_MAX_VDEV, + CFG_TGT_DEFAULT_ROAM_OFFLOAD_MAX_PROFILES, + CFG_TGT_DEFAULT_NUM_MCAST_GROUPS, + CFG_TGT_DEFAULT_NUM_MCAST_TABLE_ELEMS, + CFG_TGT_DEFAULT_MCAST2UCAST_MODE, + CFG_TGT_DEFAULT_TX_DBG_LOG_SIZE, + CFG_TGT_WDS_ENTRIES, + CFG_TGT_DEFAULT_DMA_BURST_SIZE, + CFG_TGT_DEFAULT_MAC_AGGR_DELIM, + CFG_TGT_DEFAULT_RX_SKIP_DEFRAG_TIMEOUT_DUP_DETECTION_CHECK, + CFG_TGT_DEFAULT_VOW_CONFIG, + CFG_TGT_DEFAULT_GTK_OFFLOAD_MAX_VDEV, + CFG_TGT_NUM_MSDU_DESC, + CFG_TGT_MAX_FRAG_TABLE_ENTRIES, + CFG_TGT_NUM_TDLS_VDEVS, + CFG_TGT_NUM_TDLS_CONN_TABLE_ENTRIES, + CFG_TGT_DEFAULT_BEACON_TX_OFFLOAD_MAX_VDEV, + CFG_TGT_MAX_MULTICAST_FILTER_ENTRIES, + 0, + 0, + 0, + CFG_TGT_NUM_TDLS_CONC_SLEEP_STAS, + CFG_TGT_NUM_TDLS_CONC_BUFFER_STAS, + 0, + CFG_TGT_NUM_OCB_VDEVS, + CFG_TGT_NUM_OCB_CHANNELS, + CFG_TGT_NUM_OCB_SCHEDULES, + }; + + no_of_peers_supported = wma_get_number_of_peers_supported(wma_handle); + tgt_cfg.num_peers = no_of_peers_supported + CFG_TGT_NUM_VDEV + 2; + tgt_cfg.num_tids = (2 * (no_of_peers_supported + CFG_TGT_NUM_VDEV + 2)); + tgt_cfg.scan_max_pending_req = wma_handle->max_scan; + + WMI_RSRC_CFG_FLAG_MGMT_COMP_EVT_BUNDLE_SUPPORT_SET(tgt_cfg.flag1, 1); + WMI_RSRC_CFG_FLAG_TX_MSDU_ID_NEW_PARTITION_SUPPORT_SET(tgt_cfg.flag1, + 1); + + WMITLV_SET_HDR(&tgt_cfg.tlv_header, + WMITLV_TAG_STRUC_wmi_resource_config, + WMITLV_GET_STRUCT_TLVLEN(wmi_resource_config)); + /* reduce the peer/vdev if CFG_TGT_NUM_MSDU_DESC exceeds 1000 */ +#ifdef PERE_IP_HDR_ALIGNMENT_WAR + if (scn->host_80211_enable) { + /* + * To make the IP header begins at dword aligned address, + * we make the decapsulation mode as Native Wifi. + */ + tgt_cfg.rx_decap_mode = CFG_TGT_RX_DECAP_MODE_NWIFI; + } +#endif /* PERE_IP_HDR_ALIGNMENT_WAR */ + if (QDF_GLOBAL_MONITOR_MODE == cds_get_conparam()) + tgt_cfg.rx_decap_mode = CFG_TGT_RX_DECAP_MODE_RAW; + + wma_handle->wlan_resource_config = tgt_cfg; +} + +/** + * wma_cli_get_command() - WMA "get" command processor + * @vdev_id: virtual device for the command + * @param_id: parameter id + * @vpdev: parameter category + * + * Return: parameter value on success, -EINVAL on failure + */ +int wma_cli_get_command(int vdev_id, int param_id, int vpdev) +{ + int ret = 0; + tp_wma_handle wma; + struct wma_txrx_node *intr = NULL; + + wma = cds_get_context(QDF_MODULE_ID_WMA); + + if (NULL == wma) { + WMA_LOGE("%s: Invalid wma handle", __func__); + return -EINVAL; + } + + intr = wma->interfaces; + + if (VDEV_CMD == vpdev) { + switch (param_id) { + case WMI_VDEV_PARAM_NSS: + ret = intr[vdev_id].config.nss; + break; +#ifdef QCA_SUPPORT_GTX + case WMI_VDEV_PARAM_GTX_HT_MCS: + ret = intr[vdev_id].config.gtx_info.gtxRTMask[0]; + break; + case WMI_VDEV_PARAM_GTX_VHT_MCS: + ret = intr[vdev_id].config.gtx_info.gtxRTMask[1]; + break; + case WMI_VDEV_PARAM_GTX_USR_CFG: + ret = intr[vdev_id].config.gtx_info.gtxUsrcfg; + break; + case WMI_VDEV_PARAM_GTX_THRE: + ret = intr[vdev_id].config.gtx_info.gtxPERThreshold; + break; + case WMI_VDEV_PARAM_GTX_MARGIN: + ret = intr[vdev_id].config.gtx_info.gtxPERMargin; + break; + case WMI_VDEV_PARAM_GTX_STEP: + ret = intr[vdev_id].config.gtx_info.gtxTPCstep; + break; + case WMI_VDEV_PARAM_GTX_MINTPC: + ret = intr[vdev_id].config.gtx_info.gtxTPCMin; + break; + case WMI_VDEV_PARAM_GTX_BW_MASK: + ret = intr[vdev_id].config.gtx_info.gtxBWMask; + break; +#endif /* QCA_SUPPORT_GTX */ + case WMI_VDEV_PARAM_LDPC: + ret = intr[vdev_id].config.ldpc; + break; + case WMI_VDEV_PARAM_TX_STBC: + ret = intr[vdev_id].config.tx_stbc; + break; + case WMI_VDEV_PARAM_RX_STBC: + ret = intr[vdev_id].config.rx_stbc; + break; + case WMI_VDEV_PARAM_SGI: + ret = intr[vdev_id].config.shortgi; + break; + case WMI_VDEV_PARAM_ENABLE_RTSCTS: + ret = intr[vdev_id].config.rtscts_en; + break; + case WMI_VDEV_PARAM_CHWIDTH: + ret = intr[vdev_id].config.chwidth; + break; + case WMI_VDEV_PARAM_FIXED_RATE: + ret = intr[vdev_id].config.tx_rate; + break; + default: + WMA_LOGE("Invalid cli_get vdev command/Not" + " yet implemented 0x%x", param_id); + return -EINVAL; + } + } else if (PDEV_CMD == vpdev) { + switch (param_id) { + case WMI_PDEV_PARAM_ANI_ENABLE: + ret = wma->pdevconfig.ani_enable; + break; + case WMI_PDEV_PARAM_ANI_POLL_PERIOD: + ret = wma->pdevconfig.ani_poll_len; + break; + case WMI_PDEV_PARAM_ANI_LISTEN_PERIOD: + ret = wma->pdevconfig.ani_listen_len; + break; + case WMI_PDEV_PARAM_ANI_OFDM_LEVEL: + ret = wma->pdevconfig.ani_ofdm_level; + break; + case WMI_PDEV_PARAM_ANI_CCK_LEVEL: + ret = wma->pdevconfig.ani_cck_level; + break; + case WMI_PDEV_PARAM_DYNAMIC_BW: + ret = wma->pdevconfig.cwmenable; + break; + case WMI_PDEV_PARAM_CTS_CBW: + ret = wma->pdevconfig.cts_cbw; + break; + case WMI_PDEV_PARAM_TX_CHAIN_MASK: + ret = wma->pdevconfig.txchainmask; + break; + case WMI_PDEV_PARAM_RX_CHAIN_MASK: + ret = wma->pdevconfig.rxchainmask; + break; + case WMI_PDEV_PARAM_TXPOWER_LIMIT2G: + ret = wma->pdevconfig.txpow2g; + break; + case WMI_PDEV_PARAM_TXPOWER_LIMIT5G: + ret = wma->pdevconfig.txpow5g; + break; + case WMI_PDEV_PARAM_BURST_ENABLE: + ret = wma->pdevconfig.burst_enable; + break; + case WMI_PDEV_PARAM_BURST_DUR: + ret = wma->pdevconfig.burst_dur; + break; + default: + WMA_LOGE("Invalid cli_get pdev command/Not" + " yet implemented 0x%x", param_id); + return -EINVAL; + } + } else if (GEN_CMD == vpdev) { + switch (param_id) { + case GEN_VDEV_PARAM_AMPDU: + ret = intr[vdev_id].config.ampdu; + break; + case GEN_VDEV_PARAM_AMSDU: + ret = intr[vdev_id].config.amsdu; + break; + case GEN_VDEV_ROAM_SYNCH_DELAY: + ret = intr[vdev_id].roam_synch_delay; + break; + default: + WMA_LOGE("Invalid generic vdev command/Not" + " yet implemented 0x%x", param_id); + return -EINVAL; + } + } else if (PPS_CMD == vpdev) { + switch (param_id) { + case WMI_VDEV_PPS_PAID_MATCH: + ret = intr[vdev_id].config.pps_params.paid_match_enable; + break; + case WMI_VDEV_PPS_GID_MATCH: + ret = intr[vdev_id].config.pps_params.gid_match_enable; + break; + case WMI_VDEV_PPS_EARLY_TIM_CLEAR: + ret = intr[vdev_id].config.pps_params.tim_clear; + break; + case WMI_VDEV_PPS_EARLY_DTIM_CLEAR: + ret = intr[vdev_id].config.pps_params.dtim_clear; + break; + case WMI_VDEV_PPS_EOF_PAD_DELIM: + ret = intr[vdev_id].config.pps_params.eof_delim; + break; + case WMI_VDEV_PPS_MACADDR_MISMATCH: + ret = intr[vdev_id].config.pps_params.mac_match; + break; + case WMI_VDEV_PPS_DELIM_CRC_FAIL: + ret = intr[vdev_id].config.pps_params.delim_fail; + break; + case WMI_VDEV_PPS_GID_NSTS_ZERO: + ret = intr[vdev_id].config.pps_params.nsts_zero; + break; + case WMI_VDEV_PPS_RSSI_CHECK: + ret = intr[vdev_id].config.pps_params.rssi_chk; + break; + default: + WMA_LOGE("Invalid pps vdev command/Not" + " yet implemented 0x%x", param_id); + return -EINVAL; + } + } else if (QPOWER_CMD == vpdev) { + switch (param_id) { + case WMI_STA_PS_PARAM_QPOWER_PSPOLL_COUNT: + ret = intr[vdev_id].config.qpower_params. + max_ps_poll_cnt; + break; + case WMI_STA_PS_PARAM_QPOWER_MAX_TX_BEFORE_WAKE: + ret = intr[vdev_id].config.qpower_params. + max_tx_before_wake; + break; + case WMI_STA_PS_PARAM_QPOWER_SPEC_PSPOLL_WAKE_INTERVAL: + ret = intr[vdev_id].config.qpower_params. + spec_ps_poll_wake_interval; + break; + case WMI_STA_PS_PARAM_QPOWER_SPEC_MAX_SPEC_NODATA_PSPOLL: + ret = intr[vdev_id].config.qpower_params. + max_spec_nodata_ps_poll; + break; + default: + WMA_LOGE("Invalid generic vdev command/Not" + " yet implemented 0x%x", param_id); + return -EINVAL; + } + } else if (GTX_CMD == vpdev) { + switch (param_id) { + case WMI_VDEV_PARAM_GTX_HT_MCS: + ret = intr[vdev_id].config.gtx_info.gtxRTMask[0]; + break; + case WMI_VDEV_PARAM_GTX_VHT_MCS: + ret = intr[vdev_id].config.gtx_info.gtxRTMask[1]; + break; + case WMI_VDEV_PARAM_GTX_USR_CFG: + ret = intr[vdev_id].config.gtx_info.gtxUsrcfg; + break; + case WMI_VDEV_PARAM_GTX_THRE: + ret = intr[vdev_id].config.gtx_info.gtxPERThreshold; + break; + case WMI_VDEV_PARAM_GTX_MARGIN: + ret = intr[vdev_id].config.gtx_info.gtxPERMargin; + break; + case WMI_VDEV_PARAM_GTX_STEP: + ret = intr[vdev_id].config.gtx_info.gtxTPCstep; + break; + case WMI_VDEV_PARAM_GTX_MINTPC: + ret = intr[vdev_id].config.gtx_info.gtxTPCMin; + break; + case WMI_VDEV_PARAM_GTX_BW_MASK: + ret = intr[vdev_id].config.gtx_info.gtxBWMask; + break; + default: + WMA_LOGE("Invalid generic vdev command/Not" + " yet implemented 0x%x", param_id); + return -EINVAL; + } + } + return ret; +} + +/** + * wma_cli_set2_command() - WMA "set 2 params" command processor + * @vdev_id: virtual device for the command + * @param_id: parameter id + * @sval1: first parameter value + * @sval2: second parameter value + * @vpdev: parameter category + * + * Command handler for set operations which require 2 parameters + * + * Return: 0 on success, errno on failure + */ +int wma_cli_set2_command(int vdev_id, int param_id, int sval1, + int sval2, int vpdev) +{ + cds_msg_t msg = { 0 }; + wma_cli_set_cmd_t *iwcmd; + + iwcmd = qdf_mem_malloc(sizeof(*iwcmd)); + if (!iwcmd) { + WMA_LOGE("%s: Failed alloc memory for iwcmd", __func__); + return -ENOMEM; + } + + qdf_mem_zero(iwcmd, sizeof(*iwcmd)); + iwcmd->param_value = sval1; + iwcmd->param_sec_value = sval2; + iwcmd->param_vdev_id = vdev_id; + iwcmd->param_id = param_id; + iwcmd->param_vp_dev = vpdev; + msg.type = WMA_CLI_SET_CMD; + msg.reserved = 0; + msg.bodyptr = iwcmd; + + if (QDF_STATUS_SUCCESS != + cds_mq_post_message(QDF_MODULE_ID_WMA, &msg)) { + WMA_LOGP("%s: Failed to post WMA_CLI_SET_CMD msg", + __func__); + qdf_mem_free(iwcmd); + return -EIO; + } + return 0; +} + +/** + * wma_cli_set_command() - WMA "set" command processor + * @vdev_id: virtual device for the command + * @param_id: parameter id + * @sval: parameter value + * @vpdev: parameter category + * + * Command handler for set operations + * + * Return: 0 on success, errno on failure + */ +int wma_cli_set_command(int vdev_id, int param_id, int sval, int vpdev) +{ + return wma_cli_set2_command(vdev_id, param_id, sval, 0, vpdev); + +} + +/** + * wma_set_priv_cfg() - set private config parameters + * @wma_handle: wma handle + * @privcmd: private command + * + * Return: 0 for success or error code + */ +static int32_t wma_set_priv_cfg(tp_wma_handle wma_handle, + wma_cli_set_cmd_t *privcmd) +{ + int32_t ret = 0; + + switch (privcmd->param_id) { + case WMA_VDEV_TXRX_FWSTATS_ENABLE_CMDID: + ret = wma_set_txrx_fw_stats_level(wma_handle, + privcmd->param_vdev_id, + privcmd->param_value); + break; + case WMA_VDEV_TXRX_FWSTATS_RESET_CMDID: + ret = wma_txrx_fw_stats_reset(wma_handle, + privcmd->param_vdev_id, + privcmd->param_value); + break; + case WMI_STA_SMPS_FORCE_MODE_CMDID: + ret = wma_set_mimops(wma_handle, + privcmd->param_vdev_id, + privcmd->param_value); + break; + case WMI_STA_SMPS_PARAM_CMDID: + wma_set_smps_params(wma_handle, privcmd->param_vdev_id, + privcmd->param_value); + break; + case WMA_VDEV_MCC_SET_TIME_LATENCY: + { + /* Extract first MCC adapter/vdev channel number and latency */ + uint8_t mcc_channel = privcmd->param_value & 0x000000FF; + uint8_t mcc_channel_latency = + (privcmd->param_value & 0x0000FF00) >> 8; + int ret = -1; + WMA_LOGD("%s: Parsed input: Channel #1:%d, latency:%dms", + __func__, mcc_channel, mcc_channel_latency); + ret = wma_set_mcc_channel_time_latency(wma_handle, + mcc_channel, + mcc_channel_latency); + } + break; + case WMA_VDEV_MCC_SET_TIME_QUOTA: + { + /* Extract the MCC 2 adapters/vdevs channel numbers and time + * quota value for the first adapter only (which is specified + * in iwpriv command. + */ + uint8_t adapter_2_chan_number = + privcmd->param_value & 0x000000FF; + uint8_t adapter_1_chan_number = + (privcmd->param_value & 0x0000FF00) >> 8; + uint8_t adapter_1_quota = + (privcmd->param_value & 0x00FF0000) >> 16; + int ret = -1; + + WMA_LOGD("%s: Parsed input: Channel #1:%d, Channel #2:%d, quota 1:%dms", + __func__, adapter_1_chan_number, + adapter_2_chan_number, adapter_1_quota); + + ret = wma_set_mcc_channel_time_quota(wma_handle, + adapter_1_chan_number, + adapter_1_quota, + adapter_2_chan_number); + } + break; + case WMA_VDEV_IBSS_SET_ATIM_WINDOW_SIZE: + { + wma_handle->wma_ibss_power_save_params.atimWindowLength = + privcmd->param_value; + WMA_LOGD("%s: IBSS power save ATIM Window = %d", + __func__, wma_handle->wma_ibss_power_save_params. + atimWindowLength); + } + break; + case WMA_VDEV_IBSS_SET_POWER_SAVE_ALLOWED: + { + wma_handle->wma_ibss_power_save_params.isPowerSaveAllowed = + privcmd->param_value; + WMA_LOGD("%s: IBSS is Power Save Allowed = %d", + __func__, wma_handle->wma_ibss_power_save_params. + isPowerSaveAllowed); + } + break; + case WMA_VDEV_IBSS_SET_POWER_COLLAPSE_ALLOWED: + { + wma_handle->wma_ibss_power_save_params. isPowerCollapseAllowed = + privcmd->param_value; + WMA_LOGD("%s: IBSS is Power Collapse Allowed = %d", + __func__, wma_handle->wma_ibss_power_save_params. + isPowerCollapseAllowed); + } + break; + case WMA_VDEV_IBSS_SET_AWAKE_ON_TX_RX: + { + wma_handle->wma_ibss_power_save_params.isAwakeonTxRxEnabled = + privcmd->param_value; + WMA_LOGD("%s: IBSS Power Save Awake on Tx/Rx Enabled = %d", + __func__, wma_handle->wma_ibss_power_save_params. + isAwakeonTxRxEnabled); + } + break; + case WMA_VDEV_IBSS_SET_INACTIVITY_TIME: + { + wma_handle->wma_ibss_power_save_params.inactivityCount = + privcmd->param_value; + WMA_LOGD("%s: IBSS Power Save Data Inactivity Count = %d", + __func__, wma_handle->wma_ibss_power_save_params. + inactivityCount); + } + break; + case WMA_VDEV_IBSS_SET_TXSP_END_INACTIVITY_TIME: + { + wma_handle->wma_ibss_power_save_params.txSPEndInactivityTime = + privcmd->param_value; + WMA_LOGD("%s: IBSS Power Save Transmit EOSP inactivity time out = %d", + __func__, wma_handle->wma_ibss_power_save_params. + txSPEndInactivityTime); + } + break; + case WMA_VDEV_DFS_CONTROL_CMDID: + { + struct ieee80211com *dfs_ic = wma_handle->dfs_ic; + struct ath_dfs *dfs; + + if (!dfs_ic) { + ret = -ENOENT; + } else { + if (dfs_ic->ic_curchan) { + WMA_LOGD("%s: Debug cmd: %s received on ch: %d", + __func__, "WMA_VDEV_DFS_CONTROL_CMDID", + dfs_ic->ic_curchan->ic_ieee); + + if (dfs_ic->ic_curchan->ic_flagext & + IEEE80211_CHAN_DFS) { + dfs = (struct ath_dfs *)dfs_ic->ic_dfs; + dfs->dfs_bangradar = 1; + dfs->ath_radar_tasksched = 1; + OS_SET_TIMER(&dfs->ath_dfs_task_timer, + 0); + } else { + ret = -ENOENT; + } + } else { + ret = -ENOENT; + } + } + + if (ret == -ENOENT) { + WMA_LOGE("%s: Operating channel is not DFS capable,ignoring %s", + __func__, "WMA_VDEV_DFS_CONTROL_CMDID"); + } else if (ret) { + WMA_LOGE("%s: Sending command %s failed with %d\n", + __func__, "WMA_VDEV_DFS_CONTROL_CMDID", + ret); + } + } + break; + case WMA_VDEV_IBSS_PS_SET_WARMUP_TIME_SECS: + { + wma_handle->wma_ibss_power_save_params.ibssPsWarmupTime = + privcmd->param_value; + WMA_LOGD("%s: IBSS Power Save Warm Up Time in Seconds = %d", + __func__, wma_handle->wma_ibss_power_save_params. + ibssPsWarmupTime); + } + break; + case WMA_VDEV_IBSS_PS_SET_1RX_CHAIN_IN_ATIM_WINDOW: + { + wma_handle->wma_ibss_power_save_params.ibssPs1RxChainInAtimEnable + = privcmd->param_value; + WMA_LOGD("%s: IBSS Power Save single RX Chain Enable In ATIM = %d", + __func__, wma_handle->wma_ibss_power_save_params. + ibssPs1RxChainInAtimEnable); + } + break; + + case WMA_VDEV_TXRX_GET_IPA_UC_FW_STATS_CMDID: + { + ol_txrx_pdev_handle pdev; + + pdev = cds_get_context(QDF_MODULE_ID_TXRX); + if (!pdev) { + WMA_LOGE("pdev NULL for uc stat"); + return -EINVAL; + } + ol_txrx_ipa_uc_get_stat(pdev); + } + break; + + case WMA_VDEV_TXRX_GET_IPA_UC_SHARING_STATS_CMDID: + { + ol_txrx_pdev_handle pdev; + uint8_t reset_stats = privcmd->param_value; + + WMA_LOGE("%s: reset_stats=%d", + "WMA_VDEV_TXRX_GET_IPA_UC_SHARING_STATS_CMDID", + reset_stats); + pdev = cds_get_context(QDF_MODULE_ID_TXRX); + if (!pdev) { + WMA_LOGE("pdev NULL for uc stat"); + return -EINVAL; + } + ol_txrx_ipa_uc_get_share_stats(pdev, reset_stats); + } + break; + + case WMA_VDEV_TXRX_SET_IPA_UC_QUOTA_CMDID: + { + ol_txrx_pdev_handle pdev; + uint64_t quota_bytes = privcmd->param_sec_value; + + quota_bytes <<= 32; + quota_bytes |= privcmd->param_value; + + WMA_LOGE("%s: quota_bytes=%llu", + "WMA_VDEV_TXRX_SET_IPA_UC_QUOTA_CMDID", + quota_bytes); + pdev = cds_get_context(QDF_MODULE_ID_TXRX); + if (!pdev) { + WMA_LOGE("pdev NULL for uc stat"); + return -EINVAL; + } + ol_txrx_ipa_uc_set_quota(pdev, quota_bytes); + } + break; + + default: + WMA_LOGE("Invalid wma config command id:%d", privcmd->param_id); + ret = -EINVAL; + } + return ret; +} + +/** + * wma_set_dtim_period() - set dtim period to FW + * @wma: wma handle + * @dtim_params: dtim params + * + * Return: none + */ +static void wma_set_dtim_period(tp_wma_handle wma, + struct set_dtim_params *dtim_params) +{ + QDF_STATUS ret; + uint8_t vdev_id = dtim_params->session_id; + struct wma_txrx_node *iface = + &wma->interfaces[vdev_id]; + + WMA_LOGI("%s: set dtim_period %d", __func__, + dtim_params->dtim_period); + iface->dtimPeriod = dtim_params->dtim_period; + ret = wma_vdev_set_param(wma->wmi_handle, + vdev_id, + WMI_VDEV_PARAM_LISTEN_INTERVAL, + dtim_params->dtim_period); + if (QDF_IS_STATUS_ERROR(ret)) + WMA_LOGW("Failed to set listen interval"); + +} +/** + * wma_set_modulated_dtim() - function to configure modulated dtim + * @wma: wma handle + * @privcmd: structure containing parameters + * + * This function configures the modulated dtim in firmware + * + * Return: none + */ +static void wma_set_modulated_dtim(tp_wma_handle wma, + wma_cli_set_cmd_t *privcmd) +{ + uint8_t vdev_id = privcmd->param_vdev_id; + struct wma_txrx_node *iface = + &wma->interfaces[vdev_id]; + bool prev_dtim_enabled; + uint32_t listen_interval; + QDF_STATUS ret; + + iface->alt_modulated_dtim = privcmd->param_value; + + prev_dtim_enabled = iface->alt_modulated_dtim_enabled; + + if (1 != privcmd->param_value) + iface->alt_modulated_dtim_enabled = true; + else + iface->alt_modulated_dtim_enabled = false; + + if ((true == iface->alt_modulated_dtim_enabled) || + (true == prev_dtim_enabled)) { + + listen_interval = iface->alt_modulated_dtim + * iface->dtimPeriod; + + ret = wma_vdev_set_param(wma->wmi_handle, + privcmd->param_vdev_id, + WMI_VDEV_PARAM_LISTEN_INTERVAL, + listen_interval); + if (QDF_IS_STATUS_ERROR(ret)) + /* Even if it fails, continue */ + WMA_LOGW("Failed to set listen interval %d", + listen_interval); + + ret = wma_vdev_set_param(wma->wmi_handle, + privcmd->param_vdev_id, + WMI_VDEV_PARAM_DTIM_POLICY , + NORMAL_DTIM); + if (QDF_IS_STATUS_ERROR(ret)) + WMA_LOGE("Failed to Set to Normal DTIM policy"); + } +} + + +/** + * wma_process_cli_set_cmd() - set parameters to fw + * @wma: wma handle + * @privcmd: command + * + * Return: none + */ +static void wma_process_cli_set_cmd(tp_wma_handle wma, + wma_cli_set_cmd_t *privcmd) +{ + int vid = privcmd->param_vdev_id, pps_val = 0; + QDF_STATUS ret; + struct wma_txrx_node *intr = wma->interfaces; + tpAniSirGlobal pMac = cds_get_context(QDF_MODULE_ID_PE); + struct qpower_params *qparams = &intr[vid].config.qpower_params; + struct pdev_params pdev_param; + + WMA_LOGD("wmihandle %p", wma->wmi_handle); + + if (NULL == pMac) { + WMA_LOGE("%s: Failed to get pMac", __func__); + return; + } + + if (privcmd->param_id >= WMI_CMDID_MAX) { + /* + * This configuration setting is not done using any wmi + * command, call appropriate handler. + */ + if (wma_set_priv_cfg(wma, privcmd)) + WMA_LOGE("Failed to set wma priv congiuration"); + return; + } + + switch (privcmd->param_vp_dev) { + case VDEV_CMD: + if (!wma->interfaces[privcmd->param_vdev_id].is_vdev_valid) { + WMA_LOGE("%s Vdev id is not valid", __func__); + return ; + } + + WMA_LOGD("vdev id %d pid %d pval %d", privcmd->param_vdev_id, + privcmd->param_id, privcmd->param_value); + ret = wma_vdev_set_param(wma->wmi_handle, + privcmd->param_vdev_id, + privcmd->param_id, + privcmd->param_value); + if (QDF_IS_STATUS_ERROR(ret)) { + WMA_LOGE("wma_vdev_set_param failed ret %d", + ret); + return; + } + break; + case PDEV_CMD: + WMA_LOGD("pdev pid %d pval %d", privcmd->param_id, + privcmd->param_value); + if ((privcmd->param_id == WMI_PDEV_PARAM_RX_CHAIN_MASK) || + (privcmd->param_id == WMI_PDEV_PARAM_TX_CHAIN_MASK)) { + wma_update_txrx_chainmask(wma->num_rf_chains, + &privcmd->param_value); + } + pdev_param.param_id = privcmd->param_id; + pdev_param.param_value = privcmd->param_value; + ret = wmi_unified_pdev_param_send(wma->wmi_handle, + &pdev_param, + WMA_WILDCARD_PDEV_ID); + if (QDF_IS_STATUS_ERROR(ret)) { + WMA_LOGE("wma_vdev_set_param failed ret %d", + ret); + return; + } + break; + case GEN_CMD: + { + ol_txrx_vdev_handle vdev = NULL; + struct wma_txrx_node *intr = wma->interfaces; + + vdev = wma_find_vdev_by_id(wma, privcmd->param_vdev_id); + if (!vdev) { + WMA_LOGE("%s:Invalid vdev handle", __func__); + return; + } + + WMA_LOGD("gen pid %d pval %d", privcmd->param_id, + privcmd->param_value); + + switch (privcmd->param_id) { + case GEN_VDEV_PARAM_AMPDU: + ret = ol_txrx_aggr_cfg(vdev, privcmd->param_value, 0); + if (ret) + WMA_LOGE("ol_txrx_aggr_cfg set ampdu failed ret %d", + ret); + else + intr[privcmd->param_vdev_id].config.ampdu = + privcmd->param_value; + break; + case GEN_VDEV_PARAM_AMSDU: + /* + * Firmware currently does not support set operation + * for AMSDU. It may cause crash if the configuration + * is sent to firmware. + * Firmware enhancement will advertise a service bit + * to enable AMSDU configuration through WMI. Then + * add the WMI command to configure AMSDU parameter. + * For the older chipset that does not advertise the + * service bit, enable the following legacy code: + * ol_txrx_aggr_cfg(vdev, 0, privcmd->param_value); + * intr[privcmd->param_vdev_id].config.amsdu = + * privcmd->param_value; + */ + WMA_LOGE("SET GEN_VDEV_PARAM_AMSDU command is currently not supported"); + break; + case GEN_PARAM_CRASH_INJECT: + if (QDF_GLOBAL_FTM_MODE == cds_get_conparam()) + WMA_LOGE("Crash inject not allowed in FTM mode"); + else + ret = wma_crash_inject(wma, + privcmd->param_value, + privcmd->param_sec_value); + break; + case GEN_PARAM_CAPTURE_TSF: + ret = wma_capture_tsf(wma, privcmd->param_value); + break; + case GEN_PARAM_RESET_TSF_GPIO: + ret = wma_reset_tsf_gpio(wma, privcmd->param_value); + break; + case GEN_PARAM_MODULATED_DTIM: + wma_set_modulated_dtim(wma, privcmd); + break; + default: + WMA_LOGE("Invalid param id 0x%x", + privcmd->param_id); + break; + } + break; + } + case DBG_CMD: + WMA_LOGD("dbg pid %d pval %d", privcmd->param_id, + privcmd->param_value); + switch (privcmd->param_id) { + case WMI_DBGLOG_LOG_LEVEL: + ret = dbglog_set_log_lvl(wma->wmi_handle, + privcmd->param_value); + if (ret) + WMA_LOGE("dbglog_set_log_lvl failed ret %d", + ret); + break; + case WMI_DBGLOG_VAP_ENABLE: + ret = dbglog_vap_log_enable(wma->wmi_handle, + privcmd->param_value, true); + if (ret) + WMA_LOGE("dbglog_vap_log_enable failed ret %d", + ret); + break; + case WMI_DBGLOG_VAP_DISABLE: + ret = dbglog_vap_log_enable(wma->wmi_handle, + privcmd->param_value, false); + if (ret) + WMA_LOGE("dbglog_vap_log_enable failed ret %d", + ret); + break; + case WMI_DBGLOG_MODULE_ENABLE: + ret = dbglog_module_log_enable(wma->wmi_handle, + privcmd->param_value, true); + if (ret) + WMA_LOGE("dbglog_module_log_enable failed ret %d", + ret); + break; + case WMI_DBGLOG_MODULE_DISABLE: + ret = dbglog_module_log_enable(wma->wmi_handle, + privcmd->param_value, false); + if (ret) + WMA_LOGE("dbglog_module_log_enable failed ret %d", + ret); + break; + case WMI_DBGLOG_MOD_LOG_LEVEL: + ret = dbglog_set_mod_log_lvl(wma->wmi_handle, + privcmd->param_value); + if (ret) + WMA_LOGE("dbglog_module_log_enable failed ret %d", + ret); + break; + case WMI_DBGLOG_TYPE: + ret = dbglog_parser_type_init(wma->wmi_handle, + privcmd->param_value); + if (ret) + WMA_LOGE("dbglog_parser_type_init failed ret %d", + ret); + break; + case WMI_DBGLOG_REPORT_ENABLE: + ret = dbglog_report_enable(wma->wmi_handle, + privcmd->param_value); + if (ret) + WMA_LOGE("dbglog_report_enable failed ret %d", + ret); + break; + case WMI_WLAN_PROFILE_TRIGGER_CMDID: + ret = wma_unified_fw_profiling_cmd(wma->wmi_handle, + WMI_WLAN_PROFILE_TRIGGER_CMDID, + privcmd->param_value, 0); + if (ret) + WMA_LOGE("Profile cmd failed for %d ret %d", + WMI_WLAN_PROFILE_TRIGGER_CMDID, ret); + break; + case WMI_WLAN_PROFILE_ENABLE_PROFILE_ID_CMDID: + ret = wma_unified_fw_profiling_cmd(wma->wmi_handle, + WMI_WLAN_PROFILE_ENABLE_PROFILE_ID_CMDID, + privcmd->param_value, + privcmd->param_sec_value); + if (ret) + WMA_LOGE("Profile cmd failed for %d ret %d", + WMI_WLAN_PROFILE_ENABLE_PROFILE_ID_CMDID, + ret); + break; + case WMI_WLAN_PROFILE_SET_HIST_INTVL_CMDID: + ret = wma_unified_fw_profiling_cmd(wma->wmi_handle, + WMI_WLAN_PROFILE_SET_HIST_INTVL_CMDID, + privcmd->param_value, + privcmd->param_sec_value); + if (ret) + WMA_LOGE("Profile cmd failed for %d ret %d", + WMI_WLAN_PROFILE_SET_HIST_INTVL_CMDID, + ret); + break; + case WMI_WLAN_PROFILE_LIST_PROFILE_ID_CMDID: + ret = wma_unified_fw_profiling_cmd(wma->wmi_handle, + WMI_WLAN_PROFILE_LIST_PROFILE_ID_CMDID, + 0, 0); + if (ret) + WMA_LOGE("Profile cmd failed for %d ret %d", + WMI_WLAN_PROFILE_LIST_PROFILE_ID_CMDID, + ret); + break; + case WMI_WLAN_PROFILE_GET_PROFILE_DATA_CMDID: + ret = wma_unified_fw_profiling_cmd(wma->wmi_handle, + WMI_WLAN_PROFILE_GET_PROFILE_DATA_CMDID, + 0, 0); + if (ret) + WMA_LOGE("Profile cmd failed for %d ret %d", + WMI_WLAN_PROFILE_GET_PROFILE_DATA_CMDID, + ret); + break; + case WMI_PDEV_GREEN_AP_PS_ENABLE_CMDID: + /* Set the Green AP */ + ret = wmi_unified_green_ap_ps_send + (wma->wmi_handle, privcmd->param_value, + WMA_WILDCARD_PDEV_ID); + if (ret) { + WMA_LOGE("Set GreenAP Failed val %d", + privcmd->param_value); + } + break; + + default: + WMA_LOGE("Invalid param id 0x%x", privcmd->param_id); + break; + } + break; + case PPS_CMD: + WMA_LOGD("dbg pid %d pval %d", privcmd->param_id, + privcmd->param_value); + switch (privcmd->param_id) { + + case WMI_VDEV_PPS_PAID_MATCH: + pps_val = ((privcmd->param_value << 31) & 0xffff0000) | + (PKT_PWR_SAVE_PAID_MATCH & 0xffff); + intr[vid].config.pps_params.paid_match_enable = + privcmd->param_value; + break; + case WMI_VDEV_PPS_GID_MATCH: + pps_val = ((privcmd->param_value << 31) & 0xffff0000) | + (PKT_PWR_SAVE_GID_MATCH & 0xffff); + intr[vid].config.pps_params.gid_match_enable = + privcmd->param_value; + break; + case WMI_VDEV_PPS_EARLY_TIM_CLEAR: + pps_val = ((privcmd->param_value << 31) & 0xffff0000) | + (PKT_PWR_SAVE_EARLY_TIM_CLEAR & 0xffff); + intr[vid].config.pps_params.tim_clear = + privcmd->param_value; + break; + case WMI_VDEV_PPS_EARLY_DTIM_CLEAR: + pps_val = ((privcmd->param_value << 31) & 0xffff0000) | + (PKT_PWR_SAVE_EARLY_DTIM_CLEAR & 0xffff); + intr[vid].config.pps_params.dtim_clear = + privcmd->param_value; + break; + case WMI_VDEV_PPS_EOF_PAD_DELIM: + pps_val = ((privcmd->param_value << 31) & 0xffff0000) | + (PKT_PWR_SAVE_EOF_PAD_DELIM & 0xffff); + intr[vid].config.pps_params.eof_delim = + privcmd->param_value; + break; + case WMI_VDEV_PPS_MACADDR_MISMATCH: + pps_val = ((privcmd->param_value << 31) & 0xffff0000) | + (PKT_PWR_SAVE_MACADDR_MISMATCH & 0xffff); + intr[vid].config.pps_params.mac_match = + privcmd->param_value; + break; + case WMI_VDEV_PPS_DELIM_CRC_FAIL: + pps_val = ((privcmd->param_value << 31) & 0xffff0000) | + (PKT_PWR_SAVE_DELIM_CRC_FAIL & 0xffff); + intr[vid].config.pps_params.delim_fail = + privcmd->param_value; + break; + case WMI_VDEV_PPS_GID_NSTS_ZERO: + pps_val = ((privcmd->param_value << 31) & 0xffff0000) | + (PKT_PWR_SAVE_GID_NSTS_ZERO & 0xffff); + intr[vid].config.pps_params.nsts_zero = + privcmd->param_value; + break; + case WMI_VDEV_PPS_RSSI_CHECK: + pps_val = ((privcmd->param_value << 31) & 0xffff0000) | + (PKT_PWR_SAVE_RSSI_CHECK & 0xffff); + intr[vid].config.pps_params.rssi_chk = + privcmd->param_value; + break; + case WMI_VDEV_PPS_5G_EBT: + pps_val = ((privcmd->param_value << 31) & 0xffff0000) | + (PKT_PWR_SAVE_5G_EBT & 0xffff); + intr[vid].config.pps_params.ebt_5g = + privcmd->param_value; + break; + default: + WMA_LOGE("Invalid param id 0x%x", privcmd->param_id); + break; + } + break; + + case QPOWER_CMD: + WMA_LOGD("QPOWER CLI CMD pid %d pval %d", privcmd->param_id, + privcmd->param_value); + switch (privcmd->param_id) { + case WMI_STA_PS_PARAM_QPOWER_PSPOLL_COUNT: + WMA_LOGD("QPOWER CLI CMD:Ps Poll Cnt val %d", + privcmd->param_value); + /* Set the QPower Ps Poll Count */ + ret = wma_unified_set_sta_ps_param(wma->wmi_handle, + vid, WMI_STA_PS_PARAM_QPOWER_PSPOLL_COUNT, + privcmd->param_value); + if (ret) { + WMA_LOGE("Set Q-PsPollCnt Failed vdevId %d val %d", + vid, privcmd->param_value); + } else { + qparams->max_ps_poll_cnt = privcmd->param_value; + } + break; + case WMI_STA_PS_PARAM_QPOWER_MAX_TX_BEFORE_WAKE: + WMA_LOGD("QPOWER CLI CMD:Max Tx Before wake val %d", + privcmd->param_value); + /* Set the QPower Max Tx Before Wake */ + ret = wma_unified_set_sta_ps_param(wma->wmi_handle, + vid, WMI_STA_PS_PARAM_QPOWER_MAX_TX_BEFORE_WAKE, + privcmd->param_value); + if (ret) { + WMA_LOGE("Set Q-MaxTxBefWake Failed vId %d val %d", + vid, privcmd->param_value); + } else { + qparams->max_tx_before_wake = + privcmd->param_value; + } + break; + case WMI_STA_PS_PARAM_QPOWER_SPEC_PSPOLL_WAKE_INTERVAL: + WMA_LOGD("QPOWER CLI CMD:Ps Poll Wake Inv val %d", + privcmd->param_value); + /* Set the QPower Spec Ps Poll Wake Inv */ + ret = wma_unified_set_sta_ps_param(wma->wmi_handle, + vid, WMI_STA_PS_PARAM_QPOWER_SPEC_PSPOLL_WAKE_INTERVAL, + privcmd->param_value); + if (ret) { + WMA_LOGE("Set Q-PsPoll WakeIntv Failed vId %d val %d", + vid, privcmd->param_value); + } else { + qparams->spec_ps_poll_wake_interval = + privcmd->param_value; + } + break; + case WMI_STA_PS_PARAM_QPOWER_SPEC_MAX_SPEC_NODATA_PSPOLL: + WMA_LOGD("QPOWER CLI CMD:Spec NoData Ps Poll val %d", + privcmd->param_value); + /* Set the QPower Spec NoData PsPoll */ + ret = wma_unified_set_sta_ps_param(wma->wmi_handle, + vid, WMI_STA_PS_PARAM_QPOWER_SPEC_MAX_SPEC_NODATA_PSPOLL, + privcmd->param_value); + if (ret) { + WMA_LOGE("Set Q-SpecNoDataPsPoll Failed vId %d val %d", + vid, privcmd->param_value); + } else { + qparams->max_spec_nodata_ps_poll = + privcmd->param_value; + } + break; + + default: + WMA_LOGE("Invalid param id 0x%x", privcmd->param_id); + break; + } + break; + case GTX_CMD: + WMA_LOGD("vdev id %d pid %d pval %d", privcmd->param_vdev_id, + privcmd->param_id, privcmd->param_value); + switch (privcmd->param_id) { + case WMI_VDEV_PARAM_GTX_HT_MCS: + intr[vid].config.gtx_info.gtxRTMask[0] = + privcmd->param_value; + ret = wmi_unified_vdev_set_gtx_cfg_send(wma->wmi_handle, + privcmd->param_vdev_id, + &intr[vid].config.gtx_info); + break; + case WMI_VDEV_PARAM_GTX_VHT_MCS: + intr[vid].config.gtx_info.gtxRTMask[1] = + privcmd->param_value; + ret = wmi_unified_vdev_set_gtx_cfg_send(wma->wmi_handle, + privcmd->param_vdev_id, + &intr[vid].config.gtx_info); + break; + + case WMI_VDEV_PARAM_GTX_USR_CFG: + intr[vid].config.gtx_info.gtxUsrcfg = + privcmd->param_value; + ret = wmi_unified_vdev_set_gtx_cfg_send(wma->wmi_handle, + privcmd->param_vdev_id, + &intr[vid].config.gtx_info); + break; + + case WMI_VDEV_PARAM_GTX_THRE: + intr[vid].config.gtx_info.gtxPERThreshold = + privcmd->param_value; + ret = wmi_unified_vdev_set_gtx_cfg_send(wma->wmi_handle, + privcmd->param_vdev_id, + &intr[vid].config.gtx_info); + break; + + case WMI_VDEV_PARAM_GTX_MARGIN: + intr[vid].config.gtx_info.gtxPERMargin = + privcmd->param_value; + ret = wmi_unified_vdev_set_gtx_cfg_send(wma->wmi_handle, + privcmd->param_vdev_id, + &intr[vid].config.gtx_info); + break; + + case WMI_VDEV_PARAM_GTX_STEP: + intr[vid].config.gtx_info.gtxTPCstep = + privcmd->param_value; + ret = wmi_unified_vdev_set_gtx_cfg_send(wma->wmi_handle, + privcmd->param_vdev_id, + &intr[vid].config.gtx_info); + break; + + case WMI_VDEV_PARAM_GTX_MINTPC: + intr[vid].config.gtx_info.gtxTPCMin = + privcmd->param_value; + ret = wmi_unified_vdev_set_gtx_cfg_send(wma->wmi_handle, + privcmd->param_vdev_id, + &intr[vid].config.gtx_info); + break; + + case WMI_VDEV_PARAM_GTX_BW_MASK: + intr[vid].config.gtx_info.gtxBWMask = + privcmd->param_value; + ret = wmi_unified_vdev_set_gtx_cfg_send(wma->wmi_handle, + privcmd->param_vdev_id, + &intr[vid].config.gtx_info); + if (ret) { + WMA_LOGE("wma_vdev_set_param" + " failed ret %d", ret); + return; + } + break; + default: + break; + } + break; + + default: + WMA_LOGE("Invalid vpdev command id"); + } + if (1 == privcmd->param_vp_dev) { + switch (privcmd->param_id) { + case WMI_VDEV_PARAM_NSS: + intr[vid].config.nss = privcmd->param_value; + break; + case WMI_VDEV_PARAM_LDPC: + intr[vid].config.ldpc = privcmd->param_value; + break; + case WMI_VDEV_PARAM_TX_STBC: + intr[vid].config.tx_stbc = privcmd->param_value; + break; + case WMI_VDEV_PARAM_RX_STBC: + intr[vid].config.rx_stbc = privcmd->param_value; + break; + case WMI_VDEV_PARAM_SGI: + intr[vid].config.shortgi = privcmd->param_value; + break; + case WMI_VDEV_PARAM_ENABLE_RTSCTS: + intr[vid].config.rtscts_en = privcmd->param_value; + break; + case WMI_VDEV_PARAM_CHWIDTH: + intr[vid].config.chwidth = privcmd->param_value; + break; + case WMI_VDEV_PARAM_FIXED_RATE: + intr[vid].config.tx_rate = privcmd->param_value; + break; + case WMI_VDEV_PARAM_EARLY_RX_ADJUST_ENABLE: + intr[vid].config.erx_adjust = privcmd->param_value; + break; + case WMI_VDEV_PARAM_EARLY_RX_TGT_BMISS_NUM: + intr[vid].config.erx_bmiss_num = privcmd->param_value; + break; + case WMI_VDEV_PARAM_EARLY_RX_BMISS_SAMPLE_CYCLE: + intr[vid].config.erx_bmiss_cycle = privcmd->param_value; + break; + case WMI_VDEV_PARAM_EARLY_RX_SLOP_STEP: + intr[vid].config.erx_slop_step = privcmd->param_value; + break; + case WMI_VDEV_PARAM_EARLY_RX_INIT_SLOP: + intr[vid].config.erx_init_slop = privcmd->param_value; + break; + case WMI_VDEV_PARAM_EARLY_RX_ADJUST_PAUSE: + intr[vid].config.erx_adj_pause = privcmd->param_value; + break; + case WMI_VDEV_PARAM_EARLY_RX_DRIFT_SAMPLE: + intr[vid].config.erx_dri_sample = privcmd->param_value; + break; + default: + WMA_LOGE("Invalid wma_cli_set vdev command/Not" + " yet implemented 0x%x", privcmd->param_id); + break; + } + } else if (2 == privcmd->param_vp_dev) { + switch (privcmd->param_id) { + case WMI_PDEV_PARAM_ANI_ENABLE: + wma->pdevconfig.ani_enable = privcmd->param_value; + break; + case WMI_PDEV_PARAM_ANI_POLL_PERIOD: + wma->pdevconfig.ani_poll_len = privcmd->param_value; + break; + case WMI_PDEV_PARAM_ANI_LISTEN_PERIOD: + wma->pdevconfig.ani_listen_len = privcmd->param_value; + break; + case WMI_PDEV_PARAM_ANI_OFDM_LEVEL: + wma->pdevconfig.ani_ofdm_level = privcmd->param_value; + break; + case WMI_PDEV_PARAM_ANI_CCK_LEVEL: + wma->pdevconfig.ani_cck_level = privcmd->param_value; + break; + case WMI_PDEV_PARAM_DYNAMIC_BW: + wma->pdevconfig.cwmenable = privcmd->param_value; + break; + case WMI_PDEV_PARAM_CTS_CBW: + wma->pdevconfig.cts_cbw = privcmd->param_value; + break; + case WMI_PDEV_PARAM_TX_CHAIN_MASK: + wma->pdevconfig.txchainmask = privcmd->param_value; + break; + case WMI_PDEV_PARAM_RX_CHAIN_MASK: + wma->pdevconfig.rxchainmask = privcmd->param_value; + break; + case WMI_PDEV_PARAM_BURST_ENABLE: + wma->pdevconfig.burst_enable = privcmd->param_value; + if ((wma->pdevconfig.burst_enable == 1) && + (wma->pdevconfig.burst_dur == 0)) + wma->pdevconfig.burst_dur = + WMA_DEFAULT_SIFS_BURST_DURATION; + else if (wma->pdevconfig.burst_enable == 0) + wma->pdevconfig.burst_dur = 0; + break; + case WMI_PDEV_PARAM_BURST_DUR: + wma->pdevconfig.burst_dur = privcmd->param_value; + break; + case WMI_PDEV_PARAM_TXPOWER_LIMIT2G: + wma->pdevconfig.txpow2g = privcmd->param_value; + if ((pMac->roam.configParam.bandCapability == + eCSR_BAND_ALL) || + (pMac->roam.configParam.bandCapability == + eCSR_BAND_24)) { + if (cfg_set_int(pMac, + WNI_CFG_CURRENT_TX_POWER_LEVEL, + privcmd->param_value) != + eSIR_SUCCESS) + WMA_LOGE("could not set WNI_CFG_CURRENT_TX_POWER_LEVEL"); + + } else { + WMA_LOGE("Current band is not 2G"); + } + break; + case WMI_PDEV_PARAM_TXPOWER_LIMIT5G: + wma->pdevconfig.txpow5g = privcmd->param_value; + if ((pMac->roam.configParam.bandCapability == + eCSR_BAND_ALL) || + (pMac->roam.configParam.bandCapability == + eCSR_BAND_5G)) { + if (cfg_set_int(pMac, + WNI_CFG_CURRENT_TX_POWER_LEVEL, + privcmd->param_value) != + eSIR_SUCCESS) + WMA_LOGE("could not set WNI_CFG_CURRENT_TX_POWER_LEVEL"); + + } else { + WMA_LOGE("Current band is not 5G"); + } + break; + default: + WMA_LOGE("Invalid wma_cli_set pdev command/Not yet implemented 0x%x", + privcmd->param_id); + break; + } + } else if (5 == privcmd->param_vp_dev) { + ret = wma_vdev_set_param(wma->wmi_handle, + privcmd->param_vdev_id, + WMI_VDEV_PARAM_PACKET_POWERSAVE, + pps_val); + if (ret) + WMA_LOGE("Failed to send wmi packet power save cmd"); + else + WMA_LOGD("Sent packet power save cmd %d value %x to target", + privcmd->param_id, pps_val); + } +} + +/** + * wma_process_fw_event() - process any fw event + * @wma: wma handle + * @buf: fw event buffer + * + * This function process any fw event to serialize it through mc thread. + * + * Return: none + */ +static int wma_process_fw_event(tp_wma_handle wma, + wma_process_fw_event_params *buf) +{ + struct wmi_unified *wmi_handle = (struct wmi_unified *)buf->wmi_handle; + + wmi_process_fw_event(wmi_handle, buf->evt_buf); + return 0; +} + +/** + * wmi_process_fw_event_tasklet_ctx() - process in tasklet context + * @ctx: handle to wmi + * @ev: wmi event buffer + * + * Event process by below function will be in tasket context, + * need to use this method only for time sensitive functions. + * + * Return: none + */ +static int wma_process_fw_event_tasklet_ctx(void *ctx, void *ev) +{ + wmi_process_fw_event(ctx, ev); + + return 0; +} + +/** + * wma_process_hal_pwr_dbg_cmd() - send hal pwr dbg cmd to fw. + * @handle: wma handle + * @sir_pwr_dbg_params: unit test command + * + * This function send unit test command to fw. + * + * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_** on error + */ +QDF_STATUS wma_process_hal_pwr_dbg_cmd(WMA_HANDLE handle, + struct sir_mac_pwr_dbg_cmd * + sir_pwr_dbg_params) +{ + tp_wma_handle wma_handle = (tp_wma_handle)handle; + int i; + struct wmi_power_dbg_params wmi_pwr_dbg_params; + QDF_STATUS status; + + if (!sir_pwr_dbg_params) { + WMA_LOGE("%s: sir_pwr_dbg_params is null", __func__); + return QDF_STATUS_E_INVAL; + } + wmi_pwr_dbg_params.module_id = sir_pwr_dbg_params->module_id; + wmi_pwr_dbg_params.pdev_id = sir_pwr_dbg_params->pdev_id; + wmi_pwr_dbg_params.num_args = sir_pwr_dbg_params->num_args; + + for (i = 0; i < wmi_pwr_dbg_params.num_args; i++) + wmi_pwr_dbg_params.args[i] = sir_pwr_dbg_params->args[i]; + + status = wmi_unified_send_power_dbg_cmd(wma_handle->wmi_handle, + &wmi_pwr_dbg_params); + + return status; +} + +/** + * wma_process_fw_event_handler() - common event handler to serialize + * event processing through mc_thread + * @ctx: wmi context + * @ev: event buffer + * @rx_ctx: rx execution context + * + * Return: 0 on success, errno on failure + */ +static int wma_process_fw_event_mc_thread_ctx(void *ctx, void *ev) +{ + wma_process_fw_event_params *params_buf; + cds_msg_t cds_msg = { 0 }; + + params_buf = qdf_mem_malloc(sizeof(wma_process_fw_event_params)); + if (!params_buf) { + WMA_LOGE("%s: Failed alloc memory for params_buf", __func__); + qdf_nbuf_free(ev); + return -ENOMEM; + } + + params_buf->wmi_handle = (struct wmi_unified *)ctx; + params_buf->evt_buf = (wmi_buf_t *)ev; + + cds_msg.type = WMA_PROCESS_FW_EVENT; + cds_msg.bodyptr = params_buf; + cds_msg.bodyval = 0; + + if (QDF_STATUS_SUCCESS != + cds_mq_post_message(CDS_MQ_ID_WMA, &cds_msg)) { + WMA_LOGP("%s: Failed to post WMA_PROCESS_FW_EVENT msg", + __func__); + qdf_nbuf_free(ev); + qdf_mem_free(params_buf); + return -EFAULT; + } + return 0; + +} + +/** + * wma_process_fw_event_handler() - common event handler to serialize + * event processing through mc_thread + * @ctx: wmi context + * @ev: event buffer + * @rx_ctx: rx execution context + * + * Return: 0 on success, errno on failure + */ +int wma_process_fw_event_handler(void *ctx, void *ev, uint8_t rx_ctx) +{ + int err = 0; + + if (rx_ctx == WMA_RX_SERIALIZER_CTX) { + err = wma_process_fw_event_mc_thread_ctx(ctx, ev); + } else if (rx_ctx == WMA_RX_TASKLET_CTX) { + wma_process_fw_event_tasklet_ctx(ctx, ev); + } else { + WMA_LOGE("%s: invalid wmi event execution context", __func__); + qdf_nbuf_free(ev); + } + + return err; +} + +#ifdef QCA_LL_TX_FLOW_CONTROL_V2 +/** + * ol_cfg_set_flow_control_parameters() - set flow control parameters + * @olCfg: cfg parameters + * @cds_cfg: CDS Configuration + * + * Return: none + */ +static +void ol_cfg_set_flow_control_parameters(struct txrx_pdev_cfg_param_t *olCfg, + struct cds_config_info *cds_cfg) +{ + olCfg->tx_flow_start_queue_offset = + cds_cfg->tx_flow_start_queue_offset; + olCfg->tx_flow_stop_queue_th = + cds_cfg->tx_flow_stop_queue_th; +} +#else +static +void ol_cfg_set_flow_control_parameters(struct txrx_pdev_cfg_param_t *olCfg, + struct cds_config_info *cds_cfg) +{ + return; +} +#endif + +/** + * ol_cfg_update_ac_specs_params() - update ac_specs params + * @olcfg: cfg handle + * @mac_params: mac params + * + * Return: none + */ +static void ol_cfg_update_ac_specs_params(struct txrx_pdev_cfg_param_t *olcfg, + struct cds_config_info *cds_cfg) +{ + int i; + + if (NULL == olcfg) + return; + + if (NULL == cds_cfg) + return; + + for (i = 0; i < OL_TX_NUM_WMM_AC; i++) { + olcfg->ac_specs[i].wrr_skip_weight = + cds_cfg->ac_specs[i].wrr_skip_weight; + olcfg->ac_specs[i].credit_threshold = + cds_cfg->ac_specs[i].credit_threshold; + olcfg->ac_specs[i].send_limit = + cds_cfg->ac_specs[i].send_limit; + olcfg->ac_specs[i].credit_reserve = + cds_cfg->ac_specs[i].credit_reserve; + olcfg->ac_specs[i].discard_weight = + cds_cfg->ac_specs[i].discard_weight; + } +} + +#ifdef WLAN_FEATURE_NAN +/** + * wma_set_nan_enable() - set nan enable flag in WMA handle + * @wma_handle: Pointer to wma handle + * @cds_cfg: Pointer to CDS Configuration + * + * Return: none + */ +static void wma_set_nan_enable(tp_wma_handle wma_handle, + struct cds_config_info *cds_cfg) +{ + wma_handle->is_nan_enabled = cds_cfg->is_nan_enabled; +} +#else +static void wma_set_nan_enable(tp_wma_handle wma_handle, + struct cds_config_info *cds_cfg) +{ +} +#endif + +/** + * wma_init_max_no_of_peers - API to initialize wma configuration params + * @wma_handle: WMA Handle + * @max_peers: Max Peers supported + * + * Return: void + */ +static void wma_init_max_no_of_peers(tp_wma_handle wma_handle, + uint16_t max_peers) +{ + struct wma_ini_config *cfg = wma_get_ini_handle(wma_handle); + + if (cfg == NULL) { + WMA_LOGE("%s: NULL WMA ini handle", __func__); + return; + } + + cfg->max_no_of_peers = max_peers; +} + +/** + * wma_cleanup_vdev_resp_queue() - cleanup vdev response queue + * @wma: wma handle + * + * Return: none + */ +static void wma_cleanup_vdev_resp_queue(tp_wma_handle wma) +{ + struct wma_target_req *req_msg = NULL; + qdf_list_node_t *node1 = NULL; + + qdf_spin_lock_bh(&wma->vdev_respq_lock); + if (!qdf_list_size(&wma->vdev_resp_queue)) { + qdf_spin_unlock_bh(&wma->vdev_respq_lock); + WMA_LOGI(FL("request queue maybe empty")); + return; + } + + while (qdf_list_peek_front(&wma->vdev_resp_queue, &node1) == + QDF_STATUS_SUCCESS) { + req_msg = qdf_container_of(node1, struct wma_target_req, node); + qdf_spin_unlock_bh(&wma->vdev_respq_lock); + qdf_mc_timer_stop(&req_msg->event_timeout); + wma_vdev_resp_timer(req_msg); + qdf_spin_lock_bh(&wma->vdev_respq_lock); + } + qdf_spin_unlock_bh(&wma->vdev_respq_lock); +} + +/** + * wma_cleanup_hold_req() - cleanup hold request queue + * @wma: wma handle + * + * Return: none + */ +static void wma_cleanup_hold_req(tp_wma_handle wma) +{ + struct wma_target_req *req_msg = NULL; + qdf_list_node_t *node1 = NULL; + + qdf_spin_lock_bh(&wma->wma_hold_req_q_lock); + if (!qdf_list_size(&wma->wma_hold_req_queue)) { + qdf_spin_unlock_bh(&wma->wma_hold_req_q_lock); + WMA_LOGD(FL("request queue is empty")); + return; + } + + while (QDF_STATUS_SUCCESS == + qdf_list_peek_front(&wma->wma_hold_req_queue, &node1)) { + req_msg = qdf_container_of(node1, struct wma_target_req, node); + qdf_spin_unlock_bh(&wma->wma_hold_req_q_lock); + /* Cleanup timeout handler */ + qdf_mc_timer_stop(&req_msg->event_timeout); + qdf_mc_timer_destroy(&req_msg->event_timeout); + wma_hold_req_timer(req_msg); + qdf_spin_lock_bh(&wma->wma_hold_req_q_lock); + } + qdf_spin_unlock_bh(&wma->wma_hold_req_q_lock); +} + +/** + * wma_shutdown_notifier_cb - Shutdown notifer call back + * @priv : WMA handle + * + * During recovery, WMA may wait for resume to complete if the crash happens + * while in suspend. This may cause delays in completing the recovery. This call + * back would be called during recovery and the event is completed so that if + * the resume is waiting on FW to respond then it can get out of the wait so + * that recovery thread can start bringing down all the modules. + * + * Return: None + */ +static void wma_shutdown_notifier_cb(void *priv) +{ + tp_wma_handle wma_handle = priv; + + qdf_event_set(&wma_handle->wma_resume_event); + wma_cleanup_vdev_resp_queue(wma_handle); + wma_cleanup_hold_req(wma_handle); +} + +struct wma_version_info g_wmi_version_info; + +/** + * wma_state_info_dump() - prints state information of wma layer + * @buf: buffer pointer + * @size: size of buffer to be filled + * + * This function is used to dump state information of wma layer + * + * Return: None + */ +static void wma_state_info_dump(char **buf_ptr, uint16_t *size) +{ + t_wma_handle *wma; + struct sir_vdev_wow_stats *stats; + uint16_t len = 0; + char *buf = *buf_ptr; + struct wma_txrx_node *iface; + uint8_t vdev_id; + + wma = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma) { + WMA_LOGE("%s: WMA context is invald!", __func__); + return; + } + + WMA_LOGI("%s: size of buffer: %d", __func__, *size); + + for (vdev_id = 0; vdev_id < wma->max_bssid; vdev_id++) { + iface = &wma->interfaces[vdev_id]; + if (!iface->handle) + continue; + + stats = &iface->wow_stats; + len += qdf_scnprintf(buf + len, *size - len, + "\n" + "vdev_id %d\n" + "WoW Stats\n" + "\tpno_match %u\n" + "\tpno_complete %u\n" + "\tgscan %u\n" + "\tlow_rssi %u\n" + "\trssi_breach %u\n" + "\tucast %u\n" + "\tbcast %u\n" + "\ticmpv4 %u\n" + "\ticmpv6 %u\n" + "\tipv4_mcast %u\n" + "\tipv6_mcast %u\n" + "\tipv6_mcast_ra %u\n" + "\tipv6_mcast_ns %u\n" + "\tipv6_mcast_na %u\n" + "\toem_response %u\n" + "conn_state %d\n" + "dtimPeriod %d\n" + "chanmode %d\n" + "vht_capable %d\n" + "ht_capable %d\n" + "chan_width %d\n" + "vdev_active %d\n" + "vdev_up %d\n" + "aid %d\n" + "rate_flags %d\n" + "nss %d\n" + "tx_power %d\n" + "max_tx_power %d\n" + "nwType %d\n" + "tx_streams %d\n" + "rx_streams %d\n" + "chain_mask %d\n" + "nss_2g %d\n" + "nss_5g %d", + vdev_id, + stats->pno_match, + stats->pno_complete, + stats->gscan, + stats->low_rssi, + stats->rssi_breach, + stats->ucast, + stats->bcast, + stats->icmpv4, + stats->icmpv6, + stats->ipv4_mcast, + stats->ipv6_mcast, + stats->ipv6_mcast_ra, + stats->ipv6_mcast_ns, + stats->ipv6_mcast_na, + stats->oem_response, + iface->conn_state, + iface->dtimPeriod, + iface->chanmode, + iface->vht_capable, + iface->ht_capable, + iface->chan_width, + iface->vdev_active, + iface->vdev_up, + iface->aid, + iface->rate_flags, + iface->nss, + iface->tx_power, + iface->max_tx_power, + iface->nwType, + iface->tx_streams, + iface->rx_streams, + iface->chain_mask, + iface->nss_2g, + iface->nss_5g); + } + + *size -= len; + *buf_ptr += len; +} + +/** + * wma_register_debug_callback() - registration function for wma layer + * to print wma state information + */ +static void wma_register_debug_callback(void) +{ + qdf_register_debug_callback(QDF_MODULE_ID_WMA, &wma_state_info_dump); +} + +/** + * wma_flush_complete_evt_handler() - FW log flush complete event handler + * @handle: WMI handle + * @event: Event recevied from FW + * @len: Length of the event + * + */ +static int wma_flush_complete_evt_handler(void *handle, + u_int8_t *event, + u_int32_t len) +{ + QDF_STATUS status; + tp_wma_handle wma = (tp_wma_handle) handle; + + WMI_DEBUG_MESG_FLUSH_COMPLETE_EVENTID_param_tlvs *param_buf; + wmi_debug_mesg_flush_complete_fixed_param *wmi_event; + uint32_t reason_code; + + param_buf = (WMI_DEBUG_MESG_FLUSH_COMPLETE_EVENTID_param_tlvs *) event; + if (!param_buf) { + WMA_LOGE("Invalid log flush complete event buffer"); + return QDF_STATUS_E_FAILURE; + } + + wmi_event = param_buf->fixed_param; + reason_code = wmi_event->reserved0; + + /* + * reason_code = 0; Flush event in response to flush command + * reason_code = other value; Asynchronous flush event for fatal events + */ + if (!reason_code && (cds_is_log_report_in_progress() == false)) { + WMA_LOGE("Received WMI flush event without sending CMD"); + return -EINVAL; + } else if (!reason_code && cds_is_log_report_in_progress() == true) { + /* Flush event in response to flush command */ + WMA_LOGI("Received WMI flush event in response to flush CMD"); + status = qdf_mc_timer_stop(&wma->log_completion_timer); + if (status != QDF_STATUS_SUCCESS) + WMA_LOGE("Failed to stop the log completion timeout"); + cds_logging_set_fw_flush_complete(); + } else if (reason_code && cds_is_log_report_in_progress() == false) { + /* Asynchronous flush event for fatal events */ + status = cds_set_log_completion(WLAN_LOG_TYPE_FATAL, + WLAN_LOG_INDICATOR_FIRMWARE, + reason_code, false); + if (QDF_STATUS_SUCCESS != status) { + WMA_LOGE("%s: Failed to set log trigger params", + __func__); + return QDF_STATUS_E_FAILURE; + } + cds_logging_set_fw_flush_complete(); + return status; + } else { + /* Asynchronous flush event for fatal event, + * but, report in progress already + */ + WMA_LOGI("%s: Bug report already in progress - dropping! type:%d, indicator=%d reason_code=%d", + __func__, WLAN_LOG_TYPE_FATAL, + WLAN_LOG_INDICATOR_FIRMWARE, reason_code); + return QDF_STATUS_E_FAILURE; + } + return 0; +} + +/** + * wma_open() - Allocate wma context and initialize it. + * @cds_context: cds context + * @wma_tgt_cfg_cb: tgt config callback fun + * @radar_ind_cb: dfs radar indication callback + * @cds_cfg: mac parameters + * + * Return: 0 on success, errno on failure + */ +QDF_STATUS wma_open(void *cds_context, + wma_tgt_cfg_cb tgt_cfg_cb, + wma_dfs_radar_indication_cb radar_ind_cb, + struct cds_config_info *cds_cfg) +{ + tp_wma_handle wma_handle; + HTC_HANDLE htc_handle; + qdf_device_t qdf_dev; + void *wmi_handle; + QDF_STATUS qdf_status; + struct txrx_pdev_cfg_param_t olCfg = { 0 }; + struct wmi_rx_ops ops; + + bool use_cookie = false; + + WMA_LOGD("%s: Enter", __func__); + + g_wmi_version_info.major = __WMI_VER_MAJOR_; + g_wmi_version_info.minor = __WMI_VER_MINOR_; + g_wmi_version_info.revision = __WMI_REVISION_; + + qdf_dev = cds_get_context(QDF_MODULE_ID_QDF_DEVICE); + htc_handle = cds_get_context(QDF_MODULE_ID_HTC); + + if (!htc_handle) { + WMA_LOGP("%s: Invalid HTC handle", __func__); + return QDF_STATUS_E_INVAL; + } + + /* Alloc memory for WMA Context */ + qdf_status = cds_alloc_context(cds_context, QDF_MODULE_ID_WMA, + (void **)&wma_handle, + sizeof(t_wma_handle)); + + if (qdf_status != QDF_STATUS_SUCCESS) { + WMA_LOGP("%s: Memory allocation failed for wma_handle", + __func__); + return qdf_status; + } + + qdf_mem_zero(wma_handle, sizeof(t_wma_handle)); + + if (cds_get_conparam() != QDF_GLOBAL_FTM_MODE) { +#ifdef FEATURE_WLAN_SCAN_PNO + qdf_wake_lock_create(&wma_handle->pno_wake_lock, "wlan_pno_wl"); +#endif /* FEATURE_WLAN_SCAN_PNO */ +#ifdef FEATURE_WLAN_EXTSCAN + qdf_wake_lock_create(&wma_handle->extscan_wake_lock, + "wlan_extscan_wl"); +#endif /* FEATURE_WLAN_EXTSCAN */ + qdf_wake_lock_create(&wma_handle->wow_wake_lock, "wlan_wow_wl"); + } + + /* Attach mc_thread context processing function */ + ops.wma_process_fw_event_handler_cbk = wma_process_fw_event_handler; + /* attach the wmi */ + wmi_handle = wmi_unified_attach(wma_handle, NULL, + WMI_TLV_TARGET, use_cookie, &ops); + if (!wmi_handle) { + WMA_LOGP("%s: failed to attach WMI", __func__); + qdf_status = QDF_STATUS_E_NOMEM; + goto err_wma_handle; + } + + WMA_LOGD("WMA --> wmi_unified_attach - success"); + wmi_unified_register_event_handler(wmi_handle, + WMI_SERVICE_READY_EVENTID, + wma_rx_service_ready_event, + WMA_RX_SERIALIZER_CTX); + wmi_unified_register_event_handler(wmi_handle, + WMI_SERVICE_READY_EXT_EVENTID, + wma_rx_service_ready_ext_event, + WMA_RX_SERIALIZER_CTX); + wmi_unified_register_event_handler(wmi_handle, + WMI_READY_EVENTID, + wma_rx_ready_event, + WMA_RX_SERIALIZER_CTX); + /* Save the WMI & HTC handle */ + wma_handle->wmi_handle = wmi_handle; + wma_handle->htc_handle = htc_handle; + wma_handle->cds_context = cds_context; + wma_handle->qdf_dev = qdf_dev; + wma_handle->max_scan = cds_cfg->max_scan; + + qdf_runtime_lock_init(&wma_handle->wma_runtime_resume_lock); + + /* Initialize max_no_of_peers for wma_get_number_of_peers_supported() */ + wma_init_max_no_of_peers(wma_handle, cds_cfg->max_station); + /* Cap maxStation based on the target version */ + cds_cfg->max_station = wma_get_number_of_peers_supported(wma_handle); + /* Reinitialize max_no_of_peers based on the capped maxStation value */ + wma_init_max_no_of_peers(wma_handle, cds_cfg->max_station); + + /* initialize default target config */ + wma_set_default_tgt_config(wma_handle); + + olCfg.is_uc_offload_enabled = cds_cfg->uc_offload_enabled; + olCfg.uc_tx_buffer_count = cds_cfg->uc_txbuf_count; + olCfg.uc_tx_buffer_size = cds_cfg->uc_txbuf_size; + olCfg.uc_rx_indication_ring_count = cds_cfg->uc_rxind_ringcount; + olCfg.uc_tx_partition_base = cds_cfg->uc_tx_partition_base; + + + wma_handle->tx_chain_mask_cck = cds_cfg->tx_chain_mask_cck; + wma_handle->self_gen_frm_pwr = cds_cfg->self_gen_frm_pwr; + + /* Allocate cfg handle */ + + /* RX Full reorder should enable for PCIe, ROME3.X project only now + * MDM should enable later, schedule TBD + * HL also sdould be enabled, schedule TBD + */ +#ifdef WLAN_FEATURE_RX_FULL_REORDER_OL + olCfg.is_full_reorder_offload = cds_cfg->reorder_offload; +#else + olCfg.is_full_reorder_offload = 0; +#endif /* WLAN_FEATURE_RX_FULL_REORDER_OL */ + olCfg.enable_rxthread = cds_cfg->enable_rxthread; + olCfg.ip_tcp_udp_checksum_offload = + cds_cfg->ip_tcp_udp_checksum_offload; + olCfg.ce_classify_enabled = cds_cfg->ce_classify_enabled; + + ol_cfg_set_flow_control_parameters(&olCfg, cds_cfg); + ol_cfg_update_ac_specs_params(&olCfg, cds_cfg); + + ((p_cds_contextType) cds_context)->cfg_ctx = + ol_pdev_cfg_attach(((p_cds_contextType) cds_context)->qdf_ctx, + olCfg); + if (!(((p_cds_contextType) cds_context)->cfg_ctx)) { + WMA_LOGP("%s: failed to init cfg handle", __func__); + qdf_status = QDF_STATUS_E_NOMEM; + goto err_wmi_handle; + } + + /* adjust the cfg_ctx default value based on setting */ + ol_set_cfg_rx_fwd_disabled((ol_pdev_handle) + ((p_cds_contextType) cds_context)->cfg_ctx, + (uint8_t) cds_cfg->ap_disable_intrabss_fwd); + + /* Configure Receive flow steering */ + ol_set_cfg_flow_steering((ol_pdev_handle) + ((p_cds_contextType)cds_context)->cfg_ctx, + cds_cfg->flow_steering_enabled); + + /* adjust the packet log enable default value based on CFG INI setting */ + ol_set_cfg_packet_log_enabled((ol_pdev_handle) + ((p_cds_contextType) cds_context)-> + cfg_ctx, + (uint8_t)cds_is_packet_log_enabled()); + + /* Allocate dfs_ic and initialize DFS */ + wma_handle->dfs_ic = wma_dfs_attach(wma_handle->dfs_ic); + if (wma_handle->dfs_ic == NULL) { + WMA_LOGE("%s: Memory allocation failed for dfs_ic", __func__); + goto err_wmi_handle; + } +#if defined(QCA_WIFI_FTM) + if (cds_get_conparam() == QDF_GLOBAL_FTM_MODE) + wma_utf_attach(wma_handle); +#endif /* QCA_WIFI_FTM */ + wma_init_max_no_of_peers(wma_handle, cds_cfg->max_station); + cds_cfg->max_station = wma_get_number_of_peers_supported(wma_handle); + + cds_cfg->max_bssid = WMA_MAX_SUPPORTED_BSS; + + wma_handle->wlan_resource_config.num_wow_filters = + cds_cfg->max_wow_filters; + wma_handle->wlan_resource_config.num_keep_alive_pattern = + WMA_MAXNUM_PERIODIC_TX_PTRNS; + + /* The current firmware implementation requires the number of + * offload peers should be (number of vdevs + 1). + */ + wma_handle->wlan_resource_config.num_offload_peers = + cds_cfg->ap_maxoffload_peers + 1; + + wma_handle->wlan_resource_config.num_offload_reorder_buffs = + cds_cfg->ap_maxoffload_reorderbuffs + 1; + + wma_handle->ol_ini_info = cds_cfg->ol_ini_info; + wma_handle->max_station = cds_cfg->max_station; + wma_handle->max_bssid = cds_cfg->max_bssid; + wma_handle->driver_type = cds_cfg->driver_type; + wma_handle->ssdp = cds_cfg->ssdp; + wma_handle->enable_mc_list = cds_cfg->enable_mc_list; + wma_handle->bpf_packet_filter_enable = + cds_cfg->bpf_packet_filter_enable; + wma_handle->active_bpf_mode = cds_cfg->active_bpf_mode; + wma_handle->link_stats_results = NULL; +#ifdef FEATURE_WLAN_RA_FILTERING + wma_handle->IsRArateLimitEnabled = cds_cfg->is_ra_ratelimit_enabled; + wma_handle->RArateLimitInterval = cds_cfg->ra_ratelimit_interval; +#endif /* FEATURE_WLAN_RA_FILTERING */ +#ifdef WLAN_FEATURE_LPSS + wma_handle->is_lpass_enabled = cds_cfg->is_lpass_enabled; +#endif + wma_set_nan_enable(wma_handle, cds_cfg); + /* + * Indicates if DFS Phyerr filtering offload + * is Enabled/Disabed from ini + */ + wma_handle->dfs_phyerr_filter_offload = + cds_cfg->dfs_phyerr_filter_offload; + wma_handle->dfs_pri_multiplier = cds_cfg->dfs_pri_multiplier; + wma_handle->interfaces = qdf_mem_malloc(sizeof(struct wma_txrx_node) * + wma_handle->max_bssid); + if (!wma_handle->interfaces) { + WMA_LOGP("%s: failed to allocate interface table", __func__); + qdf_status = QDF_STATUS_E_NOMEM; + goto err_scn_context; + } + qdf_mem_zero(wma_handle->interfaces, sizeof(struct wma_txrx_node) * + wma_handle->max_bssid); + /* Register the debug print event handler */ + wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_DEBUG_PRINT_EVENTID, + wma_unified_debug_print_event_handler, + WMA_RX_SERIALIZER_CTX); + /* Register profiling event Handler */ + wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_WLAN_PROFILE_DATA_EVENTID, + wma_profile_data_report_event_handler, + WMA_RX_SERIALIZER_CTX); + + wma_handle->tgt_cfg_update_cb = tgt_cfg_cb; + wma_handle->dfs_radar_indication_cb = radar_ind_cb; + wma_handle->old_hw_mode_index = WMA_DEFAULT_HW_MODE_INDEX; + wma_handle->new_hw_mode_index = WMA_DEFAULT_HW_MODE_INDEX; + wma_handle->saved_chan.num_channels = 0; + wma_handle->fw_timeout_crash = cds_cfg->fw_timeout_crash; + + qdf_status = qdf_event_create(&wma_handle->wma_ready_event); + if (qdf_status != QDF_STATUS_SUCCESS) { + WMA_LOGP("%s: wma_ready_event initialization failed", __func__); + goto err_event_init; + } + + qdf_status = qdf_mc_timer_init(&wma_handle->service_ready_ext_timer, + QDF_TIMER_TYPE_SW, + wma_service_ready_ext_evt_timeout, + wma_handle); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + WMA_LOGE("Failed to initialize service ready ext timeout"); + goto err_event_init; + } + + qdf_status = qdf_event_create(&wma_handle->target_suspend); + if (qdf_status != QDF_STATUS_SUCCESS) { + WMA_LOGP("%s: target suspend event initialization failed", + __func__); + goto err_event_init; + } + + /* Init Tx Frame Complete event */ + qdf_status = qdf_event_create(&wma_handle->tx_frm_download_comp_event); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + WMA_LOGP("%s: failed to init tx_frm_download_comp_event", + __func__); + goto err_event_init; + } + + /* Init tx queue empty check event */ + qdf_status = qdf_event_create(&wma_handle->tx_queue_empty_event); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + WMA_LOGP("%s: failed to init tx_queue_empty_event", __func__); + goto err_event_init; + } + + qdf_status = qdf_event_create(&wma_handle->wma_resume_event); + if (qdf_status != QDF_STATUS_SUCCESS) { + WMA_LOGP("%s: wma_resume_event initialization failed", + __func__); + goto err_event_init; + } + + qdf_status = cds_shutdown_notifier_register(wma_shutdown_notifier_cb, + wma_handle); + if (qdf_status != QDF_STATUS_SUCCESS) { + WMA_LOGP("%s: Shutdown notifier register failed: %d", + __func__, qdf_status); + goto err_event_init; + } + + qdf_status = qdf_event_create(&wma_handle->runtime_suspend); + if (qdf_status != QDF_STATUS_SUCCESS) { + WMA_LOGP("%s: runtime_suspend event initialization failed", + __func__); + goto err_event_init; + } + + qdf_status = qdf_event_create(&wma_handle->recovery_event); + if (qdf_status != QDF_STATUS_SUCCESS) { + WMA_LOGP("%s: recovery event initialization failed", __func__); + goto err_event_init; + } + + qdf_list_create(&wma_handle->vdev_resp_queue, + MAX_ENTRY_VDEV_RESP_QUEUE); + qdf_spinlock_create(&wma_handle->vdev_respq_lock); + qdf_list_create(&wma_handle->wma_hold_req_queue, + MAX_ENTRY_HOLD_REQ_QUEUE); + qdf_spinlock_create(&wma_handle->wma_hold_req_q_lock); + qdf_atomic_init(&wma_handle->is_wow_bus_suspended); + qdf_atomic_init(&wma_handle->scan_id_counter); + + /* Register vdev start response event handler */ + wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_VDEV_START_RESP_EVENTID, + wma_vdev_start_resp_handler, + WMA_RX_SERIALIZER_CTX); + + /* Register vdev stop response event handler */ + wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_VDEV_STOPPED_EVENTID, + wma_vdev_stop_resp_handler, + WMA_RX_SERIALIZER_CTX); + + /* register for STA kickout function */ + wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_PEER_STA_KICKOUT_EVENTID, + wma_peer_sta_kickout_event_handler, + WMA_RX_SERIALIZER_CTX); + + /* register for stats response event */ + wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_UPDATE_STATS_EVENTID, + wma_stats_event_handler, + WMA_RX_SERIALIZER_CTX); + + /* register for stats response event */ + wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_VDEV_GET_ARP_STAT_EVENTID, + wma_get_arp_stats_handler, + WMA_RX_SERIALIZER_CTX); + + +#ifdef WLAN_POWER_DEBUGFS + /* register for Chip Power stats event */ + wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_PDEV_CHIP_POWER_STATS_EVENTID, + wma_unified_power_debug_stats_event_handler, + WMA_RX_SERIALIZER_CTX); +#endif + + /* register for linkspeed response event */ + wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_PEER_ESTIMATED_LINKSPEED_EVENTID, + wma_link_speed_event_handler, + WMA_RX_SERIALIZER_CTX); + +#ifdef FEATURE_OEM_DATA_SUPPORT + wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_OEM_RESPONSE_EVENTID, + wma_oem_data_response_handler, + WMA_RX_SERIALIZER_CTX); +#endif /* FEATURE_OEM_DATA_SUPPORT */ + /* + * Register appropriate DFS phyerr event handler for + * Phyerror events. Handlers differ for phyerr filtering + * offload enable and disable cases. + */ + wma_register_dfs_event_handler(wma_handle); + + /* Register peer change event handler */ + wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_PEER_STATE_EVENTID, + wma_peer_state_change_event_handler, + WMA_RX_WORK_CTX); + + /* Register beacon tx complete event id. The event is required + * for sending channel switch announcement frames + */ + wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_OFFLOAD_BCN_TX_STATUS_EVENTID, + wma_unified_bcntx_status_event_handler, + WMA_RX_SERIALIZER_CTX); + + wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_UPDATE_VDEV_RATE_STATS_EVENTID, + wma_link_status_event_handler, + WMA_RX_SERIALIZER_CTX); +#ifdef WLAN_FEATURE_LINK_LAYER_STATS + /* Register event handler for processing Link Layer Stats + * response from the FW + */ + wma_register_ll_stats_event_handler(wma_handle); + +#endif /* WLAN_FEATURE_LINK_LAYER_STATS */ + + /* + * Register event handler to receive firmware mem dump + * copy complete indication + */ + wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_UPDATE_FW_MEM_DUMP_EVENTID, + wma_fw_mem_dump_event_handler, + WMA_RX_SERIALIZER_CTX); + + wmi_set_tgt_assert(wma_handle->wmi_handle, + cds_cfg->force_target_assert_enabled); + /* Firmware debug log */ + qdf_status = dbglog_init(wma_handle->wmi_handle); + if (qdf_status != QDF_STATUS_SUCCESS) { + WMA_LOGP("%s: Firmware Dbglog initialization failed", __func__); + goto err_dbglog_init; + } + + /* + * Update Powersave mode + * 1 - Legacy Powersave + Deepsleep Disabled + * 2 - QPower + Deepsleep Disabled + * 3 - Legacy Powersave + Deepsleep Enabled + * 4 - QPower + Deepsleep Enabled + */ + wma_handle->powersave_mode = cds_cfg->powersave_offload_enabled; + wma_handle->staMaxLIModDtim = cds_cfg->sta_maxlimod_dtim; + wma_handle->staModDtim = cds_cfg->sta_mod_dtim; + wma_handle->staDynamicDtim = cds_cfg->sta_dynamic_dtim; + + /* + * Value of cds_cfg->wow_enable can be, + * 0 - Disable both magic pattern match and pattern byte match. + * 1 - Enable magic pattern match on all interfaces. + * 2 - Enable pattern byte match on all interfaces. + * 3 - Enable both magic patter and pattern byte match on + * all interfaces. + */ + wma_handle->wow.magic_ptrn_enable = + (cds_cfg->wow_enable & 0x01) ? true : false; + wma_handle->ptrn_match_enable_all_vdev = + (cds_cfg->wow_enable & 0x02) ? true : false; + +#ifdef FEATURE_WLAN_TDLS + wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_TDLS_PEER_EVENTID, + wma_tdls_event_handler, + WMA_RX_SERIALIZER_CTX); +#endif /* FEATURE_WLAN_TDLS */ + + /* register for install key completion event */ + wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_VDEV_INSTALL_KEY_COMPLETE_EVENTID, + wma_vdev_install_key_complete_event_handler, + WMA_RX_SERIALIZER_CTX); +#ifdef WLAN_FEATURE_NAN + /* register for nan response event */ + wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_NAN_EVENTID, + wma_nan_rsp_event_handler, + WMA_RX_SERIALIZER_CTX); +#endif /* WLAN_FEATURE_NAN */ + +#ifdef WLAN_FEATURE_STATS_EXT + /* register for extended stats event */ + wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_STATS_EXT_EVENTID, + wma_stats_ext_event_handler, + WMA_RX_SERIALIZER_CTX); +#endif /* WLAN_FEATURE_STATS_EXT */ +#ifdef FEATURE_WLAN_EXTSCAN + wma_register_extscan_event_handler(wma_handle); +#endif /* WLAN_FEATURE_STATS_EXT */ + + WMA_LOGD("%s: Exit", __func__); + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_ROAM_SYNCH_EVENTID, + wma_roam_synch_event_handler, + WMA_RX_SERIALIZER_CTX); +#endif /* WLAN_FEATURE_ROAM_OFFLOAD */ + wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_RSSI_BREACH_EVENTID, + wma_rssi_breached_event_handler, + WMA_RX_SERIALIZER_CTX); + + qdf_wake_lock_create(&wma_handle->wmi_cmd_rsp_wake_lock, + "wlan_fw_rsp_wakelock"); + qdf_runtime_lock_init(&wma_handle->wmi_cmd_rsp_runtime_lock); + + /* Register peer assoc conf event handler */ + wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_PEER_ASSOC_CONF_EVENTID, + wma_peer_assoc_conf_handler, + WMA_RX_SERIALIZER_CTX); + wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_VDEV_DELETE_RESP_EVENTID, + wma_vdev_delete_handler, + WMA_RX_SERIALIZER_CTX); + wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_PEER_DELETE_RESP_EVENTID, + wma_peer_delete_handler, + WMA_RX_SERIALIZER_CTX); + wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_BPF_CAPABILIY_INFO_EVENTID, + wma_get_bpf_caps_event_handler, + WMA_RX_SERIALIZER_CTX); + wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_VDEV_ENCRYPT_DECRYPT_DATA_RESP_EVENTID, + wma_encrypt_decrypt_msg_handler, + WMA_RX_SERIALIZER_CTX); + wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_DEBUG_MESG_FLUSH_COMPLETE_EVENTID, + wma_flush_complete_evt_handler, + WMA_RX_WORK_CTX); + + wma_handle->ito_repeat_count = cds_cfg->ito_repeat_count; + + wma_handle->auto_power_save_enabled = + cds_cfg->auto_power_save_fail_mode; + /* Register PWR_SAVE_FAIL event only in case of recovery(1) */ + if (wma_handle->auto_power_save_enabled) { + wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_PDEV_CHIP_POWER_SAVE_FAILURE_DETECTED_EVENTID, + wma_chip_power_save_failure_detected_handler, + WMA_RX_SERIALIZER_CTX); + } + + wma_ndp_register_all_event_handlers(wma_handle); + wma_register_debug_callback(); + + wma_handle->peer_dbg = qdf_mem_malloc(sizeof(*wma_handle->peer_dbg)); + if (!wma_handle->peer_dbg) { + WMA_LOGP("%s: failed to peer debug info table", __func__); + qdf_status = QDF_STATUS_E_NOMEM; + goto err_dbglog_init; + } + qdf_atomic_init(&wma_handle->peer_dbg->index); + qdf_atomic_set(&wma_handle->peer_dbg->index, -1); + + return QDF_STATUS_SUCCESS; + +err_dbglog_init: + qdf_wake_lock_destroy(&wma_handle->wmi_cmd_rsp_wake_lock); + qdf_runtime_lock_deinit(&wma_handle->wmi_cmd_rsp_runtime_lock); + qdf_spinlock_destroy(&wma_handle->vdev_respq_lock); + qdf_spinlock_destroy(&wma_handle->wma_hold_req_q_lock); +err_event_init: + wmi_unified_unregister_event_handler(wma_handle->wmi_handle, + WMI_DEBUG_PRINT_EVENTID); + qdf_mem_free(wma_handle->interfaces); +err_scn_context: + wma_dfs_detach(wma_handle->dfs_ic); +#if defined(QCA_WIFI_FTM) + wma_utf_detach(wma_handle); +#endif /* QCA_WIFI_FTM */ +err_wmi_handle: + qdf_mem_free(((p_cds_contextType) cds_context)->cfg_ctx); + OS_FREE(wmi_handle); + +err_wma_handle: + + if (cds_get_conparam() != QDF_GLOBAL_FTM_MODE) { +#ifdef FEATURE_WLAN_SCAN_PNO + qdf_wake_lock_destroy(&wma_handle->pno_wake_lock); +#endif /* FEATURE_WLAN_SCAN_PNO */ +#ifdef FEATURE_WLAN_EXTSCAN + qdf_wake_lock_destroy(&wma_handle->extscan_wake_lock); +#endif /* FEATURE_WLAN_EXTSCAN */ + qdf_wake_lock_destroy(&wma_handle->wow_wake_lock); + } + + qdf_runtime_lock_deinit(&wma_handle->wma_runtime_resume_lock); + cds_free_context(cds_context, QDF_MODULE_ID_WMA, wma_handle); + + WMA_LOGD("%s: Exit", __func__); + + return qdf_status; +} + +/** + * wma_pre_start() - wma pre start + * @cds_ctx: cds context + * + * Return: 0 on success, errno on failure + */ +QDF_STATUS wma_pre_start(void *cds_ctx) +{ + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + A_STATUS status = A_OK; + tp_wma_handle wma_handle; + cds_msg_t wma_msg = { 0 }; + + WMA_LOGD("%s: Enter", __func__); + + wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + + /* Validate the wma_handle */ + if (NULL == wma_handle) { + WMA_LOGP("%s: invalid argument", __func__); + qdf_status = QDF_STATUS_E_INVAL; + goto end; + } + /* Open endpoint for ctrl path - WMI <--> HTC */ + status = wmi_unified_connect_htc_service(wma_handle->wmi_handle, + wma_handle->htc_handle); + if (A_OK != status) { + WMA_LOGP("%s: wmi_unified_connect_htc_service", __func__); + qdf_status = QDF_STATUS_E_FAULT; + goto end; + } + + WMA_LOGD("WMA --> wmi_unified_connect_htc_service - success"); + + /* Trigger the CFG DOWNLOAD */ + wma_msg.type = WNI_CFG_DNLD_REQ; + wma_msg.bodyptr = NULL; + wma_msg.bodyval = 0; + + qdf_status = cds_mq_post_message(CDS_MQ_ID_WMA, &wma_msg); + if (QDF_STATUS_SUCCESS != qdf_status) { + WMA_LOGP("%s: Failed to post WNI_CFG_DNLD_REQ msg", __func__); + QDF_ASSERT(0); + qdf_status = QDF_STATUS_E_FAILURE; + } +end: + WMA_LOGD("%s: Exit", __func__); + return qdf_status; +} + +/** + * wma_send_msg() - Send wma message to PE. + * @wma_handle: wma handle + * @msg_type: message type + * @body_ptr: message body ptr + * @body_val: message body value + * + * Return: none + */ +void wma_send_msg(tp_wma_handle wma_handle, uint16_t msg_type, + void *body_ptr, uint32_t body_val) +{ + tSirMsgQ msg = { 0 }; + uint32_t status = QDF_STATUS_SUCCESS; + tpAniSirGlobal pMac = cds_get_context(QDF_MODULE_ID_PE); + msg.type = msg_type; + msg.bodyval = body_val; + msg.bodyptr = body_ptr; + status = lim_post_msg_api(pMac, &msg); + if (QDF_STATUS_SUCCESS != status) { + if (NULL != body_ptr) + qdf_mem_free(body_ptr); + QDF_ASSERT(0); + } + return; +} + +/** + * wma_set_base_macaddr_indicate() - set base mac address in fw + * @wma_handle: wma handle + * @customAddr: base mac address + * + * Return: 0 for success or error code + */ +static int wma_set_base_macaddr_indicate(tp_wma_handle wma_handle, + tSirMacAddr *customAddr) +{ + int err; + + err = wmi_unified_set_base_macaddr_indicate_cmd(wma_handle->wmi_handle, + (uint8_t *)customAddr); + if (err) + return -EIO; + WMA_LOGD("Base MAC Addr: " MAC_ADDRESS_STR, + MAC_ADDR_ARRAY((*customAddr))); + + return 0; +} + +/** + * wma_log_supported_evt_handler() - Enable/Disable FW diag/log events + * @handle: WMA handle + * @event: Event received from FW + * @len: Length of the event + * + * Enables the low frequency events and disables the high frequency + * events. Bit 17 indicates if the event if low/high frequency. + * 1 - high frequency, 0 - low frequency + * + * Return: 0 on successfully enabling/disabling the events + */ +static int wma_log_supported_evt_handler(void *handle, + uint8_t *event, + uint32_t len) +{ + tp_wma_handle wma = (tp_wma_handle) handle; + + if (wmi_unified_log_supported_evt_cmd(wma->wmi_handle, + event, len)) + return -EINVAL; + + return 0; +} + +/** + * wma_pdev_set_hw_mode_resp_evt_handler() - Set HW mode resp evt handler + * @handle: WMI handle + * @event: Event recevied from FW + * @len: Length of the event + * + * Event handler for WMI_PDEV_SET_HW_MODE_RESP_EVENTID that is sent to host + * driver in response to a WMI_PDEV_SET_HW_MODE_CMDID being sent to WLAN + * firmware + * + * Return: Success on receiving valid params from FW + */ +static int wma_pdev_set_hw_mode_resp_evt_handler(void *handle, + uint8_t *event, + uint32_t len) +{ + WMI_PDEV_SET_HW_MODE_RESP_EVENTID_param_tlvs *param_buf; + wmi_pdev_set_hw_mode_response_event_fixed_param *wmi_event; + wmi_pdev_set_hw_mode_response_vdev_mac_entry *vdev_mac_entry; + uint32_t i; + struct sir_set_hw_mode_resp *hw_mode_resp; + tp_wma_handle wma = (tp_wma_handle) handle; + + if (!wma) { + WMA_LOGE("%s: Invalid WMA handle", __func__); + /* Since WMA handle itself is NULL, we cannot send fail + * response back to LIM here + */ + return QDF_STATUS_E_NULL_VALUE; + } + + hw_mode_resp = qdf_mem_malloc(sizeof(*hw_mode_resp)); + if (!hw_mode_resp) { + WMA_LOGI("%s: Memory allocation failed", __func__); + /* Since this memory allocation itself failed, we cannot + * send fail response back to LIM here + */ + return QDF_STATUS_E_NULL_VALUE; + } + + param_buf = (WMI_PDEV_SET_HW_MODE_RESP_EVENTID_param_tlvs *) event; + if (!param_buf) { + WMA_LOGE("Invalid WMI_PDEV_SET_HW_MODE_RESP_EVENTID event"); + /* Need to send response back to upper layer to free + * active command list + */ + goto fail; + } + + wmi_event = param_buf->fixed_param; + hw_mode_resp->status = wmi_event->status; + hw_mode_resp->cfgd_hw_mode_index = wmi_event->cfgd_hw_mode_index; + hw_mode_resp->num_vdev_mac_entries = wmi_event->num_vdev_mac_entries; + + WMA_LOGI("%s: status:%d cfgd_hw_mode_index:%d num_vdev_mac_entries:%d", + __func__, wmi_event->status, + wmi_event->cfgd_hw_mode_index, + wmi_event->num_vdev_mac_entries); + vdev_mac_entry = + param_buf->wmi_pdev_set_hw_mode_response_vdev_mac_mapping; + + /* Store the vdev-mac map in WMA and prepare to send to PE */ + for (i = 0; i < wmi_event->num_vdev_mac_entries; i++) { + uint32_t vdev_id, mac_id, pdev_id; + vdev_id = vdev_mac_entry[i].vdev_id; + pdev_id = vdev_mac_entry[i].pdev_id; + if (pdev_id == WMI_PDEV_ID_SOC) { + WMA_LOGE("%s: soc level id received for mac id)", + __func__); + QDF_BUG(0); + goto fail; + } + mac_id = WMA_PDEV_TO_MAC_MAP(vdev_mac_entry[i].pdev_id); + + WMA_LOGI("%s: vdev_id:%d mac_id:%d", + __func__, vdev_id, mac_id); + + hw_mode_resp->vdev_mac_map[i].vdev_id = vdev_id; + hw_mode_resp->vdev_mac_map[i].mac_id = mac_id; + wma_update_intf_hw_mode_params(vdev_id, mac_id, + wmi_event->cfgd_hw_mode_index); + } + + if (hw_mode_resp->status == SET_HW_MODE_STATUS_OK) { + if (WMA_DEFAULT_HW_MODE_INDEX == wma->new_hw_mode_index) { + wma->new_hw_mode_index = wmi_event->cfgd_hw_mode_index; + } else { + wma->old_hw_mode_index = wma->new_hw_mode_index; + wma->new_hw_mode_index = wmi_event->cfgd_hw_mode_index; + } + } + + WMA_LOGI("%s: Updated: old_hw_mode_index:%d new_hw_mode_index:%d", + __func__, wma->old_hw_mode_index, wma->new_hw_mode_index); + + wma_send_msg(wma, SIR_HAL_PDEV_SET_HW_MODE_RESP, + (void *) hw_mode_resp, 0); + + return QDF_STATUS_SUCCESS; + +fail: + WMA_LOGE("%s: Sending fail response to LIM", __func__); + hw_mode_resp->status = SET_HW_MODE_STATUS_ECANCELED; + hw_mode_resp->cfgd_hw_mode_index = 0; + hw_mode_resp->num_vdev_mac_entries = 0; + wma_send_msg(wma, SIR_HAL_PDEV_SET_HW_MODE_RESP, + (void *) hw_mode_resp, 0); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wma_process_pdev_hw_mode_trans_ind() - Process HW mode transition info + * + * @handle: WMA handle + * @fixed_param: Event fixed parameters + * @vdev_mac_entry - vdev mac entry + * @hw_mode_trans_ind - Buffer to store parsed information + * + * Parses fixed_param, vdev_mac_entry and fills in the information into + * hw_mode_trans_ind and wma + * + * Return: None + */ +void wma_process_pdev_hw_mode_trans_ind(void *handle, + wmi_pdev_hw_mode_transition_event_fixed_param *fixed_param, + wmi_pdev_set_hw_mode_response_vdev_mac_entry *vdev_mac_entry, + struct sir_hw_mode_trans_ind *hw_mode_trans_ind) +{ + uint32_t i; + tp_wma_handle wma = (tp_wma_handle) handle; + + hw_mode_trans_ind->old_hw_mode_index = fixed_param->old_hw_mode_index; + hw_mode_trans_ind->new_hw_mode_index = fixed_param->new_hw_mode_index; + hw_mode_trans_ind->num_vdev_mac_entries = + fixed_param->num_vdev_mac_entries; + WMA_LOGI("%s: old_hw_mode_index:%d new_hw_mode_index:%d entries=%d", + __func__, fixed_param->old_hw_mode_index, + fixed_param->new_hw_mode_index, + fixed_param->num_vdev_mac_entries); + + /* Store the vdev-mac map in WMA and send to policy manager */ + for (i = 0; i < fixed_param->num_vdev_mac_entries; i++) { + uint32_t vdev_id, mac_id, pdev_id; + vdev_id = vdev_mac_entry[i].vdev_id; + pdev_id = vdev_mac_entry[i].pdev_id; + + if (pdev_id == WMI_PDEV_ID_SOC) { + WMA_LOGE("%s: soc level id received for mac id)", + __func__); + QDF_BUG(0); + return; + } + + mac_id = WMA_PDEV_TO_MAC_MAP(vdev_mac_entry[i].pdev_id); + + WMA_LOGI("%s: vdev_id:%d mac_id:%d", + __func__, vdev_id, mac_id); + + hw_mode_trans_ind->vdev_mac_map[i].vdev_id = vdev_id; + hw_mode_trans_ind->vdev_mac_map[i].mac_id = mac_id; + wma_update_intf_hw_mode_params(vdev_id, mac_id, + fixed_param->new_hw_mode_index); + } + wma->old_hw_mode_index = fixed_param->old_hw_mode_index; + wma->new_hw_mode_index = fixed_param->new_hw_mode_index; + + WMA_LOGI("%s: Updated: old_hw_mode_index:%d new_hw_mode_index:%d", + __func__, wma->old_hw_mode_index, wma->new_hw_mode_index); +} + +/** + * wma_pdev_hw_mode_transition_evt_handler() - HW mode transition evt handler + * @handle: WMI handle + * @event: Event recevied from FW + * @len: Length of the event + * + * Event handler for WMI_PDEV_HW_MODE_TRANSITION_EVENTID that indicates an + * asynchronous hardware mode transition. This event notifies the host driver + * that firmware independently changed the hardware mode for some reason, such + * as Coex, LFR 3.0, etc + * + * Return: Success on receiving valid params from FW + */ +static int wma_pdev_hw_mode_transition_evt_handler(void *handle, + uint8_t *event, + uint32_t len) +{ + WMI_PDEV_HW_MODE_TRANSITION_EVENTID_param_tlvs *param_buf; + wmi_pdev_hw_mode_transition_event_fixed_param *wmi_event; + wmi_pdev_set_hw_mode_response_vdev_mac_entry *vdev_mac_entry; + struct sir_hw_mode_trans_ind *hw_mode_trans_ind; + tp_wma_handle wma = (tp_wma_handle) handle; + + if (!wma) { + /* This is an async event. So, not sending any event to LIM */ + WMA_LOGE("Invalid WMA handle"); + return QDF_STATUS_E_NULL_VALUE; + } + + param_buf = (WMI_PDEV_HW_MODE_TRANSITION_EVENTID_param_tlvs *) event; + if (!param_buf) { + /* This is an async event. So, not sending any event to LIM */ + WMA_LOGE("Invalid WMI_PDEV_HW_MODE_TRANSITION_EVENTID event"); + return QDF_STATUS_E_FAILURE; + } + + hw_mode_trans_ind = qdf_mem_malloc(sizeof(*hw_mode_trans_ind)); + if (!hw_mode_trans_ind) { + WMA_LOGI("%s: Memory allocation failed", __func__); + return QDF_STATUS_E_NULL_VALUE; + } + + wmi_event = param_buf->fixed_param; + vdev_mac_entry = + param_buf->wmi_pdev_set_hw_mode_response_vdev_mac_mapping; + wma_process_pdev_hw_mode_trans_ind(wma, wmi_event, vdev_mac_entry, + hw_mode_trans_ind); + /* Pass the message to PE */ + wma_send_msg(wma, SIR_HAL_PDEV_HW_MODE_TRANS_IND, + (void *) hw_mode_trans_ind, 0); + + return QDF_STATUS_SUCCESS; +} + +/** + * wma_pdev_set_dual_mode_config_resp_evt_handler() - Dual mode evt handler + * @handle: WMI handle + * @event: Event received from FW + * @len: Length of the event + * + * Notifies the host driver of the completion or failure of a + * WMI_PDEV_SET_MAC_CONFIG_CMDID command. This event would be returned to + * the host driver once the firmware has completed a reconfiguration of the Scan + * and FW mode configuration. This changes could include entering or leaving a + * dual mac configuration for either scan and/or more permanent firmware mode. + * + * Return: Success on receiving valid params from FW + */ +static int wma_pdev_set_dual_mode_config_resp_evt_handler(void *handle, + uint8_t *event, + uint32_t len) +{ + WMI_PDEV_SET_MAC_CONFIG_RESP_EVENTID_param_tlvs *param_buf; + wmi_pdev_set_mac_config_response_event_fixed_param *wmi_event; + tp_wma_handle wma = (tp_wma_handle) handle; + struct sir_dual_mac_config_resp *dual_mac_cfg_resp; + + if (!wma) { + WMA_LOGE("%s: Invalid WMA handle", __func__); + /* Since the WMA handle is NULL, we cannot send resp to LIM. + * So, returning from here. + */ + return QDF_STATUS_E_NULL_VALUE; + } + + dual_mac_cfg_resp = qdf_mem_malloc(sizeof(*dual_mac_cfg_resp)); + if (!dual_mac_cfg_resp) { + WMA_LOGE("%s: Memory allocation failed", __func__); + /* Since the mem alloc failed, we cannot send resp to LIM. + * So, returning from here. + */ + return QDF_STATUS_E_NULL_VALUE; + } + + param_buf = (WMI_PDEV_SET_MAC_CONFIG_RESP_EVENTID_param_tlvs *) + event; + if (!param_buf) { + WMA_LOGE("%s: Invalid event", __func__); + goto fail; + } + + wmi_event = param_buf->fixed_param; + WMA_LOGI("%s: status:%d", __func__, wmi_event->status); + dual_mac_cfg_resp->status = wmi_event->status; + + if (SET_HW_MODE_STATUS_OK == dual_mac_cfg_resp->status) { + wma->dual_mac_cfg.prev_scan_config = + wma->dual_mac_cfg.cur_scan_config; + wma->dual_mac_cfg.prev_fw_mode_config = + wma->dual_mac_cfg.cur_fw_mode_config; + wma->dual_mac_cfg.cur_scan_config = + wma->dual_mac_cfg.req_scan_config; + wma->dual_mac_cfg.cur_fw_mode_config = + wma->dual_mac_cfg.req_fw_mode_config; + } + + /* Pass the message to PE */ + wma_send_msg(wma, SIR_HAL_PDEV_MAC_CFG_RESP, + (void *) dual_mac_cfg_resp, 0); + + return QDF_STATUS_SUCCESS; + +fail: + WMA_LOGE("%s: Sending fail response to LIM", __func__); + dual_mac_cfg_resp->status = SET_HW_MODE_STATUS_ECANCELED; + wma_send_msg(wma, SIR_HAL_PDEV_MAC_CFG_RESP, + (void *) dual_mac_cfg_resp, 0); + + return QDF_STATUS_E_FAILURE; + +} + +/** + * wma_start() - wma start function. + * Intialize event handlers and timers. + * @cds_ctx: cds context + * + * Return: 0 on success, QDF Error on failure + */ +QDF_STATUS wma_start(void *cds_ctx) +{ + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + tp_wma_handle wma_handle; + int status; + WMA_LOGD("%s: Enter", __func__); + + wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + + /* validate the wma_handle */ + if (NULL == wma_handle) { + WMA_LOGP("%s: Invalid handle", __func__); + qdf_status = QDF_STATUS_E_INVAL; + goto end; + } + + status = wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_SCAN_EVENTID, + wma_scan_event_callback, + WMA_RX_SERIALIZER_CTX); + if (0 != status) { + WMA_LOGP("%s: Failed to register scan callback", __func__); + qdf_status = QDF_STATUS_E_FAILURE; + goto end; + } + + status = wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_ROAM_EVENTID, + wma_roam_event_callback, + WMA_RX_SERIALIZER_CTX); + if (0 != status) { + WMA_LOGP("%s: Failed to register Roam callback", __func__); + qdf_status = QDF_STATUS_E_FAILURE; + goto end; + } + + status = wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_WOW_WAKEUP_HOST_EVENTID, + wma_wow_wakeup_host_event, + WMA_RX_TASKLET_CTX); + if (status) { + WMA_LOGP("%s: Failed to register wow wakeup host event handler", + __func__); + qdf_status = QDF_STATUS_E_FAILURE; + goto end; + } + + status = wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_PDEV_RESUME_EVENTID, + wma_pdev_resume_event_handler, + WMA_RX_TASKLET_CTX); + if (status) { + WMA_LOGP("%s: Failed to register PDEV resume event handler", + __func__); + qdf_status = QDF_STATUS_E_FAILURE; + goto end; + } + +#ifdef FEATURE_WLAN_SCAN_PNO + if (WMI_SERVICE_IS_ENABLED(wma_handle->wmi_service_bitmap, + WMI_SERVICE_NLO)) { + + WMA_LOGD("FW supports pno offload, registering nlo match handler"); + + status = wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_NLO_MATCH_EVENTID, + wma_nlo_match_evt_handler, + WMA_RX_SERIALIZER_CTX); + if (status) { + WMA_LOGE("Failed to register nlo match event cb"); + qdf_status = QDF_STATUS_E_FAILURE; + goto end; + } + + status = wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_NLO_SCAN_COMPLETE_EVENTID, + wma_nlo_scan_cmp_evt_handler, + WMA_RX_SERIALIZER_CTX); + if (status) { + WMA_LOGE("Failed to register nlo scan comp event cb"); + qdf_status = QDF_STATUS_E_FAILURE; + goto end; + } + } +#endif /* FEATURE_WLAN_SCAN_PNO */ + +#if defined(QCA_LL_LEGACY_TX_FLOW_CONTROL) || \ + defined(QCA_LL_TX_FLOW_CONTROL_V2) || defined(CONFIG_HL_SUPPORT) + WMA_LOGE("MCC TX Pause Event Handler register"); + status = wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_TX_PAUSE_EVENTID, + wma_mcc_vdev_tx_pause_evt_handler, + WMA_RX_TASKLET_CTX); +#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */ + +#ifdef FEATURE_WLAN_CH_AVOID + WMA_LOGD("Registering channel to avoid handler"); + + status = wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_WLAN_FREQ_AVOID_EVENTID, + wma_channel_avoid_evt_handler, + WMA_RX_SERIALIZER_CTX); + if (status) { + WMA_LOGE("Failed to register channel to avoid event cb"); + qdf_status = QDF_STATUS_E_FAILURE; + goto end; + } +#endif /* FEATURE_WLAN_CH_AVOID */ +#ifdef FEATURE_WLAN_AUTO_SHUTDOWN + WMA_LOGD("Registering auto shutdown handler"); + status = wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_HOST_AUTO_SHUTDOWN_EVENTID, + wma_auto_shutdown_event_handler, + WMA_RX_SERIALIZER_CTX); + if (status) { + WMA_LOGE("Failed to register WMI Auto shutdown event handler"); + qdf_status = QDF_STATUS_E_FAILURE; + goto end; + } +#endif /* FEATURE_WLAN_AUTO_SHUTDOWN */ + status = wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_THERMAL_MGMT_EVENTID, + wma_thermal_mgmt_evt_handler, + WMA_RX_SERIALIZER_CTX); + if (status) { + WMA_LOGE("Failed to register thermal mitigation event cb"); + qdf_status = QDF_STATUS_E_FAILURE; + goto end; + } + + status = wma_ocb_register_event_handlers(wma_handle); + if (status) { + WMA_LOGE("Failed to register ocb event handlers"); + qdf_status = QDF_STATUS_E_FAILURE; + goto end; + } + + qdf_status = QDF_STATUS_SUCCESS; + +#ifdef QCA_WIFI_FTM + /* + * Tx mgmt attach requires TXRX context which is not created + * in FTM mode. So skip the TX mgmt attach. + */ + if (cds_get_conparam() == QDF_GLOBAL_FTM_MODE) + goto end; +#endif /* QCA_WIFI_FTM */ + + if (WMI_SERVICE_IS_ENABLED(wma_handle->wmi_service_bitmap, + WMI_SERVICE_RMC)) { + + WMA_LOGD("FW supports cesium network, registering event handlers"); + + status = wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_PEER_INFO_EVENTID, + wma_ibss_peer_info_event_handler, + WMA_RX_SERIALIZER_CTX); + if (status) { + WMA_LOGE("Failed to register ibss peer info event cb"); + qdf_status = QDF_STATUS_E_FAILURE; + goto end; + } + + status = wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_PEER_TX_FAIL_CNT_THR_EVENTID, + wma_fast_tx_fail_event_handler, + WMA_RX_SERIALIZER_CTX); + if (status) { + WMA_LOGE("Failed to register peer fast tx failure event cb"); + qdf_status = QDF_STATUS_E_FAILURE; + goto end; + } + } else { + WMA_LOGE("Target does not support cesium network"); + } + + qdf_status = wma_tx_attach(wma_handle); + if (qdf_status != QDF_STATUS_SUCCESS) { + WMA_LOGP("%s: Failed to register tx management", __func__); + goto end; + } + + /* Initialize log completion timeout */ + qdf_status = qdf_mc_timer_init(&wma_handle->log_completion_timer, + QDF_TIMER_TYPE_SW, + wma_log_completion_timeout, + wma_handle); + if (qdf_status != QDF_STATUS_SUCCESS) { + WMA_LOGE("Failed to initialize log completion timeout"); + goto end; + } + + /* Initialize the get temperature event handler */ + status = wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_PDEV_TEMPERATURE_EVENTID, + wma_pdev_temperature_evt_handler, + WMA_RX_SERIALIZER_CTX); + if (status != QDF_STATUS_SUCCESS) { + WMA_LOGE("Failed to register get_temperature event cb"); + qdf_status = QDF_STATUS_E_FAILURE; + goto end; + } + + status = wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_VDEV_TSF_REPORT_EVENTID, + wma_vdev_tsf_handler, + WMA_RX_SERIALIZER_CTX); + if (0 != status) { + WMA_LOGP("%s: Failed to register tsf callback", __func__); + qdf_status = QDF_STATUS_E_FAILURE; + goto end; + } + + /* Initialize the wma_pdev_set_hw_mode_resp_evt_handler event handler */ + status = wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_PDEV_SET_HW_MODE_RESP_EVENTID, + wma_pdev_set_hw_mode_resp_evt_handler, + WMA_RX_SERIALIZER_CTX); + if (status != QDF_STATUS_SUCCESS) { + WMA_LOGE("Failed to register set hw mode resp event cb"); + qdf_status = QDF_STATUS_E_FAILURE; + goto end; + } + + /* Initialize the WMI_SOC_HW_MODE_TRANSITION_EVENTID event handler */ + status = wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_PDEV_HW_MODE_TRANSITION_EVENTID, + wma_pdev_hw_mode_transition_evt_handler, + WMA_RX_SERIALIZER_CTX); + if (status != QDF_STATUS_SUCCESS) { + WMA_LOGE("Failed to register hw mode transition event cb"); + qdf_status = QDF_STATUS_E_FAILURE; + goto end; + } + + /* Initialize the set dual mac configuration event handler */ + status = wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_PDEV_SET_MAC_CONFIG_RESP_EVENTID, + wma_pdev_set_dual_mode_config_resp_evt_handler, + WMA_RX_SERIALIZER_CTX); + if (status != QDF_STATUS_SUCCESS) { + WMA_LOGE("Failed to register hw mode transition event cb"); + qdf_status = QDF_STATUS_E_FAILURE; + goto end; + } + + /* Initialize the P2P Listen Offload event handler */ + status = wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_P2P_LISTEN_OFFLOAD_STOPPED_EVENTID, + wma_p2p_lo_event_handler, + WMA_RX_SERIALIZER_CTX); + if (!QDF_IS_STATUS_SUCCESS(status)) { + WMA_LOGE("Failed to register p2p lo event cb"); + qdf_status = QDF_STATUS_E_FAILURE; + goto end; + } + +end: + WMA_LOGD("%s: Exit", __func__); + return qdf_status; +} + +/** + * wma_stop() - wma stop function. + * cleanup timers and suspend target. + * @cds_ctx: cds context + * @reason: reason for wma_stop. + * + * Return: 0 on success, QDF Error on failure + */ +QDF_STATUS wma_stop(void *cds_ctx, uint8_t reason) +{ + tp_wma_handle wma_handle; + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + int i; + wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + + WMA_LOGD("%s: Enter", __func__); + + /* validate the wma_handle */ + if (NULL == wma_handle) { + WMA_LOGP("%s: Invalid handle", __func__); + qdf_status = QDF_STATUS_E_INVAL; + goto end; + } +#ifdef QCA_WIFI_FTM + /* + * Tx mgmt detach requires TXRX context which is not created + * in FTM mode. So skip the TX mgmt detach. + */ + if (cds_get_conparam() == QDF_GLOBAL_FTM_MODE) { + qdf_status = QDF_STATUS_SUCCESS; + goto end; + } +#endif /* QCA_WIFI_FTM */ + + if (wma_handle->ack_work_ctx) { + cds_flush_work(&wma_handle->ack_work_ctx->ack_cmp_work); + qdf_mem_free(wma_handle->ack_work_ctx); + wma_handle->ack_work_ctx = NULL; + } + + /* Destroy the timer for log completion */ + qdf_status = qdf_mc_timer_destroy(&wma_handle->log_completion_timer); + if (qdf_status != QDF_STATUS_SUCCESS) { + WMA_LOGE("Failed to destroy the log completion timer"); + } + + /* clean up ll-queue for all vdev */ + for (i = 0; i < wma_handle->max_bssid; i++) { + if (wma_handle->interfaces[i].handle && + wma_handle->interfaces[i].vdev_up) { + ol_txrx_vdev_flush(wma_handle->interfaces[i].handle); + } + } + qdf_status = wma_tx_detach(wma_handle); + if (qdf_status != QDF_STATUS_SUCCESS) { + WMA_LOGP("%s: Failed to deregister tx management", __func__); + goto end; + } + +end: + WMA_LOGD("%s: Exit", __func__); + return qdf_status; +} + +/** + * wma_wmi_service_close() - close wma wmi service interface. + * @cds_ctx: cds context + * + * Return: 0 on success, QDF Error on failure + */ +QDF_STATUS wma_wmi_service_close(void *cds_ctx) +{ + tp_wma_handle wma_handle; + struct beacon_info *bcn; + int i; + + WMA_LOGD("%s: Enter", __func__); + + wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + + /* validate the wma_handle */ + if (NULL == wma_handle) { + WMA_LOGE("%s: Invalid wma handle", __func__); + return QDF_STATUS_E_INVAL; + } + + /* validate the wmi handle */ + if (NULL == wma_handle->wmi_handle) { + WMA_LOGE("%s: Invalid wmi handle", __func__); + return QDF_STATUS_E_INVAL; + } + + /* dettach the wmi serice */ + WMA_LOGD("calling wmi_unified_detach"); + wmi_unified_detach(wma_handle->wmi_handle); + wma_handle->wmi_handle = NULL; + + for (i = 0; i < wma_handle->max_bssid; i++) { + bcn = wma_handle->interfaces[i].beacon; + + if (bcn) { + if (bcn->dma_mapped) + qdf_nbuf_unmap_single(wma_handle->qdf_dev, + bcn->buf, QDF_DMA_TO_DEVICE); + qdf_nbuf_free(bcn->buf); + qdf_mem_free(bcn); + wma_handle->interfaces[i].beacon = NULL; + } + + if (wma_handle->interfaces[i].handle) { + qdf_mem_free(wma_handle->interfaces[i].handle); + wma_handle->interfaces[i].handle = NULL; + } + + if (wma_handle->interfaces[i].addBssStaContext) { + qdf_mem_free(wma_handle-> + interfaces[i].addBssStaContext); + wma_handle->interfaces[i].addBssStaContext = NULL; + } + + if (wma_handle->interfaces[i].del_staself_req) { + qdf_mem_free(wma_handle->interfaces[i].del_staself_req); + wma_handle->interfaces[i].del_staself_req = NULL; + } + + if (wma_handle->interfaces[i].stats_rsp) { + qdf_mem_free(wma_handle->interfaces[i].stats_rsp); + wma_handle->interfaces[i].stats_rsp = NULL; + } + + if (wma_handle->interfaces[i].psnr_req) { + qdf_mem_free(wma_handle-> + interfaces[i].psnr_req); + wma_handle->interfaces[i].psnr_req = NULL; + } + + if (wma_handle->interfaces[i].rcpi_req) { + qdf_mem_free(wma_handle-> + interfaces[i].rcpi_req); + wma_handle->interfaces[i].rcpi_req = NULL; + } + + } + + qdf_mem_free(wma_handle->interfaces); + /* free the wma_handle */ + cds_free_context(wma_handle->cds_context, QDF_MODULE_ID_WMA, + wma_handle); + + qdf_mem_free(((p_cds_contextType) cds_ctx)->cfg_ctx); + WMA_LOGD("%s: Exit", __func__); + return QDF_STATUS_SUCCESS; +} + +/** + * wma_wmi_work_close() - close the work queue items associated with WMI + * @cds_ctx: Pointer to cds context + * + * This function closes work queue items associated with WMI, but not fully + * closes WMI service. + * + * Return: QDF_STATUS_SUCCESS if work close is successful. Otherwise + * proper error codes. + */ +QDF_STATUS wma_wmi_work_close(void *cds_ctx) +{ + tp_wma_handle wma_handle; + + WMA_LOGD("%s: Enter", __func__); + + wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + + /* validate the wma_handle */ + if (NULL == wma_handle) { + WMA_LOGE("%s: Invalid wma handle", __func__); + return QDF_STATUS_E_INVAL; + } + + /* validate the wmi handle */ + if (NULL == wma_handle->wmi_handle) { + WMA_LOGE("%s: Invalid wmi handle", __func__); + return QDF_STATUS_E_INVAL; + } + + /* remove the wmi work */ + WMA_LOGD("calling wmi_unified_remove_work"); + wmi_unified_remove_work(wma_handle->wmi_handle); + + return QDF_STATUS_SUCCESS; +} + +/** + * wma_cleanup_dbs_phy_caps() - release memory allocated for holding ext cap + * @wma_handle: pointer to wma handle + * + * This function releases all the memory created for holding extended + * capabilities per hardware mode and per PHY + * + * Return: void + */ +static void wma_cleanup_dbs_phy_caps(t_wma_handle *wma_handle) +{ + if (NULL == wma_handle) { + WMA_LOGE("%s: Invalid wma handle", __func__); + return; + } + + if (wma_handle->phy_caps.hw_mode_to_mac_cap_map) { + qdf_mem_free(wma_handle->phy_caps.hw_mode_to_mac_cap_map); + wma_handle->phy_caps.hw_mode_to_mac_cap_map = NULL; + WMA_LOGI("%s: hw_mode_to_mac_cap_map freed", __func__); + } + + if (wma_handle->phy_caps.each_hw_mode_cap) { + qdf_mem_free(wma_handle->phy_caps.each_hw_mode_cap); + wma_handle->phy_caps.each_hw_mode_cap = NULL; + WMA_LOGI("%s: each_hw_mode_cap freed", __func__); + } + + if (wma_handle->phy_caps.each_phy_cap_per_hwmode) { + qdf_mem_free(wma_handle->phy_caps.each_phy_cap_per_hwmode); + wma_handle->phy_caps.each_phy_cap_per_hwmode = NULL; + WMA_LOGI("%s: each_phy_cap_per_hwmode freed", __func__); + } + + if (wma_handle->phy_caps.each_phy_hal_reg_cap) { + qdf_mem_free(wma_handle->phy_caps.each_phy_hal_reg_cap); + wma_handle->phy_caps.each_phy_hal_reg_cap = NULL; + WMA_LOGI("%s: each_phy_hal_reg_cap freed", __func__); + } +} + +/** + * wma_close() - wma close function. + * cleanup resources attached with wma. + * @cds_ctx: cds context + * + * Return: 0 on success, QDF Error on failure + */ +QDF_STATUS wma_close(void *cds_ctx) +{ + tp_wma_handle wma_handle; + uint32_t idx; + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + + WMA_LOGD("%s: Enter", __func__); + + wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + + /* validate the wma_handle */ + if (NULL == wma_handle) { + WMA_LOGE("%s: Invalid wma handle", __func__); + return QDF_STATUS_E_INVAL; + } + + /* validate the wmi handle */ + if (NULL == wma_handle->wmi_handle) { + WMA_LOGP("%s: Invalid wmi handle", __func__); + return QDF_STATUS_E_INVAL; + } + + /* Free DBS list */ + if (wma_handle->hw_mode.hw_mode_list) { + qdf_mem_free(wma_handle->hw_mode.hw_mode_list); + wma_handle->hw_mode.hw_mode_list = NULL; + WMA_LOGI("%s: DBS list is freed", __func__); + } + wma_cleanup_dbs_phy_caps(wma_handle); + if (cds_get_conparam() != QDF_GLOBAL_FTM_MODE) { +#ifdef FEATURE_WLAN_SCAN_PNO + qdf_wake_lock_destroy(&wma_handle->pno_wake_lock); +#endif /* FEATURE_WLAN_SCAN_PNO */ +#ifdef FEATURE_WLAN_EXTSCAN + qdf_wake_lock_destroy(&wma_handle->extscan_wake_lock); +#endif /* FEATURE_WLAN_EXTSCAN */ + qdf_wake_lock_destroy(&wma_handle->wow_wake_lock); + } + + /* unregister Firmware debug log */ + qdf_status = dbglog_deinit(wma_handle->wmi_handle); + if (qdf_status != QDF_STATUS_SUCCESS) + WMA_LOGP("%s: dbglog_deinit failed", __func__); + + /* close the qdf events */ + qdf_event_destroy(&wma_handle->wma_ready_event); + qdf_status = qdf_mc_timer_destroy(&wma_handle->service_ready_ext_timer); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) + WMA_LOGP("%s: Failed to destroy service ready ext event timer", + __func__); + + qdf_event_destroy(&wma_handle->target_suspend); + qdf_event_destroy(&wma_handle->wma_resume_event); + qdf_event_destroy(&wma_handle->runtime_suspend); + qdf_event_destroy(&wma_handle->recovery_event); + qdf_event_destroy(&wma_handle->tx_frm_download_comp_event); + qdf_event_destroy(&wma_handle->tx_queue_empty_event); + wma_cleanup_vdev_resp_queue(wma_handle); + wma_cleanup_hold_req(wma_handle); + qdf_wake_lock_destroy(&wma_handle->wmi_cmd_rsp_wake_lock); + qdf_runtime_lock_deinit(&wma_handle->wmi_cmd_rsp_runtime_lock); + for (idx = 0; idx < wma_handle->num_mem_chunks; ++idx) { + qdf_mem_free_consistent(wma_handle->qdf_dev, + wma_handle->qdf_dev->dev, + wma_handle->mem_chunks[idx].len, + wma_handle->mem_chunks[idx].vaddr, + wma_handle->mem_chunks[idx].paddr, + qdf_get_dma_mem_context( + (&(wma_handle->mem_chunks[idx])), + memctx)); + } + +#if defined(QCA_WIFI_FTM) + /* Detach UTF and unregister the handler */ + if (cds_get_conparam() == QDF_GLOBAL_FTM_MODE) + wma_utf_detach(wma_handle); +#endif /* QCA_WIFI_FTM */ + + if (NULL != wma_handle->dfs_ic) { + wma_dfs_detach(wma_handle->dfs_ic); + wma_handle->dfs_ic = NULL; + } + + if (NULL != wma_handle->pGetRssiReq) { + qdf_mem_free(wma_handle->pGetRssiReq); + wma_handle->pGetRssiReq = NULL; + } + + if (wma_handle->link_stats_results) { + qdf_mem_free(wma_handle->link_stats_results); + wma_handle->link_stats_results = NULL; + } + + wma_ndp_unregister_all_event_handlers(wma_handle); + + if (WMI_SERVICE_IS_ENABLED(wma_handle->wmi_service_bitmap, + WMI_SERVICE_MGMT_TX_WMI)) { + wmi_desc_pool_deinit(wma_handle); + } + + if (wma_handle->peer_dbg) { + qdf_mem_free(wma_handle->peer_dbg); + wma_handle->peer_dbg = NULL; + } + + WMA_LOGD("%s: Exit", __func__); + return QDF_STATUS_SUCCESS; +} + +/** + * wma_update_fw_config() - update fw configuration + * @wma_handle: wma handle + * @tgt_cap: target capabality + * + * Return: none + */ +static void wma_update_fw_config(tp_wma_handle wma_handle, + struct wma_target_cap *tgt_cap) +{ + /* + * tgt_cap contains default target resource configuration + * which can be modified here, if required + */ + /* Override the no. of max fragments as per platform configuration */ + tgt_cap->wlan_resource_config.max_frag_entries = + QDF_MIN(QCA_OL_11AC_TX_MAX_FRAGS, + wma_handle->max_frag_entry); + wma_handle->max_frag_entry = + tgt_cap->wlan_resource_config.max_frag_entries; + + /* Update no. of maxWoWFilters depending on BPF service */ + if (WMI_SERVICE_IS_ENABLED(wma_handle->wmi_service_bitmap, + WMI_SERVICE_BPF_OFFLOAD)) + tgt_cap->wlan_resource_config.num_wow_filters = + WMA_STA_WOW_DEFAULT_PTRN_MAX; +} + +/** + * wma_alloc_host_mem_chunk() - allocate host memory + * @wma_handle: wma handle + * @req_id: request id + * @idx: index + * @num_units: number of units + * @unit_len: unit length + * + * allocate a chunk of memory at the index indicated and + * if allocation fail allocate smallest size possiblr and + * return number of units allocated. + * + * Return: number of units or 0 for error. + */ +static uint32_t wma_alloc_host_mem_chunk(tp_wma_handle wma_handle, + uint32_t req_id, uint32_t idx, + uint32_t num_units, uint32_t unit_len) +{ + qdf_dma_addr_t paddr; + if (!num_units || !unit_len) { + return 0; + } + wma_handle->mem_chunks[idx].vaddr = NULL; + /** reduce the requested allocation by half until allocation succeeds */ + while (wma_handle->mem_chunks[idx].vaddr == NULL && num_units) { + wma_handle->mem_chunks[idx].vaddr = + qdf_mem_alloc_consistent(wma_handle->qdf_dev, + wma_handle->qdf_dev->dev, + num_units * unit_len, + &paddr); + if (wma_handle->mem_chunks[idx].vaddr == NULL) { + num_units = (num_units >> 1);/* reduce length by half */ + } else { + wma_handle->mem_chunks[idx].paddr = paddr; + wma_handle->mem_chunks[idx].len = num_units * unit_len; + wma_handle->mem_chunks[idx].req_id = req_id; + } + } + return num_units; +} + +#define HOST_MEM_SIZE_UNIT 4 +/** + * wma_alloc_host_mem() - allocate amount of memory requested by FW. + * @wma_handle: wma handle + * @req_id: request id + * @num_units: number of units + * @unit_len: unit length + * + * Return: none + */ +static void wma_alloc_host_mem(tp_wma_handle wma_handle, uint32_t req_id, + uint32_t num_units, uint32_t unit_len) +{ + uint32_t remaining_units, allocated_units, idx; + + /* adjust the length to nearest multiple of unit size */ + unit_len = (unit_len + (HOST_MEM_SIZE_UNIT - 1)) & + (~(HOST_MEM_SIZE_UNIT - 1)); + idx = wma_handle->num_mem_chunks; + remaining_units = num_units; + while (remaining_units) { + allocated_units = wma_alloc_host_mem_chunk(wma_handle, req_id, + idx, remaining_units, + unit_len); + if (allocated_units == 0) { + WMA_LOGE("FAILED TO ALLOCATED memory unit len %d" + " units requested %d units allocated %d ", + unit_len, num_units, + (num_units - remaining_units)); + wma_handle->num_mem_chunks = idx; + break; + } + remaining_units -= allocated_units; + ++idx; + if (idx == MAX_MEM_CHUNKS) { + WMA_LOGE("RWACHED MAX CHUNK LIMIT for memory units %d" + " unit len %d requested by FW," + " only allocated %d ", + num_units, unit_len, + (num_units - remaining_units)); + wma_handle->num_mem_chunks = idx; + break; + } + } + wma_handle->num_mem_chunks = idx; +} + +/** + * wma_update_target_services() - update target services from wma handle + * @wh: wma handle + * @cfg: target services + * + * Return: none + */ +static inline void wma_update_target_services(tp_wma_handle wh, + struct wma_tgt_services *cfg) +{ + /* STA power save */ + cfg->sta_power_save = WMI_SERVICE_IS_ENABLED(wh->wmi_service_bitmap, + WMI_SERVICE_STA_PWRSAVE); + + /* Enable UAPSD */ + cfg->uapsd = WMI_SERVICE_IS_ENABLED(wh->wmi_service_bitmap, + WMI_SERVICE_AP_UAPSD); + + /* Update AP DFS service */ + cfg->ap_dfs = WMI_SERVICE_IS_ENABLED(wh->wmi_service_bitmap, + WMI_SERVICE_AP_DFS); + + /* Enable 11AC */ + cfg->en_11ac = WMI_SERVICE_IS_ENABLED(wh->wmi_service_bitmap, + WMI_SERVICE_11AC); + if (cfg->en_11ac) + g_fw_wlan_feat_caps |= (1 << DOT11AC); + + /* Proactive ARP response */ + g_fw_wlan_feat_caps |= (1 << WLAN_PERIODIC_TX_PTRN); + + /* Enable WOW */ + g_fw_wlan_feat_caps |= (1 << WOW); + + /* ARP offload */ + cfg->arp_offload = WMI_SERVICE_IS_ENABLED(wh->wmi_service_bitmap, + WMI_SERVICE_ARPNS_OFFLOAD); + + /* Adaptive early-rx */ + cfg->early_rx = WMI_SERVICE_IS_ENABLED(wh->wmi_service_bitmap, + WMI_SERVICE_EARLY_RX); +#ifdef FEATURE_WLAN_SCAN_PNO + /* PNO offload */ + if (WMI_SERVICE_IS_ENABLED(wh->wmi_service_bitmap, WMI_SERVICE_NLO)) + cfg->pno_offload = true; +#endif /* FEATURE_WLAN_SCAN_PNO */ + +#ifdef FEATURE_WLAN_EXTSCAN + if (WMI_SERVICE_IS_ENABLED(wh->wmi_service_bitmap, WMI_SERVICE_EXTSCAN)) { + g_fw_wlan_feat_caps |= (1 << EXTENDED_SCAN); + } +#endif /* FEATURE_WLAN_EXTSCAN */ + cfg->lte_coex_ant_share = WMI_SERVICE_IS_ENABLED(wh->wmi_service_bitmap, + WMI_SERVICE_LTE_ANT_SHARE_SUPPORT); +#ifdef FEATURE_WLAN_TDLS + /* Enable TDLS */ + if (WMI_SERVICE_IS_ENABLED(wh->wmi_service_bitmap, WMI_SERVICE_TDLS)) { + cfg->en_tdls = 1; + g_fw_wlan_feat_caps |= (1 << TDLS); + } + /* Enable advanced TDLS features */ + if (WMI_SERVICE_IS_ENABLED(wh->wmi_service_bitmap, + WMI_SERVICE_TDLS_OFFCHAN)) { + cfg->en_tdls_offchan = 1; + g_fw_wlan_feat_caps |= (1 << TDLS_OFF_CHANNEL); + } + + cfg->en_tdls_uapsd_buf_sta = + WMI_SERVICE_IS_ENABLED(wh->wmi_service_bitmap, + WMI_SERVICE_TDLS_UAPSD_BUFFER_STA); + cfg->en_tdls_uapsd_sleep_sta = + WMI_SERVICE_IS_ENABLED(wh->wmi_service_bitmap, + WMI_SERVICE_TDLS_UAPSD_SLEEP_STA); +#endif /* FEATURE_WLAN_TDLS */ + if (WMI_SERVICE_IS_ENABLED + (wh->wmi_service_bitmap, WMI_SERVICE_BEACON_OFFLOAD)) + cfg->beacon_offload = true; + if (WMI_SERVICE_IS_ENABLED + (wh->wmi_service_bitmap, WMI_SERVICE_STA_PMF_OFFLOAD)) + cfg->pmf_offload = true; +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + /* Enable Roam Offload */ + cfg->en_roam_offload = WMI_SERVICE_IS_ENABLED(wh->wmi_service_bitmap, + WMI_SERVICE_ROAM_HO_OFFLOAD); +#endif /* WLAN_FEATURE_ROAM_OFFLOAD */ +#ifdef WLAN_FEATURE_NAN + if (WMI_SERVICE_IS_ENABLED(wh->wmi_service_bitmap, WMI_SERVICE_NAN)) + g_fw_wlan_feat_caps |= (1 << NAN); +#endif /* WLAN_FEATURE_NAN */ + + if (WMI_SERVICE_IS_ENABLED(wh->wmi_service_bitmap, WMI_SERVICE_RTT)) + g_fw_wlan_feat_caps |= (1 << RTT); + + if (WMI_SERVICE_IS_ENABLED(wh->wmi_service_bitmap, + WMI_SERVICE_TX_MSDU_ID_NEW_PARTITION_SUPPORT)) { + ol_cfg_set_ipa_uc_tx_partition_base((ol_pdev_handle) + ((p_cds_contextType) wh->cds_context)->cfg_ctx, + HTT_TX_IPA_NEW_MSDU_ID_SPACE_BEGIN); + WMA_LOGI("%s: TX_MSDU_ID_NEW_PARTITION=%d", __func__, + HTT_TX_IPA_NEW_MSDU_ID_SPACE_BEGIN); + } else { + ol_cfg_set_ipa_uc_tx_partition_base((ol_pdev_handle) + ((p_cds_contextType) wh->cds_context)->cfg_ctx, + HTT_TX_IPA_MSDU_ID_SPACE_BEGIN); + WMA_LOGI("%s: TX_MSDU_ID_OLD_PARTITION=%d", __func__, + HTT_TX_IPA_MSDU_ID_SPACE_BEGIN); + } +} + +/** + * wma_update_target_ht_cap() - update ht capabality from wma handle + * @wh: wma handle + * @cfg: ht capabality + * + * Return: none + */ +static inline void wma_update_target_ht_cap(tp_wma_handle wh, + struct wma_tgt_ht_cap *cfg) +{ + /* RX STBC */ + cfg->ht_rx_stbc = !!(wh->ht_cap_info & WMI_HT_CAP_RX_STBC); + + /* TX STBC */ + cfg->ht_tx_stbc = !!(wh->ht_cap_info & WMI_HT_CAP_TX_STBC); + + /* MPDU density */ + cfg->mpdu_density = wh->ht_cap_info & WMI_HT_CAP_MPDU_DENSITY; + + /* HT RX LDPC */ + cfg->ht_rx_ldpc = !!(wh->ht_cap_info & WMI_HT_CAP_LDPC); + + /* HT SGI */ + cfg->ht_sgi_20 = !!(wh->ht_cap_info & WMI_HT_CAP_HT20_SGI); + + cfg->ht_sgi_40 = !!(wh->ht_cap_info & WMI_HT_CAP_HT40_SGI); + + /* RF chains */ + cfg->num_rf_chains = wh->num_rf_chains; + + WMA_LOGD("%s: ht_cap_info - %x ht_rx_stbc - %d, ht_tx_stbc - %d\n" + "mpdu_density - %d ht_rx_ldpc - %d ht_sgi_20 - %d\n" + "ht_sgi_40 - %d num_rf_chains - %d", __func__, wh->ht_cap_info, + cfg->ht_rx_stbc, cfg->ht_tx_stbc, cfg->mpdu_density, + cfg->ht_rx_ldpc, cfg->ht_sgi_20, cfg->ht_sgi_40, + cfg->num_rf_chains); + +} + +/** + * wma_update_target_vht_cap() - update vht capabality from wma handle + * @wh: wma handle + * @cfg: vht capabality + * + * Return: none + */ +static inline void wma_update_target_vht_cap(tp_wma_handle wh, + struct wma_tgt_vht_cap *cfg) +{ + + if (wh->vht_cap_info & WMI_VHT_CAP_MAX_MPDU_LEN_11454) + cfg->vht_max_mpdu = WMI_VHT_CAP_MAX_MPDU_LEN_11454; + else if (wh->vht_cap_info & WMI_VHT_CAP_MAX_MPDU_LEN_7935) + cfg->vht_max_mpdu = WMI_VHT_CAP_MAX_MPDU_LEN_7935; + else + cfg->vht_max_mpdu = 0; + + + if (wh->vht_cap_info & WMI_VHT_CAP_CH_WIDTH_80P80_160MHZ) { + cfg->supp_chan_width = 1 << eHT_CHANNEL_WIDTH_80P80MHZ; + cfg->supp_chan_width |= 1 << eHT_CHANNEL_WIDTH_160MHZ; + } else if (wh->vht_cap_info & WMI_VHT_CAP_CH_WIDTH_160MHZ) + cfg->supp_chan_width = 1 << eHT_CHANNEL_WIDTH_160MHZ; + else + cfg->supp_chan_width = 1 << eHT_CHANNEL_WIDTH_80MHZ; + + cfg->vht_rx_ldpc = wh->vht_cap_info & WMI_VHT_CAP_RX_LDPC; + + cfg->vht_short_gi_80 = wh->vht_cap_info & WMI_VHT_CAP_SGI_80MHZ; + cfg->vht_short_gi_160 = wh->vht_cap_info & WMI_VHT_CAP_SGI_160MHZ; + + cfg->vht_tx_stbc = wh->vht_cap_info & WMI_VHT_CAP_TX_STBC; + + cfg->vht_rx_stbc = (wh->vht_cap_info & WMI_VHT_CAP_RX_STBC_1SS) | + (wh->vht_cap_info & WMI_VHT_CAP_RX_STBC_2SS) | + (wh->vht_cap_info & WMI_VHT_CAP_RX_STBC_3SS) ; + + cfg->vht_max_ampdu_len_exp = (wh->vht_cap_info & + WMI_VHT_CAP_MAX_AMPDU_LEN_EXP) + >> WMI_VHT_CAP_MAX_AMPDU_LEN_EXP_SHIFT; + + cfg->vht_su_bformer = wh->vht_cap_info & WMI_VHT_CAP_SU_BFORMER; + + cfg->vht_su_bformee = wh->vht_cap_info & WMI_VHT_CAP_SU_BFORMEE; + + cfg->vht_mu_bformer = wh->vht_cap_info & WMI_VHT_CAP_MU_BFORMER; + + cfg->vht_mu_bformee = wh->vht_cap_info & WMI_VHT_CAP_MU_BFORMEE; + + cfg->vht_txop_ps = wh->vht_cap_info & WMI_VHT_CAP_TXOP_PS; + + WMA_LOGD("%s: max_mpdu %d supp_chan_width %x rx_ldpc %x\n" + "short_gi_80 %x tx_stbc %x rx_stbc %x txop_ps %x\n" + "su_bformee %x mu_bformee %x max_ampdu_len_exp %d", __func__, + cfg->vht_max_mpdu, cfg->supp_chan_width, cfg->vht_rx_ldpc, + cfg->vht_short_gi_80, cfg->vht_tx_stbc, cfg->vht_rx_stbc, + cfg->vht_txop_ps, cfg->vht_su_bformee, cfg->vht_mu_bformee, + cfg->vht_max_ampdu_len_exp); +} + +/** + * wma_derive_ext_ht_cap() - Derive HT caps based on given value + * @wma_handle: pointer to wma_handle + * @ht_cap: given pointer to HT caps which needs to be updated + * @tx_chain: given tx chainmask value + * @rx_chain: given rx chainmask value + * @value: new HT cap info provided in form of bitmask + * + * This function takes the value provided in form of bitmask and decodes + * it. After decoding, what ever value it gets, it takes the union(max) or + * intersection(min) with previously derived values. + * + * Return: none + * + */ +static void wma_derive_ext_ht_cap(tp_wma_handle wma_handle, + struct wma_tgt_ht_cap *ht_cap, uint32_t value, + uint32_t tx_chain, uint32_t rx_chain) +{ + struct wma_tgt_ht_cap tmp = {0}; + + if (NULL == wma_handle || NULL == ht_cap) + return; + + if (!qdf_mem_cmp(ht_cap, &tmp, sizeof(struct wma_tgt_ht_cap))) { + ht_cap->ht_rx_stbc = (!!(value & WMI_HT_CAP_RX_STBC)); + ht_cap->ht_tx_stbc = (!!(value & WMI_HT_CAP_TX_STBC)); + ht_cap->mpdu_density = (!!(value & WMI_HT_CAP_MPDU_DENSITY)); + ht_cap->ht_rx_ldpc = (!!(value & WMI_HT_CAP_RX_LDPC)); + ht_cap->ht_sgi_20 = (!!(value & WMI_HT_CAP_HT20_SGI)); + ht_cap->ht_sgi_40 = (!!(value & WMI_HT_CAP_HT40_SGI)); + ht_cap->num_rf_chains = + QDF_MAX(wma_get_num_of_setbits_from_bitmask(tx_chain), + wma_get_num_of_setbits_from_bitmask(rx_chain)); + } else { + ht_cap->ht_rx_stbc = QDF_MIN(ht_cap->ht_rx_stbc, + (!!(value & WMI_HT_CAP_RX_STBC))); + ht_cap->ht_tx_stbc = QDF_MAX(ht_cap->ht_tx_stbc, + (!!(value & WMI_HT_CAP_TX_STBC))); + ht_cap->mpdu_density = QDF_MIN(ht_cap->mpdu_density, + (!!(value & WMI_HT_CAP_MPDU_DENSITY))); + ht_cap->ht_rx_ldpc = QDF_MIN(ht_cap->ht_rx_ldpc, + (!!(value & WMI_HT_CAP_RX_LDPC))); + ht_cap->ht_sgi_20 = QDF_MIN(ht_cap->ht_sgi_20, + (!!(value & WMI_HT_CAP_HT20_SGI))); + ht_cap->ht_sgi_40 = QDF_MIN(ht_cap->ht_sgi_40, + (!!(value & WMI_HT_CAP_HT40_SGI))); + ht_cap->num_rf_chains = + QDF_MAX(ht_cap->num_rf_chains, + QDF_MAX(wma_get_num_of_setbits_from_bitmask( + tx_chain), + wma_get_num_of_setbits_from_bitmask( + rx_chain))); + } +} + +/** + * wma_update_target_ext_ht_cap() - Update HT caps with given extended cap + * @wma_handle: pointer to wma_handle + * @ht_cap: HT cap structure to be filled + * + * This function loop through each hardware mode and for each hardware mode + * again it loop through each MAC/PHY and pull the caps 2G and 5G specific + * HT caps and derives the final cap. + * + * Return: none + * + */ +static void wma_update_target_ext_ht_cap(tp_wma_handle wma_handle, + struct wma_tgt_ht_cap *ht_cap) +{ + int i, j = 0, max_mac; + uint32_t ht_2g, ht_5g; + struct wma_tgt_ht_cap tmp_ht_cap = {0}, tmp_cap = {0}; + struct extended_caps *phy_caps; + WMI_MAC_PHY_CAPABILITIES *mac_cap; + + /* + * for legacy device extended cap might not even come, so in that case + * don't overwrite legacy values + */ + if (!wma_handle || + (0 == wma_handle->phy_caps.num_hw_modes.num_hw_modes)) { + WMA_LOGI("%s: No extended HT cap for current SOC", __func__); + return; + } + + phy_caps = &wma_handle->phy_caps; + for (i = 0; i < phy_caps->num_hw_modes.num_hw_modes; i++) { + if (phy_caps->each_hw_mode_cap[i].phy_id_map == PHY1_PHY2) + max_mac = j + 2; + else + max_mac = j + 1; + for ( ; j < max_mac; j++) { + mac_cap = &phy_caps->each_phy_cap_per_hwmode[j]; + ht_2g = mac_cap->ht_cap_info_2G; + ht_5g = mac_cap->ht_cap_info_5G; + if (ht_2g) + wma_derive_ext_ht_cap(wma_handle, &tmp_ht_cap, + ht_2g, mac_cap->tx_chain_mask_2G, + mac_cap->rx_chain_mask_2G); + if (ht_5g) + wma_derive_ext_ht_cap(wma_handle, &tmp_ht_cap, + ht_5g, mac_cap->tx_chain_mask_5G, + mac_cap->rx_chain_mask_5G); + } + } + + if (qdf_mem_cmp(&tmp_cap, &tmp_ht_cap, + sizeof(struct wma_tgt_ht_cap))) { + qdf_mem_copy(ht_cap, &tmp_ht_cap, + sizeof(struct wma_tgt_ht_cap)); + } + + WMA_LOGI("%s: [ext ht cap] ht_rx_stbc - %d, ht_tx_stbc - %d\n" + "mpdu_density - %d ht_rx_ldpc - %d ht_sgi_20 - %d\n" + "ht_sgi_40 - %d num_rf_chains - %d", __func__, + ht_cap->ht_rx_stbc, ht_cap->ht_tx_stbc, + ht_cap->mpdu_density, ht_cap->ht_rx_ldpc, + ht_cap->ht_sgi_20, ht_cap->ht_sgi_40, + ht_cap->num_rf_chains); +} + +/** + * wma_derive_ext_vht_cap() - Derive VHT caps based on given value + * @wma_handle: pointer to wma_handle + * @vht_cap: pointer to given VHT caps to be filled + * @value: new VHT cap info provided in form of bitmask + * + * This function takes the value provided in form of bitmask and decodes + * it. After decoding, what ever value it gets, it takes the union(max) or + * intersection(min) with previously derived values. + * + * Return: none + * + */ +static void wma_derive_ext_vht_cap(t_wma_handle *wma_handle, + struct wma_tgt_vht_cap *vht_cap, uint32_t value) +{ + struct wma_tgt_vht_cap tmp_cap = {0}; + uint32_t tmp = 0; + + if (NULL == wma_handle || NULL == vht_cap) + return; + + if (!qdf_mem_cmp(vht_cap, &tmp_cap, + sizeof(struct wma_tgt_vht_cap))) { + if (value & WMI_VHT_CAP_MAX_MPDU_LEN_11454) + vht_cap->vht_max_mpdu = WMI_VHT_CAP_MAX_MPDU_LEN_11454; + else if (value & WMI_VHT_CAP_MAX_MPDU_LEN_7935) + vht_cap->vht_max_mpdu = WMI_VHT_CAP_MAX_MPDU_LEN_7935; + else + vht_cap->vht_max_mpdu = 0; + + if (value & WMI_VHT_CAP_CH_WIDTH_80P80_160MHZ) { + vht_cap->supp_chan_width = + 1 << eHT_CHANNEL_WIDTH_80P80MHZ; + vht_cap->supp_chan_width |= + 1 << eHT_CHANNEL_WIDTH_160MHZ; + } else if (value & WMI_VHT_CAP_CH_WIDTH_160MHZ) { + vht_cap->supp_chan_width = + 1 << eHT_CHANNEL_WIDTH_160MHZ; + } else { + vht_cap->supp_chan_width = 1 << eHT_CHANNEL_WIDTH_80MHZ; + } + vht_cap->vht_rx_ldpc = value & WMI_VHT_CAP_RX_LDPC; + vht_cap->vht_short_gi_80 = value & WMI_VHT_CAP_SGI_80MHZ; + vht_cap->vht_short_gi_160 = value & WMI_VHT_CAP_SGI_160MHZ; + vht_cap->vht_tx_stbc = value & WMI_VHT_CAP_TX_STBC; + vht_cap->vht_rx_stbc = + (value & WMI_VHT_CAP_RX_STBC_1SS) | + (value & WMI_VHT_CAP_RX_STBC_2SS) | + (value & WMI_VHT_CAP_RX_STBC_3SS); + vht_cap->vht_max_ampdu_len_exp = + (value & WMI_VHT_CAP_MAX_AMPDU_LEN_EXP) >> + WMI_VHT_CAP_MAX_AMPDU_LEN_EXP_SHIFT; + vht_cap->vht_su_bformer = value & WMI_VHT_CAP_SU_BFORMER; + vht_cap->vht_su_bformee = value & WMI_VHT_CAP_SU_BFORMEE; + vht_cap->vht_mu_bformer = value & WMI_VHT_CAP_MU_BFORMER; + vht_cap->vht_mu_bformee = value & WMI_VHT_CAP_MU_BFORMEE; + vht_cap->vht_txop_ps = value & WMI_VHT_CAP_TXOP_PS; + } else { + if (value & WMI_VHT_CAP_MAX_MPDU_LEN_11454) + tmp = WMI_VHT_CAP_MAX_MPDU_LEN_11454; + else if (value & WMI_VHT_CAP_MAX_MPDU_LEN_7935) + tmp = WMI_VHT_CAP_MAX_MPDU_LEN_7935; + else + tmp = 0; + vht_cap->vht_max_mpdu = QDF_MIN(vht_cap->vht_max_mpdu, tmp); + + if ((value & WMI_VHT_CAP_CH_WIDTH_80P80_160MHZ)) { + tmp = (1 << eHT_CHANNEL_WIDTH_80P80MHZ) | + (1 << eHT_CHANNEL_WIDTH_160MHZ); + } else if (value & WMI_VHT_CAP_CH_WIDTH_160MHZ) { + tmp = 1 << eHT_CHANNEL_WIDTH_160MHZ; + } else { + tmp = 1 << eHT_CHANNEL_WIDTH_80MHZ; + } + vht_cap->supp_chan_width = + QDF_MAX(vht_cap->supp_chan_width, tmp); + vht_cap->vht_rx_ldpc = QDF_MIN(vht_cap->vht_rx_ldpc, + value & WMI_VHT_CAP_RX_LDPC); + vht_cap->vht_short_gi_80 = QDF_MAX(vht_cap->vht_short_gi_80, + value & WMI_VHT_CAP_SGI_80MHZ); + vht_cap->vht_short_gi_160 = QDF_MAX(vht_cap->vht_short_gi_160, + value & WMI_VHT_CAP_SGI_160MHZ); + vht_cap->vht_tx_stbc = QDF_MAX(vht_cap->vht_tx_stbc, + value & WMI_VHT_CAP_TX_STBC); + vht_cap->vht_rx_stbc = QDF_MIN(vht_cap->vht_rx_stbc, + (value & WMI_VHT_CAP_RX_STBC_1SS) | + (value & WMI_VHT_CAP_RX_STBC_2SS) | + (value & WMI_VHT_CAP_RX_STBC_3SS)); + vht_cap->vht_max_ampdu_len_exp = + QDF_MIN(vht_cap->vht_max_ampdu_len_exp, + (value & WMI_VHT_CAP_MAX_AMPDU_LEN_EXP) >> + WMI_VHT_CAP_MAX_AMPDU_LEN_EXP_SHIFT); + vht_cap->vht_su_bformer = QDF_MAX(vht_cap->vht_su_bformer, + value & WMI_VHT_CAP_SU_BFORMER); + vht_cap->vht_su_bformee = QDF_MAX(vht_cap->vht_su_bformee, + value & WMI_VHT_CAP_SU_BFORMEE); + vht_cap->vht_mu_bformer = QDF_MAX(vht_cap->vht_mu_bformer, + value & WMI_VHT_CAP_MU_BFORMER); + vht_cap->vht_mu_bformee = QDF_MAX(vht_cap->vht_mu_bformee, + value & WMI_VHT_CAP_MU_BFORMEE); + vht_cap->vht_txop_ps = QDF_MIN(vht_cap->vht_txop_ps, + value & WMI_VHT_CAP_TXOP_PS); + } +} + +/** + * wma_update_target_ext_vht_cap() - Update VHT caps with given extended cap + * @wma_handle: pointer to wma_handle + * @vht_cap: VHT cap structure to be filled + * + * This function loop through each hardware mode and for each hardware mode + * again it loop through each MAC/PHY and pull the caps 2G and 5G specific + * VHT caps and derives the final cap. + * + * Return: none + * + */ +static void wma_update_target_ext_vht_cap(t_wma_handle *wma_handle, + struct wma_tgt_vht_cap *vht_cap) +{ + int i, j = 0, max_mac; + uint32_t vht_cap_info_2g, vht_cap_info_5g; + struct wma_tgt_vht_cap tmp_vht_cap = {0}, tmp_cap = {0}; + struct extended_caps *phy_caps; + WMI_MAC_PHY_CAPABILITIES *mac_cap; + + /* + * for legacy device extended cap might not even come, so in that case + * don't overwrite legacy values + */ + if (!wma_handle || + (0 == wma_handle->phy_caps.num_hw_modes.num_hw_modes)) { + WMA_LOGI("%s: No extended VHT cap for current SOC", __func__); + return; + } + + phy_caps = &wma_handle->phy_caps; + for (i = 0; i < phy_caps->num_hw_modes.num_hw_modes; i++) { + if (phy_caps->each_hw_mode_cap[i].phy_id_map == PHY1_PHY2) + max_mac = j + 2; + else + max_mac = j + 1; + for ( ; j < max_mac; j++) { + mac_cap = &phy_caps->each_phy_cap_per_hwmode[j]; + vht_cap_info_2g = mac_cap->vht_cap_info_2G; + vht_cap_info_5g = mac_cap->vht_cap_info_5G; + if (vht_cap_info_2g) + wma_derive_ext_vht_cap(wma_handle, &tmp_vht_cap, + vht_cap_info_2g); + if (vht_cap_info_5g) + wma_derive_ext_vht_cap(wma_handle, &tmp_vht_cap, + vht_cap_info_5g); + } + } + + if (qdf_mem_cmp(&tmp_cap, &tmp_vht_cap, + sizeof(struct wma_tgt_vht_cap))) { + qdf_mem_copy(vht_cap, &tmp_vht_cap, + sizeof(struct wma_tgt_vht_cap)); + } + + WMA_LOGI("%s: [ext vhtcap] max_mpdu %d supp_chan_width %x rx_ldpc %x\n" + "short_gi_80 %x tx_stbc %x rx_stbc %x txop_ps %x\n" + "su_bformee %x mu_bformee %x max_ampdu_len_exp %d", __func__, + vht_cap->vht_max_mpdu, vht_cap->supp_chan_width, + vht_cap->vht_rx_ldpc, vht_cap->vht_short_gi_80, + vht_cap->vht_tx_stbc, vht_cap->vht_rx_stbc, + vht_cap->vht_txop_ps, vht_cap->vht_su_bformee, + vht_cap->vht_mu_bformee, vht_cap->vht_max_ampdu_len_exp); +} + +/** + * wma_update_ra_rate_limit() - update wma config + * @wma_handle: wma handle + * @cfg: target config + * + * Return: none + */ +#ifdef FEATURE_WLAN_RA_FILTERING +static void wma_update_ra_rate_limit(tp_wma_handle wma_handle, + struct wma_tgt_cfg *cfg) +{ + cfg->is_ra_rate_limit_enabled = wma_handle->IsRArateLimitEnabled; +} +#else +static void wma_update_ra_rate_limit(tp_wma_handle wma_handle, + struct wma_tgt_cfg *cfg) +{ +} +#endif + +/** + * wma_update_hdd_cfg() - update HDD config + * @wma_handle: wma handle + * + * Return: none + */ +static void wma_update_hdd_cfg(tp_wma_handle wma_handle) +{ + struct wma_tgt_cfg tgt_cfg; + void *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + + qdf_mem_zero(&tgt_cfg, sizeof(struct wma_tgt_cfg)); + + tgt_cfg.sub_20_support = wma_handle->sub_20_support; + tgt_cfg.reg_domain = wma_handle->reg_cap.eeprom_rd; + tgt_cfg.eeprom_rd_ext = wma_handle->reg_cap.eeprom_rd_ext; + + switch (wma_handle->phy_capability) { + case WMI_11G_CAPABILITY: + case WMI_11NG_CAPABILITY: + tgt_cfg.band_cap = eCSR_BAND_24; + break; + case WMI_11A_CAPABILITY: + case WMI_11NA_CAPABILITY: + case WMI_11AC_CAPABILITY: + tgt_cfg.band_cap = eCSR_BAND_5G; + break; + case WMI_11AG_CAPABILITY: + case WMI_11NAG_CAPABILITY: + default: + tgt_cfg.band_cap = eCSR_BAND_ALL; + } + + tgt_cfg.max_intf_count = wma_handle->wlan_resource_config.num_vdevs; + + qdf_mem_copy(tgt_cfg.hw_macaddr.bytes, wma_handle->hwaddr, + ATH_MAC_LEN); + + wma_update_target_services(wma_handle, &tgt_cfg.services); + wma_update_target_ht_cap(wma_handle, &tgt_cfg.ht_cap); + wma_update_target_vht_cap(wma_handle, &tgt_cfg.vht_cap); + /* + * This will overwrite the structure filled by wma_update_target_ht_cap + * and wma_update_target_vht_cap APIs. + */ + wma_update_target_ext_ht_cap(wma_handle, &tgt_cfg.ht_cap); + wma_update_target_ext_vht_cap(wma_handle, &tgt_cfg.vht_cap); + + tgt_cfg.target_fw_version = wma_handle->target_fw_version; + tgt_cfg.target_fw_vers_ext = wma_handle->target_fw_vers_ext; +#ifdef WLAN_FEATURE_LPSS + tgt_cfg.lpss_support = wma_handle->lpss_support; +#endif /* WLAN_FEATURE_LPSS */ + tgt_cfg.ap_arpns_support = wma_handle->ap_arpns_support; + tgt_cfg.bpf_enabled = wma_handle->bpf_enabled; + tgt_cfg.rcpi_enabled = wma_handle->rcpi_enabled; + wma_update_ra_rate_limit(wma_handle, &tgt_cfg); + tgt_cfg.fine_time_measurement_cap = + wma_handle->fine_time_measurement_cap; + tgt_cfg.wmi_max_len = wmi_get_max_msg_len(wma_handle->wmi_handle) + - WMI_TLV_HEADROOM; + wma_setup_egap_support(&tgt_cfg, wma_handle); + tgt_cfg.fw_mem_dump_enabled = wma_handle->fw_mem_dump_enabled; + tgt_cfg.tx_bfee_8ss_enabled = wma_handle->tx_bfee_8ss_enabled; + wma_update_hdd_cfg_ndp(wma_handle, &tgt_cfg); + wma_handle->tgt_cfg_update_cb(hdd_ctx, &tgt_cfg); +} + +/** + * wma_setup_wmi_init_msg() - fill wmi init message buffer + * @wma_handle: wma handle + * @ev: ready event fixed params + * @param_buf: redy event TLVs + * @len: buffer length + * + * Return: wmi buffer or NULL for error + */ +static int wma_setup_wmi_init_msg(tp_wma_handle wma_handle, + wmi_service_ready_event_fixed_param *ev, + WMI_SERVICE_READY_EVENTID_param_tlvs *param_buf) +{ + wlan_host_mem_req *ev_mem_reqs; + wmi_abi_version my_vers; + wmi_abi_version host_abi_vers; + int num_whitelist; + uint16_t idx; + uint32_t num_units; + + ev_mem_reqs = param_buf->mem_reqs; + + /* allocate memory requested by FW */ + if (ev->num_mem_reqs > WMI_MAX_MEM_REQS) { + QDF_ASSERT(0); + return QDF_STATUS_E_NOMEM; + } + + for (idx = 0; idx < ev->num_mem_reqs; ++idx) { + num_units = ev_mem_reqs[idx].num_units; + if (ev_mem_reqs[idx].num_unit_info & NUM_UNITS_IS_NUM_PEERS) { + /* + * number of units to allocate is number + * of peers, 1 extra for self peer on + * target. this needs to be fied, host + * and target can get out of sync + */ + num_units = wma_handle->wlan_resource_config.num_peers + 1; + } + WMA_LOGD + ("idx %d req %d num_units %d num_unit_info %d unit size %d actual units %d ", + idx, ev_mem_reqs[idx].req_id, + ev_mem_reqs[idx].num_units, + ev_mem_reqs[idx].num_unit_info, + ev_mem_reqs[idx].unit_size, num_units); + wma_alloc_host_mem(wma_handle, ev_mem_reqs[idx].req_id, + num_units, ev_mem_reqs[idx].unit_size); + } + + qdf_mem_copy(&wma_handle->target_abi_vers, + ¶m_buf->fixed_param->fw_abi_vers, + sizeof(wmi_abi_version)); + num_whitelist = sizeof(version_whitelist) / + sizeof(wmi_whitelist_version_info); + my_vers.abi_version_0 = WMI_ABI_VERSION_0; + my_vers.abi_version_1 = WMI_ABI_VERSION_1; + my_vers.abi_version_ns_0 = WMI_ABI_VERSION_NS_0; + my_vers.abi_version_ns_1 = WMI_ABI_VERSION_NS_1; + my_vers.abi_version_ns_2 = WMI_ABI_VERSION_NS_2; + my_vers.abi_version_ns_3 = WMI_ABI_VERSION_NS_3; + + wmi_cmp_and_set_abi_version(num_whitelist, version_whitelist, + &my_vers, + ¶m_buf->fixed_param->fw_abi_vers, + &host_abi_vers); + + qdf_mem_copy(&wma_handle->final_abi_vers, &host_abi_vers, + sizeof(wmi_abi_version)); + + return QDF_STATUS_SUCCESS; +} + +/** + * wma_dump_dbs_hw_mode() - Print the DBS HW modes + * @wma_handle: WMA handle + * + * Prints the DBS HW modes sent by the FW as part + * of WMI ready event + * + * Return: None + */ +static void wma_dump_dbs_hw_mode(tp_wma_handle wma_handle) +{ + uint32_t i, param; + + if (!wma_handle) { + WMA_LOGE("%s: Invalid WMA handle", __func__); + return; + } + + for (i = 0; i < wma_handle->num_dbs_hw_modes; i++) { + param = wma_handle->hw_mode.hw_mode_list[i]; + WMA_LOGD("%s:[%d]-MAC0: tx_ss:%d rx_ss:%d bw_idx:%d", + __func__, i, + WMA_HW_MODE_MAC0_TX_STREAMS_GET(param), + WMA_HW_MODE_MAC0_RX_STREAMS_GET(param), + WMA_HW_MODE_MAC0_BANDWIDTH_GET(param)); + WMA_LOGD("%s:[%d]-MAC1: tx_ss:%d rx_ss:%d bw_idx:%d", + __func__, i, + WMA_HW_MODE_MAC1_TX_STREAMS_GET(param), + WMA_HW_MODE_MAC1_RX_STREAMS_GET(param), + WMA_HW_MODE_MAC1_BANDWIDTH_GET(param)); + WMA_LOGD("%s:[%d] DBS:%d SBS:%d", __func__, i, + WMA_HW_MODE_DBS_MODE_GET(param), + WMA_HW_MODE_SBS_MODE_GET(param)); + } +} + +/** + * wma_init_scan_fw_mode_config() - Initialize scan/fw mode config + * @wma_handle: WMA handle + * @scan_config: Scam mode configuration + * @fw_config: FW mode configuration + * + * Enables all the valid bits of concurrent_scan_config_bits and + * fw_mode_config_bits. + * + * Return: None + */ +static void wma_init_scan_fw_mode_config(tp_wma_handle wma_handle, + uint32_t scan_config, + uint32_t fw_config) +{ + tpAniSirGlobal mac = cds_get_context(QDF_MODULE_ID_PE); + + WMA_LOGD("%s: Enter", __func__); + + if (!mac) { + WMA_LOGE("%s: Invalid mac handle", __func__); + return; + } + + if (!wma_handle) { + WMA_LOGE("%s: Invalid WMA handle", __func__); + return; + } + + wma_handle->dual_mac_cfg.cur_scan_config = 0; + wma_handle->dual_mac_cfg.cur_fw_mode_config = 0; + + /* If dual mac features are disabled in the INI, we + * need not proceed further + */ + if (mac->dual_mac_feature_disable) { + WMA_LOGE("%s: Disabling dual mac capabilities", __func__); + /* All capabilites are initialized to 0. We can return */ + goto done; + } + + /* Initialize concurrent_scan_config_bits with default FW value */ + WMI_DBS_CONC_SCAN_CFG_DBS_SCAN_SET( + wma_handle->dual_mac_cfg.cur_scan_config, + WMI_DBS_CONC_SCAN_CFG_DBS_SCAN_GET(scan_config)); + WMI_DBS_CONC_SCAN_CFG_AGILE_SCAN_SET( + wma_handle->dual_mac_cfg.cur_scan_config, + WMI_DBS_CONC_SCAN_CFG_AGILE_SCAN_GET(scan_config)); + WMI_DBS_CONC_SCAN_CFG_AGILE_DFS_SCAN_SET( + wma_handle->dual_mac_cfg.cur_scan_config, + WMI_DBS_CONC_SCAN_CFG_AGILE_DFS_SCAN_GET(scan_config)); + + /* Initialize fw_mode_config_bits with default FW value */ + WMI_DBS_FW_MODE_CFG_DBS_SET( + wma_handle->dual_mac_cfg.cur_fw_mode_config, + WMI_DBS_FW_MODE_CFG_DBS_GET(fw_config)); + WMI_DBS_FW_MODE_CFG_AGILE_DFS_SET( + wma_handle->dual_mac_cfg.cur_fw_mode_config, + WMI_DBS_FW_MODE_CFG_AGILE_DFS_GET(fw_config)); +done: + /* Initialize the previous scan/fw mode config */ + wma_handle->dual_mac_cfg.prev_scan_config = + wma_handle->dual_mac_cfg.cur_scan_config; + wma_handle->dual_mac_cfg.prev_fw_mode_config = + wma_handle->dual_mac_cfg.cur_fw_mode_config; + + WMA_LOGD("%s: cur_scan_config:%x cur_fw_mode_config:%x", + __func__, + wma_handle->dual_mac_cfg.cur_scan_config, + wma_handle->dual_mac_cfg.cur_fw_mode_config); +} + +/** + * wma_update_ra_limit() - update ra limit based on bpf filter + * enabled or not + * @handle: wma handle + * + * Return: none + */ +#ifdef FEATURE_WLAN_RA_FILTERING +static void wma_update_ra_limit(tp_wma_handle wma_handle) +{ + if (wma_handle->bpf_enabled) + wma_handle->IsRArateLimitEnabled = false; +} +#else +static void wma_update_ra__limit(tp_wma_handle handle) +{ +} +#endif + +/** + * wma_rx_service_ready_event() - event handler to process + * wmi rx sevice ready event. + * @handle: wma handle + * @cmd_param_info: command params info + * + * Return: none + */ +int wma_rx_service_ready_event(void *handle, uint8_t *cmd_param_info, + uint32_t length) +{ + tp_wma_handle wma_handle = (tp_wma_handle) handle; + struct wma_target_cap target_cap; + WMI_SERVICE_READY_EVENTID_param_tlvs *param_buf; + wmi_service_ready_event_fixed_param *ev; + int status; + uint32_t *ev_wlan_dbs_hw_mode_list; + QDF_STATUS ret; + + WMA_LOGD("%s: Enter", __func__); + + param_buf = (WMI_SERVICE_READY_EVENTID_param_tlvs *) cmd_param_info; + if (!(handle && param_buf)) { + WMA_LOGP("%s: Invalid arguments", __func__); + return -EINVAL; + } + + ev = param_buf->fixed_param; + if (!ev) { + WMA_LOGP("%s: Invalid buffer", __func__); + return -EINVAL; + } + + WMA_LOGD("WMA <-- WMI_SERVICE_READY_EVENTID"); + + wma_handle->num_dbs_hw_modes = ev->num_dbs_hw_modes; + ev_wlan_dbs_hw_mode_list = param_buf->wlan_dbs_hw_mode_list; + wma_handle->hw_mode.hw_mode_list = + qdf_mem_malloc(sizeof(*wma_handle->hw_mode.hw_mode_list) * + wma_handle->num_dbs_hw_modes); + if (!wma_handle->hw_mode.hw_mode_list) { + WMA_LOGE("%s: Memory allocation failed for DBS", __func__); + /* Continuing with the rest of the processing */ + } + qdf_mem_copy(wma_handle->hw_mode.hw_mode_list, + ev_wlan_dbs_hw_mode_list, + (sizeof(*wma_handle->hw_mode.hw_mode_list) * + wma_handle->num_dbs_hw_modes)); + + wma_dump_dbs_hw_mode(wma_handle); + + /* Initializes the fw_mode and scan_config to zero. + * If ext service ready event is present it will set + * the actual values of these two params. + * This is to ensure that no garbage values would be + * present in the absence of ext service ready event. + */ + wma_init_scan_fw_mode_config(wma_handle, 0, 0); + + wma_handle->phy_capability = ev->phy_capability; + wma_handle->max_frag_entry = ev->max_frag_entry; + wma_handle->num_rf_chains = ev->num_rf_chains; + qdf_mem_copy(&wma_handle->reg_cap, param_buf->hal_reg_capabilities, + sizeof(HAL_REG_CAPABILITIES)); + wma_handle->ht_cap_info = ev->ht_cap_info; + wma_handle->vht_cap_info = ev->vht_cap_info; + wma_handle->vht_supp_mcs = ev->vht_supp_mcs; + wma_handle->num_rf_chains = ev->num_rf_chains; + + wma_handle->target_fw_version = ev->fw_build_vers; + wma_handle->new_hw_mode_index = ev->default_dbs_hw_mode_index; + wma_handle->fine_time_measurement_cap = ev->wmi_fw_sub_feat_caps; + + WMA_LOGD("%s: Firmware default hw mode index : %d", + __func__, ev->default_dbs_hw_mode_index); + WMA_LOGE("%s: Firmware build version : %08x", + __func__, ev->fw_build_vers); + WMA_LOGD(FL("FW fine time meas cap: 0x%x"), ev->wmi_fw_sub_feat_caps); + + if (ev->hw_bd_id) { + wma_handle->hw_bd_id = ev->hw_bd_id; + qdf_mem_copy(wma_handle->hw_bd_info, + ev->hw_bd_info, sizeof(ev->hw_bd_info)); + + WMA_LOGE("%s: Board version: %x.%x", + __func__, + wma_handle->hw_bd_info[0], wma_handle->hw_bd_info[1]); + } else { + wma_handle->hw_bd_id = 0; + qdf_mem_zero(wma_handle->hw_bd_info, + sizeof(wma_handle->hw_bd_info)); + WMA_LOGE("%s: Board version is unknown!", __func__); + } + wma_handle->dfs_ic->dfs_hw_bd_id = wma_handle->hw_bd_id; + + /* TODO: Recheck below line to dump service ready event */ + /* dbg_print_wmi_service_11ac(ev); */ + + /* wmi service is ready */ + qdf_mem_copy(wma_handle->wmi_service_bitmap, + param_buf->wmi_service_bitmap, + sizeof(wma_handle->wmi_service_bitmap)); + + ol_tx_set_is_mgmt_over_wmi_enabled( + WMI_SERVICE_IS_ENABLED(wma_handle->wmi_service_bitmap, + WMI_SERVICE_MGMT_TX_WMI)); + ol_tx_set_desc_global_pool_size(ev->num_msdu_desc); + + /* SWBA event handler for beacon transmission */ + status = wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_HOST_SWBA_EVENTID, + wma_beacon_swba_handler, + WMA_RX_SERIALIZER_CTX); + if (status) { + WMA_LOGE("Failed to register swba beacon event cb"); + return -EINVAL; + } +#ifdef WLAN_FEATURE_LPSS + wma_handle->lpss_support = + WMI_SERVICE_IS_ENABLED(wma_handle->wmi_service_bitmap, + WMI_SERVICE_LPASS); +#endif /* WLAN_FEATURE_LPSS */ + + /* + * This Service bit is added to check for ARP/NS Offload + * support for LL/HL targets + */ + wma_handle->ap_arpns_support = + WMI_SERVICE_IS_ENABLED(wma_handle->wmi_service_bitmap, + WMI_SERVICE_AP_ARPNS_OFFLOAD); + + wma_handle->bpf_enabled = (wma_handle->bpf_packet_filter_enable && + WMI_SERVICE_IS_ENABLED(wma_handle->wmi_service_bitmap, + WMI_SERVICE_BPF_OFFLOAD)); + wma_update_ra_limit(wma_handle); + if (WMI_SERVICE_IS_ENABLED(wma_handle->wmi_service_bitmap, + WMI_SERVICE_CSA_OFFLOAD)) { + WMA_LOGD("%s: FW support CSA offload capability", __func__); + status = + wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_CSA_HANDLING_EVENTID, + wma_csa_offload_handler, + WMA_RX_SERIALIZER_CTX); + if (status) { + WMA_LOGE("Failed to register CSA offload event cb"); + return -EINVAL; + } + } + + if (WMI_SERVICE_IS_ENABLED(wma_handle->wmi_service_bitmap, + WMI_SERVICE_MGMT_TX_WMI)) { + WMA_LOGE("Firmware supports management TX over WMI,use WMI interface instead of HTT for management Tx"); + status = wmi_desc_pool_init(wma_handle, WMI_DESC_POOL_MAX); + if (status) { + WMA_LOGE("Failed to initialize wmi descriptor pool"); + return -EINVAL; + } + /* + * Register Tx completion event handler for MGMT Tx over WMI + * case + */ + status = wmi_unified_register_event_handler( + wma_handle->wmi_handle, + WMI_MGMT_TX_COMPLETION_EVENTID, + wma_mgmt_tx_completion_handler, + WMA_RX_SERIALIZER_CTX); + if (status) { + WMA_LOGE("Failed to register MGMT over WMI completion handler"); + return -EINVAL; + } + + status = wmi_unified_register_event_handler( + wma_handle->wmi_handle, + WMI_MGMT_TX_BUNDLE_COMPLETION_EVENTID, + wma_mgmt_tx_bundle_completion_handler, + WMA_RX_SERIALIZER_CTX); + if (status) { + WMA_LOGE("Failed to register MGMT over WMI completion handler"); + return -EINVAL; + } + + } else { + WMA_LOGE("FW doesnot support WMI_SERVICE_MGMT_TX_WMI, Use HTT interface for Management Tx"); + } +#ifdef WLAN_FEATURE_GTK_OFFLOAD + if (WMI_SERVICE_IS_ENABLED(wma_handle->wmi_service_bitmap, + WMI_SERVICE_GTK_OFFLOAD)) { + status = + wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_GTK_OFFLOAD_STATUS_EVENTID, + wma_gtk_offload_status_event, + WMA_RX_SERIALIZER_CTX); + if (status) { + WMA_LOGE("Failed to register GTK offload event cb"); + return -EINVAL; + } + } +#endif /* WLAN_FEATURE_GTK_OFFLOAD */ + + if (WMI_SERVICE_IS_ENABLED(wma_handle->wmi_service_bitmap, + WMI_SERVICE_FW_MEM_DUMP_SUPPORT)) + wma_handle->fw_mem_dump_enabled = true; + else + wma_handle->fw_mem_dump_enabled = false; + + status = wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_P2P_NOA_EVENTID, + wma_p2p_noa_event_handler, + WMA_RX_SERIALIZER_CTX); + if (status) { + WMA_LOGE("Failed to register WMI_P2P_NOA_EVENTID callback"); + return -EINVAL; + } + status = wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_TBTTOFFSET_UPDATE_EVENTID, + wma_tbttoffset_update_event_handler, + WMA_RX_SERIALIZER_CTX); + if (status) { + WMA_LOGE + ("Failed to register WMI_TBTTOFFSET_UPDATE_EVENTID callback"); + return -EINVAL; + } + + if (WMI_SERVICE_IS_ENABLED(wma_handle->wmi_service_bitmap, + WMI_SERVICE_RCPI_SUPPORT)) { + /* register for rcpi response event */ + status = wmi_unified_register_event_handler( + wma_handle->wmi_handle, + WMI_UPDATE_RCPI_EVENTID, + wma_rcpi_event_handler, + WMA_RX_SERIALIZER_CTX); + if (status) { + WMA_LOGE("Failed to register RCPI event handler"); + return -EINVAL; + } + wma_handle->rcpi_enabled = true; + } + + /* mac_id is replaced with pdev_id in converged firmware to have + * multi-radio support. In order to maintain backward compatibility + * with old fw, host needs to check WMI_SERVICE_DEPRECATED_REPLACE + * in service bitmap from FW and host needs to set use_pdev_id in + * wmi_resource_config to true. If WMI_SERVICE_DEPRECATED_REPLACE + * service is not set, then host shall not expect MAC ID from FW in + * VDEV START RESPONSE event and host shall use PDEV ID. + */ + if (WMI_SERVICE_IS_ENABLED(wma_handle->wmi_service_bitmap, + WMI_SERVICE_DEPRECATED_REPLACE)) + wma_handle->wlan_resource_config.use_pdev_id = true; + else + wma_handle->wlan_resource_config.use_pdev_id = false; + + /* register the Enhanced Green AP event handler */ + wma_register_egap_event_handle(wma_handle); + + /* Initialize the log supported event handler */ + status = wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_DIAG_EVENT_LOG_SUPPORTED_EVENTID, + wma_log_supported_evt_handler, + WMA_RX_SERIALIZER_CTX); + if (status != QDF_STATUS_SUCCESS) { + WMA_LOGE("Failed to register log supported event cb"); + return -EINVAL; + } + + ol_tx_mark_first_wakeup_packet( + WMI_SERVICE_IS_ENABLED(wma_handle->wmi_service_bitmap, + WMI_SERVICE_MARK_FIRST_WAKEUP_PACKET)); + + wma_handle->nan_datapath_enabled = + WMI_SERVICE_IS_ENABLED(wma_handle->wmi_service_bitmap, + WMI_SERVICE_NAN_DATA); + qdf_mem_copy(target_cap.wmi_service_bitmap, + param_buf->wmi_service_bitmap, + sizeof(wma_handle->wmi_service_bitmap)); + target_cap.wlan_resource_config = wma_handle->wlan_resource_config; + wma_update_fw_config(wma_handle, &target_cap); + qdf_mem_copy(wma_handle->wmi_service_bitmap, + target_cap.wmi_service_bitmap, + sizeof(wma_handle->wmi_service_bitmap)); + wma_handle->wlan_resource_config = target_cap.wlan_resource_config; + + status = wmi_unified_save_fw_version_cmd(wma_handle->wmi_handle, + param_buf); + if (status != EOK) { + WMA_LOGE("Failed to send WMI_INIT_CMDID command"); + return -EINVAL; + } + + status = wma_setup_wmi_init_msg(wma_handle, ev, param_buf); + if (status != EOK) { + WMA_LOGE("Failed to setup for wma init command"); + return -EINVAL; + } + + /* A host, which supports WMI_SERVICE_READY_EXT_EVENTID, would need to + * check the WMI_SERVICE_READY message for an "extension" flag, and if + * this flag is set, then hold off on sending the WMI_INIT message until + * WMI_SERVICE_READY_EXT_EVENTID is received. + */ + if (!WMI_SERVICE_IS_ENABLED(wma_handle->wmi_service_bitmap, + WMI_SERVICE_EXT_MSG)) { + /* No service extended message support. + * Send INIT command immediately + */ + WMA_LOGA("WMA --> WMI_INIT_CMDID"); + status = wmi_unified_send_init_cmd(wma_handle->wmi_handle, + &wma_handle->wlan_resource_config, + wma_handle->num_mem_chunks, + wma_handle->mem_chunks, 1); + if (status != EOK) { + WMA_LOGE("Failed to send WMI_INIT_CMDID command"); + return -EINVAL; + } + } else { + status = wmi_unified_send_init_cmd(wma_handle->wmi_handle, + &wma_handle->wlan_resource_config, + wma_handle->num_mem_chunks, + wma_handle->mem_chunks, 0); + if (status != EOK) { + WMA_LOGE("Failed to save WMI_INIT_CMDID command parameter"); + return -EINVAL; + } + /* The saved 'buf' will be freed after sending INIT command or + * in other cases as required + */ + ret = qdf_mc_timer_start(&wma_handle->service_ready_ext_timer, + WMA_SERVICE_READY_EXT_TIMEOUT); + if (!QDF_IS_STATUS_SUCCESS(ret)) + WMA_LOGP("Failed to start the service ready ext timer"); + + WMA_LOGA("%s: WMA waiting for WMI_SERVICE_READY_EXT_EVENTID", + __func__); + } + + if (WMI_SERVICE_IS_ENABLED(wma_handle->wmi_service_bitmap, + WMI_SERVICE_8SS_TX_BFEE)) + wma_handle->tx_bfee_8ss_enabled = true; + else + wma_handle->tx_bfee_8ss_enabled = false; + + return 0; +} + +/** + * wma_get_phyid_for_given_band() - to get phyid for band + * + * @wma_handle: Pointer to wma handle + * @map: Pointer to map which is derived from hw mode & has mapping between + * hw mode and available PHYs for that hw mode. + * @band: enum value of for 2G or 5G band + * @phyid: Pointer to phyid which needs to be filled + * + * This API looks in to the map to find out which particular phy supports + * provided band and return the idx (also called phyid) of that phy. Caller + * use this phyid to fetch various caps of that phy + * + * Return: QDF_STATUS + */ +static QDF_STATUS wma_get_phyid_for_given_band( + t_wma_handle * wma_handle, + struct hw_mode_idx_to_mac_cap_idx *map, + enum cds_band_type band, uint8_t *phyid) +{ + uint8_t idx, i; + WMI_MAC_PHY_CAPABILITIES *cap; + + if (!wma_handle) { + WMA_LOGE("Invalid wma handle"); + return QDF_STATUS_E_FAILURE; + } + + if (!map) { + WMA_LOGE("Invalid given map"); + return QDF_STATUS_E_FAILURE; + } + idx = map->mac_cap_idx; + *phyid = idx; + + for (i = 0; i < map->num_of_macs; i++) { + cap = &wma_handle->phy_caps.each_phy_cap_per_hwmode[idx + i]; + if ((band == CDS_BAND_2GHZ) && + (WLAN_2G_CAPABILITY == cap->supported_bands)) { + *phyid = idx + i; + WMA_LOGI("Select 2G capable phyid[%d]", *phyid); + return QDF_STATUS_SUCCESS; + } else if ((band == CDS_BAND_5GHZ) && + (WLAN_5G_CAPABILITY == cap->supported_bands)) { + *phyid = idx + i; + WMA_LOGI("Select 5G capable phyid[%d]", *phyid); + return QDF_STATUS_SUCCESS; + } + } + WMA_LOGI("Using default single hw mode phyid[%d]", *phyid); + return QDF_STATUS_SUCCESS; +} + +/** + * wma_get_caps_for_phyidx_hwmode() - to fetch caps for given hw mode and band + * @caps_per_phy: Pointer to capabilities structure which needs to be filled + * @hw_mode: Provided hardware mode + * @band: Provide band i.e. 2G or 5G + * + * This API finds cap which suitable for provided hw mode and band. If user + * is provides some invalid hw mode then it will automatically falls back to + * default hw mode + * + * Return: QDF_STATUS + */ +QDF_STATUS wma_get_caps_for_phyidx_hwmode(struct wma_caps_per_phy *caps_per_phy, + enum hw_mode_dbs_capab hw_mode, enum cds_band_type band) +{ + t_wma_handle *wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + struct hw_mode_idx_to_mac_cap_idx *map; + WMI_MAC_PHY_CAPABILITIES *phy_cap; + uint8_t phyid, our_hw_mode = hw_mode; + + if (!wma_handle) { + WMA_LOGE("Invalid wma handle"); + return QDF_STATUS_E_FAILURE; + } + + if (0 == wma_handle->phy_caps.num_hw_modes.num_hw_modes) { + WMA_LOGE("Invalid number of hw modes"); + return QDF_STATUS_E_FAILURE; + } + + if (!wma_is_dbs_enable()) + our_hw_mode = HW_MODE_DBS_NONE; + + if (!caps_per_phy) { + WMA_LOGE("Invalid caps pointer"); + return QDF_STATUS_E_FAILURE; + } + + map = &wma_handle->phy_caps.hw_mode_to_mac_cap_map[our_hw_mode]; + + if (QDF_STATUS_SUCCESS != + wma_get_phyid_for_given_band(wma_handle, map, band, &phyid)) { + WMA_LOGE("Invalid phyid"); + return QDF_STATUS_E_FAILURE; + } + phy_cap = &wma_handle->phy_caps.each_phy_cap_per_hwmode[phyid]; + + caps_per_phy->ht_2g = phy_cap->ht_cap_info_2G; + caps_per_phy->ht_5g = phy_cap->ht_cap_info_5G; + caps_per_phy->vht_2g = phy_cap->vht_cap_info_2G; + caps_per_phy->vht_5g = phy_cap->vht_cap_info_5G; + caps_per_phy->he_2g = phy_cap->he_cap_info_2G; + caps_per_phy->he_5g = phy_cap->he_cap_info_5G; + + return QDF_STATUS_SUCCESS; +} + +/** + * wma_is_rx_ldpc_supported_for_channel() - to find out if ldpc is supported + * + * @channel: Channel number for which it needs to check if rx ldpc is enabled + * + * This API takes channel number as argument and takes default hw mode as DBS + * to check if rx LDPC support is enabled for that channel or no + */ +bool wma_is_rx_ldpc_supported_for_channel(uint32_t channel) +{ + struct wma_caps_per_phy caps_per_phy = {0}; + enum cds_band_type band; + bool status; + + if (!CDS_IS_CHANNEL_24GHZ(channel)) + band = CDS_BAND_5GHZ; + else + band = CDS_BAND_2GHZ; + + if (QDF_STATUS_SUCCESS != wma_get_caps_for_phyidx_hwmode( + &caps_per_phy, + HW_MODE_DBS, band)) { + return false; + } + if (CDS_IS_CHANNEL_24GHZ(channel)) + status = (!!(caps_per_phy.ht_2g & WMI_HT_CAP_RX_LDPC)); + else + status = (!!(caps_per_phy.ht_5g & WMI_HT_CAP_RX_LDPC)); + + return status; +} + + +/** + * wma_print_populate_soc_caps() - Prints all the caps populated per hw mode + * @wma_handle: pointer to wma_handle + * + * This function prints all the caps populater per hw mode and per PHY + * + * Return: none + */ +static void wma_print_populate_soc_caps(t_wma_handle *wma_handle) +{ + int i, j = 0, max_mac; + WMI_MAC_PHY_CAPABILITIES *tmp; + + /* print number of hw modes */ + WMA_LOGI("%s: num of hw modes [%d]", __func__, + wma_handle->phy_caps.num_hw_modes.num_hw_modes); + WMA_LOGI("%s: <====== HW mode cap printing starts ======>", __func__); + /* print cap of each hw mode */ + for (i = 0; i < wma_handle->phy_caps.num_hw_modes.num_hw_modes; i++) { + WMA_LOGI("====>: hw mode id[%d], phy_id map[%d]", + wma_handle->phy_caps.each_hw_mode_cap[i].hw_mode_id, + wma_handle->phy_caps.each_hw_mode_cap[i].phy_id_map); + if (wma_handle->phy_caps.each_hw_mode_cap[i].phy_id_map == + PHY1_PHY2) + max_mac = j + 2; + else + max_mac = j + 1; + + for ( ; j < max_mac; j++) { + tmp = &wma_handle->phy_caps.each_phy_cap_per_hwmode[j]; + WMA_LOGI("\t: index j[%d]", j); + WMA_LOGI("\t: cap for hw_mode_id[%d]", tmp->hw_mode_id); + WMA_LOGI("\t: pdev_id[%d]", tmp->pdev_id); + WMA_LOGI("\t: phy_id[%d]", tmp->phy_id); + WMA_LOGI("\t: supports_11b[%d]", + WMI_SUPPORT_11B_GET(tmp->supported_flags)); + WMA_LOGI("\t: supports_11g[%d]", + WMI_SUPPORT_11G_GET(tmp->supported_flags)); + WMA_LOGI("\t: supports_11a[%d]", + WMI_SUPPORT_11A_GET(tmp->supported_flags)); + WMA_LOGI("\t: supports_11n[%d]", + WMI_SUPPORT_11N_GET(tmp->supported_flags)); + WMA_LOGI("\t: supports_11ac[%d]", + WMI_SUPPORT_11AC_GET(tmp->supported_flags)); + WMA_LOGI("\t: supports_11ax[%d]", + WMI_SUPPORT_11AX_GET(tmp->supported_flags)); + WMA_LOGI("\t: supported_flags[%d]", + tmp->supported_flags); + WMA_LOGI("\t: supported_bands[%d]", + tmp->supported_bands); + WMA_LOGI("\t: ampdu_density[%d]", + tmp->ampdu_density); + WMA_LOGI("\t: max_bw_supported_2G[%d]", + tmp->max_bw_supported_2G); + WMA_LOGI("\t: ht_cap_info_2G[%d]", tmp->ht_cap_info_2G); + WMA_LOGI("\t: vht_cap_info_2G[%d]", + tmp->vht_cap_info_2G); + WMA_LOGI("\t: he_cap_info_2G[%d]", tmp->he_cap_info_2G); + WMA_LOGI("\t: vht_supp_mcs_2G[%d]", + tmp->vht_supp_mcs_2G); + WMA_LOGI("\t: he_supp_mcs_2G[%d]", tmp->he_supp_mcs_2G); + WMA_LOGI("\t: tx_chain_mask_2G[%d]", + tmp->tx_chain_mask_2G); + WMA_LOGI("\t: rx_chain_mask_2G[%d]", + tmp->rx_chain_mask_2G); + WMA_LOGI("\t: max_bw_supported_5G[%d]", + tmp->max_bw_supported_5G); + WMA_LOGI("\t: ht_cap_info_5G[%d]", + tmp->ht_cap_info_5G); + WMA_LOGI("\t: vht_cap_info_5G[%d]", + tmp->vht_cap_info_5G); + WMA_LOGI("\t: he_cap_info_5G[%d]", tmp->he_cap_info_5G); + WMA_LOGI("\t: vht_supp_mcs_5G[%d]", + tmp->vht_supp_mcs_5G); + WMA_LOGI("\t: he_supp_mcs_5G[%d]", tmp->he_supp_mcs_5G); + WMA_LOGI("\t: tx_chain_mask_5G[%d]", + tmp->tx_chain_mask_5G); + WMA_LOGI("\t: rx_chain_mask_5G[%d]", + tmp->rx_chain_mask_5G); + } + } + WMA_LOGI("%s: <====== HW mode cap printing ends ======>\n", __func__); +} + +/** + * wma_map_wmi_channel_width_to_hw_mode_bw() - returns bandwidth + * in terms of hw_mode_bandwidth + * @width: bandwidth in terms of wmi_channel_width + * + * This function returns the bandwidth in terms of hw_mode_bandwidth. + * + * Return: BW in terms of hw_mode_bandwidth. + */ +static enum hw_mode_bandwidth wma_map_wmi_channel_width_to_hw_mode_bw( + wmi_channel_width width) +{ + switch (width) { + case WMI_CHAN_WIDTH_20: + return HW_MODE_20_MHZ; + case WMI_CHAN_WIDTH_40: + return HW_MODE_40_MHZ; + case WMI_CHAN_WIDTH_80: + return HW_MODE_80_MHZ; + case WMI_CHAN_WIDTH_160: + return HW_MODE_160_MHZ; + case WMI_CHAN_WIDTH_80P80: + return HW_MODE_80_PLUS_80_MHZ; + case WMI_CHAN_WIDTH_5: + return HW_MODE_5_MHZ; + case WMI_CHAN_WIDTH_10: + return HW_MODE_10_MHZ; + default: + return HW_MODE_BW_NONE; + } + + return HW_MODE_BW_NONE; +} + +/** + * wma_get_hw_mode_params() - get TX-RX stream and bandwidth + * supported from the capabilities. + * @caps: PHY capability + * @info: param to store TX-RX stream and BW information + * + * This function will calculate TX-RX stream and bandwidth supported + * as per the PHY capability, and assign to mac_ss_bw_info. + * + * Return: none + */ +static void wma_get_hw_mode_params(WMI_MAC_PHY_CAPABILITIES *caps, + struct mac_ss_bw_info *info) +{ + if (!caps) { + WMA_LOGE("%s: Invalid capabilities", __func__); + return; + } + + info->mac_tx_stream = wma_get_num_of_setbits_from_bitmask( + QDF_MAX(caps->tx_chain_mask_2G, + caps->tx_chain_mask_5G)); + info->mac_rx_stream = wma_get_num_of_setbits_from_bitmask( + QDF_MAX(caps->rx_chain_mask_2G, + caps->rx_chain_mask_5G)); + info->mac_bw = wma_map_wmi_channel_width_to_hw_mode_bw( + QDF_MAX(caps->max_bw_supported_2G, + caps->max_bw_supported_5G)); +} + +/** + * wma_set_hw_mode_params() - sets TX-RX stream, bandwidth and + * DBS in hw_mode_list + * @wma_handle: pointer to wma global structure + * @mac0_ss_bw_info: TX-RX streams, BW for MAC0 + * @mac1_ss_bw_info: TX-RX streams, BW for MAC1 + * @pos: refers to hw_mode_index + * @dbs_mode: dbs_mode for the dbs_hw_mode + * @sbs_mode: sbs_mode for the sbs_hw_mode + * + * This function sets TX-RX stream, bandwidth and DBS mode in + * hw_mode_list. + * + * Return: none + */ +static void wma_set_hw_mode_params(t_wma_handle *wma_handle, + struct mac_ss_bw_info mac0_ss_bw_info, + struct mac_ss_bw_info mac1_ss_bw_info, + uint32_t pos, uint32_t dbs_mode, + uint32_t sbs_mode) +{ + WMA_HW_MODE_MAC0_TX_STREAMS_SET( + wma_handle->hw_mode.hw_mode_list[pos], + mac0_ss_bw_info.mac_tx_stream); + WMA_HW_MODE_MAC0_RX_STREAMS_SET( + wma_handle->hw_mode.hw_mode_list[pos], + mac0_ss_bw_info.mac_rx_stream); + WMA_HW_MODE_MAC0_BANDWIDTH_SET( + wma_handle->hw_mode.hw_mode_list[pos], + mac0_ss_bw_info.mac_bw); + WMA_HW_MODE_MAC1_TX_STREAMS_SET( + wma_handle->hw_mode.hw_mode_list[pos], + mac1_ss_bw_info.mac_tx_stream); + WMA_HW_MODE_MAC1_RX_STREAMS_SET( + wma_handle->hw_mode.hw_mode_list[pos], + mac1_ss_bw_info.mac_rx_stream); + WMA_HW_MODE_MAC1_BANDWIDTH_SET( + wma_handle->hw_mode.hw_mode_list[pos], + mac1_ss_bw_info.mac_bw); + WMA_HW_MODE_DBS_MODE_SET( + wma_handle->hw_mode.hw_mode_list[pos], + dbs_mode); + WMA_HW_MODE_AGILE_DFS_SET( + wma_handle->hw_mode.hw_mode_list[pos], + HW_MODE_AGILE_DFS_NONE); + WMA_HW_MODE_SBS_MODE_SET( + wma_handle->hw_mode.hw_mode_list[pos], + sbs_mode); +} + +/** + * wma_update_hw_mode_list() - updates hw_mode_list + * @wma_handle: pointer to wma global structure + * + * This function updates hw_mode_list with tx_streams, rx_streams, + * bandwidth, dbs and agile dfs for each hw_mode. + * + * Returns: 0 for success else failure. + */ +static QDF_STATUS wma_update_hw_mode_list(t_wma_handle *wma_handle) +{ + struct extended_caps *phy_caps; + WMI_MAC_PHY_CAPABILITIES *tmp; + uint32_t i, hw_config_type, j = 0; + uint32_t dbs_mode, sbs_mode; + struct mac_ss_bw_info mac0_ss_bw_info = {0}; + struct mac_ss_bw_info mac1_ss_bw_info = {0}; + + if (!wma_handle) { + WMA_LOGE("%s: Invalid wma handle", __func__); + return QDF_STATUS_E_FAILURE; + } + + phy_caps = &wma_handle->phy_caps; + if (!phy_caps) { + WMA_LOGE("%s: Invalid phy capabilities", __func__); + return QDF_STATUS_SUCCESS; + } + + if (!phy_caps->num_hw_modes.num_hw_modes) { + WMA_LOGE("%s: Number of HW modes: %d", + __func__, phy_caps->num_hw_modes.num_hw_modes); + return QDF_STATUS_SUCCESS; + } + + /* + * This list was updated as part of service ready event. Re-populate + * HW mode list from the device capabilities. + */ + if (wma_handle->hw_mode.hw_mode_list) { + qdf_mem_free(wma_handle->hw_mode.hw_mode_list); + wma_handle->hw_mode.hw_mode_list = NULL; + WMA_LOGI("%s: DBS list is freed", __func__); + } + + wma_handle->num_dbs_hw_modes = phy_caps->num_hw_modes.num_hw_modes; + wma_handle->hw_mode.hw_mode_list = + qdf_mem_malloc(sizeof(*wma_handle->hw_mode.hw_mode_list) * + wma_handle->num_dbs_hw_modes); + if (!wma_handle->hw_mode.hw_mode_list) { + WMA_LOGE("%s: Memory allocation failed for DBS", __func__); + return QDF_STATUS_E_FAILURE; + } + + WMA_LOGA("%s: Updated HW mode list: Num modes:%d", + __func__, wma_handle->num_dbs_hw_modes); + + for (i = 0; i < wma_handle->num_dbs_hw_modes; i++) { + /* Update for MAC0 */ + tmp = &phy_caps->each_phy_cap_per_hwmode[j++]; + wma_get_hw_mode_params(tmp, &mac0_ss_bw_info); + hw_config_type = + phy_caps->each_hw_mode_cap[i].hw_mode_config_type; + dbs_mode = HW_MODE_DBS_NONE; + sbs_mode = HW_MODE_SBS_NONE; + mac1_ss_bw_info.mac_tx_stream = 0; + mac1_ss_bw_info.mac_rx_stream = 0; + mac1_ss_bw_info.mac_bw = 0; + + /* SBS and DBS have dual MAC. Upto 2 MACs are considered. */ + if ((hw_config_type == WMI_HW_MODE_DBS) || + (hw_config_type == WMI_HW_MODE_SBS_PASSIVE) || + (hw_config_type == WMI_HW_MODE_SBS)) { + /* Update for MAC1 */ + tmp = &phy_caps->each_phy_cap_per_hwmode[j++]; + wma_get_hw_mode_params(tmp, &mac1_ss_bw_info); + if (hw_config_type == WMI_HW_MODE_DBS) + dbs_mode = HW_MODE_DBS; + if ((hw_config_type == WMI_HW_MODE_SBS_PASSIVE) || + (hw_config_type == WMI_HW_MODE_SBS)) + sbs_mode = HW_MODE_SBS; + } + + /* Updating HW mode list */ + wma_set_hw_mode_params(wma_handle, mac0_ss_bw_info, + mac1_ss_bw_info, i, dbs_mode, + sbs_mode); + } + wma_dump_dbs_hw_mode(wma_handle); + return QDF_STATUS_SUCCESS; +} + +/** + * wma_populate_soc_caps() - populate entire SOC's capabilities + * @wma_handle: pointer to wma global structure + * @param_buf: pointer to param of service ready extension event from fw + * + * This API populates all capabilities of entire SOC. For example, + * how many number of hw modes are supported by this SOC, what are the + * capabilities of each phy per hw mode, what are HAL reg capabilities per + * phy. + * + * Return: none + */ +static void wma_populate_soc_caps(t_wma_handle *wma_handle, + WMI_SERVICE_READY_EXT_EVENTID_param_tlvs *param_buf) +{ + int i, num_of_mac_caps = 0, tmp = 0; + struct extended_caps *phy_caps; + struct hw_mode_idx_to_mac_cap_idx *map; + + WMA_LOGD("%s: Enter", __func__); + + if (!wma_handle) { + WMA_LOGP("%s: Invalid WMA handle", __func__); + return; + } + + if (!param_buf) { + WMA_LOGP("%s: Invalid event", __func__); + return; + } + phy_caps = &wma_handle->phy_caps; + + /* + * first thing to do is to get how many number of hw modes are + * supported and populate in wma_handle global structure + */ + if (NULL == param_buf->soc_hw_mode_caps) { + WMA_LOGE("%s: Invalid number of hw modes", __func__); + return; + } + + qdf_mem_copy(&phy_caps->num_hw_modes, + param_buf->soc_hw_mode_caps, + sizeof(WMI_SOC_MAC_PHY_HW_MODE_CAPS)); + if (0 == phy_caps->num_hw_modes.num_hw_modes) { + WMA_LOGE("%s: Number of hw modes is zero", __func__); + return; + } + WMA_LOGI("%s: Given number of hw modes[%d]", + __func__, phy_caps->num_hw_modes.num_hw_modes); + + /* + * next thing is to allocate the memory to map hw mode to phy/mac caps + */ + phy_caps->hw_mode_to_mac_cap_map = + qdf_mem_malloc(phy_caps->num_hw_modes.num_hw_modes * + sizeof(struct hw_mode_idx_to_mac_cap_idx)); + if (!phy_caps->hw_mode_to_mac_cap_map) { + WMA_LOGE("%s: Memory allocation failed", __func__); + return; + } + + /* + * next thing is to allocate the memory for per hw caps + */ + phy_caps->each_hw_mode_cap = + qdf_mem_malloc(phy_caps->num_hw_modes.num_hw_modes * + sizeof(WMI_HW_MODE_CAPABILITIES)); + if (!phy_caps->each_hw_mode_cap) { + WMA_LOGE("%s: Memory allocation failed", __func__); + wma_cleanup_dbs_phy_caps(wma_handle); + return; + } + qdf_mem_copy(phy_caps->each_hw_mode_cap, + param_buf->hw_mode_caps, + phy_caps->num_hw_modes.num_hw_modes * + sizeof(WMI_HW_MODE_CAPABILITIES)); + /* + * next thing is to count the number of mac cap to populate per + * hw mode and generate map, so that our search can be done + * efficiently which is O(1) + */ + for (i = 0; i < phy_caps->num_hw_modes.num_hw_modes; i++) { + map = &phy_caps->hw_mode_to_mac_cap_map[i]; + if (phy_caps->each_hw_mode_cap[i].phy_id_map == PHY1_PHY2) { + tmp = num_of_mac_caps; + num_of_mac_caps = num_of_mac_caps + 2; + map->num_of_macs = 2; + } else { + tmp = num_of_mac_caps; + num_of_mac_caps = num_of_mac_caps + 1; + map->num_of_macs = 1; + } + map->mac_cap_idx = tmp; + map->hw_mode_id = phy_caps->each_hw_mode_cap[i].hw_mode_id; + } + + /* + * next thing is to populate each phy caps per hw mode + */ + phy_caps->each_phy_cap_per_hwmode = + qdf_mem_malloc(num_of_mac_caps * + sizeof(WMI_MAC_PHY_CAPABILITIES)); + if (!phy_caps->each_phy_cap_per_hwmode) { + WMA_LOGE("%s: Memory allocation failed", __func__); + wma_cleanup_dbs_phy_caps(wma_handle); + return; + } + qdf_mem_copy(phy_caps->each_phy_cap_per_hwmode, + param_buf->mac_phy_caps, + num_of_mac_caps * sizeof(WMI_MAC_PHY_CAPABILITIES)); + + /* + * next thing is to populate reg caps per phy + */ + qdf_mem_copy(&phy_caps->num_phy_for_hal_reg_cap, + param_buf->soc_hal_reg_caps, + sizeof(WMI_SOC_HAL_REG_CAPABILITIES)); + if (phy_caps->num_phy_for_hal_reg_cap.num_phy == 0) { + WMA_LOGE("%s: incorrect number of phys", __func__); + wma_cleanup_dbs_phy_caps(wma_handle); + return; + } + phy_caps->each_phy_hal_reg_cap = + qdf_mem_malloc(phy_caps->num_phy_for_hal_reg_cap.num_phy * + sizeof(WMI_HAL_REG_CAPABILITIES_EXT)); + if (!phy_caps->each_phy_hal_reg_cap) { + WMA_LOGE("%s: Memory allocation failed", __func__); + wma_cleanup_dbs_phy_caps(wma_handle); + return; + } + qdf_mem_copy(phy_caps->each_phy_hal_reg_cap, + param_buf->hal_reg_caps, + phy_caps->num_phy_for_hal_reg_cap.num_phy * + sizeof(WMI_HAL_REG_CAPABILITIES_EXT)); + wma_print_populate_soc_caps(wma_handle); + return; +} + +/** + * wma_rx_service_ready_ext_event() - evt handler for sevice ready ext event. + * @handle: wma handle + * @event: params of the service ready extended event + * @length: param length + * + * Return: none + */ +int wma_rx_service_ready_ext_event(void *handle, uint8_t *event, + uint32_t length) +{ + tp_wma_handle wma_handle = (tp_wma_handle) handle; + WMI_SERVICE_READY_EXT_EVENTID_param_tlvs *param_buf; + wmi_service_ready_ext_event_fixed_param *ev; + int status; + QDF_STATUS ret; + + WMA_LOGD("%s: Enter", __func__); + + if (!wma_handle) { + WMA_LOGP("%s: Invalid WMA handle", __func__); + return -EINVAL; + } + + param_buf = (WMI_SERVICE_READY_EXT_EVENTID_param_tlvs *) event; + if (!param_buf) { + WMA_LOGP("%s: Invalid event", __func__); + return -EINVAL; + } + + ev = param_buf->fixed_param; + if (!ev) { + WMA_LOGP("%s: Invalid buffer", __func__); + return -EINVAL; + } + + WMA_LOGD("WMA <-- WMI_SERVICE_READY_EXT_EVENTID"); + + WMA_LOGD("%s: Defaults: scan config:%x FW mode config:%x", + __func__, ev->default_conc_scan_config_bits, + ev->default_fw_config_bits); + + ret = qdf_mc_timer_stop(&wma_handle->service_ready_ext_timer); + if (!QDF_IS_STATUS_SUCCESS(ret)) { + WMA_LOGP("Failed to stop the service ready ext timer"); + return -EINVAL; + } + wma_populate_soc_caps(wma_handle, param_buf); + + ret = wma_update_hw_mode_list(wma_handle); + if (QDF_IS_STATUS_ERROR(ret)) { + WMA_LOGE("Failed to update hw mode list"); + return -EINVAL; + } + + WMA_LOGD("WMA --> WMI_INIT_CMDID"); + status = wmi_unified_send_saved_init_cmd(wma_handle->wmi_handle); + if (status != EOK) + /* In success case, WMI layer will free after getting copy + * engine TX complete interrupt + */ + WMA_LOGE("Failed to send WMI_INIT_CMDID command"); + + wma_init_scan_fw_mode_config(wma_handle, + ev->default_conc_scan_config_bits, + ev->default_fw_config_bits); + wma_handle->target_fw_vers_ext = ev->fw_build_vers_ext; + return 0; +} + +/** + * wma_rx_ready_event() - event handler to process + * wmi rx ready event. + * @handle: wma handle + * @cmd_param_info: command params info + * @length: param length + * + * Return: none + */ +int wma_rx_ready_event(void *handle, uint8_t *cmd_param_info, + uint32_t length) +{ + tp_wma_handle wma_handle = (tp_wma_handle) handle; + WMI_READY_EVENTID_param_tlvs *param_buf = NULL; + wmi_ready_event_fixed_param *ev = NULL; + + WMA_LOGD("%s: Enter", __func__); + + param_buf = (WMI_READY_EVENTID_param_tlvs *) cmd_param_info; + if (!(wma_handle && param_buf)) { + WMA_LOGP("%s: Invalid arguments", __func__); + QDF_ASSERT(0); + return -EINVAL; + } + + WMA_LOGD("WMA <-- WMI_READY_EVENTID"); + + ev = param_buf->fixed_param; + /* Indicate to the waiting thread that the ready + * event was received */ + wma_handle->sub_20_support = + WMI_SERVICE_IS_ENABLED(wma_handle->wmi_service_bitmap, + WMI_SERVICE_HALF_RATE_QUARTER_RATE_SUPPORT); + wma_handle->wmi_ready = true; + wma_handle->wlan_init_status = ev->status; + + /* + * We need to check the WMI versions and make sure both + * host and fw are compatible. + */ + if (!wmi_versions_are_compatible(&wma_handle->final_abi_vers, + &ev->fw_abi_vers)) { + /* + * Error: Our host version and the given firmware version + * are incompatible. + */ + WMA_LOGE("%s: Error: Incompatible WMI version." + "Host: %d,%d,0x%x 0x%x 0x%x 0x%x, FW: %d,%d,0x%x 0x%x 0x%x 0x%x", + __func__, + WMI_VER_GET_MAJOR(wma_handle->final_abi_vers. + abi_version_0), + WMI_VER_GET_MINOR(wma_handle->final_abi_vers. + abi_version_0), + wma_handle->final_abi_vers.abi_version_ns_0, + wma_handle->final_abi_vers.abi_version_ns_1, + wma_handle->final_abi_vers.abi_version_ns_2, + wma_handle->final_abi_vers.abi_version_ns_3, + WMI_VER_GET_MAJOR(ev->fw_abi_vers.abi_version_0), + WMI_VER_GET_MINOR(ev->fw_abi_vers.abi_version_0), + ev->fw_abi_vers.abi_version_ns_0, + ev->fw_abi_vers.abi_version_ns_1, + ev->fw_abi_vers.abi_version_ns_2, + ev->fw_abi_vers.abi_version_ns_3); + if (wma_handle->wlan_init_status == WLAN_INIT_STATUS_SUCCESS) { + /* Failed this connection to FW */ + wma_handle->wlan_init_status = + WLAN_INIT_STATUS_GEN_FAILED; + } + } + qdf_mem_copy(&wma_handle->final_abi_vers, &ev->fw_abi_vers, + sizeof(wmi_abi_version)); + qdf_mem_copy(&wma_handle->target_abi_vers, &ev->fw_abi_vers, + sizeof(wmi_abi_version)); + + /* copy the mac addr */ + WMI_MAC_ADDR_TO_CHAR_ARRAY(&ev->mac_addr, wma_handle->myaddr); + WMI_MAC_ADDR_TO_CHAR_ARRAY(&ev->mac_addr, wma_handle->hwaddr); + + wma_update_hdd_cfg(wma_handle); + + qdf_event_set(&wma_handle->wma_ready_event); + + WMA_LOGD("Exit"); + + return 0; +} + +/** + * wma_setneedshutdown() - setting wma needshutdown flag + * @cds_ctx: cds context + * + * Return: none + */ +void wma_setneedshutdown(void *cds_ctx) +{ + tp_wma_handle wma_handle; + + WMA_LOGD("%s: Enter", __func__); + + wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + + if (NULL == wma_handle) { + WMA_LOGP("%s: Invalid arguments", __func__); + QDF_ASSERT(0); + return; + } + + wma_handle->needShutdown = true; + WMA_LOGD("%s: Exit", __func__); +} + +/** + * wma_needshutdown() - Is wma needs shutdown? + * @cds_ctx: cds context + * + * Return: returns true/false + */ +bool wma_needshutdown(void *cds_ctx) +{ + tp_wma_handle wma_handle; + + WMA_LOGD("%s: Enter", __func__); + + wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + + if (NULL == wma_handle) { + WMA_LOGP("%s: Invalid arguments", __func__); + QDF_ASSERT(0); + return false; + } + + WMA_LOGD("%s: Exit", __func__); + return wma_handle->needShutdown; +} + +/** + * wma_wait_for_ready_event() - wait for wma ready event + * @handle: wma handle + * + * Return: 0 for success or QDF error + */ +QDF_STATUS wma_wait_for_ready_event(WMA_HANDLE handle) +{ + tp_wma_handle wma_handle = (tp_wma_handle) handle; + QDF_STATUS qdf_status; + + /* wait until WMI_READY_EVENTID received from FW */ + qdf_status = qdf_wait_single_event(&(wma_handle->wma_ready_event), + WMA_READY_EVENTID_TIMEOUT); + + if (QDF_STATUS_SUCCESS != qdf_status) { + WMA_LOGP("%s: Timeout waiting for ready event from FW", + __func__); + qdf_status = QDF_STATUS_E_FAILURE; + } + return qdf_status; +} + +/** + * wma_set_ppsconfig() - set pps config in fw + * @vdev_id: vdev id + * @pps_param: pps params + * @val : param value + * + * Return: 0 for success or QDF error + */ +QDF_STATUS wma_set_ppsconfig(uint8_t vdev_id, uint16_t pps_param, + int val) +{ + tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA); + int ret = -EIO; + uint32_t pps_val; + + if (NULL == wma) { + WMA_LOGE("%s: Failed to get wma", __func__); + return QDF_STATUS_E_INVAL; + } + + switch (pps_param) { + case WMA_VHT_PPS_PAID_MATCH: + pps_val = ((val << 31) & 0xffff0000) | + (PKT_PWR_SAVE_PAID_MATCH & 0xffff); + goto pkt_pwr_save_config; + case WMA_VHT_PPS_GID_MATCH: + pps_val = ((val << 31) & 0xffff0000) | + (PKT_PWR_SAVE_GID_MATCH & 0xffff); + goto pkt_pwr_save_config; + case WMA_VHT_PPS_DELIM_CRC_FAIL: + pps_val = ((val << 31) & 0xffff0000) | + (PKT_PWR_SAVE_DELIM_CRC_FAIL & 0xffff); + goto pkt_pwr_save_config; + + /* Enable the code below as and when the functionality + * is supported/added in host. + */ +#ifdef NOT_YET + case WMA_VHT_PPS_EARLY_TIM_CLEAR: + pps_val = ((val << 31) & 0xffff0000) | + (PKT_PWR_SAVE_EARLY_TIM_CLEAR & 0xffff); + goto pkt_pwr_save_config; + case WMA_VHT_PPS_EARLY_DTIM_CLEAR: + pps_val = ((val << 31) & 0xffff0000) | + (PKT_PWR_SAVE_EARLY_DTIM_CLEAR & 0xffff); + goto pkt_pwr_save_config; + case WMA_VHT_PPS_EOF_PAD_DELIM: + pps_val = ((val << 31) & 0xffff0000) | + (PKT_PWR_SAVE_EOF_PAD_DELIM & 0xffff); + goto pkt_pwr_save_config; + case WMA_VHT_PPS_MACADDR_MISMATCH: + pps_val = ((val << 31) & 0xffff0000) | + (PKT_PWR_SAVE_MACADDR_MISMATCH & 0xffff); + goto pkt_pwr_save_config; + case WMA_VHT_PPS_GID_NSTS_ZERO: + pps_val = ((val << 31) & 0xffff0000) | + (PKT_PWR_SAVE_GID_NSTS_ZERO & 0xffff); + goto pkt_pwr_save_config; + case WMA_VHT_PPS_RSSI_CHECK: + pps_val = ((val << 31) & 0xffff0000) | + (PKT_PWR_SAVE_RSSI_CHECK & 0xffff); + goto pkt_pwr_save_config; +#endif /* NOT_YET */ +pkt_pwr_save_config: + WMA_LOGD("vdev_id:%d val:0x%x pps_val:0x%x", vdev_id, + val, pps_val); + ret = wma_vdev_set_param(wma->wmi_handle, vdev_id, + WMI_VDEV_PARAM_PACKET_POWERSAVE, + pps_val); + break; + default: + WMA_LOGE("%s:INVALID PPS CONFIG", __func__); + } + + return (ret) ? QDF_STATUS_E_FAILURE : QDF_STATUS_SUCCESS; +} + +/** + * wma_process_set_mas() - Function to enable/disable MAS + * @wma: Pointer to WMA handle + * @mas_val: 1-Enable MAS, 0-Disable MAS + * + * This function enables/disables the MAS value + * + * Return: QDF_SUCCESS for success otherwise failure + */ +static QDF_STATUS wma_process_set_mas(tp_wma_handle wma, + uint32_t *mas_val) +{ + uint32_t val; + + if (NULL == wma || NULL == mas_val) { + WMA_LOGE("%s: Invalid input to enable/disable MAS", __func__); + return QDF_STATUS_E_FAILURE; + } + + val = (*mas_val); + + if (QDF_STATUS_SUCCESS != + wma_set_enable_disable_mcc_adaptive_scheduler(val)) { + WMA_LOGE("%s: Unable to enable/disable MAS", __func__); + return QDF_STATUS_E_FAILURE; + } else { + WMA_LOGE("%s: Value is %d", __func__, val); + } + + return QDF_STATUS_SUCCESS; +} + +/** + * wma_process_set_miracast() - Function to set miracast value in WMA + * @wma: Pointer to WMA handle + * @miracast_val: 0-Disabled,1-Source,2-Sink + * + * This function stores the miracast value in WMA + * + * Return: QDF_SUCCESS for success otherwise failure + * + */ +static QDF_STATUS wma_process_set_miracast(tp_wma_handle wma, + uint32_t *miracast_val) +{ + if (NULL == wma || NULL == miracast_val) { + WMA_LOGE("%s: Invalid input to store miracast value", __func__); + return QDF_STATUS_E_FAILURE; + } + + wma->miracast_value = *miracast_val; + WMA_LOGE("%s: Miracast value is %d", __func__, wma->miracast_value); + + return QDF_STATUS_SUCCESS; +} + +/** + * wma_config_stats_factor() - Function to configure stats avg. factor + * @wma: pointer to WMA handle + * @avg_factor: stats. avg. factor passed down by userspace + * + * This function configures the avg. stats value in firmware + * + * Return: QDF_STATUS_SUCCESS for success otherwise failure + * + */ +static QDF_STATUS wma_config_stats_factor(tp_wma_handle wma, + struct sir_stats_avg_factor *avg_factor) +{ + QDF_STATUS ret; + + if (NULL == wma || NULL == avg_factor) { + WMA_LOGE("%s: Invalid input of stats avg factor", __func__); + return QDF_STATUS_E_FAILURE; + } + + ret = wma_vdev_set_param(wma->wmi_handle, + avg_factor->vdev_id, + WMI_VDEV_PARAM_STATS_AVG_FACTOR, + avg_factor->stats_avg_factor); + if (QDF_IS_STATUS_ERROR(ret)) { + WMA_LOGE(" failed to set avg_factor for vdev_id %d", + avg_factor->vdev_id); + } + + WMA_LOGD("%s: Set stats_avg_factor %d for vdev_id %d", __func__, + avg_factor->stats_avg_factor, avg_factor->vdev_id); + + return ret; +} + +/** + * wma_config_guard_time() - Function to set guard time in firmware + * @wma: pointer to WMA handle + * @guard_time: guard time passed down by userspace + * + * This function configures the guard time in firmware + * + * Return: QDF_STATUS_SUCCESS for success otherwise failure + * + */ +static QDF_STATUS wma_config_guard_time(tp_wma_handle wma, + struct sir_guard_time_request *guard_time) +{ + QDF_STATUS ret; + + if (NULL == wma || NULL == guard_time) { + WMA_LOGE("%s: Invalid input of guard time", __func__); + return QDF_STATUS_E_FAILURE; + } + + ret = wma_vdev_set_param(wma->wmi_handle, + guard_time->vdev_id, + WMI_VDEV_PARAM_RX_LEAK_WINDOW, + guard_time->guard_time); + if (QDF_IS_STATUS_ERROR(ret)) { + WMA_LOGE(" failed to set guard time for vdev_id %d", + guard_time->vdev_id); + } + + WMA_LOGD("Set guard time %d for vdev_id %d", + guard_time->guard_time, guard_time->vdev_id); + + return ret; +} + +/** + * wma_enable_specific_fw_logs() - Start/Stop logging of diag event/log id + * @wma_handle: WMA handle + * @start_log: Start logging related parameters + * + * Send the command to the FW based on which specific logging of diag + * event/log id can be started/stopped + * + * Return: None + */ +static void wma_enable_specific_fw_logs(tp_wma_handle wma_handle, + struct sir_wifi_start_log *start_log) +{ + + if (!start_log) { + WMA_LOGE("%s: start_log pointer is NULL", __func__); + return; + } + if (!wma_handle) { + WMA_LOGE("%s: Invalid wma handle", __func__); + return; + } + + if (!((start_log->ring_id == RING_ID_CONNECTIVITY) || + (start_log->ring_id == RING_ID_FIRMWARE_DEBUG))) { + WMA_LOGD("%s: Not connectivity or fw debug ring: %d", + __func__, start_log->ring_id); + return; + } + + wmi_unified_enable_specific_fw_logs_cmd(wma_handle->wmi_handle, + (struct wmi_wifi_start_log *)start_log); + + return; +} + +#define MEGABYTE (1024 * 1024) +/** + * wma_set_wifi_start_packet_stats() - Start/stop packet stats + * @wma_handle: WMA handle + * @start_log: Struture containing the start wifi logger params + * + * This function is used to send the WMA commands to start/stop logging + * of per packet statistics + * + * Return: None + * + */ +#ifdef REMOVE_PKT_LOG +static void wma_set_wifi_start_packet_stats(void *wma_handle, + struct sir_wifi_start_log *start_log) +{ + return; +} +#else +static void wma_set_wifi_start_packet_stats(void *wma_handle, + struct sir_wifi_start_log *start_log) +{ + struct hif_opaque_softc *scn; + uint32_t log_state; + + if (!start_log) { + WMA_LOGE("%s: start_log pointer is NULL", __func__); + return; + } + if (!wma_handle) { + WMA_LOGE("%s: Invalid wma handle", __func__); + return; + } + + /* No need to register for ring IDs other than packet stats */ + if (start_log->ring_id != RING_ID_PER_PACKET_STATS) { + WMA_LOGI("%s: Ring id is not for per packet stats: %d", + __func__, start_log->ring_id); + return; + } + + scn = cds_get_context(QDF_MODULE_ID_HIF); + if (scn == NULL) { + WMA_LOGE("%s: Invalid HIF handle", __func__); + return; + } + + log_state = ATH_PKTLOG_ANI | ATH_PKTLOG_RCUPDATE | ATH_PKTLOG_RCFIND | + ATH_PKTLOG_RX | ATH_PKTLOG_TX | + ATH_PKTLOG_TEXT | ATH_PKTLOG_SW_EVENT; + + if (start_log->size != 0) { + pktlog_setsize(scn, start_log->size * MEGABYTE); + return; + } else if (start_log->is_pktlog_buff_clear == true) { + pktlog_clearbuff(scn, start_log->is_pktlog_buff_clear); + return; + } + + if (start_log->verbose_level == WLAN_LOG_LEVEL_ACTIVE) { + pktlog_enable(scn, log_state, start_log->ini_triggered, + start_log->user_triggered, + start_log->is_iwpriv_command); + } else { + pktlog_enable(scn, 0, start_log->ini_triggered, + start_log->user_triggered, + start_log->is_iwpriv_command); + } +} +#endif + +/** + * wma_send_flush_logs_to_fw() - Send log flush command to FW + * @wma_handle: WMI handle + * + * This function is used to send the flush command to the FW, + * that will flush the fw logs that are residue in the FW + * + * Return: None + */ +void wma_send_flush_logs_to_fw(tp_wma_handle wma_handle) +{ + QDF_STATUS status; + int ret; + + ret = wmi_unified_flush_logs_to_fw_cmd(wma_handle->wmi_handle); + if (ret != EOK) + return; + + status = qdf_mc_timer_start(&wma_handle->log_completion_timer, + WMA_LOG_COMPLETION_TIMER); + if (status != QDF_STATUS_SUCCESS) + WMA_LOGE("Failed to start the log completion timer"); +} + +/** + * wma_update_wep_default_key - To update default key id + * @wma: pointer to wma handler + * @update_def_key: pointer to wep_update_default_key_idx + * + * This function makes a copy of default key index to txrx node + * + * Return: Success + */ +static QDF_STATUS wma_update_wep_default_key(tp_wma_handle wma, + struct wep_update_default_key_idx *update_def_key) +{ + struct wma_txrx_node *iface = + &wma->interfaces[update_def_key->session_id]; + iface->wep_default_key_idx = update_def_key->default_idx; + + return QDF_STATUS_SUCCESS; +} + +/** + * wma_update_tx_fail_cnt_th() - Set threshold for TX pkt fail + * @wma_handle: WMA handle + * @tx_fail_cnt_th: sme_tx_fail_cnt_threshold parameter + * + * This function is used to set Tx pkt fail count threshold, + * FW will do disconnect with station once this threshold is reached. + * + * Return: VOS_STATUS_SUCCESS on success, error number otherwise + */ +static QDF_STATUS wma_update_tx_fail_cnt_th(tp_wma_handle wma, + struct sme_tx_fail_cnt_threshold *tx_fail_cnt_th) +{ + u_int8_t vdev_id; + u_int32_t tx_fail_disconn_th; + int ret = -EIO; + + if (!wma || !wma->wmi_handle) { + WMA_LOGE(FL("WMA is closed, can not issue Tx pkt fail count threshold")); + return QDF_STATUS_E_INVAL; + } + vdev_id = tx_fail_cnt_th->session_id; + tx_fail_disconn_th = tx_fail_cnt_th->tx_fail_cnt_threshold; + WMA_LOGD("Set TX pkt fail count threshold vdevId %d count %d", + vdev_id, tx_fail_disconn_th); + + + ret = wma_vdev_set_param(wma->wmi_handle, vdev_id, + WMI_VDEV_PARAM_DISCONNECT_TH, + tx_fail_disconn_th); + + if (ret) { + WMA_LOGE(FL("Failed to send TX pkt fail count threshold command")); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * wma_update_short_retry_limit() - Set retry limit for short frames + * @wma_handle: WMA handle + * @short_retry_limit_th: retry limir count for Short frames. + * + * This function is used to configure the transmission retry limit at which + * short frames needs to be retry. + * + * Return: VOS_STATUS_SUCCESS on success, error number otherwise + */ +static QDF_STATUS wma_update_short_retry_limit(tp_wma_handle wma, + struct sme_short_retry_limit *short_retry_limit_th) +{ + uint8_t vdev_id; + uint32_t short_retry_limit; + int ret; + + if (!wma || !wma->wmi_handle) { + WMA_LOGE("WMA is closed, can not issue short retry limit threshold"); + return QDF_STATUS_E_INVAL; + } + vdev_id = short_retry_limit_th->session_id; + short_retry_limit = short_retry_limit_th->short_retry_limit; + WMA_LOGD("Set short retry limit threshold vdevId %d count %d", + vdev_id, short_retry_limit); + + ret = wma_vdev_set_param(wma->wmi_handle, vdev_id, + WMI_VDEV_PARAM_NON_AGG_SW_RETRY_TH, + short_retry_limit); + + if (ret) { + WMA_LOGE("Failed to send short limit threshold command"); + return QDF_STATUS_E_FAILURE; + } + return QDF_STATUS_SUCCESS; +} + +/** + * wma_update_long_retry_limit() - Set retry limit for long frames + * @wma_handle: WMA handle + * @long_retry_limit_th: retry limir count for long frames + * + * This function is used to configure the transmission retry limit at which + * long frames needs to be retry + * + * Return: VOS_STATUS_SUCCESS on success, error number otherwise + */ +static QDF_STATUS wma_update_long_retry_limit(tp_wma_handle wma, + struct sme_long_retry_limit *long_retry_limit_th) +{ + uint8_t vdev_id; + uint32_t long_retry_limit; + int ret; + + if (!wma || !wma->wmi_handle) { + WMA_LOGE("WMA is closed, can not issue long retry limit threshold"); + return QDF_STATUS_E_INVAL; + } + vdev_id = long_retry_limit_th->session_id; + long_retry_limit = long_retry_limit_th->long_retry_limit; + WMA_LOGD("Set TX pkt fail count threshold vdevId %d count %d", + vdev_id, long_retry_limit); + + ret = wma_vdev_set_param(wma->wmi_handle, vdev_id, + WMI_VDEV_PARAM_AGG_SW_RETRY_TH, + long_retry_limit); + + if (ret) { + WMA_LOGE("Failed to send long limit threshold command"); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/* + * wma_update_sta_inactivity_timeout() - Set sta_inactivity_timeout to fw + * @wma_handle: WMA handle + * @sta_inactivity_timer: sme_sta_inactivity_timeout + * + * This function is used to set sta_inactivity_timeout. + * If a station does not send anything in sta_inactivity_timeout seconds, an + * empty data frame is sent to it in order to verify whether it is + * still in range. If this frame is not ACKed, the station will be + * disassociated and then deauthenticated. + * + * Return: None + */ +void wma_update_sta_inactivity_timeout(tp_wma_handle wma, + struct sme_sta_inactivity_timeout *sta_inactivity_timer) +{ + uint8_t vdev_id; + uint32_t max_unresponsive_time; + uint32_t min_inactive_time, max_inactive_time; + + if (!wma || !wma->wmi_handle) { + WMA_LOGE("WMA is closed, can not issue sta_inactivity_timeout"); + return; + } + vdev_id = sta_inactivity_timer->session_id; + max_unresponsive_time = sta_inactivity_timer->sta_inactivity_timeout; + max_inactive_time = max_unresponsive_time * TWO_THIRD; + min_inactive_time = max_unresponsive_time - max_inactive_time; + + if (wma_vdev_set_param(wma->wmi_handle, vdev_id, + WMI_VDEV_PARAM_AP_KEEPALIVE_MIN_IDLE_INACTIVE_TIME_SECS, + min_inactive_time)) + WMA_LOGE("Failed to Set AP MIN IDLE INACTIVE TIME"); + + if (wma_vdev_set_param(wma->wmi_handle, vdev_id, + WMI_VDEV_PARAM_AP_KEEPALIVE_MAX_IDLE_INACTIVE_TIME_SECS, + max_inactive_time)) + WMA_LOGE("Failed to Set AP MAX IDLE INACTIVE TIME"); + + if (wma_vdev_set_param(wma->wmi_handle, vdev_id, + WMI_VDEV_PARAM_AP_KEEPALIVE_MAX_UNRESPONSIVE_TIME_SECS, + max_unresponsive_time)) + WMA_LOGE("Failed to Set MAX UNRESPONSIVE TIME"); + + WMA_LOGI("%s:vdev_id:%d min_inactive_time: %u max_inactive_time: %u max_unresponsive_time: %u", + __func__, vdev_id, + min_inactive_time, max_inactive_time, + max_unresponsive_time); +} + +#ifdef WLAN_FEATURE_WOW_PULSE + + +#define WMI_WOW_HOSTWAKEUP_GPIO_CMD_FIXED_PARAM \ +WMI_WOW_HOSTWAKEUP_GPIO_PIN_PATTERN_CONFIG_CMD_fixed_param + + +#define WMITLV_TAG_HOSTWAKEUP_GPIO_CMD_FIXED_PARAM \ +WMITLV_TAG_STRUC_wmi_wow_hostwakeup_gpio_pin_pattern_config_cmd_fixed_param + +/** +* wma_send_wow_pulse_cmd() - send wmi cmd of wow pulse cmd +* infomation to fw. +* @wma_handle: wma handler +* @udp_response: wow_pulse_mode pointer +* +* Return: Return QDF_STATUS +*/ +static QDF_STATUS wma_send_wow_pulse_cmd(tp_wma_handle wma_handle, + struct wow_pulse_mode *wow_pulse_cmd) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + wmi_buf_t buf; + WMI_WOW_HOSTWAKEUP_GPIO_CMD_FIXED_PARAM *cmd; + u_int16_t len; + + len = sizeof(*cmd); + buf = wmi_buf_alloc(wma_handle->wmi_handle, len); + if (!buf) { + WMA_LOGE("wmi_buf_alloc failed"); + return QDF_STATUS_E_NOMEM; + } + + cmd = (WMI_WOW_HOSTWAKEUP_GPIO_CMD_FIXED_PARAM *)wmi_buf_data(buf); + qdf_mem_zero(cmd, len); + + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_HOSTWAKEUP_GPIO_CMD_FIXED_PARAM, + WMITLV_GET_STRUCT_TLVLEN( + WMI_WOW_HOSTWAKEUP_GPIO_CMD_FIXED_PARAM)); + + cmd->enable = wow_pulse_cmd->wow_pulse_enable; + cmd->pin = wow_pulse_cmd->wow_pulse_pin; + cmd->interval_low = wow_pulse_cmd->wow_pulse_interval_low; + cmd->interval_high = wow_pulse_cmd->wow_pulse_interval_high; + cmd->repeat_cnt = WMI_WOW_PULSE_REPEAT_CNT; + + if (wmi_unified_cmd_send(wma_handle->wmi_handle, buf, len, + WMI_WOW_HOSTWAKEUP_GPIO_PIN_PATTERN_CONFIG_CMDID)) { + WMA_LOGE("Failed to send send wow pulse"); + wmi_buf_free(buf); + status = QDF_STATUS_E_FAILURE; + } + + WMA_LOGD("%s: Exit", __func__); + return status; +} + +#undef WMI_WOW_HOSTWAKEUP_GPIO_CMD_FIXED_PARAM +#undef WMITLV_TAG_HOSTWAKEUP_GPIO_CMD_FIXED_PARAM +#undef WMI_WOW_PULSE_REPEAT_CNT + +#else +static inline QDF_STATUS wma_send_wow_pulse_cmd(tp_wma_handle wma_handle, + struct wow_pulse_mode *wow_pulse_cmd) +{ + return QDF_STATUS_E_FAILURE; +} +#endif + + +/** + * wma_process_power_debug_stats_req() - Process the Chip Power stats collect + * request and pass the Power stats request to Fw + * @wma_handle: WMA handle + * + * Return: QDF_STATUS + */ +#ifdef WLAN_POWER_DEBUGFS +static QDF_STATUS wma_process_power_debug_stats_req(tp_wma_handle wma_handle) +{ + wmi_pdev_get_chip_power_stats_cmd_fixed_param *cmd; + int32_t len; + wmi_buf_t buf; + uint8_t *buf_ptr; + int ret; + + if (!wma_handle) { + WMA_LOGE("%s: input pointer is NULL", __func__); + return QDF_STATUS_E_FAILURE; + } + + len = sizeof(*cmd); + buf = wmi_buf_alloc(wma_handle->wmi_handle, len); + if (!buf) { + WMA_LOGE("%s: Failed allocate wmi buffer", __func__); + return QDF_STATUS_E_NOMEM; + } + + buf_ptr = (u_int8_t *) wmi_buf_data(buf); + cmd = (wmi_pdev_get_chip_power_stats_cmd_fixed_param *) buf_ptr; + + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_get_chip_power_stats_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN( + wmi_pdev_get_chip_power_stats_cmd_fixed_param)); + cmd->pdev_id = 0; + + WMA_LOGD("POWER_DEBUG_STATS - Get Request Params; Pdev id - %d", + cmd->pdev_id); + ret = wmi_unified_cmd_send(wma_handle->wmi_handle, buf, len, + WMI_PDEV_GET_CHIP_POWER_STATS_CMDID); + if (ret) { + WMA_LOGE("%s: Failed to send power debug stats request", + __func__); + wmi_buf_free(buf); + return QDF_STATUS_E_FAILURE; + } + return QDF_STATUS_SUCCESS; +} +#else +static QDF_STATUS wma_process_power_debug_stats_req(tp_wma_handle wma_handle) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +void wma_mc_discard_msg(cds_msg_t *msg) +{ + switch (msg->type) { + case WMA_PROCESS_FW_EVENT: + qdf_nbuf_free(((wma_process_fw_event_params *)msg->bodyptr)-> + evt_buf); + break; + case WMA_SET_LINK_STATE: + qdf_mem_free(((tpLinkStateParams) msg->bodyptr)->callbackArg); + break; + } + + if (msg->bodyptr) { + qdf_mem_free(msg->bodyptr); + } + + msg->bodyptr = NULL; + msg->bodyval = 0; + msg->type = 0; +} + +static void wma_set_arp_req_stats(WMA_HANDLE handle, + struct set_arp_stats_params *req_buf) +{ + int status; + struct set_arp_stats *arp_stats; + tp_wma_handle wma_handle = (tp_wma_handle) handle; + + if (!wma_handle || !wma_handle->wmi_handle) { + WMA_LOGE("%s: WMA is closed, cannot send per roam config", + __func__); + return; + } + + arp_stats = (struct set_arp_stats *)req_buf; + status = wmi_unified_set_arp_stats_req(wma_handle->wmi_handle, + arp_stats); + if (status != EOK) + WMA_LOGE("%s: failed to set arp stats to FW", + __func__); +} + +static void wma_get_arp_req_stats(WMA_HANDLE handle, + struct get_arp_stats_params *req_buf) +{ + int status; + struct get_arp_stats *arp_stats; + tp_wma_handle wma_handle = (tp_wma_handle) handle; + + if (!wma_handle || !wma_handle->wmi_handle) { + WMA_LOGE("%s: WMA is closed, cannot send per roam config", + __func__); + return; + } + + arp_stats = (struct get_arp_stats *)req_buf; + status = wmi_unified_get_arp_stats_req(wma_handle->wmi_handle, + arp_stats); + if (status != EOK) + WMA_LOGE("%s: failed to send get arp stats to FW", + __func__); +} + +/** + * wma_mc_process_msg() - process wma messages and call appropriate function. + * @cds_context: cds context + * @msg: message + * + * Return: QDF_SUCCESS for success otherwise failure + */ +QDF_STATUS wma_mc_process_msg(void *cds_context, cds_msg_t *msg) +{ + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + tp_wma_handle wma_handle; + ol_txrx_vdev_handle txrx_vdev_handle = NULL; + extern uint8_t *mac_trace_get_wma_msg_string(uint16_t wmaMsg); + + if (NULL == msg) { + WMA_LOGE("msg is NULL"); + QDF_ASSERT(0); + qdf_status = QDF_STATUS_E_INVAL; + goto end; + } + + WMA_LOGD("msg->type = %x %s", msg->type, + mac_trace_get_wma_msg_string(msg->type)); + + wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + + if (NULL == wma_handle) { + WMA_LOGP("%s: wma_handle is NULL", __func__); + QDF_ASSERT(0); + qdf_mem_free(msg->bodyptr); + qdf_status = QDF_STATUS_E_INVAL; + goto end; + } + + switch (msg->type) { + + /* Message posted by wmi for all control path related + * FW events to serialize through mc_thread. + */ + case WMA_PROCESS_FW_EVENT: + wma_process_fw_event(wma_handle, + (wma_process_fw_event_params *) msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + +#ifdef FEATURE_WLAN_ESE + case WMA_TSM_STATS_REQ: + WMA_LOGD("McThread: WMA_TSM_STATS_REQ"); + wma_process_tsm_stats_req(wma_handle, (void *)msg->bodyptr); + break; +#endif /* FEATURE_WLAN_ESE */ + case WNI_CFG_DNLD_REQ: + WMA_LOGD("McThread: WNI_CFG_DNLD_REQ"); + qdf_status = wma_wni_cfg_dnld(wma_handle); + if (QDF_IS_STATUS_SUCCESS(qdf_status)) { + cds_wma_complete_cback(cds_context); + } else { + WMA_LOGD("config download failure"); + } + break; + case WMA_ADD_STA_SELF_REQ: + txrx_vdev_handle = + wma_vdev_attach(wma_handle, + (struct add_sta_self_params *) msg-> + bodyptr, 1); + if (!txrx_vdev_handle) { + WMA_LOGE("Failed to attach vdev"); + } else { + /* Register with TxRx Module for Data Ack Complete Cb */ + ol_txrx_data_tx_cb_set(txrx_vdev_handle, + wma_data_tx_ack_comp_hdlr, + wma_handle); + } + break; + case WMA_DEL_STA_SELF_REQ: + wma_vdev_detach(wma_handle, + (struct del_sta_self_params *) msg->bodyptr, 1); + break; + case WMA_START_SCAN_OFFLOAD_REQ: + wma_start_scan(wma_handle, msg->bodyptr, msg->type); + qdf_mem_free(msg->bodyptr); + break; + case WMA_STOP_SCAN_OFFLOAD_REQ: + wma_stop_scan(wma_handle, msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_UPDATE_CHAN_LIST_REQ: + wma_update_channel_list(wma_handle, + (tSirUpdateChanList *) msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_SET_LINK_STATE: + wma_set_linkstate(wma_handle, (tpLinkStateParams) msg->bodyptr); + break; + case WMA_CHNL_SWITCH_REQ: + wma_set_channel(wma_handle, + (tpSwitchChannelParams) msg->bodyptr); + break; + case WMA_ADD_BSS_REQ: + wma_add_bss(wma_handle, (tpAddBssParams) msg->bodyptr); + break; + case WMA_ADD_STA_REQ: + wma_add_sta(wma_handle, (tpAddStaParams) msg->bodyptr); + break; + case WMA_SET_BSSKEY_REQ: + wma_set_bsskey(wma_handle, (tpSetBssKeyParams) msg->bodyptr); + break; + case WMA_SET_STAKEY_REQ: + wma_set_stakey(wma_handle, (tpSetStaKeyParams) msg->bodyptr); + break; + case WMA_DELETE_STA_REQ: + wma_delete_sta(wma_handle, (tpDeleteStaParams) msg->bodyptr); + break; + case WMA_DELETE_BSS_HO_FAIL_REQ: + wma_delete_bss_ho_fail(wma_handle, + (tpDeleteBssParams) msg->bodyptr); + break; + case WMA_DELETE_BSS_REQ: + wma_delete_bss(wma_handle, (tpDeleteBssParams) msg->bodyptr); + break; + case WMA_UPDATE_EDCA_PROFILE_IND: + wma_process_update_edca_param_req(wma_handle, + (tEdcaParams *) msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_SEND_BEACON_REQ: + wma_send_beacon(wma_handle, (tpSendbeaconParams) msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_SEND_PROBE_RSP_TMPL: + wma_send_probe_rsp_tmpl(wma_handle, + (tpSendProbeRespParams) msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_CLI_SET_CMD: + wma_process_cli_set_cmd(wma_handle, + (wma_cli_set_cmd_t *) msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_SET_PDEV_IE_REQ: + wma_process_set_pdev_ie_req(wma_handle, + (struct set_ie_param *)msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; +#if !defined(REMOVE_PKT_LOG) + case WMA_PKTLOG_ENABLE_REQ: + wma_pktlog_wmi_send_cmd(wma_handle, + (struct ath_pktlog_wmi_params *)msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; +#endif /* REMOVE_PKT_LOG */ +#if defined(QCA_WIFI_FTM) + case WMA_FTM_CMD_REQ: + wma_process_ftm_command(wma_handle, + (struct ar6k_testmode_cmd_data *)msg->bodyptr); + break; +#endif /* QCA_WIFI_FTM */ + case WMA_ENTER_PS_REQ: + wma_enable_sta_ps_mode(wma_handle, + (tpEnablePsParams) msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_EXIT_PS_REQ: + wma_disable_sta_ps_mode(wma_handle, + (tpDisablePsParams) msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_ENABLE_UAPSD_REQ: + wma_enable_uapsd_mode(wma_handle, + (tpEnableUapsdParams) msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_DISABLE_UAPSD_REQ: + wma_disable_uapsd_mode(wma_handle, + (tpDisableUapsdParams) msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_SET_DTIM_PERIOD: + wma_set_dtim_period(wma_handle, + (struct set_dtim_params *)msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_SET_TX_POWER_REQ: + wma_set_tx_power(wma_handle, (tpMaxTxPowerParams) msg->bodyptr); + break; + case WMA_SET_MAX_TX_POWER_REQ: + wma_set_max_tx_power(wma_handle, + (tpMaxTxPowerParams) msg->bodyptr); + break; + case WMA_SET_KEEP_ALIVE: + wma_set_keepalive_req(wma_handle, + (tSirKeepAliveReq *) msg->bodyptr); + break; +#ifdef FEATURE_WLAN_SCAN_PNO + case WMA_SET_PNO_REQ: + wma_config_pno(wma_handle, (tpSirPNOScanReq) msg->bodyptr); + break; + + case WMA_SME_SCAN_CACHE_UPDATED: + wma_scan_cache_updated_ind(wma_handle, msg->bodyval); + break; +#endif /* FEATURE_WLAN_SCAN_PNO */ +#ifdef FEATURE_WLAN_ESE + case WMA_SET_PLM_REQ: + wma_config_plm(wma_handle, (tpSirPlmReq) msg->bodyptr); + break; +#endif + case WMA_GET_STATISTICS_REQ: + wma_get_stats_req(wma_handle, + (tAniGetPEStatsReq *) msg->bodyptr); + break; + + case WMA_CONFIG_PARAM_UPDATE_REQ: + wma_update_cfg_params(wma_handle, (tSirMsgQ *) msg); + break; + + case WMA_UPDATE_OP_MODE: + wma_process_update_opmode(wma_handle, + (tUpdateVHTOpMode *) msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_UPDATE_RX_NSS: + wma_process_update_rx_nss(wma_handle, + (tUpdateRxNss *) msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_UPDATE_MEMBERSHIP: + wma_process_update_membership(wma_handle, + (tUpdateMembership *) msg->bodyptr); + break; + case WMA_UPDATE_USERPOS: + wma_process_update_userpos(wma_handle, + (tUpdateUserPos *) msg->bodyptr); + break; + case WMA_UPDATE_BEACON_IND: + wma_process_update_beacon_params(wma_handle, + (tUpdateBeaconParams *) msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + + case WMA_ADD_TS_REQ: + wma_add_ts_req(wma_handle, (tAddTsParams *) msg->bodyptr); + break; + + case WMA_DEL_TS_REQ: + wma_del_ts_req(wma_handle, (tDelTsParams *) msg->bodyptr); + break; + + case WMA_AGGR_QOS_REQ: + wma_aggr_qos_req(wma_handle, (tAggrAddTsParams *) msg->bodyptr); + break; + + case WMA_RECEIVE_FILTER_SET_FILTER_REQ: + wma_process_receive_filter_set_filter_req(wma_handle, + (tSirRcvPktFilterCfgType *) msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + + case WMA_RECEIVE_FILTER_CLEAR_FILTER_REQ: + wma_process_receive_filter_clear_filter_req(wma_handle, + (tSirRcvFltPktClearParam *) msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + + case WMA_WOW_ADD_PTRN: + wma_wow_add_pattern(wma_handle, + (struct wow_add_pattern *) msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_WOW_DEL_PTRN: + wma_wow_delete_user_pattern(wma_handle, + (struct wow_delete_pattern *) msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_WOWL_ENTER_REQ: + wma_wow_enter(wma_handle, + (tpSirHalWowlEnterParams) msg->bodyptr); + break; + case WMA_WOWL_EXIT_REQ: + wma_wow_exit(wma_handle, (tpSirHalWowlExitParams) msg->bodyptr); + break; + + case WMA_RUNTIME_PM_SUSPEND_IND: + wma_calculate_and_update_conn_state(wma_handle); + wma_suspend_req(wma_handle, QDF_RUNTIME_SUSPEND); + break; + + case WMA_RUNTIME_PM_RESUME_IND: + wma_resume_req(wma_handle, QDF_RUNTIME_SUSPEND); + break; + + case WMA_WLAN_SUSPEND_IND: + wma_update_conn_state(wma_handle, msg->bodyval); + wma_suspend_req(wma_handle, QDF_SYSTEM_SUSPEND); + break; + case WMA_8023_MULTICAST_LIST_REQ: + wma_process_mcbc_set_filter_req(wma_handle, + (tpSirRcvFltMcAddrList) msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; +#ifdef WLAN_FEATURE_GTK_OFFLOAD + case WMA_GTK_OFFLOAD_REQ: + wma_process_gtk_offload_req(wma_handle, + (tpSirGtkOffloadParams) msg->bodyptr); + break; + + case WMA_GTK_OFFLOAD_GETINFO_REQ: + wma_process_gtk_offload_getinfo_req(wma_handle, + (tpSirGtkOffloadGetInfoRspParams)msg->bodyptr); + break; +#endif /* WLAN_FEATURE_GTK_OFFLOAD */ + case WMA_SET_HOST_OFFLOAD: + wma_enable_arp_ns_offload(wma_handle, + (tpSirHostOffloadReq) msg->bodyptr, + true); + break; +#ifdef WLAN_NS_OFFLOAD + case WMA_SET_NS_OFFLOAD: + wma_enable_arp_ns_offload(wma_handle, + (tpSirHostOffloadReq) msg->bodyptr, + false); + break; +#endif /*WLAN_NS_OFFLOAD */ + case WMA_ROAM_SCAN_OFFLOAD_REQ: + /* + * Main entry point or roaming directives from CSR. + */ + wma_process_roaming_config(wma_handle, + (tSirRoamOffloadScanReq *) msg->bodyptr); + break; + + case WMA_RATE_UPDATE_IND: + wma_process_rate_update_indicate(wma_handle, + (tSirRateUpdateInd *) msg->bodyptr); + break; + +#ifdef FEATURE_WLAN_TDLS + case WMA_UPDATE_FW_TDLS_STATE: + wma_update_fw_tdls_state(wma_handle, + (t_wma_tdls_params *) msg->bodyptr); + break; + case WMA_UPDATE_TDLS_PEER_STATE: + wma_update_tdls_peer_state(wma_handle, + (tTdlsPeerStateParams *) msg->bodyptr); + break; + case WMA_TDLS_SET_OFFCHAN_MODE: + wma_set_tdls_offchan_mode(wma_handle, + (tdls_chan_switch_params *)msg->bodyptr); + break; +#endif /* FEATURE_WLAN_TDLS */ + case WMA_ADD_PERIODIC_TX_PTRN_IND: + wma_process_add_periodic_tx_ptrn_ind(wma_handle, + (tSirAddPeriodicTxPtrn *) msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_DEL_PERIODIC_TX_PTRN_IND: + wma_process_del_periodic_tx_ptrn_ind(wma_handle, + (tSirDelPeriodicTxPtrn *) msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_TX_POWER_LIMIT: + wma_process_tx_power_limits(wma_handle, + (tSirTxPowerLimit *) msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; +#ifdef FEATURE_WLAN_LPHB + case WMA_LPHB_CONF_REQ: + wma_process_lphb_conf_req(wma_handle, + (tSirLPHBReq *) msg->bodyptr); + break; +#endif /* FEATURE_WLAN_LPHB */ + +#ifdef FEATURE_WLAN_CH_AVOID + case WMA_CH_AVOID_UPDATE_REQ: + wma_process_ch_avoid_update_req(wma_handle, + (tSirChAvoidUpdateReq *) msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; +#endif /* FEATURE_WLAN_CH_AVOID */ +#ifdef FEATURE_WLAN_AUTO_SHUTDOWN + case WMA_SET_AUTO_SHUTDOWN_TIMER_REQ: + wma_set_auto_shutdown_timer_req(wma_handle, msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; +#endif /* FEATURE_WLAN_AUTO_SHUTDOWN */ + case WMA_DHCP_START_IND: + case WMA_DHCP_STOP_IND: + wma_process_dhcp_ind(wma_handle, (tAniDHCPInd *) msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + + case WMA_IBSS_CESIUM_ENABLE_IND: + wma_process_cesium_enable_ind(wma_handle); + break; + case WMA_GET_IBSS_PEER_INFO_REQ: + wma_process_get_peer_info_req(wma_handle, + (tSirIbssGetPeerInfoReqParams *) + msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_TX_FAIL_MONITOR_IND: + wma_process_tx_fail_monitor_ind(wma_handle, + (tAniTXFailMonitorInd *) msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + + case WMA_RMC_ENABLE_IND: + wma_process_rmc_enable_ind(wma_handle); + break; + case WMA_RMC_DISABLE_IND: + wma_process_rmc_disable_ind(wma_handle); + break; + case WMA_RMC_ACTION_PERIOD_IND: + wma_process_rmc_action_period_ind(wma_handle); + break; + case WMA_INIT_THERMAL_INFO_CMD: + wma_process_init_thermal_info(wma_handle, + (t_thermal_mgmt *) msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + + case WMA_SET_THERMAL_LEVEL: + wma_process_set_thermal_level(wma_handle, msg->bodyval); + break; +#ifdef CONFIG_HL_SUPPORT + case WMA_INIT_BAD_PEER_TX_CTL_INFO_CMD: + wma_process_init_bad_peer_tx_ctl_info( + wma_handle, + (struct t_bad_peer_txtcl_config *)msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; +#endif + case WMA_SET_P2P_GO_NOA_REQ: + wma_process_set_p2pgo_noa_req(wma_handle, + (tP2pPsParams *) msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_SET_MIMOPS_REQ: + wma_process_set_mimops_req(wma_handle, + (tSetMIMOPS *) msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_SET_SAP_INTRABSS_DIS: + wma_set_vdev_intrabss_fwd(wma_handle, + (tDisableIntraBssFwd *) msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_MODEM_POWER_STATE_IND: + wma_notify_modem_power_state(wma_handle, + (tSirModemPowerStateInd *) msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_WLAN_RESUME_REQ: + wma_resume_req(wma_handle, QDF_SYSTEM_SUSPEND); + break; + +#ifdef WLAN_FEATURE_STATS_EXT + case WMA_STATS_EXT_REQUEST: + wma_stats_ext_req(wma_handle, + (tpStatsExtRequest) (msg->bodyptr)); + qdf_mem_free(msg->bodyptr); + break; +#endif /* WLAN_FEATURE_STATS_EXT */ + case WMA_HIDDEN_SSID_VDEV_RESTART: + wma_hidden_ssid_vdev_restart(wma_handle, + (tHalHiddenSsidVdevRestart *) msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; +#ifdef WLAN_FEATURE_EXTWOW_SUPPORT + case WMA_WLAN_EXT_WOW: + wma_enable_ext_wow(wma_handle, + (tSirExtWoWParams *) msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_WLAN_SET_APP_TYPE1_PARAMS: + wma_set_app_type1_params_in_fw(wma_handle, + (tSirAppType1Params *) msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_WLAN_SET_APP_TYPE2_PARAMS: + wma_set_app_type2_params_in_fw(wma_handle, + (tSirAppType2Params *) msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; +#endif /* WLAN_FEATURE_EXTWOW_SUPPORT */ +#ifdef FEATURE_WLAN_EXTSCAN + case WMA_EXTSCAN_START_REQ: + wma_start_extscan(wma_handle, + (tSirWifiScanCmdReqParams *) msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_EXTSCAN_STOP_REQ: + wma_stop_extscan(wma_handle, + (tSirExtScanStopReqParams *) msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_EXTSCAN_SET_BSSID_HOTLIST_REQ: + wma_extscan_start_hotlist_monitor(wma_handle, + (tSirExtScanSetBssidHotListReqParams *) msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_EXTSCAN_RESET_BSSID_HOTLIST_REQ: + wma_extscan_stop_hotlist_monitor(wma_handle, + (tSirExtScanResetBssidHotlistReqParams *) msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_EXTSCAN_SET_SIGNF_CHANGE_REQ: + wma_extscan_start_change_monitor(wma_handle, + (tSirExtScanSetSigChangeReqParams *) msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_EXTSCAN_RESET_SIGNF_CHANGE_REQ: + wma_extscan_stop_change_monitor(wma_handle, + (tSirExtScanResetSignificantChangeReqParams *) msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_EXTSCAN_GET_CACHED_RESULTS_REQ: + wma_extscan_get_cached_results(wma_handle, + (tSirExtScanGetCachedResultsReqParams *) msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_EXTSCAN_GET_CAPABILITIES_REQ: + wma_extscan_get_capabilities(wma_handle, + (tSirGetExtScanCapabilitiesReqParams *) msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_SET_EPNO_LIST_REQ: + wma_set_epno_network_list(wma_handle, + (struct wifi_epno_params *)msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_SET_PER_ROAM_CONFIG_CMD: + wma_update_per_roam_config(wma_handle, + (struct wmi_per_roam_config_req *)msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_SET_PASSPOINT_LIST_REQ: + /* Issue reset passpoint network list first and clear + * the entries */ + wma_reset_passpoint_network_list(wma_handle, + (struct wifi_passpoint_req *)msg->bodyptr); + + wma_set_passpoint_network_list(wma_handle, + (struct wifi_passpoint_req *)msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_RESET_PASSPOINT_LIST_REQ: + wma_reset_passpoint_network_list(wma_handle, + (struct wifi_passpoint_req *)msg->bodyptr); + break; +#endif /* FEATURE_WLAN_EXTSCAN */ + case WMA_SET_SCAN_MAC_OUI_REQ: + wma_scan_probe_setoui(wma_handle, msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; +#ifdef WLAN_FEATURE_LINK_LAYER_STATS + case WMA_LINK_LAYER_STATS_CLEAR_REQ: + wma_process_ll_stats_clear_req(wma_handle, + (tpSirLLStatsClearReq) msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_LINK_LAYER_STATS_SET_REQ: + wma_process_ll_stats_set_req(wma_handle, + (tpSirLLStatsSetReq) msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_LINK_LAYER_STATS_GET_REQ: + wma_process_ll_stats_get_req(wma_handle, + (tpSirLLStatsGetReq) msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; +#endif /* WLAN_FEATURE_LINK_LAYER_STATS */ + case SIR_HAL_UNIT_TEST_CMD: + wma_process_unit_test_cmd(wma_handle, + (t_wma_unit_test_cmd *) msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + case WMA_ROAM_OFFLOAD_SYNCH_FAIL: + wma_process_roam_synch_fail(wma_handle, + (struct roam_offload_synch_fail *)msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case SIR_HAL_ROAM_INVOKE: + wma_process_roam_invoke(wma_handle, + (struct wma_roam_invoke_cmd *)msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; +#endif /* WLAN_FEATURE_ROAM_OFFLOAD */ +#ifdef WLAN_FEATURE_NAN + case WMA_NAN_REQUEST: + wma_nan_req(wma_handle, (tNanRequest *) msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; +#endif /* WLAN_FEATURE_NAN */ + case SIR_HAL_SET_BASE_MACADDR_IND: + wma_set_base_macaddr_indicate(wma_handle, + (tSirMacAddr *) msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_LINK_STATUS_GET_REQ: + wma_process_link_status_req(wma_handle, + (tAniGetLinkStatus *) msg->bodyptr); + break; + case WMA_GET_TEMPERATURE_REQ: + wma_get_temperature(wma_handle); + qdf_mem_free(msg->bodyptr); + break; + case WMA_TSF_GPIO_PIN: + wma_set_tsf_gpio_pin(wma_handle, msg->bodyval); + break; + +#ifdef DHCP_SERVER_OFFLOAD + case WMA_SET_DHCP_SERVER_OFFLOAD_CMD: + wma_process_dhcpserver_offload(wma_handle, + (tSirDhcpSrvOffloadInfo *) msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; +#endif /* DHCP_SERVER_OFFLOAD */ +#ifdef WLAN_FEATURE_GPIO_LED_FLASHING + case WMA_LED_FLASHING_REQ: + wma_set_led_flashing(wma_handle, + (tSirLedFlashingReq *) msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; +#endif /* WLAN_FEATURE_GPIO_LED_FLASHING */ + case SIR_HAL_SET_MAS: + wma_process_set_mas(wma_handle, + (uint32_t *)msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case SIR_HAL_SET_MIRACAST: + wma_process_set_miracast(wma_handle, + (uint32_t *)msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case SIR_HAL_CONFIG_STATS_FACTOR: + wma_config_stats_factor(wma_handle, + (struct sir_stats_avg_factor *) + msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case SIR_HAL_CONFIG_GUARD_TIME: + wma_config_guard_time(wma_handle, + (struct sir_guard_time_request *) + msg->bodyptr); + case WMA_IPA_OFFLOAD_ENABLE_DISABLE: + wma_ipa_offload_enable_disable(wma_handle, + (struct sir_ipa_offload_enable_disable *)msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case SIR_HAL_START_STOP_LOGGING: + wma_set_wifi_start_packet_stats(wma_handle, + (struct sir_wifi_start_log *)msg->bodyptr); + wma_enable_specific_fw_logs(wma_handle, + (struct sir_wifi_start_log *)msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case SIR_HAL_FLUSH_LOG_TO_FW: + wma_send_flush_logs_to_fw(wma_handle); + /* Body ptr is NULL here */ + break; + case WMA_SET_RSSI_MONITOR_REQ: + wma_set_rssi_monitoring(wma_handle, + (struct rssi_monitor_req *)msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WDA_SET_UDP_RESP_OFFLOAD: + wma_send_udp_resp_offload_cmd(wma_handle, + (struct udp_resp_offload *)msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_FW_MEM_DUMP_REQ: + wma_process_fw_mem_dump_req(wma_handle, + (struct fw_dump_req *)msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case SIR_HAL_PDEV_SET_PCL_TO_FW: + wma_send_pdev_set_pcl_cmd(wma_handle, + (struct wmi_pcl_chan_weights *)msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case SIR_HAL_PDEV_SET_HW_MODE: + wma_send_pdev_set_hw_mode_cmd(wma_handle, + (struct sir_hw_mode *)msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_OCB_SET_CONFIG_CMD: + wma_ocb_set_config_req(wma_handle, + (struct sir_ocb_config *)msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_OCB_SET_UTC_TIME_CMD: + wma_ocb_set_utc_time(wma_handle, + (struct sir_ocb_utc *)msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_OCB_START_TIMING_ADVERT_CMD: + wma_ocb_start_timing_advert(wma_handle, + (struct sir_ocb_timing_advert *)msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_OCB_STOP_TIMING_ADVERT_CMD: + wma_ocb_stop_timing_advert(wma_handle, + (struct sir_ocb_timing_advert *)msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_DCC_CLEAR_STATS_CMD: + wma_dcc_clear_stats(wma_handle, + (struct sir_dcc_clear_stats *)msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_OCB_GET_TSF_TIMER_CMD: + wma_ocb_get_tsf_timer(wma_handle, + (struct sir_ocb_get_tsf_timer *)msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_SET_WISA_PARAMS: + wma_set_wisa_params(wma_handle, + (struct sir_wisa_params *)msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_DCC_GET_STATS_CMD: + wma_dcc_get_stats(wma_handle, + (struct sir_dcc_get_stats *)msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_DCC_UPDATE_NDL_CMD: + wma_dcc_update_ndl(wma_handle, + (struct sir_dcc_update_ndl *)msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case SIR_HAL_PDEV_DUAL_MAC_CFG_REQ: + wma_send_pdev_set_dual_mac_config(wma_handle, + (struct sir_dual_mac_config *)msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_SET_IE_INFO: + wma_process_set_ie_info(wma_handle, + (struct vdev_ie_info *)msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case SIR_HAL_SOC_ANTENNA_MODE_REQ: + wma_send_pdev_set_antenna_mode(wma_handle, + (struct sir_antenna_mode_param *)msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_LRO_CONFIG_CMD: + wma_lro_config_cmd(wma_handle, + (struct wma_lro_config_cmd_t *)msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_GW_PARAM_UPDATE_REQ: + wma_set_gateway_params(wma_handle, + (struct gateway_param_update_req *)msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_SET_EGAP_CONF_PARAMS: + wma_send_egap_conf_params(wma_handle, + (struct egap_conf_params *)msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_SET_ADAPT_DWELLTIME_CONF_PARAMS: + wma_send_adapt_dwelltime_params(wma_handle, + (struct adaptive_dwelltime_params *)msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_HT40_OBSS_SCAN_IND: + wma_send_ht40_obss_scanind(wma_handle, + (struct obss_ht40_scanind *)msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_ADD_BCN_FILTER_CMDID: + wma_add_beacon_filter(wma_handle, msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_REMOVE_BCN_FILTER_CMDID: + wma_remove_beacon_filter(wma_handle, msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WDA_BPF_GET_CAPABILITIES_REQ: + wma_get_bpf_capabilities(wma_handle); + break; + case WDA_BPF_SET_INSTRUCTIONS_REQ: + wma_set_bpf_instructions(wma_handle, msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case SIR_HAL_NDP_INITIATOR_REQ: + wma_handle_ndp_initiator_req(wma_handle, msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + + case SIR_HAL_NDP_RESPONDER_REQ: + wma_handle_ndp_responder_req(wma_handle, msg->bodyptr); + break; + + case SIR_HAL_NDP_END_REQ: + wma_handle_ndp_end_req(wma_handle, msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case SIR_HAL_POWER_DBG_CMD: + wma_process_hal_pwr_dbg_cmd(wma_handle, + msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_UPDATE_WEP_DEFAULT_KEY: + wma_update_wep_default_key(wma_handle, + (struct wep_update_default_key_idx *)msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_SEND_FREQ_RANGE_CONTROL_IND: + wma_enable_disable_caevent_ind(wma_handle, msg->bodyval); + break; + case WMA_ENCRYPT_DECRYPT_MSG: + wma_encrypt_decrypt_msg(wma_handle, msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case SIR_HAL_UPDATE_TX_FAIL_CNT_TH: + wma_update_tx_fail_cnt_th(wma_handle, msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case SIR_HAL_LONG_RETRY_LIMIT_CNT: + wma_update_long_retry_limit(wma_handle, msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case SIR_HAL_SHORT_RETRY_LIMIT_CNT: + wma_update_short_retry_limit(wma_handle, msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case SIR_HAL_POWER_DEBUG_STATS_REQ: + wma_process_power_debug_stats_req(wma_handle); + break; + case WMA_SET_WOW_PULSE_CMD: + wma_send_wow_pulse_cmd(wma_handle, + (struct wow_pulse_mode *)msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_GET_RCPI_REQ: + wma_get_rcpi_req(wma_handle, + (struct sme_rcpi_req *)msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_CONF_HW_FILTER: { + struct hw_filter_request *req = msg->bodyptr; + + qdf_status = wma_conf_hw_filter_mode(wma_handle, req); + break; + } + case WMA_SET_ARP_STATS_REQ: + wma_set_arp_req_stats(wma_handle, + (struct set_arp_stats_params *)msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_GET_ARP_STATS_REQ: + wma_get_arp_req_stats(wma_handle, + (struct get_arp_stats_params *)msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + default: + WMA_LOGE("Unhandled WMA message of type %d", msg->type); + if (msg->bodyptr) + qdf_mem_free(msg->bodyptr); + } +end: + return qdf_status; +} + +/** + * wma_log_completion_timeout() - Log completion timeout + * @data: Timeout handler data + * + * This function is called when log completion timer expires + * + * Return: None + */ +void wma_log_completion_timeout(void *data) +{ + tp_wma_handle wma_handle; + + WMA_LOGE("%s: Timeout occured for log completion command", __func__); + + wma_handle = (tp_wma_handle) data; + if (!wma_handle) + WMA_LOGE("%s: Invalid WMA handle", __func__); + + /* Though we did not receive any event from FW, + * we can flush whatever logs we have with us */ + cds_logging_set_fw_flush_complete(); + + return; +} + +/** + * wma_map_pcl_weights() - Map PCL weights + * @pcl_weight: Internal PCL weights + * + * Maps the internal weights of PCL to the weights needed by FW + * + * Return: Mapped channel weight of type wmi_pcl_chan_weight + */ +static wmi_pcl_chan_weight wma_map_pcl_weights(uint32_t pcl_weight) +{ + switch (pcl_weight) { + case WEIGHT_OF_GROUP1_PCL_CHANNELS: + return WMI_PCL_WEIGHT_VERY_HIGH; + case WEIGHT_OF_GROUP2_PCL_CHANNELS: + return WMI_PCL_WEIGHT_HIGH; + case WEIGHT_OF_GROUP3_PCL_CHANNELS: + return WMI_PCL_WEIGHT_MEDIUM; + case WEIGHT_OF_NON_PCL_CHANNELS: + return WMI_PCL_WEIGHT_LOW; + default: + return WMI_PCL_WEIGHT_DISALLOW; + } +} + +/** + * wma_send_pdev_set_pcl_cmd() - Send WMI_SOC_SET_PCL_CMDID to FW + * @wma_handle: WMA handle + * @msg: PCL structure containing the PCL and the number of channels + * + * WMI_PDEV_SET_PCL_CMDID provides a Preferred Channel List (PCL) to the WLAN + * firmware. The DBS Manager is the consumer of this information in the WLAN + * firmware. The channel list will be used when a Virtual DEVice (VDEV) needs + * to migrate to a new channel without host driver involvement. An example of + * this behavior is Legacy Fast Roaming (LFR 3.0). Generally, the host will + * manage the channel selection without firmware involvement. + * + * WMI_PDEV_SET_PCL_CMDID will carry only the weight list and not the actual + * channel list. The weights corresponds to the channels sent in + * WMI_SCAN_CHAN_LIST_CMDID. The channels from PCL would be having a higher + * weightage compared to the non PCL channels. + * + * Return: Success if the cmd is sent successfully to the firmware + */ +QDF_STATUS wma_send_pdev_set_pcl_cmd(tp_wma_handle wma_handle, + struct wmi_pcl_chan_weights *msg) +{ + uint32_t i; + QDF_STATUS status; + + if (!wma_handle) { + WMA_LOGE("%s: WMA handle is NULL. Cannot issue command", + __func__); + return QDF_STATUS_E_NULL_VALUE; + } + + for (i = 0; i < wma_handle->saved_chan.num_channels; i++) { + msg->saved_chan_list[i] = + wma_handle->saved_chan.channel_list[i]; + } + + msg->saved_num_chan = wma_handle->saved_chan.num_channels; + status = cds_get_valid_chan_weights((struct sir_pcl_chan_weights *)msg); + + for (i = 0; i < msg->saved_num_chan; i++) { + msg->weighed_valid_list[i] = + wma_map_pcl_weights(msg->weighed_valid_list[i]); + WMA_LOGD("%s: chan:%d weight[%d]=%d", __func__, + msg->saved_chan_list[i], i, + msg->weighed_valid_list[i]); + } + + if (!QDF_IS_STATUS_SUCCESS(status)) { + WMA_LOGE("%s: Error in creating weighed pcl", __func__); + return status; + } + + if (wmi_unified_pdev_set_pcl_cmd(wma_handle->wmi_handle, msg)) + return QDF_STATUS_E_FAILURE; + + return QDF_STATUS_SUCCESS; +} + +/** + * wma_send_pdev_set_hw_mode_cmd() - Send WMI_PDEV_SET_HW_MODE_CMDID to FW + * @wma_handle: WMA handle + * @msg: Structure containing the following parameters + * + * - hw_mode_index: The HW_Mode field is a enumerated type that is selected + * from the HW_Mode table, which is returned in the WMI_SERVICE_READY_EVENTID. + * + * Provides notification to the WLAN firmware that host driver is requesting a + * HardWare (HW) Mode change. This command is needed to support iHelium in the + * configurations that include the Dual Band Simultaneous (DBS) feature. + * + * Return: Success if the cmd is sent successfully to the firmware + */ +QDF_STATUS wma_send_pdev_set_hw_mode_cmd(tp_wma_handle wma_handle, + struct sir_hw_mode *msg) +{ + struct sir_set_hw_mode_resp *param; + + if (!wma_handle) { + WMA_LOGE("%s: WMA handle is NULL. Cannot issue command", + __func__); + /* Handle is NULL. Will not be able to send failure + * response as well + */ + return QDF_STATUS_E_NULL_VALUE; + } + + if (!msg) { + WMA_LOGE("%s: Set HW mode param is NULL", __func__); + /* Lets try to free the active command list */ + goto fail; + } + + if (wmi_unified_soc_set_hw_mode_cmd(wma_handle->wmi_handle, + msg->hw_mode_index)) + goto fail; + + return QDF_STATUS_SUCCESS; +fail: + param = qdf_mem_malloc(sizeof(*param)); + if (!param) { + WMA_LOGE("%s: Memory allocation failed", __func__); + return QDF_STATUS_E_NULL_VALUE; + } + param->status = SET_HW_MODE_STATUS_ECANCELED; + param->cfgd_hw_mode_index = 0; + param->num_vdev_mac_entries = 0; + WMA_LOGE("%s: Sending HW mode fail response to LIM", __func__); + wma_send_msg(wma_handle, SIR_HAL_PDEV_SET_HW_MODE_RESP, + (void *) param, 0); + return QDF_STATUS_SUCCESS; +} + +/** + * wma_send_pdev_set_dual_mac_config() - Set dual mac config to FW + * @wma_handle: WMA handle + * @msg: Dual MAC config parameters + * + * Configures WLAN firmware with the dual MAC features + * + * Return: QDF_STATUS. 0 on success. + */ +QDF_STATUS wma_send_pdev_set_dual_mac_config(tp_wma_handle wma_handle, + struct sir_dual_mac_config *msg) +{ + QDF_STATUS status; + + if (!wma_handle) { + WMA_LOGE("%s: WMA handle is NULL. Cannot issue command", + __func__); + return QDF_STATUS_E_NULL_VALUE; + } + + if (!msg) { + WMA_LOGE("%s: Set dual mode config is NULL", __func__); + return QDF_STATUS_E_NULL_VALUE; + } + + status = wmi_unified_pdev_set_dual_mac_config_cmd( + wma_handle->wmi_handle, + (struct wmi_dual_mac_config *)msg); + if (QDF_IS_STATUS_ERROR(status)) { + WMA_LOGE("%s: Failed to send WMI_PDEV_SET_DUAL_MAC_CONFIG_CMDID: %d", + __func__, status); + return status; + } + + wma_handle->dual_mac_cfg.req_scan_config = msg->scan_config; + wma_handle->dual_mac_cfg.req_fw_mode_config = msg->fw_mode_config; + + return QDF_STATUS_SUCCESS; +} + +/** + * wma_send_pdev_set_antenna_mode() - Set antenna mode to FW + * @wma_handle: WMA handle + * @msg: Antenna mode parameters + * + * Send WMI_PDEV_SET_ANTENNA_MODE_CMDID to FW requesting to + * modify the number of TX/RX chains from host + * + * Return: QDF_STATUS. 0 on success. + */ +QDF_STATUS wma_send_pdev_set_antenna_mode(tp_wma_handle wma_handle, + struct sir_antenna_mode_param *msg) +{ + wmi_pdev_set_antenna_mode_cmd_fixed_param *cmd; + wmi_buf_t buf; + uint32_t len; + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct sir_antenna_mode_resp *param; + + if (!wma_handle) { + WMA_LOGE("%s: WMA handle is NULL. Cannot issue command", + __func__); + return QDF_STATUS_E_NULL_VALUE; + } + + if (!msg) { + WMA_LOGE("%s: Set antenna mode param is NULL", __func__); + return QDF_STATUS_E_NULL_VALUE; + } + + len = sizeof(*cmd); + + buf = wmi_buf_alloc(wma_handle->wmi_handle, len); + if (!buf) { + WMA_LOGE("%s: wmi_buf_alloc failed", __func__); + status = QDF_STATUS_E_NOMEM; + goto resp; + } + + cmd = (wmi_pdev_set_antenna_mode_cmd_fixed_param *) wmi_buf_data(buf); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_pdev_set_antenna_mode_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN( + wmi_pdev_set_antenna_mode_cmd_fixed_param)); + + cmd->pdev_id = WMI_PDEV_ID_SOC; + /* Bits 0-15 is num of RX chains 16-31 is num of TX chains */ + cmd->num_txrx_chains = msg->num_rx_chains; + cmd->num_txrx_chains |= (msg->num_tx_chains << 16); + + WMA_LOGI("%s: Num of chains TX: %d RX: %d txrx_chains: 0x%x", + __func__, msg->num_tx_chains, + msg->num_rx_chains, cmd->num_txrx_chains); + + if (wmi_unified_cmd_send(wma_handle->wmi_handle, buf, len, + WMI_PDEV_SET_ANTENNA_MODE_CMDID)) { + WMA_LOGE("%s: Failed to send WMI_PDEV_SET_ANTENNA_MODE_CMDID", + __func__); + wmi_buf_free(buf); + status = QDF_STATUS_E_FAILURE; + goto resp; + } + status = QDF_STATUS_SUCCESS; + +resp: + param = qdf_mem_malloc(sizeof(*param)); + if (!param) { + WMA_LOGE("%s: Memory allocation failed", __func__); + return QDF_STATUS_E_NOMEM; + } + param->status = (status) ? + SET_ANTENNA_MODE_STATUS_ECANCELED : + SET_ANTENNA_MODE_STATUS_OK; + WMA_LOGE("%s: Send antenna mode resp to LIM status: %d", + __func__, param->status); + wma_send_msg(wma_handle, SIR_HAL_SOC_ANTENNA_MODE_RESP, + (void *) param, 0); + return status; +} + +/** + * wma_crash_inject() - sends command to FW to simulate crash + * @wma_handle: pointer of WMA context + * @type: subtype of the command + * @delay_time_ms: time in milliseconds for FW to delay the crash + * + * This function will send a command to FW in order to simulate different + * kinds of FW crashes. + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +QDF_STATUS wma_crash_inject(tp_wma_handle wma_handle, uint32_t type, + uint32_t delay_time_ms) +{ + struct crash_inject param; + param.type = type; + param.delay_time_ms = delay_time_ms; + + return wmi_crash_inject(wma_handle->wmi_handle, ¶m); +} + +#if defined(FEATURE_LRO) +/** + * wma_lro_init() - sends LRO configuration to FW + * @lro_config: pointer to the config parameters + * + * This function ends LRO configuration to FW. + * + * Return: 0 for success or reasons for failure + */ +int wma_lro_init(struct wma_lro_config_cmd_t *lro_config) +{ + cds_msg_t msg = {0}; + struct wma_lro_config_cmd_t *iwcmd; + + iwcmd = qdf_mem_malloc(sizeof(*iwcmd)); + if (!iwcmd) { + WMA_LOGE("memory allocation for WMA_LRO_CONFIG_CMD failed!"); + return -ENOMEM; + } + + *iwcmd = *lro_config; + + msg.type = WMA_LRO_CONFIG_CMD; + msg.reserved = 0; + msg.bodyptr = iwcmd; + + if (QDF_STATUS_SUCCESS != + cds_mq_post_message(QDF_MODULE_ID_WMA, &msg)) { + WMA_LOGE("Failed to post WMA_LRO_CONFIG_CMD msg!"); + qdf_mem_free(iwcmd); + return -EAGAIN; + } + + WMA_LOGD("sending the LRO configuration to the fw"); + return 0; +} +#endif + + +void wma_ipa_uc_stat_request(wma_cli_set_cmd_t *privcmd) +{ + tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA); + + if (wma_set_priv_cfg(wma, privcmd)) + WMA_LOGE("Failed to set wma priv congiuration"); +} diff --git a/drivers/staging/qcacld-3.0/core/wma/src/wma_mgmt.c b/drivers/staging/qcacld-3.0/core/wma/src/wma_mgmt.c new file mode 100644 index 0000000000000000000000000000000000000000..e744ac624f333167aa0cd4706ed0ae61a9640f84 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/wma/src/wma_mgmt.c @@ -0,0 +1,3637 @@ +/* + * Copyright (c) 2013-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: wma_mgmt.c + * + * This file contains STA/SAP/IBSS and protocol related functions. + */ + +/* Header files */ + +#include "wma.h" +#include "wma_api.h" +#include "cds_api.h" +#include "wmi_unified_api.h" +#include "wlan_qct_sys.h" +#include "wni_api.h" +#include "ani_global.h" +#include "wmi_unified.h" +#include "wni_cfg.h" +#include "cfg_api.h" + +#include "qdf_nbuf.h" +#include "qdf_types.h" +#include "qdf_mem.h" +#include "ol_txrx_peer_find.h" +#include "ol_txrx.h" + +#include "wma_types.h" +#include "lim_api.h" +#include "lim_session_utils.h" + +#include "cds_utils.h" + +#if !defined(REMOVE_PKT_LOG) +#include "pktlog_ac.h" +#endif /* REMOVE_PKT_LOG */ + +#include "dbglog_host.h" +#include "csr_api.h" +#include "ol_fw.h" +#include "dfs.h" +#include "wma_internal.h" +#include "cds_concurrency.h" +#include "cdp_txrx_flow_ctrl_legacy.h" +#include +#include +#include +#include +#include + +/** + * wma_send_bcn_buf_ll() - prepare and send beacon buffer to fw for LL + * @wma: wma handle + * @pdev: txrx pdev + * @vdev_id: vdev id + * @param_buf: SWBA parameters + * + * Return: none + */ +static void wma_send_bcn_buf_ll(tp_wma_handle wma, + ol_txrx_pdev_handle pdev, + uint8_t vdev_id, + WMI_HOST_SWBA_EVENTID_param_tlvs *param_buf) +{ + struct ieee80211_frame *wh; + struct beacon_info *bcn; + wmi_tim_info *tim_info = param_buf->tim_info; + uint8_t *bcn_payload; + QDF_STATUS ret; + struct beacon_tim_ie *tim_ie; + wmi_p2p_noa_info *p2p_noa_info = param_buf->p2p_noa_info; + struct p2p_sub_element_noa noa_ie; + struct wmi_bcn_send_from_host params; + uint8_t i; + + bcn = wma->interfaces[vdev_id].beacon; + if (!bcn->buf) { + WMA_LOGE("%s: Invalid beacon buffer", __func__); + return; + } + + qdf_spin_lock_bh(&bcn->lock); + + bcn_payload = qdf_nbuf_data(bcn->buf); + + tim_ie = (struct beacon_tim_ie *)(&bcn_payload[bcn->tim_ie_offset]); + + if (tim_info->tim_changed) { + if (tim_info->tim_num_ps_pending) + qdf_mem_copy(&tim_ie->tim_bitmap, tim_info->tim_bitmap, + WMA_TIM_SUPPORTED_PVB_LENGTH); + else + qdf_mem_zero(&tim_ie->tim_bitmap, + WMA_TIM_SUPPORTED_PVB_LENGTH); + /* + * Currently we support fixed number of + * peers as limited by HAL_NUM_STA. + * tim offset is always 0 + */ + tim_ie->tim_bitctl = 0; + } + + /* Update DTIM Count */ + if (tim_ie->dtim_count == 0) + tim_ie->dtim_count = tim_ie->dtim_period - 1; + else + tim_ie->dtim_count--; + + /* + * DTIM count needs to be backedup so that + * when umac updates the beacon template + * current dtim count can be updated properly + */ + bcn->dtim_count = tim_ie->dtim_count; + + /* update state for buffered multicast frames on DTIM */ + if (tim_info->tim_mcast && (tim_ie->dtim_count == 0 || + tim_ie->dtim_period == 1)) + tim_ie->tim_bitctl |= 1; + else + tim_ie->tim_bitctl &= ~1; + + /* To avoid sw generated frame sequence the same as H/W generated frame, + * the value lower than min_sw_seq is reserved for HW generated frame */ + if ((bcn->seq_no & IEEE80211_SEQ_MASK) < MIN_SW_SEQ) + bcn->seq_no = MIN_SW_SEQ; + + wh = (struct ieee80211_frame *)bcn_payload; + *(uint16_t *) &wh->i_seq[0] = htole16(bcn->seq_no + << IEEE80211_SEQ_SEQ_SHIFT); + bcn->seq_no++; + + if (WMI_UNIFIED_NOA_ATTR_IS_MODIFIED(p2p_noa_info)) { + qdf_mem_zero(&noa_ie, sizeof(noa_ie)); + + noa_ie.index = + (uint8_t) WMI_UNIFIED_NOA_ATTR_INDEX_GET(p2p_noa_info); + noa_ie.oppPS = + (uint8_t) WMI_UNIFIED_NOA_ATTR_OPP_PS_GET(p2p_noa_info); + noa_ie.ctwindow = + (uint8_t) WMI_UNIFIED_NOA_ATTR_CTWIN_GET(p2p_noa_info); + noa_ie.num_descriptors = + (uint8_t) WMI_UNIFIED_NOA_ATTR_NUM_DESC_GET(p2p_noa_info); + WMA_LOGI("%s: index %u, oppPs %u, ctwindow %u, " + "num_descriptors = %u", __func__, noa_ie.index, + noa_ie.oppPS, noa_ie.ctwindow, noa_ie.num_descriptors); + for (i = 0; i < noa_ie.num_descriptors; i++) { + noa_ie.noa_descriptors[i].type_count = + (uint8_t) p2p_noa_info->noa_descriptors[i]. + type_count; + noa_ie.noa_descriptors[i].duration = + p2p_noa_info->noa_descriptors[i].duration; + noa_ie.noa_descriptors[i].interval = + p2p_noa_info->noa_descriptors[i].interval; + noa_ie.noa_descriptors[i].start_time = + p2p_noa_info->noa_descriptors[i].start_time; + WMA_LOGI("%s: NoA descriptor[%d] type_count %u, " + "duration %u, interval %u, start_time = %u", + __func__, i, + noa_ie.noa_descriptors[i].type_count, + noa_ie.noa_descriptors[i].duration, + noa_ie.noa_descriptors[i].interval, + noa_ie.noa_descriptors[i].start_time); + } + wma_update_noa(bcn, &noa_ie); + + /* Send a msg to LIM to update the NoA IE in probe response + * frames transmitted by the host */ + wma_update_probe_resp_noa(wma, &noa_ie); + } + + if (bcn->dma_mapped) { + qdf_nbuf_unmap_single(pdev->osdev, bcn->buf, QDF_DMA_TO_DEVICE); + bcn->dma_mapped = 0; + } + ret = qdf_nbuf_map_single(pdev->osdev, bcn->buf, QDF_DMA_TO_DEVICE); + if (ret != QDF_STATUS_SUCCESS) { + WMA_LOGE("%s: failed map beacon buf to DMA region", __func__); + qdf_spin_unlock_bh(&bcn->lock); + return; + } + + bcn->dma_mapped = 1; + params.vdev_id = vdev_id; + params.data_len = bcn->len; + params.frame_ctrl = *((A_UINT16 *) wh->i_fc); + params.frag_ptr = qdf_nbuf_get_frag_paddr(bcn->buf, 0); + params.dtim_flag = 0; + /* notify Firmware of DTM and mcast/bcast traffic */ + if (tim_ie->dtim_count == 0) { + params.dtim_flag |= WMI_BCN_SEND_DTIM_ZERO; + /* deliver mcast/bcast traffic in next DTIM beacon */ + if (tim_ie->tim_bitctl & 0x01) + params.dtim_flag |= WMI_BCN_SEND_DTIM_BITCTL_SET; + } + + wmi_unified_bcn_buf_ll_cmd(wma->wmi_handle, + ¶ms); + + qdf_spin_unlock_bh(&bcn->lock); +} + +/** + * wma_beacon_swba_handler() - swba event handler + * @handle: wma handle + * @event: event data + * @len: data length + * + * SWBA event is alert event to Host requesting host to Queue a beacon + * for transmission use only in host beacon mode + * + * Return: 0 for success or error code + */ +int wma_beacon_swba_handler(void *handle, uint8_t *event, uint32_t len) +{ + tp_wma_handle wma = (tp_wma_handle) handle; + WMI_HOST_SWBA_EVENTID_param_tlvs *param_buf; + wmi_host_swba_event_fixed_param *swba_event; + uint32_t vdev_map; + ol_txrx_pdev_handle pdev; + uint8_t vdev_id = 0; + + param_buf = (WMI_HOST_SWBA_EVENTID_param_tlvs *) event; + if (!param_buf) { + WMA_LOGE("Invalid swba event buffer"); + return -EINVAL; + } + swba_event = param_buf->fixed_param; + vdev_map = swba_event->vdev_map; + + pdev = cds_get_context(QDF_MODULE_ID_TXRX); + if (!pdev) { + WMA_LOGE("%s: pdev is NULL", __func__); + return -EINVAL; + } + + for (; vdev_map; vdev_id++, vdev_map >>= 1) { + if (!(vdev_map & 0x1)) + continue; + if (!ol_cfg_is_high_latency(pdev->ctrl_pdev)) + wma_send_bcn_buf_ll(wma, pdev, vdev_id, param_buf); + break; + } + return 0; +} + +#ifdef FEATURE_WLAN_DIAG_SUPPORT +void wma_sta_kickout_event(uint32_t kickout_reason, uint8_t vdev_id, + uint8_t *macaddr) +{ + WLAN_HOST_DIAG_EVENT_DEF(sta_kickout, struct host_event_wlan_kickout); + qdf_mem_zero(&sta_kickout, sizeof(sta_kickout)); + sta_kickout.reasoncode = kickout_reason; + sta_kickout.vdev_id = vdev_id; + if (macaddr) + qdf_mem_copy(sta_kickout.peer_mac, macaddr, + IEEE80211_ADDR_LEN); + WLAN_HOST_DIAG_EVENT_REPORT(&sta_kickout, EVENT_WLAN_STA_KICKOUT); +} +#endif + +/** + * wma_peer_sta_kickout_event_handler() - kickout event handler + * @handle: wma handle + * @event: event data + * @len: data length + * + * Kickout event is received from firmware on observing beacon miss + * It handles kickout event for different modes and indicate to + * upper layers. + * + * Return: 0 for success or error code + */ +int wma_peer_sta_kickout_event_handler(void *handle, u8 *event, u32 len) +{ + tp_wma_handle wma = (tp_wma_handle) handle; + WMI_PEER_STA_KICKOUT_EVENTID_param_tlvs *param_buf = NULL; + wmi_peer_sta_kickout_event_fixed_param *kickout_event = NULL; + uint8_t vdev_id, peer_id, macaddr[IEEE80211_ADDR_LEN]; + ol_txrx_peer_handle peer; + ol_txrx_pdev_handle pdev; + tpDeleteStaContext del_sta_ctx; + tpSirIbssPeerInactivityInd p_inactivity; + + WMA_LOGD("%s: Enter", __func__); + param_buf = (WMI_PEER_STA_KICKOUT_EVENTID_param_tlvs *) event; + kickout_event = param_buf->fixed_param; + pdev = cds_get_context(QDF_MODULE_ID_TXRX); + if (!pdev) { + WMA_LOGE("%s: pdev is NULL", __func__); + return -EINVAL; + } + WMI_MAC_ADDR_TO_CHAR_ARRAY(&kickout_event->peer_macaddr, macaddr); + peer = ol_txrx_find_peer_by_addr(pdev, macaddr, &peer_id); + if (!peer) { + WMA_LOGE("PEER [%pM] not found", macaddr); + return -EINVAL; + } + + if (ol_txrx_get_vdevid(peer, &vdev_id) != QDF_STATUS_SUCCESS) { + WMA_LOGE("Not able to find BSSID for peer [%pM]", macaddr); + return -EINVAL; + } + + WMA_LOGA("%s: PEER:[%pM], ADDR:[%pN], INTERFACE:%d, peer_id:%d, reason:%d", + __func__, macaddr, wma->interfaces[vdev_id].addr, vdev_id, + peer_id, kickout_event->reason); + if (wma->interfaces[vdev_id].roaming_in_progress) { + WMA_LOGE("Ignore STA kick out since roaming is in progress"); + return -EINVAL; + } + + switch (kickout_event->reason) { + case WMI_PEER_STA_KICKOUT_REASON_IBSS_DISCONNECT: + p_inactivity = (tpSirIbssPeerInactivityInd) + qdf_mem_malloc(sizeof(tSirIbssPeerInactivityInd)); + if (!p_inactivity) { + WMA_LOGE("QDF MEM Alloc Failed for tSirIbssPeerInactivity"); + return -ENOMEM; + } + + p_inactivity->staIdx = peer_id; + qdf_mem_copy(p_inactivity->peer_addr.bytes, macaddr, + IEEE80211_ADDR_LEN); + wma_send_msg(wma, WMA_IBSS_PEER_INACTIVITY_IND, + (void *)p_inactivity, 0); + goto exit_handler; + break; + +#ifdef FEATURE_WLAN_TDLS + case WMI_PEER_STA_KICKOUT_REASON_TDLS_DISCONNECT: + del_sta_ctx = (tpDeleteStaContext) + qdf_mem_malloc(sizeof(tDeleteStaContext)); + if (!del_sta_ctx) { + WMA_LOGE("%s: mem alloc failed for tDeleteStaContext for TDLS peer: %pM", + __func__, macaddr); + return -ENOMEM; + } + + del_sta_ctx->is_tdls = true; + del_sta_ctx->vdev_id = vdev_id; + del_sta_ctx->staId = peer_id; + qdf_mem_copy(del_sta_ctx->addr2, macaddr, IEEE80211_ADDR_LEN); + qdf_mem_copy(del_sta_ctx->bssId, wma->interfaces[vdev_id].bssid, + IEEE80211_ADDR_LEN); + del_sta_ctx->reasonCode = HAL_DEL_STA_REASON_CODE_KEEP_ALIVE; + wma_send_msg(wma, SIR_LIM_DELETE_STA_CONTEXT_IND, + (void *)del_sta_ctx, 0); + goto exit_handler; + break; +#endif /* FEATURE_WLAN_TDLS */ + + case WMI_PEER_STA_KICKOUT_REASON_XRETRY: + if (wma->interfaces[vdev_id].type == WMI_VDEV_TYPE_STA && + (wma->interfaces[vdev_id].sub_type == 0 || + wma->interfaces[vdev_id].sub_type == + WMI_UNIFIED_VDEV_SUBTYPE_P2P_CLIENT) && + !qdf_mem_cmp(wma->interfaces[vdev_id].bssid, + macaddr, IEEE80211_ADDR_LEN)) { + wma_sta_kickout_event(HOST_STA_KICKOUT_REASON_XRETRY, + vdev_id, macaddr); + /* + * KICKOUT event is for current station-AP connection. + * Treat it like final beacon miss. Station may not have + * missed beacons but not able to transmit frames to AP + * for a long time. Must disconnect to get out of + * this sticky situation. + * In future implementation, roaming module will also + * handle this event and perform a scan. + */ + WMA_LOGW("%s: WMI_PEER_STA_KICKOUT_REASON_XRETRY event for STA", + __func__); + wma_beacon_miss_handler(wma, vdev_id, + kickout_event->rssi); + goto exit_handler; + } + break; + + case WMI_PEER_STA_KICKOUT_REASON_UNSPECIFIED: + /* + * Default legacy value used by original firmware implementation. + */ + if (wma->interfaces[vdev_id].type == WMI_VDEV_TYPE_STA && + (wma->interfaces[vdev_id].sub_type == 0 || + wma->interfaces[vdev_id].sub_type == + WMI_UNIFIED_VDEV_SUBTYPE_P2P_CLIENT) && + !qdf_mem_cmp(wma->interfaces[vdev_id].bssid, + macaddr, IEEE80211_ADDR_LEN)) { + wma_sta_kickout_event( + HOST_STA_KICKOUT_REASON_UNSPECIFIED, vdev_id, macaddr); + /* + * KICKOUT event is for current station-AP connection. + * Treat it like final beacon miss. Station may not have + * missed beacons but not able to transmit frames to AP + * for a long time. Must disconnect to get out of + * this sticky situation. + * In future implementation, roaming module will also + * handle this event and perform a scan. + */ + WMA_LOGW("%s: WMI_PEER_STA_KICKOUT_REASON_UNSPECIFIED event for STA", + __func__); + wma_beacon_miss_handler(wma, vdev_id, + kickout_event->rssi); + goto exit_handler; + } + break; + + case WMI_PEER_STA_KICKOUT_REASON_INACTIVITY: + /* + * Handle SA query kickout is same as inactivity kickout. + * This could be for STA or SAP role + */ + case WMI_PEER_STA_KICKOUT_REASON_SA_QUERY_TIMEOUT: + default: + break; + } + + /* + * default action is to send delete station context indication to LIM + */ + del_sta_ctx = + (tpDeleteStaContext) qdf_mem_malloc(sizeof(tDeleteStaContext)); + if (!del_sta_ctx) { + WMA_LOGE("QDF MEM Alloc Failed for tDeleteStaContext"); + return -ENOMEM; + } + + del_sta_ctx->is_tdls = false; + del_sta_ctx->vdev_id = vdev_id; + del_sta_ctx->staId = peer_id; + qdf_mem_copy(del_sta_ctx->addr2, macaddr, IEEE80211_ADDR_LEN); + qdf_mem_copy(del_sta_ctx->bssId, wma->interfaces[vdev_id].addr, + IEEE80211_ADDR_LEN); + del_sta_ctx->reasonCode = HAL_DEL_STA_REASON_CODE_KEEP_ALIVE; + del_sta_ctx->rssi = kickout_event->rssi + WMA_TGT_NOISE_FLOOR_DBM; + wma_sta_kickout_event(HOST_STA_KICKOUT_REASON_KEEP_ALIVE, + vdev_id, macaddr); + wma_send_msg(wma, SIR_LIM_DELETE_STA_CONTEXT_IND, (void *)del_sta_ctx, + 0); + wma_lost_link_info_handler(wma, vdev_id, kickout_event->rssi + + WMA_TGT_NOISE_FLOOR_DBM); +exit_handler: + WMA_LOGD("%s: Exit", __func__); + return 0; +} + +/** + * wma_unified_bcntx_status_event_handler() - beacon tx status event handler + * @handle: wma handle + * @cmd_param_info: event data + * @len: data length + * + * WMI Handler for WMI_OFFLOAD_BCN_TX_STATUS_EVENTID event from firmware. + * This event is generated by FW when the beacon transmission is offloaded + * and the host performs beacon template modification using WMI_BCN_TMPL_CMDID + * The FW generates this event when the first successful beacon transmission + * after template update + * + * Return: 0 for success or error code + */ +int wma_unified_bcntx_status_event_handler(void *handle, + uint8_t *cmd_param_info, + uint32_t len) +{ + tp_wma_handle wma = (tp_wma_handle) handle; + WMI_OFFLOAD_BCN_TX_STATUS_EVENTID_param_tlvs *param_buf; + wmi_offload_bcn_tx_status_event_fixed_param *resp_event; + tSirFirstBeaconTxCompleteInd *beacon_tx_complete_ind; + + param_buf = + (WMI_OFFLOAD_BCN_TX_STATUS_EVENTID_param_tlvs *) cmd_param_info; + if (!param_buf) { + WMA_LOGE("Invalid bcn tx response event buffer"); + return -EINVAL; + } + + resp_event = param_buf->fixed_param; + + WMA_LOGD("%s", __func__); + + /* Check for valid handle to ensure session is not + * deleted in any race + */ + if (!wma->interfaces[resp_event->vdev_id].handle) { + WMA_LOGE("%s: The session does not exist", __func__); + return -EINVAL; + } + + /* Beacon Tx Indication supports only AP mode. Ignore in other modes */ + if (wma_is_vdev_in_ap_mode(wma, resp_event->vdev_id) == false) { + WMA_LOGI("%s: Beacon Tx Indication does not support type %d and sub_type %d", + __func__, wma->interfaces[resp_event->vdev_id].type, + wma->interfaces[resp_event->vdev_id].sub_type); + return 0; + } + + beacon_tx_complete_ind = (tSirFirstBeaconTxCompleteInd *) + qdf_mem_malloc(sizeof(tSirFirstBeaconTxCompleteInd)); + if (!beacon_tx_complete_ind) { + WMA_LOGE("%s: Failed to alloc beacon_tx_complete_ind", + __func__); + return -ENOMEM; + } + + beacon_tx_complete_ind->messageType = WMA_DFS_BEACON_TX_SUCCESS_IND; + beacon_tx_complete_ind->length = sizeof(tSirFirstBeaconTxCompleteInd); + beacon_tx_complete_ind->bssIdx = resp_event->vdev_id; + + wma_send_msg(wma, WMA_DFS_BEACON_TX_SUCCESS_IND, + (void *)beacon_tx_complete_ind, 0); + return 0; +} + +/** + * wma_get_link_probe_timeout() - get link timeout based on sub type + * @mac: UMAC handler + * @sub_type: vdev syb type + * @max_inactive_time: return max inactive time + * @max_unresponsive_time: return max unresponsive time + * + * Return: none + */ +static inline void wma_get_link_probe_timeout(struct sAniSirGlobal *mac, + uint32_t sub_type, + uint32_t *max_inactive_time, + uint32_t *max_unresponsive_time) +{ + uint32_t keep_alive; + uint16_t lm_id, ka_id; + + switch (sub_type) { + case WMI_UNIFIED_VDEV_SUBTYPE_P2P_GO: + lm_id = WNI_CFG_GO_LINK_MONITOR_TIMEOUT; + ka_id = WNI_CFG_GO_KEEP_ALIVE_TIMEOUT; + break; + default: + /*For softAp the subtype value will be zero */ + lm_id = WNI_CFG_AP_LINK_MONITOR_TIMEOUT; + ka_id = WNI_CFG_AP_KEEP_ALIVE_TIMEOUT; + } + + if (wlan_cfg_get_int(mac, lm_id, max_inactive_time) != eSIR_SUCCESS) { + WMA_LOGE("Failed to read link monitor for subtype %d", + sub_type); + *max_inactive_time = WMA_LINK_MONITOR_DEFAULT_TIME_SECS; + } + + if (wlan_cfg_get_int(mac, ka_id, &keep_alive) != eSIR_SUCCESS) { + WMA_LOGE("Failed to read keep alive for subtype %d", sub_type); + keep_alive = WMA_KEEP_ALIVE_DEFAULT_TIME_SECS; + } + *max_unresponsive_time = *max_inactive_time + keep_alive; +} + +/** + * wma_set_mgmt_rate() - set vdev mgmt rate. + * @wma: wma handle + * @vdev_id: vdev id + * + * Return: None + */ +void wma_set_vdev_mgmt_rate(tp_wma_handle wma, uint8_t vdev_id) +{ + uint32_t cfg_val; + int ret; + struct sAniSirGlobal *mac = cds_get_context(QDF_MODULE_ID_PE); + + if (NULL == mac) { + WMA_LOGE("%s: Failed to get mac", __func__); + return; + } + + if (wlan_cfg_get_int(mac, WNI_CFG_RATE_FOR_TX_MGMT, + &cfg_val) == eSIR_SUCCESS) { + if (cfg_val == WNI_CFG_RATE_FOR_TX_MGMT_STADEF) { + WMA_LOGD("default WNI_CFG_RATE_FOR_TX_MGMT, ignore"); + } else { + ret = wma_vdev_set_param( + wma->wmi_handle, + vdev_id, + WMI_VDEV_PARAM_MGMT_TX_RATE, + cfg_val); + if (ret) + WMA_LOGE( + "Failed to set WMI_VDEV_PARAM_MGMT_TX_RATE" + ); + } + } else { + WMA_LOGE("Failed to get value of WNI_CFG_RATE_FOR_TX_MGMT"); + } +} + +/** + * wma_set_sap_keepalive() - set SAP keep alive parameters to fw + * @wma: wma handle + * @vdev_id: vdev id + * + * Return: none + */ +void wma_set_sap_keepalive(tp_wma_handle wma, uint8_t vdev_id) +{ + uint32_t min_inactive_time, max_inactive_time, max_unresponsive_time; + struct sAniSirGlobal *mac = cds_get_context(QDF_MODULE_ID_PE); + QDF_STATUS status; + + if (NULL == mac) { + WMA_LOGE("%s: Failed to get mac", __func__); + return; + } + + wma_get_link_probe_timeout(mac, wma->interfaces[vdev_id].sub_type, + &max_inactive_time, &max_unresponsive_time); + + min_inactive_time = max_inactive_time / 2; + + status = wma_vdev_set_param(wma->wmi_handle, + vdev_id, + WMI_VDEV_PARAM_AP_KEEPALIVE_MIN_IDLE_INACTIVE_TIME_SECS, + min_inactive_time); + if (QDF_IS_STATUS_ERROR(status)) + WMA_LOGE("Failed to Set AP MIN IDLE INACTIVE TIME"); + + status = wma_vdev_set_param(wma->wmi_handle, + vdev_id, + WMI_VDEV_PARAM_AP_KEEPALIVE_MAX_IDLE_INACTIVE_TIME_SECS, + max_inactive_time); + if (QDF_IS_STATUS_ERROR(status)) + WMA_LOGE("Failed to Set AP MAX IDLE INACTIVE TIME"); + + status = wma_vdev_set_param(wma->wmi_handle, + vdev_id, + WMI_VDEV_PARAM_AP_KEEPALIVE_MAX_UNRESPONSIVE_TIME_SECS, + max_unresponsive_time); + if (QDF_IS_STATUS_ERROR(status)) + WMA_LOGE("Failed to Set MAX UNRESPONSIVE TIME"); + + WMA_LOGD("%s:vdev_id:%d min_inactive_time: %u max_inactive_time: %u" + " max_unresponsive_time: %u", __func__, vdev_id, + min_inactive_time, max_inactive_time, max_unresponsive_time); +} + +/** + * wma_set_sta_sa_query_param() - set sta sa query parameters + * @wma: wma handle + * @vdev_id: vdev id + + * This function sets sta query related parameters in fw. + * + * Return: none + */ + +void wma_set_sta_sa_query_param(tp_wma_handle wma, + uint8_t vdev_id) +{ + struct sAniSirGlobal *mac = cds_get_context(QDF_MODULE_ID_PE); + uint32_t max_retries, retry_interval; + + WMA_LOGD(FL("Enter:")); + + if (!mac) { + WMA_LOGE(FL("mac context is NULL")); + return; + } + + if (wlan_cfg_get_int + (mac, WNI_CFG_PMF_SA_QUERY_MAX_RETRIES, + &max_retries) != eSIR_SUCCESS) { + max_retries = DEFAULT_STA_SA_QUERY_MAX_RETRIES_COUNT; + WMA_LOGE(FL("Failed to get value for WNI_CFG_PMF_SA_QUERY_MAX_RETRIES")); + } + if (wlan_cfg_get_int + (mac, WNI_CFG_PMF_SA_QUERY_RETRY_INTERVAL, + &retry_interval) != eSIR_SUCCESS) { + retry_interval = DEFAULT_STA_SA_QUERY_RETRY_INTERVAL; + WMA_LOGE(FL("Failed to get value for WNI_CFG_PMF_SA_QUERY_RETRY_INTERVAL")); + } + + wmi_unified_set_sta_sa_query_param_cmd(wma->wmi_handle, + vdev_id, + max_retries, + retry_interval); + + WMA_LOGD(FL("Exit :")); + return; +} + +/** + * wma_set_sta_keep_alive() - set sta keep alive parameters + * @wma: wma handle + * @vdev_id: vdev id + * @method: method for keep alive + * @timeperiod: time period + * @hostv4addr: host ipv4 address + * @destv4addr: dst ipv4 address + * @destmac: destination mac + * + * This function sets keep alive related parameters in fw. + * + * Return: none + */ +void wma_set_sta_keep_alive(tp_wma_handle wma, uint8_t vdev_id, + uint32_t method, uint32_t timeperiod, + uint8_t *hostv4addr, uint8_t *destv4addr, + uint8_t *destmac) +{ + struct sta_params params; + + WMA_LOGD("%s: Enter", __func__); + + if (!wma) { + WMA_LOGE("%s: wma handle is NULL", __func__); + return; + } + + if (timeperiod > WNI_CFG_INFRA_STA_KEEP_ALIVE_PERIOD_STAMAX) { + WMI_LOGE("Invalid period %d Max limit %d", timeperiod, + WNI_CFG_INFRA_STA_KEEP_ALIVE_PERIOD_STAMAX); + return; + } + + params.vdev_id = vdev_id; + params.method = method; + params.timeperiod = timeperiod; + params.hostv4addr = hostv4addr; + params.destv4addr = destv4addr; + params.destmac = destmac; + + wmi_unified_set_sta_keep_alive_cmd(wma->wmi_handle, + ¶ms); + + WMA_LOGD("%s: Exit", __func__); + return; +} + +/** + * wma_vdev_install_key_complete_event_handler() - install key complete handler + * @handle: wma handle + * @event: event data + * @len: data length + * + * This event is sent by fw once WPA/WPA2 keys are installed in fw. + * + * Return: 0 for success or error code + */ +int wma_vdev_install_key_complete_event_handler(void *handle, + uint8_t *event, + uint32_t len) +{ + WMI_VDEV_INSTALL_KEY_COMPLETE_EVENTID_param_tlvs *param_buf = NULL; + wmi_vdev_install_key_complete_event_fixed_param *key_fp = NULL; + + if (!event) { + WMA_LOGE("%s: event param null", __func__); + return -EINVAL; + } + + param_buf = (WMI_VDEV_INSTALL_KEY_COMPLETE_EVENTID_param_tlvs *) event; + if (!param_buf) { + WMA_LOGE("%s: received null buf from target", __func__); + return -EINVAL; + } + + key_fp = param_buf->fixed_param; + if (!key_fp) { + WMA_LOGE("%s: received null event data from target", __func__); + return -EINVAL; + } + /* + * Do nothing for now. Completion of set key is already indicated to lim + */ + WMA_LOGI("%s: WMI_VDEV_INSTALL_KEY_COMPLETE_EVENTID", __func__); + return 0; +} +/* + * 802.11n D2.0 defined values for "Minimum MPDU Start Spacing": + * 0 for no restriction + * 1 for 1/4 us - Our lower layer calculations limit our precision to 1 msec + * 2 for 1/2 us - Our lower layer calculations limit our precision to 1 msec + * 3 for 1 us + * 4 for 2 us + * 5 for 4 us + * 6 for 8 us + * 7 for 16 us + */ +static const uint8_t wma_mpdu_spacing[] = { 0, 1, 1, 1, 2, 4, 8, 16 }; + +/** + * wma_parse_mpdudensity() - give mpdu spacing from mpdu density + * @mpdudensity: mpdu density + * + * Return: mpdu spacing or 0 for error + */ +static inline uint8_t wma_parse_mpdudensity(uint8_t mpdudensity) +{ + if (mpdudensity < sizeof(wma_mpdu_spacing)) + return wma_mpdu_spacing[mpdudensity]; + else + return 0; +} + +#if defined(CONFIG_HL_SUPPORT) && defined(FEATURE_WLAN_TDLS) + +/** + * wma_unified_peer_state_update() - update peer state + * @pdev: pdev handle + * @sta_mac: pointer to sta mac addr + * @bss_addr: bss address + * @sta_type: sta entry type + * + * + * Return: None + */ +static void +wma_unified_peer_state_update( + struct ol_txrx_pdev_t *pdev, + uint8_t *sta_mac, + uint8_t *bss_addr, + uint8_t sta_type) +{ + if (STA_ENTRY_TDLS_PEER == sta_type) + ol_txrx_peer_state_update(pdev, sta_mac, + OL_TXRX_PEER_STATE_AUTH); + else + ol_txrx_peer_state_update(pdev, bss_addr, + OL_TXRX_PEER_STATE_AUTH); +} +#else + +static inline void +wma_unified_peer_state_update( + struct ol_txrx_pdev_t *pdev, + uint8_t *sta_mac, + uint8_t *bss_addr, + uint8_t sta_type) +{ + ol_txrx_peer_state_update(pdev, bss_addr, OL_TXRX_PEER_STATE_AUTH); +} +#endif + +#define CFG_CTRL_MASK 0xFF00 +#define CFG_DATA_MASK 0x00FF + +/** + * wma_mask_tx_ht_rate() - mask tx ht rate based on config + * @wma: wma handle + * @mcs_set mcs set buffer + * + * Return: None + */ +static void wma_mask_tx_ht_rate(tp_wma_handle wma, uint8_t *mcs_set) +{ + uint32_t mcs_limit, i, j; + uint8_t *rate_pos = mcs_set; + + /* + * Get MCS limit from ini configure, and map it to rate parameters + * This will limit HT rate upper bound. CFG_CTRL_MASK is used to + * check whether ini config is enabled and CFG_DATA_MASK to get the + * MCS value. + */ + if (wlan_cfg_get_int(wma->mac_context, WNI_CFG_MAX_HT_MCS_TX_DATA, + &mcs_limit) != eSIR_SUCCESS) { + mcs_limit = WNI_CFG_MAX_HT_MCS_TX_DATA_STADEF; + } + + if (mcs_limit & CFG_CTRL_MASK) { + WMA_LOGD("%s: set mcs_limit %x", __func__, mcs_limit); + + mcs_limit &= CFG_DATA_MASK; + for (i = 0, j = 0; i < MAX_SUPPORTED_RATES;) { + if (j < mcs_limit / 8) { + rate_pos[j] = 0xff; + j++; + i += 8; + } else if (j < mcs_limit / 8 + 1) { + if (i <= mcs_limit) + rate_pos[i / 8] |= 1 << (i % 8); + else + rate_pos[i / 8] &= ~(1 << (i % 8)); + i++; + + if (i >= (j + 1) * 8) + j++; + } else { + rate_pos[j++] = 0; + i += 8; + } + } + } +} + +/** + * wmi_unified_send_peer_assoc() - send peer assoc command to fw + * @wma: wma handle + * @nw_type: nw type + * @params: add sta params + * + * This function send peer assoc command to firmware with + * different parameters. + * + * Return: QDF_STATUS + */ +QDF_STATUS wma_send_peer_assoc(tp_wma_handle wma, + tSirNwType nw_type, + tpAddStaParams params) +{ + ol_txrx_pdev_handle pdev; + struct peer_assoc_params *cmd; + int32_t ret, max_rates, i; + uint8_t rx_stbc, tx_stbc; + uint8_t *rate_pos; + wmi_rate_set peer_legacy_rates, peer_ht_rates; + uint32_t num_peer_11b_rates = 0; + uint32_t num_peer_11a_rates = 0; + uint32_t phymode; + uint32_t peer_nss = 1; + uint32_t disable_abg_rate; + struct wma_txrx_node *intr = NULL; + QDF_STATUS status; + + cmd = qdf_mem_malloc(sizeof(struct peer_assoc_params)); + if (!cmd) { + WMA_LOGE("Failed to allocate peer_assoc_params param"); + return QDF_STATUS_E_NOMEM; + } + + intr = &wma->interfaces[params->smesessionId]; + + pdev = cds_get_context(QDF_MODULE_ID_TXRX); + + if (NULL == pdev) { + WMA_LOGE("%s: Failed to get pdev", __func__); + qdf_mem_free(cmd); + return QDF_STATUS_E_INVAL; + } + + wma_mask_tx_ht_rate(wma, params->supportedRates.supportedMCSSet); + + qdf_mem_zero(&peer_legacy_rates, sizeof(wmi_rate_set)); + qdf_mem_zero(&peer_ht_rates, sizeof(wmi_rate_set)); + qdf_mem_zero(cmd, sizeof(struct peer_assoc_params)); + + phymode = wma_peer_phymode(nw_type, params->staType, + params->htCapable, + params->ch_width, + params->vhtCapable); + + if (wlan_cfg_get_int(wma->mac_context, + WNI_CFG_DISABLE_ABG_RATE_FOR_TX_DATA, + &disable_abg_rate) != eSIR_SUCCESS) + disable_abg_rate = WNI_CFG_DISABLE_ABG_RATE_FOR_TX_DATA_STADEF; + + if (!disable_abg_rate) { + /* Legacy Rateset */ + rate_pos = (uint8_t *) peer_legacy_rates.rates; + for (i = 0; i < SIR_NUM_11B_RATES; i++) { + if (!params->supportedRates.llbRates[i]) + continue; + rate_pos[peer_legacy_rates.num_rates++] = + params->supportedRates.llbRates[i]; + num_peer_11b_rates++; + } + for (i = 0; i < SIR_NUM_11A_RATES; i++) { + if (!params->supportedRates.llaRates[i]) + continue; + rate_pos[peer_legacy_rates.num_rates++] = + params->supportedRates.llaRates[i]; + num_peer_11a_rates++; + } + } + + if ((phymode == MODE_11A && num_peer_11a_rates == 0) || + (phymode == MODE_11B && num_peer_11b_rates == 0)) { + WMA_LOGW("%s: Invalid phy rates. phymode 0x%x, 11b_rates %d, 11a_rates %d", + __func__, phymode, num_peer_11b_rates, num_peer_11a_rates); + qdf_mem_free(cmd); + return QDF_STATUS_E_INVAL; + } + + /* HT Rateset */ + max_rates = sizeof(peer_ht_rates.rates) / + sizeof(peer_ht_rates.rates[0]); + rate_pos = (uint8_t *) peer_ht_rates.rates; + for (i = 0; i < MAX_SUPPORTED_RATES; i++) { + if (params->supportedRates.supportedMCSSet[i / 8] & + (1 << (i % 8))) { + rate_pos[peer_ht_rates.num_rates++] = i; + if (i >= 8) { + /* MCS8 or higher rate is present, must be 2x2 */ + peer_nss = 2; + } + } + if (peer_ht_rates.num_rates == max_rates) + break; + } + + if (params->htCapable && !peer_ht_rates.num_rates) { + uint8_t temp_ni_rates[8] = { 0x0, 0x1, 0x2, 0x3, + 0x4, 0x5, 0x6, 0x7}; + /* + * Workaround for EV 116382: The peer is marked HT but with + * supported rx mcs set is set to 0. 11n spec mandates MCS0-7 + * for a HT STA. So forcing the supported rx mcs rate to + * MCS 0-7. This workaround will be removed once we get + * clarification from WFA regarding this STA behavior. + */ + + /* TODO: Do we really need this? */ + WMA_LOGW("Peer is marked as HT capable but supported mcs rate is 0"); + peer_ht_rates.num_rates = sizeof(temp_ni_rates); + qdf_mem_copy((uint8_t *) peer_ht_rates.rates, temp_ni_rates, + peer_ht_rates.num_rates); + } + + /* in ap/ibss mode and for tdls peer, use mac address of the peer in + * the other end as the new peer address; in sta mode, use bss id to + * be the new peer address + */ + if ((wma_is_vdev_in_ap_mode(wma, params->smesessionId)) + || (wma_is_vdev_in_ibss_mode(wma, params->smesessionId)) +#ifdef FEATURE_WLAN_TDLS + || (STA_ENTRY_TDLS_PEER == params->staType) +#endif /* FEATURE_WLAN_TDLS */ + ) + WMI_CHAR_ARRAY_TO_MAC_ADDR(params->staMac, &cmd->peer_macaddr); + else + WMI_CHAR_ARRAY_TO_MAC_ADDR(params->bssId, &cmd->peer_macaddr); + cmd->vdev_id = params->smesessionId; + cmd->peer_new_assoc = 1; + cmd->peer_associd = params->assocId; + + /* + * The target only needs a subset of the flags maintained in the host. + * Just populate those flags and send it down + */ + cmd->peer_flags = 0; + + if (params->wmmEnabled) + cmd->peer_flags |= WMI_PEER_QOS; + + if (params->uAPSD) { + cmd->peer_flags |= WMI_PEER_APSD; + WMA_LOGD("Set WMI_PEER_APSD: uapsd Mask %d", params->uAPSD); + } + + if (params->htCapable) { + cmd->peer_flags |= (WMI_PEER_HT | WMI_PEER_QOS); + cmd->peer_rate_caps |= WMI_RC_HT_FLAG; + + if (params->ch_width) { + cmd->peer_flags |= WMI_PEER_40MHZ; + cmd->peer_rate_caps |= WMI_RC_CW40_FLAG; + if (params->fShortGI40Mhz) + cmd->peer_rate_caps |= WMI_RC_SGI_FLAG; + } else if (params->fShortGI20Mhz) { + cmd->peer_rate_caps |= WMI_RC_SGI_FLAG; + } + } + + if (params->vhtCapable) { + cmd->peer_flags |= (WMI_PEER_HT | WMI_PEER_VHT | WMI_PEER_QOS); + cmd->peer_rate_caps |= WMI_RC_HT_FLAG; + } + + if (params->ch_width == CH_WIDTH_80MHZ) + cmd->peer_flags |= WMI_PEER_80MHZ; + else if (params->ch_width == CH_WIDTH_160MHZ) + cmd->peer_flags |= WMI_PEER_160MHZ; + else if (params->ch_width == CH_WIDTH_80P80MHZ) + cmd->peer_flags |= WMI_PEER_160MHZ; + + cmd->peer_vht_caps = params->vht_caps; + if (params->p2pCapableSta) + cmd->peer_flags |= WMI_PEER_IS_P2P_CAPABLE; + + if (params->rmfEnabled) + cmd->peer_flags |= WMI_PEER_PMF; + + rx_stbc = (params->ht_caps & IEEE80211_HTCAP_C_RXSTBC) >> + IEEE80211_HTCAP_C_RXSTBC_S; + if (rx_stbc) { + cmd->peer_flags |= WMI_PEER_STBC; + cmd->peer_rate_caps |= (rx_stbc << WMI_RC_RX_STBC_FLAG_S); + } + + tx_stbc = (params->ht_caps & IEEE80211_HTCAP_C_TXSTBC) >> + IEEE80211_HTCAP_C_TXSTBC_S; + if (tx_stbc) { + cmd->peer_flags |= WMI_PEER_STBC; + cmd->peer_rate_caps |= (tx_stbc << WMI_RC_TX_STBC_FLAG_S); + } + + if (params->htLdpcCapable || params->vhtLdpcCapable) + cmd->peer_flags |= WMI_PEER_LDPC; + + switch (params->mimoPS) { + case eSIR_HT_MIMO_PS_STATIC: + cmd->peer_flags |= WMI_PEER_STATIC_MIMOPS; + break; + case eSIR_HT_MIMO_PS_DYNAMIC: + cmd->peer_flags |= WMI_PEER_DYN_MIMOPS; + break; + case eSIR_HT_MIMO_PS_NO_LIMIT: + cmd->peer_flags |= WMI_PEER_SPATIAL_MUX; + break; + default: + break; + } + +#ifdef FEATURE_WLAN_TDLS + if (STA_ENTRY_TDLS_PEER == params->staType) + cmd->peer_flags |= WMI_PEER_AUTH; +#endif /* FEATURE_WLAN_TDLS */ + + if (params->wpa_rsn +#ifdef FEATURE_WLAN_WAPI + || params->encryptType == eSIR_ED_WPI +#endif /* FEATURE_WLAN_WAPI */ + ) + cmd->peer_flags |= WMI_PEER_NEED_PTK_4_WAY; + if (params->wpa_rsn >> 1) + cmd->peer_flags |= WMI_PEER_NEED_GTK_2_WAY; + + wma_unified_peer_state_update(pdev, params->staMac, + params->bssId, params->staType); + +#ifdef FEATURE_WLAN_WAPI + if (params->encryptType == eSIR_ED_WPI) { + ret = wma_vdev_set_param(wma->wmi_handle, + params->smesessionId, + WMI_VDEV_PARAM_DROP_UNENCRY, + false); + if (ret) { + WMA_LOGE + ("Set WMI_VDEV_PARAM_DROP_UNENCRY Param status:%d\n", + ret); + qdf_mem_free(cmd); + return ret; + } + } +#endif /* FEATURE_WLAN_WAPI */ + + cmd->peer_caps = params->capab_info; + cmd->peer_listen_intval = params->listenInterval; + cmd->peer_ht_caps = params->ht_caps; + cmd->peer_max_mpdu = (1 << (IEEE80211_HTCAP_MAXRXAMPDU_FACTOR + + params->maxAmpduSize)) - 1; + cmd->peer_mpdu_density = wma_parse_mpdudensity(params->maxAmpduDensity); + + if (params->supportedRates.supportedMCSSet[1] && + params->supportedRates.supportedMCSSet[2]) + cmd->peer_rate_caps |= WMI_RC_TS_FLAG; + else if (params->supportedRates.supportedMCSSet[1]) + cmd->peer_rate_caps |= WMI_RC_DS_FLAG; + + /* Update peer legacy rate information */ + cmd->peer_legacy_rates.num_rates = peer_legacy_rates.num_rates; + qdf_mem_copy(cmd->peer_legacy_rates.rates, peer_legacy_rates.rates, + peer_legacy_rates.num_rates); + + /* Update peer HT rate information */ + cmd->peer_ht_rates.num_rates = peer_ht_rates.num_rates; + qdf_mem_copy(cmd->peer_ht_rates.rates, peer_ht_rates.rates, + peer_ht_rates.num_rates); + + /* VHT Rates */ + + cmd->peer_nss = peer_nss; + /* + * Because of DBS a vdev may come up in any of the two MACs with + * different capabilities. STBC capab should be fetched for given + * hard_mode->MAC_id combo. It is planned that firmware should provide + * these dev capabilities. But for now number of tx streams can be used + * to identify if Tx STBC needs to be disabled. + */ + if (intr->tx_streams < 2) { + cmd->peer_vht_caps &= ~(1 << SIR_MAC_VHT_CAP_TXSTBC); + WMA_LOGD("Num tx_streams: %d, Disabled txSTBC", + intr->tx_streams); + } + WMA_LOGD("peer_nss %d peer_ht_rates.num_rates %d ", cmd->peer_nss, + peer_ht_rates.num_rates); + + cmd->vht_capable = params->vhtCapable; + if (params->vhtCapable) { +#define VHT2x2MCSMASK 0xc + cmd->rx_max_rate = params->supportedRates.vhtRxHighestDataRate; + cmd->rx_mcs_set = params->supportedRates.vhtRxMCSMap; + cmd->tx_max_rate = params->supportedRates.vhtTxHighestDataRate; + cmd->tx_mcs_set = params->supportedRates.vhtTxMCSMap; + + if (params->vhtSupportedRxNss) { + cmd->peer_nss = params->vhtSupportedRxNss; + } else { + cmd->peer_nss = ((cmd->rx_mcs_set & VHT2x2MCSMASK) + == VHT2x2MCSMASK) ? 1 : 2; + } + } + + /* + * Limit nss to max number of rf chain supported by target + * Otherwise Fw will crash + */ + if (cmd->peer_nss > WMA_MAX_NSS) + cmd->peer_nss = WMA_MAX_NSS; + + intr->nss = cmd->peer_nss; + cmd->peer_phymode = phymode; + WMA_LOGD("%s: vdev_id %d associd %d peer_flags %x rate_caps %x " + "peer_caps %x listen_intval %d ht_caps %x max_mpdu %d " + "nss %d phymode %d peer_mpdu_density %d encr_type %d " + "cmd->peer_vht_caps %x", __func__, + cmd->vdev_id, cmd->peer_associd, cmd->peer_flags, + cmd->peer_rate_caps, cmd->peer_caps, + cmd->peer_listen_intval, cmd->peer_ht_caps, + cmd->peer_max_mpdu, cmd->peer_nss, cmd->peer_phymode, + cmd->peer_mpdu_density, params->encryptType, + cmd->peer_vht_caps); + + status = wmi_unified_peer_assoc_send(wma->wmi_handle, + cmd); + if (QDF_IS_STATUS_ERROR(status)) + WMA_LOGP(FL("Failed to send peer assoc command status = %d"), + status); + qdf_mem_free(cmd); + + return status; +} + +/** + * wmi_unified_vdev_set_gtx_cfg_send() - set GTX params + * @wmi_handle: wmi handle + * @if_id: vdev id + * @gtx_info: GTX config params + * + * This function set GTX related params in firmware. + * + * Return: 0 for success or error code + */ +QDF_STATUS wmi_unified_vdev_set_gtx_cfg_send(wmi_unified_t wmi_handle, + uint32_t if_id, + gtx_config_t *gtx_info) +{ + struct wmi_gtx_config params; + + params.gtx_rt_mask[0] = gtx_info->gtxRTMask[0]; + params.gtx_rt_mask[1] = gtx_info->gtxRTMask[1]; + params.gtx_usrcfg = gtx_info->gtxUsrcfg; + params.gtx_threshold = gtx_info->gtxPERThreshold; + params.gtx_margin = gtx_info->gtxPERMargin; + params.gtx_tpcstep = gtx_info->gtxTPCstep; + params.gtx_tpcmin = gtx_info->gtxTPCMin; + params.gtx_bwmask = gtx_info->gtxBWMask; + + return wmi_unified_vdev_set_gtx_cfg_cmd(wmi_handle, + if_id, ¶ms); + +} + +/** + * wma_update_protection_mode() - update protection mode + * @wma: wma handle + * @vdev_id: vdev id + * @llbcoexist: protection mode info + * + * This function set protection mode(RTS/CTS) to fw for passed vdev id. + * + * Return: none + */ +void wma_update_protection_mode(tp_wma_handle wma, uint8_t vdev_id, + uint8_t llbcoexist) +{ + QDF_STATUS ret; + enum ieee80211_protmode prot_mode; + + prot_mode = llbcoexist ? IEEE80211_PROT_CTSONLY : IEEE80211_PROT_NONE; + + ret = wma_vdev_set_param(wma->wmi_handle, vdev_id, + WMI_VDEV_PARAM_PROTECTION_MODE, + prot_mode); + + if (QDF_IS_STATUS_ERROR(ret)) + WMA_LOGE("Failed to send wmi protection mode cmd"); + else + WMA_LOGD("Updated protection mode %d to target", prot_mode); +} + +/** + * wma_update_beacon_interval() - update beacon interval in fw + * @wma: wma handle + * @vdev_id: vdev id + * @beaconInterval: becon interval + * + * Return: none + */ +static void +wma_update_beacon_interval(tp_wma_handle wma, uint8_t vdev_id, + uint16_t beaconInterval) +{ + QDF_STATUS ret; + + ret = wma_vdev_set_param(wma->wmi_handle, vdev_id, + WMI_VDEV_PARAM_BEACON_INTERVAL, + beaconInterval); + + if (QDF_IS_STATUS_ERROR(ret)) + WMA_LOGE("Failed to update beacon interval"); + else + WMA_LOGI("Updated beacon interval %d for vdev %d", + beaconInterval, vdev_id); +} + +/** + * wma_process_update_beacon_params() - update beacon parameters to target + * @wma: wma handle + * @bcn_params: beacon parameters + * + * Return: none + */ +void +wma_process_update_beacon_params(tp_wma_handle wma, + tUpdateBeaconParams *bcn_params) +{ + if (!bcn_params) { + WMA_LOGE("bcn_params NULL"); + return; + } + + if (bcn_params->smeSessionId >= wma->max_bssid) { + WMA_LOGE("Invalid vdev id %d", bcn_params->smeSessionId); + return; + } + + if (bcn_params->paramChangeBitmap & PARAM_BCN_INTERVAL_CHANGED) { + wma_update_beacon_interval(wma, bcn_params->smeSessionId, + bcn_params->beaconInterval); + } + + if (bcn_params->paramChangeBitmap & PARAM_llBCOEXIST_CHANGED) + wma_update_protection_mode(wma, bcn_params->smeSessionId, + bcn_params->llbCoexist); +} + +/** + * wma_update_cfg_params() - update cfg parameters to target + * @wma: wma handle + * @cfgParam: cfg parameter + * + * Return: none + */ +void wma_update_cfg_params(tp_wma_handle wma, tSirMsgQ *cfgParam) +{ + uint8_t vdev_id; + uint32_t param_id; + uint32_t cfg_val; + QDF_STATUS ret; + /* get mac to acess CFG data base */ + struct sAniSirGlobal *pmac; + + switch (cfgParam->bodyval) { + case WNI_CFG_RTS_THRESHOLD: + param_id = WMI_VDEV_PARAM_RTS_THRESHOLD; + break; + case WNI_CFG_FRAGMENTATION_THRESHOLD: + param_id = WMI_VDEV_PARAM_FRAGMENTATION_THRESHOLD; + break; + default: + WMA_LOGD("Unhandled cfg parameter %d", cfgParam->bodyval); + return; + } + + pmac = cds_get_context(QDF_MODULE_ID_PE); + + if (NULL == pmac) { + WMA_LOGE("%s: Failed to get pmac", __func__); + return; + } + + if (wlan_cfg_get_int(pmac, (uint16_t) cfgParam->bodyval, + &cfg_val) != eSIR_SUCCESS) { + WMA_LOGE("Failed to get value for CFG PARAMS %d. returning without updating", + cfgParam->bodyval); + return; + } + + for (vdev_id = 0; vdev_id < wma->max_bssid; vdev_id++) { + if (wma->interfaces[vdev_id].handle != 0) { + ret = wma_vdev_set_param(wma->wmi_handle, + vdev_id, param_id, + cfg_val); + if (QDF_IS_STATUS_ERROR(ret)) + WMA_LOGE("Update cfg params failed for vdevId %d", + vdev_id); + } + } +} + +/** + * wma_read_cfg_wepkey() - fill key_info for WEP key + * @wma_handle: wma handle + * @key_info: key_info ptr + * @def_key_idx: default key index + * @num_keys: number of keys + * + * This function reads WEP keys from cfg and fills + * up key_info. + * + * Return: none + */ +static void wma_read_cfg_wepkey(tp_wma_handle wma_handle, + tSirKeys *key_info, uint32_t *def_key_idx, + uint8_t *num_keys) +{ + tSirRetStatus status; + uint32_t val = SIR_MAC_KEY_LENGTH; + uint8_t i, j; + + WMA_LOGD("Reading WEP keys from cfg"); + /* NOTE:def_key_idx is initialized to 0 by the caller */ + status = wlan_cfg_get_int(wma_handle->mac_context, + WNI_CFG_WEP_DEFAULT_KEYID, def_key_idx); + if (status != eSIR_SUCCESS) + WMA_LOGE("Unable to read default id, defaulting to 0"); + + for (i = 0, j = 0; i < SIR_MAC_MAX_NUM_OF_DEFAULT_KEYS; i++) { + status = wlan_cfg_get_str(wma_handle->mac_context, + (uint16_t) WNI_CFG_WEP_DEFAULT_KEY_1 + + i, key_info[j].key, &val); + if (status != eSIR_SUCCESS) { + WMA_LOGE("WEP key is not configured at :%d", i); + } else { + key_info[j].keyId = i; + key_info[j].keyLength = (uint16_t) val; + j++; + } + } + *num_keys = j; +} + +/** + * wma_setup_install_key_cmd() - set key parameters + * @wma_handle: wma handle + * @key_params: key parameters + * @mode: op mode + * + * This function fills structure from information + * passed in key_params. + * + * Return: QDF_STATUS_SUCCESS - success + QDF_STATUS_E_FAILURE - failure + QDF_STATUS_E_NOMEM - invalid request + */ +static QDF_STATUS wma_setup_install_key_cmd(tp_wma_handle wma_handle, + struct wma_set_key_params + *key_params, uint8_t mode) +{ + struct set_key_params params; + QDF_STATUS status = QDF_STATUS_SUCCESS; +#ifdef WLAN_FEATURE_11W + struct wma_txrx_node *iface = NULL; +#endif /* WLAN_FEATURE_11W */ + if ((key_params->key_type == eSIR_ED_NONE && + key_params->key_len) || (key_params->key_type != eSIR_ED_NONE && + !key_params->key_len)) { + WMA_LOGE("%s:Invalid set key request", __func__); + return QDF_STATUS_E_NOMEM; + } + + params.vdev_id = key_params->vdev_id; + params.key_idx = key_params->key_idx; + qdf_mem_copy(params.peer_mac, key_params->peer_mac, IEEE80211_ADDR_LEN); + +#ifdef FEATURE_WLAN_WAPI + qdf_mem_set(params.tx_iv, 16, 0); + qdf_mem_set(params.rx_iv, 16, 0); +#endif + params.key_txmic_len = 0; + params.key_rxmic_len = 0; + + params.key_flags = 0; + if (key_params->unicast) + params.key_flags |= PAIRWISE_USAGE; + else + params.key_flags |= GROUP_USAGE; + + switch (key_params->key_type) { + case eSIR_ED_NONE: + params.key_cipher = WMI_CIPHER_NONE; + break; + case eSIR_ED_WEP40: + case eSIR_ED_WEP104: + params.key_cipher = WMI_CIPHER_WEP; + if (key_params->unicast && + params.key_idx == key_params->def_key_idx) { + WMA_LOGD("STA Mode: cmd->key_flags |= TX_USAGE"); + params.key_flags |= TX_USAGE; + } else if ((mode == wlan_op_mode_ap) && + (params.key_idx == key_params->def_key_idx)) { + WMA_LOGD("AP Mode: cmd->key_flags |= TX_USAGE"); + params.key_flags |= TX_USAGE; + } + break; + case eSIR_ED_TKIP: + params.key_txmic_len = WMA_TXMIC_LEN; + params.key_rxmic_len = WMA_RXMIC_LEN; + params.key_cipher = WMI_CIPHER_TKIP; + break; +#ifdef FEATURE_WLAN_WAPI +#define WPI_IV_LEN 16 + case eSIR_ED_WPI: + { + /*initialize receive and transmit IV with default values */ + /* **Note: tx_iv must be sent in reverse** */ + unsigned char tx_iv[16] = { 0x36, 0x5c, 0x36, 0x5c, 0x36, 0x5c, + 0x36, 0x5c, 0x36, 0x5c, 0x36, 0x5c, + 0x36, 0x5c, 0x36, 0x5c}; + unsigned char rx_iv[16] = { 0x5c, 0x36, 0x5c, 0x36, 0x5c, 0x36, + 0x5c, 0x36, 0x5c, 0x36, 0x5c, 0x36, + 0x5c, 0x36, 0x5c, 0x37}; + if (mode == wlan_op_mode_ap) { + /* Authenticator initializes the value of PN as + * 0x5C365C365C365C365C365C365C365C36 for MCastkey Update + */ + if (key_params->unicast) + tx_iv[0] = 0x37; + + rx_iv[WPI_IV_LEN - 1] = 0x36; + } else { + if (!key_params->unicast) + rx_iv[WPI_IV_LEN - 1] = 0x36; + } + + params.key_txmic_len = WMA_TXMIC_LEN; + params.key_rxmic_len = WMA_RXMIC_LEN; + + qdf_mem_copy(¶ms.rx_iv, &rx_iv, + WPI_IV_LEN); + qdf_mem_copy(¶ms.tx_iv, &tx_iv, + WPI_IV_LEN); + params.key_cipher = WMI_CIPHER_WAPI; + break; + } +#endif /* FEATURE_WLAN_WAPI */ + case eSIR_ED_CCMP: + params.key_cipher = WMI_CIPHER_AES_CCM; + break; +#ifdef WLAN_FEATURE_11W + case eSIR_ED_AES_128_CMAC: + params.key_cipher = WMI_CIPHER_AES_CMAC; + break; +#endif /* WLAN_FEATURE_11W */ + default: + /* TODO: MFP ? */ + WMA_LOGE("%s:Invalid encryption type:%d", __func__, + key_params->key_type); + return QDF_STATUS_E_NOMEM; + } + +#ifdef BIG_ENDIAN_HOST + { + /* for big endian host, copy engine byte_swap is enabled + * But the key data content is in network byte order + * Need to byte swap the key data content - so when copy engine + * does byte_swap - target gets key_data content in the correct + * order. + */ + int8_t i; + uint32_t *destp, *srcp; + + destp = (uint32_t *) params.key_data; + srcp = (uint32_t *) key_params->key_data; + for (i = 0; + i < roundup(key_params->key_len, sizeof(uint32_t)) / 4; + i++) { + *destp = le32_to_cpu(*srcp); + destp++; + srcp++; + } + } +#else + qdf_mem_copy((void *)params.key_data, + (const void *)key_params->key_data, key_params->key_len); +#endif /* BIG_ENDIAN_HOST */ + params.key_len = key_params->key_len; + +#ifdef WLAN_FEATURE_11W + if (key_params->key_type == eSIR_ED_AES_128_CMAC) { + iface = &wma_handle->interfaces[key_params->vdev_id]; + if (iface) { + iface->key.key_length = key_params->key_len; + qdf_mem_copy(iface->key.key, + (const void *)key_params->key_data, + iface->key.key_length); + if ((params.key_idx == WMA_IGTK_KEY_INDEX_4) || + (params.key_idx == WMA_IGTK_KEY_INDEX_5)) + qdf_mem_zero(iface->key.key_id[params.key_idx - + WMA_IGTK_KEY_INDEX_4].ipn, + CMAC_IPN_LEN); + } + } +#endif /* WLAN_FEATURE_11W */ + + WMA_LOGD("Key setup : vdev_id %d key_idx %d key_type %d key_len %d" + " unicast %d peer_mac %pM def_key_idx %d", key_params->vdev_id, + key_params->key_idx, key_params->key_type, key_params->key_len, + key_params->unicast, key_params->peer_mac, + key_params->def_key_idx); + + status = wmi_unified_setup_install_key_cmd(wma_handle->wmi_handle, + ¶ms); + + return status; +} + +/** + * wma_set_bsskey() - set encryption key to fw. + * @wma_handle: wma handle + * @key_info: key info + * + * Return: none + */ +void wma_set_bsskey(tp_wma_handle wma_handle, tpSetBssKeyParams key_info) +{ + struct wma_set_key_params key_params; + QDF_STATUS status = QDF_STATUS_SUCCESS; + uint32_t i; + uint32_t def_key_idx = 0; + uint32_t wlan_opmode; + ol_txrx_vdev_handle txrx_vdev; + uint8_t *mac_addr; + + WMA_LOGD("BSS key setup"); + txrx_vdev = wma_find_vdev_by_id(wma_handle, key_info->smesessionId); + if (!txrx_vdev) { + WMA_LOGE("%s:Invalid vdev handle", __func__); + key_info->status = QDF_STATUS_E_FAILURE; + goto out; + } + wlan_opmode = ol_txrx_get_opmode(txrx_vdev); + + /* + * For IBSS, WMI expects the BSS key to be set per peer key + * So cache the BSS key in the wma_handle and re-use it when the + * STA key is been setup for a peer + */ + if (wlan_op_mode_ibss == wlan_opmode) { + key_info->status = QDF_STATUS_SUCCESS; + if (wma_handle->ibss_started > 0) + goto out; + WMA_LOGD("Caching IBSS Key"); + qdf_mem_copy(&wma_handle->ibsskey_info, key_info, + sizeof(tSetBssKeyParams)); + } + + qdf_mem_set(&key_params, sizeof(key_params), 0); + key_params.vdev_id = key_info->smesessionId; + key_params.key_type = key_info->encType; + key_params.singl_tid_rc = key_info->singleTidRc; + key_params.unicast = false; + if (wlan_opmode == wlan_op_mode_sta) { + qdf_mem_copy(key_params.peer_mac, + wma_handle->interfaces[key_info->smesessionId].bssid, + IEEE80211_ADDR_LEN); + } else { + mac_addr = ol_txrx_get_vdev_mac_addr(txrx_vdev); + if (mac_addr == NULL) { + WMA_LOGE("%s: mac_addr is NULL for vdev with id %d", + __func__, key_info->smesessionId); + goto out; + } + /* vdev mac address will be passed for all other modes */ + qdf_mem_copy(key_params.peer_mac, mac_addr, + IEEE80211_ADDR_LEN); + WMA_LOGA("BSS Key setup with vdev_mac %pM\n", + mac_addr); + } + + if (key_info->numKeys == 0 && + (key_info->encType == eSIR_ED_WEP40 || + key_info->encType == eSIR_ED_WEP104)) { + wma_read_cfg_wepkey(wma_handle, key_info->key, + &def_key_idx, &key_info->numKeys); + } + + for (i = 0; i < key_info->numKeys; i++) { + if (key_params.key_type != eSIR_ED_NONE && + !key_info->key[i].keyLength) + continue; + if (key_info->encType == eSIR_ED_WPI) { + key_params.key_idx = key_info->key[i].keyId; + key_params.def_key_idx = key_info->key[i].keyId; + } else + key_params.key_idx = key_info->key[i].keyId; + + key_params.key_len = key_info->key[i].keyLength; + if (key_info->encType == eSIR_ED_TKIP) { + qdf_mem_copy(key_params.key_data, + key_info->key[i].key, 16); + qdf_mem_copy(&key_params.key_data[16], + &key_info->key[i].key[24], 8); + qdf_mem_copy(&key_params.key_data[24], + &key_info->key[i].key[16], 8); + } else + qdf_mem_copy((void *)key_params.key_data, + (const void *)key_info->key[i].key, + key_info->key[i].keyLength); + + WMA_LOGD("%s: bss key[%d] length %d", __func__, i, + key_info->key[i].keyLength); + + status = wma_setup_install_key_cmd(wma_handle, &key_params, + wlan_opmode); + if (status == QDF_STATUS_E_NOMEM) { + WMA_LOGE("%s:Failed to setup install key buf", + __func__); + key_info->status = QDF_STATUS_E_NOMEM; + goto out; + } else if (status == QDF_STATUS_E_FAILURE) { + WMA_LOGE("%s:Failed to send install key command", + __func__); + key_info->status = QDF_STATUS_E_FAILURE; + goto out; + } + } + + wma_handle->ibss_started++; + /* TODO: Should we wait till we get HTT_T2H_MSG_TYPE_SEC_IND? */ + key_info->status = QDF_STATUS_SUCCESS; + +out: + wma_send_msg(wma_handle, WMA_SET_BSSKEY_RSP, (void *)key_info, 0); +} + +#ifdef QCA_IBSS_SUPPORT +/** + * wma_calc_ibss_heart_beat_timer() - calculate IBSS heart beat timer + * @peer_num: number of peers + * + * Return: heart beat timer value + */ +static uint16_t wma_calc_ibss_heart_beat_timer(int16_t peer_num) +{ + /* heart beat timer value look-up table */ + /* entry index : (the number of currently connected peers) - 1 + entry value : the heart time threshold value in seconds for + detecting ibss peer departure */ + static const uint16_t heart_beat_timer[MAX_PEERS] = { + 4, 4, 4, 4, 4, 4, 4, 4, + 8, 8, 8, 8, 8, 8, 8, 8, + 12, 12, 12, 12, 12, 12, 12, 12, + 16, 16, 16, 16, 16, 16, 16, 16 + }; + + if (peer_num < 1 || peer_num > MAX_PEERS) + return 0; + + return heart_beat_timer[peer_num - 1]; + +} + +/** + * wma_adjust_ibss_heart_beat_timer() - set ibss heart beat timer in fw. + * @wma: wma handle + * @vdev_id: vdev id + * @peer_num_delta: peer number delta value + * + * Return: none + */ +void wma_adjust_ibss_heart_beat_timer(tp_wma_handle wma, + uint8_t vdev_id, + int8_t peer_num_delta) +{ + ol_txrx_vdev_handle vdev; + int16_t new_peer_num; + uint16_t new_timer_value_sec; + uint32_t new_timer_value_ms; + QDF_STATUS status; + + if (peer_num_delta != 1 && peer_num_delta != -1) { + WMA_LOGE("Invalid peer_num_delta value %d", peer_num_delta); + return; + } + + vdev = wma_find_vdev_by_id(wma, vdev_id); + if (!vdev) { + WMA_LOGE("vdev not found : vdev_id %d", vdev_id); + return; + } + + /* adjust peer numbers */ + new_peer_num = ol_txrx_update_ibss_add_peer_num_of_vdev(vdev, + peer_num_delta); + if (OL_TXRX_INVALID_NUM_PEERS == new_peer_num) { + WMA_LOGE("new peer num %d out of valid boundary", new_peer_num); + return; + } + + /* reset timer value if all peers departed */ + if (new_peer_num == 0) { + ol_txrx_set_ibss_vdev_heart_beat_timer(vdev, 0); + return; + } + + /* calculate new timer value */ + new_timer_value_sec = wma_calc_ibss_heart_beat_timer(new_peer_num); + if (new_timer_value_sec == 0) { + WMA_LOGE("timer value %d is invalid for peer number %d", + new_timer_value_sec, new_peer_num); + return; + } + if (new_timer_value_sec == + ol_txrx_set_ibss_vdev_heart_beat_timer(vdev, new_timer_value_sec)) { + WMA_LOGD("timer value %d stays same, no need to notify target", + new_timer_value_sec); + return; + } + + new_timer_value_ms = ((uint32_t) new_timer_value_sec) * 1000; + + status = wma_vdev_set_param(wma->wmi_handle, vdev_id, + WMI_VDEV_PARAM_IBSS_MAX_BCN_LOST_MS, + new_timer_value_ms); + if (QDF_IS_STATUS_ERROR(status)) { + WMA_LOGE("Failed to set IBSS link monitoring timer value"); + return; + } + + WMA_LOGD("Set IBSS link monitor timer: peer_num = %d timer_value = %d", + new_peer_num, new_timer_value_ms); +} + +#endif /* QCA_IBSS_SUPPORT */ +/** + * wma_set_ibsskey_helper() - cached IBSS key in wma handle + * @wma_handle: wma handle + * @key_info: set bss key info + * @peerMacAddr: peer mac address + * + * Return: none + */ +static void wma_set_ibsskey_helper(tp_wma_handle wma_handle, + tpSetBssKeyParams key_info, + struct qdf_mac_addr peer_macaddr) +{ + struct wma_set_key_params key_params; + QDF_STATUS status = QDF_STATUS_SUCCESS; + uint32_t i; + uint32_t def_key_idx = 0; + ol_txrx_vdev_handle txrx_vdev; + int opmode; + + WMA_LOGD("BSS key setup for peer"); + txrx_vdev = wma_find_vdev_by_id(wma_handle, key_info->smesessionId); + if (!txrx_vdev) { + WMA_LOGE("%s:Invalid vdev handle", __func__); + key_info->status = QDF_STATUS_E_FAILURE; + return; + } + + qdf_mem_set(&key_params, sizeof(key_params), 0); + opmode = ol_txrx_get_opmode(txrx_vdev); + qdf_mem_set(&key_params, sizeof(key_params), 0); + key_params.vdev_id = key_info->smesessionId; + key_params.key_type = key_info->encType; + key_params.singl_tid_rc = key_info->singleTidRc; + key_params.unicast = false; + ASSERT(wlan_op_mode_ibss == opmode); + + qdf_mem_copy(key_params.peer_mac, peer_macaddr.bytes, + IEEE80211_ADDR_LEN); + + if (key_info->numKeys == 0 && + (key_info->encType == eSIR_ED_WEP40 || + key_info->encType == eSIR_ED_WEP104)) { + wma_read_cfg_wepkey(wma_handle, key_info->key, + &def_key_idx, &key_info->numKeys); + } else if ((key_info->encType == eSIR_ED_WEP40) || + (key_info->encType == eSIR_ED_WEP104)) { + struct wma_txrx_node *intf = + &wma_handle->interfaces[key_info->smesessionId]; + key_params.def_key_idx = intf->wep_default_key_idx; + } + + for (i = 0; i < key_info->numKeys; i++) { + if (key_params.key_type != eSIR_ED_NONE && + !key_info->key[i].keyLength) + continue; + key_params.key_idx = key_info->key[i].keyId; + key_params.key_len = key_info->key[i].keyLength; + if (key_info->encType == eSIR_ED_TKIP) { + qdf_mem_copy(key_params.key_data, + key_info->key[i].key, 16); + qdf_mem_copy(&key_params.key_data[16], + &key_info->key[i].key[24], 8); + qdf_mem_copy(&key_params.key_data[24], + &key_info->key[i].key[16], 8); + } else + qdf_mem_copy((void *)key_params.key_data, + (const void *)key_info->key[i].key, + key_info->key[i].keyLength); + + WMA_LOGD("%s: peer bcast key[%d] length %d", __func__, i, + key_info->key[i].keyLength); + + status = wma_setup_install_key_cmd(wma_handle, &key_params, + opmode); + if (status == QDF_STATUS_E_NOMEM) { + WMA_LOGE("%s:Failed to setup install key buf", + __func__); + return; + } else if (status == QDF_STATUS_E_FAILURE) { + WMA_LOGE("%s:Failed to send install key command", + __func__); + } + } +} + +/** + * wma_set_stakey() - set encryption key + * @wma_handle: wma handle + * @key_info: station key info + * + * This function sets encryption key for WEP/WPA/WPA2 + * encryption mode in firmware and send response to upper layer. + * + * Return: none + */ +void wma_set_stakey(tp_wma_handle wma_handle, tpSetStaKeyParams key_info) +{ + int32_t i; + QDF_STATUS status = QDF_STATUS_SUCCESS; + ol_txrx_pdev_handle txrx_pdev; + ol_txrx_vdev_handle txrx_vdev; + ol_txrx_peer_handle peer; + uint8_t num_keys = 0, peer_id; + struct wma_set_key_params key_params; + uint32_t def_key_idx = 0; + int opmode; + + WMA_LOGD("STA key setup"); + + /* Get the txRx Pdev handle */ + txrx_pdev = cds_get_context(QDF_MODULE_ID_TXRX); + if (!txrx_pdev) { + WMA_LOGE("%s:Invalid txrx pdev handle", __func__); + key_info->status = QDF_STATUS_E_FAILURE; + goto out; + } + + peer = ol_txrx_find_peer_by_addr(txrx_pdev, + key_info->peer_macaddr.bytes, + &peer_id); + if (!peer) { + WMA_LOGE("%s:Invalid peer for key setting", __func__); + key_info->status = QDF_STATUS_E_FAILURE; + goto out; + } + + txrx_vdev = wma_find_vdev_by_id(wma_handle, key_info->smesessionId); + if (!txrx_vdev) { + WMA_LOGE("%s:TxRx Vdev Handle is NULL", __func__); + key_info->status = QDF_STATUS_E_FAILURE; + goto out; + } + opmode = ol_txrx_get_opmode(txrx_vdev); + + if (key_info->defWEPIdx == WMA_INVALID_KEY_IDX && + (key_info->encType == eSIR_ED_WEP40 || + key_info->encType == eSIR_ED_WEP104) && + opmode != wlan_op_mode_ap) { + wma_read_cfg_wepkey(wma_handle, key_info->key, + &def_key_idx, &num_keys); + key_info->defWEPIdx = def_key_idx; + } else { + num_keys = SIR_MAC_MAX_NUM_OF_DEFAULT_KEYS; + if (key_info->encType != eSIR_ED_NONE) { + for (i = 0; i < num_keys; i++) { + if (key_info->key[i].keyDirection == + eSIR_TX_DEFAULT) { + key_info->defWEPIdx = i; + break; + } + } + } + } + qdf_mem_set(&key_params, sizeof(key_params), 0); + key_params.vdev_id = key_info->smesessionId; + key_params.key_type = key_info->encType; + key_params.singl_tid_rc = key_info->singleTidRc; + key_params.unicast = true; + key_params.def_key_idx = key_info->defWEPIdx; + qdf_mem_copy((void *)key_params.peer_mac, + (const void *)key_info->peer_macaddr.bytes, + IEEE80211_ADDR_LEN); + for (i = 0; i < num_keys; i++) { + if (key_params.key_type != eSIR_ED_NONE && + !key_info->key[i].keyLength) + continue; + if (key_info->encType == eSIR_ED_TKIP) { + qdf_mem_copy(key_params.key_data, + key_info->key[i].key, 16); + qdf_mem_copy(&key_params.key_data[16], + &key_info->key[i].key[24], 8); + qdf_mem_copy(&key_params.key_data[24], + &key_info->key[i].key[16], 8); + } else + qdf_mem_copy(key_params.key_data, key_info->key[i].key, + key_info->key[i].keyLength); + if (key_info->encType == eSIR_ED_WPI) { + key_params.key_idx = key_info->key[i].keyId; + key_params.def_key_idx = key_info->key[i].keyId; + } else + key_params.key_idx = i; + + key_params.key_len = key_info->key[i].keyLength; + status = wma_setup_install_key_cmd(wma_handle, &key_params, + opmode); + if (status == QDF_STATUS_E_NOMEM) { + WMA_LOGE("%s:Failed to setup install key buf", + __func__); + key_info->status = QDF_STATUS_E_NOMEM; + goto out; + } + + WMA_LOGD("%s: peer unicast key[%d] %d ", __func__, i, + key_info->key[i].keyLength); + + if (status == QDF_STATUS_E_FAILURE) { + WMA_LOGE("%s:Failed to send install key command", + __func__); + key_info->status = QDF_STATUS_E_FAILURE; + goto out; + } + } + + /* In IBSS mode, set the BSS KEY for this peer + * BSS key is supposed to be cache into wma_handle + */ + if (wlan_op_mode_ibss == opmode) { + wma_set_ibsskey_helper(wma_handle, &wma_handle->ibsskey_info, + key_info->peer_macaddr); + } + + /* TODO: Should we wait till we get HTT_T2H_MSG_TYPE_SEC_IND? */ + key_info->status = QDF_STATUS_SUCCESS; +out: + if (key_info->sendRsp) + wma_send_msg(wma_handle, WMA_SET_STAKEY_RSP, (void *)key_info, + 0); +} + +/** + * wma_process_update_edca_param_req() - update EDCA params + * @handle: wma handle + * @edca_params: edca parameters + * + * This function updates EDCA parameters to the target + * + * Return: QDF Status + */ +QDF_STATUS wma_process_update_edca_param_req(WMA_HANDLE handle, + tEdcaParams *edca_params) +{ + tp_wma_handle wma_handle = (tp_wma_handle) handle; + wmi_wmm_vparams wmm_param[WME_NUM_AC]; + tSirMacEdcaParamRecord *edca_record; + int ac; + ol_txrx_pdev_handle pdev; + struct ol_tx_wmm_param_t ol_tx_wmm_param; + uint8_t vdev_id; + QDF_STATUS status; + + vdev_id = edca_params->bssIdx; + + for (ac = 0; ac < WME_NUM_AC; ac++) { + switch (ac) { + case WME_AC_BE: + edca_record = &edca_params->acbe; + break; + case WME_AC_BK: + edca_record = &edca_params->acbk; + break; + case WME_AC_VI: + edca_record = &edca_params->acvi; + break; + case WME_AC_VO: + edca_record = &edca_params->acvo; + break; + default: + goto fail; + } + + wma_update_edca_params_for_ac(edca_record, &wmm_param[ac], ac); + + ol_tx_wmm_param.ac[ac].aifs = wmm_param[ac].aifs; + ol_tx_wmm_param.ac[ac].cwmin = wmm_param[ac].cwmin; + ol_tx_wmm_param.ac[ac].cwmax = wmm_param[ac].cwmax; + } + + status = wmi_unified_process_update_edca_param(wma_handle->wmi_handle, + vdev_id, wmm_param); + if (status == QDF_STATUS_E_NOMEM) + return status; + else if (status == QDF_STATUS_E_FAILURE) + goto fail; + + pdev = cds_get_context(QDF_MODULE_ID_TXRX); + if (pdev) + ol_txrx_set_wmm_param(pdev, ol_tx_wmm_param); + else + QDF_ASSERT(0); + + return QDF_STATUS_SUCCESS; + +fail: + WMA_LOGE("%s: Failed to set WMM Paremeters", __func__); + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_probe_rsp_tmpl_send() - send probe response template to fw + * @wma: wma handle + * @vdev_id: vdev id + * @probe_rsp_info: probe response info + * + * Return: 0 for success or error code + */ +static int wmi_unified_probe_rsp_tmpl_send(tp_wma_handle wma, + uint8_t vdev_id, + tpSendProbeRespParams probe_rsp_info) +{ + uint8_t *frm; + uint64_t adjusted_tsf_le; + struct ieee80211_frame *wh; + struct wmi_probe_resp_params params; + + WMA_LOGD(FL("Send probe response template for vdev %d"), vdev_id); + + frm = probe_rsp_info->pProbeRespTemplate; + + /* + * Make the TSF offset negative so probe response in the same + * staggered batch have the same TSF. + */ + adjusted_tsf_le = cpu_to_le64(0ULL - + wma->interfaces[vdev_id].tsfadjust); + /* Update the timstamp in the probe response buffer with adjusted TSF */ + wh = (struct ieee80211_frame *)frm; + A_MEMCPY(&wh[1], &adjusted_tsf_le, sizeof(adjusted_tsf_le)); + + params.pProbeRespTemplate = probe_rsp_info->pProbeRespTemplate; + params.probeRespTemplateLen = probe_rsp_info->probeRespTemplateLen; + qdf_mem_copy(params.bssId, probe_rsp_info->bssId, + IEEE80211_ADDR_LEN); + qdf_mem_copy(params.ucProxyProbeReqValidIEBmap, + probe_rsp_info->ucProxyProbeReqValidIEBmap, + 8 * sizeof(uint32_t)); + + return wmi_unified_probe_rsp_tmpl_send_cmd(wma->wmi_handle, vdev_id, + ¶ms, frm); +} + +/** + * wma_unified_bcn_tmpl_send() - send beacon template to fw + * @wma:wma handle + * @vdev_id: vdev id + * @bcn_info: beacon info + * @bytes_to_strip: bytes to strip + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +static QDF_STATUS wma_unified_bcn_tmpl_send(tp_wma_handle wma, + uint8_t vdev_id, + const tpSendbeaconParams bcn_info, + uint8_t bytes_to_strip) +{ + struct beacon_params params = {0}; + uint32_t tmpl_len, tmpl_len_aligned; + uint8_t *frm; + QDF_STATUS ret; + uint8_t *p2p_ie; + uint16_t p2p_ie_len = 0; + uint64_t adjusted_tsf_le; + struct ieee80211_frame *wh; + + WMA_LOGD("Send beacon template for vdev %d", vdev_id); + + if (bcn_info->p2pIeOffset) { + p2p_ie = bcn_info->beacon + bcn_info->p2pIeOffset; + p2p_ie_len = (uint16_t) p2p_ie[1] + 2; + } + + /* + * XXX: The first byte of beacon buffer contains beacon length + * only when UMAC in sending the beacon template. In othercases + * (ex: from tbtt update) beacon length is read from beacon + * information. + */ + if (bytes_to_strip) + tmpl_len = *(uint32_t *) &bcn_info->beacon[0]; + else + tmpl_len = bcn_info->beaconLength; + if (p2p_ie_len) { + tmpl_len -= (uint32_t) p2p_ie_len; + } + + frm = bcn_info->beacon + bytes_to_strip; + tmpl_len_aligned = roundup(tmpl_len, sizeof(A_UINT32)); + /* + * Make the TSF offset negative so beacons in the same + * staggered batch have the same TSF. + */ + adjusted_tsf_le = cpu_to_le64(0ULL - + wma->interfaces[vdev_id].tsfadjust); + /* Update the timstamp in the beacon buffer with adjusted TSF */ + wh = (struct ieee80211_frame *)frm; + A_MEMCPY(&wh[1], &adjusted_tsf_le, sizeof(adjusted_tsf_le)); + + + + params.vdev_id = vdev_id; + params.tim_ie_offset = bcn_info->timIeOffset - bytes_to_strip; + params.tmpl_len = tmpl_len; + params.frm = frm; + params.tmpl_len_aligned = tmpl_len_aligned; + + ret = wmi_unified_beacon_send_cmd(wma->wmi_handle, + ¶ms); + if (QDF_IS_STATUS_ERROR(ret)) { + WMA_LOGE("%s: Failed to send bcn tmpl: %d", __func__, ret); + } + + return ret; +} + +/** + * wma_store_bcn_tmpl() - store beacon template + * @wma: wma handle + * @vdev_id: vdev id + * @bcn_info: beacon params + * + * This function stores beacon template locally. + * This will send to target on the reception of + * SWBA event. + * + * Return: QDF status + */ +static QDF_STATUS wma_store_bcn_tmpl(tp_wma_handle wma, uint8_t vdev_id, + tpSendbeaconParams bcn_info) +{ + struct beacon_info *bcn; + uint32_t len; + uint8_t *bcn_payload; + struct beacon_tim_ie *tim_ie; + + bcn = wma->interfaces[vdev_id].beacon; + if (!bcn || !bcn->buf) { + WMA_LOGE("%s: Memory is not allocated to hold bcn template", + __func__); + return QDF_STATUS_E_INVAL; + } + + len = *(u32 *) &bcn_info->beacon[0]; + if (len > WMA_BCN_BUF_MAX_SIZE) { + WMA_LOGE("%s: Received beacon len %d exceeding max limit %d", + __func__, len, WMA_BCN_BUF_MAX_SIZE); + return QDF_STATUS_E_INVAL; + } + WMA_LOGD("%s: Storing received beacon template buf to local buffer", + __func__); + qdf_spin_lock_bh(&bcn->lock); + + /* + * Copy received beacon template content in local buffer. + * this will be send to target on the reception of SWBA + * event from target. + */ + qdf_nbuf_trim_tail(bcn->buf, qdf_nbuf_len(bcn->buf)); + memcpy(qdf_nbuf_data(bcn->buf), + bcn_info->beacon + 4 /* Exclude beacon length field */, + len); + if (bcn_info->timIeOffset > 3) { + bcn->tim_ie_offset = bcn_info->timIeOffset - 4; + } else { + bcn->tim_ie_offset = bcn_info->timIeOffset; + } + + if (bcn_info->p2pIeOffset > 3) { + bcn->p2p_ie_offset = bcn_info->p2pIeOffset - 4; + } else { + bcn->p2p_ie_offset = bcn_info->p2pIeOffset; + } + bcn_payload = qdf_nbuf_data(bcn->buf); + if (bcn->tim_ie_offset) { + tim_ie = + (struct beacon_tim_ie *)(&bcn_payload[bcn->tim_ie_offset]); + /* + * Intial Value of bcn->dtim_count will be 0. + * But if the beacon gets updated then current dtim + * count will be restored + */ + tim_ie->dtim_count = bcn->dtim_count; + tim_ie->tim_bitctl = 0; + } + + qdf_nbuf_put_tail(bcn->buf, len); + bcn->len = len; + + qdf_spin_unlock_bh(&bcn->lock); + + return QDF_STATUS_SUCCESS; +} + +/** + * wma_tbttoffset_update_event_handler() - tbtt offset update handler + * @handle: wma handle + * @event: event buffer + * @len: data length + * + * Return: 0 for success or error code + */ +int wma_tbttoffset_update_event_handler(void *handle, uint8_t *event, + uint32_t len) +{ + tp_wma_handle wma = (tp_wma_handle) handle; + WMI_TBTTOFFSET_UPDATE_EVENTID_param_tlvs *param_buf; + wmi_tbtt_offset_event_fixed_param *tbtt_offset_event; + struct wma_txrx_node *intf; + struct beacon_info *bcn; + tSendbeaconParams bcn_info; + uint32_t *adjusted_tsf = NULL; + uint32_t if_id = 0, vdev_map; + + if (!wma) { + WMA_LOGE("Invalid wma handle"); + return -EINVAL; + } + + param_buf = (WMI_TBTTOFFSET_UPDATE_EVENTID_param_tlvs *) event; + if (!param_buf) { + WMA_LOGE("Invalid tbtt update event buffer"); + return -EINVAL; + } + + tbtt_offset_event = param_buf->fixed_param; + intf = wma->interfaces; + vdev_map = tbtt_offset_event->vdev_map; + adjusted_tsf = param_buf->tbttoffset_list; + if (!adjusted_tsf) { + WMA_LOGE("%s: Invalid adjusted_tsf", __func__); + return -EINVAL; + } + + for (; (vdev_map); vdev_map >>= 1, if_id++) { + if (!(vdev_map & 0x1) || (!(intf[if_id].handle))) + continue; + + bcn = intf[if_id].beacon; + if (!bcn) { + WMA_LOGE("%s: Invalid beacon", __func__); + return -EINVAL; + } + if (!bcn->buf) { + WMA_LOGE("%s: Invalid beacon buffer", __func__); + return -EINVAL; + } + /* Save the adjusted TSF */ + intf[if_id].tsfadjust = adjusted_tsf[if_id]; + + qdf_spin_lock_bh(&bcn->lock); + qdf_mem_zero(&bcn_info, sizeof(bcn_info)); + bcn_info.beacon = qdf_nbuf_data(bcn->buf); + bcn_info.p2pIeOffset = bcn->p2p_ie_offset; + bcn_info.beaconLength = bcn->len; + bcn_info.timIeOffset = bcn->tim_ie_offset; + qdf_spin_unlock_bh(&bcn->lock); + + /* Update beacon template in firmware */ + wma_unified_bcn_tmpl_send(wma, if_id, &bcn_info, 0); + } + return 0; +} + +/** + * wma_p2p_go_set_beacon_ie() - set beacon IE for p2p go + * @wma_handle: wma handle + * @vdev_id: vdev id + * @p2pIe: p2p IE + * + * Return: 0 for success or error code + */ +static int wma_p2p_go_set_beacon_ie(t_wma_handle *wma_handle, + A_UINT32 vdev_id, uint8_t *p2pIe) +{ + if (!wma_handle) { + WMA_LOGE("%s: wma handle is NULL", __func__); + return QDF_STATUS_E_FAILURE; + } + + return wmi_unified_p2p_go_set_beacon_ie_cmd(wma_handle->wmi_handle, + vdev_id, p2pIe); +} + +/** + * wma_send_probe_rsp_tmpl() - send probe resp template + * @wma: wma handle + * @probe_rsp_info: probe response info + * + * This funciton sends probe response template to fw which + * firmware will use in case of probe response offload. + * + * Return: none + */ +void wma_send_probe_rsp_tmpl(tp_wma_handle wma, + tpSendProbeRespParams probe_rsp_info) +{ + ol_txrx_vdev_handle vdev; + uint8_t vdev_id; + tpAniProbeRspStruct probe_rsp; + + if (!probe_rsp_info) { + WMA_LOGE(FL("probe_rsp_info is NULL")); + return; + } + + probe_rsp = (tpAniProbeRspStruct) (probe_rsp_info->pProbeRespTemplate); + if (!probe_rsp) { + WMA_LOGE(FL("probe_rsp is NULL")); + return; + } + + vdev = wma_find_vdev_by_addr(wma, probe_rsp->macHdr.sa, &vdev_id); + if (!vdev) { + WMA_LOGE(FL("failed to get vdev handle")); + return; + } + + if (WMI_SERVICE_IS_ENABLED(wma->wmi_service_bitmap, + WMI_SERVICE_BEACON_OFFLOAD)) { + WMA_LOGI("Beacon Offload Enabled Sending Unified command"); + if (wmi_unified_probe_rsp_tmpl_send(wma, vdev_id, + probe_rsp_info) < 0) { + WMA_LOGE(FL("wmi_unified_probe_rsp_tmpl_send Failed ")); + return; + } + } +} + +/** + * wma_send_beacon() - send beacon template + * @wma: wma handle + * @bcn_info: beacon info + * + * This funciton store beacon template locally and + * update keep alive parameters + * + * Return: none + */ +void wma_send_beacon(tp_wma_handle wma, tpSendbeaconParams bcn_info) +{ + ol_txrx_vdev_handle vdev; + uint8_t vdev_id; + QDF_STATUS status; + uint8_t *p2p_ie; + tpAniBeaconStruct beacon; + struct vdev_up_params param = {0}; + + beacon = (tpAniBeaconStruct) (bcn_info->beacon); + vdev = wma_find_vdev_by_addr(wma, beacon->macHdr.sa, &vdev_id); + if (!vdev) { + WMA_LOGE("%s : failed to get vdev handle", __func__); + return; + } + + if (WMI_SERVICE_IS_ENABLED(wma->wmi_service_bitmap, + WMI_SERVICE_BEACON_OFFLOAD)) { + WMA_LOGI("Beacon Offload Enabled Sending Unified command"); + status = wma_unified_bcn_tmpl_send(wma, vdev_id, bcn_info, 4); + if (QDF_IS_STATUS_ERROR(status)) { + WMA_LOGE("%s : wmi_unified_bcn_tmpl_send Failed ", + __func__); + return; + } + + if (bcn_info->p2pIeOffset) { + p2p_ie = bcn_info->beacon + bcn_info->p2pIeOffset; + WMA_LOGI + (" %s: p2pIe is present - vdev_id %hu, p2p_ie = %p, p2p ie len = %hu", + __func__, vdev_id, p2p_ie, p2p_ie[1]); + if (wma_p2p_go_set_beacon_ie(wma, vdev_id, p2p_ie) < 0) { + WMA_LOGE + ("%s : wmi_unified_bcn_tmpl_send Failed ", + __func__); + return; + } + } + } + status = wma_store_bcn_tmpl(wma, vdev_id, bcn_info); + if (status != QDF_STATUS_SUCCESS) { + WMA_LOGE("%s : wma_store_bcn_tmpl Failed", __func__); + return; + } + if (!((qdf_atomic_read( + &wma->interfaces[vdev_id].vdev_restart_params. + hidden_ssid_restart_in_progress)) || + (wma->interfaces[vdev_id].is_channel_switch))) { + if (!wma->interfaces[vdev_id].vdev_up) { + param.vdev_id = vdev_id; + param.assoc_id = 0; + status = wmi_unified_vdev_up_send(wma->wmi_handle, + bcn_info->bssId, + ¶m); + if (QDF_IS_STATUS_ERROR(status)) { + WMA_LOGE(FL("failed to send vdev up")); + cds_set_do_hw_mode_change_flag(false); + return; + } + wma->interfaces[vdev_id].vdev_up = true; + wma_set_sap_keepalive(wma, vdev_id); + wma_set_vdev_mgmt_rate(wma, vdev_id); + } + } +} + +/** + * wma_set_keepalive_req() - send keep alive request to fw + * @wma: wma handle + * @keepalive: keep alive parameters + * + * Return: none + */ +void wma_set_keepalive_req(tp_wma_handle wma, + tSirKeepAliveReq *keepalive) +{ + WMA_LOGD("KEEPALIVE:PacketType:%d", keepalive->packetType); + wma_set_sta_keep_alive(wma, keepalive->sessionId, + keepalive->packetType, + keepalive->timePeriod, + keepalive->hostIpv4Addr, + keepalive->destIpv4Addr, + keepalive->dest_macaddr.bytes); + + qdf_mem_free(keepalive); +} + +/** + * wma_beacon_miss_handler() - beacon miss event handler + * @wma: wma handle + * @vdev_id: vdev id + * @riis: rssi value + * + * This function send beacon miss indication to upper layers. + * + * Return: none + */ +void wma_beacon_miss_handler(tp_wma_handle wma, uint32_t vdev_id, int32_t rssi) +{ + tSirSmeMissedBeaconInd *beacon_miss_ind; + + beacon_miss_ind = (tSirSmeMissedBeaconInd *) qdf_mem_malloc + (sizeof(tSirSmeMissedBeaconInd)); + + if (NULL == beacon_miss_ind) { + WMA_LOGE("%s: Memory allocation failure", __func__); + return; + } + beacon_miss_ind->messageType = WMA_MISSED_BEACON_IND; + beacon_miss_ind->length = sizeof(tSirSmeMissedBeaconInd); + beacon_miss_ind->bssIdx = vdev_id; + + wma_send_msg(wma, WMA_MISSED_BEACON_IND, (void *)beacon_miss_ind, 0); + wma_lost_link_info_handler(wma, vdev_id, rssi + + WMA_TGT_NOISE_FLOOR_DBM); +} + +/** + * wma_process_mgmt_tx_completion() - process mgmt completion + * @wma_handle: wma handle + * @desc_id: descriptor id + * @status: status + * + * Return: 0 for success or error code + */ +static int wma_process_mgmt_tx_completion(tp_wma_handle wma_handle, + uint32_t desc_id, uint32_t status) +{ + struct wmi_desc_t *wmi_desc; + ol_txrx_pdev_handle pdev = cds_get_context(QDF_MODULE_ID_TXRX); + tp_wma_packetdump_cb packetdump_cb; + + if (pdev == NULL) { + WMA_LOGE("%s: NULL pdev pointer", __func__); + return -EINVAL; + } + + WMA_LOGI("%s: status:%d wmi_desc_id:%d", __func__, status, desc_id); + + wmi_desc = (struct wmi_desc_t *) + (&wma_handle->wmi_desc_pool.array[desc_id]); + + if (!wmi_desc) { + WMA_LOGE("%s: Invalid wmi desc", __func__); + return -EINVAL; + } + + if (wmi_desc->nbuf) + qdf_nbuf_unmap_single(pdev->osdev, wmi_desc->nbuf, + QDF_DMA_TO_DEVICE); + + packetdump_cb = wma_handle->wma_mgmt_tx_packetdump_cb; + if (packetdump_cb) + packetdump_cb(wmi_desc->nbuf, QDF_STATUS_SUCCESS, + wmi_desc->vdev_id, TX_MGMT_PKT); + + if (wmi_desc->tx_cmpl_cb) { + wmi_desc->tx_cmpl_cb(wma_handle->mac_context, + wmi_desc->nbuf, 1); + wmi_desc->nbuf = NULL; + } + + if (wmi_desc->ota_post_proc_cb) + wmi_desc->ota_post_proc_cb((tpAniSirGlobal) + wma_handle->mac_context, + (status ? 0 : 1)); + + wmi_desc_put(wma_handle, wmi_desc); + return 0; +} + +/** + * wma_mgmt_tx_completion_handler() - wma mgmt Tx completion event handler + * @handle: wma handle + * @cmpl_event_params: completion event handler data + * @len: length of @cmpl_event_params + * + * Return: 0 on success; error number otherwise + */ + +int wma_mgmt_tx_completion_handler(void *handle, uint8_t *cmpl_event_params, + uint32_t len) +{ + tp_wma_handle wma_handle = (tp_wma_handle)handle; + WMI_MGMT_TX_COMPLETION_EVENTID_param_tlvs *param_buf; + wmi_mgmt_tx_compl_event_fixed_param *cmpl_params; + + param_buf = (WMI_MGMT_TX_COMPLETION_EVENTID_param_tlvs *) + cmpl_event_params; + if (!param_buf || !wma_handle) { + WMA_LOGE("%s: Invalid mgmt Tx completion event", __func__); + return -EINVAL; + } + cmpl_params = param_buf->fixed_param; + + wma_process_mgmt_tx_completion(wma_handle, + cmpl_params->desc_id, cmpl_params->status); + + return 0; +} + +/** + * wma_mgmt_tx_bundle_completion_handler() - mgmt bundle comp handler + * @handle: wma handle + * @buf: buffer + * @len: length + * + * Return: 0 for success or error code + */ +int wma_mgmt_tx_bundle_completion_handler(void *handle, uint8_t *buf, + uint32_t len) +{ + tp_wma_handle wma_handle = (tp_wma_handle)handle; + WMI_MGMT_TX_BUNDLE_COMPLETION_EVENTID_param_tlvs *param_buf; + wmi_mgmt_tx_compl_bundle_event_fixed_param *cmpl_params; + uint32_t num_reports; + uint32_t *desc_ids; + uint32_t *status; + int i; + + param_buf = (WMI_MGMT_TX_BUNDLE_COMPLETION_EVENTID_param_tlvs *)buf; + if (!param_buf || !wma_handle) { + WMA_LOGE("%s: Invalid mgmt Tx completion event", __func__); + return -EINVAL; + } + cmpl_params = param_buf->fixed_param; + num_reports = cmpl_params->num_reports; + desc_ids = (uint32_t *)(param_buf->desc_ids); + status = (uint32_t *)(param_buf->status); + + for (i = 0; i < num_reports; i++) + wma_process_mgmt_tx_completion(wma_handle, + desc_ids[i], status[i]); + return 0; +} + +/** + * wma_process_update_opmode() - process update VHT opmode cmd from UMAC + * @wma_handle: wma handle + * @update_vht_opmode: vht opmode + * + * Return: none + */ +void wma_process_update_opmode(tp_wma_handle wma_handle, + tUpdateVHTOpMode *update_vht_opmode) +{ + struct wma_txrx_node *iface; + uint16_t chan_mode; + + + iface = &wma_handle->interfaces[update_vht_opmode->smesessionId]; + if (iface == NULL) + return; + + chan_mode = wma_chan_phy_mode(cds_freq_to_chan(iface->mhz), + update_vht_opmode->opMode, + update_vht_opmode->dot11_mode); + if (MODE_UNKNOWN == chan_mode) + return; + + WMA_LOGD("%s: opMode = %d, chanMode = %d, dot11mode = %d ", + __func__, + update_vht_opmode->opMode, chan_mode, + update_vht_opmode->dot11_mode); + + wma_set_peer_param(wma_handle, update_vht_opmode->peer_mac, + WMI_PEER_PHYMODE, chan_mode, + update_vht_opmode->smesessionId); + + wma_set_peer_param(wma_handle, update_vht_opmode->peer_mac, + WMI_PEER_CHWIDTH, update_vht_opmode->opMode, + update_vht_opmode->smesessionId); +} + +/** + * wma_process_update_rx_nss() - process update RX NSS cmd from UMAC + * @wma_handle: wma handle + * @update_rx_nss: rx nss value + * + * Return: none + */ +void wma_process_update_rx_nss(tp_wma_handle wma_handle, + tUpdateRxNss *update_rx_nss) +{ + struct wma_txrx_node *intr = + &wma_handle->interfaces[update_rx_nss->smesessionId]; + int rx_nss = update_rx_nss->rxNss; + + if (rx_nss > WMA_MAX_NSS) + rx_nss = WMA_MAX_NSS; + + intr->nss = (uint8_t)rx_nss; + update_rx_nss->rxNss = (uint32_t)rx_nss; + + WMA_LOGD("%s: Rx Nss = %d", __func__, update_rx_nss->rxNss); + + wma_set_peer_param(wma_handle, update_rx_nss->peer_mac, + WMI_PEER_NSS, update_rx_nss->rxNss, + update_rx_nss->smesessionId); +} + +/** + * wma_process_update_membership() - process update group membership cmd + * @wma_handle: wma handle + * @membership: group membership info + * + * Return: none + */ +void wma_process_update_membership(tp_wma_handle wma_handle, + tUpdateMembership *membership) +{ + WMA_LOGD("%s: membership = %x ", __func__, membership->membership); + + wma_set_peer_param(wma_handle, membership->peer_mac, + WMI_PEER_MEMBERSHIP, membership->membership, + membership->smesessionId); +} + +/** + * wma_process_update_userpos() - process update user pos cmd from UMAC + * @wma_handle: wma handle + * @userpos: user pos value + * + * Return: none + */ +void wma_process_update_userpos(tp_wma_handle wma_handle, + tUpdateUserPos *userpos) +{ + WMA_LOGD("%s: userPos = %x ", __func__, userpos->userPos); + + wma_set_peer_param(wma_handle, userpos->peer_mac, + WMI_PEER_USERPOS, userpos->userPos, + userpos->smesessionId); + + /* Now that membership/userpos is updated in fw, + * enable GID PPS. + */ + wma_set_ppsconfig(userpos->smesessionId, WMA_VHT_PPS_GID_MATCH, 1); + +} + +QDF_STATUS wma_set_cts2self_for_p2p_go(void *wma_handle, + uint32_t cts2self_for_p2p_go) +{ + int32_t ret; + tp_wma_handle wma = (tp_wma_handle)wma_handle; + struct pdev_params pdevparam; + + pdevparam.param_id = WMI_PDEV_PARAM_CTS2SELF_FOR_P2P_GO_CONFIG; + pdevparam.param_value = cts2self_for_p2p_go; + + ret = wmi_unified_pdev_param_send(wma->wmi_handle, + &pdevparam, + WMA_WILDCARD_PDEV_ID); + if (ret) { + WMA_LOGE("Fail to Set CTS2SELF for p2p GO %d", + cts2self_for_p2p_go); + return QDF_STATUS_E_FAILURE; + } + + WMA_LOGD("Successfully Set CTS2SELF for p2p GO %d", + cts2self_for_p2p_go); + + return QDF_STATUS_SUCCESS; +} + + +/** + * wma_set_htconfig() - set ht config parameters to target + * @vdev_id: vdev id + * @ht_capab: ht capablity + * @value: value of ht param + * + * Return: QDF status + */ +QDF_STATUS wma_set_htconfig(uint8_t vdev_id, uint16_t ht_capab, int value) +{ + tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA); + QDF_STATUS ret = QDF_STATUS_E_FAILURE; + + if (NULL == wma) { + WMA_LOGE("%s: Failed to get wma", __func__); + return QDF_STATUS_E_INVAL; + } + + switch (ht_capab) { + case WNI_CFG_HT_CAP_INFO_ADVANCE_CODING: + ret = wma_vdev_set_param(wma->wmi_handle, vdev_id, + WMI_VDEV_PARAM_LDPC, + value); + break; + case WNI_CFG_HT_CAP_INFO_TX_STBC: + ret = wma_vdev_set_param(wma->wmi_handle, vdev_id, + WMI_VDEV_PARAM_TX_STBC, + value); + break; + case WNI_CFG_HT_CAP_INFO_RX_STBC: + ret = wma_vdev_set_param(wma->wmi_handle, vdev_id, + WMI_VDEV_PARAM_RX_STBC, + value); + break; + case WNI_CFG_HT_CAP_INFO_SHORT_GI_20MHZ: + case WNI_CFG_HT_CAP_INFO_SHORT_GI_40MHZ: + WMA_LOGE("%s: ht_capab = %d, value = %d", __func__, ht_capab, + value); + ret = wma_vdev_set_param(wma->wmi_handle, vdev_id, + WMI_VDEV_PARAM_SGI, value); + if (ret == QDF_STATUS_SUCCESS) + wma->interfaces[vdev_id].config.shortgi = value; + break; + default: + WMA_LOGE("%s:INVALID HT CONFIG", __func__); + } + + return ret; +} + +/** + * wma_hidden_ssid_vdev_restart() - vdev restart for hidden ssid + * @wma_handle: wma handle + * @pReq: hidden ssid vdev restart request + * + * Return: none + */ +void wma_hidden_ssid_vdev_restart(tp_wma_handle wma_handle, + tHalHiddenSsidVdevRestart *pReq) +{ + struct wma_txrx_node *intr = wma_handle->interfaces; + struct wma_target_req *msg; + + if ((pReq->sessionId != + intr[pReq->sessionId].vdev_restart_params.vdev_id) + || !((intr[pReq->sessionId].type == WMI_VDEV_TYPE_AP) + && (intr[pReq->sessionId].sub_type == 0))) { + WMA_LOGE("%s : invalid session id", __func__); + return; + } + + intr[pReq->sessionId].vdev_restart_params.ssidHidden = pReq->ssidHidden; + qdf_atomic_set(&intr[pReq->sessionId].vdev_restart_params. + hidden_ssid_restart_in_progress, 1); + + msg = wma_fill_vdev_req(wma_handle, pReq->sessionId, + WMA_HIDDEN_SSID_VDEV_RESTART, + WMA_TARGET_REQ_TYPE_VDEV_STOP, pReq, + WMA_VDEV_STOP_REQUEST_TIMEOUT); + if (!msg) { + WMA_LOGE("%s: Failed to fill vdev restart request for vdev_id %d", + __func__, pReq->sessionId); + return; + } + + /* vdev stop -> vdev restart -> vdev up */ + WMA_LOGD("%s, vdev_id: %d, pausing tx_ll_queue for VDEV_STOP", + __func__, pReq->sessionId); + ol_txrx_vdev_pause(wma_handle->interfaces[pReq->sessionId].handle, + OL_TXQ_PAUSE_REASON_VDEV_STOP); + wma_handle->interfaces[pReq->sessionId].pause_bitmap |= + (1 << PAUSE_TYPE_HOST); + if (wma_send_vdev_stop_to_fw(wma_handle, pReq->sessionId)) { + WMA_LOGE("%s: %d Failed to send vdev stop", __func__, __LINE__); + qdf_atomic_set(&intr[pReq->sessionId].vdev_restart_params. + hidden_ssid_restart_in_progress, 0); + wma_remove_vdev_req(wma_handle, pReq->sessionId, + WMA_TARGET_REQ_TYPE_VDEV_STOP); + return; + } +} + + +#ifdef WLAN_FEATURE_11W + +/** + * wma_extract_ccmp_pn() - extract 6 byte PN from the CCMP header + * @ccmp_ptr: CCMP header + * + * Return: PN extracted from header. + */ +static uint64_t wma_extract_ccmp_pn(uint8_t *ccmp_ptr) +{ + uint8_t rsvd, key, pn[6]; + uint64_t new_pn; + + /* + * +-----+-----+------+----------+-----+-----+-----+-----+ + * | PN0 | PN1 | rsvd | rsvd/key | PN2 | PN3 | PN4 | PN5 | + * +-----+-----+------+----------+-----+-----+-----+-----+ + * CCMP Header Format + */ + + /* Extract individual bytes */ + pn[0] = (uint8_t) *ccmp_ptr; + pn[1] = (uint8_t) *(ccmp_ptr + 1); + rsvd = (uint8_t) *(ccmp_ptr + 2); + key = (uint8_t) *(ccmp_ptr + 3); + pn[2] = (uint8_t) *(ccmp_ptr + 4); + pn[3] = (uint8_t) *(ccmp_ptr + 5); + pn[4] = (uint8_t) *(ccmp_ptr + 6); + pn[5] = (uint8_t) *(ccmp_ptr + 7); + + /* Form 6 byte PN with 6 individual bytes of PN */ + new_pn = ((uint64_t) pn[5] << 40) | + ((uint64_t) pn[4] << 32) | + ((uint64_t) pn[3] << 24) | + ((uint64_t) pn[2] << 16) | + ((uint64_t) pn[1] << 8) | ((uint64_t) pn[0] << 0); + + WMA_LOGE("PN of received packet is %llu", new_pn); + return new_pn; +} + +/** + * wma_is_ccmp_pn_replay_attack() - detect replay attacking using PN in CCMP + * @cds_ctx: cds context + * @wh: 802.11 frame header + * @ccmp_ptr: CCMP frame header + * + * Return: true/false + */ +static bool +wma_is_ccmp_pn_replay_attack(void *cds_ctx, struct ieee80211_frame *wh, + uint8_t *ccmp_ptr) +{ + ol_txrx_pdev_handle pdev; + ol_txrx_vdev_handle vdev; + ol_txrx_peer_handle peer; + uint8_t vdev_id, peer_id; + uint8_t *last_pn_valid; + uint64_t *last_pn, new_pn; + uint32_t *rmf_pn_replays; + + pdev = cds_get_context(QDF_MODULE_ID_TXRX); + if (!pdev) { + WMA_LOGE("%s: Failed to find pdev", __func__); + return true; + } + + vdev = wma_find_vdev_by_bssid(cds_ctx, wh->i_addr3, &vdev_id); + if (!vdev) { + WMA_LOGE("%s: Failed to find vdev", __func__); + return true; + } + + /* Retrieve the peer based on vdev and addr */ + peer = ol_txrx_find_peer_by_addr_and_vdev(pdev, vdev, wh->i_addr2, + &peer_id); + + if (NULL == peer) { + WMA_LOGE("%s: Failed to find peer, Not able to validate PN", + __func__); + return true; + } + + new_pn = wma_extract_ccmp_pn(ccmp_ptr); + ol_txrx_get_pn_info(peer, &last_pn_valid, &last_pn, &rmf_pn_replays); + + if (*last_pn_valid) { + if (new_pn > *last_pn) { + *last_pn = new_pn; + WMA_LOGE("%s: PN validation successful", __func__); + } else { + WMA_LOGE("%s: PN Replay attack detected", __func__); + /* per 11W amendment, keeping track of replay attacks */ + *rmf_pn_replays += 1; + return true; + } + } else { + *last_pn_valid = 1; + *last_pn = new_pn; + } + + return false; +} + +/** + * wma_process_bip() - process mmie in rmf frame + * @wma_handle: wma handle + * @iface: txrx node + * @wh: 80211 frame + * @wbuf: Buffer + * + * Return: 0 for success or error code + */ + +static +int wma_process_bip(tp_wma_handle wma_handle, + struct wma_txrx_node *iface, + struct ieee80211_frame *wh, + qdf_nbuf_t wbuf +) +{ + uint16_t key_id; + uint8_t *efrm; + + efrm = qdf_nbuf_data(wbuf) + qdf_nbuf_len(wbuf); + key_id = (uint16_t)*(efrm - cds_get_mmie_size() + 2); + + if (!((key_id == WMA_IGTK_KEY_INDEX_4) + || (key_id == WMA_IGTK_KEY_INDEX_5))) { + WMA_LOGE(FL("Invalid KeyID(%d) dropping the frame"), key_id); + return -EINVAL; + } + if (WMI_SERVICE_IS_ENABLED(wma_handle->wmi_service_bitmap, + WMI_SERVICE_STA_PMF_OFFLOAD)) { + /* + * if 11w offload is enabled then mmie validation is performed + * in firmware, host just need to trim the mmie. + */ + qdf_nbuf_trim_tail(wbuf, cds_get_mmie_size()); + } else { + if (cds_is_mmie_valid(iface->key.key, + iface->key.key_id[key_id - WMA_IGTK_KEY_INDEX_4].ipn, + (uint8_t *) wh, efrm)) { + WMA_LOGE(FL("Protected BC/MC frame MMIE validation successful")); + /* Remove MMIE */ + qdf_nbuf_trim_tail(wbuf, cds_get_mmie_size()); + } else { + WMA_LOGE(FL("BC/MC MIC error or MMIE not present, dropping the frame")); + return -EINVAL; + } + } + return 0; +} + +/** + * wma_process_rmf_frame() - process rmf frame + * @wma_handle: wma handle + * @iface: txrx node + * @wh: 80211 frame + * @rx_pkt: rx packet + * @wbuf: Buffer + * + * Return: 0 for success or error code + */ +static +int wma_process_rmf_frame(tp_wma_handle wma_handle, + struct wma_txrx_node *iface, + struct ieee80211_frame *wh, + cds_pkt_t *rx_pkt, + qdf_nbuf_t wbuf) +{ + uint8_t *orig_hdr; + uint8_t *ccmp; + + if ((wh)->i_fc[1] & IEEE80211_FC1_WEP) { + if (IEEE80211_IS_BROADCAST(wh->i_addr1) || + IEEE80211_IS_MULTICAST(wh->i_addr1)) { + WMA_LOGE("Encrypted BC/MC frame dropping the frame"); + cds_pkt_return_packet(rx_pkt); + return -EINVAL; + } + + orig_hdr = (uint8_t *) qdf_nbuf_data(wbuf); + /* Pointer to head of CCMP header */ + ccmp = orig_hdr + sizeof(*wh); + if (wma_is_ccmp_pn_replay_attack( + wma_handle, wh, ccmp)) { + WMA_LOGE("Dropping the frame"); + cds_pkt_return_packet(rx_pkt); + return -EINVAL; + } + + /* Strip privacy headers (and trailer) + * for a received frame + */ + qdf_mem_move(orig_hdr + + IEEE80211_CCMP_HEADERLEN, wh, + sizeof(*wh)); + qdf_nbuf_pull_head(wbuf, + IEEE80211_CCMP_HEADERLEN); + qdf_nbuf_trim_tail(wbuf, IEEE80211_CCMP_MICLEN); + /* + * CCMP header has been pulled off + * reinitialize the start pointer of mac header + * to avoid accessing incorrect address + */ + wh = (struct ieee80211_frame *) qdf_nbuf_data(wbuf); + rx_pkt->pkt_meta.mpdu_hdr_ptr = + qdf_nbuf_data(wbuf); + rx_pkt->pkt_meta.mpdu_len = qdf_nbuf_len(wbuf); + rx_pkt->pkt_meta.mpdu_data_len = + rx_pkt->pkt_meta.mpdu_len - + rx_pkt->pkt_meta.mpdu_hdr_len; + rx_pkt->pkt_meta.mpdu_data_ptr = + rx_pkt->pkt_meta.mpdu_hdr_ptr + + rx_pkt->pkt_meta.mpdu_hdr_len; + rx_pkt->pkt_meta.tsf_delta = rx_pkt->pkt_meta.tsf_delta; + rx_pkt->pkt_buf = wbuf; + WMA_LOGD(FL("BSSID: "MAC_ADDRESS_STR" tsf_delta: %u"), + MAC_ADDR_ARRAY(wh->i_addr3), rx_pkt->pkt_meta.tsf_delta); + } else { + if (IEEE80211_IS_BROADCAST(wh->i_addr1) || + IEEE80211_IS_MULTICAST(wh->i_addr1)) { + if (0 != wma_process_bip(wma_handle, iface, wh, wbuf)) { + cds_pkt_return_packet(rx_pkt); + return -EINVAL; + } + } else { + WMA_LOGE("Rx unprotected unicast mgmt frame"); + rx_pkt->pkt_meta.dpuFeedback = + DPU_FEEDBACK_UNPROTECTED_ERROR; + } + } + return 0; +} +#endif + +/** + * wma_is_pkt_drop_candidate() - check if the mgmt frame should be droppped + * @wma_handle: wma handle + * @peer_addr: peer MAC address + * @subtype: Management frame subtype + * + * This function is used to decide if a particular management frame should be + * dropped to prevent DOS attack. Timestamp is used to decide the DOS attack. + * + * Return: true if the packet should be dropped and false oterwise + */ +static bool wma_is_pkt_drop_candidate(tp_wma_handle wma_handle, + uint8_t *peer_addr, uint8_t subtype) +{ + struct ol_txrx_peer_t *peer = NULL; + struct ol_txrx_pdev_t *pdev_ctx; + uint8_t peer_id; + bool should_drop = false; + + /* + * Currently this function handles only Disassoc, + * Deauth and Assoc req frames. Return false for + * all other frames. + */ + if (subtype != IEEE80211_FC0_SUBTYPE_DISASSOC && + subtype != IEEE80211_FC0_SUBTYPE_DEAUTH && + subtype != IEEE80211_FC0_SUBTYPE_ASSOC_REQ) { + should_drop = false; + goto end; + } + + pdev_ctx = cds_get_context(QDF_MODULE_ID_TXRX); + if (!pdev_ctx) { + WMA_LOGE(FL("Failed to get the context")); + should_drop = true; + goto end; + } + + peer = ol_txrx_find_peer_by_addr_inc_ref(pdev_ctx, peer_addr, &peer_id); + if (!peer) { + if (SIR_MAC_MGMT_ASSOC_REQ != subtype) { + WMA_LOGI( + FL("Received mgmt frame: %0x from unknow peer: %pM"), + subtype, peer_addr); + should_drop = true; + } + goto end; + } + + switch (subtype) { + case SIR_MAC_MGMT_ASSOC_REQ: + if (peer->last_assoc_rcvd) { + if (qdf_get_system_timestamp() - peer->last_assoc_rcvd < + WMA_MGMT_FRAME_DETECT_DOS_TIMER) { + WMA_LOGI(FL("Dropping Assoc Req received")); + should_drop = true; + } + } + peer->last_assoc_rcvd = qdf_get_system_timestamp(); + break; + case SIR_MAC_MGMT_DISASSOC: + if (peer->last_disassoc_rcvd) { + if (qdf_get_system_timestamp() - + peer->last_disassoc_rcvd < + WMA_MGMT_FRAME_DETECT_DOS_TIMER) { + WMA_LOGI(FL("Dropping DisAssoc received")); + should_drop = true; + } + } + peer->last_disassoc_rcvd = qdf_get_system_timestamp(); + break; + case SIR_MAC_MGMT_DEAUTH: + if (peer->last_deauth_rcvd) { + if (qdf_get_system_timestamp() - + peer->last_deauth_rcvd < + WMA_MGMT_FRAME_DETECT_DOS_TIMER) { + WMA_LOGI(FL("Dropping Deauth received")); + should_drop = true; + } + } + peer->last_deauth_rcvd = qdf_get_system_timestamp(); + break; + default: + break; + } + +end: + if (peer) + OL_TXRX_PEER_UNREF_DELETE(peer); + return should_drop; +} + +#define RATE_LIMIT 16 +/** + * wma_mgmt_rx_process() - process management rx frame. + * @handle: wma handle + * @data: rx data + * @data_len: data length + * + * Return: 0 for success or error code + */ +static int wma_mgmt_rx_process(void *handle, uint8_t *data, + uint32_t data_len) +{ + tp_wma_handle wma_handle = (tp_wma_handle) handle; + WMI_MGMT_RX_EVENTID_param_tlvs *param_tlvs = NULL; + wmi_mgmt_rx_hdr *hdr = NULL; + struct wma_txrx_node *iface = NULL; + uint8_t vdev_id = WMA_INVALID_VDEV_ID; + cds_pkt_t *rx_pkt; + qdf_nbuf_t wbuf; + struct ieee80211_frame *wh; + uint8_t mgt_type, mgt_subtype; + int status; + tp_wma_packetdump_cb packetdump_cb; + static uint8_t limit_prints_invalid_len = RATE_LIMIT - 1; + static uint8_t limit_prints_load_unload = RATE_LIMIT - 1; + static uint8_t limit_prints_recovery = RATE_LIMIT - 1; + + if (!wma_handle) { + WMA_LOGE("%s: Failed to get WMA context", __func__); + return -EINVAL; + } + + param_tlvs = (WMI_MGMT_RX_EVENTID_param_tlvs *) data; + if (!param_tlvs) { + WMA_LOGE("Get NULL point message from FW"); + return -EINVAL; + } + + hdr = param_tlvs->hdr; + if (!hdr) { + WMA_LOGE("Rx event is NULL"); + return -EINVAL; + } + + if (hdr->buf_len < sizeof(struct ieee80211_frame)) { + limit_prints_invalid_len++; + if (limit_prints_invalid_len == RATE_LIMIT) { + WMA_LOGD("Invalid rx mgmt packet"); + limit_prints_invalid_len = 0; + } + return -EINVAL; + } + + if (cds_is_load_or_unload_in_progress()) { + limit_prints_load_unload++; + if (limit_prints_load_unload == RATE_LIMIT) { + WMA_LOGD(FL("Load/Unload in progress")); + limit_prints_load_unload = 0; + } + return -EINVAL; + } + + if (cds_is_driver_recovering()) { + limit_prints_recovery++; + if (limit_prints_recovery == RATE_LIMIT) { + WMA_LOGD(FL("Recovery in progress")); + limit_prints_recovery = 0; + } + return -EINVAL; + } + + rx_pkt = qdf_mem_malloc(sizeof(*rx_pkt)); + if (!rx_pkt) { + WMA_LOGE("Failed to allocate rx packet"); + return -ENOMEM; + } + + qdf_mem_zero(rx_pkt, sizeof(*rx_pkt)); + + /* + * Fill in meta information needed by pe/lim + * TODO: Try to maintain rx metainfo as part of skb->data. + */ + rx_pkt->pkt_meta.channel = hdr->channel; + rx_pkt->pkt_meta.scan_src = hdr->flags; + + /* + * Get the rssi value from the current snr value + * using standard noise floor of -96. + */ + rx_pkt->pkt_meta.rssi = hdr->snr + WMA_NOISE_FLOOR_DBM_DEFAULT; + rx_pkt->pkt_meta.snr = hdr->snr; + + /* If absolute rssi is available from firmware, use it */ + if (hdr->rssi != 0) + rx_pkt->pkt_meta.rssi_raw = hdr->rssi; + else + rx_pkt->pkt_meta.rssi_raw = rx_pkt->pkt_meta.rssi; + + + /* + * FIXME: Assigning the local timestamp as hw timestamp is not + * available. Need to see if pe/lim really uses this data. + */ + rx_pkt->pkt_meta.timestamp = (uint32_t) jiffies; + rx_pkt->pkt_meta.mpdu_hdr_len = sizeof(struct ieee80211_frame); + rx_pkt->pkt_meta.mpdu_len = hdr->buf_len; + rx_pkt->pkt_meta.mpdu_data_len = hdr->buf_len - + rx_pkt->pkt_meta.mpdu_hdr_len; + + rx_pkt->pkt_meta.roamCandidateInd = 0; + + /* Why not just use rx_event->hdr.buf_len? */ + wbuf = qdf_nbuf_alloc(NULL, roundup(hdr->buf_len, 4), 0, 4, false); + if (!wbuf) { + WMA_LOGE("%s: Failed to allocate wbuf for mgmt rx len(%u)", + __func__, hdr->buf_len); + qdf_mem_free(rx_pkt); + return -ENOMEM; + } + + qdf_nbuf_put_tail(wbuf, hdr->buf_len); + qdf_nbuf_set_protocol(wbuf, ETH_P_CONTROL); + wh = (struct ieee80211_frame *)qdf_nbuf_data(wbuf); + + rx_pkt->pkt_meta.mpdu_hdr_ptr = qdf_nbuf_data(wbuf); + rx_pkt->pkt_meta.mpdu_data_ptr = rx_pkt->pkt_meta.mpdu_hdr_ptr + + rx_pkt->pkt_meta.mpdu_hdr_len; + rx_pkt->pkt_meta.tsf_delta = hdr->tsf_delta; + rx_pkt->pkt_buf = wbuf; + +#ifdef BIG_ENDIAN_HOST + { + /* + * for big endian host, copy engine byte_swap is enabled + * But the rx mgmt frame buffer content is in network byte order + * Need to byte swap the mgmt frame buffer content - so when + * copy engine does byte_swap - host gets buffer content in the + * correct byte order. + */ + int i; + uint32_t *destp, *srcp; + destp = (uint32_t *) wh; + srcp = (uint32_t *) param_tlvs->bufp; + for (i = 0; + i < (roundup(hdr->buf_len, sizeof(uint32_t)) / 4); i++) { + *destp = cpu_to_le32(*srcp); + destp++; + srcp++; + } + } +#else + qdf_mem_copy(wh, param_tlvs->bufp, hdr->buf_len); +#endif + + WMA_LOGD( + FL("BSSID: "MAC_ADDRESS_STR" snr = %d, rssi = %d, rssi_raw = %d tsf_delta: %u"), + MAC_ADDR_ARRAY(wh->i_addr3), + hdr->snr, rx_pkt->pkt_meta.rssi, + rx_pkt->pkt_meta.rssi_raw, + hdr->tsf_delta); + if (!wma_handle->mgmt_rx) { + WMA_LOGE("Not registered for Mgmt rx, dropping the frame"); + cds_pkt_return_packet(rx_pkt); + return -EINVAL; + } + + /* If it is a beacon/probe response, save it for future use */ + mgt_type = (wh)->i_fc[0] & IEEE80211_FC0_TYPE_MASK; + mgt_subtype = (wh)->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK; + +#ifdef WLAN_FEATURE_11W + if (mgt_type == IEEE80211_FC0_TYPE_MGT && + (mgt_subtype == IEEE80211_FC0_SUBTYPE_DISASSOC || + mgt_subtype == IEEE80211_FC0_SUBTYPE_DEAUTH || + mgt_subtype == IEEE80211_FC0_SUBTYPE_ACTION)) { + if (wma_find_vdev_by_bssid( + wma_handle, wh->i_addr3, &vdev_id)) { + iface = &(wma_handle->interfaces[vdev_id]); + if (iface->rmfEnabled) { + status = wma_process_rmf_frame(wma_handle, + iface, wh, rx_pkt, wbuf); + if (status) + return status; + /* + * CCMP header might have been pulled off + * reinitialize the start pointer of mac header + */ + wh = (struct ieee80211_frame *) + qdf_nbuf_data(wbuf); + + } + } + } +#endif /* WLAN_FEATURE_11W */ + rx_pkt->pkt_meta.sessionId = + (vdev_id == WMA_INVALID_VDEV_ID ? 0 : vdev_id); + + if (wma_is_pkt_drop_candidate(wma_handle, wh->i_addr2, mgt_subtype)) { + cds_pkt_return_packet(rx_pkt); + return -EINVAL; + } + + packetdump_cb = wma_handle->wma_mgmt_rx_packetdump_cb; + if ((mgt_type == IEEE80211_FC0_TYPE_MGT && + mgt_subtype != IEEE80211_FC0_SUBTYPE_BEACON) && + packetdump_cb) + packetdump_cb(rx_pkt->pkt_buf, QDF_STATUS_SUCCESS, + rx_pkt->pkt_meta.sessionId, RX_MGMT_PKT); + + wma_handle->mgmt_rx(wma_handle, rx_pkt); + return 0; +} + +/** + * wma_de_register_mgmt_frm_client() - deregister management frame + * @cds_ctx: cds context + * + * Return: QDF status + */ +QDF_STATUS wma_de_register_mgmt_frm_client(void *cds_ctx) +{ + tp_wma_handle wma_handle; + +#ifdef QCA_WIFI_FTM + if (cds_get_conparam() == QDF_GLOBAL_FTM_MODE) + return QDF_STATUS_SUCCESS; +#endif + + wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma_handle) { + WMA_LOGE("%s: Failed to get WMA context", __func__); + return QDF_STATUS_E_FAILURE; + } + + if (wmi_unified_unregister_event_handler(wma_handle->wmi_handle, + WMI_MGMT_RX_EVENTID) != 0) { + WMA_LOGE("Failed to Unregister rx mgmt handler with wmi"); + return QDF_STATUS_E_FAILURE; + } + wma_handle->mgmt_rx = NULL; + return QDF_STATUS_SUCCESS; +} + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +/** + * wma_register_roaming_callbacks() - Register roaming callbacks + * @cds_ctx: CDS Context + * @csr_roam_synch_cb: CSR roam synch callback routine pointer + * @pe_roam_synch_cb: PE roam synch callback routine pointer + * + * Register the SME and PE callback routines with WMA for + * handling roaming + * + * Return: Success or Failure Status + */ +QDF_STATUS wma_register_roaming_callbacks(void *cds_ctx, + QDF_STATUS (*csr_roam_synch_cb)(tpAniSirGlobal mac, + roam_offload_synch_ind *roam_synch_data, + tpSirBssDescription bss_desc_ptr, + enum sir_roam_op_code reason), + QDF_STATUS (*pe_roam_synch_cb)(tpAniSirGlobal mac, + roam_offload_synch_ind *roam_synch_data, + tpSirBssDescription bss_desc_ptr)) +{ + + tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA); + + if (!wma) { + WMA_LOGE("%s: Failed to get WMA context", __func__); + return QDF_STATUS_E_FAILURE; + } + wma->csr_roam_synch_cb = csr_roam_synch_cb; + wma->pe_roam_synch_cb = pe_roam_synch_cb; + WMA_LOGD("Registered roam synch callbacks with WMA successfully"); + return QDF_STATUS_SUCCESS; +} +#endif + +/** + * wma_register_mgmt_frm_client() - register management frame callback + * @cds_ctx: cds context + * @mgmt_frm_rx: management frame + * + * Return: QDF status + */ +QDF_STATUS wma_register_mgmt_frm_client( + void *cds_ctx, wma_mgmt_frame_rx_callback mgmt_frm_rx) +{ + tp_wma_handle wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + + if (!wma_handle) { + WMA_LOGE("%s: Failed to get WMA context", __func__); + return QDF_STATUS_E_FAILURE; + } + + if (wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_MGMT_RX_EVENTID, + wma_mgmt_rx_process, + WMA_RX_WORK_CTX) != 0) { + WMA_LOGE("Failed to register rx mgmt handler with wmi"); + return QDF_STATUS_E_FAILURE; + } + wma_handle->mgmt_rx = mgmt_frm_rx; + + return QDF_STATUS_SUCCESS; +} + +/** + * wma_register_packetdump_callback() - stores tx and rx mgmt packet dump + * callback handler + * @wma_mgmt_tx_packetdump_cb: tx mgmt packetdump cb + * @wma_mgmt_rx_packetdump_cb: rx mgmt packetdump cb + * + * This function is used to store tx and rx mgmt. packet dump callback + * + * Return: None + * + */ +void wma_register_packetdump_callback( + tp_wma_packetdump_cb wma_mgmt_tx_packetdump_cb, + tp_wma_packetdump_cb wma_mgmt_rx_packetdump_cb) +{ + tp_wma_handle wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + + if (!wma_handle) { + WMA_LOGE("wma handle is NULL"); + return; + } + + wma_handle->wma_mgmt_tx_packetdump_cb = wma_mgmt_tx_packetdump_cb; + wma_handle->wma_mgmt_rx_packetdump_cb = wma_mgmt_rx_packetdump_cb; +} + +/** + * wma_deregister_packetdump_callback() - removes tx and rx mgmt packet dump + * callback handler + * + * This function is used to remove tx and rx mgmt. packet dump callback + * + * Return: None + * + */ +void wma_deregister_packetdump_callback(void) +{ + tp_wma_handle wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + + if (!wma_handle) { + WMA_LOGE("wma handle is NULL"); + return; + } + + wma_handle->wma_mgmt_tx_packetdump_cb = NULL; + wma_handle->wma_mgmt_rx_packetdump_cb = NULL; +} diff --git a/drivers/staging/qcacld-3.0/core/wma/src/wma_nan_datapath.c b/drivers/staging/qcacld-3.0/core/wma/src/wma_nan_datapath.c new file mode 100644 index 0000000000000000000000000000000000000000..22eb647bb81339a26654b0566e9385e36a4b6fae --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/wma/src/wma_nan_datapath.c @@ -0,0 +1,1265 @@ +/* + * Copyright (c) 2016-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * 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. + */ + +/** + * DOC: wma_nan_datapath.c + * + * WMA NAN Data path API implementation + */ + +#include "wma.h" +#include "wma_api.h" +#include "wmi_unified_api.h" +#include "wmi_unified.h" +#include "wma_nan_datapath.h" +#include "wma_internal.h" +#include "cds_utils.h" + +/** + * wma_handle_ndp_initiator_req() - NDP initiator request handler + * @wma_handle: wma handle + * @req: request parameters + * + * Return: QDF_STATUS_SUCCESS on success; error number otherwise + */ +QDF_STATUS wma_handle_ndp_initiator_req(tp_wma_handle wma_handle, void *req) +{ + QDF_STATUS status; + int ret; + uint16_t len; + uint32_t vdev_id, ndp_cfg_len, ndp_app_info_len, pmk_len; + struct ndp_initiator_rsp ndp_rsp = {0}; + ol_txrx_vdev_handle vdev; + wmi_buf_t buf; + wmi_ndp_initiator_req_fixed_param *cmd; + cds_msg_t pe_msg = {0}; + struct ndp_initiator_req *ndp_req = req; + wmi_channel *ch_tlv; + uint8_t *tlv_ptr; + + if (NULL == ndp_req) { + WMA_LOGE(FL("Invalid ndp_req.")); + goto send_ndp_initiator_fail; + } + vdev_id = ndp_req->vdev_id; + vdev = wma_find_vdev_by_id(wma_handle, vdev_id); + if (!vdev) { + WMA_LOGE(FL("vdev not found for vdev id %d."), vdev_id); + goto send_ndp_initiator_fail; + } + + if (!WMA_IS_VDEV_IN_NDI_MODE(wma_handle->interfaces, vdev_id)) { + WMA_LOGE(FL("vdev :%d, not in NDI mode"), vdev_id); + goto send_ndp_initiator_fail; + } + + /* + * WMI command expects 4 byte alligned len: + * round up ndp_cfg_len and ndp_app_info_len to 4 bytes + */ + ndp_cfg_len = qdf_roundup(ndp_req->ndp_config.ndp_cfg_len, 4); + ndp_app_info_len = qdf_roundup(ndp_req->ndp_info.ndp_app_info_len, 4); + pmk_len = qdf_roundup(ndp_req->pmk.pmk_len, 4); + /* allocated memory for fixed params as well as variable size data */ + len = sizeof(*cmd) + sizeof(*ch_tlv) + (3 * WMI_TLV_HDR_SIZE) + + ndp_cfg_len + ndp_app_info_len + pmk_len; + + buf = wmi_buf_alloc(wma_handle->wmi_handle, len); + if (!buf) { + WMA_LOGE(FL("wmi_buf_alloc failed")); + goto send_ndp_initiator_fail; + } + cmd = (wmi_ndp_initiator_req_fixed_param *) wmi_buf_data(buf); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_ndp_initiator_req_fixed_param, + WMITLV_GET_STRUCT_TLVLEN( + wmi_ndp_initiator_req_fixed_param)); + cmd->vdev_id = ndp_req->vdev_id; + cmd->transaction_id = ndp_req->transaction_id; + cmd->service_instance_id = ndp_req->service_instance_id; + WMI_CHAR_ARRAY_TO_MAC_ADDR(ndp_req->peer_discovery_mac_addr.bytes, + &cmd->peer_discovery_mac_addr); + + cmd->ndp_cfg_len = ndp_req->ndp_config.ndp_cfg_len; + cmd->ndp_app_info_len = ndp_req->ndp_info.ndp_app_info_len; + cmd->ndp_channel_cfg = ndp_req->channel_cfg; + cmd->nan_pmk_len = ndp_req->pmk.pmk_len; + cmd->nan_csid = ndp_req->ncs_sk_type; + + ch_tlv = (wmi_channel *)&cmd[1]; + WMITLV_SET_HDR(ch_tlv, WMITLV_TAG_STRUC_wmi_channel, + WMITLV_GET_STRUCT_TLVLEN(wmi_channel)); + ch_tlv->mhz = ndp_req->channel; + ch_tlv->band_center_freq1 = + cds_chan_to_freq(cds_freq_to_chan(ndp_req->channel)); + tlv_ptr = (uint8_t *)&ch_tlv[1]; + + WMITLV_SET_HDR(tlv_ptr, WMITLV_TAG_ARRAY_BYTE, ndp_cfg_len); + qdf_mem_copy(&tlv_ptr[WMI_TLV_HDR_SIZE], + ndp_req->ndp_config.ndp_cfg, cmd->ndp_cfg_len); + tlv_ptr = tlv_ptr + WMI_TLV_HDR_SIZE + ndp_cfg_len; + + WMITLV_SET_HDR(tlv_ptr, WMITLV_TAG_ARRAY_BYTE, ndp_app_info_len); + qdf_mem_copy(&tlv_ptr[WMI_TLV_HDR_SIZE], + ndp_req->ndp_info.ndp_app_info, cmd->ndp_app_info_len); + tlv_ptr = tlv_ptr + WMI_TLV_HDR_SIZE + ndp_app_info_len; + + WMITLV_SET_HDR(tlv_ptr, WMITLV_TAG_ARRAY_BYTE, pmk_len); + qdf_mem_copy(&tlv_ptr[WMI_TLV_HDR_SIZE], ndp_req->pmk.pmk, + cmd->nan_pmk_len); + tlv_ptr = tlv_ptr + WMI_TLV_HDR_SIZE + pmk_len; + + WMA_LOGE(FL("vdev_id = %d, transaction_id: %d, service_instance_id: %d, ch: %d, ch_cfg: %d, csid: %d"), + cmd->vdev_id, cmd->transaction_id, cmd->service_instance_id, + ch_tlv->mhz, cmd->ndp_channel_cfg, cmd->nan_csid); + WMA_LOGE(FL("peer mac addr: mac_addr31to0: 0x%x, mac_addr47to32: 0x%x"), + cmd->peer_discovery_mac_addr.mac_addr31to0, + cmd->peer_discovery_mac_addr.mac_addr47to32); + + WMA_LOGE(FL("ndp_config len: %d"), cmd->ndp_cfg_len); + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_WMA, QDF_TRACE_LEVEL_DEBUG, + ndp_req->ndp_config.ndp_cfg, + ndp_req->ndp_config.ndp_cfg_len); + + WMA_LOGE(FL("ndp_app_info len: %d"), cmd->ndp_app_info_len); + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_WMA, QDF_TRACE_LEVEL_DEBUG, + ndp_req->ndp_info.ndp_app_info, + ndp_req->ndp_info.ndp_app_info_len); + + WMA_LOGE(FL("pmk len: %d"), cmd->nan_pmk_len); + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_WMA, QDF_TRACE_LEVEL_DEBUG, + ndp_req->pmk.pmk, cmd->nan_pmk_len); + WMA_LOGE(FL("sending WMI_NDP_INITIATOR_REQ_CMDID(0x%X)"), + WMI_NDP_INITIATOR_REQ_CMDID); + + ret = wmi_unified_cmd_send(wma_handle->wmi_handle, buf, len, + WMI_NDP_INITIATOR_REQ_CMDID); + if (ret < 0) { + WMA_LOGE(FL("WMI_NDP_INITIATOR_REQ_CMDID failed, ret: %d"), + ret); + wmi_buf_free(buf); + goto send_ndp_initiator_fail; + } + + return QDF_STATUS_SUCCESS; + +send_ndp_initiator_fail: + status = QDF_STATUS_E_FAILURE; + if (ndp_req) { + ndp_rsp.vdev_id = ndp_req->vdev_id; + ndp_rsp.transaction_id = ndp_req->transaction_id; + ndp_rsp.ndp_instance_id = ndp_req->service_instance_id; + ndp_rsp.status = NDP_DATA_INITIATOR_REQ_FAILED; + } else { + /* unblock SME queue, but do not send rsp to HDD */ + pe_msg.bodyval = true; + } + + pe_msg.type = SIR_HAL_NDP_INITIATOR_RSP; + pe_msg.bodyptr = &ndp_rsp; + return wma_handle->pe_ndp_event_handler(wma_handle->mac_context, + &pe_msg); +} + +/** + * wma_handle_ndp_responder_req() - NDP responder request handler + * @wma_handle: wma handle + * @req_params: request parameters + * + * Return: QDF_STATUS_SUCCESS on success; error number otherwise + */ +QDF_STATUS wma_handle_ndp_responder_req(tp_wma_handle wma_handle, + struct ndp_responder_req *req_params) +{ + wmi_buf_t buf; + ol_txrx_vdev_handle vdev; + uint32_t vdev_id = 0, ndp_cfg_len, ndp_app_info_len, pmk_len; + uint8_t *tlv_ptr; + int ret; + wmi_ndp_responder_req_fixed_param *cmd; + uint16_t len; + struct ndp_responder_rsp_event rsp = {0}; + cds_msg_t pe_msg = {0}; + + if (NULL == req_params) { + WMA_LOGE(FL("Invalid req_params.")); + return QDF_STATUS_E_INVAL; + } + + vdev_id = req_params->vdev_id; + WMA_LOGD(FL("vdev_id: %d, transaction_id: %d, ndp_rsp %d, ndp_instance_id: %d, ndp_app_info_len: %d"), + req_params->vdev_id, req_params->transaction_id, + req_params->ndp_rsp, + req_params->ndp_instance_id, + req_params->ndp_info.ndp_app_info_len); + vdev = wma_find_vdev_by_id(wma_handle, vdev_id); + if (!vdev) { + WMA_LOGE(FL("vdev not found for vdev id %d."), vdev_id); + goto send_ndp_responder_fail; + } + + if (!WMA_IS_VDEV_IN_NDI_MODE(wma_handle->interfaces, vdev_id)) { + WMA_LOGE(FL("vdev :$%d, not in NDI mode"), vdev_id); + goto send_ndp_responder_fail; + } + + /* + * WMI command expects 4 byte alligned len: + * round up ndp_cfg_len and ndp_app_info_len to 4 bytes + */ + ndp_cfg_len = qdf_roundup(req_params->ndp_config.ndp_cfg_len, 4); + ndp_app_info_len = qdf_roundup(req_params->ndp_info.ndp_app_info_len, 4); + pmk_len = qdf_roundup(req_params->pmk.pmk_len, 4); + /* allocated memory for fixed params as well as variable size data */ + len = sizeof(*cmd) + 3*WMI_TLV_HDR_SIZE + ndp_cfg_len + ndp_app_info_len + + pmk_len; + + buf = wmi_buf_alloc(wma_handle->wmi_handle, len); + if (!buf) { + WMA_LOGE(FL("wmi_buf_alloc failed")); + goto send_ndp_responder_fail; + } + cmd = (wmi_ndp_responder_req_fixed_param *) wmi_buf_data(buf); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_ndp_responder_req_fixed_param, + WMITLV_GET_STRUCT_TLVLEN( + wmi_ndp_responder_req_fixed_param)); + cmd->vdev_id = req_params->vdev_id; + cmd->transaction_id = req_params->transaction_id; + cmd->ndp_instance_id = req_params->ndp_instance_id; + cmd->rsp_code = req_params->ndp_rsp; + + cmd->ndp_cfg_len = req_params->ndp_config.ndp_cfg_len; + cmd->ndp_app_info_len = req_params->ndp_info.ndp_app_info_len; + cmd->nan_pmk_len = req_params->pmk.pmk_len; + cmd->nan_csid = req_params->ncs_sk_type; + + tlv_ptr = (uint8_t *)&cmd[1]; + + WMITLV_SET_HDR(tlv_ptr, WMITLV_TAG_ARRAY_BYTE, ndp_cfg_len); + qdf_mem_copy(&tlv_ptr[WMI_TLV_HDR_SIZE], + req_params->ndp_config.ndp_cfg, cmd->ndp_cfg_len); + tlv_ptr = tlv_ptr + WMI_TLV_HDR_SIZE + ndp_cfg_len; + + WMITLV_SET_HDR(tlv_ptr, WMITLV_TAG_ARRAY_BYTE, ndp_app_info_len); + qdf_mem_copy(&tlv_ptr[WMI_TLV_HDR_SIZE], + req_params->ndp_info.ndp_app_info, + req_params->ndp_info.ndp_app_info_len); + tlv_ptr = tlv_ptr + WMI_TLV_HDR_SIZE + ndp_app_info_len; + + WMITLV_SET_HDR(tlv_ptr, WMITLV_TAG_ARRAY_BYTE, pmk_len); + qdf_mem_copy(&tlv_ptr[WMI_TLV_HDR_SIZE], req_params->pmk.pmk, + cmd->nan_pmk_len); + tlv_ptr = tlv_ptr + WMI_TLV_HDR_SIZE + pmk_len; + + WMA_LOGE(FL("vdev_id = %d, transaction_id: %d, csid: %d"), + cmd->vdev_id, cmd->transaction_id, cmd->nan_csid); + + WMA_LOGD(FL("ndp_config len: %d"), + req_params->ndp_config.ndp_cfg_len); + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_WMA, QDF_TRACE_LEVEL_DEBUG, + req_params->ndp_config.ndp_cfg, + req_params->ndp_config.ndp_cfg_len); + + WMA_LOGD(FL("ndp_app_info len: %d"), + req_params->ndp_info.ndp_app_info_len); + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_WMA, QDF_TRACE_LEVEL_DEBUG, + req_params->ndp_info.ndp_app_info, + req_params->ndp_info.ndp_app_info_len); + + WMA_LOGE(FL("pmk len: %d"), cmd->nan_pmk_len); + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_WMA, QDF_TRACE_LEVEL_DEBUG, + req_params->pmk.pmk, cmd->nan_pmk_len); + + WMA_LOGE(FL("sending WMI_NDP_RESPONDER_REQ_CMDID(0x%X)"), + WMI_NDP_RESPONDER_REQ_CMDID); + ret = wmi_unified_cmd_send(wma_handle->wmi_handle, buf, len, + WMI_NDP_RESPONDER_REQ_CMDID); + if (ret < 0) { + WMA_LOGE(FL("WMI_NDP_RESPONDER_REQ_CMDID failed, ret: %d"), + ret); + wmi_buf_free(buf); + goto send_ndp_responder_fail; + } + return QDF_STATUS_SUCCESS; +send_ndp_responder_fail: + qdf_mem_zero(&rsp, sizeof(rsp)); + rsp.vdev_id = req_params->vdev_id; + rsp.transaction_id = req_params->transaction_id; + rsp.status = NDP_RSP_STATUS_ERROR; + rsp.reason = NDP_DATA_RESPONDER_REQ_FAILED; + + pe_msg.bodyptr = &rsp; + pe_msg.type = SIR_HAL_NDP_RESPONDER_RSP; + return wma_handle->pe_ndp_event_handler(wma_handle->mac_context, + &pe_msg); +} + +/** + * wma_handle_ndp_end_req() - NDP end request handler + * @wma_handle: wma handle + * @ptr: request parameters + * + * Return: QDF_STATUS_SUCCESS on success; error number otherwise + */ +QDF_STATUS wma_handle_ndp_end_req(tp_wma_handle wma_handle, void *ptr) +{ + int ret; + uint16_t len; + uint32_t ndp_end_req_len, i; + wmi_ndp_end_req *ndp_end_req_lst; + wmi_buf_t buf; + cds_msg_t pe_msg = {0}; + wmi_ndp_end_req_fixed_param *cmd; + struct ndp_end_rsp_event end_rsp = {0}; + struct ndp_end_req *req = ptr; + + if (NULL == req) { + WMA_LOGE(FL("Invalid ndp_end_req")); + goto send_ndp_end_fail; + } + + /* len of tlv following fixed param */ + ndp_end_req_len = sizeof(wmi_ndp_end_req) * req->num_ndp_instances; + /* above comes out to 4 byte alligned already, no need of padding */ + len = sizeof(*cmd) + ndp_end_req_len + WMI_TLV_HDR_SIZE; + buf = wmi_buf_alloc(wma_handle->wmi_handle, len); + if (!buf) { + WMA_LOGE(FL("Malloc failed")); + return QDF_STATUS_E_NOMEM; + } + cmd = (wmi_ndp_end_req_fixed_param *) wmi_buf_data(buf); + + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_ndp_end_req_fixed_param, + WMITLV_GET_STRUCT_TLVLEN(wmi_ndp_end_req_fixed_param)); + + cmd->transaction_id = req->transaction_id; + + /* set tlv pointer to end of fixed param */ + WMITLV_SET_HDR((uint8_t *)&cmd[1], WMITLV_TAG_ARRAY_STRUC, + ndp_end_req_len); + + ndp_end_req_lst = (wmi_ndp_end_req *)((uint8_t *)&cmd[1] + + WMI_TLV_HDR_SIZE); + for (i = 0; i < req->num_ndp_instances; i++) { + WMITLV_SET_HDR(&ndp_end_req_lst[i], + WMITLV_TAG_ARRAY_FIXED_STRUC, + (sizeof(*ndp_end_req_lst) - WMI_TLV_HDR_SIZE)); + + ndp_end_req_lst[i].ndp_instance_id = req->ndp_ids[i]; + } + + WMA_LOGD(FL("Sending WMI_NDP_END_REQ_CMDID to FW")); + ret = wmi_unified_cmd_send(wma_handle->wmi_handle, buf, len, + WMI_NDP_END_REQ_CMDID); + if (ret < 0) { + WMA_LOGE(FL("WMI_NDP_END_REQ_CMDID failed, ret: %d"), ret); + wmi_buf_free(buf); + goto send_ndp_end_fail; + } + return QDF_STATUS_SUCCESS; + +send_ndp_end_fail: + pe_msg.type = SIR_HAL_NDP_END_RSP; + if (req) { + end_rsp.status = NDP_RSP_STATUS_ERROR; + end_rsp.reason = NDP_END_FAILED; + end_rsp.transaction_id = req->transaction_id; + pe_msg.bodyptr = &end_rsp; + } else { + pe_msg.bodyval = true; + } + + wma_handle->pe_ndp_event_handler(wma_handle->mac_context, &pe_msg); + return QDF_STATUS_E_FAILURE; +} + +/** + * wma_ndp_indication_event_handler() - NDP indication event handler + * @handle: wma handle + * @event_info: event handler data + * @len: length of event_info + * + * Handler for WMI_NDP_INDICATION_EVENTID + * Return: 0 on success, negative errno on failure + */ +static int wma_ndp_indication_event_handler(void *handle, uint8_t *event_info, + uint32_t len) +{ + cds_msg_t pe_msg = {0}; + WMI_NDP_INDICATION_EVENTID_param_tlvs *event; + wmi_ndp_indication_event_fixed_param *fixed_params; + struct ndp_indication_event ind_event = {0}; + tp_wma_handle wma_handle = handle; + + event = (WMI_NDP_INDICATION_EVENTID_param_tlvs *)event_info; + fixed_params = + (wmi_ndp_indication_event_fixed_param *)event->fixed_param; + + ind_event.vdev_id = fixed_params->vdev_id; + ind_event.service_instance_id = fixed_params->service_instance_id; + ind_event.ndp_instance_id = fixed_params->ndp_instance_id; + ind_event.role = fixed_params->self_ndp_role; + ind_event.policy = fixed_params->accept_policy; + + WMI_MAC_ADDR_TO_CHAR_ARRAY(&fixed_params->peer_ndi_mac_addr, + ind_event.peer_mac_addr.bytes); + WMI_MAC_ADDR_TO_CHAR_ARRAY(&fixed_params->peer_discovery_mac_addr, + ind_event.peer_discovery_mac_addr.bytes); + + WMA_LOGD(FL("WMI_NDP_INDICATION_EVENTID(0x%X) received. vdev %d, \n" + "service_instance %d, ndp_instance %d, role %d, policy %d, \n" + "csid: %d, scid_len: %d, peer_mac_addr: %pM, peer_disc_mac_addr: %pM"), + WMI_NDP_INDICATION_EVENTID, fixed_params->vdev_id, + fixed_params->service_instance_id, + fixed_params->ndp_instance_id, fixed_params->self_ndp_role, + fixed_params->accept_policy, + fixed_params->nan_csid, fixed_params->nan_scid_len, + ind_event.peer_mac_addr.bytes, + ind_event.peer_discovery_mac_addr.bytes); + + WMA_LOGD(FL("ndp_cfg - %d bytes"), fixed_params->ndp_cfg_len); + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_WMA, QDF_TRACE_LEVEL_DEBUG, + &event->ndp_cfg, fixed_params->ndp_cfg_len); + + WMA_LOGD(FL("ndp_app_info - %d bytes"), fixed_params->ndp_app_info_len); + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_WMA, QDF_TRACE_LEVEL_DEBUG, + &event->ndp_app_info, fixed_params->ndp_app_info_len); + + ind_event.ndp_config.ndp_cfg_len = fixed_params->ndp_cfg_len; + ind_event.ndp_info.ndp_app_info_len = fixed_params->ndp_app_info_len; + ind_event.ncs_sk_type = fixed_params->nan_csid; + ind_event.scid.scid_len = fixed_params->nan_scid_len; + + if (ind_event.ndp_config.ndp_cfg_len) { + ind_event.ndp_config.ndp_cfg = + qdf_mem_malloc(fixed_params->ndp_cfg_len); + if (NULL == ind_event.ndp_config.ndp_cfg) { + WMA_LOGE(FL("malloc failed")); + return QDF_STATUS_E_NOMEM; + } + qdf_mem_copy(ind_event.ndp_config.ndp_cfg, event->ndp_cfg, + ind_event.ndp_config.ndp_cfg_len); + } + + if (ind_event.ndp_info.ndp_app_info_len) { + ind_event.ndp_info.ndp_app_info = + qdf_mem_malloc(ind_event.ndp_info.ndp_app_info_len); + if (NULL == ind_event.ndp_info.ndp_app_info) { + WMA_LOGE(FL("malloc failed")); + qdf_mem_free(ind_event.ndp_config.ndp_cfg); + return QDF_STATUS_E_NOMEM; + } + qdf_mem_copy(ind_event.ndp_info.ndp_app_info, + event->ndp_app_info, + ind_event.ndp_info.ndp_app_info_len); + } + + if (ind_event.scid.scid_len) { + ind_event.scid.scid = + qdf_mem_malloc(ind_event.scid.scid_len); + if (NULL == ind_event.scid.scid) { + WMA_LOGE(FL("malloc failed")); + qdf_mem_free(ind_event.ndp_config.ndp_cfg); + qdf_mem_free(ind_event.ndp_info.ndp_app_info); + return QDF_STATUS_E_NOMEM; + } + qdf_mem_copy(ind_event.scid.scid, + event->ndp_scid, ind_event.scid.scid_len); + WMA_LOGD(FL("scid hex dump:")); + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_WMA, QDF_TRACE_LEVEL_DEBUG, + ind_event.scid.scid, ind_event.scid.scid_len); + } + + pe_msg.type = SIR_HAL_NDP_INDICATION; + pe_msg.bodyptr = &ind_event; + return wma_handle->pe_ndp_event_handler(wma_handle->mac_context, + &pe_msg); +} + +/** + * wma_ndp_responder_rsp_event_handler() - NDP responder response event handler + * @handle: wma handle + * @event_info: event handler data + * @len: length of event_info + * + * Handler for WMI_NDP_RESPONDER_RSP_EVENTID + * Return: 0 on success, negative errno on failure + */ +static int wma_ndp_responder_rsp_event_handler(void *handle, + uint8_t *event_info, uint32_t len) +{ + cds_msg_t pe_msg = {0}; + tp_wma_handle wma_handle = handle; + WMI_NDP_RESPONDER_RSP_EVENTID_param_tlvs *event; + wmi_ndp_responder_rsp_event_fixed_param *fixed_params; + struct ndp_responder_rsp_event rsp = {0}; + + event = (WMI_NDP_RESPONDER_RSP_EVENTID_param_tlvs *)event_info; + fixed_params = event->fixed_param; + + rsp.vdev_id = fixed_params->vdev_id; + rsp.transaction_id = fixed_params->transaction_id; + rsp.reason = fixed_params->reason_code; + rsp.status = fixed_params->rsp_status; + rsp.create_peer = fixed_params->create_peer; + WMI_MAC_ADDR_TO_CHAR_ARRAY(&fixed_params->peer_ndi_mac_addr, + rsp.peer_mac_addr.bytes); + + WMA_LOGE(FL("WMI_NDP_RESPONDER_RSP_EVENTID(0x%X) received. vdev_id: %d, peer_mac_addr: %pM,transaction_id: %d, status_code %d, reason_code: %d, create_peer: %d"), + WMI_NDP_RESPONDER_RSP_EVENTID, rsp.vdev_id, + rsp.peer_mac_addr.bytes, rsp.transaction_id, + rsp.status, rsp.reason, rsp.create_peer); + + pe_msg.bodyptr = &rsp; + pe_msg.type = SIR_HAL_NDP_RESPONDER_RSP; + return wma_handle->pe_ndp_event_handler(wma_handle->mac_context, + &pe_msg); +} + +/** + * wma_ndp_confirm_event_handler() - NDP confirm event handler + * @handle: wma handle + * @event_info: event handler data + * @len: length of event_info + * + * Handler for WMI_NDP_CONFIRM_EVENTID + * Return: 0 on success, negative errno on failure + */ +static int wma_ndp_confirm_event_handler(void *handle, uint8_t *event_info, + uint32_t len) +{ + struct ndp_confirm_event ndp_confirm = {0}; + cds_msg_t msg = {0}; + WMI_NDP_CONFIRM_EVENTID_param_tlvs *event; + wmi_ndp_confirm_event_fixed_param *fixed_params; + tp_wma_handle wma_handle = handle; + + event = (WMI_NDP_CONFIRM_EVENTID_param_tlvs *) event_info; + fixed_params = (wmi_ndp_confirm_event_fixed_param *)event->fixed_param; + WMA_LOGE(FL("WMI_NDP_CONFIRM_EVENTID(0x%X) recieved. vdev %d, ndp_instance %d, rsp_code %d, reason_code: %d, num_active_ndps_on_peer: %d"), + WMI_NDP_CONFIRM_EVENTID, fixed_params->vdev_id, + fixed_params->ndp_instance_id, fixed_params->rsp_code, + fixed_params->reason_code, + fixed_params->num_active_ndps_on_peer); + + WMA_LOGE(FL("ndp_cfg - %d bytes"), fixed_params->ndp_cfg_len); + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_WMA, QDF_TRACE_LEVEL_DEBUG, + &event->ndp_cfg, fixed_params->ndp_cfg_len); + + WMA_LOGE(FL("ndp_app_info - %d bytes"), fixed_params->ndp_app_info_len); + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_WMA, QDF_TRACE_LEVEL_DEBUG, + &event->ndp_app_info, fixed_params->ndp_app_info_len); + + ndp_confirm.vdev_id = fixed_params->vdev_id; + ndp_confirm.ndp_instance_id = fixed_params->ndp_instance_id; + ndp_confirm.rsp_code = fixed_params->rsp_code; + ndp_confirm.reason_code = fixed_params->reason_code; + ndp_confirm.num_active_ndps_on_peer = + fixed_params->num_active_ndps_on_peer; + + WMI_MAC_ADDR_TO_CHAR_ARRAY(&fixed_params->peer_ndi_mac_addr, + ndp_confirm.peer_ndi_mac_addr.bytes); + + ndp_confirm.ndp_info.ndp_app_info_len = fixed_params->ndp_app_info_len; + + if (ndp_confirm.ndp_info.ndp_app_info_len) { + ndp_confirm.ndp_info.ndp_app_info = + qdf_mem_malloc(fixed_params->ndp_app_info_len); + if (NULL == ndp_confirm.ndp_info.ndp_app_info) { + WMA_LOGE(FL("malloc failed")); + return QDF_STATUS_E_NOMEM; + } + qdf_mem_copy(&ndp_confirm.ndp_info.ndp_app_info, + event->ndp_app_info, + ndp_confirm.ndp_info.ndp_app_info_len); + } + msg.type = SIR_HAL_NDP_CONFIRM; + msg.bodyptr = &ndp_confirm; + return wma_handle->pe_ndp_event_handler(wma_handle->mac_context, &msg); +} + +/** + * wma_ndp_end_response_event_handler() - NDP end response event handler + * @handle: wma handle + * @event_info: event handler data + * @len: length of event_info + * + * Handler for WMI_NDP_END_RSP_EVENTID + * Return: 0 on success, negative errno on failure + */ +static int wma_ndp_end_response_event_handler(void *handle, + uint8_t *event_info, uint32_t len) +{ + int ret = 0; + QDF_STATUS status; + cds_msg_t pe_msg = {0}; + struct ndp_end_rsp_event *end_rsp; + WMI_NDP_END_RSP_EVENTID_param_tlvs *event; + wmi_ndp_end_rsp_event_fixed_param *fixed_params = NULL; + tp_wma_handle wma_handle = handle; + + event = (WMI_NDP_END_RSP_EVENTID_param_tlvs *) event_info; + fixed_params = (wmi_ndp_end_rsp_event_fixed_param *)event->fixed_param; + WMA_LOGD(FL("WMI_NDP_END_RSP_EVENTID(0x%X) recieved. transaction_id: %d, rsp_status: %d, reason_code: %d"), + WMI_NDP_END_RSP_EVENTID, fixed_params->transaction_id, + fixed_params->rsp_status, fixed_params->reason_code); + + end_rsp = qdf_mem_malloc(sizeof(*end_rsp)); + if (NULL == end_rsp) { + WMA_LOGE("malloc failed"); + pe_msg.bodyval = true; + ret = -ENOMEM; + goto send_ndp_end_rsp; + } + pe_msg.bodyptr = end_rsp; + qdf_mem_zero(end_rsp, sizeof(*end_rsp)); + + end_rsp->transaction_id = fixed_params->transaction_id; + end_rsp->reason = fixed_params->reason_code; + end_rsp->status = fixed_params->rsp_status; + +send_ndp_end_rsp: + pe_msg.type = SIR_HAL_NDP_END_RSP; + status = wma_handle->pe_ndp_event_handler(wma_handle->mac_context, + &pe_msg); + if (!QDF_IS_STATUS_SUCCESS(status)) + ret = -EINVAL; + + qdf_mem_free(end_rsp); + return ret; +} + +/** + * wma_ndp_end_indication_event_handler() - NDP end indication event handler + * @handle: wma handle + * @event_info: event handler data + * @len: length of event_info + * + * Handler for WMI_NDP_END_INDICATION_EVENTID + * Return: 0 on success, negative errno on failure + */ +static int wma_ndp_end_indication_event_handler(void *handle, + uint8_t *event_info, uint32_t len) +{ + tp_wma_handle wma_handle = handle; + WMI_NDP_END_INDICATION_EVENTID_param_tlvs *event; + wmi_ndp_end_indication *ind; + cds_msg_t pe_msg; + struct ndp_end_indication_event *ndp_event_buf; + int i, ret, buf_size; + struct qdf_mac_addr peer_addr; + + event = (WMI_NDP_END_INDICATION_EVENTID_param_tlvs *) event_info; + + if (event->num_ndp_end_indication_list == 0) { + WMA_LOGE( + FL("Error: Event ignored, 0 ndp instances")); + return -EINVAL; + } + + WMA_LOGD(FL("number of ndp instances = %d"), + event->num_ndp_end_indication_list); + + buf_size = sizeof(*ndp_event_buf) + event->num_ndp_end_indication_list * + sizeof(ndp_event_buf->ndp_map[0]); + ndp_event_buf = qdf_mem_malloc(buf_size); + if (!ndp_event_buf) { + WMA_LOGP(FL("Failed to allocate memory")); + return -ENOMEM; + } + qdf_mem_zero(ndp_event_buf, buf_size); + ndp_event_buf->num_ndp_ids = event->num_ndp_end_indication_list; + + ind = event->ndp_end_indication_list; + for (i = 0; i < ndp_event_buf->num_ndp_ids; i++) { + WMI_MAC_ADDR_TO_CHAR_ARRAY( + &ind[i].peer_ndi_mac_addr, + peer_addr.bytes); + WMA_LOGD( + FL("ind[%d]: type %d, reason_code %d, instance_id %d num_active %d MAC: " MAC_ADDRESS_STR), + i, + ind[i].type, + ind[i].reason_code, + ind[i].ndp_instance_id, + ind[i].num_active_ndps_on_peer, + MAC_ADDR_ARRAY(peer_addr.bytes)); + + /* Add each instance entry to the list */ + ndp_event_buf->ndp_map[i].ndp_instance_id = + ind[i].ndp_instance_id; + ndp_event_buf->ndp_map[i].vdev_id = ind[i].vdev_id; + WMI_MAC_ADDR_TO_CHAR_ARRAY(&ind[i].peer_ndi_mac_addr, + ndp_event_buf->ndp_map[i].peer_ndi_mac_addr.bytes); + ndp_event_buf->ndp_map[i].num_active_ndp_sessions = + ind[i].num_active_ndps_on_peer; + ndp_event_buf->ndp_map[i].type = ind[i].type; + ndp_event_buf->ndp_map[i].reason_code = + ind[i].reason_code; + } + + pe_msg.type = SIR_HAL_NDP_END_IND; + pe_msg.bodyptr = ndp_event_buf; + pe_msg.bodyval = 0; + ret = wma_handle->pe_ndp_event_handler(wma_handle->mac_context, + &pe_msg); + qdf_mem_free(ndp_event_buf); + return ret; +} + +/** + * wma_ndp_initiator_rsp_event_handler() -NDP initiator rsp event handler + * @handle: wma handle + * @event_info: event handler data + * @len: length of event_info + * + * Handler for WMI_NDP_INITIATOR_RSP_EVENTID + * Return: 0 on success, negative errno on failure + */ +static int wma_ndp_initiator_rsp_event_handler(void *handle, + uint8_t *event_info, uint32_t len) +{ + cds_msg_t pe_msg = {0}; + WMI_NDP_INITIATOR_RSP_EVENTID_param_tlvs *event; + wmi_ndp_initiator_rsp_event_fixed_param *fixed_params; + struct ndp_initiator_rsp ndp_rsp = {0}; + tp_wma_handle wma_handle = handle; + + event = (WMI_NDP_INITIATOR_RSP_EVENTID_param_tlvs *)event_info; + fixed_params = event->fixed_param; + + ndp_rsp.vdev_id = fixed_params->vdev_id; + ndp_rsp.transaction_id = fixed_params->transaction_id; + ndp_rsp.ndp_instance_id = fixed_params->ndp_instance_id; + ndp_rsp.status = fixed_params->rsp_status; + ndp_rsp.reason = fixed_params->reason_code; + + pe_msg.type = SIR_HAL_NDP_INITIATOR_RSP; + pe_msg.bodyptr = &ndp_rsp; + return wma_handle->pe_ndp_event_handler(wma_handle->mac_context, + &pe_msg); +} + +/** + * wma_ndp_register_all_event_handlers() - Register all NDP event handlers + * @wma_handle: WMA context + * + * Register the handlers for NAN datapath events from firmware. + * + * Return: None + */ +void wma_ndp_register_all_event_handlers(tp_wma_handle wma_handle) +{ + WMA_LOGD(FL("Register WMI_NDP_INITIATOR_RSP_EVENTID")); + wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_NDP_INITIATOR_RSP_EVENTID, + wma_ndp_initiator_rsp_event_handler, + WMA_RX_SERIALIZER_CTX); + + WMA_LOGD(FL("Register WMI_NDP_RESPONDER_RSP_EVENTID")); + wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_NDP_RESPONDER_RSP_EVENTID, + wma_ndp_responder_rsp_event_handler, + WMA_RX_SERIALIZER_CTX); + + WMA_LOGD(FL("Register WMI_NDP_END_RSP_EVENTID")); + wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_NDP_END_RSP_EVENTID, + wma_ndp_end_response_event_handler, + WMA_RX_SERIALIZER_CTX); + + WMA_LOGD(FL("Register WMI_NDP_INDICATION_EVENTID")); + wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_NDP_INDICATION_EVENTID, + wma_ndp_indication_event_handler, + WMA_RX_SERIALIZER_CTX); + + WMA_LOGD(FL("Register WMI_NDP_CONFIRM_EVENTID")); + wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_NDP_CONFIRM_EVENTID, + wma_ndp_confirm_event_handler, + WMA_RX_SERIALIZER_CTX); + + WMA_LOGD(FL("Register WMI_NDP_END_INDICATION_EVENTID")); + wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_NDP_END_INDICATION_EVENTID, + wma_ndp_end_indication_event_handler, + WMA_RX_SERIALIZER_CTX); +} + +/** + * wma_ndp_unregister_all_event_handlers() - Unregister all NDP event handlers + * @wma_handle: WMA context + * + * Register the handlers for NAN datapath events from firmware. + * + * Return: None + */ +void wma_ndp_unregister_all_event_handlers(tp_wma_handle wma_handle) +{ + WMA_LOGD(FL("Unregister WMI_NDP_INITIATOR_RSP_EVENTID")); + wmi_unified_unregister_event_handler(wma_handle->wmi_handle, + WMI_NDP_INITIATOR_RSP_EVENTID); + + WMA_LOGD(FL("Unregister WMI_NDP_RESPONDER_RSP_EVENTID")); + wmi_unified_unregister_event_handler(wma_handle->wmi_handle, + WMI_NDP_RESPONDER_RSP_EVENTID); + + WMA_LOGD(FL("Unregister WMI_NDP_END_RSP_EVENTID")); + wmi_unified_unregister_event_handler(wma_handle->wmi_handle, + WMI_NDP_END_RSP_EVENTID); + + WMA_LOGD(FL("Unregister WMI_NDP_INDICATION_EVENTID")); + wmi_unified_unregister_event_handler(wma_handle->wmi_handle, + WMI_NDP_INDICATION_EVENTID); + + WMA_LOGD(FL("Unregister WMI_NDP_CONFIRM_EVENTID")); + wmi_unified_unregister_event_handler(wma_handle->wmi_handle, + WMI_NDP_CONFIRM_EVENTID); + + WMA_LOGD(FL("Unregister WMI_NDP_END_INDICATION_EVENTID")); + wmi_unified_unregister_event_handler(wma_handle->wmi_handle, + WMI_NDP_END_INDICATION_EVENTID); +} + +/** + * wma_ndp_add_wow_wakeup_event() - Add Wake on Wireless event for NDP + * @wma_handle: WMA context + * @vdev_id: vdev id + * + * Enables the firmware to wake up the host on NAN data path event. + * All NDP events such as NDP_INDICATION, NDP_CONFIRM, etc. use the + * same event. They can be distinguished using their TLV tags. + * + * Return: none + */ +void wma_ndp_add_wow_wakeup_event(tp_wma_handle wma_handle, + uint8_t vdev_id) +{ + uint32_t event_bitmap[WMI_WOW_MAX_EVENT_BM_LEN] = {0}; + + wma_set_wow_event_bitmap(WOW_NAN_DATA_EVENT, WMI_WOW_MAX_EVENT_BM_LEN, + event_bitmap); + WMA_LOGI("NDI specific default wake up event 0x%x vdev id %d", + event_bitmap[0], vdev_id); + wma_add_wow_wakeup_event(wma_handle, vdev_id, event_bitmap, true); +} + +/** + * wma_ndp_get_eventid_from_tlvtag() - map tlv tag to event id + * @tag: WMI TLV tag + * + * map the tag to known NDP event fixed_param tags and return the + * corresponding NDP event id. + * + * Return: 0 if TLV tag is invalid + * else return corresponding WMI event id + */ +uint32_t wma_ndp_get_eventid_from_tlvtag(uint32_t tag) +{ + uint32_t event_id; + + switch (tag) { + case WMITLV_TAG_STRUC_wmi_ndp_initiator_rsp_event_fixed_param: + event_id = WMI_NDP_INITIATOR_RSP_EVENTID; + break; + + case WMITLV_TAG_STRUC_wmi_ndp_responder_rsp_event_fixed_param: + event_id = WMI_NDP_RESPONDER_RSP_EVENTID; + break; + + case WMITLV_TAG_STRUC_wmi_ndp_end_rsp_event_fixed_param: + event_id = WMI_NDP_END_RSP_EVENTID; + break; + + case WMITLV_TAG_STRUC_wmi_ndp_indication_event_fixed_param: + event_id = WMI_NDP_INDICATION_EVENTID; + break; + + case WMITLV_TAG_STRUC_wmi_ndp_confirm_event_fixed_param: + event_id = WMI_NDP_CONFIRM_EVENTID; + break; + + case WMITLV_TAG_STRUC_wmi_ndp_end_indication_event_fixed_param: + event_id = WMI_NDP_END_INDICATION_EVENTID; + break; + + default: + event_id = 0; + WMA_LOGE(FL("Unknown tag: %d"), tag); + break; + } + + WMA_LOGI(FL("For tag %d WMI event 0x%x"), tag, event_id); + return event_id; +} + +/** + * wma_ndp_wow_event_callback() - NAN data path wow event callback + * @handle: WMA handle + * @event: event buffer + * @len: length of @event buffer + * @event_id: event id for ndp wow event + * + * The wow event WOW_REASON_NAN_DATA is followed by the payload of the event + * which generated the wow event. + * Payload is 4 bytes of length followed by event buffer. First 4 bytes + * of event buffer is common tlv header, which is a combination + * of tag (higher 2 bytes) and length (lower 2 bytes). The tag is used to + * identify the event which triggered wow event. + * + * Return: none + */ +void wma_ndp_wow_event_callback(void *handle, void *event, uint32_t len, + uint32_t event_id) +{ + WMA_LOGD(FL("ndp_wow_event dump")); + qdf_trace_hex_dump(QDF_MODULE_ID_WMA, QDF_TRACE_LEVEL_DEBUG, + event, len); + switch (event_id) { + case WMI_NDP_INITIATOR_RSP_EVENTID: + wma_ndp_initiator_rsp_event_handler(handle, event, len); + break; + + case WMI_NDP_RESPONDER_RSP_EVENTID: + wma_ndp_responder_rsp_event_handler(handle, event, len); + break; + + case WMI_NDP_END_RSP_EVENTID: + wma_ndp_end_response_event_handler(handle, event, len); + break; + + case WMI_NDP_INDICATION_EVENTID: + wma_ndp_indication_event_handler(handle, event, len); + break; + + case WMI_NDP_CONFIRM_EVENTID: + wma_ndp_confirm_event_handler(handle, event, len); + break; + + case WMI_NDP_END_INDICATION_EVENTID: + wma_ndp_end_indication_event_handler(handle, event, len); + break; + + default: + WMA_LOGE(FL("Unknown event: %d"), event_id); + break; + } +} + +/** + * wma_add_bss_ndi_mode() - Process BSS creation request while adding NaN + * Data interface + * @wma: wma handle + * @add_bss: Parameters for ADD_BSS command + * + * Sends VDEV_START command to firmware + * Return: None + */ +void wma_add_bss_ndi_mode(tp_wma_handle wma, tpAddBssParams add_bss) +{ + ol_txrx_pdev_handle pdev; + struct wma_vdev_start_req req; + ol_txrx_peer_handle peer = NULL; + struct wma_target_req *msg; + uint8_t vdev_id, peer_id; + QDF_STATUS status; + struct vdev_set_params param = {0}; + + WMA_LOGI("%s: enter", __func__); + if (NULL == wma_find_vdev_by_addr(wma, add_bss->bssId, &vdev_id)) { + WMA_LOGE("%s: Failed to find vdev", __func__); + goto send_fail_resp; + } + pdev = cds_get_context(QDF_MODULE_ID_TXRX); + + if (!pdev) { + WMA_LOGE("%s: Failed to get pdev", __func__); + goto send_fail_resp; + } + + wma_set_bss_rate_flags(&wma->interfaces[vdev_id], add_bss); + + peer = ol_txrx_find_peer_by_addr(pdev, add_bss->selfMacAddr, &peer_id); + if (!peer) { + WMA_LOGE("%s Failed to find peer %pM", __func__, + add_bss->selfMacAddr); + goto send_fail_resp; + } + + msg = wma_fill_vdev_req(wma, vdev_id, WMA_ADD_BSS_REQ, + WMA_TARGET_REQ_TYPE_VDEV_START, add_bss, + WMA_VDEV_START_REQUEST_TIMEOUT); + if (!msg) { + WMA_LOGE("%s Failed to allocate vdev request vdev_id %d", + __func__, vdev_id); + goto send_fail_resp; + } + + add_bss->staContext.staIdx = ol_txrx_local_peer_id(peer); + + /* + * beacon_intval, dtim_period, hidden_ssid, is_dfs, ssid + * will be ignored for NDI device. + */ + qdf_mem_zero(&req, sizeof(req)); + req.vdev_id = vdev_id; + req.chan = add_bss->currentOperChannel; + req.ch_center_freq_seg0 = add_bss->ch_center_freq_seg0; + req.ch_center_freq_seg1 = add_bss->ch_center_freq_seg1; + req.vht_capable = add_bss->vhtCapable; + req.max_txpow = add_bss->maxTxPower; + req.oper_mode = add_bss->operMode; + + status = wma_vdev_start(wma, &req, false); + if (status != QDF_STATUS_SUCCESS) { + wma_remove_vdev_req(wma, vdev_id, + WMA_TARGET_REQ_TYPE_VDEV_START); + goto send_fail_resp; + } + WMA_LOGI("%s: vdev start request for NDI sent to target", __func__); + + /* Initialize protection mode to no protection */ + param.if_id = vdev_id; + param.param_id = WMI_VDEV_PARAM_PROTECTION_MODE; + param.param_value = WMI_VDEV_PARAM_PROTECTION_MODE; + if (wmi_unified_vdev_set_param_send(wma->wmi_handle, ¶m)) + WMA_LOGE("Failed to initialize protection mode"); + + + return; +send_fail_resp: + add_bss->status = QDF_STATUS_E_FAILURE; + wma_send_msg(wma, WMA_ADD_BSS_RSP, (void *)add_bss, 0); +} + +/** + * wma_delete_all_nan_remote_peers() - Delete all nan peers + * @wma: wma handle + * @vdev_id: vdev id + * + * Return: None + */ +void wma_delete_all_nan_remote_peers(tp_wma_handle wma, uint32_t vdev_id) +{ + ol_txrx_vdev_handle vdev; + ol_txrx_peer_handle peer, temp; + + if (vdev_id > wma->max_bssid) { + WMA_LOGE("%s: invalid vdev_id = %d", __func__, vdev_id); + return; + } + + vdev = wma->interfaces[vdev_id].handle; + if (!vdev) { + WMA_LOGE("%s: vdev is NULL for vdev_id = %d", + __func__, vdev_id); + return; + } + + /* remove all remote peers of ndi */ + qdf_spin_lock_bh(&vdev->pdev->peer_ref_mutex); + + temp = NULL; + TAILQ_FOREACH_REVERSE(peer, &vdev->peer_list, + peer_list_t, peer_list_elem) { + if (temp) { + qdf_spin_unlock_bh(&vdev->pdev->peer_ref_mutex); + if (qdf_atomic_read( + &temp->delete_in_progress) == 0) + wma_remove_peer(wma, temp->mac_addr.raw, + vdev_id, temp, false); + qdf_spin_lock_bh(&vdev->pdev->peer_ref_mutex); + } + /* self peer is deleted last */ + if (peer == TAILQ_FIRST(&vdev->peer_list)) { + WMA_LOGE("%s: self peer removed", __func__); + break; + } else + temp = peer; + } + qdf_spin_unlock_bh(&vdev->pdev->peer_ref_mutex); + + /* remove ndi self peer last */ + peer = TAILQ_FIRST(&vdev->peer_list); + wma_remove_peer(wma, peer->mac_addr.raw, vdev_id, peer, + false); +} + +/** + * wma_register_ndp_cb() - Register NDP callbacks + * @pe_ndp_event_handler: PE NDP callback routine pointer + * + * Register the PE callback NDP routines with WMA for + * handling NDP events + * + * Return: Success or Failure Status + */ +QDF_STATUS wma_register_ndp_cb(QDF_STATUS (*pe_ndp_event_handler) + (tpAniSirGlobal mac_ctx, cds_msg_t *msg)) +{ + + tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA); + + if (!wma) { + WMA_LOGE("%s: Failed to get WMA context", __func__); + return QDF_STATUS_E_FAILURE; + } + wma->pe_ndp_event_handler = pe_ndp_event_handler; + WMA_LOGD("Registered NDP callbacks with WMA successfully"); + return QDF_STATUS_SUCCESS; +} + +/** + * wma_add_sta_ndi_mode() - Process ADD_STA for NaN Data path + * @wma: wma handle + * @add_sta: Parameters of ADD_STA command + * + * Sends CREATE_PEER command to firmware + * Return: void + */ +void wma_add_sta_ndi_mode(tp_wma_handle wma, tpAddStaParams add_sta) +{ + enum ol_txrx_peer_state state = OL_TXRX_PEER_STATE_CONN; + ol_txrx_pdev_handle pdev; + ol_txrx_vdev_handle vdev; + ol_txrx_peer_handle peer; + u_int8_t peer_id; + QDF_STATUS status; + struct wma_txrx_node *iface; + + pdev = cds_get_context(QDF_MODULE_ID_TXRX); + + if (NULL == pdev) { + WMA_LOGE(FL("Failed to find pdev")); + add_sta->status = QDF_STATUS_E_FAILURE; + goto send_rsp; + } + + vdev = wma_find_vdev_by_id(wma, add_sta->smesessionId); + if (!vdev) { + WMA_LOGE(FL("Failed to find vdev")); + add_sta->status = QDF_STATUS_E_FAILURE; + goto send_rsp; + } + + iface = &wma->interfaces[vdev->vdev_id]; + WMA_LOGD(FL("vdev: %d, peer_mac_addr: "MAC_ADDRESS_STR), + add_sta->smesessionId, MAC_ADDR_ARRAY(add_sta->staMac)); + + peer = ol_txrx_find_peer_by_addr_and_vdev(pdev, vdev, add_sta->staMac, + &peer_id); + if (peer) { + WMA_LOGE(FL("NDI peer already exists, peer_addr %pM"), + add_sta->staMac); + add_sta->status = QDF_STATUS_E_EXISTS; + goto send_rsp; + } + + /* + * The code above only checks the peer existence on its own vdev. + * Need to check whether the peer exists on other vDevs because firmware + * can't create the peer if the peer with same MAC address already + * exists on the pDev. As this peer belongs to other vDevs, just return + * here. + */ + peer = ol_txrx_find_peer_by_addr(pdev, add_sta->staMac, &peer_id); + if (peer) { + WMA_LOGE(FL("vdev:%d, peer exists on other vdev with peer_addr %pM and peer_id %d"), + vdev->vdev_id, add_sta->staMac, peer_id); + add_sta->status = QDF_STATUS_E_EXISTS; + goto send_rsp; + } + + status = wma_create_peer(wma, pdev, vdev, add_sta->staMac, + WMI_PEER_TYPE_NAN_DATA, add_sta->smesessionId, + false); + if (status != QDF_STATUS_SUCCESS) { + WMA_LOGE(FL("Failed to create peer for %pM"), add_sta->staMac); + add_sta->status = status; + goto send_rsp; + } + + peer = ol_txrx_find_peer_by_addr_and_vdev(pdev, vdev, add_sta->staMac, + &peer_id); + if (!peer) { + WMA_LOGE(FL("Failed to find peer handle using peer mac %pM"), + add_sta->staMac); + add_sta->status = QDF_STATUS_E_FAILURE; + wma_remove_peer(wma, add_sta->staMac, add_sta->smesessionId, + peer, false); + goto send_rsp; + } + + WMA_LOGD(FL("Moving peer %pM to state %d"), add_sta->staMac, state); + ol_txrx_peer_state_update(pdev, add_sta->staMac, state); + + add_sta->staIdx = ol_txrx_local_peer_id(peer); + add_sta->nss = iface->nss; + add_sta->status = QDF_STATUS_SUCCESS; +send_rsp: + WMA_LOGD(FL("Sending add sta rsp to umac (mac:%pM, status:%d)"), + add_sta->staMac, add_sta->status); + wma_send_msg(wma, WMA_ADD_STA_RSP, (void *)add_sta, 0); +} + +/** + * wma_delete_sta_req_ndi_mode() - Process DEL_STA request for NDI data peer + * @wma: WMA context + * @del_sta: DEL_STA parameters from LIM + * + * Removes wma/txrx peer entry for the NDI STA + * + * Return: None + */ +void wma_delete_sta_req_ndi_mode(tp_wma_handle wma, + tpDeleteStaParams del_sta) +{ + ol_txrx_pdev_handle pdev; + struct ol_txrx_peer_t *peer; + + pdev = cds_get_context(QDF_MODULE_ID_TXRX); + + if (!pdev) { + WMA_LOGE(FL("Failed to get pdev")); + del_sta->status = QDF_STATUS_E_FAILURE; + goto send_del_rsp; + } + + peer = ol_txrx_peer_find_by_local_id(pdev, del_sta->staIdx); + if (!peer) { + WMA_LOGE(FL("Failed to get peer handle using peer id %d"), + del_sta->staIdx); + del_sta->status = QDF_STATUS_E_FAILURE; + goto send_del_rsp; + } + + wma_remove_peer(wma, peer->mac_addr.raw, del_sta->smesessionId, peer, + false); + del_sta->status = QDF_STATUS_SUCCESS; + +send_del_rsp: + if (del_sta->respReqd) { + WMA_LOGD(FL("Sending del rsp to umac (status: %d)"), + del_sta->status); + wma_send_msg(wma, WMA_DELETE_STA_RSP, del_sta, 0); + } +} diff --git a/drivers/staging/qcacld-3.0/core/wma/src/wma_nan_datapath.h b/drivers/staging/qcacld-3.0/core/wma/src/wma_nan_datapath.h new file mode 100644 index 0000000000000000000000000000000000000000..6f9013853bbf6d8d201f667083a6da9ca2cdf83c --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/wma/src/wma_nan_datapath.h @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * 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. + */ + +/** + * DOC: wma_nan_datapath.h + * + * WMA NAN Data path API specification + */ + +#ifndef __WMA_NAN_DATAPATH_H +#define __WMA_NAN_DATAPATH_H + +#include "wma.h" +#include "sir_api.h" +#include "sme_nan_datapath.h" + +#ifdef WLAN_FEATURE_NAN_DATAPATH +#define WMA_IS_VDEV_IN_NDI_MODE(intf, vdev_id) \ + (WMI_VDEV_TYPE_NDI == intf[vdev_id].type) +/** + * wma_update_hdd_cfg_ndp() - Update target device NAN datapath capability + * @wma_handle: pointer to WMA context + * @tgt_cfg: Pointer to target configuration data structure + * + * Return: none + */ +static inline void wma_update_hdd_cfg_ndp(tp_wma_handle wma_handle, + struct wma_tgt_cfg *tgt_cfg) +{ + tgt_cfg->nan_datapath_enabled = wma_handle->nan_datapath_enabled; +} +QDF_STATUS wma_handle_ndp_responder_req(tp_wma_handle wma_handle, + struct ndp_responder_req *req_params); +void wma_delete_all_nan_remote_peers(tp_wma_handle wma, + uint32_t vdev_id); + +void wma_ndp_register_all_event_handlers(tp_wma_handle wma_handle); +void wma_ndp_unregister_all_event_handlers(tp_wma_handle wma_handle); +void wma_ndp_add_wow_wakeup_event(tp_wma_handle wma_handle, + uint8_t vdev_id); +void wma_ndp_wow_event_callback(void *handle, void *event, + uint32_t len, uint32_t event_id); +void wma_add_bss_ndi_mode(tp_wma_handle wma, tpAddBssParams add_bss); +void wma_add_sta_ndi_mode(tp_wma_handle wma, tpAddStaParams add_sta); +QDF_STATUS wma_handle_ndp_initiator_req(tp_wma_handle wma_handle, void *req); +QDF_STATUS wma_handle_ndp_end_req(tp_wma_handle wma_handle, void *req); +void wma_delete_sta_req_ndi_mode(tp_wma_handle wma, + tpDeleteStaParams del_sta); +uint32_t wma_ndp_get_eventid_from_tlvtag(uint32_t tag); +#else +#define WMA_IS_VDEV_IN_NDI_MODE(intf, vdev_id) (false) +static inline void wma_update_hdd_cfg_ndp(tp_wma_handle wma_handle, + struct wma_tgt_cfg *tgt_cfg) +{ + return; +} +static inline void wma_add_bss_ndi_mode(tp_wma_handle wma, + tpAddBssParams add_bss) +{ + return; +} +static inline void wma_delete_all_nan_remote_peers(tp_wma_handle wma, + uint32_t vdev_id) +{ +} +static inline void wma_ndp_register_all_event_handlers( + tp_wma_handle wma_handle) {} +static inline void wma_ndp_unregister_all_event_handlers( + tp_wma_handle wma_handle) {} +static inline void wma_ndp_add_wow_wakeup_event(tp_wma_handle wma_handle, + uint8_t vdev_id) {} +static inline void wma_ndp_wow_event_callback(void *handle, void *event, + uint32_t len, uint32_t event_id) {} +static inline void wma_add_sta_ndi_mode(tp_wma_handle wma, + tpAddStaParams add_sta) {} +static inline QDF_STATUS wma_handle_ndp_initiator_req(tp_wma_handle wma_handle, + void *req) +{ + return QDF_STATUS_SUCCESS; +} +static inline QDF_STATUS wma_handle_ndp_responder_req(tp_wma_handle wma_handle, + void *req_params) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS wma_handle_ndp_end_req(tp_wma_handle wma_handle, + void *req) +{ + return QDF_STATUS_SUCCESS; +} +static inline void wma_delete_sta_req_ndi_mode(tp_wma_handle wma, + tpDeleteStaParams del_sta) +{ +} + +static inline uint32_t wma_ndp_get_eventid_from_tlvtag(uint32_t tag) +{ + return 0; +} +#endif /* WLAN_FEATURE_NAN_DATAPATH */ +#endif /* __WMA_NAN_DATAPATH_H */ diff --git a/drivers/staging/qcacld-3.0/core/wma/src/wma_ocb.c b/drivers/staging/qcacld-3.0/core/wma/src/wma_ocb.c new file mode 100644 index 0000000000000000000000000000000000000000..0a4dcfb395e451f73a66857ce78e98b1f39fd66a --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/wma/src/wma_ocb.c @@ -0,0 +1,731 @@ +/* + * Copyright (c) 2013-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: wma_ocb.c + * + * WLAN Host Device Driver 802.11p OCB implementation + */ + +#include "wma_ocb.h" +#include "wmi_unified_api.h" +#include "cds_utils.h" +#include + +/** + * wma_ocb_resp() - send the OCB set config response via callback + * @wma_handle: pointer to the WMA handle + * @status: status of the set config command + */ +int wma_ocb_set_config_resp(tp_wma_handle wma_handle, uint8_t status) +{ + QDF_STATUS qdf_status; + struct sir_ocb_set_config_response *resp; + cds_msg_t msg = {0}; + struct sir_ocb_config *req = wma_handle->ocb_config_req; + ol_txrx_vdev_handle vdev = (req ? + wma_handle->interfaces[req->session_id].handle : NULL); + struct ol_txrx_ocb_set_chan ocb_set_chan; + + /* + * If the command was successful, save the channel information in the + * vdev. + */ + if (status == QDF_STATUS_SUCCESS && vdev && req) { + ocb_set_chan.ocb_channel_info = ol_txrx_get_ocb_chan_info(vdev); + if (ocb_set_chan.ocb_channel_info) + qdf_mem_free(ocb_set_chan.ocb_channel_info); + ocb_set_chan.ocb_channel_count = + req->channel_count; + if (req->channel_count) { + int i; + int buf_size = sizeof(*ocb_set_chan.ocb_channel_info) * + req->channel_count; + ocb_set_chan.ocb_channel_info = + qdf_mem_malloc(buf_size); + if (!ocb_set_chan.ocb_channel_info) + return -ENOMEM; + qdf_mem_zero(ocb_set_chan.ocb_channel_info, buf_size); + for (i = 0; i < req->channel_count; i++) { + ocb_set_chan.ocb_channel_info[i].chan_freq = + req->channels[i].chan_freq; + if (req->channels[i].flags & + OCB_CHANNEL_FLAG_DISABLE_RX_STATS_HDR) + ocb_set_chan.ocb_channel_info[i]. + disable_rx_stats_hdr = 1; + } + } else { + ocb_set_chan.ocb_channel_info = 0; + ocb_set_chan.ocb_channel_count = 0; + } + /* Default TX parameter */ + if (!ol_txrx_set_ocb_def_tx_param(vdev, + req->def_tx_param, req->def_tx_param_size)) { + /* Setting the default param failed */ + WMA_LOGE(FL("Invalid default TX parameters")); + status = QDF_STATUS_E_INVAL; + } + ol_txrx_set_ocb_chan_info(vdev, ocb_set_chan); + } + + /* Free the configuration that was saved in wma_ocb_set_config. */ + qdf_mem_free(wma_handle->ocb_config_req); + wma_handle->ocb_config_req = NULL; + + resp = qdf_mem_malloc(sizeof(*resp)); + if (!resp) + return -ENOMEM; + + resp->status = status; + + msg.type = eWNI_SME_OCB_SET_CONFIG_RSP; + msg.bodyptr = resp; + + qdf_status = cds_mq_post_message(QDF_MODULE_ID_SME, &msg); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + WMA_LOGE(FL("Fail to post msg to SME")); + qdf_mem_free(resp); + return -EINVAL; + } + + return 0; +} + +/** + * copy_sir_ocb_config() - deep copy of an OCB config struct + * @src: pointer to the source struct + * + * Return: pointer to the copied struct + */ +static struct sir_ocb_config *copy_sir_ocb_config(struct sir_ocb_config *src) +{ + struct sir_ocb_config *dst; + uint32_t length; + void *cursor; + + length = sizeof(*src) + + src->channel_count * sizeof(*src->channels) + + src->schedule_size * sizeof(*src->schedule) + + src->dcc_ndl_chan_list_len + + src->dcc_ndl_active_state_list_len; + + dst = qdf_mem_malloc(length); + if (!dst) + return NULL; + + *dst = *src; + + cursor = dst; + cursor += sizeof(*dst); + dst->channels = cursor; + cursor += src->channel_count * sizeof(*dst->channels); + qdf_mem_copy(dst->channels, src->channels, + src->channel_count * sizeof(*dst->channels)); + dst->schedule = cursor; + cursor += src->schedule_size * sizeof(*dst->schedule); + qdf_mem_copy(dst->schedule, src->schedule, + src->schedule_size * sizeof(*dst->schedule)); + dst->dcc_ndl_chan_list = cursor; + cursor += src->dcc_ndl_chan_list_len; + qdf_mem_copy(dst->dcc_ndl_chan_list, src->dcc_ndl_chan_list, + src->dcc_ndl_chan_list_len); + dst->dcc_ndl_active_state_list = cursor; + cursor += src->dcc_ndl_active_state_list_len; + qdf_mem_copy(dst->dcc_ndl_active_state_list, + src->dcc_ndl_active_state_list, + src->dcc_ndl_active_state_list_len); + return dst; +} + +/** + * wma_ocb_set_config_req() - send the OCB config request + * @wma_handle: pointer to the WMA handle + * @config_req: the configuration to be set. + */ +int wma_ocb_set_config_req(tp_wma_handle wma_handle, + struct sir_ocb_config *config_req) +{ + struct wma_target_req *msg; + struct wma_vdev_start_req req; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + /* if vdev is not yet up, send vdev start request and wait for response. + * OCB set_config request should be sent on receiving + * vdev start response message + */ + if (!wma_handle->interfaces[config_req->session_id].vdev_up) { + qdf_mem_zero(&req, sizeof(req)); + /* Enqueue OCB Set Schedule request message */ + msg = wma_fill_vdev_req(wma_handle, config_req->session_id, + WMA_OCB_SET_CONFIG_CMD, + WMA_TARGET_REQ_TYPE_VDEV_START, + (void *)config_req, 1000); + if (!msg) { + WMA_LOGE(FL("Failed to fill vdev req %d"), req.vdev_id); + status = QDF_STATUS_E_NOMEM; + return status; + } + req.chan = cds_freq_to_chan(config_req->channels[0].chan_freq); + req.vdev_id = msg->vdev_id; + if (cds_chan_to_band(req.chan) == CDS_BAND_2GHZ) + req.dot11_mode = WNI_CFG_DOT11_MODE_11G; + else + req.dot11_mode = WNI_CFG_DOT11_MODE_11A; + + if (wma_handle->ocb_config_req) + qdf_mem_free(wma_handle->ocb_config_req); + wma_handle->ocb_config_req = copy_sir_ocb_config(config_req); + req.preferred_rx_streams = 2; + req.preferred_tx_streams = 2; + + status = wma_vdev_start(wma_handle, &req, false); + if (status != QDF_STATUS_SUCCESS) { + wma_remove_vdev_req(wma_handle, req.vdev_id, + WMA_TARGET_REQ_TYPE_VDEV_START); + WMA_LOGE(FL("vdev_start failed, status = %d"), status); + } + return 0; + } else { + return wma_ocb_set_config(wma_handle, config_req); + } +} + +int wma_ocb_start_resp_ind_cont(tp_wma_handle wma_handle) +{ + QDF_STATUS qdf_status = 0; + + if (!wma_handle->ocb_config_req) { + WMA_LOGE(FL("The request could not be found")); + return QDF_STATUS_E_EMPTY; + } + + qdf_status = wma_ocb_set_config(wma_handle, wma_handle->ocb_config_req); + return qdf_status; +} + +static WLAN_PHY_MODE wma_ocb_freq_to_mode(uint32_t freq) +{ + if (cds_chan_to_band(cds_freq_to_chan(freq)) == CDS_BAND_2GHZ) + return MODE_11G; + else + return MODE_11A; +} + +/** + * wma_send_ocb_set_config() - send the OCB config to the FW + * @wma_handle: pointer to the WMA handle + * @config: the OCB configuration + * + * Return: 0 on success + */ +int wma_ocb_set_config(tp_wma_handle wma_handle, struct sir_ocb_config *config) +{ + int32_t ret, i; + uint32_t *ch_mhz; + struct ocb_config_param tconfig = {0}; + + tconfig.session_id = config->session_id; + tconfig.channel_count = config->channel_count; + tconfig.schedule_size = config->schedule_size; + tconfig.flags = config->flags; + tconfig.channels = (struct ocb_config_channel *)config->channels; + tconfig.schedule = (struct ocb_config_sched *)config->schedule; + tconfig.dcc_ndl_chan_list_len = config->dcc_ndl_chan_list_len; + tconfig.dcc_ndl_chan_list = config->dcc_ndl_chan_list; + tconfig.dcc_ndl_active_state_list_len = config->dcc_ndl_active_state_list_len; + tconfig.dcc_ndl_active_state_list = config->dcc_ndl_active_state_list; + ch_mhz = qdf_mem_malloc(sizeof(uint32_t)*config->channel_count); + if (ch_mhz == NULL) { + WMA_LOGE(FL("Memory allocation failed")); + return -ENOMEM; + } + + for (i = 0; i < config->channel_count; i++) + ch_mhz[i] = wma_ocb_freq_to_mode(config->channels[i].chan_freq); + + /* + * Save the configuration so that it can be used in + * wma_ocb_set_config_event_handler. + */ + if (wma_handle->ocb_config_req != config) { + if (wma_handle->ocb_config_req) + qdf_mem_free(wma_handle->ocb_config_req); + wma_handle->ocb_config_req = copy_sir_ocb_config(config); + } + + ret = wmi_unified_ocb_set_config(wma_handle->wmi_handle, &tconfig, + ch_mhz); + if (ret != EOK) { + if (wma_handle->ocb_config_req) { + qdf_mem_free(wma_handle->ocb_config_req); + wma_handle->ocb_config_req = NULL; + } + qdf_mem_free(ch_mhz); + WMA_LOGE("Failed to set OCB config"); + return -EIO; + } + qdf_mem_free(ch_mhz); + + return 0; +} + +/** + * wma_ocb_set_config_event_handler() - Response event for the set config cmd + * @handle: the WMA handle + * @event_buf: buffer with the event parameters + * @len: length of the buffer + * + * Return: 0 on success + */ +int wma_ocb_set_config_event_handler(void *handle, uint8_t *event_buf, + uint32_t len) +{ + WMI_OCB_SET_CONFIG_RESP_EVENTID_param_tlvs *param_tlvs; + wmi_ocb_set_config_resp_event_fixed_param *fix_param; + param_tlvs = (WMI_OCB_SET_CONFIG_RESP_EVENTID_param_tlvs *)event_buf; + fix_param = param_tlvs->fixed_param; + return wma_ocb_set_config_resp(handle, fix_param->status); +}; + +/** + * wma_ocb_set_utc_time() - send the UTC time to the firmware + * @wma_handle: pointer to the WMA handle + * @utc: pointer to the UTC time struct + * + * Return: 0 on succes + */ +int wma_ocb_set_utc_time(tp_wma_handle wma_handle, struct sir_ocb_utc *utc) +{ + int32_t ret; + struct ocb_utc_param cmd = {0}; + + cmd.vdev_id = utc->vdev_id; + qdf_mem_copy(&cmd.utc_time, &utc->utc_time, WMI_SIZE_UTC_TIME); + qdf_mem_copy(&cmd.time_error, &utc->time_error, WMI_SIZE_UTC_TIME_ERROR); + ret = wmi_unified_ocb_set_utc_time_cmd(wma_handle->wmi_handle, &cmd); + if (ret != EOK) { + WMA_LOGE(FL("Failed to set OCB UTC time")); + return -EIO; + } + + return 0; +} + +/** + * wma_ocb_start_timing_advert() - start sending the timing advertisement + * frames on a channel + * @wma_handle: pointer to the WMA handle + * @timing_advert: pointer to the timing advertisement struct + * + * Return: 0 on succes + */ +int wma_ocb_start_timing_advert(tp_wma_handle wma_handle, + struct sir_ocb_timing_advert *timing_advert) +{ + int32_t ret; + struct ocb_timing_advert_param cmd = {0}; + + cmd.vdev_id = timing_advert->vdev_id; + cmd.repeat_rate = timing_advert->repeat_rate; + cmd.chan_freq = timing_advert->chan_freq; + cmd.timestamp_offset = timing_advert->timestamp_offset; + cmd.time_value_offset = timing_advert->time_value_offset; + cmd.template_length = timing_advert->template_length; + cmd.template_value = (uint8_t *)timing_advert->template_value; + + ret = wmi_unified_ocb_start_timing_advert(wma_handle->wmi_handle, + &cmd); + if (ret != EOK) { + WMA_LOGE(FL("Failed to start OCB timing advert")); + return -EIO; + } + + return 0; +} + +/** + * wma_ocb_stop_timing_advert() - stop sending the timing advertisement frames + * on a channel + * @wma_handle: pointer to the WMA handle + * @timing_advert: pointer to the timing advertisement struct + * + * Return: 0 on succes + */ +int wma_ocb_stop_timing_advert(tp_wma_handle wma_handle, + struct sir_ocb_timing_advert *timing_advert) +{ + int32_t ret; + struct ocb_timing_advert_param cmd = {0}; + + cmd.vdev_id = timing_advert->vdev_id; + cmd.chan_freq = timing_advert->chan_freq; + ret = wmi_unified_ocb_stop_timing_advert(wma_handle->wmi_handle, + &cmd); + if (ret != EOK) { + WMA_LOGE(FL("Failed to stop OCB timing advert")); + return -EIO; + } + + return 0; +} + +/** + * wma_ocb_get_tsf_timer() - stop sending the timing advertisement frames on a + * channel + * @wma_handle: pointer to the WMA handle + * @request: pointer to the request + * + * Return: 0 on succes + */ +int wma_ocb_get_tsf_timer(tp_wma_handle wma_handle, + struct sir_ocb_get_tsf_timer *request) +{ + QDF_STATUS ret; + + /* Send the WMI command */ + ret = wmi_unified_ocb_get_tsf_timer(wma_handle->wmi_handle, request->vdev_id); + /* If there is an error, set the completion event */ + if (ret != EOK) { + WMA_LOGE(FL("Failed to send WMI message: %d"), ret); + return -EIO; + } + return 0; +} + +/** + * wma_ocb_get_tsf_timer_resp_event_handler() - Event for the get TSF timer cmd + * @handle: the WMA handle + * @event_buf: buffer with the event parameters + * @len: length of the buffer + * + * Return: 0 on success + */ +int wma_ocb_get_tsf_timer_resp_event_handler(void *handle, uint8_t *event_buf, + uint32_t len) +{ + QDF_STATUS qdf_status; + struct sir_ocb_get_tsf_timer_response *response; + WMI_OCB_GET_TSF_TIMER_RESP_EVENTID_param_tlvs *param_tlvs; + wmi_ocb_get_tsf_timer_resp_event_fixed_param *fix_param; + cds_msg_t msg = {0}; + + param_tlvs = (WMI_OCB_GET_TSF_TIMER_RESP_EVENTID_param_tlvs *)event_buf; + fix_param = param_tlvs->fixed_param; + + /* Allocate and populate the response */ + response = qdf_mem_malloc(sizeof(*response)); + if (response == NULL) + return -ENOMEM; + response->vdev_id = fix_param->vdev_id; + response->timer_high = fix_param->tsf_timer_high; + response->timer_low = fix_param->tsf_timer_low; + + msg.type = eWNI_SME_OCB_GET_TSF_TIMER_RSP; + msg.bodyptr = response; + + qdf_status = cds_mq_post_message(QDF_MODULE_ID_SME, &msg); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + WMA_LOGE(FL("Failed to post msg to SME")); + qdf_mem_free(response); + return -EINVAL; + } + + return 0; +} + +/** + * wma_dcc_get_stats() - get the DCC channel stats + * @wma_handle: pointer to the WMA handle + * @get_stats_param: pointer to the dcc stats + * + * Return: 0 on succes + */ +int wma_dcc_get_stats(tp_wma_handle wma_handle, + struct sir_dcc_get_stats *get_stats_param) +{ + int32_t ret; + struct dcc_get_stats_param cmd = {0}; + + cmd.vdev_id = get_stats_param->vdev_id; + cmd.channel_count = get_stats_param->channel_count; + cmd.request_array_len = get_stats_param->request_array_len; + cmd.request_array = get_stats_param->request_array; + + /* Send the WMI command */ + ret = wmi_unified_dcc_get_stats_cmd(wma_handle->wmi_handle, &cmd); + + if (ret != EOK) { + WMA_LOGE(FL("Failed to send WMI message: %d"), ret); + return -EIO; + } + + return 0; +} + +/** + * wma_dcc_get_stats_resp_event_handler() - Response event for the get stats cmd + * @handle: the WMA handle + * @event_buf: buffer with the event parameters + * @len: length of the buffer + * + * Return: 0 on success + */ +int wma_dcc_get_stats_resp_event_handler(void *handle, uint8_t *event_buf, + uint32_t len) +{ + QDF_STATUS qdf_status; + struct sir_dcc_get_stats_response *response; + WMI_DCC_GET_STATS_RESP_EVENTID_param_tlvs *param_tlvs; + wmi_dcc_get_stats_resp_event_fixed_param *fix_param; + cds_msg_t msg = {0}; + + param_tlvs = (WMI_DCC_GET_STATS_RESP_EVENTID_param_tlvs *)event_buf; + fix_param = param_tlvs->fixed_param; + + /* Allocate and populate the response */ + response = qdf_mem_malloc(sizeof(*response) + fix_param->num_channels * + sizeof(wmi_dcc_ndl_stats_per_channel)); + if (response == NULL) + return -ENOMEM; + + response->vdev_id = fix_param->vdev_id; + response->num_channels = fix_param->num_channels; + response->channel_stats_array_len = + fix_param->num_channels * sizeof(wmi_dcc_ndl_stats_per_channel); + response->channel_stats_array = ((void *)response) + sizeof(*response); + qdf_mem_copy(response->channel_stats_array, + param_tlvs->stats_per_channel_list, + response->channel_stats_array_len); + + msg.type = eWNI_SME_DCC_GET_STATS_RSP; + msg.bodyptr = response; + + qdf_status = cds_mq_post_message(QDF_MODULE_ID_SME, &msg); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + WMA_LOGE(FL("Failed to post msg to SME")); + qdf_mem_free(response); + return -EINVAL; + } + + return 0; +} + +/** + * wma_dcc_clear_stats() - command to clear the DCC stats + * @wma_handle: pointer to the WMA handle + * @clear_stats_param: parameters to the command + * + * Return: 0 on succes + */ +int wma_dcc_clear_stats(tp_wma_handle wma_handle, + struct sir_dcc_clear_stats *clear_stats_param) +{ + int32_t ret; + + /* Send the WMI command */ + ret = wmi_unified_dcc_clear_stats(wma_handle->wmi_handle, + clear_stats_param->vdev_id, + clear_stats_param->dcc_stats_bitmap); + if (ret != EOK) { + WMA_LOGE(FL("Failed to send the WMI command")); + return -EIO; + } + + return 0; +} + +/** + * wma_dcc_update_ndl() - command to update the NDL data + * @wma_handle: pointer to the WMA handle + * @update_ndl_param: pointer to the request parameters + * + * Return: 0 on success + */ +int wma_dcc_update_ndl(tp_wma_handle wma_handle, + struct sir_dcc_update_ndl *update_ndl_param) +{ + QDF_STATUS qdf_status; + struct dcc_update_ndl_param *cmd; + + cmd = (struct dcc_update_ndl_param *) update_ndl_param; + /* Send the WMI command */ + qdf_status = wmi_unified_dcc_update_ndl(wma_handle->wmi_handle, + cmd); + /* If there is an error, set the completion event */ + if (qdf_status) { + WMA_LOGE(FL("Failed to send WMI message: %d"), qdf_status); + return -EIO; + } + + return 0; +} + +/** + * wma_dcc_update_ndl_resp_event_handler() - Response event for the update NDL + * command + * @handle: the WMA handle + * @event_buf: buffer with the event parameters + * @len: length of the buffer + * + * Return: 0 on success + */ +int wma_dcc_update_ndl_resp_event_handler(void *handle, uint8_t *event_buf, + uint32_t len) +{ + QDF_STATUS qdf_status; + struct sir_dcc_update_ndl_response *resp; + WMI_DCC_UPDATE_NDL_RESP_EVENTID_param_tlvs *param_tlvs; + wmi_dcc_update_ndl_resp_event_fixed_param *fix_param; + cds_msg_t msg = {0}; + + param_tlvs = (WMI_DCC_UPDATE_NDL_RESP_EVENTID_param_tlvs *)event_buf; + fix_param = param_tlvs->fixed_param; + /* Allocate and populate the response */ + resp = qdf_mem_malloc(sizeof(*resp)); + if (!resp) { + WMA_LOGE(FL("Error allocating memory for the response.")); + return -ENOMEM; + } + resp->vdev_id = fix_param->vdev_id; + resp->status = fix_param->status; + + msg.type = eWNI_SME_DCC_UPDATE_NDL_RSP; + msg.bodyptr = resp; + + qdf_status = cds_mq_post_message(QDF_MODULE_ID_SME, &msg); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + WMA_LOGE(FL("Failed to post msg to SME")); + qdf_mem_free(resp); + return -EINVAL; + } + + return 0; +} + +/** + * wma_dcc_stats_event_handler() - Response event for the get stats cmd + * @handle: the WMA handle + * @event_buf: buffer with the event parameters + * @len: length of the buffer + * + * Return: 0 on success + */ +int wma_dcc_stats_event_handler(void *handle, uint8_t *event_buf, + uint32_t len) +{ + QDF_STATUS qdf_status; + struct sir_dcc_get_stats_response *response; + WMI_DCC_STATS_EVENTID_param_tlvs *param_tlvs; + wmi_dcc_stats_event_fixed_param *fix_param; + cds_msg_t msg = {0}; + + param_tlvs = (WMI_DCC_STATS_EVENTID_param_tlvs *)event_buf; + fix_param = param_tlvs->fixed_param; + /* Allocate and populate the response */ + response = qdf_mem_malloc(sizeof(*response) + + fix_param->num_channels * sizeof(wmi_dcc_ndl_stats_per_channel)); + if (response == NULL) + return -ENOMEM; + response->vdev_id = fix_param->vdev_id; + response->num_channels = fix_param->num_channels; + response->channel_stats_array_len = + fix_param->num_channels * sizeof(wmi_dcc_ndl_stats_per_channel); + response->channel_stats_array = ((void *)response) + sizeof(*response); + qdf_mem_copy(response->channel_stats_array, + param_tlvs->stats_per_channel_list, + response->channel_stats_array_len); + + msg.type = eWNI_SME_DCC_STATS_EVENT; + msg.bodyptr = response; + + qdf_status = cds_mq_post_message(QDF_MODULE_ID_SME, &msg); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + WMA_LOGE(FL("Failed to post msg to SME")); + qdf_mem_free(response); + return -EINVAL; + } + + return 0; +} + +/** + * wma_ocb_register_event_handlers() - register handlers for the OCB WMI + * events + * @wma_handle: pointer to the WMA handle + * + * Return: 0 on success, non-zero on failure + */ +int wma_ocb_register_event_handlers(tp_wma_handle wma_handle) +{ + int status; + + if (!wma_handle) { + WMA_LOGE(FL("wma_handle is NULL")); + return -EINVAL; + } + + /* Initialize the members in WMA used by wma_ocb */ + status = wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_OCB_SET_CONFIG_RESP_EVENTID, + wma_ocb_set_config_event_handler, + WMA_RX_SERIALIZER_CTX); + if (status) + return status; + + status = wmi_unified_register_event_handler( + wma_handle->wmi_handle, + WMI_OCB_GET_TSF_TIMER_RESP_EVENTID, + wma_ocb_get_tsf_timer_resp_event_handler, + WMA_RX_SERIALIZER_CTX); + if (status) + return status; + + status = wmi_unified_register_event_handler( + wma_handle->wmi_handle, + WMI_DCC_GET_STATS_RESP_EVENTID, + wma_dcc_get_stats_resp_event_handler, + WMA_RX_SERIALIZER_CTX); + if (status) + return status; + + status = wmi_unified_register_event_handler( + wma_handle->wmi_handle, + WMI_DCC_UPDATE_NDL_RESP_EVENTID, + wma_dcc_update_ndl_resp_event_handler, + WMA_RX_SERIALIZER_CTX); + if (status) + return status; + + status = wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_DCC_STATS_EVENTID, + wma_dcc_stats_event_handler, + WMA_RX_SERIALIZER_CTX); + if (status) + return status; + + return QDF_STATUS_SUCCESS; +} diff --git a/drivers/staging/qcacld-3.0/core/wma/src/wma_ocb.h b/drivers/staging/qcacld-3.0/core/wma/src/wma_ocb.h new file mode 100644 index 0000000000000000000000000000000000000000..878a7c9d4fd8a75c93b0baf4a5217ec75a0760f3 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/wma/src/wma_ocb.h @@ -0,0 +1,145 @@ +/* + * Copyright (c) 2015-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef __WMA_OCB_H +#define __WMA_OCB_H + +#include "wma.h" +#include "sir_api.h" + +#ifdef WLAN_FEATURE_DSRC +int wma_ocb_set_config_resp(tp_wma_handle wma_handle, uint8_t status); + +int wma_ocb_set_config_req(tp_wma_handle handle, + struct sir_ocb_config *config_req); + +int wma_ocb_set_config_event_handler(void *handle, uint8_t *event_buf, + uint32_t len); + +int wma_ocb_start_resp_ind_cont(tp_wma_handle wma_handle); + +int wma_ocb_set_config(tp_wma_handle wma_handle, struct sir_ocb_config *config); + +int wma_ocb_set_utc_time(tp_wma_handle wma_handle, struct sir_ocb_utc *utc); + +int wma_ocb_start_timing_advert(tp_wma_handle wma_handle, + struct sir_ocb_timing_advert *timing_advert); + +int wma_ocb_stop_timing_advert(tp_wma_handle wma_handle, + struct sir_ocb_timing_advert *timing_advert); + +int wma_ocb_get_tsf_timer(tp_wma_handle wma_handle, + struct sir_ocb_get_tsf_timer *request); + +int wma_dcc_get_stats(tp_wma_handle wma_handle, + struct sir_dcc_get_stats *get_stats_param); + +int wma_dcc_clear_stats(tp_wma_handle wma_handle, + struct sir_dcc_clear_stats *clear_stats_param); + +int wma_dcc_update_ndl(tp_wma_handle wma_handle, + struct sir_dcc_update_ndl *update_ndl_param); + +int wma_ocb_register_event_handlers(tp_wma_handle wma_handle); +#else +static inline int wma_ocb_set_config_resp(tp_wma_handle wma_handle, + uint8_t status) +{ + return 0; +} + +static inline int wma_ocb_set_config_req(tp_wma_handle handle, + struct sir_ocb_config *config_req) +{ + return 0; +} + +static inline int wma_ocb_set_config_event_handler(void *handle, + uint8_t *event_buf, uint32_t len) +{ + return 0; +} + +static inline int wma_ocb_start_resp_ind_cont(tp_wma_handle wma_handle) +{ + return 0; +} + +static inline int wma_ocb_set_config(tp_wma_handle wma_handle, + struct sir_ocb_config *config) +{ + return 0; +} + +static inline int wma_ocb_set_utc_time(tp_wma_handle wma_handle, + struct sir_ocb_utc *utc) +{ + return 0; +} + +static inline int wma_ocb_start_timing_advert(tp_wma_handle wma_handle, + struct sir_ocb_timing_advert *timing_advert) +{ + return 0; +} + +static inline int wma_ocb_stop_timing_advert(tp_wma_handle wma_handle, + struct sir_ocb_timing_advert *timing_advert) +{ + return 0; +} + +static inline int wma_ocb_get_tsf_timer(tp_wma_handle wma_handle, + struct sir_ocb_get_tsf_timer *request) +{ + return 0; +} + +static inline int wma_dcc_get_stats(tp_wma_handle wma_handle, + struct sir_dcc_get_stats *get_stats_param) +{ + return 0 ; +} + +static inline int wma_dcc_clear_stats(tp_wma_handle wma_handle, + struct sir_dcc_clear_stats *clear_stats_param) +{ + return 0; +} + +static inline int wma_dcc_update_ndl(tp_wma_handle wma_handle, + struct sir_dcc_update_ndl *update_ndl_param) +{ + return 0; +} + +static inline int wma_ocb_register_event_handlers(tp_wma_handle wma_handle) +{ + return 0; +} +#endif +#endif /* __WMA_OCB_H */ diff --git a/drivers/staging/qcacld-3.0/core/wma/src/wma_power.c b/drivers/staging/qcacld-3.0/core/wma/src/wma_power.c new file mode 100644 index 0000000000000000000000000000000000000000..c0257963b4a97fa771bb3ddfee5bac99cf4afc47 --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/wma/src/wma_power.c @@ -0,0 +1,2109 @@ +/* + * Copyright (c) 2013-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: wma_power.c + * This file contains powersave related functions. + */ + +/* Header files */ + +#include "wma.h" +#include "wma_api.h" +#include "cds_api.h" +#include "wmi_unified_api.h" +#include "wlan_qct_sys.h" +#include "wni_api.h" +#include "ani_global.h" +#include "wmi_unified.h" +#include "wni_cfg.h" +#include "cfg_api.h" + +#include "qdf_nbuf.h" +#include "qdf_types.h" +#include "qdf_mem.h" +#include "ol_txrx_peer_find.h" + +#include "wma_types.h" +#include "lim_api.h" +#include "lim_session_utils.h" + +#include "cds_utils.h" + +#if !defined(REMOVE_PKT_LOG) +#include "pktlog_ac.h" +#endif /* REMOVE_PKT_LOG */ + +#include "dbglog_host.h" +#include "csr_api.h" +#include "ol_fw.h" + +#include "dfs.h" +#include "wma_internal.h" + +/** + * wma_unified_modem_power_state() - set modem power state to fw + * @wmi_handle: wmi handle + * @param_value: parameter value + * + * Return: 0 for success or error code + */ +static int +wma_unified_modem_power_state(wmi_unified_t wmi_handle, uint32_t param_value) +{ + int ret; + wmi_modem_power_state_cmd_param *cmd; + wmi_buf_t buf; + uint16_t len = sizeof(*cmd); + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + WMA_LOGE("%s:wmi_buf_alloc failed", __func__); + return -ENOMEM; + } + cmd = (wmi_modem_power_state_cmd_param *) wmi_buf_data(buf); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_modem_power_state_cmd_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_modem_power_state_cmd_param)); + cmd->modem_power_state = param_value; + WMA_LOGD("%s: Setting cmd->modem_power_state = %u", __func__, + param_value); + ret = wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_MODEM_POWER_STATE_CMDID); + if (ret != EOK) { + WMA_LOGE("Failed to send notify cmd ret = %d", ret); + wmi_buf_free(buf); + } + return ret; +} + +/** + * wma_unified_set_sta_ps_param() - set sta power save parameter to fw + * @wmi_handle: wmi handle + * @vdev_id: vdev id + * @param: param + * @value: parameter value + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +QDF_STATUS wma_unified_set_sta_ps_param(wmi_unified_t wmi_handle, + uint32_t vdev_id, uint32_t param, + uint32_t value) +{ + tp_wma_handle wma; + struct wma_txrx_node *iface; + struct sta_ps_params sta_ps_param = {0}; + QDF_STATUS status; + + wma = cds_get_context(QDF_MODULE_ID_WMA); + if (NULL == wma) { + WMA_LOGE("%s: wma is NULL", __func__); + return QDF_STATUS_E_FAILURE; + } + WMA_LOGD("Set Sta Ps param vdevId %d Param %d val %d", + vdev_id, param, value); + iface = &wma->interfaces[vdev_id]; + + sta_ps_param.vdev_id = vdev_id; + sta_ps_param.param = param; + sta_ps_param.value = value; + status = wmi_unified_sta_ps_cmd_send(wmi_handle, &sta_ps_param); + if (QDF_IS_STATUS_ERROR(status)) + return status; + + return status; +} + +#ifdef QCA_IBSS_SUPPORT +/** + * wma_set_ibss_pwrsave_params() - set ibss power save parameter to fw + * @wma: wma handle + * @vdev_id: vdev id + * + * Return: 0 for success or error code. + */ +QDF_STATUS +wma_set_ibss_pwrsave_params(tp_wma_handle wma, uint8_t vdev_id) +{ + QDF_STATUS ret; + + ret = wma_vdev_set_param(wma->wmi_handle, vdev_id, + WMI_VDEV_PARAM_ATIM_WINDOW_LENGTH, + wma->wma_ibss_power_save_params.atimWindowLength); + if (QDF_IS_STATUS_ERROR(ret)) { + WMA_LOGE("Failed to set WMI_VDEV_PARAM_ATIM_WINDOW_LENGTH ret = %d", + ret); + return QDF_STATUS_E_FAILURE; + } + + ret = wma_vdev_set_param(wma->wmi_handle, vdev_id, + WMI_VDEV_PARAM_IS_IBSS_POWER_SAVE_ALLOWED, + wma->wma_ibss_power_save_params.isPowerSaveAllowed); + if (QDF_IS_STATUS_ERROR(ret)) { + WMA_LOGE("Failed, set WMI_VDEV_PARAM_IS_IBSS_POWER_SAVE_ALLOWED ret=%d", + ret); + return QDF_STATUS_E_FAILURE; + } + + ret = wma_vdev_set_param(wma->wmi_handle, vdev_id, + WMI_VDEV_PARAM_IS_POWER_COLLAPSE_ALLOWED, + wma->wma_ibss_power_save_params.isPowerCollapseAllowed); + if (QDF_IS_STATUS_ERROR(ret)) { + WMA_LOGE("Failed, set WMI_VDEV_PARAM_IS_POWER_COLLAPSE_ALLOWED ret=%d", + ret); + return QDF_STATUS_E_FAILURE; + } + + ret = wma_vdev_set_param(wma->wmi_handle, vdev_id, + WMI_VDEV_PARAM_IS_AWAKE_ON_TXRX_ENABLED, + wma->wma_ibss_power_save_params.isAwakeonTxRxEnabled); + if (QDF_IS_STATUS_ERROR(ret)) { + WMA_LOGE("Failed, set WMI_VDEV_PARAM_IS_AWAKE_ON_TXRX_ENABLED ret=%d", + ret); + return QDF_STATUS_E_FAILURE; + } + + ret = wma_vdev_set_param(wma->wmi_handle, vdev_id, + WMI_VDEV_PARAM_INACTIVITY_CNT, + wma->wma_ibss_power_save_params.inactivityCount); + if (QDF_IS_STATUS_ERROR(ret)) { + WMA_LOGE("Failed, set WMI_VDEV_PARAM_INACTIVITY_CNT ret=%d", + ret); + return QDF_STATUS_E_FAILURE; + } + + ret = wma_vdev_set_param(wma->wmi_handle, vdev_id, + WMI_VDEV_PARAM_TXSP_END_INACTIVITY_TIME_MS, + wma->wma_ibss_power_save_params.txSPEndInactivityTime); + if (QDF_IS_STATUS_ERROR(ret)) { + WMA_LOGE("Failed, set WMI_VDEV_PARAM_TXSP_END_INACTIVITY_TIME_MS ret=%d", + ret); + return QDF_STATUS_E_FAILURE; + } + + ret = wma_vdev_set_param(wma->wmi_handle, vdev_id, + WMI_VDEV_PARAM_IBSS_PS_WARMUP_TIME_SECS, + wma->wma_ibss_power_save_params.ibssPsWarmupTime); + if (QDF_IS_STATUS_ERROR(ret)) { + WMA_LOGE("Failed, set WMI_VDEV_PARAM_IBSS_PS_WARMUP_TIME_SECS ret=%d", + ret); + return QDF_STATUS_E_FAILURE; + } + + ret = wma_vdev_set_param(wma->wmi_handle, vdev_id, + WMI_VDEV_PARAM_IBSS_PS_1RX_CHAIN_IN_ATIM_WINDOW_ENABLE, + wma->wma_ibss_power_save_params.ibssPs1RxChainInAtimEnable); + if (QDF_IS_STATUS_ERROR(ret)) { + WMA_LOGE("Failed to set IBSS_PS_1RX_CHAIN_IN_ATIM_WINDOW_ENABLE ret=%d", + ret); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} +#endif /* QCA_IBSS_SUPPORT */ + +/** + * wma_set_ap_peer_uapsd() - set powersave parameters in ap mode to fw + * @wma: wma handle + * @vdev_id: vdev id + * @peer_addr: peer mac address + * @uapsd_value: uapsd value + * @max_sp: maximum service period + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +QDF_STATUS wma_set_ap_peer_uapsd(tp_wma_handle wma, uint32_t vdev_id, + uint8_t *peer_addr, uint8_t uapsd_value, + uint8_t max_sp) +{ + uint32_t uapsd = 0; + uint32_t max_sp_len = 0; + QDF_STATUS ret; + struct ap_ps_params param = {0}; + + if (uapsd_value & UAPSD_VO_ENABLED) { + uapsd |= WMI_AP_PS_UAPSD_AC3_DELIVERY_EN | + WMI_AP_PS_UAPSD_AC3_TRIGGER_EN; + } + + if (uapsd_value & UAPSD_VI_ENABLED) { + uapsd |= WMI_AP_PS_UAPSD_AC2_DELIVERY_EN | + WMI_AP_PS_UAPSD_AC2_TRIGGER_EN; + } + + if (uapsd_value & UAPSD_BK_ENABLED) { + uapsd |= WMI_AP_PS_UAPSD_AC1_DELIVERY_EN | + WMI_AP_PS_UAPSD_AC1_TRIGGER_EN; + } + + if (uapsd_value & UAPSD_BE_ENABLED) { + uapsd |= WMI_AP_PS_UAPSD_AC0_DELIVERY_EN | + WMI_AP_PS_UAPSD_AC0_TRIGGER_EN; + } + + switch (max_sp) { + case UAPSD_MAX_SP_LEN_2: + max_sp_len = WMI_AP_PS_PEER_PARAM_MAX_SP_2; + break; + case UAPSD_MAX_SP_LEN_4: + max_sp_len = WMI_AP_PS_PEER_PARAM_MAX_SP_4; + break; + case UAPSD_MAX_SP_LEN_6: + max_sp_len = WMI_AP_PS_PEER_PARAM_MAX_SP_6; + break; + default: + max_sp_len = WMI_AP_PS_PEER_PARAM_MAX_SP_UNLIMITED; + break; + } + + WMA_LOGD("Set WMI_AP_PS_PEER_PARAM_UAPSD 0x%x for %pM", + uapsd, peer_addr); + param.vdev_id = vdev_id; + param.param = WMI_AP_PS_PEER_PARAM_UAPSD; + param.value = uapsd; + ret = wmi_unified_ap_ps_cmd_send(wma->wmi_handle, peer_addr, + ¶m); + if (QDF_IS_STATUS_ERROR(ret)) { + WMA_LOGE("Failed to set WMI_AP_PS_PEER_PARAM_UAPSD for %pM", + peer_addr); + return ret; + } + + WMA_LOGD("Set WMI_AP_PS_PEER_PARAM_MAX_SP 0x%x for %pM", + max_sp_len, peer_addr); + + param.vdev_id = vdev_id; + param.param = WMI_AP_PS_PEER_PARAM_MAX_SP; + param.value = max_sp_len; + ret = wmi_unified_ap_ps_cmd_send(wma->wmi_handle, peer_addr, + ¶m); + if (QDF_IS_STATUS_ERROR(ret)) { + WMA_LOGE("Failed to set WMI_AP_PS_PEER_PARAM_MAX_SP for %pM", + peer_addr); + return ret; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * wma_update_edca_params_for_ac() - to update per ac EDCA parameters + * @edca_param: EDCA parameters + * @wmm_param: wmm parameters + * @ac: access category + * + * Return: none + */ +void wma_update_edca_params_for_ac(tSirMacEdcaParamRecord *edca_param, + wmi_wmm_vparams *wmm_param, int ac) +{ +#define WMA_WMM_EXPO_TO_VAL(val) ((1 << (val)) - 1) + wmm_param->cwmin = WMA_WMM_EXPO_TO_VAL(edca_param->cw.min); + wmm_param->cwmax = WMA_WMM_EXPO_TO_VAL(edca_param->cw.max); + wmm_param->aifs = edca_param->aci.aifsn; + wmm_param->txoplimit = edca_param->txoplimit; + wmm_param->acm = edca_param->aci.acm; + + /* TODO: No ack is not present in EdcaParamRecord */ + wmm_param->no_ack = 0; + + WMA_LOGI("WMM PARAMS AC[%d]: AIFS %d Min %d Max %d TXOP %d ACM %d NOACK %d", + ac, wmm_param->aifs, wmm_param->cwmin, wmm_param->cwmax, + wmm_param->txoplimit, wmm_param->acm, wmm_param->no_ack); +} + +/** + * wma_set_tx_power() - set tx power limit in fw + * @handle: wma handle + * @tx_pwr_params: tx power parameters + * + * Return: none + */ +void wma_set_tx_power(WMA_HANDLE handle, + tMaxTxPowerParams *tx_pwr_params) +{ + tp_wma_handle wma_handle = (tp_wma_handle) handle; + uint8_t vdev_id; + QDF_STATUS ret = QDF_STATUS_E_FAILURE; + void *pdev; + + if (tx_pwr_params->dev_mode == QDF_SAP_MODE || + tx_pwr_params->dev_mode == QDF_P2P_GO_MODE) { + pdev = wma_find_vdev_by_addr(wma_handle, + tx_pwr_params->bssId.bytes, + &vdev_id); + } else { + pdev = wma_find_vdev_by_bssid(wma_handle, + tx_pwr_params->bssId.bytes, + &vdev_id); + } + if (!pdev) { + WMA_LOGE("vdev handle is invalid for %pM", + tx_pwr_params->bssId.bytes); + qdf_mem_free(tx_pwr_params); + return; + } + + if (!(wma_handle->interfaces[vdev_id].vdev_up)) { + WMA_LOGE("%s: vdev id %d is not up for %pM", __func__, vdev_id, + tx_pwr_params->bssId.bytes); + qdf_mem_free(tx_pwr_params); + return; + } + + if (tx_pwr_params->power == 0) { + /* set to default. Since the app does not care the tx power + * we keep the previous setting */ + wma_handle->interfaces[vdev_id].tx_power = 0; + ret = 0; + goto end; + } + if (wma_handle->interfaces[vdev_id].max_tx_power != 0) { + /* make sure tx_power less than max_tx_power */ + if (tx_pwr_params->power > + wma_handle->interfaces[vdev_id].max_tx_power) { + tx_pwr_params->power = + wma_handle->interfaces[vdev_id].max_tx_power; + } + } + if (wma_handle->interfaces[vdev_id].tx_power != tx_pwr_params->power) { + + /* tx_power changed, Push the tx_power to FW */ + WMA_LOGI("%s: Set TX pwr limit [WMI_VDEV_PARAM_TX_PWRLIMIT] to %d", + __func__, tx_pwr_params->power); + ret = wma_vdev_set_param(wma_handle->wmi_handle, + vdev_id, + WMI_VDEV_PARAM_TX_PWRLIMIT, + tx_pwr_params->power); + if (ret == QDF_STATUS_SUCCESS) + wma_handle->interfaces[vdev_id].tx_power = + tx_pwr_params->power; + } else { + /* no tx_power change */ + ret = QDF_STATUS_SUCCESS; + } +end: + qdf_mem_free(tx_pwr_params); + if (QDF_IS_STATUS_ERROR(ret)) + WMA_LOGE("Failed to set vdev param WMI_VDEV_PARAM_TX_PWRLIMIT"); +} + +/** + * wma_set_max_tx_power() - set max tx power limit in fw + * @handle: wma handle + * @tx_pwr_params: tx power parameters + * + * Return: none + */ +void wma_set_max_tx_power(WMA_HANDLE handle, + tMaxTxPowerParams *tx_pwr_params) +{ + tp_wma_handle wma_handle = (tp_wma_handle) handle; + uint8_t vdev_id; + QDF_STATUS ret = QDF_STATUS_E_FAILURE; + void *pdev; + int8_t prev_max_power; + + pdev = wma_find_vdev_by_addr(wma_handle, tx_pwr_params->bssId.bytes, + &vdev_id); + if (pdev == NULL) { + /* not in SAP array. Try the station/p2p array */ + pdev = wma_find_vdev_by_bssid(wma_handle, + tx_pwr_params->bssId.bytes, + &vdev_id); + } + if (!pdev) { + WMA_LOGE("vdev handle is invalid for %pM", + tx_pwr_params->bssId.bytes); + qdf_mem_free(tx_pwr_params); + return; + } + + if (!(wma_handle->interfaces[vdev_id].vdev_up)) { + WMA_LOGE("%s: vdev id %d is not up", __func__, vdev_id); + qdf_mem_free(tx_pwr_params); + return; + } + + if (wma_handle->interfaces[vdev_id].max_tx_power == + tx_pwr_params->power) { + ret = QDF_STATUS_SUCCESS; + goto end; + } + prev_max_power = wma_handle->interfaces[vdev_id].max_tx_power; + wma_handle->interfaces[vdev_id].max_tx_power = tx_pwr_params->power; + if (wma_handle->interfaces[vdev_id].max_tx_power == 0) { + ret = QDF_STATUS_SUCCESS; + goto end; + } + WMA_LOGI("Set MAX TX pwr limit [WMI_VDEV_PARAM_TX_PWRLIMIT] to %d", + wma_handle->interfaces[vdev_id].max_tx_power); + ret = wma_vdev_set_param(wma_handle->wmi_handle, vdev_id, + WMI_VDEV_PARAM_TX_PWRLIMIT, + wma_handle->interfaces[vdev_id].max_tx_power); + if (ret == QDF_STATUS_SUCCESS) + wma_handle->interfaces[vdev_id].tx_power = + wma_handle->interfaces[vdev_id].max_tx_power; + else + wma_handle->interfaces[vdev_id].max_tx_power = prev_max_power; +end: + qdf_mem_free(tx_pwr_params); + if (QDF_IS_STATUS_ERROR(ret)) + WMA_LOGE("%s: Failed to set vdev param WMI_VDEV_PARAM_TX_PWRLIMIT", + __func__); +} + +/** + * wmi_unified_set_sta_ps() - set sta powersave params in fw + * @handle: wma handle + * @vdev_id: vdev id + * @val: value + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +static QDF_STATUS wmi_unified_set_sta_ps(wmi_unified_t wmi_handle, + uint32_t vdev_id, uint8_t val) +{ + QDF_STATUS ret; + + ret = wmi_unified_set_sta_ps_mode(wmi_handle, vdev_id, + val); + if (QDF_IS_STATUS_ERROR(ret)) + WMA_LOGE("Failed to send set Mimo PS ret = %d", ret); + + return QDF_STATUS_SUCCESS; +} + +/** + * wma_get_uapsd_mask() - get uapsd mask based on uapsd parameters + * @uapsd_params: uapsed parameters + * + * Return: uapsd mask + */ +static inline uint32_t wma_get_uapsd_mask(tpUapsd_Params uapsd_params) +{ + uint32_t uapsd_val = 0; + + if (uapsd_params->beDeliveryEnabled) + uapsd_val |= WMI_STA_PS_UAPSD_AC0_DELIVERY_EN; + + if (uapsd_params->beTriggerEnabled) + uapsd_val |= WMI_STA_PS_UAPSD_AC0_TRIGGER_EN; + + if (uapsd_params->bkDeliveryEnabled) + uapsd_val |= WMI_STA_PS_UAPSD_AC1_DELIVERY_EN; + + if (uapsd_params->bkTriggerEnabled) + uapsd_val |= WMI_STA_PS_UAPSD_AC1_TRIGGER_EN; + + if (uapsd_params->viDeliveryEnabled) + uapsd_val |= WMI_STA_PS_UAPSD_AC2_DELIVERY_EN; + + if (uapsd_params->viTriggerEnabled) + uapsd_val |= WMI_STA_PS_UAPSD_AC2_TRIGGER_EN; + + if (uapsd_params->voDeliveryEnabled) + uapsd_val |= WMI_STA_PS_UAPSD_AC3_DELIVERY_EN; + + if (uapsd_params->voTriggerEnabled) + uapsd_val |= WMI_STA_PS_UAPSD_AC3_TRIGGER_EN; + + return uapsd_val; +} + +/** + * wma_set_force_sleep() - set power save parameters to fw + * @wma: wma handle + * @vdev_id: vdev id + * @enable: enable/disable + * @qpower_config: qpower configuration + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +static QDF_STATUS wma_set_force_sleep(tp_wma_handle wma, + uint32_t vdev_id, + uint8_t enable, + enum powersave_qpower_mode qpower_config, + bool enable_ps) +{ + QDF_STATUS ret; + uint32_t cfg_data_val = 0; + /* get mac to acess CFG data base */ + struct sAniSirGlobal *mac = cds_get_context(QDF_MODULE_ID_PE); + uint32_t rx_wake_policy; + uint32_t tx_wake_threshold; + uint32_t pspoll_count; + uint32_t inactivity_time; + uint32_t psmode; + + WMA_LOGD("Set Force Sleep vdevId %d val %d", vdev_id, enable); + + if (NULL == mac) { + WMA_LOGE("%s: Unable to get PE context", __func__); + return QDF_STATUS_E_NOMEM; + } + + /* Set Tx/Rx Data InActivity Timeout */ + if (wlan_cfg_get_int(mac, WNI_CFG_PS_DATA_INACTIVITY_TIMEOUT, + &cfg_data_val) != eSIR_SUCCESS) { + QDF_TRACE(QDF_MODULE_ID_WMA, QDF_TRACE_LEVEL_ERROR, + "Failed to get WNI_CFG_PS_DATA_INACTIVITY_TIMEOUT"); + cfg_data_val = POWERSAVE_DEFAULT_INACTIVITY_TIME; + } + inactivity_time = (uint32_t) cfg_data_val; + + if (enable) { + /* override normal configuration and force station asleep */ + rx_wake_policy = WMI_STA_PS_RX_WAKE_POLICY_POLL_UAPSD; + tx_wake_threshold = WMI_STA_PS_TX_WAKE_THRESHOLD_NEVER; + + if (wlan_cfg_get_int(mac, WNI_CFG_MAX_PS_POLL, + &cfg_data_val) != eSIR_SUCCESS) { + QDF_TRACE(QDF_MODULE_ID_WMA, QDF_TRACE_LEVEL_ERROR, + "Failed to get value for WNI_CFG_MAX_PS_POLL"); + } + if (cfg_data_val) + pspoll_count = (uint32_t) cfg_data_val; + else + pspoll_count = WMA_DEFAULT_MAX_PSPOLL_BEFORE_WAKE; + + psmode = WMI_STA_PS_MODE_ENABLED; + } else { + /* Ps Poll Wake Policy */ + if (wlan_cfg_get_int(mac, WNI_CFG_MAX_PS_POLL, + &cfg_data_val) != eSIR_SUCCESS) { + QDF_TRACE(QDF_MODULE_ID_WMA, QDF_TRACE_LEVEL_ERROR, + "Failed to get value for WNI_CFG_MAX_PS_POLL"); + } + if (cfg_data_val) { + /* Ps Poll is enabled */ + rx_wake_policy = WMI_STA_PS_RX_WAKE_POLICY_POLL_UAPSD; + pspoll_count = (uint32_t) cfg_data_val; + tx_wake_threshold = WMI_STA_PS_TX_WAKE_THRESHOLD_NEVER; + } else { + rx_wake_policy = WMI_STA_PS_RX_WAKE_POLICY_WAKE; + pspoll_count = WMI_STA_PS_PSPOLL_COUNT_NO_MAX; + tx_wake_threshold = WMI_STA_PS_TX_WAKE_THRESHOLD_ALWAYS; + } + psmode = WMI_STA_PS_MODE_ENABLED; + } + + /* + * QPower is enabled by default in Firmware + * So Disable QPower explicitly + */ + ret = wma_unified_set_sta_ps_param(wma->wmi_handle, vdev_id, + WMI_STA_PS_ENABLE_QPOWER, + qpower_config); + if (QDF_IS_STATUS_ERROR(ret)) { + WMA_LOGE("%s(%d) QPower Failed vdevId %d", + qpower_config ? "Enable" : "Disable", + qpower_config, vdev_id); + return ret; + } + WMA_LOGD("QPower %s(%d) vdevId %d", + qpower_config ? "Enabled" : "Disabled", + qpower_config, vdev_id); + + /* Set the Wake Policy to WMI_STA_PS_RX_WAKE_POLICY_POLL_UAPSD */ + ret = wma_unified_set_sta_ps_param(wma->wmi_handle, vdev_id, + WMI_STA_PS_PARAM_RX_WAKE_POLICY, + rx_wake_policy); + + if (QDF_IS_STATUS_ERROR(ret)) { + WMA_LOGE("Setting wake policy Failed vdevId %d", vdev_id); + return ret; + } + WMA_LOGD("Setting wake policy to %d vdevId %d", + rx_wake_policy, vdev_id); + + /* Set the Tx Wake Threshold */ + ret = wma_unified_set_sta_ps_param(wma->wmi_handle, vdev_id, + WMI_STA_PS_PARAM_TX_WAKE_THRESHOLD, + tx_wake_threshold); + + if (QDF_IS_STATUS_ERROR(ret)) { + WMA_LOGE("Setting TxWake Threshold vdevId %d", vdev_id); + return ret; + } + WMA_LOGD("Setting TxWake Threshold to %d vdevId %d", + tx_wake_threshold, vdev_id); + + /* Set the Ps Poll Count */ + ret = wma_unified_set_sta_ps_param(wma->wmi_handle, vdev_id, + WMI_STA_PS_PARAM_PSPOLL_COUNT, + pspoll_count); + + if (QDF_IS_STATUS_ERROR(ret)) { + WMA_LOGE("Set Ps Poll Count Failed vdevId %d ps poll cnt %d", + vdev_id, pspoll_count); + return ret; + } + WMA_LOGD("Set Ps Poll Count vdevId %d ps poll cnt %d", + vdev_id, pspoll_count); + + /* Set the Tx/Rx InActivity */ + ret = wma_unified_set_sta_ps_param(wma->wmi_handle, vdev_id, + WMI_STA_PS_PARAM_INACTIVITY_TIME, + inactivity_time); + + if (QDF_IS_STATUS_ERROR(ret)) { + WMA_LOGE("Setting Tx/Rx InActivity Failed vdevId %d InAct %d", + vdev_id, inactivity_time); + return ret; + } + WMA_LOGD("Set Tx/Rx InActivity vdevId %d InAct %d", + vdev_id, inactivity_time); + + /* Enable Sta Mode Power save */ + if (enable_ps) { + ret = wmi_unified_set_sta_ps(wma->wmi_handle, vdev_id, true); + + if (QDF_IS_STATUS_ERROR(ret)) { + WMA_LOGE("Enable Sta Mode Ps Failed vdevId %d", + vdev_id); + return ret; + } + } + + /* Set Listen Interval */ + if (wlan_cfg_get_int(mac, WNI_CFG_LISTEN_INTERVAL, + &cfg_data_val) != eSIR_SUCCESS) { + QDF_TRACE(QDF_MODULE_ID_WMA, QDF_TRACE_LEVEL_ERROR, + "Failed to get value for WNI_CFG_LISTEN_INTERVAL"); + cfg_data_val = POWERSAVE_DEFAULT_LISTEN_INTERVAL; + } + + ret = wma_vdev_set_param(wma->wmi_handle, vdev_id, + WMI_VDEV_PARAM_LISTEN_INTERVAL, + cfg_data_val); + if (QDF_IS_STATUS_ERROR(ret)) { + /* Even it fails continue Fw will take default LI */ + WMA_LOGE("Failed to Set Listen Interval vdevId %d", vdev_id); + } + WMA_LOGD("Set Listen Interval vdevId %d Listen Intv %d", + vdev_id, cfg_data_val); + + return QDF_STATUS_SUCCESS; +} + +/** + * wma_get_qpower_config() - get qpower configuration + * @wma: WMA handle + * + * Power Save Offload configuration: + * 0 -> Power save offload is disabled + * 1 -> Legacy Power save enabled + Deep sleep Disabled + * 2 -> QPower enabled + Deep sleep Disabled + * 3 -> Legacy Power save enabled + Deep sleep Enabled + * 4 -> QPower enabled + Deep sleep Enabled + * 5 -> Duty cycling QPower enabled + * + * Return: enum powersave_qpower_mode with below values + * QPOWER_DISABLED if QPOWER is disabled + * QPOWER_ENABLED if QPOWER is enabled + * QPOWER_DUTY_CYCLING if DUTY CYCLING QPOWER is enabled + */ +static enum powersave_qpower_mode wma_get_qpower_config(tp_wma_handle wma) +{ + switch (wma->powersave_mode) { + case PS_QPOWER_NODEEPSLEEP: + case PS_QPOWER_DEEPSLEEP: + WMA_LOGI("QPOWER is enabled in power save mode %d", + wma->powersave_mode); + return QPOWER_ENABLED; + case PS_DUTY_CYCLING_QPOWER: + WMA_LOGI("DUTY cycling QPOWER is enabled in power save mode %d", + wma->powersave_mode); + return QPOWER_DUTY_CYCLING; + + default: + WMA_LOGI("QPOWER is disabled in power save mode %d", + wma->powersave_mode); + return QPOWER_DISABLED; + } +} + +/** + * wma_enable_sta_ps_mode() - enable sta powersave params in fw + * @wma: wma handle + * @ps_req: power save request + * + * Return: none + */ +void wma_enable_sta_ps_mode(tp_wma_handle wma, tpEnablePsParams ps_req) +{ + uint32_t vdev_id = ps_req->sessionid; + QDF_STATUS ret; + enum powersave_qpower_mode qpower_config = wma_get_qpower_config(wma); + struct wma_txrx_node *iface = &wma->interfaces[vdev_id]; + + wma->ps_setting = ps_req->psSetting; + + if (!iface->handle) { + WMA_LOGE("vdev id %d is not active", vdev_id); + return; + } + if (eSIR_ADDON_NOTHING == ps_req->psSetting) { + if (qpower_config && iface->uapsd_cached_val) { + qpower_config = 0; + WMA_LOGD("Qpower is disabled"); + } + WMA_LOGD("Enable Sta Mode Ps vdevId %d", vdev_id); + ret = wma_unified_set_sta_ps_param(wma->wmi_handle, vdev_id, + WMI_STA_PS_PARAM_UAPSD, 0); + if (QDF_IS_STATUS_ERROR(ret)) { + WMA_LOGE("Set Uapsd param 0 Failed vdevId %d", vdev_id); + return; + } + + ret = wma_set_force_sleep(wma, vdev_id, false, + qpower_config, true); + if (QDF_IS_STATUS_ERROR(ret)) { + WMA_LOGE("Enable Sta Ps Failed vdevId %d", vdev_id); + return; + } + } else if (eSIR_ADDON_ENABLE_UAPSD == ps_req->psSetting) { + uint32_t uapsd_val = 0; + uapsd_val = wma_get_uapsd_mask(&ps_req->uapsdParams); + + if (uapsd_val != iface->uapsd_cached_val) { + WMA_LOGD("Enable Uapsd vdevId %d Mask %d", + vdev_id, uapsd_val); + ret = wma_unified_set_sta_ps_param(wma->wmi_handle, + vdev_id, + WMI_STA_PS_PARAM_UAPSD, + uapsd_val); + if (QDF_IS_STATUS_ERROR(ret)) { + WMA_LOGE("Enable Uapsd Failed vdevId %d", + vdev_id); + return; + } + /* Cache the Uapsd Mask */ + iface->uapsd_cached_val = uapsd_val; + } else { + WMA_LOGD("Already Uapsd Enabled vdevId %d Mask %d", + vdev_id, uapsd_val); + } + + if (qpower_config && iface->uapsd_cached_val) { + qpower_config = 0; + WMA_LOGD("Qpower is disabled"); + } + WMA_LOGD("Enable Forced Sleep vdevId %d", vdev_id); + ret = wma_set_force_sleep(wma, vdev_id, true, + qpower_config, true); + + if (QDF_IS_STATUS_ERROR(ret)) { + WMA_LOGE("Enable Forced Sleep Failed vdevId %d", + vdev_id); + return; + } + } + + if (wma->ito_repeat_count) { + WMA_LOGI("Set ITO count to %d for vdevId %d", + wma->ito_repeat_count, vdev_id); + + ret = wma_unified_set_sta_ps_param(wma->wmi_handle, + vdev_id, + WMI_STA_PS_PARAM_MAX_RESET_ITO_COUNT_ON_TIM_NO_TXRX, + wma->ito_repeat_count); + if (QDF_IS_STATUS_ERROR(ret)) { + WMA_LOGE("Set ITO count failed vdevId %d Error %d", + vdev_id, ret); + return; + } + } + + /* power save request succeeded */ + iface->in_bmps = true; +} + +/** + * wma_disable_sta_ps_mode() - disable sta powersave params in fw + * @wma: wma handle + * @ps_req: power save request + * + * Return: none + */ +void wma_disable_sta_ps_mode(tp_wma_handle wma, tpDisablePsParams ps_req) +{ + QDF_STATUS ret; + uint32_t vdev_id = ps_req->sessionid; + struct wma_txrx_node *iface = &wma->interfaces[vdev_id]; + + WMA_LOGD("Disable Sta Mode Ps vdevId %d", vdev_id); + + /* Disable Sta Mode Power save */ + ret = wmi_unified_set_sta_ps(wma->wmi_handle, vdev_id, false); + if (QDF_IS_STATUS_ERROR(ret)) { + WMA_LOGE("Disable Sta Mode Ps Failed vdevId %d", vdev_id); + return; + } + iface->in_bmps = false; + /* Disable UAPSD incase if additional Req came */ + if (eSIR_ADDON_DISABLE_UAPSD == ps_req->psSetting) { + WMA_LOGD("Disable Uapsd vdevId %d", vdev_id); + ret = wma_unified_set_sta_ps_param(wma->wmi_handle, vdev_id, + WMI_STA_PS_PARAM_UAPSD, 0); + if (QDF_IS_STATUS_ERROR(ret)) { + WMA_LOGE("Disable Uapsd Failed vdevId %d", vdev_id); + /* + * Even this fails we can proceed as success + * since we disabled powersave + */ + } + } +} + +QDF_STATUS wma_set_qpower_config(uint8_t vdev_id, uint8_t qpower) +{ + tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA); + + if (!wma) { + WMA_LOGE("%s: WMA context is invald!", __func__); + return QDF_STATUS_E_INVAL; + } + + WMA_LOGI("configuring qpower: %d", qpower); + wma->powersave_mode = qpower; + return wma_unified_set_sta_ps_param(wma->wmi_handle, + vdev_id, + WMI_STA_PS_ENABLE_QPOWER, + wma_get_qpower_config(wma)); +} + +/** + * wma_enable_uapsd_mode() - enable uapsd mode in fw + * @wma: wma handle + * @ps_req: power save request + * + * Return: none + */ +void wma_enable_uapsd_mode(tp_wma_handle wma, tpEnableUapsdParams ps_req) +{ + QDF_STATUS ret; + uint32_t vdev_id = ps_req->sessionid; + uint32_t uapsd_val = 0; + enum powersave_qpower_mode qpower_config = wma_get_qpower_config(wma); + struct wma_txrx_node *iface = &wma->interfaces[vdev_id]; + + if (!iface->handle) { + WMA_LOGE("vdev id %d is not active", vdev_id); + return; + } + + /* Disable Sta Mode Power save */ + ret = wmi_unified_set_sta_ps(wma->wmi_handle, vdev_id, false); + if (QDF_IS_STATUS_ERROR(ret)) { + WMA_LOGE("Disable Sta Mode Ps Failed vdevId %d", vdev_id); + return; + } + + uapsd_val = wma_get_uapsd_mask(&ps_req->uapsdParams); + + WMA_LOGD("Enable Uapsd vdevId %d Mask %d", vdev_id, uapsd_val); + ret = wma_unified_set_sta_ps_param(wma->wmi_handle, vdev_id, + WMI_STA_PS_PARAM_UAPSD, uapsd_val); + if (QDF_IS_STATUS_ERROR(ret)) { + WMA_LOGE("Enable Uapsd Failed vdevId %d", vdev_id); + return; + } + + if (qpower_config && uapsd_val) { + qpower_config = 0; + WMA_LOGD("Disable Qpower %d", vdev_id); + } + iface->uapsd_cached_val = uapsd_val; + WMA_LOGD("Enable Forced Sleep vdevId %d", vdev_id); + ret = wma_set_force_sleep(wma, vdev_id, true, + qpower_config, ps_req->uapsdParams.enable_ps); + if (QDF_IS_STATUS_ERROR(ret)) { + WMA_LOGE("Enable Forced Sleep Failed vdevId %d", vdev_id); + return; + } + +} + +/** + * wma_disable_uapsd_mode() - disable uapsd mode in fw + * @wma: wma handle + * @ps_req: power save request + * + * Return: none + */ +void wma_disable_uapsd_mode(tp_wma_handle wma, + tpDisableUapsdParams ps_req) +{ + QDF_STATUS ret; + uint32_t vdev_id = ps_req->sessionid; + enum powersave_qpower_mode qpower_config = wma_get_qpower_config(wma); + + WMA_LOGD("Disable Uapsd vdevId %d", vdev_id); + + /* Disable Sta Mode Power save */ + ret = wmi_unified_set_sta_ps(wma->wmi_handle, vdev_id, false); + if (QDF_IS_STATUS_ERROR(ret)) { + WMA_LOGE("Disable Sta Mode Ps Failed vdevId %d", vdev_id); + return; + } + + ret = wma_unified_set_sta_ps_param(wma->wmi_handle, vdev_id, + WMI_STA_PS_PARAM_UAPSD, 0); + if (QDF_IS_STATUS_ERROR(ret)) { + WMA_LOGE("Disable Uapsd Failed vdevId %d", vdev_id); + return; + } + + /* Re enable Sta Mode Powersave with proper configuration */ + ret = wma_set_force_sleep(wma, vdev_id, false, + qpower_config, true); + if (QDF_IS_STATUS_ERROR(ret)) { + WMA_LOGE("Disable Forced Sleep Failed vdevId %d", vdev_id); + return; + } +} + +/** + * wma_set_sta_uapsd_auto_trig_cmd() - set uapsd auto trigger command + * @wmi_handle: wma handle + * @vdevid: vdev id + * @peer_addr: peer mac address + * @autoTriggerparam: auto trigger parameters + * @num_ac: number of access category + * + * This function sets the trigger + * uapsd params such as service interval, delay interval + * and suspend interval which will be used by the firmware + * to send trigger frames periodically when there is no + * traffic on the transmit side. + * + * Return: 0 for success or error code. + */ +static QDF_STATUS wma_set_sta_uapsd_auto_trig_cmd(wmi_unified_t wmi_handle, + uint32_t vdevid, + uint8_t peer_addr[IEEE80211_ADDR_LEN], + uint8_t *autoTriggerparam, + uint32_t num_ac) +{ + QDF_STATUS ret; + struct sta_uapsd_trig_params cmd = {0}; + + cmd.vdevid = vdevid; + cmd.auto_triggerparam = autoTriggerparam; + cmd.num_ac = num_ac; + + qdf_mem_copy((uint8_t *) cmd.peer_addr, (uint8_t *) peer_addr, + sizeof(uint8_t) * IEEE80211_ADDR_LEN); + ret = wmi_unified_set_sta_uapsd_auto_trig_cmd(wmi_handle, + &cmd); + if (QDF_IS_STATUS_ERROR(ret)) + WMA_LOGE("Failed to send set uapsd param ret = %d", ret); + + return ret; +} + +/** + * wma_trigger_uapsd_params() - set trigger uapsd parameter + * @wmi_handle: wma handle + * @vdev_id: vdev id + * @trigger_uapsd_params: trigger uapsd parameters + * + * This function sets the trigger uapsd + * params such as service interval, delay + * interval and suspend interval which + * will be used by the firmware to send + * trigger frames periodically when there + * is no traffic on the transmit side. + * + * Return: QDF_STATUS_SUCCESS for success or error code. + */ +QDF_STATUS wma_trigger_uapsd_params(tp_wma_handle wma_handle, uint32_t vdev_id, + tp_wma_trigger_uapsd_params + trigger_uapsd_params) +{ + QDF_STATUS ret; + wmi_sta_uapsd_auto_trig_param uapsd_trigger_param; + + WMA_LOGD("Trigger uapsd params vdev id %d", vdev_id); + + WMA_LOGD("WMM AC %d User Priority %d SvcIntv %d DelIntv %d SusIntv %d", + trigger_uapsd_params->wmm_ac, + trigger_uapsd_params->user_priority, + trigger_uapsd_params->service_interval, + trigger_uapsd_params->delay_interval, + trigger_uapsd_params->suspend_interval); + + if (!WMI_SERVICE_IS_ENABLED(wma_handle->wmi_service_bitmap, + WMI_STA_UAPSD_BASIC_AUTO_TRIG) || + !WMI_SERVICE_IS_ENABLED(wma_handle->wmi_service_bitmap, + WMI_STA_UAPSD_VAR_AUTO_TRIG)) { + WMA_LOGD("Trigger uapsd is not supported vdev id %d", vdev_id); + return QDF_STATUS_SUCCESS; + } + + uapsd_trigger_param.wmm_ac = trigger_uapsd_params->wmm_ac; + uapsd_trigger_param.user_priority = trigger_uapsd_params->user_priority; + uapsd_trigger_param.service_interval = + trigger_uapsd_params->service_interval; + uapsd_trigger_param.suspend_interval = + trigger_uapsd_params->suspend_interval; + uapsd_trigger_param.delay_interval = + trigger_uapsd_params->delay_interval; + + ret = wma_set_sta_uapsd_auto_trig_cmd(wma_handle->wmi_handle, + vdev_id, wma_handle->interfaces[vdev_id].bssid, + (uint8_t *) (&uapsd_trigger_param), 1); + if (QDF_IS_STATUS_ERROR(ret)) { + WMA_LOGE("Fail to send uapsd param cmd for vdevid %d ret = %d", + ret, vdev_id); + return ret; + } + + return ret; +} + +/** + * wma_disable_uapsd_per_ac() - disable uapsd per ac + * @wmi_handle: wma handle + * @vdev_id: vdev id + * @ac: access category + * + * Return: QDF_STATUS_SUCCESS for success or error code. + */ +QDF_STATUS wma_disable_uapsd_per_ac(tp_wma_handle wma_handle, + uint32_t vdev_id, enum uapsd_ac ac) +{ + QDF_STATUS ret; + struct wma_txrx_node *iface = &wma_handle->interfaces[vdev_id]; + wmi_sta_uapsd_auto_trig_param uapsd_trigger_param; + enum uapsd_up user_priority; + + WMA_LOGD("Disable Uapsd per ac vdevId %d ac %d", vdev_id, ac); + + switch (ac) { + case UAPSD_VO: + iface->uapsd_cached_val &= + ~(WMI_STA_PS_UAPSD_AC3_DELIVERY_EN | + WMI_STA_PS_UAPSD_AC3_TRIGGER_EN); + user_priority = UAPSD_UP_VO; + break; + case UAPSD_VI: + iface->uapsd_cached_val &= + ~(WMI_STA_PS_UAPSD_AC2_DELIVERY_EN | + WMI_STA_PS_UAPSD_AC2_TRIGGER_EN); + user_priority = UAPSD_UP_VI; + break; + case UAPSD_BK: + iface->uapsd_cached_val &= + ~(WMI_STA_PS_UAPSD_AC1_DELIVERY_EN | + WMI_STA_PS_UAPSD_AC1_TRIGGER_EN); + user_priority = UAPSD_UP_BK; + break; + case UAPSD_BE: + iface->uapsd_cached_val &= + ~(WMI_STA_PS_UAPSD_AC0_DELIVERY_EN | + WMI_STA_PS_UAPSD_AC0_TRIGGER_EN); + user_priority = UAPSD_UP_BE; + break; + default: + WMA_LOGE("Invalid AC vdevId %d ac %d", vdev_id, ac); + return QDF_STATUS_E_FAILURE; + } + + /* + * Disable Auto Trigger Functionality before + * disabling uapsd for a particular AC + */ + uapsd_trigger_param.wmm_ac = ac; + uapsd_trigger_param.user_priority = user_priority; + uapsd_trigger_param.service_interval = 0; + uapsd_trigger_param.suspend_interval = 0; + uapsd_trigger_param.delay_interval = 0; + + ret = wma_set_sta_uapsd_auto_trig_cmd(wma_handle->wmi_handle, + vdev_id, wma_handle->interfaces[vdev_id].bssid, + (uint8_t *)(&uapsd_trigger_param), 1); + if (QDF_IS_STATUS_ERROR(ret)) { + WMA_LOGE("Fail to send auto trig cmd for vdevid %d ret = %d", + ret, vdev_id); + return ret; + } + + ret = wma_unified_set_sta_ps_param(wma_handle->wmi_handle, vdev_id, + WMI_STA_PS_PARAM_UAPSD, + iface->uapsd_cached_val); + if (QDF_IS_STATUS_ERROR(ret)) { + WMA_LOGE("Disable Uapsd per ac Failed vdevId %d ac %d", vdev_id, + ac); + return ret; + } + WMA_LOGD("Disable Uapsd per ac vdevId %d val %d", vdev_id, + iface->uapsd_cached_val); + + return QDF_STATUS_SUCCESS; +} + +/** + * wma_get_temperature() - get pdev temperature req + * @wmi_handle: wma handle + * + * Return: QDF_STATUS_SUCCESS for success or error code. + */ +QDF_STATUS wma_get_temperature(tp_wma_handle wma_handle) +{ + QDF_STATUS ret = QDF_STATUS_SUCCESS; + + ret = wmi_unified_get_temperature(wma_handle->wmi_handle); + if (ret) + WMA_LOGE("Failed to send set Mimo PS ret = %d", ret); + + return ret; +} + +/** + * wma_pdev_temperature_evt_handler() - pdev temperature event handler + * @handle: wma handle + * @event: event buffer + * @len : length + * + * Return: 0 for success or error code. + */ +int wma_pdev_temperature_evt_handler(void *handle, uint8_t *event, + uint32_t len) +{ + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + cds_msg_t sme_msg = { 0 }; + WMI_PDEV_TEMPERATURE_EVENTID_param_tlvs *param_buf; + wmi_pdev_temperature_event_fixed_param *wmi_event; + + param_buf = (WMI_PDEV_TEMPERATURE_EVENTID_param_tlvs *) event; + if (!param_buf) { + WMA_LOGE("Invalid pdev_temperature event buffer"); + return -EINVAL; + } + + wmi_event = param_buf->fixed_param; + WMA_LOGI(FL("temperature: %d"), wmi_event->value); + + sme_msg.type = eWNI_SME_MSG_GET_TEMPERATURE_IND; + sme_msg.bodyptr = NULL; + sme_msg.bodyval = wmi_event->value; + + qdf_status = cds_mq_post_message(QDF_MODULE_ID_SME, &sme_msg); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + WMA_LOGE(FL("Fail to post get temperature ind msg")); + } + + return 0; +} + +/** + * wma_process_tx_power_limits() - sends the power limits for 2g/5g to firmware + * @handle: wma handle + * @ptxlim: power limit value + * + * Return: QDF_STATUS_SUCCESS for success or error code. + */ +QDF_STATUS wma_process_tx_power_limits(WMA_HANDLE handle, + tSirTxPowerLimit *ptxlim) +{ + tp_wma_handle wma = (tp_wma_handle) handle; + int32_t ret = 0; + uint32_t txpower_params2g = 0; + uint32_t txpower_params5g = 0; + struct pdev_params pdevparam; + + if (!wma || !wma->wmi_handle) { + WMA_LOGE("%s: WMA is closed, can not issue tx power limit", + __func__); + return QDF_STATUS_E_INVAL; + } + /* Set value and reason code for 2g and 5g power limit */ + + SET_PDEV_PARAM_TXPOWER_REASON(txpower_params2g, + WMI_PDEV_PARAM_TXPOWER_REASON_SAR); + SET_PDEV_PARAM_TXPOWER_VALUE(txpower_params2g, ptxlim->txPower2g); + + SET_PDEV_PARAM_TXPOWER_REASON(txpower_params5g, + WMI_PDEV_PARAM_TXPOWER_REASON_SAR); + SET_PDEV_PARAM_TXPOWER_VALUE(txpower_params5g, ptxlim->txPower5g); + + WMA_LOGD("%s: txpower2g: %x txpower5g: %x", + __func__, txpower_params2g, txpower_params5g); + + pdevparam.param_id = WMI_PDEV_PARAM_TXPOWER_LIMIT2G; + pdevparam.param_value = txpower_params2g; + ret = wmi_unified_pdev_param_send(wma->wmi_handle, + &pdevparam, + WMA_WILDCARD_PDEV_ID); + if (ret) { + WMA_LOGE("%s: Failed to set txpower 2g (%d)", __func__, ret); + return QDF_STATUS_E_FAILURE; + } + pdevparam.param_id = WMI_PDEV_PARAM_TXPOWER_LIMIT5G; + pdevparam.param_value = txpower_params5g; + ret = wmi_unified_pdev_param_send(wma->wmi_handle, + &pdevparam, + WMA_WILDCARD_PDEV_ID); + if (ret) { + WMA_LOGE("%s: Failed to set txpower 5g (%d)", __func__, ret); + return QDF_STATUS_E_FAILURE; + } + return QDF_STATUS_SUCCESS; +} + +/** + * wma_add_p2p_ie() - add p2p IE + * @frm: ptr where p2p ie needs to add + * + * Return: ptr after p2p ie + */ +static uint8_t *wma_add_p2p_ie(uint8_t *frm) +{ + uint8_t wfa_oui[3] = WMA_P2P_WFA_OUI; + struct p2p_ie *p2p_ie = (struct p2p_ie *)frm; + + p2p_ie->p2p_id = WMA_P2P_IE_ID; + p2p_ie->p2p_oui[0] = wfa_oui[0]; + p2p_ie->p2p_oui[1] = wfa_oui[1]; + p2p_ie->p2p_oui[2] = wfa_oui[2]; + p2p_ie->p2p_oui_type = WMA_P2P_WFA_VER; + p2p_ie->p2p_len = 4; + return frm + sizeof(struct p2p_ie); +} + +/** + * wma_update_beacon_noa_ie() - update beacon ie + * @bcn: beacon info + * @new_noa_sub_ie_len: ie length + * + * Return: none + */ +static void wma_update_beacon_noa_ie(struct beacon_info *bcn, + uint16_t new_noa_sub_ie_len) +{ + struct p2p_ie *p2p_ie; + uint8_t *buf; + + /* if there is nothing to add, just return */ + if (new_noa_sub_ie_len == 0) { + if (bcn->noa_sub_ie_len && bcn->noa_ie) { + WMA_LOGD("%s: NoA is present in previous beacon, " + "but not present in swba event, " + "So Reset the NoA", __func__); + /* TODO: Assuming p2p noa ie is last ie in the beacon */ + qdf_mem_zero(bcn->noa_ie, (bcn->noa_sub_ie_len + + sizeof(struct p2p_ie))); + bcn->len -= (bcn->noa_sub_ie_len + + sizeof(struct p2p_ie)); + bcn->noa_ie = NULL; + bcn->noa_sub_ie_len = 0; + } + WMA_LOGD("%s: No need to update NoA", __func__); + return; + } + + if (bcn->noa_sub_ie_len && bcn->noa_ie) { + /* NoA present in previous beacon, update it */ + WMA_LOGD("%s: NoA present in previous beacon, " + "update the NoA IE, bcn->len %u" + "bcn->noa_sub_ie_len %u", + __func__, bcn->len, bcn->noa_sub_ie_len); + bcn->len -= (bcn->noa_sub_ie_len + sizeof(struct p2p_ie)); + qdf_mem_zero(bcn->noa_ie, + (bcn->noa_sub_ie_len + sizeof(struct p2p_ie))); + } else { /* NoA is not present in previous beacon */ + WMA_LOGD("%s: NoA not present in previous beacon, add it" + "bcn->len %u", __func__, bcn->len); + buf = qdf_nbuf_data(bcn->buf); + bcn->noa_ie = buf + bcn->len; + } + + bcn->noa_sub_ie_len = new_noa_sub_ie_len; + wma_add_p2p_ie(bcn->noa_ie); + p2p_ie = (struct p2p_ie *)bcn->noa_ie; + p2p_ie->p2p_len += new_noa_sub_ie_len; + qdf_mem_copy((bcn->noa_ie + sizeof(struct p2p_ie)), bcn->noa_sub_ie, + new_noa_sub_ie_len); + + bcn->len += (new_noa_sub_ie_len + sizeof(struct p2p_ie)); + WMA_LOGI("%s: Updated beacon length with NoA Ie is %u", + __func__, bcn->len); +} + +/** + * wma_p2p_create_sub_ie_noa() - put p2p noa ie + * @buf: buffer + * @noa: noa element ie + * @new_noa_sub_ie_len: ie length + * + * Return: none + */ +static void wma_p2p_create_sub_ie_noa(uint8_t *buf, + struct p2p_sub_element_noa *noa, + uint16_t *new_noa_sub_ie_len) +{ + uint8_t tmp_octet = 0; + int i; + uint8_t *buf_start = buf; + + *buf++ = WMA_P2P_SUB_ELEMENT_NOA; /* sub-element id */ + ASSERT(noa->num_descriptors <= WMA_MAX_NOA_DESCRIPTORS); + + /* + * Length = (2 octets for Index and CTWin/Opp PS) and + * (13 octets for each NOA Descriptors) + */ + P2PIE_PUT_LE16(buf, WMA_NOA_IE_SIZE(noa->num_descriptors)); + buf += 2; + + *buf++ = noa->index; /* Instance Index */ + + tmp_octet = noa->ctwindow & WMA_P2P_NOA_IE_CTWIN_MASK; + if (noa->oppPS) { + tmp_octet |= WMA_P2P_NOA_IE_OPP_PS_SET; + } + *buf++ = tmp_octet; /* Opp Ps and CTWin capabilities */ + + for (i = 0; i < noa->num_descriptors; i++) { + ASSERT(noa->noa_descriptors[i].type_count != 0); + + *buf++ = noa->noa_descriptors[i].type_count; + + P2PIE_PUT_LE32(buf, noa->noa_descriptors[i].duration); + buf += 4; + P2PIE_PUT_LE32(buf, noa->noa_descriptors[i].interval); + buf += 4; + P2PIE_PUT_LE32(buf, noa->noa_descriptors[i].start_time); + buf += 4; + } + *new_noa_sub_ie_len = (buf - buf_start); +} + +/** + * wma_update_noa() - update noa params + * @beacon: beacon info + * @noa_ie: noa ie + * + * Return: none + */ +void wma_update_noa(struct beacon_info *beacon, + struct p2p_sub_element_noa *noa_ie) +{ + uint16_t new_noa_sub_ie_len; + + /* Call this function by holding the spinlock on beacon->lock */ + + if (noa_ie) { + if ((noa_ie->ctwindow == 0) && (noa_ie->oppPS == 0) && + (noa_ie->num_descriptors == 0)) { + /* NoA is not present */ + WMA_LOGD("%s: NoA is not present", __func__); + new_noa_sub_ie_len = 0; + } else { + /* Create the binary blob containing NOA sub-IE */ + WMA_LOGD("%s: Create NOA sub ie", __func__); + wma_p2p_create_sub_ie_noa(&beacon->noa_sub_ie[0], + noa_ie, &new_noa_sub_ie_len); + } + } else { + WMA_LOGD("%s: No need to add NOA", __func__); + new_noa_sub_ie_len = 0; /* no NOA IE sub-attributes */ + } + + wma_update_beacon_noa_ie(beacon, new_noa_sub_ie_len); +} + +/** + * wma_update_probe_resp_noa() - update noa IE in probe response + * @wma_handle: wma handle + * @noa_ie: noa ie + * + * Return: none + */ +void wma_update_probe_resp_noa(tp_wma_handle wma_handle, + struct p2p_sub_element_noa *noa_ie) +{ + tSirP2PNoaAttr *noa_attr = + (tSirP2PNoaAttr *) qdf_mem_malloc(sizeof(tSirP2PNoaAttr)); + WMA_LOGD("Received update NoA event"); + if (!noa_attr) { + WMA_LOGE("Failed to allocate memory for tSirP2PNoaAttr"); + return; + } + + qdf_mem_zero(noa_attr, sizeof(tSirP2PNoaAttr)); + + noa_attr->index = noa_ie->index; + noa_attr->oppPsFlag = noa_ie->oppPS; + noa_attr->ctWin = noa_ie->ctwindow; + if (!noa_ie->num_descriptors) { + WMA_LOGD("Zero NoA descriptors"); + } else { + WMA_LOGD("%d NoA descriptors", noa_ie->num_descriptors); + noa_attr->uNoa1IntervalCnt = + noa_ie->noa_descriptors[0].type_count; + noa_attr->uNoa1Duration = noa_ie->noa_descriptors[0].duration; + noa_attr->uNoa1Interval = noa_ie->noa_descriptors[0].interval; + noa_attr->uNoa1StartTime = + noa_ie->noa_descriptors[0].start_time; + if (noa_ie->num_descriptors > 1) { + noa_attr->uNoa2IntervalCnt = + noa_ie->noa_descriptors[1].type_count; + noa_attr->uNoa2Duration = + noa_ie->noa_descriptors[1].duration; + noa_attr->uNoa2Interval = + noa_ie->noa_descriptors[1].interval; + noa_attr->uNoa2StartTime = + noa_ie->noa_descriptors[1].start_time; + } + } + WMA_LOGI("Sending SIR_HAL_P2P_NOA_ATTR_IND to LIM"); + wma_send_msg(wma_handle, SIR_HAL_P2P_NOA_ATTR_IND, (void *)noa_attr, 0); +} + +/** + * wma_p2p_noa_event_handler() - p2p noa event handler + * @handle: wma handle + * @event: event data + * @len: length + * + * Return: 0 for success or error code. + */ +int wma_p2p_noa_event_handler(void *handle, uint8_t *event, + uint32_t len) +{ + tp_wma_handle wma = (tp_wma_handle) handle; + WMI_P2P_NOA_EVENTID_param_tlvs *param_buf; + wmi_p2p_noa_event_fixed_param *p2p_noa_event; + uint8_t vdev_id, i; + wmi_p2p_noa_info *p2p_noa_info; + struct p2p_sub_element_noa noa_ie; + uint8_t *buf_ptr; + uint32_t descriptors; + + param_buf = (WMI_P2P_NOA_EVENTID_param_tlvs *) event; + if (!param_buf) { + WMA_LOGE("Invalid P2P NoA event buffer"); + return -EINVAL; + } + + p2p_noa_event = param_buf->fixed_param; + buf_ptr = (uint8_t *) p2p_noa_event; + buf_ptr += sizeof(wmi_p2p_noa_event_fixed_param); + p2p_noa_info = (wmi_p2p_noa_info *) (buf_ptr); + vdev_id = p2p_noa_event->vdev_id; + + if (WMI_UNIFIED_NOA_ATTR_IS_MODIFIED(p2p_noa_info)) { + + qdf_mem_zero(&noa_ie, sizeof(noa_ie)); + noa_ie.index = + (uint8_t) WMI_UNIFIED_NOA_ATTR_INDEX_GET(p2p_noa_info); + noa_ie.oppPS = + (uint8_t) WMI_UNIFIED_NOA_ATTR_OPP_PS_GET(p2p_noa_info); + noa_ie.ctwindow = + (uint8_t) WMI_UNIFIED_NOA_ATTR_CTWIN_GET(p2p_noa_info); + descriptors = WMI_UNIFIED_NOA_ATTR_NUM_DESC_GET(p2p_noa_info); + noa_ie.num_descriptors = (uint8_t) descriptors; + + WMA_LOGI("%s: index %u, oppPs %u, ctwindow %u, " + "num_descriptors = %u", __func__, noa_ie.index, + noa_ie.oppPS, noa_ie.ctwindow, noa_ie.num_descriptors); + for (i = 0; i < noa_ie.num_descriptors; i++) { + noa_ie.noa_descriptors[i].type_count = + (uint8_t) p2p_noa_info->noa_descriptors[i]. + type_count; + noa_ie.noa_descriptors[i].duration = + p2p_noa_info->noa_descriptors[i].duration; + noa_ie.noa_descriptors[i].interval = + p2p_noa_info->noa_descriptors[i].interval; + noa_ie.noa_descriptors[i].start_time = + p2p_noa_info->noa_descriptors[i].start_time; + WMA_LOGI("%s: NoA descriptor[%d] type_count %u, " + "duration %u, interval %u, start_time = %u", + __func__, i, + noa_ie.noa_descriptors[i].type_count, + noa_ie.noa_descriptors[i].duration, + noa_ie.noa_descriptors[i].interval, + noa_ie.noa_descriptors[i].start_time); + } + + /* Send a msg to LIM to update the NoA IE in probe response + * frames transmitted by the host */ + wma_update_probe_resp_noa(wma, &noa_ie); + } + + return 0; +} + +/** + * wma_set_p2pgo_noa_req() - send p2p go noa request to fw + * @wma: wma handle + * @noa: p2p power save parameters + * + * Return: none + */ +static void wma_set_p2pgo_noa_req(tp_wma_handle wma, tP2pPsParams *noa) +{ + QDF_STATUS ret; + struct p2p_ps_params cmd = {0}; + + cmd.opp_ps = noa->opp_ps; + cmd.ctwindow = noa->ctWindow; + cmd.count = noa->count; + cmd.duration = noa->duration; + cmd.interval = noa->interval; + cmd.single_noa_duration = noa->single_noa_duration; + cmd.ps_selection = noa->psSelection; + cmd.session_id = noa->sessionId; + + ret = wmi_unified_set_p2pgo_noa_req_cmd(wma->wmi_handle, + &cmd); + if (QDF_IS_STATUS_ERROR(ret)) + WMA_LOGE("Failed to send set uapsd param ret = %d", ret); + + return; +} + +/** + * wma_set_p2pgo_oppps_req() - send p2p go opp power save request to fw + * @wma: wma handle + * @noa: p2p opp power save parameters + * + * Return: none + */ +static void wma_set_p2pgo_oppps_req(tp_wma_handle wma, tP2pPsParams *oppps) +{ + QDF_STATUS ret; + struct p2p_ps_params cmd = {0}; + + cmd.opp_ps = oppps->opp_ps; + cmd.ctwindow = oppps->ctWindow; + cmd.count = oppps->count; + cmd.duration = oppps->duration; + cmd.interval = oppps->interval; + cmd.single_noa_duration = oppps->single_noa_duration; + cmd.ps_selection = oppps->psSelection; + cmd.session_id = oppps->sessionId; + + ret = wmi_unified_set_p2pgo_oppps_req(wma->wmi_handle, + &cmd); + if (QDF_IS_STATUS_ERROR(ret)) + WMA_LOGE("Failed to send set uapsd param ret = %d", ret); + + return; +} + +/** + * wma_process_set_p2pgo_noa_req() - process p2pgo noa request + * @handle: wma handle + * @ps_params: powersave params + * + * Return: none + */ +void wma_process_set_p2pgo_noa_req(tp_wma_handle wma, + tP2pPsParams *ps_params) +{ + WMA_LOGD("%s: Enter", __func__); + if (ps_params->opp_ps) { + wma_set_p2pgo_oppps_req(wma, ps_params); + } else { + wma_set_p2pgo_noa_req(wma, ps_params); + } + + WMA_LOGD("%s: Exit", __func__); +} + +/** + * wma_process_set_mimops_req() - Set the received MiMo PS state to firmware + * @handle: wma handle + * @mimops: MIMO powersave params + * + * Return: none + */ +void wma_process_set_mimops_req(tp_wma_handle wma_handle, + tSetMIMOPS *mimops) +{ + /* Translate to what firmware understands */ + if (mimops->htMIMOPSState == eSIR_HT_MIMO_PS_DYNAMIC) + mimops->htMIMOPSState = WMI_PEER_MIMO_PS_DYNAMIC; + else if (mimops->htMIMOPSState == eSIR_HT_MIMO_PS_STATIC) + mimops->htMIMOPSState = WMI_PEER_MIMO_PS_STATIC; + else if (mimops->htMIMOPSState == eSIR_HT_MIMO_PS_NO_LIMIT) + mimops->htMIMOPSState = WMI_PEER_MIMO_PS_NONE; + + WMA_LOGD("%s: htMIMOPSState = %d, sessionId = %d peerMac <%02x:%02x:%02x:%02x:%02x:%02x>", + __func__, + mimops->htMIMOPSState, mimops->sessionId, mimops->peerMac[0], + mimops->peerMac[1], mimops->peerMac[2], mimops->peerMac[3], + mimops->peerMac[4], mimops->peerMac[5]); + + wma_set_peer_param(wma_handle, mimops->peerMac, + WMI_PEER_MIMO_PS_STATE, mimops->htMIMOPSState, + mimops->sessionId); +} + +/** + * wma_set_mimops() - set MIMO powersave + * @handle: wma handle + * @vdev_id: vdev id + * @value: value + * + * Return: QDF_STATUS_SUCCESS for success or error code. + */ +QDF_STATUS wma_set_mimops(tp_wma_handle wma, uint8_t vdev_id, int value) +{ + QDF_STATUS ret; + + ret = wmi_unified_set_mimops(wma->wmi_handle, vdev_id, + value); + if (QDF_IS_STATUS_ERROR(ret)) + WMA_LOGE("Failed to send set Mimo PS ret = %d", ret); + + return ret; +} + +/** + * wma_notify_modem_power_state() - notify modem power state + * @wma_ptr: wma handle + * @pReq: modem power state + * + * Return: QDF_STATUS_SUCCESS for success or error code. + */ +QDF_STATUS wma_notify_modem_power_state(void *wma_ptr, + tSirModemPowerStateInd *pReq) +{ + int32_t ret; + tp_wma_handle wma = (tp_wma_handle) wma_ptr; + + WMA_LOGD("%s: WMA notify Modem Power State %d", __func__, pReq->param); + + ret = wma_unified_modem_power_state(wma->wmi_handle, pReq->param); + if (ret) { + WMA_LOGE("%s: Fail to notify Modem Power State %d", + __func__, pReq->param); + return QDF_STATUS_E_FAILURE; + } + + WMA_LOGD("Successfully notify Modem Power State %d", pReq->param); + return QDF_STATUS_SUCCESS; +} + +/** + * wma_set_idle_ps_config() - enable/disble Low Power Support(Pdev Specific) + * @wma_ptr: wma handle + * @idle_ps: idle powersave + * + * Return: QDF_STATUS_SUCCESS for success or error code. + */ +QDF_STATUS wma_set_idle_ps_config(void *wma_ptr, uint32_t idle_ps) +{ + int32_t ret; + tp_wma_handle wma = (tp_wma_handle) wma_ptr; + struct pdev_params pdevparam; + + WMA_LOGD("WMA Set Idle Ps Config [1:set 0:clear] val %d", idle_ps); + + /* Set Idle Mode Power Save Config */ + pdevparam.param_id = WMI_PDEV_PARAM_IDLE_PS_CONFIG; + pdevparam.param_value = idle_ps; + ret = wmi_unified_pdev_param_send(wma->wmi_handle, + &pdevparam, + WMA_WILDCARD_PDEV_ID); + + if (ret) { + WMA_LOGE("Fail to Set Idle Ps Config %d", idle_ps); + return QDF_STATUS_E_FAILURE; + } + wma->in_imps = idle_ps; + + WMA_LOGD("Successfully Set Idle Ps Config %d", idle_ps); + return QDF_STATUS_SUCCESS; +} + +/** + * wma_set_smps_params() - set smps params + * @wma: wma handle + * @vdev_id: vdev id + * @value: value + * + * Return: QDF_STATUS_SUCCESS for success or error code. + */ +QDF_STATUS wma_set_smps_params(tp_wma_handle wma, uint8_t vdev_id, + int value) +{ + QDF_STATUS ret; + + ret = wmi_unified_set_smps_params(wma->wmi_handle, vdev_id, + value); + if (QDF_IS_STATUS_ERROR(ret)) + WMA_LOGE("Failed to send set Mimo PS ret = %d", ret); + + return ret; +} + +/** + * wma_set_vdev_suspend_dtim() - set suspend dtim parameters in fw + * @wma: wma handle + * @vdev_id: vdev id + * + * Return: none + */ +static void wma_set_vdev_suspend_dtim(tp_wma_handle wma, uint8_t vdev_id) +{ + struct wma_txrx_node *iface = &wma->interfaces[vdev_id]; + uint32_t cfg_data_val = 0; + + if ((iface->type == WMI_VDEV_TYPE_STA) && + (iface->dtimPeriod != 0)) { + QDF_STATUS ret; + uint32_t listen_interval; + uint32_t max_mod_dtim; + uint32_t beacon_interval_mod; + + /* get mac to acess CFG data base */ + struct sAniSirGlobal *mac = cds_get_context(QDF_MODULE_ID_PE); + if (!mac) { + WMA_LOGE(FL("Failed to get mac context")); + return; + } + + if (wma->staDynamicDtim) { + listen_interval = wma->staDynamicDtim; + } else if ((wma->staModDtim) && + (wma->staMaxLIModDtim)) { + /* + * When the system is in suspend + * (maximum beacon will be at 1s == 10) + * If maxModulatedDTIM ((MAX_LI_VAL = 10) / AP_DTIM) + * equal or larger than MDTIM + * (configured in WCNSS_qcom_cfg.ini) + * Set LI to MDTIM * AP_DTIM + * If Dtim = 2 and Mdtim = 2 then LI is 4 + * Else + * Set LI to maxModulatedDTIM * AP_DTIM + */ + + beacon_interval_mod = iface->beaconInterval / 100; + if (beacon_interval_mod == 0) + beacon_interval_mod = 1; + + max_mod_dtim = wma->staMaxLIModDtim + / (iface->dtimPeriod*beacon_interval_mod); + + if (max_mod_dtim <= 0) + max_mod_dtim = 1; + + if (max_mod_dtim >= wma->staModDtim) { + listen_interval = + (wma->staModDtim * iface->dtimPeriod); + } else { + listen_interval = + (max_mod_dtim * iface->dtimPeriod); + } + } else { + /* Set Listen Interval */ + if ((wlan_cfg_get_int(mac, WNI_CFG_LISTEN_INTERVAL, + &cfg_data_val) != eSIR_SUCCESS)) { + QDF_TRACE(QDF_MODULE_ID_WMA, + QDF_TRACE_LEVEL_ERROR, + "Failed to listen interval"); + cfg_data_val = + POWERSAVE_DEFAULT_LISTEN_INTERVAL; + } + listen_interval = cfg_data_val; + } + ret = wma_vdev_set_param(wma->wmi_handle, vdev_id, + WMI_VDEV_PARAM_LISTEN_INTERVAL, + listen_interval); + if (QDF_IS_STATUS_ERROR(ret)) { + /* Even it fails continue Fw will take default LI */ + WMA_LOGE("Failed to Set Listen Interval vdevId %d", + vdev_id); + } + + WMA_LOGD("Set Listen Interval vdevId %d Listen Intv %d", + vdev_id, listen_interval); + + if (wlan_cfg_get_int(mac, + WNI_CFG_PS_WOW_DATA_INACTIVITY_TIMEOUT, + &cfg_data_val) != eSIR_SUCCESS) { + QDF_TRACE(QDF_MODULE_ID_WMA, QDF_TRACE_LEVEL_ERROR, + "Can't get WNI_CFG_PS_WOW_DATA_INACTIVITY_TO"); + cfg_data_val = WOW_POWERSAVE_DEFAULT_INACTIVITY_TIME; + } + + WMA_LOGD("%s: Set inactivity_time for wow: %d", __func__, + cfg_data_val); + ret = wma_unified_set_sta_ps_param(wma->wmi_handle, vdev_id, + WMI_STA_PS_PARAM_INACTIVITY_TIME, cfg_data_val); + if (ret) + WMA_LOGE("%s: Setting InActivity time Failed.", + __func__); + + WMA_LOGD("%s: Set the Tx Wake Threshold 0.", __func__); + ret = wma_unified_set_sta_ps_param( + wma->wmi_handle, vdev_id, + WMI_STA_PS_PARAM_TX_WAKE_THRESHOLD, + WMI_STA_PS_TX_WAKE_THRESHOLD_NEVER); + if (ret) + WMA_LOGE("%s: Setting TxWake Threshold Failed.", + __func__); + + iface->restore_dtim_setting = true; + } +} + +/** + * wma_set_suspend_dtim() - set suspend dtim + * @wma: wma handle + * + * Return: none + */ +void wma_set_suspend_dtim(tp_wma_handle wma) +{ + uint8_t i; + + if (NULL == wma) { + WMA_LOGE("%s: wma is NULL", __func__); + return; + } + + for (i = 0; i < wma->max_bssid; i++) { + if ((wma->interfaces[i].handle) && + (false == wma->interfaces[i].alt_modulated_dtim_enabled)) { + wma_set_vdev_suspend_dtim(wma, i); + } + } +} + +/** + * wma_set_vdev_resume_dtim() - set resume dtim parameters in fw + * @wma: wma handle + * @vdev_id: vdev id + * + * Return: none + */ +static void wma_set_vdev_resume_dtim(tp_wma_handle wma, uint8_t vdev_id) +{ + struct wma_txrx_node *iface = &wma->interfaces[vdev_id]; + u_int32_t inactivity_time; + uint8_t ito_repeat_count_value = 0; + + if ((iface->type == WMI_VDEV_TYPE_STA) && + (iface->restore_dtim_setting)) { + QDF_STATUS ret; + uint32_t cfg_data_val = 0; + /* get mac to acess CFG data base */ + struct sAniSirGlobal *mac = cds_get_context(QDF_MODULE_ID_PE); + if (!mac) { + WMA_LOGE(FL("Failed to get mac context")); + return; + } + /* Set Listen Interval */ + if ((wlan_cfg_get_int(mac, WNI_CFG_LISTEN_INTERVAL, + &cfg_data_val) != eSIR_SUCCESS)) { + QDF_TRACE(QDF_MODULE_ID_WMA, QDF_TRACE_LEVEL_ERROR, + "Failed to get value for listen interval"); + cfg_data_val = POWERSAVE_DEFAULT_LISTEN_INTERVAL; + } + + ret = wma_vdev_set_param(wma->wmi_handle, vdev_id, + WMI_VDEV_PARAM_LISTEN_INTERVAL, + cfg_data_val); + if (QDF_IS_STATUS_ERROR(ret)) { + /* Even it fails continue Fw will take default LI */ + WMA_LOGE("Failed to Set Listen Interval vdevId %d", + vdev_id); + } + + WMA_LOGD("Set Listen Interval vdevId %d Listen Intv %d", + vdev_id, cfg_data_val); + + if (wlan_cfg_get_int(mac, WNI_CFG_PS_DATA_INACTIVITY_TIMEOUT, + &cfg_data_val) != eSIR_SUCCESS) { + QDF_TRACE(QDF_MODULE_ID_WMA, QDF_TRACE_LEVEL_ERROR, + "Failed to get WNI_CFG_PS_DATA_INACTIVITY_TIMEOUT"); + cfg_data_val = POWERSAVE_DEFAULT_INACTIVITY_TIME; + } + + iface->restore_dtim_setting = false; + inactivity_time = (u_int32_t)cfg_data_val; + WMA_LOGD("%s: Setting InActivity time %d.", __func__, + inactivity_time); + ret = wma_unified_set_sta_ps_param(wma->wmi_handle, vdev_id, + WMI_STA_PS_PARAM_INACTIVITY_TIME, + inactivity_time); + if (ret) + WMA_LOGE("%s: Setting InActivity time Failed.", + __func__); + + if (wlan_cfg_get_int(mac, + WNI_CFG_PS_WOW_DATA_INACTIVITY_TIMEOUT, + &cfg_data_val) != eSIR_SUCCESS) { + QDF_TRACE(QDF_MODULE_ID_WMA, QDF_TRACE_LEVEL_ERROR, + "Failed to get WOW_DATA_INACTIVITY_TIMEOUT"); + cfg_data_val = WOW_POWERSAVE_DEFAULT_INACTIVITY_TIME; + } + + ito_repeat_count_value = (inactivity_time / cfg_data_val) * + wma->ito_repeat_count; + + if (ito_repeat_count_value) { + ret = + wma_unified_set_sta_ps_param(wma->wmi_handle, + vdev_id, + WMI_STA_PS_PARAM_MAX_RESET_ITO_COUNT_ON_TIM_NO_TXRX, + ito_repeat_count_value); + WMA_LOGD("%s: Setting ito_repeat_count_value %d.", __func__, + ito_repeat_count_value); + + if (ret) + WMA_LOGE("%s: Setting ITO count failed.", __func__); + } + + if (wlan_cfg_get_int(mac, WNI_CFG_MAX_PS_POLL, + &cfg_data_val) != eSIR_SUCCESS) { + QDF_TRACE(QDF_MODULE_ID_WMA, + QDF_TRACE_LEVEL_ERROR, + "Failed to get value for WNI_CFG_MAX_PS_POLL"); + cfg_data_val = 0; + } + + /* + * Recover the Tx Wake Threshold + * 1, do not recover the value, because driver sets + * WMI_STA_PS_TX_WAKE_THRESHOLD_NEVER before suspend, + * 2, recover the value, because driver sets + * WMI_STA_PS_TX_WAKE_THRESHOLD_ALWAYS before suspend, + * 3, recover the value WMI_STA_PS_TX_WAKE_THRESHOLD_ALWAYS, + * which is defined by fw as default and driver does + * not set it when psSetting is eSIR_ADDON_DISABLE_UAPSD. + */ + if ((eSIR_ADDON_DISABLE_UAPSD == wma->ps_setting) + || ((eSIR_ADDON_NOTHING == wma->ps_setting) + && (!cfg_data_val))) { + WMA_LOGD("%s: Set the Tx Wake Threshold.", __func__); + ret = wma_unified_set_sta_ps_param( + wma->wmi_handle, vdev_id, + WMI_STA_PS_PARAM_TX_WAKE_THRESHOLD, + WMI_STA_PS_TX_WAKE_THRESHOLD_ALWAYS); + if (ret) + WMA_LOGE("Setting TxWake Threshold vdevId %d", + vdev_id); + } + } +} + +/** + * wma_set_resume_dtim() - set resume dtim + * @wma: wma handle + * + * Return: none + */ +void wma_set_resume_dtim(tp_wma_handle wma) +{ + uint8_t i; + + if (NULL == wma) { + WMA_LOGE("%s: wma is NULL", __func__); + return; + } + + for (i = 0; i < wma->max_bssid; i++) { + if ((wma->interfaces[i].handle) && + (false == wma->interfaces[i].alt_modulated_dtim_enabled)) { + wma_set_vdev_resume_dtim(wma, i); + } + } +} + +/** + * wma_set_tx_power_scale() - set tx power scale + * @vdev_id: vdev id + * @value: value + * + * Return: QDF_STATUS_SUCCESS for success or error code. + */ +QDF_STATUS wma_set_tx_power_scale(uint8_t vdev_id, int value) +{ + QDF_STATUS ret; + tp_wma_handle wma_handle = + (tp_wma_handle)cds_get_context(QDF_MODULE_ID_WMA); + + if (NULL == wma_handle) { + WMA_LOGE("%s: wma_handle is NULL", __func__); + return QDF_STATUS_E_FAILURE; + } + + if (!(wma_handle->interfaces[vdev_id].vdev_up)) { + WMA_LOGE("%s: vdev id %d is not up", __func__, vdev_id); + return QDF_STATUS_E_FAILURE; + } + + ret = wma_vdev_set_param(wma_handle->wmi_handle, vdev_id, + WMI_VDEV_PARAM_TXPOWER_SCALE, value); + if (QDF_IS_STATUS_ERROR(ret)) + WMA_LOGE("Set tx power scale failed"); + + return ret; +} + +/** + * wma_set_tx_power_scale_decr_db() - decrease power by DB value + * @vdev_id: vdev id + * @value: value + * + * Return: QDF_STATUS_SUCCESS for success or error code. + */ +QDF_STATUS wma_set_tx_power_scale_decr_db(uint8_t vdev_id, int value) +{ + QDF_STATUS ret; + tp_wma_handle wma_handle = + (tp_wma_handle)cds_get_context(QDF_MODULE_ID_WMA); + + if (NULL == wma_handle) { + WMA_LOGE("%s: wma_handle is NULL", __func__); + return QDF_STATUS_E_FAILURE; + } + + if (!(wma_handle->interfaces[vdev_id].vdev_up)) { + WMA_LOGE("%s: vdev id %d is not up", __func__, vdev_id); + return QDF_STATUS_E_FAILURE; + } + + ret = wma_vdev_set_param(wma_handle->wmi_handle, vdev_id, + WMI_VDEV_PARAM_TXPOWER_SCALE_DECR_DB, value); + if (QDF_IS_STATUS_ERROR(ret)) + WMA_LOGE("Decrease tx power value failed"); + + return ret; +} diff --git a/drivers/staging/qcacld-3.0/core/wma/src/wma_scan_roam.c b/drivers/staging/qcacld-3.0/core/wma/src/wma_scan_roam.c new file mode 100644 index 0000000000000000000000000000000000000000..bcac65870040ca7aac94c8f4d004ea4cc841eacc --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/wma/src/wma_scan_roam.c @@ -0,0 +1,6087 @@ +/* + * Copyright (c) 2013-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: wma_scan_roam.c + * This file contains functions related to scan and + * roaming functionality. + */ + +/* Header files */ + +#include "wma.h" +#include "wma_api.h" +#include "cds_api.h" +#include "wmi_unified_api.h" +#include "wlan_qct_sys.h" +#include "wni_api.h" +#include "ani_global.h" +#include "wmi_unified.h" +#include "wni_cfg.h" +#include "cfg_api.h" +#include +#include + +#include "qdf_nbuf.h" +#include "qdf_types.h" +#include "qdf_mem.h" +#include "ol_txrx_peer_find.h" +#include "ol_htt_api.h" + +#include "wma_types.h" +#include "lim_api.h" +#include "lim_session_utils.h" + +#include "cds_utils.h" +#include "cds_concurrency.h" + +#if !defined(REMOVE_PKT_LOG) +#include "pktlog_ac.h" +#endif /* REMOVE_PKT_LOG */ + +#include "dbglog_host.h" +/* FIXME: Inclusion of .c looks odd but this is how it is in internal codebase */ +#include "csr_api.h" +#include "ol_fw.h" + +#include "dfs.h" +#include "wma_internal.h" + +#define WMA_MCC_MIRACAST_REST_TIME 400 +#define WMA_SCAN_ID_MASK 0x0fff + +#ifdef FEATURE_WLAN_EXTSCAN +/** + * enum extscan_report_events_type - extscan report events type + * @EXTSCAN_REPORT_EVENTS_BUFFER_FULL: report only when scan history is % full + * @EXTSCAN_REPORT_EVENTS_EACH_SCAN: report a scan completion event after scan + * @EXTSCAN_REPORT_EVENTS_FULL_RESULTS: forward scan results + * (beacons/probe responses + IEs) + * in real time to HAL, in addition to completion events. + * Note: To keep backward compatibility, + * fire completion events regardless of REPORT_EVENTS_EACH_SCAN. + * @EXTSCAN_REPORT_EVENTS_NO_BATCH: controls batching, + * 0 => batching, 1 => no batching + * @EXTSCAN_REPORT_EVENTS_CONTEXT_HUB: forward results to context hub + */ +enum extscan_report_events_type { + EXTSCAN_REPORT_EVENTS_BUFFER_FULL = 0x00, + EXTSCAN_REPORT_EVENTS_EACH_SCAN = 0x01, + EXTSCAN_REPORT_EVENTS_FULL_RESULTS = 0x02, + EXTSCAN_REPORT_EVENTS_NO_BATCH = 0x04, + EXTSCAN_REPORT_EVENTS_CONTEXT_HUB = 0x08, +}; + +#define WMA_EXTSCAN_CYCLE_WAKE_LOCK_DURATION (5 * 1000) /* in msec */ +#endif + +/** + * wma_is_mcc_24G() - check that if device is in 2.4GHz MCC + * @handle: wma handle + * + * Return: true/false + */ +static bool wma_is_mcc_24G(WMA_HANDLE handle) +{ + tp_wma_handle wma_handle = (tp_wma_handle) handle; + int32_t prev_chan = 0; + int32_t i; + + if (NULL == wma_handle) { + WMA_LOGE("%s: wma_handle is NULL", __func__); + return false; + } + for (i = 0; i < wma_handle->max_bssid; i++) { + if (wma_handle->interfaces[i].handle && + wma_handle->interfaces[i].vdev_up) { + if ((prev_chan != 0 && + prev_chan != wma_handle->interfaces[i].mhz) && + (wma_handle->interfaces[i].mhz <= + CDS_CHAN_14_FREQ)) + return true; + else + prev_chan = wma_handle->interfaces[i].mhz; + } + } + return false; +} + +/** + * wma_get_buf_start_scan_cmd() - Fill start scan command + * @wma_handle: wma handle + * @scan_req: scan request + * @cmd: wmi buffer to be filled in + * + * Fill individual elements of wmi_start_scan_req and TLV for + * channel list, bssid, ssid etc. + * + * Return: QDF status + */ +QDF_STATUS wma_get_buf_start_scan_cmd(tp_wma_handle wma_handle, + tSirScanOffloadReq *scan_req, + struct scan_start_params *cmd) +{ + QDF_STATUS qdf_status = QDF_STATUS_E_FAILURE; + uint32_t dwell_time; + uint8_t SSID_num; + int i; + tpAniSirGlobal pMac = cds_get_context(QDF_MODULE_ID_PE); + + if (!pMac) { + WMA_LOGP("%s: pMac is NULL!", __func__); + return QDF_STATUS_E_FAILURE; + } + + cmd->vdev_id = scan_req->sessionId; + /* + * host cycles through the lower 12 bits for scan id generation + * and prefix 0xA000 to scan id + */ + if (scan_req->scan_id < WMA_HOST_SCAN_REQID_PREFIX) { + WMA_LOGE("Received scan_id 0x%x is wrong", + cmd->scan_id); + scan_req->scan_id = scan_req->scan_id & WMA_SCAN_ID_MASK; + /* Appending the 0xA000 to scan Id*/ + cmd->scan_id = scan_req->scan_id | WMA_HOST_SCAN_REQID_PREFIX; + } else { + cmd->scan_id = scan_req->scan_id; + } + cmd->scan_priority = WMI_SCAN_PRIORITY_LOW; + cmd->scan_req_id = scan_req->scan_requestor_id; + + if (PREAUTH_REQUESTOR_ID == cmd->scan_req_id) + cmd->scan_priority = WMI_SCAN_PRIORITY_VERY_HIGH; + + /* Set the scan events which the driver is intereseted to receive */ + /* TODO: handle all the other flags also */ + cmd->notify_scan_events = WMI_SCAN_EVENT_STARTED | + WMI_SCAN_EVENT_START_FAILED | + WMI_SCAN_EVENT_FOREIGN_CHANNEL | + WMI_SCAN_EVENT_COMPLETED | + WMI_SCAN_EVENT_DEQUEUED | + WMI_SCAN_EVENT_PREEMPTED | WMI_SCAN_EVENT_RESTARTED; + + cmd->dwell_time_active = scan_req->maxChannelTime; + + if (scan_req->scanType == eSIR_ACTIVE_SCAN) { + /* In Active scan case, the firmware has to do passive scan on DFS channels + * So the passive scan duration should be updated properly so that the duration + * will be sufficient enough to receive the beacon from AP */ + + if (wlan_cfg_get_int(pMac, WNI_CFG_PASSIVE_MAXIMUM_CHANNEL_TIME, + &dwell_time) != eSIR_SUCCESS) { + WMA_LOGE("Failed to get passive max channel value" + "using default value"); + dwell_time = WMA_DWELL_TIME_PASSIVE_DEFAULT; + } + cmd->dwell_time_passive = dwell_time; + } else + cmd->dwell_time_passive = scan_req->maxChannelTime; + + /* Ensure correct number of probes are sent on active channel */ + if (scan_req->scan_probe_repeat_time) + cmd->repeat_probe_time = scan_req->scan_probe_repeat_time; + else + cmd->repeat_probe_time = + cmd->dwell_time_active / WMA_SCAN_NPROBES_DEFAULT; + + WMA_LOGD("Repeat probe time %d", cmd->repeat_probe_time); + /* CSR sends min_rest_Time, max_rest_time and idle_time + * for staying on home channel to continue data traffic. + * Rome fw has facility to monitor the traffic + * and move to next channel. Stay on the channel for min_rest_time + * and then leave if there is no traffic. + */ + cmd->min_rest_time = scan_req->min_rest_time; + cmd->max_rest_time = scan_req->restTime; + + /* Check for traffic at idle_time interval after min_rest_time. + * Default value is 25 ms to allow full use of max_rest_time + * when voice packets are running at 20 ms interval. + */ + cmd->idle_time = scan_req->idle_time; + + + /* Large timeout value for full scan cycle, 30 seconds */ + cmd->max_scan_time = WMA_HW_DEF_SCAN_MAX_DURATION; + + /* add DS param IE in probe req frame */ + cmd->scan_ctrl_flags |= WMI_SCAN_ADD_DS_IE_IN_PROBE_REQ; + + /* do not add OFDM rates in 11B mode */ + if (scan_req->dot11mode != WNI_CFG_DOT11_MODE_11B) + cmd->scan_ctrl_flags |= WMI_SCAN_ADD_OFDM_RATES; + else + WMA_LOGD("OFDM_RATES not included in 11B mode"); + + if (scan_req->p2pScanType) + scan_req->scan_adaptive_dwell_mode = WMI_DWELL_MODE_STATIC; + + WMI_SCAN_SET_DWELL_MODE(cmd->scan_ctrl_flags, + scan_req->scan_adaptive_dwell_mode); + + /* Do not combine multiple channels in a single burst. Come back + * to home channel for data traffic after every foreign channel. + * By default, prefer throughput performance over scan cycle time. + */ + cmd->burst_duration = 0; + + /* mac randomization attributes */ + cmd->enable_scan_randomization = scan_req->enable_scan_randomization; + qdf_mem_copy(cmd->mac_addr, scan_req->mac_addr, QDF_MAC_ADDR_SIZE); + qdf_mem_copy(cmd->mac_addr_mask, scan_req->mac_addr_mask, + QDF_MAC_ADDR_SIZE); + + if (!scan_req->p2pScanType) { + WMA_LOGD("Normal Scan request"); + cmd->scan_ctrl_flags |= WMI_SCAN_ADD_CCK_RATES; + if (!scan_req->numSsid) + cmd->scan_ctrl_flags |= WMI_SCAN_ADD_BCAST_PROBE_REQ; + if (scan_req->scanType == eSIR_PASSIVE_SCAN) + cmd->scan_ctrl_flags |= WMI_SCAN_FLAG_PASSIVE; + cmd->scan_ctrl_flags |= WMI_SCAN_ADD_TPC_IE_IN_PROBE_REQ; + cmd->scan_ctrl_flags |= WMI_SCAN_FILTER_PROBE_REQ; + + /* + * Decide burst_duration and dwell_time_active based on + * what type of devices are active. + */ + do { + if (wma_is_sap_active(wma_handle) && + wma_is_p2p_go_active(wma_handle) && + wma_is_sta_active(wma_handle)) { + if (scan_req->maxChannelTime <= + WMA_3PORT_CONC_SCAN_MAX_BURST_DURATION) + cmd->burst_duration = + scan_req->maxChannelTime; + else + cmd->burst_duration = + WMA_3PORT_CONC_SCAN_MAX_BURST_DURATION; + break; + } + if (wma_handle->miracast_value && + wma_is_mcc_24G(wma_handle)) { + cmd->max_rest_time = + pMac->f_sta_miracast_mcc_rest_time_val; + } + if (wma_is_p2p_go_active(wma_handle)) { + /* Background scan while GO is sending beacons. + * Every off-channel transition has overhead of 2 beacon + * intervals for NOA. Maximize number of channels in + * every transition by using burst scan. + */ + if (wma_handle->miracast_value) { + /* When miracast is running, burst duration + * needs to be minimum to avoid any stutter + * or glitch in miracast during station scan + */ + if (scan_req->maxChannelTime <= + WMA_GO_MIN_ACTIVE_SCAN_BURST_DURATION) + cmd->burst_duration = + scan_req->maxChannelTime; + else + cmd->burst_duration = + WMA_GO_MIN_ACTIVE_SCAN_BURST_DURATION; + } else { + /* If miracast is not running, accomodate max + * stations to make the scans faster + */ + cmd->burst_duration = + WMA_BURST_SCAN_MAX_NUM_OFFCHANNELS * + scan_req->maxChannelTime; + if (cmd->burst_duration > + WMA_GO_MAX_ACTIVE_SCAN_BURST_DURATION) { + uint8_t channels = + WMA_P2P_SCAN_MAX_BURST_DURATION + / scan_req->maxChannelTime; + if (channels) + cmd->burst_duration = + channels * + scan_req->maxChannelTime; + else + cmd->burst_duration = + WMA_GO_MAX_ACTIVE_SCAN_BURST_DURATION; + } + } + break; + } + if (wma_is_sta_active(wma_handle) || + wma_is_p2p_cli_active(wma_handle)) { + if (scan_req->burst_scan_duration) + cmd->burst_duration = + scan_req->burst_scan_duration; + else + /* Typical background scan. + * Disable burst scan for now. + */ + cmd->burst_duration = 0; + break; + } + } while (0); + + } else { + WMA_LOGD("P2P Scan"); + switch (scan_req->p2pScanType) { + case P2P_SCAN_TYPE_LISTEN: + WMA_LOGD("P2P_SCAN_TYPE_LISTEN"); + cmd->scan_ctrl_flags |= WMI_SCAN_FLAG_PASSIVE; + cmd->notify_scan_events |= + WMI_SCAN_EVENT_FOREIGN_CHANNEL; + cmd->repeat_probe_time = 0; + cmd->scan_priority = WMI_SCAN_PRIORITY_HIGH; + break; + case P2P_SCAN_TYPE_SEARCH: + WMA_LOGD("P2P_SCAN_TYPE_SEARCH"); + cmd->scan_ctrl_flags |= WMI_SCAN_FILTER_PROBE_REQ; + /* Default P2P burst duration of 120 ms will cover + * 3 channels with default max dwell time 40 ms. + * Cap limit will be set by + * WMA_P2P_SCAN_MAX_BURST_DURATION. Burst duration + * should be such that no channel is scanned less + * than the dwell time in normal scenarios. + */ + if (scan_req->channelList.numChannels == + P2P_SOCIAL_CHANNELS + && (!(wma_handle->miracast_value))) + cmd->repeat_probe_time = + scan_req->maxChannelTime / 5; + else + cmd->repeat_probe_time = + scan_req->maxChannelTime / 3; + + cmd->burst_duration = + WMA_BURST_SCAN_MAX_NUM_OFFCHANNELS * + scan_req->maxChannelTime; + if (cmd->burst_duration > + WMA_P2P_SCAN_MAX_BURST_DURATION) { + uint8_t channels = + WMA_P2P_SCAN_MAX_BURST_DURATION / + scan_req->maxChannelTime; + if (channels) + cmd->burst_duration = + channels * scan_req->maxChannelTime; + else + cmd->burst_duration = + WMA_P2P_SCAN_MAX_BURST_DURATION; + } + cmd->scan_priority = WMI_SCAN_PRIORITY_MEDIUM; + break; + default: + WMA_LOGE("Invalid scan type"); + goto error; + } + } + + if (wma_is_sap_active(wma_handle)) { + /* P2P/STA scan while SoftAP is sending beacons. + * Max duration of CTS2self is 32 ms, which limits the + * dwell time. If DBS is supported and if SAP is on 2G channel + * then keep passive dwell time default. + */ + cmd->dwell_time_active = + QDF_MIN(scan_req->maxChannelTime, + (WMA_CTS_DURATION_MS_MAX - + WMA_ROAM_SCAN_CHANNEL_SWITCH_TIME)); + if (!wma_is_hw_dbs_capable() || + (wma_is_hw_dbs_capable() && + CDS_IS_CHANNEL_5GHZ( + cds_get_channel(CDS_SAP_MODE, NULL)))) { + cmd->dwell_time_passive = cmd->dwell_time_active; + } + cmd->burst_duration = 0; + if (CDS_IS_DFS_CH(cds_get_channel(CDS_SAP_MODE, NULL))) + cmd->burst_duration = + WMA_BURST_SCAN_MAX_NUM_OFFCHANNELS * + scan_req->maxChannelTime; + WMA_LOGI("SAP: burst_duration: %d", cmd->burst_duration); + } + + if (scan_req->scan_num_probes) + cmd->n_probes = scan_req->scan_num_probes; + else + cmd->n_probes = (cmd->repeat_probe_time > 0) ? + cmd->dwell_time_active / cmd->repeat_probe_time : 0; + + WMA_LOGD("Num Probes in each ch scan %d", cmd->n_probes); + if (scan_req->channelList.numChannels) { + cmd->num_chan = scan_req->channelList.numChannels; + for (i = 0; i < scan_req->channelList.numChannels; ++i) { + cmd->chan_list[i] = + cds_chan_to_freq(scan_req->channelList. + channelNumber[i]); + } + } + + if (scan_req->numSsid > SIR_SCAN_MAX_NUM_SSID) { + WMA_LOGE("Invalid value for numSsid"); + goto error; + } + + cmd->num_ssids = scan_req->numSsid; + + if (scan_req->numSsid) { + for (i = 0; i < scan_req->numSsid; ++i) { + cmd->ssid[i].length = scan_req->ssId[i].length; + qdf_mem_copy(cmd->ssid[i].mac_ssid, + scan_req->ssId[i].ssId, + scan_req->ssId[i].length); + } + } + + cmd->num_bssid = 1; + + if (!scan_req->p2pScanType) { + if (wma_is_sap_active(wma_handle)) { + SSID_num = cmd->num_ssids * cmd->num_bssid; + cmd->repeat_probe_time = probe_time_dwell_time_map[ + QDF_MIN(SSID_num, + WMA_DWELL_TIME_PROBE_TIME_MAP_SIZE + - 1)].probe_time; + cmd->n_probes = (cmd->repeat_probe_time > 0) ? + cmd->dwell_time_active/ + cmd->repeat_probe_time : 0; + } + } + WMA_LOGI("Scan Type 0x%x, Active dwell time %u, Passive dwell time %u", + scan_req->scanType, cmd->dwell_time_active, + cmd->dwell_time_passive); + WMA_LOGI("Scan repeat_probe_time %u n_probes %u num_ssids %u num_bssid %u", + cmd->repeat_probe_time, + cmd->n_probes, + cmd->num_ssids, + cmd->num_bssid); + + qdf_mem_copy(cmd->mac_add_bytes, scan_req->bssId.bytes, QDF_MAC_ADDR_SIZE); + cmd->ie_len = scan_req->uIEFieldLen; + cmd->ie_len_with_pad = roundup(scan_req->uIEFieldLen, sizeof(uint32_t)); + cmd->uie_fieldOffset = scan_req->uIEFieldOffset; + cmd->ie_base = (uint8_t *) scan_req; + + return QDF_STATUS_SUCCESS; + +error: + return qdf_status; +} + +/** + * wma_start_scan() - start scan command + * @wma_handle: wma handle + * @scan_req: scan request params + * @msg_type: message time + * + * Send start scan command to fw. + * + * Return: QDF status + */ +QDF_STATUS wma_start_scan(tp_wma_handle wma_handle, + tSirScanOffloadReq *scan_req, uint16_t msg_type) +{ + uint32_t vdev_id, scan_id; + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + struct scan_start_params cmd = {0}; + tSirScanOffloadEvent *scan_event; + + if (scan_req->channelList.numChannels > 0) { + cmd.chan_list = qdf_mem_malloc(sizeof(uint32_t) * + scan_req->channelList.numChannels); + if (NULL == cmd.chan_list) { + qdf_status = QDF_STATUS_E_NOMEM; + goto error; + } + } + if (scan_req->sessionId > wma_handle->max_bssid) { + WMA_LOGE("%s: Invalid vdev_id %d, msg_type : 0x%x", __func__, + scan_req->sessionId, msg_type); + goto error1; + } + + /* Sanity check to find whether vdev id active or not */ + if (msg_type != WMA_START_SCAN_OFFLOAD_REQ && + !wma_handle->interfaces[scan_req->sessionId].handle) { + WMA_LOGA("vdev id [%d] is not active", scan_req->sessionId); + goto error1; + } + + /* Fill individual elements of wmi_start_scan_req and + * TLV for channel list, bssid, ssid etc ... */ + qdf_status = wma_get_buf_start_scan_cmd(wma_handle, scan_req, + &cmd); + if (qdf_status != QDF_STATUS_SUCCESS) { + WMA_LOGE("Failed to get buffer for start scan cmd"); + goto error1; + } + + WMA_LOGI("scan_id 0x%x, vdev_id %d, p2pScanType %d, msg_type 0x%x", + cmd.scan_id, cmd.vdev_id, scan_req->p2pScanType, msg_type); + + /* + * Cache vdev_id and scan_id because cmd is freed after calling + * wmi_unified_cmd_send cmd. WMI internally frees cmd buffer after + * getting TX complete from CE + */ + vdev_id = cmd.vdev_id; + scan_id = cmd.scan_id; + WMA_LOGI("ActiveDwell %d, PassiveDwell %d, ScanFlags 0x%x NumChan %d", + cmd.dwell_time_active, cmd.dwell_time_passive, + cmd.scan_ctrl_flags, cmd.num_chan); + + /* Call the wmi api to request the scan */ + qdf_status = wmi_unified_scan_start_cmd_send(wma_handle->wmi_handle, + &cmd); + if (QDF_IS_STATUS_ERROR(qdf_status)) { + WMA_LOGE("wmi_unified_cmd_send returned Error %d", qdf_status); + goto error1; + } + + if (NULL != cmd.chan_list) + qdf_mem_free(cmd.chan_list); + + WMA_LOGI("WMA --> WMI_START_SCAN_CMDID"); + + return QDF_STATUS_SUCCESS; + +error1: + if (NULL != cmd.chan_list) + qdf_mem_free(cmd.chan_list); + +error: + /* Send completion event for only for start scan request */ + if (msg_type == WMA_START_SCAN_OFFLOAD_REQ) { + scan_event = + (tSirScanOffloadEvent *) + qdf_mem_malloc(sizeof(tSirScanOffloadEvent)); + if (!scan_event) { + WMA_LOGP("%s: Failed to allocate memory for scan rsp", + __func__); + return QDF_STATUS_E_NOMEM; + } + memset(scan_event, 0x00, sizeof(*scan_event)); + scan_event->event = WMI_SCAN_EVENT_COMPLETED; + scan_event->reasonCode = eSIR_SME_SCAN_FAILED; + scan_event->sessionId = scan_req->sessionId; + scan_event->p2pScanType = scan_req->p2pScanType; + scan_event->scanId = scan_req->scan_id; + scan_event->requestor = scan_req->scan_requestor_id; + wma_send_msg(wma_handle, WMA_RX_SCAN_EVENT, (void *)scan_event, + 0); + } + + return qdf_status; +} + +/** + * wma_stop_scan() - stop scan command + * @wma_handle: wma handle + * @abort_scan_req: abort scan params + * + * Send stop scan command to fw. + * + * Return: QDF status + */ +QDF_STATUS wma_stop_scan(tp_wma_handle wma_handle, + tAbortScanParams *abort_scan_req) +{ + QDF_STATUS qdf_status; + struct scan_stop_params scan_param = {0}; + + scan_param.vdev_id = abort_scan_req->SessionId; + scan_param.requestor = abort_scan_req->scan_requestor_id; + scan_param.scan_id = abort_scan_req->scan_id; + /* stop the scan with the corresponding scan_id */ + scan_param.req_type = WMI_SCAN_STOP_ONE; + qdf_status = wmi_unified_scan_stop_cmd_send(wma_handle->wmi_handle, + &scan_param); + /* Call the wmi api to request the scan */ + if (QDF_IS_STATUS_ERROR(qdf_status)) { + WMA_LOGE("wmi_unified_cmd_send WMI_STOP_SCAN_CMDID returned Error %d", + qdf_status); + goto error; + } + WMA_LOGI("scan_id 0x%x, scan_requestor_id 0x%x, vdev_id %d", + abort_scan_req->scan_id, + abort_scan_req->scan_requestor_id, + abort_scan_req->SessionId); + WMA_LOGI("WMA --> WMI_STOP_SCAN_CMDID"); + + return QDF_STATUS_SUCCESS; + +error: + return qdf_status; +} + +/** + * wma_update_channel_list() - update channel list + * @handle: wma handle + * @chan_list: channel list + * + * Function is used to update the support channel list in fw. + * + * Return: QDF status + */ +QDF_STATUS wma_update_channel_list(WMA_HANDLE handle, + tSirUpdateChanList *chan_list) +{ + tp_wma_handle wma_handle = (tp_wma_handle) handle; + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + int i; + struct scan_chan_list_params scan_ch_param = {0}; + wmi_channel_param *tchan_info; + + scan_ch_param.chan_info = qdf_mem_malloc(sizeof(wmi_channel) * + chan_list->numChan); + if (NULL == scan_ch_param.chan_info) { + WMA_LOGE("%s: Failed to allocate channel info", __func__); + return QDF_STATUS_E_NOMEM; + } + qdf_mem_zero(scan_ch_param.chan_info, sizeof(wmi_channel) * + chan_list->numChan); + WMA_LOGD("no of channels = %d", chan_list->numChan); + tchan_info = scan_ch_param.chan_info; + scan_ch_param.num_scan_chans = chan_list->numChan; + wma_handle->saved_chan.num_channels = chan_list->numChan; + WMA_LOGD("ht %d, vht %d, vht_24 %d", chan_list->ht_en, + chan_list->vht_en, chan_list->vht_24_en); + + for (i = 0; i < chan_list->numChan; ++i) { + tchan_info->mhz = + cds_chan_to_freq(chan_list->chanParam[i].chanId); + tchan_info->band_center_freq1 = + tchan_info->mhz; + tchan_info->band_center_freq2 = 0; + wma_handle->saved_chan.channel_list[i] = + chan_list->chanParam[i].chanId; + + WMA_LOGD("chan[%d] = freq:%u chan:%d DFS:%d tx power:%d", + i, tchan_info->mhz, + chan_list->chanParam[i].chanId, + chan_list->chanParam[i].dfsSet, + chan_list->chanParam[i].pwr); + + if (chan_list->chanParam[i].dfsSet) + WMI_SET_CHANNEL_FLAG(tchan_info, + WMI_CHAN_FLAG_PASSIVE); + + if (tchan_info->mhz < WMA_2_4_GHZ_MAX_FREQ) { + WMI_SET_CHANNEL_MODE(tchan_info, MODE_11G); + if (chan_list->vht_en && chan_list->vht_24_en) + WMI_SET_CHANNEL_FLAG(tchan_info, + WMI_CHAN_FLAG_ALLOW_VHT); + } else { + WMI_SET_CHANNEL_MODE(tchan_info, MODE_11A); + if (chan_list->vht_en) + WMI_SET_CHANNEL_FLAG(tchan_info, + WMI_CHAN_FLAG_ALLOW_VHT); + } + + if (chan_list->ht_en) + WMI_SET_CHANNEL_FLAG(tchan_info, + WMI_CHAN_FLAG_ALLOW_HT); + + if (chan_list->chanParam[i].half_rate) + WMI_SET_CHANNEL_FLAG(tchan_info, + WMI_CHAN_FLAG_HALF_RATE); + else if (chan_list->chanParam[i].quarter_rate) + WMI_SET_CHANNEL_FLAG(tchan_info, + WMI_CHAN_FLAG_QUARTER_RATE); + + WMI_SET_CHANNEL_MAX_TX_POWER(tchan_info, + chan_list->chanParam[i].pwr); + + WMI_SET_CHANNEL_REG_POWER(tchan_info, + chan_list->chanParam[i].pwr); + tchan_info++; + } + + qdf_status = wmi_unified_scan_chan_list_cmd_send(wma_handle->wmi_handle, + &scan_ch_param); + + if (QDF_IS_STATUS_ERROR(qdf_status)) { + WMA_LOGE("Failed to send WMI_SCAN_CHAN_LIST_CMDID"); + } + + qdf_mem_free(scan_ch_param.chan_info); + + return qdf_status; +} + +/** + * wma_roam_scan_offload_mode() - send roam scan mode request to fw + * @wma_handle: wma handle + * @scan_cmd_fp: start scan command ptr + * @roam_req: roam request param + * @mode: mode + * @vdev_id: vdev id + * + * send WMI_ROAM_SCAN_MODE TLV to firmware. It has a piggyback + * of WMI_ROAM_SCAN_MODE. + * + * Return: QDF status + */ +QDF_STATUS wma_roam_scan_offload_mode(tp_wma_handle wma_handle, + wmi_start_scan_cmd_fixed_param * + scan_cmd_fp, + tSirRoamOffloadScanReq *roam_req, + uint32_t mode, uint32_t vdev_id) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct roam_offload_scan_params *params = + qdf_mem_malloc(sizeof(*params)); + + if (!params) { + WMA_LOGE("%s: Failed to allocate scan params", __func__); + return QDF_STATUS_E_NOMEM; + } +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + params->auth_mode = WMI_AUTH_NONE; + if (roam_req) + params->auth_mode = e_csr_auth_type_to_rsn_authmode + (roam_req->ConnectedNetwork.authentication, + roam_req->ConnectedNetwork.encryption); + WMA_LOGD("%s : auth mode = %d", __func__, params->auth_mode); +#endif /* WLAN_FEATURE_ROAM_OFFLOAD */ + + params->is_roam_req_valid = 0; + params->mode = mode; + params->vdev_id = vdev_id; + if (roam_req) { + params->is_roam_req_valid = 1; +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + params->roam_offload_enabled = roam_req->RoamOffloadEnabled; + params->prefer_5ghz = roam_req->Prefer5GHz; + params->roam_rssi_cat_gap = roam_req->RoamRssiCatGap; + params->select_5ghz_margin = roam_req->Select5GHzMargin; + params->reassoc_failure_timeout = + roam_req->ReassocFailureTimeout; + params->rokh_id_length = roam_req->R0KH_ID_Length; + qdf_mem_copy(params->rokh_id, roam_req->R0KH_ID, + WMI_ROAM_R0KH_ID_MAX_LEN); + qdf_mem_copy(params->krk, roam_req->KRK, WMI_KRK_KEY_LEN); + qdf_mem_copy(params->btk, roam_req->BTK, WMI_BTK_KEY_LEN); + qdf_mem_copy(params->psk_pmk, roam_req->PSK_PMK, + WMI_ROAM_SCAN_PSK_SIZE); + params->pmk_len = roam_req->pmk_len; + params->roam_key_mgmt_offload_enabled = + roam_req->RoamKeyMgmtOffloadEnabled; + wma_roam_scan_fill_self_caps(wma_handle, + ¶ms->roam_offload_params, roam_req); + params->fw_okc = roam_req->pmkid_modes.fw_okc; + params->fw_pmksa_cache = roam_req->pmkid_modes.fw_pmksa_cache; +#endif + params->is_ese_assoc = roam_req->IsESEAssoc; + params->mdid.mdie_present = roam_req->MDID.mdiePresent; + params->mdid.mobility_domain = roam_req->MDID.mobilityDomain; + params->assoc_ie_length = roam_req->assoc_ie.length; + qdf_mem_copy(params->assoc_ie, roam_req->assoc_ie.addIEdata, + roam_req->assoc_ie.length); + } + + WMA_LOGD(FL("qos_caps: %d, qos_enabled: %d"), + params->roam_offload_params.qos_caps, + params->roam_offload_params.qos_enabled); + + status = wmi_unified_roam_scan_offload_mode_cmd(wma_handle->wmi_handle, + scan_cmd_fp, params); + if (QDF_IS_STATUS_ERROR(status)) + return status; + + WMA_LOGI("%s: WMA --> WMI_ROAM_SCAN_MODE", __func__); + qdf_mem_free(params); + return status; +} + +/** + * wma_roam_scan_offload_rssi_threshold() - set scan offload rssi threashold + * @wma_handle: wma handle + * @roam_req: Roaming request buffer + * + * Send WMI_ROAM_SCAN_RSSI_THRESHOLD TLV to firmware + * + * Return: QDF status + */ +QDF_STATUS wma_roam_scan_offload_rssi_thresh(tp_wma_handle wma_handle, + tSirRoamOffloadScanReq *roam_req) +{ + struct roam_offload_scan_rssi_params params = {0}; + QDF_STATUS status = QDF_STATUS_SUCCESS; + int rssi_thresh, rssi_thresh_diff; + struct roam_ext_params *roam_params; + int32_t good_rssi_threshold; + uint32_t hirssi_scan_max_count; + uint32_t hirssi_scan_delta; + int32_t hirssi_upper_bound; + + /* Send rssi threshold */ + roam_params = &roam_req->roam_params; + rssi_thresh = roam_req->LookupThreshold - WMA_NOISE_FLOOR_DBM_DEFAULT; + rssi_thresh_diff = roam_req->OpportunisticScanThresholdDiff; + hirssi_scan_max_count = roam_req->hi_rssi_scan_max_count; + hirssi_scan_delta = roam_req->hi_rssi_scan_rssi_delta; + hirssi_upper_bound = roam_req->hi_rssi_scan_rssi_ub - + WMA_NOISE_FLOOR_DBM_DEFAULT; + + /* fill in threshold values */ + params.session_id = roam_req->sessionId; + params.rssi_thresh = rssi_thresh & 0x000000ff; + params.rssi_thresh_diff = rssi_thresh_diff & 0x000000ff; + params.hi_rssi_scan_max_count = hirssi_scan_max_count; + params.hi_rssi_scan_rssi_delta = hirssi_scan_delta; + params.hi_rssi_scan_rssi_ub = hirssi_upper_bound & 0x00000ff; + params.raise_rssi_thresh_5g = roam_params->raise_rssi_thresh_5g; + params.dense_rssi_thresh_offset = + roam_params->dense_rssi_thresh_offset; + params.dense_min_aps_cnt = roam_params->dense_min_aps_cnt; + params.traffic_threshold = + roam_params->traffic_threshold; + params.initial_dense_status = roam_params->initial_dense_status; + + + /* + * The current Noise floor in firmware is -96dBm. Penalty/Boost + * threshold is applied on a weaker signal to make it even more weaker. + * So, there is a chance that the user may configure a very low + * Penalty/Boost threshold beyond the noise floor. If that is the case, + * then suppress the penalty/boost threshold to the noise floor. + */ + if (roam_params->raise_rssi_thresh_5g < WMA_NOISE_FLOOR_DBM_DEFAULT) + params.penalty_threshold_5g = 0; + else + params.boost_threshold_5g = + (roam_params->raise_rssi_thresh_5g - + WMA_NOISE_FLOOR_DBM_DEFAULT) & 0x000000ff; + if (roam_params->drop_rssi_thresh_5g < WMA_NOISE_FLOOR_DBM_DEFAULT) + params.penalty_threshold_5g = 0; + else + params.penalty_threshold_5g = + (roam_params->drop_rssi_thresh_5g - + WMA_NOISE_FLOOR_DBM_DEFAULT) & 0x000000ff; + params.raise_factor_5g = roam_params->raise_factor_5g; + params.drop_factor_5g = roam_params->drop_factor_5g; + params.max_raise_rssi_5g = roam_params->max_raise_rssi_5g; + params.max_drop_rssi_5g = roam_params->max_drop_rssi_5g; + + if (roam_params->good_rssi_roam) + good_rssi_threshold = WMA_NOISE_FLOOR_DBM_DEFAULT; + else + good_rssi_threshold = 0; + params.good_rssi_threshold = + (good_rssi_threshold - WMA_NOISE_FLOOR_DBM_DEFAULT) & 0x000000ff; + + WMA_LOGD("WMA --> good_rssi_threshold=%d", + params.good_rssi_threshold); + + if (roam_req->early_stop_scan_enable) { + params.roam_earlystop_thres_min = + roam_req->early_stop_scan_min_threshold - + WMA_NOISE_FLOOR_DBM_DEFAULT; + params.roam_earlystop_thres_max = + roam_req->early_stop_scan_max_threshold - + WMA_NOISE_FLOOR_DBM_DEFAULT; + } else { + params.roam_earlystop_thres_min = 0; + params.roam_earlystop_thres_max = 0; + } + + WMA_LOGD("early_stop_thresholds en=%d, min=%d, max=%d", + roam_req->early_stop_scan_enable, + params.roam_earlystop_thres_min, + params.roam_earlystop_thres_max); + + status = wmi_unified_roam_scan_offload_rssi_thresh_cmd( + wma_handle->wmi_handle, ¶ms); + if (QDF_IS_STATUS_ERROR(status)) { + return status; + } + + WMA_LOGI(FL("roam_scan_rssi_thresh=%d, roam_rssi_thresh_diff=%d"), + rssi_thresh, rssi_thresh_diff); + WMA_LOGI( + FL("hirssi_scan max_count=%d, delta=%d, hirssi_upper_bound=%d"), + hirssi_scan_max_count, hirssi_scan_delta, hirssi_upper_bound); + WMA_LOGI( + FL("dense_rssi_thresh_offset=%d, dense_min_aps_cnt=%d, traffic_threshold=%d initial_dense_status=%d"), + roam_params->dense_rssi_thresh_offset, + roam_params->dense_min_aps_cnt, + roam_params->traffic_threshold, + roam_params->initial_dense_status); + return status; +} + +/** + * wma_roam_scan_offload_scan_period() - set roam offload scan period + * @wma_handle: wma handle + * @scan_period: scan period + * @scan_age: scan age + * @vdev_id: vdev id + * + * Send WMI_ROAM_SCAN_PERIOD parameters to fw. + * + * Return: QDF status + */ +QDF_STATUS wma_roam_scan_offload_scan_period(tp_wma_handle wma_handle, + uint32_t scan_period, + uint32_t scan_age, + uint32_t vdev_id) +{ + return wmi_unified_roam_scan_offload_scan_period(wma_handle->wmi_handle, + scan_period, scan_age, vdev_id); +} + +/** + * wma_roam_scan_offload_rssi_change() - set roam offload RSSI change threshold + * @wma_handle: wma handle + * @rssi_change_thresh: RSSI Change threshold + * @bcn_rssi_weight: beacon RSSI weight + * @vdev_id: vdev id + * + * Send WMI_ROAM_SCAN_RSSI_CHANGE_THRESHOLD parameters to fw. + * + * Return: QDF status + */ +QDF_STATUS wma_roam_scan_offload_rssi_change(tp_wma_handle wma_handle, + uint32_t vdev_id, + int32_t rssi_change_thresh, + uint32_t bcn_rssi_weight, + uint32_t hirssi_delay_btw_scans) +{ + int status; + + status = wmi_unified_roam_scan_offload_rssi_change_cmd(wma_handle->wmi_handle, + vdev_id, rssi_change_thresh, + bcn_rssi_weight, hirssi_delay_btw_scans); + if (status != EOK) + return QDF_STATUS_E_FAILURE; + + + return QDF_STATUS_SUCCESS; +} + +/** + * wma_roam_scan_offload_chan_list() - set roam offload channel list + * @wma_handle: wma handle + * @chan_count: channel count + * @chan_list: channel list + * @list_type: list type + * @vdev_id: vdev id + * + * Set roam offload channel list. + * + * Return: QDF status + */ +QDF_STATUS wma_roam_scan_offload_chan_list(tp_wma_handle wma_handle, + uint8_t chan_count, + uint8_t *chan_list, + uint8_t list_type, uint32_t vdev_id) +{ + QDF_STATUS status; + int i; + uint32_t *chan_list_mhz; + + if (chan_count == 0) { + WMA_LOGD("%s : invalid number of channels %d", __func__, + chan_count); + return QDF_STATUS_E_EMPTY; + } + chan_list_mhz = qdf_mem_malloc(chan_count * sizeof(*chan_list_mhz)); + if (chan_list_mhz == NULL) { + WMA_LOGE("%s : Memory allocation failed", __func__); + return QDF_STATUS_E_NOMEM; + } + + for (i = 0; ((i < chan_count) && + (i < SIR_ROAM_MAX_CHANNELS)); i++) { + chan_list_mhz[i] = cds_chan_to_freq(chan_list[i]); + WMA_LOGI("%d,", chan_list_mhz[i]); + } + + status = wmi_unified_roam_scan_offload_chan_list_cmd(wma_handle->wmi_handle, + chan_count, chan_list_mhz, + list_type, vdev_id); + qdf_mem_free(chan_list_mhz); + + return status; +} + +/** + * e_csr_auth_type_to_rsn_authmode() - map csr auth type to rsn authmode + * @authtype: CSR authtype + * @encr: CSR Encryption + * + * Map CSR's authentication type into RSN auth mode used by firmware + * + * Return: WMI RSN auth mode + */ +A_UINT32 e_csr_auth_type_to_rsn_authmode(eCsrAuthType authtype, + eCsrEncryptionType encr) +{ + switch (authtype) { + case eCSR_AUTH_TYPE_OPEN_SYSTEM: + return WMI_AUTH_OPEN; + case eCSR_AUTH_TYPE_WPA: + return WMI_AUTH_WPA; + case eCSR_AUTH_TYPE_WPA_PSK: + return WMI_AUTH_WPA_PSK; + case eCSR_AUTH_TYPE_RSN: + return WMI_AUTH_RSNA; + case eCSR_AUTH_TYPE_RSN_PSK: + return WMI_AUTH_RSNA_PSK; + case eCSR_AUTH_TYPE_FT_RSN: + return WMI_AUTH_FT_RSNA; + case eCSR_AUTH_TYPE_FT_RSN_PSK: + return WMI_AUTH_FT_RSNA_PSK; +#ifdef FEATURE_WLAN_WAPI + case eCSR_AUTH_TYPE_WAPI_WAI_CERTIFICATE: + return WMI_AUTH_WAPI; + case eCSR_AUTH_TYPE_WAPI_WAI_PSK: + return WMI_AUTH_WAPI_PSK; +#endif /* FEATURE_WLAN_WAPI */ +#ifdef FEATURE_WLAN_ESE + case eCSR_AUTH_TYPE_CCKM_WPA: + return WMI_AUTH_CCKM_WPA; + case eCSR_AUTH_TYPE_CCKM_RSN: + return WMI_AUTH_CCKM_RSNA; +#endif /* FEATURE_WLAN_ESE */ +#ifdef WLAN_FEATURE_11W + case eCSR_AUTH_TYPE_RSN_PSK_SHA256: + return WMI_AUTH_RSNA_PSK_SHA256; + case eCSR_AUTH_TYPE_RSN_8021X_SHA256: + return WMI_AUTH_RSNA_8021X_SHA256; +#endif /* WLAN_FEATURE_11W */ + case eCSR_AUTH_TYPE_NONE: + case eCSR_AUTH_TYPE_AUTOSWITCH: + /* In case of WEP and other keys, NONE means OPEN auth */ + if (encr == eCSR_ENCRYPT_TYPE_WEP40_STATICKEY || + encr == eCSR_ENCRYPT_TYPE_WEP104_STATICKEY || + encr == eCSR_ENCRYPT_TYPE_WEP40 || + encr == eCSR_ENCRYPT_TYPE_WEP104 || + encr == eCSR_ENCRYPT_TYPE_TKIP || + encr == eCSR_ENCRYPT_TYPE_AES) { + return WMI_AUTH_OPEN; + } + return WMI_AUTH_NONE; + default: + return WMI_AUTH_NONE; + } +} + +/** + * e_csr_encryption_type_to_rsn_cipherset() - map csr enc type to ESN cipher + * @encr: CSR Encryption + * + * Map CSR's encryption type into RSN cipher types used by firmware + * + * Return: WMI RSN cipher + */ +A_UINT32 e_csr_encryption_type_to_rsn_cipherset(eCsrEncryptionType encr) +{ + + switch (encr) { + case eCSR_ENCRYPT_TYPE_WEP40_STATICKEY: + case eCSR_ENCRYPT_TYPE_WEP104_STATICKEY: + case eCSR_ENCRYPT_TYPE_WEP40: + case eCSR_ENCRYPT_TYPE_WEP104: + return WMI_CIPHER_WEP; + case eCSR_ENCRYPT_TYPE_TKIP: + return WMI_CIPHER_TKIP; + case eCSR_ENCRYPT_TYPE_AES: + return WMI_CIPHER_AES_CCM; +#ifdef FEATURE_WLAN_WAPI + case eCSR_ENCRYPT_TYPE_WPI: + return WMI_CIPHER_WAPI; +#endif /* FEATURE_WLAN_WAPI */ + case eCSR_ENCRYPT_TYPE_ANY: + return WMI_CIPHER_ANY; + case eCSR_ENCRYPT_TYPE_NONE: + default: + return WMI_CIPHER_NONE; + } +} + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +/** + * wma_roam_scan_get_cckm_mode() - Get the CCKM auth mode + * @roam_req: Roaming request buffer + * @auth_mode: Auth mode to be converted + * + * Based on LFR2.0 or LFR3.0, return the proper auth type + * + * Return: if LFR2.0, then return WMI_AUTH_CCKM for backward compatibility + * if LFR3.0 then return the appropriate auth type + */ +static uint32_t wma_roam_scan_get_cckm_mode(tSirRoamOffloadScanReq *roam_req, + uint32_t auth_mode) +{ + if (roam_req->RoamOffloadEnabled) + return auth_mode; + else + return WMI_AUTH_CCKM; + +} +#endif +/** + * wma_roam_scan_fill_ap_profile() - fill ap_profile + * @wma_handle: wma handle + * @pMac: Mac ptr + * @roam_req: roam offload scan request + * @ap_profile_p: ap profile + * + * Fill ap_profile structure from configured parameters + * + * Return: none + */ +void wma_roam_scan_fill_ap_profile(tp_wma_handle wma_handle, + tpAniSirGlobal pMac, + tSirRoamOffloadScanReq *roam_req, + wmi_ap_profile *ap_profile_p) +{ + uint32_t rsn_authmode; + qdf_mem_zero(ap_profile_p, sizeof(wmi_ap_profile)); + if (roam_req == NULL) { + ap_profile_p->ssid.ssid_len = 0; + ap_profile_p->ssid.ssid[0] = 0; + ap_profile_p->rsn_authmode = WMI_AUTH_NONE; + ap_profile_p->rsn_ucastcipherset = WMI_CIPHER_NONE; + ap_profile_p->rsn_mcastcipherset = WMI_CIPHER_NONE; + ap_profile_p->rsn_mcastmgmtcipherset = WMI_CIPHER_NONE; + ap_profile_p->rssi_threshold = WMA_ROAM_RSSI_DIFF_DEFAULT; + } else { + ap_profile_p->ssid.ssid_len = + roam_req->ConnectedNetwork.ssId.length; + qdf_mem_copy(ap_profile_p->ssid.ssid, + roam_req->ConnectedNetwork.ssId.ssId, + ap_profile_p->ssid.ssid_len); + ap_profile_p->rsn_authmode = + e_csr_auth_type_to_rsn_authmode( + roam_req->ConnectedNetwork.authentication, + roam_req->ConnectedNetwork.encryption); + rsn_authmode = ap_profile_p->rsn_authmode; + + if ((rsn_authmode == WMI_AUTH_CCKM_WPA) || + (rsn_authmode == WMI_AUTH_CCKM_RSNA)) + ap_profile_p->rsn_authmode = + wma_roam_scan_get_cckm_mode( + roam_req, rsn_authmode); + ap_profile_p->rsn_ucastcipherset = + e_csr_encryption_type_to_rsn_cipherset(roam_req->ConnectedNetwork.encryption); + ap_profile_p->rsn_mcastcipherset = + e_csr_encryption_type_to_rsn_cipherset(roam_req->ConnectedNetwork.mcencryption); + ap_profile_p->rsn_mcastmgmtcipherset = + ap_profile_p->rsn_mcastcipherset; + ap_profile_p->rssi_threshold = roam_req->RoamRssiDiff; +#ifdef WLAN_FEATURE_11W + if (roam_req->ConnectedNetwork.mfp_enabled) + ap_profile_p->flags |= WMI_AP_PROFILE_FLAG_PMF; +#endif + } +} + +/** + * wma_process_set_pdev_ie_req() - process the pdev set IE req + * @wma: Pointer to wma handle + * @ie_params: Pointer to IE data. + * + * Sends the WMI req to set the IE to FW. + * + * Return: None + */ +void wma_process_set_pdev_ie_req(tp_wma_handle wma, + struct set_ie_param *ie_params) +{ + if (ie_params->ie_type == DOT11_HT_IE) + wma_process_set_pdev_ht_ie_req(wma, ie_params); + if (ie_params->ie_type == DOT11_VHT_IE) + wma_process_set_pdev_vht_ie_req(wma, ie_params); + + qdf_mem_free(ie_params->ie_ptr); +} + +/** + * wma_process_set_pdev_ht_ie_req() - sends HT IE data to FW + * @wma: Pointer to wma handle + * @ie_params: Pointer to IE data. + * @nss: Nss values to prepare the HT IE. + * + * Sends the WMI req to set the HT IE to FW. + * + * Return: None + */ +void wma_process_set_pdev_ht_ie_req(tp_wma_handle wma, + struct set_ie_param *ie_params) +{ + int ret; + wmi_pdev_set_ht_ie_cmd_fixed_param *cmd; + wmi_buf_t buf; + uint16_t len; + uint16_t ie_len_pad; + uint8_t *buf_ptr; + + len = sizeof(*cmd) + WMI_TLV_HDR_SIZE; + ie_len_pad = roundup(ie_params->ie_len, sizeof(uint32_t)); + len += ie_len_pad; + + buf = wmi_buf_alloc(wma->wmi_handle, len); + if (!buf) { + WMA_LOGE("%s:wmi_buf_alloc failed", __func__); + return; + } + cmd = (wmi_pdev_set_ht_ie_cmd_fixed_param *) wmi_buf_data(buf); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_pdev_set_ht_ie_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN( + wmi_pdev_set_ht_ie_cmd_fixed_param)); + cmd->reserved0 = 0; + cmd->ie_len = ie_params->ie_len; + cmd->tx_streams = ie_params->nss; + cmd->rx_streams = ie_params->nss; + WMA_LOGD("Setting pdev HT ie with Nss = %u", + ie_params->nss); + buf_ptr = (uint8_t *)cmd + sizeof(*cmd); + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE, ie_len_pad); + if (ie_params->ie_len) { + qdf_mem_copy(buf_ptr + WMI_TLV_HDR_SIZE, + (uint8_t *)ie_params->ie_ptr, + ie_params->ie_len); + } + ret = wmi_unified_cmd_send(wma->wmi_handle, buf, len, + WMI_PDEV_SET_HT_CAP_IE_CMDID); + if (ret != EOK) { + WMA_LOGE("Failed to send set param command ret = %d", ret); + wmi_buf_free(buf); + } +} + +/** + * wma_process_set_pdev_vht_ie_req() - sends VHT IE data to FW + * @wma: Pointer to wma handle + * @ie_params: Pointer to IE data. + * @nss: Nss values to prepare the VHT IE. + * + * Sends the WMI req to set the VHT IE to FW. + * + * Return: None + */ +void wma_process_set_pdev_vht_ie_req(tp_wma_handle wma, + struct set_ie_param *ie_params) +{ + int ret; + wmi_pdev_set_vht_ie_cmd_fixed_param *cmd; + wmi_buf_t buf; + uint16_t len; + uint16_t ie_len_pad; + uint8_t *buf_ptr; + + len = sizeof(*cmd) + WMI_TLV_HDR_SIZE; + ie_len_pad = roundup(ie_params->ie_len, sizeof(uint32_t)); + len += ie_len_pad; + + buf = wmi_buf_alloc(wma->wmi_handle, len); + if (!buf) { + WMA_LOGE("%s:wmi_buf_alloc failed", __func__); + return; + } + cmd = (wmi_pdev_set_vht_ie_cmd_fixed_param *) wmi_buf_data(buf); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_pdev_set_vht_ie_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN( + wmi_pdev_set_vht_ie_cmd_fixed_param)); + cmd->reserved0 = 0; + cmd->ie_len = ie_params->ie_len; + cmd->tx_streams = ie_params->nss; + cmd->rx_streams = ie_params->nss; + WMA_LOGD("Setting pdev VHT ie with Nss = %u", + ie_params->nss); + buf_ptr = (uint8_t *)cmd + sizeof(*cmd); + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE, ie_len_pad); + if (ie_params->ie_len) { + qdf_mem_copy(buf_ptr + WMI_TLV_HDR_SIZE, + (uint8_t *)ie_params->ie_ptr, + ie_params->ie_len); + } + ret = wmi_unified_cmd_send(wma->wmi_handle, buf, len, + WMI_PDEV_SET_VHT_CAP_IE_CMDID); + if (ret != EOK) { + WMA_LOGE("Failed to send set param command ret = %d", ret); + wmi_buf_free(buf); + } +} + +/** + * wma_roam_scan_scan_params() - fill roam scan params + * @wma_handle: wma handle + * @pMac: Mac ptr + * @scan_params: scan parameters + * @roam_req: NULL if this routine is called before connect + * It will be non-NULL if called after assoc. + * + * Fill scan_params structure from configured parameters + * + * Return: none + */ +void wma_roam_scan_fill_scan_params(tp_wma_handle wma_handle, + tpAniSirGlobal pMac, + tSirRoamOffloadScanReq *roam_req, + wmi_start_scan_cmd_fixed_param * + scan_params) +{ + uint8_t channels_per_burst = 0; + uint32_t val = 0; + + if (NULL == pMac) { + WMA_LOGE("%s: pMac is NULL", __func__); + return; + } + + qdf_mem_zero(scan_params, sizeof(wmi_start_scan_cmd_fixed_param)); + scan_params->scan_ctrl_flags = WMI_SCAN_ADD_CCK_RATES | + WMI_SCAN_ADD_OFDM_RATES | + WMI_SCAN_ADD_DS_IE_IN_PROBE_REQ; + if (roam_req != NULL) { + /* Parameters updated after association is complete */ + WMA_LOGI("%s: Input parameters: NeighborScanChannelMinTime" + " = %d, NeighborScanChannelMaxTime = %d", + __func__, + roam_req->NeighborScanChannelMinTime, + roam_req->NeighborScanChannelMaxTime); + WMA_LOGI("%s: Input parameters: NeighborScanTimerPeriod =" + " %d, HomeAwayTime = %d, nProbes = %d", + __func__, + roam_req->NeighborScanTimerPeriod, + roam_req->HomeAwayTime, roam_req->nProbes); + + /* + * roam_req->NeighborScanChannelMaxTime = SCAN_CHANNEL_TIME + * roam_req->HomeAwayTime = SCAN_HOME_AWAY_TIME + * roam_req->NeighborScanTimerPeriod = SCAN_HOME_TIME + * + * scan_params->dwell_time_active = time station stays on channel + * and sends probes; + * scan_params->dwell_time_passive = time station stays on channel + * and listens probes; + * scan_params->burst_duration = time station goes off channel + * to scan; + */ + + if (wlan_cfg_get_int + (pMac, WNI_CFG_PASSIVE_MAXIMUM_CHANNEL_TIME, + &val) != eSIR_SUCCESS) { + /* + * Could not get max channel value from CFG. Log error. + */ + WMA_LOGE + ("could not retrieve passive max channel value"); + + /* use a default value of 110ms */ + val = WMA_ROAM_DWELL_TIME_PASSIVE_DEFAULT; + } + + scan_params->dwell_time_passive = val; + /* + * Here is the formula, + * T(HomeAway) = N * T(dwell) + (N+1) * T(cs) + * where N is number of channels scanned in single burst + */ + scan_params->dwell_time_active = + roam_req->NeighborScanChannelMaxTime; + if (roam_req->HomeAwayTime < + 2 * WMA_ROAM_SCAN_CHANNEL_SWITCH_TIME) { + /* clearly we can't follow home away time. + * Make it a split scan. + */ + scan_params->burst_duration = 0; + } else { + channels_per_burst = + (roam_req->HomeAwayTime - + WMA_ROAM_SCAN_CHANNEL_SWITCH_TIME) + / (scan_params->dwell_time_active + + WMA_ROAM_SCAN_CHANNEL_SWITCH_TIME); + + if (channels_per_burst < 1) { + /* dwell time and home away time conflicts */ + /* we will override dwell time */ + scan_params->dwell_time_active = + roam_req->HomeAwayTime - + 2 * WMA_ROAM_SCAN_CHANNEL_SWITCH_TIME; + scan_params->burst_duration = + scan_params->dwell_time_active; + } else { + scan_params->burst_duration = + channels_per_burst * + scan_params->dwell_time_active; + } + } + if (roam_req->allowDFSChannelRoam == + SIR_ROAMING_DFS_CHANNEL_ENABLED_NORMAL + && roam_req->HomeAwayTime > 0 + && roam_req->ChannelCacheType != CHANNEL_LIST_STATIC) { + /* Roaming on DFS channels is supported and it is not + * app channel list. It is ok to override homeAwayTime + * to accomodate DFS dwell time in burst + * duration. + */ + scan_params->burst_duration = + QDF_MAX(scan_params->burst_duration, + scan_params->dwell_time_passive); + } + scan_params->min_rest_time = roam_req->NeighborScanTimerPeriod; + scan_params->max_rest_time = roam_req->NeighborScanTimerPeriod; + scan_params->repeat_probe_time = (roam_req->nProbes > 0) ? + QDF_MAX(scan_params->dwell_time_active / roam_req->nProbes, + 1) : 0; + scan_params->probe_spacing_time = 0; + scan_params->probe_delay = 0; + /* 30 seconds for full scan cycle */ + scan_params->max_scan_time = WMA_HW_DEF_SCAN_MAX_DURATION; + scan_params->idle_time = scan_params->min_rest_time; + scan_params->n_probes = roam_req->nProbes; + if (roam_req->allowDFSChannelRoam == + SIR_ROAMING_DFS_CHANNEL_DISABLED) { + scan_params->scan_ctrl_flags |= WMI_SCAN_BYPASS_DFS_CHN; + } else { + /* Roaming scan on DFS channel is allowed. + * No need to change any flags for default + * allowDFSChannelRoam = 1. + * Special case where static channel list is given by\ + * application that contains DFS channels. + * Assume that the application has knowledge of matching + * APs being active and that probe request transmission + * is permitted on those channel. + * Force active scans on those channels. + */ + + if (roam_req->allowDFSChannelRoam == + SIR_ROAMING_DFS_CHANNEL_ENABLED_ACTIVE && + roam_req->ChannelCacheType == CHANNEL_LIST_STATIC && + roam_req->ConnectedNetwork.ChannelCount > 0) { + scan_params->scan_ctrl_flags |= + WMI_SCAN_FLAG_FORCE_ACTIVE_ON_DFS; + } + } + WMI_SCAN_SET_DWELL_MODE(scan_params->scan_ctrl_flags, + roam_req->roamscan_adaptive_dwell_mode); + + } else { + /* roam_req = NULL during initial or pre-assoc invocation */ + scan_params->dwell_time_active = + WMA_ROAM_DWELL_TIME_ACTIVE_DEFAULT; + scan_params->dwell_time_passive = + WMA_ROAM_DWELL_TIME_PASSIVE_DEFAULT; + scan_params->min_rest_time = WMA_ROAM_MIN_REST_TIME_DEFAULT; + scan_params->max_rest_time = WMA_ROAM_MAX_REST_TIME_DEFAULT; + scan_params->repeat_probe_time = 0; + scan_params->probe_spacing_time = 0; + scan_params->probe_delay = 0; + scan_params->max_scan_time = WMA_HW_DEF_SCAN_MAX_DURATION; + scan_params->idle_time = scan_params->min_rest_time; + scan_params->burst_duration = 0; + scan_params->n_probes = 0; + } + + WMA_LOGI("%s: Rome roam scan parameters:" + " dwell_time_active = %d, dwell_time_passive = %d", + __func__, + scan_params->dwell_time_active, + scan_params->dwell_time_passive); + WMA_LOGI("%s: min_rest_time = %d, max_rest_time = %d," + " repeat_probe_time = %d n_probes = %d", + __func__, + scan_params->min_rest_time, + scan_params->max_rest_time, + scan_params->repeat_probe_time, scan_params->n_probes); + WMA_LOGI("%s: max_scan_time = %d, idle_time = %d," + " burst_duration = %d, scan_ctrl_flags = 0x%x", + __func__, + scan_params->max_scan_time, + scan_params->idle_time, + scan_params->burst_duration, scan_params->scan_ctrl_flags); +} + +/** + * wma_roam_scan_offload_ap_profile() - set roam ap profile in fw + * @wma_handle: wma handle + * @ap_profile_p: ap profile + * @vdev_id: vdev id + * + * Send WMI_ROAM_AP_PROFILE to firmware + * + * Return: QDF status + */ +QDF_STATUS wma_roam_scan_offload_ap_profile(tp_wma_handle wma_handle, + wmi_ap_profile *ap_profile_p, + uint32_t vdev_id) +{ + return wmi_unified_send_roam_scan_offload_ap_cmd(wma_handle->wmi_handle, + ap_profile_p, vdev_id); +} + +/** + * wma_roam_scan_filter() - Filter to be applied while roaming + * @wma_handle: Global WMA Handle + * @roam_req: Request which contains the filters + * + * There are filters such as whitelist, blacklist and preferred + * list that need to be applied to the scan results to form the + * probable candidates for roaming. + * + * Return: Return success upon succesfully passing the + * parameters to the firmware, otherwise failure. + */ +static QDF_STATUS wma_roam_scan_filter(tp_wma_handle wma_handle, + tSirRoamOffloadScanReq *roam_req) +{ + int i; + QDF_STATUS status = QDF_STATUS_SUCCESS; + uint32_t num_bssid_black_list = 0, num_ssid_white_list = 0, + num_bssid_preferred_list = 0; + uint32_t op_bitmap = 0; + struct roam_ext_params *roam_params; + struct roam_scan_filter_params *params; + + params = qdf_mem_malloc(sizeof(struct roam_scan_filter_params)); + if (params == NULL) { + WMA_LOGE("%s : Memory allocation failed", __func__); + return QDF_STATUS_E_NOMEM; + } + + roam_params = &roam_req->roam_params; + if (roam_req->Command != ROAM_SCAN_OFFLOAD_STOP) { + switch (roam_req->reason) { + case REASON_ROAM_SET_BLACKLIST_BSSID: + op_bitmap |= 0x1; + num_bssid_black_list = + roam_params->num_bssid_avoid_list; + break; + case REASON_ROAM_SET_SSID_ALLOWED: + op_bitmap |= 0x2; + num_ssid_white_list = + roam_params->num_ssid_allowed_list; + break; + case REASON_ROAM_SET_FAVORED_BSSID: + op_bitmap |= 0x4; + num_bssid_preferred_list = + roam_params->num_bssid_favored; + break; + default: + WMA_LOGD("%s : Roam Filter need not be sent", __func__); + qdf_mem_free(params); + return QDF_STATUS_SUCCESS; + } + } else { + /* In case of STOP command, reset all the variables + * except for blacklist BSSID which should be retained + * across connections.*/ + op_bitmap = 0x2 | 0x4; + num_ssid_white_list = roam_params->num_ssid_allowed_list; + num_bssid_preferred_list = roam_params->num_bssid_favored; + } + + /* fill in fixed values */ + params->session_id = roam_req->sessionId; + params->op_bitmap = op_bitmap; + params->num_bssid_black_list = num_bssid_black_list; + params->num_ssid_white_list = num_ssid_white_list; + params->num_bssid_preferred_list = num_bssid_preferred_list; + qdf_mem_copy(params->bssid_avoid_list, roam_params->bssid_avoid_list, + MAX_BSSID_AVOID_LIST * sizeof(struct qdf_mac_addr)); + + for (i = 0; i < num_ssid_white_list; i++) { + qdf_mem_copy(params->ssid_allowed_list[i].mac_ssid, + roam_params->ssid_allowed_list[i].ssId, + roam_params->ssid_allowed_list[i].length); + params->ssid_allowed_list[i].length = + roam_params->ssid_allowed_list[i].length; + WMA_LOGD("%s: SSID length=%d", __func__, + params->ssid_allowed_list[i].length); + qdf_trace_hex_dump(QDF_MODULE_ID_WMA, QDF_TRACE_LEVEL_DEBUG, + (uint8_t *)params->ssid_allowed_list[i].mac_ssid, + params->ssid_allowed_list[i].length); + } + qdf_mem_copy(params->bssid_favored, roam_params->bssid_favored, + MAX_BSSID_FAVORED * sizeof(struct qdf_mac_addr)); + qdf_mem_copy(params->bssid_favored_factor, + roam_params->bssid_favored_factor, MAX_BSSID_FAVORED); + + status = wmi_unified_roam_scan_filter_cmd(wma_handle->wmi_handle, + params); + + qdf_mem_free(params); + return status; +} + +/** + * wma_roam_scan_bmiss_cnt() - set bmiss count to fw + * @wma_handle: wma handle + * @first_bcnt: first bmiss count + * @final_bcnt: final bmiss count + * @vdev_id: vdev id + * + * set first & final biss count to fw. + * + * Return: QDF status + */ +QDF_STATUS wma_roam_scan_bmiss_cnt(tp_wma_handle wma_handle, + A_INT32 first_bcnt, + A_UINT32 final_bcnt, uint32_t vdev_id) +{ + QDF_STATUS status; + + WMA_LOGI("%s: first_bcnt=%d, final_bcnt=%d", __func__, first_bcnt, + final_bcnt); + + status = wma_vdev_set_param(wma_handle->wmi_handle, + vdev_id, + WMI_VDEV_PARAM_BMISS_FIRST_BCNT, + first_bcnt); + if (QDF_IS_STATUS_ERROR(status)) { + WMA_LOGE("wma_vdev_set_param WMI_VDEV_PARAM_BMISS_FIRST_BCNT returned Error %d", + status); + return status; + } + + status = wma_vdev_set_param(wma_handle->wmi_handle, + vdev_id, + WMI_VDEV_PARAM_BMISS_FINAL_BCNT, + final_bcnt); + if (QDF_IS_STATUS_ERROR(status)) { + WMA_LOGE("wma_vdev_set_param WMI_VDEV_PARAM_BMISS_FINAL_BCNT returned Error %d", + status); + return status; + } + + return status; +} + +/** + * wma_roam_scan_offload_command() - set roam offload command + * @wma_handle: wma handle + * @command: command + * @vdev_id: vdev id + * + * This function set roam offload command to fw. + * + * Return: QDF status + */ +QDF_STATUS wma_roam_scan_offload_command(tp_wma_handle wma_handle, + uint32_t command, uint32_t vdev_id) +{ + return wmi_unified_roam_scan_offload_cmd(wma_handle->wmi_handle, + command, vdev_id); +} + +/** + * wma_process_roaming_config() - process roam request + * @wma_handle: wma handle + * @roam_req: roam request parameters + * + * Main routine to handle ROAM commands coming from CSR module. + * + * Return: QDF status + */ +QDF_STATUS wma_process_roaming_config(tp_wma_handle wma_handle, + tSirRoamOffloadScanReq *roam_req) +{ + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + wmi_start_scan_cmd_fixed_param scan_params; + wmi_ap_profile ap_profile; + tpAniSirGlobal pMac = cds_get_context(QDF_MODULE_ID_PE); + uint32_t mode = 0; + struct wma_txrx_node *intr = NULL; + + WMA_LOGI("%s: command 0x%x, reason %d", __func__, roam_req->Command, + roam_req->reason); + + if (NULL == pMac) { + WMA_LOGE("%s: pMac is NULL", __func__); + qdf_mem_free(roam_req); + return QDF_STATUS_E_FAILURE; + } + + if (!wma_handle->roam_offload_enabled) { + /* roam scan offload is not enabled in firmware. + * Cannot initialize it in the middle of connection. + */ + qdf_mem_free(roam_req); + return QDF_STATUS_E_PERM; + } + WMA_LOGD("%s: roaming in progress set to false for vdev %d", + __func__, roam_req->sessionId); + wma_handle->interfaces[roam_req->sessionId].roaming_in_progress = false; + switch (roam_req->Command) { + case ROAM_SCAN_OFFLOAD_START: + intr = &wma_handle->interfaces[roam_req->sessionId]; + intr->delay_before_vdev_stop = roam_req->delay_before_vdev_stop; + /* + * Scan/Roam threshold parameters are translated from fields of + * tSirRoamOffloadScanReq to WMITLV values sent to Rome firmware. + * some of these parameters are configurable in qcom_cfg.ini file. + */ + + /* First parameter is positive rssi value to trigger rssi based scan. + * Opportunistic scan is started at 30 dB higher that trigger rssi. + */ + wma_handle->suitable_ap_hb_failure = false; + + qdf_status = wma_roam_scan_offload_rssi_thresh(wma_handle, + roam_req); + if (qdf_status != QDF_STATUS_SUCCESS) + break; + qdf_status = wma_roam_scan_bmiss_cnt(wma_handle, + roam_req->RoamBmissFirstBcnt, + roam_req->RoamBmissFinalBcnt, + roam_req->sessionId); + if (qdf_status != QDF_STATUS_SUCCESS) + break; + + /* Opportunistic scan runs on a timer, value set by + * EmptyRefreshScanPeriod. Age out the entries after 3 such + * cycles. + */ + if (roam_req->EmptyRefreshScanPeriod > 0) { + qdf_status = + wma_roam_scan_offload_scan_period(wma_handle, + roam_req->EmptyRefreshScanPeriod, + roam_req->EmptyRefreshScanPeriod * 3, + roam_req->sessionId); + if (qdf_status != QDF_STATUS_SUCCESS) + break; + + mode = WMI_ROAM_SCAN_MODE_PERIODIC; + /* Don't use rssi triggered roam scans if external app + * is in control of channel list. + */ + if (roam_req->ChannelCacheType != CHANNEL_LIST_STATIC) + mode |= WMI_ROAM_SCAN_MODE_RSSI_CHANGE; + + } else { + mode = WMI_ROAM_SCAN_MODE_RSSI_CHANGE; + } + + /* Start new rssi triggered scan only if it changes by RoamRssiDiff value. + * Beacon weight of 14 means average rssi is taken over 14 previous samples + + * 2 times the current beacon's rssi. + */ + qdf_status = wma_roam_scan_offload_rssi_change(wma_handle, + roam_req->sessionId, + roam_req->RoamRescanRssiDiff, + roam_req->RoamBeaconRssiWeight, + roam_req->hi_rssi_scan_delay); + + if (qdf_status != QDF_STATUS_SUCCESS) + break; + + wma_roam_scan_fill_ap_profile(wma_handle, pMac, roam_req, + &ap_profile); + + qdf_status = wma_roam_scan_offload_ap_profile(wma_handle, + &ap_profile, + roam_req->sessionId); + if (qdf_status != QDF_STATUS_SUCCESS) + break; + + qdf_status = wma_roam_scan_offload_chan_list(wma_handle, + roam_req->ConnectedNetwork.ChannelCount, + &roam_req->ConnectedNetwork.ChannelCache[0], + roam_req->ChannelCacheType, + roam_req->sessionId); + if ((qdf_status != QDF_STATUS_SUCCESS) && + (qdf_status != QDF_STATUS_E_EMPTY)) + break; + + + wma_roam_scan_fill_scan_params(wma_handle, pMac, roam_req, + &scan_params); + qdf_status = + wma_roam_scan_offload_mode(wma_handle, &scan_params, + roam_req, mode, + roam_req->sessionId); + if (qdf_status != QDF_STATUS_SUCCESS) + break; + qdf_status = wma_roam_scan_filter(wma_handle, roam_req); + if (qdf_status != QDF_STATUS_SUCCESS) { + WMA_LOGE("Sending start for roam scan filter failed"); + break; + } + break; + + case ROAM_SCAN_OFFLOAD_STOP: + /* + * If roam synch propagation is in progress and an user space + * disconnect is requested, then there is no need to send the + * RSO STOP to firmware, since the roaming is already complete. + * If the RSO STOP is sent to firmware, then an HO_FAIL will be + * generated and the expectation from firmware would be to + * clean up the peer context on the host and not send down any + * WMI PEER DELETE commands to firmware. But, if the user space + * disconnect gets processed first, then there is a chance to + * send down the PEER DELETE commands. Hence, if we do not + * receive the HO_FAIL, and we complete the roam sync + * propagation, then the host and firmware will be in sync with + * respect to the peer and then the user space disconnect can + * be handled gracefully in a normal way. + * + * Ensure to check the reason code since the RSO Stop might + * come when roam sync failed as well and at that point it + * should go through to the firmware and receive HO_FAIL + * and clean up. + */ + if (wma_is_roam_synch_in_progress(wma_handle, + roam_req->sessionId) && + roam_req->reason == + REASON_ROAM_STOP_ALL) { + WMA_LOGD("Dont send RSO stop during roam sync"); + break; + } + wma_handle->suitable_ap_hb_failure = false; + if (wma_handle->roam_offload_enabled) { + uint32_t mode; + + wma_roam_scan_fill_scan_params(wma_handle, pMac, + NULL, &scan_params); + + if (roam_req->reason == REASON_ROAM_STOP_ALL) + mode = WMI_ROAM_SCAN_MODE_NONE; + else + mode = WMI_ROAM_SCAN_MODE_NONE | + WMI_ROAM_SCAN_MODE_ROAMOFFLOAD; + qdf_status = wma_roam_scan_offload_mode(wma_handle, + &scan_params, NULL, mode, + roam_req->sessionId); + } + /* + * If the STOP command is due to a disconnect, then + * send the filter command to clear all the filter + * entries. If it is roaming scenario, then do not + * send the cleared entries. + */ + if (!roam_req->middle_of_roaming) { + qdf_status = wma_roam_scan_filter(wma_handle, roam_req); + if (qdf_status != QDF_STATUS_SUCCESS) { + WMA_LOGE("clear for roam scan filter failed"); + break; + } + } + + if (roam_req->reason == + REASON_OS_REQUESTED_ROAMING_NOW) { + cds_msg_t cds_msg; + tSirRoamOffloadScanRsp *scan_offload_rsp; + scan_offload_rsp = + qdf_mem_malloc(sizeof(*scan_offload_rsp)); + if (!scan_offload_rsp) { + WMA_LOGE("%s: Alloc failed for scan_offload_rsp", + __func__); + qdf_mem_free(roam_req); + return QDF_STATUS_E_NOMEM; + } + cds_msg.type = eWNI_SME_ROAM_SCAN_OFFLOAD_RSP; + scan_offload_rsp->sessionId = roam_req->sessionId; + scan_offload_rsp->reason = roam_req->reason; + cds_msg.bodyptr = scan_offload_rsp; + /* + * Since REASSOC request is processed in + * Roam_Scan_Offload_Rsp post a dummy rsp msg back to + * SME with proper reason code. + */ + if (QDF_STATUS_SUCCESS != + cds_mq_post_message(CDS_MQ_ID_SME, + (cds_msg_t *) &cds_msg)) { + qdf_mem_free(scan_offload_rsp); + QDF_TRACE(QDF_MODULE_ID_WMA, + QDF_TRACE_LEVEL_INFO, + "%s: Failed to post Scan Offload Rsp to UMAC", + __func__); + } + } + break; + + case ROAM_SCAN_OFFLOAD_ABORT_SCAN: + /* If roam scan is running, stop that cycle. + * It will continue automatically on next trigger. + */ + qdf_status = wma_roam_scan_offload_command(wma_handle, + WMI_ROAM_SCAN_STOP_CMD, + roam_req->sessionId); + break; + + case ROAM_SCAN_OFFLOAD_RESTART: + /* Rome offload engine does not stop after any scan. + * If this command is sent because all preauth attempts failed + * and WMI_ROAM_REASON_SUITABLE_AP event was received earlier, + * now it is time to call it heartbeat failure. + */ + if ((roam_req->reason == REASON_PREAUTH_FAILED_FOR_ALL) + && wma_handle->suitable_ap_hb_failure) { + WMA_LOGE("%s: Sending heartbeat failure after preauth failures", + __func__); + wma_beacon_miss_handler(wma_handle, + roam_req->sessionId, + wma_handle->suitable_ap_hb_failure_rssi); + wma_handle->suitable_ap_hb_failure = false; + } + break; + + case ROAM_SCAN_OFFLOAD_UPDATE_CFG: + wma_handle->suitable_ap_hb_failure = false; + wma_roam_scan_fill_scan_params(wma_handle, pMac, roam_req, + &scan_params); + qdf_status = + wma_roam_scan_offload_mode(wma_handle, &scan_params, + roam_req, + WMI_ROAM_SCAN_MODE_NONE, + roam_req->sessionId); + if (qdf_status != QDF_STATUS_SUCCESS) + break; + + if (roam_req->RoamScanOffloadEnabled == false) + break; + + qdf_status = wma_roam_scan_bmiss_cnt(wma_handle, + roam_req->RoamBmissFirstBcnt, + roam_req->RoamBmissFinalBcnt, + roam_req->sessionId); + if (qdf_status != QDF_STATUS_SUCCESS) + break; + qdf_status = wma_roam_scan_filter(wma_handle, roam_req); + if (qdf_status != QDF_STATUS_SUCCESS) { + WMA_LOGE("Sending update for roam scan filter failed"); + break; + } + + + /* + * Runtime (after association) changes to rssi thresholds and + * other parameters. + */ + qdf_status = wma_roam_scan_offload_chan_list(wma_handle, + roam_req->ConnectedNetwork.ChannelCount, + &roam_req->ConnectedNetwork.ChannelCache[0], + roam_req->ChannelCacheType, + roam_req->sessionId); + /* + * Even though the channel list is empty, we can + * still go ahead and start Roaming. + */ + if ((qdf_status != QDF_STATUS_SUCCESS) && + (qdf_status != QDF_STATUS_E_EMPTY)) + break; + + + qdf_status = wma_roam_scan_offload_rssi_thresh(wma_handle, + roam_req); + if (qdf_status != QDF_STATUS_SUCCESS) + break; + + if (roam_req->EmptyRefreshScanPeriod > 0) { + qdf_status = + wma_roam_scan_offload_scan_period(wma_handle, + roam_req->EmptyRefreshScanPeriod, + roam_req->EmptyRefreshScanPeriod * 3, + roam_req->sessionId); + if (qdf_status != QDF_STATUS_SUCCESS) + break; + + mode = WMI_ROAM_SCAN_MODE_PERIODIC; + /* Don't use rssi triggered roam scans if external app + * is in control of channel list. + */ + if (roam_req->ChannelCacheType != CHANNEL_LIST_STATIC) + mode |= WMI_ROAM_SCAN_MODE_RSSI_CHANGE; + + } else { + mode = WMI_ROAM_SCAN_MODE_RSSI_CHANGE; + } + + qdf_status = wma_roam_scan_offload_rssi_change(wma_handle, + roam_req->sessionId, + roam_req->RoamRescanRssiDiff, + roam_req->RoamBeaconRssiWeight, + roam_req->hi_rssi_scan_delay); + if (qdf_status != QDF_STATUS_SUCCESS) + break; + + wma_roam_scan_fill_ap_profile(wma_handle, pMac, roam_req, + &ap_profile); + qdf_status = + wma_roam_scan_offload_ap_profile(wma_handle, &ap_profile, + roam_req->sessionId); + if (qdf_status != QDF_STATUS_SUCCESS) + break; + + wma_roam_scan_fill_scan_params(wma_handle, pMac, roam_req, + &scan_params); + qdf_status = + wma_roam_scan_offload_mode(wma_handle, &scan_params, + roam_req, mode, + roam_req->sessionId); + + break; + + default: + break; + } + qdf_mem_free(roam_req); + return qdf_status; +} + +void wma_update_per_roam_config(WMA_HANDLE handle, + struct wmi_per_roam_config_req *req_buf) +{ + int status; + tp_wma_handle wma_handle = (tp_wma_handle) handle; + + if (!wma_handle || !wma_handle->wmi_handle) { + WMA_LOGE("%s: WMA is closed, cannot send per roam config", + __func__); + return; + } + + status = wmi_unified_set_per_roam_config(wma_handle->wmi_handle, + req_buf); + if (status != EOK) + WMA_LOGE("%s: failed to set per roam config to FW", + __func__); +} + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + +/** + * wma_process_roam_invoke() - send roam invoke command to fw. + * @handle: wma handle + * @roaminvoke: roam invoke command + * + * Send roam invoke command to fw for fastreassoc. + * + * Return: none + */ +void wma_process_roam_invoke(WMA_HANDLE handle, + struct wma_roam_invoke_cmd *roaminvoke) +{ + tp_wma_handle wma_handle = (tp_wma_handle) handle; + uint32_t ch_hz; + + if (!wma_handle || !wma_handle->wmi_handle) { + WMA_LOGE("%s: WMA is closed, can not send roam invoke", + __func__); + goto free_frame_buf; + } + ch_hz = (A_UINT32)cds_chan_to_freq(roaminvoke->channel); + wmi_unified_roam_invoke_cmd(wma_handle->wmi_handle, + (struct wmi_roam_invoke_cmd *)roaminvoke, + ch_hz); +free_frame_buf: + if (roaminvoke->frame_len) { + qdf_mem_free(roaminvoke->frame_buf); + roaminvoke->frame_buf = NULL; + } + + return; +} + +/** + * wma_process_roam_synch_fail() -roam synch failure handle + * @handle: wma handle + * @synch_fail: roam synch fail parameters + * + * Return: none + */ +void wma_process_roam_synch_fail(WMA_HANDLE handle, + struct roam_offload_synch_fail *synch_fail) +{ + tp_wma_handle wma_handle = (tp_wma_handle) handle; + + if (!wma_handle || !wma_handle->wmi_handle) { + WMA_LOGE("%s: WMA is closed, can not clean-up roam synch", + __func__); + return; + } + + wma_peer_debug_log(synch_fail->session_id, DEBUG_ROAM_SYNCH_FAIL, + DEBUG_INVALID_PEER_ID, NULL, NULL, 0, 0); + + /* Hand Off Failure could happen as an exception, when a roam synch + * indication is posted to Host, but a roam synch complete is not + * posted to the firmware.So, clear the roam synch in progress + * flag before disconnecting the session through this event.*/ + wma_handle->interfaces[synch_fail->session_id].roam_synch_in_progress = + false; +} + +/** + * wma_fill_roam_synch_buffer() - Fill the the roam sync buffer + * @wma: Global WMA Handle + * @roam_synch_ind_ptr: Buffer to be filled + * @param_buf: Source buffer + * + * Firmware sends all the required information required for roam + * synch propagation as TLV's and stored in param_buf. These + * parameters are parsed and filled into the roam synch indication + * buffer which will be used at different layers for propagation. + * + * Return: Success or Failure + */ +static int wma_fill_roam_synch_buffer(tp_wma_handle wma, + roam_offload_synch_ind *roam_synch_ind_ptr, + WMI_ROAM_SYNCH_EVENTID_param_tlvs *param_buf) +{ + wmi_roam_synch_event_fixed_param *synch_event; + uint8_t *bcn_probersp_ptr; + uint8_t *reassoc_rsp_ptr; + uint8_t *reassoc_req_ptr; + wmi_channel *chan; + wmi_key_material *key; + + synch_event = param_buf->fixed_param; + roam_synch_ind_ptr->roamedVdevId = synch_event->vdev_id; + roam_synch_ind_ptr->authStatus = synch_event->auth_status; + roam_synch_ind_ptr->roamReason = synch_event->roam_reason; + roam_synch_ind_ptr->rssi = synch_event->rssi; + roam_synch_ind_ptr->isBeacon = synch_event->is_beacon; + WMI_MAC_ADDR_TO_CHAR_ARRAY(&synch_event->bssid, + roam_synch_ind_ptr->bssid.bytes); + WMA_LOGI("%s: roamedVdevId %d authStatus %d roamReason %d rssi %d" + "isBeacon %d", + __func__, + roam_synch_ind_ptr->roamedVdevId, + roam_synch_ind_ptr->authStatus, + roam_synch_ind_ptr->roamReason, + roam_synch_ind_ptr->rssi, + roam_synch_ind_ptr->isBeacon); + + if (!QDF_IS_STATUS_SUCCESS( + wma->csr_roam_synch_cb((tpAniSirGlobal)wma->mac_context, + roam_synch_ind_ptr, NULL, SIR_ROAMING_DEREGISTER_STA))) { + WMA_LOGE("LFR3: CSR Roam synch cb failed"); + return -EINVAL; + } + /* Beacon/Probe Rsp data */ + roam_synch_ind_ptr->beaconProbeRespOffset = + sizeof(roam_offload_synch_ind); + bcn_probersp_ptr = (uint8_t *) roam_synch_ind_ptr + + roam_synch_ind_ptr->beaconProbeRespOffset; + roam_synch_ind_ptr->beaconProbeRespLength = + synch_event->bcn_probe_rsp_len; + qdf_mem_copy(bcn_probersp_ptr, param_buf->bcn_probe_rsp_frame, + roam_synch_ind_ptr->beaconProbeRespLength); + /* ReAssoc Rsp data */ + roam_synch_ind_ptr->reassocRespOffset = + sizeof(roam_offload_synch_ind) + + roam_synch_ind_ptr->beaconProbeRespLength; + roam_synch_ind_ptr->reassocRespLength = synch_event->reassoc_rsp_len; + reassoc_rsp_ptr = (uint8_t *) roam_synch_ind_ptr + + roam_synch_ind_ptr->reassocRespOffset; + qdf_mem_copy(reassoc_rsp_ptr, + param_buf->reassoc_rsp_frame, + roam_synch_ind_ptr->reassocRespLength); + + /* ReAssoc Req data */ + roam_synch_ind_ptr->reassoc_req_offset = + sizeof(roam_offload_synch_ind) + + roam_synch_ind_ptr->beaconProbeRespLength + + roam_synch_ind_ptr->reassocRespLength; + roam_synch_ind_ptr->reassoc_req_length = synch_event->reassoc_req_len; + reassoc_req_ptr = (uint8_t *) roam_synch_ind_ptr + + roam_synch_ind_ptr->reassoc_req_offset; + qdf_mem_copy(reassoc_req_ptr, param_buf->reassoc_req_frame, + roam_synch_ind_ptr->reassoc_req_length); + + chan = (wmi_channel *) param_buf->chan; + roam_synch_ind_ptr->chan_freq = chan->mhz; + key = (wmi_key_material *) param_buf->key; + if (key != NULL) { + qdf_mem_copy(roam_synch_ind_ptr->kck, key->kck, + SIR_KCK_KEY_LEN); + qdf_mem_copy(roam_synch_ind_ptr->kek, key->kek, + SIR_KEK_KEY_LEN); + qdf_mem_copy(roam_synch_ind_ptr->replay_ctr, + key->replay_counter, SIR_REPLAY_CTR_LEN); + WMA_LOGD("%s: KCK dump", __func__); + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_WMA, QDF_TRACE_LEVEL_DEBUG, + key->kck, SIR_KCK_KEY_LEN); + WMA_LOGD("%s: KEK dump", __func__); + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_WMA, QDF_TRACE_LEVEL_DEBUG, + key->kek, SIR_KEK_KEY_LEN); + WMA_LOGD("%s: Key Replay Counter dump", __func__); + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_WMA, QDF_TRACE_LEVEL_DEBUG, + key->replay_counter, SIR_REPLAY_CTR_LEN); + } + if (param_buf->hw_mode_transition_fixed_param) + wma_process_pdev_hw_mode_trans_ind(wma, + param_buf->hw_mode_transition_fixed_param, + param_buf->wmi_pdev_set_hw_mode_response_vdev_mac_mapping, + &roam_synch_ind_ptr->hw_mode_trans_ind); + else + WMA_LOGD(FL("hw_mode transition fixed param is NULL")); + + return 0; +} + +/** + * wma_roam_update_vdev() - Update the STA and BSS + * @wma: Global WMA Handle + * @roam_synch_ind_ptr: Information needed for roam sync propagation + * + * This function will perform all the vdev related operations with + * respect to the self sta and the peer after roaming and completes + * the roam synch propagation with respect to WMA layer. + * + * Return: None + */ +static void wma_roam_update_vdev(tp_wma_handle wma, + roam_offload_synch_ind *roam_synch_ind_ptr) +{ + tDeleteBssParams *del_bss_params; + tDeleteStaParams *del_sta_params; + tLinkStateParams *set_link_params; + tAddStaParams *add_sta_params; + uint8_t vdev_id; + + vdev_id = roam_synch_ind_ptr->roamedVdevId; + wma->interfaces[vdev_id].nss = roam_synch_ind_ptr->nss; + del_bss_params = qdf_mem_malloc(sizeof(*del_bss_params)); + del_sta_params = qdf_mem_malloc(sizeof(*del_sta_params)); + set_link_params = qdf_mem_malloc(sizeof(*set_link_params)); + add_sta_params = qdf_mem_malloc(sizeof(*add_sta_params)); + if (!del_bss_params || !del_sta_params || + !set_link_params || !add_sta_params) { + WMA_LOGE("%s: failed to allocate memory", __func__); + return; + } + qdf_mem_zero(del_bss_params, sizeof(*del_bss_params)); + qdf_mem_zero(del_sta_params, sizeof(*del_sta_params)); + qdf_mem_zero(set_link_params, sizeof(*set_link_params)); + qdf_mem_zero(add_sta_params, sizeof(*add_sta_params)); + + del_bss_params->smesessionId = vdev_id; + del_sta_params->smesessionId = vdev_id; + qdf_mem_copy(del_bss_params->bssid, wma->interfaces[vdev_id].bssid, + IEEE80211_ADDR_LEN); + set_link_params->state = eSIR_LINK_PREASSOC_STATE; + qdf_mem_copy(set_link_params->selfMacAddr, + roam_synch_ind_ptr->self_mac.bytes, IEEE80211_ADDR_LEN); + qdf_mem_copy(set_link_params->bssid, roam_synch_ind_ptr->bssid.bytes, + IEEE80211_ADDR_LEN); + add_sta_params->staType = STA_ENTRY_SELF; + add_sta_params->smesessionId = vdev_id; + qdf_mem_copy(&add_sta_params->bssId, &roam_synch_ind_ptr->bssid.bytes, + IEEE80211_ADDR_LEN); + add_sta_params->staIdx = STA_INVALID_IDX; + add_sta_params->assocId = roam_synch_ind_ptr->aid; + + wma_delete_sta(wma, del_sta_params); + wma_delete_bss(wma, del_bss_params); + wma_set_linkstate(wma, set_link_params); + wma_add_bss(wma, (tpAddBssParams)roam_synch_ind_ptr->add_bss_params); + wma_add_sta(wma, add_sta_params); + wma->interfaces[vdev_id].vdev_up = true; + qdf_mem_copy(wma->interfaces[vdev_id].bssid, + roam_synch_ind_ptr->bssid.bytes, IEEE80211_ADDR_LEN); + qdf_mem_free(del_bss_params); + qdf_mem_free(del_sta_params); + qdf_mem_free(set_link_params); + qdf_mem_free(add_sta_params); +} + +/** + * wma_roam_synch_event_handler() - roam synch event handler + * @handle: wma handle + * @event: event data + * @len: length of data + * + * This function is roam synch event handler. It sends roam + * indication for upper layer. + * + * Return: Success or Failure status + */ +int wma_roam_synch_event_handler(void *handle, uint8_t *event, + uint32_t len) +{ + WMI_ROAM_SYNCH_EVENTID_param_tlvs *param_buf = NULL; + wmi_roam_synch_event_fixed_param *synch_event = NULL; + tp_wma_handle wma = (tp_wma_handle) handle; + roam_offload_synch_ind *roam_synch_ind_ptr = NULL; + tpSirBssDescription bss_desc_ptr = NULL; + uint16_t ie_len = 0; + int status = -EINVAL; + tSirRoamOffloadScanReq *roam_req; + qdf_time_t roam_synch_received = qdf_get_system_timestamp(); + + WMA_LOGD("LFR3:%s", __func__); + if (!event) { + WMA_LOGE("%s: event param null", __func__); + goto cleanup_label; + } + + param_buf = (WMI_ROAM_SYNCH_EVENTID_param_tlvs *) event; + if (!param_buf) { + WMA_LOGE("%s: received null buf from target", __func__); + goto cleanup_label; + } + + synch_event = param_buf->fixed_param; + if (!synch_event) { + WMA_LOGE("%s: received null event data from target", __func__); + goto cleanup_label; + } + + wma_peer_debug_log(synch_event->vdev_id, DEBUG_ROAM_SYNCH_IND, + DEBUG_INVALID_PEER_ID, NULL, NULL, + synch_event->bssid.mac_addr31to0, + synch_event->bssid.mac_addr47to32); + + DPTRACE(qdf_dp_trace_record_event(QDF_DP_TRACE_EVENT_RECORD, + synch_event->vdev_id, QDF_PROTO_TYPE_EVENT, QDF_ROAM_SYNCH)); + + if (wma_is_roam_synch_in_progress(wma, synch_event->vdev_id)) { + WMA_LOGE("%s: Ignoring RSI since one is already in progress", + __func__); + goto cleanup_label; + } + WMA_LOGE("LFR3: Received WMA_ROAM_OFFLOAD_SYNCH_IND"); + + qdf_wake_lock_timeout_acquire(&wma->wow_wake_lock, + WMA_ROAM_HO_WAKE_LOCK_DURATION); + + wma->interfaces[synch_event->vdev_id].roam_synch_in_progress = true; + len = sizeof(roam_offload_synch_ind) + + synch_event->bcn_probe_rsp_len + synch_event->reassoc_rsp_len + + synch_event->reassoc_req_len; + roam_synch_ind_ptr = (roam_offload_synch_ind *)qdf_mem_malloc(len); + if (!roam_synch_ind_ptr) { + WMA_LOGE("%s: failed to allocate memory for roam_synch_event", + __func__); + QDF_ASSERT(roam_synch_ind_ptr != NULL); + status = -ENOMEM; + goto cleanup_label; + } + qdf_mem_zero(roam_synch_ind_ptr, len); + status = wma_fill_roam_synch_buffer(wma, + roam_synch_ind_ptr, param_buf); + if (status != 0) + goto cleanup_label; + /* 24 byte MAC header and 12 byte to ssid IE */ + if (roam_synch_ind_ptr->beaconProbeRespLength > + (SIR_MAC_HDR_LEN_3A + SIR_MAC_B_PR_SSID_OFFSET)) { + ie_len = roam_synch_ind_ptr->beaconProbeRespLength - + (SIR_MAC_HDR_LEN_3A + SIR_MAC_B_PR_SSID_OFFSET); + } else { + WMA_LOGE("LFR3: Invalid Beacon Length"); + goto cleanup_label; + } + bss_desc_ptr = qdf_mem_malloc(sizeof(tSirBssDescription) + ie_len); + if (NULL == bss_desc_ptr) { + WMA_LOGE("LFR3: mem alloc failed!"); + QDF_ASSERT(bss_desc_ptr != NULL); + status = -ENOMEM; + goto cleanup_label; + } + qdf_mem_zero(bss_desc_ptr, sizeof(tSirBssDescription) + ie_len); + if (QDF_IS_STATUS_ERROR(wma->pe_roam_synch_cb( + (tpAniSirGlobal)wma->mac_context, + roam_synch_ind_ptr, bss_desc_ptr))) { + WMA_LOGE("LFR3: PE roam synch cb failed"); + status = -EBUSY; + goto cleanup_label; + } + + wma_roam_update_vdev(wma, roam_synch_ind_ptr); + wma->csr_roam_synch_cb((tpAniSirGlobal)wma->mac_context, + roam_synch_ind_ptr, bss_desc_ptr, SIR_ROAM_SYNCH_PROPAGATION); + wma_process_roam_synch_complete(wma, synch_event->vdev_id); + + /* update freq and channel width */ + wma->interfaces[synch_event->vdev_id].mhz = + roam_synch_ind_ptr->chan_freq; + if (roam_synch_ind_ptr->join_rsp) + wma->interfaces[synch_event->vdev_id].chan_width = + roam_synch_ind_ptr->join_rsp->vht_channel_width; + + wma->csr_roam_synch_cb((tpAniSirGlobal)wma->mac_context, + roam_synch_ind_ptr, bss_desc_ptr, SIR_ROAM_SYNCH_COMPLETE); + wma->interfaces[synch_event->vdev_id].roam_synch_delay = + qdf_get_system_timestamp() - roam_synch_received; + WMA_LOGD("LFR3: roam_synch_delay:%d", + wma->interfaces[synch_event->vdev_id].roam_synch_delay); + wma->csr_roam_synch_cb((tpAniSirGlobal)wma->mac_context, + roam_synch_ind_ptr, bss_desc_ptr, SIR_ROAM_SYNCH_NAPI_OFF); + + status = 0; + +cleanup_label: + if (status != 0) { + if (roam_synch_ind_ptr) + wma->csr_roam_synch_cb((tpAniSirGlobal)wma->mac_context, + roam_synch_ind_ptr, NULL, SIR_ROAMING_ABORT); + roam_req = qdf_mem_malloc(sizeof(tSirRoamOffloadScanReq)); + if (roam_req && synch_event) { + roam_req->Command = ROAM_SCAN_OFFLOAD_STOP; + roam_req->reason = REASON_ROAM_SYNCH_FAILED; + roam_req->sessionId = synch_event->vdev_id; + wma_process_roaming_config(wma, roam_req); + } + } + if (roam_synch_ind_ptr && roam_synch_ind_ptr->join_rsp) + qdf_mem_free(roam_synch_ind_ptr->join_rsp); + if (roam_synch_ind_ptr) + qdf_mem_free(roam_synch_ind_ptr); + if (bss_desc_ptr) + qdf_mem_free(bss_desc_ptr); + if (wma && synch_event) + wma->interfaces[synch_event->vdev_id].roam_synch_in_progress = + false; + + return status; +} + +/** + * wma_roam_scan_fill_self_caps() - fill capabilities + * @wma_handle: wma handle + * @roam_offload_params: offload parameters + * @roam_req: roam request + * + * This function fills roam self capablities. + * + * Return: QDF status + */ +QDF_STATUS wma_roam_scan_fill_self_caps(tp_wma_handle wma_handle, + roam_offload_param * + roam_offload_params, + tSirRoamOffloadScanReq *roam_req) +{ + struct sAniSirGlobal *pMac = NULL; + tSirMacCapabilityInfo selfCaps; + uint32_t val = 0; + uint32_t nCfgValue; + uint16_t *pCfgValue16; + uint8_t nCfgValue8, *pCfgValue8; + tSirMacQosInfoStation macQosInfoSta; + union { + uint16_t nCfgValue16; + tSirMacHTCapabilityInfo htCapInfo; + tSirMacExtendedHTCapabilityInfo extHtCapInfo; + } uHTCapabilityInfo; + + qdf_mem_set(&macQosInfoSta, sizeof(tSirMacQosInfoStation), 0); + /* Roaming is done only for INFRA STA type. + * So, ess will be one and ibss will be Zero */ + pMac = cds_get_context(QDF_MODULE_ID_PE); + if (!pMac) { + WMA_LOGE("%s:NULL pMac ptr. Exiting", __func__); + QDF_ASSERT(0); + return QDF_STATUS_E_FAILURE; + } + + if (wlan_cfg_get_int(pMac, WNI_CFG_PRIVACY_ENABLED, &val) != eSIR_SUCCESS) { + QDF_TRACE(QDF_MODULE_ID_WMA, QDF_TRACE_LEVEL_ERROR, + "Failed to get WNI_CFG_PRIVACY_ENABLED"); + return QDF_STATUS_E_FAILURE; + } + selfCaps.ess = 1; + selfCaps.ibss = 0; + if (val) + selfCaps.privacy = 1; + if (wlan_cfg_get_int(pMac, WNI_CFG_SHORT_PREAMBLE, &val) != eSIR_SUCCESS) { + QDF_TRACE(QDF_MODULE_ID_WMA, QDF_TRACE_LEVEL_ERROR, + "Failed to get WNI_CFG_SHORT_PREAMBLE"); + return QDF_STATUS_E_FAILURE; + } + if (val) + selfCaps.shortPreamble = 1; + + selfCaps.pbcc = 0; + selfCaps.channelAgility = 0; + if (wlan_cfg_get_int(pMac, WNI_CFG_11G_SHORT_SLOT_TIME_ENABLED, + &val) != eSIR_SUCCESS) { + QDF_TRACE(QDF_MODULE_ID_WMA, QDF_TRACE_LEVEL_ERROR, + "Failed to get WNI_CFG_11G_SHORT_SLOT_TIME_ENABLED"); + return QDF_STATUS_E_FAILURE; + } + if (val) + selfCaps.shortSlotTime = 1; + if (wlan_cfg_get_int(pMac, WNI_CFG_11H_ENABLED, &val) != eSIR_SUCCESS) { + QDF_TRACE(QDF_MODULE_ID_WMA, QDF_TRACE_LEVEL_ERROR, + "Failed to get WNI_CFG_11H_ENABLED"); + return QDF_STATUS_E_FAILURE; + } + if (val) + selfCaps.spectrumMgt = 1; + if (wlan_cfg_get_int(pMac, WNI_CFG_QOS_ENABLED, &val) != eSIR_SUCCESS) { + QDF_TRACE(QDF_MODULE_ID_WMA, QDF_TRACE_LEVEL_ERROR, + "Failed to get WNI_CFG_QOS_ENABLED"); + return QDF_STATUS_E_FAILURE; + } + if (val) + selfCaps.qos = 1; + if (wlan_cfg_get_int(pMac, WNI_CFG_APSD_ENABLED, &val) != eSIR_SUCCESS) { + QDF_TRACE(QDF_MODULE_ID_WMA, QDF_TRACE_LEVEL_ERROR, + "Failed to get WNI_CFG_APSD_ENABLED"); + return QDF_STATUS_E_FAILURE; + } + if (val) + selfCaps.apsd = 1; + + selfCaps.rrm = pMac->rrm.rrmSmeContext.rrmConfig.rrm_enabled; + + if (wlan_cfg_get_int(pMac, WNI_CFG_BLOCK_ACK_ENABLED, &val) != + eSIR_SUCCESS) { + QDF_TRACE(QDF_MODULE_ID_WMA, QDF_TRACE_LEVEL_ERROR, + "Failed to get WNI_CFG_BLOCK_ACK_ENABLED"); + return QDF_STATUS_E_FAILURE; + } + selfCaps.delayedBA = + (uint16_t) ((val >> WNI_CFG_BLOCK_ACK_ENABLED_DELAYED) & 1); + selfCaps.immediateBA = + (uint16_t) ((val >> WNI_CFG_BLOCK_ACK_ENABLED_IMMEDIATE) & 1); + pCfgValue16 = (uint16_t *) &selfCaps; + roam_offload_params->capability = (*pCfgValue16) & 0xFFFF; + + if (wlan_cfg_get_int(pMac, WNI_CFG_HT_CAP_INFO, &nCfgValue) != + eSIR_SUCCESS) { + QDF_TRACE(QDF_MODULE_ID_WMA, QDF_TRACE_LEVEL_ERROR, + "Failed to get WNI_CFG_HT_CAP_INFO"); + return QDF_STATUS_E_FAILURE; + } + uHTCapabilityInfo.nCfgValue16 = nCfgValue & 0xFFFF; + roam_offload_params->ht_caps_info = + uHTCapabilityInfo.nCfgValue16 & 0xFFFF; + if (wlan_cfg_get_int(pMac, WNI_CFG_HT_AMPDU_PARAMS, &nCfgValue) != + eSIR_SUCCESS) { + QDF_TRACE(QDF_MODULE_ID_WMA, QDF_TRACE_LEVEL_ERROR, + "Failed to get WNI_CFG_HT_AMPDU_PARAMS"); + return QDF_STATUS_E_FAILURE; + } + /* tSirMacHTParametersInfo */ + nCfgValue8 = (uint8_t) nCfgValue; + roam_offload_params->ampdu_param = (nCfgValue8) & 0xFF; + + val = ROAM_OFFLOAD_NUM_MCS_SET; + if (wlan_cfg_get_str(pMac, WNI_CFG_SUPPORTED_MCS_SET, + (uint8_t *) roam_offload_params->mcsset, + &val) != eSIR_SUCCESS) { + QDF_TRACE(QDF_MODULE_ID_WMA, QDF_TRACE_LEVEL_ERROR, + "Failed to get WNI_CFG_SUPPORTED_MCS_SET"); + return QDF_STATUS_E_FAILURE; + } + if (wlan_cfg_get_int(pMac, WNI_CFG_EXT_HT_CAP_INFO, &nCfgValue) != + eSIR_SUCCESS) { + QDF_TRACE(QDF_MODULE_ID_WMA, QDF_TRACE_LEVEL_ERROR, + "Failed to get WNI_CFG_EXT_HT_CAP_INFO"); + return QDF_STATUS_E_FAILURE; + } + /* uHTCapabilityInfo.extHtCapInfo */ + uHTCapabilityInfo.nCfgValue16 = nCfgValue & 0xFFFF; + roam_offload_params->ht_ext_cap = + uHTCapabilityInfo.nCfgValue16 & 0xFFFF; + + if (wlan_cfg_get_int(pMac, WNI_CFG_TX_BF_CAP, &nCfgValue) != eSIR_SUCCESS) { + QDF_TRACE(QDF_MODULE_ID_WMA, QDF_TRACE_LEVEL_ERROR, + "Failed to get WNI_CFG_TX_BF_CAP"); + return QDF_STATUS_E_FAILURE; + } + /* tSirMacTxBFCapabilityInfo */ + nCfgValue8 = (uint8_t) nCfgValue; + roam_offload_params->ht_txbf = nCfgValue8 & 0xFF; + if (wlan_cfg_get_int(pMac, WNI_CFG_AS_CAP, &nCfgValue) != eSIR_SUCCESS) { + QDF_TRACE(QDF_MODULE_ID_WMA, QDF_TRACE_LEVEL_ERROR, + "Failed to get WNI_CFG_AS_CAP"); + return QDF_STATUS_E_FAILURE; + } + /* tSirMacASCapabilityInfo */ + nCfgValue8 = (uint8_t) nCfgValue; + roam_offload_params->asel_cap = nCfgValue8 & 0xFF; + + /* QOS Info */ + if (wlan_cfg_get_int(pMac, WNI_CFG_MAX_SP_LENGTH, &nCfgValue) != + eSIR_SUCCESS) { + QDF_TRACE(QDF_MODULE_ID_WMA, QDF_TRACE_LEVEL_ERROR, + "Failed to get WNI_CFG_MAX_SP_LENGTH"); + return QDF_STATUS_E_FAILURE; + } + nCfgValue8 = (uint8_t) nCfgValue; + macQosInfoSta.maxSpLen = nCfgValue8; + macQosInfoSta.moreDataAck = 0; + macQosInfoSta.qack = 0; + macQosInfoSta.acbe_uapsd = roam_req->AcUapsd.acbe_uapsd; + macQosInfoSta.acbk_uapsd = roam_req->AcUapsd.acbk_uapsd; + macQosInfoSta.acvi_uapsd = roam_req->AcUapsd.acvi_uapsd; + macQosInfoSta.acvo_uapsd = roam_req->AcUapsd.acvo_uapsd; + pCfgValue8 = (uint8_t *) &macQosInfoSta; + /* macQosInfoSta Only queue_request is set.Refer to + * populate_dot11f_wmm_caps for more details + */ + roam_offload_params->qos_caps = (*pCfgValue8) & 0xFF; + if (roam_offload_params->qos_caps) + roam_offload_params->qos_enabled = true; + roam_offload_params->wmm_caps = 0x4 & 0xFF; + return QDF_STATUS_SUCCESS; +} + +/** + * wma_set_ric_req() - set ric request element + * @wma: wma handle + * @msg: message + * @is_add_ts: is addts required + * + * This function sets ric request element for 11r roaming. + * + * Return: none + */ +void wma_set_ric_req(tp_wma_handle wma, void *msg, uint8_t is_add_ts) +{ + if (!wma) { + WMA_LOGE("%s: wma handle is NULL", __func__); + return; + } + + wmi_unified_set_ric_req_cmd(wma->wmi_handle, msg, is_add_ts); + + return; +} +#endif /* WLAN_FEATURE_ROAM_OFFLOAD */ + +/** + * wma_rssi_breached_event_handler() - rssi breached event handler + * @handle: wma handle + * @cmd_param_info: event handler data + * @len: length of @cmd_param_info + * + * Return: 0 on success; error number otherwise + */ +int wma_rssi_breached_event_handler(void *handle, + u_int8_t *cmd_param_info, u_int32_t len) +{ + WMI_RSSI_BREACH_EVENTID_param_tlvs *param_buf; + wmi_rssi_breach_event_fixed_param *event; + struct rssi_breach_event rssi; + tpAniSirGlobal mac = cds_get_context(QDF_MODULE_ID_PE); + + if (!mac) { + WMA_LOGE("%s: Invalid mac context", __func__); + return -EINVAL; + } + if (!mac->sme.rssi_threshold_breached_cb) { + WMA_LOGE("%s: Callback not registered", __func__); + return -EINVAL; + } + param_buf = (WMI_RSSI_BREACH_EVENTID_param_tlvs *)cmd_param_info; + if (!param_buf) { + WMA_LOGE("%s: Invalid rssi breached event", __func__); + return -EINVAL; + } + event = param_buf->fixed_param; + + rssi.request_id = event->request_id; + rssi.session_id = event->vdev_id; + rssi.curr_rssi = event->rssi + WMA_TGT_NOISE_FLOOR_DBM; + WMI_MAC_ADDR_TO_CHAR_ARRAY(&event->bssid, rssi.curr_bssid.bytes); + + WMA_LOGD("%s: req_id: %u vdev_id: %d curr_rssi: %d", __func__, + rssi.request_id, rssi.session_id, rssi.curr_rssi); + WMA_LOGI("%s: curr_bssid: %pM", __func__, rssi.curr_bssid.bytes); + + mac->sme.rssi_threshold_breached_cb(mac->hHdd, &rssi); + WMA_LOGD("%s: Invoke HDD rssi breached callback", __func__); + return 0; +} + +/** + * wma_process_unit_test_cmd() - send unit test command to fw. + * @handle: wma handle + * @wma_utest: unit test command + * + * This function send unit test command to fw. + * + * Return: none + */ +void wma_process_unit_test_cmd(WMA_HANDLE handle, + t_wma_unit_test_cmd *wma_utest) +{ + tp_wma_handle wma_handle = (tp_wma_handle) handle; + + if (!wma_handle || !wma_handle->wmi_handle) { + WMA_LOGE("%s: WMA is closed, can not issue fw unit test cmd", + __func__); + return; + } + + if (wmi_unified_unit_test_cmd(wma_handle->wmi_handle, + (struct wmi_unit_test_cmd *)wma_utest)) { + return; + } + + return; +} + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +/** + * wma_roam_ho_fail_handler() - LFR3.0 roam hand off failed handler + * @wma: wma handle + * @vdev_id: vdev id + * + * Return: none + */ +static void wma_roam_ho_fail_handler(tp_wma_handle wma, uint32_t vdev_id) +{ + tSirSmeHOFailureInd *ho_failure_ind; + cds_msg_t sme_msg = { 0 }; + QDF_STATUS qdf_status; + + ho_failure_ind = qdf_mem_malloc(sizeof(tSirSmeHOFailureInd)); + + if (NULL == ho_failure_ind) { + WMA_LOGE("%s: Memory allocation failure", __func__); + return; + } + ho_failure_ind->sessionId = vdev_id; + sme_msg.type = eWNI_SME_HO_FAIL_IND; + sme_msg.bodyptr = ho_failure_ind; + sme_msg.bodyval = 0; + + qdf_status = cds_mq_post_message(QDF_MODULE_ID_SME, &sme_msg); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + WMA_LOGE("Fail to post eWNI_SME_HO_FAIL_IND msg to SME"); + qdf_mem_free(ho_failure_ind); + return; + } + return; +} + +/** + * wma_process_roam_synch_complete() - roam synch complete command to fw. + * @handle: wma handle + * @synchcnf: offload synch confirmation params + * + * This function sends roam synch complete event to fw. + * + * Return: none + */ +void wma_process_roam_synch_complete(WMA_HANDLE handle, uint8_t vdev_id) +{ + tp_wma_handle wma_handle = (tp_wma_handle) handle; + + if (!wma_handle || !wma_handle->wmi_handle) { + WMA_LOGE("%s: WMA is closed, can not issue roam synch cnf", + __func__); + return; + } + + if (wmi_unified_roam_synch_complete_cmd(wma_handle->wmi_handle, + vdev_id)) { + return; + } + + DPTRACE(qdf_dp_trace_record_event(QDF_DP_TRACE_EVENT_RECORD, + vdev_id, QDF_PROTO_TYPE_EVENT, QDF_ROAM_COMPLETE)); + + wma_peer_debug_log(vdev_id, DEBUG_ROAM_SYNCH_CNF, + DEBUG_INVALID_PEER_ID, NULL, NULL, 0, 0); + + WMA_LOGE("LFR3: Posting WMA_ROAM_OFFLOAD_SYNCH_CNF"); + return; +} +#endif /* WLAN_FEATURE_ROAM_OFFLOAD */ + +/** + * wma_switch_channel() - WMA api to switch channel dynamically + * @wma: Pointer of WMA context + * @req: Pointer vdev_start having channel switch info. + * + * Return: 0 for success, otherwise appropriate error code + */ +static QDF_STATUS wma_switch_channel(tp_wma_handle wma, + struct wma_vdev_start_req *req) +{ + + wmi_buf_t buf; + wmi_channel *cmd; + int32_t len, ret; + WLAN_PHY_MODE chanmode; + struct wma_txrx_node *intr = wma->interfaces; + tpAniSirGlobal pmac; + + pmac = cds_get_context(QDF_MODULE_ID_PE); + + if (pmac == NULL) { + WMA_LOGE("%s: vdev start failed as pmac is NULL", __func__); + return QDF_STATUS_E_FAILURE; + } + + len = sizeof(*cmd); + buf = wmi_buf_alloc(wma->wmi_handle, len); + if (!buf) { + WMA_LOGE("%s : wmi_buf_alloc failed", __func__); + return QDF_STATUS_E_NOMEM; + } + cmd = (wmi_channel *)wmi_buf_data(buf); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_channel, + WMITLV_GET_STRUCT_TLVLEN(wmi_channel)); + + /* Fill channel info */ + cmd->mhz = cds_chan_to_freq(req->chan); + chanmode = wma_chan_phy_mode(req->chan, req->chan_width, + req->dot11_mode); + + intr[req->vdev_id].chanmode = chanmode; /* save channel mode */ + intr[req->vdev_id].ht_capable = req->ht_capable; + intr[req->vdev_id].vht_capable = req->vht_capable; + intr[req->vdev_id].config.gtx_info.gtxRTMask[0] = + CFG_TGT_DEFAULT_GTX_HT_MASK; + intr[req->vdev_id].config.gtx_info.gtxRTMask[1] = + CFG_TGT_DEFAULT_GTX_VHT_MASK; + + if (wlan_cfg_get_int(pmac, WNI_CFG_TGT_GTX_USR_CFG, + &intr[req->vdev_id].config.gtx_info.gtxUsrcfg) != eSIR_SUCCESS) { + intr[req->vdev_id].config.gtx_info.gtxUsrcfg = + WNI_CFG_TGT_GTX_USR_CFG_STADEF; + QDF_TRACE(QDF_MODULE_ID_WMA, QDF_TRACE_LEVEL_WARN, + "Failed to get WNI_CFG_TGT_GTX_USR_CFG"); + } + + intr[req->vdev_id].config.gtx_info.gtxPERThreshold = + CFG_TGT_DEFAULT_GTX_PER_THRESHOLD; + intr[req->vdev_id].config.gtx_info.gtxPERMargin = + CFG_TGT_DEFAULT_GTX_PER_MARGIN; + intr[req->vdev_id].config.gtx_info.gtxTPCstep = + CFG_TGT_DEFAULT_GTX_TPC_STEP; + intr[req->vdev_id].config.gtx_info.gtxTPCMin = + CFG_TGT_DEFAULT_GTX_TPC_MIN; + intr[req->vdev_id].config.gtx_info.gtxBWMask = + CFG_TGT_DEFAULT_GTX_BW_MASK; + intr[req->vdev_id].mhz = cmd->mhz; + + WMI_SET_CHANNEL_MODE(cmd, chanmode); + cmd->band_center_freq1 = cmd->mhz; + + if (chanmode == MODE_11AC_VHT80) + cmd->band_center_freq1 = + cds_chan_to_freq(req->ch_center_freq_seg0); + + if ((chanmode == MODE_11NA_HT40) || (chanmode == MODE_11NG_HT40) || + (chanmode == MODE_11AC_VHT40)) { + if (req->chan_width == CH_WIDTH_80MHZ) + cmd->band_center_freq1 += 10; + else + cmd->band_center_freq1 -= 10; + } + cmd->band_center_freq2 = 0; + + /* Set half or quarter rate WMI flags */ + if (req->is_half_rate) + WMI_SET_CHANNEL_FLAG(cmd, WMI_CHAN_FLAG_HALF_RATE); + else if (req->is_quarter_rate) + WMI_SET_CHANNEL_FLAG(cmd, WMI_CHAN_FLAG_QUARTER_RATE); + + /* Find out min, max and regulatory power levels */ + WMI_SET_CHANNEL_REG_POWER(cmd, req->max_txpow); + WMI_SET_CHANNEL_MAX_TX_POWER(cmd, req->max_txpow); + + + WMA_LOGE("%s: freq %d channel %d chanmode %d center_chan %d center_freq2 %d reg_info_1: 0x%x reg_info_2: 0x%x, req->max_txpow: 0x%x", + __func__, cmd->mhz, req->chan, chanmode, + cmd->band_center_freq1, cmd->band_center_freq2, + cmd->reg_info_1, cmd->reg_info_2, req->max_txpow); + + + ret = wmi_unified_cmd_send(wma->wmi_handle, buf, len, + WMI_PDEV_SET_CHANNEL_CMDID); + + if (ret < 0) { + WMA_LOGP("%s: Failed to send vdev start command", __func__); + wmi_buf_free(buf); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * wma_set_channel() - set channel + * @wma: wma handle + * @params: switch channel parameters + * + * Return: none + */ +void wma_set_channel(tp_wma_handle wma, tpSwitchChannelParams params) +{ + struct wma_vdev_start_req req; + struct wma_target_req *msg; + QDF_STATUS status = QDF_STATUS_SUCCESS; + uint8_t vdev_id, peer_id; + ol_txrx_peer_handle peer; + ol_txrx_pdev_handle pdev; + struct wma_txrx_node *intr = wma->interfaces; + struct sir_hw_mode_params hw_mode = {0}; + + WMA_LOGD("%s: Enter", __func__); + if (!wma_find_vdev_by_addr(wma, params->selfStaMacAddr, &vdev_id)) { + WMA_LOGP("%s: Failed to find vdev id for %pM", + __func__, params->selfStaMacAddr); + status = QDF_STATUS_E_FAILURE; + goto send_resp; + } + pdev = cds_get_context(QDF_MODULE_ID_TXRX); + if (NULL == pdev) { + WMA_LOGE("%s: Failed to get pdev", __func__); + status = QDF_STATUS_E_FAILURE; + goto send_resp; + } + + peer = ol_txrx_find_peer_by_addr(pdev, intr[vdev_id].bssid, &peer_id); + + qdf_mem_zero(&req, sizeof(req)); + req.vdev_id = vdev_id; + req.chan = params->channelNumber; + req.chan_width = params->ch_width; + + if (params->ch_width == CH_WIDTH_10MHZ) + req.is_half_rate = 1; + else if (params->ch_width == CH_WIDTH_5MHZ) + req.is_quarter_rate = 1; + + req.vht_capable = params->vhtCapable; + req.ch_center_freq_seg0 = params->ch_center_freq_seg0; + req.ch_center_freq_seg1 = params->ch_center_freq_seg1; + req.dot11_mode = params->dot11_mode; + status = wma_get_current_hw_mode(&hw_mode); + if (!QDF_IS_STATUS_SUCCESS(status)) + WMA_LOGE("wma_get_current_hw_mode failed"); + + if ((params->nss == 2) && !hw_mode.dbs_cap) { + req.preferred_rx_streams = 2; + req.preferred_tx_streams = 2; + } else { + req.preferred_rx_streams = 1; + req.preferred_tx_streams = 1; + } + + req.max_txpow = params->maxTxPower; + req.beacon_intval = 100; + req.dtim_period = 1; + req.is_dfs = params->isDfsChannel; + + /* In case of AP mode, once radar is detected, we need to + * issuse VDEV RESTART, so we making is_channel_switch as + * true + */ + if ((wma_is_vdev_in_ap_mode(wma, req.vdev_id) == true) || + (params->restart_on_chan_switch == true)) + wma->interfaces[req.vdev_id].is_channel_switch = true; + + if (params->restart_on_chan_switch == true && + wma->interfaces[req.vdev_id].beacon_filter_enabled) + wma_remove_beacon_filter(wma, + &wma->interfaces[req.vdev_id].beacon_filter); + + if (QDF_GLOBAL_MONITOR_MODE == cds_get_conparam() && + wma_is_vdev_up(vdev_id)) { + status = wma_switch_channel(wma, &req); + if (status != QDF_STATUS_SUCCESS) + WMA_LOGE("%s: wma_switch_channel failed %d\n", __func__, + status); + + ol_htt_mon_note_chan(pdev, req.chan); + goto send_resp; + } else { + + msg = wma_fill_vdev_req(wma, req.vdev_id, WMA_CHNL_SWITCH_REQ, + WMA_TARGET_REQ_TYPE_VDEV_START, params, + WMA_VDEV_START_REQUEST_TIMEOUT); + if (!msg) { + WMA_LOGP("%s: Failed to fill channel switch request for vdev %d", + __func__, req.vdev_id); + status = QDF_STATUS_E_NOMEM; + goto send_resp; + } + status = wma_vdev_start(wma, &req, + wma->interfaces[req.vdev_id].is_channel_switch); + if (status != QDF_STATUS_SUCCESS) { + wma_remove_vdev_req(wma, req.vdev_id, + WMA_TARGET_REQ_TYPE_VDEV_START); + WMA_LOGP("%s: vdev start failed status = %d", __func__, status); + goto send_resp; + } + + if (QDF_GLOBAL_MONITOR_MODE == cds_get_conparam()) + ol_htt_mon_note_chan(pdev, req.chan); + } + return; +send_resp: + WMA_LOGD("%s: channel %d ch_width %d txpower %d status %d", __func__, + params->channelNumber, params->ch_width, + params->maxTxPower, + status); + params->status = status; + WMA_LOGI("%s: sending WMA_SWITCH_CHANNEL_RSP, status = 0x%x", + __func__, status); + wma_send_msg(wma, WMA_SWITCH_CHANNEL_RSP, (void *)params, 0); +} + +#ifdef FEATURE_WLAN_SCAN_PNO +/** + * wma_set_pno_channel_prediction() - Set PNO configuration + * @buf_ptr: Buffer passed by upper layers + * @pno: Buffer to be sent to the firmware + * + * Copy the PNO Channel prediction configuration parameters + * passed by the upper layers to a WMI format TLV and send it + * down to the firmware. + * + * Return: None + */ +void wma_set_pno_channel_prediction(uint8_t *buf_ptr, + tpSirPNOScanReq pno) +{ + nlo_channel_prediction_cfg *channel_prediction_cfg = + (nlo_channel_prediction_cfg *) buf_ptr; + WMITLV_SET_HDR(&channel_prediction_cfg->tlv_header, + WMITLV_TAG_ARRAY_BYTE, + WMITLV_GET_STRUCT_TLVLEN(nlo_channel_prediction_cfg)); + channel_prediction_cfg->enable = pno->pno_channel_prediction; + channel_prediction_cfg->top_k_num = pno->top_k_num_of_channels; + channel_prediction_cfg->stationary_threshold = pno->stationary_thresh; + channel_prediction_cfg->full_scan_period_ms = + pno->channel_prediction_full_scan; + buf_ptr += sizeof(nlo_channel_prediction_cfg); + WMA_LOGD("enable: %d, top_k_num: %d, stat_thresh: %d, full_scan: %d", + channel_prediction_cfg->enable, + channel_prediction_cfg->top_k_num, + channel_prediction_cfg->stationary_threshold, + channel_prediction_cfg->full_scan_period_ms); +} +/** + * wma_pno_start() - PNO start request + * @wma: wma handle + * @pno: PNO request + * + * This function request FW to start PNO request. + * Request: QDF status + */ +QDF_STATUS wma_pno_start(tp_wma_handle wma, tpSirPNOScanReq pno) +{ + struct pno_scan_req_params *params; + uint32_t i; + uint32_t num_channels; + uint32_t *channel_list = NULL; + QDF_STATUS status; + + WMA_LOGD("PNO Start"); + + num_channels = (uint32_t) QDF_MIN(pno->aNetworks[0].ucChannelCount, + WMI_NLO_MAX_CHAN); + + if (num_channels) { + channel_list = qdf_mem_malloc(sizeof(uint32_t) * num_channels); + if (!channel_list) + return QDF_STATUS_E_FAILURE; + + for (i = 0; i < num_channels; i++) { + channel_list[i] = pno->aNetworks[0].aChannels[i]; + + if (channel_list[i] < WMA_NLO_FREQ_THRESH) + channel_list[i] = + cds_chan_to_freq(channel_list[i]); + } + } + + params = qdf_mem_malloc(sizeof(struct pno_scan_req_params)); + if (params == NULL) { + WMA_LOGE("%s : Memory allocation failed", __func__); + status = QDF_STATUS_E_NOMEM; + goto exit_pno_start; + } + + params->enable = pno->enable; + params->modePNO = (enum pno_mode) pno->modePNO; + params->ucNetworksCount = pno->ucNetworksCount; + params->do_passive_scan = pno->do_passive_scan; + params->sessionId = pno->sessionId; + params->fast_scan_period = pno->fast_scan_period; + params->slow_scan_period = pno->slow_scan_period; + params->fast_scan_max_cycles = pno->fast_scan_max_cycles; + params->delay_start_time = pno->delay_start_time; + params->active_min_time = pno->active_min_time; + params->active_max_time = pno->active_max_time; + params->passive_min_time = pno->passive_min_time; + params->passive_max_time = pno->passive_max_time; + params->pnoscan_adaptive_dwell_mode = pno->pnoscan_adaptive_dwell_mode; +#ifdef FEATURE_WLAN_SCAN_PNO + params->pno_channel_prediction = pno->pno_channel_prediction; + params->top_k_num_of_channels = pno->top_k_num_of_channels; + params->stationary_thresh = pno->stationary_thresh; + params->channel_prediction_full_scan = + pno->channel_prediction_full_scan; +#endif + for (i = 0; i < WMI_PNO_MAX_SUPP_NETWORKS; i++) { + params->aNetworks[i].authentication = + pno->aNetworks[i].authentication; + params->aNetworks[i].encryption = pno->aNetworks[i].encryption; + params->aNetworks[i].bcastNetwType = + pno->aNetworks[i].bcastNetwType; + params->aNetworks[i].ucChannelCount = + pno->aNetworks[i].ucChannelCount; + params->aNetworks[i].rssiThreshold = + pno->aNetworks[i].rssiThreshold; + qdf_mem_copy(params->aNetworks[i].aChannels, + pno->aNetworks[i].aChannels, + WMI_PNO_MAX_NETW_CHANNELS_EX); + params->aNetworks[i].ssid.length = + pno->aNetworks[i].ssId.length; + qdf_mem_copy(params->aNetworks[i].ssid.mac_ssid, + pno->aNetworks[i].ssId.ssId, + WMI_MAC_MAX_SSID_LENGTH); + } + + params->enable_pno_scan_randomization = + pno->enable_pno_scan_randomization; + qdf_mem_copy(params->mac_addr, pno->mac_addr, QDF_MAC_ADDR_SIZE); + qdf_mem_copy(params->mac_addr_mask, pno->mac_addr_mask, + QDF_MAC_ADDR_SIZE); + + status = wmi_unified_pno_start_cmd(wma->wmi_handle, + params, channel_list); + if (QDF_IS_STATUS_SUCCESS(status)) { + wma->interfaces[pno->sessionId].pno_in_progress = true; + WMA_LOGD("PNO start request sent successfully for vdev %d", + pno->sessionId); + } + +exit_pno_start: + if (channel_list) + qdf_mem_free(channel_list); + if (params) + qdf_mem_free(params); + return status; +} + +/** + * wma_pno_stop() - PNO stop request + * @wma: wma handle + * @vdev_id: vdev id + * + * This function request FW to stop ongoing PNO operation. + * + * Return: QDF status + */ +QDF_STATUS wma_pno_stop(tp_wma_handle wma, uint8_t vdev_id) +{ + QDF_STATUS status; + if (!wma->interfaces[vdev_id].pno_in_progress) { + WMA_LOGD("No active pno session found for vdev %d, skip pno stop request", + vdev_id); + return QDF_STATUS_SUCCESS; + } + + WMA_LOGD("PNO Stop"); + + status = wmi_unified_pno_stop_cmd(wma->wmi_handle, vdev_id); + if (QDF_IS_STATUS_ERROR(status)) + return status; + + wma->interfaces[vdev_id].pno_in_progress = false; + + WMA_LOGD("PNO stop request sent successfully for vdev %d", vdev_id); + + return status; +} + +/** + * wma_config_pno() - config PNO + * @wma: wma handle + * @pno: PNO request parameters + * + * Return: none + */ +void wma_config_pno(tp_wma_handle wma, tpSirPNOScanReq pno) +{ + QDF_STATUS ret; + + if (pno->enable) + ret = wma_pno_start(wma, pno); + else + ret = wma_pno_stop(wma, pno->sessionId); + + if (ret) + WMA_LOGE("%s: PNO %s failed %d", __func__, + pno->enable ? "start" : "stop", ret); + + /* SME expects WMA to free tpSirPNOScanReq memory after + * processing PNO request. */ + qdf_mem_free(pno); +} + +#ifdef FEATURE_WLAN_ESE +/** + * wma_plm_start() - plm start request + * @wma: wma handle + * @plm: plm request parameters + * + * This function request FW to start PLM. + * + * Return: QDF status + */ +QDF_STATUS wma_plm_start(tp_wma_handle wma, const tpSirPlmReq plm) +{ + struct plm_req_params params = {0}; + uint32_t num_channels; + uint32_t *channel_list = NULL; + uint32_t i; + QDF_STATUS status; + + if (NULL == plm || NULL == wma) { + WMA_LOGE("%s: input pointer is NULL ", __func__); + return QDF_STATUS_E_FAILURE; + } + WMA_LOGD("PLM Start"); + + num_channels = plm->plmNumCh; + + if (num_channels) { + channel_list = qdf_mem_malloc(sizeof(uint32_t) * num_channels); + if (!channel_list) + return QDF_STATUS_E_FAILURE; + + for (i = 0; i < num_channels; i++) { + channel_list[i] = plm->plmChList[i]; + + if (channel_list[i] < WMA_NLO_FREQ_THRESH) + channel_list[i] = + cds_chan_to_freq(channel_list[i]); + } + } + + params.diag_token = plm->diag_token; + params.meas_token = plm->meas_token; + params.num_bursts = plm->numBursts; + params.burst_int = plm->burstInt; + params.meas_duration = plm->measDuration; + params.burst_len = plm->burstLen; + params.desired_tx_pwr = plm->desiredTxPwr; + params.plm_num_ch = plm->plmNumCh; + params.session_id = plm->sessionId; + params.enable = plm->enable; + qdf_mem_copy(¶ms.mac_addr, &plm->mac_addr, + sizeof(struct qdf_mac_addr)); + qdf_mem_copy(params.plm_ch_list, plm->plmChList, + WMI_CFG_VALID_CHANNEL_LIST_LEN); + + status = wmi_unified_plm_start_cmd(wma->wmi_handle, + ¶ms, channel_list); + if (QDF_IS_STATUS_ERROR(status)) { + qdf_mem_free(channel_list); + return status; + } + + qdf_mem_free(channel_list); + wma->interfaces[plm->sessionId].plm_in_progress = true; + + WMA_LOGD("Plm start request sent successfully for vdev %d", + plm->sessionId); + + return status; +} + +/** + * wma_plm_stop() - plm stop request + * @wma: wma handle + * @plm: plm request parameters + * + * This function request FW to stop PLM. + * + * Return: QDF status + */ +QDF_STATUS wma_plm_stop(tp_wma_handle wma, const tpSirPlmReq plm) +{ + struct plm_req_params params = {0}; + QDF_STATUS status; + + if (NULL == plm || NULL == wma) { + WMA_LOGE("%s: input pointer is NULL ", __func__); + return QDF_STATUS_E_FAILURE; + } + + if (false == wma->interfaces[plm->sessionId].plm_in_progress) { + WMA_LOGE("No active plm req found, skip plm stop req"); + return QDF_STATUS_E_FAILURE; + } + + WMA_LOGD("PLM Stop"); + + params.diag_token = plm->diag_token; + params.meas_token = plm->meas_token; + params.num_bursts = plm->numBursts; + params.burst_int = plm->burstInt; + params.meas_duration = plm->measDuration; + params.burst_len = plm->burstLen; + params.desired_tx_pwr = plm->desiredTxPwr; + params.plm_num_ch = plm->plmNumCh; + params.session_id = plm->sessionId; + params.enable = plm->enable; + qdf_mem_copy(¶ms.mac_addr, &plm->mac_addr, + sizeof(struct qdf_mac_addr)); + qdf_mem_copy(params.plm_ch_list, plm->plmChList, + WMI_CFG_VALID_CHANNEL_LIST_LEN); + + status = wmi_unified_plm_stop_cmd(wma->wmi_handle, + ¶ms); + if (QDF_IS_STATUS_ERROR(status)) + return status; + + wma->interfaces[plm->sessionId].plm_in_progress = false; + + WMA_LOGD("Plm stop request sent successfully for vdev %d", + plm->sessionId); + + return status; +} + +/** + * wma_config_plm()- config PLM + * @wma: wma handle + * @plm: plm request parameters + * + * Return: none + */ +void wma_config_plm(tp_wma_handle wma, tpSirPlmReq plm) +{ + QDF_STATUS ret = 0; + + if (NULL == plm || NULL == wma) + return; + + if (plm->enable) + ret = wma_plm_start(wma, plm); + else + ret = wma_plm_stop(wma, plm); + + if (ret) + WMA_LOGE("%s: PLM %s failed %d", __func__, + plm->enable ? "start" : "stop", ret); + + /* SME expects WMA to free tpSirPlmReq memory after + * processing PLM request. */ + qdf_mem_free(plm); + plm = NULL; +} +#endif + +/** + * wma_scan_cache_updated_ind() - scan update indication + * @wma: wma handle + * @sessionId: session ID + * + * After pushing cached scan results (that are stored in LIM) to SME, + * PE will post WMA_SME_SCAN_CACHE_UPDATED message indication to + * wma and intern this function handles that message. This function will + * check for PNO completion (by checking NLO match event) and post PNO + * completion back to SME if PNO operation is completed successfully. + * + * Return: none + */ +void wma_scan_cache_updated_ind(tp_wma_handle wma, uint8_t sessionId) +{ + tSirPrefNetworkFoundInd *nw_found_ind; + QDF_STATUS status; + cds_msg_t cds_msg; + uint8_t len, i; + + for (i = 0; i < wma->max_bssid; i++) { + if (wma->interfaces[i].nlo_match_evt_received) + break; + } + + if (i == wma->max_bssid) { + WMA_LOGD("PNO match event is not received in any vdev, skip scan cache update indication"); + return; + } + wma->interfaces[i].nlo_match_evt_received = false; + + WMA_LOGD("Posting PNO completion to umac"); + + len = sizeof(tSirPrefNetworkFoundInd); + nw_found_ind = (tSirPrefNetworkFoundInd *) qdf_mem_malloc(len); + + if (NULL == nw_found_ind) { + WMA_LOGE("%s: Memory allocation failure", __func__); + return; + } + + nw_found_ind->mesgType = eWNI_SME_PREF_NETWORK_FOUND_IND; + nw_found_ind->mesgLen = len; + nw_found_ind->sessionId = sessionId; + + cds_msg.type = eWNI_SME_PREF_NETWORK_FOUND_IND; + cds_msg.bodyptr = (void *)nw_found_ind; + cds_msg.bodyval = 0; + + status = cds_mq_post_message(CDS_MQ_ID_SME, &cds_msg); + if (status != QDF_STATUS_SUCCESS) { + WMA_LOGE("%s: Failed to post PNO completion match event to SME", + __func__); + qdf_mem_free(nw_found_ind); + } +} + +#ifdef FEATURE_WLAN_EXTSCAN +/** + * wma_extscan_wow_event_callback() - extscan wow event callback + * @handle: WMA handle + * @event: event buffer + * @len: length of @event buffer + * + * In wow case, the wow event is followed by the payload of the event + * which generated the wow event. + * payload is 4 bytes of length followed by event buffer. the first 4 bytes + * of event buffer is common tlv header, which is a combination + * of tag (higher 2 bytes) and length (lower 2 bytes). The tag is used to + * identify the event which triggered wow event. + * Payload is extracted and converted into generic tlv structure before + * being passed to this function. + * + * @Return: none + */ +void wma_extscan_wow_event_callback(void *handle, void *event, uint32_t len) +{ + uint32_t tag = WMITLV_GET_TLVTAG(WMITLV_GET_HDR(event)); + + switch (tag) { + case WMITLV_TAG_STRUC_wmi_extscan_start_stop_event_fixed_param: + wma_extscan_start_stop_event_handler(handle, event, len); + break; + + case WMITLV_TAG_STRUC_wmi_extscan_operation_event_fixed_param: + wma_extscan_operations_event_handler(handle, event, len); + break; + + case WMITLV_TAG_STRUC_wmi_extscan_table_usage_event_fixed_param: + wma_extscan_table_usage_event_handler(handle, event, len); + break; + + case WMITLV_TAG_STRUC_wmi_extscan_cached_results_event_fixed_param: + wma_extscan_cached_results_event_handler(handle, event, len); + break; + + case WMITLV_TAG_STRUC_wmi_extscan_wlan_change_results_event_fixed_param: + wma_extscan_change_results_event_handler(handle, event, len); + break; + + case WMITLV_TAG_STRUC_wmi_extscan_hotlist_match_event_fixed_param: + wma_extscan_hotlist_match_event_handler(handle, event, len); + break; + + case WMITLV_TAG_STRUC_wmi_extscan_capabilities_event_fixed_param: + wma_extscan_capabilities_event_handler(handle, event, len); + break; + + default: + WMA_LOGE(FL("Unknown tag: %d"), tag); + break; + } + + return; +} +#endif + +/** + * wma_nlo_match_evt_handler() - nlo match event handler + * @handle: wma handle + * @event: event data + * @len: data length + * + * Record NLO match event comes from FW. It's a indication that + * one of the profile is matched. + * + * Return: 0 for success or error code. + */ +int wma_nlo_match_evt_handler(void *handle, uint8_t *event, + uint32_t len) +{ + tp_wma_handle wma = (tp_wma_handle) handle; + wmi_nlo_event *nlo_event; + WMI_NLO_MATCH_EVENTID_param_tlvs *param_buf = + (WMI_NLO_MATCH_EVENTID_param_tlvs *) event; + struct wma_txrx_node *node; + + if (!param_buf) { + WMA_LOGE("Invalid NLO match event buffer"); + return -EINVAL; + } + + nlo_event = param_buf->fixed_param; + WMA_LOGD("PNO match event received for vdev %d", nlo_event->vdev_id); + + node = &wma->interfaces[nlo_event->vdev_id]; + if (node) + node->nlo_match_evt_received = true; + + cds_host_diag_log_work(&wma->pno_wake_lock, + WMA_PNO_MATCH_WAKE_LOCK_TIMEOUT, + WIFI_POWER_EVENT_WAKELOCK_PNO); + qdf_wake_lock_timeout_acquire(&wma->pno_wake_lock, + WMA_PNO_MATCH_WAKE_LOCK_TIMEOUT); + + return 0; +} + +/** + * wma_nlo_scan_cmp_evt_handler() - nlo scan completion handler + * @handle: wma handle + * @event: event handler + * @len: length of data + * + * This function handles NLO scan completion event. + * + * Return: 0 for success or error code. + */ +int wma_nlo_scan_cmp_evt_handler(void *handle, uint8_t *event, + uint32_t len) +{ + tp_wma_handle wma = (tp_wma_handle) handle; + wmi_nlo_event *nlo_event; + WMI_NLO_SCAN_COMPLETE_EVENTID_param_tlvs *param_buf = + (WMI_NLO_SCAN_COMPLETE_EVENTID_param_tlvs *) event; + tSirScanOffloadEvent *scan_event; + struct wma_txrx_node *node; + + if (!param_buf) { + WMA_LOGE("Invalid NLO scan comp event buffer"); + return -EINVAL; + } + + nlo_event = param_buf->fixed_param; + WMA_LOGD("PNO scan completion event received for vdev %d", + nlo_event->vdev_id); + + node = &wma->interfaces[nlo_event->vdev_id]; + + /* Handle scan completion event only after NLO match event. */ + if (!node || !node->nlo_match_evt_received) { + WMA_LOGD("NLO match not received skip PNO complete ind for vdev %d", + nlo_event->vdev_id); + goto skip_pno_cmp_ind; + } + + qdf_wake_lock_release(&wma->pno_wake_lock, + WIFI_POWER_EVENT_WAKELOCK_PNO); + node->wow_stats.pno_complete++; + + scan_event = (tSirScanOffloadEvent *) + qdf_mem_malloc(sizeof(tSirScanOffloadEvent)); + if (scan_event) { + /* Posting scan completion msg would take scan cache result + * from LIM module and update in scan cache maintained in SME.*/ + cds_host_diag_log_work(&wma->pno_wake_lock, + WMA_PNO_SCAN_COMPLETE_WAKE_LOCK_TIMEOUT, + WIFI_POWER_EVENT_WAKELOCK_PNO); + qdf_wake_lock_timeout_acquire(&wma->pno_wake_lock, + WMA_PNO_SCAN_COMPLETE_WAKE_LOCK_TIMEOUT); + qdf_mem_zero(scan_event, sizeof(tSirScanOffloadEvent)); + scan_event->reasonCode = eSIR_PNO_SCAN_SUCCESS; + scan_event->event = SIR_SCAN_EVENT_COMPLETED; + scan_event->sessionId = nlo_event->vdev_id; + wma_send_msg(wma, WMA_RX_SCAN_EVENT, (void *)scan_event, 0); + } else { + WMA_LOGE("Memory allocation failed for tSirScanOffloadEvent"); + } + +skip_pno_cmp_ind: + return 0; +} + +#endif + +/** + * wma_register_extscan_event_handler() - register extscan event handler + * @wma_handle: wma handle + * + * This function register extscan related event handlers. + * + * Return: none + */ +void wma_register_extscan_event_handler(tp_wma_handle wma_handle) +{ + if (!wma_handle) { + WMA_LOGE("%s: extscan wma_handle is NULL", __func__); + return; + } + wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_EXTSCAN_START_STOP_EVENTID, + wma_extscan_start_stop_event_handler, + WMA_RX_SERIALIZER_CTX); + + wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_EXTSCAN_CAPABILITIES_EVENTID, + wma_extscan_capabilities_event_handler, + WMA_RX_SERIALIZER_CTX); + + wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_EXTSCAN_HOTLIST_MATCH_EVENTID, + wma_extscan_hotlist_match_event_handler, + WMA_RX_SERIALIZER_CTX); + + wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_EXTSCAN_WLAN_CHANGE_RESULTS_EVENTID, + wma_extscan_change_results_event_handler, + WMA_RX_SERIALIZER_CTX); + + wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_EXTSCAN_OPERATION_EVENTID, + wma_extscan_operations_event_handler, + WMA_RX_SERIALIZER_CTX); + wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_EXTSCAN_TABLE_USAGE_EVENTID, + wma_extscan_table_usage_event_handler, + WMA_RX_SERIALIZER_CTX); + + wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_EXTSCAN_CACHED_RESULTS_EVENTID, + wma_extscan_cached_results_event_handler, + WMA_RX_SERIALIZER_CTX); + + wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_PASSPOINT_MATCH_EVENTID, + wma_passpoint_match_event_handler, + WMA_RX_SERIALIZER_CTX); + + return; +} + +#ifdef FEATURE_WLAN_EXTSCAN + +/** + * wma_extscan_start_stop_event_handler() - extscan start/stop event handler + * @handle: wma handle + * @cmd_param_info: event buffer + * @len: data length + * + * This function handles different extscan related commands + * like start/stop/get results etc and indicate to upper layers. + * + * Return: 0 for success or error code. + */ +int wma_extscan_start_stop_event_handler(void *handle, + uint8_t *cmd_param_info, + uint32_t len) +{ + WMI_EXTSCAN_START_STOP_EVENTID_param_tlvs *param_buf; + wmi_extscan_start_stop_event_fixed_param *event; + struct sir_extscan_generic_response *extscan_ind; + uint16_t event_type; + tpAniSirGlobal pMac = cds_get_context(QDF_MODULE_ID_PE); + if (!pMac) { + WMA_LOGE("%s: Invalid pMac", __func__); + return -EINVAL; + } + if (!pMac->sme.pExtScanIndCb) { + WMA_LOGE("%s: Callback not registered", __func__); + return -EINVAL; + } + param_buf = (WMI_EXTSCAN_START_STOP_EVENTID_param_tlvs *) + cmd_param_info; + if (!param_buf) { + WMA_LOGE("%s: Invalid extscan event", __func__); + return -EINVAL; + } + event = param_buf->fixed_param; + extscan_ind = qdf_mem_malloc(sizeof(*extscan_ind)); + if (!extscan_ind) { + WMA_LOGE("%s: extscan memory allocation failed", __func__); + return -ENOMEM; + } + switch (event->command) { + case WMI_EXTSCAN_START_CMDID: + event_type = eSIR_EXTSCAN_START_RSP; + extscan_ind->status = event->status; + extscan_ind->request_id = event->request_id; + break; + case WMI_EXTSCAN_STOP_CMDID: + event_type = eSIR_EXTSCAN_STOP_RSP; + extscan_ind->status = event->status; + extscan_ind->request_id = event->request_id; + break; + case WMI_EXTSCAN_CONFIGURE_WLAN_CHANGE_MONITOR_CMDID: + extscan_ind->status = event->status; + extscan_ind->request_id = event->request_id; + if (event->mode == WMI_EXTSCAN_MODE_STOP) { + event_type = + eSIR_EXTSCAN_RESET_SIGNIFICANT_WIFI_CHANGE_RSP; + } else { + event_type = + eSIR_EXTSCAN_SET_SIGNIFICANT_WIFI_CHANGE_RSP; + } + break; + case WMI_EXTSCAN_CONFIGURE_HOTLIST_MONITOR_CMDID: + extscan_ind->status = event->status; + extscan_ind->request_id = event->request_id; + if (event->mode == WMI_EXTSCAN_MODE_STOP) { + event_type = eSIR_EXTSCAN_RESET_BSSID_HOTLIST_RSP; + } else { + event_type = eSIR_EXTSCAN_SET_BSSID_HOTLIST_RSP; + } + break; + case WMI_EXTSCAN_GET_CACHED_RESULTS_CMDID: + extscan_ind->status = event->status; + extscan_ind->request_id = event->request_id; + event_type = eSIR_EXTSCAN_CACHED_RESULTS_RSP; + break; + case WMI_EXTSCAN_CONFIGURE_HOTLIST_SSID_MONITOR_CMDID: + extscan_ind->status = event->status; + extscan_ind->request_id = event->request_id; + if (event->mode == WMI_EXTSCAN_MODE_STOP) { + event_type = + eSIR_EXTSCAN_RESET_SSID_HOTLIST_RSP; + } else { + event_type = + eSIR_EXTSCAN_SET_SSID_HOTLIST_RSP; + } + break; + default: + WMA_LOGE("%s: Unknown event(%d) from target", + __func__, event->status); + qdf_mem_free(extscan_ind); + return -EINVAL; + } + pMac->sme.pExtScanIndCb(pMac->hHdd, event_type, extscan_ind); + WMA_LOGD("%s: sending event to umac for requestid %u" + "with status %d", __func__, + extscan_ind->request_id, extscan_ind->status); + qdf_mem_free(extscan_ind); + return 0; +} + +/** + * wma_extscan_operations_event_handler() - extscan operation event handler + * @handle: wma handle + * @cmd_param_info: event buffer + * @len: length + * + * This function handles different operations related event and indicate + * upper layers with appropriate callback. + * + * Return: 0 for success or error code. + */ +int wma_extscan_operations_event_handler(void *handle, + uint8_t *cmd_param_info, + uint32_t len) +{ + tp_wma_handle wma = (tp_wma_handle) handle; + WMI_EXTSCAN_OPERATION_EVENTID_param_tlvs *param_buf; + wmi_extscan_operation_event_fixed_param *oprn_event; + tSirExtScanOnScanEventIndParams *oprn_ind; + uint32_t cnt; + + tpAniSirGlobal pMac = cds_get_context(QDF_MODULE_ID_PE); + if (!pMac) { + WMA_LOGE("%s: Invalid pMac", __func__); + return -EINVAL; + } + if (!pMac->sme.pExtScanIndCb) { + WMA_LOGE("%s: Callback not registered", __func__); + return -EINVAL; + } + param_buf = (WMI_EXTSCAN_OPERATION_EVENTID_param_tlvs *) + cmd_param_info; + if (!param_buf) { + WMA_LOGE("%s: Invalid scan operation event", __func__); + return -EINVAL; + } + oprn_event = param_buf->fixed_param; + oprn_ind = qdf_mem_malloc(sizeof(*oprn_ind)); + if (!oprn_ind) { + WMA_LOGE("%s: extscan memory allocation failed", __func__); + qdf_mem_free(oprn_ind); + return -ENOMEM; + } + + oprn_ind->requestId = oprn_event->request_id; + + switch (oprn_event->event) { + case WMI_EXTSCAN_BUCKET_COMPLETED_EVENT: + oprn_ind->status = 0; + goto exit_handler; + case WMI_EXTSCAN_CYCLE_STARTED_EVENT: + WMA_LOGD("%s: received WMI_EXTSCAN_CYCLE_STARTED_EVENT", + __func__); + cds_host_diag_log_work(&wma->extscan_wake_lock, + WMA_EXTSCAN_CYCLE_WAKE_LOCK_DURATION, + WIFI_POWER_EVENT_WAKELOCK_EXT_SCAN); + qdf_wake_lock_timeout_acquire(&wma->extscan_wake_lock, + WMA_EXTSCAN_CYCLE_WAKE_LOCK_DURATION); + oprn_ind->scanEventType = WIFI_EXTSCAN_CYCLE_STARTED_EVENT; + oprn_ind->status = 0; + oprn_ind->buckets_scanned = 0; + for (cnt = 0; cnt < oprn_event->num_buckets; cnt++) + oprn_ind->buckets_scanned |= + (1 << param_buf->bucket_id[cnt]); + WMA_LOGD(FL("num_buckets %u request_id %u buckets_scanned %u"), + oprn_event->num_buckets, oprn_ind->requestId, + oprn_ind->buckets_scanned); + break; + case WMI_EXTSCAN_CYCLE_COMPLETED_EVENT: + WMA_LOGD("%s: received WMI_EXTSCAN_CYCLE_COMPLETED_EVENT", + __func__); + qdf_wake_lock_release(&wma->extscan_wake_lock, + WIFI_POWER_EVENT_WAKELOCK_EXT_SCAN); + oprn_ind->scanEventType = WIFI_EXTSCAN_CYCLE_COMPLETED_EVENT; + oprn_ind->status = 0; + /* Set bucket scanned mask to zero on cycle complete */ + oprn_ind->buckets_scanned = 0; + break; + case WMI_EXTSCAN_BUCKET_STARTED_EVENT: + WMA_LOGD("%s: received WMI_EXTSCAN_BUCKET_STARTED_EVENT", + __func__); + oprn_ind->scanEventType = WIFI_EXTSCAN_BUCKET_STARTED_EVENT; + oprn_ind->status = 0; + goto exit_handler; + case WMI_EXTSCAN_THRESHOLD_NUM_SCANS: + WMA_LOGD("%s: received WMI_EXTSCAN_THRESHOLD_NUM_SCANS", + __func__); + oprn_ind->scanEventType = WIFI_EXTSCAN_THRESHOLD_NUM_SCANS; + oprn_ind->status = 0; + break; + case WMI_EXTSCAN_THRESHOLD_PERCENT: + WMA_LOGD("%s: received WMI_EXTSCAN_THRESHOLD_PERCENT", + __func__); + oprn_ind->scanEventType = WIFI_EXTSCAN_THRESHOLD_PERCENT; + oprn_ind->status = 0; + break; + default: + WMA_LOGE("%s: Unknown event(%d) from target", + __func__, oprn_event->event); + qdf_mem_free(oprn_ind); + return -EINVAL; + } + pMac->sme.pExtScanIndCb(pMac->hHdd, + eSIR_EXTSCAN_SCAN_PROGRESS_EVENT_IND, oprn_ind); + WMA_LOGI("%s: sending scan progress event to hdd", __func__); +exit_handler: + qdf_mem_free(oprn_ind); + return 0; +} + +/** + * wma_extscan_table_usage_event_handler() - extscan table usage event handler + * @handle: wma handle + * @cmd_param_info: event buffer + * @len: length + * + * This function handles table usage related event and indicate + * upper layers with appropriate callback. + * + * Return: 0 for success or error code. + */ +int wma_extscan_table_usage_event_handler(void *handle, + uint8_t *cmd_param_info, + uint32_t len) +{ + WMI_EXTSCAN_TABLE_USAGE_EVENTID_param_tlvs *param_buf; + wmi_extscan_table_usage_event_fixed_param *event; + tSirExtScanResultsAvailableIndParams *tbl_usg_ind; + tpAniSirGlobal pMac = cds_get_context(QDF_MODULE_ID_PE); + if (!pMac) { + WMA_LOGE("%s: Invalid pMac", __func__); + return -EINVAL; + } + if (!pMac->sme.pExtScanIndCb) { + WMA_LOGE("%s: Callback not registered", __func__); + return -EINVAL; + } + param_buf = (WMI_EXTSCAN_TABLE_USAGE_EVENTID_param_tlvs *) + cmd_param_info; + if (!param_buf) { + WMA_LOGE("%s: Invalid table usage event", __func__); + return -EINVAL; + } + event = param_buf->fixed_param; + tbl_usg_ind = qdf_mem_malloc(sizeof(*tbl_usg_ind)); + if (!tbl_usg_ind) { + WMA_LOGE("%s: table usage allocation failed", __func__); + return -ENOMEM; + } + tbl_usg_ind->requestId = event->request_id; + tbl_usg_ind->numResultsAvailable = event->entries_in_use; + + pMac->sme.pExtScanIndCb(pMac->hHdd, + eSIR_EXTSCAN_SCAN_RES_AVAILABLE_IND, + tbl_usg_ind); + WMA_LOGI("%s: sending scan_res available event to hdd", __func__); + qdf_mem_free(tbl_usg_ind); + return 0; +} + +/** + * wma_extscan_capabilities_event_handler() - extscan capabilities event handler + * @handle: wma handle + * @cmd_param_info: event buffer + * @len: length + * + * This function handles capabilities event and indicate + * upper layers with registered callback. + * + * Return: 0 for success or error code. + */ +int wma_extscan_capabilities_event_handler(void *handle, + uint8_t *cmd_param_info, + uint32_t len) +{ + WMI_EXTSCAN_CAPABILITIES_EVENTID_param_tlvs *param_buf; + wmi_extscan_capabilities_event_fixed_param *event; + wmi_extscan_cache_capabilities *src_cache; + wmi_extscan_hotlist_monitor_capabilities *src_hotlist; + wmi_extscan_wlan_change_monitor_capabilities *src_change; + + struct ext_scan_capabilities_response *dest_capab; + tpAniSirGlobal pMac = cds_get_context(QDF_MODULE_ID_PE); + if (!pMac) { + WMA_LOGE("%s: Invalid pMac", __func__); + return -EINVAL; + } + if (!pMac->sme.pExtScanIndCb) { + WMA_LOGE("%s: Callback not registered", __func__); + return -EINVAL; + } + param_buf = (WMI_EXTSCAN_CAPABILITIES_EVENTID_param_tlvs *) + cmd_param_info; + if (!param_buf) { + WMA_LOGE("%s: Invalid capabilities event", __func__); + return -EINVAL; + } + event = param_buf->fixed_param; + src_cache = param_buf->extscan_cache_capabilities; + src_hotlist = param_buf->hotlist_capabilities; + src_change = param_buf->wlan_change_capabilities; + + if (!src_cache || !src_hotlist || !src_change) { + WMA_LOGE("%s: Invalid capabilities list", __func__); + return -EINVAL; + } + dest_capab = qdf_mem_malloc(sizeof(*dest_capab)); + if (!dest_capab) { + WMA_LOGE("%s: Allocation failed for capabilities buffer", + __func__); + return -ENOMEM; + } + dest_capab->requestId = event->request_id; + dest_capab->max_scan_buckets = src_cache->max_buckets; + dest_capab->max_scan_cache_size = src_cache->scan_cache_entry_size; + dest_capab->max_ap_cache_per_scan = src_cache->max_bssid_per_scan; + dest_capab->max_scan_reporting_threshold = + src_cache->max_table_usage_threshold; + + dest_capab->max_hotlist_bssids = src_hotlist->max_hotlist_entries; + dest_capab->max_rssi_sample_size = src_change->max_rssi_averaging_samples; + dest_capab->max_bssid_history_entries = + src_change->max_rssi_history_entries; + dest_capab->max_significant_wifi_change_aps = + src_change->max_wlan_change_entries; + dest_capab->max_hotlist_ssids = + event->num_extscan_hotlist_ssid; + dest_capab->max_number_epno_networks = + event->num_epno_networks; + dest_capab->max_number_epno_networks_by_ssid = + event->num_epno_networks; + dest_capab->max_number_of_white_listed_ssid = + event->num_roam_ssid_whitelist; + dest_capab->max_number_of_black_listed_bssid = + event->num_roam_bssid_blacklist; + dest_capab->status = 0; + + WMA_LOGD("%s: request_id: %u status: %d", + __func__, dest_capab->requestId, dest_capab->status); + + WMA_LOGD("%s: Capabilities: max_scan_buckets: %d," + "max_hotlist_bssids: %d, max_scan_cache_size: %d," + "max_ap_cache_per_scan: %d, max_scan_reporting_threshold: %d," + "max_rssi_sample_size: %d, max_bssid_history_entries: %d," + "max_significant_wifi_change_aps: %d", + __func__, dest_capab->max_scan_buckets, + dest_capab->max_hotlist_bssids, + dest_capab->max_scan_cache_size, + dest_capab->max_ap_cache_per_scan, + dest_capab->max_scan_reporting_threshold, + dest_capab->max_rssi_sample_size, + dest_capab->max_bssid_history_entries, + dest_capab->max_significant_wifi_change_aps); + + WMA_LOGD("%s: Capabilities: max_hotlist_ssids: %d," + "max_number_epno_networks: %d, max_number_epno_networks_by_ssid: %d," + "max_number_of_white_listed_ssid: %d," + "max_number_of_black_listed_bssid: %d", + __func__, dest_capab->max_hotlist_ssids, + dest_capab->max_number_epno_networks, + dest_capab->max_number_epno_networks_by_ssid, + dest_capab->max_number_of_white_listed_ssid, + dest_capab->max_number_of_black_listed_bssid); + + pMac->sme.pExtScanIndCb(pMac->hHdd, + eSIR_EXTSCAN_GET_CAPABILITIES_IND, dest_capab); + WMA_LOGI("%s: sending capabilities event to hdd", __func__); + qdf_mem_free(dest_capab); + return 0; +} + +/** + * wma_extscan_hotlist_match_event_handler() - hotlist match event handler + * @handle: wma handle + * @cmd_param_info: event buffer + * @len: length + * + * This function handles hotlist match event and indicate + * upper layers with registered callback. + * + * Return: 0 for success or error code. + */ +int wma_extscan_hotlist_match_event_handler(void *handle, + uint8_t *cmd_param_info, + uint32_t len) +{ + WMI_EXTSCAN_HOTLIST_MATCH_EVENTID_param_tlvs *param_buf; + wmi_extscan_hotlist_match_event_fixed_param *event; + struct extscan_hotlist_match *dest_hotlist; + tSirWifiScanResult *dest_ap; + wmi_extscan_wlan_descriptor *src_hotlist; + int numap, j, ap_found = 0; + tpAniSirGlobal pMac = cds_get_context(QDF_MODULE_ID_PE); + + if (!pMac) { + WMA_LOGE("%s: Invalid pMac", __func__); + return -EINVAL; + } + if (!pMac->sme.pExtScanIndCb) { + WMA_LOGE("%s: Callback not registered", __func__); + return -EINVAL; + } + param_buf = (WMI_EXTSCAN_HOTLIST_MATCH_EVENTID_param_tlvs *) + cmd_param_info; + if (!param_buf) { + WMA_LOGE("%s: Invalid hotlist match event", __func__); + return -EINVAL; + } + event = param_buf->fixed_param; + src_hotlist = param_buf->hotlist_match; + numap = event->total_entries; + + if (!src_hotlist || !numap) { + WMA_LOGE("%s: Hotlist AP's list invalid", __func__); + return -EINVAL; + } + dest_hotlist = qdf_mem_malloc(sizeof(*dest_hotlist) + + sizeof(*dest_ap) * numap); + if (!dest_hotlist) { + WMA_LOGE("%s: Allocation failed for hotlist buffer", __func__); + return -ENOMEM; + } + dest_ap = &dest_hotlist->ap[0]; + dest_hotlist->numOfAps = event->total_entries; + dest_hotlist->requestId = event->config_request_id; + + if (event->first_entry_index + + event->num_entries_in_page < event->total_entries) + dest_hotlist->moreData = 1; + else + dest_hotlist->moreData = 0; + + WMA_LOGD("%s: Hotlist match: requestId: %u," + "numOfAps: %d", __func__, + dest_hotlist->requestId, dest_hotlist->numOfAps); + + /* + * Currently firmware sends only one bss information in-case + * of both hotlist ap found and lost. + */ + for (j = 0; j < numap; j++) { + dest_ap->rssi = 0; + dest_ap->channel = src_hotlist->channel; + dest_ap->ts = src_hotlist->tstamp; + ap_found = src_hotlist->flags & WMI_HOTLIST_FLAG_PRESENCE; + dest_ap->rtt = src_hotlist->rtt; + dest_ap->rtt_sd = src_hotlist->rtt_sd; + dest_ap->beaconPeriod = src_hotlist->beacon_interval; + dest_ap->capability = src_hotlist->capabilities; + dest_ap->ieLength = src_hotlist->ie_length; + WMI_MAC_ADDR_TO_CHAR_ARRAY(&src_hotlist->bssid, + dest_ap->bssid.bytes); + qdf_mem_copy(dest_ap->ssid, src_hotlist->ssid.ssid, + src_hotlist->ssid.ssid_len); + dest_ap->ssid[src_hotlist->ssid.ssid_len] = '\0'; + dest_ap++; + src_hotlist++; + } + dest_hotlist->ap_found = ap_found; + pMac->sme.pExtScanIndCb(pMac->hHdd, + eSIR_EXTSCAN_HOTLIST_MATCH_IND, dest_hotlist); + WMA_LOGI("%s: sending hotlist match event to hdd", __func__); + qdf_mem_free(dest_hotlist); + return 0; +} + +/** wma_extscan_find_unique_scan_ids() - find unique scan ids + * @cmd_param_info: event data. + * + * This utility function parses the input bss table of information + * and find the unique number of scan ids + * + * Return: 0 on success; error number otherwise + */ +static int wma_extscan_find_unique_scan_ids(const u_int8_t *cmd_param_info) +{ + WMI_EXTSCAN_CACHED_RESULTS_EVENTID_param_tlvs *param_buf; + wmi_extscan_cached_results_event_fixed_param *event; + wmi_extscan_wlan_descriptor *src_hotlist; + wmi_extscan_rssi_info *src_rssi; + int prev_scan_id, scan_ids_cnt, i; + + param_buf = (WMI_EXTSCAN_CACHED_RESULTS_EVENTID_param_tlvs *) + cmd_param_info; + event = param_buf->fixed_param; + src_hotlist = param_buf->bssid_list; + src_rssi = param_buf->rssi_list; + + /* Find the unique number of scan_id's for grouping */ + prev_scan_id = src_rssi->scan_cycle_id; + scan_ids_cnt = 1; + for (i = 1; i < event->num_entries_in_page; i++) { + src_rssi++; + + if (prev_scan_id != src_rssi->scan_cycle_id) { + scan_ids_cnt++; + prev_scan_id = src_rssi->scan_cycle_id; + } + } + + return scan_ids_cnt; +} + +/** wma_fill_num_results_per_scan_id() - fill number of bss per scan id + * @cmd_param_info: event data. + * @scan_id_group: pointer to scan id group. + * + * This utility function parses the input bss table of information + * and finds how many bss are there per unique scan id. + * + * Return: 0 on success; error number otherwise + */ +static int wma_fill_num_results_per_scan_id(const u_int8_t *cmd_param_info, + struct extscan_cached_scan_result *scan_id_group) +{ + WMI_EXTSCAN_CACHED_RESULTS_EVENTID_param_tlvs *param_buf; + wmi_extscan_cached_results_event_fixed_param *event; + wmi_extscan_wlan_descriptor *src_hotlist; + wmi_extscan_rssi_info *src_rssi; + struct extscan_cached_scan_result *t_scan_id_grp; + int i, prev_scan_id; + + param_buf = (WMI_EXTSCAN_CACHED_RESULTS_EVENTID_param_tlvs *) + cmd_param_info; + event = param_buf->fixed_param; + src_hotlist = param_buf->bssid_list; + src_rssi = param_buf->rssi_list; + t_scan_id_grp = scan_id_group; + + prev_scan_id = src_rssi->scan_cycle_id; + + t_scan_id_grp->scan_id = src_rssi->scan_cycle_id; + t_scan_id_grp->flags = src_rssi->flags; + t_scan_id_grp->buckets_scanned = src_rssi->buckets_scanned; + t_scan_id_grp->num_results = 1; + for (i = 1; i < event->num_entries_in_page; i++) { + src_rssi++; + if (prev_scan_id == src_rssi->scan_cycle_id) { + t_scan_id_grp->num_results++; + } else { + t_scan_id_grp++; + prev_scan_id = t_scan_id_grp->scan_id = + src_rssi->scan_cycle_id; + t_scan_id_grp->flags = src_rssi->flags; + t_scan_id_grp->buckets_scanned = + src_rssi->buckets_scanned; + t_scan_id_grp->num_results = 1; + } + } + return 0; +} + +/** wma_group_num_bss_to_scan_id() - group bss to scan id table + * @cmd_param_info: event data. + * @cached_result: pointer to cached table. + * + * This function reads the bss information from the format + * ------------------------------------------------------------------------ + * | bss info {rssi, channel, ssid, bssid, timestamp} | scan id_1 | flags | + * | bss info {rssi, channel, ssid, bssid, timestamp} | scan id_2 | flags | + * ........................................................................ + * | bss info {rssi, channel, ssid, bssid, timestamp} | scan id_N | flags | + * ------------------------------------------------------------------------ + * + * and converts it into the below format and store it + * + * ------------------------------------------------------------------------ + * | scan id_1 | -> bss info_1 -> bss info_2 -> .... bss info_M1 + * | scan id_2 | -> bss info_1 -> bss info_2 -> .... bss info_M2 + * ...................... + * | scan id_N | -> bss info_1 -> bss info_2 -> .... bss info_Mn + * ------------------------------------------------------------------------ + * + * Return: 0 on success; error number otherwise + */ +static int wma_group_num_bss_to_scan_id(const u_int8_t *cmd_param_info, + struct extscan_cached_scan_results *cached_result) +{ + WMI_EXTSCAN_CACHED_RESULTS_EVENTID_param_tlvs *param_buf; + wmi_extscan_cached_results_event_fixed_param *event; + wmi_extscan_wlan_descriptor *src_hotlist; + wmi_extscan_rssi_info *src_rssi; + struct extscan_cached_scan_results *t_cached_result; + struct extscan_cached_scan_result *t_scan_id_grp; + int i, j; + tSirWifiScanResult *ap; + + param_buf = (WMI_EXTSCAN_CACHED_RESULTS_EVENTID_param_tlvs *) + cmd_param_info; + event = param_buf->fixed_param; + src_hotlist = param_buf->bssid_list; + src_rssi = param_buf->rssi_list; + t_cached_result = cached_result; + t_scan_id_grp = &t_cached_result->result[0]; + + WMA_LOGD("%s: num_scan_ids:%d", __func__, + t_cached_result->num_scan_ids); + for (i = 0; i < t_cached_result->num_scan_ids; i++) { + WMA_LOGD("%s: num_results:%d", __func__, + t_scan_id_grp->num_results); + t_scan_id_grp->ap = qdf_mem_malloc(t_scan_id_grp->num_results * + sizeof(*ap)); + if (!t_scan_id_grp->ap) { + WMA_LOGD("%s: qdf_mem_malloc failed", __func__); + return -ENOMEM; + } + + ap = &t_scan_id_grp->ap[0]; + for (j = 0; j < t_scan_id_grp->num_results; j++) { + ap->channel = src_hotlist->channel; + ap->ts = WMA_MSEC_TO_USEC(src_rssi->tstamp); + ap->rtt = src_hotlist->rtt; + ap->rtt_sd = src_hotlist->rtt_sd; + ap->beaconPeriod = src_hotlist->beacon_interval; + ap->capability = src_hotlist->capabilities; + ap->ieLength = src_hotlist->ie_length; + + /* Firmware already applied noise floor adjustment and + * due to WMI interface "UINT32 rssi", host driver + * receives a positive value, hence convert to + * signed char to get the absolute rssi. + */ + ap->rssi = (signed char) src_rssi->rssi; + WMI_MAC_ADDR_TO_CHAR_ARRAY(&src_hotlist->bssid, + ap->bssid.bytes); + + qdf_mem_copy(ap->ssid, src_hotlist->ssid.ssid, + src_hotlist->ssid.ssid_len); + ap->ssid[src_hotlist->ssid.ssid_len] = '\0'; + ap++; + src_rssi++; + src_hotlist++; + } + t_scan_id_grp++; + } + return 0; +} + +/** + * wma_extscan_cached_results_event_handler() - cached results event handler + * @handle: wma handle + * @cmd_param_info: event buffer + * @len: length of @cmd_param_info + * + * This function handles cached results event and indicate + * cached results to upper layer. + * + * Return: 0 for success or error code. + */ +int wma_extscan_cached_results_event_handler(void *handle, + uint8_t *cmd_param_info, + uint32_t len) +{ + WMI_EXTSCAN_CACHED_RESULTS_EVENTID_param_tlvs *param_buf; + wmi_extscan_cached_results_event_fixed_param *event; + struct extscan_cached_scan_results *dest_cachelist; + struct extscan_cached_scan_result *dest_result; + struct extscan_cached_scan_results empty_cachelist; + wmi_extscan_wlan_descriptor *src_hotlist; + wmi_extscan_rssi_info *src_rssi; + int numap, i, moredata, scan_ids_cnt, buf_len; + + tpAniSirGlobal pMac = cds_get_context(QDF_MODULE_ID_PE); + if (!pMac) { + WMA_LOGE("%s: Invalid pMac", __func__); + return -EINVAL; + } + if (!pMac->sme.pExtScanIndCb) { + WMA_LOGE("%s: Callback not registered", __func__); + return -EINVAL; + } + param_buf = (WMI_EXTSCAN_CACHED_RESULTS_EVENTID_param_tlvs *) + cmd_param_info; + if (!param_buf) { + WMA_LOGE("%s: Invalid cached results event", __func__); + return -EINVAL; + } + event = param_buf->fixed_param; + src_hotlist = param_buf->bssid_list; + src_rssi = param_buf->rssi_list; + numap = event->num_entries_in_page; + WMA_LOGI("Total_entries: %u first_entry_index: %u num_entries_in_page: %d", + event->total_entries, + event->first_entry_index, numap); + if (!src_hotlist || !src_rssi || !numap) { + WMA_LOGW("%s: Cached results empty, send 0 results", __func__); + goto noresults; + } + if (event->first_entry_index + + event->num_entries_in_page < event->total_entries) + moredata = 1; + else + moredata = 0; + + dest_cachelist = qdf_mem_malloc(sizeof(*dest_cachelist)); + if (!dest_cachelist) { + WMA_LOGE("%s: qdf_mem_malloc failed", __func__); + return -ENOMEM; + } + qdf_mem_zero(dest_cachelist, sizeof(*dest_cachelist)); + dest_cachelist->request_id = event->request_id; + dest_cachelist->more_data = moredata; + + scan_ids_cnt = wma_extscan_find_unique_scan_ids(cmd_param_info); + WMA_LOGI("%s: scan_ids_cnt %d", __func__, scan_ids_cnt); + dest_cachelist->num_scan_ids = scan_ids_cnt; + + buf_len = sizeof(*dest_result) * scan_ids_cnt; + dest_cachelist->result = qdf_mem_malloc(buf_len); + if (!dest_cachelist->result) { + WMA_LOGE("%s: Allocation failed for scanid grouping", __func__); + qdf_mem_free(dest_cachelist); + return -ENOMEM; + } + + dest_result = dest_cachelist->result; + wma_fill_num_results_per_scan_id(cmd_param_info, dest_result); + wma_group_num_bss_to_scan_id(cmd_param_info, dest_cachelist); + + pMac->sme.pExtScanIndCb(pMac->hHdd, + eSIR_EXTSCAN_CACHED_RESULTS_IND, + dest_cachelist); + dest_result = dest_cachelist->result; + for (i = 0; i < dest_cachelist->num_scan_ids; i++) { + qdf_mem_free(dest_result->ap); + dest_result++; + } + qdf_mem_free(dest_cachelist->result); + qdf_mem_free(dest_cachelist); + return 0; + +noresults: + empty_cachelist.request_id = event->request_id; + empty_cachelist.more_data = 0; + empty_cachelist.num_scan_ids = 0; + + pMac->sme.pExtScanIndCb(pMac->hHdd, + eSIR_EXTSCAN_CACHED_RESULTS_IND, + &empty_cachelist); + return 0; +} + +/** + * wma_extscan_change_results_event_handler() - change results event handler + * @handle: wma handle + * @cmd_param_info: event buffer + * @len: length + * + * This function handles change results event and indicate + * change results to upper layer. + * + * Return: 0 for success or error code. + */ +int wma_extscan_change_results_event_handler(void *handle, + uint8_t *cmd_param_info, + uint32_t len) +{ + WMI_EXTSCAN_WLAN_CHANGE_RESULTS_EVENTID_param_tlvs *param_buf; + wmi_extscan_wlan_change_results_event_fixed_param *event; + tSirWifiSignificantChangeEvent *dest_chglist; + tSirWifiSignificantChange *dest_ap; + wmi_extscan_wlan_change_result_bssid *src_chglist; + + int numap; + int i, k; + uint8_t *src_rssi; + int count = 0; + int moredata; + int rssi_num = 0; + tpAniSirGlobal pMac = cds_get_context(QDF_MODULE_ID_PE); + if (!pMac) { + WMA_LOGE("%s: Invalid pMac", __func__); + return -EINVAL; + } + if (!pMac->sme.pExtScanIndCb) { + WMA_LOGE("%s: Callback not registered", __func__); + return -EINVAL; + } + param_buf = (WMI_EXTSCAN_WLAN_CHANGE_RESULTS_EVENTID_param_tlvs *) + cmd_param_info; + if (!param_buf) { + WMA_LOGE("%s: Invalid change monitor event", __func__); + return -EINVAL; + } + event = param_buf->fixed_param; + src_chglist = param_buf->bssid_signal_descriptor_list; + src_rssi = param_buf->rssi_list; + numap = event->num_entries_in_page; + + if (!src_chglist || !numap) { + WMA_LOGE("%s: Results invalid", __func__); + return -EINVAL; + } + for (i = 0; i < numap; i++) { + rssi_num += src_chglist->num_rssi_samples; + } + if (event->first_entry_index + + event->num_entries_in_page < event->total_entries) { + moredata = 1; + } else { + moredata = 0; + } + dest_chglist = qdf_mem_malloc(sizeof(*dest_chglist) + + sizeof(*dest_ap) * numap + + sizeof(int32_t) * rssi_num); + if (!dest_chglist) { + WMA_LOGE("%s: Allocation failed for change monitor", __func__); + return -ENOMEM; + } + dest_ap = &dest_chglist->ap[0]; + for (i = 0; i < numap; i++) { + dest_ap->channel = src_chglist->channel; + WMI_MAC_ADDR_TO_CHAR_ARRAY(&src_chglist->bssid, + dest_ap->bssid.bytes); + dest_ap->numOfRssi = src_chglist->num_rssi_samples; + if (dest_ap->numOfRssi) { + for (k = 0; k < dest_ap->numOfRssi; k++) { + dest_ap->rssi[k] = WMA_TGT_NOISE_FLOOR_DBM + + src_rssi[count++]; + } + } + dest_ap += dest_ap->numOfRssi * sizeof(int32_t); + src_chglist++; + } + dest_chglist->requestId = event->request_id; + dest_chglist->moreData = moredata; + dest_chglist->numResults = event->total_entries; + + pMac->sme.pExtScanIndCb(pMac->hHdd, + eSIR_EXTSCAN_SIGNIFICANT_WIFI_CHANGE_RESULTS_IND, + dest_chglist); + WMA_LOGI("%s: sending change monitor results", __func__); + qdf_mem_free(dest_chglist); + return 0; +} + +/** + * wma_passpoint_match_event_handler() - passpoint match found event handler + * @handle: WMA handle + * @cmd_param_info: event data + * @len: event data length + * + * This is the passpoint match found event handler; it reads event data from + * @cmd_param_info and fill in the destination buffer and sends indication + * up layer. + * + * Return: 0 on success; error number otherwise + */ +int wma_passpoint_match_event_handler(void *handle, + uint8_t *cmd_param_info, + uint32_t len) +{ + WMI_PASSPOINT_MATCH_EVENTID_param_tlvs *param_buf; + wmi_passpoint_event_hdr *event; + struct wifi_passpoint_match *dest_match; + tSirWifiScanResult *dest_ap; + uint8_t *buf_ptr; + tpAniSirGlobal mac = cds_get_context(QDF_MODULE_ID_PE); + + if (!mac) { + WMA_LOGE("%s: Invalid mac", __func__); + return -EINVAL; + } + if (!mac->sme.pExtScanIndCb) { + WMA_LOGE("%s: Callback not registered", __func__); + return -EINVAL; + } + + param_buf = (WMI_PASSPOINT_MATCH_EVENTID_param_tlvs *) cmd_param_info; + if (!param_buf) { + WMA_LOGE("%s: Invalid passpoint match event", __func__); + return -EINVAL; + } + event = param_buf->fixed_param; + buf_ptr = (uint8_t *)param_buf->fixed_param; + + dest_match = qdf_mem_malloc(sizeof(*dest_match) + + event->ie_length + event->anqp_length); + if (!dest_match) { + WMA_LOGE("%s: qdf_mem_malloc failed", __func__); + return -EINVAL; + } + dest_ap = &dest_match->ap; + dest_match->request_id = 0; + dest_match->id = event->id; + dest_match->anqp_len = event->anqp_length; + WMA_LOGI("%s: passpoint match: id: %u anqp length %u", __func__, + dest_match->id, dest_match->anqp_len); + + dest_ap->channel = event->channel_mhz; + dest_ap->ts = event->timestamp; + dest_ap->rtt = event->rtt; + dest_ap->rssi = event->rssi; + dest_ap->rtt_sd = event->rtt_sd; + dest_ap->beaconPeriod = event->beacon_period; + dest_ap->capability = event->capability; + dest_ap->ieLength = event->ie_length; + WMI_MAC_ADDR_TO_CHAR_ARRAY(&event->bssid, dest_ap->bssid.bytes); + qdf_mem_copy(dest_ap->ssid, event->ssid.ssid, + event->ssid.ssid_len); + dest_ap->ssid[event->ssid.ssid_len] = '\0'; + qdf_mem_copy(dest_ap->ieData, buf_ptr + sizeof(*event) + + WMI_TLV_HDR_SIZE, dest_ap->ieLength); + qdf_mem_copy(dest_match->anqp, buf_ptr + sizeof(*event) + + WMI_TLV_HDR_SIZE + dest_ap->ieLength, + dest_match->anqp_len); + + mac->sme.pExtScanIndCb(mac->hHdd, + eSIR_PASSPOINT_NETWORK_FOUND_IND, + dest_match); + WMA_LOGI("%s: sending passpoint match event to hdd", __func__); + qdf_mem_free(dest_match); + return 0; +} + +/** + * wma_get_buf_extscan_start_cmd() - Fill extscan start request + * @handle: wma handle + * @pstart: scan command request params + * @buf: event buffer + * @buf_len: length of buffer + * + * This function fills individual elements of extscan request and + * TLV for buckets, channel list. + * + * Return: QDF Status. + */ +QDF_STATUS wma_get_buf_extscan_start_cmd(tp_wma_handle wma_handle, + tSirWifiScanCmdReqParams *pstart, + wmi_buf_t *buf, int *buf_len) +{ + wmi_extscan_start_cmd_fixed_param *cmd; + wmi_extscan_bucket *dest_blist; + wmi_extscan_bucket_channel *dest_clist; + tSirWifiScanBucketSpec *src_bucket = pstart->buckets; + tSirWifiScanChannelSpec *src_channel = src_bucket->channels; + tSirWifiScanChannelSpec save_channel[WLAN_EXTSCAN_MAX_CHANNELS]; + + uint8_t *buf_ptr; + int i, k, count = 0; + int len = sizeof(*cmd); + int nbuckets = pstart->numBuckets; + int nchannels = 0; + + /* These TLV's are are NULL by default */ + uint32_t ie_len_with_pad = 0; + int num_ssid = 0; + int num_bssid = 0; + int ie_len = 0; + + uint32_t base_period = pstart->basePeriod; + + /* TLV placeholder for ssid_list (NULL) */ + len += WMI_TLV_HDR_SIZE; + len += num_ssid * sizeof(wmi_ssid); + + /* TLV placeholder for bssid_list (NULL) */ + len += WMI_TLV_HDR_SIZE; + len += num_bssid * sizeof(wmi_mac_addr); + + /* TLV placeholder for ie_data (NULL) */ + len += WMI_TLV_HDR_SIZE; + len += ie_len * sizeof(uint32_t); + + /* TLV placeholder for bucket */ + len += WMI_TLV_HDR_SIZE; + len += nbuckets * sizeof(wmi_extscan_bucket); + + /* TLV channel placeholder */ + len += WMI_TLV_HDR_SIZE; + for (i = 0; i < nbuckets; i++) { + nchannels += src_bucket->numChannels; + src_bucket++; + } + + len += nchannels * sizeof(wmi_extscan_bucket_channel); + /* Allocate the memory */ + *buf = wmi_buf_alloc(wma_handle->wmi_handle, len); + if (!*buf) { + WMA_LOGP("%s: failed to allocate memory" + " for start extscan cmd", __func__); + return QDF_STATUS_E_NOMEM; + } + buf_ptr = (uint8_t *) wmi_buf_data(*buf); + cmd = (wmi_extscan_start_cmd_fixed_param *) buf_ptr; + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_extscan_start_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_extscan_start_cmd_fixed_param)); + + cmd->request_id = pstart->requestId; + cmd->vdev_id = pstart->sessionId; + cmd->base_period = pstart->basePeriod; + cmd->num_buckets = nbuckets; + cmd->configuration_flags = 0; + if (pstart->configuration_flags & EXTSCAN_LP_EXTENDED_BATCHING) + cmd->configuration_flags |= WMI_EXTSCAN_EXTENDED_BATCHING_EN; + WMA_LOGI("%s: Total buckets: %d total #of channels is %d cfgn_flags: 0x%x", + __func__, nbuckets, nchannels, + cmd->configuration_flags); + + cmd->min_rest_time = WMA_EXTSCAN_REST_TIME; + cmd->max_rest_time = WMA_EXTSCAN_REST_TIME; + cmd->max_bssids_per_scan_cycle = pstart->maxAPperScan; + + /* The max dwell time is retrieved from the first channel + * of the first bucket and kept common for all channels. + */ + cmd->min_dwell_time_active = pstart->min_dwell_time_active; + cmd->max_dwell_time_active = pstart->max_dwell_time_active; + cmd->min_dwell_time_passive = pstart->min_dwell_time_passive; + cmd->max_dwell_time_passive = pstart->max_dwell_time_passive; + cmd->max_bssids_per_scan_cycle = pstart->maxAPperScan; + cmd->max_table_usage = pstart->report_threshold_percent; + cmd->report_threshold_num_scans = pstart->report_threshold_num_scans; + + cmd->repeat_probe_time = cmd->max_dwell_time_active / + WMA_SCAN_NPROBES_DEFAULT; + cmd->max_scan_time = WMA_EXTSCAN_MAX_SCAN_TIME; + cmd->probe_delay = 0; + cmd->probe_spacing_time = 0; + cmd->idle_time = 0; + cmd->burst_duration = WMA_EXTSCAN_BURST_DURATION; + cmd->scan_ctrl_flags = WMI_SCAN_ADD_BCAST_PROBE_REQ | + WMI_SCAN_ADD_CCK_RATES | + WMI_SCAN_ADD_OFDM_RATES | + WMI_SCAN_ADD_SPOOFED_MAC_IN_PROBE_REQ | + WMI_SCAN_ADD_DS_IE_IN_PROBE_REQ; + + cmd->scan_priority = WMI_SCAN_PRIORITY_HIGH; + cmd->num_ssids = 0; + cmd->num_bssid = 0; + cmd->ie_len = 0; + cmd->n_probes = (cmd->repeat_probe_time > 0) ? + cmd->max_dwell_time_active / cmd->repeat_probe_time : 0; + + buf_ptr += sizeof(*cmd); + WMITLV_SET_HDR(buf_ptr, + WMITLV_TAG_ARRAY_FIXED_STRUC, + num_ssid * sizeof(wmi_ssid)); + buf_ptr += WMI_TLV_HDR_SIZE + (num_ssid * sizeof(wmi_ssid)); + + WMITLV_SET_HDR(buf_ptr, + WMITLV_TAG_ARRAY_FIXED_STRUC, + num_bssid * sizeof(wmi_mac_addr)); + buf_ptr += WMI_TLV_HDR_SIZE + (num_bssid * sizeof(wmi_mac_addr)); + + ie_len_with_pad = 0; + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE, ie_len_with_pad); + buf_ptr += WMI_TLV_HDR_SIZE + ie_len_with_pad; + + WMITLV_SET_HDR(buf_ptr, + WMITLV_TAG_ARRAY_STRUC, + nbuckets * sizeof(wmi_extscan_bucket)); + dest_blist = (wmi_extscan_bucket *) + (buf_ptr + WMI_TLV_HDR_SIZE); + src_bucket = pstart->buckets; + + /* Retrieve scanning information from each bucket and + * channels and send it to the target + */ + for (i = 0; i < nbuckets; i++) { + WMITLV_SET_HDR(dest_blist, + WMITLV_TAG_STRUC_wmi_extscan_bucket_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN(wmi_extscan_bucket)); + + dest_blist->bucket_id = src_bucket->bucket; + dest_blist->base_period_multiplier = + src_bucket->period / base_period; + dest_blist->min_period = src_bucket->period; + dest_blist->max_period = src_bucket->max_period; + dest_blist->exp_backoff = src_bucket->exponent; + dest_blist->exp_max_step_count = src_bucket->step_count; + dest_blist->channel_band = src_bucket->band; + dest_blist->num_channels = src_bucket->numChannels; + dest_blist->notify_extscan_events = 0; + + if (src_bucket->reportEvents & EXTSCAN_REPORT_EVENTS_EACH_SCAN) + dest_blist->notify_extscan_events = + WMI_EXTSCAN_BUCKET_COMPLETED_EVENT; + + if (src_bucket->reportEvents & + EXTSCAN_REPORT_EVENTS_FULL_RESULTS) { + dest_blist->forwarding_flags = + WMI_EXTSCAN_FORWARD_FRAME_TO_HOST; + dest_blist->notify_extscan_events |= + WMI_EXTSCAN_BUCKET_COMPLETED_EVENT | + WMI_EXTSCAN_CYCLE_STARTED_EVENT | + WMI_EXTSCAN_CYCLE_COMPLETED_EVENT; + } else { + dest_blist->forwarding_flags = + WMI_EXTSCAN_NO_FORWARDING; + } + + if (src_bucket->reportEvents & EXTSCAN_REPORT_EVENTS_NO_BATCH) + dest_blist->configuration_flags = 0; + else + dest_blist->configuration_flags = + WMI_EXTSCAN_BUCKET_CACHE_RESULTS; + + if (src_bucket->reportEvents & + EXTSCAN_REPORT_EVENTS_CONTEXT_HUB) + dest_blist->configuration_flags |= + WMI_EXTSCAN_REPORT_EVENT_CONTEXT_HUB; + + WMA_LOGI("%s: ntfy_extscan_events:%u cfg_flags:%u fwd_flags:%u", + __func__, dest_blist->notify_extscan_events, + dest_blist->configuration_flags, + dest_blist->forwarding_flags); + + dest_blist->min_dwell_time_active = src_bucket->min_dwell_time_active; + dest_blist->max_dwell_time_active = src_bucket->max_dwell_time_active; + dest_blist->min_dwell_time_passive = src_bucket->min_dwell_time_passive; + dest_blist->max_dwell_time_passive = src_bucket->max_dwell_time_passive; + src_channel = src_bucket->channels; + + /* save the channel info to later populate + * the channel TLV + */ + for (k = 0; k < src_bucket->numChannels; k++) { + save_channel[count++].channel = src_channel->channel; + src_channel++; + } + dest_blist++; + src_bucket++; + } + buf_ptr += WMI_TLV_HDR_SIZE + (nbuckets * sizeof(wmi_extscan_bucket)); + WMITLV_SET_HDR(buf_ptr, + WMITLV_TAG_ARRAY_STRUC, + nchannels * sizeof(wmi_extscan_bucket_channel)); + dest_clist = (wmi_extscan_bucket_channel *) + (buf_ptr + WMI_TLV_HDR_SIZE); + + /* Active or passive scan is based on the bucket dwell time + * and channel specific active,passive scans are not + * supported yet + */ + for (i = 0; i < nchannels; i++) { + WMITLV_SET_HDR(dest_clist, + WMITLV_TAG_STRUC_wmi_extscan_bucket_channel_event_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_extscan_bucket_channel)); + dest_clist->channel = save_channel[i].channel; + dest_clist++; + } + buf_ptr += WMI_TLV_HDR_SIZE + + (nchannels * sizeof(wmi_extscan_bucket_channel)); + *buf_len = len; + return QDF_STATUS_SUCCESS; +} + +/** + * wma_start_extscan() - start extscan command to fw. + * @handle: wma handle + * @pstart: scan command request params + * + * This function sends start extscan request to fw. + * + * Return: QDF Status. + */ +QDF_STATUS wma_start_extscan(tp_wma_handle wma, + tSirWifiScanCmdReqParams *pstart) +{ + struct wifi_scan_cmd_req_params *params; + int i, j; + QDF_STATUS status; + + if (!wma || !wma->wmi_handle) { + WMA_LOGE("%s: WMA is closed,can not issue extscan cmd", + __func__); + return QDF_STATUS_E_INVAL; + } + if (!WMI_SERVICE_IS_ENABLED(wma->wmi_service_bitmap, + WMI_SERVICE_EXTSCAN)) { + WMA_LOGE("%s: extscan feature bit not enabled", __func__); + return QDF_STATUS_E_FAILURE; + } + + params = qdf_mem_malloc(sizeof(struct wifi_scan_cmd_req_params)); + if (params == NULL) { + WMA_LOGE("%s : Memory allocation failed", __func__); + return QDF_STATUS_E_NOMEM; + } + + params->basePeriod = pstart->basePeriod; + params->maxAPperScan = pstart->maxAPperScan; + params->report_threshold_percent = pstart->report_threshold_percent; + params->report_threshold_num_scans = pstart->report_threshold_num_scans; + params->requestId = pstart->requestId; + params->sessionId = pstart->sessionId; + params->numBuckets = pstart->numBuckets; + params->min_dwell_time_active = pstart->min_dwell_time_active; + params->min_dwell_time_passive = pstart->min_dwell_time_passive; + params->max_dwell_time_active = pstart->max_dwell_time_active; + params->max_dwell_time_passive = pstart->max_dwell_time_passive; + params->configuration_flags = pstart->configuration_flags; + params->extscan_adaptive_dwell_mode = + pstart->extscan_adaptive_dwell_mode; + for (i = 0; i < WMI_WLAN_EXTSCAN_MAX_BUCKETS; i++) { + params->buckets[i].bucket = pstart->buckets[i].bucket; + params->buckets[i].band = + (enum wmi_wifi_band) pstart->buckets[i].band; + params->buckets[i].period = pstart->buckets[i].period; + params->buckets[i].reportEvents = + pstart->buckets[i].reportEvents; + params->buckets[i].max_period = pstart->buckets[i].max_period; + params->buckets[i].exponent = pstart->buckets[i].exponent; + params->buckets[i].step_count = pstart->buckets[i].step_count; + params->buckets[i].numChannels = pstart->buckets[i].numChannels; + params->buckets[i].min_dwell_time_active = + pstart->buckets[i].min_dwell_time_active; + params->buckets[i].min_dwell_time_passive = + pstart->buckets[i].min_dwell_time_passive; + params->buckets[i].max_dwell_time_active = + pstart->buckets[i].max_dwell_time_active; + params->buckets[i].max_dwell_time_passive = + pstart->buckets[i].max_dwell_time_passive; + for (j = 0; j < WLAN_EXTSCAN_MAX_CHANNELS; j++) { + params->buckets[i].channels[j].channel = + pstart->buckets[i].channels[j].channel; + params->buckets[i].channels[j].dwellTimeMs = + pstart->buckets[i].channels[j].dwellTimeMs; + params->buckets[i].channels[j].passive = + pstart->buckets[i].channels[j].passive; + params->buckets[i].channels[j].chnlClass = + pstart->buckets[i].channels[j].chnlClass; + } + } + + status = wmi_unified_start_extscan_cmd(wma->wmi_handle, + params); + qdf_mem_free(params); + if (QDF_IS_STATUS_ERROR(status)) + return status; + + wma->interfaces[pstart->sessionId].extscan_in_progress = true; + WMA_LOGD("Extscan start request sent successfully for vdev %d", + pstart->sessionId); + + return status; +} + +/** + * wma_stop_extscan() - stop extscan command to fw. + * @handle: wma handle + * @pstopcmd: stop scan command request params + * + * This function sends stop extscan request to fw. + * + * Return: QDF Status. + */ +QDF_STATUS wma_stop_extscan(tp_wma_handle wma, + tSirExtScanStopReqParams *pstopcmd) +{ + struct extscan_stop_req_params params = {0}; + QDF_STATUS status; + + if (!wma || !wma->wmi_handle) { + WMA_LOGE("%s: WMA is closed, cannot issue cmd", __func__); + return QDF_STATUS_E_INVAL; + } + if (!WMI_SERVICE_IS_ENABLED(wma->wmi_service_bitmap, + WMI_SERVICE_EXTSCAN)) { + WMA_LOGE("%s: extscan not enabled", __func__); + return QDF_STATUS_E_FAILURE; + } + + params.request_id = pstopcmd->requestId; + params.session_id = pstopcmd->sessionId; + + status = wmi_unified_stop_extscan_cmd(wma->wmi_handle, + ¶ms); + if (QDF_IS_STATUS_ERROR(status)) + return status; + + wma->interfaces[pstopcmd->sessionId].extscan_in_progress = false; + WMA_LOGD("Extscan stop request sent successfully for vdev %d", + pstopcmd->sessionId); + + return status; +} + +/** wma_get_hotlist_entries_per_page() - hotlist entries per page + * @wmi_handle: wmi handle. + * @cmd: size of command structure. + * @per_entry_size: per entry size. + * + * This utility function calculates how many hotlist entries can + * fit in one page. + * + * Return: number of entries + */ +static inline int wma_get_hotlist_entries_per_page(wmi_unified_t wmi_handle, + size_t cmd_size, + size_t per_entry_size) +{ + uint32_t avail_space = 0; + int num_entries = 0; + uint16_t max_msg_len = wmi_get_max_msg_len(wmi_handle); + + /* Calculate number of hotlist entries that can + * be passed in wma message request. + */ + avail_space = max_msg_len - cmd_size; + num_entries = avail_space / per_entry_size; + return num_entries; +} + +/** + * wma_get_buf_extscan_hotlist_cmd() - prepare hotlist command + * @handle: wma handle + * @photlist: hotlist command params + * @buf_len: buffer length + * + * This function fills individual elements for hotlist request and + * TLV for bssid entries + * + * Return: QDF Status. + */ +QDF_STATUS wma_get_buf_extscan_hotlist_cmd(tp_wma_handle wma_handle, + tSirExtScanSetBssidHotListReqParams * + photlist, int *buf_len) +{ + return wmi_unified_get_buf_extscan_hotlist_cmd(wma_handle->wmi_handle, + (struct ext_scan_setbssi_hotlist_params *)photlist, + buf_len); +} + +/** + * wma_extscan_start_hotlist_monitor() - start hotlist monitor + * @wma: wma handle + * @photlist: hotlist request params + * + * This function configures hotlist monitor in fw. + * + * Return: QDF status + */ +QDF_STATUS wma_extscan_start_hotlist_monitor(tp_wma_handle wma, + tSirExtScanSetBssidHotListReqParams + *photlist) +{ + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + int len; + + if (!wma || !wma->wmi_handle) { + WMA_LOGE("%s: WMA is closed, can not issue hotlist cmd", + __func__); + return QDF_STATUS_E_INVAL; + } + /* Fill individual elements for hotlist request and + * TLV for bssid entries + */ + qdf_status = wma_get_buf_extscan_hotlist_cmd(wma, photlist, &len); + if (qdf_status != QDF_STATUS_SUCCESS) { + WMA_LOGE("%s: Failed to get buffer" + "for hotlist scan cmd", __func__); + return QDF_STATUS_E_FAILURE; + } + return QDF_STATUS_SUCCESS; +} + +/** + * wma_extscan_stop_hotlist_monitor() - stop hotlist monitor + * @wma: wma handle + * @photlist_reset: hotlist reset params + * + * This function configures hotlist monitor to stop in fw. + * + * Return: QDF status + */ +QDF_STATUS wma_extscan_stop_hotlist_monitor(tp_wma_handle wma, + tSirExtScanResetBssidHotlistReqParams + *photlist_reset) +{ + struct extscan_bssid_hotlist_reset_params params = {0}; + + if (!wma || !wma->wmi_handle) { + WMA_LOGE("%s: WMA is closed, can not issue cmd", __func__); + return QDF_STATUS_E_INVAL; + } + if (!photlist_reset) { + WMA_LOGE("%s: Invalid reset hotlist buffer", __func__); + return QDF_STATUS_E_INVAL; + } + if (!WMI_SERVICE_IS_ENABLED(wma->wmi_service_bitmap, + WMI_SERVICE_EXTSCAN)) { + WMA_LOGE("%s: extscan not enabled", __func__); + return QDF_STATUS_E_FAILURE; + } + + params.request_id = photlist_reset->requestId; + params.session_id = photlist_reset->requestId; + + return wmi_unified_extscan_stop_hotlist_monitor_cmd(wma->wmi_handle, + ¶ms); +} + +/** + * wma_get_buf_extscan_change_monitor_cmd() - fill change monitor request + * @wma: wma handle + * @psigchange: change monitor request params + * @buf: wmi buffer + * @buf_len: buffer length + * + * This function fills elements of change monitor request buffer. + * + * Return: QDF status + */ +QDF_STATUS wma_get_buf_extscan_change_monitor_cmd(tp_wma_handle wma_handle, + tSirExtScanSetSigChangeReqParams + *psigchange, wmi_buf_t *buf, + int *buf_len) +{ + wmi_extscan_configure_wlan_change_monitor_cmd_fixed_param *cmd; + wmi_extscan_wlan_change_bssid_param *dest_chglist; + uint8_t *buf_ptr; + int j; + int len = sizeof(*cmd); + int numap = psigchange->numAp; + tSirAPThresholdParam *src_ap = psigchange->ap; + + if (!numap) { + WMA_LOGE("%s: Invalid number of bssid's", __func__); + return QDF_STATUS_E_INVAL; + } + len += WMI_TLV_HDR_SIZE; + len += numap * sizeof(wmi_extscan_wlan_change_bssid_param); + + *buf = wmi_buf_alloc(wma_handle->wmi_handle, len); + if (!*buf) { + WMA_LOGP("%s: failed to allocate memory for change monitor cmd", + __func__); + return QDF_STATUS_E_FAILURE; + } + buf_ptr = (uint8_t *) wmi_buf_data(*buf); + cmd = + (wmi_extscan_configure_wlan_change_monitor_cmd_fixed_param *) + buf_ptr; + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_extscan_configure_wlan_change_monitor_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_extscan_configure_wlan_change_monitor_cmd_fixed_param)); + + cmd->request_id = psigchange->requestId; + cmd->vdev_id = psigchange->sessionId; + cmd->total_entries = numap; + cmd->mode = 1; + cmd->num_entries_in_page = numap; + cmd->lost_ap_scan_count = psigchange->lostApSampleSize; + cmd->max_rssi_samples = psigchange->rssiSampleSize; + cmd->rssi_averaging_samples = psigchange->rssiSampleSize; + cmd->max_out_of_range_count = psigchange->minBreaching; + + buf_ptr += sizeof(*cmd); + WMITLV_SET_HDR(buf_ptr, + WMITLV_TAG_ARRAY_STRUC, + numap * sizeof(wmi_extscan_wlan_change_bssid_param)); + dest_chglist = (wmi_extscan_wlan_change_bssid_param *) + (buf_ptr + WMI_TLV_HDR_SIZE); + + for (j = 0; j < numap; j++) { + WMITLV_SET_HDR(dest_chglist, + WMITLV_TAG_STRUC_wmi_extscan_bucket_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_extscan_wlan_change_bssid_param)); + + dest_chglist->lower_rssi_limit = src_ap->low; + dest_chglist->upper_rssi_limit = src_ap->high; + WMI_CHAR_ARRAY_TO_MAC_ADDR(src_ap->bssid.bytes, + &dest_chglist->bssid); + + WMA_LOGD("%s: min_rssi %d", __func__, + dest_chglist->lower_rssi_limit); + dest_chglist++; + src_ap++; + } + buf_ptr += WMI_TLV_HDR_SIZE + + (numap * sizeof(wmi_extscan_wlan_change_bssid_param)); + *buf_len = len; + return QDF_STATUS_SUCCESS; +} + +/** + * wma_extscan_start_change_monitor() - send start change monitor cmd + * @wma: wma handle + * @psigchange: change monitor request params + * + * This function sends start change monitor request to fw. + * + * Return: QDF status + */ +QDF_STATUS wma_extscan_start_change_monitor(tp_wma_handle wma, + tSirExtScanSetSigChangeReqParams * + psigchange) +{ + int i = 0; + QDF_STATUS status; + struct extscan_set_sig_changereq_params *params_ptr; + + if (!wma || !wma->wmi_handle) { + WMA_LOGE("%s: WMA is closed,can not issue extscan cmd", + __func__); + return QDF_STATUS_E_INVAL; + } + + params_ptr = qdf_mem_malloc(sizeof(*params_ptr)); + + if (!params_ptr) { + WMA_LOGE( + "%s: unable to allocate memory for extscan_set_sig_changereq_params", + __func__); + return QDF_STATUS_E_NOMEM; + } + + params_ptr->request_id = psigchange->requestId; + params_ptr->session_id = psigchange->sessionId; + params_ptr->rssi_sample_size = psigchange->rssiSampleSize; + params_ptr->lostap_sample_size = psigchange->lostApSampleSize; + params_ptr->min_breaching = psigchange->minBreaching; + params_ptr->num_ap = psigchange->numAp; + for (i = 0; i < WLAN_EXTSCAN_MAX_SIGNIFICANT_CHANGE_APS; i++) { + qdf_mem_copy(¶ms_ptr->ap[i].bssid, + &psigchange->ap[i].bssid, + sizeof(struct qdf_mac_addr)); + params_ptr->ap[i].high = psigchange->ap[i].high; + params_ptr->ap[i].low = psigchange->ap[i].low; + } + + status = wmi_unified_extscan_start_change_monitor_cmd + (wma->wmi_handle, + params_ptr); + qdf_mem_free(params_ptr); + return status; +} + +/** + * wma_extscan_stop_change_monitor() - send stop change monitor cmd + * @wma: wma handle + * @pResetReq: Reset change request params + * + * This function sends stop change monitor request to fw. + * + * Return: QDF status + */ +QDF_STATUS wma_extscan_stop_change_monitor(tp_wma_handle wma, + tSirExtScanResetSignificantChangeReqParams + *pResetReq) +{ + struct extscan_capabilities_reset_params params = {0}; + + if (!wma || !wma->wmi_handle) { + WMA_LOGE("%s: WMA is closed, can not issue cmd", __func__); + return QDF_STATUS_E_INVAL; + } + if (!WMI_SERVICE_IS_ENABLED(wma->wmi_service_bitmap, + WMI_SERVICE_EXTSCAN)) { + WMA_LOGE("%s: ext scan not enabled", __func__); + return QDF_STATUS_E_FAILURE; + } + + params.request_id = pResetReq->requestId; + params.session_id = pResetReq->sessionId; + + return wmi_unified_extscan_stop_change_monitor_cmd(wma->wmi_handle, + ¶ms); +} + +/** + * wma_extscan_get_cached_results() - extscan get cached results + * @wma: wma handle + * @pcached_results: cached results parameters + * + * This function send request to fw to get cached results. + * + * Return: QDF status + */ +QDF_STATUS wma_extscan_get_cached_results(tp_wma_handle wma, + tSirExtScanGetCachedResultsReqParams * + pcached_results) +{ + struct extscan_cached_result_params params = {0}; + + if (!wma || !wma->wmi_handle) { + WMA_LOGE("%s: WMA is closed, cannot issue cmd", __func__); + return QDF_STATUS_E_INVAL; + } + if (!WMI_SERVICE_IS_ENABLED(wma->wmi_service_bitmap, + WMI_SERVICE_EXTSCAN)) { + WMA_LOGE("%s: extscan not enabled", __func__); + return QDF_STATUS_E_FAILURE; + } + + params.request_id = pcached_results->requestId; + params.session_id = pcached_results->sessionId; + params.flush = pcached_results->flush; + + return wmi_unified_extscan_get_cached_results_cmd(wma->wmi_handle, + ¶ms); +} + +/** + * wma_extscan_get_capabilities() - extscan get capabilities + * @wma: wma handle + * @pgetcapab: get capabilities params + * + * This function send request to fw to get extscan capabilities. + * + * Return: QDF status + */ +QDF_STATUS wma_extscan_get_capabilities(tp_wma_handle wma, + tSirGetExtScanCapabilitiesReqParams * + pgetcapab) +{ + struct extscan_capabilities_params params = {0}; + + if (!wma || !wma->wmi_handle) { + WMA_LOGE("%s: WMA is closed, can not issue cmd", __func__); + return QDF_STATUS_E_INVAL; + } + if (!WMI_SERVICE_IS_ENABLED(wma->wmi_service_bitmap, + WMI_SERVICE_EXTSCAN)) { + WMA_LOGE("%s: extscan not enabled", __func__); + return QDF_STATUS_E_FAILURE; + } + + params.request_id = pgetcapab->requestId; + params.session_id = pgetcapab->sessionId; + + return wmi_unified_extscan_get_capabilities_cmd(wma->wmi_handle, + ¶ms); +} + +QDF_STATUS wma_ipa_offload_enable_disable(tp_wma_handle wma, + struct sir_ipa_offload_enable_disable *ipa_offload) +{ + ol_txrx_vdev_handle vdev; + int32_t intra_bss_fwd = 0; + struct ipa_offload_control_params params = {0}; + QDF_STATUS status; + uint8_t rx_fwd_disabled; + + if (!wma || !wma->wmi_handle) { + WMA_LOGE("%s: WMA is closed, can not issue cmd", + __func__); + return QDF_STATUS_E_INVAL; + } + + if (!WMI_SERVICE_IS_ENABLED(wma->wmi_service_bitmap, + ((ipa_offload->offload_type == AP_RX_DATA_OFFLOAD) ? + WMI_SERVICE_HSOFFLOAD : + WMI_SERVICE_STA_RX_IPA_OFFLOAD_SUPPORT))) { + WMA_LOGE("%s: %s not supported", __func__, + ((ipa_offload->offload_type == AP_RX_DATA_OFFLOAD) ? + "WMI_SERVICE_HSOFFLOAD" : + "WMI_SERVICE_STA_RX_IPA_OFFLOAD_SUPPORT")); + return QDF_STATUS_E_FAILURE; + } + + if (ipa_offload->offload_type > STA_RX_DATA_OFFLOAD) { + return QDF_STATUS_E_INVAL; + } + + params.offload_type = ipa_offload->offload_type; + params.vdev_id = ipa_offload->vdev_id; + params.enable = ipa_offload->enable; + + status = wmi_unified_ipa_offload_control_cmd(wma->wmi_handle, + ¶ms); + if (QDF_IS_STATUS_ERROR(status)) + return status; + + /* + * Check if VDEV is already deleted. If deleted, don't + * send INTRA BSS FWD WMI command + */ + vdev = wma_find_vdev_by_id(wma, ipa_offload->vdev_id); + if (!vdev) + return QDF_STATUS_SUCCESS; + + /* Disable Intra-BSS FWD offload when gDisableIntraBssFwd=1 in INI */ + rx_fwd_disabled = ol_txrx_is_rx_fwd_disabled(vdev); + if (!ipa_offload->enable || rx_fwd_disabled) { + WMA_LOGE("%s: ipa_offload->enable=%d, rx_fwd_disabled=%d", + __func__, + ipa_offload->enable, rx_fwd_disabled); + intra_bss_fwd = 1; + } + + /* Disable/enable WMI_VDEV_PARAM_INTRA_BSS_FWD */ + status = wma_vdev_set_param(wma->wmi_handle, + ipa_offload->vdev_id, WMI_VDEV_PARAM_INTRA_BSS_FWD, + intra_bss_fwd); + if (QDF_IS_STATUS_ERROR(status)) { + WMA_LOGE("Failed to disable WMI_VDEV_PARAM_INTRA_BSS_FWD"); + return status; + } + + return status; +} + +/** wma_set_epno_network_list() - set epno network list + * @wma: WMA handle + * @req: epno config params request structure + * + * This function reads the incoming epno config request structure + * and constructs the WMI message to the firmware. + * + * Returns: 0 on success, error number otherwise + */ +QDF_STATUS wma_set_epno_network_list(tp_wma_handle wma, + struct wifi_epno_params *req) +{ + struct wifi_enhanched_pno_params *params; + uint8_t i = 0; + QDF_STATUS status; + size_t params_len; + + WMA_LOGD("wma_set_epno_network_list"); + + if (!wma || !wma->wmi_handle) { + WMA_LOGE("%s: WMA is closed, can not issue cmd", __func__); + return QDF_STATUS_E_FAILURE; + } + if (!WMI_SERVICE_IS_ENABLED(wma->wmi_service_bitmap, + WMI_SERVICE_EXTSCAN)) { + WMA_LOGE("%s: extscan not enabled", __func__); + return QDF_STATUS_E_NOSUPPORT; + } + + params_len = sizeof(*params) + (req->num_networks * + sizeof(struct wifi_epno_network_params)); + params = qdf_mem_malloc(params_len); + if (params == NULL) { + WMA_LOGE(FL("memory allocation failed")); + return QDF_STATUS_E_NOMEM; + } + + params->request_id = req->request_id; + params->session_id = req->session_id; + params->num_networks = req->num_networks; + + /* Fill only when num_networks are non zero */ + if (req->num_networks) { + params->min_5ghz_rssi = req->min_5ghz_rssi; + params->min_24ghz_rssi = req->min_24ghz_rssi; + params->initial_score_max = req->initial_score_max; + params->same_network_bonus = req->same_network_bonus; + params->secure_bonus = req->secure_bonus; + params->band_5ghz_bonus = req->band_5ghz_bonus; + params->current_connection_bonus = + req->current_connection_bonus; + + for (i = 0; i < req->num_networks; i++) { + params->networks[i].flags = req->networks[i].flags; + params->networks[i].auth_bit_field = + req->networks[i].auth_bit_field; + params->networks[i].ssid.length = + req->networks[i].ssid.length; + qdf_mem_copy(params->networks[i].ssid.mac_ssid, + req->networks[i].ssid.ssId, + WMI_MAC_MAX_SSID_LENGTH); + } + } + + status = wmi_unified_set_epno_network_list_cmd(wma->wmi_handle, params); + qdf_mem_free(params); + + if (QDF_IS_STATUS_ERROR(status)) + return status; + + WMA_LOGD("set ePNO list request sent successfully for vdev %d", + req->session_id); + + return status; +} + +/** + * wma_set_passpoint_network_list() - set passpoint network list + * @handle: WMA handle + * @req: passpoint network request structure + * + * This function reads the incoming @req and fill in the destination + * WMI structure and send down the passpoint configs down to the firmware + * + * Return: QDF_STATUS enumeration + */ +QDF_STATUS wma_set_passpoint_network_list(tp_wma_handle wma, + struct wifi_passpoint_req *req) +{ + struct wifi_passpoint_req_param *params; + int i = 0; + QDF_STATUS status; + size_t params_len; + + WMA_LOGD("wma_set_passpoint_network_list"); + + if (!wma || !wma->wmi_handle) { + WMA_LOGE("%s: WMA is closed, can not issue cmd", __func__); + return QDF_STATUS_E_FAILURE; + } + if (!WMI_SERVICE_IS_ENABLED(wma->wmi_service_bitmap, + WMI_SERVICE_EXTSCAN)) { + WMA_LOGE("%s: extscan not enabled", __func__); + return QDF_STATUS_E_NOSUPPORT; + } + + params_len = sizeof(*params) + (req->num_networks * + sizeof(struct wifi_passpoint_network_param)); + params = qdf_mem_malloc(params_len); + if (params == NULL) { + WMA_LOGE(FL("memory allocation failed")); + return QDF_STATUS_E_NOMEM; + } + + params->request_id = req->request_id; + params->session_id = req->session_id; + params->num_networks = req->num_networks; + for (i = 0; i < req->num_networks; i++) { + params->networks[i].id = req->networks[i].id; + qdf_mem_copy(params->networks[i].realm, req->networks[i].realm, + WMI_PASSPOINT_REALM_LEN); + qdf_mem_copy(params->networks[i].roaming_consortium_ids, + req->networks[i].roaming_consortium_ids, + WMI_PASSPOINT_ROAMING_CONSORTIUM_ID_NUM * + sizeof(int64_t)); + qdf_mem_copy(params->networks[i].plmn, req->networks[i].plmn, + WMI_PASSPOINT_PLMN_LEN); + } + + status = wmi_unified_set_passpoint_network_list_cmd(wma->wmi_handle, + params); + qdf_mem_free(params); + + if (QDF_IS_STATUS_ERROR(status)) + return status; + + WMA_LOGD("Set passpoint network list request is sent successfully for vdev %d", + req->session_id); + + return status; +} + +/** + * wma_reset_passpoint_network_list() - reset passpoint network list + * @handle: WMA handle + * @req: passpoint network request structure + * + * This function sends down WMI command with network id set to wildcard id. + * firmware shall clear all the config entries + * + * Return: QDF_STATUS enumeration + */ +QDF_STATUS wma_reset_passpoint_network_list(tp_wma_handle wma, + struct wifi_passpoint_req *req) +{ + struct wifi_passpoint_req_param *params; + int i = 0; + QDF_STATUS status; + size_t params_len; + + WMA_LOGD("wma_reset_passpoint_network_list"); + + if (!wma || !wma->wmi_handle) { + WMA_LOGE("%s: WMA is closed, can not issue cmd", __func__); + return QDF_STATUS_E_FAILURE; + } + if (!WMI_SERVICE_IS_ENABLED(wma->wmi_service_bitmap, + WMI_SERVICE_EXTSCAN)) { + WMA_LOGE("%s: extscan not enabled", __func__); + return QDF_STATUS_E_NOSUPPORT; + } + + params_len = sizeof(*params) + (req->num_networks * + sizeof(struct wifi_passpoint_network_param)); + params = qdf_mem_malloc(params_len); + if (params == NULL) { + WMA_LOGE(FL("memory allocation failed")); + return QDF_STATUS_E_NOMEM; + } + + params->request_id = req->request_id; + params->session_id = req->session_id; + params->num_networks = req->num_networks; + for (i = 0; i < req->num_networks; i++) { + params->networks[i].id = req->networks[i].id; + qdf_mem_copy(params->networks[i].realm, req->networks[i].realm, + WMI_PASSPOINT_REALM_LEN); + qdf_mem_copy(params->networks[i].roaming_consortium_ids, + req->networks[i].roaming_consortium_ids, + WMI_PASSPOINT_ROAMING_CONSORTIUM_ID_NUM * + sizeof(int64_t)); + qdf_mem_copy(params->networks[i].plmn, req->networks[i].plmn, + WMI_PASSPOINT_PLMN_LEN); + } + + status = wmi_unified_reset_passpoint_network_list_cmd(wma->wmi_handle, + params); + qdf_mem_free(params); + + return status; +} + +#endif + +/** + * wma_scan_probe_setoui() - set scan probe OUI + * @wma: wma handle + * @psetoui: OUI parameters + * + * set scan probe OUI parameters in firmware + * + * Return: QDF status + */ +QDF_STATUS wma_scan_probe_setoui(tp_wma_handle wma, tSirScanMacOui *psetoui) +{ + struct scan_mac_oui set_oui; + + qdf_mem_set(&set_oui, sizeof(struct scan_mac_oui), 0); + + if (!wma || !wma->wmi_handle) { + WMA_LOGE("%s: WMA is closed, can not issue cmd", __func__); + return QDF_STATUS_E_INVAL; + } + + qdf_mem_copy(set_oui.oui, psetoui->oui, + WMI_WIFI_SCANNING_MAC_OUI_LENGTH); + + set_oui.vdev_id = psetoui->vdev_id; + set_oui.enb_probe_req_sno_randomization = + psetoui->enb_probe_req_sno_randomization; + + return wmi_unified_scan_probe_setoui_cmd(wma->wmi_handle, + &set_oui); +} + +/** + * wma_scan_event_callback() - scan event callback + * @handle: wma handle + * @data: event data + * @len: data length + * + * This function process scan event and provide indication + * to upper layers. + * + * Return: 0 for success or error code. + */ +int wma_scan_event_callback(WMA_HANDLE handle, uint8_t *data, + uint32_t len) +{ + tp_wma_handle wma_handle = (tp_wma_handle) handle; + WMI_SCAN_EVENTID_param_tlvs *param_buf = NULL; + wmi_scan_event_fixed_param *wmi_event = NULL; + tSirScanOffloadEvent *scan_event; + uint8_t vdev_id; + uint32_t scan_id; + + param_buf = (WMI_SCAN_EVENTID_param_tlvs *) data; + wmi_event = param_buf->fixed_param; + vdev_id = wmi_event->vdev_id; + scan_id = wma_handle->interfaces[vdev_id].scan_info.scan_id; + + scan_event = (tSirScanOffloadEvent *) qdf_mem_malloc + (sizeof(tSirScanOffloadEvent)); + if (!scan_event) { + WMA_LOGE("Memory allocation failed for tSirScanOffloadEvent"); + return -ENOMEM; + } + + WMA_LOGI("scan event %u, id 0x%x, requestor 0x%x, freq %u, reason %u", + wmi_event->event, wmi_event->scan_id, wmi_event->requestor, + wmi_event->channel_freq, wmi_event->reason); + + scan_event->event = wmi_event->event; + scan_event->scanId = wmi_event->scan_id; + scan_event->requestor = wmi_event->requestor; + scan_event->chanFreq = wmi_event->channel_freq; + scan_event->sessionId = vdev_id; + scan_event->reasonCode = eSIR_SME_SCAN_FAILED; + + switch (wmi_event->event) { + case WMI_SCAN_EVENT_COMPLETED: + case WMI_SCAN_EVENT_DEQUEUED: + /* + * return success always so that SME can pick whatever scan + * results is available in scan cache(due to partial or + * aborted scan) + */ + scan_event->event = WMI_SCAN_EVENT_COMPLETED; + scan_event->reasonCode = eSIR_SME_SUCCESS; + break; + case WMI_SCAN_EVENT_START_FAILED: + scan_event->event = WMI_SCAN_EVENT_COMPLETED; + scan_event->reasonCode = eSIR_SME_SCAN_FAILED; + break; + case WMI_SCAN_EVENT_PREEMPTED: + WMA_LOGW("%s: Unhandled Scan Event WMI_SCAN_EVENT_PREEMPTED", + __func__); + break; + case WMI_SCAN_EVENT_RESTARTED: + WMA_LOGW("%s: Unhandled Scan Event WMI_SCAN_EVENT_RESTARTED", + __func__); + break; + } + + /* Stop scan completion timeout if event is WMI_SCAN_EVENT_COMPLETED */ + if (scan_event->event == + (enum sir_scan_event_type) WMI_SCAN_EVENT_COMPLETED) { + WMA_LOGI("scan complete:scan_id 0x%x, requestor 0x%x, vdev %d", + wmi_event->scan_id, wmi_event->requestor, vdev_id); + } + + wma_send_msg(wma_handle, WMA_RX_SCAN_EVENT, (void *)scan_event, 0); + + return 0; +} + +/** + * wma_roam_better_ap_handler() - better ap event handler + * @wma: wma handle + * @vdev_id: vdev id + * + * Handler for WMI_ROAM_REASON_BETTER_AP event from roam firmware in Rome. + * This event means roam algorithm in Rome has found a better matching + * candidate AP. The indication is sent to SME. + * + * Return: none + */ +void wma_roam_better_ap_handler(tp_wma_handle wma, uint32_t vdev_id) +{ + cds_msg_t cds_msg; + tSirSmeCandidateFoundInd *candidate_ind; + struct scan_param *params; + + params = &wma->interfaces[vdev_id].scan_info; + /* abort existing scans from GUI, but not roaming preauth scan */ + if (params->scan_id != 0 && params->chan_freq == 0 && + params->scan_requestor_id == USER_SCAN_REQUESTOR_ID) { + tAbortScanParams abortScan; + abortScan.SessionId = vdev_id; + abortScan.scan_id = params->scan_id; + abortScan.scan_requestor_id = params->scan_requestor_id; + wma_stop_scan(wma, &abortScan); + } + + candidate_ind = qdf_mem_malloc(sizeof(tSirSmeCandidateFoundInd)); + if (!candidate_ind) { + WMA_LOGE("%s: Alloc failed for tSirSmeCandidateFoundInd", + __func__); + return; + } + WMA_LOGD("%s: roaming in progress for vdev %d", + __func__, vdev_id); + wma->interfaces[vdev_id].roaming_in_progress = true; + + candidate_ind->messageType = eWNI_SME_CANDIDATE_FOUND_IND; + candidate_ind->sessionId = vdev_id; + candidate_ind->length = sizeof(tSirSmeCandidateFoundInd); + + cds_msg.type = eWNI_SME_CANDIDATE_FOUND_IND; + cds_msg.bodyptr = candidate_ind; + QDF_TRACE(QDF_MODULE_ID_WMA, QDF_TRACE_LEVEL_INFO, + FL("posting candidate ind to SME")); + + if (QDF_STATUS_SUCCESS != cds_mq_post_message(CDS_MQ_ID_SME, + (cds_msg_t *) &cds_msg)) { + qdf_mem_free(candidate_ind); + QDF_TRACE(QDF_MODULE_ID_WMA, QDF_TRACE_LEVEL_ERROR, + FL("Failed to post candidate ind to SME")); + } +} + +/** + * wma_roam_event_callback() - roam event callback + * @handle: wma handle + * @event_buf: event buffer + * @len: buffer length + * + * Handler for all events from roam engine in firmware + * + * Return: 0 for success or error code + */ +int wma_roam_event_callback(WMA_HANDLE handle, uint8_t *event_buf, + uint32_t len) +{ + tp_wma_handle wma_handle = (tp_wma_handle) handle; + WMI_ROAM_EVENTID_param_tlvs *param_buf; + wmi_roam_event_fixed_param *wmi_event; + struct sSirSmeRoamOffloadSynchInd *roam_synch_data; + enum sir_roam_op_code op_code = {0}; + + param_buf = (WMI_ROAM_EVENTID_param_tlvs *) event_buf; + if (!param_buf) { + WMA_LOGE("Invalid roam event buffer"); + return -EINVAL; + } + + wmi_event = param_buf->fixed_param; + WMA_LOGD("%s: Reason %x, Notif %x for vdevid %x, rssi %d", + __func__, wmi_event->reason, wmi_event->notif, + wmi_event->vdev_id, wmi_event->rssi); + wma_peer_debug_log(wmi_event->vdev_id, DEBUG_ROAM_EVENT, + DEBUG_INVALID_PEER_ID, NULL, NULL, + wmi_event->reason, + (wmi_event->reason == WMI_ROAM_REASON_INVALID) ? + wmi_event->notif : wmi_event->rssi); + + + DPTRACE(qdf_dp_trace_record_event(QDF_DP_TRACE_EVENT_RECORD, + wmi_event->vdev_id, QDF_PROTO_TYPE_EVENT, QDF_ROAM_EVENTID)); + + switch (wmi_event->reason) { + case WMI_ROAM_REASON_BMISS: + WMA_LOGD("Beacon Miss for vdevid %x", wmi_event->vdev_id); + wma_beacon_miss_handler(wma_handle, wmi_event->vdev_id, + wmi_event->rssi); + wma_sta_kickout_event(HOST_STA_KICKOUT_REASON_BMISS, + wmi_event->vdev_id, NULL); + break; + case WMI_ROAM_REASON_BETTER_AP: + WMA_LOGD("%s:Better AP found for vdevid %x, rssi %d", __func__, + wmi_event->vdev_id, wmi_event->rssi); + wma_handle->suitable_ap_hb_failure = false; + wma_roam_better_ap_handler(wma_handle, wmi_event->vdev_id); + break; + case WMI_ROAM_REASON_SUITABLE_AP: + wma_handle->suitable_ap_hb_failure = true; + wma_handle->suitable_ap_hb_failure_rssi = wmi_event->rssi; + WMA_LOGD("%s:Bmiss scan AP found for vdevid %x, rssi %d", + __func__, wmi_event->vdev_id, wmi_event->rssi); + wma_roam_better_ap_handler(wma_handle, wmi_event->vdev_id); + break; +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + case WMI_ROAM_REASON_HO_FAILED: + WMA_LOGE("LFR3:Hand-Off Failed for vdevid %x", + wmi_event->vdev_id); + wma_roam_ho_fail_handler(wma_handle, wmi_event->vdev_id); + break; +#endif + case WMI_ROAM_REASON_INVALID: + roam_synch_data = qdf_mem_malloc(sizeof(*roam_synch_data)); + if (NULL == roam_synch_data) { + WMA_LOGE("Memory unavailable for roam synch data"); + return -ENOMEM; + } + if (wmi_event->notif == WMI_ROAM_NOTIF_ROAM_START) + op_code = SIR_ROAMING_START; + if (wmi_event->notif == WMI_ROAM_NOTIF_ROAM_ABORT) + op_code = SIR_ROAMING_ABORT; + roam_synch_data->roamedVdevId = wmi_event->vdev_id; + wma_handle->csr_roam_synch_cb( + (tpAniSirGlobal)wma_handle->mac_context, + roam_synch_data, NULL, op_code); + qdf_mem_free(roam_synch_data); + break; + case WMI_ROAM_REASON_RSO_STATUS: + wma_rso_cmd_status_event_handler(wmi_event); + break; + case WMI_ROAM_REASON_INVOKE_ROAM_FAIL: + roam_synch_data = qdf_mem_malloc(sizeof(*roam_synch_data)); + if (!roam_synch_data) { + WMA_LOGE("Memory unavailable for roam synch data"); + return -ENOMEM; + } + roam_synch_data->roamedVdevId = wmi_event->vdev_id; + wma_handle->csr_roam_synch_cb( + (tpAniSirGlobal)wma_handle->mac_context, + roam_synch_data, NULL, SIR_ROAMING_INVOKE_FAIL); + qdf_mem_free(roam_synch_data); + break; + default: + WMA_LOGD("%s:Unhandled Roam Event %x for vdevid %x", __func__, + wmi_event->reason, wmi_event->vdev_id); + break; + } + return 0; +} + + +/** + * wma_set_rssi_monitoring() - set rssi monitoring + * @handle: WMA handle + * @req: rssi monitoring request structure + * + * This function reads the incoming @req and fill in the destination + * WMI structure and send down the rssi monitoring configs down to the firmware + * + * Return: 0 on success; error number otherwise + */ +QDF_STATUS wma_set_rssi_monitoring(tp_wma_handle wma, + struct rssi_monitor_req *req) +{ + struct rssi_monitor_param params = {0}; + + if (!wma) { + WMA_LOGE("%s: wma handle is NULL", __func__); + return QDF_STATUS_E_INVAL; + } + + params.request_id = req->request_id; + params.session_id = req->session_id; + params.min_rssi = req->min_rssi; + params.max_rssi = req->max_rssi; + params.control = req->control; + + return wmi_unified_set_rssi_monitoring_cmd(wma->wmi_handle, + ¶ms); +} + +/** + * wma_get_scan_id() - Generates scan id + * @scan_id: Scan id + * + * This function generates the scan id. + * + * Return: QDF_STATUS + */ + +QDF_STATUS wma_get_scan_id(uint32_t *scan_id) +{ + tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA); + + if (!scan_id) { + WMA_LOGE("Scan_id is NULL"); + return QDF_STATUS_E_FAULT; + } + + /* host need to cycle through the lower 12 bits to generate ids */ + *scan_id = qdf_atomic_inc_return(&wma->scan_id_counter) & + WMA_SCAN_ID_MASK; + /* + * Firmware expects the host scan request id appended + * by PREFIX 0xA000 + */ + *scan_id = *scan_id | WMI_HOST_SCAN_REQ_ID_PREFIX; + return QDF_STATUS_SUCCESS; +} + +#ifdef FEATURE_LFR_SUBNET_DETECTION +/** + * wma_set_gateway_params() - set gateway parameters + * @wma: WMA handle + * @req: gateway parameter update request structure + * + * This function reads the incoming @req and fill in the destination + * WMI structure and sends down the gateway configs down to the firmware + * + * Return: QDF_STATUS + */ +QDF_STATUS wma_set_gateway_params(tp_wma_handle wma, + struct gateway_param_update_req *req) +{ + struct gateway_update_req_param params = {0}; + + if (!wma) { + WMA_LOGE("%s: wma handle is NULL", __func__); + return QDF_STATUS_E_INVAL; + } + + params.request_id = req->request_id; + params.session_id = req->session_id; + params.max_retries = req->max_retries; + params.timeout = req->timeout; + params.ipv4_addr_type = req->ipv4_addr_type; + params.ipv6_addr_type = req->ipv6_addr_type; + qdf_mem_copy(¶ms.gw_mac_addr, &req->gw_mac_addr, + sizeof(struct qdf_mac_addr)); + qdf_mem_copy(params.ipv4_addr, req->ipv4_addr, + QDF_IPV4_ADDR_SIZE); + qdf_mem_copy(params.ipv6_addr, req->ipv6_addr, + QDF_IPV6_ADDR_SIZE); + + return wmi_unified_set_gateway_params_cmd(wma->wmi_handle, + ¶ms); +} +#endif /* FEATURE_LFR_SUBNET_DETECTION */ + +/** + * wma_ht40_stop_obss_scan() - ht40 obss stop scan + * @wma: WMA handel + * @vdev_id: vdev identifier + * + * Return: Return QDF_STATUS, otherwise appropriate failure code + */ +QDF_STATUS wma_ht40_stop_obss_scan(tp_wma_handle wma, int32_t vdev_id) +{ + + wmi_buf_t buf; + wmi_obss_scan_disable_cmd_fixed_param *cmd; + int ret; + int len = sizeof(*cmd); + + buf = wmi_buf_alloc(wma->wmi_handle, len); + if (!buf) { + WMA_LOGP("%s: wmi_buf_alloc failed", __func__); + return QDF_STATUS_E_NOMEM; + } + + WMA_LOGD("cmd %x vdev_id %d", WMI_OBSS_SCAN_DISABLE_CMDID, vdev_id); + + cmd = (wmi_obss_scan_disable_cmd_fixed_param *) wmi_buf_data(buf); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_obss_scan_disable_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN( + wmi_obss_scan_disable_cmd_fixed_param)); + + cmd->vdev_id = vdev_id; + ret = wmi_unified_cmd_send(wma->wmi_handle, buf, len, + WMI_OBSS_SCAN_DISABLE_CMDID); + if (ret != EOK) { + WMA_LOGE("Failed to send gw config parameter to fw, ret: %d", + ret); + wmi_buf_free(buf); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * wma_send_ht40_obss_scanind() - ht40 obss start scan indication + * @wma: WMA handel + * @req: start scan request + * + * Return: Return QDF_STATUS, otherwise appropriate failure code + */ +QDF_STATUS wma_send_ht40_obss_scanind(tp_wma_handle wma, + struct obss_ht40_scanind *req) +{ + wmi_buf_t buf; + wmi_obss_scan_enable_cmd_fixed_param *cmd; + int ret; + int len = 0; + uint8_t *buf_ptr, i; + uint8_t *channel_list; + + len += sizeof(wmi_obss_scan_enable_cmd_fixed_param); + + len += WMI_TLV_HDR_SIZE; + len += qdf_roundup(sizeof(uint8_t) * req->channel_count, + sizeof(uint32_t)); + + len += WMI_TLV_HDR_SIZE; + len += qdf_roundup(sizeof(uint8_t) * 1, sizeof(uint32_t)); + + WMA_LOGE("cmdlen %d vdev_id %d channel count %d iefield_len %d", + len, req->bss_id, req->channel_count, req->iefield_len); + + WMA_LOGE("scantype %d active_time %d passive %d Obss interval %d", + req->scan_type, req->obss_active_dwelltime, + req->obss_passive_dwelltime, + req->obss_width_trigger_interval); + + buf = wmi_buf_alloc(wma->wmi_handle, len); + if (!buf) { + WMA_LOGP("%s: wmi_buf_alloc failed", __func__); + return QDF_STATUS_E_NOMEM; + } + + cmd = (wmi_obss_scan_enable_cmd_fixed_param *) wmi_buf_data(buf); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_obss_scan_enable_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN(wmi_obss_scan_enable_cmd_fixed_param)); + + buf_ptr = (uint8_t *) cmd; + + cmd->vdev_id = req->bss_id; + cmd->scan_type = req->scan_type; + cmd->obss_scan_active_dwell = + req->obss_active_dwelltime; + cmd->obss_scan_passive_dwell = + req->obss_passive_dwelltime; + cmd->bss_channel_width_trigger_scan_interval = + req->obss_width_trigger_interval; + cmd->bss_width_channel_transition_delay_factor = + req->bsswidth_ch_trans_delay; + cmd->obss_scan_active_total_per_channel = + req->obss_active_total_per_channel; + cmd->obss_scan_passive_total_per_channel = + req->obss_passive_total_per_channel; + cmd->obss_scan_activity_threshold = + req->obss_activity_threshold; + + cmd->channel_len = req->channel_count; + cmd->forty_mhz_intolerant = req->fortymhz_intolerent; + cmd->current_operating_class = req->current_operatingclass; + cmd->ie_len = req->iefield_len; + + buf_ptr += sizeof(wmi_obss_scan_enable_cmd_fixed_param); + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE, + qdf_roundup(req->channel_count, sizeof(uint32_t))); + + buf_ptr += WMI_TLV_HDR_SIZE; + channel_list = (uint8_t *) buf_ptr; + + for (i = 0; i < req->channel_count; i++) { + channel_list[i] = req->channels[i]; + WMA_LOGD("Ch[%d]: %d ", i, channel_list[i]); + } + + buf_ptr += qdf_roundup(sizeof(uint8_t) * req->channel_count, + sizeof(uint32_t)); + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE, + qdf_roundup(1, sizeof(uint32_t))); + buf_ptr += WMI_TLV_HDR_SIZE; + + ret = wmi_unified_cmd_send(wma->wmi_handle, buf, len, + WMI_OBSS_SCAN_ENABLE_CMDID); + if (ret != EOK) { + WMA_LOGE("Failed to send gw config parameter to fw, ret: %d", + ret); + wmi_buf_free(buf); + return QDF_STATUS_E_FAILURE; + } + return QDF_STATUS_SUCCESS; +} diff --git a/drivers/staging/qcacld-3.0/core/wma/src/wma_utils.c b/drivers/staging/qcacld-3.0/core/wma/src/wma_utils.c new file mode 100644 index 0000000000000000000000000000000000000000..caa794dbfb8da777b2bacad34f4806614117a1ec --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/wma/src/wma_utils.c @@ -0,0 +1,4491 @@ +/* + * Copyright (c) 2013-2017 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: wma_utis.c + * This file contains utilities and stats related functions. + */ + +/* Header files */ + +#include "wma.h" +#include "wma_api.h" +#include "cds_api.h" +#include "wmi_unified_api.h" +#include "wlan_qct_sys.h" +#include "wni_api.h" +#include "ani_global.h" +#include "wmi_unified.h" +#include "wni_cfg.h" +#include "cfg_api.h" + +#include "qdf_nbuf.h" +#include "qdf_types.h" +#include "qdf_mem.h" +#include "ol_txrx_peer_find.h" + +#include "wma_types.h" +#include "lim_api.h" +#include "lim_session_utils.h" + +#include "cds_utils.h" + +#if !defined(REMOVE_PKT_LOG) +#include "pktlog_ac.h" +#endif /* REMOVE_PKT_LOG */ + +#include "dbglog_host.h" +#include "csr_api.h" +#include "ol_fw.h" + +#include "dfs.h" +#include "wma_internal.h" +#include "cds_concurrency.h" +#include "wmi_unified_param.h" +#include "linux/ieee80211.h" + +/* MCS Based rate table */ +/* HT MCS parameters with Nss = 1 */ +static struct index_data_rate_type mcs_nss1[] = { + /* MCS L20 S20 L40 S40 */ + {0, {65, 72}, {135, 150 } }, + {1, {130, 144}, {270, 300 } }, + {2, {195, 217}, {405, 450 } }, + {3, {260, 289}, {540, 600 } }, + {4, {390, 433}, {815, 900 } }, + {5, {520, 578}, {1080, 1200} }, + {6, {585, 650}, {1215, 1350} }, + {7, {650, 722}, {1350, 1500} } +}; + +/* HT MCS parameters with Nss = 2 */ +static struct index_data_rate_type mcs_nss2[] = { + /* MCS L20 S20 L40 S40 */ + {0, {130, 144}, {270, 300 } }, + {1, {260, 289}, {540, 600 } }, + {2, {390, 433}, {810, 900 } }, + {3, {520, 578}, {1080, 1200} }, + {4, {780, 867}, {1620, 1800} }, + {5, {1040, 1156}, {2160, 2400} }, + {6, {1170, 1300}, {2430, 2700} }, + {7, {1300, 1440}, {2700, 3000} } +}; + +/* MCS Based VHT rate table */ +/* MCS parameters with Nss = 1*/ +static struct index_vht_data_rate_type vht_mcs_nss1[] = { + /* MCS L20 S20 L40 S40 L80 S80 */ + {0, {65, 72 }, {135, 150}, {293, 325} }, + {1, {130, 144}, {270, 300}, {585, 650} }, + {2, {195, 217}, {405, 450}, {878, 975} }, + {3, {260, 289}, {540, 600}, {1170, 1300} }, + {4, {390, 433}, {810, 900}, {1755, 1950} }, + {5, {520, 578}, {1080, 1200}, {2340, 2600} }, + {6, {585, 650}, {1215, 1350}, {2633, 2925} }, + {7, {650, 722}, {1350, 1500}, {2925, 3250} }, + {8, {780, 867}, {1620, 1800}, {3510, 3900} }, + {9, {865, 960}, {1800, 2000}, {3900, 4333} } +}; + +/*MCS parameters with Nss = 2*/ +static struct index_vht_data_rate_type vht_mcs_nss2[] = { + /* MCS L20 S20 L40 S40 L80 S80 */ + {0, {130, 144}, {270, 300}, { 585, 650} }, + {1, {260, 289}, {540, 600}, {1170, 1300} }, + {2, {390, 433}, {810, 900}, {1755, 1950} }, + {3, {520, 578}, {1080, 1200}, {2340, 2600} }, + {4, {780, 867}, {1620, 1800}, {3510, 3900} }, + {5, {1040, 1156}, {2160, 2400}, {4680, 5200} }, + {6, {1170, 1300}, {2430, 2700}, {5265, 5850} }, + {7, {1300, 1444}, {2700, 3000}, {5850, 6500} }, + {8, {1560, 1733}, {3240, 3600}, {7020, 7800} }, + {9, {1730, 1920}, {3600, 4000}, {7800, 8667} } +}; + +#ifdef BIG_ENDIAN_HOST + +/* ############# function definitions ############ */ + +/** + * wma_swap_bytes() - swap bytes + * @pv: buffer + * @n: swap bytes + * + * Return: none + */ +void wma_swap_bytes(void *pv, uint32_t n) +{ + int32_t no_words; + int32_t i; + uint32_t *word_ptr; + + no_words = n / sizeof(uint32_t); + word_ptr = (uint32_t *) pv; + for (i = 0; i < no_words; i++) { + *(word_ptr + i) = __cpu_to_le32(*(word_ptr + i)); + } +} + +#define SWAPME(x, len) wma_swap_bytes(&x, len); +#endif /* BIG_ENDIAN_HOST */ + +/** + * wma_mcs_rate_match() - find the match mcs rate + * @match_rate: the rate to look up + * @is_sgi: return if the SGI rate is found + * @nss: the nss in use + * @nss1_rate: the nss1 rate + * @nss1_srate: the nss1 SGI rate + * @nss2_rate: the nss2 rate + * @nss2_srate: the nss2 SGI rate + * + * This is a helper function to find the match of the tx_rate + * in terms of the nss1/nss2 rate with non-SGI/SGI. + * + * Return: the found rate or 0 otherwise + */ +static inline uint16_t wma_mcs_rate_match(uint16_t match_rate, bool *is_sgi, + uint8_t nss, uint16_t nss1_rate, + uint16_t nss1_srate, + uint16_t nss2_rate, + uint16_t nss2_srate) +{ + WMA_LOGD("%s match_rate: %d, %d %d %d %d", + __func__, match_rate, nss1_rate, nss1_srate, nss2_rate, + nss2_srate); + + if (match_rate == nss1_rate) { + return nss1_rate; + } else if (match_rate == nss1_srate) { + *is_sgi = true; + return nss1_srate; + } else if (nss == 2 && match_rate == nss2_rate) + return nss2_rate; + else if (nss == 2 && match_rate == nss2_srate) { + *is_sgi = true; + return nss2_srate; + } else + return 0; +} + +/** + * wma_get_mcs_idx() - get mcs index + * @maxRate: max rate + * @rate_flags: rate flags + * @nss: number of nss + * @mcsRateFlag: mcs rate flag + * + * Return: return mcs index + */ +static uint8_t wma_get_mcs_idx(uint16_t maxRate, uint8_t rate_flags, + uint8_t nss, uint8_t *mcsRateFlag) +{ + uint8_t index = 0; + uint16_t match_rate = 0; + bool is_sgi = false; + + WMA_LOGD("%s rate:%d rate_flgs: 0x%x, nss: %d", + __func__, maxRate, rate_flags, nss); + + *mcsRateFlag = rate_flags; + *mcsRateFlag &= ~eHAL_TX_RATE_SGI; + for (index = 0; index < MAX_VHT_MCS_IDX; index++) { + if (rate_flags & eHAL_TX_RATE_VHT80) { + /* check for vht80 nss1/2 rate set */ + match_rate = wma_mcs_rate_match(maxRate, &is_sgi, nss, + vht_mcs_nss1[index].ht80_rate[0], + vht_mcs_nss1[index].ht80_rate[1], + vht_mcs_nss2[index].ht80_rate[0], + vht_mcs_nss2[index].ht80_rate[1]); + if (match_rate) + goto rate_found; + } + if ((rate_flags & eHAL_TX_RATE_VHT40) | + (rate_flags & eHAL_TX_RATE_VHT80)) { + /* check for vht40 nss1/2 rate set */ + match_rate = wma_mcs_rate_match(maxRate, &is_sgi, nss, + vht_mcs_nss1[index].ht40_rate[0], + vht_mcs_nss1[index].ht40_rate[1], + vht_mcs_nss2[index].ht40_rate[0], + vht_mcs_nss2[index].ht40_rate[1]); + if (match_rate) { + *mcsRateFlag &= ~eHAL_TX_RATE_VHT80; + goto rate_found; + } + } + if ((rate_flags & eHAL_TX_RATE_VHT20) | + (rate_flags & eHAL_TX_RATE_VHT40) | + (rate_flags & eHAL_TX_RATE_VHT80)) { + /* check for vht20 nss1/2 rate set */ + match_rate = wma_mcs_rate_match(maxRate, &is_sgi, nss, + vht_mcs_nss1[index].ht20_rate[0], + vht_mcs_nss1[index].ht20_rate[1], + vht_mcs_nss2[index].ht20_rate[0], + vht_mcs_nss2[index].ht20_rate[1]); + if (match_rate) { + *mcsRateFlag &= ~(eHAL_TX_RATE_VHT80 | + eHAL_TX_RATE_VHT40); + goto rate_found; + } + } + } + for (index = 0; index < MAX_HT_MCS_IDX; index++) { + if (rate_flags & eHAL_TX_RATE_HT40) { + /* check for ht40 nss1/2 rate set */ + match_rate = wma_mcs_rate_match(maxRate, &is_sgi, nss, + mcs_nss1[index].ht40_rate[0], + mcs_nss1[index].ht40_rate[1], + mcs_nss2[index].ht40_rate[0], + mcs_nss2[index].ht40_rate[1]); + if (match_rate) { + *mcsRateFlag = eHAL_TX_RATE_HT40; + goto rate_found; + } + } + if ((rate_flags & eHAL_TX_RATE_HT20) || + (rate_flags & eHAL_TX_RATE_HT40)) { + /* check for ht20 nss1/2 rate set */ + match_rate = wma_mcs_rate_match(maxRate, &is_sgi, nss, + mcs_nss1[index].ht20_rate[0], + mcs_nss1[index].ht20_rate[1], + mcs_nss2[index].ht20_rate[0], + mcs_nss2[index].ht20_rate[1]); + if (match_rate) { + *mcsRateFlag = eHAL_TX_RATE_HT20; + goto rate_found; + } + } + } + +rate_found: + /* set SGI flag only if this is SGI rate */ + if (match_rate && is_sgi == true) + *mcsRateFlag |= eHAL_TX_RATE_SGI; + + WMA_LOGD("%s - match_rate: %d index: %d rate_flag: 0x%x is_sgi: %d", + __func__, match_rate, index, *mcsRateFlag, is_sgi); + + return match_rate ? index : INVALID_MCS_IDX; +} + +/** + * wma_peek_vdev_req() - peek what request message is queued for response. + * the function does not delete the node after found + * @wma: WMA handle + * @vdev_id: vdev ID + * @type: request message type + * + * Return: the request message found + */ +static struct wma_target_req *wma_peek_vdev_req(tp_wma_handle wma, + uint8_t vdev_id, uint8_t type) +{ + struct wma_target_req *req_msg = NULL; + bool found = false; + qdf_list_node_t *node1 = NULL, *node2 = NULL; + + qdf_spin_lock_bh(&wma->vdev_respq_lock); + if (QDF_STATUS_SUCCESS != qdf_list_peek_front(&wma->vdev_resp_queue, + &node2)) { + qdf_spin_unlock_bh(&wma->vdev_respq_lock); + return NULL; + } + + do { + node1 = node2; + req_msg = qdf_container_of(node1, struct wma_target_req, node); + if (req_msg->vdev_id != vdev_id) + continue; + if (req_msg->type != type) + continue; + + found = true; + break; + } while (QDF_STATUS_SUCCESS == qdf_list_peek_next(&wma->vdev_resp_queue, + node1, &node2)); + qdf_spin_unlock_bh(&wma->vdev_respq_lock); + if (!found) { + WMA_LOGP(FL("target request not found for vdev_id %d type %d"), + vdev_id, type); + return NULL; + } + WMA_LOGD(FL("target request found for vdev id: %d type %d msg %d"), + vdev_id, type, req_msg->msg_type); + return req_msg; +} + +void wma_lost_link_info_handler(tp_wma_handle wma, uint32_t vdev_id, + int32_t rssi) +{ + struct sir_lost_link_info *lost_link_info; + QDF_STATUS qdf_status; + cds_msg_t sme_msg = {0}; + + /* report lost link information only for STA mode */ + if (wma->interfaces[vdev_id].vdev_up && + (WMI_VDEV_TYPE_STA == wma->interfaces[vdev_id].type) && + (0 == wma->interfaces[vdev_id].sub_type)) { + lost_link_info = qdf_mem_malloc(sizeof(*lost_link_info)); + if (NULL == lost_link_info) { + WMA_LOGE("%s: failed to allocate memory", __func__); + return; + } + lost_link_info->vdev_id = vdev_id; + lost_link_info->rssi = rssi; + sme_msg.type = eWNI_SME_LOST_LINK_INFO_IND; + sme_msg.bodyptr = lost_link_info; + sme_msg.bodyval = 0; + WMA_LOGI("%s: post msg to SME, bss_idx %d, rssi %d", __func__, + lost_link_info->vdev_id, lost_link_info->rssi); + + qdf_status = cds_mq_post_message(QDF_MODULE_ID_SME, &sme_msg); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + WMA_LOGE("%s: fail to post msg to SME", __func__); + qdf_mem_free(lost_link_info); + } + } +} + +/** + * host_map_smps_mode() - map fw smps mode to tSmpsModeValue + * @fw_smps_mode: fw smps mode + * + * Return: return tSmpsModeValue + */ +tSmpsModeValue host_map_smps_mode(A_UINT32 fw_smps_mode) +{ + tSmpsModeValue smps_mode = SMPS_MODE_DISABLED; + switch (fw_smps_mode) { + case WMI_SMPS_FORCED_MODE_STATIC: + smps_mode = STATIC_SMPS_MODE; + break; + case WMI_SMPS_FORCED_MODE_DYNAMIC: + smps_mode = DYNAMIC_SMPS_MODE; + break; + default: + smps_mode = SMPS_MODE_DISABLED; + } + + return smps_mode; +} + +/** + * wma_smps_mode_to_force_mode_param() - Map smps mode to force + * mode commmand param + * @smps_mode: SMPS mode according to the protocol + * + * Return: int > 0 for success else failure + */ +int wma_smps_mode_to_force_mode_param(uint8_t smps_mode) +{ + int param = -EINVAL; + + switch (smps_mode) { + case STATIC_SMPS_MODE: + param = WMI_SMPS_FORCED_MODE_STATIC; + break; + case DYNAMIC_SMPS_MODE: + param = WMI_SMPS_FORCED_MODE_DYNAMIC; + break; + case SMPS_MODE_DISABLED: + param = WMI_SMPS_FORCED_MODE_DISABLED; + break; + default: + WMA_LOGE(FL("smps mode cannot be mapped :%d "), + smps_mode); + } + return param; +} + +#ifdef WLAN_FEATURE_STATS_EXT +/** + * wma_stats_ext_event_handler() - extended stats event handler + * @handle: wma handle + * @event_buf: event buffer received from fw + * @len: length of data + * + * Return: 0 for success or error code + */ +int wma_stats_ext_event_handler(void *handle, uint8_t *event_buf, + uint32_t len) +{ + WMI_STATS_EXT_EVENTID_param_tlvs *param_buf; + tSirStatsExtEvent *stats_ext_event; + wmi_stats_ext_event_fixed_param *stats_ext_info; + QDF_STATUS status; + cds_msg_t cds_msg; + uint8_t *buf_ptr; + uint32_t alloc_len; + + WMA_LOGD("%s: Posting stats ext event to SME", __func__); + + param_buf = (WMI_STATS_EXT_EVENTID_param_tlvs *) event_buf; + if (!param_buf) { + WMA_LOGE("%s: Invalid stats ext event buf", __func__); + return -EINVAL; + } + + stats_ext_info = param_buf->fixed_param; + buf_ptr = (uint8_t *) stats_ext_info; + + alloc_len = sizeof(tSirStatsExtEvent); + alloc_len += stats_ext_info->data_len; + + stats_ext_event = (tSirStatsExtEvent *) qdf_mem_malloc(alloc_len); + if (NULL == stats_ext_event) { + WMA_LOGE("%s: Memory allocation failure", __func__); + return -ENOMEM; + } + + buf_ptr += sizeof(wmi_stats_ext_event_fixed_param) + WMI_TLV_HDR_SIZE; + + stats_ext_event->vdev_id = stats_ext_info->vdev_id; + stats_ext_event->event_data_len = stats_ext_info->data_len; + qdf_mem_copy(stats_ext_event->event_data, + buf_ptr, stats_ext_event->event_data_len); + + cds_msg.type = eWNI_SME_STATS_EXT_EVENT; + cds_msg.bodyptr = (void *)stats_ext_event; + cds_msg.bodyval = 0; + + status = cds_mq_post_message(CDS_MQ_ID_SME, &cds_msg); + if (status != QDF_STATUS_SUCCESS) { + WMA_LOGE("%s: Failed to post stats ext event to SME", __func__); + qdf_mem_free(stats_ext_event); + return -EFAULT; + } + + WMA_LOGD("%s: stats ext event Posted to SME", __func__); + return 0; +} +#endif /* WLAN_FEATURE_STATS_EXT */ + + +/** + * wma_profile_data_report_event_handler() - fw profiling handler + * @handle: wma handle + * @event_buf: event buffer received from fw + * @len: length of data + * + * Return: 0 for success or error code + */ +int wma_profile_data_report_event_handler(void *handle, uint8_t *event_buf, + uint32_t len) +{ + WMI_WLAN_PROFILE_DATA_EVENTID_param_tlvs *param_buf; + wmi_wlan_profile_ctx_t *profile_ctx; + wmi_wlan_profile_t *profile_data; + uint32_t i = 0; + uint32_t entries; + uint8_t *buf_ptr; + char temp_str[150]; + param_buf = (WMI_WLAN_PROFILE_DATA_EVENTID_param_tlvs *) event_buf; + + if (!param_buf) { + WMA_LOGE("%s: Invalid profile data event buf", __func__); + return -EINVAL; + } + profile_ctx = param_buf->profile_ctx; + buf_ptr = (uint8_t *)profile_ctx; + buf_ptr = buf_ptr + sizeof(wmi_wlan_profile_ctx_t) + WMI_TLV_HDR_SIZE; + profile_data = (wmi_wlan_profile_t *) buf_ptr; + entries = profile_ctx->bin_count; + QDF_TRACE(QDF_MODULE_ID_WMA, QDF_TRACE_LEVEL_ERROR, + "Profile data stats\n"); + QDF_TRACE(QDF_MODULE_ID_WMA, QDF_TRACE_LEVEL_ERROR, + "TOT: %d\n" + "tx_msdu_cnt: %d\n" + "tx_mpdu_cnt: %d\n" + "tx_ppdu_cnt: %d\n" + "rx_msdu_cnt: %d\n" + "rx_mpdu_cnt: %d\n" + "bin_count: %d\n", + profile_ctx->tot, + profile_ctx->tx_msdu_cnt, + profile_ctx->tx_mpdu_cnt, + profile_ctx->tx_ppdu_cnt, + profile_ctx->rx_msdu_cnt, + profile_ctx->rx_mpdu_cnt, + profile_ctx->bin_count); + + QDF_TRACE(QDF_MODULE_ID_WMA, QDF_TRACE_LEVEL_ERROR, + "Profile ID: Count: TOT: Min: Max: hist_intvl: hist[0]: hist[1]:hist[2]"); + + for (i = 0; i < entries; i++) { + if (i == WMI_WLAN_PROFILE_MAX_BIN_CNT) + break; + snprintf(temp_str, sizeof(temp_str), + " %d : %d : %d : %d : %d : %d : %d : %d : %d", + profile_data[i].id, + profile_data[i].cnt, + profile_data[i].tot, + profile_data[i].min, + profile_data[i].max, + profile_data[i].hist_intvl, + profile_data[i].hist[0], + profile_data[i].hist[1], + profile_data[i].hist[2]); + QDF_TRACE(QDF_MODULE_ID_WMA, QDF_TRACE_LEVEL_ERROR, + "%s", temp_str); + } + + return 0; +} + +#ifdef WLAN_FEATURE_LINK_LAYER_STATS + +/** + * wma_unified_link_peer_stats_event_handler() - peer stats event handler + * @handle: wma handle + * @cmd_param_info: data received with event from fw + * @len: length of data + * + * Return: 0 for success or error code + */ +static int wma_unified_link_peer_stats_event_handler(void *handle, + uint8_t *cmd_param_info, + uint32_t len) +{ + WMI_PEER_LINK_STATS_EVENTID_param_tlvs *param_tlvs; + wmi_peer_stats_event_fixed_param *fixed_param; + wmi_peer_link_stats *peer_stats, *temp_peer_stats; + wmi_rate_stats *rate_stats; + tSirLLStatsResults *link_stats_results; + uint8_t *results, *t_peer_stats, *t_rate_stats; + uint32_t count, num_rates = 0, rate_cnt; + uint32_t next_res_offset, next_peer_offset, next_rate_offset; + size_t peer_info_size, peer_stats_size, rate_stats_size; + size_t link_stats_results_size; + + tpAniSirGlobal pMac = cds_get_context(QDF_MODULE_ID_PE); + + if (!pMac) { + WMA_LOGD("%s: NULL pMac ptr. Exiting", __func__); + return -EINVAL; + } + + if (!pMac->sme.pLinkLayerStatsIndCallback) { + WMA_LOGD("%s: HDD callback is null", __func__); + return -EINVAL; + } + + param_tlvs = (WMI_PEER_LINK_STATS_EVENTID_param_tlvs *) cmd_param_info; + if (!param_tlvs) { + WMA_LOGA("%s: Invalid stats event", __func__); + return -EINVAL; + } + /* + * cmd_param_info contains + * wmi_peer_stats_event_fixed_param fixed_param; + * num_peers * size of(struct wmi_peer_link_stats) + * num_rates * size of(struct wmi_rate_stats) + * num_rates is the sum of the rates of all the peers. + */ + fixed_param = param_tlvs->fixed_param; + peer_stats = param_tlvs->peer_stats; + rate_stats = param_tlvs->peer_rate_stats; + + if (!fixed_param || !peer_stats || + (peer_stats->num_rates && !rate_stats)) { + WMA_LOGA("%s: Invalid param_tlvs for Peer Stats", __func__); + return -EINVAL; + } + + /* + * num_rates - sum of the rates of all the peers + */ + temp_peer_stats = (wmi_peer_link_stats *) peer_stats; + for (count = 0; count < fixed_param->num_peers; count++) { + num_rates += temp_peer_stats->num_rates; + temp_peer_stats++; + } + + peer_stats_size = sizeof(tSirWifiPeerStat); + peer_info_size = sizeof(tSirWifiPeerInfo); + rate_stats_size = sizeof(tSirWifiRateStat); + link_stats_results_size = + sizeof(*link_stats_results) + peer_stats_size + + (fixed_param->num_peers * peer_info_size) + + (num_rates * rate_stats_size); + + link_stats_results = qdf_mem_malloc(link_stats_results_size); + if (NULL == link_stats_results) { + WMA_LOGD("%s: could not allocate mem for stats results-len %zu", + __func__, link_stats_results_size); + return -ENOMEM; + } + + qdf_mem_zero(link_stats_results, link_stats_results_size); + + link_stats_results->paramId = WMI_LINK_STATS_ALL_PEER; + link_stats_results->rspId = fixed_param->request_id; + link_stats_results->ifaceId = 0; + link_stats_results->num_peers = fixed_param->num_peers; + link_stats_results->peer_event_number = fixed_param->peer_event_number; + link_stats_results->moreResultToFollow = fixed_param->more_data; + + qdf_mem_copy(link_stats_results->results, + &fixed_param->num_peers, peer_stats_size); + + results = (uint8_t *) link_stats_results->results; + t_peer_stats = (uint8_t *) peer_stats; + t_rate_stats = (uint8_t *) rate_stats; + next_res_offset = peer_stats_size; + next_peer_offset = WMI_TLV_HDR_SIZE; + next_rate_offset = WMI_TLV_HDR_SIZE; + for (rate_cnt = 0; rate_cnt < fixed_param->num_peers; rate_cnt++) { + qdf_mem_copy(results + next_res_offset, + t_peer_stats + next_peer_offset, peer_info_size); + next_res_offset += peer_info_size; + + /* Copy rate stats associated with this peer */ + for (count = 0; count < peer_stats->num_rates; count++) { + rate_stats++; + + qdf_mem_copy(results + next_res_offset, + t_rate_stats + next_rate_offset, + rate_stats_size); + next_res_offset += rate_stats_size; + next_rate_offset += sizeof(*rate_stats); + } + next_peer_offset += sizeof(*peer_stats); + peer_stats++; + } + + /* call hdd callback with Link Layer Statistics + * vdev_id/ifacId in link_stats_results will be + * used to retrieve the correct HDD context + */ + pMac->sme.pLinkLayerStatsIndCallback(pMac->hHdd, + WMA_LINK_LAYER_STATS_RESULTS_RSP, + link_stats_results); + qdf_mem_free(link_stats_results); + + return 0; +} + +/** + * wma_unified_radio_tx_mem_free() - Free radio tx power stats memory + * @handle: WMI handle + * + * Return: 0 on success, error number otherwise. + */ +static int wma_unified_radio_tx_mem_free(void *handle) +{ + tp_wma_handle wma_handle = (tp_wma_handle) handle; + tSirWifiRadioStat *rs_results; + uint32_t i = 0; + + if (!wma_handle->link_stats_results) + return 0; + + rs_results = (tSirWifiRadioStat *)&wma_handle->link_stats_results->results[0]; + for (i = 0; i < wma_handle->link_stats_results->num_radio; i++) { + rs_results += i; + if (rs_results->tx_time_per_power_level) { + qdf_mem_free(rs_results->tx_time_per_power_level); + rs_results->tx_time_per_power_level = NULL; + } + + if (rs_results->channels) { + qdf_mem_free(rs_results->channels); + rs_results->channels = NULL; + } + } + + qdf_mem_free(wma_handle->link_stats_results); + wma_handle->link_stats_results = NULL; + + return 0; +} + +/** + * wma_unified_radio_tx_power_level_stats_event_handler() - tx power level stats + * @handle: WMI handle + * @cmd_param_info: command param info + * @len: Length of @cmd_param_info + * + * This is the WMI event handler function to receive radio stats tx + * power level stats. + * + * Return: 0 on success, error number otherwise. +*/ +static int wma_unified_radio_tx_power_level_stats_event_handler(void *handle, + u_int8_t *cmd_param_info, u_int32_t len) +{ + tp_wma_handle wma_handle = (tp_wma_handle) handle; + WMI_RADIO_TX_POWER_LEVEL_STATS_EVENTID_param_tlvs *param_tlvs; + wmi_tx_power_level_stats_evt_fixed_param *fixed_param; + uint8_t *tx_power_level_values; + tSirLLStatsResults *link_stats_results; + tSirWifiRadioStat *rs_results; + + tpAniSirGlobal mac = cds_get_context(QDF_MODULE_ID_PE); + + if (!mac) { + WMA_LOGD("%s: NULL pMac ptr. Exiting", __func__); + return -EINVAL; + } + + if (!mac->sme.pLinkLayerStatsIndCallback) { + WMA_LOGD("%s: HDD callback is null", __func__); + return -EINVAL; + } + + param_tlvs = (WMI_RADIO_TX_POWER_LEVEL_STATS_EVENTID_param_tlvs *)cmd_param_info; + if (!param_tlvs) { + WMA_LOGA("%s: Invalid tx power level stats event", __func__); + return -EINVAL; + } + + fixed_param = param_tlvs->fixed_param; + if (!fixed_param) { + WMA_LOGA("%s: Invalid param_tlvs for Radio tx_power level Stats", __func__); + return -EINVAL; + } + + link_stats_results = wma_handle->link_stats_results; + if (!link_stats_results) { + WMA_LOGA("%s: link_stats_results is NULL", __func__); + return -EINVAL; + } + + WMA_LOGD("%s: tot_num_tx_pwr_lvls: %u num_tx_pwr_lvls: %u pwr_lvl_offset: %u radio_id: %u", + __func__, fixed_param->total_num_tx_power_levels, + fixed_param->num_tx_power_levels, + fixed_param->power_level_offset, + fixed_param->radio_id); + + rs_results = (tSirWifiRadioStat *) &link_stats_results->results[0] + fixed_param->radio_id; + tx_power_level_values = (uint8_t *) param_tlvs->tx_time_per_power_level; + + rs_results->total_num_tx_power_levels = + fixed_param->total_num_tx_power_levels; + if (!rs_results->total_num_tx_power_levels) { + link_stats_results->nr_received++; + goto post_stats; + } + + if (!rs_results->tx_time_per_power_level) { + rs_results->tx_time_per_power_level = qdf_mem_malloc( + sizeof(uint32_t) * + rs_results->total_num_tx_power_levels); + if (!rs_results->tx_time_per_power_level) { + WMA_LOGA("%s: Mem alloc failed for tx power level stats", __func__); + /* In error case, atleast send the radio stats without + * tx_power_level stats */ + rs_results->total_num_tx_power_levels = 0; + link_stats_results->nr_received++; + goto post_stats; + } + } + qdf_mem_copy(&rs_results->tx_time_per_power_level[fixed_param->power_level_offset], + tx_power_level_values, + sizeof(uint32_t) * fixed_param->num_tx_power_levels); + if (rs_results->total_num_tx_power_levels == + (fixed_param->num_tx_power_levels + fixed_param->power_level_offset)) { + link_stats_results->moreResultToFollow = 0; + link_stats_results->nr_received++; + } + + WMA_LOGD("%s: moreResultToFollow: %u nr: %u nr_received: %u", + __func__, link_stats_results->moreResultToFollow, + link_stats_results->num_radio, + link_stats_results->nr_received); + + /* If still data to receive, return from here */ + if (link_stats_results->moreResultToFollow) + return 0; + +post_stats: + if (link_stats_results->num_radio != link_stats_results->nr_received) { + /* Not received all radio stats yet, don't post yet */ + return 0; + } + + /* call hdd callback with Link Layer Statistics + * vdev_id/ifacId in link_stats_results will be + * used to retrieve the correct HDD context + */ + mac->sme.pLinkLayerStatsIndCallback(mac->hHdd, + WMA_LINK_LAYER_STATS_RESULTS_RSP, + link_stats_results); + wma_unified_radio_tx_mem_free(handle); + + return 0; +} + +/** + * wma_unified_link_radio_stats_event_handler() - radio link stats event handler + * @handle: wma handle + * @cmd_param_info: data received with event from fw + * @len: length of data + * + * Return: 0 for success or error code + */ +static int wma_unified_link_radio_stats_event_handler(void *handle, + uint8_t *cmd_param_info, + uint32_t len) +{ + tp_wma_handle wma_handle = (tp_wma_handle) handle; + WMI_RADIO_LINK_STATS_EVENTID_param_tlvs *param_tlvs; + wmi_radio_link_stats_event_fixed_param *fixed_param; + wmi_radio_link_stats *radio_stats; + wmi_channel_stats *channel_stats; + tSirLLStatsResults *link_stats_results; + uint8_t *results, *t_radio_stats, *t_channel_stats; + uint32_t next_chan_offset, count; + size_t radio_stats_size, chan_stats_size; + size_t link_stats_results_size; + tSirWifiRadioStat *rs_results; + tSirWifiChannelStats *chn_results; + + tpAniSirGlobal pMac = cds_get_context(QDF_MODULE_ID_PE); + + if (!pMac) { + WMA_LOGD("%s: NULL pMac ptr. Exiting", __func__); + return -EINVAL; + } + + if (!pMac->sme.pLinkLayerStatsIndCallback) { + WMA_LOGD("%s: HDD callback is null", __func__); + return -EINVAL; + } + + param_tlvs = (WMI_RADIO_LINK_STATS_EVENTID_param_tlvs *) cmd_param_info; + if (!param_tlvs) { + WMA_LOGA("%s: Invalid stats event", __func__); + return -EINVAL; + } + + /* + * cmd_param_info contains + * wmi_radio_link_stats_event_fixed_param fixed_param; + * size of(struct wmi_radio_link_stats); + * num_channels * size of(struct wmi_channel_stats) + */ + fixed_param = param_tlvs->fixed_param; + radio_stats = param_tlvs->radio_stats; + channel_stats = param_tlvs->channel_stats; + + if (!fixed_param || !radio_stats || + (radio_stats->num_channels && !channel_stats)) { + WMA_LOGA("%s: Invalid param_tlvs for Radio Stats", __func__); + return -EINVAL; + } + + radio_stats_size = sizeof(tSirWifiRadioStat); + chan_stats_size = sizeof(tSirWifiChannelStats); + link_stats_results_size = sizeof(*link_stats_results) + + fixed_param->num_radio * radio_stats_size; + + if (!wma_handle->link_stats_results) { + wma_handle->link_stats_results = qdf_mem_malloc(link_stats_results_size); + if (NULL == wma_handle->link_stats_results) { + WMA_LOGD("%s: could not allocate mem for stats results-len %zu", + __func__, link_stats_results_size); + return -ENOMEM; + } + } + link_stats_results = wma_handle->link_stats_results; + + WMA_LOGD("Radio stats Fixed Param:"); + WMA_LOGD("req_id: %u num_radio: %u more_radio_events: %u", + fixed_param->request_id, fixed_param->num_radio, + fixed_param->more_radio_events); + + WMA_LOGD("Radio Info: radio_id: %u on_time: %u tx_time: %u rx_time: %u on_time_scan: %u " + "on_time_nbd: %u on_time_gscan: %u on_time_roam_scan: %u " + "on_time_pno_scan: %u on_time_hs20: %u num_channels: %u", + radio_stats->radio_id, radio_stats->on_time, + radio_stats->tx_time, radio_stats->rx_time, + radio_stats->on_time_scan, radio_stats->on_time_nbd, + radio_stats->on_time_gscan, + radio_stats->on_time_roam_scan, + radio_stats->on_time_pno_scan, + radio_stats->on_time_hs20, radio_stats->num_channels); + + link_stats_results->paramId = WMI_LINK_STATS_RADIO; + link_stats_results->rspId = fixed_param->request_id; + link_stats_results->ifaceId = 0; + link_stats_results->num_radio = fixed_param->num_radio; + link_stats_results->peer_event_number = 0; + + /* + * Backward compatibility: + * There are firmware(s) which will send Radio stats only with + * more_radio_events set to 0 and firmware which sends Radio stats + * followed by tx_power level stats with more_radio_events set to 1. + * if more_radio_events is set to 1, buffer the radio stats and + * wait for tx_power_level stats. + */ + link_stats_results->moreResultToFollow = fixed_param->more_radio_events; + + results = (uint8_t *) link_stats_results->results; + t_radio_stats = (uint8_t *) radio_stats; + t_channel_stats = (uint8_t *) channel_stats; + + rs_results = (tSirWifiRadioStat *) &results[0] + radio_stats->radio_id; + rs_results->radio = radio_stats->radio_id; + rs_results->onTime = radio_stats->on_time; + rs_results->txTime = radio_stats->tx_time; + rs_results->rxTime = radio_stats->rx_time; + rs_results->onTimeScan = radio_stats->on_time_scan; + rs_results->onTimeNbd = radio_stats->on_time_nbd; + rs_results->onTimeGscan = radio_stats->on_time_gscan; + rs_results->onTimeRoamScan = radio_stats->on_time_roam_scan; + rs_results->onTimePnoScan = radio_stats->on_time_pno_scan; + rs_results->onTimeHs20 = radio_stats->on_time_hs20; + rs_results->total_num_tx_power_levels = 0; + rs_results->tx_time_per_power_level = NULL; + rs_results->numChannels = radio_stats->num_channels; + rs_results->channels = NULL; + + if (rs_results->numChannels) { + rs_results->channels = (tSirWifiChannelStats *) qdf_mem_malloc( + radio_stats->num_channels * + chan_stats_size); + if (rs_results->channels == NULL) { + WMA_LOGD("%s: could not allocate mem for channel stats (size=%zu)", + __func__, radio_stats->num_channels * chan_stats_size); + wma_unified_radio_tx_mem_free(handle); + return -ENOMEM; + } + + chn_results = (tSirWifiChannelStats *) &rs_results->channels[0]; + next_chan_offset = WMI_TLV_HDR_SIZE; + WMA_LOGD("Channel Stats Info"); + for (count = 0; count < radio_stats->num_channels; count++) { + WMA_LOGD("channel_width %u center_freq %u center_freq0 %u " + "center_freq1 %u radio_awake_time %u cca_busy_time %u", + channel_stats->channel_width, + channel_stats->center_freq, + channel_stats->center_freq0, + channel_stats->center_freq1, + channel_stats->radio_awake_time, + channel_stats->cca_busy_time); + channel_stats++; + + qdf_mem_copy(chn_results, + t_channel_stats + next_chan_offset, + chan_stats_size); + chn_results++; + next_chan_offset += sizeof(*channel_stats); + } + } + + if (link_stats_results->moreResultToFollow) { + /* More results coming, don't post yet */ + return 0; + } else { + link_stats_results->nr_received++; + } + + if (link_stats_results->num_radio != link_stats_results->nr_received) { + /* Not received all radio stats yet, don't post yet */ + return 0; + } + + pMac->sme.pLinkLayerStatsIndCallback(pMac->hHdd, + WMA_LINK_LAYER_STATS_RESULTS_RSP, + link_stats_results); + wma_unified_radio_tx_mem_free(handle); + + return 0; +} + +/** + * wma_register_ll_stats_event_handler() - register link layer stats related + * event handler + * @wma_handle: wma handle + * + * Return: none + */ +void wma_register_ll_stats_event_handler(tp_wma_handle wma_handle) +{ + if (NULL == wma_handle) { + WMA_LOGE("%s: wma_handle is NULL", __func__); + return; + } + + wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_IFACE_LINK_STATS_EVENTID, + wma_unified_link_iface_stats_event_handler, + WMA_RX_SERIALIZER_CTX); + wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_PEER_LINK_STATS_EVENTID, + wma_unified_link_peer_stats_event_handler, + WMA_RX_SERIALIZER_CTX); + wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_RADIO_LINK_STATS_EVENTID, + wma_unified_link_radio_stats_event_handler, + WMA_RX_SERIALIZER_CTX); + wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_RADIO_TX_POWER_LEVEL_STATS_EVENTID, + wma_unified_radio_tx_power_level_stats_event_handler, + WMA_RX_SERIALIZER_CTX); + + return; +} + + +/** + * wma_process_ll_stats_clear_req() - clear link layer stats + * @wma: wma handle + * @clearReq: ll stats clear request command params + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +QDF_STATUS wma_process_ll_stats_clear_req + (tp_wma_handle wma, const tpSirLLStatsClearReq clearReq) +{ + struct ll_stats_clear_params cmd = {0}; + int ret; + + if (!clearReq || !wma) { + WMA_LOGE("%s: input pointer is NULL", __func__); + return QDF_STATUS_E_FAILURE; + } + + cmd.stop_req = clearReq->stopReq; + cmd.sta_id = clearReq->staId; + cmd.stats_clear_mask = clearReq->statsClearReqMask; + + ret = wmi_unified_process_ll_stats_clear_cmd(wma->wmi_handle, &cmd, + wma->interfaces[clearReq->staId].addr); + if (ret) { + WMA_LOGE("%s: Failed to send clear link stats req", __func__); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * wma_process_ll_stats_set_req() - link layer stats set request + * @wma: wma handle + * @setReq: ll stats set request command params + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +QDF_STATUS wma_process_ll_stats_set_req + (tp_wma_handle wma, const tpSirLLStatsSetReq setReq) +{ + struct ll_stats_set_params cmd = {0}; + int ret; + + if (!setReq || !wma) { + WMA_LOGE("%s: input pointer is NULL", __func__); + return QDF_STATUS_E_FAILURE; + } + + cmd.mpdu_size_threshold = setReq->mpduSizeThreshold; + cmd.aggressive_statistics_gathering = + setReq->aggressiveStatisticsGathering; + + ret = wmi_unified_process_ll_stats_set_cmd(wma->wmi_handle, + &cmd); + if (ret) { + WMA_LOGE("%s: Failed to send set link stats request", __func__); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * wma_process_ll_stats_get_req() - link layer stats get request + * @wma:wma handle + * @getReq:ll stats get request command params + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +QDF_STATUS wma_process_ll_stats_get_req + (tp_wma_handle wma, const tpSirLLStatsGetReq getReq) +{ + struct ll_stats_get_params cmd = {0}; + int ret; + + if (!getReq || !wma) { + WMA_LOGE("%s: input pointer is NULL", __func__); + return QDF_STATUS_E_FAILURE; + } + + if (!wma->interfaces[getReq->staId].vdev_active) { + WMA_LOGE("%s: vdev not created yet", __func__); + return QDF_STATUS_E_FAILURE; + } + + cmd.req_id = getReq->reqId; + cmd.param_id_mask = getReq->paramIdMask; + cmd.sta_id = getReq->staId; + + ret = wmi_unified_process_ll_stats_get_cmd(wma->wmi_handle, &cmd, + wma->interfaces[getReq->staId].addr); + if (ret) { + WMA_LOGE("%s: Failed to send get link stats request", __func__); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * wma_unified_link_iface_stats_event_handler() - link iface stats event handler + * @wma:wma handle + * @cmd_param_info: data from event + * @len: length + * + * Return: 0 for success or error code + */ +int wma_unified_link_iface_stats_event_handler(void *handle, + uint8_t *cmd_param_info, + uint32_t len) +{ + WMI_IFACE_LINK_STATS_EVENTID_param_tlvs *param_tlvs; + wmi_iface_link_stats_event_fixed_param *fixed_param; + wmi_iface_link_stats *link_stats; + wmi_wmm_ac_stats *ac_stats; + tSirLLStatsResults *link_stats_results; + uint8_t *results, *t_link_stats, *t_ac_stats; + uint32_t next_res_offset, next_ac_offset, count; + uint32_t roaming_offset, roaming_size; + size_t link_stats_size, ac_stats_size, iface_info_size; + size_t link_stats_results_size; + + tpAniSirGlobal pMac = cds_get_context(QDF_MODULE_ID_PE); + + if (!pMac) { + WMA_LOGD("%s: NULL pMac ptr. Exiting", __func__); + return -EINVAL; + } + + if (!pMac->sme.pLinkLayerStatsIndCallback) { + WMA_LOGD("%s: HDD callback is null", __func__); + return -EINVAL; + } + + param_tlvs = (WMI_IFACE_LINK_STATS_EVENTID_param_tlvs *) cmd_param_info; + if (!param_tlvs) { + WMA_LOGA("%s: Invalid stats event", __func__); + return -EINVAL; + } + + /* + * cmd_param_info contains + * wmi_iface_link_stats_event_fixed_param fixed_param; + * wmi_iface_link_stats iface_link_stats; + * iface_link_stats->num_ac * size of(struct wmi_wmm_ac_stats) + */ + fixed_param = param_tlvs->fixed_param; + link_stats = param_tlvs->iface_link_stats; + ac_stats = param_tlvs->ac; + + if (!fixed_param || !link_stats || (link_stats->num_ac && !ac_stats)) { + WMA_LOGA("%s: Invalid param_tlvs for Iface Stats", __func__); + return -EINVAL; + } + + link_stats_size = sizeof(tSirWifiIfaceStat); + iface_info_size = sizeof(tSirWifiInterfaceInfo); + ac_stats_size = sizeof(tSirWifiWmmAcStat); + link_stats_results_size = sizeof(*link_stats_results) + link_stats_size; + + link_stats_results = qdf_mem_malloc(link_stats_results_size); + if (!link_stats_results) { + WMA_LOGD("%s: could not allocate mem for stats results-len %zu", + __func__, link_stats_results_size); + return -ENOMEM; + } + + qdf_mem_zero(link_stats_results, link_stats_results_size); + + link_stats_results->paramId = WMI_LINK_STATS_IFACE; + link_stats_results->rspId = fixed_param->request_id; + link_stats_results->ifaceId = fixed_param->vdev_id; + link_stats_results->num_peers = link_stats->num_peers; + link_stats_results->peer_event_number = 0; + link_stats_results->moreResultToFollow = 0; + + results = (uint8_t *) link_stats_results->results; + t_link_stats = (uint8_t *) link_stats; + t_ac_stats = (uint8_t *) ac_stats; + + /* Copy roaming state */ + roaming_offset = offsetof(tSirWifiInterfaceInfo, roaming); + roaming_size = member_size(tSirWifiInterfaceInfo, roaming); + + qdf_mem_copy(results + roaming_offset, &link_stats->roam_state, + roaming_size); + + qdf_mem_copy(results + iface_info_size, + t_link_stats + WMI_TLV_HDR_SIZE, + link_stats_size - iface_info_size - + WIFI_AC_MAX * ac_stats_size); + + next_res_offset = link_stats_size - WIFI_AC_MAX * ac_stats_size; + next_ac_offset = WMI_TLV_HDR_SIZE; + + for (count = 0; count < link_stats->num_ac; count++) { + ac_stats++; + + qdf_mem_copy(results + next_res_offset, + t_ac_stats + next_ac_offset, ac_stats_size); + next_res_offset += ac_stats_size; + next_ac_offset += sizeof(*ac_stats); + } + + /* call hdd callback with Link Layer Statistics + * vdev_id/ifacId in link_stats_results will be + * used to retrieve the correct HDD context + */ + pMac->sme.pLinkLayerStatsIndCallback(pMac->hHdd, + WMA_LINK_LAYER_STATS_RESULTS_RSP, + link_stats_results); + qdf_mem_free(link_stats_results); + + return 0; +} + +#endif /* WLAN_FEATURE_LINK_LAYER_STATS */ + +/** + * wma_update_pdev_stats() - update pdev stats + * @wma: wma handle + * @pdev_stats: pdev stats + * + * Return: none + */ +static void wma_update_pdev_stats(tp_wma_handle wma, + wmi_pdev_stats *pdev_stats) +{ + tAniGetPEStatsRsp *stats_rsp_params; + uint32_t temp_mask; + uint8_t *stats_buf; + tCsrGlobalClassAStatsInfo *classa_stats = NULL; + struct wma_txrx_node *node; + uint8_t i; + + for (i = 0; i < wma->max_bssid; i++) { + node = &wma->interfaces[i]; + stats_rsp_params = node->stats_rsp; + if (stats_rsp_params) { + node->fw_stats_set |= FW_PDEV_STATS_SET; + WMA_LOGD("<---FW PDEV STATS received for vdevId:%d", i); + stats_buf = (uint8_t *) (stats_rsp_params + 1); + temp_mask = stats_rsp_params->statsMask; + if (temp_mask & (1 << eCsrSummaryStats)) + stats_buf += sizeof(tCsrSummaryStatsInfo); + + if (temp_mask & (1 << eCsrGlobalClassAStats)) { + classa_stats = + (tCsrGlobalClassAStatsInfo *) stats_buf; + classa_stats->max_pwr = pdev_stats->chan_tx_pwr; + } + } + } +} + +/** + * wma_vdev_stats_lost_link_helper() - helper function to extract + * lost link information from vdev statistics event while deleting BSS. + * @wma: WMA handle + * @vdev_stats: statistics information from firmware + * + * This is for informing HDD to collect lost link information while + * disconnection. Following conditions to check + * 1. vdev is up + * 2. bssid is zero. When handling DELETE_BSS request message, it sets bssid to + * zero, hence add the check here to indicate the event comes during deleting + * BSS + * 3. DELETE_BSS is the request message queued. Put this condition check on the + * last one as it consumes more resource searching entries in the list + * + * Return: none + */ +static void wma_vdev_stats_lost_link_helper(tp_wma_handle wma, + wmi_vdev_stats *vdev_stats) +{ + struct wma_txrx_node *node; + int32_t rssi; + struct wma_target_req *req_msg; + static const uint8_t zero_mac[QDF_MAC_ADDR_SIZE] = {0}; + int32_t bcn_snr, dat_snr; + + node = &wma->interfaces[vdev_stats->vdev_id]; + if (node->vdev_up && + !qdf_mem_cmp(node->bssid, zero_mac, QDF_MAC_ADDR_SIZE)) { + req_msg = wma_peek_vdev_req(wma, vdev_stats->vdev_id, + WMA_TARGET_REQ_TYPE_VDEV_STOP); + if ((NULL == req_msg) || + (WMA_DELETE_BSS_REQ != req_msg->msg_type)) { + WMA_LOGD(FL("cannot find DELETE_BSS request message")); + return; + } + bcn_snr = vdev_stats->vdev_snr.bcn_snr; + dat_snr = vdev_stats->vdev_snr.dat_snr; + WMA_LOGD(FL("get vdev id %d, beancon snr %d, data snr %d"), + vdev_stats->vdev_id, bcn_snr, dat_snr); + + if (WMA_TGT_IS_VALID_SNR(bcn_snr)) + rssi = bcn_snr; + else if (WMA_TGT_IS_VALID_SNR(dat_snr)) + rssi = dat_snr; + else + rssi = WMA_TGT_INVALID_SNR; + + /* Get the absolute rssi value from the current rssi value */ + rssi = rssi + WMA_TGT_NOISE_FLOOR_DBM; + wma_lost_link_info_handler(wma, vdev_stats->vdev_id, rssi); + } +} + +/** + * wma_update_vdev_stats() - update vdev stats + * @wma: wma handle + * @vdev_stats: vdev stats + * + * Return: none + */ +static void wma_update_vdev_stats(tp_wma_handle wma, + wmi_vdev_stats *vdev_stats) +{ + tAniGetPEStatsRsp *stats_rsp_params; + tCsrSummaryStatsInfo *summary_stats = NULL; + uint8_t *stats_buf; + struct wma_txrx_node *node; + uint8_t i; + int32_t rssi = 0; + QDF_STATUS qdf_status; + tAniGetRssiReq *pGetRssiReq = (tAniGetRssiReq *) wma->pGetRssiReq; + cds_msg_t sme_msg = { 0 }; + int32_t bcn_snr, dat_snr; + + bcn_snr = vdev_stats->vdev_snr.bcn_snr; + dat_snr = vdev_stats->vdev_snr.dat_snr; + WMA_LOGD("vdev id %d beancon snr %d data snr %d", + vdev_stats->vdev_id, bcn_snr, dat_snr); + + node = &wma->interfaces[vdev_stats->vdev_id]; + stats_rsp_params = node->stats_rsp; + if (stats_rsp_params) { + stats_buf = (uint8_t *) (stats_rsp_params + 1); + node->fw_stats_set |= FW_VDEV_STATS_SET; + WMA_LOGD("<---FW VDEV STATS received for vdevId:%d", + vdev_stats->vdev_id); + if (stats_rsp_params->statsMask & (1 << eCsrSummaryStats)) { + summary_stats = (tCsrSummaryStatsInfo *) stats_buf; + for (i = 0; i < 4; i++) { + summary_stats->tx_frm_cnt[i] = + vdev_stats->tx_frm_cnt[i]; + summary_stats->fail_cnt[i] = + vdev_stats->fail_cnt[i]; + summary_stats->multiple_retry_cnt[i] = + vdev_stats->multiple_retry_cnt[i]; + } + + summary_stats->rx_frm_cnt = vdev_stats->rx_frm_cnt; + summary_stats->rx_error_cnt = vdev_stats->rx_err_cnt; + summary_stats->rx_discard_cnt = + vdev_stats->rx_discard_cnt; + summary_stats->ack_fail_cnt = vdev_stats->ack_fail_cnt; + summary_stats->rts_succ_cnt = vdev_stats->rts_succ_cnt; + summary_stats->rts_fail_cnt = vdev_stats->rts_fail_cnt; + /* Update SNR and RSSI in SummaryStats */ + if (WMA_TGT_IS_VALID_SNR(bcn_snr)) { + summary_stats->snr = bcn_snr; + summary_stats->rssi = + bcn_snr + WMA_TGT_NOISE_FLOOR_DBM; + } else if (WMA_TGT_IS_VALID_SNR(dat_snr)) { + summary_stats->snr = dat_snr; + summary_stats->rssi = + dat_snr + WMA_TGT_NOISE_FLOOR_DBM; + } else { + summary_stats->snr = WMA_TGT_INVALID_SNR; + summary_stats->rssi = 0; + } + } + } + + if (pGetRssiReq && pGetRssiReq->sessionId == vdev_stats->vdev_id) { + if (WMA_TGT_IS_VALID_SNR(bcn_snr)) { + rssi = bcn_snr; + rssi = rssi + WMA_TGT_NOISE_FLOOR_DBM; + } else if (WMA_TGT_IS_VALID_SNR(dat_snr)) { + rssi = dat_snr; + rssi = rssi + WMA_TGT_NOISE_FLOOR_DBM; + } else { + /* + * Firmware sends invalid snr till it sees + * Beacon/Data after connection since after + * vdev up fw resets the snr to invalid. + * In this duartion Host will return the last know + * rssi during connection. + */ + WMA_LOGE("Invalid SNR from firmware"); + } + + WMA_LOGD("Average Rssi = %d, vdev id= %d", rssi, + pGetRssiReq->sessionId); + + /* update the average rssi value to UMAC layer */ + if (NULL != pGetRssiReq->rssiCallback) { + ((tCsrRssiCallback) (pGetRssiReq->rssiCallback))(rssi, + pGetRssiReq->staId, + pGetRssiReq->pDevContext); + } + + qdf_mem_free(pGetRssiReq); + wma->pGetRssiReq = NULL; + } + + if (node->psnr_req) { + tAniGetSnrReq *p_snr_req = node->psnr_req; + + if (WMA_TGT_IS_VALID_SNR(bcn_snr)) + p_snr_req->snr = bcn_snr; + else if (WMA_TGT_IS_VALID_SNR(dat_snr)) + p_snr_req->snr = dat_snr; + else + p_snr_req->snr = WMA_TGT_INVALID_SNR; + + sme_msg.type = eWNI_SME_SNR_IND; + sme_msg.bodyptr = p_snr_req; + sme_msg.bodyval = 0; + + qdf_status = cds_mq_post_message(QDF_MODULE_ID_SME, &sme_msg); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + WMA_LOGE("%s: Fail to post snr ind msg", __func__); + qdf_mem_free(p_snr_req); + } + + node->psnr_req = NULL; + } + wma_vdev_stats_lost_link_helper(wma, vdev_stats); +} + +/** + * wma_post_stats() - update stats to PE + * @wma: wma handle + * @node: txrx node + * + * Return: none + */ +static void wma_post_stats(tp_wma_handle wma, struct wma_txrx_node *node) +{ + /* send response to UMAC */ + wma_send_msg(wma, WMA_GET_STATISTICS_RSP, node->stats_rsp, 0); + node->stats_rsp = NULL; + node->fw_stats_set = 0; +} + +/** + * wma_update_peer_stats() - update peer stats + * @wma: wma handle + * @peer_stats: peer stats + * + * Return: none + */ +static void wma_update_peer_stats(tp_wma_handle wma, + wmi_peer_stats *peer_stats) +{ + tAniGetPEStatsRsp *stats_rsp_params; + tCsrGlobalClassAStatsInfo *classa_stats = NULL; + struct wma_txrx_node *node; + uint8_t *stats_buf, vdev_id, macaddr[IEEE80211_ADDR_LEN], mcsRateFlags; + uint32_t temp_mask; + + WMI_MAC_ADDR_TO_CHAR_ARRAY(&peer_stats->peer_macaddr, &macaddr[0]); + if (!wma_find_vdev_by_bssid(wma, macaddr, &vdev_id)) + return; + + node = &wma->interfaces[vdev_id]; + stats_rsp_params = (tAniGetPEStatsRsp *) node->stats_rsp; + if (stats_rsp_params) { + node->fw_stats_set |= FW_PEER_STATS_SET; + WMA_LOGD("<-- FW PEER STATS received for vdevId:%d", vdev_id); + stats_buf = (uint8_t *) (stats_rsp_params + 1); + temp_mask = stats_rsp_params->statsMask; + if (temp_mask & (1 << eCsrSummaryStats)) + stats_buf += sizeof(tCsrSummaryStatsInfo); + + if (temp_mask & (1 << eCsrGlobalClassAStats)) { + classa_stats = (tCsrGlobalClassAStatsInfo *) stats_buf; + WMA_LOGD("peer tx rate:%d", peer_stats->peer_tx_rate); + /*The linkspeed returned by fw is in kbps so convert + *it in to units of 500kbps which is expected by UMAC*/ + if (peer_stats->peer_tx_rate) { + classa_stats->tx_rate = + peer_stats->peer_tx_rate / 500; + } + + classa_stats->tx_rate_flags = node->rate_flags; + if (!(node->rate_flags & eHAL_TX_RATE_LEGACY)) { + classa_stats->mcs_index = + wma_get_mcs_idx((peer_stats->peer_tx_rate / + 100), node->rate_flags, + node->nss, &mcsRateFlags); + /* rx_frag_cnt and promiscuous_rx_frag_cnt + * parameter is currently not used. lets use the + * same parameter to hold the nss value and mcs + * rate flags */ + classa_stats->rx_frag_cnt = node->nss; + classa_stats->promiscuous_rx_frag_cnt = + mcsRateFlags; + } + /* FW returns tx power in intervals of 0.5 dBm + Convert it back to intervals of 1 dBm */ + classa_stats->max_pwr = + roundup(classa_stats->max_pwr, 2) >> 1; + } + } +} + +/** + * wma_post_link_status() - post link status to SME + * @pGetLinkStatus: SME Link status + * @link_status: Link status + * + * Return: none + */ +void wma_post_link_status(tAniGetLinkStatus *pGetLinkStatus, + uint8_t link_status) +{ + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + cds_msg_t sme_msg = { 0 }; + + pGetLinkStatus->linkStatus = link_status; + sme_msg.type = eWNI_SME_LINK_STATUS_IND; + sme_msg.bodyptr = pGetLinkStatus; + sme_msg.bodyval = 0; + + qdf_status = cds_mq_post_message(QDF_MODULE_ID_SME, &sme_msg); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + WMA_LOGE("%s: Fail to post link status ind msg", __func__); + qdf_mem_free(pGetLinkStatus); + } +} + +/** + * wma_update_per_chain_rssi_stats() - to store per chain rssi stats + * @wma: wma handle + * @rssi_stats: rssi stats + * @rssi_per_chain_stats: buffer where rssi stats to be stored + * + * This function stores per chain rssi stats received from fw for all vdevs for + * which the stats were requested into a csr stats structure. + * + * Return: void + */ +static void wma_update_per_chain_rssi_stats(tp_wma_handle wma, + wmi_rssi_stats *rssi_stats, + struct csr_per_chain_rssi_stats_info *rssi_per_chain_stats) +{ + int i; + int32_t bcn_snr, dat_snr; + + for (i = 0; i < NUM_CHAINS_MAX; i++) { + bcn_snr = rssi_stats->rssi_avg_beacon[i]; + dat_snr = rssi_stats->rssi_avg_data[i]; + WMA_LOGD("chain %d beacon snr %d data snr %d", + i, bcn_snr, dat_snr); + + if (WMA_TGT_IS_VALID_SNR(bcn_snr)) + rssi_per_chain_stats->rssi[i] = bcn_snr; + else if (WMA_TGT_IS_VALID_SNR(dat_snr)) + rssi_per_chain_stats->rssi[i] = dat_snr; + else + /* + * Firmware sends invalid snr till it sees + * Beacon/Data after connection since after + * vdev up fw resets the snr to invalid. + * In this duartion Host will return an invalid rssi + * value. + */ + rssi_per_chain_stats->rssi[i] = WMA_TGT_INVALID_SNR; + + /* + * Get the absolute rssi value from the current rssi value the + * sinr value is hardcoded into 0 in the qcacld-new/CORE stack + */ + rssi_per_chain_stats->rssi[i] += WMA_TGT_NOISE_FLOOR_DBM; + WMI_MAC_ADDR_TO_CHAR_ARRAY(&(rssi_stats->peer_macaddr), + rssi_per_chain_stats->peer_mac_addr); + } +} + +/** + * wma_update_rssi_stats() - to update rssi stats for all vdevs + * for which the stats were requested. + * @wma: wma handle + * @rssi_stats: rssi stats + * + * This function updates the rssi stats for all vdevs for which + * the stats were requested. + * + * Return: void + */ +static void wma_update_rssi_stats(tp_wma_handle wma, + wmi_rssi_stats *rssi_stats) +{ + tAniGetPEStatsRsp *stats_rsp_params; + struct csr_per_chain_rssi_stats_info *rssi_per_chain_stats = NULL; + struct wma_txrx_node *node; + uint8_t *stats_buf; + uint32_t temp_mask; + uint8_t vdev_id; + + vdev_id = rssi_stats->vdev_id; + node = &wma->interfaces[vdev_id]; + stats_rsp_params = (tAniGetPEStatsRsp *) node->stats_rsp; + if (stats_rsp_params) { + node->fw_stats_set |= FW_RSSI_PER_CHAIN_STATS_SET; + WMA_LOGD("<-- FW RSSI PER CHAIN STATS received for vdevId:%d", + vdev_id); + stats_buf = (uint8_t *) (stats_rsp_params + 1); + temp_mask = stats_rsp_params->statsMask; + + if (temp_mask & (1 << eCsrSummaryStats)) + stats_buf += sizeof(tCsrSummaryStatsInfo); + if (temp_mask & (1 << eCsrGlobalClassAStats)) + stats_buf += sizeof(tCsrGlobalClassAStatsInfo); + if (temp_mask & (1 << eCsrGlobalClassBStats)) + stats_buf += sizeof(tCsrGlobalClassBStatsInfo); + if (temp_mask & (1 << eCsrGlobalClassCStats)) + stats_buf += sizeof(tCsrGlobalClassCStatsInfo); + if (temp_mask & (1 << eCsrGlobalClassDStats)) + stats_buf += sizeof(tCsrGlobalClassDStatsInfo); + if (temp_mask & (1 << eCsrPerStaStats)) + stats_buf += sizeof(tCsrPerStaStatsInfo); + + if (temp_mask & (1 << csr_per_chain_rssi_stats)) { + rssi_per_chain_stats = + (struct csr_per_chain_rssi_stats_info *)stats_buf; + wma_update_per_chain_rssi_stats(wma, rssi_stats, + rssi_per_chain_stats); + } + } +} + + +/** + * wma_link_status_event_handler() - link status event handler + * @handle: wma handle + * @cmd_param_info: data from event + * @len: length + * + * Return: 0 for success or error code + */ +int wma_link_status_event_handler(void *handle, uint8_t *cmd_param_info, + uint32_t len) +{ + tp_wma_handle wma = (tp_wma_handle) handle; + WMI_UPDATE_VDEV_RATE_STATS_EVENTID_param_tlvs *param_buf; + wmi_vdev_rate_stats_event_fixed_param *event; + wmi_vdev_rate_ht_info *ht_info; + struct wma_txrx_node *intr = wma->interfaces; + uint8_t link_status = LINK_STATUS_LEGACY; + int i; + + param_buf = + (WMI_UPDATE_VDEV_RATE_STATS_EVENTID_param_tlvs *) cmd_param_info; + if (!param_buf) { + WMA_LOGA("%s: Invalid stats event", __func__); + return -EINVAL; + } + + event = (wmi_vdev_rate_stats_event_fixed_param *) param_buf->fixed_param; + ht_info = (wmi_vdev_rate_ht_info *) param_buf->ht_info; + + WMA_LOGD("num_vdev_stats: %d", event->num_vdev_stats); + for (i = 0; (i < event->num_vdev_stats) && ht_info; i++) { + WMA_LOGD("%s vdevId:%d tx_nss:%d rx_nss:%d tx_preamble:%d rx_preamble:%d", + __func__, ht_info->vdevid, ht_info->tx_nss, + ht_info->rx_nss, ht_info->tx_preamble, + ht_info->rx_preamble); + if (ht_info->vdevid < wma->max_bssid + && intr[ht_info->vdevid].plink_status_req) { + if (ht_info->tx_nss || ht_info->rx_nss) + link_status = LINK_STATUS_MIMO; + + if ((ht_info->tx_preamble == LINK_RATE_VHT) || + (ht_info->rx_preamble == LINK_RATE_VHT)) + link_status |= LINK_STATUS_VHT; + + if (intr[ht_info->vdevid].nss == 2) + link_status |= LINK_SUPPORT_MIMO; + + if (intr[ht_info->vdevid].rate_flags & + (eHAL_TX_RATE_VHT20 | eHAL_TX_RATE_VHT40 | + eHAL_TX_RATE_VHT80)) + link_status |= LINK_SUPPORT_VHT; + + wma_post_link_status(intr[ht_info->vdevid].plink_status_req, + link_status); + intr[ht_info->vdevid].plink_status_req = NULL; + link_status = LINK_STATUS_LEGACY; + } + + ht_info++; + } + + return 0; +} + +int wma_rso_cmd_status_event_handler(wmi_roam_event_fixed_param *wmi_event) +{ + struct rso_cmd_status *rso_status; + cds_msg_t sme_msg; + QDF_STATUS qdf_status; + + rso_status = qdf_mem_malloc(sizeof(*rso_status)); + if (!rso_status) { + WMA_LOGE("%s: malloc fails for rso cmd status", __func__); + return -ENOMEM; + } + + rso_status->vdev_id = wmi_event->vdev_id; + if (WMI_ROAM_NOTIF_SCAN_MODE_SUCCESS == wmi_event->notif) + rso_status->status = true; + else if (WMI_ROAM_NOTIF_SCAN_MODE_FAIL == wmi_event->notif) + rso_status->status = false; + sme_msg.type = eWNI_SME_RSO_CMD_STATUS_IND; + sme_msg.bodyptr = rso_status; + sme_msg.bodyval = 0; + WMA_LOGI("%s: Post RSO cmd status to SME", __func__); + + qdf_status = cds_mq_post_message(QDF_MODULE_ID_SME, &sme_msg); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + WMA_LOGE("%s: fail to post RSO cmd status to SME", __func__); + qdf_mem_free(rso_status); + } + return 0; +} + +/** + * wma_stats_event_handler() - stats event handler + * @handle: wma handle + * @cmd_param_info: data from event + * @len: length + * + * Return: 0 for success or error code + */ +int wma_stats_event_handler(void *handle, uint8_t *cmd_param_info, + uint32_t len) +{ + tp_wma_handle wma = (tp_wma_handle) handle; + WMI_UPDATE_STATS_EVENTID_param_tlvs *param_buf; + wmi_stats_event_fixed_param *event; + wmi_pdev_stats *pdev_stats; + wmi_vdev_stats *vdev_stats; + wmi_peer_stats *peer_stats; + wmi_rssi_stats *rssi_stats; + wmi_per_chain_rssi_stats *rssi_event; + struct wma_txrx_node *node; + uint8_t i, *temp; + wmi_congestion_stats *congestion_stats; + tpAniSirGlobal mac; + + param_buf = (WMI_UPDATE_STATS_EVENTID_param_tlvs *) cmd_param_info; + if (!param_buf) { + WMA_LOGA("%s: Invalid stats event", __func__); + return -EINVAL; + } + event = param_buf->fixed_param; + temp = (uint8_t *) param_buf->data; + + if (event->num_pdev_stats > 0) { + for (i = 0; i < event->num_pdev_stats; i++) { + pdev_stats = (wmi_pdev_stats *) temp; + wma_update_pdev_stats(wma, pdev_stats); + temp += sizeof(wmi_pdev_stats); + } + } + + if (event->num_vdev_stats > 0) { + for (i = 0; i < event->num_vdev_stats; i++) { + vdev_stats = (wmi_vdev_stats *) temp; + wma_update_vdev_stats(wma, vdev_stats); + temp += sizeof(wmi_vdev_stats); + } + } + + if (event->num_peer_stats > 0) { + for (i = 0; i < event->num_peer_stats; i++) { + peer_stats = (wmi_peer_stats *) temp; + wma_update_peer_stats(wma, peer_stats); + temp += sizeof(wmi_peer_stats); + } + } + + rssi_event = (wmi_per_chain_rssi_stats *) param_buf->chain_stats; + if (rssi_event) { + if (((rssi_event->tlv_header & 0xFFFF0000) >> 16 == + WMITLV_TAG_STRUC_wmi_per_chain_rssi_stats) && + ((rssi_event->tlv_header & 0x0000FFFF) == + WMITLV_GET_STRUCT_TLVLEN(wmi_per_chain_rssi_stats))) { + if (rssi_event->num_per_chain_rssi_stats > 0) { + temp = (uint8_t *) rssi_event; + temp += sizeof(*rssi_event); + + /* skip past struct array tlv header */ + temp += WMI_TLV_HDR_SIZE; + + for (i = 0; + i < rssi_event->num_per_chain_rssi_stats; + i++) { + rssi_stats = (wmi_rssi_stats *)temp; + wma_update_rssi_stats(wma, rssi_stats); + temp += sizeof(wmi_rssi_stats); + } + } + } + } + + congestion_stats = (wmi_congestion_stats *) param_buf->congestion_stats; + if (congestion_stats) { + if (((congestion_stats->tlv_header & 0xFFFF0000) >> 16 == + WMITLV_TAG_STRUC_wmi_congestion_stats) && + ((congestion_stats->tlv_header & 0x0000FFFF) == + WMITLV_GET_STRUCT_TLVLEN(wmi_congestion_stats))) { + mac = cds_get_context(QDF_MODULE_ID_PE); + if (!mac) { + WMA_LOGE("%s: Invalid mac", __func__); + return -EINVAL; + } + if (!mac->sme.congestion_cb) { + WMA_LOGE("%s: Callback not registered", + __func__); + return -EINVAL; + } + WMA_LOGI("%s: congestion %d", __func__, + congestion_stats->congestion); + mac->sme.congestion_cb(mac->hHdd, + congestion_stats->congestion, + congestion_stats->vdev_id); + } + } + + for (i = 0; i < wma->max_bssid; i++) { + node = &wma->interfaces[i]; + if (node->fw_stats_set & FW_PEER_STATS_SET) { + wma_post_stats(wma, node); + } + } + + WMA_LOGI("%s: Exit", __func__); + return 0; +} + +/** + * wma_send_link_speed() - send link speed to SME + * @link_speed: link speed + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +QDF_STATUS wma_send_link_speed(uint32_t link_speed) +{ + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + tpAniSirGlobal mac_ctx; + tSirLinkSpeedInfo *ls_ind = + (tSirLinkSpeedInfo *) qdf_mem_malloc(sizeof(tSirLinkSpeedInfo)); + + mac_ctx = cds_get_context(QDF_MODULE_ID_PE); + if (!mac_ctx) { + WMA_LOGD("%s: NULL mac_ctx ptr. Exiting", __func__); + return QDF_STATUS_E_INVAL; + } + + if (!ls_ind) { + WMA_LOGE("%s: Memory allocation failed.", __func__); + qdf_status = QDF_STATUS_E_NOMEM; + } else { + ls_ind->estLinkSpeed = link_speed; + if (mac_ctx->sme.pLinkSpeedIndCb) + mac_ctx->sme.pLinkSpeedIndCb(ls_ind, + mac_ctx->sme.pLinkSpeedCbContext); + else + WMA_LOGD("%s: pLinkSpeedIndCb is null", __func__); + qdf_mem_free(ls_ind); + } + + return qdf_status; +} + +/** + * wma_link_speed_event_handler() - link speed event handler + * @handle: wma handle + * @cmd_param_info: event data + * @len: length + * + * Return: 0 for success or error code + */ +int wma_link_speed_event_handler(void *handle, uint8_t *cmd_param_info, + uint32_t len) +{ + WMI_PEER_ESTIMATED_LINKSPEED_EVENTID_param_tlvs *param_buf; + wmi_peer_estimated_linkspeed_event_fixed_param *event; + QDF_STATUS qdf_status; + + param_buf = + (WMI_PEER_ESTIMATED_LINKSPEED_EVENTID_param_tlvs *) cmd_param_info; + if (!param_buf) { + WMA_LOGE("%s: Invalid linkspeed event", __func__); + return -EINVAL; + } + event = param_buf->fixed_param; + qdf_status = wma_send_link_speed(event->est_linkspeed_kbps); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + return -EINVAL; + } + return 0; +} + +/** + * wma_wni_cfg_dnld() - cfg download request + * @handle: wma handle + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +QDF_STATUS wma_wni_cfg_dnld(tp_wma_handle wma_handle) +{ + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + void *mac = cds_get_context(QDF_MODULE_ID_PE); + + WMA_LOGD("%s: Enter", __func__); + + if (NULL == mac) { + WMA_LOGP("%s: Invalid context", __func__); + QDF_ASSERT(0); + return QDF_STATUS_E_FAILURE; + } + + process_cfg_download_req(mac); + + WMA_LOGD("%s: Exit", __func__); + return qdf_status; +} + +/** + * wma_unified_debug_print_event_handler() - debug print event handler + * @handle: wma handle + * @datap: data pointer + * @len: length + * + * Return: 0 for success or error code + */ +int wma_unified_debug_print_event_handler(void *handle, uint8_t *datap, + uint32_t len) +{ + WMI_DEBUG_PRINT_EVENTID_param_tlvs *param_buf; + uint8_t *data; + uint32_t datalen; + + param_buf = (WMI_DEBUG_PRINT_EVENTID_param_tlvs *) datap; + if (!param_buf) { + WMA_LOGE("Get NULL point message from FW"); + return -ENOMEM; + } + data = param_buf->data; + datalen = param_buf->num_data; + +#ifdef BIG_ENDIAN_HOST + { + char dbgbuf[500] = { 0 }; + memcpy(dbgbuf, data, datalen); + SWAPME(dbgbuf, datalen); + WMA_LOGD("FIRMWARE:%s", dbgbuf); + return 0; + } +#else + WMA_LOGD("FIRMWARE:%s", data); + return 0; +#endif /* BIG_ENDIAN_HOST */ +} + +/** + * wma_is_sap_active() - check sap is active or not + * @handle: wma handle + * + * Return: true/false + */ +bool wma_is_sap_active(tp_wma_handle wma_handle) +{ + int i; + + for (i = 0; i < wma_handle->max_bssid; i++) { + if (!wma_handle->interfaces[i].vdev_up) + continue; + if (wma_handle->interfaces[i].type == WMI_VDEV_TYPE_AP && + wma_handle->interfaces[i].sub_type == 0) + return true; + } + return false; +} + +/** + * wma_is_p2p_go_active() - check p2p go is active or not + * @handle: wma handle + * + * Return: true/false + */ +bool wma_is_p2p_go_active(tp_wma_handle wma_handle) +{ + int i; + + for (i = 0; i < wma_handle->max_bssid; i++) { + if (!wma_handle->interfaces[i].vdev_up) + continue; + if (wma_handle->interfaces[i].type == WMI_VDEV_TYPE_AP && + wma_handle->interfaces[i].sub_type == + WMI_UNIFIED_VDEV_SUBTYPE_P2P_GO) + return true; + } + return false; +} + +/** + * wma_is_p2p_cli_active() - check p2p cli is active or not + * @handle: wma handle + * + * Return: true/false + */ +bool wma_is_p2p_cli_active(tp_wma_handle wma_handle) +{ + int i; + + for (i = 0; i < wma_handle->max_bssid; i++) { + if (!wma_handle->interfaces[i].vdev_up) + continue; + if (wma_handle->interfaces[i].type == WMI_VDEV_TYPE_STA && + wma_handle->interfaces[i].sub_type == + WMI_UNIFIED_VDEV_SUBTYPE_P2P_CLIENT) + return true; + } + return false; +} + +/** + * wma_is_sta_active() - check sta is active or not + * @handle: wma handle + * + * Return: true/false + */ +bool wma_is_sta_active(tp_wma_handle wma_handle) +{ + int i; + + for (i = 0; i < wma_handle->max_bssid; i++) { + if (!wma_handle->interfaces[i].vdev_up) + continue; + if (wma_handle->interfaces[i].type == WMI_VDEV_TYPE_STA && + wma_handle->interfaces[i].sub_type == 0) + return true; + if (wma_handle->interfaces[i].type == WMI_VDEV_TYPE_IBSS) + return true; + } + return false; +} + +/** + * wma_peer_phymode() - get phymode + * @nw_type: nw type + * @sta_type: sta type + * @is_ht: is ht supported + * @is_cw40: is channel width 40 supported + * @is_vht: is vht supported + * @is_cw_vht: is channel width 80 supported + * + * Return: WLAN_PHY_MODE + */ +WLAN_PHY_MODE wma_peer_phymode(tSirNwType nw_type, uint8_t sta_type, + uint8_t is_ht, uint8_t ch_width, + uint8_t is_vht) +{ + WLAN_PHY_MODE phymode = MODE_UNKNOWN; + + switch (nw_type) { + case eSIR_11B_NW_TYPE: + phymode = MODE_11B; + if (is_ht || is_vht) + WMA_LOGE("HT/VHT is enabled with 11B NW type"); + break; + case eSIR_11G_NW_TYPE: + if (!(is_ht || is_vht)) { + phymode = MODE_11G; + break; + } + if (CH_WIDTH_40MHZ < ch_width) + WMA_LOGE("80/160 MHz BW sent in 11G, configured 40MHz"); + if (ch_width) + phymode = (is_vht) ? + MODE_11AC_VHT40_2G : MODE_11NG_HT40; + else + phymode = (is_vht) ? + MODE_11AC_VHT20_2G : MODE_11NG_HT20; + break; + case eSIR_11A_NW_TYPE: + if (!(is_ht || is_vht)) { + phymode = MODE_11A; + break; + } + if (is_vht) { + if (ch_width == CH_WIDTH_160MHZ) + phymode = MODE_11AC_VHT160; + else if (ch_width == CH_WIDTH_80P80MHZ) + phymode = MODE_11AC_VHT80_80; + else if (ch_width == CH_WIDTH_80MHZ) + phymode = MODE_11AC_VHT80; + else + phymode = (ch_width) ? + MODE_11AC_VHT40 : MODE_11AC_VHT20; + } else + phymode = (ch_width) ? MODE_11NA_HT40 : MODE_11NA_HT20; + break; + default: + WMA_LOGP("%s: Invalid nw type %d", __func__, nw_type); + break; + } + WMA_LOGD("%s: nw_type %d is_ht %d ch_width %d is_vht %d phymode %d", + __func__, nw_type, is_ht, ch_width, is_vht, phymode); + + return phymode; +} + +/** + * wma_txrx_fw_stats_reset() - reset txrx fw statistics + * @wma_handle: wma handle + * @vdev_id: vdev id + * @value: value + * + * Return: 0 for success or return error + */ +int32_t wma_txrx_fw_stats_reset(tp_wma_handle wma_handle, + uint8_t vdev_id, uint32_t value) +{ + struct ol_txrx_stats_req req; + ol_txrx_vdev_handle vdev; + + vdev = wma_find_vdev_by_id(wma_handle, vdev_id); + if (!vdev) { + WMA_LOGE("%s:Invalid vdev handle", __func__); + return -EINVAL; + } + qdf_mem_zero(&req, sizeof(req)); + req.stats_type_reset_mask = value; + ol_txrx_fw_stats_get(vdev, &req, false, false); + + return 0; +} + +#ifdef HELIUMPLUS +#define SET_UPLOAD_MASK(_mask, _rate_info) \ + ((_mask) = 1 << (_rate_info ## _V2)) +#else /* !HELIUMPLUS */ +#define SET_UPLOAD_MASK(_mask, _rate_info) \ + ((_mask) = 1 << (_rate_info)) +#endif + +#ifdef HELIUMPLUS +static bool wma_is_valid_fw_stats_cmd(uint32_t value) +{ + if (value > (HTT_DBG_NUM_STATS + 1) || + value == (HTT_DBG_STATS_RX_RATE_INFO + 1) || + value == (HTT_DBG_STATS_TX_RATE_INFO + 1) || + value == (HTT_DBG_STATS_TXBF_MUSU_NDPA_PKT + 1)) { + WMA_LOGE("%s: Not supported", __func__); + return false; + } + return true; +} +#else +static bool wma_is_valid_fw_stats_cmd(uint32_t value) +{ + if (value > (HTT_DBG_NUM_STATS + 1) || + value == (HTT_DBG_STATS_RX_RATE_INFO_V2 + 1) || + value == (HTT_DBG_STATS_TX_RATE_INFO_V2 + 1) || + value == (HTT_DBG_STATS_TXBF_MUSU_NDPA_PKT + 1)) { + WMA_LOGE("%s: Not supported", __func__); + return false; + } + return true; +} +#endif + +/** + * wma_set_txrx_fw_stats_level() - set txrx fw stats level + * @wma_handle: wma handle + * @vdev_id: vdev id + * @value: value + * + * Return: 0 for success or return error + */ +int32_t wma_set_txrx_fw_stats_level(tp_wma_handle wma_handle, + uint8_t vdev_id, uint32_t value) +{ + struct ol_txrx_stats_req req; + ol_txrx_vdev_handle vdev; + uint32_t l_up_mask; + + vdev = wma_find_vdev_by_id(wma_handle, vdev_id); + if (!vdev) { + WMA_LOGE("%s:Invalid vdev handle", __func__); + return -EINVAL; + } + + if (wma_is_valid_fw_stats_cmd(value) == false) + return -EINVAL; + + qdf_mem_zero(&req, sizeof(req)); + req.print.verbose = 1; + + /* TODO: Need to check how to avoid mem leak*/ + l_up_mask = 1 << (value - 1); + req.stats_type_upload_mask = l_up_mask; + + ol_txrx_fw_stats_get(vdev, &req, false, true); + + return 0; +} + +/** + * wma_get_stats_rsp_buf() - fill get stats response buffer + * @get_stats_param: get stats parameters + * + * Return: stats response buffer + */ +static tAniGetPEStatsRsp *wma_get_stats_rsp_buf + (tAniGetPEStatsReq *get_stats_param) +{ + tAniGetPEStatsRsp *stats_rsp_params; + uint32_t len, temp_mask, counter = 0; + + len = sizeof(tAniGetPEStatsRsp); + temp_mask = get_stats_param->statsMask; + + while (temp_mask) { + if (temp_mask & 1) { + switch (counter) { + case eCsrSummaryStats: + len += sizeof(tCsrSummaryStatsInfo); + break; + case eCsrGlobalClassAStats: + len += sizeof(tCsrGlobalClassAStatsInfo); + break; + case eCsrGlobalClassBStats: + len += sizeof(tCsrGlobalClassBStatsInfo); + break; + case eCsrGlobalClassCStats: + len += sizeof(tCsrGlobalClassCStatsInfo); + break; + case eCsrGlobalClassDStats: + len += sizeof(tCsrGlobalClassDStatsInfo); + break; + case eCsrPerStaStats: + len += sizeof(tCsrPerStaStatsInfo); + break; + case csr_per_chain_rssi_stats: + len += + sizeof(struct csr_per_chain_rssi_stats_info); + break; + } + } + + counter++; + temp_mask >>= 1; + } + + stats_rsp_params = (tAniGetPEStatsRsp *) qdf_mem_malloc(len); + if (!stats_rsp_params) { + WMA_LOGE("memory allocation failed for tAniGetPEStatsRsp"); + QDF_ASSERT(0); + return NULL; + } + + qdf_mem_zero(stats_rsp_params, len); + stats_rsp_params->staId = get_stats_param->staId; + stats_rsp_params->statsMask = get_stats_param->statsMask; + stats_rsp_params->msgType = WMA_GET_STATISTICS_RSP; + stats_rsp_params->msgLen = len - sizeof(tAniGetPEStatsRsp); + stats_rsp_params->rc = QDF_STATUS_SUCCESS; + return stats_rsp_params; +} + +/** + * wma_get_stats_req() - get stats request + * @handle: wma handle + * @get_stats_param: stats params + * + * Return: none + */ +void wma_get_stats_req(WMA_HANDLE handle, + tAniGetPEStatsReq *get_stats_param) +{ + tp_wma_handle wma_handle = (tp_wma_handle) handle; + struct wma_txrx_node *node; + struct pe_stats_req cmd = {0}; + tAniGetPEStatsRsp *pGetPEStatsRspParams; + + + WMA_LOGD("%s: Enter", __func__); + node = &wma_handle->interfaces[get_stats_param->sessionId]; + if (node->stats_rsp) { + pGetPEStatsRspParams = node->stats_rsp; + if (pGetPEStatsRspParams->staId == get_stats_param->staId && + pGetPEStatsRspParams->statsMask == + get_stats_param->statsMask) { + WMA_LOGI("Stats for staId %d with stats mask %d " + "is pending.... ignore new request", + get_stats_param->staId, + get_stats_param->statsMask); + goto end; + } else { + qdf_mem_free(node->stats_rsp); + node->stats_rsp = NULL; + node->fw_stats_set = 0; + } + } + + pGetPEStatsRspParams = wma_get_stats_rsp_buf(get_stats_param); + if (!pGetPEStatsRspParams) + goto end; + + node->fw_stats_set = 0; + if (node->stats_rsp) { + WMA_LOGD(FL("stats_rsp is not null, prev_value: %p"), + node->stats_rsp); + qdf_mem_free(node->stats_rsp); + node->stats_rsp = NULL; + } + node->stats_rsp = pGetPEStatsRspParams; + WMA_LOGD("stats_rsp allocated: %p, sta_id: %d, mask: %d, vdev_id: %d", + node->stats_rsp, node->stats_rsp->staId, + node->stats_rsp->statsMask, get_stats_param->sessionId); + + cmd.session_id = get_stats_param->sessionId; + if (wmi_unified_get_stats_cmd(wma_handle->wmi_handle, &cmd, + node->bssid)) { + + WMA_LOGE("%s: Failed to send WMI_REQUEST_STATS_CMDID", + __func__); + goto failed; + } + + goto end; +failed: + + pGetPEStatsRspParams->rc = QDF_STATUS_E_FAILURE; + /* send response to UMAC */ + wma_send_msg(wma_handle, WMA_GET_STATISTICS_RSP, pGetPEStatsRspParams, + 0); + node->stats_rsp = NULL; +end: + qdf_mem_free(get_stats_param); + WMA_LOGD("%s: Exit", __func__); + return; +} + +/** + * wma_get_cca_stats() - send request to fw to get CCA + * @wma_handle: wma handle + * @vdev_id: vdev id + * + * Return: QDF status + */ +QDF_STATUS wma_get_cca_stats(tp_wma_handle wma_handle, + uint8_t vdev_id) +{ + if (wmi_unified_congestion_request_cmd(wma_handle->wmi_handle, + vdev_id)) { + WMA_LOGE("Failed to congestion request to fw"); + return QDF_STATUS_E_FAILURE; + } + return QDF_STATUS_SUCCESS; +} + +/** + * wma_get_beacon_buffer_by_vdev_id() - get the beacon buffer from vdev ID + * @vdev_id: vdev id + * @buffer_size: size of buffer + * + * Return: none + */ +void *wma_get_beacon_buffer_by_vdev_id(uint8_t vdev_id, uint32_t *buffer_size) +{ + tp_wma_handle wma; + struct beacon_info *beacon; + uint8_t *buf; + uint32_t buf_size; + + wma = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma) { + WMA_LOGE("%s: Invalid WMA handle", __func__); + return NULL; + } + + if (vdev_id >= wma->max_bssid) { + WMA_LOGE("%s: Invalid vdev_id %u", __func__, vdev_id); + return NULL; + } + + if (!wma_is_vdev_in_ap_mode(wma, vdev_id)) { + WMA_LOGE("%s: vdevid %d is not in AP mode", __func__, vdev_id); + return NULL; + } + + beacon = wma->interfaces[vdev_id].beacon; + + if (!beacon) { + WMA_LOGE("%s: beacon invalid", __func__); + return NULL; + } + + qdf_spin_lock_bh(&beacon->lock); + + buf_size = qdf_nbuf_len(beacon->buf); + buf = qdf_mem_malloc(buf_size); + + if (!buf) { + qdf_spin_unlock_bh(&beacon->lock); + WMA_LOGE("%s: alloc failed for beacon buf", __func__); + return NULL; + } + + qdf_mem_copy(buf, qdf_nbuf_data(beacon->buf), buf_size); + + qdf_spin_unlock_bh(&beacon->lock); + + if (buffer_size) + *buffer_size = buf_size; + + return buf; +} + +/** + * wma_get_vdev_address_by_vdev_id() - lookup MAC address from vdev ID + * @vdev_id: vdev id + * + * Return: mac address + */ +uint8_t *wma_get_vdev_address_by_vdev_id(uint8_t vdev_id) +{ + tp_wma_handle wma; + + wma = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma) { + WMA_LOGE("%s: Invalid WMA handle", __func__); + return NULL; + } + + if (vdev_id >= wma->max_bssid) { + WMA_LOGE("%s: Invalid vdev_id %u", __func__, vdev_id); + return NULL; + } + + return wma->interfaces[vdev_id].addr; +} + +/** + * wma_get_interface_by_vdev_id() - lookup interface entry using vdev ID + * @vdev_id: vdev id + * + * Return: entry from vdev table + */ +struct wma_txrx_node *wma_get_interface_by_vdev_id(uint8_t vdev_id) +{ + tp_wma_handle wma; + + wma = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma) { + WMA_LOGE("%s: Invalid WMA handle", __func__); + return NULL; + } + + if (vdev_id >= wma->max_bssid) { + WMA_LOGE("%s: Invalid vdev_id %u", __func__, vdev_id); + return NULL; + } + + return &wma->interfaces[vdev_id]; +} + +/** + * wma_is_vdev_up() - return whether a vdev is up + * @vdev_id: vdev id + * + * Return: true if the vdev is up, false otherwise + */ +bool wma_is_vdev_up(uint8_t vdev_id) +{ + struct wma_txrx_node *vdev = wma_get_interface_by_vdev_id(vdev_id); + if (vdev) + return vdev->vdev_up; + else + return false; +} + +#if defined(QCA_WIFI_FTM) +/** + * wma_utf_rsp() - utf response + * @wma_handle: wma handle + * @payload: payload + * @len: length of payload + * + * Return: 0 for success or error code + */ +static int wma_utf_rsp(tp_wma_handle wma_handle, uint8_t **payload, + uint32_t *len) +{ + int ret = -1; + uint32_t payload_len; + + payload_len = wma_handle->utf_event_info.length; + if (payload_len) { + ret = 0; + + /* + * The first 4 bytes holds the payload size + * and the actual payload sits next to it + */ + *payload = (uint8_t *) qdf_mem_malloc((uint32_t) payload_len + + sizeof(A_UINT32)); + *(A_UINT32 *) &(*payload[0]) = + wma_handle->utf_event_info.length; + memcpy(*payload + sizeof(A_UINT32), + wma_handle->utf_event_info.data, payload_len); + wma_handle->utf_event_info.length = 0; + *len = payload_len; + } + + return ret; +} + +/** + * wma_post_ftm_response() - post ftm response to upper layer + * @wma_handle: wma handle + * + * Return: none + */ +static void wma_post_ftm_response(tp_wma_handle wma_handle) +{ + int ret; + uint8_t *payload; + uint32_t data_len; + cds_msg_t msg = { 0 }; + QDF_STATUS status; + + ret = wma_utf_rsp(wma_handle, &payload, &data_len); + + if (ret) { + return; + } + + sys_build_message_header(SYS_MSG_ID_FTM_RSP, &msg); + msg.bodyptr = payload; + msg.bodyval = 0; + + status = cds_mq_post_message(CDS_MQ_ID_SYS, &msg); + + if (status != QDF_STATUS_SUCCESS) { + WMA_LOGE("failed to post ftm response to SYS"); + qdf_mem_free(payload); + } +} + +/** + * wma_process_utf_event() - process utf event + * @handle: wma handle + * @datap: data buffer + * @dataplen: data length + * + * Return: 0 for success or error code + */ +static int +wma_process_utf_event(WMA_HANDLE handle, uint8_t *datap, uint32_t dataplen) +{ + tp_wma_handle wma_handle = (tp_wma_handle) handle; + struct seg_hdr_info segHdrInfo; + uint8_t totalNumOfSegments, currentSeq; + WMI_PDEV_UTF_EVENTID_param_tlvs *param_buf; + uint8_t *data; + uint32_t datalen; + + param_buf = (WMI_PDEV_UTF_EVENTID_param_tlvs *) datap; + if (!param_buf) { + WMA_LOGE("Get NULL point message from FW"); + return -EINVAL; + } + data = param_buf->data; + datalen = param_buf->num_data; + + segHdrInfo = *(struct seg_hdr_info *) &(data[0]); + + wma_handle->utf_event_info.currentSeq = (segHdrInfo.segmentInfo & 0xF); + + currentSeq = (segHdrInfo.segmentInfo & 0xF); + totalNumOfSegments = (segHdrInfo.segmentInfo >> 4) & 0xF; + + datalen = datalen - sizeof(segHdrInfo); + + if (currentSeq == 0) { + wma_handle->utf_event_info.expectedSeq = 0; + wma_handle->utf_event_info.offset = 0; + } else { + if (wma_handle->utf_event_info.expectedSeq != currentSeq) + WMA_LOGE("Mismatch in expecting seq expected" + " Seq %d got seq %d", + wma_handle->utf_event_info.expectedSeq, + currentSeq); + } + + memcpy(&wma_handle->utf_event_info. + data[wma_handle->utf_event_info.offset], + &data[sizeof(segHdrInfo)], datalen); + wma_handle->utf_event_info.offset = + wma_handle->utf_event_info.offset + datalen; + wma_handle->utf_event_info.expectedSeq++; + + if (wma_handle->utf_event_info.expectedSeq == totalNumOfSegments) { + if (wma_handle->utf_event_info.offset != segHdrInfo.len) + WMA_LOGE("All segs received total len mismatch.." + " len %zu total len %d", + wma_handle->utf_event_info.offset, + segHdrInfo.len); + + wma_handle->utf_event_info.length = + wma_handle->utf_event_info.offset; + } + + wma_post_ftm_response(wma_handle); + + return 0; +} + +/** + * wma_utf_detach() - utf detach + * @wma_handle: wma handle + * + * Return: none + */ +void wma_utf_detach(tp_wma_handle wma_handle) +{ + if (wma_handle->utf_event_info.data) { + qdf_mem_free(wma_handle->utf_event_info.data); + wma_handle->utf_event_info.data = NULL; + wma_handle->utf_event_info.length = 0; + wmi_unified_unregister_event_handler(wma_handle->wmi_handle, + WMI_PDEV_UTF_EVENTID); + } +} + +/** + * wma_utf_attach() - utf attach + * @wma_handle: wma handle + * + * Return: none + */ +void wma_utf_attach(tp_wma_handle wma_handle) +{ + int ret; + + wma_handle->utf_event_info.data = (unsigned char *) + qdf_mem_malloc(MAX_UTF_EVENT_LENGTH); + wma_handle->utf_event_info.length = 0; + + ret = wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_PDEV_UTF_EVENTID, + wma_process_utf_event, + WMA_RX_SERIALIZER_CTX); + + if (ret) + WMA_LOGP("%s: Failed to register UTF event callback", __func__); +} + +/** + * wma_utf_cmd() - utf command + * @wma_handle: wma handle + * @data: data + * @len: length + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +static QDF_STATUS wma_utf_cmd(tp_wma_handle wma_handle, uint8_t *data, + uint16_t len) +{ + struct pdev_utf_params param = {0}; + + wma_handle->utf_event_info.length = 0; + param.utf_payload = data; + param.len = len; + + return wmi_unified_pdev_utf_cmd_send(wma_handle->wmi_handle, ¶m, + WMA_WILDCARD_PDEV_ID); +} + +/** + * wma_process_ftm_command() - process ftm command + * @wma_handle: wma handle + * @msg_buffer: message buffer + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +QDF_STATUS +wma_process_ftm_command(tp_wma_handle wma_handle, + struct ar6k_testmode_cmd_data *msg_buffer) +{ + uint8_t *data = NULL; + uint16_t len = 0; + int ret; + + if (!msg_buffer) + return QDF_STATUS_E_INVAL; + + if (cds_get_conparam() != QDF_GLOBAL_FTM_MODE) { + WMA_LOGE("FTM command issued in non-FTM mode"); + qdf_mem_free(msg_buffer->data); + qdf_mem_free(msg_buffer); + return QDF_STATUS_E_NOSUPPORT; + } + + data = msg_buffer->data; + len = msg_buffer->len; + + ret = wma_utf_cmd(wma_handle, data, len); + + qdf_mem_free(msg_buffer->data); + qdf_mem_free(msg_buffer); + + if (ret) + return QDF_STATUS_E_FAILURE; + + return QDF_STATUS_SUCCESS; +} +#endif /* QCA_WIFI_FTM */ + +/** + * wma_get_wcnss_software_version() - get wcnss software version + * @p_cds_gctx: cds context + * @pVersion: version pointer + * @versionBufferSize: buffer size + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +QDF_STATUS wma_get_wcnss_software_version(void *p_cds_gctx, + uint8_t *pVersion, + uint32_t versionBufferSize) +{ + tp_wma_handle wma_handle; + wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + + if (NULL == wma_handle) { + WMA_LOGE("%s: Failed to get wma", __func__); + return QDF_STATUS_E_FAULT; + } + + snprintf(pVersion, versionBufferSize, "%x", + (unsigned int)wma_handle->target_fw_version); + return QDF_STATUS_SUCCESS; +} + +/** + * wma_get_tx_rx_ss_from_config() - Get Tx/Rx spatial stream from HW mode config + * @mac_ss: Config which indicates the HW mode as per 'hw_mode_ss_config' + * @tx_ss: Contains the Tx spatial stream + * @rx_ss: Contains the Rx spatial stream + * + * Returns the number of spatial streams of Tx and Rx + * + * Return: None + */ +static void wma_get_tx_rx_ss_from_config(enum hw_mode_ss_config mac_ss, + uint32_t *tx_ss, uint32_t *rx_ss) +{ + switch (mac_ss) { + case HW_MODE_SS_0x0: + *tx_ss = 0; + *rx_ss = 0; + break; + case HW_MODE_SS_1x1: + *tx_ss = 1; + *rx_ss = 1; + break; + case HW_MODE_SS_2x2: + *tx_ss = 2; + *rx_ss = 2; + break; + case HW_MODE_SS_3x3: + *tx_ss = 3; + *rx_ss = 3; + break; + case HW_MODE_SS_4x4: + *tx_ss = 4; + *rx_ss = 4; + break; + default: + *tx_ss = 0; + *rx_ss = 0; + } +} + +/** + * wma_get_matching_hw_mode_index() - Get matching HW mode index + * @wma: WMA handle + * @mac0_tx_ss: Number of tx spatial streams of MAC0 + * @mac0_rx_ss: Number of rx spatial streams of MAC0 + * @mac0_bw: Bandwidth of MAC0 of type 'hw_mode_bandwidth' + * @mac1_tx_ss: Number of tx spatial streams of MAC1 + * @mac1_rx_ss: Number of rx spatial streams of MAC1 + * @mac1_bw: Bandwidth of MAC1 of type 'hw_mode_bandwidth' + * @dbs: DBS capability of type 'hw_mode_dbs_capab' + * @dfs: Agile DFS capability of type 'hw_mode_agile_dfs_capab' + * @sbs: SBS capability of type 'hw_mode_sbs_capab' + * + * Fetches the HW mode index corresponding to the HW mode provided + * + * Return: Positive hw mode index in case a match is found or a negative + * value, otherwise + */ +static int8_t wma_get_matching_hw_mode_index(tp_wma_handle wma, + uint32_t mac0_tx_ss, uint32_t mac0_rx_ss, + enum hw_mode_bandwidth mac0_bw, + uint32_t mac1_tx_ss, uint32_t mac1_rx_ss, + enum hw_mode_bandwidth mac1_bw, + enum hw_mode_dbs_capab dbs, + enum hw_mode_agile_dfs_capab dfs, + enum hw_mode_sbs_capab sbs) +{ + uint32_t i; + uint32_t t_mac0_tx_ss, t_mac0_rx_ss, t_mac0_bw; + uint32_t t_mac1_tx_ss, t_mac1_rx_ss, t_mac1_bw; + uint32_t dbs_mode, agile_dfs_mode, sbs_mode; + int8_t found = -EINVAL; + + if (!wma) { + WMA_LOGE("%s: Invalid WMA handle", __func__); + return found; + } + + for (i = 0; i < wma->num_dbs_hw_modes; i++) { + t_mac0_tx_ss = WMA_HW_MODE_MAC0_TX_STREAMS_GET( + wma->hw_mode.hw_mode_list[i]); + if (t_mac0_tx_ss != mac0_tx_ss) + continue; + + t_mac0_rx_ss = WMA_HW_MODE_MAC0_RX_STREAMS_GET( + wma->hw_mode.hw_mode_list[i]); + if (t_mac0_rx_ss != mac0_rx_ss) + continue; + + t_mac0_bw = WMA_HW_MODE_MAC0_BANDWIDTH_GET( + wma->hw_mode.hw_mode_list[i]); + /* + * Firmware advertises max bw capability as CBW 80+80 + * for single MAC. Thus CBW 20/40/80 should also be + * supported, if CBW 80+80 is supported. + */ + if (t_mac0_bw < mac0_bw) + continue; + + t_mac1_tx_ss = WMA_HW_MODE_MAC1_TX_STREAMS_GET( + wma->hw_mode.hw_mode_list[i]); + if (t_mac1_tx_ss != mac1_tx_ss) + continue; + + t_mac1_rx_ss = WMA_HW_MODE_MAC1_RX_STREAMS_GET( + wma->hw_mode.hw_mode_list[i]); + if (t_mac1_rx_ss != mac1_rx_ss) + continue; + + t_mac1_bw = WMA_HW_MODE_MAC1_BANDWIDTH_GET( + wma->hw_mode.hw_mode_list[i]); + if (t_mac1_bw < mac1_bw) + continue; + + dbs_mode = WMA_HW_MODE_DBS_MODE_GET( + wma->hw_mode.hw_mode_list[i]); + if (dbs_mode != dbs) + continue; + + agile_dfs_mode = WMA_HW_MODE_AGILE_DFS_GET( + wma->hw_mode.hw_mode_list[i]); + if (agile_dfs_mode != dfs) + continue; + + sbs_mode = WMA_HW_MODE_SBS_MODE_GET( + wma->hw_mode.hw_mode_list[i]); + if (sbs_mode != sbs) + continue; + + found = i; + WMA_LOGI("%s: hw_mode index %d found", + __func__, i); + break; + } + return found; +} + +/** + * wma_get_hw_mode_from_dbs_hw_list() - Get hw_mode index + * @mac0_ss: MAC0 spatial stream configuration + * @mac0_bw: MAC0 bandwidth configuration + * @mac1_ss: MAC1 spatial stream configuration + * @mac1_bw: MAC1 bandwidth configuration + * @dbs: HW DBS capability + * @dfs: HW Agile DFS capability + * @sbs: HW SBS capability + * + * Get the HW mode index corresponding to the HW modes spatial stream, + * bandwidth, DBS, Agile DFS and SBS capability + * + * Return: Index number if a match is found or -negative value if not found + */ +int8_t wma_get_hw_mode_idx_from_dbs_hw_list(enum hw_mode_ss_config mac0_ss, + enum hw_mode_bandwidth mac0_bw, + enum hw_mode_ss_config mac1_ss, + enum hw_mode_bandwidth mac1_bw, + enum hw_mode_dbs_capab dbs, + enum hw_mode_agile_dfs_capab dfs, + enum hw_mode_sbs_capab sbs) +{ + tp_wma_handle wma; + uint32_t mac0_tx_ss, mac0_rx_ss; + uint32_t mac1_tx_ss, mac1_rx_ss; + + wma = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma) { + WMA_LOGE("%s: Invalid WMA handle", __func__); + return -EINVAL; + } + + wma_get_tx_rx_ss_from_config(mac0_ss, &mac0_tx_ss, &mac0_rx_ss); + wma_get_tx_rx_ss_from_config(mac1_ss, &mac1_tx_ss, &mac1_rx_ss); + + WMA_LOGI("%s: MAC0: TxSS=%d, RxSS=%d, BW=%d", + __func__, mac0_tx_ss, mac0_rx_ss, mac0_bw); + WMA_LOGI("%s: MAC1: TxSS=%d, RxSS=%d, BW=%d", + __func__, mac1_tx_ss, mac1_rx_ss, mac1_bw); + WMA_LOGI("%s: DBS=%d, Agile DFS=%d, SBS=%d", + __func__, dbs, dfs, sbs); + + return wma_get_matching_hw_mode_index(wma, mac0_tx_ss, mac0_rx_ss, + mac0_bw, + mac1_tx_ss, mac1_rx_ss, + mac1_bw, + dbs, dfs, sbs); +} + +/** + * wma_get_hw_mode_from_idx() - Get HW mode based on index + * @idx: HW mode index + * @hw_mode: HW mode params + * + * Fetches the HW mode parameters + * + * Return: Success if hw mode is obtained and the hw mode params + */ +QDF_STATUS wma_get_hw_mode_from_idx(uint32_t idx, + struct sir_hw_mode_params *hw_mode) +{ + tp_wma_handle wma; + uint32_t param; + + wma = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma) { + WMA_LOGE("%s: Invalid WMA handle", __func__); + return QDF_STATUS_E_FAILURE; + } + + if (idx > wma->num_dbs_hw_modes) { + WMA_LOGE("%s: Invalid index", __func__); + return QDF_STATUS_E_FAILURE; + } + + if (!wma->num_dbs_hw_modes) { + WMA_LOGE("%s: No dbs hw modes available", __func__); + return QDF_STATUS_E_FAILURE; + } + + param = wma->hw_mode.hw_mode_list[idx]; + + hw_mode->mac0_tx_ss = WMA_HW_MODE_MAC0_TX_STREAMS_GET(param); + hw_mode->mac0_rx_ss = WMA_HW_MODE_MAC0_RX_STREAMS_GET(param); + hw_mode->mac0_bw = WMA_HW_MODE_MAC0_BANDWIDTH_GET(param); + hw_mode->mac1_tx_ss = WMA_HW_MODE_MAC1_TX_STREAMS_GET(param); + hw_mode->mac1_rx_ss = WMA_HW_MODE_MAC1_RX_STREAMS_GET(param); + hw_mode->mac1_bw = WMA_HW_MODE_MAC1_BANDWIDTH_GET(param); + hw_mode->dbs_cap = WMA_HW_MODE_DBS_MODE_GET(param); + hw_mode->agile_dfs_cap = WMA_HW_MODE_AGILE_DFS_GET(param); + hw_mode->sbs_cap = WMA_HW_MODE_SBS_MODE_GET(param); + + return QDF_STATUS_SUCCESS; +} + +/** + * wma_get_num_dbs_hw_modes() - Get number of HW mode + * + * Fetches the number of DBS HW modes returned by the FW + * + * Return: Negative value on error or returns the number of DBS HW modes + */ +int8_t wma_get_num_dbs_hw_modes(void) +{ + tp_wma_handle wma; + + wma = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma) { + WMA_LOGE("%s: Invalid WMA handle", __func__); + return -EINVAL; + } + return wma->num_dbs_hw_modes; +} + +/** + * wma_is_hw_dbs_capable() - Check if HW is DBS capable + * + * Checks if the HW is DBS capable + * + * Return: true if the HW is DBS capable + */ +bool wma_is_hw_dbs_capable(void) +{ + tp_wma_handle wma; + uint32_t param, i, found = 0; + + wma = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma) { + WMA_LOGE("%s: Invalid WMA handle", __func__); + return false; + } + + if (!wma_is_dbs_enable()) { + WMA_LOGI("%s: DBS is disabled", __func__); + return false; + } + + WMA_LOGI("%s: DBS service bit map: %d", __func__, + WMI_SERVICE_IS_ENABLED(wma->wmi_service_bitmap, + WMI_SERVICE_DUAL_BAND_SIMULTANEOUS_SUPPORT)); + + /* The agreement with FW is that: To know if the target is DBS + * capable, DBS needs to be supported both in the HW mode list + * and in the service ready event + */ + if (!(WMI_SERVICE_IS_ENABLED(wma->wmi_service_bitmap, + WMI_SERVICE_DUAL_BAND_SIMULTANEOUS_SUPPORT))) + return false; + + for (i = 0; i < wma->num_dbs_hw_modes; i++) { + param = wma->hw_mode.hw_mode_list[i]; + WMA_LOGI("%s: HW param: %x", __func__, param); + if (WMA_HW_MODE_DBS_MODE_GET(param)) { + WMA_LOGI("%s: HW (%d) is DBS capable", __func__, i); + found = 1; + break; + } + } + + if (found) + return true; + + return false; +} + +/** + * wma_get_cds_hw_mode_change_from_hw_mode_index - Returns value in terms of + * cds_hw_mode_change enums derived from hw_mode_index. + * + * Returns cds_hw_mode_change value derived from hw_mode_index. + * + * Return: value in terms of cds_hw_mode_change enums. + */ +enum cds_hw_mode_change +wma_get_cds_hw_mode_change_from_hw_mode_index(uint32_t hw_mode_index) +{ + tp_wma_handle wma; + uint32_t param = 0; + enum cds_hw_mode_change value = CDS_HW_MODE_NOT_IN_PROGRESS; + + wma = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma) { + WMA_LOGE("%s: Invalid WMA handle", __func__); + goto ret_value; + } + + WMA_LOGI("%s: HW param: %x", __func__, param); + + param = wma->hw_mode.hw_mode_list[hw_mode_index]; + if (WMA_HW_MODE_DBS_MODE_GET(param)) { + WMA_LOGI("%s: DBS is requested with HW (%d)", __func__, + hw_mode_index); + value = CDS_DBS_IN_PROGRESS; + goto ret_value; + } + + if (WMA_HW_MODE_SBS_MODE_GET(param)) { + WMA_LOGI("%s: SBS is requested with HW (%d)", __func__, + hw_mode_index); + value = CDS_SBS_IN_PROGRESS; + goto ret_value; + } + + value = CDS_SMM_IN_PROGRESS; + WMA_LOGI("%s: SMM is requested with HW (%d)", __func__, + hw_mode_index); +ret_value: + return value; +} + +/** + * wma_get_mac_id_of_vdev() - Get MAC id corresponding to a vdev + * @vdev_id: VDEV whose MAC ID is required + * + * Get MAC id corresponding to a vdev id from the WMA structure + * + * Return: Negative value on failure and MAC id on success + */ +int8_t wma_get_mac_id_of_vdev(uint32_t vdev_id) +{ + tp_wma_handle wma; + + wma = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma) { + WMA_LOGE("%s: Invalid WMA handle", __func__); + return -EINVAL; + } + + if (wma->interfaces) + return wma->interfaces[vdev_id].mac_id; + + return -EINVAL; +} + +/** + * wma_get_old_and_new_hw_index() - Get the old and new HW index + * @old_hw_mode_index: Value at this pointer contains the old HW mode index + * Default value when not configured is WMA_DEFAULT_HW_MODE_INDEX + * @new_hw_mode_index: Value at this pointer contains the new HW mode index + * Default value when not configured is WMA_DEFAULT_HW_MODE_INDEX + * + * Get the old and new HW index configured in the driver + * + * Return: Failure in case the HW mode indices cannot be fetched and Success + * otherwise. When no HW mode transition has happened the values of + * old_hw_mode_index and new_hw_mode_index will be the same. + */ +QDF_STATUS wma_get_old_and_new_hw_index(uint32_t *old_hw_mode_index, + uint32_t *new_hw_mode_index) +{ + tp_wma_handle wma; + + wma = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma) { + WMA_LOGE("%s: Invalid WMA handle", __func__); + return QDF_STATUS_E_INVAL; + } + + *old_hw_mode_index = wma->old_hw_mode_index; + *new_hw_mode_index = wma->new_hw_mode_index; + + return QDF_STATUS_SUCCESS; +} + +/** + * wma_update_intf_hw_mode_params() - Update WMA params + * @vdev_id: VDEV id whose params needs to be updated + * @mac_id: MAC id to be updated + * @cfgd_hw_mode_index: HW mode index from which Tx and Rx SS will be updated + * + * Updates the MAC id, tx spatial stream, rx spatial stream in WMA + * + * Return: None + */ +void wma_update_intf_hw_mode_params(uint32_t vdev_id, uint32_t mac_id, + uint32_t cfgd_hw_mode_index) +{ + tp_wma_handle wma; + uint32_t param; + + wma = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma) { + WMA_LOGE("%s: Invalid WMA handle", __func__); + return; + } + + if (!wma->interfaces) { + WMA_LOGE("%s: Interface is NULL", __func__); + return; + } + + if (cfgd_hw_mode_index > wma->num_dbs_hw_modes) { + WMA_LOGE("%s: Invalid index", __func__); + return; + } + + param = wma->hw_mode.hw_mode_list[cfgd_hw_mode_index]; + wma->interfaces[vdev_id].mac_id = mac_id; + if (mac_id == 0) { + wma->interfaces[vdev_id].tx_streams = + WMA_HW_MODE_MAC0_TX_STREAMS_GET(param); + wma->interfaces[vdev_id].rx_streams = + WMA_HW_MODE_MAC0_RX_STREAMS_GET(param); + } else { + wma->interfaces[vdev_id].tx_streams = + WMA_HW_MODE_MAC1_TX_STREAMS_GET(param); + wma->interfaces[vdev_id].rx_streams = + WMA_HW_MODE_MAC1_RX_STREAMS_GET(param); + } +} + +/** + * wma_get_dbs_hw_modes() - Get the DBS HW modes for userspace + * @one_by_one_dbs: 1x1 DBS capability of HW + * @two_by_two_dbs: 2x2 DBS capability of HW + * + * Provides the DBS HW mode capability such as whether + * 1x1 DBS, 2x2 DBS is supported by the HW or not. + * + * Return: Failure in case of error and 0 on success + * one_by_one_dbs/two_by_two_dbs will be false, + * if they are not supported. + * one_by_one_dbs/two_by_two_dbs will be true, + * if they are supported. + * false values of one_by_one_dbs/two_by_two_dbs, + * indicate DBS is disabled + */ +QDF_STATUS wma_get_dbs_hw_modes(bool *one_by_one_dbs, bool *two_by_two_dbs) +{ + tp_wma_handle wma; + uint32_t i; + int8_t found_one_by_one = -EINVAL, found_two_by_two = -EINVAL; + uint32_t conf1_tx_ss, conf1_rx_ss; + uint32_t conf2_tx_ss, conf2_rx_ss; + + *one_by_one_dbs = false; + *two_by_two_dbs = false; + + if (wma_is_hw_dbs_capable() == false) { + WMA_LOGE("%s: HW is not DBS capable", __func__); + /* Caller will understand that DBS is disabled */ + return QDF_STATUS_SUCCESS; + + } + + wma = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma) { + WMA_LOGE("%s: Invalid WMA handle", __func__); + return QDF_STATUS_E_FAILURE; + } + + /* To check 1x1 capability */ + wma_get_tx_rx_ss_from_config(HW_MODE_SS_1x1, + &conf1_tx_ss, &conf1_rx_ss); + /* To check 2x2 capability */ + wma_get_tx_rx_ss_from_config(HW_MODE_SS_2x2, + &conf2_tx_ss, &conf2_rx_ss); + + for (i = 0; i < wma->num_dbs_hw_modes; i++) { + uint32_t t_conf0_tx_ss, t_conf0_rx_ss; + uint32_t t_conf1_tx_ss, t_conf1_rx_ss; + uint32_t dbs_mode; + + t_conf0_tx_ss = WMA_HW_MODE_MAC0_TX_STREAMS_GET( + wma->hw_mode.hw_mode_list[i]); + t_conf0_rx_ss = WMA_HW_MODE_MAC0_RX_STREAMS_GET( + wma->hw_mode.hw_mode_list[i]); + t_conf1_tx_ss = WMA_HW_MODE_MAC1_TX_STREAMS_GET( + wma->hw_mode.hw_mode_list[i]); + t_conf1_rx_ss = WMA_HW_MODE_MAC1_RX_STREAMS_GET( + wma->hw_mode.hw_mode_list[i]); + dbs_mode = WMA_HW_MODE_DBS_MODE_GET( + wma->hw_mode.hw_mode_list[i]); + + if (((((t_conf0_tx_ss == conf1_tx_ss) && + (t_conf0_rx_ss == conf1_rx_ss)) || + ((t_conf1_tx_ss == conf1_tx_ss) && + (t_conf1_rx_ss == conf1_rx_ss))) && + (dbs_mode == HW_MODE_DBS)) && + (found_one_by_one < 0)) { + found_one_by_one = i; + WMA_LOGI("%s: 1x1 hw_mode index %d found", + __func__, i); + /* Once an entry is found, need not check for 1x1 + * again + */ + continue; + } + + if (((((t_conf0_tx_ss == conf2_tx_ss) && + (t_conf0_rx_ss == conf2_rx_ss)) || + ((t_conf1_tx_ss == conf2_tx_ss) && + (t_conf1_rx_ss == conf2_rx_ss))) && + (dbs_mode == HW_MODE_DBS)) && + (found_two_by_two < 0)) { + found_two_by_two = i; + WMA_LOGI("%s: 2x2 hw_mode index %d found", + __func__, i); + /* Once an entry is found, need not check for 2x2 + * again + */ + continue; + } + } + + if (found_one_by_one >= 0) + *one_by_one_dbs = true; + if (found_two_by_two >= 0) + *two_by_two_dbs = true; + + return QDF_STATUS_SUCCESS; +} + +/** + * wma_get_current_hw_mode() - Get current HW mode params + * @hw_mode: HW mode parameters + * + * Provides the current HW mode parameters if the HW mode is initialized + * in the driver + * + * Return: Success if the current HW mode params are successfully populated + */ +QDF_STATUS wma_get_current_hw_mode(struct sir_hw_mode_params *hw_mode) +{ + QDF_STATUS status; + uint32_t old_hw_index = 0, new_hw_index = 0; + + WMA_LOGI("%s: Get the current hw mode", __func__); + + status = wma_get_old_and_new_hw_index(&old_hw_index, + &new_hw_index); + if (QDF_STATUS_SUCCESS != status) { + WMA_LOGE("%s: Failed to get HW mode index", __func__); + return QDF_STATUS_E_FAILURE; + } + + if (new_hw_index == WMA_DEFAULT_HW_MODE_INDEX) { + WMA_LOGE("%s: HW mode is not yet initialized", __func__); + return QDF_STATUS_E_FAILURE; + } + + status = wma_get_hw_mode_from_idx(new_hw_index, hw_mode); + if (QDF_STATUS_SUCCESS != status) { + WMA_LOGE("%s: Failed to get HW mode index", __func__); + return QDF_STATUS_E_FAILURE; + } + return QDF_STATUS_SUCCESS; +} + +/** + * wma_is_current_hwmode_dbs() - Check if current hw mode is DBS + * + * Checks if current hardware mode of the system is DBS or no + * + * Return: true or false + */ +bool wma_is_current_hwmode_dbs(void) +{ + struct sir_hw_mode_params hw_mode; + + if (!wma_is_hw_dbs_capable()) + return false; + if (QDF_STATUS_SUCCESS != wma_get_current_hw_mode(&hw_mode)) + return false; + if (hw_mode.dbs_cap) + return true; + return false; +} + +/** + * wma_is_dbs_enable() - Check if master DBS control is enabled + * + * Checks if the master DBS control is enabled. This will be used + * to override any other DBS capability + * + * Return: True if master DBS control is enabled + */ +bool wma_is_dbs_enable(void) +{ + tp_wma_handle wma; + + if (wma_is_dual_mac_disabled_in_ini()) + return false; + + wma = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma) { + WMA_LOGE("%s: Invalid WMA handle", __func__); + return false; + } + + WMA_LOGD("%s: DBS=%d", __func__, + WMI_DBS_FW_MODE_CFG_DBS_GET(wma->dual_mac_cfg.cur_fw_mode_config)); + + if (WMI_DBS_FW_MODE_CFG_DBS_GET(wma->dual_mac_cfg.cur_fw_mode_config)) + return true; + + return false; +} + +/** + * wma_get_updated_scan_config() - Get the updated scan configuration + * @scan_config: Pointer containing the updated scan config + * @dbs_scan: 0 or 1 indicating if DBS scan needs to be enabled/disabled + * @dbs_plus_agile_scan: 0 or 1 indicating if DBS plus agile scan needs to be + * enabled/disabled + * @single_mac_scan_with_dfs: 0 or 1 indicating if single MAC scan with DFS + * needs to be enabled/disabled + * + * Takes the current scan configuration and set the necessary scan config + * bits to either 0/1 and provides the updated value to the caller who + * can use this to pass it on to the FW + * + * Return: 0 on success + */ +QDF_STATUS wma_get_updated_scan_config(uint32_t *scan_config, + bool dbs_scan, + bool dbs_plus_agile_scan, + bool single_mac_scan_with_dfs) +{ + tp_wma_handle wma; + + wma = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma) { + WMA_LOGE("%s: Invalid WMA handle", __func__); + return QDF_STATUS_E_FAILURE; + } + *scan_config = wma->dual_mac_cfg.cur_scan_config; + + WMI_DBS_CONC_SCAN_CFG_DBS_SCAN_SET(*scan_config, dbs_scan); + WMI_DBS_CONC_SCAN_CFG_AGILE_SCAN_SET(*scan_config, + dbs_plus_agile_scan); + WMI_DBS_CONC_SCAN_CFG_AGILE_DFS_SCAN_SET(*scan_config, + single_mac_scan_with_dfs); + + WMA_LOGD("%s: *scan_config:%x ", __func__, *scan_config); + return QDF_STATUS_SUCCESS; +} + +/** + * wma_get_updated_fw_mode_config() - Get the updated fw mode configuration + * @fw_mode_config: Pointer containing the updated fw mode config + * @dbs: 0 or 1 indicating if DBS needs to be enabled/disabled + * @agile_dfs: 0 or 1 indicating if agile DFS needs to be enabled/disabled + * + * Takes the current fw mode configuration and set the necessary fw mode config + * bits to either 0/1 and provides the updated value to the caller who + * can use this to pass it on to the FW + * + * Return: 0 on success + */ +QDF_STATUS wma_get_updated_fw_mode_config(uint32_t *fw_mode_config, + bool dbs, + bool agile_dfs) +{ + tp_wma_handle wma; + + wma = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma) { + WMA_LOGE("%s: Invalid WMA handle", __func__); + return QDF_STATUS_E_FAILURE; + } + *fw_mode_config = wma->dual_mac_cfg.cur_fw_mode_config; + + WMI_DBS_FW_MODE_CFG_DBS_SET(*fw_mode_config, dbs); + WMI_DBS_FW_MODE_CFG_AGILE_DFS_SET(*fw_mode_config, agile_dfs); + + WMA_LOGD("%s: *fw_mode_config:%x ", __func__, *fw_mode_config); + return QDF_STATUS_SUCCESS; +} + +/** + * wma_get_dbs_config() - Get DBS bit + * + * Gets the DBS bit of fw_mode_config_bits + * + * Return: 0 or 1 to indicate the DBS bit + */ +bool wma_get_dbs_config(void) +{ + tp_wma_handle wma; + uint32_t fw_mode_config; + + if (wma_is_dual_mac_disabled_in_ini()) + return false; + + wma = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma) { + WMA_LOGE("%s: Invalid WMA handle", __func__); + /* We take that it is disabled and proceed */ + return false; + } + fw_mode_config = wma->dual_mac_cfg.cur_fw_mode_config; + + return WMI_DBS_FW_MODE_CFG_DBS_GET(fw_mode_config); +} + +/** + * wma_get_agile_dfs_config() - Get Agile DFS bit + * + * Gets the Agile DFS bit of fw_mode_config_bits + * + * Return: 0 or 1 to indicate the Agile DFS bit + */ +bool wma_get_agile_dfs_config(void) +{ + tp_wma_handle wma; + uint32_t fw_mode_config; + + if (wma_is_dual_mac_disabled_in_ini()) + return false; + + wma = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma) { + WMA_LOGE("%s: Invalid WMA handle", __func__); + /* We take that it is disabled and proceed */ + return false; + } + fw_mode_config = wma->dual_mac_cfg.cur_fw_mode_config; + + return WMI_DBS_FW_MODE_CFG_AGILE_DFS_GET(fw_mode_config); +} + +/** + * wma_get_dbs_scan_config() - Get DBS scan bit + * + * Gets the DBS scan bit of concurrent_scan_config_bits + * + * Return: 0 or 1 to indicate the DBS scan bit + */ +bool wma_get_dbs_scan_config(void) +{ + tp_wma_handle wma; + uint32_t scan_config; + + if (wma_is_dual_mac_disabled_in_ini()) + return false; + + wma = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma) { + WMA_LOGE("%s: Invalid WMA handle", __func__); + /* We take that it is disabled and proceed */ + return false; + } + scan_config = wma->dual_mac_cfg.cur_scan_config; + + return WMI_DBS_CONC_SCAN_CFG_DBS_SCAN_GET(scan_config); +} + +/** + * wma_get_dbs_plus_agile_scan_config() - Get DBS plus agile scan bit + * + * Gets the DBS plus agile scan bit of concurrent_scan_config_bits + * + * Return: 0 or 1 to indicate the DBS plus agile scan bit + */ +bool wma_get_dbs_plus_agile_scan_config(void) +{ + tp_wma_handle wma; + uint32_t scan_config; + + if (wma_is_dual_mac_disabled_in_ini()) + return false; + + wma = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma) { + WMA_LOGE("%s: Invalid WMA handle", __func__); + /* We take that it is disabled and proceed */ + return false; + } + scan_config = wma->dual_mac_cfg.cur_scan_config; + + return WMI_DBS_CONC_SCAN_CFG_AGILE_SCAN_GET(scan_config); +} + +/** + * wma_get_single_mac_scan_with_dfs_config() - Get Single MAC scan with DFS bit + * + * Gets the Single MAC scan with DFS bit of concurrent_scan_config_bits + * + * Return: 0 or 1 to indicate the Single MAC scan with DFS bit + */ +bool wma_get_single_mac_scan_with_dfs_config(void) +{ + tp_wma_handle wma; + uint32_t scan_config; + + if (wma_is_dual_mac_disabled_in_ini()) + return false; + + wma = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma) { + WMA_LOGE("%s: Invalid WMA handle", __func__); + /* We take that it is disabled and proceed */ + return false; + } + scan_config = wma->dual_mac_cfg.cur_scan_config; + + return WMI_DBS_CONC_SCAN_CFG_AGILE_DFS_SCAN_GET(scan_config); +} + +/** + * wma_is_dual_mac_disabled_in_ini() - Check if dual mac is disabled in INI + * + * Checks if the dual mac feature is disabled in INI + * + * Return: true if the dual mac feature is disabled from INI + */ +bool wma_is_dual_mac_disabled_in_ini(void) +{ + tpAniSirGlobal mac = cds_get_context(QDF_MODULE_ID_PE); + + if (!mac) { + WMA_LOGE("%s: Invalid mac pointer", __func__); + return true; + } + + if (mac->dual_mac_feature_disable) + return true; + + return false; +} + +/** + * wma_get_prev_dbs_config() - Get prev DBS bit + * + * Gets the previous DBS bit of fw_mode_config_bits + * + * Return: 0 or 1 to indicate the DBS bit + */ +bool wma_get_prev_dbs_config(void) +{ + tp_wma_handle wma; + uint32_t fw_mode_config; + + if (wma_is_dual_mac_disabled_in_ini()) + return false; + + wma = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma) { + WMA_LOGE("%s: Invalid WMA handle", __func__); + /* We take that it is disabled and proceed */ + return false; + } + fw_mode_config = wma->dual_mac_cfg.prev_fw_mode_config; + + return WMI_DBS_FW_MODE_CFG_DBS_GET(fw_mode_config); +} + +/** + * wma_get_prev_agile_dfs_config() - Get prev Agile DFS bit + * + * Gets the previous Agile DFS bit of fw_mode_config_bits + * + * Return: 0 or 1 to indicate the Agile DFS bit + */ +bool wma_get_prev_agile_dfs_config(void) +{ + tp_wma_handle wma; + uint32_t fw_mode_config; + + if (wma_is_dual_mac_disabled_in_ini()) + return false; + + wma = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma) { + WMA_LOGE("%s: Invalid WMA handle", __func__); + /* We take that it is disabled and proceed */ + return false; + } + fw_mode_config = wma->dual_mac_cfg.prev_fw_mode_config; + + return WMI_DBS_FW_MODE_CFG_AGILE_DFS_GET(fw_mode_config); +} + +/** + * wma_get_prev_dbs_scan_config() - Get prev DBS scan bit + * + * Gets the previous DBS scan bit of concurrent_scan_config_bits + * + * Return: 0 or 1 to indicate the DBS scan bit + */ +bool wma_get_prev_dbs_scan_config(void) +{ + tp_wma_handle wma; + uint32_t scan_config; + + if (wma_is_dual_mac_disabled_in_ini()) + return false; + + wma = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma) { + WMA_LOGE("%s: Invalid WMA handle", __func__); + /* We take that it is disabled and proceed */ + return false; + } + scan_config = wma->dual_mac_cfg.prev_scan_config; + + return WMI_DBS_CONC_SCAN_CFG_DBS_SCAN_GET(scan_config); +} + +/** + * wma_get_prev_dbs_plus_agile_scan_config() - Get prev DBS plus agile scan bit + * + * Gets the previous DBS plus agile scan bit of concurrent_scan_config_bits + * + * Return: 0 or 1 to indicate the DBS plus agile scan bit + */ +bool wma_get_prev_dbs_plus_agile_scan_config(void) +{ + tp_wma_handle wma; + uint32_t scan_config; + + if (wma_is_dual_mac_disabled_in_ini()) + return false; + + wma = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma) { + WMA_LOGE("%s: Invalid WMA handle", __func__); + /* We take that it is disabled and proceed */ + return false; + } + scan_config = wma->dual_mac_cfg.prev_scan_config; + + return WMI_DBS_CONC_SCAN_CFG_AGILE_SCAN_GET(scan_config); +} + +/** + * wma_get_prev_single_mac_scan_with_dfs_config() - Get prev Single MAC scan + * with DFS bit + * + * Gets the previous Single MAC scan with DFS bit of concurrent_scan_config_bits + * + * Return: 0 or 1 to indicate the Single MAC scan with DFS bit + */ +bool wma_get_prev_single_mac_scan_with_dfs_config(void) +{ + tp_wma_handle wma; + uint32_t scan_config; + + if (wma_is_dual_mac_disabled_in_ini()) + return false; + + wma = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma) { + WMA_LOGE("%s: Invalid WMA handle", __func__); + /* We take that it is disabled and proceed */ + return false; + } + scan_config = wma->dual_mac_cfg.prev_scan_config; + + return WMI_DBS_CONC_SCAN_CFG_AGILE_DFS_SCAN_GET(scan_config); +} + +/** + * wma_is_scan_simultaneous_capable() - Check if scan parallelization is + * supported or not + * + * currently scan parallelization feature support is dependent on DBS but + * it can be independent in future. + * + * Return: True if master DBS control is enabled + */ +bool wma_is_scan_simultaneous_capable(void) +{ + if (wma_is_hw_dbs_capable()) + return true; + + return false; +} + +/** + * wma_get_vht_ch_width - return vht channel width + * + * Return: return vht channel width + */ +uint32_t wma_get_vht_ch_width(void) +{ + uint32_t fw_ch_wd = WNI_CFG_VHT_CHANNEL_WIDTH_80MHZ; + tp_wma_handle wm_hdl = cds_get_context(QDF_MODULE_ID_WMA); + + if (NULL == wm_hdl) + return fw_ch_wd; + + if (wm_hdl->vht_cap_info & WMI_VHT_CAP_CH_WIDTH_80P80_160MHZ) + fw_ch_wd = WNI_CFG_VHT_CHANNEL_WIDTH_80_PLUS_80MHZ; + else if (wm_hdl->vht_cap_info & WMI_VHT_CAP_CH_WIDTH_160MHZ) + fw_ch_wd = WNI_CFG_VHT_CHANNEL_WIDTH_160MHZ; + + return fw_ch_wd; +} + +/** + * wma_get_num_of_setbits_from_bitmask() - to get num of setbits from bitmask + * @mask: given bitmask + * + * This helper function should return number of setbits from bitmask + * + * Return: number of setbits from bitmask + */ +uint32_t wma_get_num_of_setbits_from_bitmask(uint32_t mask) +{ + uint32_t num_of_setbits = 0; + + while (mask) { + mask &= (mask - 1); + num_of_setbits++; + } + return num_of_setbits; +} + +/** + * wma_config_debug_module_cmd - set debug log config + * @wmi_handle: wmi layer handle + * @param: debug log parameter + * @val: debug log value + * @module_id_bitmap: debug module id bitmap + * @bitmap_len: debug module bitmap length + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +QDF_STATUS +wma_config_debug_module_cmd(wmi_unified_t wmi_handle, A_UINT32 param, + A_UINT32 val, A_UINT32 *module_id_bitmap, + A_UINT32 bitmap_len) +{ + struct dbglog_params dbg_param; + dbg_param.param = param; + dbg_param.val = val; + dbg_param.module_id_bitmap = module_id_bitmap; + dbg_param.bitmap_len = bitmap_len; + + return wmi_unified_dbglog_cmd_send(wmi_handle, &dbg_param); +} + +/** + * wma_is_p2p_lo_capable() - if driver is capable of p2p listen offload + * + * This function checks if driver is capable of p2p listen offload + * true: capable of p2p offload + * false: not capable + * + * Return: true - capable, false - not capable + */ +bool wma_is_p2p_lo_capable(void) +{ + tp_wma_handle wma; + + wma = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma) { + WMA_LOGE("%s: Invalid WMA handle", __func__); + return false; + } + + if (WMI_SERVICE_IS_ENABLED(wma->wmi_service_bitmap, + WMI_SERVICE_P2P_LISTEN_OFFLOAD_SUPPORT)) + return true; + + return false; +} + +QDF_STATUS wma_get_rcpi_req(WMA_HANDLE handle, + struct sme_rcpi_req *rcpi_request) +{ + tp_wma_handle wma_handle = (tp_wma_handle) handle; + struct rcpi_req cmd = {0}; + struct wma_txrx_node *iface; + struct sme_rcpi_req *node_rcpi_req = NULL; + + WMA_LOGD("%s: Enter", __func__); + iface = &wma_handle->interfaces[rcpi_request->session_id]; + /* command is in progress */ + if (iface->rcpi_req != NULL) { + WMA_LOGE("%s : previous rcpi request is pending", __func__); + return QDF_STATUS_SUCCESS; + } + + node_rcpi_req = qdf_mem_malloc(sizeof(*node_rcpi_req)); + if (!node_rcpi_req) { + WMA_LOGE("Failed to allocate memory for rcpi_request"); + return QDF_STATUS_E_NOMEM; + } + + node_rcpi_req->session_id = rcpi_request->session_id; + node_rcpi_req->measurement_type = rcpi_request->measurement_type; + node_rcpi_req->rcpi_callback = rcpi_request->rcpi_callback; + node_rcpi_req->rcpi_context = rcpi_request->rcpi_context; + node_rcpi_req->mac_addr = rcpi_request->mac_addr; + iface->rcpi_req = node_rcpi_req; + + cmd.vdev_id = rcpi_request->session_id; + qdf_mem_copy(cmd.mac_addr, &rcpi_request->mac_addr, QDF_MAC_ADDR_SIZE); + + switch (rcpi_request->measurement_type) { + + case RCPI_MEASUREMENT_TYPE_AVG_MGMT: + cmd.measurement_type = WMI_RCPI_MEASUREMENT_TYPE_AVG_MGMT; + break; + + case RCPI_MEASUREMENT_TYPE_AVG_DATA: + cmd.measurement_type = WMI_RCPI_MEASUREMENT_TYPE_AVG_DATA; + break; + + case RCPI_MEASUREMENT_TYPE_LAST_MGMT: + cmd.measurement_type = WMI_RCPI_MEASUREMENT_TYPE_LAST_MGMT; + break; + + case RCPI_MEASUREMENT_TYPE_LAST_DATA: + cmd.measurement_type = WMI_RCPI_MEASUREMENT_TYPE_LAST_DATA; + break; + + default: + /* + * invalid rcpi measurement type, fall back to + * RCPI_MEASUREMENT_TYPE_AVG_MGMT + */ + cmd.measurement_type = WMI_RCPI_MEASUREMENT_TYPE_AVG_MGMT; + break; + } + + if (wmi_unified_get_rcpi_cmd(wma_handle->wmi_handle, &cmd)) { + WMA_LOGE("%s: Failed to send WMI_REQUEST_RCPI_CMDID", + __func__); + iface->rcpi_req = NULL; + qdf_mem_free(node_rcpi_req); + return QDF_STATUS_E_FAILURE; + } + + WMA_LOGD("%s: Exit", __func__); + + return QDF_STATUS_SUCCESS; +} + +int wma_rcpi_event_handler(void *handle, uint8_t *cmd_param_info, + uint32_t len) +{ + WMI_UPDATE_RCPI_EVENTID_param_tlvs *param_buf; + wmi_update_rcpi_event_fixed_param *event; + struct sme_rcpi_req *rcpi_req; + uint8_t mac_addr[QDF_MAC_ADDR_SIZE]; + struct qdf_mac_addr qdf_mac; + struct wma_txrx_node *iface; + enum rcpi_measurement_type msmt_type; + QDF_STATUS rcpi_status = QDF_STATUS_SUCCESS; + QDF_STATUS status = QDF_STATUS_SUCCESS; + tp_wma_handle wma = (tp_wma_handle)handle; + + param_buf = (WMI_UPDATE_RCPI_EVENTID_param_tlvs *)cmd_param_info; + if (!param_buf) { + WMA_LOGA("%s: Invalid rcpi event", __func__); + return -EINVAL; + } + + event = param_buf->fixed_param; + iface = &wma->interfaces[event->vdev_id]; + + if (!iface->rcpi_req) { + WMI_LOGE("rcpi_req buffer not available"); + return 0; + } + + rcpi_req = iface->rcpi_req; + if (!rcpi_req->rcpi_callback) { + iface->rcpi_req = NULL; + qdf_mem_free(rcpi_req); + return 0; + } + WMI_MAC_ADDR_TO_CHAR_ARRAY(&event->peer_macaddr, mac_addr); + + switch (event->measurement_type) { + case WMI_RCPI_MEASUREMENT_TYPE_AVG_MGMT: + msmt_type = RCPI_MEASUREMENT_TYPE_AVG_MGMT; + break; + + case WMI_RCPI_MEASUREMENT_TYPE_AVG_DATA: + msmt_type = RCPI_MEASUREMENT_TYPE_AVG_DATA; + break; + + case WMI_RCPI_MEASUREMENT_TYPE_LAST_MGMT: + msmt_type = RCPI_MEASUREMENT_TYPE_LAST_MGMT; + break; + + case WMI_RCPI_MEASUREMENT_TYPE_LAST_DATA: + msmt_type = RCPI_MEASUREMENT_TYPE_LAST_DATA; + break; + + default: + WMI_LOGE("Invalid rcpi measurement type from firmware"); + rcpi_status = QDF_STATUS_E_INVAL; + break; + } + + + if (!QDF_IS_STATUS_SUCCESS(rcpi_status) || + (event->vdev_id != rcpi_req->session_id) || + (msmt_type != rcpi_req->measurement_type) || + (qdf_mem_cmp(mac_addr, &rcpi_req->mac_addr, QDF_MAC_ADDR_SIZE))) { + WMI_LOGE("invalid rcpi_req for specified rcpi_req"); + iface->rcpi_req = NULL; + qdf_mem_free(rcpi_req); + return 0; + } + + qdf_mem_copy(&qdf_mac, mac_addr, QDF_MAC_ADDR_SIZE); + + if (event->status) + status = QDF_STATUS_E_FAILURE; + else + status = QDF_STATUS_SUCCESS; + + (rcpi_req->rcpi_callback)(rcpi_req->rcpi_context, qdf_mac, event->rcpi, + status); + iface->rcpi_req = NULL; + qdf_mem_free(rcpi_req); + + return 0; +} + +/** + * wma_next_peer_log_index() - atomically increment and wrap around index value + * @index: address of index to increment + * @size: wrap around this value + * + * Return: new value of index + */ +static int wma_next_peer_log_index(qdf_atomic_t *index, int size) +{ + int i = qdf_atomic_inc_return(index); + + if (i == WMA_PEER_DEBUG_MAX_REC) + qdf_atomic_sub(WMA_PEER_DEBUG_MAX_REC, index); + while (i >= size) + i -= WMA_PEER_DEBUG_MAX_REC; + + return i; +} + +/** + * wma_peer_debug_log() - Add a debug log entry into peer debug records + * @vdev_id: vdev identifier + * @op: operation identifier + * @peer_id: peer id + * @mac_addr: mac address of peer, can be NULL + * @peer_obj: peer object address, can be NULL + * @arg1: extra argument #1 + * @arg2: extra argument #2 + * + * Return: none + */ +void wma_peer_debug_log(uint8_t vdev_id, uint8_t op, + uint16_t peer_id, void *mac_addr, + void *peer_obj, uint32_t arg1, uint32_t arg2) +{ + tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA); + uint32_t i; + struct peer_debug_rec *rec; + + if (!wma) { + WMA_LOGE("%s: WMA handle NULL. Exiting", __func__); + return; + } + + i = wma_next_peer_log_index(&wma->peer_dbg->index, + WMA_PEER_DEBUG_MAX_REC); + rec = &wma->peer_dbg->rec[i]; + rec->time = qdf_get_log_timestamp(); + rec->operation = op; + rec->vdev_id = vdev_id; + rec->peer_id = peer_id; + if (mac_addr) + qdf_mem_copy(rec->mac_addr.bytes, mac_addr, + IEEE80211_ADDR_LEN); + else + qdf_mem_zero(rec->mac_addr.bytes, + IEEE80211_ADDR_LEN); + rec->peer_obj = peer_obj; + rec->arg1 = arg1; + rec->arg2 = arg2; +} + +/** + * wma_peer_debug_string() - convert operation value to printable string + * @op: operation identifier + * + * Return: printable string for the operation + */ +static char *wma_peer_debug_string(uint32_t op) +{ + switch (op) { + case DEBUG_PEER_CREATE_SEND: + return "peer create send"; + case DEBUG_PEER_CREATE_RESP: + return "peer create resp_event"; + case DEBUG_PEER_DELETE_SEND: + return "peer delete send"; + case DEBUG_PEER_DELETE_RESP: + return "peer delete resp_event"; + case DEBUG_PEER_MAP_EVENT: + return "peer map event"; + case DEBUG_PEER_UNMAP_EVENT: + return "peer unmap event"; + case DEBUG_PEER_UNREF_DELETE: + return "peer unref delete"; + case DEBUG_DELETING_PEER_OBJ: + return "peer obj deleted"; + case DEBUG_ROAM_SYNCH_IND: + return "roam synch ind event"; + case DEBUG_ROAM_SYNCH_CNF: + return "roam sync conf sent"; + case DEBUG_ROAM_SYNCH_FAIL: + return "roam sync fail event"; + case DEBUG_ROAM_EVENT: + return "roam event"; + case DEBUG_WOW_ROAM_EVENT: + return "wow wakeup roam event"; + case DEBUG_BUS_SUSPEND: + return "host suspend"; + case DEBUG_BUS_RESUME: + return "host wakeup"; + case DEBUG_WOW_REASON: + return "wow wakeup reason"; + default: + return "unknown"; + } +} + +/** + * wma_peer_debug_dump() - Print the peer debug log records + * print all the valid debug records in the order of timestamp + * + * Return: none + */ +void wma_peer_debug_dump(void) +{ + tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA); + uint32_t i; + uint32_t current_index; + struct peer_debug_rec *dbg_rec; + uint64_t startt = 0; + uint32_t delta; + + if (!wma) { + WMA_LOGE("%s: WMA handle NULL. Exiting", __func__); + return; + } + + if (!wma) { + WMA_LOGD("%s: WMA handle NULL. Exiting", __func__); + return; + } + +#define DEBUG_CLOCK_TICKS_PER_MSEC 19200 + + current_index = qdf_atomic_read(&wma->peer_dbg->index); + if (current_index < 0) { + WMA_LOGE("%s: No records to dump", __func__); + return; + } else { + WMA_LOGD("%s: Dumping all records. current index %d", + __func__, current_index); + } + + i = current_index; + do { + /* wrap around */ + i = (i + 1) % WMA_PEER_DEBUG_MAX_REC; + dbg_rec = &wma->peer_dbg->rec[i]; + /* skip unused entry */ + if (dbg_rec->time == 0) + continue; + if (startt == 0) + startt = dbg_rec->time; + + /* + * Divide by 19200 == right shift 8 bits, then divide by 75 + * 32 bit computation keeps both 32 and 64 bit compilers happy. + * The value will roll over after approx. 33554 seconds. + */ + delta = (uint32_t) (((dbg_rec->time - startt) >> 8) & + 0xffffffff); + delta = delta / (DEBUG_CLOCK_TICKS_PER_MSEC >> 8); + + WMA_LOGD("index = %5d timestamp = 0x%016llx delta ms = %-12u " + "info = %-24s vdev_id = %-3d mac addr = %pM " + "peer obj = 0x%p peer_id = %-4d " + "arg1 = 0x%-8x arg2 = 0x%-8x", + i, + dbg_rec->time, + delta, + wma_peer_debug_string(dbg_rec->operation), + (int8_t) dbg_rec->vdev_id, + dbg_rec->mac_addr.bytes, + dbg_rec->peer_obj, + (int8_t) dbg_rec->peer_id, + dbg_rec->arg1, + dbg_rec->arg2); + } while (i != current_index); +} + +void wma_acquire_wmi_resp_wakelock(t_wma_handle *wma, uint32_t msec) +{ + cds_host_diag_log_work(&wma->wmi_cmd_rsp_wake_lock, + msec, + WIFI_POWER_EVENT_WAKELOCK_WMI_CMD_RSP); + qdf_wake_lock_timeout_acquire(&wma->wmi_cmd_rsp_wake_lock, msec); + qdf_runtime_pm_prevent_suspend(&wma->wmi_cmd_rsp_runtime_lock); +} + +void wma_release_wmi_resp_wakelock(t_wma_handle *wma) +{ + qdf_wake_lock_release(&wma->wmi_cmd_rsp_wake_lock, + WIFI_POWER_EVENT_WAKELOCK_WMI_CMD_RSP); + qdf_runtime_pm_allow_suspend(&wma->wmi_cmd_rsp_runtime_lock); +} + +QDF_STATUS +wma_send_vdev_start_to_fw(t_wma_handle *wma, struct vdev_start_params *params) +{ + QDF_STATUS status; + + wma_acquire_wmi_resp_wakelock(wma, WMA_VDEV_START_REQUEST_TIMEOUT); + status = wmi_unified_vdev_start_send(wma->wmi_handle, params); + if (QDF_IS_STATUS_ERROR(status)) + wma_release_wmi_resp_wakelock(wma); + + return status; +} + +QDF_STATUS wma_send_vdev_stop_to_fw(t_wma_handle *wma, uint8_t vdev_id) +{ + QDF_STATUS status; + + wma_acquire_wmi_resp_wakelock(wma, WMA_VDEV_STOP_REQUEST_TIMEOUT); + status = wmi_unified_vdev_stop_send(wma->wmi_handle, vdev_id); + if (QDF_IS_STATUS_ERROR(status)) + wma_release_wmi_resp_wakelock(wma); + + return status; +} + +int wma_chip_power_save_failure_detected_handler(void *handle, + uint8_t *cmd_param_info, + uint32_t len) +{ + tp_wma_handle wma = (tp_wma_handle)handle; + WMI_PDEV_CHIP_POWER_SAVE_FAILURE_DETECTED_EVENTID_param_tlvs *param_buf; + wmi_chip_power_save_failure_detected_fixed_param *event; + struct chip_pwr_save_fail_detected_params pwr_save_fail_params; + tpAniSirGlobal mac = (tpAniSirGlobal)cds_get_context( + QDF_MODULE_ID_PE); + if (NULL == wma) { + WMA_LOGE("%s: wma_handle is NULL", __func__); + return -EINVAL; + } + if (!mac) { + WMA_LOGE("%s: Invalid mac context", __func__); + return -EINVAL; + } + if (!mac->sme.chip_power_save_fail_cb) { + WMA_LOGE("%s: Callback not registered", __func__); + return -EINVAL; + } + + param_buf = + (WMI_PDEV_CHIP_POWER_SAVE_FAILURE_DETECTED_EVENTID_param_tlvs *) + cmd_param_info; + if (!param_buf) { + WMA_LOGE("%s: Invalid pwr_save_fail_params breached event", + __func__); + return -EINVAL; + } + event = param_buf->fixed_param; + pwr_save_fail_params.failure_reason_code = + event->power_save_failure_reason_code; + pwr_save_fail_params.wake_lock_bitmap[0] = + event->protocol_wake_lock_bitmap[0]; + pwr_save_fail_params.wake_lock_bitmap[1] = + event->protocol_wake_lock_bitmap[1]; + pwr_save_fail_params.wake_lock_bitmap[2] = + event->protocol_wake_lock_bitmap[2]; + pwr_save_fail_params.wake_lock_bitmap[3] = + event->protocol_wake_lock_bitmap[3]; + mac->sme.chip_power_save_fail_cb(mac->hHdd, + &pwr_save_fail_params); + + WMA_LOGD("%s: Invoke HDD pwr_save_fail callback", __func__); + return 0; +} +/** + * wma_get_event_bitmap_idx() - get indices for extended wow bitmaps + * @event: wow event + * @wow_bitmap_size: WOW bitmap size + * @bit_idx: bit index + * @idx: byte index + * + * Return: none + */ +static inline void wma_get_event_bitmap_idx(WOW_WAKE_EVENT_TYPE event, + uint32_t wow_bitmap_size, + uint32_t *bit_idx, + uint32_t *idx) +{ + + if (!bit_idx || !idx || wow_bitmap_size == 0) + return; + if (event == 0) + *idx = *bit_idx = 0; + else { + *idx = event / (wow_bitmap_size * 8); + *bit_idx = event % (wow_bitmap_size * 8); + } +} + +void wma_set_wow_event_bitmap(WOW_WAKE_EVENT_TYPE event, + uint32_t wow_bitmap_size, + uint32_t *bitmask) +{ + uint32_t bit_idx = 0, idx = 0; + + if (!bitmask || wow_bitmap_size < WMI_WOW_MAX_EVENT_BM_LEN) { + WMA_LOGE("%s: wow bitmask length shorter than %d", + __func__, WMI_WOW_MAX_EVENT_BM_LEN); + return; + } + wma_get_event_bitmap_idx(event, wow_bitmap_size, &bit_idx, &idx); + bitmask[idx] |= 1 << bit_idx; + + WMA_LOGI("%s: bitmask updated %x%x%x%x", + __func__, bitmask[0], bitmask[1], bitmask[2], bitmask[3]); +} + +inline bool wma_is_wow_bitmask_zero(uint32_t *bitmask, + uint32_t wow_bitmap_size) +{ + int i = 0; + + if (!bitmask || wow_bitmap_size < WMI_WOW_MAX_EVENT_BM_LEN) + WMA_LOGE("%s: wow bitmask length shorter than %d", + __func__, WMI_WOW_MAX_EVENT_BM_LEN); + else { + for (; i < WMI_WOW_MAX_EVENT_BM_LEN; i++) { + if (bitmask[i] != 0) + return false; + } + } + return true; +} + +void wma_set_sta_wow_bitmask(uint32_t *bitmask, uint32_t wow_bitmap_size) +{ + + if (!bitmask || wow_bitmap_size < WMI_WOW_MAX_EVENT_BM_LEN) { + WMA_LOGE("%s: wow bitmask length shorter than %d", + __func__, WMI_WOW_MAX_EVENT_BM_LEN); + return; + } + wma_set_wow_event_bitmap(WOW_CSA_IE_EVENT, + WMI_WOW_MAX_EVENT_BM_LEN, + bitmask); + wma_set_wow_event_bitmap(WOW_CLIENT_KICKOUT_EVENT, + WMI_WOW_MAX_EVENT_BM_LEN, + bitmask); + wma_set_wow_event_bitmap(WOW_PATTERN_MATCH_EVENT, + WMI_WOW_MAX_EVENT_BM_LEN, + bitmask); + wma_set_wow_event_bitmap(WOW_MAGIC_PKT_RECVD_EVENT, + WMI_WOW_MAX_EVENT_BM_LEN, + bitmask); + wma_set_wow_event_bitmap(WOW_DEAUTH_RECVD_EVENT, + WMI_WOW_MAX_EVENT_BM_LEN, + bitmask); + wma_set_wow_event_bitmap(WOW_DISASSOC_RECVD_EVENT, + WMI_WOW_MAX_EVENT_BM_LEN, + bitmask); + wma_set_wow_event_bitmap(WOW_BMISS_EVENT, + WMI_WOW_MAX_EVENT_BM_LEN, + bitmask); + wma_set_wow_event_bitmap(WOW_GTK_ERR_EVENT, + WMI_WOW_MAX_EVENT_BM_LEN, + bitmask); + wma_set_wow_event_bitmap(WOW_BETTER_AP_EVENT, + WMI_WOW_MAX_EVENT_BM_LEN, + bitmask); + wma_set_wow_event_bitmap(WOW_HTT_EVENT, + WMI_WOW_MAX_EVENT_BM_LEN, + bitmask); + wma_set_wow_event_bitmap(WOW_RA_MATCH_EVENT, + WMI_WOW_MAX_EVENT_BM_LEN, + bitmask); + wma_set_wow_event_bitmap(WOW_NLO_DETECTED_EVENT, + WMI_WOW_MAX_EVENT_BM_LEN, + bitmask); + wma_set_wow_event_bitmap(WOW_EXTSCAN_EVENT, + WMI_WOW_MAX_EVENT_BM_LEN, + bitmask); + wma_set_wow_event_bitmap(WOW_OEM_RESPONSE_EVENT, + WMI_WOW_MAX_EVENT_BM_LEN, + bitmask); + wma_set_wow_event_bitmap(WOW_TDLS_CONN_TRACKER_EVENT, + WMI_WOW_MAX_EVENT_BM_LEN, + bitmask); + /* Add further STA wakeup events above this line. */ +} + +void wma_set_sap_wow_bitmask(uint32_t *bitmask, uint32_t wow_bitmap_size) +{ + + if (!bitmask || wow_bitmap_size < WMI_WOW_MAX_EVENT_BM_LEN) { + WMA_LOGE("%s: wow bitmask length shorter than %d", + __func__, WMI_WOW_MAX_EVENT_BM_LEN); + return; + } + + wma_set_wow_event_bitmap(WOW_PROBE_REQ_WPS_IE_EVENT, + WMI_WOW_MAX_EVENT_BM_LEN, + bitmask); + wma_set_wow_event_bitmap(WOW_PATTERN_MATCH_EVENT, + WMI_WOW_MAX_EVENT_BM_LEN, + bitmask); + wma_set_wow_event_bitmap(WOW_AUTH_REQ_EVENT, + WMI_WOW_MAX_EVENT_BM_LEN, + bitmask); + wma_set_wow_event_bitmap(WOW_ASSOC_REQ_EVENT, + WMI_WOW_MAX_EVENT_BM_LEN, + bitmask); + wma_set_wow_event_bitmap(WOW_DEAUTH_RECVD_EVENT, + WMI_WOW_MAX_EVENT_BM_LEN, + bitmask); + wma_set_wow_event_bitmap(WOW_DISASSOC_RECVD_EVENT, + WMI_WOW_MAX_EVENT_BM_LEN, + bitmask); + wma_set_wow_event_bitmap(WOW_HTT_EVENT, + WMI_WOW_MAX_EVENT_BM_LEN, + bitmask); + + wma_set_wow_event_bitmap(WOW_CLIENT_KICKOUT_EVENT, + WMI_WOW_MAX_EVENT_BM_LEN, + bitmask); + + /* Add further SAP wakeup events above this line. */ +} diff --git a/drivers/staging/qcacld-3.0/core/wma/src/wma_utils_ut.c b/drivers/staging/qcacld-3.0/core/wma/src/wma_utils_ut.c new file mode 100644 index 0000000000000000000000000000000000000000..8eb5e3d302e85342ac6a3ab03e4d7d514888b1ba --- /dev/null +++ b/drivers/staging/qcacld-3.0/core/wma/src/wma_utils_ut.c @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2015-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: wma_utils_ut.c + * This file contains utilities related to unit test framework + */ + +/* Header files */ + +#include "wma.h" + +/** + * wma_set_dbs_capability_ut() - Set DBS capability for UT framework + * @dbs: Value of DBS capability to be set + * + * Sets the DBS capability for unit test framework. If the HW mode is + * already sent by the FW, only the DBS capability needs to be set. If the + * FW did not send any HW mode list, a single entry is created and DBS mode + * is set in it. The DBS capability is also set in the service bit map. + * + * Return: None + */ +void wma_set_dbs_capability_ut(uint32_t dbs) +{ + tp_wma_handle wma; + uint32_t i; + + wma = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma) { + WMA_LOGE("%s: Invalid WMA handle", __func__); + return; + } + + /* DBS list was not configured by the FW, so + * for UT, we can configure a single entry + */ + if (wma->hw_mode.hw_mode_list == NULL) { + wma->num_dbs_hw_modes = 1; + wma->hw_mode.hw_mode_list = + qdf_mem_malloc(sizeof(*wma->hw_mode.hw_mode_list) * + wma->num_dbs_hw_modes); + if (!wma->hw_mode.hw_mode_list) { + WMA_LOGE("%s: Memory allocation failed for UT-DBS", + __func__); + return; + } + wma->hw_mode.hw_mode_list[0] = 0x0000; + } + + for (i = 0; i < wma->num_dbs_hw_modes; i++) { + WMA_HW_MODE_DBS_MODE_SET(wma->hw_mode.hw_mode_list[i], + dbs); + } + + WMI_SERVICE_ENABLE(wma->wmi_service_bitmap, + WMI_SERVICE_DUAL_BAND_SIMULTANEOUS_SUPPORT); +} diff --git a/drivers/staging/qcacld-3.0/uapi/linux/a_debug.h b/drivers/staging/qcacld-3.0/uapi/linux/a_debug.h new file mode 100644 index 0000000000000000000000000000000000000000..3a5fd4c2204c1f0115b23b71e7c689dd92efb34d --- /dev/null +++ b/drivers/staging/qcacld-3.0/uapi/linux/a_debug.h @@ -0,0 +1,202 @@ +/* + * Copyright (c) 2013-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef _A_DEBUG_H_ +#define _A_DEBUG_H_ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#include +#include "osapi_linux.h" + +/* standard debug print masks bits 0..7 */ +#define ATH_DEBUG_ERR (1 << 0) /* errors */ +#define ATH_DEBUG_WARN (1 << 1) /* warnings */ +#define ATH_DEBUG_INFO (1 << 2) /* informational (module startup info) */ +#define ATH_DEBUG_TRC (1 << 3) /* generic function call tracing */ +#define ATH_DEBUG_RSVD1 (1 << 4) +#define ATH_DEBUG_RSVD2 (1 << 5) +#define ATH_DEBUG_RSVD3 (1 << 6) +#define ATH_DEBUG_RSVD4 (1 << 7) + +#define ATH_DEBUG_MASK_DEFAULTS (ATH_DEBUG_ERR | ATH_DEBUG_WARN) +#define ATH_DEBUG_ANY 0xFFFF + +/* other aliases used throughout */ +#define ATH_DEBUG_ERROR ATH_DEBUG_ERR +#define ATH_LOG_ERR ATH_DEBUG_ERR +#define ATH_LOG_INF ATH_DEBUG_INFO +#define ATH_LOG_TRC ATH_DEBUG_TRC +#define ATH_DEBUG_TRACE ATH_DEBUG_TRC +#define ATH_DEBUG_INIT ATH_DEBUG_INFO + +/* bits 8..31 are module-specific masks */ +#define ATH_DEBUG_MODULE_MASK_SHIFT 8 + +/* macro to make a module-specific masks */ +#define ATH_DEBUG_MAKE_MODULE_MASK(index) (1 << (ATH_DEBUG_MODULE_MASK_SHIFT + (index))) + +void debug_dump_bytes(A_UCHAR *buffer, A_UINT16 length, + char *pDescription); + +/* Debug support on a per-module basis + * + * Usage: + * + * Each module can utilize it's own debug mask variable. A set of commonly used + * masks are provided (ERRORS, WARNINGS, TRACE etc..). It is up to each module + * to define module-specific masks using the macros above. + * + * Each module defines a single debug mask variable debug_XXX where the "name" of the module is + * common to all C-files within that module. This requires every C-file that includes a_debug.h + * to define the module name in that file. + * + * Example: + * + * #define ATH_MODULE_NAME htc + * #include "a_debug.h" + * + * This will define a debug mask structure called debug_htc and all debug macros will reference this + * variable. + * + * A module can define module-specific bit masks using the ATH_DEBUG_MAKE_MODULE_MASK() macro: + * + * #define ATH_DEBUG_MY_MASK1 ATH_DEBUG_MAKE_MODULE_MASK(0) + * #define ATH_DEBUG_MY_MASK2 ATH_DEBUG_MAKE_MODULE_MASK(1) + * + * The instantiation of the debug structure should be made by the module. When a module is + * instantiated, the module can set a description string, a default mask and an array of description + * entries containing information on each module-defined debug mask. + * NOTE: The instantiation is statically allocated, only one instance can exist per module. + * + * Example: + * + * + * #define ATH_DEBUG_BMI ATH_DEBUG_MAKE_MODULE_MASK(0) + * + * #ifdef DEBUG + * static ATH_DEBUG_MASK_DESCRIPTION bmi_debug_desc[] = { + * { ATH_DEBUG_BMI , "BMI Tracing"}, <== description of the module specific mask + * }; + * + * ATH_DEBUG_INSTANTIATE_MODULE_VAR(bmi, + * "bmi" <== module name + * "Boot Manager Interface", <== description of module + * ATH_DEBUG_MASK_DEFAULTS, <== defaults + * ATH_DEBUG_DESCRIPTION_COUNT(bmi_debug_desc), + * bmi_debug_desc); + * + * #endif + * + * A module can optionally register it's debug module information in order for other tools to change the + * bit mask at runtime. A module can call A_REGISTER_MODULE_DEBUG_INFO() in it's module + * init code. This macro can be called multiple times without consequence. The debug info maintains + * state to indicate whether the information was previously registered. + * + * */ + +#define ATH_DEBUG_MAX_MASK_DESC_LENGTH 32 +#define ATH_DEBUG_MAX_MOD_DESC_LENGTH 64 + +typedef struct { + A_UINT32 Mask; + A_CHAR Description[ATH_DEBUG_MAX_MASK_DESC_LENGTH]; +} ATH_DEBUG_MASK_DESCRIPTION; + +#define ATH_DEBUG_INFO_FLAGS_REGISTERED (1 << 0) + +typedef struct _ATH_DEBUG_MODULE_DBG_INFO { + struct _ATH_DEBUG_MODULE_DBG_INFO *pNext; + A_CHAR ModuleName[16]; + A_CHAR ModuleDescription[ATH_DEBUG_MAX_MOD_DESC_LENGTH]; + A_UINT32 Flags; + A_UINT32 CurrentMask; + int MaxDescriptions; + ATH_DEBUG_MASK_DESCRIPTION *pMaskDescriptions; /* pointer to array of descriptions */ +} ATH_DEBUG_MODULE_DBG_INFO; + +#define ATH_DEBUG_DESCRIPTION_COUNT(d) (int)((sizeof((d))) / (sizeof(ATH_DEBUG_MASK_DESCRIPTION))) + +#define GET_ATH_MODULE_DEBUG_VAR_NAME(s) _XGET_ATH_MODULE_NAME_DEBUG_(s) +#define GET_ATH_MODULE_DEBUG_VAR_MASK(s) _XGET_ATH_MODULE_NAME_DEBUG_(s).CurrentMask +#define _XGET_ATH_MODULE_NAME_DEBUG_(s) debug_ ## s + +#ifdef WLAN_DEBUG + +/* for source files that will instantiate the debug variables */ +#define ATH_DEBUG_INSTANTIATE_MODULE_VAR(s,name,moddesc,initmask,count,descriptions) \ + ATH_DEBUG_MODULE_DBG_INFO GET_ATH_MODULE_DEBUG_VAR_NAME(s) = \ + {NULL,(name),(moddesc),0,(initmask),count,(descriptions)} + +#ifdef ATH_MODULE_NAME +extern ATH_DEBUG_MODULE_DBG_INFO +GET_ATH_MODULE_DEBUG_VAR_NAME(ATH_MODULE_NAME); +#define AR_DEBUG_LVL_CHECK(lvl) (GET_ATH_MODULE_DEBUG_VAR_MASK(ATH_MODULE_NAME) & (lvl)) +#endif /* ATH_MODULE_NAME */ + +#define ATH_DEBUG_SET_DEBUG_MASK(s,lvl) GET_ATH_MODULE_DEBUG_VAR_MASK(s) = (lvl) + +#define ATH_DEBUG_DECLARE_EXTERN(s) \ + extern ATH_DEBUG_MODULE_DBG_INFO GET_ATH_MODULE_DEBUG_VAR_NAME(s) + +#define AR_DEBUG_PRINTBUF(buffer, length, desc) debug_dump_bytes(buffer,length,desc) + +#define AR_DEBUG_ASSERT A_ASSERT + +void a_dump_module_debug_info(ATH_DEBUG_MODULE_DBG_INFO *pInfo); +void a_register_module_debug_info(ATH_DEBUG_MODULE_DBG_INFO *pInfo); +#ifdef A_SIMOS_DEVHOST +#define A_DUMP_MODULE_DEBUG_INFO(s) a_dump_module_debug_info(&(GET_ATH_MODULE_DEBUG_VAR_NAME(s))) +#define A_REGISTER_MODULE_DEBUG_INFO(s) a_register_module_debug_info(&(GET_ATH_MODULE_DEBUG_VAR_NAME(s))) +#else +#define A_DUMP_MODULE_DEBUG_INFO(s) +#define A_REGISTER_MODULE_DEBUG_INFO(s) +#endif + +#else /* !DEBUG */ +/* NON DEBUG */ +#define ATH_DEBUG_INSTANTIATE_MODULE_VAR(s,name,moddesc,initmask,count,descriptions) +#define AR_DEBUG_LVL_CHECK(lvl) 0 +#define AR_DEBUG_PRINTBUF(buffer, length, desc) +#define AR_DEBUG_ASSERT(test) +#define ATH_DEBUG_DECLARE_EXTERN(s) +#define ATH_DEBUG_SET_DEBUG_MASK(s,lvl) +#define A_DUMP_MODULE_DEBUG_INFO(s) +#define A_REGISTER_MODULE_DEBUG_INFO(s) + +#endif + +#if defined(__linux__) && !defined(LINUX_EMULATION) +#include "debug_linux.h" +#endif + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif diff --git a/drivers/staging/qcacld-3.0/uapi/linux/a_types.h b/drivers/staging/qcacld-3.0/uapi/linux/a_types.h new file mode 100644 index 0000000000000000000000000000000000000000..b47f4a83903ccc70bbcf8efcf357388897cce77e --- /dev/null +++ b/drivers/staging/qcacld-3.0/uapi/linux/a_types.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2013-2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* depot/sw/qca_main/perf_pwr_offload/drivers/host/include/a_types.h#7 - integrate change 1327637 (ktext) */ +/* ============================================================================== */ +/* This file contains the definitions of the basic atheros data types. */ +/* It is used to map the data types in atheros files to a platform specific */ +/* type. */ +/* */ +/* Author(s): ="Atheros" */ +/* ============================================================================== */ + +#ifndef _A_TYPES_H_ +#define _A_TYPES_H_ +#include + +typedef unsigned int A_UINT32; +typedef unsigned long long A_UINT64; +typedef unsigned short A_UINT16; +typedef unsigned char A_UINT8; +typedef int A_INT32; +typedef short A_INT16; +typedef char A_INT8; +typedef unsigned char A_UCHAR; +typedef char A_CHAR; +typedef _Bool A_BOOL; + +#endif /* _ATHTYPES_H_ */ diff --git a/drivers/staging/qcacld-3.0/uapi/linux/athstartpack.h b/drivers/staging/qcacld-3.0/uapi/linux/athstartpack.h new file mode 100644 index 0000000000000000000000000000000000000000..c6c051eb29120ad92e4ff9729325d24455eae852 --- /dev/null +++ b/drivers/staging/qcacld-3.0/uapi/linux/athstartpack.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2013-2014 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef _ATHSTARTPACK_H +#define _ATHSTARTPACK_H + +#if defined(LINUX) || defined(__linux__) +#include "osapi_linux.h" +#endif /* LINUX */ + +#ifdef QNX +#endif /* QNX */ + +#if __LONG_MAX__ == __INT_MAX__ +/* 32-bit compilation */ +#define PREPACK64 +#define POSTPACK64 +#else +/* 64-bit compilation */ +#define PREPACK64 PREPACK +#define POSTPACK64 POSTPACK +#endif + +#endif /* _ATHSTARTPACK_H */ diff --git a/drivers/staging/qcacld-3.0/uapi/linux/dbglog_common.h b/drivers/staging/qcacld-3.0/uapi/linux/dbglog_common.h new file mode 100644 index 0000000000000000000000000000000000000000..152862fa661b22a336e8c8f9f1bb35b0ac57e081 --- /dev/null +++ b/drivers/staging/qcacld-3.0/uapi/linux/dbglog_common.h @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2011, 2014-2015 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef _DBGLOG_COMMON_H_ +#define _DBGLOG_COMMON_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "dbglog_id.h" +#include "dbglog.h" + +#define MAX_DBG_MSGS 256 + +#define ATH6KL_FWLOG_PAYLOAD_SIZE 1500 + +#define DBGLOG_PRINT_PREFIX "FWLOG: " + +/* Handy Macros to read data length and type from FW */ +#define WLAN_DIAG_0_TYPE_S 0 +#define WLAN_DIAG_0_TYPE 0x000000ff +#define WLAN_DIAG_0_TYPE_GET(x) WMI_F_MS(x, WLAN_DIAG_0_TYPE) +#define WLAN_DIAG_0_TYPE_SET(x, y) WMI_F_RMW(x, y, WLAN_DIAG_0_TYPE) +/* bits 8-15 reserved */ + +/* length includes the size of wlan_diag_data */ +#define WLAN_DIAG_0_LEN_S 16 +#define WLAN_DIAG_0_LEN 0xffff0000 +#define WLAN_DIAG_0_LEN_GET(x) WMI_F_MS(x, WLAN_DIAG_0_LEN) +#define WLAN_DIAG_0_LEN_SET(x, y) WMI_F_RMW(x, y, WLAN_DIAG_0_LEN) + +#define CNSS_DIAG_SLEEP_INTERVAL 5 /* In secs */ + +#define ATH6KL_FWLOG_MAX_ENTRIES 20 +#define ATH6KL_FWLOG_PAYLOAD_SIZE 1500 + +#define DIAG_WLAN_DRIVER_UNLOADED 6 +#define DIAG_WLAN_DRIVER_LOADED 7 +#define DIAG_TYPE_LOGS 1 +#define DIAG_TYPE_EVENTS 2 + +typedef enum { + DBGLOG_PROCESS_DEFAULT = 0, + DBGLOG_PROCESS_PRINT_RAW, /* print them in debug view */ + DBGLOG_PROCESS_POOL_RAW, /* user buffer pool to save them */ + DBGLOG_PROCESS_NET_RAW, /* user buffer pool to save them */ + DBGLOG_PROCESS_MAX, +} dbglog_process_t; + +enum cnss_diag_type { + DIAG_TYPE_FW_EVENT, /* send fw event- to diag */ + DIAG_TYPE_FW_LOG, /* send log event- to diag */ + DIAG_TYPE_FW_DEBUG_MSG, /* send dbg message- to diag */ + DIAG_TYPE_INIT_REQ, /* cnss_diag initialization- from diag */ + DIAG_TYPE_FW_MSG, /* fw msg command-to diag */ + DIAG_TYPE_HOST_MSG, /* host command-to diag */ + DIAG_TYPE_CRASH_INJECT, /*crash inject-from diag */ + DIAG_TYPE_DBG_LEVEL, /* DBG LEVEL-from diag */ +}; + +enum wlan_diag_config_type { + DIAG_VERSION_INFO, +}; + +enum wlan_diag_frame_type { + WLAN_DIAG_TYPE_CONFIG, + WLAN_DIAG_TYPE_EVENT, + WLAN_DIAG_TYPE_LOG, + WLAN_DIAG_TYPE_MSG, + WLAN_DIAG_TYPE_LEGACY_MSG, +}; + +/* log/event are always 32-bit aligned. Padding is inserted after + * optional payload to satisify this requirement */ +struct wlan_diag_data { + unsigned int word0; /* type, length */ + unsigned int target_time; + unsigned int code; /* Diag log or event Code */ + uint8_t payload[0]; +}; + +struct dbglog_slot { + unsigned int diag_type; + unsigned int timestamp; + unsigned int length; + unsigned int dropped; + /* max ATH6KL_FWLOG_PAYLOAD_SIZE bytes */ + uint8_t payload[0]; +} __packed; + +typedef struct event_report_s { + unsigned int diag_type; + unsigned short event_id; + unsigned short length; +} event_report_t; + +/* + * Custom debug_print handlers + * Args: + * module Id + * vap id + * debug msg id + * Time stamp + * no of arguments + * pointer to the buffer holding the args + */ +typedef A_BOOL (*module_dbg_print)(A_UINT32, A_UINT16, A_UINT32, + A_UINT32, A_UINT16, A_UINT32 *); + +/** Register module specific dbg print*/ +void dbglog_reg_modprint(A_UINT32 mod_id, module_dbg_print printfn); + +#ifdef __cplusplus +} +#endif + +#endif /* _DBGLOG_COMMON_H_ */ diff --git a/drivers/staging/qcacld-3.0/uapi/linux/debug_linux.h b/drivers/staging/qcacld-3.0/uapi/linux/debug_linux.h new file mode 100644 index 0000000000000000000000000000000000000000..428c90b057f56d3b6248665b7f4655544721f111 --- /dev/null +++ b/drivers/staging/qcacld-3.0/uapi/linux/debug_linux.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2013-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef _DEBUG_LINUX_H_ +#define _DEBUG_LINUX_H_ + +/* macro to remove parens */ +#define ATH_PRINTX_ARG(arg ...) arg + +#ifdef WLAN_DEBUG +/* NOTE: the AR_DEBUG_PRINTF macro is defined here to handle special handling of variable arg macros + * which may be compiler dependent. */ +#define AR_DEBUG_PRINTF(mask, args) do { \ + if (GET_ATH_MODULE_DEBUG_VAR_MASK(ATH_MODULE_NAME) & (mask)) { \ + A_LOGGER(mask, ATH_MODULE_NAME, ATH_PRINTX_ARG args); \ + } \ +} while (0) +#else +/* on non-debug builds, keep in error and warning messages in the driver, all other + * message tracing will get compiled out */ +#define AR_DEBUG_PRINTF(mask, args) \ + if ((mask) & (ATH_DEBUG_ERR | ATH_DEBUG_WARN)) { A_PRINTF(ATH_PRINTX_ARG args); } + +#endif + +#endif /* _DEBUG_LINUX_H_ */ diff --git a/drivers/staging/qcacld-3.0/uapi/linux/osapi_linux.h b/drivers/staging/qcacld-3.0/uapi/linux/osapi_linux.h new file mode 100644 index 0000000000000000000000000000000000000000..4e61a5e21f9e04977427f73ece4489222223d3ac --- /dev/null +++ b/drivers/staging/qcacld-3.0/uapi/linux/osapi_linux.h @@ -0,0 +1,286 @@ +/* + * Copyright (c) 2013-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/* ------------------------------------------------------------------------------ */ +/* This file contains the definitions of the basic atheros data types. */ +/* It is used to map the data types in atheros files to a platform specific */ +/* type. */ +/* ------------------------------------------------------------------------------ */ + +#ifndef _OSAPI_LINUX_H_ +#define _OSAPI_LINUX_H_ + +#ifdef __KERNEL__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +/* #include */ +#include "a_types.h" + +#ifdef __GNUC__ +#define __ATTRIB_PACK __attribute__ ((packed)) +#define __ATTRIB_PRINTF __attribute__ ((format (printf, 1, 2))) +#define __ATTRIB_NORETURN __attribute__ ((noreturn)) +#ifndef INLINE +#define INLINE __inline__ +#endif +#else /* Not GCC */ +#define __ATTRIB_PACK +#define __ATTRIB_PRINTF +#define __ATTRIB_NORETURN +#ifndef INLINE +#define INLINE __inline +#endif +#endif /* End __GNUC__ */ + +#define PREPACK +#define POSTPACK __ATTRIB_PACK + +#define A_MEMCPY(dst, src, len) memcpy((A_UINT8 *)(dst), (src), (len)) +#define A_MEMZERO(addr, len) memset(addr, 0, len) +#define A_MEMSET(addr, value, size) memset((addr), (value), (size)) +#define A_MEMCMP(addr1, addr2, len) memcmp((addr1), (addr2), (len)) + +#define A_LOGGER(mask, mod, args ...) \ + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, ## args) +#define A_PRINTF(args ...) \ + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, ## args) +#define A_PRINTF_LOG(args ...) \ + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, ## args) +#define A_SNPRINTF(buf, len, args ...) snprintf (buf, len, args) + +/* + * Timer Functions + */ +#define A_MSLEEP(msecs) \ + { \ + set_current_state(TASK_INTERRUPTIBLE); \ + schedule_timeout((HZ * (msecs)) / 1000); \ + set_current_state(TASK_RUNNING); \ + } + +typedef struct timer_list A_TIMER; + +/* + * Wait Queue related functions + */ +#ifndef wait_event_interruptible_timeout +#define __wait_event_interruptible_timeout(wq, condition, ret) \ + do { \ + wait_queue_t __wait; \ + init_waitqueue_entry(&__wait, current); \ + \ + add_wait_queue(&wq, &__wait); \ + for (;; ) { \ + set_current_state(TASK_INTERRUPTIBLE); \ + if (condition) \ + break; \ + if (!signal_pending(current)) { \ + ret = schedule_timeout(ret); \ + if (!ret) \ + break; \ + continue; \ + } \ + ret = -ERESTARTSYS; \ + break; \ + } \ + current->state = TASK_RUNNING; \ + remove_wait_queue(&wq, &__wait); \ + } while (0) + +#define wait_event_interruptible_timeout(wq, condition, timeout) \ + ({ \ + long __ret = timeout; \ + if (!(condition)) \ + __wait_event_interruptible_timeout(wq, condition, __ret); \ + __ret; \ + }) +#endif /* wait_event_interruptible_timeout */ + +#ifdef WLAN_DEBUG +#ifdef A_SIMOS_DEVHOST +extern unsigned int panic_on_assert; +#define A_ASSERT(expr) \ + if (!(expr)) { \ + printk(KERN_ALERT "Debug Assert Caught, File %s, Line: %d, Test:%s \n", __FILE__, __LINE__, # expr); \ + if (panic_on_assert) panic(# expr); \ + } +#else +#define A_ASSERT(expr) \ + if (!(expr)) { \ + printk(KERN_ALERT "Debug Assert Caught, File %s, Line: %d, Test:%s \n", __FILE__, __LINE__, # expr); \ + } +#endif +#else +#define A_ASSERT(expr) +#endif /* DEBUG */ + +#ifdef ANDROID_ENV +struct firmware; +int android_request_firmware(const struct firmware **firmware_p, + const char *filename, struct device *device); +void android_release_firmware(const struct firmware *firmware); +#define A_REQUEST_FIRMWARE(_ppf, _pfile, _dev) android_request_firmware(_ppf, _pfile, _dev) +#define A_RELEASE_FIRMWARE(_pf) android_release_firmware(_pf) +#else +#define A_REQUEST_FIRMWARE(_ppf, _pfile, _dev) request_firmware(_ppf, _pfile, _dev) +#define A_RELEASE_FIRMWARE(_pf) release_firmware(_pf) +#endif + +/* + * Network buffer queue support + */ +typedef struct sk_buff_head A_NETBUF_QUEUE_T; + +#define A_NETBUF_FREE(bufPtr) \ + a_netbuf_free(bufPtr) +#define A_NETBUF_LEN(bufPtr) \ + a_netbuf_to_len(bufPtr) +#define A_NETBUF_PUSH(bufPtr, len) \ + a_netbuf_push(bufPtr, len) +#define A_NETBUF_PUT(bufPtr, len) \ + a_netbuf_put(bufPtr, len) +#define A_NETBUF_TRIM(bufPtr, len) \ + a_netbuf_trim(bufPtr, len) +#define A_NETBUF_PULL(bufPtr, len) \ + a_netbuf_pull(bufPtr, len) +#define A_NETBUF_HEADROOM(bufPtr) \ + a_netbuf_headroom(bufPtr) +#define A_NETBUF_SETLEN(bufPtr, len) \ + a_netbuf_setlen(bufPtr, len) + +/* Add data to end of a buffer */ +#define A_NETBUF_PUT_DATA(bufPtr, srcPtr, len) \ + a_netbuf_put_data(bufPtr, srcPtr, len) + +/* Add data to start of the buffer */ +#define A_NETBUF_PUSH_DATA(bufPtr, srcPtr, len) \ + a_netbuf_push_data(bufPtr, srcPtr, len) + +/* Remove data at start of the buffer */ +#define A_NETBUF_PULL_DATA(bufPtr, dstPtr, len) \ + a_netbuf_pull_data(bufPtr, dstPtr, len) + +/* Remove data from the end of the buffer */ +#define A_NETBUF_TRIM_DATA(bufPtr, dstPtr, len) \ + a_netbuf_trim_data(bufPtr, dstPtr, len) + +/* View data as "size" contiguous bytes of type "t" */ +#define A_NETBUF_VIEW_DATA(bufPtr, t, size) \ + (t)(((struct skbuf *)(bufPtr))->data) + +/* return the beginning of the headroom for the buffer */ +#define A_NETBUF_HEAD(bufPtr) \ + ((((struct sk_buff *)(bufPtr))->head)) + +/* + * OS specific network buffer access routines + */ +void a_netbuf_free(void *bufPtr); +void *a_netbuf_to_data(void *bufPtr); +A_UINT32 a_netbuf_to_len(void *bufPtr); +A_STATUS a_netbuf_push(void *bufPtr, A_INT32 len); +A_STATUS a_netbuf_push_data(void *bufPtr, char *srcPtr, A_INT32 len); +A_STATUS a_netbuf_put(void *bufPtr, A_INT32 len); +A_STATUS a_netbuf_put_data(void *bufPtr, char *srcPtr, A_INT32 len); +A_STATUS a_netbuf_pull(void *bufPtr, A_INT32 len); +A_STATUS a_netbuf_pull_data(void *bufPtr, char *dstPtr, A_INT32 len); +A_STATUS a_netbuf_trim(void *bufPtr, A_INT32 len); +A_STATUS a_netbuf_trim_data(void *bufPtr, char *dstPtr, A_INT32 len); +A_STATUS a_netbuf_setlen(void *bufPtr, A_INT32 len); +A_INT32 a_netbuf_headroom(void *bufPtr); +void a_netbuf_enqueue(A_NETBUF_QUEUE_T *q, void *pkt); +void a_netbuf_prequeue(A_NETBUF_QUEUE_T *q, void *pkt); +void *a_netbuf_dequeue(A_NETBUF_QUEUE_T *q); +int a_netbuf_queue_size(A_NETBUF_QUEUE_T *q); +int a_netbuf_queue_empty(A_NETBUF_QUEUE_T *q); +int a_netbuf_queue_empty(A_NETBUF_QUEUE_T *q); +void a_netbuf_queue_init(A_NETBUF_QUEUE_T *q); + +#ifdef QCA_PARTNER_PLATFORM +#include "ath_carr_pltfrm.h" +#endif /* QCA_PARTNER_PLATFORM */ + +#else /* __KERNEL__ */ + +#ifdef __GNUC__ +#define __ATTRIB_PACK __attribute__ ((packed)) +#define __ATTRIB_PRINTF __attribute__ ((format (printf, 1, 2))) +#define __ATTRIB_NORETURN __attribute__ ((noreturn)) +#ifndef inline +#define inline __inline__ +#endif +#ifndef INLINE +#define INLINE __inline__ +#endif +#else /* Not GCC */ +#define __ATTRIB_PACK +#define __ATTRIB_PRINTF +#define __ATTRIB_NORETURN +#ifndef inline +#define inline __inline +#endif +#ifndef INLINE +#define INLINE __inline +#endif +#endif /* End __GNUC__ */ + +#define PREPACK +#define POSTPACK __ATTRIB_PACK + +#define A_MEMCPY(dst, src, len) memcpy((dst), (src), (len)) +#define A_MEMSET(addr, value, size) memset((addr), (value), (size)) +#define A_MEMZERO(addr, len) memset((addr), 0, (len)) +#define A_MEMCMP(addr1, addr2, len) memcmp((addr1), (addr2), (len)) + +#ifdef ANDROID +#ifndef err +#include +#define err(_s, args ...) do { \ + fprintf(stderr, "%s: line %d ", __FILE__, __LINE__); \ + fprintf(stderr, args); fprintf(stderr, ": %d\n", errno); \ + exit(_s); } while (0) +#endif +#else +#include +#endif + +#endif /* __KERNEL__ */ + +#endif /* _OSAPI_LINUX_H_ */ diff --git a/drivers/staging/qcacld-3.0/uapi/linux/pktlog_ac_fmt.h b/drivers/staging/qcacld-3.0/uapi/linux/pktlog_ac_fmt.h new file mode 100644 index 0000000000000000000000000000000000000000..ee5b4abb402a7ffa3aa1db2dfbc73ccb3eff9b27 --- /dev/null +++ b/drivers/staging/qcacld-3.0/uapi/linux/pktlog_ac_fmt.h @@ -0,0 +1,394 @@ +/* + * Copyright (c) 2012-2016 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#ifndef REMOVE_PKT_LOG +#ifndef _PKTLOG_FMT_H_ +#define _PKTLOG_FMT_H_ + +#define CUR_PKTLOG_VER 10010 /* Packet log version */ +#define PKTLOG_MAGIC_NUM 7735225 + +#ifdef __linux__ +#ifdef MULTI_IF_NAME +#define PKTLOG_PROC_DIR "ath_pktlog" MULTI_IF_NAME +#define WLANDEV_BASENAME "cld" MULTI_IF_NAME +#else +#define PKTLOG_PROC_DIR "ath_pktlog" +#define WLANDEV_BASENAME "cld" +#endif +#endif +#define PKTLOG_PROC_SYSTEM "system" +#ifdef WIN32 +#pragma pack(push, pktlog_fmt, 1) +#define __ATTRIB_PACK +#elif defined(__EFI__) +#define __ATTRIB_PACK +#else +#ifndef __ATTRIB_PACK +#define __ATTRIB_PACK __attribute__ ((packed)) +#endif +#endif +#include +/* + * Each packet log entry consists of the following fixed length header + * followed by variable length log information determined by log_type + */ + +struct ath_pktlog_hdr { + uint16_t flags; + uint16_t missed_cnt; +#ifdef HELIUMPLUS + uint8_t log_type; + uint8_t macId; +#else + uint16_t log_type; +#endif + uint16_t size; + uint32_t timestamp; +#ifdef HELIUMPLUS + uint32_t type_specific_data; +#endif +} __ATTRIB_PACK; + +/** + * enum pkt_type - packet type + * @START_MONITOR: indicates parser to start packetdump parsing + * @STOP_MONITOR: indicates parser to stop packetdump parsing + * @TX_MGMT_PKT: TX management Packet + * @TX_DATA_PKT: TX data Packet + * @RX_MGMT_PKT: RX management Packet + * @RX_DATA_PKT: RX data Packet + * + * This enum has packet types + */ +enum pkt_type { + START_MONITOR = 1, + STOP_MONITOR, + TX_MGMT_PKT, + TX_DATA_PKT, + RX_MGMT_PKT, + RX_DATA_PKT, +}; + +#define ATH_PKTLOG_HDR_FLAGS_MASK 0xffff +#define ATH_PKTLOG_HDR_FLAGS_SHIFT 0 +#define ATH_PKTLOG_HDR_FLAGS_OFFSET 0 +#define ATH_PKTLOG_HDR_MISSED_CNT_MASK 0xffff0000 +#define ATH_PKTLOG_HDR_MISSED_CNT_SHIFT 16 +#define ATH_PKTLOG_HDR_MISSED_CNT_OFFSET 0 +#ifdef HELIUMPLUS +#define ATH_PKTLOG_HDR_LOG_TYPE_MASK 0x00ff +#define ATH_PKTLOG_HDR_LOG_TYPE_SHIFT 0 +#define ATH_PKTLOG_HDR_LOG_TYPE_OFFSET 1 +#define ATH_PKTLOG_HDR_MAC_ID_MASK 0xff00 +#define ATH_PKTLOG_HDR_MAC_ID_SHIFT 8 +#define ATH_PKTLOG_HDR_MAC_ID_OFFSET 1 +#else +#define ATH_PKTLOG_HDR_LOG_TYPE_MASK 0xffff +#define ATH_PKTLOG_HDR_LOG_TYPE_SHIFT 0 +#define ATH_PKTLOG_HDR_LOG_TYPE_OFFSET 1 +#endif + +#define ATH_PKTLOG_HDR_SIZE_MASK 0xffff0000 +#define ATH_PKTLOG_HDR_SIZE_SHIFT 16 +#define ATH_PKTLOG_HDR_SIZE_OFFSET 1 +#define ATH_PKTLOG_HDR_TIMESTAMP_OFFSET 2 +#define ATH_PKTLOG_HDR_TYPE_SPECIFIC_DATA_OFFSET 3 + +/** + * enum - Pktlog flag field details + * packet origin [1:0] + * 00 - Local + * 01 - Remote + * 10 - Unknown/Not applicable + * 11 - Reserved + * reserved [15:2] + */ +enum { + PKTLOG_FLG_FRM_TYPE_LOCAL_S = 0, + PKTLOG_FLG_FRM_TYPE_REMOTE_S, + PKTLOG_FLG_FRM_TYPE_CLONE_S, + PKTLOG_FLG_FRM_TYPE_CBF_S, + PKTLOG_FLG_FRM_TYPE_UNKNOWN_S +}; + +#define PHFLAGS_INTERRUPT_CONTEXT 0x80000000 + +/* Masks for setting pktlog events filters */ +#define ATH_PKTLOG_TX 0x000000001 +#define ATH_PKTLOG_RX 0x000000002 +#define ATH_PKTLOG_RCFIND 0x000000004 +#define ATH_PKTLOG_RCUPDATE 0x000000008 +#define ATH_PKTLOG_ANI 0x000000010 +#define ATH_PKTLOG_TEXT 0x000000020 +#define ATH_PKTLOG_PHYERR 0x000000040 +#define ATH_PKTLOG_PROMISC 0x000000080 +#define ATH_PKTLOG_SW_EVENT 0x000000100 + + +/* Types of packet log events */ +#define PKTLOG_TYPE_TX_CTRL 1 +#define PKTLOG_TYPE_TX_STAT 2 +#define PKTLOG_TYPE_TX_MSDU_ID 3 +#define PKTLOG_TYPE_TX_FRM_HDR 4 +#define PKTLOG_TYPE_RX_STAT 5 +#define PKTLOG_TYPE_RC_FIND 6 +#define PKTLOG_TYPE_RC_UPDATE 7 +#define PKTLOG_TYPE_TX_VIRT_ADDR 8 +#define PKTLOG_TYPE_SMART_ANTENNA 9 +#define PKTLOG_TYPE_SW_EVENT 10 +#define PKTLOG_TYPE_PKT_DUMP 11 +#define PKTLOG_TYPE_MAX 12 + +#define PKTLOG_MAX_TXCTL_WORDS 57 /* +2 words for bitmap */ +#define PKTLOG_MAX_TXSTATUS_WORDS 32 +#define PKTLOG_MAX_PROTO_WORDS 16 +#define PKTLOG_MAX_RXDESC_WORDS 62 +#define PKTLOG_HDR_SIZE_16 0x8000 + +struct txctl_frm_hdr { + uint16_t framectrl; /* frame control field from header */ + uint16_t seqctrl; /* frame control field from header */ + uint16_t bssid_tail; /* last two octets of bssid */ + uint16_t sa_tail; /* last two octets of SA */ + uint16_t da_tail; /* last two octets of DA */ + uint16_t resvd; +}; + +#if defined(HELIUMPLUS) +/* Peregrine 11ac based */ +#define MAX_PKT_INFO_MSDU_ID 1 +#else +/* Peregrine 11ac based */ +#define MAX_PKT_INFO_MSDU_ID 192 +#endif /* defined(HELIUMPLUS) */ + +/* + * msdu_id_info_t is defined for reference only + */ +struct msdu_id_info { + uint32_t num_msdu; + uint8_t bound_bmap[(MAX_PKT_INFO_MSDU_ID + 7)>>3]; + /* TODO: + * Convert the id's to uint32_t + * Reduces computation in the driver code + */ + uint16_t id[MAX_PKT_INFO_MSDU_ID]; +} __ATTRIB_PACK; +#define MSDU_ID_INFO_NUM_MSDU_OFFSET 0 /* char offset */ +#define MSDU_ID_INFO_BOUND_BM_OFFSET offsetof(struct msdu_id_info, bound_bmap) +#define MSDU_ID_INFO_ID_OFFSET offsetof(struct msdu_id_info, id) + + +struct ath_pktlog_txctl { + struct ath_pktlog_hdr pl_hdr; + /* struct txctl_frm_hdr frm_hdr; */ + void *txdesc_hdr_ctl; /* frm_hdr + Tx descriptor words */ + struct { + struct txctl_frm_hdr frm_hdr; + uint32_t txdesc_ctl[PKTLOG_MAX_TXCTL_WORDS]; + /* uint32_t *proto_hdr; / * protocol header (variable length!) * / */ + /* uint32_t *misc; / * Can be used for HT specific or other misc info * / */ + } priv; +} __ATTRIB_PACK; + +struct ath_pktlog_tx_status { + struct ath_pktlog_hdr pl_hdr; + void *ds_status; + int32_t misc[0]; /* Can be used for HT specific or other misc info */ +} __ATTRIB_PACK; + +struct ath_pktlog_msdu_info { + struct ath_pktlog_hdr pl_hdr; + void *ath_msdu_info; + A_UINT32 num_msdu; + struct { + /* + * Provision to add more information fields + */ + struct msdu_info_t { + A_UINT32 num_msdu; + A_UINT8 bound_bmap[MAX_PKT_INFO_MSDU_ID >> 3]; + } msdu_id_info; + /* + * array of num_msdu + * Static implementation will consume unwanted memory + * Need to split the pktlog_get_buf to get the buffer pointer only + */ + uint16_t msdu_len[MAX_PKT_INFO_MSDU_ID]; + } priv; + size_t priv_size; + +} __ATTRIB_PACK; + +struct ath_pktlog_rx_info { + struct ath_pktlog_hdr pl_hdr; + void *rx_desc; +} __ATTRIB_PACK; + +struct ath_pktlog_rc_find { + struct ath_pktlog_hdr pl_hdr; + void *rcFind; +} __ATTRIB_PACK; + +struct ath_pktlog_sw_event { + struct ath_pktlog_hdr pl_hdr; + void *sw_event; +} __ATTRIB_PACK; + +struct ath_pktlog_rc_update { + struct ath_pktlog_hdr pl_hdr; + void *txRateCtrl; /* rate control state proper */ +} __ATTRIB_PACK; + +#ifdef WIN32 +#pragma pack(pop, pktlog_fmt) +#endif +#ifdef __ATTRIB_PACK +#undef __ATTRIB_PACK +#endif /* __ATTRIB_PACK */ + +/* + * The following header is included in the beginning of the file, + * followed by log entries when the log buffer is read through procfs + */ + +struct ath_pktlog_bufhdr { + uint32_t magic_num; /* Used by post processing scripts */ + uint32_t version; /* Set to CUR_PKTLOG_VER */ +}; + +struct ath_pktlog_buf { + struct ath_pktlog_bufhdr bufhdr; + int32_t rd_offset; + volatile int32_t wr_offset; + /* Whenever this bytes written value croses 4K bytes, + * logging will be triggered + */ + int32_t bytes_written; + /* Index of the messages sent to userspace */ + uint32_t msg_index; + /* Offset for read */ + loff_t offset; + char log_data[0]; +}; + +#define PKTLOG_MOV_RD_IDX(_rd_offset, _log_buf, _log_size) \ + do { \ + if((_rd_offset + sizeof(struct ath_pktlog_hdr) + \ + ((struct ath_pktlog_hdr *)((_log_buf)->log_data + \ + (_rd_offset)))->size) <= _log_size) { \ + _rd_offset = ((_rd_offset) + sizeof(struct ath_pktlog_hdr) + \ + ((struct ath_pktlog_hdr *)((_log_buf)->log_data + \ + (_rd_offset)))->size); \ + } else { \ + _rd_offset = ((struct ath_pktlog_hdr *)((_log_buf)->log_data + \ + (_rd_offset)))->size; \ + } \ + (_rd_offset) = (((_log_size) - (_rd_offset)) >= \ + sizeof(struct ath_pktlog_hdr)) ? _rd_offset : 0; \ + } while(0) + +/** + * enum tx_pkt_fate - tx packet fate + * @TX_PKT_FATE_ACKED: Sent over air and ACKed + * @TX_PKT_FATE_SENT: Sent over air but not ACKed. + * @TX_PKT_FATE_FW_QUEUED: Queued within firmware, + * but not yet sent over air + * @TX_PKT_FATE_FW_DROP_INVALID: Dropped by firmware as invalid. + * E.g. bad source address, bad checksum, or invalid for current state. + * @TX_PKT_FATE_FW_DROP_NOBUFS: Dropped by firmware due + * to lack of buffer space + * @TX_PKT_FATE_FW_DROP_OTHER: Dropped by firmware for any other + * reason. Includes frames that were sent by driver to firmware, but + * unaccounted for by firmware. + * @TX_PKT_FATE_DRV_QUEUED: Queued within driver, not yet sent to firmware. + * @TX_PKT_FATE_DRV_DROP_INVALID: Dropped by driver as invalid. + * E.g. bad source address, or invalid for current state. + * @TX_PKT_FATE_DRV_DROP_NOBUFS: Dropped by driver due to lack of buffer space + * @TX_PKT_FATE_DRV_DROP_OTHER: Dropped by driver for any other reason. + * E.g. out of buffers. + * + * This enum has packet fate types + */ + +enum tx_pkt_fate { + TX_PKT_FATE_ACKED, + TX_PKT_FATE_SENT, + TX_PKT_FATE_FW_QUEUED, + TX_PKT_FATE_FW_DROP_INVALID, + TX_PKT_FATE_FW_DROP_NOBUFS, + TX_PKT_FATE_FW_DROP_OTHER, + TX_PKT_FATE_DRV_QUEUED, + TX_PKT_FATE_DRV_DROP_INVALID, + TX_PKT_FATE_DRV_DROP_NOBUFS, + TX_PKT_FATE_DRV_DROP_OTHER, +}; + +/** + * enum rx_pkt_fate - rx packet fate + * @RX_PKT_FATE_SUCCESS: Valid and delivered to + * network stack (e.g., netif_rx()). + * @RX_PKT_FATE_FW_QUEUED: Queued within firmware, + * but not yet sent to driver. + * @RX_PKT_FATE_FW_DROP_FILTER: Dropped by firmware + * due to host-programmable filters. + * @RX_PKT_FATE_FW_DROP_INVALID: Dropped by firmware + * as invalid. E.g. bad checksum, decrypt failed, or invalid for current state. + * @RX_PKT_FATE_FW_DROP_NOBUFS: Dropped by firmware + * due to lack of buffer space. + * @RX_PKT_FATE_FW_DROP_OTHER: Dropped by firmware + * for any other reason. + * @RX_PKT_FATE_DRV_QUEUED: Queued within driver, + * not yet delivered to network stack. + * @RX_PKT_FATE_DRV_DROP_FILTER: Dropped by driver + * due to filter rules. + * @RX_PKT_FATE_DRV_DROP_INVALID: Dropped by driver as invalid. + * E.g. not permitted in current state. + * @RX_PKT_FATE_DRV_DROP_NOBUFS: Dropped by driver + * due to lack of buffer space. + * @RX_PKT_FATE_DRV_DROP_OTHER: Dropped by driver for any other reason. + * + * This enum has packet fate types + */ + +enum rx_pkt_fate { + RX_PKT_FATE_SUCCESS, + RX_PKT_FATE_FW_QUEUED, + RX_PKT_FATE_FW_DROP_FILTER, + RX_PKT_FATE_FW_DROP_INVALID, + RX_PKT_FATE_FW_DROP_NOBUFS, + RX_PKT_FATE_FW_DROP_OTHER, + RX_PKT_FATE_DRV_QUEUED, + RX_PKT_FATE_DRV_DROP_FILTER, + RX_PKT_FATE_DRV_DROP_INVALID, + RX_PKT_FATE_DRV_DROP_NOBUFS, + RX_PKT_FATE_DRV_DROP_OTHER, +}; + +#endif /* _PKTLOG_FMT_H_ */ +#endif /* REMOVE_PKT_LOG */